summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2005-10-03 13:43:40 +0000
committer <>2014-09-25 11:25:48 +0000
commit10de491ef0bc43827ab8631a4c02860134e620a9 (patch)
tree22e734337cc9aa5d9b1d7c71261d160b6a60634d
downloadcvs-tarball-10de491ef0bc43827ab8631a4c02860134e620a9.tar.gz
Imported from /home/lorry/working-area/delta_cvs-tarball/cvs-1.12.13.tar.bz2.HEADcvs-1.12.13master
-rw-r--r--.cvsignore19
-rw-r--r--ABOUT-NLS5
-rw-r--r--AUTHORS90
-rw-r--r--BUGS113
-rw-r--r--COPYING251
-rw-r--r--COPYING.LIB484
-rw-r--r--ChangeLog7109
-rw-r--r--ChangeLog.zoo700
-rw-r--r--DEVEL-CVS31
-rw-r--r--FAQ8555
-rw-r--r--HACKING453
-rw-r--r--INSTALL236
-rw-r--r--MINOR-BUGS61
-rw-r--r--Makefile.am62
-rw-r--r--Makefile.in770
-rw-r--r--NEWS2140
-rw-r--r--PROJECTS53
-rw-r--r--README131
-rw-r--r--README.VMS155
-rw-r--r--TESTS257
-rw-r--r--TODO853
-rw-r--r--aclocal.m41040
-rwxr-xr-xbuild-aux/compile142
-rwxr-xr-xbuild-aux/config.guess1411
-rwxr-xr-xbuild-aux/config.rpath571
-rwxr-xr-xbuild-aux/config.sub1500
-rwxr-xr-xbuild-aux/depcomp529
-rwxr-xr-xbuild-aux/install-sh323
-rwxr-xr-xbuild-aux/mdate-sh193
-rwxr-xr-xbuild-aux/missing357
-rw-r--r--build-aux/texinfo.tex7086
-rwxr-xr-xbuild-aux/ylwrap222
-rwxr-xr-xbuild.com10
-rw-r--r--config.h.in1244
-rwxr-xr-xconfigure43702
-rw-r--r--configure.in1596
-rw-r--r--contrib/.cvsignore18
-rw-r--r--contrib/ChangeLog1083
-rw-r--r--contrib/Makefile.am110
-rw-r--r--contrib/Makefile.in751
-rw-r--r--contrib/README148
-rwxr-xr-xcontrib/clmerge.in164
-rwxr-xr-xcontrib/cln_hist.in103
-rwxr-xr-xcontrib/commit_prep.in86
-rw-r--r--contrib/cvs2vendor.sh159
-rw-r--r--contrib/cvs_acls.html459
-rwxr-xr-xcontrib/cvs_acls.in963
-rw-r--r--contrib/cvshelp.man561
-rwxr-xr-xcontrib/debug_check_log.sh201
-rw-r--r--contrib/descend.man114
-rw-r--r--contrib/descend.sh127
-rw-r--r--contrib/dirfns.shar481
-rw-r--r--contrib/intro.doc112
-rwxr-xr-xcontrib/log.in238
-rwxr-xr-xcontrib/log_accum.in789
-rwxr-xr-xcontrib/mfpipe.in115
-rwxr-xr-xcontrib/newcvsroot.sh47
-rw-r--r--contrib/pam/.cvsignore1
-rw-r--r--contrib/pam/ChangeLog27
-rw-r--r--contrib/pam/Makefile.am22
-rw-r--r--contrib/pam/Makefile.in422
-rw-r--r--contrib/pam/cvs.linux9
-rw-r--r--contrib/pam/cvs.solaris9
-rw-r--r--contrib/pvcs2rcs.in1314
-rw-r--r--contrib/rcs-5.7-commitid.patch411
-rw-r--r--contrib/rcs-to-cvs.sh193
-rw-r--r--contrib/rcs2log.199
-rw-r--r--contrib/rcs2log.sh742
-rw-r--r--contrib/rcs2sccs.sh156
-rwxr-xr-xcontrib/rcslock.in265
-rw-r--r--contrib/sandbox_status.man52
-rw-r--r--contrib/sandbox_status.sh95
-rwxr-xr-xcontrib/sccs2rcs.in326
-rw-r--r--contrib/validate_repo.in856
-rw-r--r--cvs-format.el145
-rw-r--r--cvs.spec239
-rw-r--r--cvs.spec.in239
-rw-r--r--cvsnt.dep2560
-rw-r--r--cvsnt.dsp711
-rw-r--r--cvsnt.dsw77
-rw-r--r--cvsnt.mak975
-rw-r--r--diff/.cvsignore9
-rw-r--r--diff/ChangeLog722
-rw-r--r--diff/Makefile.am31
-rw-r--r--diff/Makefile.in525
-rw-r--r--diff/README8
-rw-r--r--diff/analyze.c1082
-rw-r--r--diff/build_diff.com20
-rw-r--r--diff/cmpbuf.c38
-rw-r--r--diff/cmpbuf.h18
-rw-r--r--diff/context.c462
-rw-r--r--diff/diagmeet.note71
-rw-r--r--diff/diff.c1267
-rw-r--r--diff/diff.h354
-rw-r--r--diff/diff3.c1927
-rw-r--r--diff/diffrun.h69
-rw-r--r--diff/dir.c218
-rw-r--r--diff/ed.c198
-rw-r--r--diff/ifdef.c436
-rw-r--r--diff/io.c711
-rw-r--r--diff/libdiff.dep151
-rw-r--r--diff/libdiff.dsp192
-rw-r--r--diff/libdiff.mak340
-rw-r--r--diff/normal.c69
-rw-r--r--diff/side.c294
-rw-r--r--diff/system.h302
-rw-r--r--diff/util.c849
-rw-r--r--diff/version.c5
-rw-r--r--doc/.cvsignore43
-rw-r--r--doc/ChangeLog5307
-rw-r--r--doc/ChangeLog.fsf38
-rw-r--r--doc/HACKING.DOCS46
-rw-r--r--doc/Makefile.am154
-rw-r--r--doc/Makefile.in987
-rw-r--r--doc/RCSFILES281
-rw-r--r--doc/cvs-paper.ms1069
-rw-r--r--doc/cvs-paper.pdfbin0 -> 87703 bytes
-rw-r--r--doc/cvs.13967
-rw-r--r--doc/cvs.info234
-rw-r--r--doc/cvs.info-16966
-rw-r--r--doc/cvs.info-26139
-rw-r--r--doc/cvs.man.footer58
-rw-r--r--doc/cvs.man.header61
-rw-r--r--doc/cvs.pdfbin0 -> 1297631 bytes
-rw-r--r--doc/cvs.texinfo15923
-rw-r--r--doc/cvsclient.info2118
-rw-r--r--doc/cvsclient.pdfbin0 -> 207565 bytes
-rw-r--r--doc/cvsclient.texi2188
-rw-r--r--doc/getdate-cvs.texi554
-rw-r--r--doc/getdate.texi547
-rw-r--r--doc/i18n/.cvsignore1
-rw-r--r--doc/i18n/ChangeLog11
-rw-r--r--doc/i18n/Makefile.am22
-rw-r--r--doc/i18n/Makefile.in578
-rw-r--r--doc/i18n/README11
-rw-r--r--doc/i18n/pt_BR/.cvsignore1
-rw-r--r--doc/i18n/pt_BR/ChangeLog68
-rw-r--r--doc/i18n/pt_BR/Makefile.am20
-rw-r--r--doc/i18n/pt_BR/Makefile.in421
-rw-r--r--doc/i18n/pt_BR/README21
-rw-r--r--doc/i18n/pt_BR/cvs.texinfo21184
-rwxr-xr-xdoc/mdate-sh193
-rw-r--r--doc/mkman.pl369
-rw-r--r--doc/stamp-14
-rw-r--r--doc/stamp-vti4
-rw-r--r--doc/version-client.texi4
-rw-r--r--doc/version.texi4
-rw-r--r--doc/writeproxy.rtf652
-rw-r--r--emx/.cvsignore3
-rw-r--r--emx/ChangeLog237
-rw-r--r--emx/Makefile409
-rw-r--r--emx/Makefile.in409
-rw-r--r--emx/README70
-rw-r--r--emx/config.h446
-rw-r--r--emx/filesubr.c804
-rw-r--r--emx/rcmd.h46
-rw-r--r--emx/savecwd.c141
-rw-r--r--emx/startserver.c82
-rw-r--r--emx/system.c91
-rw-r--r--lib/.cvsignore17
-rw-r--r--lib/ChangeLog2726
-rw-r--r--lib/ChangeLog.fsf90
-rw-r--r--lib/Makefile.am321
-rw-r--r--lib/Makefile.gnulib258
-rw-r--r--lib/Makefile.in855
-rw-r--r--lib/README9
-rw-r--r--lib/__fpending.c32
-rw-r--r--lib/__fpending.h13
-rw-r--r--lib/alloca.c491
-rw-r--r--lib/alloca_.h52
-rw-r--r--lib/allocsa.c139
-rw-r--r--lib/allocsa.h113
-rw-r--r--lib/allocsa.valgrind7
-rw-r--r--lib/asnprintf.c37
-rw-r--r--lib/asprintf.c37
-rw-r--r--lib/atexit.c15
-rw-r--r--lib/basename.c79
-rwxr-xr-xlib/build_lib.com20
-rw-r--r--lib/canon-host.c90
-rw-r--r--lib/canon-host.h30
-rw-r--r--lib/canonicalize.c318
-rw-r--r--lib/canonicalize.h41
-rw-r--r--lib/chdir-long.c276
-rw-r--r--lib/chdir-long.h35
-rw-r--r--lib/closeout.c101
-rw-r--r--lib/closeout.h33
-rw-r--r--lib/cycle-check.c93
-rw-r--r--lib/cycle-check.h44
-rw-r--r--lib/dev-ino.h13
-rw-r--r--lib/dirname.c121
-rw-r--r--lib/dirname.h47
-rw-r--r--lib/dup-safer.c46
-rw-r--r--lib/dup2.c61
-rw-r--r--lib/error.c304
-rw-r--r--lib/error.h66
-rw-r--r--lib/exit.h32
-rw-r--r--lib/exitfail.c27
-rw-r--r--lib/exitfail.h20
-rw-r--r--lib/fd-safer.c59
-rw-r--r--lib/filenamecat.c126
-rw-r--r--lib/filenamecat.h22
-rw-r--r--lib/fncase.c155
-rw-r--r--lib/fnmatch.c383
-rw-r--r--lib/fnmatch_.h63
-rw-r--r--lib/fnmatch_loop.c1192
-rw-r--r--lib/fseeko.c48
-rw-r--r--lib/ftello.c28
-rw-r--r--lib/ftruncate.c92
-rw-r--r--lib/gai_strerror.c78
-rw-r--r--lib/getaddrinfo.c210
-rw-r--r--lib/getaddrinfo.h95
-rw-r--r--lib/getcwd.c407
-rw-r--r--lib/getcwd.h42
-rw-r--r--lib/getdate.c2936
-rw-r--r--lib/getdate.h22
-rw-r--r--lib/getdate.y1495
-rw-r--r--lib/getdelim.c119
-rw-r--r--lib/getdelim.h28
-rw-r--r--lib/gethostname.c53
-rw-r--r--lib/getline.c32
-rw-r--r--lib/getline.h28
-rw-r--r--lib/getlogin_r.c61
-rw-r--r--lib/getlogin_r.h38
-rw-r--r--lib/getndelim2.c155
-rw-r--r--lib/getndelim2.h43
-rw-r--r--lib/getnline.c39
-rw-r--r--lib/getnline.h48
-rw-r--r--lib/getopt.c1241
-rw-r--r--lib/getopt1.c174
-rw-r--r--lib/getopt_.h227
-rw-r--r--lib/getopt_int.h131
-rw-r--r--lib/getpagesize.h65
-rw-r--r--lib/getpass.c226
-rw-r--r--lib/getpass.h31
-rw-r--r--lib/gettext.h78
-rw-r--r--lib/gettime.c53
-rw-r--r--lib/gettimeofday.c123
-rw-r--r--lib/glob-libc.h196
-rw-r--r--lib/glob.c1289
-rw-r--r--lib/glob_.h65
-rw-r--r--lib/libcvs.dep548
-rw-r--r--lib/libcvs.dsp704
-rw-r--r--lib/libcvs.mak795
-rw-r--r--lib/lstat.c77
-rw-r--r--lib/lstat.h24
-rw-r--r--lib/malloc.c36
-rw-r--r--lib/mbchar.c38
-rw-r--r--lib/mbchar.h352
-rw-r--r--lib/mbuiter.h203
-rw-r--r--lib/md5.c452
-rw-r--r--lib/md5.h136
-rw-r--r--lib/memchr.c201
-rw-r--r--lib/memmove.c28
-rw-r--r--lib/mempcpy.c29
-rw-r--r--lib/mempcpy.h36
-rw-r--r--lib/memrchr.c194
-rw-r--r--lib/memrchr.h27
-rw-r--r--lib/minmax.h60
-rw-r--r--lib/mkdir.c65
-rw-r--r--lib/mkstemp.c44
-rw-r--r--lib/mktime.c664
-rw-r--r--lib/nanosleep.c124
-rw-r--r--lib/openat.c181
-rw-r--r--lib/openat.h44
-rw-r--r--lib/pagealign_alloc.c198
-rw-r--r--lib/pagealign_alloc.h42
-rw-r--r--lib/pathmax.h49
-rw-r--r--lib/pipe-safer.c50
-rw-r--r--lib/printf-args.c118
-rw-r--r--lib/printf-args.h136
-rw-r--r--lib/printf-parse.c536
-rw-r--r--lib/printf-parse.h74
-rw-r--r--lib/progname.c24
-rw-r--r--lib/quotearg.c679
-rw-r--r--lib/quotearg.h137
-rw-r--r--lib/readlink.c49
-rw-r--r--lib/realloc.c46
-rw-r--r--lib/regcomp.c3779
-rw-r--r--lib/regex.c68
-rw-r--r--lib/regex.h769
-rw-r--r--lib/regex_internal.c1656
-rw-r--r--lib/regex_internal.h907
-rw-r--r--lib/regexec.c4333
-rw-r--r--lib/rename.c58
-rw-r--r--lib/rpmatch.c79
-rw-r--r--lib/save-cwd.c115
-rw-r--r--lib/save-cwd.h34
-rw-r--r--lib/setenv.c328
-rw-r--r--lib/setenv.h54
-rw-r--r--lib/sighandle.c416
-rw-r--r--lib/size_max.h27
-rw-r--r--lib/stat-macros.h255
-rw-r--r--lib/stdbool_.h93
-rw-r--r--lib/stdint_.h283
-rw-r--r--lib/strcase.h48
-rw-r--r--lib/strcasecmp.c98
-rw-r--r--lib/strdup.c56
-rw-r--r--lib/strdup.h29
-rw-r--r--lib/strerror.c49
-rw-r--r--lib/strftime.c1375
-rw-r--r--lib/strftime.h21
-rw-r--r--lib/stripslash.c40
-rw-r--r--lib/strncasecmp.c58
-rw-r--r--lib/strnlen1.c39
-rw-r--r--lib/strnlen1.h41
-rw-r--r--lib/strstr.c128
-rw-r--r--lib/strstr.h37
-rw-r--r--lib/strtol.c447
-rw-r--r--lib/strtoul.c20
-rw-r--r--lib/sunos57-select.c225
-rw-r--r--lib/system.h349
-rw-r--r--lib/tempname.c319
-rwxr-xr-xlib/test-getdate.sh340
-rw-r--r--lib/time_r.c69
-rw-r--r--lib/time_r.h57
-rw-r--r--lib/timespec.h62
-rw-r--r--lib/unistd--.h28
-rw-r--r--lib/unistd-safer.h23
-rw-r--r--lib/unlocked-io.h137
-rw-r--r--lib/unsetenv.c99
-rw-r--r--lib/vasnprintf.c901
-rw-r--r--lib/vasnprintf.h77
-rw-r--r--lib/vasprintf.c42
-rw-r--r--lib/vasprintf.h63
-rw-r--r--lib/wait.h42
-rw-r--r--lib/waitpid.c80
-rw-r--r--lib/xalloc-die.c45
-rw-r--r--lib/xalloc.h79
-rw-r--r--lib/xgetcwd.c43
-rw-r--r--lib/xgetcwd.h18
-rw-r--r--lib/xgethostname.c84
-rw-r--r--lib/xgethostname.h1
-rw-r--r--lib/xmalloc.c241
-rw-r--r--lib/xreadlink.c93
-rw-r--r--lib/xreadlink.h23
-rw-r--r--lib/xselect.h21
-rw-r--r--lib/xsize.h108
-rw-r--r--lib/xtime.h42
-rw-r--r--lib/yesno.c53
-rw-r--r--lib/yesno.h26
-rw-r--r--m4/ChangeLog805
-rw-r--r--m4/README9
-rw-r--r--m4/acx_extract_cpp_defn.m462
-rw-r--r--m4/acx_with_external_zlib.m4180
-rw-r--r--m4/acx_with_gssapi.m4286
-rw-r--r--m4/alloca.m442
-rw-r--r--m4/allocsa.m415
-rw-r--r--m4/asx_version_compare.m465
-rw-r--r--m4/atexit.m418
-rw-r--r--m4/bison.m431
-rw-r--r--m4/canon-host.m416
-rw-r--r--m4/canonicalize.m418
-rw-r--r--m4/chdir-long.m442
-rw-r--r--m4/clock_time.m426
-rw-r--r--m4/closeout.m414
-rw-r--r--m4/codeset.m421
-rw-r--r--m4/cvs_func_printf_ptr.m443
-rw-r--r--m4/d-ino.m449
-rw-r--r--m4/d-type.m449
-rw-r--r--m4/dirname.m416
-rw-r--r--m4/dos.m458
-rw-r--r--m4/dup2.m418
-rw-r--r--m4/eealloc.m432
-rw-r--r--m4/eoverflow.m464
-rw-r--r--m4/error.m420
-rw-r--r--m4/exitfail.m414
-rw-r--r--m4/extensions.m430
-rw-r--r--m4/filenamecat.m414
-rw-r--r--m4/fnmatch.m4102
-rw-r--r--m4/fpending.m479
-rw-r--r--m4/ftruncate.m423
-rw-r--r--m4/getaddrinfo.m419
-rw-r--r--m4/getcwd-path-max.m4189
-rw-r--r--m4/getcwd.m467
-rw-r--r--m4/getdate.m423
-rw-r--r--m4/getdelim.m430
-rw-r--r--m4/gethostname.m418
-rw-r--r--m4/getline.m470
-rw-r--r--m4/getlogin_r.m433
-rw-r--r--m4/getndelim2.m425
-rw-r--r--m4/getnline.m413
-rw-r--r--m4/getopt.m480
-rw-r--r--m4/getpagesize.m415
-rw-r--r--m4/getpass.m441
-rw-r--r--m4/gettext.m4549
-rw-r--r--m4/gettime.m416
-rw-r--r--m4/gettimeofday.m480
-rw-r--r--m4/glob.m480
-rw-r--r--m4/gnulib-comp.m4399
-rw-r--r--m4/iconv.m4101
-rw-r--r--m4/intmax_t.m461
-rw-r--r--m4/inttypes.m425
-rw-r--r--m4/inttypes_h.m426
-rw-r--r--m4/lib-ld.m4110
-rw-r--r--m4/lib-link.m4554
-rw-r--r--m4/lib-prefix.m4185
-rw-r--r--m4/longdouble.m428
-rw-r--r--m4/longlong.m423
-rw-r--r--m4/lstat.m419
-rw-r--r--m4/mbchar.m421
-rw-r--r--m4/mbiter.m414
-rw-r--r--m4/mbrtowc.m431
-rw-r--r--m4/mbstate_t.m430
-rw-r--r--m4/md5.m418
-rw-r--r--m4/memchr.m418
-rw-r--r--m4/memmove.m418
-rw-r--r--m4/mempcpy.m423
-rw-r--r--m4/memrchr.m423
-rw-r--r--m4/minmax.m441
-rw-r--r--m4/mkdir-slash.m444
-rw-r--r--m4/mkstemp.m472
-rw-r--r--m4/mktime.m4200
-rw-r--r--m4/mmap-anon.m448
-rw-r--r--m4/nanosleep.m472
-rw-r--r--m4/nls.m451
-rw-r--r--m4/onceonly_2_57.m486
-rw-r--r--m4/openat.m428
-rw-r--r--m4/pagealign_alloc.m424
-rw-r--r--m4/pathmax.m413
-rw-r--r--m4/po.m4429
-rw-r--r--m4/progtest.m492
-rw-r--r--m4/quotearg.m417
-rw-r--r--m4/readlink.m420
-rw-r--r--m4/regex.m4136
-rw-r--r--m4/rename.m451
-rw-r--r--m4/restrict.m438
-rw-r--r--m4/rpmatch.m416
-rw-r--r--m4/save-cwd.m414
-rw-r--r--m4/setenv.m470
-rw-r--r--m4/signed.m417
-rw-r--r--m4/size_max.m459
-rw-r--r--m4/sockpfaf.m439
-rw-r--r--m4/ssize_t.m420
-rw-r--r--m4/stat-macros.m414
-rw-r--r--m4/stdbool.m483
-rw-r--r--m4/stdint.m458
-rw-r--r--m4/stdint_h.m426
-rw-r--r--m4/strcase.m438
-rw-r--r--m4/strdup.m417
-rw-r--r--m4/strerror.m418
-rw-r--r--m4/strftime.m438
-rw-r--r--m4/strstr.m418
-rw-r--r--m4/strtol.m419
-rw-r--r--m4/strtoul.m418
-rw-r--r--m4/sunos57-select.m455
-rw-r--r--m4/time_r.m438
-rw-r--r--m4/timespec.m459
-rw-r--r--m4/tm_gmtoff.m414
-rw-r--r--m4/tzset.m468
-rw-r--r--m4/uint32_t.m453
-rw-r--r--m4/uintmax_t.m430
-rw-r--r--m4/ulonglong.m423
-rw-r--r--m4/unistd-safer.m426
-rw-r--r--m4/unlocked-io.m436
-rw-r--r--m4/vasnprintf.m458
-rw-r--r--m4/vasprintf.m425
-rw-r--r--m4/wchar_t.m420
-rw-r--r--m4/wint_t.m420
-rw-r--r--m4/xalloc.m425
-rw-r--r--m4/xgetcwd.m413
-rw-r--r--m4/xreadlink.m412
-rw-r--r--m4/xsize.m413
-rw-r--r--m4/yesno.m414
-rw-r--r--maint-aux/Makefile.am26
-rw-r--r--maint-aux/Makefile.in424
-rw-r--r--maint-aux/gnulib-filelist.txt214
-rw-r--r--maint-aux/gnulib-modules66
-rwxr-xr-xmaint-aux/gnulib-update112
-rw-r--r--maint-aux/srclist.txt69
-rw-r--r--man/.cvsignore1
-rw-r--r--man/ChangeLog423
-rw-r--r--man/Makefile.am26
-rw-r--r--man/Makefile.in526
-rw-r--r--man/cvs.5330
-rw-r--r--man/cvsbug.8243
-rw-r--r--mktemp.sh39
-rw-r--r--os2/.cvsignore3
-rw-r--r--os2/ChangeLog1012
-rw-r--r--os2/Makefile357
-rw-r--r--os2/Makefile.in357
-rw-r--r--os2/README50
-rw-r--r--os2/config.h514
-rw-r--r--os2/dirent.c180
-rw-r--r--os2/dirent.h50
-rw-r--r--os2/filesubr.c946
-rw-r--r--os2/getpass.c63
-rw-r--r--os2/mkdir.c17
-rw-r--r--os2/os2inc.h22
-rw-r--r--os2/popen.c385
-rw-r--r--os2/popen.h6
-rw-r--r--os2/porttcp.c227
-rw-r--r--os2/pwd.c198
-rw-r--r--os2/pwd.h70
-rw-r--r--os2/rcmd.c76
-rw-r--r--os2/rcmd.h40
-rw-r--r--os2/run.c611
-rw-r--r--os2/tcpip.h131
-rw-r--r--os2/test-makefile40
-rw-r--r--os2/waitpid.c36
-rw-r--r--os2/watcom.mak153
-rw-r--r--src/.cvsignore13
-rw-r--r--src/ChangeLog14075
-rw-r--r--src/ChangeLog-9194524
-rw-r--r--src/ChangeLog-93953731
-rw-r--r--src/ChangeLog-964434
-rw-r--r--src/ChangeLog-973249
-rw-r--r--src/Makefile.am152
-rw-r--r--src/Makefile.in776
-rw-r--r--src/add.c923
-rw-r--r--src/admin.c1009
-rw-r--r--src/annotate.c287
-rw-r--r--src/buffer.c2187
-rw-r--r--src/buffer.h196
-rwxr-xr-xsrc/build_src.com71
-rw-r--r--src/checkin.c178
-rw-r--r--src/checkout.c1260
-rw-r--r--src/classify.c437
-rw-r--r--src/client.c5180
-rw-r--r--src/client.h221
-rw-r--r--src/commit.c2469
-rw-r--r--src/create_adm.c171
-rw-r--r--src/cvs.h923
-rwxr-xr-xsrc/cvsbug.in527
-rw-r--r--src/cvsrc.c162
-rw-r--r--src/diff.c1128
-rw-r--r--src/edit.c1233
-rw-r--r--src/edit.h45
-rw-r--r--src/entries.c1133
-rw-r--r--src/error.c267
-rw-r--r--src/exithandle.c63
-rw-r--r--src/expand_path.c382
-rw-r--r--src/fileattr.c695
-rw-r--r--src/fileattr.h136
-rw-r--r--src/filesubr.c878
-rw-r--r--src/find_names.c532
-rw-r--r--src/gssapi-client.c316
-rw-r--r--src/gssapi-client.h61
-rw-r--r--src/hardlink.c304
-rw-r--r--src/hardlink.h35
-rw-r--r--src/hash.c584
-rw-r--r--src/hash.h66
-rw-r--r--src/history.c1686
-rw-r--r--src/history.h18
-rw-r--r--src/ignore.c486
-rw-r--r--src/import.c1778
-rw-r--r--src/kerberos4-client.c110
-rw-r--r--src/kerberos4-client.h25
-rw-r--r--src/lock.c1373
-rw-r--r--src/log-buffer.c529
-rw-r--r--src/log-buffer.h34
-rw-r--r--src/log.c1782
-rw-r--r--src/login.c658
-rw-r--r--src/logmsg.c977
-rw-r--r--src/ls.c688
-rw-r--r--src/main.c1466
-rw-r--r--src/mkmodules.c1284
-rw-r--r--src/modules.c1042
-rw-r--r--src/ms-buffer.c163
-rw-r--r--src/ms-buffer.h22
-rw-r--r--src/myndbm.c334
-rw-r--r--src/myndbm.h59
-rw-r--r--src/no_diff.c96
-rw-r--r--src/parseinfo.c723
-rw-r--r--src/parseinfo.h67
-rw-r--r--src/patch.c846
-rw-r--r--src/rcs.c8878
-rw-r--r--src/rcs.h264
-rw-r--r--src/rcscmds.c595
-rw-r--r--src/recurse.c1363
-rw-r--r--src/release.c399
-rw-r--r--src/remove.c276
-rw-r--r--src/repos.c200
-rw-r--r--src/root.c1054
-rw-r--r--src/root.h69
-rw-r--r--src/rsh-client.c202
-rw-r--r--src/rsh-client.h19
-rw-r--r--src/run.c608
-rw-r--r--src/sanity.config.sh.in1
-rwxr-xr-xsrc/sanity.sh35660
-rw-r--r--src/scramble.c243
-rw-r--r--src/server.c7987
-rw-r--r--src/server.h221
-rw-r--r--src/socket-client.c241
-rw-r--r--src/socket-client.h46
-rw-r--r--src/stack.c165
-rw-r--r--src/stack.h17
-rw-r--r--src/status.c378
-rw-r--r--src/subr.c2003
-rw-r--r--src/subr.h92
-rw-r--r--src/tag.c1689
-rw-r--r--src/update.c2907
-rw-r--r--src/update.h21
-rw-r--r--src/vers_ts.c464
-rw-r--r--src/version.c84
-rw-r--r--src/watch.c540
-rw-r--r--src/watch.h61
-rw-r--r--src/wrapper.c574
-rw-r--r--src/zlib.c810
-rw-r--r--tools/.cvsignore1
-rw-r--r--tools/ChangeLog142
-rw-r--r--tools/Makefile.am24
-rw-r--r--tools/Makefile.in424
-rw-r--r--tools/README10
-rw-r--r--vms/.cvsignore2
-rwxr-xr-xvms/ChangeLog472
-rw-r--r--vms/Makefile.am94
-rw-r--r--vms/Makefile.in486
-rwxr-xr-xvms/build_vms.com26
-rwxr-xr-xvms/config.h341
-rw-r--r--vms/config.h.in334
-rw-r--r--vms/dir.h93
-rw-r--r--vms/filesubr.c1161
-rw-r--r--vms/filutils.c321
-rw-r--r--vms/filutils.h21
-rw-r--r--vms/getpass.c75
-rw-r--r--vms/getwd.c23
-rw-r--r--vms/misc.c155
-rw-r--r--vms/misc.h32
-rw-r--r--vms/ndir.c312
-rw-r--r--vms/ndir.h63
-rw-r--r--vms/pathnames.h37
-rw-r--r--vms/pc.c62
-rw-r--r--vms/pipe.c449
-rw-r--r--vms/pipe.h23
-rw-r--r--vms/piped_child.c382
-rw-r--r--vms/pwd.c33
-rw-r--r--vms/pwd.h25
-rw-r--r--vms/rcmd.c115
-rw-r--r--vms/readlink.c5
-rw-r--r--vms/rmdir.c23
-rwxr-xr-xvms/startserver.c56
-rw-r--r--vms/stat.c33
-rw-r--r--vms/unlink.c28
-rw-r--r--vms/utime.c42
-rw-r--r--vms/vms-types.h45
-rwxr-xr-xvms/vms.h45
-rw-r--r--vms/vmsmunch.c370
-rw-r--r--vms/vmsmunch.h32
-rw-r--r--vms/vmsmunch_private.h176
-rw-r--r--vms/waitpid.c77
-rw-r--r--windows-NT/.cvsignore6
-rw-r--r--windows-NT/ChangeLog1871
-rw-r--r--windows-NT/JmgStat.c214
-rw-r--r--windows-NT/JmgStat.h4
-rw-r--r--windows-NT/Makefile.am154
-rw-r--r--windows-NT/Makefile.in708
-rw-r--r--windows-NT/README113
-rw-r--r--windows-NT/SCC/.cvsignore8
-rw-r--r--windows-NT/SCC/ChangeLog250
-rw-r--r--windows-NT/SCC/Makefile.am33
-rw-r--r--windows-NT/SCC/Makefile.in431
-rw-r--r--windows-NT/SCC/README.txt116
-rw-r--r--windows-NT/SCC/SCC.dsp108
-rw-r--r--windows-NT/SCC/SCC.mak216
-rw-r--r--windows-NT/SCC/pubscc.h546
-rw-r--r--windows-NT/SCC/scc.c469
-rw-r--r--windows-NT/SCC/scc.def25
-rw-r--r--windows-NT/arpa/inet.h1
-rw-r--r--windows-NT/config.h1452
-rw-r--r--windows-NT/config.h.in1445
-rw-r--r--windows-NT/config.h.in.footer186
-rw-r--r--windows-NT/config.h.in.in1240
-rw-r--r--windows-NT/filesubr.c1029
-rw-r--r--windows-NT/fix-msvc-mak.pl99
-rw-r--r--windows-NT/mkconfig.pl314
-rw-r--r--windows-NT/mkdir.c33
-rw-r--r--windows-NT/ndir.c214
-rw-r--r--windows-NT/ndir.h62
-rw-r--r--windows-NT/netdb.h1
-rw-r--r--windows-NT/netinet/in.h1
-rw-r--r--windows-NT/pwd.c207
-rw-r--r--windows-NT/pwd.h67
-rw-r--r--windows-NT/rcmd.c190
-rw-r--r--windows-NT/rcmd.h30
-rw-r--r--windows-NT/run.c721
-rw-r--r--windows-NT/sockerror.c136
-rw-r--r--windows-NT/stamp-chi1445
-rw-r--r--windows-NT/startserver.c100
-rw-r--r--windows-NT/stdbool.h100
-rw-r--r--windows-NT/stdint.h290
-rw-r--r--windows-NT/sys/socket.h9
-rw-r--r--windows-NT/sys/types.h155
-rw-r--r--windows-NT/unistd.c71
-rw-r--r--windows-NT/unistd.h96
-rw-r--r--windows-NT/waitpid.c22
-rw-r--r--windows-NT/woe32.c355
-rw-r--r--windows-NT/woe32.h35
-rw-r--r--zlib/.cvsignore10
-rw-r--r--zlib/CVS/Entries11
-rw-r--r--zlib/CVS/Repository1
-rw-r--r--zlib/CVS/Root1
-rw-r--r--zlib/ChangeLog1097
-rw-r--r--zlib/FAQ339
-rw-r--r--zlib/INDEX51
-rw-r--r--zlib/Makefile.b32104
-rw-r--r--zlib/Makefile.bor105
-rw-r--r--zlib/Makefile.dj293
-rw-r--r--zlib/Makefile.in275
-rw-r--r--zlib/Makefile.msc101
-rw-r--r--zlib/Makefile.sas64
-rw-r--r--zlib/Makefile.tc105
-rw-r--r--zlib/Makefile.wat103
-rw-r--r--zlib/README125
-rw-r--r--zlib/adler32.c149
-rw-r--r--zlib/algorithm.txt209
-rw-r--r--zlib/amiga/Makefile.pup66
-rw-r--r--zlib/amiga/Makefile.sas65
-rw-r--r--zlib/as400/bndsrc132
-rw-r--r--zlib/as400/compile.clp123
-rw-r--r--zlib/as400/readme.txt111
-rw-r--r--zlib/as400/zlib.inc331
-rw-r--r--zlib/compress.c79
-rwxr-xr-xzlib/configure459
-rw-r--r--zlib/contrib/README.contrib71
-rw-r--r--zlib/contrib/ada/buffer_demo.adb106
-rw-r--r--zlib/contrib/ada/mtest.adb156
-rw-r--r--zlib/contrib/ada/read.adb156
-rw-r--r--zlib/contrib/ada/readme.txt65
-rw-r--r--zlib/contrib/ada/test.adb463
-rw-r--r--zlib/contrib/ada/zlib-streams.adb225
-rw-r--r--zlib/contrib/ada/zlib-streams.ads114
-rw-r--r--zlib/contrib/ada/zlib-thin.adb141
-rw-r--r--zlib/contrib/ada/zlib-thin.ads450
-rw-r--r--zlib/contrib/ada/zlib.adb701
-rw-r--r--zlib/contrib/ada/zlib.ads328
-rw-r--r--zlib/contrib/ada/zlib.gpr20
-rw-r--r--zlib/contrib/asm586/README.58643
-rw-r--r--zlib/contrib/asm586/match.S364
-rw-r--r--zlib/contrib/asm686/README.68634
-rw-r--r--zlib/contrib/asm686/match.S329
-rw-r--r--zlib/contrib/blast/Makefile8
-rw-r--r--zlib/contrib/blast/README4
-rw-r--r--zlib/contrib/blast/blast.c444
-rw-r--r--zlib/contrib/blast/blast.h71
-rw-r--r--zlib/contrib/blast/test.pkbin0 -> 8 bytes
-rw-r--r--zlib/contrib/blast/test.txt1
-rw-r--r--zlib/contrib/delphi/ZLib.pas557
-rw-r--r--zlib/contrib/delphi/ZLibConst.pas11
-rw-r--r--zlib/contrib/delphi/readme.txt76
-rw-r--r--zlib/contrib/delphi/zlibd32.mak93
-rw-r--r--zlib/contrib/infback9/README1
-rw-r--r--zlib/contrib/infback9/infback9.c608
-rw-r--r--zlib/contrib/infback9/infback9.h37
-rw-r--r--zlib/contrib/infback9/inffix9.h107
-rw-r--r--zlib/contrib/infback9/inflate9.h47
-rw-r--r--zlib/contrib/infback9/inftree9.c323
-rw-r--r--zlib/contrib/infback9/inftree9.h55
-rw-r--r--zlib/contrib/inflate86/inffas86.c1157
-rw-r--r--zlib/contrib/inflate86/inffast.S1368
-rw-r--r--zlib/contrib/iostream/test.cpp24
-rw-r--r--zlib/contrib/iostream/zfstream.cpp329
-rw-r--r--zlib/contrib/iostream/zfstream.h128
-rw-r--r--zlib/contrib/iostream2/zstream.h307
-rw-r--r--zlib/contrib/iostream2/zstream_test.cpp25
-rw-r--r--zlib/contrib/iostream3/README35
-rw-r--r--zlib/contrib/iostream3/TODO17
-rw-r--r--zlib/contrib/iostream3/test.cc50
-rw-r--r--zlib/contrib/iostream3/zfstream.cc479
-rw-r--r--zlib/contrib/iostream3/zfstream.h466
-rw-r--r--zlib/contrib/masm686/match.asm413
-rw-r--r--zlib/contrib/masmx64/bld_ml64.bat2
-rw-r--r--zlib/contrib/masmx64/gvmat64.asm513
-rw-r--r--zlib/contrib/masmx64/inffas8664.c186
-rw-r--r--zlib/contrib/masmx64/inffasx64.asm392
-rw-r--r--zlib/contrib/masmx64/readme.txt28
-rw-r--r--zlib/contrib/masmx86/bld_ml32.bat2
-rw-r--r--zlib/contrib/masmx86/gvmat32.asm972
-rw-r--r--zlib/contrib/masmx86/gvmat32c.c62
-rw-r--r--zlib/contrib/masmx86/inffas32.asm1083
-rwxr-xr-xzlib/contrib/masmx86/mkasm.bat3
-rw-r--r--zlib/contrib/masmx86/readme.txt21
-rw-r--r--zlib/contrib/minizip/ChangeLogUnzip67
-rw-r--r--zlib/contrib/minizip/Makefile25
-rw-r--r--zlib/contrib/minizip/crypt.h132
-rw-r--r--zlib/contrib/minizip/ioapi.c177
-rw-r--r--zlib/contrib/minizip/ioapi.h75
-rw-r--r--zlib/contrib/minizip/iowin32.c270
-rw-r--r--zlib/contrib/minizip/iowin32.h21
-rw-r--r--zlib/contrib/minizip/miniunz.c585
-rw-r--r--zlib/contrib/minizip/minizip.c420
-rw-r--r--zlib/contrib/minizip/mztools.c281
-rw-r--r--zlib/contrib/minizip/mztools.h31
-rw-r--r--zlib/contrib/minizip/unzip.c1598
-rw-r--r--zlib/contrib/minizip/unzip.h354
-rw-r--r--zlib/contrib/minizip/zip.c1219
-rw-r--r--zlib/contrib/minizip/zip.h235
-rw-r--r--zlib/contrib/pascal/example.pas599
-rw-r--r--zlib/contrib/pascal/readme.txt76
-rw-r--r--zlib/contrib/pascal/zlibd32.mak93
-rw-r--r--zlib/contrib/pascal/zlibpas.pas236
-rw-r--r--zlib/contrib/puff/Makefile8
-rw-r--r--zlib/contrib/puff/README63
-rw-r--r--zlib/contrib/puff/puff.c837
-rw-r--r--zlib/contrib/puff/puff.h31
-rw-r--r--zlib/contrib/puff/zeros.rawbin0 -> 1213 bytes
-rw-r--r--zlib/contrib/testzlib/testzlib.c275
-rw-r--r--zlib/contrib/testzlib/testzlib.txt10
-rw-r--r--zlib/contrib/untgz/Makefile14
-rw-r--r--zlib/contrib/untgz/Makefile.msc17
-rw-r--r--zlib/contrib/untgz/untgz.c674
-rw-r--r--zlib/contrib/vstudio/readme.txt73
-rw-r--r--zlib/contrib/vstudio/vc7/miniunz.vcproj126
-rw-r--r--zlib/contrib/vstudio/vc7/minizip.vcproj126
-rw-r--r--zlib/contrib/vstudio/vc7/testzlib.vcproj126
-rw-r--r--zlib/contrib/vstudio/vc7/zlib.rc32
-rw-r--r--zlib/contrib/vstudio/vc7/zlibstat.vcproj246
-rw-r--r--zlib/contrib/vstudio/vc7/zlibvc.def92
-rw-r--r--zlib/contrib/vstudio/vc7/zlibvc.sln78
-rw-r--r--zlib/contrib/vstudio/vc7/zlibvc.vcproj445
-rw-r--r--zlib/contrib/vstudio/vc8/miniunz.vcproj566
-rw-r--r--zlib/contrib/vstudio/vc8/minizip.vcproj563
-rw-r--r--zlib/contrib/vstudio/vc8/testzlib.vcproj948
-rw-r--r--zlib/contrib/vstudio/vc8/testzlibdll.vcproj567
-rw-r--r--zlib/contrib/vstudio/vc8/zlib.rc32
-rw-r--r--zlib/contrib/vstudio/vc8/zlibstat.vcproj870
-rw-r--r--zlib/contrib/vstudio/vc8/zlibvc.def92
-rw-r--r--zlib/contrib/vstudio/vc8/zlibvc.sln144
-rw-r--r--zlib/contrib/vstudio/vc8/zlibvc.vcproj1219
-rw-r--r--zlib/crc32.c423
-rw-r--r--zlib/crc32.h441
-rw-r--r--zlib/deflate.c1736
-rw-r--r--zlib/deflate.h331
-rw-r--r--zlib/example.c565
-rw-r--r--zlib/examples/README.examples42
-rw-r--r--zlib/examples/fitblk.c233
-rw-r--r--zlib/examples/gun.c693
-rw-r--r--zlib/examples/gzappend.c500
-rw-r--r--zlib/examples/gzjoin.c448
-rw-r--r--zlib/examples/gzlog.c413
-rw-r--r--zlib/examples/gzlog.h58
-rw-r--r--zlib/examples/zlib_how.html523
-rw-r--r--zlib/examples/zpipe.c191
-rw-r--r--zlib/examples/zran.c404
-rw-r--r--zlib/gzio.c1026
-rw-r--r--zlib/infback.c623
-rw-r--r--zlib/inffast.c318
-rw-r--r--zlib/inffast.h11
-rw-r--r--zlib/inffixed.h94
-rw-r--r--zlib/inflate.c1368
-rw-r--r--zlib/inflate.h115
-rw-r--r--zlib/inftrees.c329
-rw-r--r--zlib/inftrees.h55
-rw-r--r--zlib/libz.dep76
-rw-r--r--zlib/libz.dsp176
-rw-r--r--zlib/libz.mak272
-rw-r--r--zlib/make_vms.com461
-rw-r--r--zlib/minigzip.c322
-rw-r--r--zlib/msdos/Makefile.bor109
-rw-r--r--zlib/msdos/Makefile.dj2104
-rw-r--r--zlib/msdos/Makefile.emx69
-rw-r--r--zlib/msdos/Makefile.msc106
-rw-r--r--zlib/msdos/Makefile.tc94
-rw-r--r--zlib/old/Makefile.riscos151
-rw-r--r--zlib/old/README3
-rw-r--r--zlib/old/descrip.mms48
-rw-r--r--zlib/old/os2/Makefile.os2136
-rw-r--r--zlib/old/os2/zlib.def51
-rw-r--r--zlib/old/visual-basic.txt160
-rw-r--r--zlib/old/zlib.html971
-rw-r--r--zlib/os2/CVS/Entries3
-rw-r--r--zlib/os2/CVS/Repository1
-rw-r--r--zlib/os2/CVS/Root1
-rw-r--r--zlib/os2/Makefile.os2136
-rw-r--r--zlib/os2/zlib.def51
-rw-r--r--zlib/qnx/package.qpg141
-rw-r--r--zlib/trees.c1219
-rw-r--r--zlib/trees.h128
-rw-r--r--zlib/uncompr.c61
-rw-r--r--zlib/win32/DLL_FAQ.txt397
-rw-r--r--zlib/win32/Makefile.bor107
-rw-r--r--zlib/win32/Makefile.emx69
-rw-r--r--zlib/win32/Makefile.gcc141
-rw-r--r--zlib/win32/Makefile.msc126
-rw-r--r--zlib/win32/VisualC.txt3
-rw-r--r--zlib/win32/zlib.def60
-rw-r--r--zlib/win32/zlib1.rc39
-rw-r--r--zlib/zconf.h332
-rw-r--r--zlib/zlib.3159
-rw-r--r--zlib/zlib.h1357
-rw-r--r--zlib/zutil.c318
-rw-r--r--zlib/zutil.h269
881 files changed, 454595 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..e954774
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,19 @@
+*.ncb
+*.opt
+*.plg
+Debug
+Makefile
+Release
+WinDebug
+WinRel
+autom4te*.cache
+config.h
+config.log
+config.status
+cvs-*.tar.bz2*
+cvs-*.tar.gz*
+cvs.spec
+cvsinit
+cvsnt.mdp
+cvsnt.001
+stamp-h1
diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100644
index 0000000..da27fad
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,5 @@
+Automake started requiring this file after I included the gettext support from
+GNULIB <http://savannah.gnu.org/projects/gnulib>. I'm not sure why, exactly,
+but there was an nls.m4 macro I had to import which claims that NLS stands for
+"Native Language Support". If someone would like to replace this ABOUT-NLS
+file with a more appropriate one, please do.
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..938d55a
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,90 @@
+Authors of GNU CVS
+
+The conflict-resolution algorithms and much of the administrative file
+definitions of CVS were based on the original package written by Dick Grune
+at Vrije Universiteit in Amsterdam <dick@cs.vu.nl>, and posted to
+comp.sources.unix in the volume 6 release sometime in 1986. This original
+version was a collection of shell scripts. I am thankful that Dick made
+his work available.
+
+Brian Berliner from Prisma, Inc. (now at Sun Microsystems, Inc.)
+<berliner@sun.com> converted the original CVS shell scripts into reasonably
+fast C and added many, many features to support software release control
+functions. See the manual page in the "man" directory. A copy of the
+USENIX article presented at the Winter 1990 USENIX Conference, Washington
+D.C., is included in the "doc" directory.
+
+Jeff Polk from BSDI <polk@bsdi.com> converted the CVS 1.2
+sources into much more readable and maintainable C code. He also added a
+whole lot of functionality and modularity to the code in the process.
+See the bottom of the NEWS file (from about 1992).
+
+david d `zoo' zuhn <zoo@armadillo.com> contributed the working base code
+for CVS 1.4 Alpha. His work carries on from work done by K. Richard Pixley
+and others at Cygnus Support. The CVS 1.4 upgrade is due in large part to
+Zoo's efforts.
+
+David G. Grubbs <dgg@odi.com> contributed the CVS "history" and "release"
+commands. As well as the ever-so-useful "-n" option of CVS which tells CVS
+to show what it would do, without actually doing it. He also contributed
+support for the .cvsignore file.
+
+The Free Software Foundation (GNU) contributed most of the portability
+framework that CVS now uses. This can be found in the "configure" script,
+the Makefile's, and basically most of the "lib" directory.
+
+K. Richard Pixley, Cygnus Support <rich@cygnus.com> contributed many bug
+fixes/enhancement as well as completing early reviews of the CVS 1.3 manual
+pages.
+
+Roland Pesch, then of Cygnus Support <roland@wrs.com> contributed
+brand new cvs(1) and cvs(5) manual pages. Thanks to him for saving us
+from poor use of our language!
+
+Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
+contributed the code in lib/sighandle.c. I added support for POSIX, BSD,
+and non-POSIX/non-BSD systems.
+
+Jim Kingdon and others at Cygnus Support <info@cygnus.com> wrote the
+remote repository access code.
+
+Larry Jones and Derek Price <derek@ximbiot.com> have been maintaining and
+enhancing CVS for some years. Mark D. Baushke <mdb@gnu.org> came on in
+2003.
+
+Conrad Pino <Conrad@Pino.com> began maintaining the Windows port in 2004.
+
+There have been many, many contributions not listed here. Consult the
+individual ChangeLog files in each directory for a more complete idea.
+
+In addition to the above contributors, the following Beta testers
+deserve special mention for their support. This is only a partial
+list; if you have helped in this way and would like to be listed, let
+bug-cvs know (as described in the Cederqvist manual).
+
+ Mark D. Baushke <mdb@cisco.com>
+ Per Cederqvist <ceder@signum.se>
+ J.T. Conklin <jtc@cygnus.com>
+ Vince DeMarco <vdemarco@fdcsrvr.cs.mci.com>
+ Paul Eggert <eggert@twinsun.com>
+ Lal George <george@research.att.com>
+ Dean E. Hardi <Dean.E.Hardi@ccmail.jpl.nasa.gov>
+ Mike Heath <mike@pencom.com>
+ Jim Kingdon <kingdon@cygnus.com>
+ Bernd Leibing <bernd.leibing@rz.uni-ulm.de>
+ Benedict Lofstedt <benedict@tusc.com.au>
+ Dave Love <d.love@dl.ac.uk>
+ Robert Lupton the Good <rhl@astro.princeton.edu>
+ Tom McAliney <tom@hilco.com>
+ Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
+ Jim Meyering <meyering@comco.com>
+ Thomas Mohr <mohr@lts.sel.alcatel.de>
+ Thomas Nilsson <thoni@softlab.se>
+ Raye Raskin <raye.raskin@lia.com>
+ Harlan Stenn <harlan@landmark.com>
+ Gunnar Tornblom <gunnar.tornblom@senet.abb.se>
+ Greg A. Woods <woods@planix.com>
+
+Many contributors have added code to the "contrib" directory. See the
+README file there for a list of what is available. There is also a
+contributed GNU Emacs CVS-mode in tools/pcl-cvs.
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..382ba5f
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,113 @@
+See the Cederqvist manual (cvs.texinfo) for information on how to
+report bugs (and what will happen to your bug reports if you do).
+
+The following is a list of some of the known bugs. It may or may not
+be comprehensive. We would dearly love for people to volunteer to
+help us keep it up to date (for starters, if you notice any
+inaccuracies, please let bug-cvs know as described in the Cederqvist
+manual). There are some other reported bugs in MINOR-BUGS; the
+difference, at least in theory, is that those bugs are less serious.
+
+
+* For platform-specific information (in some cases including known
+bugs), see README.VMS, windows-NT/README, or os2/README. There is no
+similar file for the unix-like operating systems (not yet, at least).
+This file also might contain some platform-specific bugs.
+
+
+* If your login name contains a space or various other characters
+(particularly an issue on Windows), CVS will have trouble (it will
+write invalid RCS files, probably). The fix would be to have CVS
+change such characters to underscores before writing them to the RCS
+file. Furthermore, the LOGNAME or USER environment variables usually
+won't override the system login name, so this can be hard to work
+around.
+
+
+* If you specify the -w global option to client/server CVS, it only
+overrides a CVSREAD environment variable set on the client, not a
+CVSREAD variable which was set on the server (for example, in .bashrc
+when the server was run via rsh). The fix of course will be to
+provide a "Option-read-write" request which sends -w, in addition to
+"Global_option -r" which sends -r.
+
+
+* Symbolic links to files will not work with or without LockDir. In the
+repository, you should avoid using symbolic links to files since this issue
+can cause data loss. Symlinks are only a problem when writing files. If your
+repository does not allow any write access, symlinks are not a problem.
+
+
+* Symbolic links to directories will not work with LockDir. In the
+repository, you should avoid using symbolic links to directories if
+you intend to use LockDir as the correct directory will NOT be locked
+by CVS during write. Directory symlinks are not recommended, but should work
+as long as LockDir is not being used. Symlinks are only a problem when
+writing files. If your repository does not allow any write access, symlinks
+are never a problem, whether or not LockDir is in use.
+
+
+* The -m option to "cvs add" does not work with client/server CVS.
+CVS will accept the option, but it won't actually set the
+file's description.
+
+
+* cvs update walks into a user's work directory if there's a directory
+ of the same name in the repository even if the user's directory
+ doesn't yet have a CVS admin sub-directory. This can greatly confuse
+ users who try to add the same directory at nearly the same time.
+
+
+* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
+ To: info-cvs@prep.ai.mit.edu
+ Subject: Still one more bug
+ Date: Sat, 25 Feb 1995 17:01:15 -0500
+
+ mycroft@duality [1]; cd /usr/src/lib/libc
+ mycroft@duality [1]; cvs diff -C2 '-D1 day ago' -Dnow
+ cvs server: Diffing .
+ cvs server: Diffing DB
+ cvs [server aborted]: could not chdir to DB: No such file or directory
+ mycroft@duality [1];
+
+ `DB' is an old directory, which no longer has files in it, and is
+ removed automatically when I use the `-P' option to checkout.
+
+ This error doesn't occur when run locally.
+
+ P.S. Is anyone working on fixing these bugs?
+
+
+* CVS does not always seem to be waiting to the next filesystem timestamp
+quanta after commits. So far this has only shown up in testing under the BSDI
+OS. The symptoms are that ocassionally CVS will not notice that modified files
+are modified, though the file must be modified within a short time after the
+commit, probably milliseconds or seconds, for this symptom to be noticed. One
+suspected cause is that one of the calls to sleep_past() is being called with
+an incorrect value, though this does not explain why symptoms have only been
+noticed under BSDI.
+
+
+* The CVS server is leaving a temp directory (/tmp/cvs-serv*) on AIX 4.3 under
+very rare circumstances (one out of c. 10,500 test cases). This appears to be
+dependent on some sort of race condition as it disappears with tracing enabled
+and under the debugger. Informative feedback is welcome.
+
+
+* UNICOS 9.0 on Cray currently fails testing in both client/server and
+ writeproxy modes.
+
+
+* Status
+
+ This experimental version of CVS contains new features which may not have
+ been tested as thoroughly as the stable release. It is classified as:
+
+ /*-------------.
+ | Experimental |
+ `-------------*/
+
+ /*-------------------------.
+ | Sane for full scale use. |
+ `-------------------------*/
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..57da8a4
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,251 @@
+[I have snipped the snail mail address of the FSF because it has
+changed in the past and is likely to change again. The current
+address should be at http://www.gnu.org/]
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The license agreements of most software companies try to keep users
+at the mercy of those companies. By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must tell them their rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License. The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications. Each
+licensee is addressed as "you".
+
+ 1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program. You may charge a fee for the physical act of
+transferring a copy.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating that
+ you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish, that
+ in whole or in part contains the Program or any part thereof, either
+ with or without modifications, to be licensed at no charge to all
+ third parties under the terms of this General Public License (except
+ that you may choose to grant warranty protection to some or all
+ third parties, at your option).
+
+ c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the simplest and most usual way, to print or display an
+ announcement including an appropriate copyright notice and a notice
+ that there is no warranty (or else, saying that you provide a
+ warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this General
+ Public License.
+
+ d) You may charge a fee for the physical act of transferring a
+ copy, and you may at your option offer warranty protection in
+ exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+ 3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+ a) accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal charge
+ for the cost of distribution) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it. For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+ 4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License. However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+ 5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+
+ 7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+ 8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+ To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19xx name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (a program to direct compilers to make passes
+ at assemblers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/COPYING.LIB b/COPYING.LIB
new file mode 100644
index 0000000..5e5cda2
--- /dev/null
+++ b/COPYING.LIB
@@ -0,0 +1,484 @@
+[I have snipped the snail mail address of the FSF because it has
+changed in the past and is likely to change again. The current
+address should be at http://www.gnu.org/]
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..665f7e4
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,7109 @@
+2005-10-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note ZLib security issues.
+
+2005-09-30 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Mention Conrad's Windows client fix.
+
+2005-09-28 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Consolidate TmpDir with the other new config keys.
+
+2005-09-26 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note FreeBSD 5.x GSSAPI fix.
+
+ * NEWS: Note fsync'd commits.
+
+2005-09-25 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add files (lib\getdelim.h lib\setenv.h) to project.
+
+ * cvsnt.dep: Regenerated for "cvsnt.dsp" changes.
+
+2005-09-24 Derek Price <derek@ximbiot.com>
+
+ * NEWS, HACKING: Standardize on Automake 1.9.6.
+
+2005-09-22 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Mention conflict fixes.
+
+2005-09-20 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add files (lib\canon-host.h lib\glob-libc.h) to project.
+
+ * cvsnt.dep: Regenerated for "cvsnt.dsp" changes.
+
+2005-09-19 Derek Price <derek@ximbiot.com>
+
+ * maint-aux/gnulib-update: Default $GNULIB path rather than setting.
+ Check for error return from gnulib-tool before expecting results.
+
+2005-09-13 Derek Price <derek@ximbiot.com>
+
+ * TESTS: Mention new $username8 & $anyusername variables.
+
+2005-09-06 Derek Price <derek@ximbiot.com>
+
+ * TESTS: Reword slightly. s/\$PROG/\$CPROG/. Document $tempfile &
+ $tempname.
+
+ * NEWS: Note Kerberos4 build fix.
+
+2005-09-05 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note TmpDir config key. Reorder config news items. Reword
+ the [root] specification item.
+
+ * configure.in (--enable-config-override): Verify $prefix is set before
+ expanding $sysconfdir.
+
+2005-09-04 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove putenv cruft.
+
+ * maint-aux/gnulib-modules: Add glob.
+
+ * NEWS: Note new [root] specification in config files.
+
+ * configure.in: Remove unneeded search for hstrerror.
+ * maint-aux/gnulib-modules: Add canon-host.
+
+2005-09-04 Larry Jones <lawrence.jones@ugs.com>
+
+ * NEWS: s/bug-cvs@gnu.org/bug-cvs@nongnu.org/.
+ * configure.in: s/info-cvs@gnu.org/info-cvs@nongnu.org/.
+ * configure: Regenerated.
+
+2005-09-03 Larry Jones <lawrence.jones.ugs.com>
+
+ * configure: Regenerated.
+
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * DEVEL-CVS, FAQ, HACKING, INSTALL-CVS, README, README.VMS,
+ configure.in, build-aux/bison-missing: Update links and email
+ addresses.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * www/.htaccess: Remove this file.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * cvs.spec.in: Note last spec file change in internal ChangeLog.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note spec file repair.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * cvs.spec.in: Update links to point to Savannah. s/Copyright/License/
+ for RPM 4.mumble.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note configurable config file path.
+ * configure.in (--enable-config-override): New option.
+
+2005-08-30 Larry Jones <lawrence.jones@ugs.com>
+
+ * NEWS: Note import locking fix.
+
+2005-08-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new verifymsg %{sV} format strings.
+
+2005-08-04 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Move 1.12 change from BUG FIXES to NEW FEATURES and rephrase.
+ Correct spelling error in different entry.
+
+2005-07-20 Derek Price <derek@ximbiot.com>
+
+ * AUTHORS, HACKING, README, cvs.spec.in:
+ s/cvshome.org/nongnu.org.etc.../.
+ * DEVEL-CVS: Ditto. Remove devel-cvs mailing list charter.
+
+2005-07-12 Derek Price <derek@ximbiot.com>
+
+ * FAQ, HACKING, INSTALL: Add copyright notices.
+
+2005-07-11 Derek Price <derek@ximbiot.com>
+
+ * FAQ, HACKING, INSTALL-CVS: Update license notices.
+
+2005-06-15 Derek Price <derek@ximbiot.com>
+
+ * build-aux/missing: Add hack to fail gracefully when Bison is too old.
+
+2005-06-15 Derek Price <derek@ximbiot.com>
+
+ * HACKING: Note GNU Bison 1.875 requirement.
+
+2005-06-12 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add file "lstat.h" to project.
+ * cvsnt.dep: Regenerate for "cvsnt.dsp" change.
+
+2005-06-10 Derek Price <derek@ximbiot.com>
+
+ * maint-aux/gnulib-modules: Remove stat module.
+
+2005-06-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * HACKING: Add a few more guidelines. Adjust examples for switch
+ labels. Fix some spelling mistakes.
+ * cvs-format.el (c-label-offset, case-label): Adjust indentation
+ to agree with changes in the HACKING document.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * HACKING: Remove `!= NULL' in example conditional.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new server compression limit config options. Correct
+ HistorySearchPath name.
+
+2005-06-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note server compression hang fix.
+
+2005-06-01 Derek Price <derek@ximbiot.com>
+
+ * TODO (214): Remove completed item.
+
+2005-06-01 Conrad T. Pino <Conrad@Pino.com>
+
+ * makewin32.cmd: Add options to support CLEAN build target.
+
+2005-06-01 Conrad T. Pino <Conrad@Pino.com>
+
+ * makewin32.cmd: Add Windows NT command file to build CVS Project.
+
+2005-05-31 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dep: Regenerate after build for #include changes.
+
+2005-05-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add files "lib/quotearg.h", "lib/stat-macros.h",
+ "windows-NT/woe32.h" and "windows-NT/unistd.c" to project.
+ * cvsnt.dep, cvsnt.mak: Regenerate for "cvsnt.dsp" changes.
+
+2005-05-27 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note diff space split fix.
+ * BUGS: Remove diff space split note.
+
+2005-05-27 Derek Price <derek@ximbiot.com>
+
+ * maint-aux/gnulib-modules: Add quotearg module.
+
+2005-05-26 Derek Price <derek@ximbiot.com>
+
+ * maint-aux/gnulib-modules: Add stat-macros module.
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * maint-aux/gnulib-modules: Add getlogin_r module.
+
+2005-05-24 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add lib/canonicalize.h and lib/glob.h to project.
+ * cvsnt.dep: Regenerate for cvsnt.dsp changes.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * maint-aux/gnulib-modules: Add GNULIB canonicalize module.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update Copyright years.
+
+2005-05-17 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dep: Regenerated for "lib/libcvs.dsp" change.
+
+2005-05-11 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new History* config options.
+ * maint-aux/gnulib-filelist.txt: Add strdup module.
+
+2005-05-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dep, cvsnt.mak: Regenerated after Windows full rebuild.
+
+2005-05-09 Derek Price <derek@ximbiot.com>
+
+ * cvs.spec.in: Find install-sh in its new location.
+
+2005-05-06 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Solaris 10 command option parsing fix.
+
+2005-05-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * maint-aux/gnulib-update: Depend on maint-aux/gnulib-modules
+ which needs to exist relative to the top-level directory rather
+ than config.h which may be sitting in a build subdirectory.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * INSTALL-CVS: Add footnote about compiling a CVS checkout of CVS on a
+ case-insensitive UNIX file system like Mac OS X.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note GNULIB updates as misc efficiency and portability fixes.
+
+2005-05-02 Derek Price <derek@ximbiot.com>
+
+ * TODO (231): New item.
+ (22, 30, 31): Remove completed items.
+
+2005-05-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new val-tags locks.
+
+2005-05-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that lock compatibility is now enabled on Windows by
+ default.
+
+2005-05-01 Mark D. Baushke <mdb@cvshome.org>
+
+ * maint-aux/gnulib-filelist.txt: Update from GNULIB.
+ * configure: Regenerated.
+
+2005-04-30 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new history locks.
+
+2005-04-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in: Add support for <pam/pam_appl.h> to allow
+ --enable-pam to work on MacOSX 10.2 and newer.
+ (Pach from Moriyoshi Koizumi <moriyoshi@at.wakwak.com>.)
+ * configure, config.h.in: Regenerated.
+
+2005-04-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note log overflow fix.
+
+2005-04-15 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Klocwork fixes.
+
+2005-04-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note contrib Perl taint vulnerability fix.
+
+2005-04-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Avoid self-aggrandizement.
+
+2005-04-08 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note GMT/get_date fix.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * gnulib.txt: Move to...
+ * gnulib-filelist.txt: ...this new file.
+ * gnulib-update: Clean up slightly. Use new file.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * maint-aux/.cvsignore: New file.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Generate maint-aux/Makefile.
+ * Makefile.am (SUBDIRS): Add maint-aux.
+ * maint-aux/Makefile.am, maint-aux/Makefile.in: New files.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * gnulib-modules, gnulib-update, gnulib.txt, srclist.txt: Move these...
+ * maint-aux: ...to this new directory, with minor modifications.
+ * Makefile.am (EXTRA_DIST): Accomodate move of the above files. Add
+ maint-aux/gnulib-modules.
+ * HACKING: s#srclist.txt#maint-aux/srclist.txt#.
+
+2005-04-05 Derek Price <derek@ximbiot.com>
+
+ * mkinstalldirs: Remove this obsolete file. It's work is now done by
+ `build-aux/install-sh -d'.
+
+2005-04-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Specify new build-aux directory for auxiliary build
+ files.
+ * compile, config.guess, config.rpath, config.sub, depcomp, install-sh,
+ mdate-sh, missing, texinfo.tex, ylwrap: Move to...
+ * build-aux: ...this new directory.
+ * INSTALL: Replace with generic version from Automake, moving...
+ * INSTALL-CVS: ...original to here. Reference INSTALL for more
+ configure information.
+ * FAQ, README: Reference INSTALL-CVS rather than INSTALL.
+
+2005-03-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.guess, config.rpath, config.sub, depcomp, gnulib.txt,
+ install-sh, mdate-sh, missing, mkinstalldirs: Update from GNULIB.
+ * configure: Regenerated.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * aclocal.m4, gnulib.txt: Update from GNULIB.
+ * Makefile.in, config.h.in, configure: Regenerated.
+
+2005-03-16 Mark Baushke <mdb@cvshome.org>
+
+ * cvs-format.el: Update to work with modern GNU Emacs versions
+ that have cc-mode instead of c-mode.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that writeproxy primary failures are now detected.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that failure to open debug logs is no longer fatal.
+
+2005-03-15 Derek Price <derek@ximbiot.com>
+
+ * HACKING, NEWS: Note new Automake version.
+
+2005-03-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure: Regenerated.
+
+2005-03-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Don't generate windows-NT/mkconfig or
+ windows-NT/fix-msvc-mak.
+ * configure: Regenerated.
+
+2005-03-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add .\lib\closeout.h, .\lib\getpagesize.h and
+ .\lib\pagealign_alloc.h files.
+ * cvsnt.dep, cvsnt.mak: Regenerate for cvsnt.dsp changes.
+
+2005-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in, configure: Regenerated.
+
+2005-03-04 Jim Hyslop <jhyslop@ieee.org>
+
+ * NEWS: Note fix for compile errors on IRIX 5.3.
+
+2005-03-03 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove checks for valloc and mmap.
+ * gnulib-modules: Add pagealign_alloc.
+ * NEWS: Note new buffer allocation method.
+
+2005-03-03 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update: Clean up "saved" files on interrupt.
+
+2005-03-02 Jim Meyering <jim@meyering.net>
+
+ * NEWS: Note that cvs now detects write errors on stdout.
+ * gnulib-modules: Add closeout.
+ * gnulib.txt: Regenerate.
+
+2005-03-02 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove checks for funcs covered by GNULIB.
+
+2005-03-02 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update: Redirect gnulib-tool output back to /dev/null.
+
+2005-03-02 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update: Avoid munging timestamps when files haven't changed.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note GNULIB update. Expand --disables-* note.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update: Correct m4/error.m4 to avoid compiling the GNULIB
+ lib/error.c.
+ (MODULES): Move content to...
+ * gnulib-modules: This new file.
+
+2005-02-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note commitid feature.
+ (Patch from Frank Hemer <frank@hemer.org>.)
+
+2005-02-24 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Disable proxy when either the client or server are
+ disabled. Other minor cleanup.
+ * NEWS: Note --disable-client fix.
+
+2005-02-23 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note -r<tag>:<date> change.
+
+2005-02-21 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note zlib update.
+ * srclist.txt: Note new source for zlib.
+
+2005-02-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note `cvs -n release' fix.
+
+2005-02-19 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--with-rsh): Prefer ssh to rsh.
+ * NEWS: Note this.
+
+2005-02-04 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note zlib fix.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * AUTHORS: Add Conrad Pino.
+ * README: Update copyright notice.
+
+2005-01-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note some recent changes.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note no-longer missing files.
+ * Makefile.am (EXTRA_DIST): Add m4/README, gnulib-update, gnulib.txt,
+ and srclist.txt.
+ * configure.in (AC_OUTPUT): Add doc/i18n/Makefile &
+ doc/i18n/pt_BR/Makefile.
+
+2004-12-13 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Windows build fixes.
+
+2004-12-09 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note `Redirect' CVSROOT method option and doc improvements.
+
+2004-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * README: Remove Dr. Pascal Molli's CVS URL from the
+ documentation.
+ * FAQ: Ditto.
+
+2004-12-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: Document new CVSROOT options and case insensitivity.
+
+2004-11-30 Mark D. Baushke <mdb@cvshome.org>
+
+ * HACKING (Coding standards): Add the primary URL for the GNU
+ coding standards.
+
+2004-11-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "src/subr.h" to project.
+ * cvsnt.dep: Regenerated for "cvsnt.dsp" change.
+ * cvsnt.mak: Regenerated for "cvsnt.dsp" change.
+
+2004-11-21 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvsnt.dep: Add "xgethostname.h" to project.
+ * cvsnt.dsp: Add "xgethostname.h" to project.
+
+2004-11-20 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove note about BSDI test failure.
+
+2004-11-19 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add xgethostname.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note "red file" fix source inclusion.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Windows distribution fix.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note most recent GNULIB update.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note current CVS test failures on BSD/OS & Cray.
+
+2004-11-11 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note current CVS server turds on AIX.
+
+2004-11-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in, configure: Regenerated.
+
+2004-11-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure: Regenerated.
+
+2004-11-04 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Remove "lib/allocsa.c", "lib/readlink.c", "lib/xreadlink.c"
+ and "allocsa.h" from project.
+ * cvsnt.dep: Regenerate for "cvsnt.dsp" change.
+ * cvsnt.mak: Regenerate for "cvsnt.dsp" change.
+
+2004-11-04 Derek Price <derek@ximbiot.com>
+
+ * TODO (233): New item.
+
+2004-11-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvsnt.dsp: Add entries for allocsa.c and allocsa.h.
+ * cvsnt.dep: Re-order sources in front of includes.
+ * Makefile.am: Update allocsa from GNULIB.
+ * gnulib.txt, Makefile.gnulib: Regenerated.
+
+2004-11-03 Derek Price <derek@ximbiot.com>
+
+ * HACKING, NEWS: Note new Autoconf & Automake versions.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvsnt.dsp: Add readlink.c, xreadlink.c and xreadlink.h.
+ * cvsnt.dep: Add readlink.c and xreadlink.c dependencies.
+
+ * gnulib-update (MODULES): Add readlink xreadlink.
+ * Makefile.in, aclocal.m4, configure, configure.in, gnulib.txt:
+ Regenerated.
+
+2004-11-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in, configure: Regenerated.
+
+2004-11-01 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dep: Regenerated for "lib/libcvs.dsp" change.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new date format documentation.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that CVS handles new time zones.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Remove getdate module.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add allocsa, setenv, getdate.
+
+2004-10-30 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in: Add AC_SEARCH_LIBS for hstrerror in resolv to also
+ define HAVE_HSTRERROR if it is found.
+ * configure: Regenerated.
+
+2004-10-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in: Add AC_SEARCH_LIBS for hstrerror in resolv.
+ * configure: Regenerated.
+
+2004-10-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note xreadlink fix.
+
+2004-10-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "lib/yesno.h" to project.
+ * cvsnt.dep: Regenerate for "cvsnt.dsp" change.
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note GSSAPI error message fix.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add yesno.
+
+2004-10-23 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dep: Regenerate for "lib/libcvs.dsp" change.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvsnt.dsp: Add "windows-NT/stdint.h" to project.
+ * cvsnt.dep: Regenerated.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure: Regenerated.
+
+2004-10-22 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "lib/strftime.h" to project.
+ * cvsnt.dep: Regenerate for "cvsnt.dsp" change.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * gnulib-update (MODULES): Add stdint.
+ * Makefile.in, aclocal.m4, config.h.in, configure, gnulib.txt:
+ Regenerated.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am (proxycheck): Add new test target.
+ * Makefile.in: Regenerated.
+
+2004-10-22 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add md5.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Backout addition of rpmatch & yesno.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (error): Update from GNULIB.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add rpmatch & yesno.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add getpagesize.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add xsize module explicitly.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove outdated comment.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_GNU_STRFTIME.
+ * gnulib-update (MODULES): Add strftime module.
+ * srclist.txt: Remove GNULIB strftime module.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to jm_REALLOC.
+ * gnulib-update (MODULES): Add realloc module.
+ * srclist.txt: Remove GNULIB realloc module.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to jm_MALLOC.
+ * gnulib-update (MODULES): Add malloc module.
+ * srclist.txt: Remove GNULIB malloc module.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * TODO (22, 31): Remove completed items.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove ls assertion failure bug.
+
+2001-10-21 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dep: Regenerated for "../zlib/lib.dsp" change.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note `cvs ls filename' fix.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in (ccvs_FUNC_SELECT): Work around Solaris 7 select()
+ hang.
+ * Makefile.in, aclocal.m4, config.h.in, configure:
+ Regenerate for new configure.in.
+
+2004-10-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note validate_repo change.
+
+2004-10-19 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note resurrection fix.
+
+2004-10-19 Derek Price <derek@ximbiot.com>
+
+ * HACKING (Portability): Note assumption of sys/stat.h.
+
+2004-10-16 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "lib/vasprintf.h" to project.
+ * cvsnt.dep: Regenerate for "cvsnt.dsp" change.
+ * cvsnt.mak: Regenerate for "cvsnt.dsp" change.
+
+2004-10-15 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add vasprintf.
+
+2004-10-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new import branch verification.
+
+2004-10-10 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_STRERROR.
+ * gnulib-update (MODULES): Add strerror.
+ * srclist.txt (strerror): Remove list generated by gnulib-update.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_LSTAT.
+ * gnulib-update (MODULES): Add lstat.
+ * srclist.txt (lstat): Remove list generated by gnulib-update.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_STAT.
+ * gnulib-update (MODULES): Add stat.
+ * srclist.txt (stat): Remove list generated by gnulib-update.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_NANOSLEEP.
+ * gnulib-update (MODULES): Add nanosleep.
+ * srclist.txt (nanosleep): Remove list generated by gnulib-update.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_MEMMOVE.
+ * gnulib-update (MODULES): Add memmove.
+ * srclist.txt (memmove): Remove list generated by gnulib-update.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add minmax.
+ * srclist.txt (minmax): Remove list generated by gnulib-update.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_TIME_R, gl_FUNC_MKTIME.
+ * gnulib-update (MODULES): Add restrict, time_r, & mktime.
+ * srclist.txt (restrict, time_r, mktime): Remove lists generated by
+ gnulib-update.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_TZSET_CLOBBER.
+ * gnulib-update (MODULES): Add tzset.
+ * srclist.txt (tzset): Remove list generated by gnulib-update.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_GLIBC_UNLOCKED_IO.
+ * gnulib-update (MODULES): Add unlocked-io.
+ * srclist.txt (unlocked-io): Remove list generated by gnulib-update.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_GETTIME.
+ * gnulib-update (MODULES): Add gettime.
+ * srclist.txt (gettime): Remove list generated by gnulib-update.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * HACKING, NEWS: Note new Autoconf & Automake version requirements.
+ * Makefile.am (SUBDIRS): Remove m4.
+ (EXTRA_DIST): Distribute m4/ChangeLog.
+ * configure.in (AM_INIT_AUTOMAKE): Require Automake 1.9.2.
+ (AC_PREREQ): Require Automake 2.59.
+
+2004-10-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "lib/getpass.h" and "lib/strcase.h" to project.
+ * cvsnt.dep: Regenerate for "cvsnt.dsp" change.
+ * cvsnt.mak: Regenerate for "cvsnt.dsp" change.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_TIMESPEC.
+ * gnulib-update (MODULES): Add timespec.
+ * srclist.txt (timespec): Remove list generated by gnulib-update.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to AC_FUNC_GETTIMEOFDAY_CLOBBER.
+ * gnulib-update (MODULES): Add gettimeofday.
+ * srclist.txt (gettimeofday): Remove list generated by gnulib-update.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_GETPASS.
+ * gnulib-update (MODULES): Add getpass.
+ * srclist.txt (getpass): Remove list generated by gnulib-update.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add strcase.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_GETHOSTNAME.
+ * gnulib-update (MODULES): Add gethostname.
+ * srclist.txt (gethostname): Remove list generated by gnulib-update.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove calls to AM_FUNC_GETLINE, gl_GETNLINE,
+ & gl_GETNDELIM2.
+ * gnulib-update (MODULES): Add getline, getnline, & getndelim2.
+ * srclist.txt (getline, getnline, getndelim2): Remove lists now
+ generated by gnulib-update.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to AM_STDBOOL_H.
+ * gnulib-update (MODULES): Add stdbool.
+ * srclist.txt (stdbool): Remove list now generated by gnulib-update.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_GETOPT.
+ * gnulib-update (MODULES): Add getopt.
+ * srclist.txt (getopt): Remove list now generated by gnulib-update.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to UTILS_FUNC_MKSTEMP.
+ * gnulib-update (MODULES): Add mkstemp.
+ * srclist.txt (mkstemp): Remove list now generated by gnulib-update.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_FUNC_FNMATCH_POSIX.
+ * gnulib-update (MODULES): Add fnmatch & fnmatch-posix.
+ * srclist.txt (fnmatch, fnmatch-posix): Remove list now generated by
+ gnulib-update.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add extensions.
+ * srclist.txt (extensions): Remove list now generated by gnulib-update.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_EXITFAIL.
+ * gnulib-update (MODULES): Add exitfail.
+ * srclist.txt (exitfail): Remove list now generated by gnulib-update.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update (MODULES): Add exit.
+ * srclist.txt (exit): Remove list now generated by gnulib-update.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (xalloc): Remove list since it is now generated by
+ gnulib-update.
+
+2004-10-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "lib/save-cwd.h" and "lib/xgetcwd.h" to project.
+ * cvsnt.dep: Regenerated for "cvsnt.dsp" change.
+ * cvsnt.mak: Regenerated for "cvsnt.dsp" change.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to gl_DIRNAME.
+ * gnulib-update (MODULES): Add dirname.
+ * srclist.txt: Remove auto-updated GNULIB modules.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * gnulib.txt: New file.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * gnulib-update: Keep track of file changes.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Consolidate some GNULIB macro calls into a call to the
+ autogenerated gl_INIT.
+ * gnulib-update: New script.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Rename some GNULIB macro calls.
+ * srclist.txt (gettext, vasnprintf, shared): Add new files.
+ * config.rpath: Import new version from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_SAVE_CWD.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_XGETCWD.
+ * srclist.txt (xgetcwd): New module.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (pathmax): Remove dependency on onceonly_2_57.m4.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (unlocked-io): Remove dependency on onceonly_2_57.m4.
+
+2004-10-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "lib/dirname.h" and "src/parseinfo.h" to project.
+ * cvsnt.dep: Regenerated for "cvsnt.dsp" change.
+ * cvsnt.mak: Regenerated for "cvsnt.dsp" change.
+
+2004-10-04 Derek Price <derek@ximbiot.com>
+
+ * TODO: Item 180 is now done (cvs edit should report editors).
+ It reports editors as long as it can successfully contact the
+ server. (Part of advisary locks patch originally from Noel Yap
+ <yap_noel@yahoo.com>, originally ported forward and enhanced by Matthew
+ Ogilvie <mmo9317bd@mailcan.com>.)
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * configure.in (getpass): Don't define twice.
+ (Report and original patch from Martin Neitzel
+ <neitzel@sco.gaertner.de>.)
+
+2004-09-25 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Use doc/mkman.pl as source for doc/mkman.
+
+2004-09-23 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: Fix spelling.
+ (Reported by Shane Turner <shane.turner@infointeractive.com>.)
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Correct file cache note.
+ * configure.in (--enable-trust-file-cache): Remove option.
+
+2004-09-16 Derek Price <derek@ximbiot.com>
+
+ * HACKING: Correct obsolete note about configure not remembering -Wall.
+
+2004-09-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note potential new Log keyword expansion behaviors.
+
+2004-09-13 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: Note change to contrib/cvs_acls and addition of
+ contrib/cvs_acls.html
+
+2004-09-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dep: Regenerated for "cvsnt.dsp" changes made 2004-09-08.
+ * cvsnt.mak: Regenerated for "cvsnt.dsp" changes made 2004-09-08.
+
+2004-09-08 Conrad T. Pino <Conrad@Pino.com>
+
+ * cvsnt.dsp: Add "windows-NT/JmgStat.c" to project. Add
+ "windows-NT/JmgStat.h" to project. Add "src/ms-buffer.h" to project.
+
+2004-09-07 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Windows DST fix.
+ * srclist.txt: Add Windows stat files.
+
+2004-09-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new commit message format.
+
+2004-09-03 Derek Price <derek@ximbiot.com>
+
+ * HACKING: Codify backwards compatibility conventions. Remove outdated
+ reference to very old MSVC++ releases.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Mention Juniper's funding for other items.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Enable proxy support by default.
+ * NEWS: Note this.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * configure.in: s/SECONDARY_SUPPORT/PROXY_SUPPORT/.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note recent attempts at improving I/O efficiency.
+ * configure.in (--enable-file-cache-trust): New option.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Credit Juniper Networks funding for writeproxy code and add a
+ few other details.
+
+2004-08-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--enable-proxy): Switch to turn off writeproxy support.
+
+2004-06-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new scripting hooks and new loginfo behavior.
+
+2004-06-28 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Note minmax imported from GNULIB.
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * Note addition of write proxy functionality.
+
+2004-08-30 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note compliance of log_accum.pl with Perl 5.8.5.
+
+2004-08-27 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Note minmax imported from GNULIB.
+
+2004-08-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--enable-file-cache-trust, --enable-proxy): New
+ options.
+
+2004-08-25 Derek Price <derek@ximbiot.com>
+
+ * TODO (232): New item.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * TODO (24, 49, 92, 113): Remove completed/obsolescent items.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove release subdir note. This was fixed with the commit on
+ 2004-02-25, based on Matthew Ogilvie's patch.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note r* . fix.
+ * BUGS: Remove r* . note.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note invalid tag fix.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note error message corrections.
+
+2004-08-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: Note that modules -a bugfix has a change in behavior.
+
+2004-06-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new scripting hooks and val-tags behavior.
+
+2004-07-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: Add note about new ImportNewFilesToVendorBranchOnly
+ option.
+
+2004-07-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note PAM session management support.
+
+2004-07-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Generate contrib/pam/Makefile.
+ * NEWS: Note distribution of sample PAM configs.
+ (Thanks to a report from Brian Murphy <brian@murphy.dk>.)
+
+2004-07-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note improved time zone handling. Attribute previous change.
+
+2004-07-12 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update copyright year.
+
+2004-06-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note client/server sending short repositories.
+
+2004-06-24 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dsp: Add "./lib/xsize.h" to Header file list.
+ * cvsnt.dep: Regenerated for "./cvsnt.dsp" change.
+ (Patch submitted by Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-06-22 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Conrad's Windows fix.
+
+2004-06-21 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore GPG signature files for distributions.
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note manual update.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Stefan & Sebastian's security fixes.
+ * acinclude.m4 (gl_SIZE_MAX, gl_XSIZE): Import from GNULIB.
+ * configure.in: Call gl_XSIZE.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note CAN-2004-0414 fix.
+
+2004-06-02 Derek Price <derek@ximbiot.com>
+
+ * TODO (231): New item.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add calls to gl_FUNC_TZSET_CLOBBER &
+ gl_FUNC_GNU_STRFTIME.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+ * srclist.txt (strftime): New module.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (tzet): New GNULIB module.
+ * configure: Regenerated.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add `cvs ls' to localtime item. 1.12.9, not 1.12.8.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * TODO (224): Remove completed item.
+ (Patch from Bart Robinson <lomew@pobox.com>.)
+
+ * NEWS: Note new local time output.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note generation of windows-NT/config.h.in.
+ * configure.in: Use new plhead.pl for windows-NT/fix-msvc-mak. Add
+ windows-NT/mkconfig target.
+ * configure: Regenerated.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note CAN-2004-0396 fix.
+
+2004-05-17 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dsp: Add "lib/xtime.h" to project header files.
+ * cvsnt.dep: Regnerated for "cvsnt.dsp" file change.
+
+2004-05-17 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note assertion failure of r* commands.
+
+2004-05-17 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note current `cvs ls' assertion failure. Remove out of date
+ comment about out of date Windows build files and several bug reports
+ that are so old, without similar recent reports, that I'm assuming that
+ the problems have been fixed.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ Back out getdate.y update.
+ * NEWS: Remove note about half-hour time zones.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dsp: Move "lib/*.c" to project "lib/libcvs". Header file list
+ updated for GNULIB updates.
+ * cvsnt.dep: Regenerated for "cvsnt.dsp" change.
+ * cvsnt.mak: Regenerated for "cvsnt.dsp" change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-05-11 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note commit output suppression.
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Note bison.m4 forked from GNULIB.
+ * aclocal.m4, configure: Regenerated.
+
+2004-05-02 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call AC_FUNC_STRERROR_R.
+ * srclist.txt (error): New module, kinda.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that man page is generated from cvs.texinfo now.
+ * configure.in: Build doc/mkman.
+ * configure, Makefile.in: Regenerated.
+
+2004-04-29 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove AC_PROG_YACC invocation in favor of gl_BISON.
+ * configure: Regenerated.
+
+2004-04-29 Derek Price <derek@ximbiot.com>
+
+ * configure.in: s/jm_FUNC_GLIBC_UNLOCKED_IO/gl_FUNC_GLIBC_UNLOCKED_IO/.
+ * aclocal.m4, configure: Regenerated.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * ylwrap: Add from Automake to support YACC.
+ * Makefile.in: Regenerated.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note half-hour timezone strings handled.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_GETDATE and remove obsoleted cruft.
+ * srclist.txt (getdate): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_FUNC_MKTIME.
+ * srclist.txt (mktime): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_TIME_R.
+ * srclist.txt (time_r): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_FUNC_NANOSLEEP.
+ * srclist.txt (nanosleep): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_GETTIME.
+ * srclist.txt (gettime): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call AC_FUNC_GETTIMEOFDAY_CLOBBER.
+ * srclist.txt (gettimeofday): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_TIMESPEC.
+ * srclist.txt (timespec): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Replace calls to AC_AIX, AC_MINIX, & AC_GNU_SOURCE
+ with gl_USE_SYSTEM_EXTENSIONS.
+ * srclist.txt (extensions): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (dirname): Mark as not forked.
+ * aclocal.m4: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ Add dirname module from GNULIB.
+
+ * configure.in: Use gl_DIRNAME.
+ * srclist.txt (dirname): New module.
+ * Makefile.in, aclocal.m4, config.h.in, configure: Regenerated.
+
+2004-04-26 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that :ext: no longer relies on an external transport with
+ a GNU argument processor.
+
+2004-04-26 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dsp: Add ls.c & stdbool.h as dependencies.
+ * cvsnt.dep, cvsnt.mak: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new cvs ls subcommand.
+ (Thanks for patches from Mark D Baushke <mdb@cvshome.org>
+ & Alexander Taler <dissent@cvshome.org>.)
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dep, cvsnt.mak: Back out previous change.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dep, cvsnt.mak: Regenerated.
+
+2004-04-21 Derek Price <derek@ximbiot.com>
+
+ Add stdbool module from GNULIB.
+
+ * HACKING: Note availability of stdbool, fnmatch, alloca & GNULIB
+ substitutes in general.
+ * configure.in: Call AM_STDBOOL_H.
+ * srclist.txt: Add stdbool.
+ * aclocal.m4, configure, config.h.in, Makefile.in: Regenerated.
+
+2004-04-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note XP directory deletion fix.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Regenerated for "zlib/libz.dsp" change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-17 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dsw, cvsnt.dsp: Rename "lib/lib.*" to "lib/libcvs.*" and
+ "zlib/zlib.*" to "zlib/libz.*".
+ * cvsnt.dep, cvsnt.mak: Regenerated.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-16 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Correct CVS name for piped checkout issue now that we have one.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dsp: Set PROP BASE directories to projet standard,
+ synchronize ADD BASE statements with ADD counter part,
+ remove child note property overrides which taken together
+ reduce file size and "Reset" function uses project defaults.
+ Place project libraries first in link library order.
+ * cvsnt.mak: Regenerated for cvsnt.dsp change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dep: Regenerated for lib/lib.dsp change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Retroactively add CVE issue name for the piped etc issue.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Retroactively add CVE issue name for the trojan server issue.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dsp: Set default configuration on generated make files to
+ Win32 Debug.
+ (Patch from Conrad T. Pino <conrad@pino.com>.)
+ * cvsnt.dep, cvsnt.mak: Regenerated.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note MSVC++ project file regeneration.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add cvsnt.dep.
+ * Makefile.in: Regenerated.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dep: New generated file.
+ * cvsnt.mak: Regenerated.
+ (Original patch from Conrad T. Pino <conrad@pino.com>.)
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note use of POSIX.2 fnmatch.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * HACKING: s/cvsntfix.pl/fix-msvc-head.pl/.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Generate windows-NT/fix-msvc-mak.
+ * configure, Makefile.in: Regenerated.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * INSTALL (Building from source code under Unix): Move Autoconf &
+ Automake notes...
+ * HACKING (Regenerating Build Files (UNIX)): ...here.
+ (Regenerating Build Files (Windows)): New section.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ Update to current fnmatch module from GNULIB.
+
+ * configure.in: Call gl_FUNC_FNMATCH_POSIX.
+ (AC_CHECK_HEADERS): Don't bother checking for fnmatch.h - we can assume
+ it.
+ * srclist.txt: Note origins of fnmatch.
+ * aclocal.m4, config.h.in, configure, Makefile.in: Regenerated.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Remove cvsnt.dep.
+ * Makefile.in: Regenerated.
+
+2004-04-13 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note validation of paths passed to the client.
+
+2004-04-13 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note restriction of modules to within $CVSROOT.
+
+2004-04-07 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Clarify relative-path up-reference article.
+
+2004-04-07 Derek Price <derek@ximbiot.com>
+
+ Update regex module from GNULIB.
+
+ * NEWS: Note update.
+ * configure.in: Call gl_REGEX.
+ * srclist.txt: Note origins of regex module.
+ * Makefile.in, configure, config.h.in, aclocal.m4: Regenerated.
+
+2004-04-06 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note web proxy support.
+
+2004-04-06 Derek Price <derek@ximbiot.com>
+
+ * TODO (196, 217, 219, 220, 222, 226): Remove completed items.
+ (230): New item.
+
+2004-04-06 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note this change.
+ * configure.in: Do not try and use TMP, TEMP, or TMPDIR as default
+ temporary directories.
+ * configure: Regenerated.
+
+2004-04-05 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Note new location for GNULIB CVS repository.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Cygwin handles paths like X:\.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Windows ISDIRSEP fix.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Instruct users to use the Workspace file and not the project
+ file for MSVC++.
+ (Patch from Conrad T. Pino <conrad@pino.com>.)
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Make some notes as to client/serverness of changes.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note relative path fix.
+
+2004-04-01 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Record run race removal.
+
+2004-03-31 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note contrb script renames.
+ * configure.in: Rename contrib scripts.
+ * configure: Regenerated.
+
+2004-03-31 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.spec.in (BuildRequires): Do not fail if info DIR file does
+ not exist. (Not everyone has an install-info that generates the
+ dir file that we want deleted.)
+ (Report from Geoff Beier <geoff@caradas.com>.)
+
+2004-03-29 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Regenerated with VC++ 5.0.
+ (Original sent by Dennis Jones <djones@oregon.com>.)
+ * cvsnt.dep: Removed.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Print "Debug" when defaulting to Debug.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Default to using debugging symbols so that folks who don't
+ know enough to remove the debugging symbols might still be able to send
+ us stack traces after encountering problems.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dep, cvsnt.mak: Regnerated. Remove system specific
+ dependency reference.
+
+2004-03-27 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dep, cvsnt.mak: Regnerated.
+
+2004-03-26 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Note that build files have been regenerated with MSVC 6.0.
+
+2004-03-26 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Windows build file regeneration.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note failure of Cygwin to convert back slashes to slashes.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.spec.in (BuildRoot): Use a more unique directory name.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add cvsnt.dep.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.dep: New files created by Visual C++ 6.0.
+ * cvsnt.dsp, cvsnt.dsw, cvsnt.mak: Updated by Visual C++ 6.0.
+ * .cvsignore: Add and remove files for new MSVC++ setup.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Windows memory allocation fix.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Note compilation & --without-gssapi requirement for HPPA
+ with HP-UX 11.11.
+ (Report from Nicolas Vervelle <nicolas.vervelle@steria.com>.)
+
+2004-03-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note resurrection fixes.
+
+2004-03-18 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Back out previous NEWS change at Larry Jones' suggestion.
+
+2004-03-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note spelling fix.
+
+2004-03-17 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--enable-password-authentication-client): Correct
+ error message text.
+ * NEWS: Note this change.
+ * configure: Regenerated.
+
+2004-03-15 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note cvs release + Kerberos fix.
+
+2004-03-15 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Correct grammar in help text.
+ * configure: Regenerated.
+
+2004-03-15 Derek Price <derek@ximbiot.com>
+
+ * macintosh/.cvsignore: Complete pruning of directory started in 1999.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note resurrection fix.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note error & status message corrections.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note diff of added files against arbitrary revisions fix.
+
+2004-03-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Remove header comment fix note, per GNU coding standards.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note sanity.sh client/server message fix.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note add.c message changes.
+
+2004-03-13 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note server.c header comment fix.
+
+2004-03-13 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Restore since 1.12.5 section since 1.12.6 distcheck failed.
+
+2004-03-11 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak (alloca.obj, alloca.h): New targets.
+ (CLEAN): Clean generated headers.
+ (vasnprintf.c): Add dependency on alloca.h.
+
+2004-03-11 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Note unfork of lib/xsize.h.
+
+2004-03-07 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak (asnprintf, vasnprintf, printf-args, printf-parse):
+ New targets.
+ * srclist.txt: Note fork of lib/xsize.h.
+ * NEWS: Note that CVSROOT/*info scripts may not work as expected under
+ Windows.
+
+2004-03-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that directories and files named `CVS' are now also
+ rejected by import.
+
+2004-02-26 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak (cvs.exe): Build xmalloc.obj, not xalloc.obj.
+
+2004-02-26 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak (xmalloc.obj, xstrdup.obj): s/windows-NT/lib/.
+
+2004-02-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note `checkout -d' behavior change.
+
+2004-02-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Update dying gasp note.
+
+2004-02-25 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak (exitfail.obj): s/windows-NT/lib/.
+
+2004-02-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note `cvs release' Entries corruption fix.
+
+2004-02-24 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Add xstrdup, xalloc, exitfail.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that the dying gasp check has now been completely removed.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ Import xalloc module from GNULIB, as well as its remaining unimported
+ dependency, the exitfail module.
+
+ * NEWS: Note addition of xalloc & vasnprintf modules from GNULIB.
+ * configure.in: Call gl_XALLOC & gl_EXITFAIL.
+ * cvsnt.mak: Add new objects & sources.
+ * srclist.txt (exitfail, xalloc): New GNULIB modules.
+ * Makefile.in, aclocal.m4, configure: Regenerated.
+
+2004-02-20 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * configure.in: Don't use grep -w, it's not portable.
+ * configure: Regenerated.
+
+2004-02-19 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * configure.in: Move the wint_t size check after all the base type
+ size checks and include the relevant header file, use "short" rather
+ than "short int" (ala "long" and "long long"), add a size check for
+ intmax_t, remove "CVSROOT/*" since it ends up embedded in a C
+ comment where the "/*" looks like an attempt to have a nested comment.
+ * config.h.in, configure: Regenerated.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * configure.in: AC_REQUIRE some HAVE_TYPE functions to avoid using
+ post-C89 constructs in the new format_cmdline stuff when they are not
+ available. Update comments. s/_LONG_INT\>/_LONG/i;
+ s/\<long int\>/long/. Don't check size of types that are not
+ available. Check size of size_t and ptrdiff_t.
+ * config.h.in, configure: Regenerated.
+
+2004-02-18 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Don't require AC_C_INLINE, now that m4/xsize.m4 does
+ this itself.
+ * aclocal.m4, configure: Regenerated.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * configure.in: added macros to set the UNIQUE_*_TYPE_* flags and
+ HAVE_STDINT_T (for intmax_t) for some stuff involving varargs in
+ format_cmdline() in src/run.c. UNIQUE_X_TYPE_Y means that
+ type Y (e.g. INT, SHORT_INT, or DOUBLE) is the first type, according
+ to an arbitrary order of precedence within type group X (e.g. INT or
+ FLOAT), that has a particular size, in bytes. Added
+ SUPPORT_OLD_INFO_FMT_STRINGS in order to make configurable whether to
+ support the old style info file command line format strings. The idea
+ is to deprecate the use of the old strings until one day this can be
+ switched to off. This option can be enabled/disabled with
+ --enable-old-info-format-support and --disable-old-info-format-support.
+ * HACKING (Run-time behaviors): Remove reference to Parse_Info not
+ accepting a void * argument.
+
+ * config.h.in: Regenerated.
+ * configure: Ditto..
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note spec file fix.
+ * cvs.spec: Update to avoid the error checking algorithm's of more
+ recent version of RPM.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note recent commenting of src/checkout.c and Mark's leak fixes.
+
+2004-02-16 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * configure.in: Add AC_C_INLINE for vasnprintf and friends.
+ * config.h.in, configure: Regenerated.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import vasnprintf module from GNULIB.
+ * configure.in: Call gl_FUNC_VASNPRINTF.
+ * srclist.txt: Add vasnprintf module.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import xsize module from GNULIB for vasnprintf().
+ * configure.in: Call gl_XSIZE.
+ * srclist.txt: Add xsize module.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import alloca module from GNULIB for vasnprintf().
+ * configure.in: Use gl_FUNC_ALLOCA.
+ * srclist.txt: Add alloca module.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note GNULIB updates.
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Mark D. Baushke's recent memory leak plugs.
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Ville Skyttä's other recent man page patch.
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note lock wait seg fault fix.
+
+2004-02-11 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note :fork: segfault avoidance.
+
+2004-02-11 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note readability improvements.
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note dying gasp check.
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note flow control pipe race fix.
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note problems building with MSVC++ under Windows and
+ workaround.
+ * INSTALL: Ditto.
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Add stack.c and stack.h in order to compile under Windows.
+ * README: Update copyright notice.
+
+2004-02-09 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new tests in sanity.sh.
+
+2004-02-06 Derek Price <derek@ximbiot.com>
+
+ * README: Undo accidental overwrite.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that alias module recursion is now more comprehensive.
+
+2004-02-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note case insensitive client directory case preservation.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Correct "error message" from two commits back to read
+ "status mesage".
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new join-rm tests.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note update error message correction.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that the server no longer claims to support the "Case"
+ request.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Ammend last note to specify the continued lack of any server
+ support for case insensitive clients more clearly.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that client handling of case insensitivity is restored.
+
+2004-01-30 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note man page fix.
+
+2004-01-30 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note contrib/log_accum tidy.
+
+2004-01-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Kerberos 4 fix.
+
+2004-01-22 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note recent infinite alias loop fix.
+
+2004-01-22 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Remove a note about an Automake bug that has been fixed for
+ quite awhile.
+
+2004-01-22 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: s/Automake 1.7.5/Automake 1.7.9/.
+
+2004-01-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Larrys recent mktemp.sh inclusion, documentation reorg,
+ and zlib code fix.
+
+2003-12-23 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * Makefile.am: Add mktemp.sh to EXTRA_DIST.
+ * Makefile.in: Regenerated.
+
+ * configure.in: Get mktemp.sh from $srcdir.
+ * configure: Regenerated.
+ (Reported by Matt Selsky <selsky@columbia.edu>.)
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add since 1.12.5 section.
+ * configure.in: Update for dev 1.12.5.1.
+ * configure: Regenerated.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update for release 1.12.5.
+ * configure: Regenerated.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Mark and Rob Clevenger's recent Windows build fixes.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note syslog of root attempts.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that pserver can no longer run as root.
+
+2003-12-12 Derek Price <derek@ximbiot.com>
+
+ * cvs.spec.in (%post): Do the same for cvsclient.info.
+
+2003-12-12 Derek Price <derek@ximbiot.com>
+
+ * cvs.spec.in (%post): Remove info's uncompressed info file cache after
+ installing the new gzipped files.
+
+2003-12-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in(AC_FUNC_FSEEKO): Add. Include handling for fseeko
+ and ftello with AC_LIBOBJ.
+ (AC_REPLACE_FUNCS): Remove fseeko and ftello.
+ * config.h.in, configure: Regenerated.
+
+2003-12-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvsnt.mak (CLEAN, CPP_SBRS): Add ftello, fseeko, exithandle and
+ getndelim2.
+ (ftello.c, fseeko.c, exithandle.c, getndelim2): Add new source
+ file definitions.
+ (Patch from Rob Clevenger <rob@robsite.org>.)
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add section for 1.12.4.
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update for release 1.12.4.1.
+ * configure: Regenerated.
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new promotable read locks.
+ * configure.in (--enable-lock-compatibility): New option.
+ * configure, config.h.in: Regenerated.
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Reorder enables slightly and improve commenting.
+ * configure: Regenerated.
+
+2003-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in (fseeko, ftello): Add to AC_REPLACE_FUNCS list.
+ * configure, config.h.in: Regenerated.
+
+2003-12-08 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in (AC_SYS_LARGEFILE). Add.
+ * configure, config.h.in: Regenerated.
+ * NEWS: Document.
+
+2003-12-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in (AC_SYS_LARGEFILE): Remove. More work is needed
+ before AC_SYS_LARGEFILE will work on all platforms.
+ * configure, config.h.in: Regenerated.
+ * NEWS: Remove last note.
+
+ * configure.in (AC_SYS_LARGEFILE): Add. The history file on
+ Solaris boxes can grow beyond 2GB.
+ * configure, config.h.in: Regenerated.
+ * NEWS: Note addition of --disable-largefiles option.
+
+2003-12-05 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update to require Automake 1.7.9.
+
+2003-12-05 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add since 1.12.3 section.
+ * configure.in: Update for dev version 1.12.3.1.
+ * configure: Regenerated.
+
+2003-12-04 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update for release 1.12.3.
+ * configure: Regenerated.
+
+2003-12-03 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--enable-case-sensitivity): Restore this option.
+ Always AC_LIBOBJ(fncase) when filenames are found to be case
+ insensitive.
+ * configure, config.h.in: Regenerated.
+
+2003-11-26 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--enable-case-sensitivity): Remove this option.
+ * NEWS: Note removal of case sensitivity support.
+
+ * config.h.in, configure: Regenerated.
+
+2003-11-26 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note recase tests.
+
+2003-11-26 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new test suite functionality.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in (RSH_DFLT): Macro substitution for configured CVS_RSH.
+ * Makefile.in, configure: Regenerated.
+
+2003-11-19 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (getline): Update to match new module definitions and
+ imports.
+ * aclocal.m4, configure: Regenerated.
+
+2003-11-19 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Rename "OTHER ISSUES" to "GENERAL USER ISSUES" and move the
+ note about the Autoconf upgrade to a new "DEVELOPER ISSUES" section.
+ Add a note about upgrading Automake.
+ * aclocal.m4, configure, **/Makefile.in: Regenerated with Automake
+ 1.7.9.
+
+2003-11-18 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Subdivide Changes section into "SERVER SECURITY ISSUES" and
+ "OTHER ISSUES". Note module abspath issue in security section.
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Add some detail to the last two notes Mark added.
+
+2003-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * BUGS: Note bugs symlinks to files will not work with or without
+ LockDir. Note that symlinks to directories will not work with
+ LockDir.
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Require Autoconf 2.58.
+ * INSTALL, NEWS: Note new Autoconf requirements.
+
+ * configure: Regenerated.
+
+2003-11-04 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add some more help text for --enable-case-sensitivity.
+ * configure: Regenerated.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * configure.in (AM_INIT_AUTOMAKE): Require Automake 1.7.5.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Add some notes on Autoconf requirements.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am (ACLOCAL_AMFLAGS): autoreconf does not understand
+ what to do with $(srcdir) so remove it -- autoreconf needs to be
+ done in the srcdir in order to regenerate all the files properly
+ in any case.
+
+ * configure.in (AM_GNU_GETTEXT_VERSION): Add to allow autoreconf
+ to regenerate files instead of using the incantation:
+ 'aclocal -I m4 && autoconf && automake && autoheader' to do the
+ same thing as 'autoreconf' should do.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that we're better at detecting ZLIB versions now.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4, configure: Regenerated.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that server ignores `-l' rather than rejecting it with a
+ fatal error.
+
+2003-10-31 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Note Cygwin as an option for building CVS under Windows.
+
+2003-10-31 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: s/cvsgui/wincvs/.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Move case sensitivity test to the enable-* section and
+ allow override via command line switch.
+ * NEWS: Update last news item to reflect new command line switch.
+ * configure, config.h.in: Regenerated.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add new test for a case insensitive file system.
+ * configure, config.h.in: Regenerated.
+ * NEWS: Note the above change.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update version to 1.12.2.1.
+ * NEWS (Changes since 1.12.2): New section.
+ * configure: Regenerated.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update version to 1.12.2.
+ * configure: Regenerated.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: /PROTO\.h/d;.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Update recent text about joins to reflect new behavior.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note that release of a project subdir does not remove the entry
+ from `./CVS/Entries'.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note things like plugging memory leaks and code cleanup and
+ reorganization under misc.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove obsolete bug report.
+ (Patch from Paul Edwards <somewhere in Australia>.)
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove obsolete bug report.
+ (Patch from Paul Edwards <somewhere in Australia>.)
+
+2003-10-23 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: Note behavior change for cvs update -jrev1 -jrev2.
+
+2003-10-23 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that double include of getndelim2.o problem is gone from
+ OS X.
+ * srclist.txt (getline, getndelim2): Note divergence from GNULIB.
+ * aclocal.m4, configure: Regenerated.
+
+2003-10-22 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note that we build on systems with gettext installed now.
+
+2003-10-21 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note Mark's recent admin -m fix.
+
+2003-10-21 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note the @email{} and @url{} fixes as misc documentation fixes.
+
+2003-10-14 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note POSIX 1003.1-2001 compatibility of docs and scripts.
+
+2003-10-14 Derek Price <derek@ximbiot.com>
+
+ Port to pedantic POSIX 1003.1-2001 hosts, such as Debian GNU/Linux
+ testing with _POSIX2_VERSION=200112 in the environment.
+
+ * BUGS: Suggest 'diff -C2', not 'diff -c2'.
+ * FAQ: Suggest 'sort -k 1.2', not 'sort +0.1'.
+ * depcomp: Sync to the depcomp shipped with Automake 1.7.8, as
+ it has the bug fixed and that's better than maintaining our
+ own depcomp.
+ (Patch from Paul Eggert <eggert@twinsun.com>.)
+
+2003-10-14 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Add HPPA 2.0 running HP-UX 10.20 for CVS 1.11.9.
+ (Report from Tom Kuiper <kuiper@DSNra.JPL.NASA.gov>.)
+
+2003-10-09 Derek Price <derek@ximbiot.com>
+
+ * HACKING (Other style issues): Note the dev team's preference for
+ consistency in the use of the `extern' storage-class identifier.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note history reporting fix.
+
+2003-10-08 Larry Jones <lawrence.jones@eds.com>
+
+ * TESTS: Add pointer to debug_check_log script.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Improve syntax and punctuation of my last entry.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note history fix for clients requesting `P' records.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note case insensitive file lookup fix. Note getpass fix.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ Add the GNULIB restrict module.
+
+ * configure.in: Add call to gl_C_RESTRICT.
+ * srclist.txt: Add m4/restrict.m4.
+ * aclocal.m4, configure, config.h.in: Regenerated.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove check for getopt function. Add call to
+ gl_GETOPT.
+ * srclist.txt: Add entries for GNULIB getopt module.
+ * aclocal.m4, config.h.in, configure: Regenerated.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ Assume headers in m4/gettext.m4 per notes in HACKING.
+
+ * aclocal.m4: Regenerated.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove call to AC_TYPE_SIZE_T since size_t can be
+ assumed via our C89 assumption of stddef.h. Don't check for errno.h
+ or string.h. We are assuming these headers.
+ * HACKING (Portability): Add a few more notes on our header assumptions
+ based on some comments from Paul Eggert <eggert@cs.ucla.edu> on the
+ GNULIB list.
+ * config.h.in, configure.in: Regenerated.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ Provide an atexit() function on systems which provide on_exit() but not
+ atexit().
+
+ * configure.in: Add a call to gl_FUNC_ATEXIT.
+ * srclist.txt: List atexit sources.
+ * aclocal.m4, config.h.in, configure: Regenerated.
+
+2003-09-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note recent fix of the potential segfault during a diff.
+
+2003-09-29 Derek Price <derek@ximbiot.com>
+
+ * HACKING (Indentation style): Put an ANSI function prototype in the
+ indentation style example.
+ (Portability): Add a few more notes on assuming a freestanding C89
+ compiler and what that means.
+
+2003-09-26 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note bug in options passed to diff via `cvs diff'.
+
+2003-09-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Move last blurb into an item with more detail.
+
+2003-09-12 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add the recent checkoutlist fix as "Other miscellaneous
+ bug fixes."
+
+2003-09-08 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note removal of the workaround for a bug in GLIBC prior to
+ GLIBC 2.0.7 and advise upgrading GLIBC rather than depending on silly
+ hacks that don't fix other programs installed on the system.
+
+2003-08-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note removal of CVSROOT/editinfo functionality.
+
+2003-08-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Remove typo in recent getpass() note.
+
+2003-08-27 Larry Jones <lawrence.jones@eds.com>
+
+ * NEWS: Note client/server messages have real command name, client/
+ server updates get logged in history file, history file has "P"
+ record type.
+
+2003-08-19 Derek Price <derek@ximbiot.com>
+
+ * HACKING (Portability): Add further comments about which headers we
+ can use.
+
+2003-08-12 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4, configure: Regenerated.
+
+2003-07-31 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call the newly prescribed gl_FUNC_GETPASS_GNU rather
+ than the internal gl_PREREQ_GETPASS.
+ * srclist.txt ($GNULIB/modules/getpass): Rename to...
+ ($GNULIB/modules/getpass-gnu): ...this new module.
+ * aclocal.m4, configure: Regenerated.
+
+2003-07-29 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Replace my recent misuse of AH_VERBATIM with a call to
+ AC_DEFINE.
+ * config.h.in, configure: Regenerated.
+
+2003-07-29 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Do not check for getpassphrase. Define `getpass' to
+ `cvs_getpass' in config.h to avoid conflicts with system decls.
+ * srclist.txt ($GNULIB/modules/getpass): New entry.
+ * NEWS: Note use of GNULIB getpass.
+
+ * config.h.in, configure: Regenerated.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Note --without-gssapi required to configure on OS X.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (lstat, stat): Correct typo.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt (getline, getnline, getndelim2): Mark some files sync'd.
+ * aclocal.m4, config.h.in, configure: Regenerated.
+
+2003-07-24 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove gethostname from AC_REPLACE_FUNCS call and add a
+ call to gl_FUNC_GETHOSTNAME.
+ * srclist.txt ($GNULIB/modules/gethostname): Add this source.
+
+ * aclocal.m4, config.h.in, configure: Regenerated.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * HACKING (Indentation style): Note the new C89 literal string
+ standard.
+ (Portability): Ditto, plus mention the headers we assume from C89.
+ * NEWS: Mention that we dropped K&R support.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * configure.in: We can assume <limits.h> and <stdarg.h>, so we no
+ longer need to check for <limits.h> or <varargs.h>.
+ * srclist.txt (m4/gettext): Note local modifications.
+
+ * aclocal.m4: Regenerate.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add call to gl_FUNC_STRERROR,
+ s/jm_FUNC_MEMMOVE/gl_FUNC_MEMMOVE/, and alphebetize list.
+ * srclist.txt: Add GNULIB strerror module.
+
+ * aclocal.m4: Regenerated.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add call to gl_FUNC_MEMMOVE and remove memmove from the
+ call to AC_REPLACE_FUNCS.
+ * srclist.txt: Note import of GNULIB memmove module.
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Note GNULIB exit() function support.
+
+2003-07-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Mention experimental PAM support.
+
+2003-07-20 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--enable-pam): New experimental option to enable PAM
+ support on systems that support it.
+ (--with-hardcoded-pam-service-name): PAM configuration option.
+ (Original patch from Brian Murphy <brian@murphy.dk>.)
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: Add a few missed files and reorganize slightly.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * srclist.txt: New file which describes where various external source
+ files come from.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Always call gl_GETNDELIM2 as per new API.
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove mention of wrappers -t/-f since they are no longer
+ supported.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add cvs.spec so that RPMs can be built
+ directly from tarballs.
+ * Makefile.in: Regenerated.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * TODO (72): Remove mention of the -i/-o in the modules file since they
+ have been removed.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new keyword expansion mode behavior.
+ * TODO (216): Remove completed item.
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Use gl_GETNLINE rather than the obsolete
+ gl_FUNC_GETNLINE.
+ * aclocal.m4: Regenerated.
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Use gl_FUNC_GETNLINE rather than the obsolete
+ gl_PREREQ_GETNLINE,
+
+ * aclocal.m4: Regenerated.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call gl_PATHMAX, not gl_PATH_MAX.
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove AC_C_PROTOTYPES call.
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add calls to new pathmax macro.
+
+ * aclocal.m4: Regenerated.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add calls to new getline & getnline macros.
+
+ * aclocal.m4: Regenerated.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-07-15 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-06-27 Larry Jones <lawrence.jones@eds.com>
+
+ * NEWS: Note LockDir fix.
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Debian Woody has -lkrb4, so check for that.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Add some OS X platforms to the compile list. Correct link to
+ cvsgui.org -> wincvs.org.
+
+2003-06-20 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Compile kerberos4-client.[ch] if needed.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * configure: Regenerated.
+
+2003-06-14 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call UTILS_FUNC_MKSTEMP for lib/mkstemp.c.
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+ * config.h.in: Ditto.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * HACKING: Update note on reentrancy.
+ (Original patch from Ken Lorber <keni@his.com>.)
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Call AM_GNU_GETTEXT.
+ * ABOUT-NLS: New file for GNU gettext support.
+ * config.guess: Ditto.
+ * config.rpath: Ditto.
+ * config.sub: Ditto.
+
+ * Makefile.in: Regenerated.
+ * aclocal.m4: Ditto.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-06-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: New LocalKeyword and KeywordExpand options.
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Rename win32.c to woe32.c in accordance with the GNU
+ convention to avoid implying that we consider the Microsoft Windows
+ Operating Environment any sort of "win".
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note short patch fix.
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * TODO (45): Combine this with...
+ (30): ...this item (as #30). Remove reference to diff since the
+ modules file is only consulted for the r* commands.
+
+2003-06-02 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note empty diff change text fix.
+
+2003-05-31 Derek Price <derek@ximbiot.com>
+
+ * TESTS: Note new $SPROG & $testcvs_server_support variables.
+
+2003-05-29 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note removal of global -l option.
+
+2003-05-28 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Add lib\PROTO.h to appropriate DEPS.
+
+2003-05-27 Derek Price <derek@ximbiot.com>
+
+ * AUTHORS: Give Mark an email address.
+
+2003-05-27 Derek Price <derek@ximbiot.com>
+
+ * cvs.spec.in: Add some files to doc. Remove redundant %defattr.
+
+2003-05-27 Derek Price <derek@ximbiot.com>
+
+ * README (Credits): Move...
+ * AUTHORS: ...here and update.
+
+2003-05-26 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update CVS version to 1.12.1.1.
+
+ * configure: Regenerated.
+
+2003-05-25 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update CVS version to 1.12.1.
+
+ * configure: Regenerated.
+
+2003-05-25 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note current intermittant BSDI failures.
+
+2003-05-22 Derek Price <derek@ximbiot.com>
+
+ * TODO (230): Remove this completed item.
+
+2003-05-22 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Note new --with-external-zlib option.
+ * configure.in (AC_PREREQ): 2.57.
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-05-22 Larry Jones <lawrence.jones@eds.com>
+
+ * NEWS: Note recent administrative file changes.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Mention new Automake version.
+ * NEWS: Ditto.
+
+ * Makefile.in: Regenerated.
+ * aclocal.m4: Ditto.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add call to AC_GNU_SOURCE & jm_FUNC_GLIBC_UNLOCKED_IO.
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add call to jm_FUNC_REALLOC.
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+ * aclocal.m4: Ditto.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Using Autoconf version 2.57.
+ * NEWS: Ditto. Reorder NEWS items to put the stuff which it is likely
+ that only developers care about last.
+ * configure: Regenerated with Autoconf 2.57.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove note about build being broken on windows. That was
+ fixed a few commits back.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add call to ACX_WITH_SYSTEM_VLIB.
+ * Makefile.am: Macro substitution for "zlib" subdir.
+ (Original patch from Anthon Pang <apang@telus.net>.)
+
+ * TODO (230): Add note about possible improvements to
+ ACX_WITH_EXTERNAL_ZLIB.
+ * aclocal.m4: Regenerated
+ * config.h.in: Ditto
+ * configure: Ditto
+ * Makefile.in: Ditto
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add calls to support lib/malloc.c from GNULIB.
+
+ * aclocal: Regenerated.
+ * configure: Ditto.
+ * config.h.in: Ditto.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add calls to support lib/lstat.c and lib/stat.c. Add
+ m4/Makefile to AC_OUTPUT.
+
+ * aclocal: Regenerated.
+ * configure: Ditto.
+ * config.h.in: Ditto.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (SUBDIRS): Add m4 subdir.
+ (ACLOCAL_AMFLAGS): Include m4 subdir when generating aclocal.m4.
+ * acinclude.m4: Remove this file, moving contents into two files in the
+ m4 subdirectory to ease maintenance.
+
+ * Makefile.in: Regenerated.
+ * aclocal.m4: Ditto.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: added rules and dependencies for log-buffer.[c,obj],
+ socket-client.[c,obj], and rsh-client.[c,obj]
+ (Patch from Anthon Pang <apang@telus.net>.)
+
+2003-05-18 Larry Jones <lawrence.jones@eds.com>
+
+ * acinclude.m4 (CVS_FUNC_PRINTF_PTR): New test.
+ * configure.in: Use it.
+ * aclocal.m4: Regenerated.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Back out all the S_ISSOCK changes I just made and move
+ the equivalent to lib/system.h.
+
+ * configure.in: Regenerated.
+ * config.h.in: Ditto.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * acinclude.m4: set cvs_client_objects in order to support optional
+ compilation of src/gssapi-client.c.
+ * configure.in: AC_SUBST(cvs_client_objects).
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+ * Makefile.in: Ditto.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Try again, with AC_TRY_LINK this time.
+
+ * configure: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Correct a typo in my last patch.
+
+ * configure: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add some checks for S_ISSOCK to avoid a problem on
+ SCO OpenServer 5.0.6a.
+ (Reported by Boyd Lynn Gerber <gerberb@zenez.com>.)
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+
+2003-05-07 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Add rsh-client.{h,c} to the note that I probably just broke the
+ Windows build by comitting Alexey Mahotkin's patches.
+
+2003-05-06 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Note that I probably just broke the Windows build by comitting
+ Alexey Mahotkin's patch.
+
+2003-05-01 Derek Price <derek@ximbiot.com>
+
+ * TODO (149): Remove reference to defunct RELATIVE_REPOS macro.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * acinclude.m4 (ACX_WITH_GSSAPI): Get rid of $includeopt, using
+ $CPPFLAGS as intended by the Autoconf folk.
+ * configure.in: Ditto.
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+ * Makefile.in: Ditto.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * acinclude.m4 (ACX_WITH_GSSAPI): Fix typo in broken conditional.
+ (Thanks to Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * configure: Regenerated.
+ * aclocal.m4: Ditto.
+
+2003-04-28 Derek Price <derek@ximbiot.com>
+
+ * NEWS (Changes since 1.11.5): Note removal of Checkin.prog and
+ Update.prog functionality.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * aclocal.m4 (AM_MAINTAINER_MODE): New macro to support
+ --enable-maintainer-mode.
+ * configure.in: Use it.
+ * configure: Regenerated.
+ * Makefile.in: Regenerated.
+ * noautomake.sh: Removed; no longer needed.
+ * INSTALL: Remove reference to noautomake.sh, add reference to
+ --enable-maintainer-mode.
+ * Makefile.am: Remove noautomake.sh.
+ * NEWS: Add note about --enable-maintainer-mode and noautomake.sh.
+ * README: Remove noautomake.sh.
+
+2003-04-01 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove a pcl-cvs bug. pcl-cvs is no longer part of the CVS
+ source distribution.
+
+2003-04-01 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove reference to cvs admin SEGV bug Larry Jones fixed
+ on 2003-02-19.
+
+2003-04-01 Derek Price <derek@ximbiot.com>
+
+ * BUGS: Remove obsolete bug.
+ * configure.in: Tail the BUGS file for status.
+
+ * configure: Regenerated.
+
+2003-03-31 Derek Price <derek@ximbiot.com>
+
+ * NEWS (Changes since 1.11.5): Note symlinked CVSROOT now works.
+
+2003-03-28 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--with-editor): Quit with an error message when no
+ editor is found. Allow --with-editor to override $EDITOR from the
+ user's environment. Add vim to the list of defaults.
+
+ * configure: Regenerated.
+
+2003-03-26 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--with-editor): Quit with an error message when
+ --without-editor is specified.
+ (Report from Jim Salter <jsalterjim@earthlink.net>.)
+
+ * configure: Regenerated.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add copyright notice.
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+ * configure: Ditto.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * configure.in (WITH_RSH): Add --with-rsh configure option. The
+ default is still "rsh" but it will look for "ssh" if "rsh" is not
+ found on the system.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+ * Makefile.in: Ditto.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * configure.in: AC_SUBST HAVE_PUTENV and create a dynamic config file
+ for src/sanity.sh.
+
+ * Makefile.in: Regenerated.
+ * configure: Ditto.
+
+2003-03-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS (changes since 1.11.5): Mention CVSREADONLYFS environment
+ variable and new `-R' cvs global option for read-only file-system
+ repository mode.
+
+2003-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * NEWS: (Changes since 1.11.5): Mention rcsinfo template updates.
+
+ * TESTS: Document some new global variables.
+
+ * TESTS: Remove some obsolete global variables.
+
+2003-03-07 Derek Price <derek@ximbiot.com>
+
+ * TESTS: Document some more global variables.
+
+2003-03-04 Mark D Baushke <mdb@cvshome.org>
+
+ * NEWS (Changes since 1.11.5): Mention CVS_LOCAL_BRANCH_NUM
+ environment varaible.
+
+2003-02-28 Larry Jones <lawrence.jones@eds.com>
+
+ * TODO (206): Done in 1.11.3.
+ (226): Add comment about deadlock.
+ (228, 229): New items.
+
+2003-02-26 Derek Price <derek@ximbiot.com>
+
+ * mktemp.sh: Add copyright notice, some comments, and attempt to return
+ success and error codes.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * configure.in (WITH_KRB4): Import KRB4 patch from Redhat 8.0's CVS
+ 1.11.2-5 SRPM. It's not the right fix, but it will work until I get
+ around to merging some of the code with WITH_GSSAPI and seperating the
+ bits into separate M4 files.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Remove the forced nondetection of mktemp I was using
+ to test the scripts.
+
+ * configure: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add checks for mktemp and sendmail.
+ * mktemp.sh: New file.
+
+ * Makefile.in: Regenerated.
+ * configure: Ditto.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * NEWS (Changes since 1.11.5): Mention UserAdminOptions.
+
+2003-02-06 Derek Price <derek@ximbiot.com>
+
+ * NEWS (Changes since 1.11.5): Note error message corrections and
+ documentation corrections.
+
+2003-01-31 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Check for varargs.h. Use the AC_C_PROTOTYPES macro
+ to check for handling of prototypes.
+
+ * configure: Regenerated.
+ * config.h.in: Regenerated.
+
+2003-01-31 Derek Price <derek@ximbiot.com>
+
+ * acinclude.m4 (ACX_WITH_GSSAPI): Move the checkin from 1/23 to here.
+ * configure.in: Update version to 1.12.10.1.
+
+ * aclocal.m4: Regenerated.
+ * configure: Regenerated.
+
+2003-01-30 Larry Jones <lawrence.jones@eds.com>
+
+ * FAQ: Update URL for tkCVS info.
+
+ * NEWS (Changes from 1.11.2 to 1.11.3): Add note about fixing watch
+ in server mode.
+
+2003-01-28 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Remove a reference to options.h.
+ (Thanks to Jenn Vesperman <jenn@anthill.echidna.id.au> for the report.)
+
+2003-01-28 Larry Jones <lawrence.jones@eds.com>
+
+ * NEWS: Update for 1.11.5, add notes about bug fixes in older
+ versions.
+
+2003-01-23 Derek Price <derek@ximbiot.com>
+
+ * aclocal.m4 (WITH_GSSAPI): Check for libcrypt before libroken to
+ satisfy a FreeBSD 4.6 dependency.
+ (Thanks to Jan Ruzicka <jan.ruzicka@comtechmobile.com> for the bug
+ report and a partial fix.)
+
+ * configure: regenerated.
+
+2003-01-20 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Update the news for the last release to mention that client
+ builds are not affected by the security vulnerability.
+
+2003-01-20 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update to dev version 1.11.5.1.
+ * configure: Regenerated.
+
+2003-01-16 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add 1.11.4 entry in regards to
+ <http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2003-0015>.
+ The Common Vulnerabilities and Exposures project (cve.mitre.org)
+ has assigned the name CAN-2003-0015 to this issue.
+ * configure.in: Update to CVS version 1.11.5.
+
+ * configure: Regenerated.
+
+2002-01-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--with-editor): Look for nano, the GNU GPL pico clone.
+ (Reported by Robin Cook <rcook@wyrms.net>.)
+
+ * configure: Regenerated.
+
+2002-01-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Update to dev version (1.11.4.1).
+ * configure: Regenerated.
+
+2002-12-28 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add since 1.11.3 entry.
+ * configure.in: Update to version 1.11.4.
+ * configure: Regenerated.
+
+2002-12-27 Derek Price <derek@ximbiot.com>
+
+ * NEWS: Add dummy entry for since 1.11.3.
+ * configure.in: Update to dev version 1.11.3.1.
+ * configure: Regenerated.
+
+2002-12-27 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Add bz2.
+ * NEWS: Add note about options.h.
+ * configure.in: Set version to 1.11.3.
+ * cvs.spec.in: No longer need to remove config.cache between runs
+ of configure.
+
+ * configure: Regenerated.
+
+2002-12-20 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Make previous rule more like Visual Studio expects.
+
+2002-12-19 Derek Price <derek@ximbiot.com>
+
+ * cvsnt.mak: Add lib/fnmatch.h.in -> lib/fnmatch.h rule.
+
+2002-12-19 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Remove references to options.h.
+ * cvsnt.mak: Ditto.
+ * FAQ: Ditto, plus some references to installing RCS & DIFF. Wow.
+ That was _really_ out of date.
+ * configure.in: Define MY_NDBM here rather than in src/options.h.
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+
+2002-12-16 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Add a platform to the tested platforms list.
+ (Thanks to Johan Vermeire <Johan.Vermeire@skynet.be>.)
+
+2002-12-04 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Add --with switch for specifying CVS_ADMIN_GROUP.
+
+ * config.h.in: Regenerated.
+ * configure: Ditto.
+
+2002-11-21 Larry Jones <lawrence.jones@eds.com>
+
+ * configure.in: Add contrib/check_cvs.
+ * configure: Regenerated.
+
+2002-11-12 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Update autom4te ignore pattern for version number
+ included in path name by new versions of autom4te.
+
+2002-10-28 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Flesh out some comments in regards to Sun Interactive
+ UNIX (ISC).
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * configure.in (WITH_KRB4): Update WITH_KRB4 output to use
+ AC_MSG_CHECKING and AC_MSG_RESULT for consitency.
+ (with-editor): Update comment.
+
+ * configure: Regenerated.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * configure.in (--enable-password-authenticated-client): New option.
+ (--enable-encryption): Increase the readability of the help text.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * configure.in (enable-encryption): Move to a more sensible location
+ and print a warning if it is specified with neither the client or the
+ server enabled.
+ (--with-editor): Move to a closer resemblance to alphabetical order.
+ (enables and withs): Reformat help strings for consistency.
+ * acinclude.m4: Ditto.
+
+ * configure: Regenerated.
+ * aclocal.m4: Ditto.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * configure.in (enable-force-editor): New option.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * acinclude.m4 (ACX_WITH_GSAPI): Use AC_MSG_CHECKING & AC_MSG_RESULT
+ instead of AS_MESSAGE for consistent appearance of the output even
+ though it makes the code look a little clunky.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Document --with-umask.
+ * configure.in (--with-umask): New option.
+ (--with-tmpdir): Move to something more closely resembling alphabetical
+ order of the --with- arguments.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Note new Automake version.
+ * NEWS: Ditto.
+ * configure.in (AC_ISC_POSIX): Remove this obsolete call and comment
+ out some related code with an explanation.
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+ * aclocal.m4: Ditto.
+ * configure: Regenerated.
+
+2002-09-24 Larry Jones <lawrence.jones@eds.com>
+
+ * aclocal.m4: Remove no longer needed definition of AC_ISC_POSIX
+ from gettext-0.10.40.
+ * configure.in: Remove warnings about obsolete AC_STRUCT_ST_BLKSIZE
+ and AC_STRUCT_ST_RDEV, add check for geteuid().
+ * configure, config.h.in: Regenerated.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * TODO (227): New item.
+
+2002-09-24 Larry Jones <lawrence.jones@eds.com>
+
+ * configure.in (--enable-server-flow-control): Fix nonportable code.
+ * configure: Regenerated.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Explain --with-tmpdir.
+ * configure.in (--with-tmpdir): New configure argument.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Explain --with-editor.
+ * configure.in (--with-editor): New configure argument.
+
+ * Makefile.in: Regenerated.
+ * configure: Ditto.
+ * config.h.in: Ditto.
+
+2002-09-24 Larry Jones <lawrence.jones@eds.com>
+
+ * TODO (226): New item.
+
+ * configure.in: Remove PATCH_PROGRAM.
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-09-20 Derek Price <derek@ximbiot.com>
+
+ * INSTALL: Explain --enable-server-flow-control.
+ * configure.in (--enable-server-flow-control): New configure argument.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-09-20 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Set PATCH_PROGRAM as possible, autodetecting with
+ a user override.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-09-20 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Use AC_HELP_STRING to create pretty help strings.
+ Reformat some lines for legibility.
+ (with-krb4): Fix help strings and logging.
+
+ * configure.in: Regenerated.
+
+2002-08-16 Derek Price <derek@ximbiot.com>
+
+ * configure.in: Make CVS_BADROOT a configure option.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-08-12 Derek Price <oberon@umich.edu>
+
+ * configure.in: Move ftruncate from AC_CHECK_FUNC to AC_REPLACE_FUNC.
+ (Symptoms reported by
+ Andrey Aristarkhov <Aristarkhov@bitechnology.ru>.)
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2002-07-09 Larry Jones <lawrence.jones@eds.com>
+
+ * NEWS (Changes since 1.11.2): Note lock message times now UTC.
+
+2002-06-28 Derek Price <oberon@umich.edu>
+
+ * INSTALL (Building [on] other platforms): Don't reference the Mac
+ README file since it has been missing for several releases. Mention
+ the UNIXness of Mac OS X and correct references to wincvs.org to point
+ to the new cvsgui.org .
+ (Reported by Sarah Gonzales <slindahl@rice.edu>.)
+
+2002-05-22 Larry Jones <lawrence.jones@eds.com>
+
+ * TODO (173, 202): Update to reflect current state of affairs.
+ (207): Defunct as of 1.11.2.
+
+ * NEWS (Changes from 1.11.1p1 to 1.11.2): Note new RereadLogAfterVerify
+ config option.
+
+2002-05-15 Larry Jones <lawrence.jones@eds.com>
+
+ * NEWS (Changes from 1.11.1p1 to 1.11.2): Note log/rlog changes.
+
+2002-05-08 Derek Price <oberon@umich.edu>
+
+ * configure.in: Add code to use lib/fnmatch.h.in redirection when
+ necessary to avoid namespace conflicts in #includes.
+ * configure: Regenerated.
+
+2002-05-08 Derek Price <oberon@umich.edu>
+
+ * TODO (215): Add note.
+
+2002-05-08 Derek Price <oberon@umich.edu>
+
+ * TODO (214): Clarify item.
+
+2002-05-02 Derek Price <oberon@umich.edu>
+
+ * configure.in: Add check for fnmatch.h so we can avoid namespace
+ conflicts on systems where the fnmatch function is broken. Not sure
+ this applies to any systems but Mac OS X.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-05-02 Derek Price <oberon@umich.edu>
+
+ * .cvsignore: Remove config.cache and add autom4te.cache.
+
+2002-05-02 Derek Price <oberon@umich.edu>
+
+ * noautoconf.sh: Update this script for operation with the new autotools.
+ * stamp-h1.in: Remove this obsolete file.
+
+2002-05-01 Derek Price <oberon@umich.edu>
+
+ * TODO (224): Comment on this item.
+
+2002-05-01 Larry Jones <lawrence.jones@eds.com>
+
+ * TODO (215 - 225): New items.
+
+2002-05-01 Derek Price <oberon@umich.edu>
+
+ * TODO (214): Add note about moving options.h options into the configure
+ script.
+ * configure.in: Remove last few references to options.h.
+ * configure: Regenerated.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * acconfig.h: Remove this file, it is deprecated.
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Move these into configure.in.
+ * acinclude.m4: Some minor updates for compatibility with the new
+ Autotools, some reformatting for readability, and a minor bugfix or
+ two.
+ * configure.in: Add new AC_DEFINE arguments and replace some direct
+ assignments to LIBOBJS with calls to AC_LIBOBJ. Call AC_INIT and
+ AM_INIT_AUTOMAKE with the new APIs. Call AC_PACKAGE_NAME,
+ AC_PACKAGE_TARNAME, AC_PACKAGE_VERSION, and AC_PACKAGE_STRING to
+ subst/define the corresponding variables. Call AC_CONFIG_FILES with
+ the old AC_OUTPUT args and call AC_OUTPUT without args. Remove
+ references to version.h.
+ * cvs.spec.in: Use the new substs.
+
+ * INSTALL: Mention new versions of Automake & Autoconf.
+ * NEWS: Ditto.
+
+ * Makefile.in: Regenerated.
+ * aclocal.m4: Ditto.
+ * configure: Ditto.
+ * config.h.in: Ditto.
+
+2002-04-28 Derek Price <oberon@umich.edu>
+
+ * TODO (208, 209, 210, 211, 212, 213): New items.
+
+2002-04-27 Derek Price <oberon@umich.edu>
+
+ * configure.in: Set LIBOBJ for fnmatch.c and fnmatch.h using the
+ correct functions. Add checks for some functions whose names conflict
+ with functions on Mac OS X 10.1 with the most recent dev packages.
+ This should be removable after the Mac dev packages are fixed.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2002-04-18 Derek Price <oberon@umich.edu>
+
+ * NEWS: Add a dummy entry so automake will let me update the version.
+ * configure.in: Update the version number.
+ * configure: Regenerated.
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * configure.in: Update version number.
+ * configure: Regenerated.
+
+2002-04-03 Derek Price <oberon@umich.edu>
+
+ * cvs.spec.in: Use a lowercase "cvshome.org". Add some RedHat safety
+ features to avoid "rm -rf /". No need to rebuild the docs in the
+ distribution. Don't strip the binary.
+
+2002-03-26 Derek Price <oberon@umich.edu>
+
+ * configure.in: Add a FIXME comment.
+
+2002-03-21 Derek Price <oberon@umich.edu>
+
+ * aclocal.m4: Regenerate with recent version of Autoconf. It looks
+ like things changed because of some RedHat patches or the like which
+ didn't change the Autoconf version number, but the differences look
+ like useful changes so I'm going to use them for consistency.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+
+2002-03-19 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS (Changes since 1.11.1p1): Note -S flag for [r]log.
+
+2002-02-08 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS (Changes since 1.11.1p1): Note read-only tag fix.
+
+2002-02-01 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS (Changes from 1.9 to 1.10): Note -t/-f wrappers disabled.
+
+2001-12-12 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS (Changes from 1.10 to 1.11): Note update -C.
+
+2001-12-03 Larry Jones <larry.jones@sdrc.com>
+
+ * TODO (206, 207): New items.
+
+ * NEWS (Changes since 1.11.1p1): Note -F flag for [r]annotate.
+ (Changes from 1.11 to 1.11.1): Note :: for log.
+
+2001-10-18 Derek Price <dprice@collab.net>
+
+ * TESTS: Remove outdated note about tests that don't use the dotest
+ function and add some notes on writing tests.
+ * HACKING: Reference TESTS file in note about submitting test cases
+ with patches.
+
+2001-09-28 Larry Jones <larry.jones@sdrc.com>
+
+ * noautomake.sh: Protect wildcards from shell expansion.
+ (Patch submitted by Stephen Cameron <smcameron@yahoo.com>.)
+
+2001-09-22 Derek Price <dprice@collab.net>
+
+ * INSTALL (Building from source code under Unix): Continue
+ noautoconf.sh note, stressing source checked out from CVS.
+
+2001-09-22 Derek Price <dprice@collab.net>
+
+ * noautomake.sh: Correct usage.
+
+2001-09-13 Derek Price <dprice@collab.net>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Updated to require Automake 1.5.
+ * NEWS (Changes since 1.11.1p1): Added note about standardizing on
+ Automake 1.5.
+ * INSTALL (Building from source code under UNIX): It's Automake version
+ `1.5', not `2.5'.
+ (Detailed information about your interaction with "configure"): Added
+ note about using `configure --help'.
+ * README (Installation): Add noautoconf.sh to the list of build and
+ installation commands.
+
+ * Makefile.in: Regenerated.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+ * aclocal.m4: Ditto.
+ * configure: Ditto.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * INSTALL (Building from source code under UNIX): Add a comment about
+ the noautomake.sh script and autotool versions.
+
+2001-08-20 Derek Price <dprice@collab.net>
+
+ * configure.in (AC_OUTPUT): Add src/version.h.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * configure: Regenerated.
+
+2001-08-20 Derek Price <dprice@collab.net>
+
+ * .cvsignore: Add cvs.spec.
+
+2001-08-14 Derek Price <dprice@collab.net>
+
+ * configure.in (AC_OUTPUT): Add cvs.spec.
+ * Makefile.am (EXTRA_DIST): Remove cvs.spec.in and cvs.spec.
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * cvs.spec.in: Use @PACKAGE@ from configure.
+ * cvs.spec: Remove this file.
+
+ * configure: Regenerated.
+ * Makefile.in: Ditto.
+
+2001-08-14 Derek Price <dprice@collab.net>
+
+ * DEVEL-CVS: Update mailing list addresses.
+ * HACKING: Ditto.
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * cvsnt.mak: Add entry for annotate.c.
+
+2001-08-07 Derek Price <dprice@collab.net>
+
+ * build.com: correct name of build .com for zlib.
+ (Patch from Mike Marciniszyn <Mike.Marciniszyn@sanchez.com>.)
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * configure.in: Remove some redundant macros (they appear to be run
+ automatically by AC_INIT).
+
+ * configure: Regenerated.
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * configure.in: Add AC_EXEEXT to get things right when under Windows.
+ (Report and patch from manklu@web.de.)
+
+ * configure.in: Reorder some macros to prevent Autoconf warnings.
+
+ * configure: Regenerated.
+ * Makefile.in: Ditto.
+
+2001-07-26 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS: Fix format, add note about tag -B.
+
+2001-07-16 Derek Price <dprice@collab.net>
+
+ * compile: New Automake file.
+ * configure.in: Add AM_PROG_CC_C_O to work around problems with some
+ compilers.
+
+ * aclocal.m4: Regenerated.
+ * Makefile.in: Ditto.
+ * config.h.in: Ditto.
+ * configure: Ditto.
+ (Thanks to Stephen Cameron <smcameron@yahoo.com> and
+ Tom Tromey <tromey@redhat.com>.)
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+ * aclocal.m4: Ditto.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * configure.in: Tidy and add some comments.
+
+ * configure: Regenerated.
+
+2001-07-03 Derek Price <dprice@collab.net>
+
+ * HACKING (Source): Add a note about where to obtain the development
+ sources.
+ (Thanks to Bear Giles <bear@coyotesong.com>.)
+
+2001-07-03 Derek Price <dprice@collab.net>
+
+ * configure.in: Test for mmap.
+
+ * configure: Regenerated.
+ * config.h.in: Ditto.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+ * aclocal.m4: Ditto.
+ * configure: Regenerated.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * mdate-sh: New file to support doc/version.texi.
+
+2001-06-27 Larry Jones <larry.jones@sdrc.com>
+
+ * TESTS: Note environment variables to select certain tools,
+ potential problems with big environments.
+
+ * TODO: Add note about non-canonical paths. Reformat long lines.
+
+ * NEWS (Changes since 1.11): Note new loginfo format string expansion.
+ Reformat some long lines.
+
+2001-06-11 Derek Price <dprice@collab.net>
+
+ * cvsnt.dsp: Add src/annotate.c to source file list.
+ (Thanks to Jerzy Kaczorowski <kaczoroj@hotmail.com>.)
+
+2001-05-30 Derek Price <dprice@collab.net>
+
+ * configure.in (AC_OUTPUT): Change contrib/pvcs2cvs to contrib/pvcs2rcs.
+
+ * configure: Regenerated.
+
+2001-05-29 Derek Price <dprice@collab.net>
+
+ * configure.in (AC_OUTPUT): Add pvcs2cvs.
+
+ * configure: Regenerated.
+
+2001-05-21 Derek Price <dprice@collab.net>
+
+ * NEWS (Changes since 1.11): It's "noautomake.sh", not "noautoconf.sh".
+ * Makefile.am (EXTRA_DIST): Include noautomake.sh.
+ (AUTOMAKE_OPTIONS): Update required Automake version to 1.4e.
+ (Reported by Alexey Mahotkin <alexm@hsys.msk.ru>).
+
+2001-05-21 Derek Price <dprice@collab.net>
+
+ * Makefile.am (EXTRA_DIST): Add noautoconf.sh.
+
+2001-05-17 Larry Jones <larry.jones@sdrc.com>
+
+ * depcomp: Yet another newer (unofficial) version from Automake.
+
+2001-05-10 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in (AC_OUTPUT): Remove -f from chmod -- not portable.
+ * configure: Regenerated.
+
+2001-05-03 Derek Price <dprice@collab.net>
+
+ * TODO (204): New item.
+
+2001-05-02 Derek Price <dprice@collab.net>
+
+ * acinclude.m4 (ACX_WITH_GSSAPI): Make krb5.h a requirement for GSSAPI.
+ krb5.h shouldn't be required, but CVS's GSSAPI implementation is
+ broken.
+ (Reported by Stephen Rasku <stephen@tgivan.com>.)
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+
+2001-04-29 Derek Price <dprice@collab.net>
+
+ * Makefile.am (distcheck-hook): Undo last change.
+ (localcheck): New target.
+
+ * Makefile.in: Regenerated.
+
+2001-04-29 Derek Price <dprice@collab.net>
+
+ * Makefile.am: Add remotecheck to distcheck-hook.
+
+ * Makefile.in: Regenerated.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * TODO (202): Remove my claim.
+ (203): New item.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * configure.in: Update version number.
+
+ * configure: Regenerated.
+ * cvs.spec: Ditto.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * configure.in: Update version number.
+ * NEWS (new since 1.11.1): Broke read-only fix.
+ (new since 1.11): Diff fix.
+
+ * configure: Regenerated.
+ * cvs.spec: Ditto.
+
+2001-04-26 Derek Price <dprice@collab.net>
+
+ * cvs.spec.in: Don't include %{_infodir}/dir.
+ (krb5): Remove krb5-config from dependencies.
+
+ * cvs.spec: Regenerated.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * configure.in: Update version to 1.11.1.
+
+ * Makefile.in: Regenerated with AM 1.4e as of today at 18:10 -0400
+ (EDT).
+ * aclocal.m4: Ditto.
+ * configure: Ditto.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * NEWS: Correct punctuation.
+
+2001-04-25 Larry Jones <larry.jones@sdrc.com>
+
+ * depcomp (aix, sgi): Correct previous fixes.
+
+2001-04-24 Larry Jones <larry.jones@sdrc.com>
+
+ * depcomp (sgi): Remove stray HP-UX code.
+
+2001-04-18 Derek Price <dprice@collab.net>
+
+ * noautoconf.sh: New shell script to touch Makefile.in files and
+ prevent unecessary AUtomake rebuilds after updates.
+ * NEWS: Note this new scipt.
+
+2001-04-16 Larry Jones <larry.jones@sdrc.com>
+
+ * depcomp (aix): Remove stray HP-UX code.
+
+2001-04-12 Larry Jones <larry.jones@sdrc.com>
+
+ * mkinstalldirs: Newer version from Automake.
+
+2001-04-12 Larry Jones <larry.jones@sdrc.com>
+
+ * depcomp: Newer version from Automake.
+
+2001-04-04 Larry Jones <larry.jones@sdrc.com>
+
+ * depcomp: Don't count on $? being set in then or else clauses.
+
+2001-03-30 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS: Note new rlog and rannotate commands.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * configure.in (AC_CHECK_FUNCS): Look for gettimeofday.
+
+ * config.h.in: Regenerated:
+ * configure: Ditto.
+ * stamp-h1.in: Ditto.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ New version of Automake (1.4e). With luck it works with the quirky BSD
+ Make.
+
+ * aclocal.m4: Regenerated.
+ * configure: Ditto.
+ * Makefile.in: Ditto.
+ * stamp-h1.in: Ditto.
+
+2001-02-28 Derek Price <derek.price@openavenue.com>
+
+ * acinclude.m4 (ACX_WITH_GSSAPI): Move the -L linker option back into
+ LIBS where it should be. LDFLAGS is a user variable.
+
+ * aclocal.m4: Regenerated.
+ * configure: Regenerated.
+
+2001-02-23 Derek Price <derek.price@openavenue.com>
+
+ * configure.in: Comment definition of PR_PROGRAM.
+
+ * configure: Regenerated.
+
+2001-02-22 Derek Price <derek.price@openavenue.com>
+ Pavel Roskin <proski@gnu.org>
+
+ * configure.in: Define PR_PROGRAM if `pr' has been found.
+
+ * config.h.in: Regenerated.
+ * configure: Regenerated.
+
+2001-02-20 Derek Price <derek.price@openavenue.com>
+
+ * acconfig.h (HAVE_GSSAPI): Removed. Entries in acconfig.h aren't
+ necesary when the full functionality of AC_DEFINE is used.
+ (HAVE_GSS_C_NT_HOSTBASED_SERVICE): Ditto.
+ * acinclude.m4 (ACX_WITH_GSSAPI): New file with GSSAPI configure code.
+ * configure.in: Use ACX_WITH_GSSAPI instead of writing GSSAPI code in
+ place.
+
+ * aclocal.m4: Regenerated.
+ * config.h.in: Regenerated.
+ * configure: Regenerated.
+
+2001-02-15 Derek Price <derek.price@openavenue.com>
+
+ * configure: Regenerated without beta automake macros.
+
+2001-02-14 Derek Price <derek.price@openavenue.com>
+
+ * configure.in (AC_CHECK_FUNCS): Alphebetize & reorganize. Add
+ cascading search for nanosleep, usleep, & select, in that order.
+ * config.h.in: Regenerated.
+ * configure: Regenerated.
+ * cvsnt.mak: List xtime.h & xselect.h dependancies.
+
+2001-02-14 Larry Jones <larry.jones@sdrc.com>
+
+ * cvsnt.dsp: Remove references to rtag.c & rtag.obj.
+ * cvsnt.mak: Ditto.
+
+2001-02-13 Derek Price <derek.price@openavenue.com>
+
+ * TODO: Add note about merging rdiff & diff.
+
+2001-02-13 Derek Price <derek.price@openavenue.com>
+
+ * TODO: Add note about cvs_temp_file.
+
+2001-02-07 Derek Price <derek.price@openavenue.com>
+
+ * cvs.spec.in (build): Remove the info 'dir' file so it doesn't get
+ installed accidentally.
+ (post): Install info files _into_ system dir file
+ (preun): uninstall info files from dir file
+ * cvs.spec: regenerated
+
+2001-01-31 Derek Price <derek.price@openavenue.com>
+
+ * TODO: Add a note about 'cvs add' w/o write access
+
+2001-01-29 Derek Price <derek.price@openavenue.com>
+
+ * NEWS: Rewrite the comment on the new ~/.cvspass functionality
+ * TODO: Add a note about testing login/logout
+
+2001-01-29 Derek Price <derek.price@openavenue.com>
+
+ * configure.in: Rewrite args to AC_TRY_COMMAND in a form that is
+ acceptable to both Autoconf 1.13 and the new 1.49 beta.
+
+ * configure: regenerated
+
+2001-01-29 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Check for syslog.h.
+ * configure, config.h.in: Regenerated.
+
+2001-01-17 Derek Price <derek.price@openavenue.com>
+
+ * configure.in: add machinery to check for the BSD VPATH bug
+ and check for texi2dvi.
+ * doc/Makefile.am: use the machinery
+ * diff/Makefile.in: changes to support 'make dist' from a build dir
+ * emx/Makefile.in: changes to support 'make dist' from a build dir
+ * os2/Makefile.in: changes to support 'make dist' from a build dir
+ * zlib/Makefile.in: changes to support 'make dist' from a build dir
+
+ * Makefile.in: regenerated
+ * aclocal.m4: regenerated
+ * configure: regenerated
+ * contrib/Makefile.in: regenerated
+ * doc/Makefile.in: regenerated
+ * lib/Makefile.in: regenerated
+ * man/Makefile.in: regenerated
+ * src/Makefile.in: regenerated
+ * tools/Makefile.in: regenerated
+ * vms/Makefile.in: regenerated
+ * windows-NT/Makefile.in: regenerated
+ * windows-NT/SCC/Makefile.in: regenerated
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+
+ * NEWS (new since 1.11): Add comment about VMS wildcards
+
+2001-01-05 Derek Price <derek.price@openavenue.com>
+
+ * configure.in (AC_OUTPUT): Move some script targets here
+ * contrib/Makefile.am (EXTRA_DIST, SUFFIXES, .pl:, .csh:): Move some
+ script targets to configure.in
+ * src/Makefile.am (cvsbug, cvsbug_EXTRA_DIST, EXTRA_DIST): move cvsbug
+ target to configure.in
+
+ * aclocal.m4: Regenerated due to change in Automake installation
+
+ * Makefile.in: Regenerated
+ * configure: ditto
+ * contrib/Makefile.in: ditto
+ * doc/Makefile.in: ditto
+ * lib/Makefile.in: ditto
+ * man/Makefile.in: ditto
+ * src/Makefile.in: ditto
+ * tools/Makefile.in: ditto
+ * vms/Makefile.in: ditto
+ * windows-NT/Makefile.in: ditto
+ * windows-NT/SCC/Makefile.in: ditto
+
+ * cvs.spec: updated timestamp
+ * stamp-h1.in: ditto
+ * doc/CVSvn.texi: ditto
+ * src/stamp-h2.in: ditto
+ * src/version.c: ditto
+
+ * contrib/clmerge.in: Rename from clmerge.pl
+ * contrib/cln_hist.in: Rename from cln_hist.pl
+ * contrib/commit_prep.in: Rename from commit_prep.pl
+ * contrib/cvs_acls.in: Rename from cvs_acls.pl
+ * contrib/log.in: Rename from log.pl
+ * contrib/log_accum.in: Rename from log_accum.pl
+ * contrib/mfpipe.in: Rename from mfpipe.pl
+ * contrib/rcslock.in: Rename from rcslock.pl
+ * contrib/sccs2rcs.in: Rename from scc2rcs.csh
+ * src/cvsbug.in: Rename from cvsbug.sh
+
+ * contrib/clmerge.pl: Rename to clmerge.in
+ * contrib/cln_hist.pl: Rename to cln_hist.in
+ * contrib/commit_prep.pl: Rename to commit_prep.in
+ * contrib/cvs_acls.pl: Rename to cvs_acls.in
+ * contrib/log.pl: Rename to log.in
+ * contrib/log_accum.pl: Rename to log_accum.in
+ * contrib/mfpipe.pl: Rename to mfpipe.in
+ * contrib/rcslock.pl: Rename to rcslock.in
+ * contrib/sccs2rcs.csh: Rename to sccs2rcs.in
+ * src/cvsbug.sh: Rename to cvsbug.in
+
+2001-01-03 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (remotecheck): depend on 'all'
+ * Makefile.in: regenerated
+
+2001-01-03 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in (DEP_FILES): Regenerated with new version of Automake
+ (DEP_FILES_conditional patch for BSD make compatibility)
+ * contrib/Makefile.in: ditto
+ * doc/Makefile.in: ditto
+ * lib/Makefile.in: ditto
+ * man/Makefile.in: ditto
+ * src/Makefile.in: ditto
+ * tools/Makefile.in: ditto
+ * vms/Makefile.in: ditto
+ * windows-NT/Makefile.in: ditto
+ * windows-NT/SCC/Makefile.in: ditto
+
+2000-12-28 Derek Price <derek.price@openavenue.com>
+
+ * INSTALL (BUILDING FROM SOURCES): Added a couple more platforms to the
+ build and test list.
+ (Building ... under Unix): Added note about BSD make and
+ --disable-dependency-tracking
+ (Building ... under Windows ...): Added note about using MSVC++ 6.0
+ (Building [on] other platforms): Added note about wincvs.org and
+ cvsnt.org. Added more complete note about BSD make and
+ --disable-dependency-tracking than the above
+
+2000-12-27 Derek Price <derek.price@openavenue.com>
+
+ * NEWS: Fix comments about the changes to ~/.cvspass
+
+2000-12-26 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (EXTRA_DIST): Add cvs.spec.in
+ (cvs.spec): new target
+ * Makefile.in: Regenerated
+ * aclocal.m4: update timestamp
+ * configure: Regenerated
+ * configure.in (AC_OUTPUT): Remove cvs.spec, doc/CVSvn.texi,
+ & src/version.c
+ * stamp-h1.in: update timestamp
+ * contrib/Makefile.in: ditto
+ * lib/Makefile.in: ditto
+ * man/Makefile.in: ditto
+ * tools/Makefile.in: ditto
+ * vms/Makefile.in: ditto
+ * windows-NT/Makefile.in: ditto
+ * windows-NT/SCC/Makefile.in: ditto
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * configure.in (AC_OUTPUT): Stretched
+ * configure: Regenerated
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * aclocal.m4: Regenerated due to Automake update
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+ * aclocal.m4: Regenerated due to a change to AM_PROG_ETAGS
+ * configure: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * .cvsignore: removed newly unused files, added new stamp file,
+ and alphabetized.
+ * AUTHORS: Added this file to please Automake. Apparently, its
+ presence is mandated by the GNU coding standards.
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+ * NEWS: Add a comment about the Automake conversion
+ * aclocal.m4: Added this file for Automake
+ * config.h.in: Regenerated
+ * configure: Regenerated
+ * configure.in: Some changes to support Automake and support for
+ missing roff & ps2pdf programs.
+ * cvs.spec: Regenerated
+ * cvs.spec.in: New file leveraging Automake support
+ * depcomp: New Automake file
+ * install-sh: Newer version from Automake
+ * missing: New Automake file
+ * mkinstalldirs: Newer version from Automake
+ * stamp-h.in: Remove unused file
+ * stamp-h1.in: New Automake generated stamp file
+
+2000-11-30 Derek Price <derek.price@openavenue.com>
+ Stephen Kennedy <Stephen.Kennedy@havok.com>
+
+ * cvs.spec (krb5): Require krb5-devel for a build of the krb5 target
+
+2000-11-29 Derek Price <derek.price@openavenue.com>
+ Stephen Kennedy <Stephen.Kennedy@havok.com>
+
+ * cvs.spec (build, post, preun): remove an old, commented out
+ line and replace hardcoded paths with _infodir and _bindir as
+ appropriate
+ (files): replace file list with more generic and succinct one
+
+2000-11-15 Derek Price <derek.price@openavenue.com>
+
+ * TODO (198): added note about deprecating cvs_temp_name
+ * configure.in (AC_CHECK_FUNCS): added mkstemp to support
+ new cvs_temp_file function.
+ * config.h.in: regenerated
+ * configure: regenerated
+
+2000-11-08 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Check for getgroups function.
+ * configure, config.h.in: Regenerated.
+
+2000-11-07 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in (FLAGS_TO_PASS): Add INSTALL, INSTALL_DATA, and
+ INSTALL_PROGRAM.
+ (Reported by Christian Brechbuehler <christian@arsdigita.com>.)
+
+2000-11-03 Derek Price <derek.price@openavenue.com>
+
+ * cvs.spec (build): pass in --without-gssapi when configuring the main
+ package so that the Kerberized version of CVS doesn't get built when
+ the user happens to have Kerberos installed in the default location.
+
+2000-10-31 Derek Price <derek.price@openavenue.com>
+
+ * NEWS: Mention zlib was updated to 1.1.3.
+
+2000-10-30 Derek Price <derek.price@openavenue.com>
+
+ * cvs.spec: Fixed trapping for gssapi so that the RPM can be built
+ on a machine without Kerberos. Should now build standard RPM on a
+ machine without Kerberos and the standard RPM + the Kerberos RPM on
+ a machine with the Kerberos devel libraries.
+
+2000-10-26 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Get path to pr for diff.
+ (Patch submitted by Urs Thuermann <urs@isnogud.escape.de>.)
+ * configure: Regenerated.
+
+2000-10-18 Derek Price <derek.price@openavenue.com>
+
+ * .cvsignore: Added .fname & .version, two temporary files used in spec
+ file creation.
+ * Makefile.in (distclean-local): clean .fname & .version
+ * cvs.spec: Replaced with a new version based on RedHat 6.2's spec file
+ for cvs 1.10.7. Edited heavily to include a krb5 subpackage for the
+ gssapi binary and fixed RedHat's info and man file placement.
+
+2000-10-17 Derek Price <derek.price@openavenue.com>
+
+ * NEWS: added a comment about the new CVSROOT format for pserver.
+
+2000-10-17 Derek Price <derek.price@openavenue.com>
+
+ * NEWS: added a comment about the new format of ~/.cvspass
+
+2000-10-09 Derek Price <derek.price@openavenue.com>
+
+ * cvsnt.mak: Some minor changes to allow CVS to compile correctly
+ under NT and Visual C++ 6.0.
+
+2000-09-07 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@
+ from autoconf.
+
+ * acconfig.h: Copy HAVE_CRYPT, HAVE_GETSPNAM, REGEX_MALLOC, and
+ _REGEX_RE_COMP from config.h.in to here, where they should have
+ been in the first place.
+ * config.h.in: Regenerated.
+
+2000-08-30 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS: Note additional history enhancements.
+
+2000-08-01 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in, config.h.in: Add check for getpassphrase (Solaris).
+ * configure: Regenerated.
+
+2000-07-11 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in, config.h.in: Add checks for mknod() and st_rdev
+ since some systems (notably Plan 9) don't have them.
+ * configure: Regenerated.
+
+2000-07-10 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS: Note the new "version" command.
+
+2000-07-06 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS: Note that admin -t works in client/server.
+
+2000-06-19 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in (AC_DEFINE): Define REGEX_MALLOC and _REGEX_RE_COMP
+ to configure lib/regex.c the way we want without messing with the
+ code.
+ * config.h.in: Ditto.
+ * configure: Regenerated.
+
+2000-05-16 Jim Kingdon <kingdon@redhat.com>
+
+ * TODO (186): Remove paragraph about Eric Raymond's interest.
+ This is still on the future projects on his site, it just seems to
+ brief (and too long ago updated) that I don't really see the need
+ to mention it.
+
+2000-05-05 Larry Jones <larry.jones@sdrc.com>
+
+ * TESTS: Add notes about required tools and where to get them.
+
+2000-05-02 Donald Sharp <sharpd@cisco.com>
+ and Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS: Note history output format change.
+
+2000-02-17 Larry Jones <larry.jones@sdrc.com>
+
+ * NEWS: Note that PreservePermissions is disabled.
+ * configure.in: Don't define PRESERVE_PERMISSIONS_SUPPORT.
+ * configure: Regenerated.
+
+2000-02-01 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Try again to handle systems that need both libsocket
+ and libnsl.
+ * configure: Regenerated.
+
+1999-12-09 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Correctly handle systems that need both libsocket
+ and libnsl.
+ * configure: Regenerated.
+
+1999-12-06 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Update to autoconf 2.13; use new AC_SEARCH_LIBS
+ to handle getspnam, connect, gethostbyname, and crypt correctly;
+ use new AC_FUNC_FNMATCH instead of doing it by hand.
+ * configure: Regenerated with autoconf 2.13.
+
+1999-12-06 Larry Jones <larry.jones@sdrc.com>
+
+ * INSTALL (Tested platforms): Update info.
+
+1999-11-04 Jim Kingdon <http://developer.redhat.com/>
+
+ * README (Installation): Yet another prep.ai.mit.edu -> gnu.org
+ change (can't believe we still haven't gotten them all).
+
+1999-11-04 Karl Fogel <kfogel@red-bean.com>
+
+ * NEWS: added item about anon cvs no longer needing password.
+
+1999-10-28 Larry Jones <larry.jones@sdrc.com>
+
+ * TESTS: Add note about not running as root. Remove note about
+ Solaris sort since sanity.sh was changed to avoid the problem.
+
+1999-07-12 Larry Jones <larry.jones@sdrc.com>
+
+ * TESTS: Remove suspicion that setting LC_COLLATE has fixed the
+ problem with Solaris sort -- people are still reporting it.
+
+1999-05-17 Jim Kingdon <http://www.cyclic.com>
+
+ (These changes were run by devel-cvs; feedback was "They look fine"
+ from Jim Meyering and "I concur" from Noel Cragg).
+ * HACKING (Submitting patches): Rewrite parts to try to sketch out
+ a process which is less centralized and hopefully describes the
+ status quo better (for example, I've mostly removed the word
+ "submit" because it describes a process of sending your patch to a
+ central authority rather than to whoever wants it). Update to
+ reflect some of the current practices/thinking regarding quality
+ and other matters. Try to be more concise where feasible.
+
+1999-05-13 Jim Kingdon <http://www.cyclic.com>
+
+ * BUGS: Remove item about RELATIVE_REPOS not working with
+ client/server CVS; it must have been fixed because the testsuite
+ is working fine with RELATIVE_REPOS.
+
+1999-05-07 Jim Kingdon <http://www.cyclic.com>
+
+ * TESTS: Add note about send-expect style interaction.
+
+1999-04-26 Jim Kingdon
+
+ * cvsnt.mak: Revert to the version before today's changes
+ (modulo one "because the IDE feels like it" change). I
+ couldn't get O'Connor's cvsnt.mak to work with MSVC 4.0 at
+ all (I tried the IDE, which tried to wrap the makefile and
+ wouldn't build even with the wrap, and the command line NMAKE).
+ * .cvsignore: Add back cvsnt.mdp WinDebug WinRel, accordingly.
+
+1999-04-26 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add cvsnt.dsw.
+
+1999-04-26 (submitted 1999-03-24) John O'Connor <john@shore.net>
+
+ * cvsnt.dsw: new file. The workspace file used by MSVC 5+ to
+ manage multiple projects. It contains three projects: cvsnt,
+ zlib and diff.
+
+ * cvsnt.dsp: Fixed problem where CVS wouldn't build because of
+ file name conflicts. Removed all the files from zlib and diff
+ directories and moved to separate project files.
+
+ * cvsnt.mak: Re-generated due to the changes in cvsnt.dsp.
+
+ * .cvsignore: Removed un-used entries related to MSVC. Added
+ entries to cover all files generated by the NT build: *.ncb,
+ *.opt, *.plg, Debug and Release.
+
+1999-04-09 Jim Kingdon <http://www.cyclic.com>
+
+ * HACKING: Add a sentence about sending patches somewhere other
+ than bug-cvs, while still granting permission for people to use
+ them under the GPL.
+
+1999-04-08 Jim Kingdon <http://www.cyclic.com>
+
+ * configure.in (AC_OUTPUT): Remove macintosh/Makefile (overlooked
+ in change of 1999-02-26; thanks to Erik Bertelsen for reporting it).
+ * configure: Regenerated.
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * macintosh: Remove this subdirectory and all its contents. It
+ contained MacCVS 2.x, but pretty much everyone has moved on to
+ MacCVS 3.x, MacCVS Pro, or MacCVSClient.
+ * Makefile.in (SUBDIRS): Remove macintosh.
+
+1999-02-25 Mehul N. Sanghvi (and Jim Kingdon)
+
+ * INSTALL: Add MkLinux on PowerPC.
+
+1999-02-18 Jim Kingdon
+
+ * cvsnt.mak: Remove vasprintf. Plus of course the usual
+ "because the IDE feels like it" changes.
+
+1999-02-09 Jim Kingdon <http://www.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS): Remove vasprintf; see
+ lib/ChangeLog for rationale.
+ * configure: Regenerated.
+
+1999-01-31 Assar Westerlund of sics.se
+ and Jim Kingdon
+
+ * configure.in: The GSSAPI code in CVS requires krb5.h which
+ Solaris 2.7 doesn't have. Check for it.
+ * configure: Regenerated.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * COPYING, COPYING.LIB: Remove obsolete snail address of the Free
+ Software Foundation.
+
+1998-12-01 Jim Kingdon
+
+ * TODO (195): Check in a few clarifications from Andrew Tridgell,
+ the rsync author.
+
+1998-11-11 Jim Kingdon
+
+ * HACKING: Change prep.ai.mit.edu to gnu.org.
+
+1998-10-26 Jim Kingdon
+
+ * INSTALL: Add information for Sequent DYNIX/ptx4.0, from a report
+ by Marco Franzen.
+
+1998-10-14 Jim Kingdon
+
+ * configure.in (AC_OUTPUT): Remove contrib/elib/Makefile.
+ * configure: Regenerated using autoconf 2.10.
+
+1998-10-13 Jim Kingdon
+
+ * TODO (149): Update since -d doesn't rewrite CVS/Root any more.
+
+1998-10-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO (31): Mention the ,foo.c, and SIGINT issue.
+
+1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Update from FAQ-O-Matic. This features fewer blank lines
+ and a few more minor formatting changes (not sure whether the
+ FAQ-O-Matic changed or whether this is because I upgraded Lynx).
+ I read through the diffs, and the real changes are: (A) In
+ /Advanced_Topics_/Setting_up_and_Manag/, #1, describe "cvs init",
+ don't describe committing modules file twice
+ (no longer needed now that mkmodules is not a separate program),
+ don't mention "cvs import" here. (B)
+ /Advanced_Topics_/Setting_up_and_Manag/, #5, describe special
+ issues with pserver and repository permissions,
+ (C), /Advanced_Topics_/Tricks_of_the_Trade/, renumber the question
+ "Why do timestamps sometimes get set to the date of the revision"
+ from #17 to #9. Renumber the questions between #9 and #17
+ accordingly, (D) /User_Tasks_/Less_Common_User_Tas/, "8. How do I
+ split a file into pieces, retaining revision histories?", include
+ a script which may help with this, (E)
+ /What_is_CVS_/How_does_CVS_differ_/, correct the name of SABLIME,
+ (F) /What_is_CVS_/Where_do_I_find_CVS_/, "2. Is there an archive
+ of CVS material?", note that http://www.delos.com/cvs doesn't
+ exist any more.
+
+ * NEWS: Mention :fork:.
+
+1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL (Tested platforms): Update SCO OpenServer information,
+ from a report by Robert Lipe@DIGI.
+
+1998-09-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add items about multiple roots and -d not updating
+ CVS/Root.
+
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_OUTPUT): Remove tools/pcl-cvs/Makefile.
+ * configure: Regenerated using autoconf 2.10.
+
+1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add item about LockDir.
+
+1998-08-31 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL (Tested platforms): Add Solaris x86 (reported by Jeremy of
+ exit109.com) and Irix 6.4 (reported by Russ Allbery).
+
+ * INSTALL (Tested platforms): Add Solaris 2.6 (reported by Russ
+ Allbery).
+
+1998-08-28 Noel Cragg <noel@swish.red-bean.com>
+
+ * TODO (196): new item.
+
+1998-08-26 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Update comments concerning Solaris sort and LC_COLLATE.
+
+1998-08-17 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update Irix, Ultrix, and NetBSD/Alpha with test results
+ from Noel.
+
+1998-08-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Add NetBSD/mac68k (reported by Hauke Fath of melog.de).
+ Add alpha-dec-osf4.0 and update SunOS and linux entries (reported
+ by Jim Kingdon and Noel Cragg).
+
+1998-08-06 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update for SCO OpenServer 5 (reported by Jeffery
+ Cann).
+
+1998-08-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Add Unixware 7 (reported by Phillip Porch).
+
+1998-07-29 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsnt.mak: For rcscmds.c, also include files from the diff
+ directory. Plus of course the usual voluminous "because Visual
+ C++ 4.0 feels like it" changes.
+
+Tue Jul 28 22:16:48 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * Makefile.in (dist): unset the GZIP shell variable before calling
+ gzip to avoid invocation problems.
+
+Sun Jul 26 16:22:21 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * NEWS: add info about TopLevelAdmin.
+
+1998-07-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update entries for HPUX and AIX (based on a submission
+ from Andreas Ley).
+
+1998-06-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.VMS: We generally don't need GNU patch any more.
+
+1998-06-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Don't mention the version of Solaris; Mark Borges says
+ that it applies to Solaris 2.5 as well as 2.6.
+
+1998-06-02 Assar Westerlund <assar@sics.se>
+
+ * configure.in: Test for GSS_C_NT_HOSTBASED_SERVICE in gssapi.h.
+ * acconfig.h: Add undef for HAVE_GSS_C_NT_HOSTBASED_SERVICE.
+ * configure, config.h.in: Rebuild.
+
+1998-06-01 Assar Westerlund <assar@sics.se>
+ and Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Check for GSSAPI headers individually. Use a
+ different set of GSSPI libraries if gssapi.h rather than
+ gssapi/gssapi.h is found. Adds Heimdal support.
+ * configure, config.h.in: Rebuild.
+
+1998-05-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.spec (%description): Rewrite to be slightly more verbose
+ about the basic features. Don't try to mention what CVS lacks.
+
+1998-05-23 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Remove items about binary file bugs which were fixed
+ approximately 6 months ago.
+
+1998-04-28 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Add note about Solaris sort program (reported by Mark
+ D. Baushke).
+
+1998-03-16 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Simplify test for shadow password support since
+ the code now handles the case where shadow passwords are supported
+ but are not in use.
+ * configure: Regenerated.
+
+1998-03-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Remove note about SGI's XFS. Someone reports that it
+ works (I would assume due to the 13 Feb 1998, and earlier, changes
+ to sanity.sh).
+
+ * NEWS: Add item about PreservePermissions. Fix unclear wording
+ in gserver item.
+
+1998-03-04 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * acconfig.h, configure.in: Add PRESERVE_PERMISSIONS_SUPPORT and
+ always define it.
+ * configure, config.h.in: Regenerated.
+
+Tue Feb 17 18:32:36 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Add memmove back to AC_REPLACE_FUNCS list.
+ * configure: Rebuild.
+
+1998-02-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO (190): Remove "failed to check out" from commit.c from
+ lists of error messages suppressed by -q; it no longer is.
+
+4 Feb 1998 Jim Kingdon
+
+ * cvsnt.mak: The usual "because Visual C++ feels like it"
+ changes. These ones seem to have to do with reordering
+ files and release versus debug configurations, mainly.
+
+Fri Jan 30 10:37:40 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update which version of CVS was tested with EMX.
+
+15 Jan 1998 W. L. Estes <wlestes@hamlet.uncg.edu>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.spec, Makefile.in: Fix some problems with the spec file
+ distributed with cvs. RPM chokes on a build root of slash, so
+ that is gone now. CVS is relocatable (as far as I know) so I
+ added a prefix tag. The source location was incorrect and in
+ fixing that I had to add a `g' flag to one of the sed commands in
+ the Makefile.in so the spec file gets generated correctly.
+
+13 Jan 1998 Jim Kingdon
+
+ * cvsnt.mak: Add lib/fncase.c. Plus of course the usual
+ "because Visual C++ feels like it" changes.
+
+Tue Jan 13 16:49:38 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * acconfig.h (USE_SETMODE_STDOUT): Add undef line.
+ (HAVE_SETMODE): Likewise.
+ * configure.in: If cygwin32, define USE_SETMODE_STDOUT and
+ HAVE_SETMODE.
+ * configure, config.h.in: Regenerate.
+
+ * acconfig.h (UTIME_EXPECTS_WRITABLE): Add undef line.
+ * configure.in: If cygwin32, define UTIME_EXPECTS_WRITABLE.
+ * configure, config.h.in: Regenerate.
+
+ * configure.in: Add test for cygwin32, and set LIBOBJS and LIBS
+ accordingly.
+ * configure: Regenerate.
+
+Sun Jan 11 11:43:55 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Add example of indentation for switch statement. I
+ always have to look this one up, and it seems worthwhile to
+ specify it here rather than be unsure which switch statement in
+ CVS to use as an example.
+
+Wed Jan 7 09:41:08 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Revise item 149 (concerning changing CVS/Root and such).
+ "This whole area is a rather bad pile of individual decisions which
+ accumulated over time, some of them probably bad decisions with
+ hindsight."
+
+Wed Dec 31 09:25:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Re-import from FAQ-O-Matic. Features a change regarding
+ removing directories.
+
+Tue Dec 23 08:28:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.VMS, INSTALL, HACKING, BUGS, README: Change bug-cvs
+ address from prep.ai.mit.edu to gnu.org per email from Martin
+ Hamilton. When referring to bug-reporting procedure refer to
+ Cederqvist not README.
+
+Tue Dec 16 13:13:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Re-import from FAQ-O-Matic. The content is the same, but
+ instead of being from Mosaic, it is from "lynx -dump -nolist".
+ This output is somewhat better (for example, it is formatted for
+ 80 columns or so, rather than Mosaic which is rather
+ inconsistent), and also lynx is free and still maintained whereas
+ NCSA Mosaic is proprietary and no longer maintained.
+
+ * FAQ: Re-import from FAQ-O-Matic. Features an update to the
+ Sablime question.
+
+ * NEWS: Add item about GSSAPI.
+
+Fri Dec 12 14:00:57 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Add --with-gssapi option, and look for gssapi.h
+ and GSSAPI Kerberos v5 libraries.
+ * acconfig.h: Add HAVE_GSSAPI.
+ * configure, config.h.in: Regenerate.
+
+Thu Dec 11 15:58:06 1997 Eric Mumpower <nocturne@cygnus.com>
+
+ * configure.in: Let --with-krb4 override the system Kerberos
+ header files and libraries, if any.
+ * configure: Regenerate.
+
+Thu Dec 4 20:01:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_CHECK_FUNCS): Remove mempcpy per change to
+ src/rcs.c.
+ * configure: Regenerated (never was regenerated after getwd change).
+
+1997-12-04 Jim Meyering <meyering@na-net.ornl.gov>
+
+ * configure.in (AC_CHECK_FUNCS): Add mempcpy.
+
+Thu Dec 4 10:42:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Update for kfogel .cvswrappers fix.
+
+Tue Dec 2 22:14:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * MINOR-BUGS: Update per info-cvs mail from Steve Cameron.
+
+1997-11-29 Jim Kingdon
+
+ * cvsnt.mak: Remove lib/getwd.c (see lib/ChangeLog for rationale).
+
+ * cvsnt.mak: The usual "because Developer Studio feels like
+ it" changes.
+
+Sat Nov 29 22:10:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS): Remove getwd (see lib/ChangeLog
+ for rationale).
+
+Mon Nov 24 10:36:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update QNX information per email from Michael Hunter of
+ QNX.
+
+Wed Nov 19 17:44:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Add Sequent entry per bug-cvs report.
+
+1997-11-17 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * BUGS: Remove item about exporting binary files to non-unix
+ clients; this is fixed.
+
+Mon Nov 17 09:07:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add yet another binary files problem.
+
+1997-11-14 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * cvsnt.mak: updated for diff/ subdir.
+
+Fri Nov 14 12:25:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Remove item about dying gasps message. At least one known
+ cause has been fixed.
+
+Wed Nov 12 20:24:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Re-import from FAQ-O-Matic. Features a wording fix to
+ "What do I do first? How do I create a Repository?" and a
+ formatting fix (makes it clear which bullets are under what)
+ to "What is a module?"
+
+ * NEWS: Add item about RCS library. Remove item about RCSBIN in
+ CVSROOT/config.
+ * INSTALL: Simplify instructions to reflect the fact that one need
+ not any longer install RCS and GNU diff.
+ * PROJECTS: Remove item about RCS library; it is done.
+
+Mon, 10 Nov 1997 Jim Kingdon
+
+ * cvsnt.dsp: For diff/diff.c, also look for include files in
+ diff directory. This means we get diff/system.h not lib/system.h.
+
+Sun Nov 9 16:16:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO (#195): New item, about rsync and such issues.
+
+Thu Nov 6 14:29:14 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO (#194): New item, about separated metadata.
+
+ * TODO (#186): Rewrite paragraph on CVSclusters to be clearer
+ about what this can do and why I think it is a cool idea.
+
+Sun Nov 2 19:34:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * DEVEL-CVS: Wording fix: want to specify that new developers are
+ granted checkin access and the ability to send to devel-cvs, not
+ specify whether this is implemented via an "account" (whatever
+ that is) (editorial change, not run by devel-cvs).
+
+Fri Oct 31 16:30:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention admin -o rev1::rev2.
+
+Wed Oct 29 08:40:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Add item 193, about alternatives to timestamps in CVS/Entries.
+
+Tue Oct 28 19:59:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO (190): "rcs failed" message is no longer affected by global
+ -q option.
+
+1997-10-28 Jim Kingdon
+
+ * .cvsignore: Add Visual C++ files du jour, namely
+ {diff,vc50}.{pdb,idb,pch}.
+
+ * cvsnt.dsp: Add files for diff library. The custom build
+ stuff for diff/version.c and diff/diff.c was to deal with
+ there also being a src/version.c and src/diff.c. There
+ might be an easier way.
+
+Mon Oct 27 11:21:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Re-import from FAQ-O-Matic. Features an edit from Larry
+ Jones regarding CVS on Windows.
+
+Mon Oct 20 15:23:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add item about spaces in login names.
+
+Mon Oct 20 10:25:42 1997 Hannes R. Boehm <hannes@boehm.org>
+
+ * INSTALL (Tested platforms): Add Red Hat Linux 4.2.
+
+Wed Oct 15 10:55:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO (#192): Also mention issue with opening connections to new
+ servers if CVSROOT changes.
+
+ * TODO (#191): Add thoughts on external difference programs.
+
+1997-10-11 Noel Cragg <noel@swish.red-bean.com>
+
+ * BUGS: remove note about the `-d' flag bug that was just fixed.
+
+ * TODO: new item 192.
+
+Thu Oct 9 12:59:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Revise item #182 to be clearer and to point to the
+ unofficial patch.
+
+Thu Sep 25 14:48:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * build.com: Also recurse into diff directory.
+
+Wed Sep 24 10:35:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Don't check for system-supplied regex matcher; see
+ comment for rationale.
+ * configure: Regenerated.
+
+Tue Sep 23 16:00:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add item about cvs add and -k wrappers.
+
+Mon Sep 22 11:21:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Revise item #191 in response to xdelta 1.10 release and a
+ few other random thoughts.
+
+Sun Sep 21 17:56:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Instead of checking for memchr, just define
+ HAVE_MEMCHR and HAVE_STRCHR.
+ Add comment about AC_FUNC_VFORK and vfork in general.
+ * acconfig.h: Add HAVE_MEMCHR and HAVE_STRCHR.
+ * configure, config.h.in: Regenerated.
+
+ * config.h.in: Regenerate using autoheader from autoconf 2.10.
+
+Sat Sep 20 01:17:10 1997 Tim Pierce <twp@twp.tezcat.com>
+
+ [notes: (1) includes the patches to config.h.in which he sent
+ (presumably generated), (2) I have omitted a change, which was
+ sent without a ChangeLog entry, to change re_exec to
+ re_compile_pattern in configure.in, (3) Also adds diff/Makefile in
+ AC_OUTPUT -kingdon]
+
+ * Makefile.in (USOURCE_SUBDIRS, check, remotecheck, installcheck):
+ Add diff.
+
+ Note that AC_CHECK_FUNCS(vfork)
+ has been replaced by AC_FUNC_VFORK... libdiff wants the more
+ specific test, and it seems unlikely to break CVS.
+
+ * configure.in: Add AC_FUNC_CLOSEDIR_VOID, AC_FUNC_VFORK,
+ AC_STRUCT_ST_BLKSIZE.
+ (AC_CHECK_HEADERS): Add limits.h and sys/file.h.
+ (AC_REPLACE_FUNCS): Add memchr.
+ (AC_CHECK_FUNCS): Remove vfork.
+
+Fri Sep 19 09:59:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Add item #191, concerning how to store binary files.
+
+Wed Sep 17 16:13:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Add ideas about ability to pass spaces in arguments, and
+ stdin, to the program under test, as something to consider for the
+ different test frameworks.
+
+Tue Sep 16 00:14:55 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add item about importing binary files.
+
+ * TODO: Adjust item #150 to reflect the fact that the client is
+ not quite so mean about tossing the log message as it was.
+
+Fri Sep 12 13:04:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update Windows entries per email from Greg Strockbine
+ <gstrock@dpc.com>.
+
+Thu Sep 11 15:03:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: New item #190, about meaning of -q and -Q global options.
+
+Wed Sep 10 18:48:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: A few more thoughts on "cvs message" (item 150).
+
+Tue Sep 9 22:20:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.VMS (Notes regarding compiling on VAX/VMS): Add item
+ about mode_t and pid_t.
+
+Sun Sep 7 17:34:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Re-import from FAQ-O-Matic. The metavariables are back.
+
+ * FAQ: Re-import from FAQ-O-Matic. Features comment from
+ julian@whistle about update -r branch:date. It also clobbered the
+ metavariables (confusion about "<" as data vs. HTML tag I would
+ guess), which I plan on fixing in a moment.
+
+ * configure.in: Add comment about re_exec and regexp syntax.
+
+ * configure.in (AC_REPLACE_FUNCS): Remove strdup; CVS was long
+ ago converted to use its own routine xstrdup.
+ * configure: Regenerated.
+
+Sat Sep 6 00:08:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Re-import from FAQ-O-Matic. In particular: GIC info
+ updated, binary files updated (e.g. -kb not -ko), rename database
+ and rCVS info updated (refer to TODO), tweaks to section on
+ contributing (HACKING, DEVEL-CVS, &c), Cyclic info updated
+ (e.g. remove Indiana address), usenet info updated
+ (e.g. comp.software.config-mgmt not gnu.*).
+
+Fri Sep 5 20:46:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Add another introductory paragraph which talks about out of
+ date material from 1995 FAQ.
+
+ * FAQ: Re-import from FAQ-O-Matic. This was mainly as a proof of
+ concept that I could edit the Cygnus question and have the diffs
+ come out looking right (which worked), but I also discovered that
+ the previous checkin was truncated partway through.
+
+ * FAQ: Replace file with an introductory paragraph plus a
+ downloaded copy of Molli's FAQ-O-Matic. I believe the content
+ closely matches the 1995 Grubbs FAQ but because everything is
+ re-ordered it would be painstaking work to verify this.
+
+Thu Sep 4 17:33:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add item about -w global option and client/server.
+
+Wed Sep 3 23:03:34 1997 Noel Cragg <noel@harvey.cyclic.com>
+
+ * TODO: Verbosify verbiage in item #189.
+
+Wed Sep 3 14:14:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Add item #189, concerning renames.
+
+Sat Aug 30 03:26:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Fix typo in Noel's change.
+
+Sat Aug 30 03:17:36 1997 Noel Cragg <noel@harvey.cyclic.com>
+
+ * TODO: Add a header so emacs chooses the correct editing mode.
+ Made several entries more verbose (expanded some of the less
+ well-known acronyms and/or added pointers to further
+ documentation).
+
+Wed Aug 20 09:51:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Remove "SparcClassing" typo that has been there for
+ a while.
+
+Wed Aug 20 09:51:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+ and Loren James Rittle <rittle@comm.mot.com>
+
+ * INSTALL: Update information for SunOS4, Solaris, Digital Unix,
+ and HPUX.
+
+Fri Aug 15 16:42:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Remove the "CVS 1.6" crud; it really isn't needed. Add
+ paragraph about the meaning of the last three arguments to cvs
+ import.
+
+Thu Aug 14 14:42:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+ and Loren James Rittle <rittle@comm.mot.com>
+
+ * INSTALL: Update information for SunOS4 and Solaris.
+
+Mon Aug 4 00:02:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Be specific about wrappers not working client/server.
+
+Sat Aug 2 09:23:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: In step 4, be more generic (the CVS sources are just an
+ example, and people might not have them handy).
+
+Fri Jul 25 17:02:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Refer to cvs.texinfo as the Cederqvist manual; that
+ seems to be the description which best applies no matter how it
+ was obtained. Be a little more explicit about the "$" prompt
+ convention and setting environment variables. Use double quotes
+ because they work on both DOS and Unix.
+
+Thu Jul 24 12:22:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Also mention SystemAuth.
+
+ * INSTALL (MIPS): Add more detailed report concerning Irix 6.2,
+ as reported by larry.jones@sdrc.com (Larry Jones).
+
+Tue Jul 22 17:35:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL (PowerPC): Add item for Lynx 2.5.
+
+21 Jul 1997 Jim Kingdon
+
+ * Makefile.in (DISTFILES): Add cvsnt.dsp.
+
+Mon Jul 21 09:40:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Adjust comment regarding version of autoconf which
+ introduced --bindir.
+
+Fri Jul 18 09:47:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Remove item 161 (the comments in cvs.texinfo have a much
+ more complete discussion of date format issues). In item 30,
+ change "patch" to "rdiff" and expand discussion slightly. Remove
+ item 64 (the performance issues in initial checkout have probably
+ changed quite a bit since that was written and in any event it
+ isn't particularly useful without specifics of what is slow and
+ ideas for speeding it up).
+
+ * INSTALL: Reorganize to separate out building/installing CVS
+ executables from what to do once you have them. Adjust Visual C++
+ instructions to deal with Visual C++ 5.x. Add brief mentions of
+ platforms other than unix and Windows.
+
+Thu Jul 17 21:13:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: In item 39, talk about how PRCS 1.2 as a possible model.
+
+Sat Jul 12 15:43:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Rewrite paragraph on arbitrary limits to reflect the
+ fact that the known arbitrary limits are gone.
+
+8 Jul 1997 Jim Kingdon
+
+ * cvsnt.dsp: Turn on browse information.
+
+Thu Jul 3 10:07:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Sending exact suggested text is almost as good as a diff.
+
+ * INSTALL (i386 family): Add lines about Watcom and EMX on OS/2.
+
+ * TODO: Add notes about popt and option parsing in general.
+
+Wed Jul 2 13:11:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Update item 149 to reflect CVS/Root.
+
+ * TODO: Add item 187, about usage errors vs. help messages.
+
+Mon Jun 23 18:24:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Adjust mention of read-only access in the light of
+ changes to cvs.texinfo.
+
+ * TODO: Add item 186, concerning multisite.
+
+Sun, 22 Jun 1997 Jim Kingdon
+
+ * cvsnt.dsp: New file. This apparently is what Visual C++ 5.0
+ uses in lieu of a .mak file (or so it seems).
+ * .cvsignore: Add cvsnt.opt cvsnt.dsw cvsnt.plg. These seem to
+ be the generated files du jour for Visual C++ 5.0.
+
+Thu Jun 19 17:16:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add item about CVSROOT/config.
+
+Wed Jun 18 00:00:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention pserver --allow-root.
+
+Mon Jun 16 19:07:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (SUBDIRS): Add emx.
+ * configure.in (AC_OUTPUT): Add emx.
+ * configure: Regenerated.
+
+Sun Jun 8 23:44:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_CHECK_FUNCS): Remove mkfifo; not used anywhere.
+ * configure, config.h.in: Regenerated.
+
+Thu May 29 15:53:06 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * DEVEL-CVS: Add "Policy regarding checkout-only access" to
+ replace parenthetical remark about checkout-only access. This is
+ more of a cosmetic/editorial change than a new policy.
+
+Wed May 21 17:02:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add item about wrappers.
+
+Fri May 16 13:43:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add item about "cvs export" and binary files.
+
+Sun May 11 11:38:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.VMS: Remove information about "direct TCP". Noone has
+ been complaining about it being broken (the code bitrotted not long
+ after it was written), nor has anyone complained
+ that contrib/listener.c was omitted from the distribution (because
+ it wasn't mentioned in contrib/Makefile.in DISTFILES). If there
+ is a desire to resurrect such a feature, it should use port 2401
+ as now discussed in doc/cvsclient.texi.
+
+Thu May 8 12:14:40 1997 Larry Jones <larry.jones@sdrc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update MIPS/SGI Irix 6.2
+ * TESTS: Add note about TESTDIR and SGI Irix 6's XFS.
+
+Wed May 7 12:01:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Fix keywords accidentally expanded in previous checkin.
+
+ * TODO: Add item #185, concerning keyword expansion and merges.
+
+Sun May 4 19:46:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Replace section on reporting bugs with a reference to
+ the bug-reporting section in cvs.texinfo.
+
+Fri May 2 22:50:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Remove item about importing binary files; the bug is fixed.
+
+Sun Apr 27 19:54:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Refer to doc/DIFFUTILS-2.7-BUG.
+
+ * INSTALL: Don't mention GREP; CVS no longer uses it.
+
+ * configure.in: Add comment about --bindir.
+
+Thu Apr 24 15:21:17 1997 Norbert Kiesel <nk@cosa.de>
+
+ * configure.in (AC_CHECK_FUNCS): added tempnam and mktemp
+ * config.h.in, configure: Regenerated with autoconf 2.10.
+
+21 Apr 1997 Jim Kingdon
+
+ * cvsnt.mak: Visual C++, as usual, wants to fiddle with this.
+ This time it would appear to be chiefly the dependencies.
+
+Mon Apr 21 01:06:31 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * NEWS: Document that the client no longer needs an external patch
+ program.
+
+Thu Apr 17 14:28:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Combine items 150 and 181 since they are basically the same.
+
+Tue Apr 15 12:32:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: The URL of yahoo's Configuration Management category has
+ changed. As it might change again, just cite their top-level page
+ rather than the entire URL.
+
+8 Apr 1997 Jim Kingdon
+
+ * cvsnt.mak: Add windows-NT/sockerror.c.
+
+Wed Mar 26 15:51:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Further note on import -kb bug.
+
+Tue Mar 25 17:51:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs-format.el: Add comment concerning c-label-offset.
+
+Wed Mar 19 14:06:40 1997 Jim Meyering <meyering@totoro.cyclic.com>
+
+ * configure.in (test for shadow passwords): Use AC_MSG_RESULT
+ rather than echo, so configure obeys --quiet.
+ Use yes and no in message rather than yup and nope.
+
+19 Mar 1997 Jim Kingdon
+
+ * cvsnt.mak: Now Visual C++ wants to add a bunch of dependencies
+ for the Release configuration as well as the Debug one. Why it
+ didn't do this before, I have no idea.
+
+13 Mar 1997 Jim Kingdon
+
+ * cvsnt.mak: Recent changes have added a number of getline.h
+ dependencies.
+
+Thu Mar 13 08:43:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_C_CROSS): Add comment about obsolescence
+ thereof.
+ * config.h.in, configure: Regenerated with autoconf 2.10.
+
+Thu Mar 13 05:50:29 1997 Philippe De Muyter <phdm@info.ucl.ac.be>
+
+ Here are the fixes I needed to make to cvs-1.9 to get it to
+ compile and successfully pass 'make check' on m68k-motorola-sysv.
+ * lib/getwd.c (getwd): Added declaration for getcwd().
+ * lib/wait.h (WIFSTOPPED et al.): Macro defined if not defined.
+ * lib/waitpid.c (waitpid): Use wait, not wait3, if !HAVE_WAIT3.
+ * src/admin.c (admin): Added declaration for getgrnam().
+ * src/server.c (fcntl.h): Do not include file twice. Already included
+ from system.h from cvs.h.
+ * src/sanity.sh (imported-f*): Renamed from imported-file*, that were
+ too long for sysv.
+ * configure.in (wait3): Added to AC_CHECK_FUNCS list.
+
+Wed Mar 12 14:32:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add "failed assertion `rev == NULL || isdigit (*rev)'" bug.
+
+ * TODO: Remove item 135; this is solved by %v and %V in loginfo.
+
+ * configure.in (AC_CHECK_FUNCS): Don't check for setvbuf;
+ HAVE_SETVBUF is no longer used.
+ * config.h, configure: Regenerated with autoconf 2.10.
+
+ * TODO: Add item 184, concerning MD5-based password hash.
+ Remove item 14, concerning "pathname stripper". I think that was
+ a reference to the late unlamented strip_path.
+
+Sat Mar 8 21:22:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: NT 4.0 is client and local (like other NT 3.51 & Win95).
+
+Fri Mar 7 16:51:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Just talked to a NT 4.0 user; add it to the list.
+
+Sun Mar 2 22:01:23 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add item about "cvs admin" vs. "cvs admin .".
+
+ * TODO: Remove item #169. It doesn't really explain what an
+ "archive library" is or in general what the feature they discuss is
+ supposed to do--I mean, CVS _can_ be used to store .o's, if
+ that is what they are talking about.
+
+ * TODO: Add item #183, about greater documentation/visiblity for
+ Entries.Static and CVS/Tag.
+
+ * INSTALL (footnote 5): Add note about how /usr/tmp vs. /var/tmp
+ shouldn't be an issue anymore
+
+Thu Feb 20 13:53:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update Cray entry per mail from John Bowman
+ <bowman@ipp-garching.mpg.de>
+
+ * configure.in: Add comments about autoconf version.
+
+Mon Feb 17 09:55:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure: Regenerated.
+
+Sat Feb 15 15:37:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_OUTPUT): Add windows-NT/SCC/Makefile.
+
+Sun Dec 15 13:12:30 1996 Michael Douglass <mikedoug@texas.net>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention "cvs logout".
+
+1997-02-12 Jim Kingdon
+
+ * cvsnt.mak: Visual C++ seems to want to make some cosmetic
+ changes (reordering *.obj files), perhaps prodded by "Save
+ All". I hope that putting in these changes will make it
+ happy...
+
+1997-02-11 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Replace with version from Visual C++ 4.0. If someone
+ wants the 2.x one back, I suppose we can put them side by side,
+ but I won't be able to update the 2.x one any more as I won't be
+ having access to 2.x.
+
+Tue Feb 11 16:43:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * .cvsignore: Add cvsnt.mdp and cvsnt.ncb. They seem to be files
+ created by Visual C++ 4.x which were not created by Visual C++ 2.x.
+
+Tue Feb 4 11:42:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: OS/2 port is client only.
+
+ * Rename devel-cvs (which had only been in the repository, not the
+ distribution) to DEVEL-CVS. Add "Charter for the devel-cvs
+ mailing list:" heading, "CVS Development Policies" title, and
+ one-sentence introduction (editorial changes, not run by
+ devel-cvs). Revise paragraph concerning membership in the list to
+ reflect policy change to make read-only membership different from
+ the ability to send to the list (the new wording was approved by
+ devel-cvs, as was the rename and including it in the
+ distribution).
+ * Makefile.in (DISTFILES): Add DEVEL-CVS.
+ * HACKING: Add "Mailing lists" section.
+
+Tue Jan 28 10:41:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Remove AC_CHECK_SIZEOF; no longer needed with
+ lib/md5.c changes.
+ * acconfig.h: Add HAVE_CONNECT. This is needed so that autoheader
+ 2.10 works; I think this has been broken since 2 Dec 1996.
+ * config.h.in: Regenerated with autoheader 2.10.
+ * configure: Regenerated with autoconf 2.10.
+
+ * HACKING: Revise criterion for whether something goes in NEWS
+ again (now "user-visible change worth mentioning"--the language
+ from the GNU coding standards).
+
+Mon Jan 27 23:05:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Criterion for whether something goes in NEWS is not
+ whether it is user-visible; it is whether it is a bugfix or a
+ feature.
+
+Tue Jan 21 10:21:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Warn people against pre-5.x RCS; describe how to find
+ out what version of RCS you have.
+
+Wed Jan 8 14:50:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, NEWS, README, TODO, configure.in: Remove CVSid; we
+ decided to get rid of these some time ago.
+
+Wed Jan 8 00:17:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README (Credits): Refer to NEWS not ChangeLog; the ChangeLog in
+ question got renamed a bit but ended up as the bottom of the NEWS
+ file. Eliminate use of first person in a few places where it is
+ unclear who it refers to. Explicitly say that the lists
+ of contributors are not comprehensive.
+
+Thu Jan 2 12:59:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README, Makefile.in: Remove paragraph about writing to the Free
+ Software Foundation at 675 Massachusetts Avenue. (1) They are no
+ longer at that address; (2) the Free Software Foundation are not
+ the ones to write to concerning CVS licensing. bug-cvs would be a
+ more appropriate choice; (3) there is probably little need for
+ this paragraph anyway.
+
+Thu Jan 2 09:46:37 1997 Karl Fogel <kfogel@ynu38.ynu.edu.cn>
+
+ * NEWS: mention read-only repository access feature.
+
+Wed Jan 1 18:47:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.spec: Don't include ChangeLog and ChangeLog.zoo in %doc.
+ There is no point in including them without src/ChangeLog,
+ src/ChangeLog-96, etc., but more to the point they really belong
+ in the source distribution rather than a binary distribution anyway.
+
+Mon Dec 30 16:55:54 1996 Abe Feldman <feldman@harvey.cyclic.com>
+
+ * NEWS: Add entry for changes to checkout command (creating CVS
+ directory at top of working directory)
+
+Tue Dec 17 13:13:30 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add entry for verifymsg.
+
+Tue Dec 10 19:22:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs-format.el: Revise comments to explain how to use it and
+ general minor tidying of comments.
+
+Mon Dec 2 13:05:44 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Don't call AC_CHECK_FUNCS(connect) a second time,
+ because the value will have been cached; instead, check whether
+ the library was found with connect defined.
+ * configure: Rebuild with autoconf 2.12.
+
+Sat Nov 30 23:04:52 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add note about mysterious failure in test 187a3.
+
+Fri Nov 29 10:19:50 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_CHECK_FUNCS): Also check for readlink.
+ * config.h.in: Regenerated using autoheader 2.10.
+
+Fri Nov 22 16:30:27 1996 Brendan Kehoe <brendan@cygnus.com>
+
+ * configure.in: Check for -lsocket, etc., before checking for
+ Kerberos libraries.
+ * configure: Rebuild.
+
+1996-11-19 Jim Kingdon
+
+ * cvsnt.mak: Remove strippath.c.
+
+Sun Nov 3 21:54:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Move detailed information on compatibility to
+ the manual; simply point to it here.
+
+Thu Oct 31 07:20:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add note about cvs import of binary files on non-unix.
+
+Tue Oct 29 13:59:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Add note about "dying gasps" message.
+
+Sat Oct 26 16:17:09 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * configure.in (AC_CHECK_FUNCS): Check for tzset.
+
+Fri Oct 25 10:27:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention new loginfo features.
+
+Thu Oct 24 08:21:48 1996 Lars.Henriksen@netman.dk
+
+ * INSTALL: Update to "DEC Alpha running OSF/1 version 3.2 (1.9)"
+
+Tue Oct 22 10:34:21 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * configure.in: don't check for the existence of the /etc/security
+ directory, because it's possible to have PAM installed without
+ using shadow passwords.
+ * configure: regenerated.
+
+Sat Oct 19 18:34:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Say that the remote protocol is not interoperable before
+ CVS 1.5.
+
+Sat Oct 19 13:06:53 1996 Mark H. Wilkinson <mhw@minster.york.ac.uk>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * configure.in, INSTALL: New options for configure to enable or
+ disable client and server code, overriding configure's defaults.
+ * confiugre: Regenerated.
+
+Sat Oct 19 13:06:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Add note about what to do if you got a binary
+ distribution of CVS. Add VAX/VMS entry.
+
+Thu Oct 17 15:38:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS, README: Reinstate 30 Sep 96 changes concerning US letter
+ vs. A4 paper.
+
+Wed Oct 16 16:59:57 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * configure.in: Simplify code to check for crypt. Check for
+ -lcrypt first, and then check for the crypt function. The old
+ code did slightly funky things with cache variables, which JimK's
+ last change disturbed. Let's just keep it simple.
+ * configure: Rebuilt.
+
+Wed Oct 16 15:01:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Don't call unset. It isn't portable to Ultrix,
+ but perhaps more to the point, seems like we should be using the
+ cached values (there was no comment explaining why we should
+ ignore the cached values, and none of the CVS developers were
+ able to provide an explanation when I asked).
+ * configure: Regenerated.
+
+ * NEWS: Add item regarding export and "cvs history".
+
+Tue Oct 15 07:40:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Mention the fact that expr is only for the tests, not for
+ CVS itself. At least one person was unclear on this.
+
+Mon Oct 14 12:13:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Add "Submitting patches (strategy)" section and
+ sentence about test cases. These changes have been run by
+ devel-cvs and there was no objection.
+
+Sat Oct 12 19:43:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.VMS: Add notes about some build problems on VAX/VMS.
+
+Thu Oct 10 09:20:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Remove item about & in modules file and client/server; the
+ bug is fixed.
+
+ * README.VMS: Rewrite sections about wildcard expansion and
+ calling editors to suggest technical approaches and to make it
+ clear that fixes will only happen if someone gets around to them.
+
+Sat Oct 5 15:01:22 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Version 1.9 released.
+
+Tue Oct 1 14:32:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS, README: Revert changes regarding -D, -g, and A4. They
+ are for new features which are not appropriate at this stage of
+ the release process.
+
+Mon Sep 30 14:51:36 1996 Greg A. Woods <woods@most.weird.com>
+
+ * INSTALL (sun3): 1.8.86+ builds and runs make check.
+
+ * NEWS: describe -D and -g; DIFFBIN and GREPBIN
+
+ * MINOR-BUGS: yet another couple of annoyances...
+
+Mon Sep 30 08:33:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Mention "cvs add -m" client/server bug.
+
+ * NEWS: Document change from A4 to US letter. It may seem minor,
+ but it affects a *lot* of people.
+
+ * README: Revise discussion of US letter vs. A4 to reflect recent
+ change to cvs.texinfo.
+
+Sun Sep 29 16:32:47 1996 Greg A. Woods <woods@most.weird.com>
+
+ * MINOR-BUGS: describe a minor annoyance or two
+
+ * BUGS: describe a couple of new bugs
+
+Sun Sep 29 14:09:49 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * configure.in: check for shadow password files as well as for
+ getspnam. Some systems (like Linux) have getspnam in the C
+ library, but aren't necessarily using shadow passwords.
+ * configure, config.h.in: Regenerate.
+
+Fri Sep 27 16:49:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (TSUBDIRS): Remove comment about order of
+ directories mattering. That was only for an old set of hacks,
+ since gone, which tried to combine several tag files into one
+ (before emacs could use several tag files at once).
+
+Wed Sep 25 10:35:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add note about "cvs log -d" date formats changing. See
+ comment I added to cvs.texinfo for more whining about this situation.
+
+ * BUGS: Remove item about ~/.cvsignore on NT; it is fixed.
+
+Wed Sep 25 10:22:00 1996 Larry Jones <larry.jones@sdrc.com>
+
+ * configure.in: Add hack for ISC crypt (the version in the posix C
+ library doesn't work -- why am I not surprised). Add check for
+ libsec.a for shadow password functions.
+
+ * Makefile.in: Make zlib along with lib in the check targets.
+
+Wed Sep 25 08:34:01 1996 Jim Blandy <jimb@floss.cyclic.com>
+
+ Fix from Mark A. Solinski <markso@mcs.com>:
+ * cvsnt.mak: The debug configuration adds the zlib directory to
+ the include path but it is missing from the release configuration.
+ Add it to the "ADD CPP" and "CPP_PROJ" lines.
+
+Tue Sep 24 11:32:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Add VMS entry. Clarify what "tested" means.
+
+ * README: Replace section about what CVS is with the blurb from
+ cvs.spec (which is also the paragraph we use in the release
+ announcements).
+ Change location of pcl-cvs from contrib/pcl-cvs to tools/pcl-cvs.
+
+ * BUGS: Remove item about version numbers; we now have version
+ numbers. Remove item about server using /usr/tmp; this has been
+ changed. Remove item about deadlocks between server and client
+ and file contents being interpreted as commands; I believe this
+ refers to the case which was fixed by Ian's 7 Aug 96 change to
+ receive_partial_file. Remove item about server temp directory
+ becoming full; I'm not sure all bugs related to that have been
+ fixed, but I think the ones mentioned have been. Remove item
+ about .# files; this is a documented behavior. Refer to
+ platform-specific documentation. Add bug with & in modules file
+ and client/server CVS. Move bug about weird use of long file
+ names to end; the bug report is so long people won't want to read
+ past it. Refer to README concerning reporting bugs. Add
+ introduction. Reword some bug descriptions. Add bug concerning
+ ~/.cvsignore on NT.
+ * MINOR-BUGS: Add introduction. Reword some bug descriptions.
+ Remove item about "premature end of file"--we've improved that
+ error message as much as we can figure out how. Remove item about
+ filenames getting truncated (with rcs2log?)--I think this is a fixed
+ bug although I couldn't quickly find a ChangeLog entry for the fix.
+
+Tue Sep 17 12:46:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * .cvsignore: Add cvs-*.spec.
+
+Mon Sep 16 17:42:30 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: In 180, mention issue of network being down. Add item
+ 182, about inclusiveness of "cvs log -r foo -r bar".
+
+ * HACKING: Also mention arbitrary limits and reentrancy.
+ User-visible changes should be documented in cvs.texinfo as well
+ as NEWS.
+
+Thu Sep 12 16:06:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.VMS: Put authorship info at end. Add disclaimer. Say
+ that patch is mandatory not optional. Don't mention gzip; we
+ don't require it any more. Remove section on filename case; the
+ bugs described there are fixed. Miscellaneous tweaks and updates.
+
+Wed Sep 11 11:08:39 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * configure.in (AC_OUTPUT): Don't forget to create vms/Makefile.
+
+Tue Sep 10 19:55:07 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add build.com and README.VMS.
+ (SUBDIRS): Add vms.
+ * build.com: Also recurse into zlib directory.
+
+ * NEWS: Mention Win95.
+
+Fri Sep 6 11:43:26 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Add AC_ARG_ENABLE for encryption.
+ * acconfig.h: Add ENCRYPTION.
+ * configure, config.h.in: Regenerate.
+ * NEWS: Modify the entry on encryption to mention that you must
+ configure with --enable-encryption.
+ * INSTALL: Mention the --with-krb4 and --enable-encryption
+ configure options.
+
+Thu Sep 5 11:30:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Revise access method item to mention both :ext: and
+ :server:.
+
+ * README.VMS: Change bug reporting address to bug-cvs. In
+ discussing filenames, don't mention a hypothetical behavior
+ involving folding to lowercase (I'm not sure what is meant, and it
+ doesn't sound right to me) and do mention that things might be
+ different now (as a result of recent changes to case sensitivity
+ code).
+
+Wed Sep 4 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Add windows-NT/ChangeLog.
+
+Wed Sep 4 13:55:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add cvs.spec.
+
+Mon Aug 26 15:30:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Add item suggesting "cvs message" command.
+
+Tue Aug 20 12:22:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_C_INLINE): Removed; see src/ChangeLog.
+ * config.h.in, configure: Regenerated.
+ * os2/config.h, windows-NT/config.h: Remove #define of inline.
+
+ * configure.in (AC_C_CHAR_UNSIGNED): Removed; it is not used
+ anywhere.
+ * config.h.in, configure: Regenerated.
+ * os2/config.h, vms/config.h, windows-NT/config.h: Likewise,
+ remove __CHAR_UNSIGNED__.
+
+Fri Aug 16 13:37:19 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.spec (%description): Replace description with one that
+ resembles the release announcements we have been sending out. The
+ previous one was out of date and not really focused on describing
+ what CVS does.
+ (%build): Don't define SERVER_FLOWCONTROL; if we are ready to make
+ this is the default it should be for all kinds of builds, not just
+ those via RPM.
+
+Fri Aug 16 16:09:59 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.spec: new file. This is a template for a RPM specification
+ file (which is used by 'make spec').
+
+ * Makefile.in (installdirs-local): new (empty) target
+ (all install uninstall installdirs): add installdirs to list of
+ targets which are done for all subdirs
+ (spec): new target to create a rpm specification file (which can
+ be used to create RPM source and binary packages)
+ (dist): depend on spec (which now also creates .fname)
+
+Wed Aug 14 13:59:11 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * configure.in (AC_REPLACE_FUNCS): add getspnam for reading shadow
+ password entries
+ * configure: regenerated
+ * config.h.in: regenerated
+
+Mon Aug 12 14:15:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (config.status): When running config.status
+ --recheck, preserve the value of CFLAGS.
+
+Fri Aug 9 14:11:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Also mention dejagnu advantages.
+
+Thu Aug 8 16:00:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS (ABOUT STDOUT AND STDERR): New section.
+ (ABOUT TEST FRAMEWORKS): Add sed/cmp/diff (a la C News) as an option.
+
+ * NEWS: Change entry regarding "cvs log" not invoking "rlog" so
+ that it emphasizes user-visible behaviors.
+
+Tue Aug 6 17:01:23 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * TODO: Remove item #167 (cvs log doesn't understand symbolic
+ branch names). It works now.
+
+ * NEWS: Mention that "cvs log" no longer invokes "rlog".
+
+Wed Jul 31 16:06:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Mention rule about _ vs - in file names.
+
+Wed Jul 24 19:10:38 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * NEWS: Mention that Kerberos encryption is now supported.
+
+Mon Jul 22 23:48:39 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * NEWS: Mention that the commit message has changed slightly when
+ committing changes on a branch.
+
+Fri Jul 19 16:10:04 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Say that GNU expr is part of sh-utils.
+
+Thu Jul 18 18:16:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention -k wrappers option.
+
+ * TESTS: In list of what we would like in a test framework, only
+ mention portable once, and other wording cleanups.
+
+Mon Jul 15 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Add src/ChangeLog (lets us edit it from within
+ the integrated development environment).
+
+Sun Jul 14 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Add src/zlib.c. Add zlib group containing the .c
+ files in zlib. Add /I "zlib" compiler options.
+
+Sun Jul 14 10:26:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Expand zlib item to emphasize user-visible (and
+ CVS-installer-visible) consequences.
+
+Sat Jul 13 21:11:50 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * NEWS: Mention that -z now uses zlib.
+
+Fri Jul 12 18:54:21 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * Makefile.in (USOURCE_SUBDIRS): Add zlib.
+ * configure.in (AC_OUTPUT): Add zlib/Makefile.
+ * configure: Regenerate.
+
+ * zlib/*: Import zlib 1.0.3. Remove zlib/Makefile. Modify
+ zlib/Makefile.in for use with CVS.
+
+Fri Jul 12 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Add src/buffer.c
+
+Wed Jul 10 18:44:58 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Say that rlog is deprecated.
+
+Tue Jul 9 14:37:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * PROJECTS: Refer to comment in rcscmds.c regarding RCS library.
+
+ * HACKING: Expand comments on portability.
+
+Sun Jul 7 23:21:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS): Remove memmove; it was used by
+ a very old version of the CVS server for nefarious purposes and it
+ has been long gone.
+ * configure: Regenerated.
+
+Tue Jul 2 22:36:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Add discussion of test frameworks.
+
+Fri Jun 28 20:27:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Describe "cvs diff -q" removal and new diff options.
+
+Thu Jun 13 17:29:30 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Remove item #67 about having cvs import create CVS
+ directories; I don't think it is wise to have cvs import mess with
+ the directory it is working in at all. Remove item #69 about
+ having import edit modules--in many cases there is no need for an
+ entry in modules. Remove item #76 about running on top of SCCS;
+ we are clearly not evolving in that direction. Remove item #91
+ about documenting how to import sources from SCCS or RCS; this is
+ now documented in cvs.texinfo. Remove item #129 about "U CFTS/";
+ without more information it is impossible to know what behavior is
+ being discussed. Remove item #157 concerning module names in cvs
+ release; cvs release takes a directory name, not a module name.
+ Remove item #159 about checking access times; this is as likely to
+ be an annoyance as a help, and people who are into that can just
+ look at the result from "cvs update" (directly or with a script).
+ Remove item #164 concerning variables in *info files; it is done.
+ Remove item #35 (it just says "cvs admin" is cheesy, which isn't
+ specific enough to be useful). Rewrite #39 to be specific about
+ what would be nice in having branches track each other. Remove
+ item #46--I'm not sure what it means and if it means that one
+ should check in with "cci" or some such instead of "cvs ci" then
+ that is an installation hassle and a minimal convenience. Add
+ item #180.
+
+ * config.h.in: Regenerated.
+
+Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * configure.in: Put -L${krb_libdir} in LDFLAGS temporarily when
+ looking for -ldes.
+ * configure: Regenerated.
+
+Mon Jun 10 13:13:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention NT local.
+
+Fri Jun 7 18:02:36 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * NEWS: Mention new annotate options.
+
+Thu Jun 6 14:08:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * lib/savecwd.c: Revert CVS_* patch. The include files where
+ CVS_* is defined were not included, and the code in question was
+ inside HAVE_FCHDIR which isn't defined on the Mac anyway.
+
+ * src/filesubr.c: Revert CVS_* patch in this one file. The mac
+ port should have its own copy of filesubr.c instead.
+
+Wed Jun 05 10:03:10 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * lib/{system.h,savecwd.c}, src/{add.c,checkout.c,client.c,
+ commit.c,create_adm.c,diff.c,edit.c,entries.c,fileattr.c,
+ filesubr.c,find_names.c,history.c,ignore.c,import.c,lock.c,
+ login.c,logmsg.c,mkmodules.c,modules.c,myndbm.c,no_diff.c,
+ parseinfo.c,patch.c,rcs.c,recurse.c,release.c,remove.c,root.c,
+ rtag.c,server.c,tag.c,update.c,vers_ts.c,wrapper.c}:
+ Under non-UNIX operating systems (MS-DOS, WinNT, MacOS), many
+ filesystem calls take only one argument; permission is handled
+ very differently on those systems than in UNIX. On MacOS,
+ the naming scheme for volumes and subdirectories is quite
+ different. This patch leaves hooks in the form of CVS_ACCESS,
+ CVS_CHDIR, CVS_CREAT, CVS_FOPEN, CVS_MKDIR, CVS_OPEN, CVS_OPENDIR,
+ CVS_RENAME, CVS_RMDIR, CVS_STAT, and CVS_UNLINK to accomodate
+ these differences.
+
+Thu Jun 6 11:11:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Say "changes from 1.7 to 1.8" not "changes since 1.7".
+
+Wed Jun 5 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Visual C++ 2.1 seems to want to reformat the line
+ breaks. No substantive changes, I think.
+
+Thu May 30 15:35:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): add TESTS.
+
+Tue May 28 13:10:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * src/server.c: Add comment regarding out-of-order bug.
+ * TESTS: Explain out-of-order bug.
+
+ * INSTALL: Remove $CVSId$. More strongly encourage people to skip
+ the tests if they don't have the time to look at the results.
+ Move most of the discussion of tests to new file TESTS, and add
+ some information on interpreting check.log output.
+ * README: In brief summary of install, don't spell out details of
+ "make check" or "cvs init" steps.
+
+Sun May 26 17:59:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Change "up-to-date" to "not locally modified"; the file
+ need not match the head revision it only need match some revision.
+
+Sun May 26 17:02:49 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * NEWS: document new option "-c" for tag
+
+Thu May 23 21:49:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Remove footnote 10. The only kind of change suitable
+ for listing here is fairly easy portability stuff.
+
+Fri May 17 11:49:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Refer to cvs.texinfo and say "filesystem" not "fs".
+
+Thu May 16 17:13:56 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * NEWS: Mention all access methods.
+
+Wed May 15 23:38:15 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * NEWS: add info about access methods and document behavior change
+ for "cvs login."
+
+Mon May 13 10:37:09 1996 Greg A. Woods <woods@most.weird.com>
+
+ * INSTALL: updated for Sun-3 SunOS 4.1.1_U1 (1.8.2)
+
+Fri May 10 09:39:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Document that -d overrides CVS/Root.
+
+Mon May 6 06:00:10 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.8.1
+
+Sun May 5 17:38:21 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ Integrated changes submitted by Ian Taylor <ian@cygnus.com>
+
+ * update.c (update_dirent_proc): cvs co -p doesn't print
+ anything when run from an empty directory.
+
+ * import.c (import_descend_dir): Check for a file in the
+ repository which will be checked out to the same name as the
+ directory.
+
+Sun May 5 15:49:00 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * configure.in: autoconf 2.9 handles AC_CHECK_LIB in a
+ way that it can not be used to check for main(). Check
+ for printf() instead. (Reported by ian@cygnus.com)
+
+ * configure: Regenerated.
+
+Thu May 2 13:34:37 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.7.88
+
+Thu May 2 10:42:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Clarify what happened to examples directory.
+
+Thu May 2 02:06:49 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * INSTALL: Updated for NeXTSTEP 3.3 (1.7)
+
+Thu May 2 01:40:55 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Compatibility fixes affecting QNX, NetBSD, and SCO
+
+ * configure.in (AC_CHECK_FUNCS): Added check for initgroups(),
+ (ac_cv_func_crypt) Added check for crypt() in -lcrypt;
+ define AUTH_SERVER_SUPPORT only if crypt() is found.
+
+ * configure: Regenerated.
+
+ * src/server.c (HAVE_INITGROUPS): Use initgroups() only if
+ located by configure.
+
+Wed May 1 15:38:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Remove item about reserving all-uppercase tag names.
+
+Wed May 01 00:18:01 1996 noel <noel@BOAT_ANCHOR>
+
+ * cvsnt.mak: remove all of those unnecessary libraries! We only
+ need advapi32.lib and wsock32.lib.
+
+Wed Apr 24 16:48:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Document that -d overrides CVS/Root.
+
+Fri Apr 19 11:22:35 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.7.86
+
+Sun Apr 14 11:06:44 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * configure.in (AC_OUTPUT): generate contrib/elib/Makefile,
+ tools/Makefile, and tools/pcl-cvs/Makefile. Do not any longer
+ generate contrib/pcl-cvs/Makefile.
+
+ * Makefile.in: deal w/ above changes.
+
+ * configure: regenerated.
+
+ * Added `tools' subdir (pcl-cvs will live there, as will other
+ things maintained along with the CVS distribution).
+
+Wed Apr 10 17:15:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Mention documentation and A4 paper in particular.
+
+Thu Mar 28 12:31:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add "cvs annotate".
+
+Tue Mar 26 10:46:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: In example, change tag name to avoid using a tag name
+ reserved to CVS.
+
+ * NEWS: Document reservation of some tag names.
+
+Fri Mar 22 10:45:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Clarify that RCS is only for server or local.
+
+Mon Mar 18 10:15:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Mention info@cyclic.com where we mention support
+ contracts, not at the end where people might be tempted to view it
+ as a generic help line.
+
+Thu Mar 14 16:34:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (stamp-h): Don't run ./config.status --recheck.
+
+Thu Mar 14 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Regenerate dependencies.
+
+Thu Mar 14 13:45:11 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * configure.in (AC_OUTPUT): Don't create examples/Makefile; we're
+ not using the examples directory any more.
+
+Wed Mar 13 17:02:00 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Refer to cvs.texinfo rather than out-of-date cvsinit
+ instructions. Instead of telling everyone to update modules
+ whenever adding directories (which is optional), refer to the
+ manual regarding all administrative files. Revise "make check"
+ instructions to be even less encouraging about submitting bug
+ reports.
+
+ * examples/*: Removed.
+ * Makefile.in (SUBDIRS): Remove examples.
+ * cvsinit.sh: Removed.
+ * Makefile.in: Remove all cvsinit and PROGS stuff.
+ * NEWS: Mention cvsinit -> cvs init change.
+
+Mon Mar 11 13:12:35 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * BUGS: removed previous description from Greg Woods (3/6/96)
+ since the bug seems to be corrected
+
+Wed Mar 6 10:35:32 1996 Greg A. Woods <woods@most.weird.com>
+
+ * BUGS: describe a weird core-dump with 'cvs co -c'. Now I can't
+ even get a stack backtrace again -- dbx dumps core!
+
+Fri Mar 1 09:21:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.VMS: Remove distribution information (since it is no
+ longer different for VMS). Various wording fixes to reflect the
+ fact that using rsh is just one of several ways to connect to a
+ cvs server, not "the official" one. Say that the unsuitable rsh
+ is the UCX one. Clarify what rsh uses privileged ports for.
+
+Fri Mar 1 01:26:28 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * README.VMS, build.com: Added for VMS.
+
+Thu Feb 29 10:04:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention change to default ignore list.
+
+Thu Feb 29 00:28:08 1996 Peter Wemm <peter@jhome.DIALix.COM>
+
+ * configure.in: correctly spell FNM_PATHNAME in fnmatch() test,
+ the supplied test fails on proposed POSIX.2, lib/fnmatch.*, Linux,
+ FreeBSD, etc.
+ * configure: Regenerated.
+
+Tue Feb 27 10:43:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Change submission address to bug-cvs from info-cvs.
+ Encourage submissions to be in the form of diffs to INSTALL.
+
+Sun Feb 25 15:23:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Fix typo.
+
+Fri Feb 23 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Add login.c and scramble.c.
+
+Fri Feb 23 16:36:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Mention comp.software.config-mgmt. Don't mention old
+ cyclic-cvs mailing list.
+
+ * acconfig.h: Add AUTH_SERVER_SUPPORT. Remove DIFF and GREP (no
+ longer used).
+ * configure.in: Define AUTH_SERVER_SUPPORT.
+ * config.h.in, configure: Regenerated.
+
+Thu Feb 22 22:32:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Remove AC_FUNC_ALLOCA.
+ * configure: Regenerated.
+
+Mon Feb 19 09:39:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Add comments about portability and assert().
+
+Thu Feb 15 16:40:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention $USER internal variable.
+
+Thu Feb 15 14:00:00 1996 Gary Oberbrunner <garyo@avs.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * cvsnt.mak: Add vasprintf.c and mkmodules.c
+
+Tue Feb 13 20:05:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS): Add strtoul.
+ * configure: Regenerated.
+
+Mon Feb 12 10:06:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Remove mkmodules stuff.
+ * NEWS: Add item concerning mkmodules.
+
+ * configure.in (AC_REPLACE_FUNCS): Add vasprintf.
+ * configure: Regenerated.
+
+Sun Feb 11 16:43:38 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * Makefile.in (DISTFILES): added HACKING.
+
+Sun Feb 11 12:38:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Revise *info files feature (now user vars, not env vars).
+
+Fri Feb 9 23:51:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention env var in *info files feature.
+
+Fri Feb 9 02:41:50 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove config.sub and config.guess from
+ the list; they're not distributed any more.
+
+Thu Feb 1 19:47:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Remove RM; no longer used.
+
+Thu Feb 1 14:38:04 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * configure: re-ran autoconf.
+
+ * Makefile.in (USOURCE_SUBDIRS, SUBDIRS): abstract unix source
+ subdirs to new var USOURCE_SUBDIRS, for lint's sake and possibly
+ etags's someday.
+ (lint): run in USOURCE_SUBDIRS only.
+
+Thu Feb 1 13:06:47 1996 Roland McGrath <roland@baalperazim.frob.com>
+
+ * configure.in (WITH_KRB4): Escape $ in help text.
+
+Wed Jan 31 19:03:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * HACKING: Add info about NEWS file and release process.
+
+Tue Jan 30 16:00:00 1996 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * cvsnt.mak: Change save-cwd.c to savecwd.c and regenerate
+ dependencies to take care of save-cwd.h.
+ * windows-NT/README: Update information about Visual C++ 4.0.
+
+Tue Jan 30 16:09:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Rename lib/save-cwd.c to lib/savecwd.c. Avoiding a hyphen
+ seems to be the only way to get Visual C++ 2.1 to generate a
+ cvsnt.mak which Visual C++ 4.0 will accept.
+ * Rename lib/save-cwd.h to lib/savecwd.h for consistency.
+ * os2/Makefile.in, lib/Makefile.in, lib/savecwd.c, src/add.c,
+ src/import.c, src/modules.c, src/recurse.c, src/tag.c: Update
+ accordingly.
+
+ * INSTALL, os2/options.h, windows-NT/options.h,
+ macintosh/options.h, src/options.h.in: Remove SORT; it is no
+ longer used.
+
+Mon Jan 29 15:16:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Mention -b. Don't talk about RCS 5.6.[5-7] beta
+ releases; this will be an issue for few if any people. Remove
+ stuff about diff and --with-diffutils which is no longer true.
+
+ * README: Refer to HACKING file. Refer to cvs.texinfo not
+ manpage. Rewrite section about compatibility between CVS versions.
+ * HACKING: New file.
+ * INSTALL: Move -Wall section to HACKING; refer to HACKING.
+
+Wed Jan 24 20:26:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Remove diff stuff. Also remove AC_CANONICAL_HOST
+ and bindir crud as that was the only place they were used.
+ * config.h.in, configure: Regenerated.
+ * config.sub, config.guess: Removed.
+ * src/options.h.in (DIFF): Change to "diff" and change comment to tell
+ people not to use -a.
+ * src/sanity.sh: New test binfiles tests for above-fixed bug (see
+ comments in patch_file in update.c--passing -a to diff generates a
+ patch which patch cannot apply).
+
+ * NEWS: Adjust to reflect existence of 1.7.
+
+Tue Jan 23 14:20:39 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * devel-cvs: New file, not to be included in the distribution.
+
+Thu Jan 18 21:46:56 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * BUGS: Remove all mention of the outdated cyclic-cvs@cyclic.com
+ and remote-cvs@cyclic.com addresses. It turns out that people see
+ these addresses and use them. Mention the proper way to report
+ bugs.
+
+Wed Jan 17 16:40:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Fix typo (info-cvs-requests -> info-cvs-request).
+
+Fri Jan 12 13:38:12 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in, configure: Revert "Checking user's gender" change.
+ Sure, you only live once, but I want mine to be a *long* life, not
+ one interrupted by a CVS user who is not amused coming after me
+ with an axe.
+
+Fri Jan 12 12:46:23 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * configure: regenerated.
+
+ * configure.in: print "Checking user's gender... ok". I mean,
+ what the heck, you only live once.
+
+Thu Jan 11 14:00:00 1996 Jim Kingdon <peary.cyclic.com>
+
+ * cvsnt.mak: Update dependencies.
+
+Thu Jan 11 12:03:10 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * NEWS: document loss of CVS_NOADMIN. Also, mention the
+ possibility to use "cvs" in .cvsrc.
+
+Wed Jan 10 20:40:23 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * configure: regenerated.
+
+ * configure.in (AC_OUTPUT): added `macintosh/Makefile'.
+
+ * Makefile.in (SUBDIRS): added `macintosh'.
+
+Wed Jan 10 01:17:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Remove URL of obsolete David Zuhn web page.
+
+ * FAQ: Replace entire file with short paragraph explaining the FAQ
+ is dead.
+
+ * configure.in: Don't set exec_prefix. Set bindir from prefix if
+ exec_prefix isn't set.
+ * configure: Regenerated.
+
+ * INSTALL: Update list of machines for 1.6.85 (further changes to
+ the list of machines will not receive ChangeLog entries).
+
+Tue Jan 9 09:02:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention changes in default ignore list.
+
+ * INSTALL: check.log is not in /tmp/cvs-sanity. Mention
+ submitting bug reports as a possibility, not a request from us.
+ Separate out "make check" a bit to make clear it is optional.
+
+Mon Jan 8 11:42:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Remove grep stuff; no longer necessary.
+ Don't say that patch must understand unidiffs; no longer true.
+ Suggest configuring with -Wall (here until we have a "how to hack
+ CVS document").
+
+Wed Jan 3 19:00:00 1996 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * .cvsignore: Add cvsnt.vcp.
+
+Mon Jan 1 22:45:50 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * os2/Makefile.in (Makefile), windows-NT/Makefile.in (Makefile):
+ New rules.
+
+Sun Dec 31 16:52:49 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * NEWS: add a blurb about password authentication.
+
+Sun Dec 31 16:16:38 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Add "submissions will be distributed under the GPL"
+ language (like the newspapers have for letters to the editor).
+
+Thu Dec 21 16:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * cvsnt.mak: Revert to an old version, then add in recent changes
+ to lists of files (using Visual C++; not by hand editing--this way
+ it can be used as an internal project not just an external one).
+
+Tue Dec 19 17:13:14 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Mention -kb (strictly speaking a bugfix, not a new
+ feature, I guess, but it seems worth mentioning anyway).
+
+Tue Dec 19 17:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * TODO: Remove "regular TODO list:" line which accidentally got
+ checked in.
+
+Mon Dec 18 18:59:30 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (TAR_VERBOSE): Default to empty, not "v". I don't
+ want that whole long list of files any more than jimb's daily
+ update script does.
+
+Sun Dec 17 23:59:11 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS): Remove vasprintf.
+ * configure: Regenerated.
+
+Sat Dec 16 17:19:45 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS): Add vasprintf.
+ * configure: Regenerated.
+
+Mon Nov 20 14:19:47 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Remove items about developer communications; they are done.
+ * NEWS: Mention developer communication features.
+ * cvsinit.sh: Also add notify file.
+
+Mon Dec 11 22:44:58 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * New subdir "macintosh", for Mike Ladwig's
+ <mike@twinpeaks.prc.com> port-in-progress.
+
+Thu Dec 7 14:32:49 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (check): Make sure library is built before running
+ make in src.
+ (remotecheck): Likewise.
+ (installcheck): Likewise.
+
+Wed Dec 6 11:40:37 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * configure.in: Remove leading -l from first argument of
+ AC_CHECK_LIB for -lkrb and -ldes checks.
+
+Mon Dec 4 08:06:31 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h.in: Regenerated.
+
+Sun Dec 3 20:05:10 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in: Remove grep stuff.
+ * configure: Regenerated.
+
+Fri Dec 1 11:16:18 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * configure, config.h.in: re-ran autoconf
+
+ * configure.in (AC_CHECK_HEADERS): add sys/resource.h to list of
+ tested headers
+
+ * Makefile.in (DISTFILES): add config.sub and config.guess
+
+Thu Nov 23 09:01:53 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Remove item about doc describing undoing a change; it
+ already does.
+
+Sun Nov 19 18:12:36 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (dist): Pull out the 'v' in the tar command to a
+ variable, so I can disable it in my daily update script.
+
+Tue Nov 14 18:31:36 1995 Greg A. Woods <woods@most.weird.com>
+
+ * cvsinit.sh:
+ - new rcs id
+ - new opening comment
+ - read only one "word" for CVSROOT
+ - add checkoutlist, cvswrappers, taginfo, wrap, & unwrap to
+ examples install loop, special handling for latter....
+ - don't do any special stuff for loginfo -- always comment out
+ everything in the newly installed examples
+ - add a wee message to suggest editing newly installed examples
+ - tweak some more comments, esp. regarding install of contrib
+ scripts....
+ - make $CVSROOT/CVROOT/history group writable if it didn't exist
+ as it's not very useful otherwise
+
+Tue Nov 14 15:22:25 1995 Greg A. Woods <woods@most.weird.com>
+
+ * cvsinit.sh: woops! wasn't installing contrib/log!
+
+Tue Nov 14 12:09:11 1995 Greg A. Woods <woods@most.weird.com>
+
+ * INSTALL: oops, missed a couple of things about "configure"
+
+ * configure: re-ran autoconf
+
+Tue Nov 14 11:06:25 1995 Greg A. Woods <woods@most.weird.com>
+
+ * config.guess, config.sub: first time in (from autoconf-2.4)
+
+ * configure.in:
+ - updated to work with autoconf-2.4
+ - call AC_CANONICAL_HOST to get host OS type right (needs
+ config.sub and config.guess)
+ - added full support for --with-diffutils and --with-gnugrep
+ - fixed the diff search to work almost like the one for RCS-5.7
+ - fixed some quoting problems
+
+ * README: mention optional 'make check' step
+
+ * INSTALL:
+ - updated notes about working SunOS versions
+ - re-wrote notes about RCS, diffutils, etc.
+ - added notes about configuring with GNU diffutils and GNU grep
+ - added notes about using 'make check'
+ - changed bug reporiting instructions to mention cvsbug
+ - re-wrote notes about setting CVSROOT in shell startups
+
+Fri Nov 3 11:11:16 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Fix typo in URL of molli's web site.
+
+Tue Oct 31 19:28:16 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * testing something, please ignore.
+
+Mon Oct 23 18:37:27 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * configure: re-ran autoconf.
+
+ * configure.in (AC_OUTPUT): os2/Makefile.
+
+ * Makefile.in (SUBDIRS): added os2 subdir.
+
+Mon Oct 23 12:02:51 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvsnt.mak: added lib/getline.c
+
+Fri Oct 20 17:04:55 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvsnt.mak: added src/expand_path.c, error.[ch] now in src
+
+Thu Oct 19 16:26:32 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Remove note about RCS 5.7 and log messages
+ consisting only of whitespace; fixed in CVS on 11 Jul 95.
+
+Tue Oct 17 17:57:23 1995 Warren Jones <wjones@tc.fluke.com>
+
+ * man/cvs.5, examples/modules: Document -e.
+
+Tue Oct 10 16:34:25 1995 Thorsten Lockert <tholo@sigmasoft.com>
+
+ * configure.in: More crud looking for kerberos, this time for 4.4BSD.
+ * configure: Regenerated.
+
+Sun Oct 8 12:22:19 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * configure.in: check for POSIX and BSD style reliable signals
+ * configure: regenerated by autoconf
+ * config.h.in: regenerated by autoheader
+
+Fri Oct 6 21:50:48 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ There is little point in trying to share a file as trivial as
+ lib/error.c between programs. So just admit it is CVS specific:
+ * lib/error.c: Move from here...
+ * src/error.c: ...to here, and remove CVS_SUPPORT ifdefs.
+ * lib/error.h: Move from here...
+ * src/error.h: ...to here. Remove CVS_SUPPORT
+ ifdefs; remove unused variable error_message_count.
+ * src/Makefile.in (OBJECTS): Add error.o.
+ (SOURCES): Add error.c.
+ (HEADERS): Add error.h.
+ * lib/Makefile.in (OBJECTS): Remove error.o.
+ (SOURCES): Remove error.c.
+ (HEADERS): Remove error.h.
+ * acconfig.h, configure.in: Remove CVS_SUPPORT.
+ * configure, config.h.in: Rebuilt using autoconf and autoheader.
+ * windows-NT/config.h: Remove CVS_SUPPORT.
+
+Thu Oct 5 17:26:38 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Mention Siemens-Nixdorf RM600.
+
+Tue Oct 3 09:32:19 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Remove item about -f global option; it is old news already
+ mentioned elsewhere in the file.
+
+Mon Oct 2 18:12:15 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * FAQ: Updated for CVS 1.5. And now 1.6 is almost out. The FAQ
+ always lags the package, sigh...
+
+Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * configure, config.h.in: Rebuilt using autoconf and autoheader.
+
+ * configure.in: check for <sys/bsdtypes.h>; used by src/server.c.
+ (ISC keeps all the stuff that BSD has in <sys/types.h> here, so
+ we need it for the FD_SET stuff for select().)
+ Moved check for gethostname() after check for connect() since if
+ connect() is not found, we may add librariesd and gethostname()
+ may well be in one of those libraries.
+ If connect() isn't found, look in -linet (ISC) in addition to
+ -lsocket and -lnsl. Also, ignore the cache since we need to
+ update LIBS reguardless of whether it was found before or not and
+ the answer may well be different afterwards.
+ Define CLIENT_SUPPORT and SERVER_SUPPORT only if connect() is
+ found.
+
+ * INSTALL: update info for ISC 4.0.1; renumber footnotes.
+
+Mon Oct 2 17:01:07 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Indicate CVS version tested with Solaris 2.4.
+
+Mon Oct 2 10:42:37 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * (configure): Re-ran autoconf.
+
+Mon Oct 2 10:33:58 1995 Michael Finken <finken@conware.de>
+
+ * configure.in: AC_REPLACE `strstr'.
+
+Sun Oct 1 23:22:28 1995 Bryan O'Sullivan <bos@serpentine.com>
+
+ * (INSTALL): noted that CVS works fine on Solaris 2.4 with both
+ gcc and SPARCworks cc.
+
+Sun Oct 1 18:48:19 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * (configure): re-ran autoconf following Peter Wemm's change
+ below.
+
+Sun Oct 1 22:24:56 1995 Peter Wemm <peter@haywire.dialix.com>
+
+ * configure.in: more extensive searching for -lsocket and -lnsl
+ as done in Taylor-UUCP 1.06
+
+Sun Oct 1 15:32:01 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * (configure): re-ran autoconf.
+
+Sun Oct 1 11:35:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Remove item about setting comment leader automatically;
+ RCS 5.7 does this.
+
+Wed Sep 27 15:34:04 1995 Peter Wemm <peter@haywire.dialix.com>
+
+ * configure.in: correct detection of GNU diff's -a option for
+ src/options.h
+ * configure: regenerate with autoconf
+
+Fri Sep 22 14:29:31 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: Remove item about reindenting on the way in and out.
+ wrappers provide this functionality.
+
+Wed Sep 20 14:27:28 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * configure.in: #define the symbols DIFF and GREP to be the paths
+ to the DIFF and GREP programs; their values will be edited into
+ src/options.h (and config.h, coincidentally).
+ * acconfig.h (DIFF, GREP): Add these.
+ * configure, config.h.in: Rebuilt using autoconf and autoheader.
+
+Sun Sep 10 21:38:05 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO: CVS can already undo a change, suggest documenting how.
+ Expand slightly on mode stuff.
+ Remove item about not letting people check out into repository (it
+ is done).
+ Redo item about expanding env vars in *info to reflect current
+ thinking.
+ Remove item about making it hard to accidentally move tags; it is
+ done.
+ Add client/server note to suggestion regarding interactive merging.
+
+Fri Sep 1 12:07:02 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * BUGS: Remove items about refetching unpatchable files and options.h.
+
+Fri Sep 1 09:20:09 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove cvsnt.vcp; it's been deleted.
+
+Thu Aug 31 13:47:35 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (stamp-h): Rebuild config.status before trying to
+ use it to build config.h.
+
+ * Makefile.in: Change "cd foo; make" to "cd foo && make";
+ otherwise we get into an infinite loop if an objdir doesn't exist.
+
+Thu Aug 31 11:07:06 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * configure.in: Arrange not to touch options.h if we haven't
+ modified it. AC_CONFIG_HEADER checks if the file is unmodified,
+ whereas AC_OUTPUT doesn't, and they're otherwise identical, so...
+ (AC_CONFIG_HEADER): ... mention src/options.h here...
+ (AC_OUTPUT): ... not here.
+ Copy src/options.h to src/options.h-SAVED, don't move it.
+ Otherwise, configure will create it again every time.
+ Remove the code to compare the new src/options.h with
+ src/options.h-SAVED and move it back if it's unchanged; autoconf
+ writes that for us now.
+
+Wed Aug 30 18:45:28 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * .cvsignore: Ignore WinDebug and WinRel directories, used by
+ Microsoft Visual C++ to store object files and executables.
+
+ * acconfig.h (CVS_SUPPORT, CLIENT_SUPPORT, SERVER_SUPPORT): New
+ symbols, which autoheader will use to build config.h.in from
+ configure.in.
+ * configure.in (SERVER_SUPPORT, CLIENT_SUPPORT): Remove spaces
+ between AC_DEFINEs and opening parens of argument lists. Oops.
+ * configure: Rebuild using autoconf.
+ * config.h.in: Rebuild using autoheader.
+
+ * Makefile.in (SUBDIRS): Uncomment windows-NT.
+
+ * INSTALL: Added Windows NT to list of supported platforms.
+ Added Windows NT installation instructions.
+
+Tue Aug 29 16:08:01 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * cvsnt.mak: Completed Windows NT port.
+
+ * configure.in (SERVER_SUPPORT, CLIENT_SUPPORT): Arrange for these
+ to get #defined. In the config.h file for the Windows NT port, we
+ only #define CLIENT_SUPPORT.
+ * config.h.in (SERVER_SUPPORT, CLIENT_SUPPORT): Add #undefs for
+ these.
+
+ * configure.in (AC_OUTPUT): Build the Makefile for the windows-NT
+ subdirectory too.
+
+ * cvsnt.vcp: Removed. This doesn't store any information needed
+ to compile CVS; it seems to be mostly programmer preference stuff.
+ There's no need to distribute it.
+
+ * INSTALL: Added info about Harris Nighthawk from Steve Allen ---
+ thanks!
+
+Mon Aug 21 16:08:37 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ Bring the saga to a close:
+ * configure.in: Use AC_PROG_MAKE_SET here, to decide whether we
+ need to set the MAKE variable in Makefile.
+ * Makefile.in: Use @SET_MAKE@ here, to set MAKE when appropriate.
+
+Mon Aug 21 15:26:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Add comment regarding AC_SET_MAKE.
+
+Sat Aug 19 21:57:51 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * configure.in: Define CVS_SUPPORT, to tell certain library
+ functions that they're part of CVS.
+ * config.h.in: Add #undef for CVS_SUPPORT, for configure to chew
+ on.
+
+Fri Aug 18 22:35:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Don't set MAKE; apparently all makes set it and GNU
+ make, at least, will set it to what make was invoked as (perhaps gmake
+ or some such), not just "make" (which might not support VPATH, for
+ example).
+
+Sun Aug 13 23:35:47 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Convert Data General entry to same format as other entries.
+
+Sun Aug 13 13:11:36 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * cvs-format.el: Add note about set-c-style.
+
+Thu Aug 3 16:13:29 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * INSTALL: Fixed mail address for updates.
+
+ * INSTALL: Noted that 1.5 runs on SunOS 4.1.1 -- 4.1.3.
+
+Sun Jul 30 20:12:26 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsinit.sh: Unify code for modules and loginfo with code for
+ other files which have checked-out and ,v files in CVSROOT.
+ Don't add "#" to start of lines in rcstemplate.
+
+Sat Jul 29 16:48:05 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsinit.sh: If arguments are given, give version number and
+ usage message. Make printed messages much more concise.
+
+ * cvsinit.sh: Rename log.pl to log. Don't install log twice.
+
+ * Makefile.in (install-local), contrib/Makefile.in (install):
+ Remove "reminder" to run cvsinit; running cvsinit is not required.
+
+Fri Jul 28 16:46:10 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (SUBDIRS): Comment out windows-NT.
+
+Fri Jul 28 02:27:54 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add cvsnt.mak and cvsnt.vcp.
+ (SUBDIRS): Add windows-NT.
+
+ * config.h.in: Regenerated from configure.in by autoheader.
+
+Wed Jul 19 18:00:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * configure.in (AC_CHECK_HEADERS): Check for <io.h> and <direct.h>.
+
+Tue Jul 18 21:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * configure.in (AC_CHECK_HEADERS): Check for sys/param.h; Windows NT
+ doesn't have it.
+
+ * configure.in (AC_CHECK_HEADERS): Check for sys/time.h. If you're
+ using AC_HEADER_TIME, it's best to check for this too.
+
+ * cvsnt.mak: New file --- makefile equivalent for Microsoft Visual C++.
+ Choose this as your project when working with CVS under MSVC++.
+ * cvsnt.vcp: New file --- configuration info for Microsoft Visual C++.
+ * windows-NT: New subdirectory, containing files to be used to
+ build under Microsoft Windows NT.
+
+Wed Jul 12 23:26:24 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Remove duplicate install-info rule.
+
+Wed Jul 12 16:00:27 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (install-local): added rule for install-info, made
+ `install' depend on it.
+
+ * README: correct mailing list addresses.
+ * INSTALL: same.
+
+Wed Jul 12 09:15:02 1995 Jim Meyering (meyering@comco.com)
+
+ * configure.in (gdiff_path): Remove gdiff from the list of programs.
+ SGI's Irix includes a program named gdiff that is an X-based GUI to
+ diff.
+
+ * configure.in: Add check for working fnmatch functions so that
+ systems providing it don't incur the space overhead of linking
+ with the version in lib. Cross compiling builds always use the
+ version in lib.
+
+Tue Jul 11 15:47:20 1995 Greg A. Woods <woods@most.weird.com>
+
+ * configure.in: add some FIXME comments
+ - add a hack to restore src/options.h if AC_OUTPUT() didn't modify
+ it. Note that this does *not* work for config.status, thus one
+ FIXME comment.
+ - add test for #! (to warn about possible failure of perl scripts
+ - add test for diff and grep paths (for src/options.h.in)
+ - fix up handling of src/options.h.in
+ - add checks for PERL_PATH and CSH_PATH (from previous local changes)
+
+Tue Jul 11 14:31:18 1995 Michael Shields <shields@tembel.org>
+
+ * Makefile.in (LDFLAGS): Pick up from configure.
+
+Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * configure: re-ran autoconf-2.4
+
+ * cvsinit.sh: make use of xVERSIONx from the Makefile
+ - get rid of stuff duplicated in examples/* and use that instead
+
+ * Makefile.in: $(VERSION) for cvsinit.sh wasn't set, so get it
+ from src/version.c instead.
+
+ * cvsinit.sh: install two more example CVSROOT control/config
+ files: rcstemplate checkoutlist
+ - install useful scripts from $CVSLIB/contrib too...
+ (from previous local changes)
+
+ * Makefile.in: add another reminder to run 'cvsinit' to update
+ repository(ies) (from previous local changes)
+
+Thu Jul 6 17:53:55 1995 Paul Eggert <eggert@twinsun.com>
+
+ * Makefile.in (mostlyclean-local): Remove $(PROGS).
+
+Sat Jul 1 13:11:41 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.5.1.
+
+Thu Jun 29 01:02:09 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in, configure: cross_compiling gets set to "no", not
+ empty--change test accordingly.
+
+ * Version 1.4.93.
+
+Wed Jun 28 22:33:54 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * lib/Makefile.in, man/Makefile.in, doc/Makefile.in: Comment out
+ rules for configure and config.status, just like in Makefile.in or
+ src/Makefile.in.
+
+Tue Jun 27 19:53:05 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS), configure: Remove fnmatch.
+ * lib/Makefile.in (OBJECTS): Add fnmatch.
+ Avoids buggy Solaris 2.4 libc fnmatch.
+
+ * FAQ: Updated with new version from ftp.odi.com.
+
+Mon Jun 26 15:17:46 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.4.92.
+
+Thu Jun 22 12:45:24 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.4.91.
+
+Wed Jun 21 16:33:04 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * PROJECTS: New file.
+ * Makefile.in (DISTFILES): Add it.
+
+Wed Jun 21 16:12:14 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (FLAGS_TO_PASS): Don't pass INSTALL to sub-makes.
+ The reason for passing it is gone now that we are using autoconf
+ 2.x which will set INSTALL in the sub-makefiles correctly.
+
+Tue Jun 20 18:14:54 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in, configure: Make sure src directory exists before
+ trying to copy options.h to it.
+
+Mon Jun 19 13:47:20 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in: Add a "remotecheck" target here, for consistency;
+ people shouldn't have to switch to src before running the tests.
+
+Mon Jun 19 10:08:03 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * INSTALL: Update list of machines tested. Remove note about
+ systems missing opendir--this is an autoconf issue, not something
+ installers should have to worry about. Refer to NEWS instead of
+ ChangeLog. No longer "strongly recommend" putting diff -a in
+ options.h.
+
+Fri Jun 16 22:30:03 1995 Jim Kingdon (kingdon@cyclic.com)
+
+ * Version 1.4.90.
+
+ * configure, configure.in (AC_OUTPUT): Add config/pcl-cvs/Makefile.
+
+ * Makefile.in (dist): Rename dist from ccvs-<version> to cvs-<version>.
+
+ * Makefile.in (dist, dist-dir), src/Makefile.in, doc/Makefile.in,
+ examples/Makefile.in, contrib/Makefile.in,
+ contrib/pcl-cvs/Makefile, man/Makefile.in, lib/Makefile.in
+ (dist-dir): Use srcdir where appropriate.
+
+Thu Jun 15 14:33:37 1995 Jim Kingdon (kingdon@cyclic.com)
+
+ * CYCLIC-CVS-FAQ: Removed.
+ * Rename ChangeLog.fsf to NEWS. Add information about changes
+ since 1.4A2.
+ * Makefile.in (DISTFILES): Adjust accordingly.
+ * README: Revise to reflect current status of releases.
+
+Thu Jun 15 12:22:42 1995 Jim Kingdon (kingdon@cyclic.com)
+
+ * TODO: Remove various items already fixed. Revise others.
+
+Thu Jun 15 12:24:45 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * configure.in: Use AC_C_INLINE to handle inline.
+ Reorganized to put compiler and OS checks first so that any
+ special defines they might provide are used in subsequent tests.
+
+ * configure, config.h.in: regenerated with autoconf and
+ autoheader version 2.3.
+
+Thu Jun 8 16:33:51 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * INSTALL (Installation): Disrecommend RCS 5.6.[5-7].
+
+Tue May 30 00:07:15 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (distclean-local): Don't delete config.status here.
+ (distclean): Delete config.status here instead, but only after
+ recursive make invocations. Otherwise, the new dependencies
+ in */Makefile.in on ../config.status led to failure in each sub-make
+ because there is no rule there to make ../config.status.
+ Reported by Jeff Johnson <jbj@brewster.jbj.org>.
+ (realclean): Likewise.
+
+Mon May 29 22:24:28 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * configure.in: Use AC_HEADER_DIRENT instead of AC_DIR_HEADER.
+ Use AC_HEADER_STAT to determine if S_FOO() macros work.
+ Use AC_HEADER_TIME to determine if both <sys/time.h> and <time.h>
+ can be included as recommend by autoconf manual.
+ Remove AC_STRUCT_TM test, as above test is better.
+
+ * configure, config.h.in: regenerated with autoconf and
+ autoheader version 2.3.
+
+Fri Apr 28 14:36:49 1995 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * Makefile.in: Set "all" as default target instead of ".PHONY".
+ Some versions of make will otherwise try building all of the phony
+ targets, in order.
+
+Mon May 1 14:02:42 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * configure.in: Set up src/options.h for the user. Its defaults are
+ usually right.
+ * README, INSTALL: Adjust installation instructions appropriately.
+
+Fri Apr 28 22:31:26 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (DISTFILES): Brought up-to-date.
+ (dist): Rewritten to use dist-dir targets, passing DISTDIR variable.
+ (GZIP, GZIP_EXT): New variables.
+ (dist-dir): New target.
+
+ We don't want to include a file the user has to edit in the
+ distribution.
+ * src/options.h: No longer distributed.
+ * src/options.h.in: Distribute this instead.
+ * INSTALL, README: Installation instructions updated.
+
+Sat Apr 8 19:02:21 1995 Roland McGrath <roland@baalperazim.frob.com>
+
+ * configure.in: Check for fchdir.
+ (connect check): Use AC_CHECK_LIB instead of (obsolete)
+ AC_HAVE_LIBRARY.
+
+Sat Apr 8 14:52:46 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (CFLAGS): Let configure set the default for CFLAGS.
+ Under GCC, we want -g -O.
+
+Wed Feb 8 06:49:49 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * Makefile.in (stamp-h): Pass CONFIG_FILES=$@ to config.status so
+ the target is created.
+ * configure.in: Applied `autoupdate' from Autoconf 2.1 to
+ modernize macro usage.
+ (AC_RSH): Call removed. It was obsolete and not doing anything useful.
+ (AC_OUTPUT): Write stamp-h as the Makefile rules expect we will.
+ (AC_TYPE_PID_T): Add this check.
+
+Tue Nov 8 06:26:54 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Add stamp-h.in. Remove it from .cvsignore.
+
+Fri Oct 28 11:50:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Makefile.in: Comment out autoconf and autoheader rules.
+
+Tue Oct 25 17:44:13 1994 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * Makefile.in (all, install, uninstall): Fail if make in
+ subdirectory fails.
+
+Tue Oct 18 13:26:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Makefile.in (FLAGS_TO_PASS): Pass INSTALL*. Add comment about
+ why we need to.
+
+Tue Sep 27 08:27:06 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Makefile.in (SUBDIRS): Reinstate "contrib".
+ * configure.in (AC_OUTPUT): Add contrib/Makefile.
+ * configure: Regenerated.
+
+Tue Sep 27 01:03:59 1994 John Gilmore (gnu@cygnus.com)
+
+ * Makefile.in (SUBDIRS): Comment out "contrib". Since we don't
+ bother to configure it, we shouldn't make it either.
+
+Wed Aug 10 14:52:57 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * Makefile.in (FLAGS_TO_PASS): Don't include LIBS or CFLAGS twice.
+
+ * configure.in: Include waitpid and memmove in AC_REPLACE_FUNCS
+ list. Don't check for memmove separately.
+ * configure: Regenerated.
+ * config.h.in: Regenerated for Mark's change.
+
+Wed Aug 10 14:32:24 1994 Mark Eichin (eichin@cygnus.com)
+
+ * configure.in (KRB4): recognize --with-krb4=path. Also test for
+ krb_get_err_text so src/main.c and src/client.c can deal
+ appropriately.
+
+Tue Aug 9 15:49:07 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * configure.in: Check sizes of `long' and `int', needed for md5
+ code.
+ * acconfig.h: New file. Mention HAVE_KERBEROS, to keep autoheader
+ happy.
+ * configure, config.h.in: Regenerated.
+
+Tue Jul 19 11:23:21 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * configure.in: Check not only that krb.h exists, but that it will
+ actually compile correctly.
+ * configure: Regenerated.
+
+Mon Jul 11 07:04:36 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * configure.in: Add comment re autoheader.
+
+Tue Jun 28 22:09:23 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * configure.in: Only look for -lsocket and -lnsl if we don't
+ already have connect.
+ * configure: Regenerated.
+
+Mon Jun 27 17:21:48 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * configure.in: Correct "krb_libdir" to "${krb_libdir}".
+ * configure: Regenerated.
+
+Fri Jun 3 10:15:24 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * configure.in: Check for -lsocket and -lnsl.
+ * configure: Regenerated.
+
+Fri May 27 18:12:43 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * configure.in: Add valloc to AC_REPLACE_FUNCS. Add getpagesize
+ to AC_HAVE_FUNCS. Check for krb.h and -lkrb. If not found, look
+ in /usr/kerberos if native. If found somewhere, define
+ HAVE_KERBEROS and also look for -ldes. Substitute includeopt.
+ * configure: Regenerated.
+
+Fri Mar 11 13:11:51 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * configure.in: Check for <sys/select.h>; used by src/server.c.
+ * configure: Regenerated.
+
+Sun Jan 9 12:04:15 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * configure.in: Check for timezone function, for NetBSD support.
+ * configure: Regenerated.
+
+Wed Dec 15 18:05:21 1993 david d `zoo' zuhn (zoo@andros.cygnus.com)
+
+ * Makefile.in: add MAKEINFO to MDEFINES, pass down MDEFINES on all
+ recursive make invocations that require it; define
+ INSTALL_PROGRAM and use it; reorganize MDEFINES; set infodir and
+ add to MDEFINES; use YACC instead of BISON
+
+
+Mon Dec 6 17:02:18 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * src/diff.c (diff_fileproc): add support for "cvs diff -N" which
+ allows for adding or removing files via patches.
diff --git a/ChangeLog.zoo b/ChangeLog.zoo
new file mode 100644
index 0000000..a1e1d0e
--- /dev/null
+++ b/ChangeLog.zoo
@@ -0,0 +1,700 @@
+Thu Sep 15 14:19:21 1994 david d `zoo' zuhn <zoo@monad.armadillo.com>
+
+ * Makefile.in: define TEXI2DVI, add it to FLAGS_TO_PASS; remove
+ old comments about parameters for DEFS
+
+Wed Jul 13 21:54:46 1994 david d `zoo' zuhn (zoo@monad.armadillo.com)
+
+ * contrib/rcs-to-cvs: rewritten for Bourne shell (thanks to David
+ MacKenzie <djm@cygnus.com>)
+
+Wed Jul 13 21:48:38 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * Makefile.in: Deleted line consisting of only whitespace; it
+ confuses some versions of make.
+
+Mon Jan 24 12:26:47 1994 david d zuhn (zoo@monad.armadillo.com)
+
+ * configure.in: check for <sys/select.h> and <ndbm.h>
+
+ * Makefile.in: define YACC and not BISON
+
+Sat Dec 18 00:52:04 1993 david d zuhn (zoo@monad.armadillo.com)
+
+ * config.h.in: handle HAVE_SYS_WAIT_H, HAVE_ERRNO_H
+
+ * configure.in: check for memmove, <errno.h>
+
+ * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead
+
+ * configure.in (AC_HAVE_HEADERS): check for <sys/wait.h>
+
+Mon Nov 29 15:05:43 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * lib/Makefile.in, src/Makefile.in (CFLAGS): default to -g.
+
+ * src/log.c (log_fileproc): if a file has been added, but not
+ committed, then say so rather than reporting that nothing is
+ known.
+
+ * src/sanity.el: update for emacs-19.
+
+ * src/RCS-patches, src/README-rm-add: update for rcs-5.6.6.
+
+ * src/Makefile.in: removed some gratuitous diffs from cvs-1.3.
+
+ * src/cvsrc.c: strdup -> xstrdup, malloc -> xmalloc, comment about
+ fgets lossage.
+
+ * configure, configure.in, Makefile.in: support man and doc
+ directories and info and dvi targets.
+
+ * doc/cvs.texinfo: comment out include of gpl.texinfo.
+
+ * doc/Makefile.in: added dvi & info targets.
+
+ * doc/cvsclient.texi: added @setfilename.
+
+ * lib/Makefile.in: remove some extraneous diffs against the
+ patched cvs-1.3.
+
+ * doc/Makefile.in, man/Makefile.in: update for autoconf.
+
+Fri Nov 19 12:56:34 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * Many files: added configure.in, updated configure based on
+ autoconf.
+
+Tue Jun 1 17:02:41 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * configure: add support for alloca and sys/select.h
+
+Wed May 19 19:34:48 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvs-format.el: Don't set c-tab-always-indent.
+
+Mon Mar 22 23:25:33 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * Makefile.in: installcheck: recurse into src directory to run tests
+
+Mon Jan 18 17:21:16 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * Makefile.in (check): recur into src directory in order to pick
+ up the sanity check.
+
+Thu Dec 17 19:41:22 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * Makefile.in: added blank 'dvi' target
+
+Tue Apr 7 15:55:25 1992 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.3 Beta-3 and official CVS 1.3!
+
+ * A new shell script is provided, "./cvsinit", which can be run at
+ install time to help setup your $CVSROOT area. This can greatly
+ ease your entry into CVS usage.
+
+ * The INSTALL file has been updated to include the machines on
+ which CVS has compiled successfully. I think CVS 1.3 is finally
+ portable. Thanks to all the Beta testers!
+
+ * Support for the "editinfo" file was contributed. This file
+ (located in $CVSROOT/CVSROOT) can be used to specify a special
+ "editor" to run on a per-directory basis within the repository,
+ instead of the usual user's editor. As such, it can verify that
+ the log message entered by the user is of the appropriate form
+ (contains a bugid and test validation, for example).
+
+ * The manual pages cvs(1) and cvs(5) have been updated.
+
+ * The "mkmodules" command now informs you when your modules file
+ has duplicate entries.
+
+ * The "add" command now preserves any per-directory sticky tag when
+ you add a new directory to your checked-out sources.
+
+ * The "admin" command is now a fully recursive interface to the
+ "rcs" program which operates on your checked-out sources. It no
+ longer requires you to specify the full path to the RCS file.
+
+ * The per-file sticky tags can now be effectively removed with
+ "cvs update -A file", even if you had checked out the whole
+ directory with a per-directory sticky tag. This allows a great
+ deal of flexibility in managing the revisions that your checked-out
+ sources are based upon (both per-directory and per-file sticky
+ tags).
+
+ * The "cvs -n commit" command now works, to show which files are
+ out-of-date and will cause the real commit to fail, or which files
+ will fail any pre-commit checks. Also, the "cvs -n import ..."
+ command will now show you what it would've done without actually
+ doing it.
+
+ * Doing "cvs commit modules" to checkin the modules file will no
+ properly run the "mkmodules" program (assuming you have setup your
+ $CVSROOT/CVSROOT/modules file to do so).
+
+ * The -t option in the modules file (which specifies a program to
+ run when you do a "cvs rtag" operation on a module) now gets the
+ symbolic tag as the second argument when invoked.
+
+ * When the source repository is locked by another user, that user's
+ login name will be displayed as the holder of the lock.
+
+ * Doing "cvs checkout module/file.c" now works even if
+ module/file.c is in the Attic (has been removed from main-line
+ development).
+
+ * Doing "cvs commit */Makefile" now works as one would expect.
+ Rather than trying to commit everything recursively, it will now
+ commit just the files specified.
+
+ * The "cvs remove" command is now fully recursive. To schedule a
+ file for removal, all you have to do is "rm file" and "cvs rm".
+ With no arguments, "cvs rm" will schedule all files that have been
+ physically removed for removal from the source repository at the
+ next "cvs commit".
+
+ * The "cvs tag" command now prints "T file" for each file that was
+ tagged by this invocation and "D file" for each file that had the
+ tag removed (as with "cvs tag -d").
+
+ * The -a option has been added to "cvs rtag" to force it to clean
+ up any old, matching tags for files that have been removed (in the
+ Attic) that may not have been touched by this tag operation. This
+ can help keep a consistent view with your tag, even if you re-use
+ it frequently.
+
+Sat Feb 29 16:02:05 1992 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.3 Beta-2 and CVS 1.3 Beta-3
+
+ * Many portability fixes, thanks to all the Beta testers! With any
+ luck, this Beta release will compile correctly on most anything.
+ Hey, what are we without our dreams.
+
+ * CVS finally has support for doing isolated development on a
+ branch off the current (or previous!) revisions. This is also
+ extremely nice for generating patches for previously released
+ software while development is progressing on the next release.
+ Here's an example of creating a branch to fix a patch with the 2.0
+ version of the "foo" module, even though we are already well into
+ the 3.0 release. Do:
+
+ % cvs rtag -b -rFOO_2_0 FOO_2_0_Patch foo
+ % cvs checkout -rFOO_2_0_Patch foo
+ % cd foo
+ [[ hack away ]]
+ % cvs commit
+
+ A physical branch will be created in the RCS file only when you
+ actually commit the change. As such, forking development at some
+ random point in time is extremely light-weight -- requiring just a
+ symbolic tag in each file until a commit is done. To fork
+ development at the currently checked out sources, do:
+
+ % cvs tag -b Personal_Hack
+ % cvs update -rPersonal_Hack
+ [[ hack away ]]
+ % cvs commit
+
+ Now, if you decide you want the changes made in the Personal_Hack
+ branch to be merged in with other changes made in the main-line
+ development, you could do:
+
+ % cvs commit # to make Personal_Hack complete
+ % cvs update -A # to update sources to main-line
+ % cvs update -jPersonal_Hack # to merge Personal_Hack
+
+ to update your checked-out sources, or:
+
+ % cvs checkout -jPersonal_Hack module
+
+ to checkout a fresh copy.
+
+ To support this notion of forked development, CVS reserves
+ all even-numbered branches for its own use. In addition, CVS
+ reserves the ".0" and ".1" branches. So, if you intend to do your
+ own branches by hand with RCS, you should use odd-numbered branches
+ starting with ".3", as in "1.1.3", "1.1.5", 1.2.9", ....
+
+ * The "cvs commit" command now supports a fully functional -r
+ option, allowing you to commit your changes to a specific numeric
+ revision or symbolic tag with full consistency checks. Numeric
+ tags are useful for bringing your sources all up to some revision
+ level:
+
+ % cvs commit -r2.0
+
+ For symbolic tags, you can only commit to a tag that references a
+ branch in the RCS file. One created by "cvs rtag -b" or from
+ "cvs tag -b" is appropriate (see below).
+
+ * Roland Pesch <pesch@cygnus.com> and K. Richard Pixley
+ <rich@cygnus.com> were kind enough to contribute two new manual
+ pages for CVS: cvs(1) and cvs(5). Most of the new CVS 1.3 features
+ are now documented, with the exception of the new branch support
+ added to commit/rtag/tag/checkout/update.
+
+ * The -j options of checkout/update have been added. The "cvs join"
+ command has been removed.
+
+ With one -j option, CVS will merge the changes made between the
+ resulting revision and the revision that it is based on (e.g., if
+ the tag refers to a branch, CVS will merge all changes made in
+ that branch into your working file).
+
+ With two -j options, CVS will merge in the changes between the two
+ respective revisions. This can be used to "remove" a certain delta
+ from your working file. E.g., If the file foo.c is based on
+ revision 1.6 and I want to remove the changes made between 1.3 and
+ 1.5, I might do:
+
+ % cvs update -j1.5 -j1.3 foo.c # note the order...
+
+ In addition, each -j option can contain on optional date
+ specification which, when used with branches, can limit the chosen
+ revision to one within a specific date. An optional date is
+ specified by adding a colon (:) to the tag, as in:
+
+ -jSymbolic_Tag:Date_Specifier
+
+ An example might be what "cvs import" tells you to do when you have
+ just imported sources that have conflicts with local changes:
+
+ % cvs checkout -jTAG:yesterday -jTAG module
+
+ which tells CVS to merge in the changes made to the branch
+ specified by TAG in the last 24 hours. If this is not what is
+ intended, substitute "yesterday" for whatever format of date that
+ is appropriate, like:
+
+ % cvs checkout -jTAG:'1 week ago' -jTAG module
+
+ * "cvs diff" now supports the special tags "BASE" and "HEAD". So,
+ the command:
+
+ % cvs diff -u -rBASE -rHEAD
+
+ will effectively show the changes made by others (in unidiff
+ format) that will be merged into your working sources with your
+ next "cvs update" command. "-rBASE" resolves to the revision that
+ your working file is based on. "-rHEAD" resolves to the current
+ head of the branch or trunk that you are working on.
+
+ * The -P option of "cvs checkout" now means to Prune empty
+ directories, as with "update". The default is to not remove empty
+ directories. However, if you do "checkout" with any -r options, -P
+ will be implied. I.e., checking out with a tag will cause empty
+ directories to be pruned automatically.
+
+ * The new file INSTALL describes how to install CVS, including
+ detailed descriptions of interfaces to "configure".
+
+ * The example loginfo file in examples/loginfo has been updated to
+ use the perl script included in contrib/log.pl. The nice thing
+ about this log program is that it records the revision numbers of
+ your change in the log message.
+
+ Example files for commitinfo and rcsinfo are now included in the
+ examples directory.
+
+ * All "#if defined(__STDC__) && __STDC__ == 1" lines have been
+ changed to be "#if __STDC__" to fix some problems with the former.
+
+ * The lib/regex.[ch] files have been updated to the 1.3 release of
+ the GNU regex package.
+
+ * The ndbm emulation routines included with CVS 1.3 Beta-2 in the
+ src/ndbm.[ch] files has been moved into the src/myndbm.[ch] files
+ to avoid any conflict with the system <ndbm.h> header file. If
+ you had a previous CVS 1.3 Beta release, you will want to "cvs
+ remove ndbm.[ch]" form your copy of CVS as well.
+
+ * "cvs add" and "cvs remove" are a bit more verbose, telling you
+ what to do to add/remove your file permanently.
+
+ * We no longer mess with /dev/tty in "commit" and "add".
+
+ * More things are quiet with the -Q option set.
+
+ * New src/config.h option: If CVS_BADROOT is set, CVS will not
+ allow people really logged in as "root" to commit changes.
+
+ * "cvs diff" exits with a status of 0 if there were no diffs, 1 if
+ there were diffs, and 2 if there were errors.
+
+ * "cvs -n diff" is now supported so that you can still run diffs
+ even while in the middle of committing files.
+
+ * Handling of the CVS/Entries file is now much more robust.
+
+ * The default file ignore list now includes "*.so".
+
+ * "cvs import" did not expand '@' in the log message correctly. It
+ does now. Also, import now uses the ignore file facility
+ correctly.
+
+ Import will now tell you whether there were conflicts that need to
+ be resolved, and how to resolve them.
+
+ * "cvs log" has been changed so that you can "log" things that are
+ not a part of the current release (in the Attic).
+
+ * If you don't change the editor message on commit, CVS now prompts
+ you with the choice:
+
+ !)reuse this message unchanged for remaining dirs
+
+ which allows you to tell CVS that you have no intention of changing
+ the log message for the remainder of the commit.
+
+ * It is no longer necessary to have CVSROOT set if you are using
+ the -H option to get Usage information on the commands.
+
+ * Command argument changes:
+ checkout: -P handling changed as described above.
+ New -j option (up to 2 can be specified)
+ for doing rcsmerge kind of things on
+ checkout.
+ commit: -r option now supports committing to a
+ numeric or symbolic tags, with some
+ restrictions. Full consistency checks will
+ be done.
+ Added "-f logfile" option, which tells
+ commit to glean the log message from the
+ specified file, rather than invoking the
+ editor.
+ rtag: Added -b option to create a branch tag,
+ useful for creating a patch for a previous
+ release, or for forking development.
+ tag: Added -b option to create a branch tag,
+ useful for creating a patch for a previous
+ release, or for forking development.
+ update: New -j option (up to 2 can be specified)
+ for doing rcsmerge kind of things on
+ update.
+
+Thu Jan 9 10:51:35 MST 1992 Jeff Polk (polk at BSDI.COM)
+
+ * Changes between CVS 1.3 Beta-1 and CVS 1.3 Beta-2
+
+ * Thanks to K. Richard Pixley at Cygnus we now have function
+ prototypes in all the files
+
+ * Some small changes to configure for portability. There have
+ been other portability problems submitted that have not been fixed
+ (Brian will be working on those). Additionally all __STDC__
+ tests have been modified to check __STDC__ against the constant 1
+ (this is what the Second edition of K&R says must be true).
+
+ * Lots of additional error checking for forked processes (run_exec)
+ (thanks again to K. Richard Pixley)
+
+ * Lots of miscellaneous bug fixes - including but certainly not
+ limited to:
+ various commit core dumps
+ various update core dumps
+ bogus results from status with numeric sticky tags
+ commitprog used freed memory
+ Entries file corruption caused by No_Difference
+ commit to revision broken (now works if branch exists)
+ ignore file processing broken for * and !
+ ignore processing didn't handle memory reasonably
+ miscellaneous bugs in the recursion processor
+ file descriptor leak in ParseInfo
+ CVSROOT.adm->CVSROOT rename bug
+ lots of lint fixes
+
+ * Reformatted all the code in src (with GNU indent) and then
+ went back and fixed prototypes, etc since indent gets confused. The
+ rationale is that it is better to do it sooner than later and now
+ everything is consistent and will hopefully stay that way.
+ The basic options to indent were: "-bad -bbb -bap -cdb -d0 -bl -bli0
+ -nce -pcs -cs -cli4 -di1 -nbc -psl -lp -i4 -ip4 -c41" and then
+ miscellaneous formatting fixes were applied. Note also that the
+ "-nfc1" or "-nfca" may be appropriate in files where comments have
+ been carefully formatted (e.g, modules.c).
+
+Sat Dec 14 20:35:22 1991 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.2 and CVS 1.3 Beta are described here.
+
+ * Lots of portability work. CVS now uses the GNU "configure"
+ script to dynamically determine the features provided by your
+ system. It probably is not foolproof, but it is better than
+ nothing. Please let me know of any portability problems. Some
+ file names were changed to fit within 14-characters.
+
+ * CVS has a new RCS parser that is much more flexible and
+ extensible. It should read all known RCS ",v" format files.
+
+ * Most of the commands now are fully recursive, rather than just
+ operating on the current directory alone. This includes "commit",
+ which makes it real easy to do an "atomic" commit of all the
+ changes made to a CVS hierarchy of sources. Most of the commands
+ also correctly handle file names that are in directories other than
+ ".", including absolute path names. Commands now accept the "-R"
+ option to force recursion on (though it is always the default now)
+ and the "-l" option to force recursion off, doing just "." and not
+ any sub-directories.
+
+ * CVS supports many of the features provided with the RCS 5.x
+ distribution - including the new "-k" keyword expansion options. I
+ recommend using RCS 5.x (5.6 is the current official RCS version)
+ and GNU diff 1.15 (or later) distributions with CVS.
+
+ * Checking out files with symbolic tags/dates is now "sticky", in
+ that CVS remembers the tag/date used for each file (and directory)
+ and will use that tag/date automatically on the next "update" call.
+ This stickyness also holds for files checked out with the the new
+ RCS 5.x "-k" options.
+
+ * The "cvs diff" command now recognizes all of the rcsdiff 5.x
+ options. Unidiff format is available by installing the GNU
+ diff 1.15 distribution.
+
+ * The old "CVS.adm" directories created on checkout are now called
+ "CVS" directories, to look more like "RCS" and "SCCS". Old CVS.adm
+ directories are automagically converted to CVS directories. The
+ old "CVSROOT.adm" directory within the source repository is
+ automagically changed into a "CVSROOT" directory as well.
+
+ * Symbolic links in the source repository are fully supported ONLY
+ if you use RCS 5.6 or later and (of course) your system supports
+ symlinks.
+
+ * A history database has been contributed which maintains the
+ history of certain CVS operations, as well as providing a wide array
+ of querying options.
+
+ * The "cvs" program has a "-n" option which can be used with the
+ "update" command to show what would be updated without actually
+ doing the update, like: "cvs -n update". All usage statements
+ have been cleaned up and made more verbose.
+
+ * The module database parsing has been rewritten. The new format
+ is compatible with the old format, but with much more
+ functionality. It allows modules to be created that grab pieces or
+ whole directories from various different parts of your source
+ repository. Module-relative specifications are also correctly
+ recognized now, like "cvs checkout module/file.c".
+
+ * A configurable template can be specified such that on a "commit",
+ certain directories can supply a template that the user must fill
+ before completing the commit operation.
+
+ * A configurable pre-commit checking program can be specified which
+ will run to verify that a "commit" can happen. This feature can be
+ used to restrict certain users from changing certain pieces of the
+ source repository, or denying commits to the entire source
+ repository.
+
+ * The new "cvs export" command is much like "checkout", but
+ establishes defaults suitable for exporting code to others (expands
+ out keywords, forces the use of a symbolic tag, and does not create
+ "CVS" directories within the checked out sources.
+
+ * The new "cvs import" command replaces the deprecated "checkin"
+ shell script and is used to import sources into CVS control. It is
+ also much faster for the first-time import. Some algorithmic
+ improvements have also been made to reduce the number of
+ conflicting files on next-time imports.
+
+ * The new "cvs admin" command is basically an interface to the
+ "rcs" program. (Not yet implemented very well).
+
+ * Signal handling (on systems with BSD or POSIX signals) is much
+ improved. Interrupting CVS now works with a single interrupt!
+
+ * CVS now invokes RCS commands by direct fork/exec rather than
+ calling system(3). This improves performance by removing a call to
+ the shell to parse the arguments.
+
+ * Support for the .cvsignore file has been contributed. CVS will
+ now show "unknown" files as "? filename" as the result of an "update"
+ command. The .cvsignore file can be used to add files to the
+ current list of ignored files so that they won't show up as unknown.
+
+ * Command argument changes:
+ cvs: Added -l to turn off history logging.
+ Added -n to show what would be done without actually
+ doing anything.
+ Added -q/-Q for quiet and really quiet settings.
+ Added -t to show debugging trace.
+ add: Added -k to allow RCS 5.x -k options to be specified.
+ admin: New command; an interface to rcs(1).
+ checkout: Added -A to reset sticky tags/date/options.
+ Added -N to not shorten module paths.
+ Added -R option to force recursion.
+ Changed -p (prune empty directories) to -P option.
+ Changed -f option; forcing tags match is now default.
+ Added -p option to checkout module to standard output.
+ Added -s option to cat the modules db with status.
+ Added -d option to checkout in the specified directory.
+ Added -k option to use RCS 5.x -k support.
+ commit: Removed -a option; use -l instead.
+ Removed -f option.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ If no files specified, commit is recursive.
+ diff: Now recognizes all RCS 5.x rcsdiff options.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ history: New command; displays info about CVS usage.
+ import: Replaces "checkin" shell script; imports sources
+ under CVS control. Ignores files on the ignore
+ list (see -I option or .cvsignore description above).
+ export: New command; like "checkout", but w/special options
+ turned on by default to facilitate exporting sources.
+ join: Added -B option to join from base of the branch;
+ join now defaults to only joining with the top two
+ revisions on the branch.
+ Added -k option for RCS 5.x -k support.
+ log: Supports all RCS 5.x options.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ patch: Changed -f option; forcing tags match is now default.
+ Added -c option to force context-style diffs.
+ Added -u option to support unidiff-style diffs.
+ Added -V option to support RCS specific-version
+ keyword expansion formats.
+ Added -R option to force recursion.
+ remove: No option changes. It's a bit more verbose.
+ rtag: Equivalent to the old "cvs tag" command.
+ No option changes. It's a lot faster for re-tag.
+ status: New output formats with more information.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ Added -v option to show symbolic tags for files.
+ tag: Functionality changed to tag checked out files
+ rather than modules; use "rtag" command to get the
+ old "cvs tag" behaviour.
+ update: Added -A to reset sticky tags/date/options.
+ Changed -p (prune empty directories) to -P option.
+ Changed -f option; forcing tags match is now default.
+ Added -p option to checkout module to standard output.
+ Added -I option to add files to the ignore list.
+ Added -R option to force recursion.
+
+ Major Contributors:
+
+ * Jeff Polk <polk@bsdi.com> rewrote most of the grody code of CVS
+ 1.2. He made just about everything dynamic (by using malloc),
+ added a generic hashed list manager, re-wrote the modules database
+ parsing in a compatible - but extended way, generalized directory
+ hierarchy recursion for virtually all the commands (including
+ commit!), generalized the loginfo file to be used for pre-commit
+ checks and commit templates, wrote a new and flexible RCS parser,
+ fixed an uncountable number of bugs, and helped in the design of
+ future CVS features. If there's anything gross left in CVS, it's
+ probably my fault!
+
+ * David G. Grubbs <dgg@ksr.com> contributed the CVS "history" and
+ "release" commands. As well as the ever-so-useful "-n" option of
+ CVS which tells CVS to show what it would do, without actually
+ doing it. He also contributed support for the .cvsignore file.
+
+ * Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
+ contributed the code in lib/sighandle.c. I added support for
+ POSIX, BSD, and non-POSIX/non-BSD systems.
+
+ * Free Software Foundation contributed the "configure" script and
+ other compatibility support in the "lib" directory, which will help
+ make CVS much more portable.
+
+ * Many others have contributed bug reports and enhancement requests.
+ Some have even submitted actual code which I have not had time yet
+ to integrate into CVS. Maybe for the next release.
+
+ * Thanks to you all!
+
+Wed Feb 6 10:10:58 1991 Brian Berliner (berliner at sun.com)
+
+ * Changes from CVS 1.0 Patchlevel 1 to CVS 1.0 Patchlevel 2; also
+ known as "Changes from CVS 1.1 to CVS 1.2".
+
+ * Major new support with this release is the ability to use the
+ recently-posted RCS 5.5 distribution with CVS 1.2. See below for
+ other assorted bug-fixes that have been thrown in.
+
+ * ChangeLog (new): Added Emacs-style change-log file to CVS 1.2
+ release. Chronological description of changes between release.
+
+ * README: Small fixes to installation instructions. My email
+ address is now "berliner@sun.com".
+
+ * src/Makefile: Removed "rcstime.h". Removed "depend" rule.
+
+ * src/partime.c: Updated to RCS 5.5 version with hooks for CVS.
+ * src/maketime.c: Updated to RCS 5.5 version with hooks for CVS.
+ * src/rcstime.h: Removed from the CVS 1.2 distribution.
+ Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
+
+ * src/checkin.csh: Support for RCS 5.5 parsing.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/collect_sets.c (Collect_Sets): Be quieter if "-f" option is
+ specified. When checking out files on-top-of other files that CVS
+ doesn't know about, run a diff in the hopes that they are really
+ the same file before aborting.
+
+ * src/commit.c (branch_number): Fix for RCS 5.5 parsing.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/commit.c (do_editor): Bug fix - fprintf missing argument
+ which sometimes caused core dumps.
+
+ * src/modules.c (process_module): Properly NULL-terminate
+ update_dir[] in all cases.
+
+ * src/no_difference.c (No_Difference): The wrong RCS revision was
+ being registered in certain (strange) cases.
+
+ * src/patch.c (get_rcsdate): New algorithm. No need to call
+ maketime() any longer.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/patchlevel.h: Increased patch level to "2".
+
+ * src/subr.c (isdir, islink): Changed to compare stat mode bits
+ correctly.
+
+ * src/tag.c (tag_file): Added support for following symbolic links
+ that are in the master source repository when tagging. Made tag
+ somewhat quieter in certain cases.
+
+ * src/update.c (update_process_lists): Unlink the user's file if it
+ was put on the Wlist, meaning that the user's file is not modified
+ and its RCS file has been removed by someone else.
+
+ * src/update.c (update): Support for "cvs update dir" to correctly
+ just update the argument directory "dir".
+
+ * src/cvs.h: Fixes for RCS 5.5 parsing.
+ * src/version_number.c (Version_Number): Fixes for parsing RCS 5.5
+ and older RCS-format files.
+ Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
+
+ * src/version_number.c (Version_Number): Bug fixes for "-f" option.
+ Bug fixes for parsing with certain branch numbers. RCS
+ revision/symbol parsing is much more solid now.
+
+Wed Feb 14 10:01:33 1990 Brian Berliner (berliner at sun.com)
+
+ * Changes from CVS 1.0 Patchlevel 0 to CVS 1.0 Patchlevel 1; also
+ known as "Changes from CVS 1.0 to CVS 1.1".
+
+ * src/patch.c (get_rcsdate): Portability fix. Replaced call to
+ timelocal() with call to maketime().
+
+Mon Nov 19 23:15:11 1990 Brian Berliner (berliner at prisma.com)
+
+ * Sent CVS 1.0 release to comp.sources.unix moderator and FSF.
+
+ * Special thanks to Dick Grune <dick@cs.vu.nl> for his work on the
+ 1986 version of CVS and making it available to the world. Dick's
+ version is available on uunet.uu.net in the
+ comp.sources.unix/volume6/cvs directory.
+
+@(#)ChangeLog 1.17 92/04/10
diff --git a/DEVEL-CVS b/DEVEL-CVS
new file mode 100644
index 0000000..cf4e3a7
--- /dev/null
+++ b/DEVEL-CVS
@@ -0,0 +1,31 @@
+ CVS Development Policies
+
+This file, DEVEL-CVS, contains the policies by which the CVS
+development group operates. Also see the HACKING file.
+
+----------------------------------------------------------------------
+Policies regarding the CVS source repository:
+
+By checking items into the repository, developers agree to permit
+distribution of such items under the terms of the GNU Public License.
+
+----------------------------------------------------------------------
+Procedure for dealing with people who want to be developers:
+
+People who want checkin access are first requested to send
+patches and have them reviewed by a developer. If they submit some
+good ones (preferably over a period of time, to demonstrate sustained
+interest), then one of the developers can ask the other CVS
+developers, usually via the bug-cvs@nongnu.org mailing list, whether it
+is OK to make this person a developer (after first sending the
+prospective developer a copy of this file and then having the
+prospective developer say they want to be a developer). If there are
+no objections, the person will be made a developer.
+
+----------------------------------------------------------------------
+Policy regarding checkout-only access:
+
+Checkout-only access to the CVS repository is available to all, on an
+anonymous basis (no need for registration or other complications).
+The exact technical mechanisms by which it is available are not
+covered by this policy.
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..e632049
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,8555 @@
+-------------------------------------------------------------------------------
+
+ CVS is Copyright (C) 1989-2005 The Free Software Foundation, Inc.
+
+ CVS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ More details are available in the COPYING file but, in simplified
+ terms, this means that any distributed modifications you make to
+ this software must also be released under the GNU General Public
+ License.
+
+ CVS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+-------------------------------------------------------------------------------
+
+This file contains a CVS FAQ. Until 1995 it was maintained by David
+Grubbs. It was out of date and not being maintained, but it had a
+certain following and in 1997 Pascal Molli decided to start
+maintaining it with the FAQ-O-Matic package which allows any
+contributor with a web browser to help maintain it. The following
+text is (mostly automatically) extracted from the FAQ-O-Matic.
+In 2004, Dr. Pascal Molli's FAQ-O-Matic was decommissioned.
+
+The answers which are dated "6/13/1997" below are really from the 1995
+FAQ, for the most part. Many of them are out of date. The current FAQ may
+be found at <http://ximbiot.com/cvs/wiki/index.php?title=CVS_FAQ>. If you have
+some time, you are encouraged to export that FAQ as text and import it here.
+If you don't have such time, take the answers in this file with at least a few
+grains of salt.
+
+Since August, 2005, many of the existing CVS resources have been centralized on
+<http://cvs.nongnu.org> & <http://ximbiot.com>.
+
+ Category: /, all questions
+
+ Category: /
+
+ " [INLINE] "
+
+ 1. About FAQ-O-Matic
+
+This is FAQ-O-Matic, a quick-and-dirty Perl hack (aren't they all?) by
+Jon Howell.
+
+It seems like most FAQ maintainers make a valiant initial effort, then get
+a life and don't have time to keep their FAQs up to date. Also, I often
+find out a solution to a problem, and feel like I could write a single
+FAQ answer on it in a few minutes, but where to post it?
+
+Thus the FAQ-O-Matic was born. FAQ-O-Matic is a couple sleazy Perl scripts
+that allow people to submit FAQ answers to this database, so it can stay
+current, with just a tiny bit of work on any one person's part.
+
+Yes, a bad guy could come along and wipe out all the FAQ entries. Please don't.
+But to give the good guys some measure of comfort, each submission is stored
+in an RCS file, so if someone does tamper, we can recover the database.
+
+Guidelines for submissions:
+
+1. Please _try to be fairly unbiased in matters of opinion._ Mailing lists are
+the place to start flame wars (just kidding :v), but definitely not here.
+
+2. Please _use HTML only conservatively_ in your entries. Links are appropriate
+,
+but put the URL in the plaintext also so it's useable on printed versions of
+the FAQ. Inline images pointing off this site are inappropriate, as is much
+fancy formatting. This is meant to be bandwidth-light and dumb-browser-friendly
+.
+
+3. If you feel there's a place for a _new category, or a reorganization of
+existing questions_, send e-mail to bug-cvs@nongnu.org.
+
+4. Please _leave an email address_ at the bottom of your submission so that oth
+ers
+can drop you a note.
+
+5. _If you only have a question_, not an answer, you should probably post
+it to a mailing list, not here. If there are frequently asked questions to whic
+h
+the answer is not forthcoming on mailing lists (or perhaps there's no
+useful answer yet other than "no one knows"), then it's appropriate to
+post here, in hopes that someone will see it and know the answer.
+
+6. Please refrain from crude or inconsiderate language. Please don't use
+this as a forum for advertising. However, mention of worthy commercial
+products is certainly appropriate (even if you sell said product). Just
+don't overdo it. :v)
+
+ Last modified: _6/13/1997_
+
+ 2. Adding a new category ?
+
+try to get bug-cvs@nongnu.org to help you.
+
+
+ Last modified: _12/09/2004_
+
+ Category: /Advanced_Topics_/
+
+ " Advanced Topics "
+
+ Category: /Advanced_Topics_/Branching_and_Mergin/
+
+ " + Branching and Merging"
+
+ 1. What is a branch?
+
+ Unfortunately, the word "branch" is an overloaded technical
+ term. It is used in too many different ways in three
+ categories. It might help to understand some of the issues by
+ going through the categories:
+
+ How Humans use the word "branch":
+
+ Most development starts with everyone working on the same
+ software, making changes and heading toward a single goal. This
+ is called something like "Main Line Development". Note that
+ though many people do main line development on CVS's "Main
+ Branch", that is a choice, not a requirement.
+
+ After a release or when one or more developers want to go off
+ and work on some project for a while, the Software Engineers
+ assigned to deal with large software issues generate a "Branch
+ in Development" to support the release or project. (Keep in
+ mind that a programmer is no more a Software Engineer than a
+ carpenter is a Civil Engineer.)
+
+ Essentially, the word "branch" implies a way to allow
+ simultaneous development on the same files by multiple people.
+
+ The above terms are human-oriented. They refer to actions that
+ people would like to take. They do *not* imply any particular
+ implementation or set of procedures. Branches in development
+ can be supported in many different ways.
+
+ How CVS uses the word "branch":
+
+ CVS uses the word "branch" in a number of ways. The two most
+ important are:
+
+ - The vendor branch holds releases from (normally) an outside
+ software vendor. It is implemented using a specific RCS branch
+ (i.e. 1.1.1).
+
+ - The "Main Branch", which normally holds your "Main Line
+ Development", but is defined as the collection of revisions you
+ get when you "checkout" something fresh, or when you use the
+ '-A' option to "update".
+
+ Important Note: The CVS "Main Branch" is *not* the same as the
+ RCS concept with the same name. If you are using Vendor
+ Branches, files you have never changed are on three branches at
+ the same time:
+
+ - The RCS 1.1.1 branch.
+ - The CVS Vendor branch.
+ - The CVS "Main Branch".
+
+ The concepts overlap, but they are not equivalent.
+
+ In referring to CVS, "branch" can be used in four other ways:
+
+ - A CVS working directory satisfies the definition of "branch"
+ for a single developer -- you are on a private "virtual branch"
+ that does not appear in any of the RCS files or the CVS control
+ files.
+
+ - The CVS "default branch" is the Repository source for the
+ collection of files in your working directory. It is *not* the
+ same as the RCS "default branch". Normally the CVS default
+ branch is the same as the CVS Main branch. If you use the "-r
+ <branch_tag>" option to the "checkout" command, you will record
+ a "sticky" tag that changes your default branch to the one you
+ checked out.
+
+ - A "magic" branch can be a branch that hasn't happened yet. It
+ is implemented by a special tag you can check out that is not
+ attached to a real RCS branch. When you commit a file to a
+ magic branch, the branch becomes real (i.e. a physical RCS
+ branch).
+
+ - And, of course, CVS uses "branch" to indicate a
+ human-oriented "branch in development".
+
+ How RCS uses the word "branch":
+
+ - The RCS "Main Branch" (Synonym: "The Trunk") contains a
+ series of two-part revision numbers separated by a single '.'
+ (e.g. 1.2). It is treated specially and is the initial default
+ branch. (The default default?)
+
+ - The RCS "Default" branch starts out attached to the RCS "Main
+ Branch". For RCS purposes, it can be changed to point to any
+ branch. Within CVS, you *must*not* alter the RCS default
+ branch. It is used to support the CVS idea of a "Main Branch"
+ and it must either point to the RCS Main Branch, or the Vendor
+ Branch (1.1.1) if you haven't made any changes to the file
+ since you executed "import".
+
+ Last modified: _6/13/1997_
+
+ 2. Why (or when) would I want to create a branch?
+
+ Remember that you can think of your working directory as a "branch for
+ one". You can consider yourself to be on a branch all the time because
+ you can work without interfering with others until your project (big
+ or small) is done.
+
+ The four major situations when you should create a branch:
+
+ When you expect to take a long time or make a large set of changes
+ that the merging process will be difficult. Both "long" and "large"
+ are defined in your own environment.
+
+ When you want to be able to "commit" and "tag" your work repeatedly
+ without affecting others.
+
+ If you ever think you need Source Control for your own work, but don't
+ want your changes to affect others, create a private branch. (Put your
+ username in the branch tag, to make it obvious that it is private.)
+
+ When you need to share code among a group of developers, but not the
+ whole development organization working on the files.
+
+ Rather than trying to share a working directory, you can move onto a
+ branch and share your work with others by "committing" your work onto
+ the branch. Developers not working on the branch won't see your work
+ unless they switch to your branch or explicitly merge your branch into
+ theirs.
+
+ When you need to make minor changes to a released system.
+
+ Normally a "release" is labeled by a branch tag, allowing later work
+ on the released files. If the release is labeled by a non-branch tag,
+ it is easy to add a branch tag to a previously tagged module with the
+ "rtag" command. If the release is not tagged, you made a mistake.
+ Recovery requires identifying all revisions involved in the release
+ and adding a tag to them.
+
+ Last modified: _6/13/1997_
+
+ 3. How do I create and checkout a branch?
+
+ Suggested technique:
+
+ Attach a non-branch tag to all the revisions you want to branch
+ from. (i.e. the branch point revisions)
+
+ When you decide you really need a branch, attach a branch tag to the
+ same revisions marked by the non-branch tag.
+
+ "Checkout" or "update" your working directory onto the branch.
+
+ Suggested procedure when using modules:
+
+ cvs rtag <branch_point_tag> module
+
+ cvs rtag -b -r <branch_point_tag> <branch_tag> <module>
+
+ cvs checkout -r <branch_tag> module
+
+ Suggested procedure when using your working directory, which
+ contains the revisions of your working files you want to branch from:
+
+ cvs tag <branch_point_tag>
+
+ cvs rtag -b -r <branch_point_tag> <branch_tag> <module>
+
+ cvs update -r <branch_tag>
+
+ In each procedure above, Step #1 applies a non-branch tag to all the
+ branch point revisions in the module/directory. Though this is not
+ strictly necessary, if you don't add a non-branch tag to the revisions
+ you branch from, you won't be able to refer to the branch point in the
+ future.
+
+ Between steps 1 & 2 you may commit changes. The result would be same
+ because "rtag -r <oldtag> <newtag>" applies <newtag> to the same
+ revision that <oldtag> is attached to. You can use this technique to
+ avoid attaching *any* branch tags until you need them.
+
+ Step B.2 has two corollaries:
+
+ If you plan to create the branch tag before committing anything in
+ your working directory, you can use "cvs tag -b <branch_tag>" instead
+ of the "rtag" command.
+
+ The <module> can be a relative path to a directory from which your
+ working directory was checked out.
+
+ If you have trouble figuring out what <module> to use (or pathname to
+ use in its place), you can aim it at whatever parent directories you
+ believe will cover all your work.
+
+ If you are sure the <branch_tag> is not being used anywhere else, you
+ can even aim it at the whole Repository ($CVSROOT), if you have to. It
+ might take some extra time, but assuming that your <tag> is a unique
+ string and you don't use the '-f' option to "rtag -r", "rtag" will
+ only add a <tag> to files in which it actually *finds* the earlier
+ <tag>.
+
+ In each procedure above, Step #3 may occur any time after step 2.
+ Unless you explicitly remove them with "tag -d", a <tag> is permanent.
+
+ The <branch_tag> is an unusual creature. It labels a branch in a way
+ that allows you to "checkout" the branch, to "commit" files to the end
+ of the branch and to refer to the end of the branch. It does not label
+ the base of the branch (the branch point).
+
+ There are two obvious ways to choose the <branch_point_tag> and
+ <branch_tag> names. But keep in mind that the <branch_tag> is typed by
+ any developer who wants to work on the branch -- you should make it
+ mean something to them.
+
+ Style #1 presumes that the simple version string refers to a set of
+ designed, documented or promised features, not to a specific set of
+ files. In this case, you tag the branch with the generic Version
+ string and assume that whenever you refer to "Version", you want the
+ "latest" set of files associated with that Version, including all
+ patches. (You can substitute whatever you like for "bp_", as long as
+ your <branch_point_tag> is some modification of the <branch_tag>.)
+
+ <branch_point_tag> Matching <branch_tag>
+
+ bp_V1_3 V1_3
+ bp_Release2-3-5 Release2-3-5
+ bp_Production4_5 Release4_5
+
+ Style #2 presumes that the simple version string refers to the
+ specific set of files used to construct the first release of
+ "version". In this case, you tag the branch-point revisions with the
+ generic Version string and assume that whenever you refer to this
+ Version, you want the original set of released revisions. To get the
+ latest patched revisions of the release, you refer to the branch tag
+ "latest_<branch_point_tag>". (You can substitute what ever you like
+ for "latest_", as long as your <branch_tag> is some modification of
+ the <branch_point_tag>.)
+
+ <branch_point_tag> Matching <branch_tag>
+
+ V1_3 latest_V1_3
+ Release2-3-5 latest_Release2-3-5
+ Release4_5 latest_Production4_5
+
+ In both styles you can find out what you had to change since the
+ original release of this Version by typing:
+
+ cvs diff -r <branch_point_tag> -r <branch_tag>
+
+ For Style 1, this is:
+
+ cvs diff -r bp_<branch_tag> -r <branch_tag>
+
+ For Style 2, this is:
+
+ cvs diff -r <branch_point_tag> -r latest_<branch_point_tag>
+
+ Notes on "being on a branch":
+
+ - "update -r <tag>" tells CVS to attach a "sticky tag" to working
+ directory (in ./CVS/Tag) and the checked-out files (on each line of
+ ./CVS/Entries).
+
+ - A "sticky" <tag> (including a <branch_tag>) causes most CVS commands
+ to act as if "-r <tag>" were on the command line.
+
+ - A "sticky" <branch_tag> indicates that the working directory (and
+ working files) are "on the branch".
+
+ Last modified: _6/13/1997_
+
+ 4. Once created, how do I manage a branch?
+
+ The most important thing you should know about managing a branch is
+ that the creation of a branch is not a lightweight act. When you
+ create a branch, you must also create a set of procedures to keep
+ track of it.
+
+ Specifically, you must:
+
+ - Remember that the branch exists. (This is non-trivial if you create
+ a lot of them.)
+
+ - Plan when to merge it back into the main line of development.
+
+ - Schedule the order that multiple branch merges are to be done.
+
+ - If you ever intend to merge branches into each other, instead of
+ limiting merges of branch work back into the "main line", you must
+ keep careful track of which parts of which branches have merged into
+ which other branches.
+
+ The simplest way to deal with branches is to limit their number,
+ "collapse" them back into the main line as quickly as is reasonable
+ and forget them. If a group wants to continue working, tell them to
+ create another branch off the fully merged main line.
+
+ Remember that CVS is just a tool. Over time, it will probably handle
+ branching better, requiring less careful attendance. But no matter how
+ good it becomes, the whole idea of "branching" is a complicated
+ management problem. Don't take it lightly.
+
+ Last modified: _6/13/1997_
+
+ 5. Are there any extra issues in managing multiple branches?
+
+ If you plan to split from the "main line" and merge back after a time,
+ the only problem will be scheduling the order of branch merges. As
+ each branch is merged, the main line must be rebuilt and tested.
+ Merging multiple branches (i.e. "lines of development") before
+ building and testing creates more problems than you are ready for.
+
+ If you plan to collapse some branches into others, then move the
+ combined branches back into the main line, you have to be careful with
+ the revisions and tags you hand to your "update -j" command, but it
+ shouldn't be much trouble.
+
+ If you plan to allow every branch to incrementally take the work done
+ on other branches, you are creating an almost insurmountable
+ bookkeeping problem. Every developer will say "Hey, I can handle
+ taking just this little bit," but for the system as a whole it is
+ disaster. Try it once and see. If you are forced into this situation,
+ you will need to keep track of the beginning and end points of every
+ merge ever done. Good Luck.
+
+ Last modified: _6/13/1997_
+
+ 6. How do I merge a whole branch back into the trunk?
+
+ If you don't have a working directory, you can checkout and merge in
+ one command:
+
+ cvs checkout -j <branch_tag> <module>
+ cd <module>
+
+ If you already have a working directory:
+
+ cd <working_directory>
+ cvs update <== Optional, to bring it up to date.
+ cvs update -j <branch_tag>
+
+ CVS will print lines beginning with
+
+ 'U' for files that you hadn't changed, but the branch did.
+
+ 'M' for files that you changed and the branch didn't
+ *and* for files that you both changed that were merged
+ without overlaps. (This overload is unfortunate.)
+
+ 'C' for files that you both changed in a way that conflicts
+ with each other.
+
+ You need to go edit all the 'C' files and clean up the conflicts. Then
+ you must commit them.
+
+ Last modified: _6/13/1997_
+
+ 7. How do I merge changes from the trunk into my branch or between
+ branches?
+
+ The idea is similar to the above, but since CVS doesn't treat the main
+ branch like other branches, you'll have to be more careful. There are
+ 5 different ways to look at the problem.
+
+ The way to merge *all* changes made on the trunk into a working
+ branch is to move to the branch you want via "checkout -r" or "update
+ -r":
+
+ cvs update -r <branch_tag> {optional files}
+
+ Then merge the changes from the trunk into your working branch using
+ the pseudo-tag named "HEAD":
+
+ cvs up -j HEAD {optional files}
+
+ You will get everything from the branch point of the branch named
+ <branch_tag> up to the HEAD of the main branch. This is still kind of
+ strange. If the file is on a branch, HEAD should be the latest thing
+ on the branch, not the HEAD of MAIN. But that's not the way CVS
+ (currently) works.
+
+ If you run "cvs up -j HEAD" again after adding more revisions to the
+ trunk, you may get overlaps for the text you have already merged. It
+ depends on your version of your RCS "merge" command (actually the "co
+ -j" option, which depends on the version of "diff3" you configured RCS
+ to use).
+
+ You can merge the difference between any two <tags> using two "-j"
+ options on "update" or "checkout".
+
+ Identify the two tags on the branch you want to merge from.
+
+ cvs update -j <tag1> -j <tag2> {optional files}
+
+ This step assumes you were careful about tagging milestones. You can
+ use this technique for any two <tags> on the same branch, even the
+ trunk. It is also possible to use tags on different branches, but
+ you'll have to ponder the meaning of the difference between those two
+ tags.
+
+ In place of one of the <tags>, you can use a <branch_tag> to refer to
+ the latest revision on that branch. See 4C.11 and 4C.3 for info on
+ branch points.
+
+ Merges can also be performed by handing RCS revisions to the '-j'
+ options, but since revision numbers aren't the same in all files,
+ merging by number is normally limited to one file. Sets of files with
+ the exact same trees of branches and revision numbers would work too,
+ but that's a rare situation.
+
+ To "take" revisions from other branches instead of merging them, see
+ 4C.19 for an idea.
+
+ A way to gain the effect of merging the main to the branch is to
+ merge the branch into the main using the normal
+
+ cvs update -A {optional files}
+ cvs update -j <branch_tag> {optional files}
+ cvs commit
+ cvs tag -F -b <same_branch_tag> {optional files}
+
+ See part B of 4D.5
+
+ Other oddities.
+
+ This also works, but is probably not officially supported:
+
+ cvs update -j N {optional files}
+
+ where N is a number. This will merge all the changes from the branch
+ point up to the highest revision on the main branch starting with N.
+ For example, if your highest trunk revision is 1.52, you can use this
+ to grab revisions from the trunk:
+
+ cvs update -j 1 {optional files}
+
+ Another example: Say you have a branch point at rev 1.2 for a branch
+ named "BR1" and trunk revisions 1.3, 1.4, 2.1, 2.2, 2.3, 3.1, 3.2.
+ Then:
+
+ cvs update -j 1 {optional files}
+
+ will merge the changes from 1.2 to 1.4
+
+ cvs update -j 2 {optional files}
+
+ will merge the changes from 1.2 to 2.3
+
+ cvs update -j 3 {optional files}
+
+ will merge the changes from 1.2 to 3.2, which in this example, is
+ equivalent to the use of "-j HEAD" in part A above.
+
+ The intuitive (at least to me):
+
+ cvs up -j MAIN (or TRUNK) {optional files}
+
+ doesn't work. If the trunk (i.e. "main branch") had an implicit branch
+ named "MAIN", you could use:
+
+ cvs up -j MAIN:10/26 -j MAIN:now {optional files}
+
+ and refer to date-stamped revisions on the trunk using the
+ <branch_tag>:<date> support that works on other branches.
+
+ You might also think you could place an explicit tag on branch 1 (or
+ higher) (e.g. MAINHACK:1) and use it in place of the implicit "MAIN",
+ but I haven't found the right combination.
+
+ [[If you find working techniques, I'll add them here.]]
+
+ Last modified: _6/13/1997_
+
+ 8. How do I merge onto the Main Branch a file that exists only on a branch
+ other than the Main Branch? (i.e. it is in the Attic)
+
+ For how such a file can exist, see 3A.2 and 3A.3.
+
+ For how to avoid creating such a file, see 3A.5.
+
+ Though you might think that the "update -j" command could perform the
+ "merge" of a file from the side branch to the Main Branch, it isn't
+ (yet) smart enough. Unfortunately, there is no single CVS command to
+ do this -- it takes three steps:
+
+ To move something onto the Main Branch from the Attic, you have to
+ physically move the file from the Attic to the main Repository
+ directory associated with your working directory.
+
+ It is exactly like resurrecting a removed file. See 3L.4
+
+ I use something like this: (csh-like syntax)
+
+ set repos = `cat ./CVS/Repository` mv $repos/Attic/filename,v
+ $repos/filename,v
+
+ (If you use relative paths in your Repository files, that first line
+ becomes: set repos = $CVSROOT/`cat ./CVS/Repository`)
+
+ Now that the file is physically in the right place within the
+ Repository, "update -A" will make it appear in your working directory
+ on the Main Branch. Do that now.
+
+ You now have a choice. The act of physically moving the file has
+ fused together the <branch_tag> branch and the Main Branch for this
+ file. You can continue that way, making changes along the RCS Main
+ Branch which CVS will (for this type of file only) treat as both the
+ Main Branch and the <branch_tag> branch.
+
+ The other choice, which I would suggest, is to re-tag the file with
+ <branch_tag>, restoring a normal-looking magic branch tag to the file:
+
+ cvs tag -F -b <branch_tag> <file>
+
+ After you have done the above, you can run "update -A" or "update -r
+ <branch_tag>" to resume whatever you were doing before you started
+ this procedure.
+
+ Caveat: The final result is a file whose revision tree doesn't look
+ like it was ever on any branch but the Main Branch until the above
+ "tag -F -b" command was executed. CVS and RCS have no way of saving
+ the history of the actions you have just performed.
+
+ Last modified: _6/13/1997_
+
+ 9. How do I know what branch I'm (working) on?
+
+ Type:
+ cvs status
+
+ and look at the "Sticky Tag" field for each file. If:
+
+ The *same* tag is on *every* file in your working tree, *and*
+
+ That tag matches the contents of the ./CVS/Tag file, *and*
+
+ That tag is a branch tag,
+
+ then you know what branch you are working on. You can get sticky Tag
+ information directly from the ./CVS/Entries file instead of "cvs
+ status".
+
+ If all the sticky Tags don't agree, then your directory is temporarily
+ inconsistent. This is a feature allowing you to make changes (or
+ perform merges) to individual files on multiple branches without
+ checking out the whole directory.
+
+ The sticky Tag on each file in the ./CVS/Entries file (as displayed by
+ the "status" command) indicates what branch the working file is on.
+ New files are added to the Tag stored in ./CVS/Tag.
+
+ To force your entire working directory onto the same branch, type:
+
+ cvs update -r <branch_tag>
+
+ Last modified: _6/13/1997_
+
+ 10. Do I really have to know the name of the branch I'm working on?
+
+ If a developer can't be relied on to know what branch of development
+ to work on, then either the developer's manager isn't planning
+ branches properly or the developer has serious problems.
+
+ I have found that one of the hardest concepts to get across to
+ developers (and some managers) is that "a branch in development" (as
+ opposed to the use of RCS branches to support some other scheme) is a
+ heavyweight act. Every time you create a real branch in development,
+ you must spawn a set of managerial procedures and a schedule by which
+ you plan to merge each branch into each other branch. Unless you plan
+ to keep it simple and collapse (by merging and forgetting) branches
+ quickly, they are not to be created lightly.
+
+ In other words, if you don't regularly attend group meetings in which
+ the branch to be worked on is a major topic of discussion, then the
+ group is not managing branches properly.
+
+ We created a couple major branches a few months ago and even the
+ customer service people refer to the "XYZ branch" as a shorthand for
+ "continuing development on the XYZ project".
+
+ Last modified: _6/13/1997_
+
+ 11. How do I refer to the revision where I branched so I can see what
+ changed since the Branch Point on another branch?
+
+ Given the current <branch_tag> format, there is no direct way to refer
+ to the branch point, which is more useful in many ways than referring
+ to the branch, which always refers to the latest revision on the
+ branch.
+
+ When CVS adds a branch tag, it attaches an RCS symbol to a
+ non-existent revision number containing the revision number of the
+ branch point as a prefix. (See Section 3O, on the "tag" command.) RCS
+ can't use the CVS magic branch tag and many of the CVS commands can't
+ refer to it.
+
+ To be certain of your ability to refer to a branch point, you must
+ create a "branch point" tag at the same time as the Branch tag. See
+ 4C.3.
+
+ Last modified: _6/13/1997_
+
+ 12. Why didn't the command "cvs admin -bBRANCH1 *" create a branch?
+
+ Because your command creates an RCS branch, not a CVS branch. See the
+ above discussion on branches. RCS branches are used to support CVS
+ branches, but they are not the same. You can't act as if you have
+ direct control over the RCS files.
+
+ The "admin" command was placed there as a convenience to allow you to
+ execute raw "rcs" commands on the Repository, taking advantage of
+ CVS's ability to find the files in the Repository.
+
+ But you have to remember that you are using RCS commands on a CVS
+ Repository, which is not generally safe unless you know exactly what
+ CVS depends on.
+
+ For one thing, CVS insists on control of the default branch. It is set
+ either to the Main branch or the Vendor branch depending on whether
+ you have changed the Vendor's code. If you change the default branch,
+ you are monkeying with the internals and you will get unexpected
+ results.
+
+ To set your "default CVS branch" to BRANCH1, you must use "checkout"
+ or "update" with the "-r BRANCH1" option. Then you have changed CVS's
+ idea of your "default branch", which has little to do with RCS's
+ default branch.
+
+ Last modified: _6/13/1997_
+
+ 13. Is it possible to set the "default CVS branch" for everyone?
+
+ No. It doesn't work that way.
+
+ When using CVS, all administrative information (such as what branch
+ you checked out) is stored in CVS sub-directories, local to the user.
+ There is no global state, other than the description and logging files
+ in the $CVSROOT/CVSROOT directory.
+
+ You tell "checkout" or "update" what branch you want to check out via
+ the "-r <tag>" option. The default is CVS's "Main Branch".
+
+ I don't see a problem in *designing* a new way to indicate what branch
+ you get by default, instead of the main one, but that's not how it
+ currently works.
+
+ Last modified: _6/13/1997_
+
+ 14. How do I perform a large merge?
+
+ Large merges require a bit more planning to be able to track what has
+ happened in the inevitable cases where something goes wrong. No tool
+ can force a "merge" to make perfect sense.
+
+ Though you can handle the details in many different ways, the two ends
+ of the spectrum of merge techniques are: gonzo and paranoid.
+
+ The gonzo method assumes that you know everything about your sources
+ so that recovery from failures is "just a matter of typing." You
+ created the branch this way:
+
+ cvs checkout <module>
+ cd <module>
+ cvs tag -b <branch_tag>
+ cvs update -r <branch_tag>
+ >>> Edit away.
+ cvs commit <<== Onto branch
+
+ Now you want to merge your branch back into the Main branch, you are
+ certain you can make it work, or at least detect all the failures, so
+ you dive in and hack away: (For simplicity, we will assume you are
+ collapsing (i.e. merging and forgetting) a side-branch into the Main
+ branch from your single working directory.)
+
+ cvs update -A
+ cvs update -j <branch_tag>
+ >>> Edit the 'C' files and remove the overlaps.
+ >>> Edit some more to make it all compile and work.
+ cvs commit
+
+ Looks simple. For more details on the output from the "update -j"
+ command, see 3P.2 and 4C.6.
+
+ Note: You could also checkout a whole new working directory and
+ perform the merge at the same time by replacing the two
+ update commands with these two commands:
+
+ cvs checkout -j <branch_tag> <module>
+ cd <module>
+
+ The paranoid way is more difficult, but it can catch all sorts of
+ problems. You created the branch this way:
+
+ cvs checkout <module>
+ cd <module>
+ cvs tag <branch_point_tag>
+ cvs tag -b <branch_tag>
+ cvs update -r <branch_tag>
+ >>> Edit away.
+ cvs commit <<== Onto branch
+
+ The extra tag command places a non-branch tag on the Branch Point, an
+ act that makes it easier to do "diffs" later. Now we decide to perform
+ the merge:
+
+ cvs tag <latest_on_branch_tag>
+ cvs update -A
+ *1* cvs diff -r <branch_point_tag> -r <latest_on_branch_tag>
+ >>> *1* shows all the changes on the branch.
+ *2* cvs diff -r <branch_point_tag> -r HEAD
+ >>> *2* shows the changes on the trunk since branching.
+ cvs tag <premerge_tag>
+ cvs update -j <branch_tag>
+ >>> Edit the 'C' files and remove the overlaps.
+ *3* cvs diff
+ >>> Verify that *3* matches *1*, except for line numbers.
+ cvs commit
+ cvs tag <just_merge_changes_tag>
+ >>> Edit some more to make it all compile and work.
+ cvs commit
+ cvs tag <after_merge_cleanup_tag>
+
+ The reason *3* and *1* match so closely is that they are the
+ differences between two pairs of starting points and ending points
+ after the same data was inserted. If they are significantly different,
+ you will want to figure out why.
+
+ NOTE: You will have to tell everyone to stay the hell out of the
+ Repository while you do this. If they commit something while you are
+ in the middle of a merge, your job will be much more difficult. If
+ they "update" at the wrong time, their work will be randomized until
+ you finish. It's better to call a halt.
+
+ See 3H.13 for some more information about dealing with merges after
+ import. The last part of the procedure is applicable to any large
+ merge.
+
+ Last modified: _6/13/1997_
+
+ 15. Is a Vendor merge any different from a branch merge?
+
+ No. In most ways, a Vendor branch is exactly the same as any other
+ branch. In a Vendor merge, the data is append to the branch by the
+ "import" command, rather than by hand-editing, but the merge process
+ is the same.
+
+ See the "import" command in section 3H.
+
+ Last modified: _6/13/1997_
+
+ 16. How do I go back to a previous version of the code on a branch?
+
+
+
+
+ You can avoid digging into RCS revision numbers (executing "update
+ -r (rev)" on each file) by trying one of these:
+
+Use non-branch tags as you normally would. Non-branch tags
+ attach to specific revisions, so a "tag (tag)" command would
+ mark the revisions you have in your working directory, which
+ are on your branch. If you need to retrieve them, use "update
+ -r (non-branch-tag)"
+
+ Doing this overrides the sticky (branch-tag) attached to your
+ working directory with a non-branch tag, which means you won't
+ be able to commit until you again move forward to the end of
+ the branch with "update -r (branch-tag)".
+
+Use the "update -r (branch-tag):(date)" trick.
+
+ This is almost like using the '-D' option, but it looks for
+ revisions extant on (date) only along the given branch.
+
+ As in #1, you can't commit to this kind of working area,
+ because it has a sticky date referring to revisions in the
+ middle of a branch.
+
+[comment from the audience: You are dreaming..
+this does not work.. try it, you get
+No such tag: "MYTAG:May 1"
+or similar. I wish it did because I need it. julian@whistle.com]
+
+
+You can branch a branch.
+
+ If you add a branch tag to file in a working directory that was
+ checked out on a branch, you will branch the branch. This
+ works just fine, though you'll have to play some games to merge
+ everything back together again. You'll also create 6-part
+ revision numbers. (They'll be 8-part revision numbers if you
+ branch a branch that started out with some unmodified files on
+ the Vendor branch. Think about it. How does revision
+ 1.2.4.2.4.2.2.1 grab you?)
+
+
+(fixed formatting, kingdon@cyclic.com)
+
+ Last modified: _9/8/1997_
+
+ 17. Once I've found the files I want, how do I start changing them? I keep
+ getting warnings about sticky tags.
+
+ What you probably did was type "cvs update -r <tag>" where <tag> is a
+ non-branch tag. "update" created a sticky tag for a specific revision,
+ not a branch. To start working right there, you have to create a
+ branch to work on.
+
+ You have two choices.
+
+ You can do it in place and keep working:
+
+ cvs tag -b <branch_tag> <<== To tag the current files.
+ cvs update -r <branch_tab> <<== To move onto the branch.
+
+ You can do it "externally" and create a new working directory:
+
+ cvs rtag -b -r <tag> <branch_tag> <module>
+ cvs checkout -r <branch_tag> <module>
+
+ <module> can be a relative path within the Repository.
+
+ <tag> in the above is the non-branch tag you placed earlier
+ that caused the error in your question. Be warned that
+ if <tag> is not set on all the files (or all the right
+ revisions) you won't get exactly what you wanted.
+
+ Last modified: _6/13/1997_
+
+ 18. Why do I get the latest files on the branch when I tried to "update -r
+ <tag>"?
+
+ If "update -r <tag>" always retrieves the latest files on a branch,
+ then <tag> is really a <branch_tag>. A branch tag is supposed to be
+ used to grab a branch to work on. Since you can't modify a file in the
+ middle of a branch, checking out a <branch_tag> will give you the
+ latest revision on the branch.
+
+ If you want to "checkout" a specific collection of revisions, you must
+ use a "non-branch" tag. See the first part of 4C.16.
+
+ Last modified: _6/13/1997_
+
+ 19. How can I avoid a merge? I just want to move the latest revision on my
+ working branch directly onto the trunk.
+
+ There is no direct way to do this using CVS, though the technique is
+ not difficult using shell commands. Here's one way:
+
+ Move your working directory to the Main Branch.
+
+ cvs update -A
+
+ Use "update -p" to grab the latest revision on the branch and write
+ it over your working files. Make sure you don't have an modified files
+ -- you will lose them. The following is in "csh" syntax. Change the
+ wildcard to grab the files you want
+
+ foreach i (Makefile *.cc *.hh)
+ cvs update -p -r <branch_tag> $i > $i
+ end
+
+ Commit all the working files onto the Main Branch.
+
+ cvs commit -m 'Moved branch <branch_tag> onto MAIN'
+
+ You should experiment with the above before blasting everything.
+
+ Last modified: _6/13/1997_
+
+ 20. How to I avoid merge collisions in the RCS $\Log$ data?
+
+ In short, you can't. The RCS $\Log$ keyword is handled differently
+ from all other RCS keywords.
+
+ On the info-cvs mailing list, there is a periodic discussion that goes
+ something like this:
+
+ Question: How do I deal with $\Log$? Answer1: You can't do much with
+ it. Here's how it works. . . Answer2: I've found a limited way to use
+ it. . . Answer3: Get rid of it. $\Log$ is an abomination.
+
+ I tend to lean toward answer #3. There are only two sets of people who
+ would ever have access to logs stored within sources files, developers
+ and source customers.
+
+ For developers:
+
+ Log entries within sources files are notoriously incomplete, rushed,
+ poorly phrased and in many cases incorrect, making them useless for
+ debugging or file maintenance. I remember a maxim from "Software
+ Tools" (I believe): "Read the code, not the comments." No managerial
+ order or plan for programmer discipline will affect this in the real
+ world.
+
+ Log entries are usually in an unreadable mixture of styles. Many log
+ entries are just plain meaningless. Some are foolish. Some are even
+ insulting. Examples:
+
+ "Corrected spelling of misspelling." "Bug fix." "Reversed stupid
+ change in previous revisions." "If Joe could do his job, this would
+ already have worked."
+
+ Log entries are not managed well by the tools. Any merge can cause
+ conflicts in the $\Log$ data. Branch merges produce incomplete logs.
+ They can be edited into chaos and they are not regenerated. They waste
+ space duplicating information available to the developer with a single
+ command.
+
+ Even if correct when originally entered, as changes are made to the
+ file, log entries become false over time. Humans are not good at
+ reading down through a list and remembering only the last change
+ affecting something. Over time *most* of the log is wrong.
+
+ Even if still correct, the log data is almost useless to developers
+ without the code diffs. If you can get code diffs, you can display the
+ log.
+
+ For source customers the problem is even worse. The last thing you
+ want to show customers is a hodge-podge of tiny comments about large
+ changes followed by a series of emergency fixes before delivery. If
+ you distribute sources, then you should provide documentation, or
+ changelogs reviewed by people who won't let comments like "Fixed for
+ stupid customer." out the door.
+
+ Conclusion: Though some people would prefer to see in this FAQ
+ techniques for making the $\Log$ entries the best they can be, I
+ believe them to be a lost cause. My suggestion is to hunt down, root
+ out and destroy all occurrences of $\Log$ and the unusable data
+ attached to it wherever you may find it.
+
+ Last modified: _6/13/1997_
+
+ 21. Why should I trust automatic merges?
+
+ Some developers have the feeling that three-way merging doesn't work.
+ They fear and distrust the way the "update" command automatically
+ merges committed changes from the Repository into the working file.
+
+ Experience has shown that most merges are utterly painless and most of
+ the rest are easily resolved. The few conflicts that cause headaches
+ are nearly all due to poor communication between developers, a problem
+ no source control system can obviate.
+
+ Some developers were troubled in the past by flaky Unix software. I
+ can't say that everything is perfect, but the tools CVS depends on
+ (RCS and diff, mainly) are fairly solid nowadays. They work.
+
+ Since it does seem to work for most of us, the algorithm is unlikely
+ to change soon. Why not test it on a couple trouble spots and if it
+ works for you, use it for a while? Then you can make an informed
+ decision.
+
+ Last modified: _6/13/1997_
+
+ 22. How does CVS decide if it can safely perform a merge?
+
+ CVS can merge any text file, possibly discovering a conflict and
+ leaving overlaps for you to edit. Editing the conflict markers out of
+ the file is a moment's work, but resolving the conflict could take an
+ arbitrary amount of time. CVS works to determine if it *should* merge,
+ not if it *can*.
+
+ See 2B.6 for how the merge proceeds.
+
+ Last modified: _6/13/1997_
+
+ 23. After resolving merge conflicts in a file, what if I want to keep my
+ previous version, and not take any of the branch changes?
+
+ If you want to retain your previous version, a version on the MAIN
+ branch greater than 1.1 (one you committed there), just throw the
+ merged file away and "cvs update" the file.
+
+ You don't need to commit something to remember it. The tags you place
+ before and after the merge should give all the handles you need to
+ find various versions. You don't have to create a new version of the
+ file.
+
+ If you want to retain the previous Vendor revision, you can grab a
+ copy of it using "cvs update -p" and commit it or use the technique
+ described in 3B.3 to revert back to the Vendor branch.
+
+ Last modified: _6/13/1997_
+
+ Category: /Advanced_Topics_/Engineering/
+
+ " + Engineering"
+
+ 1. Where can I find out about Software Engineering?
+
+ A couple different people suggested this book:
+
+ Software Configuration Management: Coordination for Team Productivity;
+ Wayne A. Babich; Addison Wesley; 1986; ISBN 0-201-10161-0
+
+ A number of others suggested Appendix B of the book "Decline and Fall
+ of the American Programmer" by Ed Yourdon, called "The Programmer's
+ Bookshelf". It list 87 books you are expected to have read. Since they
+ publish many of the books, Prentice-Hall distributes this list as
+ "Prentice Hall Professional Technical reference PTR-125-AA3.
+
+ One interesting item from the Yourdon book: The total number of
+ professional computer books sold is less than the number of
+ programmers currently in the United States. It wasn't clear from the
+ book whether this meant "per year" or not, but it is still
+ frightening.
+
+ Last modified: _6/13/1997_
+
+ 2. How do I flexibly arrange the modules file to describe my sources?
+
+ An equivalent question might be, "How do I structure my sources?" This
+ can be a difficult question especially in the areas that are more
+ political than technical.
+
+ Generally you want to think about which pieces of your system need to
+ be checked out together, built as one system or tagged as a consistent
+ whole. You should certainly create module names that correspond to
+ complete, buildable collections that you would tag and release as one
+ "product". It is also convenient to create module names for small
+ sections of the Repository containing files that will all be worked on
+ at the same time by the same person or group.
+
+ Once you have defined the structure of your work, you can usually see
+ how to lay it out in a Repository. After that the modules file is
+ easy. You set up module names and aliases to match what you need to
+ check out by name. If you like relative directories, it is possible,
+ but not recommended, to work completely without a modules file. See
+ 1D.11 and 2C.7 for some info about the modules file.
+
+ Here are a few types of modules. You should experiment to see what
+ kind of structure each of these produces. They all have different
+ uses.
+
+ Connected projects in one group with two separate helper
+ directories. The helper directories can contain build tools, header
+ files, libraries, or whatever you like.
+
+ These are all aliases that checkout relative pathnames. The equivalent
+ results could be produced by placing the selected relative pathnames
+ on the "cvs checkout" command line.
+
+ pr1 -a P1 HELPERS
+ pr2 -a P2 HELPERS
+ pr3 -a P3 HELPERS
+ pr12 -a P1 P2 HELPERS
+ pr13 -a P1 P3 HELPERS
+ pr23 -a P2 P3 HELPERS
+
+ P1 -a group1/proj1
+ P2 -a group1/proj2
+ P3 -a group1/proj3
+ HELPERS -a group1/helper1 group1/helper2 MAKEFILE
+ MAKEFILE -a group1/Makefile
+
+ Actual Repository directory structure: (from $CVSROOT down)
+
+ group1/ Makefile The top level Makefile. helper1/ helper2/ Helper
+ files and dirs proj1/ Files and dirs proj2/ Files and dirs proj3/
+ Files and dirs
+
+ "checkout group1" produces a duplicate of the above. "checkout projX"
+ produces all but "projY" and "projZ". "checkout projXY" produces all
+ but "projZ".
+
+ Here is the exact same set of module names describing the same
+ Repository layout using module names (and aliases containing module
+ names) instead of merely aliases for relative pathnames.
+
+ There is one difference in the result. The name of the top level
+ directory in the checked out working tree will match the "module" name
+ (e.g. pr1) instead of always being "group1" as it was in the first
+ example above.
+
+ pr1 group1 proj1 &HELPERS
+ pr2 group1 proj2 &HELPERS
+ pr3 group1 proj3 &HELPERS
+ pr12 group1 proj1 proj2 &HELPERS
+ pr13 group1 proj1 proj3 &HELPERS
+ pr23 group1 proj2 proj3 &HELPERS
+
+ HELPERS -a helper1 helper2 group1-Makefile
+ helper1 group1/helper1
+ helper2 group1/helper2
+ group1-Makefile -d . group1 Makefile
+
+ The above line (with the -d in it) says that when the module named
+ "group1-Makefile" is checked out, the file named Makefile file will be
+ found in a directory named $CVSROOT/group1 and will be checked out
+ into a directory named '.', which obviously already exists.
+
+ The & references say to interpret those pathnames relative to the
+ directory where the whole module is stored. For the "pr1" module, that
+ directory is "group1", so the &HELPERS reference winds up placing
+ Makefile in '.' relative to "group1".
+
+ A short one containing the basic "module" actions:
+
+ m1 head/path file1 dir2 file3 dir4 file5
+
+ When checked out, a directory named "m1" appears in your current
+ directory. Elements named file1, dir2, file3, dir4, and file5 appear
+ in it. They were originally taken as relative paths from
+ $CVSROOT/head/path.
+
+ Here's another way to construct a working directory out of pieces of
+ the Repository:
+
+ projX projX Makefile &projX_inc &projX_src &projX_doc
+
+ # The first line selects a single file within projX, plus
+ # the contents of three other modules. Those three other
+ # modules rename their directories.
+
+ projX_inc -d include projX/inc projX_src -d source projX/src projX_doc
+ -d documentation projX/doc
+
+ A Unix tree. This is similar to what CVS was developed for and the
+ way I have used it for years.
+
+ # Top level
+ unix unix
+ u_bin unix/bin
+ u_etc unix/etc
+ u_man unix/man
+ usr-bin unix/usr.bin
+
+ # Subdirs of top level dirs. (tiny subset)
+ ls unix/bin/ls
+ fsck unix/etc/fsck
+ man8 unix/man/man8
+
+ # Programs without subdirs. (tiny subset)
+ cat unix/bin Makefile cat.c
+ uniq unix/usr.bin Makefile uniq.c
+
+ # /usr/local/src
+ localsrc localsrc
+ gnu localsrc/gnu
+ public localsrc/public
+ X11 localsrc/X11
+
+ # GNU and PD tools
+ cvs localsrc/gnu/cvs
+ emacs localsrc/gnu/emacs
+ rcs localsrc/gnu/rcs
+ btoa localsrc/public/btoa
+ tcsh localsrc/public/tcsh
+
+ # X11 related items.
+ tvtwm localsrc/X11/contrib/tvtwm
+
+ "unix" was checked out and built from the top down, using a set of
+ Makefiles that knew about the whole structure. "localsrc" was kept
+ checked out in /usr/local/src.
+
+ At any time I could run "checkout ls" or "checkout cat" and get a
+ simple directory with only that tool in it, plus a subset Makefile
+ that knew how to build that tool against the installed (or alternate,
+ via environment variables) headers and libraries.
+
+ I found it very handy to be able to run "ls" and see the three tools I
+ was porting that week.
+
+ Last modified: _6/13/1997_
+
+ 3. Can I have multiple source repositories, one for each project?
+
+ Yes, you can have as many Repositories as you like. But each
+ Repository must be managed separately, creating additional work.
+
+ Question 4A.1 provides a short description of setting up a single
+ Repository. A few additional considerations:
+
+ It is a good idea to start by creating a single Repository and split
+ it up (or create additional Repositories) only if you believe it is
+ really necessary. I would only create a new Repository if the data is
+ completely disconnected from the rest of the main Repository.
+
+ If there is a lot of overlap among the developers working on the
+ collections of files you want to place in different Repositories, or
+ if there is any connection between those collections, I would go out
+ of my way to create a single Repository. It is much easier to manage.
+
+ Disk space should not be a factor since you can build up a
+ Repository using symbolic links and/or remote mounts.
+
+ Each Repository is completely distinct. You can't check out modules
+ from different Repositories at the same time. A better way of looking
+ at it is that if you *can* check out two modules or directories with a
+ single "checkout" command (without contortions or explicit absolute
+ pathnames), then they are in the same Repository.
+
+ To "checkout" modules from multiple Repositories, you must use the
+ "cvs -d" option on all CVS commands or alter your $CVSROOT variable
+ when you change focus to another Repository. If you work with multiple
+ Repositories, it is a good idea to configure CVS to use absolute
+ pathnames in the ./CVS/Repository file, since most commands (other
+ than "checkout") will use that file rather than $CVSROOT.
+
+ If you configure CVS to use relative pathnames in your
+ ./CVS/Repository files, you must always be careful to set your
+ $CVSROOT properly or you will get unexpected results.
+
+ If you have two modules or directories by the same name at the same
+ relative path inside two different Repositories, you are asking for
+ disaster. You could unexpectedly update a directory with completely
+ unrelated files. This is not a fanciful example -- a Repository is
+ occasionally duplicated for release purposes in which case *all* the
+ paths in the two Repositories are the same.
+
+ Last modified: _6/13/1997_
+
+ 4. Who should administer the Repository and manage the modules file?
+
+ This is a "management style" question. In large or traditional groups,
+ the CVS procedures are warped to conform to local conventions. In
+ small groups, in groups with strong personalities or on new projects
+ the choice of source control procedures can help create some of the
+ working environment. Here is a taxonomy of environments I have worked
+ in or helped set up:
+
+ Situation 1.
+
+ A small number of competent developers working on a medium size
+ project. We all got along and we all respected each other (at least
+ technically). Anyone edited anything.
+
+ Modules and Repository admin was mostly left to me. I never found a
+ problem in minor changes made by anyone else.
+
+ Situation 2.
+
+ A large number of experienced developers sprinkled with wackos. Many
+ of the developers didn't want to deal with any kind of source control.
+ They wanted a full-service source control system that caused them zero
+ thought.
+
+ I learned "big stick" diplomacy here. There was a small number of
+ "designated" (by me) people who were allowed to do *anything* other
+ than "update" and "commit". Even "checkouts" were controlled. This is
+ where I found "history" and "release" the most useful.
+
+ Situation 3.
+
+ A small number of developers who wanted me to "help", but who didn't
+ want to deal with anything other than their favorite algorithms.
+
+ I didn't have the time to baby-sit this group, so I designated one of
+ them to be my official contact and made him do it all. He felt sullied
+ by the requirement to pay attention to anything other than his pet
+ coding projects, but enjoyed the "status" of being the only one who
+ could touch the control files without my kicking the chair out from
+ under him.
+
+ Situation 4.
+
+ A huge number of developers of covering the whole spectrum of
+ competence and experience split into 20 groups, none of which
+ cooperated with the others, working on 57 different projects, most of
+ which didn't inter-operate.
+
+ Managing it in any coherent way was not my responsibility (and beyond
+ my tolerance for chaos). Too many people. So I privately designated a
+ person in each group to be the contact and kept watch on the
+ Repository activity. When something went wrong, I notified the contact
+ for the group and told him what was happening and *he* kept his troops
+ in line. They were tougher with their own group that I would have
+ been.
+
+ Eventually only a few people were willing to touch the control files,
+ since they were flamed from all directions if they screwed up.
+
+ Situation 5.
+
+ In a medium group of really *serious*, and seriously overworked,
+ people, someone else was designated the "master". I convinced the
+ master I knew what I was doing and went on my way.
+
+ No one else in the world was allowed to touch anything.
+
+ Situation 6.
+
+ In a large amorphous group of beginners, experts and clowns, over whom
+ no one had official control, I was forced to employ a group of
+ relative beginners (who became experts rather quickly) to police the
+ world. The ultimate in locking the barn after the horse was stolen, we
+ kept Chaos from destroying us only by use of superior firepower.
+
+ My choice, if allowed, is to let anyone touch anything. I keep backups
+ of important items and let people know individually whether I want
+ them to touch things or not. If someone on my "no touch" list touches
+ and succeeds, they are allowed more slack. If they screw up after
+ being warned, their screwup becomes public. After a few months, I
+ usually have no trouble keeping the world running smoothly, at least
+ from my (and CVS's) perspective.
+
+ Last modified: _6/13/1997_
+
+ 5. Isn't disk space a big factor? CVS copies files out of the Repository,
+ duplicating everything.
+
+ Everyone knows that disk space is getting cheaper. How do we reconcile
+ this with the equally well-known problem that *all* disk is *always*
+ filled up?
+
+ In my opinion, the main reason disk space will never be an unlimited
+ resource is that it is the major variable in organizational time/space
+ tradeoffs. It isn't a problem of waste or an aspect of Murphy's law,
+ as some claim it is, but rather a direct consequence of good
+ management. Disk space is, and will always be, a limited resource.
+
+ First, the cost of *deploying* that disk is not dropping as fast as
+ the cost of the storage medium. The cost of machines to hold the disks
+ and the networks to connect them are dropping more slowly than disk
+ media. And the cost of the human time necessary to manage the
+ machines, networks, disks, and the developers using them, is not
+ dropping at all. The cost of human time continues to rise.
+
+ If management decides that expensive human time can be saved by using
+ all that new disk space to keep the last three releases online, then
+ that's what it will be used for. If each release takes up a Gigabyte
+ and you support 30 platforms, a simple time-saving suggestion has just
+ grabbed 100 Gigabytes of disk space. And we've ignored the potential
+ disk storage needed to support "better Customer Service", another
+ management refrain.
+
+ Even at 30 cents per Megabyte (next year's price), you've just used up
+ $30,000 of disk space. And that doesn't count the computers, tape
+ drives and humans necessary to maintain and deploy all of it. Spending
+ money to save time has its own overhead, too.
+
+ Binaries are getting bigger. Graphics and data collection devices can
+ eat up any amount of disk. There are more tools available, more
+ libraries, more raw data than you can ever store. My home computer has
+ a Gigabyte of disk on it. It could easily handle 30.
+
+ The "economy" of disk storage media will never remove the need to
+ manage disk space.
+
+ So, here's an un-reviewed suggestion originally from Graydon Dodson
+ <grdodson@lexmark.com>, which I've altered and edited heavily.
+
+ - Keep a directory where the whole tree is checked out. (It might be
+ built and tested once in a while to make sure it is worth linking to,
+ but that doesn't affect the source control aspect of this procedure).
+ Let's call it /master/build.
+
+ - Write a tool that creates a tree of directories (like the X11
+ "lndir" command) filled with links to the checked out files in the
+ /master/build tree.
+
+ This tool should also provide real copies of, not symlinks to, all the
+ files within the CVS administrative directories.
+
+ - You could also provide a way for the tool to take a list of whole
+ directories that you will never change, for which it would create a
+ single symlink to the directory and not a subtree of symlinks to
+ files. Or you could rm -r pieces of the resulting working directory
+ yourself and replace it with links.
+
+ - If you want to edit a file, you have to grab a real copy and keep it
+ until your revision shows up in the /master/build tree. I'd create a
+ script to do this: cvsgrab <file>
+
+ #!/bin/csh -f
+ set f = $1
+ if (! -l $f) then
+ echo "file $f is not a symlink"
+ exit 1
+ endif
+ rm $f
+ set rev = `grep "^/$f/" CVS/Entries | awk -F/ '{print $3}'`
+ cvs update -p -r $rev $f > $f
+
+ You can't do a plain "cvs update" since that would grab newer
+ revisions from the Repository, not the revision you wanted to start
+ with. After the file is no longer a symlink, you can work normally.
+ You'll have to run "update" before "commit" anyway if there are newer
+ revisions.
+
+ - Presumably there would also be a tool to traverse the link tree and
+ revert it to links if there are no modified files and/or if all the
+ real files match the revision of the /master/build tree.
+
+ - To avoid confusing CVS when the /master/build revisions are updated
+ but your CVS/Entries files is not, CVS would have to change to handle
+ symlinks. It currently causes problems with this scenario:
+
+ ./<file> is a symlink.
+
+ ./CVS/Entries says you are revision 1.2.
+
+ The corresponding CVS/Entries file in /master/build says the latest
+ revision is 1.3.
+
+ cvs update <file> shows a 'C' conflict flag.
+
+ Last modified: _6/13/1997_
+
+ Category: /Advanced_Topics_/Installing_CVS/
+
+ " + Installing CVS"
+
+ 1. What do I have to do before I install CVS?
+
+ You must decide where to set up a Repository.
+
+ Though you can construct a Repository tree structure using links and
+ mount points, there must be a single copy of each real file across
+ your entire organization. You may not "rdist" files and expect to edit
+ both copies.
+
+ CVS does not support a truly distributed Repository. You can have
+ multiple Repositories, but each one must be mounted (not copied or
+ "rdist"ed) from a single place onto all machines where it will be
+ used.
+
+ Initially, a Repository takes about same amount of disk space as the
+ sources you want to put into it, plus a bit of overhead for the RCS
+ files.
+
+ See Section 4B. For multiple Repositories, see 4G.3
+
+ You need a directory in everyone's $PATH variable where you can
+ install all the executables. /usr/local/bin is a common place.
+
+ You need some helper tools besides CVS such as "RCS" and a good set
+ of "diff" and "diff3" programs. See 1B.4 for suggestions.
+
+ Read the README, INSTALL-CVS and ChangeLog files to see what you are
+ getting into.
+
+ Though you can probably muddle along without it, you should appoint
+ one or more "Repository Administrators" who will be responsible for
+ maintaining the Repository structure, administrative files and the
+ "modules" interface.
+
+ Someone at your site should probably be on the info-cvs mailing list.
+ See 1B.5.
+
+ Last modified: _6/13/1997_
+
+ 2. How do I configure the CVS programs?
+
+ You should certainly start by reading the README file, the INSTALL-CVS
+ files and possibly the ChangeLogs in each directory, the Makefile.in
+ files and the "cvsinit.sh" program.
+
+ Execute the ./configure command.
+
+ Type "make".
+
+ After running "make" you might try running the "sanity.sh" script:
+ ./src/sanity.sh `pwd`/src/cvs
+
+ It writes into /tmp/cvs-sanity by default.
+
+ Finish reading the INSTALL-CVS file and test out the system.
+
+ Last modified: _6/13/1997_
+
+ 3. What do I have to install?
+
+ Install the "cvs" executable and "mkmodules" from the CVS sources.
+ The man page is useful too. If you plan to report bugs, you should
+ also install "cvsbug".
+
+ Set your $CVSROOT environment variable and create the Repository
+ (which you planned out in 4A.1) with the "cvsinit" command at the top
+ of the CVS sources.
+
+ You'll need to edit the Repository control files created by
+ "cvsinit".
+
+ Install any helper programs mentioned in the modules file.
+
+ Last modified: _6/13/1997_
+
+ 4. How do I work around the merge problems in GNU diff version 2.1 or
+ later?
+
+ See 1B.4 If you use recent versions of RCS and "diff", you won't run
+ into the above. If you do, see 5B.8
+
+ Last modified: _6/13/1997_
+
+ Category: /Advanced_Topics_/Internal_errors/
+
+ " + Internal errors"
+
+ 1. Explain: "ci error: unexpected EOF in diff output"
+
+ RCS versions earlier than 5.5 print the above error when a file does
+ not end in a newline character. It can be caused by:
+
+ - Editing with Emacs and not using "require-final-newline".
+ - Committing a binary file.
+ - Filesystem failures (NFS!) that put nulls in your file.
+
+ The solution is to upgrade to RCS 5.5 or later. (Of course, this won't
+ fix filesystem failures. It will merely allow RCS (and therefore CVS)
+ to handle the file without error.)
+
+ Last modified: _6/13/1997_
+
+ 2. Explain: "RCS file /Repository/module/file.c,v is in use"
+
+ This is an RCS error that occurs when its internal lock file has been
+ left around by an RCS command interrupted by some sort of system
+ crash, disk failure or SIGKILL signal.
+
+ Go into the Repository and look for files with names similar to
+ "file.c,v", usually starting with ',', '_' or '#'. Make sure they are
+ really crash remnants and do not belong to transactions in progress --
+ a recent last-modified timestamp is a good indicator of a live
+ transaction. Delete them if they are old.
+
+ Last modified: _6/13/1997_
+
+ 3. Explain: "co error, line 2: Missing access list"
+
+ This is an error message from RCS Version 3 when it tries to read a
+ file created by a later version of RCS.
+
+ HP decided to "standardize" on an ancient version of RCS some time
+ ago. You can't use it for CVS. See 4H.6.
+
+ Since the error comes from having a later version of RCS than HP
+ supports, you probably did install the later version but must have
+ recently changed your $PATH or installed the HP package that has RCS
+ in it.
+
+ You should either reconfigure CVS to use absolute pathnames to the
+ proper versions of the RCS programs that CVS uses, or change your PATH
+ to look there first. If you haven't installed the latest version of
+ RCS, you should upgrade. See 1B.4
+
+ Last modified: _6/13/1997_
+
+ 4. Explain: "error: RCS file name `xyz .c' contains white space"
+
+ RCS 5.6 doesn't allow white space in filenames. Apparently this
+ restriction will be removed in RCS 5.7, but CVS may still require that
+ filenames have no white space in them.
+
+ Last modified: _6/13/1997_
+
+ 5. Explain: cvs checkout: warning: <X> is not (any longer) pertinent
+
+ This message occurs in three instances:
+
+ When there is an entry in the ./CVS/Entries for file <X> and there
+ is no RCS file in the Repository to back it up.
+
+ If the working file exists, and hasn't changed (determined from the
+ timestamp) it is removed.
+
+ When you try to check out a piece of the Repository with:
+
+ cvs checkout some/place/in/repository/tree
+
+ and at least the first element of the path (i.e. "some" in the above)
+ exists, but some part of the rest of it does not.
+
+ The checkout command checks the modules file first for the whole path,
+ then for a prefix of the path as a module name. If it doesn't find
+ *any* portion of your path in the modules file, it says:
+
+ cvs checkout: cannot find module `<module/path>' - ignored
+
+ If it finds some set of prefix directories, it prints the message you
+ see.
+
+ In practice this is usually a spelling error.
+
+ If the Repository files you are trying to check out or update are
+ not readable by you, the same problems can occur. Check the
+ permissions on the files involved.
+
+ Last modified: _6/13/1997_
+
+ 6. Why did a Repository file change from <file>,v to ,<file>,?
+
+ This is an RCS problem, since the ,<file>, syntax for file names is
+ used by RCS and not CVS.
+
+ RCS constructs a new <file>,v in a temporary file named ,<file>,
+ (which doubles as a lock file) then renames it to <file>,v when it is
+ done. The only way this is reliable is if your system's version of
+ rename(2) is an atomic, as required by POSIX.
+
+ If your system has a non-atomic (and therefore non-POSIX) rename(2)
+ system call, RCS runs uses an internal version of this algorithm to
+ approximate the atomic rename:
+
+ rm <file>,v; ln ,<file>, <file>,v; rm ,<file>,
+
+ If the system crashes, or you lose your NFS connection between the
+ first "rm", but before the "ln", you can be left only with the
+ ,<file>, file. If the crash or network failure occurs between the "ln"
+ and the final "rm", you could be left with a pair of linked names.
+
+ Recovery:
+ - If only the ,<file>, exists, rename it to <file>,v.
+
+ - If both ,<file>, and <file>,v exist and are linked, remove the
+ ,<file>, file.
+
+ - If both ,<file>, and <file>,v exist and are separate files, look at
+ the dates, "diff" them and make your best guess. This sounds like the
+ remnants of two separate events.
+
+ Last modified: _6/13/1997_
+
+ Category: /Advanced_Topics_/Other_Systems/
+
+ " + Other Systems"
+
+ 1. I use a NeXT. Is there anything I need to know?
+
+ NeXTSTEP 3.0's Interface Builder uses "nib" directories, rather than
+ the files used in previous revisions. It removes files it doesn't
+ recognize, making it impossible to place such a directory under CVS --
+ the CVS admin directory will be removed.
+
+ Some time ago, <Bob_Vadnais@pdh.com> posted a palette named CVSPalette
+ that claimed to resolve this problem. It was intended to preserve the
+ CVS administrative directories within nib documents (directories) that
+ Interface Builder usually removes.
+
+ CVSPalette is no longer in its announced place:
+
+ ftp.cs.orst.edu:/pub/next/submissions
+
+ though I did find two other interesting files on ftp.cs.orst.edu:
+
+ /software/NeXT/sources/tools/cvs-next-2_1_1.tar.Z
+
+ which is a port of CVS 1.3 (along with RCS and diff) and:
+
+ /software/NeXT/sources/programming/cvs.postamble-2.4.gz
+
+ which appears to be a set of wrappers for CVS commands that claim to
+ allow you to use CVS effectively (and without need for the "command
+ line") on a NeXT machine.
+
+ [[Anyone know the truth about CVS and NeXT?]]
+
+ Last modified: _6/13/1997_
+
+ 2. I use OS/2 and/or DOS and/or Windows. Is there anything I need to know?
+
+ When using a local repository, be sure to specify the local access
+ method or CVS will interpret the drive letter as a remote host name
+ due to the : following it:
+
+ WRONG: CVSROOT=C:\SRC\CVSROOT
+
+ RIGHT: CVSROOT=:local:C:\SRC\CVSROOT
+
+ (larry.jones@sdrc.com)
+
+ You can share RCS files between Unix and DOS while avoiding the MS-DOS
+ file name limits by setting your RCSINIT environment variable to
+ '-x/,v'. New RCS files will be created without the standard ",v"
+ suffix, though files ending in ",v" will still be found if there is no
+ matching file in the same directory without the ",v".
+
+ Erik van Linstee offers an OS/2 and a DOS port of CVS 1.3 in:
+
+ ftp.informatik.tu-muenchen.de:/pub/comp/os/os2/gnu/devtools or
+ ftp.rrzn.uni-hannover.de:/pub/os2-local
+
+ The files are named:
+
+ cvs13p?[bs].zip
+
+ Where the ? stands for the patch level (currently 8) and the b is for
+ the binaries, the s for the sources.
+
+ There are three binaries. An OS/2 only one (32-bit), a DOS only one
+ (16-bit) and an EMX one that runs on both (32-bit).
+
+ There are many differences between the Unix and the DOS versions of
+ CVS. Read the material that comes with the DOS version before using
+ it.
+
+ [[Updates?]].
+
+ Last modified: _9/22/1997_
+
+ 3. I use SCO Unix. Is there anything I need to know?
+
+ On SCO/UNIX 3.2 V2.0 POSIX signals don't work. Unfortunately the
+ configure program detects POSIXness and configures in the use of POSIX
+ signals. Workaround : Edit out the check for POSIXness in the
+ configure script. [[You could also remove all occurrences of
+ "-DPOSIX=1" from the Makefiles after configure is run. -dgg-]]
+
+ SCO/UNIX doesn't understand #!/<some shell> syntax. This breaks the
+ use of log.pl as it gets invoked by /bin/sh instead of
+ !#/usr/local/bin/perl. WorkAround : edit log.pl and change it into a
+ shell script which invokes perl with log.perl (renamed from log.pl) as
+ input.
+ Contributed by Joe Drumgoole
+
+ Last modified: _6/13/1997_
+
+ 4. I use AIX. Is there anything I need to know?
+
+ The only report on AIX claims to have no trouble using it in concert
+ with SunOS and IRIX platforms.
+
+ Last modified: _6/13/1997_
+
+ 5. I use IRIX. Is there anything I need to know?
+
+ If you see "uid" numbers where you would expect user names, try adding
+ -lsun to the link line. Without it CVS is unable to retrieve "passwd"
+ data through NIS.
+
+ Last modified: _6/13/1997_
+
+ 6. I use an HP system. Is there anything I need to know?
+
+ HP distributes RCS version 3 (a circa 1983 release!) with HP-UX. CVS
+ does not work with RCS version 3; it requires RCS version 4 or later.
+ Your best bet is to find the latest version of RCS and install it
+ somewhere.
+
+ HP-UX 8.07 has a serious bug with the mmap system call and NFS files;
+ the bug can crash the operating system. Make sure that you configure
+ RCS to avoid mmap by setting has_mmap to 0 in RCS's conf.h. This bug
+ is fixed in HP-UX 9.
+
+ Contributed by Paul Eggert
+
+ If using the setgid() trick described in 4D.13, you will have to
+ create an entry in the /etc/privgroup file to give the group assigned
+ to the cvs executable setgid permission (see setprivgrp(1m)).
+ Additionally, if you are restricting "read" access to the Repository
+ by limiting access to the executable (this requires yet another
+ group), then you will require that /etc/logingroup exists and is
+ configured correctly (usually it's just alink to /etc/group).
+
+ Contributed by Dale Woolridge
+
+ Last modified: _6/13/1997_
+
+ 7. I use AFS. Is there anything I need to know?
+
+ There is a problem with the way CVS performs its locking when the
+ files are within AFS. When your current PTS id != your uid, the locks
+ are not deleted. The stat() system call returns the PTS id of the
+ owner. If that id != your uid, CVS assumes you did not lock it, and
+ leaves the lock files alone. The next time you try to use it, it
+ complains that someone has the repository locked.
+
+ Contributed by Michael Ganzberger
+
+ [[This was against CVS 1.3. Is it still in CVS 1.4?]]
+
+ Last modified: _6/13/1997_
+
+ 8. I use A/UX. Is there anything I need to know?
+
+ [[??]]
+
+ Last modified: _6/13/1997_
+
+ Category: /Advanced_Topics_/Related_Software/
+
+ " + Related Software"
+
+ 1. How do I use CVS under Emacs? Is there an Emacs cvs-mode?
+
+ The pcl-cvs package distributed with CVS is an emacs package that
+ helps with the update/commit process. When you are ready to update,
+ you use the 'cvs-update' command within emacs. This executes "update"
+ and fills a cvs-mode buffer with a line for each file that changed.
+ The most helpful features are: descriptive words for what happened
+ (i.e. Merged or Conflict rather than 'U' or 'C'), single keys bound to
+ diffs and commits, and the ability to mark arbitrary groups of files,
+ possibly from different directories, for commit as a whole.
+
+ All the developers in my group that use emacs find pcl-cvs a much
+ friendlier and more helpful way to update/commit than raw cvs. One vi
+ user even converted to emacs just to use pcl-cvs.
+
+ Contributed by Jeffrey M Loomis
+
+ Last modified: _6/13/1997_
+
+ 2. What is GIC (Graphical Interface to CVS)?
+
+
+
+
+ GIC provides a graphical user interface to the Concurrent Version
+ System (CVS), a powerful revision control system. GIC is
+ implemented in the Tcl/Tk programming language and is intended to
+ augment the sometimes cumbersome CVS command line interface.
+
+ Note that according to the official GIC page at
+ http://www.cpsc.ucalgary.ca/redirect/grouplab/projects/gic/
+ GIC is no longer being maintained and tkCVS is recommended
+ instead.
+
+ For more on tkCVS, see
+ <http://ximbiot.com/cvs/cvshome/dev/addontkcvs.html>.
+
+ kingdon@cyclic.com
+
+ Last modified: _9/6/1997_
+
+ 3. What is CAVEMAN?
+
+ CAVEMAN is a front end to CVS written in PERL providing a collection
+ of features desired by the site where it was developed.
+
+ - The ability to spread a "project" over multiple Repositories.
+ - Optional automatic tagging after each commit.
+ - Additional locking of files.
+ - Extra before and after program hooks.
+ - A layer of event logging.
+ - All sorts of error messages.
+ - Many changes to the semantics of commands.
+
+ It is available via anonymous ftp on ftp.llnl.gov [128.115.54.18] in
+ gnu/caveman_vX.Y.Z.tar.gz (The numbers X, Y, & Z vary.)
+
+ contact Kathleen Dyer kdyer@llnl.gov
+ (510)423-6803
+ (510)423-5112 FAX
+
+ [[Does someone want to elaborate?]]
+
+ Last modified: _6/13/1997_
+
+ Category: /Advanced_Topics_/Setting_up_and_Manag/
+
+ " + Setting up and Managing the Repository"
+
+ 1. What do I do first? How do I create a Repository?
+
+ First, install all the programs. (See Section 4A.)
+
+ Then create a Repository by executing "cvs -d init". (This works with
+ CVS 1.9.)
+
+ Now you can configure your repository by checking out CVSROOT: "cvs -d
+ checkout CVSROOT". Change into the created directory CVSROOT. Edit the
+ files you want to edit, and afterwards, commit the changes by typing
+ "cvs commit".
+
+ You will certainly want to add modules of your own. Edit the "modules"
+ file and add lines to describe the items you want to "checkout" by
+ module name. Here's a short list that could be used for storing a
+ small number of GNU and PD sources:
+
+ local local
+
+ gnu local/gnu
+ emacs local/gnu/emacs
+ cvs local/gnu/cvs
+
+ public local/public
+ pdprog1 local/public/pdprog1
+ pdprog2 local/public/pdprog2
+
+ test test
+ junk test/junk
+
+ Andreas Kostyrka
+
+ Last modified: _4/21/1998_
+
+ 2. What are those files in $CVSROOT/CVSROOT?
+
+ There are eight Repository control (or "database") files of interest
+ in the CVSROOT directory:
+
+ modules contains the "modules" database. See 1D.11, 2C.7, 4B.6 and
+ 4B.7 for more details.
+
+ commitinfo contains two columns: 1. a regular expression to match
+ against pathnames within the Repository and
+
+ a <command> to execute for matching pathnames.
+
+ When you execute "commit", CVS passes the Repository pathname for each
+ directory (and the files to commit within that directory) to
+ <command>. If <command> exits with a non-zero status, the commit is
+ blocked.
+
+ A <command> associated with a pathname of "DEFAULT" is executed if
+ nothing else matches. Every <command> associated with a pathname of
+ "ALL" is executed separately.
+
+ rcsinfo contains the same first column as commitinfo, but the second
+ column is a template file for specifying the log entry you are
+ required to enter for each commit.
+
+ "DEFAULT" and "ALL" work the same as in the commitinfo file.
+
+ editinfo contains the same two columns as commitinfo, but the
+ <command> in the second column is intended to do some consistency
+ checking on the commit log.
+
+ "DEFAULT" works as in commitinfo.
+
+ loginfo contains the same two columns as commitinfo, but the
+ <command> is expected to read a log message from its standard input.
+ The <command> can do anything it wants with the log information, but
+ normally it is appended to a log file or sent to mailing lists.
+
+ "DEFAULT" & "ALL" work the same as in commitinfo.
+
+ cvsignore contains "ignore" patterns that are added to the built-in
+ ignore list. See 2D.10.
+
+ checkoutlist contains a list of other files kept under RCS in
+ $CVSROOT/CVSROOT that should be checked out by mkmodules to provide a
+ readable copy.
+
+ history contains a stream of text records, one for each event that
+ the "history" command is interested in. Though the contents of the
+ history file can be read, it is intended to be read and displayed by
+ the "history" command. This file is the only one in the above list
+ that is not under RCS.
+
+ Last modified: _6/13/1997_
+
+ 3. Is there any other state stored in the Repository besides in the
+ $CVSROOT/CVSROOT directory?
+
+ Only in the RCS files. The Repository holds exactly two things: the
+ tree of RCS files (each usually ending in ",v") and the CVSROOT
+ directory described above.
+
+ Last modified: _6/13/1997_
+
+ 4. How do I put sources into the Repository?
+
+ There are three main ways to put files in the Repository:
+
+ Use the "import" command described in Section 3H.
+
+ This method is the fastest way to put trees of new code into the
+ Repository and the *only* way to handle source releases from a 3rd
+ party software vendor.
+
+ Use "add" followed by "commit".
+
+ This is how to add new files and directories to the Repository, a few
+ at a time. Directories don't need to be committed.
+
+ You can move RCS files directly into the Repository.
+
+ You should create a directory hierarchy to hold them, but you can just
+ move arbitrary ",v" files into the Repository. The only "state" in the
+ Repository other than within ",v" files is in the required CVSROOT
+ directory at the top of the Repository.
+
+ Last modified: _6/13/1997_
+
+ 5. What file permissions should I use on (and in) the Repository?
+
+ If you are using pserver (password-authenticated access), see below.
+
+ If you run a completely open environment (which usually means that you
+ don't have, or don't want to waste, the time to deal with it):
+
+ - Set all directory permissions to 777.
+
+ - Have everyone set their umasks to 0.
+
+ (BTW, I don't suggest this. I am merely reporting it.)
+
+ If you are a normal Unix shop and want to use groups effectively:
+
+ - Set all the directory permissions in the Repository to 775.
+
+ If you are using a system that handles both System V and BSD
+ filesystems, you might have to set the permissions to 2775.)
+
+ If you are using one of the many recent versions of Unix that don't
+ allow you to use the full octal mode, then you'll have to type: chmod
+ u=rwx,g=rwx,o=rx,g+s dir&gt;
+
+ - Change all the groups on the directories to match the groups you
+ want to write to various directories.
+
+ - Make sure every user is in the appropriate groups.
+
+ - Have everyone set their umask to 002, including root.
+
+ If you don't want non-group members to even read the files, do the
+ above, but change:
+
+ - Repository directory permissions to 770. (or 2770)
+
+ - umasks to 007.
+
+ If you work in an environment where people can't be trusted to set
+ their "umask" to something reasonable, you might want to set the umask
+ for them:
+
+ mv /usr/local/bin/cvs /usr/local/bin/cvs.real
+ cat > /usr/local/bin/cvs
+ #!/bin/sh
+ umask 2 # Or whatever your site standard is.
+ exec /usr/local/bin/cvs.real ${1+"$@"}
+ ^D
+
+ Pserver (Password-Authenticated Access) &lt;blome@de.ibm.com&gt;
+
+ The above suggestions are not valid when you use the pserver facility.
+ Be sure to read and understand the manual section about this (should
+ be 4.6.something). Above all: do /not/ make the repository and CVSROOT
+ group writeable. In CVSROOT, make `history´ group or world writeable
+ instead.
+
+ I suggest creating one unix group per project group. In the
+ repository, you would then create one directory for each group, group
+ writeable. New projects must then be created in these group
+ directories. If you don't want to say &lt;group&gt;/&lt;project&gt; on
+ checkout, create a &lt;project&gt; module and point it there.
+
+ Last modified: _9/24/1998_
+
+ 6. How do I structure my Repository?
+
+ The Repository holds your software. It can be all interrelated or it
+ can be a bunch of separately managed directories.
+
+ How you break a whole system down into its component parts, while
+ defining interfaces between them, is one aspect of "Software
+ Engineering", a discipline that requires the study of dozens of
+ strange and wonderful areas of the computer and management worlds.
+
+ CVS provides a way to keep track of changes to individual files, a way
+ to "tag" collections of files, and a way to "name" collections of
+ files and directories. That's all. Everything else is in the way you
+ apply it.
+
+ In other words, you should structure your Repository to match your
+ needs, usually tied in with the other tools you use to build, install
+ and distribute your work. Common needs include the ability to:
+
+ - mount (or automount) directories from many places in your
+ organization.
+ - check out just what you need and no more.
+ - check out multiple sections in a fixed relation to each other.
+ - check out large sections to match the assumptions built into your
+ build system. (Makefiles?)
+
+ In my opinion, you should start small and keep everything in one tree,
+ placing each major sub-system into a separate directory. Later, when
+ you know what you are doing, you can make it more sophisticated.
+
+ Last modified: _6/13/1997_
+
+ 7. Why would anyone use "modules"? They are too restrictive. I want to be
+ able to select just the files I want to edit.
+
+ Any form of structure is restrictive. If you believe that total chaos
+ is a viable working paradigm, or if you believe you can keep track of
+ the interrelations between all portions of your Repository in your
+ head, then you can do what you please.
+
+ If you believe that systems of files require management and structure,
+ then the "modules" idea is very useful. It is a way to impose a naming
+ scheme on a tree of files, a naming scheme that can be simpler than a
+ large list of relative pathnames.
+
+ The "modules" file represents a published interface to the Repository
+ set up by your Repository Administrator. If s/he did a creditable job,
+ the modules offered will be internally consistent and will smoothly
+ interact with the rest of your environment.
+
+ Last modified: _6/13/1997_
+
+ 8. How do I rename a file or directory? What are the consequences?
+
+ In CVS there is no single "rename" command.
+
+ See 2C.4 for the suggested way to rename a file or directory.
+
+ The rest of this section covers some of the consequences of renaming.
+
+ A "renaming database" has been proposed that would keep track of name
+ changes so that "update -r <tag>" would continue to work across the
+ renaming. But as it stands, you have to pick one of the following
+ options:
+
+ Use the technique described in 2C.4. (For each file, duplicate the
+ file in the Repository, "remove" the old version so it winds up in the
+ Attic and strip all Tags off the new version.)
+
+ - "update -r <tag>" produces the correct files.
+
+ - The duplicated revision history can be slightly misleading.
+
+ - A plain (i.e. without the "-r <tag>") "checkout" or "update -d" will
+ create directories "renamed" this way, but you can delete it and a
+ plain "update" won't bring it back.
+
+ Move the files and directories in the Repository to the new names.
+
+ - You save the revision history under a different file name.
+
+ - You save a little space.
+
+ - "update -r <tag>" produces the wrong files or directories.
+
+ This is not a good general solution, but if you plan never to look
+ back (someone may be gaining on you!), it is sometimes a useful
+ notion.
+
+ If you are clever with Makefiles, you might be able to rework them to
+ handle either the new or old names, depending on which ones exist at
+ the time. Then you can move an old <tag> onto the new, more
+ sophisticated, revision of the Makefile. (Yes, this changes the
+ "released" file if <tag> indicates a release. But it is an option.)
+
+ - Important Note: If you rename a directory, you must rename the
+ corresponding directory in every checked-out working directory. At the
+ same time, you must edit the pathname stored in the ./CVS/Repository
+ file within each of the moved directories.
+
+ The easiest way to move a lot of directories around is to tell
+ everyone to remove their working directories and check them out again
+ from scratch.
+
+ - The file exists in the working directory and in the ./CVS/Entries
+ file, but not in the Repository. For the old file, "update" prints:
+
+ cvs update: xyz.c is no longer in the repository
+
+ and deletes the file. If the file was modified, "update" prints:
+
+ cvs update: conflict: xyz.c is modified but no longer in the
+ repository C xyz.c
+
+ and leaves the file alone. In the new directory, you see:
+
+ U xyz.c
+
+ as you would if someone else executed "add" and "commit".
+
+ For each file, copy the working file to a new name in the working
+ directory and use the "cvs remove" to get rid of the old old file and
+ "cvs add" to add the new one. Since there is no way for CVS to remove
+ a directory, this only works for files.
+
+ - This is what most people think of first. Without a "rename" command,
+ the remove/add technique seems obvious.
+
+ - You lose the connection of your new working file to its past
+ revision history.
+
+ Last modified: _6/13/1997_
+
+ 9. What are "Attic" directories?
+
+ When you use the "remove" command on a file, CVS doesn't delete the
+ file, it only registers your desire to delete it.
+
+ When you "commit" a removed file, CVS moves the Repository's matching
+ RCS file into a sub-directory named "Attic" within the Repository.
+
+ Attic files are examined when the '-r' or '-D' option is used on
+ "checkout" or "update". If the specified revision, tag or date matches
+ one on a file in the Attic, that file is checked out with the others.
+
+ You can think of the Attic as a sort of dead branch, which is only
+ looked at when you refer to a <tag> or <date>.
+
+ Last modified: _6/13/1997_
+
+ 10. Is it OK to remove anything from the Repository?
+
+ In general, removing anything from the Repository is a bad idea. The
+ information in a deleted object is lost forever. There are many ways
+ to skip over files, directories and revisions without deleting them.
+
+ Here are some of the consequences of removing the following things
+ stored in the Repository:
+
+ CVSROOT files (Repository control files)
+
+ The Repository will work without any of them, but you should
+ understand what you are losing by deleting them. See 4B.2.
+
+ Revisions
+
+ The only way to remove revisions is to use the "admin -o" command (or
+ the equivalent RCS command "rcs -o").
+
+ They are lost forever. Any tags formerly attached to deleted revisions
+ are now pointing into the Phantom Zone. You'll need to contact Jor-el
+ to get them back.
+
+ Files
+
+ You should not remove a file unless you truly never want to see it
+ again. If you want to be able to check out an old revision of this
+ file, use "cvs remove" instead.
+
+ Tags
+
+ Tags take up little space and you can't recover from deleting them. If
+ you depend on tags for releases you will lose vital information.
+
+ Directories
+
+ There is no Attic for directories, so the only way to remove them is
+ to use "rm -r". They are gone forever.
+
+ If you delete (or move) a directory, all checked-out versions of that
+ directory will cause CVS to halt. You'll have to visit each
+ checked-out directory and remove the matching working directory by
+ hand.
+
+ Attic files
+
+ The "remove" command sends files to the Attic. To really delete them,
+ you have to go into the Attic and use "rm".
+
+ If a file in the Attic has a Tag on it that you might ever want to
+ check out again, you probably don't want to delete it.
+
+ Lock files (named: "#cvs.[wr]fl.<pid>")
+
+ These are lock files. If you are getting "lock" errors and the dates
+ on the lock files indicate that they are old, you can delete them.
+
+ Deleting lock files still in use by a CVS process might produce
+ unusual errors.
+
+ Last modified: _6/13/1997_
+
+ 11. Can I convert to CVS from RCS without losing my revision history?
+
+ Yes, you can simply move (or copy) your RCS files into a directory
+ within the Repository, check out that directory and start working.
+
+ Last modified: _6/13/1997_
+
+ 12. Can I move RCS files with branches in them into the Repository?
+
+ Yes, but they may not work if you created branches in a way that
+ conflicts with CVS's assumptions:
+
+ You can't use .0. branches. (They are reserved for "Magic" branch
+ tags.)
+
+ If you use branch 1.1.1, you can't use the Vendor branch.
+
+ You can use other RCS branches under CVS. There is no need to create
+ "magic" branch tags because the physical branch already exists.
+
+ Last modified: _6/13/1997_
+
+ 13. Can I use raw RCS commands on the Repository?
+
+ You can use raw rcs commands directly on the Repository if you take a
+ little care. The Repository itself contains no "CVS state" (as opposed
+ to RCS revision histories) outside the CVSROOT directory.
+
+ But using raw RCS commands to change branches, tags or other things
+ that CVS depends on may render the files unusable.
+
+ See 4D.7 on RCS/CVS sharing of the Repository and Section 3B on the
+ "admin" command.
+
+ Last modified: _6/13/1997_
+
+ 14. How do I convert from SCCS to RCS?
+
+ You'll have to execute something like "sccs2rcs" (in the CVS contrib
+ directory) on every file. Then you can move the resulting RCS files
+ into the Repository as described above.
+
+ Last modified: _6/13/1997_
+
+ 15. How do I limit access to the Repository?
+
+ There are all sorts of ways to restrict access to Repository files,
+ none of which are hooked directly into CVS.
+
+ Techniques for limiting access include:
+
+ Training, management and good backups.
+
+ The best form of Repository control is a combination of:
+
+ - A reliable backup scheme (verify it!)
+ - Enough training to ensure your developers are competent and
+ knowledgeable about all areas of your sources.
+ - Effective management of the boundaries and grey areas.
+
+ In many cases, technical solutions to "security" problems are
+ inadequate. You should first try to avoid them.
+
+ Personal Opinion: In an environment where "unknowns" are allowed to
+ touch important sources the "owner" of the CVS Repository must be a
+ large, loud, vigorous lout with a well-balanced truncheon and the
+ right to use it. Don't underestimate the effectiveness of letting
+ everyone know they will be strapped into the stocks on the Town Common
+ and pelted with vegetables if they break something they don't
+ understand without first asking the experts.
+
+ Set Unix groups and permissions. See 4B.5. You can set different
+ owners, groups and permissions for each sub-directory within the
+ Repository if that helps.
+
+ Catch invocations of "commit" by defining pre-commit programs in the
+ "commitinfo" file. This is fairly powerful, since it can block commits
+ based on anything you can program. Take a look at the programs in the
+ "contrib" directory of the CVS source tree.
+
+ Use multiple Repositories, each with its own protection scheme. If
+ you use NFS (or AFS) you can even use "export" restrictions to various
+ groups of machines to keep (for example) the Engineering Repository
+ off the Customer Service machines.
+
+ Try the "setgid" trick described in 4D.13.
+
+ Try to use the RCS access control lists, though I don't think CVS
+ will handle them cleanly.
+
+ Edit the source code to CVS to add your own access control.
+
+ Last modified: _6/13/1997_
+
+ 16. What are the Repository Administrator's responsibilities?
+
+ Generally, the Administrator should set "policy", create the
+ Repository and monitor its size and control files.
+
+ Some specific responsibilities include:
+
+ Examining the Repository once in a while to clean up:
+
+ Trash files left by misguided developers who mistake the Repository
+ for a working directory.
+
+ Non-RCS files. Other than the files CVS needs in the
+ $CVSROOT/CVSROOT directory, every file in the Repository should be an
+ RCS file.
+
+ Lock files (both CVS '#*' and RCS ',*' files) left around after
+ crashes.
+
+ Wrong permissions, groups and ownerships.
+
+ Locked files. (RCS locks, that is.)
+
+ Attic files that should never have been under CVS at all. Don't
+ blindly delete files from Attic directories -- they were mostly put
+ there (via the "cvs remove") for a reason. Files that should be
+ deleted are binary files (e.g. '*.o', 'core', executables) that were
+ mistakenly inserted by "import -I !".
+
+ Maintaining the modules file.
+
+ Storing site-specific ignore patterns in the
+ $CVSROOT/CVSROOT/cvsignore file.
+
+ Storing the names of non-standard CVSROOT files (See 4B.2) in the
+ $CVSROOT/CVSROOT/checkoutlist
+
+ Maintaining the other Repository control files: commitinfo, loginfo,
+ rcsinfo and editinfo.
+
+ Pruning the history file every once in a while. (Try the
+ "cln_hist.pl" script in the "contrib" directory.)
+
+ Staying aware of developments on the info-cvs mailing list and what
+ is available in the FTP and WWW archives.
+
+ Running "ps ax" once in a while and kill off any "update" programs
+ not running as "root". It is too easy to leave the "cvs" off the front
+ of the "cvs update" command.
+
+ Executing monitor programs to check the internal consistency of the
+ Repository files. Ideas:
+
+ Files that have a default RCS branch that is not 1.1.1 (From an
+ abuse of "admin -b".)
+
+ Files that have only Revisions 1.1 and 1.1.1.1, with a default
+ branch of "MAIN". (From an abuse of "admin -o".)
+
+ Existing branch tags and various branch consistency checks.
+
+ Last modified: _6/13/1997_
+
+ 17. How do I move the whole Repository?
+
+ Copy or move the tree. (On Unix systems, a set of piped "tar" commands
+ works great. If the Repository does not contain any symlinks, which it
+ normally doesn't, you can also use "cp -r".)
+
+ If you can avoid changing $CVSROOT (i.e. the "logical" pathname of the
+ Repository) by replacing the old location with a symbolic link to the
+ new location, you don't have to do anything else.
+
+ (You could also mount the new location on top of the old location if
+ you are using NFS or some other filesystem that allows it.)
+
+ If you must change $CVSROOT, you must also tell everyone to change the
+ CVSROOT environment variable in all running shells and in any personal
+ configuration files ('.' files on Unix) where it is set.
+
+ The Repository itself contains no references to its own name, except
+ possibly in some of the files in the CVSROOT directory. If your
+ modules (or loginfo, commitinfo, etc.) file mentions helper programs
+ directly in the Repository, you'll have to change the pathnames to
+ point to the new Repository location.
+
+ The main changes you'll have to make are to all the CVS administrative
+ files (./CVS/Repository and ./CVS/Root) in every working directory
+ ever checked out from the previous location of the Repository you just
+ moved.
+
+ You have three choices:
+
+ If all ./CVS/Repository files in all working directories contain
+ relative pathnames, you don't have to do anything else.
+
+ Have everyone "release" or delete their working directories (after
+ committing, or just saving, their work) and check them all out again
+ from the new Repository after the move.
+
+ Use "find . ( -name Repository -o -name Root )" and a PERL or shell
+ script to run through all the ./CVS/Repository and ./CVS/Root files
+ and edit the values in the files.
+
+ Last modified: _6/13/1997_
+
+ 18. How do I change permissions on a file in the Repository by using a CVS
+ command? (i.e. without using "chmod 777 $CVSROOT/dir/file")
+
+ When you first "import" or "add"/"commit" a file, the read and execute
+ bits on the Repository file are inherited from the original source
+ file, while the write bits on the Repository file are are turned off.
+ This is a standard RCS action.
+
+ After that, there is no way to alter the permissions on a file in the
+ Repository using CVS (or RCS) commands. You have to change the
+ permissions on both your working file and on the Repository file from
+ which it was retrieved.
+
+ Whenever you "checkout" the file or retrieve a new revision via
+ "update" (or after a "commit"), your working file is set to match the
+ permissions of the Repository file, minus any "umask" bits you have
+ set.
+
+ Last modified: _6/13/1997_
+
+ Category: /Advanced_Topics_/Tricks_of_the_Trade/
+
+ " + Tricks of the Trade"
+
+ 1. How can you even check in binary files, let alone allow CVS to do its
+ auto-merge trick on them?
+
+
+First of all, if you want to use binary files, you should get RCS 5.7
+and CVS 1.9 or later (earlier versions had some support, but there have been
+bug fixes). Secondly, follow the instructions for installing RCS very
+carefully (it is easy to get it installed so it works for everything
+except binary files).
+
+Then, specify 'cvs add -kb' instead of just 'cvs add' to add a binary
+file. If you want to set an existing file to binary, run 'cvs admin
+-kb' (and then check in a new copy of the file). Note that old
+versions of CVS used -ko instead of -kb for binary files, so if you
+see a reference to -ko in the context of binary files, you should
+think -kb instead.
+
+Of course when 'cvs update' finds that a merge is needed, it can't
+do this for binary files the same way as for text files. With the
+latest versions (e.g. CVS 1.9.14), it should be able to give you both
+versions and let you merge manually. Another approach is to
+run 'cvs admin -l' to lock files, as described in
+"How can I lock files while I'm working on them the way RCS does?"
+elsewhere in this FAQ. See also
+"Is there any way to import binary files?" and
+"How do I "add" a binary file?" elsewhere in this FAQ.
+
+kingdon@cyclic.com
+
+ Last modified: _9/6/1997_
+
+ 2. Can I edit the RCS (",v") files in the Repository?
+
+ Yes, but be very careful. The RCS files are not free-form files, they
+ have a structure that is easily broken by hand-editing. The only time
+ I would suggest doing this is to recover from emergency failures that
+ are difficult to deal with using CVS commands, including the "admin"
+ command, which can talk directly to RCS.
+
+ Though no one actively encourages the editing of RCS files, many
+ people have succumbed to the urge to do so when pressed for time. The
+ reasons given, usually with evident contrition, include:
+
+ - Editing mistakes in, or adding text to, log entries. (If you have
+ RCS 5.6 or later, you should use `cvs admin -m'.)
+ - Renaming or moving symbolic names. (You should `cvs admin -N'
+ instead.)
+ - Unlocking a file by changing the "locker" from someone else to
+ yourself. (It's safer to use `cvs admin -u -l'.)
+ - Making global changes to past history. Example: Eradicating former
+ employees names from old documents and Author entries. (And someone
+ thought the "history" command was evidence of Big Brother! I never
+ realized how much help a wide-open revision control system could have
+ provided to The Ministry of Truth.)
+
+ Last modified: _6/13/1997_
+
+ 3. Can I edit the ./CVS/{Entries,Repository,Tag} files?
+
+ Yes, but with CVS 1.3 and later, there is almost no reason to edit any
+ of the CVS administrative files.
+
+ If you move pieces of your Repository around it can be faster to edit
+ all the ./CVS/Repository files rather than checking out a large tree.
+ But that is nearly the only reason to do so.
+
+ Last modified: _6/13/1997_
+
+ 4. Someone executed "admin -o" and removed revisions to which tags/symbols
+ were attached. How do I fix them?
+
+ It depends on what you mean by "fix". I can think of three ways to fix
+ your predicament:
+
+ Remove the tags.
+
+ Assuming you really wanted to get rid of the revision and its
+ associated tags, you can remove them with the "admin" command. The
+ "tag -d" command will only remove tags attached to existing revisions.
+ You can remove a tag, even if it is attached to a non-existent
+ revision, by typing:
+
+ cvs admin -N<tag> <file>
+
+ Retrieve the outdated revision.
+
+ You should first look in your backup system for recent versions of the
+ file. If you can't use them, you can carefully extract each revision
+ that followed the earliest outdated revision using RCS (or "cvs
+ admin") commands and reconstruct the file with all the right
+ revisions, branches and tags. This is a lot of work.
+
+ You *can't* insert a revision into the current RCS file.
+
+ Move the Tags to another revision in each file.
+
+ If you want to move the tags to another valid revision, you have two
+ choices, both of which require that you find all the revision numbers
+ of the files you want to "tag" and execute the following command
+ sequences on each <file>.
+
+ Use "update" to grab the revision you want, then execute a normal
+ "tag" command to Tag that revision:
+
+ cvs update -r <rev> <file>
+ cvs tag <tag> <file>
+
+ Use "admin" to set the tag to a specific revision:
+
+ cvs admin -N<tag>:<rev> <file>
+
+ Last modified: _6/13/1997_
+
+ 5. How do I move or rename a magic branch tag?
+
+ (To rename a non-branch <tag> see 3O.9.)
+
+ Before reading this, read 3M.3 and 3M.4 and understand exactly how tag
+ and rtag use '-r' and why it won't do the right job here.
+
+ First, I have to explain exactly what a magic branch tag is.
+
+ A magic <branch_tag> is an artificial tag attached to a non-existent
+ revision on a non-existent branch number zero. It looks like this:
+
+ TAG1:<X>.0.Y
+
+ <X> is the "branch point revision", a normal revision with an
+ odd number of '.'s in it. (e.g. 1.5, 1.3.1.6, etc)
+
+ Y is an even number (e.g. 2, 4, 6, etc.) All CVS branches,
+ other than the Vendor branch, are even numbered.
+
+ TAG1 is considered by CVS to be attached to revision <X>. The first
+ "update -r TAG1 <file>" after applying TAG1 will produce a copy of
+ revision <X> with a sticky tag of TAG1. The first "commit" to that
+ file will cause CVS to construct an RCS branch named <X>.Y and check
+ in revision <X>.Y.1 on the new branch.
+
+ Note: TAG1 is *not* considered to be attached to <X> by RCS, which
+ explains why you can't refer directly to the branch point revision for
+ some CVS commands.
+
+ Moving a magic <branch_tag> is the act of reapplying the same tag to
+ different revisions in the file:
+
+ TAG1:<X>.0.Y
+ to
+ TAG1:<X>.0.Z or TAG1:<A>.0.B
+
+ You can move a magic branch tag to the revisions of your choice by
+ using "update" to find the revisions you want to tag and reapplying
+ the tag to all the files with the '-F' option to force it to move the
+ existing <branch_tag>.
+
+ cvs update -r <tag/rev> (or '-A' for the Main Branch)
+ cvs tag -F -b <branch_tag>
+
+ If the earlier location of TAG1 refers to a physical branch within any
+ RCS file, moving it will make the existing branch in the file seem to
+ disappear from CVS's view. This is not a good idea unless you really
+ want to forget the existence of those RCS branches.
+
+ If the "update" above retrieves the original branch point revision
+ (<X>), the "tag" command above will create the tag:
+
+ TAG1:<X>.0.Z
+
+ Where Z is 2 greater than the highest magic branch already on revision
+ <X>. The TAG1 branch will still have the same branch point (i.e.
+ revision <X>), but the first commit to the new TAG1 branch will create
+ a different RCS branch number (<X>.Z instead of <X>.Y).
+
+ Renaming a magic <branch_tag> is the act of changing
+
+ TAG1:<X>.0.Y
+ to
+ TAG2:<X>.0.Y
+
+ There is no harm in changing a tag name as long as you forget that
+ TAG1 ever existed and you clean up any working directories with sticky
+ TAG1 tags on them by using "update -A", "update -r <other_tag>" or by
+ removing the working directories.
+
+ On the other hand, actually changing the tag is not easy.
+
+ See 3M.3 for why the seemingly obvious solution won't work:
+
+ cvs tag -b -r <old_branch_tag> <new_branch_tag>
+
+ The only direct way to rename a magic tag is to use the "admin"
+ command on each file: (You might want to use '-n'. Read "man rcs" and
+ look at the '-n' and '-N' options.)
+
+ cvs admin -N<new_branch_tag>:<old_branch_tag> .
+ cvs tag -d <old_branch_tag>
+
+ But you have to be careful because "admin" is different from other CVS
+ commands:
+
+ "admin" can be used recursively, but only by specifying directory
+ names in its argument list (e.g. '.'),
+
+ Where "rtag -r <old_branch_tag>" would interpret <old_branch_tag> as
+ a magic CVS branch tag, "admin" is a direct interface to RCS which
+ sees a magic branch tag as a simple (though non-existent) RCS revision
+ number.
+
+ This is good for us in this particular case, but different from normal
+ CVS.
+
+ "admin" also skips the Attic and produces different kinds of errors
+ than CVS usually does. (Because they are coming directly from RCS.)
+
+ The other way to rename a magic <branch_tag> is to edit the Repository
+ files with a script of some kind. I've done it in the past, but I'll
+ leave it as an exercise for the reader.
+
+ Last modified: _6/13/1997_
+
+ 6. Can I use RCS locally to record my changes without making them globally
+ visible by committing them?
+
+ You can, but it will probably confuse CVS to have ",v" files in your
+ working directory. And you will lose all your log entries when you
+ finally commit it.
+
+ Your best bet is to create your own CVS branch and work there. You can
+ commit as many revisions as you want, then merge it back into the main
+ line (or parent branch) when you are finished.
+
+ Last modified: _6/13/1997_
+
+ 7. How can I allow access to the Repository by both CVS and RCS?
+
+ The first step is to try not to. If some people are using CVS, there
+ is no reason for everyone not to. It is not hard to learn the basics
+ and CVS makes certain operations *easier* than a series of RCS
+ commands. Personal preference in what software tools can be applied to
+ a shared Repository has to take second place to system integration
+ needs. If you disagree, try writing some Lisp code for inclusion in
+ your Unix kernel and see what kind of reception you get.
+
+ If you really must allow routine RCS access to the CVS Repository, you
+ can link an RCS sub-directory into a piece of the Repository:
+
+ ln -s /Repository/some/directory/I/want RCS
+
+ and RCS will work just fine.
+
+ Those who are using RCS will have to keep the following in mind:
+
+ If a file was originally added to the Repository by "import" and has
+ not been changed using CVS, the *RCS* default branch will remain
+ attached to the Vendor branch, causing revisions checked-in by "ci" to
+ wind up on the Vendor branch, instead of the main branch. Only CVS
+ moves the RCS default branch on first commit.
+
+ The way around this is to checkin (using "ci") all the files first and
+ move them into the Repository. That way they won't have Vendor
+ branches. Then RCS will work OK.
+
+ It is possible to use "rcs" and "ci" to make the files unusable by
+ CVS. The same is true of the CVS "admin" command.
+
+ Normal RCS practice locks a file on checkout with "co -l". In such
+ an environment, RCS users should plan to keep survival gear and food
+ for at least 30 days near their desks. When faced with bizarre and
+ unexpected permission errors, howling mobs of slavering CVS users will
+ run the RCS users out of town with pitchforks and machetes.
+
+ See 3C.8 for a way to avoid machetes aroused by lock collisions.
+
+ Though files checked in by RCS users will correctly cause
+ "up-to-date" failures during CVS "commits" and they will be
+ auto-merged into CVS working directories during "update", the opposite
+ won't happen.
+
+ RCS users will get no warning and will not be required to merge older
+ work into their code. They can easily checkin an old file on top of a
+ new revision added by CVS, discarding work committed earlier by CVS
+ users.
+
+ See the howling mob scenario described above.
+
+ RCS is great. I have used it for years. But I wouldn't mix it this
+ way. In a two-camp society, you are asking for real trouble, both in
+ technical hassles to clean up and in political hassles to soothe.
+ Branch merges will also be a major problem.
+
+ Last modified: _6/13/1997_
+
+ 8. I "updated" a file my friend, "bubba", committed yesterday. Why doesn't
+ the file now have a modified date of yesterday?
+
+ CVS restores dates from the RCS files only on first "checkout". After
+ that, it is more important to maintain a timestamp relative to the
+ other files in the working directory.
+
+ Example: You committed a source file at 5PM. Bubba updated his copy of
+ the file, grabbing your changes, then changed and committed a new
+ revision of the file at 6PM. At 7PM, you compile your file. Then you
+ execute "update". If CVS sets the date to the one in the RCS file, the
+ file would be given a timestamp of 6PM and your Makefile wouldn't
+ rebuild anything that depended on it. Bad news.
+
+ Note that the same logic applies to retrieving a revision out of the
+ Repository to replace a deleted file. If CVS changes your file in an
+ existing working directory, whether it was because a new revision was
+ committed by someone else or because you deleted your working file,
+ the timestamp on the retrieved working file *must* be set to the
+ current time.
+
+ When you first retrieve a file, there is no reason to expect any
+ particular timestamp on the file within your working area. But later,
+ when dependency checking is performed during a build, it is more
+ important for the timestamps on the local files to be consistent with
+ each other than than it is for working files to match the timestamps
+ on the files in the Repository. See 4D.17 for some more about
+ timestamps.
+
+ Last modified: _6/13/1997_
+
+ 9. Why do timestamps sometimes get set to the date of the revision,
+ sometimes not? The inconsistency causes unnecessary recompiles.
+
+ The "checkout" command normally sets the timestamp of a working file
+ to match the timestamp stored on the revision in the Repository's RCS
+ file.
+
+ The "commit" command retains the timestamp of the file, if the act of
+ checking it in didn't change it (by expanding keywords).
+
+ The "update" command sets the time to the revision time the first time
+ it sees the file. After that, it sets the time of the file to the
+ current time. See 4D.8 for a reason why.
+
+ Here's a two-line PERL program to set timestamps on files based on
+ other timestamps. I've found this program useful. When you are certain
+ you don't want a source file to be recompiled, you can set its
+ timestamp to the stamp on the object file.
+
+ #!/usr/local/bin/perl
+ #
+ # Set timestamp of args 2nd-Last to that of the first arg.
+ #
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime)
+ = stat(shift);
+ utime($atime,$mtime,@ARGV);
+
+ Last modified: _6/13/1997_
+
+ 10. While in the middle of a large "commit", how do I run other commands,
+ like "diff" or "stat" without seeing lock errors?
+
+ Type:
+ cvs -n <command>
+
+ The '-n' option to the main cvs command turns off lock checking, a
+ reasonable act for read-only commands given the promise offered by
+ '-n' not to alter anything. The "diff", "log" and "stat" commands
+ provide the same information (for files that are not being committed)
+ when used with and without the '-n' option.
+
+ Warning: Ignoring locks can produce inconsistent information across a
+ collection of files if you are looking at the revisions affected by an
+ active commit. Be careful when creating "patches" from the output of
+ "cvs -n diff". If you are looking only at your working files, tagged
+ revisions, and BASE revisions (revisions whose numbers are read from
+ your ./CVS/Entries files), you should get consistent results. Of
+ course, if you catch a single file in the middle of RCS activity, you
+ might get some strange errors.
+
+ Note that the suggested command is "cvs -n <command>". The visually
+ similar command "cvs <command> -n" has no relation to the suggested
+ usage and has an entirely different meaning for each command.
+
+ "cvs -n update" also works in the middle of a commit, providing
+ slightly different information from a plain "cvs update". But, of
+ course, it also avoids modifying anything.
+
+ You could also use the RCS functions, "rlog" and "rcsdiff" to display
+ some of the information by referring directly to the Repository files.
+
+ You need RCS version 5 or later for the commands described above to
+ work reliably.
+
+ Last modified: _6/13/1997_
+
+ 11. Where did the ./CVS/Entries.Static file come from? What is it for?
+
+ Each CVS working directory contains a ./CVS/Entries file listing the
+ files managed by CVS in that working directory. Normally, if the
+ "update" command finds a file in the Repository that is not in the
+ ./CVS/Entries file, "update" copies the appropriate revision of the
+ "new" file out of the Repository and adds the filename to the Entries
+ file. This happens for files:
+
+ Added to the Repository from another working directory.
+
+ Dragged out of the Attic when switching branches with "update -A" or
+ "update -r".
+
+ Whose names were deleted from the ./CVS/Entries file.
+
+ If the ./CVS/Entries.Static file exists, CVS will only bring out
+ revisions of files that are contained in either ./CVS/Entries or
+ ./CVS/Entries.Static. If a Repository file is found in *neither* file,
+ it is ignored.
+
+ The ./CVS/Entries.Static file is created when you check out an
+ individual file or a module that creates working directories that
+ don't contain all files in the corresponding Repository directory. In
+ those cases, without an ./CVS/Entries.Static file, a simple "update"
+ would bring more files out of the Repository than the original
+ "checkout" wanted.
+
+ The ./CVS/Entries.Static file can be removed by hand. It is
+ automatically removed if you run "update -d" to create new directories
+ (even if no new directories are created). (Internally, since
+ "checkout" turns on the '-d' flag and calls the "update" routine, a
+ "checkout" of a module or directory that writes into an existing
+ directory will also remove the ./CVS/Entries.Static file.)
+
+ Last modified: _6/13/1997_
+
+ 12. Why did I get the wrong Repository in the loginfo message?
+
+ You probably:
+
+ Use multiple Repositories.
+
+ Configured CVS to use absolute pathnames in the ./CVS/Repository
+ file.
+
+ Configured CVS not to use the ./CVS/Root file.
+
+ Typed the "commit" command in one Repository with your $CVSROOT
+ pointing at another.
+
+ "commit" and all other CVS commands will heed an absolute pathname in
+ the ./CVS/Repository file (or in the "-d CVSrootdir" override), but
+ the log function doesn't take arguments -- it just looks at $CVSROOT.
+
+ If you avoid even one of the four steps above, you won't see this
+ problem. If you configure ./CVS/Root, you won't be allowed to execute
+ the program causing the error.
+
+ Last modified: _6/13/1997_
+
+ 13. How do I run CVS setuid so I can only allow access through the CVS
+ program itself?
+
+ Setuid to root is not a great idea. Any program that modifies files
+ and is used by a widely distributed group of users is not a good
+ candidate for a setuid program. (The worst suggestion I've ever heard
+ was to make *Emacs* setuid to root.)
+
+ Root access on Unix is too powerful. Also, it might not work in some
+ (secure?) environments.
+
+ Running it setuid to some user other than root might work, if you add
+ this line to main.c near the beginning:
+
+ setuid(geteuid());
+
+ Otherwise it uses *your* access rights, rather than the effective
+ uid's.
+
+ Also, you have to invent a fake user whose name will show up in
+ various places. But many sites, especially those who might want a
+ setuid CVS for "security", want personal accountability -- no generic
+ accounts. I don't know whether accountability outweighs file security.
+
+ And finally, unless you take action to limit the "admin" command, you
+ are leaving yourself unprotected anyway.
+
+ Last modified: _6/13/1997_
+
+ 14. How about using groups and setgid() then?
+
+ Here is a way to run CVS setgid in some environments:
+
+ Stick this near the front of the main() in main.c:
+
+ setgid(getegid());
+
+ This will allow "access" to work on systems where it only works on the
+ real gid.
+
+ Create a group named "cvsg". (This example uses "cvsg". You can name
+ it as you wish.)
+
+ Put *no* users in the "cvsg" group. You can put Repository
+ administrators in this group if you want to.
+
+ Set the cvs executable to setgid (not setuid):
+
+ cd /usr/local/bin; chown root.cvsg cvs; chmod 2755 cvs
+
+ Make sure every file in the Repository is in group "cvsg":
+
+ chown -R root.cvsg $CVSROOT
+
+ Change all directory permissions to 770. This allows all access to
+ the files by the "cvsg" group (which has no members!) and no access at
+ all to anyone else.
+
+ find $CVSROOT -type d -exec chmod 2770 {} \;
+
+ On some systems you might have to type:
+
+ find $CVSROOT -type d -exec chmod u=rwx,g=rwx,o=,g+s {} \;
+
+ This should allow only the cvs program (or other "setgid to group
+ cvsg") programs to write into the area, but no one else. Yes the user
+ winds up owning the file, but s/he can't find it again later since
+ s/he can't traverse the tree. (If you enable the world execute bit
+ (mode 2771) on directories, users can traverse the tree and the user
+ who last wrote the file can still write to it.)
+
+ If you want to allow read access, check out an entire tree somewhere.
+ You have to do this anyway to build it.
+
+ Note: If you are using a stupid file system that can't inherit file
+ groups from the parent directory (even with the "setgid" (Octal 2000)
+ bit set), you might have to modify CVS (or RCS) to reset the group
+ every time you create a new file. I have not tested this.
+
+ The setgid() method shares with the setuid() method the problem of
+ keeping "admin" from breaking things.
+
+ Last modified: _6/13/1997_
+
+ 15. How do I use the "commitinfo" file?
+
+ Go read 4B.2 first.
+
+ The "commitinfo" file allows you to execute "sanity check" functions
+ before allowing a commit. If any function called from within the
+ commitinfo file exits with a non-zero status, the commit is denied.
+
+ To fill out a "commitinfo" file, ask yourself (and those sharing your
+ Repository) these questions:
+
+ - Is there anything you want to check or change before someone is
+ allowed to commit a file? If not, forget commitinfo.
+
+ If you want to serialize binary files, you might consider something
+ like the rcslock.pl program in the contrib directory of the CVS
+ sources.
+
+ - Do you want to execute the same exact thing before committing to
+ every file in the Repository? (This is useful if you want to program
+ the restrictions yourself.) If so, set up a single line in the
+ commitinfo:
+
+ DEFAULT /absolute/path/to/program
+
+ CVS executes the program once for each directory that "commit"
+ traverses, passing as arguments the directory and the files to be
+ committed within that directory.
+
+ Write your program accordingly. Some examples exist in the contrib
+ directory.
+
+ - Do you want a different kind of sanity check performed for different
+ directories? If so, you'll have to decide what to do for all
+ directories and enter lines like this:
+
+ regexp1 /absolute/path/to/program-for-regexp1
+ regexp2 /absolute/path/to/program-for-regexp2
+ DEFAULT /absolute/path/to/program-for-all-else
+
+ - Is there anything you want to happen before *all* commits, in
+ addition to other pattern matches? If so, include a line like this:
+
+ ALL /absolute/path/to/program
+
+ It is executed independently of all the above. And it's repeatable --
+ you can have as many ALL lines as you like.
+
+ Last modified: _6/13/1997_
+
+ 16. How do I use the "loginfo" files?
+
+ See 4B.2 and the "commitinfo" question above.
+
+ The "loginfo" file has the same format as the "commitinfo" file, but
+ its function is different. Where the "commitinfo" information is used
+ before a commit, the "loginfo" file is used after a commit.
+
+ All the commands in the "loginfo" file should read data from standard
+ input, then either append it to a file or send a message to a mailing
+ list. If you want to make it simple, you can put shell (the shell used
+ by "popen(3)") command lines directly in the "loginfo" (or
+ "commitinfo") file. These seem to work:
+
+ ^special /usr/ucb/Mail -s %s special-mailing-list ^other /usr/ucb/Mail
+ -s %s other-mailing-list DEFAULT (echo '===='; echo %s; cat) >
+ /path/name/to/log/file
+
+ Last modified: _6/13/1997_
+
+ 17. How can I keep people with restrictive umask values from blocking
+ access to the Repository?
+
+ If a user creates a new file with restricted permissions (e.g. 0600),
+ and commits it, the Repository will have a file in it that is
+ unreadable by everyone. The 0600 example would be unreadable by
+ *anyone* but root and the user who created it.
+
+ There are 3 solutions to this:
+
+ Let it happen. This is a valid way to protect things. If everyone is
+ working alone, a umask of 077 is OK. If everyone is working only in
+ small groups, a umask of 007 is OK.
+
+ Train your users not to create such things if you expect to share
+ them.
+
+ See 4B.5 for a small script that will reset the umask.
+
+ I personally don't like the idea of a program automatically
+ *loosening* security. It would be better for you all to talk about the
+ issue and decide how to work together.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/
+
+ " Commands "
+
+ Category: /Commands_/add_ad_new/
+
+ " + "add", "ad", "new""
+
+ 1. What is "add" for?
+
+ To add a new directory to the Repository or to register the desire to
+ add a new file to the Repository.
+
+ The directory is created immediately, while the desire to add the file
+ is recorded in the local ./CVS administrative directory. To really add
+ the file to the Repository, you must then "commit" it.
+
+ Last modified: _6/13/1997_
+
+ 2. How do I add a new file to the branch I'm working on?
+
+ The user actions for adding a file to any branch, including the Main
+ Branch, are exactly the same.
+
+ You are in a directory checked out (or updated) with the '-A' option
+ (to place you on the Main Branch) or the "-r <branch_tag>" option (to
+ place you on a branch tagged with <branch_tag>). To add <file> to the
+ branch you are on, you type:
+
+ cvs add <file>
+ cvs commit <file>
+
+ If no ./CVS/Tag file exists (the '-A' option deletes it), the file
+ will be added to the Main Branch. If a ./CVS/Tag file exists (the "-r
+ <branch_tag>" option creates it), the file will be added to the branch
+ named (i.e. tagged with) <branch_tag>.
+
+ Unless you took steps to first add the file to the Main Branch, your
+ new file ends up in the Attic.
+
+ Last modified: _6/13/1997_
+
+ 3. Why did my new file end up in the Attic?
+
+ The file is thrown into the Attic to keep it from being visible when
+ you check out the Main Branch, since it was never committed to the
+ Main Branch.
+
+ Last modified: _6/13/1997_
+
+ 4. Now that it's in the Attic, how do I connect it to the Main branch?
+
+ That can be considered a kind of "merge". See 4C.8
+
+ Last modified: _6/13/1997_
+
+ 5. How do I avoid the hassle of reconnecting an Attic-only file to the Main
+ Branch?
+
+ You create it on the Main Branch first, then branch it.
+
+ If you haven't yet added the file or if you decided to delete the new
+ Attic file and start over, then do the following: (If you added the
+ file (or worse, the 157 files) to the Attic and don't want to start
+ over, try the procedure in 4C.8.)
+
+ Temporarily remove the sticky branch information. Either:
+
+ Move the whole directory back to the Main Branch. [This might not be
+ a good idea if you have modified files, since it will require a merge
+ in each direction.]
+
+ cvs update -A
+
+ *or*
+
+ Move the ./CVS/Tag file out of the way.
+
+ mv ./CVS/Tag HOLD_Tag
+
+ Add and branch the file "normally":
+
+ cvs add <file>
+ cvs commit <file>
+ cvs tag -b <branch_tag> <file>
+
+ [<branch_tag> is the same Branch Tag as you used on all the other
+ files. Look at ./CVS/Entries or the output from "cvs stat" for sticky
+ tags.]
+
+ Clean up the temporary step.
+
+ If you moved the ./CVS/Tag file, put it back. Then move the new file
+ onto the branch where you are working.
+
+ mv HOLD_Tag ./CVS/Tag
+ cvs update -r <branch_tag> <file>
+
+ If you ran "update -A" rather than moving the ./CVS/Tag file, move
+ the whole directory (including the new file) back onto the branch
+ where you were working:
+
+ cvs update -r <branch_tag>
+
+ Last modified: _6/13/1997_
+
+ 6. How do I cancel an "add"?
+
+ If you want to remove the file entirely and cancel the "add" at the
+ same time, type:
+
+ cvs remove -f <file>
+
+ If you want to cancel the "add", but leave the file as it was before
+ you typed "cvs add", then you have to fake it:
+
+ mv <file> <file>.hold
+ cvs remove <file>
+ mv <file>.hold <file>
+
+ Last modified: _6/13/1997_
+
+ 7. What are the ./CVS/file,p and ./CVS/file,t files for?
+
+ The ./CVS/file,p and ./CVS/file,t files are created by the "add"
+ command to hold command line options and message text between the time
+ of the "add" command and the expected "commit".
+
+ The ./CVS/file,p file is always null, since its function was absorbed
+ by the "options" field in the ./CVS/Entries file. If you put something
+ in this file it will be used as arguments to the RCS "ci" command that
+ commit uses to check the file in, but CVS itself doesn't put anything
+ there.
+
+ The ./CVS/file,t file is null unless you specify an initial message in
+ an "add -m 'message'" command. The text is handed to "rcs -i
+ -t./CVS/file,t" to create the initial RCS file container.
+
+ Both files must exist to commit a newly added file. If the
+ ./CVS/file,p file doesn't exist, CVS prints an error and aborts the
+ commit. If the ./CVS/file,t file doesn't exist, RCS prints an error
+ and CVS gets confused, but does no harm.
+
+ To recover from missing ,p and ,t files, just create two zero-length
+ files and rerun the "commit".
+
+ Last modified: _6/13/1997_
+
+ 8. How do I "add" a binary file?
+
+ If you configured CVS to use the GNU version of "diff" and "diff3",
+ you only need to turn off RCS keyword expansion.
+
+ First you turn off RCS keyword expansion for the initial checkin by
+ using "add -ko". It works like "update -ko" in creating a "sticky"
+ option only for the copy of the file in the current working directory.
+
+ cvs add -ko <file>
+
+ Commit the file normally. The sticky -ko option will be used.
+
+ cvs commit <file>
+
+ Then mark the RCS file in the Repository so that keyword expansion is
+ turned off for all checked out versions of the file.
+
+ cvs admin -ko <file>
+
+ Since "admin -ko" records the keyword substitution value in the
+ Repository's RCS file, you no longer need the sticky option. You can
+ turn it off with the "update -A" command, but if you were on a branch,
+ you'll have to follow it "update -r <branch_tag>" to put yourself back
+ on the branch.
+
+ Managing that binary file is another problem. See 4D.1.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/admin_adm_rcs/
+
+ " + "admin", "adm", "rcs""
+
+ 1. What is "admin" for?
+
+ To provide direct access to the underlying "rcs" command (which is not
+ documented in this FAQ) bypassing all safeguards and CVS assumptions.
+
+ Last modified: _6/13/1997_
+
+ 2. Wow! Isn't that dangerous?
+
+ Yes.
+
+ Though you can't hurt the internal structure of an RCS file using its
+ own "rcs" command, you *can* change the underlying RCS files using
+ "admin" in ways that CVS can't handle.
+
+ If you feel the need to use "admin", create some test files with the
+ RCS "ci" command and experiment on them with "rcs" before blasting any
+ CVS files.
+
+ Last modified: _6/13/1997_
+
+ 3. What would I normally use "admin" for?
+
+ Normally, you wouldn't use admin at all. In unusual circumstances,
+ experts can use it to set up or restore the internal RCS state that
+ CVS requires.
+
+ You can use "admin -o" (for "outdate") to remove revisions you don't
+ care about. This has its own problems, such as leaving dangling Tags
+ and confusing the "update" command.
+
+ There is some feeling among manipulators of binary files that "admin
+ -l" should be used to serialize access. See 3C.8.
+
+ An interesting use for "admin" came up while maintaining CVS itself. I
+ import versions of CVS onto the Vendor branch of my copy of CVS, make
+ changes to some files and ship the diffs (created by "cvs diff -c -r
+ TO_BRIAN") off to Brian Berliner. After creating the diff, I retag
+ ("cvs tag -F TO_BRIAN") the working directory, which is then ready to
+ produce the next patch.
+
+ I'll use "add.c" as an example (only because the name is short).
+
+ When the next release came out, I discovered that the released "add.c"
+ (version 1.1.1.3 on the Vendor branch) was exactly the same as my
+ modified file (version 1.3). I didn't care about the changelog on
+ versions 1.2 and 1.3 (or the evidence of having done the work), so I
+ decided to revert the file to the state where it looked like I had not
+ touched the file -- where I was just using the latest on the vendor
+ branch after a sequence of imports.
+
+ To do that, I removed all the revisions on the main branch, except for
+ the original 1.1 from which the Vendor branch sprouts:
+
+ cvs admin -o1.2: add.c
+
+ Then I set the RCS "default branch" back to the Vendor branch, the way
+ import would have created it:
+
+ cvs admin -b1.1.1 add.c
+
+ And I moved the "TO_BRIAN" Tag to the latest revision on the Vendor
+ branch, since that is the base from which further patches would be
+ created (if I made any):
+
+ cvs admin -NTO_BRIAN:1.1.1.3 add.c
+
+ Instead of 1.1.1.3, I could have used one of the "Release Tags" last
+ applied by "import" (3rd through Nth arguments).
+
+ Suggestion: Practice on non-essential files.
+
+ Last modified: _6/13/1997_
+
+ 4. What should I avoid when using "admin"?
+
+ If you know exactly what you are doing, hack away. But under normal
+ circumstances:
+
+ Never use "admin" to alter branches (using the '-b' option), which CVS
+ takes very seriously. If you change the default branch, CVS will not
+ work as expected. If you create new branches without using the "tag
+ -b" command, you may not be able to treat them as CVS branches.
+
+ See 3C.8 for a short discussion of how to use "admin -l" for
+ serializing access to binary files.
+
+ The "admin -o <file>" allows you to delete revisions, usually a bad
+ idea. You should commit a correction rather than back out a revision.
+ Outdating a revision is prone to all sorts of problems:
+
+ Discarding data is always a bad idea. Unless something in the
+ revision you just committed is a threat to your job or your life,
+ (like naming a function "<boss's name>_is_a_dweeb", or including the
+ combination to the local Mafioso's safe in a C comment), just leave it
+ there. No one cares about simple mistakes -- just commit a corrected
+ revision.
+
+ The time travel paradoxes you can cause by changing history are not
+ worth the trouble. Even if CVS can't interfere with your parents'
+ introduction, it *can* log commits in at least two ways (history and
+ loginfo). The reports now lie -- the revision referred to in the logs
+ no longer exists.
+
+ If you used "import" to place <file> into CVS, outdating all the
+ revisions on the Main branch back to and including revision 1.2 (or
+ worse, 1.1), will produce an invalid CVS file.
+
+ If the <file>,v file only contains revision 1.1 (and the connected
+ branch revision 1.1.1.1), then the default branch must be set to the
+ Vendor branch as it was when you first imported the file. Outdating
+ back through 1.2 doesn't restore the branch setting. Despite the above
+ admonition against it, "admin -b" is the only way to recover:
+
+ cvs admin -b1.1.1 <file>
+
+ Although you can't outdate a physical (RCS) branch point without
+ removing the whole branch, you *can* outdate a revision referred to by
+ a magic branch tag. If you do so, you will invalidate the branch.
+
+ If you "outdate" a tagged revision, you will invalidate all uses of
+ the <tag>, not just the one on <file>. A tag is supposed to be
+ attached to a consistent set of files, usually a set built as a unit.
+ By discarding one of the files in the set, you have destroyed the
+ utility of the <tag>. And it leaves a dangling tag, which points to
+ nothing.
+
+ And even worse, if you commit a revision already tagged, you will
+ alter what the <tag> pointed to without using the "tag" command. For
+ example, if revision 1.3 has <tag> attached to it and you "outdate"
+ the 1.3 revision, <tag> will point to a nonexistent revision. Although
+ this is annoying, it is nowhere near as much trouble as the problem
+ that will occur when you commit to this file again, recreating
+ revision 1.3. The old tag will point to the new revision, a file that
+ was not in existence when the <tag> was applied. And the discrepancy
+ is nearly undetectable.
+
+ If you don't understand the above, you should not use the admin
+ command at all.
+
+ Last modified: _6/13/1997_
+
+ 5. How do I restrict the "admin" command? The -i flag in the modules file
+ can restrict commits. What's the equivalent for "admin"?
+
+ At this writing, to disable the "admin" command, you will have to
+ change the program source code, recompile and reinstall.
+
+ Last modified: _6/13/1997_
+
+ 6. I backed out a revision with "admin -o" and committed a replacement. Why
+ doesn't "update" retrieve the new revision?
+
+ CVS is confused because the revision in the ./CVS/Entries file matches
+ the latest revision in the Repository *and* the timestamp in the
+ ./CVS/Entries file matches your working file. CVS believes that your
+ file is "up-to-date" and doesn't need to be updated.
+
+ You can cause CVS to notice the change by "touch"ing the file.
+ Unfortunately what CVS will tell you is that you have a "Modified"
+ file. If you then "commit" the file, you will bypass the normal CVS
+ check for "up-to-date" and will probably commit the revision that was
+ originally removed by "admin -o".
+
+ Changing a file without changing the revision number confuses CVS no
+ matter whether you did it by replacing the revision (using "admin -o"
+ and "commit" or raw RCS commands) or by applying an editor directly to
+ a Repository (",v") file. Don't do it unless you are absolutely
+ certain no one has the latest revision of the file checked out.
+
+ The best solution to this is to institute a program of deterrent
+ flogging of abusers of "admin -o".
+
+ The "admin" command has other problems." See 3B.4 above.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/checkout_co_get/
+
+ " + "checkout", "co", "get""
+
+ 1. What is "checkout" for?
+
+ To acquire a copy of a module (or set of files) to work on.
+
+ All work on files controlled by CVS starts with a "checkout".
+
+ Last modified: _6/13/1997_
+
+ 2. What is the "module" that "checkout" takes on the command line?
+
+ It is a name for a directory or a collection of files in the
+ Repository. It provides a compact name space and the ability to
+ execute before and after helper functions based on definitions in the
+ modules file.
+
+ See 1D.11.
+
+ Last modified: _6/13/1997_
+
+ 3. Isn't a CVS "checkout" just a bunch of RCS checkouts?
+
+ Like much of CVS, a similar RCS concept is used to support a CVS
+ function. But a CVS checkout is *not* the same as an RCS checkout.
+
+ Differences include:
+
+ CVS does not lock the files. Others may access them at the same
+ time.
+
+ CVS works best when you provide a name for a collection of files (a
+ module or a directory) rather than an explicit list of files to work
+ on.
+
+ CVS remembers what revisions you checked out and what branch you are
+ on, simplifying later commands.
+
+ Last modified: _6/13/1997_
+
+ 4. What's the difference between "update" and "checkout"?
+
+ The "checkout" and "update" commands are nearly equivalent in how they
+ treat individual files. They differ in the following ways:
+
+ The "checkout" command always creates a directory, moves into it,
+ then becomes equivalent to "update -d".
+
+ The "update" command does not create directories unless you add the
+ '-d' option.
+
+ "Update" is intended to be executed within a working directory
+ created by "checkout". It doesn't take a module or directory argument,
+ but figures out what Repository files to look at by reading the files
+ in the ./CVS administrative directory.
+
+ The two commands generate completely different types of records in
+ the "history" file.
+
+ Last modified: _6/13/1997_
+
+ 5. Why can't I check out a file from within my working directory?
+
+ Though you *can* check out a file, you normally check out a module or
+ directory. And you normally do it only once at the beginning of a
+ project.
+
+ After the initial "checkout", you can use the "update" command to
+ retrieve any file you want within the checked-out directory. There is
+ no need for further "checkout" commands.
+
+ If you want to retrieve another module or directory to work on, you
+ must provide two pathnames: where to find it in the Repository and
+ where to put it on disk. The "modules" file and your current directory
+ supply two pieces of naming information. While inside a checked-out
+ working directory, the CVS administrative information provides most of
+ the rest.
+
+ You should be careful not to confuse CVS with RCS and use "checkout"
+ in the RCS sense. An RCS "checkout" (which is performed by the RCS
+ "co" command) is closer to a "cvs update" than to a "cvs checkout".
+
+ Last modified: _6/13/1997_
+
+ 6. How do I avoid dealing with those long relative pathnames?
+
+ This question has also been phrased:
+
+ How do I avoid all those layers of directories on checkout? or Why do
+ I have to go to the top of my working directory and checkout some long
+ pathname to get a file or two?
+
+ This type of question occurs only among groups of people who decide
+ not to use "modules". The answer is to use "modules".
+
+ When you hand the "checkout" command a relative pathname rather than a
+ module name, all directories in the path are created, maintaining the
+ same directory hierarchy as in the Repository. The same kind of
+ environment results if you specify a "module" that is really an alias
+ expanding into a list of relative pathnames rather than a list of
+ module names.
+
+ If you use "module" names, "checkout" creates a single directory by
+ the name of the module in your current directory. This "module"
+ directory becomes your working directory.
+
+ The "module" concept combines the ability to "name" a collection of
+ files with the ability to structure the Repository so that consistent
+ sets of files are checked out together. It is the responsibility of
+ the Repository Administrators to set up a modules file that describes
+ the software within the Repository.
+
+ Last modified: _6/13/1997_
+
+ 7. Can I move a checked-out directory? Does CVS remember where it was
+ checked out?
+
+ Yes and Yes.
+
+ The ./CVS/Repository file in each working directory contains a
+ pathname pointing to the matching directory within the Repository. The
+ pathname is either absolute or relative to $CVSROOT, depending on how
+ you configured CVS.
+
+ When you move a checked-out directory, the CVS administrative files
+ will move along with it. As long as you don't move the Repository
+ itself, or alter your $CVSROOT variable, the moved directory will
+ continue to be usable.
+
+ CVS remembers where you checked out the directory in the "history"
+ file, which can be edited, or even ignored if you don't use the
+ "working directory" information displayed by the "history" command.
+
+ Last modified: _6/13/1997_
+
+ 8. How can I lock files while I'm working on them the way RCS does?
+
+ Until the day arrives of the all-powerful merge tool, there are still
+ files that must be accessed serially. For those instances, here's a
+ potential solution:
+
+ Install a pre-commit program in the "commitinfo" file to check for
+ RCS locks. The program "rcslock.pl" performs this function. It can be
+ found in the contrib directory of the CVS source distribution.
+
+ When you want to make a change to a file you know can't be merged,
+ first use "cvs admin -l" to lock the file. If you can't acquire the
+ lock, use the standard "locked out" protocol: go talk to the person
+ holding the lock.
+
+ Make sure the pre-commit program prints a message and exits with a
+ non-zero status if someone besides the user running "commit" has the
+ file locked. This non-zero exist status will cause the "commit" to
+ fail cleanly.
+
+ Make sure the pre-commit program exits with a zero status if the
+ file is either unlocked or locked by the user running "commit". The
+ "cvs commit" command that kicked off the pre-commit program will take
+ a zero exist status as an OK and checkin the file, which has the
+ side-effect of unlocking it.
+
+ ===> The following is opinion and context. Don't read it if you are
+ looking for a quick fix.
+
+ The topic of locking CVS files resurfaces on the network every so
+ often, producing the same results each time:
+
+ The Big Endians:
+
+ CVS was designed to avoid locks, using a copy-modify-merge model.
+ Locking is not necessary and you should take the time to learn the CVS
+ model which many people find workable. So why not get with the program
+ and learn how to think the CVS way?
+
+ The Little Endians:
+
+ The users determine how a tool is to be used, not the designers. We,
+ the users, have always used locking, our bosses demand locking,
+ locking is good, locking is God. I don't want to hear any more
+ lectures on the CVS model. Make locking work.
+
+ Any organization making active changes to a source base will
+ eventually face the need to do parallel development. Parallel
+ development implies merges. (If you plan to keep separate copies of
+ everything and never merge, good luck. Tell me who you work for so I
+ can buy stock in your disk suppliers this year and sell your stock
+ short next year.)
+
+ Merges will never go away. CVS chose to make "merges" stand front and
+ center as an important, common occurrence in development. It is one
+ way of looking at things.
+
+ For free-format text, the merge paradigm gives you a considerable
+ amount of freedom. It does take a bit of management, but any project
+ should be ready to deal with it.
+
+ On the other hand, there are many files that can't be merged using
+ text merge techniques. Straight text merge programs like "diff3" are
+ guaranteed to fail on executables (with relative branch statements),
+ files with self-referential counts stored in the file (such as TAGS
+ files), or files with relative motion statements in them (such as
+ Frame MIF files, many postscript files). They aren't all binary files.
+
+ For these types of files, and many others, there are only two
+ solutions:
+
+ Complex merge tools that are intimately aware of the contents of the
+ files to be merged. (ClearCase, and probably others, allow you to
+ define your own "files types" with associated "merge tools".)
+
+ Serialization of access to the file. The only technical solution to
+ the problem of serialization is "locking".
+
+ Since you can call a program that offers:
+
+ "Which one do you want? A/B?"
+
+ a "merge tool", more and more merge tools will appear which can be
+ hooked into a merge-intensive program like CVS. Think of a bitmap
+ "merge" tool that displays the bitmaps on the screen and offers a
+ "paint" interface to allow you to cut and paste, overlay, invert or
+ fuse the two images such that the result is a "merged" file.
+
+ My conclusion is that the need for locking is temporary, awaiting
+ better technology. For large development groups, locking is not an
+ alternative to merging for text files.
+
+ Last modified: _6/13/1997_
+
+ 9. What is "checkout -s"? How is it different from "checkout -c"?
+
+ The '-c' and '-s' options to "checkout" both cause the modules file to
+ appear on standard output, but formatted differently.
+
+ "checkout -c" lists the modules file alphabetized by the module name.
+ It also prints all data (including options like '-a' and "-o <prog>")
+ specified in the modules file.
+
+ "checkout -s" lists the modules file sorted by "status" field, then by
+ module name. The status field was intended to allow you to mark
+ modules with strings of your choice to get a quick sorted report based
+ on the data you chose to put in the status fields. I have used it for
+ priority ("Showstopper", etc as tied into a bug database), for porting
+ status ("Ported", "Compiled", etc. when porting a large collection of
+ modules), for "assignee" (the person responsible for maintenance), and
+ for "test suite" (which automatic test procedure to run for a
+ particular module).
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/commit_ci_com/
+
+ " + "commit", "ci", "com""
+
+ 1. What is "commit" for?
+
+ To store new revisions in the Repository, making them visible to other
+ users.
+
+ Last modified: _6/13/1997_
+
+ 2. If I edit ten files, do I have to type "commit" ten times?
+
+ No. The "commit" command will take multiple filenames, directory names
+ and relative pathnames on the command line and commit them all with
+ the same log message. If a file is unchanged, even if it is explicitly
+ listed on the command line, CVS will skip it.
+
+ Like all CVS commands, "commit" will work on the whole directory by
+ default. Just type "cvs commit" to tell CVS to commit all modified
+ files (i.e. the files that "update" would display preceded by 'M') in
+ the current directory and in all sub-directories.
+
+ Last modified: _6/13/1997_
+
+ 3. Explain: cvs commit: Up-to-date check failed for `<file>'
+
+ You may not "commit" a file if your BASE revision (i.e. the revision
+ you last checked out, committed or retrieved via "update") doesn't
+ match the HEAD revision (i.e the latest revision on your branch,
+ usually the Main Branch).
+
+ In other words, someone committed a revision since you last executed
+ "checkout", "update" or "commit". You must now execute "update" to
+ merge the other person's changes into your working file before
+ "commit" will work. You are thus protected (somewhat) from a common
+ form of race condition in source control systems, where a checkin of a
+ minor alteration of a second copy of the same base file obliterates
+ the changes made in the first.
+
+ Normally, the "update" command's auto-merge should be followed by
+ another round of building and testing before the "commit".
+
+ Last modified: _6/13/1997_
+
+ 4. What happens if two people try to "commit" conflicting changes?
+
+ Conflicts can occur only when two developers check out the same
+ revision of the same file and make changes. The first developer to
+ commit the file has no chance of seeing the conflict. Only the second
+ developer runs into it, usually when faced with the "Up-to-date" error
+ explained in the previous question.
+
+ There are two types of conflicts:
+
+ When two developers make changes to the same section of code, the
+ auto-merge caused by "update" will print a 'C' on your terminal and
+ leave "overlap" markers in the file.
+
+ You are expected to examine and clean them up before committing the
+ file. (That may be obvious to *some* of you, but . . .)
+
+ A more difficult problem arises when two developers change different
+ sections of code, but make calls to, or somehow depend on, the old
+ version of each other's code.
+
+ The auto-merge does the "right" thing, if you view the file as a
+ series of text lines. But as a program, the two developers have
+ created a problem for themselves.
+
+ This is no different from making cross-referential changes in
+ *separate* files. CVS can't help you. In a perfect world, you would
+ each refer to the specification and resolve it independently. In the
+ real world you have to talk/argue, read code, test and debug until the
+ combined changes work again.
+
+ Welcome to the world of parallel development.
+
+ Last modified: _6/13/1997_
+
+ 5. I committed something and I don't like it. How do I remove it?
+
+ Though you *can* use the "admin -o" (synonym: "rcs -o") command to
+ delete revisions, unless the file you committed is so embarrassing
+ that the need to eradicate it overrides the need to be careful, you
+ should just grab an old version of the file ("update -p -r
+ <previous-rev>" might help here) and commit it on top of the offending
+ revision.
+
+ See Section 3B on "admin".
+
+ Last modified: _6/13/1997_
+
+ 6. Explain: cvs commit: sticky tag `V3' for file `X' is not a branch
+
+ The message implies two things:
+
+ You created your working directory by using "checkout -r V3", or you
+ recently executed "update -r V3".
+
+ The tag named V3 is not a branch tag.
+
+ CVS records (i.e. makes "sticky") any "-r <tag/rev>" argument handed
+ to the "checkout" or "update" commands. The <tag/rev> is recorded as
+ the CVS working branch, which is the branch to which "commit" will add
+ a new revision.
+
+ Branch tags are created when you use the -b switch on the "tag" or
+ "rtag" commands. Branch tags are magic tags that don't create a
+ physical branch, but merely mark the revision to branch from when the
+ branch is needed. The first commit to a magic branch creates a
+ physical branch in the RCS files.
+
+ You can commit onto the end of the Main Trunk, if you have no sticky
+ tag at all, or onto the end of a branch, if you have a sticky branch
+ tag. But you can't commit a file that has a sticky tag not pointing to
+ a branch. CVS assumes a sticky Tag or Revision that does not refer to
+ a branch is attached to the middle of a series of revisions. You can't
+ squeeze a new revision between two others. Sticky dates also block
+ commits since they never refer to a branch.
+
+ Scenario1:
+
+ If you don't want a branch and were just looking at an old revision,
+ then you can move back to the Main Branch by typing:
+
+ cvs update -A {files or dirs, default is '.'}
+
+ or you can move to the branch named <branch_tag> by:
+
+ cvs update -r <branch_tag> {files or dirs, default is '.'}
+
+ Scenario2:
+
+ If you really wanted to be on a branch and made an earlier mistake by
+ tagging your branch point with a non-branch tag, you can recover by
+ adding a new branch tag to the old non-branch tag:
+
+ cvs rtag -b -r <oldtag> <newtag> <module>
+
+ (It was not a big mistake. Branch-point tags can be useful. But the
+ <newtag> must have a different name.)
+
+ If you don't know the <module> name or don't use "modules", you can
+ also use "tag" this way:
+
+ cvs update -r <oldtag>
+ cvs tag -b <newtag> .
+
+ Then, to put your working directory onto the branch, you type:
+
+ cvs update -r <newtag>
+
+ You can't delete <oldtag> before adding <newtag>, and I would not
+ advise deleting the <oldtag> at all, because it is useful in referring
+ to the branch point. If you must, you can delete the non-branch tag
+ by:
+
+ cvs rtag -d <oldtag> <module>
+ or
+ cvs tag -d <oldtag> .
+
+ Scenario3:
+
+ If you made the same mistake as in Scenario2 (of placing a non-branch
+ tag where you wanted a branch tag), but really want <oldtag> to be the
+ name of your branch, you can execute a slightly different series of
+ commands to rename it and move your working directory onto the branch.
+
+ Warning: This is not a way to rename a branch tag. It is a way to turn
+ a non-branch tag into a branch tag with the same name.
+
+ cvs rtag -r <oldtag> <branch_point_tag> <module>
+ cvs rtag -d <oldtag> <module>
+ cvs rtag -b -r <branch_point_tag> <oldtag> <module>
+
+ Then, if you really must, delete the <branch_point_tag>:
+
+ cvs rtag -d <branch_point_tag> <module>
+
+ Note: The unwieldy mixture of "tag" and "rtag" is mostly because you
+ can't specify a revision (-r <tag>) to the "tag" command.
+
+ See 4C.3 for more info on creating a branch.
+
+ Last modified: _6/13/1997_
+
+ 7. Why does "commit -r <tag/rev>" put newly added files in the Attic?
+
+ If you specify "-r <rev>" (where <rev> is a dotted numeric number like
+ 2.4), it correctly sets the initial revision to <rev>, but it also
+ attaches the numeric <rev> as a sticky tag and throws the file into
+ the Attic. This is a bug. The obvious solution is to move the file out
+ of the Attic into the associated Repository directory and "update -A"
+ the file. There are no Tags to clean up.
+
+ If you specify "-r <tag>" to commit a newly added file, the <tag> is
+ treated like a <branch_tag>, which becomes a symbolic RCS label
+ pointing to the string '1', which can be considered to be the "Main
+ branch number" when the main branch is still at revision 1.N. The file
+ is also thrown into the Attic. See 4C.8 for a way to recover from
+ this.
+
+ In fact, a plain "commit" without the "-r" will throw a newly added
+ file into the Attic if you added it to a directory checked out on a
+ branch. See 3A.[2-5].
+
+ See Section 4C, on Branching, for many more details.
+
+ Last modified: _6/13/1997_
+
+ 8. Why would a "commit" of a newly added file not produce rev 1.1?
+
+ When committing a newly added file CVS looks for the highest main
+ branch major number in all files in the ./CVS/Entries file. Normally
+ it is '1', but if you have a file of revision 3.27 in your directory,
+ CVS will find the '3' and create revision 3.1 for the first rev of
+ <file>. Normally, the first revision is 1.1.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/diff_di_dif/
+
+ " + "diff", "di", "dif""
+
+ 1. What is "diff" for?
+
+ To display the difference between a working file and its BASE
+ revision (the revision last checked out, updated or committed):
+
+ cvs diff <file>
+
+ To display the difference between a working file and a committed
+ revision of the same file:
+
+ cvs diff -r <tag/rev> <file>
+
+ To display the difference between two committed revisions of the
+ same file:
+
+ cvs diff -r <tag1/rev1> -r <tag2/rev2> <file>
+
+ You can specify any number of <file> arguments. Without any <file>
+ arguments, it compares the whole directory.
+
+ In the examples above, "-D <date>" may be substituted wherever "-r
+ <tag/rev>" appears. The revision a <date> refers to is the revision
+ that existed on that date.
+
+ Last modified: _6/13/1997_
+
+ 2. Why did "diff" display nothing when I know there are later committed
+ revisions in the Repository?
+
+ By default, "diff" displays the difference between your working file
+ and the BASE revision. If you haven't made any changes to the file
+ since your last "checkout", "update" or "commit" there is no
+ difference to display.
+
+ To display the difference between your working file and the latest
+ revision committed to your current branch, type:
+
+ cvs diff -r HEAD <file>
+
+ Last modified: _6/13/1997_
+
+ 3. How do I display what changed in the Repository since I last executed
+ "checkout", "update" or "commit"?
+
+ A special tag (interpreted by CVS -- it does not appear in the Tag
+ list) named "BASE" always refers to the revision you last checked out,
+ updated or committed. Another special tag named "HEAD" always refers
+ to the latest revision on your working branch.
+
+ To compare BASE and HEAD, you type:
+
+ cvs diff -r BASE -r HEAD <file>
+
+ Last modified: _6/13/1997_
+
+ 4. How do I display the difference between my working file and what I
+ checked in last Thursday?
+
+ cvs diff -D "last Thursday" <file>
+
+ where "last Thursday" is a date string. To be more precise, the
+ argument to the '-D' option is a timestamp. Many formats are accepted.
+ See the man page under "-D date_spec" for details.
+
+ Last modified: _6/13/1997_
+
+ 5. Why can't I pass long options, like --unified, to "diff"?
+
+ CVS only handles single character '-X' arguments, not the FSF long
+ options. CVS also passes through only arguments it knows about,
+ because a few arguments are captured and interpreted by CVS.
+
+ If you didn't configure RCS and CVS to use the GNU version of diff,
+ long options wouldn't work even if future versions of CVS acquire the
+ ability to pass them through.
+
+ Most of the long options have equivalent single-character options,
+ which do work. The "--unified" option is equivalent to '-u' in
+ revisions of GNU diff since 1.15.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/export_exp_ex/
+
+ " + "export", "exp", "ex""
+
+ 1. What is "export" for?
+
+ "export" checks out a copy of a module in a form intended for export
+ outside the CVS environment. The "export" command produces the same
+ directory and file structure as the "checkout" command, but it doesn't
+ create "CVS" sub-directories and it removes all the RCS keywords from
+ the files.
+
+ Last modified: _6/13/1997_
+
+ 2. Why does it remove the RCS keywords so I can't use the "ident" command
+ on the source files?
+
+ It removes the RCS keywords, so that if the recipient of the exported
+ sources checks them into another set of RCS files (with or without
+ CVS), and then makes modifications through RCS or CVS commands, the
+ revision numbers that they had when you exported them will be
+ preserved. (That ident no longer works is just an unfortunate side
+ effect.)
+
+ The theory is that you are exporting the sources to someone else who
+ will make independent changes, and at some point you or they will want
+ to know what revisions from your Repository they started with
+ (probably to merge changes, or to try to decide whether to merge
+ changes).
+
+ A better way to handle this situation would be to give them their own
+ branch of your Repository. They would need to remember to checkin the
+ exported sources with RCS IDs intact (ci -k) so that their changes
+ would get revision numbers from the branch, rather than starting at
+ 1.1 again. Perhaps a future version of CVS will provide a way to
+ export sources this way.
+
+ Contributed by Dan Franklin
+
+ Last modified: _6/13/1997_
+
+ 3. Can I override the '-kv' flag CVS passes to RCS?
+
+ Not as of CVS version 1.4.
+
+ Last modified: _6/13/1997_
+
+ 4. Why doesn't "export" have a '-k' flag like "import" does?
+
+ Export is intended for a specific purpose -- to remove all trace of
+ revision control on the way *out* of CVS.
+
+ Last modified: _6/13/1997_
+
+ 5. Why does "export -D" check out every file in the Attic?
+
+ See 5B.3 for an explanation of the same problem with "update".
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/history_hi_his/
+
+ " + "history", "hi", "his""
+
+ 1. What is "history" for?
+
+ To provide information difficult or impossible to extract out of the
+ RCS files, such as a "tag" history or a summary of module activities.
+
+ Last modified: _6/13/1997_
+
+ 2. Of what use is it?
+
+ I have found it useful in a number of ways, including:
+
+ Providing a list of files changed since
+
+ - A tagged release.
+ - Yesterday, last Thursday, or a specific date.
+ - Someone changed a specific file.
+
+ Providing a list of special events:
+
+ - Files added or removed since one of the above events.
+ - Merge failures since one of the above events. (Where did the
+ conflicts occur?)
+ - Has anyone (and who) grabbed the revision of this file I committed
+ last week, or are they still working blind?
+
+ Telling me how often a file/directory/module has been changed.
+
+ Dumping a summary of work done on a particular module, including who
+ last worked on it and what changed.
+
+ Displaying the checked-out modules and where they are being worked
+ on.
+
+ To tell me what users "joe" and "malcolm" have done this week.
+
+ Last modified: _6/13/1997_
+
+ 3. What is this, Big Brother?
+
+ War is Peace.
+ Freedom is Slavery.
+ Ignorance is Strength.
+
+ Normally manager types and those with the power to play Big Brother
+ don't care about this information. The Software Engineer responsible
+ for integration usually wants to know who is working on what and what
+ changed. Use your imagination.
+
+ Last modified: _6/13/1997_
+
+ 4. I deleted my working directory and "history" still says I have it
+ checked out. How do I fix it?
+
+ You can use "release -f" to forcibly add a "release" record to the
+ history file for a working directory associated with a "module". If
+ your version of "release" doesn't have the '-f' option, or you checked
+ out the directory using a relative path, you have to edit the
+ $CVSROOT/CVSROOT/history file.
+
+ You can remove the last 'O' line in the history file referring to the
+ module in question or add an 'F' record.
+
+ Last modified: _6/13/1997_
+
+ 5. So I *can* edit the History file?
+
+ Yes, but if you are using history at all, you should take a little
+ care not to lose information. I normally use Emacs on the file, since
+ it can detect that a file has changed out from under it. You could
+ also copy and zero out the history file, edit the copy and append any
+ new records to the edited copy before replacing it.
+
+ Last modified: _6/13/1997_
+
+ 6. Why does the history file grow so quickly?
+
+ It stores 'U' records, which come in handy sometimes when you are
+ tracking whether people have updated each other's code before testing.
+ There should (and probably will sometime) be a way to choose what
+ kinds of events go into the history file.
+
+ The contributed "cln_hist.pl" script will remove all the 'U' records,
+ plus matching pairs of 'O' and 'F' records during your normal clean up
+ of the history file.
+
+ Last modified: _6/13/1997_
+
+ 7. What is the difference between "cvs history -r <tag/rev>" and "cvs
+ history -t <tag>"?
+
+ The '-t' option looks for a Tag record stored by "rtag" in the history
+ file and limits the search to dates after the last <tag> of the given
+ name was added.
+
+ The '-r' option was intended to search all files looking for the <tag>
+ in the RCS files. It takes forever and needs to be rewritten.
+
+ Last modified: _6/13/1997_
+
+ 8. Why does "cvs history -c -t <tag>" fail to print anything?
+
+ You have been using "tag" instead of "rtag". The "tag" command
+ currently doesn't store a history record. This is another remnant of
+ CVS's earlier firm belief in "modules". But it also has a basis in how
+ "rtag" and "tag" were originally used.
+
+ "rtag" was intended for large-scale tagging of large chunks of the
+ Repository, an event work recording. "tag" was intended for adding and
+ updating tags on a few files or directories, though it could also be
+ used to tag the entire checked-out working tree when there is no
+ module defined to match the tree or when the working tree is the only
+ place where the right collection of revisions to tag can be found.
+
+ Last modified: _6/13/1997_
+
+ 9. "cvs history -a -o" only printed one line for each checked-out module.
+ Shouldn't it print all the directories where the modules are checked out?
+
+ Not as designed.
+
+ Command Question it is supposed to answer.
+ ---------------- ------------------------------------------
+ cvs history -o What modules do I have checked out?
+ cvs history -a -o <same for all users>
+
+ cvs history -o -w What working directories have I created
+ and what modules are in them?
+ cvs history -a -o -w <same for every user>
+
+ The -o option chooses the "checked out modules" report, which is the
+ default history report.
+
+ Last modified: _6/13/1997_
+
+ 10. I can't figure out "history", can you give me concrete examples?
+
+ Default output selects records only for the user who executes the
+ "history" command. To see records for other users, add one or more "-u
+ user" options or the '-a' option to select *all* users.
+
+ To list (for the selected users): Type "cvs history" and:
+
+ * Checked out modules: -o (the default)
+ * Files added since creation: -x A
+ * Modified files since creation: -c
+ * Modified files since last Friday: -c -D 'last Friday'
+ * Modified files since TAG was added: -c -t <tag>
+ * Modified files since TAG on files: -c -r <tag>
+ * Last modifier of file/Repository X? -c -l -[fp] X
+ * Modified files since string "str": -c -b str
+ * Tag history: (Actually "rtag".) -T
+ * History of file/Repository/module X: -[fpn] X
+ * Module report on "module": -m module
+
+ Last modified: _6/13/1997_
+
+ 11. Can we merge history files when we merge Repositories?
+
+ Assuming that the two Repositories have different sets of pathnames,
+ it should be possible to merge two history files by sorting them
+ together by the timestamp fields.
+
+ You should be able to run:
+
+ sort -k 1.2 ${dir1}/history ${dir2}/history > history
+
+ If you "diff" a standard history file before and after such a sort,
+ you might see other differences caused by garbage (split lines, nulls,
+ etc) in the file. If your Repository is mounted through NFS onto
+ multiple machines you will also see a few differences caused by
+ different clocks on different machines. (Especially if you don't use
+ NTP to keep the clocks in sync.)
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/import_im_imp/
+
+ " + "import", "im", "imp""
+
+ 1. What is "import" for?
+
+ The "import" command is a fast way to insert a whole tree of files
+ into CVS.
+
+ The first "import" to a particular file within the Repository creates
+ an RCS file with a single revision on the "Vendor branch." Subsequent
+ "import"s of the same file within the Repository append a new revision
+ onto the Vendor branch. It does not, as some seem to believe, create a
+ new branch for each "import". All "imports" are appended to the single
+ Vendor branch.
+
+ If the file hasn't changed, no new revision is created -- the new
+ "Release-Tag" is added to the previous revision.
+
+ After the import is finished, files you have not changed locally are
+ considered to have changed in the "Main line of development". Files
+ you *have* changed locally must have the new Vendor code merged into
+ them before they are visible on the "Main line".
+
+ See 4C.6 and 4C.15
+
+ Last modified: _6/13/1997_
+
+ 2. How am I supposed to use "import"?
+
+ Create a source directory containing only the files you want to
+ import. Make sure you clean up any cruft left over from previous
+ builds or editing. You want to make sure that the directory contains
+ only what you want to call "source" from which everything else is
+ built.
+
+ If this is not the first import from this "Vendor", you should also
+ compare the output of "find . ! -name CVS -print | sort" executed both
+ at the head of a checked out working directory and at the head of the
+ sources to be imported. If you find any deleted or renamed files, you
+ have to deal with them by hand. (See 4B.8 on renaming.)
+
+ "cd" into your source directory and type:
+
+ cvs import -m "Message" <repos> <Vendor-Tag> <Release-Tag>
+
+ where <repos> is the relative directory pathname within the Repository
+ that corresponds to the sources you are importing.
+
+ You might also consider using the "-I !" option to avoid ignoring
+ anything. It is easier to remove bogus files from the Repository than
+ to create a sparse tree of the ignored files and rerun "import".
+
+ For example, if the FSF, CVS, Make and I are still active in the year
+ 2015, I'll import version 89.53 of GNU make this way:
+
+ cvs import -m "GNUmake V89.53" gnu/make GNU GNUMAKE_89_53
+
+ See 3H.13 for more details.
+
+ Last modified: _6/13/1997_
+
+ 3. Why does import put files on a branch? Why can't I work on the main
+ trunk instead of a Vendor branch?
+
+ This was a Design choice. The Vendor branch is the way "import" deals
+ with a Vendor release. It is a solution to the Engineering problem of
+ how to merge multiple external releases of Vendor-supplied sources
+ into your ongoing work. The Vendor releases are kept on a separate,
+ special, "Vendor" branch and your work is kept on the RCS trunk. New
+ Vendor releases are imported onto the Vendor branch and then merged
+ into your work, if there is any, on the trunk.
+
+ This way, you can use CVS to find out not only about your work, but
+ you can also find out what the Vendor changed by diffing between two
+ of the Release Tags you handed to "import".
+
+ CVS was designed to work this way. If you use CVS in some other way,
+ you should think carefully about what you are doing.
+
+ Note that the CVS "Main Branch" and the RCS Main Trunk are not the
+ same. Placing files on the Vendor Branch doesn't keep you from
+ creating a development branch to work on.
+
+ See Section 4C, on Branching.
+
+ If you are not working with 3rd party (i.e. Vendor) sources, you can
+ skip the "import" and avoid the Vendor branch entirely. It works just
+ as well to move pre-existing RCS files into Repository directories.
+
+ You can create a whole Repository tree by copying a directory
+ hierarchy of normal source files directly into the Repository and
+ applying CVS to it. Here's an idea you should *test* before using:
+
+ cd <your source tree>
+ set source = `pwd`
+ set module = xyzzy <<== Your choice of directory name
+ mkdir $CVSROOT/$module
+ cd $CVSROOT/$module
+ (cd $source; tar cf - .) | tar xvpBf -
+ find . -type f -exec ci -t-Original. {} \;
+
+ The RCS "ci" command, without -u or -l options, will turn your source
+ file into an RCS (",v") and delete the original source.
+
+ Last modified: _6/13/1997_
+
+ 4. Is there any way to import binary files?
+
+ If you configured CVS to use the GNU version of "diff" and "diff3",
+ then you can import any kind of file.
+
+ Binary files with RCS keywords in them are a problem, since you don't
+ want them to expand.
+
+ If the tree you are about to "import" is entirely filled with binary
+ files, you can use the '-ko' option on "import". Otherwise, I would
+ run the import normally, then fix the binary files as described below
+ in 3H.5.
+
+ See 4D.1 on Binary files.
+
+ Last modified: _6/13/1997_
+
+ 5. Why does "import" corrupt some binary files?
+
+ The RCS "co" command, when it is invoked by a CVS "checkout" or
+ "update" (or after a "commit") command, searches for and expands a
+ list of keywords within the file. They are documented in the RCS "co"
+ man page. Strings such as "$\Id$" (or "$\Id:"), or "$\Revision$" (or
+ "$\Revision:") are altered to the include the indicated information.
+
+ [[Note: The keywords should appear in the text without the '\'
+ character I have inserted to *avoid* expansion here. The only real RCS
+ keywords in this document are at the top of the file, where I store
+ the Revision and Date.]]
+
+ If RCS keyword strings show up in a binary file, they will be altered
+ unless you set the '-ko' option on the RCS files to tell RCS to keep
+ the original keyword values and not to expand new ones. After
+ "import", you can set the '-ko' option this way:
+
+ cvs admin -ko <file>
+ rm <file>
+ cvs update <file>
+
+ After an import that didn't use '-ko' (because the whole tree wasn't
+ of binary files) you should fix up the binary files as described above
+ before checking out any new copies of the files and before updating
+ any working directories you checked out earlier.
+
+ See 4D.1 on Binary files.
+
+ Last modified: _6/13/1997_
+
+ 6. How do I retain the original $\Revision$ strings in the sources?
+
+ If you want to leave old RCS keywords as they are, you can use the
+ '-ko' tricks described above.
+
+ Last modified: _6/13/1997_
+
+ 7. I imported some files for the Yarg compiler that compiles files with a
+ suffix of ".yarg" and whose comment prefix is "YARG> ". When I check them
+ out, they will no longer compile because they have this junk in them. Why?
+
+ YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>
+ YARG> $\Log:
+ # Revision 1.3 1998/03/03 00:16:16 bubba
+ # What is 2+2 anyway?
+ #
+ # Revision 1.2 1998/03/03 00:15:15 bubba
+ # Added scorekeeping.
+ YARG>
+ YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>
+
+ Well bubba, "Yarg" hasn't hit the big time yet. Neither RCS nor CVS
+ know about your suffix or your comment prefix. So you have two
+ choices:
+
+ Check out the Yarg-less module, and tell all the files about your
+ comment prefix. Visit each directory and type:
+
+ cvs admin -c"YARG> " *.yarg
+
+ If *all* files in the whole directory tree are Yarg files, you can use
+ this instead:
+
+ cvs admin -c"YARG> " .
+
+ Then save any changes you made, remove all the "*.yarg" files and grab
+ new copies from the Repository:
+
+ rm *.yarg (or: find . -name '*.yarg' -exec rm {} ';') (or: find .
+ -name '*.yarg' -print | xargs rm) (or: find . -name '*.yarg' -print0 |
+ xargs -0 rm if you have spaces in filenames and the GNU find/xargs.)
+ cvs update
+
+ It might be faster to remove the whole directory and check it out
+ again.
+
+ Change the import.c file in the CVS sources and add the .yarg
+ suffix, along with the "YARG> " comment prefix to the "comtable"
+ array.
+
+ If you ever plan to add new files with $\Log in them, you should also
+ go into the RCS sources and make the same change in the table
+ contained in the "rcsfnms.c" file.
+
+ Then delete the imported files from the Repository and re-"import" the
+ sources.
+
+ Last modified: _6/13/1997_
+
+ 8. How do I make "import" save the timestamps on the original files?
+
+ Use "import -d" to save the current timestamps on the files as the RCS
+ revision times.
+
+ See 4D.8 for another aspect of file timestamps.
+
+ Last modified: _6/13/1997_
+
+ 9. Why can't I "import" 3 releases on different branches?
+
+ I'll bet you typed something like this:
+
+ cd /src/blasto.v2
+ cvs import -b 1.1.2 VENDOR2 Version2
+ cd /src/blasto.v3
+ cvs import -b 1.1.3 VENDOR3 Version3
+ cd /src/blasto.v4
+ cvs import -b 1.1.4 VENDOR4 Version4
+
+ This is wrong, or at least it won't help you much. You have created
+ three separate Vendor branches, which is probably not what you wanted.
+
+ Earlier versions of CVS, as described in Brian Berliner's Usenix
+ paper, tried to support multiple Vendor branches on the theory that
+ you might receive source for the *same* program from multiple vendors.
+ It turns out that this is very rare, whereas the need to branch in
+ *your* development, for releases and for project branches, is much
+ greater.
+
+ So the model now is to use a single vendor branch to contain a series
+ of releases from the same vendor. Your work moves along on the Main
+ Trunk, or on a CVS branch to support a real "branch in development".
+
+ To set this up, you should type this instead of the above:
+
+ cd /src/blasto.v2
+ cvs import VENDOR Version2
+ cd /src/blasto.v3
+ cvs import VENDOR Version3
+ cd /src/blasto.v4
+ cvs import VENDOR Version4
+
+ Last modified: _6/13/1997_
+
+ 10. What do I do if the Vendor adds or deletes files between releases?
+
+ Added files show up with no extra effort. To handle "removed" files,
+ you should always compare the tree structure of the new release
+ against the one you have in your Repository. If the Vendor has removed
+ files since the previous release, go into a working directory
+ containing your current version of the sources and "cvs remove"
+ (followed by "cvs commit" to make it really take effect) each file
+ that is no longer in the latest release.
+
+ Using this scheme will allow you to "checkout" any version of the
+ vendor's code, with the correct revisions and files, by using
+ "checkout -r Version[234]".
+
+ Renames are harder to find, since you have to compare file contents to
+ determine that one has occurred. If you notice one, see 4B.8 on
+ renaming files.
+
+ Last modified: _6/13/1997_
+
+ 11. What about if the Vendor changes the names of files or directories, or
+ rearranges the whole structure between releases?
+
+ Currently CVS can't handle this cleanly. It requires "renaming" a
+ bunch of files or directories.
+
+ See 4B.8 on "renaming" for more details.
+
+ What I generally do is to close the Repository for a while and make
+ changes in both the Repository and in a copy of the vendor release
+ until the structure matches, then execute the import.
+
+ If you ever have to check out and build an old version, you may have
+ to use the new, or completely different Makefiles.
+
+ Last modified: _6/13/1997_
+
+ 12. I thought "import" was for Vendor releases, why would I use it for code
+ of my own? Do I have to use import?
+
+ For code you produce yourself, "import" is a convenience for fast
+ insertion of whole trees. It is not necessary. You can just as easily
+ create ",v" files using the RCS "ci" command and move them directly
+ into the Repository.
+
+ Other than the CVSROOT directory, the Repository consists entirely of
+ directories of ",v" files. The Repository contains no other state
+ information.
+
+ See Section 4B, on Setting up and Managing the Repository.
+
+ Last modified: _6/13/1997_
+
+ 13. How do I import a large Vendor release?
+
+ When the sum of the changes made by the Vendor and the changes made by
+ local developers is small, "import" is not a big problem. But when you
+ are managing a large Repository, any care taken up front will save you
+ time later.
+
+ First read the following, then, before executing "import", see the
+ questions in Section 4C dealing with branch merges and Vendor branch
+ merges.
+
+ If this is not the first import of this code, before starting, rtag
+ the whole directory you will be changing.
+
+ The first step is to make sure the structure of the new files
+ matches the structure of the current Repository.
+
+ Run "find . -print | sort" on both trees and "diff" the output.
+
+ Alter the "source" tree until the "diff" (of the list of filenames,
+ not of the whole trees) shows that the directory structures are
+ equivalent.
+
+ The "comm" command, if you have it, can help figure out what has been
+ added or deleted between releases.
+
+ If they deleted any files, you can handle them cleanly with "cvs
+ remove". The command "comm -23 files.old files.new" will show you a
+ list of files that need to be removed.
+
+ You should examine the list first to see if any have been renamed
+ rather than simply deleted.
+
+ If they renamed any files, see 4B.8 on renaming files.
+
+ Remember to *SAVE* the output from the import command.
+
+ When you have dealt with removed and renamed files, then you can
+ execute the import:
+
+ cd <new source>
+ cvs import -I ! -m "Message" <repos> <VendorTag> <ReleaseTag>
+
+ Where
+
+ "-I !" is an optional argument that keeps "import" from ignoring
+ files. The comparison of the "find" commands above will probably avoid
+ the need for this, but it is easier to remove files from the
+ Repository than to run a subset "import" to catch just the ignored
+ files. [You might have to quote or backwhack the '!'.]
+
+ Message is the log message to be stored in the RCS files.
+
+ <repos> is a relative path to a directory within the
+ Repository. The directory <new source> must be at
+ the same relative level within the new sources as
+ the <repos> you give is within the Repository. (I
+ realize this is not obvious. Experiment first.)
+
+ <VendorTag> is a Tag used to identify the Vendor who sent you
+ the files you are importing. All "imports" into
+ the same <repos> *must* use the same VendorTag.
+ You can find it later by using the "log" command.
+
+ <ReleaseTag> is a Tag used to identify the particular release of the
+ software you are importing. It must be unique and should be mnemonic
+ -- at least include the revision number in it. (Note: you can't use
+ '.' characters in a Tag. Substitute '_' or '-'.)
+
+ There will be six categories of files to deal with. (Actually there
+ are eight, but you have already dealt with "removed" and "renamed"
+ files.)
+
+ If this is the first "import" into a given <repos> directory, only the
+ first three of these ('I', 'L' and 'N') can occur.
+
+ Ignored file.
+
+ CVS prints: I filename
+
+ You'll need to examine it to see if it *should* have been ignored. If
+ you use "-I !", nothing will be ignored.
+
+ Symbolic link.
+
+ CVS prints: L linkname
+
+ Links are "ignored", but you'll probably want to create a "checkout
+ helper" function to regenerate them.
+
+ New file.
+
+ CVS prints: N filename
+
+ CVS creates a new file in the Repository. You don't have to do
+ anything to the file, but you might have to change Makefiles to refer
+ to it if this is really a new file.
+
+ A file unchanged by the Vendor since its last release.
+
+ CVS prints: U filename
+
+ CVS will notice this and simply add the new ReleaseTag to the latest
+ rev on the Vendor branch.
+
+ No work will be needed by you, whether you have changed the file or
+ not. No one will notice anything.
+
+ A file changed by the Vendor, but not by you.
+
+ CVS prints: U filename
+
+ CVS should add the file onto the vendor branch and attach the Release
+ Tag to it.
+
+ When you next execute "update" in any working directory you'll get the
+ new revision.
+
+ A file changed by both the Vendor and by you.
+
+ CVS prints: C filename
+
+ These are the trouble files. For each of these files (or in groups --
+ I usually do one directory at a time), you must execute:
+
+ cvs update -j <PreviousReleaseTag> -j <ReleaseTag>
+ or
+ cvs update -j <VendorTag:yesterday> -j <VendorTag>
+
+ It will print either 'M' (if no overlaps) or 'C', if overlaps. If a
+ 'C' shows up, you'll need to edit the file by hand.
+
+ Then, for every file, you'll need to execute "cvs commit".
+
+ See the part of Section 4C dealing with branch merges.
+
+ If you are truly performing a large import, you will most likely
+ need help. Managing those people is another problem area.
+
+ Since the merge of the Vendor branch is just like any other merge, you
+ should read section 4C for more info about performing and cleaning up
+ merges.
+
+ The larger the import, and the larger the group of people involved,
+ the more often you should use "tag" and "rtag" to record even trivial
+ milestones. See 4C.14, especially the "paranoid" section.
+
+ Before starting the import, you should install and test a "commitinfo"
+ procedure to record all commits in a file or via Email to a mail
+ archive. Along with the tags you placed on the Repository before the
+ import, this archive will help to track what was changed, if problems
+ occur
+
+ There are four stages to the recovery:
+
+ Parcel out the work -- Effective Emacs Engineering.
+
+ As input to the assignment process, you might want to examine the tree
+ and record the last person who changed the file. You can also
+ research, if you don't already know, who is expert in each area of the
+ software.
+
+ Examine the import log (you saved the output, right?), estimate how
+ much work is involved in each area and assign groups of files to
+ individual developers. Unless some directory is immense, it is easier
+ to manage if you assign whole directories to one person.
+
+ Keep a list. Suggest a completion date/time. Tell them to "commit" the
+ file when they are finished with the merge. If you tagged the
+ Repository before starting the import, you should have no trouble
+ figuring out what happened.
+
+ If you can, find out (or tell them) which working directory to use.
+ You should verify that the working directory they use is on the Main
+ Branch ("update -A") and without modified files.
+
+ If you trust your crew, have them notify you by Email. Have them send
+ you the output from "cvs update" in their working directory. You might
+ have to poll some people until you are certain they have finished, or
+ have given up. (This is not an invention. I've heard a false, "Yeah,
+ sure. I finished yesterday," more times that you'd believe.)
+
+ When all reports are in, go on to the Source Verification stage.
+
+ Source Verification -- CVS and other Tools.
+
+ If you didn't dictate which ones to use, find all working directories
+ and run "cvs -n update" in all of them. The history command and the
+ "commitinfo" log you set up might help to find checked out working
+ directories.
+
+ Sticky conflict flags will help, but they can't recover from
+ sloppiness or incompetence. You might want to check everything out
+ into a tree and grep for the parts of the merge conflict markers CVS
+ doesn't look for. CVS looks for the string '^>>>>>>> '. The merge
+ operation also puts '^<<<<<<< ' and '^======= ' markers in the file
+ that careless developers might leave there.
+
+ If you find problems simply by looking at the source files and working
+ directories, start the flogging now. Resolving the textual conflicts
+ is the easy part. Weed the turkeys out before reaching the next part
+ of the cleanup -- the resolution of logical conflicts.
+
+ Then apply a set of post-commit tags.
+
+ Logical Verification -- Diff and powerful eyeballs.
+
+ No source control system can solve the problem of resolving
+ distributed conflicts in program logic. If you change the argument
+ template for function A (defined in file A.c) and add new calls to
+ function A from within function B (defined in file B.c) using the old
+ argument format, you are outside the realm of CVS's competence.
+
+ Assign someone to understand what the Vendor changed by running "cvs
+ diff -c -r <PreviousReleaseTag> <ReleaseTag>", where the tags were
+ those handed to the last two invocations of "import".
+
+ Then have the same person compare that output (logically or you can
+ actually diff the diffs) to the output of the similar "cvs diff -c -r
+ <pre-import-tag> <post-commit-tag>". The two sets of differences
+ should be almost identical. They should both show only the work *you*
+ have performed.
+
+ Product Verification -- Build and Test.
+
+ Don't let your help off the hook until you verify that the merge
+ actually produced something that can compile and pass tests. Compiling
+ should really be part of the logical verification phase, but you
+ should test the output of the build system before declaring victory
+ and releasing the troops.
+
+ After it is all built, apply another set of tags to mark the end of
+ the "import process". You can delete the intermediate tags you added
+ during source and logic testing, but keep the "pre-import" and
+ "post-import" tags forever.
+
+ Of course, experience can tell you when to skip a step. But I'd start
+ out by considering each one as necessary unless you can prove
+ otherwise.
+
+ Last modified: _6/13/1997_
+
+ 14. Explain: ERROR: cannot create link to <file>: Permission denied
+
+ This error appears when you try to execute a second (or later)
+ "import" into the same module from a directory to which you don't have
+ write access.
+
+ The "link error" is caused by a feature purposely added to speed up
+ the import.
+
+ Though the error message is somewhat strange, it indicates that
+ "import" is supposed to be executed only in writable directories.
+
+ Last modified: _6/13/1997_
+
+ 15. Where does the -m <message> go when the file doesn't change?
+
+ The <message> handed to import is used as an RCS log message, but only
+ if the imported file changed since the last version on the Vendor
+ branch. If the imported file hasn't changed, then no new revision is
+ created. The <ReleaseTag> is still applied, but to the previous
+ revision. So the Tags are still correct, but the message is lost.
+
+ Maybe it should be appended to the previous log message. But currently
+ it isn't.
+
+ Last modified: _6/13/1997_
+
+ 16. How do I "import" just the files ignored by a previous "import"?
+
+ A real answer follows, but first, an editorial:
+
+ I am now convinced that you should always use the "-I !" option.
+ Removing a few extraneous files from the Repository is a lot easier
+ than the recovery step described below.
+
+ Let's assume your original import procedure was: (We assume there is
+ enough disk space in /tmp.)
+
+ cd <head-of-vendor-tree>
+ cvs import -m 'xyz 1.3' gnu/xyz GNU GNUXYZ_1_3 | tee /tmp/IMP
+
+ To import just the files ignored by "import", I would do this:
+
+ Create a list of the ignored files to import:
+
+ cd <head-of-vendor-tree> awk '/^I / {print $2}' /tmp/IMP | sed
+ 's|^gnu/xyz/||' > /tmp/IG [Edit the IG file to contain just the files
+ you want.]
+
+ Then create a sparse directory by handing your list to the GNU
+ version of "tar", installed in many places as "gtar":
+
+ mkdir /tmp/FIXUP gtar -T /tmp/IG -c -f - . | (cd /tmp/FIXUP; gtar xvBf
+ -)
+
+ Then rerun the import. Use the exact same command, but execute it in
+ the sparse directory tree you just created. And this time, tell it not
+ to ignore anything.
+
+ cd /tmp/FIXUP
+ cvs import -I ! -m 'xyz 1.3' gnu/xyz GNU GNUXYZ_1_3
+
+ Last modified: _6/13/1997_
+
+ 17. Why did "import" ignore all the symlinks?
+
+ This is another design choice.
+
+ Like the Unix "tar" command, "import" could sprout an option to follow
+ symbolic links, but I don't think CVS will ever follow symbolic links
+ by default.
+
+ Two possible future enhancements have been seriously discussed:
+
+ Treat symbolic links as data in its parent directory (the way
+ ClearCase does) in some sort of per-directory control file.
+
+ Treat symbolic links as version-controlled elements themselves,
+ whose data is the value of readlink(2).
+
+ For now, they are simply ignored.
+
+ If you want to save and reconstruct symlinks, you might want to define
+ a "checkout" or "update" program in the modules file which could
+ consult a file kept under CVS in your working directory and make sure
+ the specified links are in place.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/log_lo_rlog/
+
+ " + "log", "lo", "rlog""
+
+ 1. What is "log" for?
+
+ To provide an interface to the RCS "rlog" command, which displays
+ information about the underlying RCS files, including the revision
+ history and Tag (RCS calls it a "symbol") list.
+
+ Last modified: _6/13/1997_
+
+ 2. How do I extract the log entries between two revisions?
+
+ If both <rev1> and <rev2> are on the same branch, you can get what you
+ are looking for with: (If they aren't on the same branch you'll either
+ get an error or a display of the whole change log.)
+
+ cvs log -r<rev1>:<rev2> <file>
+
+ If you want all the revisions on the branch from <rev1> to the end of
+ the branch <rev1> is on, you can use:
+
+ cvs log -r<rev1>: <file>
+
+ (If <rev1> is a numeric RCS symbol attached to a branch revision with
+ an even number of '.'s in it, you get the whole branch.)
+
+ If you want all the revisions on the branch from the beginning of the
+ branch <rev2> is on up to revision <rev2>, you can use:
+
+ cvs log -r:<rev2> <file>
+
+ Note: Depending on whether <rev1> and <rev2> are:
+
+ - numeric or symbolic
+ - in the file or not
+ - on the same branch or not
+
+ the RCS "rlog" (and therefore the "cvs log") command will
+ display some combination of:
+
+ - error messages
+ - (intuitively correct) partial log listings
+ - a display of the entire change log.
+
+ Last modified: _6/13/1997_
+
+ 3. How do I extract the log entries on a whole branch?
+
+ cvs log -r<rev> <file>
+
+ where <rev> must be a branch revision (one with an even number of
+ dots) or a *non-branch* tag on a branch revision. Non-branch tags on a
+ branch revision are not normally attached by CVS, to add one you will
+ have to explicitly tag a physical branch number within each file.
+ Since these branch numbers are almost never the same in different
+ files, this command is not all that useful.
+
+ The intuitive command (at least from the CVS perspective):
+
+ cvs log -r<branch_tag> <file>
+
+ does not work.
+
+ Last modified: _6/13/1997_
+
+ 4. How do I generate ChangeLogs from RCS logs?
+
+ A program called rcs2log is distributed as part of GNU Emacs 19. A
+ (possibly older) version of this program appears in the contrib
+ directory of the cvs source tree.
+
+ Last modified: _6/13/1997_
+
+ 5. Why does "log" tell me a file was committed exactly 5 hours later
+
+ than I know it was?
+
+ I can tell by this question that you were working in a time zone that
+ is 5 hours behind GMT (e.g. the U.S. East Coast in winter).
+
+ RCS file dates are stored in GMT to allow users in different time
+ zones to agree on the meaning of a timestamp. At first glance this
+ doesn't seem necessary, but many companies use distributed file
+ systems, such as NFS or AFS, across multiple timezones.
+
+ Some standard form must be used. GMT, as the "grid origin", is an
+ obvious candidate. The only other reasonable choice is to put the
+ timezone information in all the time stamps, but that changes the RCS
+ file format incompatibly, a step which has been avoided in the last
+ few RCS releases.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/patch_pa_rdiff/
+
+ " + "patch", "pa", "rdiff""
+
+ 1. What is "patch" for?
+
+ To produce a "diff" between tagged releases to be handed to the
+ "patch" command at other sites. This is the standard way that source
+ patches are distributed on the network.
+
+ Last modified: _6/13/1997_
+
+ 2. Why does "patch" include files from the Attic when I use '-D'?
+
+ See the explanation of the same problem with "update -D" contained in
+ section 5B.
+
+ Last modified: _6/13/1997_
+
+ 3. How do I make "patch" produce a patch for one or two files? It seems to
+ work only with modules.
+
+ Patch is intended for producing patches of whole modules between
+ releases to be distributed to remote sites. Instead of "patch", you
+ can use the "diff" command with the '-c' context option:
+
+ cvs diff -c -r <rev/tag> -r <rev/tag> <file1> . . .
+
+ The patch command will be able to merge such a "diff" into the remote
+ source files.
+
+ If you configured CVS to use a version of "diff" that supports the
+ '-u' option, you can produce a more compact "patch" in "unidiff"
+ format. The latest revisions of the patch command can parse and apply
+ patches in "unidiff" format.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/release_re_rel/
+
+ " + "release", "re", "rel""
+
+ 1. What is "release" for?
+
+ To register that a module is no longer in use. It is intended to
+ reverse the effects of a "checkout" by adding a record to the history
+ file to balance the checkout record and by optionally allowing you to
+ delete the checked-out directory associated with the module name.
+
+ Last modified: _6/13/1997_
+
+ 2. Why can't I reverse a "cvs checkout path/name/subdir" with a "cvs
+ release path/name/subdir" without an "unknown module name"?
+
+ A simplistic implementation. (I can say this -- I wrote it.)
+
+ The "release" function was written for CVS 1.2 under the assumption
+ that the "module name" is a first class, unavoidable interface to the
+ Repository, allowing no way to retrieve anything other than by module
+ name. Though it is easier to program that way, many users of CVS
+ believe the modules support to be too primitive to allow such a
+ limitation.
+
+ Since "release" was written, other parts of CVS broke that assumption.
+ It needs to be revised.
+
+ Last modified: _6/13/1997_
+
+ 3. Why can't I "release" portions of a checked out directory? I should be
+ able to "release" any file or sub-directory within my working directory.
+
+ This isn't really a limitation in "release", per se. CVS doesn't try
+ to keep track of which files in which directories are "checked out"
+ and which are just lying there. You can delete directories and
+ "update" will not bring them back unless you add a special "-d"
+ option.
+
+ In other words, CVS doesn't keep track of how you adjust the partition
+ between files you consider part of your working set and files that
+ were checked out because they are part of the same module or
+ directory. And neither does "release".
+
+ In future CVS releases, "release" might become sophisticated enough to
+ handle both the reversal of a "checkout" and the deletion of random
+ portions of the working directory, but it isn't that way now.
+
+ Last modified: _6/13/1997_
+
+ 4. I removed the tree that I was about to start working on. How do I tell
+ cvs that I want to release it if I don't have it anymore?
+
+ See 3G.4.
+
+ Last modified: _6/13/1997_
+
+ 5. Why doesn't "release -d module" reverse a "checkout module"?
+
+ It does, if you are using "module" in a way that "release" expects: a
+ non-alias string in the left column of the "modules" database.
+
+ If "module" is really an alias, or if you are using a relative path in
+ the place of "module", or if you renamed the directory with the -d
+ option in the modules file or on the "checkout" command line, then the
+ current version of "release" won't work.
+
+ Future versions of "release" will probably fix most of these.
+
+ Last modified: _6/13/1997_
+
+ 6. Why can't I release a module renamed with "cvs checkout -d"?
+
+ The current version of "release" doesn't know how to track the
+ renaming option ('-d') of the "checkout" command. It will probably be
+ fixed in the future.
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/remove_rm_delete/
+
+ " + "remove", "rm", "delete""
+
+ 1. What is "remove" for?
+
+ To remove a file from the working branch. It removes a file from the
+ main branch by placing it in an "Attic" directory.
+
+ Last modified: _6/13/1997_
+
+ 2. Why doesn't "remove" work on directories when it appears to try?
+
+ Oversight. It should be able to delete an empty directory, but you
+ still don't have a way to remember when it was there and when it
+ disappeared to allow the "-D " option to work.
+
+ You'll have to remove the working directory and the matching directory
+ in the Repository.
+
+ Note that you want to do a _cvs remove dir_ in the working directory,
+ do a cvs commit, and then do a _rmdir dir_ in the Repository.
+ (msusrtsp.mark at eds dot com)
+
+ Last modified: _12/18/1997_
+
+ 3. I don't like removing files. Is there another way to ignore them?
+
+ There's no reason to be hasty in using the "remove" command.
+
+ If there is a way to ignore files in your build procedures, I'd just
+ do that. Later, when you decide that the files are really ancient, you
+ can execute a "remove" command to clean up.
+
+ The CVS "ignore" concept can't ignore files already in CVS.
+
+ Last modified: _6/13/1997_
+
+ 4. I just removed a file. How do I resurrect it?
+
+ If you executed "remove", but haven't typed "commit" (you can tell
+ this by the 'R' notation that "update" prints next to the file), you
+ can execute "add" to reverse the "remove".
+
+ If you followed the "remove" with a "commit", you'll have to move it
+ back out of the Attic by hand:
+
+ I use something like this: (csh-like syntax)
+
+ set repos = `cat ./CVS/Repository`
+ mv $repos/Attic/filename,v $repos/filename,v
+
+ (If you use relative paths in your Repository files, that first line
+ becomes: set repos = $CVSROOT/`cat ./CVS/Repository`)
+
+ While a file is in the Attic, you can't "add" another file by the same
+ name. To add such a file you either have to move it by hand as in the
+ above, or delete it from the Attic.
+
+ The main reason for the Attic is to retain files with tags in them. If
+ you execute: "update -r <oldtag>", files with <oldtag> attached to
+ some revision will be taken from the normal Repository area and from
+ the Attic. That's why you can't "add" a file with the same name.
+ "remove" only moves a file off the main branch, it doesn't obliterate
+ it.
+
+ Last modified: _6/13/1997_
+
+ 5. Why doesn't "remove" delete the file? Instead, it prints an error
+ message and tells me to remove the file by hand.
+
+ Design choice. Unix software written within last decade, usually
+ requires an extra verification step, such as answering a question or
+ adding a flag on the command line. CVS currently requires that you
+ delete the file first unless you specify the '-f' (force) option,
+ which deletes the file before performing "cvs remove".
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/rtag_rt_rfreeze/
+
+ " + "rtag", "rt", "rfreeze""
+
+ 1. What is "rtag" for?
+
+ To add a symbolic label (a "tag") to the last committed revisions of a
+ module directly in the Repository.
+
+ Last modified: _6/13/1997_
+
+ 2. Why use "rtag"? It assumes no one is changing the Repository.
+
+ Though the "tag" command is more useful in marking the revisions you
+ have in a particular working directory, "rtag" is much handier for
+ whole-Repository actions, which occur at major release boundaries.
+
+ Last modified: _6/13/1997_
+
+ 3. What revision does "rtag -r <tag1> <tag2>" actually put the tag on?
+
+ In short, the '-r' option is another way to select the revision to
+ tag. The revision is selected the same way for all commands that
+ accept a "-r <tag/rev>" option.
+
+ Depending on whether <tag1> is a <branch_tag>, or a non-branch <tag>
+ and on whether you use the '-b' option to "rtag", you get four
+ different results:
+
+ rtag -r <tag1> <tag2>
+
+ Adds the non-branch tag <tag2> to the same revision that the
+ non-branch tag <tag1> is attached to.
+
+ Example:
+ <tag1> --> TT1
+ <tag2> --> TT2
+ <file> --> Symbols: TT1:1.4
+ After --> Symbols: TT1:1.4,TT2:1.4
+
+ rtag -r <branch_tag1> <tag2>
+
+ Adds the non-branch tag <tag2> to the HEAD of (the highest revision
+ number on) the branch labelled with tag <branch_tag1>.
+
+ Example:
+ <branch_tag1> --> BR1
+ <tag2> --> TT2
+ <file> --> Symbols: BR1:1.2.0.2 (1.2.2.5 is HEAD)
+ After --> Symbols: BR1:1.2.0.2,TT2:1.2.2.5
+
+ If the branch tagged by <branch_tag1> has not been created, then the
+ tag shows up on the branch point revision:
+
+ Example:
+ <branch_tag1> --> BR1
+ <tag2> --> TT2
+ <file> --> Symbols: BR1:1.2.0.2 (No 1.2.X exists.)
+ After --> Symbols: BR1:1.2.0.2,TT2:1.2
+
+ rtag -b -r <tag1> <branch_tag2>
+
+ Adds the magic branch tag <branch_tag2> to the revision that the
+ non-branch tag <tag1> is attached to, preparing it to be a branch
+ point.
+
+ Example:
+ <tag1> --> TT1
+ <branch_tag2> --> BR2
+ <file> --> Symbol: TT1:1.4
+ After --> Symbol: TT1:1.4, BR2:1.4.0.2
+
+ rtag -b -r <branch_tag1> <branch_tag2>
+
+ Adds the magic branch tag <branch_tag2> to the revision at the HEAD of
+ (the highest revision number on) the branch labelled with
+ <branch_tag1>, preparing it to be a branch point.
+
+ Example:
+ <branch_tag1> --> BR1
+ <branch_tag2> --> BR2
+ <file> --> Symbol: BR1:1.2.0.2 (1.2.2.5 is HEAD)
+ After --> Symbol: BR1:1.2.0.2,BR2:1.2.2.5.0.2
+
+ If the branch tagged by <branch_tag1> has not been created, then the
+ tag shows up as a second branch off the same branch point revision:
+
+ Example:
+ <branch_tag1> --> BR1
+ <tag2> --> TT2
+ <file> --> Symbols: BR1:1.2.0.2 (No 1.2.X exists.)
+ After --> Symbols: BR1:1.2.0.2,TT2:1.2.0.4
+
+ In all four cases above, if <tag2> already exists on the file, you get
+ an error unless you specify the '-F' option.
+
+ In all four cases, if <tag1> does not exist on the file, <tag2> is not
+ added unless you specify the '-f' option.
+
+ Last modified: _6/13/1997_
+
+ 4. What happens if the tags are the same in "rtag -r <tag> <tag>"?
+
+ Again, there are four cases depending on whether <tag> is a branch
+ tag, or a non-branch tag and on whether you use the '-b' option to
+ "rtag":
+
+ rtag -r <tag> <tag>
+
+ Is a no-op. It does nothing even with '-F' specified.
+
+ If you add the '-f' option ("rtag -f -r <tag> <tag>"), then <tag> is
+ attached to the latest revision on the Main Branch if the file does
+ *not* already have <tag> on some revision.
+
+ If the <tag> is already on the file, using "rtag -f" is still a no-op.
+
+ rtag -r <branch_tag> <branch_tag>
+
+ Produces an error, since the <branch_tag> is already on some revision
+ of the file.
+
+ But, "rtag -F -r <branch_tag> <branch_tag>" turns the magic branch tag
+ into a non-branch tag.
+
+ Symbols: BR1:1.4.0.2 becomes Symbols: BR1:1.4
+
+ rtag -b -r <tag> <tag>
+
+ Produces an error, since the <tag> is already on the file.
+
+ But, "rtag -F -b -r <tag> <tag>" turns the non-branch tag into a magic
+ branch tag.
+
+ Symbols: BR1:1.4 becomes Symbols: BR1:1.4.0.2
+
+ rtag -b -r <branch_tag> <branch_tag>
+
+ Produces an error, since the <branch_tag> is already on the file.
+
+ But, "rtag -F -b -r <branch_tag> <branch_tag>" increments the branch
+ number. It essentially removes the branch and creates a new one by the
+ same name.
+
+ Symbols: BR1:1.2.0.4 becomes Symbols: BR1:1.2.0.6
+
+ Last modified: _6/13/1997_
+
+ 5. Why doesn't "rtag -b -r <branch_tag1> <branch_tag2>" rename or duplicate
+ a magic branch tag?
+
+ None of the "tag" or "rtag" options rename anything. They only apply
+ (or, with the '-F' option, move) tags to specific revisions in the
+ file.
+
+ See 3M.[3-4] above for details of how it works.
+
+ To rename a non-branch tag, see 3O.9. To rename a magic branch tag,
+ see 4D.5
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/status_st_stat/
+
+ " + "status", "st", "stat""
+
+ 1. What is "status" for?
+
+ To display the status of files, including the revision and branch you
+ are working on and the existence of "sticky" information.
+
+ Last modified: _6/13/1997_
+
+ 2. Why does "status" limit the File: at the top to 17 characters?
+
+ Designed that way to line up with other data. You can find the whole
+ filename in the line beginning with "RCS version:", which is not
+ limited in length.
+
+ Last modified: _6/13/1997_
+
+ 3. Why does it print "Sticky" lines when the values are "(none)"?
+
+ Oversight. It should probably elide lines without information.
+
+ Last modified: _6/13/1997_
+
+ 4. Shouldn't the status "Needs Checkout" be "Needs Update"?
+
+ Probably.
+
+ [[Did this show up in CVS 1.4?]]
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/tag_ta_freeze/
+
+ " + "tag", "ta", "freeze""
+
+ 1. What is "tag" for?
+
+ To add a symbolic label (a "tag") to the RCS files last checked out,
+ updated or committed in a working directory.
+
+ Last modified: _6/13/1997_
+
+ 2. What is the difference between "tag" and "rtag"?
+
+ The end result of both commands is that a <tag>, or symbolic name, is
+ attached to a single revision in each of a collection of files.
+
+ The differences lie in:
+
+ The collection of files they work on.
+
+ "rtag" works on the collection of files referred to by a "module" name
+ as defined in the "modules" file, or a relative path within the
+ Repository.
+
+ "tag" works on files and directories specified on the command line
+ within the user's working directory. (Default is '.')
+
+ Both commands recursively follow directory hierarchies within the
+ named files and directories.
+
+ The revisions they choose to tag.
+
+ "rtag" places a tag on the latest committed revision of each file on
+ the branch specified by the '-r' option. By default it tags the Main
+ Branch.
+
+ "tag" places a tag on the BASE (i.e. last checked out, updated or
+ committed) revision of each file found in the working directory. (The
+ BASE revision of a file is the one stored in the ./CVS/Entries file.)
+
+ A different set of command line options.
+
+ For example, "rtag" takes a "-r <oldtag>" option to retag an existing
+ tag. The "tag" command does not.
+
+ How it is logged.
+
+ Currently "rtag" records the <tag> and the module in the "history"
+ file, while "tag" does not.
+
+ Last modified: _6/13/1997_
+
+ 3. Why does "tag -b" not put a tag on the Branch Point revision? How do I
+ refer to the Branch Point?
+
+ This is probably an oversight, or a disbelief in the need for it. If
+ everything works perfectly, the "update -j" command will do the merge
+ you need and you don't need to check up on it by playing with the
+ branch point revision.
+
+ The '-b' option attaches a magic branch tag to allow CVS later to
+ figure out the branch point. The actual revision that <tag> is
+ attached to does not exist. References to the branch tag are
+ equivalent to references to the latest revision on the branch.
+
+ There is no way to refer to the branch point without adding a
+ non-branch tag. You might want to add non-branch tags as a habit and
+ add branch tags later, possibly immediate after adding the non-branch
+ tag. See 4C.3 on Creating a Branch.
+
+ Last modified: _6/13/1997_
+
+ 4. So "{r}tag" labels a bunch of files. What do you use a Tag for?
+
+ You use it to "checkout" the labeled collection of files as a single
+ object, referring to it by name.
+
+ Anywhere a revision number can be used a Tag can be used. In fact tags
+ are more useful because they draw a line through a collection of
+ files, marking a development milestone.
+
+ The way to think about a Tag is as a curve drawn through a matrix of
+ filename vs. revision number. Consider this:
+
+ Say we have 5 files (in some arbitrary modules, some may be in 2 or
+ more modules by name, some may be in 2 or more modules because of the
+ Repository tree structure) with the following revisions:
+
+ file1 file2 file3 file4 file5
+
+ 1.1 1.1 1.1 1.1 /--1.1* <-*- <tag>
+ 1.2*- 1.2 1.2 -1.2*-
+ 1.3 \- 1.3*- 1.3 / 1.3
+ 1.4 \ 1.4 / 1.4
+ \-1.5*- 1.5
+ 1.6
+
+ At some time in the past, the '*' versions were tagged. Think of the
+ <tag> as a handle attached to the curve drawn through the tagged
+ revisions. When you pull on the handle, you get all the tagged
+ revisions. Another way to look at it is that you draw a straight line
+ through the set of revisions you care about and shuffle the other
+ revisions accordingly. Like this:
+
+ file1 file2 file3 file4 file5
+
+ 1.1
+ 1.2
+ 1.1 1.3 _
+ 1.1 1.2 1.4 1.1 /
+ 1.2*----1.3*----1.5*----1.2*----1.1 (--- <-- Look here
+ 1.3 1.6 1.3 \_
+ 1.4 1.4
+ 1.5
+
+ I find that using these visual aids, it is much easier to understand
+ what a <tag> is and what it is useful for.
+
+ Last modified: _6/13/1997_
+
+ 5. How do I get "tag" and "rtag" to send mail the way "commit" does?
+
+ The "commit" command is supported by two files ("commitinfo" and
+ "loginfo") not used by other commands. To do logging the same way for
+ "tag" and "rtag" would require another file like loginfo, which
+ currently doesn't exist.
+
+ The "rtag" command requires a "module" entry, which can specify a
+ "tag" program using the "-t programname" option on the module line.
+
+ There is no equivalent support for "tag".
+
+ Last modified: _6/13/1997_
+
+ 6. Why can't "tag" handle the '-r' option that "rtag" takes?
+
+ Oversight. The answer is probably "Fixed in a Future Release."
+
+ Last modified: _6/13/1997_
+
+ 7. After a "tag <tag>" in my working directory, why doesn't "checkout -r
+ <tag>" somewhere else produce copies of my current files?
+
+ The only reason this would fail, other than misspelling the <tag>
+ string, is that you didn't "commit" your work before "tagging" it.
+ Only committed revisions may be tagged. Modified files are not marked
+ for later tagging.
+
+ Last modified: _6/13/1997_
+
+ 8. Why doesn't "tag" write a history record the way "rtag" does?
+
+ The "rtag" command was originally intended to place major "release"
+ tags onto modules. The "tag" functionality was developed to *move* the
+ more significant tag when slight changes to individual files sneaked
+ in after the release tag was stamped onto the Repository.
+
+ The significant event was the "rtag", which was recorded in the
+ "history" file for the "history -T" option to work.
+
+ It turns out that "tag" is generally more useful than "rtag", so the
+ model has changed. Future revisions of CVS will probably store both
+ kinds of tags in the history file.
+
+ Last modified: _6/13/1997_
+
+ 9. How do I rename a <tag>?
+
+ For a procedure to rename a branch tag, See section 4D.5 The following
+ covers only non-branch tags.
+
+ First, pick a <newtag> that is not in use. You could reuse (i.e. move)
+ an existing tag to the new revisions using the '-F' option, but that
+ will confuse matters when both tags are not already on a file. (It
+ will probably confuse "rtag -f" too.)
+
+ Use "rtag" to place <newtag> only on revisions attached to <oldtag> in
+ the whole Repository, then delete the old one.
+
+ cvs rtag -r <oldtag> <newtag> world
+ cvs rtag -d <oldtag> world.
+
+ You can also checkout or update your working directory to the <oldtag>
+ and "tag" rather than "rtag" the result. But that will take longer and
+ it has the chance of producing conflicts.
+
+ cvs update -r <oldtag>
+ cvs tag <newtag>
+ cvs tag -d <oldtag>
+ cvs update -A (or cvs update -r <previous_tag>)
+
+ Last modified: _6/13/1997_
+
+ Category: /Commands_/update_up_upd/
+
+ " + "update", "up", "upd""
+
+ 1. What is "update" for?
+
+ The "update" command is by far the most important command and is
+ probably also the most used command.
+
+ It has five purposes: (And many options.)
+
+ To display the status of your working files.
+
+ Though a plain "update" also displays the status, it does so after
+ possibly altering your working directory. To see the status of your
+ working files without changing anything, type:
+
+ cvs -n update {optional list of files}
+
+ To merge changes made by others to the branch you are working on
+ into your working files.
+
+ Each working directory is attached to a branch, usually the Main
+ branch. To merge changes made on your working branch since your last
+ checkout, update or commit, type:
+
+ cvs update {optional list of files}
+
+ To merge changes made on another branch into the branch you are
+ working on (your "working branch").
+
+ If you want to grab a whole branch, from the branch point, which is
+ assumed to be on the Main Branch, to the end of the branch, you type:
+
+ cvs update -j <branch_tag> {optional files}
+
+ If you want to grab the changes made between two tags or revisions,
+ you type:
+
+ cvs update -j <tag1> -j <tag2> {optional files}
+
+ (If you are working with a single file, the Tags could also be
+ revisions numbers. Unless you take great care to match revision
+ numbers across different files (a waste of time given the way Tags
+ work), using revision numbers in place of the Tags for multiple files
+ would be meaningless.)
+
+ To move your working directory to another branch.
+
+ A working directory is presumed to be attached to (or working on) a
+ particular branch, usually the Main branch. To alter what CVS believes
+ to be your working branch, you "move" to that branch.
+
+ To move to a tagged branch, type:
+
+ cvs update -r <branch_tag> {optional files}
+
+ To move to the Main Branch, type:
+
+ cvs update -A {optional files}
+
+ If you have modified files in your working directory, this is not a
+ clean move. CVS will attempt to merge the changes necessary to make it
+ look like you made the same changes to the new branch as you made in
+ the old one. But if you do this twice without resolving the merge
+ conflicts each time, you can lose work.
+
+ To retrieve old revisions of files.
+
+ This option is similar to 4 above but you are not restricted to using
+ a <branch_tag>. You may specify any revision or <tag> with '-r' and
+ get the specified revision or the tagged revision:
+
+ cvs update -r <tag/rev> {optional files}
+
+ Or you may specify any date with '-D':
+
+ cvs update -D <date> {optional files}
+
+ The '-p' option sends the revisions to standard output (normally your
+ terminal) rather than setting the "sticky" tag and changing the files.
+
+ Last modified: _6/13/1997_
+
+ 2. What do 'U', 'M' and 'C' mean when I type "update"? Are they different
+ for "cvs -n update"?
+
+ "cvs update" merges changes made to the Repository, since your last
+ "checkout", "update" or "commit", into your working files. You can
+ think of it as changing your BASE revision.
+
+ "cvs update" prints lines beginning with:
+
+ 'U' after replacing your unmodified file with a different
+ revision from the Repository.
+
+ 'M' for two different reasons:
+
+ for files you have modified that have not changed in the Repository.
+
+ after a merge, if it detected no conflicts.
+
+ 'C' after a merge, if it detected conflicts. See 2D.7 and 3P.6 for
+ more info on conflict resolution and "sticky conflicts."
+
+ "cvs -n update" shows what it *would* do, rather than doing it. Or,
+ another way of looking at it, "cvs -n update" displays the
+ relationship between your current BASE revisions (identified in your
+ ./CVS/Entries file) and the HEAD revisions (the latest revisions in
+ the Repository).
+
+ "cvs -n update" prints lines beginning with:
+
+ 'U' for files you have not modified that have changed in the
+ Repository.
+
+ 'M' for files you have modified that have not changed in the
+ Repository.
+
+ 'C' for files you have modified that have also been changed in the
+ Repository.
+
+ See 4C.6 for what the letters mean when merging in from another
+ branch. The output is almost the same for a normal update if you
+ consider the Repository as the branch and your working directory as
+ the "trunk".
+
+ Last modified: _6/13/1997_
+
+ 3. What's the difference between "update" and "checkout"?
+
+ See 3C.4 above.
+
+ Last modified: _6/13/1997_
+
+ 4. Why don't I get new files when I execute "update"?
+
+ There are six reasons for nothing to happen during an "update":
+
+ Nothing on your branch changed in the Repository.
+
+ If no one has committed anything to the branch you are working on
+ (normally the Main branch) since the last time you executed
+ "checkout", "update" or "commit", nothing will happen.
+
+ It's like shouting "xyzzy" or "plugh" in the wrong room.
+
+ You have a "sticky" non-branch <tag> or <date> attached to the
+ working files you are trying to "update".
+
+ At some time in the past you checked out or updated your directory
+ with the "-r <tag>" or "-D <date>" option. Until you do it again with
+ a different tag or date, or go back to the Main Branch with "update
+ -A", you will never again see any updates.
+
+ The ./CVS/Entries.Static file exists and you are expecting a new
+ file.
+
+ If your ./CVS administrative directory contains a file named
+ Entries.Static, no files will be checked out that aren't already in
+ the Entries or Entries.Static file.
+
+ You forgot to use the '-d' option and are looking for new
+ directories.
+
+ If you execute "update" without the '-d' option, it will not create
+ new directories that have been added to the Repository.
+
+ You typed "update" instead of "cvs update".
+
+ On most Unix systems, your disk caches are now furiously being flushed
+ by multiple update daemons, destroying performance and proving to
+ management that you need more CPU power. :-)
+
+ On HP systems you might be asked what package you want to install from
+ the "update server".
+
+ Someone removed (using "admin -o") your BASE revision (the revision
+ CVS thought you had in your working directory), then committed a
+ "replacement". CVS is now confused because the revision in the
+ Repository matches your BASE revision when the files themselves don't
+ match. See 3B.6.
+
+ Last modified: _6/13/1997_
+
+ 5. Why does "update" say 'M' both for plain modified files and for
+ successful (i.e. conflict-free) merges? Aren't they different?
+
+ A design choice. Yes, they are different internally, but that
+ shouldn't matter. Your files are in the same condition after the
+ "update" as they were before -- a "diff" will display only your
+ modifications. And you are expected to continue onward with parts two
+ and three of the normal development cycle: "emacs" (a synonym for
+ "edit" in most of the civilized world) and "commit".
+
+ Last modified: _6/13/1997_
+
+ 6. What's a "sticky conflict"? How does it know a conflict occurred?
+
+ When a "cvs update" (or an "update -j") creates a conflict, it prints
+ a 'C' and stores the timestamp of the file after the merge in a
+ special field in the ./CVS/Entries file.
+
+ This conflict indication implies that the merge command altered your
+ working file to contain conflict markers surrounding the overlapping
+ code segments. For example, say that
+
+ - Two developers acquire revision 1.2 of <file> via "checkout" or
+ "update".
+
+ - Developer A changes line 1 from "9999" to "5555", then commits the
+ file, creating revision 1.3.
+
+ - Developer B changes line 1 from "9999" to "7777", then tries to
+ commit the file, but is blocked because the file is not up to date.
+ Developer B then runs "update" and sees the conflict marker 'C'. The
+ beginning of the file would look like this:
+
+ <<<<<<< <file> The working <file> in question.
+ 7777 Change made to the working <file>.
+ =======
+ 5555 Change made in the first commit (1.3)
+ >>>>>>> 1.3 The revision created by the first commit.
+
+ The conflict is "sticky", which means that until the conflict is
+ cleared, the "update" command will continue to display the file's
+ status as 'C' and the "status" command will show the file's status as
+ "Unresolved Conflict".
+
+ Until the conflict is cleared, "commit" is blocked for this file.
+
+ The sticky conflict indicator can be cleared by:
+
+ Resolving the conflict by editing the file. Two things must happen
+ before the conflict is considered resolved:
+
+ The timestamp of the file must change. *and* The file must contain no
+ conflict markers. (The string searched for in the file is the regexp:
+ "^>>>>>>> ".)
+
+ After clearing the sticky conflict indicator, you may then commit the
+ file normally.
+
+ Removing the file and running "update". This throws away the local
+ changes and accepts the latest committed file on this branch. No
+ commit is needed.
+
+ Forcing the commit to happen by using "commit -f". This is probably
+ a mistake since there are few lines of real text that begin with
+ ">>>>>>> ".
+
+ Last modified: _6/13/1997_
+
+ 7. Is there a feature to tell me what I have changed, added and removed
+ without changing anything?
+
+ The command "cvs -n update" will do exactly that.
+
+ Last modified: _6/13/1997_
+
+ 8. Why were all my files deleted when I executed "update"?
+
+ You probably executed "update -r <tag>" some time ago, then removed
+ <tag> from the Repository files. "update -r <tag>" will delete a file
+ that doesn't contain <tag>.
+
+ A way to fix this is to "cd" into your working directory and type:
+
+ cvs update -A
+
+ If you don't want the latest revisions on the Main (or Vendor) Branch,
+ then decide what Tag (normal or branch) you want and type:
+
+ cvs update -r <the_tag_you_want>
+
+ Another way to make a file disappear is to execute "update -D <date>"
+ where <date> is before the date stamped onto the first revision in the
+ RCS file.
+
+ Last modified: _6/13/1997_
+
+ Category: /Past__Future_/
+
+ " Past & Future "
+
+ Category: /Past__Future_/Bugs_and_Patches/
+
+ " + Bugs and Patches"
+
+ 1. Why can't CVS handle deletion of directories?
+
+ An oversight, probably. [[Fixed in a future release?]]
+
+ Last modified: _6/13/1997_
+
+ 2. Why can't CVS handle the moving of sources from one place in the
+
+ directory hierarchy to another?
+
+ A "renaming database" has been proposed to track the history of
+ pathname changes in the Repository. A general solution is a difficult
+ problem. See 4B.8.
+
+ Last modified: _6/13/1997_
+
+ 3. When I typed "cvs update -D <date>", why did it check out all
+
+ sorts of ancient files from the Attic? Shouldn't it just create the
+ set of files and revisions that existed at that date?
+
+ This seems to be a bug, but is really the lack of any obvious place to
+ store the date when a file is "removed".
+
+ There are four ranges of dates that CVS has to deal with when trying
+ to determine what revision was available on <date>:
+
+ Dates before the earliest revision in the file.
+
+ Dates between any two revisions in the file.
+
+ Dates between the latest revision in the file and the date when the
+ file was moved to the Attic by "commit".
+
+ Dates after moving the file to the Attic.
+
+ Since the date when a file is moved to the Attic is not stored
+ anywhere, CVS can't tell the difference between #3 and #4. To avoid
+ not producing a file that should exist in case #3, it produces
+ extraneous files in case #4.
+
+ For the above reason, if you have removed files in the Attic, it is
+ better to use "-r <tag>, or even "-r HEAD" than to use a date spec.
+
+ If you must use "-D <date>", then you should either archive and delete
+ Attic files (losing some past history) or construct your Makefiles to
+ work with an explicit list of files and let the old source files stay
+ in the working directory. The contents of the revision-controlled
+ Makefile can then be considered to contain deletion "information".
+
+ Last modified: _6/13/1997_
+
+ 4. When I typed "cvs update -D <date>" in my branch, why did it screw up
+ all my files?
+
+ Currently, the internal routine ("version_ts") that looks up info
+ about a file, overrides both the tag and date if *either* the tag or
+ date is specified on the command line. If only the date is specified,
+ it should not override a branch tag, but it does.
+
+ In CVS 1.3, the documented "-D <branch_tag>:<date>" syntax only works
+ with the Main Branch and the Vendor Branch.
+
+ [[Is this fixed in CVS 1.4? This is one item I didn't check.]]
+
+ Last modified: _6/13/1997_
+
+ 5. When I executed "checkout" into an existing directory I got "No such
+ file or directory" errors. Why?
+
+ Though the man page says that "checkout" turns into an "update -d" in
+ directories that already exist, it is referring to directories that
+ already exist *and* were created by CVS.
+
+ When you try to run "checkout" on top of an existing directory
+ structure, some of which wasn't created by CVS, it will handle
+ directories and non-CVS files within directories already under CVS,
+ but it will display the above error on non-CVS files within non-CVS
+ directories.
+
+ Last modified: _6/13/1997_
+
+ 6. Why does "update" send all output to the terminal after 26 files have
+ been updated?
+
+ CVS uses the "tmpnam()" function to generate temporary file names. The
+ ANSI standard for the "tmpnam()" function says:
+
+ "The tmpnam function generates a different string each time it is
+ called, up to TMP_MAX times. If it is called more than TMP_MAX times,
+ the behavior is implementation defined."
+
+ Later it says that the value of "TMP_MAX shall be at least 25."
+
+ On some platforms, the above specification is taken literally by
+ turning "at least 25" into "exactly 26" and by doing something foolish
+ (i.e. "implementation defined") after that. Some systems return the
+ same name repeatedly, which causes one form of trouble. Others return
+ NULL or garbage, which causes a different form of trouble.
+
+ The broken systems appear to be cycling a single character through the
+ alphabet. SunOS cycles 3 characters through the alphabet, so it won't
+ cause trouble until 26 cubed or 17576 calls to "tmpnam()".
+
+ Since CVS doesn't depend on the exact format of the tmp files, the
+ workaround is to provide a "tmpnam()" that doesn't have a limit on the
+ number of calls to it.
+
+ Last modified: _6/13/1997_
+
+ 7. Why does the merge occasionally resurrect lines of code?
+
+ The diff3 program provided by GNU diff version 1.15 has a bug that
+ occasionally causes text to come back from the dead.
+
+ This is an old problem which you can avoid by upgrading to the latest
+ GNU "diffutils" package. If you were using GNU diff version 1.15 and
+ plan to upgrade to the latest GNU diff program, see the next question.
+
+ Last modified: _6/13/1997_
+
+ 8. Why does the merge fail when my "rcsmerge" program is configured to use
+ GNU diff version 2.1 or later?
+
+ A change in the overlap format was introduced in GNU diff3 between
+ versions 2.0 and 2.1 that causes RCS versions before 5.6.0.1 to fail
+ during a merge.
+
+ To get consistent rcsmerge behavior, you have four choices:
+
+ Go back to using GNU diff 1.15 or 2.0 with RCS versions 5.5 or 5.6.
+ If you want to use GNU diff 2.1 or later, you'll have to pick one of
+ the other three choices in this list.
+
+ Grab RCS version 5.6.0.1 from an FSF archive and set the DIFF3_A
+ macro to '1' as it tells you to in the Makefile:
+
+ #define DIFF3_A 1
+
+ Patch the RCS 5.6 source. Change line 84 in "merger.c" from:
+
+ DIFF3, "-am", "-L", label[0], "-L", label[1], to DIFF3, "-amE", "-L",
+ label[0], "-L", "", "-L", label[1],
+
+ Wait both for RCS version 5.7 to be released and for a new version
+ of CVS that can deal with it.
+
+ Last modified: _6/13/1997_
+
+ Category: /Past__Future_/Contributors/
+
+ " + Contributors"
+
+ 1. Who wrote CVS?
+
+ Brian Berliner <berliner@sun.com> converted a collection of scripts
+ written by Dick Grune <dick@cs.vu.nl> into a C program, then added all
+ sorts of features. He continues to maintain CVS.
+
+ Jeff Polk <polk@bsdi.com> wrote much of the code added between
+ revisions 1.2 and 1.3. Many others were involved at some level.
+
+ david d zuhn <zoo@armadillo.com> fixed a number of bugs, added some of
+ the new features, reworked the whole thing to be more portable, and
+ provided much of the energy to push CVS 1.4 out the door.
+
+ Jim Kingdon implemented CVS 1.5's remote repository access features,
+ fixed many bugs, and managed the release of version 1.5.
+
+ Take a look at the README and the ChangeLog files in the CVS sources
+ for more contributors.
+
+ Last modified: _6/13/1997_
+
+ 2. You didn't write all of this FAQ, did you?
+
+ In the original hunt for questions to answer (performed in Jan/Feb,
+ 1993), I polled hundreds of people and I rephrased all sorts of text
+ found on the net. Between 2/93 and 10/93, I released about 20
+ versions, with corrections and additions from the info-cvs mailing
+ list and private correspondence.
+
+ Between 10/93 and 10/94 I extracted frequently asked questions from
+ the 1200 mail messages to the info-cvs mailing list, turned them into
+ focused questions and tried to answer them.
+
+ 93/02/?? ~4000 lines 93/06/?? ~5000 lines 93/10/23 7839 lines 278K
+ 94/10/29 9856 lines 360K 95/05/09 9981 lines 365K
+
+ Because there are so many posers of questions, I will list only those
+ who contribute answers or help significantly with the content and
+ structure of this document.
+
+ If I used someone else's text verbatim, I mentioned it in the given
+ answer. The people whose email postings have added to this document or
+ who have added to my understanding are:
+
+ Brian Berliner <berliner@sun.com>, CVS maintainer. Paul Eggert
+ <eggert@twinsun.com>, RCS maintainer.
+
+ Gray Watson <gray@antaire.com> Per Cederqvist <ceder@signum.se> Pete
+ Clark <pclark@is.com>
+
+ all of whom have sent me copies of their tutorials and local CVS
+ documentation.
+
+ Additional contributors, who have sent me ideas, text, corrections and
+ support include (in alphabetical order):
+
+ Per Abrahamsen <amanda@iesd.auc.dk> Donald Amby
+ <amby@mixcom.mixcom.com> Mark D Baushke <mdb@cisco.com> Jim Blandy
+ <jimb@cyclic.com> Tom Cunningham <tomc@bouwsma,sps.mot.com> Graydon
+ Dodson <grdodson@lexmark.com> Joe Drumgoole
+ <joed@splatter.demon.co.uk> Don Dwiggins <dwig@markv.com> Bryant
+ Eastham <bryant@ced.utah.edu> Dan Franklin <dan@diamond.bbn.com>
+ Michael Ganzberger <ganzbergermd@ES.net> Steve Harris
+ <vsh%etnibsd@uunet.uu.net> Erik van Linstee
+ <linstee@dutecaj.et.tudelft.nl> Jeffrey M Loomis <jml@world.std.com>
+ Barry Margolin <barmar@near.net> Mark K. Mellis <mkm@ncd.com> Chris
+ Moore <Chris.Moore@src.bae.co.uk> Gary Oberbrunner <garyo@avs.com>
+ Steve Turner <stevet@carrier.sps.mot.com> Dave Wolfe
+ <dwolfe@pffft.sps.mot.com> Dale Woolridge <dwoolridge@cid.aes.doe.ca>
+
+ Please send corrections. If I forgot you, remind me and I'll add your
+ name to the list.
+
+ Last modified: _6/13/1997_
+
+ Category: /Past__Future_/Development/
+
+ " + Development"
+
+ 1. Where do I send bug reports?
+
+ First make sure it is a bug. Talk to your friends, coworkers and
+ anyone you know who uses CVS. Search this FAQ for related issues. Then
+ test it carefully. Try out variations to narrow down the problem. Make
+ sure it is repeatable. Look for workarounds so you can report them.
+
+ If you are still sure it's a bug and you tried to fix it, skip to the
+ next question. Otherwise, send a message to the info-cvs mailing list
+ containing one of the following:
+
+ If you have a good repeatable case and you think you know what is
+ going on, then describe the problem in detail. Include a workaround if
+ you have one.
+
+ If you have no idea what is going on, go ahead and send a question
+ to the info-cvs mailing list. Include any information you have
+ describing the symptoms.
+
+ Last modified: _6/13/1997_
+
+ 2. Where do I send fixes and patches?
+
+ First make sure the "fix" does something useful. Have someone review
+ your fix. Spend a bit of one person's time in a detailed analysis of
+ your vast idea before displaying a half-vast idea to hundreds of
+ people.
+
+ If you tried to fix it and the patch is small, include the patch in
+ your message. Make sure the patch is based on the latest released
+ version of CVS.
+
+ If you tried to fix it and the patch is large, you should think about
+ why it is so large. Did you add a generally useful feature, or did it
+ grow out of hand?
+
+ If you still believe it is solid, produce a patch file using the CVS
+ commands "patch" or "diff -c". [[You *are* keeping CVS under CVS,
+ right?]] The patch should be based on the latest released version of
+ CVS. Then use the "cvsbug" program (provided with the CVS sources) to
+ send it to the CVS maintainers. A self-contained patch that provides a
+ single useful feature or correction might show up independently in the
+ patches directory of the FTP archive.
+
+ If careful testing reveals an RCS bug rather than a CVS bug, you can
+ send bug reports to: rcs-bugs@cs.purdue.edu
+
+ Last modified: _6/13/1997_
+
+ 3. Where do I send ideas for future development?
+
+ If you have a bright idea, discuss it on the info-cvs mailing list. If
+ you have the time to implement something you can test, send the diffs
+ along too as described above.
+
+ Last modified: _6/13/1997_
+
+ 4. What plans are there for new features?
+
+
+
+A "rename" or "per-directory" database has been bandied about on
+the net for years. Many of the goals of the rename database have
+been achieved by the so-called "death support" in recent versions of
+CVS (such as 1.9). For more information on what may remain to be
+done, see item #189 in the TODO file of a development version of CVS.
+
+CVS version 1.5 supports remote repository access, but Paul
+Kunz has produced another version
+(rCVS) that also runs remotely. Note that as far as I know there
+are no advantages to rCVS over the remote CVS in CVS 1.5 and later,
+and the rCVS user community has migrated to remote CVS.
+rCVS is *not* a multisite CVS (see item #186 in TODO for more on
+multisite). For more on rCVS, see
+
+ftp://ftp.slac.stanford.edu/software/rcvs
+
+kingdon@cyclic.com
+
+ Last modified: _9/6/1997_
+
+ 5. I have some time and I'd like to help. What can I do for you?
+
+
+ You can review this document, correct errors and fill in any of
+ the incomplete sections.
+
+ You can write scripts or CVS add-ons and make them available by
+ web/FTP/etc.
+
+ You could work on the regression test suite (src/sanity.sh in the
+ CVS source distribution).
+
+ You can write specs for new features, fix bugs, review the
+ documentation or . . .
+
+ For more information, see the files HACKING and DEVEL-CVS in the
+ CVS source distribution or
+ http://www.cyclic.com/cyclic-pages/cvsdev.html
+
+ kingdon@cyclic.com
+
+ Last modified: _9/6/1997_
+
+ Category: /Past__Future_/Professional_Support/
+
+ " + Professional Support"
+
+ 1. Doesn't Cygnus support CVS?
+
+
+
+
+ Cygnus is a company that supports free software such as the GCC
+ compiler. They have never sold support for CVS, however. They
+ do use CVS internally and have contributed much code to CVS over
+ the years (for which CVS users should be grateful).
+
+ kingdon@cyclic.com
+
+ Last modified: _9/6/1997_
+
+ 2. What is Cyclic Software doing with CVS?
+
+
+Cyclic Software exists to provide support for CVS. For details such
+as prices and what this covers, see http://www.cyclic.com or ask
+info@cyclic.com.
+
+kingdon@cyclic.com
+
+ Last modified: _9/6/1997_
+
+ Category: /User_Tasks_/
+
+ " User Tasks "
+
+ Category: /User_Tasks_/Common_User_Tasks/
+
+ " + Common User Tasks"
+
+ 1. What is the absolute minimum I have to do to edit a file?
+
+ Tell your Repository Administrator to create a module covering the
+ directory or files you care about. You will be told that your module
+ name is <module>. Then type:
+
+ cvs checkout <module>
+ cd <module>
+ emacs <file> # Isn't Emacs a synonym for edit?
+ cvs commit <file>
+
+ If you don't use modules (in my opinion, a mistake), you can check out
+ a directory by substituting its relative path within the Repository
+ for <module> in the example above.
+
+ To work on a single file, you'll have to change "cd <module>" to "cd
+ `dirname <module>`".
+
+ Last modified: _6/13/1997_
+
+ 2. If I edit multiple files, must I type "commit" for each one?
+
+ No. You can commit a list of files and directories, including relative
+ paths into multiple directories. You can also commit every modified
+ file in the current directory or in all directories and subdirectories
+ from your current directory downward. See 3D.2.
+
+ Last modified: _6/13/1997_
+
+ 3. How do I get rid of the <module> directory that "checkout" created?
+
+ Change your directory to be the same as when you executed the
+ "checkout" command that created <module>.
+
+ If you want to get rid of the CVS control information, but leave the
+ files and directories, type:
+
+ cvs release <module>
+
+ If you want to obliterate the entire directory, type:
+
+ cvs release -d <module>
+
+ ("release -d" searches through the output of "cvs -n update" and
+ refuses to continue if the "update" command finds any modified files
+ or non-ignored foreign files. Foreign directories too.)
+
+ If you don't care about keeping "history", or checking for modified
+ and foreign files, you can just remove the whole directory. That's "rm
+ -rf <module>" under Unix.
+
+ Last modified: _6/13/1997_
+
+ 4. How do I find out what has changed since my last update?
+
+ There are many ways to answer this.
+
+ To find out what you've changed in your current working directory
+ since your last checkout, update or commit, type:
+
+ cvs diff
+
+ To find out what other people have added (to your branch) since you
+ last checked out or updated, type:
+
+ cvs diff -r BASE -r HEAD
+
+ To look at a revision history containing the comments for all changes,
+ you can use the "log" command.
+
+ You can also use "history" to trace a wide variety of events.
+
+ Last modified: _6/13/1997_
+
+ 5. I just created a new file. How do I add it to the Repository?
+
+ The "update" command will mark files CVS doesn't know about in your
+ working directory with a '?' indicator.
+
+ ? <file>
+
+ To add <file> to the Repository, type:
+
+ cvs add <file>
+ cvs commit <file>
+
+ See 3A.[2-5] and 4C.8 for branch and merge considerations.
+
+ Last modified: _6/13/1997_
+
+ 6. How do I merge changes made by others into my working directory?
+
+ If you are asking about other branches, see Section 4C on "Branching".
+ You will have to use the "update -j" command.
+
+ Retrieving changes made to the Repository on the *same* branch you are
+ working on is the main purpose of the "update" command. The "update"
+ command tries to merge work committed to the Repository by others
+ since you last executed "checkout", "update" or "commit" into your
+ working files.
+
+ For a single file, there are six possible results when you type the
+ "update" command:
+
+ If the file is lying in your working directory, but is not under
+ CVS, it will do nothing but print:
+
+ ? <file>
+
+ If neither you nor anyone else has committed changes to <file>,
+ since your last "checkout", "update" or "commit", "update" will print
+ nothing and do nothing.
+
+ If you have made no changes to a working file, but you or others
+ have committed changes to the Repository since your last "checkout",
+ "update" or "commit" of this working file, CVS will remove your
+ working file and replace it with a copy of the latest revision of that
+ file in the Repository. It will print:
+
+ U <file>
+
+ You might want to examine the changes (using the CVS "diff" command)
+ to see if they mesh with your own in related files.
+
+ If you have made changes to a working file, but no one has changed
+ your BASE revision (the revision you retrieved from the Repository in
+ your last "checkout", "update" or "commit"), "update" will print:
+
+ M <file>
+
+ Nothing changes. You were told that you have a modified file in your
+ directory.
+
+ If you have made changes to your working file and you or others have
+ committed changes to the Repository, but in different sections of the
+ file, CVS will merge the changes stored in the Repository since your
+ last "checkout", "update" or "commit" into your working file. "update"
+ will print:
+
+ RCS file: /Repository/module/<file> retrieving revision 1.X retrieving
+ revision 1.Y Merging differences between 1.X and 1.Y into <file> M
+ <file>
+
+ If you execute "diff" before and after this step, you should see the
+ same output, since both the base file and your working file changed in
+ parallel. This is one of the few times the otherwise nonsensical
+ phrase "same difference" means something.
+
+ If both you and those who committed files (since your last checkout,
+ update or commit) have made changes to the same section of a file, CVS
+ will merge the changes into your file as in #5 above, but it will
+ leave conflict indicators in the file. "update" will print:
+
+ RCS file: /Repository/module/<file> retrieving revision 1.X retrieving
+ revision 1.Y Merging differences between 1.X and 1.Y into <file>
+ rcsmerge warning: overlaps during merge
+ cvs update: conflicts found in <file>
+ C <file>
+
+ This is a "conflict". The file will contain markers surrounding the
+ overlapping text. The 'C' conflict indicator is sticky -- subsequent
+ "update" commands will continue to show a 'C' until you edit the file.
+
+ You must examine the overlaps with care and resolve the problem by
+ analyzing how to retain the features of both changes. See 2D.7 and
+ 3P.6 for more details on conflict resolution.
+
+ Last modified: _6/13/1997_
+
+ 7. How do I label a set of revisions so I can retrieve them later?
+
+ To "tag" the BASE revisions (the ones you last checked out, updated,
+ or committed) you should "cd" to the head of the working directory you
+ want to tag and type:
+
+ cvs tag <tag>
+
+ It recursively walks through your working directory tagging the BASE
+ revisions of all files.
+
+ To "tag" the latest revision on the Main branch in the Repository, you
+ can use the following from anywhere: (No "cd" is required -- it works
+ directly on the Repository.)
+
+ cvs rtag <tag> <module>
+
+ Last modified: _6/13/1997_
+
+ 8. How do I checkout an old release of a module, directory or file?
+
+ Module names and directories are simply ways to name sets of files.
+ Once the names are determined, there are 6 ways to specify which
+ revision of a particular file to check out:
+
+ By tag or symbolic name, via the "-r <tag>" option.
+
+ By date, via the "-D <date>" option.
+
+ By branch tag (a type of tag with a magic format), via the "-r
+ <branch_tag>" option.
+
+ By date within a branch, via the "-r <branch_tag>:<date>" option.
+
+ By an explicit branch revision number ("-r <rev>"), which refers to
+ the latest revision on the branch. This isn't really an "old"
+ revision, from the branch's perspective, but from the user's
+ perspective the whole branch might have been abandoned in the past.
+
+ An explicit revision number: "-r <rev>" Though this works, it is
+ almost useless for more than one file.
+
+ You type:
+
+ cvs checkout <option-specified-above> <module>
+ cd <module>
+
+ Last modified: _6/13/1997_
+
+ 9. What do I have to remember to do periodically?
+
+ You should execute "cvs -n update" fairly often to keep track of what
+ you and others have changed. It won't change anything -- it will just
+ give you a report.
+
+ Unless you are purposely delaying the inclusion of others' work, you
+ should execute "update" once in a while and resolve the conflicts. It
+ is not good to get too far out of sync with the rest of the developers
+ working on your branch.
+
+ It is assumed that your system administrators have arranged for editor
+ backup and Unix temp files (#* and .#*) to be deleted after a few
+ weeks. But you might want to look around for anything else that is
+ ignored or hidden. Try "cvs -n update -I !" to see all the ignored
+ files.
+
+ If you are the Repository Administrator, see 4B.16 on Administrator
+ responsibilities.
+
+ Last modified: _6/13/1997_
+
+ Category: /User_Tasks_/General_Questions/
+
+ " + General Questions"
+
+ 1. How do I see what CVS is trying to do?
+
+ The '-t' option on the main "cvs" command will display every external
+ command (mostly RCS commands and file deletions) it executes. When
+ combined with the '-n' option, which prevents the execution of any
+ command that might modify a file, you can see what it will do before
+ you let it fly. The '-t' option will *not* display every internal
+ action, only calls to external programs.
+
+ To see a harmless example, try typing:
+
+ cvs -nt update
+
+ Some systems offer a "trace" or "truss" command that will display all
+ system calls as they happen. This is a *very* low-level interface that
+ does not normally follow the execution of external commands, but it
+ can be useful.
+
+ The most complete answer is to read the source, compile it with the
+ '-g' option and step through it under a debugger.
+
+ Last modified: _6/13/1997_
+
+ 2. If I work with multiple modules, should I check them all out and commit
+ them occasionally? Is it OK to leave modules checked out?
+
+ The simple answers are "Yes."
+
+ There is no reason to remove working directories, other than to save
+ disk space. As long as you have committed the files you choose to make
+ public, your working directory is just like any other directory.
+
+ CVS doesn't care whether you leave modules checked out or not. The
+ advantage of leaving them checked out is that you can quickly visit
+ them to make and commit changes.
+
+ Last modified: _6/13/1997_
+
+ 3. What is a "sticky" tag? What makes it sticky? How do I loosen it?
+
+ When you execute "update -r <tag>", CVS remembers the <tag>. It has
+ become "sticky" in the sense that until you change it or remove it,
+ the tag is remembered and used in references to the file as if you had
+ typed "-r <tag>" on the command line.
+
+ It is most useful for a <branch_tag>, which is a sticky tag indicating
+ what branch you are working on.
+
+ A revision number ("-r <rev-number>") or date ("-D <date>") can also
+ become sticky when they are specified on the command line.
+
+ A sticky tag, revision or date remains until you specify another tag,
+ revision or date the same way. The "update -A" command moves back to
+ the Main branch, which has the side-effect of clearing all sticky
+ items on the updated files.
+
+ The "checkout" command creates sticky tags, revisions and dates the
+ same way "update" does.
+
+ Also, the '-k' option records a "sticky" keyword option that is used
+ in further "updates until "update -A" is specified.
+
+ Last modified: _6/13/1997_
+
+ 4. How do I get an old revision without updating the "sticky tag"?
+
+ Use the '-p' option to "pipe" data to standard output. The command
+ "update -p -r <tag/rev>" sends the selected revision to your standard
+ output (usually the terminal, unless redirected). The '-p' affects no
+ disk files, leaving a "sticky tag" unaltered and avoiding all other
+ side-effects of a normal "update".
+
+ If you want to save the result, you can redirect "stdout" to a file
+ using your shell's redirection capability. In most shells the
+ following command works:
+
+ cvs update -p -r <tag/rev> filename > diskfile
+
+ Last modified: _6/13/1997_
+
+ 5. What operations disregard sticky tags?
+
+ The functions that routinely disregard sticky tags are:
+
+ Those that work directly on the Repository or its administrative
+ files:
+
+ admin rtag log status remove history
+
+ Those that take Tags or revisions as arguments and ignore everything
+ else: (They also never *set* a sticky tag.)
+
+ rdiff import export
+
+ The "release" command itself ignores sticky tags, but it calls "cvs
+ -n update" (which *does* pay attention to a sticky tag) to figure out
+ what inconsistencies exist in the working directory. If no
+ discrepancies exist between the files you originally checked out
+ (possibly marked by a sticky tag) and what is there now, "release -d"
+ will delete them all.
+
+ The "tag" command works on the revision lying in the working
+ directory however it got there. That the revision lying there might
+ happen to have a sticky tag attached to it is not the "tag" command's
+ concern.
+
+ The main function that *does* read and write sticky tags is the
+ "update" command. You can avoid referring to or changing the sticky
+ tag by using the '-p' option, which sends files to your terminal,
+ touching nothing else.
+
+ The "checkout" command sets sticky tags when checking out a new module
+ and it acts like "update" when checking out a module into an existing
+ directory.
+
+ The "diff" and "commit" commands use the sticky tags, unless
+ overridden on the command line. They do not set sticky tags. Note that
+ you can only "commit" to a file checked out with a sticky tag, if the
+ tag identifies a branch.
+
+ There are really two types of sticky tags, one attached to individual
+ files (in the ./CVS/Entries file) and one attached to each directory
+ (in the ./CVS/Tag file). They can differ.
+
+ The "add" command registers the desire to add a new file. If the
+ "directory tag" (./CVS/Tag) file exists at the time of the "add", the
+ value stored in ./CVS/Tag becomes the "sticky tag" on the new file.
+ The file doesn't exist in the Repository until you "commit" it, but
+ the ./CVS/Entries file holds the sticky tag name from the time of the
+ "add" forward.
+
+ Last modified: _6/13/1997_
+
+ 6. Is there a way to avoid reverting my Emacs buffer after committing a
+ file? Is there a "cvs-mode" for Emacs?
+
+ See Section 4F.1
+
+ Last modified: _6/13/1997_
+
+ 7. How does conflict resolution work? What *really* happens if two of us
+ change the same file?
+
+ While editing files, there is no conflict. You are working on separate
+ copies of the file stored in the virtual "branch" represented by your
+ working directories. After one of you commits a file, the other may
+ not commit the same file until "update" has merged the earlier
+ committed changes into the later working file.
+
+ For example, say you both check out rev 1.2 of <file> and make change
+ to your working files. Your coworker commits revision 1.3. When you
+ try to commit your file, CVS says:
+
+ cvs commit: Up-to-date check failed for `<file>'
+
+ You must merge your coworker's changes into your working file by
+ typing:
+
+ cvs update <file>
+
+ which will produce the output described in 2B.6.
+
+ If a conflict occurs, the filename will be shown with a status of 'C'.
+ After you resolve any overlaps caused by the merging process, you may
+ then commit the file. See 3P.6 for info on "sticky conflicts".
+
+ Even if you get a simple 'M', you should examine the differences
+ before committing the file. A smooth, error-free text merge is still
+ no indication that the file is in proper shape. Compile and test it at
+ least.
+
+ The answer to two obvious questions is "Yes".
+
+ Yes, the first one who commits avoids the merge. Later developers have
+ to merge the earlier changes into their working files before
+ committing the merged result. Depending on how difficult the merge is
+ and how important the contending projects are, the order of commits
+ and updates might have to be carefully staged.
+
+ And yes, between the time you execute "update" and "commit" (while you
+ are fixing conflicts and testing the results) someone else may commit
+ another revision of <file>. You will have to execute "update" again to
+ merge the new work before committing. Most organizations don't have
+ this problem. If you do, you might consider splitting the file. Or
+ hiring a manager.
+
+ Last modified: _6/13/1997_
+
+ 8. How can I tell who has a module checked out?
+
+ If you "checkout" module names (not relative pathnames) and you use
+ the release command, the "history" command will display active
+ checkouts, who has them and where they were checked out. It is
+ advisory only; it can be circumvented by using the '-l' option on the
+ main "cvs" command.
+
+ Last modified: _6/13/1997_
+
+ 9. Where did the .#<file>.1.3 file in my working directory come from?
+
+ It was created during an "update" when CVS merged changes from the
+ Repository into your modified working file.
+
+ It serves the same purpose as any "backup" file: saving your bacon
+ often enough to be worth retaining. It is invaluable in recovering
+ when things go wrong.
+
+ Say Developers A (you) and B check out rev 1.3 of file <file>. You
+ both make changes -- different changes. B commits first, so <file>,v
+ in the Repository contains revisions up through 1.4.
+
+ At this point, there are 5 (yes, five) versions of the file of
+ interest to you:
+
+ Revision 1.3 (What you originally checked out.)
+
+ Revision 1.4 (What you need from developer B.)
+
+ Your old working file. (Before the update.)
+
+ Your new working file. (After the merge caused by "update".)
+
+ Revision 1.5 (Which you will commit shortly.)
+
+ In the case where your working file was not modified, #1 and #3 will
+ be the same, as will #2 and #4. In this degenerate case, there is no
+ need to create #5. The following assumes that your working file was
+ modified.
+
+ If the merge executed by the "update" caused no overlaps, and you
+ commit the file immediately, #4 and #5 will be the same. But you can
+ make arbitrary changes before committing, so the difference between #4
+ and #5 might be more than just the correction of overlaps. In general,
+ though, you don't need #4 after a commit.
+
+ But #3 (which is the one saved as ".#<file>.1.3") holds all of your
+ work, independent of B's work. It could represent a major effort that
+ you couldn't afford to lose. If you don't save it somewhere, the merge
+ makes #3 *disappear* under a potential blizzard of conflicts caused by
+ overlapping changes.
+
+ I have been saved a few times, and others I support have been saved
+ hundreds of times, by the ability to "diff <original file> <original
+ file with only my work added>", which can be done in the example above
+ by the Unix shell command:
+
+ cvs update -p -r 1.3 <file> | diff - .#<file>.1.3
+
+ The assumption is that the ".#" files will be useful far beyond the
+ "commit" point, but not forever. You are expected to run the "normal"
+ Unix cleanup script from "cron", which removes "#*" and ".#*" files
+ older than a some period chosen by your sysadmin, usually ranging from
+ 7 to 30 days.
+
+ A question was raised about the need for #3 after #5 has been
+ committed, under the assumption that you won't commit files until
+ everything is exactly as you like them.
+
+ This assumes perfect humans, which violates one of the Cardinal rules
+ of Software Engineering: Never assume any form of discipline on the
+ part of the users of software. If restrictions are not bound into the
+ software, then you, the toolsmith, have to arrange a recovery path.
+
+ In other words, I've seen every possible variety of screwup you can
+ imagine in #5. There is no way to make assumptions about what "should"
+ happen. I've seen #5 filled with zeros because of NFS failures, I've
+ seen emacs core dumps that leave #5 in an unreasonable state, I've
+ seen a foolish developer uppercase the whole file (with his "undo"
+ size set low so he couldn't undo it) and decide that it would be less
+ work to play with the uppercased file than to blow it away and start
+ over. I've even seen committed files with conflict markers still in
+ them, a sure sign of carelessness.
+
+ There are all sorts of scenarios where having #3 is incredibly useful.
+ You can move it back into place and try again.
+
+ Last modified: _6/13/1997_
+
+ 10. What is this "ignore" business? What is it ignoring?
+
+ The "update" and "import" commands use collections of Unix wildcards
+ to skip over files and directories matching any of those patterns.
+
+ You may add to the built-in ignore list by adding lines of
+ whitespace-separated wildcards to the following places: (They are read
+ in this order.)
+
+ In a file named "cvsignore" in $CVSROOT/CVSROOT.
+
+ A Repository Administrator uses this to add site-specific files and
+ patterns to the built-in ignore list.
+
+ In a file named ".cvsignore" in your home directory.
+
+ For user-specific files. For example, if you use "__" as your default
+ junk file prefix, you can put "__*" in your .cvsignore file.
+
+ People who play around exclusively in directory trees where the
+ Makefiles are generated by "imake" or "configure" might want to put
+ "Makefile" in their ignore list, since they are all generated and
+ usually don't end up in the Repository.
+
+ In the CVSIGNORE environment variable.
+
+ For session-specific files.
+
+ Via the '-I' option on "import" or "update" commands.
+
+ For this-command-only files.
+
+ In a file named ".cvsignore" within each directory.
+
+ The contents of a ".cvsignore" file in each directory is temporarily
+ added to the ignore list. This way you can ignore files that are
+ peculiar to that directory, such as executables and other generated
+ files without known wildcard patterns.
+
+ In any of the places listed above, a single '!' character nulls out
+ the ignore list. A Repository administrator can use this to override,
+ rather than enhance, the built-in ignore list. A user can choose to
+ override the system-wide ignore list. For example, if you place "! *.o
+ *.a" in your .cvsignore file, only *.o *.a files, plus any files a
+ local-directory .cvsignore file, are ignored.
+
+ A variant of the ignore-file scheme is used internally during
+ checkout. "Module names" found in the modules file (or on the
+ "checkout" command line) that begin with a '!' are ignored during
+ checkout. This is useful to permanently ignore (if the '!' path is in
+ the modules file) or temporarily ignore (if the '!' path is on the
+ command line) a sub-directory within a Repository hierarchy. For
+ example:
+
+ cvs checkout !gnu/emacs/tests gnu/emacs
+
+ would checkout the module (or relative path within $CVSROOT) named
+ "gnu/emacs", but ignore the "tests" directory within it.
+
+ Last modified: _6/13/1997_
+
+ 11. Is there a way to set user-specific configuration options?
+
+ User-specific configuration is available through use of a ".cvsrc"
+ file in your home directory.
+
+ CVS searches the first column of your ~/.cvsrc file for the cvs
+ command name you invoked. If the command is found, the rest of the
+ line is treated like a set of command line options, stuffed into the
+ command line before the arguments you actually typed.
+
+ For example, if you always want to see context diffs and you never
+ want to have to delete a file before you run "cvs remove", then you
+ should create a .cvsrc file containing the following:
+
+ diff -c
+ remove -f
+
+ which will add the given options to every invocation of the given
+ commands.
+
+ [[The rest of this will be removed someday, when CVS changes.]]
+
+ I would like to stop here with a comment that the command name to use
+ is the full, canonical one. But the command that the cvsrc support
+ uses is the string you typed on the command line, not the proper
+ command. So to get the full effect of the above example, you should
+ also add all the alternate command names:
+
+ di -c
+ dif -c
+ rm -f
+ delete -f
+
+ There are two other limitations that will probably be fixed when CVS
+ sprouts long option names:
+
+ It only affects options made available on the command line.
+
+ There is a limited number of short options. With long option names,
+ there is no problem. You can have as many long options as you like,
+ affecting anything that looks malleable.
+
+ The existing command line options do not come in on/off pairs, so
+ there is no easy way to override your ~/.cvsrc configuration for a
+ single invocation of a command.
+
+ Choosing a good set of long option pairs would fix this.
+
+ Last modified: _6/13/1997_
+
+ 12. Is it safe to interrupt CVS using Control-C?
+
+ It depends on what you mean by "safe". ("Ah," said Arthur, "this is
+ obviously some strange usage of the word *safe* that I wasn't
+ previously aware of." -- Hitchhiker's Guide to the Galaxy)
+
+ You won't hurt the underlying RCS files and if you are executing a
+ command that only *reads* data, you will have no cleanup to do.
+
+ But you may have to hit Control-C repeatedly to stop it. CVS uses the
+ Unix "system" routine which blocks signals in the CVS parent process.
+ A single Control-C during "system" will only halt the child process,
+ usually some form of RCS command.
+
+ If you don't hit another Control-C while the CVS process has control,
+ it is likely to continue onto the next task assuming that the earlier
+ one did its job. It is not enough to hit two Control-C's. You might
+ simply kill two child processes and not interrupt CVS at all.
+ Depending on the speed of your processor, your terminal and your
+ fingers, you might have to hit dozens of Control-C's to stop the damn
+ thing.
+
+ Executing a CVS command, such as "commit" or "tag" that writes to the
+ files is a different matter.
+
+ Since CVS is not a full-fledged database, with what database people
+ call "commit points", merely stopping the process will not back out
+ the "transaction" and place you back in the starting blocks. CVS has
+ no concept of an "atomic" transaction or of "backtracking", which
+ means that a command can be half-executed.
+
+ Hitting Control-C will usually leave lock files that you have to go
+ clean up in the Repository.
+
+ Example1:
+
+ If you interrupt a multi-file "commit" in the middle of
+ an RCS checkin, RCS will leave the file either fully
+ checked-in or in its original state. But CVS might have
+ been half-way through the list of files to commit. The
+ directory or module will be inconsistent.
+
+ To recover, you must remove the lock files, then decide
+ whether you want to back out or finish the job.
+
+ To back out, you'll have to apply the "admin -o"
+ command, very carefully, to remove the newly committed
+ revisions. This is usually a bad idea, but is
+ occasionally necessary.
+
+ To finish, you can simply retype the same commit command.
+ CVS will figure out what files are still modified and
+ commit them. It helps that RCS doesn't leave a file in an
+ intermediate state.
+
+ Example2:
+
+ If you interrupt a multi-file "tag" command, you have a
+ problem similar, but not equivalent, to interrupting a
+ "commit". The RCS file will still be consistent, but
+ unlike "commit", which only *adds* to the RCS file, "tag"
+ can *move* a tag and it doesn't keep a history of what
+ revision a tag used to be attached to.
+
+ Normally, you have little choice but to re-execute the
+ command and allow it to tag everything consistently.
+
+ You might be able to recover by carefully re-applying the
+ tags via the "cvs admin -N" command, but you'll still have
+ to dig up from outside sources the information you use to
+ determine what tag was on what revision in what file.
+ the Repository, or by using the equivalent: "cvs admin".
+
+ Halting a new "checkout" should cause no harm. If you don't want it,
+ "release" (or rm -rf) it. If you do want it, re-execute the command. A
+ repeated "checkout" from above a directory acts like a repeated
+ "update -d" within it.
+
+ Halting "update" half-way will give you an unpredictable collection of
+ files and revisions. To continue, you can rerun the update and it
+ should move you forward into in a known state. To back out, you'll
+ have to examine the output from the first "update" command, take a
+ look at each file that was modified and reconstruct the previous state
+ by editing the ./CVS/Entries file and by using "cvs admin". Good Luck.
+
+ Last modified: _6/13/1997_
+
+ 13. How do I turn off the "admin" command?
+
+ In the current revision, you'd have to edit the source code.
+
+ Last modified: _6/13/1997_
+
+ 14. How do I turn off the ability to disable history via "cvs -l"?
+
+ In the current revision, you'd have to edit the source code.
+
+ Last modified: _6/13/1997_
+
+ 15. How do I keep certain people from accessing certain directories?
+
+ If you don't try to run CVS set[ug]id, you can use Unix groups and
+ permissions to limit access to the Repository.
+
+ If you only want to limit "commit" commands, you can write a program
+ to put in the "commitinfo" file. In the "contrib" directory, there are
+ a few scripts that might help you out.
+
+ Last modified: _6/13/1997_
+
+ Category: /User_Tasks_/Getting_Started/
+
+ " + Getting Started"
+
+ 1. What is the first thing I have to know?
+
+ Your organization has most likely assigned one or more persons to
+ understand, baby-sit and administer the CVS programs and the data
+ Repository. I call these persons Repository Administrators. They
+ should have set up a Repository and "imported" files into it.
+
+ If you don't believe anyone has this responsibility, or you are just
+ testing CVS, then *you* are the Repository Administrator.
+
+ If you are a normal user of CVS ask your Repository Administrator what
+ module you should check out.
+
+ Then you can work.
+
+ If you *are* the Repository Administrator, you will want to read
+ everything you can get your hands on, including this FAQ. Source
+ control issues can be difficult, especially when you get to branches
+ and release planning. Expect to feel stupid for a few days/weeks.
+
+ No tool in the universe avoids the need for intelligent organization.
+ In other words, there are all sorts of related issues you will
+ probably have to learn. Don't expect to dive in without any
+ preparation, stuff your 300 Megabytes of sources into CVS and expect
+ to start working. If you don't prepare first, you will probably spend
+ a few sleepless nights.
+
+ Last modified: _6/13/1997_
+
+ 2. Where do I work?
+
+ Wherever you have disk space. That's one of the advantages of CVS: you
+ use the "checkout" command to copy files from the Repository to your
+ working directory, which can be anywhere you have the space.
+
+ Your local group might have conventions for where to work. Ask your
+ peers.
+
+ Last modified: _6/13/1997_
+
+ 3. What does CVS use from my environment?
+
+ You must set two environment variables. Some shells share these
+ variables with local shell variables using a different syntax. You'll
+ have to learn how your shell handles them.
+
+ Variable Value (or action)
+ --------- ---------------------
+ CVSROOT Absolute pathname of the head of your Repository.
+
+ PATH Normally set to a list of ':'-separated directory
+ pathnames searched to find executables. You must
+ make sure "cvs" is in one of the directories.
+
+ If your CVS was built with the RCSBIN directory set
+ to null (""), and you don't set the RCSBIN
+ variable mentioned below, then the RCS commands
+ also must be somewhere in your PATH.
+
+ Optional variables: (Used if set, but ignored otherwise.)
+
+ Variable Value (or action)
+ --------- ---------------------
+ CVSEDITOR The name of your favorite fast-start editor
+ program. You'll be kicked into your editor to
+ supply revision comments if you don't specify them
+ via -m "Log message" on the command line.
+
+ EDITOR Used if CVSEDITOR doesn't exist. If EDITOR
+ doesn't exist, CVS uses a configured constant,
+ usually, "vi".
+
+ CVSREAD Sets files to read-only on "checkout".
+
+ RCSBIN Changes where CVS finds the RCS commands.
+
+ CVSIGNORE Adds to the ignore list. See Section 2D.
+
+ Other variables used by CVS that are normally set upon login:
+
+ Variable Value (or action)
+ --------- ---------------------
+ LOGNAME Used to find the real user name.
+
+ USER Used to find the real user name if no LOGNAME.
+
+ HOME Used to determine your home directory, if set.
+ Otherwise LOGNAME/USER/getuid() are used to find
+ your home directory from the passwd file.
+
+ TMPDIR Used during import. It might also be used if your
+ platform's version of mktemp(3) is unusual, or
+ you have changed the source to use tmpnam(3).
+
+ Last modified: _6/13/1997_
+
+ 4. OK, I've been told that CVS is set up, my module is named "ralph" and I
+ have to start editing. What do I type?
+
+ cd <where you have some space to work>
+ cvs checkout ralph
+ cd ralph
+
+ And hack away.
+
+ Last modified: _6/13/1997_
+
+ 5. I have been using RCS for a while. Can I convert to CVS without losing
+ my revision history? How about converting from SCCS?
+
+ If you are asking such questions, you are not a mere user of CVS, but
+ one of its Administrators! You should take a look at Section 4A,
+ "Installing CVS" and Section 4B, "Setting up and Managing the
+ Repository".
+
+ Last modified: _6/13/1997_
+
+ Category: /User_Tasks_/Less_Common_User_Tas/
+
+ " + Less Common User Tasks"
+
+ 1. Can I create non-CVS sub-directories in my working directory?
+
+ Yes. Unless the directory exists in the Repository, "update" will skip
+ over them and print a '?' the way it does for files you forgot to add.
+ You can avoid seeing the '?' by adding the name of the foreign
+ directory to the ./.cvsignore file, just ask you can do with files.
+
+ If you explicitly mention a foreign directory on the "update" command
+ line, it will traverse the directory and waste a bit of time, but if
+ any directory or sub-directory lacks the ./CVS administrative
+ directory, CVS will print an error and abort.
+
+ Last modified: _6/13/1997_
+
+ 2. How do I add new sub-directories to the Repository?
+
+ The "add" command will work on directories. You type:
+
+ mkdir <dir>
+ cvs add <dir>
+
+ It will respond:
+
+ Directory /Repos/<dir> added to the repository
+
+ and will create both a matching directory in the Repository and a
+ ./CVS administrative directory within the local <dir> directory.
+
+ Last modified: _6/13/1997_
+
+ 3. How do I remove a file I don't need?
+
+ (See the questions in Section 4B on removing files from the
+ Repository.)
+
+ You type:
+
+ rm <file>
+ cvs remove <file>
+
+ CVS registers the file for removal. To complete the removal, you must
+ type:
+
+ cvs commit <file>
+
+ CVS moves the file to the Attic associated with your working
+ directory. Each directory in the Repository stores its deleted files
+ in an Attic sub-directory. A normal "checkout" doesn't look in the
+ Attic, but if you specify a tag, a date or a revision, the "checkout"
+ (or "update") command will retrieve files from the Attic with that
+ tag, date or revision.
+
+ Last modified: _6/13/1997_
+
+ 4. How do I rename a file?
+
+ CVS does not offer a way to rename a file in a way that CVS can track
+ later. See Section 4B for more information.
+
+ Here is the best (to some, the only acceptable) way to get the effect
+ of renaming, while preserving the change log:
+
+ Copy the RCS (",v") file directly in the Repository.
+
+ cp $CVSROOT/<odir>/<ofile>,v $CVSROOT/<ndir>/<nfile>,v
+
+ By duplicating the file, you will preserve the change history and the
+ ability to retrieve earlier revisions of the old file via the "-r
+ <tag/rev>" or "-D <date>" options to "checkout" and "update".
+
+ Remove the old file using CVS.
+
+ cd <working-dir>/<odir> rm <ofile>
+ cvs remove <ofile>
+ cvs commit <ofile>
+
+ This will move the <ofile> to the Attic associated with <odir>.
+
+ Retrieve <nfile> and remove all the Tags from it.
+
+ By stripping off all the old Tags, "checkout -r" and "update -r" won't
+ retrieve revisions Tagged before the renaming.
+
+ cd <working-dir>/<ndir>
+ cvs update <nfile>
+ cvs log <nfile> # Save the list of Tags
+ cvs tag -d <tag1> <nfile>
+ cvs tag -d <tag2> <nfile>
+ . . .
+
+ This technique can be used to rename files within one directory or
+ across different directories. You can apply this idea to directories
+ too, as long as you apply the above to each file and don't delete the
+ old directory.
+
+ Of course, you have to change your build system (e.g. Makefile) in
+ your <working-dir> to know about the name change.
+
+ Warning: Stripping the old tags from the copied file will allow "-r
+ <tag>" to do the right thing, but you will still have problems with
+ "-D <date>" because there is no place to store the "deletion time".
+ See 5B.3 for more details.
+
+ Last modified: _6/13/1997_
+
+ 5. How do I make sure that all the files and directories in my working
+ directory are really in the Repository?
+
+ A "cvs update", or "cvs -n update" (which won't modify your working
+ directory) will display foreign elements, which have no counterpart in
+ the Repository, preceded by a '?'. To register foreign directories,
+ you can use "cvs add". To register foreign files, you can use "cvs
+ add" followed by "cvs commit".
+
+ You could also checkout your module, or the Repository directory
+ associated with your working directory, a second time into another
+ work area and compare it to your working directory using the (non-CVS)
+ "diff -r" command.
+
+ By default many patterns of files are ignored. If you create a file
+ named "core" or a file ending in ".o", it is usually ignored. If you
+ really want to see all the files that aren't in the Repository, you
+ can use a special "ignore" pattern to say "ignore no files". Try
+ executing: (You may have to quote or backwhack (i.e. precede by '\')
+ the '!' in your shell.)
+
+ cvs -n update -I !
+
+ The above command will display not only the normal modified, update
+ and conflict indicators ('M', 'U', and 'C' respectively) on files
+ within the Repository, but it will also display each file not in the
+ Repository preceded by a '?' character.
+
+ The '-n' option will not allow "update" to alter your working
+ directory.
+
+ Last modified: _6/13/1997_
+
+ 6. How do I create a branch?
+
+ Type this in your working directory:
+
+ cvs tag -b <branch_tag>
+
+ and you will create a branch. No files have real branches in them yet,
+ but if you move onto the branch by typing:
+
+ cvs update -r <branch_tag>
+
+ and commit a file in the normal way:
+
+ cvs commit <file>
+
+ then a branch will be created in the underlying <file>,v file and the
+ new revision of <file> will appear only on that branch.
+
+ See Section 4C, on Branching.
+
+ Last modified: _6/13/1997_
+
+ 7. How do I modify the modules file? How about the other files in the
+ CVSROOT administrative area?
+
+ A module named "modules" has been provided in the default modules
+ file, so you can type:
+
+ cvs checkout modules
+ cd modules
+
+ Another module named CVSROOT has been provided in the default modules
+ file, covering all the administrative files. Type:
+
+ cvs checkout CVSROOT
+ cd CVSROOT
+
+ Then you can edit your files, followed by:
+
+ cvs commit
+
+ If you start with the provided template for the "modules" file, the
+ CVSROOT and the "modules" module will have the "mkmodules" program as
+ a "commit helper". After a file is committed to such a module,
+ "mkmodules" will convert a number of standard files (See 4B.2) in the
+ CVSROOT directory inside the Repository into a form that is usable by
+ CVS.
+
+ Last modified: _6/13/1997_
+
+ 8. How do I split a file into pieces, retaining revision histories?
+
+ If you and a coworker find yourselves repeatedly committing the same
+ file, but never for changes in the same area of the file, you might
+ want to split the file into two or more pieces. If you are both
+ changing the same section of code, splitting the file is of no use.
+ You should talk to each other instead.
+
+ If you decide to split the file, here's a suggestion. In many ways, it
+ is similar to multiple "renamings" as described in 2C.4 above.
+
+ Say you want to split , which already in the Repository, into three
+ pieces, , and .
+
+ Copy the RCS (",v") files directly in the Repository, creating the
+ new files, then bring readable copies of the new files into the
+ working directory via "update".
+
+ cp $CVSROOT//,v $CVSROOT//,v cp $CVSROOT//,v $CVSROOT//,v
+ cvs update
+
+ Then remove all the from the new files, either using:
+
+ cvs log # Save the list of
+ cvs tag -d
+ cvs tag -d
+ . . .
+
+ (eivind@freebsd.org) or using the following little script to
+ autmatically remove the tags directly from the repository files:
+
+#!/bin/sh
+for file in $*
+do
+ TAGS=`rlog $file | awk '/^symbolic names:/,/^keyword subst/' | awk 'BEG
+IN {FS=":"} /^\t/ {print $1}'`
+ echo The tags in $file are
+ echo $TAGS
+ echo Is it OK to remove these?
+ read confirm
+ if [ "$confirm" = "y" -o "$confirm" = "yes" ]
+ then
+ for tag in $TAGS
+ do
+ echo Removing $file:$tag
+ rcs -n$tag $file
+ done
+ fi
+done
+
+ Edit each file until it has the data you want in it. This is a
+ hand-editing job, not something CVS can handle. Then commit all the
+ files.
+
+ [From experience, I'd suggest making sure that only one copy of each
+ line of code exists among the three files, except for "include"
+ statements, which must be duplicated. And make sure the code
+ compiles.]
+
+ emacs
+ cvs commit
+
+ As in the "rename" case, by duplicating the files, you'll preserve the
+ change history and the ability to retrieve earlier revisions.
+
+ Of course, you have to alter your build system (e.g. Makefiles) to
+ take the new names and the change in contents into account.
+
+ Last modified: _3/11/1998_
+
+ Category: /What_is_CVS_/
+
+ " What is CVS? "
+
+ Category: /What_is_CVS_/How_does_CVS_differ_/
+
+ " + How does CVS differ from other, similar software?"
+
+ 1. How does CVS differ from RCS?
+
+ CVS uses RCS to do much of its work and absolutely all the work of
+ changing the underlying RCS files in the Repository.
+
+ RCS comprises a set of programs designed to keep track of changes to
+ individual files. Of course, it also allows you to refer to multiple
+ files on the command line, but they are handled by iterating over
+ individual files. There is no pretense of coordinated interaction
+ among groups of files.
+
+ CVS's main intent is to provide a set of grouping functions that allow
+ you to treat a collection of RCS files as a single object. Of course,
+ CVS also has to do a lot of iteration, but it tries its best to hide
+ that it is doing so. In addition, CVS has some truly group-oriented
+ facets, such as the modules file and the CVS administrative files that
+ refer to a whole directory or module.
+
+ One group aspect that can be a bit confusing is that a CVS branch is
+ not the same as an RCS branch. To support a CVS branch, CVS uses
+ "tags" (what RCS calls "symbols") and some local state, in addition to
+ RCS branches.
+
+ Other features offered by CVS that are not supported directly by RCS
+ are
+
+ Automatic determination of the state of a file, (e.g. modified,
+ up-to-date with the Repository, already tagged with the same string,
+ etc.) which helps in limiting the amount of displayed text you have to
+ wade through to figure out what changed and what to do next.
+
+ A copy-modify-merge scheme that avoids locking the files and allows
+ simultaneous development on a single file.
+
+ Serialization of commits. CVS requires you to merge all changes
+ committed (via "update") since you checked out your working copy of
+ the file. Although it is still possible to commit a file filled with
+ old data, it is less likely than when using raw RCS.
+
+ Relatively easy merging of releases from external Vendors.
+
+ Last modified: _6/13/1997_
+
+ 2. How does CVS differ from SCCS?
+
+ SCCS is much closer to RCS than to CVS, so some of the previous entry
+ applies.
+
+ You might want to take a look at Walter Tichy's papers on RCS, which
+ are referred to in the RCS man pages.
+
+ [[More info here?]]
+
+ Last modified: _6/13/1997_
+
+ 3. How does CVS differ from ClearCase?
+
+ ClearCase is a distributed client-server version control system.
+ ClearCase is a variant DSEE tools, formerly available on Apollo
+ platforms. The ClearCase tool set includes a few X-based interface
+ tools, a command-line interface, and C programmer API. It is currently
+ available on Sun, HP, SGI and OSF/1 platforms.
+
+ ClearCase uses a special Unix filesystem type, called "mvfs" for
+ "multi-version file system". Conceptually, mvfs adds another dimension
+ to a regular Unix filesystem. The new axis is used to store the
+ different versions of files and to provide a tree-hierarchical view of
+ a collection of objects that might be scattered across any number of
+ separate hosts on your local network.
+
+ Each user acquires a "view" into the file database by creating a
+ special mvfs mount point on their machine. Each view has a
+ "configuration spec" containing a set of selection rules that specify
+ the particular version of each file to make visible in that view. You
+ can think of a "view" as a work area in CVS, except that the files
+ don't really exist on your local disk until you modify them. This
+ technique conserves disk space because it doesn't keep private copies
+ of read-only files.
+
+ Another advantage is that a view is "transparent" in the sense that
+ all of the files in a "view" appear to be regular Unix files to other
+ tools and Unix system calls. An extended naming convention allows
+ access to particular versions of a file directly:
+ "test.cc@@/main/bugfix/3" identifies the third version of test.c on
+ the bugfix branch.
+
+ ClearCase supports both the copy-modify-merge model of CVS (by using
+ what are called "unreserved checkouts" and the checkin/checkout
+ development model with file locking. Directories are
+ version-controlled objects as well as files. A graphical merge tool is
+ provided. Like RCS, ClearCase supports branches, symbolic tags, and
+ delta compression. ASCII as well as binary files are supported, and
+ converters from RCS, SCCS, DSEE formats are also included.
+
+ A make-compatible build facility is provided that can identify common
+ object code and share it among developers. A build auditing feature
+ automatically records file dependencies by tracking every file that is
+ opened when producing a derived object, thus making explicit
+ dependency lists unnecessary. Pre- and post-event triggers are
+ available for most ClearCase operations to invoke user programs or
+ shell scripts. User-defined attributes can be assigned to any version
+ or object. Hyper-links between version controlled objects can record
+ their relationship.
+
+ For more information, contact:
+
+ Atria Software, Inc. 24 Prime Park Way Natick, MA 01760 info@atria.com
+
+ (508) 650-1193 (phone) (508) 650-1196 (fax)
+
+ Originally contributed by Steve Turner
+ Edited by the author of this FAQ.
+
+ Last modified: _6/13/1997_
+
+ 4. How does CVS differ from TeamWare/SparcWorks?
+
+ TeamWare is a configuration management tool from Sun Microsystems, a
+ part of SparcWorks. It uses the same copy and merge model as CVS. The
+ central abstraction is a workspace, which corresponds to either a CVS
+ branch or a checked out module. TeamWare allows you to manipulate
+ workspaces directly, including moving and merging code between
+ workspaces. You can put your workspace on tape and continue to work
+ with it at home, just like you can with CVS. TeamWare is built upon
+ and compatible with SCCS.
+
+ TeamWare provides both a command line interface and a graphical
+ interface. The CodeManager tool will display the project as a tree of
+ workspaces, and allows you to manipulate them with drag and drop. The
+ other tools are VersionTool that displays and manipulates a dag with a
+ version history of a single file, CheckPoint that will create symbolic
+ tags, MakeTool, a make compatible tool with a GUI, and FileMerge which
+ will interactively merge files when needed (like emerge for emacs). If
+ you have a sun, you can try /usr/old/mergetool for an old SunView
+ version of FileMerge.
+
+ Email: sunprosig@sun.com
+
+ Originally extracted from TeamWare
+ Marketing literature by Per Abrahamsen.
+ Edited by the author of this FAQ.
+
+ For more information, contact:
+
+ SunExpress, Inc. P.O. Box 4426 Bridgeton, MO 63044-9863 (800)873-7869
+
+ Last modified: _6/13/1997_
+
+ 5. How does CVS differ from Aegis?
+
+ Aegis appears to be a policy-setting tool that allows you to use other
+ sub-programs (make, RCS, etc.) to implement pieces of the imposed
+ policy.
+
+ The initial document seems to say that most Unix tools are inadequate
+ for use under Aegis.
+
+ It is not really similar to CVS and requires a different mindset.
+
+ [[Need more info here.]]
+
+ Last modified: _6/13/1997_
+
+ 6. How does CVS differ from Shapetools?
+
+ Shapetools includes a build mechanism (called Shape, not surprisingly)
+ that is aware of the version mechanism, and some dependency tracking.
+ It is based on a file system extension called Attributed File System,
+ which allows arbitrary-sized "attributes" to be associated with a
+ file. Files are version controlled in a manner similar to RCS.
+ Configurations are managed through the Shapefile, an extension of the
+ Makefile syntax and functionality. Shape includes version selection
+ rules to allow sophisticated selection of component versions in a
+ build.
+
+ Shapetools' concurrency control is pessimistic, in contrast to that of
+ CVS. Also, there's very limited support for branching and merging. It
+ has a built-in policy for transitioning a system from initial
+ development to production.
+
+ Contributed by Don Dwiggins
+
+ Last modified: _6/13/1997_
+
+ 7. How does CVS differ from TeamNet?
+
+ TeamNet is a configuration management tool from TeamOne.
+
+ For more information, contact:
+
+ TeamOne 710 Lakeway Drive, Ste 100 Sunnyvale, CA 94086 (800) 442-6650
+
+ Contributed by Steve Turner
+
+ Last modified: _6/13/1997_
+
+ 8. How does CVS differ from ProFrame?
+
+ ProFrame is a new system integration framework from IBM. ProFrame is
+ compliant with the CFI (CAD Framework Initiative) industry standards,
+ including the Scheme extension language.
+
+ ProFrame consists of three major components: (1) the Process Manager
+ that automates your local design methodology (2) the Design Data
+ Manager handles configuration management, and (3) Inter-tool
+ Communication to provide a communication path among tools running on
+ heterogeneous servers.
+
+ The Design Data Manager(2) is probably the appropriate component to
+ compare to CVS. The Design Data Manager provides version control with
+ checkin/checkout capability, configuration management, and data
+ dependency tracking. A graphical data selection interface is provided.
+ Using this interface, you may create and manipulate objects and
+ hierarchy structures, view the revision history for an object, and
+ view and assign attributes to a design object.
+
+ The ProFrame server currently runs only on RS6000, but clients may be
+ a wide variety of Unix platforms. Contact IBM for the latest platform
+ information.
+
+ For more information, contact:
+
+ IBM EDA Marketing and Sales P.O. Box 950, M/S P121 Poughkeepsie, NY
+ 12602 (800) 332-0066
+
+ Contributed by Steve Turner
+ [extracted from the ProFrame 1.1.0 datasheet]
+
+ Last modified: _6/13/1997_
+
+ 9. How does CVS differ from CaseWare/CM?
+
+ CaseWare/CM is a software configuration management product from
+ CaseWare, Inc. CaseWare/CM may be customized to support a wide variety
+ of methodologies, including various phases of the software lifecycle,
+ and different access rights for users.
+
+ A GUI is provided to view version histories and configurations. A
+ merge tools is also included. CaseWare supports type-specific
+ lifecycles, which allows different types of files to move through
+ different lifecycles. Also provided is a build facility to support
+ automatic dependency analysis, parallel, distributed, and remote
+ builds, and variant releases.
+
+ CaseWare/CM has been integrated with other CASE tools, including
+ FrameMaker, ALSYS Ada, CodeCenter/Object Center, HP SoftBench, and
+ Software Through Pictures. CaseWare also offers CaseWare/PT, a problem
+ tracking system to integrate change requests with configuration
+ management.
+
+ Multiple vendors and operating systems are supported.
+
+ For more information, contact:
+
+ CaseWare, Inc. 108 Pacifica, 2nd Floor Irvine, CA 92718-3332 (714)
+ 453-2200 (phone) (714) 453-2276 (fax)
+
+ Contributed by Steve Turner
+ [extracted from the CaseWare/CM data sheet]
+
+ Last modified: _6/13/1997_
+
+ 10. How does CVS differ from SABLIME?
+
+ Produced by AT&T. Sablime uses SCCS as the underlying source code
+ control system. It uses some other control system (called sbcs I
+ think) for managing binary files. It uses lock, edit, comit, unlock
+ mechanism. It has a motif based GUI and curses based GUI (that works
+ only with ksh, not tcsh, or bash) to do more common tasks. It has even
+ a command line interface.
+
+ Changing source happens as a result of MR. A testing person or a
+ developer assigns an MR (modification request) to a group of people.
+ They are allowed to take out files under that MR and change them and
+ check them back in. You can set up dependencies between and MR and do
+ release management to say "I want the sources to include these MRs"
+ etc. It is a reasonably good maintanance system. It is bit heavy
+ weight though, and the interface is not too polished and does not work
+ on windows (though that may have changed). rama@savera.com
+
+ Last modified: _7/30/1998_
+
+ 11. How does CVS differ from PVCS?
+
+ PVCS works on single files like RCS and SCCS, CVS works on complete
+ subsystems. PVCS has a make utility (called a configuration builder),
+ CVS does not. PVCS has a GUI interface for Unix, DOS, OS/2, and MS
+ Windows.
+
+ Intersolv, Inc.
+ 1700 NW 167th Place
+ OR 97006
+
+ Contributed by Per Abrahamsen
+ [Extracted from Intersolv Marketing literature.]
+
+ Last modified: _6/13/1997_
+
+ 12. How does CVS differ from CMVC?
+
+ CMVC is an IBM Configuration Management and Version Control system.
+ (Though I'm not certain that's the right acronym expansion.) It runs
+ on Suns, HPs, RS6000s, OS/2 and Windows.
+
+ Other than revision control, it apparently has features to manage
+ releases, bug tracking and the connection between alterations and
+ reported bugs and feature requests. It is a client/server system,
+ based on a choice of commercial Relational Database systems, and it
+ provides a Motif or command line interface.
+
+ Unlike CVS, it uses a strict locking protocol to serialize source code
+ alterations.
+
+ Last modified: _6/13/1997_
+
+ Category: /What_is_CVS_/What_do_you_mean_by_/
+
+ " + What do you mean by . . .? (Definitions)"
+
+ 1. What are "The Repository", "$CVSROOT" and "CVSROOT"?
+
+ The Repository is a directory tree containing the CVS administrative
+ files and all the RCS files that constitute "imported" or "committed"
+ work. The Repository is kept in a shared area, separate from the
+ working areas of all developers.
+
+ Users of CVS must set their "CVSROOT" environment variable to the
+ absolute pathname of the head of the Repository. Most command line
+ interpreters replace an instance of "$CVSROOT" with the value of the
+ "CVSROOT" environment variable. By analogy, in this document
+ "$CVSROOT" is used as shorthand for "the absolute pathname of the
+ directory at the head of the Repository".
+
+ One of the things found in $CVSROOT is a directory named CVSROOT. It
+ contains all the "state", the administrative files, that CVS needs
+ during execution. The "modules", "history", "commitinfo", "loginfo"
+ and other files can be found there. See 4B.2 for more information
+ about CVSROOT files.
+
+ Last modified: _6/13/1997_
+
+ 2. What is an RCS file?
+
+ An RCS file is a text file containing the source text and the revision
+ history for all committed revisions of a source file. It is stored
+ separately from the working files, in a directory hierarchy, called
+ the Repository.
+
+ RCS is the "Revision Control System" that CVS uses to manage
+ individual files. RCS file names normally end in ",v", but that can be
+ altered (via the RCS -x option) to conform to file naming standards on
+ platforms with unusual filename limitations.
+
+ Last modified: _6/13/1997_
+
+ 3. What is a working file?
+
+ A working file is a disk file containing a checked-out copy of a
+ source file that earlier had been placed under CVS. If the working
+ file has been edited, the changes since the last committed revision
+ are invisible to other users of CVS.
+
+ Last modified: _6/13/1997_
+
+ 4. What is a working directory (or working area)?
+
+ A working directory is the place where you work and the place from
+ which you "commit" files.
+
+ The "checkout" command creates a tree of working directories, filling
+ them with working files. Each working directory contains a
+ sub-directory named ./CVS containing three administrative files, which
+ are created by "checkout" and are always present:
+
+ ./CVS/Entries
+ contains information about working files.
+
+ ./CVS/Repository
+ contains the location of the directory within the
+ Repository that was used to create the working directory.
+
+ ./CVS/Root
+ contains the value of $CVSROOT at the time you created
+ the working directory.
+
+ Other files may also appear in ./CVS depending on the state of your
+ working directory:
+
+ ./CVS/Tag
+ contains the "sticky tag" associated with the whole
+ directory. See 3A.2 for its main purpose.
+ [Created by "checkout" or "update" when using "-r <tag>".]
+ [Deleted by "checkout" or "update" when using '-A'.]
+
+ ./CVS/Entries.Static
+ contains a fixed list of working files. If this file
+ exists, an "update" doesn't automatically bring newly
+ added files out of the Repository.
+ [Created and maintained by hand.]
+
+ ./CVS/Checkin.prog
+ contains a program to run whenever anything in the
+ working directory is committed.
+ [Created by checkout if "-i <prog>" appears in the
+ modules file for the checked-out module.]
+
+ ./CVS/Update.prog
+ contains a program to run whenever anything in the
+ working directory is updated.
+ [Created by checkout if "-u <prog>" appears in the
+ modules file for the checked-out module.]
+
+ ./CVS/<file>,p ./CVS/<file>,t
+ contain (possibly zero-length) state information about an
+ "add" that has not been committed.
+ [Created by "add".]
+ [Deleted by "commit" or "remove".]
+
+ Last modified: _6/13/1997_
+
+ 5. What is "checking out"?
+
+ "Checking out" is the act of using the "checkout" command to copy a
+ particular revision from a set of RCS files into your working area.
+ You normally execute "checkout" only once per working directory (or
+ tree of working directories), maintaining them thereafter with the
+ "update" command.
+
+ See section 3C on the "checkout" command.
+
+ Last modified: _6/13/1997_
+
+ 6. What is a revision?
+
+ A "revision" is a version of a file that was "committed" ("checked
+ in", in RCS terms) some time in the past. CVS (and RCS) can retrieve
+ any file that was committed by specifying its revision number or its
+ "tag" ("symbolic name", in RCS terms).
+
+ In CVS, a "tag" is more useful than a revision number. It usually
+ marks a milestone in development represented by different revision
+ numbers in different files, all available as one "tagged" collection.
+
+ Sometimes the word "revision" is used as shorthand for "the file you
+ get if you retrieve (via "checkout" or "update") the given revision
+ from the Repository."
+
+ Last modified: _6/13/1997_
+
+ 7. What is a "Tag"?
+
+ A "Tag" is a symbolic name, a synonym or alias for a particular
+ revision number in a file. The CVS "tag" command places the same "Tag"
+ on all files in a working directory, allowing you to retrieve those
+ files by name in the future.
+
+ The CVS "Tag" is implemented by applying RCS "symbols" to each
+ individual file. The Tags on a file (or collection of files) may be
+ displayed using the "log" command.
+
+ Last modified: _6/13/1997_
+
+ 8. What are "HEAD" and "BASE"?
+
+ HEAD and BASE are built-in tags that don't show up in the "log" or
+ "status" listings. They are interpreted directly by CVS.
+
+ "HEAD" refers to the latest revision on the current branch in the
+ Repository. The current branch is either the main line of development,
+ or a branch in development created by placing a branch tag on a set of
+ files and checking out that branch.
+
+ "BASE" refers to the revision on the current branch you last checked
+ out, updated, or committed. If you have not modified your working
+ file, "BASE" is the committed revision matching it.
+
+ Most of the time BASE and HEAD refer to the same revision. They can
+ become different in two ways:
+
+ Someone else changed HEAD by committing a new revision of your file
+ to the Repository. You can pull BASE up to equal HEAD by executing
+ "update".
+
+ You moved BASE backward by executing "checkout" or "update" with the
+ option "-r <rev/tag>" or "-D <date>". CVS records a sticky tag and
+ moves your files to the specified earlier revision. You can clear the
+ sticky tag and pull BASE up to equal HEAD again by executing "update
+ -A".
+
+ Last modified: _6/13/1997_
+
+ 9. What is a Branch?
+
+ In general, a branch is any mechanism that allows one or more
+ developers to modify a file without affecting anyone other than those
+ working on the same branch.
+
+ There are four kinds of "branch" CVS can manage:
+
+ The Vendor Branch.
+
+ A single vendor branch is supported. The "import" command takes a
+ sequence of releases from a source code vendor (called a "vendor" even
+ if no money is involved), placing them on a special "Vendor" branch.
+ The Vendor branch is considered part of the "Main line" of
+ development, though it must be merged into locally modified files on
+ the RCS Main branch before the "import" is complete.
+
+ See Section 3H ("import").
+
+ Your Working directory.
+
+ A checked-out working directory, can be treated like a private branch.
+ No one but you can touch your files. You have complete control over
+ when you include work committed by others. However, you can't commit
+ or tag intermediate versions of your work.
+
+ A Development branch.
+
+ A group of developers can share changes among the group, without
+ affecting the Main line of development, by creating a branch. Only
+ those who have checked-out the branch see the changes committed to
+ that branch. This kind of branch is usually temporary, collapsing
+ (i.e. merge and forget) into the Main line when the project requiring
+ the branch is completed.
+
+ You can also create a private branch of this type, allowing an
+ individual to commit (and tag) intermediate revisions without changing
+ the Main line. It should be managed exactly like a Development Branch
+ -- collapsed into the Main line (or its parent branch, if that is not
+ the Main Branch) and forgotten when the work is done.
+
+ A Release branch.
+
+ At release time, a branch should be created marking what was released.
+ Later, small changes (sometimes called "patches") can be made to the
+ release without including everything else on the Main line of
+ development. You avoid forcing the customer to accept new, possibly
+ untested, features added since the release. This is also the way to
+ correct bugs found during testing in an environment where other
+ developers have continued to commit to the Main line while you are
+ testing and packaging the release.
+
+ Although the internal format of this type of branch (branch tag and
+ RCS branches) is the same as in a development branch, its purpose and
+ the way it is managed are different. The major difference is that a
+ Release branch is normally Permanent. Once you let a release out the
+ door to customers, or to the next stage of whatever process you are
+ using, you should retain forever the branch marking that release.
+
+ Since the branch is permanent, you cannot incorporate the branch fixes
+ into the Main line by "collapsing" (merging and forgetting) the
+ release branch. For large changes to many files on the release branch,
+ you will have to perform a branch merge using "update -j <rev> -j
+ <rev>". (See 4C.7)
+
+ The most common way to merge small changes back into Main line
+ development is to make the change in both places simultaneously. This
+ is faster than trying to perform a selective merge.
+
+ See 1D.12 (merges) and Section 4C, on Branching for more info.
+
+ Last modified: _6/13/1997_
+
+ 10. What is "the trunk"?
+
+ Another name for the RCS Main Branch. The RCS Main Branch is related,
+ but not equivalent, to both the CVS Main branch and what developers
+ consider to be the Main line of development. See 3H.3 and Section 4C
+ on Branching.
+
+ Last modified: _6/13/1997_
+
+ 11. What is a module?
+
+ In essence, a module is a name you hand to the "checkout" command to
+ retrieve one or more files to work on. It was originally intended to
+ be a simple, unique name in the "modules" file attached to a directory
+ or a subset of files within a directory.
+
+ The module idea is now a somewhat slippery concept that can be defined
+ in two different ways:
+ * A module is an argument to "checkout". There are three types:
+ 1. An entry in the modules file. A "module" name as described in
+ 'B.' below.
+ 2. A relative path to a directory or file in the Repository.
+ 3. A mixed-mode string of "modulename/relative-path". Everything
+ up to the first slash ('/') is looked up as a module. The
+ relative path is appended to the directory associated with
+ the module name and the resulting path is checked out as in
+ #2 above.
+ * A module is a unique (within the file) character string in the
+ first column of the modules file. There are five types:
+ 1. A name for a directory within the Repository that allows you
+ to ignore the parent directories above it.
+ Example:
+ emacs gnu/emacs
+ 2. A name for a subset of the files within such a directory.
+ Example:
+ ls unix/bin Makefile ls.c
+ The 2nd through Nth strings in the above can be files,
+ directories or module substitutions. No relative paths.
+ A module substitution occurs when you use a '&module-name'
+ reference. The module-name referred to is logically
+ substituted for the '&module-name' string.
+ 3. A relative pathname to a directory within the Repository
+ which, when checked out, creates an image of part of the
+ Repository structure in your current directory.
+ Example:
+ gnu/emacs -o /bin/emacs.helper gnu/emacs
+ The files checked out are exactly the same as the files
+ "checkout" would retrieve if the path weren't even in the
+ modules file. The only reason to put this kind of relative
+ pathname into the modules file is to hook one of the helper
+ functions onto it.
+ 4. A relative pathname to a single file within the Repository
+ which, when checked out, creates something you probably don't
+ want: It creates a directory by the name of the file and puts
+ the file in it.
+ Example:
+ gnu/emacs/Makefile -o /bin/emacs.helper gnu/emacs Makefile
+ The file checked out is the same as what you would get if you
+ handed the relative pathname to the "checkout" command. But
+ it puts it in a strange place. The only reason to do this is
+ to hook a helper function onto a specific file name.
+ 5. An alias consisting of a list of any of the above, including
+ other aliases, plus exceptions.
+ Example:
+ my_work -a emacs !emacs/tests gnu/bison unix/bin/ls.c
+ The exception "!emacs/test" above is functionally equivalent
+ to specifying "!emacs/tests" on the "checkout" command line.
+
+ Another way to look at it is that the modules file is simply another
+ way to "name" files. The hierarchical directory structure provides
+ another. You should use whatever turns out to be simplest for your
+ development group.
+
+ See 4G.2 for some specific ideas about how to use the modules file.
+
+ Last modified: _11/12/1997_
+
+ 12. What does "merge" mean?
+
+ A merge is a way of combining changes made in two independent copies
+ of a common starting file. Checking out an RCS revision produces a
+ file, so for the purposes of a merge "file" and "revision" are
+ equivalent. So, we can say there are always three "files" involved in
+ a merge:
+
+ The original, starting, "base" or "branch point" file.
+
+ A copy of the base file modified in one way.
+
+ Another copy of the base file modified in a different way.
+
+ Humans aren't very good at handling three things at once, so the
+ terminology dealing with merges can become strained. One way to think
+ about it is that all merges are performed by inserting the difference
+ between a base revision and a later revision (committed by someone
+ else) into your working file. Both the "later" revision and your
+ working file are presumed to have started life as a copy of the "base"
+ revision.
+
+ In CVS, there are three main types of "merge":
+
+ The "update" command automatically merges revisions committed by
+ others into your working file. In this case, the three files involved
+ in the merge are:
+
+ Base: The revision you originally checked out. Later: A revision
+ committed onto the current branch after you checked out the Base
+ revision. Working: Your working file. The one lying in the working
+ directory containing changes you have made.
+
+ The "update -j <branch_tag> {optional files}" command merges changes
+ made on the given branch into your working files, which is presumed to
+ be on the Main line of development.
+
+ See 4C.6
+
+ The "update -j <rev> -j <rev> {optional files}" command merges the
+ difference between two specified revisions into files in your working
+ directory. The two revisions <rev> are usually on the same branch and,
+ when updating multiple files, they are most useful when they are Tag
+ names rather than numeric revisions.
+
+ See 4C.7
+
+ Last modified: _6/13/1997_
+
+ Category: /What_is_CVS_/What_is_CVS_Whats_it/
+
+ " + What is CVS? What's it for? Why CVS?"
+
+ 1. What does CVS stand for? Can you describe it in one sentence?
+
+ "CVS" is an acronym for the "Concurrent Versions System".
+
+ CVS is a "Source Control" or "Revision Control" tool designed to keep
+ track of source changes made by groups of developers working on the
+ same files, allowing them to stay in sync with each other as each
+ individual chooses.
+
+ Last modified: _6/13/1997_
+
+ 2. What is CVS for? What does it do for me?
+
+ CVS is used to keep track of collections of files in a shared
+ directory called "The Repository". Each collection of files can be
+ given a "module" name, which is used to "checkout" that collection.
+
+ After checkout, files can be modified (using your favorite editor),
+ "committed" back into the Repository and compared against earlier
+ revisions. Collections of files can be "tagged" with a symbolic name
+ for later retrieval.
+
+ You can add new files, remove files you no longer want, ask for
+ information about sets of files in three different ways, produce patch
+ "diffs" from a base revision and merge the committed changes of other
+ developers into your working files.
+
+ Last modified: _6/13/1997_
+
+ 3. How does CVS work?
+
+ CVS saves its version-control information in RCS files stored in a
+ directory hierarchy, called the Repository, which is separate from the
+ user's working directory.
+
+ Files in the Repository are stored in a format dictated by the RCS
+ commands CVS uses to do much of its real work. RCS files are standard
+ byte-stream files with an internal format described by keywords stored
+ in the files themselves.
+
+ To begin work, you execute a "checkout" command, handing it a module
+ name or directory path (relative to the $CVSROOT variable) you want to
+ work on. CVS copies the latest revision of each file in the specified
+ module or directory out of the Repository and into a directory tree
+ created in your current directory. You may specify a particular branch
+ to work on by symbolic name if you don't want to work on the default
+ (main or trunk) branch.
+
+ You may then modify files in the new directory tree, build them into
+ output files and test the results. When you want to make your changes
+ available to other developers, you "commit" them back into the
+ Repository.
+
+ Other developers can check out the same files at the same time. To
+ merge the committed work of others into your working files you use the
+ "update" command. When your merged files build and test correctly, you
+ may commit the merged result. This method is referred to as
+ "copy-modify-merge", which does not require locks on the source files.
+
+ At any time, usually at some milestone, you can "tag" the committed
+ files, producing a symbolic name that can be handed to a future
+ "checkout" command. A special form of "tag" produces a branch in
+ development, as usually happens at "release" time.
+
+ When you no longer plan to modify or refer to your local copy of the
+ files, they can be removed.
+
+ Last modified: _6/13/1997_
+
+ 4. What is CVS useful for?
+
+ CVS is intended to handle source control for files in three major
+ situations:
+
+ Multiple developers working on the same files.
+
+ The major advantage of using CVS over the simpler tools like RCS or
+ SCCS is that it allows multiple developers to work on the same sources
+ at the same time.
+
+ The shared Repository provides a rendezvous for committed sources that
+ allows developers a fair amount of flexibility in how often to publish
+ (via the "commit" command) changes or include work committed by others
+ (via the "update" command).
+
+ Tracking a stream of releases from a source vendor.
+
+ If you are making changes to sources distributed by someone else, the
+ CVS feature, called the Vendor Branch, allows you to combine local
+ modifications with repeated vendor releases.
+
+ I have found this most useful when dealing with sources from three
+ major classes of source vendor:
+
+ Large companies who send you tapes full of the latest release (e.g.
+ Unix OS vendors, database companies).
+
+ Public Domain software which *always* requires work.
+
+ Pseudo-Public sources which may require work. (e.g. GNU programs, X,
+ CVS itself, etc.)
+
+ Branching development.
+
+ Aside from the "Vendor Branch", there are three kinds of "branches in
+ development" that CVS can support:
+
+ Your working directory can be treated as a private branch.
+
+ A Development branch can be shared by one or more developers.
+
+ At release time, a branch is usually created for bug fixes.
+
+ (See 1D.9 and Section 4C for more info on branches.)
+
+ CVS's branch support is a bit primitive, but it was designed to allow
+ you to create branches, work on them for while and merge them back
+ into the main line of development. You should also be able to merge
+ work performed on the main branch into the branch you are working on.
+ Arbitrary sharing and merging between branches is not currently
+ supported.
+
+ Last modified: _6/13/1997_
+
+ 5. What is CVS *not* useful for?
+
+ CVS is not a build system.
+
+ Though the structure of your Repository and modules file interact with
+ your build system (e.g. a tree of Makefiles), they are essentially
+ independent.
+
+ CVS does not dictate how you build anything. It merely stores files
+ for retrieval in a tree structure you devise.
+
+ CVS does not dictate how to use disk space in the checked out working
+ directories. If you require your Makefiles or build procedures to know
+ the relative positions of everything else, you wind up requiring the
+ entire Repository to be checked out. That's simply bad planning.
+
+ If you modularize your work, and construct a build system that will
+ share files (via links, mounts, VPATH in Makefiles, etc.), you can
+ arrange your disk usage however you like.
+
+ But you have to remember that *any* such system is a lot of work to
+ construct and maintain. CVS does not address the issues involved. You
+ must use your brain and a collection of other tools to provide a build
+ scheme to match your plans.
+
+ Of course, you should use CVS to maintain the tools created to support
+ such a build system (scripts, Makefiles, etc).
+
+ CVS is not a substitute for management.
+
+ You and your project leaders are expected to plan what you are doing.
+ Everyone involved must be aware of schedules, merge points, branch
+ names, release dates and the range of procedures needed to build
+ products. (If you produce it and someone else uses it, it is a
+ product.) CVS can't cover for a failure to manage your project.
+
+ CVS is an instrument for making sources dance to your tune. But you
+ are the piper and the composer. No instrument plays itself or writes
+ its own music.
+
+ CVS is not a substitute for developer communication.
+
+ When faced with conflicts within a single file, most developers manage
+ to resolve them without too much effort. But a more general definition
+ of "conflict" includes problems too difficult to solve without
+ communication between developers.
+
+ CVS cannot determine when simultaneous changes within a single file,
+ or across a whole collection of files, will logically conflict with
+ one another. Its concept of a "conflict" is purely textual, arising
+ when two changes to the same base file are near enough to spook the
+ merge command into dropping conflict markers into the merged file.
+
+ CVS is not capable of figuring out distributed conflicts in program
+ logic. For example, if you change the arguments to function X defined
+ in file A and, at the same time, edit file B, adding new calls to
+ function X using the old arguments. You are outside the realm of CVS's
+ competence.
+
+ Acquire the habit of reading specs and talking to your peers.
+
+ CVS is not a configuration management system.
+
+ CVS is a source control system. The phrase "configuration management"
+ is a marketing term, not an industry-recognized set of functions.
+
+ A true "configuration management system" would contain elements of the
+ following:
+
+ * Source control.
+ * Dependency tracking.
+ * Build systems (i.e. What to build and how to find
+ things during a build. What is shared? What is local?)
+ * Bug tracking.
+ * Automated Testing procedures.
+ * Release Engineering documentation and procedures.
+ * Tape Construction.
+ * Customer Installation.
+ * A way for users to run different versions of the same
+ software on the same host at the same time.
+
+ CVS provides only the first.
+
+ Last modified: _6/13/1997_
+
+ Category: /What_is_CVS_/Where_do_I_find_CVS_/
+
+ " + Where do I find CVS? Where can I find Help?"
+
+ 1. How do I get more information about CVS?
+
+ The first thing I would do is to read the Info file that comes with
+ the CVS sources under "doc". You can format and read the cvs.texinfo
+ file in two ways: 1. Use TeX to format it and a "dvips" command to
+ print it and 2. Install the cvs.info files that are created by the
+ Makefile and read them online using the Emacs "info-mode" or a
+ stand-alone "info" reader.
+
+ Then I'd run "cvsinit" to set up a Repository and read the man page
+ while trying out the commands.
+
+ Type "cvs -H" for general help or "cvs -H command" for
+ command-specific help.
+
+ For background, you can read the original CVS paper (in the source
+ tree, under "doc"). It describes the purpose of CVS and some of how it
+ was designed. Note that the emphasis of the document (especially on
+ multiple vendors providing the same sources) is somewhat out of date.
+
+ For more detailed information about "internals", read the man pages
+ for RCS. If you are a programmer, you can also read the source code to
+ CVS.
+
+ Other information and tutorials may be available in the "doc"
+ directory of the FTP archive described below.
+
+ For current information, and a fair amount of detail, join the
+ info-cvs mailing list described below.
+
+ Last modified: _6/13/1997_
+
+ 2. Is there an archive of CVS material?
+
+ An anonymous FTP area has been set up. It contains many of the CVS
+ files you might want, including extra documentation, patches and a
+ copy of the latest release.
+
+ ftp ftp.delos.com
+ >>> User: anonymous
+ >>> Passwd:
+ cd /pub/cvs
+ get README
+ get Index
+
+ The README has more (and more up-to-date) information. The Index
+ contains a terse list of what is in the archive.
+
+ A WWW home page is also available at http://www.delos.com/cvs.
+
+ This Didn't Exist 6/23/1998
+
+ Last modified: _6/24/1998_
+
+ 3. How do I get files out of the archive if I don't have FTP?
+
+ Use one of the FTP<->Email servers. These are the ones I've been told
+ about:
+
+ FTPMAIL service is available from the same host as the FTP server
+ described above. Send mail to "ftpmail@delos.com" containing "help" in
+ the body of the message. For example, on most Unix systems, you can
+ type:
+
+ echo help | Mail ftpmail@delos.com
+
+ The FTPMAIL server will respond with a document describing how to use
+ the server. If the "Mail" command doesn't exist on your system, try
+ "mailx", "/usr/ucb/mail" or "/bin/mail".
+
+ If you are on BITNET, use Princeton's BITFTP server. Type
+
+ echo 'send help' | Mail bitftp@pucc.princeton.edu
+
+ (It is likely that only BITNET addresses can use this one.)
+
+ Other possibilities I've heard of from the net: (Try the one closest
+ to you.)
+
+ ftpmail@decwrl.dec.com ftpmail@sunsite.unc.edu ftpmail@cs.arizona.edu
+ ftpmail@cs.uow.edu.au ftpmail@doc.ic.ac.uk
+
+ Last modified: _6/13/1997_
+
+ 4. How do I get a copy of the latest version of CVS?
+
+ The latest released version of CVS and all the programs it depends on
+ should be available through anonymous FTP on any FSF archive. The main
+ FSF archive is at "prep.ai.mit.edu". There are mirrors of the FSF
+ archive on UUNET and other large Internet sites.
+
+ Program(s) Suggested revision
+ ----------- -----------------------
+ CVS 1.5
+ RCS 5.7 (latest version available today)
+ GNU diff 2.7 (or later) [contained in diffutils-2.7]
+ GDBM 1.5 (or later) [optional]
+
+ The GNU version of diff is suggested by both the RCS and CVS
+ configuration instructions because it works better than the standard
+ version.
+
+ It is a good idea not to accept the versions of CVS, RCS or diff you
+ find lying on your system unless you have checked out their
+ provenance. Using inconsistent collections of tools can cause you more
+ trouble than you can probably afford.
+
+ The FTP archive mentioned above should contain the latest official
+ release of CVS, some official and unofficial patches and possibly
+ complete patched versions of CVS in use somewhere.
+
+ Last modified: _6/13/1997_
+
+ 5. Is there a mailing list devoted to CVS? How do I find it?
+
+ An Internet mailing list named "info-cvs" grew out of the private
+ mailing list used by the CVS 1.3 alpha testers in early 1992.
+ Throughout 1994, the list received an average of 100 messages per
+ month.
+
+ You can add yourself to the mailing list by sending an Email message
+ to:
+
+ info-cvs-request@prep.ai.mit.edu
+
+ (Don't forget the "-request" or you'll send a message to the whole
+ list, some of whom are capable of remote execution.)
+
+ Mail to the whole list should be sent to:
+
+ info-cvs@prep.ai.mit.edu
+
+ An archive of the mailing list is maintained in the FTP archive
+ mentioned above.
+
+ Last modified: _6/13/1997_
+
+ 6. What happened to the CVS Usenet newsgroup I heard about?
+
+
+ A Usenet newsgroup named "gnu.cvs.info" was announced in April
+ 1993, with an expected creation date of August, 1993. However,
+ nothing came of this.
+
+ If you want to discuss CVS on usenet, the correct group is
+ comp.software.config-mgmt (which also covers other configuration
+ management systems). Someday it might be possible to create a
+ comp.software.config-mgmt.cvs, but only if there is sufficient
+ CVS traffic on comp.software.config-mgmt.
+
+ kingdon@cyclic.com
+
+ Last modified: _9/6/1997_
+ _________________________________________________________________
+
+ [Add an answer to this category]
+
+ [Category /]
+ _________________________________________________________________
+
+ _Search the FAQ-O-Matic:_ ____________________ Search
+ [matching all words]
+ Or look for questions modified in the last: [7.] Days
+ _________________________________________________________________
+
+ The FAQ-O-Matic lives at http://gille.loria.fr:7000/cgi-bin/faqomatic.
+ The code was written by Jon Howell, and the content by folks from all
+ over the web.
+ _________________________________________________________________
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..e294576
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,453 @@
+How to write code for CVS
+
+* License of CVS
+
+ CVS is Copyright (C) 1989-2005 The Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ More details are available in the COPYING file but, in simplified
+ terms, this means that any distributed modifications you make to
+ this software must also be released under the GNU General Public
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+* Source
+
+Patches against the development version of CVS are most likely to be accepted:
+
+ $ export CVS_RSH="ssh"
+ $ cvs -z3 -d:ext:anoncvs@savannah.nongnu.org:/cvsroot/cvs co ccvs
+
+* Compiler options
+
+If you are using GCC, you'll want to configure with -Wall, which can
+detect many programming errors. This is not the default because it
+might cause spurious warnings, but at least on some machines, there
+should be no spurious warnings. For example:
+
+ $ ./configure CPPFLAGS=-Wall
+
+* Backwards Compatibility
+
+Only bug fixes are accepted into the stable branch. New features should be
+applied to the trunk.
+
+If it is not inextricable from a bug fix, CVS's output (to stdout/stderr)
+should not be changed on the stable branch in order to best support scripts and
+other tools which parse CVS's output. It is ok to change output between
+feature releases (on the trunk), though such changes should be noted in the
+NEWS file.
+
+Changes in the way CVS responds to command line options, config options, etc.
+should be accompanied by deprecation warnings for an entire stable series of
+releases before being changed permanently, if at all possible.
+
+* Indentation style
+
+CVS mostly uses a consistent indentation style which looks like this:
+
+void
+foo (char *arg, int c)
+{
+ long aflag;
+
+ if (arg)
+ {
+ bar (arg);
+ baz (arg);
+ }
+
+ switch (c)
+ {
+ case 'A':
+ aflag = 1;
+ break;
+ case 'E':
+ go to myerr;
+ }
+
+ printf ("Literal string line 1\n"
+ "Literal string line 2\n"
+ "Literal string line 3\n");
+ return;
+
+ myerr:
+ printf ("Error argument found\n");
+}
+
+ - Do not cast NULL unless it is a stdarg argument to a function.
+
+ - Do not cast functions returning (void *), e.g., xmalloc ().
+
+ - Do not cast non-stdarg arguments to a function to '(void *)'
+ except to drop a 'const' modifier.
+
+ - Snuggle ! close to its expression (i.e., '! foo' => '!foo').
+
+ - Functions and C statements have a space before the "("
+ and the expression does not have a leading or trailing space
+ (i.e., 'if( foo )' => 'if (foo)'), although it is sometimes
+ desirable to add a newline after the "(" for #ifdef'd code.
+
+ - For switch statements, indent 'case' by 2 and the body of the case
+ by an additional 2 spaces.
+
+ - Labels should be indented by 2 spaces rather than the 4 spaces
+ used by the rest of the current block level.
+
+
+ while ((var = next_arg ()) != 0)
+ {
+ again:
+ switch (var)
+ {
+ case ONE:
+ code_for_case_one ();
+ break;
+ case TWO:
+ code_for_case_two ();
+ break;
+ case THREE:
+ push_arg (RESET_ONE);
+ var = ONE;
+ go to again;
+ default:
+ code_for_default_case ():
+ break;
+ }
+ }
+
+ - NULL-protected free goes on one line if possible, for example:
+
+ if (var)
+ free (var);
+ if (var2 != NULL)
+ free (var2);
+
+ should be written as:
+
+ if (var) free (var);
+ if (var2) free (var2);
+
+ if the value needs to be set to NULL after the free, then use
+
+ if (var)
+ {
+ free (var):
+ var = NULL;
+ }
+
+ as the idiom.
+
+ - Use whitespace in arithmetic expressions, for example
+
+ foo (arg+2);
+
+ should be written as
+
+ foo (arg + 2);
+
+ likewise for normal arithmetic expression assignments.
+
+ - Argument lists get a space after a comma.
+
+ - Do not parenthesize return values unless the expression needs to
+ span multiple lines.
+
+ - Cast negative constants when used in assignments or comparisons
+ with unsigned types.
+
+ - Try to be consistent with block comments:
+
+ /* This is a good block comment (spanning multiple lines of text).
+ * It starts with slash-star, leads each line with a star aligned with
+ * the first, and ends with a similarly aligned star-slash on a line
+ * by itself.
+ */
+
+ /* This is a bad block comment,
+ because it can make it hard to tell what is code
+ and what is not code. */
+
+ - Sentences in comments should have a double space between each
+ period (.) and the beginning of the next sentence.
+
+ - Conditional expressions that need to be split should put the ?
+ operator on the new line.
+
+ - Follow GNU standards for breaking logical expressions over
+ multiple lines where possible.
+
+ - Do not snuggle open-lbrace blocks.
+
+ - Remove '#if 0' code where possible. Add a comment FIXME if it
+ really is a possible problem.
+
+ - Remove commented-out code where possible (FIXME blocks are
+ excepted).
+
+The file cvs-format.el contains settings for emacs and the NEWS file
+contains a set of options for the indent program which I haven't tried
+but which are correct as far as I know. You will find some code which
+does not conform to this indentation style; the plan is to re-indent it
+as those sections of the code are changed (one function at a time,
+perhaps).
+
+In a submitted patch it is acceptable to refrain from changing the
+indentation of large blocks of code to minimize the size of the patch;
+the person checking in such a patch should re-indent it.
+
+* Portability
+
+The general rule for portability is that it is only worth including
+portability cruft for systems on which people are actually testing and
+using new CVS releases. Without testing, CVS will fail to be portable
+for any number of unanticipated reasons.
+
+CVS is now assuming a freestanding C89 compiler. If you don't have one, you
+should find an old release of GCC that did not require a freestanding C89
+compiler to build, build that on your system, build a newer release of GCC
+if you wish, then build CVS using GCC as your freestanding C89 compiler.
+
+A freestanding C89 compiler is guaranteed to support function prototypes,
+void *, and assert().
+
+The following headers can be assumed and are included from lib/system.h for a
+freestanding C89 implementation: <float.h>, <limits.h>, <stdarg.h>, <stddef.h>.
+We are not assuming the other standard headers listed by C89 (hosted headers)
+because these four headers are the only headers guaranteed to be shipped with
+a C89 compiler (freestanding compiler). We are not currently assuming that the
+system the compiler is running on provides the rest of the C89 headers.
+
+The following C89 hosted headers can be assumed due to their presence in UNIX
+version 7 and are included from lib/system.h: <assert.h>, <ctype.h>, <errno.h>,
+<math.h>, <setjmp.h>, <signal.h>, <stdio.h>. <time.h> can also be assumed but
+is included via lib/xtime.h via lib/system.h to include some Autoconf magic
+which avoids including <time.h> and <sys/time.h> on systems that can't handle
+both.
+
+The following C89 headers are also assumed since we believe GCC includes them
+even on systems where it is installed as a freestanding compiler when the
+system lacks them, despite their not being required: <stdlib.h>, <string.h>.
+When the system does not lack these headers, they can sometimes not be
+standards compatible, but GCC provides a script, `fixincludes', for the purpose
+of fixing ANSI conformance problems and we think we can rely on asking users to
+either use GCC or run this script to fix conformance problems manually. A
+GNULIB developer has made a statement that if this turns out to be a problem,
+GNULIB <stdlib.h> and <string.h> substitutes could be included in GNULIB, so if
+we discover the problem, this should be discussed on <bug-gnulib@gnu.org>.
+
+A substitute C99 <stdbool.h> is included from GNULIB for platforms that lack
+this header. Please see the comments in the lib/stdbool_.h file for its
+limitations.
+
+<sys/types.h> can be assumed despite a lack of a presence in even C99, since
+it has been around nearly forever and no-one has ever complained about our code
+assuming its existence.
+
+CVS has also been assuming <pwd.h> for some time. I am unsure of the
+rationale.
+
+GNULIB also assumes <sys/stat.h>. I am unsure of the rationale.
+
+A substitute POSIX.2 <fnmatch.h> header and fnmatch() function is provided for
+systems that lack them. Similarly for the non-standard <alloca.h> header and
+alloca() function. Other substitute headers and functions are also provided
+when needed. See the lib directory or the maint-aux/srclist.txt file for more
+information.
+
+Please do not use multi-line strings. Despite their common acceptance by many
+compilers, they are not part of the ANSI C specification. As of GCC version
+3.3, they are no longer supported. See the Indentation Style section above for
+an example of a literal string which is not multi-line but which will print
+multiple lines.
+
+* Other style issues
+
+When composing header files, do not declare function prototypes using the
+`extern' storage-class identifier. Under C89, there is no functional
+difference between a function declaration with and without `extern', unless the
+function is declared `static'. This is NOT the case for global variables.
+Global variables declared in header files MUST be declared `extern'. For
+example:
+
+/* Global variables */
+extern int foo;
+extern char *bar;
+
+/* Function declarations */
+int make_foo(void);
+char *make_bar(int _foobar);
+
+* Run-time behaviors
+
+Use assert() to check "can't happen" conditions internal to CVS. We
+realize that there are functions in CVS which instead return NULL or
+some such value (thus confusing the meaning of such a returned value),
+but we want to fix that code. Of course, bad input data, a corrupt
+repository, bad options, etc., should always print a real error
+message instead.
+
+Do not use arbitrary limits (such as PATH_MAX) except perhaps when the
+operating system or some external interface requires it. We spent a
+lot of time getting rid of them, and we don't want to put them back.
+If you find any that we missed, please report it as with other bugs.
+In most cases such code will create security holes (for example, for
+anonymous read-only access via the CVS protocol, or if a WWW cgi script
+passes client-supplied arguments to CVS).
+
+Although this is a long-term goal, it also would be nice to move CVS
+in the direction of reentrancy. This reduces the size of the data
+segment and will allow a multi-threaded server if that is desirable.
+It is also useful to write the code so that it can be easily be made
+reentrant later. For example, if you need to pass data to some functions,
+you need a static variable, but use a single pointer so that when the function
+is fixed to pass along the argument, then the code can easily use that
+argument.
+
+* Coding standards in general
+
+Generally speaking the GNU coding standards are mostly used by CVS
+(but see the exceptions mentioned above, such as indentation style,
+and perhaps an exception or two we haven't mentioned). This is the
+file standards.text at the GNU FTP sites. The primary URL for this
+information is http://www.gnu.org/prep/standards/ which contains links
+to many different formats of the standards.
+
+* Regenerating Build Files (UNIX)
+
+On UNIX, if you wish to change the build files, you will need Autoconf and
+Automake.
+
+Some combinations of Automake and Autoconf versions may break the
+CVS build if file timestamps aren't set correctly and people don't
+have the same versions the developers do, so the rules to run them
+automatically aren't included in the generated Makefiles unless you run
+configure with --enable-maintainer-mode.
+
+The CVS Makefiles and configure script were built using Automake 1.9.6 and
+Autoconf 2.59, respectively.
+
+There is a known bug in Autoconf 2.57 that will prevent the configure
+scripts it generates from working on some platforms. Other combinations of
+autotool versions may or may not work. If you get other versions to work,
+please send a report to <bug-cvs@nongnu.org>.
+
+* Regenerating Build Files (Windows)
+
+If for some reason you end up regenerating the *.mak files to submit a patch,
+please run windows-NT/fix-msvc-mak.pl to remove the absolute paths from the
+generated *.mak files before generating any patches.
+
+* Rebuilding Yacc sources
+
+The lib/getdate.y file requires GNU Bison 1.875 to rebuild lib/getdate.c. Not
+having GNU Bison 1.875 should not stop the build unless the lib/getdate.c file
+is actually missing, perhaps deleted via `make maintainerclean'.
+
+* Writing patches (strategy)
+
+Only some kinds of changes are suitable for inclusion in the
+"official" CVS. Bugfixes, where CVS's behavior contradicts the
+documentation and/or expectations that everyone agrees on, should be
+OK (strategically). For features, the desirable attributes are that
+the need is clear and that they fit nicely into the architecture of
+CVS. Is it worth the cost (in terms of complexity or any other
+tradeoffs involved)? Are there better solutions?
+
+If the design is not yet clear (which is true of most features), then
+the design is likely to benefit from more work and community input.
+Make a list of issues, or write documentation including rationales for
+how one would use the feature. Discuss it with coworkers, a
+newsgroup, or a mailing list, and see what other people think.
+Distribute some experimental patches and see what people think. The
+intention is arrive at some kind of rough community consensus before
+changing the "official" CVS. Features like zlib, encryption, and
+the RCS library have benefited from this process in the past.
+
+If longstanding CVS behavior, that people may be relying on, is
+clearly deficient, it can be changed, but only slowly and carefully.
+For example, the global -q option was introduced in CVS 1.3 but the
+command -q options, which the global -q replaced, were not removed
+until CVS 1.6.
+
+* Writing patches (tactics)
+
+When you first distribute a patch it may be suitable to just put forth
+a rough patch, or even just an idea. But before the end of the
+process the following should exist:
+
+ - ChangeLog entry (see the GNU coding standards for details).
+
+ - Changes to the NEWS file and cvs.texinfo, if the change is a
+ user-visible change worth mentioning.
+
+ - Somewhere, a description of what the patch fixes (often in
+ comments in the code, or maybe the ChangeLog or documentation).
+
+ - Most of the time, a test case (see TESTS). It can be quite
+ frustrating to fix a bug only to see it reappear later, and adding
+ the case to the testsuite, where feasible, solves this and other
+ problems. See the TESTS file for notes on writing new tests.
+
+If you solve several unrelated problems, it is generally easier to
+consider the desirability of the changes if there is a separate patch
+for each issue. Use context diffs or unidiffs for patches.
+
+Include words like "I grant permission to distribute this patch under
+the terms of the GNU Public License" with your patch. By sending a
+patch to bug-cvs@nongnu.org, you implicitly grant this permission.
+
+Submitting a patch to bug-cvs is the way to reach the people who have
+signed up to receive such submissions (including CVS developers), but
+there may or may not be much (or any) response. If you want to pursue
+the matter further, you are probably best off working with the larger
+CVS community. Distribute your patch as widely as desired (mailing
+lists, newsgroups, web sites, whatever). Write a web page or other
+information describing what the patch is for. It is neither practical
+nor desirable for all/most contributions to be distributed through the
+"official" (whatever that means) mechanisms of CVS releases and CVS
+developers. Now, the "official" mechanisms do try to incorporate
+those patches which seem most suitable for widespread usage, together
+with test cases and documentation. So if a patch becomes sufficiently
+popular in the CVS community, it is likely that one of the CVS
+developers will eventually try to do something with it. But dealing
+with the CVS developers may be the last step of the process rather
+than the first.
+
+* What is the schedule for the next release?
+
+There isn't one. That is, upcoming releases are not announced (or
+even hinted at, really) until the feature freeze which is
+approximately 2 weeks before the final release (at this time test
+releases start appearing and are announced on info-cvs). This is
+intentional, to avoid a last minute rush to get new features in.
+
+* Mailing lists
+
+In addition to the mailing lists listed in the README file, developers should
+take particular note of the following mailling lists:
+
+ bug-cvs: This is the list which users are requested to send bug reports
+ to. General CVS development and design discussions also take place on
+ this list.
+ info-cvs: This list is intended for user questions, but general CVS
+ development and design discussions sometimes take place on this list.
+ cvs-cvs: The only messages sent to this list are sent
+ automatically, via the CVS `loginfo' mechanism, when someone
+ checks something in to the master CVS repository.
+ cvs-test-results: The only messages sent to this list are sent
+ automatically, daily, by a script which runs "make check"
+ and "make remotecheck" on the master CVS sources.
+
+To subscribe to any of these lists, send mail to <list>-request@nongnu.org
+or visit http://savannah.nongnu.org/mail/?group=cvs and follow the instructions
+for the list you wish to subscribe to.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..56b077d
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PREFIX', the package will
+use PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script). Here is a another example:
+
+ /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/MINOR-BUGS b/MINOR-BUGS
new file mode 100644
index 0000000..9eb0e7b
--- /dev/null
+++ b/MINOR-BUGS
@@ -0,0 +1,61 @@
+Low-priority bugs go here. Actually, most every documented bug is
+"low-priority"--in the sense that if it is documented it means noone
+has gotten around to fixing it.
+
+
+* "cvs update -ko -p -r REV file" doesn't seem to pay attention to the
+ '-ko', at least in client/server mode. A simple work around is to
+ temporarily change the db file with "cvs admin -ko file", then switch
+ it back to the original modes after the checkout (probably '-kkv').
+
+* "cvs status" has a difference in its output between local and
+ client/server mode. Namely there's a tab character followed by a
+ ctime(3)-style date string at the end of the "Working revision:"
+ field.
+
+* commands which don't work in a local working directory should probably
+ ignore any CVS/Root values and revert to using CVSROOT alone. The
+ current use of CVS/Root can be very confusing if you forget you're in
+ a working directory for a remote module -- something that's very easy
+ to do since CVS hides the client operation very well, esp. for
+ commands which fail for this reason. The only clue might be the word
+ "server" in a message such as this:
+ cvs server: cannot find module `patch' - ignored
+
+* cvs init may gave a strange error at times:
+ ttyp4:<woods@clapton> $ cvs -d /local/src-CVS init
+ cvs [init aborted]: cannot open CVS/Root: No such file or directory
+ but it seemed to work just the same.... Note that at the time CVSROOT
+ was set to point to a CVS server using the ":server:" option.
+
+* If a ~/CVS/Root file exists on the server and you are using rsh to
+connect to the server, CVS may loose its mind (this was reported in
+May 1995 and I suspect the symptoms have changed, but I have no
+particular reason to think the bug is fixed -kingdon, Sep 96).
+
+* (Jeff Johnson <jbj@jbj.org>)
+ I tried a "cvs status -v" and received the following:
+
+ ? CVS
+ ? programs/CVS
+ ? tests/CVS
+ cvs server: Examining .
+ ===================================================================
+ File: Install.dec Status: Up-to-date
+ ...
+
+ I claim that CVS dirs should be ignored.
+ (This reportedly happens if "cvs add CVS" (or "cvs add *")
+ is followed by "cvs status", in client/server mode - CVS 1.9).
+
+* On remote checkout, files don't have the right time/date stamps in
+ the CVS/Entries files. Doesn't look like the C/S protocol has any
+ way to send this information along (according to cvsclient.texi).
+ Perhaps we can spiff it up a bit by using the conflict field for the
+ stamp on the checkout/update command. Please note that this really
+ doesn't do very much for us even if we get it done.
+
+* Does the function that lists the available modules in the repository
+ belong under the "checkout" function? Perhaps it is more logically
+ grouped with the "history" function or we should create a new "info"
+ function?
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..4c1d8ac
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,62 @@
+## Process this file with automake to produce Makefile.in
+# Master Makefile for the GNU Concurrent Versions System.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+## Subdirectories to run make in for the primary targets.
+# Unix source subdirs, where we'll want to run lint and etags:
+# This is a legacy variable from b4 Automake
+USOURCE_SUBDIRS = lib $(ZLIB_SUBDIRS) diff src
+# All other subdirs:
+SUBDIRS = $(USOURCE_SUBDIRS) man doc contrib tools \
+ windows-NT os2 emx vms maint-aux
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST = \
+ .cvsignore \
+ BUGS \
+ ChangeLog.zoo \
+ DEVEL-CVS \
+ FAQ \
+ HACKING \
+ MINOR-BUGS \
+ PROJECTS \
+ README.VMS \
+ TESTS \
+ build.com \
+ cvs-format.el \
+ cvsnt.dep \
+ cvsnt.dsp \
+ cvsnt.dsw \
+ cvsnt.mak \
+ cvs.spec \
+ mktemp.sh \
+ m4/ChangeLog \
+ m4/README
+
+
+## MAINTAINER Targets
+
+.PHONY: localcheck remotecheck proxycheck
+localcheck remotecheck proxycheck: all
+ cd src && $(MAKE) $(AM_MAKEFLAGS) "$@"
+
+.PHONY: doc
+doc:
+ cd doc && $(MAKE) $(AM_MAKEFLAGS) "$@"
+
+# for backwards compatibility with the old makefiles
+.PHONY: realclean
+realclean: maintainer-clean
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..6e399aa
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,770 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Master Makefile for the GNU Concurrent Versions System.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = .
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(srcdir)/cvs.spec.in $(top_srcdir)/configure \
+ $(top_srcdir)/emx/Makefile.in $(top_srcdir)/os2/Makefile.in \
+ $(top_srcdir)/zlib/Makefile.in ABOUT-NLS AUTHORS COPYING \
+ COPYING.LIB ChangeLog INSTALL NEWS TODO build-aux/compile \
+ build-aux/config.guess build-aux/config.rpath \
+ build-aux/config.sub build-aux/depcomp build-aux/install-sh \
+ build-aux/mdate-sh build-aux/missing build-aux/texinfo.tex \
+ build-aux/ylwrap
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno configure.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = cvs.spec emx/Makefile os2/Makefile zlib/Makefile
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+
+# Unix source subdirs, where we'll want to run lint and etags:
+# This is a legacy variable from b4 Automake
+USOURCE_SUBDIRS = lib $(ZLIB_SUBDIRS) diff src
+# All other subdirs:
+SUBDIRS = $(USOURCE_SUBDIRS) man doc contrib tools \
+ windows-NT os2 emx vms maint-aux
+
+ACLOCAL_AMFLAGS = -I m4
+EXTRA_DIST = \
+ .cvsignore \
+ BUGS \
+ ChangeLog.zoo \
+ DEVEL-CVS \
+ FAQ \
+ HACKING \
+ MINOR-BUGS \
+ PROJECTS \
+ README.VMS \
+ TESTS \
+ build.com \
+ cvs-format.el \
+ cvsnt.dep \
+ cvsnt.dsp \
+ cvsnt.dsw \
+ cvsnt.mak \
+ cvs.spec \
+ mktemp.sh \
+ m4/ChangeLog \
+ m4/README
+
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
+ cd $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+cvs.spec: $(top_builddir)/config.status $(srcdir)/cvs.spec.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+emx/Makefile: $(top_builddir)/config.status $(top_srcdir)/emx/Makefile.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+os2/Makefile: $(top_builddir)/config.status $(top_srcdir)/os2/Makefile.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+zlib/Makefile: $(top_builddir)/config.status $(top_srcdir)/zlib/Makefile.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ mkdir $(distdir)
+ $(mkdir_p) $(distdir)/. $(distdir)/build-aux $(distdir)/contrib $(distdir)/doc $(distdir)/emx $(distdir)/m4 $(distdir)/os2 $(distdir)/src $(distdir)/zlib
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
+ check-am clean clean-generic clean-recursive ctags \
+ ctags-recursive dist dist-all dist-bzip2 dist-gzip dist-shar \
+ dist-tarZ dist-zip distcheck distclean distclean-generic \
+ distclean-hdr distclean-recursive distclean-tags \
+ distcleancheck distdir distuninstallcheck dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-recursive \
+ mostlyclean mostlyclean-generic mostlyclean-recursive pdf \
+ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-info-am
+
+
+.PHONY: localcheck remotecheck proxycheck
+localcheck remotecheck proxycheck: all
+ cd src && $(MAKE) $(AM_MAKEFLAGS) "$@"
+
+.PHONY: doc
+doc:
+ cd doc && $(MAKE) $(AM_MAKEFLAGS) "$@"
+
+# for backwards compatibility with the old makefiles
+.PHONY: realclean
+realclean: maintainer-clean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..732099b
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,2140 @@
+Changes since 1.12.12:
+**********************
+
+SECURITY FIXES
+
+* CVS now uses version 1.2.3 of the ZLib compression libraries in order to
+ avoid two recently announced security vulnerabilities in them. Both may be
+ used for denial of service attacks and one may reportedly allow execution of
+ arbitrary code, though this is not confirmed. Please see the CERT
+ vulnerabilities advisories #238678 <http://www.kb.cert.org/vuls/id/238678> &
+ #680620 <http://www.kb.cert.org/vuls/id/680620> for more.
+
+NEW FEATURES
+
+* Thanks to Conrad Pino <conrad@pino.com>, a hang in the Windows client, which
+ had pretty much rendered the client useless, has been fixed.
+
+* A minor problem preventing build of the Kerberos4 client has been fixed.
+
+* The path to the config file may be set as an argument to the CVS server
+ commands.
+
+* Sections of directives specific to one or more repositories and not others
+ may now be specified in the config file.
+
+* %{sV} format strings are now available to the verifymsg trigger, similar to
+ the %{stVv} available to loginfo.
+
+* `cvs watch add' on an empty directory no longer clears watchers, and
+ specifying a directory for `cvs watch add' now (correctly) sets default
+ attributes.
+
+* Missing CVSROOT/history files will now cause CVS to attempt to create one.
+ To suppress history logging, set LogHistory equal to the empty string in
+ CVSROOT/config.
+
+* There are several new options available in CVSROOT/config. These are
+ TmpDir, HistoryLogPath, HistorySearchPath, MinCompressionLevel, &
+ MaxCompressionLevel. Please see the manual for more.
+
+* CVS on Solaris 10 was refusing to parse command options. This has been
+ fixed.
+
+* The Windows client now creates locks compatible with older versions of CVS by
+ default. This should only be relevant if your client is accessing a local
+ repository concurrently with another, older client. If you would like to
+ disable compatibility mode (because it is slightly faster), edit the
+ LOCK_COMPATIBILITY flag in windows-NT/config.h and recompile.
+
+* Misc efficiency and portability improvements.
+
+BUG FIXES
+
+* Thanks to Serguei E. Leontiev <lse@CryptoPro.ru>, CVS with Kerberos 5 GSSAPI
+ should automatically link on FreeBSD 5.x. (bug #14639).
+
+* Thanks to Rahul Bhargava <rahul@wandisco.com>, heavily loaded systems
+ suffering from a disk crash or power failure will not lose data they claimed
+ to have committed.
+
+* CVS server now handles conflict markers in Entry requests as documented.
+
+* CVS now remembers that binary file merge conflicts occurred until the
+ timestamp of the updated binary file changes.
+
+* CVS client now saves some bandwidth by not sending the contents of files
+ with conflicts to the server when it isn't needed.
+
+* CVS now does correct locking during import.
+
+* A problem where the server could block indefinitely waiting for an EOF from
+ the client when compression was enabled has been fixed.
+
+* `cvs diff' no longer splits its arguments on spaces.
+
+* Thanks to an old report and patch from Stewart Brodie <stewart@eh.org>, a
+ potential crash in response to a corrupt RCS file has been fixed.
+
+* CVS now locks the history and val-tags files before writing to them.
+ Especially with large repositories, users should no longer see new warnings
+ about corrupt history records when using the `cvs history' command. Existing
+ corrupt history records will still need to be removed manually. val-tags
+ corruption should have had less obvious effects, but removing the
+ CVSROOT/val-tags file and allowing a 1.11.21 or later version of CVS to
+ regenerate it may eliminate a few odd behaviors and possibly cause a slight
+ speed up of read transactions in large repositories over time.
+
+BUILD ISSUES
+
+* The RPM spec file works again with the most modern versions of `rpm'. It
+ also finds the correct version of install-sh when building the CVS with
+ GSSAPI.
+
+DEVELOPER ISSUES
+
+* We've standardized on Automake 1.9.6 to get some at new features that make
+ our jobs easier. See the HACKING file for more on using the autotools with
+ CVS.
+
+Changes from 1.12.11 to 1.12.12:
+********************************
+
+SERVER SECURITY FIXES
+
+* Thanks to a report from Alen Zukich <alen.zukich@klocwork.com>, several minor
+ security issues have been addressed. One was a buffer overflow that is
+ potentially serious but which may not be exploitable, assigned CAN-2005-0753
+ by the Common Vulnerabilities and Exposures Project
+ <http://www.cve.mitre.org>. Other fixes resulting from Alen's report include
+ repair of an arbitrary free with no known exploit and several plugged memory
+ leaks and potentially freed NULL pointers which may have been exploitable for
+ a denial of service attack.
+
+* Thanks to a report from Craig Monson <craig@malachiarts.com>, minor
+ potential vulnerabilities in the contributed Perl scripts have been fixed.
+ The confirmed vulnerability could allow the execution of arbitrary code on
+ the CVS server, but only if a user already had commit access and if one of
+ the contrib scripts was installed improperly, a condition which should have
+ been quickly visible to any administrator. The complete description of the
+ problem is here: <https://ccvs.cvshome.org/issues/show_bug.cgi?id=224>. If
+ you were making use of any of the contributed trigger scripts on a CVS
+ server, you should probably still replace them with the new versions, to be
+ on the safe side.
+
+ Unfortunately, our fix is incomplete. Taint-checking has been enabled in all
+ the contributed Perl scripts intended to be run as trigger scripts, but no
+ attempt has been made to ensure that they still run in taint mode. You will
+ most likely have to tweak the scripts in some way to make them run. Please
+ send any patches you find necessary back to <bug-cvs@nongnu.org> so that we
+ may again ship fully enabled scripts in the future.
+
+ You should also make sure that any home-grown Perl scripts that you might
+ have installed as CVS triggers also have taint-checking enabled. This can be
+ done by adding `-T' on the scripts' #! lines. Please try running
+ `perldoc perlsec' if you would like more information on general Perl security
+ and taint-checking.
+
+NEW FEATURES
+
+* Thanks to a report from Ian Abbott <abbotti@mev.co.uk>, a problem that caused
+ CVS to stop with broken assertions in certain time zones when daylight
+ savings is in effect has been fixed.
+
+* A problem where a proxy server could fail to notice that its primary closed
+ the connection has been fixed.
+
+* Failures to open the CVS_CLIENT_LOG, CVS_SERVER_LOG, and CVS_SECONDARY_LOG
+ are no longer fatal.
+
+* CVS's client and server IO buffers now rely on a GNULIB modules for memory
+ management rather than taking on the task themseleves. This should be faster
+ on any system but may increase memory usage noticably on systems without the
+ POSIX mmap() function. Benchmark reports to <bug-cvs@gnulib.org> would be
+ welcome.
+
+* Some more GNULIB functions have been imported and/or updated for portability
+ reasons. This change should not be visible to most users, though CVS may now
+ compile on a few more platforms.
+
+* CVS creates a unique session id that gets written to the RCS files during
+ import and commit. When committing several files at once, they all get the
+ same 'commitid'. The commitid becomes visible with log and status commands,
+ and is derived and compatible with the cvsnt project.
+
+* CVS once again compiles correctly configured with various combinations of
+ --disable-client, --disable-server, and --disable-proxy.
+
+* CVS now accepts the <tag>:<date> format, which has long been acceptable as an
+ argument to -j options, in most places where <tag> used to be acceptable. An
+ empty tag in this format (e.g. ":<date>"), which used to be rejected, is now
+ interpreted as specifying a date on the trunk.
+
+* CVS now uses ZLib 1.2.2. This fixes the minor vulnerability described here:
+ <http://www.kb.cert.org/vuls/id/238678>, as well as some other minor bugs we
+ are not aware of bug reports for in conjunction with CVS.
+
+* `cvs -n release' now does what it should (see changes to the info-cleanup-0
+ test in sanity.sh for more).
+
+* The configure script now prefers `ssh' to `rsh' when determining a default
+ executable to use when connecting via the :ext: method.
+
+* A problem in the compression buffer that was causing some incompatibility
+ with some 3rd party CVS clients when compression was enabled has been fixed.
+
+* Some files missing from the distribution have been added or readded. The
+ missing files were mostly development support files, with a few docs and
+ .cvsignore files thrown in.
+
+* The incomplete Brazillian Portugese translation of the CVS manual is now
+ included in the distribution.
+
+BUG FIXES
+
+* Misc bug and documentation fixes.
+
+* CVS now detects write errors on standard output. Before, e.g.,
+ `cvs update -p FILE > /dev/full' would fail to report the write error.
+
+* Thanks to a report and a patch from Georg Scwharz <georg.scwarz@freenet.de>
+ CVS now builds without error on IRIX 5.3
+
+DEVELOPER ISSUES
+
+* We've standardized on Automake 1.9.5 to get some at new features that make
+ our jobs easier. See the HACKING file for more on using the autotools with
+ CVS.
+
+Changes from 1.12.10 to 1.12.11:
+********************************
+
+NEW FEATURES
+
+* Thanks to Conrad Pino <conrad@pino.com>, the Windows build works once again.
+
+* CVSROOT methods and option names are now case insensitive
+
+* CVSROOT methods :ext: and :fork: now support the CVS_SERVER option.
+
+* CVSROOT method :ext: now supports the CVS_RSH and Redirect options.
+
+* Date handling has been improved slightly.
+
+* Miscellaneous bug fixes.
+
+* Miscellaneous documentation fixes.
+
+BUG FIXES
+
+* An intermittant assertion failure in checkout has been fixed.
+
+* Thanks to a report from Chris Bohn <cbohn@rrinc.com>, all the source files
+ needed to build on Windows are now included in the source distribution.
+
+Changes from 1.12.9 to 1.12.10:
+*******************************
+
+NEW FEATURES
+
+* The date formats which CVS accepts are now documented more fully in the
+ manual.
+
+* CVS commands which accept dates now understand some more time zones,
+ including those which are some hours plus some fraction of an hour off of
+ universal coordinated time.
+
+* `cvs ls filename' no longer causes an assertion failure.
+
+* The maximum length of the discovered comment leader used in a Log keyword
+ substitution is now limited to 20 characters by default. If a longer leader
+ is discovered, then the keyword is not expanded. This default behavior may
+ be altered using the new MaxCommentLeaderLength & UseArchiveCommentLeader
+ config options.
+
+* Commit messages once again include the full relative path to the file being
+ committed.
+
+* Thanks to funding from Juniper Networks <http://juniper.net>, "write proxy"
+ functionality has been added to the CVS server. Write proxy functionality
+ allows any of multiple, read-only "secondary" servers to relay write requests
+ from clients to a single primary CVS server, allowing for a massive
+ redistribution of server load which is transparent to all known CVS clients.
+
+* Thanks to funding from Juniper Networks <http://juniper.net>, some code has
+ been added which second-guesses the system file cache for a performance
+ boost.
+
+* The loginfo scripting hook now runs after the administrative files in CVSROOT
+ are rebuilt, rather than before.
+
+* Misc error message improvements.
+
+* Thanks to funding from Juniper Networks <http://juniper.net>, new scripting
+ hooks have been added to the CVS server. These are the postadmin, posttag,
+ and postwatch hooks. See the manual for more info.
+
+* Thanks to funding from Juniper Networks <http://juniper.net>, all the
+ existing scripting hooks may now optionally be passed a command name
+ argument.
+
+* Thanks to funding from Juniper Networks <http://juniper.net>, new tags are
+ cached in the val-tags file at the time of tag creation.
+
+* Thanks to a patch from Brian Murphy <brian@murphy.dk>, CVS now supports PAM
+ session management.
+
+* Thanks to a report from Brian Murphy <brian@murphy.dk>, the demo PAM
+ configuration files mentioned in the manual are actually being distributed.
+
+* Thanks again to Bart Robinson <lomew@pobox.com>, `cvs log' & `cvs ls' now
+ actually output local times when the server is version 1.12.9 or greater and
+ the client is version 1.12.10 or greater.
+
+* The CVS server now sends paths to files relative to the repository. CVS
+ clients have been able to handle this since at least the 10 year old
+ CVS 1.9.2 release, so no attempt at verifying compatibility of clients has
+ been made. This saves a small amount of bandwidth and may enable some future
+ functionality.
+
+* The CVS client will send relative Directory requests if the server claims to
+ support it. This saves a very small amount of bandwidth but may enable some
+ future functionality.
+
+* "cvs import" now has a new option, `-X', which causes new files to be
+ imported in a way that they appear only on the vendor branch, and do not
+ automatically appear on the main trunk.
+
+ This option may be made the default on a repository-wide basis
+ using the new ImportNewFilesToVendorBranchOnly=yes option in
+ CVSROOT/config.
+
+* contrib/cvs_acls.in has been revised. Users of the old version will
+ want to upgrade to use the new format. See the documentation in
+ contrib/cvs_acls.html for more information.
+
+* Thanks to Dan Peterson <dbpete@aol.com>, the contrib/validate_repo script now
+ accepts and logs corrupted revision numbers in RCS archives.
+
+BUG FIXES
+
+* Thanks to a report from Gottfried Ganssauge <gotti@cvshome.org>, CVS no
+ longer exits when it encounters links pointing to paths containing more
+ than 128 characters.
+
+* Thanks to a report from Dan Peterson <dbpete@aol.com>, error messages from
+ GSSAPI servers are no longer truncated.
+
+* Thanks to a report from Dan Peterson <dbpete@aol.com>, attempts to resurrect
+ a file on the trunk that was added on a branch no longer causes an assertion
+ failure.
+
+* Thanks to a report from Dan Peterson <dbpete@aol.com>, imports to branches
+ like "1.1." no longer create corrupt RCS archives.
+
+* Thanks to a report from Chris Bohn <cbohn@rrinc.com>, links from J.C. Hamlin
+ <jchamlin@ibsys.com>, and code posted by Jonathan Gilligan, we think we have
+ finally corrected the Windows "red-file" (daylight savings time) bug once and
+ for all.
+
+* Thanks to a patch from Jeroen Ruigrok/asmodai <asmodai@wxs.nl>, the
+ log_accum.pl script should no longer elicit warnings from Perl 5.8.5.
+
+* The r* commands (rlog, rls, etc.) can once again handle requests to run
+ against the entire repository (e.g. `cvs rlog .'). Thanks go to Dan Peterson
+ <dbpete@aol.com> for the report.
+
+* A problem where the attempted access of files via tags beginning with spaces
+ could cause the CVS server to hang has been fixed. This was a particular
+ problem with WinCVS clients because users would sometimes accidentally
+ include spaces in tags pasted into a dialog box. This fix also altered some
+ of the error messages generated by the use of invalid tags. Thanks go to Dan
+ Peterson <dbpete@aol.com> for the report.
+
+* Thanks to James E Wilson <wilson@specifixinc.com> for a bug fix to
+ modules processing "gcc-core -a !gcc/f gcc" will no longer exclude
+ gcc/fortran by mistake.
+
+* Thanks to Conrad Pino <conrad@pino.com>, the Windows build works once again.
+
+* Misc updates to the manual.
+
+DEVELOPER ISSUES
+
+* We've standardized on Automake 1.9.3 to get some at new features that make
+ our jobs easier. See the note below on the Autoconf upgrade for more
+ details.
+
+* We've standardized on Autoconf version 2.59 to get presumed bug fixes and
+ features, but nothing specific. Mostly, once we decide to upgrade one of the
+ autotools we just figure it'll save time later to grab the most current
+ versions of the others too. See the HACKING file for more on using the
+ autotools with CVS.
+
+Changes from 1.12.8 to 1.12.9:
+******************************
+
+SERVER SECURITY FIXES
+
+* Thanks to Stefan Esser & Sebastian Krahmer, several potential security
+ problems have been fixed. The ones which were considered dangerous enough
+ to catalogue were assigned issue numbers CAN-2004-0416, CAN-2004-0417, &
+ CAN-2004-0418 by the Common Vulnerabilities and Exposures Project. Please
+ see <http://www.cve.mitre.org> for more information.
+
+* A potential buffer overflow vulnerability in the server has been fixed.
+ This addresses the Common Vulnerabilities and Exposures Project's issue
+ #CAN-2004-0414. Please see <http://www.cve.mitre.org> for more information.
+
+NEW FEATURES
+
+* `cvs log' & `cvs ls' now output local times when both the server and client
+ are 1.12.9 or greater. (Thanks to Bart Robinson <lomew@pobox.com>.)
+
+DEVELOPER NOTES
+
+* The windows-NT/config.h.in file is now generated dynamically from the
+ root config.h.in file and a few inputs in the windows-NT directory in hopes
+ of keeping it more in sync with the root config.h.in file.
+
+Changes from 1.12.7 to 1.12.8:
+******************************
+
+SERVER SECURITY FIXES
+
+* A potential buffer overflow vulnerability in the server has been fixed.
+ Prior to this patch, a malicious client could potentially use carefully
+ crafted server requests to run arbitrary programs on the CVS server machine.
+ This addresses the Common Vulnerabilities and Exposures Project's issue
+ #CAN-2004-0396. Please see <http://www.cve.mitre.org> for more information.
+
+NEW FEATURES
+
+* Some redundant output generated by the `cvs commit' command has been removed.
+
+* Most output from the `cvs commit' command is suppressed when the -Q global
+ option is specified.
+
+* Repository directory browsing via `cvs rls' & `cvs ls' commands. Expect
+ changes in the long format output soon. The "entries" format output should
+ remain fairly stable for automated parsers.
+
+* Glob matches, as specified in ignore lists and wrapper options, now conform
+ to the POSIX.2 specification for fnmatch on all platforms.
+
+* The Windows MS Visual C++ project files, including the nmake build files,
+ are now generated with MSVC++ 6.0, but should still work with MSVC++ 5.0.
+
+BUG FIXES
+
+* The cvs.1 man page is now generated automatically from a section of the CVS
+ Manual.
+
+* Thanks to a report from Mark Andrews at the Internet Systems Consortium, the
+ :ext: connection method no longer relies on a transparent transport that uses
+ an argument processor that can handle arbitrary ordering of options and other
+ arguments when using a username other than the caller's.
+
+* Thanks to Ken Raeburn at MIT, directory deletion, whether via `cvs release'
+ or empty directory pruning, now works on network shares under Windows XP.
+
+Changes from 1.12.6 to 1.12.7:
+******************************
+
+SERVER SECURITY ISSUES
+
+* Piped checkouts of paths above $CVSROOT no longer work. Previously, clients
+ could have requested the contents of RCS archive files anywhere on a CVS
+ server. This addresses CVE issue CAN-2004-0405. Please see
+ <http://www.cve.mitre.org> for more information.
+
+CLIENT SECURITY ISSUES
+
+* Clients now check paths from the server to verify that they are within one of
+ the sandboxes the user requested be updated. Previously, a trojan server
+ could have written or overwritten files anywhere the user had access,
+ presenting a serious security risk. This addresses CVE issue CAN-2004-1080.
+ Please see <http://www.cve.mitre.org> for more information.
+
+GENERAL USER ISSUES
+
+* Imported the most recent version of regex from GNULIB, which actually means
+ some systems will use now their native regex functions instead of compiling
+ CVS's. Users should notice no changes in CVS responses to regular
+ expressions. If you do, please report them to <bug-cvs@gnu.org>.
+
+* CVS now accepts the location of HTTP tunnel web proxies as part of the
+ CVSROOT string. Actually using a proxy remains untested. Please report
+ problems and successes to <bug-cvs@gnu.org>.
+
+* Configure no longer checks the $TMPDIR, $TMP, & $TEMP variables to set the
+ default temporary directory.
+
+* CVS on Cygwin correctly handles X:\ style paths.
+
+* Import now uses backslash rather than slash on Windows when checking for
+ "CVS" directories to ignore in import commands.
+
+* Relative paths containing up-references (`..') should now work in
+ client/server mode (client fix).
+
+* A race condition between the ordering of messages from CVS and messages from
+ called scripts in client/server mode has been removed (server fix).
+
+* The check_cvs and cvscheck scripts in the contrib directory have been renamed
+ validate_repo and sandbox_status, respectively, in the interests of clarity.
+
+* The Windows MS Visual C++ 6.0 project files have been brought up to date.
+ The nmake build files were regenerated from these files with MSVC++ 5.0.
+
+* A memory allocation bug on Windows that could cause at least executions of
+ `cvs status' to fail has been fixed (client fix).
+
+* Resurrected files now get their modes and timestamps set correctly and a
+ longstanding bug involving resurrection of an uncommitted removal has been
+ fixed (server fix).
+
+* Some resurrection (cvs add) status messages have changed slightly.
+
+* `cvs release' now works with Kerberos or GSSAPI encryption enabled (server
+ fix).
+
+* File resurrection from a previously existing revision no longer just reports
+ that it works (server fix).
+
+* Misc error & status message corrections.
+
+* Diffing of locally added files against arbitrary revisions in an RCS archive
+ is now allowed when a file of the same name exists or used to exist on some
+ branch (server fix).
+
+* Some user messages have been updated for consistency and spelling.
+
+DEVELOPER ISSUES
+
+* The message source differentiation in the test suite between client and
+ server executables has been repaired.
+
+Changes from 1.12.5 to 1.12.6:
+******************************
+
+GENERAL USER ISSUES
+
+* CVSROOT/*info scripts may not work as expected with executables compiled
+ using VC++ under Windows since all quoting is currently done according to
+ Bourne Shell rules, which probably don't look like command.com rules.
+ Patches gratefully accepted.
+
+* Imports will now always ignore directories and files named `CVS' to avoid
+ violating assumptions made by other parts of CVS.
+
+* Directories specified to `checkout -d' are no longer required to exist. This
+ consolidates some behavior between `-d' options specified in the modules file
+ and `checkout -d' as well as removing some prior differences between local
+ and client/server mode operation.
+
+* A problem with `cvs release' of subdirs that could corrupt CVS/Entries files
+ has been fixed (client/server).
+
+* The CVS server's protocol check for unused data from the client is no longer
+ called automatically at program exit in order to avoid potential recursive
+ calls to error when the first close is due to memory allocation or similar
+ problems that cause calls to error() to fail. The check is still made when
+ the server program exits normally.
+
+* The CVSROOT/*info files want a new command format and the old style strings
+ have been deprecated. Please see the manual for more information on the new
+ format.
+
+* The spec file has been updated to work with more recent versions of RPM.
+
+* Some more GNULIB functions have been imported and/or updated for portability
+ reasons.
+
+* Several memory leaks have been plugged.
+
+* A seg fault which always occurred after waiting on another process's lock
+ in order to establish a promotable lock is now avoided.
+
+* An unlikely potential segfault when using the :fork: connection method has
+ been fixed.
+
+* The CVS server has had the protocol check for unused data from the client
+ partially restored.
+
+* A fix has been included that should avoid a very rare race condition that
+ could cause a CVS server to exit with a "broken pipe" message.
+
+* Infinite alias loops in the modules file are now checked for and avoided.
+
+* Clients on case insensitive systems now preserve the case of directories in
+ CVS/Entries, in addition to files, for use in communications with the CVS
+ server.
+
+* Misc status message fixes for consistency.
+
+* Some previously untested behavior is now being tested.
+
+* Server no longer claims to support the "Case" request.
+
+* Case insensitive clients once again preserve the case of filenames in
+ CVS/Entries for communication with the server, as specified in the CVS
+ client/server protocol spec. Note that all CVS _servers_ still lack support
+ for case insensitive clients - servers are relying on the client to preserve
+ the case of checked out files.
+
+* Thanks to Ville Skyttä the man page has a few less spelling errors and is
+ slightly more accurate.
+
+* Thanks to Ville Skyttä some unused variables were removed from the log_accum
+ Perl script in contrib.
+
+* Thanks to Alexey Mahotkin, a bug that prevented CVS from being compiled with
+ Kerberos 4 authentication enabled has been fixed.
+
+* A minor bug that caused CVS to fail to report an inifinte alias loop in the
+ modules file when portions of the alias definition contained trailing slashes
+ has been fixed.
+
+* A bug in the gzip code that could cause heap corruption and segfaults in CVS
+ servers talking to clients less than 1.8 and some modern third-party CVS
+ clients has been fixed.
+
+* mktemp.sh is now included with the source distribution so that the rcs2log
+ and cvsbug executables may be run on systems which do not contain an
+ implementation of mktemp.
+
+* Misc documentation fixes.
+
+DEVELOPER ISSUES
+
+* xmalloc, xstrdup, & some other memory allocating functions are now available
+ vi GNULIB versions imported into lib.
+
+* The asnprintf() & vasnprintf() functions are now available due to a GNULIB
+ implementation.
+
+* Misc cosmetic, readability, and commenting fixes.
+
+Changes between 1.12.4 and 1.12.5:
+**********************************
+
+SERVER SECURITY ISSUES
+
+* pserver can no longer be configured to run as root via the
+ $CVSROOT/CVSROOT/passwd file, so if your passwd file is compromised, it no
+ longer leads directly to a root hack. Attempts to root will also be logged
+ via the syslog.
+
+GENERAL USER ISSUES
+
+* The Windows build files were updated to allow building of the current version
+ under Windows.
+
+Changes between 1.12.3 and 1.12.4:
+**********************************
+
+GENERAL USER ISSUES
+
+* The CVS server no longer locks more than a directory at a time for write, so
+ large commits & tags should now have a much harder time blocking other
+ operations.
+
+* Add support for large files. Use --disable-largefile to omit support
+ for large files.
+
+Changes between 1.12.2 and 1.12.3:
+**********************************
+
+SERVER SECURITY ISSUES
+
+* Malformed module requests could cause the CVS server to attempt to create
+ directories and possibly files at the root of the filesystem holding the CVS
+ repository. Filesystem permissions usually prevent the creation of these
+ misplaced directories, but nevertheless, the CVS server now rejects the
+ malformed requests.
+
+GENERAL USER ISSUES
+
+* Support for case insensitive clients has been removed. This is not as
+ drastic as it sounds, as all of the current tests still pass without
+ modification when run from a case insensitive client to a case sensitive
+ server. In the end this should provide a major stability improvement.
+
+* A minor problem that prevented the correct version of a system ZLIB from
+ being detected on some platforms has been fixed.
+
+* Attempts to use the global `-l' option, removed from both client and server
+ as of version 1.12.1, will now elicit a warning rather than a fatal error
+ from the server.
+
+* The configure script now tests whether it is building CVS on a case
+ insensitive file system. If it is, CVS assumes that all file systems on this
+ platform will be case insensitive. This is useful for getting the case
+ insensitivity flag set correctly when compiling on Mac OS X and under Cygwin
+ on Windows. Autodetection can be overridden using the
+ --disable-case-sensitivity and --enable-case-sensitivity arguments to
+ configure.
+
+DEVELOPER ISSUES
+
+* A new set of tests to test issues specific to case insensitive clients and
+ servers has also been added.
+
+* Support has been added to the test suite to support testing over a :ext: link
+ to another machine, subject to some stringent requirements. This support can
+ be used, for instance, to test the operation of a case insensitive client
+ against a case sensitive server. Please see the comments in TEST and the
+ src/sanity.sh test script itself for more.
+
+* We've standardized on Automake 1.7.9 to get a bug fix. See the note below
+ on the Autoconf upgrade for more details.
+
+* We've standardized on Autoconf version 2.58 to avoid a bug and get at a few
+ new macros. Again, this should only really affect developers, though it is
+ possible that CVS will now compile on a few new platforms. Please see the
+ section of the INSTALL file about using the autotools if you are compiling
+ CVS yourself.
+
+Changes between 1.12.1 and 1.12.2:
+
+* Misc cleanup, reorganization, and other minor fixes.
+
+* A behavior change in `cvs up -jrev1 -jrev2' for modified files with a base
+ revision of rev2 (ie, checked-out version matches rev2 and file has been
+ modified). The operation is no longer ignored and instead is passed to
+ diff3. This will potentially re-apply the diffs between the two revisions to
+ a modified local file. Status messages like from a standard merge have also
+ been added when the file would not or does not change due to this merge
+ request ("[file] already contains the changes between [revisions]...").
+
+* A build problem that caused warnings and slower builds on systems without a
+working getline() function (e.g. Mac OS X 10.1) has been fixed.
+
+* A build problem that prevented the CVS executable from being built on systems
+with the gettext library installed has been fixed.
+
+* A bug which could stop `cvs admin -mTAG:message' from recursing has been
+ fixed.
+
+* Misc documentation cleanup and fixes.
+
+* Some of the contrib scripts, some of the documentation, and sanity.sh were
+ modified to use and recommend more portable commands rather than using and
+ recommending commands which were not compatible with the POSIX 1003.1-2001
+ specification.
+
+* CVS now knows how to report, as well as record, `P' record types.
+
+* When running the `cvs history' command, clients will now send the
+ long-accepted `-e' option, for all records, rather than explicitly requesting
+ `P' record types, a request which servers prior to 1.11.7 will reject with a
+ fatal error message.
+
+* A problem with locating files requested by case insensitive clients which was
+ accidentally introduced in 1.11.6 as part of a fix for a data loss problem
+ involving `cvs add's from case insensitive clients has been fixed. The
+ relevant error message was `cvs [<command> aborted]: filE,v is ambiguous;
+ could mean FILE,v or file,v'.
+
+* A problem in the CVS getpass library that could cause passwords to echo on
+ some systems has been fixed.
+
+* A segfault that could occur in very rare cases where the stat of a file
+ failed during a diff has been fixed.
+
+* Any user with write privleges to the CVSROOT/checkoutlist file could pass
+arbitrary format strings directly through to a printf function. This was
+probably bad and has been fixed. White space at the beginning of error strings
+in checkoutlist is now ignored properly.
+
+* A chmod 0600 that CVS performed on temp files it created designed to work
+around a bug in versions of GLIBC eariler than 2.0.7 has been removed since it
+still left a race condition open to exploitation and provided a false sense of
+security. If you are linking CVS against a version of GLIBC prior to 2.0.7,
+you should consider upgrading GLIBC.
+
+* The CVSROOT/editinfo file is no longer referenced by CVS. This funcitonality
+has been deprecated for over six years and removing it will presumably not
+cause anyone any problems.
+
+* In client/server mode, most messages from CVS now contain the actual
+command name rather than the generic "server".
+
+* A long-standing bug that prevented most client/server updates from being
+logged in the history file has been fixed.
+
+* Updates done via a patch ("P" status) are now logged in the history file
+by default and the corresponding "P" history record type is now documented.
+If you're setting the LogHistory option in your CVSROOT/config file, you may
+want to add "P" to the list of record types.
+
+* CVS now will always compile its own getpass() function (originally from
+GNULIB) in favor of any system one that may exist. This avoids some problems
+with long passwords on some systems and updates us to POSIX.2 compliance, since
+getpass() was removed from the POSIX.2 specification.
+
+* Support for pre-ANSI compilers has been removed. Our minimum support level
+now assumes at least a freestanding C89 compilers. See the HACKING file for
+more information. If you *really* need K&R support, our Makefile.am files
+should only need minor tweaking to get them to run the ansi2knr script from the
+Automake project. If you get this working, please send a patch to
+<bug-cvs@gnu.org>.
+
+* Experimental support for Pluggable Authentication Modules (PAM) has been
+added, though it is not compiled by default. If you like this feature (or
+don't), please send us feedback. See the Cederqvist, `./configure --help',
+and the INSTALL file for more.
+
+* Command line keyword expansion modes no longer override binary keyword
+expansion modes.
+
+* New LocalKeyword and KeywordExpand options to CVSROOT/config which
+FreeBSD, OpenBSD, and NetBSD users may find familiar as the "tag" and
+"tagexpand" options used for many years. The CVSHeader keyword has
+also been added to the mixture.
+
+* A bug that allowed a write lock to be created in a directory despite
+there being existing read locks when using LockDir in CVSROOT/config has
+been fixed.
+
+* A bug with short patches (`rdiff -s') which caused rdiff to sometimes report
+differences that did not exist has been fixed.
+
+* Some minor corrections were made to the diff code to keep diff & rdiff from
+printing diff headers with empty change texts when two files have different
+revision numbers but the same content.
+
+* The global '-l' option, which suppressed history logging, has been removed
+from both client and server.
+
+Changes from 1.11.5 to 1.12.1:
+
+* The new --with-external-zlib option can be passed to configure to compile
+CVS against an external installed zlib.
+
+* A warning message is now issued if an administrative file contains
+more than one DEFAULT entry.
+
+* An error running a verifymsg script (such as referencing an unset user
+variable or the script not existing) now causes the verification to
+fail.
+
+* Errors in administrative files commands (like unset user variables)
+are no longer reported unless the command is actually executed.
+
+* When a file is initially checked out, its last access time is now set
+to the current time rather than being set to the time the file was last
+checked in like the modification time is.
+
+* The Checkin.prog and Update.prog functionality has been removed. This
+fuctionality previously allowed executables to be specified in the modules file
+to be run at update and checkin time, but users could edit these files on a per
+workspace basis, creating a security hole.
+
+* CVSROOTs which contain a symlink to a real repository should work.
+
+* contrib/rcs2log and src/cvsbug now use the BSD mktemp program to create
+their temp files and directories on systems which provide it.
+
+* Added a UserAdminOptions configuration option to CVSROOT/config to
+control which `cvs admin' commands are not restricted to the `cvsadmin'
+group.
+
+* If the rcsinfo specified template changes after a user has checked
+out a tree, the template in the users' tree will be updated rather
+than remaining static from the time of the original checkout.
+
+* Added a CVSREADONLYFS environment variable and `-R' cvs global
+option to turn on read-only repository mode for local repositories.
+This allows users to checkout from a CDROM repository or other
+read-only filesystem.
+
+* There is a new CVS_LOCAL_BRANCH_NUM environment variable, which
+may be used to give control over the branch number to be used next.
+Useful for having local changes in a CVSup mirrored repository.
+
+* Miscellaneous documentation corrections.
+
+* Corrected the path in a failed write error message.
+
+* Autoconf and Automake are no longer run automatically unless you run
+configure with --enable-maintainer-mode. Accordingly, noautomake.sh is
+no longer needed and has been removed.
+
+* We've standardized on Automake version 1.7.5 and Autoconf version 2.57 to get
+at a few new macros. Again, this should only really affect developers. See
+the section of the INSTALL file about using the autotools if you are compiling
+CVS yourself.
+
+Changes from 1.11.4 to 1.11.5:
+
+* Fixed a security hole in the CVS server by which users with read only access
+could gain write access. This issue does not affect client builds. The
+Common Vulnerabilities and Exposures project (cve.mitre.org) has assigned the
+name CAN-2003-0015 to this issue. See
+<http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2003-0015> for more
+information.
+
+* Fixed some bugs where revision numbers starting with 0 (like 0.3)
+weren't correctly handled. (CVS doesn't normally use such revision
+numbers, but users may be able to force it to do so and old RCS files
+might.)
+
+Changes from 1.11.3 to 1.11.4:
+
+* Some minor changes to allow the code to compile on Windows platforms.
+
+Changes from 1.11.2 to 1.11.3:
+
+* The tag/rtag code has been fixed to once again lock just a single
+directory at a time.
+
+* There was a bug where certain error conditions could cause the server
+to go into an infinite loop. There was also a bug that caused a
+compressed connection from an older client to hang on shutdown. These
+bugs have been fixed.
+
+* Fixed a bug that caused the server to reject most watch commands.
+
+* When waiting for another user's lock, the message timestamps are now
+in UTC rather than the server's local time.
+
+* The options.h file is no longer used. This fixes a bug that occurred when
+1.11.2 was compiled on Windows platforms.
+
+* We've standardized on Automake version 1.6.3 and Autoconf version 2.53.
+They are cleaner, less bug prone, and will hopfully allow me to start updating
+sanity.sh to use Autotest and Autoshell. Again, this should only really affect
+developers. See the section of the INSTALL file about using the autotools if
+you are compiling CVS yourself.
+
+* Fixed a bug in the log/rlog code when a revision range crosses a
+branch point.
+
+* Fixed a bug where filenames starting with - would be misinterpreted as
+options when using client/server mode.
+
+Changes from 1.11.1p1 to 1.11.2:
+
+* There is a new feature, enabled by RereadLogAfterVerify in CVSROOT/config,
+which tells CVS to reread the log message after running the verifymsg
+script. This allows the verifymsg script to reformat or otherwise
+modify the log message.
+
+* The interpretation of revision ranges using :: in "log" and "rlog"
+has changed: a::b now excludes the log message from revision a but
+includes the log message from revision b. Also, revision ranges that
+cross branch points should now work.
+
+* zlib has been updated to version 1.4. There is a security advisory
+out in regards to 1.3. This should fix that problem.
+
+* The "log" and "rlog" commands now have a -S option to suppress the
+header information when no revisions are selected.
+
+* A serious error that allowed read-only users to tag files has been
+corrected.
+
+* The "annotate" command will no longer annotate binary files unless
+you specify the new -F option.
+
+* The "tag" and "rtag" commands will no longer move or delete branch
+tags unless you use the new -B option. (This prevents accidental
+changes to branch tags that are hard to undo.)
+
+* We've standardized on the 1.5 Automake release for the moment. Again, this
+should only really affect developers. See the section of the INSTALL file
+about using the autotools if you are compiling CVS yourself.
+
+Changes from 1.11.1 to 1.11.1p1:
+
+* Read only access was broken - now fixed.
+
+Changes from 1.11 to 1.11.1:
+
+* There was a locking bug in the tag/rtag code that could lose changes
+made to a file while the tag operation was in progress. This has been
+fixed, but all of the directories being tagged are now locked for the
+entire duration of the tag operation rather than only one directory at a
+time.
+
+* The "cvs diff" command now accepts the -y/--side=by-side and -T/
+--initial-tab options. (To use these options with a remote repository,
+both the client and the server must support them.)
+
+* The expansion of the loginfo format string has changed slightly.
+Previously, the expansion was surrounded by single quotes ('); if a file
+name contained a single quote character, the string would not be parsed
+as a single entity by the Unix shell (and it would not be possible to
+parse it unambiguously). Now the expansion is surrounded by double
+quotes (") and any embedded dollar signs ($), backticks (`), backslashes
+(\), and double quotes are preceded by a backslash. This is parsed as a
+single entity by the shell reguardless of content. This change should
+not be noticable unless you're not using a Unix shell or you have
+embedded the format string inside a double quoted string.
+
+* There was a bug in the diff code which sometimes caused conflicts to
+be flagged which shouldn't have been. This has been fixed.
+
+* New "cvs rlog" and "cvs rannotate" commands have been added to get log
+messages and annotations without having to have a checked-out copy.
+
+* Exclusive revision ranges have been added to "cvs log" using ::
+(similar to "cvs admin -o").
+
+* The VMS client now accepts wildcards if you're running VMS 7.x.
+
+* ZLIB has been updated to version 1.1.3, the most current version. This
+includes mostly some optimizations and minor bug fixes.
+
+* The ~/.cvspass file has a slightly modified format. CVSROOTs are now
+stored in a new canonical form - hostnames are now case insensitive and
+port numbers are always stored in the new format. Until a new login for
+a particular CVSROOT is performed with the new version of CVS, new and
+old versions of CVS should interoperate invisibly. After that point, an
+extra login using the old version of CVS may be necessary to continue to
+allow the new and old versions of CVS to interoperate using the same
+~/.cvspass file and CVSROOT. The exception to this rule occurs when the
+CVSROOTs used with the different versions use case insensitively
+different hostnames, for example, "empress", and "empress.2-wit.com".
+
+* A password and a port number may now be specified in CVSROOT for
+pserver connections. The new format is:
+
+ :pserver:[[user][:password]@]host[:[port]]/path
+
+Note that passwords specified in a checkout command will be saved in the
+clear in the CVS/Root file in each created directory, so this is not
+recommended, except perhaps when accessing anonymous repositories or the
+like.
+
+* The distribution has been converted to use Automake. This shouldn't
+affect most users except to ease some portability concerns, but if you
+are building from the repository and encounter problems with the
+makefiles, you might try running ./noautomake.sh after a fresh update
+-AC.
+
+Changes from 1.10 to 1.11:
+
+* The "cvs update" command has a new -C option to get clean copies from
+the repository, abandoning any local changes.
+
+* The new "cvs version" command gives a short version message. If
+the repository is remote, both the client and server versions are
+reported.
+
+* "cvs admin -t" now works correctly in client/server mode.
+
+* The "cvs history" command output format has changed -- the date
+now includes the year and is given is ISO 8601 format (yyyy-mm-dd).
+Also, the new LogHistory option in CVSROOT/config can be used to
+control what information gets recorded in the log file and code has
+been added to record file removals.
+
+* The buggy PreservePermissions code has been disabled.
+
+* Anonymous read-only access can now be done without requiring a
+password. On the server side, simply give that user (presumably
+`anonymous') an empty password in the CVSROOT/passwd file, and then
+any received password will authenticate successfully.
+
+* There is a new access method :fork: which is similar to :local:
+except that it is implemented via the CVS remote protocol, and thus
+has a somewhat different set of quirks and bugs.
+
+* The -d command line option no longer updates the CVS/Root file. For
+one thing, the CVS 1.9/1.10 behavior never had updated CVS/Root in
+subdirectories, and for another, it didn't seem that popular in
+general. So this change restores the CVS 1.8 behavior (which is also
+the CVS 1.9/1.10 behavior if the environment variable
+CVS_IGNORE_REMOTE_ROOT is set; with this change,
+CVS_IGNORE_REMOTE_ROOT no longer has any effect).
+
+* It is now possible for a single CVS command to recurse into several
+CVS roots. This includes roots which are located on several servers,
+or which are both remote and local. CVS will make connections to as
+many servers as necessary.
+
+* It is now possible to put the CVS lock files in a directory
+set by the new LockDir option in CVSROOT/config. The default
+continues to be to put the lock files in the repository itself.
+
+Changes from 1.9 to 1.10:
+
+* A bug was discovered in the -t/-f wrapper support that can cause
+serious data loss. Because of this (and also the fact that it doesn't
+work at all in client/server mode), the -t/-f wrapper code has been
+disabled until it can be fixed.
+
+* There is a new feature, enabled by TopLevelAdmin in CVSROOT/config,
+which tells CVS to modify the behavior of the "checkout" command. The
+command now creates a CVS directory at the top level of the new
+working directory, in addition to CVS directories created within
+checked-out directories. See the Cederqvist for details.
+
+* There is an optional set of features, enabled by PreservePermissions
+in CVSROOT/config, which allow CVS to store unix-specific file
+information such as permissions, file ownership, and links. See the
+Cederqvist for details.
+
+* One can now authenticate and encrypt using the GSSAPI network
+security interface. For details see the Cederqvist's description of
+specifying :gserver: in CVSROOT, and the -a global option.
+
+* All access to RCS files is now implemented internally rather than by
+calling RCS programs. The main user-visible consequence of this is
+that there is no need to worry about making sure that CVS finds the
+correct version of RCS. The -b global option and the RCSBIN setting
+in CVSROOT/config are still accepted but don't do anything. The
+$RCSBIN internal variable in administrative files is no longer
+accepted.
+
+* There is a new syntax, "cvs admin -orev1::rev2", which collapses the
+revisions between rev1 and rev2 without deleting rev1 or rev2
+themselves.
+
+* There is a new administrative file CVSROOT/config which allows one
+to specify miscellaneous aspects of CVS configuration. Currently
+supported here:
+
+ - SystemAuth, allows you to prevent pserver from checking for system
+ usernames/passwords.
+
+For more information see the "config" section of cvs.texinfo.
+
+* When setting up the pserver server, one now must specify the
+allowable CVSROOT directories in inetd.conf. See the Password
+authentication server section of cvs.texinfo for details. Note that
+this implies that everyone who is running a pserver server must edit
+inetd.conf when upgrading their CVS.
+
+* The client no longer needs an external patch program (assuming both
+the client and the server have been updated to the new version).
+
+* "cvs admin [options]" will now recurse. In previous versions of
+CVS, it was an error and one needed to specify "cvs admin [options] ."
+to recurse. This change brings admin in line with the other CVS
+commands.
+
+* New "logout" command to remove the password for a remote cvs
+repository from the cvspass file.
+
+* Read-only repository access is implemented for the
+password-authenticated server (other access methods are just governed
+by Unix file permissions, since they require login access to the
+repository machine anyway). See the "Repository" section of
+cvs.texinfo for details, including a discussion of security issues.
+Note that the requirement that read-only users be able to create locks
+and write the history file still applies.
+
+* There is a new administrative file verifymsg which is like editinfo
+but merely validates the message, rather than also getting it from the
+user. It therefore works with client/server CVS or if one uses the -m
+or -F options to commit. See the verifymsg section of cvs.texinfo for
+details.
+
+* The %s format formerly accepted in loginfo has been extended to
+formats such as %{sVv}, so that loginfo scripts have access to the
+version numbers being changed. See the Loginfo section of cvs.texinfo
+for details.
+
+* The postscript documentation (doc/cvs.ps) shipped with CVS is now
+formatted for US letter size instead of A4. This is not because we
+consider this size "better" than A4, but because we believe that the
+US letter version will print better on A4 paper than the other way
+around.
+
+* The "cvs export" command is now logged in the history file and there
+is a "cvs history -x E" command to select history file entries
+produced by export.
+
+* CVS no longer uses the CVS_PASSWORD environment variable. Storing
+passwords in cleartext in an environment variable is a security risk,
+especially since (on BSD variants) any user on the system can display
+any process's environment using 'ps'. Users should use the 'cvs
+login' command instead.
+
+
+Changes from 1.8 to 1.9:
+
+* Windows NT client should now work on Windows 95 as well.
+
+* New option "--help-synonyms" prints a list of all recognized command
+synonyms.
+
+* The "log" command is now implemented internally rather than via the
+RCS "rlog" program. The main user-visible consequence is that
+symbolic branch names now work (for example "cvs log -rbranch1").
+Also, the date formats accepted by -d have changed. They previously
+had been a bewildering variety of poorly-documented date formats. Now
+they are the same as the date formats accepted by the -D options to
+the other CVS commands, which is also a (different) bewildering
+variety of poorly-documented date formats, but at least we are
+consistently bewildering :-).
+
+* Encryption is now supported over a Kerberos client/server
+connection. The new "-x" global option requests it. You must
+configure with the --enable-encryption option in order to enable
+encryption.
+
+* The format of the CVS commit message has changed slightly when
+committing changes on a branch. The tag on which the commit is
+ocurring is now reported correctly in all cases.
+
+* New flag -k in wrappers allows you to specify the keyword expansion
+mode for added files based on their name. For example, you can
+specify that files whose name matches *.exe are binary by default.
+See the Wrappers section of cvs.texinfo for more details.
+
+* Remote CVS with the "-z" option now uses the zlib library (included
+with CVS) to compress all communication between the client and the
+server, rather than invoking gzip on each file separately. This means
+that compression is better and there is no need for an external gzip
+program (except to interoperate with older version of CVS).
+
+* The "cvs rlog" command is deprecated and running it will print a
+warning; use the synonymous "cvs log" command instead. It is
+confusing for rlog to mean the same as log because some other CVS
+commands are in pairs consisting of a plain command which operates on
+a working directory and an "r" command which does not (diff/rdiff;
+tag/rtag).
+
+* "cvs diff" has a bunch of new options, mostly long options. Most of
+these work only if rcsdiff and diff support them, and are named the
+same as the corresponding options to diff.
+
+* The -q and -Q command options to "cvs diff" were removed (use the
+global options instead). This brings "cvs diff" into line with the
+rest of the CVS commands.
+
+* The "annotate" command can now be used to annotate a revision other
+than the head revision on the trunk (see the -r, -D, and -f options in
+the annotate node of cvs.texinfo for details).
+
+* The "tag" command has a new option "-c" which checks that all files
+ are not locally modified before tagging.
+
+* The -d command line option now overrides the cvsroot setting stored
+in the CVS/Root file in each working directory, and specifying -d will
+cause CVS/Root to be updated.
+
+* Local (non-client/server) CVS now runs on Windows NT. See
+windows-NT/README for details.
+
+* The CVSROOT variable specification has changed to support more
+access methods. In addition to "pserver," "server" (internal rsh
+client), "ext" (external rsh client), "kserver" (kerberos), and
+"local" (local filesystem access) can now be specified. For more
+details on each method, see cvs.texinfo (there is an index entry for
+:local: and each of the other access methods).
+
+* The "login" command no longer prompts the user for username and
+hostname, since one will have to provide that information via the `-d'
+flag or by setting CVSROOT.
+
+Changes from 1.7 to 1.8:
+
+* New "cvs annotate" command to display the last modification for each
+line of a file, with the revision number, user checking in the
+modification, and date of the modification. For more information see
+the `annotate' node in cvs.texinfo.
+
+* The cvsinit shell script has been replaced by a cvs init command.
+The cvs init command creates some example administrative files which
+are similar to the files found in the examples directory (and copied
+by cvsinit) in previous releases.
+
+* Added the patterns *.olb *.exe _$* *$ to default ignore list.
+
+* There is now a $USER internal variable for *info files.
+
+* There is no longer a separate `mkmodules' program; the functionality
+is now built into `cvs'. If upgrading an old repository, it is OK to
+leave in the lines in the modules file which run mkmodules (the
+mkmodules actions will get done twice, but that is harmless); you will
+probably want to remove them once you are no longer using the old CVS.
+
+* One can now specify user variables in *info files via the
+${=varname} syntax; there is a -s global option to set them. See the
+Variables node in cvs.texinfo for details.
+
+Changes from 1.6 to 1.7:
+
+* The default ignore list has changed slightly: *.obj has been added
+and CVS* has been changed to CVS CVS.adm.
+
+* CVS now supports password authentication when accessing remote
+repositories; this is useful for sites that can't use rsh (because of
+a firewall, for example), and also don't have kerberos. See node
+"Password authenticated" (in "Remote repositories", in
+doc/cvs.texinfo) for more details. Note: This feature requires both
+the client and server to be upgraded.
+
+* Using the -kb option to specify binary files now works--most cases
+did not work before. See the "Binary files" section of
+doc/cvs.texinfo for details.
+
+* New developer communication features. See the "Watches" section of
+doc/cvs.texinfo for details.
+
+* RCS keyword "Name" supported for "cvs update -r <tag>" and "cvs
+checkout -r <tag>".
+
+* If there is a group whose name matches a compiled in value which
+defaults to "cvsadmin", only members of that group can use "cvs
+admin". This replaces the CVS_NOADMIN option.
+
+* CVS now sets the modes of files in the repository based on the
+CVSUMASK environment variable or a compiled in value defaulting to
+002. This way other developers will be able to access the files in
+the repository regardless of the umask of the developer creating them.
+
+* The command names in .cvsrc now match the official name of the
+command, not the one (possibly an alias) by which it was invoked. If
+you had previously relied on "cvs di" and "cvs diff" using different
+options, instead use a shell function or alias (for example "alias
+cvsdi='cvs diff -u'"). You also can specify global CVS options (like
+"-z") using the command name "cvs".
+
+Changes from 1.5 to 1.6:
+
+* Del updated the man page to include all of the new features
+of CVS 1.6.
+
+* "cvs tag" now supports a "-r | -D" option for tagging an already
+tagged revision / specific revision of a file.
+
+* There is a "taginfo" file in CVSROOT that supports filtering and
+recording of tag operations.
+
+* Long options support added, including --help and --version options.
+
+* "cvs release" no longer cares whether or not the directory being
+released has an entry in the `modules' file.
+
+* The modules file now takes a -e option which is used instead of -o
+for "cvs export". If your modules file has a -o option which you want
+to be used for "cvs export", change it to specify -e as well as -o.
+
+* "cvs export" now takes a -k option to set RCS keyword expansion.
+This way you can export binary files. If you want the old behavior,
+you need to specify -kv.
+
+* "cvs update", "cvs rdiff", "cvs checkout", "cvs import", "cvs
+release", "cvs rtag", and "cvs tag" used to take -q and -Q options
+after the command name (e.g. "cvs update -q"). This was confusing
+because other commands, such as "cvs ci", did not. So the options
+after the command name have been removed and you must now specify, for
+example, "cvs -q update", which has been supported since CVS 1.3.
+
+* New "wrappers" feature. This allows you to set a hook which
+transforms files on their way in and out of cvs (apparently on the
+NeXT there is some particular usefulness in tarring things up in the
+repository). It also allows you to declare files as merge-by-copy
+which means that instead of trying to merge the file, CVS will merely
+copy the new version. There is a CVSROOT/cvswrappers file and an
+optionsl ~/.cvswrappers file to support this feature.
+
+* You can set CVSROOT to user@host:dir, not just host:dir, if your
+username on the server host is different than on the client host.
+
+* VISUAL is accepted as well as EDITOR.
+
+* $CVSROOT is expanded in *info files.
+
+Changes from 1.4A2 to 1.5:
+
+* Remote implementation. This is very helpful when collaborating on a
+project with someone across a wide-area network. This release can
+also be used locally, like other CVS versions, if you have no need for
+remote access.
+
+Here are some of the features of the remote implementation:
+- It uses reliable transport protocols (TCP/IP) for remote repository
+ access, not NFS. NFS is unusable over long distances (and sometimes
+ over short distances)
+- It transfers only those files that have changed in the repository or
+ the working directory. To save transmission time, it will transfer
+ patches when appropriate, and can compress data for transmission.
+- The server never holds CVS locks while waiting for a reply from the client;
+ this makes the system robust when used over flaky networks.
+
+The remote features are documented in doc/cvsclient.texi in the CVS
+distribution, but the main doc file, cvs.texinfo, has not yet been
+updated to include the remote features.
+
+* Death support. See src/README-rm-add for more information on this.
+
+* Many speedups, especially from jtc@cygnus.com.
+
+* CVS 1.2 compatibility code has been removed as a speedup. If you
+have working directories checked out by CVS 1.2, CVS 1.3 or 1.4A2 will
+try to convert them, but CVS 1.5 and later will not (if the working
+directory is up to date and contains no extraneous files, you can just
+remove it, and then check out a new working directory). Likewise if
+your repository contains a CVSROOT.adm directory instead of a CVSROOT
+directory, you need to rename it.
+
+Fri Oct 21 20:58:54 1994 Brian Berliner <berliner@sun.com>
+
+ * Changes between CVS 1.3 and CVS 1.4 Alpha-2
+
+ * A new program, "cvsbug", is provided to let you send bug reports
+ directly to the CVS maintainers. Please use it instead of sending
+ mail to the info-cvs mailing list. If your build fails, you may
+ have to invoke "cvsbug" directly from the "src" directory as
+ "src/cvsbug.sh".
+
+ * A new User's Guide and Tutorial, written by Per Cederqvist
+ <ceder@signum.se> of Signum Support. See the "doc" directory. A
+ PostScript version is included as "doc/cvs.ps".
+
+ * The Frequesntly Asked Questions file, FAQ, has been added to the
+ release. Unfortunately, its contents are likely out-of-date.
+
+ * The "cvsinit" shell script is now installed in the $prefix/bin
+ directory like the other programs. You can now create new
+ CVS repositories with great ease.
+
+ * Index: lines are now printed on output from 'diff' and 'rdiff',
+ in order to facilitate application of patches to multiple subdirs.
+
+ * Support for a ~/.cvsrc file, which allows you to specify options
+ that are always supposed to be given to a specific command. This
+ feature shows the non-orthogonality of the option set, since while
+ there may be an option to turn something on, the option to turn
+ that same thing off may not exist.
+
+ * You can now list subdirectories that you wish to ignore in a
+ modules listing, such as:
+
+ gcc -a gnu/gcc, !gnu/gcc/testsuites
+
+ which will check out everything underneath gnu/gcc, except
+ everything underneath gnu/gcc/testsuites.
+
+ * It is now much harder to accidentally overwrite an existing tag
+ name, since attempting to move a tag name will result in a error,
+ unless the -F (force) flag is given to the tag subcommands.
+
+ * Better error checking on matching of the repository used to
+ check code out from against the repository the current cvs
+ commnands would use. (Thanks to Mark Baushke <mdb@cisco.com>)
+
+ * Better support for sites with multiple CVSROOT repositories has
+ been contributed. The file "CVS/Root" in your working directory
+ is created to hold the full path to the CVS repository and a
+ simple check is made against your current CVSROOT setting.
+
+ * You can now specify an RCS keyword substitution value when you
+ import files into the repository.
+
+ * Uses a much newer version of Autoconf, and conforms to the GNU
+ coding standards much more closely. No, it still doesn't have
+ long option names.
+
+ * Code cleanup. Many passes through gcc -Wall helped to identify
+ a number of questionable constructs. Most arbitrary length limits
+ were removed.
+
+ * Profiling to determine bottlenecks helped to identify the best
+ places to spend time speeding up the code, which was then done. A
+ number of performance enhancements in filename matching have sped
+ up checkouts.
+
+ * Many more contributions have been added to the "contrib"
+ directory. See the README file in that directory for more
+ information.
+
+ * "cvs commit" will try harder to not change the file's
+ modification time after the commit. If the file does not change
+ as a result of the commit operation, CVS will preserve the
+ original modification time, thus speeding up future make-type
+ builds.
+
+ * "cvs commit" now includes any removed files in the (optional)
+ pre-commit checking program that may be invoked. Previously, only
+ added and modified files were included.
+
+ * It is now possible to commit a file directly onto the trunk at a
+ specific revision level by doing "cvs commit -r3.0 file.c", where
+ "3.0" specifies the revision you wish to create. The file must be
+ up-to-date with the current head of the trunk for this to succeed.
+
+ * "cvs commit" will now function with a pre-commit program that
+ has arguments specified in the "commitinfo" file.
+
+ * The "mkmodules" program will now look within the
+ $CVSROOT/CVSROOT/checkoutlist" file for any additional files that
+ should be automatically checked out within CVSROOT; mkmodules also
+ tries harder to preserve any execute bits the files may have
+ originally had.
+
+ * "cvs diff" is much more accurate about its exit status now. It
+ now returns the maximum exit status of any invoked diff.
+
+ * The "-I !" option is now supported for the import and update
+ commands correctly. It will properly clear the ignore list now.
+
+ * Some problems with "cvs import" handling of .cvsignore have been
+ fixed; as well, some rampant recursion problems with import have
+ also been fixed.
+
+ * "cvs rdiff" (aka "cvs patch") now tries to set the modify time
+ of any temporary files it uses to match those specified for the
+ particular revision. This allows a more accurate patch image to
+ be created.
+
+ * "cvs status" has improved revision descriptions. "Working
+ revision" is used for the revision of the working file that you
+ edit directly; "Repository revision" is the revision of the file
+ with the $CVSROOT source repository. Also, the output is clearer
+ with regard to sticky and branch revisions.
+
+ * CVS no longer dumps core when given a mixture of directories and
+ files in sub-directories (as in "cvs ci file1 dir1/file2").
+ Instead, arguments are now clumped into their respective directory
+ and operated on in chunks, together.
+
+ * If the CVSEDITOR environment variable is set, that editor is
+ used for log messages instead of the EDITOR environment variable.
+ This makes it easy to substitute intelligent programs to make more
+ elaborate log messages. Contributed by Mark D Baushke
+ (mdb@cisco.com).
+
+ * Command argument changes:
+ cvs: The "-f" option has been added to ignore
+ the ~/.cvsrc file.
+ commit: Renamed the "-f logfile" option to the
+ "-F logfile" option. Added the "-f"
+ option to force a commit of the specified
+ files (this disables recursion).
+ history: Added "-t timezone" option to force any
+ date-specific output into the specified
+ timezone.
+ import: Added "-d" option to use the file's
+ modification time as the time of the
+ import. Added "-k sub" option to set the
+ default RCS keyword substitution mode for
+ newly-created files.
+ remove: Added "-f" option to force the file's
+ automatic removal if it still exists in
+ the working directory (use with caution).
+ rtag: Added "-F" option to move the tag if it
+ already exists -- new default is to NOT
+ move tags automatically.
+ tag: Added "-F" option to move the tag if it
+ already exists -- new default is to NOT
+ move tags automatically.
+
+Tue Apr 7 15:55:25 1992 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.3 Beta-3 and official CVS 1.3!
+
+ * A new shell script is provided, "./cvsinit", which can be run at
+ install time to help setup your $CVSROOT area. This can greatly
+ ease your entry into CVS usage.
+
+ * The INSTALL file has been updated to include the machines on
+ which CVS has compiled successfully. I think CVS 1.3 is finally
+ portable. Thanks to all the Beta testers!
+
+ * Support for the "editinfo" file was contributed. This file
+ (located in $CVSROOT/CVSROOT) can be used to specify a special
+ "editor" to run on a per-directory basis within the repository,
+ instead of the usual user's editor. As such, it can verify that
+ the log message entered by the user is of the appropriate form
+ (contains a bugid and test validation, for example).
+
+ * The manual pages cvs(1) and cvs(5) have been updated.
+
+ * The "mkmodules" command now informs you when your modules file
+ has duplicate entries.
+
+ * The "add" command now preserves any per-directory sticky tag when
+ you add a new directory to your checked-out sources.
+
+ * The "admin" command is now a fully recursive interface to the
+ "rcs" program which operates on your checked-out sources. It no
+ longer requires you to specify the full path to the RCS file.
+
+ * The per-file sticky tags can now be effectively removed with
+ "cvs update -A file", even if you had checked out the whole
+ directory with a per-directory sticky tag. This allows a great
+ deal of flexibility in managing the revisions that your checked-out
+ sources are based upon (both per-directory and per-file sticky
+ tags).
+
+ * The "cvs -n commit" command now works, to show which files are
+ out-of-date and will cause the real commit to fail, or which files
+ will fail any pre-commit checks. Also, the "cvs -n import ..."
+ command will now show you what it would've done without actually
+ doing it.
+
+ * Doing "cvs commit modules" to checkin the modules file will no
+ properly run the "mkmodules" program (assuming you have setup your
+ $CVSROOT/CVSROOT/modules file to do so).
+
+ * The -t option in the modules file (which specifies a program to
+ run when you do a "cvs rtag" operation on a module) now gets the
+ symbolic tag as the second argument when invoked.
+
+ * When the source repository is locked by another user, that user's
+ login name will be displayed as the holder of the lock.
+
+ * Doing "cvs checkout module/file.c" now works even if
+ module/file.c is in the Attic (has been removed from main-line
+ development).
+
+ * Doing "cvs commit */Makefile" now works as one would expect.
+ Rather than trying to commit everything recursively, it will now
+ commit just the files specified.
+
+ * The "cvs remove" command is now fully recursive. To schedule a
+ file for removal, all you have to do is "rm file" and "cvs rm".
+ With no arguments, "cvs rm" will schedule all files that have been
+ physically removed for removal from the source repository at the
+ next "cvs commit".
+
+ * The "cvs tag" command now prints "T file" for each file that was
+ tagged by this invocation and "D file" for each file that had the
+ tag removed (as with "cvs tag -d").
+
+ * The -a option has been added to "cvs rtag" to force it to clean
+ up any old, matching tags for files that have been removed (in the
+ Attic) that may not have been touched by this tag operation. This
+ can help keep a consistent view with your tag, even if you re-use
+ it frequently.
+
+Sat Feb 29 16:02:05 1992 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.3 Beta-2 and CVS 1.3 Beta-3
+
+ * Many portability fixes, thanks to all the Beta testers! With any
+ luck, this Beta release will compile correctly on most anything.
+ Hey, what are we without our dreams.
+
+ * CVS finally has support for doing isolated development on a
+ branch off the current (or previous!) revisions. This is also
+ extremely nice for generating patches for previously released
+ software while development is progressing on the next release.
+ Here's an example of creating a branch to fix a patch with the 2.0
+ version of the "foo" module, even though we are already well into
+ the 3.0 release. Do:
+
+ % cvs rtag -b -rFOO_2_0 FOO_2_0_Patch foo
+ % cvs checkout -rFOO_2_0_Patch foo
+ % cd foo
+ [[ hack away ]]
+ % cvs commit
+
+ A physical branch will be created in the RCS file only when you
+ actually commit the change. As such, forking development at some
+ random point in time is extremely light-weight -- requiring just a
+ symbolic tag in each file until a commit is done. To fork
+ development at the currently checked out sources, do:
+
+ % cvs tag -b Personal_Hack
+ % cvs update -rPersonal_Hack
+ [[ hack away ]]
+ % cvs commit
+
+ Now, if you decide you want the changes made in the Personal_Hack
+ branch to be merged in with other changes made in the main-line
+ development, you could do:
+
+ % cvs commit # to make Personal_Hack complete
+ % cvs update -A # to update sources to main-line
+ % cvs update -jPersonal_Hack # to merge Personal_Hack
+
+ to update your checked-out sources, or:
+
+ % cvs checkout -jPersonal_Hack module
+
+ to checkout a fresh copy.
+
+ To support this notion of forked development, CVS reserves
+ all even-numbered branches for its own use. In addition, CVS
+ reserves the ".0" and ".1" branches. So, if you intend to do your
+ own branches by hand with RCS, you should use odd-numbered branches
+ starting with ".3", as in "1.1.3", "1.1.5", 1.2.9", ....
+
+ * The "cvs commit" command now supports a fully functional -r
+ option, allowing you to commit your changes to a specific numeric
+ revision or symbolic tag with full consistency checks. Numeric
+ tags are useful for bringing your sources all up to some revision
+ level:
+
+ % cvs commit -r2.0
+
+ For symbolic tags, you can only commit to a tag that references a
+ branch in the RCS file. One created by "cvs rtag -b" or from
+ "cvs tag -b" is appropriate (see below).
+
+ * Roland Pesch <pesch@cygnus.com> and K. Richard Pixley
+ <rich@cygnus.com> were kind enough to contribute two new manual
+ pages for CVS: cvs(1) and cvs(5). Most of the new CVS 1.3 features
+ are now documented, with the exception of the new branch support
+ added to commit/rtag/tag/checkout/update.
+
+ * The -j options of checkout/update have been added. The "cvs join"
+ command has been removed.
+
+ With one -j option, CVS will merge the changes made between the
+ resulting revision and the revision that it is based on (e.g., if
+ the tag refers to a branch, CVS will merge all changes made in
+ that branch into your working file).
+
+ With two -j options, CVS will merge in the changes between the two
+ respective revisions. This can be used to "remove" a certain delta
+ from your working file. E.g., If the file foo.c is based on
+ revision 1.6 and I want to remove the changes made between 1.3 and
+ 1.5, I might do:
+
+ % cvs update -j1.5 -j1.3 foo.c # note the order...
+
+ In addition, each -j option can contain on optional date
+ specification which, when used with branches, can limit the chosen
+ revision to one within a specific date. An optional date is
+ specified by adding a colon (:) to the tag, as in:
+
+ -jSymbolic_Tag:Date_Specifier
+
+ An example might be what "cvs import" tells you to do when you have
+ just imported sources that have conflicts with local changes:
+
+ % cvs checkout -jTAG:yesterday -jTAG module
+
+ which tells CVS to merge in the changes made to the branch
+ specified by TAG in the last 24 hours. If this is not what is
+ intended, substitute "yesterday" for whatever format of date that
+ is appropriate, like:
+
+ % cvs checkout -jTAG:'1 week ago' -jTAG module
+
+ * "cvs diff" now supports the special tags "BASE" and "HEAD". So,
+ the command:
+
+ % cvs diff -u -rBASE -rHEAD
+
+ will effectively show the changes made by others (in unidiff
+ format) that will be merged into your working sources with your
+ next "cvs update" command. "-rBASE" resolves to the revision that
+ your working file is based on. "-rHEAD" resolves to the current
+ head of the branch or trunk that you are working on.
+
+ * The -P option of "cvs checkout" now means to Prune empty
+ directories, as with "update". The default is to not remove empty
+ directories. However, if you do "checkout" with any -r options, -P
+ will be implied. I.e., checking out with a tag will cause empty
+ directories to be pruned automatically.
+
+ * The new file INSTALL describes how to install CVS, including
+ detailed descriptions of interfaces to "configure".
+
+ * The example loginfo file in examples/loginfo has been updated to
+ use the perl script included in contrib/log.pl. The nice thing
+ about this log program is that it records the revision numbers of
+ your change in the log message.
+
+ Example files for commitinfo and rcsinfo are now included in the
+ examples directory.
+
+ * All "#if defined(__STDC__) && __STDC__ == 1" lines have been
+ changed to be "#if __STDC__" to fix some problems with the former.
+
+ * The lib/regex.[ch] files have been updated to the 1.3 release of
+ the GNU regex package.
+
+ * The ndbm emulation routines included with CVS 1.3 Beta-2 in the
+ src/ndbm.[ch] files has been moved into the src/myndbm.[ch] files
+ to avoid any conflict with the system <ndbm.h> header file. If
+ you had a previous CVS 1.3 Beta release, you will want to "cvs
+ remove ndbm.[ch]" form your copy of CVS as well.
+
+ * "cvs add" and "cvs remove" are a bit more verbose, telling you
+ what to do to add/remove your file permanently.
+
+ * We no longer mess with /dev/tty in "commit" and "add".
+
+ * More things are quiet with the -Q option set.
+
+ * New src/config.h option: If CVS_BADROOT is set, CVS will not
+ allow people really logged in as "root" to commit changes.
+
+ * "cvs diff" exits with a status of 0 if there were no diffs, 1 if
+ there were diffs, and 2 if there were errors.
+
+ * "cvs -n diff" is now supported so that you can still run diffs
+ even while in the middle of committing files.
+
+ * Handling of the CVS/Entries file is now much more robust.
+
+ * The default file ignore list now includes "*.so".
+
+ * "cvs import" did not expand '@' in the log message correctly. It
+ does now. Also, import now uses the ignore file facility
+ correctly.
+
+ Import will now tell you whether there were conflicts that need to
+ be resolved, and how to resolve them.
+
+ * "cvs log" has been changed so that you can "log" things that are
+ not a part of the current release (in the Attic).
+
+ * If you don't change the editor message on commit, CVS now prompts
+ you with the choice:
+
+ !)reuse this message unchanged for remaining dirs
+
+ which allows you to tell CVS that you have no intention of changing
+ the log message for the remainder of the commit.
+
+ * It is no longer necessary to have CVSROOT set if you are using
+ the -H option to get Usage information on the commands.
+
+ * Command argument changes:
+ checkout: -P handling changed as described above.
+ New -j option (up to 2 can be specified)
+ for doing rcsmerge kind of things on
+ checkout.
+ commit: -r option now supports committing to a
+ numeric or symbolic tags, with some
+ restrictions. Full consistency checks will
+ be done.
+ Added "-f logfile" option, which tells
+ commit to glean the log message from the
+ specified file, rather than invoking the
+ editor.
+ rtag: Added -b option to create a branch tag,
+ useful for creating a patch for a previous
+ release, or for forking development.
+ tag: Added -b option to create a branch tag,
+ useful for creating a patch for a previous
+ release, or for forking development.
+ update: New -j option (up to 2 can be specified)
+ for doing rcsmerge kind of things on
+ update.
+
+Thu Jan 9 10:51:35 MST 1992 Jeff Polk (polk at BSDI.COM)
+
+ * Changes between CVS 1.3 Beta-1 and CVS 1.3 Beta-2
+
+ * Thanks to K. Richard Pixley at Cygnus we now have function
+ prototypes in all the files
+
+ * Some small changes to configure for portability. There have
+ been other portability problems submitted that have not been fixed
+ (Brian will be working on those). Additionally all __STDC__
+ tests have been modified to check __STDC__ against the constant 1
+ (this is what the Second edition of K&R says must be true).
+
+ * Lots of additional error checking for forked processes (run_exec)
+ (thanks again to K. Richard Pixley)
+
+ * Lots of miscellaneous bug fixes - including but certainly not
+ limited to:
+ various commit core dumps
+ various update core dumps
+ bogus results from status with numeric sticky tags
+ commitprog used freed memory
+ Entries file corruption caused by No_Difference
+ commit to revision broken (now works if branch exists)
+ ignore file processing broken for * and !
+ ignore processing didn't handle memory reasonably
+ miscellaneous bugs in the recursion processor
+ file descriptor leak in ParseInfo
+ CVSROOT.adm->CVSROOT rename bug
+ lots of lint fixes
+
+ * Reformatted all the code in src (with GNU indent) and then
+ went back and fixed prototypes, etc since indent gets confused. The
+ rationale is that it is better to do it sooner than later and now
+ everything is consistent and will hopefully stay that way.
+ The basic options to indent were: "-bad -bbb -bap -cdb -d0 -bl -bli0
+ -nce -pcs -cs -cli4 -di1 -nbc -psl -lp -i4 -ip4 -c41" and then
+ miscellaneous formatting fixes were applied. Note also that the
+ "-nfc1" or "-nfca" may be appropriate in files where comments have
+ been carefully formatted (e.g, modules.c).
+
+Sat Dec 14 20:35:22 1991 Brian Berliner (berliner at sun.com)
+
+ * Changes between CVS 1.2 and CVS 1.3 Beta are described here.
+
+ * Lots of portability work. CVS now uses the GNU "configure"
+ script to dynamically determine the features provided by your
+ system. It probably is not foolproof, but it is better than
+ nothing. Please let me know of any portability problems. Some
+ file names were changed to fit within 14-characters.
+
+ * CVS has a new RCS parser that is much more flexible and
+ extensible. It should read all known RCS ",v" format files.
+
+ * Most of the commands now are fully recursive, rather than just
+ operating on the current directory alone. This includes "commit",
+ which makes it real easy to do an "atomic" commit of all the
+ changes made to a CVS hierarchy of sources. Most of the commands
+ also correctly handle file names that are in directories other than
+ ".", including absolute path names. Commands now accept the "-R"
+ option to force recursion on (though it is always the default now)
+ and the "-l" option to force recursion off, doing just "." and not
+ any sub-directories.
+
+ * CVS supports many of the features provided with the RCS 5.x
+ distribution - including the new "-k" keyword expansion options. I
+ recommend using RCS 5.x (5.6 is the current official RCS version)
+ and GNU diff 1.15 (or later) distributions with CVS.
+
+ * Checking out files with symbolic tags/dates is now "sticky", in
+ that CVS remembers the tag/date used for each file (and directory)
+ and will use that tag/date automatically on the next "update" call.
+ This stickyness also holds for files checked out with the the new
+ RCS 5.x "-k" options.
+
+ * The "cvs diff" command now recognizes all of the rcsdiff 5.x
+ options. Unidiff format is available by installing the GNU
+ diff 1.15 distribution.
+
+ * The old "CVS.adm" directories created on checkout are now called
+ "CVS" directories, to look more like "RCS" and "SCCS". Old CVS.adm
+ directories are automagically converted to CVS directories. The
+ old "CVSROOT.adm" directory within the source repository is
+ automagically changed into a "CVSROOT" directory as well.
+
+ * Symbolic links in the source repository are fully supported ONLY
+ if you use RCS 5.6 or later and (of course) your system supports
+ symlinks.
+
+ * A history database has been contributed which maintains the
+ history of certain CVS operations, as well as providing a wide array
+ of querying options.
+
+ * The "cvs" program has a "-n" option which can be used with the
+ "update" command to show what would be updated without actually
+ doing the update, like: "cvs -n update". All usage statements
+ have been cleaned up and made more verbose.
+
+ * The module database parsing has been rewritten. The new format
+ is compatible with the old format, but with much more
+ functionality. It allows modules to be created that grab pieces or
+ whole directories from various different parts of your source
+ repository. Module-relative specifications are also correctly
+ recognized now, like "cvs checkout module/file.c".
+
+ * A configurable template can be specified such that on a "commit",
+ certain directories can supply a template that the user must fill
+ before completing the commit operation.
+
+ * A configurable pre-commit checking program can be specified which
+ will run to verify that a "commit" can happen. This feature can be
+ used to restrict certain users from changing certain pieces of the
+ source repository, or denying commits to the entire source
+ repository.
+
+ * The new "cvs export" command is much like "checkout", but
+ establishes defaults suitable for exporting code to others (expands
+ out keywords, forces the use of a symbolic tag, and does not create
+ "CVS" directories within the checked out sources.
+
+ * The new "cvs import" command replaces the deprecated "checkin"
+ shell script and is used to import sources into CVS control. It is
+ also much faster for the first-time import. Some algorithmic
+ improvements have also been made to reduce the number of
+ conflicting files on next-time imports.
+
+ * The new "cvs admin" command is basically an interface to the
+ "rcs" program. (Not yet implemented very well).
+
+ * Signal handling (on systems with BSD or POSIX signals) is much
+ improved. Interrupting CVS now works with a single interrupt!
+
+ * CVS now invokes RCS commands by direct fork/exec rather than
+ calling system(3). This improves performance by removing a call to
+ the shell to parse the arguments.
+
+ * Support for the .cvsignore file has been contributed. CVS will
+ now show "unknown" files as "? filename" as the result of an "update"
+ command. The .cvsignore file can be used to add files to the
+ current list of ignored files so that they won't show up as unknown.
+
+ * Command argument changes:
+ cvs: Added -l to turn off history logging.
+ Added -n to show what would be done without actually
+ doing anything.
+ Added -q/-Q for quiet and really quiet settings.
+ Added -t to show debugging trace.
+ add: Added -k to allow RCS 5.x -k options to be specified.
+ admin: New command; an interface to rcs(1).
+ checkout: Added -A to reset sticky tags/date/options.
+ Added -N to not shorten module paths.
+ Added -R option to force recursion.
+ Changed -p (prune empty directories) to -P option.
+ Changed -f option; forcing tags match is now default.
+ Added -p option to checkout module to standard output.
+ Added -s option to cat the modules db with status.
+ Added -d option to checkout in the specified directory.
+ Added -k option to use RCS 5.x -k support.
+ commit: Removed -a option; use -l instead.
+ Removed -f option.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ If no files specified, commit is recursive.
+ diff: Now recognizes all RCS 5.x rcsdiff options.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ history: New command; displays info about CVS usage.
+ import: Replaces "checkin" shell script; imports sources
+ under CVS control. Ignores files on the ignore
+ list (see -I option or .cvsignore description above).
+ export: New command; like "checkout", but w/special options
+ turned on by default to facilitate exporting sources.
+ join: Added -B option to join from base of the branch;
+ join now defaults to only joining with the top two
+ revisions on the branch.
+ Added -k option for RCS 5.x -k support.
+ log: Supports all RCS 5.x options.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ patch: Changed -f option; forcing tags match is now default.
+ Added -c option to force context-style diffs.
+ Added -u option to support unidiff-style diffs.
+ Added -V option to support RCS specific-version
+ keyword expansion formats.
+ Added -R option to force recursion.
+ remove: No option changes. It's a bit more verbose.
+ rtag: Equivalent to the old "cvs tag" command.
+ No option changes. It's a lot faster for re-tag.
+ status: New output formats with more information.
+ Added -l option to disable recursion.
+ Added -R option to force recursion.
+ Added -v option to show symbolic tags for files.
+ tag: Functionality changed to tag checked out files
+ rather than modules; use "rtag" command to get the
+ old "cvs tag" behaviour.
+ update: Added -A to reset sticky tags/date/options.
+ Changed -p (prune empty directories) to -P option.
+ Changed -f option; forcing tags match is now default.
+ Added -p option to checkout module to standard output.
+ Added -I option to add files to the ignore list.
+ Added -R option to force recursion.
+
+ Major Contributors:
+
+ * Jeff Polk <polk@bsdi.com> rewrote most of the grody code of CVS
+ 1.2. He made just about everything dynamic (by using malloc),
+ added a generic hashed list manager, re-wrote the modules database
+ parsing in a compatible - but extended way, generalized directory
+ hierarchy recursion for virtually all the commands (including
+ commit!), generalized the loginfo file to be used for pre-commit
+ checks and commit templates, wrote a new and flexible RCS parser,
+ fixed an uncountable number of bugs, and helped in the design of
+ future CVS features. If there's anything gross left in CVS, it's
+ probably my fault!
+
+ * David G. Grubbs <dgg@odi.com> contributed the CVS "history" and
+ "release" commands. As well as the ever-so-useful "-n" option of
+ CVS which tells CVS to show what it would do, without actually
+ doing it. He also contributed support for the .cvsignore file.
+
+ * Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
+ contributed the code in lib/sighandle.c. I added support for
+ POSIX, BSD, and non-POSIX/non-BSD systems.
+
+ * Free Software Foundation contributed the "configure" script and
+ other compatibility support in the "lib" directory, which will help
+ make CVS much more portable.
+
+ * Many others have contributed bug reports and enhancement requests.
+ Some have even submitted actual code which I have not had time yet
+ to integrate into CVS. Maybe for the next release.
+
+ * Thanks to you all!
+
+Wed Feb 6 10:10:58 1991 Brian Berliner (berliner at sun.com)
+
+ * Changes from CVS 1.0 Patchlevel 1 to CVS 1.0 Patchlevel 2; also
+ known as "Changes from CVS 1.1 to CVS 1.2".
+
+ * Major new support with this release is the ability to use the
+ recently-posted RCS 5.5 distribution with CVS 1.2. See below for
+ other assorted bug-fixes that have been thrown in.
+
+ * ChangeLog (new): Added Emacs-style change-log file to CVS 1.2
+ release. Chronological description of changes between release.
+
+ * README: Small fixes to installation instructions. My email
+ address is now "berliner@sun.com".
+
+ * src/Makefile: Removed "rcstime.h". Removed "depend" rule.
+
+ * src/partime.c: Updated to RCS 5.5 version with hooks for CVS.
+ * src/maketime.c: Updated to RCS 5.5 version with hooks for CVS.
+ * src/rcstime.h: Removed from the CVS 1.2 distribution.
+ Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
+
+ * src/checkin.csh: Support for RCS 5.5 parsing.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/collect_sets.c (Collect_Sets): Be quieter if "-f" option is
+ specified. When checking out files on-top-of other files that CVS
+ doesn't know about, run a diff in the hopes that they are really
+ the same file before aborting.
+
+ * src/commit.c (branch_number): Fix for RCS 5.5 parsing.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/commit.c (do_editor): Bug fix - fprintf missing argument
+ which sometimes caused core dumps.
+
+ * src/modules.c (process_module): Properly NULL-terminate
+ update_dir[] in all cases.
+
+ * src/no_difference.c (No_Difference): The wrong RCS revision was
+ being registered in certain (strange) cases.
+
+ * src/patch.c (get_rcsdate): New algorithm. No need to call
+ maketime() any longer.
+ Thanks to Paul Eggert <eggert@twinsun.com> for this change.
+
+ * src/patchlevel.h: Increased patch level to "2".
+
+ * src/subr.c (isdir, islink): Changed to compare stat mode bits
+ correctly.
+
+ * src/tag.c (tag_file): Added support for following symbolic links
+ that are in the master source repository when tagging. Made tag
+ somewhat quieter in certain cases.
+
+ * src/update.c (update_process_lists): Unlink the user's file if it
+ was put on the Wlist, meaning that the user's file is not modified
+ and its RCS file has been removed by someone else.
+
+ * src/update.c (update): Support for "cvs update dir" to correctly
+ just update the argument directory "dir".
+
+ * src/cvs.h: Fixes for RCS 5.5 parsing.
+ * src/version_number.c (Version_Number): Fixes for parsing RCS 5.5
+ and older RCS-format files.
+ Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
+
+ * src/version_number.c (Version_Number): Bug fixes for "-f" option.
+ Bug fixes for parsing with certain branch numbers. RCS
+ revision/symbol parsing is much more solid now.
+
+Wed Feb 14 10:01:33 1990 Brian Berliner (berliner at sun.com)
+
+ * Changes from CVS 1.0 Patchlevel 0 to CVS 1.0 Patchlevel 1; also
+ known as "Changes from CVS 1.0 to CVS 1.1".
+
+ * src/patch.c (get_rcsdate): Portability fix. Replaced call to
+ timelocal() with call to maketime().
+
+Mon Nov 19 23:15:11 1990 Brian Berliner (berliner at prisma.com)
+
+ * Sent CVS 1.0 release to comp.sources.unix moderator and FSF.
+
+ * Special thanks to Dick Grune <dick@cs.vu.nl> for his work on the
+ 1986 version of CVS and making it available to the world. Dick's
+ version is available on uunet.uu.net in the
+ comp.sources.unix/volume6/cvs directory.
diff --git a/PROJECTS b/PROJECTS
new file mode 100644
index 0000000..b46eb2a
--- /dev/null
+++ b/PROJECTS
@@ -0,0 +1,53 @@
+This is a list of projects for CVS. In general, unlike the things in
+the TODO file, these need more analysis to determine if and how
+worthwhile each task is.
+
+I haven't gone through TODO, but it's likely that it has entries that
+are actually more appropriate for this list.
+
+0. Improved Efficency
+
+* CVS uses a single doubly linked list/hash table data structure for
+ all of its lists. Since the back links are only used for deleting
+ list nodes it might be beneficial to use singly linked lists or a
+ tree structure. Most likely, a single list implementation will not
+ be appropriate for all uses.
+
+ One easy change would be to remove the "type" field out of the list
+ and node structures. I have found it to be of very little use when
+ debugging, and each instance eats up a word of memory. This can add
+ up and be a problem on memory-starved machines.
+
+ Profiles have shown that on fast machines like the Alpha, fsortcmp()
+ is one of the hot spots.
+
+* Dynamically allocated character strings are created, copied, and
+ destroyed throughout CVS. The overhead of malloc()/strcpy()/free()
+ needs to be measured. If significant, it could be minimized by using a
+ reference counted string "class".
+
+* File modification time is stored as a character string. It might be
+ worthwile to use a time_t internally if the time to convert a time_t
+ (from struct stat) to a string is greater that the time to convert a
+ ctime style string (from the entries file) to a time_t. time_t is
+ an machine-dependant type (although it's pretty standard on UN*X
+ systems), so we would have to have different conversion routines.
+ Profiles show that both operations are called about the same number
+ of times.
+
+* stat() is one of the largest performance bottlenecks on systems
+ without the 4.4BSD filesystem. By spliting information out of
+ the filesystem (perhaps the "rename database") we should be
+ able to improve performance.
+
+* Parsing RCS files is very expensive. This might be unnecessary if
+ RCS files are only used as containers for revisions, and tag,
+ revision, and date information was available in easy to read
+ (and modify) indexes. This becomes very apparent with files
+ with several hundred revisions.
+
+1. Improved testsuite/sanity check script
+
+* Need to use a code coverage tool to determine how much the sanity
+ script tests, and fill in the holes.
+
diff --git a/README b/README
new file mode 100644
index 0000000..a04e680
--- /dev/null
+++ b/README
@@ -0,0 +1,131 @@
+ CVS Kit
+
+ Copyright (C) 1986-2005 Free Software Foundation, Inc.
+
+ Portions Copyright (C) 1998-2005 Derek Price,
+ & Ximbiot <http://ximbiot.com>.
+ Portions Copyright (C) 1993-1994 Brian Berliner.
+ Portions Copyright (C) 1992 Brian Berliner and Jeff Polk.
+ Portions Copyright (C) 1989-1992 Brian Berliner.
+ All Rights Reserved
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+-------------------------------------------------------------------------------
+
+Welcome to CVS!
+
+If you have problems or think you have found a bug in CVS, see the
+section BUGS in the CVS manual (also known as Version Management with
+CVS by Per Cederqvist et al, or cvs.texinfo--see below for details).
+
+If you are thinking of submitting changes to CVS, see the
+file HACKING.
+
+Please consult the INSTALL-CVS file for information on tested
+configurations. If you have a comment about an already tested
+configuration, or have tried CVS on a new configuration, please let us
+know as described in INSTALL-CVS. Free software only works if we all help
+out.
+
+Finally, we cannot guarantee that this release will not completely wipe out
+all of your work from your system. We do some simple testing before each
+release, but you are completely on your own. We recommend testing this
+release on a source repository that is not critical to your work. THIS
+SOFTWARE IS SUPPLIED COMPLETELY "AS IS". NO WARRANTY....
+
+Thanks for your support!
+
+ -The CVS Team
+
+-------------------------------------------------------------------------------
+
+What Is CVS?
+
+CVS is a version control system, which allows you to keep old versions
+of files (usually source code), keep a log of who, when, and why
+changes occurred, etc., like RCS or SCCS. It handles multiple
+developers, multiple directories, triggers to enable/log/control
+various operations, and can work over a wide area network. The
+following tasks are not included; they can be done in conjunction with
+CVS but will tend to require some script-writing and software other
+than CVS: bug-tracking, build management (that is, make and make-like
+tools), and automated testing.
+
+And a whole lot more. See the manual for more information.
+
+-------------------------------------------------------------------------------
+
+Notes to people upgrading from a previous release of CVS:
+
+See the NEWS file for a description of features new in this version.
+
+See the Compatibility section of the manual for information on
+compatibility between CVS versions. The quick summary is that as long
+as you not using the optional watch features, there are no
+compatibility problems with CVS 1.5 or later.
+
+-------------------------------------------------------------------------------
+
+Installation:
+
+Please read the INSTALL-CVS file for installation instructions. The brief
+summary is:
+
+ $ ./configure
+ $ make
+ (run the regression tests, if desired, via `make check')
+ $ make install
+ (create a repository if you don't already have one)
+
+The documentation is in the doc subdirectory. cvs.texinfo is the main
+manual; cvs.info* and cvs.ps are the info and postscript versions,
+respectively, generated from cvs.texinfo. The postscript version is
+for US letter size paper; we do this not because we consider this size
+"better" than A4, but because we believe that the US letter version
+will print better on A4 paper than the other way around. If you want a
+version formatted for A4, add the line @afourpaper near the start of
+cvs.texinfo and re-generate cvs.ps using TeX.
+
+-------------------------------------------------------------------------------
+
+* How do I get up-to-date information and information about other
+versions of CVS?
+
+See also
+ http://cvs.nongnu.org
+ http://www.cvsnt.org
+
+Anyone can add themselves to the following mailing lists:
+
+ bug-cvs: This is the list which users are requested to send bug reports
+ to. General CVS development and design discussions also tend to take
+ place on this list.
+ info-cvs: This list is intended for user questions, including general
+ help requests.
+ cvs-announce: CVS release announcements and other major
+ announcements about the project are sent to this list.
+ cvs-announce-binaries: Announcements are made to this list
+ when binaries for various platforms are built and initially
+ posted for download.
+
+To subscribe to any of these lists, send mail to <list>-request@nongnu.org
+or visit http://savannah.nongnu.org/mail/?group=cvs and follow the instructions
+for the list you wish to subscribe to.
+
+The newsgroup for CVS (and other configuration management systems) is
+comp.software.config-mgmt. The gnu.cvs.help newsgroup is a 2-way mirror
+of the info-cvs@nongnu.org mailing list and gnu.cvs.bug is similarly a 2-way
+mirror of bug-cvs@nongnu.org.
+
+-------------------------------------------------------------------------------
+
+Credits: See the AUTHORS file.
diff --git a/README.VMS b/README.VMS
new file mode 100644
index 0000000..b3f242f
--- /dev/null
+++ b/README.VMS
@@ -0,0 +1,155 @@
+ CVS port to VMS
+
+DISCLAIMER: This port must be considered experimental. Although
+previous versions have been in use at one large site since about
+October, 1995, and the port is believed to be quite usable, various
+VMS-specific quirks are known and the port cannot be considered as
+mature as the ports to, say, Windows NT or unix. As always, future
+progress of this port will depend on volunteer and customer interest.
+
+This port is of the CVS client only. Or in other words, the port
+implements the full set of CVS commands, but cannot access
+repositories located on the local machine. The repository must live
+on another machine (a Unix box) which runs a complete port of CVS.
+
+Most (all?) work to date has been done on OpenVMS/AXP 6.2. Other VMS
+variants might work too.
+
+Provided that both your client and your server are recent (for
+example, CVS 1.9.27 or later), you shouldn't need GNU patch or any
+other executables other than CVS.EXE.
+
+Please send bug reports to bug-cvs@nongnu.org.
+
+As of CVS 1.5.something, this port passed most of the tests in
+[.src]sanity.sh. I say "most" because some tests to not apply to the
+CVS client. The tests were run by hand because the VMS POSIX shell
+was incapable of running the script. The tests that sanity.sh
+provides are not conclusive but at least provides some assurance that
+the client is usable.
+
+To compile, you will need DEC C (CC), DEC UCX, and of course DCL
+installed on your machine. Just type "@build" in the top level
+directory. This will build the sources in each subdirectory, and link
+the executable [.src]cvs.exe
+
+Copy the executable to an appropriate directory, and define the symbol "CVS"
+in a .COM file which everyone running CVS will need to run. Here's an example
+of what needs to be done.
+
+$ CVS :== $YOUR_DEVICE:[YOUR.DIRECTORY.CVS]CVS.EXE
+
+Accessing a remote repository can happen in several ways.
+
+1. pserver
+2. rsh - privileged (default)
+3. rsh - unprivileged (on VMS side)
+
+Here's how to do each of the above:
+
+-------------------------------------------------------------------------------
+1. pserver. This is the preferred way. It works just as it is
+documented in the CVS manual (see the README file in the CVS
+distribution for more information on the manual).
+
+-------------------------------------------------------------------------------
+2. Using CVS internal rsh support (privileged)
+
+VMS's RSH is unusable for CVS's purposes (that is, the one in UCX.
+Don't know about Multinet). However, there is code within CVS to
+emulate RSH for purposes of contacting a CVS server "in the usual way"
+via rshd. Unfortunately, this requires the VMS CVS client to be
+installed with OPER privilege, by your system administrator.
+
+RSH uses privileged ports and trusted software/hosts to determine
+which user on the client side is trying to connect. Part of this
+security is due to the fact that on VMS or UNIX, a non privileged
+process is not permitted to bind a socket to a privileged port.
+
+If rshd receives a connection on a non-privileged port, the connection is
+immediately aborted. Only connections arriving from a privileged port will
+be authenticated and served. The CVS client will therefore need privileges
+under VMS to produce such a connection.
+
+*** Please note that no careful examination has been done of the security
+ implications of installing CVS with the OPER privilege. If some hole
+ exists, then by doing so, you will enable users who are already on
+ your system to gain unauthorized privileges ***
+
+-------------------------------------------------------------------------------
+3. Using CVS internal rsh support (non-privileged)
+
+There is a workaround, but this is one case where I think the cure is worse
+than the disease. If you patch an rshd to not care that the RSH originating
+port is "non-privileged", the CVS VMS client will allow you to define the
+logical CVS_RCMD_PORT to the port number where this patched rshd will be
+listening. I leave the talk of patching rshd to the gentle reader and his/her
+friendly system administrator.
+
+If I put an entry in my /etc/services file:
+
+cvs_rcmd 4381/tcp cvs_rcmd
+
+And add a line to /etc/inetd.conf, then restart inetd via "kill -1"
+
+cvs_rcmd stream tcp nowait root /usr/sbin/tcpd /usr/local/sbin/cvs_rcmd
+
+On the VMS side, you will have to do this:
+
+$ define CVS_RCMD_PORT 4381
+
+Then run CVS in the "usual way".
+
+Note that the patched rshd will need to be invoked via inetd as root, so it can
+authenticate and _become_ the intended user, the same as the regular rshd.
+
+***Please note that you will be installing a security hole by doing this.***
+
+Please also note that this security hole is no larger than allowing a
+Macintosh, PC (OS/2, NT, etc.) to have it's hostname in any .rhosts file,
+as any user can create a privileged socket without authentication, under these
+environments. In fact, existing ports of CVS to these environment use this
+to their advantage.
+
+-------------------------------------------------------------------------------
+Wildcard expansion is not yet implemented (i.e. CVS COMMIT *.c won't
+work.) I think that expand_wild should be calling lib$findfile
+(util.c in gzip is said to provide an example), but noone has gotten
+around to implementing this.
+
+Log messages must be entered on the command line using -m or -F. You
+can use -e or define the logical EDITOR to cause CVS to try other
+editors (TPU.EXE or any other editor which wants DCL command parsing
+will not work) if you want to test what's available on your system. I
+haven't tested this, but if you install vi or emacs, chances are it
+will probably work. Just make sure the .EXE files are in a directory
+listed in VAXC$PATH (is this a typo for DCL$PATH? Also, will a
+logical name work?). If someone gets around to implementing it, we
+should probably be using the callable editors (e.g. TPU$TPU), although
+of course we also need interface(s) which are not locked into any
+particular editors.
+
+----------------------------------------
+
+Notes regarding compiling on VAX/VMS 6.2 (not Alpha) (These are items
+which hopefully will have cleaner solutions in the future, but here is
+how to get around them for now):
+
+* Need to compile lib/getdate.c with vaxc instead of decc to avoid a
+compiler bugcheck. Therefore one must add SYS$LIBRARY:VAXCRTL/LIBRARY
+to the link.
+
+* In src/ignore.c, change lstat to stat. In vms/filesubr.c, change
+"#ifdef S_ISLNK" to "#if 0".
+
+* Ignore the warnings in vms/vmsmunch.c; the system include file
+declares something as an int when it should be void *. Not *our*
+fault!
+
+* Remove the #define's of mode_t in vms/vms.h and pid_t in vms/pwd.h.
+Add "#include <sys/types.h>" in vms/pwd.h.
+
+Credits:
+
+Initial VMS port by Benjamin J. Lee <benjamin@cyclic.com>, Cyclic
+Software, October 1, 1995 (Update March 1, 1996).
diff --git a/TESTS b/TESTS
new file mode 100644
index 0000000..de7ced1
--- /dev/null
+++ b/TESTS
@@ -0,0 +1,257 @@
+To run the tests:
+
+ $ make check
+
+Note that if your /bin/sh doesn't support shell functions, you'll
+have to try something like this, where "/bin/sh5" is replaced by the
+pathname of a shell which handles normal shell functions:
+
+ $ make SHELL=/bin/sh5 check
+
+Also note that you must be logged in as a regular user, not root.
+
+WARNING: This test can take quite a while to run, esp. if your
+disks are slow or over-loaded.
+
+The tests work in /tmp/cvs-sanity (which the tests create) by default.
+If for some reason you want them to work in a different directory, you
+can set the TESTDIR environment variable to the desired location
+before running them.
+
+The tests use a number of tools (awk, expr, id, tr, etc.) that are not
+required for running CVS itself. In most cases, the standard vendor-
+supplied versions of these tools work just fine, but there are some
+exceptions -- expr in particular is heavily used and many vendor
+versions are deficient in one way or another. Note that some vendors
+provide multiple versions of tools (typically an ancient, traditional
+version and a new, standards-conforming version), so you may already
+have a usable version even if the default version isn't. If you don't
+have a suitable tool, you can probably get one from the GNU Project (see
+http://www.gnu.org). At this writting, expr and id are both part of the
+GNU shellutils package, tr is part of the GNU textutils package, and awk
+is part of the GNU gawk package. The test script tries to verify that
+the tools exist and are usable; if not, it tries to find the GNU
+versions and use them instead. If it can't find the GNU versions
+either, it will print an error message and, depending on the severity of
+the deficiency, it may exit. There are environment variables you can
+set to use a particular version of a tool -- see the test script
+(src/sanity.sh) for details.
+
+Some of the tests use fairly long command lines -- this usually isn't a
+problem, but if you have a very short command line length limit (or a
+lot of environment variables), you may run into trouble. Also, some of
+the tests expect your local timezone to be an integral number of hours
+from UTC -- if you usually use a fractional timezone, use a different
+(integral) timezone when running the tests to avoid spurious failures.
+
+If running the tests produces the output "FAIL:" followed by the name
+of the test that failed, then the details on the failure are in the
+file check.log. If it says "exit status is " followed by a number,
+then the exit status of the command under test was not what the test
+expected. If it says "** expected:" followed by a regular expression
+followed by "** got:" followed by some text, then the regular
+expression is the output which the test expected, and the text is the
+output which the command under test actually produced. In some cases
+you'll have to look closely to see how they differ; the debug_check_log
+script in the contrib directory can assist in this process.
+
+If output from "make remotecheck" is out of order compared to what is
+expected (for example,
+
+ a
+ b
+ cvs foo: this is a demo
+
+is expected and
+
+ a
+ cvs foo: this is a demo
+ b
+
+is output), this is probably a well-known bug in the CVS server
+(search for "out-of-order" in src/server.c for a comment explaining
+the cause). It is a real pain in running the testsuite, but if you
+are lucky and/or your machine is fast and/or lightly loaded, you won't
+run into it. Running the tests again might succeed if the first run
+failed in this manner.
+
+For more information on what goes in check.log, and how the tests are
+run in general, you'll have to read sanity.sh. Depending on just what
+you are looking for, and how familiar you are with the Bourne shell
+and regular expressions, it will range from relatively straightforward
+to obscure.
+
+If you choose to submit a bug report based on tests failing, be
+aware that, as with all bug reports, you may or may not get a
+response, and your odds might be better if you include enough
+information to reproduce the bug, an analysis of what is going
+wrong (if you have the time to provide one), etc. The check.log
+file is the first place to look.
+
+ABOUT STDOUT AND STDERR
+***********************
+
+The sanity.sh test framework combines stdout and stderr and for tests
+to pass requires that output appear in the given order. Some people
+suggest that ordering between stdout and stderr should not be
+required, or to put it another way, that the out-of-order bug referred
+to above, and similar behaviors, should be considered features, or at
+least tolerable. The reasoning behind the current behavior is that
+having the output appear in a certain order is the correct behavior
+for users using CVS interactively--that users get confused if the
+order is unpredictable.
+
+ABOUT TEST FRAMEWORKS
+*********************
+
+People periodically suggest using dejagnu or some other test
+framework. A quick look at sanity.sh should make it clear that there
+are indeed reasons to be dissatisfied with the status quo. Ideally a
+replacement framework would achieve the following:
+
+1. Widely portable, including to a wide variety of unices, NT, Win95,
+OS/2, VMS, probably DOS and Win3, etc.
+
+2. Nicely match extended regular expressions of unlimited length.
+
+3. Be freely redistributable, and if possible already the kind of
+thing people might have already installed. The harder it is to get
+and install the framework, the less people will run the tests.
+
+The various contenders are:
+
+* Bourne shell and GNU expr (the status quo). Falls short on #1
+(we've only tried unix and NT, although MKS might help with other DOS
+mutants). #3 is pretty good (the main dependency is GNU expr which is
+fairly widely available).
+
+* Bourne shell with a new regexp matcher we would distribute with
+CVS. This means maintaining a regexp matcher and the makefiles which
+go with it. Not clearly a win over Bourne shell and GNU expr.
+
+* Bourne shell, and use sed to remove variable portions of output, and
+thus produce a form that can be compared with cmp or diff (this
+sidesteps the need for a full regular expression matcher as mentioned
+in #2 above). The C News tests are said to work this way. This would
+appear to rely on variable portions of output having a certain syntax
+and might spuriously recognize them out of context (this issue needs
+more investigation; it isn't clear how big a problem it is in
+practice). Same portability issues as the other choices based on the
+Bourne shell.
+
+* Dejagnu. This is overkill; most of dejagnu is either unnecessary
+(e.g. libraries for communicating with target boards) or undesirable
+(e.g. the code which stats every file in sight to find the tests). On
+the plus side, dejagnu is probably closer than any of the other
+choices to having everything which is needed already there.
+
+* Write our own small framework directly in tcl and distribute with
+CVS. The tests would look much like dejagnu tests, but we'd avoid the
+unnecessary baggage. The only dependency would be on tcl (that is,
+wish).
+
+* perl or python or <any other serious contenders here?>
+
+It is worth thinking about how to:
+
+a. include spaces in arguments which we pass to the program under
+test (sanity.sh dotest cannot do this; see test rcs-9 for a
+workaround).
+
+b. pass stdin to the program under test (sanity.sh, again, handles
+this by bypassing dotest).
+
+c. have a send-expect type dialog with the program under test
+ (e.g. see server-7 or pserver-4 which want to talk the CVS
+ protocol, or the many tests which need to answer the prompt of "cvs
+ release", e.g. deep-5).
+
+ABOUT ADDING YOUR OWN TESTS
+***************************
+
+As stated in the HACKING file, patches are not accepted without documentation
+and tests. Many people seem to be scared off by the large size of the
+sanity.sh script, but it is not really very complicated.
+
+You can probably ignore most of the begining of the script. This section
+just sets some environment variables and finds the tools the script needs to
+run.
+
+There is one main loop you can find by grepping for "The big loop". This loop
+repeatedly calls a case statement where the individual cases are of the form:
+
+ testname)
+ ...
+ ;;
+
+If you add a complete new test be sure to add it into the default list of tests
+(grep for 'tests=' near the begining of the script) as well as the case
+statement. During debugging, be aware that the sanity.sh usage allows for a '-f
+testname' option to continue through the default list "from" a particular test
+as well as interpreting everything in argv past the required options as test
+names to run individual tests.
+
+Within each major test section, individual tests usually look like:
+
+ dotest testname-subtestname "shell command" "optionally multiline regexp"
+
+Tests should always start in $testdir and create a subdirectory to operate in
+and remove their cruft and end back in $testdir. The dotest functions output
+failure messages and exit if the shell command exits with the wrong exit code or
+its stdin/stderr output doesn't match the regexp. There are a few dotest
+variations, most notably dotest_fail for expected non-zero exit codes.
+
+Other than that the script is mostly vanilla Bourne shell. There are a few
+common constructs used for versatility and portability. You can grep for the
+ones I miss, but here are a few important ones. I'm leaving off long
+explanations after the first few since it probably gives you the idea and the
+data is in sanity.sh.
+
+Several variables contain things intended to make a test writer's job easier.
+Note that the boolean variables contain shell commands which return true or
+false when executed and are intended to be used like,
+"if $remote; then ... ; else ... ; fi"
+
+
+ * $testdir = the directory this test is taking place in
+ (CVSROOT=$testdir/cvsroot or CVSROOT=:fork:$testdir/cvsroot)
+ * $testcvs = full path to the cvs executable we are testing
+ * $PLUS = expr dependant uninterpreted '+' since this can vary
+ * $DOTSTAR = expr dependant _interpreted_ .* since some exprs don't match
+ EOL
+ * $username = the username of the user running the tests
+ * $username8 = the first 8 characters of $username, output by some system
+ and CVS commands
+ * $anyusername
+ = regexp to match any valid system or CVS username
+ * $hostname = regexp to match a hostname
+ * $SPROG = regexp to match server progname in CVS error messages. For
+ tests run in local and remote mode, this is usually the
+ string to test for, since some messages can be printed either
+ by the CVS client or CVS server, dependant on the mode. In
+ local mode it will = $CPROG.
+ * $CPROG = regexp to match client progname in CVS error messages. Use
+ this to match error messages known to be printed only from
+ the CVS client.
+ * $remote = ':' (true) or 'false', depending on whether the script is
+ running with a remote CVSROOT
+ * $keep = ':' (true) or 'false'. When set, the first test run will
+ leave any files and directories it created in $testdir and
+ exit when complete.
+ * $servercvs = cvs executable to be run as CVS_SERVER in remote testing
+ * $testcvs_server_support
+ = ':' (true) or 'false', depending whether server support was
+ detected in the ${testcvs} executable.
+ * $tempfile = a regex to match a temporary file name, as generated by
+ the cvs_temp_file function.
+ * $tempname = a regex to match the full path to a temporary file generated
+ by cvs_temp_file (always set to `$TMPDIR/$tempfile').
+
+And, of course, some characters like '.' in regexps need to be '\' escaped when
+you mean them literally. Some characters may be interpreted by the shell,
+e.g. backquotes and '$', are usually either escaped or replaced with '.'.
+dotest adds the final '$' anchor to the regexp itself and all the expr
+implementations I know of implicitly supply the start anchor ('^').
+
+If you only make a few mistakes, the work is, of course, still usable, though we
+may send the patch back to you for repair. :)
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..783bf60
--- /dev/null
+++ b/TODO
@@ -0,0 +1,853 @@
+The "TODO" file! -*-Indented-Text-*-
+
+38. Think hard about using RCS state information to allow one to checkin
+ a new vendor release without having it be accessed until it has been
+ integrated into the local changes.
+
+39. Think about a version of "cvs update -j" which remembers what from
+ that other branch is already merged. This has pitfalls--it could
+ easily lead to invisible state which could confuse users very
+ rapidly--but having to create a tag or some such mechanism to keep
+ track of what has been merged is a pain. Take a look at PRCS 1.2.
+ PRCS 1.0 was particularly bad the way it handled the "invisible
+ state", but 1.2 is significantly better.
+
+52. SCCS has a feature that I would *love* to see in CVS, as it is very
+ useful. One may make a private copy of SCCS suid to a particular user,
+ so other users in the authentication list may check files in and out of
+ a project directory without mucking about with groups. Is there any
+ plan to provide a similar functionality to CVS? Our site (and, I'd
+ imagine, many other sites with large user bases) has decided against
+ having the user-groups feature of unix available to the users, due to
+ perceived administrative, technical and performance headaches. A tool
+ such as CVS with features that provide group-like functionality would
+ be a huge help.
+
+62. Consider using revision controlled files and directories to handle the
+ new module format -- consider a cvs command front-end to
+ add/delete/modify module contents, maybe.
+
+63. The "import" and vendor support commands (co -j) need to be documented
+ better.
+
+66. Length of the CVS temporary files must be limited to 14 characters for
+ System-V stupid support. As well as the length on the CVS.adm files.
+
+72. Consider re-design of the module -t options to use the file system more
+ intuitively.
+
+73. Consider an option (in .cvsrc?) to automatically add files that are new
+ and specified to commit.
+
+79. Might be nice to have some sort of interface to Sun's Translucent
+ (?) File System and tagged revisions.
+
+82. Maybe the import stuff should allow an arbitrary revision to be
+ specified.
+
+84. Improve the documentation about administration of the repository and
+ how to add/remove files and the use of symbolic links.
+
+85. Make symbolic links a valid thing to put under version control.
+ Perhaps use one of the tag fields in the RCS file? Note that we
+ can only support symlinks that are relative and within the scope of
+ the sources being controlled.
+
+93. Need to think hard about release and development environments. Think
+ about execsets as well.
+
+98. If diff3 bombs out (too many differences) cvs then thinks that the file
+ has been updated and is OK to be commited even though the file
+ has not yet been merged.
+
+100. Checked out files should have revision control support. Maybe.
+
+102. Perhaps directory modes should be propagated on all import check-ins.
+ Not necessarily uid/gid changes.
+
+103. setuid/setgid on files is suspect.
+
+104. cvs should recover nicely on unreadable files/directories.
+
+105. cvs should have administrative tools to allow for changing permissions
+ and modes and what not. In particular, this would make cvs a
+ more attractive alternative to rdist.
+
+107. It should be possible to specify a list of symbolic revisions to
+ checkout such that the list is processed in reverse order looking for
+ matches within the RCS file for the symbolic revision. If there is
+ not a match, the next symbolic rev on the list is checked, and so on,
+ until all symbolic revs are exhausted. This would allow one to, say,
+ checkout "4.0" + "4.0.3" + "4.0.3Patch1" + "4.0.3Patch2" to get the
+ most recent 4.x stuff. This is usually handled by just specifying the
+ right release_tag, but most people forget to do this.
+
+108. If someone creates a whole new directory (i.e. adds it to the cvs
+ repository) and you happen to have a directory in your source farm by
+ the same name, when you do your cvs update -d it SILENTLY does
+ *nothing* to that directory. At least, I think it was silent;
+ certainly, it did *not* abort my cvs update, as it would have if the
+ same thing had happened with a file instead of a directory.
+
+109. I had gotten pieces of the sys directory in the past but not a
+ complete tree. I just did something like:
+
+ cvs get *
+
+ Where sys was in * and got the message
+
+ cvs get: Executing 'sys/tools/make_links sys'
+ sh: sys/tools/make_links: not found
+
+ I suspect this is because I didn't have the file in question,
+ but I do not understand how I could fool it into getting an
+ error. I think a later cvs get sys seemed to work so perhaps
+ something is amiss in handling multiple arguments to cvs get?
+
+119. When importing a directory tree that is under SCCS/RCS control,
+ consider an option to have import checkout the SCCS/RCS files if
+ necessary. (This is if someone wants to import something which
+ is in RCS or SCCS without preserving the history, but makes sure
+ they do get the latest versions. It isn't clear to me how useful
+ that is -kingdon, June 1996).
+
+122. If Name_Repository fails, it currently causes CVS to die completely. It
+ should instead return NULL and have the caller do something reasonable
+ (??? -what is reasonable? I'm not sure there is a real problem here.
+ -kingdon, June 1996).
+
+123. Add a flag to import to not build vendor branches for local code.
+ (See `importb' tests in src/sanity.sh for more details).
+
+124. Anyway, I thought you might want to add something like the following
+ to the cvs man pages:
+
+ BUGS
+ The sum of the sizes of a module key and its contents are
+ limited. See ndbm(3).
+
+126. Do an analysis to see if CVS is forgetting to close file descriptors.
+ Especially when committing many files (more than the open file limit
+ for the particular UNIX).
+
+127. Look at *info files; they should all be quiet if the files are not
+ there. Should be able to point at a RCS directory and go.
+
+130. cvs diff with no -r arguments does not need to look up the current RCS
+ version number since it only cares about what's in the Entries file.
+ This should make it much faster.
+
+ It should ParseEntries itself and access the entries list much like
+ Version_TS does (sticky tags and sticky options may need to be
+ supported here as well). Then it should only diff the things that
+ have the wrong time stamp (the ones that look modified).
+
+134. Make a statement about using hard NFS mounts to your source
+ repository. Look into checking NULL fgets() returns with ferror() to
+ see if an error had occurred. (we should be checking for errors, quite
+ aside from NFS issues -kingdon, June 1996).
+
+137. Some sites might want CVS to fsync() the RCS ,v file to protect
+ against nasty hardware errors. There is a slight performance hit with
+ doing so, though, so it should be configurable in the .cvsrc file.
+ Also, along with this, we should look at the places where CVS itself
+ could be a little more synchronous so as not to lose data.
+ [[ I've done some of this, but it could use much more ]]
+
+138. Some people have suggested that CVS use a VPATH-like environment
+ variable to limit the amount of sources that need to be duplicated for
+ sites with giant source trees and no disk space.
+
+141. Import should accept modules as its directory argument. If we're
+ going to implement this, we should think hard about how modules
+ might be expanded and how to handle those cases.
+
+143. Update the documentation to show that the source repository is
+ something far away from the files that you work on. (People who
+ come from an RCS background are used to their `repository' being
+ _very_ close to their working directory.)
+
+144. Have cvs checkout look for the environment variable CVSPREFIX
+ (or CVSMODPREFIX or some such). If it's set, then when looking
+ up an alias in the modules database, first look it up with the
+ value of CVSPREFIX attached, and then look for the alias itself.
+ This would be useful when you have several projects in a single
+ repository. You could have aliases abc_src and xyz_src and
+ tell people working on project abc to put "setenv CVSPREFIX abc_"
+ in their .cshrc file (or equivalent for other shells).
+ Then they could do "cvs co src" to get a copy of their src
+ directory, not xyz's. (This should create a directory called
+ src, not abc_src.)
+
+145. After you create revision 1.1.1.1 in the previous scenario, if
+ you do "cvs update -r1 filename" you get revision 1.1, not
+ 1.1.1.1. It would be nice to get the later revision. Again,
+ this restriction comes from RCS and is probably hard to
+ change in CVS. Sigh.
+
+ |"cvs update -r1 filename" does not tell RCS to follow any branches. CVS
+ |tries to be consistent with RCS in this fashion, so I would not change
+ |this. Within CVS we do have the flexibility of extending things, like
+ |making a revision of the form "-r1HEAD" find the most recent revision
+ |(branch or not) with a "1." prefix in the RCS file. This would get what
+ |you want maybe.
+
+ This would be very useful. Though I would prefer an option
+ such as "-v1" rather than "-r1HEAD". This option might be
+ used quite often.
+
+146. The merging of files should be controlled via a hook so that programs
+ other than "rcsmerge" can be used, like Sun's filemerge or emacs's
+ emerge.el. (but be careful in making this work client/server--it means
+ doing the interactive merging at the end after the server is done).
+ (probably best is to have CVS do the non-interactive part and
+ tell the user about where the files are (.#foo.c.working and
+ .#foo.c.1.5 or whatever), so they can do the interactive part at
+ that point -kingdon, June 1996).
+
+149. Maybe there should be an option to cvs admin that allows a user to
+ change the Repository/Root file with some degree of error checking?
+ Something like "cvs admin reposmv /old/path /new/pretty/path". Before
+ it does the replace it check to see that the files
+ /new/pretty/path/<dir>/<files> exist.
+
+ The obvious cases are where one moves the repository to another
+ machine or directory. But there are other cases, like where the
+ user might want to change from :pserver: to :ext:, use a different
+ server (if there are two server machines which share the
+ repository using a networked file system), etc.
+
+ The status quo is a bit of a mess (as of, say, CVS 1.9). It is
+ that the -d global option has two moderately different uses. One
+ is to use a totally different repository (in which case we'd
+ probably want to give an error if it disagreed with CVS/Root, as
+ CVS 1.8 and earlier did). The other is the "reposmv"
+ functionality above (in which the two repositories really are the
+ same, and we want to update the CVS/Root files). In CVS 1.9 and
+ 1.10, -d rewrites the CVS/Root file (but not in subdirectories).
+ This behavior was not particularly popular and has been since
+ reverted.
+
+ This whole area is a rather bad pile of individual decisions which
+ accumulated over time, some of them probably bad decisions with
+ hindsight. But we didn't get into this mess overnight, and we're
+ not going to get out of it overnight (that is, we need to come up
+ with a replacement behavior, document what parts of the status
+ quo are deprecated, probably circulate some unofficial patches, &c).
+
+ (this item originally added 2 Feb 1992 but revised since).
+
+150. I have a customer request for a way to specify log message per
+ file, non-interactively before the commit, such that a single, fully
+ recursive commit prompts for one commit message, and concatenates the
+ per file messages for each file. In short, one commit, one editor
+ session, log messages allowed to vary across files within the commit.
+ Also, the per file messages should be allowed to be written when the
+ files are changed, which may predate the commit considerably.
+
+ A new command seems appropriate for this. The state can be saved in the
+ CVS directory. I.e.,
+
+ % cvs message foo.c
+ Enter log message for foo.c
+ >> fixed an uninitialized variable
+ >> ^D
+
+ The text is saved as CVS/foo.c,m (or some such name) and commit
+ is modified to append (prepend?) the text (if found) to the log
+ message specified at commit time. Easy enough. (having cvs
+ commit be non-interactive takes care of various issues like
+ whether to connect to the server before or after prompting for a
+ message (see comment in commit.c at call to start_server). Also
+ would clean up the kludge for what to do with the message from
+ do_editor if the up-to-date check fails (see commit.c client code).
+
+ I'm not sure about the part above about having commit prompt
+ for an overall message--part of the point is having commit
+ non-interactive and somehow combining messages seems like (excess?)
+ hair.
+
+ Would be nice to do this so it allows users more flexibility in
+ specifying messages per-directory ("cvs message -l") or per-tree
+ ("cvs message") or per-file ("cvs message foo.c"), and fixes the
+ incompatibility between client/server (per-tree) and
+ non-client/server (per-directory).
+
+ A few interesting issues with this: (1) if you do a cvs update or
+ some other operation which changes the working directory, do you
+ need to run "cvs message" again (it would, of course, bring up
+ the old message which you could accept)? Probably yes, after all
+ merging in some conflicts might change the situation. (2) How do
+ you change the stored messages if you change your mind before the
+ commit (probably run "cvs message" again, as hinted in (1))?
+
+151. Also, is there a flag I am missing that allows replacing Ulrtx_Build
+ by Ultrix_build? I.E. I would like a tag replacement to be a one step
+ operation rather than a two step "cvs rtag -r Ulrtx_Build Ultrix_Build"
+ followed by "cvs rtag -d Ulrtx_Build"
+
+152. The "cvs -n" option does not work as one would expect for all the
+ commands. In particular, for "commit" and "import", where one would
+ also like to see what it would do, without actually doing anything.
+
+153. There should be some command (maybe I just haven't figured out
+ which one...) to import a source directory which is already
+ RCS-administered without losing all prior RCS gathered data.
+ Thus, it would have to examine the RCS files and choose a
+ starting version and branch higher than previous ones used.
+ (Check out rcs-to-cvs and see if it addresses this issue.)
+
+154. When committing the modules file, a pre-commit check should be done to
+ verify the validity of the new modules file before allowing it to be
+ committed.
+
+155. The options for "cvs history" are mutually exclusive, even though
+ useful queries can be done if they are not, as in specifying both
+ a module and a tag. A workaround is to specify the module, then
+ run the output through grep to only display lines that begin with
+ T, which are tag lines. (Better perhaps if we redesign the whole
+ "history" business -- check out doc/cvs.texinfo for the entire
+ rant.)
+
+156. Also, how hard would it be to allow continuation lines in the
+ {commit,rcs,log}info files? It would probably be useful with all of
+ the various flags that are now available, or if somebody has a lot of
+ files to put into a module.
+
+158. If I do a recursive commit and find that the same RCS file is checked
+ out (and modified!) in two different places within my checked-out
+ files (but within the realm of a single "commit"), CVS will commit the
+ first change, then overwrite that change with the second change. We
+ should catch this (typically unusual) case and issue an appropriate
+ diagnostic and die.
+
+160. The checks that the commit command does should be extended to make
+ sure that the revision that we will lock is not already locked by
+ someone else. Maybe it should also lock the new revision if the old
+ revision was already locked by the user as well, thus moving the lock
+ forward after the commit.
+
+163. The rtag/tag commands should have an option that removes the specified
+ tag from any file that is in the attic. This allows one to re-use a
+ tag (like "Mon", "Tue", ...) all the time and still have it tag the
+ real main-line code.
+
+165. The "import" command will create RCS files automatically, but will
+ screw-up when trying to create long file names on short file name
+ file systems. Perhaps import should be a bit more cautious.
+
+166. There really needs to be a "Getting Started" document which describes
+ some of the new CVS philosophies. Folks coming straight from SCCS or
+ RCS might be confused by "cvs import". Also need to explain:
+ - How one might setup their $CVSROOT
+ - What all the tags mean in an "import" command
+ - Tags are important; revision numbers are not
+
+170. Is there an "info" file that can be invoked when a file is checked out, or
+ updated ? What I want to do is to advise users, particularly novices, of
+ the state of their working source whenever they check something out, as
+ a sanity check.
+
+ For example, I've written a perl script which tells you what branch you're
+ on, if any. Hopefully this will help guard against mistaken checkins to
+ the trunk, or to the wrong branch. I suppose I can do this in
+ "commitinfo", but it'd be nice to advise people before they edit their
+ files.
+
+ It would also be nice if there was some sort of "verboseness" switch to
+ the checkout and update commands that could turn this invocation of the
+ script off, for mature users.
+
+173. Need generic date-on-branch handling. Currently, many commands
+ allow both -r and -D, but that's problematic for commands like diff
+ that interpret that as two revisions rather than a single revision.
+ Checkout and update -j takes tag:date which is probably a better
+ solution overall.
+
+174. I would like to see "cvs release" modified so that it only removes files
+ which are known to CVS - all the files in the repository, plus those which
+ are listed in .cvsignore. This way, if you do leave something valuable in
+ a source tree you can "cvs release -d" the tree and your non-CVS goodies
+ are still there. If a user is going to leave non-CVS files in their source
+ trees, they really should have to clean them up by hand.
+
+175. And, in the feature request department, I'd dearly love a command-line
+ interface to adding a new module to the CVSROOT/modules file.
+
+176. If you use the -i flag in the modules file, you can control access
+ to source code; this is a Good Thing under certain circumstances. I
+ just had a nasty thought, and on experiment discovered that the
+ filter specified by -i is _not_ run before a cvs admin command; as
+ this allows a user to go behind cvs's back and delete information
+ (cvs admin -o1.4 file) this seems like a serious problem.
+
+177. We've got some external vendor source that sits under a source code
+ hierarchy, and when we do a cvs update, it gets wiped out because
+ its tag is different from the "main" distribution. I've tried to
+ use "-I" to ignore the directory, as well as .cvsignore, but this
+ doesn't work.
+
+179. "cvs admin" does not log its actions with loginfo, nor does it check
+ whether the action is allowed with commitinfo. It should.
+
+182. There should be a way to show log entries corresponding to
+changes from tag "foo" to tag "bar". "cvs log -rfoo:bar" doesn't cut
+it, because it erroneously shows the changes associated with the
+change from the revision before foo to foo. I'm not sure that is ever
+a useful or logical behavior ("cvs diff -r foo -r bar" gets this
+right), but is compatibility an issue? See
+http://www.cyclic.com/cvs/unoff-log.txt for an unofficial patch.
+
+183. "cvs status" should report on Entries.Static flag and CVS/Tag (how?
+maybe a "cvs status -d" to give directory status?). There should also
+be more documentation of how these get set and how/when to re-set them.
+
+184. Would be nice to implement the FreeBSD MD5-based password hash
+algorithm in pserver. For more info see "6.1. DES, MD5, and Crypt" in
+the FreeBSD Handbook, and src/lib/libcrypt/crypt.c in the FreeBSD
+sources. Certainly in the context of non-unix servers this algorithm
+makes more sense than the traditional unix crypt() algorithm, which
+suffers from export control problems.
+
+185. A frequent complaint is that keyword expansion causes conflicts
+when merging from one branch to another. The first step is
+documenting CVS's existing features in this area--what happens with
+various -k options in various places? The second step is thinking
+about whether there should be some new feature and if so how it should
+be designed. For example, here is one thought:
+
+ rcs' co command needs a new -k option. The new option should expand
+ $Log entries without expanding $Revision entries. This would
+ allow cvs to use rcsmerge in such a way that joining branches into
+ main lines would neither generate extra collisions on revisions nor
+ drop log lines.
+
+The details of this are out of date (CVS no longer invokes "co", and
+any changes in this area would be done by bypassing RCS rather than
+modifying it), but even as to the general idea, I don't have a clear
+idea about whether it would be good (see what I mean about the need
+for better documentation? I work on CVS full-time, and even I don't
+understand the state of the art on this subject).
+
+186. There is a frequent discussion of multisite features.
+
+* There may be some overlap with the client/server CVS, which is good
+especially when there is a single developer at each location. But by
+"multisite" I mean something in which each site is more autonomous, to
+one extent or another.
+
+* Vendor branches are the closest thing that CVS currently has for
+multisite features. They have fixable drawbacks (such as poor
+handling of added and removed files), and more fundamental drawbacks
+(when you import a vendor branch, you are importing a set of files,
+not importing any knowledge of their version history outside the
+current repository).
+
+* One approach would be to require checkins (or other modifications to
+the repository) to succeed at a write quorum of sites (51%) before
+they are allowed to complete. To work well, the network should be
+reliable enough that one can typically get to that many sites. When a
+server which has been out of touch reconnects, it would want to update
+its data before doing anything else. Any of the servers can service
+all requests locally, except perhaps for a check that they are
+up-to-date. The way this differs from a run-of-the-mill distributed
+database is that if one only allows reversible operations via this
+mechanism (exclude "cvs admin -o", "cvs tag -d", &c), then each site
+can back up the others, such that failures at one site, including
+something like deleting all the sources, can be recovered from. Thus
+the sites need not trust each other as much as for many shared
+databases, and the system may be resilient to many types of
+organizational failures. Sometimes I call this design the
+"CVScluster" design.
+
+* Another approach is a master/slave one. Checkins happen at the
+master site, and slave sites need to check whether their local
+repository is up to date before relying on its information.
+
+* Another approach is to have each site own a particular branch. This
+one is the most tolerant of flaky networks; if checkins happen at each
+site independently there is no particular problem. The big question
+is whether merges happen only manually, as with existing CVS branches,
+or whether there is a feature whereby there are circumstances in which
+merges from one branch to the other happen automatically (for example,
+the case in which the branches have not diverged). This might be a
+legitimate question to ask even quite aside from multisite features.
+
+187. Might want to separate out usage error messages and help
+messages. The problem now is that if you specify an invalid option,
+for example, the error message is lost among all the help text. In
+the new regime, the error message would be followed by a one-line
+message directing people to the appropriate help option ("cvs -H
+<command>" or "cvs --help-commands" or whatever, according to the
+situation). I'm not sure whether this change would be controversial
+(as defined in HACKING), so there might be a need for further
+discussion or other actions other than just coding.
+
+188. Option parsing and .cvsrc has at least one notable limitation.
+If you want to set a global option only for some CVS commands, there
+is no way to do it (for example, if one wants to set -q only for
+"rdiff"). I am told that the "popt" package from RPM
+(http://www.rpm.org) could solve this and other problems (for example,
+if the syntax of option stuff in .cvsrc is similar to RPM, that would
+be great from a user point of view). It would at least be worth a
+look (it also provides a cleaner API than getopt_long).
+
+Another issue which may or may not be related is the issue of
+overriding .cvsrc from the command line. The cleanest solution might
+be to have options in mutually exclusive sets (-l/-R being a current
+example, but --foo/--no-foo is a better way to name such options). Or
+perhaps there is some better solution.
+
+189. Renaming files and directories is a frequently discussed topic.
+
+Some of the problems with the status quo:
+
+a. "cvs annotate" cannot operate on both the old and new files in a
+single run. You need to run it twice, once for the new name and once
+for the old name.
+
+b. "cvs diff" (or "cvs diff -N") shows a rename as a removal of the
+old file and an addition of the new one. Some people would like to
+see the differences between the file contents (but then how would we
+indicate the fact that the file has been renamed? Certainly the
+notion that "patch(1)" has of renames is as a removal and addition).
+
+c. "cvs log" should be able to show the changes between two
+tags/dates, even in the presence of adds/removes/renames (I'm not sure
+what the status quo is on this; see also item #182).
+
+d. Renaming directories is way too hard.
+
+Implementations:
+
+It is perhaps premature to try to design implementation details
+without answering some of the above questions about desired behaviors
+but several general implementations get mentioned.
+
+i. No fundamental changes (for example, a "cvs rename" command which
+operated on directories could still implement the current recommended
+practice for renaming directories, which is to rename each of the
+files contained therein via an add and a remove). One thing to note
+that the status quo gets right is proper merges, even with adds and
+removals (Well, mostly right at least. There are a *LOT* of different
+cases; see the testsuite for some of them).
+
+ii. Rename database. In this scheme the files in the repository
+would have some arbitrary name, and then a separate rename database
+would indicate the current correspondence between the filename in the
+working directory and the actual storage. As far as I know this has
+never been designed in detail for CVS.
+
+iii. A modest change in which the RCS files would contain some
+information such as "renamed from X" or "renamed to Y". That is, this
+would be generally similar to the log messages which are suggested
+when one renames via an add and a removal, but would be
+computer-parseable. I don't think anyone has tried to flesh out any
+details here either.
+
+It is interesting to note that in solution ii. version numbers in the
+"new file" start where the "old file" left off, while in solutions
+i. and iii., version numbers restart from 1.1 each time a file is
+renamed. Except perhaps in the case where we rename a file from foo
+to bar and then back to foo. I'll shut up now.
+
+Regardless of the method we choose, we need to address how renames
+affect existing CVS behaviors. For example, what happens when you
+rename a file on a branch but not the trunk and then try to merge the
+two? What happens when you rename a file on one branch and delete it
+on another and try to merge the two?
+
+Ideally, we'd come up with a way to parameterize the problem and
+simply write up a lookup table to determine the correct behavior.
+
+190. The meaning of the -q and -Q global options is very ad hoc;
+there is no clear definition of which messages are suppressed by them
+and which are not. Here is a classification of the current meanings
+of -q; I don't know whether anyone has done a similar investigation of
+-Q:
+
+ a. The "warm fuzzies" printed upon entering each directory (for
+ example, "cvs update: Updating sdir"). The need for these messages
+ may be decreased now that most of CVS uses ->fullname instead of
+ ->file in messages (a project which is *still* not 100% complete,
+ alas). However, the issue of whether CVS can offer status as it
+ runs is an important one. Of course from the command line it is
+ hard to do this well and one ends up with options like -q. But
+ think about emacs, jCVS, or other environments which could flash you
+ the latest status line so you can see whether the system is working
+ or stuck.
+
+ b. Other cases where the message just offers information (rather
+ than an error) and might be considered unnecessarily verbose. These
+ have a certain point to them, although it isn't really clear whether
+ it should be the same option as the warm fuzzies or whether it is
+ worth the conceptual hair:
+
+ add.c: scheduling %s `%s' for addition (may be an issue)
+ modules.c: %s %s: Executing '%s' (I can see how that might be noise,
+ but...)
+ remove.c: scheduling `%s' for removal (analogous to the add.c one)
+ update.c: Checking out %s (hmm, that message is a bit on the noisy side...)
+ (but the similar message in annotate is not affected by -q).
+
+ c. Suppressing various error messages. This is almost surely
+ bogus.
+
+ commit.c: failed to remove tag `%s' from `%s' (Questionable.
+ Rationale might be that we already printed another message
+ elsewhere but why would it be necessary to avoid
+ the extra message in such an uncommon case?)
+ commit.c: failed to commit dead revision for `%s' (likewise)
+ remove.c: file `%s' still in working directory (see below about rm
+ -f analogy)
+ remove.c: nothing known about `%s' (looks dubious to me, especially in
+ the case where the user specified it explicitly).
+ remove.c: removed `%s' (seems like an obscure enough case that I fail
+ to see the appeal of being cryptically concise here).
+ remove.c: file `%s' already scheduled for removal (now it is starting
+ to look analogous to the infamous rm -f option).
+ rtag.c: cannot find tag `%s' in `%s' (more rm -f like behavior)
+ rtag.c: failed to remove tag `%s' from `%s' (ditto)
+ tag.c: failed to remove tag %s from %s (see above about whether RCS_*
+ has already printed an error message).
+ tag.c: couldn't tag added but un-commited file `%s' (more rm -f
+ like behavior)
+ tag.c: skipping removed but un-commited file `%s' (ditto)
+ tag.c: cannot find revision control file for `%s' (ditto, but at first
+ glance seems even worse, as this would seem to be a "can't happen"
+ condition)
+
+191. Storing RCS files, especially binary files, takes rather more
+space than it could, typically.
+ - The virtue of the status quo is that it is simple to implement.
+ Of course it is also simplest in terms of dealing with compatibility.
+ - Just storing the revisions as separate gzipped files is a common
+ technique. It also is pretty simple (no new algorithms, CVS
+ already has zlib around). Of course for some files (such as files
+ which are already compressed) the gzip step won't help, but
+ something which can at least sometimes avoid rewriting the entire
+ RCS file for each new revision would, I would think, be a big
+ speedup for large files.
+ - Josh MacDonald has written a tool called xdelta which produces
+ differences (that is, sufficient information to transform the old
+ to the new) which looks for common sequences of bytes, like RCS
+ currently does, but which is not based on lines. This seems to do
+ quite well for some kinds of files (e.g. FrameMaker documents,
+ text files), and not as well for others (anything which is already
+ compressed, executables). xdelta 1.10 also is faster than GNU diff.
+ - Karl Fogel has thought some about using a difference technique
+ analogous to fractal compression (see the comp.compression FAQ for
+ more on fractal compression, including at least one patent to
+ watch for; I don't know how analogous Karl's ideas are to the
+ techniques described there).
+ - Quite possibly want some documented interface by which a site can
+ plug in their choice of external difference programs (with the
+ ability to choose the program based on filename, magic numbers,
+ or some such).
+
+192. "cvs update" using an absolute pathname does not work if the
+working directory is not a CVS-controlled directory with the correct
+CVSROOT. For example, the following will fail:
+
+ cd /tmp
+ cvs -d /repos co foo
+ cd /
+ cvs update /tmp/foo
+
+It is possible to read the CVSROOT from the administrative files in
+the directory specified by the absolute pathname argument to update.
+In that case, the last command above would be equivalent to:
+
+ cd /tmp/foo
+ cvs update .
+
+This can be problematic, however, if we ask CVS to update two
+directories with different CVSROOTs. Currently, CVS has no way of
+changing CVSROOT mid-stream. Consider the following:
+
+ cd /tmp
+ cvs -d /repos1 co foo
+ cvs -d /repos2 co bar
+ cd /
+ cvs update /tmp/foo /tmp/bar
+
+To make that example work, we need to think hard about:
+
+ - where and when CVSROOT-related variables get set
+ - who caches said variables for later use
+ - how the remote protocol should be extended to handle sending a new
+ repository mid-stream
+ - how the client should maintain connections to a variety of servers
+ in a single invocation.
+
+Because those issues are hairy, I suspect that having a change in
+CVSROOT be an error would be a better move.
+
+193. The client relies on timestamps to figure out whether a file is
+(maybe) modified. If something goes awry, then it ends up sending
+entire files to the server to be checked, and this can be quite slow
+especially over a slow network. A couple of things that can happen:
+(a) other programs, like make, use timestamps, so one ends up needing
+to do "touch foo" and otherwise messing with timestamps, (b) changing
+the timezone offset (e.g. summer vs. winter or moving a machine)
+should work on unix, but there may be problems with non-unix.
+
+Possible solutions:
+
+ a. Store a checksum for each file in CVS/Entries or some such
+ place. What to do about hash collisions is interesting: using a
+ checksum, like MD5, large enough to "never" have collisions
+ probably works in practice (of course, if there is a collision then
+ all hell breaks loose because that code path was not tested, but
+ given the tiny, tiny probability of that I suppose this is only an
+ aesthetic issue).
+
+ b. I'm not thinking of others, except storing the whole file in
+ CVS/Base, and I'm sure using twice the disk space would be
+ unpopular.
+
+194. CVS does not separate the "metadata" from the actual revision
+history; it stores them both in the RCS files. Metadata means tags
+and header information such as the number of the head revision.
+Storing the metadata separately could speed up "cvs tag" enormously,
+which is a big problem for large repositories. It could also probably
+make CVS's locking much less in the way (see comment in do_recursion
+about "two-pass design").
+
+195. Many people using CVS over a slow link are interested in whether
+the remote protocol could be any more efficient with network
+bandwidth. This item is about one aspect of that--how the server
+sends a new version of a file the client has a different version of,
+or vice versa.
+
+a. Cases in which the status quo already sends a diff. For most text
+files, this is probably already close to optimal. For binary files,
+and anomalous (?) text files (e.g. those in which it would help to do
+moves, as well as adds and deletes), it might be worth looking into other
+difference algorithms (see item #191).
+
+b. Cases in which the status quo does not send a diff (e.g. "cvs
+commit").
+
+b1. With some frequency, people suggest rsync or a similar algorithm
+(see ftp://samba.anu.edu.au/pub/rsync/). This could speed things up,
+and in some ways involves the most minimal changes to the default CVS
+paradigm. There are some downsides though: (1) there is an extra
+network turnaround, (2) the algorithm needs to transmit some data to
+discover what difference type programs can discover locally (although
+this is only about 1% of the size of the files).
+
+b2. If one is willing to require that users use "cvs edit" before
+editing a file on the client side (in some cases, a development
+environment like emacs can make this fairly easy), then the Modified
+request in the protocol could be extended to allow the client to just
+send differences instead of entire files. In the degenerate case
+(e.g. "cvs diff" without arguments) the required network traffic is
+reduced to zero, and the client need not even contact the server.
+
+197. Analyze the difference between CVS_UNLINK & unlink_file. As far as I
+can tell, unlink_file aborts in noexec mode and CVS_UNLINK does not. I'm not
+sure it would be possible to remove even the use of temp files in noexec mode,
+but most unlinks should probably be using unlink_file and not CVS_UNLINK.
+
+198. Remove references to deprecated cvs_temp_name function.
+
+199. Add test for login & logout functionality, including support for
+backwards compatibility with old CVSROOTs.
+
+200. Make a 'cvs add' without write access a non-fatal error so that
+the user's Entries file is updated and future 'cvs diffs' will work
+properly. This should ease patch submission.
+
+201. cvs_temp_file should be creating temporary files in a privately owned
+subdirectory of of temp due to security issues on some systems.
+
+202. Enable rdiff to accept most diff options. Make rdiff output look
+like diff's. Make CVS diff garbage go to stderr and only standard diff
+output go to stdout.
+
+203. Add val-tags additions to the tagging code. Don't remove the
+update additions since val-tags could still be used as a cache when the
+repository was imported from elsewhere (the tags weren't applied with a
+version which wrote val-tags).
+
+204. Add test case for compression. A buf_shutdown error using compression
+wasn't caught by the test suite.
+
+205. There are lots of cases where trailing slashes on directory names
+and other non-canonical paths confuse CVS. Most of the cases that do
+work are handled on an ad-hoc basis. We need to come up with a coherent
+strategy to address path canonicalization and apply it consistently.
+
+208. Merge enhancements to the diff package back into the original GNU source.
+
+209. Go through this file and try to:
+
+ a. Verify that items are still valid.
+
+ b. Create test cases for valid items when they don't exist.
+
+ c. Remove fixed and no longer applicable items.
+
+210. Explain to sanity.sh how to deal with paths with spaces and other odd
+characters in them.
+
+211. Make sanity.sh run under the Win32 bash (cygwin) and maybe other Windex
+environments (e.g. DGSS or whatever the MSVC portability environemnt is called).
+
+212. Autotestify (see autoconf source) sanity.sh.
+
+213. Examine desirability of updating the regex library (regex.{c,h}) to the
+more recent versions that come with glibc and emacs. It might be worth waiting
+for the emacs folks to get their act together and merge their changes into the
+glibc version.
+
+215. Add reditors and rwatchers commands.
+
+ - Is an r* command abstraction layer possible here for the commands
+ where this makes sense? Would it be simpler? It seems to me the
+ major operational differences lie in the file list construction.
+
+218. Fix "checkout -d ." in client/server mode.
+
+221. Handle spaces in file/directory names. (Most, if not all, of the
+internal infrastructure already handles them correctly, but most of the
+administrative file interfaces do not.)
+
+223. Internationalization support. This probably means using some kind
+of universal character set (ISO 10646?) internally and converting on
+input and output, which opens the locale can of worms.
+
+225. Add support for --allow-root to server command.
+
+227. 'cvs release' should use the CVS/Root in the directory being released
+when such is specified rather than $CVSROOT. In my work directory with no CVS
+dir, a release of subdirectories causes the released projects to be tested
+against my $CVSROOT environment variable, which often isn't correct but which
+can complete without generating error messages if the project also exists in
+the other CVSROOT. This happens a lot with my copies of the ccvs project.
+
+228. Consider adding -d to commit ala ci.
+
+229. Improve the locking code to use a random delay with exponential
+backoff ala Ethernet and separate the notification interval from the
+wait interval.
+
+230. Support for options like compression as part of the CVSROOT might be
+nice. This should be fairly easy to implement now using the method options.
+
+231. The `cvs watch off' command needs an extension which enables users in the
+cvsadmin group to turn watch off for users whose logins and email address may
+not exist anymore.
+
+232. Use file descriptor operations exclusively for I/O (not STDIO).
+
+233. The ls-D-2 test fails when run in the hour transition between daylight
+savings time and standard time. This probably has something to do with the
+two 1AM to 2AM time slots that occur over that two hour period (one such
+failure was on the morning of October 31st, 2004).
+
+234. Noop commands should be logged in the history file. Information can
+still be obtained with noop commands, for instance via `cvs -n up -p', and
+paranoid admins might appreciate this. Similarly, perhaps diff operations
+should be logged.
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..840c772
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1040 @@
+# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+ [AM_AUTOMAKE_VERSION([1.9.6])])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 7
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 3
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 12
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.58])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $1 | $1:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+AC_DEFUN([AM_MAINTAINER_MODE],
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Copyright (C) 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# AM_PROG_CC_C_O
+# --------------
+# Like AC_PROG_CC_C_O, but changed for automake.
+AC_DEFUN([AM_PROG_CC_C_O],
+[AC_REQUIRE([AC_PROG_CC_C_O])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+ac_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+#
+# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+# created by `make install' are always world readable, even if the
+# installer happens to have an overly restrictive umask (e.g. 077).
+# This was a mistake. There are at least two reasons why we must not
+# use `-m 0755':
+# - it causes special bits like SGID to be ignored,
+# - it may be too restrictive (some setups expect 775 directories).
+#
+# Do not use -m 0755 and let people choose whatever they expect by
+# setting umask.
+#
+# We cannot accept any implementation of `mkdir' that recognizes `-p'.
+# Some implementations (such as Solaris 8's) are not thread-safe: if a
+# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
+# concurrently, both version can detect that a/ is missing, but only
+# one can create it and the other will error out. Consequently we
+# restrict ourselves to GNU make (using the --version option ensures
+# this.)
+AC_DEFUN([AM_PROG_MKDIR_P],
+[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+AC_SUBST([mkdir_p])])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/acx_extract_cpp_defn.m4])
+m4_include([m4/acx_with_external_zlib.m4])
+m4_include([m4/acx_with_gssapi.m4])
+m4_include([m4/alloca.m4])
+m4_include([m4/allocsa.m4])
+m4_include([m4/asx_version_compare.m4])
+m4_include([m4/atexit.m4])
+m4_include([m4/bison.m4])
+m4_include([m4/canon-host.m4])
+m4_include([m4/canonicalize.m4])
+m4_include([m4/chdir-long.m4])
+m4_include([m4/clock_time.m4])
+m4_include([m4/closeout.m4])
+m4_include([m4/codeset.m4])
+m4_include([m4/cvs_func_printf_ptr.m4])
+m4_include([m4/d-ino.m4])
+m4_include([m4/d-type.m4])
+m4_include([m4/dirname.m4])
+m4_include([m4/dos.m4])
+m4_include([m4/dup2.m4])
+m4_include([m4/eealloc.m4])
+m4_include([m4/eoverflow.m4])
+m4_include([m4/error.m4])
+m4_include([m4/exitfail.m4])
+m4_include([m4/extensions.m4])
+m4_include([m4/filenamecat.m4])
+m4_include([m4/fnmatch.m4])
+m4_include([m4/fpending.m4])
+m4_include([m4/ftruncate.m4])
+m4_include([m4/getaddrinfo.m4])
+m4_include([m4/getcwd-path-max.m4])
+m4_include([m4/getcwd.m4])
+m4_include([m4/getdate.m4])
+m4_include([m4/getdelim.m4])
+m4_include([m4/gethostname.m4])
+m4_include([m4/getline.m4])
+m4_include([m4/getlogin_r.m4])
+m4_include([m4/getndelim2.m4])
+m4_include([m4/getnline.m4])
+m4_include([m4/getopt.m4])
+m4_include([m4/getpagesize.m4])
+m4_include([m4/getpass.m4])
+m4_include([m4/gettext.m4])
+m4_include([m4/gettime.m4])
+m4_include([m4/gettimeofday.m4])
+m4_include([m4/glob.m4])
+m4_include([m4/gnulib-comp.m4])
+m4_include([m4/iconv.m4])
+m4_include([m4/intmax_t.m4])
+m4_include([m4/inttypes.m4])
+m4_include([m4/inttypes_h.m4])
+m4_include([m4/lib-ld.m4])
+m4_include([m4/lib-link.m4])
+m4_include([m4/lib-prefix.m4])
+m4_include([m4/longdouble.m4])
+m4_include([m4/longlong.m4])
+m4_include([m4/lstat.m4])
+m4_include([m4/mbchar.m4])
+m4_include([m4/mbiter.m4])
+m4_include([m4/mbrtowc.m4])
+m4_include([m4/mbstate_t.m4])
+m4_include([m4/md5.m4])
+m4_include([m4/memchr.m4])
+m4_include([m4/memmove.m4])
+m4_include([m4/mempcpy.m4])
+m4_include([m4/memrchr.m4])
+m4_include([m4/minmax.m4])
+m4_include([m4/mkdir-slash.m4])
+m4_include([m4/mkstemp.m4])
+m4_include([m4/mktime.m4])
+m4_include([m4/mmap-anon.m4])
+m4_include([m4/nanosleep.m4])
+m4_include([m4/nls.m4])
+m4_include([m4/onceonly_2_57.m4])
+m4_include([m4/openat.m4])
+m4_include([m4/pagealign_alloc.m4])
+m4_include([m4/pathmax.m4])
+m4_include([m4/po.m4])
+m4_include([m4/progtest.m4])
+m4_include([m4/quotearg.m4])
+m4_include([m4/readlink.m4])
+m4_include([m4/regex.m4])
+m4_include([m4/rename.m4])
+m4_include([m4/restrict.m4])
+m4_include([m4/rpmatch.m4])
+m4_include([m4/save-cwd.m4])
+m4_include([m4/setenv.m4])
+m4_include([m4/signed.m4])
+m4_include([m4/size_max.m4])
+m4_include([m4/sockpfaf.m4])
+m4_include([m4/ssize_t.m4])
+m4_include([m4/stat-macros.m4])
+m4_include([m4/stdbool.m4])
+m4_include([m4/stdint.m4])
+m4_include([m4/stdint_h.m4])
+m4_include([m4/strcase.m4])
+m4_include([m4/strdup.m4])
+m4_include([m4/strerror.m4])
+m4_include([m4/strftime.m4])
+m4_include([m4/strstr.m4])
+m4_include([m4/strtol.m4])
+m4_include([m4/strtoul.m4])
+m4_include([m4/sunos57-select.m4])
+m4_include([m4/time_r.m4])
+m4_include([m4/timespec.m4])
+m4_include([m4/tm_gmtoff.m4])
+m4_include([m4/tzset.m4])
+m4_include([m4/uint32_t.m4])
+m4_include([m4/uintmax_t.m4])
+m4_include([m4/ulonglong.m4])
+m4_include([m4/unistd-safer.m4])
+m4_include([m4/unlocked-io.m4])
+m4_include([m4/vasnprintf.m4])
+m4_include([m4/vasprintf.m4])
+m4_include([m4/wchar_t.m4])
+m4_include([m4/wint_t.m4])
+m4_include([m4/xalloc.m4])
+m4_include([m4/xgetcwd.m4])
+m4_include([m4/xreadlink.m4])
+m4_include([m4/xsize.m4])
+m4_include([m4/yesno.m4])
diff --git a/build-aux/compile b/build-aux/compile
new file mode 100755
index 0000000..ad57e2f
--- /dev/null
+++ b/build-aux/compile
@@ -0,0 +1,142 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2005-02-03.08
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as `compile cc -o foo foo.c'.
+ # So we strip `-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no `-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # `.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/build-aux/config.guess b/build-aux/config.guess
new file mode 100755
index 0000000..2fc3acc
--- /dev/null
+++ b/build-aux/config.guess
@@ -0,0 +1,1411 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-17'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+## for Red Hat Linux
+if test -f /etc/redhat-release ; then
+ VENDOR=redhat ;
+else
+ VENDOR= ;
+fi
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha*:OpenVMS:*:*)
+ echo alpha-hp-vms
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit 0 ;;
+ DRS?6000:UNIX_SV:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7 && exit 0 ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c \
+ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && exit 0
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ # avoid double evaluation of $set_cc_for_build
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ *:UNICOS/mp:*:*)
+ echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
+ # Determine whether the default compiler uses glibc.
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #if __GLIBC__ >= 2
+ LIBC=gnu
+ #else
+ LIBC=
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit 0 ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu
+ exit 0 ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit 0 ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ case `uname -p` in
+ *86) UNAME_PROCESSOR=i686 ;;
+ powerpc) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build-aux/config.rpath b/build-aux/config.rpath
new file mode 100755
index 0000000..3f1bef3
--- /dev/null
+++ b/build-aux/config.rpath
@@ -0,0 +1,571 @@
+#! /bin/sh
+# Output a system dependent set of variables, describing how to set the
+# run time search path of shared libraries in an executable.
+#
+# Copyright 1996-2005 Free Software Foundation, Inc.
+# Taken from GNU libtool, 2001
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# The first argument passed to this file is the canonical host specification,
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
+# should be set by the caller.
+#
+# The set of defined variables is at the end of this script.
+
+# Known limitations:
+# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
+# than 256 bytes, otherwise the compiler driver will dump core. The only
+# known workaround is to choose shorter directory names for the build
+# directory and/or the installation directory.
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+shrext=.so
+
+host="$1"
+host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+cc_basename=`echo "$CC" | sed -e 's%^.*/%%'`
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
+
+wl=
+if test "$GCC" = yes; then
+ wl='-Wl,'
+else
+ case "$host_os" in
+ aix*)
+ wl='-Wl,'
+ ;;
+ darwin*)
+ case "$cc_basename" in
+ xlc*)
+ wl='-Wl,'
+ ;;
+ esac
+ ;;
+ mingw* | pw32* | os2*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ wl='-Wl,'
+ ;;
+ irix5* | irix6* | nonstopux*)
+ wl='-Wl,'
+ ;;
+ newsos6)
+ ;;
+ linux*)
+ case $cc_basename in
+ icc* | ecc*)
+ wl='-Wl,'
+ ;;
+ pgcc | pgf77 | pgf90)
+ wl='-Wl,'
+ ;;
+ ccc*)
+ wl='-Wl,'
+ ;;
+ como)
+ wl='-lopt='
+ ;;
+ esac
+ ;;
+ osf3* | osf4* | osf5*)
+ wl='-Wl,'
+ ;;
+ sco3.2v5*)
+ ;;
+ solaris*)
+ wl='-Wl,'
+ ;;
+ sunos4*)
+ wl='-Qoption ld '
+ ;;
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ wl='-Wl,'
+ ;;
+ sysv4*MP*)
+ ;;
+ unicos*)
+ wl='-Wl,'
+ ;;
+ uts4*)
+ ;;
+ esac
+fi
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
+
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+
+case "$host_os" in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+ case "$host_os" in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ fi
+ ;;
+ amigaos*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we cannot use
+ # them.
+ ld_shlibs=no
+ ;;
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ cygwin* | mingw* | pw32*)
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ netbsd*)
+ ;;
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ sunos4*)
+ hardcode_direct=yes
+ ;;
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ if test "$ld_shlibs" = yes; then
+ # Unlike libtool, we use -rpath here, not --rpath, since the documented
+ # option of GNU ld is called -rpath, not --rpath.
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ fi
+else
+ case "$host_os" in
+ aix3*)
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ else
+ aix_use_runtimelinking=no
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+ fi
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ esac
+ fi
+ # Begin _LT_AC_SYS_LIBPATH_AIX.
+ echo 'int main () { return 0; }' > conftest.c
+ ${CC} ${LDFLAGS} conftest.c -o conftest
+ aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ fi
+ if test -z "$aix_libpath"; then
+ aix_libpath="/usr/lib:/lib"
+ fi
+ rm -f conftest.c conftest
+ # End _LT_AC_SYS_LIBPATH_AIX.
+ if test "$aix_use_runtimelinking" = yes; then
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ else
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ fi
+ fi
+ ;;
+ amigaos*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+ bsdi[45]*)
+ ;;
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ libext=lib
+ ;;
+ darwin* | rhapsody*)
+ hardcode_direct=no
+ if test "$GCC" = yes ; then
+ :
+ else
+ case "$cc_basename" in
+ xlc*)
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+ ;;
+ dgux*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+ freebsd2.2*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ freebsd2*)
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ freebsd* | kfreebsd*-gnu | dragonfly*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ hpux9*)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ hpux10* | hpux11*)
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=no
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=no
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+ irix5* | irix6* | nonstopux*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ netbsd*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ newsos6)
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ openbsd*)
+ hardcode_direct=yes
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ else
+ case "$host_os" in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ osf3*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ osf4* | osf5*)
+ if test "$GCC" = yes; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ # Both cc and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+ sco3.2v5*)
+ ;;
+ solaris*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ sunos4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ sysv4)
+ case $host_vendor in
+ sni)
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ hardcode_direct=no
+ ;;
+ motorola)
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ ;;
+ sysv4.3*)
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ ld_shlibs=yes
+ fi
+ ;;
+ sysv4.2uw2*)
+ hardcode_direct=yes
+ hardcode_minus_L=no
+ ;;
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ ;;
+ sysv5*)
+ hardcode_libdir_flag_spec=
+ ;;
+ uts4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+fi
+
+# Check dynamic linker characteristics
+# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
+libname_spec='lib$name'
+case "$host_os" in
+ aix3*)
+ ;;
+ aix4* | aix5*)
+ ;;
+ amigaos*)
+ ;;
+ beos*)
+ ;;
+ bsdi[45]*)
+ ;;
+ cygwin* | mingw* | pw32*)
+ shrext=.dll
+ ;;
+ darwin* | rhapsody*)
+ shrext=.dylib
+ ;;
+ dgux*)
+ ;;
+ freebsd1*)
+ ;;
+ kfreebsd*-gnu)
+ ;;
+ freebsd*)
+ ;;
+ gnu*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case "$host_cpu" in
+ ia64*)
+ shrext=.so
+ ;;
+ hppa*64*)
+ shrext=.sl
+ ;;
+ *)
+ shrext=.sl
+ ;;
+ esac
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case "$host_os" in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
+ *) libsuff= shlibsuff= ;;
+ esac
+ ;;
+ esac
+ ;;
+ linux*oldld* | linux*aout* | linux*coff*)
+ ;;
+ linux*)
+ ;;
+ knetbsd*-gnu)
+ ;;
+ netbsd*)
+ ;;
+ newsos6)
+ ;;
+ nto-qnx*)
+ ;;
+ openbsd*)
+ ;;
+ os2*)
+ libname_spec='$name'
+ shrext=.dll
+ ;;
+ osf3* | osf4* | osf5*)
+ ;;
+ sco3.2v5*)
+ ;;
+ solaris*)
+ ;;
+ sunos4*)
+ ;;
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ ;;
+ sysv4*MP*)
+ ;;
+ uts4*)
+ ;;
+esac
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
+shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
+escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+
+LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/build-aux/config.sub b/build-aux/config.sub
new file mode 100755
index 0000000..7cee3d6
--- /dev/null
+++ b/build-aux/config.sub
@@ -0,0 +1,1500 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-18'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k \
+ | m32r | m68000 | m68k | m88k | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | msp430 \
+ | ns16k | ns32k \
+ | openrisc | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | s390 | s390x \
+ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* \
+ | m32r-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | msp430-* \
+ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | s390-* | s390x-* \
+ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ mmix*)
+ basic_machine=mmix-knuth
+ os=-mmixware
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nv1)
+ basic_machine=nv1-cray
+ os=-unicosmp
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ or32 | or32-*)
+ basic_machine=or32-unknown
+ os=-coff
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparc | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build-aux/depcomp b/build-aux/depcomp
new file mode 100755
index 0000000..ffcd540
--- /dev/null
+++ b/build-aux/depcomp
@@ -0,0 +1,529 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2005-02-09.22
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+ "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+ stat=$?
+
+ if test -f "$tmpdepfile"; then :
+ else
+ stripped=`echo "$stripped" | sed 's,^.*/,,'`
+ tmpdepfile="$stripped.u"
+ fi
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mecanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/build-aux/install-sh b/build-aux/install-sh
new file mode 100755
index 0000000..1a83534
--- /dev/null
+++ b/build-aux/install-sh
@@ -0,0 +1,323 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2005-02-02.21
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# 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
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c (ignored)
+-d create directories instead of installing files.
+-g GROUP $chgrpprog installed files to GROUP.
+-m MODE $chmodprog installed files to MODE.
+-o USER $chownprog installed files to USER.
+-s $stripprog installed files.
+-t DIRECTORY install into DIRECTORY.
+-T report an error if DSTFILE is a directory.
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t) dstarg=$2
+ shift
+ shift
+ continue;;
+
+ -T) no_target_directory=true
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ *) # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ test -n "$dir_arg$dstarg" && break
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+ break;;
+ esac
+done
+
+if test -z "$1"; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ src=
+
+ if test -d "$dst"; then
+ mkdircmd=:
+ chmodcmd=
+ else
+ mkdircmd=$mkdirprog
+ fi
+ else
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dstarg: Is a directory" >&2
+ exit 1
+ fi
+ dst=$dst/`basename "$src"`
+ fi
+ fi
+
+ # This sed command emulates the dirname command.
+ dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
+
+ # Make sure that the destination directory exists.
+
+ # Skip lots of stat calls in the usual case.
+ if test ! -d "$dstdir"; then
+ defaultIFS='
+ '
+ IFS="${IFS-$defaultIFS}"
+
+ oIFS=$IFS
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+ shift
+ IFS=$oIFS
+
+ pathcomp=
+
+ while test $# -ne 0 ; do
+ pathcomp=$pathcomp$1
+ shift
+ if test ! -d "$pathcomp"; then
+ $mkdirprog "$pathcomp"
+ # mkdir can fail with a `File exist' error in case several
+ # install-sh are creating the directory concurrently. This
+ # is OK.
+ test -d "$pathcomp" || exit
+ fi
+ pathcomp=$pathcomp/
+ done
+ fi
+
+ if test -n "$dir_arg"; then
+ $doit $mkdircmd "$dst" \
+ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+ else
+ dstfile=`basename "$dst"`
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Copy the file name to the temp name.
+ $doit $cpprog "$src" "$dsttmp" &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+ # Now rename the file to the real destination.
+ { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
+ || {
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ if test -f "$dstdir/$dstfile"; then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+ || {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit 1
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+ }
+ }
+ fi || { (exit 1); exit 1; }
+done
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+ (exit 0); exit 0
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/build-aux/mdate-sh b/build-aux/mdate-sh
new file mode 100755
index 0000000..4b2efdf
--- /dev/null
+++ b/build-aux/mdate-sh
@@ -0,0 +1,193 @@
+#!/bin/sh
+# Get modification time of a file or directory and pretty-print it.
+
+scriptversion=2005-02-07.09
+
+# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005 Free Software
+# Foundation, Inc.
+# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No file. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: mdate-sh [--help] [--version] FILE
+
+Pretty-print the modification time of FILE.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "mdate-sh $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Prevent date giving response in another language.
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+LC_TIME=C
+export LC_TIME
+
+save_arg1="$1"
+
+# Find out how to get the extended ls output of a file or directory.
+if ls -L /dev/null 1>/dev/null 2>&1; then
+ ls_command='ls -L -l -d'
+else
+ ls_command='ls -l -d'
+fi
+
+# A `ls -l' line looks as follows on OS/2.
+# drwxrwx--- 0 Aug 11 2001 foo
+# This differs from Unix, which adds ownership information.
+# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
+#
+# To find the date, we split the line on spaces and iterate on words
+# until we find a month. This cannot work with files whose owner is a
+# user named `Jan', or `Feb', etc. However, it's unlikely that `/'
+# will be owned by a user whose name is a month. So we first look at
+# the extended ls output of the root directory to decide how many
+# words should be skipped to get the date.
+
+# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
+set x`ls -l -d /`
+
+# Find which argument is the month.
+month=
+command=
+until test $month
+do
+ shift
+ # Add another shift to the command.
+ command="$command shift;"
+ case $1 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+ esac
+done
+
+# Get the extended ls output of the file or directory.
+set dummy x`eval "$ls_command \"\$save_arg1\""`
+
+# Remove all preceding arguments
+eval $command
+
+# Because of the dummy argument above, month is in $2.
+#
+# On a POSIX system, we should have
+#
+# $# = 5
+# $1 = file size
+# $2 = month
+# $3 = day
+# $4 = year or time
+# $5 = filename
+#
+# On Darwin 7.7.0 and 7.6.0, we have
+#
+# $# = 4
+# $1 = day
+# $2 = month
+# $3 = year or time
+# $4 = filename
+
+# Get the month.
+case $2 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+esac
+
+case $3 in
+ ???*) day=$1;;
+ *) day=$3; shift;;
+esac
+
+# Here we have to deal with the problem that the ls output gives either
+# the time of day or the year.
+case $3 in
+ *:*) set `date`; eval year=\$$#
+ case $2 in
+ Jan) nummonthtod=1;;
+ Feb) nummonthtod=2;;
+ Mar) nummonthtod=3;;
+ Apr) nummonthtod=4;;
+ May) nummonthtod=5;;
+ Jun) nummonthtod=6;;
+ Jul) nummonthtod=7;;
+ Aug) nummonthtod=8;;
+ Sep) nummonthtod=9;;
+ Oct) nummonthtod=10;;
+ Nov) nummonthtod=11;;
+ Dec) nummonthtod=12;;
+ esac
+ # For the first six month of the year the time notation can also
+ # be used for files modified in the last year.
+ if (expr $nummonth \> $nummonthtod) > /dev/null;
+ then
+ year=`expr $year - 1`
+ fi;;
+ *) year=$3;;
+esac
+
+# The result.
+echo $day $month $year
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/build-aux/missing b/build-aux/missing
new file mode 100755
index 0000000..09edd88
--- /dev/null
+++ b/build-aux/missing
@@ -0,0 +1,357 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2005-02-08.22
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case "$1" in
+ lex|yacc)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/build-aux/texinfo.tex b/build-aux/texinfo.tex
new file mode 100644
index 0000000..58bea4d
--- /dev/null
+++ b/build-aux/texinfo.tex
@@ -0,0 +1,7086 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+%
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{2005-01-30.17}
+%
+% Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
+% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software
+% Foundation, Inc.
+%
+% This texinfo.tex file is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License as
+% published by the Free Software Foundation; either version 2, or (at
+% your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this texinfo.tex file; see the file COPYING. If not, write
+% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+% Boston, MA 02111-1307, USA.
+%
+% As a special exception, when this file is read by TeX when processing
+% a Texinfo source document, you may use the result without
+% restriction. (This has been our intent since Texinfo was invented.)
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+% http://www.gnu.org/software/texinfo/ (the Texinfo home page), or
+% ftp://tug.org/tex/texinfo.tex
+% (and all CTAN mirrors, see http://www.ctan.org).
+% The texinfo.tex in any given distribution could well be out
+% of date, so if that's what you're using, please check.
+%
+% Send bug reports to bug-texinfo@gnu.org. Please include including a
+% complete document in each bug report with which we can reproduce the
+% problem. Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution. For a simple
+% manual foo.texi, however, you can get away with this:
+% tex foo.texi
+% texindex foo.??
+% tex foo.texi
+% tex foo.texi
+% dvips foo.dvi -o # or whatever; this makes foo.ps.
+% The extra TeX runs get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages, to some
+% extent. You can get the existing language-specific files from the
+% full Texinfo distribution.
+%
+% The GNU Texinfo home page is http://www.gnu.org/software/texinfo.
+
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+ \catcode`+=\active \catcode`\_=\active}
+
+\message{Basics,}
+\chardef\other=12
+
+% We never want plain's \outer definition of \+ in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+% Save some plain tex macros whose names we will redefine.
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexfootnote=\footnote
+\let\ptexgtr=>
+\let\ptexhat=^
+\let\ptexi=\i
+\let\ptexindent=\indent
+\let\ptexinsert=\insert
+\let\ptexlbrace=\{
+\let\ptexless=<
+\let\ptexnewwrite\newwrite
+\let\ptexnoindent=\noindent
+\let\ptexplus=+
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexstar=\*
+\let\ptext=\t
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+ \let\linenumber = \empty % Pre-3.0.
+\else
+ \def\linenumber{l.\the\inputlineno:\space}
+\fi
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi
+\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi
+
+% In some macros, we cannot use the `\? notation---the left quote is
+% in some cases the escape char.
+\chardef\colonChar = `\:
+\chardef\commaChar = `\,
+\chardef\dotChar = `\.
+\chardef\exclamChar= `\!
+\chardef\questChar = `\?
+\chardef\semiChar = `\;
+\chardef\underChar = `\_
+
+\chardef\spaceChar = `\ %
+\chardef\spacecat = 10
+\def\spaceisspace{\catcode\spaceChar=\spacecat}
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+% The following is used inside several \edef's.
+\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname}
+
+% Hyphenation fixes.
+\hyphenation{
+ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script
+ ap-pen-dix bit-map bit-maps
+ data-base data-bases eshell fall-ing half-way long-est man-u-script
+ man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm
+ par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces
+ spell-ing spell-ings
+ stand-alone strong-est time-stamp time-stamps which-ever white-space
+ wide-spread wrap-around
+}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen\bindingoffset
+\newdimen\normaloffset
+\newdimen\pagewidth \newdimen\pageheight
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+% @| inserts a changebar to the left of the current line. It should
+% surround any changed text. This approach does *not* work if the
+% change spans more than two lines of output. To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+ % \vadjust can only be used in horizontal mode.
+ \leavevmode
+ %
+ % Append this vertical mode material after the current line in the output.
+ \vadjust{%
+ % We want to insert a rule with the height and depth of the current
+ % leading; that is exactly what \strutbox is supposed to record.
+ \vskip-\baselineskip
+ %
+ % \vadjust-items are inserted at the left edge of the type. So
+ % the \llap here moves out into the left-hand margin.
+ \llap{%
+ %
+ % For a thicker or thinner bar, change the `1pt'.
+ \vrule height\baselineskip width1pt
+ %
+ % This is the space between the bar and the text.
+ \hskip 12pt
+ }%
+ }%
+}
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal. We don't just call \tracingall here,
+% since that produces some useless output on the terminal. We also make
+% some effort to order the tracing commands to reduce output in the log
+% file; cf. trace.sty in LaTeX.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{%
+ \tracingstats2
+ \tracingpages1
+ \tracinglostchars2 % 2 gives us more in etex
+ \tracingparagraphs1
+ \tracingoutput1
+ \tracingmacros2
+ \tracingrestores1
+ \showboxbreadth\maxdimen \showboxdepth\maxdimen
+ \ifx\eTeXversion\undefined\else % etex gives us more logging
+ \tracingscantokens1
+ \tracingifs1
+ \tracinggroups1
+ \tracingnesting2
+ \tracingassigns1
+ \fi
+ \tracingcommands3 % 3 gives us more in etex
+ \errorcontextlines16
+}%
+
+% add check for \lastpenalty to plain's definitions. If the last thing
+% we did was a \nobreak, we don't want to insert more space.
+%
+\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount
+ \removelastskip\penalty-50\smallskip\fi\fi}
+\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount
+ \removelastskip\penalty-100\medskip\fi\fi}
+\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount
+ \removelastskip\penalty-200\bigskip\fi\fi}
+
+% For @cropmarks command.
+% Do @cropmarks to get crop marks.
+%
+\newif\ifcropmarks
+\let\cropmarks = \cropmarkstrue
+%
+% Dimensions to add cropmarks at corners.
+% Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\cornerlong \cornerlong=1pc
+\newdimen\cornerthick \cornerthick=.3pt
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Main output routine.
+\chardef\PAGE = 255
+\output = {\onepageout{\pagecontents\PAGE}}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% \onepageout takes a vbox as an argument. Note that \pagecontents
+% does insertions, but you have to call it yourself.
+\def\onepageout#1{%
+ \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi
+ %
+ \ifodd\pageno \advance\hoffset by \bindingoffset
+ \else \advance\hoffset by -\bindingoffset\fi
+ %
+ % Do this outside of the \shipout so @code etc. will be expanded in
+ % the headline as they should be, not taken literally (outputting ''code).
+ \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}%
+ \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}%
+ %
+ {%
+ % Have to do this stuff outside the \shipout because we want it to
+ % take effect in \write's, yet the group defined by the \vbox ends
+ % before the \shipout runs.
+ %
+ \escapechar = `\\ % use backslash in output files.
+ \indexdummies % don't expand commands in the output.
+ \normalturnoffactive % \ in index entries must not stay \, e.g., if
+ % the page break happens to be in the middle of an example.
+ \shipout\vbox{%
+ % Do this early so pdf references go to the beginning of the page.
+ \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi
+ %
+ \ifcropmarks \vbox to \outervsize\bgroup
+ \hsize = \outerhsize
+ \vskip-\topandbottommargin
+ \vtop to0pt{%
+ \line{\ewtop\hfil\ewtop}%
+ \nointerlineskip
+ \line{%
+ \vbox{\moveleft\cornerthick\nstop}%
+ \hfill
+ \vbox{\moveright\cornerthick\nstop}%
+ }%
+ \vss}%
+ \vskip\topandbottommargin
+ \line\bgroup
+ \hfil % center the page within the outer (page) hsize.
+ \ifodd\pageno\hskip\bindingoffset\fi
+ \vbox\bgroup
+ \fi
+ %
+ \unvbox\headlinebox
+ \pagebody{#1}%
+ \ifdim\ht\footlinebox > 0pt
+ % Only leave this space if the footline is nonempty.
+ % (We lessened \vsize for it in \oddfootingxxx.)
+ % The \baselineskip=24pt in plain's \makefootline has no effect.
+ \vskip 2\baselineskip
+ \unvbox\footlinebox
+ \fi
+ %
+ \ifcropmarks
+ \egroup % end of \vbox\bgroup
+ \hfil\egroup % end of (centering) \line\bgroup
+ \vskip\topandbottommargin plus1fill minus1fill
+ \boxmaxdepth = \cornerthick
+ \vbox to0pt{\vss
+ \line{%
+ \vbox{\moveleft\cornerthick\nsbot}%
+ \hfill
+ \vbox{\moveright\cornerthick\nsbot}%
+ }%
+ \nointerlineskip
+ \line{\ewbot\hfil\ewbot}%
+ }%
+ \egroup % \vbox from first cropmarks clause
+ \fi
+ }% end of \shipout\vbox
+ }% end of group with \normalturnoffactive
+ \advancepageno
+ \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+ \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Here are the rules for the cropmarks. Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+ {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+ {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1. The argument is the rest of
+% the input line (except we remove a trailing comment). #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg{\parseargusing{}}
+\def\parseargusing#1#2{%
+ \def\next{#2}%
+ \begingroup
+ \obeylines
+ \spaceisspace
+ #1%
+ \parseargline\empty% Insert the \empty token, see \finishparsearg below.
+}
+
+{\obeylines %
+ \gdef\parseargline#1^^M{%
+ \endgroup % End of the group started in \parsearg.
+ \argremovecomment #1\comment\ArgTerm%
+ }%
+}
+
+% First remove any @comment, then any @c comment.
+\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm}
+\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm}
+
+% Each occurence of `\^^M' or `<space>\^^M' is replaced by a single space.
+%
+% \argremovec might leave us with trailing space, e.g.,
+% @end itemize @c foo
+% This space token undergoes the same procedure and is eventually removed
+% by \finishparsearg.
+%
+\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M}
+\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M}
+\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{%
+ \def\temp{#3}%
+ \ifx\temp\empty
+ % We cannot use \next here, as it holds the macro to run;
+ % thus we reuse \temp.
+ \let\temp\finishparsearg
+ \else
+ \let\temp\argcheckspaces
+ \fi
+ % Put the space token in:
+ \temp#1 #3\ArgTerm
+}
+
+% If a _delimited_ argument is enclosed in braces, they get stripped; so
+% to get _exactly_ the rest of the line, we had to prevent such situation.
+% We prepended an \empty token at the very beginning and we expand it now,
+% just before passing the control to \next.
+% (Similarily, we have to think about #3 of \argcheckspacesY above: it is
+% either the null string, or it ends with \^^M---thus there is no danger
+% that a pair of braces would be stripped.
+%
+% But first, we have to remove the trailing space token.
+%
+\def\finishparsearg#1 \ArgTerm{\expandafter\next\expandafter{#1}}
+
+% \parseargdef\foo{...}
+% is roughly equivalent to
+% \def\foo{\parsearg\Xfoo}
+% \def\Xfoo#1{...}
+%
+% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my
+% favourite TeX trick. --kasal, 16nov03
+
+\def\parseargdef#1{%
+ \expandafter \doparseargdef \csname\string#1\endcsname #1%
+}
+\def\doparseargdef#1#2{%
+ \def#2{\parsearg#1}%
+ \def#1##1%
+}
+
+% Several utility definitions with active space:
+{
+ \obeyspaces
+ \gdef\obeyedspace{ }
+
+ % Make each space character in the input produce a normal interword
+ % space in the output. Don't allow a line break at this space, as this
+ % is used only in environments like @example, where each line of input
+ % should produce a line of output anyway.
+ %
+ \gdef\sepspaces{\obeyspaces\let =\tie}
+
+ % If an index command is used in an @example environment, any spaces
+ % therein should become regular spaces in the raw index file, not the
+ % expansion of \tie (\leavevmode \penalty \@M \ ).
+ \gdef\unsepspaces{\let =\space}
+}
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+% Define the framework for environments in texinfo.tex. It's used like this:
+%
+% \envdef\foo{...}
+% \def\Efoo{...}
+%
+% It's the responsibility of \envdef to insert \begingroup before the
+% actual body; @end closes the group after calling \Efoo. \envdef also
+% defines \thisenv, so the current environment is known; @end checks
+% whether the environment name matches. The \checkenv macro can also be
+% used to check whether the current environment is the one expected.
+%
+% Non-false conditionals (@iftex, @ifset) don't fit into this, so they
+% are not treated as enviroments; they don't open a group. (The
+% implementation of @end takes care not to call \endgroup in this
+% special case.)
+
+
+% At runtime, environments start with this:
+\def\startenvironment#1{\begingroup\def\thisenv{#1}}
+% initialize
+\let\thisenv\empty
+
+% ... but they get defined via ``\envdef\foo{...}'':
+\long\def\envdef#1#2{\def#1{\startenvironment#1#2}}
+\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}}
+
+% Check whether we're in the right environment:
+\def\checkenv#1{%
+ \def\temp{#1}%
+ \ifx\thisenv\temp
+ \else
+ \badenverr
+ \fi
+}
+
+% Evironment mismatch, #1 expected:
+\def\badenverr{%
+ \errhelp = \EMsimple
+ \errmessage{This command can appear only \inenvironment\temp,
+ not \inenvironment\thisenv}%
+}
+\def\inenvironment#1{%
+ \ifx#1\empty
+ out of any environment%
+ \else
+ in environment \expandafter\string#1%
+ \fi
+}
+
+% @end foo executes the definition of \Efoo.
+% But first, it executes a specialized version of \checkenv
+%
+\parseargdef\end{%
+ \if 1\csname iscond.#1\endcsname
+ \else
+ % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03
+ \expandafter\checkenv\csname#1\endcsname
+ \csname E#1\endcsname
+ \endgroup
+ \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt\char64}}
+
+% This is turned off because it was never documented
+% and you can use @w{...} around a quote to suppress ligatures.
+%% Define @` and @' to be the same as ` and '
+%% but suppressing ligatures.
+%\def\`{{`}}
+%\def\'{{'}}
+
+% Used to generate quoted braces.
+\def\mylbrace {{\tt\char123}}
+\def\myrbrace {{\tt\char125}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+\begingroup
+ % Definitions to produce \{ and \} commands for indices,
+ % and @{ and @} for the aux file.
+ \catcode`\{ = \other \catcode`\} = \other
+ \catcode`\[ = 1 \catcode`\] = 2
+ \catcode`\! = 0 \catcode`\\ = \other
+ !gdef!lbracecmd[\{]%
+ !gdef!rbracecmd[\}]%
+ !gdef!lbraceatcmd[@{]%
+ !gdef!rbraceatcmd[@}]%
+!endgroup
+
+% @comma{} to avoid , parsing problems.
+\let\comma = ,
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H.
+\let\, = \c
+\let\dotaccent = \.
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \t
+\let\ubaraccent = \b
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown @ordf @ordm
+% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+ \def\temp{#1}%
+ \ifx\temp\imacro \ptexi
+ \else\ifx\temp\jmacro \j
+ \else \errmessage{@dotless can be used only with i or j}%
+ \fi\fi
+}
+
+% The \TeX{} logo, as in plain, but resetting the spacing so that a
+% period following counts as ending a sentence. (Idea found in latex.)
+%
+\edef\TeX{\TeX \spacefactor=1000 }
+
+% @LaTeX{} logo. Not quite the same results as the definition in
+% latex.ltx, since we use a different font for the raised A; it's most
+% convenient for us to use an explicitly smaller font, rather than using
+% the \scriptstyle font (since we don't reset \scriptstyle and
+% \scriptscriptstyle).
+%
+\def\LaTeX{%
+ L\kern-.36em
+ {\setbox0=\hbox{T}%
+ \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}%
+ \kern-.15em
+ \TeX
+}
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @/ allows a line break.
+\let\/=\allowbreak
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=3000 }
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=3000 }
+
+% @w prevents a word break. Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox. We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line. According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0). If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+% Another complication is that the group might be very large. This can
+% cause the glue on the previous page to be unduly stretched, because it
+% does not have much material. In this case, it's better to add an
+% explicit \vfill so that the extra space is at the bottom. The
+% threshold for doing this is if the group is more than \vfilllimit
+% percent of a page (\vfilllimit can be changed inside of @tex).
+%
+\newbox\groupbox
+\def\vfilllimit{0.7}
+%
+\envdef\group{%
+ \ifnum\catcode`\^^M=\active \else
+ \errhelp = \groupinvalidhelp
+ \errmessage{@group invalid in context where filling is enabled}%
+ \fi
+ \startsavinginserts
+ %
+ \setbox\groupbox = \vtop\bgroup
+ % Do @comment since we are called inside an environment such as
+ % @example, where each end-of-line in the input causes an
+ % end-of-line in the output. We don't want the end-of-line after
+ % the `@group' to put extra space in the output. Since @group
+ % should appear on a line by itself (according to the Texinfo
+ % manual), we don't worry about eating any user text.
+ \comment
+}
+%
+% The \vtop produces a box with normal height and large depth; thus, TeX puts
+% \baselineskip glue before it, and (when the next line of text is done)
+% \lineskip glue after it. Thus, space below is not quite equal to space
+% above. But it's pretty close.
+\def\Egroup{%
+ % To get correct interline space between the last line of the group
+ % and the first line afterwards, we have to propagate \prevdepth.
+ \endgraf % Not \par, as it may have been set to \lisppar.
+ \global\dimen1 = \prevdepth
+ \egroup % End the \vtop.
+ % \dimen0 is the vertical size of the group's box.
+ \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox
+ % \dimen2 is how much space is left on the page (more or less).
+ \dimen2 = \pageheight \advance\dimen2 by -\pagetotal
+ % if the group doesn't fit on the current page, and it's a big big
+ % group, force a page break.
+ \ifdim \dimen0 > \dimen2
+ \ifdim \pagetotal < \vfilllimit\pageheight
+ \page
+ \fi
+ \fi
+ \box\groupbox
+ \prevdepth = \dimen1
+ \checkinserts
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil \mil=0.001in
+
+% Old definition--didn't work.
+%\parseargdef\need{\par %
+%% This method tries to make TeX break the page naturally
+%% if the depth of the box does not fit.
+%{\baselineskip=0pt%
+%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak
+%\prevdepth=-1000pt
+%}}
+
+\parseargdef\need{%
+ % Ensure vertical mode, so we don't make a big box in the middle of a
+ % paragraph.
+ \par
+ %
+ % If the @need value is less than one line space, it's useless.
+ \dimen0 = #1\mil
+ \dimen2 = \ht\strutbox
+ \advance\dimen2 by \dp\strutbox
+ \ifdim\dimen0 > \dimen2
+ %
+ % Do a \strut just to make the height of this box be normal, so the
+ % normal leading is inserted relative to the preceding line.
+ % And a page break here is fine.
+ \vtop to #1\mil{\strut\vfil}%
+ %
+ % TeX does not even consider page breaks if a penalty added to the
+ % main vertical list is 10000 or more. But in order to see if the
+ % empty box we just added fits on the page, we must make it consider
+ % page breaks. On the other hand, we don't want to actually break the
+ % page after the empty box. So we use a penalty of 9999.
+ %
+ % There is an extremely small chance that TeX will actually break the
+ % page at this \penalty, if there are no other feasible breakpoints in
+ % sight. (If the user is using lots of big @group commands, which
+ % almost-but-not-quite fill up a page, TeX will have a hard time doing
+ % good page breaking, for example.) However, I could not construct an
+ % example where a page broke at this \penalty; if it happens in a real
+ % document, then we can reconsider our strategy.
+ \penalty9999
+ %
+ % Back up by the size of the box, whether we did a page break or not.
+ \kern -#1\mil
+ %
+ % Do not allow a page break right after this kern.
+ \nobreak
+ \fi
+}
+
+% @br forces paragraph break (and is undocumented).
+
+\let\br = \par
+
+% @page forces the start of a new page.
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}
+
+% This defn is used inside nofill environments such as @example.
+\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount
+ \leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current
+% paragraph. For more general purposes, use the \margin insertion
+% class. WHICH is `l' or `r'.
+%
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+%
+\def\doinmargin#1#2{\strut\vadjust{%
+ \nobreak
+ \kern-\strutdepth
+ \vtop to \strutdepth{%
+ \baselineskip=\strutdepth
+ \vss
+ % if you have multiple lines of stuff to put here, you'll need to
+ % make the vbox yourself of the appropriate size.
+ \ifx#1l%
+ \llap{\ignorespaces #2\hskip\inmarginspacing}%
+ \else
+ \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}%
+ \fi
+ \null
+ }%
+}}
+\def\inleftmargin{\doinmargin l}
+\def\inrightmargin{\doinmargin r}
+%
+% @inmargin{TEXT [, RIGHT-TEXT]}
+% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right;
+% else use TEXT for both).
+%
+\def\inmargin#1{\parseinmargin #1,,\finish}
+\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing.
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0 > 0pt
+ \def\lefttext{#1}% have both texts
+ \def\righttext{#2}%
+ \else
+ \def\lefttext{#1}% have only one text
+ \def\righttext{#1}%
+ \fi
+ %
+ \ifodd\pageno
+ \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin
+ \else
+ \def\temp{\inleftmargin\lefttext}%
+ \fi
+ \temp
+}
+
+% @include file insert text of that file as input.
+%
+\def\include{\parseargusing\filenamecatcodes\includezzz}
+\def\includezzz#1{%
+ \pushthisfilestack
+ \def\thisfile{#1}%
+ {%
+ \makevalueexpandable
+ \def\temp{\input #1 }%
+ \expandafter
+ }\temp
+ \popthisfilestack
+}
+\def\filenamecatcodes{%
+ \catcode`\\=\other
+ \catcode`~=\other
+ \catcode`^=\other
+ \catcode`_=\other
+ \catcode`|=\other
+ \catcode`<=\other
+ \catcode`>=\other
+ \catcode`+=\other
+ \catcode`-=\other
+}
+
+\def\pushthisfilestack{%
+ \expandafter\pushthisfilestackX\popthisfilestack\StackTerm
+}
+\def\pushthisfilestackX{%
+ \expandafter\pushthisfilestackY\thisfile\StackTerm
+}
+\def\pushthisfilestackY #1\StackTerm #2\StackTerm {%
+ \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}%
+}
+
+\def\popthisfilestack{\errthisfilestackempty}
+\def\errthisfilestackempty{\errmessage{Internal error:
+ the stack of filenames is empty.}}
+
+\def\thisfile{}
+
+% @center line
+% outputs that line, centered.
+%
+\parseargdef\center{%
+ \ifhmode
+ \let\next\centerH
+ \else
+ \let\next\centerV
+ \fi
+ \next{\hfil \ignorespaces#1\unskip \hfil}%
+}
+\def\centerH#1{%
+ {%
+ \hfil\break
+ \advance\hsize by -\leftskip
+ \advance\hsize by -\rightskip
+ \line{#1}%
+ \break
+ }%
+}
+\def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}}
+
+% @sp n outputs n lines of vertical space
+
+\parseargdef\sp{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore is another way to write a comment
+
+\def\comment{\begingroup \catcode`\^^M=\other%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\commentxxx}
+{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}}
+
+\let\c=\comment
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% NCHARS can also be the word `asis' or `none'.
+% We cannot feasibly implement @paragraphindent asis, though.
+%
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\parseargdef\paragraphindent{%
+ \def\temp{#1}%
+ \ifx\temp\asisword
+ \else
+ \ifx\temp\noneword
+ \defaultparindent = 0pt
+ \else
+ \defaultparindent = #1em
+ \fi
+ \fi
+ \parindent = \defaultparindent
+}
+
+% @exampleindent NCHARS
+% We'll use ems for NCHARS like @paragraphindent.
+% It seems @exampleindent asis isn't necessary, but
+% I preserve it to make it similar to @paragraphindent.
+\parseargdef\exampleindent{%
+ \def\temp{#1}%
+ \ifx\temp\asisword
+ \else
+ \ifx\temp\noneword
+ \lispnarrowing = 0pt
+ \else
+ \lispnarrowing = #1em
+ \fi
+ \fi
+}
+
+% @firstparagraphindent WORD
+% If WORD is `none', then suppress indentation of the first paragraph
+% after a section heading. If WORD is `insert', then do indent at such
+% paragraphs.
+%
+% The paragraph indentation is suppressed or not by calling
+% \suppressfirstparagraphindent, which the sectioning commands do.
+% We switch the definition of this back and forth according to WORD.
+% By default, we suppress indentation.
+%
+\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent}
+\def\insertword{insert}
+%
+\parseargdef\firstparagraphindent{%
+ \def\temp{#1}%
+ \ifx\temp\noneword
+ \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent
+ \else\ifx\temp\insertword
+ \let\suppressfirstparagraphindent = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @firstparagraphindent option `\temp'}%
+ \fi\fi
+}
+
+% Here is how we actually suppress indentation. Redefine \everypar to
+% \kern backwards by \parindent, and then reset itself to empty.
+%
+% We also make \indent itself not actually do anything until the next
+% paragraph.
+%
+\gdef\dosuppressfirstparagraphindent{%
+ \gdef\indent{%
+ \restorefirstparagraphindent
+ \indent
+ }%
+ \gdef\noindent{%
+ \restorefirstparagraphindent
+ \noindent
+ }%
+ \global\everypar = {%
+ \kern -\parindent
+ \restorefirstparagraphindent
+ }%
+}
+
+\gdef\restorefirstparagraphindent{%
+ \global \let \indent = \ptexindent
+ \global \let \noindent = \ptexnoindent
+ \global \everypar = {}%
+}
+
+
+% @asis just yields its argument. Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math outputs its argument in math mode.
+%
+% One complication: _ usually means subscripts, but it could also mean
+% an actual _ character, as in @math{@var{some_variable} + 1}. So make
+% _ active, and distinguish by seeing if the current family is \slfam,
+% which is what @var uses.
+{
+ \catcode\underChar = \active
+ \gdef\mathunderscore{%
+ \catcode\underChar=\active
+ \def_{\ifnum\fam=\slfam \_\else\sb\fi}%
+ }
+}
+% Another complication: we want \\ (and @\) to output a \ character.
+% FYI, plain.tex uses \\ as a temporary control sequence (why?), but
+% this is not advertised and we don't care. Texinfo does not
+% otherwise define @\.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+ \tex
+ \mathunderscore
+ \let\\ = \mathbackslash
+ \mathactive
+ $\finishmath
+}
+\def\finishmath#1{#1$\endgroup} % Close the group opened by \tex.
+
+% Some active characters (such as <) are spaced differently in math.
+% We have to reset their definitions in case the @math was an argument
+% to a command which sets the catcodes (such as @item or @section).
+%
+{
+ \catcode`^ = \active
+ \catcode`< = \active
+ \catcode`> = \active
+ \catcode`+ = \active
+ \gdef\mathactive{%
+ \let^ = \ptexhat
+ \let< = \ptexless
+ \let> = \ptexgtr
+ \let+ = \ptexplus
+ }
+}
+
+% @bullet and @minus need the same treatment as @math, just above.
+\def\bullet{$\ptexbullet$}
+\def\minus{$-$}
+
+% @dots{} outputs an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in a typewriter
+% font as three actual period characters.
+%
+\def\dots{%
+ \leavevmode
+ \hbox to 1.5em{%
+ \hskip 0pt plus 0.25fil
+ .\hfil.\hfil.%
+ \hskip 0pt plus 0.5fil
+ }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+ \dots
+ \spacefactor=3000
+}
+
+% @comma{} is so commas can be inserted into text without messing up
+% Texinfo's parsing.
+%
+\let\comma = ,
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate (before @setfilename).
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+ \fixbackslash % Turn off hack to swallow `\input texinfo'.
+ \iflinks
+ \tryauxfile
+ % Open the new aux file. TeX will close it automatically at exit.
+ \immediate\openout\auxfile=\jobname.aux
+ \fi % \openindices needs to do some work in any case.
+ \openindices
+ \let\setfilename=\comment % Ignore extra @setfilename cmds.
+ %
+ % If texinfo.cnf is present on the system, read it.
+ % Useful for site-wide @afourpaper, etc.
+ \openin 1 texinfo.cnf
+ \ifeof 1 \else \input texinfo.cnf \fi
+ \closein 1
+ %
+ \comment % Ignore the actual filename.
+}
+
+% Called from \setfilename.
+%
+\def\openindices{%
+ \newindex{cp}%
+ \newcodeindex{fn}%
+ \newcodeindex{vr}%
+ \newcodeindex{tp}%
+ \newcodeindex{ky}%
+ \newcodeindex{pg}%
+}
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{pdf,}
+% adobe `portable' document format
+\newcount\tempnum
+\newcount\lnkcount
+\newtoks\filename
+\newcount\filenamelength
+\newcount\pgn
+\newtoks\toksA
+\newtoks\toksB
+\newtoks\toksC
+\newtoks\toksD
+\newbox\boxA
+\newcount\countA
+\newif\ifpdf
+\newif\ifpdfmakepagedest
+
+% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
+% can be set). So we test for \relax and 0 as well as \undefined,
+% borrowed from ifpdf.sty.
+\ifx\pdfoutput\undefined
+\else
+ \ifx\pdfoutput\relax
+ \else
+ \ifcase\pdfoutput
+ \else
+ \pdftrue
+ \fi
+ \fi
+\fi
+%
+\ifpdf
+ \input pdfcolor
+ \pdfcatalog{/PageMode /UseOutlines}%
+ \def\dopdfimage#1#2#3{%
+ \def\imagewidth{#2}%
+ \def\imageheight{#3}%
+ % without \immediate, pdftex seg faults when the same image is
+ % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.)
+ \ifnum\pdftexversion < 14
+ \immediate\pdfimage
+ \else
+ \immediate\pdfximage
+ \fi
+ \ifx\empty\imagewidth\else width \imagewidth \fi
+ \ifx\empty\imageheight\else height \imageheight \fi
+ \ifnum\pdftexversion<13
+ #1.pdf%
+ \else
+ {#1.pdf}%
+ \fi
+ \ifnum\pdftexversion < 14 \else
+ \pdfrefximage \pdflastximage
+ \fi}
+ \def\pdfmkdest#1{{%
+ % We have to set dummies so commands such as @code in a section title
+ % aren't expanded.
+ \atdummies
+ \normalturnoffactive
+ \pdfdest name{#1} xyz%
+ }}
+ \def\pdfmkpgn#1{#1}
+ \let\linkcolor = \Blue % was Cyan, but that seems light?
+ \def\endlink{\Black\pdfendlink}
+ % Adding outlines to PDF; macros for calculating structure of outlines
+ % come from Petr Olsak
+ \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+ \else \csname#1\endcsname \fi}
+ \def\advancenumber#1{\tempnum=\expnumber{#1}\relax
+ \advance\tempnum by 1
+ \expandafter\xdef\csname#1\endcsname{\the\tempnum}}
+ %
+ % #1 is the section text. #2 is the pdf expression for the number
+ % of subentries (or empty, for subsubsections). #3 is the node
+ % text, which might be empty if this toc entry had no
+ % corresponding node. #4 is the page number.
+ %
+ \def\dopdfoutline#1#2#3#4{%
+ % Generate a link to the node text if that exists; else, use the
+ % page number. We could generate a destination for the section
+ % text in the case where a section has no node, but it doesn't
+ % seem worthwhile, since most documents are normally structured.
+ \def\pdfoutlinedest{#3}%
+ \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}\fi
+ %
+ \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{#1}%
+ }
+ %
+ \def\pdfmakeoutlines{%
+ \begingroup
+ % Thanh's hack / proper braces in bookmarks
+ \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace
+ \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace
+ %
+ % Read toc silently, to get counts of subentries for \pdfoutline.
+ \def\numchapentry##1##2##3##4{%
+ \def\thischapnum{##2}%
+ \def\thissecnum{0}%
+ \def\thissubsecnum{0}%
+ }%
+ \def\numsecentry##1##2##3##4{%
+ \advancenumber{chap\thischapnum}%
+ \def\thissecnum{##2}%
+ \def\thissubsecnum{0}%
+ }%
+ \def\numsubsecentry##1##2##3##4{%
+ \advancenumber{sec\thissecnum}%
+ \def\thissubsecnum{##2}%
+ }%
+ \def\numsubsubsecentry##1##2##3##4{%
+ \advancenumber{subsec\thissubsecnum}%
+ }%
+ \def\thischapnum{0}%
+ \def\thissecnum{0}%
+ \def\thissubsecnum{0}%
+ %
+ % use \def rather than \let here because we redefine \chapentry et
+ % al. a second time, below.
+ \def\appentry{\numchapentry}%
+ \def\appsecentry{\numsecentry}%
+ \def\appsubsecentry{\numsubsecentry}%
+ \def\appsubsubsecentry{\numsubsubsecentry}%
+ \def\unnchapentry{\numchapentry}%
+ \def\unnsecentry{\numsecentry}%
+ \def\unnsubsecentry{\numsubsecentry}%
+ \def\unnsubsubsecentry{\numsubsubsecentry}%
+ \input \jobname.toc
+ %
+ % Read toc second time, this time actually producing the outlines.
+ % The `-' means take the \expnumber as the absolute number of
+ % subentries, which we calculated on our first read of the .toc above.
+ %
+ % We use the node names as the destinations.
+ \def\numchapentry##1##2##3##4{%
+ \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+ \def\numsecentry##1##2##3##4{%
+ \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}%
+ \def\numsubsecentry##1##2##3##4{%
+ \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}%
+ \def\numsubsubsecentry##1##2##3##4{% count is always zero
+ \dopdfoutline{##1}{}{##3}{##4}}%
+ %
+ % PDF outlines are displayed using system fonts, instead of
+ % document fonts. Therefore we cannot use special characters,
+ % since the encoding is unknown. For example, the eogonek from
+ % Latin 2 (0xea) gets translated to a | character. Info from
+ % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100.
+ %
+ % xx to do this right, we have to translate 8-bit characters to
+ % their "best" equivalent, based on the @documentencoding. Right
+ % now, I guess we'll just let the pdf reader have its way.
+ \indexnofonts
+ \turnoffactive
+ \input \jobname.toc
+ \endgroup
+ }
+ %
+ \def\makelinks #1,{%
+ \def\params{#1}\def\E{END}%
+ \ifx\params\E
+ \let\nextmakelinks=\relax
+ \else
+ \let\nextmakelinks=\makelinks
+ \ifnum\lnkcount>0,\fi
+ \picknum{#1}%
+ \startlink attr{/Border [0 0 0]}
+ goto name{\pdfmkpgn{\the\pgn}}%
+ \linkcolor #1%
+ \advance\lnkcount by 1%
+ \endlink
+ \fi
+ \nextmakelinks
+ }
+ \def\picknum#1{\expandafter\pn#1}
+ \def\pn#1{%
+ \def\p{#1}%
+ \ifx\p\lbrace
+ \let\nextpn=\ppn
+ \else
+ \let\nextpn=\ppnn
+ \def\first{#1}
+ \fi
+ \nextpn
+ }
+ \def\ppn#1{\pgn=#1\gobble}
+ \def\ppnn{\pgn=\first}
+ \def\pdfmklnk#1{\lnkcount=0\makelinks #1,END,}
+ \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+ \ifx\PP\D\let\nextsp\relax
+ \else\let\nextsp\skipspaces
+ \ifx\p\space\else\addtokens{\filename}{\PP}%
+ \advance\filenamelength by 1
+ \fi
+ \fi
+ \nextsp}
+ \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax}
+ \ifnum\pdftexversion < 14
+ \let \startlink \pdfannotlink
+ \else
+ \let \startlink \pdfstartlink
+ \fi
+ \def\pdfurl#1{%
+ \begingroup
+ \normalturnoffactive\def\@{@}%
+ \makevalueexpandable
+ \leavevmode\Red
+ \startlink attr{/Border [0 0 0]}%
+ user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+ \endgroup}
+ \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+ \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+ \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+ \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+ \def\maketoks{%
+ \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+ \ifx\first0\adn0
+ \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+ \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+ \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+ \else
+ \ifnum0=\countA\else\makelink\fi
+ \ifx\first.\let\next=\done\else
+ \let\next=\maketoks
+ \addtokens{\toksB}{\the\toksD}
+ \ifx\first,\addtokens{\toksB}{\space}\fi
+ \fi
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \next}
+ \def\makelink{\addtokens{\toksB}%
+ {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+ \def\pdflink#1{%
+ \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}}
+ \linkcolor #1\endlink}
+ \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+\else
+ \let\pdfmkdest = \gobble
+ \let\pdfurl = \gobble
+ \let\endlink = \relax
+ \let\linkcolor = \relax
+ \let\pdfmakeoutlines = \relax
+\fi % \ifx\pdfoutput
+
+
+\message{fonts,}
+
+% Change the current font style to #1, remembering it in \curfontstyle.
+% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
+% italics, not bold italics.
+%
+\def\setfontstyle#1{%
+ \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
+ \csname ten#1\endcsname % change the current font
+}
+
+% Select #1 fonts with the current style.
+%
+\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname}
+
+\def\rm{\fam=0 \setfontstyle{rm}}
+\def\it{\fam=\itfam \setfontstyle{it}}
+\def\sl{\fam=\slfam \setfontstyle{sl}}
+\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf.
+\newfam\sffam
+\def\sf{\fam=\sffam \setfontstyle{sf}}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+% Default leading.
+\newdimen\textleading \textleading = 13.2pt
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly. There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+\def\setleading#1{%
+ \normalbaselineskip = #1\relax
+ \normallineskip = \lineskipfactor\normalbaselineskip
+ \normalbaselines
+ \setbox\strutbox =\hbox{%
+ \vrule width0pt height\strutheightpercent\baselineskip
+ depth \strutdepthpercent \baselineskip
+ }%
+}
+
+% Set the font macro #1 to the font named #2, adding on the
+% specified font prefix (normally `cm').
+% #3 is the font's design size, #4 is a scale factor
+\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4}
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\undefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx} %where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+% Text fonts (11.2pt, magstep1).
+\def\textnominalsize{11pt}
+\edef\mainmagstep{\magstephalf}
+\setfont\textrm\rmshape{10}{\mainmagstep}
+\setfont\texttt\ttshape{10}{\mainmagstep}
+\setfont\textbf\bfshape{10}{\mainmagstep}
+\setfont\textit\itshape{10}{\mainmagstep}
+\setfont\textsl\slshape{10}{\mainmagstep}
+\setfont\textsf\sfshape{10}{\mainmagstep}
+\setfont\textsc\scshape{10}{\mainmagstep}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstep1}
+\setfont\deftt\ttshape{10}{\magstep1}
+\setfont\defttsl\ttslshape{10}{\magstep1}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}
+\setfont\smalltt\ttshape{9}{1000}
+\setfont\smallbf\bfshape{10}{900}
+\setfont\smallit\itshape{9}{1000}
+\setfont\smallsl\slshape{9}{1000}
+\setfont\smallsf\sfshape{9}{1000}
+\setfont\smallsc\scshape{10}{900}
+\setfont\smallttsl\ttslshape{10}{900}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}
+\setfont\smallertt\ttshape{8}{1000}
+\setfont\smallerbf\bfshape{10}{800}
+\setfont\smallerit\itshape{8}{1000}
+\setfont\smallersl\slshape{8}{1000}
+\setfont\smallersf\sfshape{8}{1000}
+\setfont\smallersc\scshape{10}{800}
+\setfont\smallerttsl\ttslshape{10}{800}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}
+\setfont\titleit\itbshape{10}{\magstep4}
+\setfont\titlesl\slbshape{10}{\magstep4}
+\setfont\titlett\ttbshape{12}{\magstep3}
+\setfont\titlettsl\ttslshape{10}{\magstep4}
+\setfont\titlesf\sfbshape{17}{\magstep1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\authorrm{\secrm}
+\def\authortt{\sectt}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\def\chapnominalsize{17pt}
+\setfont\chaprm\rmbshape{12}{\magstep2}
+\setfont\chapit\itbshape{10}{\magstep3}
+\setfont\chapsl\slbshape{10}{\magstep3}
+\setfont\chaptt\ttbshape{12}{\magstep2}
+\setfont\chapttsl\ttslshape{10}{\magstep3}
+\setfont\chapsf\sfbshape{17}{1000}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+% Section fonts (14.4pt).
+\def\secnominalsize{14pt}
+\setfont\secrm\rmbshape{12}{\magstep1}
+\setfont\secit\itbshape{10}{\magstep2}
+\setfont\secsl\slbshape{10}{\magstep2}
+\setfont\sectt\ttbshape{12}{\magstep1}
+\setfont\secttsl\ttslshape{10}{\magstep2}
+\setfont\secsf\sfbshape{12}{\magstep1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% Subsection fonts (13.15pt).
+\def\ssecnominalsize{13pt}
+\setfont\ssecrm\rmbshape{12}{\magstephalf}
+\setfont\ssecit\itbshape{10}{1315}
+\setfont\ssecsl\slbshape{10}{1315}
+\setfont\ssectt\ttbshape{12}{\magstephalf}
+\setfont\ssecttsl\ttslshape{10}{1315}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1315}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+
+% Reduced fonts for @acro in text (10pt).
+\def\reducednominalsize{10pt}
+\setfont\reducedrm\rmshape{10}{1000}
+\setfont\reducedtt\ttshape{10}{1000}
+\setfont\reducedbf\bfshape{10}{1000}
+\setfont\reducedit\itshape{10}{1000}
+\setfont\reducedsl\slshape{10}{1000}
+\setfont\reducedsf\sfshape{10}{1000}
+\setfont\reducedsc\scshape{10}{1000}
+\setfont\reducedttsl\ttslshape{10}{1000}
+\font\reducedi=cmmi10
+\font\reducedsy=cmsy10
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families. Since
+% texinfo doesn't allow for producing subscripts and superscripts except
+% in the main text, we don't bother to reset \scriptfont and
+% \scriptscriptfont (which would also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+ \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy
+ \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf
+ \textfont\ttfam=\tentt \textfont\sffam=\tensf
+}
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE. We do this because \STYLE needs to also set the
+% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire
+% \tenSTYLE to set the current font.
+%
+% Each font-changing command also sets the names \lsize (one size lower)
+% and \lllsize (three sizes lower). These relative commands are used in
+% the LaTeX logo and acronyms.
+%
+% This all needs generalizing, badly.
+%
+\def\textfonts{%
+ \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+ \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+ \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+ \let\tenttsl=\textttsl
+ \def\curfontsize{text}%
+ \def\lsize{reduced}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{\textleading}}
+\def\titlefonts{%
+ \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
+ \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
+ \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
+ \let\tenttsl=\titlettsl
+ \def\curfontsize{title}%
+ \def\lsize{chap}\def\lllsize{subsec}%
+ \resetmathfonts \setleading{25pt}}
+\def\titlefont#1{{\titlefonts\rm #1}}
+\def\chapfonts{%
+ \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+ \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+ \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+ \let\tenttsl=\chapttsl
+ \def\curfontsize{chap}%
+ \def\lsize{sec}\def\lllsize{text}%
+ \resetmathfonts \setleading{19pt}}
+\def\secfonts{%
+ \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+ \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+ \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+ \let\tenttsl=\secttsl
+ \def\curfontsize{sec}%
+ \def\lsize{subsec}\def\lllsize{reduced}%
+ \resetmathfonts \setleading{16pt}}
+\def\subsecfonts{%
+ \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+ \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+ \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+ \let\tenttsl=\ssecttsl
+ \def\curfontsize{ssec}%
+ \def\lsize{text}\def\lllsize{small}%
+ \resetmathfonts \setleading{15pt}}
+\let\subsubsecfonts = \subsecfonts
+\def\reducedfonts{%
+ \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl
+ \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc
+ \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy
+ \let\tenttsl=\reducedttsl
+ \def\curfontsize{reduced}%
+ \def\lsize{small}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{10.5pt}}
+\def\smallfonts{%
+ \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl
+ \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc
+ \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy
+ \let\tenttsl=\smallttsl
+ \def\curfontsize{small}%
+ \def\lsize{smaller}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{10.5pt}}
+\def\smallerfonts{%
+ \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl
+ \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc
+ \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy
+ \let\tenttsl=\smallerttsl
+ \def\curfontsize{smaller}%
+ \def\lsize{smaller}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{9.5pt}}
+
+% Set the fonts to use with the @small... environments.
+\let\smallexamplefonts = \smallfonts
+
+% About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample
+% can fit this many characters:
+% 8.5x11=86 smallbook=72 a4=90 a5=69
+% If we use \scriptfonts (8pt), then we can fit this many characters:
+% 8.5x11=90+ smallbook=80 a4=90+ a5=77
+% For me, subjectively, the few extra characters that fit aren't worth
+% the additional smallness of 8pt. So I'm making the default 9pt.
+%
+% By the way, for comparison, here's what fits with @example (10pt):
+% 8.5x11=71 smallbook=60 a4=75 a5=58
+%
+% I wish the USA used A4 paper.
+% --karl, 24jan03.
+
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts \rm
+
+% Define these so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}
+\setfont\shortcontbf\bfshape{10}{\magstep1} % no cmb12
+\setfont\shortcontsl\slshape{12}{1000}
+\setfont\shortconttt\ttshape{12}{1000}
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else
+ \ptexslash\fi\fi\fi}
+\def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx}
+\def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx}
+
+% like \smartslanted except unconditionally uses \ttsl.
+% @var is set to this for defun arguments.
+\def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx}
+
+% like \smartslanted except unconditionally use \sl. We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\let\var=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+
+% @b, explicit bold.
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% @sansserif, explicit sans.
+\def\sansserif#1{{\sf #1}}
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph. Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+% Set sfcode to normal for the chars that usually have another value.
+% Can't use plain's \frenchspacing because it uses the `\x notation, and
+% sometimes \x has an active definition that messes things up.
+%
+\catcode`@=11
+ \def\frenchspacing{%
+ \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m
+ \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m
+ }
+\catcode`@=\other
+
+\def\t#1{%
+ {\tt \rawbackslash \frenchspacing #1}%
+ \null
+}
+\def\samp#1{`\tclose{#1}'\null}
+\setfont\keyrm\rmshape{8}{1000}
+\font\keysy=cmsy9
+\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{%
+ \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+ \vbox{\hrule\kern-0.4pt
+ \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+ \kern-0.4pt\hrule}%
+ \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+% The old definition, with no lozenge:
+%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+% @file, @option are the same as @samp.
+\let\file=\samp
+\let\option=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\def\tclose#1{%
+ {%
+ % Change normal interword space to be same as for the current font.
+ \spaceskip = \fontdimen2\font
+ %
+ % Switch to typewriter.
+ \tt
+ %
+ % But `\ ' produces the large typewriter interword space.
+ \def\ {{\spaceskip = 0pt{} }}%
+ %
+ % Turn off hyphenation.
+ \nohyphenation
+ %
+ \rawbackslash
+ \frenchspacing
+ #1%
+ }%
+ \null
+}
+
+% We *must* turn on hyphenation at `-' and `_' in @code.
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash.
+% -- rms.
+{
+ \catcode`\-=\active
+ \catcode`\_=\active
+ %
+ \global\def\code{\begingroup
+ \catcode`\-=\active \let-\codedash
+ \catcode`\_=\active \let_\codeunder
+ \codex
+ }
+}
+
+\def\realdash{-}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{%
+ % this is all so @math{@code{var_name}+1} can work. In math mode, _
+ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.)
+ % will therefore expand the active definition of _, which is us
+ % (inside @code that is), therefore an endless loop.
+ \ifusingtt{\ifmmode
+ \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_.
+ \else\normalunderscore \fi
+ \discretionary{}{}{}}%
+ {\_}%
+}
+\def\codex #1{\tclose{#1}\endgroup}
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+% `example' (@kbd uses ttsl only inside of @example and friends),
+% or `code' (@kbd uses normal tty font always).
+\parseargdef\kbdinputstyle{%
+ \def\arg{#1}%
+ \ifx\arg\worddistinct
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+ \else\ifx\arg\wordexample
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+ \else\ifx\arg\wordcode
+ \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @kbdinputstyle option `\arg'}%
+ \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct.'
+\kbdinputstyle distinct
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else{\tclose{\kbdfont\look}}\fi
+\else{\tclose{\kbdfont\look}}\fi}
+
+% For @indicateurl, @env, @command quotes seem unnecessary, so use \code.
+\let\indicateurl=\code
+\let\env=\code
+\let\command=\code
+
+% @uref (abbreviation for `urlref') takes an optional (comma-separated)
+% second argument specifying the text to display and an optional third
+% arg as text to display instead of (rather than in addition to) the url
+% itself. First (mandatory) arg is the url. Perhaps eventually put in
+% a hypertex \special here.
+%
+\def\uref#1{\douref #1,,,\finish}
+\def\douref#1,#2,#3,#4\finish{\begingroup
+ \unsepspaces
+ \pdfurl{#1}%
+ \setbox0 = \hbox{\ignorespaces #3}%
+ \ifdim\wd0 > 0pt
+ \unhbox0 % third arg given, show only that
+ \else
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0 > 0pt
+ \ifpdf
+ \unhbox0 % PDF: 2nd arg given, show only it
+ \else
+ \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url
+ \fi
+ \else
+ \code{#1}% only url given, so show it
+ \fi
+ \fi
+ \endlink
+\endgroup}
+
+% @url synonym for @uref, since that's how everyone uses it.
+%
+\let\url=\uref
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\ifpdf
+ \def\email#1{\doemail#1,,\finish}
+ \def\doemail#1,#2,#3\finish{\begingroup
+ \unsepspaces
+ \pdfurl{mailto:#1}%
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+ \endlink
+ \endgroup}
+\else
+ \let\email=\uref
+\fi
+
+% Check if we are currently using a typewriter font. Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Typeset a dimension, e.g., `in' or `pt'. The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+% @l was never documented to mean ``switch to the Lisp font'',
+% and it is not used as such in any manual I can find. We need it for
+% Polish suppressed-l. --karl, 22sep96.
+%\def\l#1{{\li #1}\null}
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}} % roman font
+\def\sc#1{{\smallcaps#1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+% @acronym for "FBI", "NATO", and the like.
+% We print this one point size smaller, since it's intended for
+% all-uppercase.
+%
+\def\acronym#1{\doacronym #1,,\finish}
+\def\doacronym#1,#2,#3\finish{%
+ {\selectfonts\lsize #1}%
+ \def\temp{#2}%
+ \ifx\temp\empty \else
+ \space ({\unsepspaces \ignorespaces \temp \unskip})%
+ \fi
+}
+
+% @abbr for "Comput. J." and the like.
+% No font change, but don't do end-of-sentence spacing.
+%
+\def\abbr#1{\doabbr #1,,\finish}
+\def\doabbr#1,#2,#3\finish{%
+ {\frenchspacing #1}%
+ \def\temp{#2}%
+ \ifx\temp\empty \else
+ \space ({\unsepspaces \ignorespaces \temp \unskip})%
+ \fi
+}
+
+% @pounds{} is a sterling sign, which Knuth put in the CM italic font.
+%
+\def\pounds{{\it\$}}
+
+% @euro{} comes from a separate font, depending on the current style.
+% We use the free feym* fonts from the eurosym package by Henrik
+% Theiling, which support regular, slanted, bold and bold slanted (and
+% "outlined" (blackboard board, sort of) versions, which we don't need).
+% It is available from http://www.ctan.org/tex-archive/fonts/eurosym.
+%
+% Although only regular is the truly official Euro symbol, we ignore
+% that. The Euro is designed to be slightly taller than the regular
+% font height.
+%
+% feymr - regular
+% feymo - slanted
+% feybr - bold
+% feybo - bold slanted
+%
+% There is no good (free) typewriter version, to my knowledge.
+% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide.
+% Hmm.
+%
+% Also doesn't work in math. Do we need to do math with euro symbols?
+% Hope not.
+%
+%
+\def\euro{{\eurofont e}}
+\def\eurofont{%
+ % We set the font at each command, rather than predefining it in
+ % \textfonts and the other font-switching commands, so that
+ % installations which never need the symbol don't have to have the
+ % font installed.
+ %
+ % There is only one designed size (nominal 10pt), so we always scale
+ % that to the current nominal size.
+ %
+ % By the way, simply using "at 1em" works for cmr10 and the like, but
+ % does not work for cmbx10 and other extended/shrunken fonts.
+ %
+ \def\eurosize{\csname\curfontsize nominalsize\endcsname}%
+ %
+ \ifx\curfontstyle\bfstylename
+ % bold:
+ \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize
+ \else
+ % regular:
+ \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize
+ \fi
+ \thiseurofont
+}
+
+% @registeredsymbol - R in a circle. The font for the R should really
+% be smaller yet, but lllsize is the best we can do for now.
+% Adapted from the plain.tex definition of \copyright.
+%
+\def\registeredsymbol{%
+ $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}%
+ \hfil\crcr\Orb}}%
+ }$%
+}
+
+% Laurent Siebenmann reports \Orb undefined with:
+% Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38
+% so we'll define it if necessary.
+%
+\ifx\Orb\undefined
+\def\Orb{\mathhexbox20D}
+\fi
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page. Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% Do an implicit @contents or @shortcontents after @end titlepage if the
+% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
+%
+\newif\ifsetcontentsaftertitlepage
+ \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
+\newif\ifsetshortcontentsaftertitlepage
+ \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+
+\parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+ \endgroup\page\hbox{}\page}
+
+\envdef\titlepage{%
+ % Open one extra group, as we want to close it in the middle of \Etitlepage.
+ \begingroup
+ \parindent=0pt \textfonts
+ % Leave some space at the very top of the page.
+ \vglue\titlepagetopglue
+ % No rule at page bottom unless we print one at the top with @title.
+ \finishedtitlepagetrue
+ %
+ % Most title ``pages'' are actually two pages long, with space
+ % at the top of the second. We don't want the ragged left on the second.
+ \let\oldpage = \page
+ \def\page{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ \let\page = \oldpage
+ \page
+ \null
+ }%
+}
+
+\def\Etitlepage{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ % It is important to do the page break before ending the group,
+ % because the headline and footline are only empty inside the group.
+ % If we use the new definition of \page, we always get a blank page
+ % after the title page, which we certainly don't want.
+ \oldpage
+ \endgroup
+ %
+ % Need this before the \...aftertitlepage checks so that if they are
+ % in effect the toc pages will come out with page numbers.
+ \HEADINGSon
+ %
+ % If they want short, they certainly want long too.
+ \ifsetshortcontentsaftertitlepage
+ \shortcontents
+ \contents
+ \global\let\shortcontents = \relax
+ \global\let\contents = \relax
+ \fi
+ %
+ \ifsetcontentsaftertitlepage
+ \contents
+ \global\let\contents = \relax
+ \global\let\shortcontents = \relax
+ \fi
+}
+
+\def\finishtitlepage{%
+ \vskip4pt \hrule height 2pt width \hsize
+ \vskip\titlepagebottomglue
+ \finishedtitlepagetrue
+}
+
+%%% Macros to be used within @titlepage:
+
+\let\subtitlerm=\tenrm
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines
+ \let\tt=\authortt}
+
+\parseargdef\title{%
+ \checkenv\titlepage
+ \leftline{\titlefonts\rm #1}
+ % print a rule at the page bottom also.
+ \finishedtitlepagefalse
+ \vskip4pt \hrule height 4pt width \hsize \vskip4pt
+}
+
+\parseargdef\subtitle{%
+ \checkenv\titlepage
+ {\subtitlefont \rightline{#1}}%
+}
+
+% @author should come last, but may come many times.
+% It can also be used inside @quotation.
+%
+\parseargdef\author{%
+ \def\temp{\quotation}%
+ \ifx\thisenv\temp
+ \def\quotationauthor{#1}% printed in \Equotation.
+ \else
+ \checkenv\titlepage
+ \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
+ {\authorfont \leftline{#1}}%
+ \fi
+}
+
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline % headline on even pages
+\newtoks\oddheadline % headline on odd pages
+\newtoks\evenfootline % footline on even pages
+\newtoks\oddfootline % footline on odd pages
+
+% Now make TeX use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+ \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+ \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what @headings on does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish}
+\def\evenheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish}
+\def\oddheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish}
+\def\evenfootingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish}
+\def\oddfootingyyy #1\|#2\|#3\|#4\finish{%
+ \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+ %
+ % Leave some space for the footline. Hopefully ok to assume
+ % @evenfooting will not be used by itself.
+ \global\advance\pageheight by -\baselineskip
+ \global\advance\vsize by -\baselineskip
+}
+
+\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+
+
+% @headings double turns headings on for double-sided printing.
+% @headings single turns headings on for single-sided printing.
+% @headings off turns them off.
+% @headings on same as @headings double, retained for compatibility.
+% @headings after turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{%
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% This produces Day Month Year style of output.
+% Only define if not already defined, in case a txi-??.tex file has set
+% up a different format (e.g., txi-cs.tex does this).
+\ifx\today\undefined
+\def\today{%
+ \number\day\space
+ \ifcase\month
+ \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+ \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+ \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+ \fi
+ \space\number\year}
+\fi
+
+% @settitle line... specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg{\gdef\thistitle}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @ftable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\itemzzz #1{\begingroup %
+ \advance\hsize by -\rightskip
+ \advance\hsize by -\tableindent
+ \setbox0=\hbox{\itemindicate{#1}}%
+ \itemindex{#1}%
+ \nobreak % This prevents a break before @itemx.
+ %
+ % If the item text does not fit in the space we have, put it on a line
+ % by itself, and do not allow a page break either before or after that
+ % line. We do not start a paragraph here because then if the next
+ % command is, e.g., @kindex, the whatsit would get put into the
+ % horizontal list on a line by itself, resulting in extra blank space.
+ \ifdim \wd0>\itemmax
+ %
+ % Make this a paragraph so we get the \parskip glue and wrapping,
+ % but leave it ragged-right.
+ \begingroup
+ \advance\leftskip by-\tableindent
+ \advance\hsize by\tableindent
+ \advance\rightskip by0pt plus1fil
+ \leavevmode\unhbox0\par
+ \endgroup
+ %
+ % We're going to be starting a paragraph, but we don't want the
+ % \parskip glue -- logically it's part of the @item we just started.
+ \nobreak \vskip-\parskip
+ %
+ % Stop a page break at the \parskip glue coming up. However, if
+ % what follows is an environment such as @example, there will be no
+ % \parskip glue; then the negative vskip we just inserted would
+ % cause the example and the item to crash together. So we use this
+ % bizarre value of 10001 as a signal to \aboveenvbreak to insert
+ % \parskip glue after all. Section titles are handled this way also.
+ %
+ \penalty 10001
+ \endgroup
+ \itemxneedsnegativevskipfalse
+ \else
+ % The item text fits into the space. Start a paragraph, so that the
+ % following text (if any) will end up on the same line.
+ \noindent
+ % Do this with kerns and \unhbox so that if there is a footnote in
+ % the item text, it can migrate to the main vertical list and
+ % eventually be printed.
+ \nobreak\kern-\tableindent
+ \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+ \unhbox0
+ \nobreak\kern\dimen0
+ \endgroup
+ \itemxneedsnegativevskiptrue
+ \fi
+}
+
+\def\item{\errmessage{@item while not in a list environment}}
+\def\itemx{\errmessage{@itemx while not in a list environment}}
+
+% @table, @ftable, @vtable.
+\envdef\table{%
+ \let\itemindex\gobble
+ \tablecheck{table}%
+}
+\envdef\ftable{%
+ \def\itemindex ##1{\doind {fn}{\code{##1}}}%
+ \tablecheck{ftable}%
+}
+\envdef\vtable{%
+ \def\itemindex ##1{\doind {vr}{\code{##1}}}%
+ \tablecheck{vtable}%
+}
+\def\tablecheck#1{%
+ \ifnum \the\catcode`\^^M=\active
+ \endgroup
+ \errmessage{This command won't work in this context; perhaps the problem is
+ that we are \inenvironment\thisenv}%
+ \def\next{\doignore{#1}}%
+ \else
+ \let\next\tablex
+ \fi
+ \next
+}
+\def\tablex#1{%
+ \def\itemindicate{#1}%
+ \parsearg\tabley
+}
+\def\tabley#1{%
+ {%
+ \makevalueexpandable
+ \edef\temp{\noexpand\tablez #1\space\space\space}%
+ \expandafter
+ }\temp \endtablez
+}
+\def\tablez #1 #2 #3 #4\endtablez{%
+ \aboveenvbreak
+ \ifnum 0#1>0 \advance \leftskip by #1\mil \fi
+ \ifnum 0#2>0 \tableindent=#2\mil \fi
+ \ifnum 0#3>0 \advance \rightskip by #3\mil \fi
+ \itemmax=\tableindent
+ \advance \itemmax by -\itemmargin
+ \advance \leftskip by \tableindent
+ \exdentamount=\tableindent
+ \parindent = 0pt
+ \parskip = \smallskipamount
+ \ifdim \parskip=0pt \parskip=2pt \fi
+ \let\item = \internalBitem
+ \let\itemx = \internalBitemx
+}
+\def\Etable{\endgraf\afterenvbreak}
+\let\Eftable\Etable
+\let\Evtable\Etable
+\let\Eitemize\Etable
+\let\Eenumerate\Etable
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\envdef\itemize{\parsearg\doitemize}
+
+\def\doitemize#1{%
+ \aboveenvbreak
+ \itemmax=\itemindent
+ \advance\itemmax by -\itemmargin
+ \advance\leftskip by \itemindent
+ \exdentamount=\itemindent
+ \parindent=0pt
+ \parskip=\smallskipamount
+ \ifdim\parskip=0pt \parskip=2pt \fi
+ \def\itemcontents{#1}%
+ % @itemize with no arg is equivalent to @itemize @bullet.
+ \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi
+ \let\item=\itemizeitem
+}
+
+% Definition of @item while inside @itemize and @enumerate.
+%
+\def\itemizeitem{%
+ \advance\itemno by 1 % for enumerations
+ {\let\par=\endgraf \smallbreak}% reasonable place to break
+ {%
+ % If the document has an @itemize directly after a section title, a
+ % \nobreak will be last on the list, and \sectionheading will have
+ % done a \vskip-\parskip. In that case, we don't want to zero
+ % parskip, or the item text will crash with the heading. On the
+ % other hand, when there is normal text preceding the item (as there
+ % usually is), we do want to zero parskip, or there would be too much
+ % space. In that case, we won't have a \nobreak before. At least
+ % that's the theory.
+ \ifnum\lastpenalty<10000 \parskip=0in \fi
+ \noindent
+ \hbox to 0pt{\hss \itemcontents \kern\itemmargin}%
+ \vadjust{\penalty 1200}}% not good to break after first line of item.
+ \flushcr
+}
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list. No
+% argument is the same as `1'.
+%
+\envparseargdef\enumerate{\enumeratey #1 \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+ % If we were given no argument, pretend we were given `1'.
+ \def\thearg{#1}%
+ \ifx\thearg\empty \def\thearg{1}\fi
+ %
+ % Detect if the argument is a single token. If so, it might be a
+ % letter. Otherwise, the only valid thing it can be is a number.
+ % (We will always have one token, because of the test we just made.
+ % This is a good thing, since \splitoff doesn't work given nothing at
+ % all -- the first parameter is undelimited.)
+ \expandafter\splitoff\thearg\endmark
+ \ifx\rest\empty
+ % Only one token in the argument. It could still be anything.
+ % A ``lowercase letter'' is one whose \lccode is nonzero.
+ % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+ % not equal to itself.
+ % Otherwise, we assume it's a number.
+ %
+ % We need the \relax at the end of the \ifnum lines to stop TeX from
+ % continuing to look for a <number>.
+ %
+ \ifnum\lccode\expandafter`\thearg=0\relax
+ \numericenumerate % a number (we hope)
+ \else
+ % It's a letter.
+ \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+ \lowercaseenumerate % lowercase letter
+ \else
+ \uppercaseenumerate % uppercase letter
+ \fi
+ \fi
+ \else
+ % Multiple tokens in the argument. We hope it's a number.
+ \numericenumerate
+ \fi
+}
+
+% An @enumerate whose labels are integers. The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+ \itemno = \thearg
+ \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more lowercase letters in @enumerate; get a bigger
+ alphabet}%
+ \fi
+ \char\lccode\itemno
+ }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more uppercase letters in @enumerate; get a bigger
+ alphabet}
+ \fi
+ \char\uccode\itemno
+ }%
+}
+
+% Call \doitemize, adding a period to the first argument and supplying the
+% common last two arguments. Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+ \advance\itemno by -1
+ \doitemize{#1.}\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble. Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+% @multitable @columnfractions .25 .3 .45
+% @item ...
+%
+% Numbers following @columnfractions are the percent of the total
+% current hsize to be used for each column. You may use as many
+% columns as desired.
+
+
+% Or use a template:
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item ...
+% using the widest term desired in each column.
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab do not need to be on their own lines, but it will not hurt
+% if they are.
+
+% Sample multitable:
+
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item first col stuff @tab second col stuff @tab third col
+% @item
+% first col stuff
+% @tab
+% second col stuff
+% @tab
+% third col
+% @item first col stuff @tab second col stuff
+% @tab Many paragraphs of text may be used in any column.
+%
+% They will wrap at the width determined by the template.
+% @item@tab@tab This will be in third column.
+% @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+% to baseline.
+% 0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the @columnfraction, usually a decimal number like .5, but might
+% be just 1. We just use it, whatever it is.
+%
+\def\pickupwholefraction#1 {%
+ \global\advance\colcount by 1
+ \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}%
+ \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+ \def\firstarg{#1}%
+ \ifx\firstarg\xendsetuptable
+ \let\go = \relax
+ \else
+ \ifx\firstarg\xcolumnfractions
+ \global\setpercenttrue
+ \else
+ \ifsetpercent
+ \let\go\pickupwholefraction
+ \else
+ \global\advance\colcount by 1
+ \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a
+ % separator; typically that is always in the input, anyway.
+ \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+ \fi
+ \fi
+ \ifx\go\pickupwholefraction
+ % Put the argument back for the \pickupwholefraction call, so
+ % we'll always have a period there to be parsed.
+ \def\go{\pickupwholefraction#1}%
+ \else
+ \let\go = \setuptable
+ \fi%
+ \fi
+ \go
+}
+
+% multitable-only commands.
+%
+% @headitem starts a heading row, which we typeset in bold.
+% Assignments have to be global since we are inside the implicit group
+% of an alignment entry. Note that \everycr resets \everytab.
+\def\headitem{\checkenv\multitable \crcr \global\everytab={\bf}\the\everytab}%
+%
+% A \tab used to include \hskip1sp. But then the space in a template
+% line is not enough. That is bad. So let's go back to just `&' until
+% we encounter the problem it was intended to solve again.
+% --karl, nathan@acm.org, 20apr99.
+\def\tab{\checkenv\multitable &\the\everytab}%
+
+% @multitable ... @end multitable definitions:
+%
+\newtoks\everytab % insert after every tab.
+%
+\envdef\multitable{%
+ \vskip\parskip
+ \startsavinginserts
+ %
+ % @item within a multitable starts a normal row.
+ % We use \def instead of \let so that if one of the multitable entries
+ % contains an @itemize, we don't choke on the \item (seen as \crcr aka
+ % \endtemplate) expanding \doitemize.
+ \def\item{\crcr}%
+ %
+ \tolerance=9500
+ \hbadness=9500
+ \setmultitablespacing
+ \parskip=\multitableparskip
+ \parindent=\multitableparindent
+ \overfullrule=0pt
+ \global\colcount=0
+ %
+ \everycr = {%
+ \noalign{%
+ \global\everytab={}%
+ \global\colcount=0 % Reset the column counter.
+ % Check for saved footnotes, etc.
+ \checkinserts
+ % Keeps underfull box messages off when table breaks over pages.
+ %\filbreak
+ % Maybe so, but it also creates really weird page breaks when the
+ % table breaks over pages. Wouldn't \vfil be better? Wait until the
+ % problem manifests itself, so it can be fixed for real --karl.
+ }%
+ }%
+ %
+ \parsearg\domultitable
+}
+\def\domultitable#1{%
+ % To parse everything between @multitable and @item:
+ \setuptable#1 \endsetuptable
+ %
+ % This preamble sets up a generic column definition, which will
+ % be used as many times as user calls for columns.
+ % \vtop will set a single line and will also let text wrap and
+ % continue for many paragraphs if desired.
+ \halign\bgroup &%
+ \global\advance\colcount by 1
+ \multistrut
+ \vtop{%
+ % Use the current \colcount to find the correct column width:
+ \hsize=\expandafter\csname col\the\colcount\endcsname
+ %
+ % In order to keep entries from bumping into each other
+ % we will add a \leftskip of \multitablecolspace to all columns after
+ % the first one.
+ %
+ % If a template has been used, we will add \multitablecolspace
+ % to the width of each template entry.
+ %
+ % If the user has set preamble in terms of percent of \hsize we will
+ % use that dimension as the width of the column, and the \leftskip
+ % will keep entries from bumping into each other. Table will start at
+ % left margin and final column will justify at right margin.
+ %
+ % Make sure we don't inherit \rightskip from the outer environment.
+ \rightskip=0pt
+ \ifnum\colcount=1
+ % The first column will be indented with the surrounding text.
+ \advance\hsize by\leftskip
+ \else
+ \ifsetpercent \else
+ % If user has not set preamble in terms of percent of \hsize
+ % we will advance \hsize by \multitablecolspace.
+ \advance\hsize by \multitablecolspace
+ \fi
+ % In either case we will make \leftskip=\multitablecolspace:
+ \leftskip=\multitablecolspace
+ \fi
+ % Ignoring space at the beginning and end avoids an occasional spurious
+ % blank line, when TeX decides to break the line at the space before the
+ % box from the multistrut, so the strut ends up on a line by itself.
+ % For example:
+ % @multitable @columnfractions .11 .89
+ % @item @code{#}
+ % @tab Legal holiday which is valid in major parts of the whole country.
+ % Is automatically provided with highlighting sequences respectively
+ % marking characters.
+ \noindent\ignorespaces##\unskip\multistrut
+ }\cr
+}
+\def\Emultitable{%
+ \crcr
+ \egroup % end the \halign
+ \global\setpercentfalse
+}
+
+\def\setmultitablespacing{%
+ \def\multistrut{\strut}% just use the standard line spacing
+ %
+ % Compute \multitablelinespace (if not defined by user) for use in
+ % \multitableparskip calculation. We used define \multistrut based on
+ % this, but (ironically) that caused the spacing to be off.
+ % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100.
+\ifdim\multitablelinespace=0pt
+\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip
+\global\advance\multitablelinespace by-\ht0
+\fi
+%% Test to see if parskip is larger than space between lines of
+%% table. If not, do nothing.
+%% If so, set to same dimension as multitablelinespace.
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+ %% than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+ %% than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+
+% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext,
+% @ifnotxml always succeed. They currently do nothing; we don't
+% attempt to check whether the conditionals are properly nested. But we
+% have to remember that they are conditionals, so that @end doesn't
+% attempt to close an environment group.
+%
+\def\makecond#1{%
+ \expandafter\let\csname #1\endcsname = \relax
+ \expandafter\let\csname iscond.#1\endcsname = 1
+}
+\makecond{iftex}
+\makecond{ifnotdocbook}
+\makecond{ifnothtml}
+\makecond{ifnotinfo}
+\makecond{ifnotplaintext}
+\makecond{ifnotxml}
+
+% Ignore @ignore, @ifhtml, @ifinfo, and the like.
+%
+\def\direntry{\doignore{direntry}}
+\def\documentdescription{\doignore{documentdescription}}
+\def\docbook{\doignore{docbook}}
+\def\html{\doignore{html}}
+\def\ifdocbook{\doignore{ifdocbook}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\ifplaintext{\doignore{ifplaintext}}
+\def\ifxml{\doignore{ifxml}}
+\def\ignore{\doignore{ignore}}
+\def\menu{\doignore{menu}}
+\def\xml{\doignore{xml}}
+
+% Ignore text until a line `@end #1', keeping track of nested conditionals.
+%
+% A count to remember the depth of nesting.
+\newcount\doignorecount
+
+\def\doignore#1{\begingroup
+ % Scan in ``verbatim'' mode:
+ \catcode`\@ = \other
+ \catcode`\{ = \other
+ \catcode`\} = \other
+ %
+ % Make sure that spaces turn into tokens that match what \doignoretext wants.
+ \spaceisspace
+ %
+ % Count number of #1's that we've seen.
+ \doignorecount = 0
+ %
+ % Swallow text until we reach the matching `@end #1'.
+ \dodoignore{#1}%
+}
+
+{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source.
+ \obeylines %
+ %
+ \gdef\dodoignore#1{%
+ % #1 contains the command name as a string, e.g., `ifinfo'.
+ %
+ % Define a command to find the next `@end #1', which must be on a line
+ % by itself.
+ \long\def\doignoretext##1^^M@end #1{\doignoretextyyy##1^^M@#1\_STOP_}%
+ % And this command to find another #1 command, at the beginning of a
+ % line. (Otherwise, we would consider a line `@c @ifset', for
+ % example, to count as an @ifset for nesting.)
+ \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}%
+ %
+ % And now expand that command.
+ \obeylines %
+ \doignoretext ^^M%
+ }%
+}
+
+\def\doignoreyyy#1{%
+ \def\temp{#1}%
+ \ifx\temp\empty % Nothing found.
+ \let\next\doignoretextzzz
+ \else % Found a nested condition, ...
+ \advance\doignorecount by 1
+ \let\next\doignoretextyyy % ..., look for another.
+ % If we're here, #1 ends with ^^M\ifinfo (for example).
+ \fi
+ \next #1% the token \_STOP_ is present just after this macro.
+}
+
+% We have to swallow the remaining "\_STOP_".
+%
+\def\doignoretextzzz#1{%
+ \ifnum\doignorecount = 0 % We have just found the outermost @end.
+ \let\next\enddoignore
+ \else % Still inside a nested condition.
+ \advance\doignorecount by -1
+ \let\next\doignoretext % Look for the next @end.
+ \fi
+ \next
+}
+
+% Finish off ignored text.
+\def\enddoignore{\endgroup\ignorespaces}
+
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+% We rely on the fact that \parsearg sets \catcode`\ =10.
+%
+\parseargdef\set{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+ {%
+ \makevalueexpandable
+ \def\temp{#2}%
+ \edef\next{\gdef\makecsname{SET#1}}%
+ \ifx\temp\empty
+ \next{}%
+ \else
+ \setzzz#2\endsetzzz
+ \fi
+ }%
+}
+% Remove the trailing space \setxxx inserted.
+\def\setzzz#1 \endsetzzz{\next{#1}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\parseargdef\clear{%
+ {%
+ \makevalueexpandable
+ \global\expandafter\let\csname SET#1\endcsname=\relax
+ }%
+}
+
+% @value{foo} gets the text saved in variable foo.
+\def\value{\begingroup\makevalueexpandable\valuexxx}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+{
+ \catcode`\- = \active \catcode`\_ = \active
+ %
+ \gdef\makevalueexpandable{%
+ \let\value = \expandablevalue
+ % We don't want these characters active, ...
+ \catcode`\-=\other \catcode`\_=\other
+ % ..., but we might end up with active ones in the argument if
+ % we're called from @code, as @code{@value{foo-bar_}}, though.
+ % So \let them to their normal equivalents.
+ \let-\realdash \let_\normalunderscore
+ }
+}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we call \makevalueexpandable in \indexdummies).
+% The command has to be fully expandable (if the variable is set), since
+% the result winds up in the index file. This means that if the
+% variable's value contains other Texinfo commands, it's almost certain
+% it will fail (although perhaps we could fix that with sufficient work
+% to do a one-level expansion on the result, instead of complete).
+%
+\def\expandablevalue#1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ {[No value for ``#1'']}%
+ \message{Variable `#1', used in @value, is not set.}%
+ \else
+ \csname SET#1\endcsname
+ \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+% To get special treatment of `@end ifset,' call \makeond and the redefine.
+%
+\makecond{ifset}
+\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}}
+\def\doifset#1#2{%
+ {%
+ \makevalueexpandable
+ \let\next=\empty
+ \expandafter\ifx\csname SET#2\endcsname\relax
+ #1% If not set, redefine \next.
+ \fi
+ \expandafter
+ }\next
+}
+\def\ifsetfail{\doignore{ifset}}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+% The `\else' inside the `\doifset' parameter is a trick to reuse the
+% above code: if the variable is not set, do nothing, if it is set,
+% then redefine \next to \ifclearfail.
+%
+\makecond{ifclear}
+\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}}
+\def\ifclearfail{\doignore{ifclear}}
+
+% @dircategory CATEGORY -- specify a category of the dir file
+% which this file should belong to. Ignore this in TeX.
+\let\dircategory=\comment
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within macros and \if's.
+\edef\newwrite{\makecsname{ptexnewwrite}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index. The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+ \iflinks
+ \expandafter\newwrite \csname#1indfile\endcsname
+ \openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+ \fi
+ \expandafter\xdef\csname#1index\endcsname{% % Define @#1index
+ \noexpand\doindex{#1}}
+}
+
+% @defindex foo == \newindex{foo}
+%
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+%
+\def\defcodeindex{\parsearg\newcodeindex}
+%
+\def\newcodeindex#1{%
+ \iflinks
+ \expandafter\newwrite \csname#1indfile\endcsname
+ \openout \csname#1indfile\endcsname \jobname.#1
+ \fi
+ \expandafter\xdef\csname#1index\endcsname{%
+ \noexpand\docodeindex{#1}}%
+}
+
+
+% @synindex foo bar makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+%
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+%
+\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}}
+\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}}
+
+% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo),
+% #3 the target index (bar).
+\def\dosynindex#1#2#3{%
+ % Only do \closeout if we haven't already done it, else we'll end up
+ % closing the target index.
+ \expandafter \ifx\csname donesynindex#2\endcsname \undefined
+ % The \closeout helps reduce unnecessary open files; the limit on the
+ % Acorn RISC OS is a mere 16 files.
+ \expandafter\closeout\csname#2indfile\endcsname
+ \expandafter\let\csname\donesynindex#2\endcsname = 1
+ \fi
+ % redefine \fooindfile:
+ \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname
+ \expandafter\let\csname#2indfile\endcsname=\temp
+ % redefine \fooindex:
+ \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+% Take care of Texinfo commands that can appear in an index entry.
+% Since there are some commands we want to expand, and others we don't,
+% we have to laboriously prevent expansion for those that we don't.
+%
+\def\indexdummies{%
+ \def\@{@}% change to @@ when we switch to @ as escape char in index files.
+ \def\ {\realbackslash\space }%
+ % Need these in case \tex is in effect and \{ is a \delimiter again.
+ % But can't use \lbracecmd and \rbracecmd because texindex assumes
+ % braces and backslashes are used only as delimiters.
+ \let\{ = \mylbrace
+ \let\} = \myrbrace
+ %
+ % \definedummyword defines \#1 as \realbackslash #1\space, thus
+ % effectively preventing its expansion. This is used only for control
+ % words, not control letters, because the \space would be incorrect
+ % for control characters, but is needed to separate the control word
+ % from whatever follows.
+ %
+ % For control letters, we have \definedummyletter, which omits the
+ % space.
+ %
+ % These can be used both for control words that take an argument and
+ % those that do not. If it is followed by {arg} in the input, then
+ % that will dutifully get written to the index (or wherever).
+ %
+ \def\definedummyword##1{%
+ \expandafter\def\csname ##1\endcsname{\realbackslash ##1\space}%
+ }%
+ \def\definedummyletter##1{%
+ \expandafter\def\csname ##1\endcsname{\realbackslash ##1}%
+ }%
+ \let\definedummyaccent\definedummyletter
+ %
+ % Do the redefinitions.
+ \commondummies
+}
+
+% For the aux file, @ is the escape character. So we want to redefine
+% everything using @ instead of \realbackslash. When everything uses
+% @, this will be simpler.
+%
+\def\atdummies{%
+ \def\@{@@}%
+ \def\ {@ }%
+ \let\{ = \lbraceatcmd
+ \let\} = \rbraceatcmd
+ %
+ % (See comments in \indexdummies.)
+ \def\definedummyword##1{%
+ \expandafter\def\csname ##1\endcsname{@##1\space}%
+ }%
+ \def\definedummyletter##1{%
+ \expandafter\def\csname ##1\endcsname{@##1}%
+ }%
+ \let\definedummyaccent\definedummyletter
+ %
+ % Do the redefinitions.
+ \commondummies
+}
+
+% Called from \indexdummies and \atdummies. \definedummyword and
+% \definedummyletter must be defined first.
+%
+\def\commondummies{%
+ %
+ \normalturnoffactive
+ %
+ \commondummiesnofonts
+ %
+ \definedummyletter{_}%
+ %
+ % Non-English letters.
+ \definedummyword{AA}%
+ \definedummyword{AE}%
+ \definedummyword{L}%
+ \definedummyword{OE}%
+ \definedummyword{O}%
+ \definedummyword{aa}%
+ \definedummyword{ae}%
+ \definedummyword{l}%
+ \definedummyword{oe}%
+ \definedummyword{o}%
+ \definedummyword{ss}%
+ \definedummyword{exclamdown}%
+ \definedummyword{questiondown}%
+ \definedummyword{ordf}%
+ \definedummyword{ordm}%
+ %
+ % Although these internal commands shouldn't show up, sometimes they do.
+ \definedummyword{bf}%
+ \definedummyword{gtr}%
+ \definedummyword{hat}%
+ \definedummyword{less}%
+ \definedummyword{sf}%
+ \definedummyword{sl}%
+ \definedummyword{tclose}%
+ \definedummyword{tt}%
+ %
+ \definedummyword{LaTeX}%
+ \definedummyword{TeX}%
+ %
+ % Assorted special characters.
+ \definedummyword{bullet}%
+ \definedummyword{comma}%
+ \definedummyword{copyright}%
+ \definedummyword{registeredsymbol}%
+ \definedummyword{dots}%
+ \definedummyword{enddots}%
+ \definedummyword{equiv}%
+ \definedummyword{error}%
+ \definedummyword{euro}%
+ \definedummyword{expansion}%
+ \definedummyword{minus}%
+ \definedummyword{pounds}%
+ \definedummyword{point}%
+ \definedummyword{print}%
+ \definedummyword{result}%
+ %
+ % Handle some cases of @value -- where it does not contain any
+ % (non-fully-expandable) commands.
+ \makevalueexpandable
+ %
+ % Normal spaces, not active ones.
+ \unsepspaces
+ %
+ % No macro expansion.
+ \turnoffmacros
+}
+
+% \commondummiesnofonts: common to \commondummies and \indexnofonts.
+%
+% Better have this without active chars.
+{
+ \catcode`\~=\other
+ \gdef\commondummiesnofonts{%
+ % Control letters and accents.
+ \definedummyletter{!}%
+ \definedummyaccent{"}%
+ \definedummyaccent{'}%
+ \definedummyletter{*}%
+ \definedummyaccent{,}%
+ \definedummyletter{.}%
+ \definedummyletter{/}%
+ \definedummyletter{:}%
+ \definedummyaccent{=}%
+ \definedummyletter{?}%
+ \definedummyaccent{^}%
+ \definedummyaccent{`}%
+ \definedummyaccent{~}%
+ \definedummyword{u}%
+ \definedummyword{v}%
+ \definedummyword{H}%
+ \definedummyword{dotaccent}%
+ \definedummyword{ringaccent}%
+ \definedummyword{tieaccent}%
+ \definedummyword{ubaraccent}%
+ \definedummyword{udotaccent}%
+ \definedummyword{dotless}%
+ %
+ % Texinfo font commands.
+ \definedummyword{b}%
+ \definedummyword{i}%
+ \definedummyword{r}%
+ \definedummyword{sc}%
+ \definedummyword{t}%
+ %
+ % Commands that take arguments.
+ \definedummyword{acronym}%
+ \definedummyword{cite}%
+ \definedummyword{code}%
+ \definedummyword{command}%
+ \definedummyword{dfn}%
+ \definedummyword{emph}%
+ \definedummyword{env}%
+ \definedummyword{file}%
+ \definedummyword{kbd}%
+ \definedummyword{key}%
+ \definedummyword{math}%
+ \definedummyword{option}%
+ \definedummyword{samp}%
+ \definedummyword{strong}%
+ \definedummyword{tie}%
+ \definedummyword{uref}%
+ \definedummyword{url}%
+ \definedummyword{var}%
+ \definedummyword{verb}%
+ \definedummyword{w}%
+ }
+}
+
+% \indexnofonts is used when outputting the strings to sort the index
+% by, and when constructing control sequence names. It eliminates all
+% control sequences and just writes whatever the best ASCII sort string
+% would be for a given command (usually its argument).
+%
+\def\indexnofonts{%
+ % Accent commands should become @asis.
+ \def\definedummyaccent##1{%
+ \expandafter\let\csname ##1\endcsname\asis
+ }%
+ % We can just ignore other control letters.
+ \def\definedummyletter##1{%
+ \expandafter\def\csname ##1\endcsname{}%
+ }%
+ % Hopefully, all control words can become @asis.
+ \let\definedummyword\definedummyaccent
+ %
+ \commondummiesnofonts
+ %
+ % Don't no-op \tt, since it isn't a user-level command
+ % and is used in the definitions of the active chars like <, >, |, etc.
+ % Likewise with the other plain tex font commands.
+ %\let\tt=\asis
+ %
+ \def\ { }%
+ \def\@{@}%
+ % how to handle braces?
+ \def\_{\normalunderscore}%
+ %
+ % Non-English letters.
+ \def\AA{AA}%
+ \def\AE{AE}%
+ \def\L{L}%
+ \def\OE{OE}%
+ \def\O{O}%
+ \def\aa{aa}%
+ \def\ae{ae}%
+ \def\l{l}%
+ \def\oe{oe}%
+ \def\o{o}%
+ \def\ss{ss}%
+ \def\exclamdown{!}%
+ \def\questiondown{?}%
+ \def\ordf{a}%
+ \def\ordm{o}%
+ %
+ \def\LaTeX{LaTeX}%
+ \def\TeX{TeX}%
+ %
+ % Assorted special characters.
+ % (The following {} will end up in the sort string, but that's ok.)
+ \def\bullet{bullet}%
+ \def\comma{,}%
+ \def\copyright{copyright}%
+ \def\registeredsymbol{R}%
+ \def\dots{...}%
+ \def\enddots{...}%
+ \def\equiv{==}%
+ \def\error{error}%
+ \def\euro{euro}%
+ \def\expansion{==>}%
+ \def\minus{-}%
+ \def\pounds{pounds}%
+ \def\point{.}%
+ \def\print{-|}%
+ \def\result{=>}%
+ %
+ % Don't write macro names.
+ \emptyusermacros
+}
+
+\let\indexbackslash=0 %overridden during \printindex.
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% Most index entries go through here, but \dosubind is the general case.
+% #1 is the index name, #2 is the entry text.
+\def\doind#1#2{\dosubind{#1}{#2}{}}
+
+% Workhorse for all \fooindexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% empty if called from \doind, as we usually are (the main exception
+% is with most defuns, which call us directly).
+%
+\def\dosubind#1#2#3{%
+ \iflinks
+ {%
+ % Store the main index entry text (including the third arg).
+ \toks0 = {#2}%
+ % If third arg is present, precede it with a space.
+ \def\thirdarg{#3}%
+ \ifx\thirdarg\empty \else
+ \toks0 = \expandafter{\the\toks0 \space #3}%
+ \fi
+ %
+ \edef\writeto{\csname#1indfile\endcsname}%
+ %
+ \ifvmode
+ \dosubindsanitize
+ \else
+ \dosubindwrite
+ \fi
+ }%
+ \fi
+}
+
+% Write the entry in \toks0 to the index file:
+%
+\def\dosubindwrite{%
+ % Put the index entry in the margin if desired.
+ \ifx\SETmarginindex\relax\else
+ \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}%
+ \fi
+ %
+ % Remember, we are within a group.
+ \indexdummies % Must do this here, since \bf, etc expand at this stage
+ \escapechar=`\\
+ \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now
+ % so it will be output as is; and it will print as backslash.
+ %
+ % Process the index entry with all font commands turned off, to
+ % get the string to sort by.
+ {\indexnofonts
+ \edef\temp{\the\toks0}% need full expansion
+ \xdef\indexsorttmp{\temp}%
+ }%
+ %
+ % Set up the complete index entry, with both the sort key and
+ % the original text, including any font commands. We write
+ % three arguments to \entry to the .?? file (four in the
+ % subentry case), texindex reduces to two when writing the .??s
+ % sorted result.
+ \edef\temp{%
+ \write\writeto{%
+ \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}%
+ }%
+ \temp
+}
+
+% Take care of unwanted page breaks:
+%
+% If a skip is the last thing on the list now, preserve it
+% by backing up by \lastskip, doing the \write, then inserting
+% the skip again. Otherwise, the whatsit generated by the
+% \write will make \lastskip zero. The result is that sequences
+% like this:
+% @end defun
+% @tindex whatever
+% @defun ...
+% will have extra space inserted, because the \medbreak in the
+% start of the @defun won't see the skip inserted by the @end of
+% the previous defun.
+%
+% But don't do any of this if we're not in vertical mode. We
+% don't want to do a \vskip and prematurely end a paragraph.
+%
+% Avoid page breaks due to these extra skips, too.
+%
+% But wait, there is a catch there:
+% We'll have to check whether \lastskip is zero skip. \ifdim is not
+% sufficient for this purpose, as it ignores stretch and shrink parts
+% of the skip. The only way seems to be to check the textual
+% representation of the skip.
+%
+% The following is almost like \def\zeroskipmacro{0.0pt} except that
+% the ``p'' and ``t'' characters have catcode \other, not 11 (letter).
+%
+\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname}
+%
+% ..., ready, GO:
+%
+\def\dosubindsanitize{%
+ % \lastskip and \lastpenalty cannot both be nonzero simultaneously.
+ \skip0 = \lastskip
+ \edef\lastskipmacro{\the\lastskip}%
+ \count255 = \lastpenalty
+ %
+ % If \lastskip is nonzero, that means the last item was a
+ % skip. And since a skip is discardable, that means this
+ % -\skip0 glue we're inserting is preceded by a
+ % non-discardable item, therefore it is not a potential
+ % breakpoint, therefore no \nobreak needed.
+ \ifx\lastskipmacro\zeroskipmacro
+ \else
+ \vskip-\skip0
+ \fi
+ %
+ \dosubindwrite
+ %
+ \ifx\lastskipmacro\zeroskipmacro
+ % If \lastskip was zero, perhaps the last item was a penalty, and
+ % perhaps it was >=10000, e.g., a \nobreak. In that case, we want
+ % to re-insert the same penalty (values >10000 are used for various
+ % signals); since we just inserted a non-discardable item, any
+ % following glue (such as a \parskip) would be a breakpoint. For example:
+ %
+ % @deffn deffn-whatever
+ % @vindex index-whatever
+ % Description.
+ % would allow a break between the index-whatever whatsit
+ % and the "Description." paragraph.
+ \ifnum\count255>9999 \penalty\count255 \fi
+ \else
+ % On the other hand, if we had a nonzero \lastskip,
+ % this make-up glue would be preceded by a non-discardable item
+ % (the whatsit from the \write), so we must insert a \nobreak.
+ \nobreak\vskip\skip0
+ \fi
+}
+
+% The index entry written in the file actually looks like
+% \entry {sortstring}{page}{topic}
+% or
+% \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+% \initial {c}
+% before the first topic whose initial is c
+% \entry {topic}{pagelist}
+% for a topic that is used without subtopics
+% \primary {topic}
+% for the beginning of a topic that is used with subtopics
+% \secondary {subtopic}{pagelist}
+% for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\parseargdef\printindex{\begingroup
+ \dobreak \chapheadingskip{10000}%
+ %
+ \smallfonts \rm
+ \tolerance = 9500
+ \everypar = {}% don't want the \kern\-parindent from indentation suppression.
+ %
+ % See if the index file exists and is nonempty.
+ % Change catcode of @ here so that if the index file contains
+ % \initial {@}
+ % as its first line, TeX doesn't complain about mismatched braces
+ % (because it thinks @} is a control sequence).
+ \catcode`\@ = 11
+ \openin 1 \jobname.#1s
+ \ifeof 1
+ % \enddoublecolumns gets confused if there is no text in the index,
+ % and it loses the chapter title and the aux file entries for the
+ % index. The easiest way to prevent this problem is to make sure
+ % there is some text.
+ \putwordIndexNonexistent
+ \else
+ %
+ % If the index file exists but is empty, then \openin leaves \ifeof
+ % false. We have to make TeX try to read something from the file, so
+ % it can discover if there is anything in it.
+ \read 1 to \temp
+ \ifeof 1
+ \putwordIndexIsEmpty
+ \else
+ % Index files are almost Texinfo source, but we use \ as the escape
+ % character. It would be better to use @, but that's too big a change
+ % to make right now.
+ \def\indexbackslash{\backslashcurfont}%
+ \catcode`\\ = 0
+ \escapechar = `\\
+ \begindoublecolumns
+ \input \jobname.#1s
+ \enddoublecolumns
+ \fi
+ \fi
+ \closein 1
+\endgroup}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+\def\initial#1{{%
+ % Some minor font changes for the special characters.
+ \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+ %
+ % Remove any glue we may have, we'll be inserting our own.
+ \removelastskip
+ %
+ % We like breaks before the index initials, so insert a bonus.
+ \nobreak
+ \vskip 0pt plus 3\baselineskip
+ \penalty 0
+ \vskip 0pt plus -3\baselineskip
+ %
+ % Typeset the initial. Making this add up to a whole number of
+ % baselineskips increases the chance of the dots lining up from column
+ % to column. It still won't often be perfect, because of the stretch
+ % we need before each entry, but it's better.
+ %
+ % No shrink because it confuses \balancecolumns.
+ \vskip 1.67\baselineskip plus .5\baselineskip
+ \leftline{\secbf #1}%
+ % Do our best not to break after the initial.
+ \nobreak
+ \vskip .33\baselineskip plus .1\baselineskip
+}}
+
+% \entry typesets a paragraph consisting of the text (#1), dot leaders, and
+% then page number (#2) flushed to the right margin. It is used for index
+% and table of contents entries. The paragraph is indented by \leftskip.
+%
+% A straightforward implementation would start like this:
+% \def\entry#1#2{...
+% But this frozes the catcodes in the argument, and can cause problems to
+% @code, which sets - active. This problem was fixed by a kludge---
+% ``-'' was active throughout whole index, but this isn't really right.
+%
+% The right solution is to prevent \entry from swallowing the whole text.
+% --kasal, 21nov03
+\def\entry{%
+ \begingroup
+ %
+ % Start a new paragraph if necessary, so our assignments below can't
+ % affect previous text.
+ \par
+ %
+ % Do not fill out the last line with white space.
+ \parfillskip = 0in
+ %
+ % No extra space above this paragraph.
+ \parskip = 0in
+ %
+ % Do not prefer a separate line ending with a hyphen to fewer lines.
+ \finalhyphendemerits = 0
+ %
+ % \hangindent is only relevant when the entry text and page number
+ % don't both fit on one line. In that case, bob suggests starting the
+ % dots pretty far over on the line. Unfortunately, a large
+ % indentation looks wrong when the entry text itself is broken across
+ % lines. So we use a small indentation and put up with long leaders.
+ %
+ % \hangafter is reset to 1 (which is the value we want) at the start
+ % of each paragraph, so we need not do anything with that.
+ \hangindent = 2em
+ %
+ % When the entry text needs to be broken, just fill out the first line
+ % with blank space.
+ \rightskip = 0pt plus1fil
+ %
+ % A bit of stretch before each entry for the benefit of balancing
+ % columns.
+ \vskip 0pt plus1pt
+ %
+ % Swallow the left brace of the text (first parameter):
+ \afterassignment\doentry
+ \let\temp =
+}
+\def\doentry{%
+ \bgroup % Instead of the swallowed brace.
+ \noindent
+ \aftergroup\finishentry
+ % And now comes the text of the entry.
+}
+\def\finishentry#1{%
+ % #1 is the page number.
+ %
+ % The following is kludged to not output a line of dots in the index if
+ % there are no page numbers. The next person who breaks this will be
+ % cursed by a Unix daemon.
+ \def\tempa{{\rm }}%
+ \def\tempb{#1}%
+ \edef\tempc{\tempa}%
+ \edef\tempd{\tempb}%
+ \ifx\tempc\tempd
+ \ %
+ \else
+ %
+ % If we must, put the page number on a line of its own, and fill out
+ % this line with blank space. (The \hfil is overwhelmed with the
+ % fill leaders glue in \indexdotfill if the page number does fit.)
+ \hfil\penalty50
+ \null\nobreak\indexdotfill % Have leaders before the page number.
+ %
+ % The `\ ' here is removed by the implicit \unskip that TeX does as
+ % part of (the primitive) \par. Without it, a spurious underfull
+ % \hbox ensues.
+ \ifpdf
+ \pdfgettoks#1.%
+ \ \the\toksA
+ \else
+ \ #1%
+ \fi
+ \fi
+ \par
+ \endgroup
+}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+ \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+\def\secondary#1#2{{%
+ \parfillskip=0in
+ \parskip=0in
+ \hangindent=1in
+ \hangafter=1
+ \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill
+ \ifpdf
+ \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph.
+ \else
+ #2
+ \fi
+ \par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+ % Grab any single-column material above us.
+ \output = {%
+ %
+ % Here is a possibility not foreseen in manmac: if we accumulate a
+ % whole lot of material, we might end up calling this \output
+ % routine twice in a row (see the doublecol-lose test, which is
+ % essentially a couple of indexes with @setchapternewpage off). In
+ % that case we just ship out what is in \partialpage with the normal
+ % output routine. Generally, \partialpage will be empty when this
+ % runs and this will be a no-op. See the indexspread.tex test case.
+ \ifvoid\partialpage \else
+ \onepageout{\pagecontents\partialpage}%
+ \fi
+ %
+ \global\setbox\partialpage = \vbox{%
+ % Unvbox the main output page.
+ \unvbox\PAGE
+ \kern-\topskip \kern\baselineskip
+ }%
+ }%
+ \eject % run that output routine to set \partialpage
+ %
+ % Use the double-column output routine for subsequent pages.
+ \output = {\doublecolumnout}%
+ %
+ % Change the page size parameters. We could do this once outside this
+ % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+ % format, but then we repeat the same computation. Repeating a couple
+ % of assignments once per index is clearly meaningless for the
+ % execution time, so we may as well do it in one place.
+ %
+ % First we halve the line length, less a little for the gutter between
+ % the columns. We compute the gutter based on the line length, so it
+ % changes automatically with the paper format. The magic constant
+ % below is chosen so that the gutter has the same value (well, +-<1pt)
+ % as it did when we hard-coded it.
+ %
+ % We put the result in a separate register, \doublecolumhsize, so we
+ % can restore it in \pagesofar, after \hsize itself has (potentially)
+ % been clobbered.
+ %
+ \doublecolumnhsize = \hsize
+ \advance\doublecolumnhsize by -.04154\hsize
+ \divide\doublecolumnhsize by 2
+ \hsize = \doublecolumnhsize
+ %
+ % Double the \vsize as well. (We don't need a separate register here,
+ % since nobody clobbers \vsize.)
+ \vsize = 2\vsize
+}
+
+% The double-column output routine for all double-column pages except
+% the last.
+%
+\def\doublecolumnout{%
+ \splittopskip=\topskip \splitmaxdepth=\maxdepth
+ % Get the available space for the double columns -- the normal
+ % (undoubled) page height minus any material left over from the
+ % previous page.
+ \dimen@ = \vsize
+ \divide\dimen@ by 2
+ \advance\dimen@ by -\ht\partialpage
+ %
+ % box0 will be the left-hand column, box2 the right.
+ \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \onepageout\pagesofar
+ \unvbox255
+ \penalty\outputpenalty
+}
+%
+% Re-output the contents of the output page -- any previous material,
+% followed by the two boxes we just split, in box0 and box2.
+\def\pagesofar{%
+ \unvbox\partialpage
+ %
+ \hsize = \doublecolumnhsize
+ \wd0=\hsize \wd2=\hsize
+ \hbox to\pagewidth{\box0\hfil\box2}%
+}
+%
+% All done with double columns.
+\def\enddoublecolumns{%
+ \output = {%
+ % Split the last of the double-column material. Leave it on the
+ % current page, no automatic page break.
+ \balancecolumns
+ %
+ % If we end up splitting too much material for the current page,
+ % though, there will be another page break right after this \output
+ % invocation ends. Having called \balancecolumns once, we do not
+ % want to call it again. Therefore, reset \output to its normal
+ % definition right away. (We hope \balancecolumns will never be
+ % called on to balance too much material, but if it is, this makes
+ % the output somewhat more palatable.)
+ \global\output = {\onepageout{\pagecontents\PAGE}}%
+ }%
+ \eject
+ \endgroup % started in \begindoublecolumns
+ %
+ % \pagegoal was set to the doubled \vsize above, since we restarted
+ % the current page. We're now back to normal single-column
+ % typesetting, so reset \pagegoal to the normal \vsize (after the
+ % \endgroup where \vsize got restored).
+ \pagegoal = \vsize
+}
+%
+% Called at the end of the double column material.
+\def\balancecolumns{%
+ \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+ \dimen@ = \ht0
+ \advance\dimen@ by \topskip
+ \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by 2 % target to split to
+ %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}%
+ \splittopskip = \topskip
+ % Loop until we get a decent breakpoint.
+ {%
+ \vbadness = 10000
+ \loop
+ \global\setbox3 = \copy0
+ \global\setbox1 = \vsplit3 to \dimen@
+ \ifdim\ht3>\dimen@
+ \global\advance\dimen@ by 1pt
+ \repeat
+ }%
+ %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}%
+ \setbox0=\vbox to\dimen@{\unvbox1}%
+ \setbox2=\vbox to\dimen@{\unvbox3}%
+ %
+ \pagesofar
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+% \unnumberedno is an oxymoron, of course. But we count the unnumbered
+% sections so that we can refer to them unambiguously in the pdf
+% outlines by their "section number". We avoid collisions with chapter
+% numbers by starting them at 10000. (If a document ever has 10000
+% chapters, we're in trouble anyway, I'm sure.)
+\newcount\unnumberedno \unnumberedno = 10000
+\newcount\chapno
+\newcount\secno \secno=0
+\newcount\subsecno \subsecno=0
+\newcount\subsubsecno \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno \appendixno = `\@
+%
+% \def\appendixletter{\char\the\appendixno}
+% We do the following ugly conditional instead of the above simple
+% construct for the sake of pdftex, which needs the actual
+% letter in the expansion, not just typeset.
+%
+\def\appendixletter{%
+ \ifnum\appendixno=`A A%
+ \else\ifnum\appendixno=`B B%
+ \else\ifnum\appendixno=`C C%
+ \else\ifnum\appendixno=`D D%
+ \else\ifnum\appendixno=`E E%
+ \else\ifnum\appendixno=`F F%
+ \else\ifnum\appendixno=`G G%
+ \else\ifnum\appendixno=`H H%
+ \else\ifnum\appendixno=`I I%
+ \else\ifnum\appendixno=`J J%
+ \else\ifnum\appendixno=`K K%
+ \else\ifnum\appendixno=`L L%
+ \else\ifnum\appendixno=`M M%
+ \else\ifnum\appendixno=`N N%
+ \else\ifnum\appendixno=`O O%
+ \else\ifnum\appendixno=`P P%
+ \else\ifnum\appendixno=`Q Q%
+ \else\ifnum\appendixno=`R R%
+ \else\ifnum\appendixno=`S S%
+ \else\ifnum\appendixno=`T T%
+ \else\ifnum\appendixno=`U U%
+ \else\ifnum\appendixno=`V V%
+ \else\ifnum\appendixno=`W W%
+ \else\ifnum\appendixno=`X X%
+ \else\ifnum\appendixno=`Y Y%
+ \else\ifnum\appendixno=`Z Z%
+ % The \the is necessary, despite appearances, because \appendixletter is
+ % expanded while writing the .toc file. \char\appendixno is not
+ % expandable, thus it is written literally, thus all appendixes come out
+ % with the same letter (or @) in the toc without it.
+ \else\char\the\appendixno
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it. @section does likewise.
+% However, they are not reliable, because we don't use marks.
+\def\thischapter{}
+\def\thissection{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% we only have subsub.
+\chardef\maxseclevel = 3
+%
+% A numbered section within an unnumbered changes to unnumbered too.
+% To achive this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unmlevel = \maxseclevel
+%
+% Trace whether the current chapter is an appendix or not:
+% \chapheadtype is "N" or "A", unnumbered chapters are ignored.
+\def\chapheadtype{N}
+
+% Choose a heading macro
+% #1 is heading type
+% #2 is heading level
+% #3 is text for heading
+\def\genhead#1#2#3{%
+ % Compute the abs. sec. level:
+ \absseclevel=#2
+ \advance\absseclevel by \secbase
+ % Make sure \absseclevel doesn't fall outside the range:
+ \ifnum \absseclevel < 0
+ \absseclevel = 0
+ \else
+ \ifnum \absseclevel > 3
+ \absseclevel = 3
+ \fi
+ \fi
+ % The heading type:
+ \def\headtype{#1}%
+ \if \headtype U%
+ \ifnum \absseclevel < \unmlevel
+ \chardef\unmlevel = \absseclevel
+ \fi
+ \else
+ % Check for appendix sections:
+ \ifnum \absseclevel = 0
+ \edef\chapheadtype{\headtype}%
+ \else
+ \if \headtype A\if \chapheadtype N%
+ \errmessage{@appendix... within a non-appendix chapter}%
+ \fi\fi
+ \fi
+ % Check for numbered within unnumbered:
+ \ifnum \absseclevel > \unmlevel
+ \def\headtype{U}%
+ \else
+ \chardef\unmlevel = 3
+ \fi
+ \fi
+ % Now print the heading:
+ \if \headtype U%
+ \ifcase\absseclevel
+ \unnumberedzzz{#3}%
+ \or \unnumberedseczzz{#3}%
+ \or \unnumberedsubseczzz{#3}%
+ \or \unnumberedsubsubseczzz{#3}%
+ \fi
+ \else
+ \if \headtype A%
+ \ifcase\absseclevel
+ \appendixzzz{#3}%
+ \or \appendixsectionzzz{#3}%
+ \or \appendixsubseczzz{#3}%
+ \or \appendixsubsubseczzz{#3}%
+ \fi
+ \else
+ \ifcase\absseclevel
+ \chapterzzz{#3}%
+ \or \seczzz{#3}%
+ \or \numberedsubseczzz{#3}%
+ \or \numberedsubsubseczzz{#3}%
+ \fi
+ \fi
+ \fi
+ \suppressfirstparagraphindent
+}
+
+% an interface:
+\def\numhead{\genhead N}
+\def\apphead{\genhead A}
+\def\unnmhead{\genhead U}
+
+% @chapter, @appendix, @unnumbered. Increment top-level counter, reset
+% all lower-level sectioning counters to zero.
+%
+% Also set \chaplevelprefix, which we prepend to @float sequence numbers
+% (e.g., figures), q.v. By default (before any chapter), that is empty.
+\let\chaplevelprefix = \empty
+%
+\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz#1{%
+ % section resetting is \global in case the chapter is in a group, such
+ % as an @include file.
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\chapno by 1
+ %
+ % Used for \float.
+ \gdef\chaplevelprefix{\the\chapno.}%
+ \resetallfloatnos
+ %
+ \message{\putwordChapter\space \the\chapno}%
+ %
+ % Write the actual heading.
+ \chapmacro{#1}{Ynumbered}{\the\chapno}%
+ %
+ % So @section and the like are numbered underneath this chapter.
+ \global\let\section = \numberedsec
+ \global\let\subsection = \numberedsubsec
+ \global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\parseargdef\appendix{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz#1{%
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\appendixno by 1
+ \gdef\chaplevelprefix{\appendixletter.}%
+ \resetallfloatnos
+ %
+ \def\appendixnum{\putwordAppendix\space \appendixletter}%
+ \message{\appendixnum}%
+ %
+ \chapmacro{#1}{Yappendix}{\appendixletter}%
+ %
+ \global\let\section = \appendixsec
+ \global\let\subsection = \appendixsubsec
+ \global\let\subsubsection = \appendixsubsubsec
+}
+
+\outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz#1{%
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\unnumberedno by 1
+ %
+ % Since an unnumbered has no number, no prefix for figures.
+ \global\let\chaplevelprefix = \empty
+ \resetallfloatnos
+ %
+ % This used to be simply \message{#1}, but TeX fully expands the
+ % argument to \message. Therefore, if #1 contained @-commands, TeX
+ % expanded them. For example, in `@unnumbered The @cite{Book}', TeX
+ % expanded @cite (which turns out to cause errors because \cite is meant
+ % to be executed, not expanded).
+ %
+ % Anyway, we don't want the fully-expanded definition of @cite to appear
+ % as a result of the \message, we just want `@cite' itself. We use
+ % \the<toks register> to achieve this: TeX expands \the<toks> only once,
+ % simply yielding the contents of <toks register>. (We also do this for
+ % the toc entries.)
+ \toks0 = {#1}%
+ \message{(\the\toks0)}%
+ %
+ \chapmacro{#1}{Ynothing}{\the\unnumberedno}%
+ %
+ \global\let\section = \unnumberedsec
+ \global\let\subsection = \unnumberedsubsec
+ \global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\parseargdef\centerchap{%
+ % Well, we could do the following in a group, but that would break
+ % an assumption that \chapmacro is called at the outermost level.
+ % Thus we are safer this way: --kasal, 24feb04
+ \let\centerparametersmaybe = \centerparameters
+ \unnmhead0{#1}%
+ \let\centerparametersmaybe = \relax
+}
+
+% @top is like @unnumbered.
+\let\top\unnumbered
+
+% Sections.
+\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz
+\def\seczzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}%
+}
+
+\outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+\outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+\outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Yappendix}%
+ {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Ynothing}%
+ {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Ynumbered}%
+ {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Yappendix}%
+ {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Ynothing}%
+ {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\let\section = \numberedsec
+\let\subsection = \numberedsubsec
+\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and such:
+% 1) We use \vbox rather than the earlier \line to permit
+% overlong headings to fold.
+% 2) \hyphenpenalty is set to 10000 because hyphenation in a
+% heading is obnoxious; this forbids it.
+% 3) Likewise, headings look best if no \parindent is used, and
+% if justification is not attempted. Hence \raggedright.
+
+
+\def\majorheading{%
+ {\advance\chapheadingskip by 10pt \chapbreak }%
+ \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+ {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+ \bigskip \par\penalty 200\relax
+ \suppressfirstparagraphindent
+}
+
+% @heading, @subheading, @subsubheading.
+\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip\chapheadingskip
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{%
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+% Chapter opening.
+%
+% #1 is the text, #2 is the section type (Ynumbered, Ynothing,
+% Yappendix, Yomitfromtoc), #3 the chapter number.
+%
+% To test against our argument.
+\def\Ynothingkeyword{Ynothing}
+\def\Yomitfromtockeyword{Yomitfromtoc}
+\def\Yappendixkeyword{Yappendix}
+%
+\def\chapmacro#1#2#3{%
+ \pchapsepmacro
+ {%
+ \chapfonts \rm
+ %
+ % Have to define \thissection before calling \donoderef, because the
+ % xref code eventually uses it. On the other hand, it has to be called
+ % after \pchapsepmacro, or the headline will change too soon.
+ \gdef\thissection{#1}%
+ \gdef\thischaptername{#1}%
+ %
+ % Only insert the separating space if we have a chapter/appendix
+ % number, and don't print the unnumbered ``number''.
+ \def\temptype{#2}%
+ \ifx\temptype\Ynothingkeyword
+ \setbox0 = \hbox{}%
+ \def\toctype{unnchap}%
+ \gdef\thischapter{#1}%
+ \else\ifx\temptype\Yomitfromtockeyword
+ \setbox0 = \hbox{}% contents like unnumbered, but no toc entry
+ \def\toctype{omit}%
+ \gdef\thischapter{}%
+ \else\ifx\temptype\Yappendixkeyword
+ \setbox0 = \hbox{\putwordAppendix{} #3\enspace}%
+ \def\toctype{app}%
+ % We don't substitute the actual chapter name into \thischapter
+ % because we don't want its macros evaluated now. And we don't
+ % use \thissection because that changes with each section.
+ %
+ \xdef\thischapter{\putwordAppendix{} \appendixletter:
+ \noexpand\thischaptername}%
+ \else
+ \setbox0 = \hbox{#3\enspace}%
+ \def\toctype{numchap}%
+ \xdef\thischapter{\putwordChapter{} \the\chapno:
+ \noexpand\thischaptername}%
+ \fi\fi\fi
+ %
+ % Write the toc entry for this chapter. Must come before the
+ % \donoderef, because we include the current node name in the toc
+ % entry, and \donoderef resets it to empty.
+ \writetocentry{\toctype}{#1}{#3}%
+ %
+ % For pdftex, we have to write out the node definition (aka, make
+ % the pdfdest) after any page break, but before the actual text has
+ % been typeset. If the destination for the pdf outline is after the
+ % text, then jumping from the outline may wind up with the text not
+ % being visible, for instance under high magnification.
+ \donoderef{#2}%
+ %
+ % Typeset the actual heading.
+ \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+ \hangindent=\wd0 \centerparametersmaybe
+ \unhbox0 #1\par}%
+ }%
+ \nobreak\bigskip % no page break after a chapter title
+ \nobreak
+}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerparameters{%
+ \advance\rightskip by 3\rightskip
+ \leftskip = \rightskip
+ \parfillskip = 0pt
+}
+
+
+% I don't think this chapter style is supported any more, so I'm not
+% updating it with the new noderef stuff. We'll see. --karl, 11aug03.
+%
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+%
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\nobreak
+}
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+\def\centerchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt
+ \hfill {\rm #1}\hfill}}\bigskip \par\nobreak
+}
+\def\CHAPFopen{%
+ \global\let\chapmacro=\chfopen
+ \global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles. These macros combine the section number parts and
+% call the generic \sectionheading to do the printing.
+%
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip{-1000}}
+
+% Subsection titles.
+\newskip\subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}}
+
+% Subsubsection titles.
+\def\subsubsecheadingskip{\subsecheadingskip}
+\def\subsubsecheadingbreak{\subsecheadingbreak}
+
+
+% Print any size, any type, section title.
+%
+% #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is
+% the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the
+% section number.
+%
+\def\sectionheading#1#2#3#4{%
+ {%
+ % Switch to the right set of fonts.
+ \csname #2fonts\endcsname \rm
+ %
+ % Insert space above the heading.
+ \csname #2headingbreak\endcsname
+ %
+ % Only insert the space after the number if we have a section number.
+ \def\sectionlevel{#2}%
+ \def\temptype{#3}%
+ %
+ \ifx\temptype\Ynothingkeyword
+ \setbox0 = \hbox{}%
+ \def\toctype{unn}%
+ \gdef\thissection{#1}%
+ \else\ifx\temptype\Yomitfromtockeyword
+ % for @headings -- no section number, don't include in toc,
+ % and don't redefine \thissection.
+ \setbox0 = \hbox{}%
+ \def\toctype{omit}%
+ \let\sectionlevel=\empty
+ \else\ifx\temptype\Yappendixkeyword
+ \setbox0 = \hbox{#4\enspace}%
+ \def\toctype{app}%
+ \gdef\thissection{#1}%
+ \else
+ \setbox0 = \hbox{#4\enspace}%
+ \def\toctype{num}%
+ \gdef\thissection{#1}%
+ \fi\fi\fi
+ %
+ % Write the toc entry (before \donoderef). See comments in \chfplain.
+ \writetocentry{\toctype\sectionlevel}{#1}{#4}%
+ %
+ % Write the node reference (= pdf destination for pdftex).
+ % Again, see comments in \chfplain.
+ \donoderef{#3}%
+ %
+ % Output the actual section heading.
+ \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+ \hangindent=\wd0 % zero if no section number
+ \unhbox0 #1}%
+ }%
+ % Add extra space after the heading -- half of whatever came above it.
+ % Don't allow stretch, though.
+ \kern .5 \csname #2headingskip\endcsname
+ %
+ % Do not let the kern be a potential breakpoint, as it would be if it
+ % was followed by glue.
+ \nobreak
+ %
+ % We'll almost certainly start a paragraph next, so don't let that
+ % glue accumulate. (Not a breakpoint because it's preceded by a
+ % discardable item.)
+ \vskip-\parskip
+ %
+ % This is purely so the last item on the list is a known \penalty >
+ % 10000. This is so \startdefun can avoid allowing breakpoints after
+ % section headings. Otherwise, it would insert a valid breakpoint between:
+ %
+ % @section sec-whatever
+ % @deffn def-whatever
+ \penalty 10001
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.
+%
+% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno}
+% We append the current node name (if any) and page number as additional
+% arguments for the \{chap,sec,...}entry macros which will eventually
+% read this. The node name is used in the pdf outlines as the
+% destination to jump to.
+%
+% We open the .toc file for writing here instead of at @setfilename (or
+% any other fixed time) so that @contents can be anywhere in the document.
+% But if #1 is `omit', then we don't do anything. This is used for the
+% table of contents chapter openings themselves.
+%
+\newif\iftocfileopened
+\def\omitkeyword{omit}%
+%
+\def\writetocentry#1#2#3{%
+ \edef\writetoctype{#1}%
+ \ifx\writetoctype\omitkeyword \else
+ \iftocfileopened\else
+ \immediate\openout\tocfile = \jobname.toc
+ \global\tocfileopenedtrue
+ \fi
+ %
+ \iflinks
+ \toks0 = {#2}%
+ \toks2 = \expandafter{\lastnode}%
+ \edef\temp{\write\tocfile{\realbackslash #1entry{\the\toks0}{#3}%
+ {\the\toks2}{\noexpand\folio}}}%
+ \temp
+ \fi
+ \fi
+ %
+ % Tell \shipout to create a pdf destination on each page, if we're
+ % writing pdf. These are used in the table of contents. We can't
+ % just write one on every page because the title pages are numbered
+ % 1 and 2 (the page numbers aren't printed), and so are the first
+ % two pages of the document. Thus, we'd have two destinations named
+ % `1', and two named `2'.
+ \ifpdf \global\pdfmakepagedesttrue \fi
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Prepare to read what we've written to \tocfile.
+%
+\def\startcontents#1{%
+ % If @setchapternewpage on, and @headings double, the contents should
+ % start on an odd page, unlike chapters. Thus, we maintain
+ % \contentsalignmacro in parallel with \pagealignmacro.
+ % From: Torbjorn Granlund <tege@matematik.su.se>
+ \contentsalignmacro
+ \immediate\closeout\tocfile
+ %
+ % Don't need to put `Contents' or `Short Contents' in the headline.
+ % It is abundantly clear what they are.
+ \def\thischapter{}%
+ \chapmacro{#1}{Yomitfromtoc}{}%
+ %
+ \savepageno = \pageno
+ \begingroup % Set up to handle contents files properly.
+ \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
+ % We can't do this, because then an actual ^ in a section
+ % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97.
+ %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+ %
+ % Roman numerals for page numbers.
+ \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi
+}
+
+
+% Normal (long) toc.
+\def\contents{%
+ \startcontents{\putwordTOC}%
+ \openin 1 \jobname.toc
+ \ifeof 1 \else
+ \input \jobname.toc
+ \fi
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \ifeof 1 \else
+ \pdfmakeoutlines
+ \fi
+ \closein 1
+ \endgroup
+ \lastnegativepageno = \pageno
+ \global\pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+ \startcontents{\putwordShortTOC}%
+ %
+ \let\numchapentry = \shortchapentry
+ \let\appentry = \shortchapentry
+ \let\unnchapentry = \shortunnchapentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf
+ \let\sl=\shortcontsl \let\tt=\shortconttt
+ \rm
+ \hyphenpenalty = 10000
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\numsecentry##1##2##3##4{}
+ \let\appsecentry = \numsecentry
+ \let\unnsecentry = \numsecentry
+ \let\numsubsecentry = \numsecentry
+ \let\appsubsecentry = \numsecentry
+ \let\unnsubsecentry = \numsecentry
+ \let\numsubsubsecentry = \numsecentry
+ \let\appsubsubsecentry = \numsecentry
+ \let\unnsubsubsecentry = \numsecentry
+ \openin 1 \jobname.toc
+ \ifeof 1 \else
+ \input \jobname.toc
+ \fi
+ \closein 1
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \endgroup
+ \lastnegativepageno = \pageno
+ \global\pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g., `A' for an appendix, or `3' for a chapter.
+%
+\def\shortchaplabel#1{%
+ % This space should be enough, since a single number is .5em, and the
+ % widest letter (M) is 1em, at least in the Computer Modern fonts.
+ % But use \hss just in case.
+ % (This space doesn't include the extra space that gets added after
+ % the label; that gets put in by \shortchapentry above.)
+ %
+ % We'd like to right-justify chapter numbers, but that looks strange
+ % with appendix letters. And right-justifying numbers and
+ % left-justifying letters looks strange when there is less than 10
+ % chapters. Have to read the whole toc once to know how many chapters
+ % there are before deciding ...
+ \hbox to 1em{#1\hss}%
+}
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapters, in the main contents.
+\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}}
+%
+% Chapters, in the short toc.
+% See comments in \dochapentry re vbox and related settings.
+\def\shortchapentry#1#2#3#4{%
+ \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}%
+}
+
+% Appendices, in the main contents.
+% Need the word Appendix, and a fixed-size box.
+%
+\def\appendixbox#1{%
+ % We use M since it's probably the widest letter.
+ \setbox0 = \hbox{\putwordAppendix{} M}%
+ \hbox to \wd0{\putwordAppendix{} #1\hss}}
+%
+\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}}
+
+% Unnumbered chapters.
+\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}}
+\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}}
+
+% Sections.
+\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}}
+\let\appsecentry=\numsecentry
+\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}}
+
+% Subsections.
+\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsecentry=\numsubsecentry
+\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}}
+
+% And subsubsections.
+\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsubsecentry=\numsubsubsecentry
+\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}}
+
+% This parameter controls the indentation of the various levels.
+% Same as \defaultparindent.
+\newdimen\tocindent \tocindent = 15pt
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+ \begingroup
+ \chapentryfonts
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+ \endgroup
+ \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+ \secentryfonts \leftskip=\tocindent
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+ \subsecentryfonts \leftskip=2\tocindent
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+ \subsubsecentryfonts \leftskip=3\tocindent
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+% We use the same \entry macro as for the index entries.
+\let\tocentry = \entry
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\def\subsecentryfonts{\textfonts}
+\def\subsubsecentryfonts{\textfonts}
+
+
+\message{environments,}
+% @foo ... @end foo.
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+%
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+%
+\def\point{$\star$}
+\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% The @error{} command.
+% Adapted from the TeXbook's \boxit.
+%
+\newbox\errorbox
+%
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+%
+\setbox\errorbox=\hbox to \dimen0{\hfil
+ \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+ \advance\hsize by -2\dimen2 % Rules.
+ \vbox{%
+ \hrule height\dimen2
+ \hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
+ \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+ \kern3pt\vrule width\dimen2}% Space to right.
+ \hrule height\dimen2}
+ \hfil}
+%
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\envdef\tex{%
+ \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+ \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+ \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie
+ \catcode `\%=14
+ \catcode `\+=\other
+ \catcode `\"=\other
+ \catcode `\|=\other
+ \catcode `\<=\other
+ \catcode `\>=\other
+ \escapechar=`\\
+ %
+ \let\b=\ptexb
+ \let\bullet=\ptexbullet
+ \let\c=\ptexc
+ \let\,=\ptexcomma
+ \let\.=\ptexdot
+ \let\dots=\ptexdots
+ \let\equiv=\ptexequiv
+ \let\!=\ptexexclam
+ \let\i=\ptexi
+ \let\indent=\ptexindent
+ \let\noindent=\ptexnoindent
+ \let\{=\ptexlbrace
+ \let\+=\tabalign
+ \let\}=\ptexrbrace
+ \let\/=\ptexslash
+ \let\*=\ptexstar
+ \let\t=\ptext
+ %
+ \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+ \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+ \def\@{@}%
+}
+% There is no need to define \Etex.
+
+% Define @lisp ... @end lisp.
+% @lisp environment forms a group so it can rebind things,
+% including the definition of @end lisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments. \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical. We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip.
+%
+\def\aboveenvbreak{{%
+ % =10000 instead of <10000 because of a special case in \itemzzz and
+ % \sectionheading, q.v.
+ \ifnum \lastpenalty=10000 \else
+ \advance\envskipamount by \parskip
+ \endgraf
+ \ifdim\lastskip<\envskipamount
+ \removelastskip
+ % it's not a good place to break if the last penalty was \nobreak
+ % or better ...
+ \ifnum\lastpenalty<10000 \penalty-50 \fi
+ \vskip\envskipamount
+ \fi
+ \fi
+}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+ \ctl\leaders\hrule height\circthick\hfil\ctr
+ \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+ \cbl\leaders\hrule height\circthick\hfil\cbr
+ \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\envdef\cartouche{%
+ \ifhmode\par\fi % can't be in the midst of a paragraph.
+ \startsavinginserts
+ \lskip=\leftskip \rskip=\rightskip
+ \leftskip=0pt\rightskip=0pt % we want these *outside*.
+ \cartinner=\hsize \advance\cartinner by-\lskip
+ \advance\cartinner by-\rskip
+ \cartouter=\hsize
+ \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+ % side, and for 6pt waste from
+ % each corner char, and rule thickness
+ \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+ % Flag to tell @lisp, etc., not to narrow margin.
+ \let\nonarrowing=\comment
+ \vbox\bgroup
+ \baselineskip=0pt\parskip=0pt\lineskip=0pt
+ \carttop
+ \hbox\bgroup
+ \hskip\lskip
+ \vrule\kern3pt
+ \vbox\bgroup
+ \kern3pt
+ \hsize=\cartinner
+ \baselineskip=\normbskip
+ \lineskip=\normlskip
+ \parskip=\normpskip
+ \vskip -\parskip
+ \comment % For explanation, see the end of \def\group.
+}
+\def\Ecartouche{%
+ \ifhmode\par\fi
+ \kern3pt
+ \egroup
+ \kern3pt\vrule
+ \hskip\rskip
+ \egroup
+ \cartbot
+ \egroup
+ \checkinserts
+}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+ \aboveenvbreak
+ \hfuzz = 12pt % Don't be fussy
+ \sepspaces % Make spaces be word-separators rather than space tokens.
+ \let\par = \lisppar % don't ignore blank lines
+ \obeylines % each line of input is a line of output
+ \parskip = 0pt
+ \parindent = 0pt
+ \emergencystretch = 0pt % don't try to avoid overfull boxes
+ % @cartouche defines \nonarrowing to inhibit narrowing
+ % at next level down.
+ \ifx\nonarrowing\relax
+ \advance \leftskip by \lispnarrowing
+ \exdentamount=\lispnarrowing
+ \fi
+ \let\exdent=\nofillexdent
+}
+
+% If you want all examples etc. small: @set dispenvsize small.
+% If you want even small examples the full size: @set dispenvsize nosmall.
+% This affects the following displayed environments:
+% @example, @display, @format, @lisp
+%
+\def\smallword{small}
+\def\nosmallword{nosmall}
+\let\SETdispenvsize\relax
+\def\setnormaldispenv{%
+ \ifx\SETdispenvsize\smallword
+ \smallexamplefonts \rm
+ \fi
+}
+\def\setsmalldispenv{%
+ \ifx\SETdispenvsize\nosmallword
+ \else
+ \smallexamplefonts \rm
+ \fi
+}
+
+% We often define two environments, @foo and @smallfoo.
+% Let's do it by one command:
+\def\makedispenv #1#2{
+ \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}
+ \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}
+ \expandafter\let\csname E#1\endcsname \afterenvbreak
+ \expandafter\let\csname Esmall#1\endcsname \afterenvbreak
+}
+
+% Define two synonyms:
+\def\maketwodispenvs #1#2#3{
+ \makedispenv{#1}{#3}
+ \makedispenv{#2}{#3}
+}
+
+% @lisp: indented, narrowed, typewriter font; @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvs {lisp}{example}{%
+ \nonfillstart
+ \tt
+ \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+ \gobble % eat return
+}
+
+% @display/@smalldisplay: same as @lisp except keep current font.
+%
+\makedispenv {display}{%
+ \nonfillstart
+ \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenv{format}{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \gobble
+}
+
+% @flushleft: same as @format, but doesn't obey \SETdispenvsize.
+\envdef\flushleft{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \gobble
+}
+\let\Eflushleft = \afterenvbreak
+
+% @flushright.
+%
+\envdef\flushright{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \advance\leftskip by 0pt plus 1fill
+ \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins. We keep \parskip nonzero in general, since
+% we're doing normal filling. So, when using \aboveenvbreak and
+% \afterenvbreak, temporarily make \parskip 0.
+%
+\envdef\quotation{%
+ {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+ \parindent=0pt
+ %
+ % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+ \ifx\nonarrowing\relax
+ \advance\leftskip by \lispnarrowing
+ \advance\rightskip by \lispnarrowing
+ \exdentamount = \lispnarrowing
+ \let\nonarrowing = \relax
+ \fi
+ \parsearg\quotationlabel
+}
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+ \par
+ \ifx\quotationauthor\undefined\else
+ % indent a bit.
+ \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+ \fi
+ {\parskip=0pt \afterenvbreak}%
+}
+
+% If we're given an argument, typeset it in bold with a colon after.
+\def\quotationlabel#1{%
+ \def\temp{#1}%
+ \ifx\temp\empty \else
+ {\bf #1: }%
+ \fi
+}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>}
+% If we want to allow any <char> as delimiter,
+% we need the curly braces so that makeinfo sees the @verb command, eg:
+% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org
+%
+% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook.
+%
+% [Knuth] p.344; only we need to do the other characters Texinfo sets
+% active too. Otherwise, they get lost as the first character on a
+% verbatim line.
+\def\dospecials{%
+ \do\ \do\\\do\{\do\}\do\$\do\&%
+ \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~%
+ \do\<\do\>\do\|\do\@\do+\do\"%
+}
+%
+% [Knuth] p. 380
+\def\uncatcodespecials{%
+ \def\do##1{\catcode`##1=\other}\dospecials}
+%
+% [Knuth] pp. 380,381,391
+% Disable Spanish ligatures ?` and !` of \tt font
+\begingroup
+ \catcode`\`=\active\gdef`{\relax\lq}
+\endgroup
+%
+% Setup for the @verb command.
+%
+% Eight spaces for a tab
+\begingroup
+ \catcode`\^^I=\active
+ \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }}
+\endgroup
+%
+\def\setupverb{%
+ \tt % easiest (and conventionally used) font for verbatim
+ \def\par{\leavevmode\endgraf}%
+ \catcode`\`=\active
+ \tabeightspaces
+ % Respect line breaks,
+ % print special symbols as themselves, and
+ % make each space count
+ % must do in this order:
+ \obeylines \uncatcodespecials \sepspaces
+}
+
+% Setup for the @verbatim environment
+%
+% Real tab expansion
+\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount
+%
+\def\starttabbox{\setbox0=\hbox\bgroup}
+\begingroup
+ \catcode`\^^I=\active
+ \gdef\tabexpand{%
+ \catcode`\^^I=\active
+ \def^^I{\leavevmode\egroup
+ \dimen0=\wd0 % the width so far, or since the previous tab
+ \divide\dimen0 by\tabw
+ \multiply\dimen0 by\tabw % compute previous multiple of \tabw
+ \advance\dimen0 by\tabw % advance to next multiple of \tabw
+ \wd0=\dimen0 \box0 \starttabbox
+ }%
+ }
+\endgroup
+\def\setupverbatim{%
+ \nonfillstart
+ \advance\leftskip by -\defbodyindent
+ % Easiest (and conventionally used) font for verbatim
+ \tt
+ \def\par{\leavevmode\egroup\box0\endgraf}%
+ \catcode`\`=\active
+ \tabexpand
+ % Respect line breaks,
+ % print special symbols as themselves, and
+ % make each space count
+ % must do in this order:
+ \obeylines \uncatcodespecials \sepspaces
+ \everypar{\starttabbox}%
+}
+
+% Do the @verb magic: verbatim text is quoted by unique
+% delimiter characters. Before first delimiter expect a
+% right brace, after last delimiter expect closing brace:
+%
+% \def\doverb'{'<char>#1<char>'}'{#1}
+%
+% [Knuth] p. 382; only eat outer {}
+\begingroup
+ \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other
+ \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next]
+\endgroup
+%
+\def\verb{\begingroup\setupverb\doverb}
+%
+%
+% Do the @verbatim magic: define the macro \doverbatim so that
+% the (first) argument ends when '@end verbatim' is reached, ie:
+%
+% \def\doverbatim#1@end verbatim{#1}
+%
+% For Texinfo it's a lot easier than for LaTeX,
+% because texinfo's \verbatim doesn't stop at '\end{verbatim}':
+% we need not redefine '\', '{' and '}'.
+%
+% Inspired by LaTeX's verbatim command set [latex.ltx]
+%
+\begingroup
+ \catcode`\ =\active
+ \obeylines %
+ % ignore everything up to the first ^^M, that's the newline at the end
+ % of the @verbatim input line itself. Otherwise we get an extra blank
+ % line in the output.
+ \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}%
+ % We really want {...\end verbatim} in the body of the macro, but
+ % without the active space; thus we have to use \xdef and \gobble.
+\endgroup
+%
+\envdef\verbatim{%
+ \setupverbatim\doverbatim
+}
+\let\Everbatim = \afterenvbreak
+
+
+% @verbatiminclude FILE - insert text of file in verbatim environment.
+%
+\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude}
+%
+\def\doverbatiminclude#1{%
+ {%
+ \makevalueexpandable
+ \setupverbatim
+ \input #1
+ \afterenvbreak
+ }%
+}
+
+% @copying ... @end copying.
+% Save the text away for @insertcopying later.
+%
+% We save the uninterpreted tokens, rather than creating a box.
+% Saving the text in a box would be much easier, but then all the
+% typesetting commands (@smallbook, font changes, etc.) have to be done
+% beforehand -- and a) we want @copying to be done first in the source
+% file; b) letting users define the frontmatter in as flexible order as
+% possible is very desirable.
+%
+\def\copying{\checkenv{}\begingroup\scanargctxt\docopying}
+\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
+%
+\def\insertcopying{%
+ \begingroup
+ \parindent = 0pt % paragraph indentation looks wrong on title page
+ \scanexp\copyingtext
+ \endgroup
+}
+
+\message{defuns,}
+% @defun etc.
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+% Start the processing of @deffn:
+\def\startdefun{%
+ \ifnum\lastpenalty<10000
+ \medbreak
+ \else
+ % If there are two @def commands in a row, we'll have a \nobreak,
+ % which is there to keep the function description together with its
+ % header. But if there's nothing but headers, we need to allow a
+ % break somewhere. Check specifically for penalty 10002, inserted
+ % by \defargscommonending, instead of 10000, since the sectioning
+ % commands also insert a nobreak penalty, and we don't want to allow
+ % a break between a section heading and a defun.
+ %
+ \ifnum\lastpenalty=10002 \penalty2000 \fi
+ %
+ % Similarly, after a section heading, do not allow a break.
+ % But do insert the glue.
+ \medskip % preceded by discardable penalty, so not a breakpoint
+ \fi
+ %
+ \parindent=0in
+ \advance\leftskip by \defbodyindent
+ \exdentamount=\defbodyindent
+}
+
+\def\dodefunx#1{%
+ % First, check whether we are in the right environment:
+ \checkenv#1%
+ %
+ % As above, allow line break if we have multiple x headers in a row.
+ % It's not a great place, though.
+ \ifnum\lastpenalty=10002 \penalty3000 \fi
+ %
+ % And now, it's time to reuse the body of the original defun:
+ \expandafter\gobbledefun#1%
+}
+\def\gobbledefun#1\startdefun{}
+
+% \printdefunline \deffnheader{text}
+%
+\def\printdefunline#1#2{%
+ \begingroup
+ % call \deffnheader:
+ #1#2 \endheader
+ % common ending:
+ \interlinepenalty = 10000
+ \advance\rightskip by 0pt plus 1fil
+ \endgraf
+ \nobreak\vskip -\parskip
+ \penalty 10002 % signal to \startdefun and \dodefunx
+ % Some of the @defun-type tags do not enable magic parentheses,
+ % rendering the following check redundant. But we don't optimize.
+ \checkparencounts
+ \endgroup
+}
+
+\def\Edefun{\endgraf\medbreak}
+
+% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
+% the only thing remainnig is to define \deffnheader.
+%
+\def\makedefun#1{%
+ \expandafter\let\csname E#1\endcsname = \Edefun
+ \edef\temp{\noexpand\domakedefun
+ \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
+ \temp
+}
+
+% \domakedefun \deffn \deffnx \deffnheader
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+ \envdef#1{%
+ \startdefun
+ \parseargusing\activeparens{\printdefunline#3}%
+ }%
+ \def#2{\dodefunx#1}%
+ \def#3%
+}
+
+%%% Untyped functions:
+
+% @deffn category name args
+\makedefun{deffn}{\deffngeneral{}}
+
+% @deffn category class name args
+\makedefun{defop}#1 {\defopon{#1\ \putwordon}}
+
+% \defopon {category on}class name args
+\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deffngeneral {subind}category name args
+%
+\def\deffngeneral#1#2 #3 #4\endheader{%
+ % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}.
+ \dosubind{fn}{\code{#3}}{#1}%
+ \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}%
+}
+
+%%% Typed functions:
+
+% @deftypefn category type name args
+\makedefun{deftypefn}{\deftypefngeneral{}}
+
+% @deftypeop category class type name args
+\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}}
+
+% \deftypeopon {category on}class type name args
+\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypefngeneral {subind}category type name args
+%
+\def\deftypefngeneral#1#2 #3 #4 #5\endheader{%
+ \dosubind{fn}{\code{#4}}{#1}%
+ \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+%%% Typed variables:
+
+% @deftypevr category type var args
+\makedefun{deftypevr}{\deftypecvgeneral{}}
+
+% @deftypecv category class type var args
+\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
+
+% \deftypecvof {category of}class type var args
+\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypecvgeneral {subind}category type var args
+%
+\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
+ \dosubind{vr}{\code{#4}}{#1}%
+ \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+%%% Untyped variables:
+
+% @defvr category var args
+\makedefun{defvr}#1 {\deftypevrheader{#1} {} }
+
+% @defcv category class var args
+\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
+
+% \defcvof {category of}class var args
+\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+
+%%% Type:
+% @deftp category name args
+\makedefun{deftp}#1 #2 #3\endheader{%
+ \doind{tp}{\code{#2}}%
+ \defname{#1}{}{#2}\defunargs{#3\unskip}%
+}
+
+% Remaining @defun-like shortcuts:
+\makedefun{defun}{\deffnheader{\putwordDeffunc} }
+\makedefun{defmac}{\deffnheader{\putwordDefmac} }
+\makedefun{defspec}{\deffnheader{\putwordDefspec} }
+\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} }
+\makedefun{defvar}{\defvrheader{\putwordDefvar} }
+\makedefun{defopt}{\defvrheader{\putwordDefopt} }
+\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
+\makedefun{defmethod}{\defopon\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
+\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+
+% \defname, which formats the name of the @def (not the args).
+% #1 is the category, such as "Function".
+% #2 is the return type, if any.
+% #3 is the function name.
+%
+% We are followed by (but not passed) the arguments, if any.
+%
+\def\defname#1#2#3{%
+ % Get the values of \leftskip and \rightskip as they were outside the @def...
+ \advance\leftskip by -\defbodyindent
+ %
+ % How we'll format the type name. Putting it in brackets helps
+ % distinguish it from the body text that may end up on the next line
+ % just below it.
+ \def\temp{#1}%
+ \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi}
+ %
+ % Figure out line sizes for the paragraph shape.
+ % The first line needs space for \box0; but if \rightskip is nonzero,
+ % we need only space for the part of \box0 which exceeds it:
+ \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip
+ % The continuations:
+ \dimen2=\hsize \advance\dimen2 by -\defargsindent
+ % (plain.tex says that \dimen1 should be used only as global.)
+ \parshape 2 0in \dimen0 \defargsindent \dimen2
+ %
+ % Put the type name to the right margin.
+ \noindent
+ \hbox to 0pt{%
+ \hfil\box0 \kern-\hsize
+ % \hsize has to be shortened this way:
+ \kern\leftskip
+ % Intentionally do not respect \rightskip, since we need the space.
+ }%
+ %
+ % Allow all lines to be underfull without complaint:
+ \tolerance=10000 \hbadness=10000
+ \exdentamount=\defbodyindent
+ {%
+ % defun fonts. We use typewriter by default (used to be bold) because:
+ % . we're printing identifiers, they should be in tt in principle.
+ % . in languages with many accents, such as Czech or French, it's
+ % common to leave accents off identifiers. The result looks ok in
+ % tt, but exceedingly strange in rm.
+ % . we don't want -- and --- to be treated as ligatures.
+ % . this still does not fix the ?` and !` ligatures, but so far no
+ % one has made identifiers using them :).
+ \df \tt
+ \def\temp{#2}% return value type
+ \ifx\temp\empty\else \tclose{\temp} \fi
+ #3% output function name
+ }%
+ {\rm\enskip}% hskip 0.5 em of \tenrm
+ %
+ \boldbrax
+ % arguments will be output next, if any.
+}
+
+% Print arguments in slanted roman (not ttsl), inconsistently with using
+% tt for the name. This is because literal text is sometimes needed in
+% the argument list (groff manual), and ttsl and tt are not very
+% distinguishable. Prevent hyphenation at `-' chars.
+%
+\def\defunargs#1{%
+ % use sl by default (not ttsl),
+ % tt for the names.
+ \df \sl \hyphenchar\font=0
+ %
+ % On the other hand, if an argument has two dashes (for instance), we
+ % want a way to get ttsl. Let's try @var for that.
+ \let\var=\ttslanted
+ #1%
+ \sl\hyphenchar\font=45
+}
+
+% We want ()&[] to print specially on the defun line.
+%
+\def\activeparens{%
+ \catcode`\(=\active \catcode`\)=\active
+ \catcode`\[=\active \catcode`\]=\active
+ \catcode`\&=\active
+}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+% Be sure that we always have a definition for `(', etc. For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+{
+ \activeparens
+ \global\let(=\lparen \global\let)=\rparen
+ \global\let[=\lbrack \global\let]=\rbrack
+ \global\let& = \&
+
+ \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+ \gdef\magicamp{\let&=\amprm}
+}
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#1 }}
+
+\def\parenfont{%
+ \ifampseen
+ % At the first level, print parens in roman,
+ % otherwise use the default font.
+ \ifnum \parencount=1 \rm \fi
+ \else
+ % The \sf parens (in \boldbrax) actually are a little bolder than
+ % the contained text. This is especially needed for [ and ] .
+ \sf
+ \fi
+}
+\def\infirstlevel#1{%
+ \ifampseen
+ \ifnum\parencount=1
+ #1%
+ \fi
+ \fi
+}
+\def\bfafterword#1 {#1 \bf}
+
+\def\opnr{%
+ \global\advance\parencount by 1
+ {\parenfont(}%
+ \infirstlevel \bfafterword
+}
+\def\clnr{%
+ {\parenfont)}%
+ \infirstlevel \sl
+ \global\advance\parencount by -1
+}
+
+\newcount\brackcount
+\def\lbrb{%
+ \global\advance\brackcount by 1
+ {\bf[}%
+}
+\def\rbrb{%
+ {\bf]}%
+ \global\advance\brackcount by -1
+}
+
+\def\checkparencounts{%
+ \ifnum\parencount=0 \else \badparencount \fi
+ \ifnum\brackcount=0 \else \badbrackcount \fi
+}
+\def\badparencount{%
+ \errmessage{Unbalanced parentheses in @def}%
+ \global\parencount=0
+}
+\def\badbrackcount{%
+ \errmessage{Unbalanced square braces in @def}%
+ \global\brackcount=0
+}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\undefined
+ \newwrite\macscribble
+ \def\scantokens#1{%
+ \toks0={#1}%
+ \immediate\openout\macscribble=\jobname.tmp
+ \immediate\write\macscribble{\the\toks0}%
+ \immediate\closeout\macscribble
+ \input \jobname.tmp
+ }
+\fi
+
+\def\scanmacro#1{%
+ \begingroup
+ \newlinechar`\^^M
+ \let\xeatspaces\eatspaces
+ % Undo catcode changes of \startcontents and \doprintindex
+ % When called from @insertcopying or (short)caption, we need active
+ % backslash to get it printed correctly. Previously, we had
+ % \catcode`\\=\other instead. We'll see whether a problem appears
+ % with macro expansion. --kasal, 19aug04
+ \catcode`\@=0 \catcode`\\=\active \escapechar=`\@
+ % ... and \example
+ \spaceisspace
+ %
+ % Append \endinput to make sure that TeX does not see the ending newline.
+ %
+ % I've verified that it is necessary both for e-TeX and for ordinary TeX
+ % --kasal, 29nov03
+ \scantokens{#1\endinput}%
+ \endgroup
+}
+
+\def\scanexp#1{%
+ \edef\temp{\noexpand\scanmacro{#1}}%
+ \temp
+}
+
+\newcount\paramno % Count of parameters
+\newtoks\macname % Macro name
+\newif\ifrecursive % Is it recursive?
+\def\macrolist{} % List of all defined macros in the form
+ % \do\macro1\do\macro2...
+
+% Utility routines.
+% This does \let #1 = #2, with \csnames; that is,
+% \let \csname#1\endcsname = \csname#2\endcsname
+% (except of course we have to play expansion games).
+%
+\def\cslet#1#2{%
+ \expandafter\let
+ \csname#1\expandafter\endcsname
+ \csname#2\endcsname
+}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=\other \catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \.
+
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+
+\def\scanctxt{%
+ \catcode`\"=\other
+ \catcode`\+=\other
+ \catcode`\<=\other
+ \catcode`\>=\other
+ \catcode`\@=\other
+ \catcode`\^=\other
+ \catcode`\_=\other
+ \catcode`\|=\other
+ \catcode`\~=\other
+}
+
+\def\scanargctxt{%
+ \scanctxt
+ \catcode`\\=\other
+ \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{%
+ \scanctxt
+ \catcode`\{=\other
+ \catcode`\}=\other
+ \catcode`\^^M=\other
+ \usembodybackslash
+}
+
+\def\macroargctxt{%
+ \scanctxt
+ \catcode`\\=\other
+}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+ \getargs{#1}% now \macname is the macname and \argl the arglist
+ \ifx\argl\empty % no arguments
+ \paramno=0%
+ \else
+ \expandafter\parsemargdef \argl;%
+ \fi
+ \if1\csname ismacro.\the\macname\endcsname
+ \message{Warning: redefining \the\macname}%
+ \else
+ \expandafter\ifx\csname \the\macname\endcsname \relax
+ \else \errmessage{Macro name \the\macname\space already defined}\fi
+ \global\cslet{macsave.\the\macname}{\the\macname}%
+ \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+ % Add the macroname to \macrolist
+ \toks0 = \expandafter{\macrolist\do}%
+ \xdef\macrolist{\the\toks0
+ \expandafter\noexpand\csname\the\macname\endcsname}%
+ \fi
+ \begingroup \macrobodyctxt
+ \ifrecursive \expandafter\parsermacbody
+ \else \expandafter\parsemacbody
+ \fi}
+
+\parseargdef\unmacro{%
+ \if1\csname ismacro.#1\endcsname
+ \global\cslet{#1}{macsave.#1}%
+ \global\expandafter\let \csname ismacro.#1\endcsname=0%
+ % Remove the macro name from \macrolist:
+ \begingroup
+ \expandafter\let\csname#1\endcsname \relax
+ \let\do\unmacrodo
+ \xdef\macrolist{\macrolist}%
+ \endgroup
+ \else
+ \errmessage{Macro #1 not defined}%
+ \fi
+}
+
+% Called by \do from \dounmacro on each macro. The idea is to omit any
+% macro definitions that have been changed to \relax.
+%
+\def\unmacrodo#1{%
+ \ifx#1\relax
+ % remove this
+ \else
+ \noexpand\do \noexpand #1%
+ \fi
+}
+
+% This makes use of the obscure feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname #1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+
+% Parse the optional {params} list. Set up \paramno and \paramlist
+% so \defmacro knows what to do. Define \macarg.blah for each blah
+% in the params list, to be ##N where N is the position in that list.
+% That gets used by \mbodybackslash (above).
+
+% We need to get `macro parameter char #' into several definitions.
+% The technique used is stolen from LaTeX: let \hash be something
+% unexpandable, insert that wherever you need a #, and then redefine
+% it to # just before using the token list produced.
+%
+% The same technique is used to protect \eatspaces till just before
+% the macro is used.
+
+\def\parsemargdef#1;{\paramno=0\def\paramlist{}%
+ \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,}
+\def\parsemargdefxxx#1,{%
+ \if#1;\let\next=\relax
+ \else \let\next=\parsemargdefxxx
+ \advance\paramno by 1%
+ \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+ {\xeatspaces{\hash\the\paramno}}%
+ \edef\paramlist{\paramlist\hash\the\paramno,}%
+ \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+
+% This defines the macro itself. There are six cases: recursive and
+% nonrecursive macros of zero, one, and many arguments.
+% Much magic with \expandafter here.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in; @include reads the file inside a group.
+\def\defmacro{%
+ \let\hash=##% convert placeholders to macro parameter chars
+ \ifrecursive
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\scanmacro{\temp}}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+ \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+ \egroup\noexpand\scanmacro{\temp}}%
+ \else % many
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\csname\the\macname xx\endcsname}%
+ \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname xxx\endcsname
+ \paramlist{\egroup\noexpand\scanmacro{\temp}}%
+ \fi
+ \else
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+ \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+ \egroup
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \else % many
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \expandafter\noexpand\csname\the\macname xx\endcsname}%
+ \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname xxx\endcsname
+ \paramlist{%
+ \egroup
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \fi
+ \fi}
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+% \braceorline decides whether the next nonwhitespace character is a
+% {. If so it reads up to the closing }, if not, it reads the whole
+% line. Whatever was read is then fed to the next control sequence
+% as an argument (by \parsebrace or \parsearg)
+\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+ \ifx\nchar\bgroup\else
+ \expandafter\parsearg
+ \fi \next}
+
+% We want to disable all macros during \shipout so that they are not
+% expanded by \write.
+\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}%
+ \edef\next{\macrolist}\expandafter\endgroup\next}
+
+% For \indexnofonts, we need to get rid of all macros, leaving only the
+% arguments (if present). Of course this is not nearly correct, but it
+% is the best we can do for now. makeinfo does not expand macros in the
+% argument to @deffn, which ends up writing an index entry, and texindex
+% isn't prepared for an index sort entry that starts with \.
+%
+% Since macro invocations are followed by braces, we can just redefine them
+% to take a single TeX argument. The case of a macro invocation that
+% goes to end-of-line is not handled.
+%
+\def\emptyusermacros{\begingroup
+ \def\do##1{\let\noexpand##1=\noexpand\asis}%
+ \edef\next{\macrolist}\expandafter\endgroup\next}
+
+
+% @alias.
+% We need some trickery to remove the optional spaces around the equal
+% sign. Just make them active and then expand them all to nothing.
+\def\alias{\parseargusing\obeyspaces\aliasxxx}
+\def\aliasxxx #1{\aliasyyy#1\relax}
+\def\aliasyyy #1=#2\relax{%
+ {%
+ \expandafter\let\obeyedspace=\empty
+ \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}%
+ }%
+ \next
+}
+
+
+\message{cross references,}
+
+\newwrite\auxfile
+
+\newif\ifhavexrefs % True if xref values are known.
+\newif\ifwarnedxrefs % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+ node \samp{\ignorespaces#1{}}}
+
+% @node's only job in TeX is to define \lastnode, which is used in
+% cross-references. The @node line might or might not have commas, and
+% might or might not have spaces before the first comma, like:
+% @node foo , bar , ...
+% We don't want such trailing spaces in the node name.
+%
+\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse}
+%
+% also remove a trailing comma, in case of something like this:
+% @node Help-Cross, , , Cross-refs
+\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse}
+\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}}
+
+\let\nwnode=\node
+\let\lastnode=\empty
+
+% Write a cross-reference definition for the current node. #1 is the
+% type (Ynumbered, Yappendix, Ynothing).
+%
+\def\donoderef#1{%
+ \ifx\lastnode\empty\else
+ \setref{\lastnode}{#1}%
+ \global\let\lastnode=\empty
+ \fi
+}
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\newcount\savesfregister
+%
+\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi}
+\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi}
+\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces}
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an
+% anchor), which consists of three parts:
+% 1) NAME-title - the current sectioning name taken from \thissection,
+% or the anchor name.
+% 2) NAME-snt - section number and type, passed as the SNT arg, or
+% empty for anchors.
+% 3) NAME-pg - the page number.
+%
+% This is called from \donoderef, \anchor, and \dofloat. In the case of
+% floats, there is an additional part, which is not written here:
+% 4) NAME-lof - the text as it should appear in a @listoffloats.
+%
+\def\setref#1#2{%
+ \pdfmkdest{#1}%
+ \iflinks
+ {%
+ \atdummies % preserve commands, but don't expand them
+ \turnoffactive
+ \otherbackslash
+ \edef\writexrdef##1##2{%
+ \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
+ ##1}{##2}}% these are parameters of \writexrdef
+ }%
+ \toks0 = \expandafter{\thissection}%
+ \immediate \writexrdef{title}{\the\toks0 }%
+ \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
+ \writexrdef{pg}{\folio}% will be written later, during \shipout
+ }%
+ \fi
+}
+
+% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual. All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+ \unsepspaces
+ \def\printedmanual{\ignorespaces #5}%
+ \def\printedrefname{\ignorespaces #3}%
+ \setbox1=\hbox{\printedmanual\unskip}%
+ \setbox0=\hbox{\printedrefname\unskip}%
+ \ifdim \wd0 = 0pt
+ % No printed node name was explicitly given.
+ \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax
+ % Use the node name inside the square brackets.
+ \def\printedrefname{\ignorespaces #1}%
+ \else
+ % Use the actual chapter/section title appear inside
+ % the square brackets. Use the real section title if we have it.
+ \ifdim \wd1 > 0pt
+ % It is in another manual, so we don't have it.
+ \def\printedrefname{\ignorespaces #1}%
+ \else
+ \ifhavexrefs
+ % We know the real title if we have the xref values.
+ \def\printedrefname{\refx{#1-title}{}}%
+ \else
+ % Otherwise just copy the Info node name.
+ \def\printedrefname{\ignorespaces #1}%
+ \fi%
+ \fi
+ \fi
+ \fi
+ %
+ % Make link in pdf output.
+ \ifpdf
+ \leavevmode
+ \getfilename{#4}%
+ {\turnoffactive \otherbackslash
+ \ifnum\filenamelength>0
+ \startlink attr{/Border [0 0 0]}%
+ goto file{\the\filename.pdf} name{#1}%
+ \else
+ \startlink attr{/Border [0 0 0]}%
+ goto name{\pdfmkpgn{#1}}%
+ \fi
+ }%
+ \linkcolor
+ \fi
+ %
+ % Float references are printed completely differently: "Figure 1.2"
+ % instead of "[somenode], p.3". We distinguish them by the
+ % LABEL-title being set to a magic string.
+ {%
+ % Have to otherify everything special to allow the \csname to
+ % include an _ in the xref name, etc.
+ \indexnofonts
+ \turnoffactive
+ \otherbackslash
+ \expandafter\global\expandafter\let\expandafter\Xthisreftitle
+ \csname XR#1-title\endcsname
+ }%
+ \iffloat\Xthisreftitle
+ % If the user specified the print name (third arg) to the ref,
+ % print it instead of our usual "Figure 1.2".
+ \ifdim\wd0 = 0pt
+ \refx{#1-snt}%
+ \else
+ \printedrefname
+ \fi
+ %
+ % if the user also gave the printed manual name (fifth arg), append
+ % "in MANUALNAME".
+ \ifdim \wd1 > 0pt
+ \space \putwordin{} \cite{\printedmanual}%
+ \fi
+ \else
+ % node/anchor (non-float) references.
+ %
+ % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+ % insert empty discretionaries after hyphens, which means that it will
+ % not find a line break at a hyphen in a node names. Since some manuals
+ % are best written with fairly long node names, containing hyphens, this
+ % is a loss. Therefore, we give the text of the node name again, so it
+ % is as if TeX is seeing it for the first time.
+ \ifdim \wd1 > 0pt
+ \putwordsection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}%
+ \else
+ % _ (for example) has to be the character _ for the purposes of the
+ % control sequence corresponding to the node, but it has to expand
+ % into the usual \leavevmode...\vrule stuff for purposes of
+ % printing. So we \turnoffactive for the \refx-snt, back on for the
+ % printing, back off for the \refx-pg.
+ {\turnoffactive \otherbackslash
+ % Only output a following space if the -snt ref is nonempty; for
+ % @unnumbered and @anchor, it won't be.
+ \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+ \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+ }%
+ % output the `[mynode]' via a macro so it can be overridden.
+ \xrefprintnodename\printedrefname
+ %
+ % But we always want a comma and a space:
+ ,\space
+ %
+ % output the `page 3'.
+ \turnoffactive \otherbackslash \putwordpage\tie\refx{#1-pg}{}%
+ \fi
+ \fi
+ \endlink
+\endgroup}
+
+% This macro is called from \xrefX for the `[nodename]' part of xref
+% output. It's a separate macro only so it can be changed more easily,
+% since square brackets don't work well in some documents. Particularly
+% one that Bob is working on :).
+%
+\def\xrefprintnodename#1{[#1]}
+
+% Things referred to by \setref.
+%
+\def\Ynothing{}
+\def\Yomitfromtoc{}
+\def\Ynumbered{%
+ \ifnum\secno=0
+ \putwordChapter@tie \the\chapno
+ \else \ifnum\subsecno=0
+ \putwordSection@tie \the\chapno.\the\secno
+ \else \ifnum\subsubsecno=0
+ \putwordSection@tie \the\chapno.\the\secno.\the\subsecno
+ \else
+ \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno
+ \fi\fi\fi
+}
+\def\Yappendix{%
+ \ifnum\secno=0
+ \putwordAppendix@tie @char\the\appendixno{}%
+ \else \ifnum\subsecno=0
+ \putwordSection@tie @char\the\appendixno.\the\secno
+ \else \ifnum\subsubsecno=0
+ \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno
+ \else
+ \putwordSection@tie
+ @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno
+ \fi\fi\fi
+}
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+%
+\def\refx#1#2{%
+ {%
+ \indexnofonts
+ \otherbackslash
+ \expandafter\global\expandafter\let\expandafter\thisrefX
+ \csname XR#1\endcsname
+ }%
+ \ifx\thisrefX\relax
+ % If not defined, say something at least.
+ \angleleft un\-de\-fined\angleright
+ \iflinks
+ \ifhavexrefs
+ \message{\linenumber Undefined cross reference `#1'.}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \thisrefX
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file. Usually it's
+% just a \def (we prepend XR to the control sequence name to avoid
+% collisions). But if this is a float type, we have more work to do.
+%
+\def\xrdef#1#2{%
+ \expandafter\gdef\csname XR#1\endcsname{#2}% remember this xref value.
+ %
+ % Was that xref control sequence that we just defined for a float?
+ \expandafter\iffloat\csname XR#1\endcsname
+ % it was a float, and we have the (safe) float type in \iffloattype.
+ \expandafter\let\expandafter\floatlist
+ \csname floatlist\iffloattype\endcsname
+ %
+ % Is this the first time we've seen this float type?
+ \expandafter\ifx\floatlist\relax
+ \toks0 = {\do}% yes, so just \do
+ \else
+ % had it before, so preserve previous elements in list.
+ \toks0 = \expandafter{\floatlist\do}%
+ \fi
+ %
+ % Remember this xref in the control sequence \floatlistFLOATTYPE,
+ % for later use in \listoffloats.
+ \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0{#1}}%
+ \fi
+}
+
+% Read the last existing aux file, if any. No error if none exists.
+%
+\def\tryauxfile{%
+ \openin 1 \jobname.aux
+ \ifeof 1 \else
+ \readauxfile
+ \global\havexrefstrue
+ \fi
+ \closein 1
+}
+
+\def\readauxfile{\begingroup
+ \catcode`\^^@=\other
+ \catcode`\^^A=\other
+ \catcode`\^^B=\other
+ \catcode`\^^C=\other
+ \catcode`\^^D=\other
+ \catcode`\^^E=\other
+ \catcode`\^^F=\other
+ \catcode`\^^G=\other
+ \catcode`\^^H=\other
+ \catcode`\^^K=\other
+ \catcode`\^^L=\other
+ \catcode`\^^N=\other
+ \catcode`\^^P=\other
+ \catcode`\^^Q=\other
+ \catcode`\^^R=\other
+ \catcode`\^^S=\other
+ \catcode`\^^T=\other
+ \catcode`\^^U=\other
+ \catcode`\^^V=\other
+ \catcode`\^^W=\other
+ \catcode`\^^X=\other
+ \catcode`\^^Z=\other
+ \catcode`\^^[=\other
+ \catcode`\^^\=\other
+ \catcode`\^^]=\other
+ \catcode`\^^^=\other
+ \catcode`\^^_=\other
+ % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc.
+ % in xref tags, i.e., node names. But since ^^e4 notation isn't
+ % supported in the main text, it doesn't seem desirable. Furthermore,
+ % that is not enough: for node names that actually contain a ^
+ % character, we would end up writing a line like this: 'xrdef {'hat
+ % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+ % argument, and \hat is not an expandable control sequence. It could
+ % all be worked out, but why? Either we support ^^ or we don't.
+ %
+ % The other change necessary for this was to define \auxhat:
+ % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+ % and then to call \auxhat in \setq.
+ %
+ \catcode`\^=\other
+ %
+ % Special characters. Should be turned off anyway, but...
+ \catcode`\~=\other
+ \catcode`\[=\other
+ \catcode`\]=\other
+ \catcode`\"=\other
+ \catcode`\_=\other
+ \catcode`\|=\other
+ \catcode`\<=\other
+ \catcode`\>=\other
+ \catcode`\$=\other
+ \catcode`\#=\other
+ \catcode`\&=\other
+ \catcode`\%=\other
+ \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+ %
+ % This is to support \ in node names and titles, since the \
+ % characters end up in a \csname. It's easier than
+ % leaving it active and making its active definition an actual \
+ % character. What I don't understand is why it works in the *value*
+ % of the xrdef. Seems like it should be a catcode12 \, and that
+ % should not typeset properly. But it works, so I'm moving on for
+ % now. --karl, 15jan04.
+ \catcode`\\=\other
+ %
+ % Make the characters 128-255 be printing characters.
+ {%
+ \count 1=128
+ \def\loop{%
+ \catcode\count 1=\other
+ \advance\count 1 by 1
+ \ifnum \count 1<256 \loop \fi
+ }%
+ }%
+ %
+ % @ is our escape character in .aux files, and we need braces.
+ \catcode`\{=1
+ \catcode`\}=2
+ \catcode`\@=0
+ %
+ \input \jobname.aux
+\endgroup}
+
+
+\message{insertions,}
+% including footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only.
+\let\footnotestyle=\comment
+
+{\catcode `\@=11
+%
+% Auto-number footnotes. Otherwise like plain.
+\gdef\footnote{%
+ \let\indent=\ptexindent
+ \let\noindent=\ptexnoindent
+ \global\advance\footnoteno by \@ne
+ \edef\thisfootno{$^{\the\footnoteno}$}%
+ %
+ % In case the footnote comes at the end of a sentence, preserve the
+ % extra spacing after we do the footnote number.
+ \let\@sf\empty
+ \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi
+ %
+ % Remove inadvertent blank space before typesetting the footnote number.
+ \unskip
+ \thisfootno\@sf
+ \dofootnote
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter. Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset (and anything else that uses
+% \parseargline) fails inside footnotes because the tokens are fixed when
+% the footnote is read. --karl, 16nov96.
+%
+\gdef\dofootnote{%
+ \insert\footins\bgroup
+ % We want to typeset this text as a normal paragraph, even if the
+ % footnote reference occurs in (for example) a display environment.
+ % So reset some parameters.
+ \hsize=\pagewidth
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox
+ \floatingpenalty\@MM
+ \leftskip\z@skip
+ \rightskip\z@skip
+ \spaceskip\z@skip
+ \xspaceskip\z@skip
+ \parindent\defaultparindent
+ %
+ \smallfonts \rm
+ %
+ % Because we use hanging indentation in footnotes, a @noindent appears
+ % to exdent this text, so make it be a no-op. makeinfo does not use
+ % hanging indentation so @noindent can still be needed within footnote
+ % text after an @example or the like (not that this is good style).
+ \let\noindent = \relax
+ %
+ % Hang the footnote text off the number. Use \everypar in case the
+ % footnote extends for more than one paragraph.
+ \everypar = {\hang}%
+ \textindent{\thisfootno}%
+ %
+ % Don't crash into the line above the footnote text. Since this
+ % expands into a box, it must come within the paragraph, lest it
+ % provide a place where TeX can split the footnote.
+ \footstrut
+ \futurelet\next\fo@t
+}
+}%end \catcode `\@=11
+
+% In case a @footnote appears in a vbox, save the footnote text and create
+% the real \insert just after the vbox finished. Otherwise, the insertion
+% would be lost.
+% Similarily, if a @footnote appears inside an alignment, save the footnote
+% text to a box and make the \insert when a row of the table is finished.
+% And the same can be done for other insert classes. --kasal, 16nov03.
+
+% Replace the \insert primitive by a cheating macro.
+% Deeper inside, just make sure that the saved insertions are not spilled
+% out prematurely.
+%
+\def\startsavinginserts{%
+ \ifx \insert\ptexinsert
+ \let\insert\saveinsert
+ \else
+ \let\checkinserts\relax
+ \fi
+}
+
+% This \insert replacement works for both \insert\footins{foo} and
+% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}.
+%
+\def\saveinsert#1{%
+ \edef\next{\noexpand\savetobox \makeSAVEname#1}%
+ \afterassignment\next
+ % swallow the left brace
+ \let\temp =
+}
+\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}}
+\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1}
+
+\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi}
+
+\def\placesaveins#1{%
+ \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname
+ {\box#1}%
+}
+
+% eat @SAVE -- beware, all of them have catcode \other:
+{
+ \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-)
+ \gdef\gobblesave @SAVE{}
+}
+
+% initialization:
+\def\newsaveins #1{%
+ \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}%
+ \next
+}
+\def\newsaveinsX #1{%
+ \csname newbox\endcsname #1%
+ \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts
+ \checksaveins #1}%
+}
+
+% initialize:
+\let\checkinserts\empty
+\newsaveins\footins
+\newsaveins\margin
+
+
+% @image. We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front. If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+ % Do not bother showing banner with epsf.tex v2.7k (available in
+ % doc/epsf.tex and on ctan).
+ \def\epsfannounce{\toks0 = }%
+ \input epsf.tex
+\fi
+\closein 1
+%
+% We will only complain once about lack of epsf.tex.
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+ work. It is also included in the Texinfo distribution, or you can get
+ it from ftp://tug.org/tex/epsf.tex.}
+%
+\def\image#1{%
+ \ifx\epsfbox\undefined
+ \ifwarnednoepsf \else
+ \errhelp = \noepsfhelp
+ \errmessage{epsf.tex not found, images will be ignored}%
+ \global\warnednoepsftrue
+ \fi
+ \else
+ \imagexxx #1,,,,,\finish
+ \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is (ignored optional) html alt text.
+% #5 is (ignored optional) extension.
+% #6 is just the usual extra ignored arg for parsing this stuff.
+\newif\ifimagevmode
+\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup
+ \catcode`\^^M = 5 % in case we're inside an example
+ \normalturnoffactive % allow _ et al. in names
+ % If the image is by itself, center it.
+ \ifvmode
+ \imagevmodetrue
+ \nobreak\bigskip
+ % Usually we'll have text after the image which will insert
+ % \parskip glue, so insert it here too to equalize the space
+ % above and below.
+ \nobreak\vskip\parskip
+ \nobreak
+ \line\bgroup\hss
+ \fi
+ %
+ % Output the image.
+ \ifpdf
+ \dopdfimage{#1}{#2}{#3}%
+ \else
+ % \epsfbox itself resets \epsf?size at each figure.
+ \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+ \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+ \epsfbox{#1.eps}%
+ \fi
+ %
+ \ifimagevmode \hss \egroup \bigbreak \fi % space after the image
+\endgroup}
+
+
+% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables,
+% etc. We don't actually implement floating yet, we always include the
+% float "here". But it seemed the best name for the future.
+%
+\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish}
+
+% There may be a space before second and/or third parameter; delete it.
+\def\eatcommaspace#1, {#1,}
+
+% #1 is the optional FLOATTYPE, the text label for this float, typically
+% "Figure", "Table", "Example", etc. Can't contain commas. If omitted,
+% this float will not be numbered and cannot be referred to.
+%
+% #2 is the optional xref label. Also must be present for the float to
+% be referable.
+%
+% #3 is the optional positioning argument; for now, it is ignored. It
+% will somehow specify the positions allowed to float to (here, top, bottom).
+%
+% We keep a separate counter for each FLOATTYPE, which we reset at each
+% chapter-level command.
+\let\resetallfloatnos=\empty
+%
+\def\dofloat#1,#2,#3,#4\finish{%
+ \let\thiscaption=\empty
+ \let\thisshortcaption=\empty
+ %
+ % don't lose footnotes inside @float.
+ %
+ % BEWARE: when the floats start float, we have to issue warning whenever an
+ % insert appears inside a float which could possibly float. --kasal, 26may04
+ %
+ \startsavinginserts
+ %
+ % We can't be used inside a paragraph.
+ \par
+ %
+ \vtop\bgroup
+ \def\floattype{#1}%
+ \def\floatlabel{#2}%
+ \def\floatloc{#3}% we do nothing with this yet.
+ %
+ \ifx\floattype\empty
+ \let\safefloattype=\empty
+ \else
+ {%
+ % the floattype might have accents or other special characters,
+ % but we need to use it in a control sequence name.
+ \indexnofonts
+ \turnoffactive
+ \xdef\safefloattype{\floattype}%
+ }%
+ \fi
+ %
+ % If label is given but no type, we handle that as the empty type.
+ \ifx\floatlabel\empty \else
+ % We want each FLOATTYPE to be numbered separately (Figure 1,
+ % Table 1, Figure 2, ...). (And if no label, no number.)
+ %
+ \expandafter\getfloatno\csname\safefloattype floatno\endcsname
+ \global\advance\floatno by 1
+ %
+ {%
+ % This magic value for \thissection is output by \setref as the
+ % XREFLABEL-title value. \xrefX uses it to distinguish float
+ % labels (which have a completely different output format) from
+ % node and anchor labels. And \xrdef uses it to construct the
+ % lists of floats.
+ %
+ \edef\thissection{\floatmagic=\safefloattype}%
+ \setref{\floatlabel}{Yfloat}%
+ }%
+ \fi
+ %
+ % start with \parskip glue, I guess.
+ \vskip\parskip
+ %
+ % Don't suppress indentation if a float happens to start a section.
+ \restorefirstparagraphindent
+}
+
+% we have these possibilities:
+% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap
+% @float Foo,lbl & no caption: Foo 1.1
+% @float Foo & @caption{Cap}: Foo: Cap
+% @float Foo & no caption: Foo
+% @float ,lbl & Caption{Cap}: 1.1: Cap
+% @float ,lbl & no caption: 1.1
+% @float & @caption{Cap}: Cap
+% @float & no caption:
+%
+\def\Efloat{%
+ \let\floatident = \empty
+ %
+ % In all cases, if we have a float type, it comes first.
+ \ifx\floattype\empty \else \def\floatident{\floattype}\fi
+ %
+ % If we have an xref label, the number comes next.
+ \ifx\floatlabel\empty \else
+ \ifx\floattype\empty \else % if also had float type, need tie first.
+ \appendtomacro\floatident{\tie}%
+ \fi
+ % the number.
+ \appendtomacro\floatident{\chaplevelprefix\the\floatno}%
+ \fi
+ %
+ % Start the printed caption with what we've constructed in
+ % \floatident, but keep it separate; we need \floatident again.
+ \let\captionline = \floatident
+ %
+ \ifx\thiscaption\empty \else
+ \ifx\floatident\empty \else
+ \appendtomacro\captionline{: }% had ident, so need a colon between
+ \fi
+ %
+ % caption text.
+ \appendtomacro\captionline{\scanexp\thiscaption}%
+ \fi
+ %
+ % If we have anything to print, print it, with space before.
+ % Eventually this needs to become an \insert.
+ \ifx\captionline\empty \else
+ \vskip.5\parskip
+ \captionline
+ %
+ % Space below caption.
+ \vskip\parskip
+ \fi
+ %
+ % If have an xref label, write the list of floats info. Do this
+ % after the caption, to avoid chance of it being a breakpoint.
+ \ifx\floatlabel\empty \else
+ % Write the text that goes in the lof to the aux file as
+ % \floatlabel-lof. Besides \floatident, we include the short
+ % caption if specified, else the full caption if specified, else nothing.
+ {%
+ \atdummies \turnoffactive \otherbackslash
+ % since we read the caption text in the macro world, where ^^M
+ % is turned into a normal character, we have to scan it back, so
+ % we don't write the literal three characters "^^M" into the aux file.
+ \scanexp{%
+ \xdef\noexpand\gtemp{%
+ \ifx\thisshortcaption\empty
+ \thiscaption
+ \else
+ \thisshortcaption
+ \fi
+ }%
+ }%
+ \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
+ \ifx\gtemp\empty \else : \gtemp \fi}}%
+ }%
+ \fi
+ \egroup % end of \vtop
+ %
+ % place the captured inserts
+ %
+ % BEWARE: when the floats start float, we have to issue warning whenever an
+ % insert appears inside a float which could possibly float. --kasal, 26may04
+ %
+ \checkinserts
+}
+
+% Append the tokens #2 to the definition of macro #1, not expanding either.
+%
+\def\appendtomacro#1#2{%
+ \expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+
+% @caption, @shortcaption
+%
+\def\caption{\docaption\thiscaption}
+\def\shortcaption{\docaption\thisshortcaption}
+\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption}
+\def\defcaption#1#2{\egroup \def#1{#2}}
+
+% The parameter is the control sequence identifying the counter we are
+% going to use. Create it if it doesn't exist and assign it to \floatno.
+\def\getfloatno#1{%
+ \ifx#1\relax
+ % Haven't seen this figure type before.
+ \csname newcount\endcsname #1%
+ %
+ % Remember to reset this floatno at the next chap.
+ \expandafter\gdef\expandafter\resetallfloatnos
+ \expandafter{\resetallfloatnos #1=0 }%
+ \fi
+ \let\floatno#1%
+}
+
+% \setref calls this to get the XREFLABEL-snt value. We want an @xref
+% to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we
+% first read the @float command.
+%
+\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}%
+
+% Magic string used for the XREFLABEL-title value, so \xrefX can
+% distinguish floats from other xref types.
+\def\floatmagic{!!float!!}
+
+% #1 is the control sequence we are passed; we expand into a conditional
+% which is true if #1 represents a float ref. That is, the magic
+% \thissection value which we \setref above.
+%
+\def\iffloat#1{\expandafter\doiffloat#1==\finish}
+%
+% #1 is (maybe) the \floatmagic string. If so, #2 will be the
+% (safe) float type for this float. We set \iffloattype to #2.
+%
+\def\doiffloat#1=#2=#3\finish{%
+ \def\temp{#1}%
+ \def\iffloattype{#2}%
+ \ifx\temp\floatmagic
+}
+
+% @listoffloats FLOATTYPE - print a list of floats like a table of contents.
+%
+\parseargdef\listoffloats{%
+ \def\floattype{#1}% floattype
+ {%
+ % the floattype might have accents or other special characters,
+ % but we need to use it in a control sequence name.
+ \indexnofonts
+ \turnoffactive
+ \xdef\safefloattype{\floattype}%
+ }%
+ %
+ % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE.
+ \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax
+ \ifhavexrefs
+ % if the user said @listoffloats foo but never @float foo.
+ \message{\linenumber No `\safefloattype' floats to list.}%
+ \fi
+ \else
+ \begingroup
+ \leftskip=\tocindent % indent these entries like a toc
+ \let\do=\listoffloatsdo
+ \csname floatlist\safefloattype\endcsname
+ \endgroup
+ \fi
+}
+
+% This is called on each entry in a list of floats. We're passed the
+% xref label, in the form LABEL-title, which is how we save it in the
+% aux file. We strip off the -title and look up \XRLABEL-lof, which
+% has the text we're supposed to typeset here.
+%
+% Figures without xref labels will not be included in the list (since
+% they won't appear in the aux file).
+%
+\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish}
+\def\listoffloatsdoentry#1-title\finish{{%
+ % Can't fully expand XR#1-lof because it can contain anything. Just
+ % pass the control sequence. On the other hand, XR#1-pg is just the
+ % page number, and we want to fully expand that so we can get a link
+ % in pdf output.
+ \toksA = \expandafter{\csname XR#1-lof\endcsname}%
+ %
+ % use the same \entry macro we use to generate the TOC and index.
+ \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}%
+ \writeentry
+}}
+
+\message{localization,}
+% and i18n.
+
+% @documentlanguage is usually given very early, just after
+% @setfilename. If done too late, it may not override everything
+% properly. Single argument is the language abbreviation.
+% It would be nice if we could set up a hyphenation file here.
+%
+\parseargdef\documentlanguage{%
+ \tex % read txi-??.tex file in plain TeX.
+ % Read the file if it exists.
+ \openin 1 txi-#1.tex
+ \ifeof 1
+ \errhelp = \nolanghelp
+ \errmessage{Cannot read language file txi-#1.tex}%
+ \else
+ \input txi-#1.tex
+ \fi
+ \closein 1
+ \endgroup
+}
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty. Maybe you need to install it? In the current directory
+should work if nowhere else does.}
+
+
+% @documentencoding should change something in TeX eventually, most
+% likely, but for now just recognize it.
+\let\documentencoding = \comment
+
+
+% Page size parameters.
+%
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be so finicky about underfull hboxes, either.
+\hbadness = 2000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything. We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize. We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+ \ifx\emergencystretch\thisisundefined
+ % Allow us to assign to \emergencystretch anyway.
+ \def\emergencystretch{\dimen0}%
+ \else
+ \emergencystretch = .15\hsize
+ \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth; 3) voffset;
+% 4) hoffset; 5) binding offset; 6) topskip; 7) physical page height; 8)
+% physical page width.
+%
+% We also call \setleading{\textleading}, so the caller should define
+% \textleading. The caller should also set \parskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6#7#8{%
+ \voffset = #3\relax
+ \topskip = #6\relax
+ \splittopskip = \topskip
+ %
+ \vsize = #1\relax
+ \advance\vsize by \topskip
+ \outervsize = \vsize
+ \advance\outervsize by 2\topandbottommargin
+ \pageheight = \vsize
+ %
+ \hsize = #2\relax
+ \outerhsize = \hsize
+ \advance\outerhsize by 0.5in
+ \pagewidth = \hsize
+ %
+ \normaloffset = #4\relax
+ \bindingoffset = #5\relax
+ %
+ \ifpdf
+ \pdfpageheight #7\relax
+ \pdfpagewidth #8\relax
+ \fi
+ %
+ \setleading{\textleading}
+ %
+ \parindent = \defaultparindent
+ \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+ \parskip = 3pt plus 2pt minus 1pt
+ \textleading = 13.2pt
+ %
+ % If page is nothing but text, make it come out even.
+ \internalpagesizes{46\baselineskip}{6in}%
+ {\voffset}{.25in}%
+ {\bindingoffset}{36pt}%
+ {11in}{8.5in}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.5 (or so) format.
+\def\smallbook{{\globaldefs = 1
+ \parskip = 2pt plus 1pt
+ \textleading = 12pt
+ %
+ \internalpagesizes{7.5in}{5in}%
+ {\voffset}{.25in}%
+ {\bindingoffset}{16pt}%
+ {9.25in}{7in}%
+ %
+ \lispnarrowing = 0.3in
+ \tolerance = 700
+ \hfuzz = 1pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = .5cm
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+ \parskip = 3pt plus 2pt minus 1pt
+ \textleading = 13.2pt
+ %
+ % Double-side printing via postscript on Laserjet 4050
+ % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm.
+ % To change the settings for a different printer or situation, adjust
+ % \normaloffset until the front-side and back-side texts align. Then
+ % do the same for \bindingoffset. You can set these for testing in
+ % your texinfo source file like this:
+ % @tex
+ % \global\normaloffset = -6mm
+ % \global\bindingoffset = 10mm
+ % @end tex
+ \internalpagesizes{51\baselineskip}{160mm}
+ {\voffset}{\hoffset}%
+ {\bindingoffset}{44pt}%
+ {297mm}{210mm}%
+ %
+ \tolerance = 700
+ \hfuzz = 1pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = 5mm
+}}
+
+% Use @afivepaper to print on European A5 paper.
+% From romildo@urano.iceb.ufop.br, 2 July 2000.
+% He also recommends making @example and @lisp be small.
+\def\afivepaper{{\globaldefs = 1
+ \parskip = 2pt plus 1pt minus 0.1pt
+ \textleading = 12.5pt
+ %
+ \internalpagesizes{160mm}{120mm}%
+ {\voffset}{\hoffset}%
+ {\bindingoffset}{8pt}%
+ {210mm}{148mm}%
+ %
+ \lispnarrowing = 0.2in
+ \tolerance = 800
+ \hfuzz = 1.2pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = 2mm
+ \tableindent = 12mm
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.
+\def\afourlatex{{\globaldefs = 1
+ \afourpaper
+ \internalpagesizes{237mm}{150mm}%
+ {\voffset}{4.6mm}%
+ {\bindingoffset}{7mm}%
+ {297mm}{210mm}%
+ %
+ % Must explicitly reset to 0 because we call \afourpaper.
+ \globaldefs = 0
+}}
+
+% Use @afourwide to print on A4 paper in landscape format.
+\def\afourwide{{\globaldefs = 1
+ \afourpaper
+ \internalpagesizes{241mm}{165mm}%
+ {\voffset}{-2.95mm}%
+ {\bindingoffset}{7mm}%
+ {297mm}{210mm}%
+ \globaldefs = 0
+}}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\parseargdef\pagesizes{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+ \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+ \globaldefs = 1
+ %
+ \parskip = 3pt plus 2pt minus 1pt
+ \setleading{\textleading}%
+ %
+ \dimen0 = #1
+ \advance\dimen0 by \voffset
+ %
+ \dimen2 = \hsize
+ \advance\dimen2 by \normaloffset
+ %
+ \internalpagesizes{#1}{\hsize}%
+ {\voffset}{\normaloffset}%
+ {\bindingoffset}{44pt}%
+ {\dimen0}{\dimen2}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+
+\message{and turning on texinfo input format.}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\catcode`\$=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+\def\normaldollar{$}%$ font-lock fix
+
+% This macro is used to make a character print one way in \tt
+% (where it can probably be output as-is), and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise. Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font. Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts. But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt\char126}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }
+
+\catcode`\|=\active
+\def|{{\tt\char124}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+\catcode`\$=\active
+\def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have \everyjob (or @setfilename) turn them on.
+% \otherifyactive is called near the end of this file.
+\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
+
+\catcode`\@=0
+
+% \backslashcurfont outputs one backslash character in current font,
+% as in \char`\\.
+\global\chardef\backslashcurfont=`\\
+\global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work
+
+% \rawbackslash defines an active \ to do \backslashcurfont.
+% \otherbackslash defines an active \ to be a literal `\' character with
+% catcode other.
+{\catcode`\\=\active
+ @gdef@rawbackslash{@let\=@backslashcurfont}
+ @gdef@otherbackslash{@let\=@realbackslash}
+}
+
+% \realbackslash is an actual character `\' with catcode other.
+{\catcode`\\=\other @gdef@realbackslash{\}}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\backslashcurfont}}
+
+\catcode`\\=\active
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+@def@turnoffactive{%
+ @let"=@normaldoublequote
+ @let\=@realbackslash
+ @let~=@normaltilde
+ @let^=@normalcaret
+ @let_=@normalunderscore
+ @let|=@normalverticalbar
+ @let<=@normalless
+ @let>=@normalgreater
+ @let+=@normalplus
+ @let$=@normaldollar %$ font-lock fix
+ @unsepspaces
+}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'. (Thus, \ is not expandable when this is in
+% effect.)
+%
+@def@normalturnoffactive{@turnoffactive @let\=@normalbackslash}
+
+% Make _ and + \other characters, temporarily.
+% This is canceled by @fixbackslash.
+@otherifyactive
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+% Also back turn on active characters that might appear in the input
+% file name, in case not using a pre-dumped format.
+%
+@gdef@fixbackslash{%
+ @ifx\@eatinput @let\ = @normalbackslash @fi
+ @catcode`+=@active
+ @catcode`@_=@active
+}
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These look ok in all fonts, so just make them not special.
+@catcode`@& = @other
+@catcode`@# = @other
+@catcode`@% = @other
+
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%02H"
+@c time-stamp-end: "}"
+@c End:
+
+@c vim:sw=2:
+
+@ignore
+ arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115
+@end ignore
diff --git a/build-aux/ylwrap b/build-aux/ylwrap
new file mode 100755
index 0000000..10e4368
--- /dev/null
+++ b/build-aux/ylwrap
@@ -0,0 +1,222 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2005-02-02.22
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case "$1" in
+ '')
+ echo "$0: No files given. Try \`$0 --help' for more information." 1>&2
+ exit 1
+ ;;
+ --basedir)
+ basedir=$2
+ shift 2
+ ;;
+ -h|--h*)
+ cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+ INPUT is the input file
+ OUTPUT is one file PROG generates
+ DESIRED is the file we actually want instead of OUTPUT
+ PROGRAM is program to run
+ ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v|--v*)
+ echo "ylwrap $scriptversion"
+ exit $?
+ ;;
+esac
+
+
+# The input.
+input="$1"
+shift
+case "$input" in
+ [\\/]* | ?:[\\/]*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Relative path. Make it absolute.
+ input="`pwd`/$input"
+ ;;
+esac
+
+pairlist=
+while test "$#" -ne 0; do
+ if test "$1" = "--"; then
+ shift
+ break
+ fi
+ pairlist="$pairlist $1"
+ shift
+done
+
+# The program to run.
+prog="$1"
+shift
+# Make any relative path in $prog absolute.
+case "$prog" in
+ [\\/]* | ?:[\\/]*) ;;
+ *[\\/]*) prog="`pwd`/$prog" ;;
+esac
+
+# FIXME: add hostname here for parallel makes that run commands on
+# other machines. But that might take us over the 14-char limit.
+dirname=ylwrap$$
+trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+ 0) $prog "$input" ;;
+ *) $prog "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+ set X $pairlist
+ shift
+ first=yes
+ # Since DOS filename conventions don't allow two dots,
+ # the DOS version of Bison writes out y_tab.c instead of y.tab.c
+ # and y_tab.h instead of y.tab.h. Test to see if this is the case.
+ y_tab_nodot="no"
+ if test -f y_tab.c || test -f y_tab.h; then
+ y_tab_nodot="yes"
+ fi
+
+ # The directory holding the input.
+ input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
+ # Quote $INPUT_DIR so we can use it in a regexp.
+ # FIXME: really we should care about more than `.' and `\'.
+ input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'`
+
+ while test "$#" -ne 0; do
+ from="$1"
+ # Handle y_tab.c and y_tab.h output by DOS
+ if test $y_tab_nodot = "yes"; then
+ if test $from = "y.tab.c"; then
+ from="y_tab.c"
+ else
+ if test $from = "y.tab.h"; then
+ from="y_tab.h"
+ fi
+ fi
+ fi
+ if test -f "$from"; then
+ # If $2 is an absolute path name, then just use that,
+ # otherwise prepend `../'.
+ case "$2" in
+ [\\/]* | ?:[\\/]*) target="$2";;
+ *) target="../$2";;
+ esac
+
+ # We do not want to overwrite a header file if it hasn't
+ # changed. This avoid useless recompilations. However the
+ # parser itself (the first file) should always be updated,
+ # because it is the destination of the .y.c rule in the
+ # Makefile. Divert the output of all other files to a temporary
+ # file so we can compare them to existing versions.
+ if test $first = no; then
+ realtarget="$target"
+ target="tmp-`echo $target | sed s/.*[\\/]//g`"
+ fi
+ # Edit out `#line' or `#' directives.
+ #
+ # We don't want the resulting debug information to point at
+ # an absolute srcdir; it is better for it to just mention the
+ # .y file with no path.
+ #
+ # We want to use the real output file name, not yy.lex.c for
+ # instance.
+ #
+ # We want the include guards to be adjusted too.
+ FROM=`echo "$from" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+ TARGET=`echo "$2" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+
+ sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \
+ -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$?
+
+ # Check whether header files must be updated.
+ if test $first = no; then
+ if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+ echo "$2" is unchanged
+ rm -f "$target"
+ else
+ echo updating "$2"
+ mv -f "$target" "$realtarget"
+ fi
+ fi
+ else
+ # A missing file is only an error for the first file. This
+ # is a blatant hack to let us support using "yacc -d". If -d
+ # is not specified, we don't want an error when the header
+ # file is "missing".
+ if test $first = yes; then
+ ret=1
+ fi
+ fi
+ shift
+ shift
+ first=no
+ done
+else
+ ret=$?
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/build.com b/build.com
new file mode 100755
index 0000000..7c60ef0
--- /dev/null
+++ b/build.com
@@ -0,0 +1,10 @@
+$ set def [.zlib]
+$ @make_vms.com
+$ set def [-.diff]
+$ @build_diff.com
+$ set def [-.vms]
+$ @build_vms.com
+$ set def [-.lib]
+$ @build_lib.com
+$ set def [-.src]
+$ @build_src.com
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..8e0461d
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,1244 @@
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define this to a NULL terminated list of allowed path prefixes (for
+ directories) and paths to files the CVS server will allow configuration to
+ be read from when specified from the command line. */
+#undef ALLOW_CONFIG_OVERRIDE
+
+/* Enable AUTH_CLIENT_SUPPORT to enable pserver as a remote access method in
+ the CVS client (default) */
+#undef AUTH_CLIENT_SUPPORT
+
+/* Define if you want to use the password authenticated server. */
+#undef AUTH_SERVER_SUPPORT
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#undef CLIENT_SUPPORT
+
+/* Define to 1 if the `closedir' function returns void instead of `int'. */
+#undef CLOSEDIR_VOID
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* define if cross compiling */
+#undef CROSS_COMPILING
+
+/* The CVS admin command is restricted to the members of the group
+ CVS_ADMIN_GROUP. If this group does not exist, all users are allowed to run
+ CVS admin. To disable the CVS admin command for all users, create an empty
+ CVS_ADMIN_GROUP by running configure with the --with-cvs-admin-group=
+ option. To disable access control for CVS admin, run configure with the
+ --without-cvs-admin-group option in order to comment out the define below.
+ */
+#undef CVS_ADMIN_GROUP
+
+/* When committing a permanent change, CVS and RCS make a log entry of who
+ committed the change. If you are committing the change logged in as "root"
+ (not under "su" or other root-priv giving program), CVS/RCS cannot
+ determine who is actually making the change. As such, by default, CVS
+ prohibits changes committed by users logged in as "root". You can disable
+ checking by passing the "--enable-rootcommit" option to configure or by
+ commenting out the lines below. */
+#undef CVS_BADROOT
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define if there is a member named d_ino in the struct describing directory
+ headers. */
+#undef D_INO_IN_DIRENT
+
+/* The default editor to use, if one does not specify the "-e" option to cvs,
+ or does not have an EDITOR environment variable. If this is not set to an
+ absolute path to an executable, use the shell to find where the editor
+ actually is. This allows sites with /usr/bin/vi or /usr/ucb/vi to work
+ equally well (assuming that their PATH is reasonable). */
+#undef EDITOR_DFLT
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#undef ENABLE_NLS
+
+/* Define to enable encryption support. */
+#undef ENCRYPTION
+
+/* Define as good substitute value for EOVERFLOW. */
+#undef EOVERFLOW
+
+/* Define if this executable will be running on case insensitive file systems.
+ In the client case, this means that it will request that the server pretend
+ to be case insensitive if it isn't already. */
+#undef FILENAMES_CASE_INSENSITIVE
+
+/* Define on systems for which file names may have a so-called `drive letter'
+ prefix, define this to compute the length of that prefix, including the
+ colon. */
+#undef FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+
+/* Define if the backslash character may also serve as a file name component
+ separator. */
+#undef FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
+
+#if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+# define FILE_SYSTEM_PREFIX_LEN(Filename) \
+ ((Filename)[0] && (Filename)[1] == ':' ? 2 : 0)
+#else
+# define FILE_SYSTEM_PREFIX_LEN(Filename) 0
+#endif
+
+/* When committing or importing files, you must enter a log message. Normally,
+ you can do this either via the -m flag on the command line, the -F flag on
+ the command line, or an editor will be started for you. If you like to use
+ logging templates (the rcsinfo file within the $CVSROOT/CVSROOT directory),
+ you might want to force people to use the editor even if they specify a
+ message with -m or -F. Enabling FORCE_USE_EDITOR will cause the -m or -F
+ message to be appended to the temp file when the editor is started. */
+#undef FORCE_USE_EDITOR
+
+/* Define to an alternative value if GSS_C_NT_HOSTBASED_SERVICE isn't defined
+ in the gssapi.h header file. MIT Kerberos 1.2.1 requires this. Only
+ relevant when using GSSAPI. */
+#undef GSS_C_NT_HOSTBASED_SERVICE
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have `alloca' after including <alloca.h>, a header that
+ may be supplied by this distribution. */
+#undef HAVE_ALLOCA
+
+/* Define HAVE_ALLOCA_H for backward compatibility with older code that
+ includes <alloca.h> only if HAVE_ALLOCA_H is defined. */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the `atexit' function. */
+#undef HAVE_ATEXIT
+
+/* Define to 1 if you have the <bp-sym.h> header file. */
+#undef HAVE_BP_SYM_H
+
+/* Define to 1 if you have the `btowc' function. */
+#undef HAVE_BTOWC
+
+/* Define to 1 if you have the `canonicalize_file_name' function. */
+#undef HAVE_CANONICALIZE_FILE_NAME
+
+/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+#undef HAVE_CFLOCALECOPYCURRENT
+
+/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+#undef HAVE_CFPREFERENCESCOPYAPPVALUE
+
+/* Define to 1 if you have the `chsize' function. */
+#undef HAVE_CHSIZE
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `clock_settime' function. */
+#undef HAVE_CLOCK_SETTIME
+
+/* Define if you have the connect function. */
+#undef HAVE_CONNECT
+
+/* Define if you have the crypt function. */
+#undef HAVE_CRYPT
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+#undef HAVE_DCGETTEXT
+
+/* Define to 1 if you have the declaration of `clearerr_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_CLEARERR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FEOF_UNLOCKED
+
+/* Define to 1 if you have the declaration of `ferror_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FERROR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fflush_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FFLUSH_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FGETS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `flockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FLOCKFILE
+
+/* Define to 1 if you have the declaration of `fputc_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fputs_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fread_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FREAD_UNLOCKED
+
+/* Define to 1 if you have the declaration of `funlockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FUNLOCKFILE
+
+/* Define to 1 if you have the declaration of `fwrite_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FWRITE_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getcwd', and to 0 if you don't.
+ */
+#undef HAVE_DECL_GETCWD
+
+/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getdelim', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETDELIM
+
+/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
+ */
+#undef HAVE_DECL_GETENV
+
+/* Define to 1 if you have the declaration of `getline', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLINE
+
+/* Define to 1 if you have the declaration of `getlogin', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN
+
+/* Define to 1 if you have the declaration of `getlogin_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN_R
+
+/* Define to 1 if you have the declaration of `getpass', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETPASS
+
+/* Define to 1 if you have the declaration of `memrchr', and to 0 if you
+ don't. */
+#undef HAVE_DECL_MEMRCHR
+
+/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
+ don't. */
+#undef HAVE_DECL_NANOSLEEP
+
+/* Define to 1 if you have the declaration of `putchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_PUTCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `putc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_PUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `strdup', and to 0 if you don't.
+ */
+#undef HAVE_DECL_STRDUP
+
+/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_STRERROR_R
+
+/* Define to 1 if you have the declaration of `__fpending', and to 0 if you
+ don't. */
+#undef HAVE_DECL___FPENDING
+
+/* Define to 1 if you have the <direct.h> header file. */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dup2' function. */
+#undef HAVE_DUP2
+
+/* Define if you have the declaration of environ. */
+#undef HAVE_ENVIRON_DECL
+
+/* Define if you have the declaration of errno. */
+#undef HAVE_ERRNO_DECL
+
+/* Define to 1 if you have the `fchdir' function. */
+#undef HAVE_FCHDIR
+
+/* Define to 1 if you have the `fchmod' function. */
+#undef HAVE_FCHMOD
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `flockfile' function. */
+#undef HAVE_FLOCKFILE
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `fsync' function. */
+#undef HAVE_FSYNC
+
+/* Define to 1 if you have the `ftime' function. */
+#undef HAVE_FTIME
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have the `funlockfile' function. */
+#undef HAVE_FUNLOCKFILE
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `getgroups' function. */
+#undef HAVE_GETGROUPS
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getlogin_r' function. */
+#undef HAVE_GETLOGIN_R
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long_only' function. */
+#undef HAVE_GETOPT_LONG_ONLY
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define if you have the getspnam function. */
+#undef HAVE_GETSPNAM
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#undef HAVE_GETTEXT
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <glob.h> header file. */
+#undef HAVE_GLOB_H
+
+/* Define if you have GSSAPI with Kerberos version 5 available. */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
+/* Define if you have the iconv() function. */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_INTMAX_T
+
+/* Define if <inttypes.h> exists and doesn't clash with <sys/types.h>. */
+#undef HAVE_INTTYPES_H
+
+/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
+ declares uintmax_t. */
+#undef HAVE_INTTYPES_H_WITH_UINTMAX
+
+/* Define to 1 if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define to 1 if <sys/socket.h> defines AF_INET. */
+#undef HAVE_IPV4
+
+/* Define to 1 if <sys/socket.h> defines AF_INET6. */
+#undef HAVE_IPV6
+
+/* Define to 1 if you have the `isascii' function. */
+#undef HAVE_ISASCII
+
+/* Define to 1 if you have the `isblank' function. */
+#undef HAVE_ISBLANK
+
+/* Define to 1 if you have the `iswprint' function. */
+#undef HAVE_ISWPRINT
+
+/* Define if you have MIT Kerberos version 4 available. */
+#undef HAVE_KERBEROS
+
+/* Define to 1 if you have the <krb5.h> header file. */
+#undef HAVE_KRB5_H
+
+/* Define to 1 if you have the `krb_get_err_text' function. */
+#undef HAVE_KRB_GET_ERR_TEXT
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#undef HAVE_LANGINFO_CODESET
+
+/* Define to 1 if you have the `krb' library (-lkrb). */
+#undef HAVE_LIBKRB
+
+/* Define to 1 if you have the `krb4' library (-lkrb4). */
+#undef HAVE_LIBKRB4
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if you have the `login' function. */
+#undef HAVE_LOGIN
+
+/* Define to 1 if you have the `logout' function. */
+#undef HAVE_LOGOUT
+
+/* Define if you have the 'long double' type. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you support file names longer than 14 characters. */
+#undef HAVE_LONG_FILE_NAMES
+
+/* Define if you have the 'long long' type. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#undef HAVE_MALLOC
+
+/* Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including
+ config.h and <sys/mman.h>. */
+#undef HAVE_MAP_ANONYMOUS
+
+/* Define to 1 if you have the `mblen' function. */
+#undef HAVE_MBLEN
+
+/* Define to 1 if you have the `mbrlen' function. */
+#undef HAVE_MBRLEN
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#undef HAVE_MBRTOWC
+
+/* Define to 1 if you have the `mbsinit' function. */
+#undef HAVE_MBSINIT
+
+/* Define to 1 if you have the `mbsrtowcs' function. */
+#undef HAVE_MBSRTOWCS
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#undef HAVE_MBSTATE_T
+
+/* Define if you have memchr (always for CVS). */
+#undef HAVE_MEMCHR
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mempcpy' function. */
+#undef HAVE_MEMPCPY
+
+/* Define to 1 if you have the `memrchr' function. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if <limits.h> defines the MIN and MAX macros. */
+#undef HAVE_MINMAX_IN_LIMITS_H
+
+/* Define to 1 if <sys/param.h> defines the MIN and MAX macros. */
+#undef HAVE_MINMAX_IN_SYS_PARAM_H
+
+/* Define to 1 if you have the `mknod' function. */
+#undef HAVE_MKNOD
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `nanotime' function. */
+#undef HAVE_NANOTIME
+
+/* Define to 1 if you have the <ndbm.h> header file. */
+#undef HAVE_NDBM_H
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
+/* Define to 1 if you have the <OS.h> header file. */
+#undef HAVE_OS_H
+
+/* Define to enable system authentication with PAM instead of using the simple
+ getpwnam interface. This allows authentication (in theory) with any PAM
+ module, e.g. on systems with shadow passwords or via LDAP */
+#undef HAVE_PAM
+
+/* Define to 1 if pam/pam_appl.h is available */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
+ setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX is not
+ defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD is defined.
+ */
+#undef HAVE_PARTLY_WORKING_GETCWD
+
+/* Define to 1 if you have the `posix_memalign' function. */
+#undef HAVE_POSIX_MEMALIGN
+
+/* Define to 1 if the `printf' function supports the %p format for printing
+ pointers. */
+#undef HAVE_PRINTF_PTR
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#undef HAVE_PTRDIFF_T
+
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#undef HAVE_REALLOC
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the `regerror' function. */
+#undef HAVE_REGERROR
+
+/* Define to 1 if you have the `regexec' function. */
+#undef HAVE_REGEXEC
+
+/* Define to 1 if you have the `regfree' function. */
+#undef HAVE_REGFREE
+
+/* Define to 1 if you have the `resolvepath' function. */
+#undef HAVE_RESOLVEPATH
+
+/* Define to 1 if you have the `rpmatch' function. */
+#undef HAVE_RPMATCH
+
+/* Define to 1 if you have run the test for working tzset. */
+#undef HAVE_RUN_TZSET_TEST
+
+/* Define to 1 if you have the <search.h> header file. */
+#undef HAVE_SEARCH_H
+
+/* Define to 1 if security/pam_appl.h is available */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define if the diff library should use setmode for binary files. */
+#undef HAVE_SETMODE
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigblock' function. */
+#undef HAVE_SIGBLOCK
+
+/* Define to 1 if you have the `siginterrupt' function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define to 1 if you have the `sigsetmask' function. */
+#undef HAVE_SIGSETMASK
+
+/* Define to 1 if you have the `sigvec' function. */
+#undef HAVE_SIGVEC
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
+ uintmax_t. */
+#undef HAVE_STDINT_H_WITH_UINTMAX
+
+/* Define to 1 if you have the <stdio_ext.h> header file. */
+#undef HAVE_STDIO_EXT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define if you have strchr (always for CVS). */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strerror_r' function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define if there is a member named d_type in the struct describing directory
+ headers. */
+#undef HAVE_STRUCT_DIRENT_D_TYPE
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define if struct timespec is declared in <time.h>. */
+#undef HAVE_STRUCT_TIMESPEC
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_ZONE
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/inttypes.h> header file. */
+#undef HAVE_SYS_INTTYPES_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `tcgetattr' function. */
+#undef HAVE_TCGETATTR
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the `timezone' function. */
+#undef HAVE_TIMEZONE
+
+/* Define to 1 if localtime_r, etc. have the type signatures that POSIX
+ requires. */
+#undef HAVE_TIME_R_POSIX
+
+/* Define if struct tm has the tm_gmtoff member. */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#undef HAVE_TM_ZONE
+
+/* Define to 1 if you have the `tsearch' function. */
+#undef HAVE_TSEARCH
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+#undef HAVE_TZNAME
+
+/* Define to 1 if you have the `tzset' function. */
+#undef HAVE_TZSET
+
+/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_UINTMAX_T
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define if you have the 'unsigned long long' type. */
+#undef HAVE_UNSIGNED_LONG_LONG
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
+#undef HAVE_UTIME_NULL
+
+/* Define to 1 if you have the `vasnprintf' function. */
+#undef HAVE_VASNPRINTF
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#undef HAVE_VPRINTF
+
+/* Define to 1 if you have the `wait3' function. */
+#undef HAVE_WAIT3
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#undef HAVE_WCHAR_H
+
+/* Define if you have the 'wchar_t' type. */
+#undef HAVE_WCHAR_T
+
+/* Define to 1 if you have the `wcrtomb' function. */
+#undef HAVE_WCRTOMB
+
+/* Define to 1 if you have the `wcscoll' function. */
+#undef HAVE_WCSCOLL
+
+/* Define to 1 if you have the `wcslen' function. */
+#undef HAVE_WCSLEN
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#undef HAVE_WCTYPE_H
+
+/* Define if you have the 'wint_t' type. */
+#undef HAVE_WINT_T
+
+/* Define to 1 if you have the `wmemchr' function. */
+#undef HAVE_WMEMCHR
+
+/* Define to 1 if you have the `wmemcpy' function. */
+#undef HAVE_WMEMCPY
+
+/* Define to 1 if you have the `wmempcpy' function. */
+#undef HAVE_WMEMPCPY
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to 1 if you have the `__fpending' function. */
+#undef HAVE___FPENDING
+
+/* Define to 1 if you have the `__fsetlocking' function. */
+#undef HAVE___FSETLOCKING
+
+/* Define to 1 if you have the `__secure_getenv' function. */
+#undef HAVE___SECURE_GETENV
+
+#if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+#else
+# define ISSLASH(C) ((C) == '/')
+#endif
+
+/* Define to include locking code which prevents versions of CVS earlier than
+ 1.12.4 directly accessing the same repositiory as this executable from
+ ignoring this executable's promotable read locks. If only CVS versions
+ 1.12.4 and later will be accessing your repository directly (as a server or
+ locally), you can safely disable this option in return for fewer disk
+ accesses and a small speed increase. Disabling this option when versions of
+ CVS earlier than 1,12,4 _will_ be accessing your repository, however, is
+ *VERY* *VERY* *VERY* dangerous and could result in data loss. As such, by
+ default, CVS is compiled with this code enabled. If you are sure you would
+ like this code disabled, you can disable it by passing the
+ "--disable-lock-compatibility" option to configure or by commenting out the
+ lines below. */
+#undef LOCK_COMPATIBILITY
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
+
+/* If malloc(0) is != NULL, define this to 1. Otherwise define this to 0. */
+#undef MALLOC_0_IS_NONNULL
+
+/* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */
+#undef MAP_ANONYMOUS
+
+/* By default, CVS stores its modules and other such items in flat text files
+ (MY_NDBM enables this). Turning off MY_NDBM causes CVS to look for a
+ system-supplied ndbm database library and use it instead. That may speed
+ things up, but the default setting generally works fine too. */
+#undef MY_NDBM
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to set a service name for PAM. This must be defined. Define to
+ `program_name', without the quotes, to use whatever name CVS was invoked
+ as. Otherwise, define to a double-quoted literal string, such as `"cvs"'.
+ */
+#undef PAM_SERVICE_NAME
+
+/* the number of pending output bytes on stream `fp' */
+#undef PENDING_OUTPUT_N_BYTES
+
+/* Define if you want CVS to be able to serve as a transparent proxy for write
+ operations. Disabling this may produce a slight performance gain on some
+ systems, at the expense of write proxy support. */
+#undef PROXY_SUPPORT
+
+/* Path to the pr utility */
+#undef PR_PROGRAM
+
+/* Define to force lib/regex.c to use malloc instead of alloca. */
+#undef REGEX_MALLOC
+
+/* Define if rename does not work for source file names with a trailing slash,
+ like the one from SunOS 4.1.1_U1. */
+#undef RENAME_TRAILING_SLASH_BUG
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#undef RSH_DFLT
+
+/* If you are working with a large remote repository and a 'cvs checkout' is
+ swamping your network and memory, define these to enable flow control. You
+ will end up with even less probability of a consistent checkout (see
+ Concurrency in cvs.texinfo), but CVS doesn't try to guarantee that anyway.
+ The master server process will monitor how far it is getting behind, if it
+ reaches the high water mark, it will signal the child process to stop
+ generating data when convenient (ie: no locks are held, currently at the
+ beginning of a new directory). Once the buffer has drained sufficiently to
+ reach the low water mark, it will be signalled to start again. */
+#undef SERVER_FLOWCONTROL
+
+/* The high water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_HI_WATER
+
+/* The low water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_LO_WATER
+
+/* Define if you want CVS to be able to serve repositories to remote clients.
+ */
+#undef SERVER_SUPPORT
+
+/* The size of a `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of a `double', as computed by sizeof. */
+#undef SIZEOF_DOUBLE
+
+/* The size of a `float', as computed by sizeof. */
+#undef SIZEOF_FLOAT
+
+/* The size of a `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of a `intmax_t', as computed by sizeof. */
+#undef SIZEOF_INTMAX_T
+
+/* The size of a `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of a `long double', as computed by sizeof. */
+#undef SIZEOF_LONG_DOUBLE
+
+/* The size of a `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of a `ptrdiff_t', as computed by sizeof. */
+#undef SIZEOF_PTRDIFF_T
+
+/* The size of a `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of a `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of a `wint_t', as computed by sizeof. */
+#undef SIZEOF_WINT_T
+
+/* Define as the maximum value of type 'size_t', if the system doesn't define
+ it. */
+#undef SIZE_MAX
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#undef STAT_MACROS_BROKEN
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if strerror_r returns char *. */
+#undef STRERROR_R_CHAR_P
+
+/* Enable support for the pre 1.12.1 *info scripting hook format strings.
+ Disable this option for a smaller executable once your scripting hooks have
+ been updated to use the new *info format strings by passing
+ "--disable-old-info-format-support" option to configure or by commenting
+ out the line below. */
+#undef SUPPORT_OLD_INFO_FMT_STRINGS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little need
+ to change this (-T is a better mechanism if you need to use a different
+ directory for temporary files). */
+#undef TMPDIR_DFLT
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define if tzset clobbers localtime's static buffer. */
+#undef TZSET_CLOBBERS_LOCALTIME_BUFFER
+
+/* Define to its maximum value if an unsigned integer type of width exactly 32
+ bits exists and the standard includes do not define UINT32_MAX. */
+#undef UINT32_MAX
+
+/* The default umask to use when creating or otherwise setting file or
+ directory permissions in the repository. Must be a value in the range of 0
+ through 0777. For example, a value of 002 allows group rwx access and world
+ rx access; a value of 007 allows group rwx access but no world access. This
+ value is overridden by the value of the CVSUMASK environment variable,
+ which is interpreted as an octal number. */
+#undef UMASK_DFLT
+
+/* Define if double is the first floating point type detected with its size.
+ */
+#undef UNIQUE_FLOAT_TYPE_DOUBLE
+
+/* Define if float is the first floating point type detected with its size. */
+#undef UNIQUE_FLOAT_TYPE_FLOAT
+
+/* Define if long double is the first floating point type detected with its
+ size. */
+#undef UNIQUE_FLOAT_TYPE_LONG_DOUBLE
+
+/* Define if char is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_CHAR
+
+/* Define if int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INT
+
+/* Define if intmax_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INTMAX_T
+
+/* Define if long int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG
+
+/* Define if long long is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG_LONG
+
+/* Define if ptrdiff_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_PTRDIFF_T
+
+/* Define if short is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SHORT
+
+/* Define if size_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SIZE_T
+
+/* Define if wint_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_WINT_T
+
+/* Define if setmode is required when writing binary data to stdout. */
+#undef USE_SETMODE_STDOUT
+
+/* Define to 1 if you want getc etc. to use unlocked I/O if available.
+ Unlocked I/O can improve performance in unithreaded apps, but it is not
+ safe for multithreaded apps. */
+#undef USE_UNLOCKED_IO
+
+/* Define if utime requires write access to the file (true on Windows, but not
+ Unix). */
+#undef UTIME_EXPECTS_WRITABLE
+
+/* Define if unsetenv() returns void, not int. */
+#undef VOID_UNSETENV
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define if you want regoff_t to be at least as wide POSIX requires. */
+#undef _REGEX_LARGE_OFFSETS
+
+/* Define to force lib/regex.c to define re_comp et al. */
+#undef _REGEX_RE_COMP
+
+/* Define for Solaris 2.5.1 so uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+
+/* Define to rpl_ if the getcwd replacement function should be used. */
+#undef __GETCWD_PREFIX
+
+/* Define to rpl_ if the getopt replacement functions and variables should be
+ used. */
+#undef __GETOPT_PREFIX
+
+/* Define to rpl_ if the openat replacement function should be used. */
+#undef __OPENAT_PREFIX
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to a replacement function name for fnmatch(). */
+#undef fnmatch
+
+/* Define to a replacement function name for getline(). */
+#undef getline
+
+/* Define to a replacement function name for getpass(). */
+#undef getpass
+
+/* Define to rpl_gettimeofday if the replacement function should be used. */
+#undef gettimeofday
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to rpl_gmtime if the replacement function should be used. */
+#undef gmtime
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to long or long long if <inttypes.h> and <stdint.h> don't define. */
+#undef intmax_t
+
+/* Define to rpl_localtime if the replacement function should be used. */
+#undef localtime
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to a type if <wchar.h> does not define. */
+#undef mbstate_t
+
+/* Define to rpl_mkdir if the replacement function should be used. */
+#undef mkdir
+
+/* Define to rpl_mkstemp if the replacement function should be used. */
+#undef mkstemp
+
+/* Define to rpl_mktime if the replacement function should be used. */
+#undef mktime
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef mode_t
+
+/* Define to the name of the strftime replacement function. */
+#undef my_strftime
+
+/* Define to rpl_nanosleep if the replacement function should be used. */
+#undef nanosleep
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to rpl_realloc if the replacement function should be used. */
+#undef realloc
+
+/* Define to rpl_rename if the replacement function should be used. */
+#undef rename
+
+/* Define to equivalent of C99 restrict keyword, or to nothing if this is not
+ supported. Do not define if restrict is supported directly. */
+#undef restrict
+
+/* Define to rpl_select if the replacement function should be used. */
+#undef select
+
+/* Define to empty if the C compiler doesn't support this keyword. */
+#undef signed
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define as a signed type of the same size as size_t. */
+#undef ssize_t
+
+/* Define to rpl_strcasecmp always. */
+#undef strcasecmp
+
+/* Define to rpl_tzset if the wrapper function should be used. */
+#undef tzset
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to the type of a unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to unsigned long or unsigned long long if <stdint.h> and
+ <inttypes.h> don't define. */
+#undef uintmax_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
diff --git a/configure b/configure
new file mode 100755
index 0000000..23034a7
--- /dev/null
+++ b/configure
@@ -0,0 +1,43702 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59 for Concurrent Versions System (CVS) 1.12.13.
+#
+# Report bugs to <bug-cvs@nongnu.org>.
+#
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+# 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME='Concurrent Versions System (CVS)'
+PACKAGE_TARNAME='cvs'
+PACKAGE_VERSION='1.12.13'
+PACKAGE_STRING='Concurrent Versions System (CVS) 1.12.13'
+PACKAGE_BUGREPORT='bug-cvs@nongnu.org'
+
+ac_unique_file="src/cvs.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+gl_func_list=
+gl_header_list=
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar ac_prefix_program MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP EGREP RANLIB ac_ct_RANLIB LN_S PERL CSH MKTEMP SENDMAIL PR ROFF PS2PDF TEXI2DVI MAKE_TARGETS_IN_VPATH_TRUE MAKE_TARGETS_IN_VPATH_FALSE LIBOBJS ALLOCA ALLOCA_H STDBOOL_H HAVE__BOOL FNMATCH_H YACC YFLAGS LIB_CLOCK_GETTIME GETOPT_H GLOB_H LIB_NANOSLEEP HAVE_LONG_64BIT HAVE_LONG_LONG_64BIT STDINT_H EOVERFLOW MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE build build_cpu build_vendor build_os host host_cpu host_vendor host_os INTL_MACOSX_LIBS LIBICONV LTLIBICONV INTLLIBS LIBINTL LTLIBINTL POSUB cvs_client_objects KRB4 ZLIB_SUBDIRS ZLIB_CPPFLAGS ZLIB_LIBS with_default_rsh RSH_DFLT EDITOR LTLIBOBJS'
+ac_subst_files='MKTEMP_SH_FUNCTION'
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+ac_env_YACC_set=${YACC+set}
+ac_env_YACC_value=$YACC
+ac_cv_env_YACC_set=${YACC+set}
+ac_cv_env_YACC_value=$YACC
+ac_env_YFLAGS_set=${YFLAGS+set}
+ac_env_YFLAGS_value=$YFLAGS
+ac_cv_env_YFLAGS_set=${YFLAGS+set}
+ac_cv_env_YFLAGS_value=$YFLAGS
+ac_env_EDITOR_set=${EDITOR+set}
+ac_env_EDITOR_value=$EDITOR
+ac_cv_env_EDITOR_set=${EDITOR+set}
+ac_cv_env_EDITOR_value=$EDITOR
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures Concurrent Versions System (CVS) 1.12.13 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of Concurrent Versions System (CVS) 1.12.13:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --disable-largefile omit support for large files
+ --disable-nls do not use Native Language Support
+ --disable-rpath do not hardcode runtime library paths
+ --enable-cvs-ndbm Use the NDBM library distributed with CVS rather
+ than attempting to use a system NDBM library.
+ Disabling this may not work. (default)
+ --enable-client Include code for running as a remote client
+ (default)
+ --enable-password-authenticated-client
+ Enable pserver as a remote access method in the CVS
+ client (default)
+ --enable-server Include code for running as a server (default)
+ --enable-server-flow-control
+ If you are working with a large remote repository
+ and a 'cvs checkout' is swamping your network and
+ memory, define these to enable flow control. You may
+ optionally pass a low water mark in bytes and a high
+ water mark in bytes, separated by commas. (default
+ is enabled 1M,2M)
+ --enable-proxy Include code for running as a transparent proxy
+ server. Disabling this may produce a slight
+ performance gain on some systems, at the expense of
+ write proxy support. (default)
+ --enable-pam Use to enable system authentication with PAM instead
+ of using the simple getpwnam interface. This allows
+ authentication (in theory) with any PAM module, e.g.
+ on systems with shadow passwords or via LDAP
+ --enable-case-sensitivity
+ Force CVS to expect a case sensitive file system.
+ Enabling this on a case insensitive system should
+ have little effect on the server or client
+ operation, though client users may ocassionally be
+ suprised that the CVS server appears to be case
+ sensitive. Disabling this for a case sensitive
+ server disables server support for case insensitive
+ clients, which can confuse all users of case
+ insensitive clients contacting the server. Disabling
+ this for a case sensitive client will cause the
+ client to ask servers to behave case insensitively,
+ which could cause confusion for users, but also
+ probably no real harm. (default autoselects based on
+ the case sensitivity of the file system containing
+ the current working directory)
+ --enable-encryption Enable encryption support (disabled by default)
+ --enable-force-editor When committing or importing files, you must enter a
+ log message. Normally, you can do this either via
+ the -m flag on the command line, the -F flag on the
+ command line, or an editor will be started for you.
+ If you like to use logging templates (the rcsinfo
+ file within the $CVSROOT/CVSROOT directory), you
+ might want to force people to use the editor even if
+ they specify a message with -m or -F.
+ --enable-force-editor will cause the -m or -F
+ message to be appended to the temp file when the
+ editor is started. (disabled by default)
+ --enable-lock-compatibility
+ Include locking code which prevents versions of CVS
+ earlier than 1.12.4 directly accessing the same
+ repositiory as this executable from ignoring this
+ executable's promotable read locks. If only CVS
+ versions 1.12.4 and later will be accessing your
+ repository directly (as a server or locally), you
+ can safely disable this option in return for fewer
+ disk accesses and a small speed increase. Disabling
+ this option when versions of CVS earlier than 1,12,4
+ _will_ be accessing your repository, however, is
+ *VERY* *VERY* *VERY* dangerous and could result in
+ data loss. (enabled by default)
+ --enable-rootcommit Allow the root user to commit files (disabled by
+ default)
+ --enable-old-info-format-support
+ Enable support for the pre 1.12.1 *info scripting
+ hook format strings. Disable this option for a
+ smaller executable once your scripting hooks have
+ been updated to use the new *info format strings
+ (default).
+ --enable-config-override
+ Set to a comma-seperated list of paths to
+ directories (designated by trailing `/') and files,
+ specifies the path prefixes (for directories) and
+ paths to files the CVS server commands will allow
+ configuration to be read from. Specify
+ `--enable-config-override=no' to disable config file
+ overrides completely and
+ `--enable-config-override=/' or simply
+ `--enable-config-override' to allow all paths.
+ (Defaults to `SYSCONFDIR/cvs.conf,SYSCONFDIR/cvs/')
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-included-regex
+ don't compile regex; this is the default on systems
+ with recent-enough versions of the GNU C Library
+ (use with caution on other systems)
+ --with-gnu-ld assume the C compiler uses GNU ld default=no
+ --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib
+ --without-libiconv-prefix don't search for libiconv in includedir and libdir
+ --with-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib
+ --without-libintl-prefix don't search for libintl in includedir and libdir
+ --with-krb4 Kerberos 4 directory (default /usr/kerberos)
+ --with-gssapi GSSAPI directory (default autoselects)
+ --with-external-zlib Use the specified ZLIB library (defaults to the
+ version distributed with the CVS source)
+ --with-rsh The default remote shell CVS will use for :ext:
+ transport (default ssh)
+ --with-editor The default text editor CVS should use for log
+ messages (default autoselects)
+ --with-hardcoded-pam-service-name
+ Use this to hard code a service name for PAM CVS
+ authentication. The special name, `program_name',
+ will cause CVS to use whatever name it was invoked
+ as as the service name. (defaults to `cvs')
+ --with-tmpdir The temporary directory CVS should use as a default
+ (default autoselects)
+ --with-umask Set the umask CVS will use by default in the
+ repository (default 002)
+ --with-cvs-admin-group=GROUP
+ The CVS admin command is restricted to the members
+ of this group. If this group does not exist, all
+ users are allowed to run CVS admin. To disable the
+ CVS admin command for all users, create an empty
+ group by specifying the --with-cvs-admin-group=
+ option. To disable access control for CVS admin, run
+ configure with the --without-cvs-admin-group option.
+ (default 'cvsadmin')
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ YACC The `Yet Another C Compiler' implementation to use. Defaults to
+ `bison -y'. Values other than `bison -y' will most likely break
+ on most systems.
+ YFLAGS YFLAGS contains the list arguments that will be passed by
+ default to Bison. This script will default YFLAGS to the empty
+ string to avoid a default value of `-d' given by some make
+ applications.
+ EDITOR The text editor CVS will use by default for log messages.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <bug-cvs@nongnu.org>.
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+Concurrent Versions System (CVS) configure 1.12.13
+generated by GNU Autoconf 2.59
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+
+Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by Concurrent Versions System (CVS) $as_me 1.12.13, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+gl_func_list="$gl_func_list fchdir"
+gl_header_list="$gl_header_list unistd.h"
+gl_func_list="$gl_func_list mempcpy"
+gl_header_list="$gl_header_list sys/time.h"
+gl_func_list="$gl_func_list isascii"
+gl_header_list="$gl_header_list sys/param.h"
+gl_header_list="$gl_header_list stdio_ext.h"
+gl_header_list="$gl_header_list termios.h"
+gl_func_list="$gl_func_list __fsetlocking"
+gl_func_list="$gl_func_list tcgetattr"
+gl_func_list="$gl_func_list tcsetattr"
+gl_func_list="$gl_func_list gettimeofday"
+gl_func_list="$gl_func_list nanotime"
+gl_header_list="$gl_header_list sys/cdefs.h"
+gl_func_list="$gl_func_list getlogin_r"
+gl_func_list="$gl_func_list getpwnam_r"
+gl_header_list="$gl_header_list wchar.h"
+gl_header_list="$gl_header_list wctype.h"
+gl_header_list="$gl_header_list stdint.h"
+gl_func_list="$gl_func_list siginterrupt"
+gl_func_list="$gl_func_list posix_memalign"
+gl_func_list="$gl_func_list iswprint"
+gl_func_list="$gl_func_list mbsinit"
+gl_header_list="$gl_header_list locale.h"
+gl_func_list="$gl_func_list isblank"
+gl_func_list="$gl_func_list mbrtowc"
+gl_func_list="$gl_func_list wcrtomb"
+gl_func_list="$gl_func_list wcscoll"
+gl_func_list="$gl_func_list mblen"
+gl_func_list="$gl_func_list mbrlen"
+gl_func_list="$gl_func_list tzset"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in build-aux $srcdir/build-aux; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in build-aux $srcdir/build-aux" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in build-aux $srcdir/build-aux" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+am__api_version="1.9"
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,$program_prefix,;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$,$program_suffix,;$program_transform_name"
+# Double any \ or $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm conftest.sed
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='cvs'
+ VERSION='1.12.13'
+
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+
+if test "x$prefix" = xNONE; then
+ echo $ECHO_N "checking for prefix by $ECHO_C" >&6
+ # Extract the first word of "cvs", so it can be a program name with args.
+set dummy cvs; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_ac_prefix_program+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ac_prefix_program in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_prefix_program="$ac_prefix_program" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_prefix_program="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+ac_prefix_program=$ac_cv_path_ac_prefix_program
+
+if test -n "$ac_prefix_program"; then
+ echo "$as_me:$LINENO: result: $ac_prefix_program" >&5
+echo "${ECHO_T}$ac_prefix_program" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ if test -n "$ac_prefix_program"; then
+ prefix=`(dirname "$ac_prefix_program") 2>/dev/null ||
+$as_expr X"$ac_prefix_program" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_prefix_program" : 'X\(//\)[^/]' \| \
+ X"$ac_prefix_program" : 'X\(//\)$' \| \
+ X"$ac_prefix_program" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_prefix_program" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ prefix=`(dirname "$prefix") 2>/dev/null ||
+$as_expr X"$prefix" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$prefix" : 'X\(//\)[^/]' \| \
+ X"$prefix" : 'X\(//\)$' \| \
+ X"$prefix" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$prefix" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ fi
+fi
+
+ ac_config_headers="$ac_config_headers config.h"
+
+echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi;
+ echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5
+echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6
+
+
+if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _GNU_SOURCE 1
+_ACEOF
+
+
+DEPDIR="${am__leading_dot}deps"
+
+ ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+ enableval="$enable_dependency_tracking"
+
+fi;
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+
+
+if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+
+echo "$as_me:$LINENO: checking for AIX" >&5
+echo $ECHO_N "checking for AIX... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef _AIX
+ yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+cat >>confdefs.h <<\_ACEOF
+#define _ALL_SOURCE 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for minix/config.h" >&5
+echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5
+echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking minix/config.h usability" >&5
+echo $ECHO_N "checking minix/config.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <minix/config.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking minix/config.h presence" >&5
+echo $ECHO_N "checking minix/config.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <minix/config.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: minix/config.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: minix/config.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: minix/config.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: minix/config.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: minix/config.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for minix/config.h" >&5
+echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_minix_config_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5
+echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6
+
+fi
+if test $ac_cv_header_minix_config_h = yes; then
+ MINIX=yes
+else
+ MINIX=
+fi
+
+
+if test "$MINIX" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define _POSIX_SOURCE 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _POSIX_1_SOURCE 2
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _MINIX 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+ cat >>confdefs.h <<\_ACEOF
+#define __EXTENSIONS__ 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _POSIX_PTHREAD_SEMANTICS 1
+_ACEOF
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+if test "x$CC" != xcc; then
+ echo "$as_me:$LINENO: checking whether $CC and cc understand -c and -o together" >&5
+echo $ECHO_N "checking whether $CC and cc understand -c and -o together... $ECHO_C" >&6
+else
+ echo "$as_me:$LINENO: checking whether cc understands -c and -o together" >&5
+echo $ECHO_N "checking whether cc understands -c and -o together... $ECHO_C" >&6
+fi
+set dummy $CC; ac_cc=`echo $2 |
+ sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if eval "test \"\${ac_cv_prog_cc_${ac_cc}_c_o+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='$CC -c conftest.$ac_ext -o conftest.$ac_objext >&5'
+if { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ test -f conftest.$ac_objext && { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); };
+then
+ eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+ if test "x$CC" != xcc; then
+ # Test first that cc exists at all.
+ if { ac_try='cc -c conftest.$ac_ext >&5'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_try='cc -c conftest.$ac_ext -o conftest.$ac_objext >&5'
+ if { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ test -f conftest.$ac_objext && { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); };
+ then
+ # cc works too.
+ :
+ else
+ # cc exists but doesn't like -o.
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+ fi
+ fi
+ fi
+else
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_MINUS_C_MINUS_O 1
+_ACEOF
+
+fi
+
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+ac_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+
+
+# Find the posix library needed on INTERACTIVE UNIX (ISC)
+echo "$as_me:$LINENO: checking for library containing strerror" >&5
+echo $ECHO_N "checking for library containing strerror... $ECHO_C" >&6
+if test "${ac_cv_search_strerror+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_strerror=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strerror ();
+int
+main ()
+{
+strerror ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_strerror="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_strerror" = no; then
+ for ac_lib in cposix; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strerror ();
+int
+main ()
+{
+strerror ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_strerror="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_strerror" >&5
+echo "${ECHO_T}$ac_cv_search_strerror" >&6
+if test "$ac_cv_search_strerror" != no; then
+ test "$ac_cv_search_strerror" = "none required" || LIBS="$ac_cv_search_strerror $LIBS"
+
+fi
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
+# Check whether --enable-largefile or --disable-largefile was given.
+if test "${enable_largefile+set}" = set; then
+ enableval="$enable_largefile"
+
+fi;
+if test "$enable_largefile" != no; then
+
+ echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5
+echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6
+if test "${ac_cv_sys_largefile_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_sys_largefile_CC=no
+ if test "$GCC" != yes; then
+ ac_save_CC=$CC
+ while :; do
+ # IRIX 6.2 and later do not support large files by default,
+ # so use the C compiler's -n32 option if that helps.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+ CC="$CC -n32"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sys_largefile_CC=' -n32'; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+ break
+ done
+ CC=$ac_save_CC
+ rm -f conftest.$ac_ext
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5
+echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6
+ if test "$ac_cv_sys_largefile_CC" != no; then
+ CC=$CC$ac_cv_sys_largefile_CC
+ fi
+
+ echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ while :; do
+ ac_cv_sys_file_offset_bits=no
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sys_file_offset_bits=64; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ break
+done
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5
+echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6
+if test "$ac_cv_sys_file_offset_bits" != no; then
+
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+
+fi
+rm -f conftest*
+ echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5
+echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6
+if test "${ac_cv_sys_large_files+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ while :; do
+ ac_cv_sys_large_files=no
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sys_large_files=1; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ break
+done
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5
+echo "${ECHO_T}$ac_cv_sys_large_files" >&6
+if test "$ac_cv_sys_large_files" != no; then
+
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+
+fi
+rm -f conftest*
+fi
+
+
+
+# Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PERL+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PERL in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="no"
+ ;;
+esac
+fi
+PERL=$ac_cv_path_PERL
+
+if test -n "$PERL"; then
+ echo "$as_me:$LINENO: result: $PERL" >&5
+echo "${ECHO_T}$PERL" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "csh", so it can be a program name with args.
+set dummy csh; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_CSH+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $CSH in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_CSH="$CSH" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_CSH="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_CSH" && ac_cv_path_CSH="no"
+ ;;
+esac
+fi
+CSH=$ac_cv_path_CSH
+
+if test -n "$CSH"; then
+ echo "$as_me:$LINENO: result: $CSH" >&5
+echo "${ECHO_T}$CSH" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# for contrib/rcs2log.sh & src/cvsbug.in.
+# Extract the first word of "mktemp", so it can be a program name with args.
+set dummy mktemp; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_MKTEMP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MKTEMP in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MKTEMP="$MKTEMP" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_MKTEMP="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_MKTEMP" && ac_cv_path_MKTEMP="mktemp"
+ ;;
+esac
+fi
+MKTEMP=$ac_cv_path_MKTEMP
+
+if test -n "$MKTEMP"; then
+ echo "$as_me:$LINENO: result: $MKTEMP" >&5
+echo "${ECHO_T}$MKTEMP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test x"$MKTEMP" = xmktemp; then
+ MKTEMP_SH_FUNCTION=$srcdir/mktemp.sh
+else
+ MKTEMP_SH_FUNCTION=/dev/null
+fi
+
+# for src/cvsbug.in
+# Extract the first word of "sendmail", so it can be a program name with args.
+set dummy sendmail; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_SENDMAIL+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $SENDMAIL in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_SENDMAIL="$SENDMAIL" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="$PATH:/usr/sbin:/usr/lib"
+for as_dir in $as_dummy
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_SENDMAIL="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_SENDMAIL" && ac_cv_path_SENDMAIL="no"
+ ;;
+esac
+fi
+SENDMAIL=$ac_cv_path_SENDMAIL
+
+if test -n "$SENDMAIL"; then
+ echo "$as_me:$LINENO: result: $SENDMAIL" >&5
+echo "${ECHO_T}$SENDMAIL" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# For diff/util.c
+# Extract the first word of "pr", so it can be a program name with args.
+set dummy pr; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PR="$PR" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PR="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_PR" && ac_cv_path_PR="no"
+ ;;
+esac
+fi
+PR=$ac_cv_path_PR
+
+if test -n "$PR"; then
+ echo "$as_me:$LINENO: result: $PR" >&5
+echo "${ECHO_T}$PR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test x"$PR" != xno; then
+
+cat >>confdefs.h <<_ACEOF
+#define PR_PROGRAM "$PR"
+_ACEOF
+
+fi
+
+missing_dir=`cd $ac_aux_dir && pwd`
+glocs="$PATH:/usr/local/bin:/usr/contrib/bin:/usr/gnu/bin:/local/bin:/local/gnu/bin:/gnu/bin"
+for ac_prog in groff roff
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_ROFF+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ROFF in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ROFF="$ROFF" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $glocs
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ROFF="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+ROFF=$ac_cv_path_ROFF
+
+if test -n "$ROFF"; then
+ echo "$as_me:$LINENO: result: $ROFF" >&5
+echo "${ECHO_T}$ROFF" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ROFF" && break
+done
+test -n "$ROFF" || ROFF="$missing_dir/missing roff"
+
+# Extract the first word of "ps2pdf", so it can be a program name with args.
+set dummy ps2pdf; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PS2PDF+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PS2PDF in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PS2PDF="$PS2PDF" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PS2PDF="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_PS2PDF" && ac_cv_path_PS2PDF="$missing_dir/missing ps2pdf"
+ ;;
+esac
+fi
+PS2PDF=$ac_cv_path_PS2PDF
+
+if test -n "$PS2PDF"; then
+ echo "$as_me:$LINENO: result: $PS2PDF" >&5
+echo "${ECHO_T}$PS2PDF" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "texi2dvi", so it can be a program name with args.
+set dummy texi2dvi; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_TEXI2DVI+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $TEXI2DVI in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_TEXI2DVI="$TEXI2DVI" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_TEXI2DVI="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_TEXI2DVI" && ac_cv_path_TEXI2DVI="$missing_dir/missing texi2dvi"
+ ;;
+esac
+fi
+TEXI2DVI=$ac_cv_path_TEXI2DVI
+
+if test -n "$TEXI2DVI"; then
+ echo "$as_me:$LINENO: result: $TEXI2DVI" >&5
+echo "${ECHO_T}$TEXI2DVI" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+echo "$as_me:$LINENO: checking whether #! works in shell scripts" >&5
+echo $ECHO_N "checking whether #! works in shell scripts... $ECHO_C" >&6
+if test "${ac_cv_sys_interpreter+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ echo '#! /bin/cat
+exit 69
+' >conftest
+chmod u+x conftest
+(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null)
+if test $? -ne 69; then
+ ac_cv_sys_interpreter=yes
+else
+ ac_cv_sys_interpreter=no
+fi
+rm -f conftest
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_interpreter" >&5
+echo "${ECHO_T}$ac_cv_sys_interpreter" >&6
+interpval=$ac_cv_sys_interpreter
+
+if test X"$ac_cv_sys_interpreter" != X"yes" ; then
+ # silly trick to avoid problems in AC macros...
+ ac_msg='perl scripts using #! may not be invoked properly'
+ { echo "$as_me:$LINENO: WARNING: $ac_msg" >&5
+echo "$as_me: WARNING: $ac_msg" >&2;}
+fi
+
+# BSD's logo is a devil for a reason, hey?
+echo "$as_me:$LINENO: checking for BSD VPATH bug in make" >&5
+echo $ECHO_N "checking for BSD VPATH bug in make... $ECHO_C" >&6
+if test "${ccvs_cv_bsd_make_vpath_bug+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test ! -d ac_test_dir ; then
+ { ac_try='mkdir ac_test_dir'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }
+fi
+cat >conftestmake <<EOF
+VPATH = ac_test_dir
+ac_test_target: ac_test_dep
+ echo BSD VPATH bug present >&2
+ac_test_dep: ac_test_dep_dep
+EOF
+touch ac_test_dir/ac_test_dep_dep
+touch ac_test_dir/ac_test_dep
+touch ac_test_target
+# Don't know why, but the following test doesn't work under FreeBSD 4.2
+# without this sleep command
+sleep 1
+if { ac_try='make -f conftestmake 2>&1 >/dev/null |grep ^BSD\ VPATH\ bug\ present\$ >/dev/null'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } ; then
+ ccvs_cv_bsd_make_vpath_bug=yes
+else
+ ccvs_cv_bsd_make_vpath_bug=no
+fi
+{ ac_try='rm -rf ac_test_dir ac_test_target conftestmake'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_bsd_make_vpath_bug" >&5
+echo "${ECHO_T}$ccvs_cv_bsd_make_vpath_bug" >&6
+# We also don't need to worry about the bug when $srcdir = $builddir
+
+
+if \
+ test $ccvs_cv_bsd_make_vpath_bug = no \
+ || test $srcdir = .; then
+ MAKE_TARGETS_IN_VPATH_TRUE=
+ MAKE_TARGETS_IN_VPATH_FALSE='#'
+else
+ MAKE_TARGETS_IN_VPATH_TRUE='#'
+ MAKE_TARGETS_IN_VPATH_FALSE=
+fi
+
+
+
+
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+ as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5
+echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+ echo "$as_me:$LINENO: checking for library containing opendir" >&5
+echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6
+if test "${ac_cv_search_opendir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_opendir=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir ();
+int
+main ()
+{
+opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_opendir="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_opendir" = no; then
+ for ac_lib in dir; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir ();
+int
+main ()
+{
+opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_opendir="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5
+echo "${ECHO_T}$ac_cv_search_opendir" >&6
+if test "$ac_cv_search_opendir" != no; then
+ test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS"
+
+fi
+
+else
+ echo "$as_me:$LINENO: checking for library containing opendir" >&5
+echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6
+if test "${ac_cv_search_opendir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_opendir=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir ();
+int
+main ()
+{
+opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_opendir="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_opendir" = no; then
+ for ac_lib in x; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir ();
+int
+main ()
+{
+opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_opendir="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5
+echo "${ECHO_T}$ac_cv_search_opendir" >&6
+if test "$ac_cv_search_opendir" != no; then
+ test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS"
+
+fi
+
+fi
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5
+echo $ECHO_N "checking for sys/wait.h that is POSIX.1 compatible... $ECHO_C" >&6
+if test "${ac_cv_header_sys_wait_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+ int s;
+ wait (&s);
+ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6
+if test $ac_cv_header_sys_wait_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYS_WAIT_H 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in \
+ direct.h \
+ fcntl.h \
+ io.h \
+ memory.h \
+ ndbm.h \
+ stdint.h \
+ syslog.h \
+ sys/bsdtypes.h \
+ sys/file.h \
+ sys/param.h \
+ sys/resource.h \
+ sys/select.h \
+ unistd.h \
+ utime.h\
+
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+echo "$as_me:$LINENO: checking whether stat file-mode macros are broken" >&5
+echo $ECHO_N "checking whether stat file-mode macros are broken... $ECHO_C" >&6
+if test "${ac_cv_header_stat_broken+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "You lose" >/dev/null 2>&1; then
+ ac_cv_header_stat_broken=yes
+else
+ ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stat_broken" >&5
+echo "${ECHO_T}$ac_cv_header_stat_broken" >&6
+if test $ac_cv_header_stat_broken = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STAT_MACROS_BROKEN 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5
+echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6
+if test "${ac_cv_type_uid_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "uid_t" >/dev/null 2>&1; then
+ ac_cv_type_uid_t=yes
+else
+ ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5
+echo "${ECHO_T}$ac_cv_type_uid_t" >&6
+if test $ac_cv_type_uid_t = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define uid_t int
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define gid_t int
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for mode_t" >&5
+echo $ECHO_N "checking for mode_t... $ECHO_C" >&6
+if test "${ac_cv_type_mode_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((mode_t *) 0)
+ return 0;
+if (sizeof (mode_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_mode_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_mode_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_mode_t" >&5
+echo "${ECHO_T}$ac_cv_type_mode_t" >&6
+if test $ac_cv_type_mode_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define mode_t int
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for pid_t" >&5
+echo $ECHO_N "checking for pid_t... $ECHO_C" >&6
+if test "${ac_cv_type_pid_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((pid_t *) 0)
+ return 0;
+if (sizeof (pid_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_pid_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_pid_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5
+echo "${ECHO_T}$ac_cv_type_pid_t" >&6
+if test $ac_cv_type_pid_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_signal=void
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+echo "$as_me:$LINENO: checking for struct stat.st_blksize" >&5
+echo $ECHO_N "checking for struct stat.st_blksize... $ECHO_C" >&6
+if test "${ac_cv_member_struct_stat_st_blksize+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (ac_aggr.st_blksize)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_stat_st_blksize=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (sizeof ac_aggr.st_blksize)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_stat_st_blksize=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_stat_st_blksize=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_blksize" >&5
+echo "${ECHO_T}$ac_cv_member_struct_stat_st_blksize" >&6
+if test $ac_cv_member_struct_stat_st_blksize = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
+_ACEOF
+
+
+fi
+
+echo "$as_me:$LINENO: checking for struct stat.st_rdev" >&5
+echo $ECHO_N "checking for struct stat.st_rdev... $ECHO_C" >&6
+if test "${ac_cv_member_struct_stat_st_rdev+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (ac_aggr.st_rdev)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_stat_st_rdev=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (sizeof ac_aggr.st_rdev)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_stat_st_rdev=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_stat_st_rdev=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_rdev" >&5
+echo "${ECHO_T}$ac_cv_member_struct_stat_st_rdev" >&6
+if test $ac_cv_member_struct_stat_st_rdev = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+_ACEOF
+
+
+fi
+
+
+echo "$as_me:$LINENO: checking for _LARGEFILE_SOURCE value needed for large files" >&5
+echo $ECHO_N "checking for _LARGEFILE_SOURCE value needed for large files... $ECHO_C" >&6
+if test "${ac_cv_sys_largefile_source+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ while :; do
+ ac_cv_sys_largefile_source=no
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+return !fseeko;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#define _LARGEFILE_SOURCE 1
+#include <stdio.h>
+int
+main ()
+{
+return !fseeko;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sys_largefile_source=1; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ break
+done
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_source" >&5
+echo "${ECHO_T}$ac_cv_sys_largefile_source" >&6
+if test "$ac_cv_sys_largefile_source" != no; then
+
+cat >>confdefs.h <<_ACEOF
+#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source
+_ACEOF
+
+fi
+rm -f conftest*
+
+# We used to try defining _XOPEN_SOURCE=500 too, to work around a bug
+# in glibc 2.1.3, but that breaks too many other things.
+# If you want fseeko and ftello with glibc, upgrade to a fixed glibc.
+echo "$as_me:$LINENO: checking for fseeko" >&5
+echo $ECHO_N "checking for fseeko... $ECHO_C" >&6
+if test "${ac_cv_func_fseeko+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+return fseeko && fseeko (stdin, 0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_fseeko=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_fseeko=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_fseeko" >&5
+echo "${ECHO_T}$ac_cv_func_fseeko" >&6
+if test $ac_cv_func_fseeko = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FSEEKO 1
+_ACEOF
+
+fi
+
+if test $ac_cv_func_fseeko = no; then
+ case $LIBOBJS in
+ "fseeko.$ac_objext" | \
+ *" fseeko.$ac_objext" | \
+ "fseeko.$ac_objext "* | \
+ *" fseeko.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS fseeko.$ac_objext" ;;
+esac
+
+ case $LIBOBJS in
+ "ftello.$ac_objext" | \
+ *" ftello.$ac_objext" | \
+ "ftello.$ac_objext "* | \
+ *" ftello.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS ftello.$ac_objext" ;;
+esac
+
+fi
+
+# Replace functions with versions in lib/ when they can't be found.
+
+for ac_func in \
+ waitpid \
+
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+
+#
+# Special hack for a SunOS 5.7 (aka Solaris 7) select() problem.
+#
+
+
+for ac_header in fcntl.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ echo "$as_me:$LINENO: checking whether select hangs on /dev/null fd when timeout is NULL" >&5
+echo $ECHO_N "checking whether select hangs on /dev/null fd when timeout is NULL... $ECHO_C" >&6
+if test "${ccvs_cv_func_select_hang+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ccvs_cv_func_select_hang=yes
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <sys/select.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#include <errno.h>
+int
+main ()
+{
+
+ int numfds;
+ fd_set readfds;
+ struct timeval timeout;
+ int fd = open ("/dev/null", O_RDONLY);
+
+ FD_ZERO (&readfds);
+ FD_SET (fd, &readfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1;
+
+ while ((numfds = select (fd + 1, &readfds, NULL, NULL, &timeout)) < 0
+ && errno == EINTR);
+ return (numfds <= 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ccvs_cv_func_select_hang=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ccvs_cv_func_select_hang=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_func_select_hang" >&5
+echo "${ECHO_T}$ccvs_cv_func_select_hang" >&6
+ if test $ccvs_cv_func_select_hang = yes; then
+
+
+
+for ac_header in fcntl.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ case $LIBOBJS in
+ "sunos57-select.$ac_objext" | \
+ *" sunos57-select.$ac_objext" | \
+ "sunos57-select.$ac_objext "* | \
+ *" sunos57-select.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS sunos57-select.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define select rpl_select
+_ACEOF
+
+ fi
+
+
+#
+# Begin GNULIB stuff.
+#
+
+# Look for functions from GNULIB and replace with versions in lib/ when
+# necessary.
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo "$as_me:$LINENO: checking for working alloca.h" >&5
+echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6
+if test "${ac_cv_working_alloca_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_working_alloca_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_working_alloca_h=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5
+echo "${ECHO_T}$ac_cv_working_alloca_h" >&6
+if test $ac_cv_working_alloca_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA_H 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for alloca" >&5
+echo $ECHO_N "checking for alloca... $ECHO_C" >&6
+if test "${ac_cv_func_alloca_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_alloca_works=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_alloca_works=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5
+echo "${ECHO_T}$ac_cv_func_alloca_works" >&6
+
+if test $ac_cv_func_alloca_works = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA 1
+_ACEOF
+
+else
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+# that cause trouble. Some versions do not even contain alloca or
+# contain a buggy version. If you still want to use their alloca,
+# use ar to extract alloca.o from them instead of compiling alloca.c.
+
+ALLOCA=alloca.$ac_objext
+
+cat >>confdefs.h <<\_ACEOF
+#define C_ALLOCA 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5
+echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6
+if test "${ac_cv_os_cray+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "webecray" >/dev/null 2>&1; then
+ ac_cv_os_cray=yes
+else
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5
+echo "${ECHO_T}$ac_cv_os_cray" >&6
+if test $ac_cv_os_cray = yes; then
+ for ac_func in _getb67 GETB67 getb67; do
+ as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define CRAY_STACKSEG_END $ac_func
+_ACEOF
+
+ break
+fi
+
+ done
+fi
+
+echo "$as_me:$LINENO: checking stack direction for C alloca" >&5
+echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6
+if test "${ac_cv_c_stack_direction+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+
+int
+main ()
+{
+ exit (find_stack_direction () < 0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_stack_direction=1
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_stack_direction=-1
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5
+echo "${ECHO_T}$ac_cv_c_stack_direction" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+_ACEOF
+
+
+fi
+
+
+
+for ac_header in stdlib.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5
+echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6
+if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_malloc_0_nonnull=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#if STDC_HEADERS || HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+int
+main ()
+{
+exit (malloc (0) ? 0 : 1);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_malloc_0_nonnull=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_malloc_0_nonnull=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5
+echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6
+if test $ac_cv_func_malloc_0_nonnull = yes; then
+ gl_cv_func_malloc_0_nonnull=1
+else
+ gl_cv_func_malloc_0_nonnull=0
+fi
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define MALLOC_0_IS_NONNULL $gl_cv_func_malloc_0_nonnull
+_ACEOF
+
+
+
+ echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6
+if test "${ac_cv_type_long_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+long long ll = 1LL; int i = 63;
+int
+main ()
+{
+long long llmax = (long long) -1;
+ return ll << i | ll >> i | llmax / ll | llmax % ll;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_long_long=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_long_long=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6
+ if test $ac_cv_type_long_long = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LONG_LONG 1
+_ACEOF
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for long double" >&5
+echo $ECHO_N "checking for long double... $ECHO_C" >&6
+if test "${gt_cv_c_long_double+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$GCC" = yes; then
+ gt_cv_c_long_double=yes
+ else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ /* The Stardent Vistra knows sizeof(long double), but does not support it. */
+ long double foo = 0.0;
+ /* On Ultrix 4.3 cc, long double is 4 and double is 8. */
+ int array [2*(sizeof(long double) >= sizeof(double)) - 1];
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_c_long_double=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_c_long_double=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+fi
+echo "$as_me:$LINENO: result: $gt_cv_c_long_double" >&5
+echo "${ECHO_T}$gt_cv_c_long_double" >&6
+ if test $gt_cv_c_long_double = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LONG_DOUBLE 1
+_ACEOF
+
+ fi
+
+echo "$as_me:$LINENO: checking for C/C++ restrict keyword" >&5
+echo $ECHO_N "checking for C/C++ restrict keyword... $ECHO_C" >&6
+if test "${gl_cv_c_restrict+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gl_cv_c_restrict=no
+ # Try the official restrict keyword, then gcc's __restrict, and
+ # the less common variants.
+ for ac_kw in restrict __restrict __restrict__ _Restrict; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+float * $ac_kw x;
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_c_restrict=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+
+fi
+echo "$as_me:$LINENO: result: $gl_cv_c_restrict" >&5
+echo "${ECHO_T}$gl_cv_c_restrict" >&6
+ case $gl_cv_c_restrict in
+ restrict) ;;
+ no)
+cat >>confdefs.h <<\_ACEOF
+#define restrict
+_ACEOF
+ ;;
+ *) cat >>confdefs.h <<_ACEOF
+#define restrict $gl_cv_c_restrict
+_ACEOF
+ ;;
+ esac
+
+
+ echo "$as_me:$LINENO: checking for IPv4 sockets" >&5
+echo $ECHO_N "checking for IPv4 sockets... $ECHO_C" >&6
+ if test "${gl_cv_socket_ipv4+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int
+main ()
+{
+int x = AF_INET; struct in_addr y; struct sockaddr_in z;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_socket_ipv4=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_socket_ipv4=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ echo "$as_me:$LINENO: result: $gl_cv_socket_ipv4" >&5
+echo "${ECHO_T}$gl_cv_socket_ipv4" >&6
+ if test $gl_cv_socket_ipv4 = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV4 1
+_ACEOF
+
+ fi
+
+ echo "$as_me:$LINENO: checking for IPv6 sockets" >&5
+echo $ECHO_N "checking for IPv6 sockets... $ECHO_C" >&6
+ if test "${gl_cv_socket_ipv6+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int
+main ()
+{
+int x = AF_INET6; struct in6_addr y; struct sockaddr_in6 z;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_socket_ipv6=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_socket_ipv6=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ echo "$as_me:$LINENO: result: $gl_cv_socket_ipv6" >&5
+echo "${ECHO_T}$gl_cv_socket_ipv6" >&6
+ if test $gl_cv_socket_ipv6 = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ fi
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+
+ echo "$as_me:$LINENO: checking for library containing getaddrinfo" >&5
+echo $ECHO_N "checking for library containing getaddrinfo... $ECHO_C" >&6
+if test "${ac_cv_search_getaddrinfo+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_getaddrinfo=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getaddrinfo="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_getaddrinfo" = no; then
+ for ac_lib in nsl socket; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getaddrinfo="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_getaddrinfo" >&5
+echo "${ECHO_T}$ac_cv_search_getaddrinfo" >&6
+if test "$ac_cv_search_getaddrinfo" != no; then
+ test "$ac_cv_search_getaddrinfo" = "none required" || LIBS="$ac_cv_search_getaddrinfo $LIBS"
+
+fi
+
+
+
+for ac_func in getaddrinfo gai_strerror
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for stdbool.h that conforms to C99" >&5
+echo $ECHO_N "checking for stdbool.h that conforms to C99... $ECHO_C" >&6
+if test "${ac_cv_header_stdbool_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ #include <stdbool.h>
+ #ifndef bool
+ "error: bool is not defined"
+ #endif
+ #ifndef false
+ "error: false is not defined"
+ #endif
+ #if false
+ "error: false is not 0"
+ #endif
+ #ifndef true
+ "error: true is not defined"
+ #endif
+ #if true != 1
+ "error: true is not 1"
+ #endif
+ #ifndef __bool_true_false_are_defined
+ "error: __bool_true_false_are_defined is not defined"
+ #endif
+
+ struct s { _Bool s: 1; _Bool t; } s;
+
+ char a[true == 1 ? 1 : -1];
+ char b[false == 0 ? 1 : -1];
+ char c[__bool_true_false_are_defined == 1 ? 1 : -1];
+ char d[(bool) -0.5 == true ? 1 : -1];
+ bool e = &s;
+ char f[(_Bool) -0.0 == false ? 1 : -1];
+ char g[true];
+ char h[sizeof (_Bool)];
+ char i[sizeof s.t];
+ enum { j = false, k = true, l = false * true, m = true * 256 };
+ _Bool n[m];
+ char o[sizeof n == m * sizeof n[0] ? 1 : -1];
+
+int
+main ()
+{
+
+ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !j + !k + !l
+ + !m + !n + !o);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdbool_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdbool_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdbool_h" >&5
+echo "${ECHO_T}$ac_cv_header_stdbool_h" >&6
+ echo "$as_me:$LINENO: checking for _Bool" >&5
+echo $ECHO_N "checking for _Bool... $ECHO_C" >&6
+if test "${ac_cv_type__Bool+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((_Bool *) 0)
+ return 0;
+if (sizeof (_Bool))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type__Bool=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type__Bool=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type__Bool" >&5
+echo "${ECHO_T}$ac_cv_type__Bool" >&6
+if test $ac_cv_type__Bool = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE__BOOL 1
+_ACEOF
+
+
+fi
+
+ if test $ac_cv_header_stdbool_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STDBOOL_H 1
+_ACEOF
+
+ fi
+
+
+
+
+
+for ac_func in $gl_func_list
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in $gl_header_list
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+ case $LIBOBJS in
+ "save-cwd.$ac_objext" | \
+ *" save-cwd.$ac_objext" | \
+ "save-cwd.$ac_objext "* | \
+ *" save-cwd.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS save-cwd.$ac_objext" ;;
+esac
+
+
+ :
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether memrchr is declared" >&5
+echo $ECHO_N "checking whether memrchr is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_memrchr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef memrchr
+ char *p = (char *) memrchr;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_memrchr=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_memrchr=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_memrchr" >&5
+echo "${ECHO_T}$ac_cv_have_decl_memrchr" >&6
+if test $ac_cv_have_decl_memrchr = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_MEMRCHR 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_MEMRCHR 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether system is Windows or MSDOS" >&5
+echo $ECHO_N "checking whether system is Windows or MSDOS... $ECHO_C" >&6
+if test "${ac_cv_win_or_dos+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#if !defined _WIN32 && !defined __WIN32__ && !defined __MSDOS__ && !defined __CYGWIN__
+neither MSDOS nor Windows
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_win_or_dos=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_win_or_dos=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_win_or_dos" >&5
+echo "${ECHO_T}$ac_cv_win_or_dos" >&6
+
+ if test x"$ac_cv_win_or_dos" = xyes; then
+ ac_fs_accepts_drive_letter_prefix=1
+ ac_fs_backslash_is_file_name_separator=1
+ else
+ ac_fs_accepts_drive_letter_prefix=0
+ ac_fs_backslash_is_file_name_separator=0
+ fi
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX $ac_fs_accepts_drive_letter_prefix
+_ACEOF
+
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR $ac_fs_backslash_is_file_name_separator
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking whether strerror_r is declared" >&5
+echo $ECHO_N "checking whether strerror_r is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_strerror_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef strerror_r
+ char *p = (char *) strerror_r;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_strerror_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_strerror_r=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_strerror_r" >&5
+echo "${ECHO_T}$ac_cv_have_decl_strerror_r" >&6
+if test $ac_cv_have_decl_strerror_r = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRERROR_R 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRERROR_R 0
+_ACEOF
+
+
+fi
+
+
+
+for ac_func in strerror_r
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+echo "$as_me:$LINENO: checking whether strerror_r returns char *" >&5
+echo $ECHO_N "checking whether strerror_r returns char *... $ECHO_C" >&6
+if test "${ac_cv_func_strerror_r_char_p+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ ac_cv_func_strerror_r_char_p=no
+ if test $ac_cv_have_decl_strerror_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ char buf[100];
+ char x = *strerror_r (0, buf, sizeof buf);
+ char *p = strerror_r (0, buf, sizeof buf);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strerror_r_char_p=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ else
+ # strerror_r is not declared. Choose between
+ # systems that have relatively inaccessible declarations for the
+ # function. BeOS and DEC UNIX 4.0 fall in this category, but the
+ # former has a strerror_r that returns char*, while the latter
+ # has a strerror_r that returns `int'.
+ # This test should segfault on the DEC system.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+ extern char *strerror_r ();
+int
+main ()
+{
+char buf[100];
+ char x = *strerror_r (0, buf, sizeof buf);
+ exit (!isalpha (x));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strerror_r_char_p=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ fi
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strerror_r_char_p" >&5
+echo "${ECHO_T}$ac_cv_func_strerror_r_char_p" >&6
+if test $ac_cv_func_strerror_r_char_p = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STRERROR_R_CHAR_P 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for mbstate_t" >&5
+echo $ECHO_N "checking for mbstate_t... $ECHO_C" >&6
+if test "${ac_cv_type_mbstate_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+# include <wchar.h>
+int
+main ()
+{
+mbstate_t x; return sizeof x;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_mbstate_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_mbstate_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_mbstate_t" >&5
+echo "${ECHO_T}$ac_cv_type_mbstate_t" >&6
+ if test $ac_cv_type_mbstate_t = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MBSTATE_T 1
+_ACEOF
+
+ else
+
+cat >>confdefs.h <<\_ACEOF
+#define mbstate_t int
+_ACEOF
+
+ fi
+
+
+
+
+ :
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getcwd (NULL, 0) allocates memory for result" >&5
+echo $ECHO_N "checking whether getcwd (NULL, 0) allocates memory for result... $ECHO_C" >&6
+if test "${gl_cv_func_getcwd_null+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ gl_cv_func_getcwd_null=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# include <stdlib.h>
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+# ifndef getcwd
+ char *getcwd ();
+# endif
+ int
+ main ()
+ {
+ if (chdir ("/") != 0)
+ exit (1);
+ else
+ {
+ char *f = getcwd (NULL, 0);
+ exit (! (f && f[0] == '/' && !f[1]));
+ }
+ }
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_getcwd_null=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_func_getcwd_null=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_getcwd_null" >&5
+echo "${ECHO_T}$gl_cv_func_getcwd_null" >&6
+
+
+ echo "$as_me:$LINENO: checking whether getcwd is declared" >&5
+echo $ECHO_N "checking whether getcwd is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getcwd+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getcwd
+ char *p = (char *) getcwd;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getcwd=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getcwd=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getcwd" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getcwd" >&6
+if test $ac_cv_have_decl_getcwd = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETCWD 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETCWD 0
+_ACEOF
+
+
+fi
+
+
+
+ echo "$as_me:$LINENO: checking for d_ino member in directory struct" >&5
+echo $ECHO_N "checking for d_ino member in directory struct... $ECHO_C" >&6
+if test "${jm_cv_struct_dirent_d_ino+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#else /* not HAVE_DIRENT_H */
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+#endif /* HAVE_DIRENT_H */
+
+int
+main ()
+{
+struct dirent dp; dp.d_ino = 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ jm_cv_struct_dirent_d_ino=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+jm_cv_struct_dirent_d_ino=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+echo "$as_me:$LINENO: result: $jm_cv_struct_dirent_d_ino" >&5
+echo "${ECHO_T}$jm_cv_struct_dirent_d_ino" >&6
+ if test $jm_cv_struct_dirent_d_ino = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define D_INO_IN_DIRENT 1
+_ACEOF
+
+ fi
+
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_time=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for struct timespec" >&5
+echo $ECHO_N "checking for struct timespec... $ECHO_C" >&6
+if test "${fu_cv_sys_struct_timespec+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+int
+main ()
+{
+static struct timespec x; x.tv_sec = x.tv_nsec;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ fu_cv_sys_struct_timespec=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fu_cv_sys_struct_timespec=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $fu_cv_sys_struct_timespec" >&5
+echo "${ECHO_T}$fu_cv_sys_struct_timespec" >&6
+
+ if test $fu_cv_sys_struct_timespec = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_TIMESPEC 1
+_ACEOF
+
+ fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether nanosleep is declared" >&5
+echo $ECHO_N "checking whether nanosleep is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_nanosleep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+
+int
+main ()
+{
+#ifndef nanosleep
+ char *p = (char *) nanosleep;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_nanosleep=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_nanosleep=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_nanosleep" >&5
+echo "${ECHO_T}$ac_cv_have_decl_nanosleep" >&6
+if test $ac_cv_have_decl_nanosleep = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_NANOSLEEP 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_NANOSLEEP 0
+_ACEOF
+
+
+fi
+
+
+
+ # expand $ac_aux_dir to an absolute path
+ am_aux_dir=`cd $ac_aux_dir && pwd`
+
+ # getdate.y works with bison only.
+ : ${YACC="\${SHELL} $am_aux_dir/bison-missing --run bison -y"}
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
+echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6
+if test "${ac_cv_struct_tm+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm *tp; tp->tm_sec;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_struct_tm=time.h
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
+echo "${ECHO_T}$ac_cv_struct_tm" >&6
+if test $ac_cv_struct_tm = sys/time.h; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TM_IN_SYS_TIME 1
+_ACEOF
+
+fi
+
+
+ # dnl Persuade glibc <time.h> to declare these functions.
+
+
+ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
+ # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
+
+ # Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all*
+ # programs in the package would end up linked with that potentially-shared
+ # library, inducing unnecessary run-time overhead.
+ gl_saved_libs=$LIBS
+ echo "$as_me:$LINENO: checking for library containing clock_gettime" >&5
+echo $ECHO_N "checking for library containing clock_gettime... $ECHO_C" >&6
+if test "${ac_cv_search_clock_gettime+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_clock_gettime=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_clock_gettime="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_clock_gettime" = no; then
+ for ac_lib in rt posix4; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_clock_gettime="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_clock_gettime" >&5
+echo "${ECHO_T}$ac_cv_search_clock_gettime" >&6
+if test "$ac_cv_search_clock_gettime" != no; then
+ test "$ac_cv_search_clock_gettime" = "none required" || LIBS="$ac_cv_search_clock_gettime $LIBS"
+ test "$ac_cv_search_clock_gettime" = "none required" ||
+ LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime
+fi
+
+
+
+
+for ac_func in clock_gettime clock_settime
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ LIBS=$gl_saved_libs
+
+
+ echo "$as_me:$LINENO: checking for struct tm.tm_gmtoff" >&5
+echo $ECHO_N "checking for struct tm.tm_gmtoff... $ECHO_C" >&6
+if test "${ac_cv_member_struct_tm_tm_gmtoff+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+
+int
+main ()
+{
+static struct tm ac_aggr;
+if (ac_aggr.tm_gmtoff)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_tm_tm_gmtoff=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+
+int
+main ()
+{
+static struct tm ac_aggr;
+if (sizeof ac_aggr.tm_gmtoff)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_tm_tm_gmtoff=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_tm_tm_gmtoff=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_tm_tm_gmtoff" >&5
+echo "${ECHO_T}$ac_cv_member_struct_tm_tm_gmtoff" >&6
+if test $ac_cv_member_struct_tm_tm_gmtoff = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TM_GMTOFF 1
+_ACEOF
+
+fi
+
+
+
+ echo "$as_me:$LINENO: checking whether getdelim is declared" >&5
+echo $ECHO_N "checking whether getdelim is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getdelim+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getdelim
+ char *p = (char *) getdelim;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getdelim=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getdelim=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getdelim" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getdelim" >&6
+if test $ac_cv_have_decl_getdelim = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETDELIM 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETDELIM 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getlogin is declared" >&5
+echo $ECHO_N "checking whether getlogin is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getlogin+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getlogin
+ char *p = (char *) getlogin;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getlogin=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getlogin=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getlogin" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getlogin" >&6
+if test $ac_cv_have_decl_getlogin = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLOGIN 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLOGIN 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getlogin_r is declared" >&5
+echo $ECHO_N "checking whether getlogin_r is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getlogin_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getlogin_r
+ char *p = (char *) getlogin_r;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getlogin_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getlogin_r=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getlogin_r" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getlogin_r" >&6
+if test $ac_cv_have_decl_getlogin_r = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLOGIN_R 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLOGIN_R 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking for ssize_t" >&5
+echo $ECHO_N "checking for ssize_t... $ECHO_C" >&6
+if test "${gt_cv_ssize_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+int
+main ()
+{
+int x = sizeof (ssize_t *) + sizeof (ssize_t);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_ssize_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_ssize_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gt_cv_ssize_t" >&5
+echo "${ECHO_T}$gt_cv_ssize_t" >&6
+ if test $gt_cv_ssize_t = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ssize_t int
+_ACEOF
+
+ fi
+
+
+ if test -z "$GETOPT_H"; then
+
+for ac_header in getopt.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ GETOPT_H=getopt.h
+fi
+
+done
+
+ fi
+
+ if test -z "$GETOPT_H"; then
+
+for ac_func in getopt_long_only
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ GETOPT_H=getopt.h
+fi
+done
+
+ fi
+
+ if test -z "$GETOPT_H"; then
+ echo "$as_me:$LINENO: checking whether optreset is declared" >&5
+echo $ECHO_N "checking whether optreset is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_optreset+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <getopt.h>
+
+int
+main ()
+{
+#ifndef optreset
+ char *p = (char *) optreset;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_optreset=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_optreset=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_optreset" >&5
+echo "${ECHO_T}$ac_cv_have_decl_optreset" >&6
+if test $ac_cv_have_decl_optreset = yes; then
+ GETOPT_H=getopt.h
+fi
+
+ fi
+
+ if test -z "$GETOPT_H"; then
+ echo "$as_me:$LINENO: checking for working GNU getopt function" >&5
+echo $ECHO_N "checking for working GNU getopt function... $ECHO_C" >&6
+if test "${gl_cv_func_gnu_getopt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "$as_me:$LINENO: checking whether getopt_clip is declared" >&5
+echo $ECHO_N "checking whether getopt_clip is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getopt_clip+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <getopt.h>
+
+int
+main ()
+{
+#ifndef getopt_clip
+ char *p = (char *) getopt_clip;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getopt_clip=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getopt_clip=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getopt_clip" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getopt_clip" >&6
+if test $ac_cv_have_decl_getopt_clip = yes; then
+ gl_cv_func_gnu_getopt=no
+else
+ gl_cv_func_gnu_getopt=yes
+fi
+
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <getopt.h>
+int
+main ()
+{
+
+ char *myargv[3];
+ myargv[0] = "conftest";
+ myargv[1] = "-+";
+ myargv[2] = 0;
+ return getopt (2, myargv, "+a") != '?';
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_gnu_getopt=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_func_gnu_getopt=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_gnu_getopt" >&5
+echo "${ECHO_T}$gl_cv_func_gnu_getopt" >&6
+ if test "$gl_cv_func_gnu_getopt" = "no"; then
+ GETOPT_H=getopt.h
+ fi
+ fi
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getpass is declared" >&5
+echo $ECHO_N "checking whether getpass is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getpass+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getpass
+ char *p = (char *) getpass;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getpass=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getpass=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getpass" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getpass" >&6
+if test $ac_cv_have_decl_getpass = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETPASS 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETPASS 0
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether fflush_unlocked is declared" >&5
+echo $ECHO_N "checking whether fflush_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_fflush_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef fflush_unlocked
+ char *p = (char *) fflush_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_fflush_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_fflush_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_fflush_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_fflush_unlocked" >&6
+if test $ac_cv_have_decl_fflush_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FFLUSH_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FFLUSH_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether flockfile is declared" >&5
+echo $ECHO_N "checking whether flockfile is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_flockfile+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef flockfile
+ char *p = (char *) flockfile;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_flockfile=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_flockfile=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_flockfile" >&5
+echo "${ECHO_T}$ac_cv_have_decl_flockfile" >&6
+if test $ac_cv_have_decl_flockfile = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FLOCKFILE 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FLOCKFILE 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether fputs_unlocked is declared" >&5
+echo $ECHO_N "checking whether fputs_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_fputs_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef fputs_unlocked
+ char *p = (char *) fputs_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_fputs_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_fputs_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_fputs_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_fputs_unlocked" >&6
+if test $ac_cv_have_decl_fputs_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FPUTS_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FPUTS_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether funlockfile is declared" >&5
+echo $ECHO_N "checking whether funlockfile is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_funlockfile+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef funlockfile
+ char *p = (char *) funlockfile;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_funlockfile=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_funlockfile=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_funlockfile" >&5
+echo "${ECHO_T}$ac_cv_have_decl_funlockfile" >&6
+if test $ac_cv_have_decl_funlockfile = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FUNLOCKFILE 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FUNLOCKFILE 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether putc_unlocked is declared" >&5
+echo $ECHO_N "checking whether putc_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_putc_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef putc_unlocked
+ char *p = (char *) putc_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_putc_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_putc_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_putc_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_putc_unlocked" >&6
+if test $ac_cv_have_decl_putc_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PUTC_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PUTC_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for d_type member in directory struct" >&5
+echo $ECHO_N "checking for d_type member in directory struct... $ECHO_C" >&6
+if test "${jm_cv_struct_dirent_d_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#else /* not HAVE_DIRENT_H */
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+#endif /* HAVE_DIRENT_H */
+
+int
+main ()
+{
+struct dirent dp; dp.d_type = 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ jm_cv_struct_dirent_d_type=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+jm_cv_struct_dirent_d_type=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+echo "$as_me:$LINENO: result: $jm_cv_struct_dirent_d_type" >&5
+echo "${ECHO_T}$jm_cv_struct_dirent_d_type" >&6
+ if test $jm_cv_struct_dirent_d_type = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_DIRENT_D_TYPE 1
+_ACEOF
+
+ fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking whether lstat dereferences a symlink specified with a trailing slash" >&5
+echo $ECHO_N "checking whether lstat dereferences a symlink specified with a trailing slash... $ECHO_C" >&6
+if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ rm -f conftest.sym conftest.file
+echo >conftest.file
+if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_lstat_dereferences_slashed_symlink=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+struct stat sbuf;
+ /* Linux will dereference the symlink and fail.
+ That is better in the sense that it means we will not
+ have to compile and use the lstat wrapper. */
+ exit (lstat ("conftest.sym/", &sbuf) ? 0 : 1);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_lstat_dereferences_slashed_symlink=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_lstat_dereferences_slashed_symlink=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+else
+ # If the `ln -s' command failed, then we probably don't even
+ # have an lstat function.
+ ac_cv_func_lstat_dereferences_slashed_symlink=no
+fi
+rm -f conftest.sym conftest.file
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5
+echo "${ECHO_T}$ac_cv_func_lstat_dereferences_slashed_symlink" >&6
+
+test $ac_cv_func_lstat_dereferences_slashed_symlink = yes &&
+
+cat >>confdefs.h <<_ACEOF
+#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
+_ACEOF
+
+
+if test $ac_cv_func_lstat_dereferences_slashed_symlink = no; then
+ case $LIBOBJS in
+ "lstat.$ac_objext" | \
+ *" lstat.$ac_objext" | \
+ "lstat.$ac_objext "* | \
+ *" lstat.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;;
+esac
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6
+if test "${gl_cv_c_uint32_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gl_cv_c_uint32_t=no
+ for ac_type in "uint32_t" "unsigned int" \
+ "unsigned long int" "unsigned short int"; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(($ac_type) -1 == 4294967295U)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_c_uint32_t=$ac_type
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$gl_cv_c_uint32_t" != no && break
+ done
+fi
+echo "$as_me:$LINENO: result: $gl_cv_c_uint32_t" >&5
+echo "${ECHO_T}$gl_cv_c_uint32_t" >&6
+ case "$gl_cv_c_uint32_t" in
+ no|uint32_t) ;;
+ *)
+
+cat >>confdefs.h <<\_ACEOF
+#define _UINT32_T 1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t $gl_cv_c_uint32_t
+_ACEOF
+
+ ;;
+ esac
+
+ echo "$as_me:$LINENO: checking for UINT32_MAX" >&5
+echo $ECHO_N "checking for UINT32_MAX... $ECHO_C" >&6
+if test "${gl_cv_c_uint32_max+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(UINT32_MAX == 4294967295U)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_c_uint32_max=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_c_uint32_max=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_c_uint32_max" >&5
+echo "${ECHO_T}$gl_cv_c_uint32_max" >&6
+ case $gl_cv_c_uint32_max,$gl_cv_c_uint32_t in
+ yes,*) ;;
+ *,no) ;;
+ *)
+
+cat >>confdefs.h <<\_ACEOF
+#define UINT32_MAX 4294967295U
+_ACEOF
+
+ ;;
+ esac
+
+echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+ # try to guess the endianness by grepping values into an object file
+ ac_cv_c_bigendian=unknown
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+ ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+main ()
+{
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+ yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+ no)
+ ;;
+ *)
+ { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether <limits.h> defines MIN and MAX" >&5
+echo $ECHO_N "checking whether <limits.h> defines MIN and MAX... $ECHO_C" >&6
+if test "${gl_cv_minmax_in_limits_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <limits.h>
+int x = MIN (42, 17);
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_minmax_in_limits_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_minmax_in_limits_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_minmax_in_limits_h" >&5
+echo "${ECHO_T}$gl_cv_minmax_in_limits_h" >&6
+ if test $gl_cv_minmax_in_limits_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MINMAX_IN_LIMITS_H 1
+_ACEOF
+
+ fi
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether <sys/param.h> defines MIN and MAX" >&5
+echo $ECHO_N "checking whether <sys/param.h> defines MIN and MAX... $ECHO_C" >&6
+if test "${gl_cv_minmax_in_sys_param_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/param.h>
+int x = MIN (42, 17);
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_minmax_in_sys_param_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_minmax_in_sys_param_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_minmax_in_sys_param_h" >&5
+echo "${ECHO_T}$gl_cv_minmax_in_sys_param_h" >&6
+ if test $gl_cv_minmax_in_sys_param_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MINMAX_IN_SYS_PARAM_H 1
+_ACEOF
+
+ fi
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getenv is declared" >&5
+echo $ECHO_N "checking whether getenv is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getenv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getenv
+ char *p = (char *) getenv;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getenv=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getenv=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getenv" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getenv" >&6
+if test $ac_cv_have_decl_getenv = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETENV 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETENV 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking for inttypes.h" >&5
+echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6
+if test "${gl_cv_header_inttypes_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <inttypes.h>
+int
+main ()
+{
+uintmax_t i = (uintmax_t) -1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_header_inttypes_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_header_inttypes_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_header_inttypes_h" >&5
+echo "${ECHO_T}$gl_cv_header_inttypes_h" >&6
+ if test $gl_cv_header_inttypes_h = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INTTYPES_H_WITH_UINTMAX 1
+_ACEOF
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for stdint.h" >&5
+echo $ECHO_N "checking for stdint.h... $ECHO_C" >&6
+if test "${gl_cv_header_stdint_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <stdint.h>
+int
+main ()
+{
+uintmax_t i = (uintmax_t) -1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_header_stdint_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_header_stdint_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_header_stdint_h" >&5
+echo "${ECHO_T}$gl_cv_header_stdint_h" >&6
+ if test $gl_cv_header_stdint_h = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STDINT_H_WITH_UINTMAX 1
+_ACEOF
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for unsigned long long" >&5
+echo $ECHO_N "checking for unsigned long long... $ECHO_C" >&6
+if test "${ac_cv_type_unsigned_long_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+unsigned long long ull = 1ULL; int i = 63;
+int
+main ()
+{
+unsigned long long ullmax = (unsigned long long) -1;
+ return ull << i | ull >> i | ullmax / ull | ullmax % ull;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_unsigned_long_long=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_unsigned_long_long=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_unsigned_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_unsigned_long_long" >&6
+ if test $ac_cv_type_unsigned_long_long = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_UNSIGNED_LONG_LONG 1
+_ACEOF
+
+ fi
+
+
+
+
+ if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+
+ test $ac_cv_type_unsigned_long_long = yes \
+ && ac_type='unsigned long long' \
+ || ac_type='unsigned long'
+
+cat >>confdefs.h <<_ACEOF
+#define uintmax_t $ac_type
+_ACEOF
+
+ else
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_UINTMAX_T 1
+_ACEOF
+
+ fi
+
+
+
+
+for ac_header in stdlib.h sys/time.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in alarm
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+echo "$as_me:$LINENO: checking for working mktime" >&5
+echo $ECHO_N "checking for working mktime... $ECHO_C" >&6
+if test "${ac_cv_func_working_mktime+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_working_mktime=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Test program from Paul Eggert and Tony Leneis. */
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !HAVE_ALARM
+# define alarm(X) /* empty */
+#endif
+
+/* Work around redefinition to rpl_putenv by other config tests. */
+#undef putenv
+
+static time_t time_t_max;
+static time_t time_t_min;
+
+/* Values we'll use to set the TZ environment variable. */
+static char *tz_strings[] = {
+ (char *) 0, "TZ=GMT0", "TZ=JST-9",
+ "TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00"
+};
+#define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0]))
+
+/* Fail if mktime fails to convert a date in the spring-forward gap.
+ Based on a problem report from Andreas Jaeger. */
+static void
+spring_forward_gap ()
+{
+ /* glibc (up to about 1998-10-07) failed this test. */
+ struct tm tm;
+
+ /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0"
+ instead of "TZ=America/Vancouver" in order to detect the bug even
+ on systems that don't support the Olson extension, or don't have the
+ full zoneinfo tables installed. */
+ putenv ("TZ=PST8PDT,M4.1.0,M10.5.0");
+
+ tm.tm_year = 98;
+ tm.tm_mon = 3;
+ tm.tm_mday = 5;
+ tm.tm_hour = 2;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ tm.tm_isdst = -1;
+ if (mktime (&tm) == (time_t)-1)
+ exit (1);
+}
+
+static void
+mktime_test1 (now)
+ time_t now;
+{
+ struct tm *lt;
+ if ((lt = localtime (&now)) && mktime (lt) != now)
+ exit (1);
+}
+
+static void
+mktime_test (now)
+ time_t now;
+{
+ mktime_test1 (now);
+ mktime_test1 ((time_t) (time_t_max - now));
+ mktime_test1 ((time_t) (time_t_min + now));
+}
+
+static void
+irix_6_4_bug ()
+{
+ /* Based on code from Ariel Faigon. */
+ struct tm tm;
+ tm.tm_year = 96;
+ tm.tm_mon = 3;
+ tm.tm_mday = 0;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ tm.tm_isdst = -1;
+ mktime (&tm);
+ if (tm.tm_mon != 2 || tm.tm_mday != 31)
+ exit (1);
+}
+
+static void
+bigtime_test (j)
+ int j;
+{
+ struct tm tm;
+ time_t now;
+ tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j;
+ now = mktime (&tm);
+ if (now != (time_t) -1)
+ {
+ struct tm *lt = localtime (&now);
+ if (! (lt
+ && lt->tm_year == tm.tm_year
+ && lt->tm_mon == tm.tm_mon
+ && lt->tm_mday == tm.tm_mday
+ && lt->tm_hour == tm.tm_hour
+ && lt->tm_min == tm.tm_min
+ && lt->tm_sec == tm.tm_sec
+ && lt->tm_yday == tm.tm_yday
+ && lt->tm_wday == tm.tm_wday
+ && ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst)
+ == (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst))))
+ exit (1);
+ }
+}
+
+int
+main ()
+{
+ time_t t, delta;
+ int i, j;
+
+ /* This test makes some buggy mktime implementations loop.
+ Give up after 60 seconds; a mktime slower than that
+ isn't worth using anyway. */
+ alarm (60);
+
+ for (time_t_max = 1; 0 < time_t_max; time_t_max *= 2)
+ continue;
+ time_t_max--;
+ if ((time_t) -1 < 0)
+ for (time_t_min = -1; (time_t) (time_t_min * 2) < 0; time_t_min *= 2)
+ continue;
+ delta = time_t_max / 997; /* a suitable prime number */
+ for (i = 0; i < N_STRINGS; i++)
+ {
+ if (tz_strings[i])
+ putenv (tz_strings[i]);
+
+ for (t = 0; t <= time_t_max - delta; t += delta)
+ mktime_test (t);
+ mktime_test ((time_t) 1);
+ mktime_test ((time_t) (60 * 60));
+ mktime_test ((time_t) (60 * 60 * 24));
+
+ for (j = 1; 0 < j; j *= 2)
+ bigtime_test (j);
+ bigtime_test (j - 1);
+ }
+ irix_6_4_bug ();
+ spring_forward_gap ();
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_working_mktime=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_working_mktime=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_working_mktime" >&5
+echo "${ECHO_T}$ac_cv_func_working_mktime" >&6
+if test $ac_cv_func_working_mktime = no; then
+ case $LIBOBJS in
+ "mktime.$ac_objext" | \
+ *" mktime.$ac_objext" | \
+ "mktime.$ac_objext "* | \
+ *" mktime.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS mktime.$ac_objext" ;;
+esac
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+ # Check for mmap()
+
+
+for ac_header in stdlib.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in getpagesize
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+echo "$as_me:$LINENO: checking for working mmap" >&5
+echo $ECHO_N "checking for working mmap... $ECHO_C" >&6
+if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_mmap_fixed_mapped=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+/* malloc might have been renamed as rpl_malloc. */
+#undef malloc
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+ Here is a matrix of mmap possibilities:
+ mmap private not fixed
+ mmap private fixed at somewhere currently unmapped
+ mmap private fixed at somewhere already mapped
+ mmap shared not fixed
+ mmap shared fixed at somewhere currently unmapped
+ mmap shared fixed at somewhere already mapped
+ For private mappings, we should verify that changes cannot be read()
+ back from the file, nor mmap's back from the file at a different
+ address. (There have been systems where private was not correctly
+ implemented like the infamous i386 svr4.0, and systems where the
+ VM page cache was not coherent with the file system buffer cache
+ like early versions of FreeBSD and possibly contemporary NetBSD.)
+ For shared mappings, we should conversely verify that changes get
+ propagated back to all the places they're supposed to be.
+
+ Grep wants private fixed already mapped.
+ The main things grep needs to know about mmap are:
+ * does it exist and is it safe to write into the mmap'd area
+ * how to use it (BSD variants) */
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !STDC_HEADERS && !HAVE_STDLIB_H
+char *malloc ();
+#endif
+
+/* This mess was copied from the GNU getpagesize.h. */
+#if !HAVE_GETPAGESIZE
+/* Assume that all systems that can run configure have sys/param.h. */
+# if !HAVE_SYS_PARAM_H
+# define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+# define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+# if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define getpagesize() EXEC_PAGESIZE
+# else /* no EXEC_PAGESIZE */
+# ifdef NBPG
+# define getpagesize() NBPG * CLSIZE
+# ifndef CLSIZE
+# define CLSIZE 1
+# endif /* no CLSIZE */
+# else /* no NBPG */
+# ifdef NBPC
+# define getpagesize() NBPC
+# else /* no NBPC */
+# ifdef PAGESIZE
+# define getpagesize() PAGESIZE
+# endif /* PAGESIZE */
+# endif /* no NBPC */
+# endif /* no NBPG */
+# endif /* no EXEC_PAGESIZE */
+# else /* no HAVE_SYS_PARAM_H */
+# define getpagesize() 8192 /* punt totally */
+# endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+int
+main ()
+{
+ char *data, *data2, *data3;
+ int i, pagesize;
+ int fd;
+
+ pagesize = getpagesize ();
+
+ /* First, make a file with some known garbage in it. */
+ data = (char *) malloc (pagesize);
+ if (!data)
+ exit (1);
+ for (i = 0; i < pagesize; ++i)
+ *(data + i) = rand ();
+ umask (0);
+ fd = creat ("conftest.mmap", 0600);
+ if (fd < 0)
+ exit (1);
+ if (write (fd, data, pagesize) != pagesize)
+ exit (1);
+ close (fd);
+
+ /* Next, try to mmap the file at a fixed address which already has
+ something else allocated at it. If we can, also make sure that
+ we see the same garbage. */
+ fd = open ("conftest.mmap", O_RDWR);
+ if (fd < 0)
+ exit (1);
+ data2 = (char *) malloc (2 * pagesize);
+ if (!data2)
+ exit (1);
+ data2 += (pagesize - ((long) data2 & (pagesize - 1))) & (pagesize - 1);
+ if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED, fd, 0L))
+ exit (1);
+ for (i = 0; i < pagesize; ++i)
+ if (*(data + i) != *(data2 + i))
+ exit (1);
+
+ /* Finally, make sure that changes to the mapped area do not
+ percolate back to the file as seen by read(). (This is a bug on
+ some variants of i386 svr4.0.) */
+ for (i = 0; i < pagesize; ++i)
+ *(data2 + i) = *(data2 + i) + 1;
+ data3 = (char *) malloc (pagesize);
+ if (!data3)
+ exit (1);
+ if (read (fd, data3, pagesize) != pagesize)
+ exit (1);
+ for (i = 0; i < pagesize; ++i)
+ if (*(data + i) != *(data3 + i))
+ exit (1);
+ close (fd);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_mmap_fixed_mapped=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_mmap_fixed_mapped" >&5
+echo "${ECHO_T}$ac_cv_func_mmap_fixed_mapped" >&6
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MMAP 1
+_ACEOF
+
+fi
+rm -f conftest.mmap
+
+
+ # Try to allow MAP_ANONYMOUS.
+ gl_have_mmap_anonymous=no
+ if test $ac_cv_func_mmap_fixed_mapped = yes; then
+ echo "$as_me:$LINENO: checking for MAP_ANONYMOUS" >&5
+echo $ECHO_N "checking for MAP_ANONYMOUS... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/mman.h>
+#ifdef MAP_ANONYMOUS
+ I cant identify this map.
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "I cant identify this map." >/dev/null 2>&1; then
+ gl_have_mmap_anonymous=yes
+fi
+rm -f conftest*
+
+ if test $gl_have_mmap_anonymous != yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/mman.h>
+#ifdef MAP_ANON
+ I cant identify this map.
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "I cant identify this map." >/dev/null 2>&1; then
+
+cat >>confdefs.h <<\_ACEOF
+#define MAP_ANONYMOUS MAP_ANON
+_ACEOF
+
+ gl_have_mmap_anonymous=yes
+fi
+rm -f conftest*
+
+ fi
+ echo "$as_me:$LINENO: result: $gl_have_mmap_anonymous" >&5
+echo "${ECHO_T}$gl_have_mmap_anonymous" >&6
+ if test $gl_have_mmap_anonymous = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MAP_ANONYMOUS 1
+_ACEOF
+
+ fi
+ fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for nl_langinfo and CODESET" >&5
+echo $ECHO_N "checking for nl_langinfo and CODESET... $ECHO_C" >&6
+if test "${am_cv_langinfo_codeset+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <langinfo.h>
+int
+main ()
+{
+char* cs = nl_langinfo(CODESET);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ am_cv_langinfo_codeset=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+am_cv_langinfo_codeset=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_langinfo_codeset" >&5
+echo "${ECHO_T}$am_cv_langinfo_codeset" >&6
+ if test $am_cv_langinfo_codeset = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LANGINFO_CODESET 1
+_ACEOF
+
+ fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for inttypes.h" >&5
+echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6
+if test "${gt_cv_header_inttypes_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <inttypes.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_header_inttypes_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_header_inttypes_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $gt_cv_header_inttypes_h" >&5
+echo "${ECHO_T}$gt_cv_header_inttypes_h" >&6
+ if test $gt_cv_header_inttypes_h = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INTTYPES_H 1
+_ACEOF
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking whether strdup is declared" >&5
+echo $ECHO_N "checking whether strdup is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_strdup+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef strdup
+ char *p = (char *) strdup;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_strdup=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_strdup=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_strdup" >&5
+echo "${ECHO_T}$ac_cv_have_decl_strdup" >&6
+if test $ac_cv_have_decl_strdup = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRDUP 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRDUP 0
+_ACEOF
+
+
+fi
+
+
+
+
+for ac_func in strftime
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ # strftime is in -lintl on SCO UNIX.
+echo "$as_me:$LINENO: checking for strftime in -lintl" >&5
+echo $ECHO_N "checking for strftime in -lintl... $ECHO_C" >&6
+if test "${ac_cv_lib_intl_strftime+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lintl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strftime ();
+int
+main ()
+{
+strftime ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_intl_strftime=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_intl_strftime=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_intl_strftime" >&5
+echo "${ECHO_T}$ac_cv_lib_intl_strftime" >&6
+if test $ac_cv_lib_intl_strftime = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRFTIME 1
+_ACEOF
+
+LIBS="-lintl $LIBS"
+fi
+
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ case $LIBOBJS in
+ "strftime.$ac_objext" | \
+ *" strftime.$ac_objext" | \
+ "strftime.$ac_objext "* | \
+ *" strftime.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS strftime.$ac_objext" ;;
+esac
+
+
+ # strftime.c uses the underyling system strftime if it exists.
+
+
+ # This defines (or not) HAVE_TZNAME and HAVE_TM_ZONE.
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define my_strftime nstrftime
+_ACEOF
+
+
+
+ echo "$as_me:$LINENO: checking whether clearerr_unlocked is declared" >&5
+echo $ECHO_N "checking whether clearerr_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_clearerr_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef clearerr_unlocked
+ char *p = (char *) clearerr_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_clearerr_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_clearerr_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_clearerr_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_clearerr_unlocked" >&6
+if test $ac_cv_have_decl_clearerr_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_CLEARERR_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_CLEARERR_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether feof_unlocked is declared" >&5
+echo $ECHO_N "checking whether feof_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_feof_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef feof_unlocked
+ char *p = (char *) feof_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_feof_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_feof_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_feof_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_feof_unlocked" >&6
+if test $ac_cv_have_decl_feof_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FEOF_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FEOF_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether ferror_unlocked is declared" >&5
+echo $ECHO_N "checking whether ferror_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_ferror_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef ferror_unlocked
+ char *p = (char *) ferror_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_ferror_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_ferror_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_ferror_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_ferror_unlocked" >&6
+if test $ac_cv_have_decl_ferror_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FERROR_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FERROR_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether fgets_unlocked is declared" >&5
+echo $ECHO_N "checking whether fgets_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_fgets_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef fgets_unlocked
+ char *p = (char *) fgets_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_fgets_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_fgets_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_fgets_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_fgets_unlocked" >&6
+if test $ac_cv_have_decl_fgets_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FGETS_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FGETS_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether fputc_unlocked is declared" >&5
+echo $ECHO_N "checking whether fputc_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_fputc_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef fputc_unlocked
+ char *p = (char *) fputc_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_fputc_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_fputc_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_fputc_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_fputc_unlocked" >&6
+if test $ac_cv_have_decl_fputc_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FPUTC_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FPUTC_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether fread_unlocked is declared" >&5
+echo $ECHO_N "checking whether fread_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_fread_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef fread_unlocked
+ char *p = (char *) fread_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_fread_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_fread_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_fread_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_fread_unlocked" >&6
+if test $ac_cv_have_decl_fread_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FREAD_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FREAD_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether fwrite_unlocked is declared" >&5
+echo $ECHO_N "checking whether fwrite_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_fwrite_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef fwrite_unlocked
+ char *p = (char *) fwrite_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_fwrite_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_fwrite_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_fwrite_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_fwrite_unlocked" >&6
+if test $ac_cv_have_decl_fwrite_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FWRITE_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FWRITE_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getc_unlocked is declared" >&5
+echo $ECHO_N "checking whether getc_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getc_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getc_unlocked
+ char *p = (char *) getc_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getc_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getc_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getc_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getc_unlocked" >&6
+if test $ac_cv_have_decl_getc_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETC_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETC_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getchar_unlocked is declared" >&5
+echo $ECHO_N "checking whether getchar_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getchar_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getchar_unlocked
+ char *p = (char *) getchar_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getchar_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getchar_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getchar_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getchar_unlocked" >&6
+if test $ac_cv_have_decl_getchar_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETCHAR_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETCHAR_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether putchar_unlocked is declared" >&5
+echo $ECHO_N "checking whether putchar_unlocked is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_putchar_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef putchar_unlocked
+ char *p = (char *) putchar_unlocked;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_putchar_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_putchar_unlocked=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_putchar_unlocked" >&5
+echo "${ECHO_T}$ac_cv_have_decl_putchar_unlocked" >&6
+if test $ac_cv_have_decl_putchar_unlocked = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PUTCHAR_UNLOCKED 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PUTCHAR_UNLOCKED 0
+_ACEOF
+
+
+fi
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for EOVERFLOW" >&5
+echo $ECHO_N "checking for EOVERFLOW... $ECHO_C" >&6
+if test "${ac_cv_decl_EOVERFLOW+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <errno.h>
+#ifdef EOVERFLOW
+yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ have_eoverflow=1
+fi
+rm -f conftest*
+
+ if test -n "$have_eoverflow"; then
+ ac_cv_decl_EOVERFLOW=yes
+ else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+#ifdef EOVERFLOW
+yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ have_eoverflow=1
+fi
+rm -f conftest*
+
+ if test -n "$have_eoverflow"; then
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((EOVERFLOW) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((EOVERFLOW) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((EOVERFLOW) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((EOVERFLOW) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((EOVERFLOW) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_decl_EOVERFLOW=$ac_lo;;
+'') ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+
+long longval () { return EOVERFLOW; }
+unsigned long ulongval () { return EOVERFLOW; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if ((EOVERFLOW) < 0)
+ {
+ long i = longval ();
+ if (i != (EOVERFLOW))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != (EOVERFLOW))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_decl_EOVERFLOW=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+ else
+ ac_cv_decl_EOVERFLOW=E2BIG
+ fi
+ fi
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_decl_EOVERFLOW" >&5
+echo "${ECHO_T}$ac_cv_decl_EOVERFLOW" >&6
+ if test "$ac_cv_decl_EOVERFLOW" != yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define EOVERFLOW $ac_cv_decl_EOVERFLOW
+_ACEOF
+
+ EOVERFLOW="$ac_cv_decl_EOVERFLOW"
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for signed" >&5
+echo $ECHO_N "checking for signed... $ECHO_C" >&6
+if test "${bh_cv_c_signed+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+signed char x;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ bh_cv_c_signed=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+bh_cv_c_signed=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $bh_cv_c_signed" >&5
+echo "${ECHO_T}$bh_cv_c_signed" >&6
+ if test $bh_cv_c_signed = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define signed
+_ACEOF
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for wchar_t" >&5
+echo $ECHO_N "checking for wchar_t... $ECHO_C" >&6
+if test "${gt_cv_c_wchar_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+ wchar_t foo = (wchar_t)'\0';
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_c_wchar_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_c_wchar_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gt_cv_c_wchar_t" >&5
+echo "${ECHO_T}$gt_cv_c_wchar_t" >&6
+ if test $gt_cv_c_wchar_t = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WCHAR_T 1
+_ACEOF
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for wint_t" >&5
+echo $ECHO_N "checking for wint_t... $ECHO_C" >&6
+if test "${gt_cv_c_wint_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <wchar.h>
+ wint_t foo = (wchar_t)'\0';
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_c_wint_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_c_wint_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gt_cv_c_wint_t" >&5
+echo "${ECHO_T}$gt_cv_c_wint_t" >&6
+ if test $gt_cv_c_wint_t = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WINT_T 1
+_ACEOF
+
+ fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_size_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking for intmax_t" >&5
+echo $ECHO_N "checking for intmax_t... $ECHO_C" >&6
+if test "${gt_cv_c_intmax_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <stddef.h>
+#include <stdlib.h>
+#if HAVE_STDINT_H_WITH_UINTMAX
+#include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+#include <inttypes.h>
+#endif
+
+int
+main ()
+{
+intmax_t x = -1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_c_intmax_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_c_intmax_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gt_cv_c_intmax_t" >&5
+echo "${ECHO_T}$gt_cv_c_intmax_t" >&6
+ if test $gt_cv_c_intmax_t = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTMAX_T 1
+_ACEOF
+
+ else
+
+ test $ac_cv_type_long_long = yes \
+ && ac_type='long long' \
+ || ac_type='long'
+
+cat >>confdefs.h <<_ACEOF
+#define intmax_t $ac_type
+_ACEOF
+
+ fi
+
+
+
+
+
+
+
+ if test $ac_cv_func_alloca_works = no; then
+ :
+ fi
+
+ # Define an additional variable used in the Makefile substitution.
+ if test $ac_cv_working_alloca_h = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#if defined __GNUC__ || defined _AIX || defined _MSC_VER
+ Need own alloca
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "Need own alloca" >/dev/null 2>&1; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA 1
+_ACEOF
+
+ ALLOCA_H=alloca.h
+else
+ ALLOCA_H=
+fi
+rm -f conftest*
+
+ else
+ ALLOCA_H=alloca.h
+ fi
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA_H 1
+_ACEOF
+
+
+
+
+
+
+
+
+
+
+for ac_func in atexit
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_atexit = no; then
+
+ :
+
+ fi
+
+
+
+ case $LIBOBJS in
+ "canon-host.$ac_objext" | \
+ *" canon-host.$ac_objext" | \
+ "canon-host.$ac_objext "* | \
+ *" canon-host.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS canon-host.$ac_objext" ;;
+esac
+
+
+
+
+
+
+
+ case $LIBOBJS in
+ "canonicalize.$ac_objext" | \
+ *" canonicalize.$ac_objext" | \
+ "canonicalize.$ac_objext "* | \
+ *" canonicalize.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS canonicalize.$ac_objext" ;;
+esac
+
+
+
+
+
+for ac_header in string.h sys/param.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_func in resolvepath canonicalize_file_name
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+ echo "$as_me:$LINENO: checking whether this system has a definition of PATH_MAX" >&5
+echo $ECHO_N "checking whether this system has a definition of PATH_MAX... $ECHO_C" >&6
+if test "${gl_have_path_max_definition+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <unistd.h>
+#include <limits.h>
+#ifdef PATH_MAX
+have_path_max_definition
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "have_path_max_definition" >/dev/null 2>&1; then
+ gl_have_path_max_definition=yes
+else
+ gl_have_path_max_definition=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $gl_have_path_max_definition" >&5
+echo "${ECHO_T}$gl_have_path_max_definition" >&6
+
+ if test $gl_have_path_max_definition; then
+ case $LIBOBJS in
+ "chdir-long.$ac_objext" | \
+ *" chdir-long.$ac_objext" | \
+ "chdir-long.$ac_objext "* | \
+ *" chdir-long.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS chdir-long.$ac_objext" ;;
+esac
+
+
+
+
+
+ # Define two additional variables used in the Makefile substitution.
+
+ if test "$ac_cv_header_stdbool_h" = yes; then
+ STDBOOL_H=''
+ else
+ STDBOOL_H='stdbool.h'
+ fi
+
+
+ if test "$ac_cv_type__Bool" = yes; then
+ HAVE__BOOL=1
+ else
+ HAVE__BOOL=0
+ fi
+
+
+
+
+
+
+
+
+for ac_func in mempcpy
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_mempcpy = no; then
+
+ :
+
+ fi
+
+
+
+
+
+for ac_func in openat
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ case $ac_cv_func_openat in
+ yes) ;;
+ *)
+
+cat >>confdefs.h <<\_ACEOF
+#define __OPENAT_PREFIX rpl_
+_ACEOF
+
+
+
+;;
+ esac
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+for ac_func in memrchr
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_memrchr = no; then
+ :
+ fi
+
+
+ fi
+
+
+
+ case $LIBOBJS in
+ "closeout.$ac_objext" | \
+ *" closeout.$ac_objext" | \
+ "closeout.$ac_objext "* | \
+ *" closeout.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS closeout.$ac_objext" ;;
+esac
+
+
+ :
+
+
+
+ case $LIBOBJS in
+ "dirname.$ac_objext" | \
+ *" dirname.$ac_objext" | \
+ "dirname.$ac_objext "* | \
+ *" dirname.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS dirname.$ac_objext" ;;
+esac
+
+
+
+
+
+
+
+for ac_func in dup2
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_dup2 = no; then
+
+
+ :
+
+
+
+
+
+
+ fi
+
+
+
+
+ :
+
+
+
+
+ case $LIBOBJS in
+ "exitfail.$ac_objext" | \
+ *" exitfail.$ac_objext" | \
+ "exitfail.$ac_objext "* | \
+ *" exitfail.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS exitfail.$ac_objext" ;;
+esac
+
+
+ :
+
+
+
+ case $LIBOBJS in
+ "filenamecat.$ac_objext" | \
+ *" filenamecat.$ac_objext" | \
+ "filenamecat.$ac_objext "* | \
+ *" filenamecat.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS filenamecat.$ac_objext" ;;
+esac
+
+
+
+ :
+
+
+
+
+
+
+ # No macro. You should also use one of fnmatch-posix or fnmatch-gnu.
+
+ FNMATCH_H=
+ echo "$as_me:$LINENO: checking for working POSIX fnmatch" >&5
+echo $ECHO_N "checking for working POSIX fnmatch... $ECHO_C" >&6
+if test "${ac_cv_func_fnmatch_posix+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_fnmatch_posix=cross
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# include <stdlib.h>
+# include <fnmatch.h>
+# define y(a, b, c) (fnmatch (a, b, c) == 0)
+# define n(a, b, c) (fnmatch (a, b, c) == FNM_NOMATCH)
+
+int
+main ()
+{
+exit
+ (!(y ("a*", "abc", 0)
+ && n ("d*/*1", "d/s/1", FNM_PATHNAME)
+ && y ("a\\\\bc", "abc", 0)
+ && n ("a\\\\bc", "abc", FNM_NOESCAPE)
+ && y ("*x", ".x", 0)
+ && n ("*x", ".x", FNM_PERIOD)
+ && 1));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_fnmatch_posix=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_fnmatch_posix=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_fnmatch_posix" >&5
+echo "${ECHO_T}$ac_cv_func_fnmatch_posix" >&6
+if test $ac_cv_func_fnmatch_posix = yes; then
+ rm -f lib/fnmatch.h
+else
+ echo "$as_me:$LINENO: checking whether getenv is declared" >&5
+echo $ECHO_N "checking whether getenv is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getenv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getenv
+ char *p = (char *) getenv;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getenv=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getenv=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getenv" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getenv" >&6
+if test $ac_cv_have_decl_getenv = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETENV 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETENV 0
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+
+
+for ac_func in btowc mbsrtowcs mempcpy wmemchr wmemcpy wmempcpy
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+for ac_header in wchar.h wctype.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+case $LIBOBJS in
+ "fnmatch.$ac_objext" | \
+ *" fnmatch.$ac_objext" | \
+ "fnmatch.$ac_objext "* | \
+ *" fnmatch.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS fnmatch.$ac_objext" ;;
+esac
+
+FNMATCH_H=fnmatch.h
+
+fi
+
+
+ if test $ac_cv_func_fnmatch_posix != yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define fnmatch posix_fnmatch
+_ACEOF
+
+ fi
+
+
+
+
+
+
+for ac_header in stdio_ext.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in __fpending
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ fp_headers='
+# if HAVE_STDIO_EXT_H
+# include <stdio_ext.h>
+# endif
+'
+ echo "$as_me:$LINENO: checking whether __fpending is declared" >&5
+echo $ECHO_N "checking whether __fpending is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl___fpending+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$fp_headers
+
+int
+main ()
+{
+#ifndef __fpending
+ char *p = (char *) __fpending;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl___fpending=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl___fpending=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl___fpending" >&5
+echo "${ECHO_T}$ac_cv_have_decl___fpending" >&6
+if test $ac_cv_have_decl___fpending = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL___FPENDING 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL___FPENDING 0
+_ACEOF
+
+
+fi
+
+
+ if test $ac_cv_func___fpending = no; then
+ echo "$as_me:$LINENO: checking how to determine the number of pending output bytes on a stream" >&5
+echo $ECHO_N "checking how to determine the number of pending output bytes on a stream... $ECHO_C" >&6
+if test "${ac_cv_sys_pending_output_n_bytes+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ for ac_expr in \
+ \
+ '# glibc2' \
+ 'fp->_IO_write_ptr - fp->_IO_write_base' \
+ \
+ '# traditional Unix' \
+ 'fp->_ptr - fp->_base' \
+ \
+ '# BSD' \
+ 'fp->_p - fp->_bf._base' \
+ \
+ '# SCO, Unixware' \
+ 'fp->__ptr - fp->__base' \
+ \
+ '# old glibc?' \
+ 'fp->__bufp - fp->__buffer' \
+ \
+ '# old glibc iostream?' \
+ 'fp->_pptr - fp->_pbase' \
+ \
+ '# VMS' \
+ '(*fp)->_ptr - (*fp)->_base' \
+ \
+ '# e.g., DGUX R4.11; the info is not available' \
+ 1 \
+ ; do
+
+ # Skip each embedded comment.
+ case "$ac_expr" in '#'*) continue;; esac
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+
+int
+main ()
+{
+FILE *fp = stdin; (void) ($ac_expr);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ fp_done=yes
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$fp_done" = yes && break
+ done
+
+ ac_cv_sys_pending_output_n_bytes=$ac_expr
+
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_pending_output_n_bytes" >&5
+echo "${ECHO_T}$ac_cv_sys_pending_output_n_bytes" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define PENDING_OUTPUT_N_BYTES $ac_cv_sys_pending_output_n_bytes
+_ACEOF
+
+ fi
+
+
+
+for ac_func in ftruncate
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_ftruncate = no; then
+
+
+ :
+
+
+
+
+
+
+for ac_func in chsize
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for library containing getaddrinfo" >&5
+echo $ECHO_N "checking for library containing getaddrinfo... $ECHO_C" >&6
+if test "${ac_cv_search_getaddrinfo+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_getaddrinfo=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getaddrinfo="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_getaddrinfo" = no; then
+ for ac_lib in nsl socket; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getaddrinfo="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_getaddrinfo" >&5
+echo "${ECHO_T}$ac_cv_search_getaddrinfo" >&6
+if test "$ac_cv_search_getaddrinfo" != no; then
+ test "$ac_cv_search_getaddrinfo" = "none required" || LIBS="$ac_cv_search_getaddrinfo $LIBS"
+
+fi
+
+
+
+for ac_func in getaddrinfo gai_strerror
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+ case $gl_cv_func_getcwd_null in
+ yes)
+
+ :
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getcwd handles long file names properly" >&5
+echo $ECHO_N "checking whether getcwd handles long file names properly... $ECHO_C" >&6
+if test "${gl_cv_func_getcwd_path_max+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Arrange for deletion of the temporary directory this test creates.
+ ac_clean_files="$ac_clean_files confdir3"
+ if test "$cross_compiling" = yes; then
+ gl_cv_func_getcwd_path_max=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifndef AT_FDCWD
+# define AT_FDCWD 0
+#endif
+#ifdef ENAMETOOLONG
+# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
+#else
+# define is_ENAMETOOLONG(x) 0
+#endif
+
+/* Don't get link errors because mkdir is redefined to rpl_mkdir. */
+#undef mkdir
+
+#ifndef S_IRWXU
+# define S_IRWXU 0700
+#endif
+
+/* The length of this name must be 8. */
+#define DIR_NAME "confdir3"
+#define DIR_NAME_LEN 8
+#define DIR_NAME_SIZE (DIR_NAME_LEN + 1)
+
+/* The length of "../". */
+#define DOTDOTSLASH_LEN 3
+
+/* Leftover bytes in the buffer, to work around library or OS bugs. */
+#define BUF_SLOP 20
+
+int
+main (void)
+{
+#ifndef PATH_MAX
+ /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
+ at least not on a local file system. And if we were to start worrying
+ about remote file systems, we'd have to enable the wrapper function
+ all of the time, just to be safe. That's not worth the cost. */
+ exit (0);
+#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \
+ - DIR_NAME_SIZE - BUF_SLOP) \
+ <= PATH_MAX)
+ /* FIXME: Assuming there's a system for which this is true,
+ this should be done in a compile test. */
+ exit (0);
+#else
+ char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
+ + DIR_NAME_SIZE + BUF_SLOP];
+ char *cwd = getcwd (buf, PATH_MAX);
+ size_t initial_cwd_len;
+ size_t cwd_len;
+ int fail = 0;
+ size_t n_chdirs = 0;
+
+ if (cwd == NULL)
+ exit (1);
+
+ cwd_len = initial_cwd_len = strlen (cwd);
+
+ while (1)
+ {
+ size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
+ char *c = NULL;
+
+ cwd_len += DIR_NAME_SIZE;
+ /* If mkdir or chdir fails, it could be that this system cannot create
+ any file with an absolute name longer than PATH_MAX, such as cygwin.
+ If so, leave fail as 0, because the current working directory can't
+ be too long for getcwd if it can't even be created. For other
+ errors, be pessimistic and consider that as a failure, too. */
+ if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
+ {
+ if (! (errno == ERANGE || is_ENAMETOOLONG (errno)))
+ fail = 2;
+ break;
+ }
+
+ if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
+ {
+ c = getcwd (buf, PATH_MAX);
+ if (!c && errno == ENOENT)
+ {
+ fail = 1;
+ break;
+ }
+ if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno)))
+ {
+ fail = 2;
+ break;
+ }
+ }
+
+ if (dotdot_max <= cwd_len - initial_cwd_len)
+ {
+ if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
+ break;
+ c = getcwd (buf, cwd_len + 1);
+ if (!c)
+ {
+ if (! (errno == ERANGE || errno == ENOENT
+ || is_ENAMETOOLONG (errno)))
+ {
+ fail = 2;
+ break;
+ }
+ if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
+ {
+ fail = 1;
+ break;
+ }
+ }
+ }
+
+ if (c && strlen (c) != cwd_len)
+ {
+ fail = 2;
+ break;
+ }
+ ++n_chdirs;
+ }
+
+ /* Leaving behind such a deep directory is not polite.
+ So clean up here, right away, even though the driving
+ shell script would also clean up. */
+ {
+ size_t i;
+
+ /* Unlink first, in case the chdir failed. */
+ unlink (DIR_NAME);
+ for (i = 0; i <= n_chdirs; i++)
+ {
+ if (chdir ("..") < 0)
+ break;
+ rmdir (DIR_NAME);
+ }
+ }
+
+ exit (fail);
+#endif
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_getcwd_path_max=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+case $? in
+ 1) gl_cv_func_getcwd_path_max='no, but it is partly working';;
+ *) gl_cv_func_getcwd_path_max=no;;
+ esac
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_getcwd_path_max" >&5
+echo "${ECHO_T}$gl_cv_func_getcwd_path_max" >&6
+ case $gl_cv_func_getcwd_path_max in
+ no,*)
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PARTLY_WORKING_GETCWD 1
+_ACEOF
+;;
+ esac
+;;
+ esac
+
+ case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_path_max in
+ yes,yes) ;;
+ *)
+ case $LIBOBJS in
+ "getcwd.$ac_objext" | \
+ *" getcwd.$ac_objext" | \
+ "getcwd.$ac_objext "* | \
+ *" getcwd.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getcwd.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define __GETCWD_PREFIX rpl_
+_ACEOF
+
+
+
+
+
+ :
+;;
+ esac
+
+
+
+ case $LIBOBJS in
+ "getdate.$ac_objext" | \
+ *" getdate.$ac_objext" | \
+ "getdate.$ac_objext "* | \
+ *" getdate.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getdate.$ac_objext" ;;
+esac
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for struct tm.tm_zone" >&5
+echo $ECHO_N "checking for struct tm.tm_zone... $ECHO_C" >&6
+if test "${ac_cv_member_struct_tm_tm_zone+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_cv_struct_tm>
+
+
+int
+main ()
+{
+static struct tm ac_aggr;
+if (ac_aggr.tm_zone)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_tm_tm_zone=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_cv_struct_tm>
+
+
+int
+main ()
+{
+static struct tm ac_aggr;
+if (sizeof ac_aggr.tm_zone)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_tm_tm_zone=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_tm_tm_zone=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_tm_tm_zone" >&5
+echo "${ECHO_T}$ac_cv_member_struct_tm_tm_zone" >&6
+if test $ac_cv_member_struct_tm_tm_zone = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_TM_TM_ZONE 1
+_ACEOF
+
+
+fi
+
+if test "$ac_cv_member_struct_tm_tm_zone" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TM_ZONE 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: checking for tzname" >&5
+echo $ECHO_N "checking for tzname... $ECHO_C" >&6
+if test "${ac_cv_var_tzname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+#ifndef tzname /* For SGI. */
+extern char *tzname[]; /* RS6000 and others reject char **tzname. */
+#endif
+
+int
+main ()
+{
+atoi(*tzname);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_var_tzname=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_var_tzname=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_var_tzname" >&5
+echo "${ECHO_T}$ac_cv_var_tzname" >&6
+ if test $ac_cv_var_tzname = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TZNAME 1
+_ACEOF
+
+ fi
+fi
+
+
+
+
+
+
+
+
+
+
+for ac_func in getdelim
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+
+ :
+
+
+
+
+
+
+ if test $ac_cv_func_getdelim = no; then
+
+
+
+for ac_func in flockfile funlockfile
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ fi
+
+
+
+for ac_func in gethostname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_gethostname = no; then
+
+
+for ac_func in uname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ fi
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether getline is declared" >&5
+echo $ECHO_N "checking whether getline is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_getline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getline
+ char *p = (char *) getline;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_getline=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_getline=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_getline" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getline" >&6
+if test $ac_cv_have_decl_getline = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLINE 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETLINE 0
+_ACEOF
+
+
+fi
+
+
+
+ gl_getline_needs_run_time_check=no
+ echo "$as_me:$LINENO: checking for getline" >&5
+echo $ECHO_N "checking for getline... $ECHO_C" >&6
+if test "${ac_cv_func_getline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getline to an innocuous variant, in case <limits.h> declares getline.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getline innocuous_getline
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getline (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getline
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getline ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getline) || defined (__stub___getline)
+choke me
+#else
+char (*f) () = getline;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getline;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getline=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getline=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getline" >&5
+echo "${ECHO_T}$ac_cv_func_getline" >&6
+if test $ac_cv_func_getline = yes; then
+ gl_getline_needs_run_time_check=yes
+else
+ am_cv_func_working_getline=no
+fi
+
+ if test $gl_getline_needs_run_time_check = yes; then
+ echo "$as_me:$LINENO: checking for working getline function" >&5
+echo $ECHO_N "checking for working getline function... $ECHO_C" >&6
+if test "${am_cv_func_working_getline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ echo fooN |tr -d '\012'|tr N '\012' > conftest.data
+ if test "$cross_compiling" = yes; then
+ am_cv_func_working_getline=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+ int main ()
+ { /* Based on a test program from Karl Heuer. */
+ char *line = NULL;
+ size_t siz = 0;
+ int len;
+ FILE *in = fopen ("./conftest.data", "r");
+ if (!in)
+ return 1;
+ len = getline (&line, &siz, in);
+ exit ((len == 4 && line && strcmp (line, "foo\n") == 0) ? 0 : 1);
+ }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ am_cv_func_working_getline=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+am_cv_func_working_getline=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $am_cv_func_working_getline" >&5
+echo "${ECHO_T}$am_cv_func_working_getline" >&6
+ fi
+
+ if test $am_cv_func_working_getline = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define getline gnu_getline
+_ACEOF
+
+ case $LIBOBJS in
+ "getline.$ac_objext" | \
+ *" getline.$ac_objext" | \
+ "getline.$ac_objext "* | \
+ *" getline.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getline.$ac_objext" ;;
+esac
+
+
+
+
+
+
+
+
+
+for ac_func in getdelim
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+
+ :
+
+
+
+
+
+
+ if test $ac_cv_func_getdelim = no; then
+
+
+
+for ac_func in flockfile funlockfile
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ fi
+
+
+ fi
+
+
+
+for ac_func in getlogin_r
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_getlogin_r = no; then
+
+
+
+ :
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+ case $LIBOBJS in
+ "getlogin_r.$ac_objext" | \
+ *" getlogin_r.$ac_objext" | \
+ "getlogin_r.$ac_objext "* | \
+ *" getlogin_r.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getlogin_r.$ac_objext" ;;
+esac
+
+
+ fi
+
+
+ # Avoid multiple inclusions of getndelim2.o into LIBOBJS.
+ # This hack won't be needed after gnulib requires Autoconf 2.58 or later.
+ case " $LIBOBJS " in
+ *" getndelim2.$ac_objext "* ) ;;
+ *) case $LIBOBJS in
+ "getndelim2.$ac_objext" | \
+ *" getndelim2.$ac_objext" | \
+ "getndelim2.$ac_objext "* | \
+ *" getndelim2.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getndelim2.$ac_objext" ;;
+esac
+;;
+ esac
+
+
+
+
+
+
+
+ :
+
+
+
+ if test -n "$GETOPT_H"; then
+
+ case $LIBOBJS in
+ "getopt.$ac_objext" | \
+ *" getopt.$ac_objext" | \
+ "getopt.$ac_objext "* | \
+ *" getopt.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getopt.$ac_objext" ;;
+esac
+
+ case $LIBOBJS in
+ "getopt1.$ac_objext" | \
+ *" getopt1.$ac_objext" | \
+ "getopt1.$ac_objext "* | \
+ *" getopt1.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getopt1.$ac_objext" ;;
+esac
+
+
+ GETOPT_H=getopt.h
+
+cat >>confdefs.h <<\_ACEOF
+#define __GETOPT_PREFIX rpl_
+_ACEOF
+
+
+
+ :
+
+fi
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+for ac_header in OS.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in getpagesize
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+ :
+
+
+
+
+
+ case $LIBOBJS in
+ "getpass.$ac_objext" | \
+ *" getpass.$ac_objext" | \
+ "getpass.$ac_objext "* | \
+ *" getpass.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS getpass.$ac_objext" ;;
+esac
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define getpass gnu_getpass
+_ACEOF
+
+
+
+
+ case $LIBOBJS in
+ "gettime.$ac_objext" | \
+ *" gettime.$ac_objext" | \
+ "gettime.$ac_objext "* | \
+ *" gettime.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS gettime.$ac_objext" ;;
+esac
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether gettimeofday clobbers localtime buffer" >&5
+echo $ECHO_N "checking whether gettimeofday clobbers localtime buffer... $ECHO_C" >&6
+if test "${jm_cv_func_gettimeofday_clobber+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ jm_cv_func_gettimeofday_clobber=yes
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <string.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <stdlib.h>
+
+int
+main ()
+{
+ time_t t = 0;
+ struct tm *lt;
+ struct tm saved_lt;
+ struct timeval tv;
+ lt = localtime (&t);
+ saved_lt = *lt;
+ gettimeofday (&tv, NULL);
+ if (memcmp (lt, &saved_lt, sizeof (struct tm)) != 0)
+ exit (1);
+
+ exit (0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ jm_cv_func_gettimeofday_clobber=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+jm_cv_func_gettimeofday_clobber=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+fi
+echo "$as_me:$LINENO: result: $jm_cv_func_gettimeofday_clobber" >&5
+echo "${ECHO_T}$jm_cv_func_gettimeofday_clobber" >&6
+ if test $jm_cv_func_gettimeofday_clobber = yes; then
+
+ case $LIBOBJS in
+ "gettimeofday.$ac_objext" | \
+ *" gettimeofday.$ac_objext" | \
+ "gettimeofday.$ac_objext "* | \
+ *" gettimeofday.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS gettimeofday.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define gmtime rpl_gmtime
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define localtime rpl_localtime
+_ACEOF
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define gettimeofday rpl_gettimeofday
+_ACEOF
+
+
+
+
+ fi
+
+ GLOB_H=
+
+for ac_header in glob.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ GLOB_H=glob.h
+fi
+
+done
+
+
+ if test -z "$GLOB_H"; then
+ echo "$as_me:$LINENO: checking for GNU glob interface version 1" >&5
+echo $ECHO_N "checking for GNU glob interface version 1... $ECHO_C" >&6
+if test "${gl_cv_gnu_glob_interface_version_1+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#include <gnu-versions.h>
+char a[_GNU_GLOB_INTERFACE_VERSION == 1 ? 1 : -1];
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_gnu_glob_interface_version_1=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_gnu_glob_interface_version_1=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_gnu_glob_interface_version_1" >&5
+echo "${ECHO_T}$gl_cv_gnu_glob_interface_version_1" >&6
+
+ if test "$gl_cv_gnu_glob_interface_version_1" = "no"; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ if test -z "$GLOB_H"; then
+ echo "$as_me:$LINENO: checking whether glob lists broken symlinks" >&5
+echo $ECHO_N "checking whether glob lists broken symlinks... $ECHO_C" >&6
+if test "${gl_cv_glob_lists_symlinks+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if ln -s conf-doesntexist conf$$-globtest 2>/dev/null; then
+ gl_cv_glob_lists_symlinks=maybe
+ else
+ # If we can't make a symlink, then we cannot test this issue. Be
+ # pessimistic about this.
+ gl_cv_glob_lists_symlinks=no
+ fi
+
+ if test $gl_cv_glob_lists_symlinks = maybe; then
+ if test "$cross_compiling" = yes; then
+ gl_cv_glob_lists_symlinks=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+#include <glob.h>
+int
+main ()
+{
+glob_t found;
+if (glob ("conf*-globtest", 0, NULL, &found) == GLOB_NOMATCH) return 1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_glob_lists_symlinks=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_glob_lists_symlinks=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ fi
+fi
+echo "$as_me:$LINENO: result: $gl_cv_glob_lists_symlinks" >&5
+echo "${ECHO_T}$gl_cv_glob_lists_symlinks" >&6
+
+ if test $gl_cv_glob_lists_symlinks = no; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ rm -f conf$$-globtest
+
+ if test -n "$GLOB_H"; then
+
+
+ :
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+ :
+
+ GLOB_H=glob.h
+
+ case $LIBOBJS in
+ "glob.$ac_objext" | \
+ *" glob.$ac_objext" | \
+ "glob.$ac_objext "* | \
+ *" glob.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS glob.$ac_objext" ;;
+esac
+
+
+
+ fi
+
+
+
+
+
+ :
+
+
+for ac_header in stdlib.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5
+echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6
+if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_malloc_0_nonnull=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#if STDC_HEADERS || HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+int
+main ()
+{
+exit (malloc (0) ? 0 : 1);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_malloc_0_nonnull=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_malloc_0_nonnull=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5
+echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6
+if test $ac_cv_func_malloc_0_nonnull = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MALLOC 1
+_ACEOF
+
+else
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_MALLOC 0
+_ACEOF
+
+ case $LIBOBJS in
+ "malloc.$ac_objext" | \
+ *" malloc.$ac_objext" | \
+ "malloc.$ac_objext "* | \
+ *" malloc.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define malloc rpl_malloc
+_ACEOF
+
+fi
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+ if test x$ac_cv_header_wchar_h = xyes && test x$ac_cv_header_wctype_h = xyes; then
+ case $LIBOBJS in
+ "mbchar.$ac_objext" | \
+ *" mbchar.$ac_objext" | \
+ "mbchar.$ac_objext "* | \
+ *" mbchar.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS mbchar.$ac_objext" ;;
+esac
+
+ fi
+
+
+ :
+
+
+
+ :
+
+
+
+ case $LIBOBJS in
+ "md5.$ac_objext" | \
+ *" md5.$ac_objext" | \
+ "md5.$ac_objext "* | \
+ *" md5.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS md5.$ac_objext" ;;
+esac
+
+
+
+
+
+ :
+
+
+
+for ac_func in memchr
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_memchr = no; then
+
+
+for ac_header in bp-sym.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ fi
+
+
+
+for ac_func in memmove
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_memmove = no; then
+
+ :
+
+ fi
+
+
+
+
+
+
+
+for ac_func in mempcpy
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_mempcpy = no; then
+
+ :
+
+ fi
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+for ac_func in memrchr
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_memrchr = no; then
+ :
+ fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether mkdir fails due to a trailing slash" >&5
+echo $ECHO_N "checking whether mkdir fails due to a trailing slash... $ECHO_C" >&6
+if test "${gl_cv_func_mkdir_trailing_slash_bug+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ # Arrange for deletion of the temporary directory this test might create.
+ ac_clean_files="$ac_clean_files confdir-slash"
+ if test "$cross_compiling" = yes; then
+ gl_cv_func_mkdir_trailing_slash_bug=yes
+
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <stdlib.h>
+ int main ()
+ {
+ rmdir ("confdir-slash");
+ exit (mkdir ("confdir-slash/", 0700));
+ }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_mkdir_trailing_slash_bug=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_func_mkdir_trailing_slash_bug=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_mkdir_trailing_slash_bug" >&5
+echo "${ECHO_T}$gl_cv_func_mkdir_trailing_slash_bug" >&6
+
+ if test $gl_cv_func_mkdir_trailing_slash_bug = yes; then
+ case $LIBOBJS in
+ "mkdir.$ac_objext" | \
+ *" mkdir.$ac_objext" | \
+ "mkdir.$ac_objext "* | \
+ *" mkdir.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS mkdir.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define mkdir rpl_mkdir
+_ACEOF
+
+ :
+ fi
+
+
+for ac_func in mkstemp
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_mkstemp = no; then
+ gl_cv_func_mkstemp_limitations=yes
+ else
+ echo "$as_me:$LINENO: checking for mkstemp limitations" >&5
+echo $ECHO_N "checking for mkstemp limitations... $ECHO_C" >&6
+if test "${gl_cv_func_mkstemp_limitations+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ mkdir conftest.mkstemp
+ if test "$cross_compiling" = yes; then
+ gl_cv_func_mkstemp_limitations=yes
+
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# include <stdlib.h>
+# include <unistd.h>
+ int main ()
+ {
+ int i;
+ for (i = 0; i < 70; i++)
+ {
+ char template[] = "conftest.mkstemp/coXXXXXX";
+ int fd = mkstemp (template);
+ if (fd == -1)
+ exit (1);
+ close (fd);
+ }
+ exit (0);
+ }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_mkstemp_limitations=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_func_mkstemp_limitations=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ rm -rf conftest.mkstemp
+
+
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_mkstemp_limitations" >&5
+echo "${ECHO_T}$gl_cv_func_mkstemp_limitations" >&6
+ fi
+
+ if test $gl_cv_func_mkstemp_limitations = yes; then
+ case $LIBOBJS in
+ "mkstemp.$ac_objext" | \
+ *" mkstemp.$ac_objext" | \
+ "mkstemp.$ac_objext "* | \
+ *" mkstemp.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext" ;;
+esac
+
+ case $LIBOBJS in
+ "tempname.$ac_objext" | \
+ *" tempname.$ac_objext" | \
+ "tempname.$ac_objext "* | \
+ *" tempname.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS tempname.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define mkstemp rpl_mkstemp
+_ACEOF
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in __secure_getenv gettimeofday
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ :
+
+
+
+
+
+
+
+ fi
+
+
+
+ if test $ac_cv_func_working_mktime = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define mktime rpl_mktime
+_ACEOF
+
+ :
+ fi
+
+
+
+
+ nanosleep_save_libs=$LIBS
+
+ # Solaris 2.5.1 needs -lposix4 to get the nanosleep function.
+ # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
+ echo "$as_me:$LINENO: checking for library containing nanosleep" >&5
+echo $ECHO_N "checking for library containing nanosleep... $ECHO_C" >&6
+if test "${ac_cv_search_nanosleep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_nanosleep=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char nanosleep ();
+int
+main ()
+{
+nanosleep ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_nanosleep="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_nanosleep" = no; then
+ for ac_lib in rt posix4; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char nanosleep ();
+int
+main ()
+{
+nanosleep ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_nanosleep="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_nanosleep" >&5
+echo "${ECHO_T}$ac_cv_search_nanosleep" >&6
+if test "$ac_cv_search_nanosleep" != no; then
+ test "$ac_cv_search_nanosleep" = "none required" || LIBS="$ac_cv_search_nanosleep $LIBS"
+ test "$ac_cv_search_nanosleep" = "none required" ||
+ LIB_NANOSLEEP=$ac_cv_search_nanosleep
+fi
+
+
+
+ echo "$as_me:$LINENO: checking whether nanosleep works" >&5
+echo $ECHO_N "checking whether nanosleep works... $ECHO_C" >&6
+if test "${jm_cv_func_nanosleep_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+
+
+ :
+
+
+
+
+
+ if test "$cross_compiling" = yes; then
+ jm_cv_func_nanosleep_works=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+ int
+ main ()
+ {
+ struct timespec ts_sleep, ts_remaining;
+ ts_sleep.tv_sec = 0;
+ ts_sleep.tv_nsec = 1;
+ exit (nanosleep (&ts_sleep, &ts_remaining) == 0 ? 0 : 1);
+ }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ jm_cv_func_nanosleep_works=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+jm_cv_func_nanosleep_works=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+fi
+echo "$as_me:$LINENO: result: $jm_cv_func_nanosleep_works" >&5
+echo "${ECHO_T}$jm_cv_func_nanosleep_works" >&6
+ if test $jm_cv_func_nanosleep_works = no; then
+ case $LIBOBJS in
+ "nanosleep.$ac_objext" | \
+ *" nanosleep.$ac_objext" | \
+ "nanosleep.$ac_objext "* | \
+ *" nanosleep.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS nanosleep.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define nanosleep rpl_nanosleep
+_ACEOF
+
+
+
+ :
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+ fi
+
+ LIBS=$nanosleep_save_libs
+
+
+
+
+
+for ac_func in openat
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ case $ac_cv_func_openat in
+ yes) ;;
+ *)
+
+cat >>confdefs.h <<\_ACEOF
+#define __OPENAT_PREFIX rpl_
+_ACEOF
+
+
+
+;;
+ esac
+
+
+
+
+
+ case $LIBOBJS in
+ "pagealign_alloc.$ac_objext" | \
+ *" pagealign_alloc.$ac_objext" | \
+ "pagealign_alloc.$ac_objext "* | \
+ *" pagealign_alloc.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS pagealign_alloc.$ac_objext" ;;
+esac
+
+
+
+
+
+ :
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+ case $LIBOBJS in
+ "quotearg.$ac_objext" | \
+ *" quotearg.$ac_objext" | \
+ "quotearg.$ac_objext "* | \
+ *" quotearg.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS quotearg.$ac_objext" ;;
+esac
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for mbstate_t" >&5
+echo $ECHO_N "checking for mbstate_t... $ECHO_C" >&6
+if test "${ac_cv_type_mbstate_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+# include <wchar.h>
+int
+main ()
+{
+mbstate_t x; return sizeof x;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_mbstate_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_mbstate_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_mbstate_t" >&5
+echo "${ECHO_T}$ac_cv_type_mbstate_t" >&6
+ if test $ac_cv_type_mbstate_t = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MBSTATE_T 1
+_ACEOF
+
+ else
+
+cat >>confdefs.h <<\_ACEOF
+#define mbstate_t int
+_ACEOF
+
+ fi
+
+ echo "$as_me:$LINENO: checking whether mbrtowc and mbstate_t are properly declared" >&5
+echo $ECHO_N "checking whether mbrtowc and mbstate_t are properly declared... $ECHO_C" >&6
+if test "${gl_cv_func_mbrtowc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <wchar.h>
+int
+main ()
+{
+wchar_t wc;
+ char const s[] = "";
+ size_t n = 1;
+ mbstate_t state;
+ return ! (sizeof state && (mbrtowc) (&wc, s, n, &state));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_mbrtowc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_func_mbrtowc=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_mbrtowc" >&5
+echo "${ECHO_T}$gl_cv_func_mbrtowc" >&6
+ if test $gl_cv_func_mbrtowc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MBRTOWC 1
+_ACEOF
+
+ fi
+
+
+
+
+for ac_func in readlink
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ if test $ac_cv_func_readlink = no; then
+ case $LIBOBJS in
+ "readlink.$ac_objext" | \
+ *" readlink.$ac_objext" | \
+ "readlink.$ac_objext "* | \
+ *" readlink.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS readlink.$ac_objext" ;;
+esac
+
+
+ :
+
+ fi
+
+
+for ac_header in stdlib.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+echo "$as_me:$LINENO: checking for GNU libc compatible realloc" >&5
+echo $ECHO_N "checking for GNU libc compatible realloc... $ECHO_C" >&6
+if test "${ac_cv_func_realloc_0_nonnull+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_realloc_0_nonnull=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#if STDC_HEADERS || HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+char *realloc ();
+#endif
+
+int
+main ()
+{
+exit (realloc (0, 0) ? 0 : 1);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_realloc_0_nonnull=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_realloc_0_nonnull=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_realloc_0_nonnull" >&5
+echo "${ECHO_T}$ac_cv_func_realloc_0_nonnull" >&6
+if test $ac_cv_func_realloc_0_nonnull = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_REALLOC 1
+_ACEOF
+
+else
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_REALLOC 0
+_ACEOF
+
+ case $LIBOBJS in
+ "realloc.$ac_objext" | \
+ *" realloc.$ac_objext" | \
+ "realloc.$ac_objext "* | \
+ *" realloc.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define realloc rpl_realloc
+_ACEOF
+
+fi
+
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _REGEX_LARGE_OFFSETS 1
+_ACEOF
+
+
+
+
+
+# Check whether --with-included-regex or --without-included-regex was given.
+if test "${with_included_regex+set}" = set; then
+ withval="$with_included_regex"
+
+fi;
+
+ case $with_included_regex in
+ yes|no) ac_use_included_regex=$with_included_regex
+ ;;
+ '')
+ # If the system regex support is good enough that it passes the the
+ # following run test, then default to *not* using the included regex.c.
+ # If cross compiling, assume the test would fail and use the included
+ # regex.c. The first failing regular expression is from `Spencer ere
+ # test #75' in grep-2.3.
+ echo "$as_me:$LINENO: checking for working re_compile_pattern" >&5
+echo $ECHO_N "checking for working re_compile_pattern... $ECHO_C" >&6
+if test "${gl_cv_func_re_compile_pattern_broken+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ gl_cv_func_re_compile_pattern_broken=yes
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+ #include <regex.h>
+int
+main ()
+{
+static struct re_pattern_buffer regex;
+ const char *s;
+ struct re_registers regs;
+ /* Use the POSIX-compliant spelling with leading REG_,
+ rather than the traditional GNU spelling with leading RE_,
+ so that we reject older libc implementations. */
+ re_set_syntax (REG_SYNTAX_POSIX_EGREP);
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("a[:]:]b\n", 9, &regex);
+ /* This should fail with _Invalid character class name_ error. */
+ if (!s)
+ exit (1);
+
+ /* This should succeed, but does not for e.g. glibc-2.1.3. */
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("{1", 2, &regex);
+
+ if (s)
+ exit (1);
+
+ /* The following example is derived from a problem report
+ against gawk from Jorge Stolfi <stolfi@ic.unicamp.br>. */
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("[an\371]*n", 7, &regex);
+ if (s)
+ exit (1);
+
+ /* This should match, but does not for e.g. glibc-2.2.1. */
+ if (re_match (&regex, "an", 2, 0, &regs) != 2)
+ exit (1);
+
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("x", 1, &regex);
+ if (s)
+ exit (1);
+
+ /* The version of regex.c in e.g. GNU libc-2.2.93 did not
+ work with a negative RANGE argument. */
+ if (re_search (&regex, "wxy", 3, 2, -2, &regs) != 1)
+ exit (1);
+
+ /* The version of regex.c in older versions of gnulib
+ ignored REG_IGNORE_CASE (which was then called RE_ICASE).
+ Detect that problem too. */
+ memset (&regex, 0, sizeof (regex));
+ re_set_syntax (REG_SYNTAX_EMACS | REG_IGNORE_CASE);
+ s = re_compile_pattern ("x", 1, &regex);
+ if (s)
+ exit (1);
+
+ if (re_search (&regex, "WXY", 3, 0, 3, &regs) < 0)
+ exit (1);
+
+ /* REG_STARTEND was added to glibc on 2004-01-15.
+ Reject older versions. */
+ if (! REG_STARTEND)
+ exit (1);
+
+ /* Reject hosts whose regoff_t values are too narrow.
+ These include glibc 2.3.5 on hosts with 64-bit off_t
+ and 32-bit int, and Solaris 10 on hosts with 32-bit int
+ and _FILE_OFFSET_BITS=64. */
+ if (sizeof (regoff_t) < sizeof (off_t))
+ exit (1);
+
+ exit (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_re_compile_pattern_broken=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_func_re_compile_pattern_broken=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_re_compile_pattern_broken" >&5
+echo "${ECHO_T}$gl_cv_func_re_compile_pattern_broken" >&6
+ ac_use_included_regex=$gl_cv_func_re_compile_pattern_broken
+ ;;
+ *) { { echo "$as_me:$LINENO: error: Invalid value for --with-included-regex: $with_included_regex" >&5
+echo "$as_me: error: Invalid value for --with-included-regex: $with_included_regex" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+
+ if test $ac_use_included_regex = yes; then
+ case $LIBOBJS in
+ "regex.$ac_objext" | \
+ *" regex.$ac_objext" | \
+ "regex.$ac_objext "* | \
+ *" regex.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS regex.$ac_objext" ;;
+esac
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking whether rename is broken" >&5
+echo $ECHO_N "checking whether rename is broken... $ECHO_C" >&6
+if test "${vb_cv_func_rename_trailing_slash_bug+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ rm -rf conftest.d1 conftest.d2
+ mkdir conftest.d1 ||
+ { { echo "$as_me:$LINENO: error: cannot create temporary directory" >&5
+echo "$as_me: error: cannot create temporary directory" >&2;}
+ { (exit 1); exit 1; }; }
+ if test "$cross_compiling" = yes; then
+ vb_cv_func_rename_trailing_slash_bug=yes
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# include <stdio.h>
+ int
+ main ()
+ {
+ exit (rename ("conftest.d1/", "conftest.d2") ? 1 : 0);
+ }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ vb_cv_func_rename_trailing_slash_bug=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+vb_cv_func_rename_trailing_slash_bug=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+ rm -rf conftest.d1 conftest.d2
+
+fi
+echo "$as_me:$LINENO: result: $vb_cv_func_rename_trailing_slash_bug" >&5
+echo "${ECHO_T}$vb_cv_func_rename_trailing_slash_bug" >&6
+ if test $vb_cv_func_rename_trailing_slash_bug = yes; then
+ case $LIBOBJS in
+ "rename.$ac_objext" | \
+ *" rename.$ac_objext" | \
+ "rename.$ac_objext "* | \
+ *" rename.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS rename.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define rename rpl_rename
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define RENAME_TRAILING_SLASH_BUG 1
+_ACEOF
+
+ :
+ fi
+
+ echo "$as_me:$LINENO: checking for C/C++ restrict keyword" >&5
+echo $ECHO_N "checking for C/C++ restrict keyword... $ECHO_C" >&6
+if test "${gl_cv_c_restrict+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gl_cv_c_restrict=no
+ # Try the official restrict keyword, then gcc's __restrict, and
+ # the less common variants.
+ for ac_kw in restrict __restrict __restrict__ _Restrict; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+float * $ac_kw x;
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_c_restrict=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+
+fi
+echo "$as_me:$LINENO: result: $gl_cv_c_restrict" >&5
+echo "${ECHO_T}$gl_cv_c_restrict" >&6
+ case $gl_cv_c_restrict in
+ restrict) ;;
+ no)
+cat >>confdefs.h <<\_ACEOF
+#define restrict
+_ACEOF
+ ;;
+ *) cat >>confdefs.h <<_ACEOF
+#define restrict $gl_cv_c_restrict
+_ACEOF
+ ;;
+ esac
+
+
+
+for ac_func in rpmatch
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_rpmatch = no; then
+ :
+ fi
+
+
+
+ case $LIBOBJS in
+ "save-cwd.$ac_objext" | \
+ *" save-cwd.$ac_objext" | \
+ "save-cwd.$ac_objext "* | \
+ *" save-cwd.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS save-cwd.$ac_objext" ;;
+esac
+
+
+ :
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+for ac_func in setenv unsetenv
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_setenv = no; then
+
+
+
+ :
+
+
+
+
+
+
+for ac_header in search.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in tsearch
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+ echo "$as_me:$LINENO: checking if errno is properly declared" >&5
+echo $ECHO_N "checking if errno is properly declared... $ECHO_C" >&6
+ if test "${gt_cv_var_errno_declaration+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <errno.h>
+ extern struct { int foo; } errno;
+int
+main ()
+{
+errno.foo = 1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_var_errno_declaration=no
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_var_errno_declaration=yes
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ echo "$as_me:$LINENO: result: $gt_cv_var_errno_declaration" >&5
+echo "${ECHO_T}$gt_cv_var_errno_declaration" >&6
+ if test $gt_cv_var_errno_declaration = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ERRNO_DECL 1
+_ACEOF
+
+ fi
+
+
+
+ echo "$as_me:$LINENO: checking if environ is properly declared" >&5
+echo $ECHO_N "checking if environ is properly declared... $ECHO_C" >&6
+ if test "${gt_cv_var_environ_declaration+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <unistd.h>
+ extern struct { int foo; } environ;
+int
+main ()
+{
+environ.foo = 1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_var_environ_declaration=no
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_var_environ_declaration=yes
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ echo "$as_me:$LINENO: result: $gt_cv_var_environ_declaration" >&5
+echo "${ECHO_T}$gt_cv_var_environ_declaration" >&6
+ if test $gt_cv_var_environ_declaration = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ENVIRON_DECL 1
+_ACEOF
+
+ fi
+
+
+ fi
+ if test $ac_cv_func_unsetenv = no; then
+
+
+ :
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking if errno is properly declared" >&5
+echo $ECHO_N "checking if errno is properly declared... $ECHO_C" >&6
+ if test "${gt_cv_var_errno_declaration+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <errno.h>
+ extern struct { int foo; } errno;
+int
+main ()
+{
+errno.foo = 1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_var_errno_declaration=no
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_var_errno_declaration=yes
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ echo "$as_me:$LINENO: result: $gt_cv_var_errno_declaration" >&5
+echo "${ECHO_T}$gt_cv_var_errno_declaration" >&6
+ if test $gt_cv_var_errno_declaration = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ERRNO_DECL 1
+_ACEOF
+
+ fi
+
+
+
+ echo "$as_me:$LINENO: checking if environ is properly declared" >&5
+echo $ECHO_N "checking if environ is properly declared... $ECHO_C" >&6
+ if test "${gt_cv_var_environ_declaration+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <unistd.h>
+ extern struct { int foo; } environ;
+int
+main ()
+{
+environ.foo = 1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_var_environ_declaration=no
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_var_environ_declaration=yes
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ echo "$as_me:$LINENO: result: $gt_cv_var_environ_declaration" >&5
+echo "${ECHO_T}$gt_cv_var_environ_declaration" >&6
+ if test $gt_cv_var_environ_declaration = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ENVIRON_DECL 1
+_ACEOF
+
+ fi
+
+
+ else
+ echo "$as_me:$LINENO: checking for unsetenv() return type" >&5
+echo $ECHO_N "checking for unsetenv() return type... $ECHO_C" >&6
+if test "${gt_cv_func_unsetenv_ret+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+int unsetenv (const char *name);
+#else
+int unsetenv();
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_func_unsetenv_ret='int'
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_func_unsetenv_ret='void'
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gt_cv_func_unsetenv_ret" >&5
+echo "${ECHO_T}$gt_cv_func_unsetenv_ret" >&6
+ if test $gt_cv_func_unsetenv_ret = 'void'; then
+
+cat >>confdefs.h <<\_ACEOF
+#define VOID_UNSETENV 1
+_ACEOF
+
+ fi
+ fi
+
+
+
+for ac_header in stdint.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ echo "$as_me:$LINENO: checking for SIZE_MAX" >&5
+echo $ECHO_N "checking for SIZE_MAX... $ECHO_C" >&6
+ result=
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <limits.h>
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef SIZE_MAX
+Found it
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "Found it" >/dev/null 2>&1; then
+ result=yes
+fi
+rm -f conftest*
+
+ if test -z "$result"; then
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 / 10) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 / 10) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 / 10) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 / 10) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 / 10) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) res_hi=$ac_lo;;
+'') result=? ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+long longval () { return (size_t)~(size_t)0 / 10; }
+unsigned long ulongval () { return (size_t)~(size_t)0 / 10; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((size_t)~(size_t)0 / 10) < 0)
+ {
+ long i = longval ();
+ if (i != ((size_t)~(size_t)0 / 10))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((size_t)~(size_t)0 / 10))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ res_hi=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+result=?
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 % 10) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 % 10) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 % 10) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 % 10) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !(((size_t)~(size_t)0 % 10) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) res_lo=$ac_lo;;
+'') result=? ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+long longval () { return (size_t)~(size_t)0 % 10; }
+unsigned long ulongval () { return (size_t)~(size_t)0 % 10; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((size_t)~(size_t)0 % 10) < 0)
+ {
+ long i = longval ();
+ if (i != ((size_t)~(size_t)0 % 10))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((size_t)~(size_t)0 % 10))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ res_lo=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+result=?
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (size_t) <= sizeof (unsigned int)) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (size_t) <= sizeof (unsigned int)) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (size_t) <= sizeof (unsigned int)) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (size_t) <= sizeof (unsigned int)) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+int
+main ()
+{
+static int test_array [1 - 2 * !((sizeof (size_t) <= sizeof (unsigned int)) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) fits_in_uint=$ac_lo;;
+'') result=? ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+long longval () { return sizeof (size_t) <= sizeof (unsigned int); }
+unsigned long ulongval () { return sizeof (size_t) <= sizeof (unsigned int); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if ((sizeof (size_t) <= sizeof (unsigned int)) < 0)
+ {
+ long i = longval ();
+ if (i != (sizeof (size_t) <= sizeof (unsigned int)))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != (sizeof (size_t) <= sizeof (unsigned int)))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ fits_in_uint=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+result=?
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+ if test "$fits_in_uint" = 1; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+ extern size_t foo;
+ extern unsigned long foo;
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ fits_in_uint=0
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test -z "$result"; then
+ if test "$fits_in_uint" = 1; then
+ result="$res_hi$res_lo"U
+ else
+ result="$res_hi$res_lo"UL
+ fi
+ else
+ result='((size_t)~(size_t)0)'
+ fi
+ fi
+ echo "$as_me:$LINENO: result: $result" >&5
+echo "${ECHO_T}$result" >&6
+ if test "$result" != yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define SIZE_MAX $result
+_ACEOF
+
+ fi
+
+
+ echo "$as_me:$LINENO: checking for ssize_t" >&5
+echo $ECHO_N "checking for ssize_t... $ECHO_C" >&6
+if test "${gt_cv_ssize_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+int
+main ()
+{
+int x = sizeof (ssize_t *) + sizeof (ssize_t);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_ssize_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_ssize_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gt_cv_ssize_t" >&5
+echo "${ECHO_T}$gt_cv_ssize_t" >&6
+ if test $gt_cv_ssize_t = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ssize_t int
+_ACEOF
+
+ fi
+
+
+
+
+
+
+
+
+
+ # Define two additional variables used in the Makefile substitution.
+
+ if test "$ac_cv_header_stdbool_h" = yes; then
+ STDBOOL_H=''
+ else
+ STDBOOL_H='stdbool.h'
+ fi
+
+
+ if test "$ac_cv_type__Bool" = yes; then
+ HAVE__BOOL=1
+ else
+ HAVE__BOOL=0
+ fi
+
+
+
+
+for ac_header in sys/inttypes.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for stdint.h" >&5
+echo $ECHO_N "checking for stdint.h... $ECHO_C" >&6
+if test "${gl_cv_header_stdint_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdint.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_header_stdint_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_header_stdint_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+echo "$as_me:$LINENO: result: $gl_cv_header_stdint_h" >&5
+echo "${ECHO_T}$gl_cv_header_stdint_h" >&6
+if test $gl_cv_header_stdint_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STDINT_H 1
+_ACEOF
+
+ STDINT_H=''
+else
+ STDINT_H='stdint.h'
+
+ echo "$as_me:$LINENO: checking whether 'long' is 64 bit wide" >&5
+echo $ECHO_N "checking whether 'long' is 64 bit wide... $ECHO_C" >&6
+if test "${gl_cv_long_bitsize_64+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define POW63 ((((((long) 1 << 15) << 15) << 15) << 15) << 3)
+#define POW64 ((((((long) 1 << 15) << 15) << 15) << 15) << 4)
+typedef int array [2 * (POW63 != 0 && POW64 == 0) - 1];
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_long_bitsize_64=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_long_bitsize_64=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_long_bitsize_64" >&5
+echo "${ECHO_T}$gl_cv_long_bitsize_64" >&6
+ if test $gl_cv_long_bitsize_64 = yes; then
+ HAVE_LONG_64BIT=1
+ else
+ HAVE_LONG_64BIT=0
+ fi
+
+
+ echo "$as_me:$LINENO: checking whether 'long long' is 64 bit wide" >&5
+echo $ECHO_N "checking whether 'long long' is 64 bit wide... $ECHO_C" >&6
+if test "${gl_cv_longlong_bitsize_64+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define POW63 ((((((long long) 1 << 15) << 15) << 15) << 15) << 3)
+#define POW64 ((((((long long) 1 << 15) << 15) << 15) << 15) << 4)
+typedef int array [2 * (POW63 != 0 && POW64 == 0) - 1];
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_longlong_bitsize_64=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_longlong_bitsize_64=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_longlong_bitsize_64" >&5
+echo "${ECHO_T}$gl_cv_longlong_bitsize_64" >&6
+ if test $gl_cv_longlong_bitsize_64 = yes; then
+ HAVE_LONG_LONG_64BIT=1
+ else
+ HAVE_LONG_LONG_64BIT=0
+ fi
+
+
+fi
+
+
+
+
+ case $LIBOBJS in
+ "strcasecmp.$ac_objext" | \
+ *" strcasecmp.$ac_objext" | \
+ "strcasecmp.$ac_objext "* | \
+ *" strcasecmp.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS strcasecmp.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define strcasecmp rpl_strcasecmp
+_ACEOF
+
+
+
+ echo "$as_me:$LINENO: checking whether mbrtowc and mbstate_t are properly declared" >&5
+echo $ECHO_N "checking whether mbrtowc and mbstate_t are properly declared... $ECHO_C" >&6
+if test "${gl_cv_func_mbrtowc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <wchar.h>
+int
+main ()
+{
+wchar_t wc;
+ char const s[] = "";
+ size_t n = 1;
+ mbstate_t state;
+ return ! (sizeof state && (mbrtowc) (&wc, s, n, &state));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_mbrtowc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_func_mbrtowc=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_mbrtowc" >&5
+echo "${ECHO_T}$gl_cv_func_mbrtowc" >&6
+ if test $gl_cv_func_mbrtowc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MBRTOWC 1
+_ACEOF
+
+ fi
+
+
+
+
+
+for ac_func in strncasecmp
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_strncasecmp = no; then
+
+ :
+
+ fi
+
+
+
+
+
+
+for ac_func in strdup
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+
+ :
+
+
+
+
+
+ :
+
+
+
+for ac_func in strerror
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_strerror = no; then
+
+ :
+
+ fi
+
+
+
+ case $LIBOBJS in
+ "strstr.$ac_objext" | \
+ *" strstr.$ac_objext" | \
+ "strstr.$ac_objext "* | \
+ *" strstr.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS strstr.$ac_objext" ;;
+esac
+
+
+
+ echo "$as_me:$LINENO: checking whether mbrtowc and mbstate_t are properly declared" >&5
+echo $ECHO_N "checking whether mbrtowc and mbstate_t are properly declared... $ECHO_C" >&6
+if test "${gl_cv_func_mbrtowc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <wchar.h>
+int
+main ()
+{
+wchar_t wc;
+ char const s[] = "";
+ size_t n = 1;
+ mbstate_t state;
+ return ! (sizeof state && (mbrtowc) (&wc, s, n, &state));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_mbrtowc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_func_mbrtowc=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_mbrtowc" >&5
+echo "${ECHO_T}$gl_cv_func_mbrtowc" >&6
+ if test $gl_cv_func_mbrtowc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MBRTOWC 1
+_ACEOF
+
+ fi
+
+
+
+
+
+for ac_func in strtol
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_strtol = no; then
+
+
+
+ :
+
+
+
+
+
+
+ fi
+
+
+
+for ac_func in strtoul
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_strtoul = no; then
+
+
+
+
+ :
+
+
+
+
+
+
+
+ fi
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether localtime_r is compatible with its POSIX signature" >&5
+echo $ECHO_N "checking whether localtime_r is compatible with its POSIX signature... $ECHO_C" >&6
+if test "${gl_cv_time_r_posix+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+int
+main ()
+{
+/* We don't need to append 'restrict's to the argument types,
+ even though the POSIX signature has the 'restrict's,
+ since C99 says they can't affect type compatibility. */
+ struct tm * (*ptr) (time_t const *, struct tm *) = localtime_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_time_r_posix=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_time_r_posix=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_time_r_posix" >&5
+echo "${ECHO_T}$gl_cv_time_r_posix" >&6
+ if test $gl_cv_time_r_posix = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TIME_R_POSIX 1
+_ACEOF
+
+ else
+ case $LIBOBJS in
+ "time_r.$ac_objext" | \
+ *" time_r.$ac_objext" | \
+ "time_r.$ac_objext "* | \
+ *" time_r.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS time_r.$ac_objext" ;;
+esac
+
+
+ :
+
+ fi
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for struct timespec" >&5
+echo $ECHO_N "checking for struct timespec... $ECHO_C" >&6
+if test "${fu_cv_sys_struct_timespec+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+int
+main ()
+{
+static struct timespec x; x.tv_sec = x.tv_nsec;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ fu_cv_sys_struct_timespec=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fu_cv_sys_struct_timespec=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $fu_cv_sys_struct_timespec" >&5
+echo "${ECHO_T}$fu_cv_sys_struct_timespec" >&6
+
+ if test $fu_cv_sys_struct_timespec = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_TIMESPEC 1
+_ACEOF
+
+ fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether nanosleep is declared" >&5
+echo $ECHO_N "checking whether nanosleep is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_nanosleep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+
+int
+main ()
+{
+#ifndef nanosleep
+ char *p = (char *) nanosleep;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_nanosleep=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_nanosleep=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_nanosleep" >&5
+echo "${ECHO_T}$ac_cv_have_decl_nanosleep" >&6
+if test $ac_cv_have_decl_nanosleep = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_NANOSLEEP 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_NANOSLEEP 0
+_ACEOF
+
+
+fi
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether tzset clobbers localtime buffer" >&5
+echo $ECHO_N "checking whether tzset clobbers localtime buffer... $ECHO_C" >&6
+if test "${gl_cv_func_tzset_clobber+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ if test "$cross_compiling" = yes; then
+ gl_cv_func_tzset_clobber=yes
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#include <stdlib.h>
+
+int
+main ()
+{
+ time_t t1 = 853958121;
+ struct tm *p, s;
+ putenv ("TZ=GMT0");
+ p = localtime (&t1);
+ s = *p;
+ putenv ("TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00");
+ tzset ();
+ exit (p->tm_year != s.tm_year
+ || p->tm_mon != s.tm_mon
+ || p->tm_mday != s.tm_mday
+ || p->tm_hour != s.tm_hour
+ || p->tm_min != s.tm_min
+ || p->tm_sec != s.tm_sec);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_func_tzset_clobber=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_func_tzset_clobber=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $gl_cv_func_tzset_clobber" >&5
+echo "${ECHO_T}$gl_cv_func_tzset_clobber" >&6
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_RUN_TZSET_TEST 1
+_ACEOF
+
+
+ if test $gl_cv_func_tzset_clobber = yes; then
+
+ case $LIBOBJS in
+ "gettimeofday.$ac_objext" | \
+ *" gettimeofday.$ac_objext" | \
+ "gettimeofday.$ac_objext "* | \
+ *" gettimeofday.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS gettimeofday.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define gmtime rpl_gmtime
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define localtime rpl_localtime
+_ACEOF
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define tzset rpl_tzset
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define TZSET_CLOBBERS_LOCALTIME_BUFFER 1
+_ACEOF
+
+ fi
+
+
+
+ case $LIBOBJS in
+ "dup-safer.$ac_objext" | \
+ *" dup-safer.$ac_objext" | \
+ "dup-safer.$ac_objext "* | \
+ *" dup-safer.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS dup-safer.$ac_objext" ;;
+esac
+
+ case $LIBOBJS in
+ "fd-safer.$ac_objext" | \
+ *" fd-safer.$ac_objext" | \
+ "fd-safer.$ac_objext "* | \
+ *" fd-safer.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS fd-safer.$ac_objext" ;;
+esac
+
+ case $LIBOBJS in
+ "pipe-safer.$ac_objext" | \
+ *" pipe-safer.$ac_objext" | \
+ "pipe-safer.$ac_objext "* | \
+ *" pipe-safer.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS pipe-safer.$ac_objext" ;;
+esac
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_UNLOCKED_IO 1
+_ACEOF
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in vasnprintf
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_vasnprintf = no; then
+ case $LIBOBJS in
+ "printf-args.$ac_objext" | \
+ *" printf-args.$ac_objext" | \
+ "printf-args.$ac_objext "* | \
+ *" printf-args.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS printf-args.$ac_objext" ;;
+esac
+
+ case $LIBOBJS in
+ "printf-parse.$ac_objext" | \
+ *" printf-parse.$ac_objext" | \
+ "printf-parse.$ac_objext "* | \
+ *" printf-parse.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS printf-parse.$ac_objext" ;;
+esac
+
+ case $LIBOBJS in
+ "asnprintf.$ac_objext" | \
+ *" asnprintf.$ac_objext" | \
+ "asnprintf.$ac_objext "* | \
+ *" asnprintf.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS asnprintf.$ac_objext" ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for ptrdiff_t" >&5
+echo $ECHO_N "checking for ptrdiff_t... $ECHO_C" >&6
+if test "${ac_cv_type_ptrdiff_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((ptrdiff_t *) 0)
+ return 0;
+if (sizeof (ptrdiff_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_ptrdiff_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_ptrdiff_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_ptrdiff_t" >&5
+echo "${ECHO_T}$ac_cv_type_ptrdiff_t" >&6
+if test $ac_cv_type_ptrdiff_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PTRDIFF_T 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in snprintf wcslen
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+ fi
+
+
+
+for ac_func in vasprintf
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ case $LIBOBJS in
+ "$ac_func.$ac_objext" | \
+ *" $ac_func.$ac_objext" | \
+ "$ac_func.$ac_objext "* | \
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+ if test $ac_cv_func_vasprintf = no; then
+ case $LIBOBJS in
+ "asprintf.$ac_objext" | \
+ *" asprintf.$ac_objext" | \
+ "asprintf.$ac_objext "* | \
+ *" asprintf.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" ;;
+esac
+
+
+
+
+
+ fi
+
+
+
+ case $LIBOBJS in
+ "xmalloc.$ac_objext" | \
+ *" xmalloc.$ac_objext" | \
+ "xmalloc.$ac_objext "* | \
+ *" xmalloc.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS xmalloc.$ac_objext" ;;
+esac
+
+
+
+ :
+
+
+
+ :
+
+
+
+
+ case $LIBOBJS in
+ "xgetcwd.$ac_objext" | \
+ *" xgetcwd.$ac_objext" | \
+ "xgetcwd.$ac_objext "* | \
+ *" xgetcwd.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS xgetcwd.$ac_objext" ;;
+esac
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+for ac_header in stdint.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+ case $LIBOBJS in
+ "yesno.$ac_objext" | \
+ *" yesno.$ac_objext" | \
+ "yesno.$ac_objext "* | \
+ *" yesno.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS yesno.$ac_objext" ;;
+esac
+
+
+ :
+
+
+
+
+ MKINSTALLDIRS=
+ if test -n "$ac_aux_dir"; then
+ case "$ac_aux_dir" in
+ /*) MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" ;;
+ *) MKINSTALLDIRS="\$(top_builddir)/$ac_aux_dir/mkinstalldirs" ;;
+ esac
+ fi
+ if test -z "$MKINSTALLDIRS"; then
+ MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+ fi
+
+
+
+ echo "$as_me:$LINENO: checking whether NLS is requested" >&5
+echo $ECHO_N "checking whether NLS is requested... $ECHO_C" >&6
+ # Check whether --enable-nls or --disable-nls was given.
+if test "${enable_nls+set}" = set; then
+ enableval="$enable_nls"
+ USE_NLS=$enableval
+else
+ USE_NLS=yes
+fi;
+ echo "$as_me:$LINENO: result: $USE_NLS" >&5
+echo "${ECHO_T}$USE_NLS" >&6
+
+
+
+
+
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+ ac_executable_p="test -x"
+else
+ ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "msgfmt", so it can be a program name with args.
+set dummy msgfmt; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_MSGFMT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case "$MSGFMT" in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$ac_save_IFS"
+ test -z "$ac_dir" && ac_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+ echo "$as_me: trying $ac_dir/$ac_word..." >&5
+ if $ac_dir/$ac_word --statistics /dev/null >&5 2>&1 &&
+ (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext"
+ break 2
+ fi
+ fi
+ done
+ done
+ IFS="$ac_save_IFS"
+ test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":"
+ ;;
+esac
+fi
+MSGFMT="$ac_cv_path_MSGFMT"
+if test "$MSGFMT" != ":"; then
+ echo "$as_me:$LINENO: result: $MSGFMT" >&5
+echo "${ECHO_T}$MSGFMT" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ # Extract the first word of "gmsgfmt", so it can be a program name with args.
+set dummy gmsgfmt; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_GMSGFMT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $GMSGFMT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT"
+ ;;
+esac
+fi
+GMSGFMT=$ac_cv_path_GMSGFMT
+
+if test -n "$GMSGFMT"; then
+ echo "$as_me:$LINENO: result: $GMSGFMT" >&5
+echo "${ECHO_T}$GMSGFMT" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+ ac_executable_p="test -x"
+else
+ ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "xgettext", so it can be a program name with args.
+set dummy xgettext; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_XGETTEXT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case "$XGETTEXT" in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$ac_save_IFS"
+ test -z "$ac_dir" && ac_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+ echo "$as_me: trying $ac_dir/$ac_word..." >&5
+ if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&5 2>&1 &&
+ (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext"
+ break 2
+ fi
+ fi
+ done
+ done
+ IFS="$ac_save_IFS"
+ test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":"
+ ;;
+esac
+fi
+XGETTEXT="$ac_cv_path_XGETTEXT"
+if test "$XGETTEXT" != ":"; then
+ echo "$as_me:$LINENO: result: $XGETTEXT" >&5
+echo "${ECHO_T}$XGETTEXT" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ rm -f messages.po
+
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+ ac_executable_p="test -x"
+else
+ ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "msgmerge", so it can be a program name with args.
+set dummy msgmerge; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_MSGMERGE+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case "$MSGMERGE" in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$ac_save_IFS"
+ test -z "$ac_dir" && ac_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+ echo "$as_me: trying $ac_dir/$ac_word..." >&5
+ if $ac_dir/$ac_word --update -q /dev/null /dev/null >&5 2>&1; then
+ ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext"
+ break 2
+ fi
+ fi
+ done
+ done
+ IFS="$ac_save_IFS"
+ test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":"
+ ;;
+esac
+fi
+MSGMERGE="$ac_cv_path_MSGMERGE"
+if test "$MSGMERGE" != ":"; then
+ echo "$as_me:$LINENO: result: $MSGMERGE" >&5
+echo "${ECHO_T}$MSGMERGE" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+ if test "$GMSGFMT" != ":"; then
+ if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 &&
+ (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ : ;
+ else
+ GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'`
+ echo "$as_me:$LINENO: result: found $GMSGFMT program is not GNU msgfmt; ignore it" >&5
+echo "${ECHO_T}found $GMSGFMT program is not GNU msgfmt; ignore it" >&6
+ GMSGFMT=":"
+ fi
+ fi
+
+ if test "$XGETTEXT" != ":"; then
+ if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 &&
+ (if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ : ;
+ else
+ echo "$as_me:$LINENO: result: found xgettext program is not GNU xgettext; ignore it" >&5
+echo "${ECHO_T}found xgettext program is not GNU xgettext; ignore it" >&6
+ XGETTEXT=":"
+ fi
+ rm -f messages.po
+ fi
+
+ ac_config_commands="$ac_config_commands default-1"
+
+
+
+ if test "X$prefix" = "XNONE"; then
+ acl_final_prefix="$ac_default_prefix"
+ else
+ acl_final_prefix="$prefix"
+ fi
+ if test "X$exec_prefix" = "XNONE"; then
+ acl_final_exec_prefix='${prefix}'
+ else
+ acl_final_exec_prefix="$exec_prefix"
+ fi
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+ prefix="$acl_save_prefix"
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval="$with_gnu_ld"
+ test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi;
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ echo "$as_me:$LINENO: checking for ld used by GCC" >&5
+echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | [A-Za-z]:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the path of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+ echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${acl_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$LD"; then
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ acl_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break ;;
+ *)
+ test "$with_gnu_ld" != yes && break ;;
+ esac
+ fi
+ done
+ IFS="$ac_save_ifs"
+else
+ acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${acl_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ acl_cv_prog_gnu_ld=yes ;;
+*)
+ acl_cv_prog_gnu_ld=no ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $acl_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$acl_cv_prog_gnu_ld" >&6
+with_gnu_ld=$acl_cv_prog_gnu_ld
+
+
+
+
+ echo "$as_me:$LINENO: checking for shared library run path origin" >&5
+echo $ECHO_N "checking for shared library run path origin... $ECHO_C" >&6
+if test "${acl_cv_rpath+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+ . ./conftest.sh
+ rm -f ./conftest.sh
+ acl_cv_rpath=done
+
+fi
+echo "$as_me:$LINENO: result: $acl_cv_rpath" >&5
+echo "${ECHO_T}$acl_cv_rpath" >&6
+ wl="$acl_cv_wl"
+ libext="$acl_cv_libext"
+ shlibext="$acl_cv_shlibext"
+ hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ hardcode_direct="$acl_cv_hardcode_direct"
+ hardcode_minus_L="$acl_cv_hardcode_minus_L"
+ # Check whether --enable-rpath or --disable-rpath was given.
+if test "${enable_rpath+set}" = set; then
+ enableval="$enable_rpath"
+ :
+else
+ enable_rpath=yes
+fi;
+
+
+ acl_libdirstem=lib
+ searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+ if test -n "$searchpath"; then
+ acl_save_IFS="${IFS= }"; IFS=":"
+ for searchdir in $searchpath; do
+ if test -d "$searchdir"; then
+ case "$searchdir" in
+ */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
+ *) searchdir=`cd "$searchdir" && pwd`
+ case "$searchdir" in
+ */lib64 ) acl_libdirstem=lib64 ;;
+ esac ;;
+ esac
+ fi
+ done
+ IFS="$acl_save_IFS"
+ fi
+
+
+
+
+
+
+
+
+ use_additional=yes
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+
+# Check whether --with-libiconv-prefix or --without-libiconv-prefix was given.
+if test "${with_libiconv_prefix+set}" = set; then
+ withval="$with_libiconv_prefix"
+
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/$acl_libdirstem"
+ fi
+ fi
+
+fi;
+ LIBICONV=
+ LTLIBICONV=
+ INCICONV=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='iconv '
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value"
+ else
+ :
+ fi
+ else
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIBICONV; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so"
+ else
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ if test "$hardcode_direct" = yes; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so"
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ haveit=
+ for x in $LDFLAGS $LIBICONV; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so"
+ else
+ LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a"
+ else
+ LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name"
+ fi
+ fi
+ additional_includedir=
+ case "$found_dir" in
+ */$acl_libdirstem | */$acl_libdirstem/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INCICONV; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -n "$found_la"; then
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIBICONV; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIBICONV; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$dep"
+ LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name"
+ LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$flag"
+ else
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ for found_dir in $ltrpathdirs; do
+ LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir"
+ done
+ fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for CFPreferencesCopyAppValue" >&5
+echo $ECHO_N "checking for CFPreferencesCopyAppValue... $ECHO_C" >&6
+if test "${gt_cv_func_CFPreferencesCopyAppValue+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gt_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers"
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS -framework CoreFoundation"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <CFPreferences.h>
+int
+main ()
+{
+CFPreferencesCopyAppValue(NULL, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_func_CFPreferencesCopyAppValue=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_func_CFPreferencesCopyAppValue=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CPPFLAGS="$gt_save_CPPFLAGS"
+ LIBS="$gt_save_LIBS"
+fi
+echo "$as_me:$LINENO: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5
+echo "${ECHO_T}$gt_cv_func_CFPreferencesCopyAppValue" >&6
+ if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CFPREFERENCESCOPYAPPVALUE 1
+_ACEOF
+
+ fi
+ echo "$as_me:$LINENO: checking for CFLocaleCopyCurrent" >&5
+echo $ECHO_N "checking for CFLocaleCopyCurrent... $ECHO_C" >&6
+if test "${gt_cv_func_CFLocaleCopyCurrent+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gt_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers"
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS -framework CoreFoundation"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <CFLocale.h>
+int
+main ()
+{
+CFLocaleCopyCurrent();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_func_CFLocaleCopyCurrent=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_func_CFLocaleCopyCurrent=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CPPFLAGS="$gt_save_CPPFLAGS"
+ LIBS="$gt_save_LIBS"
+fi
+echo "$as_me:$LINENO: result: $gt_cv_func_CFLocaleCopyCurrent" >&5
+echo "${ECHO_T}$gt_cv_func_CFLocaleCopyCurrent" >&6
+ if test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CFLOCALECOPYCURRENT 1
+_ACEOF
+
+ fi
+ INTL_MACOSX_LIBS=
+ if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+ INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation"
+ fi
+
+
+
+
+ echo "$as_me:$LINENO: checking whether NLS is requested" >&5
+echo $ECHO_N "checking whether NLS is requested... $ECHO_C" >&6
+ # Check whether --enable-nls or --disable-nls was given.
+if test "${enable_nls+set}" = set; then
+ enableval="$enable_nls"
+ USE_NLS=$enableval
+else
+ USE_NLS=yes
+fi;
+ echo "$as_me:$LINENO: result: $USE_NLS" >&5
+echo "${ECHO_T}$USE_NLS" >&6
+
+
+
+
+ LIBINTL=
+ LTLIBINTL=
+ POSUB=
+
+ if test "$USE_NLS" = "yes"; then
+ gt_use_preinstalled_gnugettext=no
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking for GNU gettext in libc" >&5
+echo $ECHO_N "checking for GNU gettext in libc... $ECHO_C" >&6
+if test "${gt_cv_func_gnugettext1_libc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <libintl.h>
+extern int _nl_msg_cat_cntr;
+extern int *_nl_domain_bindings;
+int
+main ()
+{
+bindtextdomain ("", "");
+return * gettext ("") + _nl_msg_cat_cntr + *_nl_domain_bindings
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_func_gnugettext1_libc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_func_gnugettext1_libc=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gt_cv_func_gnugettext1_libc" >&5
+echo "${ECHO_T}$gt_cv_func_gnugettext1_libc" >&6
+
+ if test "$gt_cv_func_gnugettext1_libc" != "yes"; then
+
+
+
+
+
+ am_save_CPPFLAGS="$CPPFLAGS"
+
+ for element in $INCICONV; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+
+ echo "$as_me:$LINENO: checking for iconv" >&5
+echo $ECHO_N "checking for iconv... $ECHO_C" >&6
+if test "${am_cv_func_iconv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ am_cv_func_iconv="no, consider installing GNU libiconv"
+ am_cv_lib_iconv=no
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <iconv.h>
+int
+main ()
+{
+iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ am_cv_func_iconv=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test "$am_cv_func_iconv" != yes; then
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBICONV"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <iconv.h>
+int
+main ()
+{
+iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ am_cv_lib_iconv=yes
+ am_cv_func_iconv=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$am_save_LIBS"
+ fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5
+echo "${ECHO_T}$am_cv_func_iconv" >&6
+ if test "$am_cv_func_iconv" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ICONV 1
+_ACEOF
+
+ fi
+ if test "$am_cv_lib_iconv" = yes; then
+ echo "$as_me:$LINENO: checking how to link with libiconv" >&5
+echo $ECHO_N "checking how to link with libiconv... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: $LIBICONV" >&5
+echo "${ECHO_T}$LIBICONV" >&6
+ else
+ CPPFLAGS="$am_save_CPPFLAGS"
+ LIBICONV=
+ LTLIBICONV=
+ fi
+
+
+
+
+
+
+
+ use_additional=yes
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+
+# Check whether --with-libintl-prefix or --without-libintl-prefix was given.
+if test "${with_libintl_prefix+set}" = set; then
+ withval="$with_libintl_prefix"
+
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/$acl_libdirstem"
+ fi
+ fi
+
+fi;
+ LIBINTL=
+ LTLIBINTL=
+ INCINTL=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='intl '
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIBINTL="${LIBINTL}${LIBINTL:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$value"
+ else
+ :
+ fi
+ else
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIBINTL; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so"
+ else
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ if test "$hardcode_direct" = yes; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so"
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ haveit=
+ for x in $LDFLAGS $LIBINTL; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so"
+ else
+ LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$found_a"
+ else
+ LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir -l$name"
+ fi
+ fi
+ additional_includedir=
+ case "$found_dir" in
+ */$acl_libdirstem | */$acl_libdirstem/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INCINTL; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -n "$found_la"; then
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIBINTL; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIBINTL; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$dep"
+ LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name"
+ LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$flag"
+ else
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ for found_dir in $ltrpathdirs; do
+ LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-R$found_dir"
+ done
+ fi
+
+ echo "$as_me:$LINENO: checking for GNU gettext in libintl" >&5
+echo $ECHO_N "checking for GNU gettext in libintl... $ECHO_C" >&6
+if test "${gt_cv_func_gnugettext1_libintl+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gt_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $INCINTL"
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBINTL"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <libintl.h>
+extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);
+int
+main ()
+{
+bindtextdomain ("", "");
+return * gettext ("") + _nl_msg_cat_cntr + *_nl_expand_alias ("")
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gt_cv_func_gnugettext1_libintl=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gt_cv_func_gnugettext1_libintl=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test "$gt_cv_func_gnugettext1_libintl" != yes && test -n "$LIBICONV"; then
+ LIBS="$LIBS $LIBICONV"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <libintl.h>
+extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);
+int
+main ()
+{
+bindtextdomain ("", "");
+return * gettext ("") + _nl_msg_cat_cntr + *_nl_expand_alias ("")
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ LIBINTL="$LIBINTL $LIBICONV"
+ LTLIBINTL="$LTLIBINTL $LTLIBICONV"
+ gt_cv_func_gnugettext1_libintl=yes
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+ CPPFLAGS="$gt_save_CPPFLAGS"
+ LIBS="$gt_save_LIBS"
+fi
+echo "$as_me:$LINENO: result: $gt_cv_func_gnugettext1_libintl" >&5
+echo "${ECHO_T}$gt_cv_func_gnugettext1_libintl" >&6
+ fi
+
+ if test "$gt_cv_func_gnugettext1_libc" = "yes" \
+ || { test "$gt_cv_func_gnugettext1_libintl" = "yes" \
+ && test "$PACKAGE" != gettext-runtime \
+ && test "$PACKAGE" != gettext-tools; }; then
+ gt_use_preinstalled_gnugettext=yes
+ else
+ LIBINTL=
+ LTLIBINTL=
+ INCINTL=
+ fi
+
+
+
+ if test -n "$INTL_MACOSX_LIBS"; then
+ if test "$gt_use_preinstalled_gnugettext" = "yes" \
+ || test "$nls_cv_use_gnu_gettext" = "yes"; then
+ LIBINTL="$LIBINTL $INTL_MACOSX_LIBS"
+ LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS"
+ fi
+ fi
+
+ if test "$gt_use_preinstalled_gnugettext" = "yes" \
+ || test "$nls_cv_use_gnu_gettext" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_NLS 1
+_ACEOF
+
+ else
+ USE_NLS=no
+ fi
+ fi
+
+ echo "$as_me:$LINENO: checking whether to use NLS" >&5
+echo $ECHO_N "checking whether to use NLS... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: $USE_NLS" >&5
+echo "${ECHO_T}$USE_NLS" >&6
+ if test "$USE_NLS" = "yes"; then
+ echo "$as_me:$LINENO: checking where the gettext function comes from" >&5
+echo $ECHO_N "checking where the gettext function comes from... $ECHO_C" >&6
+ if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+ if test "$gt_cv_func_gnugettext1_libintl" = "yes"; then
+ gt_source="external libintl"
+ else
+ gt_source="libc"
+ fi
+ else
+ gt_source="included intl directory"
+ fi
+ echo "$as_me:$LINENO: result: $gt_source" >&5
+echo "${ECHO_T}$gt_source" >&6
+ fi
+
+ if test "$USE_NLS" = "yes"; then
+
+ if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+ if test "$gt_cv_func_gnugettext1_libintl" = "yes"; then
+ echo "$as_me:$LINENO: checking how to link with libintl" >&5
+echo $ECHO_N "checking how to link with libintl... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: $LIBINTL" >&5
+echo "${ECHO_T}$LIBINTL" >&6
+
+ for element in $INCINTL; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+ fi
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETTEXT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DCGETTEXT 1
+_ACEOF
+
+ fi
+
+ POSUB=po
+ fi
+
+
+
+ INTLLIBS="$LIBINTL"
+
+
+
+
+
+
+ # The error module still poses merge problems.
+echo "$as_me:$LINENO: checking whether strerror_r is declared" >&5
+echo $ECHO_N "checking whether strerror_r is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_strerror_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef strerror_r
+ char *p = (char *) strerror_r;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_strerror_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_strerror_r=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_strerror_r" >&5
+echo "${ECHO_T}$ac_cv_have_decl_strerror_r" >&6
+if test $ac_cv_have_decl_strerror_r = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRERROR_R 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRERROR_R 0
+_ACEOF
+
+
+fi
+
+
+
+for ac_func in strerror_r
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+echo "$as_me:$LINENO: checking whether strerror_r returns char *" >&5
+echo $ECHO_N "checking whether strerror_r returns char *... $ECHO_C" >&6
+if test "${ac_cv_func_strerror_r_char_p+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ ac_cv_func_strerror_r_char_p=no
+ if test $ac_cv_have_decl_strerror_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ char buf[100];
+ char x = *strerror_r (0, buf, sizeof buf);
+ char *p = strerror_r (0, buf, sizeof buf);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strerror_r_char_p=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ else
+ # strerror_r is not declared. Choose between
+ # systems that have relatively inaccessible declarations for the
+ # function. BeOS and DEC UNIX 4.0 fall in this category, but the
+ # former has a strerror_r that returns char*, while the latter
+ # has a strerror_r that returns `int'.
+ # This test should segfault on the DEC system.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+ extern char *strerror_r ();
+int
+main ()
+{
+char buf[100];
+ char x = *strerror_r (0, buf, sizeof buf);
+ exit (!isalpha (x));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strerror_r_char_p=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ fi
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strerror_r_char_p" >&5
+echo "${ECHO_T}$ac_cv_func_strerror_r_char_p" >&6
+if test $ac_cv_func_strerror_r_char_p = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STRERROR_R_CHAR_P 1
+_ACEOF
+
+fi
+
+
+
+
+
+ if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+
+ test $ac_cv_type_long_long = yes \
+ && ac_type='long long' \
+ || ac_type='long'
+
+cat >>confdefs.h <<_ACEOF
+#define intmax_t $ac_type
+_ACEOF
+
+ else
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTMAX_T 1
+_ACEOF
+
+ fi
+
+
+
+
+
+
+
+ GLOB_H=
+
+for ac_header in glob.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ GLOB_H=glob.h
+fi
+
+done
+
+
+ if test -z "$GLOB_H"; then
+ echo "$as_me:$LINENO: checking for GNU glob interface version 1" >&5
+echo $ECHO_N "checking for GNU glob interface version 1... $ECHO_C" >&6
+if test "${gl_cv_gnu_glob_interface_version_1+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#include <gnu-versions.h>
+char a[_GNU_GLOB_INTERFACE_VERSION == 1 ? 1 : -1];
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_gnu_glob_interface_version_1=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gl_cv_gnu_glob_interface_version_1=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gl_cv_gnu_glob_interface_version_1" >&5
+echo "${ECHO_T}$gl_cv_gnu_glob_interface_version_1" >&6
+
+ if test "$gl_cv_gnu_glob_interface_version_1" = "no"; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ if test -z "$GLOB_H"; then
+ echo "$as_me:$LINENO: checking whether glob lists broken symlinks" >&5
+echo $ECHO_N "checking whether glob lists broken symlinks... $ECHO_C" >&6
+if test "${gl_cv_glob_lists_symlinks+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if ln -s conf-doesntexist conf$$-globtest 2>/dev/null; then
+ gl_cv_glob_lists_symlinks=maybe
+ else
+ # If we can't make a symlink, then we cannot test this issue. Be
+ # pessimistic about this.
+ gl_cv_glob_lists_symlinks=no
+ fi
+
+ if test $gl_cv_glob_lists_symlinks = maybe; then
+ if test "$cross_compiling" = yes; then
+ gl_cv_glob_lists_symlinks=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stddef.h>
+#include <glob.h>
+int
+main ()
+{
+glob_t found;
+if (glob ("conf*-globtest", 0, NULL, &found) == GLOB_NOMATCH) return 1;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gl_cv_glob_lists_symlinks=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gl_cv_glob_lists_symlinks=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ fi
+fi
+echo "$as_me:$LINENO: result: $gl_cv_glob_lists_symlinks" >&5
+echo "${ECHO_T}$gl_cv_glob_lists_symlinks" >&6
+
+ if test $gl_cv_glob_lists_symlinks = no; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ rm -f conf$$-globtest
+
+ if test -n "$GLOB_H"; then
+
+
+ :
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+ :
+
+ GLOB_H=glob.h
+
+ case $LIBOBJS in
+ "glob.$ac_objext" | \
+ *" glob.$ac_objext" | \
+ "glob.$ac_objext "* | \
+ *" glob.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS glob.$ac_objext" ;;
+esac
+
+
+
+ fi
+
+
+#
+# End GNULIB stuff.
+#
+
+
+
+# Check for function existance.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in \
+ fchdir \
+ fchmod \
+ fsync \
+ ftime \
+ geteuid \
+ getgroups \
+ getpagesize \
+ gettimeofday \
+ initgroups \
+ login \
+ logout \
+ mknod \
+ regcomp \
+ regerror \
+ regexec \
+ regfree \
+ sigaction \
+ sigblock \
+ sigprocmask \
+ sigsetmask \
+ sigvec \
+ timezone \
+ tzset \
+ vprintf \
+ wait3 \
+
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+if test $cross_compiling = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define CROSS_COMPILING 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: checking for char" >&5
+echo $ECHO_N "checking for char... $ECHO_C" >&6
+if test "${ac_cv_type_char+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((char *) 0)
+ return 0;
+if (sizeof (char))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_char=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_char=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_char" >&5
+echo "${ECHO_T}$ac_cv_type_char" >&6
+
+echo "$as_me:$LINENO: checking size of char" >&5
+echo $ECHO_N "checking size of char... $ECHO_C" >&6
+if test "${ac_cv_sizeof_char+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_char" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (char))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (char))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (char))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (char))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (char))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_char=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (char), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (char), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (char)); }
+unsigned long ulongval () { return (long) (sizeof (char)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (char))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (char))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (char))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_char=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (char), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (char), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_char=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_char" >&5
+echo "${ECHO_T}$ac_cv_sizeof_char" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_CHAR $ac_cv_sizeof_char
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized char" >&5
+echo $ECHO_N "checking for uniquely sized char... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_char+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_char)" >/dev/null ; then
+ ccvs_cv_unique_int_type_char=no
+ else
+ ccvs_cv_unique_int_type_char=yes\($ac_cv_sizeof_char\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_char" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_char" >&6
+ if test $ccvs_cv_unique_int_type_char != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_CHAR 1
+_ACEOF
+
+ fi
+ echo "$as_me:$LINENO: checking for short" >&5
+echo $ECHO_N "checking for short... $ECHO_C" >&6
+if test "${ac_cv_type_short+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((short *) 0)
+ return 0;
+if (sizeof (short))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_short=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_short=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5
+echo "${ECHO_T}$ac_cv_type_short" >&6
+
+echo "$as_me:$LINENO: checking size of short" >&5
+echo $ECHO_N "checking size of short... $ECHO_C" >&6
+if test "${ac_cv_sizeof_short+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_short" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_short=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (short)); }
+unsigned long ulongval () { return (long) (sizeof (short)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (short))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (short))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (short))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_short=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_short=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5
+echo "${ECHO_T}$ac_cv_sizeof_short" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SHORT $ac_cv_sizeof_short
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized short" >&5
+echo $ECHO_N "checking for uniquely sized short... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_short+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_short)" >/dev/null ; then
+ ccvs_cv_unique_int_type_short=no
+ else
+ ccvs_cv_unique_int_type_short=yes\($ac_cv_sizeof_short\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_short" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_short" >&6
+ if test $ccvs_cv_unique_int_type_short != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_SHORT 1
+_ACEOF
+
+ fi
+ echo "$as_me:$LINENO: checking for int" >&5
+echo $ECHO_N "checking for int... $ECHO_C" >&6
+if test "${ac_cv_type_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((int *) 0)
+ return 0;
+if (sizeof (int))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_int=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5
+echo "${ECHO_T}$ac_cv_type_int" >&6
+
+echo "$as_me:$LINENO: checking size of int" >&5
+echo $ECHO_N "checking size of int... $ECHO_C" >&6
+if test "${ac_cv_sizeof_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_int" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (int)); }
+unsigned long ulongval () { return (long) (sizeof (int)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (int))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (int))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (int))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_int=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_int=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized int" >&5
+echo $ECHO_N "checking for uniquely sized int... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_int)" >/dev/null ; then
+ ccvs_cv_unique_int_type_int=no
+ else
+ ccvs_cv_unique_int_type_int=yes\($ac_cv_sizeof_int\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_int" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_int" >&6
+ if test $ccvs_cv_unique_int_type_int != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_INT 1
+_ACEOF
+
+ fi
+ echo "$as_me:$LINENO: checking for long" >&5
+echo $ECHO_N "checking for long... $ECHO_C" >&6
+if test "${ac_cv_type_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((long *) 0)
+ return 0;
+if (sizeof (long))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_long=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_long=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5
+echo "${ECHO_T}$ac_cv_type_long" >&6
+
+echo "$as_me:$LINENO: checking size of long" >&5
+echo $ECHO_N "checking size of long... $ECHO_C" >&6
+if test "${ac_cv_sizeof_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_long" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (long)); }
+unsigned long ulongval () { return (long) (sizeof (long)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (long))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (long))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (long))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_long=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_long=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized long" >&5
+echo $ECHO_N "checking for uniquely sized long... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_long)" >/dev/null ; then
+ ccvs_cv_unique_int_type_long=no
+ else
+ ccvs_cv_unique_int_type_long=yes\($ac_cv_sizeof_long\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_long" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_long" >&6
+ if test $ccvs_cv_unique_int_type_long != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_LONG 1
+_ACEOF
+
+ fi
+ if test $ac_cv_type_long_long != no; then
+ echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6
+if test "${ac_cv_type_long_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((long long *) 0)
+ return 0;
+if (sizeof (long long))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_long_long=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_long_long=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6
+
+echo "$as_me:$LINENO: checking size of long long" >&5
+echo $ECHO_N "checking size of long long... $ECHO_C" >&6
+if test "${ac_cv_sizeof_long_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_long_long" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_long=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (long long)); }
+unsigned long ulongval () { return (long) (sizeof (long long)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (long long))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (long long))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (long long))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_long_long=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_long_long=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized long long" >&5
+echo $ECHO_N "checking for uniquely sized long long... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_long_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_long_long)" >/dev/null ; then
+ ccvs_cv_unique_int_type_long_long=no
+ else
+ ccvs_cv_unique_int_type_long_long=yes\($ac_cv_sizeof_long_long\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_long_long" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_long_long" >&6
+ if test $ccvs_cv_unique_int_type_long_long != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_LONG_LONG 1
+_ACEOF
+
+ fi
+ fi
+ echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_size_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+
+echo "$as_me:$LINENO: checking size of size_t" >&5
+echo $ECHO_N "checking size of size_t... $ECHO_C" >&6
+if test "${ac_cv_sizeof_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_size_t" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (size_t))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (size_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (size_t))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (size_t))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (size_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_size_t=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (size_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (size_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (size_t)); }
+unsigned long ulongval () { return (long) (sizeof (size_t)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (size_t))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (size_t))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (size_t))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_size_t=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (size_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (size_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_size_t=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_size_t" >&5
+echo "${ECHO_T}$ac_cv_sizeof_size_t" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized size_t" >&5
+echo $ECHO_N "checking for uniquely sized size_t... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_size_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_size_t=no
+ else
+ ccvs_cv_unique_int_type_size_t=yes\($ac_cv_sizeof_size_t\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_size_t" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_size_t" >&6
+ if test $ccvs_cv_unique_int_type_size_t != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_SIZE_T 1
+_ACEOF
+
+ fi
+ echo "$as_me:$LINENO: checking for ptrdiff_t" >&5
+echo $ECHO_N "checking for ptrdiff_t... $ECHO_C" >&6
+if test "${ac_cv_type_ptrdiff_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((ptrdiff_t *) 0)
+ return 0;
+if (sizeof (ptrdiff_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_ptrdiff_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_ptrdiff_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_ptrdiff_t" >&5
+echo "${ECHO_T}$ac_cv_type_ptrdiff_t" >&6
+
+echo "$as_me:$LINENO: checking size of ptrdiff_t" >&5
+echo $ECHO_N "checking size of ptrdiff_t... $ECHO_C" >&6
+if test "${ac_cv_sizeof_ptrdiff_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_ptrdiff_t" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (ptrdiff_t))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (ptrdiff_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (ptrdiff_t))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (ptrdiff_t))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (ptrdiff_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_ptrdiff_t=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (ptrdiff_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (ptrdiff_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (ptrdiff_t)); }
+unsigned long ulongval () { return (long) (sizeof (ptrdiff_t)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (ptrdiff_t))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (ptrdiff_t))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (ptrdiff_t))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_ptrdiff_t=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (ptrdiff_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (ptrdiff_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_ptrdiff_t=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_ptrdiff_t" >&5
+echo "${ECHO_T}$ac_cv_sizeof_ptrdiff_t" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_PTRDIFF_T $ac_cv_sizeof_ptrdiff_t
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized ptrdiff_t" >&5
+echo $ECHO_N "checking for uniquely sized ptrdiff_t... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_ptrdiff_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_ptrdiff_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_ptrdiff_t=no
+ else
+ ccvs_cv_unique_int_type_ptrdiff_t=yes\($ac_cv_sizeof_ptrdiff_t\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_ptrdiff_t" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_ptrdiff_t" >&6
+ if test $ccvs_cv_unique_int_type_ptrdiff_t != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_PTRDIFF_T 1
+_ACEOF
+
+ fi
+ if test $gt_cv_c_wint_t != no; then
+ echo "$as_me:$LINENO: checking for wint_t" >&5
+echo $ECHO_N "checking for wint_t... $ECHO_C" >&6
+if test "${ac_cv_type_wint_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#include <wchar.h>
+
+
+int
+main ()
+{
+if ((wint_t *) 0)
+ return 0;
+if (sizeof (wint_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_wint_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_wint_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_wint_t" >&5
+echo "${ECHO_T}$ac_cv_type_wint_t" >&6
+
+echo "$as_me:$LINENO: checking size of wint_t" >&5
+echo $ECHO_N "checking size of wint_t... $ECHO_C" >&6
+if test "${ac_cv_sizeof_wint_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_wint_t" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#include <wchar.h>
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (wint_t))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#include <wchar.h>
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (wint_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#include <wchar.h>
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (wint_t))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#include <wchar.h>
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (wint_t))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#include <wchar.h>
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (wint_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_wint_t=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (wint_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (wint_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#include <wchar.h>
+
+
+long longval () { return (long) (sizeof (wint_t)); }
+unsigned long ulongval () { return (long) (sizeof (wint_t)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (wint_t))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (wint_t))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (wint_t))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_wint_t=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (wint_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (wint_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_wint_t=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_wint_t" >&5
+echo "${ECHO_T}$ac_cv_sizeof_wint_t" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_WINT_T $ac_cv_sizeof_wint_t
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized wint_t" >&5
+echo $ECHO_N "checking for uniquely sized wint_t... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_wint_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_wint_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_wint_t=no
+ else
+ ccvs_cv_unique_int_type_wint_t=yes\($ac_cv_sizeof_wint_t\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_wint_t" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_wint_t" >&6
+ if test $ccvs_cv_unique_int_type_wint_t != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_WINT_T 1
+_ACEOF
+
+ fi
+ fi
+ if test $gt_cv_c_intmax_t != no; then
+ echo "$as_me:$LINENO: checking for intmax_t" >&5
+echo $ECHO_N "checking for intmax_t... $ECHO_C" >&6
+if test "${ac_cv_type_intmax_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+
+int
+main ()
+{
+if ((intmax_t *) 0)
+ return 0;
+if (sizeof (intmax_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_intmax_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_intmax_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_intmax_t" >&5
+echo "${ECHO_T}$ac_cv_type_intmax_t" >&6
+
+echo "$as_me:$LINENO: checking size of intmax_t" >&5
+echo $ECHO_N "checking size of intmax_t... $ECHO_C" >&6
+if test "${ac_cv_sizeof_intmax_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_intmax_t" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (intmax_t))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (intmax_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (intmax_t))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (intmax_t))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (intmax_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_intmax_t=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (intmax_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (intmax_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+
+long longval () { return (long) (sizeof (intmax_t)); }
+unsigned long ulongval () { return (long) (sizeof (intmax_t)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (intmax_t))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (intmax_t))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (intmax_t))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_intmax_t=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (intmax_t), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (intmax_t), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_intmax_t=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_intmax_t" >&5
+echo "${ECHO_T}$ac_cv_sizeof_intmax_t" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INTMAX_T $ac_cv_sizeof_intmax_t
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized intmax_t" >&5
+echo $ECHO_N "checking for uniquely sized intmax_t... $ECHO_C" >&6
+if test "${ccvs_cv_unique_int_type_intmax_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_intmax_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_intmax_t=no
+ else
+ ccvs_cv_unique_int_type_intmax_t=yes\($ac_cv_sizeof_intmax_t\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_int_type_intmax_t" >&5
+echo "${ECHO_T}$ccvs_cv_unique_int_type_intmax_t" >&6
+ if test $ccvs_cv_unique_int_type_intmax_t != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_INT_TYPE_INTMAX_T 1
+_ACEOF
+
+ fi
+ fi
+
+ echo "$as_me:$LINENO: checking for float" >&5
+echo $ECHO_N "checking for float... $ECHO_C" >&6
+if test "${ac_cv_type_float+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((float *) 0)
+ return 0;
+if (sizeof (float))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_float=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_float=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_float" >&5
+echo "${ECHO_T}$ac_cv_type_float" >&6
+
+echo "$as_me:$LINENO: checking size of float" >&5
+echo $ECHO_N "checking size of float... $ECHO_C" >&6
+if test "${ac_cv_sizeof_float+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_float" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (float))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (float))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (float))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (float))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (float))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_float=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (float), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (float), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (float)); }
+unsigned long ulongval () { return (long) (sizeof (float)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (float))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (float))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (float))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_float=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (float), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (float), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_float=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_float" >&5
+echo "${ECHO_T}$ac_cv_sizeof_float" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_FLOAT $ac_cv_sizeof_float
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized float" >&5
+echo $ECHO_N "checking for uniquely sized float... $ECHO_C" >&6
+if test "${ccvs_cv_unique_float_type_float+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_float_type_ \
+ |grep "($ac_cv_sizeof_float)" >/dev/null ; then
+ ccvs_cv_unique_float_type_float=no
+ else
+ ccvs_cv_unique_float_type_float=yes\($ac_cv_sizeof_float\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_float_type_float" >&5
+echo "${ECHO_T}$ccvs_cv_unique_float_type_float" >&6
+ if test $ccvs_cv_unique_float_type_float != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_FLOAT_TYPE_FLOAT 1
+_ACEOF
+
+ fi
+ echo "$as_me:$LINENO: checking for double" >&5
+echo $ECHO_N "checking for double... $ECHO_C" >&6
+if test "${ac_cv_type_double+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((double *) 0)
+ return 0;
+if (sizeof (double))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_double=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_double=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_double" >&5
+echo "${ECHO_T}$ac_cv_type_double" >&6
+
+echo "$as_me:$LINENO: checking size of double" >&5
+echo $ECHO_N "checking size of double... $ECHO_C" >&6
+if test "${ac_cv_sizeof_double+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_double" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (double))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (double))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (double))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (double))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (double))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_double=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (double), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (double), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (double)); }
+unsigned long ulongval () { return (long) (sizeof (double)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (double))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (double))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (double))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_double=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (double), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (double), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_double=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_double" >&5
+echo "${ECHO_T}$ac_cv_sizeof_double" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_DOUBLE $ac_cv_sizeof_double
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized double" >&5
+echo $ECHO_N "checking for uniquely sized double... $ECHO_C" >&6
+if test "${ccvs_cv_unique_float_type_double+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_float_type_ \
+ |grep "($ac_cv_sizeof_double)" >/dev/null ; then
+ ccvs_cv_unique_float_type_double=no
+ else
+ ccvs_cv_unique_float_type_double=yes\($ac_cv_sizeof_double\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_float_type_double" >&5
+echo "${ECHO_T}$ccvs_cv_unique_float_type_double" >&6
+ if test $ccvs_cv_unique_float_type_double != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_FLOAT_TYPE_DOUBLE 1
+_ACEOF
+
+ fi
+ if test $gt_cv_c_long_double != no; then
+ echo "$as_me:$LINENO: checking for long double" >&5
+echo $ECHO_N "checking for long double... $ECHO_C" >&6
+if test "${ac_cv_type_long_double+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((long double *) 0)
+ return 0;
+if (sizeof (long double))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_long_double=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_long_double=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_long_double" >&5
+echo "${ECHO_T}$ac_cv_type_long_double" >&6
+
+echo "$as_me:$LINENO: checking size of long double" >&5
+echo $ECHO_N "checking size of long double... $ECHO_C" >&6
+if test "${ac_cv_sizeof_long_double+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$ac_cv_type_long_double" = yes; then
+ # The cast to unsigned long works around a bug in the HP C Compiler
+ # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+ # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+ # This bug is HP SR number 8606223364.
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long double))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long double))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long double))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long double))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_lo=$ac_mid; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long double))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_hi=$ac_mid
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_double=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long double), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long double), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+long longval () { return (long) (sizeof (long double)); }
+unsigned long ulongval () { return (long) (sizeof (long double)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ exit (1);
+ if (((long) (sizeof (long double))) < 0)
+ {
+ long i = longval ();
+ if (i != ((long) (sizeof (long double))))
+ exit (1);
+ fprintf (f, "%ld\n", i);
+ }
+ else
+ {
+ unsigned long i = ulongval ();
+ if (i != ((long) (sizeof (long double))))
+ exit (1);
+ fprintf (f, "%lu\n", i);
+ }
+ exit (ferror (f) || fclose (f) != 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_long_double=`cat conftest.val`
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long double), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long double), 77
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+ ac_cv_sizeof_long_double=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_double" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long_double" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for uniquely sized long double" >&5
+echo $ECHO_N "checking for uniquely sized long double... $ECHO_C" >&6
+if test "${ccvs_cv_unique_float_type_long_double+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if set |grep ^ccvs_cv_unique_float_type_ \
+ |grep "($ac_cv_sizeof_long_double)" >/dev/null ; then
+ ccvs_cv_unique_float_type_long_double=no
+ else
+ ccvs_cv_unique_float_type_long_double=yes\($ac_cv_sizeof_long_double\)
+ fi
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_unique_float_type_long_double" >&5
+echo "${ECHO_T}$ccvs_cv_unique_float_type_long_double" >&6
+ if test $ccvs_cv_unique_float_type_long_double != no ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIQUE_FLOAT_TYPE_LONG_DOUBLE 1
+_ACEOF
+
+ fi
+ fi
+fi
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRCHR 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MEMCHR 1
+_ACEOF
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define REGEX_MALLOC 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _REGEX_RE_COMP 1
+_ACEOF
+
+
+
+for ac_header in unistd.h vfork.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_func in fork vfork
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+if test "x$ac_cv_func_fork" = xyes; then
+ echo "$as_me:$LINENO: checking for working fork" >&5
+echo $ECHO_N "checking for working fork... $ECHO_C" >&6
+if test "${ac_cv_func_fork_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_fork_works=cross
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* By Ruediger Kuhlmann. */
+ #include <sys/types.h>
+ #if HAVE_UNISTD_H
+ # include <unistd.h>
+ #endif
+ /* Some systems only have a dummy stub for fork() */
+ int main ()
+ {
+ if (fork() < 0)
+ exit (1);
+ exit (0);
+ }
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_fork_works=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_fork_works=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_fork_works" >&5
+echo "${ECHO_T}$ac_cv_func_fork_works" >&6
+
+else
+ ac_cv_func_fork_works=$ac_cv_func_fork
+fi
+if test "x$ac_cv_func_fork_works" = xcross; then
+ case $host in
+ *-*-amigaos* | *-*-msdosdjgpp*)
+ # Override, as these systems have only a dummy fork() stub
+ ac_cv_func_fork_works=no
+ ;;
+ *)
+ ac_cv_func_fork_works=yes
+ ;;
+ esac
+ { echo "$as_me:$LINENO: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5
+echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;}
+fi
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+if test "x$ac_cv_func_vfork" = xyes; then
+ echo "$as_me:$LINENO: checking for working vfork" >&5
+echo $ECHO_N "checking for working vfork... $ECHO_C" >&6
+if test "${ac_cv_func_vfork_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_vfork_works=cross
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if HAVE_VFORK_H
+# include <vfork.h>
+#endif
+/* On some sparc systems, changes by the child to local and incoming
+ argument registers are propagated back to the parent. The compiler
+ is told about this with #include <vfork.h>, but some compilers
+ (e.g. gcc -O) don't grok <vfork.h>. Test for this by using a
+ static variable whose address is put into a register that is
+ clobbered by the vfork. */
+static void
+#ifdef __cplusplus
+sparc_address_test (int arg)
+# else
+sparc_address_test (arg) int arg;
+#endif
+{
+ static pid_t child;
+ if (!child) {
+ child = vfork ();
+ if (child < 0) {
+ perror ("vfork");
+ _exit(2);
+ }
+ if (!child) {
+ arg = getpid();
+ write(-1, "", 0);
+ _exit (arg);
+ }
+ }
+}
+
+int
+main ()
+{
+ pid_t parent = getpid ();
+ pid_t child;
+
+ sparc_address_test (0);
+
+ child = vfork ();
+
+ if (child == 0) {
+ /* Here is another test for sparc vfork register problems. This
+ test uses lots of local variables, at least as many local
+ variables as main has allocated so far including compiler
+ temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris
+ 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should
+ reuse the register of parent for one of the local variables,
+ since it will think that parent can't possibly be used any more
+ in this routine. Assigning to the local variable will thus
+ munge parent in the parent process. */
+ pid_t
+ p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+ p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+ /* Convince the compiler that p..p7 are live; otherwise, it might
+ use the same hardware register for all 8 local variables. */
+ if (p != p1 || p != p2 || p != p3 || p != p4
+ || p != p5 || p != p6 || p != p7)
+ _exit(1);
+
+ /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent
+ from child file descriptors. If the child closes a descriptor
+ before it execs or exits, this munges the parent's descriptor
+ as well. Test for this by closing stdout in the child. */
+ _exit(close(fileno(stdout)) != 0);
+ } else {
+ int status;
+ struct stat st;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+
+ /* Did the vfork/compiler bug occur? */
+ || parent != getpid()
+
+ /* Did the file descriptor bug occur? */
+ || fstat(fileno(stdout), &st) != 0
+ );
+ }
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_vfork_works=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_vfork_works=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_vfork_works" >&5
+echo "${ECHO_T}$ac_cv_func_vfork_works" >&6
+
+fi;
+if test "x$ac_cv_func_fork_works" = xcross; then
+ ac_cv_func_vfork_works=$ac_cv_func_vfork
+ { echo "$as_me:$LINENO: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5
+echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;}
+fi
+
+if test "x$ac_cv_func_vfork_works" = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WORKING_VFORK 1
+_ACEOF
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define vfork fork
+_ACEOF
+
+fi
+if test "x$ac_cv_func_fork_works" = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WORKING_FORK 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether closedir returns void" >&5
+echo $ECHO_N "checking whether closedir returns void... $ECHO_C" >&6
+if test "${ac_cv_func_closedir_void+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_closedir_void=yes
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header_dirent>
+#ifndef __cplusplus
+int closedir ();
+#endif
+
+int
+main ()
+{
+exit (closedir (opendir (".")) != 0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_closedir_void=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_closedir_void=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_closedir_void" >&5
+echo "${ECHO_T}$ac_cv_func_closedir_void" >&6
+if test $ac_cv_func_closedir_void = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define CLOSEDIR_VOID 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for library containing getspnam" >&5
+echo $ECHO_N "checking for library containing getspnam... $ECHO_C" >&6
+if test "${ac_cv_search_getspnam+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_getspnam=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getspnam ();
+int
+main ()
+{
+getspnam ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getspnam="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_getspnam" = no; then
+ for ac_lib in sec gen; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getspnam ();
+int
+main ()
+{
+getspnam ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getspnam="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_getspnam" >&5
+echo "${ECHO_T}$ac_cv_search_getspnam" >&6
+if test "$ac_cv_search_getspnam" != no; then
+ test "$ac_cv_search_getspnam" = "none required" || LIBS="$ac_cv_search_getspnam $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETSPNAM 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether utime accepts a null argument" >&5
+echo $ECHO_N "checking whether utime accepts a null argument... $ECHO_C" >&6
+if test "${ac_cv_func_utime_null+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ rm -f conftest.data; >conftest.data
+# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong.
+if test "$cross_compiling" = yes; then
+ ac_cv_func_utime_null=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+struct stat s, t;
+ exit (!(stat ("conftest.data", &s) == 0
+ && utime ("conftest.data", (long *)0) == 0
+ && stat ("conftest.data", &t) == 0
+ && t.st_mtime >= s.st_mtime
+ && t.st_mtime - s.st_mtime < 120));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_utime_null=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_utime_null=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core *.core
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_utime_null" >&5
+echo "${ECHO_T}$ac_cv_func_utime_null" >&6
+if test $ac_cv_func_utime_null = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_UTIME_NULL 1
+_ACEOF
+
+fi
+rm -f conftest.data
+
+echo "$as_me:$LINENO: checking for long file names" >&5
+echo $ECHO_N "checking for long file names... $ECHO_C" >&6
+if test "${ac_cv_sys_long_file_names+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_sys_long_file_names=yes
+# Test for long file names in all the places we know might matter:
+# . the current directory, where building will happen
+# $prefix/lib where we will be installing things
+# $exec_prefix/lib likewise
+# eval it to expand exec_prefix.
+# $TMPDIR if set, where it might want to write temporary files
+# if $TMPDIR is not set:
+# /tmp where it might want to write temporary files
+# /var/tmp likewise
+# /usr/tmp likewise
+if test -n "$TMPDIR" && test -d "$TMPDIR" && test -w "$TMPDIR"; then
+ ac_tmpdirs=$TMPDIR
+else
+ ac_tmpdirs='/tmp /var/tmp /usr/tmp'
+fi
+for ac_dir in . $ac_tmpdirs `eval echo $prefix/lib $exec_prefix/lib` ; do
+ test -d $ac_dir || continue
+ test -w $ac_dir || continue # It is less confusing to not echo anything here.
+ ac_xdir=$ac_dir/cf$$
+ (umask 077 && mkdir $ac_xdir 2>/dev/null) || continue
+ ac_tf1=$ac_xdir/conftest9012345
+ ac_tf2=$ac_xdir/conftest9012346
+ (echo 1 >$ac_tf1) 2>/dev/null
+ (echo 2 >$ac_tf2) 2>/dev/null
+ ac_val=`cat $ac_tf1 2>/dev/null`
+ if test ! -f $ac_tf1 || test "$ac_val" != 1; then
+ ac_cv_sys_long_file_names=no
+ rm -rf $ac_xdir 2>/dev/null
+ break
+ fi
+ rm -rf $ac_xdir 2>/dev/null
+done
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_long_file_names" >&5
+echo "${ECHO_T}$ac_cv_sys_long_file_names" >&6
+if test $ac_cv_sys_long_file_names = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LONG_FILE_NAMES 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether printf supports %p" >&5
+echo $ECHO_N "checking whether printf supports %p... $ECHO_C" >&6
+if test "${cvs_cv_func_printf_ptr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+/* If printf supports %p, exit 0. */
+int
+main ()
+{
+ void *p1, *p2;
+ char buf[256];
+ p1 = &p1; p2 = &p2;
+ sprintf(buf, "%p", p1);
+ exit(sscanf(buf, "%p", &p2) != 1 || p2 != p1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cvs_cv_func_printf_ptr=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+cvs_cv_func_printf_ptr=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core core.* *.core
+fi
+echo "$as_me:$LINENO: result: $cvs_cv_func_printf_ptr" >&5
+echo "${ECHO_T}$cvs_cv_func_printf_ptr" >&6
+if test $cvs_cv_func_printf_ptr = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PRINTF_PTR 1
+_ACEOF
+
+fi
+
+
+# Try to find connect and gethostbyname.
+
+echo "$as_me:$LINENO: checking for main in -lnsl" >&5
+echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_nsl_main=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6
+if test $ac_cv_lib_nsl_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing connect" >&5
+echo $ECHO_N "checking for library containing connect... $ECHO_C" >&6
+if test "${ac_cv_search_connect+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_connect=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect ();
+int
+main ()
+{
+connect ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_connect="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_connect" = no; then
+ for ac_lib in xnet socket inet; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect ();
+int
+main ()
+{
+connect ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_connect="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_connect" >&5
+echo "${ECHO_T}$ac_cv_search_connect" >&6
+if test "$ac_cv_search_connect" != no; then
+ test "$ac_cv_search_connect" = "none required" || LIBS="$ac_cv_search_connect $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CONNECT 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing gethostbyname" >&5
+echo $ECHO_N "checking for library containing gethostbyname... $ECHO_C" >&6
+if test "${ac_cv_search_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_gethostbyname=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_gethostbyname" = no; then
+ for ac_lib in netinet; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_search_gethostbyname" >&6
+if test "$ac_cv_search_gethostbyname" != no; then
+ test "$ac_cv_search_gethostbyname" = "none required" || LIBS="$ac_cv_search_gethostbyname $LIBS"
+
+fi
+
+
+
+
+
+
+KRB4=/usr/kerberos
+
+
+# Check whether --with-krb4 or --without-krb4 was given.
+if test "${with_krb4+set}" = set; then
+ withval="$with_krb4"
+ KRB4=$with_krb4
+fi; echo "$as_me:$LINENO: checking for KRB4 in $KRB4" >&5
+echo $ECHO_N "checking for KRB4 in $KRB4... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: " >&5
+echo "${ECHO_T}" >&6
+
+
+krb_h=
+echo "$as_me:$LINENO: checking for krb.h" >&5
+echo $ECHO_N "checking for krb.h... $ECHO_C" >&6
+if test "$cross_compiling" != yes && test -r $KRB4/include/krb.h; then
+ hold_cflags=$CFLAGS
+ CFLAGS="$CFLAGS -I$KRB4/include"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <krb.h>
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ krb_h=yes krb_incdir=$KRB4/include
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+CFLAGS=$hold_cflags
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <krb.h>
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ krb_h=yes krb_incdir=
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$hold_cflags
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <krb.h>
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ krb_h=yes krb_incdir=
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+if test -z "$krb_h"; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <krb.h>
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ krb_h=yes krb_incdir=
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+if test "$cross_compiling" != yes && test -r $KRB4/include/kerberosIV/krb.h; then
+ hold_cflags=$CFLAGS
+ CFLAGS="$CFLAGS -I$KRB4/include/kerberosIV"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <krb.h>
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ krb_h=yes krb_incdir=$KRB4/include/kerberosIV
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$hold_cflags
+ fi
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $krb_h" >&5
+echo "${ECHO_T}$krb_h" >&6
+
+if test -n "$krb_h"; then
+ krb_lib=
+ if test "$cross_compiling" != yes && test -r $KRB4/lib/libkrb.a; then
+ hold_ldflags=$LDFLAGS
+ LDFLAGS="-L${KRB4}/lib $LDFLAGS"
+ echo "$as_me:$LINENO: checking for printf in -lkrb" >&5
+echo $ECHO_N "checking for printf in -lkrb... $ECHO_C" >&6
+if test "${ac_cv_lib_krb_printf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkrb $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char printf ();
+int
+main ()
+{
+printf ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_krb_printf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_krb_printf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_krb_printf" >&5
+echo "${ECHO_T}$ac_cv_lib_krb_printf" >&6
+if test $ac_cv_lib_krb_printf = yes; then
+ krb_lib=yes krb_libdir=${KRB4}/lib
+else
+ LDFLAGS=$hold_ldflags
+ # Using open here instead of printf so we don't
+ # get confused by the cached value for printf from above.
+ echo "$as_me:$LINENO: checking for open in -lkrb" >&5
+echo $ECHO_N "checking for open in -lkrb... $ECHO_C" >&6
+if test "${ac_cv_lib_krb_open+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkrb $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char open ();
+int
+main ()
+{
+open ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_krb_open=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_krb_open=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_krb_open" >&5
+echo "${ECHO_T}$ac_cv_lib_krb_open" >&6
+if test $ac_cv_lib_krb_open = yes; then
+ krb_lib=yes krb_libdir=
+fi
+
+fi
+
+ LDFLAGS=$hold_ldflags
+ else
+ echo "$as_me:$LINENO: checking for printf in -lkrb" >&5
+echo $ECHO_N "checking for printf in -lkrb... $ECHO_C" >&6
+if test "${ac_cv_lib_krb_printf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkrb $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char printf ();
+int
+main ()
+{
+printf ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_krb_printf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_krb_printf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_krb_printf" >&5
+echo "${ECHO_T}$ac_cv_lib_krb_printf" >&6
+if test $ac_cv_lib_krb_printf = yes; then
+ krb_lib=yes krb_libdir=
+fi
+
+ echo "$as_me:$LINENO: checking for krb_recvauth" >&5
+echo $ECHO_N "checking for krb_recvauth... $ECHO_C" >&6
+if test "${ac_cv_func_krb_recvauth+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define krb_recvauth to an innocuous variant, in case <limits.h> declares krb_recvauth.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define krb_recvauth innocuous_krb_recvauth
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char krb_recvauth (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef krb_recvauth
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char krb_recvauth ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_krb_recvauth) || defined (__stub___krb_recvauth)
+choke me
+#else
+char (*f) () = krb_recvauth;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != krb_recvauth;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_krb_recvauth=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_krb_recvauth=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_krb_recvauth" >&5
+echo "${ECHO_T}$ac_cv_func_krb_recvauth" >&6
+if test $ac_cv_func_krb_recvauth = yes; then
+ krb_lib=yes krb_libdir=
+fi
+
+ fi
+ if test -n "$krb_lib"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_KERBEROS 1
+_ACEOF
+
+ cvs_client_objects="$cvs_client_objects kerberos4-client.o"
+ test -n "${krb_libdir}" && LIBS="${LIBS} -L${krb_libdir}"
+ # Put -L${krb_libdir} in LDFLAGS temporarily so that it appears before
+ # -ldes in the command line. Don't do it permanently so that we honor
+ # the user's setting for LDFLAGS
+ hold_ldflags=$LDFLAGS
+ test -n "${krb_libdir}" && LDFLAGS="$LDFLAGS -L${krb_libdir}"
+ echo "$as_me:$LINENO: checking for printf in -ldes" >&5
+echo $ECHO_N "checking for printf in -ldes... $ECHO_C" >&6
+if test "${ac_cv_lib_des_printf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldes $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char printf ();
+int
+main ()
+{
+printf ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_des_printf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_des_printf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_des_printf" >&5
+echo "${ECHO_T}$ac_cv_lib_des_printf" >&6
+if test $ac_cv_lib_des_printf = yes; then
+ LIBS="${LIBS} -ldes"
+fi
+
+
+echo "$as_me:$LINENO: checking for krb_recvauth in -lkrb" >&5
+echo $ECHO_N "checking for krb_recvauth in -lkrb... $ECHO_C" >&6
+if test "${ac_cv_lib_krb_krb_recvauth+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkrb $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char krb_recvauth ();
+int
+main ()
+{
+krb_recvauth ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_krb_krb_recvauth=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_krb_krb_recvauth=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_krb_krb_recvauth" >&5
+echo "${ECHO_T}$ac_cv_lib_krb_krb_recvauth" >&6
+if test $ac_cv_lib_krb_krb_recvauth = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBKRB 1
+_ACEOF
+
+ LIBS="-lkrb $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for krb_recvauth in -lkrb4" >&5
+echo $ECHO_N "checking for krb_recvauth in -lkrb4... $ECHO_C" >&6
+if test "${ac_cv_lib_krb4_krb_recvauth+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkrb4 $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char krb_recvauth ();
+int
+main ()
+{
+krb_recvauth ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_krb4_krb_recvauth=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_krb4_krb_recvauth=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_krb4_krb_recvauth" >&5
+echo "${ECHO_T}$ac_cv_lib_krb4_krb_recvauth" >&6
+if test $ac_cv_lib_krb4_krb_recvauth = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBKRB4 1
+_ACEOF
+
+ LIBS="-lkrb4 $LIBS"
+
+fi
+
+ LDFLAGS=$hold_ldflags
+ if test -n "$krb_incdir"; then
+ CPPFLAGS="$CPPFLAGS -I$krb_incdir"
+ fi
+ fi
+fi
+
+for ac_func in krb_get_err_text
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+#
+# Use --with-gssapi[=DIR] to enable GSSAPI support.
+#
+# defaults to enabled with DIR in default list below
+#
+# Search for /SUNHEA/ and read the comments about this default below.
+#
+
+# Check whether --with-gssapi or --without-gssapi was given.
+if test "${with_gssapi+set}" = set; then
+ withval="$with_gssapi"
+
+else
+ with_gssapi=yes
+fi;
+#
+# Try to locate a GSSAPI installation if no location was specified, assuming
+# GSSAPI was enabled (the default).
+#
+if test -n "$acx_gssapi_cv_gssapi"; then
+ # Granted, this is a slightly ugly way to print this info, but the
+ # AC_CHECK_HEADER used in the search for a GSSAPI installation makes using
+ # AC_CACHE_CHECK worse
+ echo "$as_me:$LINENO: checking for GSSAPI" >&5
+echo $ECHO_N "checking for GSSAPI... $ECHO_C" >&6
+else :; fi
+if test "${acx_gssapi_cv_gssapi+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+if test x$with_gssapi = xyes; then
+ # --with but no location specified
+ # assume a gssapi.h or gssapi/gssapi.h locates our install.
+ #
+ # This isn't always strictly true. For instance Solaris 7's SUNHEA (header)
+ # package installs gssapi.h whether or not the necessary libraries are
+ # installed. I'm still not sure whether to consider this a bug. The long
+ # way around is to not consider GSSPAI installed unless gss_import_name is
+ # found, but that brings up a lot of other hassles, like continuing to let
+ # gcc & ld generate the error messages when the user uses --with-gssapi=dir
+ # as a debugging aid. The short way around is to disable GSSAPI by default,
+ # but I think Sun users have been faced with this for awhile and I haven't
+ # heard many complaints.
+ acx_gssapi_save_CPPFLAGS=$CPPFLAGS
+ for acx_gssapi_cv_gssapi in yes /usr/kerberos /usr/cygnus/kerbnet no; do
+ if test x$acx_gssapi_cv_gssapi = xno; then
+ break
+ fi
+ if test x$acx_gssapi_cv_gssapi = xyes; then
+ echo "$as_me:$LINENO: checking for GSSAPI" >&5
+echo $ECHO_N "checking for GSSAPI... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: " >&5
+echo "${ECHO_T}" >&6
+ else
+ CPPFLAGS="$acx_gssapi_save_CPPFLAGS -I$acx_gssapi_cv_gssapi/include"
+ echo "$as_me:$LINENO: checking for GSSAPI in $acx_gssapi_cv_gssapi" >&5
+echo $ECHO_N "checking for GSSAPI in $acx_gssapi_cv_gssapi... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: " >&5
+echo "${ECHO_T}" >&6
+ fi
+ unset ac_cv_header_gssapi_h
+ unset ac_cv_header_gssapi_gssapi_h
+ unset ac_cv_header_krb5_h
+
+
+
+for ac_header in gssapi.h gssapi/gssapi.h krb5.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ if (test "$ac_cv_header_gssapi_h" = yes ||
+ test "$ac_cv_header_gssapi_gssapi_h" = yes) &&
+ test "$ac_cv_header_krb5_h" = yes; then
+ break
+ fi
+ done
+ CPPFLAGS=$acx_gssapi_save_CPPFLAGS
+else
+ acx_gssapi_cv_gssapi=$with_gssapi
+fi
+echo "$as_me:$LINENO: checking for GSSAPI" >&5
+echo $ECHO_N "checking for GSSAPI... $ECHO_C" >&6
+
+fi
+echo "$as_me:$LINENO: result: $acx_gssapi_cv_gssapi" >&5
+echo "${ECHO_T}$acx_gssapi_cv_gssapi" >&6
+
+#
+# Set up GSSAPI includes for later use. We don't bother to check for
+# $acx_gssapi_cv_gssapi=no here since that will be caught later.
+#
+if test x$acx_gssapi_cv_gssapi = xyes; then
+ # no special includes necessary
+ GSSAPI_INCLUDES=""
+else
+ # GSSAPI at $acx_gssapi_cv_gssapi (could be 'no')
+ GSSAPI_INCLUDES=" -I$acx_gssapi_cv_gssapi/include"
+fi
+
+#
+# Get the rest of the information CVS needs to compile with GSSAPI support
+#
+if test x$acx_gssapi_cv_gssapi != xno; then
+ # define HAVE_GSSAPI and set up the includes
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GSSAPI
+_ACEOF
+
+ CPPFLAGS=$CPPFLAGS$GSSAPI_INCLUDES
+
+ cvs_client_objects="$cvs_client_objects gssapi-client.o"
+
+ # locate any other headers
+
+
+
+
+for ac_header in gssapi.h gssapi/gssapi.h gssapi/gssapi_generic.h krb5.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ # And look through them for GSS_C_NT_HOSTBASED_SERVICE or its alternatives
+ echo "$as_me:$LINENO: checking for GSS_C_NT_HOSTBASED_SERVICE" >&5
+echo $ECHO_N "checking for GSS_C_NT_HOSTBASED_SERVICE... $ECHO_C" >&6
+if test "${acx_gssapi_cv_gss_c_nt_hostbased_service+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ acx_gssapi_cv_gss_c_nt_hostbased_service=no
+ if test "$ac_cv_header_gssapi_h" = "yes"; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <gssapi.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "GSS_C_NT_HOSTBASED_SERVICE" >/dev/null 2>&1; then
+ acx_gssapi_cv_gss_c_nt_hostbased_service=yes
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <gssapi.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "gss_nt_service_name" >/dev/null 2>&1; then
+ acx_gssapi_cv_gss_c_nt_hostbased_service=gss_nt_service_name
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ fi
+ if test $acx_gssapi_cv_gss_c_nt_hostbased_service = no &&
+ test "$ac_cv_header_gssapi_gssapi_h" = "yes"; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <gssapi/gssapi.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "GSS_C_NT_HOSTBASED_SERVICE" >/dev/null 2>&1; then
+ acx_gssapi_cv_gss_c_nt_hostbased_service=yes
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <gssapi/gssapi.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "gss_nt_service_name" >/dev/null 2>&1; then
+ acx_gssapi_cv_gss_c_nt_hostbased_service=gss_nt_service_name
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ else :; fi
+ if test $acx_gssapi_cv_gss_c_nt_hostbased_service = no &&
+ test "$ac_cv_header_gssapi_gssapi_generic_h" = "yes"; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <gssapi/gssapi_generic.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "GSS_C_NT_HOSTBASED_SERVICE" >/dev/null 2>&1; then
+ acx_gssapi_cv_gss_c_nt_hostbased_service=yes
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <gssapi/gssapi_generic.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "gss_nt_service_name" >/dev/null 2>&1; then
+ acx_gssapi_cv_gss_c_nt_hostbased_service=gss_nt_service_name
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ else :; fi
+
+fi
+echo "$as_me:$LINENO: result: $acx_gssapi_cv_gss_c_nt_hostbased_service" >&5
+echo "${ECHO_T}$acx_gssapi_cv_gss_c_nt_hostbased_service" >&6
+ if test $acx_gssapi_cv_gss_c_nt_hostbased_service != yes &&
+ test $acx_gssapi_cv_gss_c_nt_hostbased_service != no; then
+ # don't define for yes since that means it already means something and
+ # don't define for no since we'd rather the compiler catch the error
+ # It's debatable whether we'd prefer that the compiler catch the error
+ # - it seems our estranged developer is more likely to be familiar with
+ # the intricacies of the compiler than with those of autoconf, but by
+ # the same token, maybe we'd rather alert them to the fact that most
+ # of the support they need to fix the problem is installed if they can
+ # simply locate the appropriate symbol.
+
+cat >>confdefs.h <<_ACEOF
+#define GSS_C_NT_HOSTBASED_SERVICE $acx_gssapi_cv_gss_c_nt_hostbased_service
+_ACEOF
+
+ else :; fi
+
+ # Expect the libs to be installed parallel to the headers
+ #
+ # We could try once with and once without, but I'm not sure it's worth the
+ # trouble.
+ if test x$acx_gssapi_cv_gssapi != xyes; then
+ if test -z "$LIBS"; then
+ LIBS="-L$acx_gssapi_cv_gssapi/lib"
+ else
+ LIBS="-L$acx_gssapi_cv_gssapi/lib $LIBS"
+ fi
+ else :; fi
+
+ #
+ # Some of the order below is particular due to library dependencies
+ #
+
+ #
+ # des Heimdal K 0.3d, but Heimdal seems to be set up such
+ # that it could have been installed from elsewhere.
+ #
+ echo "$as_me:$LINENO: checking for library containing des_set_odd_parity" >&5
+echo $ECHO_N "checking for library containing des_set_odd_parity... $ECHO_C" >&6
+if test "${ac_cv_search_des_set_odd_parity+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_des_set_odd_parity=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char des_set_odd_parity ();
+int
+main ()
+{
+des_set_odd_parity ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_des_set_odd_parity="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_des_set_odd_parity" = no; then
+ for ac_lib in des; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char des_set_odd_parity ();
+int
+main ()
+{
+des_set_odd_parity ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_des_set_odd_parity="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_des_set_odd_parity" >&5
+echo "${ECHO_T}$ac_cv_search_des_set_odd_parity" >&6
+if test "$ac_cv_search_des_set_odd_parity" != no; then
+ test "$ac_cv_search_des_set_odd_parity" = "none required" || LIBS="$ac_cv_search_des_set_odd_parity $LIBS"
+
+fi
+
+
+ #
+ # com_err Heimdal K 0.3d
+ #
+ # com_err MIT K5 v1.2.2-beta1
+ #
+ echo "$as_me:$LINENO: checking for library containing com_err" >&5
+echo $ECHO_N "checking for library containing com_err... $ECHO_C" >&6
+if test "${ac_cv_search_com_err+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_com_err=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char com_err ();
+int
+main ()
+{
+com_err ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_com_err="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_com_err" = no; then
+ for ac_lib in com_err; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char com_err ();
+int
+main ()
+{
+com_err ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_com_err="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_com_err" >&5
+echo "${ECHO_T}$ac_cv_search_com_err" >&6
+if test "$ac_cv_search_com_err" != no; then
+ test "$ac_cv_search_com_err" = "none required" || LIBS="$ac_cv_search_com_err $LIBS"
+
+fi
+
+
+ #
+ # asn1 Heimdal K 0.3d -lcom_err
+ #
+ echo "$as_me:$LINENO: checking for library containing initialize_asn1_error_table_r" >&5
+echo $ECHO_N "checking for library containing initialize_asn1_error_table_r... $ECHO_C" >&6
+if test "${ac_cv_search_initialize_asn1_error_table_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_initialize_asn1_error_table_r=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char initialize_asn1_error_table_r ();
+int
+main ()
+{
+initialize_asn1_error_table_r ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_initialize_asn1_error_table_r="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_initialize_asn1_error_table_r" = no; then
+ for ac_lib in asn1; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char initialize_asn1_error_table_r ();
+int
+main ()
+{
+initialize_asn1_error_table_r ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_initialize_asn1_error_table_r="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_initialize_asn1_error_table_r" >&5
+echo "${ECHO_T}$ac_cv_search_initialize_asn1_error_table_r" >&6
+if test "$ac_cv_search_initialize_asn1_error_table_r" != no; then
+ test "$ac_cv_search_initialize_asn1_error_table_r" = "none required" || LIBS="$ac_cv_search_initialize_asn1_error_table_r $LIBS"
+
+fi
+
+
+ #
+ # resolv required, but not installed by Heimdal K 0.3d
+ #
+ # resolv MIT K5 1.2.2-beta1
+ # Linux 2.2.17
+ #
+ echo "$as_me:$LINENO: checking for library containing __dn_expand" >&5
+echo $ECHO_N "checking for library containing __dn_expand... $ECHO_C" >&6
+if test "${ac_cv_search___dn_expand+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search___dn_expand=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __dn_expand ();
+int
+main ()
+{
+__dn_expand ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search___dn_expand="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search___dn_expand" = no; then
+ for ac_lib in resolv; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __dn_expand ();
+int
+main ()
+{
+__dn_expand ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search___dn_expand="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search___dn_expand" >&5
+echo "${ECHO_T}$ac_cv_search___dn_expand" >&6
+if test "$ac_cv_search___dn_expand" != no; then
+ test "$ac_cv_search___dn_expand" = "none required" || LIBS="$ac_cv_search___dn_expand $LIBS"
+
+fi
+
+
+ #
+ # crypto Need by gssapi under FreeBSD 5.4
+ #
+ echo "$as_me:$LINENO: checking for library containing RC4" >&5
+echo $ECHO_N "checking for library containing RC4... $ECHO_C" >&6
+if test "${ac_cv_search_RC4+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_RC4=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char RC4 ();
+int
+main ()
+{
+RC4 ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_RC4="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_RC4" = no; then
+ for ac_lib in crypto; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char RC4 ();
+int
+main ()
+{
+RC4 ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_RC4="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_RC4" >&5
+echo "${ECHO_T}$ac_cv_search_RC4" >&6
+if test "$ac_cv_search_RC4" != no; then
+ test "$ac_cv_search_RC4" = "none required" || LIBS="$ac_cv_search_RC4 $LIBS"
+
+fi
+
+
+ #
+ # crypt Needed by roken under FreeBSD 4.6.
+ #
+ echo "$as_me:$LINENO: checking for library containing crypt" >&5
+echo $ECHO_N "checking for library containing crypt... $ECHO_C" >&6
+if test "${ac_cv_search_crypt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_crypt=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_crypt="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_crypt" = no; then
+ for ac_lib in crypt; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_crypt="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_crypt" >&5
+echo "${ECHO_T}$ac_cv_search_crypt" >&6
+if test "$ac_cv_search_crypt" != no; then
+ test "$ac_cv_search_crypt" = "none required" || LIBS="$ac_cv_search_crypt $LIBS"
+
+fi
+
+
+ #
+ # roken Heimdal K 0.3d -lresolv
+ # roken FreeBSD 4.6 -lcrypt
+ #
+ echo "$as_me:$LINENO: checking for library containing roken_gethostbyaddr" >&5
+echo $ECHO_N "checking for library containing roken_gethostbyaddr... $ECHO_C" >&6
+if test "${ac_cv_search_roken_gethostbyaddr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_roken_gethostbyaddr=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char roken_gethostbyaddr ();
+int
+main ()
+{
+roken_gethostbyaddr ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_roken_gethostbyaddr="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_roken_gethostbyaddr" = no; then
+ for ac_lib in roken; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char roken_gethostbyaddr ();
+int
+main ()
+{
+roken_gethostbyaddr ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_roken_gethostbyaddr="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_roken_gethostbyaddr" >&5
+echo "${ECHO_T}$ac_cv_search_roken_gethostbyaddr" >&6
+if test "$ac_cv_search_roken_gethostbyaddr" != no; then
+ test "$ac_cv_search_roken_gethostbyaddr" = "none required" || LIBS="$ac_cv_search_roken_gethostbyaddr $LIBS"
+
+fi
+
+
+ #
+ # k5crypto MIT K5 v1.2.2-beta1
+ #
+ echo "$as_me:$LINENO: checking for library containing valid_enctype" >&5
+echo $ECHO_N "checking for library containing valid_enctype... $ECHO_C" >&6
+if test "${ac_cv_search_valid_enctype+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_valid_enctype=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char valid_enctype ();
+int
+main ()
+{
+valid_enctype ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_valid_enctype="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_valid_enctype" = no; then
+ for ac_lib in k5crypto; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char valid_enctype ();
+int
+main ()
+{
+valid_enctype ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_valid_enctype="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_valid_enctype" >&5
+echo "${ECHO_T}$ac_cv_search_valid_enctype" >&6
+if test "$ac_cv_search_valid_enctype" != no; then
+ test "$ac_cv_search_valid_enctype" = "none required" || LIBS="$ac_cv_search_valid_enctype $LIBS"
+
+fi
+
+
+ #
+ # gen ? ? ? Needed on Irix 5.3 with some
+ # Irix 5.3 version of Kerberos. I'm not
+ # sure which since Irix didn't
+ # get any testing this time
+ # around. Original comment:
+ #
+ # This is necessary on Irix 5.3, in order to link against libkrb5 --
+ # there, an_to_ln.o refers to things defined only in -lgen.
+ #
+ echo "$as_me:$LINENO: checking for library containing compile" >&5
+echo $ECHO_N "checking for library containing compile... $ECHO_C" >&6
+if test "${ac_cv_search_compile+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_compile=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char compile ();
+int
+main ()
+{
+compile ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_compile="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_compile" = no; then
+ for ac_lib in gen; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char compile ();
+int
+main ()
+{
+compile ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_compile="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_compile" >&5
+echo "${ECHO_T}$ac_cv_search_compile" >&6
+if test "$ac_cv_search_compile" != no; then
+ test "$ac_cv_search_compile" = "none required" || LIBS="$ac_cv_search_compile $LIBS"
+
+fi
+
+
+ #
+ # krb5 ? ? ? -lgen -l???
+ # Irix 5.3
+ #
+ # krb5 MIT K5 v1.1.1
+ #
+ # krb5 MIT K5 v1.2.2-beta1 -lcrypto -lcom_err
+ # Linux 2.2.17
+ #
+ # krb5 MIT K5 v1.2.2-beta1 -lcrypto -lcom_err -lresolv
+ #
+ # krb5 Heimdal K 0.3d -lasn1 -lroken -ldes
+ #
+ echo "$as_me:$LINENO: checking for library containing krb5_free_context" >&5
+echo $ECHO_N "checking for library containing krb5_free_context... $ECHO_C" >&6
+if test "${ac_cv_search_krb5_free_context+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_krb5_free_context=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char krb5_free_context ();
+int
+main ()
+{
+krb5_free_context ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_krb5_free_context="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_krb5_free_context" = no; then
+ for ac_lib in krb5; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char krb5_free_context ();
+int
+main ()
+{
+krb5_free_context ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_krb5_free_context="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_krb5_free_context" >&5
+echo "${ECHO_T}$ac_cv_search_krb5_free_context" >&6
+if test "$ac_cv_search_krb5_free_context" != no; then
+ test "$ac_cv_search_krb5_free_context" = "none required" || LIBS="$ac_cv_search_krb5_free_context $LIBS"
+
+fi
+
+
+ #
+ # gssapi_krb5 Only lib needed with MIT K5 v1.2.1, so find it first in
+ # order to prefer MIT Kerberos. If both MIT & Heimdal
+ # Kerberos are installed and in the path, this will leave
+ # some of the libraries above in LIBS unnecessarily, but
+ # noone would ever do that, right?
+ #
+ # gssapi_krb5 MIT K5 v1.2.2-beta1 -lkrb5
+ #
+ # gssapi Heimdal K 0.3d -lkrb5
+ #
+ echo "$as_me:$LINENO: checking for library containing gss_import_name" >&5
+echo $ECHO_N "checking for library containing gss_import_name... $ECHO_C" >&6
+if test "${ac_cv_search_gss_import_name+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_gss_import_name=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gss_import_name ();
+int
+main ()
+{
+gss_import_name ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gss_import_name="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_gss_import_name" = no; then
+ for ac_lib in gssapi_krb5 gssapi; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gss_import_name ();
+int
+main ()
+{
+gss_import_name ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gss_import_name="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_gss_import_name" >&5
+echo "${ECHO_T}$ac_cv_search_gss_import_name" >&6
+if test "$ac_cv_search_gss_import_name" != no; then
+ test "$ac_cv_search_gss_import_name" = "none required" || LIBS="$ac_cv_search_gss_import_name $LIBS"
+
+fi
+
+fi
+
+
+
+#
+# Use --with-zlib to build with a zlib other than the version distributed
+# with CVS.
+#
+# defaults to the included snapshot of zlib
+#
+
+# Check whether --with-external-zlib or --without-external-zlib was given.
+if test "${with_external_zlib+set}" = set; then
+ withval="$with_external_zlib"
+ with_external_zlib=$withval
+else
+ with_external_zlib=no
+fi;
+
+#
+# Try to locate a ZLIB installation if no location was specified, assuming
+# external ZLIB was enabled.
+#
+if test -n "$acx_zlib_cv_external_zlib"; then
+ # Granted, this is a slightly ugly way to print this info, but the
+ # AC_CHECK_HEADER used in the search for a ZLIB installation makes using
+ # AC_CACHE_CHECK worse
+ echo "$as_me:$LINENO: checking for external ZLIB" >&5
+echo $ECHO_N "checking for external ZLIB... $ECHO_C" >&6
+else :; fi
+if test "${acx_zlib_cv_external_zlib+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ #
+ # --with but no location specified
+ # assume zlib.h locates our install.
+ #
+ acx_zlib_save_CPPFLAGS=$CPPFLAGS
+ for acx_zlib_cv_external_zlib in yes /usr/local no; do
+ if test x$acx_zlib_cv_external_zlib = xno; then
+ break
+ fi
+ if test x$acx_zlib_cv_external_zlib = xyes; then
+ echo "$as_me:$LINENO: checking for external ZLIB" >&5
+echo $ECHO_N "checking for external ZLIB... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: " >&5
+echo "${ECHO_T}" >&6
+ else
+ CPPFLAGS="$acx_zlib_save_CPPFLAGS -I$acx_zlib_cv_external_zlib/include"
+ echo "$as_me:$LINENO: checking for external ZLIB in $acx_zlib_cv_external_zlib" >&5
+echo $ECHO_N "checking for external ZLIB in $acx_zlib_cv_external_zlib... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: " >&5
+echo "${ECHO_T}" >&6
+ fi
+ unset ac_cv_header_zlib_h
+
+for ac_header in zlib.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ if test "$ac_cv_header_zlib_h" = yes; then
+ break
+ fi
+ done
+ CPPFLAGS=$acx_zlib_save_CPPFLAGS
+echo "$as_me:$LINENO: checking for external ZLIB" >&5
+echo $ECHO_N "checking for external ZLIB... $ECHO_C" >&6
+
+fi
+echo "$as_me:$LINENO: result: $acx_zlib_cv_external_zlib" >&5
+echo "${ECHO_T}$acx_zlib_cv_external_zlib" >&6
+
+
+#
+# Output a pretty message naming our selected ZLIB "external" or "package"
+# so that any warnings printed by the version check make more sense.
+#
+echo "$as_me:$LINENO: checking selected ZLIB" >&5
+echo $ECHO_N "checking selected ZLIB... $ECHO_C" >&6
+if test "x$with_external_zlib" = xno; then
+ echo "$as_me:$LINENO: result: package" >&5
+echo "${ECHO_T}package" >&6
+else
+ echo "$as_me:$LINENO: result: external" >&5
+echo "${ECHO_T}external" >&6
+fi
+
+
+#
+# Verify that the ZLIB we aren't using isn't newer than the one we are.
+#
+if test "x$acx_zlib_cv_external_zlib" != xno; then
+ LOCAL_ZLIB_VERSION=`sed -n '/^#define ZLIB_VERSION ".*"$/{
+ s/^#define ZLIB_VERSION "\(.*\)"$/\1/;
+ p;}' <$srcdir/zlib/zlib.h 2>&5`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <zlib.h>
+
+_ACEOF
+ac_extract_cpp_result=`(eval "$ac_cpp -dM conftest.$ac_ext") 2>&5 |
+ sed -n "/^#define ZLIB_VERSION /{
+ s/^#define ZLIB_VERSION //;
+ s/^ *//;
+ s/ *\$//;
+ p;}" 2>&5`
+if test -n "$ac_extract_cpp_result"; then
+ ZLIB_VERSION=$ac_extract_cpp_result
+fi
+rm -f conftest*
+
+ ZLIB_VERSION=`echo "$ZLIB_VERSION" |sed 's/"//g'`
+ if test "x$LOCAL_ZLIB_VERSION" = "x$ZLIB_VERSION"; then
+ # the strings are equal. run ACTION-IF-EQUAL and bail
+ :
+else
+ # first unletter the versions
+ # this only works for a single trailing letter
+ asx_version_1=`echo "$LOCAL_ZLIB_VERSION" |
+ sed 's/\(abcedfghi\)/.\1/;
+ s/\(jklmnopqrs\)/.1\1/;
+ s/\(tuvwxyz\)/.2\1/;
+ y/abcdefghijklmnopqrstuvwxyz/12345678901234567890123456/;'`
+ asx_version_2=`echo "$ZLIB_VERSION" |
+ sed 's/\(abcedfghi\)/.\1/;
+ s/\(jklmnopqrs\)/.1\1/;
+ s/\(tuvwxyz\)/.2\1/;
+ y/abcdefghijklmnopqrstuvwxyz/12345678901234567890123456/;'`
+ asx_count=1
+ asx_save_IFS=$IFS
+ IFS=.
+ asx_retval=-1
+ for vsub1 in $asx_version_1; do
+ vsub2=`echo "$asx_version_2" |awk -F. "{print \\\$$asx_count}"`
+ if test -z "$vsub2" || test $vsub1 -gt $vsub2; then
+ asx_retval=1
+ break
+ elif test $vsub1 -lt $vsub2; then
+ break
+ fi
+ asx_count=`expr $asx_count + 1`
+ done
+ IFS=$asx_save_IFS
+ if test $asx_retval -eq -1; then
+ if test "x$with_external_zlib" = xno; then
+ { echo "$as_me:$LINENO: WARNING: Found external ZLIB with a more recent version than the
+ package version ($ZLIB_VERSION > $LOCAL_ZLIB_VERSION). configure with the
+ --with-external-zlib option to select the more recent version." >&5
+echo "$as_me: WARNING: Found external ZLIB with a more recent version than the
+ package version ($ZLIB_VERSION > $LOCAL_ZLIB_VERSION). configure with the
+ --with-external-zlib option to select the more recent version." >&2;}
+ fi
+ else
+if test "x$with_external_zlib" != xno; then
+ { echo "$as_me:$LINENO: WARNING: Package ZLIB is more recent than requested external version
+ ($LOCAL_ZLIB_VERSION > $ZLIB_VERSION). configure with the --without-external-zlib
+ option to select the more recent version." >&5
+echo "$as_me: WARNING: Package ZLIB is more recent than requested external version
+ ($LOCAL_ZLIB_VERSION > $ZLIB_VERSION). configure with the --without-external-zlib
+ option to select the more recent version." >&2;}
+ fi
+ fi
+
+fi
+
+fi
+
+
+# Now set with_external_zlib to our discovered value or the user specified
+# value, as appropriate.
+if test x$with_external_zlib = xyes; then
+ with_external_zlib=$acx_zlib_cv_external_zlib
+fi
+# $with_external_zlib could still be "no"
+
+
+#
+# Set up ZLIB includes for later use.
+#
+if test x$with_external_zlib != xyes \
+ && test x$with_external_zlib != no; then
+ if test -z "$CPPFLAGS"; then
+ CPPFLAGS="-I$with_external_zlib/include"
+ else
+ CPPFLAGS="$CPPFLAGS -I$with_external_zlib/include"
+ fi
+ if test -z "$LDFLAGS"; then
+ LDFLAGS="-L$with_external_zlib/lib"
+ else
+ LDFLAGS="$LDFLAGS -L$with_external_zlib/lib"
+ fi
+fi
+
+ZLIB_CPPFLAGS=
+ZLIB_LIBS=
+ZLIB_SUBDIRS=
+if test x$with_external_zlib = xno; then
+ # We need ZLIB_CPPFLAGS so that later executions of cpp from configure
+ # don't try to interpret $(top_srcdir)
+ ZLIB_CPPFLAGS='-I$(top_srcdir)/zlib'
+ ZLIB_LIBS='$(top_builddir)/zlib/libz.a'
+ # ZLIB_SUBDIRS is only used in the top level Makefiles.
+ ZLIB_SUBDIRS=zlib
+else
+ # We know what to do now, so set up the CPPFLAGS, LDFLAGS, and LIBS for later
+ # use.
+ if test -z "$LIBS"; then
+ LIBS=-lz
+ else
+ LIBS="$LIBS -lz"
+ fi
+
+ #
+ # Verify external installed zlib works
+ #
+ # Ideally, we would also check that the version is newer
+ #
+ echo "$as_me:$LINENO: checking that ZLIB library works" >&5
+echo $ECHO_N "checking that ZLIB library works... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <zlib.h>
+int
+main ()
+{
+int i = Z_OK; const char *version = zlibVersion();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ { { echo "$as_me:$LINENO: error: ZLIB failed to link" >&5
+echo "$as_me: error: ZLIB failed to link" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+
+
+# What remote shell transport should our client cvs default to using?
+
+# Check whether --with-rsh or --without-rsh was given.
+if test "${with_rsh+set}" = set; then
+ withval="$with_rsh"
+
+else
+ with_rsh="ssh rsh"
+fi;
+
+if test no = "$with_rsh"; then
+ { echo "$as_me:$LINENO: WARNING: Failed to find usable remote shell. Using 'rsh'." >&5
+echo "$as_me: WARNING: Failed to find usable remote shell. Using 'rsh'." >&2;}
+ with_rsh=rsh
+elif test yes = "$with_rsh"; then
+ # Make --with-rsh mean the same thing as --with-rsh=rsh
+ with_rsh=rsh
+fi
+
+if echo $with_rsh |grep ^/ >/dev/null; then
+ # If $with_rsh is an absolute path, issue a warning if the executable
+ # doesn't exist or isn't usable, but then trust the user and use it
+ # regardless
+ with_default_rsh=$with_rsh
+ echo "$as_me:$LINENO: checking for a remote shell" >&5
+echo $ECHO_N "checking for a remote shell... $ECHO_C" >&6
+ if ! test -f $with_rsh \
+ || ! test -x $with_rsh; then
+ # warn the user that they may encounter problems
+ { echo "$as_me:$LINENO: WARNING: $with_rsh is not a path to an executable file" >&5
+echo "$as_me: WARNING: $with_rsh is not a path to an executable file" >&2;}
+ fi
+else
+ # Search for a remote shell
+ for ac_prog in $with_rsh
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_with_default_rsh+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$with_default_rsh"; then
+ ac_cv_prog_with_default_rsh="$with_default_rsh" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_with_default_rsh="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+with_default_rsh=$ac_cv_prog_with_default_rsh
+if test -n "$with_default_rsh"; then
+ echo "$as_me:$LINENO: result: $with_default_rsh" >&5
+echo "${ECHO_T}$with_default_rsh" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$with_default_rsh" && break
+done
+test -n "$with_default_rsh" || with_default_rsh=""rsh""
+
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define RSH_DFLT "$with_default_rsh"
+_ACEOF
+
+RSH_DFLT=$with_default_rsh
+
+
+
+
+
+# Let the confiscator request a specific editor
+
+# Check whether --with-editor or --without-editor was given.
+if test "${with_editor+set}" = set; then
+ withval="$with_editor"
+
+else
+ with_editor=yes
+fi;
+
+# If --with-editor was supplied with an argument, let it override $EDITOR from
+# the user's environment. We need to unset EDITOR here because AC_CHECK_PROGS
+# will let the value of EDITOR ride when it is set rather than searching. We
+# ignore the --without-editor case since it will be caught below.
+if test -n "$EDITOR" && test yes != $with_editor; then
+ $as_unset EDITOR || test "${EDITOR+set}" != set || { EDITOR=; export EDITOR; }
+fi
+
+# Set the default when --with-editor wasn't supplied or when it was supplied
+# without an argument.
+if test yes = $with_editor; then
+ with_editor="vim vi emacs nano pico edit"
+fi
+
+if echo $with_editor |grep ^/ >/dev/null; then
+ # If $with_editor is an absolute path, issue a warning if the executable
+ # doesn't exist or isn't usable, but then trust the user and use it
+ # regardless
+ EDITOR=$with_editor
+ echo "$as_me:$LINENO: checking for an editor" >&5
+echo $ECHO_N "checking for an editor... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: $EDITOR" >&5
+echo "${ECHO_T}$EDITOR" >&6
+ if ! test -f $with_editor \
+ || ! test -x $with_editor; then
+ # warn the user that they may encounter problems
+ { echo "$as_me:$LINENO: WARNING: \`$with_editor' is not a path to an executable file" >&5
+echo "$as_me: WARNING: \`$with_editor' is not a path to an executable file" >&2;}
+ fi
+elif test no != "${with_editor}"; then
+ # Search for an editor
+ for ac_prog in $with_editor
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_EDITOR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$EDITOR"; then
+ ac_cv_prog_EDITOR="$EDITOR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_EDITOR="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+EDITOR=$ac_cv_prog_EDITOR
+if test -n "$EDITOR"; then
+ echo "$as_me:$LINENO: result: $EDITOR" >&5
+echo "${ECHO_T}$EDITOR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$EDITOR" && break
+done
+test -n "$EDITOR" || EDITOR="no"
+
+ if test no = "${EDITOR}"; then
+ { { echo "$as_me:$LINENO: error:
+ Failed to find a text file editor. CVS cannot be compiled
+ without a default log message editor. Searched for
+ \`$with_editor'. Try \`configure --with-editor'." >&5
+echo "$as_me: error:
+ Failed to find a text file editor. CVS cannot be compiled
+ without a default log message editor. Searched for
+ \`$with_editor'. Try \`configure --with-editor'." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+else
+ { { echo "$as_me:$LINENO: error:
+ CVS cannot be compiled without a default log message editor.
+ Try \`configure --with-editor'." >&5
+echo "$as_me: error:
+ CVS cannot be compiled without a default log message editor.
+ Try \`configure --with-editor'." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define EDITOR_DFLT "$EDITOR"
+_ACEOF
+
+
+
+
+
+
+# Check whether --with-hardcoded-pam-service-name or --without-hardcoded-pam-service-name was given.
+if test "${with_hardcoded_pam_service_name+set}" = set; then
+ withval="$with_hardcoded_pam_service_name"
+
+else
+ with_hardcoded_pam_service_name=cvs
+fi;
+
+if test "x$with_hardcoded_pam_service_name" = xno ||
+ test "x$with_hardcoded_pam_service_name" = xprogram_name; then
+
+cat >>confdefs.h <<\_ACEOF
+#define PAM_SERVICE_NAME program_name
+_ACEOF
+
+else
+ if test x"$with_hardcoded_pam_service_name" = xyes; then
+ with_hardcoded_pam_service_name=cvs
+ fi
+ cat >>confdefs.h <<_ACEOF
+#define PAM_SERVICE_NAME "$with_hardcoded_pam_service_name"
+_ACEOF
+
+fi
+
+
+
+
+# Check whether --with-tmpdir or --without-tmpdir was given.
+if test "${with_tmpdir+set}" = set; then
+ withval="$with_tmpdir"
+
+fi;
+
+echo "$as_me:$LINENO: checking for temporary directory" >&5
+echo $ECHO_N "checking for temporary directory... $ECHO_C" >&6
+if test -z "$with_tmpdir" || test yes = "$with_tmpdir"; then
+ for with_tmpdir in /tmp /var/tmp no; do
+ if test -d "$with_tmpdir" && test -x "$with_tmpdir" \
+ && test -w "$with_tmpdir" && test -r "$with_tmpdir"; then
+ break
+ fi
+ done
+ if test no = "$with_tmpdir"; then
+ { echo "$as_me:$LINENO: WARNING: Failed to find usable temporary directory. Using '/tmp'." >&5
+echo "$as_me: WARNING: Failed to find usable temporary directory. Using '/tmp'." >&2;}
+ with_tmpdir=/tmp
+ fi
+ echo "$as_me:$LINENO: result: $with_tmpdir" >&5
+echo "${ECHO_T}$with_tmpdir" >&6
+elif ! echo "$with_tmpdir" |grep '^[\\/]'; then
+ echo "$as_me:$LINENO: result: $with_tmpdir" >&5
+echo "${ECHO_T}$with_tmpdir" >&6
+ { { echo "$as_me:$LINENO: error: --with-tmpdir requires an absolute path." >&5
+echo "$as_me: error: --with-tmpdir requires an absolute path." >&2;}
+ { (exit 1); exit 1; }; }
+elif ! test -d "$with_tmpdir" || ! test -x "$with_tmpdir" \
+ || ! test -w "$with_tmpdir" || ! test -r "$with_tmpdir"; then
+ echo "$as_me:$LINENO: result: $with_tmpdir" >&5
+echo "${ECHO_T}$with_tmpdir" >&6
+ { echo "$as_me:$LINENO: WARNING: User supplied temporary directory ('$with_tmpdir') does not
+ exist or lacks sufficient permissions for read/write." >&5
+echo "$as_me: WARNING: User supplied temporary directory ('$with_tmpdir') does not
+ exist or lacks sufficient permissions for read/write." >&2;}
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define TMPDIR_DFLT "$with_tmpdir"
+_ACEOF
+
+
+
+
+
+
+# Check whether --with-umask or --without-umask was given.
+if test "${with_umask+set}" = set; then
+ withval="$with_umask"
+
+fi;
+
+if test -z "$with_umask" || test yes = "$with_umask"; then
+ with_umask=002
+elif test no = "$with_umask"; then
+ with_umask=000
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define UMASK_DFLT $with_umask
+_ACEOF
+
+
+
+
+# Check whether --with-cvs-admin-group or --without-cvs-admin-group was given.
+if test "${with_cvs_admin_group+set}" = set; then
+ withval="$with_cvs_admin_group"
+
+else
+ with_cvs_admin_group=cvsadmin
+fi;
+
+if test yes = "$with_cvs_admin_group"; then
+ with_cvs_admin_group=cvsadmin
+fi
+if test no != "$with_cvs_admin_group"; then
+
+cat >>confdefs.h <<_ACEOF
+#define CVS_ADMIN_GROUP "$with_cvs_admin_group"
+_ACEOF
+
+fi
+
+
+# Check whether --enable-cvs-ndbm or --disable-cvs-ndbm was given.
+if test "${enable_cvs_ndbm+set}" = set; then
+ enableval="$enable_cvs_ndbm"
+
+else
+ enable_cvs_ndbm=yes
+fi;
+if test no != "$enable_cvs_ndbm"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define MY_NDBM 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+# Check for options requesting client and server feature. If none are
+# given and we have connect(), we want the full client & server arrangement.
+# Check whether --enable-client or --disable-client was given.
+if test "${enable_client+set}" = set; then
+ enableval="$enable_client"
+
+else
+ enable_client=$ac_cv_search_connect
+fi;
+if test no != "$enable_client"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define CLIENT_SUPPORT 1
+_ACEOF
+
+fi
+
+
+
+# Check whether --enable-password-authenticated-client or --disable-password-authenticated-client was given.
+if test "${enable_password_authenticated_client+set}" = set; then
+ enableval="$enable_password_authenticated_client"
+
+else
+ enable_password_authenticated_client=$enable_client
+fi;
+
+if test xno != "x$enable_password_authenticated_client"; then
+ if test xno != "x$enable_client"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define AUTH_CLIENT_SUPPORT 1
+_ACEOF
+
+ else
+ { echo "$as_me:$LINENO: WARNING: --enable-password-authenticated-client is meaningless with
+ the CVS client disabled (--disable-client)" >&5
+echo "$as_me: WARNING: --enable-password-authenticated-client is meaningless with
+ the CVS client disabled (--disable-client)" >&2;}
+ fi
+fi
+
+
+
+
+# Check whether --enable-server or --disable-server was given.
+if test "${enable_server+set}" = set; then
+ enableval="$enable_server"
+
+else
+ enable_server=$ac_cv_search_connect
+fi;
+
+if test no != "$enable_server"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define SERVER_SUPPORT 1
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for library containing crypt" >&5
+echo $ECHO_N "checking for library containing crypt... $ECHO_C" >&6
+if test "${ac_cv_search_crypt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_crypt=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_crypt="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_crypt" = no; then
+ for ac_lib in crypt; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_crypt="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_crypt" >&5
+echo "${ECHO_T}$ac_cv_search_crypt" >&6
+if test "$ac_cv_search_crypt" != no; then
+ test "$ac_cv_search_crypt" = "none required" || LIBS="$ac_cv_search_crypt $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CRYPT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define AUTH_SERVER_SUPPORT 1
+_ACEOF
+
+fi
+
+ # Check whether --enable-server-flow-control or --disable-server-flow-control was given.
+if test "${enable_server_flow_control+set}" = set; then
+ enableval="$enable_server_flow_control"
+ if test yes = $enable_server_flow_control; then
+ enable_server_flow_control=1M,2M
+ fi
+else
+ enable_server_flow_control=1M,2M
+fi;
+ if test no != $enable_server_flow_control; then
+ ccvs_lwm=`expr "$enable_server_flow_control" : '\(.*\),'`
+ ccvs_hwm=`expr "$enable_server_flow_control" : '.*,\(.*\)'`
+ ccvs_lwm_E=`expr "$ccvs_lwm" : '[0-9][0-9]*\(.*\)'`
+ ccvs_lwm=`expr "$ccvs_lwm" : '\([0-9][0-9]*\)'`
+ test "" != "$ccvs_lwm" || ccvs_lwm_E="?"
+ case $ccvs_lwm_E in
+ G) ccvs_lwm="$ccvs_lwm * 1024 * 1024 * 1024";;
+ M) ccvs_lwm="$ccvs_lwm * 1024 * 1024";;
+ k) ccvs_lwm="$ccvs_lwm * 1024";;
+ b | '') ;;
+ *) { { echo "$as_me:$LINENO: error: Can't parse argument to --enable-server-flow-control
+ ('$enable_server_flow_control') as <lwm>,<hwm>" >&5
+echo "$as_me: error: Can't parse argument to --enable-server-flow-control
+ ('$enable_server_flow_control') as <lwm>,<hwm>" >&2;}
+ { (exit 1); exit 1; }; }
+ esac
+ ccvs_hwm_E=`expr "$ccvs_hwm" : '[0-9][0-9]*\(.*\)'`
+ ccvs_hwm=`expr "$ccvs_hwm" : '\([0-9][0-9]*\).*'`
+ test "" != "$ccvs_hwm" || ccvs_hwm_E="?"
+ case $ccvs_hwm_E in
+ G) ccvs_hwm="$ccvs_hwm * 1024 * 1024 * 1024";;
+ M) ccvs_hwm="$ccvs_hwm * 1024 * 1024";;
+ k) ccvs_hwm="$ccvs_hwm * 1024";;
+ b | '') ccvs_hwm="$ccvs_hwm";;
+ *) { { echo "$as_me:$LINENO: error: Can't parse argument to --enable-server-flow-control
+ ('$enable_server_flow_control') as <lwm>,<hwm>" >&5
+echo "$as_me: error: Can't parse argument to --enable-server-flow-control
+ ('$enable_server_flow_control') as <lwm>,<hwm>" >&2;}
+ { (exit 1); exit 1; }; }
+ esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SERVER_FLOWCONTROL 1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SERVER_LO_WATER ($ccvs_lwm)
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SERVER_HI_WATER ($ccvs_hwm)
+_ACEOF
+
+ fi # enable_server_flow_control
+fi # enable_server
+
+
+
+
+# Check whether --enable-proxy or --disable-proxy was given.
+if test "${enable_proxy+set}" = set; then
+ enableval="$enable_proxy"
+
+else
+ if test xno != "x$enable_client" && test xno != "x$enable_server"; then
+ enable_proxy=yes
+ else
+ enable_proxy=no
+ fi
+fi;
+
+if test no != "$enable_proxy"; then
+ if test xno = "x$enable_client" || test xno = "x$enable_server"; then
+ { echo "$as_me:$LINENO: WARNING: --enable-proxy is meaningless when either the CVS client or the
+ CVS server is disabled (--disable-client and --disable-server)." >&5
+echo "$as_me: WARNING: --enable-proxy is meaningless when either the CVS client or the
+ CVS server is disabled (--disable-client and --disable-server)." >&2;}
+ else
+
+cat >>confdefs.h <<\_ACEOF
+#define PROXY_SUPPORT 1
+_ACEOF
+
+ fi
+fi
+
+
+
+# Check whether --enable-pam or --disable-pam was given.
+if test "${enable_pam+set}" = set; then
+ enableval="$enable_pam"
+
+else
+ enable_pam=no
+
+fi;
+
+if test yes = $enable_pam; then
+ ac_pam_header_available=
+
+ if test "${ac_cv_header_security_pam_appl_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for security/pam_appl.h" >&5
+echo $ECHO_N "checking for security/pam_appl.h... $ECHO_C" >&6
+if test "${ac_cv_header_security_pam_appl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_security_pam_appl_h" >&5
+echo "${ECHO_T}$ac_cv_header_security_pam_appl_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking security/pam_appl.h usability" >&5
+echo $ECHO_N "checking security/pam_appl.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <security/pam_appl.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking security/pam_appl.h presence" >&5
+echo $ECHO_N "checking security/pam_appl.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <security/pam_appl.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: security/pam_appl.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: security/pam_appl.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: security/pam_appl.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: security/pam_appl.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: security/pam_appl.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: security/pam_appl.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: security/pam_appl.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: security/pam_appl.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: security/pam_appl.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for security/pam_appl.h" >&5
+echo $ECHO_N "checking for security/pam_appl.h... $ECHO_C" >&6
+if test "${ac_cv_header_security_pam_appl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_security_pam_appl_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_security_pam_appl_h" >&5
+echo "${ECHO_T}$ac_cv_header_security_pam_appl_h" >&6
+
+fi
+if test $ac_cv_header_security_pam_appl_h = yes; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SECURITY_PAM_APPL_H 1
+_ACEOF
+
+ ac_pam_header_available=1
+fi
+
+
+
+ if test -z "$ac_pam_header_available"; then
+ if test "${ac_cv_header_pam_pam_appl_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for pam/pam_appl.h" >&5
+echo $ECHO_N "checking for pam/pam_appl.h... $ECHO_C" >&6
+if test "${ac_cv_header_pam_pam_appl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pam_pam_appl_h" >&5
+echo "${ECHO_T}$ac_cv_header_pam_pam_appl_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking pam/pam_appl.h usability" >&5
+echo $ECHO_N "checking pam/pam_appl.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <pam/pam_appl.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking pam/pam_appl.h presence" >&5
+echo $ECHO_N "checking pam/pam_appl.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <pam/pam_appl.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pam/pam_appl.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: pam/pam_appl.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to bug-cvs@nongnu.org ##
+## --------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for pam/pam_appl.h" >&5
+echo $ECHO_N "checking for pam/pam_appl.h... $ECHO_C" >&6
+if test "${ac_cv_header_pam_pam_appl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_pam_pam_appl_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pam_pam_appl_h" >&5
+echo "${ECHO_T}$ac_cv_header_pam_pam_appl_h" >&6
+
+fi
+if test $ac_cv_header_pam_pam_appl_h = yes; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PAM_PAM_APPL_H 1
+_ACEOF
+
+ ac_pam_header_available=1
+fi
+
+
+ fi
+
+ if test -z "$ac_pam_header_available"; then
+ { { echo "$as_me:$LINENO: error: Could not find PAM headers" >&5
+echo "$as_me: error: Could not find PAM headers" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PAM 1
+_ACEOF
+
+ echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5
+echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_pam_start+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pam_start ();
+int
+main ()
+{
+pam_start ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_pam_start=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pam_pam_start=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6
+if test $ac_cv_lib_pam_pam_start = yes; then
+ LIBS="${LIBS} -lpam"
+else
+ { { echo "$as_me:$LINENO: error: Could not find PAM libraries but the headers exist.
+ Give the --disable-pam option to compile without PAM support (or fix
+ your broken configuration)" >&5
+echo "$as_me: error: Could not find PAM libraries but the headers exist.
+ Give the --disable-pam option to compile without PAM support (or fix
+ your broken configuration)" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+
+ fi
+fi
+
+
+
+
+# Check whether --enable-case-sensitivity or --disable-case-sensitivity was given.
+if test "${enable_case_sensitivity+set}" = set; then
+ enableval="$enable_case_sensitivity"
+ case "$enable_case_sensitivity" in
+ yes | no | auto) ;;
+ *)
+ { { echo "$as_me:$LINENO: error: Unrecognized argument to --enable-case-sensitivity: \`$enable_case_sensitivity'. Acceptable values are \`yes', \`no', and \`auto'." >&5
+echo "$as_me: error: Unrecognized argument to --enable-case-sensitivity: \`$enable_case_sensitivity'. Acceptable values are \`yes', \`no', and \`auto'." >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+else
+ enable_case_sensitivity=auto
+fi;
+
+acx_forced=' (forced)'
+echo "$as_me:$LINENO: checking for a case sensitive file system" >&5
+echo $ECHO_N "checking for a case sensitive file system... $ECHO_C" >&6
+if test $enable_case_sensitivity = auto; then
+ if test "${acx_cv_case_sensitive+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ rm -f ac_TEST_filenames_CASE_sensitive
+ echo foo >ac_test_filenames_case_sensitive
+ if test -f ac_TEST_filenames_CASE_sensitive; then
+ acx_cv_case_sensitive=no
+ else
+ acx_cv_case_sensitive=yes
+ fi
+ rm ac_test_filenames_case_sensitive
+
+fi
+
+ enable_case_sensitivity=$acx_cv_case_sensitive
+ acx_forced=
+fi
+echo "$as_me:$LINENO: result: $enable_case_sensitivity$acx_forced" >&5
+echo "${ECHO_T}$enable_case_sensitivity$acx_forced" >&6
+if test $enable_case_sensitivity = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define FILENAMES_CASE_INSENSITIVE 1
+_ACEOF
+
+ case $LIBOBJS in
+ "fncase.$ac_objext" | \
+ *" fncase.$ac_objext" | \
+ "fncase.$ac_objext "* | \
+ *" fncase.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS fncase.$ac_objext" ;;
+esac
+
+fi
+
+
+
+
+# Check whether --enable-encryption or --disable-encryption was given.
+if test "${enable_encryption+set}" = set; then
+ enableval="$enable_encryption"
+
+else
+ enable_encryption=no
+fi;
+if test "x$enable_encryption" = xyes; then
+ if test xno = "x$with_client" && test xno = "x$with_server"; then
+ { echo "$as_me:$LINENO: WARNING: --enable-encryption is meaningless when neither the CVS client
+ nor the CVS server is enabled (--disable-client and --disable-server)." >&5
+echo "$as_me: WARNING: --enable-encryption is meaningless when neither the CVS client
+ nor the CVS server is enabled (--disable-client and --disable-server)." >&2;}
+ else
+
+cat >>confdefs.h <<\_ACEOF
+#define ENCRYPTION 1
+_ACEOF
+
+ fi
+fi
+
+
+
+
+# Check whether --enable-force-editor or --disable-force-editor was given.
+if test "${enable_force_editor+set}" = set; then
+ enableval="$enable_force_editor"
+
+else
+ enable_force_editor=no
+fi;
+
+if test yes = "$enable_force_editor"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define FORCE_USE_EDITOR 1
+_ACEOF
+
+fi
+
+
+
+
+# Check for options requesting client and server feature. If none are
+# given and we have connect(), we want the full client & server arrangement.
+# Check whether --enable-lock-compatibility or --disable-lock-compatibility was given.
+if test "${enable_lock_compatibility+set}" = set; then
+ enableval="$enable_lock_compatibility"
+
+else
+ enable_lock_compatibility=yes
+fi;
+
+if test x$enable_lock_compatibility = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define LOCK_COMPATIBILITY 1
+_ACEOF
+
+fi
+
+
+
+
+# Check whether --enable-rootcommit or --disable-rootcommit was given.
+if test "${enable_rootcommit+set}" = set; then
+ enableval="$enable_rootcommit"
+
+else
+ enable_rootcommit=no
+fi;
+if test "$enable_rootcommit" = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define CVS_BADROOT 1
+_ACEOF
+
+fi
+
+
+# Check whether --enable-old-info-support or --disable-old-info-support was given.
+if test "${enable_old_info_support+set}" = set; then
+ enableval="$enable_old_info_support"
+
+else
+ enable_old_info_format_support=yes
+fi;
+if test "$enable_old_info_format_support" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define SUPPORT_OLD_INFO_FMT_STRINGS 1
+_ACEOF
+
+fi
+
+
+
+
+# Check whether --enable-config-override or --disable-config-override was given.
+if test "${enable_config_override+set}" = set; then
+ enableval="$enable_config_override"
+
+else
+ # $sysconfdir may still contain variable references. By default, this will
+ # be to $prefix, and $prefix won't be set to its default value until later.
+ # Compromise without setting $prefix for the rest of the file.
+ cvs_save_prefix=$prefix
+ if test "X$prefix" = XNONE; then
+ prefix=$ac_prefix_default
+ fi
+ eval enable_config_override=`echo $sysconfdir/cvs.conf,$sysconfdir/cvs/`
+ prefix=$cvs_save_prefix
+fi;
+
+if test x"$enable_config_override" = xyes; then
+ enable_config_override=/
+fi
+
+if test x"$enable_config_override" = xno; then :; else
+ save_IFS=$IFS
+ IFS=,
+ arrayinit=""
+ for path in $enable_config_override; do
+ IFS=$save_IFS
+ case "$path" in
+ [\\/$]* | ?:[\\/]* )
+ arrayinit="$arrayinit\"$path\", "
+ ;;
+ *) { { echo "$as_me:$LINENO: error: expected comma separated list of absolute directory
+ names for --enable-config-override, or \`no', not:
+ \`$enable_config_override'
+ (\`$path' invalid.)" >&5
+echo "$as_me: error: expected comma separated list of absolute directory
+ names for --enable-config-override, or \`no', not:
+ \`$enable_config_override'
+ (\`$path' invalid.)" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+ done
+ arrayinit="${arrayinit}NULL"
+
+
+cat >>confdefs.h <<_ACEOF
+#define ALLOW_CONFIG_OVERRIDE $arrayinit
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for cygwin32" >&5
+echo $ECHO_N "checking for cygwin32... $ECHO_C" >&6
+if test "${ccvs_cv_sys_cygwin32+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+return __CYGWIN32__;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ccvs_cv_sys_cygwin32=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ccvs_cv_sys_cygwin32=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ccvs_cv_sys_cygwin32" >&5
+echo "${ECHO_T}$ccvs_cv_sys_cygwin32" >&6
+if test $ccvs_cv_sys_cygwin32 = yes; then
+ LIBS="$LIBS -ladvapi32"
+
+
+cat >>confdefs.h <<\_ACEOF
+#define UTIME_EXPECTS_WRITABLE 1
+_ACEOF
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_SETMODE_STDOUT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SETMODE 1
+_ACEOF
+
+fi
+
+ ac_config_files="$ac_config_files contrib/validate_repo"
+
+ ac_config_files="$ac_config_files contrib/clmerge"
+
+ ac_config_files="$ac_config_files contrib/cln_hist"
+
+ ac_config_files="$ac_config_files contrib/commit_prep"
+
+ ac_config_files="$ac_config_files contrib/cvs_acls"
+
+ ac_config_files="$ac_config_files contrib/log"
+
+ ac_config_files="$ac_config_files contrib/log_accum"
+
+ ac_config_files="$ac_config_files contrib/mfpipe"
+
+ ac_config_files="$ac_config_files contrib/pvcs2rcs"
+
+ ac_config_files="$ac_config_files contrib/rcs2log:contrib/rcs2log.sh"
+
+ ac_config_files="$ac_config_files contrib/rcslock"
+
+ ac_config_files="$ac_config_files contrib/sccs2rcs"
+
+ ac_config_files="$ac_config_files doc/mkman:doc/mkman.pl"
+
+ ac_config_files="$ac_config_files src/cvsbug"
+
+
+ ac_config_files="$ac_config_files Makefile contrib/Makefile contrib/pam/Makefile cvs.spec diff/Makefile doc/Makefile doc/i18n/Makefile doc/i18n/pt_BR/Makefile emx/Makefile lib/Makefile maint-aux/Makefile man/Makefile os2/Makefile src/Makefile src/sanity.config.sh tools/Makefile vms/Makefile windows-NT/Makefile windows-NT/SCC/Makefile zlib/Makefile"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${MAKE_TARGETS_IN_VPATH_TRUE}" && test -z "${MAKE_TARGETS_IN_VPATH_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MAKE_TARGETS_IN_VPATH\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MAKE_TARGETS_IN_VPATH\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by Concurrent Versions System (CVS) $as_me 1.12.13, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+Concurrent Versions System (CVS) config.status 1.12.13
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS section.
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+# Capture the value of obsolete ALL_LINGUAS because we need it to compute
+ # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it
+ # from automake.
+ eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"'
+ # Capture the value of LINGUAS because we need it to compute CATALOGS.
+ LINGUAS="${LINGUAS-%UNSET%}"
+
+
+_ACEOF
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "contrib/validate_repo" ) CONFIG_FILES="$CONFIG_FILES contrib/validate_repo" ;;
+ "contrib/clmerge" ) CONFIG_FILES="$CONFIG_FILES contrib/clmerge" ;;
+ "contrib/cln_hist" ) CONFIG_FILES="$CONFIG_FILES contrib/cln_hist" ;;
+ "contrib/commit_prep" ) CONFIG_FILES="$CONFIG_FILES contrib/commit_prep" ;;
+ "contrib/cvs_acls" ) CONFIG_FILES="$CONFIG_FILES contrib/cvs_acls" ;;
+ "contrib/log" ) CONFIG_FILES="$CONFIG_FILES contrib/log" ;;
+ "contrib/log_accum" ) CONFIG_FILES="$CONFIG_FILES contrib/log_accum" ;;
+ "contrib/mfpipe" ) CONFIG_FILES="$CONFIG_FILES contrib/mfpipe" ;;
+ "contrib/pvcs2rcs" ) CONFIG_FILES="$CONFIG_FILES contrib/pvcs2rcs" ;;
+ "contrib/rcs2log" ) CONFIG_FILES="$CONFIG_FILES contrib/rcs2log:contrib/rcs2log.sh" ;;
+ "contrib/rcslock" ) CONFIG_FILES="$CONFIG_FILES contrib/rcslock" ;;
+ "contrib/sccs2rcs" ) CONFIG_FILES="$CONFIG_FILES contrib/sccs2rcs" ;;
+ "doc/mkman" ) CONFIG_FILES="$CONFIG_FILES doc/mkman:doc/mkman.pl" ;;
+ "src/cvsbug" ) CONFIG_FILES="$CONFIG_FILES src/cvsbug" ;;
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "contrib/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;;
+ "contrib/pam/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/pam/Makefile" ;;
+ "cvs.spec" ) CONFIG_FILES="$CONFIG_FILES cvs.spec" ;;
+ "diff/Makefile" ) CONFIG_FILES="$CONFIG_FILES diff/Makefile" ;;
+ "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "doc/i18n/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/i18n/Makefile" ;;
+ "doc/i18n/pt_BR/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/i18n/pt_BR/Makefile" ;;
+ "emx/Makefile" ) CONFIG_FILES="$CONFIG_FILES emx/Makefile" ;;
+ "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
+ "maint-aux/Makefile" ) CONFIG_FILES="$CONFIG_FILES maint-aux/Makefile" ;;
+ "man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
+ "os2/Makefile" ) CONFIG_FILES="$CONFIG_FILES os2/Makefile" ;;
+ "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+ "src/sanity.config.sh" ) CONFIG_FILES="$CONFIG_FILES src/sanity.config.sh" ;;
+ "tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
+ "vms/Makefile" ) CONFIG_FILES="$CONFIG_FILES vms/Makefile" ;;
+ "windows-NT/Makefile" ) CONFIG_FILES="$CONFIG_FILES windows-NT/Makefile" ;;
+ "windows-NT/SCC/Makefile" ) CONFIG_FILES="$CONFIG_FILES windows-NT/SCC/Makefile" ;;
+ "zlib/Makefile" ) CONFIG_FILES="$CONFIG_FILES zlib/Makefile" ;;
+ "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@CYGPATH_W@,$CYGPATH_W,;t t
+s,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@ACLOCAL@,$ACLOCAL,;t t
+s,@AUTOCONF@,$AUTOCONF,;t t
+s,@AUTOMAKE@,$AUTOMAKE,;t t
+s,@AUTOHEADER@,$AUTOHEADER,;t t
+s,@MAKEINFO@,$MAKEINFO,;t t
+s,@install_sh@,$install_sh,;t t
+s,@STRIP@,$STRIP,;t t
+s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
+s,@mkdir_p@,$mkdir_p,;t t
+s,@AWK@,$AWK,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@am__leading_dot@,$am__leading_dot,;t t
+s,@AMTAR@,$AMTAR,;t t
+s,@am__tar@,$am__tar,;t t
+s,@am__untar@,$am__untar,;t t
+s,@ac_prefix_program@,$ac_prefix_program,;t t
+s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t
+s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t
+s,@MAINT@,$MAINT,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@DEPDIR@,$DEPDIR,;t t
+s,@am__include@,$am__include,;t t
+s,@am__quote@,$am__quote,;t t
+s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t
+s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t
+s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
+s,@CCDEPMODE@,$CCDEPMODE,;t t
+s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t
+s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@LN_S@,$LN_S,;t t
+s,@PERL@,$PERL,;t t
+s,@CSH@,$CSH,;t t
+s,@MKTEMP@,$MKTEMP,;t t
+s,@SENDMAIL@,$SENDMAIL,;t t
+s,@PR@,$PR,;t t
+s,@ROFF@,$ROFF,;t t
+s,@PS2PDF@,$PS2PDF,;t t
+s,@TEXI2DVI@,$TEXI2DVI,;t t
+s,@MAKE_TARGETS_IN_VPATH_TRUE@,$MAKE_TARGETS_IN_VPATH_TRUE,;t t
+s,@MAKE_TARGETS_IN_VPATH_FALSE@,$MAKE_TARGETS_IN_VPATH_FALSE,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@ALLOCA@,$ALLOCA,;t t
+s,@ALLOCA_H@,$ALLOCA_H,;t t
+s,@STDBOOL_H@,$STDBOOL_H,;t t
+s,@HAVE__BOOL@,$HAVE__BOOL,;t t
+s,@FNMATCH_H@,$FNMATCH_H,;t t
+s,@YACC@,$YACC,;t t
+s,@YFLAGS@,$YFLAGS,;t t
+s,@LIB_CLOCK_GETTIME@,$LIB_CLOCK_GETTIME,;t t
+s,@GETOPT_H@,$GETOPT_H,;t t
+s,@GLOB_H@,$GLOB_H,;t t
+s,@LIB_NANOSLEEP@,$LIB_NANOSLEEP,;t t
+s,@HAVE_LONG_64BIT@,$HAVE_LONG_64BIT,;t t
+s,@HAVE_LONG_LONG_64BIT@,$HAVE_LONG_LONG_64BIT,;t t
+s,@STDINT_H@,$STDINT_H,;t t
+s,@EOVERFLOW@,$EOVERFLOW,;t t
+s,@MKINSTALLDIRS@,$MKINSTALLDIRS,;t t
+s,@USE_NLS@,$USE_NLS,;t t
+s,@MSGFMT@,$MSGFMT,;t t
+s,@GMSGFMT@,$GMSGFMT,;t t
+s,@XGETTEXT@,$XGETTEXT,;t t
+s,@MSGMERGE@,$MSGMERGE,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@INTL_MACOSX_LIBS@,$INTL_MACOSX_LIBS,;t t
+s,@LIBICONV@,$LIBICONV,;t t
+s,@LTLIBICONV@,$LTLIBICONV,;t t
+s,@INTLLIBS@,$INTLLIBS,;t t
+s,@LIBINTL@,$LIBINTL,;t t
+s,@LTLIBINTL@,$LTLIBINTL,;t t
+s,@POSUB@,$POSUB,;t t
+s,@cvs_client_objects@,$cvs_client_objects,;t t
+s,@KRB4@,$KRB4,;t t
+s,@ZLIB_SUBDIRS@,$ZLIB_SUBDIRS,;t t
+s,@ZLIB_CPPFLAGS@,$ZLIB_CPPFLAGS,;t t
+s,@ZLIB_LIBS@,$ZLIB_LIBS,;t t
+s,@with_default_rsh@,$with_default_rsh,;t t
+s,@RSH_DFLT@,$RSH_DFLT,;t t
+s,@EDITOR@,$EDITOR,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+/@MKTEMP_SH_FUNCTION@/r $MKTEMP_SH_FUNCTION
+s,@MKTEMP_SH_FUNCTION@,,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+ # Run the commands associated with the file.
+ case $ac_file in
+ contrib/validate_repo ) chmod +x contrib/validate_repo ;;
+ contrib/clmerge ) chmod +x contrib/clmerge ;;
+ contrib/cln_hist ) chmod +x contrib/cln_hist ;;
+ contrib/commit_prep ) chmod +x contrib/commit_prep ;;
+ contrib/cvs_acls ) chmod +x contrib/cvs_acls ;;
+ contrib/log ) chmod +x contrib/log ;;
+ contrib/log_accum ) chmod +x contrib/log_accum ;;
+ contrib/mfpipe ) chmod +x contrib/mfpipe ;;
+ contrib/pvcs2rcs ) chmod +x contrib/pvcs2rcs ;;
+ contrib/rcs2log ) chmod +x contrib/rcs2log ;;
+ contrib/rcslock ) chmod +x contrib/rcslock ;;
+ contrib/sccs2rcs ) chmod +x contrib/sccs2rcs ;;
+ doc/mkman ) chmod +x doc/mkman ;;
+ src/cvsbug ) chmod +x src/cvsbug ;;
+ esac
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ # Do quote $f, to prevent DOS paths from being IFS'd.
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+# Compute $ac_file's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $ac_file | $ac_file:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null ||
+$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X$ac_file : 'X\(//\)[^/]' \| \
+ X$ac_file : 'X\(//\)$' \| \
+ X$ac_file : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X$ac_file |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_COMMANDS section.
+#
+for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
+ ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
+ ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
+$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_dest" : 'X\(//\)[^/]' \| \
+ X"$ac_dest" : 'X\(//\)$' \| \
+ X"$ac_dest" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_dest" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
+echo "$as_me: executing $ac_dest commands" >&6;}
+ case $ac_dest in
+ depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`(dirname "$mf") 2>/dev/null ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`(dirname "$file") 2>/dev/null ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p $dirpart/$fdir
+ else
+ as_dir=$dirpart/$fdir
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+ default-1 )
+ for ac_file in $CONFIG_FILES; do
+ # Support "outfile[:infile[:infile...]]"
+ case "$ac_file" in
+ *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ esac
+ # PO directories have a Makefile.in generated from Makefile.in.in.
+ case "$ac_file" in */Makefile.in)
+ # Adjust a relative srcdir.
+ ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+ ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+ ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+ # In autoconf-2.13 it is called $ac_given_srcdir.
+ # In autoconf-2.50 it is called $srcdir.
+ test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+ case "$ac_given_srcdir" in
+ .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+ /*) top_srcdir="$ac_given_srcdir" ;;
+ *) top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+ # Treat a directory as a PO directory if and only if it has a
+ # POTFILES.in file. This allows packages to have multiple PO
+ # directories under different names or in different locations.
+ if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then
+ rm -f "$ac_dir/POTFILES"
+ test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES"
+ cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES"
+ POMAKEFILEDEPS="POTFILES.in"
+ # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend
+ # on $ac_dir but don't depend on user-specified configuration
+ # parameters.
+ if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+ # The LINGUAS file contains the set of available languages.
+ if test -n "$OBSOLETE_ALL_LINGUAS"; then
+ test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+ fi
+ ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+ # Hide the ALL_LINGUAS assigment from automake.
+ eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+ POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+ else
+ # The set of available languages was given in configure.in.
+ eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS'
+ fi
+ # Compute POFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
+ # Compute UPDATEPOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
+ # Compute DUMMYPOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
+ # Compute GMOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
+ case "$ac_given_srcdir" in
+ .) srcdirpre= ;;
+ *) srcdirpre='$(srcdir)/' ;;
+ esac
+ POFILES=
+ UPDATEPOFILES=
+ DUMMYPOFILES=
+ GMOFILES=
+ for lang in $ALL_LINGUAS; do
+ POFILES="$POFILES $srcdirpre$lang.po"
+ UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+ DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+ GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+ done
+ # CATALOGS depends on both $ac_dir and the user's LINGUAS
+ # environment variable.
+ INST_LINGUAS=
+ if test -n "$ALL_LINGUAS"; then
+ for presentlang in $ALL_LINGUAS; do
+ useit=no
+ if test "%UNSET%" != "$LINGUAS"; then
+ desiredlanguages="$LINGUAS"
+ else
+ desiredlanguages="$ALL_LINGUAS"
+ fi
+ for desiredlang in $desiredlanguages; do
+ # Use the presentlang catalog if desiredlang is
+ # a. equal to presentlang, or
+ # b. a variant of presentlang (because in this case,
+ # presentlang can be used as a fallback for messages
+ # which are not translated in the desiredlang catalog).
+ case "$desiredlang" in
+ "$presentlang"*) useit=yes;;
+ esac
+ done
+ if test $useit = yes; then
+ INST_LINGUAS="$INST_LINGUAS $presentlang"
+ fi
+ done
+ fi
+ CATALOGS=
+ if test -n "$INST_LINGUAS"; then
+ for lang in $INST_LINGUAS; do
+ CATALOGS="$CATALOGS $lang.gmo"
+ done
+ fi
+ test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile"
+ sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile"
+ for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do
+ if test -f "$f"; then
+ case "$f" in
+ *.orig | *.bak | *~) ;;
+ *) cat "$f" >> "$ac_dir/Makefile" ;;
+ esac
+ fi
+ done
+ fi
+ ;;
+ esac
+ done ;;
+ esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+
+
+# Report the state of this version of CVS if this is from dev.
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..bea30e8
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,1596 @@
+dnl configure.in for cvs
+
+AC_COPYRIGHT(
+[Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.])
+
+AC_INIT([Concurrent Versions System (CVS)],[1.12.13],
+ [bug-cvs@nongnu.org],[cvs])
+AC_CONFIG_SRCDIR(src/cvs.h)
+AC_CONFIG_AUX_DIR(build-aux)
+AM_INIT_AUTOMAKE([gnu 1.9.2 dist-bzip2 no-define])
+AC_PREREQ(2.59)
+
+AC_PREFIX_PROGRAM(cvs)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+dnl This needs to be called to enable certain system extensions before calling
+dnl a C compiler.
+gl_EARLY
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+
+# Find the posix library needed on INTERACTIVE UNIX (ISC)
+dnl
+dnl From the Autoconf 2.53 manual (AC_ISC_POSIX):
+dnl
+dnl For INTERACTIVE UNIX (ISC), add `-lcposix' to output variable
+dnl `LIBS' if necessary for POSIX facilities. Call this after
+dnl `AC_PROG_CC' and before any other macros that use POSIX
+dnl interfaces. INTERACTIVE UNIX is no longer sold, and Sun says that
+dnl they will drop support for it on 2006-07-23, so this macro is
+dnl becoming obsolescent.
+dnl
+AC_SEARCH_LIBS([strerror], [cposix])
+
+dnl
+dnl Autoconf stopped setting $ISC sometime before 2.53
+dnl
+dnl If this is still important, someone should come up with a generic test
+dnl for whether _SYSV3 needs to be defined. Removed code below:
+dnl
+dnl if test "$ISC" = yes; then
+dnl CFLAGS="$CFLAGS -D_SYSV3"
+dnl # And I don't like this... In theory it should be found later if server is
+dnl # enabled, but maybe something on INTERACTIVE UNIX (ISC) we didn't ask to
+dnl # link with crypt tries? Anyhow, the autoconf manual says we can delete
+dnl # this ISC stuff on or after 2006-07-23 when Sun discontinues support and
+dnl # ISC becomes obsolescent, but I suppose that is probably a matter of
+dnl # opinion.
+dnl #
+dnl # N.B. The reason for doing this is that some moron decided to put a stub
+dnl # for crypt in libc that always returns NULL. Without this here, the later
+dnl # check will find the stub instead of the real thing, resulting in a server
+dnl # that can't process crypted passwords correctly.
+dnl
+dnl # again, if we have to try and reenable this for ISC, someone should come
+dnl # up with a generic test that figures out whether crypt is good or not -
+dnl # Is it always returning NULL?
+dnl LIBS="-lcrypt $LIBS"
+dnl fi
+dnl
+dnl FIXME - This has been broken for at least a few months anyhow, so I'm
+dnl removing the crypt lib define above, but the correct fix would be to
+dnl provide a CRYPT_WORKS macro or the like that gets called sometime after
+dnl the AC_SEARCH_LIBS call that normally finds crypt, and if crypt doesn't
+dnl work, the macro should be retried with LIBS="-lcrypt $LIBS" forced.
+dnl
+
+AC_PROG_RANLIB
+AC_PROG_LN_S
+AC_SYS_LARGEFILE
+AC_EXEEXT
+
+AC_PATH_PROG(PERL, perl, no)
+AC_PATH_PROG(CSH, csh, no)
+# for contrib/rcs2log.sh & src/cvsbug.in.
+AC_PATH_PROG(MKTEMP, mktemp, mktemp)
+if test x"$MKTEMP" = xmktemp; then
+ MKTEMP_SH_FUNCTION=$srcdir/mktemp.sh
+else
+ MKTEMP_SH_FUNCTION=/dev/null
+fi
+AC_SUBST_FILE(MKTEMP_SH_FUNCTION)
+# for src/cvsbug.in
+AC_PATH_PROG(SENDMAIL, sendmail, no, [$PATH:/usr/sbin:/usr/lib])
+# For diff/util.c
+AC_PATH_PROG(PR, pr, no)
+if test x"$PR" != xno; then
+ AC_DEFINE_UNQUOTED([PR_PROGRAM], ["$PR"], [Path to the pr utility])
+fi
+
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+dnl FIXME I pulled this default list from sanity.sh. Perhaps these lists
+dnl can be stored in one location?
+dnl
+dnl Yeah, put the value in a variable add it to the substitution list
+dnl then have configure create sanity.sh from sanity.sh.in...
+glocs="$PATH:/usr/local/bin:/usr/contrib/bin:/usr/gnu/bin:/local/bin:/local/gnu/bin:/gnu/bin"
+AC_PATH_PROGS(ROFF, groff roff, $missing_dir/missing roff, $glocs)
+AC_PATH_PROG(PS2PDF, ps2pdf, $missing_dir/missing ps2pdf)
+AC_PATH_PROG(TEXI2DVI, texi2dvi, $missing_dir/missing texi2dvi)
+
+AC_SYS_INTERPRETER
+if test X"$ac_cv_sys_interpreter" != X"yes" ; then
+ # silly trick to avoid problems in AC macros...
+ ac_msg='perl scripts using #! may not be invoked properly'
+ AC_MSG_WARN($ac_msg)
+fi
+
+# BSD's logo is a devil for a reason, hey?
+AC_CACHE_CHECK(for BSD VPATH bug in make, ccvs_cv_bsd_make_vpath_bug,
+[if test ! -d ac_test_dir ; then
+ AC_TRY_COMMAND([mkdir ac_test_dir])
+fi
+cat >conftestmake <<EOF
+VPATH = ac_test_dir
+ac_test_target: ac_test_dep
+ echo BSD VPATH bug present >&2
+ac_test_dep: ac_test_dep_dep
+EOF
+touch ac_test_dir/ac_test_dep_dep
+touch ac_test_dir/ac_test_dep
+touch ac_test_target
+# Don't know why, but the following test doesn't work under FreeBSD 4.2
+# without this sleep command
+sleep 1
+if AC_TRY_COMMAND([make -f conftestmake 2>&1 >/dev/null |grep ^BSD\ VPATH\ bug\ present\$ >/dev/null]) ; then
+ ccvs_cv_bsd_make_vpath_bug=yes
+else
+ ccvs_cv_bsd_make_vpath_bug=no
+fi
+AC_TRY_COMMAND([rm -rf ac_test_dir ac_test_target conftestmake])])
+# We also don't need to worry about the bug when $srcdir = $builddir
+AM_CONDITIONAL(MAKE_TARGETS_IN_VPATH, \
+ test $ccvs_cv_bsd_make_vpath_bug = no \
+ || test $srcdir = .)
+
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(\
+ direct.h \
+ fcntl.h \
+ io.h \
+ memory.h \
+ ndbm.h \
+ stdint.h \
+ syslog.h \
+ sys/bsdtypes.h \
+ sys/file.h \
+ sys/param.h \
+ sys/resource.h \
+ sys/select.h \
+ unistd.h \
+ utime.h\
+)
+AC_HEADER_STAT
+
+AC_C_CONST
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_TYPE_SIGNAL
+
+AC_CHECK_MEMBERS([struct stat.st_blksize])
+AC_CHECK_MEMBERS([struct stat.st_rdev])
+
+AC_FUNC_FSEEKO
+if test $ac_cv_func_fseeko = no; then
+ AC_LIBOBJ(fseeko)
+ AC_LIBOBJ(ftello)
+fi
+
+# Replace functions with versions in lib/ when they can't be found.
+AC_REPLACE_FUNCS(\
+ waitpid \
+)
+
+#
+# Special hack for a SunOS 5.7 (aka Solaris 7) select() problem.
+#
+ccvs_FUNC_SELECT
+
+#
+# Begin GNULIB stuff.
+#
+
+# Look for functions from GNULIB and replace with versions in lib/ when
+# necessary.
+dnl This calls most of the GNULIB macros we need via the
+dnl autogenerated m4/gnulib.m4.
+gl_INIT
+dnl For one reason or another, the autogenerated m4/gnulib.m4 wants
+dnl AM_GNU_GETTEXT([external]) called directly from here.
+AM_GNU_GETTEXT([external])
+AM_GNU_GETTEXT_VERSION dnl work around for autoconf-2.57 bug.
+# The error module still poses merge problems.
+AC_FUNC_STRERROR_R
+dnl The following macros can be called by other GNULIB macros but are also
+dnl used by the UNIQUE_*_TYPE stuff below. I don't want to rely on the GNULIB
+dnl macros which call these to continue to do so, so use AC_REQUIRE, which can
+dnl only be called from within another macro, to only call them only once.
+AC_DEFUN([CCVS_CALL_GNULIB_MACROS_ONCE],
+[AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+AC_REQUIRE([gt_TYPE_WCHAR_T])
+AC_REQUIRE([gt_TYPE_WINT_T])
+AC_REQUIRE([gl_AC_TYPE_INTMAX_T])
+AC_REQUIRE([gl_FUNC_MMAP_ANON])
+AC_REQUIRE([gl_AC_TYPE_LONG_LONG])])
+CCVS_CALL_GNULIB_MACROS_ONCE()
+dnl Until I persuade the GNULIB folks to integrate this module.
+gl_GLOB
+
+#
+# End GNULIB stuff.
+#
+
+
+
+# Check for function existance.
+AC_CHECK_FUNCS(\
+ fchdir \
+ fchmod \
+ fsync \
+ ftime \
+ geteuid \
+ getgroups \
+ getpagesize \
+ gettimeofday \
+ initgroups \
+ login \
+ logout \
+ mknod \
+ regcomp \
+ regerror \
+ regexec \
+ regfree \
+ sigaction \
+ sigblock \
+ sigprocmask \
+ sigsetmask \
+ sigvec \
+ timezone \
+ tzset \
+ vprintf \
+ wait3 \
+)
+
+dnl
+dnl Find the sizes of various types and set a variable for some if they
+dnl are "unique", meaning it does not share a size with a lower precedence
+dnl type.
+dnl
+dnl also, I snagged this cross_compiling line from openldap's autoconf,
+dnl because I can't figure out how to stop autoconf from giving cross compiler
+dnl related warnings each time the AC_CHECK_SIZEOF function is run
+dnl
+if test $cross_compiling = yes ; then
+ AC_DEFINE(CROSS_COMPILING, 1, [define if cross compiling])
+else
+ AC_CHECK_SIZEOF(char)
+ AC_CACHE_CHECK(for uniquely sized char,
+ ccvs_cv_unique_int_type_char,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_char)" >/dev/null ; then
+ ccvs_cv_unique_int_type_char=no
+ else
+ ccvs_cv_unique_int_type_char=yes\($ac_cv_sizeof_char\)
+ fi])
+ if test $ccvs_cv_unique_int_type_char != no ; then
+ AC_DEFINE( UNIQUE_INT_TYPE_CHAR, 1,
+ [Define if char is the first integer type
+ detected with its size.])
+ fi
+ AC_CHECK_SIZEOF(short)
+ AC_CACHE_CHECK(for uniquely sized short,
+ ccvs_cv_unique_int_type_short,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_short)" >/dev/null ; then
+ ccvs_cv_unique_int_type_short=no
+ else
+ ccvs_cv_unique_int_type_short=yes\($ac_cv_sizeof_short\)
+ fi])
+ if test $ccvs_cv_unique_int_type_short != no ; then
+ AC_DEFINE( UNIQUE_INT_TYPE_SHORT, 1,
+ [Define if short is the first integer type
+ detected with its size.])
+ fi
+ AC_CHECK_SIZEOF(int)
+ AC_CACHE_CHECK(for uniquely sized int,
+ ccvs_cv_unique_int_type_int,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_int)" >/dev/null ; then
+ ccvs_cv_unique_int_type_int=no
+ else
+ ccvs_cv_unique_int_type_int=yes\($ac_cv_sizeof_int\)
+ fi])
+ if test $ccvs_cv_unique_int_type_int != no ; then
+ AC_DEFINE( UNIQUE_INT_TYPE_INT, 1,
+ [Define if int is the first integer type
+ detected with its size.])
+ fi
+ AC_CHECK_SIZEOF(long)
+ AC_CACHE_CHECK(for uniquely sized long,
+ ccvs_cv_unique_int_type_long,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_long)" >/dev/null ; then
+ ccvs_cv_unique_int_type_long=no
+ else
+ ccvs_cv_unique_int_type_long=yes\($ac_cv_sizeof_long\)
+ fi])
+ if test $ccvs_cv_unique_int_type_long != no ; then
+ AC_DEFINE(UNIQUE_INT_TYPE_LONG, 1,
+ [Define if long int is the first integer type
+ detected with its size.])
+ fi
+ if test $ac_cv_type_long_long != no; then
+ AC_CHECK_SIZEOF(long long)
+ AC_CACHE_CHECK(for uniquely sized long long,
+ ccvs_cv_unique_int_type_long_long,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_long_long)" >/dev/null ; then
+ ccvs_cv_unique_int_type_long_long=no
+ else
+ ccvs_cv_unique_int_type_long_long=yes\($ac_cv_sizeof_long_long\)
+ fi])
+ if test $ccvs_cv_unique_int_type_long_long != no ; then
+ AC_DEFINE(UNIQUE_INT_TYPE_LONG_LONG, 1,
+ [Define if long long is the first integer type
+ detected with its size.])
+ fi
+ fi
+ AC_CHECK_SIZEOF(size_t)
+ AC_CACHE_CHECK(for uniquely sized size_t,
+ ccvs_cv_unique_int_type_size_t,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_size_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_size_t=no
+ else
+ ccvs_cv_unique_int_type_size_t=yes\($ac_cv_sizeof_size_t\)
+ fi])
+ if test $ccvs_cv_unique_int_type_size_t != no ; then
+ AC_DEFINE(UNIQUE_INT_TYPE_SIZE_T, 1,
+ [Define if size_t is the first integer type
+ detected with its size.])
+ fi
+ AC_CHECK_SIZEOF(ptrdiff_t)
+ AC_CACHE_CHECK(for uniquely sized ptrdiff_t,
+ ccvs_cv_unique_int_type_ptrdiff_t,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_ptrdiff_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_ptrdiff_t=no
+ else
+ ccvs_cv_unique_int_type_ptrdiff_t=yes\($ac_cv_sizeof_ptrdiff_t\)
+ fi])
+ if test $ccvs_cv_unique_int_type_ptrdiff_t != no ; then
+ AC_DEFINE(UNIQUE_INT_TYPE_PTRDIFF_T, 1,
+ [Define if ptrdiff_t is the first integer type
+ detected with its size.])
+ fi
+ if test $gt_cv_c_wint_t != no; then
+ AC_CHECK_SIZEOF(wint_t, [], [[#include <stdio.h>
+#include <wchar.h>
+]])
+ AC_CACHE_CHECK(for uniquely sized wint_t,
+ ccvs_cv_unique_int_type_wint_t,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_wint_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_wint_t=no
+ else
+ ccvs_cv_unique_int_type_wint_t=yes\($ac_cv_sizeof_wint_t\)
+ fi])
+ if test $ccvs_cv_unique_int_type_wint_t != no ; then
+ AC_DEFINE( UNIQUE_INT_TYPE_WINT_T, 1,
+ [Define if wint_t is the first integer type
+ detected with its size.])
+ fi
+ fi
+ if test $gt_cv_c_intmax_t != no; then
+ AC_CHECK_SIZEOF(intmax_t, [], [[#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+]])
+ AC_CACHE_CHECK(for uniquely sized intmax_t,
+ ccvs_cv_unique_int_type_intmax_t,
+ [if set |grep ^ccvs_cv_unique_int_type_ \
+ |grep "($ac_cv_sizeof_intmax_t)" >/dev/null ; then
+ ccvs_cv_unique_int_type_intmax_t=no
+ else
+ ccvs_cv_unique_int_type_intmax_t=yes\($ac_cv_sizeof_intmax_t\)
+ fi])
+ if test $ccvs_cv_unique_int_type_intmax_t != no ; then
+ AC_DEFINE( UNIQUE_INT_TYPE_INTMAX_T, 1,
+ [Define if intmax_t is the first integer type
+ detected with its size.])
+ fi
+ fi
+
+ dnl
+ dnl and the same for floats...
+ dnl
+ AC_CHECK_SIZEOF(float)
+ AC_CACHE_CHECK(for uniquely sized float,
+ ccvs_cv_unique_float_type_float,
+ [if set |grep ^ccvs_cv_unique_float_type_ \
+ |grep "($ac_cv_sizeof_float)" >/dev/null ; then
+ ccvs_cv_unique_float_type_float=no
+ else
+ ccvs_cv_unique_float_type_float=yes\($ac_cv_sizeof_float\)
+ fi])
+ if test $ccvs_cv_unique_float_type_float != no ; then
+ AC_DEFINE( UNIQUE_FLOAT_TYPE_FLOAT, 1,
+ [Define if float is the first floating point type
+ detected with its size.])
+ fi
+ AC_CHECK_SIZEOF(double)
+ AC_CACHE_CHECK(for uniquely sized double,
+ ccvs_cv_unique_float_type_double,
+ [if set |grep ^ccvs_cv_unique_float_type_ \
+ |grep "($ac_cv_sizeof_double)" >/dev/null ; then
+ ccvs_cv_unique_float_type_double=no
+ else
+ ccvs_cv_unique_float_type_double=yes\($ac_cv_sizeof_double\)
+ fi])
+ if test $ccvs_cv_unique_float_type_double != no ; then
+ AC_DEFINE( UNIQUE_FLOAT_TYPE_DOUBLE, 1,
+ [Define if double is the first floating point type
+ detected with its size.])
+ fi
+ if test $gt_cv_c_long_double != no; then
+ AC_CHECK_SIZEOF(long double)
+ AC_CACHE_CHECK(for uniquely sized long double,
+ ccvs_cv_unique_float_type_long_double,
+ [if set |grep ^ccvs_cv_unique_float_type_ \
+ |grep "($ac_cv_sizeof_long_double)" >/dev/null ; then
+ ccvs_cv_unique_float_type_long_double=no
+ else
+ ccvs_cv_unique_float_type_long_double=yes\($ac_cv_sizeof_long_double\)
+ fi])
+ if test $ccvs_cv_unique_float_type_long_double != no ; then
+ AC_DEFINE(UNIQUE_FLOAT_TYPE_LONG_DOUBLE, 1,
+ [Define if long double is the first floating point
+ type detected with its size.])
+ fi
+ fi
+fi
+
+dnl
+dnl The CVS coding standard (as specified in HACKING) is that if it exists
+dnl in SunOS4 and ANSI, we use it. CVS itself, of course, therefore doesn't
+dnl need HAVE_* defines for such functions, but diff wants them.
+dnl
+AC_DEFINE(HAVE_STRCHR, 1,
+[Define if you have strchr (always for CVS).])
+AC_DEFINE(HAVE_MEMCHR, 1,
+[Define if you have memchr (always for CVS).])
+
+dnl
+dnl Force lib/regex.c to use malloc instead of messing around with alloca
+dnl and define the old re_comp routines that we use.
+dnl
+AC_DEFINE(REGEX_MALLOC, 1,
+[Define to force lib/regex.c to use malloc instead of alloca.])
+AC_DEFINE(_REGEX_RE_COMP, 1,
+[Define to force lib/regex.c to define re_comp et al.])
+dnl
+dnl AC_FUNC_FORK([]) is rather baroque. It seems to be rather more picky
+dnl than, say, the Single Unix Specification (version 2), which simplifies
+dnl a lot of cases by saying that the child process can't set any variables
+dnl (thus avoiding problems with register allocation) or call any functions
+dnl (thus avoiding problems with whether file descriptors are shared).
+dnl It would be nice if we could just write to the Single Unix Specification.
+dnl I think the only way to do redirection this way is by doing it in the
+dnl parent, and then undoing it afterwards (analogous to windows-NT/run.c).
+dnl That would appear to have a race condition if the user hits ^C (or
+dnl some other signal) at the wrong time, as main_cleanup will try to use
+dnl stdout/stderr. So maybe we are stuck with AC_FUNC_FORK([]).
+dnl
+AC_FUNC_FORK([])
+AC_FUNC_CLOSEDIR_VOID
+
+dnl
+dnl Check for shadow password support.
+dnl
+dnl We used to try to determine whether shadow passwords were actually in
+dnl use or not, but the code has been changed to work right reguardless,
+dnl so we can go back to a simple check.
+AC_SEARCH_LIBS(getspnam, sec gen, AC_DEFINE(HAVE_GETSPNAM, 1,
+[Define if you have the getspnam function.]))
+
+AC_FUNC_UTIME_NULL
+AC_SYS_LONG_FILE_NAMES
+
+dnl for debugging code
+CVS_FUNC_PRINTF_PTR
+
+# Try to find connect and gethostbyname.
+AC_CHECK_LIB(nsl, main)
+AC_SEARCH_LIBS(connect, xnet socket inet,
+ AC_DEFINE(HAVE_CONNECT, 1,
+[Define if you have the connect function.]))
+dnl no need to search nsl for gethostbyname here since we should have
+dnl just added libnsl above if we found it.
+AC_SEARCH_LIBS(gethostbyname, netinet)
+
+AC_SUBST(cvs_client_objects)
+
+
+dnl
+dnl begin --with-*
+dnl
+
+dnl
+dnl set $(KRB4) from --with-krb4=value -- WITH_KRB4
+dnl
+dnl If you change this, keep in mind that some systems have a bogus
+dnl libkrb in the system libraries, so --with-krb4=value needs to
+dnl override the system -lkrb.
+dnl
+KRB4=/usr/kerberos
+define(WITH_KRB4,[
+AC_ARG_WITH(
+ [krb4],
+ AC_HELP_STRING(
+ [--with-krb4],
+ [Kerberos 4 directory (default /usr/kerberos)]),
+ [KRB4=$with_krb4],
+)dnl
+AC_MSG_CHECKING([for KRB4 in $KRB4])
+AC_MSG_RESULT([])
+AC_SUBST(KRB4)])dnl
+WITH_KRB4
+
+krb_h=
+AC_MSG_CHECKING([for krb.h])
+if test "$cross_compiling" != yes && test -r $KRB4/include/krb.h; then
+ hold_cflags=$CFLAGS
+ CFLAGS="$CFLAGS -I$KRB4/include"
+ AC_TRY_LINK([#include <krb.h>],[int i;],
+ [krb_h=yes krb_incdir=$KRB4/include],
+ [CFLAGS=$hold_cflags
+ AC_TRY_LINK([#include <krb.h>],[int i;],
+ [krb_h=yes krb_incdir=])])
+ CFLAGS=$hold_cflags
+else
+ AC_TRY_LINK([#include <krb.h>],[int i;],
+ [krb_h=yes krb_incdir=])
+fi
+if test -z "$krb_h"; then
+ AC_TRY_LINK([#include <krb.h>],[int i;],
+ [krb_h=yes krb_incdir=],
+ [if test "$cross_compiling" != yes && test -r $KRB4/include/kerberosIV/krb.h; then
+ hold_cflags=$CFLAGS
+ CFLAGS="$CFLAGS -I$KRB4/include/kerberosIV"
+ AC_TRY_LINK([#include <krb.h>],[int i;],
+ [krb_h=yes krb_incdir=$KRB4/include/kerberosIV])
+ CFLAGS=$hold_cflags
+ fi])
+fi
+AC_MSG_RESULT($krb_h)
+
+if test -n "$krb_h"; then
+ krb_lib=
+ if test "$cross_compiling" != yes && test -r $KRB4/lib/libkrb.a; then
+ hold_ldflags=$LDFLAGS
+ LDFLAGS="-L${KRB4}/lib $LDFLAGS"
+ AC_CHECK_LIB(krb,printf,[krb_lib=yes krb_libdir=${KRB4}/lib],
+ [LDFLAGS=$hold_ldflags
+ # Using open here instead of printf so we don't
+ # get confused by the cached value for printf from above.
+ AC_CHECK_LIB(krb,open,[krb_lib=yes krb_libdir=])])
+ LDFLAGS=$hold_ldflags
+ else
+ AC_CHECK_LIB(krb,printf,[krb_lib=yes krb_libdir=])
+ AC_CHECK_FUNC(krb_recvauth,[krb_lib=yes krb_libdir=])
+ fi
+ if test -n "$krb_lib"; then
+ AC_DEFINE([HAVE_KERBEROS], 1,
+ [Define if you have MIT Kerberos version 4 available.])
+ cvs_client_objects="$cvs_client_objects kerberos4-client.o"
+ test -n "${krb_libdir}" && LIBS="${LIBS} -L${krb_libdir}"
+ # Put -L${krb_libdir} in LDFLAGS temporarily so that it appears before
+ # -ldes in the command line. Don't do it permanently so that we honor
+ # the user's setting for LDFLAGS
+ hold_ldflags=$LDFLAGS
+ test -n "${krb_libdir}" && LDFLAGS="$LDFLAGS -L${krb_libdir}"
+ AC_CHECK_LIB(des,printf,[LIBS="${LIBS} -ldes"])
+ AC_CHECK_LIB(krb,krb_recvauth)
+ AC_CHECK_LIB(krb4,krb_recvauth)
+ LDFLAGS=$hold_ldflags
+ if test -n "$krb_incdir"; then
+ CPPFLAGS="$CPPFLAGS -I$krb_incdir"
+ fi
+ fi
+fi
+AC_CHECK_FUNCS(krb_get_err_text)
+
+
+dnl
+dnl WITH_GSSAPI is external
+dnl
+dnl TODO - I tried to put these in alphabetical order, but ACX_WITH_GSSAPI
+dnl fails unless called after the KRB4 stuff. I don't know why.
+dnl
+ACX_WITH_GSSAPI
+
+dnl
+dnl WITH_EXTERNAL_ZLIB is external
+dnl
+ACX_WITH_EXTERNAL_ZLIB
+
+dnl
+dnl begin --with-rsh
+dnl
+dnl Many sites no longer desire the use of "rsh" as the default
+dnl remote shell program. They typically favor "ssh" as the default
+
+# What remote shell transport should our client cvs default to using?
+AC_ARG_WITH(
+ [rsh],
+ AC_HELP_STRING(
+ [--with-rsh],
+ [The default remote shell CVS will use for :ext: transport
+ (default ssh)]), ,
+ [with_rsh="ssh rsh"])
+
+if test no = "$with_rsh"; then
+ AC_MSG_WARN([Failed to find usable remote shell. Using 'rsh'.])
+ with_rsh=rsh
+elif test yes = "$with_rsh"; then
+ # Make --with-rsh mean the same thing as --with-rsh=rsh
+ with_rsh=rsh
+fi
+
+if echo $with_rsh |grep ^/ >/dev/null; then
+ # If $with_rsh is an absolute path, issue a warning if the executable
+ # doesn't exist or isn't usable, but then trust the user and use it
+ # regardless
+ with_default_rsh=$with_rsh
+ AC_MSG_CHECKING([for a remote shell])
+ if ! test -f $with_rsh \
+ || ! test -x $with_rsh; then
+ # warn the user that they may encounter problems
+ AC_MSG_WARN([$with_rsh is not a path to an executable file])
+ fi
+else
+ # Search for a remote shell
+ AC_CHECK_PROGS([with_default_rsh], [$with_rsh], "rsh")
+fi
+
+AC_DEFINE_UNQUOTED(
+ [RSH_DFLT], ["$with_default_rsh"],
+ [The default remote shell to use, if one does not specify the
+ CVS_RSH environment variable.])
+RSH_DFLT=$with_default_rsh
+AC_SUBST(RSH_DFLT)
+dnl done with finding a default CVS_RSH value
+dnl
+dnl end --with-rsh
+dnl
+
+dnl
+dnl begin --with-editor
+dnl
+dnl Set the default editor to use for log messages
+dnl
+
+AC_ARG_VAR(
+ [EDITOR],
+ [The text editor CVS will use by default for log messages.])
+
+# Let the confiscator request a specific editor
+AC_ARG_WITH(
+ [editor],
+ AC_HELP_STRING(
+ [--with-editor],
+ [The default text editor CVS should use for log messages
+ (default autoselects)]), ,
+ [with_editor=yes])
+
+# If --with-editor was supplied with an argument, let it override $EDITOR from
+# the user's environment. We need to unset EDITOR here because AC_CHECK_PROGS
+# will let the value of EDITOR ride when it is set rather than searching. We
+# ignore the --without-editor case since it will be caught below.
+if test -n "$EDITOR" && test yes != $with_editor; then
+ AS_UNSET([EDITOR])
+fi
+
+# Set the default when --with-editor wasn't supplied or when it was supplied
+# without an argument.
+if test yes = $with_editor; then
+ with_editor="vim vi emacs nano pico edit"
+fi
+
+if echo $with_editor |grep ^/ >/dev/null; then
+ # If $with_editor is an absolute path, issue a warning if the executable
+ # doesn't exist or isn't usable, but then trust the user and use it
+ # regardless
+ EDITOR=$with_editor
+ AC_MSG_CHECKING([for an editor])
+ AC_MSG_RESULT([$EDITOR])
+ if ! test -f $with_editor \
+ || ! test -x $with_editor; then
+ # warn the user that they may encounter problems
+ AC_MSG_WARN([\`$with_editor' is not a path to an executable file])
+ fi
+elif test no != "${with_editor}"; then
+ # Search for an editor
+ AC_CHECK_PROGS([EDITOR], [$with_editor], [no])
+ if test no = "${EDITOR}"; then
+ AC_MSG_ERROR([
+ Failed to find a text file editor. CVS cannot be compiled
+ without a default log message editor. Searched for
+ \`$with_editor'. Try \`configure --with-editor'.])
+ fi
+else
+ AC_MSG_ERROR([
+ CVS cannot be compiled without a default log message editor.
+ Try \`configure --with-editor'.])
+fi
+
+dnl FIXME - Using --without-editor will probably break a compile at
+dnl the moment, but maybe it is reasonable for someone to want to
+dnl compile a CVS executable that refuses to run if no $EDITOR,
+dnl $CVS_EDITOR, or -e option is specified? Making a preliminary
+dnl design decision in this direction, subject to discussion.
+dnl
+dnl Still don't know if the above would be useful, but we shouldn't
+dnl be able to get here any longer without $EDITOR defined due to the
+dnl error checking above.
+AC_DEFINE_UNQUOTED(
+ [EDITOR_DFLT], ["$EDITOR"],
+ [The default editor to use, if one does not specify the "-e" option
+ to cvs, or does not have an EDITOR environment variable. If this
+ is not set to an absolute path to an executable, use the shell to
+ find where the editor actually is. This allows sites with
+ /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that their
+ PATH is reasonable).])
+
+dnl
+dnl done finding an editor
+dnl
+dnl end --with-editor
+dnl
+
+
+
+dnl
+dnl --with-hardcoded-pam-service-name
+dnl
+AC_ARG_WITH(
+ [hardcoded-pam-service-name],
+ AC_HELP_STRING(
+ [--with-hardcoded-pam-service-name],
+ [Use this to hard code a service name for PAM CVS authentication. The
+ special name, `program_name', will cause CVS to use whatever name it
+ was invoked as as the service name. (defaults to `cvs')]),,
+ [with_hardcoded_pam_service_name=cvs])
+
+if test "x$with_hardcoded_pam_service_name" = xno ||
+ test "x$with_hardcoded_pam_service_name" = xprogram_name; then
+ AC_DEFINE([PAM_SERVICE_NAME], [program_name],
+ [Define to set a service name for PAM. This must be defined. Define to
+ `program_name', without the quotes, to use whatever name CVS was invoked
+ as. Otherwise, define to a double-quoted literal string, such as
+ `"cvs"'.])
+else
+ if test x"$with_hardcoded_pam_service_name" = xyes; then
+ with_hardcoded_pam_service_name=cvs
+ fi
+ AC_DEFINE_UNQUOTED([PAM_SERVICE_NAME], ["$with_hardcoded_pam_service_name"])
+fi
+
+
+
+dnl
+dnl Find a temporary directory
+dnl
+AC_ARG_WITH(
+ [tmpdir],
+ AC_HELP_STRING(
+ [--with-tmpdir],
+ [The temporary directory CVS should use as a default
+ (default autoselects)]))
+
+AC_MSG_CHECKING([for temporary directory])
+if test -z "$with_tmpdir" || test yes = "$with_tmpdir"; then
+ for with_tmpdir in /tmp /var/tmp no; do
+ if test -d "$with_tmpdir" && test -x "$with_tmpdir" \
+ && test -w "$with_tmpdir" && test -r "$with_tmpdir"; then
+ break
+ fi
+ done
+ if test no = "$with_tmpdir"; then
+ AC_MSG_WARN([Failed to find usable temporary directory. Using '/tmp'.])
+ with_tmpdir=/tmp
+ fi
+ AC_MSG_RESULT([$with_tmpdir])
+elif ! echo "$with_tmpdir" |grep '^[[\\/]]'; then
+ AC_MSG_RESULT([$with_tmpdir])
+ AC_MSG_ERROR([--with-tmpdir requires an absolute path.])
+elif ! test -d "$with_tmpdir" || ! test -x "$with_tmpdir" \
+ || ! test -w "$with_tmpdir" || ! test -r "$with_tmpdir"; then
+ AC_MSG_RESULT([$with_tmpdir])
+ AC_MSG_WARN(
+ [User supplied temporary directory ('$with_tmpdir') does not
+ exist or lacks sufficient permissions for read/write.])
+fi
+
+AC_DEFINE_UNQUOTED(
+ [TMPDIR_DFLT], ["$with_tmpdir"],
+ [Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little
+ need to change this (-T is a better mechanism if you need to use a
+ different directory for temporary files).])
+
+dnl
+dnl done finding tmpdir
+dnl
+
+
+dnl
+dnl Get default umask
+dnl
+
+AC_ARG_WITH(
+ [umask],
+ AC_HELP_STRING(
+ [--with-umask],
+ [Set the umask CVS will use by default in the repository (default 002)]))
+
+if test -z "$with_umask" || test yes = "$with_umask"; then
+ with_umask=002
+elif test no = "$with_umask"; then
+ with_umask=000
+fi
+
+AC_DEFINE_UNQUOTED(
+ [UMASK_DFLT], [$with_umask],
+ [The default umask to use when creating or otherwise setting file or
+ directory permissions in the repository. Must be a value in the
+ range of 0 through 0777. For example, a value of 002 allows group
+ rwx access and world rx access; a value of 007 allows group rwx
+ access but no world access. This value is overridden by the value
+ of the CVSUMASK environment variable, which is interpreted as an
+ octal number.])
+
+dnl
+dnl Done setting default umask
+dnl
+
+dnl
+dnl Set CVS Administrator Group
+dnl
+AC_ARG_WITH(
+ [cvs-admin-group],
+ AC_HELP_STRING(
+ [--with-cvs-admin-group=GROUP],
+ [The CVS admin command is restricted to the members of this group.
+ If this group does not exist, all users are allowed to run CVS admin.
+ To disable the CVS admin command for all users, create an empty group
+ by specifying the --with-cvs-admin-group= option. To disable access
+ control for CVS admin, run configure with the --without-cvs-admin-group
+ option. (default 'cvsadmin')]), ,
+ [with_cvs_admin_group=cvsadmin])
+
+if test yes = "$with_cvs_admin_group"; then
+ with_cvs_admin_group=cvsadmin
+fi
+if test no != "$with_cvs_admin_group"; then
+ dnl FIXME We should warn if the group doesn't exist
+ AC_DEFINE_UNQUOTED(
+ [CVS_ADMIN_GROUP], ["$with_cvs_admin_group"],
+ [The CVS admin command is restricted to the members of the group
+ CVS_ADMIN_GROUP. If this group does not exist, all users are
+ allowed to run CVS admin. To disable the CVS admin command for
+ all users, create an empty CVS_ADMIN_GROUP by running configure
+ with the --with-cvs-admin-group= option. To disable access control
+ for CVS admin, run configure with the --without-cvs-admin-group
+ option in order to comment out the define below.])
+fi
+
+dnl
+dnl Done setting CVS Administrator Group
+dnl
+
+dnl
+dnl Set the NDBM library to use.
+dnl
+dnl XXX - FIXME - FIXME - FIXME - XXX
+dnl
+dnl This is very bad. It should really autodetect an appropriate NDBM library
+dnl and, if it doesn't find one, decide to use MY_NDBM. I'm am defining
+dnl this here since this is no worse than it worked when it was in options.h
+dnl and I am cleaning out options.h so that the Windows version of CVS will
+dnl compile properly for the next release.
+dnl
+dnl That's why this option is in the --with-* section rather than the
+dnl --enable-* section.
+dnl
+dnl XXX - FIXME - FIXME - FIXME - XXX
+dnl
+AC_ARG_ENABLE(
+ [cvs-ndbm],
+ AC_HELP_STRING(
+ [--enable-cvs-ndbm],
+ [Use the NDBM library distributed with CVS rather than attempting to use
+ a system NDBM library. Disabling this may not work. (default)]), ,
+ [enable_cvs_ndbm=yes])
+if test no != "$enable_cvs_ndbm"; then
+ AC_DEFINE(
+ [MY_NDBM], [1],
+ [By default, CVS stores its modules and other such items in flat
+ text files (MY_NDBM enables this). Turning off MY_NDBM causes CVS
+ to look for a system-supplied ndbm database library and use it
+ instead. That may speed things up, but the default setting
+ generally works fine too.])
+fi
+
+dnl
+dnl Done selecting NDBM library.
+dnl
+
+
+
+dnl
+dnl end --with-*
+dnl
+
+
+dnl
+dnl begin --enables
+dnl
+
+
+dnl
+dnl begin --enable-client
+dnl
+
+# Check for options requesting client and server feature. If none are
+# given and we have connect(), we want the full client & server arrangement.
+AC_ARG_ENABLE(
+ [client],
+ AC_HELP_STRING(
+ [--enable-client],
+ [Include code for running as a remote client (default)]), ,
+ [enable_client=$ac_cv_search_connect])
+if test no != "$enable_client"; then
+ AC_DEFINE(
+ [CLIENT_SUPPORT], [1],
+ [Define if you want CVS to be able to be a remote repository client.])
+fi
+
+dnl
+dnl end --enable-client
+dnl
+
+
+dnl
+dnl begin --enable-password-authenticated-client
+dnl
+AC_ARG_ENABLE(
+ [password-authenticated-client],
+ AC_HELP_STRING(
+ [--enable-password-authenticated-client],
+ [Enable pserver as a remote access method in the CVS client
+ (default)]), ,
+ [enable_password_authenticated_client=$enable_client])
+
+if test xno != "x$enable_password_authenticated_client"; then
+ if test xno != "x$enable_client"; then
+ AC_DEFINE(
+ [AUTH_CLIENT_SUPPORT], [1],
+ [Enable AUTH_CLIENT_SUPPORT to enable pserver as a remote access
+ method in the CVS client (default)])
+ else
+ AC_MSG_WARN(
+ [--enable-password-authenticated-client is meaningless with
+ the CVS client disabled (--disable-client)])
+ fi
+fi
+
+dnl
+dnl begin --enable-password-authenticated-client
+dnl
+
+
+dnl
+dnl begin --enable-server
+dnl
+
+dnl
+dnl Give the confiscator control over whether the server code is compiled
+dnl
+AC_ARG_ENABLE(
+ [server],
+ AC_HELP_STRING(
+ [--enable-server],
+ [Include code for running as a server (default)]), ,
+ [enable_server=$ac_cv_search_connect])
+
+if test no != "$enable_server"; then
+ AC_DEFINE(
+ [SERVER_SUPPORT], [1],
+ [Define if you want CVS to be able to serve repositories to remote
+ clients.])
+
+ dnl
+ dnl The auth server needs to be able to check passwords against passwd
+ dnl file entries, so we only #define AUTH_SERVER_SUPPORT if we can
+ dnl find the crypt function.
+ dnl
+ AC_SEARCH_LIBS(
+ [crypt], [crypt],
+ [AC_DEFINE(
+ [HAVE_CRYPT], [1],
+ [Define if you have the crypt function.])
+ AC_DEFINE(
+ [AUTH_SERVER_SUPPORT], [1],
+ [Define if you want to use the password authenticated server.])dnl
+ ])dnl AC_SEARCH_LIBS
+
+ dnl
+ dnl Allow the configurer to enable server flowcontrol. Read the help
+ dnl strings below for a full explanation.
+ dnl
+ AC_ARG_ENABLE(
+ [server-flow-control],
+ AC_HELP_STRING(
+ [--enable-server-flow-control],
+ [If you are working with a large remote repository and a 'cvs
+ checkout' is swamping your network and memory, define these to
+ enable flow control. You may optionally pass a low water mark
+ in bytes and a high water mark in bytes, separated by commas.
+ (default is enabled 1M,2M)]),
+ [if test yes = $enable_server_flow_control; then
+ enable_server_flow_control=1M,2M
+ fi],
+ [enable_server_flow_control=1M,2M])
+ if test no != $enable_server_flow_control; then
+ ccvs_lwm=`expr "$enable_server_flow_control" : '\(.*\),'`
+ ccvs_hwm=`expr "$enable_server_flow_control" : '.*,\(.*\)'`
+ ccvs_lwm_E=`expr "$ccvs_lwm" : '[[0-9]][[0-9]]*\(.*\)'`
+ ccvs_lwm=`expr "$ccvs_lwm" : '\([[0-9]][[0-9]]*\)'`
+ test "" != "$ccvs_lwm" || ccvs_lwm_E="?"
+ case $ccvs_lwm_E in
+ G) ccvs_lwm="$ccvs_lwm * 1024 * 1024 * 1024";;
+ M) ccvs_lwm="$ccvs_lwm * 1024 * 1024";;
+ k) ccvs_lwm="$ccvs_lwm * 1024";;
+ b | '') ;;
+ *) AC_MSG_ERROR([Can't parse argument to --enable-server-flow-control
+ ('$enable_server_flow_control') as <lwm>,<hwm>])
+ esac
+ ccvs_hwm_E=`expr "$ccvs_hwm" : '[[0-9]][[0-9]]*\(.*\)'`
+ ccvs_hwm=`expr "$ccvs_hwm" : '\([[0-9]][[0-9]]*\).*'`
+ test "" != "$ccvs_hwm" || ccvs_hwm_E="?"
+ case $ccvs_hwm_E in
+ G) ccvs_hwm="$ccvs_hwm * 1024 * 1024 * 1024";;
+ M) ccvs_hwm="$ccvs_hwm * 1024 * 1024";;
+ k) ccvs_hwm="$ccvs_hwm * 1024";;
+ b | '') ccvs_hwm="$ccvs_hwm";;
+ *) AC_MSG_ERROR([Can't parse argument to --enable-server-flow-control
+ ('$enable_server_flow_control') as <lwm>,<hwm>])
+ esac
+
+ AC_DEFINE(
+ [SERVER_FLOWCONTROL], [1],
+ [If you are working with a large remote repository and a 'cvs
+ checkout' is swamping your network and memory, define these to
+ enable flow control. You will end up with even less probability of
+ a consistent checkout (see Concurrency in cvs.texinfo), but CVS
+ doesn't try to guarantee that anyway. The master server process
+ will monitor how far it is getting behind, if it reaches the high
+ water mark, it will signal the child process to stop generating
+ data when convenient (ie: no locks are held, currently at the
+ beginning of a new directory). Once the buffer has drained
+ sufficiently to reach the low water mark, it will be signalled to
+ start again.])
+ AC_DEFINE_UNQUOTED(
+ [SERVER_LO_WATER], [($ccvs_lwm)],
+ [The low water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise.])
+ AC_DEFINE_UNQUOTED(
+ [SERVER_HI_WATER], [($ccvs_hwm)],
+ [The high water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise.])
+ fi # enable_server_flow_control
+fi # enable_server
+
+dnl
+dnl end --enable-server
+dnl
+
+
+dnl
+dnl begin --enable-proxy
+dnl
+
+dnl
+dnl Give the confiscator control over whether the proxy server code is compiled
+dnl
+AC_ARG_ENABLE(
+ [proxy],
+ AC_HELP_STRING(
+ [--enable-proxy],
+ [Include code for running as a transparent proxy server. Disabling this
+ may produce a slight performance gain on some systems, at the expense of
+ write proxy support. (default)]), ,
+ [if test xno != "x$enable_client" && test xno != "x$enable_server"; then
+ enable_proxy=yes
+ else
+ enable_proxy=no
+ fi])
+
+if test no != "$enable_proxy"; then
+ if test xno = "x$enable_client" || test xno = "x$enable_server"; then
+ AC_MSG_WARN(
+ [--enable-proxy is meaningless when either the CVS client or the
+ CVS server is disabled (--disable-client and --disable-server).])
+ else
+ AC_DEFINE(
+ [PROXY_SUPPORT], [1],
+ [Define if you want CVS to be able to serve as a transparent proxy for
+ write operations. Disabling this may produce a slight performance gain
+ on some systems, at the expense of write proxy support.])
+ fi
+fi
+dnl
+dnl end --enable-proxy
+dnl
+
+
+dnl
+dnl begin --enable-pam
+dnl
+
+dnl
+dnl Check if PAM authentication is enabled
+dnl
+AC_ARG_ENABLE(
+ [pam],
+ AC_HELP_STRING(
+ [--enable-pam],
+ [Use to enable system authentication with PAM instead of using the
+ simple getpwnam interface. This allows authentication (in theory)
+ with any PAM module, e.g. on systems with shadow passwords or via LDAP]), ,
+ [enable_pam=no]
+ )
+
+if test yes = $enable_pam; then
+ ac_pam_header_available=
+
+ AC_CHECK_HEADER([security/pam_appl.h], [
+ AC_DEFINE([HAVE_SECURITY_PAM_APPL_H], 1, [Define to 1 if security/pam_appl.h is available])
+ ac_pam_header_available=1])
+
+ if test -z "$ac_pam_header_available"; then
+ AC_CHECK_HEADER([pam/pam_appl.h], [
+ AC_DEFINE([HAVE_PAM_PAM_APPL_H], 1, [Define to 1 if pam/pam_appl.h is available])
+ ac_pam_header_available=1])
+ fi
+
+ if test -z "$ac_pam_header_available"; then
+ AC_MSG_ERROR([Could not find PAM headers])
+ else
+ AC_DEFINE(HAVE_PAM, 1,
+ [Define to enable system authentication with PAM instead of using the
+ simple getpwnam interface. This allows authentication (in theory)
+ with any PAM module, e.g. on systems with shadow passwords or via LDAP])
+ AC_CHECK_LIB(pam, pam_start, [LIBS="${LIBS} -lpam"],
+ AC_MSG_ERROR([Could not find PAM libraries but the headers exist.
+ Give the --disable-pam option to compile without PAM support (or fix
+ your broken configuration)])
+ )
+ fi
+fi
+
+dnl
+dnl end --enable-pam
+dnl
+
+
+dnl
+dnl begin --enable-case-sensitivity
+dnl
+
+AC_ARG_ENABLE(
+ [case-sensitivity],
+ AC_HELP_STRING(
+ [--enable-case-sensitivity],
+ [Force CVS to expect a case sensitive file system. Enabling this on a case
+ insensitive system should have little effect on the server or client
+ operation, though client users may ocassionally be suprised that the CVS
+ server appears to be case sensitive. Disabling this for a case sensitive
+ server disables server support for case insensitive clients, which can
+ confuse all users of case insensitive clients contacting the server.
+ Disabling this for a case sensitive client will cause the client to ask
+ servers to behave case insensitively, which could cause confusion for
+ users, but also probably no real harm. (default autoselects based on the
+ case sensitivity of the file system containing the current working
+ directory)]),
+ [case "$enable_case_sensitivity" in
+ yes | no | auto) ;;
+ *)
+ AC_MSG_ERROR([Unrecognized argument to --enable-case-sensitivity: \`$enable_case_sensitivity'. Acceptable values are \`yes', \`no', and \`auto'.])
+ ;;
+ esac],
+ [enable_case_sensitivity=auto])
+
+acx_forced=' (forced)'
+AC_MSG_CHECKING([for a case sensitive file system])
+if test $enable_case_sensitivity = auto; then
+ dnl
+ dnl Check for a case insensitive filesystem, like Mac OS X and Windows have.
+ dnl
+ AC_CACHE_VAL([acx_cv_case_sensitive],
+ [ rm -f ac_TEST_filenames_CASE_sensitive
+ echo foo >ac_test_filenames_case_sensitive
+ if test -f ac_TEST_filenames_CASE_sensitive; then
+ acx_cv_case_sensitive=no
+ else
+ acx_cv_case_sensitive=yes
+ fi
+ rm ac_test_filenames_case_sensitive
+ ])
+ enable_case_sensitivity=$acx_cv_case_sensitive
+ acx_forced=
+fi
+AC_MSG_RESULT([$enable_case_sensitivity$acx_forced])
+if test $enable_case_sensitivity = no; then
+ AC_DEFINE([FILENAMES_CASE_INSENSITIVE], [1],
+ [Define if this executable will be running on case insensitive
+ file systems. In the client case, this means that it will request
+ that the server pretend to be case insensitive if it isn't
+ already.])
+ dnl Compile fncase.c (containing fncase() & fncmp()) to handle file name
+ dnl comparisons on case insensitive filesystems.
+ AC_LIBOBJ(fncase)
+fi
+
+dnl
+dnl end --enable-case-sensitivity
+dnl
+
+
+dnl
+dnl begin --enable-encryption
+dnl
+
+dnl
+dnl Use --enable-encryption to turn on encryption support, but ignore this
+dnl option unless either client or server is enabled.
+dnl
+AC_ARG_ENABLE(
+ [encryption],
+ AC_HELP_STRING(
+ [--enable-encryption],
+ [Enable encryption support (disabled by default)]), ,
+ [enable_encryption=no])
+if test "x$enable_encryption" = xyes; then
+ if test xno = "x$with_client" && test xno = "x$with_server"; then
+ AC_MSG_WARN(
+ [--enable-encryption is meaningless when neither the CVS client
+ nor the CVS server is enabled (--disable-client and --disable-server).])
+ else
+ AC_DEFINE(
+ [ENCRYPTION], [1],
+ [Define to enable encryption support.])
+ fi
+fi
+
+dnl
+dnl end --enable-encryption
+dnl
+
+
+dnl
+dnl begin --enable-force-editor
+dnl
+
+AC_ARG_ENABLE(
+ [force-editor],
+ AC_HELP_STRING(
+ [--enable-force-editor],
+ [When committing or importing files, you must enter a log message.
+ Normally, you can do this either via the -m flag on the command
+ line, the -F flag on the command line, or an editor will be started
+ for you. If you like to use logging templates (the rcsinfo file
+ within the $CVSROOT/CVSROOT directory), you might want to force
+ people to use the editor even if they specify a message with -m or
+ -F. --enable-force-editor will cause the -m or -F message to be
+ appended to the temp file when the editor is started. (disabled
+ by default)]), ,
+ [enable_force_editor=no])
+
+if test yes = "$enable_force_editor"; then
+ AC_DEFINE(
+ [FORCE_USE_EDITOR], [1],
+ [When committing or importing files, you must enter a log message.
+ Normally, you can do this either via the -m flag on the command
+ line, the -F flag on the command line, or an editor will be started
+ for you. If you like to use logging templates (the rcsinfo file
+ within the $CVSROOT/CVSROOT directory), you might want to force
+ people to use the editor even if they specify a message with -m or
+ -F. Enabling FORCE_USE_EDITOR will cause the -m or -F message to be
+ appended to the temp file when the editor is started.])
+fi
+
+dnl
+dnl end --enable-force-editor
+dnl
+
+
+dnl
+dnl begin --enable-lock-compatibility
+dnl
+
+# Check for options requesting client and server feature. If none are
+# given and we have connect(), we want the full client & server arrangement.
+AC_ARG_ENABLE(
+ [lock-compatibility],
+ AC_HELP_STRING(
+ [--enable-lock-compatibility],
+ [Include locking code which prevents versions of CVS earlier than 1.12.4
+ directly accessing the same repositiory as this executable from ignoring
+ this executable's promotable read locks. If only CVS versions 1.12.4 and
+ later will be accessing your repository directly (as a server or locally),
+ you can safely disable this option in return for fewer disk accesses and a
+ small speed increase. Disabling this option when versions of CVS earlier
+ than 1,12,4 _will_ be accessing your repository, however, is *VERY* *VERY*
+ *VERY* dangerous and could result in data loss. (enabled by default)]),,
+ [enable_lock_compatibility=yes])
+
+if test x$enable_lock_compatibility = xyes; then
+ AC_DEFINE([LOCK_COMPATIBILITY], [1],
+ [Define to include locking code which prevents versions of CVS earlier than
+ 1.12.4 directly accessing the same repositiory as this executable from
+ ignoring this executable's promotable read locks. If only CVS versions
+ 1.12.4 and later will be accessing your repository directly (as a server
+ or locally), you can safely disable this option in return for fewer disk
+ accesses and a small speed increase. Disabling this option when versions
+ of CVS earlier than 1,12,4 _will_ be accessing your repository, however,
+ is *VERY* *VERY* *VERY* dangerous and could result in data loss.
+
+ As such, by default, CVS is compiled with this code enabled. If you are
+ sure you would like this code disabled, you can disable it by passing the
+ "--disable-lock-compatibility" option to configure or by commenting out
+ the lines below.])
+fi
+
+dnl
+dnl end --enable-lock-compatibility
+dnl
+
+
+dnl
+dnl begin --enable-rootcommit
+dnl
+
+dnl
+dnl I don't like this here, but I don't really like options.h, either.
+dnl Besides, this is causing some problems currently when compiling under
+dnl Windows and moving it here should avoid the issue (the wrong options.h
+dnl is being used).
+dnl
+dnl I don't like making this a runtime option either. I think I just don't
+dnl like making it easy to get to, but putting it here goes along with the
+dnl Autoconf ideal.
+dnl
+AC_ARG_ENABLE(
+ [rootcommit],
+ AC_HELP_STRING(
+ [--enable-rootcommit],
+ [Allow the root user to commit files (disabled by default)]), ,
+ [enable_rootcommit=no])
+if test "$enable_rootcommit" = no; then
+ AC_DEFINE(
+ [CVS_BADROOT], [1],
+ [When committing a permanent change, CVS and RCS make a log entry of
+ who committed the change. If you are committing the change logged
+ in as "root" (not under "su" or other root-priv giving program),
+ CVS/RCS cannot determine who is actually making the change.
+
+ As such, by default, CVS prohibits changes committed by users
+ logged in as "root". You can disable checking by passing the
+ "--enable-rootcommit" option to configure or by commenting out the
+ lines below.])
+fi
+
+dnl
+dnl end --enable-rootcommit
+dnl
+
+dnl
+dnl begin --enable-old-info-support
+dnl
+AC_ARG_ENABLE(
+ [old-info-support],
+ AC_HELP_STRING(
+ [--enable-old-info-format-support],
+ [Enable support for the pre 1.12.1 *info scripting hook format strings.
+ Disable this option for a smaller executable once your scripting
+ hooks have been updated to use the new *info format strings (default).]), ,
+ [enable_old_info_format_support=yes])
+if test "$enable_old_info_format_support" = yes; then
+ AC_DEFINE(
+ [SUPPORT_OLD_INFO_FMT_STRINGS], [1],
+ [Enable support for the pre 1.12.1 *info scripting hook format strings.
+ Disable this option for a smaller executable once your scripting
+ hooks have been updated to use the new *info format strings by passing
+ "--disable-old-info-format-support" option to configure or by commenting
+ out the line below.])
+fi
+
+dnl
+dnl end --enable-old-info-support
+dnl
+
+
+dnl
+dnl begin --enable-config-override
+dnl
+
+AC_ARG_ENABLE(
+ [config-override],
+ AC_HELP_STRING(
+ [--enable-config-override],
+ [Set to a comma-seperated list of paths to directories (designated by
+ trailing `/') and files, specifies the path prefixes (for directories) and
+ paths to files the CVS server commands will allow configuration to be read
+ from. Specify `--enable-config-override=no' to disable config file
+ overrides completely and `--enable-config-override=/' or simply
+ `--enable-config-override' to allow all paths. (Defaults to
+ `SYSCONFDIR/cvs.conf,SYSCONFDIR/cvs/')]),,
+ [# $sysconfdir may still contain variable references. By default, this will
+ # be to $prefix, and $prefix won't be set to its default value until later.
+ # Compromise without setting $prefix for the rest of the file.
+ cvs_save_prefix=$prefix
+ if test "X$prefix" = XNONE; then
+ prefix=$ac_prefix_default
+ fi
+ eval enable_config_override=`echo $sysconfdir/cvs.conf,$sysconfdir/cvs/`
+ prefix=$cvs_save_prefix])
+
+if test x"$enable_config_override" = xyes; then
+ enable_config_override=/
+fi
+
+if test x"$enable_config_override" = xno; then :; else
+ save_IFS=$IFS
+ IFS=,
+ arrayinit=""
+ for path in $enable_config_override; do
+ IFS=$save_IFS
+ case "$path" in
+ [[\\/$]]* | ?:[[\\/]]* )
+ arrayinit="$arrayinit\"$path\", "
+ ;;
+ *) AC_MSG_ERROR(
+ [expected comma separated list of absolute directory
+ names for --enable-config-override, or \`no', not:
+ \`$enable_config_override'
+ (\`$path' invalid.)]);;
+ esac
+ done
+ arrayinit="${arrayinit}NULL"
+
+ AC_DEFINE_UNQUOTED(ALLOW_CONFIG_OVERRIDE, [$arrayinit],
+ [Define this to a NULL terminated list of allowed path prefixes (for
+ directories) and paths to files the CVS server will allow configuration to
+ be read from when specified from the command line.])
+fi
+
+dnl
+dnl end --enable-config-override
+dnl
+
+
+
+dnl
+dnl end --enables
+dnl
+
+
+
+dnl For the moment we will assume that all systems which have
+dnl the unixyness to run configure are unixy enough to do the
+dnl PreservePermissions stuff. I have this sinking feeling that
+dnl things won't be that simple, before long.
+dnl AC_DEFINE(PRESERVE_PERMISSIONS_SUPPORT, 1,
+dnl [Define if this system supports chown(), link(), and friends.])
+
+dnl On cygwin32, we configure like a Unix system, but we need some support
+dnl libraries. We do this at the end so that the new libraries are added at
+dnl the end of LIBS.
+dnl
+dnl FIXME: We should be trying to meet the autoconf ideal of checking for
+dnl the properties of the system rather than the name of the os here. In other
+dnl words, we should check the case sensitivty of the system and then for
+dnl the support functions we are using and which library we find them in.
+AC_CACHE_CHECK(for cygwin32, ccvs_cv_sys_cygwin32,
+[AC_TRY_COMPILE([], [return __CYGWIN32__;],
+ccvs_cv_sys_cygwin32=yes, ccvs_cv_sys_cygwin32=no)])
+if test $ccvs_cv_sys_cygwin32 = yes; then
+ LIBS="$LIBS -ladvapi32"
+
+ dnl On Windows you can only change file times if you can write to
+ dnl the file. cygwin32 should really handle this for us, but as of
+ dnl January 1998 it doesn't.
+ AC_DEFINE(UTIME_EXPECTS_WRITABLE, 1,
+[Define if utime requires write access to the file (true on Windows,
+but not Unix).])
+
+ dnl On Windows we must use setmode to change between binary and text
+ dnl mode. This probably doesn't really require two macro definitions
+ AC_DEFINE(USE_SETMODE_STDOUT, 1,
+[Define if setmode is required when writing binary data to stdout.])
+ AC_DEFINE(HAVE_SETMODE, 1,
+[Define if the diff library should use setmode for binary files.])
+fi
+
+dnl associate the setting of the execute bit with the individual scripts
+AC_CONFIG_FILES(contrib/validate_repo, [chmod +x contrib/validate_repo])
+AC_CONFIG_FILES(contrib/clmerge, [chmod +x contrib/clmerge])
+AC_CONFIG_FILES(contrib/cln_hist, [chmod +x contrib/cln_hist])
+AC_CONFIG_FILES(contrib/commit_prep, [chmod +x contrib/commit_prep])
+AC_CONFIG_FILES(contrib/cvs_acls, [chmod +x contrib/cvs_acls])
+AC_CONFIG_FILES(contrib/log, [chmod +x contrib/log])
+AC_CONFIG_FILES(contrib/log_accum, [chmod +x contrib/log_accum])
+AC_CONFIG_FILES(contrib/mfpipe, [chmod +x contrib/mfpipe])
+AC_CONFIG_FILES(contrib/pvcs2rcs, [chmod +x contrib/pvcs2rcs])
+AC_CONFIG_FILES(contrib/rcs2log:contrib/rcs2log.sh, [chmod +x contrib/rcs2log])
+AC_CONFIG_FILES(contrib/rcslock, [chmod +x contrib/rcslock])
+AC_CONFIG_FILES(contrib/sccs2rcs, [chmod +x contrib/sccs2rcs])
+AC_CONFIG_FILES(doc/mkman:doc/mkman.pl, [chmod +x doc/mkman])
+AC_CONFIG_FILES(src/cvsbug, [chmod +x src/cvsbug])
+
+dnl the bulk files
+AC_CONFIG_FILES([Makefile \
+ contrib/Makefile \
+ contrib/pam/Makefile \
+ cvs.spec \
+ diff/Makefile \
+ doc/Makefile \
+ doc/i18n/Makefile \
+ doc/i18n/pt_BR/Makefile \
+ emx/Makefile \
+ lib/Makefile \
+ maint-aux/Makefile \
+ man/Makefile \
+ os2/Makefile \
+ src/Makefile \
+ src/sanity.config.sh \
+ tools/Makefile \
+ vms/Makefile \
+ windows-NT/Makefile \
+ windows-NT/SCC/Makefile \
+ zlib/Makefile])
+
+dnl and we're done
+AC_OUTPUT
+
+
+
+# Report the state of this version of CVS if this is from dev.
+m4_bmatch(m4_defn([AC_PACKAGE_VERSION]), [[0-9]*\.[0-9]*\.[0-9]*\.[0-9]],
+[ cat <<EOF
+
+You are about to use an unreleased version of CVS. Be sure to
+read the relevant mailing lists, most importantly <info-cvs@nongnu.org>.
+
+Below you will find information on the status of this version of CVS.
+
+
+EOF
+ sed -n '/^\* Status/,$p' $srcdir/BUGS
+])
diff --git a/contrib/.cvsignore b/contrib/.cvsignore
new file mode 100644
index 0000000..8f51190
--- /dev/null
+++ b/contrib/.cvsignore
@@ -0,0 +1,18 @@
+Makefile
+clmerge
+cln_hist
+commit_prep
+cvs2vendor
+cvs_acls
+debug_check_log
+log
+log_accum
+mfpipe
+newcvsroot
+pvcs2rcs
+rcs-to-cvs
+rcs2log
+rcslock
+sccs2rcs
+validate_repo
+sandbox_status
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
new file mode 100644
index 0000000..868aac7
--- /dev/null
+++ b/contrib/ChangeLog
@@ -0,0 +1,1083 @@
+2005-09-30 Mark D. Baushke <mdb@gnu.org>
+
+ * rcs-5.7-commitid.patch: Convert diff timestamps to UTC.
+ Acknowledge Paul Eggert's help.
+ * rcs-5.7-sameuserlocks.patch: Patch from James Olin Oden allows
+ new co -S switch to disallow the user to check out the same file
+ twice.
+ * rcs-5.7-security.patch: tmpfile security patch from Olaf Kirch.
+ * README: Document rcs-5.7-sameuserlocks.patch and
+ rcs-5.7-security.patch.
+
+2005-09-29 Mark D. Baushke <mdb@gnu.org>
+
+ * rcs-5.7-commitid.patch: Not all hosts support O_NOCTTY for open.
+ Try to use more random data when time() returns -1.
+ Simplify commitid creation.
+
+2005-09-29 Derek Price <derek@ximbiot.com>
+
+ * rcs-5.7-commitid.patch: Check for error return from time().
+
+2005-09-29 Mark D. Baushke <mdb@gnu.org>
+
+ * rcs-5.7-commitid.patch: Rename N as COMMITID_RAW_SIZE.
+ Use base62 encoding for non-urandom case.
+
+2005-09-28 Mark D. Baushke <mdb@gnu.org>
+
+ * rcs-5.7-commitid.patch: Use base62 for the commitid with
+ more random content.
+
+2005-09-27 Mark D. Baushke <mdb@gnu.org>
+
+ * rcs-5.7-commitid.patch: Add documentation for the new commitid
+ phrase.
+
+2005-09-26 Mark D. Baushke <mdb@gnu.org>
+
+ * rcs-5.7-commitid.patch: New file.
+ * README: Add rcs-5.7-commitid.patch description.
+ * Makefile.am (contrib_DATA): Add new rcs-5.7-commitid.patch file.
+ (EXTRA_DIST): Ditto.
+ * Makefile.in: Regenerated.
+
+2005-09-26 Derek Price <derek@ximbiot.com>
+
+ * README: Rename check_cvs & cvscheck to verify_repo and
+ sandbox_status, respectively.
+
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * commit_prep.in, cvs_acls.in, log.in, log_accum.in, mfpipe.in,
+ pvcs2rcs.in, rcslock.in: Update links and email addresses.
+
+2005-07-22 Mark D. Baushke <mdb@gnu.org>
+
+ * log_accum.in (change_summary): Handle cvs log date lines with
+ commitid information on them.
+
+2005-07-20 Derek Price <derek@ximbiot.com>
+
+ * cvs_acls.html, cvs_acls.in, log_accum.in:
+ s/cvshome.org/nongnu.org.etc.../.
+
+2005-07-12 Derek Price <derek@ximbiot.com>
+
+ * clmerge.in, cln_hist.in, commit_prep.in, cvs2vendor.sh, cvs_acls.in,
+ debug_check_log.sh, descend.sh, log.in, log_accum.in, mfpipe.in,
+ rcs-to-cvs.sh, rcs2log.sh, rcs2sccs.sh, rcslock.in,sandbox_status.sh,
+ sccs2rcs.in: Add copyright notices.
+
+2005-07-11 Derek Price <derek@ximbiot.com>
+
+ * clmerge.in, cln_hist.in, commit_prep.in, cvs2vendor.sh, cvs_acls.in,
+ debug_check_log.sh, descend.sh, log.in, log_accum.in, mfpipe.in,
+ rcs-to-cvs.sh, rcs2log.sh, rcs2sccs.sh, rcslock.in, sandbox_status.sh,
+ sccs2rcs.in: Update license notices.
+
+2005-06-27 Derek Price <derek@ximbiot.com>
+
+ * pvcs2rcs.pl (bin_ext): Add some new extensions. Reorganize slightly.
+ (usage, error_count): Repaginate.
+ (help): Add cvs-module option. Repaginate.
+ (options): Add cvs-module option.
+ (execdir): Keep track of CVS module dir. Add quotes around file names
+ to handle spaces when passed to shell. Parse "Description" fields
+ correctly. Try not to abort when a log line matches /^Rev [\d.]+/.
+ Handle file locks in CVS module dir and moving archives into CVS module
+ dir when done. Add a few debug prints. Branch when a 2.*, etc.
+ revision is found since in PVCS, commits to 1.* and 2.* are treated as
+ different branches.
+ (pvcs_to_rcs_rev_number): Ignore 1.*, 2.*, etc., to be handled later.
+
+2005-04-14 Derek Price <derek@ximbiot.com>
+
+ * commit_prep.in, cvs_acls.in, log.in, log_accum.in, mfpipe.in,
+ rcslock.in: Enable taint checking and comment. This closes cvshome.org
+ Issue #224.
+
+2005-04-08 Derek Price <derek@ximbiot.com>
+
+ * README: Correct my email address.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2005-03-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * validate_repo.in (get_history): Allow whitespace in the author
+ field. Avoid uninitialized hash.
+ (Problem report from "Torsten Martinsen" <tma@gatehouse.dk>.)
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notices.
+
+2005-01-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs_acls.in: Filenames may include a '-' character.
+ (Patch from "Kumar Gala" <kumar.gala@freescale.com
+ forwarded by "Peter Connolly" <Peter.Connolly@cnet.com>.)
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (contrib_MANS): Add rcs2log.1.
+
+2004-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * README: Remove Dr. Pascal Molli's CVS URL from the
+ documentation.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * validate_repo.in: Loosen revision regex even more.
+
+2004-10-22 Derek Price <derek@ximbiot.com>
+
+ * validate_repo.in: Loosen revision regex, trusting later verification.
+ (Patch from Dan Peterson <dbpete@aol.com>.)
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-10-20 Derek Price <derek@ximbiot.com>
+
+ * validate_repo.in: Minor changes to help text.
+
+2004-10-20 Derek Price <derek@ximbiot.com>
+
+ * validate_repo.in (get_ignore_files_from_cvsroot): Add new script
+ hooks to default ignore list and alphabetize.
+
+2004-10-20 Derek Price <derek@ximbiot.com>
+
+ * validate_repo.in: Accept but log bad revision numbers.
+ (Patch from Dan Peterson <dbpete@aol.com>.)
+
+2004-09-13 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs_acls.in: New version from
+ "Peter Connolly" <Peter.Connolly@cnet.com>.
+ * cvs_acls.html: New file from
+ "Peter Connolly" <Peter.Connolly@cnet.com>.
+ * Makefile.am (EXTRA_DIST): Add cvs_acls.html
+ (Close ccvs Issue #170.)
+ * Makefile.in: Regenerated.
+
+2004-09-06 Mark D. Baushke <mdb@cvshome.org>
+
+ * log_accum.in (UseNewFmtStrings, new_directory,
+ imported_sources): New variables to adapt command-line processings
+ to support use of UseNewFmtStrings=yes in the CVSROOT/config file.
+
+ * log_accum.in: Change Log processing state machine to avoid being
+ confused by user uses of the key phrases 'Modified *', 'Added *,
+ 'Removed * and 'Log * in their log message.
+
+2004-08-30 Derek Price <derek@ximbiot.com>
+
+ * log_accum.in: Changes to supress warnings under Perl 5.8.5.
+ (Patch from Jeroen Ruigrok/asmodai <asmodai@wxs.nl>.)
+
+2004-07-16 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (SUBDIRS): Add pam subdir.
+ (Thanks to a report from Brian Murphy <brian@murphy.dk>.)
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Undo previous change.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Remove some files that are included by
+ virtue of appearing in configure.in rules.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (CLEANFILES): Clean bin_LINKS, not bin_SCRIPTS.
+ * Makefile.in: Regenerated.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: s/cvscheck/sandbox_status/.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: s/check_cvs/validate_repo/.
+
+2004-03-31 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in: Rename to...
+ * validate_repo.in: ...this.
+ * cvscheck.sh, cvscheck.man: Rename to...
+ * sandbox_status.sh, sandbox_status.man: ...this and this.
+ * Makefile.am (contrib_SCRIPTS): Use new script names.
+ (contrib_MANS, EXTRA_DIST): s/cvscheck/sandbox_status/.
+ * Makefile.in: Regenerated.
+
+2004-01-30 Derek Price <derek@ximbiot.com>
+
+ Close issue #155.
+ * log_accum.in: Remove unused variables.
+ (Patch from Ville Skyttä <scop@cvshome.org>.)
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-10-14 Derek Price <derek@ximbiot.com>
+
+ Port to pedantic POSIX 1003.1-2001 hosts, such as Debian GNU/Linux
+ testing with _POSIX2_VERSION=200112 in the environment.
+
+ * cvs2vendor.sh: Work with POSIX sort as well as with
+ traditional sort.
+ * rcs2sccs.sh, sccs2rcs.in: Likewise.
+ (Patch from Paul Eggert <eggert@twinsun.com>.)
+
+2003-09-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * sccs2rcs.in: Use @AWK@ to avoid ancient Solaris awk (no support
+ for the "?" operator). Add support for handling binary SCCS files.
+ (Suggestion from Allan Schrum <agschrum@mindspring.com>.)
+
+2003-09-12 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in (get_ignore_files_from_cvsroot): Handle error messages
+ specified in checkoutlist.
+ (Report from Matthew Doar <matt@trpz.com>.)
+
+2003-09-08 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in (get_history, check_revision): Pass the STDERR of child
+ processes through in verbose mode.
+
+2003-09-08 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in (get_history): Die on failure to close a pipe due to a system
+ error.
+ (check_revision): Simplify return syntax.
+
+2003-09-02 Derek Price <derek@ximbiot.com>
+
+ * pvcs2rcs.in: Don't rely on `which' to exit with a non-zero exit
+ status when it fails to find the requested executable. Use split in an
+ undeprecated manner. Don't assign to $_ just for split.
+
+2003-09-02 Derek Price <derek@ximbiot.com>
+
+ * pvcs2rcs.in: Use UNIX EOL instead of DOS EOL.
+
+2003-09-02 Derek Price <derek@ximbiot.com>
+
+ * check_cvs (main): Strip trailing (/+.)+ off examined directories.
+ (process_file): Log files corrupted by virtue of lacking an RCS
+ extension as they are found in verbose mode.
+ (check_revision): Log RCS `ci' command in verbose mode.
+
+2003-09-02 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in (get_history): Don't let revision locks prevent the
+ revision tag from being read.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2003-08-13 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in (get_history): Pass $cvsroot to `cvs rlog'.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2003-08-13 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in (get_history): Require -----... before the revision
+ marker, not a revision marker after -----...
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2003-08-09 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in: Don't use unneeded Cwd module.
+ (process_file): s/^(./)*// paths to files.
+ (look_at_cvs_file): Pass complete path from CVSROOT to get_history.
+ Remove unecessary syntax.
+ (get_history): Use `cvs rlog' instead of rlog. Return undef for $rinfo
+ when %rinfo is empty.
+ (check_revision): Remove unecessary call to cwd.
+
+2003-08-06 Derek Price <derek@ximbiot.com>
+
+ * commit_prep.in, log_accum.in: Port copious changes from Karl Fogel
+ and CollabNet. These changes add features, generalize, and organize.
+
+2003-07-07 Larry Jones <lawrence.jones@eds.com>
+
+ * rcs2log.1: New file from Paul Eggert <eggert@twinsun.com>
+ via Eric Seidel <eseidel@apple.com>.
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * Don't call CVS with the -l option since CVS no longer accepts it.
+ (Suggestion from Matt Doar <matt@trpz.com>.)
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-21 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.pl (get_history): Store the keyword expansion mode for
+ archives %finfo. Store revision data in %rinfo.
+ (process_file): Get new %$finfo and %$rinfo arguments from get_history.
+ Use %$rinfo rather than @$revisions. Pass $finfo and $rinfo to
+ check_revision.
+ (check_revision): Receive new %$finfo and %$rinfo arguments for
+ scripts. Check out using -kb when the file is binary, -ko otherwise
+ to preserve keywords as they were committed. Read any data not read by
+ called scripts before closing the file handle to the `cvs co' process
+ in order to avoid errors on close when data is left in the pipe.
+
+2003-04-16 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.pl (pod documentation): Add --all-revisions flag and
+ change documented behavior of --exec to execute once on each checkedu
+ out revision of a file. Document passing of an open file descriptor
+ rather than a file name. Major cosmetic changes to be more compatible
+ with POD.
+ (global variables): Add $all_revisions.
+ (main): Accept new --all-revisions flag. Check for newlines in --exec
+ arguments before testing for executability.
+ (process_file): Document new behavior. Don't filter revisions when
+ --all-revisions is specified. Don't process @scripts here. Minor
+ cosmetic changes.
+ (check_revision): Document new behavior. Process @scripts here.
+ Remove unused code. Minor cosmetic changes.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.pl (pod documentation::OPTIONS): Add FIXME comment as to
+ the usefulness of --exec.
+
+2003-04-09 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.pl: Fix copy & paste error in GPL disclaimer.
+ (pod documentation::SYNOPSIS): Show optional --verbose option with
+ --help.
+ (process_file): Print filename when $verbose. Reduce verbage used to
+ ignore files. Don't add directories to the count of total files.
+ Add comments.
+ (get_history): Make error message more understandable.
+ (main): Reorganize for readability. Remove unneeded debugging info.
+ Enable verbose help. Print some more statistics. Only print
+ statistics once.
+ (elements_in_branch, get_int_branch_revision,
+ get_int_mainline_revision, remove_duplicate_branches): Remove these
+ unused functions.
+ (verbose): New function for verbose prints.
+ (*): Use new verbose function.
+
+2003-04-09 Derek Price <derek@ximbiot.com>
+
+ * check_cvs.in: Update for usability. Add help text. Add standard
+ GNU GPL disclaimer to avoid being sued.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * rcs2log.sh: Import RedHat 8.0's use of mktemp from the CVS 1.11.2
+ RPM. Use new MKTEMP variable from configure.
+ * Makefile.in: Regenerated.
+
+2003-02-24 Larry Jones <lawrence.jones@eds.com>
+ and Donald Sharp <sharpd@cisco.com>
+
+ * check_cvs.in: Filenames with funky characters need to be quoted
+ correctly. Also needed to modify regex due to locked revisions of
+ files cause output to be different.
+
+ * check_cvs.in: Fixed multiple symlinks in your cvsroot,
+ improved CVSROOT/CVSROOT handling (Patch from Shlomo Reinstein
+ <shlomo.reinstein@intel.com). Fixed retrieving revisions of ,v
+ files. Added passwd, readers, and writers to list of files to
+ ignore and sorted list to match the one in src/mkmodules.c.
+
+2003-02-03 Derek Price <derek@ximbiot.com>
+
+ * newcvsroot.sh: New file.
+ * Makefile.am (contrib_SCRIPTS, EXTRA_DIST): Add newcvsroot.
+ * .cvsignore: Ditto.
+
+ * Makefile.in: Regenerated.
+
+2002-12-16 Derek Price <derek@ximbiot.com>
+
+ * cvs_acls.in: Fix split loop error with Perl 5.8.0.
+ (Patch from Ville Skyttä <ville.skytta@iki.fi>.)
+
+2002-12-11 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.am (install-data-local): test -e isn't portable: use -f.
+ * Makefile.in: Regenerated.
+ (Reported by Philip Brown <phil@bolthole.com>.)
+
+2002-11-21 Larry Jones <lawrence.jones@eds.com>
+
+ * .cvsignore: Add check_cvs.
+
+ * check_cvs.in: New script contributed by Donald Sharp.
+ * Makefile.am (contrib_SCRIPTS): Add check_cvs.
+ * Makefile.in: Regenerated.
+ * README: Add check_cvs and other missing scripts, alphabetize.
+
+2002-11-08 Derek Price <derek@ximbiot.com>
+
+ * debug_check_log.sh: Simplify some code. Attempt to default to
+ src/check.log before falling back to ./check.log.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-05-20 Derek Price <oberon@umich.edu>
+
+ * cvs_acls.in: Add note about using checkoutlist with avail
+ in the commentary's INSTALLATION section.
+ (Original patch from Ville Skyttä <ville.skytta@xemacs.org>.)
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2002-03-21 Derek Price <oberon@umich.edu>
+
+ * Makefile.am (install-data-local): Import a patch from RedHat which
+ was no longer necessary but causes a FIXME to print - maybe someone
+ will see it and fix it.
+ * Makefile.in: Regenerated.
+
+2001-12-06 Derek Price <oberon@umich.edu>
+
+ * cvs_acls.in: Allow ACL specification based on branch matching.
+ (Patch from Aaron Voisine <voisine@bytemobile.com>.)
+
+2001-10-16 Derek Price <dprice@collab.net>
+
+ * sccs2rcs.in: Replace Y2K bug fix with something more succint.
+ (Suggested by SAKAI Hiroaki <sakai.hiroaki@pfu.fujitsu.com>.)
+
+2001-10-16 Derek Price <dprice@collab.net>
+
+ * rcs2sccs.in: Fix Y2K bug.
+ (Patch from SAKAI Hiroaki <sakai.hiroaki@pfu.fujitsu.com>.)
+
+2001-09-06 Larry Jones <larry.jones@sdrc.com>
+ for Paul Eggert <eggert@twinsun.com>
+
+ Sync with revision 1.48 of the GNU Emacs sources. This
+ incorporates the following changes:
+
+ * rcs2log (Help, mainline code): Add new option -L FILE.
+ (Copyright): Update year.
+
+ (LANG, LANGUAGE, LC_ALL, LC_COLLATE, LC_CTYPE, LC_MESSAGES,
+ LC_NUMERIC, LC_TIME): New shell vars, to make sure we live in the C locale.
+
+ (mainline code): Handle nonstandard -u option differently, by
+ transforming it to standard form. Check for "Working file: ", not
+ "Working file:". Allow file names with spaces.
+
+ (SOH, rlogfile): New shell vars.
+ (rlogout): Remove. Its old functionality is mostly migrated to rlogfile.
+
+ Append ';;' to the last arm of every case statement, for portability to
+ ancient broken BSD shells.
+
+ (logins): Fix bug; was not being computed at all, lowering performance.
+
+ (pository): New var. This fixes some bugs where repositories are
+ remote, or have trailing slashes.
+
+ (authors): $llogout is never an empty shell var, so don't worry about that
+ possibility.
+
+ (printlogline, mainline code): Fix bug with SOH's being put into the output.
+
+
+ 2001-07-20 Gerd Moellmann <gerd@gnu.org>
+
+ * rcs2log: Update copyright notice.
+
+
+ 2001-01-03 Paul Eggert <eggert@twinsun.com>
+
+ * rcs2log: Avoid security hole allowing attacker to
+ cause user of rcs2log to overwrite arbitrary files, fixing
+ a bug reported by Morten Welinder.
+
+ Don't put "exit 1" at the end of the exit trap; it's
+ ineffective in POSIX shells.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-21 Larry Jones <larry.jones@sdrc.com>
+
+ * sccs2rcs.in: Fix typo: missing quote.
+ (Patch submitted by "Mark D. Baushke" <mdb@cvshome.org>.)
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-05-30 Derek Price <dprice@collab.net>
+
+ * pvcs2cvs.in: Rename to...
+ * pvcs2rcs.in: here.
+ * .cvsignore: Add pvcs2rcs.
+ * Makefile.am (contrib_SCRIPTS): Change pvcs2cvs to pvcs2rcs.
+
+ * Makefile.in: Regenerated.
+
+2001-05-29 Derek Price <dprice@collab.net>
+ patch from Pavel Roskin <proski@gnu.org>
+
+ * Makefile.am (install-data-local): Double hash comment in rule since
+ single hash comments are not portable.
+
+ * Makefile.in: Regenerated.
+
+2001-05-29 Derek Price <dprice@collab.net>
+
+ * pvcs2cvs.in: New file.
+ * Makefile.am (contrib_SCRIPTS): Add pcvs2cvs.
+
+ * Makefile.in: Regenerated.
+
+2001-05-23 Larry Jones <larry.jones@sdrc.com>
+
+ * sccs2rcs.in: No need for grep when you're already using awk.
+
+ * sccs2rcs.in: Fix y2k bug correctly.
+ (Reported by "Hayes, Ted (London)" <HayesRog@exchange.uk.ml.com>.)
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-04-16 Derek Price <dprice@collab.net>
+
+ * log.pl: Accept new '-V' option for non-verbose status messages.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2001-01-05 Derek Price <derek.price@openavenue.com>
+
+ * contrib/Makefile.am (EXTRA_DIST, SUFFIXES, .pl:, .csh:): Move some
+ script targets to configure.in - see ../ChangeLog for more
+
+ * contrib/clmerge.in: Rename from clmerge.pl
+ * contrib/cln_hist.in: Rename from cln_hist.pl
+ * contrib/commit_prep.in: Rename from commit_prep.pl
+ * contrib/cvs_acls.in: Rename from cvs_acls.pl
+ * contrib/log.in: Rename from log.pl
+ * contrib/log_accum.in: Rename from log_accum.pl
+ * contrib/mfpipe.in: Rename from mfpipe.pl
+ * contrib/rcslock.in: Rename from rcslock.pl
+ * contrib/sccs2rcs.in: Rename from scc2rcs.csh
+
+ * contrib/clmerge.pl: Rename to clmerge.in
+ * contrib/cln_hist.pl: Rename to cln_hist.in
+ * contrib/commit_prep.pl: Rename to commit_prep.in
+ * contrib/cvs_acls.pl: Rename to cvs_acls.in
+ * contrib/log.pl: Rename to log.in
+ * contrib/log_accum.pl: Rename to log_accum.in
+ * contrib/mfpipe.pl: Rename to mfpipe.in
+ * contrib/rcslock.pl: Rename to rcslock.in
+ * contrib/sccs2rcs.csh: Rename to sccs2rcs.in
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+
+2000-12-14 Derek Price <derek.price@openavenue.com>
+ Thomas Maeder <maeder@glue.ch>
+
+ * sccs2rcs.csh: unkludge a Y2k workaround
+
+2000-10-23 Derek Price <derek.price@openavenue.com>
+
+ * debug_check_log.sh: added this script for analyzing sanity.sh output
+ * Makefile.in: add above file to DISTFILES and CONTRIB_PROGS
+ * .cvsignore: add debug_check_log
+
+2000-09-07 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@
+ from autoconf.
+
+2000-02-25 Larry Jones <larry.jones@sdr.com>
+
+ * log.pl: Get committer from command line instead of getlogin
+ so that client/server works correctly.
+ * loc_accum.pl: Ditto.
+
+2000-01-24 K.J. Paradise <kj@sourcegear.com>
+
+ * sccs2rcs.csh: fixed a y2k bug. This was submitted
+ by Ceri Davies <ceri_davies@isdcorp.com>, and looks
+ okay to me.
+
+1999-01-19 Graham Stoney <greyham@research.canon.com.au>
+
+ * log.pl: The author commited the canonical perl "localtime" Y2K
+ offence, of printing "19$year" instead of (1900 + $year). Of
+ course, the result is non-compliance in year 2000. Fix it.
+
+1998-10-14 Jim Kingdon
+
+ * ccvs-rsh.pl: Removed; it was not in DISTFILES so it didn't
+ actually get distributed. I'm going to move it to the web on the
+ theory that the web is a better place for such things.
+ * README: Don't mention it.
+
+ * Makefile.in (dist-dir, distclean): Remove references to elib.
+ * elib: Remove this subdirectory and all its contents. It went
+ with pcl-cvs, which is no longer distributed with CVS.
+
+1998-09-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * pvcs_to_rcs: Removed; it was not in DISTFILES so it didn't
+ actually get distributed. I'm going to move it to the web on the
+ theory that the web is a better place for such things.
+ * README: Don't mention it.
+
+1998-09-10 Jim Kingdon
+
+ Check in Paul Eggert <eggert@twinsun.com>'s submission of
+ 1998-08-15. I also ran "cvs admin -ko" on this file so that his
+ version number would be intact (not an ideal solution, because
+ people will import it into other repositories, but I don't feel
+ like hacking the master version).
+ * rcs2log.sh: Sync with master version at gnu.org.
+
+1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Don't mention listener, since it was removed a while
+ ago.
+ * listen2.c, listen2.mak: Removed; because there is no easy way to
+ pass a socket (as opposed to file descriptor) from one process to
+ another on Windows, this isn't a promising approach (at least not
+ in this form).
+ * Makefile.in (DISTFILES): Remove them.
+ * .cvsignore: Remove listen2.ncb listen2.mdp Debug.
+
+1998-05-11 W. Bradley Rubenstein
+
+ * log.pl: Check for errors from open and exec.
+
+Sat Feb 21 21:59:45 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * Makefile.in (clean): Change "/bin/rm" to "rm".
+
+Thu Aug 7 22:42:23 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * pvcs_to_rcs: Remove RCS keywords. Remove $Log and move the data
+ to this ChangeLog (below). Add paragraph that David Martin
+ emailed along with the script.
+
+ Revision 1.6 1997/03/07 16:21:28 divad
+ Need to explicitly state archive name in PVCS get command for
+ those cases where the case of the workfile and the case of the
+ archive file are different (OS/2)
+
+ Revision 1.5 1997/03/07 00:31:04 divad
+ Added capitalized extensions and framemaker files as binaries;
+ also overriding any path specification for workfiles at PVCS
+ checkout (most annoying).
+
+ Revision 1.4 1997/03/06 21:04:55 divad
+ Added \n to the end of each comment line to prevent multi-line
+ comments for a single revision from "merging"
+
+ Revision 1.3 1997/03/06 19:50:25 divad
+ Corrected bug in binary extensions; correcting processing
+ comment strings with double quotes
+
+ Revision 1.2 1997/03/06 17:29:10 divad
+ Provided list of extensions (rather than using Unix file
+ command) to determine which files are binary; also printing
+ version label as they are applied
+
+ Revision 1.1 1997/02/26 00:04:29 divad
+ Perl script to convert pvcs archives to rcs archives
+
+ * README: mention pvcs_to_rcs.
+ * pvcs_to_rcs: New file. This is the file as I got it from David
+ Martin. Will be checking in the tweaks shortly.
+
+17 May 1997 Jim Kingdon
+
+ * listen2.c: Failed attempt at making this do what it was
+ intended to do. Will need to rethink the approach.
+ * listen2.mak: The usual involuntary tweaks.
+ * .cvsignore: Add listen2.ncb listen2.mdp.
+
+Mon May 12 11:59:23 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * listener.c: Removed; see ../ChangeLog for rationale.
+
+10 May 1997 Jim Kingdon
+
+ * listen2.c, listen2.mak: New files.
+ * Makefile.in (DISTFILES): Add them.
+ * .cvsignore: Add Debug.
+
+Thu Feb 20 22:43:45 1997 David J MacKenzie <djm@va.pubnix.com>
+
+ * rcs-to-cvs.sh: Put temporary files in /var/tmp or /usr/tmp
+ whichever one exists. Just call "vi" not "/usr/ucb/vi".
+
+Mon Feb 17 08:51:37 1997 Greg A. Woods <woods@most.weird.com>
+
+ * .cvsignore: added 'cvs2vendor' target from Feb. 12 changes.
+
+ * log_accum.pl (build_header): added "Repository:" to the report
+ header to show the first argument supplied to the script by CVS.
+ [[this value seems spuriously to be wrong when client is used]]
+ ($hostdomain): correct order of initialization from the Feb. 12
+ changes.
+ ($modulename): add more commentary about using '-M' to to get a
+ meaningful string here.
+ Tweak a few other comments from the Feb. 12 changes.
+
+Wed Feb 12 10:27:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cln_hist.pl, commit_prep.pl, cvs2vendor.sh, cvs_acls.pl,
+ cvscheck.man, cvscheck.sh, cvshelp.man, descend.man, descend.sh,
+ log_accum.pl, mfpipe.pl, rcs-to-cvs.sh, rcs2log.sh, rcs2sccs.sh,
+ sccs2rcs.csh: Remove $Id; we decided to get rid of these some
+ time ago.
+
+Wed Feb 12 00:24:33 1997 Greg A. Woods <woods@most.weird.com>
+
+ * cvs2vendor.sh: new script.
+ * README: noted new cvs2vendor script.
+ * Makefile.in (DISTFILES): added cvs2vendor.sh.
+ (CONTRIB_PROGS): added cvs2vendor.
+
+ * log_accum.pl (show_wd): new variable, initialized to 0.
+ - set $show_wd if '-w' option found while parsing @ARGV.
+ - don't add 'In directory' line to report header unless $show_wd
+ is set.
+ (domainname): prepend a leading '.' if none there so that
+ concatenation with $hostname works (those with a FQDN hostname
+ *and* a domainname still lose).
+ (mail_notification): don't set a "From:" header -- the mailer will.
+
+Wed Jan 8 14:48:58 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, README, log.pl: Remove CVSid; we decided to get rid
+ of these some time ago.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Remove "675" paragraph; see ../ChangeLog for rationale.
+
+Thu Oct 17 18:28:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * patch-2.1-.new-fix: Removed; it was not in DISTFILES so it never
+ made it into distributions. It also isn't clear what it has to do
+ with CVS. It is available from
+ ftp://ftp.weird.com/pub/patch-2.1-.new-fix
+ * README: Remove entry for patch-2.1-.new-fix.
+
+Wed Oct 16 10:22:44 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * rcs2log.sh: Change date output format to something CVS 1.9
+ accepts. I think this breaks the Sep 29 change, but I don't have
+ a copy of CVS 1.5 handy, so I can't find a format that works with
+ both, and I think it's more important that it work with the
+ version it's distributed with.
+
+Sat Oct 12 21:18:19 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Don't mention pcl-cvs; it isn't here any more.
+
+Sun Sep 29 19:45:19 1996 Greg A. Woods <woods@most.weird.com>
+
+ * README: add entry for patch-2.1-.new-fix.
+
+ * README: re-write the top section a bit.
+
+ * patch-2.1-.new-fix: re-generated using fixed "cvs patch" command.
+
+ * patch-2.1-.new-fix: new file.
+
+Sun Sep 29 14:25:28 1996 Dave Love <d.love@dl.ac.uk>
+
+ * rcs2log.sh (month_data): Make default date format acceptable to
+ CVS post v1.8 as well as earlier CVSs and RCS.
+ Message-Id: <199609291546.QAA25531@mserv1.dl.ac.uk>
+ To: bug-gnu-emacs@prep.ai.mit.edu
+
+Thu Aug 29 11:58:03 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * rcs2log: Update FSF address.
+
+ * rcs2log: Be more aggressive about finding the author's full
+ name; try nismatch and ypmatch.
+
+ * rcs2log: If the hostname appears not to be fully qualified, see
+ if domainname provides any useful information.
+
+Fri Aug 16 16:02:36 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in (installdirs): support this target
+
+Mon May 6 13:04:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (install): Don't tell user to run cvsinit. It isn't
+ called cvsinit anymore, and it isn't necessary (repositories are,
+ and need to be, compatible between cvs versions).
+
+Sun Apr 14 11:30:36 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * Removed pcl-cvs/ subdir; see tools/ subdir in the top-level from
+ now on.
+ Added elib/ subdir.
+
+ * Makefile.in (dist-dir): Removed all references to pcl-cvs/
+ subdir.
+
+Wed Mar 6 10:20:28 1996 Greg A. Woods <woods@most.weird.com>
+
+ * log_accum.pl: ($MAILER): use sendmail directly to allow other
+ headers to be included
+ * log_accum.pl (mail_notification): add support to allow settting
+ of Reply-To and Date header fields in the sent mail; remove $mailto
+ argument and use the global variable (as with $replyto).
+ * log_accum.pl: add -R option for mail_notification()'s optional
+ Reply-To value [default to $login]
+
+Fri Mar 1 01:51:56 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * listener.c: added as mentioned in ../README.VMS
+
+Mon Feb 19 13:37:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Don't just tell people "we don't want your script"; tell
+ them what to do instead.
+
+Thu Feb 1 14:28:16 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * Makefile.in (DISTFILES): added `rcs2sccs.sh', as mentioned in
+ README.
+
+Thu Jan 18 09:39:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Talk about submitting changes to contrib directory.
+
+Tue Nov 14 15:28:25 1995 Greg A. Woods <woods@most.weird.com>
+
+ * README: fix some spelling and other typos
+
+ * Makefile.in: if I need reminding to run cvsinit....
+
+Tue Nov 14 13:47:40 1995 Greg A. Woods <woods@most.weird.com>
+
+ * log_accum.pl:
+ - Fix 'cvs status' to use global -Qq options
+ - fix up a couple of comments, incl., my proper address
+
+ * log.pl: add a CVSid and fix a couple of comments
+
+Sun Oct 1 02:02:57 1995 Peter Wemm <peter@haywire.dialix.com>
+
+ * Makefile.in: supply a suffix rule to deal with .sh "source"
+
+Sat Jul 29 17:29:13 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * log.pl: Use global options -Qq, not command options -Qq.
+
+ * Makefile.in (install): Look for $(PROGS) and
+ $(CONTRIB_PROGS) in build dir, not srcdir.
+
+Fri Jul 28 19:48:45 1995 Paul Eggert <eggert@twinsun.com>
+
+ * rcs2log.sh: Sync with latest Emacs snapshot.
+
+Thu Jul 27 20:29:30 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * rcs2log.sh: import of initial WNT port work
+
+Fri Jul 14 22:38:44 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * rcs-to-cvs.sh: Changes from David J. Mackenzie.
+ Set permissions on new repository files correctly.
+ Ignore *~ files.
+
+Thu Jul 13 23:04:12 CDT 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (.pl, .csh): *Never* redirect output directly to
+ the target (usu $@) of a rule. Instead, redirect to a temporary
+ file, and then move that temporary to the target. I chose to
+ name temporary files $@-t. Remember to be careful that the length
+ of the temporary file name not exceed the 14-character limit.
+
+Sun Jul 9 21:16:53 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ These are actually Greg Woods' changes:
+
+ * clmerge.pl, cvscheck.sh, descend.sh, dirfns.shar, rcs-to-cvs.sh,
+ rcs2log.sh, sccs2rcs.csh: renamed from the corresponding files
+ sans extensions.
+
+ * rcs2sccs.sh: new file.
+
+Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * rcs2log.sh: oops, one more thing that should not have been
+ there.
+ - fix interpreter file syntax.
+ - remove "fix" for separating filenames and comments
+
+ * Makefile.in: hmm... thought rcs2log was in RCS-5.7 for some
+ reason -- it's not, so we'll install it from here....
+ - fix typo -- that's what you get for re-doing changes by hand!
+ - updates to support proper transformation and installation of
+ renamed files (from previous local changes)
+
+ * .cvsignore: one more target noted...
+
+ * sccs2rcs.csh: set up the interpreter file for updating by
+ Makefile (from previous local changes)
+
+ * log_accum.pl, log.pl, commit_prep.pl:
+ - set up the interpreter file for updating by Makefile
+ - various modifications, updates, and enhancements
+ (from previous local changes)
+
+ * rcslock.pl, mfpipe.pl, cvs_acls.pl, cln_hist.pl, clmerge.pl:
+ - set up the interpreter file for updating by Makefile
+ (from previous local changes)
+ - include changes from 1.5 here too, if any
+
+ * README:
+ - remove extensions from filenames to match installed names
+ (from previous local changes)
+
+ * .cvsignore: - added $(CONTRIB_PROGS) (from previous local changes)
+
+
+Thu Jun 29 10:43:07 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (distclean): Also remove pcl-cvs/Makefile.
+
+Thu Jun 8 15:32:29 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * intro.doc: Added.
+ * Makefile.in (DISTFILES): Add intro.doc.
+
+Sat May 27 08:46:00 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (Makefile): Regenerate only Makefile in current
+ directory when Makefile.in is out of date. Depend on ../config.status.
+
+Mon May 8 13:06:29 1995 Bryan O'Sullivan <bos@serpentine.com>
+
+ * README: added an entry for ccvs-rsh.pl.
+
+Sun Apr 30 23:50:32 1995 Bryan O'Sullivan <bos@serpentine.com>
+
+ * ccvs-rsh.pl: fixed a typo and added more flexible use of
+ CVS_PROXY_USER.
+
+Sun Apr 30 14:56:21 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * clmerge: Changes from Tom Tromey --- fix bug in date comparison
+ function.
+
+Sat Apr 29 20:53:08 1995 Bryan O'Sullivan <bos@serpentine.com>
+
+ * ccvs-rsh.pl: created. See the file itself for documentation.
+
+ * Makefile.in (DISTFILES): added ccvs-rsh.pl to the list of
+ files to install.
+
+Fri Apr 28 22:32:45 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (DISTFILES): Brought up-to-date with current
+ directory contents.
+ (dist-dir): Renamed from dist-dir; use DISTDIR variable, passed
+ from parent.
+
+Mon Feb 13 13:32:07 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * rcs2log: rcs2log was originally in this tree; how did it get
+ deleted? Anyway, this is the version distributed with Emacs
+ 19.28, hacked to support CVS and Remote CVS.
+
+Mon Jul 26 13:18:23 1993 David J. Mackenzie (djm@thepub.cygnus.com)
+
+ * rcs-to-cvs: Rewrite in sh.
+
+Wed Jul 14 21:16:40 1993 David J. Mackenzie (djm@thepub.cygnus.com)
+
+ * rcs-to-cvs: Don't source .cshrc or hardcode paths.
+ Make respository dir if needed. Don't suppress errors
+ (such as prompts) from co.
+
+Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in, configure.in: removed traces of namesubdir,
+ -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced
+ copyrights to '92, changed some from Cygnus to FSF.
+
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
new file mode 100644
index 0000000..d8bdaa4
--- /dev/null
+++ b/contrib/Makefile.am
@@ -0,0 +1,110 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for GNU CVS contributed sources.
+# Do not use this makefile directly, but only from `../Makefile'.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+SUBDIRS = pam
+
+contribdir = $(pkgdatadir)/contrib
+
+contrib_SCRIPTS = \
+ clmerge \
+ cln_hist \
+ commit_prep \
+ cvs2vendor \
+ cvs_acls \
+ debug_check_log \
+ log \
+ log_accum \
+ mfpipe \
+ newcvsroot \
+ pvcs2rcs \
+ rcs-to-cvs \
+ rcs2log \
+ rcslock \
+ sandbox_status \
+ sccs2rcs \
+ validate_repo
+
+contrib_DATA = \
+ README \
+ intro.doc \
+ rcs-5.7-commitid.patch
+
+contrib_MANS = \
+ rcs2log.1 \
+ sandbox_status.man
+
+bin_LINKS = \
+ rcs2log
+
+EXTRA_DIST = \
+ .cvsignore \
+ $(contrib_DATA) \
+ $(contrib_MANS) \
+ cvs2vendor.sh \
+ sandbox_status.sh \
+ cvshelp.man \
+ cvs_acls.html \
+ debug_check_log.sh \
+ descend.sh \
+ descend.man \
+ dirfns.shar \
+ newcvsroot.sh \
+ rcs-5.7-commitid.patch \
+ rcs-to-cvs.sh \
+ rcs2log.sh \
+ rcs2sccs.sh
+
+CLEANFILES = $(bin_LINKS) $(contrib_SCRIPTS)
+
+# we'd rather have a link here rather than two copies of a script
+install-data-local:
+ : FIXME - this path should be determined dynamically from bindir
+ : and contribdir
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_LINKS)'; for p in $$list; do \
+ echo "test ! -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ echo " && cd $(DESTDIR)$(bindir) && $(LN_S) ../share/$(PACKAGE)/contrib/`echo $$p|sed '$(transform)'` ."; \
+ (test ! -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'` \
+ && cd $(DESTDIR)$(bindir) && $(LN_S) ../share/$(PACKAGE)/contrib/`echo $$p|sed '$(transform)'` .) \
+ || (echo "Link creation failed" && if test -f $$p; then \
+ echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ else if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ else :; fi; fi); \
+ done
+
+uninstall-local:
+ @$(NORMAL_UNINSTALL)
+ list='$(bin_LINKS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+SUFFIXES = .sh
+
+.sh:
+ rm -f $@
+ cp $< $@
+ chmod +x $@
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/contrib/Makefile.in b/contrib/Makefile.in
new file mode 100644
index 0000000..acd9f8e
--- /dev/null
+++ b/contrib/Makefile.in
@@ -0,0 +1,751 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for GNU CVS contributed sources.
+# Do not use this makefile directly, but only from `../Makefile'.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = contrib
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/clmerge.in $(srcdir)/cln_hist.in \
+ $(srcdir)/commit_prep.in $(srcdir)/cvs_acls.in \
+ $(srcdir)/log.in $(srcdir)/log_accum.in $(srcdir)/mfpipe.in \
+ $(srcdir)/pvcs2rcs.in $(srcdir)/rcs2log.sh \
+ $(srcdir)/rcslock.in $(srcdir)/sccs2rcs.in \
+ $(srcdir)/validate_repo.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = validate_repo clmerge cln_hist commit_prep \
+ cvs_acls log log_accum mfpipe pvcs2rcs rcs2log rcslock \
+ sccs2rcs
+am__installdirs = "$(DESTDIR)$(contribdir)" "$(DESTDIR)$(contribdir)"
+contribSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(contrib_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+contribDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(contrib_DATA)
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+SUBDIRS = pam
+contribdir = $(pkgdatadir)/contrib
+contrib_SCRIPTS = \
+ clmerge \
+ cln_hist \
+ commit_prep \
+ cvs2vendor \
+ cvs_acls \
+ debug_check_log \
+ log \
+ log_accum \
+ mfpipe \
+ newcvsroot \
+ pvcs2rcs \
+ rcs-to-cvs \
+ rcs2log \
+ rcslock \
+ sandbox_status \
+ sccs2rcs \
+ validate_repo
+
+contrib_DATA = \
+ README \
+ intro.doc \
+ rcs-5.7-commitid.patch
+
+contrib_MANS = \
+ rcs2log.1 \
+ sandbox_status.man
+
+bin_LINKS = \
+ rcs2log
+
+EXTRA_DIST = \
+ .cvsignore \
+ $(contrib_DATA) \
+ $(contrib_MANS) \
+ cvs2vendor.sh \
+ sandbox_status.sh \
+ cvshelp.man \
+ cvs_acls.html \
+ debug_check_log.sh \
+ descend.sh \
+ descend.man \
+ dirfns.shar \
+ newcvsroot.sh \
+ rcs-5.7-commitid.patch \
+ rcs-to-cvs.sh \
+ rcs2log.sh \
+ rcs2sccs.sh
+
+CLEANFILES = $(bin_LINKS) $(contrib_SCRIPTS)
+SUFFIXES = .sh
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .sh
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu contrib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+validate_repo: $(top_builddir)/config.status $(srcdir)/validate_repo.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+clmerge: $(top_builddir)/config.status $(srcdir)/clmerge.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+cln_hist: $(top_builddir)/config.status $(srcdir)/cln_hist.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+commit_prep: $(top_builddir)/config.status $(srcdir)/commit_prep.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+cvs_acls: $(top_builddir)/config.status $(srcdir)/cvs_acls.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+log: $(top_builddir)/config.status $(srcdir)/log.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+log_accum: $(top_builddir)/config.status $(srcdir)/log_accum.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+mfpipe: $(top_builddir)/config.status $(srcdir)/mfpipe.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+pvcs2rcs: $(top_builddir)/config.status $(srcdir)/pvcs2rcs.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+rcs2log: $(top_builddir)/config.status $(srcdir)/rcs2log.sh
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+rcslock: $(top_builddir)/config.status $(srcdir)/rcslock.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sccs2rcs: $(top_builddir)/config.status $(srcdir)/sccs2rcs.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-contribSCRIPTS: $(contrib_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(contribdir)" || $(mkdir_p) "$(DESTDIR)$(contribdir)"
+ @list='$(contrib_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(contribSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(contribdir)/$$f'"; \
+ $(contribSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(contribdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-contribSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(contrib_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(contribdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(contribdir)/$$f"; \
+ done
+uninstall-info-am:
+install-contribDATA: $(contrib_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(contribdir)" || $(mkdir_p) "$(DESTDIR)$(contribdir)"
+ @list='$(contrib_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(contribDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(contribdir)/$$f'"; \
+ $(contribDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(contribdir)/$$f"; \
+ done
+
+uninstall-contribDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(contrib_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(contribdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(contribdir)/$$f"; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(SCRIPTS) $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(contribdir)" "$(DESTDIR)$(contribdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-contribDATA install-contribSCRIPTS \
+ install-data-local
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-contribDATA uninstall-contribSCRIPTS \
+ uninstall-info-am uninstall-local
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+ clean clean-generic clean-recursive ctags ctags-recursive \
+ distclean distclean-generic distclean-recursive distclean-tags \
+ distdir dvi dvi-am html html-am info info-am install \
+ install-am install-contribDATA install-contribSCRIPTS \
+ install-data install-data-am install-data-local install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-generic \
+ mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-contribDATA \
+ uninstall-contribSCRIPTS uninstall-info-am uninstall-local
+
+
+# we'd rather have a link here rather than two copies of a script
+install-data-local:
+ : FIXME - this path should be determined dynamically from bindir
+ : and contribdir
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_LINKS)'; for p in $$list; do \
+ echo "test ! -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ echo " && cd $(DESTDIR)$(bindir) && $(LN_S) ../share/$(PACKAGE)/contrib/`echo $$p|sed '$(transform)'` ."; \
+ (test ! -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'` \
+ && cd $(DESTDIR)$(bindir) && $(LN_S) ../share/$(PACKAGE)/contrib/`echo $$p|sed '$(transform)'` .) \
+ || (echo "Link creation failed" && if test -f $$p; then \
+ echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ else if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ else :; fi; fi); \
+ done
+
+uninstall-local:
+ @$(NORMAL_UNINSTALL)
+ list='$(bin_LINKS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+.sh:
+ rm -f $@
+ cp $< $@
+ chmod +x $@
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/README b/contrib/README
new file mode 100644
index 0000000..231a1a3
--- /dev/null
+++ b/contrib/README
@@ -0,0 +1,148 @@
+This "contrib" directory is a place holder for code/scripts sent to me
+by contributors around the world. This README file will be kept
+up-to-date from release to release. BUT, we must point out that these
+contributions are really, REALLY UNSUPPORTED. In fact, we probably
+don't even know what some of them really do. We certainly do not
+guarantee to have tried them, or ported them to work with this CVS
+distribution. If you have questions, your best bet is to contact the
+original author, but you should not necessarily expect a reply, since
+the author may not be available at the address given.
+
+USE AT YOUR OWN RISK -- and all that stuff.
+
+"Unsupported" also means that no one has volunteered to accept and check
+in changes to this directory. So submissions for new scripts to add
+here are unlikely to be accepted. Suggested changes to the existing
+scripts here conceivably might, but that isn't clear either, unless of
+course they come from the original author of the script.
+
+If you have some software that works with CVS that you wish to offer it
+is suggested that you make it available by FTP or HTTP and then announce
+it on the info-cvs mailing list.
+
+An attempt at a table of Contents for this directory:
+
+ README This file.
+
+ clmerge A perl script to handle merge conflicts in GNU
+ style ChangeLog files .
+ Contributed by Tom Tromey <tromey@busco.lanl.gov>.
+
+ cln_hist A perl script to compress your
+ $CVSROOT/CVSROOT/history file, as it can grow quite
+ large after extended use.
+ Contributed by David G. Grubbs <dgg@ksr.com>
+
+ commit_prep A perl script, to be combined with log_accum.pl, to
+ log_accum provide for a way to combine the individual log
+ messages of a multi-directory "commit" into a
+ single log message, and mail the result somewhere.
+ Can also do other checks for $Id and that you are
+ committing the correct revision of the file.
+ Read the comments carefully.
+ Contributed by David Hampton <hampton@cisco.com>.
+
+ cvs2vendor A shell script to move changes from a repository
+ that was started without a vendor branch to one
+ that has a vendor branch.
+ Contributed by Greg A. Woods <woods@planix.com>.
+
+ cvs_acls A perl script that implements Access Control Lists
+ cvs_acls.html by using the "commitinfo" hook provided with the
+ "cvs commit" command.
+ Contributed by David G. Grubbs <dgg@ksr.com>.
+ Enhanced by Peter Connolly <Peter.Connolly@cnet.com>.
+
+ cvshelp.man An introductory manual page written by Lowell Skoog
+ <fluke!lowell@uunet.uu.net>. It is most likely
+ out-of-date relative to CVS 1.3, but still may be
+ useful.
+
+ debug_check_log A shell script to help analyze sanity check failures.
+ Contributed by Derek R. Price <derek@ximbiot.com>.
+
+ descend A shell script that can be used to recursively
+ descend.man descend through a directory. In CVS 1.2, this was
+ very useful, since many of the commands were not
+ recursive. In CVS 1.3 (and later), however, most of
+ the commands are recursive. However, this may still
+ come in handy.
+ Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+
+ dirfns A shar file which contains some code that might
+ help your system support opendir/readdir/closedir,
+ if it does not already.
+ Copied from the C-News distribution.
+
+ intro.doc A user's view of what you need to know to get
+ started with CVS.
+ Contributed by <Steven.Pemberton@cwi.nl>.
+
+ log A perl script suitable for including in your
+ $CVSROOT/CVSROOT/loginfo file for logging commit
+ changes. Includes the RCS revision of the change
+ as part of the log.
+ Contributed by Kevin Samborn <samborn@sunrise.com>.
+
+ log_accum See commit_prep.
+
+ mfpipe Another perl script for logging. Allows you to
+ pipe the log message to a file and/or send mail
+ to some alias.
+ Contributed by John Clyne <clyne@niwot.scd.ucar.edu>.
+
+ pvcs2rcs A perl script to convert a PVCS tree to an RCS tree.
+
+ rcs-5.7-commitid.patch
+ Patch to RCS 5.7 sources of 1995-06-16 to support
+ the newphrase 'commitid' used by CVS and CVSNT.
+
+ rcs-5.7-sameuserlocks.patch
+ Patch to RCS 5.7 sources from 2003-10-24
+ submitted to both help-rcs@gnu.org and Redhat.
+ Included in many Redhat GNU/Linux distribution
+ RPM files. A new -S switch to the co command
+ will disallow the user to check out the same
+ file twice.
+
+ rcs-5.7-security.patch
+ Patch to RCS 5.7 sources from 2001-01-05
+ included in many GNU/Linux distributions as applied
+ by Preston Brown <pbrown@redhat.com>
+ tmpfile security patch from Olaf Kirch <okir@lst.de>.
+
+ rcs-to-cvs Script to import sources that may have been under
+ RCS control already.
+ Contributed by Per Cederqvist <ceder@lysator.liu.se>.
+
+ rcs2log A shell script to create a ChangeLog-format file
+ given only a set of RCS files.
+ Contributed by Paul Eggert <eggert@twinsun.com>.
+
+ rcs2sccs A shell script to convert simple RCS files into
+ SCCS files, originally gleaned off the network
+ somewhere (originally by "kenc") and modified by
+ Jerry Jelinek <jerry@rmtc.Central.Sun.COM> and
+ Brian Berliner <berliner@sun.com> to increase
+ robustness and add support for one-level of branches.
+
+ rcslock A perl script that can be added to your commitinfo
+ file that tries to determine if your RCS file is
+ currently locked by someone else, as might be the
+ case for a binary file.
+ Contributed by John Rouillard <rouilj@cs.umb.edu>.
+
+ sandbox_status
+ sandbox_status.man
+ Identifies files added, changed, or removed in a
+ checked out CVS tree; also notices unknown files.
+ Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+
+ sccs2rcs A C-shell script that can convert (some) SCCS files
+ into RCS files, retaining the info contained in the
+ SCCS file (like dates, author, and log message).
+ Contributed by Ken Cox <kenstir@viewlogic.com>.
+
+ verify_repo A perl script to check an entire repository for
+ corruption.
+ Contributed by Donald Sharp <sharpd@cisco.com>.
diff --git a/contrib/clmerge.in b/contrib/clmerge.in
new file mode 100755
index 0000000..f2163e5
--- /dev/null
+++ b/contrib/clmerge.in
@@ -0,0 +1,164 @@
+#! @PERL@
+
+# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# Merge conflicted ChangeLogs
+# tromey Mon Aug 15 1994
+
+# Usage is:
+#
+# cl-merge [-i] file ...
+#
+# With -i, it works in place (backups put in a ~ file). Otherwise the
+# merged ChangeLog is printed to stdout.
+
+# Please report any bugs to me. I wrote this yesterday, so there are no
+# guarantees about its performance. I recommend checking its output
+# carefully. If you do send a bug report, please include the failing
+# ChangeLog, so I can include it in my test suite.
+#
+# Tom
+# ---
+# tromey@busco.lanl.gov Member, League for Programming Freedom
+# Sadism and farce are always inexplicably linked.
+# -- Alexander Theroux
+
+
+# Month->number mapping. Used for sorting.
+%months = ('Jan', 0,
+ 'Feb', 1,
+ 'Mar', 2,
+ 'Apr', 3,
+ 'May', 4,
+ 'Jun', 5,
+ 'Jul', 6,
+ 'Aug', 7,
+ 'Sep', 8,
+ 'Oct', 9,
+ 'Nov', 10,
+ 'Dec', 11);
+
+# If '-i' is given, do it in-place.
+if ($ARGV[0] eq '-i') {
+ shift (@ARGV);
+ $^I = '~';
+}
+
+$lastkey = '';
+$lastval = '';
+$conf = 0;
+%conflist = ();
+
+$tjd = 0;
+
+# Simple state machine. The states:
+#
+# 0 Not in conflict. Just copy input to output.
+# 1 Beginning an entry. Next non-blank line is key.
+# 2 In entry. Entry beginner transitions to state 1.
+while (<>) {
+ if (/^<<<</ || /^====/) {
+ # Start of a conflict.
+
+ # Copy last key into array.
+ if ($lastkey ne '') {
+ $conflist{$lastkey} = $lastval;
+
+ $lastkey = '';
+ $lastval = '';
+ }
+
+ $conf = 1;
+ } elsif (/^>>>>/) {
+ # End of conflict. Output.
+
+ # Copy last key into array.
+ if ($lastkey ne '') {
+ $conflist{$lastkey} = $lastval;
+
+ $lastkey = '';
+ $lastval = '';
+ }
+
+ foreach (reverse sort clcmp keys %conflist) {
+ print STDERR "doing $_" if $tjd;
+ print $_;
+ print $conflist{$_};
+ }
+
+ $lastkey = '';
+ $lastval = '';
+ $conf = 0;
+ %conflist = ();
+ } elsif ($conf == 1) {
+ # Beginning an entry. Skip empty lines. Error if not a real
+ # beginner.
+ if (/^$/) {
+ # Empty line; just skip at this point.
+ } elsif (/^[MTWFS]/) {
+ # Looks like the name of a day; assume opener and move to
+ # "in entry" state.
+ $lastkey = $_;
+ $conf = 2;
+ print STDERR "found $_" if $tjd;
+ } else {
+ die ("conflict crosses entry boundaries: $_");
+ }
+ } elsif ($conf == 2) {
+ # In entry. Copy into variable until we see beginner line.
+ if (/^[MTWFS]/) {
+ # Entry beginner line.
+
+ # Copy last key into array.
+ if ($lastkey ne '') {
+ $conflist{$lastkey} = $lastval;
+
+ $lastkey = '';
+ $lastval = '';
+ }
+
+ $lastkey = $_;
+ print STDERR "found $_" if $tjd;
+ $lastval = '';
+ } else {
+ $lastval .= $_;
+ }
+ } else {
+ # Just copy.
+ print;
+ }
+}
+
+# Compare ChangeLog time strings like <=>.
+#
+# 0 1 2 3
+# Thu Aug 11 13:22:42 1994 Tom Tromey (tromey@creche.colorado.edu)
+# 0123456789012345678901234567890
+#
+sub clcmp {
+ # First check year.
+ $r = substr ($a, 20, 4) <=> substr ($b, 20, 4);
+
+ # Now check month.
+ $r = $months{substr ($a, 4, 3)} <=> $months{substr ($b, 4, 3)} if !$r;
+
+ # Now check day.
+ $r = substr ($a, 8, 2) <=> substr ($b, 8, 2) if !$r;
+
+ # Now check time (3 parts).
+ $r = substr ($a, 11, 2) <=> substr ($b, 11, 2) if !$r;
+ $r = substr ($a, 14, 2) <=> substr ($b, 14, 2) if !$r;
+ $r = substr ($a, 17, 2) <=> substr ($b, 17, 2) if !$r;
+
+ $r;
+}
diff --git a/contrib/cln_hist.in b/contrib/cln_hist.in
new file mode 100755
index 0000000..ba03a27
--- /dev/null
+++ b/contrib/cln_hist.in
@@ -0,0 +1,103 @@
+#! @PERL@
+# -*-Perl-*-
+
+# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# Contributed by David G. Grubbs <dgg@ksr.com>
+#
+# Clean up the history file. 10 Record types: MAR OFT WUCG
+#
+# WUCG records are thrown out.
+# MAR records are retained.
+# T records: retain only last tag with same combined tag/module.
+#
+# Two passes: Walk through the first time and remember the
+# 1. Last Tag record with same "tag" and "module" names.
+# 2. Last O record with unique user/module/directory, unless followed
+# by a matching F record.
+#
+
+$r = $ENV{"CVSROOT"};
+$c = "$r/CVSROOT";
+$h = "$c/history";
+
+eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
+ while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
+exit 255 if $die; # process any variable=value switches
+
+%tags = ();
+%outs = ();
+
+#
+# Move history file to safe place and re-initialize a new one.
+#
+rename($h, "$h.bak");
+open(XX, ">$h");
+close(XX);
+
+#
+# Pass1 -- remember last tag and checkout.
+#
+open(HIST, "$h.bak");
+while (<HIST>) {
+ next if /^[MARWUCG]/;
+
+ # Save whole line keyed by tag|module
+ if (/^T/) {
+ @tmp = split(/\|/, $_);
+ $tags{$tmp[4] . '|' . $tmp[5]} = $_;
+ }
+ # Save whole line
+ if (/^[OF]/) {
+ @tmp = split(/\|/, $_);
+ $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} = $_;
+ }
+}
+
+#
+# Pass2 -- print out what we want to save.
+#
+open(SAVE, ">$h.work");
+open(HIST, "$h.bak");
+while (<HIST>) {
+ next if /^[FWUCG]/;
+
+ # If whole line matches saved (i.e. "last") one, print it.
+ if (/^T/) {
+ @tmp = split(/\|/, $_);
+ next if $tags{$tmp[4] . '|' . $tmp[5]} ne $_;
+ }
+ # Save whole line
+ if (/^O/) {
+ @tmp = split(/\|/, $_);
+ next if $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} ne $_;
+ }
+
+ print SAVE $_;
+}
+
+#
+# Put back the saved stuff
+#
+system "cat $h >> $h.work";
+
+if (-s $h) {
+ rename ($h, "$h.interim");
+ print "history.interim has non-zero size.\n";
+} else {
+ unlink($h);
+}
+
+rename ("$h.work", $h);
+
+exit(0);
diff --git a/contrib/commit_prep.in b/contrib/commit_prep.in
new file mode 100755
index 0000000..c795533
--- /dev/null
+++ b/contrib/commit_prep.in
@@ -0,0 +1,86 @@
+#! @PERL@ -T
+# -*-Perl-*-
+
+# Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+###############################################################################
+###############################################################################
+###############################################################################
+#
+# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE
+# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE
+# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
+# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
+# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
+# <@PACKAGE_BUGREPORT@> MAILING LIST.
+#
+# For more on general Perl security and taint-checking, please try running the
+# `perldoc perlsec' command.
+#
+###############################################################################
+###############################################################################
+###############################################################################
+
+# Perl filter to handle pre-commit checking of files. This program
+# records the last directory where commits will be taking place for
+# use by the log_accum.pl script.
+#
+# IMPORTANT: this script interacts with log_accum, they have to agree
+# on the tmpfile name to use. See $LAST_FILE below.
+#
+# Contributed by David Hampton <hampton@cisco.com>
+# Stripped to minimum by Roy Fielding
+#
+############################################################
+$TMPDIR = $ENV{'TMPDIR'} || '/tmp';
+$FILE_PREFIX = '#cvs.';
+
+# If see a "-u $USER" argument, then destructively remove it from the
+# argument list, so $ARGV[0] will be the repository dir again, as it
+# used to be before we added the -u flag.
+if ($ARGV[0] eq '-u') {
+ shift @ARGV;
+ $CVS_USERNAME = shift (@ARGV);
+}
+
+# This needs to match the corresponding var in log_accum.pl, including
+# the appending of the pgrp and username suffixes (see uses of this
+# var farther down).
+$LAST_FILE = "$TMPDIR/${FILE_PREFIX}lastdir";
+
+sub write_line {
+ my ($filename, $line) = @_;
+
+# A check of some kind is needed here, but the rules aren't apparent
+# at the moment:
+
+# foreach($filename, $line){
+# $_ =~ m#^([-\@\w.\#]+)$#;
+# $_ = $1;
+# }
+
+ open(FILE, ">$filename") || die("Cannot open $filename: $!\n");
+ print(FILE $line, "\n");
+ close(FILE);
+}
+
+#
+# Record this directory as the last one checked. This will be used
+# by the log_accumulate script to determine when it is processing
+# the final directory of a multi-directory commit.
+#
+$id = getpgrp();
+
+&write_line("$LAST_FILE.$id.$CVS_USERNAME", $ARGV[0]);
+
+exit(0);
diff --git a/contrib/cvs2vendor.sh b/contrib/cvs2vendor.sh
new file mode 100644
index 0000000..166544d
--- /dev/null
+++ b/contrib/cvs2vendor.sh
@@ -0,0 +1,159 @@
+#! /bin/sh
+#
+# Copyright (C) 1997-2005 The Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# cvs2vendor - move revsisions from files in A to files in B
+#
+# The primary reason for this script is to move deltas from a
+# non-vendor branched repository onto a fresh vendor branched one,
+# skipping the initial checkin in assumption that it is the same in
+# both repositories. This way you can take a project that was moved
+# into CVS without the benefit of the vendor branch and for all
+# intents and purposes add the vendor branch underneath the existing
+# deltas.
+#
+# This script is also a decent example of repository maintenance using
+# raw RCS commands (if I do say so myself! ;-).
+#
+# Tags are preserved.
+#
+# The timestamp of the initial vendor branch revision will be adjusted
+# to be the same as the 1.1 revision of each source file.
+#
+# Extra branches in the source directory will cause breakage.
+#
+# Intermediate files are created in the current working directory
+# where this script is started.
+#
+# Written by Greg A. Woods <woods@planix.com>, based on rcs2sccs
+# (retains some of the rlog parsing from it).
+#
+# The copyright is in the Public Domain.
+#
+
+if [ $# -ne 2 ]; then
+ echo USAGE: $0 srcdir dstdir
+ exit 2
+fi
+tsrcdir=$1
+tdstdir=$2
+
+revfile=/tmp/cvs2vendor_$$_rev
+rm -f $revfile
+
+commentfile=/tmp/cvs2vendor_$$_comment
+rm -f $commentfile
+
+if sort -k 1,1 /dev/null 2>/dev/null
+then sort_each_field='-k 1 -k 2 -k 3 -k 4 -k 5 -k 6 -k 7 -k 8 -k 9'
+else sort_each_field='+0 +1 +2 +3 +4 +5 +6 +7 +8'
+fi
+
+srcdirs=`cd $tsrcdir && find . -type d -print | sed 's~^\.[/]*~~'`
+
+# the "" is a trick to get $tsrcdir itself without resorting to '.'
+for ldir in "" $srcdirs; do
+
+ srcdir=$tsrcdir/$ldir
+ dstdir=$tdstdir/$ldir
+
+ # Loop over every RCS file in srcdir
+ #
+ for vfile in $srcdir/*,v; do
+ # get rid of the ",v" at the end of the name
+ file=`echo $vfile | sed -e 's/,v$//'`
+ bfile=`basename $file`
+
+ if [ ! -d $dstdir ]; then
+ echo "making locally added directory $dstdir"
+ mkdir -p $dstdir
+ fi
+ if [ ! -f $dstdir/$bfile,v ]; then
+ echo "copying locally added file $dstdir/$bfile ..."
+ cp $vfile $dstdir
+ continue;
+ fi
+
+ # work on each rev of that file in ascending order
+ rlog $file | grep "^revision [0-9][0-9]*\." | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u $sort_each_field | sed -e 's/ /./g' > $revfile
+
+ for rev in `cat $revfile`; do
+
+ case "$rev" in
+ 1.1)
+ newdate=`rlog -r$rev $file | grep "^date: " | awk '{printf("%s.%s\n",$2,$3); exit}' | sed -e 's~/~.~g' -e 's/:/./g' -e 's/;//' -e 's/^19//'`
+ olddate=`rlog -r1.1.1.1 $dstdir/$bfile | grep "^date: " | awk '{printf("%s.%s\n",$2,$3); exit}' | sed -e 's~/~.~g' -e 's/:/./g' -e 's/;//' -e 's/^19//'`
+ sed "s/$olddate/$newdate/" < $dstdir/$bfile,v > $dstdir/$bfile.x
+ mv -f $dstdir/$bfile.x $dstdir/$bfile,v
+ chmod -w $dstdir/$bfile,v
+ symname=`rlog -h $file | sed -e '1,/^symbolic names:/d' -e 's/[ ]*//g' | awk -F: '$2 == "'"$rev"'" {printf("-n%s:1.1.1.1\n",$1)}'`
+ if [ -n "$symname" ]; then
+ echo "tagging $file with $symname ..."
+ rcs $symname $dstdir/$bfile,v
+ if [ $? != 0 ]; then
+ echo ERROR - rcs $symname $dstdir/$bfile,v
+ exit 1
+ fi
+ fi
+ continue # skip first rev....
+ ;;
+ esac
+
+ # get a lock on the destination local branch tip revision
+ co -r1 -l $dstdir/$bfile
+ if [ $? != 0 ]; then
+ echo ERROR - co -r1 -l $dstdir/$bfile
+ exit 1
+ fi
+ rm -f $dstdir/$bfile
+
+ # get file into current dir and get stats
+ date=`rlog -r$rev $file | grep "^date: " | awk '{printf("%s %s\n",$2,$3); exit}' | sed -e 's/;//'`
+ author=`rlog -r$rev $file | grep "^date: " | awk '{print $5; exit}' | sed -e 's/;//'`
+
+ symname=`rlog -h $file | sed -e '1,/^symbolic names:/d' -e 's/[ ]*//g' | awk -F: '$2 == "'"$rev"'" {printf("-n%s\n",$1)}'`
+
+ rlog -r$rev $file | sed -e '/^branches: /d' -e '1,/^date: /d' -e '/^===========/d' | awk '{if ((total += length($0) + 1) < 510) print $0}' > $commentfile
+
+ echo "==> file $file, rev=$rev, date=$date, author=$author $symname"
+
+ co -p -r$rev $file > $bfile
+ if [ $? != 0 ]; then
+ echo ERROR - co -p -r$rev $file
+ exit 1
+ fi
+
+ # check file into vendor repository...
+ ci -f -m"`cat $commentfile`" -d"$date" $symname -w"$author" $bfile $dstdir/$bfile,v
+ if [ $? != 0 ]; then
+ echo ERROR - ci -f -m"`cat $commentfile`" -d"$date" $symname -w"$author" $bfile $dstdir/$bfile,v
+ exit 1
+ fi
+ rm -f $bfile
+
+ # set the default branch to the trunk...
+ # XXX really only need to do this once....
+ rcs -b1 $dstdir/$bfile
+ if [ $? != 0 ]; then
+ echo ERROR - rcs -b1 $dstdir/$bfile
+ exit 1
+ fi
+ done
+ done
+done
+
+echo cleaning up...
+rm -f $commentfile
+echo " Conversion Completed Successfully"
+
+exit 0
diff --git a/contrib/cvs_acls.html b/contrib/cvs_acls.html
new file mode 100644
index 0000000..6ae76b6
--- /dev/null
+++ b/contrib/cvs_acls.html
@@ -0,0 +1,459 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>cvs_acls</title>
+<link rev="made" href="mailto:root@localhost" />
+</head>
+
+<body style="background-color: white">
+
+<p><a name="__index__"></a></p>
+<!-- INDEX BEGIN -->
+
+<ul>
+
+ <li><a href="#name">Name</a></li>
+ <li><a href="#synopsis">Synopsis</a></li>
+ <li><a href="#licensing">Licensing</a></li>
+ <li><a href="#description">Description</a></li>
+ <li><a href="#enhancements">Enhancements</a></li>
+ <ul>
+
+ <li><a href="#fixed_bugs">Fixed Bugs</a></li>
+ <li><a href="#enhancements">Enhancements</a></li>
+ <li><a href="#todos">ToDoS</a></li>
+ </ul>
+
+ <li><a href="#version_information">Version Information</a></li>
+ <li><a href="#installation">Installation</a></li>
+ <li><a href="#format_of_the_cvsacl_file">Format of the cvsacl file</a></li>
+ <li><a href="#program_logic">Program Logic</a></li>
+ <ul>
+
+ <li><a href="#pseudocode">Pseudocode</a></li>
+ <li><a href="#sanity_check">Sanity Check</a></li>
+ </ul>
+
+</ul>
+<!-- INDEX END -->
+
+<hr />
+<p>
+</p>
+<h1><a name="name">Name</a></h1>
+<p>cvs_acls - Access Control List for CVS</p>
+<p>
+</p>
+<hr />
+<h1><a name="synopsis">Synopsis</a></h1>
+<p>In 'commitinfo':</p>
+<pre>
+ repository/path/to/restrict $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER][-f &lt;logfile&gt;]</pre>
+<p>where:</p>
+<pre>
+ -d turns on debug information
+ -u passes the client-side userId to the cvs_acls script
+ -f specifies an alternate filename for the restrict_log file</pre>
+<p>In 'cvsacl':</p>
+<pre>
+ {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]</pre>
+<p>where:</p>
+<pre>
+ allow|deny - allow: commits are allowed; deny: prohibited
+ user - userId to be allowed or restricted
+ repos - file or directory to be allowed or restricted
+ branch - branch to be allowed or restricted</pre>
+<p>See below for examples.</p>
+<p>
+</p>
+<hr />
+<h1><a name="licensing">Licensing</a></h1>
+<p>cvs_acls - provides access control list functionality for CVS
+</p>
+<pre>
+
+Copyright (c) 2004 by Peter Connolly &lt;peter.connolly@cnet.com&gt;
+All rights reserved.</pre>
+<p>This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.</p>
+<p>This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.</p>
+<p>You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>
+<p>
+</p>
+<hr />
+<h1><a name="description">Description</a></h1>
+<p>This script--cvs_acls--is invoked once for each directory within a
+``cvs commit''. The set of files being committed for that directory as
+well as the directory itself, are passed to this script. This script
+checks its 'cvsacl' file to see if any of the files being committed
+are on the 'cvsacl' file's restricted list. If any of the files are
+restricted, then the cvs_acls script passes back an exit code of 1
+which disallows the commits for that directory.</p>
+<p>Messages are returned to the committer indicating the <a href="#item_file"><code>file(s)</code></a> that
+he/she are not allowed to committ. Additionally, a site-specific
+set of messages (e.g., contact information) can be included in these
+messages.</p>
+<p>When a commit is prohibited, log messages are written to a restrict_log
+file in $CVSROOT/CVSROOT. This default file can be redirected to
+another destination.</p>
+<p>The script is triggered from the 'commitinfo' file in $CVSROOT/CVSROOT/.</p>
+<p>
+</p>
+<hr />
+<h1><a name="enhancements">Enhancements</a></h1>
+<p>This section lists the bug fixes and enhancements added to cvs_acls
+that make up the current cvs_acls.</p>
+<p>
+</p>
+<h2><a name="fixed_bugs">Fixed Bugs</a></h2>
+<p>This version attempts to get rid the following bugs from the
+original version of cvs_acls:</p>
+<ul>
+<li><strong><a name="item_files">Multiple entries on an 'cvsacl' line will be matched individually,
+instead of requiring that all commit files *exactly* match all
+'cvsacl' entries. Commiting a file not in the 'cvsacl' list would
+allow *all* files (including a restricted file) to be committed.</a></strong><br />
+</li>
+[IMO, this basically made the original script unuseable for our
+situation since any arbitrary combination of committed files could
+avoid matching the 'cvsacl's entries.]
+<p></p>
+<li><strong><a name="item_handle_specific_filename_restrictions_2e_cvs_acls_">Handle specific filename restrictions. cvs_acls didn't restrict
+individual files specified in 'cvsacl'.</a></strong><br />
+</li>
+<li><strong><a name="item_correctly_handle_multiple_2c_specific_filename_res">Correctly handle multiple, specific filename restrictions</a></strong><br />
+</li>
+<li><strong><a name="item_prohibit_mix_of_dirs_and_files_on_a_single__27cvsa">Prohibit mix of dirs and files on a single 'cvsacl' line
+[To simplify the logic and because this would be normal usage.]</a></strong><br />
+</li>
+<li><strong><a name="item_correctly_handle_a_mixture_of_branch_restrictions_">Correctly handle a mixture of branch restrictions within one work
+directory</a></strong><br />
+</li>
+<li><strong><a name="item__24cvsroot_existence_is_checked_too_late">$CVSROOT existence is checked too late</a></strong><br />
+</li>
+<li><strong><a name="item_option">Correctly handle the CVSROOT=:local:/... option (useful for
+interactive testing)</a></strong><br />
+</li>
+<li><strong><a name="item_logic">Replacing shoddy ``$universal_off'' logic
+(Thanks to Karl-Konig Konigsson for pointing this out.)</a></strong><br />
+</li>
+</ul>
+<p>
+</p>
+<h2><a name="enhancements">Enhancements</a></h2>
+<ul>
+<li><strong><a name="item_checks_modules_in_the__27cvsacl_27_file_for_valid_">Checks modules in the 'cvsacl' file for valid files and directories</a></strong><br />
+</li>
+<li><strong><a name="item_accurately_report_restricted_entries_and_their_mat">Accurately report restricted entries and their matching patterns</a></strong><br />
+</li>
+<li><strong><a name="item_simplified_and_commented_overly_complex_perl_regex">Simplified and commented overly complex PERL REGEXPs for readability
+and maintainability</a></strong><br />
+</li>
+<li><strong><a name="item_skip_the_rest_of_processing_if_a_mismatch_on_porti">Skip the rest of processing if a mismatch on portion of the 'cvsacl' line</a></strong><br />
+</li>
+<li><strong><a name="item_file">Get rid of opaque ``karma'' messages in favor of user-friendly messages
+that describe which user, <code>file(s)</code> and <code>branch(es)</code> were disallowed.</a></strong><br />
+</li>
+<li><strong><a name="item_add_optional__27restrict_msg_27_file_for_additiona">Add optional 'restrict_msg' file for additional, site-specific
+restriction messages.</a></strong><br />
+</li>
+<li><strong><a name="item_userid">Take a ``-u'' parameter for $USER from commit_prep so that the script
+can do restrictions based on the client-side userId rather than the
+server-side userId (usually 'cvs').</a></strong><br />
+</li>
+(See discussion below on ``Admin Setup'' for more on this point.)
+<p></p>
+<li><strong><a name="item_added_a_lot_more_debug_trace">Added a lot more debug trace</a></strong><br />
+</li>
+<li><strong><a name="item_tested_these_restrictions_with_concurrent_use_of_p">Tested these restrictions with concurrent use of pserver and SSH
+access to model our transition from pserver to ext access.</a></strong><br />
+</li>
+<li><strong><a name="item_added_logging_of_restricted_commit_attempts_2e_res">Added logging of restricted commit attempts.
+Restricted commits can be sent to a default file:
+$CVSROOT/CVSROOT/restrictlog or to one passed to the script
+via the -f command parameter.</a></strong><br />
+</li>
+</ul>
+<p>
+</p>
+<h2><a name="todos">ToDoS</a></h2>
+<ul>
+<li><strong><a name="item_need_to_deal_with_pserver_2fssh_transition_with_co">Need to deal with pserver/SSH transition with conflicting umasks?</a></strong><br />
+</li>
+<li><strong><a name="item_use_a_cpan_module_to_handle_command_parameters_2e">Use a CPAN module to handle command parameters.</a></strong><br />
+</li>
+<li><strong><a name="item_use_a_cpan_module_to_clone_data_structures_2e">Use a CPAN module to clone data structures.</a></strong><br />
+</li>
+</ul>
+<p>
+</p>
+<hr />
+<h1><a name="version_information">Version Information</a></h1>
+<p>This is not offered as a fix to the original 'cvs_acls' script since it
+differs substantially in goals and methods from the original and there
+are probably a significant number of people out there that still require
+the original version's functionality.</p>
+<p>The 'cvsacl' file flags of 'allow' and 'deny' were intentionally
+changed to 'allow' and 'deny' because there are enough differences
+between the original script's behavior and this one's that we wanted to
+make sure that users will rethink their 'cvsacl' file formats before
+plugging in this newer script.</p>
+<p>Please note that there has been very limited cross-platform testing of
+this script!!! (We did not have the time or resources to do exhaustive
+cross-platform testing.)</p>
+<p>It was developed and tested under Red Hat Linux 9.0 using PERL 5.8.0.
+Additionally, it was built and tested under Red Hat Linux 7.3 using
+PERL 5.6.1.</p>
+<p>$Id: cvs_acls.html,v 1.2 2005/07/20 10:38:40 dprice Exp $</p>
+<p>This version is based on the 1.11.13 version of cvs_acls
+<a href="mailto:peter.connolly@cnet.com">peter.connolly@cnet.com</a> (Peter Connolly)</p>
+<pre>
+ Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
+ Branch specific controls added by voisine@bytemobile.com (Aaron Voisine)</pre>
+<p>
+</p>
+<hr />
+<h1><a name="installation">Installation</a></h1>
+<p>To use this program, do the following four things:</p>
+<p>0. Install PERL, version 5.6.1 or 5.8.0.</p>
+<p>1. Admin Setup:</p>
+<pre>
+ There are two choices here.</pre>
+<pre>
+ a) The first option is to use the $ENV{&quot;USER&quot;}, server-side userId
+ (from the third column of your pserver 'passwd' file) as the basis for
+ your restrictions. In this case, you will (at a minimum) want to set
+ up a new &quot;cvsadmin&quot; userId and group on the pserver machine.
+ CVS administrators will then set up their 'passwd' file entries to
+ run either as &quot;cvs&quot; (for regular users) or as &quot;cvsadmin&quot; (for power
+ users). Correspondingly, your 'cvsacl' file will only list 'cvs'
+ and 'cvsadmin' as the userIds in the second column.</pre>
+<pre>
+ Commentary: A potential weakness of this is that the xinetd
+ cvspserver process will need to run as 'root' in order to switch
+ between the 'cvs' and the 'cvsadmin' userIds. Some sysadmins don't
+ like situations like this and may want to chroot the process.
+ Talk to them about this point...</pre>
+<pre>
+ b) The second option is to use the client-side userId as the basis for
+ your restrictions. In this case, all the xinetd cvspserver processes
+ can run as userId 'cvs' and no 'root' userId is required. If you have
+ a 'passwd' file that lists 'cvs' as the effective run-time userId for
+ all your users, then no changes to this file are needed. Your 'cvsacl'
+ file will use the individual, client-side userIds in its 2nd column.</pre>
+<pre>
+ As long as the userIds in pserver's 'passwd' file match those userIds
+ that your Linux server know about, this approach is ideal if you are
+ planning to move from pserver to SSH access at some later point in time.
+ Just by switching the CVSROOT var from CVSROOT=:pserver:&lt;userId&gt;... to
+ CVSROOT=:ext:&lt;userId&gt;..., users can switch over to SSH access without
+ any other administrative changes. When all users have switched over to
+ SSH, the inherently insecure xinetd cvspserver process can be disabled.
+ [<a href="http://ximbiot.com/cvs/manual/cvs-1.11.17/cvs_2.html#SEC32">http://ximbiot.com/cvs/manual/cvs-1.11.17/cvs_2.html#SEC32</a>]</pre>
+<pre>
+ :TODO: The only potential glitch with the SSH approach is the possibility
+ that each user can have differing umasks that might interfere with one
+ another, especially during a transition from pserver to SSH. As noted
+ in the ToDo section, this needs a good strategy and set of tests for that
+ yet...</pre>
+<p>2. Put two lines, as the *only* non-comment lines, in your commitinfo file:</p>
+<pre>
+ ALL $CVSROOT/CVSROOT/commit_prep
+ ALL $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER ][-f &lt;logfilename&gt;]</pre>
+<pre>
+ where &quot;-d&quot; turns on debug trace
+ &quot;-u $USER&quot; passes the client-side userId to cvs_acls
+ &quot;-f &lt;logfilename&quot;&gt; overrides the default filename used to log
+ restricted commit attempts.</pre>
+<pre>
+ (These are handled in the processArgs() subroutine.)</pre>
+<p>If you are using client-side userIds to restrict access to your
+repository, make sure that they are in this order since the commit_prep
+script is required in order to pass the $USER parameter.</p>
+<p>A final note about the repository matching pattern. The example above
+uses ``ALL'' but note that this means that the cvs_acls script will run
+for each and every commit in your repository. Obviously, in a large
+repository this adds up to a lot of overhead that may not be necesary.
+A better strategy is to use a repository pattern that is more specific
+to the areas that you wish to secure.</p>
+<p>3. Install this file as $CVSROOT/CVSROOT/cvs_acls and make it executable.</p>
+<p>4. Create a file named CVSROOT/cvsacl and optionally add it to
+ CVSROOT/checkoutlist and check it in. See the CVS manual's
+ administrative files section about checkoutlist. Typically:</p>
+<pre>
+ $ cvs checkout CVSROOT
+ $ cd CVSROOT
+ [ create the cvsacl file, include 'commitinfo' line ]
+ [ add cvsacl to checkoutlist ]
+ $ cvs add cvsacl
+ $ cvs commit -m 'Added cvsacl for use with cvs_acls.' cvsacl checkoutlist</pre>
+<p>Note: The format of the 'cvsacl' file is described in detail immediately
+below but here is an important set up point:</p>
+<pre>
+ Make sure to include a line like the following:</pre>
+<pre>
+ deny||CVSROOT/commitinfo CVSROOT/cvsacl
+ allow|cvsadmin|CVSROOT/commitinfo CVSROOT/cvsacl</pre>
+<pre>
+ that restricts access to commitinfo and cvsacl since this would be one of
+ the easiest &quot;end runs&quot; around this ACL approach. ('commitinfo' has the
+ line that executes the cvs_acls script and, of course, all the
+ restrictions are in 'cvsacl'.)</pre>
+<p>5. (Optional) Create a 'restrict_msg' file in the $CVSROOT/CVSROOT directory.
+ Whenever there is a restricted file or dir message, cvs_acls will look
+ for this file and, if it exists, print its contents as part of the
+ commit-denial message. This gives you a chance to print any site-specific
+ information (e.g., who to call, what procedures to look up,...) whenever
+ a commit is denied.</p>
+<p>
+</p>
+<hr />
+<h1><a name="format_of_the_cvsacl_file">Format of the cvsacl file</a></h1>
+<p>The 'cvsacl' file determines whether you may commit files. It contains lines
+read from top to bottom, keeping track of whether a given user, repository
+and branch combination is ``allowed'' or ``denied.'' The script will assume
+``allowed'' on all repository paths until 'allow' and 'deny' rules change
+that default.</p>
+<p>The normal pattern is to specify an 'deny' rule to turn off
+access to ALL users, then follow it with a matching 'allow' rule that will
+turn on access for a select set of users. In the case of multiple rules for
+the same user, repository and branch, the last one takes precedence.</p>
+<p>Blank lines and lines with only comments are ignored. Any other lines not
+beginning with ``allow'' or ``deny'' are logged to the restrict_log file.</p>
+<p>Lines beginning with ``allow'' or ``deny'' are assumed to be '|'-separated
+triples: (All spaces and tabs are ignored in a line.)</p>
+<pre>
+ {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]</pre>
+<pre>
+ 1. String starting with &quot;allow&quot; or &quot;deny&quot;.
+ 2. Optional, comma-separated list of usernames.
+ 3. Optional, comma-separated list of repository pathnames.
+ These are pathnames relative to $CVSROOT. They can be directories or
+ filenames. A directory name allows or restricts access to all files and
+ directories below it. One line can have either directories or filenames
+ but not both.
+ 4. Optional, comma-separated list of branch tags.
+ If not specified, all branches are assumed. Use HEAD to reference the
+ main branch.</pre>
+<p>Example: (Note: No in-line comments.)</p>
+<pre>
+ # ----- Make whole repository unavailable.
+ deny</pre>
+<pre>
+ # ----- Except for user &quot;dgg&quot;.
+ allow|dgg</pre>
+<pre>
+ # ----- Except when &quot;fred&quot; or &quot;john&quot; commit to the
+ # module whose repository is &quot;bin/ls&quot;
+ allow|fred, john|bin/ls</pre>
+<pre>
+ # ----- Except when &quot;ed&quot; commits to the &quot;stable&quot;
+ # branch of the &quot;bin/ls&quot; repository
+ allow|ed|/bin/ls|stable</pre>
+<p>
+</p>
+<hr />
+<h1><a name="program_logic">Program Logic</a></h1>
+<p>CVS passes to @ARGV an absolute directory pathname (the repository
+appended to your $CVSROOT variable), followed by a list of filenames
+within that directory that are to be committed.</p>
+<p>The script walks through the 'cvsacl' file looking for matches on
+the username, repository and branch.</p>
+<p>A username match is simply the user's name appearing in the second
+column of the cvsacl line in a space-or-comma separate list. If
+blank, then any user will match.</p>
+<p>A repository match:</p>
+<ul>
+<li><strong><a name="item_each_entry_in_the_modules_section_of_the_current__">Each entry in the modules section of the current 'cvsacl' line is
+examined to see if it is a dir or a file. The line must have
+either files or dirs, but not both. (To simplify the logic.)</a></strong><br />
+</li>
+<li><strong><a name="item_if_neither_2c_then_assume_the__27cvsacl_27_file_wa">If neither, then assume the 'cvsacl' file was set up in error and
+skip that 'allow' line.</a></strong><br />
+</li>
+<li><strong><a name="item_if_a_dir_2c_then_each_dir_pattern_is_matched_separ">If a dir, then each dir pattern is matched separately against the
+beginning of each of the committed files in @ARGV.</a></strong><br />
+</li>
+<li><strong><a name="item_if_a_file_2c_then_each_file_pattern_is_matched_exa">If a file, then each file pattern is matched exactly against each
+of the files to be committed in @ARGV.</a></strong><br />
+</li>
+<li><strong><a name="item_repository_and_branch_must_both_match_together_2e_">Repository and branch must BOTH match together. This is to cover
+the use case where a user has multiple branches checked out in
+a single work directory. Commit files can be from different
+branches.</a></strong><br />
+</li>
+A branch match is either:
+<ul>
+<li><strong><a name="item_when_no_branches_are_listed_in_the_fourth_column_2">When no branches are listed in the fourth column. (``Match any.'')</a></strong><br />
+</li>
+<li><strong><a name="item_all_elements_from_the_fourth_column_are_matched_ag">All elements from the fourth column are matched against each of
+the tag names for $ARGV[1..$#ARGV] found in the %branches file.</a></strong><br />
+</li>
+</ul>
+<li><strong><a name="item__27allow_27_match_remove_that_match_from_the_tally">'allow' match remove that match from the tally map.</a></strong><br />
+</li>
+<li><strong><a name="item_restricted">Restricted ('deny') matches are saved in the %repository_matches
+table.</a></strong><br />
+</li>
+<li><strong><a name="item_if_there_is_a_match_on_user_2c_repository_and_bran">If there is a match on user, repository and branch:</a></strong><br />
+</li>
+<pre>
+ If repository, branch and user match
+ if 'deny'
+ add %repository_matches entries to %restricted_entries
+ else if 'allow'
+ remove %repository_matches entries from %restricted_entries</pre>
+<li><strong><a name="item_at_the_end_of_all_the__27cvsacl_27_line_checks_2c_">At the end of all the 'cvsacl' line checks, check to see if there
+are any entries in the %restricted_entries. If so, then deny the
+commit.</a></strong><br />
+</li>
+</ul>
+<p>
+</p>
+<h2><a name="pseudocode">Pseudocode</a></h2>
+<pre>
+ read CVS/Entries file and create branch{file}-&gt;{branch} hash table
+ + for each 'allow' and 'deny' line in the 'cvsacl' file:
+ | user match?
+ | - Yes: set $user_match = 1;
+ | repository and branch match?
+ | - Yes: add to %repository_matches;
+ | did user, repository match?
+ | - Yes: if 'deny' then
+ | add %repository_matches -&gt; %restricted_entries
+ | if 'allow' then
+ | remove %repository_matches &lt;- %restricted_entries
+ + end for loop
+ any saved restrictions?
+ no: exit,
+ set exit code allowing commits and exit
+ yes: report restrictions,
+ set exit code prohibiting commits and exit</pre>
+<p>
+</p>
+<h2><a name="sanity_check">Sanity Check</a></h2>
+<pre>
+ 1) file allow trumps a dir deny
+ deny||java/lib
+ allow||java/lib/README
+ 2) dir allow can undo a file deny
+ deny||java/lib/README
+ allow||java/lib
+ 3) file deny trumps a dir allow
+ allow||java/lib
+ deny||java/lib/README
+ 4) dir deny trumps a file allow
+ allow||java/lib/README
+ deny||java/lib
+ ... so last match always takes precedence</pre>
+
+</body>
+
+</html>
diff --git a/contrib/cvs_acls.in b/contrib/cvs_acls.in
new file mode 100755
index 0000000..e51337a
--- /dev/null
+++ b/contrib/cvs_acls.in
@@ -0,0 +1,963 @@
+#! @PERL@ -T
+# -*-Perl-*-
+
+# Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+###############################################################################
+###############################################################################
+###############################################################################
+#
+# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE
+# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE
+# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
+# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
+# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
+# <@PACKAGE_BUGREPORT@> MAILING LIST.
+#
+# For more on general Perl security and taint-checking, please try running the
+# `perldoc perlsec' command.
+#
+###############################################################################
+###############################################################################
+###############################################################################
+
+=head1 Name
+
+cvs_acls - Access Control List for CVS
+
+=head1 Synopsis
+
+In 'commitinfo':
+
+ repository/path/to/restrict $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER][-f <logfile>]
+
+where:
+
+ -d turns on debug information
+ -u passes the client-side userId to the cvs_acls script
+ -f specifies an alternate filename for the restrict_log file
+
+In 'cvsacl':
+
+ {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]
+
+where:
+
+ allow|deny - allow: commits are allowed; deny: prohibited
+ user - userId to be allowed or restricted
+ repos - file or directory to be allowed or restricted
+ branch - branch to be allowed or restricted
+
+See below for examples.
+
+=head1 Licensing
+
+cvs_acls - provides access control list functionality for CVS
+
+Copyright (c) 2004 by Peter Connolly <peter.connolly@cnet.com>
+All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+=head1 Description
+
+This script--cvs_acls--is invoked once for each directory within a
+"cvs commit". The set of files being committed for that directory as
+well as the directory itself, are passed to this script. This script
+checks its 'cvsacl' file to see if any of the files being committed
+are on the 'cvsacl' file's restricted list. If any of the files are
+restricted, then the cvs_acls script passes back an exit code of 1
+which disallows the commits for that directory.
+
+Messages are returned to the committer indicating the file(s) that
+he/she are not allowed to committ. Additionally, a site-specific
+set of messages (e.g., contact information) can be included in these
+messages.
+
+When a commit is prohibited, log messages are written to a restrict_log
+file in $CVSROOT/CVSROOT. This default file can be redirected to
+another destination.
+
+The script is triggered from the 'commitinfo' file in $CVSROOT/CVSROOT/.
+
+=head1 Enhancements
+
+This section lists the bug fixes and enhancements added to cvs_acls
+that make up the current cvs_acls.
+
+=head2 Fixed Bugs
+
+This version attempts to get rid the following bugs from the
+original version of cvs_acls:
+
+=over 2
+
+=item *
+Multiple entries on an 'cvsacl' line will be matched individually,
+instead of requiring that all commit files *exactly* match all
+'cvsacl' entries. Commiting a file not in the 'cvsacl' list would
+allow *all* files (including a restricted file) to be committed.
+
+[IMO, this basically made the original script unuseable for our
+situation since any arbitrary combination of committed files could
+avoid matching the 'cvsacl's entries.]
+
+=item *
+Handle specific filename restrictions. cvs_acls didn't restrict
+individual files specified in 'cvsacl'.
+
+=item *
+Correctly handle multiple, specific filename restrictions
+
+=item *
+Prohibit mix of dirs and files on a single 'cvsacl' line
+[To simplify the logic and because this would be normal usage.]
+
+=item *
+Correctly handle a mixture of branch restrictions within one work
+directory
+
+=item *
+$CVSROOT existence is checked too late
+
+=item *
+Correctly handle the CVSROOT=:local:/... option (useful for
+interactive testing)
+
+=item *
+Replacing shoddy "$universal_off" logic
+(Thanks to Karl-Konig Konigsson for pointing this out.)
+
+=back
+
+=head2 Enhancements
+
+=over 2
+
+=item *
+Checks modules in the 'cvsacl' file for valid files and directories
+
+=item *
+Accurately report restricted entries and their matching patterns
+
+=item *
+Simplified and commented overly complex PERL REGEXPs for readability
+and maintainability
+
+=item *
+Skip the rest of processing if a mismatch on portion of the 'cvsacl' line
+
+=item *
+Get rid of opaque "karma" messages in favor of user-friendly messages
+that describe which user, file(s) and branch(es) were disallowed.
+
+=item *
+Add optional 'restrict_msg' file for additional, site-specific
+restriction messages.
+
+=item *
+Take a "-u" parameter for $USER from commit_prep so that the script
+can do restrictions based on the client-side userId rather than the
+server-side userId (usually 'cvs').
+
+(See discussion below on "Admin Setup" for more on this point.)
+
+=item *
+Added a lot more debug trace
+
+=item *
+Tested these restrictions with concurrent use of pserver and SSH
+access to model our transition from pserver to ext access.
+
+=item *
+Added logging of restricted commit attempts.
+Restricted commits can be sent to a default file:
+$CVSROOT/CVSROOT/restrictlog or to one passed to the script
+via the -f command parameter.
+
+=back
+
+=head2 ToDoS
+
+=over 2
+
+=item *
+Need to deal with pserver/SSH transition with conflicting umasks?
+
+=item *
+Use a CPAN module to handle command parameters.
+
+=item *
+Use a CPAN module to clone data structures.
+
+=back
+
+=head1 Version Information
+
+This is not offered as a fix to the original 'cvs_acls' script since it
+differs substantially in goals and methods from the original and there
+are probably a significant number of people out there that still require
+the original version's functionality.
+
+The 'cvsacl' file flags of 'allow' and 'deny' were intentionally
+changed to 'allow' and 'deny' because there are enough differences
+between the original script's behavior and this one's that we wanted to
+make sure that users will rethink their 'cvsacl' file formats before
+plugging in this newer script.
+
+Please note that there has been very limited cross-platform testing of
+this script!!! (We did not have the time or resources to do exhaustive
+cross-platform testing.)
+
+It was developed and tested under Red Hat Linux 9.0 using PERL 5.8.0.
+Additionally, it was built and tested under Red Hat Linux 7.3 using
+PERL 5.6.1.
+
+$Id: cvs_acls.in,v 1.11 2005/09/01 13:48:57 dprice Exp $
+
+This version is based on the 1.11.13 version of cvs_acls
+peter.connolly@cnet.com (Peter Connolly)
+
+ Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
+ Branch specific controls added by voisine@bytemobile.com (Aaron Voisine)
+
+=head1 Installation
+
+To use this program, do the following four things:
+
+0. Install PERL, version 5.6.1 or 5.8.0.
+
+1. Admin Setup:
+
+ There are two choices here.
+
+ a) The first option is to use the $ENV{"USER"}, server-side userId
+ (from the third column of your pserver 'passwd' file) as the basis for
+ your restrictions. In this case, you will (at a minimum) want to set
+ up a new "cvsadmin" userId and group on the pserver machine.
+ CVS administrators will then set up their 'passwd' file entries to
+ run either as "cvs" (for regular users) or as "cvsadmin" (for power
+ users). Correspondingly, your 'cvsacl' file will only list 'cvs'
+ and 'cvsadmin' as the userIds in the second column.
+
+ Commentary: A potential weakness of this is that the xinetd
+ cvspserver process will need to run as 'root' in order to switch
+ between the 'cvs' and the 'cvsadmin' userIds. Some sysadmins don't
+ like situations like this and may want to chroot the process.
+ Talk to them about this point...
+
+ b) The second option is to use the client-side userId as the basis for
+ your restrictions. In this case, all the xinetd cvspserver processes
+ can run as userId 'cvs' and no 'root' userId is required. If you have
+ a 'passwd' file that lists 'cvs' as the effective run-time userId for
+ all your users, then no changes to this file are needed. Your 'cvsacl'
+ file will use the individual, client-side userIds in its 2nd column.
+
+ As long as the userIds in pserver's 'passwd' file match those userIds
+ that your Linux server know about, this approach is ideal if you are
+ planning to move from pserver to SSH access at some later point in time.
+ Just by switching the CVSROOT var from CVSROOT=:pserver:<userId>... to
+ CVSROOT=:ext:<userId>..., users can switch over to SSH access without
+ any other administrative changes. When all users have switched over to
+ SSH, the inherently insecure xinetd cvspserver process can be disabled.
+ [http://ximbiot.com/cvs/manual/cvs-1.11.17/cvs_2.html#SEC32]
+
+ :TODO: The only potential glitch with the SSH approach is the possibility
+ that each user can have differing umasks that might interfere with one
+ another, especially during a transition from pserver to SSH. As noted
+ in the ToDo section, this needs a good strategy and set of tests for that
+ yet...
+
+2. Put two lines, as the *only* non-comment lines, in your commitinfo file:
+
+ ALL $CVSROOT/CVSROOT/commit_prep
+ ALL $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER ][-f <logfilename>]
+
+ where "-d" turns on debug trace
+ "-u $USER" passes the client-side userId to cvs_acls
+ "-f <logfilename"> overrides the default filename used to log
+ restricted commit attempts.
+
+ (These are handled in the processArgs() subroutine.)
+
+If you are using client-side userIds to restrict access to your
+repository, make sure that they are in this order since the commit_prep
+script is required in order to pass the $USER parameter.
+
+A final note about the repository matching pattern. The example above
+uses "ALL" but note that this means that the cvs_acls script will run
+for each and every commit in your repository. Obviously, in a large
+repository this adds up to a lot of overhead that may not be necesary.
+A better strategy is to use a repository pattern that is more specific
+to the areas that you wish to secure.
+
+3. Install this file as $CVSROOT/CVSROOT/cvs_acls and make it executable.
+
+4. Create a file named CVSROOT/cvsacl and optionally add it to
+ CVSROOT/checkoutlist and check it in. See the CVS manual's
+ administrative files section about checkoutlist. Typically:
+
+ $ cvs checkout CVSROOT
+ $ cd CVSROOT
+ [ create the cvsacl file, include 'commitinfo' line ]
+ [ add cvsacl to checkoutlist ]
+ $ cvs add cvsacl
+ $ cvs commit -m 'Added cvsacl for use with cvs_acls.' cvsacl checkoutlist
+
+Note: The format of the 'cvsacl' file is described in detail immediately
+below but here is an important set up point:
+
+ Make sure to include a line like the following:
+
+ deny||CVSROOT/commitinfo CVSROOT/cvsacl
+ allow|cvsadmin|CVSROOT/commitinfo CVSROOT/cvsacl
+
+ that restricts access to commitinfo and cvsacl since this would be one of
+ the easiest "end runs" around this ACL approach. ('commitinfo' has the
+ line that executes the cvs_acls script and, of course, all the
+ restrictions are in 'cvsacl'.)
+
+5. (Optional) Create a 'restrict_msg' file in the $CVSROOT/CVSROOT directory.
+ Whenever there is a restricted file or dir message, cvs_acls will look
+ for this file and, if it exists, print its contents as part of the
+ commit-denial message. This gives you a chance to print any site-specific
+ information (e.g., who to call, what procedures to look up,...) whenever
+ a commit is denied.
+
+=head1 Format of the cvsacl file
+
+The 'cvsacl' file determines whether you may commit files. It contains lines
+read from top to bottom, keeping track of whether a given user, repository
+and branch combination is "allowed" or "denied." The script will assume
+"allowed" on all repository paths until 'allow' and 'deny' rules change
+that default.
+
+The normal pattern is to specify an 'deny' rule to turn off
+access to ALL users, then follow it with a matching 'allow' rule that will
+turn on access for a select set of users. In the case of multiple rules for
+the same user, repository and branch, the last one takes precedence.
+
+Blank lines and lines with only comments are ignored. Any other lines not
+beginning with "allow" or "deny" are logged to the restrict_log file.
+
+Lines beginning with "allow" or "deny" are assumed to be '|'-separated
+triples: (All spaces and tabs are ignored in a line.)
+
+ {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]
+
+ 1. String starting with "allow" or "deny".
+ 2. Optional, comma-separated list of usernames.
+ 3. Optional, comma-separated list of repository pathnames.
+ These are pathnames relative to $CVSROOT. They can be directories or
+ filenames. A directory name allows or restricts access to all files and
+ directories below it. One line can have either directories or filenames
+ but not both.
+ 4. Optional, comma-separated list of branch tags.
+ If not specified, all branches are assumed. Use HEAD to reference the
+ main branch.
+
+Example: (Note: No in-line comments.)
+
+ # ----- Make whole repository unavailable.
+ deny
+
+ # ----- Except for user "dgg".
+ allow|dgg
+
+ # ----- Except when "fred" or "john" commit to the
+ # module whose repository is "bin/ls"
+ allow|fred, john|bin/ls
+
+ # ----- Except when "ed" commits to the "stable"
+ # branch of the "bin/ls" repository
+ allow|ed|/bin/ls|stable
+
+=head1 Program Logic
+
+CVS passes to @ARGV an absolute directory pathname (the repository
+appended to your $CVSROOT variable), followed by a list of filenames
+within that directory that are to be committed.
+
+The script walks through the 'cvsacl' file looking for matches on
+the username, repository and branch.
+
+A username match is simply the user's name appearing in the second
+column of the cvsacl line in a space-or-comma separate list. If
+blank, then any user will match.
+
+A repository match:
+
+=over 2
+
+=item *
+Each entry in the modules section of the current 'cvsacl' line is
+examined to see if it is a dir or a file. The line must have
+either files or dirs, but not both. (To simplify the logic.)
+
+=item *
+If neither, then assume the 'cvsacl' file was set up in error and
+skip that 'allow' line.
+
+=item *
+If a dir, then each dir pattern is matched separately against the
+beginning of each of the committed files in @ARGV.
+
+=item *
+If a file, then each file pattern is matched exactly against each
+of the files to be committed in @ARGV.
+
+=item *
+Repository and branch must BOTH match together. This is to cover
+the use case where a user has multiple branches checked out in
+a single work directory. Commit files can be from different
+branches.
+
+A branch match is either:
+
+=over 4
+
+=item *
+When no branches are listed in the fourth column. ("Match any.")
+
+=item *
+All elements from the fourth column are matched against each of
+the tag names for $ARGV[1..$#ARGV] found in the %branches file.
+
+=back
+
+=item *
+'allow' match remove that match from the tally map.
+
+=item *
+Restricted ('deny') matches are saved in the %repository_matches
+table.
+
+=item *
+If there is a match on user, repository and branch:
+
+ If repository, branch and user match
+ if 'deny'
+ add %repository_matches entries to %restricted_entries
+ else if 'allow'
+ remove %repository_matches entries from %restricted_entries
+
+=item *
+At the end of all the 'cvsacl' line checks, check to see if there
+are any entries in the %restricted_entries. If so, then deny the
+commit.
+
+=back
+
+=head2 Pseudocode
+
+ read CVS/Entries file and create branch{file}->{branch} hash table
+ + for each 'allow' and 'deny' line in the 'cvsacl' file:
+ | user match?
+ | - Yes: set $user_match = 1;
+ | repository and branch match?
+ | - Yes: add to %repository_matches;
+ | did user, repository match?
+ | - Yes: if 'deny' then
+ | add %repository_matches -> %restricted_entries
+ | if 'allow' then
+ | remove %repository_matches <- %restricted_entries
+ + end for loop
+ any saved restrictions?
+ no: exit,
+ set exit code allowing commits and exit
+ yes: report restrictions,
+ set exit code prohibiting commits and exit
+
+=head2 Sanity Check
+
+ 1) file allow trumps a dir deny
+ deny||java/lib
+ allow||java/lib/README
+ 2) dir allow can undo a file deny
+ deny||java/lib/README
+ allow||java/lib
+ 3) file deny trumps a dir allow
+ allow||java/lib
+ deny||java/lib/README
+ 4) dir deny trumps a file allow
+ allow||java/lib/README
+ deny||java/lib
+ ... so last match always takes precedence
+
+=cut
+
+$debug = 0; # Set to 1 for debug messages
+
+%repository_matches = (); # hash of match file and pattern from 'cvsacl'
+ # repository_matches --> [branch, matching-pattern]
+ # (Used during module/branch matching loop)
+
+%restricted_entries = (); # hash table of restricted commit files (from @ARGV)
+ # restricted_entries --> branch
+ # (If user/module/branch all match on an 'deny'
+ # line, then entries added to this map.)
+
+%branch; # hash table of key: commit file; value: branch
+ # Built from ".../CVS/Entries" file of directory
+ # currently being examined
+
+# ---------------------------------------------------------------- get CVSROOT
+$cvsroot = $ENV{'CVSROOT'};
+die "Must set CVSROOT\n" if !$cvsroot;
+if ($cvsroot =~ /:([\/\w]*)$/) { # Filter ":pserver:", ":local:"-type prefixes
+ $cvsroot = $1;
+}
+
+# ------------------------------------------------------------- set file paths
+$entries = "CVS/Entries"; # client-side file???
+$cvsaclfile = $cvsroot . "/CVSROOT/cvsacl";
+$restrictfile = $cvsroot . "/CVSROOT/restrict_msg";
+$restrictlog = $cvsroot . "/CVSROOT/restrict_log";
+
+# --------------------------------------------------------------- process args
+$user_name = processArgs(\@ARGV);
+
+print("$$ \@ARGV after processArgs is: @ARGV.\n") if $debug;
+print("$$ ========== Begin $PROGRAM_NAME for \"$ARGV[0]\" repository. ========== \n") if $debug;
+
+# --------------------------------------------------------------- filter @ARGV
+eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
+ while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
+exit 255 if $die; # process any variable=value switches
+
+print("$$ \@ARGV after shift processing contains:",join("\, ",@ARGV),".\n") if $debug;
+
+# ---------------------------------------------------------------- get cvsroot
+($repository = shift) =~ s:^$cvsroot/::;
+grep($_ = $repository . '/' . $_, @ARGV);
+
+print("$$ \$cvsroot is: $cvsroot.\n") if $debug;
+print "$$ Repos: $repository\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
+
+$exit_val = 0; # presume good exit value for commit
+
+# ----------------------------------------------------------------------------
+# ---------------------------------- create hash table $branch{file -> branch}
+# ----------------------------------------------------------------------------
+
+# Here's a typical Entries file:
+#
+# /checkoutlist/1.4/Wed Feb 4 23:51:23 2004//
+# /cvsacl/1.3/Tue Feb 24 23:05:43 2004//
+# ...
+# /verifymsg/1.1/Fri Mar 16 19:56:24 2001//
+# D/backup////
+# D/temp////
+
+open(ENTRIES, $entries) || die("Cannot open $entries.\n");
+print("$$ File / Branch\n") if $debug;
+my $i = 0;
+while(<ENTRIES>) {
+ chop;
+ next if /^\s*$/; # Skip blank lines
+ $i = $i + 1;
+ if (m|
+ / # 1st slash
+ ([\w.-]*) # file name -> $1
+ / # 2nd slash
+ .* # revision number
+ / # 3rd slash
+ .* # date and time
+ / # 4th slash
+ .* # keyword
+ / # 5th slash
+ T? # 'T' constant
+ (\w*) # branch -> #2
+ |x) {
+ $branch{$repository . '/' . $1} = ($2) ? $2 : "HEAD";
+ print "$$ CVS Entry $i: $1/$2\n" if $debug;
+ }
+}
+close(ENTRIES);
+
+# ----------------------------------------------------------------------------
+# ------------------------------------- evaluate each active line from 'cvsacl'
+# ----------------------------------------------------------------------------
+open (CVSACL, $cvsaclfile) || exit(0); # It is ok for cvsacl file not to exist
+while (<CVSACL>) {
+ chop;
+ next if /^\s*\#/; # skip comments
+ next if /^\s*$/; # skip blank lines
+ # --------------------------------------------- parse current 'cvsacl' line
+ print("$$ ==========\n$$ Processing \'cvsacl\' line: $_.\n") if $debug;
+ ($cvsacl_flag, $cvsacl_userIds, $cvsacl_modules, $cvsacl_branches) = split(/[\s,]*\|[\s,]*/, $_);
+
+ # ------------------------------ Validate 'allow' or 'deny' line prefix
+ if ($cvsacl_flag !~ /^allow/ && $cvsacl_flag !~ /^deny/) {
+ print ("Bad cvsacl line: $_\n") if $debug;
+ $log_text = sprintf "Bad cvsacl line: %s", $_;
+ write_restrictlog_record($log_text);
+ next;
+ }
+
+ # -------------------------------------------------- init loop match flags
+ $user_match = 0;
+ %repository_matches = ();
+
+ # ------------------------------------------------------------------------
+ # ---------------------------------------------------------- user matching
+ # ------------------------------------------------------------------------
+ # $user_name considered "in user list" if actually in list or is NULL
+ $user_match = (!$cvsacl_userIds || grep ($_ eq $user_name, split(/[\s,]+/,$cvsacl_userIds)));
+ print "$$ \$user_name: $user_name \$user_match match flag is: $user_match.\n" if $debug;
+ if (!$user_match) {
+ next; # no match, skip to next 'cvsacl' line
+ }
+
+ # ------------------------------------------------------------------------
+ # ---------------------------------------------------- repository matching
+ # ------------------------------------------------------------------------
+ if (!$cvsacl_modules) { # blank module list = all modules
+ if (!$cvsacl_branches) { # blank branch list = all branches
+ print("$$ Adding all modules to \%repository_matches; null " .
+ "\$cvsacl_modules and \$cvsacl_branches.\n") if $debug;
+ for $commit_object (@ARGV) {
+ $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_modules];
+ print("$$ \$repository_matches{$commit_object} = " .
+ "[$branch{$commit_object}, $cvsacl_modules].\n") if $debug;
+ }
+ }
+ else { # need to check for repository match
+ @branch_list = split (/[\s,]+/,$cvsacl_branches);
+ print("$$ Branches from \'cvsacl\' record: ", join(", ",@branch_list),".\n") if $debug;
+ for $commit_object (@ARGV) {
+ if (grep($branch{$commit_object}, @branch_list)) {
+ $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_modules];
+ print("$$ \$repository_matches{$commit_object} = " .
+ "[$branch{$commit_object}, $cvsacl_modules].\n") if $debug;
+ }
+ }
+ }
+ }
+ else {
+ # ----------------------------------- check every argument combination
+ # parse 'cvsacl' modules to array
+ my @module_list = split(/[\s,]+/,$cvsacl_modules);
+ # ------------- Check all modules in list for either file or directory
+ my $fileType = "";
+ if (($fileType = checkFileness(@module_list)) eq "") {
+ next; # skip bad file types
+ }
+ # ---------- Check each combination of 'cvsacl' modules vs. @ARGV files
+ print("$$ Checking matches for \@module_list: ", join("\, ",@module_list), ".\n") if $debug;
+ # loop thru all command-line commit objects
+ for $commit_object (@ARGV) {
+ # loop thru all modules on 'cvsacl' line
+ for $cvsacl_module (@module_list) {
+ print("$$ Is \'cvsacl\': $cvsacl_modules pattern in: \@ARGV " .
+ "\$commit_object: $commit_object?\n") if $debug;
+ # Do match of beginning of $commit_object
+ checkModuleMatch($fileType, $commit_object, $cvsacl_module);
+ } # end for commit objects
+ } # end for cvsacl modules
+ } # end if
+
+ print("$$ Matches for: \%repository_matches: ", join("\, ", (keys %repository_matches)), ".\n") if $debug;
+
+ # ------------------------------------------------------------------------
+ # ----------------------------------------------------- setting exit value
+ # ------------------------------------------------------------------------
+ if ($user_match && %repository_matches) {
+ print("$$ An \"$cvsacl_flag\" match on User(s): $cvsacl_userIds; Module(s):" .
+ " $cvsacl_modules; Branch(es): $cvsacl_branches.\n") if $debug;
+ if ($cvsacl_flag eq "deny") {
+ # Add all matches to the hash of restricted modules
+ foreach $commitFile (keys %repository_matches) {
+ print("$$ Adding \%repository_matches entry: $commitFile.\n") if $debug;
+ $restricted_entries{$commitFile} = $repository_matches{$commitFile}[0];
+ }
+ }
+ else {
+ # Remove all matches from the restricted modules hash
+ foreach $commitFile (keys %repository_matches) {
+ print("$$ Removing \%repository_matches entry: $commitFile.\n") if $debug;
+ delete $restricted_entries{$commitFile};
+ }
+ }
+ }
+ print "$$ ==== End of processing for \'cvsacl\' line: $_.\n" if $debug;
+}
+close(CVSACL);
+
+# ----------------------------------------------------------------------------
+# --------------------------------------- determine final 'commit' disposition
+# ----------------------------------------------------------------------------
+if (%restricted_entries) { # any restricted entries?
+ $exit_val = 1; # don't commit
+ print("**** Access denied: Insufficient authority for user: '$user_name\' " .
+ "to commit to \'$repository\'.\n**** Contact CVS Administrators if " .
+ "you require update access to these directories or files.\n");
+ print("**** file(s)/dir(s) restricted were:\n\t", join("\n\t",keys %restricted_entries), "\n");
+ printOptionalRestrictionMessage();
+ write_restrictlog();
+}
+elsif (!$exit_val && $debug) {
+ print "**** Access allowed: Sufficient authority for commit.\n";
+}
+
+print "$$ ==== \$exit_val = $exit_val\n" if $debug;
+exit($exit_val);
+
+# ----------------------------------------------------------------------------
+# -------------------------------------------------------------- end of "main"
+# ----------------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------------
+# -------------------------------------------------------- process script args
+# ----------------------------------------------------------------------------
+sub processArgs {
+
+# This subroutine is passed a reference to @ARGV.
+
+# If @ARGV contains a "-u" entry, use that as the effective userId. In this
+# case, the userId is the client-side userId that has been passed to this
+# script by the commit_prep script. (This is why the commit_prep script must
+# be placed *before* the cvs_acls script in the commitinfo admin file.)
+
+# Otherwise, pull the userId from the server-side environment.
+
+ my $userId = "";
+ my ($argv) = shift; # pick up ref to @ARGV
+ my @argvClone = (); # immutable copy for foreach loop
+ for ($i=0; $i<(scalar @{$argv}); $i++) {
+ $argvClone[$i]=$argv->[$i];
+ }
+
+ print("$$ \@_ to processArgs is: @_.\n") if $debug;
+
+ # Parse command line arguments (file list is seen as one arg)
+ foreach $arg (@argvClone) {
+ print("$$ \$arg for processArgs loop is: $arg.\n") if $debug;
+ # Set $debug flag?
+ if ($arg eq '-d') {
+ shift @ARGV;
+ $debug = 1;
+ print("$$ \$debug flag set on.\n") if $debug;
+ print STDERR "Debug turned on...\n";
+ }
+ # Passing in a client-side userId?
+ elsif ($arg eq '-u') {
+ shift @ARGV;
+ $userId = shift @ARGV;
+ print("$$ client-side \$userId set to: $userId.\n") if $debug;
+ }
+ # An override for the default restrictlog file?
+ elsif ($arg eq '-f') {
+ shift @ARGV;
+ $restrictlog = shift @ARGV;
+ }
+ else {
+ next;
+ }
+ }
+
+ # No client-side userId passed? then get from server env
+ if (!$userId) {
+ $userId = $ENV{"USER"} if !($userId = $ENV{"LOGNAME"});
+ print("$$ server-side \$userId set to: $userId.\n") if $debug;
+ }
+
+ print("$$ processArgs returning \$userId: $userId.\n") if $debug;
+ return $userId;
+
+}
+
+
+# ----------------------------------------------------------------------------
+# --------------------- Check all modules in list for either file or directory
+# ----------------------------------------------------------------------------
+sub checkFileness {
+
+# Module patterns on the 'cvsacl' record can be files or directories.
+# If it's a directory, we pattern-match the directory name from 'cvsacl'
+# against the left side of the committed filename to see if the file is in
+# that hierarchy. By contrast, files use an explicit match. If the entries
+# are neither files nor directories, then the cvsacl file has been set up
+# incorrectly; we return a "" and the caller skips that line as invalid.
+#
+# This function determines whether the entries on the 'cvsacl' record are all
+# directories or all files; it cannot be a mixture. This restriction put in
+# to simplify the logic (without taking away much functionality).
+
+ my @module_list = @_;
+ print("$$ Checking \"fileness\" or \"dir-ness\" for \@module_list entries.\n") if $debug;
+ print("$$ Entries are: ", join("\, ",@module_list), ".\n") if $debug;
+ my $filetype = "";
+ for $cvsacl_module (@module_list) {
+ my $reposDirName = $cvsroot . '/' . $cvsacl_module;
+ my $reposFileName = $reposDirName . "\,v";
+ print("$$ In checkFileness: \$reposDirName: $reposDirName; \$reposFileName: $reposFileName.\n") if $debug;
+ if (((-d $reposDirName) && ($filetype eq "file")) || ((-f $reposFileName) && ($filetype eq "dir"))) {
+ print("Can\'t mix files and directories on single \'cvsacl\' file record; skipping entry.\n");
+ print(" Please contact a CVS administrator.\n");
+ $filetype = "";
+ last;
+ }
+ elsif (-d $reposDirName) {
+ $filetype = "dir";
+ print("$$ $reposDirName is a directory.\n") if $debug;
+ }
+ elsif (-f $reposFileName) {
+ $filetype = "file";
+ print("$$ $reposFileName is a regular file.\n") if $debug;
+ }
+ else {
+ print("***** Item to commit was neither a regular file nor a directory.\n");
+ print("***** Current \'cvsacl\' line ignored.\n");
+ print("***** Possible problem with \'cvsacl\' admin file. Please contact a CVS administrator.\n");
+ $filetype = "";
+ $text = sprintf("Module entry on cvsacl line: %s is not a valid file or directory.\n", $cvsacl_module);
+ write_restrictlog_record($text);
+ last;
+ } # end if
+ } # end for
+
+ print("$$ checkFileness will return \$filetype: $filetype.\n") if $debug;
+ return $filetype;
+}
+
+
+# ----------------------------------------------------------------------------
+# ----------------------------------------------------- check for module match
+# ----------------------------------------------------------------------------
+sub checkModuleMatch {
+
+# This subroutine checks for a match between the directory or file pattern
+# specified in the 'cvsacl' file (i.e., $cvsacl_modules) versus the commit file
+# objects passed into the script via @ARGV (i.e., $commit_object).
+
+# The directory pattern only has to match the beginning portion of the commit
+# file's name for a match since all files under that directory are considered
+# a match. File patterns must exactly match.
+
+# Since (theoretically, if not normally in practice) a working directory can
+# contain a mixture of files from different branches, this routine checks to
+# see if there is also a match on branch before considering the file
+# comparison a match.
+
+ my $match_flag = "";
+
+ print("$$ \@_ in checkModuleMatch is: @_.\n") if $debug;
+ my ($type,$commit_object,$cvsacl_module) = @_;
+
+ if ($type eq "file") { # Do exact file match of $commit_object
+ if ($commit_object eq $cvsacl_module) {
+ $match_flag = "file";
+ } # Do dir match at beginning of $commit_object
+ }
+ elsif ($commit_object =~ /^$cvsacl_module\//) {
+ $match_flag = "dir";
+ }
+
+ if ($match_flag) {
+ print("$$ \$repository: $repository matches \$commit_object: $commit_object.\n") if $debug;
+ if (!$cvsacl_branches) { # empty branch pattern matches all
+ print("$$ blank \'cvsacl\' branch matches all commit files.\n") if $debug;
+ $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_module];
+ print("$$ \$repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_module].\n") if $debug;
+ }
+ else { # otherwise check branch hash table
+ @branch_list = split (/[\s,]+/,$cvsacl_branches);
+ print("$$ Branches from \'cvsacl\' record: ", join(", ",@branch_list),".\n") if $debug;
+ if (grep(/$branch{$commit_object}/, @branch_list)) {
+ $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_module];
+ print("$$ \$repository_matches{$commit_object} = [$branch{$commit_object}, " .
+ "$cvsacl_module].\n") if $debug;
+ }
+ }
+ }
+
+}
+
+# ----------------------------------------------------------------------------
+# ------------------------------------------------------- check for file match
+# ----------------------------------------------------------------------------
+sub printOptionalRestrictionMessage {
+
+# This subroutine optionally prints site-specific file restriction information
+# whenever a restriction condition is met. If the file 'restrict_msg' does
+# not exist, the routine immediately exits. If there is a 'restrict_msg' file
+# then all the contents are printed at the end of the standard restriction
+# message.
+
+# As seen from examining the definition of $restrictfile, the default filename
+# is: $CVSROOT/CVSROOT/restrict_msg.
+
+ open (RESTRICT, $restrictfile) || return; # It is ok for cvsacl file not to exist
+ while (<RESTRICT>) {
+ chop;
+ # print out each line
+ print("**** $_\n");
+ }
+
+}
+
+# ----------------------------------------------------------------------------
+# ---------------------------------------------------------- write log message
+# ----------------------------------------------------------------------------
+sub write_restrictlog {
+
+# This subroutine iterates through the list of restricted entries and logs
+# each one to the error logfile.
+
+ # write each line in @text out separately
+ foreach $commitfile (keys %restricted_entries) {
+ $log_text = sprintf "Commit attempt by: %s for: %s on branch: %s",
+ $user_name, $commitfile, $branch{$commitfile};
+ write_restrictlog_record($log_text);
+ }
+
+}
+
+# ----------------------------------------------------------------------------
+# ---------------------------------------------------------- write log message
+# ----------------------------------------------------------------------------
+sub write_restrictlog_record {
+
+# This subroutine receives a scalar string and writes it out to the
+# $restrictlog file as a separate line. Each line is prepended with the date
+# and time in the format: "2004/01/30 12:00:00 ".
+
+ $text = shift;
+
+ # return quietly if there is a problem opening the log file.
+ open(FILE, ">>$restrictlog") || return;
+
+ (@time) = localtime();
+
+ # write each line in @text out separately
+ $log_record = sprintf "%04d/%02d/%02d %02d:%02d:%02d %s.\n",
+ $time[5]+1900, $time[4]+1, $time[3], $time[2], $time[1], $time[0], $text;
+ print FILE $log_record;
+ print("$$ restrict_log record being written: $log_record to $restrictlog.\n") if $debug;
+
+ close(FILE);
+}
diff --git a/contrib/cvshelp.man b/contrib/cvshelp.man
new file mode 100644
index 0000000..b166af6
--- /dev/null
+++ b/contrib/cvshelp.man
@@ -0,0 +1,561 @@
+.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.\" Start a command example
+.de XS
+.SP
+.in +.5i
+.ft B
+.nf
+..
+.\" End a command example
+.de XE
+.fi
+.ft P
+.in -.5i
+.SP
+..
+.TH CVSHELP LOCAL "17 March 1991" FLUKE
+.SH NAME
+cvshelp \- advice on using the Concurrent Versions System
+.SH DESCRIPTION
+This man page is based on experience using CVS.
+It is bound to change as we gain more experience.
+If you come up with better advice than is found here,
+contact the Software Technology
+Group and we will add it to this page.
+.SS "Getting Started"
+Use the following steps to prepare to use CVS:
+.TP
+\(bu
+Take a look at the CVS manual page to see what it can do for you, and
+if it fits your environment (or can possibly be made to fit your
+environment).
+.XS
+man cvs
+.XE
+If things look good, continue on...
+.TP
+\(bu
+Setup the master source repository. Choose a directory with
+ample disk space available for source files. This is where the RCS
+`,v' files will be stored. Say you choose
+.B /src/master
+as the root
+of your source repository. Make the
+.SB CVSROOT.adm
+directory in the root of the source repository:
+.XS
+mkdir /src/master/CVSROOT.adm
+.XE
+.TP
+\(bu
+Populate this directory with the
+.I loginfo
+and
+.I modules
+files from the
+.B "/usr/doc/local/cvs"
+directory. Edit these files to reflect your local source repository
+environment \- they may be quite small initially, but will grow as
+sources are added to your source repository. Turn these files into
+RCS controlled files:
+.XS
+cd /src/master/CVSROOT.adm
+ci \-m'Initial loginfo file' loginfo
+ci \-m'Initial modules file' modules
+.XE
+.TP
+\(bu
+Run the command:
+.XS
+mkmodules /src/master/CVSROOT.adm
+.XE
+This will build the
+.BR ndbm (3)
+file for the modules database.
+.TP
+\(bu
+Remember to edit the
+.I modules
+file manually when sources are checked
+in with
+.B checkin
+or CVS
+.BR add .
+A copy of the
+.I modules
+file for editing can be retrieved with the command:
+.XS
+cvs checkout CVSROOT.adm
+.XE
+.TP
+\(bu
+Have all users of the CVS system set the
+.SM CVSROOT
+environment variable appropriately to reflect the placement of your
+source repository. If the above example is used, the following
+commands can be placed in a
+.I .login
+or
+.I .profile
+file:
+.XS
+setenv CVSROOT /src/master
+.XE
+for csh users, and
+.XS
+CVSROOT=/src/master; export CVSROOT
+.XE
+for sh users.
+.SS "Placing Locally Written Sources Under CVS Control"
+Say you want to place the `whizbang' sources under
+CVS control. Say further that the sources have never
+been under revision control before.
+.TP
+\(bu
+Move the source hierarchy (lock, stock, and barrel)
+into the master source repository:
+.XS
+mv ~/whizbang $CVSROOT
+.XE
+.TP
+\(bu
+Clean out unwanted object files:
+.XS
+cd $CVSROOT/whizbang
+make clean
+.XE
+.TP
+\(bu
+Turn every file in the hierarchy into an RCS controlled file:
+.XS
+descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-nV\fR\fIx\fR\fB_\fR\fIy\fR\fB *'
+.XE
+In this example, the initial release tag is \fBV\fIx\fB_\fIy\fR,
+representing version \fIx\fR.\fIy\fR.
+.LP
+You can use CVS on sources that are already under RCS control.
+The following example shows how.
+In this example, the source package is called `skunkworks'.
+.TP
+\(bu
+Move the source hierarchy into the master source
+repository:
+.XS
+mv ~/skunkworks $CVSROOT
+.XE
+.TP
+\(bu
+Clean out unwanted object files:
+.XS
+cd $CVSROOT/skunkworks
+make clean
+.XE
+.TP
+\(bu
+Clean out unwanted working files, leaving only the RCS `,v' files:
+.XS
+descend \-r rcsclean
+.XE
+Note: If any working files have been checked out and changed,
+.B rcsclean
+will fail. Check in the modified working files
+and run the command again.
+.TP
+\(bu
+Get rid of
+.SB RCS
+subdirectories. CVS does not use them.
+.XS
+descend \-r \-f 'mv RCS/*,v .'
+descend \-r \-f 'rmdir RCS'
+.XE
+.TP
+\(bu
+Delete any unwanted files that remain in the source hierarchy. Then
+make sure all files are under RCS control:
+.XS
+descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-n\fR\fItag\fR\fB *'
+.XE
+.I tag
+is the latest symbolic revision tag that you applied to your package
+(if any). Note: This command will probably generate lots of error
+messages (for directories and existing RCS files) that you can
+ignore.
+.SS "Placing a Third-Party Source Distribution Under CVS Control"
+The
+.B checkin
+command checks third-party sources into CVS. The
+difference between third-party sources and locally
+written sources is that third-party sources must be checked into a
+separate branch (called the
+.IR "vendor branch" )
+of the RCS tree. This makes it possible to merge local changes to
+the sources with later releases from the vendor.
+.TP
+\(bu
+Save the original distribution kit somewhere. For example, if the
+master source repository is
+.B /src/master
+the distribution kit could be saved in
+.BR /src/dist .
+Organize the distribution directory so that each release
+is clearly identifiable.
+.TP
+\(bu
+Unpack the package in a scratch directory, for example
+.BR ~/scratch .
+.TP
+\(bu
+Create a repository for the package.
+In this example, the package is called `Bugs-R-Us 4.3'.
+.XS
+mkdir $CVSROOT/bugs
+.XE
+.TP
+\(bu
+Check in the unpacked files:
+.XS
+cd ~/scratch
+checkin \-m 'Bugs-R-Us 4.3 distribution' bugs VENDOR V4_3
+.XE
+There is nothing magic about the tag `VENDOR', which is applied to
+the vendor branch. You can use whatever tag you want. `VENDOR' is a
+useful convention.
+.TP
+\(bu
+Never modify vendor files before checking them in.
+Check in the files
+.I exactly
+as you unpacked them.
+If you check in locally modified files, future vendor releases may
+wipe out your local changes.
+.SS "Working With CVS-Controlled Sources"
+To use or edit the sources, you must check out a private copy.
+For the following examples, the master files are assumed to reside in
+.BR "$CVSROOT/behemoth" .
+The working directory is
+.BR "~/work" .
+See
+.BR cvs (local)
+for more details on the commands mentioned below.
+.TP
+.I "To Check Out Working Files
+Use CVS
+.BR checkout :
+.XS
+cd ~/work
+cvs checkout behemoth
+.XE
+There is nothing magic about the working directory. CVS will check
+out sources anywhere you like. Once you have a working copy of the
+sources, you can compile or edit them as desired.
+.TP
+.I "To Display Changes You Have Made"
+Use CVS
+.BR diff
+to display detailed changes, equivalent to
+.BR rcsdiff (local).
+You can also use
+.BR cvscheck (local)
+to list files added, changed, and removed in
+the directory, but not yet
+.BR commit ted.
+You must be in a directory containing working files.
+.TP
+.I "To Display Revision Information"
+Use CVS
+.BR log ,
+which is equivalent to
+.BR rlog (local).
+You must be in a directory containing working files.
+.TP
+.I "To Update Working Files"
+Use CVS
+.BR update
+in a directory containing working files.
+This command brings your working files up
+to date with changes checked into the
+master repository since you last checked out or updated
+your files.
+.TP
+.I "To Check In Your Changes"
+Use CVS
+.BR commit
+in a directory containing working files.
+This command checks your changes into the master repository.
+You can specify files by name or use
+.XS
+cvs commit \-a
+.XE
+to
+.B commit
+all the files you have changed.
+.TP
+.I "To Add a File"
+Add the file to the working directory.
+Use CVS
+.B add
+to mark the file as added.
+Use CVS
+.B commit
+to add the file to the master repository.
+.TP
+.I "To Remove a File"
+Remove the file from the working directory.
+Use CVS
+.B remove
+to mark the file as removed.
+Use CVS
+.B commit
+to move the file from its current location in the master repository
+to the CVS
+.IR Attic
+directory.
+.TP
+.I "To Add a Directory"
+Add the directory to the working directory.
+Use CVS
+.B add
+to add the directory to the master repository.
+.TP
+.I "To Remove a Directory"
+.br
+You shouldn't remove directories under CVS. You should instead remove
+their contents and then prune them (using the
+.B \-f
+and
+.B \-p
+options) when you
+.B checkout
+or
+.B update
+your working files.
+.TP
+.I "To Tag a Release"
+Use CVS
+.B tag
+to apply a symbolic tag to the latest revision of each file in the
+master repository. For example:
+.XS
+cvs tag V2_1 behemoth
+.XE
+.TP
+.I "To Retrieve an Exact Copy of a Previous Release"
+During a CVS
+.B checkout
+or
+.BR update ,
+use the
+.B \-r
+option to retrieve revisions associated with a symbolic tag.
+Use the
+.B \-f
+option to ignore all RCS files that do not contain the
+tag.
+Use the
+.B \-p
+option to prune directories that wind up empty because none
+of their files matched the tag. Example:
+.XS
+cd ~/work
+cvs checkout \-r V2_1 \-f \-p behemoth
+.XE
+.SS "Logging Changes"
+It is a good idea to keep a change log together with the
+sources. As a minimum, the change log should name and describe each
+tagged release. The change log should also be under CVS control and
+should be tagged along with the sources.
+.LP
+.BR cvslog (local)
+can help. This command logs
+changes reported during CVS
+.B commit
+operations. It automatically
+updates a change log file in your working directory. When you are
+finished making changes, you (optionally) edit the change log file and
+then commit it to the master repository.
+.LP
+Note: You must edit the change log to describe a new release
+and
+.B commit
+it to the master repository
+.I before
+.BR tag ging
+the release using CVS. Otherwise, the release description will not be
+included in the tagged package.
+.LP
+See
+.BR cvslog (local)
+for more information.
+.SS "Merging a Subsequent Third-Party Distribution"
+The initial steps in this process are identical to placing a
+third-party distribution under CVS for the first time: save the
+distribution kit and unpack the package in a scratch directory. From
+that point the steps diverge.
+The following example considers release 5.0 of the
+Bugs-R-Us package.
+.TP
+\(bu
+Check in the sources after unpacking them:
+.XS
+cd ~/scratch
+checkin \-m 'Bugs-R-Us 5.0 distribution' bugs VENDOR V5_0 \\
+ | tee ~/WARNINGS
+.XE
+It is important to save the output of
+.B checkin
+in a file
+because it lists the sources that have been locally modified.
+It is best to save the file in a different directory (for example,
+your home directory). Otherwise,
+.B checkin
+will try to check it into the master repository.
+.TP
+\(bu
+In your usual working directory, check out a fresh copy of the
+distribution that you just checked in.
+.XS
+cd ~/work
+cvs checkout \-r VENDOR bugs
+.XE
+The
+.B checkout
+command shown above retrieves the latest revision on the vendor branch.
+.TP
+\(bu
+See the `WARNINGS' file for a list of all locally modified
+sources.
+For each locally modified source,
+look at the differences between
+the new distribution and the latest local revision:
+.XS
+cvs diff \-r \fR\fILocalRev file\fR\fB
+.XE
+In this command,
+.I LocalRev
+is the latest
+numeric or symbolic revision
+on the RCS trunk of
+.IR file .
+You can use CVS
+.B log
+to get the revision history.
+.TP
+\(bu
+If your local modifications to a file have been incorporated into
+the vendor's distribution, then you should reset the default RCS
+branch for that file to the vendor branch. CVS doesn't provide a
+mechanism to do this. You have to do it by hand in the master
+repository:
+.XS
+rcs \-bVENDOR \fR\fIfile\fR\fB,v
+.XE
+.TP
+\(bu
+If your local modifications need to be merged with the
+new distribution, use CVS
+.B join
+to do it:
+.XS
+cvs join \-r VENDOR \fR\fIfile\fR\fB
+.XE
+The resulting file will be placed in your working directory.
+Edit it to resolve any overlaps.
+.TP
+\(bu
+Test the merged package.
+.TP
+\(bu
+Commit all modified files to the repository:
+.XS
+cvs commit \-a
+.XE
+.TP
+\(bu
+Tag the repository with a new local tag.
+.SS "Applying Patches to Third-Party Sources"
+Patches are handled in a manner very similar to complete
+third-party distributions. This example considers patches applied to
+Bugs-R-Us release 5.0.
+.TP
+\(bu
+Save the patch files together with the distribution kit
+to which they apply.
+The patch file names should clearly indicate the patch
+level.
+.TP
+\(bu
+In a scratch directory, check out the last `clean' vendor copy \- the
+highest revision on the vendor branch with
+.IR "no local changes" :
+.XS
+cd ~/scratch
+cvs checkout \-r VENDOR bugs
+.XE
+.TP
+\(bu
+Use
+.BR patch (local)
+to apply the patches. You should now have an image of the
+vendor's software just as though you had received a complete,
+new release.
+.TP
+\(bu
+Proceed with the steps described for merging a subsequent third-party
+distribution.
+.TP
+\(bu
+Note: When you get to the step that requires you
+to check out the new distribution after you have
+checked it into the vendor branch, you should move to a different
+directory. Do not attempt to
+.B checkout
+files in the directory in
+which you applied the patches. If you do, CVS will try to merge the
+changes that you made during patching with the version being checked
+out and things will get very confusing. Instead,
+go to a different directory (like your working directory) and
+check out the files there.
+.SS "Advice to Third-Party Source Hackers"
+As you can see from the preceding sections, merging local changes
+into third-party distributions remains difficult, and probably
+always will. This fact suggests some guidelines:
+.TP
+\(bu
+Minimize local changes.
+.I Never
+make stylistic changes.
+Change makefiles only as much as needed for installation. Avoid
+overhauling anything. Pray that the vendor does the same.
+.TP
+\(bu
+Avoid renaming files or moving them around.
+.TP
+\(bu
+Put independent, locally written files like help documents, local
+tools, or man pages in a sub-directory called `local-additions'.
+Locally written files that are linked into an existing executable
+should be added right in with the vendor's sources (not in a
+`local-additions' directory).
+If, in the future,
+the vendor distributes something
+equivalent to your locally written files
+you can CVS
+.B remove
+the files from the `local-additions' directory at that time.
+.SH SEE ALSO
+.BR cvs (local),
+.BR checkin (local),
+.BR cvslog (local),
+.BR cvscheck (local)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+Technical Computing
diff --git a/contrib/debug_check_log.sh b/contrib/debug_check_log.sh
new file mode 100755
index 0000000..ea55344
--- /dev/null
+++ b/contrib/debug_check_log.sh
@@ -0,0 +1,201 @@
+#!/bin/sh
+
+# Copyright (C) 2000-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+#
+# This program is intended to take a check.log file generated by a failed run of
+# sanity.sh as input and run expr line by line on it. It seems a much easier
+# way of spotting a single failed line in a 100 line test result.
+#
+
+#
+# Contributed by Derek R. Price <derek.price@openavenue.com>
+#
+
+
+
+usage ()
+{
+ echo "\
+usage: $0 [-afh] [file...]
+
+ -a process alternate pattern
+ -f process first pattern (default)
+ -h print this text
+
+ file files to process (default = check.log)"
+}
+
+# Do a line by line match with expr
+#
+# INPUTS
+# $1 = text file name
+# $2 = pattern file name
+expr_line_by_line ()
+{
+ dcl_line=0
+ dcl_wrong=
+ # We are assuming a newline at the end of the file. The way sanity.sh
+ # uses echo to create the log message guarantees this newline and since
+ # expr ignores the last newline when the anchor is present anyhow, no
+ # information is being lost in the transition
+ while test $dcl_line -lt `wc -l <$1` -a $dcl_line -lt `wc -l <$2`; do
+ dcl_line=`expr $dcl_line + 1`
+ if test `sed -ne${dcl_line}p <$1 |wc -c` -eq 1 \
+ -a `sed -ne${dcl_line}p <$2 |wc -c` -eq 1; then
+ # This is a workaround for what I am calling a bug in GNU
+ # expr - it won't match the empty string to the empty
+ # string. In this case the assumption is that a single
+ # character is always a newline. Since we already checked
+ # for the end of the file, we know sed will echo the
+ # newline.
+ :
+ elif expr "`sed -ne${dcl_line}p <$1`" : \
+ "`sed -ne${dcl_line}p <$2`\$" >/dev/null; then
+ :
+ else
+ echo "$dcl_line: `sed -ne${dcl_line}p <$1`"
+ echo "$dcl_line: `sed -ne${dcl_line}p <$2`\$"
+ dcl_wrong="$dcl_wrong $dcl_line"
+ fi
+ done
+ if test `wc -l <$1` -ne `wc -l <$2`; then
+ echo "output & pattern contain differing number of lines"
+ elif test -z "$dcl_wrong"; then
+ echo "no mismatched lines"
+ else
+ echo "mismatched lines: $dcl_wrong"
+ fi
+}
+
+# Process a single check.log file
+#
+# INPUTS
+# $1 = filename
+process_check_log ()
+{
+ # abort if we can't find any expressions
+ if grep '^\*\* got: $' <$1 >/dev/null; then
+ :
+ else
+ echo "WARNING: No expressions in file: $1" >&2
+ echo " Either not a check.log or sanity.sh exited for some other reason," >&2
+ echo " like bad exit status. Try tail." >&2
+ return
+ fi
+
+ dcl_exprfiles=""
+ if grep '^\*\* or: $' <$1 >/dev/null; then
+ # file contains a second regex
+ if test $dcl_dofirst -eq 1; then
+ # get the first pattern
+ sed -ne '/^\*\* expected: $/,/^\*\* or: $/p' <$1 >/tmp/dcle$$
+ dcl_exprfiles="$dcl_exprfiles /tmp/dcle$$"
+ fi
+ if test $dcl_doalternate -eq 1; then
+ # get the alternate pattern
+ sed -ne '/^\*\* or: $/,/^\*\* got: $/p' <$1 >/tmp/dclo$$
+ dcl_exprfiles="$dcl_exprfiles /tmp/dclo$$"
+ else
+ echo "WARNING: Ignoring alternate pattern in file: $1" >&2
+ fi
+ else
+ # file doesn't contain a second regex
+ if test $dcl_dofirst = 1; then
+ # get the only pattern
+ sed -ne '/^\*\* expected: $/,/^\*\* got: $/p' <$1 >/tmp/dcle$$
+ dcl_exprfiles="$dcl_exprfiles /tmp/dcle$$"
+ fi
+ if test $dcl_doalternate -eq 1; then
+ echo "WARNING: No alternate pattern in file: $1" >&2
+ fi
+ fi
+
+ # and get the actual output
+ sed -ne '/^\*\* got: $/,$p' <$1 >/tmp/dclg$$
+ sed -ne '1D
+$D
+p' </tmp/dclg$$ >/tmp/dclh$$
+ mv /tmp/dclh$$ /tmp/dclg$$
+
+ # compare the output against each pattern requested
+ for dcl_f in $dcl_exprfiles; do
+ sed -ne '1D
+$D
+p' <$dcl_f >/tmp/dclp$$
+ mv /tmp/dclp$$ $dcl_f
+
+ case $dcl_f in
+ /tmp/dcle*)
+ echo "********** $1 : Primary **********"
+ ;;
+ /tmp/dclo*)
+ echo "********** $1 : Alternate **********"
+ ;;
+ esac
+
+ expr_line_by_line /tmp/dclg$$ $dcl_f
+
+ rm $dcl_f
+ done
+
+ rm /tmp/dclg$$
+}
+
+###
+### MAIN
+###
+
+# set up defaults
+dcl_doalternate=0
+dcl_dofirst=0
+
+# process options
+while getopts afh arg; do
+ case $arg in
+ a)
+ dcl_doalternate=1
+ ;;
+ f)
+ dcl_dofirst=1
+ ;;
+ \?|h)
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+# dispose of processed args
+shift `expr $OPTIND - 1`
+OPTIND=1
+
+# set the default mode
+if test $dcl_doalternate -eq 0; then
+ dcl_dofirst=1
+fi
+
+# set default arg
+if test $# -eq 0; then
+ if test -f src/check.log && test -r src/check.log; then
+ set src/check.log
+ else
+ set check.log
+ fi
+fi
+
+for file in "$@"; do
+ process_check_log $file;
+done
+
+exit 0
diff --git a/contrib/descend.man b/contrib/descend.man
new file mode 100644
index 0000000..0434ca8
--- /dev/null
+++ b/contrib/descend.man
@@ -0,0 +1,114 @@
+.TH DESCEND 1 "31 March 1992"
+.SH NAME
+descend \- walk directory tree and execute a command at each node
+.SH SYNOPSIS
+.B descend
+[
+.B \-afqrv
+]
+.I command
+[
+.I directory
+\&.\|.\|.
+]
+.SH DESCRIPTION
+.B descend
+walks down a directory tree and executes a command at each node. It
+is not as versatile as
+.BR find (1),
+but it has a simpler syntax. If no
+.I directory
+is specified,
+.B descend
+starts at the current one.
+.LP
+Unlike
+.BR find ,
+.B descend
+can be told to skip the special directories associated with RCS,
+CVS, and SCCS. This makes
+.B descend
+especially handy for use with these packages. It can be used with
+other commands too, of course.
+.LP
+.B descend
+is a poor man's way to make any command recursive. Note:
+.B descend
+does not follow symbolic links to directories unless they are
+specified on the command line.
+.SH OPTIONS
+.TP 15
+.B \-a
+.I All.
+Descend into directories that begin with '.'.
+.TP
+.B \-f
+.I Force.
+Ignore errors during descent. Normally,
+.B descend
+quits when an error occurs.
+.TP
+.B \-q
+.I Quiet.
+Suppress the message `In directory
+.IR directory '
+that is normally printed during the descent.
+.TP
+.B \-r
+.I Restricted.
+Don't descend into the special directories
+.SB RCS,
+.SB CVS,
+.SB CVS.adm,
+and
+.SB SCCS.
+.TP
+.B \-v
+.I Verbose.
+Print
+.I command
+before executing it.
+.SH EXAMPLES
+.TP 15
+.B "descend ls"
+Cheap substitute for `ls -R'.
+.TP 15
+.B "descend -f 'rm *' tree"
+Strip `tree' of its leaves. This command descends the `tree'
+directory, removing all regular files. Since
+.BR rm (1)
+does not remove directories, this command leaves the directory
+structure of `tree' intact, but denuded. The
+.B \-f
+option is required to keep
+.B descend
+from quitting. You could use `rm \-f' instead.
+.TP
+.B "descend -r 'co RCS/*'" /project/src/
+Check out every RCS file under the directory
+.BR "/project/src" .
+.TP
+.B "descend -r 'cvs diff'"
+Perform CVS `diff' operation on every directory below (and including)
+the current one.
+.SH DIAGNOSTICS
+Returns 1 if errors occur (and the
+.B \-f
+option is not used). Otherwise returns 0.
+.SH SEE ALSO
+.BR find (1),
+.BR rcsintro (1),
+.BR cvs (1),
+.BR sccs (1)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+John Fluke Mfg. Co., Inc.
+.SH BUGS
+Shell metacharacters in
+.I command
+may have bizarre effects. In particular, compound commands
+(containing ';', '[', and ']' characters) will not work. It is best
+to enclose complicated commands in single quotes \(aa\ \(aa.
diff --git a/contrib/descend.sh b/contrib/descend.sh
new file mode 100644
index 0000000..0b30e11
--- /dev/null
+++ b/contrib/descend.sh
@@ -0,0 +1,127 @@
+#! /bin/sh
+#
+# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# descend - walk down a directory tree and execute a command at each node
+
+fullname=$0
+name=descend
+usage="Usage: $name [-afqrv] command [directory ...]\n
+\040\040-a\040\040All: descend into directories starting with '.'\n
+\040\040-f\040\040Force: ignore errors during descent\n
+\040\040-q\040\040Quiet: don't print directory names\n
+\040\040-r\040\040Restricted: don't descend into RCS, CVS.adm, SCCS directories\n
+\040\040-v\040\040Verbose: print command before executing it"
+
+# Scan for options
+while getopts afqrv option; do
+ case $option in
+ a)
+ alldirs=$option
+ options=$options" "-$option
+ ;;
+ f)
+ force=$option
+ options=$options" "-$option
+ ;;
+ q)
+ verbose=
+ quiet=$option
+ options=$options" "-$option
+ ;;
+ r)
+ restricted=$option
+ options=$options" "-$option
+ ;;
+ v)
+ verbose=$option
+ quiet=
+ options=$options" "-$option
+ ;;
+ \?)
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+# Get command to execute
+if [ $# -lt 1 ] ; then
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+else
+ command=$1
+ shift
+fi
+
+# If no directory specified, use '.'
+if [ $# -lt 1 ] ; then
+ default_dir=.
+fi
+
+# For each directory specified
+for dir in $default_dir "$@" ; do
+
+ # Spawn sub-shell so we return to starting directory afterward
+ (cd $dir
+
+ # Execute specified command
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`
+ fi
+ if [ -n "$verbose" ] ; then
+ echo $command
+ fi
+ eval "$command" || if [ -z "$force" ] ; then exit 1; fi
+
+ # Collect dot file names if necessary
+ if [ -n "$alldirs" ] ; then
+ dotfiles=.*
+ else
+ dotfiles=
+ fi
+
+ # For each file in current directory
+ for file in $dotfiles * ; do
+
+ # Skip '.' and '..'
+ if [ "$file" = "." -o "$file" = ".." ] ; then
+ continue
+ fi
+
+ # If a directory but not a symbolic link
+ if [ -d "$file" -a ! -h "$file" ] ; then
+
+ # If not skipping this type of directory
+ if [ \( "$file" != "RCS" -a \
+ "$file" != "SCCS" -a \
+ "$file" != "CVS" -a \
+ "$file" != "CVS.adm" \) \
+ -o -z "$restricted" ] ; then
+
+ # Recursively descend into it
+ $fullname $options "$command" "$file" \
+ || if [ -z "$force" ] ; then exit 1; fi
+ fi
+
+ # Else if a directory AND a symbolic link
+ elif [ -d "$file" -a -h "$file" ] ; then
+
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`/$file: symbolic link: skipping
+ fi
+ fi
+ done
+ ) || if [ -z "$force" ] ; then exit 1; fi
+done
diff --git a/contrib/dirfns.shar b/contrib/dirfns.shar
new file mode 100644
index 0000000..8324c41
--- /dev/null
+++ b/contrib/dirfns.shar
@@ -0,0 +1,481 @@
+echo 'directory.3':
+sed 's/^X//' >'directory.3' <<'!'
+X.TH DIRECTORY 3 imported
+X.DA 9 Oct 1985
+X.SH NAME
+Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations
+X.SH SYNOPSIS
+X.B #include <sys/types.h>
+X.br
+X.B #include <ndir.h>
+X.PP
+X.SM
+X.B DIR
+X.B *opendir(filename)
+X.br
+X.B char *filename;
+X.PP
+X.SM
+X.B struct direct
+X.B *readdir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B long
+X.B telldir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B seekdir(dirp, loc)
+X.br
+X.B DIR *dirp;
+X.br
+X.B long loc;
+X.PP
+X.SM
+X.B rewinddir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B closedir(dirp)
+X.br
+X.B DIR *dirp;
+X.SH DESCRIPTION
+XThis library provides high-level primitives for directory scanning,
+Xsimilar to those available for 4.2BSD's (very different) directory system.
+X.\"The purpose of this library is to simulate
+X.\"the new flexible length directory names of 4.2bsd UNIX
+X.\"on top of the old directory structure of v7.
+XIt incidentally provides easy portability to and from 4.2BSD (insofar
+Xas such portability is not compromised by other 4.2/VAX dependencies).
+X.\"It allows programs to be converted immediately
+X.\"to the new directory access interface,
+X.\"so that they need only be relinked
+X.\"when moved to 4.2bsd.
+X.\"It is obtained with the loader option
+X.\".BR \-lndir .
+X.PP
+X.I Opendir
+Xopens the directory named by
+X.I filename
+Xand associates a
+X.I directory stream
+Xwith it.
+X.I Opendir
+Xreturns a pointer to be used to identify the
+X.I directory stream
+Xin subsequent operations.
+XThe pointer
+X.SM
+X.B NULL
+Xis returned if
+X.I filename
+Xcannot be accessed or is not a directory.
+X.PP
+X.I Readdir
+Xreturns a pointer to the next directory entry.
+XIt returns
+X.B NULL
+Xupon reaching the end of the directory or detecting
+Xan invalid
+X.I seekdir
+Xoperation.
+X.PP
+X.I Telldir
+Xreturns the current location associated with the named
+X.I directory stream.
+X.PP
+X.I Seekdir
+Xsets the position of the next
+X.I readdir
+Xoperation on the
+X.I directory stream.
+XThe new position reverts to the one associated with the
+X.I directory stream
+Xwhen the
+X.I telldir
+Xoperation was performed.
+XValues returned by
+X.I telldir
+Xare good only for the lifetime of the DIR pointer from
+Xwhich they are derived.
+XIf the directory is closed and then reopened,
+Xthe
+X.I telldir
+Xvalue may be invalidated
+Xdue to undetected directory compaction in 4.2BSD.
+XIt is safe to use a previous
+X.I telldir
+Xvalue immediately after a call to
+X.I opendir
+Xand before any calls to
+X.I readdir.
+X.PP
+X.I Rewinddir
+Xresets the position of the named
+X.I directory stream
+Xto the beginning of the directory.
+X.PP
+X.I Closedir
+Xcauses the named
+X.I directory stream
+Xto be closed,
+Xand the structure associated with the DIR pointer to be freed.
+X.PP
+XA
+X.I direct
+Xstructure is as follows:
+X.PP
+X.RS
+X.nf
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X.fi
+X.RE
+X.PP
+XThe
+X.I d_reclen
+Xfield is meaningless in non-4.2BSD systems and should be ignored.
+XThe use of a
+X.I long
+Xfor
+X.I d_ino
+Xis also a 4.2BSDism;
+X.I ino_t
+X(see
+X.IR types (5))
+Xshould be used elsewhere.
+XThe macro
+X.I DIRSIZ(dp)
+Xgives the minimum memory size needed to hold the
+X.I direct
+Xvalue pointed to by
+X.IR dp ,
+Xwith the minimum necessary allocation for
+X.IR d_name .
+X.PP
+XThe preferred way to search the current directory for entry ``name'' is:
+X.PP
+X.RS
+X.nf
+X len = strlen(name);
+X dirp = opendir(".");
+X if (dirp == NULL) {
+X fprintf(stderr, "%s: can't read directory .\\n", argv[0]);
+X return NOT_FOUND;
+X }
+X while ((dp = readdir(dirp)) != NULL)
+X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
+X closedir(dirp);
+X return FOUND;
+X }
+X closedir(dirp);
+X return NOT_FOUND;
+X.RE
+X.\".SH LINKING
+X.\"This library is accessed by specifying ``-lndir'' as the
+X.\"last argument to the compile line, e.g.:
+X.\".PP
+X.\" cc -I/usr/include/ndir -o prog prog.c -lndir
+X.SH "SEE ALSO"
+Xopen(2),
+Xclose(2),
+Xread(2),
+Xlseek(2)
+X.SH HISTORY
+XWritten by
+XKirk McKusick at Berkeley (ucbvax!mckusick).
+XMiscellaneous bug fixes from elsewhere.
+XThe size of the data structure has been decreased to avoid excessive
+Xspace waste under V7 (where filenames are 14 characters at most).
+XFor obscure historical reasons, the include file is also available
+Xas
+X.IR <ndir/sys/dir.h> .
+XThe Berkeley version lived in a separate library (\fI\-lndir\fR),
+Xwhereas ours is
+Xpart of the C library, although the separate library is retained to
+Xmaximize compatibility.
+X.PP
+XThis manual page has been substantially rewritten to be informative in
+Xthe absence of a 4.2BSD manual.
+X.SH BUGS
+XThe
+X.I DIRSIZ
+Xmacro actually wastes a bit of space due to some padding requirements
+Xthat are an artifact of 4.2BSD.
+X.PP
+XThe returned value of
+X.I readdir
+Xpoints to a static area that will be overwritten by subsequent calls.
+X.PP
+XThere are some unfortunate name conflicts with the \fIreal\fR V7
+Xdirectory structure definitions.
+!
+echo 'dir.h':
+sed 's/^X//' >'dir.h' <<'!'
+X/* dir.h 4.4 82/07/25 */
+X
+X/*
+X * A directory consists of some number of blocks of DIRBLKSIZ
+X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+X *
+X * Each DIRBLKSIZ byte block contains some number of directory entry
+X * structures, which are of variable length. Each directory entry has
+X * a struct direct at the front of it, containing its inode number,
+X * the length of the entry, and the length of the name contained in
+X * the entry. These are followed by the name padded to a 4 byte boundary
+X * with null bytes. All names are guaranteed null terminated.
+X * The maximum length of a name in a directory is MAXNAMLEN.
+X *
+X * The macro DIRSIZ(dp) gives the amount of space required to represent
+X * a directory entry. Free space in a directory is represented by
+X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes
+X * in a directory block are claimed by the directory entries. This
+X * usually results in the last entry in a directory having a large
+X * dp->d_reclen. When entries are deleted from a directory, the
+X * space is returned to the previous entry in the same directory
+X * block by increasing its dp->d_reclen. If the first entry of
+X * a directory block is free, then its dp->d_ino is set to 0.
+X * Entries other than the first in a directory do not normally have
+X * dp->d_ino set to 0.
+X */
+X#define DIRBLKSIZ 512
+X#ifdef VMUNIX
+X#define MAXNAMLEN 255
+X#else
+X#define MAXNAMLEN 14
+X#endif
+X
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X
+X/*
+X * The DIRSIZ macro gives the minimum record length which will hold
+X * the directory entry. This requires the amount of space in struct direct
+X * without the d_name field, plus enough space for the name with a terminating
+X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+X */
+X#undef DIRSIZ
+X#define DIRSIZ(dp) \
+X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+X
+X#ifndef KERNEL
+X/*
+X * Definitions for library routines operating on directories.
+X */
+Xtypedef struct _dirdesc {
+X int dd_fd;
+X long dd_loc;
+X long dd_size;
+X char dd_buf[DIRBLKSIZ];
+X} DIR;
+X#ifndef NULL
+X#define NULL 0
+X#endif
+Xextern DIR *opendir();
+Xextern struct direct *readdir();
+Xextern long telldir();
+X#ifdef void
+Xextern void seekdir();
+Xextern void closedir();
+X#endif
+X#define rewinddir(dirp) seekdir((dirp), (long)0)
+X#endif KERNEL
+!
+echo 'makefile':
+sed 's/^X//' >'makefile' <<'!'
+XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o
+XCFLAGS=-O -I. -Dvoid=int
+XDEST=..
+X
+Xall: $(DIR)
+X
+Xmv: $(DIR)
+X mv $(DIR) $(DEST)
+X
+Xcpif: dir.h
+X cp dir.h /usr/include/ndir.h
+X
+Xclean:
+X rm -f *.o
+!
+echo 'closedir.c':
+sed 's/^X//' >'closedir.c' <<'!'
+Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * close a directory.
+X */
+Xvoid
+Xclosedir(dirp)
+X register DIR *dirp;
+X{
+X close(dirp->dd_fd);
+X dirp->dd_fd = -1;
+X dirp->dd_loc = 0;
+X free((char *)dirp);
+X}
+!
+echo 'opendir.c':
+sed 's/^X//' >'opendir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82";
+X
+X#include <sys/types.h>
+X#include <sys/stat.h>
+X#include <dir.h>
+X
+X/*
+X * open a directory.
+X */
+XDIR *
+Xopendir(name)
+X char *name;
+X{
+X register DIR *dirp;
+X register int fd;
+X struct stat statbuf;
+X char *malloc();
+X
+X if ((fd = open(name, 0)) == -1)
+X return NULL;
+X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) {
+X close(fd);
+X return NULL;
+X }
+X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
+X close (fd);
+X return NULL;
+X }
+X dirp->dd_fd = fd;
+X dirp->dd_loc = 0;
+X dirp->dd_size = 0; /* so that telldir will work before readdir */
+X return dirp;
+X}
+!
+echo 'readdir.c':
+sed 's/^X//' >'readdir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * read an old stlye directory entry and present it as a new one
+X */
+X#define ODIRSIZ 14
+X
+Xstruct olddirect {
+X ino_t od_ino;
+X char od_name[ODIRSIZ];
+X};
+X
+X/*
+X * get next entry in a directory.
+X */
+Xstruct direct *
+Xreaddir(dirp)
+X register DIR *dirp;
+X{
+X register struct olddirect *dp;
+X static struct direct dir;
+X
+X for (;;) {
+X if (dirp->dd_loc == 0) {
+X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
+X DIRBLKSIZ);
+X if (dirp->dd_size <= 0) {
+X dirp->dd_size = 0;
+X return NULL;
+X }
+X }
+X if (dirp->dd_loc >= dirp->dd_size) {
+X dirp->dd_loc = 0;
+X continue;
+X }
+X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
+X dirp->dd_loc += sizeof(struct olddirect);
+X if (dp->od_ino == 0)
+X continue;
+X dir.d_ino = dp->od_ino;
+X strncpy(dir.d_name, dp->od_name, ODIRSIZ);
+X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
+X dir.d_namlen = strlen(dir.d_name);
+X dir.d_reclen = DIRBLKSIZ;
+X return (&dir);
+X }
+X}
+!
+echo 'seekdir.c':
+sed 's/^X//' >'seekdir.c' <<'!'
+Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83";
+X
+X#include <sys/param.h>
+X#include <dir.h>
+X
+X/*
+X * seek to an entry in a directory.
+X * Only values returned by "telldir" should be passed to seekdir.
+X */
+Xvoid
+Xseekdir(dirp, loc)
+X register DIR *dirp;
+X long loc;
+X{
+X long curloc, base, offset;
+X struct direct *dp;
+X extern long lseek();
+X
+X curloc = telldir(dirp);
+X if (loc == curloc)
+X return;
+X base = loc & ~(DIRBLKSIZ - 1);
+X offset = loc & (DIRBLKSIZ - 1);
+X (void) lseek(dirp->dd_fd, base, 0);
+X dirp->dd_size = 0;
+X dirp->dd_loc = 0;
+X while (dirp->dd_loc < offset) {
+X dp = readdir(dirp);
+X if (dp == NULL)
+X return;
+X }
+X}
+!
+echo 'telldir.c':
+sed 's/^X//' >'telldir.c' <<'!'
+Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * return a pointer into a directory
+X */
+Xlong
+Xtelldir(dirp)
+X DIR *dirp;
+X{
+X long lseek();
+X
+X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
+X}
+!
+echo done
diff --git a/contrib/intro.doc b/contrib/intro.doc
new file mode 100644
index 0000000..a6d4ec1
--- /dev/null
+++ b/contrib/intro.doc
@@ -0,0 +1,112 @@
+Date: Tue, 16 Jun 1992 17:05:23 +0200
+From: Steven.Pemberton@cwi.nl
+Message-Id: <9206161505.AA06927.steven@sijs.cwi.nl>
+To: berliner@Sun.COM
+Subject: cvs
+
+INTRODUCTION TO USING CVS
+
+ CVS is a system that lets groups of people work simultaneously on
+ groups of files (for instance program sources).
+
+ It works by holding a central 'repository' of the most recent version
+ of the files. You may at any time create a personal copy of these
+ files; if at a later date newer versions of the files are put in the
+ repository, you can 'update' your copy.
+
+ You may edit your copy of the files freely. If new versions of the
+ files have been put in the repository in the meantime, doing an update
+ merges the changes in the central copy into your copy.
+ (It can be that when you do an update, the changes in the
+ central copy clash with changes you have made in your own
+ copy. In this case cvs warns you, and you have to resolve the
+ clash in your copy.)
+
+ When you are satisfied with the changes you have made in your copy of
+ the files, you can 'commit' them into the central repository.
+ (When you do a commit, if you haven't updated to the most
+ recent version of the files, cvs tells you this; then you have
+ to first update, resolve any possible clashes, and then redo
+ the commit.)
+
+USING CVS
+
+ Suppose that a number of repositories have been stored in
+ /usr/src/cvs. Whenever you use cvs, the environment variable
+ CVSROOT must be set to this (for some reason):
+
+ CVSROOT=/usr/src/cvs
+ export CVSROOT
+
+TO CREATE A PERSONAL COPY OF A REPOSITORY
+
+ Suppose you want a copy of the files in repository 'views' to be
+ created in your directory src. Go to the place where you want your
+ copy of the directory, and do a 'checkout' of the directory you
+ want:
+
+ cd $HOME/src
+ cvs checkout views
+
+ This creates a directory called (in this case) 'views' in the src
+ directory, containing a copy of the files, which you may now work
+ on to your heart's content.
+
+TO UPDATE YOUR COPY
+
+ Use the command 'cvs update'.
+
+ This will update your copy with any changes from the central
+ repository, telling you which files have been updated (their names
+ are displayed with a U before them), and which have been modified
+ by you and not yet committed (preceded by an M). You will be
+ warned of any files that contain clashes, the clashes will be
+ marked in the file surrounded by lines of the form <<<< and >>>>.
+
+TO COMMIT YOUR CHANGES
+
+ Use the command 'cvs commit'.
+
+ You will be put in an editor to make a message that describes the
+ changes that you have made (for future reference). Your changes
+ will then be added to the central copy.
+
+ADDING AND REMOVING FILES
+
+ It can be that the changes you want to make involve a completely
+ new file, or removing an existing one. The commands to use here
+ are:
+
+ cvs add <filename>
+ cvs remove <filename>
+
+ You still have to do a commit after these commands. You may make
+ any number of new files in your copy of the repository, but they
+ will not be committed to the central copy unless you do a 'cvs add'.
+
+OTHER USEFUL COMMANDS AND HINTS
+
+ To see the commit messages for files, and who made them, use:
+
+ cvs log [filenames]
+
+ To see the differences between your version and the central version:
+
+ cvs diff [filenames]
+
+ To give a file a new name, rename it and do an add and a remove.
+
+ To lose your changes and go back to the version from the
+ repository, delete the file and do an update.
+
+ After an update where there have been clashes, your original
+ version of the file is saved as .#file.version.
+
+ All the cvs commands mentioned accept a flag '-n', that doesn't do
+ the action, but lets you see what would happen. For instance, you
+ can use 'cvs -n update' to see which files would be updated.
+
+MORE INFORMATION
+
+ This is necessarily a very brief introduction. See the manual page
+ (man cvs) for full details.
diff --git a/contrib/log.in b/contrib/log.in
new file mode 100755
index 0000000..f12d338
--- /dev/null
+++ b/contrib/log.in
@@ -0,0 +1,238 @@
+#! @PERL@ -T
+# -*-Perl-*-
+
+# Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+###############################################################################
+###############################################################################
+###############################################################################
+#
+# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE
+# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE
+# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
+# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
+# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
+# <@PACKAGE_BUGREPORT@> MAILING LIST.
+#
+# For more on general Perl security and taint-checking, please try running the
+# `perldoc perlsec' command.
+#
+###############################################################################
+###############################################################################
+###############################################################################
+
+# XXX: FIXME: handle multiple '-f logfile' arguments
+#
+# XXX -- I HATE Perl! This *will* be re-written in shell/awk/sed soon!
+#
+
+# Usage: log.pl [-u user] [[-m mailto] ...] [-s] [-V] -f logfile 'dirname file ...'
+#
+# -u user - $USER passed from loginfo
+# -m mailto - for each user to receive cvs log reports
+# (multiple -m's permitted)
+# -s - to prevent "cvs status -v" messages
+# -V - without '-s', don't pass '-v' to cvs status
+# -f logfile - for the logfile to append to (mandatory,
+# but only one logfile can be specified).
+
+# here is what the output looks like:
+#
+# From: woods@kuma.domain.top
+# Subject: CVS update: testmodule
+#
+# Date: Wednesday November 23, 1994 @ 14:15
+# Author: woods
+#
+# Update of /local/src-CVS/testmodule
+# In directory kuma:/home/kuma/woods/work.d/testmodule
+#
+# Modified Files:
+# test3
+# Added Files:
+# test6
+# Removed Files:
+# test4
+# Log Message:
+# - wow, what a test
+#
+# (and for each file the "cvs status -v" output is appended unless -s is used)
+#
+# ==================================================================
+# File: test3 Status: Up-to-date
+#
+# Working revision: 1.41 Wed Nov 23 14:15:59 1994
+# Repository revision: 1.41 /local/src-CVS/cvs/testmodule/test3,v
+# Sticky Options: -ko
+#
+# Existing Tags:
+# local-v2 (revision: 1.7)
+# local-v1 (revision: 1.1.1.2)
+# CVS-1_4A2 (revision: 1.1.1.2)
+# local-v0 (revision: 1.2)
+# CVS-1_4A1 (revision: 1.1.1.1)
+# CVS (branch: 1.1.1)
+
+use strict;
+use IO::File;
+
+my $cvsroot = $ENV{'CVSROOT'};
+
+# turn off setgid
+#
+$) = $(;
+
+my $dostatus = 1;
+my $verbosestatus = 1;
+my $users;
+my $login;
+my $donefiles;
+my $logfile;
+my @files;
+
+# parse command line arguments
+#
+while (@ARGV) {
+ my $arg = shift @ARGV;
+
+ if ($arg eq '-m') {
+ $users = "$users " . shift @ARGV;
+ } elsif ($arg eq '-u') {
+ $login = shift @ARGV;
+ } elsif ($arg eq '-f') {
+ ($logfile) && die "Too many '-f' args";
+ $logfile = shift @ARGV;
+ } elsif ($arg eq '-s') {
+ $dostatus = 0;
+ } elsif ($arg eq '-V') {
+ $verbosestatus = 0;
+ } else {
+ ($donefiles) && die "Too many arguments!\n";
+ $donefiles = 1;
+ @files = split(/ /, $arg);
+ }
+}
+
+# the first argument is the module location relative to $CVSROOT
+#
+my $modulepath = shift @files;
+
+my $mailcmd = "| Mail -s 'CVS update: $modulepath'";
+
+# Initialise some date and time arrays
+#
+my @mos = ('January','February','March','April','May','June','July',
+ 'August','September','October','November','December');
+my @days = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
+
+my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
+$year += 1900;
+
+# get a login name for the guy doing the commit....
+#
+if ($login eq '') {
+ $login = getlogin || (getpwuid($<))[0] || "nobody";
+}
+
+# open log file for appending
+#
+my $logfh = new IO::File ">>" . $logfile
+ or die "Could not open(" . $logfile . "): $!\n";
+
+# send mail, if there's anyone to send to!
+#
+my $mailfh;
+if ($users) {
+ $mailcmd = "$mailcmd $users";
+ $mailfh = new IO::File $mailcmd
+ or die "Could not Exec($mailcmd): $!\n";
+}
+
+# print out the log Header
+#
+$logfh->print ("\n");
+$logfh->print ("****************************************\n");
+$logfh->print ("Date:\t$days[$wday] $mos[$mon] $mday, $year @ $hour:" . sprintf("%02d", $min) . "\n");
+$logfh->print ("Author:\t$login\n\n");
+
+if ($mailfh) {
+ $mailfh->print ("\n");
+ $mailfh->print ("Date:\t$days[$wday] $mos[$mon] $mday, $year @ $hour:" . sprintf("%02d", $min) . "\n");
+ $mailfh->print ("Author:\t$login\n\n");
+}
+
+# print the stuff from logmsg that comes in on stdin to the logfile
+#
+my $infh = new IO::File "< -";
+foreach ($infh->getlines) {
+ $logfh->print;
+ if ($mailfh) {
+ $mailfh->print ($_);
+ }
+}
+undef $infh;
+
+$logfh->print ("\n");
+
+# after log information, do an 'cvs -Qq status -v' on each file in the arguments.
+#
+if ($dostatus != 0) {
+ while (@files) {
+ my $file = shift @files;
+ if ($file eq "-") {
+ $logfh->print ("[input file was '-']\n");
+ if ($mailfh) {
+ $mailfh->print ("[input file was '-']\n");
+ }
+ last;
+ }
+ my $rcsfh = new IO::File;
+ my $pid = $rcsfh->open ("-|");
+ if ( !defined $pid )
+ {
+ die "fork failed: $!";
+ }
+ if ($pid == 0)
+ {
+ my @command = ('cvs', '-nQq', 'status');
+ if ($verbosestatus)
+ {
+ push @command, '-v';
+ }
+ push @command, $file;
+ exec @command;
+ die "cvs exec failed: $!";
+ }
+ my $line;
+ while ($line = $rcsfh->getline) {
+ $logfh->print ($line);
+ if ($mailfh) {
+ $mailfh->print ($line);
+ }
+ }
+ undef $rcsfh;
+ }
+}
+
+$logfh->close()
+ or die "Write to $logfile failed: $!";
+
+if ($mailfh)
+{
+ $mailfh->close;
+ die "Pipe to $mailcmd failed" if $?;
+}
+
+## must exit cleanly
+##
+exit 0;
diff --git a/contrib/log_accum.in b/contrib/log_accum.in
new file mode 100755
index 0000000..84189ab
--- /dev/null
+++ b/contrib/log_accum.in
@@ -0,0 +1,789 @@
+#! @PERL@ -T
+# -*-Perl-*-
+
+# Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+###############################################################################
+###############################################################################
+###############################################################################
+#
+# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE
+# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE
+# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
+# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
+# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
+# <@PACKAGE_BUGREPORT@> MAILING LIST.
+#
+# For more on general Perl security and taint-checking, please try running the
+# `perldoc perlsec' command.
+#
+###############################################################################
+###############################################################################
+###############################################################################
+
+# Perl filter to handle the log messages from the checkin of files in
+# a directory. This script will group the lists of files by log
+# message, and mail a single consolidated log message at the end of
+# the commit.
+#
+# This file assumes a pre-commit checking program that leaves the
+# names of the first and last commit directories in a temporary file.
+#
+# IMPORTANT: what the above means is, this script interacts with
+# commit_prep, in that they have to agree on the tmpfile name to use.
+# See $LAST_FILE below.
+#
+# How this works: CVS triggers this script once for each directory
+# involved in the commit -- in other words, a single commit can invoke
+# this script N times. It knows when it's on the last invocation by
+# examining the contents of $LAST_FILE. Between invocations, it
+# caches information for its future incarnations in various temporary
+# files in /tmp, which are named according to the process group and
+# the committer (by themselves, neither of these are unique, but
+# together they almost always are, unless the same user is doing two
+# commits simultaneously). The final invocation is the one that
+# actually sends the mail -- it gathers up the cached information,
+# combines that with what it found out on this pass, and sends a
+# commit message to the appropriate mailing list.
+#
+# (Ask Karl Fogel <kfogel@collab.net> if questions.)
+#
+# Contributed by David Hampton <hampton@cisco.com>
+# Roy Fielding removed useless code and added log/mail of new files
+# Ken Coar added special processing (i.e., no diffs) for binary files
+#
+
+############################################################
+#
+# Configurable options
+#
+############################################################
+#
+# The newest versions of CVS have UseNewInfoFmtStrings=yes
+# to change the arguments being passed on the command line.
+# If you are using %1s on the command line, then set this
+# value to 0.
+# 0 = old-style %1s format. use split(' ') to separate ARGV into filesnames.
+# 1 = new-style %s format. Note: allows spaces in filenames.
+my $UseNewInfoFmtStrings = 0;
+
+#
+# Where do you want the RCS ID and delta info?
+# 0 = none,
+# 1 = in mail only,
+# 2 = in both mail and logs.
+#
+$rcsidinfo = 2;
+
+#if you are using CVS web then set this to some value... if not set it to ""
+#
+# When set properly, this will cause links to aspects of the project to
+# print in the commit emails.
+#$CVSWEB_SCHEME = "http";
+#$CVSWEB_DOMAIN = "nongnu.org";
+#$CVSWEB_PORT = "80";
+#$CVSWEB_URI = "source/browse/";
+#$SEND_URL = "true";
+$SEND_DIFF = "true";
+
+
+# Set this to a domain to have CVS pretend that all users who make
+# commits have mail accounts within that domain.
+#$EMULATE_LOCAL_MAIL_USER="nongnu.org";
+
+# Set this to '-c' for context diffs; defaults to '-u' for unidiff format.
+$difftype = '-uN';
+
+############################################################
+#
+# Constants
+#
+############################################################
+$STATE_NONE = 0;
+$STATE_CHANGED = 1;
+$STATE_ADDED = 2;
+$STATE_REMOVED = 3;
+$STATE_LOG = 4;
+
+$TMPDIR = $ENV{'TMPDIR'} || '/tmp';
+$FILE_PREFIX = '#cvs.';
+
+$LAST_FILE = "$TMPDIR/${FILE_PREFIX}lastdir"; # Created by commit_prep!
+$ADDED_FILE = "$TMPDIR/${FILE_PREFIX}files.added";
+$REMOVED_FILE = "$TMPDIR/${FILE_PREFIX}files.removed";
+$LOG_FILE = "$TMPDIR/${FILE_PREFIX}files.log";
+$BRANCH_FILE = "$TMPDIR/${FILE_PREFIX}files.branch";
+$MLIST_FILE = "$TMPDIR/${FILE_PREFIX}files.mlist";
+$SUMMARY_FILE = "$TMPDIR/${FILE_PREFIX}files.summary";
+
+$CVSROOT = $ENV{'CVSROOT'};
+
+$MAIL_CMD = "| /usr/lib/sendmail -i -t";
+#$MAIL_CMD = "| /var/qmail/bin/qmail-inject";
+$MAIL_FROM = 'commitlogger'; #not needed if EMULATE_LOCAL_MAIL_USER
+$SUBJECT_PRE = 'CVS update:';
+
+
+############################################################
+#
+# Subroutines
+#
+############################################################
+
+sub format_names {
+ local($dir, @files) = @_;
+ local(@lines);
+
+ $lines[0] = sprintf(" %-08s", $dir);
+ foreach $file (@files) {
+ if (length($lines[$#lines]) + length($file) > 60) {
+ $lines[++$#lines] = sprintf(" %8s", " ");
+ }
+ $lines[$#lines] .= " ".$file;
+ }
+ @lines;
+}
+
+sub cleanup_tmpfiles {
+ local(@files);
+
+ opendir(DIR, $TMPDIR);
+ push(@files, grep(/^${FILE_PREFIX}.*\.${id}\.${cvs_user}$/, readdir(DIR)));
+ closedir(DIR);
+ foreach (@files) {
+ unlink "$TMPDIR/$_";
+ }
+}
+
+sub write_logfile {
+ local($filename, @lines) = @_;
+
+ open(FILE, ">$filename") || die ("Cannot open log file $filename: $!\n");
+ print(FILE join("\n", @lines), "\n");
+ close(FILE);
+}
+
+sub append_to_file {
+ local($filename, $dir, @files) = @_;
+
+ if (@files) {
+ local(@lines) = &format_names($dir, @files);
+ open(FILE, ">>$filename") || die ("Cannot open file $filename: $!\n");
+ print(FILE join("\n", @lines), "\n");
+ close(FILE);
+ }
+}
+
+sub write_line {
+ local($filename, $line) = @_;
+
+ open(FILE, ">$filename") || die("Cannot open file $filename: $!\n");
+ print(FILE $line, "\n");
+ close(FILE);
+}
+
+sub append_line {
+ local($filename, $line) = @_;
+
+ open(FILE, ">>$filename") || die("Cannot open file $filename: $!\n");
+ print(FILE $line, "\n");
+ close(FILE);
+}
+
+sub read_line {
+ local($filename) = @_;
+ local($line);
+
+ open(FILE, "<$filename") || die("Cannot open file $filename: $!\n");
+ $line = <FILE>;
+ close(FILE);
+ chomp($line);
+ $line;
+}
+
+sub read_line_nodie {
+ local($filename) = @_;
+ local($line);
+ open(FILE, "<$filename") || return ("");
+
+ $line = <FILE>;
+ close(FILE);
+ chomp($line);
+ $line;
+}
+
+sub read_file_lines {
+ local($filename) = @_;
+ local(@text) = ();
+
+ open(FILE, "<$filename") || return ();
+ while (<FILE>) {
+ chomp;
+ push(@text, $_);
+ }
+ close(FILE);
+ @text;
+}
+
+sub read_file {
+ local($filename, $leader) = @_;
+ local(@text) = ();
+
+ open(FILE, "<$filename") || return ();
+ while (<FILE>) {
+ chomp;
+ push(@text, sprintf(" %-10s %s", $leader, $_));
+ $leader = "";
+ }
+ close(FILE);
+ @text;
+}
+
+sub read_logfile {
+ local($filename, $leader) = @_;
+ local(@text) = ();
+
+ open(FILE, "<$filename") || die ("Cannot open log file $filename: $!\n");
+ while (<FILE>) {
+ chomp;
+ push(@text, $leader.$_);
+ }
+ close(FILE);
+ @text;
+}
+
+#
+# do an 'cvs -Qn status' on each file in the arguments, and extract info.
+#
+sub change_summary {
+ local($out, @filenames) = @_;
+ local(@revline);
+ local($file, $rev, $rcsfile, $line, $vhost, $cvsweb_base);
+
+ while (@filenames) {
+ $file = shift @filenames;
+
+ if ("$file" eq "") {
+ next;
+ }
+
+ open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'status', '--', $file;
+
+ $rev = "";
+ $delta = "";
+ $rcsfile = "";
+
+
+ while (<RCS>) {
+ if (/^[ \t]*Repository revision/) {
+ chomp;
+ @revline = split(' ', $_);
+ $rev = $revline[2];
+ $rcsfile = $revline[3];
+ $rcsfile =~ s,^$CVSROOT/,,;
+ $rcsfile =~ s/,v$//;
+ }
+ }
+ close(RCS);
+
+
+ if ($rev ne '' && $rcsfile ne '') {
+ open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'log', "-r$rev",
+ '--', $file;
+ while (<RCS>) {
+ if (/^date:.*lines:([^;]+);.*/) {
+ $delta = $1;
+ last;
+ }
+ }
+ close(RCS);
+ }
+
+ $diff = "\n\n";
+ $vhost = $path[0];
+ if ($CVSWEB_PORT eq "80") {
+ $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN/$CVSWEB_URI";
+ }
+ else {
+ $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN:$CVSWEB_PORT/$CVSWEB_URI";
+ }
+ if ($SEND_URL eq "true") {
+ $diff .= $cvsweb_base . join("/", @path) . "/$file";
+ }
+
+ #
+ # If this is a binary file, don't try to report a diff; not only is
+ # it meaningless, but it also screws up some mailers. We rely on
+ # Perl's 'is this binary' algorithm; it's pretty good. But not
+ # perfect.
+ #
+ if (($file =~ /\.(?:pdf|gif|jpg|mpg)$/i) || (-B $file)) {
+ if ($SEND_URL eq "true") {
+ $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n";
+ }
+ if ($SEND_DIFF eq "true") {
+ $diff .= "\t<<Binary file>>\n\n";
+ }
+ }
+ else {
+ #
+ # Get the differences between this and the previous revision,
+ # being aware that new files always have revision '1.1' and
+ # new branches always end in '.n.1'.
+ #
+ if ($rev =~ /^(.*)\.([0-9]+)$/) {
+ $prev = $2 - 1;
+ $prev_rev = $1 . '.' . $prev;
+
+ $prev_rev =~ s/\.[0-9]+\.0$//;# Truncate if first rev on branch
+
+ if ($rev eq '1.1') {
+ if ($SEND_URL eq "true") {
+ $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n";
+ }
+ if ($SEND_DIFF eq "true") {
+ open(DIFF, "-|")
+ || exec "$cvsbin/cvs", '-Qn', 'update', '-p', '-r1.1',
+ '--', $file;
+ $diff .= "Index: $file\n=================================="
+ . "=================================\n";
+ }
+ }
+ else {
+ if ($SEND_URL eq "true") {
+ $diff .= ".diff?r1=$prev_rev&r2=$rev\n\n";
+ }
+ if ($SEND_DIFF eq "true") {
+ $diff .= "(In the diff below, changes in quantity "
+ . "of whitespace are not shown.)\n\n";
+ open(DIFF, "-|")
+ || exec "$cvsbin/cvs", '-Qn', 'diff', "$difftype",
+ '-b', "-r$prev_rev", "-r$rev", '--', $file;
+ }
+ }
+
+ if ($SEND_DIFF eq "true") {
+ while (<DIFF>) {
+ $diff .= $_;
+ }
+ close(DIFF);
+ }
+ $diff .= "\n\n";
+ }
+ }
+
+ &append_line($out, sprintf("%-9s%-12s%s%s", $rev, $delta,
+ $rcsfile, $diff));
+ }
+}
+
+
+sub build_header {
+ local($header);
+ delete $ENV{'TZ'};
+ local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
+
+ $header = sprintf(" User: %-8s\n Date: %02d/%02d/%02d %02d:%02d:%02d",
+ $cvs_user, $year%100, $mon+1, $mday,
+ $hour, $min, $sec);
+# $header = sprintf("%-8s %02d/%02d/%02d %02d:%02d:%02d",
+# $login, $year%100, $mon+1, $mday,
+# $hour, $min, $sec);
+}
+
+# !!! Destination Mailing-list and history file mappings here !!!
+
+#sub mlist_map
+#{
+# local($path) = @_;
+# my $domain = "nongnu.org";
+#
+# if ($path =~ /^([^\/]+)/) {
+# return "cvs\@$1.$domain";
+# } else {
+# return "cvs\@$domain";
+# }
+#}
+
+sub derive_subject_from_changes_file ()
+{
+ my $subj = "";
+
+ for ($i = 0; ; $i++)
+ {
+ open (CH, "<$CHANGED_FILE.$i.$id.$cvs_user") or last;
+
+ while (my $change = <CH>)
+ {
+ # A changes file looks like this:
+ #
+ # src foo.c newfile.html
+ # www index.html project_nav.html
+ #
+ # Each line is " Dir File1 File2 ..."
+ # We only care about Dir, since the subject line should
+ # summarize.
+
+ $change =~ s/^[ \t]*//;
+ $change =~ /^([^ \t]+)[ \t]*/;
+ my $dir = $1;
+ # Fold to rightmost directory component
+ $dir =~ /([^\/]+)$/;
+ $dir = $1;
+ if ($subj eq "") {
+ $subj = $dir;
+ } else {
+ $subj .= ", $dir";
+ }
+ }
+ close (CH);
+ }
+
+ if ($subj ne "") {
+ $subj = "MODIFIED: $subj ...";
+ }
+ else {
+ # NPM: See if there's any file-addition notifications.
+ my $added = &read_line_nodie("$ADDED_FILE.$i.$id.$cvs_user");
+ if ($added ne "") {
+ $subj .= "ADDED: $added ";
+ }
+
+# print "derive_subject_from_changes_file().. added== $added \n";
+
+ ## NPM: See if there's any file-removal notications.
+ my $removed = &read_line_nodie("$REMOVED_FILE.$i.$id.$cvs_user");
+ if ($removed ne "") {
+ $subj .= "REMOVED: $removed ";
+ }
+
+# print "derive_subject_from_changes_file().. removed== $removed \n";
+
+ ## NPM: See if there's any branch notifications.
+ my $branched = &read_line_nodie("$BRANCH_FILE.$i.$id.$cvs_user");
+ if ($branched ne "") {
+ $subj .= "BRANCHED: $branched";
+ }
+
+# print "derive_subject_from_changes_file().. branched== $branched \n";
+
+ ## NPM: DEFAULT: DIRECTORY CREATION (c.f. "Check for a new directory first" in main mody)
+ if ($subj eq "") {
+ my $subject = join("/", @path);
+ $subj = "NEW: $subject";
+ }
+ }
+
+ return $subj;
+}
+
+sub mail_notification
+{
+ local($addr_list, @text) = @_;
+ local($mail_to);
+
+ my $subj = &derive_subject_from_changes_file ();
+
+ if ($EMULATE_LOCAL_MAIL_USER ne "") {
+ $MAIL_FROM = "$cvs_user\@$EMULATE_LOCAL_MAIL_USER";
+ }
+
+ $mail_to = join(", ", @{$addr_list});
+
+ print "Mailing the commit message to $mail_to (from $MAIL_FROM)\n";
+
+ $ENV{'MAILUSER'} = $MAIL_FROM;
+ # Commented out on hocus, so comment it out here. -kff
+ # $ENV{'QMAILINJECT'} = 'f';
+
+ open(MAIL, "$MAIL_CMD -f$MAIL_FROM");
+ print MAIL "From: $MAIL_FROM\n";
+ print MAIL "To: $mail_to\n";
+ print MAIL "Subject: $SUBJECT_PRE $subj\n\n";
+ print(MAIL join("\n", @text));
+ close(MAIL);
+# print "Mailing the commit message to $MAIL_TO...\n";
+#
+# #added by jrobbins@collab.net 1999/12/15
+# # attempt to get rid of anonymous
+# $ENV{'MAILUSER'} = 'commitlogger';
+# $ENV{'QMAILINJECT'} = 'f';
+#
+# open(MAIL, "| /var/qmail/bin/qmail-inject");
+# print(MAIL "To: $MAIL_TO\n");
+# print(MAIL "Subject: cvs commit: $ARGV[0]\n");
+# print(MAIL join("\n", @text));
+# close(MAIL);
+}
+
+## process the command line arguments sent to this script
+## it returns an array of files, %s, sent from the loginfo
+## command
+sub process_argv
+{
+ local(@argv) = @_;
+ local(@files);
+ local($arg);
+ print "Processing log script arguments...\n";
+
+ if ($UseNewInfoFmtStrings) {
+ while (@argv) {
+ $arg = shift @argv;
+
+ if ($arg eq '-u' && !defined($cvs_user)) {
+ $cvs_user = shift @argv;
+ }
+ if ($arg eq '- New directory') {
+ $new_directory = 1;
+ } elsif ($arg eq '- Imported sources') {
+ $imported_sources = 1;
+ } else {
+ push(@files, $arg);
+ }
+ }
+ } else {
+ while (@argv) {
+ $arg = shift @argv;
+
+ if ($arg eq '-u') {
+ $cvs_user = shift @argv;
+ } else {
+ ($donefiles) && die "Too many arguments!\n";
+ $donefiles = 1;
+ $ARGV[0] = $arg;
+ if ($arg =~ s/ - New directory//) {
+ $new_directory = 1;
+ } elsif ($arg =~ s/ - Imported sources//) {
+ $imported_sources = 1;
+ }
+ @files = split(' ', $arg);
+ }
+ }
+ }
+ return @files;
+}
+
+
+#############################################################
+#
+# Main Body
+#
+############################################################
+#
+# Setup environment
+#
+umask (002);
+
+# Connect to the database
+$cvsbin = "/usr/bin";
+
+#
+# Initialize basic variables
+#
+$id = getpgrp();
+$state = $STATE_NONE;
+$cvs_user = $ENV{'USER'} || getlogin || (getpwuid($<))[0] || sprintf("uid#%d",$<);
+$new_directory = 0; # Is this a 'cvs add directory' command?
+$imported_sources = 0; # Is this a 'cvs import' command?
+@files = process_argv(@ARGV);
+@path = split('/', $files[0]);
+if ($#path == 0) {
+ $dir = ".";
+} else {
+ $dir = join('/', @path[1..$#path]);
+}
+#print("ARGV - ", join(":", @ARGV), "\n");
+#print("files - ", join(":", @files), "\n");
+#print("path - ", join(":", @path), "\n");
+#print("dir - ", $dir, "\n");
+#print("id - ", $id, "\n");
+
+#
+# Map the repository directory to an email address for commitlogs to be sent
+# to.
+#
+#$mlist = &mlist_map($files[0]);
+
+##########################
+#
+# Check for a new directory first. This will always appear as a
+# single item in the argument list, and an empty log message.
+#
+if ($new_directory) {
+ $header = &build_header;
+ @text = ();
+ push(@text, $header);
+ push(@text, "");
+ push(@text, " ".$files[0]." - New directory");
+ &mail_notification([ $mlist ], @text);
+ exit 0;
+}
+
+#
+# Iterate over the body of the message collecting information.
+#
+while (<STDIN>) {
+ chomp; # Drop the newline
+ if (/^Revision\/Branch:/) {
+ s,^Revision/Branch:,,;
+ push (@branch_lines, split);
+ next;
+ }
+# next if (/^[ \t]+Tag:/ && $state != $STATE_LOG);
+ if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
+ if (/^Added Files/) { $state = $STATE_ADDED; next; }
+ if (/^Removed Files/) { $state = $STATE_REMOVED; next; }
+ if (/^Log Message/) { $state = $STATE_LOG; last; }
+ s/[ \t\n]+$//; # delete trailing space
+
+ push (@changed_files, split) if ($state == $STATE_CHANGED);
+ push (@added_files, split) if ($state == $STATE_ADDED);
+ push (@removed_files, split) if ($state == $STATE_REMOVED);
+}
+# Proces the /Log Message/ section now, if it exists.
+# Do this here rather than above to deal with Log messages
+# that include lines that confuse the state machine.
+if (!eof(STDIN)) {
+ while (<STDIN>) {
+ next unless ($state == $STATE_LOG); # eat all STDIN
+
+ if ($state == $STATE_LOG) {
+ if (/^PR:$/i ||
+ /^Reviewed by:$/i ||
+ /^Submitted by:$/i ||
+ /^Obtained from:$/i) {
+ next;
+ }
+ push (@log_lines, $_);
+ }
+ }
+}
+
+#
+# Strip leading and trailing blank lines from the log message. Also
+# compress multiple blank lines in the body of the message down to a
+# single blank line.
+# (Note, this only does the mail and changes log, not the rcs log).
+#
+while ($#log_lines > -1) {
+ last if ($log_lines[0] ne "");
+ shift(@log_lines);
+}
+while ($#log_lines > -1) {
+ last if ($log_lines[$#log_lines] ne "");
+ pop(@log_lines);
+}
+for ($i = $#log_lines; $i > 0; $i--) {
+ if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
+ splice(@log_lines, $i, 1);
+ }
+}
+
+#
+# Find the log file that matches this log message
+#
+for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id.$cvs_user");
+ @text = &read_logfile("$LOG_FILE.$i.$id.$cvs_user", "");
+ last if ($#text == -1);
+ last if (join(" ", @log_lines) eq join(" ", @text));
+}
+
+#
+# Spit out the information gathered in this pass.
+#
+&write_logfile("$LOG_FILE.$i.$id.$cvs_user", @log_lines);
+&append_to_file("$BRANCH_FILE.$i.$id.$cvs_user", $dir, @branch_lines);
+&append_to_file("$ADDED_FILE.$i.$id.$cvs_user", $dir, @added_files);
+&append_to_file("$CHANGED_FILE.$i.$id.$cvs_user", $dir, @changed_files);
+&append_to_file("$REMOVED_FILE.$i.$id.$cvs_user", $dir, @removed_files);
+&append_line("$MLIST_FILE.$i.$id.$cvs_user", $mlist);
+if ($rcsidinfo) {
+ &change_summary("$SUMMARY_FILE.$i.$id.$cvs_user", (@changed_files, @added_files));
+}
+
+#
+# Check whether this is the last directory. If not, quit.
+#
+if (-e "$LAST_FILE.$id.$cvs_user") {
+ $_ = &read_line("$LAST_FILE.$id.$cvs_user");
+ $tmpfiles = $files[0];
+ $tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g;
+ if (! grep(/$tmpfiles$/, $_)) {
+ print "More commits to come...\n";
+ exit 0
+ }
+}
+
+#
+# This is it. The commits are all finished. Lump everything together
+# into a single message, fire a copy off to the mailing list, and drop
+# it on the end of the Changes file.
+#
+$header = &build_header;
+
+#
+# Produce the final compilation of the log messages
+#
+@text = ();
+@mlist_list = ();
+push(@text, $header);
+push(@text, "");
+for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id.$cvs_user");
+ push(@text, &read_file("$BRANCH_FILE.$i.$id.$cvs_user", "Branch:"));
+ push(@text, &read_file("$CHANGED_FILE.$i.$id.$cvs_user", "Modified:"));
+ push(@text, &read_file("$ADDED_FILE.$i.$id.$cvs_user", "Added:"));
+ push(@text, &read_file("$REMOVED_FILE.$i.$id.$cvs_user", "Removed:"));
+ push(@text, " Log:");
+ push(@text, &read_logfile("$LOG_FILE.$i.$id.$cvs_user", " "));
+ push(@mlist_list, &read_file_lines("$MLIST_FILE.$i.$id.$cvs_user"));
+ if ($rcsidinfo == 2) {
+ if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") {
+ push(@text, " ");
+ push(@text, " Revision Changes Path");
+ push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", " "));
+ }
+ }
+ push(@text, "");
+}
+
+#
+# Now generate the extra info for the mail message..
+#
+if ($rcsidinfo == 1) {
+ $revhdr = 0;
+ for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id.$cvs_user");
+ if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") {
+ if (!$revhdr++) {
+ push(@text, "Revision Changes Path");
+ }
+ push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", ""));
+ }
+ }
+ if ($revhdr) {
+ push(@text, ""); # consistancy...
+ }
+}
+
+%mlist_hash = ();
+
+foreach (@mlist_list) { $mlist_hash{ $_ } = 1; }
+
+#
+# Mail out the notification.
+#
+&mail_notification([ keys(%mlist_hash) ], @text);
+&cleanup_tmpfiles;
+exit 0;
diff --git a/contrib/mfpipe.in b/contrib/mfpipe.in
new file mode 100755
index 0000000..0461a0c
--- /dev/null
+++ b/contrib/mfpipe.in
@@ -0,0 +1,115 @@
+#! @PERL@ -T
+# -*-Perl-*-
+
+# Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+###############################################################################
+###############################################################################
+###############################################################################
+#
+# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE
+# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE
+# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
+# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
+# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
+# <@PACKAGE_BUGREPORT@> MAILING LIST.
+#
+# For more on general Perl security and taint-checking, please try running the
+# `perldoc perlsec' command.
+#
+###############################################################################
+###############################################################################
+###############################################################################
+
+# From: clyne@niwot.scd.ucar.EDU (John Clyne)
+# Date: Fri, 28 Feb 92 09:54:21 MST
+#
+# BTW, i wrote a perl script that is similar to 'nfpipe' except that in
+# addition to logging to a file it provides a command line option for mailing
+# change notices to a group of users. Obviously you probably wouldn't want
+# to mail every change. But there may be certain directories that are commonly
+# accessed by a group of users who would benefit from an email notice.
+# Especially if they regularly beat on the same directory. Anyway if you
+# think anyone would be interested here it is.
+#
+# File: mfpipe
+#
+# Author: John Clyne
+# National Center for Atmospheric Research
+# PO 3000, Boulder, Colorado
+#
+# Date: Wed Feb 26 18:34:53 MST 1992
+#
+# Description: Tee standard input to mail a list of users and to
+# a file. Used by CVS logging.
+#
+# Usage: mfpipe [-f file] [user@host...]
+#
+# Environment: CVSROOT
+# Path to CVS root.
+#
+# Files:
+#
+#
+# Options: -f file
+# Capture output to 'file'
+#
+
+$header = "Log Message:\n";
+
+$mailcmd = "| mail -s 'CVS update notice'";
+$whoami = `whoami`;
+chop $whoami;
+$date = `date`;
+chop $date;
+
+$cvsroot = $ENV{'CVSROOT'};
+
+while (@ARGV) {
+ $arg = shift @ARGV;
+
+ if ($arg eq '-f') {
+ $file = shift @ARGV;
+ }
+ else {
+ $users = "$users $arg";
+ }
+}
+
+if ($users) {
+ $mailcmd = "$mailcmd $users";
+ open(MAIL, $mailcmd) || die "Execing $mail: $!\n";
+}
+
+if ($file) {
+ $logfile = "$cvsroot/LOG/$file";
+ open(FILE, ">> $logfile") || die "Opening $logfile: $!\n";
+}
+
+print FILE "$whoami $date--------BEGIN LOG ENTRY-------------\n" if ($logfile);
+
+while (<>) {
+ print FILE $log if ($log && $logfile);
+
+ print FILE $_ if ($logfile);
+ print MAIL $_ if ($users);
+
+ $log = "log: " if ($_ eq $header);
+}
+
+close FILE;
+die "Write failed" if $?;
+close MAIL;
+die "Mail failed" if $?;
+
+exit 0;
diff --git a/contrib/newcvsroot.sh b/contrib/newcvsroot.sh
new file mode 100755
index 0000000..ab67187
--- /dev/null
+++ b/contrib/newcvsroot.sh
@@ -0,0 +1,47 @@
+#! /bin/sh
+#
+# Copyright 2002 Derek R. Price & Ximbiot <http://ximbiot.com>.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+# ///// ///// ///// ///// ///// ***** \\\\\ \\\\\ \\\\\ \\\\\ \\\\\
+#
+# newcvsroot.sh
+#
+# Recursively change the CVSROOT for a sandbox.
+#
+# INPUTS
+# $1 The new CVSROOT
+# $2+ The list of sandbox directories to convert.
+# Defaults to the current directory.
+
+usage ()
+{
+ echo "$0: usage: $prog newcvsroot [startdir]" >&2
+}
+
+prog=`basename "$0"`
+
+if test "${1+set}" != set; then
+ usage
+ exit 2
+else :; fi
+
+echo "$1" >/tmp/$prog$$
+shift
+
+for dir in `find "${@:-.}" -name CVS`; do
+ cp /tmp/$prog$$ "$dir"/Root
+done
+
+rm /tmp/$prog$$
diff --git a/contrib/pam/.cvsignore b/contrib/pam/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/contrib/pam/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/contrib/pam/ChangeLog b/contrib/pam/ChangeLog
new file mode 100644
index 0000000..0a24e24
--- /dev/null
+++ b/contrib/pam/ChangeLog
@@ -0,0 +1,27 @@
+2005-03-22 Brian Murphy <brian@murphy.dk>
+
+ * cvs.linux, cvs.solaris: updated to add session support example.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add .cvsignore.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-07-16 Derek Price <derek@ximbiot.com>
+
+ Distribute demo PAM configs.
+ * Makefile.am, Makefile.in: New files.
+ * .cvsignore: New file.
+ (Thanks to a report from Brian Murphy.)
+
+2003-07-20 Derek Price <derek@ximbiot.com>
+
+ * cvs.linux: New file.
+ * cvs.solaris: Ditto.
diff --git a/contrib/pam/Makefile.am b/contrib/pam/Makefile.am
new file mode 100644
index 0000000..e23e913
--- /dev/null
+++ b/contrib/pam/Makefile.am
@@ -0,0 +1,22 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for GNU CVS contributed sample Pluggable Authentication Manager
+# (PAM) configurations.
+#
+# Do not use this makefile directly, but only from `../Makefile'.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+EXTRA_DIST = \
+ .cvsignore \
+ cvs.linux \
+ cvs.solaris
diff --git a/contrib/pam/Makefile.in b/contrib/pam/Makefile.in
new file mode 100644
index 0000000..93a6348
--- /dev/null
+++ b/contrib/pam/Makefile.in
@@ -0,0 +1,422 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for GNU CVS contributed sample Pluggable Authentication Manager
+# (PAM) configurations.
+#
+# Do not use this makefile directly, but only from `../Makefile'.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = contrib/pam
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+EXTRA_DIST = \
+ .cvsignore \
+ cvs.linux \
+ cvs.solaris
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/pam/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu contrib/pam/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/pam/cvs.linux b/contrib/pam/cvs.linux
new file mode 100644
index 0000000..73f0e79
--- /dev/null
+++ b/contrib/pam/cvs.linux
@@ -0,0 +1,9 @@
+# This is a sample PAM configuration for Linux
+# which does standard unix authentication against
+# the password in /etc/passwd or /etc/shadow.
+# The contents of this file should be copied to
+# /etc/pam.d/cvs
+
+auth required pam_unix.so
+account required pam_unix.so
+session required pam_unix.so
diff --git a/contrib/pam/cvs.solaris b/contrib/pam/cvs.solaris
new file mode 100644
index 0000000..5d17bc2
--- /dev/null
+++ b/contrib/pam/cvs.solaris
@@ -0,0 +1,9 @@
+# This is a sample PAM configuration for Sun/Solaris
+# which does standard unix authentication against
+# the password in /etc/passwd or /etc/shadow.
+# The contents of this file should be inserted
+# at an appropriate position in /etc/pam.conf
+
+cvs auth required /usr/lib/security/$ISA/pam_unix.so.1
+cvs account required /usr/lib/security/$ISA/pam_unix.so.1
+cvs session required /usr/lib/security/$ISA/pam_unix.so.1
diff --git a/contrib/pvcs2rcs.in b/contrib/pvcs2rcs.in
new file mode 100644
index 0000000..ac36ddc
--- /dev/null
+++ b/contrib/pvcs2rcs.in
@@ -0,0 +1,1314 @@
+#! @PERL@
+# ---------------------------------
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+###########################################################################
+# FUNCTION:
+# To recursively walk through a PVCS archive directory tree (archives
+# located in VCS/ or vcs/ subdirectories) and convert them to RCS archives.
+# The RCS archive name is the PVCS workfile name with ",v" appended.
+#
+# SYNTAX:
+# pvcs_to_rcs.pl --help
+#
+# where -l indicates the operation is to be performed only in the current
+# directory (no recursion)
+#
+# EXAMPLE:
+# pvcs_to_rcs
+# Would walk through every VCS or vcs subdir starting at the current directory,
+# and produce corresponding RCS archives one level above the VCS or vcs subdir.
+# (VCS/../RCS/)
+#
+# NOTES:
+# * This script performs little error checking and logging
+# (i.e. USE AT YOUR OWN RISK)
+# * This script was last tested using ActiveState's port of Perl 5.005_02
+# (internalcut #507) under Win95, though it does compile under Perl-5.00404
+# for Solaris 2.4 run on a Solaris 2.6 system. The script crashed
+# occasionally under ActiveState's port of Perl 5.003_07 but this stopped
+# happening with the update so if you are having problems, try updating Perl.
+# Upgrading to cut #507 also seemed to coincide with a large speed
+# improvement, so try and keep up, hey? :) It was executed from MKS's
+# UNIX tools version 6.1 for Win32's sh. ALWAYS redirect your output to
+# a log!!!
+# * PVCS archives are left intact
+# * RCS archives are created in VCS/../RCS/ (or ./RCS using '-pflat')
+# * Branch labels in this script will be attached to the CVS magic
+# revision number. For branch a.b.c of a particular file, this means
+# the label will be attached to revision a.b.0.c of the converted
+# file. If you use the TrunkTip (1.*) label, be aware that it will convert
+# to RCS revision 0.1, which is useless to RCS and CVS. You'll probably
+# have to delete these.
+# * All revisions are saved with correct "metadata" (i.e. check-in date,
+# author, and log message). Any blank log message is replaced with
+# "no comment". This is because RCS does not allow non-interactive
+# check in of a new revision without a comment string.
+# * Revision numbers are incremented by 1 during the conversion (since
+# RCS does not allow revision 1.0).
+# * All converted branch numbers are even (the CVS paradigm)
+# * Version labels are assigned to the appropriate (incremented) revision
+# numbers. PVCS allows spaces and periods in version labels while RCS
+# does not. A global search and replace converts " " and "." to "_"
+# There may be other cases that ought to be added.
+# * Any working (checked-out) copies of PVCS archives
+# within the VCS/../ or vcs/../ (or possibly ./ with '-pflat')
+# will be deleted (or overwritten) depending on your mode of
+# operation since the current ./ is used in the checkout of each revision.
+# I suppose if development continues these files could be redirected to
+# temp space rather than ./ .
+# * Locks on PVCS archives should be removed (or the workfiles should be
+# checked-in) prior to conversion, although the script will blaze through
+# the archive nonetheless (But you would lose any checked out revision(s))
+# * The -kb option is added to the RCS archive for workfiles with the following
+# extensions: .bin .out .btl .rom .a07 .lib .exe .tco .obj .t8u .c8u .o .lku
+# .a and a few others. The %bin_ext variable holds these values in regexp
+# form.
+# * the --force-binary option can be used to convert binary files which don't
+# have proper extensions, but I'd *probably* edit the %bin_ext variable.
+# * This script will abort occasionally with the error "invalid revision
+# number". This is known to happen when a revision comment has
+# /^\s*Rev/ (Perl regexp notation) in it. Fix the comment and start over.
+# (The directory locks and existance checking make this a fairly quick
+# process.)
+# Binary files which do not have their mode set properly are likely to look
+# corrupted on initial checkout and use, but using
+# `cvs admin -kb <workfilename>' to retroactively change the RCS keyword
+# substitution mode of the file to binary (and refreshing the files in any
+# local workspaces they are checked out in: `rm <workfilename>; update'
+# should do the trick) should end any problems with the original import.
+# If anyone has checked in changes since the import, those revisions may
+# be corrupted in the imported archive and therefore those changes (commits
+# of corrupted data) may need to be backed out.
+# * This script writes lockfiles in the RCS/ directories. It will also not
+# convert an archive if it finds the RCS Archive existant in the RCS/
+# directory. This enables the conversion to quickly pick up where it left
+# off after errors or interrupts occur. If you interrupt the script make
+# sure you delete the last RCS Archive File which was being written.
+# If you recieve the "Invalid revision number" error, then the RCS archive
+# file for that particular PVCS file will not have been created yet.
+# * This script will not create lockfiles when processing single
+# filenames passed into the script, for hopefully obvious reasons.
+# (lockfiles lock directories - DRP)
+# * Log the output to a file. That makes it real easy to grep for errors
+# later. (grep for "^[ \t]*(rcs|ci):" and be aware I might have missed
+# a few cases (get? vcs?) !!!) *** Also note that this script will
+# exibit some harmless RCS errors. Namely, it will attempt to lock
+# branches which haven't been created yet. ***
+# * I tried to keep the error and warning info up to date, but it seems
+# to mean very little. This script almost always exits with a warning
+# or an error that didn't seem to cause any harm. I didn't trace it
+# and our imported source checks out and builds...
+# It is probably happening when trying to convert empty directories
+# or read files (possibly checked out workfiles ) which are not
+# pvcs_archives.
+# * You must use the -pflat option when processing single filenames
+# passed as arguments to the script. This is probably a bug.
+# * questions, comments, additions can be sent to info-cvs@nongnu.org
+#########################################################################
+
+
+
+#
+# USER Configurables
+#
+
+# %bin_ext should be editable from the command line.
+#
+# NOTE: Each possible binary extension is listed as a Perl regexp
+#
+# The value associated with each regexp key is used to print a log
+# message when a binary file is found.
+my %bin_ext =
+ (
+ '\.(?i)abs$' => "Absolute File",
+ '\.(?i)bin$' => "Binary",
+ '\.(?i)bit$' => "Bit File",
+ '\.(?i)ol$' => "Compiler Output",
+ '\.(?i)out$' => "Default Compiler Output",
+ '\.(?i)ln$' => "Linker Output",
+ '\.(?i)lob$' => "Lint Output",
+ '\.(?i)zob$' => "DBCO Object",
+ '\.(?i)mim$' => "MIME File",
+ '\.(?i)dwi$' => "DWI File",
+ '\.(?i)iop$' => "IOP File",
+ '\.(?i)btl$' => "",
+ '\.(?i)rom$' => "ROM File",
+ '\.(?i)a07$' => "",
+ '\.(?i)lib$' => "DOS/Wintel/Netware Compiler Library",
+ '\.(?i)lif$' => "Netware Binary File",
+ '\.(?i)(com|exe)$' => "DOS/Wintel Executable",
+ '\.(?i)tco$' => "",
+ '\.(?i)obj$' => "DOS/Wintel Compiler Object",
+ '\.(?i)res$' => "DOS/Wintel Resource File",
+ '\.(?i)ico$' => "DOS/Wintel Icon File",
+ '\.(?i)nlm$' => "Netware Loadable Module",
+ '\.(?i)t8u$' => "",
+ '\.(?i)c8u$' => "",
+ '\.(?i)lku$' => "",
+ '\.(?i)pdf$' => "Adobe Acrobat Portable Document Format",
+ '\.(?i)doc$' => "MS Word Document",
+ '\.(?i)dot$' => "MS Word Document Template",
+ '\.(?i)pps$' => "MS PowerPoint Presentation",
+ '\.(?i)xls$' => "MS Excel Spreadsheet",
+ '\.(?i)(bmp|gif|jfif|jpeg|jpg|png|tif|tiff|xbm)$' => "Image",
+ '\.(?i)(bz2|gz|tgz|zip)$' => "Compressed File",
+ '\.(?i)dll$' => "DOS/Wintel Dynamically Linked Library",
+ '\.(?i)class$' => "Compliled Java Class File",
+ '\.(?i)jar$' => "Java Archive File",
+ '\.(?i)war$' => "Java Web Archive File",
+ '\.o$' => "UNIX Compiler Object",
+ '\.a$' => "UNIX Compiler Library",
+ '\.so(\.\d+\.\d+)?$' => "UNIX Shared Library"
+ );
+
+# The binaries this script is dependant on:
+my @bin_dependancies = ("vcs", "vlog", "rcs", "ci");
+
+# Where we should put temporary files
+my $tmpdir = $ENV{TMPDIR} ? $ENV{TMPDIR} : "/var/tmp";
+
+# We use these...
+use strict;
+
+use Cwd;
+use File::Basename; # For the usage message.
+use File::Copy;
+use File::Path;
+use IO::File;
+use Getopt::Long;
+ $Getopt::Long::bundling = 1;
+
+my $program = basename $0;
+my $usage = "\
+usage: $program -h
+ $program [-lt] [-i vcsid] [-r flat|leaf] [-p flat|leaf]
+ [-x rcs_extension] [-v none|locks|exists] [options] [path...]
+";
+
+my $help = "\
+$usage
+ ---------------------------- -----------------------------------
+ -h | --Help Print this text
+
+ General Settings
+ ---------------------------- -----------------------------------
+ --Recurse Recurse through directories
+ (default)
+ -l | --NORecurse Process only .
+ --Errorfiles Save a count of conversion errors
+ in the RCS archive directory
+ (default) (unimplemented)
+ --NOErrorfiles Don't save a count of conversion
+ errors (unimplemented)
+ ( -m | --Mode ) Convert Convert PVCS files to RCS files
+ (default)
+ ( -m | --Mode ) Verify Perform verification ONLY
+ (unimplemented)
+ ( -v | --VERIfy ) None Always replace existing RCS files
+ ( -v | --VERIfy ) LOCKS Same as exists unless a #conv.done
+ file exists in the RCS directory.
+ In that case, only the #conv.done
+ file's existance is verified for
+ that directory. (default)
+ ( -v | --VERIfy ) Exists Don't replace existing RCS files
+ ( -v | --VERIfy ) LOCKDates Verify that an existing RCS file's
+ last modification date is older
+ than that of the lockfile
+ (unimplemented)
+ ( -v | --VERIfy ) Revs Verify that the PVCS archive files
+ and RCS archive file contain the
+ same number of corresponding
+ revisions. Add only new revisions
+ to the RCS file. (unimplemented)
+ ( -v | --VERIfy ) Full Perform --verify=Revs and confirm
+ that the text of the revisions is
+ identical. Add only new revisions
+ unless an error is found. Then
+ erase the RCS archive and recreate
+ it. (unimplemented)
+ -t | --Test-binaries Use 'which' to check \$PATH for
+ the binaries required by this
+ script (default)
+ --NOTest-binaries Don't check for binaries
+ --VERBose Enable verbose output
+ --NOVerbose Disable verbose output (default)
+ -w | --Warnings Print warning messages (default)
+ --NOWarnings Don't print warning messages
+
+ RCS Settings
+ ---------------------------- -----------------------------------
+ ( -r | --RCS-Dirs ) leaf RCS files stored in ./RCS (default)
+ ( -r | --RCS-Dirs ) flat RCS files stored in .
+ (unimplemented)
+ ( -x | --RCS-Extension ) Set RCS file extension
+ (default = ',v')
+ --Force-binary Pass '-kb' to 'rcs -i' regardless
+ of the file extension
+ --NOForce-binary Only use '-kb' when the file has
+ a binary extension (default)
+ --CVS-Branch-labels Use CVS magic branch revision
+ numbers when attaching branch
+ labels (default)
+ --NOCvs-branch-labels Attach branch labels to RCS branch
+ revision numbers (unimplemented)
+
+ CVS Settings
+ ---------------------------- -----------------------------------
+ ( -d | --CVS-Module-path) Import RCS files directly into this
+ destination directory rather than
+ converting in place
+
+ PVCS Settings
+ ---------------------------- -----------------------------------
+ ( -p | --Pvcs-dirs ) leaf PVCS files expected in ./VCS
+ (default)
+ ( -p | --Pvcs-dirs ) flat PVCS files expected in .
+ ( -i | --VCsid ) vcsid Use vcsid instead of \$VCSID
+
+ --------------------------------------------------------------------------
+ The optional path argument should contain the name of a file or directory
+ to convert. If not given, it will default to '.'.
+ --------------------------------------------------------------------------
+";
+
+
+
+#
+# Initialize globals
+#
+
+my ($errors, $warnings) = (0, 0);
+my ($curlevel, $maxlevel);
+my ($rcs_base_command, $ci_base_command);
+my ($donefile_name, $errorfile_name);
+my @rel_dirs = (); # list of relative directory names up to current dir
+
+
+# set up the default options
+my %options = (
+ 'recurse' => 1,
+ 'mode' => "convert",
+ 'errorfiles' => 1,
+ 'rcs-dirs' => "leaf",
+ 'rcs-extension' => ",v",
+ 'force-binary' => 0,
+ 'cvs-branch-labels' => 1,
+ 'cvs-module-path' => undef,
+ 'pvcs-dirs' => "leaf",
+ 'verify' => "locks",
+ 'test-binaries' => 1,
+ 'vcsid' => $ENV{VCSID} || "",
+ 'verbose' => 0,
+ 'debug' => 0,
+ 'warnings' => 1
+ );
+
+
+
+# This is untested except under Solaris 2.4 or 2.6 and
+# may not be portable
+#
+# I think the readline lib or some such has an interface
+# which may enable this now. The perl installer sure looks
+# like it's testing this kind of thing, anyhow.
+sub hit_any_key
+ {
+ STDOUT->autoflush;
+ system "stty", "-icanon", "min", "1";
+
+ print "Hit any key to continue...";
+ getc;
+
+ system "stty", "icanon", "min", "0";
+ STDOUT->autoflush (0);
+
+ print "\nI always wondered where that key was...\n";
+ }
+
+
+
+# print the usage
+sub print_usage
+ {
+ my $fh = shift;
+ unless (ref $fh)
+ {
+ my $fdn = $fh ? $fh : "STDERR";
+ $fh = new IO::File;
+ $fh->fdopen ($fdn, "w");
+ }
+
+ $fh->print ($usage);
+ }
+
+# print the help
+sub print_help
+ {
+ my $fh = shift;
+ unless (ref $fh)
+ {
+ my $fdn = $fh ? $fh : "STDOUT";
+ $fh = new IO::File;
+ $fh->fdopen ($fdn, "w");
+ }
+
+ $fh->print ($help);
+ }
+
+# print the help and exit $_[0] || 0
+sub exit_help
+ {
+ print_help;
+ exit shift || 0;
+ }
+
+sub error_count
+ {
+ my $type = shift
+ or die "$0: error - error_count usage: error_count type [, ref] [, LIST]\n";
+ my $error_count_ref;
+ my $outstring;
+
+ if (ref ($_[0]) && ref ($_[0]) == "SCALAR")
+ {
+ $error_count_ref = shift;
+ }
+ else
+ {
+ $error_count_ref = \$errors;
+ }
+ $$error_count_ref++;
+
+ push @_, "something wrong.\n" unless ( @_ > 0 );
+
+ $outstring = sprintf "$0: $type - " . join ("", @_);
+ $outstring .= sprintf " - $!\n" unless ($outstring =~ /\n$/);
+
+ print STDERR $outstring;
+
+ if ($options{errorfiles})
+ {
+ my $fh = new IO::File ">>$errorfile_name" or new IO::File ">$errorfile_name";
+ if ($fh)
+ {
+ $fh->print ($$error_count_ref . "\n");
+ $fh->print ($outstring);
+ $fh->close;
+ }
+ else
+ {
+ my $cd = cwd;
+ print STDERR "$0: error - failed to open errorfile $cd/$errorfile_name - $!\n"
+ if ($options{debug});
+ }
+ }
+
+ return $$error_count_ref;
+ }
+
+
+
+# the main procedure that is run once in each directory
+sub execdir
+ {
+ my $dir = shift;
+ my ($errors, $warnings) = (0, 0); # We return these error counters
+ my $old_dir = cwd;
+
+ local ($_, @_);
+
+ my $i; # Generic counter
+ my ($pvcsarchive, $workfile, $rcsarchive); # .??v, checked out file, and ,v files,
+ # respectively
+ my ($rev_count, $first_vl, $last_vl, $description,
+ $rev_index, @rev_num, %checked_in, %author,
+ $relative_comment_index, @comment_string,
+ %comment);
+ my ($num_version_labels, $label_index, @label_revision, $label,
+ @new_label, $rcs_rev);
+ my ($revision, %rcs_rev_num);
+ my @remainder;
+ my ($get_output, $rcs_output, $ci_output, $mv_output);
+ my ($ci_command, $rcs_command, $wtr);
+ my @hits;
+ my ($num_fields);
+ my $skipdirlock; # if true, don't write conv.out
+ # used only for single file operations
+ # at the moment
+ my $cd;
+ my $cvs_dir;
+
+ my @filenames;
+ # We may have recieved a single file name to process...
+ if ( -d $dir )
+ {
+ # change into the directory to be processed
+ # open the current directory for listing
+ # initialize the list of filenames
+ # and set filenames equal to directory listing
+ unless ( ( chdir $dir ) and ( opendir CURDIR, "." ) and ( @filenames = readdir CURDIR ) )
+ {
+ $cd = cwd;
+ error_count 'error', \$errors, "skipping directory $dir from $cd";
+ chdir $old_dir or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";
+ return ($errors, $warnings);
+ }
+
+ # clean up by closing the directory
+ closedir(CURDIR);
+
+ if ($options{'rcs-dirs-flat'} && $options{'cvs-module-path'})
+ {
+ my @cur_dir_names = split qr{[/\\]}, cwd;
+ my $rel_cd = $cur_dir_names[-1];
+ push @rel_dirs, $rel_cd;
+ $cvs_dir = "$options{'cvs-module-path'}/"
+ . join "/", @rel_dirs;
+ if (!-d $cvs_dir)
+ {
+ print "Creating directory \`$cvs_dir'\n";
+ if (!mkpath ($cvs_dir))
+ {
+ pop @rel_dirs;
+ error_count 'error', \$errors,
+"failed to make directory \`$cvs_dir' - skipping directory \`$cd'";
+ chdir $old_dir or die
+"Failed to restore original directory (\`$old_dir'): ", $!, ", stopped";
+ return ($errors, $warnings);
+ # after all, we have nowhere to put
+ # them...
+ }
+ }
+ }
+
+ }
+ elsif ( -f $dir ) # we recieved a single file
+ {
+ push @filenames, $dir;
+ $skipdirlock = 1;
+ }
+ else
+ {
+ $cd = cwd;
+ error_count 'error', \$errors, "no such directory/file $dir from $cd\n";
+ chdir $old_dir or die
+"Failed to restore original directory ($old_dir): ", $!, ", stopped";
+ return ($errors, $warnings);
+ }
+
+ # save the current directory
+ $cd = cwd;
+
+ # increment the global $curlevel variable
+ $curlevel = $curlevel +1;
+
+ # initialize a list for any subdirectories and any files
+ # we need to process
+ my $vcsdir = "";
+ my (@subdirs, $fn, $file, @files, @pvcsarchives);
+
+ # print "$cd: " . join (", ", @filenames) . "\n";
+ # hit_any_key;
+
+ (@files, @pvcsarchives) = ( (), () );
+ # begin a for loop to execute on each filename in the list @filename
+ foreach $fn (@filenames)
+ {
+ # if the file is a directory...
+ if (-d $fn)
+ {
+ # then if we are not expecting a flat arrangement of pvcs files
+ # and we found a vcs directory add its files to @pvcsarchives
+ if (!$options{'pvcs-dirs-flat'} and $fn =~ /^vcs$/i)
+ {
+ if ($options{verify} =~ /^locks$/ ) {
+ if ( -f $donefile_name ) {
+ print "Verified existence of lockfile $cd/$donefile_name."
+ . ( ($options{mode} =~ /^convert$/) ? " Skipping directory." : "" )
+ . "\n" if ($options{verbose});
+ next;
+ } elsif ( $options{mode} =~ /^verify$/ ) {
+ print "No lockfile found for $cd .\n";
+ next;
+ }
+ }
+
+ # else add the files in the vcs dir to our list of files to process
+ error_count 'warning', \$warnings, "Found two vcs dirs in directory $cd.\n"
+ if ($vcsdir and $options{warnings});
+
+ $vcsdir = $fn;
+
+ unless ( ( opendir VCSDIR, $vcsdir ) and ( @files = readdir VCSDIR ) )
+ {
+ error_count 'error', \$errors, "skipping directory &cd/$fn";
+ next;
+ }
+ closedir VCSDIR;
+
+ # and so we don't need to worry about where these
+ # files came from later...
+ foreach $file (@files)
+ {
+ push @pvcsarchives, "$vcsdir/$file" if (-f "$vcsdir/$file");
+ }
+
+ # don't want recursion here...
+ @pvcsarchives = grep !/^\.\.?$/, @pvcsarchives;
+ }
+ elsif ($fn !~ /^\.\.?$/)
+ {
+ next if (!$options{'rcs-dirs-flat'} and $fn =~ /^rcs$/i);
+ # include it in @subdir if it's not a parent directory
+ push(@subdirs,$fn);
+ }
+ }
+ # else if we are processing a flat arrangement of pvcs files...
+ elsif ($options{'pvcs-dirs-flat'} and -f $fn)
+ {
+ if ($options{verify} =~ /^locks$/) {
+ if ( -f $donefile_name) {
+ print "Found lockfile $cd/$donefile_name."
+ . ( ($options{mode} =~ /^convert$/) ? " Skipping directory." : "" )
+ . "\n" if ($options{verbose});
+ last;
+ } elsif ($options{mode} =~ /^verify$/) {
+ print "No lockfile found for $cd .\n";
+ last;
+ }
+ }
+ # else add this to the list of files to process
+ push (@pvcsarchives, $fn);
+ }
+ }
+
+ # print "pvcsarchives: " . join (", ", @pvcsarchives) . "\n";
+ # print "subdirs: " . join (", ", @subdirs) . "\n";
+ # hit_any_key;
+
+ # for loop of subdirs
+ foreach (@subdirs)
+ {
+ # run execdir on each sub dir
+ if ($maxlevel >= $curlevel)
+ {
+ my ($e, $w) = execdir ($_);
+ $errors += $e;
+ $warnings += $w;
+ }
+ }
+
+ # Print output header for each directory
+ print("Directory: $cd\n");
+
+ # the @files variable should already contain the list of files
+ # we should attempt to process
+ if ( @pvcsarchives && ( $options{mode} =~ /^convert$/ ) )
+ {
+ # create an RCS directory in parent to store RCS files in
+ if ( !( $options{'rcs-dirs-flat'} or (-d "RCS") or mkpath ( "RCS" ) ) )
+ {
+ error_count 'error', \$errors, "failed to make directory $cd/RCS - skipping directory $cd";
+ @pvcsarchives = ();
+ # after all, we have nowhere to put them...
+ }
+ }
+
+ # begin a for loop to execute on each filename in the list @files
+ foreach $pvcsarchive (@pvcsarchives)
+ {
+ my $got_workfile = 0;
+ my $got_version_labels = 0;
+ my $got_description = 0;
+ my $got_rev_count = 0;
+
+ my $abs_file = $cd . "/" . $pvcsarchive;
+
+ print("Verifying $abs_file...\n") if ($options{verbose});
+
+ print "vlog $pvcsarchive\n";
+ # FIXME: Quoting this is better than no quotes, but quotes in
+ # filenames remain unquoted.
+ my $vlog_output = `vlog \"$pvcsarchive\"`;
+
+ # Split the vcs status output into individual lines
+ my @vlog_strings = split /\n/, $vlog_output;
+ my $num_vlog_strings = @vlog_strings;
+ $_ = $vlog_strings[0];
+ if ( /^\s*$/ || /^vlog: warning/ )
+ {
+ error_count 'warning', \$warnings, "$abs_file is NOT a valid PVCS archive!!!\n";
+ next;
+ }
+
+ my $num;
+ # Collect all vlog output into appropriate variables
+ #
+ # This will ignore at the very least the /^\s*Archive:\s*/ field
+ # and maybe more. This should not be a problem.
+ for ( $num = 0; $num < $num_vlog_strings; $num++ )
+ {
+ # print("$vlog_strings[$num]\n");
+ $_ = $vlog_strings[$num];
+
+ if( ( /^Workfile:\s*/ ) && (!$got_workfile ) )
+ {
+ my $num_fields;
+
+ $got_workfile = 1;
+ # get the string to the right of the above search (with any path stripped)
+ $workfile = $';
+ $num_fields = split /[\/\\]/, $workfile;
+ if ( $num_fields > 1 )
+ {
+ $workfile = $_[$num_fields - 1 ];
+ }
+
+ $rcsarchive = $options{'rcs-dirs-flat'} ? "" : "RCS/";
+ $rcsarchive .= $workfile;
+ $rcsarchive .= $options{'rcs-extension'} if ($options{'rcs-extension'});
+ print "Workfile is $workfile\n" if ($options{debug});
+ }
+
+ elsif ( ( /^Rev count:\s*/ ) && (!$got_rev_count ) )
+ {
+ $got_rev_count = 1;
+ # get the string to the right of the above search
+ $rev_count = $';
+ print "Revision count is $rev_count\n";
+ }
+
+ elsif ( ( /^Version labels:\s*/ ) && (!$got_version_labels ) )
+ {
+ $got_version_labels = 1;
+ $first_vl = $num+1;
+ print "Version labels start at $first_vl\n" if ($options{debug});
+ }
+
+ elsif ( ( /^Description:\s*/ ) && (!$got_description ) )
+ {
+ $got_description = 1;
+ $description = $vlog_strings[$num+1];
+ print "Description is `$description'\n" if ($options{debug});
+ $last_vl = $num++ - 1;
+ }
+
+ elsif ( /^Rev\s+/ ) # get all the revision information at once
+ {
+ $rev_index = 0;
+ @rev_num = ();
+ while ( $rev_index < $rev_count )
+ {
+ $_ = $vlog_strings[$num];
+ /^\s*Rev\s+(\d+\.(\d+\.\d+\.)*\d+)$/;
+ $rev_num[$rev_index] = $1;
+ print "Found revision: $rev_num[$rev_index]\n" if ($options{debug});
+ die "Not a valid revision ($rev_num[$rev_index]).\n"
+ if ($rev_num[$rev_index] !~ /^(\d+\.)(\d+\.\d+\.)*\d+$/);
+
+ $_ = $vlog_strings[$num+1];
+ /^\s*Locked\s*/ and $num++;
+
+ $_ = $vlog_strings[$num+1];
+ /^\s*Checked in:\s*/;
+ $checked_in{$rev_num[$rev_index]} = "\"" . $' . "\"";
+ print "Checked in: $checked_in{$rev_num[$rev_index]}\n" if ($options{debug});
+
+ $_ = $vlog_strings[$num+3];
+ /^\s*Author id:\s*/;
+ my @fields = split;
+ $author{$rev_num[$rev_index]} = "\"" . $fields[2] . "\"";
+ print "Author: $author{$rev_num[$rev_index]}\n" if ($options{debug});
+
+ my @branches = ();
+ $_ = $vlog_strings[$num+1];
+ if (/^\s*Branches:\s*/)
+ {
+ $num++;
+ @branches = split /\s+/, $';
+ }
+
+ $relative_comment_index = 0;
+ @comment_string = ();
+ while (($num + 4 + $relative_comment_index) < @vlog_strings)
+ {
+ last if $vlog_strings[$num+4+$relative_comment_index]
+ =~ /^\s*Rev\s+(\d+\.(\d+\.\d+\.)*\d+)$/
+ && $vlog_strings[$num+3+$relative_comment_index]
+ =~ /^-{35}$/;
+
+ # We need the \n added for multi-line comments. There is no effect for
+ # single-line comments since RCS inserts the \n if it doesn't exist already
+ # print "Found commment line: $vlog_strings[$num+4+$relative_comment_index]\n"
+ # if ($options{debug});
+ push @comment_string, $vlog_strings[$num+4+$relative_comment_index], "\n";
+ $relative_comment_index += 1;
+ }
+ # print "Popped from comment: " . join ("", splice (@comment_string, -2))
+ # . "\n"
+ # if ($options{debug});
+ # Pop the "-+" or "=+" line from the comment
+ while ( (pop @comment_string) !~ /^-{35}|={35}$/ )
+ {}
+ $comment{$rev_num[$rev_index]} = join "", @comment_string;
+
+ $num += ( 4 + $relative_comment_index );
+ print "Got comment for $rev_num[$rev_index]\n" if ($options{debug});
+ print "comment string: $comment{$rev_num[$rev_index]}\n" if ($options{debug});
+ $rev_index += 1;
+ } # while ( $rev_index < $rev_count )
+ $num -= 1; #although there should be nothing left for this to matter
+ } # Get Rev information
+ } # for ($num = 0; $num < $num_vlog_strings; $num++)
+ # hit_any_key if ($options{debug});
+ # Create RCS revision numbers corresponding to PVCS version numbers
+ my @rcs_rev_nums;
+ foreach $revision (@rev_num)
+ {
+ $rcs_rev_num{ $revision } = &pvcs_to_rcs_rev_number( $revision );
+ push @rcs_rev_nums, $rcs_rev_num{$revision};
+ print"PVCS revision is $revision; RCS revision is $rcs_rev_num{ $revision }\n"
+ if ($options{debug});
+ }
+
+ # Sort the revision numbers - PVCS and RCS store them in different orders
+ # Clear @_ so we don't pass anything in by accident...
+ @_ = ();
+ @rev_num = sort revisions @rev_num;
+ print "Sorted rev_nums:\n" . join ("\n", @rev_num) . "\n" if ($options{debug});
+ # hit_any_key;
+
+ # Loop through each version label, checking for need to relabel ' ' with '_'.
+ $num_version_labels = $last_vl - $first_vl + 1;
+ print "Version label count is $num_version_labels\n";
+ for( $i = $first_vl; $i <= $last_vl; $i += 1 )
+ {
+ # print("$vlog_strings[$i]\n");
+ $label_index = $i - $first_vl;
+ $_=$vlog_strings[$i];
+ print "Starting with string '$_'\n" if ($options{debug});
+ my @fields = split /\"/;
+ $label = $fields[1];
+ print "Got label '$label'\n" if ($options{debug});
+ @fields = split /\s+/, $fields[2];
+ $label_revision[$label_index] = $fields[2];
+ print "Original label is $label_revision[$label_index]\n" if ($options{debug});
+
+ # Create RCS revision numbers corresponding to PVCS version numbers by
+ # adding 1 to the revision number (# after last .)
+ $label_revision[ $label_index ] = pvcs_to_rcs_rev_number( $label_revision [ $label_index ] );
+ # replace ' ' with '_', if needed
+ $_=$label;
+ $new_label[$label_index] = $label;
+ $new_label[$label_index] =~ s/ /_/g;
+ $new_label[$label_index] =~ s/\./_/g;
+ $new_label[$label_index] = "\"" . $new_label[$label_index] . "\"";
+ print"Label $new_label[$label_index] is for revision $label_revision[$label_index]\n" if ($options{debug});
+ }
+
+ ##########
+ #
+ # See if the RCS archive is up to date with the PVCS archive
+ #
+ ##########
+ my $cvsarchive;
+ $cvsarchive = "$cvs_dir/$rcsarchive" if $options{'cvs-module-path'};
+ $cvsarchive .= $rcsarchive;
+ if ($options{verify} =~ /^locks|exists$/ and -f $cvsarchive)
+ {
+ print "Verified existence of "
+ . ($options{'cvs-module-path'} ? $cvsarchive : "$cd/$rcsarchive")
+ . "."
+ . ( ($options{mode} =~ /^convert$/) ? " Skipping." : "" )
+ . "\n" if ($options{verbose});
+ next;
+ }
+
+ # Create RCS archive and check in all revisions, then label.
+ my $first_time = 1;
+ foreach $revision (@rev_num)
+ {
+ # print "get -p$revision $pvcsarchive >$workfile\n";
+ print "get -r$revision $pvcsarchive\n";
+ # $vcs_output = `vcs -u -r$revision $pvcsarchive`;
+ # $get_output = `get -p$revision $pvcsarchive >$workfile`;
+ # FIXME: Doesn't handle quotes in filenames as FIXME above.
+ $get_output = `get -r$revision \"$pvcsarchive\"`;
+
+ # if this is the first time, delete the rcs archive if it exists
+ # need for $options{verify} == none
+ unlink $rcsarchive if ($first_time and $options{verify} =~ /^none$/ and -f $rcsarchive);
+
+ # Also check here whether this file ought to be "binary"
+ if ( $first_time )
+ {
+ $rcs_command = "$rcs_base_command -i";
+ if ( ( @hits = grep { $workfile =~ /$_/ } keys %bin_ext ) || $options{'force-binary'} )
+ {
+ $rcs_command .= " -kb";
+ $workfile =~ /$hits[0]/ if (@hits);
+ print "Binary attribute -kb added ("
+ . (@hits ? "file type is '$bin_ext{$hits[0]}' for extension '$&'" : "forced")
+ . ")\n";
+ }
+
+ # FIXME: Doesn't handle quotes and other special characters in
+ # filenames as two FIXMEs above.
+ $rcs_command .= " \"$workfile\"";
+
+ # print and execute the rcs archive initialization command
+ print "$rcs_command\n";
+ $wtr = new IO::File "|$rcs_command";
+ $wtr->print ($description);
+ $wtr->print ("\n") unless ($description =~ /\n$/s);
+ $wtr->print (".\n");
+ $wtr->close;
+
+ # $rcs_output = `$rcs_base_command -i -kb $workfile`;
+ }
+
+ # if this isn't the first time, we need to lock the rcs branch
+ #
+ # This is a little messy, but it works. Some extra locking is attempted.
+ # (This happens the first time a branch is used, at the least)
+ my $branch = "";
+ my @branch;
+ @branch = split /\./, $rcs_rev_num{$revision};
+ pop @branch;
+ $branch = join ".", @branch if @branch != 1;
+
+ # FIXME: Quotes around file names handles spaces but not shell
+ # metacharacters in file names.
+ unless ($first_time)
+ {
+ print "$rcs_base_command -l$branch \"$workfile\"\n"
+ if $options{'debug'};
+ $rcs_output = `$rcs_base_command -l$branch \"$workfile\"`;
+ }
+
+ # If an empty comment is specified, RCS will not check in the file;
+ # check for this case. (but an empty -t- description is fine - go figure!)
+ # Since RCS will pause and ask for a comment if one is not given,
+ # substitute a dummy comment "no comment".
+ $comment{$revision} =~ /^\s*$/ and $comment{$revision} = "no comment\n";
+
+ $ci_command = $ci_base_command;
+ $ci_command .= " -f -r$rcs_rev_num{$revision} -d$checked_in{$revision}"
+ . " -w$author{$revision}";
+
+ $ci_command .= " \"$workfile\"";
+
+ # print and execute the ci command
+ print "$ci_command\n";
+ $wtr = new IO::File "|$ci_command";
+ $wtr->print ($comment{$revision});
+ $wtr->print ("\n") unless ($comment{$revision} =~ /\n$/s);
+ $wtr->print (".\n");
+ $wtr->close;
+ # $ci_output = `$ci_command`;
+ # $ci_output = `cat $tmpdir/ci.out`;
+
+ $first_time = 0 if ($first_time);
+ } # foreach revision
+
+ # Keep track of 1.*, 2.*, etc. branches as they are created.
+ my %trunk_branches;
+
+ # Attach version labels
+ for( $i = $num_version_labels - 1; $i >= 0; $i -= 1 )
+ {
+ print "$rcs_base_command -n$new_label[$i]:$label_revision[$i] \"$workfile\"\n"
+ if $options{'debug'};
+ $rcs_output = `$rcs_base_command -n$new_label[$i]:$label_revision[$i] \"$workfile\"`;
+ print "Version label $new_label[$i] added to revision $label_revision[$i]\n";
+
+ # If the label revision is attached to a 1.* revision on the trunk
+ # when a 2.* revision exists, then 1.MAX needs to be branched to
+ # allow commits to this label. This applies to 2.* when 3.*
+ # exists, as well.
+ if ($label_revision[$i] !~ /\./)
+ {
+ # This revision is attached to the trunk.
+ # $rcs_rev_nums[0] will always be the max revision.
+ print "Label `$new_label[$i]' moved from $label_revision[$i] to ";
+ if (exists $trunk_branches{$label_revision[$i]})
+ {
+ $label_revision[$i] = $trunk_branches{$label_revision[$i]};
+ }
+ else
+ {
+ # Attached to X.* with X < M
+ my @X_revs = grep /^$label_revision[$i]\./, @rcs_rev_nums;
+ # Need a _NEW_ branch from $X_revs[0] to attach
+ # to. CVS could do this easily, but our archive
+ # isn't in a CVS repository yet.
+ my @tmp_lbl = @label_revision;
+ my @branch_nums = grep s/^\Q$X_revs[0]\E\.0\.(\d+)$/$1/, @tmp_lbl;
+ @tmp_lbl = @rcs_rev_nums;
+ push @branch_nums,
+ grep (s/^\Q$X_revs[0]\E\.(\d+)\.\d+$/$1/, @tmp_lbl);
+ my $max = 0;
+ foreach my $num (@branch_nums)
+ {
+ $max = $num if $num > $max;
+ }
+ $max += 2;
+ $trunk_branches{$label_revision[$i]} = "$X_revs[0].0.$max";
+ $label_revision[$i] = "$X_revs[0].0.$max";
+ }
+ print "$label_revision[$i].\n";
+ }
+
+ $rcs_output = `$rcs_base_command -n$new_label[$i]:$label_revision[$i] \"$workfile\"`;
+ print "Version label $new_label[$i] added to revision $label_revision[$i]\n";
+
+ if ($label_revision[$i] =~ /^(.*)\.0\./)
+ {
+ my $base = $1;
+ my $rootlbl = $new_label[$i];
+ $rootlbl =~ s/.$/_broot$&/;
+ $rcs_output = `$rcs_base_command -n$rootlbl:$base \"$workfile\"`;
+ print "Version label $rootlbl added to revision $base\n";
+ }
+
+ } # foreach label
+
+ if ($options{'cvs-module-path'})
+ {
+ print "Moving $rcsarchive to $cvsarchive\n";
+ move $rcsarchive, $cvsarchive or warn "Move failed: $!";
+ }
+
+ # hit_any_key;
+ } # foreach pvcs archive file
+
+ # We processed a vcs directory, so if there were any files, lock it.
+ # We are guaranteed to have made the attempt at
+ #
+ # $skipdirlock gets set if a single file name was passed to this function to enable
+ # a '$0 *' operation...
+ if ( @pvcsarchives && !$skipdirlock)
+ {
+ my $fh = new IO::File ">>$donefile_name" or new IO::File ">$donefile_name";
+ if ($fh)
+ {
+ $fh->close;
+ }
+ else
+ {
+ error_count 'error', \$errors, "couldn't create lockfile $cd/$donefile_name";
+ }
+ }
+
+ $curlevel = $curlevel - 1;
+
+ chdir $old_dir
+ or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";
+
+ # Update the relative directory path.
+ pop @rel_dirs if -d $dir;
+
+ return ($errors, $warnings);
+ }
+
+
+
+#
+# This function effectively does a cmp between two revision numbers
+# It is intended to be passed into Perl's sort routine.
+#
+# the pvcs_out is not implemented well. It should probably be
+# returnning $b[0] <=> $a[0] rather than $a[0] <=> $b[0]
+#
+# The @_ argument implementation was going to be used for revision
+# comparison as an aid to remove the /^\sRev/ in revision comment
+# error. The effort was fruitless at the time.
+sub revisions
+ {
+ my @a = split /\./, (defined $a) ? $a : shift;
+ my @b = split /\./, (defined $b) ? $b : shift;
+ my $function = @_ ? shift : 'rcs_in';
+ my ($i, $ret_val);
+
+ die "Not enough arguments to revisions : a = ", join (".", @a),
+ "; b = ", join (".", @b), ", stopped"
+ unless (@a and @b);
+
+ for ($i = 0; $i < scalar( @a ) && $i < scalar( @b ); $i++)
+ {
+ $a[$i] == $b[$i] or return ($a[$i] <=> $b[$i]);
+ }
+
+ return 0 if (scalar (@a) == scalar (@b));
+
+ if ($function eq 'rcs_in')
+ {
+ return (($i == @b) || -1);
+ }
+ elsif ($function eq 'pvcs_out')
+ {
+ return (($i == @a) || -1);
+ }
+ else
+ {
+ die "error - Invalid function type passed to revisions ($function)", ", stopped";
+ }
+ }
+
+
+
+sub pvcs_to_rcs_rev_number
+ {
+ my($input, $num_fields, @rev_string, $return_rev_num, $i);
+
+ $input = $_[0];
+ $num_fields = split /\./, $input;
+ @rev_string = @_;
+ # @rev_string[$num_fields-1] += 1;
+
+ for( $i = 1; $i < $num_fields; $i += 1 )
+ {
+ if ( $i % 2 )
+ {
+ # DRP: 10/1
+ # RCS does not allow revision zero
+ $rev_string[ $i ] += 1;
+ }
+ elsif ( $i )
+ {
+ # DRP: 10/1
+ # Branches must have even references for compatibility
+ # with CVS's magic branch numbers.
+ # (Indexes 2, 4, 6...)
+ $rev_string[ $i ] *= 2;
+ }
+ }
+
+ # If this is a branch revision # (PVCS: a.b.c.*) then we want the CVS
+ # revision # instead. It's okay to do this conversion here since we
+ # never commit to branches. We'll only get a PVCS revision # in that
+ # form when looking through the revision labels.
+ if ($input =~ /\*$/)
+ {
+ pop @rev_string;
+ # If there is only one entry in @rev_string, this is a
+ # revision that needs to be attached to the trunk. Let it be
+ # for now. It might require a new branch, but we can't decide
+ # which branches are valid to create before we know what
+ # branches already exist.
+ push @rev_string, splice (@rev_string, -1, 1, "0")
+ unless @rev_string == 1;
+ }
+
+ $return_rev_num = join ".", @rev_string;
+ return $return_rev_num;
+ }
+
+
+
+
+
+###
+###
+###
+###
+###
+### MAIN program: checks to see if there are command line parameters
+###
+###
+###
+###
+###
+
+
+
+
+
+# and read the options
+die $usage
+ unless GetOptions (\%options, "h|help" => \&exit_help,
+ "recurse!", "mode|m=s", "errorfiles!", "l",
+ "rcs-dirs|rcs-directories|r=s",
+ "pvcs-dirs|pvcs-directories|p=s", "test-binaries|t!",
+ "rcs-extension=s", "verify|v=s", "vcsid|i=s", "verbose!",
+ "debug!", "force-binary!", "cvs-branch-labels!",
+ "warnings|w!", "cvs-module-path|d=s");
+
+
+
+#
+# Special processing for -l !^#%$^@#$%#$
+#
+# At the moment, -l overrides --recurse, regardless of the order the
+# options were passed in
+#
+$options{recurse} = 0 if defined $options{l};
+delete $options{l};
+
+
+
+# Make sure we got acceptable values for rcs-dirs and pvcs-dirs
+my @hits = grep /^$options{'rcs-dirs'}/i, ("leaf", "flat");
+@hits == 1 or die
+ "$0: $options{'rcs-dirs'} invalid argument to --rcs-dirs or ambiguous\n"
+ . " abbreviation.\n"
+ . " Must be one of: 'leaf' or 'flat'.\n"
+ . $usage;
+$options{'rcs-dirs'} = $hits[0];
+$options{'rcs-dirs-flat'} = ($options{'rcs-dirs'} =~ /flat/);
+delete $options{'rcs-dirs'};
+
+@hits = grep /^$options{'pvcs-dirs'}/i, ("leaf", "flat");
+@hits == 1 or die
+ "$0: $options{'pvcs-dirs'} invalid argument to --pvcs-dirs or ambiguous\n"
+ . " abbreviation.\n"
+ . " Must be one of: 'leaf' or 'flat'.\n"
+ . $usage;
+$options{'pvcs-dirs'} = $hits[0];
+$options{'pvcs-dirs-flat'} = ($options{'pvcs-dirs'} =~ /flat/);
+delete $options{'pvcs-dirs'};
+
+# and for verify
+@hits = grep /^$options{verify}/i, ("none", "locks", "exists", "lockdates", "revs", "full");
+@hits == 1 or die
+ "$0: $options{verify} invalid argument to --verify or ambiguous\n"
+ . " abbreviation.\n"
+ . " Must be one of: 'none', 'locks', 'exists', 'lockdates', 'revs',\n"
+ . " or 'full'.\n"
+ . $usage;
+$options{verify} = $hits[0];
+$options{verify} =~ /^none|locks|exists$/ or die
+ "$0: --verify=$options{verify} unimplemented.\n"
+ . $usage;
+
+# and mode
+@hits = grep /^$options{mode}/i, ("convert", "verify");
+@hits == 1 or die
+ "$0: $options{mode} invalid argument to --mode or ambiguous abbreviation.\n"
+ . " Must be 'convert' or 'verify'.\n"
+ . $usage;
+$options{mode} = $hits[0];
+
+$options{'cvs-branch-labels'} or die
+ "$0: RCS Branch Labels unimplemented.\n"
+ . $usage;
+
+# export VCSID into th environment for ourselves and our children
+$ENV{VCSID} = $options{vcsid};
+
+
+
+#
+# Verify we have all the binary executables we need to run this script
+#
+# Allowed this feature to be disabled in case which is missing or we are
+# running on a system which does not return error codes properly (e.g. WIN95)
+#
+# -- i.e. I don't feel like grepping output yet. --
+#
+my @missing_binaries = ();
+if ($options{'test-binaries'})
+ {
+ foreach (@bin_dependancies)
+ {
+ my $output = qx/which $_ 2>&1/;
+ print $output if $options{verbose} && $output;
+ if ($? || $output =~ /^no/)
+ {
+ push @missing_binaries, $_;
+ }
+ }
+
+ if (scalar @missing_binaries)
+ {
+ print STDERR "The following executables were not found in your PATH: "
+ . join ( " ", @missing_binaries )
+ . "\n"
+ . "You must correct this before continuing.\n";
+ exit 1;
+ }
+ }
+delete $options{'test-binaries'};
+
+
+
+#
+# set up our base archive manipulation commands
+#
+
+# set up our rcs_command mods
+$rcs_base_command = "rcs";
+$rcs_base_command .= " -x$options{'rcs-extension'}"
+ if $options{'rcs-extension'};
+
+# set up our rcs_command mods
+$ci_base_command = "ci";
+$ci_base_command .= " -x$options{'rcs-extension'}"
+ if $options{'rcs-extension'};
+
+
+
+#
+# So our logs fill in a manner we can monitor with 'tail -f' fairly easily:
+#
+STDERR->autoflush (1);
+STDOUT->autoflush (1);
+
+
+
+# Initialize the globals we use to keep track of recursion
+if ($options{recurse})
+ {
+ $maxlevel = 10000; # Arbitrary recursion limit
+ }
+else
+ {
+ $maxlevel = 1;
+ }
+delete $options{recurse};
+
+# So we can lock the directories behind us
+$donefile_name = $options{'rcs-dirs-flat'} ? "" : "RCS/";
+$errorfile_name = $donefile_name . "#conv.errors";
+$donefile_name .= "#conv.done";
+
+
+
+#
+# start the whole thing and drop the return code on exit
+#
+push @ARGV, "." unless (@ARGV);
+while ($_ = shift)
+ {
+ # reset the recursion level (corresponds to directory depth)
+ # level 0 is the first directory we enter...
+ $curlevel = -1;
+ my ($e, $w) = execdir($_);
+ $errors += $e;
+ $warnings += $w;
+ }
+
+
+
+print STDERR "$0: " . ($errors ? "Aborted" : "Done") . ".\n";
+print STDERR "$0: ";
+print STDERR ($errors ? $errors : "No") . " error" . (($errors != 1) ? "s" : "");
+print STDERR ", " . ($warnings ? $warnings : "no") . " warning" . (($warnings != 1) ? "s" : "")
+ if ($options{warnings});
+print STDERR ".\n";
+
+
+
+#
+# Woo-hoo! We made it!
+#
+exit $errors;
diff --git a/contrib/rcs-5.7-commitid.patch b/contrib/rcs-5.7-commitid.patch
new file mode 100644
index 0000000..736c1a6
--- /dev/null
+++ b/contrib/rcs-5.7-commitid.patch
@@ -0,0 +1,411 @@
+ChangeLog entry:
+
+Thanks to Paul Eggert who suggested using better random numbers as
+well as using the base62 format for compactness and provided the
+sample divide_by and convert functions used here.
+
+2005-09-29 Mark D. Baushke <mdb@gnu.org>
+
+ * man/rcsfile.5in: Document new commitid delta phrase.
+ * man/rcsfile.5: Regenerated.
+
+ * src/ci.c (RANDOM_BYTES, COMMITID_RAW_SIZE): New constants.
+ (mainProg): Add commitid to delta records. Use
+ random data and represent in base62 or fall back to using the
+ same basic format construction as is used by CVS and CVSNT.
+ (divide_by): New function used by convert.
+ (convert): New fucntion to convert to base62.
+ * rcsbase.h (commitidsize): Room for base62 encoded block or
+ 32bit pid plus a 32bit time rendered as hex plus one
+ NUL byte round up to 64.
+ (struct hshentry): Add new commitid field.
+ * src/rcsgen.c (putdelta): Preserve old commitid entries.
+ * src/rcssyn.c (Kcommitid): New global constant keyword.
+ (getdelta): Add optional parsing for it.
+ * src/rlog.c (putadelta): Print it out.
+
+Index:man/rcsfile.5
+--- man/rcsfile.5~ 1995-06-16 06:58:26.000000000 +0000
++++ man/rcsfile.5 2005-09-27 20:53:01.023504000 +0000
+@@ -1,4 +1,4 @@
+-.lf 1 ./rcsfile.5in
++.lf 1 rcsfile.5in
+ .\" Set p to 1 if your formatter can handle pic output.
+ .if t .nr p 1
+ .de Id
+@@ -69,6 +69,7 @@ nonterminal symbols are in
+ \f3state\fP {\f2id\fP}\f3;\fP
+ \f3branches\fP {\f2num\fP}*\f3;\fP
+ \f3next\fP {\f2num\fP}\f3;\fP
++ { \f3commitid\fP \f2id\fP\f3;\fP }
+ { \f2newphrase\fP }*
+ .LP
+ \f2desc\fP ::= \f3desc\fP \f2string\fP
+@@ -128,6 +129,18 @@ and all the digits of years thereafter.
+ Dates use the Gregorian calendar; times use UTC.
+ .PP
+ The
++.I commitid
++is followed by an
++.I id
++token. This token is intended to be unique across
++multiple files and is used to help group files as
++being a part of the same logical commit.
++This token must uniquely identify the commit
++operation that was applied to a set of RCS files.
++In particular, it must be unique among all the
++commitids in this file.
++.PP
++The
+ .I newphrase
+ productions in the grammar are reserved for future extensions
+ to the format of \*r files.
+@@ -230,7 +243,7 @@ The following diagram shows an example o
+ .fi
+ .\}
+ .if \np \{\
+-.lf 232
++.lf 245
+ .PS 4.250i 3.812i
+ .\" -2.0625 -4.25 1.75 0
+ .\" 0.000i 4.250i 3.812i 0.000i
+@@ -239,7 +252,7 @@ The following diagram shows an example o
+ .nr 0x 1
+ \h'3.812i'
+ .sp -1
+-.lf 242
++.lf 255
+ \h'2.062i-(\w'Head'u/2u)'\v'0.125i-(0v/2u)+0v+0.22m'Head
+ .sp -1
+ \h'2.062i'\v'0.250i'\D'l0.000i 0.500i'
+@@ -256,7 +269,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'1.688i'\v'0.750i'\D'l0.000i 0.500i'
+ .sp -1
+-.lf 244
++.lf 257
+ \h'2.062i-(\w'2.1'u/2u)'\v'1.000i-(0v/2u)+0v+0.22m'2.1
+ .sp -1
+ \h'2.062i'\v'1.250i'\D'l0.000i 0.500i'
+@@ -265,7 +278,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'2.062i'\v'1.750i'\D'l-0.025i -0.100i'
+ .sp -1
+-.lf 246
++.lf 259
+ \h'2.062i-(\w'1.3'u/2u)'\v'2.000i-(1v/2u)+0v+0.22m'1.3
+ .sp -1
+ \h'2.062i'\v'2.250i'\D'l-0.375i -0.500i'
+@@ -280,7 +293,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'1.375i'\v'1.500i'\D'l0.025i 0.100i'
+ .sp -1
+-.lf 249
++.lf 262
+ \h'1.375i-(\w'1.3.1.1'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.3.1.1
+ .sp -1
+ \h'1.375i'\v'1.000i'\D'l-0.375i 0.500i'
+@@ -295,7 +308,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'2.062i'\v'2.750i'\D'l-0.025i -0.100i'
+ .sp -1
+-.lf 252
++.lf 265
+ \h'2.062i-(\w'1.2'u/2u)'\v'3.000i-(1v/2u)+0v+0.22m'1.2
+ .sp -1
+ \h'2.062i'\v'3.250i'\D'l-0.375i -0.500i'
+@@ -310,7 +323,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'0.375i'\v'2.500i'\D'l0.025i 0.100i'
+ .sp -1
+-.lf 255
++.lf 268
+ \h'0.375i-(\w'1.2.1.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.1.1
+ .sp -1
+ \h'0.375i'\v'2.000i'\D'l-0.375i 0.500i'
+@@ -325,7 +338,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'0.375i'\v'1.500i'\D'l0.025i 0.100i'
+ .sp -1
+-.lf 257
++.lf 270
+ \h'0.375i-(\w'1.2.1.3'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.1.3
+ .sp -1
+ \h'0.375i'\v'1.000i'\D'l-0.375i 0.500i'
+@@ -340,7 +353,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'2.750i'\v'2.500i'\D'l0.025i 0.100i'
+ .sp -1
+-.lf 261
++.lf 274
+ \h'2.750i-(\w'1.2.2.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.2.1
+ .sp -1
+ \h'2.750i'\v'2.000i'\D'l-0.375i 0.500i'
+@@ -355,7 +368,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'3.438i'\v'1.250i'\D'l0.025i 0.100i'
+ .sp -1
+-.lf 264
++.lf 277
+ \h'3.438i-(\w'\s-21.2.2.1.1.1\s0'u/2u)'\v'1.000i-(1v/2u)+1v+0.22m'\s-21.2.2.1.1.1\s0
+ .sp -1
+ \h'3.438i'\v'0.750i'\D'l-0.375i 0.500i'
+@@ -370,7 +383,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'2.750i'\v'1.500i'\D'l0.025i 0.100i'
+ .sp -1
+-.lf 267
++.lf 280
+ \h'2.750i-(\w'1.2.2.2'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.2.2
+ .sp -1
+ \h'2.750i'\v'1.000i'\D'l-0.375i 0.500i'
+@@ -385,7 +398,7 @@ The following diagram shows an example o
+ .sp -1
+ \h'2.062i'\v'3.750i'\D'l-0.025i -0.100i'
+ .sp -1
+-.lf 270
++.lf 283
+ \h'2.062i-(\w'1.1'u/2u)'\v'4.000i-(1v/2u)+0v+0.22m'1.1
+ .sp -1
+ \h'2.062i'\v'4.250i'\D'l-0.375i -0.500i'
+@@ -398,9 +411,9 @@ The following diagram shows an example o
+ .if \n(00 .fi
+ .br
+ .nr 0x 0
+-.lf 271
++.lf 284
+ .PE
+-.lf 272
++.lf 285
+ .\}
+ .PP
+ .SH IDENTIFICATION
+Index:man/rcsfile.5in
+--- man/rcsfile.5in~ 1995-06-05 08:28:35.000000000 +0000
++++ man/rcsfile.5in 2005-09-27 20:52:46.424504000 +0000
+@@ -68,6 +68,7 @@ nonterminal symbols are in
+ \f3state\fP {\f2id\fP}\f3;\fP
+ \f3branches\fP {\f2num\fP}*\f3;\fP
+ \f3next\fP {\f2num\fP}\f3;\fP
++ { \f3commitid\fP \f2id\fP\f3;\fP }
+ { \f2newphrase\fP }*
+ .LP
+ \f2desc\fP ::= \f3desc\fP \f2string\fP
+@@ -127,6 +128,18 @@ and all the digits of years thereafter.
+ Dates use the Gregorian calendar; times use UTC.
+ .PP
+ The
++.I commitid
++is followed by an
++.I id
++token. This token is intended to be unique across
++multiple files and is used to help group files as
++being a part of the same logical commit.
++This token must uniquely identify the commit
++operation that was applied to a set of RCS files.
++In particular, it must be unique among all the
++commitids in this file.
++.PP
++The
+ .I newphrase
+ productions in the grammar are reserved for future extensions
+ to the format of \*r files.
+Index:src/rcsbase.h
+--- src/rcsbase.h~ 1995-06-16 06:19:24.000000000 +0000
++++ src/rcsbase.h 2005-09-28 21:47:51.490505000 +0000
+@@ -222,6 +222,11 @@ Report problems and direct all questions
+ /* 1 sets the default locking to strict; */
+ /* used in production environments. */
+
++/* base64_encode(128 random bits) needs 24 bytes + 1 for NUL */
++/* time_t may be 64bits on some machines needs 16 bytes + 1 as hex */
++#define commitidsize 64 /* time+1+base64(128bits)+1 | pid+time+rand+1 */
++#define urandom_dev "/dev/urandom"
++
+ #define yearlength 16 /* (good through AD 9,999,999,999,999,999) */
+ #define datesize (yearlength+16) /* size of output of time2date */
+ #define RCSTMPPREFIX '_' /* prefix for temp files in working dir */
+@@ -358,6 +363,7 @@ struct hshentry {
+ char const * lockedby; /* who locks the revision */
+ char const * state; /* state of revision (Exp by default) */
+ char const * name; /* name (if any) by which retrieved */
++ char const * commitid; /* text string to associate commits */
+ struct cbuf log; /* log message requested at checkin */
+ struct branchhead * branches; /* list of first revisions on branches*/
+ struct cbuf ig; /* ignored phrases in admin part */
+@@ -662,6 +668,7 @@ extern int TotalDeltas;
+ extern char const *const expand_names[];
+ extern char const
+ Kaccess[], Kauthor[], Kbranch[], Kcomment[],
++ Kcommitid[],
+ Kdate[], Kdesc[], Kexpand[], Khead[], Klocks[], Klog[],
+ Knext[], Kstate[], Kstrict[], Ksymbols[], Ktext[];
+ void unexpected_EOF P((void)) exiting;
+Index:src/ci.c
+--- src/ci.c~ 1995-06-16 06:19:24.000000000 +0000
++++ src/ci.c 2005-09-29 21:57:57.814504000 +0000
+@@ -262,6 +262,10 @@ static void cleanup P((void));
+ static void incnum P((char const*,struct buf*));
+ static void addassoclst P((int,char const*));
+
++enum {RANDOM_BYTES = 8};
++enum {COMMITID_RAW_SIZE = (sizeof(time_t) + RANDOM_BYTES)};
++static void convert P((char const input[COMMITID_RAW_SIZE], char *output));
++
+ static FILE *exfile;
+ static RILE *workptr; /* working file pointer */
+ static struct buf newdelnum; /* new revision number */
+@@ -285,6 +289,7 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
+ char olddate[datesize];
+ char newdatebuf[datesize + zonelenmax];
+ char targetdatebuf[datesize + zonelenmax];
++ char commitid[commitidsize];
+ char *a, **newargv, *textfile;
+ char const *author, *krev, *rev, *state;
+ char const *diffname, *expname;
+@@ -309,6 +314,45 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
+ suffixes = X_DEFAULT;
+ nextassoc = &assoclst;
+
++ {
++ char buf[COMMITID_RAW_SIZE] = { 0, };
++ ssize_t len = 0;
++ time_t rightnow = time (NULL);
++ char *startrand = buf + sizeof (time_t);
++ unsigned char *p = (unsigned char *) startrand;
++ size_t randbytes = RANDOM_BYTES;
++ int flags = O_RDONLY;
++ int fd;
++#ifdef O_NOCTTY
++ flags |= O_NOCTTY;
++#endif
++ if (rightnow != (time_t)-1)
++ while (rightnow > 0) {
++ *--p = rightnow % (UCHAR_MAX + 1);
++ rightnow /= UCHAR_MAX + 1;
++ }
++ else {
++ /* try to use more random data */
++ randbytes = COMMITID_RAW_SIZE;
++ startrand = buf;
++ }
++ fd = open (urandom_dev, flags);
++ if (fd >= 0) {
++ len = read (fd, startrand, randbytes);
++ close (fd);
++ }
++ if (len <= 0) {
++ /* no random data was available so use pid */
++ long int pid = (long int)getpid ();
++ p = (unsigned char *) (startrand + sizeof (pid));
++ while (pid > 0) {
++ *--p = pid % (UCHAR_MAX + 1);
++ pid /= UCHAR_MAX + 1;
++ }
++ }
++ convert(buf, commitid);
++ }
++
+ argc = getRCSINIT(argc, argv, &newargv);
+ argv = newargv;
+ while (a = *++argv, 0<--argc && *a++=='-') {
+@@ -532,6 +576,8 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
+ newdelta.name = 0;
+ clear_buf(&newdelta.ig);
+ clear_buf(&newdelta.igtext);
++ /* set commitid */
++ newdelta.commitid=commitid;
+ /* set author */
+ if (author)
+ newdelta.author=author; /* set author given by -w */
+@@ -1317,3 +1363,38 @@ addassoclst(flag, sp)
+ *nextassoc = pt;
+ nextassoc = &pt->nextsym;
+ }
++
++static char const alphabet[62] =
++ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
++
++/* Divide BUF by D, returning the remainder. Replace BUF by the
++ quotient. BUF[0] is the most significant part of BUF.
++ D must not exceed UINT_MAX >> CHAR_BIT. */
++static unsigned int
++divide_by (unsigned char buf[COMMITID_RAW_SIZE], unsigned int d)
++{
++ unsigned int carry = 0;
++ int i;
++ for (i = 0; i < COMMITID_RAW_SIZE; i++)
++ {
++ unsigned int byte = buf[i];
++ unsigned int dividend = (carry << CHAR_BIT) + byte;
++ buf[i] = dividend / d;
++ carry = dividend % d;
++ }
++ return carry;
++}
++
++static void
++convert (char const input[COMMITID_RAW_SIZE], char *output)
++{
++ static char const zero[COMMITID_RAW_SIZE] = { 0, };
++ unsigned char buf[COMMITID_RAW_SIZE];
++ size_t o = 0;
++ memcpy (buf, input, COMMITID_RAW_SIZE);
++ while (memcmp (buf, zero, COMMITID_RAW_SIZE) != 0)
++ output[o++] = alphabet[divide_by (buf, sizeof alphabet)];
++ if (! o)
++ output[o++] = '0';
++ output[o] = '\0';
++}
+Index:src/rcsgen.c
+--- src/rcsgen.c~ 1995-06-16 06:19:24.000000000 +0000
++++ src/rcsgen.c 2005-09-27 22:08:47.421504000 +0000
+@@ -547,6 +547,9 @@ putdelta(node, fout)
+
+ aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
+ awrite(node->ig.string, node->ig.size, fout);
++
++ if (node->commitid)
++ aprintf(fout, "%s\t%s;\n", Kcommitid, node->commitid);
+ }
+
+
+Index:src/rcssyn.c
+--- src/rcssyn.c~ 1995-06-16 06:19:24.000000000 +0000
++++ src/rcssyn.c 2005-09-27 22:08:47.429504000 +0000
+@@ -171,6 +171,7 @@ char const
+ Kauthor[] = "author",
+ Kbranch[] = "branch",
+ Kcomment[] = "comment",
++ Kcommitid[] = "commitid",
+ Kdate[] = "date",
+ Kdesc[] = "desc",
+ Kexpand[] = "expand",
+@@ -433,6 +434,13 @@ getdelta()
+ Delta->lockedby = 0;
+ Delta->log.string = 0;
+ Delta->selector = true;
++
++ if (getkeyopt(Kcommitid)) {
++ Delta->commitid = NextString;
++ nextlex();
++ getsemi(Kcommitid);
++ }
++
+ Delta->ig = getphrases(Kdesc);
+ TotalDeltas++;
+ return (true);
+Index:src/rlog.c
+--- src/rlog.c~ 1995-06-16 06:19:24.000000000 +0000
++++ src/rlog.c 2005-09-26 17:23:55.257504000 +0000
+@@ -591,6 +591,10 @@ putadelta(node,editscript,trunk)
+ aprintf(out, insDelFormat,
+ editscript->insertlns, editscript->deletelns);
+
++ if ( node->commitid )
++ aprintf(out, "%s commitid: %s", (editscript) ? ";" : "",
++ node->commitid);
++
+ newbranch = node->branches;
+ if ( newbranch ) {
+ bufautobegin(&branchnum);
diff --git a/contrib/rcs-to-cvs.sh b/contrib/rcs-to-cvs.sh
new file mode 100644
index 0000000..4db2578
--- /dev/null
+++ b/contrib/rcs-to-cvs.sh
@@ -0,0 +1,193 @@
+#! /bin/sh
+#
+# Copyright (c) 1989-2005 The Free Software Foundation, Inc.
+# Portions Copyright (c) 1989, Brian Berliner
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# Based on the CVS 1.0 checkin csh script.
+# Contributed by Per Cederqvist <ceder@signum.se>.
+# Rewritten in sh by David MacKenzie <djm@cygnus.com>.
+#
+#############################################################################
+#
+# Check in sources that previously were under RCS or no source control system.
+#
+# The repository is the directory where the sources should be deposited.
+#
+# Traverses the current directory, ensuring that an
+# identical directory structure exists in the repository directory. It
+# then checks the files in in the following manner:
+#
+# 1) If the file doesn't yet exist, check it in as revision 1.1
+#
+# The script also is somewhat verbose in letting the user know what is
+# going on. It prints a diagnostic when it creates a new file, or updates
+# a file that has been modified on the trunk.
+#
+# Bugs: doesn't put the files in branch 1.1.1
+# doesn't put in release and vendor tags
+#
+#############################################################################
+
+usage="Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
+vbose=0
+message=""
+if [ -d /var/tmp ]; then message_file=/var/tmp/checkin.$$; else message_file=/usr/tmp/checkin.$$; fi
+got_one=0
+
+if [ $# -lt 1 ]; then
+ echo "$usage" >&2
+ exit 1
+fi
+
+while [ $# -ne 0 ]; do
+ case "$1" in
+ -v)
+ vbose=1
+ ;;
+ -m)
+ shift
+ echo $1 > $message_file
+ got_one=1
+ ;;
+ -f)
+ shift
+ message_file=$1
+ got_one=2
+ ;;
+ *)
+ break
+ esac
+ shift
+done
+
+if [ $# -lt 1 ]; then
+ echo "$usage" >&2
+ exit 1
+fi
+
+repository=$1
+shift
+
+if [ -z "$CVSROOT" ]; then
+ echo "Please the environmental variable CVSROOT to the root" >&2
+ echo " of the tree you wish to update" >&2
+ exit 1
+fi
+
+if [ $got_one -eq 0 ]; then
+ echo "Please Edit this file to contain the RCS log information" >$message_file
+ echo "to be associated with this directory (please remove these lines)">>$message_file
+ ${EDITOR-vi} $message_file
+ got_one=1
+fi
+
+# Ya gotta share.
+umask 0
+
+update_dir=${CVSROOT}/${repository}
+[ ! -d ${update_dir} ] && mkdir $update_dir
+
+if [ -d SCCS ]; then
+ echo SCCS files detected! >&2
+ exit 1
+fi
+if [ -d RCS ]; then
+ co RCS/*
+fi
+
+for name in * .[a-zA-Z0-9]*
+do
+ case "$name" in
+ RCS | *~ | \* | .\[a-zA-Z0-9\]\* ) continue ;;
+ esac
+ echo $name
+ if [ $vbose -ne 0 ]; then
+ echo "Updating ${repository}/${name}"
+ fi
+ if [ -d "$name" ]; then
+ if [ ! -d "${update_dir}/${name}" ]; then
+ echo "WARNING: Creating new directory ${repository}/${name}"
+ mkdir "${update_dir}/${name}"
+ if [ $? -ne 0 ]; then
+ echo "ERROR: mkdir failed - aborting" >&2
+ exit 1
+ fi
+ fi
+ cd "$name"
+ if [ $? -ne 0 ]; then
+ echo "ERROR: Couldn\'t cd to $name - aborting" >&2
+ exit 1
+ fi
+ if [ $vbose -ne 0 ]; then
+ $0 -v -f $message_file "${repository}/${name}"
+ else
+ $0 -f $message_file "${repository}/${name}"
+ fi
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ cd ..
+ else # if not directory
+ if [ ! -f "$name" ]; then
+ echo "WARNING: $name is neither a regular file"
+ echo " nor a directory - ignored"
+ continue
+ fi
+ file="${update_dir}/${name},v"
+ comment=""
+ if grep -s '\$Log.*\$' "${name}"; then # If $Log keyword
+ myext=`echo $name | sed 's,.*\.,,'`
+ [ "$myext" = "$name" ] && myext=
+ case "$myext" in
+ c | csh | e | f | h | l | mac | me | mm | ms | p | r | red | s | sh | sl | cl | ml | el | tex | y | ye | yr | "" )
+ ;;
+
+ * )
+ echo "For file ${file}:"
+ grep '\$Log.*\$' "${name}"
+ echo -n "Please insert a comment leader for file ${name} > "
+ read comment
+ ;;
+ esac
+ fi
+ if [ ! -f "$file" ]; then # If not exists in repository
+ if [ ! -f "${update_dir}/Attic/${name},v" ]; then
+ echo "WARNING: Creating new file ${repository}/${name}"
+ if [ -f RCS/"${name}",v ]; then
+ echo "MSG: Copying old rcs file."
+ cp RCS/"${name}",v "$file"
+ else
+ if [ -n "${comment}" ]; then
+ rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file"
+ fi
+ ci -q -u1.1 -t${message_file} -m'.' "$file"
+ if [ $? -ne 0 ]; then
+ echo "ERROR: Initial check-in of $file failed - aborting" >&2
+ exit 1
+ fi
+ fi
+ else
+ file="${update_dir}/Attic/${name},v"
+ echo "WARNING: IGNORED: ${repository}/Attic/${name}"
+ continue
+ fi
+ else # File existed
+ echo "ERROR: File exists in repository: Ignored: $file"
+ continue
+ fi
+ fi
+done
+
+[ $got_one -eq 1 ] && rm -f $message_file
+
+exit 0
diff --git a/contrib/rcs2log.1 b/contrib/rcs2log.1
new file mode 100644
index 0000000..bffbc55
--- /dev/null
+++ b/contrib/rcs2log.1
@@ -0,0 +1,99 @@
+.\"
+.\" Copyright 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2, or (at your option)
+.\" any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; see the file COPYING. If not, write to the
+.\" Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+.\" Boston, MA 02111-1307, USA.
+.\"
+.Dd February 15, 2003
+.Dt RCS2LOG 1
+.Os
+.Sh NAME
+.Nm rcs2log
+.Nd RCS to ChangeLog generator
+.Sh SYNOPSIS
+.Nm rcs2log
+.Bk -words
+.Op Fl c Ar changelog
+.Op Fl h Ar hostname
+.Op Fl i Ar indent
+.Op Fl l Ar length
+.Op Fl R
+.Op Fl r Ar option
+.Op Fl t Ar tabwidth
+.Op Fl u Ar login<TAB>fullname<TAB>mailaddr
+.Op Fl v
+.Op Fl -help
+.Op Fl -version
+.Op Ar file ...
+.Ek
+.Sh DESCRIPTION
+The
+.Nm
+utility generates a change log prefix from RCS files (perhaps in the CVS
+repository) and the ChangeLog (if any).
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c Ar changelog
+Output a change log prefix to
+.Ar changelog
+(default ChangeLog).
+.It Fl h Ar hostname
+Use
+.Ar hostname
+in change log entries (default current host).
+.It Fl i Ar indent
+Indent change log lines by
+.Ar indent
+spaces (default 8).
+.It Fl l Ar length
+Try to limit log lines to
+.Ar length
+characters (default 79).
+.It Fl R
+If no
+.Ar file Ns Li (s)
+are given and RCS is used, recurse through working directory.
+.It Fl r Ar option
+Pass
+.Ar option
+to subsidiary log command.
+.It Fl t Ar tabwidth
+Tab stops are every
+.Ar tabwidth
+characters (default 8).
+.It Fl u Ar "login<TAB>fullname<TAB>mailaddr"
+Assume
+.Ar login
+has
+.Ar fullname
+and
+.Ar mailaddr .
+.It Fl v
+Append RCS revision to file names in log lines.
+.It Fl -help
+Output help.
+.It Fl -version
+Output version number.
+.El
+.Sh SEE ALSO
+.Xr rcs 1 ,
+.Xr rcsintro 1 ,
+.Xr rlog 1 ,
+.Xr rcsfile 5
+.Sh AUTHORS
+Paul Eggert <eggert@twinsun.com>
+.Sh BUGS
+Report bugs to <bug-gnu-emacs@gnu.org>.
diff --git a/contrib/rcs2log.sh b/contrib/rcs2log.sh
new file mode 100644
index 0000000..29049b4
--- /dev/null
+++ b/contrib/rcs2log.sh
@@ -0,0 +1,742 @@
+#! /bin/sh
+
+# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# RCS to ChangeLog generator
+
+# Generate a change log prefix from RCS files (perhaps in the CVS repository)
+# and the ChangeLog (if any).
+# Output the new prefix to standard output.
+# You can edit this prefix by hand, and then prepend it to ChangeLog.
+
+# Ignore log entries that start with `#'.
+# Clump together log entries that start with `{topic} ',
+# where `topic' contains neither white space nor `}'.
+
+Help='The default FILEs are the files registered under the working directory.
+Options:
+
+ -c CHANGELOG Output a change log prefix to CHANGELOG (default ChangeLog).
+ -h HOSTNAME Use HOSTNAME in change log entries (default current host).
+ -i INDENT Indent change log lines by INDENT spaces (default 8).
+ -l LENGTH Try to limit log lines to LENGTH characters (default 79).
+ -L FILE Use rlog-format FILE for source of logs.
+ -R If no FILEs are given and RCS is used, recurse through working directory.
+ -r OPTION Pass OPTION to subsidiary log command.
+ -t TABWIDTH Tab stops are every TABWIDTH characters (default 8).
+ -u "LOGIN<tab>FULLNAME<tab>MAILADDR" Assume LOGIN has FULLNAME and MAILADDR.
+ -v Append RCS revision to file names in log lines.
+ --help Output help.
+ --version Output version number.
+
+Report bugs to <bug-gnu-emacs@gnu.org>.'
+
+Id='$Id: rcs2log,v 1.48 2001/09/05 23:07:46 eggert Exp $'
+
+# Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2001, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+Copyright='Copyright 1992-2003 Free Software Foundation, Inc.
+This program comes with NO WARRANTY, to the extent permitted by law.
+You may redistribute copies of this program
+under the terms of the GNU General Public License.
+For more information about these matters, see the files named COPYING.
+Author: Paul Eggert <eggert@twinsun.com>'
+
+# functions
+@MKTEMP_SH_FUNCTION@
+
+# Use the traditional C locale.
+LANG=C
+LANGUAGE=C
+LC_ALL=C
+LC_COLLATE=C
+LC_CTYPE=C
+LC_MESSAGES=C
+LC_NUMERIC=C
+LC_TIME=C
+export LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_MESSAGES LC_NUMERIC LC_TIME
+
+# These variables each contain a single ASCII character.
+# Unfortunately, there's no portable way of writing these characters
+# in older Unix implementations, other than putting them directly into
+# this text file.
+SOH='' # SOH, octal code 001
+tab=' '
+nl='
+'
+
+# Parse options.
+
+# defaults
+: ${MKTEMP="@MKTEMP@"}
+: ${AWK=awk}
+: ${TMPDIR=/tmp}
+
+changelog=ChangeLog # change log file name
+datearg= # rlog date option
+hostname= # name of local host (if empty, will deduce it later)
+indent=8 # indent of log line
+length=79 # suggested max width of log line
+logins= # login names for people we know fullnames and mailaddrs of
+loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
+logTZ= # time zone for log dates (if empty, use local time)
+recursive= # t if we want recursive rlog
+revision= # t if we want revision numbers
+rlog_options= # options to pass to rlog
+rlogfile= # log file to read from
+tabwidth=8 # width of horizontal tab
+
+while :
+do
+ case $1 in
+ -c) changelog=${2?}; shift;;
+ -i) indent=${2?}; shift;;
+ -h) hostname=${2?}; shift;;
+ -l) length=${2?}; shift;;
+ -L) rlogfile=${2?}; shift;;
+ -[nu]) # -n is obsolescent; it is replaced by -u.
+ case $1 in
+ -n) case ${2?}${3?}${4?} in
+ *"$tab"* | *"$nl"*)
+ echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
+ exit 1;;
+ esac
+ login=$2
+ lfm=$2$tab$3$tab$4
+ shift; shift; shift;;
+ -u)
+ # If $2 is not tab-separated, use colon for separator.
+ case ${2?} in
+ *"$nl"*)
+ echo >&2 "$0: -u '$2': newlines not allowed"
+ exit 1;;
+ *"$tab"*)
+ t=$tab;;
+ *)
+ t=':';;
+ esac
+ case $2 in
+ *"$t"*"$t"*"$t"*)
+ echo >&2 "$0: -u '$2': too many fields"
+ exit 1;;
+ *"$t"*"$t"*)
+ uf="[^$t]*$t" # An unselected field, followed by a separator.
+ sf="\\([^$t]*\\)" # The selected field.
+ login=`expr "X$2" : "X$sf"`
+ lfm="$login$tab"`
+ expr "X$2" : "$uf$sf"
+ `"$tab"`
+ expr "X$2" : "$uf$uf$sf"
+ `;;
+ *)
+ echo >&2 "$0: -u '$2': not enough fields"
+ exit 1;;
+ esac
+ shift;;
+ esac
+ case $logins in
+ '') logins=$login;;
+ ?*) logins=$logins$nl$login;;
+ esac
+ case $loginFullnameMailaddrs in
+ '') loginFullnameMailaddrs=$lfm;;
+ ?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$lfm;;
+ esac;;
+ -r)
+ case $rlog_options in
+ '') rlog_options=${2?};;
+ ?*) rlog_options=$rlog_options$nl${2?};;
+ esac
+ shift;;
+ -R) recursive=t;;
+ -t) tabwidth=${2?}; shift;;
+ -v) revision=t;;
+ --version)
+ set $Id
+ rcs2logVersion=$3
+ echo >&2 "rcs2log (GNU Emacs) $rcs2logVersion$nl$Copyright"
+ exit 0;;
+ -*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help"
+ case $1 in
+ --help) exit 0;;
+ *) exit 1;;
+ esac;;
+ *) break;;
+ esac
+ shift
+done
+
+month_data='
+ m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
+ m[3]="Apr"; m[4]="May"; m[5]="Jun"
+ m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
+ m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
+'
+
+logdir=`$MKTEMP -d $TMPDIR/rcs2log.XXXXXX`
+test -n "$logdir" || exit
+llogout=$logdir/l
+trap exit 1 2 13 15
+trap "rm -fr $logdir 2>/dev/null" 0
+
+# If no rlog-format log file is given, generate one into $rlogfile.
+case $rlogfile in
+'')
+ rlogfile=$logdir/r
+
+ # If no rlog options are given,
+ # log the revisions checked in since the first ChangeLog entry.
+ # Since ChangeLog is only by date, some of these revisions may be duplicates of
+ # what's already in ChangeLog; it's the user's responsibility to remove them.
+ case $rlog_options in
+ '')
+ if test -s "$changelog"
+ then
+ e='
+ /^[0-9]+-[0-9][0-9]-[0-9][0-9]/{
+ # ISO 8601 date
+ print $1
+ exit
+ }
+ /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
+ # old-fashioned date and time (Emacs 19.31 and earlier)
+ '"$month_data"'
+ year = $5
+ for (i=0; i<=11; i++) if (m[i] == $2) break
+ dd = $3
+ printf "%d-%02d-%02d\n", year, i+1, dd
+ exit
+ }
+ '
+ d=`$AWK "$e" <"$changelog"` || exit
+ case $d in
+ ?*) datearg="-d>$d";;
+ esac
+ fi;;
+ esac
+
+ # Use TZ specified by ChangeLog local variable, if any.
+ if test -s "$changelog"
+ then
+ extractTZ='
+ /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{
+ s//\1/; p; q
+ }
+ /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{
+ s//UTC0/; p; q
+ }
+ '
+ logTZ=`tail "$changelog" | sed -n "$extractTZ"`
+ case $logTZ in
+ ?*) TZ=$logTZ; export TZ;;
+ esac
+ fi
+
+ # If CVS is in use, examine its repository, not the normal RCS files.
+ if test ! -f CVS/Repository
+ then
+ rlog=rlog
+ repository=
+ else
+ rlog='cvs -q log'
+ repository=`sed 1q <CVS/Repository` || exit
+ test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
+ case $CVSROOT in
+ *:/*:/*)
+ echo >&2 "$0: $CVSROOT: CVSROOT has multiple ':/'s"
+ exit 1;;
+ *:/*)
+ # remote repository
+ pository=`expr "X$repository" : '.*:\(/.*\)'`;;
+ *)
+ # local repository
+ case $repository in
+ /*) ;;
+ *) repository=${CVSROOT?}/$repository;;
+ esac
+ if test ! -d "$repository"
+ then
+ echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
+ exit 1
+ fi
+ pository=$repository;;
+ esac
+
+ # Ensure that $pository ends in exactly one slash.
+ while :
+ do
+ case $pository in
+ *//) pository=`expr "X$pository" : 'X\(.*\)/'`;;
+ */) break;;
+ *) pository=$pository/; break;;
+ esac
+ done
+
+ fi
+
+ # Use $rlog's -zLT option, if $rlog supports it.
+ case `$rlog -zLT 2>&1` in
+ *' option'*) ;;
+ *)
+ case $rlog_options in
+ '') rlog_options=-zLT;;
+ ?*) rlog_options=-zLT$nl$rlog_options;;
+ esac;;
+ esac
+
+ # With no arguments, examine all files under the RCS directory.
+ case $# in
+ 0)
+ case $repository in
+ '')
+ oldIFS=$IFS
+ IFS=$nl
+ case $recursive in
+ t)
+ RCSdirs=`find . -name RCS -type d -print`
+ filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||'
+ files=`
+ {
+ case $RCSdirs in
+ ?*) find $RCSdirs \
+ -type f \
+ ! -name '*_' \
+ ! -name ',*,' \
+ ! -name '.*_' \
+ ! -name .rcsfreeze.log \
+ ! -name .rcsfreeze.ver \
+ -print;;
+ esac
+ find . -name '*,v' -print
+ } |
+ sort -u |
+ sed "$filesFromRCSfiles"
+ `;;
+ *)
+ files=
+ for file in RCS/.* RCS/* .*,v *,v
+ do
+ case $file in
+ RCS/. | RCS/.. | RCS/,*, | RCS/*_) continue;;
+ RCS/.rcsfreeze.log | RCS/.rcsfreeze.ver) continue;;
+ RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue;;
+ RCS/*,v | RCS/.*,v) ;;
+ RCS/* | RCS/.*) test -f "$file" || continue;;
+ esac
+ case $files in
+ '') files=$file;;
+ ?*) files=$files$nl$file;;
+ esac
+ done
+ case $files in
+ '') exit 0;;
+ esac;;
+ esac
+ set x $files
+ shift
+ IFS=$oldIFS;;
+ esac;;
+ esac
+
+ case $datearg in
+ ?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogfile;;
+ '') $rlog $rlog_options ${1+"$@"} >$rlogfile;;
+ esac || exit;;
+esac
+
+
+# Get the full name of each author the logs mention, and set initialize_fullname
+# to awk code that initializes the `fullname' awk associative array.
+# Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
+# you have to fix the resulting output by hand.
+
+initialize_fullname=
+initialize_mailaddr=
+
+case $loginFullnameMailaddrs in
+?*)
+ case $loginFullnameMailaddrs in
+ *\"* | *\\*)
+ sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
+$loginFullnameMailaddrs
+EOF
+ loginFullnameMailaddrs=`cat $llogout`;;
+ esac
+
+ oldIFS=$IFS
+ IFS=$nl
+ for loginFullnameMailaddr in $loginFullnameMailaddrs
+ do
+ IFS=$tab
+ set x $loginFullnameMailaddr
+ login=$2
+ fullname=$3
+ mailaddr=$4
+ initialize_fullname="$initialize_fullname
+ fullname[\"$login\"] = \"$fullname\""
+ initialize_mailaddr="$initialize_mailaddr
+ mailaddr[\"$login\"] = \"$mailaddr\""
+ done
+ IFS=$oldIFS;;
+esac
+
+case $logins in
+?*)
+ sort -u -o $llogout <<EOF
+$logins
+EOF
+ ;;
+'')
+ : ;;
+esac >$llogout || exit
+
+output_authors='/^date: / {
+ if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) {
+ print substr($5, 1, length($5)-1)
+ }
+}'
+authors=`
+ $AWK "$output_authors" <"$rlogfile" | sort -u | comm -23 - $llogout
+`
+case $authors in
+?*)
+ cat >$llogout <<EOF || exit
+$authors
+EOF
+ initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/'
+ initialize_author=`sed -e "$initialize_author_script" <$llogout`
+ awkscript='
+ BEGIN {
+ alphabet = "abcdefghijklmnopqrstuvwxyz"
+ ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ '"$initialize_author"'
+ }
+ {
+ if (author[$1]) {
+ fullname = $5
+ if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) {
+ # Remove the junk from fullnames like "0000-Admin(0000)".
+ fullname = substr(fullname, index(fullname, "-") + 1)
+ fullname = substr(fullname, 1, index(fullname, "(") - 1)
+ }
+ if (fullname ~ /,[^ ]/) {
+ # Some sites put comma-separated junk after the fullname.
+ # Remove it, but leave "Bill Gates, Jr" alone.
+ fullname = substr(fullname, 1, index(fullname, ",") - 1)
+ }
+ abbr = index(fullname, "&")
+ if (abbr) {
+ a = substr($1, 1, 1)
+ A = a
+ i = index(alphabet, a)
+ if (i) A = substr(ALPHABET, i, 1)
+ fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
+ }
+
+ # Quote quotes and backslashes properly in full names.
+ # Do not use gsub; traditional awk lacks it.
+ quoted = ""
+ rest = fullname
+ for (;;) {
+ p = index(rest, "\\")
+ q = index(rest, "\"")
+ if (p) {
+ if (q && q<p) p = q
+ } else {
+ if (!q) break
+ p = q
+ }
+ quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1)
+ rest = substr(rest, p+1)
+ }
+
+ printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest
+ author[$1] = 0
+ }
+ }
+ '
+
+ initialize_fullname=`
+ {
+ (getent passwd $authors) ||
+ (
+ cat /etc/passwd
+ for author in $authors
+ do NIS_PATH= nismatch $author passwd.org_dir
+ done
+ ypmatch $authors passwd
+ )
+ } 2>/dev/null |
+ $AWK -F: "$awkscript"
+ `$initialize_fullname;;
+esac
+
+
+# Function to print a single log line.
+# We don't use awk functions, to stay compatible with old awk versions.
+# `Log' is the log message.
+# `files' contains the affected files.
+printlogline='{
+
+ # Following the GNU coding standards, rewrite
+ # * file: (function): comment
+ # to
+ # * file (function): comment
+ if (Log ~ /^\([^)]*\): /) {
+ i = index(Log, ")")
+ filefunc = substr(Log, 1, i)
+ while ((j = index(filefunc, "\n"))) {
+ files = files " " substr(filefunc, 1, j-1)
+ filefunc = substr(filefunc, j+1)
+ }
+ files = files " " filefunc
+ Log = substr(Log, i+3)
+ }
+
+ # If "label: comment" is too long, break the line after the ":".
+ sep = " "
+ i = index(Log, "\n")
+ if ('"$length"' <= '"$indent"' + 1 + length(files) + i) sep = "\n" indent_string
+
+ # Print the label.
+ printf "%s*%s:", indent_string, files
+
+ # Print each line of the log.
+ while (i) {
+ logline = substr(Log, 1, i-1)
+ if (logline ~ /[^'"$tab"' ]/) {
+ printf "%s%s\n", sep, logline
+ } else {
+ print ""
+ }
+ sep = indent_string
+ Log = substr(Log, i+1)
+ i = index(Log, "\n")
+ }
+}'
+
+# Pattern to match the `revision' line of rlog output.
+rlog_revision_pattern='^revision [0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)*(['"$tab"' ]+locked by: [^'"$tab"' $,.0-9:;@]*[^'"$tab"' $,:;@][^'"$tab"' $,.0-9:;@]*;)?['"$tab"' ]*$'
+
+case $hostname in
+'')
+ hostname=`(
+ hostname || uname -n || uuname -l || cat /etc/whoami
+ ) 2>/dev/null` || {
+ echo >&2 "$0: cannot deduce hostname"
+ exit 1
+ }
+
+ case $hostname in
+ *.*) ;;
+ *)
+ domainname=`(domainname) 2>/dev/null` &&
+ case $domainname in
+ *.*) hostname=$hostname.$domainname;;
+ esac;;
+ esac;;
+esac
+
+
+# Process the rlog output, generating ChangeLog style entries.
+
+# First, reformat the rlog output so that each line contains one log entry.
+# Transliterate \n to SOH so that multiline entries fit on a single line.
+# Discard irrelevant rlog output.
+$AWK '
+ BEGIN {
+ pository = "'"$pository"'"
+ SOH="'"$SOH"'"
+ }
+ /^RCS file: / {
+ if (pository != "") {
+ filename = substr($0, 11)
+ if (substr(filename, 1, length(pository)) == pository) {
+ filename = substr(filename, length(pository) + 1)
+ }
+ if (filename ~ /,v$/) {
+ filename = substr(filename, 1, length(filename) - 2)
+ }
+ if (filename ~ /(^|\/)Attic\/[^\/]*$/) {
+ i = length(filename)
+ while (substr(filename, i, 1) != "/") i--
+ filename = substr(filename, 1, i - 6) substr(filename, i + 1)
+ }
+ }
+ rev = "?"
+ }
+ /^Working file: / { if (repository == "") filename = substr($0, 15) }
+ /'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ {
+ line = $0
+ if (line ~ /'"$rlog_revision_pattern"'/) {
+ rev = $2
+ next
+ }
+ if (line ~ /^date: [0-9][- +\/0-9:]*;/) {
+ date = $2
+ if (date ~ /\//) {
+ # This is a traditional RCS format date YYYY/MM/DD.
+ # Replace "/"s with "-"s to get ISO format.
+ newdate = ""
+ while ((i = index(date, "/")) != 0) {
+ newdate = newdate substr(date, 1, i-1) "-"
+ date = substr(date, i+1)
+ }
+ date = newdate date
+ }
+ time = substr($3, 1, length($3) - 1)
+ author = substr($5, 1, length($5)-1)
+ printf "%s%s%s%s%s%s%s%s%s%s", filename, SOH, rev, SOH, date, SOH, time, SOH, author, SOH
+ rev = "?"
+ next
+ }
+ if (line ~ /^branches: /) { next }
+ if (line ~ /^(-----------*|===========*)$/) { print ""; next }
+ if (line == "Initial revision" || line ~ /^file .+ was initially added on branch .+\.$/) {
+ line = "New file."
+ }
+ printf "%s%s", line, SOH
+ }
+' <"$rlogfile" |
+
+# Now each line is of the form
+# FILENAME@REVISION@YYYY-MM-DD@HH:MM:SS[+-TIMEZONE]@AUTHOR@LOG
+# where @ stands for an SOH (octal code 001),
+# and each line of LOG is terminated by SOH instead of \n.
+# Sort the log entries, first by date+time (in reverse order),
+# then by author, then by log entry, and finally by file name and revision
+# (just in case).
+sort -t"$SOH" +2 -4r +4 +0 |
+
+# Finally, reformat the sorted log entries.
+$AWK -F"$SOH" '
+ BEGIN {
+ logTZ = "'"$logTZ"'"
+ revision = "'"$revision"'"
+
+ # Initialize the fullname and mailaddr associative arrays.
+ '"$initialize_fullname"'
+ '"$initialize_mailaddr"'
+
+ # Initialize indent string.
+ indent_string = ""
+ i = '"$indent"'
+ if (0 < '"$tabwidth"')
+ for (; '"$tabwidth"' <= i; i -= '"$tabwidth"')
+ indent_string = indent_string "\t"
+ while (1 <= i--)
+ indent_string = indent_string " "
+ }
+
+ {
+ newlog = ""
+ for (i = 6; i < NF; i++) newlog = newlog $i "\n"
+
+ # Ignore log entries prefixed by "#".
+ if (newlog ~ /^#/) { next }
+
+ if (Log != newlog || date != $3 || author != $5) {
+
+ # The previous log and this log differ.
+
+ # Print the old log.
+ if (date != "") '"$printlogline"'
+
+ # Logs that begin with "{clumpname} " should be grouped together,
+ # and the clumpname should be removed.
+ # Extract the new clumpname from the log header,
+ # and use it to decide whether to output a blank line.
+ newclumpname = ""
+ sep = "\n"
+ if (date == "") sep = ""
+ if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
+ i = index(newlog, "}")
+ newclumpname = substr(newlog, 1, i)
+ while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
+ newlog = substr(newlog, i+1)
+ if (clumpname == newclumpname) sep = ""
+ }
+ printf sep
+ clumpname = newclumpname
+
+ # Get ready for the next log.
+ Log = newlog
+ if (files != "")
+ for (i in filesknown)
+ filesknown[i] = 0
+ files = ""
+ }
+ if (date != $3 || author != $5) {
+ # The previous date+author and this date+author differ.
+ # Print the new one.
+ date = $3
+ time = $4
+ author = $5
+
+ zone = ""
+ if (logTZ && ((i = index(time, "-")) || (i = index(time, "+"))))
+ zone = " " substr(time, i)
+
+ # Print "date[ timezone] fullname <email address>".
+ # Get fullname and email address from associative arrays;
+ # default to author and author@hostname if not in arrays.
+ if (fullname[author])
+ auth = fullname[author]
+ else
+ auth = author
+ printf "%s%s %s ", date, zone, auth
+ if (mailaddr[author])
+ printf "<%s>\n\n", mailaddr[author]
+ else
+ printf "<%s@%s>\n\n", author, "'"$hostname"'"
+ }
+ if (! filesknown[$1]) {
+ filesknown[$1] = 1
+ if (files == "") files = " " $1
+ else files = files ", " $1
+ if (revision && $2 != "?") files = files " " $2
+ }
+ }
+ END {
+ # Print the last log.
+ if (date != "") {
+ '"$printlogline"'
+ printf "\n"
+ }
+ }
+' &&
+
+
+# Exit successfully.
+
+exec rm -fr $logdir
+
+# Local Variables:
+# tab-width:4
+# End:
diff --git a/contrib/rcs2sccs.sh b/contrib/rcs2sccs.sh
new file mode 100644
index 0000000..535ebd0
--- /dev/null
+++ b/contrib/rcs2sccs.sh
@@ -0,0 +1,156 @@
+#! /bin/sh
+#
+# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+############################################################
+# Error checking
+#
+if [ ! -d SCCS ] ; then
+ mkdir SCCS
+fi
+
+logfile=/tmp/rcs2sccs_$$_log
+rm -f $logfile
+tmpfile=/tmp/rcs2sccs_$$_tmp
+rm -f $tmpfile
+emptyfile=/tmp/rcs2sccs_$$_empty
+echo -n "" > $emptyfile
+initialfile=/tmp/rcs2sccs_$$_init
+echo "Initial revision" > $initialfile
+sedfile=/tmp/rcs2sccs_$$_sed
+rm -f $sedfile
+revfile=/tmp/rcs2sccs_$$_rev
+rm -f $revfile
+commentfile=/tmp/rcs2sccs_$$_comment
+rm -f $commentfile
+
+# create the sed script
+cat > $sedfile << EOF
+s,;Id;,%Z%%M% %I% %E%,g
+s,;SunId;,%Z%%M% %I% %E%,g
+s,;RCSfile;,%M%,g
+s,;Revision;,%I%,g
+s,;Date;,%E%,g
+s,;Id:.*;,%Z%%M% %I% %E%,g
+s,;SunId:.*;,%Z%%M% %I% %E%,g
+s,;RCSfile:.*;,%M%,g
+s,;Revision:.*;,%I%,g
+s,;Date:.*;,%E%,g
+EOF
+sed -e 's/;/\\$/g' $sedfile > $tmpfile
+cp $tmpfile $sedfile
+############################################################
+# Loop over every RCS file in RCS dir
+#
+if sort -k 1,1 /dev/null 2>/dev/null
+then sort_each_field='-k 1 -k 2 -k 3 -k 4 -k 5 -k 6 -k 7 -k 8 -k 9'
+else sort_each_field='+0 +1 +2 +3 +4 +5 +6 +7 +8'
+fi
+for vfile in *,v; do
+ # get rid of the ",v" at the end of the name
+ file=`echo $vfile | sed -e 's/,v$//'`
+
+ # work on each rev of that file in ascending order
+ firsttime=1
+ rlog $file | grep "^revision [0-9][0-9]*\." | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u $sort_each_field | sed -e 's/ /./g' > $revfile
+ for rev in `cat $revfile`; do
+ if [ $? != 0 ]; then
+ echo ERROR - revision
+ exit
+ fi
+ # get file into current dir and get stats
+ date=`rlog -r$rev $file | grep "^date: " | awk '{print $2; exit}' | sed -e 's/^19\|^20//'`
+ time=`rlog -r$rev $file | grep "^date: " | awk '{print $3; exit}' | sed -e 's/;//'`
+ author=`rlog -r$rev $file | grep "^date: " | awk '{print $5; exit}' | sed -e 's/;//'`
+ date="$date $time"
+ echo ""
+ rlog -r$rev $file | sed -e '/^branches: /d' -e '1,/^date: /d' -e '/^===========/d' -e 's/$/\\/' | awk '{if ((total += length($0) + 1) < 510) print $0}' > $commentfile
+ echo "==> file $file, rev=$rev, date=$date, author=$author"
+ rm -f $file
+ co -r$rev $file >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - co
+ exit
+ fi
+ echo checked out of RCS
+
+ # add SCCS keywords in place of RCS keywords
+ sed -f $sedfile $file > $tmpfile
+ if [ $? != 0 ]; then
+ echo ERROR - sed
+ exit
+ fi
+ echo performed keyword substitutions
+ rm -f $file
+ cp $tmpfile $file
+
+ # check file into SCCS
+ if [ "$firsttime" = "1" ]; then
+ firsttime=0
+ echo about to do sccs admin
+ echo sccs admin -n -i$file $file < $commentfile
+ sccs admin -n -i$file $file < $commentfile >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - sccs admin
+ exit
+ fi
+ echo initial rev checked into SCCS
+ else
+ case $rev in
+ *.*.*.*)
+ brev=`echo $rev | sed -e 's/\.[0-9]*$//'`
+ sccs admin -fb $file 2>>$logfile
+ echo sccs get -e -p -r$brev $file
+ sccs get -e -p -r$brev $file >/dev/null 2>>$logfile
+ ;;
+ *)
+ echo sccs get -e -p $file
+ sccs get -e -p $file >/dev/null 2>> $logfile
+ ;;
+ esac
+ if [ $? != 0 ]; then
+ echo ERROR - sccs get
+ exit
+ fi
+ sccs delta $file < $commentfile >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - sccs delta -r$rev $file
+ exit
+ fi
+ echo checked into SCCS
+ fi
+ sed -e "s;^d D $rev ../../.. ..:..:.. [^ ][^ ]*;d D $rev $date $author;" SCCS/s.$file > $tmpfile
+ rm -f SCCS/s.$file
+ cp $tmpfile SCCS/s.$file
+ chmod 444 SCCS/s.$file
+ sccs admin -z $file
+ if [ $? != 0 ]; then
+ echo ERROR - sccs admin -z
+ exit
+ fi
+ done
+ rm -f $file
+done
+
+
+############################################################
+# Clean up
+#
+echo cleaning up...
+rm -f $tmpfile $emptyfile $initialfile $sedfile $commentfile
+echo ===================================================
+echo " Conversion Completed Successfully"
+echo ===================================================
+
+rm -f *,v
diff --git a/contrib/rcslock.in b/contrib/rcslock.in
new file mode 100755
index 0000000..be86f81
--- /dev/null
+++ b/contrib/rcslock.in
@@ -0,0 +1,265 @@
+#! @PERL@ -T
+# -*-Perl-*-
+
+# Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+###############################################################################
+###############################################################################
+###############################################################################
+#
+# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE
+# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE
+# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
+# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
+# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
+# <@PACKAGE_BUGREPORT@> MAILING LIST.
+#
+# For more on general Perl security and taint-checking, please try running the
+# `perldoc perlsec' command.
+#
+###############################################################################
+###############################################################################
+###############################################################################
+
+# Author: John Rouillard (rouilj@cs.umb.edu)
+# Supported: Yeah right. (Well what do you expect for 2 hours work?)
+# Blame-to: rouilj@cs.umb.edu
+# Complaints to: Anybody except Brian Berliner, he's blameless for
+# this script.
+# Acknowlegements: The base code for this script has been acquired
+# from the log.pl script.
+
+# rcslock.pl - A program to prevent commits when a file to be ckecked
+# in is locked in the repository.
+
+# There are times when you need exclusive access to a file. This
+# often occurs when binaries are checked into the repository, since
+# cvs's (actually rcs's) text based merging mechanism won't work. This
+# script allows you to use the rcs lock mechanism (rcs -l) to make
+# sure that no changes to a repository are able to be committed if
+# those changes would result in a locked file being changed.
+
+# WARNING:
+# This script will work only if locking is set to strict.
+#
+
+# Setup:
+# Add the following line to the commitinfo file:
+
+# ALL /local/location/for/script/lockcheck [options]
+
+# Where ALL is replaced by any suitable regular expression.
+# Options are -v for verbose info, or -d for debugging info.
+# The %s will provide the repository directory name and the names of
+# all changed files.
+
+# Use:
+# When a developer needs exclusive access to a version of a file, s/he
+# should use "rcs -l" in the repository tree to lock the version they
+# are working on. CVS will automagically release the lock when the
+# commit is performed.
+
+# Method:
+# An "rlog -h" is exec'ed to give info on all about to be
+# committed files. This (header) information is parsed to determine
+# if any locks are outstanding and what versions of the file are
+# locked. This filename, version number info is used to index an
+# associative array. All of the files to be committed are checked to
+# see if any locks are outstanding. If locks are outstanding, the
+# version number of the current file (taken from the CVS/Entries
+# subdirectory) is used in the key to determine if that version is
+# locked. If the file being checked in is locked by the person doing
+# the checkin, the commit is allowed, but if the lock is held on that
+# version of a file by another person, the commit is not allowed.
+
+$ext = ",v"; # The extension on your rcs files.
+
+$\="\n"; # I hate having to put \n's at the end of my print statements
+$,=' '; # Spaces should occur between arguments to print when printed
+
+# turn off setgid
+#
+$) = $(;
+
+#
+# parse command line arguments
+#
+require 'getopts.pl';
+
+&Getopts("vd"); # verbose or debugging
+
+# Verbose is useful when debugging
+$opt_v = $opt_d if defined $opt_d;
+
+# $files[0] is really the name of the subdirectory.
+# @files = split(/ /,$ARGV[0]);
+@files = @ARGV[0..$#ARGV];
+$cvsroot = $ENV{'CVSROOT'};
+
+#
+# get login name
+#
+$login = getlogin || (getpwuid($<))[0] || "nobody";
+
+#
+# save the current directory since we have to return here to parse the
+# CVS/Entries file if a lock is found.
+#
+$pwd = `/bin/pwd`;
+chop $pwd;
+
+print "Starting directory is $pwd" if defined $opt_d ;
+
+#
+# cd to the repository directory and check on the files.
+#
+print "Checking directory ", $files[0] if defined $opt_v ;
+
+if ( $files[0] =~ /^\// )
+{
+ print "Directory path is $files[0]" if defined $opt_d ;
+ chdir $files[0] || die "Can't change to repository directory $files[0]" ;
+}
+else
+{
+ print "Directory path is $cvsroot/$files[0]" if defined $opt_d ;
+ chdir ($cvsroot . "/" . $files[0]) ||
+ die "Can't change to repository directory $files[0] in $cvsroot" ;
+}
+
+
+# Open the rlog process and apss all of the file names to that one
+# process to cut down on exec overhead. This may backfire if there
+# are too many files for the system buffer to handle, but if there are
+# that many files, chances are that the cvs repository is not set up
+# cleanly.
+
+print "opening rlog -h @files[1..$#files] |" if defined $opt_d;
+
+open( RLOG, "rlog -h @files[1..$#files] |") || die "Can't run rlog command" ;
+
+# Create the locks associative array. The elements in the array are
+# of two types:
+#
+# The name of the RCS file with a value of the total number of locks found
+# for that file,
+# or
+#
+# The name of the rcs file concatenated with the version number of the lock.
+# The value of this element is the name of the locker.
+
+# The regular expressions used to split the rcs info may have to be changed.
+# The current ones work for rcs 5.6.
+
+$lock = 0;
+
+while (<RLOG>)
+{
+ chop;
+ next if /^$/; # ditch blank lines
+
+ if ( $_ =~ /^RCS file: (.*)$/ )
+ {
+ $curfile = $1;
+ next;
+ }
+
+ if ( $_ =~ /^locks: strict$/ )
+ {
+ $lock = 1 ;
+ next;
+ }
+
+ if ( $lock )
+ {
+ # access list: is the line immediately following the list of locks.
+ if ( /^access list:/ )
+ { # we are done getting lock info for this file.
+ $lock = 0;
+ }
+ else
+ { # We are accumulating lock info.
+
+ # increment the lock count
+ $locks{$curfile}++;
+ # save the info on the version that is locked. $2 is the
+ # version number $1 is the name of the locker.
+ $locks{"$curfile" . "$2"} = $1
+ if /[ ]*([a-zA-Z._]*): ([0-9.]*)$/;
+
+ print "lock by $1 found on $curfile version $2" if defined $opt_d;
+
+ }
+ }
+}
+
+# Lets go back to the starting directory and see if any locked files
+# are ones we are interested in.
+
+chdir $pwd;
+
+# fo all of the file names (remember $files[0] is the directory name
+foreach $i (@files[1..$#files])
+{
+ if ( defined $locks{$i . $ext} )
+ { # well the file has at least one lock outstanding
+
+ # find the base version number of our file
+ &parse_cvs_entry($i,*entry);
+
+ # is our version of this file locked?
+ if ( defined $locks{$i . $ext . $entry{"version"}} )
+ { # if so, it is by us?
+ if ( $login ne ($by = $locks{$i . $ext . $entry{"version"}}) )
+ {# crud somebody else has it locked.
+ $outstanding_lock++ ;
+ print "$by has file $i locked for version " , $entry{"version"};
+ }
+ else
+ { # yeah I have it locked.
+ print "You have a lock on file $i for version " , $entry{"version"}
+ if defined $opt_v;
+ }
+ }
+ }
+}
+
+exit $outstanding_lock;
+
+
+### End of main program
+
+sub parse_cvs_entry
+{ # a very simple minded hack at parsing an entries file.
+local ( $file, *entry ) = @_;
+local ( @pp );
+
+
+open(ENTRIES, "< CVS/Entries") || die "Can't open entries file";
+
+while (<ENTRIES>)
+ {
+ if ( $_ =~ /^\/$file\// )
+ {
+ @pp = split('/');
+
+ $entry{"name"} = $pp[1];
+ $entry{"version"} = $pp[2];
+ $entry{"dates"} = $pp[3];
+ $entry{"name"} = $pp[4];
+ $entry{"name"} = $pp[5];
+ $entry{"sticky"} = $pp[6];
+ return;
+ }
+ }
+}
diff --git a/contrib/sandbox_status.man b/contrib/sandbox_status.man
new file mode 100644
index 0000000..c5a2add
--- /dev/null
+++ b/contrib/sandbox_status.man
@@ -0,0 +1,52 @@
+.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+.TH CVSCHECK LOCAL "4 March 1991" FLUKE
+.SH NAME
+sandbox_status \- identify files added, changed, or removed in a CVS working
+directory
+.SH SYNOPSIS
+.B sandbox_status
+.SH DESCRIPTION
+This command is a housekeeping aid. It should be run in a working
+directory that has been checked out using CVS. It identifies files
+that have been added, changed, or removed in the working directory, but
+not CVS
+.BR commit ted.
+It also determines whether the files have been CVS
+.BR add ed
+or CVS
+.BR remove d.
+For directories, this command determines only whether they have been
+.BR add ed.
+It operates in the current directory only.
+.LP
+This command provides information that is available using CVS
+.B status
+and CVS
+.BR diff .
+The advantage of
+.B sandbox_status
+is that its output is very concise. It saves you the strain (and
+potential error) of interpreting the output of CVS
+.B status
+and
+.BR diff .
+.LP
+See
+.BR cvs (local)
+or
+.BR cvshelp (local)
+for instructions on how to add or remove a file or directory in a
+CVS-controlled package.
+.SH DIAGNOSTICS
+The exit status is 0 if no files have been added, changed, or removed
+from the current directory. Otherwise, the command returns a count of
+the adds, changes, and deletes.
+.SH SEE ALSO
+.BR cvs (local),
+.BR cvshelp (local)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+Technical Computing
diff --git a/contrib/sandbox_status.sh b/contrib/sandbox_status.sh
new file mode 100644
index 0000000..7bc0731
--- /dev/null
+++ b/contrib/sandbox_status.sh
@@ -0,0 +1,95 @@
+#! /bin/sh
+#
+# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# sandbox_status - identify files added, changed, or removed
+# in CVS working directory
+#
+# Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+#
+# This program should be run in a working directory that has been
+# checked out using CVS. It identifies files that have been added,
+# changed, or removed in the working directory, but not "cvs
+# committed". It also determines whether the files have been "cvs
+# added" or "cvs removed". For directories, it is only practical to
+# determine whether they have been added.
+
+name=sandbox_status
+changes=0
+
+# If we can't run CVS commands in this directory
+cvs status . > /dev/null 2>&1
+if [ $? != 0 ] ; then
+
+ # Bail out
+ echo "$name: there is no version here; bailing out" 1>&2
+ exit 1
+fi
+
+# Identify files added to working directory
+for file in .* * ; do
+
+ # Skip '.' and '..'
+ if [ $file = '.' -o $file = '..' ] ; then
+ continue
+ fi
+
+ # If a regular file
+ if [ -f $file ] ; then
+ if cvs status $file | grep -s '^From:[ ]*New file' ; then
+ echo "file added: $file - not CVS committed"
+ changes=`expr $changes + 1`
+ elif cvs status $file | grep -s '^From:[ ]*no entry for' ; then
+ echo "file added: $file - not CVS added, not CVS committed"
+ changes=`expr $changes + 1`
+ fi
+
+ # Else if a directory
+ elif [ -d $file -a $file != CVS.adm ] ; then
+
+ # Move into it
+ cd $file
+
+ # If CVS commands don't work inside
+ cvs status . > /dev/null 2>&1
+ if [ $? != 0 ] ; then
+ echo "directory added: $file - not CVS added"
+ changes=`expr $changes + 1`
+ fi
+
+ # Move back up
+ cd ..
+ fi
+done
+
+# Identify changed files
+changedfiles=`cvs diff | egrep '^diff' | awk '{print $3}'`
+for file in $changedfiles ; do
+ echo "file changed: $file - not CVS committed"
+ changes=`expr $changes + 1`
+done
+
+# Identify files removed from working directory
+removedfiles=`cvs status | egrep '^File:[ ]*no file' | awk '{print $4}'`
+
+# Determine whether each file has been cvs removed
+for file in $removedfiles ; do
+ if cvs status $file | grep -s '^From:[ ]*-' ; then
+ echo "file removed: $file - not CVS committed"
+ else
+ echo "file removed: $file - not CVS removed, not CVS committed"
+ fi
+ changes=`expr $changes + 1`
+done
+
+exit $changes
diff --git a/contrib/sccs2rcs.in b/contrib/sccs2rcs.in
new file mode 100755
index 0000000..777937a
--- /dev/null
+++ b/contrib/sccs2rcs.in
@@ -0,0 +1,326 @@
+#! @CSH@ -f
+
+# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# Sccs2rcs is a script to convert an existing SCCS
+# history into an RCS history without losing any of
+# the information contained therein.
+# It has been tested under the following OS's:
+# SunOS 3.5, 4.0.3, 4.1
+# Ultrix-32 2.0, 3.1
+#
+# Things to note:
+# + It will NOT delete or alter your ./SCCS history under any circumstances.
+#
+# + Run in a directory where ./SCCS exists and where you can
+# create ./RCS
+#
+# + /usr/local/bin is put in front of the default path.
+# (SCCS under Ultrix is set-uid sccs, bad bad bad, so
+# /usr/local/bin/sccs here fixes that)
+#
+# + Date, time, author, comments, branches, are all preserved.
+#
+# + If a command fails somewhere in the middle, it bombs with
+# a message -- remove what it's done so far and try again.
+# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean"
+# There is no recovery and exit is far from graceful.
+# If a particular module is hanging you up, consider
+# doing it separately; move it from the current area so that
+# the next run will have a better chance or working.
+# Also (for the brave only) you might consider hacking
+# the s-file for simpler problems: I've successfully changed
+# the date of a delta to be in sync, then run "sccs admin -z"
+# on the thing.
+#
+# + After everything finishes, ./SCCS will be moved to ./old-SCCS.
+#
+# This file may be copied, processed, hacked, mutilated, and
+# even destroyed as long as you don't tell anyone you wrote it.
+#
+# Ken Cox
+# Viewlogic Systems, Inc.
+# kenstir@viewlogic.com
+# ...!harvard!cg-atla!viewlog!kenstir
+#
+# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
+#
+# Modified to detect SCCS binary files. If binary, skip the keyword
+# substitution and flag the RCS file as binary (using rcs -i -kb).
+# -Allan G. Schrum schrum@ofsoptics.com agschrum@mindspring.com
+# Fri Sep 26 10:40:40 EDT 2003
+#
+
+
+#we'll assume the user set up the path correctly
+# for the Pmax, /usr/ucb/sccs is suid sccs, what a pain
+# /usr/local/bin/sccs should override /usr/ucb/sccs there
+set path = (/usr/local/bin $path)
+
+
+############################################################
+# Error checking
+#
+if (! -w .) then
+ echo "Error: ./ not writeable by you."
+ exit 1
+endif
+if (! -d SCCS) then
+ echo "Error: ./SCCS directory not found."
+ exit 1
+endif
+set edits = (`sccs tell`)
+if ($#edits) then
+ echo "Error: $#edits file(s) out for edit...clean up before converting."
+ exit 1
+endif
+if (-d RCS) then
+ echo "Warning: RCS directory exists"
+ if (`ls -a RCS | wc -l` > 2) then
+ echo "Error: RCS directory not empty"
+ exit 1
+ endif
+else
+ mkdir RCS
+endif
+
+sccs clean
+
+set logfile = /tmp/sccs2rcs_$$_log
+rm -f $logfile
+set tmpfile = /tmp/sccs2rcs_$$_tmp
+rm -f $tmpfile
+set emptyfile = /tmp/sccs2rcs_$$_empty
+echo -n "" > $emptyfile
+set initialfile = /tmp/sccs2rcs_$$_init
+echo "Initial revision" > $initialfile
+set sedfile = /tmp/sccs2rcs_$$_sed
+rm -f $sedfile
+set revfile = /tmp/sccs2rcs_$$_rev
+rm -f $revfile
+
+# the quotes surround the dollar signs to fool RCS when I check in this script
+set sccs_keywords = (\
+ '%W%[ ]*%G%'\
+ '%W%[ ]*%E%'\
+ '%W%'\
+ '%Z%%M%[ ]*%I%[ ]*%G%'\
+ '%Z%%M%[ ]*%I%[ ]*%E%'\
+ '%M%[ ]*%I%[ ]*%G%'\
+ '%M%[ ]*%I%[ ]*%E%'\
+ '%M%'\
+ '%I%'\
+ '%G%'\
+ '%E%'\
+ '%U%')
+set rcs_keywords = (\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'SunId'$'\
+ '$'SunId'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'RCSfile'$'\
+ '$'Revision'$'\
+ '$'Date'$'\
+ '$'Date'$'\
+ '')
+
+
+############################################################
+# Get some answers from user
+#
+echo ""
+echo "Do you want to be prompted for a description of each"
+echo "file as it is checked in to RCS initially?"
+echo -n "(y=prompt for description, n=null description) [y] ?"
+set ans = $<
+if ((_$ans == _) || (_$ans == _y) || (_$ans == _Y)) then
+ set nodesc = 0
+else
+ set nodesc = 1
+endif
+echo ""
+echo "The default keyword substitutions are as follows and are"
+echo "applied in the order specified:"
+set i = 1
+while ($i <= $#sccs_keywords)
+# echo ' '\"$sccs_keywords[$i]\"' ==> '\"$rcs_keywords[$i]\"
+ echo " $sccs_keywords[$i] ==> $rcs_keywords[$i]"
+ @ i = $i + 1
+end
+echo ""
+echo -n "Do you want to change them [n] ?"
+set ans = $<
+if ((_$ans != _) && (_$ans != _n) && (_$ans != _N)) then
+ echo "You can't always get what you want."
+ echo "Edit this script file and change the variables:"
+ echo ' $sccs_keywords'
+ echo ' $rcs_keywords'
+else
+ echo "good idea."
+endif
+
+# create the sed script
+set i = 1
+while ($i <= $#sccs_keywords)
+ echo "s,$sccs_keywords[$i],$rcs_keywords[$i],g" >> $sedfile
+ @ i = $i + 1
+end
+
+onintr ERROR
+
+sort -k 1,1 /dev/null >& /dev/null
+if ($status == 0) then
+ set sort_each_field = '-k 1 -k 2 -k 3 -k 4 -k 5 -k 6 -k 7 -k 8 -k 9'
+else
+ set sort_each_field = '+0 +1 +2 +3 +4 +5 +6 +7 +8'
+endif
+
+############################################################
+# Loop over every s-file in SCCS dir
+#
+foreach sfile (SCCS/s.*)
+ # get rid of the "s." at the beginning of the name
+ set file = `echo $sfile:t | sed -e "s/^..//"`
+
+ # work on each rev of that file in ascending order
+ set firsttime = 1
+
+ # Only scan the file up to the "I" keyword, then see if
+ # the "f" keyword is set to binary. The SCCS file has
+ # <ctrl>-aI denoting the start of the file (or end of header).
+ set binary = (`sed -e '/^.I/,$d' < $sfile | grep '^.f e 1$'`)
+ #if ($#binary) then
+ # echo This is a binary file
+ #else
+ # echo This is not a binary file
+ #endif
+
+ sccs prs $file | grep "^D " | @AWK@ '{print $2}' | sed -e 's/\./ /g' | sort -n -u $sort_each_field | sed -e 's/ /./g' > $revfile
+ foreach rev (`cat $revfile`)
+ if ($status != 0) goto ERROR
+
+ # get file into current dir and get stats
+
+ # Is the substr stuff and the +0 in the following awk script really
+ # necessary? It seems to me that if we didn't find the date format
+ # we expected in the output we have other problems.
+ # Note: Solaris awk does not like the following line. Use gawk
+ # mawk, or nawk instead.
+ set date = `sccs prs -r$rev $file | @AWK@ '/^D / {print (substr($3,0,2)+0<70?20:19) $3, $4; exit}'`
+ set author = `sccs prs -r$rev $file | @AWK@ '/^D / {print $5; exit}'`
+ echo ""
+ echo "==> file $file, rev=$rev, date=$date, author=$author"
+ sccs edit -r$rev $file >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked out of SCCS
+
+ # add RCS keywords in place of SCCS keywords (only if not binary)
+ if ($#binary == 0) then
+ sed -f $sedfile $file > $tmpfile
+ if ($status != 0) goto ERROR
+ echo performed keyword substitutions
+ cp $tmpfile $file
+ endif
+
+ # check file into RCS
+ if ($firsttime) then
+ set firsttime = 0
+
+ if ($#binary) then
+ echo this is a binary file
+ # Mark initial, empty file as binary
+ rcs -i -kb -t$emptyfile $file
+ endif
+
+ if ($nodesc) then
+ echo about to do ci
+ echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file
+ ci -f -r$rev -d"$date" -w$author -t$emptyfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS without description
+ else
+ echo ""
+ echo Enter a brief description of the file $file \(end w/ Ctrl-D\):
+ cat > $tmpfile
+ ci -f -r$rev -d"$date" -w$author -t$tmpfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS
+ endif
+ else
+ # get RCS lock
+ set lckrev = `echo $rev | sed -e 's/\.[0-9]*$//'`
+ if ("$lckrev" =~ [0-9]*.*) then
+ # need to lock the brach -- it is OK if the lock fails
+ rcs -l$lckrev $file >>& $logfile
+ else
+ # need to lock the trunk -- must succeed
+ rcs -l $file >>& $logfile
+ if ($status != 0) goto ERROR
+ endif
+ echo got lock
+ sccs prs -r$rev $file | grep "." > $tmpfile
+ # it's OK if grep fails here and gives status == 1
+ # put the delta message in $tmpfile
+ ed $tmpfile >>& $logfile <<EOF
+/COMMENTS
+1,.d
+w
+q
+EOF
+ ci -f -r$rev -d"$date" -w$author $file < $tmpfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked into RCS
+ endif
+ sccs unedit $file >>& $logfile
+ if ($status != 0) goto ERROR
+ end
+ rm -f $file
+end
+
+
+############################################################
+# Clean up
+#
+echo cleaning up...
+mv SCCS old-SCCS
+rm -f $tmpfile $emptyfile $initialfile $sedfile
+echo ===================================================
+echo " Conversion Completed Successfully"
+echo ""
+echo " SCCS history now in old-SCCS/"
+echo ===================================================
+set exitval = 0
+goto cleanup
+
+ERROR:
+foreach f (`sccs tell`)
+ sccs unedit $f
+end
+echo ""
+echo ""
+echo Danger\! Danger\!
+echo Some command exited with a non-zero exit status.
+echo Log file exists in $logfile.
+echo ""
+echo Incomplete history in ./RCS -- remove it
+echo Original unchanged history in ./SCCS
+set exitval = 1
+
+cleanup:
+# leave log file
+rm -f $tmpfile $emptyfile $initialfile $sedfile $revfile
+
+exit $exitval
diff --git a/contrib/validate_repo.in b/contrib/validate_repo.in
new file mode 100644
index 0000000..6fdbead
--- /dev/null
+++ b/contrib/validate_repo.in
@@ -0,0 +1,856 @@
+#! @PERL@ -w
+########################################################################
+#
+# Copyright (c) 2000, 2001 by Donald Sharp <sharpd@cisco.com>
+# All Rights Reserved
+#
+# Some portions Copyright (c) 2002, 2003 by
+# Derek R. Price <mailto:derek@ximbiot.com>
+# & Ximbiot <http://ximbiot.com>.
+# All rights reserved.
+#
+# Permission is granted to copy and/or distribute this file, with or
+# without modifications, provided this notice is preserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+########################################################################
+
+=head1 validate_repo.pl
+
+Script to check the integrity of the Repository.
+
+=head1 SYNOPSIS
+
+ perldoc validate_repo.pl
+ validate_repo.pl --help [--verbose!]
+ validate_repo.pl [--verbose!] [--cvsroot=CVSROOT] [--exec=SCRIPT]...
+ [--all-revisions!] [module]...
+
+=head1 DESCRIPTION
+
+This script will search through a repository and determine if any of the
+files in it are corrupted.
+
+This is normally accomplished by checking out all I<important> revisions, where
+I<important> revisions are defined as the smallest set which, when checked out,
+will cause each and every revision's integrity to be verified. This resolves
+to the most recent revision on each branch and the first and last revisions on
+the trunk.
+
+Please do not run this script inside of the repository itself. This will cause
+it too fail.
+
+=head1 OPTIONS
+
+=over
+
+=item C<--help>
+
+Print this very help text (or, with C<--verbose>, act like
+C<perldoc validate_repo.pl>).
+
+=item C<-a> or C<--all-revisions>
+
+Check out each and every revision rather than just the I<important> ones.
+This flag is useful with C<--exec> to execute the C<SCRIPT> (from C<--exec>
+below) on a checked out copy of each and every revision.
+
+=item C<-d> or C<--cvsroot=CVSROOT>
+
+Use repository specified by C<CVSROOT>. Defaults to the contents of the
+F<./CVS/Root> file when it exists and is readable, then to the contents of the
+C<$CVSROOT> environment variable when it is set and non-empty.
+
+=item C<-e> or C<--exec=SCRIPT>
+
+Execute (as from command prompt) C<SCRIPT> if it exists as a file, is readable,
+and is executable, or evaluate (as a perl script) C<SCRIPT> for a checked out
+copy of each I<important> revision of each RCS archive in CVSROOT. Executed
+scripts are passed C<CVSROOT FILE REVISION FNO>, where C<CVSROOT> is what
+you'd think, C<FILE> is the path to the file relative to C<CVSROOT> and
+suitable for use as an argument to C<cvs co>, C<cvs rlog>, and so on,
+C<REVISION> is the revision of the checked out file, and C<FNO> is the file
+number of the open, read-only file descriptor containing the checked out
+contents of revision C<REVISION> of C<FILE>. An evaluated C<SCRIPT> will find
+the same four arguments in the same order in C<@_>, except that C<FNO> will be
+an open file handle.
+
+With C<--all-revisions>, execute or evaluate C<SCRIPT> for a checked out
+version of each revsion in the RCS archive.
+
+=item C<-v> or C<--verbose>
+
+Print verbose debugging information (or, when specified with C<--help>, act
+like C<perldoc validate_repo.pl>).
+
+=head1 ARGUMENTS
+
+=over
+
+=item C<modules>
+
+The module in the repository to examine. Defaults to the contents of the
+F<./CVS/Repository> file when it exists and is readable, then to F<.>
+(all modules).
+
+=head1 EXAMPLES
+
+ setenv CVSROOT /release/111/cvs
+ validate_repo.pl
+
+
+ validate_repo.pl -d /another/cvsroot --verbose --exec '
+ system "grep \"This string means Im a bad, bad file!\" <&"
+ . fileno( $_[3] )
+ . ">/dev/null"
+ or die "Revision $_[2] of $_[0]/$_[1],v is bad, bad, bad!"'
+
+=head1 SEE ALSO
+
+None.
+
+=cut
+
+######################################################################
+# MODULES #
+######################################################################
+use strict;
+
+use Fcntl qw( F_GETFD F_SETFD );
+use File::Find;
+use File::Basename;
+use File::Path;
+use File::Spec;
+use Getopt::Long;
+use IO::File;
+use Pod::Usage;
+
+######################################################################
+# GLOBALS #
+######################################################################
+
+use vars qw(
+ $all_revisions
+ $cvsroot
+ @extra_files
+ @ignore_files
+ $ignored_files
+ @invalid_revs
+ @list_of_broken_files
+ @scripts
+ $total_files
+ $total_interesting_revisions
+ $total_revisions
+ $verbose
+ );
+
+
+
+######################################################################
+# SUBROUTINES #
+######################################################################
+
+######################################################################
+#
+# NAME :
+# main
+#
+# PURPOSE :
+# To search the repository for broken files
+#
+# PARAMETERS :
+# NONE
+#
+# GLOBALS :
+# $cvsroot - The CVS repository to search through.
+# $ENV{ CVSROOT } - The default CVS repository to search through.
+# @list_of_broken_files - The list of files that need to
+# be fixed.
+# $verbose - is verbose mode on?
+# @scripts - scripts to run on checked out files.
+# $total_revisions - The number of revisions considered
+# $total_interesting_revisions - The number of revisions used
+# $total_files - The total number of files looked at.
+#
+# RETURNS :
+# A list of broken files
+#
+# COMMENTS :
+# Do not run this script inside the repository. Choose
+# a nice safe spot( like /tmp ) outside of the repository.
+#
+######################################################################
+sub main
+{
+ my $help;
+
+ $ignored_files = 0;
+ $total_files = 0;
+ $total_interesting_revisions = 0;
+ $total_revisions = 0;
+
+ Getopt::Long::Configure( "bundling" );
+ unless( GetOptions(
+ 'all-revisions|a!' => \$all_revisions,
+ 'cvsroot|d=s' => \$cvsroot,
+ 'exec|e=s' => \@scripts,
+ 'help|h|?!' => \$help,
+ 'verbose|v!' => \$verbose
+ )
+ )
+ {
+ pod2usage( 2 );
+ exit 2;
+ }
+
+ pod2usage( -exitval => 2,
+ -verbose => $verbose ? 2 : 1,
+ -output => \*STDOUT )
+ if $help;
+
+ verbose( "Verbose Mode Turned On\n" );
+
+ if( !$cvsroot && -f "CVS/Root" && -r "CVS/Root" )
+ {
+ my $file = new IO::File "< CVS/Root";
+ $cvsroot = $file->getline;
+ chomp $cvsroot;
+ }
+ $cvsroot = $ENV{'CVSROOT'} unless $cvsroot;
+ pod2usage( "error: Must set CVSROOT" ) unless $cvsroot;
+
+ if( $cvsroot =~ /^:\w+:/ && $cvsroot !~ /^:local:/
+ || $cvsroot =~ /@/ )
+ {
+ print STDERR "CVSROOT must be :local:\n";
+ exit 2;
+ }
+
+ for (@scripts)
+ {
+ $_ = File::Spec->rel2abs( $_ ) unless /\n/ || !-x $_;
+ }
+
+
+ if( !scalar( @ARGV ) && -f "CVS/Repository" && -r "CVS/Repository" )
+ {
+ my $file = new IO::File "< CVS/Repository";
+ my $module = $file->getline;
+ chomp $module;
+ push @ARGV, $module;
+ }
+
+ push @ARGV, "." unless( scalar @ARGV );
+
+ foreach my $directory_to_look_at ( @ARGV )
+ {
+ $directory_to_look_at = File::Spec->catfile( $cvsroot,
+ $directory_to_look_at );
+
+ my $sym_count = 0;
+ while( -l $directory_to_look_at )
+ {
+ $directory_to_look_at = readlink( $directory_to_look_at );
+ $sym_count += 1;
+ die( "Encountered too many symlinks for CVSROOT ($cvsroot)\n" )
+ if( $sym_count > 5 );
+ }
+
+ # Remove indirections.
+ $directory_to_look_at =~ s#(/+.)*$##o;
+
+ verbose( "Processing: $directory_to_look_at\n" );
+ @ignore_files = get_ignore_files_from_cvsroot( $directory_to_look_at );
+ find( \&process_file, $directory_to_look_at );
+ }
+
+ print "List of corrupted files\n" if @list_of_broken_files;
+ foreach my $broken ( @list_of_broken_files )
+ {
+ print( "**** File: $broken\n" );
+ }
+
+ print "List of Files containing invalid revisions:\n"
+ if @invalid_revs;
+ foreach ( @invalid_revs )
+ {
+ print( "**** File: ($_->{'rev'}) $_->{'file'}\n" );
+ }
+
+ print "List of Files That Don't belong in Repository:\n"
+ if @extra_files;
+ foreach my $extra ( @extra_files )
+ {
+ print( "**** File: $extra\n" );
+ }
+ print( "Total Files: $total_files Corrupted files: "
+ . scalar( @list_of_broken_files )
+ . " Invalid revs: "
+ . scalar( @invalid_revs )
+ . " Extra files: "
+ . scalar( @extra_files )
+ . " Ignored Files: $ignored_files\n" );
+ print( "Total Revisions: $total_revisions Interesting Revisions: $total_interesting_revisions\n" );
+}
+
+
+
+sub verbose
+{
+ print STDERR @_ if $verbose;
+}
+
+
+
+######################################################################
+#
+# NAME :
+# process_file
+#
+# PURPOSE :
+# This function is called by the find function, its purpose
+# is to decide if it is important to look at a file or not. When
+# a file is important, we log it or call &look_at_cvs_file on it.
+#
+# ALGORITHM
+# 1) If the file is an archive file, we call &look_at_cvs_file on
+# it.
+# 2) Else, if the file is not in the ignore list, we store its name
+# for later.
+#
+# PARAMETERS :
+# NONE
+#
+# GLOBALS :
+# $cvsroot - The CVS repository to search through
+# @ignore_files - File patterns we can afford to ignore.
+# $File::Find::name - The absolute path of the file being examined.
+#
+# RETURNS :
+# NONE
+#
+# COMMENTS :
+# NONE
+#
+######################################################################
+sub process_file
+{
+ if( ! -d $File::Find::name )
+ {
+ my $path = $File::Find::name;
+ $path =~ s#^$cvsroot/(\./)*##;
+ $total_files++;
+
+ verbose( "Examining `$path'\n" );
+
+ if( $path =~ s/,v$// )
+ {
+ look_at_cvs_file( $path );
+ }
+ elsif( !grep { $path =~ $_ } @ignore_files )
+ {
+ push @extra_files, $path;
+ verbose( "Adding unrecognized file `$path' to corrupted list.\n" );
+ }
+ else
+ {
+ $ignored_files++;
+ verbose( "Ignoring `$path'\n" );
+ }
+ }
+}
+
+######################################################################
+#
+# NAME :
+# look_at_cvs_file
+#
+# PURPOSE :
+# To decide if a file is broken or not. The algorithm is:
+# a) Get the revision history for the file.
+# - If that fails the file is broken, save the fact
+# and continue processing other files.
+# - If that succeeds we have a list of revisions.
+# b) For each revision call &check_revision on the file.
+# - If that fails the file is broken, save the fact
+# and continue processing other files.
+# c) Continue on
+#
+# PARAMETERS :
+# $file - The path of the file to look at, relative to $cvsroot and
+# suitable for use as an argument to `cvs co', `cvs rlog', and
+# the rest of CVS's r* commands.
+#
+# GLOBALS :
+# NONE
+#
+# RETURNS :
+# NONE
+#
+# COMMENTS :
+# We have to handle Attic files in a special manner.
+# Basically remove the Attic from the string if it
+# exists at the end of the $path variable.
+#
+######################################################################
+sub look_at_cvs_file
+{
+ my( $file ) = @_;
+ my( $name, $path ) = fileparse( $file );
+
+ $file = $path . $name if $path =~ s#Attic/$##;
+
+ my( $finfo, $rinfo ) = get_history( $file );
+
+ unless( defined $rinfo )
+ {
+ verbose( "\t`$file' is corrupted. It was determined to contain no\n"
+ . "\trevisions via a cvs rlog command\n" );
+ push( @list_of_broken_files, $file );
+ return();
+ }
+
+ my @int_revisions =
+ $all_revisions ? keys %$rinfo
+ : find_interesting_revisions( keys %$rinfo );
+
+ foreach my $revision ( @int_revisions )
+ {
+ verbose( "\t\tLooking at Revision: $revision\n" );
+ if( !check_revision( $file, $revision, $finfo, $rinfo ) )
+ {
+ verbose( "\t$file is corrupted in revision: $revision\n" );
+ push( @list_of_broken_files, $file );
+ return();
+ }
+ }
+}
+
+######################################################################
+#
+# NAME :
+# get_history
+#
+# PURPOSE :
+# To retrieve an array of revision numbers.
+#
+# PARAMETERS :
+# $file - The file to retrieve the revision numbers for
+#
+# GLOBALS :
+# $cvsroot - the CVSROOT we are examining
+#
+# RETURNS :
+# On Success - A hash of revision info, indexed by revision numbers.
+# On Failure - undef.
+#
+# COMMENTS :
+# The $_ is saved off because The File::find functionality
+# expects the $_ to not have been changed.
+# The -N option for the rlog command means to spit out
+# tags or branch names.
+#
+######################################################################
+sub get_history
+{
+ my( $file ) = @_;
+ $file =~ s/(["\$`\\])/\\$1/g;
+ my %finfo; # Info about the file.
+ my %rinfo; # Info about revisions in the file.
+ my $revision;
+
+ my $fh = new IO::File( "cvs -d $cvsroot rlog -N \"$file\""
+ . ($verbose ? "" : " 2>&1") . " |" )
+ or die( "unable to run `cvs rlog', help" );
+
+ my $ignore = -1;
+ while( my $line = $fh->getline )
+ {
+ if( $ignore == 1 )
+ {
+ if( ( $revision ) = $line =~ /^revision (.*?)(\tlocked by: \S+;)?$/ )
+ {
+ unless($revision =~ m/^\d+\.\d+(?:\.\d+\.\d+)*$/)
+ {
+ push @invalid_revs, { 'file' => $file, 'rev' => $revision };
+ verbose( "Adding invalid revision `$revision' of file `$file' to invalid revs list.\n" );
+ }
+
+ $ignore++;
+ next;
+ }
+
+ # We require ---- before a ^revision tag, not a revision
+ # after every ----.
+ $ignore = 0;
+ }
+ if( $ignore == 2 )
+ {
+ if( my ( $date, $author, $state ) =
+ $line =~ /^date: (\S+ \S+); author: ([^;]+); state: (\S+);/ )
+ {
+ $rinfo{$revision} =
+ {
+ 'date' => $date,
+ 'author' => $author,
+ 'state' => $state
+ }
+ }
+ else
+ {
+ die "Couldn't read date/author/state for revision $revision\n"
+ . "of $file from `cvs rlog'.\n"
+ . "line = $line";
+ }
+ $ignore = 0;
+ next;
+ }
+ if( $ignore == -1 )
+ {
+ # Until we find the first ---- below, we can read general file info
+ if( my ( $kwmode ) =
+ $line =~ /^keyword substitution: (\S+)$/ )
+ {
+ $finfo{'kwmode'} = $kwmode;
+ next;
+ }
+ }
+ # rlog outputs a "----" line before the actual revision
+ # without this we'll pick up peoples comments if they
+ # happen to start with revision
+ if( $line =~ /^----------------------------$/ )
+ {
+ # Catch this case when $ignore == -1 or 0
+ $ignore = 1;
+ next;
+ }
+ }
+ if( $verbose )
+ {
+ for (keys %rinfo)
+ {
+ verbose( "Revision $_: " );
+ verbose( join( ", ", %{$rinfo{$_}} ) );
+ verbose( "\n" );
+ }
+ }
+
+ die "Syserr closing pipe from `cvs co': $!"
+ if !$fh->close && $!;
+ return if $?;
+
+ return( \%finfo, %rinfo ? \%rinfo : undef );
+}
+
+######################################################################
+#
+# NAME :
+# check_revision
+#
+# PURPOSE :
+# Given a file and a revision number ensure that we can check out that
+# file.
+#
+# If the user has specified any scripts (passed in as arguments to --exec
+# and stored in @scripts), run them on the checked out revision. If
+# executable scripts exit with a non-zero status or evaluated scripts set
+# $@ (die), print $status or $@ as a warning.
+#
+# PARAMETERS :
+# $file - The file to look at.
+# $revision - The revision to look at.
+# $rinfo - A reference to a hash containing information about the
+# revisions in $file.
+# For instance, $rinfo->{$revision}->{'date'} contains the
+# date revision $revision was committed.
+#
+# GLOBALS :
+# NONE
+#
+# RETURNS :
+# If we can get the File - 1
+# If we can not get the File - 0
+#
+# COMMENTS :
+# cvs command line options are as followed:
+# -n - Do not run any checkout program as specified by the -o
+# option in the modules file
+# -p - Put all output to standard out.
+# -r - The revision of the file that we would like to look at.
+# -ko - Get the revision exactly as checked in - do not allow
+# RCS keyword substitution.
+# Please note that cvs will return 0 for being able to successfully
+# read the file and 1 for failure to read the file.
+#
+######################################################################
+sub check_revision
+{
+ my( $file, $revision, $finfo, $rinfo ) = @_;
+ $file =~ s/(["\$`\\])/\\$1/g;
+
+ # Allow binaries to be checked out as such. Otherwise, use -ko to avoid
+ # replacing keywords in the files.
+ my $kwmode = $finfo->{'kwmode'} eq 'b' ? '' : ' -ko';
+ my $command = "cvs -d $cvsroot co$kwmode -npr $revision \"$file\"";
+ my $ret_code;
+ verbose( "Executing `$command'.\n" );
+ if( @scripts )
+ {
+ my $fh = new IO::File $command . ($verbose ? "" : " 2>&1") . " |";
+ fcntl( $fh, F_SETFD, 0 )
+ or die "Can't clear close-on-exec flag on filehandle: $!";
+ my $count;
+ foreach my $script (@scripts)
+ {
+ $count++;
+ if( $script !~ /\n/ && -x $script )
+ {
+ # exec external script
+ my $status = system $script, $cvsroot, $file, $revision,
+ fileno( $fh );
+ warn "`$script $cvsroot $file $revision "
+ . fileno( $fh )
+ . "' exited with code $status"
+ if $status;
+ }
+ else
+ {
+ # eval script
+ @_ = ($cvsroot, $file, $revision, $fh);
+ eval $script;
+ warn "script $count ($cvsroot, $file, $revision, $fh) exited abnormally: $@"
+ if $@;
+ }
+ }
+ # Read any data left so the close will work even if our called script
+ # didn't finish reading the data.
+ () = $fh->getlines; # force list context
+ die "Syserr closing pipe from `cvs co': $!"
+ if !$fh->close && $!;
+ $ret_code = $?;
+ }
+ else
+ {
+ $ret_code = 0xffff & system "$command >/dev/null 2>&1";
+ }
+
+ return !$ret_code;
+}
+
+######################################################################
+#
+# NAME :
+# find_interesting_revisions
+#
+# PURPOSE :
+# CVS stores information in a logical manner. We only really
+# need to look at some interestin revisions. These are:
+# The first version
+# And the last version on every branch.
+# This is because cvs stores changes descending from
+# main line. ie suppose the last version on mainline is 1.6
+# version 1.6 of the file is stored in toto. version 1.5
+# is stored as a diff between 1.5 and 1.6. 1.4 is stored
+# as a diff between 1.5 and 1.4.
+# branches are stored a little differently. They are
+# stored in ascending order. Suppose there is a branch
+# on 1.4 of the file. The first branches revision number
+# would be 1.4.1.1. This is stored as a diff between
+# version 1.4 and 1.4.1.1. The 1.4.1.2 version is stored
+# as a diff between 1.4.1.1 and 1.4.1.2. Therefore
+# we are only interested in the earliest revision number
+# and the highest revision number on a branch.
+#
+# PARAMETERS :
+# @revisions - The list of revisions to find interesting ones
+#
+# GLOBALS :
+# NONE
+#
+# RETURNS :
+# @new_revisions - The list of revisions that we find interesting
+#
+# COMMENTS :
+#
+######################################################################
+sub find_interesting_revisions
+{
+ my( @revisions ) = @_;
+ my @new_revisions;
+ my %max_branch_revision;
+ my $branch_number;
+ my $branch_rev;
+ my $key;
+ my $value;
+
+ foreach my $revision( @revisions )
+ {
+ ( $branch_number, $branch_rev ) = branch_split( $revision );
+ $max_branch_revision{$branch_number} = $branch_rev
+ if( !exists $max_branch_revision{$branch_number}
+ || $max_branch_revision{$branch_number} < $branch_rev );
+ }
+
+ push( @new_revisions, "1.1" ) unless (exists $max_branch_revision{1}
+ && $max_branch_revision{1} == 1);
+ while( ( $key, $value ) = each ( %max_branch_revision ) )
+ {
+ push( @new_revisions, $key . "." . $value );
+ }
+
+ my $nrc;
+ my $rc;
+
+ $rc = @revisions;
+ $nrc = @new_revisions;
+
+ $total_revisions += $rc;
+ $total_interesting_revisions += $nrc;
+
+ verbose( "\t\tTotal Revisions: $rc Interesting Revisions: $nrc\n" );
+
+ return( @new_revisions );
+}
+
+
+
+######################################################################
+#
+# NAME :
+# branch_split
+#
+# PURPOSE :
+# To split up a revision number up into the branch part and
+# the number part. For Instance:
+# 1.1.1.1 - is split 1.1.1 and 1
+# 2.1 - is split 2 and 1
+# 1.3.4.5.7.8 - is split 1.3.4.5.7 and 8
+#
+# PARAMETERS :
+# $revision - The revision to look at.
+#
+# GLOBALS :
+# NONE
+#
+# RETURNS :
+# ( $branch, $revision ) -
+# $branch - The branch part of the revision number
+# $revision - The revision part of the revision number
+#
+# COMMENTS :
+# NONE
+#
+######################################################################
+sub branch_split
+{
+ my( $revision ) = @_;
+ my $branch;
+ my $version;
+ my @split_rev;
+ my $count;
+
+ @split_rev = split /\./, $revision;
+
+ my $numbers = @split_rev;
+ @split_rev = reverse( @split_rev );
+ $branch = pop( @split_rev );
+ for( $count = 0; $count < $numbers - 2 ; $count++ )
+ {
+ $branch .= "." . pop( @split_rev );
+ }
+
+ return( $branch, pop( @split_rev ) );
+}
+
+######################################################################
+#
+# NAME :
+# get_ignore_files_from_cvsroot
+#
+# PURPOSE :
+# Retrieve the list of files from the CVSROOT/ directory
+# that should be ignored.
+# These are the regular files (e.g., commitinfo, loginfo)
+# and those specified in the checkoutlist file.
+#
+# PARAMETERS :
+# The CVSROOT
+#
+# GLOBALS :
+# NONE
+#
+# RETURNS :
+# @ignore - the list of files to ignore
+#
+# COMMENTS :
+# NONE
+#
+######################################################################
+sub get_ignore_files_from_cvsroot {
+ my( $cvsroot ) = @_;
+ my @ignore = (
+ qr{CVS/fileattr$}o,
+ qr{^(./)?CVSROOT/.#[^/]*$}o,
+ qr{^(./)?CVSROOT/checkoutlist$}o,
+ qr{^(./)?CVSROOT/commitinfo$}o,
+ qr{^(./)?CVSROOT/config$}o,
+ qr{^(./)?CVSROOT/cvsignore$}o,
+ qr{^(./)?CVSROOT/cvswrappers$}o,
+ qr{^(./)?CVSROOT/editinfo$}o,
+ qr{^(./)?CVSROOT/history$}o,
+ qr{^(./)?CVSROOT/loginfo$}o,
+ qr{^(./)?CVSROOT/modules$}o,
+ qr{^(./)?CVSROOT/notify$}o,
+ qr{^(./)?CVSROOT/passwd$}o,
+ qr{^(./)?CVSROOT/postadmin$}o,
+ qr{^(./)?CVSROOT/postproxy$}o,
+ qr{^(./)?CVSROOT/posttag$}o,
+ qr{^(./)?CVSROOT/postwatch$}o,
+ qr{^(./)?CVSROOT/preproxy$}o,
+ qr{^(./)?CVSROOT/rcsinfo$}o,
+ qr{^(./)?CVSROOT/readers$}o,
+ qr{^(./)?CVSROOT/taginfo$}o,
+ qr{^(./)?CVSROOT/val-tags$}o,
+ qr{^(./)?CVSROOT/verifymsg$}o,
+ qr{^(./)?CVSROOT/writers$}o
+ );
+
+ my $checkoutlist_file = "$cvsroot/CVSROOT/checkoutlist";
+ if( -f $checkoutlist_file && -r $checkoutlist_file )
+ {
+ my $fh = new IO::File "<$checkoutlist_file"
+ or die "Unable to read checkoutlist file ($checkoutlist_file): $!\n";
+
+ my @list = $fh->getlines;
+ chomp( @list );
+ $fh->close or die( "Unable to close checkoutlist file: $!\n" );
+
+ foreach my $line( @list )
+ {
+ next if( $line =~ /^#/ || $line =~ /^\s*$/ );
+ $line =~ s/^\s*(\S+)(\s+.*)?$/$1/;
+ push @ignore, qr{^(./)?CVSROOT/$line$};
+ }
+ }
+
+ return @ignore;
+}
+
+
+
+######
+###### Go.
+######
+
+exit main @ARGV;
+
+# vim:tabstop=4:shiftwidth=4
diff --git a/cvs-format.el b/cvs-format.el
new file mode 100644
index 0000000..b3ca77d
--- /dev/null
+++ b/cvs-format.el
@@ -0,0 +1,145 @@
+;; -*- lisp-interaction -*-
+;; -*- emacs-lisp -*-
+;;
+;; Set emacs up for editing code using CVS indentation conventions.
+;; See HACKING for more on what those conventions are.
+;; To use, put in your .emacs:
+;; (load "c-mode")
+;; (load "cvs-format.el")
+;; You need to load c-mode first or else when c-mode autoloads it will
+;; clobber the settings from cvs-format.el. Using c-mode-hook perhaps would
+;; be a cleaner way to handle that. Or see below about (set-c-style "BSD").
+;;
+;; Credits: Originally from the personal .emacs file of Rich Pixley,
+;; then rich@cygnus.com, circa 1992. He sez "feel free to copy."
+;;
+;; If you have an Emacs that does not have "c-mode", but does have
+;; "cc-mode" then put this into your .emacs:
+;; (require 'cc-mode)
+;; (load "cvs-format.el")
+;; (add-hook 'c-mode-hook '(lambda () (c-set-style "cvshome")))
+;;
+;; Credit: From the personal .emacs file of Mark D. Baushke
+; circa 2005. Feel free to do anything you want with it.
+
+;;
+;;
+;; This section sets constants used by c-mode for formating
+;;
+;;
+
+;; If `c-auto-newline' is non-`nil', newlines are inserted both
+;;before and after braces that you insert, and after colons and semicolons.
+;;Correct C indentation is done on all the lines that are made this way.
+
+(if (boundp 'c-auto-newline)
+ (setq c-auto-newline nil))
+
+
+;;*Non-nil means TAB in C mode should always reindent the current line,
+;;regardless of where in the line point is when the TAB command is used.
+;;It might be desirable to set this to nil for CVS, since unlike GNU
+;; CVS often uses comments over to the right separated by TABs.
+;; Depends some on whether you're in the habit of using TAB to
+;; reindent.
+;(setq c-tab-always-indent nil)
+
+;;; It seems to me that
+;;; `M-x set-c-style BSD RET'
+;;; or
+;;; (set-c-style "BSD")
+;;; takes care of the indentation parameters correctly.
+
+
+;; C does not have anything analogous to particular function names for which
+;;special forms of indentation are desirable. However, it has a different
+;;need for customization facilities: many different styles of C indentation
+;;are in common use.
+;;
+;; There are six variables you can set to control the style that Emacs C
+;;mode will use.
+;;
+;;`c-indent-level'
+;; Indentation of C statements within surrounding block. The surrounding
+;; block's indentation is the indentation of the line on which the
+;; open-brace appears.
+
+(if (boundp 'c-indent-level)
+ (setq c-indent-level 4))
+
+;;`c-continued-statement-offset'
+;; Extra indentation given to a substatement, such as the then-clause of
+;; an if or body of a while.
+
+(if (boundp 'c-continued-statement-offset)
+ (setq c-continued-statement-offset 4))
+
+;;`c-brace-offset'
+;; Extra indentation for line if it starts with an open brace.
+
+(if (boundp 'c-brace-offset)
+ (setq c-brace-offset -4))
+
+;;`c-brace-imaginary-offset'
+;; An open brace following other text is treated as if it were this far
+;; to the right of the start of its line.
+
+(if (boundp 'c-brace-imaginary-offset)
+ (setq c-brace-imaginary-offset 0))
+
+;;`c-argdecl-indent'
+;; Indentation level of declarations of C function arguments.
+
+(if (boundp 'c-argdecl-indent)
+ (setq c-argdecl-indent 4))
+
+;;`c-label-offset'
+;; Extra indentation for line that is a label, or case or default.
+;; This doesn't quite do the right thing for CVS switches, which use the
+;; switch (foo)
+;; {
+;; case 0:
+;; break;
+;; style. But if one manually aligns the first case, then the rest
+;; should work OK.
+(if (boundp 'c-label-offset)
+ (setq c-label-offset -2))
+
+;;
+;;
+;; This section sets constants used by cc-mode for formating
+;;
+;;
+
+;; Folks that are using cc-mode in the more modern version of Emacs
+;; will likely find this useful
+
+(if (and (fboundp 'featurep)
+ (featurep 'cc-styles)
+ (fboundp 'c-add-style))
+ (c-add-style "cvshome"
+ '((c-brace-offset . -4)
+ (c-basic-offset . 4)
+ (c-continued-statement-offset . (4 . 4))
+ (c-offsets-alist
+ . ((statement-block-intro . +)
+ (knr-argdecl-intro . 4)
+ (substatement-open . 0)
+ (label . 2)
+ (case-label . 2)
+ (statement-case-open . +)
+ (statement-cont . +)
+ (arglist-intro . c-lineup-arglist-intro-after-paren)
+ (arglist-close . c-lineup-arglist)
+ (inline-open . 0)
+ (brace-list-open . 0)))
+ (c-special-indent-hook . c-gnu-impose-minimum)
+ (c-block-comment-prefix . ""))))
+
+;; You may now use the following when you wish to make use of the style:
+;; `M-x c-set-style RET cvshome RET'
+;; or
+;; (c-set-style "cvshome")
+;; to take care of things.
+
+;;;; eof
diff --git a/cvs.spec b/cvs.spec
new file mode 100644
index 0000000..c346996
--- /dev/null
+++ b/cvs.spec
@@ -0,0 +1,239 @@
+Summary: A version control system.
+Name: cvs
+Version: 1.12.13
+Release: 1
+License: GPL
+Group: Development/Tools
+Source: http://savannah.nongnu.org/download/cvs/%{name}-%{version}.tar.bz2
+URL: http://cvs.nongnu.org/
+Prereq: /sbin/install-info
+Prefix: %{_prefix}
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+%description
+Concurrent Versions System (CVS) is a version control system which can
+record the history of your files (usually, but not always, source
+code). CVS only stores the differences between versions, instead of
+every version of every file you've ever created. CVS also keeps a log
+of who, when and why changes occurred.
+
+CVS is very helpful for managing releases and controlling the
+concurrent editing of source files among multiple authors. Instead of
+providing version control for a collection of files in a single
+directory, CVS provides version control for a hierarchical collection
+of directories consisting of revision controlled files. These
+directories and files can then be combined together to form a software
+release.
+
+Install the %{name} package if you need to use a version control system.
+
+%define gssapi %(test -r /usr/kerberos/lib/libkrb5.a && echo 1 || echo 0)
+%if %gssapi
+%package krb5
+Summary: A version control system with Kerberos authentication.
+Group: Development/Tools
+Requires: %{name}
+BuildRequires: krb5-devel
+
+%description krb5
+Concurrent Versions System (CVS) is a version control system which can
+record the history of your files (usually, but not always, source
+code). CVS only stores the differences between versions, instead of
+every version of every file you've ever created. CVS also keeps a log
+of who, when and why changes occurred.
+
+CVS is very helpful for managing releases and controlling the
+concurrent editing of source files among multiple authors. Instead of
+providing version control for a collection of files in a single
+directory, CVS provides version control for a hierarchical collection
+of directories consisting of revision controlled files. These
+directories and files can then be combined together to form a software
+release.
+
+This package contains only a Kerberized version of the CVS binary. You should
+install the base %{name} package to get the standard CVS distribution.
+
+Install the Kerberos version of the %{name} package if you need to use a version
+control system with Kerberos authentication and encryption.
+
+%define _kerberosdir %{prefix}/kerberos
+%define _kerberosbindir %{_kerberosdir}/bin
+%endif
+
+%prep
+%setup -q
+
+%build
+# The Kerberized binary
+%if %gssapi
+%configure --with-gssapi=/usr/kerberos --enable-encryption
+
+make LDFLAGS=-s
+
+mv src/cvs src/cvs.krb5
+%endif
+
+# The standard package
+%configure --without-gssapi
+
+make LDFLAGS=-s
+
+%install
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+
+%makeinstall
+# The Kerberized binary
+%if %gssapi
+build-aux/install-sh src/cvs.krb5 $RPM_BUILD_ROOT%{_kerberosbindir}/cvs
+%endif
+# forcefully compress the info pages so that install-info will work properly
+# in the %%post
+gzip $RPM_BUILD_ROOT/%{_infodir}/cvs* || true
+rm -f $RPM_BUILD_ROOT/%{_infodir}/dir
+
+%clean
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+
+%post
+/sbin/install-info /%{_infodir}/cvs.info.gz /%{_infodir}/dir
+/sbin/install-info /%{_infodir}/cvsclient.info.gz /%{_infodir}/dir
+# Remove any existing uncompressed versions of the info files since
+# install-info doesn't and info doesn't seem to be very good at spotting that
+# its uncompressed cache is out of date.
+rm -f /%{_infodir}/cvs.info /%{_infodir}/cvs.info-? /%{_infodir}/cvs.info-??
+rm -f /%{_infodir}/cvsclient.info /%{_infodir}/cvsclient.info-?
+rm -f /%{_infodir}/cvsclient.info-??
+%preun
+if [ $1 = 0 ]; then
+# uninstall the info reference in the dir file
+/sbin/install-info --delete /%{_infodir}/cvs.info.gz /%{_infodir}/dir
+/sbin/install-info --delete /%{_infodir}/cvsclient.info.gz /%{_infodir}/dir
+fi
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS BUGS FAQ MINOR-BUGS NEWS PROJECTS TODO README
+%doc doc/RCSFILES doc/*.ps
+%{_bindir}/*
+%{_mandir}/*/*
+%{_infodir}/*.info*
+%{_datadir}/%{name}
+
+%if %gssapi
+%files krb5
+%defattr(-,root,root)
+%{_kerberosbindir}/*
+%endif
+
+%changelog
+* Wed Aug 31 2005 Derek Price <derek@ximbiot.com>
+- Update links to Savannah. s/Copyright/License/ for RPM 4.mumble.
+
+* Mon July 20 2005 Derek Price <derek@ximbiot.com>
+- Update to homepage on Savannah.
+
+* Mon May 09 2005 Derek Price <derek@ximbiot.com>
+- Find install-sh in its new location in the build-aux directory.
+
+* Wed Mar 31 2004 Mark D. Baushke <mdb@cvshome.org>
+- Do not fail if info DIR file is not present to be deleted.
+
+* Tue Feb 17 2004 Derek Price <derek@ximbiot.com>
+- Remove info DIR file to avoid RPM warning us about installing files we don't
+- package.
+
+* Tue May 27 2003 Derek Price <derek@ximbiot.com>
+- Install a few more files as part of doc.
+
+* Thu Mar 29 2002 Derek Price <oberon@umich.edu>
+- Misc changes imported from RedHat's spec files.
+- Let RPM pick up the krb5-libs dependency.
+- `CVSHome.org' => `cvshome.org'.
+
+* Thu Apr 26 2001 Derek Price <dprice@collab.net>
+- avoid picking up %{_infodir}/dir.
+- remove krb5-configs from requirements since RedHat doesn't use it anymore.
+
+* Wed Nov 29 2000 Derek Price <dprice@openavenue.com>
+- Use _infodir consistently for info pages and _bindir for binaries.
+- use more succinct file list
+
+* Wed Oct 18 2000 Derek Price <dprice@openavenue.com>
+- Make the Kerberos binary a subpackage.
+- fix the info & man pages too
+
+* Wed Sep 27 2000 Derek Price <dprice@openavenue.com>
+- updated for cvs 1.11
+
+* Wed Mar 1 2000 Nalin Dahyabhai <nalin@redhat.com>
+- make kerberos support conditional at build-time
+
+* Wed Mar 1 2000 Bill Nottingham <notting@redhat.com>
+- integrate kerberos support into main tree
+
+* Mon Feb 14 2000 Nalin Dahyabhai <nalin@redhat.com>
+- build with gssapi auth (--with-gssapi, --with-encryption)
+- apply patch to update libs to krb5 1.1.1
+
+* Fri Feb 04 2000 Cristian Gafton <gafton@redhat.com>
+- fix the damn info pages too while we're at it.
+- fix description
+- man pages are compressed
+- make sure %post and %preun work okay
+
+* Sun Jan 9 2000 Jim Kingdon <http://bugzilla.redhat.com/bugzilla>
+- update to 1.10.7.
+
+* Wed Jul 14 1999 Jim Kingdon <http://developer.redhat.com>
+- add the patch to make 1.10.6 usable
+ (http://www.cyclic.com/cvs/dev-known.html).
+
+* Tue Jun 1 1999 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.6.
+
+* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com>
+- auto rebuild in the new build environment (release 2)
+
+* Mon Feb 22 1999 Jeff Johnson <jbj@redhat.com>
+- updated text in spec file.
+
+* Mon Feb 22 1999 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.5.
+
+* Tue Feb 2 1999 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.4.
+
+* Tue Oct 20 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.3.
+
+* Mon Sep 28 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.2.
+
+* Wed Sep 23 1998 Jeff Johnson <jbj@redhat.com>
+- remove trailing characters from rcs2log mktemp args
+
+* Thu Sep 10 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.1
+
+* Mon Aug 31 1998 Jeff Johnson <jbj@redhat.com>
+- fix race conditions in cvsbug/rcs2log
+
+* Sun Aug 16 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.
+
+* Wed Aug 12 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.9.30.
+
+* Mon Jun 08 1998 Prospector System <bugs@redhat.com>
+- translations modified for de, fr
+
+* Mon Jun 8 1998 Jeff Johnson <jbj@redhat.com>
+- build root
+- update to 1.9.28
+
+* Mon Apr 27 1998 Prospector System <bugs@redhat.com>
+- translations modified for de, fr, tr
+
+* Wed Oct 29 1997 Otto Hammersmith <otto@redhat.com>
+- added install-info stuff
+- added changelog section
diff --git a/cvs.spec.in b/cvs.spec.in
new file mode 100644
index 0000000..98f29b6
--- /dev/null
+++ b/cvs.spec.in
@@ -0,0 +1,239 @@
+Summary: A version control system.
+Name: @PACKAGE_TARNAME@
+Version: @PACKAGE_VERSION@
+Release: 1
+License: GPL
+Group: Development/Tools
+Source: http://savannah.nongnu.org/download/cvs/%{name}-%{version}.tar.bz2
+URL: http://cvs.nongnu.org/
+Prereq: /sbin/install-info
+Prefix: %{_prefix}
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+%description
+@PACKAGE_NAME@ is a version control system which can
+record the history of your files (usually, but not always, source
+code). CVS only stores the differences between versions, instead of
+every version of every file you've ever created. CVS also keeps a log
+of who, when and why changes occurred.
+
+CVS is very helpful for managing releases and controlling the
+concurrent editing of source files among multiple authors. Instead of
+providing version control for a collection of files in a single
+directory, CVS provides version control for a hierarchical collection
+of directories consisting of revision controlled files. These
+directories and files can then be combined together to form a software
+release.
+
+Install the %{name} package if you need to use a version control system.
+
+%define gssapi %(test -r /usr/kerberos/lib/libkrb5.a && echo 1 || echo 0)
+%if %gssapi
+%package krb5
+Summary: A version control system with Kerberos authentication.
+Group: Development/Tools
+Requires: %{name}
+BuildRequires: krb5-devel
+
+%description krb5
+@PACKAGE_NAME@ is a version control system which can
+record the history of your files (usually, but not always, source
+code). CVS only stores the differences between versions, instead of
+every version of every file you've ever created. CVS also keeps a log
+of who, when and why changes occurred.
+
+CVS is very helpful for managing releases and controlling the
+concurrent editing of source files among multiple authors. Instead of
+providing version control for a collection of files in a single
+directory, CVS provides version control for a hierarchical collection
+of directories consisting of revision controlled files. These
+directories and files can then be combined together to form a software
+release.
+
+This package contains only a Kerberized version of the CVS binary. You should
+install the base %{name} package to get the standard CVS distribution.
+
+Install the Kerberos version of the %{name} package if you need to use a version
+control system with Kerberos authentication and encryption.
+
+%define _kerberosdir %{prefix}/kerberos
+%define _kerberosbindir %{_kerberosdir}/bin
+%endif
+
+%prep
+%setup -q
+
+%build
+# The Kerberized binary
+%if %gssapi
+%configure --with-gssapi=/usr/kerberos --enable-encryption
+
+make LDFLAGS=-s
+
+mv src/cvs src/cvs.krb5
+%endif
+
+# The standard package
+%configure --without-gssapi
+
+make LDFLAGS=-s
+
+%install
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+
+%makeinstall
+# The Kerberized binary
+%if %gssapi
+build-aux/install-sh src/cvs.krb5 $RPM_BUILD_ROOT%{_kerberosbindir}/cvs
+%endif
+# forcefully compress the info pages so that install-info will work properly
+# in the %%post
+gzip $RPM_BUILD_ROOT/%{_infodir}/cvs* || true
+rm -f $RPM_BUILD_ROOT/%{_infodir}/dir
+
+%clean
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+
+%post
+/sbin/install-info /%{_infodir}/cvs.info.gz /%{_infodir}/dir
+/sbin/install-info /%{_infodir}/cvsclient.info.gz /%{_infodir}/dir
+# Remove any existing uncompressed versions of the info files since
+# install-info doesn't and info doesn't seem to be very good at spotting that
+# its uncompressed cache is out of date.
+rm -f /%{_infodir}/cvs.info /%{_infodir}/cvs.info-? /%{_infodir}/cvs.info-??
+rm -f /%{_infodir}/cvsclient.info /%{_infodir}/cvsclient.info-?
+rm -f /%{_infodir}/cvsclient.info-??
+%preun
+if [ $1 = 0 ]; then
+# uninstall the info reference in the dir file
+/sbin/install-info --delete /%{_infodir}/cvs.info.gz /%{_infodir}/dir
+/sbin/install-info --delete /%{_infodir}/cvsclient.info.gz /%{_infodir}/dir
+fi
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS BUGS FAQ MINOR-BUGS NEWS PROJECTS TODO README
+%doc doc/RCSFILES doc/*.ps
+%{_bindir}/*
+%{_mandir}/*/*
+%{_infodir}/*.info*
+%{_datadir}/%{name}
+
+%if %gssapi
+%files krb5
+%defattr(-,root,root)
+%{_kerberosbindir}/*
+%endif
+
+%changelog
+* Wed Aug 31 2005 Derek Price <derek@ximbiot.com>
+- Update links to Savannah. s/Copyright/License/ for RPM 4.mumble.
+
+* Mon July 20 2005 Derek Price <derek@ximbiot.com>
+- Update to homepage on Savannah.
+
+* Mon May 09 2005 Derek Price <derek@ximbiot.com>
+- Find install-sh in its new location in the build-aux directory.
+
+* Wed Mar 31 2004 Mark D. Baushke <mdb@cvshome.org>
+- Do not fail if info DIR file is not present to be deleted.
+
+* Tue Feb 17 2004 Derek Price <derek@ximbiot.com>
+- Remove info DIR file to avoid RPM warning us about installing files we don't
+- package.
+
+* Tue May 27 2003 Derek Price <derek@ximbiot.com>
+- Install a few more files as part of doc.
+
+* Thu Mar 29 2002 Derek Price <oberon@umich.edu>
+- Misc changes imported from RedHat's spec files.
+- Let RPM pick up the krb5-libs dependency.
+- `CVSHome.org' => `cvshome.org'.
+
+* Thu Apr 26 2001 Derek Price <dprice@collab.net>
+- avoid picking up %{_infodir}/dir.
+- remove krb5-configs from requirements since RedHat doesn't use it anymore.
+
+* Wed Nov 29 2000 Derek Price <dprice@openavenue.com>
+- Use _infodir consistently for info pages and _bindir for binaries.
+- use more succinct file list
+
+* Wed Oct 18 2000 Derek Price <dprice@openavenue.com>
+- Make the Kerberos binary a subpackage.
+- fix the info & man pages too
+
+* Wed Sep 27 2000 Derek Price <dprice@openavenue.com>
+- updated for cvs 1.11
+
+* Wed Mar 1 2000 Nalin Dahyabhai <nalin@redhat.com>
+- make kerberos support conditional at build-time
+
+* Wed Mar 1 2000 Bill Nottingham <notting@redhat.com>
+- integrate kerberos support into main tree
+
+* Mon Feb 14 2000 Nalin Dahyabhai <nalin@redhat.com>
+- build with gssapi auth (--with-gssapi, --with-encryption)
+- apply patch to update libs to krb5 1.1.1
+
+* Fri Feb 04 2000 Cristian Gafton <gafton@redhat.com>
+- fix the damn info pages too while we're at it.
+- fix description
+- man pages are compressed
+- make sure %post and %preun work okay
+
+* Sun Jan 9 2000 Jim Kingdon <http://bugzilla.redhat.com/bugzilla>
+- update to 1.10.7.
+
+* Wed Jul 14 1999 Jim Kingdon <http://developer.redhat.com>
+- add the patch to make 1.10.6 usable
+ (http://www.cyclic.com/cvs/dev-known.html).
+
+* Tue Jun 1 1999 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.6.
+
+* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com>
+- auto rebuild in the new build environment (release 2)
+
+* Mon Feb 22 1999 Jeff Johnson <jbj@redhat.com>
+- updated text in spec file.
+
+* Mon Feb 22 1999 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.5.
+
+* Tue Feb 2 1999 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.4.
+
+* Tue Oct 20 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.3.
+
+* Mon Sep 28 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.2.
+
+* Wed Sep 23 1998 Jeff Johnson <jbj@redhat.com>
+- remove trailing characters from rcs2log mktemp args
+
+* Thu Sep 10 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.1
+
+* Mon Aug 31 1998 Jeff Johnson <jbj@redhat.com>
+- fix race conditions in cvsbug/rcs2log
+
+* Sun Aug 16 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.10.
+
+* Wed Aug 12 1998 Jeff Johnson <jbj@redhat.com>
+- update to 1.9.30.
+
+* Mon Jun 08 1998 Prospector System <bugs@redhat.com>
+- translations modified for de, fr
+
+* Mon Jun 8 1998 Jeff Johnson <jbj@redhat.com>
+- build root
+- update to 1.9.28
+
+* Mon Apr 27 1998 Prospector System <bugs@redhat.com>
+- translations modified for de, fr, tr
+
+* Wed Oct 29 1997 Otto Hammersmith <otto@redhat.com>
+- added install-info stuff
+- added changelog section
diff --git a/cvsnt.dep b/cvsnt.dep
new file mode 100644
index 0000000..7fca41b
--- /dev/null
+++ b/cvsnt.dep
@@ -0,0 +1,2560 @@
+# Microsoft Developer Studio Generated Dependency File, included by cvsnt.mak
+
+.\src\add.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\fileattr.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\admin.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\annotate.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\buffer.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pagealign_alloc.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\checkin.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\fileattr.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\checkout.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\classify.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\client.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\md5.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\hash.h"\
+ ".\src\log-buffer.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\rsh-client.h"\
+ ".\src\server.h"\
+ ".\src\socket-client.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\commit.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\fileattr.h"\
+ ".\src\hardlink.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\create_adm.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\cvsrc.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\diff.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\edit.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\lib\yesno.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\fileattr.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\src\watch.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\entries.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\error.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\vasnprintf.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\exithandle.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\expand_path.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\fileattr.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\fileattr.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\filesubr.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\JmgStat.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\find_names.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\glob-libc.h"\
+ ".\lib\glob.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\hash.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\history.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\history.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\ignore.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\lstat.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\import.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\lstat.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\JmgStat.c" : \
+ ".\windows-NT\JmgStat.h"\
+ ".\windows-NT\stdbool.h"\
+
+
+.\src\lock.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\src\log-buffer.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\log.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\login.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpass.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\logmsg.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\ls.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\main.c : \
+ ".\lib\closeout.h"\
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\setenv.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\strftime.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xgethostname.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\mkdir.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\mkmodules.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\history.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\modules.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\myndbm.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getdelim.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\ndir.c" : \
+ ".\lib\xalloc.h"\
+ ".\windows-NT\ndir.h"\
+
+
+.\src\no_diff.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\parseinfo.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\history.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\patch.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\pwd.c" : \
+ ".\lib\timespec.h"\
+ ".\lib\xalloc.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\rcmd.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\rcmd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\rcs.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\hardlink.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\rcscmds.c : \
+ ".\diff\diffrun.h"\
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\quotearg.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\recurse.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\fileattr.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\release.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\lib\yesno.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\remove.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\repos.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\root.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\src\rsh-client.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\rsh-client.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\run.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\scramble.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\server.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getnline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\fileattr.h"\
+ ".\src\hash.h"\
+ ".\src\log-buffer.h"\
+ ".\src\ms-buffer.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\src\watch.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\sockerror.c" : \
+
+
+".\src\socket-client.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\socket-client.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\stack.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\startserver.c" : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\rcmd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\status.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\subr.c : \
+ ".\lib\canon-host.h"\
+ ".\lib\canonicalize.h"\
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\vasnprintf.h"\
+ ".\lib\vasprintf.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\tag.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\unistd.c" : \
+ ".\windows-NT\unistd.h"\
+
+
+.\src\update.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\save-cwd.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\fileattr.h"\
+ ".\src\hardlink.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\src\watch.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\vers_ts.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\lstat.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\version.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\waitpid.c" : \
+ ".\lib\timespec.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\watch.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\edit.h"\
+ ".\src\fileattr.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\src\watch.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+".\windows-NT\woe32.c" : \
+ ".\lib\timespec.h"\
+ ".\lib\xalloc.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\wrapper.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getline.h"\
+ ".\lib\getopt.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+
+
+.\src\zlib.c : \
+ ".\lib\dirname.h"\
+ ".\lib\exit.h"\
+ ".\lib\fnmatch.h"\
+ ".\lib\getdate.h"\
+ ".\lib\getopt.h"\
+ ".\lib\getpagesize.h"\
+ ".\lib\gettext.h"\
+ ".\lib\pagealign_alloc.h"\
+ ".\lib\pathmax.h"\
+ ".\lib\regex.h"\
+ ".\lib\stat-macros.h"\
+ ".\lib\strcase.h"\
+ ".\lib\system.h"\
+ ".\lib\timespec.h"\
+ ".\lib\unlocked-io.h"\
+ ".\lib\wait.h"\
+ ".\lib\xalloc.h"\
+ ".\lib\xgetcwd.h"\
+ ".\lib\xreadlink.h"\
+ ".\lib\xsize.h"\
+ ".\src\client.h"\
+ ".\src\cvs.h"\
+ ".\src\hash.h"\
+ ".\src\myndbm.h"\
+ ".\src\parseinfo.h"\
+ ".\src\rcs.h"\
+ ".\src\root.h"\
+ ".\src\server.h"\
+ ".\src\stack.h"\
+ ".\src\subr.h"\
+ ".\src\update.h"\
+ ".\windows-NT\config.h"\
+ ".\windows-NT\ndir.h"\
+ ".\windows-NT\pwd.h"\
+ ".\windows-NT\stdbool.h"\
+ ".\windows-NT\stdint.h"\
+ ".\windows-NT\unistd.h"\
+ ".\windows-NT\woe32.h"\
+ ".\zlib\zconf.h"\
+ ".\zlib\zlib.h"\
+
diff --git a/cvsnt.dsp b/cvsnt.dsp
new file mode 100644
index 0000000..0228946
--- /dev/null
+++ b/cvsnt.dsp
@@ -0,0 +1,711 @@
+# Microsoft Developer Studio Project File - Name="cvsnt" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=cvsnt - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "cvsnt.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "cvsnt.mak" CFG="cvsnt - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "cvsnt - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "cvsnt - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "cvsnt - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "WinRel"
+# PROP BASE Intermediate_Dir "WinRel"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "WinRel"
+# PROP Intermediate_Dir "WinRel"
+# PROP Ignore_Export_Lib 0
+# ADD BASE CPP /nologo /W3 /GX /Ob1 /I ".\windows-NT" /I ".\lib" /I ".\src" /I ".\zlib" /I ".\diff" /D "NDEBUG" /D "WANT_WIN_COMPILER_VERSION" /D "_CONSOLE" /D "HAVE_CONFIG_H" /D "WIN32" /YX /FD /c
+# SUBTRACT BASE CPP /WX /Fr
+# ADD CPP /nologo /W3 /GX /Ob1 /I ".\windows-NT" /I ".\lib" /I ".\src" /I ".\zlib" /I ".\diff" /I ".\WinDebug" /D "NDEBUG" /D "WANT_WIN_COMPILER_VERSION" /D "_CONSOLE" /D "HAVE_CONFIG_H" /D "WIN32" /YX /FD /c
+# SUBTRACT CPP /WX /Fr
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 diff\WinRel\libdiff.lib lib\WinRel\libcvs.lib zlib\WinRel\libz.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /machine:I386 /out:".\WinRel\cvs.exe"
+# ADD LINK32 diff\WinRel\libdiff.lib lib\WinRel\libcvs.lib zlib\WinRel\libz.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /machine:I386 /out:".\WinRel\cvs.exe"
+
+!ELSEIF "$(CFG)" == "cvsnt - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "WinDebug"
+# PROP BASE Intermediate_Dir "WinDebug"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "WinDebug"
+# PROP Intermediate_Dir "WinDebug"
+# PROP Ignore_Export_Lib 0
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Ob1 /I ".\windows-NT" /I ".\lib" /I ".\src" /I ".\zlib" /I ".\diff" /D "_DEBUG" /D "_CONSOLE" /D "HAVE_CONFIG_H" /D "WIN32" /D "WANT_WIN_COMPILER_VERSION" /YX /FD /c
+# SUBTRACT BASE CPP /Fr
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Ob1 /I ".\windows-NT" /I ".\lib" /I ".\src" /I ".\zlib" /I ".\diff" /D "_DEBUG" /D "_CONSOLE" /D "HAVE_CONFIG_H" /D "WIN32" /D "WANT_WIN_COMPILER_VERSION" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 diff\WinDebug\libdiff.lib lib\WinDebug\libcvs.lib zlib\WinDebug\libz.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /pdb:".\WinDebug\cvs.pdb" /debug /machine:I386 /out:".\WinDebug\cvs.exe"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 diff\WinDebug\libdiff.lib lib\WinDebug\libcvs.lib zlib\WinDebug\libz.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /pdb:".\WinDebug\cvs.pdb" /debug /machine:I386 /out:".\WinDebug\cvs.exe"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "cvsnt - Win32 Release"
+# Name "cvsnt - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\src\add.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\admin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\annotate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\buffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\checkin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\checkout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\classify.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\client.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\commit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\create_adm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\cvsrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\diff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\edit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\entries.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\exithandle.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\expand_path.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\fileattr.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\filesubr.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\find_names.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\history.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\ignore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\import.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\JmgStat.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\lock.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\src\log-buffer.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\login.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\logmsg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\ls.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\main.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\mkdir.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\mkmodules.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\modules.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\myndbm.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\ndir.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\no_diff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\parseinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\patch.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\pwd.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\rcmd.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\rcs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\rcscmds.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\recurse.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\release.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\remove.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\repos.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\root.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\src\rsh-client.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\run.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\scramble.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\server.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\sockerror.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\src\socket-client.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\stack.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\startserver.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\status.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\subr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\tag.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\unistd.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\vers_ts.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\version.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\waitpid.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\watch.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\woe32.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\wrapper.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\zlib.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\lib\alloca.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\buffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\lib\canon-host.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\canonicalize.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\client.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\closeout.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\cvs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\diff\diffrun.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\dirname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\edit.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\exit.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\exitfail.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\fileattr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\fnmatch.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\getdate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\getdelim.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\getline.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\getnline.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\getopt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\getpagesize.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\getpass.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\gettext.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\lib\glob-libc.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\glob.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\hardlink.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\hash.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\history.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\infblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\infcodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\infutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\JmgStat.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\src\log-buffer.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\lstat.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\src\ms-buffer.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\myndbm.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\ndir.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\pagealign_alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\parseinfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\pathmax.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\lib\printf-args.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\lib\printf-parse.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\pwd.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\quotearg.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\rcmd.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\rcs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\regex.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\root.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\src\rsh-client.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\lib\save-cwd.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\savecwd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\server.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\setenv.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\src\socket-client.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\stack.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\lib\stat-macros.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\stdbool.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\stdint.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\strcase.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\strftime.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\subr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\system.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\timespec.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\unistd.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\lib\unlocked-io.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\update.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\vasnprintf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\vasprintf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\wait.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\watch.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\windows-NT\woe32.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\xalloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\xgetcwd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\xgethostname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\xreadlink.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\xsize.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\xtime.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lib\yesno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib\zutil.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/cvsnt.dsw b/cvsnt.dsw
new file mode 100644
index 0000000..60a82b7
--- /dev/null
+++ b/cvsnt.dsw
@@ -0,0 +1,77 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libcvs"=".\lib\libcvs.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "cvsnt"=".\cvsnt.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libdiff
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libz
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libcvs
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libdiff"=".\diff\libdiff.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libcvs
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libz"=".\zlib\libz.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/cvsnt.mak b/cvsnt.mak
new file mode 100644
index 0000000..72eadba
--- /dev/null
+++ b/cvsnt.mak
@@ -0,0 +1,975 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on cvsnt.dsp
+!IF "$(RECURSE)" == ""
+RECURSE=1
+!ENDIF
+!IF "$(CFG)" == ""
+CFG=cvsnt - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to cvsnt - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "cvsnt - Win32 Release" && "$(CFG)" != "cvsnt - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "cvsnt.mak" CFG="cvsnt - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "cvsnt - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "cvsnt - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "cvsnt - Win32 Release"
+
+OUTDIR=.\WinRel
+INTDIR=.\WinRel
+# Begin Custom Macros
+OutDir=.\WinRel
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\cvs.exe"
+
+!ELSE
+
+ALL : "libcvs - Win32 Release" "libz - Win32 Release" "libdiff - Win32 Release" "$(OUTDIR)\cvs.exe"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libdiff - Win32 ReleaseCLEAN" "libz - Win32 ReleaseCLEAN" "libcvs - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\add.obj"
+ -@erase "$(INTDIR)\admin.obj"
+ -@erase "$(INTDIR)\annotate.obj"
+ -@erase "$(INTDIR)\buffer.obj"
+ -@erase "$(INTDIR)\checkin.obj"
+ -@erase "$(INTDIR)\checkout.obj"
+ -@erase "$(INTDIR)\classify.obj"
+ -@erase "$(INTDIR)\client.obj"
+ -@erase "$(INTDIR)\commit.obj"
+ -@erase "$(INTDIR)\create_adm.obj"
+ -@erase "$(INTDIR)\cvsrc.obj"
+ -@erase "$(INTDIR)\diff.obj"
+ -@erase "$(INTDIR)\edit.obj"
+ -@erase "$(INTDIR)\entries.obj"
+ -@erase "$(INTDIR)\error.obj"
+ -@erase "$(INTDIR)\exithandle.obj"
+ -@erase "$(INTDIR)\expand_path.obj"
+ -@erase "$(INTDIR)\fileattr.obj"
+ -@erase "$(INTDIR)\filesubr.obj"
+ -@erase "$(INTDIR)\find_names.obj"
+ -@erase "$(INTDIR)\hash.obj"
+ -@erase "$(INTDIR)\history.obj"
+ -@erase "$(INTDIR)\ignore.obj"
+ -@erase "$(INTDIR)\import.obj"
+ -@erase "$(INTDIR)\JmgStat.obj"
+ -@erase "$(INTDIR)\lock.obj"
+ -@erase "$(INTDIR)\log-buffer.obj"
+ -@erase "$(INTDIR)\log.obj"
+ -@erase "$(INTDIR)\login.obj"
+ -@erase "$(INTDIR)\logmsg.obj"
+ -@erase "$(INTDIR)\ls.obj"
+ -@erase "$(INTDIR)\main.obj"
+ -@erase "$(INTDIR)\mkdir.obj"
+ -@erase "$(INTDIR)\mkmodules.obj"
+ -@erase "$(INTDIR)\modules.obj"
+ -@erase "$(INTDIR)\myndbm.obj"
+ -@erase "$(INTDIR)\ndir.obj"
+ -@erase "$(INTDIR)\no_diff.obj"
+ -@erase "$(INTDIR)\parseinfo.obj"
+ -@erase "$(INTDIR)\patch.obj"
+ -@erase "$(INTDIR)\pwd.obj"
+ -@erase "$(INTDIR)\rcmd.obj"
+ -@erase "$(INTDIR)\rcs.obj"
+ -@erase "$(INTDIR)\rcscmds.obj"
+ -@erase "$(INTDIR)\recurse.obj"
+ -@erase "$(INTDIR)\release.obj"
+ -@erase "$(INTDIR)\remove.obj"
+ -@erase "$(INTDIR)\repos.obj"
+ -@erase "$(INTDIR)\root.obj"
+ -@erase "$(INTDIR)\rsh-client.obj"
+ -@erase "$(INTDIR)\run.obj"
+ -@erase "$(INTDIR)\scramble.obj"
+ -@erase "$(INTDIR)\server.obj"
+ -@erase "$(INTDIR)\sockerror.obj"
+ -@erase "$(INTDIR)\socket-client.obj"
+ -@erase "$(INTDIR)\stack.obj"
+ -@erase "$(INTDIR)\startserver.obj"
+ -@erase "$(INTDIR)\status.obj"
+ -@erase "$(INTDIR)\subr.obj"
+ -@erase "$(INTDIR)\tag.obj"
+ -@erase "$(INTDIR)\unistd.obj"
+ -@erase "$(INTDIR)\update.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vers_ts.obj"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(INTDIR)\waitpid.obj"
+ -@erase "$(INTDIR)\watch.obj"
+ -@erase "$(INTDIR)\woe32.obj"
+ -@erase "$(INTDIR)\wrapper.obj"
+ -@erase "$(INTDIR)\zlib.obj"
+ -@erase "$(OUTDIR)\cvs.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /Ob1 /I ".\windows-NT" /I ".\lib" /I ".\src" /I ".\zlib" /I ".\diff" /I ".\WinDebug" /D "NDEBUG" /D "WANT_WIN_COMPILER_VERSION" /D "_CONSOLE" /D "HAVE_CONFIG_H" /D "WIN32" /Fp"$(INTDIR)\cvsnt.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\cvsnt.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=diff\WinRel\libdiff.lib lib\WinRel\libcvs.lib zlib\WinRel\libz.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\cvs.pdb" /machine:I386 /out:"$(OUTDIR)\cvs.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\add.obj" \
+ "$(INTDIR)\admin.obj" \
+ "$(INTDIR)\annotate.obj" \
+ "$(INTDIR)\buffer.obj" \
+ "$(INTDIR)\checkin.obj" \
+ "$(INTDIR)\checkout.obj" \
+ "$(INTDIR)\classify.obj" \
+ "$(INTDIR)\client.obj" \
+ "$(INTDIR)\commit.obj" \
+ "$(INTDIR)\create_adm.obj" \
+ "$(INTDIR)\cvsrc.obj" \
+ "$(INTDIR)\diff.obj" \
+ "$(INTDIR)\edit.obj" \
+ "$(INTDIR)\entries.obj" \
+ "$(INTDIR)\error.obj" \
+ "$(INTDIR)\exithandle.obj" \
+ "$(INTDIR)\expand_path.obj" \
+ "$(INTDIR)\fileattr.obj" \
+ "$(INTDIR)\filesubr.obj" \
+ "$(INTDIR)\find_names.obj" \
+ "$(INTDIR)\hash.obj" \
+ "$(INTDIR)\history.obj" \
+ "$(INTDIR)\ignore.obj" \
+ "$(INTDIR)\import.obj" \
+ "$(INTDIR)\JmgStat.obj" \
+ "$(INTDIR)\lock.obj" \
+ "$(INTDIR)\log-buffer.obj" \
+ "$(INTDIR)\log.obj" \
+ "$(INTDIR)\login.obj" \
+ "$(INTDIR)\logmsg.obj" \
+ "$(INTDIR)\ls.obj" \
+ "$(INTDIR)\main.obj" \
+ "$(INTDIR)\mkdir.obj" \
+ "$(INTDIR)\mkmodules.obj" \
+ "$(INTDIR)\modules.obj" \
+ "$(INTDIR)\myndbm.obj" \
+ "$(INTDIR)\ndir.obj" \
+ "$(INTDIR)\no_diff.obj" \
+ "$(INTDIR)\parseinfo.obj" \
+ "$(INTDIR)\patch.obj" \
+ "$(INTDIR)\pwd.obj" \
+ "$(INTDIR)\rcmd.obj" \
+ "$(INTDIR)\rcs.obj" \
+ "$(INTDIR)\rcscmds.obj" \
+ "$(INTDIR)\recurse.obj" \
+ "$(INTDIR)\release.obj" \
+ "$(INTDIR)\remove.obj" \
+ "$(INTDIR)\repos.obj" \
+ "$(INTDIR)\root.obj" \
+ "$(INTDIR)\rsh-client.obj" \
+ "$(INTDIR)\run.obj" \
+ "$(INTDIR)\scramble.obj" \
+ "$(INTDIR)\server.obj" \
+ "$(INTDIR)\sockerror.obj" \
+ "$(INTDIR)\socket-client.obj" \
+ "$(INTDIR)\stack.obj" \
+ "$(INTDIR)\startserver.obj" \
+ "$(INTDIR)\status.obj" \
+ "$(INTDIR)\subr.obj" \
+ "$(INTDIR)\tag.obj" \
+ "$(INTDIR)\unistd.obj" \
+ "$(INTDIR)\update.obj" \
+ "$(INTDIR)\vers_ts.obj" \
+ "$(INTDIR)\version.obj" \
+ "$(INTDIR)\waitpid.obj" \
+ "$(INTDIR)\watch.obj" \
+ "$(INTDIR)\woe32.obj" \
+ "$(INTDIR)\wrapper.obj" \
+ "$(INTDIR)\zlib.obj" \
+ ".\diff\WinRel\libdiff.lib" \
+ ".\zlib\WinRel\libz.lib" \
+ ".\lib\WinRel\libcvs.lib"
+
+"$(OUTDIR)\cvs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "cvsnt - Win32 Debug"
+
+OUTDIR=.\WinDebug
+INTDIR=.\WinDebug
+# Begin Custom Macros
+OutDir=.\WinDebug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\cvs.exe"
+
+!ELSE
+
+ALL : "libcvs - Win32 Debug" "libz - Win32 Debug" "libdiff - Win32 Debug" "$(OUTDIR)\cvs.exe"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libdiff - Win32 DebugCLEAN" "libz - Win32 DebugCLEAN" "libcvs - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\add.obj"
+ -@erase "$(INTDIR)\admin.obj"
+ -@erase "$(INTDIR)\annotate.obj"
+ -@erase "$(INTDIR)\buffer.obj"
+ -@erase "$(INTDIR)\checkin.obj"
+ -@erase "$(INTDIR)\checkout.obj"
+ -@erase "$(INTDIR)\classify.obj"
+ -@erase "$(INTDIR)\client.obj"
+ -@erase "$(INTDIR)\commit.obj"
+ -@erase "$(INTDIR)\create_adm.obj"
+ -@erase "$(INTDIR)\cvsrc.obj"
+ -@erase "$(INTDIR)\diff.obj"
+ -@erase "$(INTDIR)\edit.obj"
+ -@erase "$(INTDIR)\entries.obj"
+ -@erase "$(INTDIR)\error.obj"
+ -@erase "$(INTDIR)\exithandle.obj"
+ -@erase "$(INTDIR)\expand_path.obj"
+ -@erase "$(INTDIR)\fileattr.obj"
+ -@erase "$(INTDIR)\filesubr.obj"
+ -@erase "$(INTDIR)\find_names.obj"
+ -@erase "$(INTDIR)\hash.obj"
+ -@erase "$(INTDIR)\history.obj"
+ -@erase "$(INTDIR)\ignore.obj"
+ -@erase "$(INTDIR)\import.obj"
+ -@erase "$(INTDIR)\JmgStat.obj"
+ -@erase "$(INTDIR)\lock.obj"
+ -@erase "$(INTDIR)\log-buffer.obj"
+ -@erase "$(INTDIR)\log.obj"
+ -@erase "$(INTDIR)\login.obj"
+ -@erase "$(INTDIR)\logmsg.obj"
+ -@erase "$(INTDIR)\ls.obj"
+ -@erase "$(INTDIR)\main.obj"
+ -@erase "$(INTDIR)\mkdir.obj"
+ -@erase "$(INTDIR)\mkmodules.obj"
+ -@erase "$(INTDIR)\modules.obj"
+ -@erase "$(INTDIR)\myndbm.obj"
+ -@erase "$(INTDIR)\ndir.obj"
+ -@erase "$(INTDIR)\no_diff.obj"
+ -@erase "$(INTDIR)\parseinfo.obj"
+ -@erase "$(INTDIR)\patch.obj"
+ -@erase "$(INTDIR)\pwd.obj"
+ -@erase "$(INTDIR)\rcmd.obj"
+ -@erase "$(INTDIR)\rcs.obj"
+ -@erase "$(INTDIR)\rcscmds.obj"
+ -@erase "$(INTDIR)\recurse.obj"
+ -@erase "$(INTDIR)\release.obj"
+ -@erase "$(INTDIR)\remove.obj"
+ -@erase "$(INTDIR)\repos.obj"
+ -@erase "$(INTDIR)\root.obj"
+ -@erase "$(INTDIR)\rsh-client.obj"
+ -@erase "$(INTDIR)\run.obj"
+ -@erase "$(INTDIR)\scramble.obj"
+ -@erase "$(INTDIR)\server.obj"
+ -@erase "$(INTDIR)\sockerror.obj"
+ -@erase "$(INTDIR)\socket-client.obj"
+ -@erase "$(INTDIR)\stack.obj"
+ -@erase "$(INTDIR)\startserver.obj"
+ -@erase "$(INTDIR)\status.obj"
+ -@erase "$(INTDIR)\subr.obj"
+ -@erase "$(INTDIR)\tag.obj"
+ -@erase "$(INTDIR)\unistd.obj"
+ -@erase "$(INTDIR)\update.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\vers_ts.obj"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(INTDIR)\waitpid.obj"
+ -@erase "$(INTDIR)\watch.obj"
+ -@erase "$(INTDIR)\woe32.obj"
+ -@erase "$(INTDIR)\wrapper.obj"
+ -@erase "$(INTDIR)\zlib.obj"
+ -@erase "$(OUTDIR)\cvs.exe"
+ -@erase "$(OUTDIR)\cvs.ilk"
+ -@erase "$(OUTDIR)\cvs.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Ob1 /I ".\windows-NT" /I ".\lib" /I ".\src" /I ".\zlib" /I ".\diff" /D "_DEBUG" /D "_CONSOLE" /D "HAVE_CONFIG_H" /D "WIN32" /D "WANT_WIN_COMPILER_VERSION" /Fp"$(INTDIR)\cvsnt.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\cvsnt.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=diff\WinDebug\libdiff.lib lib\WinDebug\libcvs.lib zlib\WinDebug\libz.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\cvs.pdb" /debug /machine:I386 /out:"$(OUTDIR)\cvs.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\add.obj" \
+ "$(INTDIR)\admin.obj" \
+ "$(INTDIR)\annotate.obj" \
+ "$(INTDIR)\buffer.obj" \
+ "$(INTDIR)\checkin.obj" \
+ "$(INTDIR)\checkout.obj" \
+ "$(INTDIR)\classify.obj" \
+ "$(INTDIR)\client.obj" \
+ "$(INTDIR)\commit.obj" \
+ "$(INTDIR)\create_adm.obj" \
+ "$(INTDIR)\cvsrc.obj" \
+ "$(INTDIR)\diff.obj" \
+ "$(INTDIR)\edit.obj" \
+ "$(INTDIR)\entries.obj" \
+ "$(INTDIR)\error.obj" \
+ "$(INTDIR)\exithandle.obj" \
+ "$(INTDIR)\expand_path.obj" \
+ "$(INTDIR)\fileattr.obj" \
+ "$(INTDIR)\filesubr.obj" \
+ "$(INTDIR)\find_names.obj" \
+ "$(INTDIR)\hash.obj" \
+ "$(INTDIR)\history.obj" \
+ "$(INTDIR)\ignore.obj" \
+ "$(INTDIR)\import.obj" \
+ "$(INTDIR)\JmgStat.obj" \
+ "$(INTDIR)\lock.obj" \
+ "$(INTDIR)\log-buffer.obj" \
+ "$(INTDIR)\log.obj" \
+ "$(INTDIR)\login.obj" \
+ "$(INTDIR)\logmsg.obj" \
+ "$(INTDIR)\ls.obj" \
+ "$(INTDIR)\main.obj" \
+ "$(INTDIR)\mkdir.obj" \
+ "$(INTDIR)\mkmodules.obj" \
+ "$(INTDIR)\modules.obj" \
+ "$(INTDIR)\myndbm.obj" \
+ "$(INTDIR)\ndir.obj" \
+ "$(INTDIR)\no_diff.obj" \
+ "$(INTDIR)\parseinfo.obj" \
+ "$(INTDIR)\patch.obj" \
+ "$(INTDIR)\pwd.obj" \
+ "$(INTDIR)\rcmd.obj" \
+ "$(INTDIR)\rcs.obj" \
+ "$(INTDIR)\rcscmds.obj" \
+ "$(INTDIR)\recurse.obj" \
+ "$(INTDIR)\release.obj" \
+ "$(INTDIR)\remove.obj" \
+ "$(INTDIR)\repos.obj" \
+ "$(INTDIR)\root.obj" \
+ "$(INTDIR)\rsh-client.obj" \
+ "$(INTDIR)\run.obj" \
+ "$(INTDIR)\scramble.obj" \
+ "$(INTDIR)\server.obj" \
+ "$(INTDIR)\sockerror.obj" \
+ "$(INTDIR)\socket-client.obj" \
+ "$(INTDIR)\stack.obj" \
+ "$(INTDIR)\startserver.obj" \
+ "$(INTDIR)\status.obj" \
+ "$(INTDIR)\subr.obj" \
+ "$(INTDIR)\tag.obj" \
+ "$(INTDIR)\unistd.obj" \
+ "$(INTDIR)\update.obj" \
+ "$(INTDIR)\vers_ts.obj" \
+ "$(INTDIR)\version.obj" \
+ "$(INTDIR)\waitpid.obj" \
+ "$(INTDIR)\watch.obj" \
+ "$(INTDIR)\woe32.obj" \
+ "$(INTDIR)\wrapper.obj" \
+ "$(INTDIR)\zlib.obj" \
+ ".\diff\WinDebug\libdiff.lib" \
+ ".\zlib\WinDebug\libz.lib" \
+ ".\lib\WinDebug\libcvs.lib"
+
+"$(OUTDIR)\cvs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("cvsnt.dep")
+!INCLUDE "cvsnt.dep"
+!ELSE
+!MESSAGE Warning: cannot find "cvsnt.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "cvsnt - Win32 Release" || "$(CFG)" == "cvsnt - Win32 Debug"
+SOURCE=.\src\add.c
+
+"$(INTDIR)\add.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\admin.c
+
+"$(INTDIR)\admin.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\annotate.c
+
+"$(INTDIR)\annotate.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\buffer.c
+
+"$(INTDIR)\buffer.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\checkin.c
+
+"$(INTDIR)\checkin.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\checkout.c
+
+"$(INTDIR)\checkout.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\classify.c
+
+"$(INTDIR)\classify.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\client.c
+
+"$(INTDIR)\client.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\commit.c
+
+"$(INTDIR)\commit.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\create_adm.c
+
+"$(INTDIR)\create_adm.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\cvsrc.c
+
+"$(INTDIR)\cvsrc.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\diff.c
+
+"$(INTDIR)\diff.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\edit.c
+
+"$(INTDIR)\edit.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\entries.c
+
+"$(INTDIR)\entries.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\error.c
+
+"$(INTDIR)\error.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\exithandle.c
+
+"$(INTDIR)\exithandle.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\expand_path.c
+
+"$(INTDIR)\expand_path.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\fileattr.c
+
+"$(INTDIR)\fileattr.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\filesubr.c"
+
+"$(INTDIR)\filesubr.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\find_names.c
+
+"$(INTDIR)\find_names.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\hash.c
+
+"$(INTDIR)\hash.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\history.c
+
+"$(INTDIR)\history.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\ignore.c
+
+"$(INTDIR)\ignore.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\import.c
+
+"$(INTDIR)\import.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\JmgStat.c"
+
+"$(INTDIR)\JmgStat.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\lock.c
+
+"$(INTDIR)\lock.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\src\log-buffer.c"
+
+"$(INTDIR)\log-buffer.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\log.c
+
+"$(INTDIR)\log.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\login.c
+
+"$(INTDIR)\login.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\logmsg.c
+
+"$(INTDIR)\logmsg.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\ls.c
+
+"$(INTDIR)\ls.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\main.c
+
+"$(INTDIR)\main.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\mkdir.c"
+
+"$(INTDIR)\mkdir.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\mkmodules.c
+
+"$(INTDIR)\mkmodules.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\modules.c
+
+"$(INTDIR)\modules.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\myndbm.c
+
+"$(INTDIR)\myndbm.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\ndir.c"
+
+"$(INTDIR)\ndir.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\no_diff.c
+
+"$(INTDIR)\no_diff.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\parseinfo.c
+
+"$(INTDIR)\parseinfo.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\patch.c
+
+"$(INTDIR)\patch.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\pwd.c"
+
+"$(INTDIR)\pwd.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\rcmd.c"
+
+"$(INTDIR)\rcmd.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\rcs.c
+
+"$(INTDIR)\rcs.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\rcscmds.c
+
+"$(INTDIR)\rcscmds.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\recurse.c
+
+"$(INTDIR)\recurse.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\release.c
+
+"$(INTDIR)\release.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\remove.c
+
+"$(INTDIR)\remove.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\repos.c
+
+"$(INTDIR)\repos.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\root.c
+
+"$(INTDIR)\root.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\src\rsh-client.c"
+
+"$(INTDIR)\rsh-client.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\run.c"
+
+"$(INTDIR)\run.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\scramble.c
+
+"$(INTDIR)\scramble.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\server.c
+
+"$(INTDIR)\server.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\sockerror.c"
+
+"$(INTDIR)\sockerror.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\src\socket-client.c"
+
+"$(INTDIR)\socket-client.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\stack.c
+
+"$(INTDIR)\stack.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\startserver.c"
+
+"$(INTDIR)\startserver.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\status.c
+
+"$(INTDIR)\status.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\subr.c
+
+"$(INTDIR)\subr.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\tag.c
+
+"$(INTDIR)\tag.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\unistd.c"
+
+"$(INTDIR)\unistd.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\update.c
+
+"$(INTDIR)\update.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\vers_ts.c
+
+"$(INTDIR)\vers_ts.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\version.c
+
+"$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\waitpid.c"
+
+"$(INTDIR)\waitpid.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\watch.c
+
+"$(INTDIR)\watch.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=".\windows-NT\woe32.c"
+
+"$(INTDIR)\woe32.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\wrapper.c
+
+"$(INTDIR)\wrapper.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\zlib.c
+
+"$(INTDIR)\zlib.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!IF "$(CFG)" == "cvsnt - Win32 Release"
+
+"libdiff - Win32 Release" :
+ cd ".\diff"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdiff.mak" CFG="libdiff - Win32 Release"
+ cd ".."
+
+"libdiff - Win32 ReleaseCLEAN" :
+ cd ".\diff"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdiff.mak" CFG="libdiff - Win32 Release" RECURSE=1 CLEAN
+ cd ".."
+
+!ELSEIF "$(CFG)" == "cvsnt - Win32 Debug"
+
+"libdiff - Win32 Debug" :
+ cd ".\diff"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdiff.mak" CFG="libdiff - Win32 Debug"
+ cd ".."
+
+"libdiff - Win32 DebugCLEAN" :
+ cd ".\diff"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdiff.mak" CFG="libdiff - Win32 Debug" RECURSE=1 CLEAN
+ cd ".."
+
+!ENDIF
+
+!IF "$(CFG)" == "cvsnt - Win32 Release"
+
+"libz - Win32 Release" :
+ cd ".\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libz.mak" CFG="libz - Win32 Release"
+ cd ".."
+
+"libz - Win32 ReleaseCLEAN" :
+ cd ".\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libz.mak" CFG="libz - Win32 Release" RECURSE=1 CLEAN
+ cd ".."
+
+!ELSEIF "$(CFG)" == "cvsnt - Win32 Debug"
+
+"libz - Win32 Debug" :
+ cd ".\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libz.mak" CFG="libz - Win32 Debug"
+ cd ".."
+
+"libz - Win32 DebugCLEAN" :
+ cd ".\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libz.mak" CFG="libz - Win32 Debug" RECURSE=1 CLEAN
+ cd ".."
+
+!ENDIF
+
+!IF "$(CFG)" == "cvsnt - Win32 Release"
+
+"libcvs - Win32 Release" :
+ cd ".\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Release"
+ cd ".."
+
+"libcvs - Win32 ReleaseCLEAN" :
+ cd ".\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Release" RECURSE=1 CLEAN
+ cd ".."
+
+!ELSEIF "$(CFG)" == "cvsnt - Win32 Debug"
+
+"libcvs - Win32 Debug" :
+ cd ".\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Debug"
+ cd ".."
+
+"libcvs - Win32 DebugCLEAN" :
+ cd ".\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Debug" RECURSE=1 CLEAN
+ cd ".."
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/diff/.cvsignore b/diff/.cvsignore
new file mode 100644
index 0000000..f2e95a1
--- /dev/null
+++ b/diff/.cvsignore
@@ -0,0 +1,9 @@
+*.bb
+*.bbg
+*.da
+*.plg
+.deps
+Makefile
+WinDebug
+WinRel
+libdiff.001
diff --git a/diff/ChangeLog b/diff/ChangeLog
new file mode 100644
index 0000000..c73cf92
--- /dev/null
+++ b/diff/ChangeLog
@@ -0,0 +1,722 @@
+2004-05-31 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dsp: Add "../lib/timespec.h" and "../windows-NT/woe32.h".
+
+2004-05-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * diff.c: Include "../lib/error.h" so "error" function has prototype.
+
+2004-05-24 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerated for ../cvsnt.dsp changes.
+
+2005-05-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.mak: Regenerated after Windows full rebuild.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add .cvsignore.
+
+2004-11-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.mak: Regenerated for "../cvsnt.dsp" change.
+
+2004-11-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerated for "../lib/libcvs.dsp" change.
+
+2004-11-04 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerated for "../lib/libcvs.dsp" change.
+
+2004-11-01 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerated for "../lib/libcvs.dsp" change.
+
+2004-10-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerate for "../cvsnt.dsp" and "../lib/libcvs.dsp" change.
+
+2004-10-21 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerated for "../zlib/libz.dsp" change.
+ * libdiff.mak: Regenerated for "../zlib/libz.dsp" change.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-10-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * diff.c, diff3.c: Backout last change.
+ * Makefile.am: Add -I$(top_builddir)/lib to find getopt.h
+ * Makefile.in: Regenerated.
+
+2004-10-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * diff.c: Add support for systems that do not #include <stio.h>
+ * diff3.c: Ditto.
+
+2004-10-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerate for "../lib/libcvs.dsp" changes made 2004-10-07.
+
+2004-10-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerated for "../cvsnt.dsp" and "../lib/libcvs.dsp"
+ changes made 2004-10-05.
+ * libdiff.mak: Regenerated for "../cvsnt.dsp" and "../lib/libcvs.dsp"
+ changes made 2004-10-05.
+
+2004-09-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * libdiff.dep: Regenerated for "../cvsnt.dsp" changes made 2004-09-08.
+ * libdiff.mak: Regenerated for "../cvsnt.dsp" changes made 2004-09-08.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore GCC profiling data.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dsp: Header file list updated for GNULIB updates.
+ * libdiff.dep: Regenerated for "libdiff.dsp" changes.
+ * libdiff.mak: Regenerated for "libdiff.dsp" changes.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * libdiff.mak: Regenerated.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * libdiff.mak: Regenerated for "zlib/libz.dsp" change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-17 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dep, libdiff.mak: Regenerated for "../cvsnt.dsw" changes.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dsp: Set PROP BASE directories to projet standard
+ which has "Reset" function use project defaults.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dsp: Set default configuration on generated make files to
+ Win32 Debug.
+ (Patch from Conrad T. Pino <conrad@pino.com>.)
+ * libdiff.mak: Regenerated.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add libdiff.dep.
+ * Makefile.in: Regenerated.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dep: New generated file.
+ * libdiff.mak: Regenerated.
+ (Original patch from Conrad T. Pino <conrad@pino.com>.)
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Remove libdiff.dep.
+ * Makefile.in: Regenerated.
+
+2004-03-29 Derek Price <derek@ximbiot.com>
+
+ * libdiff.mak: Regenerated with VC++ 5.0.
+ (Original sent by Dennis Jones <djones@oregon.com>.)
+ * libdiff.dep: Removed.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * libdiff.mak: ...and correct a typo in the path.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * libdiff.mak: Remove absolute path again.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dsp, libdiff.mak: Repair & regenerate, relativizing path
+ that MSVC seems intent on keeping absolute.
+
+2004-03-27 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dep, libdiff.mak, libdiff.dsp: Repaired & regnerated.
+
+2004-03-26 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore MSVC build cruft.
+ * libdiff.dep, libdiff.mak, libdiff.dsp: Repaired & regnerated.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * libdiff.dep, libdiff.mak: New files created by Visual C++ 6.0.
+ * libdiff.dsp: Updated by Visual C++ 6.0.
+ * Makefile.am (EXTRA_DIST): Add diff.dep & diff.mak.
+ * .cvsignore: Add and remove files for new MSVC++ setup.
+
+2004-03-20 Derek Price <derek@ximbiot.com>
+
+ * diff.c (diff_run): Update string arg to const.
+ * diffrun.h: Update prototype to match.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-07-21 Derek Price <derek@ximbiot.com>
+
+ * system.h: We can assume limits.h under C89.
+
+2003-07-12 Larry Jones <lawrence.jones@eds.com>
+
+ * io.c (find_identical_ends): Update to match current diffutils
+ code and improve handling of files with no newline at end.
+ (Patch from Andrew Moise <chops@demiurgestudios.com>.)
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * diff3.c (read_diff): Fix memory leak.
+ (Patch from Kenneth Lorber <keni@his.com>.)
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-06-03 Derek Price <derek@ximbiot.com>
+
+ * README: Add this file to point would-be patchers to please send their
+ changes to the GNU diffutils project and then ask us to reimport the
+ new diffutils release with the bug fix.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * system.h: Define S_ISSOCK on SCO OpenServer.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-01 Larry Jones <lawrence.jones@eds.com>
+
+ * util.c (finish_output): Handle EINTR from waitpid.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Larry Jones <lawrence.jones@eds.com>
+
+ * system.h: Use HAVE_STRUCT_STAT_ST_BLKSIZE instead of the
+ obsolete HAVE_ST_BLKSIZE.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2002-04-28 Derek Price <oberon@umich.edu>
+
+ * diff.c: Use the system fnmatch.h when present.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * system.h: Source some header files when present to eliminate warning
+ messages under Windows.
+ (Patch from "Manfred Klug" <manklu@web.de>.)
+
+2001-08-07 Derek Price <dprice@collab.net>
+
+ * build_diff.com: Turn on verify to get a better trace of the DCL.
+ * diff3.c: Eliminate compiler warning. The VMS read rval is ssize_t
+ (signed). The VMS size_t appears to be unsigned.
+ * io.c: Eliminate compiler warning (ssize_t).
+ (Patch from Mike Marciniszyn <Mike.Marciniszyn@sanchez.com>.)
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-05-07 Larry Jones <larry.jones@sdrc.com>
+
+ * diff3.c (diff3_run): Put the name of the output file in the error
+ message instead of "could not open output file" to aid in debugging.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-03-24 Noel Cragg <noel@shave.red-bean.com>
+
+ * diff.c: fix typo in usage string.
+
+2001-03-20 Derek Price <derek.price@openavenue.com>
+ for Karl Tomlinson <k.tomlinson@auckland.ac.nz>
+
+ * diff3.c (main): changed the common file of the two diffs to
+ OLDFILE for merges and edscripts so that the diffs are more likely
+ to contain the intended changes. Not changing the horizon-lines
+ arg for the second diff. If the two diffs have the same parameters
+ equal changes in each diff are more likely to appear the same.
+
+ * analyze.c (shift_boundaries): undid Paul Eggert's patch to fix
+ the diff3 merge bug described in ccvs/doc/DIFFUTILS-2.7-BUG. The
+ patch is no longer necessary now that diff3 does its differences
+ differently. I think the hunk merges provide a better indication
+ of the area modified by the user now that the diffs are actually
+ done between the appropriate revisions.
+
+2001-03-15 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (INCLUDES): Add -I$(top_srcdir)/lib for platforms which
+ need the regex library there.
+
+ * Makefile.in: Regenerated.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * .cvsignore: Added '.deps'.
+
+ Pavel Roskin <proski@gnu.org>
+
+ * Makefile.am: New file.
+ * Makefile.in: Regenerated.
+
+2001-02-22 Derek Price <derek.price@openavenue.com>
+ Pavel Roskin <proski@gnu.org>
+
+ * Makefile.in: Don't define PR_PROGRAM - it's defined by configure.
+ Remove separate rule for util.c.
+
+2001-02-06 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+ Shawn Smith <Shawn_Smith@notes.ymp.gov>
+
+ * dir.c: Replace opendir, closedir, & readdir calls with CVS_OPENDIR,
+ CVS_CLOSEDIR, & CVS_READDIR in support of changes to handle VMS DEC C
+ 5.7 {open,read,close}dir problems. Check today's entry in the vms
+ subdir for more.
+ * system.h: definitions of CVS_*DIR provided here.
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Some changes to support Automake targets
+
+2000-10-26 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Get PR_PROGRAM from autoconf instead of hard coding.
+ (Patch submitted by Urs Thuermann <urs@isnogud.escape.de>.)
+ Also add a dependency for util.o on Makefile since PR_PROGRAM gets
+ compiled in.
+
+2000-08-03 Larry Jones <larry.jones@sdrc.com>
+
+ * diff3.c (read_diff): Use cvs_temp_name () instead of tmpnam () so
+ there's at least a chance of getting the file in the correct tmp dir.
+
+2000-07-10 Larry Jones <larry.jones@sdrc.com>
+
+ * util.c (printf_output): Fix type clashes.
+
+2000-06-15 Larry Jones <larry.jones@sdrc.com>
+
+ * diff3.c (diff3_run, make_3way_diff): Plug memory leaks.
+
+1999-12-29 Jim Kingdon <http://developer.redhat.com/>
+
+ * diff.c (compare_files): Use explicit braces with if-if-else, per
+ GNU coding standards and gcc -Wall.
+
+1999-11-23 Larry Jones <larry.jones@sdrc.com>
+
+ * diff3.c: Explicitly initialize zero_diff3 to placate neurotic
+ compilers that gripe about implicitly initialized const variables.
+ Reported by Eric Veum <sysv@yahoo.com>.
+
+1999-09-15 Larry Jones <larry.jones@sdrc.com>
+
+ * diff.c (diff_run): Move the setjmp call before the options
+ processing since option errors can call fatal which in turn
+ calls longjmp.
+
+1999-05-06 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove libdiff.mak.
+ * libdiff.mak: Removed; we are back to a single makefile for
+ Visual C++ version 4.
+
+1999-04-29 Jim Kingdon <http://www.cyclic.com>
+
+ * diff.c (diff_run): Use separate statement for setjmp call and if
+ statement. This is better style in general (IMHO) but in the case
+ of setjmp the UNICOS compiler apparently cares (I don't have the
+ standard handy, but there are lots of legitimate restrictions on
+ how you can call setjmp).
+
+1999-04-26 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add libdiff.dsp libdiff.mak .cvsignore.
+
+1999-04-26 (submitted 1999-03-24) John O'Connor <john@shore.net>
+
+ * libdiff.dsp: new file. MSVC project file used to build the library.
+
+ * libdiff.mak: new file. Makefile for building from the command-line.
+
+ * .cvsignore: Removed un-used entries related to MSVC. Added
+ entries to ignore directories generated by the NT build, Debug
+ and Release.
+
+1999-03-24 Larry Jones <larry.jones@sdrc.com>
+ and Olaf Brandes
+
+ * diff3.c (diff3_run): Use a separate stream for the input to
+ output_diff3_merge instead of reopening stdin to avoid problems
+ with leaving it open.
+
+1999-02-17 Jim Kingdon <http://www.cyclic.com>
+ and Hallvard B Furuseth.
+
+ * util.c: Use __STDC__ consistently with ./system.h.
+ * system.h: Add comment about PARAMS.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in, analyze.c, cmpbuf.c, cmpbuf.h, context.c, diff.c,
+ diff.h, diff3.c, diffrun.h, dir.c, ed.c, io.c, normal.c, system.h,
+ util.c: Remove paragraph containing the old snail mail address of
+ the Free Software Foundation.
+
+1998-09-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * util.c (printf_output): Make msg static; avoids auto
+ initializer, which is not portable to SunOS4 /bin/cc.
+ Reported by Mike Sutton@SAIC.
+
+1998-09-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add diagmeet.note.
+
+1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diffrun.h (struct diff_callbacks): Change calling convention of
+ write_output so that a zero length means to output zero bytes.
+ The cvs_output convention is just too ugly/error-prone.
+ * util.c (printf_output): Rewrite to parse format string
+ overselves rather than calling vasprintf, which cannot be
+ implemented in portable C.
+
+1998-08-06 David Masterson of kla-tencor.com
+
+ * util.c (flush_output): Don't prototype.
+
+Thu Jul 2 16:34:38 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ Simplify the callback interface:
+ * diffrun.h: Don't include <stdarg.h> or <varargs.h>.
+ (struct diff_callbacks): Remove printf_output field.
+ * util.c: Include <stdarg.h> or <varargs.h>.
+ (printf_output): Use vasprintf and write_output callback rather
+ than printf_output callback.
+ * diff3.c (read_diff): Don't set my_callbacks.printf_output.
+
+Thu Jun 18 12:43:53 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * diffrun.h: New file.
+ * diff.h: Include diffrun.h.
+ (callbacks): New EXTERN variable.
+ (write_output, printf_output, flush_output): Declare.
+ * diff.c (diff_run): Add parameter callbacks_arg. Use callback
+ functions rather than writing to stdout. Don't open a file if
+ there is a write_output callback. Call perror_with_name rather
+ than perror.
+ (usage): Use callbacks if defined rather than writing to stdout.
+ (compare_files): Call flush_output rather than fflush (outfile).
+ * diff3.c: Include diffrun.h. Change several functions to use
+ output functions from util.c rather than direct printing. Use
+ diff_error and friends rather than printing to stderr. Set global
+ variable outfile.
+ (outfile, callbacks): Declare.
+ (write_output, printf_output, flush_output): Declare.
+ (diff3_run): Add parameter callbacks_arg. Use callback functions
+ rather than writing to stdout.
+ (usage): Use callbacks if defined rather than writing to stdout.
+ (read_diff): Preserve callbacks and outfile around call to
+ diff_run.
+ * util.c (perror_with_name): Use error callback if defined.
+ (pfatal_with_name, diff_error): Likewise.
+ (message5): Use printf_output and write_output.
+ (print_message_queue, print_1_line, output_1_line): Likewise.
+ (begin_output): Reject paginate_flag if there are output
+ callbacks.
+ (write_output, printf_output, flush_output): New functions.
+ * context.c: Change all output to outfile to use printf_output and
+ write_output.
+ * ed.c: Likewise.
+ * ifdef.c: Likewise.
+ * normal.c: Likewise.
+ * side.c: Likewise.
+ * Makefile.in (SOURCES): Add diffrun.h.
+ ($(OBJECTS)): Depend upon diffrun.h.
+
+Fri Jan 16 14:58:19 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * diff.c, diff3.c: Plug memory leaks.
+
+Thu Jan 15 13:36:46 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (installdirs): New rule, for when ../Makefile
+ recurses into this directory (bug reported by W. L. Estes).
+
+Tue Nov 11 10:48:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (diff_run): Change #ifdef on HAVE_SETMODE to #if to match
+ the other uses (fixes compilation error on unix).
+
+ * diff.c (diff_run): Don't set stdout to binary mode.
+
+Mon, 10 Nov 1997 Jim Kingdon
+
+ * diff.c (run_diff): Open outfile in binary mode if --binary.
+
+Thu Nov 6 12:42:12 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Paul Eggert <eggert@twinsun.com>
+
+ * analyze.c: applied Paul Eggert's patch to fix the diff3 merge
+ bug described in ccvs/doc/DIFFUTILS-2.7-BUG:
+ (shift_boundaries): new var `inhibit_hunk_merge'; use it to
+ control something important that I don't quite understand, but
+ Paul apparently does, so that's okay.
+
+Sat Nov 1 14:17:57 1997 Michael L.H. Brouwer <michael@thi.nl>
+
+ * Makefile.in: Add call to ranlib to build a table of contents for
+ the library since some systems seem to require this.
+
+1997-10-28 Jim Kingdon
+
+ * .cvsignore: Add files du jour for Visual C++, vc50.pdb and vc50.idb.
+
+ * system.h: Define HAVE_TIME_H.
+ * dir.c [_WIN32]: Define CLOSEDIR_VOID.
+
+1997-10-18 Jim Kingdon
+
+ * build_diff.com: Add diff3.c
+
+Fri Sep 26 14:24:42 1997 Tim Pierce <twp@twp.tezcat.com>
+
+ * diff.c (diff_run): Save old value of optind before calling
+ getopt_long, then restore before returning. Eventually it would
+ be nice if diff_run were fully reentrant.
+
+ New diff3 library for CVS.
+ * Makefile.in (SOURCES): Add diff3.c.
+ (OBJECTS): Add diff3.o.
+ * diff3.c: New file, copied from diffutils-2.7. See diffutils for
+ earlier ChangeLogs. Undefine initialize_main macro. Remove <signal.h>.
+ (diff3_run): Renamed from main(). Add `outfile' argument. Remove
+ SIGCLD handling; we do not fork. Save optind and reset to 0
+ before calling getopt_long; restore after option processing done.
+ (read_diff): Use diff_run with a temporary output file,
+ instead of forking a diff subprocess and reading from a pipe.
+ Change DIFF_PROGRAM to "diff"; this argument is now used only for
+ diagnostic reporting.
+ (xmalloc, xrealloc): Removed.
+ (diff_program): Removed.
+ (diff_program_name): Made extern, so it may be used in other
+ library calls like `error'.
+ (initialize_main): New function.
+
+ Namespace munging. util.c defines both fatal() and
+ perror_with_exit(), but these cannot be used to abort diff3: both
+ attempt to longjmp() to a buffer set in diff.c, used only by
+ diff_run. This is an awful solution, but necessary until the code
+ can be cleaned up. (These functions do not *have* to be renamed,
+ since both are declared static to diff3.c and should not clash
+ with libdiff.a, but it reduces potential confusion.)
+ * diff3.c (diff3_fatal): Renamed from fatal.
+ (diff3_perror_with_exit): Renamed from perror_with_exit.
+
+ Eliminate exit calls.
+ (try_help): Change from `void' to `int'. Return, do not exit.
+ (diff3_fatal, diff3_perror_with_exit, process_diff): Change `exit'
+ to DIFF3_ABORT.
+ (diff3_run): Initialize jump buffer for nonlocal exits. Change
+ exit calls to returns. Change `perror_with_exit' to
+ `perror_with_name' and add a return. Change `fatal' to
+ `diff_error' and add a return. The reasoning is that we shouldn't
+ rely on setjmp/longjmp any more than necessary.
+
+ Redirect stdout.
+ (check_output): Renamed from check_stdout. Take stream argument
+ instead of blindly checking stdout. Do not close stream, but
+ merely fflush it.
+ (diff3_run): Initialize outstream, and close when done. Pass this
+ stream (instead of stdout) to output_diff3_edscript,
+ output_diff3_merge, and output_diff3.
+
+Thu Sep 25 14:34:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * util.c (begin_output, finish_output): If PR_PROGRAM is not
+ defined (VMS), just give a fatal error if --paginate specified.
+
+ * Makefile.in (DISTFILES): Add ChangeLog build_diff.com
+ Makefile.in.
+ * build_diff.com: New file.
+
+Wed Sep 24 10:27:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Also set top_srcdir. Needed to make today's other
+ Makefile.in change work.
+
+ * .cvsignore: New file.
+
+ * Makefile.in (COMPILE): Add -I options for srcdir (perhaps
+ unneeded) and change -I option for lib to use top_srcdir (needed
+ to avoid mixups with CVS's regex.h vs. the system one).
+
+Sun Sep 21 19:44:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (util.o): Change util.c to $<, needed for srcdir.
+
+Sat Sep 20 12:06:41 1997 Tim Pierce <twp@twp.tezcat.com>
+
+ New diff library for CVS, based on diffutils-2.7. See diffutils
+ for earlier ChangeLogs.
+ * Makefile.in, analyze.c, cmpbuf.c, cmpbuf.h, config.hin,
+ context.c, diagmeet.note, diff.c, diff.h, dir.c, ed.c, ifdef.c,
+ io.c, normal.c, side.c, stamp-h.in, system.h, util.c, version.c:
+ New files.
+ (COMPILE): Add -I../lib, so we can get getopt.h.
+
+ * Makefile.in: Removed anything not related to libdiff.a.
+ (dist-dir): New target, copied from ../lib/Makefile.in.
+ (DISTFILES): New variable.
+ (SOURCES): Renamed from `srcs'.
+ (OBJECTS): Renamed from `libdiff_o'.
+ (Makefile): Changed dependencies to reflect
+ new, shallow config directory structure.
+ (stamp-h.in, config.h.in, config.h, stamp-h): Removed.
+ * stamp-h.in, config.h.in: Removed.
+
+ * system.h: Remove dup2 macro (provided by ../lib/dup2.c).
+ Include stdlib.h if STDC_HEADERS is defined (not just
+ HAVE_STDLIB_H).
+
+Sat Sep 20 05:32:18 1997 Tim Pierce <twp@twp.tezcat.com>
+
+ Diff librarification.
+
+ * diff.c (diff_run): New function, renamed from `main'.
+ Initialize `outfile' based on the value of the new `out' filename
+ argument.
+ (initialize_main): New function.
+ * system.h: Removed initialize_main macro.
+ * diffmain.c: New file.
+ * Makefile.in (diff): Added diffmain.o.
+ (libdiff): New target.
+ (AR, libdiff_o): New variables. libdiff_o does not include
+ xmalloc.o, fnmatch.o, getopt.o, getopt1.o, regex.o or error.o,
+ because these functions are already present in CVS. It will take
+ some work to make this more general-purpose.
+
+ Redirect standard output.
+ * util.c: Redirect stdout to outfile: change all naked `printf'
+ and `putchar' statements to `fprintf (outfile)' and `putc (...,
+ outfile)' throughout. This should permit redirecting diff output
+ by changing `outfile' just once in `diff_run'.
+ (output_in_progress): New variable.
+ (begin_output, finish_output): Use `output_in_progress', rather than
+ `outfile', as a semaphore to avoid reentrancy problems.
+ (finish_output): Close `outfile' only if paginate_flag is set.
+ * diff.c (check_output): New function, was check_stdout. Take a
+ `file' argument, and flush it instead of closing it.
+ (diff_run): Change check_stdout to check_output.
+ (compare_files): Fflush outfile, not stdout.
+
+ Eliminate exit statements.
+ * diff.h: Include setjmp.h.
+ (diff_abort_buf): New variable.
+ (DIFF_ABORT): New macro.
+ * diff.c (diff_run): Change all `exit' statements to `return'.
+ Set up diff_abort_buf, so we can abort diff without
+ terminating (for libdiff.a).
+ (try_help): Return int instead of void; do not exit.
+ * util.c (fatal): Use DIFF_ABORT instead of exit.
+ (pfatal_with_name): Use DIFF_ABORT instead of exit.
+
+ Namespace cleanup (rudimentary). Strictly speaking, this is not
+ necessary to make diff into a library. However, namespace
+ clashes between diff and CVS must be resolved immediately, since
+ CVS is the first application targeted for use with difflib.
+
+ * analyze.c, diff.c, diff.h, util.c (diff_error): Renamed from `error'.
+
+ * version.c, diff.c, diff.h, cmp.c, diff3.c, sdiff.c
+ (diff_version_string): Renamed from version_string.
+ * diff.c, util.c, diff.h, diff3.c, error.c (diff_program_name):
+ Renamed from program_name.
+
+ * util.c (xmalloc, xrealloc): Removed.
+ * Makefile.in (diff_o): Added error.o and xmalloc.o.
+
diff --git a/diff/Makefile.am b/diff/Makefile.am
new file mode 100644
index 0000000..d3f4834
--- /dev/null
+++ b/diff/Makefile.am
@@ -0,0 +1,31 @@
+## Makefile.am for GNU DIFF
+## Copyright (C) 2001 Free Software Foundation, Inc.
+##
+## This file is part of GNU DIFF.
+##
+## GNU DIFF is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## GNU DIFF is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+INCLUDES = -I$(top_srcdir)/lib -I$(top_builddir)/lib
+
+noinst_LIBRARIES = libdiff.a
+
+libdiff_a_SOURCES = diff.c diff3.c analyze.c cmpbuf.c cmpbuf.h io.c \
+ context.c ed.c normal.c ifdef.c util.c dir.c version.c diff.h \
+ side.c system.h diffrun.h
+
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ build_diff.com \
+ diagmeet.note \
+ libdiff.dep \
+ libdiff.dsp \
+ libdiff.mak
diff --git a/diff/Makefile.in b/diff/Makefile.in
new file mode 100644
index 0000000..31ffbe4
--- /dev/null
+++ b/diff/Makefile.in
@@ -0,0 +1,525 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = diff
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+AR = ar
+ARFLAGS = cru
+libdiff_a_AR = $(AR) $(ARFLAGS)
+libdiff_a_LIBADD =
+am_libdiff_a_OBJECTS = diff.$(OBJEXT) diff3.$(OBJEXT) \
+ analyze.$(OBJEXT) cmpbuf.$(OBJEXT) io.$(OBJEXT) \
+ context.$(OBJEXT) ed.$(OBJEXT) normal.$(OBJEXT) \
+ ifdef.$(OBJEXT) util.$(OBJEXT) dir.$(OBJEXT) version.$(OBJEXT) \
+ side.$(OBJEXT)
+libdiff_a_OBJECTS = $(am_libdiff_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libdiff_a_SOURCES)
+DIST_SOURCES = $(libdiff_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+INCLUDES = -I$(top_srcdir)/lib -I$(top_builddir)/lib
+noinst_LIBRARIES = libdiff.a
+libdiff_a_SOURCES = diff.c diff3.c analyze.c cmpbuf.c cmpbuf.h io.c \
+ context.c ed.c normal.c ifdef.c util.c dir.c version.c diff.h \
+ side.c system.h diffrun.h
+
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ build_diff.com \
+ diagmeet.note \
+ libdiff.dep \
+ libdiff.dsp \
+ libdiff.mak
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu diff/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu diff/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libdiff.a: $(libdiff_a_OBJECTS) $(libdiff_a_DEPENDENCIES)
+ -rm -f libdiff.a
+ $(libdiff_a_AR) libdiff.a $(libdiff_a_OBJECTS) $(libdiff_a_LIBADD)
+ $(RANLIB) libdiff.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/analyze.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmpbuf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diff3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ed.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifdef.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/normal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/side.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/diff/README b/diff/README
new file mode 100644
index 0000000..0af33d7
--- /dev/null
+++ b/diff/README
@@ -0,0 +1,8 @@
+The files in this directory come from the GNU diffutils project
+<http://savannah.gnu.org/projects/diffutils/>/<mailto:bug-gnu-utils@gnu.org>,
+and, if they don't, they should.
+
+What this means is that bug fixes and enhancements to this code should be sent
+to the diffutils project and then reimported here after the diffutils
+developers approve and adopt the change. Changes should not be made locally
+without good reason!
diff --git a/diff/analyze.c b/diff/analyze.c
new file mode 100644
index 0000000..3262444
--- /dev/null
+++ b/diff/analyze.c
@@ -0,0 +1,1082 @@
+/* Analyze file differences for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993, 1997 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+/* The basic algorithm is described in:
+ "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
+ Algorithmica Vol. 1 No. 2, 1986, pp. 251-266;
+ see especially section 4.2, which describes the variation used below.
+ Unless the --minimal option is specified, this code uses the TOO_EXPENSIVE
+ heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N)
+ at the price of producing suboptimal output for large inputs with
+ many differences.
+
+ The basic algorithm was independently discovered as described in:
+ "Algorithms for Approximate String Matching", E. Ukkonen,
+ Information and Control Vol. 64, 1985, pp. 100-118. */
+
+#include "diff.h"
+#include "cmpbuf.h"
+
+extern int no_discards;
+
+static int *xvec, *yvec; /* Vectors being compared. */
+static int *fdiag; /* Vector, indexed by diagonal, containing
+ 1 + the X coordinate of the point furthest
+ along the given diagonal in the forward
+ search of the edit matrix. */
+static int *bdiag; /* Vector, indexed by diagonal, containing
+ the X coordinate of the point furthest
+ along the given diagonal in the backward
+ search of the edit matrix. */
+static int too_expensive; /* Edit scripts longer than this are too
+ expensive to compute. */
+
+#define SNAKE_LIMIT 20 /* Snakes bigger than this are considered `big'. */
+
+struct partition
+{
+ int xmid, ymid; /* Midpoints of this partition. */
+ int lo_minimal; /* Nonzero if low half will be analyzed minimally. */
+ int hi_minimal; /* Likewise for high half. */
+};
+
+static int diag PARAMS((int, int, int, int, int, struct partition *));
+static struct change *add_change PARAMS((int, int, int, int, struct change *));
+static struct change *build_reverse_script PARAMS((struct file_data const[]));
+static struct change *build_script PARAMS((struct file_data const[]));
+static void briefly_report PARAMS((int, struct file_data const[]));
+static void compareseq PARAMS((int, int, int, int, int));
+static void discard_confusing_lines PARAMS((struct file_data[]));
+static void shift_boundaries PARAMS((struct file_data[]));
+
+/* Find the midpoint of the shortest edit script for a specified
+ portion of the two files.
+
+ Scan from the beginnings of the files, and simultaneously from the ends,
+ doing a breadth-first search through the space of edit-sequence.
+ When the two searches meet, we have found the midpoint of the shortest
+ edit sequence.
+
+ If MINIMAL is nonzero, find the minimal edit script regardless
+ of expense. Otherwise, if the search is too expensive, use
+ heuristics to stop the search and report a suboptimal answer.
+
+ Set PART->(XMID,YMID) to the midpoint (XMID,YMID). The diagonal number
+ XMID - YMID equals the number of inserted lines minus the number
+ of deleted lines (counting only lines before the midpoint).
+ Return the approximate edit cost; this is the total number of
+ lines inserted or deleted (counting only lines before the midpoint),
+ unless a heuristic is used to terminate the search prematurely.
+
+ Set PART->LEFT_MINIMAL to nonzero iff the minimal edit script for the
+ left half of the partition is known; similarly for PART->RIGHT_MINIMAL.
+
+ This function assumes that the first lines of the specified portions
+ of the two files do not match, and likewise that the last lines do not
+ match. The caller must trim matching lines from the beginning and end
+ of the portions it is going to specify.
+
+ If we return the "wrong" partitions,
+ the worst this can do is cause suboptimal diff output.
+ It cannot cause incorrect diff output. */
+
+static int
+diag (xoff, xlim, yoff, ylim, minimal, part)
+ int xoff, xlim, yoff, ylim, minimal;
+ struct partition *part;
+{
+ int *const fd = fdiag; /* Give the compiler a chance. */
+ int *const bd = bdiag; /* Additional help for the compiler. */
+ int const *const xv = xvec; /* Still more help for the compiler. */
+ int const *const yv = yvec; /* And more and more . . . */
+ int const dmin = xoff - ylim; /* Minimum valid diagonal. */
+ int const dmax = xlim - yoff; /* Maximum valid diagonal. */
+ int const fmid = xoff - yoff; /* Center diagonal of top-down search. */
+ int const bmid = xlim - ylim; /* Center diagonal of bottom-up search. */
+ int fmin = fmid, fmax = fmid; /* Limits of top-down search. */
+ int bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */
+ int c; /* Cost. */
+ int odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd
+ diagonal with respect to the northwest. */
+
+ fd[fmid] = xoff;
+ bd[bmid] = xlim;
+
+ for (c = 1;; ++c)
+ {
+ int d; /* Active diagonal. */
+ int big_snake = 0;
+
+ /* Extend the top-down search by an edit step in each diagonal. */
+ fmin > dmin ? fd[--fmin - 1] = -1 : ++fmin;
+ fmax < dmax ? fd[++fmax + 1] = -1 : --fmax;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x, y, oldx, tlo = fd[d - 1], thi = fd[d + 1];
+
+ if (tlo >= thi)
+ x = tlo + 1;
+ else
+ x = thi;
+ oldx = x;
+ y = x - d;
+ while (x < xlim && y < ylim && xv[x] == yv[y])
+ ++x, ++y;
+ if (x - oldx > SNAKE_LIMIT)
+ big_snake = 1;
+ fd[d] = x;
+ if (odd && bmin <= d && d <= bmax && bd[d] <= x)
+ {
+ part->xmid = x;
+ part->ymid = y;
+ part->lo_minimal = part->hi_minimal = 1;
+ return 2 * c - 1;
+ }
+ }
+
+ /* Similarly extend the bottom-up search. */
+ bmin > dmin ? bd[--bmin - 1] = INT_MAX : ++bmin;
+ bmax < dmax ? bd[++bmax + 1] = INT_MAX : --bmax;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x, y, oldx, tlo = bd[d - 1], thi = bd[d + 1];
+
+ if (tlo < thi)
+ x = tlo;
+ else
+ x = thi - 1;
+ oldx = x;
+ y = x - d;
+ while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1])
+ --x, --y;
+ if (oldx - x > SNAKE_LIMIT)
+ big_snake = 1;
+ bd[d] = x;
+ if (!odd && fmin <= d && d <= fmax && x <= fd[d])
+ {
+ part->xmid = x;
+ part->ymid = y;
+ part->lo_minimal = part->hi_minimal = 1;
+ return 2 * c;
+ }
+ }
+
+ if (minimal)
+ continue;
+
+ /* Heuristic: check occasionally for a diagonal that has made
+ lots of progress compared with the edit distance.
+ If we have any such, find the one that has made the most
+ progress and return it as if it had succeeded.
+
+ With this heuristic, for files with a constant small density
+ of changes, the algorithm is linear in the file size. */
+
+ if (c > 200 && big_snake && heuristic)
+ {
+ int best;
+
+ best = 0;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int dd = d - fmid;
+ int x = fd[d];
+ int y = x - d;
+ int v = (x - xoff) * 2 - dd;
+ if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+ {
+ if (v > best
+ && xoff + SNAKE_LIMIT <= x && x < xlim
+ && yoff + SNAKE_LIMIT <= y && y < ylim)
+ {
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ int k;
+
+ for (k = 1; xv[x - k] == yv[y - k]; k++)
+ if (k == SNAKE_LIMIT)
+ {
+ best = v;
+ part->xmid = x;
+ part->ymid = y;
+ break;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ part->lo_minimal = 1;
+ part->hi_minimal = 0;
+ return 2 * c - 1;
+ }
+
+ best = 0;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int dd = d - bmid;
+ int x = bd[d];
+ int y = x - d;
+ int v = (xlim - x) * 2 + dd;
+ if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+ {
+ if (v > best
+ && xoff < x && x <= xlim - SNAKE_LIMIT
+ && yoff < y && y <= ylim - SNAKE_LIMIT)
+ {
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ int k;
+
+ for (k = 0; xv[x + k] == yv[y + k]; k++)
+ if (k == SNAKE_LIMIT - 1)
+ {
+ best = v;
+ part->xmid = x;
+ part->ymid = y;
+ break;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ part->lo_minimal = 0;
+ part->hi_minimal = 1;
+ return 2 * c - 1;
+ }
+ }
+
+ /* Heuristic: if we've gone well beyond the call of duty,
+ give up and report halfway between our best results so far. */
+ if (c >= too_expensive)
+ {
+ int fxybest, fxbest;
+ int bxybest, bxbest;
+
+ fxbest = bxbest = 0; /* Pacify `gcc -Wall'. */
+
+ /* Find forward diagonal that maximizes X + Y. */
+ fxybest = -1;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x = min (fd[d], xlim);
+ int y = x - d;
+ if (ylim < y)
+ x = ylim + d, y = ylim;
+ if (fxybest < x + y)
+ {
+ fxybest = x + y;
+ fxbest = x;
+ }
+ }
+
+ /* Find backward diagonal that minimizes X + Y. */
+ bxybest = INT_MAX;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x = max (xoff, bd[d]);
+ int y = x - d;
+ if (y < yoff)
+ x = yoff + d, y = yoff;
+ if (x + y < bxybest)
+ {
+ bxybest = x + y;
+ bxbest = x;
+ }
+ }
+
+ /* Use the better of the two diagonals. */
+ if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff))
+ {
+ part->xmid = fxbest;
+ part->ymid = fxybest - fxbest;
+ part->lo_minimal = 1;
+ part->hi_minimal = 0;
+ }
+ else
+ {
+ part->xmid = bxbest;
+ part->ymid = bxybest - bxbest;
+ part->lo_minimal = 0;
+ part->hi_minimal = 1;
+ }
+ return 2 * c - 1;
+ }
+ }
+}
+
+/* Compare in detail contiguous subsequences of the two files
+ which are known, as a whole, to match each other.
+
+ The results are recorded in the vectors files[N].changed_flag, by
+ storing a 1 in the element for each line that is an insertion or deletion.
+
+ The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
+
+ Note that XLIM, YLIM are exclusive bounds.
+ All line numbers are origin-0 and discarded lines are not counted.
+
+ If MINIMAL is nonzero, find a minimal difference no matter how
+ expensive it is. */
+
+static void
+compareseq (xoff, xlim, yoff, ylim, minimal)
+ int xoff, xlim, yoff, ylim, minimal;
+{
+ int * const xv = xvec; /* Help the compiler. */
+ int * const yv = yvec;
+
+ /* Slide down the bottom initial diagonal. */
+ while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff])
+ ++xoff, ++yoff;
+ /* Slide up the top initial diagonal. */
+ while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1])
+ --xlim, --ylim;
+
+ /* Handle simple cases. */
+ if (xoff == xlim)
+ while (yoff < ylim)
+ files[1].changed_flag[files[1].realindexes[yoff++]] = 1;
+ else if (yoff == ylim)
+ while (xoff < xlim)
+ files[0].changed_flag[files[0].realindexes[xoff++]] = 1;
+ else
+ {
+ int c;
+ struct partition part;
+
+ /* Find a point of correspondence in the middle of the files. */
+
+ c = diag (xoff, xlim, yoff, ylim, minimal, &part);
+
+ if (c == 1)
+ {
+ /* This should be impossible, because it implies that
+ one of the two subsequences is empty,
+ and that case was handled above without calling `diag'.
+ Let's verify that this is true. */
+ abort ();
+#if 0
+ /* The two subsequences differ by a single insert or delete;
+ record it and we are done. */
+ if (part.xmid - part.ymid < xoff - yoff)
+ files[1].changed_flag[files[1].realindexes[part.ymid - 1]] = 1;
+ else
+ files[0].changed_flag[files[0].realindexes[part.xmid]] = 1;
+#endif
+ }
+ else
+ {
+ /* Use the partitions to split this problem into subproblems. */
+ compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal);
+ compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal);
+ }
+ }
+}
+
+/* Discard lines from one file that have no matches in the other file.
+
+ A line which is discarded will not be considered by the actual
+ comparison algorithm; it will be as if that line were not in the file.
+ The file's `realindexes' table maps virtual line numbers
+ (which don't count the discarded lines) into real line numbers;
+ this is how the actual comparison algorithm produces results
+ that are comprehensible when the discarded lines are counted.
+
+ When we discard a line, we also mark it as a deletion or insertion
+ so that it will be printed in the output. */
+
+static void
+discard_confusing_lines (filevec)
+ struct file_data filevec[];
+{
+ unsigned int f, i;
+ char *discarded[2];
+ int *equiv_count[2];
+ int *p;
+
+ /* Allocate our results. */
+ p = (int *) xmalloc ((filevec[0].buffered_lines + filevec[1].buffered_lines)
+ * (2 * sizeof (int)));
+ for (f = 0; f < 2; f++)
+ {
+ filevec[f].undiscarded = p; p += filevec[f].buffered_lines;
+ filevec[f].realindexes = p; p += filevec[f].buffered_lines;
+ }
+
+ /* Set up equiv_count[F][I] as the number of lines in file F
+ that fall in equivalence class I. */
+
+ p = (int *) xmalloc (filevec[0].equiv_max * (2 * sizeof (int)));
+ equiv_count[0] = p;
+ equiv_count[1] = p + filevec[0].equiv_max;
+ bzero (p, filevec[0].equiv_max * (2 * sizeof (int)));
+
+ for (i = 0; i < filevec[0].buffered_lines; ++i)
+ ++equiv_count[0][filevec[0].equivs[i]];
+ for (i = 0; i < filevec[1].buffered_lines; ++i)
+ ++equiv_count[1][filevec[1].equivs[i]];
+
+ /* Set up tables of which lines are going to be discarded. */
+
+ discarded[0] = xmalloc (sizeof (char)
+ * (filevec[0].buffered_lines
+ + filevec[1].buffered_lines));
+ discarded[1] = discarded[0] + filevec[0].buffered_lines;
+ bzero (discarded[0], sizeof (char) * (filevec[0].buffered_lines
+ + filevec[1].buffered_lines));
+
+ /* Mark to be discarded each line that matches no line of the other file.
+ If a line matches many lines, mark it as provisionally discardable. */
+
+ for (f = 0; f < 2; f++)
+ {
+ unsigned int end = filevec[f].buffered_lines;
+ char *discards = discarded[f];
+ int *counts = equiv_count[1 - f];
+ int *equivs = filevec[f].equivs;
+ unsigned int many = 5;
+ unsigned int tem = end / 64;
+
+ /* Multiply MANY by approximate square root of number of lines.
+ That is the threshold for provisionally discardable lines. */
+ while ((tem = tem >> 2) > 0)
+ many *= 2;
+
+ for (i = 0; i < end; i++)
+ {
+ int nmatch;
+ if (equivs[i] == 0)
+ continue;
+ nmatch = counts[equivs[i]];
+ if (nmatch == 0)
+ discards[i] = 1;
+ else if (nmatch > many)
+ discards[i] = 2;
+ }
+ }
+
+ /* Don't really discard the provisional lines except when they occur
+ in a run of discardables, with nonprovisionals at the beginning
+ and end. */
+
+ for (f = 0; f < 2; f++)
+ {
+ unsigned int end = filevec[f].buffered_lines;
+ register char *discards = discarded[f];
+
+ for (i = 0; i < end; i++)
+ {
+ /* Cancel provisional discards not in middle of run of discards. */
+ if (discards[i] == 2)
+ discards[i] = 0;
+ else if (discards[i] != 0)
+ {
+ /* We have found a nonprovisional discard. */
+ register int j;
+ unsigned int length;
+ unsigned int provisional = 0;
+
+ /* Find end of this run of discardable lines.
+ Count how many are provisionally discardable. */
+ for (j = i; j < end; j++)
+ {
+ if (discards[j] == 0)
+ break;
+ if (discards[j] == 2)
+ ++provisional;
+ }
+
+ /* Cancel provisional discards at end, and shrink the run. */
+ while (j > i && discards[j - 1] == 2)
+ discards[--j] = 0, --provisional;
+
+ /* Now we have the length of a run of discardable lines
+ whose first and last are not provisional. */
+ length = j - i;
+
+ /* If 1/4 of the lines in the run are provisional,
+ cancel discarding of all provisional lines in the run. */
+ if (provisional * 4 > length)
+ {
+ while (j > i)
+ if (discards[--j] == 2)
+ discards[j] = 0;
+ }
+ else
+ {
+ register unsigned int consec;
+ unsigned int minimum = 1;
+ unsigned int tem = length / 4;
+
+ /* MINIMUM is approximate square root of LENGTH/4.
+ A subrun of two or more provisionals can stand
+ when LENGTH is at least 16.
+ A subrun of 4 or more can stand when LENGTH >= 64. */
+ while ((tem = tem >> 2) > 0)
+ minimum *= 2;
+ minimum++;
+
+ /* Cancel any subrun of MINIMUM or more provisionals
+ within the larger run. */
+ for (j = 0, consec = 0; j < length; j++)
+ if (discards[i + j] != 2)
+ consec = 0;
+ else if (minimum == ++consec)
+ /* Back up to start of subrun, to cancel it all. */
+ j -= consec;
+ else if (minimum < consec)
+ discards[i + j] = 0;
+
+ /* Scan from beginning of run
+ until we find 3 or more nonprovisionals in a row
+ or until the first nonprovisional at least 8 lines in.
+ Until that point, cancel any provisionals. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i + j] == 1)
+ break;
+ if (discards[i + j] == 2)
+ consec = 0, discards[i + j] = 0;
+ else if (discards[i + j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+
+ /* I advances to the last line of the run. */
+ i += length - 1;
+
+ /* Same thing, from end. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i - j] == 1)
+ break;
+ if (discards[i - j] == 2)
+ consec = 0, discards[i - j] = 0;
+ else if (discards[i - j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Actually discard the lines. */
+ for (f = 0; f < 2; f++)
+ {
+ char *discards = discarded[f];
+ unsigned int end = filevec[f].buffered_lines;
+ unsigned int j = 0;
+ for (i = 0; i < end; ++i)
+ if (no_discards || discards[i] == 0)
+ {
+ filevec[f].undiscarded[j] = filevec[f].equivs[i];
+ filevec[f].realindexes[j++] = i;
+ }
+ else
+ filevec[f].changed_flag[i] = 1;
+ filevec[f].nondiscarded_lines = j;
+ }
+
+ free (discarded[0]);
+ free (equiv_count[0]);
+}
+
+/* Adjust inserts/deletes of identical lines to join changes
+ as much as possible.
+
+ We do something when a run of changed lines include a
+ line at one end and have an excluded, identical line at the other.
+ We are free to choose which identical line is included.
+ `compareseq' usually chooses the one at the beginning,
+ but usually it is cleaner to consider the following identical line
+ to be the "change". */
+
+int inhibit;
+
+static void
+shift_boundaries (filevec)
+ struct file_data filevec[];
+{
+ int f;
+
+ if (inhibit)
+ return;
+
+ for (f = 0; f < 2; f++)
+ {
+ char *changed = filevec[f].changed_flag;
+ char const *other_changed = filevec[1-f].changed_flag;
+ int const *equivs = filevec[f].equivs;
+ int i = 0;
+ int j = 0;
+ int i_end = filevec[f].buffered_lines;
+
+ while (1)
+ {
+ int runlength, start, corresponding;
+
+ /* Scan forwards to find beginning of another run of changes.
+ Also keep track of the corresponding point in the other file. */
+
+ while (i < i_end && changed[i] == 0)
+ {
+ while (other_changed[j++])
+ continue;
+ i++;
+ }
+
+ if (i == i_end)
+ break;
+
+ start = i;
+
+ /* Find the end of this run of changes. */
+
+ while (changed[++i])
+ continue;
+ while (other_changed[j])
+ j++;
+
+ do
+ {
+ /* Record the length of this run of changes, so that
+ we can later determine whether the run has grown. */
+ runlength = i - start;
+
+ /* Move the changed region back, so long as the
+ previous unchanged line matches the last changed one.
+ This merges with previous changed regions. */
+
+ while (start && equivs[start - 1] == equivs[i - 1])
+ {
+ changed[--start] = 1;
+ changed[--i] = 0;
+ while (changed[start - 1])
+ start--;
+ while (other_changed[--j])
+ continue;
+ }
+
+ /* Set CORRESPONDING to the end of the changed run, at the last
+ point where it corresponds to a changed run in the other file.
+ CORRESPONDING == I_END means no such point has been found. */
+ corresponding = other_changed[j - 1] ? i : i_end;
+
+ /* Move the changed region forward, so long as the
+ first changed line matches the following unchanged one.
+ This merges with following changed regions.
+ Do this second, so that if there are no merges,
+ the changed region is moved forward as far as possible. */
+
+ while (i != i_end && equivs[start] == equivs[i])
+ {
+ changed[start++] = 0;
+ changed[i++] = 1;
+ while (changed[i])
+ i++;
+ while (other_changed[++j])
+ corresponding = i;
+ }
+ }
+ while (runlength != i - start);
+
+ /* If possible, move the fully-merged run of changes
+ back to a corresponding run in the other file. */
+
+ while (corresponding < i)
+ {
+ changed[--start] = 1;
+ changed[--i] = 0;
+ while (other_changed[--j])
+ continue;
+ }
+ }
+ }
+}
+
+/* Cons an additional entry onto the front of an edit script OLD.
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+
+static struct change *
+add_change (line0, line1, deleted, inserted, old)
+ int line0, line1, deleted, inserted;
+ struct change *old;
+{
+ struct change *new = (struct change *) xmalloc (sizeof (struct change));
+
+ new->line0 = line0;
+ new->line1 = line1;
+ new->inserted = inserted;
+ new->deleted = deleted;
+ new->link = old;
+ return new;
+}
+
+/* Scan the tables of which lines are inserted and deleted,
+ producing an edit script in reverse order. */
+
+static struct change *
+build_reverse_script (filevec)
+ struct file_data const filevec[];
+{
+ struct change *script = 0;
+ char *changed0 = filevec[0].changed_flag;
+ char *changed1 = filevec[1].changed_flag;
+ int len0 = filevec[0].buffered_lines;
+ int len1 = filevec[1].buffered_lines;
+
+ /* Note that changedN[len0] does exist, and contains 0. */
+
+ int i0 = 0, i1 = 0;
+
+ while (i0 < len0 || i1 < len1)
+ {
+ if (changed0[i0] || changed1[i1])
+ {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[i0]) ++i0;
+ while (changed1[i1]) ++i1;
+
+ /* Record this change. */
+ script = add_change (line0, line1, i0 - line0, i1 - line1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0++, i1++;
+ }
+
+ return script;
+}
+
+/* Scan the tables of which lines are inserted and deleted,
+ producing an edit script in forward order. */
+
+static struct change *
+build_script (filevec)
+ struct file_data const filevec[];
+{
+ struct change *script = 0;
+ char *changed0 = filevec[0].changed_flag;
+ char *changed1 = filevec[1].changed_flag;
+ int i0 = filevec[0].buffered_lines, i1 = filevec[1].buffered_lines;
+
+ /* Note that changedN[-1] does exist, and contains 0. */
+
+ while (i0 >= 0 || i1 >= 0)
+ {
+ if (changed0[i0 - 1] || changed1[i1 - 1])
+ {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[i0 - 1]) --i0;
+ while (changed1[i1 - 1]) --i1;
+
+ /* Record this change. */
+ script = add_change (i0, i1, line0 - i0, line1 - i1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0--, i1--;
+ }
+
+ return script;
+}
+
+/* If CHANGES, briefly report that two files differed. */
+static void
+briefly_report (changes, filevec)
+ int changes;
+ struct file_data const filevec[];
+{
+ if (changes)
+ message (no_details_flag ? "Files %s and %s differ\n"
+ : "Binary files %s and %s differ\n",
+ filevec[0].name, filevec[1].name);
+}
+
+/* Report the differences of two files. DEPTH is the current directory
+ depth. */
+int
+diff_2_files (filevec, depth)
+ struct file_data filevec[];
+ int depth;
+{
+ int diags;
+ int i;
+ struct change *e, *p;
+ struct change *script;
+ int changes;
+
+
+ /* If we have detected that either file is binary,
+ compare the two files as binary. This can happen
+ only when the first chunk is read.
+ Also, --brief without any --ignore-* options means
+ we can speed things up by treating the files as binary. */
+
+ if (read_files (filevec, no_details_flag & ~ignore_some_changes))
+ {
+ /* Files with different lengths must be different. */
+ if (filevec[0].stat.st_size != filevec[1].stat.st_size
+ && (filevec[0].desc < 0 || S_ISREG (filevec[0].stat.st_mode))
+ && (filevec[1].desc < 0 || S_ISREG (filevec[1].stat.st_mode)))
+ changes = 1;
+
+ /* Standard input equals itself. */
+ else if (filevec[0].desc == filevec[1].desc)
+ changes = 0;
+
+ else
+ /* Scan both files, a buffer at a time, looking for a difference. */
+ {
+ /* Allocate same-sized buffers for both files. */
+ size_t buffer_size = buffer_lcm (STAT_BLOCKSIZE (filevec[0].stat),
+ STAT_BLOCKSIZE (filevec[1].stat));
+ for (i = 0; i < 2; i++)
+ filevec[i].buffer = xrealloc (filevec[i].buffer, buffer_size);
+
+ for (;; filevec[0].buffered_chars = filevec[1].buffered_chars = 0)
+ {
+ /* Read a buffer's worth from both files. */
+ for (i = 0; i < 2; i++)
+ if (0 <= filevec[i].desc)
+ while (filevec[i].buffered_chars != buffer_size)
+ {
+ int r = read (filevec[i].desc,
+ filevec[i].buffer
+ + filevec[i].buffered_chars,
+ buffer_size - filevec[i].buffered_chars);
+ if (r == 0)
+ break;
+ if (r < 0)
+ pfatal_with_name (filevec[i].name);
+ filevec[i].buffered_chars += r;
+ }
+
+ /* If the buffers differ, the files differ. */
+ if (filevec[0].buffered_chars != filevec[1].buffered_chars
+ || (filevec[0].buffered_chars != 0
+ && memcmp (filevec[0].buffer,
+ filevec[1].buffer,
+ filevec[0].buffered_chars) != 0))
+ {
+ changes = 1;
+ break;
+ }
+
+ /* If we reach end of file, the files are the same. */
+ if (filevec[0].buffered_chars != buffer_size)
+ {
+ changes = 0;
+ break;
+ }
+ }
+ }
+
+ briefly_report (changes, filevec);
+ }
+ else
+ {
+ /* Allocate vectors for the results of comparison:
+ a flag for each line of each file, saying whether that line
+ is an insertion or deletion.
+ Allocate an extra element, always zero, at each end of each vector. */
+
+ size_t s = filevec[0].buffered_lines + filevec[1].buffered_lines + 4;
+ filevec[0].changed_flag = xmalloc (s);
+ bzero (filevec[0].changed_flag, s);
+ filevec[0].changed_flag++;
+ filevec[1].changed_flag = filevec[0].changed_flag
+ + filevec[0].buffered_lines + 2;
+
+ /* Some lines are obviously insertions or deletions
+ because they don't match anything. Detect them now, and
+ avoid even thinking about them in the main comparison algorithm. */
+
+ discard_confusing_lines (filevec);
+
+ /* Now do the main comparison algorithm, considering just the
+ undiscarded lines. */
+
+ xvec = filevec[0].undiscarded;
+ yvec = filevec[1].undiscarded;
+ diags = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3;
+ fdiag = (int *) xmalloc (diags * (2 * sizeof (int)));
+ bdiag = fdiag + diags;
+ fdiag += filevec[1].nondiscarded_lines + 1;
+ bdiag += filevec[1].nondiscarded_lines + 1;
+
+ /* Set TOO_EXPENSIVE to be approximate square root of input size,
+ bounded below by 256. */
+ too_expensive = 1;
+ for (i = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines;
+ i != 0; i >>= 2)
+ too_expensive <<= 1;
+ too_expensive = max (256, too_expensive);
+
+ files[0] = filevec[0];
+ files[1] = filevec[1];
+
+ compareseq (0, filevec[0].nondiscarded_lines,
+ 0, filevec[1].nondiscarded_lines, no_discards);
+
+ free (fdiag - (filevec[1].nondiscarded_lines + 1));
+
+ /* Modify the results slightly to make them prettier
+ in cases where that can validly be done. */
+
+ shift_boundaries (filevec);
+
+ /* Get the results of comparison in the form of a chain
+ of `struct change's -- an edit script. */
+
+ if (output_style == OUTPUT_ED)
+ script = build_reverse_script (filevec);
+ else
+ script = build_script (filevec);
+
+ /* Set CHANGES if we had any diffs.
+ If some changes are ignored, we must scan the script to decide. */
+ if (ignore_blank_lines_flag || ignore_regexp_list)
+ {
+ struct change *next = script;
+ changes = 0;
+
+ while (next && changes == 0)
+ {
+ struct change *this, *end;
+ int first0, last0, first1, last1, deletes, inserts;
+
+ /* Find a set of changes that belong together. */
+ this = next;
+ end = find_change (next);
+
+ /* Disconnect them from the rest of the changes, making them
+ a hunk, and remember the rest for next iteration. */
+ next = end->link;
+ end->link = 0;
+
+ /* Determine whether this hunk is really a difference. */
+ analyze_hunk (this, &first0, &last0, &first1, &last1,
+ &deletes, &inserts);
+
+ /* Reconnect the script so it will all be freed properly. */
+ end->link = next;
+
+ if (deletes || inserts)
+ changes = 1;
+ }
+ }
+ else
+ changes = (script != 0);
+
+ if (no_details_flag)
+ briefly_report (changes, filevec);
+ else
+ {
+ if (changes || ! no_diff_means_no_output)
+ {
+ /* Record info for starting up output,
+ to be used if and when we have some output to print. */
+ setup_output (files[0].name, files[1].name, depth);
+
+ switch (output_style)
+ {
+ case OUTPUT_CONTEXT:
+ print_context_script (script, 0);
+ break;
+
+ case OUTPUT_UNIFIED:
+ print_context_script (script, 1);
+ break;
+
+ case OUTPUT_ED:
+ print_ed_script (script);
+ break;
+
+ case OUTPUT_FORWARD_ED:
+ pr_forward_ed_script (script);
+ break;
+
+ case OUTPUT_RCS:
+ print_rcs_script (script);
+ break;
+
+ case OUTPUT_NORMAL:
+ print_normal_script (script);
+ break;
+
+ case OUTPUT_IFDEF:
+ print_ifdef_script (script);
+ break;
+
+ case OUTPUT_SDIFF:
+ print_sdiff_script (script);
+ }
+
+ finish_output ();
+ }
+ }
+
+ free (filevec[0].undiscarded);
+
+ free (filevec[0].changed_flag - 1);
+
+ for (i = 1; i >= 0; --i)
+ free (filevec[i].equivs);
+
+ for (i = 0; i < 2; ++i)
+ free (filevec[i].linbuf + filevec[i].linbuf_base);
+
+ for (e = script; e; e = p)
+ {
+ p = e->link;
+ free (e);
+ }
+
+ if (! ROBUST_OUTPUT_STYLE (output_style))
+ for (i = 0; i < 2; ++i)
+ if (filevec[i].missing_newline)
+ {
+ diff_error ("No newline at end of file %s", filevec[i].name, "");
+ changes = 2;
+ }
+ }
+
+ if (filevec[0].buffer != filevec[1].buffer)
+ free (filevec[0].buffer);
+ free (filevec[1].buffer);
+
+ return changes;
+}
diff --git a/diff/build_diff.com b/diff/build_diff.com
new file mode 100644
index 0000000..02f6925
--- /dev/null
+++ b/diff/build_diff.com
@@ -0,0 +1,20 @@
+$ set verify
+$ CC :== CC/DEBUG/NOOPTIMIZE/STANDARD=VAXC/DEFINE=HAVE_CONFIG_H-
+/INCLUDE_DIRECTORY=([-],[-.LIB],[-.SRC],[-.VMS])/PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
+$ CC diff.c
+$ CC analyze.c
+$ CC cmpbuf.c
+$ CC dir.c
+$ CC io.c
+$ CC util.c
+$ CC context.c
+$ CC ed.c
+$ CC ifdef.c
+$ CC normal.c
+$ CC side.c
+$ CC version.c
+$ CC diff3.c
+$ library/create diff.olb diff.obj,analyze.obj,cmpbuf.obj,-
+dir.obj,io.obj,util.obj,context.obj,ed.obj,ifdef.obj,normal.obj,-
+side.obj,version.obj,diff3.obj
+$ set noverify
diff --git a/diff/cmpbuf.c b/diff/cmpbuf.c
new file mode 100644
index 0000000..2820dfa
--- /dev/null
+++ b/diff/cmpbuf.c
@@ -0,0 +1,38 @@
+/* Buffer primitives for comparison operations.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ */
+
+#include "system.h"
+#include "cmpbuf.h"
+
+/* Least common multiple of two buffer sizes A and B. */
+
+size_t
+buffer_lcm (a, b)
+ size_t a, b;
+{
+ size_t m, n, r;
+
+ /* Yield reasonable values if buffer sizes are zero. */
+ if (!a)
+ return b ? b : 8 * 1024;
+ if (!b)
+ return a;
+
+ /* n = gcd (a, b) */
+ for (m = a, n = b; (r = m % n) != 0; m = n, n = r)
+ continue;
+
+ return a/n * b;
+}
diff --git a/diff/cmpbuf.h b/diff/cmpbuf.h
new file mode 100644
index 0000000..b7b965d
--- /dev/null
+++ b/diff/cmpbuf.h
@@ -0,0 +1,18 @@
+/* Buffer primitives for comparison operations.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+size_t buffer_lcm PARAMS((size_t, size_t));
diff --git a/diff/context.c b/diff/context.c
new file mode 100644
index 0000000..c4562c9
--- /dev/null
+++ b/diff/context.c
@@ -0,0 +1,462 @@
+/* Context-format output routines for GNU DIFF.
+ Copyright (C) 1988,1989,1991,1992,1993,1994,1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+#include "diff.h"
+
+static struct change *find_hunk PARAMS((struct change *));
+static void find_function PARAMS((struct file_data const *, int, char const **, size_t *));
+static void mark_ignorable PARAMS((struct change *));
+static void pr_context_hunk PARAMS((struct change *));
+static void pr_unidiff_hunk PARAMS((struct change *));
+static void print_context_label PARAMS ((char const *, struct file_data *, char const *));
+static void print_context_number_range PARAMS((struct file_data const *, int, int));
+static void print_unidiff_number_range PARAMS((struct file_data const *, int, int));
+
+/* Last place find_function started searching from. */
+static int find_function_last_search;
+
+/* The value find_function returned when it started searching there. */
+static int find_function_last_match;
+
+/* Print a label for a context diff, with a file name and date or a label. */
+
+static void
+print_context_label (mark, inf, label)
+ char const *mark;
+ struct file_data *inf;
+ char const *label;
+{
+ if (label)
+ printf_output ("%s %s\n", mark, label);
+ else
+ {
+ char const *ct = ctime (&inf->stat.st_mtime);
+ if (!ct)
+ ct = "?\n";
+ /* See Posix.2 section 4.17.6.1.4 for this format. */
+ printf_output ("%s %s\t%s", mark, inf->name, ct);
+ }
+}
+
+/* Print a header for a context diff, with the file names and dates. */
+
+void
+print_context_header (inf, unidiff_flag)
+ struct file_data inf[];
+ int unidiff_flag;
+{
+ if (unidiff_flag)
+ {
+ print_context_label ("---", &inf[0], file_label[0]);
+ print_context_label ("+++", &inf[1], file_label[1]);
+ }
+ else
+ {
+ print_context_label ("***", &inf[0], file_label[0]);
+ print_context_label ("---", &inf[1], file_label[1]);
+ }
+}
+
+/* Print an edit script in context format. */
+
+void
+print_context_script (script, unidiff_flag)
+ struct change *script;
+ int unidiff_flag;
+{
+ if (ignore_blank_lines_flag || ignore_regexp_list)
+ mark_ignorable (script);
+ else
+ {
+ struct change *e;
+ for (e = script; e; e = e->link)
+ e->ignore = 0;
+ }
+
+ find_function_last_search = - files[0].prefix_lines;
+ find_function_last_match = find_function_last_search - 1;
+
+ if (unidiff_flag)
+ print_script (script, find_hunk, pr_unidiff_hunk);
+ else
+ print_script (script, find_hunk, pr_context_hunk);
+}
+
+/* Print a pair of line numbers with a comma, translated for file FILE.
+ If the second number is not greater, use the first in place of it.
+
+ Args A and B are internal line numbers.
+ We print the translated (real) line numbers. */
+
+static void
+print_context_number_range (file, a, b)
+ struct file_data const *file;
+ int a, b;
+{
+ int trans_a, trans_b;
+ translate_range (file, a, b, &trans_a, &trans_b);
+
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (trans_b > trans_a)
+ printf_output ("%d,%d", trans_a, trans_b);
+ else
+ printf_output ("%d", trans_b);
+}
+
+/* Print a portion of an edit script in context format.
+ HUNK is the beginning of the portion to be printed.
+ The end is marked by a `link' that has been nulled out.
+
+ Prints out lines from both files, and precedes each
+ line with the appropriate flag-character. */
+
+static void
+pr_context_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, show_from, show_to, i;
+ struct change *next;
+ char const *prefix;
+ char const *function;
+ size_t function_length;
+
+ /* Determine range of line numbers involved in each file. */
+
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
+
+ if (!show_from && !show_to)
+ return;
+
+ /* Include a context's width before and after. */
+
+ i = - files[0].prefix_lines;
+ first0 = max (first0 - context, i);
+ first1 = max (first1 - context, i);
+ last0 = min (last0 + context, files[0].valid_lines - 1);
+ last1 = min (last1 + context, files[1].valid_lines - 1);
+
+ /* If desired, find the preceding function definition line in file 0. */
+ function = 0;
+ if (function_regexp_list)
+ find_function (&files[0], first0, &function, &function_length);
+
+ begin_output ();
+
+ /* If we looked for and found a function this is part of,
+ include its name in the header of the diff section. */
+ printf_output ("***************");
+
+ if (function)
+ {
+ printf_output (" ");
+ write_output (function, min (function_length - 1, 40));
+ }
+
+ printf_output ("\n*** ");
+ print_context_number_range (&files[0], first0, last0);
+ printf_output (" ****\n");
+
+ if (show_from)
+ {
+ next = hunk;
+
+ for (i = first0; i <= last0; i++)
+ {
+ /* Skip past changes that apply (in file 0)
+ only to lines before line I. */
+
+ while (next && next->line0 + next->deleted <= i)
+ next = next->link;
+
+ /* Compute the marking for line I. */
+
+ prefix = " ";
+ if (next && next->line0 <= i)
+ /* The change NEXT covers this line.
+ If lines were inserted here in file 1, this is "changed".
+ Otherwise it is "deleted". */
+ prefix = (next->inserted > 0 ? "!" : "-");
+
+ print_1_line (prefix, &files[0].linbuf[i]);
+ }
+ }
+
+ printf_output ("--- ");
+ print_context_number_range (&files[1], first1, last1);
+ printf_output (" ----\n");
+
+ if (show_to)
+ {
+ next = hunk;
+
+ for (i = first1; i <= last1; i++)
+ {
+ /* Skip past changes that apply (in file 1)
+ only to lines before line I. */
+
+ while (next && next->line1 + next->inserted <= i)
+ next = next->link;
+
+ /* Compute the marking for line I. */
+
+ prefix = " ";
+ if (next && next->line1 <= i)
+ /* The change NEXT covers this line.
+ If lines were deleted here in file 0, this is "changed".
+ Otherwise it is "inserted". */
+ prefix = (next->deleted > 0 ? "!" : "+");
+
+ print_1_line (prefix, &files[1].linbuf[i]);
+ }
+ }
+}
+
+/* Print a pair of line numbers with a comma, translated for file FILE.
+ If the second number is smaller, use the first in place of it.
+ If the numbers are equal, print just one number.
+
+ Args A and B are internal line numbers.
+ We print the translated (real) line numbers. */
+
+static void
+print_unidiff_number_range (file, a, b)
+ struct file_data const *file;
+ int a, b;
+{
+ int trans_a, trans_b;
+ translate_range (file, a, b, &trans_a, &trans_b);
+
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (trans_b <= trans_a)
+ printf_output (trans_b == trans_a ? "%d" : "%d,0", trans_b);
+ else
+ printf_output ("%d,%d", trans_a, trans_b - trans_a + 1);
+}
+
+/* Print a portion of an edit script in unidiff format.
+ HUNK is the beginning of the portion to be printed.
+ The end is marked by a `link' that has been nulled out.
+
+ Prints out lines from both files, and precedes each
+ line with the appropriate flag-character. */
+
+static void
+pr_unidiff_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, show_from, show_to, i, j, k;
+ struct change *next;
+ char const *function;
+ size_t function_length;
+
+ /* Determine range of line numbers involved in each file. */
+
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
+
+ if (!show_from && !show_to)
+ return;
+
+ /* Include a context's width before and after. */
+
+ i = - files[0].prefix_lines;
+ first0 = max (first0 - context, i);
+ first1 = max (first1 - context, i);
+ last0 = min (last0 + context, files[0].valid_lines - 1);
+ last1 = min (last1 + context, files[1].valid_lines - 1);
+
+ /* If desired, find the preceding function definition line in file 0. */
+ function = 0;
+ if (function_regexp_list)
+ find_function (&files[0], first0, &function, &function_length);
+
+ begin_output ();
+
+ printf_output ("@@ -");
+ print_unidiff_number_range (&files[0], first0, last0);
+ printf_output (" +");
+ print_unidiff_number_range (&files[1], first1, last1);
+ printf_output (" @@");
+
+ /* If we looked for and found a function this is part of,
+ include its name in the header of the diff section. */
+
+ if (function)
+ {
+ write_output (" ", 1);
+ write_output (function, min (function_length - 1, 40));
+ }
+ write_output ("\n", 1);
+
+ next = hunk;
+ i = first0;
+ j = first1;
+
+ while (i <= last0 || j <= last1)
+ {
+
+ /* If the line isn't a difference, output the context from file 0. */
+
+ if (!next || i < next->line0)
+ {
+ write_output (tab_align_flag ? "\t" : " ", 1);
+ print_1_line (0, &files[0].linbuf[i++]);
+ j++;
+ }
+ else
+ {
+ /* For each difference, first output the deleted part. */
+
+ k = next->deleted;
+ while (k--)
+ {
+ write_output ("-", 1);
+ if (tab_align_flag)
+ write_output ("\t", 1);
+ print_1_line (0, &files[0].linbuf[i++]);
+ }
+
+ /* Then output the inserted part. */
+
+ k = next->inserted;
+ while (k--)
+ {
+ write_output ("+", 1);
+ if (tab_align_flag)
+ write_output ("\t", 1);
+ print_1_line (0, &files[1].linbuf[j++]);
+ }
+
+ /* We're done with this hunk, so on to the next! */
+
+ next = next->link;
+ }
+ }
+}
+
+/* Scan a (forward-ordered) edit script for the first place that more than
+ 2*CONTEXT unchanged lines appear, and return a pointer
+ to the `struct change' for the last change before those lines. */
+
+static struct change *
+find_hunk (start)
+ struct change *start;
+{
+ struct change *prev;
+ int top0, top1;
+ int thresh;
+
+ do
+ {
+ /* Compute number of first line in each file beyond this changed. */
+ top0 = start->line0 + start->deleted;
+ top1 = start->line1 + start->inserted;
+ prev = start;
+ start = start->link;
+ /* Threshold distance is 2*CONTEXT between two non-ignorable changes,
+ but only CONTEXT if one is ignorable. */
+ thresh = ((prev->ignore || (start && start->ignore))
+ ? context
+ : 2 * context + 1);
+ /* It is not supposed to matter which file we check in the end-test.
+ If it would matter, crash. */
+ if (start && start->line0 - top0 != start->line1 - top1)
+ abort ();
+ } while (start
+ /* Keep going if less than THRESH lines
+ elapse before the affected line. */
+ && start->line0 < top0 + thresh);
+
+ return prev;
+}
+
+/* Set the `ignore' flag properly in each change in SCRIPT.
+ It should be 1 if all the lines inserted or deleted in that change
+ are ignorable lines. */
+
+static void
+mark_ignorable (script)
+ struct change *script;
+{
+ while (script)
+ {
+ struct change *next = script->link;
+ int first0, last0, first1, last1, deletes, inserts;
+
+ /* Turn this change into a hunk: detach it from the others. */
+ script->link = 0;
+
+ /* Determine whether this change is ignorable. */
+ analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ /* Reconnect the chain as before. */
+ script->link = next;
+
+ /* If the change is ignorable, mark it. */
+ script->ignore = (!deletes && !inserts);
+
+ /* Advance to the following change. */
+ script = next;
+ }
+}
+
+/* Find the last function-header line in FILE prior to line number LINENUM.
+ This is a line containing a match for the regexp in `function_regexp'.
+ Store the address of the line text into LINEP and the length of the
+ line into LENP.
+ Do not store anything if no function-header is found. */
+
+static void
+find_function (file, linenum, linep, lenp)
+ struct file_data const *file;
+ int linenum;
+ char const **linep;
+ size_t *lenp;
+{
+ int i = linenum;
+ int last = find_function_last_search;
+ find_function_last_search = i;
+
+ while (--i >= last)
+ {
+ /* See if this line is what we want. */
+ struct regexp_list *r;
+ char const *line = file->linbuf[i];
+ size_t len = file->linbuf[i + 1] - line;
+
+ for (r = function_regexp_list; r; r = r->next)
+ if (0 <= re_search (&r->buf, line, len, 0, len, 0))
+ {
+ *linep = line;
+ *lenp = len;
+ find_function_last_match = i;
+ return;
+ }
+ }
+ /* If we search back to where we started searching the previous time,
+ find the line we found last time. */
+ if (find_function_last_match >= - file->prefix_lines)
+ {
+ i = find_function_last_match;
+ *linep = file->linbuf[i];
+ *lenp = file->linbuf[i + 1] - *linep;
+ return;
+ }
+ return;
+}
diff --git a/diff/diagmeet.note b/diff/diagmeet.note
new file mode 100644
index 0000000..8f7242c
--- /dev/null
+++ b/diff/diagmeet.note
@@ -0,0 +1,71 @@
+Here is a comparison matrix which shows a case in which
+it is possible for the forward and backward scan in `diag'
+to meet along a nonzero length of diagonal simultaneous
+(so that bdiag[d] and fdiag[d] are not equal)
+even though there is no snake on that diagonal at the meeting point.
+
+
+ 85 1 1 1 159 1 1 17
+ 1 2 3 4
+60
+ 1 2
+1
+ 2 2 3 4
+71
+ 3 3 4 5
+85
+ 4 3 4 5
+17
+ 5 4 5
+1
+ 6 4 5 6
+183
+ 7 5 6 7
+10
+ 8 6 7
+1
+ 9 6 7 8
+12
+ 7 8 9 10
+13
+ 10 8 9 10
+14
+ 10 9 10
+17
+ 10 10
+1
+ 10 9 10
+1
+ 8 10 10 10
+183
+ 8 7 9 9 9
+10
+ 7 6 8 9 8 8
+1
+ 6 5 7 7
+1
+ 5 6 6
+1
+ 5 5 5
+50
+ 5 4 4 4
+1
+ 4 3 3
+85
+ 5 4 3 2 2
+1
+ 2 1
+17
+ 5 4 3 2 1 1
+1
+ 1 0
+ 85 1 1 1 159 1 1 17
+
+
+
+
+
+
+
+
+
diff --git a/diff/diff.c b/diff/diff.c
new file mode 100644
index 0000000..f5d82d5
--- /dev/null
+++ b/diff/diff.c
@@ -0,0 +1,1267 @@
+/* GNU DIFF entry routine.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+/* GNU DIFF was written by Mike Haertel, David Hayes,
+ Richard Stallman, Len Tower, and Paul Eggert. */
+
+#define GDIFF_MAIN
+#include "diff.h"
+#include <signal.h>
+#include "error.h"
+#include "getopt.h"
+
+#ifdef HAVE_FNMATCH
+# include <fnmatch.h> /* This is supposed to be available on Posix systems */
+#else /* HAVE_FNMATCH */
+# include "fnmatch.h" /* Our substitute */
+#endif /* HAVE_FNMATCH */
+
+#ifndef DEFAULT_WIDTH
+#define DEFAULT_WIDTH 130
+#endif
+
+#ifndef GUTTER_WIDTH_MINIMUM
+#define GUTTER_WIDTH_MINIMUM 3
+#endif
+
+/* diff.c has a real initialize_main function. */
+#ifdef initialize_main
+#undef initialize_main
+#endif
+
+static char const *filetype PARAMS((struct stat const *));
+static char *option_list PARAMS((char **, int));
+static int add_exclude_file PARAMS((char const *));
+static int ck_atoi PARAMS((char const *, int *));
+static int compare_files PARAMS((char const *, char const *, char const *, char const *, int));
+static int specify_format PARAMS((char **, char *));
+static void add_exclude PARAMS((char const *));
+static void add_regexp PARAMS((struct regexp_list **, char const *));
+static void specify_style PARAMS((enum output_style));
+static int try_help PARAMS((char const *));
+static void check_output PARAMS((FILE *));
+static void usage PARAMS((void));
+static void initialize_main PARAMS((int *, char ***));
+
+/* Nonzero for -r: if comparing two directories,
+ compare their common subdirectories recursively. */
+
+static int recursive;
+
+/* For debugging: don't do discard_confusing_lines. */
+
+int no_discards;
+
+#if HAVE_SETMODE
+/* I/O mode: nonzero only if using binary input/output. */
+static int binary_I_O;
+#endif
+
+/* Return a string containing the command options with which diff was invoked.
+ Spaces appear between what were separate ARGV-elements.
+ There is a space at the beginning but none at the end.
+ If there were no options, the result is an empty string.
+
+ Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
+ the length of that vector. */
+
+static char *
+option_list (optionvec, count)
+ char **optionvec; /* Was `vector', but that collides on Alliant. */
+ int count;
+{
+ int i;
+ size_t length = 0;
+ char *result;
+
+ for (i = 0; i < count; i++)
+ length += strlen (optionvec[i]) + 1;
+
+ result = xmalloc (length + 1);
+ result[0] = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ strcat (result, " ");
+ strcat (result, optionvec[i]);
+ }
+
+ return result;
+}
+
+/* Convert STR to a positive integer, storing the result in *OUT.
+ If STR is not a valid integer, return -1 (otherwise 0). */
+static int
+ck_atoi (str, out)
+ char const *str;
+ int *out;
+{
+ char const *p;
+ for (p = str; *p; p++)
+ if (*p < '0' || *p > '9')
+ return -1;
+
+ *out = atoi (optarg);
+ return 0;
+}
+
+/* Keep track of excluded file name patterns. */
+
+static char const **exclude;
+static int exclude_alloc, exclude_count;
+
+int
+excluded_filename (f)
+ char const *f;
+{
+ int i;
+ for (i = 0; i < exclude_count; i++)
+ if (fnmatch (exclude[i], f, 0) == 0)
+ return 1;
+ return 0;
+}
+
+static void
+add_exclude (pattern)
+ char const *pattern;
+{
+ if (exclude_alloc <= exclude_count)
+ exclude = (char const **)
+ (exclude_alloc == 0
+ ? xmalloc ((exclude_alloc = 64) * sizeof (*exclude))
+ : xrealloc (exclude, (exclude_alloc *= 2) * sizeof (*exclude)));
+
+ exclude[exclude_count++] = pattern;
+}
+
+static int
+add_exclude_file (name)
+ char const *name;
+{
+ struct file_data f;
+ char *p, *q, *lim;
+
+ f.name = optarg;
+ f.desc = (strcmp (optarg, "-") == 0
+ ? STDIN_FILENO
+ : open (optarg, O_RDONLY, 0));
+ if (f.desc < 0 || fstat (f.desc, &f.stat) != 0)
+ return -1;
+
+ sip (&f, 1);
+ slurp (&f);
+
+ for (p = f.buffer, lim = p + f.buffered_chars; p < lim; p = q)
+ {
+ q = (char *) memchr (p, '\n', lim - p);
+ if (!q)
+ q = lim;
+ *q++ = 0;
+ add_exclude (p);
+ }
+
+ return close (f.desc);
+}
+
+/* The numbers 129- that appear in the fourth element of some entries
+ tell the big switch in `diff_run' how to process those options. */
+
+static struct option const longopts[] =
+{
+ {"ignore-blank-lines", 0, 0, 'B'},
+ {"context", 2, 0, 'C'},
+ {"ifdef", 1, 0, 'D'},
+ {"show-function-line", 1, 0, 'F'},
+ {"speed-large-files", 0, 0, 'H'},
+ {"ignore-matching-lines", 1, 0, 'I'},
+ {"label", 1, 0, 'L'},
+ {"file-label", 1, 0, 'L'}, /* An alias, no longer recommended */
+ {"new-file", 0, 0, 'N'},
+ {"entire-new-file", 0, 0, 'N'}, /* An alias, no longer recommended */
+ {"unidirectional-new-file", 0, 0, 'P'},
+ {"starting-file", 1, 0, 'S'},
+ {"initial-tab", 0, 0, 'T'},
+ {"width", 1, 0, 'W'},
+ {"text", 0, 0, 'a'},
+ {"ascii", 0, 0, 'a'}, /* An alias, no longer recommended */
+ {"ignore-space-change", 0, 0, 'b'},
+ {"minimal", 0, 0, 'd'},
+ {"ed", 0, 0, 'e'},
+ {"forward-ed", 0, 0, 'f'},
+ {"ignore-case", 0, 0, 'i'},
+ {"paginate", 0, 0, 'l'},
+ {"print", 0, 0, 'l'}, /* An alias, no longer recommended */
+ {"rcs", 0, 0, 'n'},
+ {"show-c-function", 0, 0, 'p'},
+ {"brief", 0, 0, 'q'},
+ {"recursive", 0, 0, 'r'},
+ {"report-identical-files", 0, 0, 's'},
+ {"expand-tabs", 0, 0, 't'},
+ {"version", 0, 0, 'v'},
+ {"ignore-all-space", 0, 0, 'w'},
+ {"exclude", 1, 0, 'x'},
+ {"exclude-from", 1, 0, 'X'},
+ {"side-by-side", 0, 0, 'y'},
+ {"unified", 2, 0, 'U'},
+ {"left-column", 0, 0, 129},
+ {"suppress-common-lines", 0, 0, 130},
+ {"sdiff-merge-assist", 0, 0, 131},
+ {"old-line-format", 1, 0, 132},
+ {"new-line-format", 1, 0, 133},
+ {"unchanged-line-format", 1, 0, 134},
+ {"line-format", 1, 0, 135},
+ {"old-group-format", 1, 0, 136},
+ {"new-group-format", 1, 0, 137},
+ {"unchanged-group-format", 1, 0, 138},
+ {"changed-group-format", 1, 0, 139},
+ {"horizon-lines", 1, 0, 140},
+ {"help", 0, 0, 141},
+ {"binary", 0, 0, 142},
+ {0, 0, 0, 0}
+};
+
+
+
+int
+diff_run (argc, argv, out, callbacks_arg)
+ int argc;
+ char *argv[];
+ const char *out;
+ const struct diff_callbacks *callbacks_arg;
+{
+ int val;
+ int c;
+ int prev = -1;
+ int width = DEFAULT_WIDTH;
+ int show_c_function = 0;
+ int optind_old;
+ int opened_file = 0;
+
+ callbacks = callbacks_arg;
+
+ /* Do our initializations. */
+ initialize_main (&argc, &argv);
+ optind_old = optind;
+ optind = 0;
+
+ /* Set the jump buffer, so that diff may abort execution without
+ terminating the process. */
+ val = setjmp (diff_abort_buf);
+ if (val != 0)
+ {
+ optind = optind_old;
+ if (opened_file)
+ fclose (outfile);
+ return val;
+ }
+
+ /* Decode the options. */
+ while ((c = getopt_long (argc, argv,
+ "0123456789abBcC:dD:efF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:y",
+ longopts, 0)) != EOF)
+ {
+ switch (c)
+ {
+ /* All digits combine in decimal to specify the context-size. */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ if (context == -1)
+ context = 0;
+ /* If a context length has already been specified,
+ more digits allowed only if they follow right after the others.
+ Reject two separate runs of digits, or digits after -C. */
+ else if (prev < '0' || prev > '9')
+ fatal ("context length specified twice");
+
+ context = context * 10 + c - '0';
+ break;
+
+ case 'a':
+ /* Treat all files as text files; never treat as binary. */
+ always_text_flag = 1;
+ break;
+
+ case 'b':
+ /* Ignore changes in amount of white space. */
+ ignore_space_change_flag = 1;
+ ignore_some_changes = 1;
+ ignore_some_line_changes = 1;
+ break;
+
+ case 'B':
+ /* Ignore changes affecting only blank lines. */
+ ignore_blank_lines_flag = 1;
+ ignore_some_changes = 1;
+ break;
+
+ case 'C': /* +context[=lines] */
+ case 'U': /* +unified[=lines] */
+ if (optarg)
+ {
+ if (context >= 0)
+ fatal ("context length specified twice");
+
+ if (ck_atoi (optarg, &context))
+ fatal ("invalid context length argument");
+ }
+
+ /* Falls through. */
+ case 'c':
+ /* Make context-style output. */
+ specify_style (c == 'U' ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
+ break;
+
+ case 'd':
+ /* Don't discard lines. This makes things slower (sometimes much
+ slower) but will find a guaranteed minimal set of changes. */
+ no_discards = 1;
+ break;
+
+ case 'D':
+ /* Make merged #ifdef output. */
+ specify_style (OUTPUT_IFDEF);
+ {
+ int i, err = 0;
+ static char const C_ifdef_group_formats[] =
+ "#ifndef %s\n%%<#endif /* not %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c%%=%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n";
+ char *b = xmalloc (sizeof (C_ifdef_group_formats)
+ + 7 * strlen(optarg) - 14 /* 7*"%s" */
+ - 8 /* 5*"%%" + 3*"%c" */);
+ sprintf (b, C_ifdef_group_formats,
+ optarg, optarg, 0,
+ optarg, optarg, 0, 0,
+ optarg, optarg, optarg);
+ for (i = 0; i < 4; i++)
+ {
+ err |= specify_format (&group_format[i], b);
+ b += strlen (b) + 1;
+ }
+ if (err)
+ diff_error ("conflicting #ifdef formats", 0, 0);
+ }
+ break;
+
+ case 'e':
+ /* Make output that is a valid `ed' script. */
+ specify_style (OUTPUT_ED);
+ break;
+
+ case 'f':
+ /* Make output that looks vaguely like an `ed' script
+ but has changes in the order they appear in the file. */
+ specify_style (OUTPUT_FORWARD_ED);
+ break;
+
+ case 'F':
+ /* Show, for each set of changes, the previous line that
+ matches the specified regexp. Currently affects only
+ context-style output. */
+ add_regexp (&function_regexp_list, optarg);
+ break;
+
+ case 'h':
+ /* Split the files into chunks of around 1500 lines
+ for faster processing. Usually does not change the result.
+
+ This currently has no effect. */
+ break;
+
+ case 'H':
+ /* Turn on heuristics that speed processing of large files
+ with a small density of changes. */
+ heuristic = 1;
+ break;
+
+ case 'i':
+ /* Ignore changes in case. */
+ ignore_case_flag = 1;
+ ignore_some_changes = 1;
+ ignore_some_line_changes = 1;
+ break;
+
+ case 'I':
+ /* Ignore changes affecting only lines that match the
+ specified regexp. */
+ add_regexp (&ignore_regexp_list, optarg);
+ ignore_some_changes = 1;
+ break;
+
+ case 'l':
+ /* Pass the output through `pr' to paginate it. */
+ paginate_flag = 1;
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+#ifdef SIGCHLD
+ /* Pagination requires forking and waiting, and
+ System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+ break;
+
+ case 'L':
+ /* Specify file labels for `-c' output headers. */
+ if (!file_label[0])
+ file_label[0] = optarg;
+ else if (!file_label[1])
+ file_label[1] = optarg;
+ else
+ fatal ("too many file label options");
+ break;
+
+ case 'n':
+ /* Output RCS-style diffs, like `-f' except that each command
+ specifies the number of lines affected. */
+ specify_style (OUTPUT_RCS);
+ break;
+
+ case 'N':
+ /* When comparing directories, if a file appears only in one
+ directory, treat it as present but empty in the other. */
+ entire_new_file_flag = 1;
+ break;
+
+ case 'p':
+ /* Make context-style output and show name of last C function. */
+ show_c_function = 1;
+ add_regexp (&function_regexp_list, "^[_a-zA-Z$]");
+ break;
+
+ case 'P':
+ /* When comparing directories, if a file appears only in
+ the second directory of the two,
+ treat it as present but empty in the other. */
+ unidirectional_new_file_flag = 1;
+ break;
+
+ case 'q':
+ no_details_flag = 1;
+ break;
+
+ case 'r':
+ /* When comparing directories,
+ recursively compare any subdirectories found. */
+ recursive = 1;
+ break;
+
+ case 's':
+ /* Print a message if the files are the same. */
+ print_file_same_flag = 1;
+ break;
+
+ case 'S':
+ /* When comparing directories, start with the specified
+ file name. This is used for resuming an aborted comparison. */
+ dir_start_file = optarg;
+ break;
+
+ case 't':
+ /* Expand tabs to spaces in the output so that it preserves
+ the alignment of the input files. */
+ tab_expand_flag = 1;
+ break;
+
+ case 'T':
+ /* Use a tab in the output, rather than a space, before the
+ text of an input line, so as to keep the proper alignment
+ in the input line without changing the characters in it. */
+ tab_align_flag = 1;
+ break;
+
+ case 'u':
+ /* Output the context diff in unidiff format. */
+ specify_style (OUTPUT_UNIFIED);
+ break;
+
+ case 'v':
+ if (callbacks && callbacks->write_stdout)
+ {
+ (*callbacks->write_stdout) ("diff - GNU diffutils version ");
+ (*callbacks->write_stdout) (diff_version_string);
+ (*callbacks->write_stdout) ("\n");
+ }
+ else
+ printf ("diff - GNU diffutils version %s\n", diff_version_string);
+ return 0;
+
+ case 'w':
+ /* Ignore horizontal white space when comparing lines. */
+ ignore_all_space_flag = 1;
+ ignore_some_changes = 1;
+ ignore_some_line_changes = 1;
+ break;
+
+ case 'x':
+ add_exclude (optarg);
+ break;
+
+ case 'X':
+ if (add_exclude_file (optarg) != 0)
+ pfatal_with_name (optarg);
+ break;
+
+ case 'y':
+ /* Use side-by-side (sdiff-style) columnar output. */
+ specify_style (OUTPUT_SDIFF);
+ break;
+
+ case 'W':
+ /* Set the line width for OUTPUT_SDIFF. */
+ if (ck_atoi (optarg, &width) || width <= 0)
+ fatal ("column width must be a positive integer");
+ break;
+
+ case 129:
+ sdiff_left_only = 1;
+ break;
+
+ case 130:
+ sdiff_skip_common_lines = 1;
+ break;
+
+ case 131:
+ /* sdiff-style columns output. */
+ specify_style (OUTPUT_SDIFF);
+ sdiff_help_sdiff = 1;
+ break;
+
+ case 132:
+ case 133:
+ case 134:
+ specify_style (OUTPUT_IFDEF);
+ if (specify_format (&line_format[c - 132], optarg) != 0)
+ diff_error ("conflicting line format", 0, 0);
+ break;
+
+ case 135:
+ specify_style (OUTPUT_IFDEF);
+ {
+ int i, err = 0;
+ for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++)
+ err |= specify_format (&line_format[i], optarg);
+ if (err)
+ diff_error ("conflicting line format", 0, 0);
+ }
+ break;
+
+ case 136:
+ case 137:
+ case 138:
+ case 139:
+ specify_style (OUTPUT_IFDEF);
+ if (specify_format (&group_format[c - 136], optarg) != 0)
+ diff_error ("conflicting group format", 0, 0);
+ break;
+
+ case 140:
+ if (ck_atoi (optarg, &horizon_lines) || horizon_lines < 0)
+ fatal ("horizon must be a nonnegative integer");
+ break;
+
+ case 141:
+ usage ();
+ if (! callbacks || ! callbacks->write_stdout)
+ check_output (stdout);
+ return 0;
+
+ case 142:
+ /* Use binary I/O when reading and writing data.
+ On Posix hosts, this has no effect. */
+#if HAVE_SETMODE
+ binary_I_O = 1;
+# if 0
+ /* Because this code is leftover from pre-library days,
+ there is no way to set stdout back to the default mode
+ when we are done. As it turns out, I think the only
+ parts of CVS that pass out == NULL, and thus cause diff
+ to write to stdout, are "cvs diff" and "cvs rdiff". So
+ I'm not going to worry about this too much yet. */
+ setmode (STDOUT_FILENO, O_BINARY);
+# else
+ if (out == NULL)
+ error (0, 0, "warning: did not set stdout to binary mode");
+# endif
+#endif
+ break;
+
+ default:
+ return try_help (0);
+ }
+ prev = c;
+ }
+
+ if (argc - optind != 2)
+ return try_help (argc - optind < 2 ? "missing operand" : "extra operand");
+
+ {
+ /*
+ * We maximize first the half line width, and then the gutter width,
+ * according to the following constraints:
+ * 1. Two half lines plus a gutter must fit in a line.
+ * 2. If the half line width is nonzero:
+ * a. The gutter width is at least GUTTER_WIDTH_MINIMUM.
+ * b. If tabs are not expanded to spaces,
+ * a half line plus a gutter is an integral number of tabs,
+ * so that tabs in the right column line up.
+ */
+ int t = tab_expand_flag ? 1 : TAB_WIDTH;
+ int off = (width + t + GUTTER_WIDTH_MINIMUM) / (2*t) * t;
+ sdiff_half_width = max (0, min (off - GUTTER_WIDTH_MINIMUM, width - off)),
+ sdiff_column2_offset = sdiff_half_width ? off : width;
+ }
+
+ if (show_c_function && output_style != OUTPUT_UNIFIED)
+ specify_style (OUTPUT_CONTEXT);
+
+ if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED)
+ context = 0;
+ else if (context == -1)
+ /* Default amount of context for -c. */
+ context = 3;
+
+ if (output_style == OUTPUT_IFDEF)
+ {
+ /* Format arrays are char *, not char const *,
+ because integer formats are temporarily modified.
+ But it is safe to assign a constant like "%=" to a format array,
+ since "%=" does not format any integers. */
+ int i;
+ for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++)
+ if (!line_format[i])
+ line_format[i] = "%l\n";
+ if (!group_format[OLD])
+ group_format[OLD]
+ = group_format[UNCHANGED] ? group_format[UNCHANGED] : "%<";
+ if (!group_format[NEW])
+ group_format[NEW]
+ = group_format[UNCHANGED] ? group_format[UNCHANGED] : "%>";
+ if (!group_format[UNCHANGED])
+ group_format[UNCHANGED] = "%=";
+ if (!group_format[CHANGED])
+ group_format[CHANGED] = concat (group_format[OLD],
+ group_format[NEW], "");
+ }
+
+ no_diff_means_no_output =
+ (output_style == OUTPUT_IFDEF ?
+ (!*group_format[UNCHANGED]
+ || (strcmp (group_format[UNCHANGED], "%=") == 0
+ && !*line_format[UNCHANGED]))
+ : output_style == OUTPUT_SDIFF ? sdiff_skip_common_lines : 1);
+
+ switch_string = option_list (argv + 1, optind - 1);
+
+ if (callbacks && callbacks->write_output)
+ {
+ if (out != NULL)
+ {
+ diff_error ("write callback with output file", 0, 0);
+ return 2;
+ }
+ }
+ else
+ {
+ if (out == NULL)
+ outfile = stdout;
+ else
+ {
+#if HAVE_SETMODE
+ /* A diff which is full of ^Z and such isn't going to work
+ very well in text mode. */
+ if (binary_I_O)
+ outfile = fopen (out, "wb");
+ else
+#endif
+ outfile = fopen (out, "w");
+ if (outfile == NULL)
+ {
+ perror_with_name ("could not open output file");
+ return 2;
+ }
+ opened_file = 1;
+ }
+ }
+
+ val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
+
+ /* Print any messages that were saved up for last. */
+ print_message_queue ();
+
+ free (switch_string);
+
+ optind = optind_old;
+
+ if (! callbacks || ! callbacks->write_output)
+ check_output (outfile);
+
+ if (opened_file)
+ if (fclose (outfile) != 0)
+ perror_with_name ("close error on output file");
+
+ return val;
+}
+
+/* Add the compiled form of regexp PATTERN to REGLIST. */
+
+static void
+add_regexp (reglist, pattern)
+ struct regexp_list **reglist;
+ char const *pattern;
+{
+ struct regexp_list *r;
+ char const *m;
+
+ r = (struct regexp_list *) xmalloc (sizeof (*r));
+ bzero (r, sizeof (*r));
+ r->buf.fastmap = xmalloc (256);
+ m = re_compile_pattern (pattern, strlen (pattern), &r->buf);
+ if (m != 0)
+ diff_error ("%s: %s", pattern, m);
+
+ /* Add to the start of the list, since it's easier than the end. */
+ r->next = *reglist;
+ *reglist = r;
+}
+
+static int
+try_help (reason)
+ char const *reason;
+{
+ if (reason)
+ diff_error ("%s", reason, 0);
+ diff_error ("Try `%s --help' for more information.", diff_program_name, 0);
+ return 2;
+}
+
+static void
+check_output (file)
+ FILE *file;
+{
+ if (ferror (file) || fflush (file) != 0)
+ fatal ("write error");
+}
+
+static char const * const option_help[] = {
+"-i --ignore-case Consider upper- and lower-case to be the same.",
+"-w --ignore-all-space Ignore all white space.",
+"-b --ignore-space-change Ignore changes in the amount of white space.",
+"-B --ignore-blank-lines Ignore changes whose lines are all blank.",
+"-I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.",
+#if HAVE_SETMODE
+"--binary Read and write data in binary mode.",
+#endif
+"-a --text Treat all files as text.\n",
+"-c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.",
+"-u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.",
+" -NUM Use NUM context lines.",
+" -L LABEL --label LABEL Use LABEL instead of file name.",
+" -p --show-c-function Show which C function each change is in.",
+" -F RE --show-function-line=RE Show the most recent line matching RE.",
+"-q --brief Output only whether files differ.",
+"-e --ed Output an ed script.",
+"-n --rcs Output an RCS format diff.",
+"-y --side-by-side Output in two columns.",
+" -W NUM --width=NUM Output at most NUM (default 130) characters per line.",
+" --left-column Output only the left column of common lines.",
+" --suppress-common-lines Do not output common lines.",
+"-DNAME --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.",
+"--GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.",
+"--line-format=LFMT Similar, but format all input lines with LFMT.",
+"--LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.",
+" LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.",
+" GFMT may contain:",
+" %< lines from FILE1",
+" %> lines from FILE2",
+" %= lines common to FILE1 and FILE2",
+" %[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER",
+" LETTERs are as follows for new group, lower case for old group:",
+" F first line number",
+" L last line number",
+" N number of lines = L-F+1",
+" E F-1",
+" M L+1",
+" LFMT may contain:",
+" %L contents of line",
+" %l contents of line, excluding any trailing newline",
+" %[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number",
+" Either GFMT or LFMT may contain:",
+" %% %",
+" %c'C' the single character C",
+" %c'\\OOO' the character with octal code OOO\n",
+"-l --paginate Pass the output through `pr' to paginate it.",
+"-t --expand-tabs Expand tabs to spaces in output.",
+"-T --initial-tab Make tabs line up by prepending a tab.\n",
+"-r --recursive Recursively compare any subdirectories found.",
+"-N --new-file Treat absent files as empty.",
+"-P --unidirectional-new-file Treat absent first files as empty.",
+"-s --report-identical-files Report when two files are the same.",
+"-x PAT --exclude=PAT Exclude files that match PAT.",
+"-X FILE --exclude-from=FILE Exclude files that match any pattern in FILE.",
+"-S FILE --starting-file=FILE Start with FILE when comparing directories.\n",
+"--horizon-lines=NUM Keep NUM lines of the common prefix and suffix.",
+"-d --minimal Try hard to find a smaller set of changes.",
+"-H --speed-large-files Assume large files and many scattered small changes.\n",
+"-v --version Output version info.",
+"--help Output this help.",
+0
+};
+
+static void
+usage ()
+{
+ char const * const *p;
+
+ if (callbacks && callbacks->write_stdout)
+ {
+ (*callbacks->write_stdout) ("Usage: ");
+ (*callbacks->write_stdout) (diff_program_name);
+ (*callbacks->write_stdout) (" [OPTION]... FILE1 FILE2\n\n");
+ for (p = option_help; *p; p++)
+ {
+ (*callbacks->write_stdout) (" ");
+ (*callbacks->write_stdout) (*p);
+ (*callbacks->write_stdout) ("\n");
+ }
+ (*callbacks->write_stdout)
+ ("\nIf FILE1 or FILE2 is `-', read standard input.\n");
+ }
+ else
+ {
+ printf ("Usage: %s [OPTION]... FILE1 FILE2\n\n", diff_program_name);
+ for (p = option_help; *p; p++)
+ printf (" %s\n", *p);
+ printf ("\nIf FILE1 or FILE2 is `-', read standard input.\n");
+ }
+}
+
+static int
+specify_format (var, value)
+ char **var;
+ char *value;
+{
+ int err = *var ? strcmp (*var, value) : 0;
+ *var = value;
+ return err;
+}
+
+static void
+specify_style (style)
+ enum output_style style;
+{
+ if (output_style != OUTPUT_NORMAL
+ && output_style != style)
+ diff_error ("conflicting specifications of output style", 0, 0);
+ output_style = style;
+}
+
+static char const *
+filetype (st)
+ struct stat const *st;
+{
+ /* See Posix.2 section 4.17.6.1.1 and Table 5-1 for these formats.
+ To keep diagnostics grammatical, the returned string must start
+ with a consonant. */
+
+ if (S_ISREG (st->st_mode))
+ {
+ if (st->st_size == 0)
+ return "regular empty file";
+ /* Posix.2 section 5.14.2 seems to suggest that we must read the file
+ and guess whether it's C, Fortran, etc., but this is somewhat useless
+ and doesn't reflect historical practice. We're allowed to guess
+ wrong, so we don't bother to read the file. */
+ return "regular file";
+ }
+ if (S_ISDIR (st->st_mode)) return "directory";
+
+ /* other Posix.1 file types */
+#ifdef S_ISBLK
+ if (S_ISBLK (st->st_mode)) return "block special file";
+#endif
+#ifdef S_ISCHR
+ if (S_ISCHR (st->st_mode)) return "character special file";
+#endif
+#ifdef S_ISFIFO
+ if (S_ISFIFO (st->st_mode)) return "fifo";
+#endif
+
+ /* other Posix.1b file types */
+#ifdef S_TYPEISMQ
+ if (S_TYPEISMQ (st)) return "message queue";
+#endif
+#ifdef S_TYPEISSEM
+ if (S_TYPEISSEM (st)) return "semaphore";
+#endif
+#ifdef S_TYPEISSHM
+ if (S_TYPEISSHM (st)) return "shared memory object";
+#endif
+
+ /* other popular file types */
+ /* S_ISLNK is impossible with `fstat' and `stat'. */
+#ifdef S_ISSOCK
+ if (S_ISSOCK (st->st_mode)) return "socket";
+#endif
+
+ return "weird file";
+}
+
+/* Compare two files (or dirs) with specified names
+ DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
+ (if DIR0 is 0, then the name is just NAME0, etc.)
+ This is self-contained; it opens the files and closes them.
+
+ Value is 0 if files are the same, 1 if different,
+ 2 if there is a problem opening them. */
+
+static int
+compare_files (dir0, name0, dir1, name1, depth)
+ char const *dir0, *dir1;
+ char const *name0, *name1;
+ int depth;
+{
+ struct file_data inf[2];
+ register int i;
+ int val;
+ int same_files;
+ int failed = 0;
+ char *free0 = 0, *free1 = 0;
+
+ /* If this is directory comparison, perhaps we have a file
+ that exists only in one of the directories.
+ If so, just print a message to that effect. */
+
+ if (! ((name0 != 0 && name1 != 0)
+ || (unidirectional_new_file_flag && name1 != 0)
+ || entire_new_file_flag))
+ {
+ char const *name = name0 == 0 ? name1 : name0;
+ char const *dir = name0 == 0 ? dir1 : dir0;
+ message ("Only in %s: %s\n", dir, name);
+ /* Return 1 so that diff_dirs will return 1 ("some files differ"). */
+ return 1;
+ }
+
+ bzero (inf, sizeof (inf));
+
+ /* Mark any nonexistent file with -1 in the desc field. */
+ /* Mark unopened files (e.g. directories) with -2. */
+
+ inf[0].desc = name0 == 0 ? -1 : -2;
+ inf[1].desc = name1 == 0 ? -1 : -2;
+
+ /* Now record the full name of each file, including nonexistent ones. */
+
+ if (name0 == 0)
+ name0 = name1;
+ if (name1 == 0)
+ name1 = name0;
+
+ inf[0].name = dir0 == 0 ? name0 : (free0 = dir_file_pathname (dir0, name0));
+ inf[1].name = dir1 == 0 ? name1 : (free1 = dir_file_pathname (dir1, name1));
+
+ /* Stat the files. Record whether they are directories. */
+
+ for (i = 0; i <= 1; i++)
+ {
+ if (inf[i].desc != -1)
+ {
+ int stat_result;
+
+ if (i && filename_cmp (inf[i].name, inf[0].name) == 0)
+ {
+ inf[i].stat = inf[0].stat;
+ stat_result = 0;
+ }
+ else if (strcmp (inf[i].name, "-") == 0)
+ {
+ inf[i].desc = STDIN_FILENO;
+ stat_result = fstat (STDIN_FILENO, &inf[i].stat);
+ if (stat_result == 0 && S_ISREG (inf[i].stat.st_mode))
+ {
+ off_t pos = lseek (STDIN_FILENO, (off_t) 0, SEEK_CUR);
+ if (pos == -1)
+ stat_result = -1;
+ else
+ {
+ if (pos <= inf[i].stat.st_size)
+ inf[i].stat.st_size -= pos;
+ else
+ inf[i].stat.st_size = 0;
+ /* Posix.2 4.17.6.1.4 requires current time for stdin. */
+ time (&inf[i].stat.st_mtime);
+ }
+ }
+ }
+ else
+ stat_result = stat (inf[i].name, &inf[i].stat);
+
+ if (stat_result != 0)
+ {
+ perror_with_name (inf[i].name);
+ failed = 1;
+ }
+ else
+ {
+ inf[i].dir_p = S_ISDIR (inf[i].stat.st_mode) && inf[i].desc != 0;
+ if (inf[1 - i].desc == -1)
+ {
+ inf[1 - i].dir_p = inf[i].dir_p;
+ inf[1 - i].stat.st_mode = inf[i].stat.st_mode;
+ }
+ }
+ }
+ }
+
+ if (! failed && depth == 0 && inf[0].dir_p != inf[1].dir_p)
+ {
+ /* If one is a directory, and it was specified in the command line,
+ use the file in that dir with the other file's basename. */
+
+ int fnm_arg = inf[0].dir_p;
+ int dir_arg = 1 - fnm_arg;
+ char const *fnm = inf[fnm_arg].name;
+ char const *dir = inf[dir_arg].name;
+ char const *p = filename_lastdirchar (fnm);
+ char const *filename = inf[dir_arg].name
+ = dir_file_pathname (dir, p ? p + 1 : fnm);
+
+ if (strcmp (fnm, "-") == 0)
+ fatal ("can't compare - to a directory");
+
+ if (stat (filename, &inf[dir_arg].stat) != 0)
+ {
+ perror_with_name (filename);
+ failed = 1;
+ }
+ else
+ inf[dir_arg].dir_p = S_ISDIR (inf[dir_arg].stat.st_mode);
+ }
+
+ if (failed)
+ {
+
+ /* If either file should exist but does not, return 2. */
+
+ val = 2;
+
+ }
+ else if ((same_files = inf[0].desc != -1 && inf[1].desc != -1
+ && 0 < same_file (&inf[0].stat, &inf[1].stat))
+ && no_diff_means_no_output)
+ {
+ /* The two named files are actually the same physical file.
+ We know they are identical without actually reading them. */
+
+ val = 0;
+ }
+ else if (inf[0].dir_p & inf[1].dir_p)
+ {
+ if (output_style == OUTPUT_IFDEF)
+ fatal ("-D option not supported with directories");
+
+ /* If both are directories, compare the files in them. */
+
+ if (depth > 0 && !recursive)
+ {
+ /* But don't compare dir contents one level down
+ unless -r was specified. */
+ message ("Common subdirectories: %s and %s\n",
+ inf[0].name, inf[1].name);
+ val = 0;
+ }
+ else
+ {
+ val = diff_dirs (inf, compare_files, depth);
+ }
+
+ }
+ else if ((inf[0].dir_p | inf[1].dir_p)
+ || (depth > 0
+ && (! S_ISREG (inf[0].stat.st_mode)
+ || ! S_ISREG (inf[1].stat.st_mode))))
+ {
+ /* Perhaps we have a subdirectory that exists only in one directory.
+ If so, just print a message to that effect. */
+
+ if (inf[0].desc == -1 || inf[1].desc == -1)
+ {
+ if ((inf[0].dir_p | inf[1].dir_p)
+ && recursive
+ && (entire_new_file_flag
+ || (unidirectional_new_file_flag && inf[0].desc == -1)))
+ val = diff_dirs (inf, compare_files, depth);
+ else
+ {
+ char const *dir = (inf[0].desc == -1) ? dir1 : dir0;
+ /* See Posix.2 section 4.17.6.1.1 for this format. */
+ message ("Only in %s: %s\n", dir, name0);
+ val = 1;
+ }
+ }
+ else
+ {
+ /* We have two files that are not to be compared. */
+
+ /* See Posix.2 section 4.17.6.1.1 for this format. */
+ message5 ("File %s is a %s while file %s is a %s\n",
+ inf[0].name, filetype (&inf[0].stat),
+ inf[1].name, filetype (&inf[1].stat));
+
+ /* This is a difference. */
+ val = 1;
+ }
+ }
+ else if ((no_details_flag & ~ignore_some_changes)
+ && inf[0].stat.st_size != inf[1].stat.st_size
+ && (inf[0].desc == -1 || S_ISREG (inf[0].stat.st_mode))
+ && (inf[1].desc == -1 || S_ISREG (inf[1].stat.st_mode)))
+ {
+ message ("Files %s and %s differ\n", inf[0].name, inf[1].name);
+ val = 1;
+ }
+ else
+ {
+ /* Both exist and neither is a directory. */
+
+ /* Open the files and record their descriptors. */
+
+ if (inf[0].desc == -2)
+ if ((inf[0].desc = open (inf[0].name, O_RDONLY, 0)) < 0)
+ {
+ perror_with_name (inf[0].name);
+ failed = 1;
+ }
+ if (inf[1].desc == -2)
+ {
+ if (same_files)
+ inf[1].desc = inf[0].desc;
+ else if ((inf[1].desc = open (inf[1].name, O_RDONLY, 0)) < 0)
+ {
+ perror_with_name (inf[1].name);
+ failed = 1;
+ }
+ }
+
+#if HAVE_SETMODE
+ if (binary_I_O)
+ for (i = 0; i <= 1; i++)
+ if (0 <= inf[i].desc)
+ setmode (inf[i].desc, O_BINARY);
+#endif
+
+ /* Compare the files, if no error was found. */
+
+ val = failed ? 2 : diff_2_files (inf, depth);
+
+ /* Close the file descriptors. */
+
+ if (inf[0].desc >= 0 && close (inf[0].desc) != 0)
+ {
+ perror_with_name (inf[0].name);
+ val = 2;
+ }
+ if (inf[1].desc >= 0 && inf[0].desc != inf[1].desc
+ && close (inf[1].desc) != 0)
+ {
+ perror_with_name (inf[1].name);
+ val = 2;
+ }
+ }
+
+ /* Now the comparison has been done, if no error prevented it,
+ and VAL is the value this function will return. */
+
+ if (val == 0 && !inf[0].dir_p)
+ {
+ if (print_file_same_flag)
+ message ("Files %s and %s are identical\n",
+ inf[0].name, inf[1].name);
+ }
+ else
+ flush_output ();
+
+ if (free0)
+ free (free0);
+ if (free1)
+ free (free1);
+
+ return val;
+}
+
+/* Initialize status variables and flag variables used in libdiff,
+ to permit repeated calls to diff_run. */
+
+static void
+initialize_main (argcp, argvp)
+ int *argcp;
+ char ***argvp;
+{
+ /* These variables really must be reset each time diff_run is called. */
+ output_style = OUTPUT_NORMAL;
+ context = -1;
+ file_label[0] = NULL;
+ file_label[1] = NULL;
+ diff_program_name = (*argvp)[0];
+ outfile = NULL;
+
+ /* Reset these also, just for safety's sake. (If one invocation turns
+ on ignore_case_flag, it must be turned off before diff_run is called
+ again. But it is possible to make many diffs before encountering
+ such a problem. */
+ recursive = 0;
+ no_discards = 0;
+#if HAVE_SETMODE
+ binary_I_O = 0;
+#endif
+ no_diff_means_no_output = 0;
+ always_text_flag = 0;
+ horizon_lines = 0;
+ ignore_space_change_flag = 0;
+ ignore_all_space_flag = 0;
+ ignore_blank_lines_flag = 0;
+ ignore_some_line_changes = 0;
+ ignore_some_changes = 0;
+ ignore_case_flag = 0;
+ function_regexp_list = NULL;
+ ignore_regexp_list = NULL;
+ no_details_flag = 0;
+ print_file_same_flag = 0;
+ tab_align_flag = 0;
+ tab_expand_flag = 0;
+ dir_start_file = NULL;
+ entire_new_file_flag = 0;
+ unidirectional_new_file_flag = 0;
+ paginate_flag = 0;
+ bzero (group_format, sizeof (group_format));
+ bzero (line_format, sizeof (line_format));
+ sdiff_help_sdiff = 0;
+ sdiff_left_only = 0;
+ sdiff_skip_common_lines = 0;
+ sdiff_half_width = 0;
+ sdiff_column2_offset = 0;
+ switch_string = NULL;
+ heuristic = 0;
+ bzero (files, sizeof (files));
+}
diff --git a/diff/diff.h b/diff/diff.h
new file mode 100644
index 0000000..642138d
--- /dev/null
+++ b/diff/diff.h
@@ -0,0 +1,354 @@
+/* Shared definitions for GNU DIFF
+ Copyright (C) 1988, 89, 91, 92, 93, 97, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+#include "system.h"
+#include <stdio.h>
+#include <setjmp.h>
+#include "regex.h"
+#include "diffrun.h"
+
+#define TAB_WIDTH 8
+
+/* Variables for command line options */
+
+#ifndef GDIFF_MAIN
+#define EXTERN extern
+#else
+#define EXTERN
+#endif
+
+/* The callbacks to use for output. */
+EXTERN const struct diff_callbacks *callbacks;
+
+enum output_style {
+ /* Default output style. */
+ OUTPUT_NORMAL,
+ /* Output the differences with lines of context before and after (-c). */
+ OUTPUT_CONTEXT,
+ /* Output the differences in a unified context diff format (-u). */
+ OUTPUT_UNIFIED,
+ /* Output the differences as commands suitable for `ed' (-e). */
+ OUTPUT_ED,
+ /* Output the diff as a forward ed script (-f). */
+ OUTPUT_FORWARD_ED,
+ /* Like -f, but output a count of changed lines in each "command" (-n). */
+ OUTPUT_RCS,
+ /* Output merged #ifdef'd file (-D). */
+ OUTPUT_IFDEF,
+ /* Output sdiff style (-y). */
+ OUTPUT_SDIFF
+};
+
+/* True for output styles that are robust,
+ i.e. can handle a file that ends in a non-newline. */
+#define ROBUST_OUTPUT_STYLE(S) ((S) != OUTPUT_ED && (S) != OUTPUT_FORWARD_ED)
+
+EXTERN enum output_style output_style;
+
+/* Nonzero if output cannot be generated for identical files. */
+EXTERN int no_diff_means_no_output;
+
+/* Number of lines of context to show in each set of diffs.
+ This is zero when context is not to be shown. */
+EXTERN int context;
+
+/* Consider all files as text files (-a).
+ Don't interpret codes over 0177 as implying a "binary file". */
+EXTERN int always_text_flag;
+
+/* Number of lines to keep in identical prefix and suffix. */
+EXTERN int horizon_lines;
+
+/* Ignore changes in horizontal white space (-b). */
+EXTERN int ignore_space_change_flag;
+
+/* Ignore all horizontal white space (-w). */
+EXTERN int ignore_all_space_flag;
+
+/* Ignore changes that affect only blank lines (-B). */
+EXTERN int ignore_blank_lines_flag;
+
+/* 1 if lines may match even if their contents do not match exactly.
+ This depends on various options. */
+EXTERN int ignore_some_line_changes;
+
+/* 1 if files may match even if their contents are not byte-for-byte identical.
+ This depends on various options. */
+EXTERN int ignore_some_changes;
+
+/* Ignore differences in case of letters (-i). */
+EXTERN int ignore_case_flag;
+
+/* File labels for `-c' output headers (-L). */
+EXTERN char *file_label[2];
+
+struct regexp_list
+{
+ struct re_pattern_buffer buf;
+ struct regexp_list *next;
+};
+
+/* Regexp to identify function-header lines (-F). */
+EXTERN struct regexp_list *function_regexp_list;
+
+/* Ignore changes that affect only lines matching this regexp (-I). */
+EXTERN struct regexp_list *ignore_regexp_list;
+
+/* Say only whether files differ, not how (-q). */
+EXTERN int no_details_flag;
+
+/* Report files compared that match (-s).
+ Normally nothing is output when that happens. */
+EXTERN int print_file_same_flag;
+
+/* Output the differences with exactly 8 columns added to each line
+ so that any tabs in the text line up properly (-T). */
+EXTERN int tab_align_flag;
+
+/* Expand tabs in the output so the text lines up properly
+ despite the characters added to the front of each line (-t). */
+EXTERN int tab_expand_flag;
+
+/* In directory comparison, specify file to start with (-S).
+ All file names less than this name are ignored. */
+EXTERN char *dir_start_file;
+
+/* If a file is new (appears in only one dir)
+ include its entire contents (-N).
+ Then `patch' would create the file with appropriate contents. */
+EXTERN int entire_new_file_flag;
+
+/* If a file is new (appears in only the second dir)
+ include its entire contents (-P).
+ Then `patch' would create the file with appropriate contents. */
+EXTERN int unidirectional_new_file_flag;
+
+/* Pipe each file's output through pr (-l). */
+EXTERN int paginate_flag;
+
+enum line_class {
+ /* Lines taken from just the first file. */
+ OLD,
+ /* Lines taken from just the second file. */
+ NEW,
+ /* Lines common to both files. */
+ UNCHANGED,
+ /* A hunk containing both old and new lines (line groups only). */
+ CHANGED
+};
+
+/* Line group formats for old, new, unchanged, and changed groups. */
+EXTERN char *group_format[CHANGED + 1];
+
+/* Line formats for old, new, and unchanged lines. */
+EXTERN char *line_format[UNCHANGED + 1];
+
+/* If using OUTPUT_SDIFF print extra information to help the sdiff filter. */
+EXTERN int sdiff_help_sdiff;
+
+/* Tell OUTPUT_SDIFF to show only the left version of common lines. */
+EXTERN int sdiff_left_only;
+
+/* Tell OUTPUT_SDIFF to not show common lines. */
+EXTERN int sdiff_skip_common_lines;
+
+/* The half line width and column 2 offset for OUTPUT_SDIFF. */
+EXTERN unsigned sdiff_half_width;
+EXTERN unsigned sdiff_column2_offset;
+
+/* String containing all the command options diff received,
+ with spaces between and at the beginning but none at the end.
+ If there were no options given, this string is empty. */
+EXTERN char * switch_string;
+
+/* Nonzero means use heuristics for better speed. */
+EXTERN int heuristic;
+
+/* Name of program the user invoked (for error messages). */
+EXTERN char *diff_program_name;
+
+/* Jump buffer for nonlocal exits. */
+EXTERN jmp_buf diff_abort_buf;
+#define DIFF_ABORT(retval) longjmp(diff_abort_buf, retval)
+
+/* The result of comparison is an "edit script": a chain of `struct change'.
+ Each `struct change' represents one place where some lines are deleted
+ and some are inserted.
+
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+
+struct change
+{
+ struct change *link; /* Previous or next edit command */
+ int inserted; /* # lines of file 1 changed here. */
+ int deleted; /* # lines of file 0 changed here. */
+ int line0; /* Line number of 1st deleted line. */
+ int line1; /* Line number of 1st inserted line. */
+ char ignore; /* Flag used in context.c */
+};
+
+/* Structures that describe the input files. */
+
+/* Data on one input file being compared. */
+
+struct file_data {
+ int desc; /* File descriptor */
+ char const *name; /* File name */
+ struct stat stat; /* File status from fstat() */
+ int dir_p; /* nonzero if file is a directory */
+
+ /* Buffer in which text of file is read. */
+ char * buffer;
+ /* Allocated size of buffer. */
+ size_t bufsize;
+ /* Number of valid characters now in the buffer. */
+ size_t buffered_chars;
+
+ /* Array of pointers to lines in the file. */
+ char const **linbuf;
+
+ /* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines.
+ linebuf[linbuf_base ... buffered_lines - 1] are possibly differing.
+ linebuf[linbuf_base ... valid_lines - 1] contain valid data.
+ linebuf[linbuf_base ... alloc_lines - 1] are allocated. */
+ int linbuf_base, buffered_lines, valid_lines, alloc_lines;
+
+ /* Pointer to end of prefix of this file to ignore when hashing. */
+ char const *prefix_end;
+
+ /* Count of lines in the prefix.
+ There are this many lines in the file before linbuf[0]. */
+ int prefix_lines;
+
+ /* Pointer to start of suffix of this file to ignore when hashing. */
+ char const *suffix_begin;
+
+ /* Vector, indexed by line number, containing an equivalence code for
+ each line. It is this vector that is actually compared with that
+ of another file to generate differences. */
+ int *equivs;
+
+ /* Vector, like the previous one except that
+ the elements for discarded lines have been squeezed out. */
+ int *undiscarded;
+
+ /* Vector mapping virtual line numbers (not counting discarded lines)
+ to real ones (counting those lines). Both are origin-0. */
+ int *realindexes;
+
+ /* Total number of nondiscarded lines. */
+ int nondiscarded_lines;
+
+ /* Vector, indexed by real origin-0 line number,
+ containing 1 for a line that is an insertion or a deletion.
+ The results of comparison are stored here. */
+ char *changed_flag;
+
+ /* 1 if file ends in a line with no final newline. */
+ int missing_newline;
+
+ /* 1 more than the maximum equivalence value used for this or its
+ sibling file. */
+ int equiv_max;
+};
+
+/* Describe the two files currently being compared. */
+
+EXTERN struct file_data files[2];
+
+/* Stdio stream to output diffs to. */
+
+EXTERN FILE *outfile;
+
+/* Declare various functions. */
+
+/* analyze.c */
+int diff_2_files PARAMS((struct file_data[], int));
+
+/* context.c */
+void print_context_header PARAMS((struct file_data[], int));
+void print_context_script PARAMS((struct change *, int));
+
+/* diff.c */
+int excluded_filename PARAMS((char const *));
+
+/* dir.c */
+int diff_dirs PARAMS((struct file_data const[], int (*) PARAMS((char const *, char const *, char const *, char const *, int)), int));
+
+/* ed.c */
+void print_ed_script PARAMS((struct change *));
+void pr_forward_ed_script PARAMS((struct change *));
+
+/* ifdef.c */
+void print_ifdef_script PARAMS((struct change *));
+
+/* io.c */
+int read_files PARAMS((struct file_data[], int));
+int sip PARAMS((struct file_data *, int));
+void slurp PARAMS((struct file_data *));
+
+/* normal.c */
+void print_normal_script PARAMS((struct change *));
+
+/* rcs.c */
+void print_rcs_script PARAMS((struct change *));
+
+/* side.c */
+void print_sdiff_script PARAMS((struct change *));
+
+/* util.c */
+VOID *xmalloc PARAMS((size_t));
+VOID *xrealloc PARAMS((VOID *, size_t));
+char *concat PARAMS((char const *, char const *, char const *));
+char *dir_file_pathname PARAMS((char const *, char const *));
+int change_letter PARAMS((int, int));
+int line_cmp PARAMS((char const *, char const *));
+int translate_line_number PARAMS((struct file_data const *, int));
+struct change *find_change PARAMS((struct change *));
+struct change *find_reverse_change PARAMS((struct change *));
+void analyze_hunk PARAMS((struct change *, int *, int *, int *, int *, int *, int *));
+void begin_output PARAMS((void));
+void debug_script PARAMS((struct change *));
+void diff_error PARAMS((char const *, char const *, char const *));
+void fatal PARAMS((char const *));
+void finish_output PARAMS((void));
+void write_output PARAMS((char const *, size_t));
+void printf_output PARAMS((char const *, ...))
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
+ __attribute__ ((__format__ (__printf__, 1, 2)))
+#endif
+ ;
+void flush_output PARAMS((void));
+void message PARAMS((char const *, char const *, char const *));
+void message5 PARAMS((char const *, char const *, char const *, char const *, char const *));
+void output_1_line PARAMS((char const *, char const *, char const *, char const *));
+void perror_with_name PARAMS((char const *));
+void pfatal_with_name PARAMS((char const *));
+void print_1_line PARAMS((char const *, char const * const *));
+void print_message_queue PARAMS((void));
+void print_number_range PARAMS((int, struct file_data *, int, int));
+void print_script PARAMS((struct change *, struct change * (*) PARAMS((struct change *)), void (*) PARAMS((struct change *))));
+void setup_output PARAMS((char const *, char const *, int));
+void translate_range PARAMS((struct file_data const *, int, int, int *, int *));
+
+/* version.c */
+extern char const diff_version_string[];
diff --git a/diff/diff3.c b/diff/diff3.c
new file mode 100644
index 0000000..2511187
--- /dev/null
+++ b/diff/diff3.c
@@ -0,0 +1,1927 @@
+/* Three way file comparison program (diff3) for Project GNU.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ */
+
+/* Written by Randy Smith */
+/* Librarification by Tim Pierce */
+
+#include "system.h"
+#include <stdio.h>
+#include <setjmp.h>
+#include "getopt.h"
+#include "diffrun.h"
+
+/* diff3.c has a real initialize_main function. */
+#ifdef initialize_main
+#undef initialize_main
+#endif
+
+extern char const diff_version_string[];
+
+extern FILE *outfile;
+
+extern const struct diff_callbacks *callbacks;
+
+void write_output PARAMS((char const *, size_t));
+void printf_output PARAMS((char const *, ...))
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
+ __attribute__ ((__format__ (__printf__, 1, 2)))
+#endif
+ ;
+void flush_output PARAMS((void));
+
+char * cvs_temp_name PARAMS((void));
+
+/*
+ * Internal data structures and macros for the diff3 program; includes
+ * data structures for both diff3 diffs and normal diffs.
+ */
+
+/* Different files within a three way diff. */
+#define FILE0 0
+#define FILE1 1
+#define FILE2 2
+
+/*
+ * A three way diff is built from two two-way diffs; the file which
+ * the two two-way diffs share is:
+ */
+#define FILEC FILE2
+
+/*
+ * Different files within a two way diff.
+ * FC is the common file, FO the other file.
+ */
+#define FO 0
+#define FC 1
+
+/* The ranges are indexed by */
+#define START 0
+#define END 1
+
+enum diff_type {
+ ERROR, /* Should not be used */
+ ADD, /* Two way diff add */
+ CHANGE, /* Two way diff change */
+ DELETE, /* Two way diff delete */
+ DIFF_ALL, /* All three are different */
+ DIFF_1ST, /* Only the first is different */
+ DIFF_2ND, /* Only the second */
+ DIFF_3RD /* Only the third */
+};
+
+/* Two way diff */
+struct diff_block {
+ int ranges[2][2]; /* Ranges are inclusive */
+ char **lines[2]; /* The actual lines (may contain nulls) */
+ size_t *lengths[2]; /* Line lengths (including newlines, if any) */
+ struct diff_block *next;
+};
+
+/* Three way diff */
+
+struct diff3_block {
+ enum diff_type correspond; /* Type of diff */
+ int ranges[3][2]; /* Ranges are inclusive */
+ char **lines[3]; /* The actual lines (may contain nulls) */
+ size_t *lengths[3]; /* Line lengths (including newlines, if any) */
+ struct diff3_block *next;
+};
+
+/*
+ * Access the ranges on a diff block.
+ */
+#define D_LOWLINE(diff, filenum) \
+ ((diff)->ranges[filenum][START])
+#define D_HIGHLINE(diff, filenum) \
+ ((diff)->ranges[filenum][END])
+#define D_NUMLINES(diff, filenum) \
+ (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
+
+/*
+ * Access the line numbers in a file in a diff by relative line
+ * numbers (i.e. line number within the diff itself). Note that these
+ * are lvalues and can be used for assignment.
+ */
+#define D_RELNUM(diff, filenum, linenum) \
+ ((diff)->lines[filenum][linenum])
+#define D_RELLEN(diff, filenum, linenum) \
+ ((diff)->lengths[filenum][linenum])
+
+/*
+ * And get at them directly, when that should be necessary.
+ */
+#define D_LINEARRAY(diff, filenum) \
+ ((diff)->lines[filenum])
+#define D_LENARRAY(diff, filenum) \
+ ((diff)->lengths[filenum])
+
+/*
+ * Next block.
+ */
+#define D_NEXT(diff) ((diff)->next)
+
+/*
+ * Access the type of a diff3 block.
+ */
+#define D3_TYPE(diff) ((diff)->correspond)
+
+/*
+ * Line mappings based on diffs. The first maps off the top of the
+ * diff, the second off of the bottom.
+ */
+#define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \
+ ((lineno) \
+ - D_HIGHLINE ((diff), (fromfile)) \
+ + D_HIGHLINE ((diff), (tofile)))
+
+#define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \
+ ((lineno) \
+ - D_LOWLINE ((diff), (fromfile)) \
+ + D_LOWLINE ((diff), (tofile)))
+
+/*
+ * General memory allocation function.
+ */
+#define ALLOCATE(number, type) \
+ (type *) xmalloc ((number) * sizeof (type))
+
+/* Options variables for flags set on command line. */
+
+/* If nonzero, treat all files as text files, never as binary. */
+static int always_text;
+
+/* If nonzero, write out an ed script instead of the standard diff3 format. */
+static int edscript;
+
+/* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
+ preserve the lines which would normally be deleted from
+ file 1 with a special flagging mechanism. */
+static int flagging;
+
+/* Number of lines to keep in identical prefix and suffix. */
+static int const horizon_lines = 10;
+
+/* Use a tab to align output lines (-T). */
+static int tab_align_flag;
+
+/* If nonzero, do not output information for overlapping diffs. */
+static int simple_only;
+
+/* If nonzero, do not output information for non-overlapping diffs. */
+static int overlap_only;
+
+/* If nonzero, show information for DIFF_2ND diffs. */
+static int show_2nd;
+
+/* If nonzero, include `:wq' at the end of the script
+ to write out the file being edited. */
+static int finalwrite;
+
+/* If nonzero, output a merged file. */
+static int merge;
+
+extern char *diff_program_name;
+
+static char *read_diff PARAMS((char const *, char const *, char **));
+static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int));
+static enum diff_type process_diff_control PARAMS((char **, struct diff_block *));
+static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int));
+static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int));
+static int dotlines PARAMS((struct diff3_block *, int));
+static int output_diff3_edscript PARAMS((struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
+static int output_diff3_merge PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
+static size_t myread PARAMS((int, char *, size_t));
+static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int));
+static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *));
+static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *));
+static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *));
+static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **, char **));
+static void check_output PARAMS((FILE *));
+static void diff3_fatal PARAMS((char const *));
+static void output_diff3 PARAMS((struct diff3_block *, int const[3], int const[3]));
+static void diff3_perror_with_exit PARAMS((char const *));
+static int try_help PARAMS((char const *));
+static void undotlines PARAMS((int, int, int));
+static void usage PARAMS((void));
+static void initialize_main PARAMS((int *, char ***));
+static void free_diff_blocks PARAMS((struct diff_block *));
+static void free_diff3_blocks PARAMS((struct diff3_block *));
+
+/* Functions provided in libdiff.a or other external sources. */
+VOID *xmalloc PARAMS((size_t));
+VOID *xrealloc PARAMS((VOID *, size_t));
+void perror_with_name PARAMS((char const *));
+void diff_error PARAMS((char const *, char const *, char const *));
+
+/* Permit non-local exits from diff3. */
+static jmp_buf diff3_abort_buf;
+#define DIFF3_ABORT(retval) longjmp(diff3_abort_buf, retval)
+
+static struct option const longopts[] =
+{
+ {"text", 0, 0, 'a'},
+ {"show-all", 0, 0, 'A'},
+ {"ed", 0, 0, 'e'},
+ {"show-overlap", 0, 0, 'E'},
+ {"label", 1, 0, 'L'},
+ {"merge", 0, 0, 'm'},
+ {"initial-tab", 0, 0, 'T'},
+ {"overlap-only", 0, 0, 'x'},
+ {"easy-only", 0, 0, '3'},
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, 129},
+ {0, 0, 0, 0}
+};
+
+/*
+ * Main program. Calls diff twice on two pairs of input files,
+ * combines the two diffs, and outputs them.
+ */
+int
+diff3_run (argc, argv, out, callbacks_arg)
+ int argc;
+ char **argv;
+ char *out;
+ const struct diff_callbacks *callbacks_arg;
+{
+ int c, i;
+ int mapping[3];
+ int rev_mapping[3];
+ int incompat = 0;
+ int conflicts_found;
+ int status;
+ struct diff_block *thread0, *thread1, *last_block;
+ char *content0, *content1;
+ struct diff3_block *diff3;
+ int tag_count = 0;
+ char *tag_strings[3];
+ char *commonname;
+ char **file;
+ struct stat statb;
+ int optind_old;
+ int opened_file = 0;
+
+ callbacks = callbacks_arg;
+
+ initialize_main (&argc, &argv);
+
+ optind_old = optind;
+ optind = 0;
+ while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF)
+ {
+ switch (c)
+ {
+ case 'a':
+ always_text = 1;
+ break;
+ case 'A':
+ show_2nd = 1;
+ flagging = 1;
+ incompat++;
+ break;
+ case 'x':
+ overlap_only = 1;
+ incompat++;
+ break;
+ case '3':
+ simple_only = 1;
+ incompat++;
+ break;
+ case 'i':
+ finalwrite = 1;
+ break;
+ case 'm':
+ merge = 1;
+ break;
+ case 'X':
+ overlap_only = 1;
+ /* Falls through */
+ case 'E':
+ flagging = 1;
+ /* Falls through */
+ case 'e':
+ incompat++;
+ break;
+ case 'T':
+ tab_align_flag = 1;
+ break;
+ case 'v':
+ if (callbacks && callbacks->write_stdout)
+ {
+ (*callbacks->write_stdout) ("diff3 - GNU diffutils version ");
+ (*callbacks->write_stdout) (diff_version_string);
+ (*callbacks->write_stdout) ("\n");
+ }
+ else
+ printf ("diff3 - GNU diffutils version %s\n", diff_version_string);
+ return 0;
+ case 129:
+ usage ();
+ if (! callbacks || ! callbacks->write_stdout)
+ check_output (stdout);
+ return 0;
+ case 'L':
+ /* Handle up to three -L options. */
+ if (tag_count < 3)
+ {
+ tag_strings[tag_count++] = optarg;
+ break;
+ }
+ return try_help ("Too many labels were given. The limit is 3.");
+ default:
+ return try_help (0);
+ }
+ }
+
+ edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
+ show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
+ flagging |= ~incompat & merge;
+
+ if (incompat > 1 /* Ensure at most one of -AeExX3. */
+ || finalwrite & merge /* -i -m would rewrite input file. */
+ || (tag_count && ! flagging)) /* -L requires one of -AEX. */
+ return try_help ("incompatible options");
+
+ if (argc - optind != 3)
+ return try_help (argc - optind < 3 ? "missing operand" : "extra operand");
+
+ file = &argv[optind];
+
+ optind = optind_old;
+
+ for (i = tag_count; i < 3; i++)
+ tag_strings[i] = file[i];
+
+ /* Always compare file1 to file2, even if file2 is "-".
+ This is needed for -mAeExX3. Using the file0 as
+ the common file would produce wrong results, because if the
+ file0-file1 diffs didn't line up with the file0-file2 diffs
+ (which is entirely possible since we don't use diff's -n option),
+ diff3 might report phantom changes from file1 to file2. */
+ /* Also try to compare file0 to file1 because this is the where
+ changes are expected to come from. Diffing between these pairs
+ of files is is most likely to return the intended changes. There
+ can also be the same problem with phantom changes from file0 to
+ file1. */
+ /* Historically, the default common file was file2. Ediff for emacs
+ and possibly other applications, have therefore made file2 the
+ ancestor. So, for compatibility, if this is simply a three
+ way diff (not a merge or edscript) then use the old way with
+ file2 as the common file. */
+
+ {
+ int common;
+ if (edscript || merge )
+ {
+ common = 1;
+ }
+ else
+ {
+ common = 2;
+ }
+ if (strcmp (file[common], "-") == 0)
+ {
+ /* Sigh. We've got standard input as the arg corresponding to
+ the desired common file. We can't call diff twice on
+ stdin. Use another arg as the common file instead. */
+ common = 3 - common;
+ if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
+ {
+ diff_error ("%s", "`-' specified for more than one input file", 0);
+ return 2;
+ }
+ }
+
+ mapping[0] = 0;
+ mapping[1] = 3 - common;
+ mapping[2] = common;
+ }
+
+ for (i = 0; i < 3; i++)
+ rev_mapping[mapping[i]] = i;
+
+ for (i = 0; i < 3; i++)
+ if (strcmp (file[i], "-") != 0)
+ {
+ if (stat (file[i], &statb) < 0)
+ {
+ perror_with_name (file[i]);
+ return 2;
+ }
+ else if (S_ISDIR(statb.st_mode))
+ {
+ diff_error ("%s: Is a directory", file[i], 0);
+ return 2;
+ }
+ }
+
+ if (callbacks && callbacks->write_output)
+ {
+ if (out != NULL)
+ {
+ diff_error ("write callback with output file", 0, 0);
+ return 2;
+ }
+ }
+ else
+ {
+ if (out == NULL)
+ outfile = stdout;
+ else
+ {
+ outfile = fopen (out, "w");
+ if (outfile == NULL)
+ {
+ perror_with_name (out);
+ return 2;
+ }
+ opened_file = 1;
+ }
+ }
+
+ /* Set the jump buffer, so that diff may abort execution without
+ terminating the process. */
+ status = setjmp (diff3_abort_buf);
+ if (status != 0)
+ return status;
+
+ commonname = file[rev_mapping[FILEC]];
+ thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block,
+ &content1);
+ /* What is the intention behind determining horizon_lines from first
+ diff? I think it is better to use the same parameters for each
+ diff so that equal differences in each diff will appear the
+ same. */
+ /*
+ if (thread1)
+ for (i = 0; i < 2; i++)
+ {
+ horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i));
+ horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i));
+ }
+ */
+ thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block,
+ &content0);
+ diff3 = make_3way_diff (thread0, thread1);
+ if (edscript)
+ conflicts_found
+ = output_diff3_edscript (diff3, mapping, rev_mapping,
+ tag_strings[0], tag_strings[1], tag_strings[2]);
+ else if (merge)
+ {
+ FILE *mfp = fopen (file[rev_mapping[FILE0]], "r");
+ if (! mfp)
+ diff3_perror_with_exit (file[rev_mapping[FILE0]]);
+ conflicts_found = output_diff3_merge (mfp, diff3, mapping, rev_mapping,
+ tag_strings[0], tag_strings[1], tag_strings[2]);
+ if (ferror (mfp))
+ diff3_fatal ("read error");
+ if (fclose(mfp) != 0)
+ perror_with_name (file[rev_mapping[FILE0]]);
+ }
+ else
+ {
+ output_diff3 (diff3, mapping, rev_mapping);
+ conflicts_found = 0;
+ }
+
+ free(content0);
+ free(content1);
+ free_diff3_blocks(diff3);
+
+ if (! callbacks || ! callbacks->write_output)
+ check_output (outfile);
+
+ if (opened_file)
+ if (fclose (outfile) != 0)
+ perror_with_name ("close error on output file");
+
+ return conflicts_found;
+}
+
+static int
+try_help (reason)
+ char const *reason;
+{
+ if (reason)
+ diff_error ("%s", reason, 0);
+ diff_error ("Try `%s --help' for more information.", diff_program_name, 0);
+ return 2;
+}
+
+static void
+check_output (stream)
+ FILE *stream;
+{
+ if (ferror (stream) || fflush (stream) != 0)
+ diff3_fatal ("write error");
+}
+
+/*
+ * Explain, patiently and kindly, how to use this program.
+ */
+static void
+usage ()
+{
+ if (callbacks && callbacks->write_stdout)
+ {
+ (*callbacks->write_stdout) ("Usage: ");
+ (*callbacks->write_stdout) (diff_program_name);
+ (*callbacks->write_stdout) (" [OPTION]... MYFILE OLDFILE YOURFILE\n\n");
+
+ (*callbacks->write_stdout) ("\
+ -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
+ -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
+ -A --show-all Output all changes, bracketing conflicts.\n\
+ -x --overlap-only Output overlapping changes.\n\
+ -X Output overlapping changes, bracketing them.\n\
+ -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
+ (*callbacks->write_stdout) ("\
+ -m --merge Output merged file instead of ed script (default -A).\n\
+ -L LABEL --label=LABEL Use LABEL instead of file name.\n\
+ -i Append `w' and `q' commands to ed scripts.\n\
+ -a --text Treat all files as text.\n\
+ -T --initial-tab Make tabs line up by prepending a tab.\n\n");
+ (*callbacks->write_stdout) ("\
+ -v --version Output version info.\n\
+ --help Output this help.\n\n");
+ (*callbacks->write_stdout) ("If a FILE is `-', read standard input.\n");
+ }
+ else
+ {
+ printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", diff_program_name);
+
+ printf ("%s", "\
+ -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
+ -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
+ -A --show-all Output all changes, bracketing conflicts.\n\
+ -x --overlap-only Output overlapping changes.\n\
+ -X Output overlapping changes, bracketing them.\n\
+ -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
+ printf ("%s", "\
+ -m --merge Output merged file instead of ed script (default -A).\n\
+ -L LABEL --label=LABEL Use LABEL instead of file name.\n\
+ -i Append `w' and `q' commands to ed scripts.\n\
+ -a --text Treat all files as text.\n\
+ -T --initial-tab Make tabs line up by prepending a tab.\n\n");
+ printf ("%s", "\
+ -v --version Output version info.\n\
+ --help Output this help.\n\n");
+ printf ("If a FILE is `-', read standard input.\n");
+ }
+}
+
+/*
+ * Routines that combine the two diffs together into one. The
+ * algorithm used follows:
+ *
+ * File2 is shared in common between the two diffs.
+ * Diff02 is the diff between 0 and 2.
+ * Diff12 is the diff between 1 and 2.
+ *
+ * 1) Find the range for the first block in File2.
+ * a) Take the lowest of the two ranges (in File2) in the two
+ * current blocks (one from each diff) as being the low
+ * water mark. Assign the upper end of this block as
+ * being the high water mark and move the current block up
+ * one. Mark the block just moved over as to be used.
+ * b) Check the next block in the diff that the high water
+ * mark is *not* from.
+ *
+ * *If* the high water mark is above
+ * the low end of the range in that block,
+ *
+ * mark that block as to be used and move the current
+ * block up. Set the high water mark to the max of
+ * the high end of this block and the current. Repeat b.
+ *
+ * 2) Find the corresponding ranges in File0 (from the blocks
+ * in diff02; line per line outside of diffs) and in File1.
+ * Create a diff3_block, reserving space as indicated by the ranges.
+ *
+ * 3) Copy all of the pointers for file2 in. At least for now,
+ * do memcmp's between corresponding strings in the two diffs.
+ *
+ * 4) Copy all of the pointers for file0 and 1 in. Get what you
+ * need from file2 (when there isn't a diff block, it's
+ * identical to file2 within the range between diff blocks).
+ *
+ * 5) If the diff blocks you used came from only one of the two
+ * strings of diffs, then that file (i.e. the one other than
+ * the common file in that diff) is the odd person out. If you used
+ * diff blocks from both sets, check to see if files 0 and 1 match:
+ *
+ * Same number of lines? If so, do a set of memcmp's (if a
+ * memcmp matches; copy the pointer over; it'll be easier later
+ * if you have to do any compares). If they match, 0 & 1 are
+ * the same. If not, all three different.
+ *
+ * Then you do it again, until you run out of blocks.
+ *
+ */
+
+/*
+ * This routine makes a three way diff (chain of diff3_block's) from two
+ * two way diffs (chains of diff_block's). It is assumed that each of
+ * the two diffs passed are onto the same file (i.e. that each of the
+ * diffs were made "to" the same file). The three way diff pointer
+ * returned will have numbering FILE0--the other file in diff02,
+ * FILE1--the other file in diff12, and FILEC--the common file.
+ */
+static struct diff3_block *
+make_3way_diff (thread0, thread1)
+ struct diff_block *thread0, *thread1;
+{
+/*
+ * This routine works on the two diffs passed to it as threads.
+ * Thread number 0 is diff02, thread number 1 is diff12. The USING
+ * array is set to the base of the list of blocks to be used to
+ * construct each block of the three way diff; if no blocks from a
+ * particular thread are to be used, that element of the using array
+ * is set to 0. The elements LAST_USING array are set to the last
+ * elements on each of the using lists.
+ *
+ * The HIGH_WATER_MARK is set to the highest line number in the common file
+ * described in any of the diffs in either of the USING lists. The
+ * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
+ * and BASE_WATER_THREAD describe the lowest line number in the common file
+ * described in any of the diffs in either of the USING lists. The
+ * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
+ * taken.
+ *
+ * The HIGH_WATER_DIFF should always be equal to LAST_USING
+ * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
+ * higher water, and should always be equal to
+ * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread
+ * in which the OTHER_DIFF is, and hence should always be equal to
+ * HIGH_WATER_THREAD ^ 0x1.
+ *
+ * The variable LAST_DIFF is kept set to the last diff block produced
+ * by this routine, for line correspondence purposes between that diff
+ * and the one currently being worked on. It is initialized to
+ * ZERO_DIFF before any blocks have been created.
+ */
+
+ struct diff_block
+ *using[2],
+ *last_using[2],
+ *current[2];
+
+ int
+ high_water_mark;
+
+ int
+ high_water_thread,
+ base_water_thread,
+ other_thread;
+
+ struct diff_block
+ *high_water_diff,
+ *other_diff;
+
+ struct diff3_block
+ *result,
+ *tmpblock,
+ **result_end;
+
+ struct diff3_block const *last_diff3;
+
+ static struct diff3_block const zero_diff3 = { 0 };
+
+ /* Initialization */
+ result = 0;
+ result_end = &result;
+ current[0] = thread0; current[1] = thread1;
+ last_diff3 = &zero_diff3;
+
+ /* Sniff up the threads until we reach the end */
+
+ while (current[0] || current[1])
+ {
+ using[0] = using[1] = last_using[0] = last_using[1] = 0;
+
+ /* Setup low and high water threads, diffs, and marks. */
+ if (!current[0])
+ base_water_thread = 1;
+ else if (!current[1])
+ base_water_thread = 0;
+ else
+ base_water_thread =
+ (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
+
+ high_water_thread = base_water_thread;
+
+ high_water_diff = current[high_water_thread];
+
+#if 0
+ /* low and high waters start off same diff */
+ base_water_mark = D_LOWLINE (high_water_diff, FC);
+#endif
+
+ high_water_mark = D_HIGHLINE (high_water_diff, FC);
+
+ /* Make the diff you just got info from into the using class */
+ using[high_water_thread]
+ = last_using[high_water_thread]
+ = high_water_diff;
+ current[high_water_thread] = high_water_diff->next;
+ last_using[high_water_thread]->next = 0;
+
+ /* And mark the other diff */
+ other_thread = high_water_thread ^ 0x1;
+ other_diff = current[other_thread];
+
+ /* Shuffle up the ladder, checking the other diff to see if it
+ needs to be incorporated. */
+ while (other_diff
+ && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
+ {
+
+ /* Incorporate this diff into the using list. Note that
+ this doesn't take it off the current list */
+ if (using[other_thread])
+ last_using[other_thread]->next = other_diff;
+ else
+ using[other_thread] = other_diff;
+ last_using[other_thread] = other_diff;
+
+ /* Take it off the current list. Note that this following
+ code assumes that other_diff enters it equal to
+ current[high_water_thread ^ 0x1] */
+ current[other_thread] = current[other_thread]->next;
+ other_diff->next = 0;
+
+ /* Set the high_water stuff
+ If this comparison is equal, then this is the last pass
+ through this loop; since diff blocks within a given
+ thread cannot overlap, the high_water_mark will be
+ *below* the range_start of either of the next diffs. */
+
+ if (high_water_mark < D_HIGHLINE (other_diff, FC))
+ {
+ high_water_thread ^= 1;
+ high_water_diff = other_diff;
+ high_water_mark = D_HIGHLINE (other_diff, FC);
+ }
+
+ /* Set the other diff */
+ other_thread = high_water_thread ^ 0x1;
+ other_diff = current[other_thread];
+ }
+
+ /* The using lists contain a list of all of the blocks to be
+ included in this diff3_block. Create it. */
+
+ tmpblock = using_to_diff3_block (using, last_using,
+ base_water_thread, high_water_thread,
+ last_diff3);
+ free_diff_blocks(using[0]);
+ free_diff_blocks(using[1]);
+
+ if (!tmpblock)
+ diff3_fatal ("internal error: screwup in format of diff blocks");
+
+ /* Put it on the list. */
+ *result_end = tmpblock;
+ result_end = &tmpblock->next;
+
+ /* Set up corresponding lines correctly. */
+ last_diff3 = tmpblock;
+ }
+ return result;
+}
+
+/*
+ * using_to_diff3_block:
+ * This routine takes two lists of blocks (from two separate diff
+ * threads) and puts them together into one diff3 block.
+ * It then returns a pointer to this diff3 block or 0 for failure.
+ *
+ * All arguments besides using are for the convenience of the routine;
+ * they could be derived from the using array.
+ * LAST_USING is a pair of pointers to the last blocks in the using
+ * structure.
+ * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
+ * and highest line numbers for File0.
+ * last_diff3 contains the last diff produced in the calling routine.
+ * This is used for lines mappings which would still be identical to
+ * the state that diff ended in.
+ *
+ * A distinction should be made in this routine between the two diffs
+ * that are part of a normal two diff block, and the three diffs that
+ * are part of a diff3_block.
+ */
+static struct diff3_block *
+using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
+ struct diff_block
+ *using[2],
+ *last_using[2];
+ int low_thread, high_thread;
+ struct diff3_block const *last_diff3;
+{
+ int low[2], high[2];
+ struct diff3_block *result;
+ struct diff_block *ptr;
+ int d, i;
+
+ /* Find the range in the common file. */
+ int lowc = D_LOWLINE (using[low_thread], FC);
+ int highc = D_HIGHLINE (last_using[high_thread], FC);
+
+ /* Find the ranges in the other files.
+ If using[d] is null, that means that the file to which that diff
+ refers is equivalent to the common file over this range. */
+
+ for (d = 0; d < 2; d++)
+ if (using[d])
+ {
+ low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
+ high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
+ }
+ else
+ {
+ low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
+ high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
+ }
+
+ /* Create a block with the appropriate sizes */
+ result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
+
+ /* Copy information for the common file.
+ Return with a zero if any of the compares failed. */
+
+ for (d = 0; d < 2; d++)
+ for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
+ {
+ int result_offset = D_LOWLINE (ptr, FC) - lowc;
+
+ if (!copy_stringlist (D_LINEARRAY (ptr, FC),
+ D_LENARRAY (ptr, FC),
+ D_LINEARRAY (result, FILEC) + result_offset,
+ D_LENARRAY (result, FILEC) + result_offset,
+ D_NUMLINES (ptr, FC)))
+ return 0;
+ }
+
+ /* Copy information for file d. First deal with anything that might be
+ before the first diff. */
+
+ for (d = 0; d < 2; d++)
+ {
+ struct diff_block *u = using[d];
+ int lo = low[d], hi = high[d];
+
+ for (i = 0;
+ i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
+ i++)
+ {
+ D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
+ D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
+ }
+
+ for (ptr = u; ptr; ptr = D_NEXT (ptr))
+ {
+ int result_offset = D_LOWLINE (ptr, FO) - lo;
+ int linec;
+
+ if (!copy_stringlist (D_LINEARRAY (ptr, FO),
+ D_LENARRAY (ptr, FO),
+ D_LINEARRAY (result, FILE0 + d) + result_offset,
+ D_LENARRAY (result, FILE0 + d) + result_offset,
+ D_NUMLINES (ptr, FO)))
+ return 0;
+
+ /* Catch the lines between here and the next diff */
+ linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
+ for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
+ i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
+ i++)
+ {
+ D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
+ D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
+ linec++;
+ }
+ }
+ }
+
+ /* Set correspond */
+ if (!using[0])
+ D3_TYPE (result) = DIFF_2ND;
+ else if (!using[1])
+ D3_TYPE (result) = DIFF_1ST;
+ else
+ {
+ int nl0 = D_NUMLINES (result, FILE0);
+ int nl1 = D_NUMLINES (result, FILE1);
+
+ if (nl0 != nl1
+ || !compare_line_list (D_LINEARRAY (result, FILE0),
+ D_LENARRAY (result, FILE0),
+ D_LINEARRAY (result, FILE1),
+ D_LENARRAY (result, FILE1),
+ nl0))
+ D3_TYPE (result) = DIFF_ALL;
+ else
+ D3_TYPE (result) = DIFF_3RD;
+ }
+
+ return result;
+}
+
+/*
+ * This routine copies pointers from a list of strings to a different list
+ * of strings. If a spot in the second list is already filled, it
+ * makes sure that it is filled with the same string; if not it
+ * returns 0, the copy incomplete.
+ * Upon successful completion of the copy, it returns 1.
+ */
+static int
+copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
+ char * const fromptrs[];
+ char *toptrs[];
+ size_t const fromlengths[];
+ size_t tolengths[];
+ int copynum;
+{
+ register char * const *f = fromptrs;
+ register char **t = toptrs;
+ register size_t const *fl = fromlengths;
+ register size_t *tl = tolengths;
+
+ while (copynum--)
+ {
+ if (*t)
+ { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
+ else
+ { *t = *f ; *tl = *fl; }
+
+ t++; f++; tl++; fl++;
+ }
+ return 1;
+}
+
+/*
+ * Create a diff3_block, with ranges as specified in the arguments.
+ * Allocate the arrays for the various pointers (and zero them) based
+ * on the arguments passed. Return the block as a result.
+ */
+static struct diff3_block *
+create_diff3_block (low0, high0, low1, high1, low2, high2)
+ register int low0, high0, low1, high1, low2, high2;
+{
+ struct diff3_block *result = ALLOCATE (1, struct diff3_block);
+ int numlines;
+
+ D3_TYPE (result) = ERROR;
+ D_NEXT (result) = 0;
+
+ /* Assign ranges */
+ D_LOWLINE (result, FILE0) = low0;
+ D_HIGHLINE (result, FILE0) = high0;
+ D_LOWLINE (result, FILE1) = low1;
+ D_HIGHLINE (result, FILE1) = high1;
+ D_LOWLINE (result, FILE2) = low2;
+ D_HIGHLINE (result, FILE2) = high2;
+
+ /* Allocate and zero space */
+ numlines = D_NUMLINES (result, FILE0);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t);
+ bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE0) = 0;
+ D_LENARRAY (result, FILE0) = 0;
+ }
+
+ numlines = D_NUMLINES (result, FILE1);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t);
+ bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE1) = 0;
+ D_LENARRAY (result, FILE1) = 0;
+ }
+
+ numlines = D_NUMLINES (result, FILE2);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t);
+ bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE2) = 0;
+ D_LENARRAY (result, FILE2) = 0;
+ }
+
+ /* Return */
+ return result;
+}
+
+/*
+ * Compare two lists of lines of text.
+ * Return 1 if they are equivalent, 0 if not.
+ */
+static int
+compare_line_list (list1, lengths1, list2, lengths2, nl)
+ char * const list1[], * const list2[];
+ size_t const lengths1[], lengths2[];
+ int nl;
+{
+ char
+ * const *l1 = list1,
+ * const *l2 = list2;
+ size_t const
+ *lgths1 = lengths1,
+ *lgths2 = lengths2;
+
+ while (nl--)
+ if (!*l1 || !*l2 || *lgths1 != *lgths2++
+ || memcmp (*l1++, *l2++, *lgths1++))
+ return 0;
+ return 1;
+}
+
+/*
+ * Routines to input and parse two way diffs.
+ */
+
+extern char **environ;
+
+static struct diff_block *
+process_diff (filea, fileb, last_block, diff_contents)
+ char const *filea, *fileb;
+ struct diff_block **last_block;
+ char **diff_contents;
+{
+ char *diff_limit;
+ char *scan_diff;
+ enum diff_type dt;
+ int i;
+ struct diff_block *block_list, **block_list_end, *bptr;
+
+ diff_limit = read_diff (filea, fileb, diff_contents);
+ scan_diff = *diff_contents;
+ block_list_end = &block_list;
+ bptr = 0; /* Pacify `gcc -W'. */
+
+ while (scan_diff < diff_limit)
+ {
+ bptr = ALLOCATE (1, struct diff_block);
+ bptr->lines[0] = bptr->lines[1] = 0;
+ bptr->lengths[0] = bptr->lengths[1] = 0;
+
+ dt = process_diff_control (&scan_diff, bptr);
+ if (dt == ERROR || *scan_diff != '\n')
+ {
+ char *serr;
+
+ for (serr = scan_diff; *serr != '\n'; serr++)
+ ;
+ *serr = '\0';
+ diff_error ("diff error: %s", scan_diff, 0);
+ *serr = '\n';
+ DIFF3_ABORT (2);
+ }
+ scan_diff++;
+
+ /* Force appropriate ranges to be null, if necessary */
+ switch (dt)
+ {
+ case ADD:
+ bptr->ranges[0][0]++;
+ break;
+ case DELETE:
+ bptr->ranges[1][0]++;
+ break;
+ case CHANGE:
+ break;
+ default:
+ diff3_fatal ("internal error: invalid diff type in process_diff");
+ break;
+ }
+
+ /* Allocate space for the pointers for the lines from filea, and
+ parcel them out among these pointers */
+ if (dt != ADD)
+ {
+ int numlines = D_NUMLINES (bptr, 0);
+ bptr->lines[0] = ALLOCATE (numlines, char *);
+ bptr->lengths[0] = ALLOCATE (numlines, size_t);
+ for (i = 0; i < numlines; i++)
+ scan_diff = scan_diff_line (scan_diff,
+ &(bptr->lines[0][i]),
+ &(bptr->lengths[0][i]),
+ diff_limit,
+ '<');
+ }
+
+ /* Get past the separator for changes */
+ if (dt == CHANGE)
+ {
+ if (strncmp (scan_diff, "---\n", 4))
+ diff3_fatal ("invalid diff format; invalid change separator");
+ scan_diff += 4;
+ }
+
+ /* Allocate space for the pointers for the lines from fileb, and
+ parcel them out among these pointers */
+ if (dt != DELETE)
+ {
+ int numlines = D_NUMLINES (bptr, 1);
+ bptr->lines[1] = ALLOCATE (numlines, char *);
+ bptr->lengths[1] = ALLOCATE (numlines, size_t);
+ for (i = 0; i < numlines; i++)
+ scan_diff = scan_diff_line (scan_diff,
+ &(bptr->lines[1][i]),
+ &(bptr->lengths[1][i]),
+ diff_limit,
+ '>');
+ }
+
+ /* Place this block on the blocklist. */
+ *block_list_end = bptr;
+ block_list_end = &bptr->next;
+ }
+
+ *block_list_end = 0;
+ *last_block = bptr;
+ return block_list;
+}
+
+/*
+ * This routine will parse a normal format diff control string. It
+ * returns the type of the diff (ERROR if the format is bad). All of
+ * the other important information is filled into to the structure
+ * pointed to by db, and the string pointer (whose location is passed
+ * to this routine) is updated to point beyond the end of the string
+ * parsed. Note that only the ranges in the diff_block will be set by
+ * this routine.
+ *
+ * If some specific pair of numbers has been reduced to a single
+ * number, then both corresponding numbers in the diff block are set
+ * to that number. In general these numbers are interpetted as ranges
+ * inclusive, unless being used by the ADD or DELETE commands. It is
+ * assumed that these will be special cased in a superior routine.
+ */
+
+static enum diff_type
+process_diff_control (string, db)
+ char **string;
+ struct diff_block *db;
+{
+ char *s = *string;
+ int holdnum;
+ enum diff_type type;
+
+/* These macros are defined here because they can use variables
+ defined in this function. Don't try this at home kids, we're
+ trained professionals!
+
+ Also note that SKIPWHITE only recognizes tabs and spaces, and
+ that READNUM can only read positive, integral numbers */
+
+#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
+#define READNUM(s, num) \
+ { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \
+ do { holdnum = (c - '0' + holdnum * 10); } \
+ while (ISDIGIT (c = *++s)); (num) = holdnum; }
+
+ /* Read first set of digits */
+ SKIPWHITE (s);
+ READNUM (s, db->ranges[0][START]);
+
+ /* Was that the only digit? */
+ SKIPWHITE (s);
+ if (*s == ',')
+ {
+ /* Get the next digit */
+ s++;
+ READNUM (s, db->ranges[0][END]);
+ }
+ else
+ db->ranges[0][END] = db->ranges[0][START];
+
+ /* Get the letter */
+ SKIPWHITE (s);
+ switch (*s)
+ {
+ case 'a':
+ type = ADD;
+ break;
+ case 'c':
+ type = CHANGE;
+ break;
+ case 'd':
+ type = DELETE;
+ break;
+ default:
+ return ERROR; /* Bad format */
+ }
+ s++; /* Past letter */
+
+ /* Read second set of digits */
+ SKIPWHITE (s);
+ READNUM (s, db->ranges[1][START]);
+
+ /* Was that the only digit? */
+ SKIPWHITE (s);
+ if (*s == ',')
+ {
+ /* Get the next digit */
+ s++;
+ READNUM (s, db->ranges[1][END]);
+ SKIPWHITE (s); /* To move to end */
+ }
+ else
+ db->ranges[1][END] = db->ranges[1][START];
+
+ *string = s;
+ return type;
+}
+
+static char *
+read_diff (filea, fileb, output_placement)
+ char const *filea, *fileb;
+ char **output_placement;
+{
+ char *diff_result;
+ size_t bytes, current_chunk_size, total;
+ int fd, wstatus;
+ struct stat pipestat;
+ FILE *outfile_hold;
+ const struct diff_callbacks *callbacks_hold;
+ struct diff_callbacks my_callbacks;
+ struct diff_callbacks *my_callbacks_arg;
+
+ /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit;
+ add 1 for integer division truncation; add 1 more for a minus sign. */
+#define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2)
+
+ char const *argv[7];
+ char horizon_arg[17 + INT_STRLEN_BOUND (int)];
+ char const **ap;
+ char *diffout;
+
+ ap = argv;
+ *ap++ = "diff";
+ if (always_text)
+ *ap++ = "-a";
+ sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines);
+ *ap++ = horizon_arg;
+ *ap++ = "--";
+ *ap++ = filea;
+ *ap++ = fileb;
+ *ap = 0;
+
+ diffout = cvs_temp_name ();
+
+ outfile_hold = outfile;
+ callbacks_hold = callbacks;
+
+ /* We want to call diff_run preserving any stdout and stderr
+ callbacks, but discarding any callbacks to handle file output,
+ since we want the file output to go to our temporary file.
+ FIXME: We should use callbacks to just read it into a memory
+ buffer; that's we do with the temporary file just below anyhow. */
+ if (callbacks == NULL)
+ my_callbacks_arg = NULL;
+ else
+ {
+ my_callbacks = *callbacks;
+ my_callbacks.write_output = NULL;
+ my_callbacks.flush_output = NULL;
+ my_callbacks_arg = &my_callbacks;
+ }
+
+ wstatus = diff_run (ap - argv, (char **) argv, diffout, my_callbacks_arg);
+
+ outfile = outfile_hold;
+ callbacks = callbacks_hold;
+
+ if (wstatus == 2)
+ diff3_fatal ("subsidiary diff failed");
+
+ if (-1 == (fd = open (diffout, O_RDONLY)))
+ diff3_fatal ("could not open temporary diff file");
+
+ current_chunk_size = 8 * 1024;
+ if (fstat (fd, &pipestat) == 0)
+ current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat));
+
+ diff_result = xmalloc (current_chunk_size);
+ total = 0;
+ do {
+ bytes = myread (fd,
+ diff_result + total,
+ current_chunk_size - total);
+ total += bytes;
+ if (total == current_chunk_size)
+ {
+ if (current_chunk_size < 2 * current_chunk_size)
+ current_chunk_size = 2 * current_chunk_size;
+ else if (current_chunk_size < (size_t) -1)
+ current_chunk_size = (size_t) -1;
+ else
+ diff3_fatal ("files are too large to fit into memory");
+ diff_result = xrealloc (diff_result, (current_chunk_size *= 2));
+ }
+ } while (bytes);
+
+ if (total != 0 && diff_result[total-1] != '\n')
+ diff3_fatal ("invalid diff format; incomplete last line");
+
+ *output_placement = diff_result;
+
+ if (close (fd) != 0)
+ diff3_perror_with_exit ("pipe close");
+ unlink (diffout);
+ free( diffout );
+
+ return diff_result + total;
+}
+
+
+/*
+ * Scan a regular diff line (consisting of > or <, followed by a
+ * space, followed by text (including nulls) up to a newline.
+ *
+ * This next routine began life as a macro and many parameters in it
+ * are used as call-by-reference values.
+ */
+static char *
+scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar)
+ char *scan_ptr, **set_start;
+ size_t *set_length;
+ char *limit;
+ int leadingchar;
+{
+ char *line_ptr;
+
+ if (!(scan_ptr[0] == leadingchar
+ && scan_ptr[1] == ' '))
+ diff3_fatal ("invalid diff format; incorrect leading line chars");
+
+ *set_start = line_ptr = scan_ptr + 2;
+ while (*line_ptr++ != '\n')
+ ;
+
+ /* Include newline if the original line ended in a newline,
+ or if an edit script is being generated.
+ Copy any missing newline message to stderr if an edit script is being
+ generated, because edit scripts cannot handle missing newlines.
+ Return the beginning of the next line. */
+ *set_length = line_ptr - *set_start;
+ if (line_ptr < limit && *line_ptr == '\\')
+ {
+ if (! edscript)
+ {
+ --*set_length;
+ line_ptr++;
+ while (*line_ptr++ != '\n')
+ ;
+ }
+ else
+ {
+ char *serr;
+
+ line_ptr++;
+ serr = line_ptr;
+ while (*line_ptr++ != '\n')
+ ;
+ line_ptr[-1] = '\0';
+ diff_error ("%s", serr, 0);
+ line_ptr[-1] = '\n';
+ }
+ }
+
+ return line_ptr;
+}
+
+/*
+ * This routine outputs a three way diff passed as a list of
+ * diff3_block's.
+ * The argument MAPPING is indexed by external file number (in the
+ * argument list) and contains the internal file number (from the
+ * diff passed). This is important because the user expects his
+ * outputs in terms of the argument list number, and the diff passed
+ * may have been done slightly differently (if the last argument
+ * was "-", for example).
+ * REV_MAPPING is the inverse of MAPPING.
+ */
+static void
+output_diff3 (diff, mapping, rev_mapping)
+ struct diff3_block *diff;
+ int const mapping[3], rev_mapping[3];
+{
+ int i;
+ int oddoneout;
+ char *cp;
+ struct diff3_block *ptr;
+ int line;
+ size_t length;
+ int dontprint;
+ static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
+ char const *line_prefix = tab_align_flag ? "\t" : " ";
+
+ for (ptr = diff; ptr; ptr = D_NEXT (ptr))
+ {
+ char x[2];
+
+ switch (ptr->correspond)
+ {
+ case DIFF_ALL:
+ x[0] = '\0';
+ dontprint = 3; /* Print them all */
+ oddoneout = 3; /* Nobody's odder than anyone else */
+ break;
+ case DIFF_1ST:
+ case DIFF_2ND:
+ case DIFF_3RD:
+ oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
+
+ x[0] = oddoneout + '1';
+ x[1] = '\0';
+ dontprint = oddoneout==0;
+ break;
+ default:
+ diff3_fatal ("internal error: invalid diff type passed to output");
+ }
+ printf_output ("====%s\n", x);
+
+ /* Go 0, 2, 1 if the first and third outputs are equivalent. */
+ for (i = 0; i < 3;
+ i = (oddoneout == 1 ? skew_increment[i] : i + 1))
+ {
+ int realfile = mapping[i];
+ int
+ lowt = D_LOWLINE (ptr, realfile),
+ hight = D_HIGHLINE (ptr, realfile);
+
+ printf_output ("%d:", i + 1);
+ switch (lowt - hight)
+ {
+ case 1:
+ printf_output ("%da\n", lowt - 1);
+ break;
+ case 0:
+ printf_output ("%dc\n", lowt);
+ break;
+ default:
+ printf_output ("%d,%dc\n", lowt, hight);
+ break;
+ }
+
+ if (i == dontprint) continue;
+
+ if (lowt <= hight)
+ {
+ line = 0;
+ do
+ {
+ printf_output (line_prefix);
+ cp = D_RELNUM (ptr, realfile, line);
+ length = D_RELLEN (ptr, realfile, line);
+ write_output (cp, length);
+ }
+ while (++line < hight - lowt + 1);
+ if (cp[length - 1] != '\n')
+ printf_output ("\n\\ No newline at end of file\n");
+ }
+ }
+ }
+}
+
+
+/*
+ * Output the lines of B taken from FILENUM.
+ * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
+ */
+static int
+dotlines (b, filenum)
+ struct diff3_block *b;
+ int filenum;
+{
+ int i;
+ int leading_dot = 0;
+
+ for (i = 0;
+ i < D_NUMLINES (b, filenum);
+ i++)
+ {
+ char *line = D_RELNUM (b, filenum, i);
+ if (line[0] == '.')
+ {
+ leading_dot = 1;
+ write_output (".", 1);
+ }
+ write_output (line, D_RELLEN (b, filenum, i));
+ }
+
+ return leading_dot;
+}
+
+/*
+ * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero,
+ * also output a command that removes initial '.'s
+ * starting with line START and continuing for NUM lines.
+ */
+static void
+undotlines (leading_dot, start, num)
+ int leading_dot, start, num;
+{
+ write_output (".\n", 2);
+ if (leading_dot)
+ if (num == 1)
+ printf_output ("%ds/^\\.//\n", start);
+ else
+ printf_output ("%d,%ds/^\\.//\n", start, start + num - 1);
+}
+
+/*
+ * This routine outputs a diff3 set of blocks as an ed script. This
+ * script applies the changes between file's 2 & 3 to file 1. It
+ * takes the precise format of the ed script to be output from global
+ * variables set during options processing. Note that it does
+ * destructive things to the set of diff3 blocks it is passed; it
+ * reverses their order (this gets around the problems involved with
+ * changing line numbers in an ed script).
+ *
+ * Note that this routine has the same problem of mapping as the last
+ * one did; the variable MAPPING maps from file number according to
+ * the argument list to file number according to the diff passed. All
+ * files listed below are in terms of the argument list.
+ * REV_MAPPING is the inverse of MAPPING.
+ *
+ * The arguments FILE0, FILE1 and FILE2 are the strings to print
+ * as the names of the three files. These may be the actual names,
+ * or may be the arguments specified with -L.
+ *
+ * Returns 1 if conflicts were found.
+ */
+
+static int
+output_diff3_edscript (diff, mapping, rev_mapping, file0, file1, file2)
+ struct diff3_block *diff;
+ int const mapping[3], rev_mapping[3];
+ char const *file0, *file1, *file2;
+{
+ int leading_dot;
+ int conflicts_found = 0, conflict;
+ struct diff3_block *b;
+
+ for (b = reverse_diff3_blocklist (diff); b; b = b->next)
+ {
+ /* Must do mapping correctly. */
+ enum diff_type type
+ = ((b->correspond == DIFF_ALL) ?
+ DIFF_ALL :
+ ((enum diff_type)
+ (((int) DIFF_1ST)
+ + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
+
+ /* If we aren't supposed to do this output block, skip it. */
+ switch (type)
+ {
+ default: continue;
+ case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+ case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+ case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
+ }
+
+ if (conflict)
+ {
+ conflicts_found = 1;
+
+
+ /* Mark end of conflict. */
+
+ printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0]));
+ leading_dot = 0;
+ if (type == DIFF_ALL)
+ {
+ if (show_2nd)
+ {
+ /* Append lines from FILE1. */
+ printf_output ("||||||| %s\n", file1);
+ leading_dot = dotlines (b, mapping[FILE1]);
+ }
+ /* Append lines from FILE2. */
+ printf_output ("=======\n");
+ leading_dot |= dotlines (b, mapping[FILE2]);
+ }
+ printf_output (">>>>>>> %s\n", file2);
+ undotlines (leading_dot,
+ D_HIGHLINE (b, mapping[FILE0]) + 2,
+ (D_NUMLINES (b, mapping[FILE1])
+ + D_NUMLINES (b, mapping[FILE2]) + 1));
+
+
+ /* Mark start of conflict. */
+
+ printf_output ("%da\n<<<<<<< %s\n",
+ D_LOWLINE (b, mapping[FILE0]) - 1,
+ type == DIFF_ALL ? file0 : file1);
+ leading_dot = 0;
+ if (type == DIFF_2ND)
+ {
+ /* Prepend lines from FILE1. */
+ leading_dot = dotlines (b, mapping[FILE1]);
+ printf_output ("=======\n");
+ }
+ undotlines (leading_dot,
+ D_LOWLINE (b, mapping[FILE0]) + 1,
+ D_NUMLINES (b, mapping[FILE1]));
+ }
+ else if (D_NUMLINES (b, mapping[FILE2]) == 0)
+ /* Write out a delete */
+ {
+ if (D_NUMLINES (b, mapping[FILE0]) == 1)
+ printf_output ("%dd\n", D_LOWLINE (b, mapping[FILE0]));
+ else
+ printf_output ("%d,%dd\n",
+ D_LOWLINE (b, mapping[FILE0]),
+ D_HIGHLINE (b, mapping[FILE0]));
+ }
+ else
+ /* Write out an add or change */
+ {
+ switch (D_NUMLINES (b, mapping[FILE0]))
+ {
+ case 0:
+ printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0]));
+ break;
+ case 1:
+ printf_output ("%dc\n", D_HIGHLINE (b, mapping[FILE0]));
+ break;
+ default:
+ printf_output ("%d,%dc\n",
+ D_LOWLINE (b, mapping[FILE0]),
+ D_HIGHLINE (b, mapping[FILE0]));
+ break;
+ }
+
+ undotlines (dotlines (b, mapping[FILE2]),
+ D_LOWLINE (b, mapping[FILE0]),
+ D_NUMLINES (b, mapping[FILE2]));
+ }
+ }
+ if (finalwrite) printf_output ("w\nq\n");
+ return conflicts_found;
+}
+
+/*
+ * Read from INFILE and output to the standard output file a set of
+ * diff3_ blocks DIFF as a merged file. This acts like 'ed file0
+ * <[output_diff3_edscript]', except that it works even for binary
+ * data or incomplete lines.
+ *
+ * As before, MAPPING maps from arg list file number to diff file number,
+ * REV_MAPPING is its inverse,
+ * and FILE0, FILE1, and FILE2 are the names of the files.
+ *
+ * Returns 1 if conflicts were found.
+ */
+
+static int
+output_diff3_merge (infile, diff, mapping, rev_mapping,
+ file0, file1, file2)
+ FILE *infile;
+ struct diff3_block *diff;
+ int const mapping[3], rev_mapping[3];
+ char const *file0, *file1, *file2;
+{
+ int c, i;
+ char cc;
+ int conflicts_found = 0, conflict;
+ struct diff3_block *b;
+ int linesread = 0;
+
+ for (b = diff; b; b = b->next)
+ {
+ /* Must do mapping correctly. */
+ enum diff_type type
+ = ((b->correspond == DIFF_ALL) ?
+ DIFF_ALL :
+ ((enum diff_type)
+ (((int) DIFF_1ST)
+ + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
+ char const *format_2nd = "<<<<<<< %s\n";
+
+ /* If we aren't supposed to do this output block, skip it. */
+ switch (type)
+ {
+ default: continue;
+ case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+ case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+ case DIFF_ALL: if (simple_only) continue; conflict = flagging;
+ format_2nd = "||||||| %s\n";
+ break;
+ }
+
+ /* Copy I lines from file 0. */
+ i = D_LOWLINE (b, FILE0) - linesread - 1;
+ linesread += i;
+ while (0 <= --i)
+ do
+ {
+ c = getc (infile);
+ if (c == EOF)
+ if (ferror (infile))
+ diff3_perror_with_exit ("input file");
+ else if (feof (infile))
+ diff3_fatal ("input file shrank");
+ cc = c;
+ write_output (&cc, 1);
+ }
+ while (c != '\n');
+
+ if (conflict)
+ {
+ conflicts_found = 1;
+
+ if (type == DIFF_ALL)
+ {
+ /* Put in lines from FILE0 with bracket. */
+ printf_output ("<<<<<<< %s\n", file0);
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE0]);
+ i++)
+ write_output (D_RELNUM (b, mapping[FILE0], i),
+ D_RELLEN (b, mapping[FILE0], i));
+ }
+
+ if (show_2nd)
+ {
+ /* Put in lines from FILE1 with bracket. */
+ printf_output (format_2nd, file1);
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE1]);
+ i++)
+ write_output (D_RELNUM (b, mapping[FILE1], i),
+ D_RELLEN (b, mapping[FILE1], i));
+ }
+
+ printf_output ("=======\n");
+ }
+
+ /* Put in lines from FILE2. */
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE2]);
+ i++)
+ write_output (D_RELNUM (b, mapping[FILE2], i),
+ D_RELLEN (b, mapping[FILE2], i));
+
+ if (conflict)
+ printf_output (">>>>>>> %s\n", file2);
+
+ /* Skip I lines in file 0. */
+ i = D_NUMLINES (b, FILE0);
+ linesread += i;
+ while (0 <= --i)
+ while ((c = getc (infile)) != '\n')
+ if (c == EOF)
+ if (ferror (infile))
+ diff3_perror_with_exit ("input file");
+ else if (feof (infile))
+ {
+ if (i || b->next)
+ diff3_fatal ("input file shrank");
+ return conflicts_found;
+ }
+ }
+ /* Copy rest of common file. */
+ while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
+ {
+ cc = c;
+ write_output (&cc, 1);
+ }
+ return conflicts_found;
+}
+
+/*
+ * Reverse the order of the list of diff3 blocks.
+ */
+static struct diff3_block *
+reverse_diff3_blocklist (diff)
+ struct diff3_block *diff;
+{
+ register struct diff3_block *tmp, *next, *prev;
+
+ for (tmp = diff, prev = 0; tmp; tmp = next)
+ {
+ next = tmp->next;
+ tmp->next = prev;
+ prev = tmp;
+ }
+
+ return prev;
+}
+
+static size_t
+myread (fd, ptr, size)
+ int fd;
+ char *ptr;
+ size_t size;
+{
+ ssize_t result = read (fd, ptr, size);
+ if (result == -1)
+ diff3_perror_with_exit ("read failed");
+ return (size_t)result;
+}
+
+static void
+diff3_fatal (string)
+ char const *string;
+{
+ diff_error ("%s", string, 0);
+ DIFF3_ABORT (2);
+}
+
+static void
+diff3_perror_with_exit (string)
+ char const *string;
+{
+ perror_with_name (string);
+ DIFF3_ABORT (2);
+}
+
+static void
+initialize_main (argcp, argvp)
+ int *argcp;
+ char ***argvp;
+{
+ always_text = 0;
+ edscript = 0;
+ flagging = 0;
+ tab_align_flag = 0;
+ simple_only = 0;
+ overlap_only = 0;
+ show_2nd = 0;
+ finalwrite = 0;
+ merge = 0;
+ diff_program_name = (*argvp)[0];
+ outfile = NULL;
+}
+
+static void
+free_diff_blocks(p)
+ struct diff_block *p;
+{
+ register struct diff_block *next;
+
+ while (p)
+ {
+ next = p->next;
+ if (p->lines[0]) free(p->lines[0]);
+ if (p->lines[1]) free(p->lines[1]);
+ if (p->lengths[0]) free(p->lengths[0]);
+ if (p->lengths[1]) free(p->lengths[1]);
+ free(p);
+ p = next;
+ }
+}
+
+static void
+free_diff3_blocks(p)
+ struct diff3_block *p;
+{
+ register struct diff3_block *next;
+
+ while (p)
+ {
+ next = p->next;
+ if (p->lines[0]) free(p->lines[0]);
+ if (p->lines[1]) free(p->lines[1]);
+ if (p->lines[2]) free(p->lines[2]);
+ if (p->lengths[0]) free(p->lengths[0]);
+ if (p->lengths[1]) free(p->lengths[1]);
+ if (p->lengths[2]) free(p->lengths[2]);
+ free(p);
+ p = next;
+ }
+}
diff --git a/diff/diffrun.h b/diff/diffrun.h
new file mode 100644
index 0000000..9ee804b
--- /dev/null
+++ b/diff/diffrun.h
@@ -0,0 +1,69 @@
+/* Interface header file for GNU DIFF library.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+#ifndef DIFFRUN_H
+#define DIFFRUN_H
+
+/* This header file defines the interfaces used by the diff library.
+ It should be included by programs which use the diff library. */
+
+#include <sys/types.h>
+
+#if defined __STDC__ && __STDC__
+#define DIFFPARAMS(args) args
+#else
+#define DIFFPARAMS(args) ()
+#endif
+
+/* The diff_callbacks structure is used to handle callbacks from the
+ diff library. All output goes through these callbacks. When a
+ pointer to this structure is passed in, it may be NULL. Also, any
+ of the individual callbacks may be NULL. This means that the
+ default action should be taken. */
+
+struct diff_callbacks
+{
+ /* Write output. This function just writes a string of a given
+ length to the output file. The default is to fwrite to OUTFILE.
+ If this callback is defined, flush_output must also be defined.
+ If the length is zero, output zero bytes. */
+ void (*write_output) DIFFPARAMS((char const *, size_t));
+ /* Flush output. The default is to fflush OUTFILE. If this
+ callback is defined, write_output must also be defined. */
+ void (*flush_output) DIFFPARAMS((void));
+ /* Write a '\0'-terminated string to stdout.
+ This is called for version and help messages. */
+ void (*write_stdout) DIFFPARAMS((char const *));
+ /* Print an error message. The first argument is a printf format,
+ and the next two are parameters. The default is to print a
+ message on stderr. */
+ void (*error) DIFFPARAMS((char const *, char const *, char const *));
+};
+
+/* Run a diff. */
+
+extern int diff_run DIFFPARAMS((int, char **, const char *,
+ const struct diff_callbacks *));
+
+/* Run a diff3. */
+
+extern int diff3_run DIFFPARAMS((int, char **, char *,
+ const struct diff_callbacks *));
+
+#undef DIFFPARAMS
+
+#endif /* DIFFRUN_H */
diff --git a/diff/dir.c b/diff/dir.c
new file mode 100644
index 0000000..da497dc
--- /dev/null
+++ b/diff/dir.c
@@ -0,0 +1,218 @@
+/* Read, sort and compare two directories. Used for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+#include "diff.h"
+
+/* Read the directory named by DIR and store into DIRDATA a sorted vector
+ of filenames for its contents. DIR->desc == -1 means this directory is
+ known to be nonexistent, so set DIRDATA to an empty vector.
+ Return -1 (setting errno) if error, 0 otherwise. */
+
+struct dirdata
+{
+ char const **names; /* Sorted names of files in dir, 0-terminated. */
+ char *data; /* Allocated storage for file names. */
+};
+
+static int compare_names PARAMS((void const *, void const *));
+static int dir_sort PARAMS((struct file_data const *, struct dirdata *));
+
+#ifdef _WIN32
+#define CLOSEDIR_VOID 1
+#endif
+
+static int
+dir_sort (dir, dirdata)
+ struct file_data const *dir;
+ struct dirdata *dirdata;
+{
+ register struct dirent *next;
+ register int i;
+
+ /* Address of block containing the files that are described. */
+ char const **names;
+
+ /* Number of files in directory. */
+ size_t nnames;
+
+ /* Allocated and used storage for file name data. */
+ char *data;
+ size_t data_alloc, data_used;
+
+ dirdata->names = 0;
+ dirdata->data = 0;
+ nnames = 0;
+ data = 0;
+
+ if (dir->desc != -1)
+ {
+ /* Open the directory and check for errors. */
+ register DIR *reading = CVS_OPENDIR (dir->name);
+ if (!reading)
+ return -1;
+
+ /* Initialize the table of filenames. */
+
+ data_alloc = max (1, (size_t) dir->stat.st_size);
+ data_used = 0;
+ dirdata->data = data = xmalloc (data_alloc);
+
+ /* Read the directory entries, and insert the subfiles
+ into the `data' table. */
+
+ while ((errno = 0, (next = CVS_READDIR (reading)) != 0))
+ {
+ char *d_name = next->d_name;
+ size_t d_size = NAMLEN (next) + 1;
+
+ /* Ignore the files `.' and `..' */
+ if (d_name[0] == '.'
+ && (d_name[1] == 0 || (d_name[1] == '.' && d_name[2] == 0)))
+ continue;
+
+ if (excluded_filename (d_name))
+ continue;
+
+ while (data_alloc < data_used + d_size)
+ dirdata->data = data = xrealloc (data, data_alloc *= 2);
+ memcpy (data + data_used, d_name, d_size);
+ data_used += d_size;
+ nnames++;
+ }
+ if (errno)
+ {
+ int e = errno;
+ CVS_CLOSEDIR (reading);
+ errno = e;
+ return -1;
+ }
+#if CLOSEDIR_VOID
+ CVS_CLOSEDIR (reading);
+#else
+ if (CVS_CLOSEDIR (reading) != 0)
+ return -1;
+#endif
+ }
+
+ /* Create the `names' table from the `data' table. */
+ dirdata->names = names = (char const **) xmalloc (sizeof (char *)
+ * (nnames + 1));
+ for (i = 0; i < nnames; i++)
+ {
+ names[i] = data;
+ data += strlen (data) + 1;
+ }
+ names[nnames] = 0;
+
+ /* Sort the table. */
+ qsort (names, nnames, sizeof (char *), compare_names);
+
+ return 0;
+}
+
+/* Sort the files now in the table. */
+
+static int
+compare_names (file1, file2)
+ void const *file1, *file2;
+{
+ return filename_cmp (* (char const *const *) file1,
+ * (char const *const *) file2);
+}
+
+/* Compare the contents of two directories named in FILEVEC[0] and FILEVEC[1].
+ This is a top-level routine; it does everything necessary for diff
+ on two directories.
+
+ FILEVEC[0].desc == -1 says directory FILEVEC[0] doesn't exist,
+ but pretend it is empty. Likewise for FILEVEC[1].
+
+ HANDLE_FILE is a caller-provided subroutine called to handle each file.
+ It gets five operands: dir and name (rel to original working dir) of file
+ in dir 0, dir and name pathname of file in dir 1, and the recursion depth.
+
+ For a file that appears in only one of the dirs, one of the name-args
+ to HANDLE_FILE is zero.
+
+ DEPTH is the current depth in recursion, used for skipping top-level
+ files by the -S option.
+
+ Returns the maximum of all the values returned by HANDLE_FILE,
+ or 2 if trouble is encountered in opening files. */
+
+int
+diff_dirs (filevec, handle_file, depth)
+ struct file_data const filevec[];
+ int (*handle_file) PARAMS((char const *, char const *, char const *, char const *, int));
+ int depth;
+{
+ struct dirdata dirdata[2];
+ int val = 0; /* Return value. */
+ int i;
+
+ /* Get sorted contents of both dirs. */
+ for (i = 0; i < 2; i++)
+ if (dir_sort (&filevec[i], &dirdata[i]) != 0)
+ {
+ perror_with_name (filevec[i].name);
+ val = 2;
+ }
+
+ if (val == 0)
+ {
+ register char const * const *names0 = dirdata[0].names;
+ register char const * const *names1 = dirdata[1].names;
+ char const *name0 = filevec[0].name;
+ char const *name1 = filevec[1].name;
+
+ /* If `-S name' was given, and this is the topmost level of comparison,
+ ignore all file names less than the specified starting name. */
+
+ if (dir_start_file && depth == 0)
+ {
+ while (*names0 && filename_cmp (*names0, dir_start_file) < 0)
+ names0++;
+ while (*names1 && filename_cmp (*names1, dir_start_file) < 0)
+ names1++;
+ }
+
+ /* Loop while files remain in one or both dirs. */
+ while (*names0 || *names1)
+ {
+ /* Compare next name in dir 0 with next name in dir 1.
+ At the end of a dir,
+ pretend the "next name" in that dir is very large. */
+ int nameorder = (!*names0 ? 1 : !*names1 ? -1
+ : filename_cmp (*names0, *names1));
+ int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *names0++,
+ name1, nameorder < 0 ? 0 : *names1++,
+ depth + 1);
+ if (v1 > val)
+ val = v1;
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ if (dirdata[i].names)
+ free (dirdata[i].names);
+ if (dirdata[i].data)
+ free (dirdata[i].data);
+ }
+
+ return val;
+}
diff --git a/diff/ed.c b/diff/ed.c
new file mode 100644
index 0000000..74fc2a4
--- /dev/null
+++ b/diff/ed.c
@@ -0,0 +1,198 @@
+/* Output routines for ed-script format.
+ Copyright (C) 1988, 89, 91, 92, 93, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+#include "diff.h"
+
+static void print_ed_hunk PARAMS((struct change *));
+static void print_rcs_hunk PARAMS((struct change *));
+static void pr_forward_ed_hunk PARAMS((struct change *));
+
+/* Print our script as ed commands. */
+
+void
+print_ed_script (script)
+ struct change *script;
+{
+ print_script (script, find_reverse_change, print_ed_hunk);
+}
+
+/* Print a hunk of an ed diff */
+
+static void
+print_ed_hunk (hunk)
+ struct change *hunk;
+{
+ int f0, l0, f1, l1;
+ int deletes, inserts;
+
+#if 0
+ hunk = flip_script (hunk);
+#endif
+#ifdef DEBUG
+ debug_script (hunk);
+#endif
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ /* Print out the line number header for this hunk */
+ print_number_range (',', &files[0], f0, l0);
+ printf_output ("%c\n", change_letter (inserts, deletes));
+
+ /* Print new/changed lines from second file, if needed */
+ if (inserts)
+ {
+ int i;
+ int inserting = 1;
+ for (i = f1; i <= l1; i++)
+ {
+ /* Resume the insert, if we stopped. */
+ if (! inserting)
+ printf_output ("%da\n",
+ i - f1 + translate_line_number (&files[0], f0) - 1);
+ inserting = 1;
+
+ /* If the file's line is just a dot, it would confuse `ed'.
+ So output it with a double dot, and set the flag LEADING_DOT
+ so that we will output another ed-command later
+ to change the double dot into a single dot. */
+
+ if (files[1].linbuf[i][0] == '.'
+ && files[1].linbuf[i][1] == '\n')
+ {
+ printf_output ("..\n");
+ printf_output (".\n");
+ /* Now change that double dot to the desired single dot. */
+ printf_output ("%ds/^\\.\\././\n",
+ i - f1 + translate_line_number (&files[0], f0));
+ inserting = 0;
+ }
+ else
+ /* Line is not `.', so output it unmodified. */
+ print_1_line ("", &files[1].linbuf[i]);
+ }
+
+ /* End insert mode, if we are still in it. */
+ if (inserting)
+ printf_output (".\n");
+ }
+}
+
+/* Print change script in the style of ed commands,
+ but print the changes in the order they appear in the input files,
+ which means that the commands are not truly useful with ed. */
+
+void
+pr_forward_ed_script (script)
+ struct change *script;
+{
+ print_script (script, find_change, pr_forward_ed_hunk);
+}
+
+static void
+pr_forward_ed_hunk (hunk)
+ struct change *hunk;
+{
+ int i;
+ int f0, l0, f1, l1;
+ int deletes, inserts;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ printf_output ("%c", change_letter (inserts, deletes));
+ print_number_range (' ', files, f0, l0);
+ printf_output ("\n");
+
+ /* If deletion only, print just the number range. */
+
+ if (!inserts)
+ return;
+
+ /* For insertion (with or without deletion), print the number range
+ and the lines from file 2. */
+
+ for (i = f1; i <= l1; i++)
+ print_1_line ("", &files[1].linbuf[i]);
+
+ printf_output (".\n");
+}
+
+/* Print in a format somewhat like ed commands
+ except that each insert command states the number of lines it inserts.
+ This format is used for RCS. */
+
+void
+print_rcs_script (script)
+ struct change *script;
+{
+ print_script (script, find_change, print_rcs_hunk);
+}
+
+/* Print a hunk of an RCS diff */
+
+static void
+print_rcs_hunk (hunk)
+ struct change *hunk;
+{
+ int i;
+ int f0, l0, f1, l1;
+ int deletes, inserts;
+ int tf0, tl0, tf1, tl1;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ translate_range (&files[0], f0, l0, &tf0, &tl0);
+
+ if (deletes)
+ {
+ printf_output ("d");
+ /* For deletion, print just the starting line number from file 0
+ and the number of lines deleted. */
+ printf_output ("%d %d\n",
+ tf0,
+ (tl0 >= tf0 ? tl0 - tf0 + 1 : 1));
+ }
+
+ if (inserts)
+ {
+ printf_output ("a");
+
+ /* Take last-line-number from file 0 and # lines from file 1. */
+ translate_range (&files[1], f1, l1, &tf1, &tl1);
+ printf_output ("%d %d\n",
+ tl0,
+ (tl1 >= tf1 ? tl1 - tf1 + 1 : 1));
+
+ /* Print the inserted lines. */
+ for (i = f1; i <= l1; i++)
+ print_1_line ("", &files[1].linbuf[i]);
+ }
+}
diff --git a/diff/ifdef.c b/diff/ifdef.c
new file mode 100644
index 0000000..94fcfb5
--- /dev/null
+++ b/diff/ifdef.c
@@ -0,0 +1,436 @@
+/* #ifdef-format output routines for GNU DIFF.
+ Copyright (C) 1989, 1991, 1992, 1993, 1994, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY. No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing. Refer to the GNU DIFF General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU DIFF, but only under the conditions described in the
+GNU DIFF General Public License. A copy of this license is
+supposed to have been given to you along with GNU DIFF so you
+can know your rights and responsibilities. It should be in a
+file named COPYING. Among other things, the copyright notice
+and this notice must be preserved on all copies. */
+
+
+#include "diff.h"
+
+struct group
+{
+ struct file_data const *file;
+ int from, upto; /* start and limit lines for this group of lines */
+};
+
+static char *format_group PARAMS((int, char *, int, struct group const *));
+static char *scan_char_literal PARAMS((char *, int *));
+static char *scan_printf_spec PARAMS((char *));
+static int groups_letter_value PARAMS((struct group const *, int));
+static void format_ifdef PARAMS((char *, int, int, int, int));
+static void print_ifdef_hunk PARAMS((struct change *));
+static void print_ifdef_lines PARAMS((int, char *, struct group const *));
+
+static int next_line;
+
+/* Print the edit-script SCRIPT as a merged #ifdef file. */
+
+void
+print_ifdef_script (script)
+ struct change *script;
+{
+ next_line = - files[0].prefix_lines;
+ print_script (script, find_change, print_ifdef_hunk);
+ if (next_line < files[0].valid_lines)
+ {
+ begin_output ();
+ format_ifdef (group_format[UNCHANGED], next_line, files[0].valid_lines,
+ next_line - files[0].valid_lines + files[1].valid_lines,
+ files[1].valid_lines);
+ }
+}
+
+/* Print a hunk of an ifdef diff.
+ This is a contiguous portion of a complete edit script,
+ describing changes in consecutive lines. */
+
+static void
+print_ifdef_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, deletes, inserts;
+ char *format;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ if (inserts)
+ format = deletes ? group_format[CHANGED] : group_format[NEW];
+ else if (deletes)
+ format = group_format[OLD];
+ else
+ return;
+
+ begin_output ();
+
+ /* Print lines up to this change. */
+ if (next_line < first0)
+ format_ifdef (group_format[UNCHANGED], next_line, first0,
+ next_line - first0 + first1, first1);
+
+ /* Print this change. */
+ next_line = last0 + 1;
+ format_ifdef (format, first0, next_line, first1, last1 + 1);
+}
+
+/* Print a set of lines according to FORMAT.
+ Lines BEG0 up to END0 are from the first file;
+ lines BEG1 up to END1 are from the second file. */
+
+static void
+format_ifdef (format, beg0, end0, beg1, end1)
+ char *format;
+ int beg0, end0, beg1, end1;
+{
+ struct group groups[2];
+
+ groups[0].file = &files[0];
+ groups[0].from = beg0;
+ groups[0].upto = end0;
+ groups[1].file = &files[1];
+ groups[1].from = beg1;
+ groups[1].upto = end1;
+ format_group (1, format, '\0', groups);
+}
+
+/* If DOIT is non-zero, output a set of lines according to FORMAT.
+ The format ends at the first free instance of ENDCHAR.
+ Yield the address of the terminating character.
+ GROUPS specifies which lines to print.
+ If OUT is zero, do not actually print anything; just scan the format. */
+
+static char *
+format_group (doit, format, endchar, groups)
+ int doit;
+ char *format;
+ int endchar;
+ struct group const *groups;
+{
+ register char c;
+ register char *f = format;
+
+ while ((c = *f) != endchar && c != 0)
+ {
+ f++;
+ if (c == '%')
+ {
+ char *spec = f;
+ switch ((c = *f++))
+ {
+ case '%':
+ break;
+
+ case '(':
+ /* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */
+ {
+ int i, value[2];
+ int thendoit, elsedoit;
+
+ for (i = 0; i < 2; i++)
+ {
+ unsigned char f0 = f[0];
+ if (ISDIGIT (f0))
+ {
+ value[i] = atoi (f);
+ while (ISDIGIT ((unsigned char) *++f))
+ continue;
+ }
+ else
+ {
+ value[i] = groups_letter_value (groups, f0);
+ if (value[i] < 0)
+ goto bad_format;
+ f++;
+ }
+ if (*f++ != "=?"[i])
+ goto bad_format;
+ }
+ if (value[0] == value[1])
+ thendoit = doit, elsedoit = 0;
+ else
+ thendoit = 0, elsedoit = doit;
+ f = format_group (thendoit, f, ':', groups);
+ if (*f)
+ {
+ f = format_group (elsedoit, f + 1, ')', groups);
+ if (*f)
+ f++;
+ }
+ }
+ continue;
+
+ case '<':
+ /* Print lines deleted from first file. */
+ print_ifdef_lines (doit, line_format[OLD], &groups[0]);
+ continue;
+
+ case '=':
+ /* Print common lines. */
+ print_ifdef_lines (doit, line_format[UNCHANGED], &groups[0]);
+ continue;
+
+ case '>':
+ /* Print lines inserted from second file. */
+ print_ifdef_lines (doit, line_format[NEW], &groups[1]);
+ continue;
+
+ default:
+ {
+ int value;
+ char *speclim;
+
+ f = scan_printf_spec (spec);
+ if (!f)
+ goto bad_format;
+ speclim = f;
+ c = *f++;
+ switch (c)
+ {
+ case '\'':
+ f = scan_char_literal (f, &value);
+ if (!f)
+ goto bad_format;
+ break;
+
+ default:
+ value = groups_letter_value (groups, c);
+ if (value < 0)
+ goto bad_format;
+ break;
+ }
+ if (doit)
+ {
+ /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
+ *speclim = 0;
+ printf_output (spec - 1, value);
+ /* Undo the temporary replacement. */
+ *speclim = c;
+ }
+ }
+ continue;
+
+ bad_format:
+ c = '%';
+ f = spec;
+ break;
+ }
+ }
+ if (doit)
+ {
+ /* Don't take the address of a register variable. */
+ char cc = c;
+ write_output (&cc, 1);
+ }
+ }
+ return f;
+}
+
+/* For the line group pair G, return the number corresponding to LETTER.
+ Return -1 if LETTER is not a group format letter. */
+static int
+groups_letter_value (g, letter)
+ struct group const *g;
+ int letter;
+{
+ if (ISUPPER (letter))
+ {
+ g++;
+ letter = tolower (letter);
+ }
+ switch (letter)
+ {
+ case 'e': return translate_line_number (g->file, g->from) - 1;
+ case 'f': return translate_line_number (g->file, g->from);
+ case 'l': return translate_line_number (g->file, g->upto) - 1;
+ case 'm': return translate_line_number (g->file, g->upto);
+ case 'n': return g->upto - g->from;
+ default: return -1;
+ }
+}
+
+/* Output using FORMAT to print the line group GROUP.
+ But do nothing if DOIT is zero. */
+static void
+print_ifdef_lines (doit, format, group)
+ int doit;
+ char *format;
+ struct group const *group;
+{
+ struct file_data const *file = group->file;
+ char const * const *linbuf = file->linbuf;
+ int from = group->from, upto = group->upto;
+
+ if (!doit)
+ return;
+
+ /* If possible, use a single fwrite; it's faster. */
+ if (!tab_expand_flag && format[0] == '%')
+ {
+ if (format[1] == 'l' && format[2] == '\n' && !format[3])
+ {
+ write_output (linbuf[from],
+ (linbuf[upto] + (linbuf[upto][-1] != '\n')
+ - linbuf[from]));
+ return;
+ }
+ if (format[1] == 'L' && !format[2])
+ {
+ write_output (linbuf[from],
+ linbuf[upto] - linbuf[from]);
+ return;
+ }
+ }
+
+ for (; from < upto; from++)
+ {
+ register char c;
+ register char *f = format;
+ char cc;
+
+ while ((c = *f++) != 0)
+ {
+ if (c == '%')
+ {
+ char *spec = f;
+ switch ((c = *f++))
+ {
+ case '%':
+ break;
+
+ case 'l':
+ output_1_line (linbuf[from],
+ linbuf[from + 1]
+ - (linbuf[from + 1][-1] == '\n'), 0, 0);
+ continue;
+
+ case 'L':
+ output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
+ continue;
+
+ default:
+ {
+ int value;
+ char *speclim;
+
+ f = scan_printf_spec (spec);
+ if (!f)
+ goto bad_format;
+ speclim = f;
+ c = *f++;
+ switch (c)
+ {
+ case '\'':
+ f = scan_char_literal (f, &value);
+ if (!f)
+ goto bad_format;
+ break;
+
+ case 'n':
+ value = translate_line_number (file, from);
+ break;
+
+ default:
+ goto bad_format;
+ }
+ /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
+ *speclim = 0;
+ printf_output (spec - 1, value);
+ /* Undo the temporary replacement. */
+ *speclim = c;
+ }
+ continue;
+
+ bad_format:
+ c = '%';
+ f = spec;
+ break;
+ }
+ }
+
+ /* Don't take the address of a register variable. */
+ cc = c;
+ write_output (&cc, 1);
+ }
+ }
+}
+
+/* Scan the character literal represented in the string LIT; LIT points just
+ after the initial apostrophe. Put the literal's value into *INTPTR.
+ Yield the address of the first character after the closing apostrophe,
+ or zero if the literal is ill-formed. */
+static char *
+scan_char_literal (lit, intptr)
+ char *lit;
+ int *intptr;
+{
+ register char *p = lit;
+ int value, digits;
+ char c = *p++;
+
+ switch (c)
+ {
+ case 0:
+ case '\'':
+ return 0;
+
+ case '\\':
+ value = 0;
+ while ((c = *p++) != '\'')
+ {
+ unsigned digit = c - '0';
+ if (8 <= digit)
+ return 0;
+ value = 8 * value + digit;
+ }
+ digits = p - lit - 2;
+ if (! (1 <= digits && digits <= 3))
+ return 0;
+ break;
+
+ default:
+ value = c;
+ if (*p++ != '\'')
+ return 0;
+ break;
+ }
+ *intptr = value;
+ return p;
+}
+
+/* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'.
+ Return the address of the character following SPEC, or zero if failure. */
+static char *
+scan_printf_spec (spec)
+ register char *spec;
+{
+ register unsigned char c;
+
+ while ((c = *spec++) == '-')
+ continue;
+ while (ISDIGIT (c))
+ c = *spec++;
+ if (c == '.')
+ while (ISDIGIT (c = *spec++))
+ continue;
+ switch (c)
+ {
+ case 'c': case 'd': case 'o': case 'x': case 'X':
+ return spec;
+
+ default:
+ return 0;
+ }
+}
diff --git a/diff/io.c b/diff/io.c
new file mode 100644
index 0000000..31581cd
--- /dev/null
+++ b/diff/io.c
@@ -0,0 +1,711 @@
+/* File I/O for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+#include "diff.h"
+
+/* Rotate a value n bits to the left. */
+#define UINT_BIT (sizeof (unsigned) * CHAR_BIT)
+#define ROL(v, n) ((v) << (n) | (v) >> (UINT_BIT - (n)))
+
+/* Given a hash value and a new character, return a new hash value. */
+#define HASH(h, c) ((c) + ROL (h, 7))
+
+/* Guess remaining number of lines from number N of lines so far,
+ size S so far, and total size T. */
+#define GUESS_LINES(n,s,t) (((t) - (s)) / ((n) < 10 ? 32 : (s) / ((n)-1)) + 5)
+
+/* Type used for fast prefix comparison in find_identical_ends. */
+#ifndef word
+#define word int
+#endif
+
+/* Lines are put into equivalence classes (of lines that match in line_cmp).
+ Each equivalence class is represented by one of these structures,
+ but only while the classes are being computed.
+ Afterward, each class is represented by a number. */
+struct equivclass
+{
+ int next; /* Next item in this bucket. */
+ unsigned hash; /* Hash of lines in this class. */
+ char const *line; /* A line that fits this class. */
+ size_t length; /* That line's length, not counting its newline. */
+};
+
+/* Hash-table: array of buckets, each being a chain of equivalence classes.
+ buckets[-1] is reserved for incomplete lines. */
+static int *buckets;
+
+/* Number of buckets in the hash table array, not counting buckets[-1]. */
+static int nbuckets;
+
+/* Array in which the equivalence classes are allocated.
+ The bucket-chains go through the elements in this array.
+ The number of an equivalence class is its index in this array. */
+static struct equivclass *equivs;
+
+/* Index of first free element in the array `equivs'. */
+static int equivs_index;
+
+/* Number of elements allocated in the array `equivs'. */
+static int equivs_alloc;
+
+static void find_and_hash_each_line PARAMS((struct file_data *));
+static void find_identical_ends PARAMS((struct file_data[]));
+static void prepare_text_end PARAMS((struct file_data *));
+
+/* Check for binary files and compare them for exact identity. */
+
+/* Return 1 if BUF contains a non text character.
+ SIZE is the number of characters in BUF. */
+
+#define binary_file_p(buf, size) (memchr (buf, '\0', size) != 0)
+
+/* Get ready to read the current file.
+ Return nonzero if SKIP_TEST is zero,
+ and if it appears to be a binary file. */
+
+int
+sip (current, skip_test)
+ struct file_data *current;
+ int skip_test;
+{
+ /* If we have a nonexistent file at this stage, treat it as empty. */
+ if (current->desc < 0)
+ {
+ /* Leave room for a sentinel. */
+ current->bufsize = sizeof (word);
+ current->buffer = xmalloc (current->bufsize);
+ }
+ else
+ {
+ current->bufsize = STAT_BLOCKSIZE (current->stat);
+ current->buffer = xmalloc (current->bufsize);
+
+ if (! skip_test)
+ {
+ /* Check first part of file to see if it's a binary file. */
+#if HAVE_SETMODE
+ int oldmode = setmode (current->desc, O_BINARY);
+#endif
+ ssize_t n = read (current->desc, current->buffer, current->bufsize);
+ if (n == -1)
+ pfatal_with_name (current->name);
+ current->buffered_chars = n;
+#if HAVE_SETMODE
+ if (oldmode != O_BINARY)
+ {
+ if (lseek (current->desc, - (off_t) n, SEEK_CUR) == -1)
+ pfatal_with_name (current->name);
+ setmode (current->desc, oldmode);
+ current->buffered_chars = 0;
+ }
+#endif
+ return binary_file_p (current->buffer, n);
+ }
+ }
+
+ current->buffered_chars = 0;
+ return 0;
+}
+
+/* Slurp the rest of the current file completely into memory. */
+
+void
+slurp (current)
+ struct file_data *current;
+{
+ ssize_t cc;
+
+ if (current->desc < 0)
+ /* The file is nonexistent. */
+ ;
+ else if (S_ISREG (current->stat.st_mode))
+ {
+ /* It's a regular file; slurp in the rest all at once. */
+
+ /* Get the size out of the stat block.
+ Allocate enough room for appended newline and sentinel. */
+ cc = current->stat.st_size + 1 + sizeof (word);
+ if (current->bufsize < cc)
+ {
+ current->bufsize = cc;
+ current->buffer = xrealloc (current->buffer, cc);
+ }
+
+ if (current->buffered_chars < current->stat.st_size)
+ {
+ cc = read (current->desc,
+ current->buffer + current->buffered_chars,
+ current->stat.st_size - current->buffered_chars);
+ if (cc == -1)
+ pfatal_with_name (current->name);
+ current->buffered_chars += cc;
+ }
+ }
+ /* It's not a regular file; read it, growing the buffer as needed. */
+ else if (always_text_flag || current->buffered_chars != 0)
+ {
+ for (;;)
+ {
+ if (current->buffered_chars == current->bufsize)
+ {
+ current->bufsize = current->bufsize * 2;
+ current->buffer = xrealloc (current->buffer, current->bufsize);
+ }
+ cc = read (current->desc,
+ current->buffer + current->buffered_chars,
+ current->bufsize - current->buffered_chars);
+ if (cc == 0)
+ break;
+ if (cc == -1)
+ pfatal_with_name (current->name);
+ current->buffered_chars += cc;
+ }
+ /* Allocate just enough room for appended newline and sentinel. */
+ current->bufsize = current->buffered_chars + 1 + sizeof (word);
+ current->buffer = xrealloc (current->buffer, current->bufsize);
+ }
+}
+
+/* Split the file into lines, simultaneously computing the equivalence class for
+ each line. */
+
+static void
+find_and_hash_each_line (current)
+ struct file_data *current;
+{
+ unsigned h;
+ unsigned char const *p = (unsigned char const *) current->prefix_end;
+ unsigned char c;
+ int i, *bucket;
+ size_t length;
+
+ /* Cache often-used quantities in local variables to help the compiler. */
+ char const **linbuf = current->linbuf;
+ int alloc_lines = current->alloc_lines;
+ int line = 0;
+ int linbuf_base = current->linbuf_base;
+ int *cureqs = (int *) xmalloc (alloc_lines * sizeof (int));
+ struct equivclass *eqs = equivs;
+ int eqs_index = equivs_index;
+ int eqs_alloc = equivs_alloc;
+ char const *suffix_begin = current->suffix_begin;
+ char const *bufend = current->buffer + current->buffered_chars;
+ int use_line_cmp = ignore_some_line_changes;
+
+ while ((char const *) p < suffix_begin)
+ {
+ char const *ip = (char const *) p;
+
+ /* Compute the equivalence class for this line. */
+
+ h = 0;
+
+ /* Hash this line until we find a newline. */
+ if (ignore_case_flag)
+ {
+ if (ignore_all_space_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (! ISSPACE (c))
+ h = HASH (h, ISUPPER (c) ? tolower (c) : c);
+ }
+ else if (ignore_space_change_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (ISSPACE (c))
+ {
+ for (;;)
+ {
+ c = *p++;
+ if (!ISSPACE (c))
+ break;
+ if (c == '\n')
+ goto hashing_done;
+ }
+ h = HASH (h, ' ');
+ }
+ /* C is now the first non-space. */
+ h = HASH (h, ISUPPER (c) ? tolower (c) : c);
+ }
+ else
+ while ((c = *p++) != '\n')
+ h = HASH (h, ISUPPER (c) ? tolower (c) : c);
+ }
+ else
+ {
+ if (ignore_all_space_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (! ISSPACE (c))
+ h = HASH (h, c);
+ }
+ else if (ignore_space_change_flag)
+ while ((c = *p++) != '\n')
+ {
+ if (ISSPACE (c))
+ {
+ for (;;)
+ {
+ c = *p++;
+ if (!ISSPACE (c))
+ break;
+ if (c == '\n')
+ goto hashing_done;
+ }
+ h = HASH (h, ' ');
+ }
+ /* C is now the first non-space. */
+ h = HASH (h, c);
+ }
+ else
+ while ((c = *p++) != '\n')
+ h = HASH (h, c);
+ }
+ hashing_done:;
+
+ bucket = &buckets[h % nbuckets];
+ length = (char const *) p - ip - 1;
+
+ if ((char const *) p == bufend
+ && current->missing_newline
+ && ROBUST_OUTPUT_STYLE (output_style))
+ {
+ /* This line is incomplete. If this is significant,
+ put the line into bucket[-1]. */
+ if (! (ignore_space_change_flag | ignore_all_space_flag))
+ bucket = &buckets[-1];
+
+ /* Omit the inserted newline when computing linbuf later. */
+ p--;
+ bufend = suffix_begin = (char const *) p;
+ }
+
+ for (i = *bucket; ; i = eqs[i].next)
+ if (!i)
+ {
+ /* Create a new equivalence class in this bucket. */
+ i = eqs_index++;
+ if (i == eqs_alloc)
+ eqs = (struct equivclass *)
+ xrealloc (eqs, (eqs_alloc*=2) * sizeof(*eqs));
+ eqs[i].next = *bucket;
+ eqs[i].hash = h;
+ eqs[i].line = ip;
+ eqs[i].length = length;
+ *bucket = i;
+ break;
+ }
+ else if (eqs[i].hash == h)
+ {
+ char const *eqline = eqs[i].line;
+
+ /* Reuse existing equivalence class if the lines are identical.
+ This detects the common case of exact identity
+ faster than complete comparison would. */
+ if (eqs[i].length == length && memcmp (eqline, ip, length) == 0)
+ break;
+
+ /* Reuse existing class if line_cmp reports the lines equal. */
+ if (use_line_cmp && line_cmp (eqline, ip) == 0)
+ break;
+ }
+
+ /* Maybe increase the size of the line table. */
+ if (line == alloc_lines)
+ {
+ /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
+ alloc_lines = 2 * alloc_lines - linbuf_base;
+ cureqs = (int *) xrealloc (cureqs, alloc_lines * sizeof (*cureqs));
+ linbuf = (char const **) xrealloc (linbuf + linbuf_base,
+ (alloc_lines - linbuf_base)
+ * sizeof (*linbuf))
+ - linbuf_base;
+ }
+ linbuf[line] = ip;
+ cureqs[line] = i;
+ ++line;
+ }
+
+ current->buffered_lines = line;
+
+ for (i = 0; ; i++)
+ {
+ /* Record the line start for lines in the suffix that we care about.
+ Record one more line start than lines,
+ so that we can compute the length of any buffered line. */
+ if (line == alloc_lines)
+ {
+ /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
+ alloc_lines = 2 * alloc_lines - linbuf_base;
+ linbuf = (char const **) xrealloc (linbuf + linbuf_base,
+ (alloc_lines - linbuf_base)
+ * sizeof (*linbuf))
+ - linbuf_base;
+ }
+ linbuf[line] = (char const *) p;
+
+ if ((char const *) p == bufend)
+ break;
+
+ if (context <= i && no_diff_means_no_output)
+ break;
+
+ line++;
+
+ while (*p++ != '\n')
+ ;
+ }
+
+ /* Done with cache in local variables. */
+ current->linbuf = linbuf;
+ current->valid_lines = line;
+ current->alloc_lines = alloc_lines;
+ current->equivs = cureqs;
+ equivs = eqs;
+ equivs_alloc = eqs_alloc;
+ equivs_index = eqs_index;
+}
+
+/* Prepare the end of the text. Make sure it's initialized.
+ Make sure text ends in a newline,
+ but remember that we had to add one. */
+
+static void
+prepare_text_end (current)
+ struct file_data *current;
+{
+ size_t buffered_chars = current->buffered_chars;
+ char *p = current->buffer;
+
+ if (buffered_chars == 0 || p[buffered_chars - 1] == '\n')
+ current->missing_newline = 0;
+ else
+ {
+ p[buffered_chars++] = '\n';
+ current->buffered_chars = buffered_chars;
+ current->missing_newline = 1;
+ }
+
+ /* Don't use uninitialized storage when planting or using sentinels. */
+ if (p)
+ bzero (p + buffered_chars, sizeof (word));
+}
+
+/* Given a vector of two file_data objects, find the identical
+ prefixes and suffixes of each object. */
+
+static void
+find_identical_ends (filevec)
+ struct file_data filevec[];
+{
+ word *w0, *w1;
+ char *p0, *p1, *buffer0, *buffer1;
+ char const *end0, *beg0;
+ char const **linbuf0, **linbuf1;
+ int i, lines;
+ size_t n0, n1, tem;
+ int alloc_lines0, alloc_lines1;
+ int buffered_prefix, prefix_count, prefix_mask;
+
+ slurp (&filevec[0]);
+ if (filevec[0].desc != filevec[1].desc)
+ slurp (&filevec[1]);
+ else
+ {
+ filevec[1].buffer = filevec[0].buffer;
+ filevec[1].bufsize = filevec[0].bufsize;
+ filevec[1].buffered_chars = filevec[0].buffered_chars;
+ }
+ for (i = 0; i < 2; i++)
+ prepare_text_end (&filevec[i]);
+
+ /* Find identical prefix. */
+
+ p0 = buffer0 = filevec[0].buffer;
+ p1 = buffer1 = filevec[1].buffer;
+
+ n0 = filevec[0].buffered_chars;
+ n1 = filevec[1].buffered_chars;
+
+ if (p0 == p1)
+ /* The buffers are the same; sentinels won't work. */
+ p0 = p1 += n1;
+ else
+ {
+ /* Insert end sentinels, in this case characters that are guaranteed
+ to make the equality test false, and thus terminate the loop. */
+
+ if (n0 < n1)
+ p0[n0] = ~p1[n0];
+ else
+ p1[n1] = ~p0[n1];
+
+ /* Loop until first mismatch, or to the sentinel characters. */
+
+ /* Compare a word at a time for speed. */
+ w0 = (word *) p0;
+ w1 = (word *) p1;
+ while (*w0++ == *w1++)
+ ;
+ --w0, --w1;
+
+ /* Do the last few bytes of comparison a byte at a time. */
+ p0 = (char *) w0;
+ p1 = (char *) w1;
+ while (*p0++ == *p1++)
+ ;
+ --p0, --p1;
+
+ /* Don't mistakenly count missing newline as part of prefix. */
+ if (ROBUST_OUTPUT_STYLE (output_style)
+ && (buffer0 + n0 - filevec[0].missing_newline < p0)
+ !=
+ (buffer1 + n1 - filevec[1].missing_newline < p1))
+ --p0, --p1;
+ }
+
+ /* Now P0 and P1 point at the first nonmatching characters. */
+
+ /* Skip back to last line-beginning in the prefix,
+ and then discard up to HORIZON_LINES lines from the prefix. */
+ i = horizon_lines;
+ while (p0 != buffer0 && (p0[-1] != '\n' || i--))
+ --p0, --p1;
+
+ /* Record the prefix. */
+ filevec[0].prefix_end = p0;
+ filevec[1].prefix_end = p1;
+
+ /* Find identical suffix. */
+
+ /* P0 and P1 point beyond the last chars not yet compared. */
+ p0 = buffer0 + n0;
+ p1 = buffer1 + n1;
+
+ if (! ROBUST_OUTPUT_STYLE (output_style)
+ || filevec[0].missing_newline == filevec[1].missing_newline)
+ {
+ end0 = p0; /* Addr of last char in file 0. */
+
+ /* Get value of P0 at which we should stop scanning backward:
+ this is when either P0 or P1 points just past the last char
+ of the identical prefix. */
+ beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1);
+
+ /* Scan back until chars don't match or we reach that point. */
+ for (; p0 != beg0; p0--, p1--)
+ if (*p0 != *p1)
+ {
+ /* Point at the first char of the matching suffix. */
+ beg0 = p0;
+ break;
+ }
+
+ /* Are we at a line-beginning in both files? If not, add the rest of
+ this line to the main body. Discard up to HORIZON_LINES lines from
+ the identical suffix. Also, discard one extra line,
+ because shift_boundaries may need it. */
+ i = horizon_lines + !((buffer0 == p0 || p0[-1] == '\n')
+ &&
+ (buffer1 == p1 || p1[-1] == '\n'));
+ while (i-- && p0 != end0)
+ while (*p0++ != '\n')
+ ;
+
+ p1 += p0 - beg0;
+ }
+
+ /* Record the suffix. */
+ filevec[0].suffix_begin = p0;
+ filevec[1].suffix_begin = p1;
+
+ /* Calculate number of lines of prefix to save.
+
+ prefix_count == 0 means save the whole prefix;
+ we need this with for options like -D that output the whole file.
+ We also need it for options like -F that output some preceding line;
+ at least we will need to find the last few lines,
+ but since we don't know how many, it's easiest to find them all.
+
+ Otherwise, prefix_count != 0. Save just prefix_count lines at start
+ of the line buffer; they'll be moved to the proper location later.
+ Handle 1 more line than the context says (because we count 1 too many),
+ rounded up to the next power of 2 to speed index computation. */
+
+ if (no_diff_means_no_output && ! function_regexp_list)
+ {
+ for (prefix_count = 1; prefix_count < context + 1; prefix_count *= 2)
+ ;
+ prefix_mask = prefix_count - 1;
+ alloc_lines0
+ = prefix_count
+ + GUESS_LINES (0, 0, p0 - filevec[0].prefix_end)
+ + context;
+ }
+ else
+ {
+ prefix_count = 0;
+ prefix_mask = ~0;
+ alloc_lines0 = GUESS_LINES (0, 0, n0);
+ }
+
+ lines = 0;
+ linbuf0 = (char const **) xmalloc (alloc_lines0 * sizeof (*linbuf0));
+
+ /* If the prefix is needed, find the prefix lines. */
+ if (! (no_diff_means_no_output
+ && filevec[0].prefix_end == p0
+ && filevec[1].prefix_end == p1))
+ {
+ p0 = buffer0;
+ end0 = filevec[0].prefix_end;
+ while (p0 != end0)
+ {
+ int l = lines++ & prefix_mask;
+ if (l == alloc_lines0)
+ linbuf0 = (char const **) xrealloc (linbuf0, (alloc_lines0 *= 2)
+ * sizeof(*linbuf0));
+ linbuf0[l] = p0;
+ while (*p0++ != '\n')
+ ;
+ }
+ }
+ buffered_prefix = prefix_count && context < lines ? context : lines;
+
+ /* Allocate line buffer 1. */
+ tem = prefix_count ? filevec[1].suffix_begin - buffer1 : n1;
+
+ alloc_lines1
+ = (buffered_prefix
+ + GUESS_LINES (lines, filevec[1].prefix_end - buffer1, tem)
+ + context);
+ linbuf1 = (char const **) xmalloc (alloc_lines1 * sizeof (*linbuf1));
+
+ if (buffered_prefix != lines)
+ {
+ /* Rotate prefix lines to proper location. */
+ for (i = 0; i < buffered_prefix; i++)
+ linbuf1[i] = linbuf0[(lines - context + i) & prefix_mask];
+ for (i = 0; i < buffered_prefix; i++)
+ linbuf0[i] = linbuf1[i];
+ }
+
+ /* Initialize line buffer 1 from line buffer 0. */
+ for (i = 0; i < buffered_prefix; i++)
+ linbuf1[i] = linbuf0[i] - buffer0 + buffer1;
+
+ /* Record the line buffer, adjusted so that
+ linbuf*[0] points at the first differing line. */
+ filevec[0].linbuf = linbuf0 + buffered_prefix;
+ filevec[1].linbuf = linbuf1 + buffered_prefix;
+ filevec[0].linbuf_base = filevec[1].linbuf_base = - buffered_prefix;
+ filevec[0].alloc_lines = alloc_lines0 - buffered_prefix;
+ filevec[1].alloc_lines = alloc_lines1 - buffered_prefix;
+ filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
+}
+
+/* Largest primes less than some power of two, for nbuckets. Values range
+ from useful to preposterous. If one of these numbers isn't prime
+ after all, don't blame it on me, blame it on primes (6) . . . */
+static int const primes[] =
+{
+ 509,
+ 1021,
+ 2039,
+ 4093,
+ 8191,
+ 16381,
+ 32749,
+#if 32767 < INT_MAX
+ 65521,
+ 131071,
+ 262139,
+ 524287,
+ 1048573,
+ 2097143,
+ 4194301,
+ 8388593,
+ 16777213,
+ 33554393,
+ 67108859, /* Preposterously large . . . */
+ 134217689,
+ 268435399,
+ 536870909,
+ 1073741789,
+ 2147483647,
+#endif
+ 0
+};
+
+/* Given a vector of two file_data objects, read the file associated
+ with each one, and build the table of equivalence classes.
+ Return 1 if either file appears to be a binary file.
+ If PRETEND_BINARY is nonzero, pretend they are binary regardless. */
+
+int
+read_files (filevec, pretend_binary)
+ struct file_data filevec[];
+ int pretend_binary;
+{
+ int i;
+ int skip_test = always_text_flag | pretend_binary;
+ int appears_binary = pretend_binary | sip (&filevec[0], skip_test);
+
+ if (filevec[0].desc != filevec[1].desc)
+ appears_binary |= sip (&filevec[1], skip_test | appears_binary);
+ else
+ {
+ filevec[1].buffer = filevec[0].buffer;
+ filevec[1].bufsize = filevec[0].bufsize;
+ filevec[1].buffered_chars = filevec[0].buffered_chars;
+ }
+ if (appears_binary)
+ {
+#if HAVE_SETMODE
+ setmode (filevec[0].desc, O_BINARY);
+ setmode (filevec[1].desc, O_BINARY);
+#endif
+ return 1;
+ }
+
+ find_identical_ends (filevec);
+
+ equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1;
+ equivs = (struct equivclass *) xmalloc (equivs_alloc * sizeof (struct equivclass));
+ /* Equivalence class 0 is permanently safe for lines that were not
+ hashed. Real equivalence classes start at 1. */
+ equivs_index = 1;
+
+ for (i = 0; primes[i] < equivs_alloc / 3; i++)
+ if (! primes[i])
+ abort ();
+ nbuckets = primes[i];
+
+ buckets = (int *) xmalloc ((nbuckets + 1) * sizeof (*buckets));
+ bzero (buckets++, (nbuckets + 1) * sizeof (*buckets));
+
+ for (i = 0; i < 2; i++)
+ find_and_hash_each_line (&filevec[i]);
+
+ filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
+
+ free (equivs);
+ free (buckets - 1);
+
+ return 0;
+}
diff --git a/diff/libdiff.dep b/diff/libdiff.dep
new file mode 100644
index 0000000..e8275af
--- /dev/null
+++ b/diff/libdiff.dep
@@ -0,0 +1,151 @@
+# Microsoft Developer Studio Generated Dependency File, included by libdiff.mak
+
+.\analyze.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\cmpbuf.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\cmpbuf.c : \
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\cmpbuf.h"\
+ ".\system.h"\
+
+
+.\context.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\diff.c : \
+ "..\lib\fnmatch.h"\
+ "..\lib\getopt.h"\
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\diff3.c : \
+ "..\lib\getopt.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\dir.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\ed.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\ifdef.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\io.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\normal.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\side.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\util.c : \
+ "..\lib\regex.h"\
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\diff.h"\
+ ".\diffrun.h"\
+ ".\system.h"\
+
+
+.\version.c : \
+ "..\lib\timespec.h"\
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+
diff --git a/diff/libdiff.dsp b/diff/libdiff.dsp
new file mode 100644
index 0000000..37e779c
--- /dev/null
+++ b/diff/libdiff.dsp
@@ -0,0 +1,192 @@
+# Microsoft Developer Studio Project File - Name="libdiff" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libdiff - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libdiff.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libdiff.mak" CFG="libdiff - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libdiff - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libdiff - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libdiff - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "WinRel"
+# PROP BASE Intermediate_Dir "WinRel"
+# PROP BASE Target_Dir ".\libdiff"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "WinRel"
+# PROP Intermediate_Dir "WinRel"
+# PROP Target_Dir ".\libdiff"
+# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\windows-NT" /I "..\lib" /D "_WINDOWS" /D "HAVE_TIME_H" /D "CLOSEDIR_VOID" /D "NDEBUG" /D "WIN32" /D "WANT_WIN_COMPILER_VERSION" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\windows-NT" /I "..\lib" /D "_WINDOWS" /D "HAVE_TIME_H" /D "CLOSEDIR_VOID" /D "NDEBUG" /D "WIN32" /D "WANT_WIN_COMPILER_VERSION" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "libdiff - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "WinDebug"
+# PROP BASE Intermediate_Dir "WinDebug"
+# PROP BASE Target_Dir ".\libdiff"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "WinDebug"
+# PROP Intermediate_Dir "WinDebug"
+# PROP Target_Dir ".\libdiff"
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /I "..\windows-NT" /I "..\lib" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "HAVE_TIME_H" /D "CLOSEDIR_VOID" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\windows-NT" /I "..\lib" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "HAVE_TIME_H" /D "CLOSEDIR_VOID" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 ..\lib\WinDebug\libcvs.lib /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "libdiff - Win32 Release"
+# Name "libdiff - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\analyze.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\cmpbuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\cmpbuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\context.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\diff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\diff3.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ed.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ifdef.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\io.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\normal.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\side.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\version.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE="..\windows-NT\config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\diff.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\diffrun.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\fnmatch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\getopt.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\ndir.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\regex.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\system.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\timespec.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\unistd.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\woe32.h"
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/diff/libdiff.mak b/diff/libdiff.mak
new file mode 100644
index 0000000..3d84d70
--- /dev/null
+++ b/diff/libdiff.mak
@@ -0,0 +1,340 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on libdiff.dsp
+!IF "$(CFG)" == ""
+CFG=libdiff - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to libdiff - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "libdiff - Win32 Release" && "$(CFG)" != "libdiff - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libdiff.mak" CFG="libdiff - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libdiff - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libdiff - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "libdiff - Win32 Release"
+
+OUTDIR=.\WinRel
+INTDIR=.\WinRel
+# Begin Custom Macros
+OutDir=.\WinRel
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\libdiff.lib"
+
+!ELSE
+
+ALL : "libcvs - Win32 Release" "$(OUTDIR)\libdiff.lib"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libcvs - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\analyze.obj"
+ -@erase "$(INTDIR)\cmpbuf.obj"
+ -@erase "$(INTDIR)\context.obj"
+ -@erase "$(INTDIR)\diff.obj"
+ -@erase "$(INTDIR)\diff3.obj"
+ -@erase "$(INTDIR)\dir.obj"
+ -@erase "$(INTDIR)\ed.obj"
+ -@erase "$(INTDIR)\ifdef.obj"
+ -@erase "$(INTDIR)\io.obj"
+ -@erase "$(INTDIR)\normal.obj"
+ -@erase "$(INTDIR)\side.obj"
+ -@erase "$(INTDIR)\util.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(OUTDIR)\libdiff.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "..\windows-NT" /I "..\lib" /D "_WINDOWS" /D "HAVE_TIME_H" /D "CLOSEDIR_VOID" /D "NDEBUG" /D "WIN32" /D "WANT_WIN_COMPILER_VERSION" /Fp"$(INTDIR)\libdiff.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libdiff.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)\libdiff.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\analyze.obj" \
+ "$(INTDIR)\cmpbuf.obj" \
+ "$(INTDIR)\context.obj" \
+ "$(INTDIR)\diff.obj" \
+ "$(INTDIR)\diff3.obj" \
+ "$(INTDIR)\dir.obj" \
+ "$(INTDIR)\ed.obj" \
+ "$(INTDIR)\ifdef.obj" \
+ "$(INTDIR)\io.obj" \
+ "$(INTDIR)\normal.obj" \
+ "$(INTDIR)\side.obj" \
+ "$(INTDIR)\util.obj" \
+ "$(INTDIR)\version.obj" \
+ "..\lib\WinRel\libcvs.lib"
+
+"$(OUTDIR)\libdiff.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "libdiff - Win32 Debug"
+
+OUTDIR=.\WinDebug
+INTDIR=.\WinDebug
+# Begin Custom Macros
+OutDir=.\WinDebug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\libdiff.lib"
+
+!ELSE
+
+ALL : "libcvs - Win32 Debug" "$(OUTDIR)\libdiff.lib"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libcvs - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\analyze.obj"
+ -@erase "$(INTDIR)\cmpbuf.obj"
+ -@erase "$(INTDIR)\context.obj"
+ -@erase "$(INTDIR)\diff.obj"
+ -@erase "$(INTDIR)\diff3.obj"
+ -@erase "$(INTDIR)\dir.obj"
+ -@erase "$(INTDIR)\ed.obj"
+ -@erase "$(INTDIR)\ifdef.obj"
+ -@erase "$(INTDIR)\io.obj"
+ -@erase "$(INTDIR)\normal.obj"
+ -@erase "$(INTDIR)\side.obj"
+ -@erase "$(INTDIR)\util.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(OUTDIR)\libdiff.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /GX /Z7 /Od /I "..\windows-NT" /I "..\lib" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "HAVE_TIME_H" /D "CLOSEDIR_VOID" /Fp"$(INTDIR)\libdiff.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libdiff.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+LIB32_FLAGS=..\lib\WinDebug\libcvs.lib /nologo /out:"$(OUTDIR)\libdiff.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\analyze.obj" \
+ "$(INTDIR)\cmpbuf.obj" \
+ "$(INTDIR)\context.obj" \
+ "$(INTDIR)\diff.obj" \
+ "$(INTDIR)\diff3.obj" \
+ "$(INTDIR)\dir.obj" \
+ "$(INTDIR)\ed.obj" \
+ "$(INTDIR)\ifdef.obj" \
+ "$(INTDIR)\io.obj" \
+ "$(INTDIR)\normal.obj" \
+ "$(INTDIR)\side.obj" \
+ "$(INTDIR)\util.obj" \
+ "$(INTDIR)\version.obj" \
+ "..\lib\WinDebug\libcvs.lib"
+
+"$(OUTDIR)\libdiff.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("libdiff.dep")
+!INCLUDE "libdiff.dep"
+!ELSE
+!MESSAGE Warning: cannot find "libdiff.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "libdiff - Win32 Release" || "$(CFG)" == "libdiff - Win32 Debug"
+SOURCE=.\analyze.c
+
+"$(INTDIR)\analyze.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\cmpbuf.c
+
+"$(INTDIR)\cmpbuf.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\context.c
+
+"$(INTDIR)\context.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\diff.c
+
+"$(INTDIR)\diff.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\diff3.c
+
+"$(INTDIR)\diff3.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\dir.c
+
+"$(INTDIR)\dir.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\ed.c
+
+"$(INTDIR)\ed.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\ifdef.c
+
+"$(INTDIR)\ifdef.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\io.c
+
+"$(INTDIR)\io.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\normal.c
+
+"$(INTDIR)\normal.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\side.c
+
+"$(INTDIR)\side.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\util.c
+
+"$(INTDIR)\util.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\version.c
+
+"$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!IF "$(CFG)" == "libdiff - Win32 Release"
+
+"libcvs - Win32 Release" :
+ cd "..\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Release"
+ cd "..\diff"
+
+"libcvs - Win32 ReleaseCLEAN" :
+ cd "..\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Release" RECURSE=1 CLEAN
+ cd "..\diff"
+
+!ELSEIF "$(CFG)" == "libdiff - Win32 Debug"
+
+"libcvs - Win32 Debug" :
+ cd "..\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Debug"
+ cd "..\diff"
+
+"libcvs - Win32 DebugCLEAN" :
+ cd "..\lib"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libcvs.mak" CFG="libcvs - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\diff"
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/diff/normal.c b/diff/normal.c
new file mode 100644
index 0000000..b1f4955
--- /dev/null
+++ b/diff/normal.c
@@ -0,0 +1,69 @@
+/* Normal-format output routines for GNU DIFF.
+ Copyright (C) 1988, 1989, 1993, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+
+#include "diff.h"
+
+static void print_normal_hunk PARAMS((struct change *));
+
+/* Print the edit-script SCRIPT as a normal diff.
+ INF points to an array of descriptions of the two files. */
+
+void
+print_normal_script (script)
+ struct change *script;
+{
+ print_script (script, find_change, print_normal_hunk);
+}
+
+/* Print a hunk of a normal diff.
+ This is a contiguous portion of a complete edit script,
+ describing changes in consecutive lines. */
+
+static void
+print_normal_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, deletes, inserts;
+ register int i;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ begin_output ();
+
+ /* Print out the line number header for this hunk */
+ print_number_range (',', &files[0], first0, last0);
+ printf_output ("%c", change_letter (inserts, deletes));
+ print_number_range (',', &files[1], first1, last1);
+ printf_output ("\n");
+
+ /* Print the lines that the first file has. */
+ if (deletes)
+ for (i = first0; i <= last0; i++)
+ print_1_line ("<", &files[0].linbuf[i]);
+
+ if (inserts && deletes)
+ printf_output ("---\n");
+
+ /* Print the lines that the second file has. */
+ if (inserts)
+ for (i = first1; i <= last1; i++)
+ print_1_line (">", &files[1].linbuf[i]);
+}
diff --git a/diff/side.c b/diff/side.c
new file mode 100644
index 0000000..d776e77
--- /dev/null
+++ b/diff/side.c
@@ -0,0 +1,294 @@
+/* sdiff-format output routines for GNU DIFF.
+ Copyright (C) 1991, 1992, 1993, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY. No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing. Refer to the GNU DIFF General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU DIFF, but only under the conditions described in the
+GNU DIFF General Public License. A copy of this license is
+supposed to have been given to you along with GNU DIFF so you
+can know your rights and responsibilities. It should be in a
+file named COPYING. Among other things, the copyright notice
+and this notice must be preserved on all copies. */
+
+
+#include "diff.h"
+
+static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned));
+static unsigned tab_from_to PARAMS((unsigned, unsigned));
+static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *));
+static void print_sdiff_common_lines PARAMS((int, int));
+static void print_sdiff_hunk PARAMS((struct change *));
+
+/* Next line number to be printed in the two input files. */
+static int next0, next1;
+
+/* Print the edit-script SCRIPT as a sdiff style output. */
+
+void
+print_sdiff_script (script)
+ struct change *script;
+{
+ begin_output ();
+
+ next0 = next1 = - files[0].prefix_lines;
+ print_script (script, find_change, print_sdiff_hunk);
+
+ print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
+}
+
+/* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */
+
+static unsigned
+tab_from_to (from, to)
+ unsigned from, to;
+{
+ unsigned tab;
+
+ if (! tab_expand_flag)
+ for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH)
+ {
+ write_output ("\t", 1);
+ from = tab;
+ }
+ while (from++ < to)
+ write_output (" ", 1);
+ return to;
+}
+
+/*
+ * Print the text for half an sdiff line. This means truncate to width
+ * observing tabs, and trim a trailing newline. Returns the last column
+ * written (not the number of chars).
+ */
+static unsigned
+print_half_line (line, indent, out_bound)
+ char const * const *line;
+ unsigned indent, out_bound;
+{
+ register unsigned in_position = 0, out_position = 0;
+ register char const
+ *text_pointer = line[0],
+ *text_limit = line[1];
+
+ while (text_pointer < text_limit)
+ {
+ register unsigned char c = *text_pointer++;
+ /* We use CC to avoid taking the address of the register
+ variable C. */
+ char cc;
+
+ switch (c)
+ {
+ case '\t':
+ {
+ unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH;
+ if (in_position == out_position)
+ {
+ unsigned tabstop = out_position + spaces;
+ if (tab_expand_flag)
+ {
+ if (out_bound < tabstop)
+ tabstop = out_bound;
+ for (; out_position < tabstop; out_position++)
+ write_output (" ", 1);
+ }
+ else
+ if (tabstop < out_bound)
+ {
+ out_position = tabstop;
+ cc = c;
+ write_output (&cc, 1);
+ }
+ }
+ in_position += spaces;
+ }
+ break;
+
+ case '\r':
+ {
+ cc = c;
+ write_output (&cc, 1);
+ tab_from_to (0, indent);
+ in_position = out_position = 0;
+ }
+ break;
+
+ case '\b':
+ if (in_position != 0 && --in_position < out_bound)
+ if (out_position <= in_position)
+ /* Add spaces to make up for suppressed tab past out_bound. */
+ for (; out_position < in_position; out_position++)
+ write_output (" ", 1);
+ else
+ {
+ out_position = in_position;
+ cc = c;
+ write_output (&cc, 1);
+ }
+ break;
+
+ case '\f':
+ case '\v':
+ control_char:
+ if (in_position < out_bound)
+ {
+ cc = c;
+ write_output (&cc, 1);
+ }
+ break;
+
+ default:
+ if (! ISPRINT (c))
+ goto control_char;
+ /* falls through */
+ case ' ':
+ if (in_position++ < out_bound)
+ {
+ out_position = in_position;
+ cc = c;
+ write_output (&cc, 1);
+ }
+ break;
+
+ case '\n':
+ return out_position;
+ }
+ }
+
+ return out_position;
+}
+
+/*
+ * Print side by side lines with a separator in the middle.
+ * 0 parameters are taken to indicate white space text.
+ * Blank lines that can easily be caught are reduced to a single newline.
+ */
+
+static void
+print_1sdiff_line (left, sep, right)
+ char const * const *left;
+ int sep;
+ char const * const *right;
+{
+ unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
+ unsigned col = 0;
+ int put_newline = 0;
+
+ if (left)
+ {
+ if (left[1][-1] == '\n')
+ put_newline = 1;
+ col = print_half_line (left, 0, hw);
+ }
+
+ if (sep != ' ')
+ {
+ char cc;
+
+ col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
+ if (sep == '|' && put_newline != (right[1][-1] == '\n'))
+ sep = put_newline ? '/' : '\\';
+ cc = sep;
+ write_output (&cc, 1);
+ }
+
+ if (right)
+ {
+ if (right[1][-1] == '\n')
+ put_newline = 1;
+ if (**right != '\n')
+ {
+ col = tab_from_to (col, c2o);
+ print_half_line (right, col, hw);
+ }
+ }
+
+ if (put_newline)
+ write_output ("\n", 1);
+}
+
+/* Print lines common to both files in side-by-side format. */
+static void
+print_sdiff_common_lines (limit0, limit1)
+ int limit0, limit1;
+{
+ int i0 = next0, i1 = next1;
+
+ if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1))
+ {
+ if (sdiff_help_sdiff)
+ printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1);
+
+ if (! sdiff_left_only)
+ {
+ while (i0 != limit0 && i1 != limit1)
+ print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
+ while (i1 != limit1)
+ print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
+ }
+ while (i0 != limit0)
+ print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
+ }
+
+ next0 = limit0;
+ next1 = limit1;
+}
+
+/* Print a hunk of an sdiff diff.
+ This is a contiguous portion of a complete edit script,
+ describing changes in consecutive lines. */
+
+static void
+print_sdiff_hunk (hunk)
+ struct change *hunk;
+{
+ int first0, last0, first1, last1, deletes, inserts;
+ register int i, j;
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
+ if (!deletes && !inserts)
+ return;
+
+ /* Print out lines up to this change. */
+ print_sdiff_common_lines (first0, first1);
+
+ if (sdiff_help_sdiff)
+ printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
+
+ /* Print ``xxx | xxx '' lines */
+ if (inserts && deletes)
+ {
+ for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j)
+ print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
+ deletes = i <= last0;
+ inserts = j <= last1;
+ next0 = first0 = i;
+ next1 = first1 = j;
+ }
+
+
+ /* Print `` > xxx '' lines */
+ if (inserts)
+ {
+ for (j = first1; j <= last1; ++j)
+ print_1sdiff_line (0, '>', &files[1].linbuf[j]);
+ next1 = j;
+ }
+
+ /* Print ``xxx < '' lines */
+ if (deletes)
+ {
+ for (i = first0; i <= last0; ++i)
+ print_1sdiff_line (&files[0].linbuf[i], '<', 0);
+ next0 = i;
+ }
+}
diff --git a/diff/system.h b/diff/system.h
new file mode 100644
index 0000000..ad320f4
--- /dev/null
+++ b/diff/system.h
@@ -0,0 +1,302 @@
+/* System dependent declarations.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+/* We must define `volatile' and `const' first (the latter inside config.h),
+ so that they're used consistently in all system includes. */
+#if !__STDC__
+#ifndef volatile
+#define volatile
+#endif
+#endif
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Note that PARAMS is just internal to the diff library; diffrun.h
+ has its own mechanism, which will hopefully be less likely to
+ conflict with the library's caller's namespace. */
+#if __STDC__
+#define PARAMS(args) args
+#define VOID void
+#else
+#define PARAMS(args) ()
+#define VOID char
+#endif
+
+#if STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISREG
+#undef S_ISSOCK
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFFIFO)
+#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
+#endif
+
+#ifndef S_ISSOCK
+# if defined( S_IFSOCK )
+# ifdef S_IFMT
+# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(mode) ((mode) & S_IFSOCK)
+# endif /* S_IFMT */
+# elif defined( S_ISNAM )
+ /* SCO OpenServer 5.0.6a */
+# define S_ISSOCK S_ISNAM
+# endif /* !S_IFSOCK && S_ISNAM */
+#endif /* !S_ISSOCK */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# include <sys/file.h>
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+/* I believe that all relevant systems have
+ time.h. It is in ANSI, for example. The
+ code below looks quite bogus as I don't think
+ sys/time.h is ever a substitute for time.h;
+ it is something different. */
+#define HAVE_TIME_H 1
+
+#if HAVE_TIME_H
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#ifndef STAT_BLOCKSIZE
+#if HAVE_STRUCT_STAT_ST_BLKSIZE
+#define STAT_BLOCKSIZE(s) (s).st_blksize
+#else
+#define STAT_BLOCKSIZE(s) (8 * 1024)
+#endif
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) ((dirent)->d_namlen)
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#if HAVE_STDLIB_H || defined(STDC_HEADERS)
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+#endif
+#ifndef getenv
+char *getenv ();
+#endif
+
+#include <limits.h>
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+# ifndef bzero
+# define bzero(s, n) memset (s, 0, n)
+# endif
+#else
+# if !HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# if !HAVE_MEMCHR
+# define memcmp(s1, s2, n) bcmp (s1, s2, n)
+# define memcpy(d, s, n) bcopy (s, d, n)
+void *memchr ();
+# endif
+#endif
+
+#include <ctype.h>
+/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
+ as an argument to <ctype.h> macros like `isspace'. */
+#if STDC_HEADERS
+#define CTYPE_DOMAIN(c) 1
+#else
+#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
+#endif
+#ifndef ISPRINT
+#define ISPRINT(c) (CTYPE_DOMAIN (c) && isprint (c))
+#endif
+#ifndef ISSPACE
+#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
+#endif
+#ifndef ISUPPER
+#define ISUPPER(c) (CTYPE_DOMAIN (c) && isupper (c))
+#endif
+
+#ifndef ISDIGIT
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+#endif
+
+#include <errno.h>
+#if !STDC_HEADERS
+extern int errno;
+#endif
+
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+
+/* This section contains Posix-compliant defaults for macros
+ that are meant to be overridden by hand in config.h as needed. */
+
+#ifndef filename_cmp
+#define filename_cmp(a, b) strcmp (a, b)
+#endif
+
+#ifndef filename_lastdirchar
+#define filename_lastdirchar(filename) strrchr (filename, '/')
+#endif
+
+#ifndef HAVE_FORK
+#define HAVE_FORK 1
+#endif
+
+#ifndef HAVE_SETMODE
+#define HAVE_SETMODE 0
+#endif
+
+#ifndef initialize_main
+#define initialize_main(argcp, argvp)
+#endif
+
+/* Do struct stat *S, *T describe the same file? Answer -1 if unknown. */
+#ifndef same_file
+#define same_file(s,t) ((s)->st_ino==(t)->st_ino && (s)->st_dev==(t)->st_dev)
+#endif
+
+/* Place into Q a quoted version of A suitable for `popen' or `system',
+ incrementing Q and junking A.
+ Do not increment Q by more than 4 * strlen (A) + 2. */
+#ifndef SYSTEM_QUOTE_ARG
+#define SYSTEM_QUOTE_ARG(q, a) \
+ { \
+ *(q)++ = '\''; \
+ for (; *(a); *(q)++ = *(a)++) \
+ if (*(a) == '\'') \
+ { \
+ *(q)++ = '\''; \
+ *(q)++ = '\\'; \
+ *(q)++ = '\''; \
+ } \
+ *(q)++ = '\''; \
+ }
+#endif
+
+/* these come from CVS's lib/system.h, but I wasn't sure how to include that
+ * properly or even if I really should
+ */
+#ifndef CVS_OPENDIR
+#define CVS_OPENDIR opendir
+#endif
+#ifndef CVS_READDIR
+#define CVS_READDIR readdir
+#endif
+#ifndef CVS_CLOSEDIR
+#define CVS_CLOSEDIR closedir
+#endif
diff --git a/diff/util.c b/diff/util.c
new file mode 100644
index 0000000..744cf51
--- /dev/null
+++ b/diff/util.c
@@ -0,0 +1,849 @@
+/* Support routines for GNU DIFF.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+
+#include "diff.h"
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifndef strerror
+extern char *strerror ();
+#endif
+
+/* Queue up one-line messages to be printed at the end,
+ when -l is specified. Each message is recorded with a `struct msg'. */
+
+struct msg
+{
+ struct msg *next;
+ char const *format;
+ char const *arg1;
+ char const *arg2;
+ char const *arg3;
+ char const *arg4;
+};
+
+/* Head of the chain of queues messages. */
+
+static struct msg *msg_chain;
+
+/* Tail of the chain of queues messages. */
+
+static struct msg **msg_chain_end = &msg_chain;
+
+/* Use when a system call returns non-zero status.
+ TEXT should normally be the file name. */
+
+void
+perror_with_name (text)
+ char const *text;
+{
+ int e = errno;
+
+ if (callbacks && callbacks->error)
+ (*callbacks->error) ("%s: %s", text, strerror (e));
+ else
+ {
+ fprintf (stderr, "%s: ", diff_program_name);
+ errno = e;
+ perror (text);
+ }
+}
+
+/* Use when a system call returns non-zero status and that is fatal. */
+
+void
+pfatal_with_name (text)
+ char const *text;
+{
+ int e = errno;
+ print_message_queue ();
+ if (callbacks && callbacks->error)
+ (*callbacks->error) ("%s: %s", text, strerror (e));
+ else
+ {
+ fprintf (stderr, "%s: ", diff_program_name);
+ errno = e;
+ perror (text);
+ }
+ DIFF_ABORT (2);
+}
+
+/* Print an error message from the format-string FORMAT
+ with args ARG1 and ARG2. */
+
+void
+diff_error (format, arg, arg1)
+ char const *format, *arg, *arg1;
+{
+ if (callbacks && callbacks->error)
+ (*callbacks->error) (format, arg, arg1);
+ else
+ {
+ fprintf (stderr, "%s: ", diff_program_name);
+ fprintf (stderr, format, arg, arg1);
+ fprintf (stderr, "\n");
+ }
+}
+
+/* Print an error message containing the string TEXT, then exit. */
+
+void
+fatal (m)
+ char const *m;
+{
+ print_message_queue ();
+ diff_error ("%s", m, 0);
+ DIFF_ABORT (2);
+}
+
+/* Like printf, except if -l in effect then save the message and print later.
+ This is used for things like "binary files differ" and "Only in ...". */
+
+void
+message (format, arg1, arg2)
+ char const *format, *arg1, *arg2;
+{
+ message5 (format, arg1, arg2, 0, 0);
+}
+
+void
+message5 (format, arg1, arg2, arg3, arg4)
+ char const *format, *arg1, *arg2, *arg3, *arg4;
+{
+ if (paginate_flag)
+ {
+ struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
+ new->format = format;
+ new->arg1 = concat (arg1, "", "");
+ new->arg2 = concat (arg2, "", "");
+ new->arg3 = arg3 ? concat (arg3, "", "") : 0;
+ new->arg4 = arg4 ? concat (arg4, "", "") : 0;
+ new->next = 0;
+ *msg_chain_end = new;
+ msg_chain_end = &new->next;
+ }
+ else
+ {
+ if (sdiff_help_sdiff)
+ write_output (" ", 1);
+ printf_output (format, arg1, arg2, arg3, arg4);
+ }
+}
+
+/* Output all the messages that were saved up by calls to `message'. */
+
+void
+print_message_queue ()
+{
+ struct msg *m;
+
+ for (m = msg_chain; m; m = m->next)
+ printf_output (m->format, m->arg1, m->arg2, m->arg3, m->arg4);
+}
+
+/* Call before outputting the results of comparing files NAME0 and NAME1
+ to set up OUTFILE, the stdio stream for the output to go to.
+
+ Usually, OUTFILE is just stdout. But when -l was specified
+ we fork off a `pr' and make OUTFILE a pipe to it.
+ `pr' then outputs to our stdout. */
+
+static char const *current_name0;
+static char const *current_name1;
+static int current_depth;
+
+static int output_in_progress = 0;
+
+void
+setup_output (name0, name1, depth)
+ char const *name0, *name1;
+ int depth;
+{
+ current_name0 = name0;
+ current_name1 = name1;
+ current_depth = depth;
+}
+
+#if HAVE_FORK && defined (PR_PROGRAM)
+static pid_t pr_pid;
+#endif
+
+void
+begin_output ()
+{
+ char *name;
+
+ if (output_in_progress)
+ return;
+ output_in_progress = 1;
+
+ /* Construct the header of this piece of diff. */
+ name = xmalloc (strlen (current_name0) + strlen (current_name1)
+ + strlen (switch_string) + 7);
+ /* Posix.2 section 4.17.6.1.1 specifies this format. But there is a
+ bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304):
+ it says that we must print only the last component of the pathnames.
+ This requirement is silly and does not match historical practice. */
+ sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
+
+ if (paginate_flag && callbacks && callbacks->write_output)
+ fatal ("can't paginate when using library callbacks");
+
+ if (paginate_flag)
+ {
+ /* Make OUTFILE a pipe to a subsidiary `pr'. */
+
+#ifdef PR_PROGRAM
+
+# if HAVE_FORK
+ int pipes[2];
+
+ if (pipe (pipes) != 0)
+ pfatal_with_name ("pipe");
+
+ fflush (stdout);
+
+ pr_pid = vfork ();
+ if (pr_pid < 0)
+ pfatal_with_name ("vfork");
+
+ if (pr_pid == 0)
+ {
+ close (pipes[1]);
+ if (pipes[0] != STDIN_FILENO)
+ {
+ if (dup2 (pipes[0], STDIN_FILENO) < 0)
+ pfatal_with_name ("dup2");
+ close (pipes[0]);
+ }
+
+ execl (PR_PROGRAM, PR_PROGRAM, "-f", "-h", name, 0);
+ pfatal_with_name (PR_PROGRAM);
+ }
+ else
+ {
+ close (pipes[0]);
+ outfile = fdopen (pipes[1], "w");
+ if (!outfile)
+ pfatal_with_name ("fdopen");
+ }
+# else /* ! HAVE_FORK */
+ char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10);
+ char *p;
+ char const *a = name;
+ sprintf (command, "%s -f -h ", PR_PROGRAM);
+ p = command + strlen (command);
+ SYSTEM_QUOTE_ARG (p, a);
+ *p = 0;
+ outfile = popen (command, "w");
+ if (!outfile)
+ pfatal_with_name (command);
+ free (command);
+# endif /* ! HAVE_FORK */
+#else
+ fatal ("This port does not support the --paginate option to diff.");
+#endif
+ }
+ else
+ {
+
+ /* If -l was not specified, output the diff straight to `stdout'. */
+
+ /* If handling multiple files (because scanning a directory),
+ print which files the following output is about. */
+ if (current_depth > 0)
+ printf_output ("%s\n", name);
+ }
+
+ free (name);
+
+ /* A special header is needed at the beginning of context output. */
+ switch (output_style)
+ {
+ case OUTPUT_CONTEXT:
+ print_context_header (files, 0);
+ break;
+
+ case OUTPUT_UNIFIED:
+ print_context_header (files, 1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Call after the end of output of diffs for one file.
+ If -l was given, close OUTFILE and get rid of the `pr' subfork. */
+
+void
+finish_output ()
+{
+ if (paginate_flag && outfile != 0 && outfile != stdout)
+ {
+#ifdef PR_PROGRAM
+ int wstatus, w;
+ if (ferror (outfile))
+ fatal ("write error");
+# if ! HAVE_FORK
+ wstatus = pclose (outfile);
+# else /* HAVE_FORK */
+ if (fclose (outfile) != 0)
+ pfatal_with_name ("write error");
+ while ((w = waitpid (pr_pid, &wstatus, 0)) < 0 && errno == EINTR)
+ ;
+ if (w < 0)
+ pfatal_with_name ("waitpid");
+# endif /* HAVE_FORK */
+ if (wstatus != 0)
+ fatal ("subsidiary pr failed");
+#else
+ fatal ("internal error in finish_output");
+#endif
+ }
+
+ output_in_progress = 0;
+}
+
+/* Write something to the output file. */
+
+void
+write_output (text, len)
+ char const *text;
+ size_t len;
+{
+ if (callbacks && callbacks->write_output)
+ (*callbacks->write_output) (text, len);
+ else if (len == 1)
+ putc (*text, outfile);
+ else
+ fwrite (text, sizeof (char), len, outfile);
+}
+
+/* Printf something to the output file. */
+
+#if __STDC__
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else /* ! __STDC__ */
+#define VA_START(args, lastarg) va_start(args)
+#endif /* __STDC__ */
+
+void
+#if __STDC__
+printf_output (const char *format, ...)
+#else
+printf_output (format, va_alist)
+ char const *format;
+ va_dcl
+#endif
+{
+ va_list args;
+
+ VA_START (args, format);
+ if (callbacks && callbacks->write_output)
+ {
+ /* We implement our own limited printf-like functionality (%s, %d,
+ and %c only). Callers who want something fancier can use
+ sprintf. */
+ const char *p = format;
+ char *q;
+ char *str;
+ int num;
+ int ch;
+ char buf[100];
+
+ while ((q = strchr (p, '%')) != NULL)
+ {
+ static const char msg[] =
+ "\ninternal error: bad % in printf_output\n";
+ (*callbacks->write_output) (p, q - p);
+
+ switch (q[1])
+ {
+ case 's':
+ str = va_arg (args, char *);
+ (*callbacks->write_output) (str, strlen (str));
+ break;
+ case 'd':
+ num = va_arg (args, int);
+ sprintf (buf, "%d", num);
+ (*callbacks->write_output) (buf, strlen (buf));
+ break;
+ case 'c':
+ ch = va_arg (args, int);
+ buf[0] = ch;
+ (*callbacks->write_output) (buf, 1);
+ break;
+ default:
+ (*callbacks->write_output) (msg, sizeof (msg) - 1);
+ /* Don't just keep going, because q + 1 might point to the
+ terminating '\0'. */
+ goto out;
+ }
+ p = q + 2;
+ }
+ (*callbacks->write_output) (p, strlen (p));
+ }
+ else
+ vfprintf (outfile, format, args);
+ out:
+ va_end (args);
+}
+
+/* Flush the output file. */
+
+void
+flush_output ()
+{
+ if (callbacks && callbacks->flush_output)
+ (*callbacks->flush_output) ();
+ else
+ fflush (outfile);
+}
+
+/* Compare two lines (typically one from each input file)
+ according to the command line options.
+ For efficiency, this is invoked only when the lines do not match exactly
+ but an option like -i might cause us to ignore the difference.
+ Return nonzero if the lines differ. */
+
+int
+line_cmp (s1, s2)
+ char const *s1, *s2;
+{
+ register unsigned char const *t1 = (unsigned char const *) s1;
+ register unsigned char const *t2 = (unsigned char const *) s2;
+
+ while (1)
+ {
+ register unsigned char c1 = *t1++;
+ register unsigned char c2 = *t2++;
+
+ /* Test for exact char equality first, since it's a common case. */
+ if (c1 != c2)
+ {
+ /* Ignore horizontal white space if -b or -w is specified. */
+
+ if (ignore_all_space_flag)
+ {
+ /* For -w, just skip past any white space. */
+ while (ISSPACE (c1) && c1 != '\n') c1 = *t1++;
+ while (ISSPACE (c2) && c2 != '\n') c2 = *t2++;
+ }
+ else if (ignore_space_change_flag)
+ {
+ /* For -b, advance past any sequence of white space in line 1
+ and consider it just one Space, or nothing at all
+ if it is at the end of the line. */
+ if (ISSPACE (c1))
+ {
+ while (c1 != '\n')
+ {
+ c1 = *t1++;
+ if (! ISSPACE (c1))
+ {
+ --t1;
+ c1 = ' ';
+ break;
+ }
+ }
+ }
+
+ /* Likewise for line 2. */
+ if (ISSPACE (c2))
+ {
+ while (c2 != '\n')
+ {
+ c2 = *t2++;
+ if (! ISSPACE (c2))
+ {
+ --t2;
+ c2 = ' ';
+ break;
+ }
+ }
+ }
+
+ if (c1 != c2)
+ {
+ /* If we went too far when doing the simple test
+ for equality, go back to the first non-white-space
+ character in both sides and try again. */
+ if (c2 == ' ' && c1 != '\n'
+ && (unsigned char const *) s1 + 1 < t1
+ && ISSPACE(t1[-2]))
+ {
+ --t1;
+ continue;
+ }
+ if (c1 == ' ' && c2 != '\n'
+ && (unsigned char const *) s2 + 1 < t2
+ && ISSPACE(t2[-2]))
+ {
+ --t2;
+ continue;
+ }
+ }
+ }
+
+ /* Lowercase all letters if -i is specified. */
+
+ if (ignore_case_flag)
+ {
+ if (ISUPPER (c1))
+ c1 = tolower (c1);
+ if (ISUPPER (c2))
+ c2 = tolower (c2);
+ }
+
+ if (c1 != c2)
+ break;
+ }
+ if (c1 == '\n')
+ return 0;
+ }
+
+ return (1);
+}
+
+/* Find the consecutive changes at the start of the script START.
+ Return the last link before the first gap. */
+
+struct change *
+find_change (start)
+ struct change *start;
+{
+ return start;
+}
+
+struct change *
+find_reverse_change (start)
+ struct change *start;
+{
+ return start;
+}
+
+/* Divide SCRIPT into pieces by calling HUNKFUN and
+ print each piece with PRINTFUN.
+ Both functions take one arg, an edit script.
+
+ HUNKFUN is called with the tail of the script
+ and returns the last link that belongs together with the start
+ of the tail.
+
+ PRINTFUN takes a subscript which belongs together (with a null
+ link at the end) and prints it. */
+
+void
+print_script (script, hunkfun, printfun)
+ struct change *script;
+ struct change * (*hunkfun) PARAMS((struct change *));
+ void (*printfun) PARAMS((struct change *));
+{
+ struct change *next = script;
+
+ while (next)
+ {
+ struct change *this, *end;
+
+ /* Find a set of changes that belong together. */
+ this = next;
+ end = (*hunkfun) (next);
+
+ /* Disconnect them from the rest of the changes,
+ making them a hunk, and remember the rest for next iteration. */
+ next = end->link;
+ end->link = 0;
+#ifdef DEBUG
+ debug_script (this);
+#endif
+
+ /* Print this hunk. */
+ (*printfun) (this);
+
+ /* Reconnect the script so it will all be freed properly. */
+ end->link = next;
+ }
+}
+
+/* Print the text of a single line LINE,
+ flagging it with the characters in LINE_FLAG (which say whether
+ the line is inserted, deleted, changed, etc.). */
+
+void
+print_1_line (line_flag, line)
+ char const *line_flag;
+ char const * const *line;
+{
+ char const *text = line[0], *limit = line[1]; /* Help the compiler. */
+ char const *flag_format = 0;
+
+ /* If -T was specified, use a Tab between the line-flag and the text.
+ Otherwise use a Space (as Unix diff does).
+ Print neither space nor tab if line-flags are empty. */
+
+ if (line_flag && *line_flag)
+ {
+ flag_format = tab_align_flag ? "%s\t" : "%s ";
+ printf_output (flag_format, line_flag);
+ }
+
+ output_1_line (text, limit, flag_format, line_flag);
+
+ if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
+ printf_output ("\n\\ No newline at end of file\n");
+}
+
+/* Output a line from TEXT up to LIMIT. Without -t, output verbatim.
+ With -t, expand white space characters to spaces, and if FLAG_FORMAT
+ is nonzero, output it with argument LINE_FLAG after every
+ internal carriage return, so that tab stops continue to line up. */
+
+void
+output_1_line (text, limit, flag_format, line_flag)
+ char const *text, *limit, *flag_format, *line_flag;
+{
+ if (!tab_expand_flag)
+ write_output (text, limit - text);
+ else
+ {
+ register unsigned char c;
+ register char const *t = text;
+ register unsigned column = 0;
+ /* CC is used to avoid taking the address of the register
+ variable C. */
+ char cc;
+
+ while (t < limit)
+ switch ((c = *t++))
+ {
+ case '\t':
+ {
+ unsigned spaces = TAB_WIDTH - column % TAB_WIDTH;
+ column += spaces;
+ do
+ write_output (" ", 1);
+ while (--spaces);
+ }
+ break;
+
+ case '\r':
+ write_output ("\r", 1);
+ if (flag_format && t < limit && *t != '\n')
+ printf_output (flag_format, line_flag);
+ column = 0;
+ break;
+
+ case '\b':
+ if (column == 0)
+ continue;
+ column--;
+ write_output ("\b", 1);
+ break;
+
+ default:
+ if (ISPRINT (c))
+ column++;
+ cc = c;
+ write_output (&cc, 1);
+ break;
+ }
+ }
+}
+
+int
+change_letter (inserts, deletes)
+ int inserts, deletes;
+{
+ if (!inserts)
+ return 'd';
+ else if (!deletes)
+ return 'a';
+ else
+ return 'c';
+}
+
+/* Translate an internal line number (an index into diff's table of lines)
+ into an actual line number in the input file.
+ The internal line number is LNUM. FILE points to the data on the file.
+
+ Internal line numbers count from 0 starting after the prefix.
+ Actual line numbers count from 1 within the entire file. */
+
+int
+translate_line_number (file, lnum)
+ struct file_data const *file;
+ int lnum;
+{
+ return lnum + file->prefix_lines + 1;
+}
+
+void
+translate_range (file, a, b, aptr, bptr)
+ struct file_data const *file;
+ int a, b;
+ int *aptr, *bptr;
+{
+ *aptr = translate_line_number (file, a - 1) + 1;
+ *bptr = translate_line_number (file, b + 1) - 1;
+}
+
+/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
+ If the two numbers are identical, print just one number.
+
+ Args A and B are internal line numbers.
+ We print the translated (real) line numbers. */
+
+void
+print_number_range (sepchar, file, a, b)
+ int sepchar;
+ struct file_data *file;
+ int a, b;
+{
+ int trans_a, trans_b;
+ translate_range (file, a, b, &trans_a, &trans_b);
+
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (trans_b > trans_a)
+ printf_output ("%d%c%d", trans_a, sepchar, trans_b);
+ else
+ printf_output ("%d", trans_b);
+}
+
+/* Look at a hunk of edit script and report the range of lines in each file
+ that it applies to. HUNK is the start of the hunk, which is a chain
+ of `struct change'. The first and last line numbers of file 0 are stored in
+ *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
+ Note that these are internal line numbers that count from 0.
+
+ If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
+
+ Also set *DELETES nonzero if any lines of file 0 are deleted
+ and set *INSERTS nonzero if any lines of file 1 are inserted.
+ If only ignorable lines are inserted or deleted, both are
+ set to 0. */
+
+void
+analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
+ struct change *hunk;
+ int *first0, *last0, *first1, *last1;
+ int *deletes, *inserts;
+{
+ int l0, l1, show_from, show_to;
+ int i;
+ int trivial = ignore_blank_lines_flag || ignore_regexp_list;
+ struct change *next;
+
+ show_from = show_to = 0;
+
+ *first0 = hunk->line0;
+ *first1 = hunk->line1;
+
+ next = hunk;
+ do
+ {
+ l0 = next->line0 + next->deleted - 1;
+ l1 = next->line1 + next->inserted - 1;
+ show_from += next->deleted;
+ show_to += next->inserted;
+
+ for (i = next->line0; i <= l0 && trivial; i++)
+ if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n')
+ {
+ struct regexp_list *r;
+ char const *line = files[0].linbuf[i];
+ int len = files[0].linbuf[i + 1] - line;
+
+ for (r = ignore_regexp_list; r; r = r->next)
+ if (0 <= re_search (&r->buf, line, len, 0, len, 0))
+ break; /* Found a match. Ignore this line. */
+ /* If we got all the way through the regexp list without
+ finding a match, then it's nontrivial. */
+ if (!r)
+ trivial = 0;
+ }
+
+ for (i = next->line1; i <= l1 && trivial; i++)
+ if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n')
+ {
+ struct regexp_list *r;
+ char const *line = files[1].linbuf[i];
+ int len = files[1].linbuf[i + 1] - line;
+
+ for (r = ignore_regexp_list; r; r = r->next)
+ if (0 <= re_search (&r->buf, line, len, 0, len, 0))
+ break; /* Found a match. Ignore this line. */
+ /* If we got all the way through the regexp list without
+ finding a match, then it's nontrivial. */
+ if (!r)
+ trivial = 0;
+ }
+ }
+ while ((next = next->link) != 0);
+
+ *last0 = l0;
+ *last1 = l1;
+
+ /* If all inserted or deleted lines are ignorable,
+ tell the caller to ignore this hunk. */
+
+ if (trivial)
+ show_from = show_to = 0;
+
+ *deletes = show_from;
+ *inserts = show_to;
+}
+
+/* Concatenate three strings, returning a newly malloc'd string. */
+
+char *
+concat (s1, s2, s3)
+ char const *s1, *s2, *s3;
+{
+ size_t len = strlen (s1) + strlen (s2) + strlen (s3);
+ char *new = xmalloc (len + 1);
+ sprintf (new, "%s%s%s", s1, s2, s3);
+ return new;
+}
+
+/* Yield the newly malloc'd pathname
+ of the file in DIR whose filename is FILE. */
+
+char *
+dir_file_pathname (dir, file)
+ char const *dir, *file;
+{
+ char const *p = filename_lastdirchar (dir);
+ return concat (dir, "/" + (p && !p[1]), file);
+}
+
+void
+debug_script (sp)
+ struct change *sp;
+{
+ fflush (stdout);
+ for (; sp; sp = sp->link)
+ fprintf (stderr, "%3d %3d delete %d insert %d\n",
+ sp->line0, sp->line1, sp->deleted, sp->inserted);
+ fflush (stderr);
+}
diff --git a/diff/version.c b/diff/version.c
new file mode 100644
index 0000000..343a098
--- /dev/null
+++ b/diff/version.c
@@ -0,0 +1,5 @@
+/* Version number of GNU diff. */
+
+#include <config.h>
+
+char const diff_version_string[] = "2.7";
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644
index 0000000..cda8b8b
--- /dev/null
+++ b/doc/.cvsignore
@@ -0,0 +1,43 @@
+*.dvi
+Makefile
+cvs-paper.pdf
+cvs-paper.ps
+cvs.aux
+cvs.cp
+cvs.cps
+cvs.dvi
+cvs.fn
+cvs.fns
+cvs.info
+cvs.info-*
+cvs.ky
+cvs.log
+cvs.pdf
+cvs.pg
+cvs.ps
+cvs.tmp
+cvs.toc
+cvs.tp
+cvs.txt
+cvs.vr
+cvs.vrs
+cvsclient.info
+cvsclient.aux
+cvsclient.cp
+cvsclient.cps
+cvsclient.dvi
+cvsclient.fn
+cvsclient.info
+cvsclient.info-*
+cvsclient.ky
+cvsclient.log
+cvsclient.pdf
+cvsclient.pg
+cvsclient.ps
+cvsclient.toc
+cvsclient.tp
+cvsclient.txt
+cvsclient.vr
+getdate-cvs.texi
+stamp-gdt
+mkman
diff --git a/doc/ChangeLog b/doc/ChangeLog
new file mode 100644
index 0000000..c91a991
--- /dev/null
+++ b/doc/ChangeLog
@@ -0,0 +1,5307 @@
+2005-09-26 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs-paper.ps, cvs-paper.pdf): Remove implicit sources.
+ Add comments about why implicit rules won't work for these targets.
+ Make sure the distributed cvs-paper.pdf is created in $(srcdir). Make
+ cvs-paper.pdf directly from cvs-paper.ms to avoid building it just
+ because cvs-paper.ps is missing.
+
+ * Makefile.am (EXTRA_DIST): Restore PDFs.
+ * cvs-paper.ps: Removed.
+
+2005-09-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (doc): Finish removing PSs.
+
+ * Makefile.am (EXTRA_DIST): Remove PDFs too until errors go away.
+
+ * Makefile.am (EXTRA_DIST): Dist PDFs rather than PSs.
+
+2005-09-22 Larry Jones <lawrence.jones@ugs.com>
+
+ * cvs.texinfo (rdiff options): Document -k.
+ * cvs.1, stamp-vti, version.texi: Regenerated.
+
+2005-09-20 Larry Jones <lawrence.jones@ugs.com>
+
+ * cvs.texinfo: Move summary and detail contents to the front
+ where they belong.
+
+2005-09-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: s#cvs.1#$(srcdir)/cvs.1#.
+
+2005-09-12 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-gdt): Use texinfo, as opposed to C, comments in
+ the automatically generated getdate-cvs.texi file.
+
+2005-09-11 Larry Jones <lawrence.jones@ugs.com>
+
+ * cvs.texinfo (Common options): Note that -r branch for a revision
+ means the head of the branch.
+
+2005-09-10 Larry Jones <lawrence.jones@ugs.com>
+
+ * cvs.texinfo (Error messages): Add suggested messages.
+
+2005-09-09 Larry Jones <lawrence.jones@ugs.com>
+
+ * cvs.texinfo (Error messages): Move out of sync message to correct
+ location and reword.
+ Clean up bad cross reference syntax.
+
+ * cvs.texinfo (Error messages): Add signal 11 message.
+
+2005-09-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (config): Alphabetize list of keys.
+
+ * cvs.texinfo (Global options): Clarify -T description with temporary
+ file path precedence.
+ (config): Shorten TmpDir stuff and reference Global options node.
+ (Environment variables): Ditto for $TMPDIR. Remove $TMP and $TEMP. As
+ near as I can tell they are no longer used.
+
+2005-09-05 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (config): Mention TmpDir first appeared in 1.12.13.
+
+ * cvs.texinfo (config): Describe new TmpDir option.
+
+2005-09-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (config): Describe new [cvsroot] syntax.
+
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Update links and email addresses.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (CVS commands): Link to new node.
+ (server & pserver): New node.
+ (config): Note configurability of config file path.
+
+2005-08-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (verifymsg): Describe new %{sV} format strings.
+
+2005-08-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (From scratch): Add checkout to import example, from
+ wiki.
+
+2005-08-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Removing directories): Correct grammar, from wiki.
+
+2005-08-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (From scratch): Clarify note on `cvs add', inspired from
+ wiki.
+
+2005-08-22 Derek Price <derek@ximbiot.com>
+
+ Address bug #13882, submitted by Fred Maranhao.
+ * cvs.texinfo (log options, admin options, Invoking CVS): Add cross
+ references for clarity about possible states.
+
+2005-08-22 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Updating a file): Add note about update -d, inspired by
+ wiki.
+
+2005-08-12 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (What is CVS?): Rephrase for clarity, imported from
+ Wiki.
+
+2005-08-02 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (What is CVS?, BUGS): Correct grammar.
+
+2005-07-20 Derek Price <derek@ximbiot.com>
+
+ * cvs.man.footer, cvs.texinfo, cvsclient.texi:
+ s/cvshome.org/nongnu.org.etc.../.
+
+2005-06-22 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Builds): Update Gunnar Tornblom's email at his request.
+
+2005-06-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (loginfo, taginfo): Note new `T' format character in
+ {sTVv} list.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Global options): Note -z *requests* a compression level.
+ (config): Describe MinCompressionLevel and MaxCompressionLevel.
+ * cvsclient.texi (Responses): Add `Force-gzip' request.
+ (Requests): Clarify `Gzip-stream' description.
+
+2005-06-01 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Connecting via rsh): Cross-reference method options and
+ don't capitalize `remsh' and `ssh' executable names.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * getdate.texi: Update from GNULIB.
+
+2005-05-11 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (history, history file, config): Add info on the new
+ HistoryLogPath and HistorySearchPath config options.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * cvsclient.texi (Goals): Remove typo. Resolves cvshome issue #236.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Creating a repository): Provide xref to the remote
+ repositries section. Resolves issue #203 on cvshome.org.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Moving directories): Clarify instructions on renaming a
+ directory. Partially resolves issue #246 on cvshome.org.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (update output): Use "working directory" in place of
+ "source" for clarity. Closes issue #245 on cvshome.org.
+
+2005-04-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Variables): Document SESSIONID and COMMITID
+ internal variables.
+
+2005-04-18 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Restore getdate-cvs.texi.
+ (DISTCLEAN): Remove same.
+ (getdate-cvs.texi): Move to...
+ ($(srcdir)/getdate-cvs.texi): ...here to avoid rebuild infos at
+ install.
+ (stamp-gdt): Generate $(srcdir)/getdate-cvs.texi.
+
+2005-04-15 Derek Price <derek@ximbiot.com>
+
+ * mkman.pl: Minor changes to accomodate Perl 5.8.4. Improve
+ commenting.
+ ($nk, $ret, $debug): New globals.
+ (debug_print): New function.
+
+2005-04-14 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Administrative files): Rename "script hooks" node as
+ "Trigger Scripts".
+ (script hooks): Rename as...
+ (Trigger Scripts): ...this and add some clarifying text.
+ (Trigger Script Security): New node.
+ (-many *info nodes-): Rewrite to reference to Trigger Script node.
+ Add and/or rewrite index entries and cross-references.
+
+2005-04-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Make $(srcdir)/cvs.info, not cvs.info, dependent on
+ getdate-cvs.texi.
+
+2005-04-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stampt-gdt): Remove dependency on configure.
+
+2005-04-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (DISTCLEANFILES): Move getdate-cvs.tmp to...
+ (MOSTLYCLEANFILES): ...here.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs.1): Create intermediate file so that the original
+ isn't emptied on error.
+
+2005-03-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * mdate-sh, texinfo.tex: Update from GNULIB.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ Update installed GNULIB modules.
+ * getdate.texi: Update from GNULIB.
+
+2005-02-25 Derek Price <derek@ximbiot.com>
+ for Frank Hemer <frank@hemer.org>
+
+ * cvs.texinfo, RCSFILES: Describe commitid.
+
+2005-02-23 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Update many nodes to specify -r rev[:date] rather than
+ -r rev.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am, cvs.man.header, cvs.texinfo: Update copyright notices.
+
+2005-01-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (log options): Note quirky interaction of log options.
+ (Suggestion from Dan Peterson <dbpete@aol.com>.)
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add HACKING.DOCS & writeproxy.rtf.
+ (SUBDIRS): Add i18n.
+
+2004-12-09 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Error messages): Note that old, val-tags, "no such tag"
+ problem has been fixed and expound.
+
+2004-12-09 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Remote repositories): Move method option data to...
+ (The connection method): ...this new node and rework.
+
+2004-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (BUGS, What is CVS?): Remove Dr. Pascal Molli's CVS
+ URL from the documentation.
+ * cvs.man.footer: Ditto.
+ * cvs.1, stamp-vti, version.texi: Regenerated.
+
+2004-12-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Remote repositories): Add options CVS_RSH and
+ CVS_SERVER to the docs.
+ (Connecting via rsh): Ditto.
+ (getdate.texi): Replaced reference to getdate-cvs.texi file that
+ does not exist.
+ * stamp-1, stamp-vti, version-client.texi, version.texi:
+ Regenerated.
+
+2004-11-30 Derek Price <derek@ximbiot.com>
+
+ * cvsclient.texi (Responses): Document the `Referrer' response.
+
+2004-11-29 Larry Jones <lawrence.jones@ugs.com>
+
+ * cvs.texinfo (Keyword list): Add LocalKeyword and KeywordExpand.
+
+2004-11-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Keyword list): LocalKeyword may only use the Id,
+ Header, and CVSHeader keywords at present, so document it.
+
+2004-11-29 Larry Jones <lawrence.jones@ugs.com>
+
+ * cvs.texinfo: s/KeywordExpansion/KeywordExpand/.
+
+2004-11-24 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Write proxies): Mention version limitations on primary
+ and secondary write proxies.
+ (Error messages): List secondary out of sync message.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * getdate.texi: Update from GNULIB.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-gdt): Replace dependency on Makefile with
+ dependency on configure.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): s/getdate.text/getdate.texi/.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore intermediate cvs.vrs.
+
+2004-11-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs.dvi): Make dependent on getdate-cvs.texi.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Add stamp-gdt & getdate-cvs.texi.
+ * Makefile.am (EXTRA_DIST): Distribute getdate.texi.
+ (getdate-cvs.texi, stamp-gdt): New targets.
+ (cvs.html, cvs.info, cvs.pdf, cvs.ps, cvs.txt): Depend on
+ getdate-cvs.texi.
+ * cvs.texinfo: Include getdate-cvs.texi.
+ (Common options): Reference new section rather than describing valid
+ dates.
+ * getdate.texi: New file from GNULIB.
+ * mkman.pl: Ignore include lines.
+
+2004-10-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Write proxies): Mention PrimaryServer name resolution.
+
+2004-10-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Common options): The -r TAG option works with
+ the cvs annotate command.
+ (Original patch from Ville Skytta <scop@cvshome.org>.)
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-10-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (assorted edit and commit related sections): Add
+ information about new '-c' and '-f' options for reservations
+ patch. The code (not documentation) for this feature was
+ originally from Noel Yap <yap_noel@yahoo.com>, originally ported
+ forward and enhanced by Matthew Ogilvie <mmo9317bd@mailcan.com>.)
+
+ * cvsclient.texi (Requests): Add "Hostname", "LocalDir", and "edit".
+ (Responses): Add "Edit-file".
+
+2004-10-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (syntax): Note referrer format string.
+ * cvsclient.texi (Requests): Describe Referrer request.
+ (Responses): Note that a client should sent Referrer to the new server
+ after a Redirect.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Write proxies, Global options): Detail operation of
+ global --allow-root option, Remove references to global --primary-root.
+
+2004-09-25 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Move to...
+ * mkman.pl: ...here.
+ * Makefile.am (cvs.1): mkman is in build dir, not src dir.
+
+2004-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs.1): Add paths in hopes of getting more consistent
+ behavior.
+
+2004-09-14 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Keyword list, config): Note new config options and how
+ they effect the Log keyword.
+
+2004-08-17 Derek Price <derek@ximbiot.com>
+
+ * cvsclient.texi (Requests): s/Command-prenotify/Command-prep/.
+
+2004-08-16 Derek Price <derek@ximbiot.com>
+
+ * cvsclient.texi (Requests): Document the new `Command-prenotify'
+ request.
+ (Responses): Document the new `Redirect' response.
+
+2004-07-14 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Write proxies): Document recent changes in
+ implementation.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (script hooks/*): Tidy. Document new hooks as
+ implemented.
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (config): Note that PrimaryServer hostname must match
+ that returned by uname on the primary server.
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * writeproxy.rtf: Update with latest modifications.
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Write proxies): Reference new script hooks.
+ (Administrative files): Move relevant parts of FIXME and references to
+ *info files...
+ (commit files): ...and most of the menu items from this node...
+ (script hooks): ...to this new node.
+ (postadmin, posttag, postwatch, preproxy, postproxy): New nodes.
+ (syntax, taginfo): Point at "script hooks" rather than
+ "Administrative files" node.
+
+2004-06-07 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Write proxies): New node.
+ (config): Note new PrimaryServer option.
+
+2004-06-04 Derek Price <derek@ximbiot.com>
+
+ * writeproxy.rtf: Documentation for new writeproxy design.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (script hooks/*): Tidy. Document new hooks as
+ implemented.
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Write proxies): Reference new script hooks.
+ (Administrative files): Move relevant parts of FIXME and references to
+ *info files...
+ (commit files): ...and most of the menu items from this node...
+ (script hooks): ...to this new node.
+ (postadmin, posttag, postwatch): New nodes.
+ (syntax, taginfo): Point at "script hooks" rather than
+ "Administrative files" node.
+
+2004-07-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (config): Document ImportNewFilesToVendorBranchOnly
+ option.
+ (import options): Mention that ImportNewFilesToVendorBranchOnly
+ can force 'cvs import -X' behaviour for all imports.
+ (New feature from Chris Demetriou <cgd@broadcom.com>.)
+
+2004-07-17 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Update imports, import): Add notes on requirement that
+ release tags be unique.
+ (Original patch from Ilya N. Golubev <gin@mo.msk.ru>.)
+
+2004-07-17 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Password authentication server): Added documentation for
+ the now required session configuration for PAM.
+ (Patch from Brian Murphy <brian@murphy.dk>.)
+
+2004-06-29 Derek Price <derek@ximbiot.com>
+
+ * cvsclient.texi (Requests): Note new `Relative-directory request' as
+ well as new semantics for `Directory'.
+ (Response pathnames): Detail previously undocumented client
+ functionality with regards to pathnames specified in responses.
+
+2004-06-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Vendor branch): Document that sometimes
+ the default branch won't be set to the vendor branch.
+ (import options): Add -X.
+ * cvsclient.texi (MT importmergecmd tag): Document that this
+ can also be used with the 'cvs import -X' command, and
+ that it can occur when there are no conflicts.
+ (New feature from Chris Demetriou <cgd@broadcom.com>.)
+
+2004-06-21 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Password authentication server): Search for system user
+ rather than system password. Closes issue #185.
+ (Reported by Fred Maranhao <fred.maranhao@click21.com.br>.)
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (commit files): Remove reference to the obsolete -i
+ module option.
+
+2004-05-28 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Global options): Remove reference to global -l option.
+ (Report from Kevin Bulgrien <Kevin.Bulgrien@TriPointGlobal.com>.)
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (log): Updated since we display in local time now.
+ Also added some examples.
+ (Patch from Bart Robinson <lomew@pobox.com>.)
+
+ * cvs.1: Regenerated.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs.1): Generate in $(srcdir).
+ (MAINTAINERCLEANFILES): Remove cvs.1.
+
+2004-05-14 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo: Fix makeinfo error.
+
+ * cvs.texinfo (Adding files): Cleanup example.
+ (Using keywords): Cleanup text.
+
+2004-05-13 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Adding files): Minor cleanup.
+ (Using keywords): Minor cleanup.
+ (annotate): Move into the manual section, split into three nodes.
+ (annotate options): New node.
+ (annotate example): New node.
+ (based on patch from Steve McIntyre <steve@einval.com>.)
+ * cvs.1, stamp-1, stamp-vti, version-client.texi, version.texi:
+ Regenerated.
+
+2004-05-12 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Clarify status messages.
+
+2004-05-12 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (ls & rls): Document default behaviors.
+ (Patch from Alexander Taler <dissent@cvshome.org>.)
+
+ * cvs.texinfo (ls & rls options): Document -d.
+ (Common options): Note ls & rls accept -R and note that they are the
+ sole exceptions it as a default.
+
+2004-05-10 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Organize & tidy comments. Check for unprocessed texinfo
+ commands. Output better error messages on finding unprocessed texinfo
+ commands.
+ (do_keyword, keyword_mode): Accept $file argument for error messages.
+
+2004-05-06 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Require Perl 5.005. Add comments. Remove duplicate s///.
+ Handle @:.
+
+2004-05-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.man.header: Minor text correction.
+ * mkman.in: Ignore @need keyword. Restore previous font for nested
+ keywords.
+ (do_keyword): Ditto on fonts. Move some functionality to...
+ (keyword_mode): ...this new function.
+
+2004-05-06 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Handle keywords that cross multiple lines.
+ (do_keyword): New function.
+
+2004-05-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.man.header, cvs.man.footer: Reference `info CVS' rather than
+ `info cvs' to send users to the top node.
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: mkman is built in the build dir, not $(srcdir).
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * HACKING.DOCS: Fix spelling error. Add reference for @strong.
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+ * HACKING.DOCS: Note dependency on `makeinfo' 3.11 & greater.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Handle single quotes better. Parse out some redundancy
+ from node and section names.
+ * cvs.man.footer: Replace some quotes with the usual bold font.
+ Reformat links in the SEE ALSO section.
+ * cvs.1: Regenerated.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Handle examples better. Protect a few more characters.
+ * cvs.1, stamp-vti, version.texi: Regenerated.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ * cvs.man.header: Add copyright notice.
+ * cvs.1: Regenerated.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Add copyright and license notice.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ * mkman.in: Handle @@.
+ * cvs.1: Regenerated.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ First pass at closing issue #3 on cvshome.org.
+ * .cvsignore: Ignore mkman.
+ * cvs.1, mkman.in, cvs.man.header, cvs.man.footer: New files.
+ * cvs.texinfo: Add cut tags for mkman.
+ * Makefile.in (man_MANS): Add cvs.1.
+ (EXTRA_DIST): Add cvs.man.header & cvs.man.footer.
+ (cvs.1, mkman): New targets.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, version-client.texi: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (ls & rls options): Document new -P option.
+ * stamp-vti, version.texi: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * cvsclient.texi (global-list-quiet): New request.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (ls, ls options, ls examples): Document
+ new ls command.
+ (Original patch from Mark D. Baushke <mdb@cvshome.org>.)
+ * cvsclient.texi (list, ls, rlist): New requests.
+ * stamp-1, version-client.texi: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Update years in Copyright.
+ * stamp-vti, version.texi: Regenerated.
+
+2004-04-21 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Use splitrcskeyword macro consistently in a failed
+ attempt to avoid a warning during PDF generation.
+ * stamp-vti, version.texi: Regenerated.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2004-04-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Various spelling, typo, and capitalization fixes.
+ (Patch from Ville Skyttä <scop@cvshome.org>.)
+
+2004-04-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Remote repositories): Describe how to use a web proxy to
+ contact a CVS server.
+ (GSSAPI authenticated): Use slightly clearer language.
+ (Kerberos authenticated): Remove incomplete note on server setup.
+ (Environment variables): Add CVS_PROXY_PORT.
+
+2004-04-06 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * cvs.texinfo (Assigning revisions): Note that client/server mode
+ only considers files sent to the server to determine the major
+ revision for new files.
+ (Reported by Krzysztof GORBIEL <Krzysztof_GORBIEL@raiffeisen.pl>.)
+ * stamp-vti, version.texi: Regenerated.
+
+2004-03-15 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2004-03-15 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: s/UseNewInfoFormatStrings/UseNewInfoFmtStrings/g.
+ (Reported by Matthew B. Doar <matt@trpz.com>.)
+ * stamp-vti, version.texi: Regenerated.
+
+2004-03-11 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * cvs.texinfo (loginfo, Error messages): Note that not reading all of
+ the log info can result in a broken pipe signal.
+ (Reported by Steven Nicoloso <spn@nwmail.wh.lucent.com>.)
+ * stamp-vti, version.texi: Regenerated.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, version-client.texi: Regenerated.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, version-client.texi: Regenerated.
+
+2004-02-18 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (syntax, updating commit files, commitinfo,
+ verifymsg, loginfo, taginfo, user-defined logging):
+ Document new format strings.
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (File Permissions): Clarify index entry.
+ * stamp-vti, version.texi: Regenerated.
+
+2004-01-22 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2004-01-08 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * cvs.texinfo (user-defined logging): Move taginfo stuff from here...
+ (Administrative files): ...to its own node under here.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated
+ for dev 1.12.5.1.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated
+ for release 1.12.5.
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated
+ for release 1.12.4.1.
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Locks): Provide technical details for promotable
+ readlocks.
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-12-05 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated
+ for dev version 1.12.3.1.
+
+2003-12-04 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated
+ for release 1.12.3.
+
+2003-11-26 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-11-18 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-11-13 Larry Jones <lawrence.jones@eds.com>
+
+ * cvs.texinfo (Reverting local changes): Use the same vendor tag
+ in the admin command as was used in the previous import commands.
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-11-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (CVS commands): Fix typo.
+ (FreeBSD PR docs/58669 reported by Ceri Davies <ceri@FreeBSD.org>.)
+
+2003-10-30 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-10-30 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (File permissions, Error messages): Add index entries for
+ CVSROOT/val-tags file.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated
+ for 1.12.2.1.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * stamp-1, stamp-vti, version-client.texi, version.texi: Regenerated
+ for 1.12.2.
+
+2003-10-21 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Note gnu.cvs.* usenet mirrors of the email lists.
+ (Suggestion from Paul Edwards, from somewhere in Australia.)
+
+ * cvs.texinfo: Put email addresses in @email{} tags and URLs in @url{}
+ tags rather than relying on markup like @code{}.
+ * stamp-vti, version.texi: Regenerated.
+
+2003-10-14 Derek Price <derek@ximbiot.com>
+
+ Port to pedantic POSIX 1003.1-2001 hosts, such as Debian GNU/Linux
+ testing with _POSIX2_VERSION=200112 in the environment.
+
+ * cvs.texinfo: Suggest 'sed 1q', not 'head -1'.
+ (Patch from Paul Eggert <eggert@twinsun.com>.)
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * cvsclient.texi (Requests): Add recommendation to client developers to
+ avoid the `Case' request.
+ * stamp-1, version-client.texi: Regenerated.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-09-12 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (checkoutlist): Document the error messages which may be
+ specified in this file.
+ * stamp-vti, version.texi: Regenerated.
+
+2003-08-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Administrative files, Commit files): Remove references
+ to deleted nodes.
+ (editinfo, editinfo example): Remove these obsolete nodes.
+ * stamp-vti, version.texi: Regenerated.
+
+2003-08-27 Larry Jones <lawrence.jones@eds.com>
+
+ * cvs.texinfo (history options): Note the 'P' record type which
+ has been around for a long time but never actually appeared in
+ the history file due to bugs in the code.
+ (Invoking CVS): Ditto.
+ (config): Ditto.
+ * stamp-vti, version.texi: Regenerated.
+
+2003-08-12 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-08-07 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore {cvs,cvsclient}.txt.
+
+2003-08-07 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Use the @dircategory and @direntry commands from texinfo
+ rather than rolling our own.
+
+ * stamp-vti, version.texi: Regenerated.
+
+2003-08-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (POSTSCRIPTS): Rename to...
+ (PSS): ...to sync with and override Automakes default targets.
+ (PDFS): Reorder to match PSS.
+ (SUFFIXES): Remove .pdf and .aux.
+ (cvs.aux, cvs.pdf, cvsclient.aux, cvsclient.pdf): Remove these targets.
+ .aux weren't being generated anyhow and .pdf no longer need to be
+ supplied explicitly.
+ (cvs-paper.pdf: cvs-paper.ps): Provide ps2pdf rule explicitly.
+ (.{texinfo,texi,txy}.pdf): Remove these suffix rules - they are now
+ provided by Automake.
+
+2003-08-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (CLEANFILES): Move...
+ (MOSTLYCLEANFILES): ...here and drop PDFs since this is where Automake
+ cleans PDFs & PSs by default.
+ (MAINTAINERCLEANFILES): Clean all PostScripts even though they will
+ have been removed in mostlyclean. That is a bug in Automake.
+ (doc): Depend on info & ps.
+ (pdf, ps): Removed in favor of Automake's default targets for these
+ types.
+ (cvsclient.* targets): Depened on version-client.texi.
+ (cvs-paper.pdf): Remove in favor of Automake's default target.
+ (.{texinfo,texi,txi}.{pdf,txt}): Update these targets based on
+ Automake's similar treatment of dvi, ps, and info targets.
+ * .cvsignore: Add cvs.tmp, a `make pdf' generated file.
+
+ * Makefile.in: Regenerated.
+
+2003-07-21 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Expand comment on RCS terminology.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-07-20 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Setting up the server for password authentication):
+ Added documentation for PAM support.
+ (Original patch from Brian Murphy <brian@murphy.dk>.)
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Substitution modes): Improve the phrasing of the
+ description of the new treatment of -kb.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Put a few errant references to bug-cvs inside @code{}
+ for consistancy.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Update WARNINGs and Notes for a more consistent
+ appearance. Remove some obsolete comments.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Merging and keywords): Note that keyword expansion modes
+ requested on the command line no longer override binary mode. Removed
+ an obsoleted @ignore section.
+ (Common options): Ditto minus the @ignore section. Some reworking for
+ clarity.
+ (Original patch from Dieter Maurer <dieter@handshake.de>.)
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-07-12 Larry Jones <lawrence.jones@eds.com>
+
+ * cvs.texinfo (Binary howto): Add note about how to determine whether
+ a file is marked as binary or not.
+ (Suggested by Erik Sigra <sigra@home.se>.)
+ * stamp-vti: Regenerated.
+ * version.texi: Regenerated.
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-06-20 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-06-16 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (splitrcskeyword): New macro, now that @ifhtml will work
+ properly with texi2html (as of version 1.68), to cause output HTML to
+ contain <i></i> where we used to have @asis{} and prevent RCS keyword
+ substitution in generated HTML.
+ (Original patch from Patrice Dumas <dumas@centre-cired.fr>.)
+
+2003-06-16 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-06-12 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Invoking CVS): Remove `-P' from the list of `cvs export'
+ options.
+ (Patch from Alexander Taler <dissent@cvshome.org>.)
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Top): Remove out-of-date (by at least 5 years) comment.
+ (Patch from Alexander Taler <dissent@cvshome.org>.)
+
+2003-06-11 Mark D. Baushke <mdb@gnu.org>
+
+ * cvs.texinfo (Keyword list): Fix broken reference.
+ (Avoiding substitution): Ditto.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated for new configure.in.
+ * stamp-vti: Ditto.
+ * version.texi: Ditto.
+
+2003-06-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Keyword substitution): New menu entry for
+ "Configuring keyword expansion."
+ (Keyword list): New "CVSHeader" keyword. New Local keyword
+ controlled by new LocalKeyword option in CVSROOT/config.
+ (Avoiding substitution): Mention the new KeywordExpansion option
+ in CVSROOT/config.
+ (Configuring keyword expansion): Document the new KeywordExpansion
+ option in CVSROOT/config.
+ (Invoking CVS): New example of CVSHeader keyword expansion.
+
+2003-05-27 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Consolidate copyright notices into a single macro that
+ is called elsewhere to avoid needing three of them. Update copyright
+ notice.
+ (BUGS): Suggest Ximbiot rather than the defunct Signum Support as CVS
+ consultants.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-05-26 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated for 1.12.1.1.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2003-05-25 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated for 1.12.1.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Specifying what to tag by date or revision): Add a
+ missing a tag argument to the example.
+ (How your build system interacts with CVS): Correct typo.
+ (*): Let the spell checker have its way.
+ (Thanks to Anthon Pang <apang@telus.net> for the patch and
+ Max Bowsher <maxb@ukf.net> for validating it. This closes issue #84 on
+ <http://ccvs.cvshome.org>.)
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-28 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Working directory storage, Module options, Module
+ program options): Remove references to Checkin.prog and Update.prog.
+ (commit options): Remove reference to -n option.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-31 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (import output): Remove unecesary verbage.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-26 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-25 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Server temporary directory): Reorder list of places
+ to match code.
+ (Connection): Add additional example error message and note about
+ firewall software.
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-25 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-21 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Environment variables): Move @end table tag to after
+ the @item $CVSPID.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Connecting via rsh): Document that --with-rsh may
+ be used to specify the default "rsh" program to use.
+
+ * Makefile.in: Regenerated.
+
+ * cvs.texinfo (Environment variables): Document new CVS_PID
+ variable.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Global options): Document new `-R' global option
+ for read-only file-system repository mode.
+ (Environment variables): Document new CVSREADONLYFS environment
+ variable.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (rcsinfo): Document that CVS/Template will now be
+ updated during normal cvs update operations.
+
+2003-03-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (What is CVS?): Correct date of first post of CVS by
+ Dick Grune from December to July based on the archive posted on
+ Google:
+ <http://groups.google.com/groups?q=Grune+cvs+group:mod.sources.*&hl=en&lr=&ie=UTF-8&selm=122%40mirror.UUCP&rnum=2>.
+ (Thanks to David A Wheeler <dwheeler@dwheeler.com>.)
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-03-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (CVS_LOCAL_BRANCH_NUM): Document new environment
+ variable.
+
+2003-02-27 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Environment variables): Make the information on
+ CVS_CLIENT_PORT slightly clearer.
+ (Kerberos authenticated): XREF the Environment variables node.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+ * stamp-1: Ditto.
+ * version-client.texi: Ditto.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (admin): Mention UserAdminOptions.
+ (config): Ditto.
+ (Original patch from Dan Peterson <dbpete@aol.com>.)
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-02-24 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (*): Modify some tag index entries for uniformity.
+
+2003-02-14 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Watch Information, Editing files, Getting Notified,
+ Setting a watch): Edit usage specs for correctness and uniformity.
+ (Sticky tags): Use ref rather than xref to avoid a warning from
+ makeinfo.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-02-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Sticky tags, update): Make merging behavior of
+ `cvs update' a bit clearer. Add cross references.
+ (Thanks to Jenn Vesperman <jenn@anthill.echidna.id.au> for the
+ report.)
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-02-07 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2003-02-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Common options): Add tag to the list of commands that
+ accept -D.
+
+2003-02-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Working directory storage, Module options,
+ Module program options): Correct description of where Checkin.prog
+ and Update.prog are run. Provide more index entries and cross
+ references. Remove some FIXME comments. Add a FIXCVS THEN FIXME.
+ (Thanks to Art Manion at the CERT Coordination Center <cert@cert.org>.)
+
+2003-02-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (File status): Mention the "Unresolved Conflict" status
+ which was apparently and erroneously removed from the doc at some
+ point in the past.
+
+2003-02-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Merging a branch): Mention the GCA as opposed to the
+ "branch point" as the implicit revision when merging a branch.
+
+2003-02-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Remote repositories): :METHOD: is optional.
+
+2003-02-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Committing your changes): Move index entries closer to
+ their corresponding references.
+ (Environment variables): Include $VISUAL in order of
+ preference. Add index entries. Reference Global options node.
+ (Variables): Change order of list to match the Env. Variables node
+ mentioned above.
+
+ * stamp-1: Regenerated.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2003-01-31 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2003-01-23 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2003-01-22 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (config): Correct LogHistory default (U was omitted).
+
+2003-01-16 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated for version (1.11.5).
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2003-01-16 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated for dev version (1.11.4.1).
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2002-12-28 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated for version 1.11.4.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2002-12-27 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated for dev version 1.11.3.1.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2002-12-27 Derek Price <derek@ximbiot.com>
+
+ * stamp-1: Regenerated.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2002-11-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (commitinfo): Explain the environment of commands
+ run by commitinfo a little more fully.
+ (Original patch from Fred L. Drake, Jr. <fdrake@acm.org>.)
+
+ * cvs.texinfo: Change the wording of some of the commit index entries
+ for consistency and clarity.
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-09-20 Derek Price <derek@ximbiot.com>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2002-08-16 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo (Error messages): Update CVS_BADROOT notes to specify
+ new configure option instead.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2002-08-12 Derek Price <oberon@umich.edu>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2002-08-06 Derek Price <oberon@umich.edu>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2002-08-05 Derek Price <oberon@umich.edu>
+
+ * cvs.texinfo: Correct typo.
+ (Thanks to Chandra Mouleeswaran <chandra@openharbor.com>.)
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2002-04-18 Derek Price <oberon@umich.edu>
+
+ * Makefile.am: Add FIXME comment about an automake bug.
+ * Makefile.in: Regenerated.
+
+2002-04-18 Derek Price <oberon@umich.edu>
+
+ * stamp-1: Regenerated for 1.11.2.1 version update.
+ * stamp-vti: Ditto.
+ * version-client.texi: Ditto.
+ * version.texi: Ditto.
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * cvs.texinfo: Add index entries for inetd and xinetd.
+
+2002-03-26 Derek Price <oberon@umich.edu>
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2002-03-17 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (log options): Add new -S option.
+
+2002-03-12 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (diff options): Add missing menu for new subsections.
+ (Patch from Pavel Roskin <proski@gnu.org>.)
+
+2002-03-09 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Update imports): Suggest merging with two rel tags
+ instead of the branch tag and a date and explain why.
+
+2002-02-26 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (diff options): Document all the diff options.
+
+2002-01-10 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (log options): Update -r :: to match code changes.
+ (Variables): Document LOGNAME and USER environment variables.
+
+2001-12-03 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Invoking CVS): Add -F option for annotate and
+ rannotate.
+
+2001-11-28 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (File permissions): Add note about SGID being required
+ on some systems. Add note about LockDir.
+
+2001-10-18 Derek Price <dprice@collab.net>
+
+ * Makefile.am: Add --batch to texi2dvi invocations.
+ (Thanks to Akim Demaille <akim@epita.fr> for the suggestion.)
+
+ * Makefile.in: Regenerated.
+
+2001-10-04 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Connecting via rsh): Add : between host name and
+ root directory in example since some versions of CVS require it.
+ (Reported by Trevor Jim <trevor@research.att.com>.)
+
+2001-09-14 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (commit files): Make following sections (commitinfo,
+ verifymsg, editinfo, and loginfo) subsections of this one.
+
+2001-09-06 Derek Price <dprice@collab.net>
+
+ * cvs.texinfo (Watch information): Cleanup some watch/edit
+ explanations and discourage the belief that files should be
+ releasable.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+ (Patch from Eric Siegerman <erics@telepres.com>.)
+
+2001-09-05 Derek Price <dprice@collab.net>
+
+ * cvsclient.texi: Use version-client.texi instead of version.texi so
+ cvsclient.* can have a different build date than cvs.texinfo.
+
+ * Makefile.in: Regenerated.
+ * stamp-1: New file.
+ * version-client.texi: Ditto.
+ (Reported by Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+ * version.texi: Ditto.
+
+2001-08-24 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Error messages): Add new message about root not
+ being allowed to do commit.
+
+2001-08-24 Derek Price <dprice@collab.net>
+
+ * cvs.texinfo (config): Add a new RereadLogAfterVerify
+ CVSROOT/config option to control how verifymsg scripts deal with
+ read-write log messages.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+ * cvs.texinfo (verifymsg): The verification script may now modify
+ the log message.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+ * cvs.texinfo (config, verifymsg): Correct default, changes for clarity,
+ and add a warning about `stat' and large repositories.
+
+ * version.texi: Regenerated.
+ * stamp-vti: Ditto.
+
+2001-08-20 Derek Price <dprice@collab.net>
+
+ * Makefile.am: Reformat comment for 80 chars.
+
+ * Makefile.in: Regenerated.
+
+2001-08-10 Derek Price <dprice@collab.net>
+
+ * cvs.texinfo (Default options and the ~/.cvsrc file): Added a few more
+ "standard" options to the example.
+
+ * stamp-vti: Regenerated.
+ * version.texi: Ditto.
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-17 Derek Price <dprice@collab.net>
+
+ * version.texi: Regenerated.
+ * stamp-vti: Ditto.
+
+2001-07-06 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Variables): Add index entry for CVS_USER.
+ (Reported by Jens Schweikhardt <Jens.Schweikhardt@marconi.com>.)
+ (Working directory storage): Fix Emptydir index entry: Emptydir
+ is a directory, not a file.
+
+2001-07-05 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Working directory storage): Add Emptydir to index.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.am: Reference to CVSvn.texi removed.
+ * cvs.texinfo: @include version.texi and change CVSVN to VERSION.
+ * cvsclient.texi: Ditto.
+
+ * version.texi: New file.
+ * stamp-vti: Ditto.
+ * mdate-sh: New File. Work-around bug in Automake 1.4f by copying
+ top-level mdate-sh here.
+
+ * CVSvn.texi.in: Removed.
+ * CVSvn.texi: Ditto.
+
+ * Makefile.in: Regenerated.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2001-06-27 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (loginfo): Note that format string expansion is
+ quoted and contains escapes.
+
+2001-06-22 Derek Price <dprice@collab.net>
+
+ * cvs.texinfo (checkout options): Fix transliteration typo in co
+ example.
+ (Patch from Adrian Aichner <adrian@xemacs.org>.)
+
+2001-06-12 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Global options): Note that -T only affects the local
+ process in client/server mode.
+ (Environment variables): Note that CVS_SERVER can include arguments
+ as well as a program name, and note that it applies to :fork: as well
+ as to :ext: and :server:, although the default value is different.
+
+2001-06-08 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (config): Mention using LockDir on in-memory
+ filesystem to speed up locking.
+
+2001-06-07 Derek Price <dprice@collab.net>
+
+ * Makefile.am (EXTRA_DIST): Remove *.aux.
+ (MOSTLYCLEAN_FILES): Remove this macro since the Automake bug it was
+ working around has been fixed.
+
+2001-06-07 Derek Price <dprice@collab.net>
+
+ * HACKING.DOCS: Add link to the main texinfo documentation.
+
+2001-06-07 Derek Price <dprice@collab.net>
+
+ * README.DOCS: Rename to
+ * HACKING.DOCS: this.
+
+2001-06-07 Derek Price <dprice@collab.net>
+
+ * README.DOCS: New file attempting to document some of our texinfo
+ conventions.
+
+2001-06-06 Derek Price <dprice@collab.net>
+
+ (Reformatting, rewording, & additions to a patch from
+ Stephen Cameron <steve.cameron@compaq.com>.)
+
+ * cvs.texinfo (Invoking cvs, Modifying tags)
+ document new -B option of rtag and tag commands.
+
+2001-06-04 Derek Price <dprice@collab.net>
+
+ * Makefile.am: Remove commented out DISTFILES &
+ AUTOMAKE_OPTIONS=no-texinfo.tex.
+ (Reported by Alexey Mahotkin <alexm@hsys.msk.ru>.)
+ * Makefile.in: Regenerated.
+
+2001-06-04 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.am: Fix rules for cvs-paper (.pdf rule actually generated
+ .ps and vice versa).
+ (Reported by Alexey Mahotkin <alexm@hsys.msk.ru>.)
+ * Makefile.in: Regenerated.
+
+2001-05-29 Derek Price <dprice@collab.net>
+
+ * cvs.texinfo (Repository): Fix explanation of CVSROOT parsing
+ algorithm.
+
+2001-05-29 Derek Price <dprice@collab.net>
+ patch from Pavel Roskin <proski@gnu.org>
+
+ * Makefile.am (CVSvn.texi): Double hash comment in rule since single
+ hash comments are not portable.
+
+ * Makefile.in: Regenerated.
+
+2001-05-21 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Error messages): Fix ordering; add "cannot commit
+ files as root".
+
+ * cvs.texinfo (Invoking CVS): Add entries for kserver, pserver,
+ rannotate, rlog, and server.
+
+ * cvs.texinfo: Lots of minor editorial corrections. Mostly adding
+ @noindent after examples where the following text is intended to
+ be a continuation of the preceding text, not a new paragraph.
+
+ * cvs.texinfo (Connection): Replace information about unsetting
+ $HOME for people with old releases.
+
+
+ * cvs.texinfo (Connecting via rsh): Use @samp{} instead of @file{}
+ where it seemed appropriate.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>).
+
+2001-05-18 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Password authentication server): Add xinetd info.
+ (Connection): Add "broken pipe" to possible error messages.
+
+2001-05-18 Derek Price <dprice@collab.net>
+
+ * cvs.texinfo (update output): Change wording to something that sounds
+ a bit more like english.
+
+2001-05-02 Derek Price <dprice@collab.net>
+
+ * cvs.texinfo (Top): Change @ifinfo to @ifnottex to placate HTML
+ generators.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * CVSvn.texi: Regenerated.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * CVSvn.texi: Regenerated.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+ * CVSvn.texi: Regenerated.
+
+2001-03-30 Larry Jones <larry.jones@sdrc.com>
+
+ * cvsclient.texi (Dates, Requests): Add rannotate and rlog.
+
+2001-03-26 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (admin options): Fix typo: should be @pxref, not @xref.
+
+2001-03-26 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (admin options): Update description of -u option to
+ refer back to notify.
+
+2001-03-23 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (ps): Make 'ps' an alias for 'doc'.
+ (doc, pdf, ps, txt): declare as '.PHONY'.
+
+ * Makefile.in: Regenerated.
+
+2001-03-23 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (MOSTLYCLEANFILES): Add cvs.cps & cvs.fns as a temporary
+ workaround for an Automake deficiency.
+
+ * Makefile.in: Regenerated.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2001-02-20 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (BUGS): There's only one company listed now, not two.
+
+2001-02-13 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Password authentication server, First import): Use
+ @ref instead of @xref when not at the beginning of a sentence.
+
+2001-02-01 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Connection): Add still more notes about common
+ pserver error messages.
+
+2001-01-18 Derek Price <derek.price@openavenue.com>
+
+ * cvs.texinfo (Quick reference to CVS commands): add index entry for
+ version subcommand
+
+2001-01-18 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (log options): Document new :: syntax for -r.
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (CVSvn.texi): specify $(srcdir) explicitly in target rule
+ so CVSvn.texi gets built properly for all makes.
+ (cvs_TEXINFOS): specify $(srcdir) explicitly for CVSvn.texi
+ (cvsclient_TEXINFOS): ditto
+ * Makefile.in: regenerated
+
+2000-12-26 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: update timestamp
+ * CVSvn.texi: ditto
+
+2000-12-26 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: new target for creation of CVSvn.texi
+ (EXTRA_DIST): add CVSvn.texi.in & CVSvn.texi
+ * Makefile.in: Regenerated
+ * CVSvn.texi: new file
+ * .cvsignore: remove CVSvn.texi since it is now included in dist
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * cvs-paper.ps: Backout accidental regeneration.
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * .cvsignore: Added *.pdf versions of the *.ps docs
+ * CVSvn.texi.in: Use configure to generate CVSvn.texi
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+ * cvs-paper.ps: Regenerated
+ * texinfo.tex: New file added to placate Automake. Apparently, its
+ inclusion is mandated by the GNU coding standards.
+
+2000-12-14 Derek Price <derek.price@openavenue.com>
+ Linus Tolke <linus@epact.se>
+
+ * cvs.texinfo (Merging a branch): changed some references to "BRANCH"
+ to "BRANCHNAME" for consistancy. Add a warning about merging using a
+ single tagname reference with an xref to "Merging adds and removals"
+ for the long explanation
+ (Merging adds and removals): Add the long explanation of why merging
+ from a single tagname can be tricky
+ (update): Add a warning about merging using a single tagname reference
+ with an xref to "Merging adds and removals" for the long explanation
+
+2000-11-13 Derek Price <derek.price@openavenue.com>
+
+ * cvs.texinfo: use '@sc{cvs}' instead of 'CVS' in various locations
+
+2000-11-08 Derek Price <derek.price@openavenue.com>
+
+ * cvs.texinfo (settitle): stick a 'v' in front of the version number
+ to make it harder to confuse with chapter, section, and page numbers.
+
+2000-11-08 Derek Price <derek.price@openavenue.com>
+
+ * cvs.texinfo (settitle): add the version number to the title string
+ so that it is easier to find on HTML pages and the like.
+
+2000-10-20 Jim Kingdon <http://sourceforge.net/users/kingdon/>
+
+ * cvs.texinfo (Variables): Document CVS_USER.
+
+2000-10-17 Derek Price <derek.price@openavenue.com>
+
+ * cvs.texinfo (Remote repositories): added a comment about specifying
+ a password in the repository name when performaing a checkout.
+
+2000-10-17 Derek Price <derek.price@openavenue.com>
+
+ * cvs.texinfo (Remote repositories, password authenticated, GSSAPI
+ authenticated, Kerberos authenticated, Environment variables):
+ Documented CVSROOT spec change & CVS_CLIENT_PORT.
+
+2000-10-10 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Connection): Add additional notes about common
+ pserver error messages. Remove information about unsetting $HOME
+ since CVS no longer pays any attention to it in server mode.
+
+2000-09-07 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@
+ from autoconf.
+
+2000-08-21 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Removing directories, export): Note that export always
+ prunes directories and remove references to the non-existent -P flag.
+
+2000-07-28 Larry Jones <larry.jones@sdrc.com>
+
+ * cvsclient.texi (Requests): Ensure that all rootless requests say
+ that they're rootless.
+
+2000-07-12 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Module program options): Remove note that commit and
+ update programs only working locally; they've worked client/server
+ for quite some time.
+
+2000-07-10 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Invoking CVS): Document new version command.
+ * cvsclient.texi (Requests): Document new version request.
+
+2000-07-06 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (admin options): Remove note about -t not working
+ in client/server.
+
+2000-04-03 Pavel Roskin <pavel_roskin@geocities.com>
+
+ * cvs.texinfo (Telling CVS to notify you): Remove backslashes
+ before quotes.
+
+2000-05-24 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (From files): Clean up @var{wdir}/@var{rdir} vs.
+ @var{dir} usage.
+
+2000-05-19 Larry Jones <larry.jones@sdrc.com>
+
+ * cvsclient.texi (Requests): Note that Global_option is now
+ valid without Root.
+
+2000-04-17 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Variables): Clarify what USER means in pserver.
+
+2000-03-08 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Connection): Add note about inetd rate limit.
+ (ErrorMessages): Add root home directory permission messages.
+
+2000-02-12 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: Clean up text/formatting of previous change.
+
+2000-02-21 K.J. Paradise <kj@sourcegear.com>
+
+ * cvs.texinfo : Adding John Cavanaugh's patch to allow
+ the history file to log actions based on the CVSROOT/config
+ file. (To limit which cvs actions actually make it into the
+ history file)
+
+2000-02-17 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: Remove references to PreservePermissions.
+
+ * cvs.texinfo (history options): Note default report type.
+
+2000-01-18 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Global options): Document compression levels.
+
+2000-01-18 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: Minor editorial changes from Ken Foskey
+ <waratah@zip.com.au>.
+
+2000-01-11 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: Add index entries for "Compression" and "Gzip".
+ Correct typography in many index entries (English phrases should
+ have initial caps, subcommands/files/etc. should be as-is).
+
+2000-01-10 Karl Fogel <kfogel@red-bean.com>
+
+ * cvs.texinfo (loginfo): correctly describe CVSROOT/loginfo's
+ %-expansion behavior. Thanks to Karl Heinz Marbaise
+ <kama@hippo.fido.de> for noticing the error.
+
+2000-01-07 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Password authentication server): Use -f in example
+ inetd.conf line.
+ (Connection): Add advice about using shell script or env to avoid
+ problems with inetd setting HOME in the server's environment.
+ (various): Use @file for inetd.conf.
+
+2000-01-02 John P Cavanaugh <cavanaug@sr.hp.com>
+
+ * cvs.texinfo: document new -C option to update, now that it works
+ both remotely and locally.
+ (Re-applied by Karl Fogel <kfogel@red-bean.com>.)
+
+1999-12-11 Karl Fogel <kfogel@red-bean.com>
+
+ * Revert previous change -- it doesn't work remotely yet.
+
+1999-12-10 John P Cavanaugh <cavanaug@sr.hp.com>
+
+ * cvs.texinfo: document new -C option to update.
+ (Applied by Karl Fogel <kfogel@red-bean.com>.)
+
+1999-11-20 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo(history options): Document -f, -n, and -z.
+
+1999-11-09 Jim Kingdon <http://developer.redhat.com/>
+
+ * cvsclient.texi (Requests): Document the arguments to "log", now
+ that I've changed log.c to be more specific in terms of what it
+ will send.
+
+1999-11-05 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: Revert Karl's change once again since the code is now
+ fixed. Add "Variables" and "User variables" to index.
+
+1999-11-04 Karl Fogel <kfogel@red-bean.com>
+
+ * log.c (log_usage): Revert Jim Kingdon's reversion of my change
+ of 1999-11-03. Allowing a space between option and argument
+ results in lossage; here is a reproduction recipe: run this from
+ the top of a remote copy of the cvs source tree
+
+ cvs log -d '>1999-03-01' > log-out.with-space
+
+ and then run this (note there's no space after -d now):
+
+ cvs log -d'>1999-03-01' > log-out.no-space
+
+ The resulting files differ; furthermore, a glance at the output of
+ cvs shows that the first command failed to recurse into
+ subdirectories. Until this misbehavior can be fixed in the source
+ code, the documentation should reflect the true state of affairs:
+ if one simply omits the space, everything works fine.
+
+1999-11-04 Jim Kingdon <http://developer.redhat.com/>
+
+ * cvs.texinfo (log options): Revert Karl's change regarding -d and
+ -s. A space is allowed (see sanity.sh for example).
+
+ * cvs.texinfo (Password authentication server): The name of the
+ file is "passwd" not "password".
+
+ * cvsclient.texi (Top): Add @dircategory and @direntry.
+
+1999-11-04 Karl Fogel <kfogel@red-bean.com>
+
+ * cvs.texinfo (Password authentication server, Password
+ authentication client): Rewritten to accommodate the [new]
+ possibility of empty passwords.
+
+1999-11-03 Karl Fogel <kfogel@red-bean.com>
+
+ * cvs.texinfo (Invoking CVS): correct documentation for -d and -s
+ options (as did elsewhere, earlier today).
+
+1999-11-03 Karl Fogel <kfogel@red-bean.com>
+
+ * cvs.texinfo (Setting a watch): describe `watch off' behavior
+ more accurately.
+
+1999-11-03 Karl Fogel <kfogel@red-bean.com>
+
+ * cvs.texinfo (log options): correct documentation for -d and -s
+ options. There can be no space between these options and their
+ arguments.
+
+ Also, make sure all @sc{cvs} codes refer to "cvs" in lower case;
+ this avoids makeinfo warnings. And use @code for the CVSEDITOR
+ environment variable, not @sc.
+
+1999-09-24 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: Misc. formatting cleanups.
+
+1999-07-16 Tom Tromey <tromey@cygnus.com>
+
+ * cvs.texinfo (admin): Mention admin -k exception. Add cvsadmin
+ to index.
+
+1999-07-14 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Password authentication server): Note inetd limits
+ and suggest using shell script to avoid.
+
+1999-06-01 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): For the import command, the
+ repository given to the Directory requests is ignored.
+
+1999-05-27 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): Clarify that Modified, Is-modified,
+ Notify and Unchanged must specify a file within the current
+ directory.
+
+1999-05-24 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (checkoutlist): New node, contains more complete
+ documentation of this feature.
+ (CVSROOT storage): Refer to the new node when mentioning
+ checkoutlist.
+ (Administrative files): Update the menu entry for Wrappers.
+
+1999-05-17 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): For Notify request, strike duplicate
+ "Response expected: no" and fix "a edit" -> "an edit".
+
+1999-05-14 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Try to be more clear
+ about the conflict field.
+
+1999-05-11 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (config): Use comma after @xref (thanks to Pavel
+ Roskin for the report/fix).
+
+1999-05-10 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): Document restrictions on characters
+ in Notify requests.
+
+1999-05-04 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Password authentication security): Remove sentence
+ about how no one has audited pserver for holes; a lot of holes
+ have been closed, looking for, &c, since that was written.
+ In the summary, reword to reflect the fact that sniffing a
+ readonly password does not imply general system access (as far as
+ I know, of course).
+
+ * cvs.texinfo (Connection): Also suggest inetd -d.
+
+1999-04-28 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): Say what goes in the "watches" field
+ of the "Notify" request.
+
+ * cvs.texinfo (Common options): -r is for branches too.
+
+ * cvs.texinfo (Error messages): Add "no such tag" message.
+ (Common options): -f does not override val-tags check.
+
+1999-04-26 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Locks): #cvs.rfl locks must start with "#cvs.rfl."
+ not just "#cvs.rfl". As far as I know CVS has always implemented
+ the former behavior, and this just fixes the documentation.
+
+1999-04-23 Yoshiki Hayashi of u-tokyo.ac.jp
+
+ * cvs.texinfo (verifymsg): Correct wrong file name (bugid.edit ->
+ bugid.verify).
+
+1999-04-22 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Responses): The text in the "M" response is not
+ designed for machine parsing. Likewise for "error" in regular
+ protocol. Likewise for "E" and "error" in authentication protocol.
+
+1999-04-19 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "Cannot check out files into
+ the repository itself".
+
+1999-04-16 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Other problems): Add the Windows problem with home
+ directory ending in a slash.
+
+1999-04-14 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (CVS in repository): Include the format of the
+ fileattr file here, rather than referring to the CVS source code.
+
+1999-04-09 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Whether the timestamp
+ in CVS/Entries is local or universal actually depends on the system.
+
+1999-04-05 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * cvs.texinfo (export options): Remove notation that the -r
+ tag is sticky. 'cvs export' doesn't store that data.
+
+1999-04-08 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "EOF in RCS file" and
+ "unexpected EOF" (in RCS file) messages.
+
+1999-03-25 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (admin options): Say there can be no space between
+ -e and its argument (since the previous sentence said the argument
+ can be omitted, this is the only possibility).
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Merging and keywords): When including conflict
+ markers, put @asis{} at the start of the line, in case this file
+ itself is in CVS. Thanks to Derek Price for pointing this out.
+
+1999-02-25 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo: Refer to "keywords" not "RCS keywords". We had
+ only used the latter term in a few places, and it seems like a
+ somewhat odd term in that this style of keyword is by no means
+ specific to RCS.
+ (Merging a branch): Remove spurious ")". Use ref, not xref, after
+ "see".
+ (Merging a branch, Substitution modes): Make sure that @ref is
+ followed by comma, since info wants that.
+ (Merging and keywords): Use samp not code for "-kk". Something of
+ a judgement call, but the rest of the manual uses samp and that
+ seems better to me.
+ (Merging and keywords): Rewrite, to (a) better motivate the
+ discussion based on what the user wants to do, (b) fix up lots of
+ convoluted sentences, (c) move the discussion of the binary files
+ to the end, that is get across the basic idea first and then
+ embellish it. Remove a few unnecessary index entries. Expand
+ example. Just tell people to avoid -kk with binary files (comment
+ out the discussion of using -A after the commit).
+
+1999-01-29 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * cvs.texinfo: Added new node/section on merging and keywords. It
+ contains advice on how to avoid RCS keyword conflicts when merging
+ and avoid corrupting your binary files while doing it.
+
+1999-02-24 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Request intro): Add paragraph about transmitting
+ more than one command.
+
+1999-01-29 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo: Use EXAMPLE.COM EXAMPLE.ORG and EXAMPLE.NET instead
+ of domains which might conflict with actual (current or future)
+ domains. The EXAMPLE domains are registered for this purpose.
+
+1999-01-22 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Sticky tags): Refer to -j as the better way to undo
+ a change.
+ (Merging two revisions): Also talk about undoing removals and
+ adds. Move the index entries to here.
+
+1999-01-21 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "waiting for USER's lock".
+
+1999-01-16 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Comment out all the -t/-f documentation,
+ since that feature is currently disabled.
+
+1999-01-14 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Connecting via rsh): Add some more index entries so
+ that people who want to use SSH and such are slightly less lost.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs-paper.ms: Remove comments which contained the FSF's old
+ address; it has changed.
+
+1998-12-29 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Dates): Numeric timezones are preferred.
+ Also mention the Checkin-time request.
+
+1998-12-23 Jim Kingdon <http://www.cyclic.com>
+
+ * RCSFILES: Add clarification about certain character set issues
+ from Paul Eggert, the RCS maintainer. The last paragraph and the
+ change from Shift-JIS to JIS as an example of a character set
+ which contains 0x40 bytes which are not '@' characters are mine;
+ the rest is directly from Paul Eggert.
+
+1998-12-22 Martin Buchholz <martin@xemacs.org>
+
+ * cvs.texinfo: Fixed various trivial typos.
+
+1998-12-17 Jim Kingdon
+
+ * cvsclient.texi (Responses): Explicitly say that Mod-time need
+ not be sent for all files.
+
+1998-12-16 Jim Kingdon
+
+ Thanks to Ram Rajadhyaksha of the MacCVS Pro team for raising the
+ following issues.
+ * cvs.texinfo (Working directory storage): The deal about storing
+ files as text files applies to all the CVS/* files, not just
+ CVS/Entries. State the rationale too.
+ Document CVSROOT/Emptydir in CVS/Repository.
+ There is no set order in CVS/Entries.
+ Explicitly say that writing Entries.Log is optional.
+
+1998-12-03 Jim Kingdon
+
+ * cvs.texinfo (Error messages): Add "unrecognized auth response".
+ (Password authentication server): Remove comment about
+ "unrecognized auth response" and link to the troubleshooting
+ section.
+
+1998-12-02 Jim Kingdon
+
+ * cvs.texinfo (Multiple repositories): Add an example.
+
+1998-11-18 Jim Kingdon
+
+ * cvs.texinfo (Invoking CVS): Change "-r tag" to "-r rev". We
+ already use "tag" as the name of the tag we are adding.
+
+1998-11-13 Jim Kingdon
+
+ * cvs.texinfo (CVS commands): Add comment about whether part of
+ the manual should be organized by command.
+
+1998-11-06 Jim Kingdon
+
+ Clean up various confusions between modules and directories:
+ * cvs.texinfo: In "are you sure you want to release" message,
+ change module to directory. CVS was changed some time ago.
+ (Tags): "working copy of the module" -> "working directory".
+ (Merging two revisions): Remove unnecessary text "that make up a
+ module".
+ (Recursive behavior): Change "module" to "directory".
+ (Removing files): Likewise.
+ (Tracking sources): Remove "a module" from titles.
+ (Moving directories): Change "module" to "parent-dir".
+ (Inside): Remove "of the module".
+ (Inside): Change "module" to "dir".
+ (Rename by copying): Change "module" to "dir".
+ (Rename by copying): Remove "of the module".
+ (Moving directories): "copy of the module" -> "checked out copy of
+ the directory"; remove second "of the module". Change "check out
+ the module" to " check out again".
+ (Moving directories): Remove "of the module".
+ (Keyword substitution): "your working copy of a module" -> "a
+ working directory".
+ (CVS commands): Change "module" to "directory".
+ (release examples): "module" -> "tc directory".
+ (commitinfo): "relative path to the module" -> "directory in the
+ repository".
+ (verifymsg): Change "module" to "directory".
+ (Updating a file): "working copy of a module" -> "working directory".
+
+1998-10-25 Jim Kingdon
+
+ * cvs.texinfo (Branches and revisions): Fix error in branch
+ numbering which was introduced with change of 4 May 1997.
+
+1998-10-20 Jim Kingdon
+
+ * cvs.texinfo (Tags): Point to Invoking CVS node so people aren't
+ left wondering what the syntax is. When introducing -r option,
+ warn people about sticky tags right off.
+ (Tagging the working directory, Tagging by date/tag, Modifying
+ tags, Tagging add/remove): New sections.
+ (Invoking CVS): Adjust tag and rtag to point to the new sections,
+ and to add tag -c which had been omitted. Delete tag -n; there is
+ no such option.
+ (rtag, tag): Removed; no longer needed.
+ (commit examples): Update xref.
+
+1998-10-15 Jim Kingdon
+
+ * cvsclient.texi (Requests): It is OK to send Set before Root.
+
+1998-10-13 Jim Kingdon
+
+ * cvsclient.texi (Protocol Notes): Remove item about "cvs update"
+ sending modified files to the server; there are some better ideas
+ at http://www.cyclic.com/cvs/dev-update.txt
+ Add mention of www.cyclic.com.
+
+1998-09-30 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Committing your changes, Environment variables):
+ Document VISUAL.
+
+1998-09-27 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication server): Say explicitly
+ that you edit passwd directly, many users get confused by this.
+
+1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Connecting via fork): :fork: may be of interest to
+ users, for example those who prefer CVS to prompt for one log
+ message per checkin, rather than one per directory.
+ (Connecting via fork): Document CVS_SERVER.
+
+1998-09-24 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (Connecting via fork): new node about the fork
+ access method.
+
+1998-09-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Environment variables): Document
+ CVS_IGNORE_REMOTE_ROOT in the CVS 1.10 context.
+ (Moving a repository): Update comments concerning surgery on
+ CVS/Root and CVS/Repository files.
+
+1998-09-21 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (Environment variables): remove information about
+ CVS_IGNORE_REMOTE_ROOT, since it's no longer used.
+
+1998-09-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (config): Mention that CVS 1.10 doesn't have
+ LockDir.
+
+1998-09-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list): Describe $Name and checking out with
+ a revision.
+
+1998-09-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: RFC2346 is out; update comment.
+
+1998-09-13 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list, Substitution modes): In describing
+ $Locker and -kkvl, refer to cvs admin -l.
+
+ * cvsclient.texi (Requests): Re-word description of Sticky to
+ allow room for "Ntagname" (or other, future, values).
+
+ * cvs.texinfo (tag): Remove confusing wording about supplying
+ revision numbers "implicitly".
+
+1998-09-10 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (rdiff options): Thanks to the diff library, -u is
+ supported regardless of your diff program.
+
+1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (config): Add LockDir.
+
+1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): "Directory" and "Argument" are
+ requests, not commands. Likewise for "other-request". A command,
+ roughly, is a request that uses "Argument"s, but we might want to
+ phase out the use of that term more so than codify it, I'm not sure.
+
+1998-09-01 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvsclient.texi (Requests): added a detailed explanation of the
+ Directory request and how it is handled, both for pre-1.10 and
+ post-1.10 servers.
+
+1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Multiple repositories): Also describe the CVS 1.10
+ behavior. Looking at a mismatched version of the manual seems to
+ be a reasonably common occurrence.
+
+ * cvs.texinfo (Environment variables): Revert change regarding
+ CVS_SERVER_SLEEP*; having that kind of debugging code in the main
+ CVS is getting out of hand.
+
+1998-09-01 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (Multiple repositories): brief mention that cvs now
+ handles a working directory composed of multiple repositories.
+ (Environment variables): add note about CVS_SERVER_SLEEP2.
+
+1998-08-21 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvsclient.texi (Text tags): Document importmergecmd tag.
+
+1998-08-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Replace out of date URL concerning
+ ISO8601 dates with a more general statement and a few comments.
+
+1998-08-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Add "Checkin-time" request.
+
+Sun Jul 26 02:42:20 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (config): TopLevelAdmin variable.
+
+ * cvsclient.texi (Requests): fix typo.
+
+1998-07-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): "remove" is like "add" in the sense
+ that it is the "ci" request which does most of the work.
+
+1998-06-23 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Excluding directories): Fix order of
+ "!first-dir/sdir" and "first-dir" to match what CVS actually
+ accepts. Reported by Tim McIntosh of sterling.com.
+
+1998-06-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Using keywords): Rewrite to be less specific to
+ source code in C. The old text was worse than that; it was
+ specific to certain versions of GCC (not even current GCC's, I
+ don't think) (reported most recently by Mitchell Perilstein;
+ if memory serves by others before that).
+
+1998-06-08 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Concurrency): Also mention #cvs.lock. Don't
+ mention #cvs.tfl; it is quite old (before CVS 1.5).
+ (Locks, Backing up, Concurrency): Add more index entries.
+
+1998-06-03 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (Tracking sources): Clarify that the vendor branch
+ is only made the head revision when you import a new file, not any
+ time you import a file.
+
+1998-05-23 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (What is CVS?): info-cvs-request is now at gnu.org
+ and is no longer handled by a human (hallelujah).
+
+1998-05-12 Jim Meyering <meyering@ascend.com>
+
+ * cvs.texinfo: Add an info dir entry.
+ Remove trailing white space.
+
+1998-05-05 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Be more explicit that -m 'COPY' has no
+ effect on binary files.
+
+1998-05-02 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * RCSFILES: Add more discussion of the order of the revisions.
+
+1998-04-27 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (loginfo example): Also give example of sending
+ mail. Use internal variable $USER rather than expecting CVS to
+ set the environment variable $USER. Change unnecessary 'sed'
+ invocation to 'cat' (it suffered from the same problem in terms of
+ internal variables versus environment variables).
+
+ * cvs.texinfo (Error messages): Add "conflict: removed FILE was
+ modified by second party".
+
+1998-04-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Update comment about meaning of
+ HEAD in cvs diff.
+
+1998-04-12 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Dates): Also mention log -d.
+
+ * cvs.texinfo (Invoking CVS): No space is allowed between -r or -w
+ and its argument, for the log command.
+
+1998-04-11 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Dates): New section, explaining the deal with
+ date formats.
+
+1998-04-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Global options, Invoking CVS): Fix typo
+ ("files files" -> "files").
+ (Invoking CVS): Make -q and -Q more concise.
+ (Invoking CVS): Use @var for metavariables in "diff -r".
+
+1998-03-17 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (~/.cvsrc): In example, put "checkout" rather than
+ "co" into .cvsrc; we just finished explaining that only the former
+ works! Thanks to Lenny Foner for reporting this.
+
+ * cvs.texinfo (Copying): Remove this node. This basically
+ restores the status quo prior to 18 Oct 1996 (before then the node
+ existed but was empty).
+ (before Top): Adjust copyright notice accordingly.
+
+1998-03-12 Tim Pierce <twp@skepsis.com>
+
+ * RCSFILES: Updated description of `hardlinks' newphrases.
+
+1998-03-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Tags, Sticky tags, Creating a branch, Accessing
+ branches): Rename release-0-1 tag to rel-0-1 and likewise for
+ release-0-1-patches and release-0-4. This fixes an overfull hbox.
+ (diff options): Reformat table to fix underfull hboxes and such.
+
+1998-03-07 Tim Pierce <twp@skepsis.com>
+
+ * cvs.texinfo (Editing files, Special Files): Document hardlinks.
+ Various cleanups to PreservePermissions text.
+ * RCSFILES: Document PreservePermissions newphrases.
+
+1998-03-04 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Special Files): Add notes about client/server CVS
+ and hard links across directories.
+
+1998-03-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keeping a checked out copy): The magic loginfo
+ incantation isn't too likely to work except on unix.
+
+1998-02-23 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (user-defined logging): Double "@" literal.
+
+1998-02-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (user-defined logging): Add taginfo example.
+
+1998-02-04 Tim Pierce <twp@skepsis.com>
+
+ * cvs.texinfo (config): PreservePermissions variable.
+ (Special Files): New.
+ (Editing files): Add note about PreservePermissions.
+
+Tue Feb 10 18:07:35 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Connection): New node.
+
+ * cvsclient.texi (Protocol): Fix typo (lots -> lost).
+
+Sun Feb 8 21:39:22 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Invoking CVS): For admin -b, point to the section
+ where we talk about reverting to vendor branch.
+
+ * cvs.texinfo (Invoking CVS, rdiff options): Document rdiff -V
+ option as obsolete, since it was made a fatal error some time ago.
+
+ * cvs.texinfo (Invoking CVS): Add global options, keywords, and
+ keyword substitution modes. Wording fix in reference to --help
+ and Index.
+
+Wed Jan 28 23:09:39 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Excluding directories): Add index entry for "!".
+
+28 Jan 1998 Karl Fogel and Jim Kingdon
+
+ * cvsclient.texi (Requests, Responses): document
+ "wrapper-sendme-rcsOptions" and "Wrapper-rcsOption".
+
+Tue Jan 27 18:37:37 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (Excluding directories): New node, documenting how
+ to exclude directories using ! in an alias module.
+
+Sun Jan 18 18:23:02 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Add Kopt request.
+
+Thu Jan 1 17:36:42 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (BUGS, Credits): Change @unnumbered to @appendix now
+ that these are moved from the start to the end.
+
+Sat Dec 27 10:06:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "Too many arguments!".
+
+Fri Dec 26 18:30:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (What is CVS?): Just point to the two canonical web
+ sites (Pascal Molli and Cyclic) concerning CVS downloads. The GNU
+ URL was out of date and GNU only has source distributions anyway.
+
+ * cvs.texinfo: Change bug-cvs address to gnu.org per email from
+ Martin Hamilton.
+
+Tue Dec 23 18:04:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Sticky tags): Further cleanups. Fix thinko
+ (s/subsequent cvs update/& commands/). Remove "vi driver.c" and
+ commit from example (totally vestigial). Reword start of
+ paragraph on non-branch sticky tags, so that it better alludes
+ to branch sticky tags. When introducing sticky tags, make it
+ clear that even people who aren't trying to use sticky tags
+ may need to know how to avoid them. Restore comment about
+ CVS/Tag files.
+ (Accessing branches): Don't xref to merging here; that is a much
+ more advanced topic and the "but see" wording didn't tell us what
+ to see the xref about.
+
+Tue Dec 23 14:39:08 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Jim Kingdon
+
+ * cvs.texinfo (Creating a branch): Rewritten. Introduce with
+ `tag', then discuss `rtag' and `-r'.
+
+Tue Dec 23 10:03:37 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Jim Kingdon
+
+ * cvs.texinfo: Changes to dehairify the "Sticky tags" situation:
+ (Revisions): "Sticky tags" moved here, description in menu changed
+ to be a little more informative.
+ (Sticky tags): Moved from "Branching and merging" to "Revisions".
+ (Accessing branches): New node in "Branching and merging",
+ explains how to use checkout vs update to retrieve a branch.
+ Text and example inherited from "Sticky tags", but text mostly
+ rewritten.
+ (Sticky tags): Moved under "Revisions", rewritten somewhat (more
+ rewrites to follow).
+ Don't use "-v" in "cvs status" example.
+
+Mon Dec 22 11:46:05 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Jim Kingdon
+
+ Cleanups related to recent separation of revisions from
+ branching/merging:
+ * cvs.texinfo (Revisions): Take paragraph introducing branches,
+ rewrite it and move it to "Branching and merging".
+ (Branching and merging): Also rewrite merging intro.
+ (Revision numbers): Don't go into detail about branch revision
+ numbers here, just mention that they happen and refer to new
+ node "Branches and revisions".
+ (Branches and revisions): New node under "Branching and merging",
+ inherits text from "Revision numbers".
+ (Creating a branch): Refer to "Branches and revisions" now, not
+ "Revision numbers".
+ (Binary why): Rewrite sentence which refers to merging, so that
+ it isn't specific to branch merging.
+ (Branches motivation): Fix typo (select -> elect). Add comment
+ about what this node is accomplishing, in general.
+
+Sun Dec 21 20:57:24 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Jim Kingdon
+
+ This is just moving text; related cleanups to follow.
+ * cvs.texinfo: Changes to put branching and merging together, and
+ keep it all separate from revisions:
+ (Revisions): Renamed from "Revisions and branches".
+ (Branching and merging): Renamed from "Merging".
+ (Branches motivation, Creating a branch, Sticky tags, Magic branch
+ numbers): these subnodes moved to "Branching and merging" from
+ "Revisions".
+ everywhere: Adjusted cross-references to cope with above.
+
+Sun Dec 21 20:36:39 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Jim Kingdon
+
+ Note that this is just moving text, not changing it:
+ * cvs.texinfo: divide top-level menu into sections.
+ (Multiple developers, Builds, Tracking sources, Keyword
+ substitution): moved to be in "CVS and the Real World" section.
+ (Compatibility): moved to be in "References" section.
+
+Mon Dec 22 08:54:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Example): In comment, in citing the BNF style
+ used in many RFCs, cite RFC2234 not RFC822 (now that the former is
+ out).
+
+Sun Dec 21 17:42:22 1997 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * cvs.texinfo (Overview): New node.
+ (What is CVS?, A sample session): Put under Overview.
+ (What is CVS not?): New node under Overview.
+ [text previously was part of "What is CVS?" -kingdon]
+ (Preface): Removed this node and its contents.
+ (Checklist): Removed this node and its contents.
+ (Credits): Now toward end of top-level menu (was under Preface).
+ (BUGS): Now toward end of top-level menu (was under Preface).
+
+Sun Dec 14 10:14:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Add MT response.
+ (Text tags): New node.
+
+ * cvs.texinfo (loginfo): Add comment about which commands run
+ loginfo.
+
+Sat Dec 13 08:41:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Connection and Authentication): State that
+ GSSAPI is preferred to kserver. Try to be clearer about what
+ the term "pserver" means. Introduce GSSAPI and cite the relevant
+ RFCs. Discuss the limitations of the existing features in
+ preventing hijacking.
+
+ * cvs.texinfo (GSSAPI authenticated, Kerberos authenticated):
+ Briefly introduce what GSSAPI and Kerberos are. Be slightly more
+ emphatic about protecting against downgrade attacks.
+
+Fri Dec 12 17:36:46 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (GSSAPI authenticated): New node.
+ (Global options): Document -a. Mention GSSAPI in -x
+ documentation.
+ * cvsclient.texi (Connection and Authentication): Document GSSAPI
+ authentication.
+ (Requests): Add Gssapi-encrypt and Gssapi-authenticate.
+
+Fri Dec 12 09:27:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (cvsignore): Add note about comments and the
+ space-separated nature of the syntax.
+
+Sun Dec 7 09:33:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (checkout): Clarify issues regarding updating
+ existing working directories.
+
+Sun Nov 30 20:38:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Add comment: we don't document %s.
+
+Mon Nov 24 23:00:09 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi: Move Protocol Notes node to the end.
+
+ * cvsclient.texi (Request intro): new node/section.
+ (Protocol): added some introductory material.
+ Rearranged menu into General Conventions, Protocol specification,
+ and Example etc sections.
+ (File Modes): replaces Modes, for consistency.
+
+Sat Nov 22 12:29:58 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Entries Lines): Clarify options in entries line.
+
+Tue Nov 18 09:23:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Be more explicit about "export" and
+ entries lines.
+
+ * Makefile.in (DISTFILES): Remove DIFFUTILS-2.7-BUG.
+
+Mon Nov 17 18:20:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (tag options): Expand comment with reference to FAQ.
+
+Fri Nov 14 11:02:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Update discussion of "dying gasps".
+
+ * cvs.texinfo (tag options): Add FIXME comment about renaming tags.
+
+Thu Nov 13 10:20:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Remove also has a -f option with a
+ different meaning than most.
+
+Wed Nov 12 21:57:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (File permissions, Connecting via rsh, Environment
+ variables): When putting an environment variable in the index, say
+ it is an environment variable. Don't index the same name twice.
+
+ * cvs.texinfo: Many edits to reflect the fact that CVS no longer
+ invokes external RCS programs.
+
+Tue Nov 11 15:15:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Locks, CVS in repository): New nodes, document the
+ locking scheme and briefly outline CVS and CVS/fileattr.
+
+Sun Nov 9 17:39:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * DIFFUTILS-2.7-BUG: Removed; the bug is fixed and the testcases
+ are incorporated into sanity.sh.
+
+Sat Nov 8 09:49:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Binary why): Try to be a little clearer about how
+ merges fit into CVS. Say it may be error prone to have developers
+ doing merges manually.
+
+Tue Nov 4 13:02:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (admin options): Add discussion of what happens if
+ there are tags.
+
+Fri Oct 31 00:04:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (admin options): Rewrite discussion of -o to
+ hopefully be clearer and to also document the new :: syntax.
+ (admin examples): Removed; incorporated into admin options.
+ (Invoking CVS): Wording fix for admin -o.
+
+ * cvs.texinfo (Binary why): New node, talks about diff and merge.
+ (Binary howto): Renamed from Binary files.
+ (Binary files): Now just contains an introduction.
+
+ * cvs.texinfo (Error messages): Add "could not merge" message. In
+ discussion of "Binary files . . . differ" message, mention that
+ this is only an issue with old verisons of CVS.
+
+Thu Oct 30 15:55:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "authorization failed" message.
+
+Wed Oct 29 11:52:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Remove fake RCSid; we decided to remove rcsid's a
+ while ago. Cleanups suggested by Stephen Gildea (CVSROOT/passwd
+ has 2 or 3 fields; /user -> /usr; noone -> no one; in used -> in
+ use). Add comment about making compilers happy about rcsids.
+
+Sat Oct 25 00:58:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * RCSFILES: rcsfile.5 is correct about {num} after next being
+ optional.
+
+Wed Oct 22 10:08:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add message about unrecognized
+ response from cvs server.
+
+1997-10-11 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (checkout options): describe how the `-d' and `-N'
+ flags really work. Give examples.
+ (export options): refer the reader to the descriptions for `-d'
+ and `-N' in checkout options, since the behavior is the same.
+
+Thu Oct 9 12:01:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (log options): Add comment about "cvs log -r".
+
+Wed Oct 8 10:24:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (rtag options): Add comment about how this is
+ confusing.
+
+Tue Sep 30 12:31:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Add comment about
+ Entries.Static.
+
+Thu Sep 25 23:52:57 1997 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvsclient.texi (Responses): description of Module-expansion was
+ missing a carriage return after the @item clause.
+
+Wed Sep 24 12:04:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Remote repositories): Add comment about pserver
+ vs. having users create their own repositories.
+
+Sat Sep 20 00:59:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list): Change title from "RCS Keywords" to
+ "Keyword list" as it is CVS that expands them.
+ (Avoiding substitution): Change "rcs" to "cvs", in the context of
+ the program which expands keywords.
+
+Fri Sep 19 22:57:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * RCSFILES: Grammar fix in first paragraph. Re-word section on
+ dead newphrase. Add item about what it means if "expand" is omitted.
+
+ * cvs.texinfo (Magic branch numbers): Change example branch number
+ from 1.2.3 to 1.2.4; CVS assigns even branch numbers and I don't
+ think vendor branches are very relevant to this example.
+
+Wed Sep 17 17:21:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (admin options): Add comment about "cvs admin -b"
+ (with no argument to the -b).
+
+ * RCSFILES: "next" is optional, not required.
+
+Tue Sep 16 15:13:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Binary files): Add comment about another possible
+ way to auto-detect binary files.
+
+Sun Sep 14 12:38:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Conflicts example): Adjust text and comments
+ regarding conflict markers to reflect change in CVS.
+
+Wed Sep 10 12:44:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Server requirements): Add comment about server
+ disk usage in /tmp.
+
+ * cvs.texinfo (Common options): More comments about date formats:
+ "now", "yesterday", and the "3 weeks ago" family.
+
+Tue Sep 9 13:09:58 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * DIFFUTILS-2.7-BUG: Eggert patch is preferred to Rittle one.
+
+Sun Sep 7 18:38:23 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (history options): Revise -e to say that it includes
+ future record types (and remove out of date list of what record
+ types it implies).
+
+ * cvs.texinfo (Environment variables): Expand/correct discussion
+ of HOME, HOMEDRIVE, and HOMEPATH.
+ (Error messages): Add "could not find out home directory".
+
+ * cvs.texinfo (update options): Reword -r doc to hopefully be
+ clearer that it takes either numeric or symbolic revision.
+
+ * cvs.texinfo (syntax): Add comment about how regexp syntax may
+ be, er, creatively altered, by configure.in.
+
+Sat Sep 6 11:29:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Document Baserev and
+ Baserev.tmp.
+ (Working directory storage): Adjust comment regarding CVS/* being
+ text files.
+
+Fri Sep 5 14:42:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (BUGS): Remove mention of unsupported resources page
+ on http://www.cyclic.com, as it might go away in a future
+ reorganization.
+
+ * DIFFUTILS-2.7-BUG: Further info from Eggert.
+
+1997-09-05 Paul Eggert <eggert@twinsun.com>
+
+ * DIFFUTILS-2.7-BUG: Explain how this bug will probably be
+ fixed in the next diffutils release.
+
+Thu Sep 4 17:09:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Binary files): Reword the section on what you need
+ to do with cvs admin -kb to hopefully be a bit clearer. Still not
+ ideal (see comment).
+
+ * cvs.texinfo (modules): Break node into separate nodes for alias
+ modules, regular modules, ampersand modules, and options. Expand
+ text with more examples and explanations. Add index entries.
+
+Wed Sep 3 14:49:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Multiple developers): Add idea about cvs editors
+ and reserved checkouts.
+
+Sun Aug 31 19:36:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Rewrite paragraph on cvs add on a
+ filename containing '/'.
+
+Thu Aug 28 14:13:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (diff options): Add comment about "cvs diff"
+ vs. "cvs diff -r HEAD".
+
+ * cvs.texinfo (Global options): Add comment about -w not
+ overriding cvs watch on.
+
+Wed Aug 27 08:09:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication server): Grammar fix ("under
+ as the username" -> "as the username").
+
+ * cvs.texinfo: Fix doubled 'the the' typos. Reported by
+ karlb@atg.com.
+
+Tue Aug 26 12:25:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Checklist): Reword xref to point to Binary files
+ rather than Keyword expansion. Credit goes to jeff@alum.mit.edu
+ (Jeff Breidenbach) for reporting the problem.
+
+Mon Aug 18 17:23:18 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (modules): Suggest taginfo instead of -t. Add
+ comment with some of the reasons. Add comment about -u and -i
+ problems.
+
+Sat Aug 16 10:19:06 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add note about how "could not
+ check out foo.c" seems to also have been observed on Irix.
+
+Fri Aug 15 17:28:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "could not check out foo.c".
+
+Thu Aug 14 23:57:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Document new -m 'COPY' behavior.
+
+Tue Aug 12 20:56:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Sticky tags): Add comment about how we should be
+ documenting sticky tags.
+
+Fri Aug 8 10:01:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (File status): Add comment about "working revision"
+ in cvs status for a locally removed file.
+
+Thu Aug 7 22:53:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (From other version control systems): Mention
+ pvcs_to_rcs alongside sccs2rcs.
+
+Tue Aug 5 17:22:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Compatibility): Add comment about how CVS probably
+ could be detecting the case of dead files killed by CVS 1.3.
+
+ * cvs.texinfo (From other version control systems): Add paragraph
+ about converting from systems which don't export RCS files.
+
+Sun Aug 3 21:03:14 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Cite RFC1321 for MD5.
+
+ * cvs.texinfo (A sample session): Nuke index entry for "A sample
+ session". The fact that this isn't "sample session" is totally
+ bogus, but in general the table of contents is probably better for
+ this entry.
+
+ * cvs.texinfo (Error messages): Add comment about wording of error
+ concerning unknown -x option.
+
+ * cvs.texinfo (Wrappers): Add comment about absolute filter pathname.
+
+Thu Jul 31 14:40:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Use @ref not @xref when reference is not at the
+ start of a sentence. Avoids capitalizing "See" when we shouldn't.
+ Fixes to other similar xref problems.
+
+Wed Jul 30 19:30:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Connection and Authentication): Don't use @samp
+ on BEGIN AUTH REQUEST and friends. Avoids overfull hbox.
+
+Fri Jul 25 10:40:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Remove obsolete sentence regarding
+ using Directory instead of Repository enabling alternate response
+ syntax.
+
+ * cvsclient.texi (Response intro): Add discussing of file updating
+ responses and file update modifying responses.
+ (Responses): Refer to this description rather than trying to
+ describe it in each place. The descriptions in each place were
+ somewhat incomplete and didn't get updated when new file updating
+ responses were added.
+
+ * cvsclient.texi: Split node Responses into Response intro,
+ Response pathnames, and Responses.
+
+Thu Jul 24 23:13:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (config): Document SystemAuth.
+ (Password authentication server): Mention SystemAuth.
+
+Mon Jul 21 08:57:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add DIFFUTILS-2.7-BUG.
+
+Sun Jul 20 17:55:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (admin options): For options with optional
+ arguments, specify that there can be no space between the option
+ and its argument. For -N, add xref to Magic branch numbers. For
+ -t, talk about reading from stdin. Comment changes.
+
+Sat Jul 19 22:28:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Preface): Make section titles more verbose.
+ Likewise for the menu.
+
+Fri Jul 18 08:41:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): No need for an external patch if
+ server and client are current. Add comment with more thoughts
+ about messages specific to old versions of CVS.
+
+ * cvs.texinfo (Error messages): Add "cannot start server via rcmd".
+
+ * cvs.texinfo (Error messages): Add "cannot open CVS/Root" for cvs
+ init.
+
+ * cvs.texinfo (Error messages): Add "missing author".
+
+Tue Jul 15 16:47:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list): Fix documentation of $Log to reflect
+ the fact that we no longer use the comment leader.
+ (admin options): Fix documentation of $Log.
+ (admin examples): Remove example concerning comment leader, since
+ the example no longer does what it claims to.
+ (admin, admin options): Fix various parts of the documentation to
+ not refer to this being implemented via RCS. Say nastier things
+ about -I and -x. Add comments about options to "rcs" which we
+ don't document.
+
+Mon Jul 14 00:04:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): The "cannot change permissions on
+ temporary directory" error has been happening in various test cases.
+
+Sat Jul 12 11:12:18 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Repository files): Further comments about leading
+ "-" in filenames.
+
+Fri Jul 11 21:30:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Repository files): Add comment about legal
+ filenames.
+
+Wed Jul 9 18:05:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Add Mbinary response.
+
+Mon Jul 7 12:04:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Goals): Add previously unwritten goal about only
+ one way to do each operation.
+
+ * cvs.texinfo (File permissions): Rewrite paragraph on setuid to
+ be more verbose and less unix-specific.
+
+Sat Jul 5 03:16:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Connection and Authentication): When we said to
+ "ignore" an unrecogized code we mean to treat it as nonspecific,
+ not to ignore the response.
+
+ * cvsclient.texi (Example): Refer to RFC2119 when referring to
+ terminology of MUST, SHALL, &c.
+
+ * cvs.texinfo (Windows permissions): New node.
+
+Fri Jul 4 15:27:43 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (Common options): Fix typo (avaliable for
+ available).
+
+Tue Jul 1 09:19:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Server requirements): Discuss memory used by diff.
+
+ * cvs.texinfo (Substitution modes): Add comment about -A resetting
+ both sticky tags/dates and sticky options.
+
+ * cvs.texinfo (File permissions): Add paragraph concerning
+ ownership of the RCS files.
+
+ * cvs.texinfo (Working directory storage): Relative repositories
+ in CVS/Repository are legal.
+
+Mon Jun 30 10:48:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Top): Add menu item for Password scrambling.
+
+ * cvs.texinfo (Committing your changes): Add comment concerning
+ documentation of message prompting.
+
+Fri Jun 27 11:20:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Password scrambling): New node.
+ (Connection and Authentication): Adjust accordingly.
+ (Protocol Notes): Add long discussion of character sets and
+ password scrambling.
+
+ * cvs.texinfo (Repository files): Also mention doc/RCSFILES in
+ documenting RCS file format.
+ (CVSROOT, storage of files): New node.
+
+Thu Jun 26 09:18:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (File permissions): xref to the pserver thing about
+ permissions in CVSROOT.
+ (Kerberos authenticated): Explicitly mention kerberos rsh.
+ Add various index entries for "security, <foo>".
+
+Wed Jun 25 13:39:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Rewrite comments concerning HEAD
+ and testcases and solution. Changing HEAD might be too big a
+ change; might be better to phase it out.
+ (Common options, Tags): Add index entries for HEAD and BASE.
+
+Tue Jun 24 09:37:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add assertion failed.
+
+ * cvsclient.texi (Connection and Authentication): Add "E" and
+ "error" as responses in authentication protocol. The server
+ already was in the (formerly bad) habit of sending them, and we
+ might as well implement this in the client and document it.
+
+ * cvs.texinfo (Password authentication security): Note about
+ permissions on $CVSROOT also applies to its parent and so on up to
+ /.
+
+Mon Jun 23 18:28:18 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Creating a repository): xref to Server requirements
+ for more details on memory, CPU.
+ (Server requirements): Add xref to Creating a repository regarding
+ disk space.
+
+ * cvs.texinfo (Read-only access, Password authentication
+ security): The known holes which let a read-only user execute
+ arbitrary programs on the server are gone.
+
+ * cvsclient.texi (Protocol Notes): Remove multisite item; it is
+ replaced by item 186 in TODO. Add a general reference to TODO.
+ Rewrite accordingly the sentence about multisite in the item
+ concerning sending modified files in "cvs update".
+
+Fri Jun 20 17:00:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "binary files differ" when
+ trying to check in a binary file.
+
+Fri Jun 20 14:01:23 1997 David J MacKenzie <djm@va.pubnix.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Fix various formatting, spelling, stylistic, and
+ factual errors.
+
+Thu Jun 19 07:11:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (config): New node.
+ (Password authentication server): Talk about RCSBIN in config as
+ an alternative to -b global option.
+ * cvsclient.texi (Requests): Specify when Root can/must be used.
+
+ * cvs.texinfo (Error messages): Add
+ "*PANIC* administration files missing".
+
+ * cvs.texinfo (Password authentication server): Mention
+ permissions on $CVSROOT and $CVSROOT/CVSROOT as part of the
+ installation process.
+ (Password authentication security): Clarify that permissions issue
+ applies to $CVSROOT as well as $CVSROOT/CVSROOT.
+
+Wed Jun 18 00:03:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication security): Add paragraph
+ on write permissions of $CVSROOT/CVSROOT.
+
+ * cvs.texinfo (Adding and removing): New node. Move Adding files,
+ Removing files, Removing directories, Moving files, and Moving
+ directories under it.
+
+ * cvs.texinfo (Removing directories): Add sentence about how
+ one doesn't remove the directory itself.
+
+ * cvs.texinfo (Password authentication server): Document
+ --allow-root.
+
+Tue Jun 17 09:58:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "unknown option" from RCS.
+
+Fri Jun 13 12:11:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Global options): Add note about how -n might affect
+ CVS's output.
+
+Thu Jun 12 09:33:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Other problems): New node. Add discussion of
+ problem with old rcsmerge.
+
+ * cvs.texinfo (Environment variables): Add CVSUMASK.
+
+Mon Jun 2 18:39:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Moving a repository): New node.
+
+Tue May 27 18:27:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Add comment about
+ timestamps.
+ * cvsclient.texi (Responses): Add Mod-time.
+
+Mon May 26 10:04:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Add comment concerning -t/-f and
+ client/server.
+
+Sun May 25 00:08:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Multiple vendor branches): New node.
+ (First import, import options, Invoking CVS): xref to it.
+
+Sat May 24 23:47:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (File permissions): Add comment about group
+ ownership in repository and setgid bit on directories.
+
+Fri May 23 17:14:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * RCSFILES: Fix typo in dead newphrase description ("an" -> "a").
+
+Fri May 23 16:33:38 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * RCSFILES: Mention dead as a newphrase.
+
+Fri May 23 09:45:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Builds): In comment, update URL of mk.
+
+Thu May 22 09:25:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add comment about yet another way
+ to produce a "cannot open CVS/Entries for reading" error.
+
+Tue May 20 17:54:55 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add item about EINVAL in rename.
+
+Mon May 19 00:21:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keywords in imports): New node.
+ (Tracking sources): Add comment about what a "vendor" is.
+
+ * cvs.texinfo (Keyword substitution): Where it refers to RCS
+ having a certain behavior, rewrite to not pass the buck like
+ that. Saying "RCS file" is still OK; that is a legit CVS
+ concept. A few other minor edits.
+
+Sun May 18 10:24:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * RCSFILES: Add list of known newphrase extensions.
+
+ * cvs.texinfo (From other version control systems): Fix typo
+ ("systesm" -> "systems").
+
+ * cvs.texinfo (Exit status): New node.
+ (diff): Replace text on exit status with an xref to that node.
+ The previous text documented a behavior which CVS no longer
+ implements.
+ (user-defined logging, commitinfo, verifymsg, Error messages):
+ Add index entries for "exit status, of <something which CVS invokes>".
+
+ * cvs.texinfo (Administrative files): Add comment concerning
+ writing triggers and particularly performance issues.
+
+ * cvs.texinfo (rtag options, tag options): Don't discuss what old
+ versions did with respect to the behavior now controlled by -F; we
+ don't try to document old versions here. Add comments concerning
+ how -F should be documented. Add index entries for "renaming
+ tags" and such pointing to "tag -F".
+
+Wed May 14 12:16:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Binary files): Add text and comment about
+ automatically detecting binary files.
+
+Mon May 12 11:55:07 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Connection and Authentication): Add item about
+ future expansion.
+
+Thu May 8 11:08:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Update imports): Add comment about wdiff
+ vs. fsf/wdiff in example.
+
+Wed May 7 13:52:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (checkout): Add comment about need for example
+ regarding what the "module" argument means.
+
+Tue May 6 18:02:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (History browsing): Add comment about looking at old
+ revisions.
+
+Tue May 06 15:05:00 1997 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: More additions/corrections for -R due to recent
+ changes.
+
+Mon Dec 16 15:18:00 1996 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo: Added/corrected documentation for -R. (Minor edits
+ by Jim Kingdon to reflect recent changes in cvs.texinfo)
+
+Sun May 4 14:38:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Compatibility): Add comment about "D" lines in
+ Entries.
+
+ * cvs.texinfo (CVS commands, diff): Change "run diffs" to "show
+ differences"; the former is jargon.
+ (CVS commands): Don't refer to "rlog" in describing what log does.
+
+ * Makefile.in (cvsclient.dvi cvsclient.aux): Run texi2dvi rather
+ than (poorly) emulating it ourself.
+
+ Fix overfull and underfull hboxes:
+ * cvs.texinfo (What is CVS?): Add words "the newsgroup" before
+ "comp.sources.unix".
+ (Credits): Put list of people in @display.
+ (Repository files): Put /usr/local/cvsroot in @example.
+ (Connecting via rsh): Change "anklet" to "toe" in example.
+ (Kerberos authenticated, Password authentication client, Password
+ authentication server): Change "brickyard" to "yard" in example.
+ (Read-only access): Use @example and refer to files with a shorter
+ pathname.
+ (Server temporary directory): Use @example for pathname.
+ (Watches Compatibility): Add phony line break.
+ (Revision numbers): Remove revision 1.2.2.2 and tighten up the
+ spacing for "the main trunk".
+ (Tags, Creating a branch): Change /usr/local/cvsroot to /u/cvsroot.
+ (Merging more than once): Tighten up spacing for "the main trunk".
+ (Recursive behavior): Put long command in @example.
+ (First import): Remove word "called".
+ (Common options): Put long URL in @example.
+ (loginfo example): Use fewer hyphens in example.
+ (Variables): Put long command name in @example.
+ (Copying): Add line break.
+ (Administrative files): Remove "the" from title.
+ (Copying): Change "@unnumberedsec" to two "@heading"s.
+ * cvsclient.texi (Requests): Change /home/kingdon/zwork/cvsroot to
+ /u/cvsroot.
+ (Example): Add word "file".
+ (Example): Change line breaks in example log message.
+ (Example): Change /home/kingdon/testing/cvsroot to /u/cvsroot.
+
+ * cvs.texinfo (Credits): Don't refer to appendix A and B, they
+ have been renumbered. Reword so that it works whether the text in
+ question has since been rewritten or not.
+
+ * cvs.texinfo (BUGS): Rewrite to reflect the many different ways
+ that one might want to handle bugs. Move information on Signum
+ and Cyclic from Preface to here. Remove information on known
+ deficiencies in the manual (some of them I'm not sure were really
+ things in need of improvement; others were too general to be
+ useful). For the most part FIXME comments are probably better for
+ this. Remove "Linkoping, October 1993, Per Cederqvist"--many
+ parts of the manual are now from other people, dates, and places.
+ (What is CVS): For the most part, just refer to BUGS concerning
+ bug-cvs. Also tell people how to subscribe to bug-cvs.
+ (Credits): Say that list is not comprehensive and refer to
+ ChangeLog.
+
+Sat May 3 10:51:58 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (rcsinfo): Add comment about checkoutlist and
+ related topics.
+
+ * cvs.texinfo (Server temporary directory): New node.
+
+ * cvs.texinfo (Backing up): New node.
+
+ * cvs.texinfo (Repository): Be more explicit about the repository
+ and the working directory not being subdirectories of each other.
+
+Mon Apr 28 11:12:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Removing files): Use "*.c" not "?.c" in example;
+ the former should be good for both unix and DOS-like operating
+ systems. Document -f option. Refer to Invoking CVS for a full
+ list of options. Add a few comments.
+
+ * cvs.texinfo (Invoking CVS): For checkout and update, call them
+ "sticky options" not "sticky kopts".
+
+ * cvs.texinfo (Editing files): Add additional comments on get
+ vs. checkout.
+
+Sun Apr 27 16:17:06 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (commit): Only document the current flags (where -f
+ is force and -F file gets the message from a log file). We had
+ partly made this change on 9 Feb 1997, but some places got missed.
+
+ * RCSFILES: Add discussion of the common concern regarding
+ applying deltas to get to a branch head.
+
+ * DIFFUTILS-2.7-BUG: New file.
+
+ * cvs.texinfo (File status): Refer to "Invoking CVS", not
+ "status", for status options. Add paragraph about how "cvs -n -q
+ update" is another way to display file status.
+ (update examples): Removed; it had contained the "cvs -n -q
+ update" material.
+ (Invoking CVS): xref to "File status" and "Tags", not "status" and
+ "status options".
+ (status, status options): Removed.
+ (update options, checkout options): xref to "Invoking CVS"
+ not "status".
+
+ * cvsclient.texi (Requests): Clarify how long-lived Sticky and
+ Static-directory are.
+
+ * cvs.texinfo: Add @finalout.
+
+ * cvs.texinfo (Error messages): Add "cannot change permissions on
+ temporary directory" message.
+
+Wed Apr 23 12:53:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Document "add" in much more detail.
+
+Wed Apr 23 00:38:17 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvsclient.texi (Requests): Correct small typo (`a' for `as').
+
+Tue Apr 22 14:23:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Protocol Notes): Expand ideas on multisite
+ features somewhat. Add items about the network turnarounds for
+ pserver authentication and for protocol negotiation.
+
+Mon Apr 21 08:54:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Describe what to do
+ with Entries.Log in more detail.
+
+ * cvsclient.texi (Responses): Say "CVS 1.9 and earlier" rather
+ than "pre version 1.10". The latter increases confusion by
+ referring to a version which doesn't exist yet.
+
+Mon Apr 21 01:02:53 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvsclient.texi (Responses): Document Rcs-diff. Indicate that
+ Patched is now deprecated in favor of Rcs-diff.
+
+Sun Apr 20 23:42:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Add note about format
+ of timestamp and the "Result of merge" concept.
+
+Sat Apr 19 13:42:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): It is OK for Copy-file to implement
+ a rename instead of a copy.
+
+Fri Apr 18 12:05:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Assigning revisions): Say that -r implies -f.
+
+Thu Apr 17 16:34:14 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (From other version control systems): Add comment
+ about CMZ and PATCHY.
+
+Wed Apr 16 12:35:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Add paragraph describing how
+ Copy-file relates to Merged.
+ (Responses): Add paragraph about how it is the server which
+ worries about not clobbering the user's file.
+
+Tue Apr 15 00:57:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * RCSFILES: Add notes on keyword expansion.
+
+ * cvs.texinfo (Rename by copying): Comment out seemingly erroneous
+ text regarding the revision number that the new file starts with.
+
+Mon Apr 14 12:37:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Clients should try to send
+ notifications right away.
+
+ * cvsclient.texi (Requests): For Notify request, clarify a few
+ future expansion situations. Specify the format of the time.
+
+ * cvsclient.texi (Requests): Clarify that arguments to co, rdiff,
+ and rtag are module names (and how that differs from file/directory
+ names).
+
+ * cvsclient.texi (Responses): Say that servers need to create
+ directories one at a time.
+
+Sat Apr 12 09:32:58 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Committing your changes): Say that editor default
+ is notepad (not vi) for Windows NT/95. Be more clear about what
+ "cvs commit" does. Add paragraph about timestamps.
+ (Environment variables, Global options, editinfo):
+ Add xrefs to that node.
+
+Thu Apr 10 15:48:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "could not patch; will refetch".
+
+Wed Apr 9 15:21:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): New node.
+
+ * cvs.texinfo (Error messages): Add comment about "cvs co ." on
+ NT.
+
+Tue Apr 8 14:44:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add diff3 usage message.
+
+Sun Apr 6 19:03:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Removing files): Add comment about undoing a "cvs
+ remove".
+
+ * cvsclient.texi (Requests): Explicitly mention the idea of
+ deferring "Notify" requests.
+
+Tue Apr 1 07:51:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Add paragraph about directory
+ creation and empty directories.
+
+ * cvs.texinfo (Binary files): Add comment about binary files and
+ merges.
+
+ * cvsclient.texi (Requests): Add discussion of when to send
+ Is-modified.
+
+ * cvsclient.texi (Requests): Sending Is-modified is enough to
+ prevent the file from being considered "lost".
+
+Sun Mar 30 00:31:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Add Is-modified request. Clarify
+ order of Entry relative to Unchanged or Is-modified (might as well
+ specify the same thing vis-a-vis Modified while we are at it).
+
+Sat Mar 29 12:32:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi: Change "newline" to "linefeed". Most of the
+ document already reads "linefeed" and that is what is intended.
+ (File transmissions): New node, moved here from Requests.
+ (Goals, Filenames, File transmissions, new node Strings): Add
+ discussion of character sets and what we expect from the transport
+ protocol we run on.
+
+ * cvsclient.texi (Requests): Add paragraph about each Directory
+ request specifying a new local-directory and repository.
+
+ * cvsclient.texi (Requests): Add paragraph about renaming
+ local-directory in Directory request. Use "local-directory"
+ consistently instead of "working directory", for clarity.
+
+Fri Mar 28 13:59:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Make it clear that there is no
+ guarantee that one will get Clear-sticky instead of another
+ response. Also clarify that clients will tend to store the
+ repository in a long-term way.
+
+ * cvsclient.texi (Requests): Further clarify Directory example.
+
+ * cvsclient.texi (Requests): Add example and further explanation
+ of what expand-modules is for.
+
+ * cvsclient.texi (Requests): Add example, hopefully making it
+ clearer what REPOSITORY and LOCAL-DIRECTORY mean to Directory.
+
+ * cvs.texinfo (Attic): New node.
+ (rtag options): Adjust discussion of -a accordingly.
+ (Repository files): Adjust accordingly.
+
+Thu Mar 27 09:57:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): Give exact wording of broken pipe
+ error message.
+
+ * cvs.texinfo (history database): Add comment about various
+ problems with the history file.
+
+ * cvs.texinfo (Common options): The ISO8601 web page we had
+ mentioned in a comment is no more. Replace it with a new one.
+
+ * cvs.texinfo (Common options): "cvs history" also outputs dates.
+
+Wed Mar 26 10:54:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): "cvs editors" also outputs dates.
+
+ * cvs.texinfo (Outside): Fix paragraph which said that revision
+ numbers start at 1.0. First of all, it is 1.1. Second of all, it
+ is sometimes 2.1, 3.1, etc. Third of all, the xref should be to
+ Assigning revisions not commit options.
+
+ * cvs.texinfo (Outside): Comment out sentence which incorrectly
+ stated that "cvs add" can operate on "foo/bar.c".
+
+Tue Mar 25 22:21:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Error messages): New node.
+ (Magic branch numbers): Move from Troubleshooting to Revisions and
+ branches. The former placement never made any sense to me.
+ (Revision numbers): Remove "Main trunk (intro)" index entry now
+ that this node is right next to the other "main trunk" index
+ entry.
+ (BUGS): Very briefly mention reporting bugs in CVS.
+
+ * cvs.texinfo (Compatibility): Add comment about "Nfoo" in CVS/Tag.
+
+Mon Mar 24 13:50:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Creating a branch): Add comment about -r in branch
+ example.
+
+ * cvsclient.texi (Responses): Discuss meaning of tagspec and
+ future expansion in Set-sticky. The behavior described is the one
+ which CVS has always implemented.
+
+Fri Mar 21 14:19:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Revise meaning of "Case" per change
+ to CVS.
+
+Tue Mar 18 15:50:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ The following reorganization hopefully presents numeric revisions
+ in a slightly more coherent fashion. The only new material is the
+ paragraph about assigning revisions for added files.
+ * cvs.texinfo (A sample session): Bring in a sentence from Basic
+ concepts node, defining a repository.
+ (Revisions and branches): Renamed from Branches (it has always
+ covered non-branch tags too). Bring in nodes "Revision numbers" and
+ "Versions revisions releases" from Basic concepts, the former in
+ particular was way too detailed for an intro section.
+ (A sample session): Add comment about how we need an introduction
+ and what might go into one. Also bring in the paragraph from
+ Basic concepts introducing modules, but comment it out.
+ (Viewing differences): Add comment about
+ (Basic concepts): Removed; its content has been farmed out as
+ described above, and as the comment said, it was fundamentally
+ flawed.
+ (Assigning revisions): New node. Incorporates the "New major
+ release number" subsubsec which was in "commit examples". Add
+ paragraph concerning how CVS assigns revisions on added files.
+ (commit options): Refer to that node under -r.
+ (Invoking CVS): Add comment about text for -r.
+
+Tue Mar 18 13:04:30 1997 Jim Meyering <meyering@totoro.cyclic.com>
+
+ * Makefile.in: (install-info): Depend on installdirs.
+
+Sun Mar 16 12:37:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (File permissions): CVSUMASK now works for RCS
+ files; but it is (still) awkward for client/server CVS.
+
+Sat Mar 15 17:41:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Magic branch numbers): Add comment about where this
+ should go.
+
+Thu Mar 13 09:11:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Credits): Fix grammatical mistake ("manual about"
+ -> "manual is about"). Reported by Philippe De Muyter.
+
+Sun Mar 9 09:06:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (File permissions): Add comment about val-tags and
+ CVSUMASK.
+
+Sun Mar 2 12:33:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (From scratch): Add comment about creating
+ directories with add rather than import.
+
+ * cvs.texinfo (Creating a repository): Add comment about how this
+ somewhat duplicates Server requirements.
+
+ * cvs.texinfo (Connecting via rsh): Add comment about rsh
+ vs. remsh. Also wording fix ("incorrect" -> "inapplicable").
+
+ * cvs.texinfo (Outside): Add comment about renames and annotate.
+
+ * cvs.texinfo (Server requirements): New node.
+
+Thu Feb 27 15:20:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Multiple developers): Reword section on "cvs admin
+ -l". As nearly as I can tell based on when it came up on info-cvs
+ and other contexts, people who are into reserved checkouts
+ generally find that cvs admin -l is OK. Add a bunch more notes
+ (inside @ignore) about reserved checkout implementation ideas.
+
+Sun Feb 23 16:12:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Add various additional comments
+ about date formats.
+
+ * RCSFILES: Remove diff for Id and explain it in words instead.
+ The previous values for Id had been clobbered by keyword expansion
+ on the RCSFILES file itself.
+
+Sat Feb 22 14:16:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Fix typo (missing backslash).
+
+Fri Feb 21 23:08:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * RCSFILES: New file.
+ * Makefile.in (DISTFILES): Add RCSFILES.
+
+20 Feb 1997 Lenny Foner <foner@media.mit.edu>
+
+ * cvs.texinfo (Checklist): Fix typo ("keword" -> "keyword").
+
+Thu Feb 20 21:57:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keeping a checked out copy): Add "web" to index.
+
+Wed Feb 12 18:44:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication client, Invoking CVS):
+ Document "cvs logout" command.
+
+Tue Feb 11 20:42:45 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (commit options): Document that the -f option to
+ commit disables recursion.
+
+Sun Feb 9 13:58:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (diff options): Document all the options we pass
+ through to diff. Remove paragraph about -D sometimes meaning
+ --ifdef since that is no longer true.
+
+ * cvs.texinfo (Multiple developers): Add lengthy comment about
+ reserved checkout design issues.
+
+ * cvs.texinfo (Wrappers): Add paragraph about timestamps.
+
+ * cvs.texinfo (commit options): Don't try to document what CVS 1.3
+ does with -f and how recent versions differ: 1.3 is pretty old
+ anyway, we generally only try to document the current version, and
+ the way it was described here was pretty confusing.
+ (Environment variables): Likewise for CVSEDITOR.
+
+ * cvs.texinfo (import output): Add index entries for symbolic
+ links. Add brief mention of whether behavior should be
+ different. Add comments on other symbolic link issues.
+
+Wed Feb 5 13:02:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Concurrency): Add comment about commit/commit
+ atomicity.
+
+Mon Feb 3 10:55:41 1997 joel boutros <nihilis@moral.addiction.com>
+
+ * cvs.texinfo (Connecting via rsh): Fix typo (programs -> problems).
+
+Fri Jan 31 12:18:47 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvsclient.texi (Connection and Authentication): Correct typo
+ (``sent'' for ``send''), and rewrite sentence for clarity.
+
+Fri Jan 24 10:31:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (File status): Change "Unresolved Conflict" to "File
+ had conflicts on merge" per change to CVS.
+
+Sun Jan 19 16:21:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (admin): Add comments about "group" and "compiled in
+ value". At least one info-cvs poster was confused by this.
+
+Thu Jan 16 17:54:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): It is just -t/-f which doesn't work
+ client/server. -k *does* (well, except for the problem with
+ import noted in BUGS). -m I don't know and I doubt anyone cares.
+
+Mon Jan 13 15:41:02 1997 Karl Fogel <kfogel@ynu38.ynu.edu.cn>
+
+ * cvs.texinfo (Read-only access): rephrase to imply that there may
+ be other administrative files, besides history and locks, which
+ read-only users can also affect (in the future, for example, the
+ `passwd' file).
+
+Wed Jan 8 14:50:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Remove CVSid; we decided to get rid
+ of these some time ago.
+
+Wed Jan 8 09:08:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Connection and Authentication): Document
+ restriction that cvs root sent in the cvs protocol and in the
+ pserver authentication protocol must be identical.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, cvs.texinfo: Remove "675" paragraph;
+ see ../ChangeLog for rationale.
+
+Thu Jan 2 09:34:51 1997 Karl Fogel <kfogel@ynu38.ynu.edu.cn>
+
+ * cvs.texinfo (Read-only access): new node.
+ (Repository): new menu item for above new node.
+ (Password authentication server): document the user-aliasing
+ feature. Why was this undocumented before?
+
+Wed Jan 1 18:12:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Conflicts example): Use @asis in example to prevent
+ starting a line with a conflict marker. This means that when
+ maintaining the file with CVS itself, CVS will not think there is
+ a conflict merely because of the conflict marker in the example.
+ IMHO, this is totally bogus and CVS needs a better way of figuring
+ out whether a conflict is resolved (see comments elsewhere in this
+ node), but until then.... Credit to Fred Fish for reporting the
+ problem.
+
+ * cvs.texinfo (cvsignore): Add paragraph about how .cvsignore
+ files in the sources being imported by "cvs import" override
+ "-I !". Credit goes to Fred Fish for pointing out this problem.
+
+Thu Dec 19 12:36:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Credits): Update Roland Pesch email address per his
+ request.
+
+Tue Dec 17 12:57:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (verifymsg): In example, remove text "and reedit if
+ necessary"; it was copied from editinfo and doesn't apply here.
+ Fix syntax of if statement; remove unnecessary attempt at loop;
+ don't use -n with echo. Add @appendixsec at start of node.
+ Add note about how verifymsg cannot change log message.
+ (editinfo): In paragraph saying editinfo is obsolete, fix various
+ typos and formatting glitches. Mention -e as well as EDITOR.
+ (editinfo): In saying that editinfo doesn't get consulted with -m,
+ -F or client/server, recommend verifymsg. Remove comment which
+ says, in effect, "we need a feature like verifymsg".
+ (editinfo example): Change "verifymsg" back to "editinfo" here;
+ the example is of editinfo not verifymsg.
+
+Tue Dec 17 12:45:32 1996 Abe Feldman <feldman@cyclic.com>
+
+ * cvs.texinfo (verifymsg): New node.
+ various places: Say that editinfo is obsolete, or refer to
+ verifymsg instead of editinfo
+
+Wed Dec 11 08:55:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Compatibility): Add comment about 1.3 and file death.
+
+ * cvs.texinfo (update output, release output): Document "P" as
+ well as "U".
+
+Tue Dec 10 16:23:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Builds): Change "make" to "implement" and "build";
+ in this context "make" is ambiguous.
+ (Builds): Add new URL of mk web page.
+
+Mon Dec 9 11:03:37 1996 Jim Blandy <jimb@floss.cyclic.com>
+
+ * cvs.texinfo (Password authentication client, Environment
+ variables): Remove mention of CVS_PASSWORD.
+
+Sun Dec 8 22:38:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Repository files): Mention differences between RCS
+ files in RCS and in CVS.
+ (Tags): Tag names must start with a letter.
+
+Fri Dec 6 09:08:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (syntax): Expand discussion of regular expression
+ syntax.
+
+Fri Nov 29 09:06:41 1996 fnf@ninemoons.com (Fred Fish)
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo, cvsclient.texi: Make sure @ref and friends are
+ followed by "," or "." as described in the texinfo manual. This
+ is a dubious practice as texi2html and texinfo.tex don't require
+ it, and makeinfo could insert them as needed, but since makeinfo
+ doesn't do that yet, cope.
+
+ * cvs.texinfo (From files): Suggest "diff -r" rather than "ls -R"
+ as the way to see that the sources seem to have been imported
+ correctly.
+ (Common options): -k is also available with import.
+ (admin options): Fix typo ("interrested" -> "interested").
+
+Mon Nov 25 10:03:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Add comments about two digit
+ years, year 2000, and ambiguous/nonexistent dates.
+
+Sun Nov 24 17:27:24 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (First import): Don't say what the wdiff program we
+ are using as an example does--that is confusing. Also don't show
+ untarring it--people might be familiar with cpio, ZIP, VMS BACKUP,
+ etc., instead of tar.
+
+ * cvs.texinfo (Adding files): Update comment about "cvs add -m".
+
+ * cvs.texinfo (Common options): Remove -H; -H is not a command
+ option.
+ (Global options): Also list --help and --version. Don't say that
+ -H gives a list of commands; it doesn't any more (directly).
+
+ * cvs.texinfo: Add comment pointing to paper size web page.
+
+ * cvs.texinfo (Common options): Rewrite section on date formats.
+ Executive summary is that RFC822 and ISO8601 are now preferred.
+
+Wed Nov 20 08:39:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Getting Notified): Add paragraph clarifying that
+ watches happen per user, not per working directory.
+
+Tue Nov 19 09:39:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Tags): Suggest that future special tag names might
+ start with ".". Fix typo.
+
+ * cvs.texinfo (Removing directories): -P is also available with
+ export.
+ (Moving directories): Rewrite first paragraph; now says that you
+ must use -P for the directory to disappear from working
+ directories. Thanks to Martin Lorentzon
+ <Martin.Lorentzson@emw.ericsson.se> for reporting this bug.
+ (various): Where we mention -P, point to Removing directories
+ node.
+
+Sat Nov 16 18:03:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Example): Rewrite to actually be based on a real
+ live example (and therefore reflect the way the protocol currently
+ works). Add comment about formatting of the document itself.
+
+Thu Nov 14 10:22:58 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Introduction): Use @ref, not @xref, after "see".
+ (Goals): Rewrite items about locking, about uploading in big
+ chunks, and about atomicity to be focused more on the protocol
+ than the current implementation.
+ (Notes): Remove this node. The attempt to describe the basic
+ model has pretty much been replaced by the Introduction.
+ The material about how to start the client is incomplete and
+ better left to cvs.texinfo. And the item about the lack of
+ SERVER_FLOWCONTROL is obsolete now that SERVER_FLOWCONTROL is the
+ default.
+ (Protocol Notes): Add comment about multisite features.
+ (Requirements): Use @code for requests and responses.
+
+ * cvs.texinfo (Remote repositories): Add a few sentences defining
+ "client" and "server"; before we had been using the terms without
+ defining them.
+
+ * cvs.texinfo (What is CVS?): Add paragraph about reporting bugs.
+ Reword and expand comp.software.config-mgmt description (and add
+ comments about other newsgroup facts). Point people at GNU list
+ of FTP sites rather than directly at prep.ai.mit.edu.
+
+Wed Nov 6 09:45:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Tracking sources): Add comment regarding added and
+ removed files.
+
+Tue Nov 5 14:00:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Rename node "Invoking CVS" to "CVS commands".
+ Rewrite the intro and comments to reflect addition of the new
+ Invoking CVS.
+ (Invoking CVS): New node, a quick summary of each command.
+ (annotate): Don't list the options; refer to Invoking CVS and
+ Common options instead.
+
+Sun Nov 3 21:22:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Compatibility): New node, moved from ../README.
+
+ * cvs.texinfo (Common options): Add comment about how tar manual
+ contains documentation for getdate date formats.
+
+Fri Nov 1 14:00:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (commit examples): Rewrite "New major release
+ number" section to tighten up the wording, better motivate the
+ discussion, and replace the term "rcs revision number" with
+ "numeric revision".
+
+Fri Oct 25 07:49:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (loginfo): Don't say "a la printf"; the syntax is
+ only vaguely similar to printf.
+
+ * cvs.texinfo (loginfo): To get just the repository name, suggest
+ %{} instead of % "standing alone"; the latter is now an error.
+
+Tue Oct 22 13:08:54 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * cvs.texinfo (loginfo): add information on the new loginfo format
+ string specification.
+
+Mon Oct 21 17:33:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Builds): New node.
+ (What is CVS?): Refer to it.
+
+Sat Oct 19 14:32:21 1996 Jim Meyering <meyering@asic.sc.ti.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Choosing a model): Wording/grammar fix.
+
+Sat Oct 19 14:32:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Obsolete): New node.
+ (Requests): Remove Repository and Lost and adjust Directory,
+ UseUnchanged, and other places accordingly.
+ (Required): Directory and Unchanged are now required.
+
+ * cvs.texinfo (Removing files): Don't talk about modules; they are
+ not relevant in this context.
+ (Removing directories): New node.
+ (Common options): Refer to it instead of duplicating information.
+
+Fri Oct 18 11:05:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (First import, import): Add paragraph about the fact
+ that import doesn't modify the directory which it imports from.
+
+ * cvs.texinfo (Creating a repository): Add paragraph about
+ resource requirements.
+
+ * cvs.texinfo (Copying): Replace empty node with a copy of the GPL.
+
+Thu Oct 17 12:10:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Adding files): Revise comment to more accurately
+ reflect the functioning/nonfunctioning status of cvs add -m.
+
+ * cvs.texinfo (Reverting local changes): New node, somewhat based
+ on the version of this node from 30 Sep 96 change.
+ (admin options): Refer to it.
+
+ * cvs.texinfo: Reinstate 30 Sep 96 change from A4 to US letter.
+
+ * cvs.texinfo (Concurrency): When telling people how to clean up
+ locks, tell them to make sure the locks are owned by the person
+ who has the stale locks.
+ (update output, release output): Remove text about how CVS doesn't
+ print "? foo" for directories; CVS has since been changed (see
+ conflicts-130 in sanity.sh).
+
+Wed Oct 16 15:01:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (history options): Mention new option -x E.
+
+Mon Oct 14 15:21:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Tags): Add paragraph on choosing a convention for
+ naming tags.
+
+Thu Oct 10 16:05:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (modules): Describe what & does.
+
+Mon Oct 7 17:20:11 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (Removing files): Correct apparent cut and paste
+ error: refer to the removed file, not the added file.
+
+Tue Oct 1 14:15:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Revert all recent changes (the last unscathed one
+ is the CVSUMASK one from Sunday). For the most part said changes
+ are for new features which are not appropriate at this stage of
+ the release process. None of the changes being reverted need to
+ go into 1.9, that is for sure.
+
+Mon Sep 30 18:17:34 1996 Greg A. Woods <woods@most.weird.com>
+
+ * cvs.texinfo (Credits): add comment asking if we should update.
+ Add more detail about printing Letter on A4.
+ Add some comments about internal comments.
+ (From files): describe "cvs import -b 1" for importing existing
+ projects onto the main branch.
+ (First import): add a couple of helpful hints about naming vendor
+ and release tags, etc., and regularize the examples with this.
+ (Tracking sources): noted some reasons why you might use vendor
+ branches with "cvs import".
+ (Update imports): mention using "update" in place of "checkout" if
+ you have an existing working directory.
+ (Binary files in imports): add sub-menu separator comment.
+ (Tracking sources): new menu entry "Reverting to vendor release".
+ (Reverting to vendor release): new node to describe reverting
+ local changes and optionally using patch(1) to move local changes
+ forward.
+ (Global options): describe -D and -g, as well as DIFFBIN and
+ GREPBIN.
+ (export examples): add one.
+ (import options): describe the effect of '-b 1'.
+
+Mon Sep 30 08:09:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Adjust comments concerning A4 vs. US letter,
+ referring to ../README.
+
+ * cvs.texinfo (Common options): Add comment about dates which CVS
+ uses in output.
+
+Sun Sep 29 11:14:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list): Don't mention Name twice.
+
+ * cvs.texinfo (File permissions): Expand CVSUMASK stuff a bit.
+ (Setting a watch, Environment variables, Global options): Update
+ index entries for "read-only files, and ...".
+
+ * cvsclient.texi (Requests): State that Gzip-stream is preferred
+ to gzip-file-contents. Cite RFC1952/1951 rather than just "gzip".
+ Say that RFC1950/1951 compression is also known as "zlib".
+
+Sat Sep 28 09:31:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Repository): Move all information about the
+ internal structure of the repository to User modules node. Rename
+ it to "Repository storage" ("User modules" wasn't particularly
+ clear). Mention CVSUMASK. Much clarification and
+ reorganization.
+ (Basic concepts): Remove material which duplicates what is now in
+ Repository. Rewrite paragraph introducing modules.
+
+ * cvs.texinfo (Starting a new project): In discussing difficulty
+ in renaming files, don't refer to "cvs 1.x"--there is no
+ non-vaporous "cvs 2.x". Reword to reflect that part of the reason
+ to avoid renames (where possible) is not because of CVS at all, and
+ to try to give a general impression of how bad CVS issues involved in
+ renaming are.
+
+Fri Sep 27 04:23:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Adding files): Talk about directories, not modules,
+ since that is what is meant. Suggest using -kb option to add
+ rather than running cvs admin after the fact and xref to Binary
+ files not admin examples. Incorporate information which had been
+ in "add" node (there was a lot of duplication). Don't document
+ use of "add" on a directory to take the place of "cvs update -d";
+ the latter is simpler and more logical.
+ (add, add options, add examples): Removed.
+ (release output, release options): Update xrefs accordingly.
+ (Adding files, Removing files): Mention the fact that adds and
+ removes are branch-specific.
+ (Merging adds and removals): New node.
+
+ * cvs.texinfo (Concurrency): When mentioning RCS locks, use the
+ term reserved checkouts and xref to the place where we discuss
+ them in more depth.
+
+Thu Sep 26 08:26:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (log): Add comments about timezones.
+ (log, Common options): Add index entries for timezone and zone, time.
+
+Wed Sep 25 11:05:30 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (log options): Add xref to where we describe the
+ date formats that -d accepts.
+ (Common options): Don't refer to date formats accepted by co(1);
+ CVS's rules have never been the same. Add long whiny comment
+ about what a mess date formats are.
+
+Tue Sep 24 11:49:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (From other version control systems): The RCS file
+ must not be locked when you copy it to the CVS repository.
+
+ * cvs.texinfo (Editing files): Also discuss how to revert in the
+ non-watch case. Add some index entries.
+
+ * cvs.texinfo (update output): Add comment about how we *should*
+ be handling .# files. Mention fact that it is different under
+ VMS. Add .# to index.
+
+Fri Sep 20 13:08:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Multiple developers): Revise text on reserved
+ versus unreserved checkouts extensively. Move index entries for
+ "reserved checkouts" and "RCS-style locking" to here. Add
+ cross-reference to cvs admin -l. Add new section "Choosing a
+ model".
+ (Editing files): Add note about use of the word "checkout".
+
+Tue Sep 17 00:54:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Defining the module): Don't suggest "cvs co
+ modules"; that depends on a "modules" module being defined which
+ is not the default which is created by "cvs init". Instead
+ suggest "cvs co CVSROOT/modules" which should always work.
+
+Tue Sep 17 00:43:49 1996 VaX#n8 <vax@linkdead.paranoia.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Rename by copying): Suggest "cvs tag -d" on the file
+ "new", not on everything. Also don't suggest deleting branch tags.
+
+Tue Sep 17 00:34:39 1996 David A. Swierczek <swierczekd@med.ge.com>
+
+ * Makefile.in (install-info): Note whether files are in srcdir and
+ deal with it rather than cd'ing into srcdir.
+
+Mon Sep 16 23:33:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Add comment about using wrappers to
+ compress files in the repository.
+
+ * cvs.texinfo (modules): Add comments about how we should be
+ documenting how -i and friends operate in client/server CVS.
+
+ * cvs.texinfo (File permissions): Describe the need for write
+ permissions for locks and val-tags.
+
+ * cvs.texinfo (commitinfo): Add comment about using commitinfo to
+ enforce who has access.
+
+Wed Jul 24 17:01:41 1996 Larry Jones <larry.jones@sdrc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (checkout): Refer to "update output" node.
+ (import): Add new import output node.
+ (release): Correct release output menu entry (used to be
+ release options instead).
+ (update output): Say this is output from checkout as well as
+ update.
+
+Mon Sep 16 16:18:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Clarify that CVS uses MM/DD/YY dates.
+
+ * cvs.texinfo (Common options): Add comment about what HEAD means.
+
+Mon Sep 16 10:52:04 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.texinfo (Global options): Document global '-T' option.
+
+Sat Sep 14 10:46:58 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keeping a checked out copy): New node.
+
+Fri Sep 13 23:55:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Magic branch numbers): Delete song and dance about
+ how cvs log can't cope with magic branches because rlog doesn't
+ know about them; cvs log no longer calls rlog. Delete item about
+ how you can't specify a symbolic branch to cvs log; that is fixed.
+
+Wed Sep 11 22:48:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication server): Add comments
+ regarding port numbers and troubleshooting.
+
+Tue Sep 10 10:36:00 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (What is CVS?): Reword text regarding info-cvs,
+ to avoid overfull hbox.
+
+ * cvs.texinfo (Binary files): Add comment about further issues
+ with recovering from failure to use -kb.
+
+ * cvs.texinfo (Conflicts example): Describe the "feature" by which
+ CVS won't check in files with conflicts.
+ (File status): Expand and revise to document all the possible
+ statuses from cvs status. Also document "Working revision" and
+ "Repository revision". Refer to other sections for other aspects
+ of cvs status.
+ (status options): Refer to other sections as appropriate.
+ (update output): Refer user to Conflicts example node. Add
+ comment regarding purging of .# files.
+
+Fri Sep 6 11:47:14 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (Kerberos authenticated): Mention need for
+ --enable-encryption option in order to use encryption.
+ (Global options): Likewise, in description of -x option.
+
+Thu Sep 5 14:31:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Connecting via rsh): Discuss :ext:, :server:, and
+ CVS_RSH.
+ (Remote repositories): Mention what default is if no access method
+ is specified.
+ (Environment variables): Don't discuss CVS_RSH at length here;
+ rely on reference to "Connecting via rsh" node.
+
+Mon Aug 26 15:39:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Protocol Notes): When talking about having the
+ client know the original contents of files, suggest cvs edit as a
+ solution.
+
+Thu Aug 22 10:44:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list): Document Name keyword.
+
+ * cvs.texinfo (Tags): Revise comment regarding legal tag names.
+
+Mon Aug 12 14:58:54 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication security): Add comment
+ about how some of this is not pserver-specific.
+
+Tue Aug 6 16:48:53 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (log, log options): Update for changes to cvs log
+ now that it no longer invokes rlog.
+
+Thu Jul 25 10:10:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Fix typo (Kerberos-request ->
+ Kerberos-encrypt).
+
+Wed Jul 24 18:53:13 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.texinfo (Kerberos authenticated): Change the note that the
+ Kerberos connection is not encrypted.
+ (Global options): Add documentation for -x.
+ * cvsclient.texi (Protocol Notes): Remove enhancement note about
+ Kerberos encryption.
+ (Requests): Add documentation for Kerberos-encrypt request.
+
+Thu Jul 18 18:27:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Creating a repository): Mention need to be able to
+ create lock files in the repository.
+
+ * cvsclient.texi (Responses): In F response, make at least a
+ minimal attempt to define "flush".
+
+ * cvs.texinfo (Wrappers): Document -k.
+ (From files, Binary files in imports): Say that imports can deal
+ with binary files and refer to Wrappers node for details.
+ (Binary files): Likewise for imports and adds.
+
+Sat Jul 13 18:29:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Binary files): Add paragraph concerning the fact
+ that the keyword expansion mode is not versioned, and why this is
+ a problem.
+
+Fri Jul 12 18:55:06 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvsclient.texi (Requests): Document Gzip-stream.
+
+Thu Jul 11 21:51:45 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvsclient.texi (Responses): Document new "F" response.
+
+Wed Jul 10 18:46:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (log): Don't document "rlog"; it is deprecated.
+
+Sat Jul 6 22:07:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Environment variables): Document more temp
+ directory nonsense, this time with "patch".
+
+Fri Jul 5 23:27:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Add comment regarding "/." ending.
+
+Fri Sep 13 10:52:09 1996 Greg A. Woods <woods@clapton.seachange.com>
+
+ * cvs.texinfo: don't force afourpaper -- Letter prints much better
+ on A4 than the other way around, believe you me!
+ (rdiff options): describe -k and new -K.
+ (RCS keywords): add description of $Name.
+ (Using keywords): add description of #ident and example of using
+ $Name.
+ - also fixed cross references to Substitution modes in various
+ places.
+ (import options): mention that -b 1 imports to the trunk.
+
+Tue Jul 2 22:40:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Sticky tags): Update to reflect change in
+ "resurrected" message.
+
+Fri Jun 28 10:48:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Connecting via rsh): Add comment about what we
+ might be saying about troubleshooting.
+
+Sun Jun 23 10:07:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication security): Add comment
+ regarding anoncvs as practised by OpenBSD.
+
+Wed Jun 19 15:41:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Administrative files): Add xref to Intro
+ administrative files.
+ (Intro administrative files): Add comment suggesting future
+ reorganizations of this material.
+ (syntax): Add comment regarding this node.
+ (Getting Notified): Actually document the notify file. It hadn't
+ really been documented to speak of.
+ (editinfo,loginfo,rcsfino,cvsignore): Make the index entries
+ follow the standard "foo (admin file)" format.
+
+Fri Jun 14 18:14:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (editinfo): Discuss the way editinfo falls down in
+ the face of -m or -F options to commit, or remote CVS.
+
+Thu Jun 13 15:08:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Watches): Add comment discussing the
+ fact that using cvs edit instead of chmod is not enforced.
+
+ * cvs.texinfo (Setting up): Add index entry for "init (subcommand)".
+ (Creating a repository): Move contents of node Setting up here...
+ (Setting up): ...and remove this node.
+ (Creating a repository): Don't refer to the INSTALL file (it just
+ refers back to us!).
+
+ * cvsclient.texi (Responses): Document the fact that the server
+ should send data only when the client is expecting responses.
+
+Wed Jun 12 16:04:48 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Entries Lines): Add comment regarding specifying
+ the meaning of "any other" data, in the conflict field.
+ (Example): Make it clear that using a separate connection for each
+ command is not required by the protocol. Add some comments
+ regarding ways in which the example is out of date or wrong.
+
+Fri Jun 7 18:02:36 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * cvs.texinfo (annotate): Document new -r, -D, and -f options.
+
+Fri Jun 7 16:59:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Invoking CVS): Add comment describing why only some
+ commands are listed here.
+ (Structure, Environment variables): Don't describe CVS as a
+ front-end to RCS.
+
+Tue Jun 4 21:19:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Document Created and Update-existing.
+
+Mon Jun 3 17:01:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Clarify "diff -c" versus "diff -u"
+ format in Patched response. Don't specify how the client must
+ implement its patch-applying functionality.
+
+Sun May 26 17:12:24 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.texinfo (tag options) Document option "-c".
+
+Thu May 23 21:11:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Credits): Rewrite section on FAQ to reflect the
+ fact that FAQ is no longer maintained.
+ (What is CVS?): Mention comp.software.config-mgmt as well as
+ info-cvs. Mention the fact that info-cvs-request can be slow in
+ responding.
+ (What is CVS?): Rather than say that cvs is not a configuration
+ mangement system, say specifically what it lacks (change control,
+ etc.). I added process control (which was sorely lacking from the
+ list of configuration management functionality), and deleted some
+ functions such as tape construction which are not provided by the
+ well-known configuration management systems.
+
+ * cvs.texinfo (checkout options): Add comment regarding
+ subdirectories (lack of clarity pointed out by ian@cygnus.com).
+ Add comment about that infernal "short as possible" wording.
+
+ * cvs.texinfo (Global options): Fix error ("diff" -> "log")
+ (reported by ian@cygnus.com).
+ Remove footnote "Yes, this really should be fixed, and it's being
+ worked on"--it isn't clear what "this" is, and I doubt anyone is
+ working on it.
+
+Tue May 21 17:22:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Clarify Directory with "." as local
+ directory, and that filename for Questionable cannot contain "/".
+
+Mon May 20 13:15:25 1996 Greg A. Woods <woods@most.weird.com>
+
+ * cvs.texinfo (rdiff): description from main.c:cmd_usage
+ (rtag): description from main.c:cmd_usage
+ (status): description from main.c:cmd_usage
+ (tag): description from main.c:cmd_usage
+ [all for the sake of consistency]
+
+Fri May 17 11:42:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Add index entries for :local:, etc.
+ (Password authentication server): Revert erroneous change
+ regarding the format of CVSROOT/passwd file.
+
+Thu May 16 17:06:46 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * cvsclient.texi (Notes): Removed paragraphs about various server
+ invocations which are now described in full in node "Connection
+ and Authentication."
+ (Requests): Include a note that "gzip-file-contents" doesn't
+ follow the upper/lowercase convention and that unknown reqests
+ always elicit a response, regardless of capitalization.
+
+ * cvs.texinfo (Kerberos authenticated): Removed bogus version
+ number.
+ (Repository): explain the ":local:" access method.
+
+Wed May 15 23:43:04 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * cvsclient.texi (Goals): mention access methods.
+ (Requests): add note about convention: requests starting with a
+ captial letter don't have any expected response. Made sure each
+ request has a "Response expected" note.
+
+ * cvs.texinfo (Remote repositories): add info about access
+ methods; fix pserver info.
+
+Tue May 14 08:56:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Environment variables): Try to document somewhat
+ more accurately where we put temporary files.
+
+ * cvs.texinfo (From files): Say directory tree instead of module
+ where that is what we mean. Use @var{wdir} and @var{rdir} in the
+ example instead of using @var{dir} for two different things.
+ (From files): Say directory tree instead of module
+ where that is what we mean.
+ (Binary files): When using cvs admin -kb, one needs an extra
+ commit step on non-unix systems.
+ (Binary files in imports): New node.
+ (Wrappers): Add comment regarding indent example.
+ (Top): Don't refer to modules when that is not what we mean.
+
+Fri May 10 09:39:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Sticky tags): Explain what sticky dates and
+ non-branch sticky tags are good for.
+
+ * cvs.texinfo (Repository): Document that -d overrides CVS/Root.
+
+Wed May 1 15:38:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Tags): Document un-revision of all-uppercase tag
+ names.
+
+Wed Apr 24 08:41:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication security): Rewrite sentence
+ on complex and unknown security bugs to clarify that it is
+ referring to people who have been give access to cvs, not to holes
+ in the authentication method (which is relatively simple).
+
+Tue Apr 23 09:31:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Talk about what -m does (and does not
+ do). Other minor edits.
+
+Wed Apr 17 15:27:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (rcsinfo): Rewrite paragraph concerning remote CVS.
+ * cvsclient.texi (Responses): Document Template response.
+
+Sun Apr 14 16:01:39 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * .cvsignore: added CVSvn.texi.
+
+Wed Apr 10 16:56:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (~/.cvsrc): Mention setting global options with "cvs".
+
+ * cvs.texinfo (release): Change "modules" to "directories".
+ Release does not take module names as arguments.
+
+ * cvs.texinfo (Creating a branch): Add comments about how we
+ should better document tagging the branchpoint.
+
+Tue Apr 9 19:59:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Top): Use @value{CVSVN}, not a vague refenece to 1.4.
+
+ * cvs.texinfo (From other version control systems): New node.
+
+Mon Apr 8 15:59:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Connection and Authentication): Revise kerberos
+ and pserver sections to reflect the fact that port 2401 is now
+ officially registered.
+
+Thu Mar 28 09:51:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (History browsing): Reinstate this node. Try to get
+ it into some minimally useful state (it still needs a lot of
+ work).
+ (annotate): New node, subnode of History browing.
+
+ * cvsclient.texi (Requests): Add annotate request.
+
+Tue Mar 26 08:46:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: In various examples, change tag names to avoid tag
+ names reserved to CVS.
+
+ * cvs.texinfo (Tags): Document what is a valid tag name.
+
+ * cvs.texinfo (Substitution modes): Try to describe how the
+ various keyword expansion settings interract.
+ (Binary files): Suggest cvs update -A, not removing file and then
+ updating it, to get effect of new keyword expansion options.
+
+ * cvs.texinfo (admin options): Mention CVS's use of `dead' state.
+
+Thu Mar 21 08:25:17 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Environment variables): Expand introduction to RCS
+ environment variables. Expand and correct CVS_SERVER_SLEEP.
+
+ * cvs.texinfo (Environment variables): Remove POSIXLY_CORRECT; cvs
+ requires options to precede arguments regardless of it.
+
+Thu Mar 21 08:18:42 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.texinfo: Remove paragrahps about a forthcoming CVS
+ newsgroup and about sending patches to think.com.
+ (Environment): Document some more (all?) used environment
+ variables.
+
+Wed Mar 20 09:44:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Introduction): New node.
+ * Makefile.in: Add cruft to reflect fact that cvsclient.texi now
+ uses CVSvn.texi.
+
+Mon Mar 18 14:43:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Add Case request.
+
+Wed Mar 13 16:01:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Connection and Authentication): New node.
+
+ * cvsclient.texi (Requests): Expand discussion of Root a bit.
+
+ * cvs.texinfo (Setting up): Don't refer to INSTALL file; revise to
+ reflect some information which had been in the INSTALL file.
+
+ * cvs.texinfo (history file): Update to reflect cvsinit -> cvs
+ init. Adjust discussion of whether history file format is
+ documented.
+ (Setting up): Update to reflect cvsinit -> cvs init.
+
+ * cvsclient.texi (Requests): Document init request.
+
+Thu Feb 29 10:08:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (loginfo example): Adjust example to reflect the way
+ that CVS actually works. Add comments questioning whether that is
+ the best behavior.
+
+ * cvs.texinfo (cvsignore): Document additions to default ignore list.
+
+Mon Feb 26 13:48:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Filenames): New node, documents / vs \, etc.
+
+Wed Feb 24 1996 Marcus Daniels <marcus@sayre.sysc.pdx.edu>
+
+ * cvs.texinfo (Password authentication server): Mention
+ support for imaginary usernames.
+
+Thu Feb 15 16:34:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Variables): Add new internal variable $USER.
+
+Wed Feb 14 22:52:58 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (export, admin): Document -k option to cvs export.
+
+ * cvs.texinfo (admin options): Mention using -l, -u, -L, and -U in
+ conjunction with rcslock.pl.
+
+Mon Feb 12 16:38:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Remove references to mkmodules.
+
+Sun Feb 11 12:31:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi: Add Set request.
+
+ * cvs.texinfo (Variables): Rewrite to reflect user variables
+ replacing environment variables; motivate the discussion better.
+ (Global options): Add -s option.
+
+Sat Feb 10 11:18:37 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * cvs.texinfo (Variables): Fix @table commands.
+
+Fri Feb 9 17:31:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Variables): New node.
+
+ * Makefile.in (CVSvn.texi): New rule.
+ (OBJDIR_DISTFILES): Add CVSvn.texi.
+ (cvs.dvi,cvs.info): Add cruft to deal with it being in build dir
+ or srcdir.
+ * cvs.texinfo: Include CVSvn.texi and use the version number from
+ it instead of a hardcoded version number and date.
+
+Thu Feb 1 13:28:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Sticky tags): Expand so it really documents the
+ features it is talking about rather than referring to "Appendix
+ A". Add example of how to restore the old version of a dead
+ file. In various other parts of the manual refer to this node, in
+ some cases deleting duplicative text. In the case of cvs admin
+ -b, mention vendor branch usage.
+ (Removing files): Discuss removing files (in user-visible terms,
+ not in terms of the Attic and such).
+ (remove): Remove node; merge contents into Removing files.
+
+Tue Jan 30 17:52:06 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * cvs.texinfo: Tweak @top node, to make file compatible with both
+ makeinfo and texinfo-format-buffer. Perhaps we should fix the
+ formatters to agree on what constitutes valid texinfo.
+
+Mon Jan 29 16:38:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requirements): New node, to talk about required
+ versus optional parts of the protocol.
+
+Sun Jan 28 09:00:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Modes): Add discussion what what the mode really
+ means (across diverse operating systems).
+
+Tue Jan 23 12:54:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Per mail from Per Cederqvist, change author to "Per
+ Cederqvist et al". Also remove sentence about Signum shipping
+ hardcopy manuals and add information on Cyclic. Change version
+ number to 1.6.87.
+
+Fri Jan 12 15:29:39 1996 Vince Demarco <vdemarco@bou.shl.com>
+
+ * cvs.texinfo: Fix the documentation for the com/uncom change
+ to wrap/unwrap. make everything consistant
+
+Wed Jan 10 16:11:54 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Concurrency): Add index entries; minor clarification.
+
+Tue Jan 9 16:03:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Getting Notified): Document users file.
+
+ * cvs.texinfo (cvsignore): Add *.obj to list of ignored files.
+
+Wed Jan 3 17:01:58 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (import): Adjust list of ignored files to match
+ recent change to CVS (CVS* -> CVS CVS.adm). Consolidate
+ discussion of ignored files in one place (with xrefs from others).
+
+ * cvsclient.texi: Remove How To node. It was out of date
+ (again!), and I am getting sick of trying to update it (internals
+ documentation should be in the comments, where it at least has a
+ fighting chance of staying up to date).
+ (Protocol): Say what \n and \t mean in this document.
+
+Tue Jan 2 23:39:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Change comb/uncom to wrap/unwrap.
+
+Mon Jan 2 23:00:00 1996 Vince Demarco <vdemarco@bou.shl.com>
+
+ * cvs.texinfo: update the Wrappers documentation so it isn't
+ so NEXTSTEP centric. The wrappers code has alot of other
+ general uses. The new version of the documentation tryes
+ to show that to the reader.
+
+Mon Jan 1 13:09:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Clarify that Module-expansion is not
+ suitable for passing to co.
+
+Sun Dec 31 10:53:47 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication server): Suggest specifying
+ -b in inetd.conf.
+
+ * cvs.texinfo (Password authentication): Variety of cleanups and
+ minor fixes, including shorter node names.
+
+Sun Dec 24 02:37:51 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.texinfo (Using the client with password authentication):
+ tixed fypos.
+
+Sun Dec 24 00:00:16 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.texinfo (Remote repositories): use @code{rsh} most places,
+ because it is the name of a program, and because I am a pedant.
+ Refer to new node "Password authenticated".
+ (Password authenticated): new node.
+ (Setting up the server for password authentication): new node.
+ (Using the client with password authentication): new node.
+ (Security considerations with password authentication): new node.
+
+ These are all really long node names, but it seems necessary that
+ they be descriptive in case they're referenced elsewhere. If you
+ can think of a way out of this, please change them.
+
+Thu Dec 21 12:09:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Add Questionable. Revise
+ documentation of export and update to explain role of -I option.
+
+Tue Dec 19 16:44:18 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Update binary files info for -kb.
+
+Mon Dec 11 12:20:55 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Responses): Add Notified and Mode.
+ (Requests): Add Notify, noop, watch-on, watch-off, watch-add,
+ watch-remove, watchers, and editors.
+ * cvs.texinfo (Watches): New node, to describe new developer
+ communication features.
+
+Thu Nov 23 08:59:09 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (admin options): In saying that cvs admin -o is not
+ such a good way to undo a change, refer to the section which
+ describes the preferred way.
+
+Thu Nov 13 16:39:03 1995 Fred Fish <fnf@cygnus.com>
+
+ * Makefile.in: Remove extraneous tab from empty line.
+
+Mon Nov 13 15:00:26 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Concurrency): New node, to describe user-visible
+ behaviors associated with cvs locks.
+
+ * cvs.texinfo (Remote repositories): Add more details of how to
+ set things up (with rsh and kerberos).
+
+Thu Nov 9 11:41:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Remove -Q and -q options from command synopses.
+
+Wed Nov 8 09:38:00 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Notes): Revise paragraph on server memory use
+ problem.
+
+Tue Nov 7 16:26:39 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Document merging more than once from a branch;
+ miscellaneous cleanups.
+
+Mon Oct 30 13:12:53 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (modules): Document -e.
+
+Thu Oct 26 11:15:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Tags): Update "version" vs. "revision" for CVS 1.5.
+ (Index,BUGS): Change bug reporting address from Per Cederqvist to
+ bug-cvs@prep.ai.mit.edu.
+
+Wed Oct 25 15:37:05 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Miscellaneous minor changes (clean up CVS/Root
+ stuff, don't say release requires a module entry, etc.).
+
+Tue Oct 24 11:01:22 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: More precisely describe scope of document.
+ * cvsclient.texi: Describe scope of document
+
+Thu Oct 12 11:25:40 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * cvs.texinfo: cover page now refers to CVS 1.6, and "last
+ updated" date has been upped to today.
+
+Wed Oct 11 22:30:10 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (info): Look for *.info* either in build dir or in
+ srcdir.
+
+Mon Oct 2 17:10:49 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.texinfo (admin): Describe usage of CVS_ADMIN_GROUP to
+ restrict usage of admin.
+
+Fri Oct 6 21:17:50 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (~/.cvsrc): Document change to command name matching.
+
+Thu Oct 5 18:03:41 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (install-info): Add comment about srcdir.
+
+Wed Sep 13 12:45:53 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Moving files): Rewrite "Outside" node to clarify
+ that history is still there and describe how to get it. Assorted
+ cleanups.
+
+Tue Sep 12 19:02:47 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Removing files): Remove section on limitations
+ which are gone now that we have death support.
+
+Wed Aug 30 12:32:29 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.texinfo (Remote Repositories): new node, referred to from
+ `Basics' and `Repository'.
+ (Repository): documented new `-d' vs. `$CVSROOT' vs. `CVS/Root'
+ behavior.
+ (commitinfo): document client/server-case behavior.
+ (editinfo): document client/server-case behavior.
+ (loginfo): document client/server-case behavior.
+ (rcsinfo): document client/server-case behavior.
+
+Mon Aug 21 00:23:45 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (How To): The way to force rsh is to set
+ CVS_CLIENT_PORT to -1, not to some bogus value.
+
+Tue Aug 15 17:12:08 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.texinfo
+ (Basic concepts): talk about remote repositories.
+ (Repository): same.
+
+Mon Jul 24 19:09:12 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: Remove references to -q and -Q command options.
+
+Fri Jul 21 10:33:07 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * cvs.texinfo: Changes for CVSEDITOR and wrappers.
+
+Thu Jul 13 23:04:12 CDT 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (cvs-paper.ps): *Never* redirect output directly to
+ the target (usu $@) of a rule. Instead, redirect to a temporary
+ file, and then move that temporary to the target. I chose to
+ name temporary files $@-t. Remember to be careful that the length
+ of the temporary file name not exceed the 14-character limit.
+
+Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * doc/cvs.texinfo:
+ - document '-q' for 'cvs status'
+ - correction to regexp use in *info files
+ - correction to use of 'cvsinit' script
+ (from previous local changes)
+
+Tue Jun 20 18:57:55 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (dist-dir): Depend on $(OBJDIR_DISTFILES).
+
+Fri Jun 16 21:56:16 1995 Karl Fogel <kfogel@cyclic.com>
+ and Jim Meyering <meyering@comco.com>
+
+ * update.c (update_file_proc): If noexec, just write 'C', don't merge.
+
+Fri Jun 16 07:56:04 1995 Jim Kingdon (kingdon@cyclic.com)
+
+ * cvs-paper.ps: Added.
+
+Sat May 27 08:46:00 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (Makefile): Regenerate only Makefile in current
+ directory when Makefile.in is out of date. Depend on ../config.status.
+
+Sat May 27 08:08:18 1995 Jim Meyering (meyering@comco.com)
+
+ * doc/Makefile.in (realclean): Remove more postscript and info files.
+
+Fri Apr 28 22:44:06 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (DISTFILES): Updated.
+ (doc): Depend on cvsclient.ps too.
+ (cvs.aux, cvsclient.aux): Add target.
+ (cvsclient.dvi): Don't nuke the aux file. They're small and
+ helpful.
+ (cvsclient.ps): New target.
+ (dist-dir): Renamed from dist; changed to work with DISTDIR
+ variable from parent.
+
+Sun Apr 23 22:13:18 1995 Noel Cragg <noel@vo.com>
+
+ * Makefile: Added more files to the `clean' target.
+ * .cvsignore: Added the same files.
+
+Mon Nov 28 10:22:46 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Notes): Remove item about commit options; now
+ fixed. Rewrite paragraph about server memory usage.
+
+ * cvsclient.texi (Responses): Add Set-checkin-prog and
+ Set-update-prog.
+ (Requests): Add Checkin-prog and Update-prog.
+ * cvsclient.texi (TODO): Remove last item (it is fixed) and node.
+
+Fri Nov 18 16:51:36 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Requests): Add Max-dotdot.
+
+Thu Nov 3 07:04:24 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Add Directory request.
+ (TODO): Remove item about renaming directories.
+ (Protocol): Change @subheading to @node/@section.
+
+Fri Oct 28 07:51:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Add expand-module request and
+ Module-expansion response.
+ (Protocol Notes, TODO): Remove items about cvs co funkiness.
+
+Wed Oct 12 19:49:36 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Add Copy-file response.
+
+ * cvsclient.texi (How To): Correct item about where declaration
+ of cvs commands go.
+
+ * cvsclient.texi (Protocol): Add new commands. Merge description
+ of how commands work which was duplicated among the various
+ commands. Formatting cleanups.
+ (TODO): Remove item about bad error message on checking in a
+ nonexistent file; this works now (presumably fixed by the
+ Unchanged stuff).
+ (Notes): Remove thing about trying unsupported commands via NFS,
+ rdist, etc. Also remove item about some commands not being
+ supported. There are no unsupported commands anymore.
+
+Tue Sep 13 13:28:52 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Document New-entry response.
+
+Mon Sep 12 06:35:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Clarify that checksum is of patched
+ file, not patch itself. Fix typo (valid-requests -> Valid-requests).
+
+ * cvsclient.texi (Protocol): Document Sticky request and
+ Set-sticky and Clear-sticky responses.
+ (Notes): Remove sticky tags from todo list.
+
+Thu Sep 8 14:23:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Document Static-directory requests
+ and Set-static-directory and Clear-static-directory responses.
+ (Notes): Remove Entries.Static support from todo list.
+
+ * cvsclient.texi (Protocol): Document Unchanged and UseUnchanged
+ requests. Update documentation of Entry and Lost accordingly.
+
+Mon Aug 22 14:08:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Goals): Remove mention of rsh.
+ (Protocol Notes, TODO): Remove compression item.
+ (Protocol): Document "status" request.
+ (TODO): Remove suggestion to add "cvs status".
+
+Tue Jul 19 10:02:53 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * Makefile.in (install-info): Do not depend upon installdirs.
+
+Fri Jul 15 12:56:53 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * Makefile.in (all): Do not depend upon info.
+ (install): Do not depend upon install-info.
+
+Thu Jul 7 20:43:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * cvsclient.texi (Protocol): Add Checksum response.
+
+Thu Jun 30 15:16:50 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Add Global_option request.
+
+Wed Jun 29 14:09:42 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * cvsclient.texi: Describe sending patches, including the dummy
+ update-patches request and the Patched response. Mention Kerberos
+ authentication using ``cvs kserver''. Some other minor changes.
+
+Tue Jun 28 15:21:06 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol Notes): Remove note about sending diffs
+ in Updated; Ian did it. Remove note about adding encryption to rsh.
+
+Sat May 7 10:44:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi (Protocol): Document Modified without Entry. Add
+ `add' and `remove' and `Remove-entry'. Formatting cleanups.
+
+Tue Apr 19 01:29:04 1994 John Gilmore (gnu@cygnus.com)
+
+ * cvsclient.texi: New node How To; cleanups throughout.
+ * Makefile.in: Add dependencies on cvsclient.texi.
+
diff --git a/doc/ChangeLog.fsf b/doc/ChangeLog.fsf
new file mode 100644
index 0000000..2f14099
--- /dev/null
+++ b/doc/ChangeLog.fsf
@@ -0,0 +1,38 @@
+Thu Sep 15 14:19:50 1994 david d `zoo' zuhn <zoo@monad.armadillo.com>
+
+ * Makefile.in: define TEXI2DVI
+
+Sat Dec 18 01:23:39 1993 david d zuhn (zoo@monad.armadillo.com)
+
+ * cvs.texinfo: document -k SUBST options to 'cvs import';
+ regularize use @sc{cvs}
+
+ * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead
+ (install-info): grab all info files, not just *.info
+
+Mon Oct 11 16:23:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvsclient.texi: New node TODO; various other changes.
+
+Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in, configure.in: removed traces of namesubdir,
+ -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced
+ copyrights to '92, changed some from Cygnus to FSF.
+
+Tue Dec 10 04:07:10 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: infodir belongs in datadir.
+
+Thu Dec 5 22:46:01 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: idestdir and ddestdir go away. Added copyrights
+ and shift gpl to v2. Added ChangeLog if it didn't exist. docdir
+ and mandir now keyed off datadir by default.
+
+Wed Nov 27 02:45:18 1991 K. Richard Pixley (rich at sendai)
+
+ * brought Makefile.in's up to standards.text.
+
+ * fresh changelog.
+
diff --git a/doc/HACKING.DOCS b/doc/HACKING.DOCS
new file mode 100644
index 0000000..adf6077
--- /dev/null
+++ b/doc/HACKING.DOCS
@@ -0,0 +1,46 @@
+Here's some of the texinfo conventions the CVS documentation uses:
+
+@code{ ... } command usage & command snippets, including
+ command names.
+@var{ ... } variables - text which the user is expected to
+ replace with some meaningful text of their own
+ in actual usage.
+@file{ ... } file names
+@samp{ ... } for most anything else you need quotes around
+ (often still misused for command snippets)
+@example ... @end example example command usage and output, etc.
+@emph{ ... } emphasis - warnings, stress, etc. This will be
+ bracketed by underline characters in info files
+ (_ ... _) and in italics in PDF & probably in
+ postscript & HTML.
+@strong{ ... } Similar to @emph{}, but the effect is to
+ bracket with asterisks in info files (* ... *)
+ and in bold in PDF & probably in postscript &
+ HTML.
+@noindent Suppresses indentation of the following
+ paragraph. This can ocassionally be useful
+ after examples and the like.
+@cindex ... Add a tag to the index.
+@pxref{ ... } Cross reference in parentheses.
+@xref{ ... } Cross reference.
+
+Preformatted text should be marked as such (use @example... there may be other
+ways) since many of the final output formats can use relational fonts otherwise
+and marking it as formatted should restrict it to a fixed width font. Keep
+this sort of text to 80 characters or less per line since larger may not be
+properly viewable for some info users.
+
+There are dictionary lists and function definition markers. Scan cvs.texinfo
+for their usage. There may be table definitions as well but I haven't used
+them.
+
+Use lots of index markers. Scan the index for the current style. Try to reuse
+an existing entry if the meaning is similar.
+
+`makeinfo' 3.11 or greater is required for output generation since earlier
+versions do not support the @ifnottex & @ifnothtml commands. There may be
+other commands used in `cvs.texinfo' that are unsupported by earlier versions
+of `makeinfo' by the time you read this.
+
+For more on using texinfo docs, see the `info texinfo' documentation or
+http://www.gnu.org/manual/texinfo/texinfo.html .
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..52e9302
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,154 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for GNU CVS documentation (excluding man pages - see ../man).
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+SUBDIRS = i18n
+
+info_TEXINFOS = cvs.texinfo cvsclient.texi
+man_MANS = $(srcdir)/cvs.1
+
+PSS = \
+ cvs.ps \
+ cvs-paper.ps \
+ cvsclient.ps
+
+PDFS = \
+ cvs.pdf \
+ $(srcdir)/cvs-paper.pdf \
+ cvsclient.pdf
+
+TXTS = \
+ cvs.txt \
+ cvsclient.txt
+
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog.fsf \
+ HACKING.DOCS \
+ RCSFILES \
+ $(srcdir)/cvs.1 \
+ cvs-paper.ms \
+ cvs.man.header \
+ cvs.man.footer \
+ getdate.texi \
+ mdate-sh \
+ writeproxy.rtf \
+ $(PDFS)
+
+MOSTLYCLEANFILES =
+
+CLEANFILES = \
+ $(PSS) \
+ $(TXTS)
+
+DISTCLEANFILES =
+
+MAINTAINERCLEANFILES = \
+ $(PDFS)
+
+doc: info pdf
+.PHONY: doc
+
+txt: $(TXTS)
+.PHONY: txt
+
+dvi: cvs.dvi cvsclient.dvi
+.PHONY: dvi
+
+# FIXME-AUTOMAKE:
+# For some reason if I remove version.texi, it doesn't get built automatically.
+# This needs to be fixed in automake.
+cvs.txt: cvs.texinfo $(srcdir)/version.texi
+cvsclient.txt: cvsclient.texi $(srcdir)/version-client.texi
+
+# The cvs-paper.pdf target needs to be very specific so that the other PDFs get
+# generated correctly. If a more generic .ps.pdf implicit target is defined,
+# and cvs.ps is made before cvs.pdf, then cvs.pdf can be generated from the
+# .ps.pdf target and the PS source, which contains less information (hyperlinks
+# and such) than the usual texinfo source.
+#
+# It is possible that an implicit .ms.ps target could be safely defined. I
+# don't recall looking into it.
+cvs-paper.ps: cvs-paper.ms
+ $(ROFF) -t -p -ms -Tps $(srcdir)/cvs-paper.ms >cvs-paper.ps-t
+ cp cvs-paper.ps-t $@
+ -@rm -f cvs-paper.ps-t
+
+# This rule introduces some redundancy, but `make distcheck' requires that
+# Nothing in $(srcdir) be rebuilt, and this will always be rebuilt when it
+# is dependant on cvs-paper.ps and cvs-paper.ps isn't distributed.
+$(srcdir)/cvs-paper.pdf: cvs-paper.ms
+ $(ROFF) -t -p -ms -Tps $(srcdir)/cvs-paper.ms >cvs-paper.ps-t
+ ps2pdf cvs-paper.ps-t cvs-paper.pdf-t
+ cp cvs-paper.pdf-t $@
+ -@rm -f cvs-paper.pdf-t cvs-paper.ps-t
+
+MOSTLYCLEANFILES += cvs-paper.pdf-t cvs-paper.ps-t
+
+# Targets to build a man page from cvs.texinfo.
+$(srcdir)/cvs.1: @MAINTAINER_MODE_TRUE@ mkman cvs.man.header cvs.texinfo cvs.man.footer
+ $(PERL) ./mkman $(srcdir)/cvs.man.header $(srcdir)/cvs.texinfo \
+ $(srcdir)/cvs.man.footer >cvs.tmp
+ cp cvs.tmp $(srcdir)/cvs.1
+ -@rm -f cvs.tmp
+MAINTAINERCLEANFILES += $(srcdir)/cvs.1
+
+cvs.dvi cvs.html $(srcdir)/cvs.info cvs.pdf cvs.ps cvs.txt: $(srcdir)/getdate-cvs.texi
+$(srcdir)/getdate-cvs.texi: stamp-gdt
+stamp-gdt: getdate.texi
+ @echo "@c This file is generated via a rule in Makefile.am from the" \
+ >getdate-cvs.tmp
+ @echo "@c getdate.texi file." >>getdate-cvs.tmp
+ @echo "@c" >>getdate-cvs.tmp
+ @echo "@c *** DO NOT EDIT THIS FILE DIRECTLY ***" >>getdate-cvs.tmp
+ @echo "@c" >>getdate-cvs.tmp
+ @echo "@c Edit getdate.texi instead." >>getdate-cvs.tmp
+ @echo >>getdate-cvs.tmp
+ sed -e "s/^@chapter /@appendixsec /" \
+ -e "s/^@section /@appendixsubsec /" \
+ <$(srcdir)/getdate.texi >>getdate-cvs.tmp
+ @cmp -s getdate-cvs.tmp $(srcdir)/getdate-cvs.texi \
+ || (echo "Updating getdate-cvs.texi"; \
+ cp getdate-cvs.tmp $(srcdir)/getdate-cvs.texi)
+ -@rm -f getdate-cvs.tmp
+ @cp $(srcdir)/getdate-cvs.texi $@
+
+## If getdate-cvs.texi is not distributed, infos get rebuilt at every install.
+## This is a pretty big no-no.
+EXTRA_DIST += getdate-cvs.texi
+MOSTLYCLEANFILES += getdate-cvs.tmp
+DISTCLEANFILES += stamp-gdt
+
+# texinfo based targets automake neglects to include
+SUFFIXES = .txt
+.texinfo.txt:
+ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ --no-headers -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+.txi.txt:
+ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ --no-headers -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+.texi.txt:
+ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ --no-headers -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+
+##
+## MAINTAINER Targets
+##
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..a049ca7
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,987 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for GNU CVS documentation (excluding man pages - see ../man).
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/mkman.pl $(srcdir)/stamp-1 $(srcdir)/stamp-vti \
+ $(srcdir)/version-client.texi $(srcdir)/version.texi ChangeLog \
+ mdate-sh
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = mkman
+SOURCES =
+DIST_SOURCES =
+INFO_DEPS = $(srcdir)/cvs.info $(srcdir)/cvsclient.info
+TEXINFO_TEX = $(top_srcdir)/build-aux/texinfo.tex
+am__TEXINFO_TEX_DIR = $(top_srcdir)/build-aux
+DVIS = cvs.dvi cvsclient.dvi
+HTMLS = cvs.html cvsclient.html
+TEXINFOS = cvs.texinfo cvsclient.texi
+TEXI2PDF = $(TEXI2DVI) --pdf --batch
+MAKEINFOHTML = $(MAKEINFO) --html
+AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
+DVIPS = dvips
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)"
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+SUBDIRS = i18n
+info_TEXINFOS = cvs.texinfo cvsclient.texi
+man_MANS = $(srcdir)/cvs.1
+PSS = \
+ cvs.ps \
+ cvs-paper.ps \
+ cvsclient.ps
+
+PDFS = \
+ cvs.pdf \
+ $(srcdir)/cvs-paper.pdf \
+ cvsclient.pdf
+
+TXTS = \
+ cvs.txt \
+ cvsclient.txt
+
+EXTRA_DIST = .cvsignore ChangeLog.fsf HACKING.DOCS RCSFILES \
+ $(srcdir)/cvs.1 cvs-paper.ms cvs.man.header cvs.man.footer \
+ getdate.texi mdate-sh writeproxy.rtf $(PDFS) getdate-cvs.texi
+MOSTLYCLEANFILES = cvs-paper.pdf-t cvs-paper.ps-t getdate-cvs.tmp
+CLEANFILES = \
+ $(PSS) \
+ $(TXTS)
+
+DISTCLEANFILES = stamp-gdt
+MAINTAINERCLEANFILES = $(PDFS) $(srcdir)/cvs.1
+
+# texinfo based targets automake neglects to include
+SUFFIXES = .txt
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .txt .dvi .html .info .pdf .ps .texi .texinfo .txi
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu doc/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+mkman: $(top_builddir)/config.status $(srcdir)/mkman.pl
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+.texinfo.info:
+ restore=: && backupdir="$(am__leading_dot)am$$$$" && \
+ am__cwd=`pwd` && cd $(srcdir) && \
+ rm -rf $$backupdir && mkdir $$backupdir && \
+ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
+ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
+ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
+ done; \
+ else :; fi && \
+ cd "$$am__cwd"; \
+ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ -o $@ $<; \
+ then \
+ rc=0; \
+ cd $(srcdir); \
+ else \
+ rc=$$?; \
+ cd $(srcdir) && \
+ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
+ fi; \
+ rm -rf $$backupdir; exit $$rc
+
+.texinfo.dvi:
+ TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+ $(TEXI2DVI) $<
+
+.texinfo.pdf:
+ TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+ $(TEXI2PDF) $<
+
+.texinfo.html:
+ rm -rf $(@:.html=.htp)
+ if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ -o $(@:.html=.htp) $<; \
+ then \
+ rm -rf $@; \
+ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
+ mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \
+ else \
+ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
+ rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \
+ exit 1; \
+ fi
+$(srcdir)/cvs.info: cvs.texinfo $(srcdir)/version.texi
+cvs.dvi: cvs.texinfo $(srcdir)/version.texi
+cvs.pdf: cvs.texinfo $(srcdir)/version.texi
+cvs.html: cvs.texinfo $(srcdir)/version.texi
+$(srcdir)/version.texi: @MAINTAINER_MODE_TRUE@ $(srcdir)/stamp-vti
+$(srcdir)/stamp-vti: cvs.texinfo $(top_srcdir)/configure
+ @(dir=.; test -f ./cvs.texinfo || dir=$(srcdir); \
+ set `$(SHELL) $(top_srcdir)/build-aux/mdate-sh $$dir/cvs.texinfo`; \
+ echo "@set UPDATED $$1 $$2 $$3"; \
+ echo "@set UPDATED-MONTH $$2 $$3"; \
+ echo "@set EDITION $(VERSION)"; \
+ echo "@set VERSION $(VERSION)") > vti.tmp
+ @cmp -s vti.tmp $(srcdir)/version.texi \
+ || (echo "Updating $(srcdir)/version.texi"; \
+ cp vti.tmp $(srcdir)/version.texi)
+ -@rm -f vti.tmp
+ @cp $(srcdir)/version.texi $@
+
+mostlyclean-vti:
+ -rm -f vti.tmp
+
+maintainer-clean-vti:
+@MAINTAINER_MODE_TRUE@ -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi
+
+.texi.info:
+ restore=: && backupdir="$(am__leading_dot)am$$$$" && \
+ am__cwd=`pwd` && cd $(srcdir) && \
+ rm -rf $$backupdir && mkdir $$backupdir && \
+ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
+ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
+ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
+ done; \
+ else :; fi && \
+ cd "$$am__cwd"; \
+ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ -o $@ $<; \
+ then \
+ rc=0; \
+ cd $(srcdir); \
+ else \
+ rc=$$?; \
+ cd $(srcdir) && \
+ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
+ fi; \
+ rm -rf $$backupdir; exit $$rc
+
+.texi.dvi:
+ TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+ $(TEXI2DVI) $<
+
+.texi.pdf:
+ TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+ $(TEXI2PDF) $<
+
+.texi.html:
+ rm -rf $(@:.html=.htp)
+ if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ -o $(@:.html=.htp) $<; \
+ then \
+ rm -rf $@; \
+ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
+ mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \
+ else \
+ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
+ rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \
+ exit 1; \
+ fi
+$(srcdir)/cvsclient.info: cvsclient.texi $(srcdir)/version-client.texi
+cvsclient.dvi: cvsclient.texi $(srcdir)/version-client.texi
+cvsclient.pdf: cvsclient.texi $(srcdir)/version-client.texi
+cvsclient.html: cvsclient.texi $(srcdir)/version-client.texi
+$(srcdir)/version-client.texi: @MAINTAINER_MODE_TRUE@ $(srcdir)/stamp-1
+$(srcdir)/stamp-1: cvsclient.texi $(top_srcdir)/configure
+ @(dir=.; test -f ./cvsclient.texi || dir=$(srcdir); \
+ set `$(SHELL) $(top_srcdir)/build-aux/mdate-sh $$dir/cvsclient.texi`; \
+ echo "@set UPDATED $$1 $$2 $$3"; \
+ echo "@set UPDATED-MONTH $$2 $$3"; \
+ echo "@set EDITION $(VERSION)"; \
+ echo "@set VERSION $(VERSION)") > 1.tmp
+ @cmp -s 1.tmp $(srcdir)/version-client.texi \
+ || (echo "Updating $(srcdir)/version-client.texi"; \
+ cp 1.tmp $(srcdir)/version-client.texi)
+ -@rm -f 1.tmp
+ @cp $(srcdir)/version-client.texi $@
+
+mostlyclean-1:
+ -rm -f 1.tmp
+
+maintainer-clean-1:
+@MAINTAINER_MODE_TRUE@ -rm -f $(srcdir)/stamp-1 $(srcdir)/version-client.texi
+.dvi.ps:
+ TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ $(DVIPS) -o $@ $<
+
+uninstall-info-am:
+ @$(PRE_UNINSTALL)
+ @if (install-info --version && \
+ install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ relfile=`echo "$$file" | sed 's|^.*/||'`; \
+ echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \
+ install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \
+ done; \
+ else :; fi
+ @$(NORMAL_UNINSTALL)
+ @list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ relfile=`echo "$$file" | sed 's|^.*/||'`; \
+ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \
+ (if cd "$(DESTDIR)$(infodir)"; then \
+ echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \
+ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \
+ else :; fi); \
+ done
+
+dist-info: $(INFO_DEPS)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ list='$(INFO_DEPS)'; \
+ for base in $$list; do \
+ case $$base in \
+ $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \
+ esac; \
+ if test -f $$base; then d=.; else d=$(srcdir); fi; \
+ for file in $$d/$$base*; do \
+ relfile=`expr "$$file" : "$$d/\(.*\)"`; \
+ test -f $(distdir)/$$relfile || \
+ cp -p $$file $(distdir)/$$relfile; \
+ done; \
+ done
+
+mostlyclean-aminfo:
+ -rm -rf cvs.aux cvs.cp cvs.cps cvs.fn cvs.fns cvs.ky cvs.kys cvs.log cvs.pg \
+ cvs.pgs cvs.tmp cvs.toc cvs.tp cvs.tps cvs.vr cvs.vrs \
+ cvs.dvi cvs.pdf cvs.ps cvs.html cvsclient.aux cvsclient.cp \
+ cvsclient.cps cvsclient.fn cvsclient.fns cvsclient.ky \
+ cvsclient.kys cvsclient.log cvsclient.pg cvsclient.pgs \
+ cvsclient.tmp cvsclient.toc cvsclient.tp cvsclient.tps \
+ cvsclient.vr cvsclient.vrs cvsclient.dvi cvsclient.pdf \
+ cvsclient.ps cvsclient.html
+
+maintainer-clean-aminfo:
+ @list='$(INFO_DEPS)'; for i in $$list; do \
+ i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \
+ echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \
+ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \
+ done
+install-man1: $(man1_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)"
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/$(srcdir)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-info
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(INFO_DEPS) $(MANS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi-am: $(DVIS)
+
+html: html-recursive
+
+html-am: $(HTMLS)
+
+info: info-recursive
+
+info-am: $(INFO_DEPS)
+
+install-data-am: install-info-am install-man
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-info-am: $(INFO_DEPS)
+ @$(NORMAL_INSTALL)
+ test -z "$(infodir)" || $(mkdir_p) "$(DESTDIR)$(infodir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ esac; \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \
+ for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \
+ $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \
+ if test -f $$ifile; then \
+ relfile=`echo "$$ifile" | sed 's|^.*/||'`; \
+ echo " $(INSTALL_DATA) '$$ifile' '$(DESTDIR)$(infodir)/$$relfile'"; \
+ $(INSTALL_DATA) "$$ifile" "$(DESTDIR)$(infodir)/$$relfile"; \
+ else : ; fi; \
+ done; \
+ done
+ @$(POST_INSTALL)
+ @if (install-info --version && \
+ install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ relfile=`echo "$$file" | sed 's|^.*/||'`; \
+ echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\
+ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\
+ done; \
+ else : ; fi
+install-man: install-man1
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-1 \
+ maintainer-clean-aminfo maintainer-clean-generic \
+ maintainer-clean-vti
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-1 mostlyclean-aminfo mostlyclean-generic \
+ mostlyclean-vti
+
+pdf: pdf-recursive
+
+pdf-am: $(PDFS)
+
+ps: ps-recursive
+
+ps-am: $(PSS)
+
+uninstall-am: uninstall-info-am uninstall-man
+
+uninstall-info: uninstall-info-recursive
+
+uninstall-man: uninstall-man1
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+ clean clean-generic clean-recursive ctags ctags-recursive \
+ dist-info distclean distclean-generic distclean-recursive \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-man1 install-strip installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean maintainer-clean-1 \
+ maintainer-clean-aminfo maintainer-clean-generic \
+ maintainer-clean-recursive maintainer-clean-vti mostlyclean \
+ mostlyclean-1 mostlyclean-aminfo mostlyclean-generic \
+ mostlyclean-recursive mostlyclean-vti pdf pdf-am ps ps-am tags \
+ tags-recursive uninstall uninstall-am uninstall-info-am \
+ uninstall-man uninstall-man1
+
+
+doc: info pdf
+.PHONY: doc
+
+txt: $(TXTS)
+.PHONY: txt
+
+dvi: cvs.dvi cvsclient.dvi
+.PHONY: dvi
+
+# FIXME-AUTOMAKE:
+# For some reason if I remove version.texi, it doesn't get built automatically.
+# This needs to be fixed in automake.
+cvs.txt: cvs.texinfo $(srcdir)/version.texi
+cvsclient.txt: cvsclient.texi $(srcdir)/version-client.texi
+
+# The cvs-paper.pdf target needs to be very specific so that the other PDFs get
+# generated correctly. If a more generic .ps.pdf implicit target is defined,
+# and cvs.ps is made before cvs.pdf, then cvs.pdf can be generated from the
+# .ps.pdf target and the PS source, which contains less information (hyperlinks
+# and such) than the usual texinfo source.
+#
+# It is possible that an implicit .ms.ps target could be safely defined. I
+# don't recall looking into it.
+cvs-paper.ps: cvs-paper.ms
+ $(ROFF) -t -p -ms -Tps $(srcdir)/cvs-paper.ms >cvs-paper.ps-t
+ cp cvs-paper.ps-t $@
+ -@rm -f cvs-paper.ps-t
+
+# This rule introduces some redundancy, but `make distcheck' requires that
+# Nothing in $(srcdir) be rebuilt, and this will always be rebuilt when it
+# is dependant on cvs-paper.ps and cvs-paper.ps isn't distributed.
+$(srcdir)/cvs-paper.pdf: cvs-paper.ms
+ $(ROFF) -t -p -ms -Tps $(srcdir)/cvs-paper.ms >cvs-paper.ps-t
+ ps2pdf cvs-paper.ps-t cvs-paper.pdf-t
+ cp cvs-paper.pdf-t $@
+ -@rm -f cvs-paper.pdf-t cvs-paper.ps-t
+
+# Targets to build a man page from cvs.texinfo.
+$(srcdir)/cvs.1: @MAINTAINER_MODE_TRUE@ mkman cvs.man.header cvs.texinfo cvs.man.footer
+ $(PERL) ./mkman $(srcdir)/cvs.man.header $(srcdir)/cvs.texinfo \
+ $(srcdir)/cvs.man.footer >cvs.tmp
+ cp cvs.tmp $(srcdir)/cvs.1
+ -@rm -f cvs.tmp
+
+cvs.dvi cvs.html $(srcdir)/cvs.info cvs.pdf cvs.ps cvs.txt: $(srcdir)/getdate-cvs.texi
+$(srcdir)/getdate-cvs.texi: stamp-gdt
+stamp-gdt: getdate.texi
+ @echo "@c This file is generated via a rule in Makefile.am from the" \
+ >getdate-cvs.tmp
+ @echo "@c getdate.texi file." >>getdate-cvs.tmp
+ @echo "@c" >>getdate-cvs.tmp
+ @echo "@c *** DO NOT EDIT THIS FILE DIRECTLY ***" >>getdate-cvs.tmp
+ @echo "@c" >>getdate-cvs.tmp
+ @echo "@c Edit getdate.texi instead." >>getdate-cvs.tmp
+ @echo >>getdate-cvs.tmp
+ sed -e "s/^@chapter /@appendixsec /" \
+ -e "s/^@section /@appendixsubsec /" \
+ <$(srcdir)/getdate.texi >>getdate-cvs.tmp
+ @cmp -s getdate-cvs.tmp $(srcdir)/getdate-cvs.texi \
+ || (echo "Updating getdate-cvs.texi"; \
+ cp getdate-cvs.tmp $(srcdir)/getdate-cvs.texi)
+ -@rm -f getdate-cvs.tmp
+ @cp $(srcdir)/getdate-cvs.texi $@
+.texinfo.txt:
+ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ --no-headers -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+.txi.txt:
+ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ --no-headers -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+.texi.txt:
+ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+ --no-headers -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/RCSFILES b/doc/RCSFILES
new file mode 100644
index 0000000..35e30ab
--- /dev/null
+++ b/doc/RCSFILES
@@ -0,0 +1,281 @@
+It would be nice if the RCS file format (which is implemented by a
+great many tools, both free and non-free, both by calling GNU RCS and
+by reimplementing access to RCS files) were documented in some
+standard separate from any one tool. But as far as I know no such
+standard exists. Hence this file.
+
+The place to start is the rcsfile.5 manpage in the GNU RCS 5.7
+distribution. Then look at the diff at the end of this file (which
+contains a few fixes and clarifications to that manpage).
+
+If you are interested in MKS RCS, src/ci.c in GNU RCS 5.7 has a
+comment about their date format. However, as far as we know there
+isn't really any document describing MKS's changes to the RCS file
+format.
+
+The rcsfile.5 manpage does not document what goes in the "text" field
+for each revision. The answer is that the head revision contains the
+contents of that revision and every other revision contain a bunch of
+edits to produce that revision ("a" and "d" lines). The GNU diff
+manual (the version I looked at was for GNU diff 2.4) documents this
+format somewhat (as the "RCS output format"), but the presentation is
+a bit confusing as it is all tangled up with the documentation of
+several other output formats. If you just want some source code to
+look at, the part of CVS which applies these is RCS_deltas in
+src/rcs.c.
+
+The rcsfile.5 documentation only _very_ briefly touches on the order
+of the revisions. The order _is_ important and CVS relies on it.
+Here is an example of what I was able to find, based on the join3
+sanity.sh testcase (and the behavior I am documenting here seems to be
+the same for RCS 5.7 and CVS 1.9.27):
+
+ 1.1 -----------------> 1.2
+ \---> 1.1.2.1 \---> 1.2.2.1
+
+Here is how this shows up in the RCS file (omitting irrelevant parts):
+
+ admin: head 1.2;
+ deltas:
+ 1.2 branches 1.2.2.1; next 1.1;
+ 1.1 branches 1.1.2.1; next;
+ 1.1.2.1 branches; next;
+ 1.2.2.1 branches; next;
+ deltatexts:
+ 1.2
+ 1.2.2.1
+ 1.1
+ 1.1.2.1
+
+Yes, the order seems to differ between the deltas and the deltatexts.
+I have no idea how much of this should actually be considered part of
+the RCS file format, and how much programs reading it should expect to
+encounter any order.
+
+The rcsfile.5 grammar shows the {num} after "next" as optional; if it
+is omitted then there is no next delta node (for example 1.1 or the
+head of a branch will typically have no next).
+
+There is one case where CVS uses CVS-specific, non-compatible changes
+to the RCS file format, and this is magic branches. See cvs.texinfo
+for more information on them. CVS also sets the RCS state to "dead"
+to indicate that a file does not exist in a given revision (this is
+stored just as any other RCS state is).
+
+The RCS file format allows quite a variety of extensions to be added
+in a compatible manner by use of the "newphrase" feature documented in
+rcsfile.5. We won't try to document extensions not used by CVS in any
+detail, but we will briefly list them. Each occurrence of a newphrase
+begins with an identifier, which is what we list here. Future
+designers of extensions are strongly encouraged to pick
+non-conflicting identifiers. Note that newphrase occurs several
+places in the RCS grammar, and a given extension may not be legal in
+all locations. However, it seems better to reserve a particular
+identifier for all locations, to avoid confusion and complicated
+rules.
+
+ Identifier Used by
+ ---------- -------
+ namespace RCS library done at Silicon Graphics Inc. (SGI) in 1996
+ (a modified RCS 5.7--not sure it has any other name).
+ dead A set of RCS patches developed by Rich Pixley at
+ Cygnus about 1992. These were for CVS, and predated
+ the current CVS death support, which uses a state "dead"
+ rather than a "dead" newphrase.
+
+CVS does use newphrases to implement the `PreservePermissions'
+extension introduced in CVS 1.9.26. The following new keywords are
+defined when PreservePermissions=yes:
+
+ owner
+ group
+ permissions
+ special
+ symlink
+ hardlinks
+
+The contents of the `owner' and `group' field should be a numeric uid
+and a numeric gid, respectively, representing the user and group who
+own the file. The `permissions' field contains an octal integer,
+representing the permissions that should be applied to the file. The
+`special' field contains two words; the first must be either `block'
+or `character', and the second is the file's device number. The
+`symlink' field should be present only in files which are symbolic
+links to other files, and absent on all regular files. The
+`hardlinks' field contains a list of filenames to which the current
+file is linked, in alphabetical order. Because files often contain
+characters special to RCS, like `.' and sometimes even contain spaces
+or eight-bit characters, the filenames in the hardlinks field will
+usually be enclosed in RCS strings. For example:
+
+ hardlinks README @install.txt@ @Installation Notes@;
+
+The hardlinks field should always include the name of the current
+file. That is, in the repository file README,v, any hardlinks fields
+in the delta nodes should include `README'; CVS will not operate
+properly if this is not done.
+
+Newphrases are also used to implement the 'commitid' feature. The
+following new keyword is defined:
+
+ commitid
+
+The rules regarding keyword expansion are not documented along with
+the rest of the RCS file format; they are documented in the co(1)
+manpage in the RCS 5.7 distribution. See also the "Keyword
+substitution" chapter of cvs.texinfo. The co(1) manpage refers to
+special behavior if the log prefix for the $Log keyword is /* or (*.
+RCS 5.7 produces a warning whenever it behaves that way, and current
+versions of CVS do not handle this case in a special way (CVS 1.9 and
+earlier invoke RCS to perform keyword expansion).
+
+Note that if the "expand" keyword is omitted from the RCS file, the
+default is "kv".
+
+Note that the "comment {string};" syntax from rcsfile.5 specifies a
+comment leader, which affects expansion of the $Log keyword for old
+versions of RCS. The comment leader is not used by RCS 5.7 or current
+versions of CVS.
+
+Both RCS 5.7 and current versions of CVS handle the $Log keyword in a
+different way if the log message starts with "checked in with -k by ".
+I don't think this behavior is documented anywhere.
+
+Here is a clarification regarding characters versus bytes in certain
+character sets like JIS and Big5:
+
+ The RCS file format, as described in the rcsfile(5) man page, is
+ actually byte-oriented, not character-oriented, despite hints to
+ the contrary in the man page. This distinction is important for
+ multibyte characters. For example, if a multibyte character
+ contains a `@' byte, the `@' must be doubled within strings in RCS
+ files, since RCS uses `@' bytes as escapes.
+
+ This point is not an issue for encodings like ISO 8859, which do
+ not have multibyte characters. Nor is it an issue for encodings
+ like UTF-8 and EUC-JIS, which never uses ASCII bytes within a
+ multibyte character. It is an issue only for multibyte encodings
+ like JIS and BIG5, which _do_ usurp ASCII bytes.
+
+ If `@' doubling occurs within a multibyte char, the resulting RCS
+ file is not a properly encoded text file. Instead, it is a byte
+ stream that does not use a consistent character encoding that can
+ be understood by the usual text tools, since doubling `@' messes
+ up the encoding. This point affects only programs that examine
+ the RCS files -- it doesn't affect the external RCS interface, as
+ the RCS commands always give you the properly encoded text files
+ and logs (assuming that you always check in properly encoded
+ text).
+
+ CVS 1.10 (and earlier) probably has some bugs in this area on
+ systems where a C "char" is signed and where the data contains
+ bytes with the eighth bit set.
+
+One common concern about the RCS file format is the fact that to get
+the head of a branch, one must apply deltas from the head of the trunk
+to the branchpoint, and then from the branchpoint to the head of the
+branch. While more detailed analyses might be worth doing, we will
+note:
+
+ * The performance bottleneck for CVS generally is figuring out which
+ files to operate on and that sort of thing, not applying deltas.
+
+ * Here is one quick test (probably not a very good test; a better test
+ would use a normally sized file (say 50-200K) instead of a small one):
+
+ I just did a quick test with a small file (on a Sun Ultra 1/170E
+ running Solaris 5.5.1), with 1000 revisions on the main branch and
+ 1000 revisions on branch that forked at the root (i.e., RCS revisions
+ 1.1, 1.2, ..., 1.1000, and branch revisions 1.1.1.1, 1.1.1.2, ...,
+ 1.1.1.1000). It took about 0.15 seconds real time to check in the
+ first revision, and about 0.6 seconds to check in and 0.3 seconds to
+ retrieve revision 1.1.1.1000 (the worst case).
+
+ * Any attempt to "fix" this problem should be careful not to interfere
+ with other features, such as lightweight creation of branches
+ (particularly using CVS magic branches).
+
+Diff follows:
+
+(Note that in the following diff the old value for the Id keyword was:
+ Id: rcsfile.5in,v 5.6 1995/06/05 08:28:35 eggert Exp
+and the new one was:
+ Id: rcsfile.5in,v 5.7 1996/12/09 17:31:44 eggert Exp
+but since this file itself might be subject to keyword expansion I
+haven't included a diff for that fact).
+
+===================================================================
+RCS file: RCS/rcsfile.5in,v
+retrieving revision 5.6
+retrieving revision 5.7
+diff -u -r5.6 -r5.7
+--- rcsfile.5in 1995/06/05 08:28:35 5.6
++++ rcsfile.5in 1996/12/09 17:31:44 5.7
+@@ -85,7 +85,8 @@
+ .LP
+ \f2sym\fP ::= {\f2digit\fP}* \f2idchar\fP {\f2idchar\fP | \f2digit\fP}*
+ .LP
+-\f2idchar\fP ::= any visible graphic character except \f2special\fP
++\f2idchar\fP ::= any visible graphic character,
++ except \f2digit\fP or \f2special\fP
+ .LP
+ \f2special\fP ::= \f3$\fP | \f3,\fP | \f3.\fP | \f3:\fP | \f3;\fP | \f3@\fP
+ .LP
+@@ -119,12 +120,23 @@
+ the minute (00\-59),
+ and
+ .I ss
+-the second (00\-60).
++the second (00\-59).
++If
+ .I Y
+-contains just the last two digits of the year
+-for years from 1900 through 1999,
+-and all the digits of years thereafter.
+-Dates use the Gregorian calendar; times use UTC.
++contains exactly two digits,
++they are the last two digits of a year from 1900 through 1999;
++otherwise,
++.I Y
++contains all the digits of the year.
++Dates use the Gregorian calendar.
++Times use UTC, except that for portability's sake leap seconds are not allowed;
++implementations that support leap seconds should output
++.B 59
++for
++.I ss
++during an inserted leap second, and should accept
++.B 59
++for a deleted leap second.
+ .PP
+ The
+ .I newphrase
+@@ -144,16 +156,23 @@
+ field in order of decreasing numbers.
+ The
+ .B head
+-field in the
+-.I admin
+-node points to the head of that sequence (i.e., contains
++field points to the head of that sequence (i.e., contains
+ the highest pair).
+ The
+ .B branch
+-node in the admin node indicates the default
++field indicates the default
+ branch (or revision) for most \*r operations.
+ If empty, the default
+ branch is the highest branch on the trunk.
++The
++.B symbols
++field associates symbolic names with revisions.
++For example, if the file contains
++.B "symbols rr:1.1;"
++then
++.B rr
++is a name for revision
++.BR 1.1 .
+ .PP
+ All
+ .I delta
+
diff --git a/doc/cvs-paper.ms b/doc/cvs-paper.ms
new file mode 100644
index 0000000..ea9445a
--- /dev/null
+++ b/doc/cvs-paper.ms
@@ -0,0 +1,1069 @@
+.\" soelim cvs.ms | pic | tbl | troff -ms
+.\" @(#)cvs.ms 1.2 92/01/30
+.\"
+.\" troff source to the cvs USENIX article, Winter 1990, Washington, D.C.
+.\" Copyright (c) 1989, Brian Berliner
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 1, or (at your option)
+.\" any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" The author can be reached at: berliner@prisma.com
+.\"
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.de hl
+.br
+.in +0.5i
+\l'\\n(LLu-1i'
+.in -0.5i
+.sp
+..
+.OH ""
+.nr PS 11
+.nr PO 1.25i
+.pl -0.2i
+.TL
+.ps 14
+.ft B
+.nf
+CVS II:
+Parallelizing Software Development
+.fi
+.ft
+.ps
+.AU
+.ps 12
+.ft I
+Brian Berliner
+.ft
+.ps
+.AI
+.ps 12
+.ft I
+Prisma, Inc.
+5465 Mark Dabling Blvd.
+Colorado Springs, CO 80918
+berliner@prisma.com
+.ft
+.ps
+.AB
+The program described in this paper fills a need in the UNIX
+community for a freely available tool to manage software revision and
+release control in a multi-developer, multi-directory, multi-group
+environment.
+This tool also addresses the increasing need for tracking third-party vendor
+source distributions while trying to maintain local modifications to
+earlier releases.
+.AE
+.NH
+Background
+.PP
+In large software development projects, it is usually necessary for more
+than one software developer to be modifying (usually different) modules of the
+code at the same time.
+Some of these code modifications are done in an
+experimental sense, at least until the code functions correctly, and some
+testing of the entire program is usually necessary.
+Then, the modifications are returned to a master source repository
+so that others in the project can
+enjoy the new bug-fix or functionality.
+In order to manage such a project, some sort of revision control system is
+necessary.
+.PP
+Specifically, UNIX\**
+.FS
+UNIX is a registered trademark of AT&T.
+.FE
+kernel development is an excellent example of the
+problems that an adequate revision control system must address.
+The SunOS\**
+.FS
+SunOS is a trademark of Sun Microsystems, Inc.
+.FE
+kernel is composed of over a thousand files spread across a
+hierarchy of dozens of directories.\**
+.FS
+Yes, the SunOS 4.0 kernel is composed of over a \fIthousand\fP files!
+.FE
+Pieces of the kernel must be edited
+by many software developers within an organization.
+While undesirable in
+theory, it is not uncommon to have two or more people making
+modifications to the same file within the kernel sources in
+order to facilitate a desired change.
+Existing revision control systems like
+.SM
+RCS
+.LG
+[Tichy] or
+.SM
+SCCS
+.LG
+[Bell] serialize file modifications by
+allowing only one developer to have a writable copy of a particular file at
+any one point in time.
+That developer is said to
+have \*Qlocked\*U the file for his exclusive use, and no other developer is
+allowed to check out a writable copy of the file until the locking
+developer has finished impeding others' productivity.
+Development pressures of productivity and deadlines
+often force organizations to require that multiple developers be able to
+simultaneously edit
+copies of the same revision controlled file.
+.PP
+The necessity for multiple developers to modify the same file concurrently
+questions the value of serialization-based policies in traditional revision
+control.
+This paper discusses the approach that
+Prisma took in adapting a standard revision control system,
+.SM
+RCS\c
+.LG
+, along with an existing public-domain collection of shell scripts that sits
+atop
+.SM
+RCS
+.LG
+and provides the basic conflict-resolution algorithms.
+The resulting
+program, \fBcvs\fP, addresses not only the issue of conflict-resolution in
+a multi-developer open-editing environment, but also the issues of
+software release control and vendor source support and integration.
+.NH
+The CVS Program
+.PP
+\fBcvs\fP
+(Concurrent Versions System)
+is a front end to the
+.SM
+RCS
+.LG
+revision control system which extends
+the notion of revision control from a collection of files in a single
+directory to a hierarchical collection of directories each containing
+revision controlled files.
+Directories and files in the \fBcvs\fP system can be combined together in
+many ways to form a software release.
+\fBcvs\fP
+provides the functions necessary to manage these software releases and to
+control the concurrent editing of source files among multiple software
+developers.
+.PP
+The six major features of \fBcvs\fP are listed below, and will be
+described in more detail in the following sections:
+.RS
+.IP 1.
+Concurrent access and conflict-resolution algorithms to guarantee that
+source changes are not \*Qlost.\*U
+.IP 2.
+Support for tracking third-party vendor source distributions while
+maintaining the local modifications made to those sources.
+.IP 3.
+A flexible module database that provides a symbolic mapping of names to
+components of a larger software distribution.
+This symbolic mapping provides for location independence within the software
+release and, for example, allows one to check out a copy of the \*Qdiff\*U
+program without ever knowing that the sources to \*Qdiff\*U actually reside
+in the \*Qbin/diff\*U directory.
+.IP 4.
+Configurable logging support allows all \*Qcommitted\*U source file changes
+to be logged using an arbitrary program to save the log messages in a file,
+notesfile, or news database.
+.IP 5.
+A software release can be symbolically tagged and checked out at any time
+based on that tag.
+An exact copy of a previous software release can be checked out at
+any time, \fIregardless\fP of whether files or directories have been
+added/removed from the \*Qcurrent\*U software release.
+As well,
+a \*Qdate\*U can be used to check out the \fIexact\fP version of the software
+release as of the specified date.
+.IP 6.
+A \*Qpatch\*U format file [Wall] can be produced between two software
+releases, even if the releases span multiple directories.
+.RE
+.PP
+The sources maintained by \fBcvs\fP are kept within a single directory
+hierarchy known as the \*Qsource repository.\*U
+This \*Qsource repository\*U holds the actual
+.SM
+RCS
+.LG
+\*Q,v\*U files directly, as well as a special per-repository directory
+(\c
+.SM
+CVSROOT.adm\c
+.LG
+) which contains a small number of administrative files that describe the
+repository and how it can be accessed.
+See Figure 1 for a picture of the \fBcvs\fP tree.
+.KF
+.hl
+.DS B
+.PS
+line from 4.112,9.200 to 5.550,8.887
+line from 5.447,8.884 to 5.550,8.887 to 5.458,8.933
+line from 4.112,9.200 to 4.550,8.950
+line from 4.451,8.978 to 4.550,8.950 to 4.476,9.021
+line from 4.112,9.200 to 3.737,8.887
+line from 3.798,8.971 to 3.737,8.887 to 3.830,8.932
+line from 3.612,8.762 to 4.737,8.137
+line from 4.638,8.164 to 4.737,8.137 to 4.662,8.208
+line from 3.612,8.762 to 3.737,8.137
+line from 3.693,8.231 to 3.737,8.137 to 3.742,8.240
+line from 3.612,8.762 to 2.612,8.200
+line from 2.687,8.271 to 2.612,8.200 to 2.712,8.227
+line from 2.362,9.262 to 2.737,8.950
+line from 2.645,8.995 to 2.737,8.950 to 2.677,9.033
+line from 2.362,9.262 to 1.925,8.950
+line from 1.992,9.028 to 1.925,8.950 to 2.021,8.988
+line from 3.362,9.762 to 4.050,9.387
+line from 3.950,9.413 to 4.050,9.387 to 3.974,9.457
+line from 3.362,9.762 to 2.487,9.387
+line from 2.570,9.450 to 2.487,9.387 to 2.589,9.404
+.ps 11
+"newfs.c,v" at 4.487,8.043 ljust
+.ps 11
+"mkfs.c,v" at 3.487,8.043 ljust
+.ps 11
+"Makefile,v" at 2.237,8.043 ljust
+.ps 11
+"newfs" at 3.487,8.793 ljust
+.ps 11
+"halt.c,v" at 5.487,8.793 ljust
+.ps 11
+"Makefile,v" at 4.237,8.793 ljust
+.ps 11
+"modules,v" at 2.487,8.793 ljust
+.ps 11
+"loginfo,v" at 1.488,8.793 ljust
+.ps 11
+"etc" at 3.987,9.293 ljust
+.ps 11
+"CVSROOT.adm" at 1.988,9.293 ljust
+.ps 11
+"/src/master" at 2.987,9.793 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 1.\fP
+.SM
+\fBcvs\fP Source Repository
+.ce 0
+.sp
+.KE
+.NH 2
+Software Conflict Resolution\**
+.FS
+The basic conflict-resolution algorithms
+used in the \fBcvs\fP program find their roots
+in the original work done by Dick Grune at Vrije Universiteit in Amsterdam
+and posted to \fBcomp.sources.unix\fP in the volume 6 release sometime in 1986.
+This original version of \fBcvs\fP was a collection of shell scripts that
+combined to form a front end to the
+.SM
+RCS
+.LG
+programs.
+.FE
+.PP
+\fBcvs\fP allows several software developers to edit personal copies of a
+revision controlled file concurrently.
+The revision number of each checked out file is maintained independently
+for each user, and \fBcvs\fP forces the checked out file to be current with
+the \*Qhead\*U revision before it can be \*Qcommitted\*U as a permanent change.
+A checked out file is brought up-to-date with the \*Qhead\*U revision using
+the \*Qupdate\*U command of \fBcvs\fP.
+This command compares the \*Qhead\*U revision number with that of the user's
+file and performs an
+.SM
+RCS
+.LG
+merge operation if they are not the same.
+The result of the merge is a file that contains the user's modifications
+and those modifications that were \*Qcommitted\*U after the user
+checked out his version of the file (as well as a backup copy of the
+user's original file).
+\fBcvs\fP points out any conflicts during the merge.
+It is the user's responsibility to resolve these conflicts
+and to \*Qcommit\*U his/her changes when ready.
+.PP
+Although the \fBcvs\fP conflict-resolution algorithm was defined in 1986,
+it is remarkably similar to the \*QCopy-Modify-Merge\*U scenario included
+with NSE\**
+.FS
+NSE is the Network Software Environment, a product of Sun Microsystems, Inc.
+.FE
+and described in [Honda] and [Courington].
+The following explanation from [Honda] also applies to \fBcvs\fP:
+.QP
+Simply stated, a developer copies an object without locking it, modifies
+the copy, and then merges the modified copy with the original.
+This paradigm allows developers to work in isolation from one another since
+changes are made to copies of objects.
+Because locks are not used, development is not serialized and can proceed
+in parallel.
+Developers, however, must merge objects after the changes have been made.
+In particular, a developer must resolve conflicts when the same object has
+been modified by someone else.
+.PP
+In practice, Prisma has found that conflicts that occur when the same
+object has been modified by someone else are quite rare.
+When they do happen, the changes made by the other developer are usually
+easily resolved.
+This practical use has shown that the \*QCopy-Modify-Merge\*U paradigm is a
+correct and useful one.
+.NH 2
+Tracking Third-Party Source Distributions
+.PP
+Currently, a large amount of software is based on source
+distributions from a third-party distributor.
+It is often the case that local modifications are to be made to this
+distribution, \fIand\fP that the vendor's future releases should be
+tracked.
+Rolling your local modifications forward into the new vendor release is a
+time-consuming task, but \fBcvs\fP can ease this burden somewhat.
+The \fBcheckin\fP program of \fBcvs\fP initially sets up a source
+repository by integrating the source modules directly from the vendor's
+release, preserving the directory hierarchy of the vendor's distribution.
+The branch support of
+.SM
+RCS
+.LG
+is used to build this vendor release as a branch of the main
+.SM
+RCS
+.LG
+trunk.
+Figure 2 shows how the \*Qhead\*U tracks a sample vendor
+branch when no local modifications have been made to the file.
+.KF
+.hl
+.DS B
+.PS
+ellipse at 3.237,6.763 wid 1.000 ht 0.500
+dashwid = 0.050i
+line dashed from 3.237,7.513 to 3.737,7.513 to 3.737,9.762 to 4.237,9.762
+line from 4.138,9.737 to 4.237,9.762 to 4.138,9.787
+line dashed from 2.237,8.262 to 3.237,8.262 to 3.237,7.013
+line from 3.212,7.112 to 3.237,7.013 to 3.262,7.112
+line from 3.737,6.763 to 4.237,6.763
+line from 4.138,6.737 to 4.237,6.763 to 4.138,6.788
+line from 2.237,6.763 to 2.737,6.763
+line from 2.637,6.737 to 2.737,6.763 to 2.637,6.788
+line from 1.738,6.013 to 1.738,6.513
+line from 1.762,6.413 to 1.738,6.513 to 1.713,6.413
+line from 1.238,7.013 to 2.237,7.013 to 2.237,6.513 to 1.238,6.513 to 1.238,7.013
+line from 4.237,9.012 to 5.237,9.012 to 5.237,8.512 to 4.237,8.512 to 4.237,9.012
+line from 4.237,8.012 to 5.237,8.012 to 5.237,7.513 to 4.237,7.513 to 4.237,8.012
+line from 4.237,7.013 to 5.237,7.013 to 5.237,6.513 to 4.237,6.513 to 4.237,7.013
+line from 4.737,7.013 to 4.737,7.513
+line from 4.763,7.413 to 4.737,7.513 to 4.712,7.413
+line from 4.737,8.012 to 4.737,8.512
+line from 4.763,8.412 to 4.737,8.512 to 4.712,8.412
+line from 4.237,10.012 to 5.237,10.012 to 5.237,9.512 to 4.237,9.512 to 4.237,10.012
+line from 4.737,9.012 to 4.737,9.512
+line from 4.763,9.412 to 4.737,9.512 to 4.712,9.412
+line from 5.987,5.013 to 5.987,6.013 to 0.988,6.013 to 0.988,5.013 to 5.987,5.013
+.ps 11
+"\"HEAD\"" at 1.550,8.231 ljust
+.ps 11
+"'SunOS'" at 2.987,6.293 ljust
+.ps 11
+"1.1.1" at 3.050,6.793 ljust
+.ps 11
+"1.1" at 1.613,6.793 ljust
+.ps 11
+"1.1.1.1" at 4.487,6.793 ljust
+.ps 11
+"1.1.1.2" at 4.487,7.793 ljust
+.ps 11
+"1.1.1.3" at 4.487,8.793 ljust
+.ps 11
+"1.1.1.4" at 4.487,9.793 ljust
+.ps 11
+"'SunOS_4_0'" at 5.487,6.793 ljust
+.ps 11
+"'SunOS_4_0_1'" at 5.487,7.793 ljust
+.ps 11
+"'YAPT_5_5C'" at 5.487,8.793 ljust
+.ps 11
+"'SunOS_4_0_3'" at 5.487,9.793 ljust
+.ps 11
+"rcsfile.c,v" at 2.987,5.543 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 2.\fP
+.SM
+\fBcvs\fP Vendor Branch Example
+.ce 0
+.sp .3
+.KE
+Once this is done, developers can check out files and make local changes to
+the vendor's source distribution.
+These local changes form a new branch to the tree which is then used as the
+source for future check outs.
+Figure 3 shows how the \*Qhead\*U moves to the main
+.SM
+RCS
+.LG
+trunk when a local modification is made.
+.KF
+.hl
+.DS B
+.PS
+ellipse at 3.237,6.763 wid 1.000 ht 0.500
+dashwid = 0.050i
+line dashed from 2.800,9.075 to 1.738,9.075 to 1.738,8.012
+line from 1.713,8.112 to 1.738,8.012 to 1.762,8.112
+line from 1.738,7.013 to 1.738,7.513
+line from 1.762,7.413 to 1.738,7.513 to 1.713,7.413
+line from 1.238,8.012 to 2.237,8.012 to 2.237,7.513 to 1.238,7.513 to 1.238,8.012
+line from 3.737,6.763 to 4.237,6.763
+line from 4.138,6.737 to 4.237,6.763 to 4.138,6.788
+line from 2.237,6.763 to 2.737,6.763
+line from 2.637,6.737 to 2.737,6.763 to 2.637,6.788
+line from 1.738,6.013 to 1.738,6.513
+line from 1.762,6.413 to 1.738,6.513 to 1.713,6.413
+line from 1.238,7.013 to 2.237,7.013 to 2.237,6.513 to 1.238,6.513 to 1.238,7.013
+line from 4.237,9.012 to 5.237,9.012 to 5.237,8.512 to 4.237,8.512 to 4.237,9.012
+line from 4.237,8.012 to 5.237,8.012 to 5.237,7.513 to 4.237,7.513 to 4.237,8.012
+line from 4.237,7.013 to 5.237,7.013 to 5.237,6.513 to 4.237,6.513 to 4.237,7.013
+line from 4.737,7.013 to 4.737,7.513
+line from 4.763,7.413 to 4.737,7.513 to 4.712,7.413
+line from 4.737,8.012 to 4.737,8.512
+line from 4.763,8.412 to 4.737,8.512 to 4.712,8.412
+line from 4.237,10.012 to 5.237,10.012 to 5.237,9.512 to 4.237,9.512 to 4.237,10.012
+line from 4.737,9.012 to 4.737,9.512
+line from 4.763,9.412 to 4.737,9.512 to 4.712,9.412
+line from 5.987,5.013 to 5.987,6.013 to 0.988,6.013 to 0.988,5.013 to 5.987,5.013
+.ps 11
+"1.2" at 1.613,7.793 ljust
+.ps 11
+"\"HEAD\"" at 2.862,9.043 ljust
+.ps 11
+"'SunOS'" at 2.987,6.293 ljust
+.ps 11
+"1.1.1" at 3.050,6.793 ljust
+.ps 11
+"1.1" at 1.613,6.793 ljust
+.ps 11
+"1.1.1.1" at 4.487,6.793 ljust
+.ps 11
+"1.1.1.2" at 4.487,7.793 ljust
+.ps 11
+"1.1.1.3" at 4.487,8.793 ljust
+.ps 11
+"1.1.1.4" at 4.487,9.793 ljust
+.ps 11
+"'SunOS_4_0'" at 5.487,6.793 ljust
+.ps 11
+"'SunOS_4_0_1'" at 5.487,7.793 ljust
+.ps 11
+"'YAPT_5_5C'" at 5.487,8.793 ljust
+.ps 11
+"'SunOS_4_0_3'" at 5.487,9.793 ljust
+.ps 11
+"rcsfile.c,v" at 2.987,5.543 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 3.\fP
+.SM
+\fBcvs\fP Local Modification to Vendor Branch
+.ce 0
+.sp
+.KE
+.PP
+When a new version of the vendor's source distribution arrives, the
+\fBcheckin\fP program adds the new and changed vendor's files to the
+already existing source repository.
+For files that have not been changed locally, the new file from the
+vendor becomes the current \*Qhead\*U revision.
+For files that have been modified locally, \fBcheckin\fP warns that the
+file must be merged with the new vendor release.
+The \fBcvs\fP \*Qjoin\*U command is a useful tool that aids this process by
+performing the necessary
+.SM
+RCS
+.LG
+merge, as is done above when performing an \*Qupdate.\*U
+.PP
+There is also limited support for \*Qdual\*U derivations for source files.
+See Figure 4 for a sample dual-derived file.
+.KF
+.hl
+.DS B
+.PS
+ellipse at 2.337,8.575 wid 0.700 ht 0.375
+ellipse at 2.312,9.137 wid 0.700 ht 0.375
+line from 1.225,9.012 to 1.225,9.363
+line from 1.250,9.263 to 1.225,9.363 to 1.200,9.263
+line from 0.875,9.725 to 1.600,9.725 to 1.600,9.363 to 0.875,9.363 to 0.875,9.725
+line from 0.875,9.012 to 1.600,9.012 to 1.600,8.650 to 0.875,8.650 to 0.875,9.012
+line from 4.050,10.200 to 4.775,10.200 to 4.775,9.850 to 4.050,9.850 to 4.050,10.200
+line from 4.050,9.475 to 4.775,9.475 to 4.775,9.113 to 4.050,9.113 to 4.050,9.475
+line from 4.050,8.762 to 4.775,8.762 to 4.775,8.400 to 4.050,8.400 to 4.050,8.762
+line from 4.425,8.762 to 4.425,9.113
+line from 4.450,9.013 to 4.425,9.113 to 4.400,9.013
+line from 4.425,9.475 to 4.425,9.850
+line from 4.450,9.750 to 4.425,9.850 to 4.400,9.750
+line from 3.050,10.000 to 3.775,10.000 to 3.775,9.637 to 3.050,9.637 to 3.050,10.000
+line from 3.050,9.312 to 3.775,9.312 to 3.775,8.950 to 3.050,8.950 to 3.050,9.312
+line from 0.713,7.325 to 0.713,8.075 to 4.925,8.075 to 4.925,7.325 to 0.713,7.325
+line from 1.238,8.075 to 1.238,8.637
+line from 1.262,8.537 to 1.238,8.637 to 1.213,8.537
+line from 1.613,8.825 to 1.975,8.575
+line from 1.878,8.611 to 1.975,8.575 to 1.907,8.652
+line from 2.675,8.575 to 4.050,8.575
+line from 3.950,8.550 to 4.050,8.575 to 3.950,8.600
+line from 2.675,9.137 to 3.050,9.137
+line from 2.950,9.112 to 3.050,9.137 to 2.950,9.162
+line from 3.425,9.325 to 3.425,9.637
+line from 3.450,9.537 to 3.425,9.637 to 3.400,9.537
+line from 1.613,8.825 to 1.925,9.137
+line from 1.872,9.049 to 1.925,9.137 to 1.837,9.084
+.ps 11
+"'BSD'" at 2.138,9.481 ljust
+.ps 11
+"1.2" at 1.113,9.543 ljust
+.ps 11
+"1.1" at 1.125,8.831 ljust
+.ps 11
+"1.1.1.1" at 4.175,8.543 ljust
+.ps 11
+"1.1.1.2" at 4.175,9.281 ljust
+.ps 11
+"1.1.1.3" at 4.175,9.993 ljust
+.ps 11
+"1.1.2.2" at 3.175,9.793 ljust
+.ps 11
+"1.1.2.1" at 3.175,9.106 ljust
+.ps 11
+"rcsfile.c,v" at 2.425,7.706 ljust
+.ps 11
+"1.1.1" at 2.175,8.568 ljust
+.ps 11
+"'SunOS'" at 2.125,8.243 ljust
+.ps 11
+"1.1.2" at 2.163,9.131 ljust
+.PE
+.DE
+.hl
+.ce 100
+.LG
+\fBFigure 4.\fP
+.SM
+\fBcvs\fP Support For \*QDual\*U Derivations
+.ce 0
+.sp
+.KE
+This example tracks the SunOS distribution but includes major changes from
+Berkeley.
+These BSD files are saved directly in the
+.SM
+RCS
+.LG
+file off a new branch.
+.NH 2
+Location Independent Module Database
+.PP
+\fBcvs\fP contains support for a simple, yet powerful, \*Qmodule\*U database.
+For reasons of efficiency, this database is stored in \fBndbm\fP\|(3) format.
+The module database is used to apply names to collections of directories
+and files as a matter of convenience for checking out pieces of a large
+software distribution.
+The database records the physical location of the sources as a form of
+information hiding, allowing one to check out whole directory hierarchies
+or individual files without regard for their actual location within the
+global source distribution.
+.PP
+Consider the following small sample of a module database, which must be
+tailored manually to each specific source repository environment:
+.DS
+\f(CW #key [-option argument] directory [files...]
+ diff bin/diff
+ libc lib/libc
+ sys -o sys/tools/make_links sys
+ modules -i mkmodules CVSROOT.adm modules
+ kernel -a sys lang/adb
+ ps bin Makefile ps.c\fP
+.DE
+.PP
+The \*Qdiff\*U and \*Qlibc\*U modules refer to whole directory hierarchies that
+are extracted on check out.
+The \*Qsys\*U module extracts the \*Qsys\*U hierarchy, and runs the
+\*Qmake_links\*U program at the end of the check out process (the \fI-o\fP
+option specifies a program to run on check\fIo\fPut).
+The \*Qmodules\*U module allows one to edit the module database file and
+runs the \*Qmkmodules\*U program on check\fIi\fPn to regenerate the
+\fBndbm\fP database that \fBcvs\fP uses.
+The \*Qkernel\*U module is an alias (as the \fI-a\fP option specifies)
+which causes the remaining arguments after the \fI-a\fP to be interpreted
+exactly as if they had been specified on the command line.
+This is useful for objects that require shared pieces of code from far away
+places to be compiled (as is the case with the kernel debugger, \fBkadb\fP,
+which shares code with the standard \fBadb\fP debugger).
+The \*Qps\*U module shows that the source for \*Qps\*U lives in the \*Qbin\*U
+directory, but only \fIMakefile\fP and \fIps.c\fP are required to build the
+object.
+.PP
+The module database at Prisma is now populated for the entire UNIX
+distribution and thereby allows us to issue the
+following convenient commands to check out components of the UNIX
+distribution without regard for their actual location within the master source
+repository:
+.DS
+\f(CW example% cvs checkout diff
+ example% cvs checkout libc ps
+ example% cd diff; make\fP
+.DE
+.PP
+In building the module database file, it is quite possible to have name
+conflicts within a global software distribution.
+For example, SunOS provides two \fBcat\fP programs:
+one for the standard environment, \fI/bin/cat\fP, and one for the System V
+environment, \fI/usr/5bin/cat\fP.
+We resolved this conflict by naming the standard \fBcat\fP module
+\*Qcat\*U, and the System V \fBcat\fP module \*Q5cat\*U.
+Similar name modifications must be applied to other conflicting names, as
+might be found between a utility program and a library function, though
+Prisma chose not to include individual library functions within the module
+database at this time.
+.NH 2
+Configurable Logging Support
+.PP
+The \fBcvs\fP \*Qcommit\*U command is used to make a permanent change to the
+master source repository (where the
+.SM
+RCS
+.LG
+\*Q,v\*U files live).
+Whenever a \*Qcommit\*U is done, the log message for the change is carefully
+logged by an arbitrary program (in a file, notesfile, news database, or
+mail).
+For example, a collection of these updates can be used to produce release
+notices.
+\fBcvs\fP can be configured to send log updates through one or more filter
+programs, based on a regular expression match on the directory that is
+being changed.
+This allows multiple related or unrelated projects to exist within a single
+\fBcvs\fP source repository tree, with each different project sending its
+\*Qcommit\*U reports to a unique log device.
+.PP
+A sample logging configuration file might look as follows:
+.DS
+\f(CW #regex filter-program
+ DEFAULT /usr/local/bin/nfpipe -t %s utils.updates
+ ^diag /usr/local/bin/nfpipe -t %s diag.updates
+ ^local /usr/local/bin/nfpipe -t %s local.updates
+ ^perf /usr/local/bin/nfpipe -t %s perf.updates
+ ^sys /usr/local/bin/nfpipe -t %s kernel.updates\fP
+.DE
+.PP
+This sample allows the diagnostics and performance groups to
+share the same source repository with the kernel and utilities groups.
+Changes that they make are sent directly to their own notesfile [Essick]
+through the \*Qnfpipe\*U program.
+A sufficiently simple title is substituted for the \*Q%s\*U argument before
+the filter program is executed.
+This logging configuration file is tailored manually to each specific
+source repository environment.
+.NH 2
+Tagged Releases and Dates
+.PP
+Any release can be given a symbolic tag name that is stored directly in the
+.SM
+RCS
+.LG
+files.
+This tag can be used at any time to get an exact copy of any previous
+release.
+With equal ease, one can also extract an exact copy of the source files as
+of any arbitrary date in the past as well.
+Thus, all that's required to tag the current kernel, and to tag the kernel
+as of the Fourth of July is:
+.DS
+\f(CW example% cvs tag TEST_KERNEL kernel
+ example% cvs tag -D 'July 4' PATRIOTIC_KERNEL kernel\fP
+.DE
+The following command would retrieve an exact copy of the test kernel at
+some later date:
+.DS
+\f(CW example% cvs checkout -fp -rTEST_KERNEL kernel\fP
+.DE
+The \fI-f\fP option causes only files that match the specified tag to be
+extracted, while the \fI-p\fP option automatically prunes empty directories.
+Consequently, directories added to the kernel after the test kernel was
+tagged are not included in the newly extracted copy of the test kernel.
+.PP
+The \fBcvs\fP date support has exactly the same interface as that provided
+with
+.SM
+RCS\c
+.LG
+, however \fBcvs\fP must process the \*Q,v\*U files directly due to the
+special handling required by the vendor branch support.
+The standard
+.SM
+RCS
+.LG
+date handling only processes one branch (or the main trunk) when checking
+out based on a date specification.
+\fBcvs\fP must instead process the current \*Qhead\*U branch and, if a
+match is not found, proceed to look for a match on the vendor branch.
+This, combined with reasons of performance, is why \fBcvs\fP processes
+revision (symbolic and numeric) and date specifications directly from the
+\*Q,v\*U files.
+.NH 2
+Building \*Qpatch\*U Source Distributions
+.PP
+\fBcvs\fP can produce a \*Qpatch\*U format [Wall] output file which can be
+used to bring a previously released software distribution current with the
+newest release.
+This patch file supports an entire directory hierarchy within a single
+patch, as well as being able to add whole new files to the previous
+release.
+One can combine symbolic revisions and dates together to display changes in
+a very generic way:
+.DS
+\f(CW example% cvs patch -D 'December 1, 1988' \e
+ -D 'January 1, 1989' sys\fP
+.DE
+This example displays the kernel changes made in the month of December,
+1988.
+To release a patch file, for example, to take the \fBcvs\fP distribution
+from version 1.0 to version 1.4 might be done as follows:
+.DS
+\f(CW example% cvs patch -rCVS_1_0 -rCVS_1_4 cvs\fP
+.DE
+.NH
+CVS Experience
+.NH 2
+Statistics
+.PP
+A quick summary of the scale that \fBcvs\fP is addressing today
+can be found in Table 1.
+.KF
+.TS
+box center tab(:);
+c s
+c s
+c | c
+l | n .
+\fB\s+2Revision Control Statistics at Prisma
+as of 11/11/89\fP\s-2
+_
+How Many...:Total
+=
+Files:17243
+Directories:1005
+Lines of code:3927255
+Removed files:131
+Software developers:14
+Software groups:6
+Megabytes of source:128
+.TE
+.ce 100
+.LG
+\fBTable 1.\fP
+.SM
+\fBcvs\fP Statistics
+.ce 0
+.sp .3
+.KE
+Table 2 shows the history of files changed or added and the number
+of source lines affected by the change at Prisma.
+Only changes made to the kernel sources are included.
+.KF
+.TS
+box center tab(:);
+c s s s s
+c s s s s
+c || c | c || c | c
+c || c | c || c | c
+l || n | n || n | n.
+\fB\s+2Prisma Kernel Source File Changes
+By Month, 1988-1989\fP\s-2
+_
+Month:# Changed:# Lines:# Added:# Lines
+\^:Files:Changed:Files:Added
+=
+Dec:87:3619:68:9266
+Jan:39:4324:0:0
+Feb:73:1578:5:3550
+Mar:99:5301:18:11461
+Apr:112:7333:11:5759
+May:138:5371:17:13986
+Jun:65:2261:27:12875
+Jul:34:2000:1:58
+Aug:65:6378:8:4724
+Sep:266:23410:113:39965
+Oct:22:621:1:155
+Total:1000:62196:269:101799
+.TE
+.ce 100
+.LG
+\fBTable 2.\fP
+.SM
+\fBcvs\fP Usage History for the Kernel
+.ce 0
+.sp
+.KE
+The large number of source file changes made in September are the result of
+merging the SunOS 4.0.3 sources into the kernel.
+This merge process is described in section 3.3.
+.NH 2
+Performance
+.PP
+The performance of \fBcvs\fP is currently quite reasonable.
+Little effort has been expended on tuning \fBcvs\fP, although performance
+related decisions were made during the \fBcvs\fP design.
+For example, \fBcvs\fP parses the
+.SM
+RCS
+.LG
+\*Q,v\*U files directly instead of running an
+.SM
+RCS
+.LG
+process.
+This includes following branches as well as integrating with the vendor
+source branches and the main trunk when checking out files based on a date.
+.PP
+Checking out the entire kernel source tree (1223 files/59 directories)
+currently takes 16 wall clock minutes on a Sun-4/280.
+However, bringing the tree up-to-date with the current kernel sources, once
+it has been checked out, takes only 1.5 wall clock minutes.
+Updating the \fIcomplete\fP 128 MByte source tree under \fBcvs\fP control
+(17243 files/1005 directories) takes roughly 28 wall clock minutes and
+utilizes one-third of the machine.
+For now this is entirely acceptable; improvements on these numbers will
+possibly be made in the future.
+.NH 2
+The SunOS 4.0.3 Merge
+.PP
+The true test of the \fBcvs\fP vendor branch support came with the arrival
+of the SunOS 4.0.3 source upgrade tape.
+As described above, the \fBcheckin\fP program was used to install the new
+sources and the resulting output file listed the files that had been
+locally modified, needing to be merged manually.
+For the kernel, there were 94 files in conflict.
+The \fBcvs\fP \*Qjoin\*U command was used on each of the 94 conflicting
+files, and the remaining conflicts were resolved.
+.PP
+The \*Qjoin\*U command performs an \fBrcsmerge\fP operation.
+This in turn uses \fI/usr/lib/diff3\fP to produce a three-way diff file.
+As it happens, the \fBdiff3\fP program has a hard-coded limit of 200
+source-file changes maximum.
+This proved to be too small for a few of the kernel files that needed
+merging by hand, due to the large number of local changes that Prisma had
+made.
+The \fBdiff3\fP problem was solved by increasing the hard-coded limit by an
+order of magnitude.
+.PP
+The SunOS 4.0.3 kernel source upgrade distribution contained
+346 files, 233 of which were modifications to previously released files,
+and 113 of which were newly added files.
+\fBcheckin\fP added the 113 new files to the source repository
+without intervention.
+Of the 233 modified files, 139 dropped in cleanly by \fBcheckin\fP, since
+Prisma had not made any local changes to them, and 94 required manual
+merging due to local modifications.
+The 233 modified files consisted of 20,766 lines of differences.
+It took one developer two days to manually merge the 94 files using the
+\*Qjoin\*U command and resolving conflicts manually.
+An additional day was required for kernel debugging.
+The entire process of merging over 20,000 lines of differences was
+completed in less than a week.
+This one time-savings alone was justification enough for the \fBcvs\fP
+development effort; we expect to gain even more when tracking future SunOS
+releases.
+.NH
+Future Enhancements and Current Bugs
+.PP
+Since \fBcvs\fP was designed to be incomplete, for reasons of design
+simplicity, there are naturally a good
+number of enhancements that can be made to make it more useful.
+As well, some nuisances exist in the current implementation.
+.RS
+.IP \(bu 3
+\fBcvs\fP does not currently \*Qremember\*U who has a checked out a copy of a
+module.
+As a result, it is impossible to know who might be working on the same
+module that you are.
+A simple-minded database that is updated nightly would likely suffice.
+.IP \(bu 3
+Signal processing, keyboard interrupt handling in particular, is currently
+somewhat weak.
+This is due to the heavy use of the \fBsystem\fP\|(3) library
+function to execute
+.SM
+RCS
+.LG
+programs like \fBco\fP and \fBci\fP.
+It sometimes takes multiple interrupts to make \fBcvs\fP quit.
+This can be fixed by using a home-grown \fBsystem\fP\|() replacement.
+.IP \(bu 3
+Security of the source repository is currently not dealt with directly.
+The usual UNIX approach of user-group-other security permissions through
+the file system is utilized, but nothing else.
+\fBcvs\fP could likely be a set-group-id executable that checks a
+protected database to verify user access permissions for particular objects
+before allowing any operations to affect those objects.
+.IP \(bu 3
+With every checked-out directory, \fBcvs\fP maintains some administrative
+files that record the current revision numbers of the checked-out files as
+well as the location of the respective source repository.
+\fBcvs\fP does not recover nicely at all if these administrative files are
+removed.
+.IP \(bu 3
+The source code for \fBcvs\fP has been tested extensively on Sun-3 and
+Sun-4 systems, all running SunOS 4.0 or later versions of the operating
+system.
+Since the code has not yet been compiled under other platforms, the overall
+portability of the code is still questionable.
+.IP \(bu 3
+As witnessed in the previous section, the \fBcvs\fP method for tracking
+third party vendor source distributions can work quite nicely.
+However, if the vendor changes the directory structure or the file names
+within the source distribution, \fBcvs\fP has no way of matching the old
+release with the new one.
+It is currently unclear as to how to solve this, though it is certain to
+happen in practice.
+.RE
+.NH
+Availability
+.PP
+The \fBcvs\fP program sources can be found in a recent posting to the
+\fBcomp.sources.unix\fP newsgroup.
+It is also currently available via anonymous ftp from \*Qprisma.com\*U.
+Copying rights for \fBcvs\fP will be covered by the GNU General Public
+License.
+.NH
+Summary
+.PP
+Prisma has used \fBcvs\fP since December, 1988.
+It has evolved to meet our specific needs of revision and release control.
+We will make our code freely available so that others can
+benefit from our work, and can enhance \fBcvs\fP to meet broader needs yet.
+.PP
+Many of the other software release and revision control systems, like the
+one described in [Glew], appear to use a collection of tools that are
+geared toward specific environments \(em one set of tools for the kernel,
+one set for \*Qgeneric\*U software, one set for utilities, and one set for
+kernel and utilities.
+Each of these tool sets apparently handle some specific aspect of the
+problem uniquely.
+\fBcvs\fP took a somewhat different approach.
+File sharing through symbolic or hard links is not addressed; instead, the
+disk space is simply burned since it is \*Qcheap.\*U
+Support for producing objects for multiple architectures is not addressed;
+instead, a parallel checked-out source tree must be used for each
+architecture, again wasting disk space to simplify complexity and ease of
+use \(em punting on this issue allowed \fIMakefile\fPs to remain
+unchanged, unlike the approach taken in [Mahler], thereby maintaining closer
+compatibility with the third-party vendor sources.
+\fBcvs\fP is essentially a source-file server, making no assumptions or
+special handling of the sources that it controls.
+To \fBcvs\fP:
+.QP
+A source is a source, of course, of course, unless of course the source is
+Mr. Ed.\**
+.FS
+\fBcvs\fP, of course, does not really discriminate against Mr. Ed.\**
+.FE
+.FS
+Yet.
+.FE
+.LP
+Sources are maintained, saved, and retrievable at any time based on
+symbolic or numeric revision or date in the past.
+It is entirely up to \fBcvs\fP wrapper programs to provide for release
+environments and such.
+.PP
+The major advantage of \fBcvs\fP over the
+many other similar systems that have already been designed is the
+simplicity of \fBcvs\fP.
+\fBcvs\fP contains only three programs that do all the work of release
+and revision control, and two manually-maintained administrative
+files for each source repository.
+Of course, the deciding factor of any tool is whether people use it, and if
+they even \fIlike\fP to use it.
+At Prisma, \fBcvs\fP prevented members of the kernel
+group from killing each other.
+.NH
+Acknowledgements
+.PP
+Many thanks to Dick Grune at Vrije Universiteit in Amsterdam for his work
+on the original version of \fBcvs\fP and for making it available to the
+world.
+Thanks to Jeff Polk of Prisma for helping with the design of the module
+database, vendor branch support, and for writing the \fBcheckin\fP shell
+script.
+Thanks also to the entire software group at Prisma for taking the
+time to review the paper and correct my grammar.
+.NH
+References
+.IP [Bell] 12
+Bell Telephone Laboratories.
+\*QSource Code Control System User's Guide.\*U
+\fIUNIX System III Programmer's Manual\fP, October 1981.
+.IP [Courington] 12
+Courington, W.
+\fIThe Network Software Environment\fP,
+Sun Technical Report FE197-0, Sun Microsystems Inc, February 1989.
+.IP [Essick] 12
+Essick, Raymond B. and Robert Bruce Kolstad.
+\fINotesfile Reference Manual\fP,
+Department of Computer Science Technical Report #1081,
+University of Illinois at Urbana-Champaign, Urbana, Illinois,
+1982, p. 26.
+.IP [Glew] 12
+Glew, Andy.
+\*QBoxes, Links, and Parallel Trees:
+Elements of a Configuration Management System.\*U
+\fIWorkshop Proceedings of the Software Management Conference\fP, USENIX,
+New Orleans, April 1989.
+.IP [Grune] 12
+Grune, Dick.
+Distributed the original shell script version of \fBcvs\fP in the
+\fBcomp.sources.unix\fP volume 6 release in 1986.
+.IP [Honda] 12
+Honda, Masahiro and Terrence Miller.
+\*QSoftware Management Using a CASE Environment.\*U
+\fIWorkshop Proceedings of the Software Management Conference\fP, USENIX,
+New Orleans, April 1989.
+.IP [Mahler] 12
+Mahler, Alex and Andreas Lampen.
+\*QAn Integrated Toolset for Engineering Software Configurations.\*U
+\fIProceedings of the ACM SIGSOFT/SIGPLAN Software Engineering Symposium on
+Practical Software Development Environments\fP, ACM, Boston, November 1988.
+Described is the \fBshape\fP toolkit posted to the
+\fBcomp.sources.unix\fP newsgroup in the volume 19 release.
+.IP [Tichy] 12
+Tichy, Walter F.
+\*QDesign, Implementation, and Evaluation of a Revision Control System.\*U
+\fIProceedings of the 6th International Conference on Software
+Engineering\fP, IEEE, Tokyo, September 1982.
+.IP [Wall] 12
+Wall, Larry.
+The \fBpatch\fP program is an indispensable tool for applying a diff file
+to an original.
+Can be found on uunet.uu.net in ~ftp/pub/patch.tar.
diff --git a/doc/cvs-paper.pdf b/doc/cvs-paper.pdf
new file mode 100644
index 0000000..4a153dd
--- /dev/null
+++ b/doc/cvs-paper.pdf
Binary files differ
diff --git a/doc/cvs.1 b/doc/cvs.1
new file mode 100644
index 0000000..2f35d0e
--- /dev/null
+++ b/doc/cvs.1
@@ -0,0 +1,3967 @@
+.\" This is the man page for CVS. It is auto-generated from the
+.\" cvs.man.header, cvs.texinfo, & cvs.man.footer files. Please make changes
+.\" there. A full copyright & license notice may also be found in cvs.texinfo.
+.\"
+.\" Man page autogeneration, including this header file, is
+.\" Copyright 2004-2005 The Free Software Foundation, Inc.,
+.\" Derek R. Price, & Ximbiot <http://ximbiot.com>.
+.\"
+.\" This documentation is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2, or (at your option)
+.\" any later version.
+.\"
+.\" This documentation is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this documentation; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.TH CVS 1 "\*(Dt"
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.\" quoted command
+.de `
+.RB ` "\|\\$1\|" '\\$2
+..
+.SH "NAME"
+cvs \- Concurrent Versions System
+.SH "SYNOPSIS"
+.TP
+\fBcvs\fP [ \fIcvs_options\fP ]
+.I cvs_command
+[
+.I command_options
+] [
+.I command_args
+]
+.SH "NOTE"
+.IX "revision control system" "\fLcvs\fR"
+.IX cvs "" "\fLcvs\fP \- concurrent versions system"
+.IX "concurrent versions system \- \fLcvs\fP"
+.IX "release control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system"
+.IX "source control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system"
+.IX revisions "cvs command" "" "\fLcvs\fP \- source control"
+This manpage is a summary of some of the features of
+\fBcvs\fP. It is auto-generated from an appendix of the CVS manual.
+For more in-depth documentation, please consult the
+Cederqvist manual (via the
+.B info CVS
+command or otherwise,
+as described in the SEE ALSO section of this manpage). Cross-references
+in this man page refer to nodes in the same.
+.SH "CVS commands"
+.SS "Guide to CVS commands"
+.SP
+This appendix describes the overall structure of
+\fBcvs\fR commands, and describes some commands in
+detail (others are described elsewhere; for a quick
+reference to \fBcvs\fR commands, see node `Invoking CVS\(aq in the CVS manual).
+.SP
+.SH "Structure"
+.SS "Overall structure of CVS commands"
+.IX "Structure"
+.IX "CVS command structure"
+.IX "Command structure"
+.IX "Format of CVS commands"
+.SP
+The overall format of all \fBcvs\fR commands is:
+.SP
+.PD 0
+.SP
+.IP "" 2
+cvs [ cvs_options ] cvs_command [ command_options ] [ command_args ]
+
+.PD
+.IP "" 0
+.SP
+.IP "" 0
+\fBcvs\fR
+.IP "" 2
+The name of the \fBcvs\fR program.
+.SP
+.IP "" 0
+\fBcvs_options\fR
+.IP "" 2
+Some options that affect all sub-commands of \fBcvs\fR. These are
+described below.
+.SP
+.IP "" 0
+\fBcvs_command\fR
+.IP "" 2
+One of several different sub-commands. Some of the commands have
+aliases that can be used instead; those aliases are noted in the
+reference manual for that command. There are only two situations
+where you may omit \fBcvs_command\fR: \fBcvs -H\fR elicits a
+list of available commands, and \fBcvs -v\fR displays version
+information on \fBcvs\fR itself.
+.SP
+.IP "" 0
+\fBcommand_options\fR
+.IP "" 2
+Options that are specific for the command.
+.SP
+.IP "" 0
+\fBcommand_args\fR
+.IP "" 2
+Arguments to the commands.
+.SP
+There is unfortunately some confusion between
+\fBcvs_options\fR and \fBcommand_options\fR.
+When given as a \fBcvs_option\fR, some options only
+affect some of the commands. When given as a
+\fBcommand_option\fR it may have a different meaning, and
+be accepted by more commands. In other words, do not
+take the above categorization too seriously. Look at
+the documentation instead.
+.SP
+.SH "Exit status"
+.SS "CVS\(aqs exit status"
+.IX "Exit status, of CVS"
+.SP
+\fBcvs\fR can indicate to the calling environment whether it
+succeeded or failed by setting its \fIexit status\fR.
+The exact way of testing the exit status will vary from
+one operating system to another. For example in a unix
+shell script the \fB$?\fR variable will be 0 if the
+last command returned a successful exit status, or
+greater than 0 if the exit status indicated failure.
+.SP
+If \fBcvs\fR is successful, it returns a successful status;
+if there is an error, it prints an error message and
+returns a failure status. The one exception to this is
+the \fBcvs diff\fR command. It will return a
+successful status if it found no differences, or a
+failure status if there were differences or if there
+was an error. Because this behavior provides no good
+way to detect errors, in the future it is possible that
+\fBcvs diff\fR will be changed to behave like the
+other \fBcvs\fR commands.
+.SP
+.SH "~/.cvsrc"
+.SS "Default options and the ~/.cvsrc file"
+.IX "\&.cvsrc file"
+.IX "Option defaults"
+.SP
+There are some \fBcommand_options\fR that are used so
+often that you might have set up an alias or some other
+means to make sure you always specify that option. One
+example (the one that drove the implementation of the
+\fB.cvsrc\fR support, actually) is that many people find the
+default output of the \fBdiff\fR command to be very
+hard to read, and that either context diffs or unidiffs
+are much easier to understand.
+.SP
+The \fB~/.cvsrc\fR file is a way that you can add
+default options to \fBcvs_commands\fR within cvs,
+instead of relying on aliases or other shell scripts.
+.SP
+The format of the \fB~/.cvsrc\fR file is simple. The
+file is searched for a line that begins with the same
+name as the \fBcvs_command\fR being executed. If a
+match is found, then the remainder of the line is split
+up (at whitespace characters) into separate options and
+added to the command arguments \fIbefore\fR any
+options from the command line.
+.SP
+If a command has two names (e.g., \fBcheckout\fR and
+\fBco\fR), the official name, not necessarily the one
+used on the command line, will be used to match against
+the file. So if this is the contents of the user\(aqs
+\fB~/.cvsrc\fR file:
+.SP
+.PD 0
+.SP
+.IP "" 2
+log -N
+.IP "" 2
+diff -uN
+.IP "" 2
+rdiff -u
+.IP "" 2
+update -Pd
+.IP "" 2
+checkout -P
+.IP "" 2
+release -d
+
+.PD
+.IP "" 0
+.SP
+the command \fBcvs checkout foo\fR would have the
+\fB-P\fR option added to the arguments, as well as
+\fBcvs co foo\fR.
+.SP
+With the example file above, the output from \fBcvs
+diff foobar\fR will be in unidiff format. \fBcvs diff
+-c foobar\fR will provide context diffs, as usual.
+Getting "old" format diffs would be slightly more
+complicated, because \fBdiff\fR doesn\(aqt have an option
+to specify use of the "old" format, so you would need
+\fBcvs -f diff foobar\fR.
+.SP
+In place of the command name you can use \fBcvs\fR to
+specify global options (see node `Global options\(aq in the CVS manual). For
+example the following line in \fB.cvsrc\fR
+.SP
+.PD 0
+.SP
+.IP "" 2
+cvs -z6
+
+.PD
+.IP "" 0
+.SP
+causes \fBcvs\fR to use compression level 6.
+.SP
+.SH "Global options"
+.IX "Options, global"
+.IX "Global options"
+.IX "Left-hand options"
+.SP
+The available \fBcvs_options\fR (that are given to the
+left of \fBcvs_command\fR) are:
+.SP
+.IP "" 0
+\fB--allow-root=\fIrootdir\fB\fR
+.IP "" 2
+May be invoked multiple times to specify one legal \fBcvsroot\fR directory with
+each invocation. Also causes CVS to preparse the configuration file for each
+specified root, which can be useful when configuring write proxies, See
+see node `Password authentication server\(aq in the CVS manual & see node `Write proxies\(aq in the CVS manual.
+.SP
+.IX "Authentication, stream"
+.IX "Stream authentication"
+.IP "" 0
+\fB-a\fR
+.IP "" 2
+Authenticate all communication between the client and
+the server. Only has an effect on the \fBcvs\fR client.
+As of this writing, this is only implemented when using
+a GSSAPI connection (see node `GSSAPI authenticated\(aq in the CVS manual).
+Authentication prevents certain sorts of attacks
+involving hijacking the active \fBtcp\fR connection.
+Enabling authentication does not enable encryption.
+.SP
+.IX "RCSBIN, overriding"
+.IX "Overriding RCSBIN"
+.IP "" 0
+\fB-b \fIbindir\fB\fR
+.IP "" 2
+In \fBcvs\fR 1.9.18 and older, this specified that
+\fBrcs\fR programs are in the \fIbindir\fR directory.
+Current versions of \fBcvs\fR do not run \fBrcs\fR
+programs; for compatibility this option is accepted,
+but it does nothing.
+.SP
+.IX "TMPDIR, environment variable"
+.IX "temporary file directory, set via command line"
+.IX "temporary file directory, set via environment variable"
+.IX "temporary file directory, set via config"
+.IX "temporary files, location of"
+.IP "" 0
+\fB-T \fItempdir\fB\fR
+.IP "" 2
+Use \fItempdir\fR as the directory where temporary files are
+located.
+.SP
+The \fBcvs\fR client and server store temporary files in a temporary directory.
+The path to this temporary directory is set via, in order of precedence:
+.SP
+.IP "\(bu" 4
+The argument to the global \fB-T\fR option.
+.SP
+.IP "\(bu" 4
+The value set for \fBTmpDir\fR in the config file (server only -
+see node `config\(aq in the CVS manual).
+.SP
+.IP "\(bu" 4
+The contents of the \fB$TMPDIR\fR environment variable (\fB%TMPDIR%\fR on
+Windows - see node `Environment variables\(aq in the CVS manual).
+.SP
+.IP "\(bu" 4
+/tmp
+.SP
+.SP
+Temporary directories should always be specified as an absolute pathname.
+When running a CVS client, \fB-T\fR affects only the local process;
+specifying \fB-T\fR for the client has no effect on the server and
+vice versa.
+.SP
+.IX "CVSROOT, overriding"
+.IX "Overriding CVSROOT"
+.IP "" 0
+\fB-d \fIcvs_root_directory\fB\fR
+.IP "" 2
+Use \fIcvs_root_directory\fR as the root directory
+pathname of the repository. Overrides the setting of
+the \fB$CVSROOT\fR environment variable. see node `Repository\(aq in the CVS manual.
+.SP
+.IX "EDITOR, overriding"
+.IX "Overriding EDITOR"
+.IP "" 0
+\fB-e \fIeditor\fB\fR
+.IP "" 2
+Use \fIeditor\fR to enter revision log information. Overrides the
+setting of the \fB$CVSEDITOR\fR and \fB$EDITOR\fR
+environment variables. For more information, see
+see node `Committing your changes\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+Do not read the \fB~/.cvsrc\fR file. This
+option is most often used because of the
+non-orthogonality of the \fBcvs\fR option set. For
+example, the \fBcvs log\fR option \fB-N\fR (turn off
+display of tag names) does not have a corresponding
+option to turn the display on. So if you have
+\fB-N\fR in the \fB~/.cvsrc\fR entry for \fBlog\fR,
+you may need to use \fB-f\fR to show the tag names.
+.SP
+.IP "" 0
+\fB-H\fR
+.IP "" 2
+.IP "" 0
+\fB--help\fR
+.IP "" 2
+Display usage information about the specified \fBcvs_command\fR
+(but do not actually execute the command). If you don\(aqt specify
+a command name, \fBcvs -H\fR displays overall help for
+\fBcvs\fR, including a list of other help options.
+.SP
+.IX "Read-only repository mode"
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Turns on read-only repository mode. This allows one to check out from a
+read-only repository, such as within an anoncvs server, or from a \fBcd-rom\fR
+repository.
+.SP
+Same effect as if the \fBCVSREADONLYFS\fR environment
+variable is set. Using \fB-R\fR can also considerably
+speed up checkouts over NFS.
+.SP
+.IX "Read-only mode"
+.IP "" 0
+\fB-n\fR
+.IP "" 2
+Do not change any files. Attempt to execute the
+\fBcvs_command\fR, but only to issue reports; do not remove,
+update, or merge any existing files, or create any new files.
+.SP
+Note that \fBcvs\fR will not necessarily produce exactly
+the same output as without \fB-n\fR. In some cases
+the output will be the same, but in other cases
+\fBcvs\fR will skip some of the processing that would
+have been required to produce the exact same output.
+.SP
+.IP "" 0
+\fB-Q\fR
+.IP "" 2
+Cause the command to be really quiet; the command will only
+generate output for serious problems.
+.SP
+.IP "" 0
+\fB-q\fR
+.IP "" 2
+Cause the command to be somewhat quiet; informational messages,
+such as reports of recursion through subdirectories, are
+suppressed.
+.SP
+.IX "Read-only files, and -r"
+.IP "" 0
+\fB-r\fR
+.IP "" 2
+Make new working files read-only. Same effect
+as if the \fB$CVSREAD\fR environment variable is set
+(see node `Environment variables\(aq in the CVS manual). The default is to
+make working files writable, unless watches are on
+(see node `Watches\(aq in the CVS manual).
+.SP
+.IP "" 0
+\fB-s \fIvariable\fB=\fIvalue\fB\fR
+.IP "" 2
+Set a user variable (see node `Variables\(aq in the CVS manual).
+.SP
+.IX "Trace"
+.IP "" 0
+\fB-t\fR
+.IP "" 2
+Trace program execution; display messages showing the steps of
+\fBcvs\fR activity. Particularly useful with \fB-n\fR to explore the
+potential impact of an unfamiliar command.
+.SP
+.IP "" 0
+\fB-v\fR
+.IP "" 2
+.IP "" 0
+\fB--version\fR
+.IP "" 2
+Display version and copyright information for \fBcvs\fR.
+.SP
+.IX "CVSREAD, overriding"
+.IX "Overriding CVSREAD"
+.IP "" 0
+\fB-w\fR
+.IP "" 2
+Make new working files read-write. Overrides the
+setting of the \fB$CVSREAD\fR environment variable.
+Files are created read-write by default, unless \fB$CVSREAD\fR is
+set or \fB-r\fR is given.
+.SP
+.IP "" 0
+\fB-x\fR
+.IP "" 2
+.IX "Encryption"
+Encrypt all communication between the client and the
+server. Only has an effect on the \fBcvs\fR client. As
+of this writing, this is only implemented when using a
+GSSAPI connection (see node `GSSAPI authenticated\(aq in the CVS manual) or a
+Kerberos connection (see node `Kerberos authenticated\(aq in the CVS manual).
+Enabling encryption implies that message traffic is
+also authenticated. Encryption support is not
+available by default; it must be enabled using a
+special configure option, \fB--enable-encryption\fR,
+when you build \fBcvs\fR.
+.SP
+.IP "" 0
+\fB-z \fIlevel\fB\fR
+.IP "" 2
+.IX "Compression"
+.IX "Gzip"
+Request compression \fIlevel\fR for network traffic.
+\fBcvs\fR interprets \fIlevel\fR identically to the \fBgzip\fR program.
+Valid levels are 1 (high speed, low compression) to
+9 (low speed, high compression), or 0 to disable
+compression (the default). Data sent to the server will
+be compressed at the requested level and the client will request
+the server use the same compression level for data returned. The
+server will use the closest level allowed by the server administrator to
+compress returned data. This option only has an effect when passed to
+the \fBcvs\fR client.
+.SP
+.SH "Common options"
+.SS "Common command options"
+.IX "Common options"
+.IX "Right-hand options"
+.SP
+This section describes the \fBcommand_options\fR that
+are available across several \fBcvs\fR commands. These
+options are always given to the right of
+\fBcvs_command\fR. Not all
+commands support all of these options; each option is
+only supported for commands where it makes sense.
+However, when a command has one of these options you
+can almost always count on the same behavior of the
+option as in other commands. (Other command options,
+which are listed with the individual commands, may have
+different behavior from one \fBcvs\fR command to the other).
+.SP
+\fBNote: the \fBhistory\fB command is an exception; it supports
+many options that conflict even with these standard options.\fR
+.SP
+.IX "Dates"
+.IX "Time"
+.IX "Specifying dates"
+.IP "" 0
+\fB-D \fIdate_spec\fB\fR
+.IP "" 2
+Use the most recent revision no later than \fIdate_spec\fR.
+\fIdate_spec\fR is a single argument, a date description
+specifying a date in the past.
+.SP
+The specification is \fIsticky\fR when you use it to make a
+private copy of a source file; that is, when you get a working
+file using \fB-D\fR, \fBcvs\fR records the date you specified, so that
+further updates in the same directory will use the same date
+(for more information on sticky tags/dates, see node `Sticky tags\(aq in the CVS manual).
+.SP
+\fB-D\fR is available with the \fBannotate\fR, \fBcheckout\fR,
+\fBdiff\fR, \fBexport\fR, \fBhistory\fR, \fBls\fR,
+\fBrdiff\fR, \fBrls\fR, \fBrtag\fR, \fBtag\fR, and \fBupdate\fR commands.
+(The \fBhistory\fR command uses this option in a
+slightly different way; see node `history options\(aq in the CVS manual).
+.SP
+For a complete description of the date formats accepted by \fBcvs\fR,
+see node `Date input formats\(aq in the CVS manual.
+.SP
+Remember to quote the argument to the \fB-D\fR
+flag so that your shell doesn\(aqt interpret spaces as
+argument separators. A command using the \fB-D\fR
+flag can look like this:
+.SP
+.PD 0
+.SP
+.IP "" 4
+$ cvs diff -D "1 hour ago" cvs.texinfo
+
+.PD
+.IP "" 2
+.SP
+.IX "Forcing a tag match"
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+When you specify a particular date or tag to \fBcvs\fR commands, they
+normally ignore files that do not contain the tag (or did not
+exist prior to the date) that you specified. Use the \fB-f\fR option
+if you want files retrieved even when there is no match for the
+tag or date. (The most recent revision of the file
+will be used).
+.SP
+Note that even with \fB-f\fR, a tag that you specify
+must exist (that is, in some file, not necessary in
+every file). This is so that \fBcvs\fR will continue to
+give an error if you mistype a tag name.
+.SP
+\fB-f\fR is available with these commands:
+\fBannotate\fR, \fBcheckout\fR, \fBexport\fR,
+\fBrdiff\fR, \fBrtag\fR, and \fBupdate\fR.
+.SP
+\fBWARNING: The \fBcommit\fB and \fBremove\fB
+commands also have a
+\fB-f\fB option, but it has a different behavior for
+those commands. See see node `commit options\(aq in the CVS manual, and
+see node `Removing files\(aq in the CVS manual.\fR
+.SP
+.IP "" 0
+\fB-k \fIkflag\fB\fR
+.IP "" 2
+Override the default processing of RCS keywords other than
+\fB-kb\fR. see node `Keyword substitution\(aq in the CVS manual, for the meaning of
+\fIkflag\fR. Used with the \fBcheckout\fR and \fBupdate\fR
+commands, your \fIkflag\fR specification is
+\fIsticky\fR; that is, when you use this option
+with a \fBcheckout\fR or \fBupdate\fR command,
+\fBcvs\fR associates your selected \fIkflag\fR with any files
+it operates on, and continues to use that \fIkflag\fR with future
+commands on the same files until you specify otherwise.
+.SP
+The \fB-k\fR option is available with the \fBadd\fR,
+\fBcheckout\fR, \fBdiff\fR, \fBexport\fR, \fBimport\fR,
+\fBrdiff\fR, and \fBupdate\fR commands.
+.SP
+\fBWARNING: Prior to CVS version 1.12.2, the \fB-k\fB flag
+overrode the \fB-kb\fB indication for a binary file. This could
+sometimes corrupt binary files. see node `Merging and keywords\(aq in the CVS manual, for
+more.\fR
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; run only in current working directory, rather than
+recursing through subdirectories.
+.SP
+Available with the following commands: \fBannotate\fR, \fBcheckout\fR,
+\fBcommit\fR, \fBdiff\fR, \fBedit\fR, \fBeditors\fR, \fBexport\fR,
+\fBlog\fR, \fBrdiff\fR, \fBremove\fR, \fBrtag\fR,
+\fBstatus\fR, \fBtag\fR, \fBunedit\fR, \fBupdate\fR, \fBwatch\fR,
+and \fBwatchers\fR.
+.SP
+.IX "Editor, avoiding invocation of"
+.IX "Avoiding editor invocation"
+.IP "" 0
+\fB-m \fImessage\fB\fR
+.IP "" 2
+Use \fImessage\fR as log information, instead of
+invoking an editor.
+.SP
+Available with the following commands: \fBadd\fR,
+\fBcommit\fR and \fBimport\fR.
+.SP
+.IP "" 0
+\fB-n\fR
+.IP "" 2
+Do not run any tag program. (A program can be
+specified to run in the modules
+database (see node `modules\(aq in the CVS manual); this option bypasses it).
+.SP
+\fBNote: this is not the same as the \fBcvs -n\fB
+program option, which you can specify to the left of a cvs command!\fR
+.SP
+Available with the \fBcheckout\fR, \fBcommit\fR, \fBexport\fR,
+and \fBrtag\fR commands.
+.SP
+.IP "" 0
+\fB-P\fR
+.IP "" 2
+Prune empty directories. See see node `Removing directories\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-p\fR
+.IP "" 2
+Pipe the files retrieved from the repository to standard output,
+rather than writing them in the current directory. Available
+with the \fBcheckout\fR and \fBupdate\fR commands.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Process directories recursively. This is the default for all \fBcvs\fR
+commands, with the exception of \fBls\fR & \fBrls\fR.
+.SP
+Available with the following commands: \fBannotate\fR, \fBcheckout\fR,
+\fBcommit\fR, \fBdiff\fR, \fBedit\fR, \fBeditors\fR, \fBexport\fR,
+\fBls\fR, \fBrdiff\fR, \fBremove\fR, \fBrls\fR, \fBrtag\fR,
+\fBstatus\fR, \fBtag\fR, \fBunedit\fR, \fBupdate\fR, \fBwatch\fR,
+and \fBwatchers\fR.
+.SP
+.IP "" 0
+\fB-r \fItag\fB\fR
+.IP "" 2
+.IP "" 0
+\fB-r \fItag\fB[:\fIdate\fB]\fR
+.IP "" 2
+.IX "HEAD, special tag"
+.IX "BASE, special tag"
+Use the revision specified by the \fItag\fR argument (and the \fIdate\fR
+argument for the commands which accept it) instead of the
+default \fIhead\fR revision. As well as arbitrary tags defined
+with the \fBtag\fR or \fBrtag\fR command, two special tags are
+always available: \fBHEAD\fR refers to the most recent version
+available in the repository, and \fBBASE\fR refers to the
+revision you last checked out into the current working directory.
+.SP
+The tag specification is sticky when you use this
+with \fBcheckout\fR or \fBupdate\fR to make your own
+copy of a file: \fBcvs\fR remembers the tag and continues to use it on
+future update commands, until you specify otherwise (for more information
+on sticky tags/dates, see node `Sticky tags\(aq in the CVS manual).
+.SP
+The tag can be either a symbolic or numeric tag, as
+described in see node `Tags\(aq in the CVS manual, or the name of a branch, as
+described in see node `Branching and merging\(aq in the CVS manual.
+When \fItag\fR is the name of a
+branch, some commands accept the optional \fIdate\fR argument to specify
+the revision as of the given date on the branch.
+When a command expects a specific revision,
+the name of a branch is interpreted as the most recent
+revision on that branch.
+.SP
+Specifying the \fB-q\fR global option along with the
+\fB-r\fR command option is often useful, to suppress
+the warning messages when the \fBrcs\fR file
+does not contain the specified tag.
+.SP
+\fBNote: this is not the same as the overall \fBcvs -r\fB option,
+which you can specify to the left of a \fBcvs\fB command!\fR
+.SP
+\fB-r \fItag\fB\fR is available with the \fBcommit\fR and \fBhistory\fR
+commands.
+.SP
+\fB-r \fItag\fB[:\fIdate\fB]\fR is available with the \fBannotate\fR,
+\fBcheckout\fR, \fBdiff\fR, \fBexport\fR, \fBrdiff\fR, \fBrtag\fR,
+and \fBupdate\fR commands.
+.SP
+.IP "" 0
+\fB-W\fR
+.IP "" 2
+Specify file names that should be filtered. You can
+use this option repeatedly. The spec can be a file
+name pattern of the same type that you can specify in
+the \fB.cvswrappers\fR file.
+Available with the following commands: \fBimport\fR,
+and \fBupdate\fR.
+.SP
+.SP
+.SH "admin"
+.SS "Administration"
+.IX "Admin (subcommand)"
+.SP
+.IP "\(bu" 2
+Requires: repository, working directory.
+.IP "\(bu" 2
+Changes: repository.
+.IP "\(bu" 2
+Synonym: rcs
+.SP
+This is the \fBcvs\fR interface to assorted
+administrative facilities. Some of them have
+questionable usefulness for \fBcvs\fR but exist for
+historical purposes. Some of the questionable options
+are likely to disappear in the future. This command
+\fIdoes\fR work recursively, so extreme care should be
+used.
+.SP
+.IX "cvsadmin"
+.IX "UserAdminOptions, in CVSROOT/config"
+On unix, if there is a group named \fBcvsadmin\fR,
+only members of that group can run \fBcvs admin\fR
+commands, except for those specified using the
+\fBUserAdminOptions\fR configuration option in the
+\fBCVSROOT/config\fR file. Options specified using
+\fBUserAdminOptions\fR can be run by any user. See
+see node `config\(aq in the CVS manual for more on \fBUserAdminOptions\fR.
+.SP
+The \fBcvsadmin\fR group should exist on the server,
+or any system running the non-client/server \fBcvs\fR.
+To disallow \fBcvs admin\fR for all users, create a
+group with no users in it. On NT, the \fBcvsadmin\fR
+feature does not exist and all users
+can run \fBcvs admin\fR.
+.SP
+.SH "admin options"
+.SP
+Some of these options have questionable usefulness for
+\fBcvs\fR but exist for historical purposes. Some even
+make it impossible to use \fBcvs\fR until you undo the
+effect!
+.SP
+.IP "" 0
+\fB-A\fIoldfile\fB\fR
+.IP "" 2
+Might not work together with \fBcvs\fR. Append the
+access list of \fIoldfile\fR to the access list of the
+\fBrcs\fR file.
+.SP
+.IP "" 0
+\fB-a\fIlogins\fB\fR
+.IP "" 2
+Might not work together with \fBcvs\fR. Append the
+login names appearing in the comma-separated list
+\fIlogins\fR to the access list of the \fBrcs\fR file.
+.SP
+.IP "" 0
+\fB-b[\fIrev\fB]\fR
+.IP "" 2
+Set the default branch to \fIrev\fR. In \fBcvs\fR, you
+normally do not manipulate default branches; sticky
+tags (see node `Sticky tags\(aq in the CVS manual) are a better way to decide
+which branch you want to work on. There is one reason
+to run \fBcvs admin -b\fR: to revert to the vendor\(aqs
+version when using vendor branches (see node `Reverting
+local changes\(aq in the CVS manual).
+There can be no space between \fB-b\fR and its argument.
+.SP
+.IX "Comment leader"
+.IP "" 0
+\fB-c\fIstring\fB\fR
+.IP "" 2
+Sets the comment leader to \fIstring\fR. The comment
+leader is not used by current versions of \fBcvs\fR or
+\fBrcs\fR 5.7. Therefore, you can almost surely not
+worry about it. see node `Keyword substitution\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-e[\fIlogins\fB]\fR
+.IP "" 2
+Might not work together with \fBcvs\fR. Erase the login
+names appearing in the comma-separated list
+\fIlogins\fR from the access list of the RCS file. If
+\fIlogins\fR is omitted, erase the entire access list.
+There can be no space between \fB-e\fR and its argument.
+.SP
+.IP "" 0
+\fB-I\fR
+.IP "" 2
+Run interactively, even if the standard input is not a
+terminal. This option does not work with the
+client/server \fBcvs\fR and is likely to disappear in
+a future release of \fBcvs\fR.
+.SP
+.IP "" 0
+\fB-i\fR
+.IP "" 2
+Useless with \fBcvs\fR. This creates and initializes a
+new \fBrcs\fR file, without depositing a revision. With
+\fBcvs\fR, add files with the \fBcvs add\fR command
+(see node `Adding files\(aq in the CVS manual).
+.SP
+.IP "" 0
+\fB-k\fIsubst\fB\fR
+.IP "" 2
+Set the default keyword
+substitution to \fIsubst\fR. see node `Keyword
+substitution\(aq in the CVS manual. Giving an explicit \fB-k\fR option to
+\fBcvs update\fR, \fBcvs export\fR, or \fBcvs
+checkout\fR overrides this default.
+.SP
+.IP "" 0
+\fB-l[\fIrev\fB]\fR
+.IP "" 2
+Lock the revision with number \fIrev\fR. If a branch
+is given, lock the latest revision on that branch. If
+\fIrev\fR is omitted, lock the latest revision on the
+default branch. There can be no space between
+\fB-l\fR and its argument.
+.SP
+This can be used in conjunction with the
+\fBrcslock.pl\fR script in the \fBcontrib\fR
+directory of the \fBcvs\fR source distribution to
+provide reserved checkouts (where only one user can be
+editing a given file at a time). See the comments in
+that file for details (and see the \fBREADME\fR file
+in that directory for disclaimers about the unsupported
+nature of contrib). According to comments in that
+file, locking must set to strict (which is the default).
+.SP
+.IP "" 0
+\fB-L\fR
+.IP "" 2
+Set locking to strict. Strict locking means that the
+owner of an RCS file is not exempt from locking for
+checkin. For use with \fBcvs\fR, strict locking must be
+set; see the discussion under the \fB-l\fR option above.
+.SP
+.IX "Changing a log message"
+.IX "Replacing a log message"
+.IX "Correcting a log message"
+.IX "Fixing a log message"
+.IX "Log message, correcting"
+.IP "" 0
+\fB-m\fIrev\fB:\fImsg\fB\fR
+.IP "" 2
+Replace the log message of revision \fIrev\fR with
+\fImsg\fR.
+.SP
+.IP "" 0
+\fB-N\fIname\fB[:[\fIrev\fB]]\fR
+.IP "" 2
+Act like \fB-n\fR, except override any previous
+assignment of \fIname\fR. For use with magic branches,
+see see node `Magic branch numbers\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-n\fIname\fB[:[\fIrev\fB]]\fR
+.IP "" 2
+Associate the symbolic name \fIname\fR with the branch
+or revision \fIrev\fR. It is normally better to use
+\fBcvs tag\fR or \fBcvs rtag\fR instead. Delete the
+symbolic name if both \fB:\fR and \fIrev\fR are
+omitted; otherwise, print an error message if
+\fIname\fR is already associated with another number.
+If \fIrev\fR is symbolic, it is expanded before
+association. A \fIrev\fR consisting of a branch number
+followed by a \fB.\fR stands for the current latest
+revision in the branch. A \fB:\fR with an empty
+\fIrev\fR stands for the current latest revision on the
+default branch, normally the trunk. For example,
+\fBcvs admin -n\fIname\fB:\fR associates \fIname\fR with the
+current latest revision of all the RCS files;
+this contrasts with \fBcvs admin -n\fIname\fB:$\fR which
+associates \fIname\fR with the revision numbers
+extracted from keyword strings in the corresponding
+working files.
+.SP
+.IX "Deleting revisions"
+.IX "Outdating revisions"
+.IX "Saving space"
+.IP "" 0
+\fB-o\fIrange\fB\fR
+.IP "" 2
+Deletes (\fIoutdates\fR) the revisions given by
+\fIrange\fR.
+.SP
+Note that this command can be quite dangerous unless
+you know \fIexactly\fR what you are doing (for example
+see the warnings below about how the
+\fIrev1\fR:\fIrev2\fR syntax is confusing).
+.SP
+If you are short on disc this option might help you.
+But think twice before using it\(emthere is no way short
+of restoring the latest backup to undo this command!
+If you delete different revisions than you planned,
+either due to carelessness or (heaven forbid) a \fBcvs\fR
+bug, there is no opportunity to correct the error
+before the revisions are deleted. It probably would be
+a good idea to experiment on a copy of the repository
+first.
+.SP
+Specify \fIrange\fR in one of the following ways:
+.SP
+.IP "" 2
+\fB\fIrev1\fB::\fIrev2\fB\fR
+.IP "" 4
+Collapse all revisions between rev1 and rev2, so that
+\fBcvs\fR only stores the differences associated with going
+from rev1 to rev2, not intermediate steps. For
+example, after \fB-o 1.3::1.5\fR one can retrieve
+revision 1.3, revision 1.5, or the differences to get
+from 1.3 to 1.5, but not the revision 1.4, or the
+differences between 1.3 and 1.4. Other examples:
+\fB-o 1.3::1.4\fR and \fB-o 1.3::1.3\fR have no
+effect, because there are no intermediate revisions to
+remove.
+.SP
+.IP "" 2
+\fB::\fIrev\fB\fR
+.IP "" 4
+Collapse revisions between the beginning of the branch
+containing \fIrev\fR and \fIrev\fR itself. The
+branchpoint and \fIrev\fR are left intact. For
+example, \fB-o ::1.3.2.6\fR deletes revision 1.3.2.1,
+revision 1.3.2.5, and everything in between, but leaves
+1.3 and 1.3.2.6 intact.
+.SP
+.IP "" 2
+\fB\fIrev\fB::\fR
+.IP "" 4
+Collapse revisions between \fIrev\fR and the end of the
+branch containing \fIrev\fR. Revision \fIrev\fR is
+left intact but the head revision is deleted.
+.SP
+.IP "" 2
+\fB\fIrev\fB\fR
+.IP "" 4
+Delete the revision \fIrev\fR. For example, \fB-o
+1.3\fR is equivalent to \fB-o 1.2::1.4\fR.
+.SP
+.IP "" 2
+\fB\fIrev1\fB:\fIrev2\fB\fR
+.IP "" 4
+Delete the revisions from \fIrev1\fR to \fIrev2\fR,
+inclusive, on the same branch. One will not be able to
+retrieve \fIrev1\fR or \fIrev2\fR or any of the
+revisions in between. For example, the command
+\fBcvs admin -oR_1_01:R_1_02 \&.\fR is rarely useful.
+It means to delete revisions up to, and including, the
+tag R_1_02. But beware! If there are files that have not
+changed between R_1_02 and R_1_03 the file will have
+\fIthe same\fR numerical revision number assigned to
+the tags R_1_02 and R_1_03. So not only will it be
+impossible to retrieve R_1_02; R_1_03 will also have to
+be restored from the tapes! In most cases you want to
+specify \fIrev1\fR::\fIrev2\fR instead.
+.SP
+.IP "" 2
+\fB:\fIrev\fB\fR
+.IP "" 4
+Delete revisions from the beginning of the
+branch containing \fIrev\fR up to and including
+\fIrev\fR.
+.SP
+.IP "" 2
+\fB\fIrev\fB:\fR
+.IP "" 4
+Delete revisions from revision \fIrev\fR, including
+\fIrev\fR itself, to the end of the branch containing
+\fIrev\fR.
+.SP
+None of the revisions to be deleted may have
+branches or locks.
+.SP
+If any of the revisions to be deleted have symbolic
+names, and one specifies one of the \fB::\fR syntaxes,
+then \fBcvs\fR will give an error and not delete any
+revisions. If you really want to delete both the
+symbolic names and the revisions, first delete the
+symbolic names with \fBcvs tag -d\fR, then run
+\fBcvs admin -o\fR. If one specifies the
+non-\fB::\fR syntaxes, then \fBcvs\fR will delete the
+revisions but leave the symbolic names pointing to
+nonexistent revisions. This behavior is preserved for
+compatibility with previous versions of \fBcvs\fR, but
+because it isn\(aqt very useful, in the future it may
+change to be like the \fB::\fR case.
+.SP
+Due to the way \fBcvs\fR handles branches \fIrev\fR
+cannot be specified symbolically if it is a branch.
+see node `Magic branch numbers\(aq in the CVS manual, for an explanation.
+.SP
+Make sure that no-one has checked out a copy of the
+revision you outdate. Strange things will happen if he
+starts to edit it and tries to check it back in. For
+this reason, this option is not a good way to take back
+a bogus commit; commit a new revision undoing the bogus
+change instead (see node `Merging two revisions\(aq in the CVS manual).
+.SP
+.IP "" 0
+\fB-q\fR
+.IP "" 2
+Run quietly; do not print diagnostics.
+.SP
+.IP "" 0
+\fB-s\fIstate\fB[:\fIrev\fB]\fR
+.IP "" 2
+Useful with \fBcvs\fR. Set the state attribute of the
+revision \fIrev\fR to \fIstate\fR. If \fIrev\fR is a
+branch number, assume the latest revision on that
+branch. If \fIrev\fR is omitted, assume the latest
+revision on the default branch. Any identifier is
+acceptable for \fIstate\fR. A useful set of states is
+\fBExp\fR (for experimental), \fBStab\fR (for
+stable), and \fBRel\fR (for released). By default,
+the state of a new revision is set to \fBExp\fR when
+it is created. The state is visible in the output from
+\fIcvs log\fR (see node `log\(aq in the CVS manual), and in the
+\fB$\fP\fPLog$\fR and \fB$\fP\fPState$\fR keywords
+(see node `Keyword substitution\(aq in the CVS manual). Note that \fBcvs\fR
+uses the \fBdead\fR state for its own purposes (see node `Attic\(aq in the CVS manual); to
+take a file to or from the \fBdead\fR state use
+commands like \fBcvs remove\fR and \fBcvs add\fR
+(see node `Adding and removing\(aq in the CVS manual), not \fBcvs admin -s\fR.
+.SP
+.IP "" 0
+\fB-t[\fIfile\fB]\fR
+.IP "" 2
+Useful with \fBcvs\fR. Write descriptive text from the
+contents of the named \fIfile\fR into the RCS file,
+deleting the existing text. The \fIfile\fR pathname
+may not begin with \fB-\fR. The descriptive text can be seen in the
+output from \fBcvs log\fR (see node `log\(aq in the CVS manual).
+There can be no space between \fB-t\fR and its argument.
+.SP
+If \fIfile\fR is omitted,
+obtain the text from standard input, terminated by
+end-of-file or by a line containing \fB.\fR by itself.
+Prompt for the text if interaction is possible; see
+\fB-I\fR.
+.SP
+.IP "" 0
+\fB-t-\fIstring\fB\fR
+.IP "" 2
+Similar to \fB-t\fIfile\fB\fR. Write descriptive text
+from the \fIstring\fR into the \fBrcs\fR file, deleting
+the existing text.
+There can be no space between \fB-t\fR and its argument.
+.SP
+.IP "" 0
+\fB-U\fR
+.IP "" 2
+Set locking to non-strict. Non-strict locking means
+that the owner of a file need not lock a revision for
+checkin. For use with \fBcvs\fR, strict locking must be
+set; see the discussion under the \fB-l\fR option
+above.
+.SP
+.IP "" 0
+\fB-u[\fIrev\fB]\fR
+.IP "" 2
+See the option \fB-l\fR above, for a discussion of
+using this option with \fBcvs\fR. Unlock the revision
+with number \fIrev\fR. If a branch is given, unlock
+the latest revision on that branch. If \fIrev\fR is
+omitted, remove the latest lock held by the caller.
+Normally, only the locker of a revision may unlock it;
+somebody else unlocking a revision breaks the lock.
+This causes the original locker to be sent a \fBcommit\fR
+notification (see node `Getting Notified\(aq in the CVS manual).
+There can be no space between \fB-u\fR and its argument.
+.SP
+.IP "" 0
+\fB-V\fIn\fB\fR
+.IP "" 2
+In previous versions of \fBcvs\fR, this option meant to
+write an \fBrcs\fR file which would be acceptable to
+\fBrcs\fR version \fIn\fR, but it is now obsolete and
+specifying it will produce an error.
+.SP
+.IP "" 0
+\fB-x\fIsuffixes\fB\fR
+.IP "" 2
+In previous versions of \fBcvs\fR, this was documented
+as a way of specifying the names of the \fBrcs\fR
+files. However, \fBcvs\fR has always required that the
+\fBrcs\fR files used by \fBcvs\fR end in \fB,v\fR, so
+this option has never done anything useful.
+.SP
+.SP
+.SH "annotate"
+.SS "What revision modified each line of a file?"
+.IX "annotate (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: annotate [options] files\&...
+.IP "\(bu" 2
+Requires: repository.
+.IP "\(bu" 2
+Changes: nothing.
+.SP
+For each file in \fIfiles\fR, print the head revision
+of the trunk, together with information on the last
+modification for each line.
+.SP
+.SH "annotate options"
+.SP
+These standard options are supported by \fBannotate\fR
+(see node `Common options\(aq in the CVS manual, for a complete description of
+them):
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local directory only, no recursion.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Process directories recursively.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+Use head revision if tag/date not found.
+.SP
+.IP "" 0
+\fB-F\fR
+.IP "" 2
+Annotate binary files.
+.SP
+.IP "" 0
+\fB-r \fItag\fB[:\fIdate\fB]\fR
+.IP "" 2
+Annotate file as of specified revision/tag or, when \fIdate\fR is specified
+and \fItag\fR is a branch tag, the version from the branch \fItag\fR as it
+existed on \fIdate\fR. See see node `Common options\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-D \fIdate\fB\fR
+.IP "" 2
+Annotate file as of specified date.
+.SP
+.SH "annotate example"
+.SP
+For example:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs annotate ssfile
+.IP "" 2
+Annotations for ssfile
+.IP "" 2
+***************
+.IP "" 2
+1.1 (mary 27-Mar-96): ssfile line 1
+.IP "" 2
+1.2 (joe 28-Mar-96): ssfile line 2
+
+.PD
+.IP "" 0
+.SP
+The file \fBssfile\fR currently contains two lines.
+The \fBssfile line 1\fR line was checked in by
+\fBmary\fR on March 27. Then, on March 28, \fBjoe\fR
+added a line \fBssfile line 2\fR, without modifying
+the \fBssfile line 1\fR line. This report doesn\(aqt
+tell you anything about lines which have been deleted
+or replaced; you need to use \fBcvs diff\fR for that
+(see node `diff\(aq in the CVS manual).
+.SP
+The options to \fBcvs annotate\fR are listed in
+see node `Invoking CVS\(aq in the CVS manual, and can be used to select the files
+and revisions to annotate. The options are described
+in more detail there and in see node `Common options\(aq in the CVS manual.
+.SP
+.SH "checkout"
+.SS "Check out sources for editing"
+.IX "checkout (subcommand)"
+.IX "co (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: checkout [options] modules\&...
+.IP "\(bu" 2
+Requires: repository.
+.IP "\(bu" 2
+Changes: working directory.
+.IP "\(bu" 2
+Synonyms: co, get
+.SP
+Create or update a working directory containing copies of the
+source files specified by \fImodules\fR. You must execute
+\fBcheckout\fR before using most of the other \fBcvs\fR
+commands, since most of them operate on your working
+directory.
+.SP
+The \fImodules\fR are either
+symbolic names for some
+collection of source directories and files, or paths to
+directories or files in the repository. The symbolic
+names are defined in the \fBmodules\fR file.
+see node `modules\(aq in the CVS manual.
+.SP
+Depending on the modules you specify, \fBcheckout\fR may
+recursively create directories and populate them with
+the appropriate source files. You can then edit these
+source files at any time (regardless of whether other
+software developers are editing their own copies of the
+sources); update them to include new changes applied by
+others to the source repository; or commit your work as
+a permanent change to the source repository.
+.SP
+Note that \fBcheckout\fR is used to create
+directories. The top-level directory created is always
+added to the directory where \fBcheckout\fR is
+invoked, and usually has the same name as the specified
+module. In the case of a module alias, the created
+sub-directory may have a different name, but you can be
+sure that it will be a sub-directory, and that
+\fBcheckout\fR will show the relative path leading to
+each file as it is extracted into your private work
+area (unless you specify the \fB-Q\fR global option).
+.SP
+The files created by \fBcheckout\fR are created
+read-write, unless the \fB-r\fR option to \fBcvs\fR
+(see node `Global options\(aq in the CVS manual) is specified, the
+\fBCVSREAD\fR environment variable is specified
+(see node `Environment variables\(aq in the CVS manual), or a watch is in
+effect for that file (see node `Watches\(aq in the CVS manual).
+.SP
+Note that running \fBcheckout\fR on a directory that was already
+built by a prior \fBcheckout\fR is also permitted.
+This is similar to specifying the \fB-d\fR option
+to the \fBupdate\fR command in the sense that new
+directories that have been created in the repository
+will appear in your work area.
+However, \fBcheckout\fR takes a module name whereas
+\fBupdate\fR takes a directory name. Also
+to use \fBcheckout\fR this way it must be run from the
+top level directory (where you originally ran
+\fBcheckout\fR from), so before you run
+\fBcheckout\fR to update an existing directory, don\(aqt
+forget to change your directory to the top level
+directory.
+.SP
+For the output produced by the \fBcheckout\fR command
+see see node `update output\(aq in the CVS manual.
+.SP
+.SH "checkout options"
+.SP
+These standard options are supported by \fBcheckout\fR
+(see node `Common options\(aq in the CVS manual, for a complete description of
+them):
+.SP
+.IP "" 0
+\fB-D \fIdate\fB\fR
+.IP "" 2
+Use the most recent revision no later than \fIdate\fR.
+This option is sticky, and implies \fB-P\fR. See
+see node `Sticky tags\(aq in the CVS manual, for more information on sticky tags/dates.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+Only useful with the \fB-D\fR or \fB-r\fR flags. If no matching revision is
+found, retrieve the most recent revision (instead of ignoring the file).
+.SP
+.IP "" 0
+\fB-k \fIkflag\fB\fR
+.IP "" 2
+Process keywords according to \fIkflag\fR. See
+see node `Keyword substitution\(aq in the CVS manual.
+This option is sticky; future updates of
+this file in this working directory will use the same
+\fIkflag\fR. The \fBstatus\fR command can be viewed
+to see the sticky options. See see node `Invoking CVS\(aq in the CVS manual, for
+more information on the \fBstatus\fR command.
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; run only in current working directory.
+.SP
+.IP "" 0
+\fB-n\fR
+.IP "" 2
+Do not run any checkout program (as specified
+with the \fB-o\fR option in the modules file;
+see node `modules\(aq in the CVS manual).
+.SP
+.IP "" 0
+\fB-P\fR
+.IP "" 2
+Prune empty directories. See see node `Moving directories\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-p\fR
+.IP "" 2
+Pipe files to the standard output.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Checkout directories recursively. This option is on by default.
+.SP
+.IP "" 0
+\fB-r \fItag\fB[:\fIdate\fB]\fR
+.IP "" 2
+Checkout the revision specified by \fItag\fR or, when \fIdate\fR is specified
+and \fItag\fR is a branch tag, the version from the branch \fItag\fR as it
+existed on \fIdate\fR. This option is sticky, and implies \fB-P\fR.
+See see node `Sticky tags\(aq in the CVS manual, for more information on sticky tags/dates. Also,
+see see node `Common options\(aq in the CVS manual.
+.SP
+In addition to those, you can use these special command
+options with \fBcheckout\fR:
+.SP
+.IP "" 0
+\fB-A\fR
+.IP "" 2
+Reset any sticky tags, dates, or \fB-k\fR options.
+See see node `Sticky tags\(aq in the CVS manual, for more information on sticky tags/dates.
+.SP
+.IP "" 0
+\fB-c\fR
+.IP "" 2
+Copy the module file, sorted, to the standard output,
+instead of creating or modifying any files or
+directories in your working directory.
+.SP
+.IP "" 0
+\fB-d \fIdir\fB\fR
+.IP "" 2
+Create a directory called \fIdir\fR for the working
+files, instead of using the module name. In general,
+using this flag is equivalent to using \fBmkdir
+\fIdir\fB; cd \fIdir\fB\fR followed by the checkout
+command without the \fB-d\fR flag.
+.SP
+There is an important exception, however. It is very
+convenient when checking out a single item to have the
+output appear in a directory that doesn\(aqt contain empty
+intermediate directories. In this case \fIonly\fR,
+\fBcvs\fR tries to \`\`shorten\(aq\(aq pathnames to avoid those empty
+directories.
+.SP
+For example, given a module \fBfoo\fR that contains
+the file \fBbar.c\fR, the command \fBcvs co -d dir
+foo\fR will create directory \fBdir\fR and place
+\fBbar.c\fR inside. Similarly, given a module
+\fBbar\fR which has subdirectory \fBbaz\fR wherein
+there is a file \fBquux.c\fR, the command \fBcvs co
+-d dir bar/baz\fR will create directory \fBdir\fR and
+place \fBquux.c\fR inside.
+.SP
+Using the \fB-N\fR flag will defeat this behavior.
+Given the same module definitions above, \fBcvs co
+-N -d dir foo\fR will create directories \fBdir/foo\fR
+and place \fBbar.c\fR inside, while \fBcvs co -N -d
+dir bar/baz\fR will create directories \fBdir/bar/baz\fR
+and place \fBquux.c\fR inside.
+.SP
+.IP "" 0
+\fB-j \fItag\fB\fR
+.IP "" 2
+With two \fB-j\fR options, merge changes from the
+revision specified with the first \fB-j\fR option to
+the revision specified with the second \fBj\fR option,
+into the working directory.
+.SP
+With one \fB-j\fR option, merge changes from the
+ancestor revision to the revision specified with the
+\fB-j\fR option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the \fB-j\fR option.
+.SP
+In addition, each -j option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+\fB-j\fISymbolic_Tag\fB:\fIDate_Specifier\fB\fR.
+.SP
+see node `Branching and merging\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-N\fR
+.IP "" 2
+Only useful together with \fB-d \fIdir\fB\fR. With
+this option, \fBcvs\fR will not \`\`shorten\(aq\(aq module paths
+in your working directory when you check out a single
+module. See the \fB-d\fR flag for examples and a
+discussion.
+.SP
+.IP "" 0
+\fB-s\fR
+.IP "" 2
+Like \fB-c\fR, but include the status of all modules,
+and sort it by the status string. see node `modules\(aq in the CVS manual, for
+info about the \fB-s\fR option that is used inside the
+modules file to set the module status.
+.SP
+.SH "checkout examples"
+.SP
+Get a copy of the module \fBtc\fR:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs checkout tc
+
+.PD
+.IP "" 0
+.SP
+Get a copy of the module \fBtc\fR as it looked one day
+ago:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs checkout -D yesterday tc
+
+.PD
+.IP "" 0
+.SP
+.SH "commit"
+.SS "Check files into the repository"
+.IX "commit (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: commit [-lnRf] [-m \(aqlog_message\(aq |
+-F file] [-r revision] [files\&...]
+.IP "\(bu" 2
+Requires: working directory, repository.
+.IP "\(bu" 2
+Changes: repository.
+.IP "\(bu" 2
+Synonym: ci
+.SP
+Use \fBcommit\fR when you want to incorporate changes
+from your working source files into the source
+repository.
+.SP
+If you don\(aqt specify particular files to commit, all of
+the files in your working current directory are
+examined. \fBcommit\fR is careful to change in the
+repository only those files that you have really
+changed. By default (or if you explicitly specify the
+\fB-R\fR option), files in subdirectories are also
+examined and committed if they have changed; you can
+use the \fB-l\fR option to limit \fBcommit\fR to the
+current directory only.
+.SP
+\fBcommit\fR verifies that the selected files are up
+to date with the current revisions in the source
+repository; it will notify you, and exit without
+committing, if any of the specified files must be made
+current first with \fBupdate\fR (see node `update\(aq in the CVS manual).
+\fBcommit\fR does not call the \fBupdate\fR command
+for you, but rather leaves that for you to do when the
+time is right.
+.SP
+When all is well, an editor is invoked to allow you to
+enter a log message that will be written to one or more
+logging programs (see node `modules\(aq in the CVS manual, and see node `loginfo\(aq in the CVS manual)
+and placed in the \fBrcs\fR file inside the
+repository. This log message can be retrieved with the
+\fBlog\fR command; see see node `log\(aq in the CVS manual. You can specify the
+log message on the command line with the \fB-m
+\fImessage\fB\fR option, and thus avoid the editor invocation,
+or use the \fB-F \fIfile\fB\fR option to specify
+that the argument file contains the log message.
+.SP
+At \fBcommit\fR, a unique commitid is placed in the \fBrcs\fR
+file inside the repository. All files committed at once
+get the same commitid. The commitid can be retrieved with
+the \fBlog\fR and \fBstatus\fR command; see see node `log\(aq in the CVS manual,
+see node `File status\(aq in the CVS manual.
+.SP
+.SH "commit options"
+.SP
+These standard options are supported by \fBcommit\fR
+(see node `Common options\(aq in the CVS manual, for a complete description of
+them):
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; run only in current working directory.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Commit directories recursively. This is on by default.
+.SP
+.IP "" 0
+\fB-r \fIrevision\fB\fR
+.IP "" 2
+Commit to \fIrevision\fR. \fIrevision\fR must be
+either a branch, or a revision on the main trunk that
+is higher than any existing revision number
+(see node `Assigning revisions\(aq in the CVS manual). You
+cannot commit to a specific revision on a branch.
+.SP
+\fBcommit\fR also supports these options:
+.SP
+.IP "" 0
+\fB-c\fR
+.IP "" 2
+Refuse to commit files unless the user has registered a valid edit on the
+file via \fBcvs edit\fR. This is most useful when \fBcommit -c\fR
+and \fBedit -c\fR have been placed in all \fB.cvsrc\fR files.
+A commit can be forced anyways by either regestering an edit retroactively
+via \fBcvs edit\fR (no changes to the file will be lost) or using the
+\fB-f\fR option to commit. Support for \fBcommit -c\fR requires both
+client and a server versions 1.12.10 or greater.
+.SP
+.IP "" 0
+\fB-F \fIfile\fB\fR
+.IP "" 2
+Read the log message from \fIfile\fR, instead
+of invoking an editor.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+Note that this is not the standard behavior of
+the \fB-f\fR option as defined in see node `Common options\(aq in the CVS manual.
+.SP
+Force \fBcvs\fR to commit a new revision even if you haven\(aqt
+made any changes to the file. As of \fBcvs\fR version 1.12.10,
+it also causes the \fB-c\fR option to be ignored. If the current revision
+of \fIfile\fR is 1.7, then the following two commands
+are equivalent:
+.SP
+.PD 0
+.SP
+.IP "" 4
+$ cvs commit -f \fIfile\fR
+.IP "" 4
+$ cvs commit -r 1.8 \fIfile\fR
+
+.PD
+.IP "" 2
+.SP
+The \fB-f\fR option disables recursion (i.e., it
+implies \fB-l\fR). To force \fBcvs\fR to commit a new
+revision for all files in all subdirectories, you must
+use \fB-f -R\fR.
+.SP
+.IP "" 0
+\fB-m \fImessage\fB\fR
+.IP "" 2
+Use \fImessage\fR as the log message, instead of
+invoking an editor.
+.SP
+.SH "commit examples"
+.SP
+.SS "Committing to a branch"
+.SP
+You can commit to a branch revision (one that has an
+even number of dots) with the \fB-r\fR option. To
+create a branch revision, use the \fB-b\fR option
+of the \fBrtag\fR or \fBtag\fR commands
+(see node `Branching and merging\(aq in the CVS manual). Then, either \fBcheckout\fR or
+\fBupdate\fR can be used to base your sources on the
+newly created branch. From that point on, all
+\fBcommit\fR changes made within these working sources
+will be automatically added to a branch revision,
+thereby not disturbing main-line development in any
+way. For example, if you had to create a patch to the
+1.2 version of the product, even though the 2.0 version
+is already under development, you might do:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs rtag -b -r FCS1_2 FCS1_2_Patch product_module
+.IP "" 2
+$ cvs checkout -r FCS1_2_Patch product_module
+.IP "" 2
+$ cd product_module
+.IP "" 2
+[[ hack away ]]
+.IP "" 2
+$ cvs commit
+
+.PD
+.IP "" 0
+.SP
+This works automatically since the \fB-r\fR option is
+sticky.
+.SP
+.SS "Creating the branch after editing"
+.SP
+Say you have been working on some extremely
+experimental software, based on whatever revision you
+happened to checkout last week. If others in your
+group would like to work on this software with you, but
+without disturbing main-line development, you could
+commit your change to a new branch. Others can then
+checkout your experimental stuff and utilize the full
+benefit of \fBcvs\fR conflict resolution. The scenario might
+look like:
+.SP
+.PD 0
+.SP
+.IP "" 2
+[[ hacked sources are present ]]
+.IP "" 2
+$ cvs tag -b EXPR1
+.IP "" 2
+$ cvs update -r EXPR1
+.IP "" 2
+$ cvs commit
+
+.PD
+.IP "" 0
+.SP
+The \fBupdate\fR command will make the \fB-r
+EXPR1\fR option sticky on all files. Note that your
+changes to the files will never be removed by the
+\fBupdate\fR command. The \fBcommit\fR will
+automatically commit to the correct branch, because the
+\fB-r\fR is sticky. You could also do like this:
+.SP
+.PD 0
+.SP
+.IP "" 2
+[[ hacked sources are present ]]
+.IP "" 2
+$ cvs tag -b EXPR1
+.IP "" 2
+$ cvs commit -r EXPR1
+
+.PD
+.IP "" 0
+.SP
+but then, only those files that were changed by you
+will have the \fB-r EXPR1\fR sticky flag. If you hack
+away, and commit without specifying the \fB-r EXPR1\fR
+flag, some files may accidentally end up on the main
+trunk.
+.SP
+To work with you on the experimental change, others
+would simply do
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs checkout -r EXPR1 whatever_module
+
+.PD
+.IP "" 0
+.SP
+.SH "diff"
+.SS "Show differences between revisions"
+.IX "diff (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: diff [-lR] [-k kflag] [format_options] [(-r rev1[:date1] | -D date1) [-r rev2[:date2] | -D date2]] [files\&...]
+.IP "\(bu" 2
+Requires: working directory, repository.
+.IP "\(bu" 2
+Changes: nothing.
+.SP
+The \fBdiff\fR command is used to compare different
+revisions of files. The default action is to compare
+your working files with the revisions they were based
+on, and report any differences that are found.
+.SP
+If any file names are given, only those files are
+compared. If any directories are given, all files
+under them will be compared.
+.SP
+The exit status for diff is different than for other
+\fBcvs\fR commands; for details see node `Exit status\(aq in the CVS manual.
+.SP
+.SH "diff options"
+.SP
+These standard options are supported by \fBdiff\fR
+(see node `Common options\(aq in the CVS manual, for a complete description of
+them):
+.SP
+.IP "" 0
+\fB-D \fIdate\fB\fR
+.IP "" 2
+Use the most recent revision no later than \fIdate\fR.
+See \fB-r\fR for how this affects the comparison.
+.SP
+.IP "" 0
+\fB-k \fIkflag\fB\fR
+.IP "" 2
+Process keywords according to \fIkflag\fR. See
+see node `Keyword substitution\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; run only in current working directory.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Examine directories recursively. This option is on by
+default.
+.SP
+.IP "" 0
+\fB-r \fItag\fB[:\fIdate\fB]\fR
+.IP "" 2
+Compare with revision specified by \fItag\fR or, when \fIdate\fR is specified
+and \fItag\fR is a branch tag, the version from the branch \fItag\fR as it
+existed on \fIdate\fR. Zero, one or two
+\fB-r\fR options can be present. With no \fB-r\fR
+option, the working file will be compared with the
+revision it was based on. With one \fB-r\fR, that
+revision will be compared to your current working file.
+With two \fB-r\fR options those two revisions will be
+compared (and your working file will not affect the
+outcome in any way).
+.SP
+One or both \fB-r\fR options can be replaced by a
+\fB-D \fIdate\fB\fR option, described above.
+.SP
+The following options specify the format of the
+output. They have the same meaning as in GNU diff.
+Most options have two equivalent names, one of which is a single letter
+preceded by \fB-\fR, and the other of which is a long name preceded by
+\fB--\fR.
+.SP
+.IP "" 0
+\fB-\fIlines\fB\fR
+.IP "" 2
+Show \fIlines\fR (an integer) lines of context. This option does not
+specify an output format by itself; it has no effect unless it is
+combined with \fB-c\fR or \fB-u\fR. This option is obsolete. For proper
+operation, \fBpatch\fR typically needs at least two lines of context.
+.SP
+.IP "" 0
+\fB-a\fR
+.IP "" 2
+Treat all files as text and compare them line-by-line, even if they
+do not seem to be text.
+.SP
+.IP "" 0
+\fB-b\fR
+.IP "" 2
+Ignore trailing white space and consider all other sequences of one or
+more white space characters to be equivalent.
+.SP
+.IP "" 0
+\fB-B\fR
+.IP "" 2
+Ignore changes that just insert or delete blank lines.
+.SP
+.IP "" 0
+\fB--binary\fR
+.IP "" 2
+Read and write data in binary mode.
+.SP
+.IP "" 0
+\fB--brief\fR
+.IP "" 2
+Report only whether the files differ, not the details of the
+differences.
+.SP
+.IP "" 0
+\fB-c\fR
+.IP "" 2
+Use the context output format.
+.SP
+.IP "" 0
+\fB-C \fIlines\fB\fR
+.IP "" 2
+.IP "" 0
+\fB--context\fR[\fB=\fIlines\fB\fR]\fB\fR
+.IP "" 2
+Use the context output format, showing \fIlines\fR (an integer) lines of
+context, or three if \fIlines\fR is not given.
+For proper operation, \fBpatch\fR typically needs at least two lines of
+context.
+.SP
+.IP "" 0
+\fB--changed-group-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output a line group containing differing lines from
+both files in if-then-else format. see node `Line group formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-d\fR
+.IP "" 2
+Change the algorithm to perhaps find a smaller set of changes. This makes
+\fBdiff\fR slower (sometimes much slower).
+.SP
+.IP "" 0
+\fB-e\fR
+.IP "" 2
+.IP "" 0
+\fB--ed\fR
+.IP "" 2
+Make output that is a valid \fBed\fR script.
+.SP
+.IP "" 0
+\fB--expand-tabs\fR
+.IP "" 2
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+Make output that looks vaguely like an \fBed\fR script but has changes
+in the order they appear in the file.
+.SP
+.IP "" 0
+\fB-F \fIregexp\fB\fR
+.IP "" 2
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches \fIregexp\fR.
+.SP
+.IP "" 0
+\fB--forward-ed\fR
+.IP "" 2
+Make output that looks vaguely like an \fBed\fR script but has changes
+in the order they appear in the file.
+.SP
+.IP "" 0
+\fB-H\fR
+.IP "" 2
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+.SP
+.IP "" 0
+\fB--horizon-lines=\fIlines\fB\fR
+.IP "" 2
+Do not discard the last \fIlines\fR lines of the common prefix
+and the first \fIlines\fR lines of the common suffix.
+.SP
+.IP "" 0
+\fB-i\fR
+.IP "" 2
+Ignore changes in case; consider upper- and lower-case letters
+equivalent.
+.SP
+.IP "" 0
+\fB-I \fIregexp\fB\fR
+.IP "" 2
+Ignore changes that just insert or delete lines that match \fIregexp\fR.
+.SP
+.IP "" 0
+\fB--ifdef=\fIname\fB\fR
+.IP "" 2
+Make merged if-then-else output using \fIname\fR.
+.SP
+.IP "" 0
+\fB--ignore-all-space\fR
+.IP "" 2
+Ignore white space when comparing lines.
+.SP
+.IP "" 0
+\fB--ignore-blank-lines\fR
+.IP "" 2
+Ignore changes that just insert or delete blank lines.
+.SP
+.IP "" 0
+\fB--ignore-case\fR
+.IP "" 2
+Ignore changes in case; consider upper- and lower-case to be the same.
+.SP
+.IP "" 0
+\fB--ignore-matching-lines=\fIregexp\fB\fR
+.IP "" 2
+Ignore changes that just insert or delete lines that match \fIregexp\fR.
+.SP
+.IP "" 0
+\fB--ignore-space-change\fR
+.IP "" 2
+Ignore trailing white space and consider all other sequences of one or
+more white space characters to be equivalent.
+.SP
+.IP "" 0
+\fB--initial-tab\fR
+.IP "" 2
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+.SP
+.IP "" 0
+\fB-L \fIlabel\fB\fR
+.IP "" 2
+Use \fIlabel\fR instead of the file name in the context format
+and unified format headers.
+.SP
+.IP "" 0
+\fB--label=\fIlabel\fB\fR
+.IP "" 2
+Use \fIlabel\fR instead of the file name in the context format
+and unified format headers.
+.SP
+.IP "" 0
+\fB--left-column\fR
+.IP "" 2
+Print only the left column of two common lines in side by side format.
+.SP
+.IP "" 0
+\fB--line-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output all input lines in if-then-else format.
+see node `Line formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB--minimal\fR
+.IP "" 2
+Change the algorithm to perhaps find a smaller set of changes. This
+makes \fBdiff\fR slower (sometimes much slower).
+.SP
+.IP "" 0
+\fB-n\fR
+.IP "" 2
+Output RCS-format diffs; like \fB-f\fR except that each command
+specifies the number of lines affected.
+.SP
+.IP "" 0
+\fB-N\fR
+.IP "" 2
+.IP "" 0
+\fB--new-file\fR
+.IP "" 2
+In directory comparison, if a file is found in only one directory,
+treat it as present but empty in the other directory.
+.SP
+.IP "" 0
+\fB--new-group-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output a group of lines taken from just the second
+file in if-then-else format. see node `Line group formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB--new-line-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output a line taken from just the second file in
+if-then-else format. see node `Line formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB--old-group-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output a group of lines taken from just the first
+file in if-then-else format. see node `Line group formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB--old-line-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output a line taken from just the first file in
+if-then-else format. see node `Line formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-p\fR
+.IP "" 2
+Show which C function each change is in.
+.SP
+.IP "" 0
+\fB--rcs\fR
+.IP "" 2
+Output RCS-format diffs; like \fB-f\fR except that each command
+specifies the number of lines affected.
+.SP
+.IP "" 0
+\fB--report-identical-files\fR
+.IP "" 2
+.IP "" 0
+\fB-s\fR
+.IP "" 2
+Report when two files are the same.
+.SP
+.IP "" 0
+\fB--show-c-function\fR
+.IP "" 2
+Show which C function each change is in.
+.SP
+.IP "" 0
+\fB--show-function-line=\fIregexp\fB\fR
+.IP "" 2
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches \fIregexp\fR.
+.SP
+.IP "" 0
+\fB--side-by-side\fR
+.IP "" 2
+Use the side by side output format.
+.SP
+.IP "" 0
+\fB--speed-large-files\fR
+.IP "" 2
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+.SP
+.IP "" 0
+\fB--suppress-common-lines\fR
+.IP "" 2
+Do not print common lines in side by side format.
+.SP
+.IP "" 0
+\fB-t\fR
+.IP "" 2
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+.SP
+.IP "" 0
+\fB-T\fR
+.IP "" 2
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+.SP
+.IP "" 0
+\fB--text\fR
+.IP "" 2
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+.SP
+.IP "" 0
+\fB-u\fR
+.IP "" 2
+Use the unified output format.
+.SP
+.IP "" 0
+\fB--unchanged-group-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output a group of common lines taken from both files
+in if-then-else format. see node `Line group formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB--unchanged-line-format=\fIformat\fB\fR
+.IP "" 2
+Use \fIformat\fR to output a line common to both files in if-then-else
+format. see node `Line formats\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-U \fIlines\fB\fR
+.IP "" 2
+.IP "" 0
+\fB--unified\fR[\fB=\fIlines\fB\fR]\fB\fR
+.IP "" 2
+Use the unified output format, showing \fIlines\fR (an integer) lines of
+context, or three if \fIlines\fR is not given.
+For proper operation, \fBpatch\fR typically needs at least two lines of
+context.
+.SP
+.IP "" 0
+\fB-w\fR
+.IP "" 2
+Ignore white space when comparing lines.
+.SP
+.IP "" 0
+\fB-W \fIcolumns\fB\fR
+.IP "" 2
+.IP "" 0
+\fB--width=\fIcolumns\fB\fR
+.IP "" 2
+Use an output width of \fIcolumns\fR in side by side format.
+.SP
+.IP "" 0
+\fB-y\fR
+.IP "" 2
+Use the side by side output format.
+.SP
+.SH "Line group formats"
+.SP
+Line group formats let you specify formats suitable for many
+applications that allow if-then-else input, including programming
+languages and text formatting languages. A line group format specifies
+the output format for a contiguous group of similar lines.
+.SP
+For example, the following command compares the TeX file \fBmyfile\fR
+with the original version from the repository,
+and outputs a merged file in which old regions are
+surrounded by \fB\\begin{em}\fR-\fB\\end{em}\fR lines, and new
+regions are surrounded by \fB\\begin{bf}\fR-\fB\\end{bf}\fR lines.
+.SP
+.PD 0
+.SP
+.IP "" 2
+cvs diff \\
+.IP "" 2
+ --old-group-format=\(aq\\begin{em}
+.IP "" 2
+%<\\end{em}
+.IP "" 2
+\(aq \\
+.IP "" 2
+ --new-group-format=\(aq\\begin{bf}
+.IP "" 2
+%>\\end{bf}
+.IP "" 2
+\(aq \\
+.IP "" 2
+ myfile
+
+.PD
+.IP "" 0
+.SP
+The following command is equivalent to the above example, but it is a
+little more verbose, because it spells out the default line group formats.
+.SP
+.PD 0
+.SP
+.IP "" 2
+cvs diff \\
+.IP "" 2
+ --old-group-format=\(aq\\begin{em}
+.IP "" 2
+%<\\end{em}
+.IP "" 2
+\(aq \\
+.IP "" 2
+ --new-group-format=\(aq\\begin{bf}
+.IP "" 2
+%>\\end{bf}
+.IP "" 2
+\(aq \\
+.IP "" 2
+ --unchanged-group-format=\(aq%=\(aq \\
+.IP "" 2
+ --changed-group-format=\(aq\\begin{em}
+.IP "" 2
+%<\\end{em}
+.IP "" 2
+\\begin{bf}
+.IP "" 2
+%>\\end{bf}
+.IP "" 2
+\(aq \\
+.IP "" 2
+ myfile
+
+.PD
+.IP "" 0
+.SP
+Here is a more advanced example, which outputs a diff listing with
+headers containing line numbers in a \`\`plain English\(aq\(aq style.
+.SP
+.PD 0
+.SP
+.IP "" 2
+cvs diff \\
+.IP "" 2
+ --unchanged-group-format=\(aq\(aq \\
+.IP "" 2
+ --old-group-format=\(aq-------- %dn line%(n=1?:s) deleted at %df:
+.IP "" 2
+%<\(aq \\
+.IP "" 2
+ --new-group-format=\(aq-------- %dN line%(N=1?:s) added after %de:
+.IP "" 2
+%>\(aq \\
+.IP "" 2
+ --changed-group-format=\(aq-------- %dn line%(n=1?:s) changed at %df:
+.IP "" 2
+%<-------- to:
+.IP "" 2
+%>\(aq \\
+.IP "" 2
+ myfile
+
+.PD
+.IP "" 0
+.SP
+To specify a line group format, use one of the options
+listed below. You can specify up to four line group formats, one for
+each kind of line group. You should quote \fIformat\fR, because it
+typically contains shell metacharacters.
+.SP
+.IP "" 0
+\fB--old-group-format=\fIformat\fB\fR
+.IP "" 2
+These line groups are hunks containing only lines from the first file.
+The default old group format is the same as the changed group format if
+it is specified; otherwise it is a format that outputs the line group as-is.
+.SP
+.IP "" 0
+\fB--new-group-format=\fIformat\fB\fR
+.IP "" 2
+These line groups are hunks containing only lines from the second
+file. The default new group format is same as the changed group
+format if it is specified; otherwise it is a format that outputs the
+line group as-is.
+.SP
+.IP "" 0
+\fB--changed-group-format=\fIformat\fB\fR
+.IP "" 2
+These line groups are hunks containing lines from both files. The
+default changed group format is the concatenation of the old and new
+group formats.
+.SP
+.IP "" 0
+\fB--unchanged-group-format=\fIformat\fB\fR
+.IP "" 2
+These line groups contain lines common to both files. The default
+unchanged group format is a format that outputs the line group as-is.
+.SP
+In a line group format, ordinary characters represent themselves;
+conversion specifications start with \fB%\fR and have one of the
+following forms.
+.SP
+.IP "" 0
+\fB%<\fR
+.IP "" 2
+stands for the lines from the first file, including the trailing newline.
+Each line is formatted according to the old line format (see node `Line formats\(aq in the CVS manual).
+.SP
+.IP "" 0
+\fB%>\fR
+.IP "" 2
+stands for the lines from the second file, including the trailing newline.
+Each line is formatted according to the new line format.
+.SP
+.IP "" 0
+\fB%=\fR
+.IP "" 2
+stands for the lines common to both files, including the trailing newline.
+Each line is formatted according to the unchanged line format.
+.SP
+.IP "" 0
+\fB%%\fR
+.IP "" 2
+stands for \fB%\fR.
+.SP
+.IP "" 0
+\fB%c\(aq\fIC\fB\(aq\fR
+.IP "" 2
+where \fIC\fR is a single character, stands for \fIC\fR.
+\fIC\fR may not be a backslash or an apostrophe.
+For example, \fB%c\(aq:\(aq\fR stands for a colon, even inside
+the then-part of an if-then-else format, which a colon would
+normally terminate.
+.SP
+.IP "" 0
+\fB%c\(aq\\\fIO\fB\(aq\fR
+.IP "" 2
+where \fIO\fR is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code \fIO\fR.
+For example, \fB%c\(aq\\0\(aq\fR stands for a null character.
+.SP
+.IP "" 0
+\fB\fIF\fB\fIn\fB\fR
+.IP "" 2
+where \fIF\fR is a \fBprintf\fR conversion specification and \fIn\fR is one
+of the following letters, stands for \fIn\fR\(aqs value formatted with \fIF\fR.
+.SP
+.IP "" 2
+\fBe\fR
+.IP "" 4
+The line number of the line just before the group in the old file.
+.SP
+.IP "" 2
+\fBf\fR
+.IP "" 4
+The line number of the first line in the group in the old file;
+equals \fIe\fR + 1.
+.SP
+.IP "" 2
+\fBl\fR
+.IP "" 4
+The line number of the last line in the group in the old file.
+.SP
+.IP "" 2
+\fBm\fR
+.IP "" 4
+The line number of the line just after the group in the old file;
+equals \fIl\fR + 1.
+.SP
+.IP "" 2
+\fBn\fR
+.IP "" 4
+The number of lines in the group in the old file; equals \fIl\fR - \fIf\fR + 1.
+.SP
+.IP "" 2
+\fBE, F, L, M, N\fR
+.IP "" 4
+Likewise, for lines in the new file.
+.SP
+.SP
+The \fBprintf\fR conversion specification can be \fB%d\fR,
+\fB%o\fR, \fB%x\fR, or \fB%X\fR, specifying decimal, octal,
+lower case hexadecimal, or upper case hexadecimal output
+respectively. After the \fB%\fR the following options can appear in
+sequence: a \fB-\fR specifying left-justification; an integer
+specifying the minimum field width; and a period followed by an
+optional integer specifying the minimum number of digits.
+For example, \fB%5dN\fR prints the number of new lines in the group
+in a field of width 5 characters, using the \fBprintf\fR format \fB"%5d"\fR.
+.SP
+.IP "" 0
+\fB(\fIA\fB=\fIB\fB?\fIT\fB:\fIE\fB)\fR
+.IP "" 2
+If \fIA\fR equals \fIB\fR then \fIT\fR else \fIE\fR.
+\fIA\fR and \fIB\fR are each either a decimal constant
+or a single letter interpreted as above.
+This format spec is equivalent to \fIT\fR if
+\fIA\fR\(aqs value equals \fIB\fR\(aqs; otherwise it is equivalent to \fIE\fR.
+.SP
+For example, \fB%(N=0?no:%dN) line%(N=1?:s)\fR is equivalent to
+\fBno lines\fR if \fIN\fR (the number of lines in the group in the
+new file) is 0, to \fB1 line\fR if \fIN\fR is 1, and to \fB%dN lines\fR
+otherwise.
+.SP
+.SH "Line formats"
+.SP
+Line formats control how each line taken from an input file is
+output as part of a line group in if-then-else format.
+.SP
+For example, the following command outputs text with a one-column
+change indicator to the left of the text. The first column of output
+is \fB-\fR for deleted lines, \fB|\fR for added lines, and a space
+for unchanged lines. The formats contain newline characters where
+newlines are desired on output.
+.SP
+.PD 0
+.SP
+.IP "" 2
+cvs diff \\
+.IP "" 2
+ --old-line-format=\(aq-%l
+.IP "" 2
+\(aq \\
+.IP "" 2
+ --new-line-format=\(aq|%l
+.IP "" 2
+\(aq \\
+.IP "" 2
+ --unchanged-line-format=\(aq %l
+.IP "" 2
+\(aq \\
+.IP "" 2
+ myfile
+
+.PD
+.IP "" 0
+.SP
+To specify a line format, use one of the following options. You should
+quote \fIformat\fR, since it often contains shell metacharacters.
+.SP
+.IP "" 0
+\fB--old-line-format=\fIformat\fB\fR
+.IP "" 2
+formats lines just from the first file.
+.SP
+.IP "" 0
+\fB--new-line-format=\fIformat\fB\fR
+.IP "" 2
+formats lines just from the second file.
+.SP
+.IP "" 0
+\fB--unchanged-line-format=\fIformat\fB\fR
+.IP "" 2
+formats lines common to both files.
+.SP
+.IP "" 0
+\fB--line-format=\fIformat\fB\fR
+.IP "" 2
+formats all lines; in effect, it sets all three above options simultaneously.
+.SP
+In a line format, ordinary characters represent themselves;
+conversion specifications start with \fB%\fR and have one of the
+following forms.
+.SP
+.IP "" 0
+\fB%l\fR
+.IP "" 2
+stands for the contents of the line, not counting its trailing
+newline (if any). This format ignores whether the line is incomplete.
+.SP
+.IP "" 0
+\fB%L\fR
+.IP "" 2
+stands for the contents of the line, including its trailing newline
+(if any). If a line is incomplete, this format preserves its
+incompleteness.
+.SP
+.IP "" 0
+\fB%%\fR
+.IP "" 2
+stands for \fB%\fR.
+.SP
+.IP "" 0
+\fB%c\(aq\fIC\fB\(aq\fR
+.IP "" 2
+where \fIC\fR is a single character, stands for \fIC\fR.
+\fIC\fR may not be a backslash or an apostrophe.
+For example, \fB%c\(aq:\(aq\fR stands for a colon.
+.SP
+.IP "" 0
+\fB%c\(aq\\\fIO\fB\(aq\fR
+.IP "" 2
+where \fIO\fR is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code \fIO\fR.
+For example, \fB%c\(aq\\0\(aq\fR stands for a null character.
+.SP
+.IP "" 0
+\fB\fIF\fBn\fR
+.IP "" 2
+where \fIF\fR is a \fBprintf\fR conversion specification,
+stands for the line number formatted with \fIF\fR.
+For example, \fB%.5dn\fR prints the line number using the
+\fBprintf\fR format \fB"%.5d"\fR. see node `Line group formats\(aq in the CVS manual, for
+more about printf conversion specifications.
+.SP
+.SP
+The default line format is \fB%l\fR followed by a newline character.
+.SP
+If the input contains tab characters and it is important that they line
+up on output, you should ensure that \fB%l\fR or \fB%L\fR in a line
+format is just after a tab stop (e.g. by preceding \fB%l\fR or
+\fB%L\fR with a tab character), or you should use the \fB-t\fR or
+\fB--expand-tabs\fR option.
+.SP
+Taken together, the line and line group formats let you specify many
+different formats. For example, the following command uses a format
+similar to \fBdiff\fR\(aqs normal format. You can tailor this command
+to get fine control over \fBdiff\fR\(aqs output.
+.SP
+.PD 0
+.SP
+.IP "" 2
+cvs diff \\
+.IP "" 2
+ --old-line-format=\(aq< %l
+.IP "" 2
+\(aq \\
+.IP "" 2
+ --new-line-format=\(aq> %l
+.IP "" 2
+\(aq \\
+.IP "" 2
+ --old-group-format=\(aq%df%(f=l?:,%dl)d%dE
+.IP "" 2
+%<\(aq \\
+.IP "" 2
+ --new-group-format=\(aq%dea%dF%(F=L?:,%dL)
+.IP "" 2
+%>\(aq \\
+.IP "" 2
+ --changed-group-format=\(aq%df%(f=l?:,%dl)c%dF%(F=L?:,%dL)
+.IP "" 2
+%<\(em
+.IP "" 2
+%>\(aq \\
+.IP "" 2
+ --unchanged-group-format=\(aq\(aq \\
+.IP "" 2
+ myfile
+
+.PD
+.IP "" 0
+.SP
+.SH "diff examples"
+.SP
+The following line produces a Unidiff (\fB-u\fR flag)
+between revision 1.14 and 1.19 of
+\fBbackend.c\fR. Due to the \fB-kk\fR flag no
+keywords are substituted, so differences that only depend
+on keyword substitution are ignored.
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs diff -kk -u -r 1.14 -r 1.19 backend.c
+
+.PD
+.IP "" 0
+.SP
+Suppose the experimental branch EXPR1 was based on a
+set of files tagged RELEASE_1_0. To see what has
+happened on that branch, the following can be used:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs diff -r RELEASE_1_0 -r EXPR1
+
+.PD
+.IP "" 0
+.SP
+A command like this can be used to produce a context
+diff between two releases:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs diff -c -r RELEASE_1_0 -r RELEASE_1_1 > diffs
+
+.PD
+.IP "" 0
+.SP
+If you are maintaining ChangeLogs, a command like the following
+just before you commit your changes may help you write
+the ChangeLog entry. All local modifications that have
+not yet been committed will be printed.
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs diff -u | less
+
+.PD
+.IP "" 0
+.SP
+.SH "export"
+.SS "Export sources from CVS, similar to checkout"
+.IX "export (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: export [-flNnR] (-r rev[:date] | -D date) [-k subst] [-d dir] module\&...
+.IP "\(bu" 2
+Requires: repository.
+.IP "\(bu" 2
+Changes: current directory.
+.SP
+This command is a variant of \fBcheckout\fR; use it
+when you want a copy of the source for module without
+the \fBcvs\fR administrative directories. For example, you
+might use \fBexport\fR to prepare source for shipment
+off-site. This command requires that you specify a
+date or tag (with \fB-D\fR or \fB-r\fR), so that you
+can count on reproducing the source you ship to others
+(and thus it always prunes empty directories).
+.SP
+One often would like to use \fB-kv\fR with \fBcvs
+export\fR. This causes any keywords to be
+expanded such that an import done at some other site
+will not lose the keyword revision information. But be
+aware that doesn\(aqt handle an export containing binary
+files correctly. Also be aware that after having used
+\fB-kv\fR, one can no longer use the \fBident\fR
+command (which is part of the \fBrcs\fR suite\(emsee
+ident(1)) which looks for keyword strings. If
+you want to be able to use \fBident\fR you must not
+use \fB-kv\fR.
+.SP
+.SH "export options"
+.SP
+These standard options are supported by \fBexport\fR
+(see node `Common options\(aq in the CVS manual, for a complete description of
+them):
+.SP
+.IP "" 0
+\fB-D \fIdate\fB\fR
+.IP "" 2
+Use the most recent revision no later than \fIdate\fR.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; run only in current working directory.
+.SP
+.IP "" 0
+\fB-n\fR
+.IP "" 2
+Do not run any checkout program.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Export directories recursively. This is on by default.
+.SP
+.IP "" 0
+\fB-r \fItag\fB[:\fIdate\fB]\fR
+.IP "" 2
+Export the revision specified by \fItag\fR or, when \fIdate\fR is specified
+and \fItag\fR is a branch tag, the version from the branch \fItag\fR as it
+existed on \fIdate\fR. See see node `Common options\(aq in the CVS manual.
+.SP
+In addition, these options (that are common to
+\fBcheckout\fR and \fBexport\fR) are also supported:
+.SP
+.IP "" 0
+\fB-d \fIdir\fB\fR
+.IP "" 2
+Create a directory called \fIdir\fR for the working
+files, instead of using the module name.
+see node `checkout options\(aq in the CVS manual, for complete details on how
+\fBcvs\fR handles this flag.
+.SP
+.IP "" 0
+\fB-k \fIsubst\fB\fR
+.IP "" 2
+Set keyword expansion mode (see node `Substitution modes\(aq in the CVS manual).
+.SP
+.IP "" 0
+\fB-N\fR
+.IP "" 2
+Only useful together with \fB-d \fIdir\fB\fR.
+see node `checkout options\(aq in the CVS manual, for complete details on how
+\fBcvs\fR handles this flag.
+.SP
+.SH "history"
+.SS "Show status of files and users"
+.IX "history (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: history [-report] [-flags] [-options args] [files\&...]
+.IP "\(bu" 2
+Requires: the file \fB$CVSROOT/CVSROOT/history\fR
+.IP "\(bu" 2
+Changes: nothing.
+.SP
+\fBcvs\fR can keep a history log that tracks each use of most \fBcvs\fR
+commands. You can use \fBhistory\fR to display this information in
+various formats.
+.SP
+To enable logging, the \fBLogHistory\fR config option must be set to
+some value other than the empty string and the history file specified by
+the \fBHistoryLogPath\fR option must be writable by all users who may run
+the \fBcvs\fR executable (see node `config\(aq in the CVS manual).
+.SP
+To enable the \fBhistory\fR command, logging must be enabled as above and
+the \fBHistorySearchPath\fR config option (see node `config\(aq in the CVS manual) must be set to
+specify some number of the history logs created thereby and these files must
+be readable by each user who might run the \fBhistory\fR command.
+.SP
+Creating a repository via the \fBcvs init\fR command will enable logging of
+all possible events to a single history log file
+(\fB$CVSROOT/CVSROOT/history\fR) with read and write permissions for all
+users (see node `Creating a repository\(aq in the CVS manual).
+.SP
+\fBNote: \fBhistory\fB uses \fB-f\fB, \fB-l\fB,
+\fB-n\fB, and \fB-p\fB in ways that conflict with the
+normal use inside \fBcvs\fB (see node `Common options\(aq in the CVS manual).\fR
+.SP
+.SH "history options"
+.SP
+Several options (shown above as \fB-report\fR) control what
+kind of report is generated:
+.SP
+.IP "" 0
+\fB-c\fR
+.IP "" 2
+Report on each time commit was used (i.e., each time
+the repository was modified).
+.SP
+.IP "" 0
+\fB-e\fR
+.IP "" 2
+Everything (all record types). Equivalent to
+specifying \fB-x\fR with all record types. Of course,
+\fB-e\fR will also include record types which are
+added in a future version of \fBcvs\fR; if you are
+writing a script which can only handle certain record
+types, you\(aqll want to specify \fB-x\fR.
+.SP
+.IP "" 0
+\fB-m \fImodule\fB\fR
+.IP "" 2
+Report on a particular module. (You can meaningfully
+use \fB-m\fR more than once on the command line.)
+.SP
+.IP "" 0
+\fB-o\fR
+.IP "" 2
+Report on checked-out modules. This is the default report type.
+.SP
+.IP "" 0
+\fB-T\fR
+.IP "" 2
+Report on all tags.
+.SP
+.IP "" 0
+\fB-x \fItype\fB\fR
+.IP "" 2
+Extract a particular set of record types \fItype\fR from the \fBcvs\fR
+history. The types are indicated by single letters,
+which you may specify in combination.
+.SP
+Certain commands have a single record type:
+.SP
+.IP "" 2
+\fBF\fR
+.IP "" 4
+release
+.IP "" 2
+\fBO\fR
+.IP "" 4
+checkout
+.IP "" 2
+\fBE\fR
+.IP "" 4
+export
+.IP "" 2
+\fBT\fR
+.IP "" 4
+rtag
+.SP
+One of five record types may result from an update:
+.SP
+.IP "" 2
+\fBC\fR
+.IP "" 4
+A merge was necessary but collisions were
+detected (requiring manual merging).
+.IP "" 2
+\fBG\fR
+.IP "" 4
+A merge was necessary and it succeeded.
+.IP "" 2
+\fBU\fR
+.IP "" 4
+A working file was copied from the repository.
+.IP "" 2
+\fBP\fR
+.IP "" 4
+A working file was patched to match the repository.
+.IP "" 2
+\fBW\fR
+.IP "" 4
+The working copy of a file was deleted during
+update (because it was gone from the repository).
+.SP
+One of three record types results from commit:
+.SP
+.IP "" 2
+\fBA\fR
+.IP "" 4
+A file was added for the first time.
+.IP "" 2
+\fBM\fR
+.IP "" 4
+A file was modified.
+.IP "" 2
+\fBR\fR
+.IP "" 4
+A file was removed.
+.SP
+The options shown as \fB-flags\fR constrain or expand
+the report without requiring option arguments:
+.SP
+.IP "" 0
+\fB-a\fR
+.IP "" 2
+Show data for all users (the default is to show data
+only for the user executing \fBhistory\fR).
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Show last modification only.
+.SP
+.IP "" 0
+\fB-w\fR
+.IP "" 2
+Show only the records for modifications done from the
+same working directory where \fBhistory\fR is
+executing.
+.SP
+The options shown as \fB-options \fIargs\fB\fR constrain the report
+based on an argument:
+.SP
+.IP "" 0
+\fB-b \fIstr\fB\fR
+.IP "" 2
+Show data back to a record containing the string
+\fIstr\fR in either the module name, the file name, or
+the repository path.
+.SP
+.IP "" 0
+\fB-D \fIdate\fB\fR
+.IP "" 2
+Show data since \fIdate\fR. This is slightly different
+from the normal use of \fB-D \fIdate\fB\fR, which
+selects the newest revision older than \fIdate\fR.
+.SP
+.IP "" 0
+\fB-f \fIfile\fB\fR
+.IP "" 2
+Show data for a particular file
+(you can specify several \fB-f\fR options on the same command line).
+This is equivalent to specifying the file on the command line.
+.SP
+.IP "" 0
+\fB-n \fImodule\fB\fR
+.IP "" 2
+Show data for a particular module
+(you can specify several \fB-n\fR options on the same command line).
+.SP
+.IP "" 0
+\fB-p \fIrepository\fB\fR
+.IP "" 2
+Show data for a particular source repository (you
+can specify several \fB-p\fR options on the same command
+line).
+.SP
+.IP "" 0
+\fB-r \fIrev\fB\fR
+.IP "" 2
+Show records referring to revisions since the revision
+or tag named \fIrev\fR appears in individual \fBrcs\fR
+files. Each \fBrcs\fR file is searched for the revision or
+tag.
+.SP
+.IP "" 0
+\fB-t \fItag\fB\fR
+.IP "" 2
+Show records since tag \fItag\fR was last added to the
+history file. This differs from the \fB-r\fR flag
+above in that it reads only the history file, not the
+\fBrcs\fR files, and is much faster.
+.SP
+.IP "" 0
+\fB-u \fIname\fB\fR
+.IP "" 2
+Show records for user \fIname\fR.
+.SP
+.IP "" 0
+\fB-z \fItimezone\fB\fR
+.IP "" 2
+Show times in the selected records using the specified
+time zone instead of UTC.
+.SP
+.SH "import"
+.SS "Import sources into CVS, using vendor branches"
+.IX "import (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: import [-options] repository vendortag releasetag\&...
+.IP "\(bu" 2
+Requires: Repository, source distribution directory.
+.IP "\(bu" 2
+Changes: repository.
+.SP
+Use \fBimport\fR to incorporate an entire source
+distribution from an outside source (e.g., a source
+vendor) into your source repository directory. You can
+use this command both for initial creation of a
+repository, and for wholesale updates to the module
+from the outside source. see node `Tracking sources\(aq in the CVS manual, for
+a discussion on this subject.
+.SP
+The \fIrepository\fR argument gives a directory name
+(or a path to a directory) under the \fBcvs\fR root directory
+for repositories; if the directory did not exist,
+import creates it.
+.SP
+When you use import for updates to source that has been
+modified in your source repository (since a prior
+import), it will notify you of any files that conflict
+in the two branches of development; use \fBcheckout
+-j\fR to reconcile the differences, as import instructs
+you to do.
+.SP
+If \fBcvs\fR decides a file should be ignored
+(see node `cvsignore\(aq in the CVS manual), it does not import it and prints
+\fBI \fR followed by the filename (see node `import output\(aq in the CVS manual, for a
+complete description of the output).
+.SP
+If the file \fB$CVSROOT/CVSROOT/cvswrappers\fR exists,
+any file whose names match the specifications in that
+file will be treated as packages and the appropriate
+filtering will be performed on the file/directory
+before being imported. see node `Wrappers\(aq in the CVS manual.
+.SP
+The outside source is saved in a first-level
+branch, by default 1.1.1. Updates are leaves of this
+branch; for example, files from the first imported
+collection of source will be revision 1.1.1.1, then
+files from the first imported update will be revision
+1.1.1.2, and so on.
+.SP
+At least three arguments are required.
+\fIrepository\fR is needed to identify the collection
+of source. \fIvendortag\fR is a tag for the entire
+branch (e.g., for 1.1.1). You must also specify at
+least one \fIreleasetag\fR to uniquely identify the files at
+the leaves created each time you execute \fBimport\fR. The
+\fIreleasetag\fR should be new, not previously existing in the
+repository file, and uniquely identify the imported release,
+.SP
+Note that \fBimport\fR does \fInot\fR change the
+directory in which you invoke it. In particular, it
+does not set up that directory as a \fBcvs\fR working
+directory; if you want to work with the sources import
+them first and then check them out into a different
+directory (see node `Getting the source\(aq in the CVS manual).
+.SP
+.SH "import options"
+.SP
+This standard option is supported by \fBimport\fR
+(see node `Common options\(aq in the CVS manual, for a complete description):
+.SP
+.IP "" 0
+\fB-m \fImessage\fB\fR
+.IP "" 2
+Use \fImessage\fR as log information, instead of
+invoking an editor.
+.SP
+There are the following additional special options.
+.SP
+.IP "" 0
+\fB-b \fIbranch\fB\fR
+.IP "" 2
+See see node `Multiple vendor branches\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-k \fIsubst\fB\fR
+.IP "" 2
+Indicate the keyword expansion mode desired. This
+setting will apply to all files created during the
+import, but not to any files that previously existed in
+the repository. See see node `Substitution modes\(aq in the CVS manual, for a
+list of valid \fB-k\fR settings.
+.SP
+.IP "" 0
+\fB-I \fIname\fB\fR
+.IP "" 2
+Specify file names that should be ignored during
+import. You can use this option repeatedly. To avoid
+ignoring any files at all (even those ignored by
+default), specify \`-I !\(aq.
+.SP
+\fIname\fR can be a file name pattern of the same type
+that you can specify in the \fB.cvsignore\fR file.
+see node `cvsignore\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-W \fIspec\fB\fR
+.IP "" 2
+Specify file names that should be filtered during
+import. You can use this option repeatedly.
+.SP
+\fIspec\fR can be a file name pattern of the same type
+that you can specify in the \fB.cvswrappers\fR
+file. see node `Wrappers\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-X\fR
+.IP "" 2
+Modify the algorithm used by \fBcvs\fR when importing new files
+so that new files do not immediately appear on the main trunk.
+.SP
+Specifically, this flag causes \fBcvs\fR to mark new files as
+if they were deleted on the main trunk, by taking the following
+steps for each file in addition to those normally taken on import:
+creating a new revision on the main trunk indicating that
+the new file is \fBdead\fR, resetting the new file\(aqs default branch,
+and placing the file in the Attic (see node `Attic\(aq in the CVS manual) directory.
+.SP
+Use of this option can be forced on a repository-wide basis
+by setting the \fBImportNewFilesToVendorBranchOnly\fR option in
+CVSROOT/config (see node `config\(aq in the CVS manual).
+.SP
+.SH "import output"
+.SP
+\fBimport\fR keeps you informed of its progress by printing a line
+for each file, preceded by one character indicating the status of the file:
+.SP
+.IP "" 0
+\fBU \fIfile\fB\fR
+.IP "" 2
+The file already exists in the repository and has not been locally
+modified; a new revision has been created (if necessary).
+.SP
+.IP "" 0
+\fBN \fIfile\fB\fR
+.IP "" 2
+The file is a new file which has been added to the repository.
+.SP
+.IP "" 0
+\fBC \fIfile\fB\fR
+.IP "" 2
+The file already exists in the repository but has been locally modified;
+you will have to merge the changes.
+.SP
+.IP "" 0
+\fBI \fIfile\fB\fR
+.IP "" 2
+The file is being ignored (see node `cvsignore\(aq in the CVS manual).
+.SP
+.IX "Symbolic link, importing"
+.IX "Link, symbolic, importing"
+.IP "" 0
+\fBL \fIfile\fB\fR
+.IP "" 2
+The file is a symbolic link; \fBcvs import\fR ignores symbolic links.
+People periodically suggest that this behavior should
+be changed, but if there is a consensus on what it
+should be changed to, it is not apparent.
+(Various options in the \fBmodules\fR file can be used
+to recreate symbolic links on checkout, update, etc.;
+see node `modules\(aq in the CVS manual.)
+.SP
+.SH "import examples"
+.SP
+See see node `Tracking sources\(aq in the CVS manual, and see node `From files\(aq in the CVS manual.
+.SP
+.SH "log"
+.SS "Print out log information for files"
+.IX "log (subcommand)"
+.SP
+.IP "\(bu" 2
+Synopsis: log [options] [files\&...]
+.IP "\(bu" 2
+Requires: repository, working directory.
+.IP "\(bu" 2
+Changes: nothing.
+.SP
+Display log information for files. \fBlog\fR used to
+call the \fBrcs\fR utility \fBrlog\fR. Although this
+is no longer true in the current sources, this history
+determines the format of the output and the options,
+which are not quite in the style of the other \fBcvs\fR
+commands.
+.SP
+.IX "Timezone, in output"
+.IX "Zone, time, in output"
+The output includes the location of the \fBrcs\fR file,
+the \fIhead\fR revision (the latest revision on the
+trunk), all symbolic names (tags) and some other
+things. For each revision, the revision number, the
+date, the author, the number of lines added/deleted, the commitid
+and the log message are printed. All dates are displayed
+in local time at the client. This is typically specified in
+the \fB$TZ\fR environment variable, which can be set to
+govern how \fBlog\fR displays dates.
+.SP
+\fBNote: \fBlog\fB uses \fB-R\fB in a way that conflicts
+with the normal use inside \fBcvs\fB (see node `Common options\(aq in the CVS manual).\fR
+.SP
+.SH "log options"
+.SP
+By default, \fBlog\fR prints all information that is
+available. All other options restrict the output. Note that the revision
+selection options (\fB-d\fR, \fB-r\fR, \fB-s\fR, and \fB-w\fR) have no
+effect, other than possibly causing a search for files in Attic directories,
+when used in conjunction with the options that restrict the output to only
+\fBlog\fR header fields (\fB-b\fR, \fB-h\fR, \fB-R\fR, and \fB-t\fR)
+unless the \fB-S\fR option is also specified.
+.SP
+.IP "" 0
+\fB-b\fR
+.IP "" 2
+Print information about the revisions on the default
+branch, normally the highest branch on the trunk.
+.SP
+.IP "" 0
+\fB-d \fIdates\fB\fR
+.IP "" 2
+Print information about revisions with a checkin
+date/time in the range given by the
+semicolon-separated list of dates. The date formats
+accepted are those accepted by the \fB-D\fR option to
+many other \fBcvs\fR commands (see node `Common options\(aq in the CVS manual).
+Dates can be combined into ranges as follows:
+.SP
+.IP "" 2
+\fB\fId1\fB<\fId2\fB\fR
+.IP "" 4
+.IP "" 2
+\fB\fId2\fB>\fId1\fB\fR
+.IP "" 4
+Select the revisions that were deposited between
+\fId1\fR and \fId2\fR.
+.SP
+.IP "" 2
+\fB<\fId\fB\fR
+.IP "" 4
+.IP "" 2
+\fB\fId\fB>\fR
+.IP "" 4
+Select all revisions dated \fId\fR or earlier.
+.SP
+.IP "" 2
+\fB\fId\fB<\fR
+.IP "" 4
+.IP "" 2
+\fB>\fId\fB\fR
+.IP "" 4
+Select all revisions dated \fId\fR or later.
+.SP
+.IP "" 2
+\fB\fId\fB\fR
+.IP "" 4
+Select the single, latest revision dated \fId\fR or
+earlier.
+.SP
+The \fB>\fR or \fB<\fR characters may be followed by
+\fB=\fR to indicate an inclusive range rather than an
+exclusive one.
+.SP
+Note that the separator is a semicolon (;).
+.SP
+.IP "" 0
+\fB-h\fR
+.IP "" 2
+Print only the name of the \fBrcs\fR file, name
+of the file in the working directory, head,
+default branch, access list, locks, symbolic names, and
+suffix.
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; run only in current working directory. (Default
+is to run recursively).
+.SP
+.IP "" 0
+\fB-N\fR
+.IP "" 2
+Do not print the list of tags for this file. This
+option can be very useful when your site uses a lot of
+tags, so rather than "more"\(aqing over 3 pages of tag
+information, the log information is presented without
+tags at all.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Print only the name of the \fBrcs\fR file.
+.SP
+.IP "" 0
+\fB-r\fIrevisions\fB\fR
+.IP "" 2
+Print information about revisions given in the
+comma-separated list \fIrevisions\fR of revisions and
+ranges. The following table explains the available
+range formats:
+.SP
+.IP "" 2
+\fB\fIrev1\fB:\fIrev2\fB\fR
+.IP "" 4
+Revisions \fIrev1\fR to \fIrev2\fR (which must be on
+the same branch).
+.SP
+.IP "" 2
+\fB\fIrev1\fB::\fIrev2\fB\fR
+.IP "" 4
+The same, but excluding \fIrev1\fR.
+.SP
+.IP "" 2
+\fB:\fIrev\fB\fR
+.IP "" 4
+.IP "" 2
+\fB::\fIrev\fB\fR
+.IP "" 4
+Revisions from the beginning of the branch up to
+and including \fIrev\fR.
+.SP
+.IP "" 2
+\fB\fIrev\fB:\fR
+.IP "" 4
+Revisions starting with \fIrev\fR to the end of the
+branch containing \fIrev\fR.
+.SP
+.IP "" 2
+\fB\fIrev\fB::\fR
+.IP "" 4
+Revisions starting just after \fIrev\fR to the end of the
+branch containing \fIrev\fR.
+.SP
+.IP "" 2
+\fB\fIbranch\fB\fR
+.IP "" 4
+An argument that is a branch means all revisions on
+that branch.
+.SP
+.IP "" 2
+\fB\fIbranch1\fB:\fIbranch2\fB\fR
+.IP "" 4
+.IP "" 2
+\fB\fIbranch1\fB::\fIbranch2\fB\fR
+.IP "" 4
+A range of branches means all revisions
+on the branches in that range.
+.SP
+.IP "" 2
+\fB\fIbranch\fB.\fR
+.IP "" 4
+The latest revision in \fIbranch\fR.
+.SP
+A bare \fB-r\fR with no revisions means the latest
+revision on the default branch, normally the trunk.
+There can be no space between the \fB-r\fR option and
+its argument.
+.SP
+.IP "" 0
+\fB-S\fR
+.IP "" 2
+Suppress the header if no revisions are selected.
+.SP
+.IP "" 0
+\fB-s \fIstates\fB\fR
+.IP "" 2
+Print information about revisions whose state
+attributes match one of the states given in the
+comma-separated list \fIstates\fR. Individual states may
+be any text string, though \fBcvs\fR commonly only uses two
+states, \fBExp\fR and \fBdead\fR. See see node `admin options\(aq in the CVS manual
+for more information.
+.SP
+.IP "" 0
+\fB-t\fR
+.IP "" 2
+Print the same as \fB-h\fR, plus the descriptive text.
+.SP
+.IP "" 0
+\fB-w\fIlogins\fB\fR
+.IP "" 2
+Print information about revisions checked in by users
+with login names appearing in the comma-separated list
+\fIlogins\fR. If \fIlogins\fR is omitted, the user\(aqs
+login is assumed. There can be no space between the
+\fB-w\fR option and its argument.
+.SP
+\fBlog\fR prints the intersection of the revisions
+selected with the options \fB-d\fR, \fB-s\fR, and
+\fB-w\fR, intersected with the union of the revisions
+selected by \fB-b\fR and \fB-r\fR.
+.SP
+.SH "log examples"
+.SP
+.IX "Timezone, in output"
+.IX "Zone, time, in output"
+Since \fBlog\fR shows dates in local time,
+you might want to see them in Coordinated Universal Time (UTC) or
+some other timezone.
+To do this you can set your \fB$TZ\fR environment
+variable before invoking \fBcvs\fR:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ TZ=UTC cvs log foo.c
+.IP "" 2
+$ TZ=EST cvs log bar.c
+
+.PD
+.IP "" 0
+.SP
+(If you are using a \fBcsh\fR-style shell, like \fBtcsh\fR,
+you would need to prefix the examples above with \fBenv\fR.)
+.SP
+.SH "ls & rls"
+.IX "ls (subcommand)"
+.IX "rls (subcommand)"
+.SP
+.IP "\(bu" 2
+ls [-e | -l] [-RP] [-r tag[:date]] [-D date] [path\&...]
+.IP "\(bu" 2
+Requires: repository for \fBrls\fR, repository & working directory for
+\fBls\fR.
+.IP "\(bu" 2
+Changes: nothing.
+.IP "\(bu" 2
+Synonym: \fBdir\fR & \fBlist\fR are synonyms for \fBls\fR and \fBrdir\fR
+& \fBrlist\fR are synonyms for \fBrls\fR.
+.SP
+The \fBls\fR and \fBrls\fR commands are used to list
+files and directories in the repository.
+.SP
+By default \fBls\fR lists the files and directories
+that belong in your working directory, what would be
+there after an \fBupdate\fR.
+.SP
+By default \fBrls\fR lists the files and directories
+on the tip of the trunk in the topmost directory of the
+repository.
+.SP
+Both commands accept an optional list of file and
+directory names, relative to the working directory for
+\fBls\fR and the topmost directory of the repository
+for \fBrls\fR. Neither is recursive by default.
+.SP
+.SH "ls & rls options"
+.SP
+These standard options are supported by \fBls\fR & \fBrls\fR:
+.SP
+.IP "" 0
+\fB-d\fR
+.IP "" 2
+Show dead revisions (with tag when specified).
+.SP
+.IP "" 0
+\fB-e\fR
+.IP "" 2
+Display in CVS/Entries format. This format is meant to remain easily parsable
+by automation.
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Display all details.
+.SP
+.IP "" 0
+\fB-P\fR
+.IP "" 2
+Don\(aqt list contents of empty directories when recursing.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+List recursively.
+.SP
+.IP "" 0
+\fB-r \fItag\fB[:\fIdate\fB]\fR
+.IP "" 2
+Show files specified by \fItag\fR or, when \fIdate\fR is specified
+and \fItag\fR is a branch tag, the version from the branch \fItag\fR as it
+existed on \fIdate\fR. See see node `Common options\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-D \fIdate\fB\fR
+.IP "" 2
+Show files from date.
+.SP
+.SH "rls examples"
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs rls
+.IP "" 2
+cvs rls: Listing module: \`.\(aq
+.IP "" 2
+CVSROOT
+.IP "" 2
+first-dir
+
+.PD
+.IP "" 0
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs rls CVSROOT
+.IP "" 2
+cvs rls: Listing module: \`CVSROOT\(aq
+.IP "" 2
+checkoutlist
+.IP "" 2
+commitinfo
+.IP "" 2
+config
+.IP "" 2
+cvswrappers
+.IP "" 2
+loginfo
+.IP "" 2
+modules
+.IP "" 2
+notify
+.IP "" 2
+rcsinfo
+.IP "" 2
+taginfo
+.IP "" 2
+verifymsg
+.SP
+
+.PD
+.IP "" 0
+.SP
+.SH "rdiff"
+.SS "\(aqpatch\(aq format diffs between releases"
+.IX "rdiff (subcommand)"
+.SP
+.IP "\(bu" 2
+rdiff [-flags] [-V vn] (-r tag1[:date1] | -D date1) [-r tag2[:date2] | -D date2] modules\&...
+.IP "\(bu" 2
+Requires: repository.
+.IP "\(bu" 2
+Changes: nothing.
+.IP "\(bu" 2
+Synonym: patch
+.SP
+Builds a Larry Wall format patch(1) file between two
+releases, that can be fed directly into the \fBpatch\fR
+program to bring an old release up-to-date with the new
+release. (This is one of the few \fBcvs\fR commands that
+operates directly from the repository, and doesn\(aqt
+require a prior checkout.) The diff output is sent to
+the standard output device.
+.SP
+You can specify (using the standard \fB-r\fR and
+\fB-D\fR options) any combination of one or two
+revisions or dates. If only one revision or date is
+specified, the patch file reflects differences between
+that revision or date and the current head revisions in
+the \fBrcs\fR file.
+.SP
+Note that if the software release affected is contained
+in more than one directory, then it may be necessary to
+specify the \fB-p\fR option to the \fBpatch\fR command when
+patching the old sources, so that \fBpatch\fR is able to find
+the files that are located in other directories.
+.SP
+.SH "rdiff options"
+.SP
+These standard options are supported by \fBrdiff\fR
+(see node `Common options\(aq in the CVS manual, for a complete description of
+them):
+.SP
+.IP "" 0
+\fB-D \fIdate\fB\fR
+.IP "" 2
+Use the most recent revision no later than \fIdate\fR.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+.SP
+.IP "" 0
+\fB-k \fIkflag\fB\fR
+.IP "" 2
+Process keywords according to \fIkflag\fR. See
+see node `Keyword substitution\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; don\(aqt descend subdirectories.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Examine directories recursively. This option is on by default.
+.SP
+.IP "" 0
+\fB-r \fItag\fB\fR
+.IP "" 2
+Use the revision specified by \fItag\fR, or when \fIdate\fR is specified
+and \fItag\fR is a branch tag, the version from the branch \fItag\fR as it
+existed on \fIdate\fR. See see node `Common options\(aq in the CVS manual.
+.SP
+In addition to the above, these options are available:
+.SP
+.IP "" 0
+\fB-c\fR
+.IP "" 2
+Use the context diff format. This is the default format.
+.SP
+.IP "" 0
+\fB-s\fR
+.IP "" 2
+Create a summary change report instead of a patch. The
+summary includes information about files that were
+changed or added between the releases. It is sent to
+the standard output device. This is useful for finding
+out, for example, which files have changed between two
+dates or revisions.
+.SP
+.IP "" 0
+\fB-t\fR
+.IP "" 2
+A diff of the top two revisions is sent to the standard
+output device. This is most useful for seeing what the
+last change to a file was.
+.SP
+.IP "" 0
+\fB-u\fR
+.IP "" 2
+Use the unidiff format for the context diffs.
+Remember that old versions
+of the \fBpatch\fR program can\(aqt handle the unidiff
+format, so if you plan to post this patch to the net
+you should probably not use \fB-u\fR.
+.SP
+.IP "" 0
+\fB-V \fIvn\fB\fR
+.IP "" 2
+Expand keywords according to the rules current in
+\fBrcs\fR version \fIvn\fR (the expansion format changed with
+\fBrcs\fR version 5). Note that this option is no
+longer accepted. \fBcvs\fR will always expand keywords the
+way that \fBrcs\fR version 5 does.
+.SP
+.SH "rdiff examples"
+.SP
+Suppose you receive mail from \fRfoo@example.net\fR asking for an
+update from release 1.2 to 1.4 of the tc compiler. You
+have no such patches on hand, but with \fBcvs\fR that can
+easily be fixed with a command such as this:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs rdiff -c -r FOO1_2 -r FOO1_4 tc | \\
+.IP "" 2
+$$ Mail -s \(aqThe patches you asked for\(aq foo@example.net
+
+.PD
+.IP "" 0
+.SP
+Suppose you have made release 1.3, and forked a branch
+called \fBR_1_3fix\fR for bug fixes. \fBR_1_3_1\fR
+corresponds to release 1.3.1, which was made some time
+ago. Now, you want to see how much development has been
+done on the branch. This command can be used:
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cvs patch -s -r R_1_3_1 -r R_1_3fix module-name
+.IP "" 2
+cvs rdiff: Diffing module-name
+.IP "" 2
+File ChangeLog,v changed from revision 1.52.2.5 to 1.52.2.6
+.IP "" 2
+File foo.c,v changed from revision 1.52.2.3 to 1.52.2.4
+.IP "" 2
+File bar.h,v changed from revision 1.29.2.1 to 1.2
+
+.PD
+.IP "" 0
+.SP
+.SH "release"
+.SS "Indicate that a Module is no longer in use"
+.IX "release (subcommand)"
+.SP
+.IP "\(bu" 2
+release [-d] directories\&...
+.IP "\(bu" 2
+Requires: Working directory.
+.IP "\(bu" 2
+Changes: Working directory, history log.
+.SP
+This command is meant to safely cancel the effect of
+\fBcvs checkout\fR. Since \fBcvs\fR doesn\(aqt lock files, it
+isn\(aqt strictly necessary to use this command. You can
+always simply delete your working directory, if you
+like; but you risk losing changes you may have
+forgotten, and you leave no trace in the \fBcvs\fR history
+file (see node `history file\(aq in the CVS manual) that you\(aqve abandoned your
+checkout.
+.SP
+Use \fBcvs release\fR to avoid these problems. This
+command checks that no uncommitted changes are
+present; that you are executing it from immediately
+above a \fBcvs\fR working directory; and that the repository
+recorded for your files is the same as the repository
+defined in the module database.
+.SP
+If all these conditions are true, \fBcvs release\fR
+leaves a record of its execution (attesting to your
+intentionally abandoning your checkout) in the \fBcvs\fR
+history log.
+.SP
+.SH "release options"
+.SP
+The \fBrelease\fR command supports one command option:
+.SP
+.IP "" 0
+\fB-d\fR
+.IP "" 2
+Delete your working copy of the file if the release
+succeeds. If this flag is not given your files will
+remain in your working directory.
+.SP
+\fBWARNING: The \fBrelease\fB command deletes
+all directories and files recursively. This
+has the very serious side-effect that any directory
+that you have created inside your checked-out sources,
+and not added to the repository (using the \fBadd\fB
+command; see node `Adding files\(aq in the CVS manual) will be silently deleted\(emeven
+if it is non-empty!\fR
+.SP
+.SH "release output"
+.SP
+Before \fBrelease\fR releases your sources it will
+print a one-line message for any file that is not
+up-to-date.
+.SP
+.IP "" 0
+\fBU \fIfile\fB\fR
+.IP "" 2
+.IP "" 0
+\fBP \fIfile\fB\fR
+.IP "" 2
+There exists a newer revision of this file in the
+repository, and you have not modified your local copy
+of the file (\fBU\fR and \fBP\fR mean the same thing).
+.SP
+.IP "" 0
+\fBA \fIfile\fB\fR
+.IP "" 2
+The file has been added to your private copy of the
+sources, but has not yet been committed to the
+repository. If you delete your copy of the sources
+this file will be lost.
+.SP
+.IP "" 0
+\fBR \fIfile\fB\fR
+.IP "" 2
+The file has been removed from your private copy of the
+sources, but has not yet been removed from the
+repository, since you have not yet committed the
+removal. see node `commit\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fBM \fIfile\fB\fR
+.IP "" 2
+The file is modified in your working directory. There
+might also be a newer revision inside the repository.
+.SP
+.IP "" 0
+\fB? \fIfile\fB\fR
+.IP "" 2
+\fIfile\fR is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for \fBcvs\fR to ignore (see the
+description of the \fB-I\fR option, and
+see node `cvsignore\(aq in the CVS manual). If you remove your working
+sources, this file will be lost.
+.SP
+.SH "release examples"
+.SP
+Release the \fBtc\fR directory, and delete your local working copy
+of the files.
+.SP
+.PD 0
+.SP
+.IP "" 2
+$ cd \&.. # \fRYou must stand immediately above the\fR
+.IP "" 2
+ # \fRsources when you issue \fBcvs release\fR.\fR
+.IP "" 2
+$ cvs release -d tc
+.IP "" 2
+You have [0] altered files in this repository.
+.IP "" 2
+Are you sure you want to release (and delete) directory \`tc\(aq: y
+.IP "" 2
+$
+
+.PD
+.IP "" 0
+.SP
+.SH "server & pserver"
+.SS "Act as a server for a client on stdin/stdout"
+.IX "pserver (subcommand)"
+.IX "server (subcommand)"
+.SP
+.IP "\(bu" 2
+pserver [-c path]
+.SP
+server [-c path]
+.IP "\(bu" 2
+Requires: repository, client conversation on stdin/stdout
+.IP "\(bu" 2
+Changes: Repository or, indirectly, client working directory.
+.SP
+The \fBcvs\fR \fBserver\fR and \fBpserver\fR commands are used to provide
+repository access to remote clients and expect a client conversation on
+stdin & stdout. Typically these commands are launched from \fBinetd\fR or
+via \fBssh\fR (see node `Remote repositories\(aq in the CVS manual).
+.SP
+\fBserver\fR expects that the client has already been authenticated somehow,
+typically via \fBssh\fR, and \fBpserver\fR attempts to authenticate the client
+itself.
+.SP
+Only one option is available with the \fBserver\fR and \fBpserver\fR
+commands:
+.SP
+.IX "configuration file"
+.IP "" 0
+\fB-c path\fR
+.IP "" 2
+Load configuration from \fIpath\fR rather than the default location
+\fB$CVSROOT/CVSROOT/config\fR (see node `config\(aq in the CVS manual). \fIpath\fR must be
+\fB/etc/cvs.conf\fR or prefixed by \fB/etc/cvs/\fR. This option is
+supported beginning with \fBcvs\fR release 1.12.13.
+.SP
+.SH "update"
+.SS "Bring work tree in sync with repository"
+.IX "update (subcommand)"
+.SP
+.IP "\(bu" 2
+update [-ACdflPpR] [-I name] [-j rev [-j rev]] [-k kflag] [-r tag[:date] | -D date] [-W spec] files\&...
+.IP "\(bu" 2
+Requires: repository, working directory.
+.IP "\(bu" 2
+Changes: working directory.
+.SP
+After you\(aqve run checkout to create your private copy
+of source from the common repository, other developers
+will continue changing the central source. From time
+to time, when it is convenient in your development
+process, you can use the \fBupdate\fR command from
+within your working directory to reconcile your work
+with any revisions applied to the source repository
+since your last checkout or update. Without the \fB-C\fR
+option, \fBupdate\fR will also merge any differences
+between the local copy of files and their base revisions
+into any destination revisions specified with \fB-r\fR,
+\fB-D\fR, or \fB-A\fR.
+.SP
+.SH "update options"
+.SP
+These standard options are available with \fBupdate\fR
+(see node `Common options\(aq in the CVS manual, for a complete description of
+them):
+.SP
+.IP "" 0
+\fB-D date\fR
+.IP "" 2
+Use the most recent revision no later than \fIdate\fR.
+This option is sticky, and implies \fB-P\fR.
+See see node `Sticky tags\(aq in the CVS manual, for more information on sticky tags/dates.
+.SP
+.IP "" 0
+\fB-f\fR
+.IP "" 2
+Only useful with the \fB-D\fR or \fB-r\fR flags. If no matching revision
+is found, retrieve the most recent revision (instead of ignoring the file).
+.SP
+.IP "" 0
+\fB-k \fIkflag\fB\fR
+.IP "" 2
+Process keywords according to \fIkflag\fR. See
+see node `Keyword substitution\(aq in the CVS manual.
+This option is sticky; future updates of
+this file in this working directory will use the same
+\fIkflag\fR. The \fBstatus\fR command can be viewed
+to see the sticky options. See see node `Invoking CVS\(aq in the CVS manual, for
+more information on the \fBstatus\fR command.
+.SP
+.IP "" 0
+\fB-l\fR
+.IP "" 2
+Local; run only in current working directory. see node `Recursive behavior\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-P\fR
+.IP "" 2
+Prune empty directories. See see node `Moving directories\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-p\fR
+.IP "" 2
+Pipe files to the standard output.
+.SP
+.IP "" 0
+\fB-R\fR
+.IP "" 2
+Update directories recursively (default). see node `Recursive
+behavior\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-r \fItag\fB[:\fIdate\fB]\fR
+.IP "" 2
+Retrieve the revisions specified by \fItag\fR or, when \fIdate\fR is specified
+and \fItag\fR is a branch tag, the version from the branch \fItag\fR as it
+existed on \fIdate\fR. This option is sticky, and implies \fB-P\fR.
+See see node `Sticky tags\(aq in the CVS manual, for more information on sticky tags/dates. Also
+see see node `Common options\(aq in the CVS manual.
+.SP
+These special options are also available with
+\fBupdate\fR.
+.SP
+.IP "" 0
+\fB-A\fR
+.IP "" 2
+Reset any sticky tags, dates, or \fB-k\fR options.
+See see node `Sticky tags\(aq in the CVS manual, for more information on sticky tags/dates.
+.SP
+.IP "" 0
+\fB-C\fR
+.IP "" 2
+Overwrite locally modified files with clean copies from
+the repository (the modified file is saved in
+\fB.#\fIfile\fB.\fIrevision\fB\fR, however).
+.SP
+.IP "" 0
+\fB-d\fR
+.IP "" 2
+Create any directories that exist in the repository if
+they\(aqre missing from the working directory. Normally,
+\fBupdate\fR acts only on directories and files that
+were already enrolled in your working directory.
+.SP
+This is useful for updating directories that were
+created in the repository since the initial checkout;
+but it has an unfortunate side effect. If you
+deliberately avoided certain directories in the
+repository when you created your working directory
+(either through use of a module name or by listing
+explicitly the files and directories you wanted on the
+command line), then updating with \fB-d\fR will create
+those directories, which may not be what you want.
+.SP
+.IP "" 0
+\fB-I \fIname\fB\fR
+.IP "" 2
+Ignore files whose names match \fIname\fR (in your
+working directory) during the update. You can specify
+\fB-I\fR more than once on the command line to specify
+several files to ignore. Use \fB-I !\fR to avoid
+ignoring any files at all. see node `cvsignore\(aq in the CVS manual, for other
+ways to make \fBcvs\fR ignore some files.
+.SP
+.IP "" 0
+\fB-W\fIspec\fB\fR
+.IP "" 2
+Specify file names that should be filtered during
+update. You can use this option repeatedly.
+.SP
+\fIspec\fR can be a file name pattern of the same type
+that you can specify in the \fB.cvswrappers\fR
+file. see node `Wrappers\(aq in the CVS manual.
+.SP
+.IP "" 0
+\fB-j\fIrevision\fB\fR
+.IP "" 2
+With two \fB-j\fR options, merge changes from the
+revision specified with the first \fB-j\fR option to
+the revision specified with the second \fBj\fR option,
+into the working directory.
+.SP
+With one \fB-j\fR option, merge changes from the
+ancestor revision to the revision specified with the
+\fB-j\fR option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the \fB-j\fR option.
+.SP
+Note that using a single \fB-j \fItagname\fB\fR option rather than
+\fB-j \fIbranchname\fB\fR to merge changes from a branch will
+often not remove files which were removed on the branch.
+see node `Merging adds and removals\(aq in the CVS manual, for more.
+.SP
+In addition, each \fB-j\fR option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+\fB-j\fISymbolic_Tag\fB:\fIDate_Specifier\fB\fR.
+.SP
+see node `Branching and merging\(aq in the CVS manual.
+.SP
+.SP
+.SH "update output"
+.SP
+\fBupdate\fR and \fBcheckout\fR keep you informed of
+their progress by printing a line for each file, preceded
+by one character indicating the status of the file:
+.SP
+.IP "" 0
+\fBU \fIfile\fB\fR
+.IP "" 2
+The file was brought up to date with respect to the
+repository. This is done for any file that exists in
+the repository but not in your working directory, and for files
+that you haven\(aqt changed but are not the most recent
+versions available in the repository.
+.SP
+.IP "" 0
+\fBP \fIfile\fB\fR
+.IP "" 2
+Like \fBU\fR, but the \fBcvs\fR server sends a patch instead of an entire
+file. This accomplishes the same thing as \fBU\fR using less bandwidth.
+.SP
+.IP "" 0
+\fBA \fIfile\fB\fR
+.IP "" 2
+The file has been added to your private copy of the
+sources, and will be added to the source repository
+when you run \fBcommit\fR on the file. This is a
+reminder to you that the file needs to be committed.
+.SP
+.IP "" 0
+\fBR \fIfile\fB\fR
+.IP "" 2
+The file has been removed from your private copy of the
+sources, and will be removed from the source repository
+when you run \fBcommit\fR on the file. This is a
+reminder to you that the file needs to be committed.
+.SP
+.IP "" 0
+\fBM \fIfile\fB\fR
+.IP "" 2
+The file is modified in your working directory.
+.SP
+\fBM\fR can indicate one of two states for a file
+you\(aqre working on: either there were no modifications
+to the same file in the repository, so that your file
+remains as you last saw it; or there were modifications
+in the repository as well as in your copy, but they
+were merged successfully, without conflict, in your
+working directory.
+.SP
+\fBcvs\fR will print some messages if it merges your work,
+and a backup copy of your working file (as it looked
+before you ran \fBupdate\fR) will be made. The exact
+name of that file is printed while \fBupdate\fR runs.
+.SP
+.IP "" 0
+\fBC \fIfile\fB\fR
+.IP "" 2
+.IX "\&.# files"
+.IX "__ files (VMS)"
+A conflict was detected while trying to merge your
+changes to \fIfile\fR with changes from the source
+repository. \fIfile\fR (the copy in your working
+directory) is now the result of attempting to merge
+the two revisions; an unmodified copy of your file
+is also in your working directory, with the name
+\fB.#\fIfile\fB.\fIrevision\fB\fR where \fIrevision\fR
+is the revision that your modified file started
+from. Resolve the conflict as described in
+see node `Conflicts example\(aq in the CVS manual.
+(Note that some systems automatically purge
+files that begin with \fB.#\fR if they have not been
+accessed for a few days. If you intend to keep a copy
+of your original file, it is a very good idea to rename
+it.) Under \fBvms\fR, the file name starts with
+\fB__\fR rather than \fB.#\fR.
+.SP
+.IP "" 0
+\fB? \fIfile\fB\fR
+.IP "" 2
+\fIfile\fR is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for \fBcvs\fR to ignore (see the
+description of the \fB-I\fR option, and
+see node `cvsignore\(aq in the CVS manual).
+.SH "AUTHORS"
+.TP
+Dick Grune
+Original author of the
+.B cvs
+shell script version posted to
+.B comp.sources.unix
+in the volume6 release of December, 1986.
+Credited with much of the
+.B cvs
+conflict resolution algorithms.
+.TP
+Brian Berliner
+Coder and designer of the
+.B cvs
+program itself in April, 1989, based on the original work done by Dick.
+.TP
+Jeff Polk
+Helped Brian with the design of the
+.B cvs
+module and vendor branch support and author of the
+.BR checkin ( 1 )
+shell script (the ancestor of \fBcvs import\fP).
+.TP
+Larry Jones, Derek R. Price, and Mark D. Baushke
+Have helped maintain
+.B cvs
+for many years.
+.TP
+And many others too numerous to mention here.
+.SH "SEE ALSO"
+The most comprehensive manual for CVS is
+Version Management with CVS by Per Cederqvist et al. Depending on
+your system, you may be able to get it with the
+.B info CVS
+command or it may be available as cvs.pdf (Portable Document Format),
+cvs.ps (PostScript), cvs.texinfo (Texinfo source), or cvs.html.
+.SP
+For CVS updates, more information on documentation, software related
+to CVS, development of CVS, and more, see:
+.in +1i
+.SP
+.PD 0
+.IP "" 4
+.B http://www.nongnu.org/cvs/
+.in -1i
+.SP
+.BR ci ( 1 ),
+.BR co ( 1 ),
+.BR cvs ( 5 ),
+.BR cvsbug ( 8 ),
+.BR diff ( 1 ),
+.BR grep ( 1 ),
+.BR patch ( 1 ),
+.BR rcs ( 1 ),
+.BR rcsdiff ( 1 ),
+.BR rcsmerge ( 1 ),
+.BR rlog ( 1 ).
diff --git a/doc/cvs.info b/doc/cvs.info
new file mode 100644
index 0000000..3d11ca7
--- /dev/null
+++ b/doc/cvs.info
@@ -0,0 +1,234 @@
+This is cvs.info, produced by makeinfo version 4.8 from cvs.texinfo.
+
+INFO-DIR-SECTION GNU Packages
+START-INFO-DIR-ENTRY
+* CVS: (cvs). Concurrent Versions System
+END-INFO-DIR-ENTRY
+INFO-DIR-SECTION Individual utilities
+START-INFO-DIR-ENTRY
+* cvs: (cvs)CVS commands. Concurrent Versions System
+END-INFO-DIR-ENTRY
+
+
+Indirect:
+cvs.info-1: 337
+cvs.info-2: 298746
+
+Tag Table:
+(Indirect)
+Node: Top337
+Node: Overview3309
+Node: What is CVS?3874
+Node: What is CVS not?6795
+Node: A sample session12358
+Node: Getting the source13185
+Node: Committing your changes14071
+Node: Cleaning up16238
+Node: Viewing differences17951
+Node: Repository18856
+Node: Specifying a repository21569
+Node: Repository storage22909
+Node: Repository files24130
+Node: File permissions26978
+Node: Windows permissions30842
+Node: Attic31795
+Node: CVS in repository32849
+Node: Locks35949
+Node: CVSROOT storage40923
+Node: Working directory storage42730
+Node: Intro administrative files52366
+Node: Multiple repositories54087
+Node: Creating a repository55581
+Node: Backing up57945
+Node: Moving a repository59873
+Node: Remote repositories60953
+Node: Server requirements62554
+Node: The connection method64989
+Node: Connecting via rsh70069
+Node: Password authenticated73379
+Node: Password authentication server74141
+Node: Password authentication client85488
+Node: Password authentication security88691
+Node: GSSAPI authenticated90551
+Node: Kerberos authenticated92411
+Node: Connecting via fork94007
+Node: Write proxies95141
+Node: Read-only access98559
+Node: Server temporary directory101566
+Node: Starting a new project102860
+Node: Setting up the files103605
+Node: From files104234
+Node: From other version control systems106221
+Node: From scratch108798
+Node: Defining the module109683
+Node: Revisions110669
+Node: Revision numbers111877
+Node: Versions revisions releases112918
+Node: Assigning revisions113505
+Node: Tags115153
+Node: Tagging the working directory120507
+Node: Tagging by date/tag121900
+Node: Modifying tags123410
+Node: Tagging add/remove126605
+Node: Sticky tags128244
+Node: Branching and merging131335
+Node: Branches motivation132633
+Node: Creating a branch133649
+Node: Accessing branches135214
+Node: Branches and revisions138445
+Node: Magic branch numbers141164
+Node: Merging a branch142662
+Node: Merging more than once144966
+Node: Merging two revisions147447
+Node: Merging adds and removals148777
+Node: Merging and keywords150057
+Node: Recursive behavior153378
+Node: Adding and removing155206
+Node: Adding files156101
+Node: Removing files159007
+Node: Removing directories162433
+Node: Moving files163602
+Node: Outside164254
+Node: Inside165178
+Node: Rename by copying166035
+Node: Moving directories167049
+Node: History browsing168556
+Node: log messages169033
+Node: history database169359
+Node: user-defined logging169843
+Node: Binary files170877
+Node: Binary why171515
+Node: Binary howto173754
+Node: Multiple developers176802
+Node: File status179288
+Node: Updating a file182455
+Node: Conflicts example183893
+Node: Informing others187938
+Node: Concurrency188485
+Node: Watches190237
+Node: Setting a watch192163
+Node: Getting Notified193473
+Node: Editing files197182
+Node: Watch information200192
+Node: Watches Compatibility201048
+Node: Choosing a model201929
+Node: Revision management205134
+Node: When to commit205740
+Node: Keyword substitution206854
+Node: Keyword list207920
+Node: Using keywords213378
+Node: Avoiding substitution215120
+Node: Substitution modes216330
+Node: Configuring keyword expansion219136
+Node: Log keyword222278
+Node: Tracking sources223436
+Node: First import224968
+Node: Update imports226312
+Node: Reverting local changes228240
+Node: Binary files in imports228944
+Node: Keywords in imports229260
+Node: Multiple vendor branches230405
+Node: Builds232106
+Node: Special Files234786
+Node: CVS commands235435
+Node: Structure237178
+Node: Exit status238459
+Node: ~/.cvsrc239456
+Node: Global options241499
+Node: Common options247491
+Node: Date input formats254614
+Node: General date syntax256947
+Node: Calendar date items259682
+Node: Time of day items261683
+Node: Time zone items263739
+Node: Day of week items264977
+Node: Relative items in date strings265970
+Node: Pure numbers in date strings268776
+Node: Seconds since the Epoch269761
+Node: Specifying time zone rules271390
+Node: Authors of get_date273758
+Node: admin274514
+Node: admin options275702
+Node: annotate286929
+Node: annotate options287467
+Node: annotate example288151
+Node: checkout289048
+Node: checkout options291817
+Node: checkout examples296346
+Node: commit296632
+Node: commit options298746
+Node: commit examples300673
+Node: diff303071
+Node: diff options303991
+Node: Line group formats311971
+Node: Line formats317693
+Node: diff examples320912
+Node: export321883
+Node: export options323200
+Node: history324455
+Node: history options325880
+Node: import329460
+Node: import options332207
+Node: import output334180
+Node: import examples335254
+Node: log335433
+Node: log options336666
+Node: log examples340682
+Node: ls & rls341166
+Node: ls & rls options342188
+Node: rls examples342902
+Node: rdiff343306
+Node: rdiff options344666
+Node: rdiff examples346590
+Node: release347568
+Node: release options348884
+Node: release output349573
+Node: release examples350857
+Node: server & pserver351339
+Node: update352482
+Node: update options353561
+Node: update output357843
+Node: Invoking CVS360719
+Node: Administrative files385108
+Node: modules386311
+Node: Alias modules387666
+Node: Regular modules388729
+Node: Ampersand modules390131
+Node: Excluding directories391376
+Node: Module options391928
+Node: Module program options393506
+Node: Wrappers394291
+Node: Trigger Scripts395997
+Node: syntax397564
+Node: Trigger Script Security402741
+Node: commit files404099
+Node: Updating Commit Files405706
+Node: commitinfo409556
+Node: verifymsg411752
+Node: verifymsg example415545
+Node: loginfo417005
+Node: loginfo example419627
+Node: Keeping a checked out copy420510
+Node: postadmin421554
+Node: taginfo422096
+Node: posttag423995
+Node: postwatch424526
+Node: preproxy425485
+Node: postproxy426550
+Node: rcsinfo427795
+Node: cvsignore429358
+Node: checkoutlist432629
+Node: history file434171
+Node: Variables434788
+Node: config438807
+Node: Environment variables452023
+Node: Compatibility457875
+Node: Troubleshooting458898
+Node: Error messages459540
+Node: Connection478324
+Node: Other problems483269
+Node: Credits484207
+Node: BUGS485615
+Node: Index489259
+
+End Tag Table
diff --git a/doc/cvs.info-1 b/doc/cvs.info-1
new file mode 100644
index 0000000..eff61d7
--- /dev/null
+++ b/doc/cvs.info-1
@@ -0,0 +1,6966 @@
+This is cvs.info, produced by makeinfo version 4.8 from cvs.texinfo.
+
+INFO-DIR-SECTION GNU Packages
+START-INFO-DIR-ENTRY
+* CVS: (cvs). Concurrent Versions System
+END-INFO-DIR-ENTRY
+INFO-DIR-SECTION Individual utilities
+START-INFO-DIR-ENTRY
+* cvs: (cvs)CVS commands. Concurrent Versions System
+END-INFO-DIR-ENTRY
+
+
+File: cvs.info, Node: Top, Next: Overview, Up: (dir)
+
+CVS--Concurrent Versions System v1.12.13
+****************************************
+
+This info manual describes how to use and administer CVS version
+1.12.13.
+
+Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+Portions
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Derek
+ R. Price,
+ Copyright (C) 2002, 2003, 2004, 2005 Ximbiot
+ `http://ximbiot.com',
+ Copyright (C) 1992, 1993, 1999 Signum Support AB,
+ and Copyright (C) others.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided also
+that the entire resulting derived work is distributed under the terms
+of a permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Free Software Foundation.
+
+* Menu:
+
+* Overview:: An introduction to CVS
+* Repository:: Where all your sources are stored
+* Starting a new project:: Starting a project with CVS
+* Revisions:: Numeric and symbolic names for revisions
+* Branching and merging:: Diverging/rejoining branches of development
+* Recursive behavior:: CVS descends directories
+* Adding and removing:: Adding/removing/renaming files/directories
+* History browsing:: Viewing the history of files in various ways
+
+CVS and the Real World.
+-----------------------
+* Binary files:: CVS can handle binary files
+* Multiple developers:: How CVS helps a group of developers
+* Revision management:: Policy questions for revision management
+* Keyword substitution:: CVS can include the revision inside the file
+* Tracking sources:: Tracking third-party sources
+* Builds:: Issues related to CVS and builds
+* Special Files:: Devices, links and other non-regular files
+
+References.
+-----------
+* CVS commands:: CVS commands share some things
+* Invoking CVS:: Quick reference to CVS commands
+* Administrative files:: Reference manual for the Administrative files
+* Environment variables:: All environment variables which affect CVS
+* Compatibility:: Upgrading CVS versions
+* Troubleshooting:: Some tips when nothing works
+* Credits:: Some of the contributors to this manual
+* BUGS:: Dealing with bugs in CVS or this manual
+* Index:: Index
+
+
+File: cvs.info, Node: Overview, Next: Repository, Prev: Top, Up: Top
+
+1 Overview
+**********
+
+This chapter is for people who have never used CVS, and perhaps have
+never used version control software before.
+
+ If you are already familiar with CVS and are just trying to learn a
+particular feature or remember a certain command, you can probably skip
+everything here.
+
+* Menu:
+
+* What is CVS?:: What you can do with CVS
+* What is CVS not?:: Problems CVS doesn't try to solve
+* A sample session:: A tour of basic CVS usage
+
+
+File: cvs.info, Node: What is CVS?, Next: What is CVS not?, Up: Overview
+
+1.1 What is CVS?
+================
+
+CVS is a version control system. Using it, you can record the history
+of your source files.
+
+ For example, bugs sometimes creep in when software is modified, and
+you might not detect the bug until a long time after you make the
+modification. With CVS, you can easily retrieve old versions to see
+exactly which change caused the bug. This can sometimes be a big help.
+
+ You could of course save every version of every file you have ever
+created. This would however waste an enormous amount of disk space.
+CVS stores all the versions of a file in a single file in a clever way
+that only stores the differences between versions.
+
+ CVS also helps you if you are part of a group of people working on
+the same project. It is all too easy to overwrite each others' changes
+unless you are extremely careful. Some editors, like GNU Emacs, try to
+make sure that two people never modify the same file at the same time.
+Unfortunately, if someone is using another editor, that safeguard will
+not work. CVS solves this problem by insulating the different
+developers from each other. Every developer works in his own
+directory, and CVS merges the work when each developer is done.
+
+ CVS started out as a bunch of shell scripts written by Dick Grune,
+posted to the newsgroup `comp.sources.unix' in the volume 6 release of
+July, 1986. While no actual code from these shell scripts is present
+in the current version of CVS much of the CVS conflict resolution
+algorithms come from them.
+
+ In April, 1989, Brian Berliner designed and coded CVS. Jeff Polk
+later helped Brian with the design of the CVS module and vendor branch
+support.
+
+ You can get CVS in a variety of ways, including free download from
+the Internet. For more information on downloading CVS and other CVS
+topics, see:
+
+ `http://cvs.nongnu.org/'
+
+ There is a mailing list, known as <info-cvs@nongnu.org>, devoted to
+CVS. To subscribe or unsubscribe write to
+<info-cvs-request@nongnu.org>. If you prefer a Usenet group, there is
+a one-way mirror (posts to the email list are usually sent to the news
+group, but not visa versa) of <info-cvs@nongnu.org> at
+`news:gnu.cvs.help'. The right Usenet group for posts is
+`news:comp.software.config-mgmt' which is for CVS discussions (along
+with other configuration management systems). In the future, it might
+be possible to create a `comp.software.config-mgmt.cvs', but probably
+only if there is sufficient CVS traffic on
+`news:comp.software.config-mgmt'.
+
+ You can also subscribe to the <bug-cvs@nongnu.org> mailing list,
+described in more detail in *Note BUGS::. To subscribe send mail to
+<bug-cvs-request@nongnu.org>. There is a two-way Usenet mirror (posts
+to the Usenet group are usually sent to the email list and visa versa)
+of <bug-cvs@nongnu.org> named `news:gnu.cvs.bug'.
+
+
+File: cvs.info, Node: What is CVS not?, Next: A sample session, Prev: What is CVS?, Up: Overview
+
+1.2 What is CVS not?
+====================
+
+CVS can do a lot of things for you, but it does not try to be
+everything for everyone.
+
+CVS is not a build system.
+ Though the structure of your repository and modules file interact
+ with your build system (e.g. `Makefile's), they are essentially
+ independent.
+
+ CVS does not dictate how you build anything. It merely stores
+ files for retrieval in a tree structure you devise.
+
+ CVS does not dictate how to use disk space in the checked out
+ working directories. If you write your `Makefile's or scripts in
+ every directory so they have to know the relative positions of
+ everything else, you wind up requiring the entire repository to be
+ checked out.
+
+ If you modularize your work, and construct a build system that
+ will share files (via links, mounts, `VPATH' in `Makefile's,
+ etc.), you can arrange your disk usage however you like.
+
+ But you have to remember that _any_ such system is a lot of work
+ to construct and maintain. CVS does not address the issues
+ involved.
+
+ Of course, you should place the tools created to support such a
+ build system (scripts, `Makefile's, etc) under CVS.
+
+ Figuring out what files need to be rebuilt when something changes
+ is, again, something to be handled outside the scope of CVS. One
+ traditional approach is to use `make' for building, and use some
+ automated tool for generating the dependencies which `make' uses.
+
+ See *Note Builds::, for more information on doing builds in
+ conjunction with CVS.
+
+CVS is not a substitute for management.
+ Your managers and project leaders are expected to talk to you
+ frequently enough to make certain you are aware of schedules,
+ merge points, branch names and release dates. If they don't, CVS
+ can't help.
+
+ CVS is an instrument for making sources dance to your tune. But
+ you are the piper and the composer. No instrument plays itself or
+ writes its own music.
+
+CVS is not a substitute for developer communication.
+ When faced with conflicts within a single file, most developers
+ manage to resolve them without too much effort. But a more
+ general definition of "conflict" includes problems too difficult
+ to solve without communication between developers.
+
+ CVS cannot determine when simultaneous changes within a single
+ file, or across a whole collection of files, will logically
+ conflict with one another. Its concept of a "conflict" is purely
+ textual, arising when two changes to the same base file are near
+ enough to spook the merge (i.e. `diff3') command.
+
+ CVS does not claim to help at all in figuring out non-textual or
+ distributed conflicts in program logic.
+
+ For example: Say you change the arguments to function `X' defined
+ in file `A'. At the same time, someone edits file `B', adding new
+ calls to function `X' using the old arguments. You are outside
+ the realm of CVS's competence.
+
+ Acquire the habit of reading specs and talking to your peers.
+
+CVS does not have change control
+ Change control refers to a number of things. First of all it can
+ mean "bug-tracking", that is being able to keep a database of
+ reported bugs and the status of each one (is it fixed? in what
+ release? has the bug submitter agreed that it is fixed?). For
+ interfacing CVS to an external bug-tracking system, see the
+ `rcsinfo' and `verifymsg' files (*note Administrative files::).
+
+ Another aspect of change control is keeping track of the fact that
+ changes to several files were in fact changed together as one
+ logical change. If you check in several files in a single `cvs
+ commit' operation, CVS then forgets that those files were checked
+ in together, and the fact that they have the same log message is
+ the only thing tying them together. Keeping a GNU style
+ `ChangeLog' can help somewhat.
+
+ Another aspect of change control, in some systems, is the ability
+ to keep track of the status of each change. Some changes have
+ been written by a developer, others have been reviewed by a second
+ developer, and so on. Generally, the way to do this with CVS is to
+ generate a diff (using `cvs diff' or `diff') and email it to
+ someone who can then apply it using the `patch' utility. This is
+ very flexible, but depends on mechanisms outside CVS to make sure
+ nothing falls through the cracks.
+
+CVS is not an automated testing program
+ It should be possible to enforce mandatory use of a test suite
+ using the `commitinfo' file. I haven't heard a lot about projects
+ trying to do that or whether there are subtle gotchas, however.
+
+CVS does not have a built-in process model
+ Some systems provide ways to ensure that changes or releases go
+ through various steps, with various approvals as needed.
+ Generally, one can accomplish this with CVS but it might be a
+ little more work. In some cases you'll want to use the
+ `commitinfo', `loginfo', `rcsinfo', or `verifymsg' files, to
+ require that certain steps be performed before cvs will allow a
+ checkin. Also consider whether features such as branches and tags
+ can be used to perform tasks such as doing work in a development
+ tree and then merging certain changes over to a stable tree only
+ once they have been proven.
+
+
+File: cvs.info, Node: A sample session, Prev: What is CVS not?, Up: Overview
+
+1.3 A sample session
+====================
+
+As a way of introducing CVS, we'll go through a typical work-session
+using CVS. The first thing to understand is that CVS stores all files
+in a centralized "repository" (*note Repository::); this section
+assumes that a repository is set up.
+
+ Suppose you are working on a simple compiler. The source consists
+of a handful of C files and a `Makefile'. The compiler is called `tc'
+(Trivial Compiler), and the repository is set up so that there is a
+module called `tc'.
+
+* Menu:
+
+* Getting the source:: Creating a workspace
+* Committing your changes:: Making your work available to others
+* Cleaning up:: Cleaning up
+* Viewing differences:: Viewing differences
+
+
+File: cvs.info, Node: Getting the source, Next: Committing your changes, Up: A sample session
+
+1.3.1 Getting the source
+------------------------
+
+The first thing you must do is to get your own working copy of the
+source for `tc'. For this, you use the `checkout' command:
+
+ $ cvs checkout tc
+
+This will create a new directory called `tc' and populate it with the
+source files.
+
+ $ cd tc
+ $ ls
+ CVS Makefile backend.c driver.c frontend.c parser.c
+
+ The `CVS' directory is used internally by CVS. Normally, you should
+not modify or remove any of the files in it.
+
+ You start your favorite editor, hack away at `backend.c', and a
+couple of hours later you have added an optimization pass to the
+compiler. A note to RCS and SCCS users: There is no need to lock the
+files that you want to edit. *Note Multiple developers::, for an
+explanation.
+
+
+File: cvs.info, Node: Committing your changes, Next: Cleaning up, Prev: Getting the source, Up: A sample session
+
+1.3.2 Committing your changes
+-----------------------------
+
+When you have checked that the compiler is still compilable you decide
+to make a new version of `backend.c'. This will store your new
+`backend.c' in the repository and make it available to anyone else who
+is using that same repository.
+
+ $ cvs commit backend.c
+
+CVS starts an editor, to allow you to enter a log message. You type in
+"Added an optimization pass.", save the temporary file, and exit the
+editor.
+
+ The environment variable `$CVSEDITOR' determines which editor is
+started. If `$CVSEDITOR' is not set, then if the environment variable
+`$EDITOR' is set, it will be used. If both `$CVSEDITOR' and `$EDITOR'
+are not set then there is a default which will vary with your operating
+system, for example `vi' for unix or `notepad' for Windows NT/95.
+
+ In addition, CVS checks the `$VISUAL' environment variable.
+Opinions vary on whether this behavior is desirable and whether future
+releases of CVS should check `$VISUAL' or ignore it. You will be OK
+either way if you make sure that `$VISUAL' is either unset or set to
+the same thing as `$EDITOR'.
+
+ When CVS starts the editor, it includes a list of files which are
+modified. For the CVS client, this list is based on comparing the
+modification time of the file against the modification time that the
+file had when it was last gotten or updated. Therefore, if a file's
+modification time has changed but its contents have not, it will show
+up as modified. The simplest way to handle this is simply not to worry
+about it--if you proceed with the commit CVS will detect that the
+contents are not modified and treat it as an unmodified file. The next
+`update' will clue CVS in to the fact that the file is unmodified, and
+it will reset its stored timestamp so that the file will not show up in
+future editor sessions.
+
+ If you want to avoid starting an editor you can specify the log
+message on the command line using the `-m' flag instead, like this:
+
+ $ cvs commit -m "Added an optimization pass" backend.c
+
+
+File: cvs.info, Node: Cleaning up, Next: Viewing differences, Prev: Committing your changes, Up: A sample session
+
+1.3.3 Cleaning up
+-----------------
+
+Before you turn to other tasks you decide to remove your working copy of
+tc. One acceptable way to do that is of course
+
+ $ cd ..
+ $ rm -r tc
+
+but a better way is to use the `release' command (*note release::):
+
+ $ cd ..
+ $ cvs release -d tc
+ M driver.c
+ ? tc
+ You have [1] altered files in this repository.
+ Are you sure you want to release (and delete) directory `tc': n
+ ** `release' aborted by user choice.
+
+ The `release' command checks that all your modifications have been
+committed. If history logging is enabled it also makes a note in the
+history file. *Note history file::.
+
+ When you use the `-d' flag with `release', it also removes your
+working copy.
+
+ In the example above, the `release' command wrote a couple of lines
+of output. `? tc' means that the file `tc' is unknown to CVS. That is
+nothing to worry about: `tc' is the executable compiler, and it should
+not be stored in the repository. *Note cvsignore::, for information
+about how to make that warning go away. *Note release output::, for a
+complete explanation of all possible output from `release'.
+
+ `M driver.c' is more serious. It means that the file `driver.c' has
+been modified since it was checked out.
+
+ The `release' command always finishes by telling you how many
+modified files you have in your working copy of the sources, and then
+asks you for confirmation before deleting any files or making any note
+in the history file.
+
+ You decide to play it safe and answer `n <RET>' when `release' asks
+for confirmation.
+
+
+File: cvs.info, Node: Viewing differences, Prev: Cleaning up, Up: A sample session
+
+1.3.4 Viewing differences
+-------------------------
+
+You do not remember modifying `driver.c', so you want to see what has
+happened to that file.
+
+ $ cd tc
+ $ cvs diff driver.c
+
+ This command runs `diff' to compare the version of `driver.c' that
+you checked out with your working copy. When you see the output you
+remember that you added a command line option that enabled the
+optimization pass. You check it in, and release the module.
+
+ $ cvs commit -m "Added an optimization pass" driver.c
+ Checking in driver.c;
+ /usr/local/cvsroot/tc/driver.c,v <-- driver.c
+ new revision: 1.2; previous revision: 1.1
+ done
+ $ cd ..
+ $ cvs release -d tc
+ ? tc
+ You have [0] altered files in this repository.
+ Are you sure you want to release (and delete) directory `tc': y
+
+
+File: cvs.info, Node: Repository, Next: Starting a new project, Prev: Overview, Up: Top
+
+2 The Repository
+****************
+
+The CVS "repository" stores a complete copy of all the files and
+directories which are under version control.
+
+ Normally, you never access any of the files in the repository
+directly. Instead, you use CVS commands to get your own copy of the
+files into a "working directory", and then work on that copy. When
+you've finished a set of changes, you check (or "commit") them back
+into the repository. The repository then contains the changes which
+you have made, as well as recording exactly what you changed, when you
+changed it, and other such information. Note that the repository is
+not a subdirectory of the working directory, or vice versa; they should
+be in separate locations.
+
+ CVS can access a repository by a variety of means. It might be on
+the local computer, or it might be on a computer across the room or
+across the world. To distinguish various ways to access a repository,
+the repository name can start with an "access method". For example,
+the access method `:local:' means to access a repository directory, so
+the repository `:local:/usr/local/cvsroot' means that the repository is
+in `/usr/local/cvsroot' on the computer running CVS. For information
+on other access methods, see *Note Remote repositories::.
+
+ If the access method is omitted, then if the repository starts with
+`/', then `:local:' is assumed. If it does not start with `/' then
+either `:ext:' or `:server:' is assumed. For example, if you have a
+local repository in `/usr/local/cvsroot', you can use
+`/usr/local/cvsroot' instead of `:local:/usr/local/cvsroot'. But if
+(under Windows NT, for example) your local repository is
+`c:\src\cvsroot', then you must specify the access method, as in
+`:local:c:/src/cvsroot'.
+
+ The repository is split in two parts. `$CVSROOT/CVSROOT' contains
+administrative files for CVS. The other directories contain the actual
+user-defined modules.
+
+* Menu:
+
+* Specifying a repository:: Telling CVS where your repository is
+* Repository storage:: The structure of the repository
+* Working directory storage:: The structure of working directories
+* Intro administrative files:: Defining modules
+* Multiple repositories:: Multiple repositories
+* Creating a repository:: Creating a repository
+* Backing up:: Backing up a repository
+* Moving a repository:: Moving a repository
+* Remote repositories:: Accessing repositories on remote machines
+* Read-only access:: Granting read-only access to the repository
+* Server temporary directory:: The server creates temporary directories
+
+
+File: cvs.info, Node: Specifying a repository, Next: Repository storage, Up: Repository
+
+2.1 Telling CVS where your repository is
+========================================
+
+There are several ways to tell CVS where to find the repository. You
+can name the repository on the command line explicitly, with the `-d'
+(for "directory") option:
+
+ cvs -d /usr/local/cvsroot checkout yoyodyne/tc
+
+ Or you can set the `$CVSROOT' environment variable to an absolute
+path to the root of the repository, `/usr/local/cvsroot' in this
+example. To set `$CVSROOT', `csh' and `tcsh' users should have this
+line in their `.cshrc' or `.tcshrc' files:
+
+ setenv CVSROOT /usr/local/cvsroot
+
+`sh' and `bash' users should instead have these lines in their
+`.profile' or `.bashrc':
+
+ CVSROOT=/usr/local/cvsroot
+ export CVSROOT
+
+ A repository specified with `-d' will override the `$CVSROOT'
+environment variable. Once you've checked a working copy out from the
+repository, it will remember where its repository is (the information
+is recorded in the `CVS/Root' file in the working copy).
+
+ The `-d' option and the `CVS/Root' file both override the `$CVSROOT'
+environment variable. If `-d' option differs from `CVS/Root', the
+former is used. Of course, for proper operation they should be two
+ways of referring to the same repository.
+
+
+File: cvs.info, Node: Repository storage, Next: Working directory storage, Prev: Specifying a repository, Up: Repository
+
+2.2 How data is stored in the repository
+========================================
+
+For most purposes it isn't important _how_ CVS stores information in
+the repository. In fact, the format has changed in the past, and is
+likely to change in the future. Since in almost all cases one accesses
+the repository via CVS commands, such changes need not be disruptive.
+
+ However, in some cases it may be necessary to understand how CVS
+stores data in the repository, for example you might need to track down
+CVS locks (*note Concurrency::) or you might need to deal with the file
+permissions appropriate for the repository.
+
+* Menu:
+
+* Repository files:: What files are stored in the repository
+* File permissions:: File permissions
+* Windows permissions:: Issues specific to Windows
+* Attic:: Some files are stored in the Attic
+* CVS in repository:: Additional information in CVS directory
+* Locks:: CVS locks control concurrent accesses
+* CVSROOT storage:: A few things about CVSROOT are different
+
+
+File: cvs.info, Node: Repository files, Next: File permissions, Up: Repository storage
+
+2.2.1 Where files are stored within the repository
+--------------------------------------------------
+
+The overall structure of the repository is a directory tree
+corresponding to the directories in the working directory. For
+example, supposing the repository is in
+
+ /usr/local/cvsroot
+
+here is a possible directory tree (showing only the directories):
+
+ /usr
+ |
+ +--local
+ | |
+ | +--cvsroot
+ | | |
+ | | +--CVSROOT
+ | (administrative files)
+ |
+ +--gnu
+ | |
+ | +--diff
+ | | (source code to GNU diff)
+ | |
+ | +--rcs
+ | | (source code to RCS)
+ | |
+ | +--cvs
+ | (source code to CVS)
+ |
+ +--yoyodyne
+ |
+ +--tc
+ | |
+ | +--man
+ | |
+ | +--testing
+ |
+ +--(other Yoyodyne software)
+
+ With the directories are "history files" for each file under version
+control. The name of the history file is the name of the corresponding
+file with `,v' appended to the end. Here is what the repository for
+the `yoyodyne/tc' directory might look like:
+ `$CVSROOT'
+ |
+ +--yoyodyne
+ | |
+ | +--tc
+ | | |
+ +--Makefile,v
+ +--backend.c,v
+ +--driver.c,v
+ +--frontend.c,v
+ +--parser.c,v
+ +--man
+ | |
+ | +--tc.1,v
+ |
+ +--testing
+ |
+ +--testpgm.t,v
+ +--test2.t,v
+
+ The history files contain, among other things, enough information to
+recreate any revision of the file, a log of all commit messages and the
+user-name of the person who committed the revision. The history files
+are known as "RCS files", because the first program to store files in
+that format was a version control system known as RCS. For a full
+description of the file format, see the `man' page `rcsfile(5)',
+distributed with RCS, or the file `doc/RCSFILES' in the CVS source
+distribution. This file format has become very common--many systems
+other than CVS or RCS can at least import history files in this format.
+
+ The RCS files used in CVS differ in a few ways from the standard
+format. The biggest difference is magic branches; for more information
+see *Note Magic branch numbers::. Also in CVS the valid tag names are
+a subset of what RCS accepts; for CVS's rules see *Note Tags::.
+
+
+File: cvs.info, Node: File permissions, Next: Windows permissions, Prev: Repository files, Up: Repository storage
+
+2.2.2 File permissions
+----------------------
+
+All `,v' files are created read-only, and you should not change the
+permission of those files. The directories inside the repository
+should be writable by the persons that have permission to modify the
+files in each directory. This normally means that you must create a
+UNIX group (see group(5)) consisting of the persons that are to edit
+the files in a project, and set up the repository so that it is that
+group that owns the directory. (On some systems, you also need to set
+the set-group-ID-on-execution bit on the repository directories (see
+chmod(1)) so that newly-created files and directories get the group-ID
+of the parent directory rather than that of the current process.)
+
+ This means that you can only control access to files on a
+per-directory basis.
+
+ Note that users must also have write access to check out files,
+because CVS needs to create lock files (*note Concurrency::). You can
+use LockDir in CVSROOT/config to put the lock files somewhere other
+than in the repository if you want to allow read-only access to some
+directories (*note config::).
+
+ Also note that users must have write access to the
+`CVSROOT/val-tags' file. CVS uses it to keep track of what tags are
+valid tag names (it is sometimes updated when tags are used, as well as
+when they are created).
+
+ Each RCS file will be owned by the user who last checked it in.
+This has little significance; what really matters is who owns the
+directories.
+
+ CVS tries to set up reasonable file permissions for new directories
+that are added inside the tree, but you must fix the permissions
+manually when a new directory should have different permissions than its
+parent directory. If you set the `CVSUMASK' environment variable that
+will control the file permissions which CVS uses in creating directories
+and/or files in the repository. `CVSUMASK' does not affect the file
+permissions in the working directory; such files have the permissions
+which are typical for newly created files, except that sometimes CVS
+creates them read-only (see the sections on watches, *Note Setting a
+watch::; -r, *Note Global options::; or `CVSREAD', *Note Environment
+variables::).
+
+ Note that using the client/server CVS (*note Remote repositories::),
+there is no good way to set `CVSUMASK'; the setting on the client
+machine has no effect. If you are connecting with `rsh', you can set
+`CVSUMASK' in `.bashrc' or `.cshrc', as described in the documentation
+for your operating system. This behavior might change in future
+versions of CVS; do not rely on the setting of `CVSUMASK' on the client
+having no effect.
+
+ Using pserver, you will generally need stricter permissions on the
+CVSROOT directory and directories above it in the tree; see *Note
+Password authentication security::.
+
+ Some operating systems have features which allow a particular
+program to run with the ability to perform operations which the caller
+of the program could not. For example, the set user ID (setuid) or set
+group ID (setgid) features of unix or the installed image feature of
+VMS. CVS was not written to use such features and therefore attempting
+to install CVS in this fashion will provide protection against only
+accidental lapses; anyone who is trying to circumvent the measure will
+be able to do so, and depending on how you have set it up may gain
+access to more than just CVS. You may wish to instead consider
+pserver. It shares some of the same attributes, in terms of possibly
+providing a false sense of security or opening security holes wider
+than the ones you are trying to fix, so read the documentation on
+pserver security carefully if you are considering this option (*Note
+Password authentication security::).
+
+
+File: cvs.info, Node: Windows permissions, Next: Attic, Prev: File permissions, Up: Repository storage
+
+2.2.3 File Permission issues specific to Windows
+------------------------------------------------
+
+Some file permission issues are specific to Windows operating systems
+(Windows 95, Windows NT, and presumably future operating systems in
+this family. Some of the following might apply to OS/2 but I'm not
+sure).
+
+ If you are using local CVS and the repository is on a networked file
+system which is served by the Samba SMB server, some people have
+reported problems with permissions. Enabling WRITE=YES in the samba
+configuration is said to fix/workaround it. Disclaimer: I haven't
+investigated enough to know the implications of enabling that option,
+nor do I know whether there is something which CVS could be doing
+differently in order to avoid the problem. If you find something out,
+please let us know as described in *Note BUGS::.
+
+
+File: cvs.info, Node: Attic, Next: CVS in repository, Prev: Windows permissions, Up: Repository storage
+
+2.2.4 The attic
+---------------
+
+You will notice that sometimes CVS stores an RCS file in the `Attic'.
+For example, if the CVSROOT is `/usr/local/cvsroot' and we are talking
+about the file `backend.c' in the directory `yoyodyne/tc', then the
+file normally would be in
+
+ /usr/local/cvsroot/yoyodyne/tc/backend.c,v
+
+but if it goes in the attic, it would be in
+
+ /usr/local/cvsroot/yoyodyne/tc/Attic/backend.c,v
+
+instead. It should not matter from a user point of view whether a file
+is in the attic; CVS keeps track of this and looks in the attic when it
+needs to. But in case you want to know, the rule is that the RCS file
+is stored in the attic if and only if the head revision on the trunk
+has state `dead'. A `dead' state means that file has been removed, or
+never added, for that revision. For example, if you add a file on a
+branch, it will have a trunk revision in `dead' state, and a branch
+revision in a non-`dead' state.
+
+
+File: cvs.info, Node: CVS in repository, Next: Locks, Prev: Attic, Up: Repository storage
+
+2.2.5 The CVS directory in the repository
+-----------------------------------------
+
+The `CVS' directory in each repository directory contains information
+such as file attributes (in a file called `CVS/fileattr'. In the
+future additional files may be added to this directory, so
+implementations should silently ignore additional files.
+
+ This behavior is implemented only by CVS 1.7 and later; for details
+see *Note Watches Compatibility::.
+
+ The format of the `fileattr' file is a series of entries of the
+following form (where `{' and `}' means the text between the braces can
+be repeated zero or more times):
+
+ ENT-TYPE FILENAME <tab> ATTRNAME = ATTRVAL {; ATTRNAME = ATTRVAL}
+<linefeed>
+
+ ENT-TYPE is `F' for a file, in which case the entry specifies the
+attributes for that file.
+
+ ENT-TYPE is `D', and FILENAME empty, to specify default attributes
+to be used for newly added files.
+
+ Other ENT-TYPE are reserved for future expansion. CVS 1.9 and older
+will delete them any time it writes file attributes. CVS 1.10 and
+later will preserve them.
+
+ Note that the order of the lines is not significant; a program
+writing the fileattr file may rearrange them at its convenience.
+
+ There is currently no way of quoting tabs or line feeds in the
+filename, `=' in ATTRNAME, `;' in ATTRVAL, etc. Note: some
+implementations also don't handle a NUL character in any of the fields,
+but implementations are encouraged to allow it.
+
+ By convention, ATTRNAME starting with `_' is for an attribute given
+special meaning by CVS; other ATTRNAMEs are for user-defined attributes
+(or will be, once implementations start supporting user-defined
+attributes).
+
+ Built-in attributes:
+
+`_watched'
+ Present means the file is watched and should be checked out
+ read-only.
+
+`_watchers'
+ Users with watches for this file. Value is WATCHER > TYPE { ,
+ WATCHER > TYPE } where WATCHER is a username, and TYPE is zero or
+ more of edit,unedit,commit separated by `+' (that is, nothing if
+ none; there is no "none" or "all" keyword).
+
+`_editors'
+ Users editing this file. Value is EDITOR > VAL { , EDITOR > VAL }
+ where EDITOR is a username, and VAL is TIME+HOSTNAME+PATHNAME,
+ where TIME is when the `cvs edit' command (or equivalent) happened,
+ and HOSTNAME and PATHNAME are for the working directory.
+
+ Example:
+
+ Ffile1 _watched=;_watchers=joe>edit,mary>commit
+ Ffile2 _watched=;_editors=sue>8 Jan 1975+workstn1+/home/sue/cvs
+ D _watched=
+
+means that the file `file1' should be checked out read-only.
+Furthermore, joe is watching for edits and mary is watching for
+commits. The file `file2' should be checked out read-only; sue started
+editing it on 8 Jan 1975 in the directory `/home/sue/cvs' on the
+machine `workstn1'. Future files which are added should be checked out
+read-only. To represent this example here, we have shown a space after
+`D', `Ffile1', and `Ffile2', but in fact there must be a single tab
+character there and no spaces.
+
+
+File: cvs.info, Node: Locks, Next: CVSROOT storage, Prev: CVS in repository, Up: Repository storage
+
+2.2.6 CVS locks in the repository
+---------------------------------
+
+For an introduction to CVS locks focusing on user-visible behavior, see
+*Note Concurrency::. The following section is aimed at people who are
+writing tools which want to access a CVS repository without interfering
+with other tools accessing the same repository. If you find yourself
+confused by concepts described here, like "read lock", "write lock",
+and "deadlock", you might consult the literature on operating systems
+or databases.
+
+ Any file in the repository with a name starting with `#cvs.rfl.' is
+a read lock. Any file in the repository with a name starting with
+`#cvs.pfl' is a promotable read lock. Any file in the repository with
+a name starting with `#cvs.wfl' is a write lock. Old versions of CVS
+(before CVS 1.5) also created files with names starting with
+`#cvs.tfl', but they are not discussed here. The directory `#cvs.lock'
+serves as a master lock. That is, one must obtain this lock first
+before creating any of the other locks.
+
+ To obtain a read lock, first create the `#cvs.lock' directory. This
+operation must be atomic (which should be true for creating a directory
+under most operating systems). If it fails because the directory
+already existed, wait for a while and try again. After obtaining the
+`#cvs.lock' lock, create a file whose name is `#cvs.rfl.' followed by
+information of your choice (for example, hostname and process
+identification number). Then remove the `#cvs.lock' directory to
+release the master lock. Then proceed with reading the repository.
+When you are done, remove the `#cvs.rfl' file to release the read lock.
+
+ Promotable read locks are a concept you may not find in other
+literature on concurrency. They are used to allow a two (or more) pass
+process to only lock a file for read on the first (read) pass(es), then
+upgrade its read locks to write locks if necessary for a final pass,
+still assured that the files have not changed since they were first
+read. CVS uses promotable read locks, for example, to prevent commit
+and tag verification passes from interfering with other reading
+processes. It can then lock only a single directory at a time for
+write during the write pass.
+
+ To obtain a promotable read lock, first create the `#cvs.lock'
+directory, as with a non-promotable read lock. Then check that there
+are no files that start with `#cvs.pfl'. If there are, remove the
+master `#cvs.lock' directory, wait awhile (CVS waits 30 seconds between
+lock attempts), and try again. If there are no other promotable locks,
+go ahead and create a file whose name is `#cvs.pfl' followed by
+information of your choice (for example, CVS uses its hostname and the
+process identification number of the CVS server process creating the
+lock). If versions of CVS older than version 1.12.4 access your
+repository directly (not via a CVS server of version 1.12.4 or later),
+then you should also create a read lock since older versions of CVS
+will ignore the promotable lock when attempting to create their own
+write lock. Then remove the master `#cvs.lock' directory in order to
+allow other processes to obtain read locks.
+
+ To obtain a write lock, first create the `#cvs.lock' directory, as
+with read locks. Then check that there are no files whose names start
+with `#cvs.rfl.' and no files whose names start with `#cvs.pfl' that are
+not owned by the process attempting to get the write lock. If either
+exist, remove `#cvs.lock', wait for a while, and try again. If there
+are no readers or promotable locks from other processes, then create a
+file whose name is `#cvs.wfl' followed by information of your choice
+(again, CVS uses the hostname and server process identification
+number). Remove your `#cvs.pfl' file if present. Hang on to the
+`#cvs.lock' lock. Proceed with writing the repository. When you are
+done, first remove the `#cvs.wfl' file and then the `#cvs.lock'
+directory. Note that unlike the `#cvs.rfl' file, the `#cvs.wfl' file is
+just informational; it has no effect on the locking operation beyond
+what is provided by holding on to the `#cvs.lock' lock itself.
+
+ Note that each lock (write lock or read lock) only locks a single
+directory in the repository, including `Attic' and `CVS' but not
+including subdirectories which represent other directories under
+version control. To lock an entire tree, you need to lock each
+directory (note that if you fail to obtain any lock you need, you must
+release the whole tree before waiting and trying again, to avoid
+deadlocks).
+
+ Note also that CVS expects write locks to control access to
+individual `foo,v' files. RCS has a scheme where the `,foo,' file
+serves as a lock, but CVS does not implement it and so taking out a CVS
+write lock is recommended. See the comments at rcs_internal_lockfile
+in the CVS source code for further discussion/rationale.
+
+
+File: cvs.info, Node: CVSROOT storage, Prev: Locks, Up: Repository storage
+
+2.2.7 How files are stored in the CVSROOT directory
+---------------------------------------------------
+
+The `$CVSROOT/CVSROOT' directory contains the various administrative
+files. In some ways this directory is just like any other directory in
+the repository; it contains RCS files whose names end in `,v', and many
+of the CVS commands operate on it the same way. However, there are a
+few differences.
+
+ For each administrative file, in addition to the RCS file, there is
+also a checked out copy of the file. For example, there is an RCS file
+`loginfo,v' and a file `loginfo' which contains the latest revision
+contained in `loginfo,v'. When you check in an administrative file,
+CVS should print
+
+ cvs commit: Rebuilding administrative file database
+
+and update the checked out copy in `$CVSROOT/CVSROOT'. If it does not,
+there is something wrong (*note BUGS::). To add your own files to the
+files to be updated in this fashion, you can add them to the
+`checkoutlist' administrative file (*note checkoutlist::).
+
+ By default, the `modules' file behaves as described above. If the
+modules file is very large, storing it as a flat text file may make
+looking up modules slow (I'm not sure whether this is as much of a
+concern now as when CVS first evolved this feature; I haven't seen
+benchmarks). Therefore, by making appropriate edits to the CVS source
+code one can store the modules file in a database which implements the
+`ndbm' interface, such as Berkeley db or GDBM. If this option is in
+use, then the modules database will be stored in the files `modules.db',
+`modules.pag', and/or `modules.dir'.
+
+ For information on the meaning of the various administrative files,
+see *Note Administrative files::.
+
+
+File: cvs.info, Node: Working directory storage, Next: Intro administrative files, Prev: Repository storage, Up: Repository
+
+2.3 How data is stored in the working directory
+===============================================
+
+While we are discussing CVS internals which may become visible from
+time to time, we might as well talk about what CVS puts in the `CVS'
+directories in the working directories. As with the repository, CVS
+handles this information and one can usually access it via CVS
+commands. But in some cases it may be useful to look at it, and other
+programs, such as the `jCVS' graphical user interface or the `VC'
+package for emacs, may need to look at it. Such programs should follow
+the recommendations in this section if they hope to be able to work
+with other programs which use those files, including future versions of
+the programs just mentioned and the command-line CVS client.
+
+ The `CVS' directory contains several files. Programs which are
+reading this directory should silently ignore files which are in the
+directory but which are not documented here, to allow for future
+expansion.
+
+ The files are stored according to the text file convention for the
+system in question. This means that working directories are not
+portable between systems with differing conventions for storing text
+files. This is intentional, on the theory that the files being managed
+by CVS probably will not be portable between such systems either.
+
+`Root'
+ This file contains the current CVS root, as described in *Note
+ Specifying a repository::.
+
+`Repository'
+ This file contains the directory within the repository which the
+ current directory corresponds with. It can be either an absolute
+ pathname or a relative pathname; CVS has had the ability to read
+ either format since at least version 1.3 or so. The relative
+ pathname is relative to the root, and is the more sensible
+ approach, but the absolute pathname is quite common and
+ implementations should accept either. For example, after the
+ command
+
+ cvs -d :local:/usr/local/cvsroot checkout yoyodyne/tc
+
+ `Root' will contain
+
+ :local:/usr/local/cvsroot
+
+ and `Repository' will contain either
+
+ /usr/local/cvsroot/yoyodyne/tc
+
+ or
+
+ yoyodyne/tc
+
+ If the particular working directory does not correspond to a
+ directory in the repository, then `Repository' should contain
+ `CVSROOT/Emptydir'.
+
+`Entries'
+ This file lists the files and directories in the working directory.
+ The first character of each line indicates what sort of line it
+ is. If the character is unrecognized, programs reading the file
+ should silently skip that line, to allow for future expansion.
+
+ If the first character is `/', then the format is:
+
+ /NAME/REVISION/TIMESTAMP[+CONFLICT]/OPTIONS/TAGDATE
+
+ where `[' and `]' are not part of the entry, but instead indicate
+ that the `+' and conflict marker are optional. NAME is the name
+ of the file within the directory. REVISION is the revision that
+ the file in the working derives from, or `0' for an added file, or
+ `-' followed by a revision for a removed file. TIMESTAMP is the
+ timestamp of the file at the time that CVS created it; if the
+ timestamp differs with the actual modification time of the file it
+ means the file has been modified. It is stored in the format used
+ by the ISO C asctime() function (for example, `Sun Apr 7 01:29:26
+ 1996'). One may write a string which is not in that format, for
+ example, `Result of merge', to indicate that the file should
+ always be considered to be modified. This is not a special case;
+ to see whether a file is modified a program should take the
+ timestamp of the file and simply do a string compare with
+ TIMESTAMP. If there was a conflict, CONFLICT can be set to the
+ modification time of the file after the file has been written with
+ conflict markers (*note Conflicts example::). Thus if CONFLICT is
+ subsequently the same as the actual modification time of the file
+ it means that the user has obviously not resolved the conflict.
+ OPTIONS contains sticky options (for example `-kb' for a binary
+ file). TAGDATE contains `T' followed by a tag name, or `D' for a
+ date, followed by a sticky tag or date. Note that if TIMESTAMP
+ contains a pair of timestamps separated by a space, rather than a
+ single timestamp, you are dealing with a version of CVS earlier
+ than CVS 1.5 (not documented here).
+
+ The timezone on the timestamp in CVS/Entries (local or universal)
+ should be the same as the operating system stores for the
+ timestamp of the file itself. For example, on Unix the file's
+ timestamp is in universal time (UT), so the timestamp in
+ CVS/Entries should be too. On VMS, the file's timestamp is in
+ local time, so CVS on VMS should use local time. This rule is so
+ that files do not appear to be modified merely because the
+ timezone changed (for example, to or from summer time).
+
+ If the first character of a line in `Entries' is `D', then it
+ indicates a subdirectory. `D' on a line all by itself indicates
+ that the program which wrote the `Entries' file does record
+ subdirectories (therefore, if there is such a line and no other
+ lines beginning with `D', one knows there are no subdirectories).
+ Otherwise, the line looks like:
+
+ D/NAME/FILLER1/FILLER2/FILLER3/FILLER4
+
+ where NAME is the name of the subdirectory, and all the FILLER
+ fields should be silently ignored, for future expansion. Programs
+ which modify `Entries' files should preserve these fields.
+
+ The lines in the `Entries' file can be in any order.
+
+`Entries.Log'
+ This file does not record any information beyond that in
+ `Entries', but it does provide a way to update the information
+ without having to rewrite the entire `Entries' file, including the
+ ability to preserve the information even if the program writing
+ `Entries' and `Entries.Log' abruptly aborts. Programs which are
+ reading the `Entries' file should also check for `Entries.Log'.
+ If the latter exists, they should read `Entries' and then apply
+ the changes mentioned in `Entries.Log'. After applying the
+ changes, the recommended practice is to rewrite `Entries' and then
+ delete `Entries.Log'. The format of a line in `Entries.Log' is a
+ single character command followed by a space followed by a line in
+ the format specified for a line in `Entries'. The single
+ character command is `A' to indicate that the entry is being added,
+ `R' to indicate that the entry is being removed, or any other
+ character to indicate that the entire line in `Entries.Log' should
+ be silently ignored (for future expansion). If the second
+ character of the line in `Entries.Log' is not a space, then it was
+ written by an older version of CVS (not documented here).
+
+ Programs which are writing rather than reading can safely ignore
+ `Entries.Log' if they so choose.
+
+`Entries.Backup'
+ This is a temporary file. Recommended usage is to write a new
+ entries file to `Entries.Backup', and then to rename it
+ (atomically, where possible) to `Entries'.
+
+`Entries.Static'
+ The only relevant thing about this file is whether it exists or
+ not. If it exists, then it means that only part of a directory
+ was gotten and CVS will not create additional files in that
+ directory. To clear it, use the `update' command with the `-d'
+ option, which will get the additional files and remove
+ `Entries.Static'.
+
+`Tag'
+ This file contains per-directory sticky tags or dates. The first
+ character is `T' for a branch tag, `N' for a non-branch tag, or
+ `D' for a date, or another character to mean the file should be
+ silently ignored, for future expansion. This character is
+ followed by the tag or date. Note that per-directory sticky tags
+ or dates are used for things like applying to files which are
+ newly added; they might not be the same as the sticky tags or
+ dates on individual files. For general information on sticky tags
+ and dates, see *Note Sticky tags::.
+
+`Notify'
+ This file stores notifications (for example, for `edit' or
+ `unedit') which have not yet been sent to the server. Its format
+ is not yet documented here.
+
+`Notify.tmp'
+ This file is to `Notify' as `Entries.Backup' is to `Entries'.
+ That is, to write `Notify', first write the new contents to
+ `Notify.tmp' and then (atomically where possible), rename it to
+ `Notify'.
+
+`Base'
+ If watches are in use, then an `edit' command stores the original
+ copy of the file in the `Base' directory. This allows the
+ `unedit' command to operate even if it is unable to communicate
+ with the server.
+
+`Baserev'
+ The file lists the revision for each of the files in the `Base'
+ directory. The format is:
+
+ BNAME/REV/EXPANSION
+
+ where EXPANSION should be ignored, to allow for future expansion.
+
+`Baserev.tmp'
+ This file is to `Baserev' as `Entries.Backup' is to `Entries'.
+ That is, to write `Baserev', first write the new contents to
+ `Baserev.tmp' and then (atomically where possible), rename it to
+ `Baserev'.
+
+`Template'
+ This file contains the template specified by the `rcsinfo' file
+ (*note rcsinfo::). It is only used by the client; the
+ non-client/server CVS consults `rcsinfo' directly.
+
+
+File: cvs.info, Node: Intro administrative files, Next: Multiple repositories, Prev: Working directory storage, Up: Repository
+
+2.4 The administrative files
+============================
+
+The directory `$CVSROOT/CVSROOT' contains some "administrative files".
+*Note Administrative files::, for a complete description. You can use
+CVS without any of these files, but some commands work better when at
+least the `modules' file is properly set up.
+
+ The most important of these files is the `modules' file. It defines
+all modules in the repository. This is a sample `modules' file.
+
+ CVSROOT CVSROOT
+ modules CVSROOT modules
+ cvs gnu/cvs
+ rcs gnu/rcs
+ diff gnu/diff
+ tc yoyodyne/tc
+
+ The `modules' file is line oriented. In its simplest form each line
+contains the name of the module, whitespace, and the directory where
+the module resides. The directory is a path relative to `$CVSROOT'.
+The last four lines in the example above are examples of such lines.
+
+ The line that defines the module called `modules' uses features that
+are not explained here. *Note modules::, for a full explanation of all
+the available features.
+
+2.4.1 Editing administrative files
+----------------------------------
+
+You edit the administrative files in the same way that you would edit
+any other module. Use `cvs checkout CVSROOT' to get a working copy,
+edit it, and commit your changes in the normal way.
+
+ It is possible to commit an erroneous administrative file. You can
+often fix the error and check in a new revision, but sometimes a
+particularly bad error in the administrative file makes it impossible
+to commit new revisions.
+
+
+File: cvs.info, Node: Multiple repositories, Next: Creating a repository, Prev: Intro administrative files, Up: Repository
+
+2.5 Multiple repositories
+=========================
+
+In some situations it is a good idea to have more than one repository,
+for instance if you have two development groups that work on separate
+projects without sharing any code. All you have to do to have several
+repositories is to specify the appropriate repository, using the
+`CVSROOT' environment variable, the `-d' option to CVS, or (once you
+have checked out a working directory) by simply allowing CVS to use the
+repository that was used to check out the working directory (*note
+Specifying a repository::).
+
+ The big advantage of having multiple repositories is that they can
+reside on different servers. With CVS version 1.10, a single command
+cannot recurse into directories from different repositories. With
+development versions of CVS, you can check out code from multiple
+servers into your working directory. CVS will recurse and handle all
+the details of making connections to as many server machines as
+necessary to perform the requested command. Here is an example of how
+to set up a working directory:
+
+ cvs -d server1:/cvs co dir1
+ cd dir1
+ cvs -d server2:/root co sdir
+ cvs update
+
+ The `cvs co' commands set up the working directory, and then the
+`cvs update' command will contact server2, to update the dir1/sdir
+subdirectory, and server1, to update everything else.
+
+
+File: cvs.info, Node: Creating a repository, Next: Backing up, Prev: Multiple repositories, Up: Repository
+
+2.6 Creating a repository
+=========================
+
+This section describes how to set up a CVS repository for any sort of
+access method. After completing the setup described in this section,
+you should be able to access your CVS repository immediately via the
+local access method and several remote access methods. For more
+information on setting up remote access to the repository you create in
+this section, please read the section on *Note Remote repositories::.
+
+ To set up a CVS repository, first choose the machine and disk on
+which you want to store the revision history of the source files. CPU
+and memory requirements are modest, so most machines should be
+adequate. For details see *Note Server requirements::.
+
+ To estimate disk space requirements, if you are importing RCS files
+from another system, the size of those files is the approximate initial
+size of your repository, or if you are starting without any version
+history, a rule of thumb is to allow for the server approximately three
+times the size of the code to be under CVS for the repository (you will
+eventually outgrow this, but not for a while). On the machines on
+which the developers will be working, you'll want disk space for
+approximately one working directory for each developer (either the
+entire tree or a portion of it, depending on what each developer uses).
+
+ The repository should be accessible (directly or via a networked
+file system) from all machines which want to use CVS in server or local
+mode; the client machines need not have any access to it other than via
+the CVS protocol. It is not possible to use CVS to read from a
+repository which one only has read access to; CVS needs to be able to
+create lock files (*note Concurrency::).
+
+ To create a repository, run the `cvs init' command. It will set up
+an empty repository in the CVS root specified in the usual way (*note
+Repository::). For example,
+
+ cvs -d /usr/local/cvsroot init
+
+ `cvs init' is careful to never overwrite any existing files in the
+repository, so no harm is done if you run `cvs init' on an already
+set-up repository.
+
+ `cvs init' will enable history logging; if you don't want that,
+remove the history file after running `cvs init'. *Note history file::.
+
+
+File: cvs.info, Node: Backing up, Next: Moving a repository, Prev: Creating a repository, Up: Repository
+
+2.7 Backing up a repository
+===========================
+
+There is nothing particularly magical about the files in the
+repository; for the most part it is possible to back them up just like
+any other files. However, there are a few issues to consider.
+
+ The first is that to be paranoid, one should either not use CVS
+during the backup, or have the backup program lock CVS while doing the
+backup. To not use CVS, you might forbid logins to machines which can
+access the repository, turn off your CVS server, or similar mechanisms.
+The details would depend on your operating system and how you have CVS
+set up. To lock CVS, you would create `#cvs.rfl' locks in each
+repository directory. See *Note Concurrency::, for more on CVS locks.
+Having said all this, if you just back up without any of these
+precautions, the results are unlikely to be particularly dire.
+Restoring from backup, the repository might be in an inconsistent
+state, but this would not be particularly hard to fix manually.
+
+ When you restore a repository from backup, assuming that changes in
+the repository were made after the time of the backup, working
+directories which were not affected by the failure may refer to
+revisions which no longer exist in the repository. Trying to run CVS
+in such directories will typically produce an error message. One way
+to get those changes back into the repository is as follows:
+
+ * Get a new working directory.
+
+ * Copy the files from the working directory from before the failure
+ over to the new working directory (do not copy the contents of the
+ `CVS' directories, of course).
+
+ * Working in the new working directory, use commands such as `cvs
+ update' and `cvs diff' to figure out what has changed, and then
+ when you are ready, commit the changes into the repository.
+
+
+File: cvs.info, Node: Moving a repository, Next: Remote repositories, Prev: Backing up, Up: Repository
+
+2.8 Moving a repository
+=======================
+
+Just as backing up the files in the repository is pretty much like
+backing up any other files, if you need to move a repository from one
+place to another it is also pretty much like just moving any other
+collection of files.
+
+ The main thing to consider is that working directories point to the
+repository. The simplest way to deal with a moved repository is to
+just get a fresh working directory after the move. Of course, you'll
+want to make sure that the old working directory had been checked in
+before the move, or you figured out some other way to make sure that
+you don't lose any changes. If you really do want to reuse the existing
+working directory, it should be possible with manual surgery on the
+`CVS/Repository' files. You can see *Note Working directory storage::,
+for information on the `CVS/Repository' and `CVS/Root' files, but
+unless you are sure you want to bother, it probably isn't worth it.
+
+
+File: cvs.info, Node: Remote repositories, Next: Read-only access, Prev: Moving a repository, Up: Repository
+
+2.9 Remote repositories
+=======================
+
+Your working copy of the sources can be on a different machine than the
+repository. Using CVS in this manner is known as "client/server"
+operation. You run CVS on a machine which can mount your working
+directory, known as the "client", and tell it to communicate to a
+machine which can mount the repository, known as the "server".
+Generally, using a remote repository is just like using a local one,
+except that the format of the repository name is:
+
+ [:METHOD:][[USER][:PASSWORD]@]HOSTNAME[:[PORT]]/path/to/repository
+
+ Specifying a password in the repository name is not recommended
+during checkout, since this will cause CVS to store a cleartext copy of
+the password in each created directory. `cvs login' first instead
+(*note Password authentication client::).
+
+ The details of exactly what needs to be set up depend on how you are
+connecting to the server.
+
+* Menu:
+
+* Server requirements:: Memory and other resources for servers
+* The connection method:: Connection methods and method options
+* Connecting via rsh:: Using the `rsh' program to connect
+* Password authenticated:: Direct connections using passwords
+* GSSAPI authenticated:: Direct connections using GSSAPI
+* Kerberos authenticated:: Direct connections with Kerberos
+* Connecting via fork:: Using a forked `cvs server' to connect
+* Write proxies:: Distributing load across several CVS servers
+
+
+File: cvs.info, Node: Server requirements, Next: The connection method, Up: Remote repositories
+
+2.9.1 Server requirements
+-------------------------
+
+The quick answer to what sort of machine is suitable as a server is
+that requirements are modest--a server with 32M of memory or even less
+can handle a fairly large source tree with a fair amount of activity.
+
+ The real answer, of course, is more complicated. Estimating the
+known areas of large memory consumption should be sufficient to
+estimate memory requirements. There are two such areas documented
+here; other memory consumption should be small by comparison (if you
+find that is not the case, let us know, as described in *Note BUGS::,
+so we can update this documentation).
+
+ The first area of big memory consumption is large checkouts, when
+using the CVS server. The server consists of two processes for each
+client that it is serving. Memory consumption on the child process
+should remain fairly small. Memory consumption on the parent process,
+particularly if the network connection to the client is slow, can be
+expected to grow to slightly more than the size of the sources in a
+single directory, or two megabytes, whichever is larger.
+
+ Multiplying the size of each CVS server by the number of servers
+which you expect to have active at one time should give an idea of
+memory requirements for the server. For the most part, the memory
+consumed by the parent process probably can be swap space rather than
+physical memory.
+
+ The second area of large memory consumption is `diff', when checking
+in large files. This is required even for binary files. The rule of
+thumb is to allow about ten times the size of the largest file you will
+want to check in, although five times may be adequate. For example, if
+you want to check in a file which is 10 megabytes, you should have 100
+megabytes of memory on the machine doing the checkin (the server
+machine for client/server, or the machine running CVS for
+non-client/server). This can be swap space rather than physical
+memory. Because the memory is only required briefly, there is no
+particular need to allow memory for more than one such checkin at a
+time.
+
+ Resource consumption for the client is even more modest--any machine
+with enough capacity to run the operating system in question should
+have little trouble.
+
+ For information on disk space requirements, see *Note Creating a
+repository::.
+
+
+File: cvs.info, Node: The connection method, Next: Connecting via rsh, Prev: Server requirements, Up: Remote repositories
+
+2.9.2 The connection method
+---------------------------
+
+In its simplest form, the METHOD portion of the repository string
+(*note Remote repositories::) may be one of `ext', `fork', `gserver',
+`kserver', `local', `pserver', and, on some platforms, `server'.
+
+ If METHOD is not specified, and the repository name starts with a
+`/', then the default is `local'. If METHOD is not specified, and the
+repository name does not start with a `/', then the default is `ext' or
+`server', depending on your platform; both the `ext' and `server'
+methods are described in *Note Connecting via rsh::.
+
+ The `ext', `fork', `gserver', and `pserver' connection methods all
+accept optional method options, specified as part of the METHOD string,
+like so:
+
+ :METHOD[;OPTION=ARG...]:OTHER_CONNECTION_DATA
+
+ CVS is not sensitive to the case of METHOD or OPTION, though it may
+sometimes be sensitive to the case of ARG. The possible method options
+are as follows:
+
+`proxy=HOSTNAME'
+`proxyport=PORT'
+ These two method options can be used to connect via an HTTP tunnel
+ style web proxy. HOSTNAME should be the name of the HTTP proxy
+ server to connect through and PORT is the port number on the HTTP
+ proxy server to connect via. PORT defaults to 8080.
+
+ *NOTE_ An HTTP proxy server is not the same as a CVS write proxy
+ server - please see *Note Write proxies:: for more on CVS write
+ proxies.*
+
+ For example, to connect pserver via a web proxy listening on port
+ 8000 of www.myproxy.net, you would use a method of:
+
+ :pserver;proxy=www.myproxy.net;proxyport=8000:PSERVER_CONNECTION_STRING
+
+ *NOTE_ In the above example, PSERVER_CONNECTION_STRING is still
+ required to connect and authenticate to the CVS server, as noted
+ in the upcoming sections on password authentication, `gserver', and
+ `kserver'. The example above only demonstrates a modification to
+ the METHOD portion of the repository name.*
+
+ These options first appeared in CVS version 1.12.7 and are valid as
+ modifcations to the `gserver' and `pserver' connection methods.
+
+`CVS_RSH=PATH'
+ This method option can be used with the `ext' method to specify
+ the path the CVS client will use to find the remote shell used to
+ contact the CVS server and takes precedence over any path
+ specified in the `$CVS_RSH' environment variable (*note Connecting
+ via rsh::). For example, to connect to a CVS server via the local
+ `/path/to/ssh/command' command, you could choose to specify the
+ following PATH via the `CVS_RSH' method option:
+
+ :ext;CVS_RSH=/path/to/ssh/command:EXT_CONNECTION_STRING
+
+ This method option first appeared in CVS version 1.12.11 and is
+ valid only as a modifcation to the `ext' connection method.
+
+`CVS_SERVER=PATH'
+ This method option can be used with the `ext' and `fork' methods to
+ specify the path CVS will use to find the CVS executable on the
+ CVS server and takes precedence over any path specified in the
+ `$CVS_SERVER' environment variable (*note Connecting via rsh::).
+ For example, to select the remote `/path/to/cvs/command'
+ executable as your CVS server application on the CVS server
+ machine, you could choose to specify the following PATH via the
+ `CVS_SERVER' method option:
+
+ :ext;CVS_SERVER=/path/to/cvs/command:EXT_CONNECTION_STRING
+
+ or, to select an executable named `cvs-1.12.11', assuming it is in
+ your `$PATH' on the CVS server:
+
+ :ext;CVS_SERVER=cvs-1.12.11:EXT_CONNECTION_STRING
+
+ This method option first appeared in CVS version 1.12.11 and is
+ valid as a modifcation to both the `ext' and `fork' connection
+ methods.
+
+`Redirect=BOOLEAN-STATE'
+ The `Redirect' method option determines whether the CVS client will
+ allow a CVS server to redirect it to a different CVS server,
+ usually for write requests, as in a write proxy setup.
+
+ A BOOLEAN-STATE of any value acceptable for boolean
+ `CVSROOT/config' file options is acceptable here (*note config::).
+ For example, `on', `off', `true', and `false' are all valid
+ values for BOOLEAN-STATE. BOOLEAN-STATE for the `Redirect' method
+ option defaults to `on'.
+
+ This option will have no effect when talking to any non-secondary
+ CVS server. For more on write proxies and secondary servers,
+ please see *Note Write proxies::.
+
+ This method option first appeared in CVS version 1.12.11 and is
+ valid only as a modifcation to the `ext' connection method.
+
+ As a further example, to combine both the `CVS_RSH' and `CVS_SERVER'
+options, a method specification like the following would work:
+
+ :ext;CVS_RSH=/path/to/ssh/command;CVS_SERVER=/path/to/cvs/command:
+
+ This means that you would not need to have the `CVS_SERVER' or
+`CVS_RSH' environment variables set correctly. See *Note Connecting
+via rsh::, for more details on these environment variables.
+
+
+File: cvs.info, Node: Connecting via rsh, Next: Password authenticated, Prev: The connection method, Up: Remote repositories
+
+2.9.3 Connecting with rsh
+-------------------------
+
+CVS uses the `rsh' protocol to perform these operations, so the remote
+user host needs to have a `.rhosts' file which grants access to the
+local user. Note that the program that CVS uses for this purpose may be
+specified using the `--with-rsh' flag to configure.
+
+ For example, suppose you are the user `mozart' on the local machine
+`toe.example.com', and the server machine is `faun.example.org'. On
+faun, put the following line into the file `.rhosts' in `bach''s home
+directory:
+
+ toe.example.com mozart
+
+Then test that `rsh' is working with
+
+ rsh -l bach faun.example.org 'echo $PATH'
+
+ Next you have to make sure that `rsh' will be able to find the
+server. Make sure that the path which `rsh' printed in the above
+example includes the directory containing a program named `cvs' which
+is the server. You need to set the path in `.bashrc', `.cshrc', etc.,
+not `.login' or `.profile'. Alternately, you can set the environment
+variable `CVS_SERVER' on the client machine to the filename of the
+server you want to use, for example `/usr/local/bin/cvs-1.6'. For the
+`ext' and `fork' methods, you may also specify CVS_SERVER as an otpion
+in the CVSROOT so that you may use different servers for differnt
+roots. See *Note Remote repositories:: for more details.
+
+ There is no need to edit `inetd.conf' or start a CVS server daemon.
+
+ There are two access methods that you use in `CVSROOT' for rsh.
+`:server:' specifies an internal rsh client, which is supported only by
+some CVS ports. `:ext:' specifies an external rsh program. By default
+this is `rsh' (unless otherwise specified by the `--with-rsh' flag to
+configure) but you may set the `CVS_RSH' environment variable to invoke
+another program which can access the remote server (for example,
+`remsh' on HP-UX 9 because `rsh' is something different). It must be a
+program which can transmit data to and from the server without modifying
+it; for example the Windows NT `rsh' is not suitable since it by
+default translates between CRLF and LF. The OS/2 CVS port has a hack
+to pass `-b' to `rsh' to get around this, but since this could
+potentially cause problems for programs other than the standard `rsh',
+it may change in the future. If you set `CVS_RSH' to `SSH' or some
+other rsh replacement, the instructions in the rest of this section
+concerning `.rhosts' and so on are likely to be inapplicable; consult
+the documentation for your rsh replacement.
+
+ You may choose to specify the CVS_RSH option as a method option in
+the CVSROOT string to allow you to use different connection tools for
+different roots (*note The connection method::). For example, allowing
+some roots to use `CVS_RSH=remsh' and some to use `CVS_RSH=ssh' for the
+`ext' method. See also the *Note Remote repositories:: for more
+details.
+
+ Continuing our example, supposing you want to access the module
+`foo' in the repository `/usr/local/cvsroot/', on machine
+`faun.example.org', you are ready to go:
+
+ cvs -d :ext:bach@faun.example.org:/usr/local/cvsroot checkout foo
+
+(The `bach@' can be omitted if the username is the same on both the
+local and remote hosts.)
+
+
+File: cvs.info, Node: Password authenticated, Next: GSSAPI authenticated, Prev: Connecting via rsh, Up: Remote repositories
+
+2.9.4 Direct connection with password authentication
+----------------------------------------------------
+
+The CVS client can also connect to the server using a password
+protocol. This is particularly useful if using `rsh' is not feasible
+(for example, the server is behind a firewall), and Kerberos also is
+not available.
+
+ To use this method, it is necessary to make some adjustments on both
+the server and client sides.
+
+* Menu:
+
+* Password authentication server:: Setting up the server
+* Password authentication client:: Using the client
+* Password authentication security:: What this method does and does not do
+
+
+File: cvs.info, Node: Password authentication server, Next: Password authentication client, Up: Password authenticated
+
+2.9.4.1 Setting up the server for password authentication
+.........................................................
+
+First of all, you probably want to tighten the permissions on the
+`$CVSROOT' and `$CVSROOT/CVSROOT' directories. See *Note Password
+authentication security::, for more details.
+
+ On the server side, the file `/etc/inetd.conf' needs to be edited so
+`inetd' knows to run the command `cvs pserver' when it receives a
+connection on the right port. By default, the port number is 2401; it
+would be different if your client were compiled with `CVS_AUTH_PORT'
+defined to something else, though. This can also be specified in the
+CVSROOT variable (*note Remote repositories::) or overridden with the
+CVS_CLIENT_PORT environment variable (*note Environment variables::).
+
+ If your `inetd' allows raw port numbers in `/etc/inetd.conf', then
+the following (all on a single line in `inetd.conf') should be
+sufficient:
+
+ 2401 stream tcp nowait root /usr/local/bin/cvs
+ cvs -f --allow-root=/usr/cvsroot pserver
+
+(You could also use the `-T' option to specify a temporary directory.)
+
+ The `--allow-root' option specifies the allowable CVSROOT directory.
+Clients which attempt to use a different CVSROOT directory will not be
+allowed to connect. If there is more than one CVSROOT directory which
+you want to allow, repeat the option. (Unfortunately, many versions of
+`inetd' have very small limits on the number of arguments and/or the
+total length of the command. The usual solution to this problem is to
+have `inetd' run a shell script which then invokes CVS with the
+necessary arguments.)
+
+ If your `inetd' wants a symbolic service name instead of a raw port
+number, then put this in `/etc/services':
+
+ cvspserver 2401/tcp
+
+and put `cvspserver' instead of `2401' in `inetd.conf'.
+
+ If your system uses `xinetd' instead of `inetd', the procedure is
+slightly different. Create a file called `/etc/xinetd.d/cvspserver'
+containing the following:
+
+ service cvspserver
+ {
+ port = 2401
+ socket_type = stream
+ protocol = tcp
+ wait = no
+ user = root
+ passenv = PATH
+ server = /usr/local/bin/cvs
+ server_args = -f --allow-root=/usr/cvsroot pserver
+ }
+
+(If `cvspserver' is defined in `/etc/services', you can omit the `port'
+line.)
+
+ Once the above is taken care of, restart your `inetd', or do
+whatever is necessary to force it to reread its initialization files.
+
+ If you are having trouble setting this up, see *Note Connection::.
+
+ Because the client stores and transmits passwords in cleartext
+(almost--see *Note Password authentication security::, for details), a
+separate CVS password file is generally used, so people don't compromise
+their regular passwords when they access the repository. This file is
+`$CVSROOT/CVSROOT/passwd' (*note Intro administrative files::). It
+uses a colon-separated format, similar to `/etc/passwd' on Unix systems,
+except that it has fewer fields: CVS username, optional password, and
+an optional system username for CVS to run as if authentication
+succeeds. Here is an example `passwd' file with five entries:
+
+ anonymous:
+ bach:ULtgRLXo7NRxs
+ spwang:1sOp854gDF3DY
+ melissa:tGX1fS8sun6rY:pubcvs
+ qproj:XR4EZcEs0szik:pubcvs
+
+(The passwords are encrypted according to the standard Unix `crypt()'
+function, so it is possible to paste in passwords directly from regular
+Unix `/etc/passwd' files.)
+
+ The first line in the example will grant access to any CVS client
+attempting to authenticate as user `anonymous', no matter what password
+they use, including an empty password. (This is typical for sites
+granting anonymous read-only access; for information on how to do the
+"read-only" part, see *Note Read-only access::.)
+
+ The second and third lines will grant access to `bach' and `spwang'
+if they supply their respective plaintext passwords.
+
+ The fourth line will grant access to `melissa', if she supplies the
+correct password, but her CVS operations will actually run on the
+server side under the system user `pubcvs'. Thus, there need not be
+any system user named `melissa', but there _must_ be one named `pubcvs'.
+
+ The fifth line shows that system user identities can be shared: any
+client who successfully authenticates as `qproj' will actually run as
+`pubcvs', just as `melissa' does. That way you could create a single,
+shared system user for each project in your repository, and give each
+developer their own line in the `$CVSROOT/CVSROOT/passwd' file. The CVS
+username on each line would be different, but the system username would
+be the same. The reason to have different CVS usernames is that CVS
+will log their actions under those names: when `melissa' commits a
+change to a project, the checkin is recorded in the project's history
+under the name `melissa', not `pubcvs'. And the reason to have them
+share a system username is so that you can arrange permissions in the
+relevant area of the repository such that only that account has
+write-permission there.
+
+ If the system-user field is present, all password-authenticated CVS
+commands run as that user; if no system user is specified, CVS simply
+takes the CVS username as the system username and runs commands as that
+user. In either case, if there is no such user on the system, then the
+CVS operation will fail (regardless of whether the client supplied a
+valid password).
+
+ The password and system-user fields can both be omitted (and if the
+system-user field is omitted, then also omit the colon that would have
+separated it from the encrypted password). For example, this would be a
+valid `$CVSROOT/CVSROOT/passwd' file:
+
+ anonymous::pubcvs
+ fish:rKa5jzULzmhOo:kfogel
+ sussman:1sOp854gDF3DY
+
+When the password field is omitted or empty, then the client's
+authentication attempt will succeed with any password, including the
+empty string. However, the colon after the CVS username is always
+necessary, even if the password is empty.
+
+ CVS can also fall back to use system authentication. When
+authenticating a password, the server first checks for the user in the
+`$CVSROOT/CVSROOT/passwd' file. If it finds the user, it will use that
+entry for authentication as described above. But if it does not find
+the user, or if the CVS `passwd' file does not exist, then the server
+can try to authenticate the username and password using the operating
+system's user-lookup routines (this "fallback" behavior can be disabled
+by setting `SystemAuth=no' in the CVS `config' file, *note config::).
+
+ The default fallback behavior is to look in `/etc/passwd' for this
+system user unless your system has PAM (Pluggable Authentication
+Modules) and your CVS server executable was configured to use it at
+compile time (using `./configure --enable-pam' - see the INSTALL file
+for more). In this case, PAM will be consulted instead. This means
+that CVS can be configured to use any password authentication source
+PAM can be configured to use (possibilities include a simple UNIX
+password, NIS, LDAP, and others) in its global configuration file
+(usually `/etc/pam.conf' or possibly `/etc/pam.d/cvs'). See your PAM
+documentation for more details on PAM configuration.
+
+ Note that PAM is an experimental feature in CVS and feedback is
+encouraged. Please send a mail to one of the CVS mailing lists
+(`info-cvs@nongnu.org' or `bug-cvs@nongnu.org') if you use the CVS PAM
+support.
+
+ *WARNING: Using PAM gives the system administrator much more
+flexibility about how CVS users are authenticated but no more security
+than other methods. See below for more.*
+
+ CVS needs an "auth", "account" and "session" module in the PAM
+configuration file. A typical PAM configuration would therefore have
+the following lines in `/etc/pam.conf' to emulate the standard CVS
+system `/etc/passwd' authentication:
+
+ cvs auth required pam_unix.so
+ cvs account required pam_unix.so
+ cvs session required pam_unix.so
+
+ The the equivalent `/etc/pam.d/cvs' would contain
+
+ auth required pam_unix.so
+ account required pam_unix.so
+ session required pam_unix.so
+
+ Some systems require a full path to the module so that `pam_unix.so'
+(Linux) would become something like
+`/usr/lib/security/$ISA/pam_unix.so.1' (Sun Solaris). See the
+`contrib/pam' subdirectory of the CVS source distribution for further
+example configurations.
+
+ The PAM service name given above as "cvs" is just the service name
+in the default configuration and can be set using `./configure
+--with-hardcoded-pam-service-name=<pam-service-name>' before compiling.
+CVS can also be configured to use whatever name it is invoked as as
+its PAM service name using `./configure
+--without-hardcoded-pam-service-name', but this feature should not be
+used if you may not have control of the name CVS will be invoked as.
+
+ Be aware, also, that falling back to system authentication might be
+a security risk: CVS operations would then be authenticated with that
+user's regular login password, and the password flies across the
+network in plaintext. See *Note Password authentication security:: for
+more on this. This may be more of a problem with PAM authentication
+because it is likely that the source of the system password is some
+central authentication service like LDAP which is also used to
+authenticate other services.
+
+ On the other hand, PAM makes it very easy to change your password
+regularly. If they are given the option of a one-password system for
+all of their activities, users are often more willing to change their
+password on a regular basis.
+
+ In the non-PAM configuration where the password is stored in the
+`CVSROOT/passwd' file, it is difficult to change passwords on a regular
+basis since only administrative users (or in some cases processes that
+act as an administrative user) are typically given access to modify
+this file. Either there needs to be some hand-crafted web page or
+set-uid program to update the file, or the update needs to be done by
+submitting a request to an administrator to perform the duty by hand.
+In the first case, having to remember to update a separate password on
+a periodic basis can be difficult. In the second case, the manual
+nature of the change will typically mean that the password will not be
+changed unless it is absolutely necessary.
+
+ Note that PAM administrators should probably avoid configuring
+one-time-passwords (OTP) for CVS authentication/authorization. If OTPs
+are desired, the administrator may wish to encourage the use of one of
+the other Client/Server access methods. See the section on *note
+Remote repositories:: for a list of other methods.
+
+ Right now, the only way to put a password in the CVS `passwd' file
+is to paste it there from somewhere else. Someday, there may be a `cvs
+passwd' command.
+
+ Unlike many of the files in `$CVSROOT/CVSROOT', it is normal to edit
+the `passwd' file in-place, rather than via CVS. This is because of the
+possible security risks of having the `passwd' file checked out to
+people's working copies. If you do want to include the `passwd' file
+in checkouts of `$CVSROOT/CVSROOT', see *Note checkoutlist::.
+
+
+File: cvs.info, Node: Password authentication client, Next: Password authentication security, Prev: Password authentication server, Up: Password authenticated
+
+2.9.4.2 Using the client with password authentication
+.....................................................
+
+To run a CVS command on a remote repository via the
+password-authenticating server, one specifies the `pserver' protocol,
+optional username, repository host, an optional port number, and path
+to the repository. For example:
+
+ cvs -d :pserver:faun.example.org:/usr/local/cvsroot checkout someproj
+
+or
+
+ CVSROOT=:pserver:bach@faun.example.org:2401/usr/local/cvsroot
+ cvs checkout someproj
+
+ However, unless you're connecting to a public-access repository
+(i.e., one where that username doesn't require a password), you'll need
+to supply a password or "log in" first. Logging in verifies your
+password with the repository and stores it in a file. It's done with
+the `login' command, which will prompt you interactively for the
+password if you didn't supply one as part of $CVSROOT:
+
+ cvs -d :pserver:bach@faun.example.org:/usr/local/cvsroot login
+ CVS password:
+
+or
+
+ cvs -d :pserver:bach:p4ss30rd@faun.example.org:/usr/local/cvsroot login
+
+ After you enter the password, CVS verifies it with the server. If
+the verification succeeds, then that combination of username, host,
+repository, and password is permanently recorded, so future
+transactions with that repository won't require you to run `cvs login'.
+(If verification fails, CVS will exit complaining that the password
+was incorrect, and nothing will be recorded.)
+
+ The records are stored, by default, in the file `$HOME/.cvspass'.
+That file's format is human-readable, and to a degree human-editable,
+but note that the passwords are not stored in cleartext--they are
+trivially encoded to protect them from "innocent" compromise (i.e.,
+inadvertent viewing by a system administrator or other non-malicious
+person).
+
+ You can change the default location of this file by setting the
+`CVS_PASSFILE' environment variable. If you use this variable, make
+sure you set it _before_ `cvs login' is run. If you were to set it
+after running `cvs login', then later CVS commands would be unable to
+look up the password for transmission to the server.
+
+ Once you have logged in, all CVS commands using that remote
+repository and username will authenticate with the stored password.
+So, for example
+
+ cvs -d :pserver:bach@faun.example.org:/usr/local/cvsroot checkout foo
+
+should just work (unless the password changes on the server side, in
+which case you'll have to re-run `cvs login').
+
+ Note that if the `:pserver:' were not present in the repository
+specification, CVS would assume it should use `rsh' to connect with the
+server instead (*note Connecting via rsh::).
+
+ Of course, once you have a working copy checked out and are running
+CVS commands from within it, there is no longer any need to specify the
+repository explicitly, because CVS can deduce the repository from the
+working copy's `CVS' subdirectory.
+
+ The password for a given remote repository can be removed from the
+`CVS_PASSFILE' by using the `cvs logout' command.
+
+
+File: cvs.info, Node: Password authentication security, Prev: Password authentication client, Up: Password authenticated
+
+2.9.4.3 Security considerations with password authentication
+............................................................
+
+The passwords are stored on the client side in a trivial encoding of
+the cleartext, and transmitted in the same encoding. The encoding is
+done only to prevent inadvertent password compromises (i.e., a system
+administrator accidentally looking at the file), and will not prevent
+even a naive attacker from gaining the password.
+
+ The separate CVS password file (*note Password authentication
+server::) allows people to use a different password for repository
+access than for login access. On the other hand, once a user has
+non-read-only access to the repository, she can execute programs on the
+server system through a variety of means. Thus, repository access
+implies fairly broad system access as well. It might be possible to
+modify CVS to prevent that, but no one has done so as of this writing.
+
+ Note that because the `$CVSROOT/CVSROOT' directory contains `passwd'
+and other files which are used to check security, you must control the
+permissions on this directory as tightly as the permissions on `/etc'.
+The same applies to the `$CVSROOT' directory itself and any directory
+above it in the tree. Anyone who has write access to such a directory
+will have the ability to become any user on the system. Note that
+these permissions are typically tighter than you would use if you are
+not using pserver.
+
+ In summary, anyone who gets the password gets repository access
+(which may imply some measure of general system access as well). The
+password is available to anyone who can sniff network packets or read a
+protected (i.e., user read-only) file. If you want real security, get
+Kerberos.
+
+
+File: cvs.info, Node: GSSAPI authenticated, Next: Kerberos authenticated, Prev: Password authenticated, Up: Remote repositories
+
+2.9.5 Direct connection with GSSAPI
+-----------------------------------
+
+GSSAPI is a generic interface to network security systems such as
+Kerberos 5. If you have a working GSSAPI library, you can have CVS
+connect via a direct TCP connection, authenticating with GSSAPI.
+
+ To do this, CVS needs to be compiled with GSSAPI support; when
+configuring CVS it tries to detect whether GSSAPI libraries using
+Kerberos version 5 are present. You can also use the `--with-gssapi'
+flag to configure.
+
+ The connection is authenticated using GSSAPI, but the message stream
+is _not_ authenticated by default. You must use the `-a' global option
+to request stream authentication.
+
+ The data transmitted is _not_ encrypted by default. Encryption
+support must be compiled into both the client and the server; use the
+`--enable-encrypt' configure option to turn it on. You must then use
+the `-x' global option to request encryption.
+
+ GSSAPI connections are handled on the server side by the same server
+which handles the password authentication server; see *Note Password
+authentication server::. If you are using a GSSAPI mechanism such as
+Kerberos which provides for strong authentication, you will probably
+want to disable the ability to authenticate via cleartext passwords.
+To do so, create an empty `CVSROOT/passwd' password file, and set
+`SystemAuth=no' in the config file (*note config::).
+
+ The GSSAPI server uses a principal name of cvs/HOSTNAME, where
+HOSTNAME is the canonical name of the server host. You will have to
+set this up as required by your GSSAPI mechanism.
+
+ To connect using GSSAPI, use the `:gserver:' method. For example,
+
+ cvs -d :gserver:faun.example.org:/usr/local/cvsroot checkout foo
+
+
+File: cvs.info, Node: Kerberos authenticated, Next: Connecting via fork, Prev: GSSAPI authenticated, Up: Remote repositories
+
+2.9.6 Direct connection with Kerberos
+-------------------------------------
+
+The easiest way to use Kerberos is to use the Kerberos `rsh', as
+described in *Note Connecting via rsh::. The main disadvantage of
+using rsh is that all the data needs to pass through additional
+programs, so it may be slower. So if you have Kerberos installed you
+can connect via a direct TCP connection, authenticating with Kerberos.
+
+ This section concerns the Kerberos network security system, version
+4. Kerberos version 5 is supported via the GSSAPI generic network
+security interface, as described in the previous section.
+
+ To do this, CVS needs to be compiled with Kerberos support; when
+configuring CVS it tries to detect whether Kerberos is present or you
+can use the `--with-krb4' flag to configure.
+
+ The data transmitted is _not_ encrypted by default. Encryption
+support must be compiled into both the client and server; use the
+`--enable-encryption' configure option to turn it on. You must then
+use the `-x' global option to request encryption.
+
+ The CVS client will attempt to connect to port 1999 by default.
+
+ When you want to use CVS, get a ticket in the usual way (generally
+`kinit'); it must be a ticket which allows you to log into the server
+machine. Then you are ready to go:
+
+ cvs -d :kserver:faun.example.org:/usr/local/cvsroot checkout foo
+
+ Previous versions of CVS would fall back to a connection via rsh;
+this version will not do so.
+
+
+File: cvs.info, Node: Connecting via fork, Next: Write proxies, Prev: Kerberos authenticated, Up: Remote repositories
+
+2.9.7 Connecting with fork
+--------------------------
+
+This access method allows you to connect to a repository on your local
+disk via the remote protocol. In other words it does pretty much the
+same thing as `:local:', but various quirks, bugs and the like are
+those of the remote CVS rather than the local CVS.
+
+ For day-to-day operations you might prefer either `:local:' or
+`:fork:', depending on your preferences. Of course `:fork:' comes in
+particularly handy in testing or debugging `cvs' and the remote
+protocol. Specifically, we avoid all of the network-related
+setup/configuration, timeouts, and authentication inherent in the other
+remote access methods but still create a connection which uses the
+remote protocol.
+
+ To connect using the `fork' method, use `:fork:' and the pathname to
+your local repository. For example:
+
+ cvs -d :fork:/usr/local/cvsroot checkout foo
+
+ As with `:ext:', the server is called `cvs' by default, or the value
+of the `CVS_SERVER' environment variable.
+
+
+File: cvs.info, Node: Write proxies, Prev: Connecting via fork, Up: Remote repositories
+
+2.9.8 Distributing load across several CVS servers
+--------------------------------------------------
+
+CVS can be configured to distribute usage across several CVS servers.
+This is accomplished by means of one or more "write proxies", or
+"secondary servers", for a single "primary server".
+
+ When a CVS client accesses a secondary server and only sends read
+requests, then the secondary server handles the entire request. If the
+client sends any write requests, however, the secondary server asks the
+client to redirect its write request to the primary server, if the
+client supports redirect requests, and otherwise becomes a transparent
+proxy for the primary server, which actually handles the write request.
+
+ In this manner, any number of read-only secondary servers may be
+configured as write proxies for the primary server, effectively
+distributing the load from all read operations between the secondary
+servers and restricting the load on the primary server to write
+operations and pushing changes to the secondaries.
+
+ Primary servers will not automatically push changes to secondaries.
+This must be configured via `loginfo', `postadmin', `posttag', &
+`postwatch' scripts (*note Trigger Scripts::) like the following:
+
+ ALL rsync -gopr -essh ./ secondary:/cvsroot/%p &
+
+ You would probably actually want to lock directories for write on
+the secondary and for read on the primary before running the `rsync' in
+the above example, but describing such a setup is beyond the scope of
+this document.
+
+ A secondary advantage of a write proxy setup is that users pointing
+at the secondary server can still execute fast read operations while on
+a network that connects to the primary over a slow link or even one
+where the link to the primary is periodically broken. Only write
+operations will require the network link to the primary.
+
+ To configure write proxies, the primary must be specified with the
+`PrimaryServer' option in `CVSROOT/config' (*note config::). For the
+transparent proxy mode to work, all secondary servers must also be
+running the same version of the CVS server, or at least one that
+provides the same list of supported requests to the client as the
+primary server. This is not necessary for redirection.
+
+ Once a primary server is configured, secondary servers may be
+configured by:
+
+ 1. Duplicating the primary repository at the new location.
+
+ 2. Setting up the `loginfo', `postadmin', `posttag', and `postwatch'
+ files on the primary to propagate writes to the new secondary.
+
+ 3. Configure remote access to the secondary(ies) as you would
+ configure access to any other CVS server (*note Remote
+ repositories::).
+
+ 4. Ensuring that `--allow-root=SECONDARY-CVSROOT' is passed to *all*
+ incovations of the secondary server if the path to the CVS
+ repository directory is different on the two servers and you wish
+ to support clients that do not handle the `Redirect' resopnse (CVS
+ 1.12.9 and earlier clients do not handle the `Redirect' response).
+
+ Please note, again, that writethrough proxy suport requires
+ `--allow-root=SECONDARY-CVSROOT' to be specified for *all*
+ incovations of the secondary server, not just `pserver'
+ invocations. This may require a wrapper script for the CVS
+ executable on your server machine.
+
+
+File: cvs.info, Node: Read-only access, Next: Server temporary directory, Prev: Remote repositories, Up: Repository
+
+2.10 Read-only repository access
+================================
+
+It is possible to grant read-only repository access to people using the
+password-authenticated server (*note Password authenticated::). (The
+other access methods do not have explicit support for read-only users
+because those methods all assume login access to the repository machine
+anyway, and therefore the user can do whatever local file permissions
+allow her to do.)
+
+ A user who has read-only access can do only those CVS operations
+which do not modify the repository, except for certain "administrative"
+files (such as lock files and the history file). It may be desirable
+to use this feature in conjunction with user-aliasing (*note Password
+authentication server::).
+
+ Unlike with previous versions of CVS, read-only users should be able
+merely to read the repository, and not to execute programs on the
+server or otherwise gain unexpected levels of access. Or to be more
+accurate, the _known_ holes have been plugged. Because this feature is
+new and has not received a comprehensive security audit, you should use
+whatever level of caution seems warranted given your attitude concerning
+security.
+
+ There are two ways to specify read-only access for a user: by
+inclusion, and by exclusion.
+
+ "Inclusion" means listing that user specifically in the
+`$CVSROOT/CVSROOT/readers' file, which is simply a newline-separated
+list of users. Here is a sample `readers' file:
+
+ melissa
+ splotnik
+ jrandom
+
+(Don't forget the newline after the last user.)
+
+ "Exclusion" means explicitly listing everyone who has _write_
+access--if the file
+
+ $CVSROOT/CVSROOT/writers
+
+exists, then only those users listed in it have write access, and
+everyone else has read-only access (of course, even the read-only users
+still need to be listed in the CVS `passwd' file). The `writers' file
+has the same format as the `readers' file.
+
+ Note: if your CVS `passwd' file maps cvs users onto system users
+(*note Password authentication server::), make sure you deny or grant
+read-only access using the _cvs_ usernames, not the system usernames.
+That is, the `readers' and `writers' files contain cvs usernames, which
+may or may not be the same as system usernames.
+
+ Here is a complete description of the server's behavior in deciding
+whether to grant read-only or read-write access:
+
+ If `readers' exists, and this user is listed in it, then she gets
+read-only access. Or if `writers' exists, and this user is NOT listed
+in it, then she also gets read-only access (this is true even if
+`readers' exists but she is not listed there). Otherwise, she gets
+full read-write access.
+
+ Of course there is a conflict if the user is listed in both files.
+This is resolved in the more conservative way, it being better to
+protect the repository too much than too little: such a user gets
+read-only access.
+
+
+File: cvs.info, Node: Server temporary directory, Prev: Read-only access, Up: Repository
+
+2.11 Temporary directories for the server
+=========================================
+
+While running, the CVS server creates temporary directories. They are
+named
+
+ cvs-servPID
+
+where PID is the process identification number of the server. They are
+located in the directory specified by the `-T' global option (*note
+Global options::), the `TMPDIR' environment variable (*note Environment
+variables::), or, failing that, `/tmp'.
+
+ In most cases the server will remove the temporary directory when it
+is done, whether it finishes normally or abnormally. However, there
+are a few cases in which the server does not or cannot remove the
+temporary directory, for example:
+
+ * If the server aborts due to an internal server error, it may
+ preserve the directory to aid in debugging
+
+ * If the server is killed in a way that it has no way of cleaning up
+ (most notably, `kill -KILL' on unix).
+
+ * If the system shuts down without an orderly shutdown, which tells
+ the server to clean up.
+
+ In cases such as this, you will need to manually remove the
+`cvs-servPID' directories. As long as there is no server running with
+process identification number PID, it is safe to do so.
+
+
+File: cvs.info, Node: Starting a new project, Next: Revisions, Prev: Repository, Up: Top
+
+3 Starting a project with CVS
+*****************************
+
+Because renaming files and moving them between directories is somewhat
+inconvenient, the first thing you do when you start a new project
+should be to think through your file organization. It is not impossible
+to rename or move files, but it does increase the potential for
+confusion and CVS does have some quirks particularly in the area of
+renaming directories. *Note Moving files::.
+
+ What to do next depends on the situation at hand.
+
+* Menu:
+
+* Setting up the files:: Getting the files into the repository
+* Defining the module:: How to make a module of the files
+
+
+File: cvs.info, Node: Setting up the files, Next: Defining the module, Up: Starting a new project
+
+3.1 Setting up the files
+========================
+
+The first step is to create the files inside the repository. This can
+be done in a couple of different ways.
+
+* Menu:
+
+* From files:: This method is useful with old projects
+ where files already exists.
+* From other version control systems:: Old projects where you want to
+ preserve history from another system.
+* From scratch:: Creating a directory tree from scratch.
+
+
+File: cvs.info, Node: From files, Next: From other version control systems, Up: Setting up the files
+
+3.1.1 Creating a directory tree from a number of files
+------------------------------------------------------
+
+When you begin using CVS, you will probably already have several
+projects that can be put under CVS control. In these cases the easiest
+way is to use the `import' command. An example is probably the easiest
+way to explain how to use it. If the files you want to install in CVS
+reside in `WDIR', and you want them to appear in the repository as
+`$CVSROOT/yoyodyne/RDIR', you can do this:
+
+ $ cd WDIR
+ $ cvs import -m "Imported sources" yoyodyne/RDIR yoyo start
+
+ Unless you supply a log message with the `-m' flag, CVS starts an
+editor and prompts for a message. The string `yoyo' is a "vendor tag",
+and `start' is a "release tag". They may fill no purpose in this
+context, but since CVS requires them they must be present. *Note
+Tracking sources::, for more information about them.
+
+ You can now verify that it worked, and remove your original source
+directory.
+
+ $ cd ..
+ $ cvs checkout yoyodyne/RDIR # Explanation below
+ $ diff -r WDIR yoyodyne/RDIR
+ $ rm -r WDIR
+
+Erasing the original sources is a good idea, to make sure that you do
+not accidentally edit them in WDIR, bypassing CVS. Of course, it would
+be wise to make sure that you have a backup of the sources before you
+remove them.
+
+ The `checkout' command can either take a module name as argument (as
+it has done in all previous examples) or a path name relative to
+`$CVSROOT', as it did in the example above.
+
+ It is a good idea to check that the permissions CVS sets on the
+directories inside `$CVSROOT' are reasonable, and that they belong to
+the proper groups. *Note File permissions::.
+
+ If some of the files you want to import are binary, you may want to
+use the wrappers features to specify which files are binary and which
+are not. *Note Wrappers::.
+
+
+File: cvs.info, Node: From other version control systems, Next: From scratch, Prev: From files, Up: Setting up the files
+
+3.1.2 Creating Files From Other Version Control Systems
+-------------------------------------------------------
+
+If you have a project which you are maintaining with another version
+control system, such as RCS, you may wish to put the files from that
+project into CVS, and preserve the revision history of the files.
+
+From RCS
+ If you have been using RCS, find the RCS files--usually a file
+ named `foo.c' will have its RCS file in `RCS/foo.c,v' (but it
+ could be other places; consult the RCS documentation for details).
+ Then create the appropriate directories in CVS if they do not
+ already exist. Then copy the files into the appropriate
+ directories in the CVS repository (the name in the repository must
+ be the name of the source file with `,v' added; the files go
+ directly in the appropriate directory of the repository, not in an
+ `RCS' subdirectory). This is one of the few times when it is a
+ good idea to access the CVS repository directly, rather than using
+ CVS commands. Then you are ready to check out a new working
+ directory.
+
+ The RCS file should not be locked when you move it into CVS; if it
+ is, CVS will have trouble letting you operate on it.
+
+From another version control system
+ Many version control systems have the ability to export RCS files
+ in the standard format. If yours does, export the RCS files and
+ then follow the above instructions.
+
+ Failing that, probably your best bet is to write a script that
+ will check out the files one revision at a time using the command
+ line interface to the other system, and then check the revisions
+ into CVS. The `sccs2rcs' script mentioned below may be a useful
+ example to follow.
+
+From SCCS
+ There is a script in the `contrib' directory of the CVS source
+ distribution called `sccs2rcs' which converts SCCS files to RCS
+ files. Note: you must run it on a machine which has both SCCS and
+ RCS installed, and like everything else in contrib it is
+ unsupported (your mileage may vary).
+
+From PVCS
+ There is a script in the `contrib' directory of the CVS source
+ distribution called `pvcs_to_rcs' which converts PVCS archives to
+ RCS files. You must run it on a machine which has both PVCS and
+ RCS installed, and like everything else in contrib it is
+ unsupported (your mileage may vary). See the comments in the
+ script for details.
+
+
+File: cvs.info, Node: From scratch, Prev: From other version control systems, Up: Setting up the files
+
+3.1.3 Creating a directory tree from scratch
+--------------------------------------------
+
+For a new project, the easiest thing to do is probably to create an
+empty directory structure, like this:
+
+ $ mkdir tc
+ $ mkdir tc/man
+ $ mkdir tc/testing
+
+ After that, you use the `import' command to create the corresponding
+(empty) directory structure inside the repository:
+
+ $ cd tc
+ $ cvs import -m "Created directory structure" yoyodyne/DIR yoyo start
+
+ This will add yoyodyne/DIR as a directory under `$CVSROOT'.
+
+ Use `checkout' to get the new project. Then, use `add' to add files
+(and new directories) as needed.
+
+ $ cd ..
+ $ cvs co yoyodyne/DIR
+
+ Check that the permissions CVS sets on the directories inside
+`$CVSROOT' are reasonable.
+
+
+File: cvs.info, Node: Defining the module, Prev: Setting up the files, Up: Starting a new project
+
+3.2 Defining the module
+=======================
+
+The next step is to define the module in the `modules' file. This is
+not strictly necessary, but modules can be convenient in grouping
+together related files and directories.
+
+ In simple cases these steps are sufficient to define a module.
+
+ 1. Get a working copy of the modules file.
+
+ $ cvs checkout CVSROOT/modules
+ $ cd CVSROOT
+
+ 2. Edit the file and insert a line that defines the module. *Note
+ Intro administrative files::, for an introduction. *Note
+ modules::, for a full description of the modules file. You can
+ use the following line to define the module `tc':
+
+ tc yoyodyne/tc
+
+ 3. Commit your changes to the modules file.
+
+ $ cvs commit -m "Added the tc module." modules
+
+ 4. Release the modules module.
+
+ $ cd ..
+ $ cvs release -d CVSROOT
+
+
+File: cvs.info, Node: Revisions, Next: Branching and merging, Prev: Starting a new project, Up: Top
+
+4 Revisions
+***********
+
+For many uses of CVS, one doesn't need to worry too much about revision
+numbers; CVS assigns numbers such as `1.1', `1.2', and so on, and that
+is all one needs to know. However, some people prefer to have more
+knowledge and control concerning how CVS assigns revision numbers.
+
+ If one wants to keep track of a set of revisions involving more than
+one file, such as which revisions went into a particular release, one
+uses a "tag", which is a symbolic revision which can be assigned to a
+numeric revision in each file.
+
+* Menu:
+
+* Revision numbers:: The meaning of a revision number
+* Versions revisions releases:: Terminology used in this manual
+* Assigning revisions:: Assigning revisions
+* Tags:: Tags--Symbolic revisions
+* Tagging the working directory:: The cvs tag command
+* Tagging by date/tag:: The cvs rtag command
+* Modifying tags:: Adding, renaming, and deleting tags
+* Tagging add/remove:: Tags with adding and removing files
+* Sticky tags:: Certain tags are persistent
+
+
+File: cvs.info, Node: Revision numbers, Next: Versions revisions releases, Up: Revisions
+
+4.1 Revision numbers
+====================
+
+Each version of a file has a unique "revision number". Revision
+numbers look like `1.1', `1.2', `1.3.2.2' or even `1.3.2.2.4.5'. A
+revision number always has an even number of period-separated decimal
+integers. By default revision 1.1 is the first revision of a file.
+Each successive revision is given a new number by increasing the
+rightmost number by one. The following figure displays a few
+revisions, with newer revisions to the right.
+
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+ +-----+ +-----+ +-----+ +-----+ +-----+
+
+ It is also possible to end up with numbers containing more than one
+period, for example `1.3.2.2'. Such revisions represent revisions on
+branches (*note Branching and merging::); such revision numbers are
+explained in detail in *Note Branches and revisions::.
+
+
+File: cvs.info, Node: Versions revisions releases, Next: Assigning revisions, Prev: Revision numbers, Up: Revisions
+
+4.2 Versions, revisions and releases
+====================================
+
+A file can have several versions, as described above. Likewise, a
+software product can have several versions. A software product is
+often given a version number such as `4.1.1'.
+
+ Versions in the first sense are called "revisions" in this document,
+and versions in the second sense are called "releases". To avoid
+confusion, the word "version" is almost never used in this document.
+
+
+File: cvs.info, Node: Assigning revisions, Next: Tags, Prev: Versions revisions releases, Up: Revisions
+
+4.3 Assigning revisions
+=======================
+
+By default, CVS will assign numeric revisions by leaving the first
+number the same and incrementing the second number. For example,
+`1.1', `1.2', `1.3', etc.
+
+ When adding a new file, the second number will always be one and the
+first number will equal the highest first number of any file in that
+directory. For example, the current directory contains files whose
+highest numbered revisions are `1.7', `3.1', and `4.12', then an added
+file will be given the numeric revision `4.1'. (When using
+client/server CVS, only files that are actually sent to the server are
+considered.)
+
+ Normally there is no reason to care about the revision numbers--it
+is easier to treat them as internal numbers that CVS maintains, and tags
+provide a better way to distinguish between things like release 1
+versus release 2 of your product (*note Tags::). However, if you want
+to set the numeric revisions, the `-r' option to `cvs commit' can do
+that. The `-r' option implies the `-f' option, in the sense that it
+causes the files to be committed even if they are not modified.
+
+ For example, to bring all your files up to revision 3.0 (including
+those that haven't changed), you might invoke:
+
+ $ cvs commit -r 3.0
+
+ Note that the number you specify with `-r' must be larger than any
+existing revision number. That is, if revision 3.0 exists, you cannot
+`cvs commit -r 1.3'. If you want to maintain several releases in
+parallel, you need to use a branch (*note Branching and merging::).
+
+
+File: cvs.info, Node: Tags, Next: Tagging the working directory, Prev: Assigning revisions, Up: Revisions
+
+4.4 Tags-Symbolic revisions
+===========================
+
+The revision numbers live a life of their own. They need not have
+anything at all to do with the release numbers of your software
+product. Depending on how you use CVS the revision numbers might
+change several times between two releases. As an example, some of the
+source files that make up RCS 5.6 have the following revision numbers:
+
+ ci.c 5.21
+ co.c 5.9
+ ident.c 5.3
+ rcs.c 5.12
+ rcsbase.h 5.11
+ rcsdiff.c 5.10
+ rcsedit.c 5.11
+ rcsfcmp.c 5.9
+ rcsgen.c 5.10
+ rcslex.c 5.11
+ rcsmap.c 5.2
+ rcsutil.c 5.10
+
+ You can use the `tag' command to give a symbolic name to a certain
+revision of a file. You can use the `-v' flag to the `status' command
+to see all tags that a file has, and which revision numbers they
+represent. Tag names must start with an uppercase or lowercase letter
+and can contain uppercase and lowercase letters, digits, `-', and `_'.
+The two tag names `BASE' and `HEAD' are reserved for use by CVS. It is
+expected that future names which are special to CVS will be specially
+named, for example by starting with `.', rather than being named
+analogously to `BASE' and `HEAD', to avoid conflicts with actual tag
+names.
+
+ You'll want to choose some convention for naming tags, based on
+information such as the name of the program and the version number of
+the release. For example, one might take the name of the program,
+immediately followed by the version number with `.' changed to `-', so
+that CVS 1.9 would be tagged with the name `cvs1-9'. If you choose a
+consistent convention, then you won't constantly be guessing whether a
+tag is `cvs-1-9' or `cvs1_9' or what. You might even want to consider
+enforcing your convention in the `taginfo' file (*note taginfo::).
+
+ The following example shows how you can add a tag to a file. The
+commands must be issued inside your working directory. That is, you
+should issue the command in the directory where `backend.c' resides.
+
+ $ cvs tag rel-0-4 backend.c
+ T backend.c
+ $ cvs status -v backend.c
+ ===================================================================
+ File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-0-4 (revision: 1.4)
+
+ For a complete summary of the syntax of `cvs tag', including the
+various options, see *Note Invoking CVS::.
+
+ There is seldom reason to tag a file in isolation. A more common
+use is to tag all the files that constitute a module with the same tag
+at strategic points in the development life-cycle, such as when a
+release is made.
+
+ $ cvs tag rel-1-0 .
+ cvs tag: Tagging .
+ T Makefile
+ T backend.c
+ T driver.c
+ T frontend.c
+ T parser.c
+
+(When you give CVS a directory as argument, it generally applies the
+operation to all the files in that directory, and (recursively), to any
+subdirectories that it may contain. *Note Recursive behavior::.)
+
+ The `checkout' command has a flag, `-r', that lets you check out a
+certain revision of a module. This flag makes it easy to retrieve the
+sources that make up release 1.0 of the module `tc' at any time in the
+future:
+
+ $ cvs checkout -r rel-1-0 tc
+
+This is useful, for instance, if someone claims that there is a bug in
+that release, but you cannot find the bug in the current working copy.
+
+ You can also check out a module as it was on any branch at any given
+date. *Note checkout options::. When specifying `-r' or `-D' to any
+of these commands, you will need beware of sticky tags; see *Note
+Sticky tags::.
+
+ When you tag more than one file with the same tag you can think
+about the tag as "a curve drawn through a matrix of filename vs.
+revision number." Say we have 5 files with the following revisions:
+
+ file1 file2 file3 file4 file5
+
+ 1.1 1.1 1.1 1.1 /--1.1* <-*- TAG
+ 1.2*- 1.2 1.2 -1.2*-
+ 1.3 \- 1.3*- 1.3 / 1.3
+ 1.4 \ 1.4 / 1.4
+ \-1.5*- 1.5
+ 1.6
+
+ At some time in the past, the `*' versions were tagged. You can
+think of the tag as a handle attached to the curve drawn through the
+tagged revisions. When you pull on the handle, you get all the tagged
+revisions. Another way to look at it is that you "sight" through a set
+of revisions that is "flat" along the tagged revisions, like this:
+
+ file1 file2 file3 file4 file5
+
+ 1.1
+ 1.2
+ 1.1 1.3 _
+ 1.1 1.2 1.4 1.1 /
+ 1.2*----1.3*----1.5*----1.2*----1.1* (--- <--- Look here
+ 1.3 1.6 1.3 \_
+ 1.4 1.4
+ 1.5
+
+
+File: cvs.info, Node: Tagging the working directory, Next: Tagging by date/tag, Prev: Tags, Up: Revisions
+
+4.5 Specifying what to tag from the working directory
+=====================================================
+
+The example in the previous section demonstrates one of the most common
+ways to choose which revisions to tag. Namely, running the `cvs tag'
+command without arguments causes CVS to select the revisions which are
+checked out in the current working directory. For example, if the copy
+of `backend.c' in working directory was checked out from revision 1.4,
+then CVS will tag revision 1.4. Note that the tag is applied
+immediately to revision 1.4 in the repository; tagging is not like
+modifying a file, or other operations in which one first modifies the
+working directory and then runs `cvs commit' to transfer that
+modification to the repository.
+
+ One potentially surprising aspect of the fact that `cvs tag'
+operates on the repository is that you are tagging the checked-in
+revisions, which may differ from locally modified files in your working
+directory. If you want to avoid doing this by mistake, specify the
+`-c' option to `cvs tag'. If there are any locally modified files, CVS
+will abort with an error before it tags any files:
+
+ $ cvs tag -c rel-0-4
+ cvs tag: backend.c is locally modified
+ cvs [tag aborted]: correct the above errors first!
+
+
+File: cvs.info, Node: Tagging by date/tag, Next: Modifying tags, Prev: Tagging the working directory, Up: Revisions
+
+4.6 Specifying what to tag by date or revision
+==============================================
+
+The `cvs rtag' command tags the repository as of a certain date or time
+(or can be used to tag the latest revision). `rtag' works directly on
+the repository contents (it requires no prior checkout and does not
+look for a working directory).
+
+ The following options specify which date or revision to tag. See
+*Note Common options::, for a complete description of them.
+
+`-D DATE'
+ Tag the most recent revision no later than DATE.
+
+`-f'
+ Only useful with the `-D' or `-r' flags. If no matching revision
+ is found, use the most recent revision (instead of ignoring the
+ file).
+
+`-r TAG[:DATE]'
+ Tag the revision already tagged with TAG or, when DATE is specified
+ and TAG is a branch tag, the version from the branch TAG as it
+ existed on DATE. See *Note Common options::.
+
+ The `cvs tag' command also allows one to specify files by revision
+or date, using the same `-r', `-D', and `-f' options. However, this
+feature is probably not what you want. The reason is that `cvs tag'
+chooses which files to tag based on the files that exist in the working
+directory, rather than the files which existed as of the given tag/date.
+Therefore, you are generally better off using `cvs rtag'. The
+exceptions might be cases like:
+
+ cvs tag -r 1.4 stable backend.c
+
+
+File: cvs.info, Node: Modifying tags, Next: Tagging add/remove, Prev: Tagging by date/tag, Up: Revisions
+
+4.7 Deleting, moving, and renaming tags
+=======================================
+
+Normally one does not modify tags. They exist in order to record the
+history of the repository and so deleting them or changing their
+meaning would, generally, not be what you want.
+
+ However, there might be cases in which one uses a tag temporarily or
+accidentally puts one in the wrong place. Therefore, one might delete,
+move, or rename a tag.
+
+*WARNING: the commands in this section are dangerous; they permanently
+discard historical information and it can be difficult or impossible to
+recover from errors. If you are a CVS administrator, you may consider
+restricting these commands with the `taginfo' file (*note taginfo::).*
+
+ To delete a tag, specify the `-d' option to either `cvs tag' or `cvs
+rtag'. For example:
+
+ cvs rtag -d rel-0-4 tc
+
+deletes the non-branch tag `rel-0-4' from the module `tc'. In the
+event that branch tags are encountered within the repository with the
+given name, a warning message will be issued and the branch tag will
+not be deleted. If you are absolutely certain you know what you are
+doing, the `-B' option may be specified to allow deletion of branch
+tags. In that case, any non-branch tags encountered will trigger
+warnings and will not be deleted.
+
+*WARNING: Moving branch tags is very dangerous! If you think you need
+the `-B' option, think again and ask your CVS administrator about it
+(if that isn't you). There is almost certainly another way to
+accomplish what you want to accomplish.*
+
+ When we say "move" a tag, we mean to make the same name point to
+different revisions. For example, the `stable' tag may currently point
+to revision 1.4 of `backend.c' and perhaps we want to make it point to
+revision 1.6. To move a non-branch tag, specify the `-F' option to
+either `cvs tag' or `cvs rtag'. For example, the task just mentioned
+might be accomplished as:
+
+ cvs tag -r 1.6 -F stable backend.c
+
+If any branch tags are encountered in the repository with the given
+name, a warning is issued and the branch tag is not disturbed. If you
+are absolutely certain you wish to move the branch tag, the `-B' option
+may be specified. In that case, non-branch tags encountered with the
+given name are ignored with a warning message.
+
+*WARNING: Moving branch tags is very dangerous! If you think you need
+the `-B' option, think again and ask your CVS administrator about it
+(if that isn't you). There is almost certainly another way to
+accomplish what you want to accomplish.*
+
+ When we say "rename" a tag, we mean to make a different name point
+to the same revisions as the old tag. For example, one may have
+misspelled the tag name and want to correct it (hopefully before others
+are relying on the old spelling). To rename a tag, first create a new
+tag using the `-r' option to `cvs rtag', and then delete the old name.
+(Caution: this method will not work with branch tags.) This leaves the
+new tag on exactly the same files as the old tag. For example:
+
+ cvs rtag -r old-name-0-4 rel-0-4 tc
+ cvs rtag -d old-name-0-4 tc
+
+
+File: cvs.info, Node: Tagging add/remove, Next: Sticky tags, Prev: Modifying tags, Up: Revisions
+
+4.8 Tagging and adding and removing files
+=========================================
+
+The subject of exactly how tagging interacts with adding and removing
+files is somewhat obscure; for the most part CVS will keep track of
+whether files exist or not without too much fussing. By default, tags
+are applied to only files which have a revision corresponding to what
+is being tagged. Files which did not exist yet, or which were already
+removed, simply omit the tag, and CVS knows to treat the absence of a
+tag as meaning that the file didn't exist as of that tag.
+
+ However, this can lose a small amount of information. For example,
+suppose a file was added and then removed. Then, if the tag is missing
+for that file, there is no way to know whether the tag refers to the
+time before the file was added, or the time after it was removed. If
+you specify the `-r' option to `cvs rtag', then CVS tags the files
+which have been removed, and thereby avoids this problem. For example,
+one might specify `-r HEAD' to tag the head.
+
+ On the subject of adding and removing files, the `cvs rtag' command
+has a `-a' option which means to clear the tag from removed files that
+would not otherwise be tagged. For example, one might specify this
+option in conjunction with `-F' when moving a tag. If one moved a tag
+without `-a', then the tag in the removed files might still refer to
+the old revision, rather than reflecting the fact that the file had
+been removed. I don't think this is necessary if `-r' is specified, as
+noted above.
+
+
+File: cvs.info, Node: Sticky tags, Prev: Tagging add/remove, Up: Revisions
+
+4.9 Sticky tags
+===============
+
+Sometimes a working copy's revision has extra data associated with it,
+for example it might be on a branch (*note Branching and merging::), or
+restricted to versions prior to a certain date by `checkout -D' or
+`update -D'. Because this data persists - that is, it applies to
+subsequent commands in the working copy - we refer to it as "sticky".
+
+ Most of the time, stickiness is an obscure aspect of CVS that you
+don't need to think about. However, even if you don't want to use the
+feature, you may need to know _something_ about sticky tags (for
+example, how to avoid them!).
+
+ You can use the `status' command to see if any sticky tags or dates
+are set:
+
+ $ cvs status driver.c
+ ===================================================================
+ File: driver.c Status: Up-to-date
+
+ Version: 1.7.2.1 Sat Dec 5 19:35:03 1992
+ RCS Version: 1.7.2.1 /u/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ The sticky tags will remain on your working files until you delete
+them with `cvs update -A'. The `-A' option merges local changes into
+the version of the file from the head of the trunk, removing any sticky
+tags, dates, or options. See *Note update:: for more on the operation
+of `cvs update'.
+
+ The most common use of sticky tags is to identify which branch one
+is working on, as described in *Note Accessing branches::. However,
+non-branch sticky tags have uses as well. For example, suppose that
+you want to avoid updating your working directory, to isolate yourself
+from possibly destabilizing changes other people are making. You can,
+of course, just refrain from running `cvs update'. But if you want to
+avoid updating only a portion of a larger tree, then sticky tags can
+help. If you check out a certain revision (such as 1.4) it will become
+sticky. Subsequent `cvs update' commands will not retrieve the latest
+revision until you reset the tag with `cvs update -A'. Likewise, use
+of the `-D' option to `update' or `checkout' sets a "sticky date",
+which, similarly, causes that date to be used for future retrievals.
+
+ People often want to retrieve an old version of a file without
+setting a sticky tag. This can be done with the `-p' option to
+`checkout' or `update', which sends the contents of the file to
+standard output. For example:
+ $ cvs update -p -r 1.1 file1 >file1
+ ===================================================================
+ Checking out file1
+ RCS: /tmp/cvs-sanity/cvsroot/first-dir/Attic/file1,v
+ VERS: 1.1
+ ***************
+ $
+
+ However, this isn't the easiest way, if you are asking how to undo a
+previous checkin (in this example, put `file1' back to the way it was
+as of revision 1.1). In that case you are better off using the `-j'
+option to `update'; for further discussion see *Note Merging two
+revisions::.
+
+
+File: cvs.info, Node: Branching and merging, Next: Recursive behavior, Prev: Revisions, Up: Top
+
+5 Branching and merging
+***********************
+
+CVS allows you to isolate changes onto a separate line of development,
+known as a "branch". When you change files on a branch, those changes
+do not appear on the main trunk or other branches.
+
+ Later you can move changes from one branch to another branch (or the
+main trunk) by "merging". Merging involves first running `cvs update
+-j', to merge the changes into the working directory. You can then
+commit that revision, and thus effectively copy the changes onto
+another branch.
+
+* Menu:
+
+* Branches motivation:: What branches are good for
+* Creating a branch:: Creating a branch
+* Accessing branches:: Checking out and updating branches
+* Branches and revisions:: Branches are reflected in revision numbers
+* Magic branch numbers:: Magic branch numbers
+* Merging a branch:: Merging an entire branch
+* Merging more than once:: Merging from a branch several times
+* Merging two revisions:: Merging differences between two revisions
+* Merging adds and removals:: What if files are added or removed?
+* Merging and keywords:: Avoiding conflicts due to keyword substitution
+
+
+File: cvs.info, Node: Branches motivation, Next: Creating a branch, Up: Branching and merging
+
+5.1 What branches are good for
+==============================
+
+Suppose that release 1.0 of tc has been made. You are continuing to
+develop tc, planning to create release 1.1 in a couple of months.
+After a while your customers start to complain about a fatal bug. You
+check out release 1.0 (*note Tags::) and find the bug (which turns out
+to have a trivial fix). However, the current revision of the sources
+are in a state of flux and are not expected to be stable for at least
+another month. There is no way to make a bug fix release based on the
+newest sources.
+
+ The thing to do in a situation like this is to create a "branch" on
+the revision trees for all the files that make up release 1.0 of tc.
+You can then make modifications to the branch without disturbing the
+main trunk. When the modifications are finished you can elect to
+either incorporate them on the main trunk, or leave them on the branch.
+
+
+File: cvs.info, Node: Creating a branch, Next: Accessing branches, Prev: Branches motivation, Up: Branching and merging
+
+5.2 Creating a branch
+=====================
+
+You can create a branch with `tag -b'; for example, assuming you're in
+a working copy:
+
+ $ cvs tag -b rel-1-0-patches
+
+ This splits off a branch based on the current revisions in the
+working copy, assigning that branch the name `rel-1-0-patches'.
+
+ It is important to understand that branches get created in the
+repository, not in the working copy. Creating a branch based on
+current revisions, as the above example does, will _not_ automatically
+switch the working copy to be on the new branch. For information on how
+to do that, see *Note Accessing branches::.
+
+ You can also create a branch without reference to any working copy,
+by using `rtag':
+
+ $ cvs rtag -b -r rel-1-0 rel-1-0-patches tc
+
+ `-r rel-1-0' says that this branch should be rooted at the revision
+that corresponds to the tag `rel-1-0'. It need not be the most recent
+revision - it's often useful to split a branch off an old revision (for
+example, when fixing a bug in a past release otherwise known to be
+stable).
+
+ As with `tag', the `-b' flag tells `rtag' to create a branch (rather
+than just a symbolic revision name). Note that the numeric revision
+number that matches `rel-1-0' will probably be different from file to
+file.
+
+ So, the full effect of the command is to create a new branch - named
+`rel-1-0-patches' - in module `tc', rooted in the revision tree at the
+point tagged by `rel-1-0'.
+
+
+File: cvs.info, Node: Accessing branches, Next: Branches and revisions, Prev: Creating a branch, Up: Branching and merging
+
+5.3 Accessing branches
+======================
+
+You can retrieve a branch in one of two ways: by checking it out fresh
+from the repository, or by switching an existing working copy over to
+the branch.
+
+ To check out a branch from the repository, invoke `checkout' with
+the `-r' flag, followed by the tag name of the branch (*note Creating a
+branch::):
+
+ $ cvs checkout -r rel-1-0-patches tc
+
+ Or, if you already have a working copy, you can switch it to a given
+branch with `update -r':
+
+ $ cvs update -r rel-1-0-patches tc
+
+or equivalently:
+
+ $ cd tc
+ $ cvs update -r rel-1-0-patches
+
+ It does not matter if the working copy was originally on the main
+trunk or on some other branch - the above command will switch it to the
+named branch. And similarly to a regular `update' command, `update -r'
+merges any changes you have made, notifying you of conflicts where they
+occur.
+
+ Once you have a working copy tied to a particular branch, it remains
+there until you tell it otherwise. This means that changes checked in
+from the working copy will add new revisions on that branch, while
+leaving the main trunk and other branches unaffected.
+
+ To find out what branch a working copy is on, you can use the
+`status' command. In its output, look for the field named `Sticky tag'
+(*note Sticky tags::) - that's CVS's way of telling you the branch, if
+any, of the current working files:
+
+ $ cvs status -v driver.c backend.c
+ ===================================================================
+ File: driver.c Status: Up-to-date
+
+ Version: 1.7 Sat Dec 5 18:25:54 1992
+ RCS Version: 1.7 /u/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-1-0-patches (branch: 1.7.2)
+ rel-1-0 (revision: 1.7)
+
+ ===================================================================
+ File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.4.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-1-0-patches (branch: 1.4.2)
+ rel-1-0 (revision: 1.4)
+ rel-0-4 (revision: 1.4)
+
+ Don't be confused by the fact that the branch numbers for each file
+are different (`1.7.2' and `1.4.2' respectively). The branch tag is the
+same, `rel-1-0-patches', and the files are indeed on the same branch.
+The numbers simply reflect the point in each file's revision history at
+which the branch was made. In the above example, one can deduce that
+`driver.c' had been through more changes than `backend.c' before this
+branch was created.
+
+ See *Note Branches and revisions:: for details about how branch
+numbers are constructed.
+
+
+File: cvs.info, Node: Branches and revisions, Next: Magic branch numbers, Prev: Accessing branches, Up: Branching and merging
+
+5.4 Branches and revisions
+==========================
+
+Ordinarily, a file's revision history is a linear series of increments
+(*note Revision numbers::):
+
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+ +-----+ +-----+ +-----+ +-----+ +-----+
+
+ However, CVS is not limited to linear development. The "revision
+tree" can be split into "branches", where each branch is a
+self-maintained line of development. Changes made on one branch can
+easily be moved back to the main trunk.
+
+ Each branch has a "branch number", consisting of an odd number of
+period-separated decimal integers. The branch number is created by
+appending an integer to the revision number where the corresponding
+branch forked off. Having branch numbers allows more than one branch
+to be forked off from a certain revision.
+
+ All revisions on a branch have revision numbers formed by appending
+an ordinal number to the branch number. The following figure
+illustrates branching with an example.
+
+ +-------------+
+ Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 !
+ / +-------------+
+ /
+ /
+ +---------+ +---------+ +---------+
+ Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
+ / +---------+ +---------+ +---------+
+ /
+ /
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+ +---------+
+ Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 !
+ +---------+ +---------+ +---------+
+
+ The exact details of how the branch number is constructed is not
+something you normally need to be concerned about, but here is how it
+works: When CVS creates a branch number it picks the first unused even
+integer, starting with 2. So when you want to create a branch from
+revision 6.4 it will be numbered 6.4.2. All branch numbers ending in a
+zero (such as 6.4.0) are used internally by CVS (*note Magic branch
+numbers::). The branch 1.1.1 has a special meaning. *Note Tracking
+sources::.
+
+
+File: cvs.info, Node: Magic branch numbers, Next: Merging a branch, Prev: Branches and revisions, Up: Branching and merging
+
+5.5 Magic branch numbers
+========================
+
+This section describes a CVS feature called "magic branches". For most
+purposes, you need not worry about magic branches; CVS handles them for
+you. However, they are visible to you in certain circumstances, so it
+may be useful to have some idea of how it works.
+
+ Externally, branch numbers consist of an odd number of dot-separated
+decimal integers. *Note Revision numbers::. That is not the whole
+truth, however. For efficiency reasons CVS sometimes inserts an extra 0
+in the second rightmost position (1.2.4 becomes 1.2.0.4, 8.9.10.11.12
+becomes 8.9.10.11.0.12 and so on).
+
+ CVS does a pretty good job at hiding these so called magic branches,
+but in a few places the hiding is incomplete:
+
+ * The magic branch number appears in the output from `cvs log'.
+
+ * You cannot specify a symbolic branch name to `cvs admin'.
+
+
+ You can use the `admin' command to reassign a symbolic name to a
+branch the way RCS expects it to be. If `R4patches' is assigned to the
+branch 1.4.2 (magic branch number 1.4.0.2) in file `numbers.c' you can
+do this:
+
+ $ cvs admin -NR4patches:1.4.2 numbers.c
+
+ It only works if at least one revision is already committed on the
+branch. Be very careful so that you do not assign the tag to the wrong
+number. (There is no way to see how the tag was assigned yesterday).
+
+
+File: cvs.info, Node: Merging a branch, Next: Merging more than once, Prev: Magic branch numbers, Up: Branching and merging
+
+5.6 Merging an entire branch
+============================
+
+You can merge changes made on a branch into your working copy by giving
+the `-j BRANCHNAME' flag to the `update' subcommand. With one `-j
+BRANCHNAME' option it merges the changes made between the greatest
+common ancestor (GCA) of the branch and the destination revision (in
+the simple case below the GCA is the point where the branch forked) and
+the newest revision on that branch into your working copy.
+
+ The `-j' stands for "join".
+
+ Consider this revision tree:
+
+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 ! <- The main trunk
+ +-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+
+ Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+
+The branch 1.2.2 has been given the tag (symbolic name) `R1fix'. The
+following example assumes that the module `mod' contains only one file,
+`m.c'.
+
+ $ cvs checkout mod # Retrieve the latest revision, 1.4
+
+ $ cvs update -j R1fix m.c # Merge all changes made on the branch,
+ # i.e. the changes between revision 1.2
+ # and 1.2.2.2, into your working copy
+ # of the file.
+
+ $ cvs commit -m "Included R1fix" # Create revision 1.5.
+
+ A conflict can result from a merge operation. If that happens, you
+should resolve it before committing the new revision. *Note Conflicts
+example::.
+
+ If your source files contain keywords (*note Keyword substitution::),
+you might be getting more conflicts than strictly necessary. See *Note
+Merging and keywords::, for information on how to avoid this.
+
+ The `checkout' command also supports the `-j BRANCHNAME' flag. The
+same effect as above could be achieved with this:
+
+ $ cvs checkout -j R1fix mod
+ $ cvs commit -m "Included R1fix"
+
+ It should be noted that `update -j TAGNAME' will also work but may
+not produce the desired result. *Note Merging adds and removals::, for
+more.
+
+
+File: cvs.info, Node: Merging more than once, Next: Merging two revisions, Prev: Merging a branch, Up: Branching and merging
+
+5.7 Merging from a branch several times
+=======================================
+
+Continuing our example, the revision tree now looks like this:
+
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+
+ Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+
+where the starred line represents the merge from the `R1fix' branch to
+the main trunk, as just discussed.
+
+ Now suppose that development continues on the `R1fix' branch:
+
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+ +---------+
+ Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
+ +---------+ +---------+ +---------+
+
+and then you want to merge those new changes onto the main trunk. If
+you just use the `cvs update -j R1fix m.c' command again, CVS will
+attempt to merge again the changes which you have already merged, which
+can have undesirable side effects.
+
+ So instead you need to specify that you only want to merge the
+changes on the branch which have not yet been merged into the trunk.
+To do that you specify two `-j' options, and CVS merges the changes from
+the first revision to the second revision. For example, in this case
+the simplest way would be
+
+ cvs update -j 1.2.2.2 -j R1fix m.c # Merge changes from 1.2.2.2 to the
+ # head of the R1fix branch
+
+ The problem with this is that you need to specify the 1.2.2.2
+revision manually. A slightly better approach might be to use the date
+the last merge was done:
+
+ cvs update -j R1fix:yesterday -j R1fix m.c
+
+ Better yet, tag the R1fix branch after every merge into the trunk,
+and then use that tag for subsequent merges:
+
+ cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c
+
+
+File: cvs.info, Node: Merging two revisions, Next: Merging adds and removals, Prev: Merging more than once, Up: Branching and merging
+
+5.8 Merging differences between any two revisions
+=================================================
+
+With two `-j REVISION' flags, the `update' (and `checkout') command can
+merge the differences between any two revisions into your working file.
+
+ $ cvs update -j 1.5 -j 1.3 backend.c
+
+will undo all changes made between revision 1.3 and 1.5. Note the
+order of the revisions!
+
+ If you try to use this option when operating on multiple files,
+remember that the numeric revisions will probably be very different
+between the various files. You almost always use symbolic tags rather
+than revision numbers when operating on multiple files.
+
+ Specifying two `-j' options can also undo file removals or
+additions. For example, suppose you have a file named `file1' which
+existed as revision 1.1, and you then removed it (thus adding a dead
+revision 1.2). Now suppose you want to add it again, with the same
+contents it had previously. Here is how to do it:
+
+ $ cvs update -j 1.2 -j 1.1 file1
+ U file1
+ $ cvs commit -m test
+ Checking in file1;
+ /tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1
+ new revision: 1.3; previous revision: 1.2
+ done
+ $
+
+
+File: cvs.info, Node: Merging adds and removals, Next: Merging and keywords, Prev: Merging two revisions, Up: Branching and merging
+
+5.9 Merging can add or remove files
+===================================
+
+If the changes which you are merging involve removing or adding some
+files, `update -j' will reflect such additions or removals.
+
+ For example:
+ cvs update -A
+ touch a b c
+ cvs add a b c ; cvs ci -m "added" a b c
+ cvs tag -b branchtag
+ cvs update -r branchtag
+ touch d ; cvs add d
+ rm a ; cvs rm a
+ cvs ci -m "added d, removed a"
+ cvs update -A
+ cvs update -jbranchtag
+
+ After these commands are executed and a `cvs commit' is done, file
+`a' will be removed and file `d' added in the main branch.
+
+ Note that using a single static tag (`-j TAGNAME') rather than a
+dynamic tag (`-j BRANCHNAME') to merge changes from a branch will
+usually not remove files which were removed on the branch since CVS
+does not automatically add static tags to dead revisions. The
+exception to this rule occurs when a static tag has been attached to a
+dead revision manually. Use the branch tag to merge all changes from
+the branch or use two static tags as merge endpoints to be sure that
+all intended changes are propagated in the merge.
+
+
+File: cvs.info, Node: Merging and keywords, Prev: Merging adds and removals, Up: Branching and merging
+
+5.10 Merging and keywords
+=========================
+
+If you merge files containing keywords (*note Keyword substitution::),
+you will normally get numerous conflicts during the merge, because the
+keywords are expanded differently in the revisions which you are
+merging.
+
+ Therefore, you will often want to specify the `-kk' (*note
+Substitution modes::) switch to the merge command line. By
+substituting just the name of the keyword, not the expanded value of
+that keyword, this option ensures that the revisions which you are
+merging will be the same as each other, and avoid spurious conflicts.
+
+ For example, suppose you have a file like this:
+
+ +---------+
+ _! 1.1.2.1 ! <- br1
+ / +---------+
+ /
+ /
+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !
+ +-----+ +-----+
+
+and your working directory is currently on the trunk (revision 1.2).
+Then you might get the following results from a merge:
+
+ $ cat file1
+ key $Revision: 1.2 $
+ . . .
+ $ cvs update -j br1
+ U file1
+ RCS file: /cvsroot/first-dir/file1,v
+ retrieving revision 1.1
+ retrieving revision 1.1.2.1
+ Merging differences between 1.1 and 1.1.2.1 into file1
+ rcsmerge: warning: conflicts during merge
+ $ cat file1
+ <<<<<<< file1
+ key $Revision: 1.2 $
+ =======
+ key $Revision: 1.1.2.1 $
+ >>>>>>> 1.1.2.1
+ . . .
+
+ What happened was that the merge tried to merge the differences
+between 1.1 and 1.1.2.1 into your working directory. So, since the
+keyword changed from `Revision: 1.1' to `Revision: 1.1.2.1', CVS tried
+to merge that change into your working directory, which conflicted with
+the fact that your working directory had contained `Revision: 1.2'.
+
+ Here is what happens if you had used `-kk':
+
+ $ cat file1
+ key $Revision: 1.2 $
+ . . .
+ $ cvs update -kk -j br1
+ U file1
+ RCS file: /cvsroot/first-dir/file1,v
+ retrieving revision 1.1
+ retrieving revision 1.1.2.1
+ Merging differences between 1.1 and 1.1.2.1 into file1
+ $ cat file1
+ key $Revision$
+ . . .
+
+ What is going on here is that revision 1.1 and 1.1.2.1 both expand
+as plain `Revision', and therefore merging the changes between them
+into the working directory need not change anything. Therefore, there
+is no conflict.
+
+ *WARNING: In versions of CVS prior to 1.12.2, there was a major
+problem with using `-kk' on merges. Namely, `-kk' overrode any default
+keyword expansion mode set in the archive file in the repository. This
+could, unfortunately for some users, cause data corruption in binary
+files (with a default keyword expansion mode set to `-kb'). Therefore,
+when a repository contained binary files, conflicts had to be dealt
+with manually rather than using `-kk' in a merge command.*
+
+ In CVS version 1.12.2 and later, the keyword expansion mode provided
+on the command line to any CVS command no longer overrides the `-kb'
+keyword expansion mode setting for binary files, though it will still
+override other default keyword expansion modes. You can now safely
+merge using `-kk' to avoid spurious conflicts on lines containing RCS
+keywords, even when your repository contains binary files.
+
+
+File: cvs.info, Node: Recursive behavior, Next: Adding and removing, Prev: Branching and merging, Up: Top
+
+6 Recursive behavior
+********************
+
+Almost all of the subcommands of CVS work recursively when you specify
+a directory as an argument. For instance, consider this directory
+structure:
+
+ `$HOME'
+ |
+ +--tc
+ | |
+ +--CVS
+ | (internal CVS files)
+ +--Makefile
+ +--backend.c
+ +--driver.c
+ +--frontend.c
+ +--parser.c
+ +--man
+ | |
+ | +--CVS
+ | | (internal CVS files)
+ | +--tc.1
+ |
+ +--testing
+ |
+ +--CVS
+ | (internal CVS files)
+ +--testpgm.t
+ +--test2.t
+
+If `tc' is the current working directory, the following is true:
+
+ * `cvs update testing' is equivalent to
+
+ cvs update testing/testpgm.t testing/test2.t
+
+ * `cvs update testing man' updates all files in the subdirectories
+
+ * `cvs update .' or just `cvs update' updates all files in the `tc'
+ directory
+
+ If no arguments are given to `update' it will update all files in
+the current working directory and all its subdirectories. In other
+words, `.' is a default argument to `update'. This is also true for
+most of the CVS subcommands, not only the `update' command.
+
+ The recursive behavior of the CVS subcommands can be turned off with
+the `-l' option. Conversely, the `-R' option can be used to force
+recursion if `-l' is specified in `~/.cvsrc' (*note ~/.cvsrc::).
+
+ $ cvs update -l # Don't update files in subdirectories
+
+
+File: cvs.info, Node: Adding and removing, Next: History browsing, Prev: Recursive behavior, Up: Top
+
+7 Adding, removing, and renaming files and directories
+******************************************************
+
+In the course of a project, one will often add new files. Likewise
+with removing or renaming, or with directories. The general concept to
+keep in mind in all these cases is that instead of making an
+irreversible change you want CVS to record the fact that a change has
+taken place, just as with modifying an existing file. The exact
+mechanisms to do this in CVS vary depending on the situation.
+
+* Menu:
+
+* Adding files:: Adding files
+* Removing files:: Removing files
+* Removing directories:: Removing directories
+* Moving files:: Moving and renaming files
+* Moving directories:: Moving and renaming directories
+
+
+File: cvs.info, Node: Adding files, Next: Removing files, Up: Adding and removing
+
+7.1 Adding files to a directory
+===============================
+
+To add a new file to a directory, follow these steps.
+
+ * You must have a working copy of the directory. *Note Getting the
+ source::.
+
+ * Create the new file inside your working copy of the directory.
+
+ * Use `cvs add FILENAME' to tell CVS that you want to version
+ control the file. If the file contains binary data, specify `-kb'
+ (*note Binary files::).
+
+ * Use `cvs commit FILENAME' to actually check in the file into the
+ repository. Other developers cannot see the file until you
+ perform this step.
+
+ You can also use the `add' command to add a new directory.
+
+ Unlike most other commands, the `add' command is not recursive. You
+have to expcicitly name files and directories that you wish to add to
+the repository. However, each directory will need to be added
+separately before you will be able to add new files to those
+directories.
+
+ $ mkdir -p foo/bar
+ $ cp ~/myfile foo/bar/myfile
+ $ cvs add foo foo/bar
+ $ cvs add foo/bar/myfile
+
+ -- Command: cvs add [`-k' kflag] [`-m' message] files ...
+ Schedule FILES to be added to the repository. The files or
+ directories specified with `add' must already exist in the current
+ directory. To add a whole new directory hierarchy to the source
+ repository (for example, files received from a third-party
+ vendor), use the `import' command instead. *Note import::.
+
+ The added files are not placed in the source repository until you
+ use `commit' to make the change permanent. Doing an `add' on a
+ file that was removed with the `remove' command will undo the
+ effect of the `remove', unless a `commit' command intervened.
+ *Note Removing files::, for an example.
+
+ The `-k' option specifies the default way that this file will be
+ checked out; for more information see *Note Substitution modes::.
+
+ The `-m' option specifies a description for the file. This
+ description appears in the history log (if it is enabled, *note
+ history file::). It will also be saved in the version history
+ inside the repository when the file is committed. The `log'
+ command displays this description. The description can be changed
+ using `admin -t'. *Note admin::. If you omit the `-m
+ DESCRIPTION' flag, an empty string will be used. You will not be
+ prompted for a description.
+
+ For example, the following commands add the file `backend.c' to the
+repository:
+
+ $ cvs add backend.c
+ $ cvs commit -m "Early version. Not yet compilable." backend.c
+
+ When you add a file it is added only on the branch which you are
+working on (*note Branching and merging::). You can later merge the
+additions to another branch if you want (*note Merging adds and
+removals::).
+
+
+File: cvs.info, Node: Removing files, Next: Removing directories, Prev: Adding files, Up: Adding and removing
+
+7.2 Removing files
+==================
+
+Directories change. New files are added, and old files disappear.
+Still, you want to be able to retrieve an exact copy of old releases.
+
+ Here is what you can do to remove a file, but remain able to
+retrieve old revisions:
+
+ * Make sure that you have not made any uncommitted modifications to
+ the file. *Note Viewing differences::, for one way to do that.
+ You can also use the `status' or `update' command. If you remove
+ the file without committing your changes, you will of course not
+ be able to retrieve the file as it was immediately before you
+ deleted it.
+
+ * Remove the file from your working copy of the directory. You can
+ for instance use `rm'.
+
+ * Use `cvs remove FILENAME' to tell CVS that you really want to
+ delete the file.
+
+ * Use `cvs commit FILENAME' to actually perform the removal of the
+ file from the repository.
+
+ When you commit the removal of the file, CVS records the fact that
+the file no longer exists. It is possible for a file to exist on only
+some branches and not on others, or to re-add another file with the same
+name later. CVS will correctly create or not create the file, based on
+the `-r' and `-D' options specified to `checkout' or `update'.
+
+ -- Command: cvs remove [options] files ...
+ Schedule file(s) to be removed from the repository (files which
+ have not already been removed from the working directory are not
+ processed). This command does not actually remove the file from
+ the repository until you commit the removal. For a full list of
+ options, see *Note Invoking CVS::.
+
+ Here is an example of removing several files:
+
+ $ cd test
+ $ rm *.c
+ $ cvs remove
+ cvs remove: Removing .
+ cvs remove: scheduling a.c for removal
+ cvs remove: scheduling b.c for removal
+ cvs remove: use 'cvs commit' to remove these files permanently
+ $ cvs ci -m "Removed unneeded files"
+ cvs commit: Examining .
+ cvs commit: Committing .
+
+ As a convenience you can remove the file and `cvs remove' it in one
+step, by specifying the `-f' option. For example, the above example
+could also be done like this:
+
+ $ cd test
+ $ cvs remove -f *.c
+ cvs remove: scheduling a.c for removal
+ cvs remove: scheduling b.c for removal
+ cvs remove: use 'cvs commit' to remove these files permanently
+ $ cvs ci -m "Removed unneeded files"
+ cvs commit: Examining .
+ cvs commit: Committing .
+
+ If you execute `remove' for a file, and then change your mind before
+you commit, you can undo the `remove' with an `add' command.
+
+ $ ls
+ CVS ja.h oj.c
+ $ rm oj.c
+ $ cvs remove oj.c
+ cvs remove: scheduling oj.c for removal
+ cvs remove: use 'cvs commit' to remove this file permanently
+ $ cvs add oj.c
+ U oj.c
+ cvs add: oj.c, version 1.1.1.1, resurrected
+
+ If you realize your mistake before you run the `remove' command you
+can use `update' to resurrect the file:
+
+ $ rm oj.c
+ $ cvs update oj.c
+ cvs update: warning: oj.c was lost
+ U oj.c
+
+ When you remove a file it is removed only on the branch which you
+are working on (*note Branching and merging::). You can later merge
+the removals to another branch if you want (*note Merging adds and
+removals::).
+
+
+File: cvs.info, Node: Removing directories, Next: Moving files, Prev: Removing files, Up: Adding and removing
+
+7.3 Removing directories
+========================
+
+In concept, removing directories is somewhat similar to removing
+files--you want the directory to not exist in your current working
+directories, but you also want to be able to retrieve old releases in
+which the directory existed.
+
+ The way that you remove a directory is to remove all the files in
+it. You don't remove the directory itself; there is no way to do that.
+Instead you specify the `-P' option to `cvs update' or `cvs checkout',
+which will cause CVS to remove empty directories from working
+directories. (Note that `cvs export' always removes empty directories.)
+Probably the best way to do this is to always specify `-P'; if you want
+an empty directory then put a dummy file (for example `.keepme') in it
+to prevent `-P' from removing it.
+
+ Note that `-P' is implied by the `-r' or `-D' options of `checkout'.
+This way, CVS will be able to correctly create the directory or not
+depending on whether the particular version you are checking out
+contains any files in that directory.
+
+
+File: cvs.info, Node: Moving files, Next: Moving directories, Prev: Removing directories, Up: Adding and removing
+
+7.4 Moving and renaming files
+=============================
+
+Moving files to a different directory or renaming them is not
+difficult, but some of the ways in which this works may be non-obvious.
+(Moving or renaming a directory is even harder. *Note Moving
+directories::.).
+
+ The examples below assume that the file OLD is renamed to NEW.
+
+* Menu:
+
+* Outside:: The normal way to Rename
+* Inside:: A tricky, alternative way
+* Rename by copying:: Another tricky, alternative way
+
+
+File: cvs.info, Node: Outside, Next: Inside, Up: Moving files
+
+7.4.1 The Normal way to Rename
+------------------------------
+
+The normal way to move a file is to copy OLD to NEW, and then issue the
+normal CVS commands to remove OLD from the repository, and add NEW to
+it.
+
+ $ mv OLD NEW
+ $ cvs remove OLD
+ $ cvs add NEW
+ $ cvs commit -m "Renamed OLD to NEW" OLD NEW
+
+ This is the simplest way to move a file, it is not error-prone, and
+it preserves the history of what was done. Note that to access the
+history of the file you must specify the old or the new name, depending
+on what portion of the history you are accessing. For example, `cvs
+log OLD' will give the log up until the time of the rename.
+
+ When NEW is committed its revision numbers will start again, usually
+at 1.1, so if that bothers you, use the `-r TAG' option to commit. For
+more information see *Note Assigning revisions::.
+
+
+File: cvs.info, Node: Inside, Next: Rename by copying, Prev: Outside, Up: Moving files
+
+7.4.2 Moving the history file
+-----------------------------
+
+This method is more dangerous, since it involves moving files inside
+the repository. Read this entire section before trying it out!
+
+ $ cd $CVSROOT/DIR
+ $ mv OLD,v NEW,v
+
+Advantages:
+
+ * The log of changes is maintained intact.
+
+ * The revision numbers are not affected.
+
+Disadvantages:
+
+ * Old releases cannot easily be fetched from the repository. (The
+ file will show up as NEW even in revisions from the time before it
+ was renamed).
+
+ * There is no log information of when the file was renamed.
+
+ * Nasty things might happen if someone accesses the history file
+ while you are moving it. Make sure no one else runs any of the CVS
+ commands while you move it.
+
+
+File: cvs.info, Node: Rename by copying, Prev: Inside, Up: Moving files
+
+7.4.3 Copying the history file
+------------------------------
+
+This way also involves direct modifications to the repository. It is
+safe, but not without drawbacks.
+
+ # Copy the RCS file inside the repository
+ $ cd $CVSROOT/DIR
+ $ cp OLD,v NEW,v
+ # Remove the old file
+ $ cd ~/DIR
+ $ rm OLD
+ $ cvs remove OLD
+ $ cvs commit OLD
+ # Remove all tags from NEW
+ $ cvs update NEW
+ $ cvs log NEW # Remember the non-branch tag names
+ $ cvs tag -d TAG1 NEW
+ $ cvs tag -d TAG2 NEW
+ ...
+
+ By removing the tags you will be able to check out old revisions.
+
+Advantages:
+
+ * Checking out old revisions works correctly, as long as you use `-r
+ TAG' and not `-D DATE' to retrieve the revisions.
+
+ * The log of changes is maintained intact.
+
+ * The revision numbers are not affected.
+
+Disadvantages:
+
+ * You cannot easily see the history of the file across the rename.
+
+
+
+File: cvs.info, Node: Moving directories, Prev: Moving files, Up: Adding and removing
+
+7.5 Moving and renaming directories
+===================================
+
+The normal way to rename or move a directory is to rename or move each
+file within it as described in *Note Outside::. Then check out with
+the `-P' option, as described in *Note Removing directories::.
+
+ If you really want to hack the repository to rename or delete a
+directory in the repository, you can do it like this:
+
+ 1. Inform everyone who has a checked out copy of the directory that
+ the directory will be renamed. They should commit all their
+ changes in all their copies of the project containing the
+ directory to be removed, and remove all their working copies of
+ said project, before you take the steps below.
+
+ 2. Rename the directory inside the repository.
+
+ $ cd $CVSROOT/PARENT-DIR
+ $ mv OLD-DIR NEW-DIR
+
+ 3. Fix the CVS administrative files, if necessary (for instance if
+ you renamed an entire module).
+
+ 4. Tell everyone that they can check out again and continue working.
+
+
+ If someone had a working copy the CVS commands will cease to work
+for him, until he removes the directory that disappeared inside the
+repository.
+
+ It is almost always better to move the files in the directory
+instead of moving the directory. If you move the directory you are
+unlikely to be able to retrieve old releases correctly, since they
+probably depend on the name of the directories.
+
+
+File: cvs.info, Node: History browsing, Next: Binary files, Prev: Adding and removing, Up: Top
+
+8 History browsing
+******************
+
+Once you have used CVS to store a version control history--what files
+have changed when, how, and by whom, there are a variety of mechanisms
+for looking through the history.
+
+* Menu:
+
+* log messages:: Log messages
+* history database:: The history database
+* user-defined logging:: User-defined logging
+
+
+File: cvs.info, Node: log messages, Next: history database, Up: History browsing
+
+8.1 Log messages
+================
+
+Whenever you commit a file you specify a log message.
+
+ To look through the log messages which have been specified for every
+revision which has been committed, use the `cvs log' command (*note
+log::).
+
+
+File: cvs.info, Node: history database, Next: user-defined logging, Prev: log messages, Up: History browsing
+
+8.2 The history database
+========================
+
+You can use the history file (*note history file::) to log various CVS
+actions. To retrieve the information from the history file, use the
+`cvs history' command (*note history::).
+
+ Note: you can control what is logged to this file by using the
+`LogHistory' keyword in the `CVSROOT/config' file (*note config::).
+
+
+File: cvs.info, Node: user-defined logging, Prev: history database, Up: History browsing
+
+8.3 User-defined logging
+========================
+
+You can customize CVS to log various kinds of actions, in whatever
+manner you choose. These mechanisms operate by executing a script at
+various times. The script might append a message to a file listing the
+information and the programmer who created it, or send mail to a group
+of developers, or, perhaps, post a message to a particular newsgroup.
+To log commits, use the `loginfo' file (*note loginfo::), and to log
+tagging operations, use the `taginfo' file (*note taginfo::).
+
+ To log commits, checkouts, exports, and tags, respectively, you can
+also use the `-i', `-o', `-e', and `-t' options in the modules file.
+For a more flexible way of giving notifications to various users, which
+requires less in the way of keeping centralized scripts up to date, use
+the `cvs watch add' command (*note Getting Notified::); this command is
+useful even if you are not using `cvs watch on'.
+
+
+File: cvs.info, Node: Binary files, Next: Multiple developers, Prev: History browsing, Up: Top
+
+9 Handling binary files
+***********************
+
+The most common use for CVS is to store text files. With text files,
+CVS can merge revisions, display the differences between revisions in a
+human-visible fashion, and other such operations. However, if you are
+willing to give up a few of these abilities, CVS can store binary
+files. For example, one might store a web site in CVS including both
+text files and binary images.
+
+* Menu:
+
+* Binary why:: More details on issues with binary files
+* Binary howto:: How to store them
+
+
+File: cvs.info, Node: Binary why, Next: Binary howto, Up: Binary files
+
+9.1 The issues with binary files
+================================
+
+While the need to manage binary files may seem obvious if the files
+that you customarily work with are binary, putting them into version
+control does present some additional issues.
+
+ One basic function of version control is to show the differences
+between two revisions. For example, if someone else checked in a new
+version of a file, you may wish to look at what they changed and
+determine whether their changes are good. For text files, CVS provides
+this functionality via the `cvs diff' command. For binary files, it
+may be possible to extract the two revisions and then compare them with
+a tool external to CVS (for example, word processing software often has
+such a feature). If there is no such tool, one must track changes via
+other mechanisms, such as urging people to write good log messages, and
+hoping that the changes they actually made were the changes that they
+intended to make.
+
+ Another ability of a version control system is the ability to merge
+two revisions. For CVS this happens in two contexts. The first is
+when users make changes in separate working directories (*note Multiple
+developers::). The second is when one merges explicitly with the
+`update -j' command (*note Branching and merging::).
+
+ In the case of text files, CVS can merge changes made independently,
+and signal a conflict if the changes conflict. With binary files, the
+best that CVS can do is present the two different copies of the file,
+and leave it to the user to resolve the conflict. The user may choose
+one copy or the other, or may run an external merge tool which knows
+about that particular file format, if one exists. Note that having the
+user merge relies primarily on the user to not accidentally omit some
+changes, and thus is potentially error prone.
+
+ If this process is thought to be undesirable, the best choice may be
+to avoid merging. To avoid the merges that result from separate
+working directories, see the discussion of reserved checkouts (file
+locking) in *Note Multiple developers::. To avoid the merges resulting
+from branches, restrict use of branches.
+
+
+File: cvs.info, Node: Binary howto, Prev: Binary why, Up: Binary files
+
+9.2 How to store binary files
+=============================
+
+There are two issues with using CVS to store binary files. The first
+is that CVS by default converts line endings between the canonical form
+in which they are stored in the repository (linefeed only), and the
+form appropriate to the operating system in use on the client (for
+example, carriage return followed by line feed for Windows NT).
+
+ The second is that a binary file might happen to contain data which
+looks like a keyword (*note Keyword substitution::), so keyword
+expansion must be turned off.
+
+ The `-kb' option available with some CVS commands insures that
+neither line ending conversion nor keyword expansion will be done.
+
+ Here is an example of how you can create a new file using the `-kb'
+flag:
+
+ $ echo '$Id$' > kotest
+ $ cvs add -kb -m"A test file" kotest
+ $ cvs ci -m"First checkin; contains a keyword" kotest
+
+ If a file accidentally gets added without `-kb', one can use the
+`cvs admin' command to recover. For example:
+
+ $ echo '$Id$' > kotest
+ $ cvs add -m"A test file" kotest
+ $ cvs ci -m"First checkin; contains a keyword" kotest
+ $ cvs admin -kb kotest
+ $ cvs update -A kotest
+ # For non-unix systems:
+ # Copy in a good copy of the file from outside CVS
+ $ cvs commit -m "make it binary" kotest
+
+ When you check in the file `kotest' the file is not preserved as a
+binary file, because you did not check it in as a binary file. The `cvs
+admin -kb' command sets the default keyword substitution method for
+this file, but it does not alter the working copy of the file that you
+have. If you need to cope with line endings (that is, you are using
+CVS on a non-unix system), then you need to check in a new copy of the
+file, as shown by the `cvs commit' command above. On unix, the `cvs
+update -A' command suffices. (Note that you can use `cvs log' to
+determine the default keyword substitution method for a file and `cvs
+status' to determine the keyword substitution method for a working
+copy.)
+
+ However, in using `cvs admin -k' to change the keyword expansion, be
+aware that the keyword expansion mode is not version controlled. This
+means that, for example, that if you have a text file in old releases,
+and a binary file with the same name in new releases, CVS provides no
+way to check out the file in text or binary mode depending on what
+version you are checking out. There is no good workaround for this
+problem.
+
+ You can also set a default for whether `cvs add' and `cvs import'
+treat a file as binary based on its name; for example you could say
+that files who names end in `.exe' are binary. *Note Wrappers::.
+There is currently no way to have CVS detect whether a file is binary
+based on its contents. The main difficulty with designing such a
+feature is that it is not clear how to distinguish between binary and
+non-binary files, and the rules to apply would vary considerably with
+the operating system.
+
+
+File: cvs.info, Node: Multiple developers, Next: Revision management, Prev: Binary files, Up: Top
+
+10 Multiple developers
+**********************
+
+When more than one person works on a software project things often get
+complicated. Often, two people try to edit the same file
+simultaneously. One solution, known as "file locking" or "reserved
+checkouts", is to allow only one person to edit each file at a time.
+This is the only solution with some version control systems, including
+RCS and SCCS. Currently the usual way to get reserved checkouts with
+CVS is the `cvs admin -l' command (*note admin options::). This is not
+as nicely integrated into CVS as the watch features, described below,
+but it seems that most people with a need for reserved checkouts find
+it adequate.
+
+ As of CVS version 1.12.10, another technique for getting most of the
+effect of reserved checkouts is to enable advisory locks. To enable
+advisory locks, have all developers put "edit -c", "commit -c" in their
+.cvsrc file, and turn on watches in the repository. This prevents them
+from doing a `cvs edit' if anyone is already editting the file. It
+also may be possible to use plain watches together with suitable
+procedures (not enforced by software), to avoid having two people edit
+at the same time.
+
+ The default model with CVS is known as "unreserved checkouts". In
+this model, developers can edit their own "working copy" of a file
+simultaneously. The first person that commits his changes has no
+automatic way of knowing that another has started to edit it. Others
+will get an error message when they try to commit the file. They must
+then use CVS commands to bring their working copy up to date with the
+repository revision. This process is almost automatic.
+
+ CVS also supports mechanisms which facilitate various kinds of
+communication, without actually enforcing rules like reserved checkouts
+do.
+
+ The rest of this chapter describes how these various models work,
+and some of the issues involved in choosing between them.
+
+* Menu:
+
+* File status:: A file can be in several states
+* Updating a file:: Bringing a file up-to-date
+* Conflicts example:: An informative example
+* Informing others:: To cooperate you must inform
+* Concurrency:: Simultaneous repository access
+* Watches:: Mechanisms to track who is editing files
+* Choosing a model:: Reserved or unreserved checkouts?
+
+
+File: cvs.info, Node: File status, Next: Updating a file, Up: Multiple developers
+
+10.1 File status
+================
+
+Based on what operations you have performed on a checked out file, and
+what operations others have performed to that file in the repository,
+one can classify a file in a number of states. The states, as reported
+by the `status' command, are:
+
+Up-to-date
+ The file is identical with the latest revision in the repository
+ for the branch in use.
+
+Locally Modified
+ You have edited the file, and not yet committed your changes.
+
+Locally Added
+ You have added the file with `add', and not yet committed your
+ changes.
+
+Locally Removed
+ You have removed the file with `remove', and not yet committed
+ your changes.
+
+Needs Checkout
+ Someone else has committed a newer revision to the repository.
+ The name is slightly misleading; you will ordinarily use `update'
+ rather than `checkout' to get that newer revision.
+
+Needs Patch
+ Like Needs Checkout, but the CVS server will send a patch rather
+ than the entire file. Sending a patch or sending an entire file
+ accomplishes the same thing.
+
+Needs Merge
+ Someone else has committed a newer revision to the repository, and
+ you have also made modifications to the file.
+
+Unresolved Conflict
+ A file with the same name as this new file has been added to the
+ repository from a second workspace. This file will need to be
+ moved out of the way to allow an `update' to complete.
+
+File had conflicts on merge
+ This is like Locally Modified, except that a previous `update'
+ command gave a conflict. If you have not already done so, you
+ need to resolve the conflict as described in *Note Conflicts
+ example::.
+
+Unknown
+ CVS doesn't know anything about this file. For example, you have
+ created a new file and have not run `add'.
+
+
+ To help clarify the file status, `status' also reports the `Working
+revision' which is the revision that the file in the working directory
+derives from, and the `Repository revision' which is the latest
+revision in the repository for the branch in use. The `Commit
+Identifier' reflects the unique commitid of the `commit'.
+
+ The options to `status' are listed in *Note Invoking CVS::. For
+information on its `Sticky tag' and `Sticky date' output, see *Note
+Sticky tags::. For information on its `Sticky options' output, see the
+`-k' option in *Note update options::.
+
+ You can think of the `status' and `update' commands as somewhat
+complementary. You use `update' to bring your files up to date, and you
+can use `status' to give you some idea of what an `update' would do (of
+course, the state of the repository might change before you actually run
+`update'). In fact, if you want a command to display file status in a
+more brief format than is displayed by the `status' command, you can
+invoke
+
+ $ cvs -n -q update
+
+ The `-n' option means to not actually do the update, but merely to
+display statuses; the `-q' option avoids printing the name of each
+directory. For more information on the `update' command, and these
+options, see *Note Invoking CVS::.
+
+
+File: cvs.info, Node: Updating a file, Next: Conflicts example, Prev: File status, Up: Multiple developers
+
+10.2 Bringing a file up to date
+===============================
+
+When you want to update or merge a file, use the `cvs update -d'
+command. For files that are not up to date this is roughly equivalent
+to a `checkout' command: the newest revision of the file is extracted
+from the repository and put in your working directory. The `-d'
+option, not necessary with `checkout', tells CVS that you wish it to
+create directories added by other developers.
+
+ Your modifications to a file are never lost when you use `update'.
+If no newer revision exists, running `update' has no effect. If you
+have edited the file, and a newer revision is available, CVS will merge
+all changes into your working copy.
+
+ For instance, imagine that you checked out revision 1.4 and started
+editing it. In the meantime someone else committed revision 1.5, and
+shortly after that revision 1.6. If you run `update' on the file now,
+CVS will incorporate all changes between revision 1.4 and 1.6 into your
+file.
+
+ If any of the changes between 1.4 and 1.6 were made too close to any
+of the changes you have made, an "overlap" occurs. In such cases a
+warning is printed, and the resulting file includes both versions of
+the lines that overlap, delimited by special markers. *Note update::,
+for a complete description of the `update' command.
+
+
+File: cvs.info, Node: Conflicts example, Next: Informing others, Prev: Updating a file, Up: Multiple developers
+
+10.3 Conflicts example
+======================
+
+Suppose revision 1.4 of `driver.c' contains this:
+
+ #include <stdio.h>
+
+ void main()
+ {
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? 0 : 1);
+ }
+
+Revision 1.6 of `driver.c' contains this:
+
+ #include <stdio.h>
+
+ int main(int argc,
+ char **argv)
+ {
+ parse();
+ if (argc != 1)
+ {
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ }
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(!!nerr);
+ }
+
+Your working copy of `driver.c', based on revision 1.4, contains this
+before you run `cvs update':
+
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ void main()
+ {
+ init_scanner();
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+
+You run `cvs update':
+
+ $ cvs update driver.c
+ RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v
+ retrieving revision 1.4
+ retrieving revision 1.6
+ Merging differences between 1.4 and 1.6 into driver.c
+ rcsmerge warning: overlaps during merge
+ cvs update: conflicts found in driver.c
+ C driver.c
+
+CVS tells you that there were some conflicts. Your original working
+file is saved unmodified in `.#driver.c.1.4'. The new version of
+`driver.c' contains this:
+
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ int main(int argc,
+ char **argv)
+ {
+ init_scanner();
+ parse();
+ if (argc != 1)
+ {
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ }
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ <<<<<<< driver.c
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ =======
+ exit(!!nerr);
+ >>>>>>> 1.6
+ }
+
+
+ Note how all non-overlapping modifications are incorporated in your
+working copy, and that the overlapping section is clearly marked with
+`<<<<<<<', `=======' and `>>>>>>>'.
+
+ You resolve the conflict by editing the file, removing the markers
+and the erroneous line. Suppose you end up with this file:
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ int main(int argc,
+ char **argv)
+ {
+ init_scanner();
+ parse();
+ if (argc != 1)
+ {
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ }
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+
+You can now go ahead and commit this as revision 1.7.
+
+ $ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c
+ Checking in driver.c;
+ /usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c
+ new revision: 1.7; previous revision: 1.6
+ done
+
+ For your protection, CVS will refuse to check in a file if a
+conflict occurred and you have not resolved the conflict. Currently to
+resolve a conflict, you must change the timestamp on the file. In
+previous versions of CVS, you also needed to insure that the file
+contains no conflict markers. Because your file may legitimately
+contain conflict markers (that is, occurrences of `>>>>>>> ' at the
+start of a line that don't mark a conflict), the current version of CVS
+will print a warning and proceed to check in the file.
+
+ If you use release 1.04 or later of pcl-cvs (a GNU Emacs front-end
+for CVS) you can use an Emacs package called emerge to help you resolve
+conflicts. See the documentation for pcl-cvs.
+
+
+File: cvs.info, Node: Informing others, Next: Concurrency, Prev: Conflicts example, Up: Multiple developers
+
+10.4 Informing others about commits
+===================================
+
+It is often useful to inform others when you commit a new revision of a
+file. The `-i' option of the `modules' file, or the `loginfo' file,
+can be used to automate this process. *Note modules::. *Note
+loginfo::. You can use these features of CVS to, for instance,
+instruct CVS to mail a message to all developers, or post a message to
+a local newsgroup.
+
+
+File: cvs.info, Node: Concurrency, Next: Watches, Prev: Informing others, Up: Multiple developers
+
+10.5 Several developers simultaneously attempting to run CVS
+============================================================
+
+If several developers try to run CVS at the same time, one may get the
+following message:
+
+ [11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo
+
+ CVS will try again every 30 seconds, and either continue with the
+operation or print the message again, if it still needs to wait. If a
+lock seems to stick around for an undue amount of time, find the person
+holding the lock and ask them about the cvs command they are running.
+If they aren't running a cvs command, look in the repository directory
+mentioned in the message and remove files which they own whose names
+start with `#cvs.rfl', `#cvs.wfl', or `#cvs.lock'.
+
+ Note that these locks are to protect CVS's internal data structures
+and have no relationship to the word "lock" in the sense used by
+RCS--which refers to reserved checkouts (*note Multiple developers::).
+
+ Any number of people can be reading from a given repository at a
+time; only when someone is writing do the locks prevent other people
+from reading or writing.
+
+ One might hope for the following property:
+
+ If someone commits some changes in one cvs command, then an update
+ by someone else will either get all the changes, or none of them.
+
+but CVS does _not_ have this property. For example, given the files
+
+ a/one.c
+ a/two.c
+ b/three.c
+ b/four.c
+
+if someone runs
+
+ cvs ci a/two.c b/three.c
+
+and someone else runs `cvs update' at the same time, the person running
+`update' might get only the change to `b/three.c' and not the change to
+`a/two.c'.
+
+
+File: cvs.info, Node: Watches, Next: Choosing a model, Prev: Concurrency, Up: Multiple developers
+
+10.6 Mechanisms to track who is editing files
+=============================================
+
+For many groups, use of CVS in its default mode is perfectly
+satisfactory. Users may sometimes go to check in a modification only
+to find that another modification has intervened, but they deal with it
+and proceed with their check in. Other groups prefer to be able to
+know who is editing what files, so that if two people try to edit the
+same file they can choose to talk about who is doing what when rather
+than be surprised at check in time. The features in this section allow
+such coordination, while retaining the ability of two developers to
+edit the same file at the same time.
+
+ For maximum benefit developers should use `cvs edit' (not `chmod')
+to make files read-write to edit them, and `cvs release' (not `rm') to
+discard a working directory which is no longer in use, but CVS is not
+able to enforce this behavior.
+
+ If a development team wants stronger enforcement of watches and all
+team members are using a CVS client version 1.12.10 or greater to
+access a CVS server version 1.12.10 or greater, they can enable
+advisory locks. To enable advisory locks, have all developers put
+"edit -c" and "commit -c" into all .cvsrc files, and make files default
+to read only by turning on watches or putting "cvs -r" into all .cvsrc
+files. This prevents multiple people from editting a file at the same
+time (unless explicitly overriden with `-f').
+
+* Menu:
+
+* Setting a watch:: Telling CVS to watch certain files
+* Getting Notified:: Telling CVS to notify you
+* Editing files:: How to edit a file which is being watched
+* Watch information:: Information about who is watching and editing
+* Watches Compatibility:: Watches interact poorly with CVS 1.6 or earlier
+
+
+File: cvs.info, Node: Setting a watch, Next: Getting Notified, Up: Watches
+
+10.6.1 Telling CVS to watch certain files
+-----------------------------------------
+
+To enable the watch features, you first specify that certain files are
+to be watched.
+
+ -- Command: cvs watch on [`-lR'] [FILES]...
+ Specify that developers should run `cvs edit' before editing
+ FILES. CVS will create working copies of FILES read-only, to
+ remind developers to run the `cvs edit' command before working on
+ them.
+
+ If FILES includes the name of a directory, CVS arranges to watch
+ all files added to the corresponding repository directory, and
+ sets a default for files added in the future; this allows the user
+ to set notification policies on a per-directory basis. The
+ contents of the directory are processed recursively, unless the
+ `-l' option is given. The `-R' option can be used to force
+ recursion if the `-l' option is set in `~/.cvsrc' (*note
+ ~/.cvsrc::).
+
+ If FILES is omitted, it defaults to the current directory.
+
+
+ -- Command: cvs watch off [`-lR'] [FILES]...
+ Do not create FILES read-only on checkout; thus, developers will
+ not be reminded to use `cvs edit' and `cvs unedit'.
+
+ The FILES and options are processed as for `cvs watch on'.
+
+
+
+File: cvs.info, Node: Getting Notified, Next: Editing files, Prev: Setting a watch, Up: Watches
+
+10.6.2 Telling CVS to notify you
+--------------------------------
+
+You can tell CVS that you want to receive notifications about various
+actions taken on a file. You can do this without using `cvs watch on'
+for the file, but generally you will want to use `cvs watch on', to
+remind developers to use the `cvs edit' command.
+
+ -- Command: cvs watch add [`-lR'] [`-a' ACTION]... [FILES]...
+ Add the current user to the list of people to receive notification
+ of work done on FILES.
+
+ The `-a' option specifies what kinds of events CVS should notify
+ the user about. ACTION is one of the following:
+
+ `edit'
+ Another user has applied the `cvs edit' command (described
+ below) to a watched file.
+
+ `commit'
+ Another user has committed changes to one of the named FILES.
+
+ `unedit'
+ Another user has abandoned editing a file (other than by
+ committing changes). They can do this in several ways, by:
+
+ * applying the `cvs unedit' command (described below) to
+ the file
+
+ * applying the `cvs release' command (*note release::) to
+ the file's parent directory (or recursively to a
+ directory more than one level up)
+
+ * deleting the file and allowing `cvs update' to recreate
+ it
+
+
+ `all'
+ All of the above.
+
+ `none'
+ None of the above. (This is useful with `cvs edit',
+ described below.)
+
+
+ The `-a' option may appear more than once, or not at all. If
+ omitted, the action defaults to `all'.
+
+ The FILES and options are processed as for `cvs watch on'.
+
+
+ -- Command: cvs watch remove [`-lR'] [`-a' ACTION]... [FILES]...
+ Remove a notification request established using `cvs watch add';
+ the arguments are the same. If the `-a' option is present, only
+ watches for the specified actions are removed.
+
+
+ When the conditions exist for notification, CVS calls the `notify'
+administrative file. Edit `notify' as one edits the other
+administrative files (*note Intro administrative files::). This file
+follows the usual conventions for administrative files (*note
+syntax::), where each line is a regular expression followed by a
+command to execute. The command should contain a single occurrence of
+`%s' which will be replaced by the user to notify; the rest of the
+information regarding the notification will be supplied to the command
+on standard input. The standard thing to put in the `notify' file is
+the single line:
+
+ ALL mail %s -s "CVS notification"
+
+This causes users to be notified by electronic mail.
+
+ Note that if you set this up in the straightforward way, users
+receive notifications on the server machine. One could of course write
+a `notify' script which directed notifications elsewhere, but to make
+this easy, CVS allows you to associate a notification address for each
+user. To do so create a file `users' in `CVSROOT' with a line for each
+user in the format USER:VALUE. Then instead of passing the name of the
+user to be notified to `notify', CVS will pass the VALUE (normally an
+email address on some other machine).
+
+ CVS does not notify you for your own changes. Currently this check
+is done based on whether the user name of the person taking the action
+which triggers notification matches the user name of the person getting
+notification. In fact, in general, the watches features only track one
+edit by each user. It probably would be more useful if watches tracked
+each working directory separately, so this behavior might be worth
+changing.
+
+
+File: cvs.info, Node: Editing files, Next: Watch information, Prev: Getting Notified, Up: Watches
+
+10.6.3 How to edit a file which is being watched
+------------------------------------------------
+
+Since a file which is being watched is checked out read-only, you
+cannot simply edit it. To make it read-write, and inform others that
+you are planning to edit it, use the `cvs edit' command. Some systems
+call this a "checkout", but CVS uses that term for obtaining a copy of
+the sources (*note Getting the source::), an operation which those
+systems call a "get" or a "fetch".
+
+ -- Command: cvs edit [`-lR'] [`-a' ACTION]... [FILES]...
+ Prepare to edit the working files FILES. CVS makes the FILES
+ read-write, and notifies users who have requested `edit'
+ notification for any of FILES.
+
+ The `cvs edit' command accepts the same options as the `cvs watch
+ add' command, and establishes a temporary watch for the user on
+ FILES; CVS will remove the watch when FILES are `unedit'ed or
+ `commit'ted. If the user does not wish to receive notifications,
+ she should specify `-a none'.
+
+ The FILES and the options are processed as for the `cvs watch'
+ commands.
+
+ There are two additional options that `cvs edit' understands as of
+ CVS client and server versions 1.12.10 but `cvs watch' does not.
+ The first is `-c', which causes `cvs edit' to fail if anyone else
+ is editting the file. This is probably only useful when `edit -c'
+ and `commit -c' are specified in all developers' `.cvsrc' files.
+ This behavior may be overriden this via the `-f' option, which
+ overrides `-c' and allows multiple edits to succeed.
+
+
+ Normally when you are done with a set of changes, you use the `cvs
+commit' command, which checks in your changes and returns the watched
+files to their usual read-only state. But if you instead decide to
+abandon your changes, or not to make any changes, you can use the `cvs
+unedit' command.
+
+ -- Command: cvs unedit [`-lR'] [FILES]...
+ Abandon work on the working files FILES, and revert them to the
+ repository versions on which they are based. CVS makes those
+ FILES read-only for which users have requested notification using
+ `cvs watch on'. CVS notifies users who have requested `unedit'
+ notification for any of FILES.
+
+ The FILES and options are processed as for the `cvs watch'
+ commands.
+
+ If watches are not in use, the `unedit' command probably does not
+ work, and the way to revert to the repository version is with the
+ command `cvs update -C file' (*note update::). The meaning is not
+ precisely the same; the latter may also bring in some changes
+ which have been made in the repository since the last time you
+ updated.
+
+ When using client/server CVS, you can use the `cvs edit' and `cvs
+unedit' commands even if CVS is unable to successfully communicate with
+the server; the notifications will be sent upon the next successful CVS
+command.
+
+
+File: cvs.info, Node: Watch information, Next: Watches Compatibility, Prev: Editing files, Up: Watches
+
+10.6.4 Information about who is watching and editing
+----------------------------------------------------
+
+ -- Command: cvs watchers [`-lR'] [FILES]...
+ List the users currently watching changes to FILES. The report
+ includes the files being watched, and the mail address of each
+ watcher.
+
+ The FILES and options are processed as for the `cvs watch'
+ commands.
+
+
+ -- Command: cvs editors [`-lR'] [FILES]...
+ List the users currently working on FILES. The report includes
+ the mail address of each user, the time when the user began
+ working with the file, and the host and path of the working
+ directory containing the file.
+
+ The FILES and options are processed as for the `cvs watch'
+ commands.
+
+
+
+File: cvs.info, Node: Watches Compatibility, Prev: Watch information, Up: Watches
+
+10.6.5 Using watches with old versions of CVS
+---------------------------------------------
+
+If you use the watch features on a repository, it creates `CVS'
+directories in the repository and stores the information about watches
+in that directory. If you attempt to use CVS 1.6 or earlier with the
+repository, you get an error message such as the following (all on one
+line):
+
+ cvs update: cannot open CVS/Entries for reading:
+ No such file or directory
+
+and your operation will likely be aborted. To use the watch features,
+you must upgrade all copies of CVS which use that repository in local
+or server mode. If you cannot upgrade, use the `watch off' and `watch
+remove' commands to remove all watches, and that will restore the
+repository to a state which CVS 1.6 can cope with.
+
+
+File: cvs.info, Node: Choosing a model, Prev: Watches, Up: Multiple developers
+
+10.7 Choosing between reserved or unreserved checkouts
+======================================================
+
+Reserved and unreserved checkouts each have pros and cons. Let it be
+said that a lot of this is a matter of opinion or what works given
+different groups' working styles, but here is a brief description of
+some of the issues. There are many ways to organize a team of
+developers. CVS does not try to enforce a certain organization. It is
+a tool that can be used in several ways.
+
+ Reserved checkouts can be very counter-productive. If two persons
+want to edit different parts of a file, there may be no reason to
+prevent either of them from doing so. Also, it is common for someone
+to take out a lock on a file, because they are planning to edit it, but
+then forget to release the lock.
+
+ People, especially people who are familiar with reserved checkouts,
+often wonder how often conflicts occur if unreserved checkouts are
+used, and how difficult they are to resolve. The experience with many
+groups is that they occur rarely and usually are relatively
+straightforward to resolve.
+
+ The rarity of serious conflicts may be surprising, until one realizes
+that they occur only when two developers disagree on the proper design
+for a given section of code; such a disagreement suggests that the team
+has not been communicating properly in the first place. In order to
+collaborate under _any_ source management regimen, developers must
+agree on the general design of the system; given this agreement,
+overlapping changes are usually straightforward to merge.
+
+ In some cases unreserved checkouts are clearly inappropriate. If no
+merge tool exists for the kind of file you are managing (for example
+word processor files or files edited by Computer Aided Design
+programs), and it is not desirable to change to a program which uses a
+mergeable data format, then resolving conflicts is going to be
+unpleasant enough that you generally will be better off to simply avoid
+the conflicts instead, by using reserved checkouts.
+
+ The watches features described above in *Note Watches:: can be
+considered to be an intermediate model between reserved checkouts and
+unreserved checkouts. When you go to edit a file, it is possible to
+find out who else is editing it. And rather than having the system
+simply forbid both people editing the file, it can tell you what the
+situation is and let you figure out whether it is a problem in that
+particular case or not. Therefore, for some groups watches can be
+considered the best of both the reserved checkout and unreserved
+checkout worlds.
+
+ As of CVS client and server versions 1.12.10, you may also enable
+advisory locks by putting `edit -c' and `commit -c' in all developers'
+`.cvsrc' files. After this is done, `cvs edit' will fail if there are
+any other editors, and `cvs commit' will fail if the committer has not
+registered to edit the file via `cvs edit'. This is most effective in
+conjunction with files checked out read-only by default, which may be
+enabled by turning on watches in the repository or by putting `cvs -r'
+in all `.cvsrc' files.
+
+
+File: cvs.info, Node: Revision management, Next: Keyword substitution, Prev: Multiple developers, Up: Top
+
+11 Revision management
+**********************
+
+If you have read this far, you probably have a pretty good grasp on
+what CVS can do for you. This chapter talks a little about things that
+you still have to decide.
+
+ If you are doing development on your own using CVS you could
+probably skip this chapter. The questions this chapter takes up become
+more important when more than one person is working in a repository.
+
+* Menu:
+
+* When to commit:: Some discussion on the subject
+
+
+File: cvs.info, Node: When to commit, Up: Revision management
+
+11.1 When to commit?
+====================
+
+Your group should decide which policy to use regarding commits.
+Several policies are possible, and as your experience with CVS grows
+you will probably find out what works for you.
+
+ If you commit files too quickly you might commit files that do not
+even compile. If your partner updates his working sources to include
+your buggy file, he will be unable to compile the code. On the other
+hand, other persons will not be able to benefit from the improvements
+you make to the code if you commit very seldom, and conflicts will
+probably be more common.
+
+ It is common to only commit files after making sure that they can be
+compiled. Some sites require that the files pass a test suite.
+Policies like this can be enforced using the commitinfo file (*note
+commitinfo::), but you should think twice before you enforce such a
+convention. By making the development environment too controlled it
+might become too regimented and thus counter-productive to the real
+goal, which is to get software written.
+
+
+File: cvs.info, Node: Keyword substitution, Next: Tracking sources, Prev: Revision management, Up: Top
+
+12 Keyword substitution
+***********************
+
+As long as you edit source files inside a working directory you can
+always find out the state of your files via `cvs status' and `cvs log'.
+But as soon as you export the files from your development environment
+it becomes harder to identify which revisions they are.
+
+ CVS can use a mechanism known as "keyword substitution" (or "keyword
+expansion") to help identifying the files. Embedded strings of the form
+`$KEYWORD$' and `$KEYWORD:...$' in a file are replaced with strings of
+the form `$KEYWORD:VALUE$' whenever you obtain a new revision of the
+file.
+
+* Menu:
+
+* Keyword list:: Keywords
+* Using keywords:: Using keywords
+* Avoiding substitution:: Avoiding substitution
+* Substitution modes:: Substitution modes
+* Configuring keyword expansion:: Configuring keyword expansion
+* Log keyword:: Problems with the $Log$ keyword.
+
+
+File: cvs.info, Node: Keyword list, Next: Using keywords, Up: Keyword substitution
+
+12.1 Keyword List
+=================
+
+This is a list of the keywords:
+
+`$Author$'
+ The login name of the user who checked in the revision.
+
+`$CVSHeader$'
+ A standard header (similar to $Header$, but with the CVS root
+ stripped off). It contains the relative pathname of the RCS file
+ to the CVS root, the revision number, the date (UTC), the author,
+ the state, and the locker (if locked). Files will normally never
+ be locked when you use CVS.
+
+ Note that this keyword has only been recently introduced to CVS
+ and may cause problems with existing installations if $CVSHeader$
+ is already in the files for a different purpose. This keyword may
+ be excluded using the `KeywordExpand=eCVSHeader' in the
+ `CVSROOT/config' file. See *Note Configuring keyword expansion::
+ for more details.
+
+`$Date$'
+ The date and time (UTC) the revision was checked in.
+
+`$Header$'
+ A standard header containing the full pathname of the RCS file,
+ the revision number, the date (UTC), the author, the state, and
+ the locker (if locked). Files will normally never be locked when
+ you use CVS.
+
+`$Id$'
+ Same as `$Header$', except that the RCS filename is without a path.
+
+`$Name$'
+ Tag name used to check out this file. The keyword is expanded
+ only if one checks out with an explicit tag name. For example,
+ when running the command `cvs co -r first', the keyword expands to
+ `Name: first'.
+
+`$Locker$'
+ The login name of the user who locked the revision (empty if not
+ locked, which is the normal case unless `cvs admin -l' is in use).
+
+`$Log$'
+ The log message supplied during commit, preceded by a header
+ containing the RCS filename, the revision number, the author, and
+ the date (UTC). Existing log messages are _not_ replaced.
+ Instead, the new log message is inserted after `$Log:...$'. By
+ default, each new line is prefixed with the same string which
+ precedes the `$Log$' keyword, unless it exceeds the
+ `MaxCommentLeaderLength' set in `CVSROOT/config'.
+
+ For example, if the file contains:
+
+ /* Here is what people have been up to:
+ *
+ * $Log: frob.c,v $
+ * Revision 1.1 1997/01/03 14:23:51 joe
+ * Add the superfrobnicate option
+ *
+ */
+
+ then additional lines which are added when expanding the `$Log$'
+ keyword will be preceded by ` * '. Unlike previous versions of
+ CVS and RCS, the "comment leader" from the RCS file is not used.
+ The `$Log$' keyword is useful for accumulating a complete change
+ log in a source file, but for several reasons it can be
+ problematic.
+
+ If the prefix of the `$Log$' keyword turns out to be longer than
+ `MaxCommentLeaderLength', CVS will skip expansion of this keyword
+ unless `UseArchiveCommentLeader' is also set in `CVSROOT/config'
+ and a `comment leader' is set in the RCS archive file, in which
+ case the comment leader will be used instead. For more on setting
+ the comment leader in the RCS archive file, *Note admin::. For
+ more on configuring the default `$Log$' substitution behavior,
+ *Note config::.
+
+ *Note Log keyword::.
+
+`$RCSfile$'
+ The name of the RCS file without a path.
+
+`$Revision$'
+ The revision number assigned to the revision.
+
+`$Source$'
+ The full pathname of the RCS file.
+
+`$State$'
+ The state assigned to the revision. States can be assigned with
+ `cvs admin -s'--see *Note admin options::.
+
+`Local keyword'
+ The `LocalKeyword' option in the `CVSROOT/config' file may be used
+ to specify a local keyword which is to be used as an alias for one
+ of the keywords: $Id$, $Header$, or $CVSHeader$. For example, if
+ the `CVSROOT/config' file contains a line with
+ `LocalKeyword=MYBSD=CVSHeader', then a file with the local keyword
+ $MYBSD$ will be expanded as if it were a $CVSHeader$ keyword. If
+ the src/frob.c file contained this keyword, it might look
+ something like this:
+
+ /*
+ * $MYBSD: src/frob.c,v 1.1 2003/05/04 09:27:45 john Exp $
+ */
+
+ Many repositories make use of a such a "local keyword" feature. An
+ old patch to CVS provided the `LocalKeyword' feature using a `tag='
+ option and called this the "custom tag" or "local tag" feature. It
+ was used in conjunction with the what they called the `tagexpand='
+ option. In CVS this other option is known as the `KeywordExpand'
+ option. See *Note Configuring keyword expansion:: for more
+ details.
+
+ Examples from popular projects include: $FreeBSD$, $NetBSD$,
+ $OpenBSD$, $XFree86$, $Xorg$.
+
+ The advantage of this is that you can include your local version
+ information in a file using this local keyword without disrupting
+ the upstream version information (which may be a different local
+ keyword or a standard keyword). Allowing bug reports and the like
+ to more properly identify the source of the original bug to the
+ third-party and reducing the number of conflicts that arise during
+ an import of a new version.
+
+ All keyword expansion except the local keyword may be disabled
+ using the `KeywordExpand' option in the `CVSROOT/config' file--see
+ *Note Configuring keyword expansion:: for more details.
+
+
+
+File: cvs.info, Node: Using keywords, Next: Avoiding substitution, Prev: Keyword list, Up: Keyword substitution
+
+12.2 Using keywords
+===================
+
+To include a keyword string you simply include the relevant text
+string, such as `$Id$', inside the file, and commit the file. CVS will
+automatically (Or, more accurately, as part of the update run that
+automatically happens after a commit.) expand the string as part of
+the commit operation.
+
+ It is common to embed the `$Id$' string in the source files so that
+it gets passed through to generated files. For example, if you are
+managing computer program source code, you might include a variable
+which is initialized to contain that string. Or some C compilers may
+provide a `#pragma ident' directive. Or a document management system
+might provide a way to pass a string through to generated files.
+
+ The `ident' command (which is part of the RCS package) can be used
+to extract keywords and their values from a file. This can be handy
+for text files, but it is even more useful for extracting keywords from
+binary files.
+
+ $ ident samp.c
+ samp.c:
+ $Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+ $ gcc samp.c
+ $ ident a.out
+ a.out:
+ $Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+
+ SCCS is another popular revision control system. It has a command,
+`what', which is very similar to `ident' and used for the same purpose.
+Many sites without RCS have SCCS. Since `what' looks for the
+character sequence `@(#)' it is easy to include keywords that are
+detected by either command. Simply prefix the keyword with the magic
+SCCS phrase, like this:
+
+ static char *id="@(#) $Id: ab.c,v 1.5 1993/10/19 14:57:32 ceder Exp $";
+
+
+File: cvs.info, Node: Avoiding substitution, Next: Substitution modes, Prev: Using keywords, Up: Keyword substitution
+
+12.3 Avoiding substitution
+==========================
+
+Keyword substitution has its disadvantages. Sometimes you might want
+the literal text string `$Author$' to appear inside a file without CVS
+interpreting it as a keyword and expanding it into something like
+`$Author: ceder $'.
+
+ There is unfortunately no way to selectively turn off keyword
+substitution. You can use `-ko' (*note Substitution modes::) to turn
+off keyword substitution entirely.
+
+ In many cases you can avoid using keywords in the source, even
+though they appear in the final product. For example, the source for
+this manual contains `$@asis{}Author$' whenever the text `$Author$'
+should appear. In `nroff' and `troff' you can embed the null-character
+`\&' inside the keyword for a similar effect.
+
+ It is also possible to specify an explicit list of keywords to
+include or exclude using the `KeywordExpand' option in the
+`CVSROOT/config' file-see *Note Configuring keyword expansion:: for
+more details. This feature is intended primarily for use with the
+`LocalKeyword' option-see *Note Keyword list::.
+
+
+File: cvs.info, Node: Substitution modes, Next: Configuring keyword expansion, Prev: Avoiding substitution, Up: Keyword substitution
+
+12.4 Substitution modes
+=======================
+
+Each file has a stored default substitution mode, and each working
+directory copy of a file also has a substitution mode. The former is
+set by the `-k' option to `cvs add' and `cvs admin'; the latter is set
+by the `-k' or `-A' options to `cvs checkout' or `cvs update'. `cvs
+diff' and `cvs rdiff' also have `-k' options. For some examples, see
+*Note Binary files::, and *Note Merging and keywords::.
+
+ The modes available are:
+
+`-kkv'
+ Generate keyword strings using the default form, e.g. `$Revision:
+ 5.7 $' for the `Revision' keyword.
+
+`-kkvl'
+ Like `-kkv', except that a locker's name is always inserted if the
+ given revision is currently locked. The locker's name is only
+ relevant if `cvs admin -l' is in use.
+
+`-kk'
+ Generate only keyword names in keyword strings; omit their values.
+ For example, for the `Revision' keyword, generate the string
+ `$Revision$' instead of `$Revision: 5.7 $'. This option is useful
+ to ignore differences due to keyword substitution when comparing
+ different revisions of a file (*note Merging and keywords::).
+
+`-ko'
+ Generate the old keyword string, present in the working file just
+ before it was checked in. For example, for the `Revision'
+ keyword, generate the string `$Revision: 1.1 $' instead of
+ `$Revision: 5.7 $' if that is how the string appeared when the
+ file was checked in.
+
+`-kb'
+ Like `-ko', but also inhibit conversion of line endings between
+ the canonical form in which they are stored in the repository
+ (linefeed only), and the form appropriate to the operating system
+ in use on the client. For systems, like unix, which use linefeed
+ only to terminate lines, this is very similar to `-ko'. For more
+ information on binary files, see *Note Binary files::. In CVS
+ version 1.12.2 and later `-kb', as set by `cvs add', `cvs admin',
+ or `cvs import' may not be overridden by a `-k' option specified
+ on the command line.
+
+`-kv'
+ Generate only keyword values for keyword strings. For example,
+ for the `Revision' keyword, generate the string `5.7' instead of
+ `$Revision: 5.7 $'. This can help generate files in programming
+ languages where it is hard to strip keyword delimiters like
+ `$Revision: $' from a string. However, further keyword
+ substitution cannot be performed once the keyword names are
+ removed, so this option should be used with care.
+
+ One often would like to use `-kv' with `cvs export'--*note
+ export::. But be aware that doesn't handle an export containing
+ binary files correctly.
+
+
+
+File: cvs.info, Node: Configuring keyword expansion, Next: Log keyword, Prev: Substitution modes, Up: Keyword substitution
+
+12.5 Configuring Keyword Expansion
+==================================
+
+In a repository that includes third-party software on vendor branches,
+it is sometimes helpful to configure CVS to use a local keyword instead
+of the standard $Id$ or $Header$ keywords. Examples from real projects
+include $Xorg$, $XFree86$, $FreeBSD$, $NetBSD$, $OpenBSD$, and even
+$dotat$. The advantage of this is that you can include your local
+version information in a file using this local keyword (sometimes
+called a "custom tag" or a "local tag") without disrupting the upstream
+version information (which may be a different local keyword or a
+standard keyword). In these cases, it is typically desirable to disable
+the expansion of all keywords except the configured local keyword.
+
+ The `KeywordExpand' option in the `CVSROOT/config' file is intended
+to allow for the either the explicit exclusion of a keyword or list of
+keywords, or for the explicit inclusion of a keyword or a list of
+keywords. This list may include the `LocalKeyword' that has been
+configured.
+
+ The `KeywordExpand' option is followed by `=' and the next character
+may either be `i' to start an inclusion list or `e' to start an
+exclusion list. If the following lines were added to the
+`CVSROOT/config' file:
+
+ # Add a "MyBSD" keyword and restrict keyword
+ # expansion
+ LocalKeyword=MyBSD=CVSHeader
+ KeywordExpand=iMyBSD
+
+ then only the $MyBSD$ keyword would be expanded. A list may be
+used. The this example:
+
+ # Add a "MyBSD" keyword and restrict keyword
+ # expansion to the MyBSD, Name and Date keywords.
+ LocalKeyword=MyBSD=CVSHeader
+ KeywordExpand=iMyBSD,Name,Date
+
+ would allow $MyBSD$, $Name$, and $Date$ to be expanded.
+
+ It is also possible to configure an exclusion list using the
+following:
+
+ # Do not expand the non-RCS keyword CVSHeader
+ KeywordExpand=eCVSHeader
+
+ This allows CVS to ignore the recently introduced $CVSHeader$
+keyword and retain all of the others. The exclusion entry could also
+contain the standard RCS keyword list, but this could be confusing to
+users that expect RCS keywords to be expanded, so care should be taken
+to properly set user expectations for a repository that is configured
+in that manner.
+
+ If there is a desire to not have any RCS keywords expanded and not
+use the `-ko' flags everywhere, an administrator may disable all
+keyword expansion using the `CVSROOT/config' line:
+
+ # Do not expand any RCS keywords
+ KeywordExpand=i
+
+ this could be confusing to users that expect RCS keywords like $Id$
+to be expanded properly, so care should be taken to properly set user
+expectations for a repository so configured.
+
+ It should be noted that a patch to provide both the `KeywordExpand'
+and `LocalKeyword' features has been around a long time. However, that
+patch implemented these features using `tag=' and `tagexpand=' keywords
+and those keywords are NOT recognized.
+
+
+File: cvs.info, Node: Log keyword, Prev: Configuring keyword expansion, Up: Keyword substitution
+
+12.6 Problems with the $Log$ keyword.
+=====================================
+
+The `$Log$' keyword is somewhat controversial. As long as you are
+working on your development system the information is easily accessible
+even if you do not use the `$Log$' keyword--just do a `cvs log'. Once
+you export the file the history information might be useless anyhow.
+
+ A more serious concern is that CVS is not good at handling `$Log$'
+entries when a branch is merged onto the main trunk. Conflicts often
+result from the merging operation.
+
+ People also tend to "fix" the log entries in the file (correcting
+spelling mistakes and maybe even factual errors). If that is done the
+information from `cvs log' will not be consistent with the information
+inside the file. This may or may not be a problem in real life.
+
+ It has been suggested that the `$Log$' keyword should be inserted
+_last_ in the file, and not in the files header, if it is to be used at
+all. That way the long list of change messages will not interfere with
+everyday source file browsing.
+
+
+File: cvs.info, Node: Tracking sources, Next: Builds, Prev: Keyword substitution, Up: Top
+
+13 Tracking third-party sources
+*******************************
+
+If you modify a program to better fit your site, you probably want to
+include your modifications when the next release of the program
+arrives. CVS can help you with this task.
+
+ In the terminology used in CVS, the supplier of the program is
+called a "vendor". The unmodified distribution from the vendor is
+checked in on its own branch, the "vendor branch". CVS reserves branch
+1.1.1 for this use.
+
+ When you modify the source and commit it, your revision will end up
+on the main trunk. When a new release is made by the vendor, you
+commit it on the vendor branch and copy the modifications onto the main
+trunk.
+
+ Use the `import' command to create and update the vendor branch.
+When you import a new file, (usually) the vendor branch is made the
+`head' revision, so anyone that checks out a copy of the file gets that
+revision. When a local modification is committed it is placed on the
+main trunk, and made the `head' revision.
+
+* Menu:
+
+* First import:: Importing for the first time
+* Update imports:: Updating with the import command
+* Reverting local changes:: Reverting to the latest vendor release
+* Binary files in imports:: Binary files require special handling
+* Keywords in imports:: Keyword substitution might be undesirable
+* Multiple vendor branches:: What if you get sources from several places?
+
+
+File: cvs.info, Node: First import, Next: Update imports, Up: Tracking sources
+
+13.1 Importing for the first time
+=================================
+
+Use the `import' command to check in the sources for the first time.
+When you use the `import' command to track third-party sources, the
+"vendor tag" and "release tags" are useful. The "vendor tag" is a
+symbolic name for the branch (which is always 1.1.1, unless you use the
+`-b BRANCH' flag--see *Note Multiple vendor branches::.). The "release
+tags" are symbolic names for a particular release, such as `FSF_0_04'.
+
+ Note that `import' does _not_ change the directory in which you
+invoke it. In particular, it does not set up that directory as a CVS
+working directory; if you want to work with the sources import them
+first and then check them out into a different directory (*note Getting
+the source::).
+
+ Suppose you have the sources to a program called `wdiff' in a
+directory `wdiff-0.04', and are going to make private modifications
+that you want to be able to use even when new releases are made in the
+future. You start by importing the source to your repository:
+
+ $ cd wdiff-0.04
+ $ cvs import -m "Import of FSF v. 0.04" fsf/wdiff FSF_DIST WDIFF_0_04
+
+ The vendor tag is named `FSF_DIST' in the above example, and the
+only release tag assigned is `WDIFF_0_04'.
+
+
+File: cvs.info, Node: Update imports, Next: Reverting local changes, Prev: First import, Up: Tracking sources
+
+13.2 Updating with the import command
+=====================================
+
+When a new release of the source arrives, you import it into the
+repository with the same `import' command that you used to set up the
+repository in the first place. The only difference is that you specify
+a different release tag this time:
+
+ $ tar xfz wdiff-0.05.tar.gz
+ $ cd wdiff-0.05
+ $ cvs import -m "Import of FSF v. 0.05" fsf/wdiff FSF_DIST WDIFF_0_05
+
+ *WARNING: If you use a release tag that already exists in one of the
+repository archives, files removed by an import may not be detected.*
+
+ For files that have not been modified locally, the newly created
+revision becomes the head revision. If you have made local changes,
+`import' will warn you that you must merge the changes into the main
+trunk, and tell you to use `checkout -j' to do so:
+
+ $ cvs checkout -jFSF_DIST:yesterday -jFSF_DIST wdiff
+
+The above command will check out the latest revision of `wdiff',
+merging the changes made on the vendor branch `FSF_DIST' since
+yesterday into the working copy. If any conflicts arise during the
+merge they should be resolved in the normal way (*note Conflicts
+example::). Then, the modified files may be committed.
+
+ However, it is much better to use the two release tags rather than
+using a date on the branch as suggested above:
+
+ $ cvs checkout -jWDIFF_0_04 -jWDIFF_0_05 wdiff
+
+The reason this is better is that using a date, as suggested above,
+assumes that you do not import more than one release of a product per
+day. More importantly, using the release tags allows CVS to detect
+files that were removed between the two vendor releases and mark them
+for removal. Since `import' has no way to detect removed files, you
+should do a merge like this even if `import' doesn't tell you to.
+
+
+File: cvs.info, Node: Reverting local changes, Next: Binary files in imports, Prev: Update imports, Up: Tracking sources
+
+13.3 Reverting to the latest vendor release
+===========================================
+
+You can also revert local changes completely and return to the latest
+vendor release by changing the `head' revision back to the vendor
+branch on all files. For example, if you have a checked-out copy of
+the sources in `~/work.d/wdiff', and you want to revert to the vendor's
+version for all the files in that directory, you would type:
+
+ $ cd ~/work.d/wdiff
+ $ cvs admin -bFSF_DIST .
+
+You must specify the `-bFSF_DIST' without any space after the `-b'.
+*Note admin options::.
+
+
+File: cvs.info, Node: Binary files in imports, Next: Keywords in imports, Prev: Reverting local changes, Up: Tracking sources
+
+13.4 How to handle binary files with cvs import
+===============================================
+
+Use the `-k' wrapper option to tell import which files are binary.
+*Note Wrappers::.
+
+
+File: cvs.info, Node: Keywords in imports, Next: Multiple vendor branches, Prev: Binary files in imports, Up: Tracking sources
+
+13.5 How to handle keyword substitution with cvs import
+=======================================================
+
+The sources which you are importing may contain keywords (*note Keyword
+substitution::). For example, the vendor may use CVS or some other
+system which uses similar keyword expansion syntax. If you just import
+the files in the default fashion, then the keyword expansions supplied
+by the vendor will be replaced by keyword expansions supplied by your
+own copy of CVS. It may be more convenient to maintain the expansions
+supplied by the vendor, so that this information can supply information
+about the sources that you imported from the vendor.
+
+ To maintain the keyword expansions supplied by the vendor, supply
+the `-ko' option to `cvs import' the first time you import the file.
+This will turn off keyword expansion for that file entirely, so if you
+want to be more selective you'll have to think about what you want and
+use the `-k' option to `cvs update' or `cvs admin' as appropriate.
+
+
+File: cvs.info, Node: Multiple vendor branches, Prev: Keywords in imports, Up: Tracking sources
+
+13.6 Multiple vendor branches
+=============================
+
+All the examples so far assume that there is only one vendor from which
+you are getting sources. In some situations you might get sources from
+a variety of places. For example, suppose that you are dealing with a
+project where many different people and teams are modifying the
+software. There are a variety of ways to handle this, but in some
+cases you have a bunch of source trees lying around and what you want
+to do more than anything else is just to all put them in CVS so that
+you at least have them in one place.
+
+ For handling situations in which there may be more than one vendor,
+you may specify the `-b' option to `cvs import'. It takes as an
+argument the vendor branch to import to. The default is `-b 1.1.1'.
+
+ For example, suppose that there are two teams, the red team and the
+blue team, that are sending you sources. You want to import the red
+team's efforts to branch 1.1.1 and use the vendor tag RED. You want to
+import the blue team's efforts to branch 1.1.3 and use the vendor tag
+BLUE. So the commands you might use are:
+
+ $ cvs import dir RED RED_1-0
+ $ cvs import -b 1.1.3 dir BLUE BLUE_1-5
+
+ Note that if your vendor tag does not match your `-b' option, CVS
+will not detect this case! For example,
+
+ $ cvs import -b 1.1.3 dir RED RED_1-0
+
+Be careful; this kind of mismatch is sure to sow confusion or worse. I
+can't think of a useful purpose for the ability to specify a mismatch
+here, but if you discover such a use, don't. CVS is likely to make this
+an error in some future release.
+
+
+File: cvs.info, Node: Builds, Next: Special Files, Prev: Tracking sources, Up: Top
+
+14 How your build system interacts with CVS
+*******************************************
+
+As mentioned in the introduction, CVS does not contain software for
+building your software from source code. This section describes how
+various aspects of your build system might interact with CVS.
+
+ One common question, especially from people who are accustomed to
+RCS, is how to make their build get an up to date copy of the sources.
+The answer to this with CVS is two-fold. First of all, since CVS
+itself can recurse through directories, there is no need to modify your
+`Makefile' (or whatever configuration file your build tool uses) to
+make sure each file is up to date. Instead, just use two commands,
+first `cvs -q update' and then `make' or whatever the command is to
+invoke your build tool. Secondly, you do not necessarily _want_ to get
+a copy of a change someone else made until you have finished your own
+work. One suggested approach is to first update your sources, then
+implement, build and test the change you were thinking of, and then
+commit your sources (updating first if necessary). By periodically (in
+between changes, using the approach just described) updating your
+entire tree, you ensure that your sources are sufficiently up to date.
+
+ One common need is to record which versions of which source files
+went into a particular build. This kind of functionality is sometimes
+called "bill of materials" or something similar. The best way to do
+this with CVS is to use the `tag' command to record which versions went
+into a given build (*note Tags::).
+
+ Using CVS in the most straightforward manner possible, each
+developer will have a copy of the entire source tree which is used in a
+particular build. If the source tree is small, or if developers are
+geographically dispersed, this is the preferred solution. In fact one
+approach for larger projects is to break a project down into smaller
+separately-compiled subsystems, and arrange a way of releasing them
+internally so that each developer need check out only those subsystems
+which they are actively working on.
+
+ Another approach is to set up a structure which allows developers to
+have their own copies of some files, and for other files to access
+source files from a central location. Many people have come up with
+some such a system using features such as the symbolic link feature
+found in many operating systems, or the `VPATH' feature found in many
+versions of `make'. One build tool which is designed to help with this
+kind of thing is Odin (see
+`ftp://ftp.cs.colorado.edu/pub/distribs/odin').
+
+
+File: cvs.info, Node: Special Files, Next: CVS commands, Prev: Builds, Up: Top
+
+15 Special Files
+****************
+
+In normal circumstances, CVS works only with regular files. Every file
+in a project is assumed to be persistent; it must be possible to open,
+read and close them; and so on. CVS also ignores file permissions and
+ownerships, leaving such issues to be resolved by the developer at
+installation time. In other words, it is not possible to "check in" a
+device into a repository; if the device file cannot be opened, CVS will
+refuse to handle it. Files also lose their ownerships and permissions
+during repository transactions.
+
+
+File: cvs.info, Node: CVS commands, Next: Invoking CVS, Prev: Special Files, Up: Top
+
+Appendix A Guide to CVS commands
+********************************
+
+This appendix describes the overall structure of CVS commands, and
+describes some commands in detail (others are described elsewhere; for
+a quick reference to CVS commands, *note Invoking CVS::).
+
+* Menu:
+
+* Structure:: Overall structure of CVS commands
+* Exit status:: Indicating CVS's success or failure
+* ~/.cvsrc:: Default options with the ~/.cvsrc file
+* Global options:: Options you give to the left of cvs_command
+* Common options:: Options you give to the right of cvs_command
+* Date input formats:: Acceptable formats for date specifications
+* admin:: Administration
+* annotate:: What revision modified each line of a file?
+* checkout:: Checkout sources for editing
+* commit:: Check files into the repository
+* diff:: Show differences between revisions
+* export:: Export sources from CVS, similar to checkout
+* history:: Show status of files and users
+* import:: Import sources into CVS, using vendor branches
+* log:: Show log messages for files
+* ls & rls:: List files in the repository
+* rdiff:: 'patch' format diffs between releases
+* release:: Indicate that a directory is no longer in use
+* server & pserver:: Act as a server for a client on stdin/stdout
+* update:: Bring work tree in sync with repository
+
+
+File: cvs.info, Node: Structure, Next: Exit status, Up: CVS commands
+
+A.1 Overall structure of CVS commands
+=====================================
+
+The overall format of all CVS commands is:
+
+ cvs [ cvs_options ] cvs_command [ command_options ] [ command_args ]
+
+`cvs'
+ The name of the CVS program.
+
+`cvs_options'
+ Some options that affect all sub-commands of CVS. These are
+ described below.
+
+`cvs_command'
+ One of several different sub-commands. Some of the commands have
+ aliases that can be used instead; those aliases are noted in the
+ reference manual for that command. There are only two situations
+ where you may omit `cvs_command': `cvs -H' elicits a list of
+ available commands, and `cvs -v' displays version information on
+ CVS itself.
+
+`command_options'
+ Options that are specific for the command.
+
+`command_args'
+ Arguments to the commands.
+
+ There is unfortunately some confusion between `cvs_options' and
+`command_options'. When given as a `cvs_option', some options only
+affect some of the commands. When given as a `command_option' it may
+have a different meaning, and be accepted by more commands. In other
+words, do not take the above categorization too seriously. Look at the
+documentation instead.
+
+
+File: cvs.info, Node: Exit status, Next: ~/.cvsrc, Prev: Structure, Up: CVS commands
+
+A.2 CVS's exit status
+=====================
+
+CVS can indicate to the calling environment whether it succeeded or
+failed by setting its "exit status". The exact way of testing the exit
+status will vary from one operating system to another. For example in
+a unix shell script the `$?' variable will be 0 if the last command
+returned a successful exit status, or greater than 0 if the exit status
+indicated failure.
+
+ If CVS is successful, it returns a successful status; if there is an
+error, it prints an error message and returns a failure status. The
+one exception to this is the `cvs diff' command. It will return a
+successful status if it found no differences, or a failure status if
+there were differences or if there was an error. Because this behavior
+provides no good way to detect errors, in the future it is possible that
+`cvs diff' will be changed to behave like the other CVS commands.
+
+
+File: cvs.info, Node: ~/.cvsrc, Next: Global options, Prev: Exit status, Up: CVS commands
+
+A.3 Default options and the ~/.cvsrc file
+=========================================
+
+There are some `command_options' that are used so often that you might
+have set up an alias or some other means to make sure you always
+specify that option. One example (the one that drove the
+implementation of the `.cvsrc' support, actually) is that many people
+find the default output of the `diff' command to be very hard to read,
+and that either context diffs or unidiffs are much easier to understand.
+
+ The `~/.cvsrc' file is a way that you can add default options to
+`cvs_commands' within cvs, instead of relying on aliases or other shell
+scripts.
+
+ The format of the `~/.cvsrc' file is simple. The file is searched
+for a line that begins with the same name as the `cvs_command' being
+executed. If a match is found, then the remainder of the line is split
+up (at whitespace characters) into separate options and added to the
+command arguments _before_ any options from the command line.
+
+ If a command has two names (e.g., `checkout' and `co'), the official
+name, not necessarily the one used on the command line, will be used to
+match against the file. So if this is the contents of the user's
+`~/.cvsrc' file:
+
+ log -N
+ diff -uN
+ rdiff -u
+ update -Pd
+ checkout -P
+ release -d
+
+the command `cvs checkout foo' would have the `-P' option added to the
+arguments, as well as `cvs co foo'.
+
+ With the example file above, the output from `cvs diff foobar' will
+be in unidiff format. `cvs diff -c foobar' will provide context diffs,
+as usual. Getting "old" format diffs would be slightly more
+complicated, because `diff' doesn't have an option to specify use of
+the "old" format, so you would need `cvs -f diff foobar'.
+
+ In place of the command name you can use `cvs' to specify global
+options (*note Global options::). For example the following line in
+`.cvsrc'
+
+ cvs -z6
+
+causes CVS to use compression level 6.
+
+
+File: cvs.info, Node: Global options, Next: Common options, Prev: ~/.cvsrc, Up: CVS commands
+
+A.4 Global options
+==================
+
+The available `cvs_options' (that are given to the left of
+`cvs_command') are:
+
+`--allow-root=ROOTDIR'
+ May be invoked multiple times to specify one legal CVSROOT
+ directory with each invocation. Also causes CVS to preparse the
+ configuration file for each specified root, which can be useful
+ when configuring write proxies, See *Note Password authentication
+ server:: & *Note Write proxies::.
+
+`-a'
+ Authenticate all communication between the client and the server.
+ Only has an effect on the CVS client. As of this writing, this is
+ only implemented when using a GSSAPI connection (*note GSSAPI
+ authenticated::). Authentication prevents certain sorts of attacks
+ involving hijacking the active TCP connection. Enabling
+ authentication does not enable encryption.
+
+`-b BINDIR'
+ In CVS 1.9.18 and older, this specified that RCS programs are in
+ the BINDIR directory. Current versions of CVS do not run RCS
+ programs; for compatibility this option is accepted, but it does
+ nothing.
+
+`-T TEMPDIR'
+ Use TEMPDIR as the directory where temporary files are located.
+
+ The CVS client and server store temporary files in a temporary
+ directory. The path to this temporary directory is set via, in
+ order of precedence:
+
+ * The argument to the global `-T' option.
+
+ * The value set for `TmpDir' in the config file (server only -
+ *note config::).
+
+ * The contents of the `$TMPDIR' environment variable
+ (`%TMPDIR%' on Windows - *note Environment variables::).
+
+ * /tmp
+
+
+ Temporary directories should always be specified as an absolute
+ pathname. When running a CVS client, `-T' affects only the local
+ process; specifying `-T' for the client has no effect on the
+ server and vice versa.
+
+`-d CVS_ROOT_DIRECTORY'
+ Use CVS_ROOT_DIRECTORY as the root directory pathname of the
+ repository. Overrides the setting of the `$CVSROOT' environment
+ variable. *Note Repository::.
+
+`-e EDITOR'
+ Use EDITOR to enter revision log information. Overrides the
+ setting of the `$CVSEDITOR' and `$EDITOR' environment variables.
+ For more information, see *Note Committing your changes::.
+
+`-f'
+ Do not read the `~/.cvsrc' file. This option is most often used
+ because of the non-orthogonality of the CVS option set. For
+ example, the `cvs log' option `-N' (turn off display of tag names)
+ does not have a corresponding option to turn the display on. So
+ if you have `-N' in the `~/.cvsrc' entry for `log', you may need
+ to use `-f' to show the tag names.
+
+`-H'
+`--help'
+ Display usage information about the specified `cvs_command' (but
+ do not actually execute the command). If you don't specify a
+ command name, `cvs -H' displays overall help for CVS, including a
+ list of other help options.
+
+`-R'
+ Turns on read-only repository mode. This allows one to check out
+ from a read-only repository, such as within an anoncvs server, or
+ from a CD-ROM repository.
+
+ Same effect as if the `CVSREADONLYFS' environment variable is set.
+ Using `-R' can also considerably speed up checkouts over NFS.
+
+`-n'
+ Do not change any files. Attempt to execute the `cvs_command',
+ but only to issue reports; do not remove, update, or merge any
+ existing files, or create any new files.
+
+ Note that CVS will not necessarily produce exactly the same output
+ as without `-n'. In some cases the output will be the same, but
+ in other cases CVS will skip some of the processing that would
+ have been required to produce the exact same output.
+
+`-Q'
+ Cause the command to be really quiet; the command will only
+ generate output for serious problems.
+
+`-q'
+ Cause the command to be somewhat quiet; informational messages,
+ such as reports of recursion through subdirectories, are
+ suppressed.
+
+`-r'
+ Make new working files read-only. Same effect as if the
+ `$CVSREAD' environment variable is set (*note Environment
+ variables::). The default is to make working files writable,
+ unless watches are on (*note Watches::).
+
+`-s VARIABLE=VALUE'
+ Set a user variable (*note Variables::).
+
+`-t'
+ Trace program execution; display messages showing the steps of CVS
+ activity. Particularly useful with `-n' to explore the potential
+ impact of an unfamiliar command.
+
+`-v'
+
+`--version'
+ Display version and copyright information for CVS.
+
+`-w'
+ Make new working files read-write. Overrides the setting of the
+ `$CVSREAD' environment variable. Files are created read-write by
+ default, unless `$CVSREAD' is set or `-r' is given.
+
+`-x'
+ Encrypt all communication between the client and the server. Only
+ has an effect on the CVS client. As of this writing, this is only
+ implemented when using a GSSAPI connection (*note GSSAPI
+ authenticated::) or a Kerberos connection (*note Kerberos
+ authenticated::). Enabling encryption implies that message
+ traffic is also authenticated. Encryption support is not
+ available by default; it must be enabled using a special configure
+ option, `--enable-encryption', when you build CVS.
+
+`-z LEVEL'
+ Request compression LEVEL for network traffic. CVS interprets
+ LEVEL identically to the `gzip' program. Valid levels are 1 (high
+ speed, low compression) to 9 (low speed, high compression), or 0
+ to disable compression (the default). Data sent to the server will
+ be compressed at the requested level and the client will request
+ the server use the same compression level for data returned. The
+ server will use the closest level allowed by the server
+ administrator to compress returned data. This option only has an
+ effect when passed to the CVS client.
+
+
+File: cvs.info, Node: Common options, Next: Date input formats, Prev: Global options, Up: CVS commands
+
+A.5 Common command options
+==========================
+
+This section describes the `command_options' that are available across
+several CVS commands. These options are always given to the right of
+`cvs_command'. Not all commands support all of these options; each
+option is only supported for commands where it makes sense. However,
+when a command has one of these options you can almost always count on
+the same behavior of the option as in other commands. (Other command
+options, which are listed with the individual commands, may have
+different behavior from one CVS command to the other).
+
+ *Note_ the `history' command is an exception; it supports many
+options that conflict even with these standard options.*
+
+`-D DATE_SPEC'
+ Use the most recent revision no later than DATE_SPEC. DATE_SPEC
+ is a single argument, a date description specifying a date in the
+ past.
+
+ The specification is "sticky" when you use it to make a private
+ copy of a source file; that is, when you get a working file using
+ `-D', CVS records the date you specified, so that further updates
+ in the same directory will use the same date (for more information
+ on sticky tags/dates, *note Sticky tags::).
+
+ `-D' is available with the `annotate', `checkout', `diff',
+ `export', `history', `ls', `rdiff', `rls', `rtag', `tag', and
+ `update' commands. (The `history' command uses this option in a
+ slightly different way; *note history options::).
+
+ For a complete description of the date formats accepted by CVS,
+ *Note Date input formats::.
+
+ Remember to quote the argument to the `-D' flag so that your shell
+ doesn't interpret spaces as argument separators. A command using
+ the `-D' flag can look like this:
+
+ $ cvs diff -D "1 hour ago" cvs.texinfo
+
+`-f'
+ When you specify a particular date or tag to CVS commands, they
+ normally ignore files that do not contain the tag (or did not
+ exist prior to the date) that you specified. Use the `-f' option
+ if you want files retrieved even when there is no match for the
+ tag or date. (The most recent revision of the file will be used).
+
+ Note that even with `-f', a tag that you specify must exist (that
+ is, in some file, not necessary in every file). This is so that
+ CVS will continue to give an error if you mistype a tag name.
+
+ `-f' is available with these commands: `annotate', `checkout',
+ `export', `rdiff', `rtag', and `update'.
+
+ *WARNING: The `commit' and `remove' commands also have a `-f'
+ option, but it has a different behavior for those commands. See
+ *Note commit options::, and *Note Removing files::.*
+
+`-k KFLAG'
+ Override the default processing of RCS keywords other than `-kb'.
+ *Note Keyword substitution::, for the meaning of KFLAG. Used with
+ the `checkout' and `update' commands, your KFLAG specification is
+ "sticky"; that is, when you use this option with a `checkout' or
+ `update' command, CVS associates your selected KFLAG with any files
+ it operates on, and continues to use that KFLAG with future
+ commands on the same files until you specify otherwise.
+
+ The `-k' option is available with the `add', `checkout', `diff',
+ `export', `import', `rdiff', and `update' commands.
+
+ *WARNING: Prior to CVS version 1.12.2, the `-k' flag overrode the
+ `-kb' indication for a binary file. This could sometimes corrupt
+ binary files. *Note Merging and keywords::, for more.*
+
+`-l'
+ Local; run only in current working directory, rather than
+ recursing through subdirectories.
+
+ Available with the following commands: `annotate', `checkout',
+ `commit', `diff', `edit', `editors', `export', `log', `rdiff',
+ `remove', `rtag', `status', `tag', `unedit', `update', `watch',
+ and `watchers'.
+
+`-m MESSAGE'
+ Use MESSAGE as log information, instead of invoking an editor.
+
+ Available with the following commands: `add', `commit' and
+ `import'.
+
+`-n'
+ Do not run any tag program. (A program can be specified to run in
+ the modules database (*note modules::); this option bypasses it).
+
+ *Note_ this is not the same as the `cvs -n' program option, which
+ you can specify to the left of a cvs command!*
+
+ Available with the `checkout', `commit', `export', and `rtag'
+ commands.
+
+`-P'
+ Prune empty directories. See *Note Removing directories::.
+
+`-p'
+ Pipe the files retrieved from the repository to standard output,
+ rather than writing them in the current directory. Available with
+ the `checkout' and `update' commands.
+
+`-R'
+ Process directories recursively. This is the default for all CVS
+ commands, with the exception of `ls' & `rls'.
+
+ Available with the following commands: `annotate', `checkout',
+ `commit', `diff', `edit', `editors', `export', `ls', `rdiff',
+ `remove', `rls', `rtag', `status', `tag', `unedit', `update',
+ `watch', and `watchers'.
+
+`-r TAG'
+
+`-r TAG[:DATE]'
+ Use the revision specified by the TAG argument (and the DATE
+ argument for the commands which accept it) instead of the default
+ "head" revision. As well as arbitrary tags defined with the `tag'
+ or `rtag' command, two special tags are always available: `HEAD'
+ refers to the most recent version available in the repository, and
+ `BASE' refers to the revision you last checked out into the
+ current working directory.
+
+ The tag specification is sticky when you use this with `checkout'
+ or `update' to make your own copy of a file: CVS remembers the tag
+ and continues to use it on future update commands, until you
+ specify otherwise (for more information on sticky tags/dates,
+ *note Sticky tags::).
+
+ The tag can be either a symbolic or numeric tag, as described in
+ *Note Tags::, or the name of a branch, as described in *Note
+ Branching and merging::. When TAG is the name of a branch, some
+ commands accept the optional DATE argument to specify the revision
+ as of the given date on the branch. When a command expects a
+ specific revision, the name of a branch is interpreted as the most
+ recent revision on that branch.
+
+ Specifying the `-q' global option along with the `-r' command
+ option is often useful, to suppress the warning messages when the
+ RCS file does not contain the specified tag.
+
+ *Note_ this is not the same as the overall `cvs -r' option, which
+ you can specify to the left of a CVS command!*
+
+ `-r TAG' is available with the `commit' and `history' commands.
+
+ `-r TAG[:DATE]' is available with the `annotate', `checkout',
+ `diff', `export', `rdiff', `rtag', and `update' commands.
+
+`-W'
+ Specify file names that should be filtered. You can use this
+ option repeatedly. The spec can be a file name pattern of the
+ same type that you can specify in the `.cvswrappers' file.
+ Available with the following commands: `import', and `update'.
+
+
+
+File: cvs.info, Node: Date input formats, Next: admin, Prev: Common options, Up: CVS commands
+
+A.6 Date input formats
+======================
+
+First, a quote:
+
+ Our units of temporal measurement, from seconds on up to months,
+ are so complicated, asymmetrical and disjunctive so as to make
+ coherent mental reckoning in time all but impossible. Indeed, had
+ some tyrannical god contrived to enslave our minds to time, to
+ make it all but impossible for us to escape subjection to sodden
+ routines and unpleasant surprises, he could hardly have done
+ better than handing down our present system. It is like a set of
+ trapezoidal building blocks, with no vertical or horizontal
+ surfaces, like a language in which the simplest thought demands
+ ornate constructions, useless particles and lengthy
+ circumlocutions. Unlike the more successful patterns of language
+ and science, which enable us to face experience boldly or at least
+ level-headedly, our system of temporal calculation silently and
+ persistently encourages our terror of time.
+
+ ... It is as though architects had to measure length in feet,
+ width in meters and height in ells; as though basic instruction
+ manuals demanded a knowledge of five different languages. It is
+ no wonder then that we often look into our own immediate past or
+ future, last Tuesday or a week from Sunday, with feelings of
+ helpless confusion. ...
+
+ -- Robert Grudin, `Time and the Art of Living'.
+
+ This section describes the textual date representations that GNU
+programs accept. These are the strings you, as a user, can supply as
+arguments to the various programs. The C interface (via the `get_date'
+function) is not described here.
+
+* Menu:
+
+* General date syntax:: Common rules.
+* Calendar date items:: 19 Dec 1994.
+* Time of day items:: 9:20pm.
+* Time zone items:: EST, PDT, GMT.
+* Day of week items:: Monday and others.
+* Relative items in date strings:: next tuesday, 2 years ago.
+* Pure numbers in date strings:: 19931219, 1440.
+* Seconds since the Epoch:: @1078100502.
+* Specifying time zone rules:: TZ="America/New_York", TZ="UTC0".
+* Authors of get_date:: Bellovin, Eggert, Salz, Berets, et al.
+
+
+File: cvs.info, Node: General date syntax, Next: Calendar date items, Up: Date input formats
+
+A.6.1 General date syntax
+-------------------------
+
+A "date" is a string, possibly empty, containing many items separated
+by whitespace. The whitespace may be omitted when no ambiguity arises.
+The empty string means the beginning of today (i.e., midnight). Order
+of the items is immaterial. A date string may contain many flavors of
+items:
+
+ * calendar date items
+
+ * time of day items
+
+ * time zone items
+
+ * day of the week items
+
+ * relative items
+
+ * pure numbers.
+
+We describe each of these item types in turn, below.
+
+ A few ordinal numbers may be written out in words in some contexts.
+This is most useful for specifying day of the week items or relative
+items (see below). Among the most commonly used ordinal numbers, the
+word `last' stands for -1, `this' stands for 0, and `first' and `next'
+both stand for 1. Because the word `second' stands for the unit of
+time there is no way to write the ordinal number 2, but for convenience
+`third' stands for 3, `fourth' for 4, `fifth' for 5, `sixth' for 6,
+`seventh' for 7, `eighth' for 8, `ninth' for 9, `tenth' for 10,
+`eleventh' for 11 and `twelfth' for 12.
+
+ When a month is written this way, it is still considered to be
+written numerically, instead of being "spelled in full"; this changes
+the allowed strings.
+
+ In the current implementation, only English is supported for words
+and abbreviations like `AM', `DST', `EST', `first', `January',
+`Sunday', `tomorrow', and `year'.
+
+ The output of the `date' command is not always acceptable as a date
+string, not only because of the language problem, but also because
+there is no standard meaning for time zone items like `IST'. When using
+`date' to generate a date string intended to be parsed later, specify a
+date format that is independent of language and that does not use time
+zone items other than `UTC' and `Z'. Here are some ways to do this:
+
+ $ LC_ALL=C TZ=UTC0 date
+ Mon Mar 1 00:21:42 UTC 2004
+ $ TZ=UTC0 date +'%Y-%m-%d %H:%M:%SZ'
+ 2004-03-01 00:21:42Z
+ $ date --iso-8601=ns | tr T ' ' # --iso-8601 is a GNU extension.
+ 2004-02-29 16:21:42,692722128-0800
+ $ date --rfc-2822 # a GNU extension
+ Sun, 29 Feb 2004 16:21:42 -0800
+ $ date +'%Y-%m-%d %H:%M:%S %z' # %z is a GNU extension.
+ 2004-02-29 16:21:42 -0800
+ $ date +'@%s.%N' # %s and %N are GNU extensions.
+ @1078100502.692722128
+
+ Alphabetic case is completely ignored in dates. Comments may be
+introduced between round parentheses, as long as included parentheses
+are properly nested. Hyphens not followed by a digit are currently
+ignored. Leading zeros on numbers are ignored.
+
+
+File: cvs.info, Node: Calendar date items, Next: Time of day items, Prev: General date syntax, Up: Date input formats
+
+A.6.2 Calendar date items
+-------------------------
+
+A "calendar date item" specifies a day of the year. It is specified
+differently, depending on whether the month is specified numerically or
+literally. All these strings specify the same calendar date:
+
+ 1972-09-24 # ISO 8601.
+ 72-9-24 # Assume 19xx for 69 through 99,
+ # 20xx for 00 through 68.
+ 72-09-24 # Leading zeros are ignored.
+ 9/24/72 # Common U.S. writing.
+ 24 September 1972
+ 24 Sept 72 # September has a special abbreviation.
+ 24 Sep 72 # Three-letter abbreviations always allowed.
+ Sep 24, 1972
+ 24-sep-72
+ 24sep72
+
+ The year can also be omitted. In this case, the last specified year
+is used, or the current year if none. For example:
+
+ 9/24
+ sep 24
+
+ Here are the rules.
+
+ For numeric months, the ISO 8601 format `YEAR-MONTH-DAY' is allowed,
+where YEAR is any positive number, MONTH is a number between 01 and 12,
+and DAY is a number between 01 and 31. A leading zero must be present
+if a number is less than ten. If YEAR is 68 or smaller, then 2000 is
+added to it; otherwise, if YEAR is less than 100, then 1900 is added to
+it. The construct `MONTH/DAY/YEAR', popular in the United States, is
+accepted. Also `MONTH/DAY', omitting the year.
+
+ Literal months may be spelled out in full: `January', `February',
+`March', `April', `May', `June', `July', `August', `September',
+`October', `November' or `December'. Literal months may be abbreviated
+to their first three letters, possibly followed by an abbreviating dot.
+It is also permitted to write `Sept' instead of `September'.
+
+ When months are written literally, the calendar date may be given as
+any of the following:
+
+ DAY MONTH YEAR
+ DAY MONTH
+ MONTH DAY YEAR
+ DAY-MONTH-YEAR
+
+ Or, omitting the year:
+
+ MONTH DAY
+
+
+File: cvs.info, Node: Time of day items, Next: Time zone items, Prev: Calendar date items, Up: Date input formats
+
+A.6.3 Time of day items
+-----------------------
+
+A "time of day item" in date strings specifies the time on a given day.
+Here are some examples, all of which represent the same time:
+
+ 20:02:00.000000
+ 20:02
+ 8:02pm
+ 20:02-0500 # In EST (U.S. Eastern Standard Time).
+
+ More generally, the time of day may be given as
+`HOUR:MINUTE:SECOND', where HOUR is a number between 0 and 23, MINUTE
+is a number between 0 and 59, and SECOND is a number between 0 and 59
+possibly followed by `.' or `,' and a fraction containing one or more
+digits. Alternatively, `:SECOND' can be omitted, in which case it is
+taken to be zero.
+
+ If the time is followed by `am' or `pm' (or `a.m.' or `p.m.'), HOUR
+is restricted to run from 1 to 12, and `:MINUTE' may be omitted (taken
+to be zero). `am' indicates the first half of the day, `pm' indicates
+the second half of the day. In this notation, 12 is the predecessor of
+1: midnight is `12am' while noon is `12pm'. (This is the zero-oriented
+interpretation of `12am' and `12pm', as opposed to the old tradition
+derived from Latin which uses `12m' for noon and `12pm' for midnight.)
+
+ The time may alternatively be followed by a time zone correction,
+expressed as `SHHMM', where S is `+' or `-', HH is a number of zone
+hours and MM is a number of zone minutes. You can also separate HH
+from MM with a colon. When a time zone correction is given this way, it
+forces interpretation of the time relative to Coordinated Universal
+Time (UTC), overriding any previous specification for the time zone or
+the local time zone. For example, `+0530' and `+05:30' both stand for
+the time zone 5.5 hours ahead of UTC (e.g., India). The MINUTE part of
+the time of day may not be elided when a time zone correction is used.
+This is the best way to specify a time zone correction by fractional
+parts of an hour.
+
+ Either `am'/`pm' or a time zone correction may be specified, but not
+both.
+
+
+File: cvs.info, Node: Time zone items, Next: Day of week items, Prev: Time of day items, Up: Date input formats
+
+A.6.4 Time zone items
+---------------------
+
+A "time zone item" specifies an international time zone, indicated by a
+small set of letters, e.g., `UTC' or `Z' for Coordinated Universal
+Time. Any included periods are ignored. By following a
+non-daylight-saving time zone by the string `DST' in a separate word
+(that is, separated by some white space), the corresponding daylight
+saving time zone may be specified. Alternatively, a
+non-daylight-saving time zone can be followed by a time zone
+correction, to add the two values. This is normally done only for
+`UTC'; for example, `UTC+05:30' is equivalent to `+05:30'.
+
+ Time zone items other than `UTC' and `Z' are obsolescent and are not
+recommended, because they are ambiguous; for example, `EST' has a
+different meaning in Australia than in the United States. Instead,
+it's better to use unambiguous numeric time zone corrections like
+`-0500', as described in the previous section.
+
+ If neither a time zone item nor a time zone correction is supplied,
+time stamps are interpreted using the rules of the default time zone
+(*note Specifying time zone rules::).
+
+
+File: cvs.info, Node: Day of week items, Next: Relative items in date strings, Prev: Time zone items, Up: Date input formats
+
+A.6.5 Day of week items
+-----------------------
+
+The explicit mention of a day of the week will forward the date (only
+if necessary) to reach that day of the week in the future.
+
+ Days of the week may be spelled out in full: `Sunday', `Monday',
+`Tuesday', `Wednesday', `Thursday', `Friday' or `Saturday'. Days may
+be abbreviated to their first three letters, optionally followed by a
+period. The special abbreviations `Tues' for `Tuesday', `Wednes' for
+`Wednesday' and `Thur' or `Thurs' for `Thursday' are also allowed.
+
+ A number may precede a day of the week item to move forward
+supplementary weeks. It is best used in expression like `third
+monday'. In this context, `last DAY' or `next DAY' is also acceptable;
+they move one week before or after the day that DAY by itself would
+represent.
+
+ A comma following a day of the week item is ignored.
+
+
+File: cvs.info, Node: Relative items in date strings, Next: Pure numbers in date strings, Prev: Day of week items, Up: Date input formats
+
+A.6.6 Relative items in date strings
+------------------------------------
+
+"Relative items" adjust a date (or the current date if none) forward or
+backward. The effects of relative items accumulate. Here are some
+examples:
+
+ 1 year
+ 1 year ago
+ 3 years
+ 2 days
+
+ The unit of time displacement may be selected by the string `year'
+or `month' for moving by whole years or months. These are fuzzy units,
+as years and months are not all of equal duration. More precise units
+are `fortnight' which is worth 14 days, `week' worth 7 days, `day'
+worth 24 hours, `hour' worth 60 minutes, `minute' or `min' worth 60
+seconds, and `second' or `sec' worth one second. An `s' suffix on
+these units is accepted and ignored.
+
+ The unit of time may be preceded by a multiplier, given as an
+optionally signed number. Unsigned numbers are taken as positively
+signed. No number at all implies 1 for a multiplier. Following a
+relative item by the string `ago' is equivalent to preceding the unit
+by a multiplier with value -1.
+
+ The string `tomorrow' is worth one day in the future (equivalent to
+`day'), the string `yesterday' is worth one day in the past (equivalent
+to `day ago').
+
+ The strings `now' or `today' are relative items corresponding to
+zero-valued time displacement, these strings come from the fact a
+zero-valued time displacement represents the current time when not
+otherwise changed by previous items. They may be used to stress other
+items, like in `12:00 today'. The string `this' also has the meaning
+of a zero-valued time displacement, but is preferred in date strings
+like `this thursday'.
+
+ When a relative item causes the resulting date to cross a boundary
+where the clocks were adjusted, typically for daylight saving time, the
+resulting date and time are adjusted accordingly.
+
+ The fuzz in units can cause problems with relative items. For
+example, `2003-07-31 -1 month' might evaluate to 2003-07-01, because
+2003-06-31 is an invalid date. To determine the previous month more
+reliably, you can ask for the month before the 15th of the current
+month. For example:
+
+ $ date -R
+ Thu, 31 Jul 2003 13:02:39 -0700
+ $ date --date='-1 month' +'Last month was %B?'
+ Last month was July?
+ $ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
+ Last month was June!
+
+ Also, take care when manipulating dates around clock changes such as
+daylight saving leaps. In a few cases these have added or subtracted
+as much as 24 hours from the clock, so it is often wise to adopt
+universal time by setting the `TZ' environment variable to `UTC0'
+before embarking on calendrical calculations.
+
+
+File: cvs.info, Node: Pure numbers in date strings, Next: Seconds since the Epoch, Prev: Relative items in date strings, Up: Date input formats
+
+A.6.7 Pure numbers in date strings
+----------------------------------
+
+The precise interpretation of a pure decimal number depends on the
+context in the date string.
+
+ If the decimal number is of the form YYYYMMDD and no other calendar
+date item (*note Calendar date items::) appears before it in the date
+string, then YYYY is read as the year, MM as the month number and DD as
+the day of the month, for the specified calendar date.
+
+ If the decimal number is of the form HHMM and no other time of day
+item appears before it in the date string, then HH is read as the hour
+of the day and MM as the minute of the hour, for the specified time of
+day. MM can also be omitted.
+
+ If both a calendar date and a time of day appear to the left of a
+number in the date string, but no relative item, then the number
+overrides the year.
+
+
+File: cvs.info, Node: Seconds since the Epoch, Next: Specifying time zone rules, Prev: Pure numbers in date strings, Up: Date input formats
+
+A.6.8 Seconds since the Epoch
+-----------------------------
+
+If you precede a number with `@', it represents an internal time stamp
+as a count of seconds. The number can contain an internal decimal
+point (either `.' or `,'); any excess precision not supported by the
+internal representation is truncated toward minus infinity. Such a
+number cannot be combined with any other date item, as it specifies a
+complete time stamp.
+
+ Internally, computer times are represented as a count of seconds
+since an epoch--a well-defined point of time. On GNU and POSIX
+systems, the epoch is 1970-01-01 00:00:00 UTC, so `@0' represents this
+time, `@1' represents 1970-01-01 00:00:01 UTC, and so forth. GNU and
+most other POSIX-compliant systems support such times as an extension
+to POSIX, using negative counts, so that `@-1' represents 1969-12-31
+23:59:59 UTC.
+
+ Traditional Unix systems count seconds with 32-bit two's-complement
+integers and can represent times from 1901-12-13 20:45:52 through
+2038-01-19 03:14:07 UTC. More modern systems use 64-bit counts of
+seconds with nanosecond subcounts, and can represent all the times in
+the known lifetime of the universe to a resolution of 1 nanosecond.
+
+ On most systems, these counts ignore the presence of leap seconds.
+For example, on most systems `@915148799' represents 1998-12-31
+23:59:59 UTC, `@915148800' represents 1999-01-01 00:00:00 UTC, and
+there is no way to represent the intervening leap second 1998-12-31
+23:59:60 UTC.
+
+
+File: cvs.info, Node: Specifying time zone rules, Next: Authors of get_date, Prev: Seconds since the Epoch, Up: Date input formats
+
+A.6.9 Specifying time zone rules
+--------------------------------
+
+Normally, dates are interpreted using the rules of the current time
+zone, which in turn are specified by the `TZ' environment variable, or
+by a system default if `TZ' is not set. To specify a different set of
+default time zone rules that apply just to one date, start the date
+with a string of the form `TZ="RULE"'. The two quote characters (`"')
+must be present in the date, and any quotes or backslashes within RULE
+must be escaped by a backslash.
+
+ For example, with the GNU `date' command you can answer the question
+"What time is it in New York when a Paris clock shows 6:30am on October
+31, 2004?" by using a date beginning with `TZ="Europe/Paris"' as shown
+in the following shell transcript:
+
+ $ export TZ="America/New_York"
+ $ date --date='TZ="Europe/Paris" 2004-10-31 06:30'
+ Sun Oct 31 01:30:00 EDT 2004
+
+ In this example, the `--date' operand begins with its own `TZ'
+setting, so the rest of that operand is processed according to
+`Europe/Paris' rules, treating the string `2004-10-31 06:30' as if it
+were in Paris. However, since the output of the `date' command is
+processed according to the overall time zone rules, it uses New York
+time. (Paris was normally six hours ahead of New York in 2004, but
+this example refers to a brief Halloween period when the gap was five
+hours.)
+
+ A `TZ' value is a rule that typically names a location in the `tz'
+database (http://www.twinsun.com/tz/tz-link.htm). A recent catalog of
+location names appears in the TWiki Date and Time Gateway
+(http://twiki.org/cgi-bin/xtra/tzdate). A few non-GNU hosts require a
+colon before a location name in a `TZ' setting, e.g.,
+`TZ=":America/New_York"'.
+
+ The `tz' database includes a wide variety of locations ranging from
+`Arctic/Longyearbyen' to `Antarctica/South_Pole', but if you are at sea
+and have your own private time zone, or if you are using a non-GNU host
+that does not support the `tz' database, you may need to use a POSIX
+rule instead. Simple POSIX rules like `UTC0' specify a time zone
+without daylight saving time; other rules can specify simple daylight
+saving regimes. *Note Specifying the Time Zone with `TZ': (libc)TZ
+Variable.
+
+
+File: cvs.info, Node: Authors of get_date, Prev: Specifying time zone rules, Up: Date input formats
+
+A.6.10 Authors of `get_date'
+----------------------------
+
+`get_date' was originally implemented by Steven M. Bellovin
+(<smb@research.att.com>) while at the University of North Carolina at
+Chapel Hill. The code was later tweaked by a couple of people on
+Usenet, then completely overhauled by Rich $alz (<rsalz@bbn.com>) and
+Jim Berets (<jberets@bbn.com>) in August, 1990. Various revisions for
+the GNU system were made by David MacKenzie, Jim Meyering, Paul Eggert
+and others.
+
+ This chapter was originally produced by Franc,ois Pinard
+(<pinard@iro.umontreal.ca>) from the `getdate.y' source code, and then
+edited by K. Berry (<kb@cs.umb.edu>).
+
+
+File: cvs.info, Node: admin, Next: annotate, Prev: Date input formats, Up: CVS commands
+
+A.7 admin--Administration
+=========================
+
+ * Requires: repository, working directory.
+
+ * Changes: repository.
+
+ * Synonym: rcs
+
+ This is the CVS interface to assorted administrative facilities.
+Some of them have questionable usefulness for CVS but exist for
+historical purposes. Some of the questionable options are likely to
+disappear in the future. This command _does_ work recursively, so
+extreme care should be used.
+
+ On unix, if there is a group named `cvsadmin', only members of that
+group can run `cvs admin' commands, except for those specified using the
+`UserAdminOptions' configuration option in the `CVSROOT/config' file.
+Options specified using `UserAdminOptions' can be run by any user. See
+*Note config:: for more on `UserAdminOptions'.
+
+ The `cvsadmin' group should exist on the server, or any system
+running the non-client/server CVS. To disallow `cvs admin' for all
+users, create a group with no users in it. On NT, the `cvsadmin'
+feature does not exist and all users can run `cvs admin'.
+
+* Menu:
+
+* admin options:: admin options
+
+
+File: cvs.info, Node: admin options, Up: admin
+
+A.7.1 admin options
+-------------------
+
+Some of these options have questionable usefulness for CVS but exist
+for historical purposes. Some even make it impossible to use CVS until
+you undo the effect!
+
+`-AOLDFILE'
+ Might not work together with CVS. Append the access list of
+ OLDFILE to the access list of the RCS file.
+
+`-aLOGINS'
+ Might not work together with CVS. Append the login names
+ appearing in the comma-separated list LOGINS to the access list of
+ the RCS file.
+
+`-b[REV]'
+ Set the default branch to REV. In CVS, you normally do not
+ manipulate default branches; sticky tags (*note Sticky tags::) are
+ a better way to decide which branch you want to work on. There is
+ one reason to run `cvs admin -b': to revert to the vendor's
+ version when using vendor branches (*note Reverting local
+ changes::). There can be no space between `-b' and its argument.
+
+`-cSTRING'
+ Sets the comment leader to STRING. The comment leader is not used
+ by current versions of CVS or RCS 5.7. Therefore, you can almost
+ surely not worry about it. *Note Keyword substitution::.
+
+`-e[LOGINS]'
+ Might not work together with CVS. Erase the login names appearing
+ in the comma-separated list LOGINS from the access list of the RCS
+ file. If LOGINS is omitted, erase the entire access list. There
+ can be no space between `-e' and its argument.
+
+`-I'
+ Run interactively, even if the standard input is not a terminal.
+ This option does not work with the client/server CVS and is likely
+ to disappear in a future release of CVS.
+
+`-i'
+ Useless with CVS. This creates and initializes a new RCS file,
+ without depositing a revision. With CVS, add files with the `cvs
+ add' command (*note Adding files::).
+
+`-kSUBST'
+ Set the default keyword substitution to SUBST. *Note Keyword
+ substitution::. Giving an explicit `-k' option to `cvs update',
+ `cvs export', or `cvs checkout' overrides this default.
+
+`-l[REV]'
+ Lock the revision with number REV. If a branch is given, lock the
+ latest revision on that branch. If REV is omitted, lock the
+ latest revision on the default branch. There can be no space
+ between `-l' and its argument.
+
+ This can be used in conjunction with the `rcslock.pl' script in
+ the `contrib' directory of the CVS source distribution to provide
+ reserved checkouts (where only one user can be editing a given
+ file at a time). See the comments in that file for details (and
+ see the `README' file in that directory for disclaimers about the
+ unsupported nature of contrib). According to comments in that
+ file, locking must set to strict (which is the default).
+
+`-L'
+ Set locking to strict. Strict locking means that the owner of an
+ RCS file is not exempt from locking for checkin. For use with
+ CVS, strict locking must be set; see the discussion under the `-l'
+ option above.
+
+`-mREV:MSG'
+ Replace the log message of revision REV with MSG.
+
+`-NNAME[:[REV]]'
+ Act like `-n', except override any previous assignment of NAME.
+ For use with magic branches, see *Note Magic branch numbers::.
+
+`-nNAME[:[REV]]'
+ Associate the symbolic name NAME with the branch or revision REV.
+ It is normally better to use `cvs tag' or `cvs rtag' instead.
+ Delete the symbolic name if both `:' and REV are omitted;
+ otherwise, print an error message if NAME is already associated
+ with another number. If REV is symbolic, it is expanded before
+ association. A REV consisting of a branch number followed by a
+ `.' stands for the current latest revision in the branch. A `:'
+ with an empty REV stands for the current latest revision on the
+ default branch, normally the trunk. For example, `cvs admin
+ -nNAME:' associates NAME with the current latest revision of all
+ the RCS files; this contrasts with `cvs admin -nNAME:$' which
+ associates NAME with the revision numbers extracted from keyword
+ strings in the corresponding working files.
+
+`-oRANGE'
+ Deletes ("outdates") the revisions given by RANGE.
+
+ Note that this command can be quite dangerous unless you know
+ _exactly_ what you are doing (for example see the warnings below
+ about how the REV1:REV2 syntax is confusing).
+
+ If you are short on disc this option might help you. But think
+ twice before using it--there is no way short of restoring the
+ latest backup to undo this command! If you delete different
+ revisions than you planned, either due to carelessness or (heaven
+ forbid) a CVS bug, there is no opportunity to correct the error
+ before the revisions are deleted. It probably would be a good
+ idea to experiment on a copy of the repository first.
+
+ Specify RANGE in one of the following ways:
+
+ `REV1::REV2'
+ Collapse all revisions between rev1 and rev2, so that CVS
+ only stores the differences associated with going from rev1
+ to rev2, not intermediate steps. For example, after `-o
+ 1.3::1.5' one can retrieve revision 1.3, revision 1.5, or the
+ differences to get from 1.3 to 1.5, but not the revision 1.4,
+ or the differences between 1.3 and 1.4. Other examples: `-o
+ 1.3::1.4' and `-o 1.3::1.3' have no effect, because there are
+ no intermediate revisions to remove.
+
+ `::REV'
+ Collapse revisions between the beginning of the branch
+ containing REV and REV itself. The branchpoint and REV are
+ left intact. For example, `-o ::1.3.2.6' deletes revision
+ 1.3.2.1, revision 1.3.2.5, and everything in between, but
+ leaves 1.3 and 1.3.2.6 intact.
+
+ `REV::'
+ Collapse revisions between REV and the end of the branch
+ containing REV. Revision REV is left intact but the head
+ revision is deleted.
+
+ `REV'
+ Delete the revision REV. For example, `-o 1.3' is equivalent
+ to `-o 1.2::1.4'.
+
+ `REV1:REV2'
+ Delete the revisions from REV1 to REV2, inclusive, on the
+ same branch. One will not be able to retrieve REV1 or REV2
+ or any of the revisions in between. For example, the command
+ `cvs admin -oR_1_01:R_1_02 .' is rarely useful. It means to
+ delete revisions up to, and including, the tag R_1_02. But
+ beware! If there are files that have not changed between
+ R_1_02 and R_1_03 the file will have _the same_ numerical
+ revision number assigned to the tags R_1_02 and R_1_03. So
+ not only will it be impossible to retrieve R_1_02; R_1_03
+ will also have to be restored from the tapes! In most cases
+ you want to specify REV1::REV2 instead.
+
+ `:REV'
+ Delete revisions from the beginning of the branch containing
+ REV up to and including REV.
+
+ `REV:'
+ Delete revisions from revision REV, including REV itself, to
+ the end of the branch containing REV.
+
+ None of the revisions to be deleted may have branches or locks.
+
+ If any of the revisions to be deleted have symbolic names, and one
+ specifies one of the `::' syntaxes, then CVS will give an error
+ and not delete any revisions. If you really want to delete both
+ the symbolic names and the revisions, first delete the symbolic
+ names with `cvs tag -d', then run `cvs admin -o'. If one
+ specifies the non-`::' syntaxes, then CVS will delete the
+ revisions but leave the symbolic names pointing to nonexistent
+ revisions. This behavior is preserved for compatibility with
+ previous versions of CVS, but because it isn't very useful, in the
+ future it may change to be like the `::' case.
+
+ Due to the way CVS handles branches REV cannot be specified
+ symbolically if it is a branch. *Note Magic branch numbers::, for
+ an explanation.
+
+ Make sure that no-one has checked out a copy of the revision you
+ outdate. Strange things will happen if he starts to edit it and
+ tries to check it back in. For this reason, this option is not a
+ good way to take back a bogus commit; commit a new revision
+ undoing the bogus change instead (*note Merging two revisions::).
+
+`-q'
+ Run quietly; do not print diagnostics.
+
+`-sSTATE[:REV]'
+ Useful with CVS. Set the state attribute of the revision REV to
+ STATE. If REV is a branch number, assume the latest revision on
+ that branch. If REV is omitted, assume the latest revision on the
+ default branch. Any identifier is acceptable for STATE. A useful
+ set of states is `Exp' (for experimental), `Stab' (for stable),
+ and `Rel' (for released). By default, the state of a new revision
+ is set to `Exp' when it is created. The state is visible in the
+ output from CVS LOG (*note log::), and in the `$Log$' and
+ `$State$' keywords (*note Keyword substitution::). Note that CVS
+ uses the `dead' state for its own purposes (*note Attic::); to
+ take a file to or from the `dead' state use commands like `cvs
+ remove' and `cvs add' (*note Adding and removing::), not `cvs
+ admin -s'.
+
+`-t[FILE]'
+ Useful with CVS. Write descriptive text from the contents of the
+ named FILE into the RCS file, deleting the existing text. The
+ FILE pathname may not begin with `-'. The descriptive text can be
+ seen in the output from `cvs log' (*note log::). There can be no
+ space between `-t' and its argument.
+
+ If FILE is omitted, obtain the text from standard input,
+ terminated by end-of-file or by a line containing `.' by itself.
+ Prompt for the text if interaction is possible; see `-I'.
+
+`-t-STRING'
+ Similar to `-tFILE'. Write descriptive text from the STRING into
+ the RCS file, deleting the existing text. There can be no space
+ between `-t' and its argument.
+
+`-U'
+ Set locking to non-strict. Non-strict locking means that the
+ owner of a file need not lock a revision for checkin. For use
+ with CVS, strict locking must be set; see the discussion under the
+ `-l' option above.
+
+`-u[REV]'
+ See the option `-l' above, for a discussion of using this option
+ with CVS. Unlock the revision with number REV. If a branch is
+ given, unlock the latest revision on that branch. If REV is
+ omitted, remove the latest lock held by the caller. Normally,
+ only the locker of a revision may unlock it; somebody else
+ unlocking a revision breaks the lock. This causes the original
+ locker to be sent a `commit' notification (*note Getting
+ Notified::). There can be no space between `-u' and its argument.
+
+`-VN'
+ In previous versions of CVS, this option meant to write an RCS
+ file which would be acceptable to RCS version N, but it is now
+ obsolete and specifying it will produce an error.
+
+`-xSUFFIXES'
+ In previous versions of CVS, this was documented as a way of
+ specifying the names of the RCS files. However, CVS has always
+ required that the RCS files used by CVS end in `,v', so this
+ option has never done anything useful.
+
+
+
+File: cvs.info, Node: annotate, Next: checkout, Prev: admin, Up: CVS commands
+
+A.8 annotate--What revision modified each line of a file?
+=========================================================
+
+ * Synopsis: annotate [options] files...
+
+ * Requires: repository.
+
+ * Changes: nothing.
+
+ For each file in FILES, print the head revision of the trunk,
+together with information on the last modification for each line.
+
+* Menu:
+
+* annotate options:: annotate options
+* annotate example:: annotate example
+
+
+File: cvs.info, Node: annotate options, Next: annotate example, Up: annotate
+
+A.8.1 annotate options
+----------------------
+
+These standard options are supported by `annotate' (*note Common
+options::, for a complete description of them):
+
+`-l'
+ Local directory only, no recursion.
+
+`-R'
+ Process directories recursively.
+
+`-f'
+ Use head revision if tag/date not found.
+
+`-F'
+ Annotate binary files.
+
+`-r TAG[:DATE]'
+ Annotate file as of specified revision/tag or, when DATE is
+ specified and TAG is a branch tag, the version from the branch TAG
+ as it existed on DATE. See *Note Common options::.
+
+`-D DATE'
+ Annotate file as of specified date.
+
+
+File: cvs.info, Node: annotate example, Prev: annotate options, Up: annotate
+
+A.8.2 annotate example
+----------------------
+
+For example:
+
+ $ cvs annotate ssfile
+ Annotations for ssfile
+ ***************
+ 1.1 (mary 27-Mar-96): ssfile line 1
+ 1.2 (joe 28-Mar-96): ssfile line 2
+
+ The file `ssfile' currently contains two lines. The `ssfile line 1'
+line was checked in by `mary' on March 27. Then, on March 28, `joe'
+added a line `ssfile line 2', without modifying the `ssfile line 1'
+line. This report doesn't tell you anything about lines which have
+been deleted or replaced; you need to use `cvs diff' for that (*note
+diff::).
+
+ The options to `cvs annotate' are listed in *Note Invoking CVS::,
+and can be used to select the files and revisions to annotate. The
+options are described in more detail there and in *Note Common
+options::.
+
+
+File: cvs.info, Node: checkout, Next: commit, Prev: annotate, Up: CVS commands
+
+A.9 checkout--Check out sources for editing
+===========================================
+
+ * Synopsis: checkout [options] modules...
+
+ * Requires: repository.
+
+ * Changes: working directory.
+
+ * Synonyms: co, get
+
+ Create or update a working directory containing copies of the source
+files specified by MODULES. You must execute `checkout' before using
+most of the other CVS commands, since most of them operate on your
+working directory.
+
+ The MODULES are either symbolic names for some collection of source
+directories and files, or paths to directories or files in the
+repository. The symbolic names are defined in the `modules' file.
+*Note modules::.
+
+ Depending on the modules you specify, `checkout' may recursively
+create directories and populate them with the appropriate source files.
+You can then edit these source files at any time (regardless of
+whether other software developers are editing their own copies of the
+sources); update them to include new changes applied by others to the
+source repository; or commit your work as a permanent change to the
+source repository.
+
+ Note that `checkout' is used to create directories. The top-level
+directory created is always added to the directory where `checkout' is
+invoked, and usually has the same name as the specified module. In the
+case of a module alias, the created sub-directory may have a different
+name, but you can be sure that it will be a sub-directory, and that
+`checkout' will show the relative path leading to each file as it is
+extracted into your private work area (unless you specify the `-Q'
+global option).
+
+ The files created by `checkout' are created read-write, unless the
+`-r' option to CVS (*note Global options::) is specified, the `CVSREAD'
+environment variable is specified (*note Environment variables::), or a
+watch is in effect for that file (*note Watches::).
+
+ Note that running `checkout' on a directory that was already built
+by a prior `checkout' is also permitted. This is similar to specifying
+the `-d' option to the `update' command in the sense that new
+directories that have been created in the repository will appear in
+your work area. However, `checkout' takes a module name whereas
+`update' takes a directory name. Also to use `checkout' this way it
+must be run from the top level directory (where you originally ran
+`checkout' from), so before you run `checkout' to update an existing
+directory, don't forget to change your directory to the top level
+directory.
+
+ For the output produced by the `checkout' command see *Note update
+output::.
+
+* Menu:
+
+* checkout options:: checkout options
+* checkout examples:: checkout examples
+
+
+File: cvs.info, Node: checkout options, Next: checkout examples, Up: checkout
+
+A.9.1 checkout options
+----------------------
+
+These standard options are supported by `checkout' (*note Common
+options::, for a complete description of them):
+
+`-D DATE'
+ Use the most recent revision no later than DATE. This option is
+ sticky, and implies `-P'. See *Note Sticky tags::, for more
+ information on sticky tags/dates.
+
+`-f'
+ Only useful with the `-D' or `-r' flags. If no matching revision
+ is found, retrieve the most recent revision (instead of ignoring
+ the file).
+
+`-k KFLAG'
+ Process keywords according to KFLAG. See *Note Keyword
+ substitution::. This option is sticky; future updates of this
+ file in this working directory will use the same KFLAG. The
+ `status' command can be viewed to see the sticky options. See
+ *Note Invoking CVS::, for more information on the `status' command.
+
+`-l'
+ Local; run only in current working directory.
+
+`-n'
+ Do not run any checkout program (as specified with the `-o' option
+ in the modules file; *note modules::).
+
+`-P'
+ Prune empty directories. See *Note Moving directories::.
+
+`-p'
+ Pipe files to the standard output.
+
+`-R'
+ Checkout directories recursively. This option is on by default.
+
+`-r TAG[:DATE]'
+ Checkout the revision specified by TAG or, when DATE is specified
+ and TAG is a branch tag, the version from the branch TAG as it
+ existed on DATE. This option is sticky, and implies `-P'. See
+ *Note Sticky tags::, for more information on sticky tags/dates.
+ Also, see *Note Common options::.
+
+ In addition to those, you can use these special command options with
+`checkout':
+
+`-A'
+ Reset any sticky tags, dates, or `-k' options. See *Note Sticky
+ tags::, for more information on sticky tags/dates.
+
+`-c'
+ Copy the module file, sorted, to the standard output, instead of
+ creating or modifying any files or directories in your working
+ directory.
+
+`-d DIR'
+ Create a directory called DIR for the working files, instead of
+ using the module name. In general, using this flag is equivalent
+ to using `mkdir DIR; cd DIR' followed by the checkout command
+ without the `-d' flag.
+
+ There is an important exception, however. It is very convenient
+ when checking out a single item to have the output appear in a
+ directory that doesn't contain empty intermediate directories. In
+ this case _only_, CVS tries to "shorten" pathnames to avoid those
+ empty directories.
+
+ For example, given a module `foo' that contains the file `bar.c',
+ the command `cvs co -d dir foo' will create directory `dir' and
+ place `bar.c' inside. Similarly, given a module `bar' which has
+ subdirectory `baz' wherein there is a file `quux.c', the command
+ `cvs co -d dir bar/baz' will create directory `dir' and place
+ `quux.c' inside.
+
+ Using the `-N' flag will defeat this behavior. Given the same
+ module definitions above, `cvs co -N -d dir foo' will create
+ directories `dir/foo' and place `bar.c' inside, while `cvs co -N -d
+ dir bar/baz' will create directories `dir/bar/baz' and place
+ `quux.c' inside.
+
+`-j TAG'
+ With two `-j' options, merge changes from the revision specified
+ with the first `-j' option to the revision specified with the
+ second `j' option, into the working directory.
+
+ With one `-j' option, merge changes from the ancestor revision to
+ the revision specified with the `-j' option, into the working
+ directory. The ancestor revision is the common ancestor of the
+ revision which the working directory is based on, and the revision
+ specified in the `-j' option.
+
+ In addition, each -j option can contain an optional date
+ specification which, when used with branches, can limit the chosen
+ revision to one within a specific date. An optional date is
+ specified by adding a colon (:) to the tag:
+ `-jSYMBOLIC_TAG:DATE_SPECIFIER'.
+
+ *Note Branching and merging::.
+
+`-N'
+ Only useful together with `-d DIR'. With this option, CVS will
+ not "shorten" module paths in your working directory when you
+ check out a single module. See the `-d' flag for examples and a
+ discussion.
+
+`-s'
+ Like `-c', but include the status of all modules, and sort it by
+ the status string. *Note modules::, for info about the `-s'
+ option that is used inside the modules file to set the module
+ status.
+
+
+File: cvs.info, Node: checkout examples, Prev: checkout options, Up: checkout
+
+A.9.2 checkout examples
+-----------------------
+
+Get a copy of the module `tc':
+
+ $ cvs checkout tc
+
+ Get a copy of the module `tc' as it looked one day ago:
+
+ $ cvs checkout -D yesterday tc
+
+
+File: cvs.info, Node: commit, Next: diff, Prev: checkout, Up: CVS commands
+
+A.10 commit--Check files into the repository
+============================================
+
+ * Synopsis: commit [-lnRf] [-m 'log_message' | -F file] [-r
+ revision] [files...]
+
+ * Requires: working directory, repository.
+
+ * Changes: repository.
+
+ * Synonym: ci
+
+ Use `commit' when you want to incorporate changes from your working
+source files into the source repository.
+
+ If you don't specify particular files to commit, all of the files in
+your working current directory are examined. `commit' is careful to
+change in the repository only those files that you have really changed.
+By default (or if you explicitly specify the `-R' option), files in
+subdirectories are also examined and committed if they have changed;
+you can use the `-l' option to limit `commit' to the current directory
+only.
+
+ `commit' verifies that the selected files are up to date with the
+current revisions in the source repository; it will notify you, and
+exit without committing, if any of the specified files must be made
+current first with `update' (*note update::). `commit' does not call
+the `update' command for you, but rather leaves that for you to do when
+the time is right.
+
+ When all is well, an editor is invoked to allow you to enter a log
+message that will be written to one or more logging programs (*note
+modules::, and *note loginfo::) and placed in the RCS file inside the
+repository. This log message can be retrieved with the `log' command;
+see *Note log::. You can specify the log message on the command line
+with the `-m MESSAGE' option, and thus avoid the editor invocation, or
+use the `-F FILE' option to specify that the argument file contains the
+log message.
+
+ At `commit', a unique commitid is placed in the RCS file inside the
+repository. All files committed at once get the same commitid. The
+commitid can be retrieved with the `log' and `status' command; see
+*Note log::, *Note File status::.
+
+* Menu:
+
+* commit options:: commit options
+* commit examples:: commit examples
+
diff --git a/doc/cvs.info-2 b/doc/cvs.info-2
new file mode 100644
index 0000000..f95903c
--- /dev/null
+++ b/doc/cvs.info-2
@@ -0,0 +1,6139 @@
+This is cvs.info, produced by makeinfo version 4.8 from cvs.texinfo.
+
+INFO-DIR-SECTION GNU Packages
+START-INFO-DIR-ENTRY
+* CVS: (cvs). Concurrent Versions System
+END-INFO-DIR-ENTRY
+INFO-DIR-SECTION Individual utilities
+START-INFO-DIR-ENTRY
+* cvs: (cvs)CVS commands. Concurrent Versions System
+END-INFO-DIR-ENTRY
+
+
+File: cvs.info, Node: commit options, Next: commit examples, Up: commit
+
+A.10.1 commit options
+---------------------
+
+These standard options are supported by `commit' (*note Common
+options::, for a complete description of them):
+
+`-l'
+ Local; run only in current working directory.
+
+`-R'
+ Commit directories recursively. This is on by default.
+
+`-r REVISION'
+ Commit to REVISION. REVISION must be either a branch, or a
+ revision on the main trunk that is higher than any existing
+ revision number (*note Assigning revisions::). You cannot commit
+ to a specific revision on a branch.
+
+ `commit' also supports these options:
+
+`-c'
+ Refuse to commit files unless the user has registered a valid edit
+ on the file via `cvs edit'. This is most useful when `commit -c'
+ and `edit -c' have been placed in all `.cvsrc' files. A commit
+ can be forced anyways by either regestering an edit retroactively
+ via `cvs edit' (no changes to the file will be lost) or using the
+ `-f' option to commit. Support for `commit -c' requires both
+ client and a server versions 1.12.10 or greater.
+
+`-F FILE'
+ Read the log message from FILE, instead of invoking an editor.
+
+`-f'
+ Note that this is not the standard behavior of the `-f' option as
+ defined in *Note Common options::.
+
+ Force CVS to commit a new revision even if you haven't made any
+ changes to the file. As of CVS version 1.12.10, it also causes
+ the `-c' option to be ignored. If the current revision of FILE is
+ 1.7, then the following two commands are equivalent:
+
+ $ cvs commit -f FILE
+ $ cvs commit -r 1.8 FILE
+
+ The `-f' option disables recursion (i.e., it implies `-l'). To
+ force CVS to commit a new revision for all files in all
+ subdirectories, you must use `-f -R'.
+
+`-m MESSAGE'
+ Use MESSAGE as the log message, instead of invoking an editor.
+
+
+File: cvs.info, Node: commit examples, Prev: commit options, Up: commit
+
+A.10.2 commit examples
+----------------------
+
+A.10.2.1 Committing to a branch
+...............................
+
+You can commit to a branch revision (one that has an even number of
+dots) with the `-r' option. To create a branch revision, use the `-b'
+option of the `rtag' or `tag' commands (*note Branching and merging::).
+Then, either `checkout' or `update' can be used to base your sources
+on the newly created branch. From that point on, all `commit' changes
+made within these working sources will be automatically added to a
+branch revision, thereby not disturbing main-line development in any
+way. For example, if you had to create a patch to the 1.2 version of
+the product, even though the 2.0 version is already under development,
+you might do:
+
+ $ cvs rtag -b -r FCS1_2 FCS1_2_Patch product_module
+ $ cvs checkout -r FCS1_2_Patch product_module
+ $ cd product_module
+ [[ hack away ]]
+ $ cvs commit
+
+This works automatically since the `-r' option is sticky.
+
+A.10.2.2 Creating the branch after editing
+..........................................
+
+Say you have been working on some extremely experimental software,
+based on whatever revision you happened to checkout last week. If
+others in your group would like to work on this software with you, but
+without disturbing main-line development, you could commit your change
+to a new branch. Others can then checkout your experimental stuff and
+utilize the full benefit of CVS conflict resolution. The scenario might
+look like:
+
+ [[ hacked sources are present ]]
+ $ cvs tag -b EXPR1
+ $ cvs update -r EXPR1
+ $ cvs commit
+
+ The `update' command will make the `-r EXPR1' option sticky on all
+files. Note that your changes to the files will never be removed by the
+`update' command. The `commit' will automatically commit to the
+correct branch, because the `-r' is sticky. You could also do like
+this:
+
+ [[ hacked sources are present ]]
+ $ cvs tag -b EXPR1
+ $ cvs commit -r EXPR1
+
+but then, only those files that were changed by you will have the `-r
+EXPR1' sticky flag. If you hack away, and commit without specifying
+the `-r EXPR1' flag, some files may accidentally end up on the main
+trunk.
+
+ To work with you on the experimental change, others would simply do
+
+ $ cvs checkout -r EXPR1 whatever_module
+
+
+File: cvs.info, Node: diff, Next: export, Prev: commit, Up: CVS commands
+
+A.11 diff--Show differences between revisions
+=============================================
+
+ * Synopsis: diff [-lR] [-k kflag] [format_options] [(-r rev1[:date1]
+ | -D date1) [-r rev2[:date2] | -D date2]] [files...]
+
+ * Requires: working directory, repository.
+
+ * Changes: nothing.
+
+ The `diff' command is used to compare different revisions of files.
+The default action is to compare your working files with the revisions
+they were based on, and report any differences that are found.
+
+ If any file names are given, only those files are compared. If any
+directories are given, all files under them will be compared.
+
+ The exit status for diff is different than for other CVS commands;
+for details *Note Exit status::.
+
+* Menu:
+
+* diff options:: diff options
+* diff examples:: diff examples
+
+
+File: cvs.info, Node: diff options, Next: diff examples, Up: diff
+
+A.11.1 diff options
+-------------------
+
+These standard options are supported by `diff' (*note Common options::,
+for a complete description of them):
+
+`-D DATE'
+ Use the most recent revision no later than DATE. See `-r' for how
+ this affects the comparison.
+
+`-k KFLAG'
+ Process keywords according to KFLAG. See *Note Keyword
+ substitution::.
+
+`-l'
+ Local; run only in current working directory.
+
+`-R'
+ Examine directories recursively. This option is on by default.
+
+`-r TAG[:DATE]'
+ Compare with revision specified by TAG or, when DATE is specified
+ and TAG is a branch tag, the version from the branch TAG as it
+ existed on DATE. Zero, one or two `-r' options can be present.
+ With no `-r' option, the working file will be compared with the
+ revision it was based on. With one `-r', that revision will be
+ compared to your current working file. With two `-r' options
+ those two revisions will be compared (and your working file will
+ not affect the outcome in any way).
+
+ One or both `-r' options can be replaced by a `-D DATE' option,
+ described above.
+
+ The following options specify the format of the output. They have
+the same meaning as in GNU diff. Most options have two equivalent
+names, one of which is a single letter preceded by `-', and the other
+of which is a long name preceded by `--'.
+
+`-LINES'
+ Show LINES (an integer) lines of context. This option does not
+ specify an output format by itself; it has no effect unless it is
+ combined with `-c' or `-u'. This option is obsolete. For proper
+ operation, `patch' typically needs at least two lines of context.
+
+`-a'
+ Treat all files as text and compare them line-by-line, even if they
+ do not seem to be text.
+
+`-b'
+ Ignore trailing white space and consider all other sequences of
+ one or more white space characters to be equivalent.
+
+`-B'
+ Ignore changes that just insert or delete blank lines.
+
+`--binary'
+ Read and write data in binary mode.
+
+`--brief'
+ Report only whether the files differ, not the details of the
+ differences.
+
+`-c'
+ Use the context output format.
+
+`-C LINES'
+`--context[=LINES]'
+ Use the context output format, showing LINES (an integer) lines of
+ context, or three if LINES is not given. For proper operation,
+ `patch' typically needs at least two lines of context.
+
+`--changed-group-format=FORMAT'
+ Use FORMAT to output a line group containing differing lines from
+ both files in if-then-else format. *Note Line group formats::.
+
+`-d'
+ Change the algorithm to perhaps find a smaller set of changes.
+ This makes `diff' slower (sometimes much slower).
+
+`-e'
+`--ed'
+ Make output that is a valid `ed' script.
+
+`--expand-tabs'
+ Expand tabs to spaces in the output, to preserve the alignment of
+ tabs in the input files.
+
+`-f'
+ Make output that looks vaguely like an `ed' script but has changes
+ in the order they appear in the file.
+
+`-F REGEXP'
+ In context and unified format, for each hunk of differences, show
+ some of the last preceding line that matches REGEXP.
+
+`--forward-ed'
+ Make output that looks vaguely like an `ed' script but has changes
+ in the order they appear in the file.
+
+`-H'
+ Use heuristics to speed handling of large files that have numerous
+ scattered small changes.
+
+`--horizon-lines=LINES'
+ Do not discard the last LINES lines of the common prefix and the
+ first LINES lines of the common suffix.
+
+`-i'
+ Ignore changes in case; consider upper- and lower-case letters
+ equivalent.
+
+`-I REGEXP'
+ Ignore changes that just insert or delete lines that match REGEXP.
+
+`--ifdef=NAME'
+ Make merged if-then-else output using NAME.
+
+`--ignore-all-space'
+ Ignore white space when comparing lines.
+
+`--ignore-blank-lines'
+ Ignore changes that just insert or delete blank lines.
+
+`--ignore-case'
+ Ignore changes in case; consider upper- and lower-case to be the
+ same.
+
+`--ignore-matching-lines=REGEXP'
+ Ignore changes that just insert or delete lines that match REGEXP.
+
+`--ignore-space-change'
+ Ignore trailing white space and consider all other sequences of
+ one or more white space characters to be equivalent.
+
+`--initial-tab'
+ Output a tab rather than a space before the text of a line in
+ normal or context format. This causes the alignment of tabs in
+ the line to look normal.
+
+`-L LABEL'
+ Use LABEL instead of the file name in the context format and
+ unified format headers.
+
+`--label=LABEL'
+ Use LABEL instead of the file name in the context format and
+ unified format headers.
+
+`--left-column'
+ Print only the left column of two common lines in side by side
+ format.
+
+`--line-format=FORMAT'
+ Use FORMAT to output all input lines in if-then-else format.
+ *Note Line formats::.
+
+`--minimal'
+ Change the algorithm to perhaps find a smaller set of changes.
+ This makes `diff' slower (sometimes much slower).
+
+`-n'
+ Output RCS-format diffs; like `-f' except that each command
+ specifies the number of lines affected.
+
+`-N'
+`--new-file'
+ In directory comparison, if a file is found in only one directory,
+ treat it as present but empty in the other directory.
+
+`--new-group-format=FORMAT'
+ Use FORMAT to output a group of lines taken from just the second
+ file in if-then-else format. *Note Line group formats::.
+
+`--new-line-format=FORMAT'
+ Use FORMAT to output a line taken from just the second file in
+ if-then-else format. *Note Line formats::.
+
+`--old-group-format=FORMAT'
+ Use FORMAT to output a group of lines taken from just the first
+ file in if-then-else format. *Note Line group formats::.
+
+`--old-line-format=FORMAT'
+ Use FORMAT to output a line taken from just the first file in
+ if-then-else format. *Note Line formats::.
+
+`-p'
+ Show which C function each change is in.
+
+`--rcs'
+ Output RCS-format diffs; like `-f' except that each command
+ specifies the number of lines affected.
+
+`--report-identical-files'
+`-s'
+ Report when two files are the same.
+
+`--show-c-function'
+ Show which C function each change is in.
+
+`--show-function-line=REGEXP'
+ In context and unified format, for each hunk of differences, show
+ some of the last preceding line that matches REGEXP.
+
+`--side-by-side'
+ Use the side by side output format.
+
+`--speed-large-files'
+ Use heuristics to speed handling of large files that have numerous
+ scattered small changes.
+
+`--suppress-common-lines'
+ Do not print common lines in side by side format.
+
+`-t'
+ Expand tabs to spaces in the output, to preserve the alignment of
+ tabs in the input files.
+
+`-T'
+ Output a tab rather than a space before the text of a line in
+ normal or context format. This causes the alignment of tabs in
+ the line to look normal.
+
+`--text'
+ Treat all files as text and compare them line-by-line, even if they
+ do not appear to be text.
+
+`-u'
+ Use the unified output format.
+
+`--unchanged-group-format=FORMAT'
+ Use FORMAT to output a group of common lines taken from both files
+ in if-then-else format. *Note Line group formats::.
+
+`--unchanged-line-format=FORMAT'
+ Use FORMAT to output a line common to both files in if-then-else
+ format. *Note Line formats::.
+
+`-U LINES'
+`--unified[=LINES]'
+ Use the unified output format, showing LINES (an integer) lines of
+ context, or three if LINES is not given. For proper operation,
+ `patch' typically needs at least two lines of context.
+
+`-w'
+ Ignore white space when comparing lines.
+
+`-W COLUMNS'
+`--width=COLUMNS'
+ Use an output width of COLUMNS in side by side format.
+
+`-y'
+ Use the side by side output format.
+
+* Menu:
+
+* Line group formats:: Line group formats
+* Line formats:: Line formats
+
+
+File: cvs.info, Node: Line group formats, Next: Line formats, Up: diff options
+
+A.11.1.1 Line group formats
+...........................
+
+Line group formats let you specify formats suitable for many
+applications that allow if-then-else input, including programming
+languages and text formatting languages. A line group format specifies
+the output format for a contiguous group of similar lines.
+
+ For example, the following command compares the TeX file `myfile'
+with the original version from the repository, and outputs a merged
+file in which old regions are surrounded by `\begin{em}'-`\end{em}'
+lines, and new regions are surrounded by `\begin{bf}'-`\end{bf}' lines.
+
+ cvs diff \
+ --old-group-format='\begin{em}
+ %<\end{em}
+ ' \
+ --new-group-format='\begin{bf}
+ %>\end{bf}
+ ' \
+ myfile
+
+ The following command is equivalent to the above example, but it is a
+little more verbose, because it spells out the default line group
+formats.
+
+ cvs diff \
+ --old-group-format='\begin{em}
+ %<\end{em}
+ ' \
+ --new-group-format='\begin{bf}
+ %>\end{bf}
+ ' \
+ --unchanged-group-format='%=' \
+ --changed-group-format='\begin{em}
+ %<\end{em}
+ \begin{bf}
+ %>\end{bf}
+ ' \
+ myfile
+
+ Here is a more advanced example, which outputs a diff listing with
+headers containing line numbers in a "plain English" style.
+
+ cvs diff \
+ --unchanged-group-format='' \
+ --old-group-format='-------- %dn line%(n=1?:s) deleted at %df:
+ %<' \
+ --new-group-format='-------- %dN line%(N=1?:s) added after %de:
+ %>' \
+ --changed-group-format='-------- %dn line%(n=1?:s) changed at %df:
+ %<-------- to:
+ %>' \
+ myfile
+
+ To specify a line group format, use one of the options listed below.
+You can specify up to four line group formats, one for each kind of
+line group. You should quote FORMAT, because it typically contains
+shell metacharacters.
+
+`--old-group-format=FORMAT'
+ These line groups are hunks containing only lines from the first
+ file. The default old group format is the same as the changed
+ group format if it is specified; otherwise it is a format that
+ outputs the line group as-is.
+
+`--new-group-format=FORMAT'
+ These line groups are hunks containing only lines from the second
+ file. The default new group format is same as the changed group
+ format if it is specified; otherwise it is a format that outputs
+ the line group as-is.
+
+`--changed-group-format=FORMAT'
+ These line groups are hunks containing lines from both files. The
+ default changed group format is the concatenation of the old and
+ new group formats.
+
+`--unchanged-group-format=FORMAT'
+ These line groups contain lines common to both files. The default
+ unchanged group format is a format that outputs the line group
+ as-is.
+
+ In a line group format, ordinary characters represent themselves;
+conversion specifications start with `%' and have one of the following
+forms.
+
+`%<'
+ stands for the lines from the first file, including the trailing
+ newline. Each line is formatted according to the old line format
+ (*note Line formats::).
+
+`%>'
+ stands for the lines from the second file, including the trailing
+ newline. Each line is formatted according to the new line format.
+
+`%='
+ stands for the lines common to both files, including the trailing
+ newline. Each line is formatted according to the unchanged line
+ format.
+
+`%%'
+ stands for `%'.
+
+`%c'C''
+ where C is a single character, stands for C. C may not be a
+ backslash or an apostrophe. For example, `%c':'' stands for a
+ colon, even inside the then-part of an if-then-else format, which
+ a colon would normally terminate.
+
+`%c'\O''
+ where O is a string of 1, 2, or 3 octal digits, stands for the
+ character with octal code O. For example, `%c'\0'' stands for a
+ null character.
+
+`FN'
+ where F is a `printf' conversion specification and N is one of the
+ following letters, stands for N's value formatted with F.
+
+ `e'
+ The line number of the line just before the group in the old
+ file.
+
+ `f'
+ The line number of the first line in the group in the old
+ file; equals E + 1.
+
+ `l'
+ The line number of the last line in the group in the old file.
+
+ `m'
+ The line number of the line just after the group in the old
+ file; equals L + 1.
+
+ `n'
+ The number of lines in the group in the old file; equals L -
+ F + 1.
+
+ `E, F, L, M, N'
+ Likewise, for lines in the new file.
+
+
+ The `printf' conversion specification can be `%d', `%o', `%x', or
+ `%X', specifying decimal, octal, lower case hexadecimal, or upper
+ case hexadecimal output respectively. After the `%' the following
+ options can appear in sequence: a `-' specifying
+ left-justification; an integer specifying the minimum field width;
+ and a period followed by an optional integer specifying the
+ minimum number of digits. For example, `%5dN' prints the number
+ of new lines in the group in a field of width 5 characters, using
+ the `printf' format `"%5d"'.
+
+`(A=B?T:E)'
+ If A equals B then T else E. A and B are each either a decimal
+ constant or a single letter interpreted as above. This format
+ spec is equivalent to T if A's value equals B's; otherwise it is
+ equivalent to E.
+
+ For example, `%(N=0?no:%dN) line%(N=1?:s)' is equivalent to `no
+ lines' if N (the number of lines in the group in the new file) is
+ 0, to `1 line' if N is 1, and to `%dN lines' otherwise.
+
+
+File: cvs.info, Node: Line formats, Prev: Line group formats, Up: diff options
+
+A.11.1.2 Line formats
+.....................
+
+Line formats control how each line taken from an input file is output
+as part of a line group in if-then-else format.
+
+ For example, the following command outputs text with a one-column
+change indicator to the left of the text. The first column of output
+is `-' for deleted lines, `|' for added lines, and a space for
+unchanged lines. The formats contain newline characters where newlines
+are desired on output.
+
+ cvs diff \
+ --old-line-format='-%l
+ ' \
+ --new-line-format='|%l
+ ' \
+ --unchanged-line-format=' %l
+ ' \
+ myfile
+
+ To specify a line format, use one of the following options. You
+should quote FORMAT, since it often contains shell metacharacters.
+
+`--old-line-format=FORMAT'
+ formats lines just from the first file.
+
+`--new-line-format=FORMAT'
+ formats lines just from the second file.
+
+`--unchanged-line-format=FORMAT'
+ formats lines common to both files.
+
+`--line-format=FORMAT'
+ formats all lines; in effect, it sets all three above options
+ simultaneously.
+
+ In a line format, ordinary characters represent themselves;
+conversion specifications start with `%' and have one of the following
+forms.
+
+`%l'
+ stands for the contents of the line, not counting its trailing
+ newline (if any). This format ignores whether the line is
+ incomplete.
+
+`%L'
+ stands for the contents of the line, including its trailing newline
+ (if any). If a line is incomplete, this format preserves its
+ incompleteness.
+
+`%%'
+ stands for `%'.
+
+`%c'C''
+ where C is a single character, stands for C. C may not be a
+ backslash or an apostrophe. For example, `%c':'' stands for a
+ colon.
+
+`%c'\O''
+ where O is a string of 1, 2, or 3 octal digits, stands for the
+ character with octal code O. For example, `%c'\0'' stands for a
+ null character.
+
+`Fn'
+ where F is a `printf' conversion specification, stands for the
+ line number formatted with F. For example, `%.5dn' prints the
+ line number using the `printf' format `"%.5d"'. *Note Line group
+ formats::, for more about printf conversion specifications.
+
+
+ The default line format is `%l' followed by a newline character.
+
+ If the input contains tab characters and it is important that they
+line up on output, you should ensure that `%l' or `%L' in a line format
+is just after a tab stop (e.g. by preceding `%l' or `%L' with a tab
+character), or you should use the `-t' or `--expand-tabs' option.
+
+ Taken together, the line and line group formats let you specify many
+different formats. For example, the following command uses a format
+similar to `diff''s normal format. You can tailor this command to get
+fine control over `diff''s output.
+
+ cvs diff \
+ --old-line-format='< %l
+ ' \
+ --new-line-format='> %l
+ ' \
+ --old-group-format='%df%(f=l?:,%dl)d%dE
+ %<' \
+ --new-group-format='%dea%dF%(F=L?:,%dL)
+ %>' \
+ --changed-group-format='%df%(f=l?:,%dl)c%dF%(F=L?:,%dL)
+ %<---
+ %>' \
+ --unchanged-group-format='' \
+ myfile
+
+
+File: cvs.info, Node: diff examples, Prev: diff options, Up: diff
+
+A.11.2 diff examples
+--------------------
+
+The following line produces a Unidiff (`-u' flag) between revision 1.14
+and 1.19 of `backend.c'. Due to the `-kk' flag no keywords are
+substituted, so differences that only depend on keyword substitution
+are ignored.
+
+ $ cvs diff -kk -u -r 1.14 -r 1.19 backend.c
+
+ Suppose the experimental branch EXPR1 was based on a set of files
+tagged RELEASE_1_0. To see what has happened on that branch, the
+following can be used:
+
+ $ cvs diff -r RELEASE_1_0 -r EXPR1
+
+ A command like this can be used to produce a context diff between
+two releases:
+
+ $ cvs diff -c -r RELEASE_1_0 -r RELEASE_1_1 > diffs
+
+ If you are maintaining ChangeLogs, a command like the following just
+before you commit your changes may help you write the ChangeLog entry.
+All local modifications that have not yet been committed will be
+printed.
+
+ $ cvs diff -u | less
+
+
+File: cvs.info, Node: export, Next: history, Prev: diff, Up: CVS commands
+
+A.12 export--Export sources from CVS, similar to checkout
+=========================================================
+
+ * Synopsis: export [-flNnR] (-r rev[:date] | -D date) [-k subst] [-d
+ dir] module...
+
+ * Requires: repository.
+
+ * Changes: current directory.
+
+ This command is a variant of `checkout'; use it when you want a copy
+of the source for module without the CVS administrative directories.
+For example, you might use `export' to prepare source for shipment
+off-site. This command requires that you specify a date or tag (with
+`-D' or `-r'), so that you can count on reproducing the source you ship
+to others (and thus it always prunes empty directories).
+
+ One often would like to use `-kv' with `cvs export'. This causes
+any keywords to be expanded such that an import done at some other site
+will not lose the keyword revision information. But be aware that
+doesn't handle an export containing binary files correctly. Also be
+aware that after having used `-kv', one can no longer use the `ident'
+command (which is part of the RCS suite--see ident(1)) which looks for
+keyword strings. If you want to be able to use `ident' you must not
+use `-kv'.
+
+* Menu:
+
+* export options:: export options
+
+
+File: cvs.info, Node: export options, Up: export
+
+A.12.1 export options
+---------------------
+
+These standard options are supported by `export' (*note Common
+options::, for a complete description of them):
+
+`-D DATE'
+ Use the most recent revision no later than DATE.
+
+`-f'
+ If no matching revision is found, retrieve the most recent
+ revision (instead of ignoring the file).
+
+`-l'
+ Local; run only in current working directory.
+
+`-n'
+ Do not run any checkout program.
+
+`-R'
+ Export directories recursively. This is on by default.
+
+`-r TAG[:DATE]'
+ Export the revision specified by TAG or, when DATE is specified
+ and TAG is a branch tag, the version from the branch TAG as it
+ existed on DATE. See *Note Common options::.
+
+ In addition, these options (that are common to `checkout' and
+`export') are also supported:
+
+`-d DIR'
+ Create a directory called DIR for the working files, instead of
+ using the module name. *Note checkout options::, for complete
+ details on how CVS handles this flag.
+
+`-k SUBST'
+ Set keyword expansion mode (*note Substitution modes::).
+
+`-N'
+ Only useful together with `-d DIR'. *Note checkout options::, for
+ complete details on how CVS handles this flag.
+
+
+File: cvs.info, Node: history, Next: import, Prev: export, Up: CVS commands
+
+A.13 history--Show status of files and users
+============================================
+
+ * Synopsis: history [-report] [-flags] [-options args] [files...]
+
+ * Requires: the file `$CVSROOT/CVSROOT/history'
+
+ * Changes: nothing.
+
+ CVS can keep a history log that tracks each use of most CVS
+commands. You can use `history' to display this information in various
+formats.
+
+ To enable logging, the `LogHistory' config option must be set to
+some value other than the empty string and the history file specified by
+the `HistoryLogPath' option must be writable by all users who may run
+the CVS executable (*note config::).
+
+ To enable the `history' command, logging must be enabled as above and
+the `HistorySearchPath' config option (*note config::) must be set to
+specify some number of the history logs created thereby and these files
+must be readable by each user who might run the `history' command.
+
+ Creating a repository via the `cvs init' command will enable logging
+of all possible events to a single history log file
+(`$CVSROOT/CVSROOT/history') with read and write permissions for all
+users (*note Creating a repository::).
+
+ *Note_ `history' uses `-f', `-l', `-n', and `-p' in ways that
+conflict with the normal use inside CVS (*note Common options::).*
+
+* Menu:
+
+* history options:: history options
+
+
+File: cvs.info, Node: history options, Up: history
+
+A.13.1 history options
+----------------------
+
+Several options (shown above as `-report') control what kind of
+report is generated:
+
+`-c'
+ Report on each time commit was used (i.e., each time the
+ repository was modified).
+
+`-e'
+ Everything (all record types). Equivalent to specifying `-x' with
+ all record types. Of course, `-e' will also include record types
+ which are added in a future version of CVS; if you are writing a
+ script which can only handle certain record types, you'll want to
+ specify `-x'.
+
+`-m MODULE'
+ Report on a particular module. (You can meaningfully use `-m'
+ more than once on the command line.)
+
+`-o'
+ Report on checked-out modules. This is the default report type.
+
+`-T'
+ Report on all tags.
+
+`-x TYPE'
+ Extract a particular set of record types TYPE from the CVS
+ history. The types are indicated by single letters, which you may
+ specify in combination.
+
+ Certain commands have a single record type:
+
+ `F'
+ release
+
+ `O'
+ checkout
+
+ `E'
+ export
+
+ `T'
+ rtag
+
+ One of five record types may result from an update:
+
+ `C'
+ A merge was necessary but collisions were detected (requiring
+ manual merging).
+
+ `G'
+ A merge was necessary and it succeeded.
+
+ `U'
+ A working file was copied from the repository.
+
+ `P'
+ A working file was patched to match the repository.
+
+ `W'
+ The working copy of a file was deleted during update (because
+ it was gone from the repository).
+
+ One of three record types results from commit:
+
+ `A'
+ A file was added for the first time.
+
+ `M'
+ A file was modified.
+
+ `R'
+ A file was removed.
+
+ The options shown as `-flags' constrain or expand the report without
+requiring option arguments:
+
+`-a'
+ Show data for all users (the default is to show data only for the
+ user executing `history').
+
+`-l'
+ Show last modification only.
+
+`-w'
+ Show only the records for modifications done from the same working
+ directory where `history' is executing.
+
+ The options shown as `-options ARGS' constrain the report based on
+an argument:
+
+`-b STR'
+ Show data back to a record containing the string STR in either
+ the module name, the file name, or the repository path.
+
+`-D DATE'
+ Show data since DATE. This is slightly different from the normal
+ use of `-D DATE', which selects the newest revision older than
+ DATE.
+
+`-f FILE'
+ Show data for a particular file (you can specify several `-f'
+ options on the same command line). This is equivalent to
+ specifying the file on the command line.
+
+`-n MODULE'
+ Show data for a particular module (you can specify several `-n'
+ options on the same command line).
+
+`-p REPOSITORY'
+ Show data for a particular source repository (you can specify
+ several `-p' options on the same command line).
+
+`-r REV'
+ Show records referring to revisions since the revision or tag
+ named REV appears in individual RCS files. Each RCS file is
+ searched for the revision or tag.
+
+`-t TAG'
+ Show records since tag TAG was last added to the history file.
+ This differs from the `-r' flag above in that it reads only the
+ history file, not the RCS files, and is much faster.
+
+`-u NAME'
+ Show records for user NAME.
+
+`-z TIMEZONE'
+ Show times in the selected records using the specified time zone
+ instead of UTC.
+
+
+File: cvs.info, Node: import, Next: log, Prev: history, Up: CVS commands
+
+A.14 import--Import sources into CVS, using vendor branches
+===========================================================
+
+ * Synopsis: import [-options] repository vendortag releasetag...
+
+ * Requires: Repository, source distribution directory.
+
+ * Changes: repository.
+
+ Use `import' to incorporate an entire source distribution from an
+outside source (e.g., a source vendor) into your source repository
+directory. You can use this command both for initial creation of a
+repository, and for wholesale updates to the module from the outside
+source. *Note Tracking sources::, for a discussion on this subject.
+
+ The REPOSITORY argument gives a directory name (or a path to a
+directory) under the CVS root directory for repositories; if the
+directory did not exist, import creates it.
+
+ When you use import for updates to source that has been modified in
+your source repository (since a prior import), it will notify you of
+any files that conflict in the two branches of development; use
+`checkout -j' to reconcile the differences, as import instructs you to
+do.
+
+ If CVS decides a file should be ignored (*note cvsignore::), it does
+not import it and prints `I ' followed by the filename (*note import
+output::, for a complete description of the output).
+
+ If the file `$CVSROOT/CVSROOT/cvswrappers' exists, any file whose
+names match the specifications in that file will be treated as packages
+and the appropriate filtering will be performed on the file/directory
+before being imported. *Note Wrappers::.
+
+ The outside source is saved in a first-level branch, by default
+1.1.1. Updates are leaves of this branch; for example, files from the
+first imported collection of source will be revision 1.1.1.1, then
+files from the first imported update will be revision 1.1.1.2, and so
+on.
+
+ At least three arguments are required. REPOSITORY is needed to
+identify the collection of source. VENDORTAG is a tag for the entire
+branch (e.g., for 1.1.1). You must also specify at least one
+RELEASETAG to uniquely identify the files at the leaves created each
+time you execute `import'. The RELEASETAG should be new, not
+previously existing in the repository file, and uniquely identify the
+imported release,
+
+ Note that `import' does _not_ change the directory in which you
+invoke it. In particular, it does not set up that directory as a CVS
+working directory; if you want to work with the sources import them
+first and then check them out into a different directory (*note Getting
+the source::).
+
+* Menu:
+
+* import options:: import options
+* import output:: import output
+* import examples:: import examples
+
+
+File: cvs.info, Node: import options, Next: import output, Up: import
+
+A.14.1 import options
+---------------------
+
+This standard option is supported by `import' (*note Common options::,
+for a complete description):
+
+`-m MESSAGE'
+ Use MESSAGE as log information, instead of invoking an editor.
+
+ There are the following additional special options.
+
+`-b BRANCH'
+ See *Note Multiple vendor branches::.
+
+`-k SUBST'
+ Indicate the keyword expansion mode desired. This setting will
+ apply to all files created during the import, but not to any files
+ that previously existed in the repository. See *Note Substitution
+ modes::, for a list of valid `-k' settings.
+
+`-I NAME'
+ Specify file names that should be ignored during import. You can
+ use this option repeatedly. To avoid ignoring any files at all
+ (even those ignored by default), specify `-I !'.
+
+ NAME can be a file name pattern of the same type that you can
+ specify in the `.cvsignore' file. *Note cvsignore::.
+
+`-W SPEC'
+ Specify file names that should be filtered during import. You can
+ use this option repeatedly.
+
+ SPEC can be a file name pattern of the same type that you can
+ specify in the `.cvswrappers' file. *Note Wrappers::.
+
+`-X'
+ Modify the algorithm used by CVS when importing new files so that
+ new files do not immediately appear on the main trunk.
+
+ Specifically, this flag causes CVS to mark new files as if they
+ were deleted on the main trunk, by taking the following steps for
+ each file in addition to those normally taken on import: creating
+ a new revision on the main trunk indicating that the new file is
+ `dead', resetting the new file's default branch, and placing the
+ file in the Attic (*note Attic::) directory.
+
+ Use of this option can be forced on a repository-wide basis by
+ setting the `ImportNewFilesToVendorBranchOnly' option in
+ CVSROOT/config (*note config::).
+
+
+File: cvs.info, Node: import output, Next: import examples, Prev: import options, Up: import
+
+A.14.2 import output
+--------------------
+
+`import' keeps you informed of its progress by printing a line for each
+file, preceded by one character indicating the status of the file:
+
+`U FILE'
+ The file already exists in the repository and has not been locally
+ modified; a new revision has been created (if necessary).
+
+`N FILE'
+ The file is a new file which has been added to the repository.
+
+`C FILE'
+ The file already exists in the repository but has been locally
+ modified; you will have to merge the changes.
+
+`I FILE'
+ The file is being ignored (*note cvsignore::).
+
+`L FILE'
+ The file is a symbolic link; `cvs import' ignores symbolic links.
+ People periodically suggest that this behavior should be changed,
+ but if there is a consensus on what it should be changed to, it is
+ not apparent. (Various options in the `modules' file can be used
+ to recreate symbolic links on checkout, update, etc.; *note
+ modules::.)
+
+
+File: cvs.info, Node: import examples, Prev: import output, Up: import
+
+A.14.3 import examples
+----------------------
+
+See *Note Tracking sources::, and *Note From files::.
+
+
+File: cvs.info, Node: log, Next: ls & rls, Prev: import, Up: CVS commands
+
+A.15 log--Print out log information for files
+=============================================
+
+ * Synopsis: log [options] [files...]
+
+ * Requires: repository, working directory.
+
+ * Changes: nothing.
+
+ Display log information for files. `log' used to call the RCS
+utility `rlog'. Although this is no longer true in the current
+sources, this history determines the format of the output and the
+options, which are not quite in the style of the other CVS commands.
+
+ The output includes the location of the RCS file, the "head"
+revision (the latest revision on the trunk), all symbolic names (tags)
+and some other things. For each revision, the revision number, the
+date, the author, the number of lines added/deleted, the commitid and
+the log message are printed. All dates are displayed in local time at
+the client. This is typically specified in the `$TZ' environment
+variable, which can be set to govern how `log' displays dates.
+
+ *Note_ `log' uses `-R' in a way that conflicts with the normal use
+inside CVS (*note Common options::).*
+
+* Menu:
+
+* log options:: log options
+* log examples:: log examples
+
+
+File: cvs.info, Node: log options, Next: log examples, Up: log
+
+A.15.1 log options
+------------------
+
+By default, `log' prints all information that is available. All other
+options restrict the output. Note that the revision selection options
+(`-d', `-r', `-s', and `-w') have no effect, other than possibly
+causing a search for files in Attic directories, when used in
+conjunction with the options that restrict the output to only `log'
+header fields (`-b', `-h', `-R', and `-t') unless the `-S' option is
+also specified.
+
+`-b'
+ Print information about the revisions on the default branch,
+ normally the highest branch on the trunk.
+
+`-d DATES'
+ Print information about revisions with a checkin date/time in the
+ range given by the semicolon-separated list of dates. The date
+ formats accepted are those accepted by the `-D' option to many
+ other CVS commands (*note Common options::). Dates can be
+ combined into ranges as follows:
+
+ `D1<D2'
+ `D2>D1'
+ Select the revisions that were deposited between D1 and D2.
+
+ `<D'
+ `D>'
+ Select all revisions dated D or earlier.
+
+ `D<'
+ `>D'
+ Select all revisions dated D or later.
+
+ `D'
+ Select the single, latest revision dated D or earlier.
+
+ The `>' or `<' characters may be followed by `=' to indicate an
+ inclusive range rather than an exclusive one.
+
+ Note that the separator is a semicolon (;).
+
+`-h'
+ Print only the name of the RCS file, name of the file in the
+ working directory, head, default branch, access list, locks,
+ symbolic names, and suffix.
+
+`-l'
+ Local; run only in current working directory. (Default is to run
+ recursively).
+
+`-N'
+ Do not print the list of tags for this file. This option can be
+ very useful when your site uses a lot of tags, so rather than
+ "more"'ing over 3 pages of tag information, the log information is
+ presented without tags at all.
+
+`-R'
+ Print only the name of the RCS file.
+
+`-rREVISIONS'
+ Print information about revisions given in the comma-separated
+ list REVISIONS of revisions and ranges. The following table
+ explains the available range formats:
+
+ `REV1:REV2'
+ Revisions REV1 to REV2 (which must be on the same branch).
+
+ `REV1::REV2'
+ The same, but excluding REV1.
+
+ `:REV'
+ `::REV'
+ Revisions from the beginning of the branch up to and
+ including REV.
+
+ `REV:'
+ Revisions starting with REV to the end of the branch
+ containing REV.
+
+ `REV::'
+ Revisions starting just after REV to the end of the branch
+ containing REV.
+
+ `BRANCH'
+ An argument that is a branch means all revisions on that
+ branch.
+
+ `BRANCH1:BRANCH2'
+ `BRANCH1::BRANCH2'
+ A range of branches means all revisions on the branches in
+ that range.
+
+ `BRANCH.'
+ The latest revision in BRANCH.
+
+ A bare `-r' with no revisions means the latest revision on the
+ default branch, normally the trunk. There can be no space between
+ the `-r' option and its argument.
+
+`-S'
+ Suppress the header if no revisions are selected.
+
+`-s STATES'
+ Print information about revisions whose state attributes match one
+ of the states given in the comma-separated list STATES.
+ Individual states may be any text string, though CVS commonly only
+ uses two states, `Exp' and `dead'. See *Note admin options:: for
+ more information.
+
+`-t'
+ Print the same as `-h', plus the descriptive text.
+
+`-wLOGINS'
+ Print information about revisions checked in by users with login
+ names appearing in the comma-separated list LOGINS. If LOGINS is
+ omitted, the user's login is assumed. There can be no space
+ between the `-w' option and its argument.
+
+ `log' prints the intersection of the revisions selected with the
+options `-d', `-s', and `-w', intersected with the union of the
+revisions selected by `-b' and `-r'.
+
+
+File: cvs.info, Node: log examples, Prev: log options, Up: log
+
+A.15.2 log examples
+-------------------
+
+Since `log' shows dates in local time, you might want to see them in
+Coordinated Universal Time (UTC) or some other timezone. To do this
+you can set your `$TZ' environment variable before invoking CVS:
+
+ $ TZ=UTC cvs log foo.c
+ $ TZ=EST cvs log bar.c
+
+ (If you are using a `csh'-style shell, like `tcsh', you would need
+to prefix the examples above with `env'.)
+
+
+File: cvs.info, Node: ls & rls, Next: rdiff, Prev: log, Up: CVS commands
+
+A.16 ls & rls
+=============
+
+ * ls [-e | -l] [-RP] [-r tag[:date]] [-D date] [path...]
+
+ * Requires: repository for `rls', repository & working directory for
+ `ls'.
+
+ * Changes: nothing.
+
+ * Synonym: `dir' & `list' are synonyms for `ls' and `rdir' & `rlist'
+ are synonyms for `rls'.
+
+ The `ls' and `rls' commands are used to list files and directories
+in the repository.
+
+ By default `ls' lists the files and directories that belong in your
+working directory, what would be there after an `update'.
+
+ By default `rls' lists the files and directories on the tip of the
+trunk in the topmost directory of the repository.
+
+ Both commands accept an optional list of file and directory names,
+relative to the working directory for `ls' and the topmost directory of
+the repository for `rls'. Neither is recursive by default.
+
+* Menu:
+
+* ls & rls options:: ls & rls options
+* rls examples: rls examples
+
+
+File: cvs.info, Node: ls & rls options, Next: rls examples, Up: ls & rls
+
+A.16.1 ls & rls options
+-----------------------
+
+These standard options are supported by `ls' & `rls':
+
+`-d'
+ Show dead revisions (with tag when specified).
+
+`-e'
+ Display in CVS/Entries format. This format is meant to remain
+ easily parsable by automation.
+
+`-l'
+ Display all details.
+
+`-P'
+ Don't list contents of empty directories when recursing.
+
+`-R'
+ List recursively.
+
+`-r TAG[:DATE]'
+ Show files specified by TAG or, when DATE is specified and TAG is
+ a branch tag, the version from the branch TAG as it existed on
+ DATE. See *Note Common options::.
+
+`-D DATE'
+ Show files from date.
+
+
+File: cvs.info, Node: rls examples, Prev: ls & rls options, Up: ls & rls
+
+A.16.2 rls examples
+-------------------
+
+ $ cvs rls
+ cvs rls: Listing module: `.'
+ CVSROOT
+ first-dir
+
+ $ cvs rls CVSROOT
+ cvs rls: Listing module: `CVSROOT'
+ checkoutlist
+ commitinfo
+ config
+ cvswrappers
+ loginfo
+ modules
+ notify
+ rcsinfo
+ taginfo
+ verifymsg
+
+
+File: cvs.info, Node: rdiff, Next: release, Prev: ls & rls, Up: CVS commands
+
+A.17 rdiff--'patch' format diffs between releases
+=================================================
+
+ * rdiff [-flags] [-V vn] (-r tag1[:date1] | -D date1) [-r
+ tag2[:date2] | -D date2] modules...
+
+ * Requires: repository.
+
+ * Changes: nothing.
+
+ * Synonym: patch
+
+ Builds a Larry Wall format patch(1) file between two releases, that
+can be fed directly into the `patch' program to bring an old release
+up-to-date with the new release. (This is one of the few CVS commands
+that operates directly from the repository, and doesn't require a prior
+checkout.) The diff output is sent to the standard output device.
+
+ You can specify (using the standard `-r' and `-D' options) any
+combination of one or two revisions or dates. If only one revision or
+date is specified, the patch file reflects differences between that
+revision or date and the current head revisions in the RCS file.
+
+ Note that if the software release affected is contained in more than
+one directory, then it may be necessary to specify the `-p' option to
+the `patch' command when patching the old sources, so that `patch' is
+able to find the files that are located in other directories.
+
+* Menu:
+
+* rdiff options:: rdiff options
+* rdiff examples:: rdiff examples
+
+
+File: cvs.info, Node: rdiff options, Next: rdiff examples, Up: rdiff
+
+A.17.1 rdiff options
+--------------------
+
+These standard options are supported by `rdiff' (*note Common
+options::, for a complete description of them):
+
+`-D DATE'
+ Use the most recent revision no later than DATE.
+
+`-f'
+ If no matching revision is found, retrieve the most recent
+ revision (instead of ignoring the file).
+
+`-k KFLAG'
+ Process keywords according to KFLAG. See *Note Keyword
+ substitution::.
+
+`-l'
+ Local; don't descend subdirectories.
+
+`-R'
+ Examine directories recursively. This option is on by default.
+
+`-r TAG'
+ Use the revision specified by TAG, or when DATE is specified and
+ TAG is a branch tag, the version from the branch TAG as it existed
+ on DATE. See *Note Common options::.
+
+ In addition to the above, these options are available:
+
+`-c'
+ Use the context diff format. This is the default format.
+
+`-s'
+ Create a summary change report instead of a patch. The summary
+ includes information about files that were changed or added
+ between the releases. It is sent to the standard output device.
+ This is useful for finding out, for example, which files have
+ changed between two dates or revisions.
+
+`-t'
+ A diff of the top two revisions is sent to the standard output
+ device. This is most useful for seeing what the last change to a
+ file was.
+
+`-u'
+ Use the unidiff format for the context diffs. Remember that old
+ versions of the `patch' program can't handle the unidiff format,
+ so if you plan to post this patch to the net you should probably
+ not use `-u'.
+
+`-V VN'
+ Expand keywords according to the rules current in RCS version VN
+ (the expansion format changed with RCS version 5). Note that this
+ option is no longer accepted. CVS will always expand keywords the
+ way that RCS version 5 does.
+
+
+File: cvs.info, Node: rdiff examples, Prev: rdiff options, Up: rdiff
+
+A.17.2 rdiff examples
+---------------------
+
+Suppose you receive mail from foo@example.net asking for an update from
+release 1.2 to 1.4 of the tc compiler. You have no such patches on
+hand, but with CVS that can easily be fixed with a command such as this:
+
+ $ cvs rdiff -c -r FOO1_2 -r FOO1_4 tc | \
+ $$ Mail -s 'The patches you asked for' foo@example.net
+
+ Suppose you have made release 1.3, and forked a branch called
+`R_1_3fix' for bug fixes. `R_1_3_1' corresponds to release 1.3.1,
+which was made some time ago. Now, you want to see how much
+development has been done on the branch. This command can be used:
+
+ $ cvs patch -s -r R_1_3_1 -r R_1_3fix module-name
+ cvs rdiff: Diffing module-name
+ File ChangeLog,v changed from revision 1.52.2.5 to 1.52.2.6
+ File foo.c,v changed from revision 1.52.2.3 to 1.52.2.4
+ File bar.h,v changed from revision 1.29.2.1 to 1.2
+
+
+File: cvs.info, Node: release, Next: server & pserver, Prev: rdiff, Up: CVS commands
+
+A.18 release--Indicate that a Module is no longer in use
+========================================================
+
+ * release [-d] directories...
+
+ * Requires: Working directory.
+
+ * Changes: Working directory, history log.
+
+ This command is meant to safely cancel the effect of `cvs checkout'.
+Since CVS doesn't lock files, it isn't strictly necessary to use this
+command. You can always simply delete your working directory, if you
+like; but you risk losing changes you may have forgotten, and you leave
+no trace in the CVS history file (*note history file::) that you've
+abandoned your checkout.
+
+ Use `cvs release' to avoid these problems. This command checks that
+no uncommitted changes are present; that you are executing it from
+immediately above a CVS working directory; and that the repository
+recorded for your files is the same as the repository defined in the
+module database.
+
+ If all these conditions are true, `cvs release' leaves a record of
+its execution (attesting to your intentionally abandoning your
+checkout) in the CVS history log.
+
+* Menu:
+
+* release options:: release options
+* release output:: release output
+* release examples:: release examples
+
+
+File: cvs.info, Node: release options, Next: release output, Up: release
+
+A.18.1 release options
+----------------------
+
+The `release' command supports one command option:
+
+`-d'
+ Delete your working copy of the file if the release succeeds. If
+ this flag is not given your files will remain in your working
+ directory.
+
+ *WARNING: The `release' command deletes all directories and files
+ recursively. This has the very serious side-effect that any
+ directory that you have created inside your checked-out sources,
+ and not added to the repository (using the `add' command; *note
+ Adding files::) will be silently deleted--even if it is non-empty!*
+
+
+File: cvs.info, Node: release output, Next: release examples, Prev: release options, Up: release
+
+A.18.2 release output
+---------------------
+
+Before `release' releases your sources it will print a one-line message
+for any file that is not up-to-date.
+
+`U FILE'
+`P FILE'
+ There exists a newer revision of this file in the repository, and
+ you have not modified your local copy of the file (`U' and `P'
+ mean the same thing).
+
+`A FILE'
+ The file has been added to your private copy of the sources, but
+ has not yet been committed to the repository. If you delete your
+ copy of the sources this file will be lost.
+
+`R FILE'
+ The file has been removed from your private copy of the sources,
+ but has not yet been removed from the repository, since you have
+ not yet committed the removal. *Note commit::.
+
+`M FILE'
+ The file is modified in your working directory. There might also
+ be a newer revision inside the repository.
+
+`? FILE'
+ FILE is in your working directory, but does not correspond to
+ anything in the source repository, and is not in the list of files
+ for CVS to ignore (see the description of the `-I' option, and
+ *note cvsignore::). If you remove your working sources, this file
+ will be lost.
+
+
+File: cvs.info, Node: release examples, Prev: release output, Up: release
+
+A.18.3 release examples
+-----------------------
+
+Release the `tc' directory, and delete your local working copy of the
+files.
+
+ $ cd .. # You must stand immediately above the
+ # sources when you issue `cvs release'.
+ $ cvs release -d tc
+ You have [0] altered files in this repository.
+ Are you sure you want to release (and delete) directory `tc': y
+ $
+
+
+File: cvs.info, Node: server & pserver, Next: update, Prev: release, Up: CVS commands
+
+A.19 server & pserver--Act as a server for a client on stdin/stdout
+===================================================================
+
+ * pserver [-c path]
+
+ server [-c path]
+
+ * Requires: repository, client conversation on stdin/stdout
+
+ * Changes: Repository or, indirectly, client working directory.
+
+ The CVS `server' and `pserver' commands are used to provide
+repository access to remote clients and expect a client conversation on
+stdin & stdout. Typically these commands are launched from `inetd' or
+via `ssh' (*note Remote repositories::).
+
+ `server' expects that the client has already been authenticated
+somehow, typically via SSH, and `pserver' attempts to authenticate the
+client itself.
+
+ Only one option is available with the `server' and `pserver'
+commands:
+
+`-c path'
+ Load configuration from PATH rather than the default location
+ `$CVSROOT/CVSROOT/config' (*note config::). PATH must be
+ `/etc/cvs.conf' or prefixed by `/etc/cvs/'. This option is
+ supported beginning with CVS release 1.12.13.
+
+
+File: cvs.info, Node: update, Prev: server & pserver, Up: CVS commands
+
+A.20 update--Bring work tree in sync with repository
+====================================================
+
+ * update [-ACdflPpR] [-I name] [-j rev [-j rev]] [-k kflag] [-r
+ tag[:date] | -D date] [-W spec] files...
+
+ * Requires: repository, working directory.
+
+ * Changes: working directory.
+
+ After you've run checkout to create your private copy of source from
+the common repository, other developers will continue changing the
+central source. From time to time, when it is convenient in your
+development process, you can use the `update' command from within your
+working directory to reconcile your work with any revisions applied to
+the source repository since your last checkout or update. Without the
+`-C' option, `update' will also merge any differences between the local
+copy of files and their base revisions into any destination revisions
+specified with `-r', `-D', or `-A'.
+
+* Menu:
+
+* update options:: update options
+* update output:: update output
+
+
+File: cvs.info, Node: update options, Next: update output, Up: update
+
+A.20.1 update options
+---------------------
+
+These standard options are available with `update' (*note Common
+options::, for a complete description of them):
+
+`-D date'
+ Use the most recent revision no later than DATE. This option is
+ sticky, and implies `-P'. See *Note Sticky tags::, for more
+ information on sticky tags/dates.
+
+`-f'
+ Only useful with the `-D' or `-r' flags. If no matching revision
+ is found, retrieve the most recent revision (instead of ignoring
+ the file).
+
+`-k KFLAG'
+ Process keywords according to KFLAG. See *Note Keyword
+ substitution::. This option is sticky; future updates of this
+ file in this working directory will use the same KFLAG. The
+ `status' command can be viewed to see the sticky options. See
+ *Note Invoking CVS::, for more information on the `status' command.
+
+`-l'
+ Local; run only in current working directory. *Note Recursive
+ behavior::.
+
+`-P'
+ Prune empty directories. See *Note Moving directories::.
+
+`-p'
+ Pipe files to the standard output.
+
+`-R'
+ Update directories recursively (default). *Note Recursive
+ behavior::.
+
+`-r TAG[:DATE]'
+ Retrieve the revisions specified by TAG or, when DATE is specified
+ and TAG is a branch tag, the version from the branch TAG as it
+ existed on DATE. This option is sticky, and implies `-P'. See
+ *Note Sticky tags::, for more information on sticky tags/dates.
+ Also see *Note Common options::.
+
+ These special options are also available with `update'.
+
+`-A'
+ Reset any sticky tags, dates, or `-k' options. See *Note Sticky
+ tags::, for more information on sticky tags/dates.
+
+`-C'
+ Overwrite locally modified files with clean copies from the
+ repository (the modified file is saved in `.#FILE.REVISION',
+ however).
+
+`-d'
+ Create any directories that exist in the repository if they're
+ missing from the working directory. Normally, `update' acts only
+ on directories and files that were already enrolled in your
+ working directory.
+
+ This is useful for updating directories that were created in the
+ repository since the initial checkout; but it has an unfortunate
+ side effect. If you deliberately avoided certain directories in
+ the repository when you created your working directory (either
+ through use of a module name or by listing explicitly the files
+ and directories you wanted on the command line), then updating
+ with `-d' will create those directories, which may not be what you
+ want.
+
+`-I NAME'
+ Ignore files whose names match NAME (in your working directory)
+ during the update. You can specify `-I' more than once on the
+ command line to specify several files to ignore. Use `-I !' to
+ avoid ignoring any files at all. *Note cvsignore::, for other
+ ways to make CVS ignore some files.
+
+`-WSPEC'
+ Specify file names that should be filtered during update. You can
+ use this option repeatedly.
+
+ SPEC can be a file name pattern of the same type that you can
+ specify in the `.cvswrappers' file. *Note Wrappers::.
+
+`-jREVISION'
+ With two `-j' options, merge changes from the revision specified
+ with the first `-j' option to the revision specified with the
+ second `j' option, into the working directory.
+
+ With one `-j' option, merge changes from the ancestor revision to
+ the revision specified with the `-j' option, into the working
+ directory. The ancestor revision is the common ancestor of the
+ revision which the working directory is based on, and the revision
+ specified in the `-j' option.
+
+ Note that using a single `-j TAGNAME' option rather than `-j
+ BRANCHNAME' to merge changes from a branch will often not remove
+ files which were removed on the branch. *Note Merging adds and
+ removals::, for more.
+
+ In addition, each `-j' option can contain an optional date
+ specification which, when used with branches, can limit the chosen
+ revision to one within a specific date. An optional date is
+ specified by adding a colon (:) to the tag:
+ `-jSYMBOLIC_TAG:DATE_SPECIFIER'.
+
+ *Note Branching and merging::.
+
+
+
+File: cvs.info, Node: update output, Prev: update options, Up: update
+
+A.20.2 update output
+--------------------
+
+`update' and `checkout' keep you informed of their progress by printing
+a line for each file, preceded by one character indicating the status
+of the file:
+
+`U FILE'
+ The file was brought up to date with respect to the repository.
+ This is done for any file that exists in the repository but not in
+ your working directory, and for files that you haven't changed but
+ are not the most recent versions available in the repository.
+
+`P FILE'
+ Like `U', but the CVS server sends a patch instead of an entire
+ file. This accomplishes the same thing as `U' using less
+ bandwidth.
+
+`A FILE'
+ The file has been added to your private copy of the sources, and
+ will be added to the source repository when you run `commit' on
+ the file. This is a reminder to you that the file needs to be
+ committed.
+
+`R FILE'
+ The file has been removed from your private copy of the sources,
+ and will be removed from the source repository when you run
+ `commit' on the file. This is a reminder to you that the file
+ needs to be committed.
+
+`M FILE'
+ The file is modified in your working directory.
+
+ `M' can indicate one of two states for a file you're working on:
+ either there were no modifications to the same file in the
+ repository, so that your file remains as you last saw it; or there
+ were modifications in the repository as well as in your copy, but
+ they were merged successfully, without conflict, in your working
+ directory.
+
+ CVS will print some messages if it merges your work, and a backup
+ copy of your working file (as it looked before you ran `update')
+ will be made. The exact name of that file is printed while
+ `update' runs.
+
+`C FILE'
+ A conflict was detected while trying to merge your changes to FILE
+ with changes from the source repository. FILE (the copy in your
+ working directory) is now the result of attempting to merge the
+ two revisions; an unmodified copy of your file is also in your
+ working directory, with the name `.#FILE.REVISION' where REVISION
+ is the revision that your modified file started from. Resolve the
+ conflict as described in *Note Conflicts example::. (Note that
+ some systems automatically purge files that begin with `.#' if
+ they have not been accessed for a few days. If you intend to keep
+ a copy of your original file, it is a very good idea to rename
+ it.) Under VMS, the file name starts with `__' rather than `.#'.
+
+`? FILE'
+ FILE is in your working directory, but does not correspond to
+ anything in the source repository, and is not in the list of files
+ for CVS to ignore (see the description of the `-I' option, and
+ *note cvsignore::).
+
+
+File: cvs.info, Node: Invoking CVS, Next: Administrative files, Prev: CVS commands, Up: Top
+
+Appendix B Quick reference to CVS commands
+******************************************
+
+This appendix describes how to invoke CVS, with references to where
+each command or feature is described in detail. For other references
+run the `cvs --help' command, or see *Note Index::.
+
+ A CVS command looks like:
+
+ cvs [ GLOBAL_OPTIONS ] COMMAND [ COMMAND_OPTIONS ] [ COMMAND_ARGS ]
+
+ Global options:
+
+`--allow-root=ROOTDIR'
+ Specify legal CVSROOT directory (server only) (not in CVS 1.9 and
+ older). See *Note Password authentication server::.
+
+`-a'
+ Authenticate all communication (client only) (not in CVS 1.9 and
+ older). See *Note Global options::.
+
+`-b'
+ Specify RCS location (CVS 1.9 and older). See *Note Global
+ options::.
+
+`-d ROOT'
+ Specify the CVSROOT. See *Note Repository::.
+
+`-e EDITOR'
+ Edit messages with EDITOR. See *Note Committing your changes::.
+
+`-f'
+ Do not read the `~/.cvsrc' file. See *Note Global options::.
+
+`-H'
+`--help'
+ Print a help message. See *Note Global options::.
+
+`-n'
+ Do not change any files. See *Note Global options::.
+
+`-Q'
+ Be really quiet. See *Note Global options::.
+
+`-q'
+ Be somewhat quiet. See *Note Global options::.
+
+`-r'
+ Make new working files read-only. See *Note Global options::.
+
+`-s VARIABLE=VALUE'
+ Set a user variable. See *Note Variables::.
+
+`-T TEMPDIR'
+ Put temporary files in TEMPDIR. See *Note Global options::.
+
+`-t'
+ Trace CVS execution. See *Note Global options::.
+
+`-v'
+
+`--version'
+ Display version and copyright information for CVS.
+
+`-w'
+ Make new working files read-write. See *Note Global options::.
+
+`-x'
+ Encrypt all communication (client only). See *Note Global
+ options::.
+
+`-z GZIP-LEVEL'
+ Set the compression level (client only). See *Note Global
+ options::.
+
+ Keyword expansion modes (*note Substitution modes::):
+
+ -kkv $Id: file1,v 1.1 1993/12/09 03:21:13 joe Exp $
+ -kkvl $Id: file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+ -kk $Id$
+ -kv file1,v 1.1 1993/12/09 03:21:13 joe Exp
+ -ko no expansion
+ -kb no expansion, file is binary
+
+ Keywords (*note Keyword list::):
+
+ $Author: joe $
+ $Date: 1993/12/09 03:21:13 $
+ $CVSHeader: files/file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+ $Header: /home/files/file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+ $Id: file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+ $Locker: harry $
+ $Name: snapshot_1_14 $
+ $RCSfile: file1,v $
+ $Revision: 1.1 $
+ $Source: /home/files/file1,v $
+ $State: Exp $
+ $Log: file1,v $
+ Revision 1.1 1993/12/09 03:30:17 joe
+ Initial revision
+
+ Commands, command options, and command arguments:
+
+`add [OPTIONS] [FILES...]'
+ Add a new file/directory. See *Note Adding files::.
+
+ `-k KFLAG'
+ Set keyword expansion.
+
+ `-m MSG'
+ Set file description.
+
+`admin [OPTIONS] [FILES...]'
+ Administration of history files in the repository. See *Note
+ admin::.
+
+ `-b[REV]'
+ Set default branch. See *Note Reverting local changes::.
+
+ `-cSTRING'
+ Set comment leader.
+
+ `-kSUBST'
+ Set keyword substitution. See *Note Keyword substitution::.
+
+ `-l[REV]'
+ Lock revision REV, or latest revision.
+
+ `-mREV:MSG'
+ Replace the log message of revision REV with MSG.
+
+ `-oRANGE'
+ Delete revisions from the repository. See *Note admin
+ options::.
+
+ `-q'
+ Run quietly; do not print diagnostics.
+
+ `-sSTATE[:REV]'
+ Set the state. See *Note admin options:: for more
+ information on possible states.
+
+ `-t'
+ Set file description from standard input.
+
+ `-tFILE'
+ Set file description from FILE.
+
+ `-t-STRING'
+ Set file description to STRING.
+
+ `-u[REV]'
+ Unlock revision REV, or latest revision.
+
+`annotate [OPTIONS] [FILES...]'
+ Show last revision where each line was modified. See *Note
+ annotate::.
+
+ `-D DATE'
+ Annotate the most recent revision no later than DATE. See
+ *Note Common options::.
+
+ `-F'
+ Force annotation of binary files. (Without this option,
+ binary files are skipped with a message.)
+
+ `-f'
+ Use head revision if tag/date not found. See *Note Common
+ options::.
+
+ `-l'
+ Local; run only in current working directory. *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Annotate revisions specified by TAG or, when DATE is specified
+ and TAG is a branch tag, the version from the branch TAG as it
+ existed on DATE. See *Note Common options::.
+
+`checkout [OPTIONS] MODULES...'
+ Get a copy of the sources. See *Note checkout::.
+
+ `-A'
+ Reset any sticky tags/date/options. See *Note Sticky tags::
+ and *Note Keyword substitution::.
+
+ `-c'
+ Output the module database. See *Note checkout options::.
+
+ `-D DATE'
+ Check out revisions as of DATE (is sticky). See *Note Common
+ options::.
+
+ `-d DIR'
+ Check out into DIR. See *Note checkout options::.
+
+ `-f'
+ Use head revision if tag/date not found. See *Note Common
+ options::.
+
+ `-j TAG[:DATE]'
+ Merge in the change specified by TAG, or when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. See *Note checkout
+ options::.
+
+ `-k KFLAG'
+ Use KFLAG keyword expansion. See *Note Substitution modes::.
+
+ `-l'
+ Local; run only in current working directory. *Note
+ Recursive behavior::.
+
+ `-N'
+ Don't "shorten" module paths if -d specified. See *Note
+ checkout options::.
+
+ `-n'
+ Do not run module program (if any). See *Note checkout
+ options::.
+
+ `-P'
+ Prune empty directories. See *Note Moving directories::.
+
+ `-p'
+ Check out files to standard output (avoids stickiness). See
+ *Note checkout options::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Checkout the revision already tagged with TAG or, when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. This . See *Note Common
+ options::.
+
+ `-s'
+ Like -c, but include module status. See *Note checkout
+ options::.
+
+`commit [OPTIONS] [FILES...]'
+ Check changes into the repository. See *Note commit::.
+
+ `-c'
+ Check for valid edits before committing. Requires a CVS
+ client and server both version 1.12.10 or greater.
+
+ `-F FILE'
+ Read log message from FILE. See *Note commit options::.
+
+ `-f'
+ Force the file to be committed; disables recursion. See
+ *Note commit options::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-m MSG'
+ Use MSG as log message. See *Note commit options::.
+
+ `-n'
+ Do not run module program (if any). See *Note commit
+ options::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r REV'
+ Commit to REV. See *Note commit options::.
+
+`diff [OPTIONS] [FILES...]'
+ Show differences between revisions. See *Note diff::. In
+ addition to the options shown below, accepts a wide variety of
+ options to control output style, for example `-c' for context
+ diffs.
+
+ `-D DATE1'
+ Diff revision for date against working file. See *Note diff
+ options::.
+
+ `-D DATE2'
+ Diff REV1/DATE1 against DATE2. See *Note diff options::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-N'
+ Include diffs for added and removed files. See *Note diff
+ options::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG1[:DATE1]'
+ Diff the revisions specified by TAG1 or, when DATE1 is
+ specified and TAG1 is a branch tag, the version from the
+ branch TAG1 as it existed on DATE1, against the working file.
+ See *Note diff options:: and *Note Common options::.
+
+ `-r TAG2[:DATE2]'
+ Diff the revisions specified by TAG2 or, when DATE2 is
+ specified and TAG2 is a branch tag, the version from the
+ branch TAG2 as it existed on DATE2, against REV1/DATE1. See
+ *Note diff options:: and *Note Common options::.
+
+`edit [OPTIONS] [FILES...]'
+ Get ready to edit a watched file. See *Note Editing files::.
+
+ `-a ACTIONS'
+ Specify actions for temporary watch, where ACTIONS is `edit',
+ `unedit', `commit', `all', or `none'. See *Note Editing
+ files::.
+
+ `-c'
+ Check edits: Edit fails if someone else is already editting
+ the file. Requires a CVS client and server both of version
+ 1.12.10 or greater.
+
+ `-f'
+ Force edit; ignore other edits. Added in CVS 1.12.10.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+`editors [OPTIONS] [FILES...]'
+ See who is editing a watched file. See *Note Watch information::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+`export [OPTIONS] MODULES...'
+ Export files from CVS. See *Note export::.
+
+ `-D DATE'
+ Check out revisions as of DATE. See *Note Common options::.
+
+ `-d DIR'
+ Check out into DIR. See *Note export options::.
+
+ `-f'
+ Use head revision if tag/date not found. See *Note Common
+ options::.
+
+ `-k KFLAG'
+ Use KFLAG keyword expansion. See *Note Substitution modes::.
+
+ `-l'
+ Local; run only in current working directory. *Note
+ Recursive behavior::.
+
+ `-N'
+ Don't "shorten" module paths if -d specified. See *Note
+ export options::.
+
+ `-n'
+ Do not run module program (if any). See *Note export
+ options::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Export the revisions specified by TAG or, when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. See *Note Common options::.
+
+`history [OPTIONS] [FILES...]'
+ Show repository access history. See *Note history::.
+
+ `-a'
+ All users (default is self). See *Note history options::.
+
+ `-b STR'
+ Back to record with STR in module/file/repos field. See
+ *Note history options::.
+
+ `-c'
+ Report on committed (modified) files. See *Note history
+ options::.
+
+ `-D DATE'
+ Since DATE. See *Note history options::.
+
+ `-e'
+ Report on all record types. See *Note history options::.
+
+ `-l'
+ Last modified (committed or modified report). See *Note
+ history options::.
+
+ `-m MODULE'
+ Report on MODULE (repeatable). See *Note history options::.
+
+ `-n MODULE'
+ In MODULE. See *Note history options::.
+
+ `-o'
+ Report on checked out modules. See *Note history options::.
+
+ `-p REPOSITORY'
+ In REPOSITORY. See *Note history options::.
+
+ `-r REV'
+ Since revision REV. See *Note history options::.
+
+ `-T'
+ Produce report on all TAGs. See *Note history options::.
+
+ `-t TAG'
+ Since tag record placed in history file (by anyone). See
+ *Note history options::.
+
+ `-u USER'
+ For user USER (repeatable). See *Note history options::.
+
+ `-w'
+ Working directory must match. See *Note history options::.
+
+ `-x TYPES'
+ Report on TYPES, one or more of `TOEFWUPCGMAR'. See *Note
+ history options::.
+
+ `-z ZONE'
+ Output for time zone ZONE. See *Note history options::.
+
+`import [OPTIONS] REPOSITORY VENDOR-TAG RELEASE-TAGS...'
+ Import files into CVS, using vendor branches. See *Note import::.
+
+ `-b BRA'
+ Import to vendor branch BRA. See *Note Multiple vendor
+ branches::.
+
+ `-d'
+ Use the file's modification time as the time of import. See
+ *Note import options::.
+
+ `-k KFLAG'
+ Set default keyword substitution mode. See *Note import
+ options::.
+
+ `-m MSG'
+ Use MSG for log message. See *Note import options::.
+
+ `-I IGN'
+ More files to ignore (! to reset). See *Note import
+ options::.
+
+ `-W SPEC'
+ More wrappers. See *Note import options::.
+
+`init'
+ Create a CVS repository if it doesn't exist. See *Note Creating a
+ repository::.
+
+`kserver'
+ Kerberos authenticated server. See *Note Kerberos authenticated::.
+
+`log [OPTIONS] [FILES...]'
+ Print out history information for files. See *Note log::.
+
+ `-b'
+ Only list revisions on the default branch. See *Note log
+ options::.
+
+ `-d DATES'
+ Specify dates (D1<D2 for range, D for latest before). See
+ *Note log options::.
+
+ `-h'
+ Only print header. See *Note log options::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-N'
+ Do not list tags. See *Note log options::.
+
+ `-R'
+ Only print name of RCS file. See *Note log options::.
+
+ `-rREVS'
+ Only list revisions REVS. See *Note log options::.
+
+ `-s STATES'
+ Only list revisions with specified states. See *Note log
+ options::.
+
+ `-t'
+ Only print header and descriptive text. See *Note log
+ options::.
+
+ `-wLOGINS'
+ Only list revisions checked in by specified logins. See
+ *Note log options::.
+
+`login'
+ Prompt for password for authenticating server. See *Note Password
+ authentication client::.
+
+`logout'
+ Remove stored password for authenticating server. See *Note
+ Password authentication client::.
+
+`pserver'
+ Password authenticated server. See *Note Password authentication
+ server::.
+
+`rannotate [OPTIONS] [MODULES...]'
+ Show last revision where each line was modified. See *Note
+ annotate::.
+
+ `-D DATE'
+ Annotate the most recent revision no later than DATE. See
+ *Note Common options::.
+
+ `-F'
+ Force annotation of binary files. (Without this option,
+ binary files are skipped with a message.)
+
+ `-f'
+ Use head revision if tag/date not found. See *Note Common
+ options::.
+
+ `-l'
+ Local; run only in current working directory. *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Annotate the revision specified by TAG or, when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. See *Note Common options::.
+
+`rdiff [OPTIONS] MODULES...'
+ Show differences between releases. See *Note rdiff::.
+
+ `-c'
+ Context diff output format (default). See *Note rdiff
+ options::.
+
+ `-D DATE'
+ Select revisions based on DATE. See *Note Common options::.
+
+ `-f'
+ Use head revision if tag/date not found. See *Note Common
+ options::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Select the revisions specified by TAG or, when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. See *Note diff options::
+ and *Note Common options::.
+
+ `-s'
+ Short patch - one liner per file. See *Note rdiff options::.
+
+ `-t'
+ Top two diffs - last change made to the file. See *Note diff
+ options::.
+
+ `-u'
+ Unidiff output format. See *Note rdiff options::.
+
+ `-V VERS'
+ Use RCS Version VERS for keyword expansion (obsolete). See
+ *Note rdiff options::.
+
+`release [OPTIONS] DIRECTORY'
+ Indicate that a directory is no longer in use. See *Note
+ release::.
+
+ `-d'
+ Delete the given directory. See *Note release options::.
+
+`remove [OPTIONS] [FILES...]'
+ Remove an entry from the repository. See *Note Removing files::.
+
+ `-f'
+ Delete the file before removing it. See *Note Removing
+ files::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+`rlog [OPTIONS] [FILES...]'
+ Print out history information for modules. See *Note log::.
+
+ `-b'
+ Only list revisions on the default branch. See *Note log
+ options::.
+
+ `-d DATES'
+ Specify dates (D1<D2 for range, D for latest before). See
+ *Note log options::.
+
+ `-h'
+ Only print header. See *Note log options::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-N'
+ Do not list tags. See *Note log options::.
+
+ `-R'
+ Only print name of RCS file. See *Note log options::.
+
+ `-rREVS'
+ Only list revisions REVS. See *Note log options::.
+
+ `-s STATES'
+ Only list revisions with specified states. See *Note log
+ options::.
+
+ `-t'
+ Only print header and descriptive text. See *Note log
+ options::.
+
+ `-wLOGINS'
+ Only list revisions checked in by specified logins. See
+ *Note log options::.
+
+`rtag [OPTIONS] TAG MODULES...'
+ Add a symbolic tag to a module. See *Note Revisions:: and *Note
+ Branching and merging::.
+
+ `-a'
+ Clear tag from removed files that would not otherwise be
+ tagged. See *Note Tagging add/remove::.
+
+ `-b'
+ Create a branch named TAG. See *Note Branching and merging::.
+
+ `-B'
+ Used in conjunction with -F or -d, enables movement and
+ deletion of branch tags. Use with extreme caution.
+
+ `-D DATE'
+ Tag revisions as of DATE. See *Note Tagging by date/tag::.
+
+ `-d'
+ Delete TAG. See *Note Modifying tags::.
+
+ `-F'
+ Move TAG if it already exists. See *Note Modifying tags::.
+
+ `-f'
+ Force a head revision match if tag/date not found. See *Note
+ Tagging by date/tag::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-n'
+ No execution of tag program. See *Note Common options::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Tag the revision already tagged with TAG or, when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. See *Note Tagging by
+ date/tag:: and *Note Common options::.
+
+`server'
+ Rsh server. See *Note Connecting via rsh::.
+
+`status [OPTIONS] FILES...'
+ Display status information in a working directory. See *Note File
+ status::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-v'
+ Include tag information for file. See *Note Tags::.
+
+`tag [OPTIONS] TAG [FILES...]'
+ Add a symbolic tag to checked out version of files. See *Note
+ Revisions:: and *Note Branching and merging::.
+
+ `-b'
+ Create a branch named TAG. See *Note Branching and merging::.
+
+ `-c'
+ Check that working files are unmodified. See *Note Tagging
+ the working directory::.
+
+ `-D DATE'
+ Tag revisions as of DATE. See *Note Tagging by date/tag::.
+
+ `-d'
+ Delete TAG. See *Note Modifying tags::.
+
+ `-F'
+ Move TAG if it already exists. See *Note Modifying tags::.
+
+ `-f'
+ Force a head revision match if tag/date not found. See *Note
+ Tagging by date/tag::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Tag the revision already tagged with TAG, or when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. See *Note Tagging by
+ date/tag:: and *Note Common options::.
+
+`unedit [OPTIONS] [FILES...]'
+ Undo an edit command. See *Note Editing files::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+`update [OPTIONS] [FILES...]'
+ Bring work tree in sync with repository. See *Note update::.
+
+ `-A'
+ Reset any sticky tags/date/options. See *Note Sticky tags::
+ and *Note Keyword substitution::.
+
+ `-C'
+ Overwrite locally modified files with clean copies from the
+ repository (the modified file is saved in `.#FILE.REVISION',
+ however).
+
+ `-D DATE'
+ Check out revisions as of DATE (is sticky). See *Note Common
+ options::.
+
+ `-d'
+ Create directories. See *Note update options::.
+
+ `-f'
+ Use head revision if tag/date not found. See *Note Common
+ options::.
+
+ `-I IGN'
+ More files to ignore (! to reset). See *Note import
+ options::.
+
+ `-j TAG[:DATE]'
+ Merge in changes from revisions specified by TAG or, when
+ DATE is specified and TAG is a branch tag, the version from
+ the branch TAG as it existed on DATE. See *Note update
+ options::.
+
+ `-k KFLAG'
+ Use KFLAG keyword expansion. See *Note Substitution modes::.
+
+ `-l'
+ Local; run only in current working directory. *Note
+ Recursive behavior::.
+
+ `-P'
+ Prune empty directories. See *Note Moving directories::.
+
+ `-p'
+ Check out files to standard output (avoids stickiness). See
+ *Note update options::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+ `-r TAG[:DATE]'
+ Checkout the revisions specified by TAG or, when DATE is
+ specified and TAG is a branch tag, the version from the
+ branch TAG as it existed on DATE. See *Note Common options::.
+
+ `-W SPEC'
+ More wrappers. See *Note import options::.
+
+`version'
+ Display the version of CVS being used. If the repository is
+ remote, display both the client and server versions.
+
+`watch [on|off|add|remove] [OPTIONS] [FILES...]'
+ on/off: turn on/off read-only checkouts of files. See *Note
+ Setting a watch::.
+
+ add/remove: add or remove notification on actions. See *Note
+ Getting Notified::.
+
+ `-a ACTIONS'
+ Specify actions for temporary watch, where ACTIONS is `edit',
+ `unedit', `commit', `all', or `none'. See *Note Editing
+ files::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+`watchers [OPTIONS] [FILES...]'
+ See who is watching a file. See *Note Watch information::.
+
+ `-l'
+ Local; run only in current working directory. See *Note
+ Recursive behavior::.
+
+ `-R'
+ Operate recursively (default). *Note Recursive behavior::.
+
+
+
+File: cvs.info, Node: Administrative files, Next: Environment variables, Prev: Invoking CVS, Up: Top
+
+Appendix C Reference manual for Administrative files
+****************************************************
+
+Inside the repository, in the directory `$CVSROOT/CVSROOT', there are a
+number of supportive files for CVS. You can use CVS in a limited
+fashion without any of them, but if they are set up properly they can
+help make life easier. For a discussion of how to edit them, see *Note
+Intro administrative files::.
+
+ The most important of these files is the `modules' file, which
+defines the modules inside the repository.
+
+* Menu:
+
+* modules:: Defining modules
+* Wrappers:: Specify binary-ness based on file name
+* Trigger Scripts:: Launch scripts in response to server events
+* rcsinfo:: Templates for the log messages
+* cvsignore:: Ignoring files via cvsignore
+* checkoutlist:: Adding your own administrative files
+* history file:: History information
+* Variables:: Various variables are expanded
+* config:: Miscellaneous CVS configuration
+
+
+File: cvs.info, Node: modules, Next: Wrappers, Up: Administrative files
+
+C.1 The modules file
+====================
+
+The `modules' file records your definitions of names for collections of
+source code. CVS will use these definitions if you use CVS to update
+the modules file (use normal commands like `add', `commit', etc).
+
+ The `modules' file may contain blank lines and comments (lines
+beginning with `#') as well as module definitions. Long lines can be
+continued on the next line by specifying a backslash (`\') as the last
+character on the line.
+
+ There are three basic types of modules: alias modules, regular
+modules, and ampersand modules. The difference between them is the way
+that they map files in the repository to files in the working
+directory. In all of the following examples, the top-level repository
+contains a directory called `first-dir', which contains two files,
+`file1' and `file2', and a directory `sdir'. `first-dir/sdir' contains
+a file `sfile'.
+
+* Menu:
+
+* Alias modules:: The simplest kind of module
+* Regular modules::
+* Ampersand modules::
+* Excluding directories:: Excluding directories from a module
+* Module options:: Regular and ampersand modules can take options
+* Module program options:: How the modules ``program options'' programs
+ are run.
+
+
+File: cvs.info, Node: Alias modules, Next: Regular modules, Up: modules
+
+C.1.1 Alias modules
+-------------------
+
+Alias modules are the simplest kind of module:
+
+`MNAME -a ALIASES...'
+ This represents the simplest way of defining a module MNAME. The
+ `-a' flags the definition as a simple alias: CVS will treat any
+ use of MNAME (as a command argument) as if the list of names
+ ALIASES had been specified instead. ALIASES may contain either
+ other module names or paths. When you use paths in aliases,
+ `checkout' creates all intermediate directories in the working
+ directory, just as if the path had been specified explicitly in
+ the CVS arguments.
+
+ For example, if the modules file contains:
+
+ amodule -a first-dir
+
+then the following two commands are equivalent:
+
+ $ cvs co amodule
+ $ cvs co first-dir
+
+and they each would provide output such as:
+
+ cvs checkout: Updating first-dir
+ U first-dir/file1
+ U first-dir/file2
+ cvs checkout: Updating first-dir/sdir
+ U first-dir/sdir/sfile
+
+
+File: cvs.info, Node: Regular modules, Next: Ampersand modules, Prev: Alias modules, Up: modules
+
+C.1.2 Regular modules
+---------------------
+
+`MNAME [ options ] DIR [ FILES... ]'
+ In the simplest case, this form of module definition reduces to
+ `MNAME DIR'. This defines all the files in directory DIR as
+ module mname. DIR is a relative path (from `$CVSROOT') to a
+ directory of source in the source repository. In this case, on
+ checkout, a single directory called MNAME is created as a working
+ directory; no intermediate directory levels are used by default,
+ even if DIR was a path involving several directory levels.
+
+ For example, if a module is defined by:
+
+ regmodule first-dir
+
+then regmodule will contain the files from first-dir:
+
+ $ cvs co regmodule
+ cvs checkout: Updating regmodule
+ U regmodule/file1
+ U regmodule/file2
+ cvs checkout: Updating regmodule/sdir
+ U regmodule/sdir/sfile
+ $
+
+ By explicitly specifying files in the module definition after DIR,
+you can select particular files from directory DIR. Here is an example:
+
+ regfiles first-dir/sdir sfile
+
+With this definition, getting the regfiles module will create a single
+working directory `regfiles' containing the file listed, which comes
+from a directory deeper in the CVS source repository:
+
+ $ cvs co regfiles
+ U regfiles/sfile
+ $
+
+
+File: cvs.info, Node: Ampersand modules, Next: Excluding directories, Prev: Regular modules, Up: modules
+
+C.1.3 Ampersand modules
+-----------------------
+
+A module definition can refer to other modules by including `&MODULE'
+in its definition.
+ MNAME [ options ] &MODULE...
+
+ Then getting the module creates a subdirectory for each such module,
+in the directory containing the module. For example, if modules
+contains
+
+ ampermod &first-dir
+
+then a checkout will create an `ampermod' directory which contains a
+directory called `first-dir', which in turns contains all the
+directories and files which live there. For example, the command
+
+ $ cvs co ampermod
+
+will create the following files:
+
+ ampermod/first-dir/file1
+ ampermod/first-dir/file2
+ ampermod/first-dir/sdir/sfile
+
+ There is one quirk/bug: the messages that CVS prints omit the
+`ampermod', and thus do not correctly display the location to which it
+is checking out the files:
+
+ $ cvs co ampermod
+ cvs checkout: Updating first-dir
+ U first-dir/file1
+ U first-dir/file2
+ cvs checkout: Updating first-dir/sdir
+ U first-dir/sdir/sfile
+ $
+
+ Do not rely on this buggy behavior; it may get fixed in a future
+release of CVS.
+
+
+File: cvs.info, Node: Excluding directories, Next: Module options, Prev: Ampersand modules, Up: modules
+
+C.1.4 Excluding directories
+---------------------------
+
+An alias module may exclude particular directories from other modules
+by using an exclamation mark (`!') before the name of each directory to
+be excluded.
+
+ For example, if the modules file contains:
+
+ exmodule -a !first-dir/sdir first-dir
+
+then checking out the module `exmodule' will check out everything in
+`first-dir' except any files in the subdirectory `first-dir/sdir'.
+
+
+File: cvs.info, Node: Module options, Next: Module program options, Prev: Excluding directories, Up: modules
+
+C.1.5 Module options
+--------------------
+
+Either regular modules or ampersand modules can contain options, which
+supply additional information concerning the module.
+
+`-d NAME'
+ Name the working directory something other than the module name.
+
+`-e PROG'
+ Specify a program PROG to run whenever files in a module are
+ exported. PROG runs with a single argument, the module name.
+
+`-o PROG'
+ Specify a program PROG to run whenever files in a module are
+ checked out. PROG runs with a single argument, the module name.
+ See *Note Module program options:: for information on how PROG is
+ called.
+
+`-s STATUS'
+ Assign a status to the module. When the module file is printed
+ with `cvs checkout -s' the modules are sorted according to
+ primarily module status, and secondarily according to the module
+ name. This option has no other meaning. You can use this option
+ for several things besides status: for instance, list the person
+ that is responsible for this module.
+
+`-t PROG'
+ Specify a program PROG to run whenever files in a module are
+ tagged with `rtag'. PROG runs with two arguments: the module name
+ and the symbolic tag specified to `rtag'. It is not run when
+ `tag' is executed. Generally you will find that the `taginfo'
+ file is a better solution (*note taginfo::).
+
+ You should also see *note Module program options:: about how the
+"program options" programs are run.
+
+
+File: cvs.info, Node: Module program options, Prev: Module options, Up: modules
+
+C.1.6 How the modules file "program options" programs are run
+-------------------------------------------------------------
+
+For checkout, rtag, and export, the program is server-based, and as
+such the following applies:-
+
+ If using remote access methods (pserver, ext, etc.), CVS will
+execute this program on the server from a temporary directory. The path
+is searched for this program.
+
+ If using "local access" (on a local or remote NFS file system, i.e.
+repository set just to a path), the program will be executed from the
+newly checked-out tree, if found there, or alternatively searched for
+in the path if not.
+
+ The programs are all run after the operation has effectively
+completed.
+
+
+File: cvs.info, Node: Wrappers, Next: Trigger Scripts, Prev: modules, Up: Administrative files
+
+C.2 The cvswrappers file
+========================
+
+Wrappers refers to a CVS feature which lets you control certain
+settings based on the name of the file which is being operated on. The
+settings are `-k' for binary files, and `-m' for nonmergeable text
+files.
+
+ The `-m' option specifies the merge methodology that should be used
+when a non-binary file is updated. `MERGE' means the usual CVS
+behavior: try to merge the files. `COPY' means that `cvs update' will
+refuse to merge files, as it also does for files specified as binary
+with `-kb' (but if the file is specified as binary, there is no need to
+specify `-m 'COPY''). CVS will provide the user with the two versions
+of the files, and require the user using mechanisms outside CVS, to
+insert any necessary changes.
+
+ *WARNING: do not use `COPY' with CVS 1.9 or earlier - such versions
+of CVS will copy one version of your file over the other, wiping out
+the previous contents.* The `-m' wrapper option only affects behavior
+when merging is done on update; it does not affect how files are
+stored. See *Note Binary files::, for more on binary files.
+
+ The basic format of the file `cvswrappers' is:
+
+ wildcard [option value][option value]...
+
+ where option is one of
+ -m update methodology value: MERGE or COPY
+ -k keyword expansion value: expansion mode
+
+ and value is a single-quote delimited value.
+
+ For example, the following command imports a directory, treating
+files whose name ends in `.exe' as binary:
+
+ cvs import -I ! -W "*.exe -k 'b'" first-dir vendortag reltag
+
+
+File: cvs.info, Node: Trigger Scripts, Next: rcsinfo, Prev: Wrappers, Up: Administrative files
+
+C.3 The Trigger Scripts
+=======================
+
+Several of the administrative files support triggers, or the launching
+external scripts or programs at specific times before or after
+particular events, during the execution of CVS commands. These hooks
+can be used to prevent certain actions, log them, and/or maintain
+anything else you deem practical.
+
+ All the trigger scripts are launched in a copy of the user sandbox
+being committed, on the server, in client-server mode. In local mode,
+the scripts are actually launched directly from the user sandbox
+directory being committed. For most intents and purposes, the same
+scripts can be run in both locations without alteration.
+
+* Menu:
+
+* syntax:: The common syntax
+* Trigger Script Security:: Trigger script security
+
+* commit files:: The commit support files (commitinfo,
+ verifymsg, loginfo)
+* commitinfo:: Pre-commit checking
+* verifymsg:: How are log messages evaluated?
+* loginfo:: Where should log messages be sent?
+
+* postadmin:: Logging admin commands
+* taginfo:: Verifying/Logging tags
+* posttag:: Logging tags
+* postwatch:: Logging watch commands
+
+* preproxy:: Launch a script on a secondary server prior
+ to becoming a write proxy
+* postproxy:: Launch a script on a secondary server after
+ completing proxy operations
+
+
+File: cvs.info, Node: syntax, Next: Trigger Script Security, Up: Trigger Scripts
+
+C.3.1 The common syntax
+-----------------------
+
+The administrative files such as `commitinfo', `loginfo', `rcsinfo',
+`verifymsg', etc., all have a common format. The purpose of the files
+are described later on. The common syntax is described here.
+
+ Each line contains the following:
+
+ * A regular expression or the literal string `DEFAULT'. Some script
+ hooks also support the literal string `ALL'. Other than the `ALL'
+ and `DEFAULT' keywords, this is a basic regular expression in the
+ syntax used by GNU emacs. See the descriptions of the individual
+ script hooks for information on whether the `ALL' keyword is
+ supported (*note Trigger Scripts::).
+
+ * A whitespace separator--one or more spaces and/or tabs.
+
+ * A file name or command-line template.
+
+Blank lines are ignored. Lines that start with the character `#' are
+treated as comments. Long lines unfortunately can _not_ be broken in
+two parts in any way.
+
+ The first regular expression that matches the current directory name
+in the repository or the first line containing `DEFAULT' in lieu of a
+regular expression is used and all lines containing `ALL' is used for
+the hooks which support the `ALL' keyword. The rest of the line is
+used as a file name or command-line template as appropriate. See the
+descriptions of the individual script hooks for information on whether
+the `ALL' keyword is supported (*note Trigger Scripts::).
+
+_Note: The following information on format strings is valid as long as
+the line `UseNewInfoFmtStrings=yes' appears in your repository's config
+file (*note config::). Otherwise, default format strings may be
+appended to the command line and the `loginfo' file, especially, can
+exhibit slightly different behavior. For more information, *Note
+Updating Commit Files::._
+
+ In the cases where the second segment of the matched line is a
+command line template (e.g. `commitinfo', `loginfo', & `verifymsg'),
+the command line template may contain format strings which will be
+replaced with specific values before the script is run.
+
+ Format strings can represent a single variable or one or more
+attributes of a list variable. An example of a list variable would be
+the list available to scripts hung on the loginfo hooks - the list of
+files which were just committed. In the case of loginfo, three
+attributes are available for each list item: file name, precommit
+version, and postcommit version.
+
+ Format strings consist of a `%' character followed by an optional
+`{' (required in the multiple list attribute case), a single format
+character representing a variable or a single attribute of list
+elements or multiple format characters representing attributes of list
+elements, and a closing `}' when the open bracket was present.
+
+ _Flat format strings_, or single format characters which get replaced
+with a single value, will generate a single argument to the called
+script, regardless of whether the replacement variable contains white
+space or other special characters.
+
+ _List attributes_ will generate an argument for each attribute
+requested for each list item. For example, `%{sVv}' in a `loginfo'
+command template will generate three arguments (file name, precommit
+version, postcommit version, ...) for each file committed. As in the
+flat format string case, each attribute will be passed in as a single
+argument regardless of whether it contains white space or other special
+characters.
+
+ `%%' will be replaced with a literal `%'.
+
+ The format strings available to all script hooks are:
+
+c
+ The canonical name of the command being executed. For instance,
+ in the case of a hook run from `cvs up', CVS would replace `%c'
+ with the string `update' and, in the case of a hook run from `cvs
+ ci', CVS would replace `%c' with the string `commit'.
+
+n
+ The null, or empty, string.
+
+p
+ The name of the directory being operated on within the repository.
+
+r
+ The name of the repository (the path portion of `$CVSROOT').
+
+R
+ On a server, the name of the referrer, if any. The referrer is
+ the CVSROOT the client reports it used to contact a server which
+ then referred it to this server. Should usually be set on a
+ primary server with a write proxy setup.
+
+ Other format strings are file specific. See the docs on the
+particular script hooks for more information (*note Trigger Scripts::).
+
+ As an example, the following line in a `loginfo' file would match
+only the directory `module' and any subdirectories of `module':
+
+ ^module\(/\|$\) (echo; echo %p; echo %{sVv}; cat) >>$CVSROOT/CVSROOT/commitlog
+
+ Using this same line and assuming a commit of new revisions 1.5.4.4
+and 1.27.4.1 based on old revisions 1.5.4.3 and 1.27, respectively, of
+file1 and file2 in module, something like the following log message
+should be appended to commitlog:
+
+
+ module
+ file1 1.5.4.3 1.5.4.4 file2 1.27 1.27.4.1
+ Update of /cvsroot/module
+ In directory localhost.localdomain:/home/jrandom/work/module
+
+ Modified Files:
+ file1 file2
+ Log Message:
+ A log message.
+
+
+File: cvs.info, Node: Trigger Script Security, Next: commit files, Prev: syntax, Up: Trigger Scripts
+
+C.3.2 Security and the Trigger Scripts
+--------------------------------------
+
+Security is a huge subject, and implementing a secure system is a
+non-trivial task. This section will barely touch on all the issues
+involved, but it is well to note that, as with any script you will be
+allowing an untrusted user to run on your server, there are measures
+you can take to help prevent your trigger scripts from being abused.
+
+ For instance, since the CVS trigger scripts all run in a copy of the
+user's sandbox on the server, a naively coded Perl trigger script which
+attempts to use a Perl module that is not installed on the system can
+be hijacked by any user with commit access who is checking in a file
+with the correct name. Other scripting languages may be vulnerable to
+similar hacks.
+
+ One way to make a script more secure, at least with Perl, is to use
+scripts which invoke the `-T', or "taint-check" switch on their `#!'
+line. In the most basic terms, this causes Perl to avoid running code
+that may have come from an external source. Please run the `perldoc
+perlsec' command for more on Perl security. Again, other languages may
+implement other security verification hooks which look more or less
+like Perl's "taint-check" mechanism.
+
+
+File: cvs.info, Node: commit files, Next: commitinfo, Prev: Trigger Script Security, Up: Trigger Scripts
+
+C.3.3 The commit support files
+------------------------------
+
+The `-i' flag in the `modules' file can be used to run a certain
+program whenever files are committed (*note modules::). The files
+described in this section provide other, more flexible, ways to run
+programs whenever something is committed.
+
+ There are three kinds of programs that can be run on commit. They
+are specified in files in the repository, as described below. The
+following table summarizes the file names and the purpose of the
+corresponding programs.
+
+`commitinfo'
+ The program is responsible for checking that the commit is
+ allowed. If it exits with a non-zero exit status the commit will
+ be aborted. *Note commitinfo::.
+
+`verifymsg'
+ The specified program is used to evaluate the log message, and
+ possibly verify that it contains all required fields. This is
+ most useful in combination with the `rcsinfo' file, which can hold
+ a log message template (*note rcsinfo::). *Note verifymsg::.
+
+`loginfo'
+ The specified program is called when the commit is complete. It
+ receives the log message and some additional information and can
+ store the log message in a file, or mail it to appropriate
+ persons, or maybe post it to a local newsgroup, or... Your
+ imagination is the limit! *Note loginfo::.
+
+* Menu:
+
+* Updating Commit Files:: Updating legacy repositories to stop using
+ deprecated command line template formats
+
+
+File: cvs.info, Node: Updating Commit Files, Up: commit files
+
+C.3.3.1 Updating legacy repositories to stop using deprecated command line template formats
+...........................................................................................
+
+New repositories are created set to use the new format strings by
+default, so if you are creating a new repository, you shouldn't have to
+worry about this section.
+
+ If you are attempting to maintain a legacy repository which was
+making use of the `commitinfo', `editinfo', `verifymsg', `loginfo',
+and/or `taginfo' script hooks, you should have no immediate problems
+with using the current CVS executable, but your users will probably
+start to see deprecation warnings.
+
+ The reason for this is that all of the script hooks have been
+updated to use a new command line parser that extensibly supports
+multiple `loginfo' & `notify' style format strings (*note syntax::) and
+this support is not completely compatible with the old style format
+strings.
+
+ The quick upgrade method is to stick a `1' after each format string
+in your old `loginfo' file. For example:
+
+ DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
+
+ would become:
+
+ DEFAULT (echo ""; id; echo %1{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
+
+ If you were counting on the fact that only the first `%' in the line
+was replaced as a format string, you may also have to double up any
+further percent signs on the line.
+
+ If you did this all at once and checked it in, everything should
+still be running properly.
+
+ Now add the following line to your config file (*note config::):
+ UseNewInfoFmtStrings=yes
+
+ Everything should still be running properly, but your users will
+probably start seeing new deprecation warnings.
+
+ Dealing with the deprecation warnings now generated by `commitinfo',
+`editinfo', `verifymsg', and `taginfo' should be easy. Simply specify
+what are currently implicit arguments explicitly. This means appending
+the following strings to each active command line template in each file:
+`commitinfo'
+ ` %r/%p %s'
+
+`editinfo'
+ ` %l'
+
+`taginfo'
+ ` %t %o %p %{sv}'
+
+`verifymsg'
+ ` %l'
+
+ If you don't desire that any of the newly available information be
+passed to the scripts hanging off of these hooks, no further
+modifications to these files should be necessary to insure current and
+future compatibility with CVS's format strings.
+
+ Fixing `loginfo' could be a little tougher. The old style `loginfo'
+format strings caused a single space and comma separated argument to be
+passed in in place of the format string. This is what will continue to
+be generated due to the deprecated `1' you inserted into the format
+strings.
+
+ Since the new format separates each individual item and passes it
+into the script as a separate argument (for a good reason - arguments
+containing commas and/or white space are now parsable), to remove the
+deprecated `1' from your `loginfo' command line templates, you will
+most likely have to rewrite any scripts called by the hook to handle
+the new argument format.
+
+ Also note that the way `%' followed by unrecognized characters and by
+`{}' was treated in past versions of CVS is not strictly adhered to as
+there were bugs in the old versions. Specifically, `%{}' would eat the
+next character and unrecognized strings resolved only to the empty
+string, which was counter to what was stated in the documentation.
+This version will do what the documentation said it should have (if you
+were using only some combination of `%{sVv}', e.g. `%{sVv}', `%{sV}', or
+`%v', you should have no troubles).
+
+ On the bright side, you should have plenty of time to do this before
+all support for the old format strings is removed from CVS, so you can
+just put up with the deprecation warnings for awhile if you like.
+
+
+File: cvs.info, Node: commitinfo, Next: verifymsg, Prev: commit files, Up: Trigger Scripts
+
+C.3.4 Commitinfo
+----------------
+
+The `commitinfo' file defines programs to execute whenever `cvs commit'
+is about to execute. These programs are used for pre-commit checking
+to verify that the modified, added and removed files are really ready
+to be committed. This could be used, for instance, to verify that the
+changed files conform to to your site's standards for coding practice.
+
+ The `commitinfo' file has the standard form for script hooks (*note
+Trigger Scripts::), where each line is a regular expression followed by
+a command to execute. It supports only the DEFAULT keywords.
+
+ In addition to the common format strings (*note syntax::),
+`commitinfo' supports:
+
+{s}
+ a list of the names of files to be committed
+
+ Currently, if no format strings are specified, a default string of `
+%r/%p %{s}' will be appended to the command line template before
+replacement is performed, but this feature is deprecated. It is simply
+in place so that legacy repositories will remain compatible with the
+new CVS application. For information on updating, *note Updating
+Commit Files::.
+
+ The first line with a regular expression matching the directory
+within the repository will be used. If the command returns a non-zero
+exit status the commit will be aborted.
+
+ The command will be run in the root of the workspace containing the
+new versions of any files the user would like to modify (commit), _or
+in a copy of the workspace on the server (*note Remote
+repositories::)_. If a file is being removed, there will be no copy of
+the file under the current directory. If a file is being added, there
+will be no corresponding archive file in the repository unless the file
+is being resurrected.
+
+ Note that both the repository directory and the corresponding Attic
+(*note Attic::) directory may need to be checked to locate the archive
+file corresponding to any given file being committed. Much of the
+information about the specific commit request being made, including the
+destination branch, commit message, and command line options specified,
+is not available to the command.
+
+
+File: cvs.info, Node: verifymsg, Next: loginfo, Prev: commitinfo, Up: Trigger Scripts
+
+C.3.5 Verifying log messages
+----------------------------
+
+Once you have entered a log message, you can evaluate that message to
+check for specific content, such as a bug ID. Use the `verifymsg' file
+to specify a program that is used to verify the log message. This
+program could be a simple script that checks that the entered message
+contains the required fields.
+
+ The `verifymsg' file is often most useful together with the
+`rcsinfo' file, which can be used to specify a log message template
+(*note rcsinfo::).
+
+ The `verifymsg' file has the standard form for script hooks (*note
+Trigger Scripts::), where each line is a regular expression followed by
+a command to execute. It supports only the DEFAULT keywords.
+
+ In addition to the common format strings (*note syntax::),
+`verifymsg' supports:
+
+l
+ the full path to the file containing the log message to be verified
+
+{sV}
+ File attributes, where:
+ s
+ file name
+
+ V
+ old version number (pre-checkin)
+
+ Currently, if no format strings are specified, a default string of `
+%l' will be appended to the command line template before replacement is
+performed, but this feature is deprecated. It is simply in place so
+that legacy repositories will remain compatible with the new CVS
+application. For information on updating, *note Updating Commit
+Files::.
+
+ One thing that should be noted is that the `ALL' keyword is not
+supported. If more than one matching line is found, the first one is
+used. This can be useful for specifying a default verification script
+in a directory, and then overriding it in a subdirectory.
+
+ If the verification script exits with a non-zero exit status, the
+commit is aborted.
+
+ In the default configuration, CVS allows the verification script to
+change the log message. This is controlled via the RereadLogAfterVerify
+CVSROOT/config option.
+
+ When `RereadLogAfterVerify=always' or `RereadLogAfterVerify=stat',
+the log message will either always be reread after the verification
+script is run or reread only if the log message file status has changed.
+
+ *Note config::, for more on CVSROOT/config options.
+
+ It is NOT a good idea for a `verifymsg' script to interact directly
+with the user in the various client/server methods. For the `pserver'
+method, there is no protocol support for communicating between
+`verifymsg' and the client on the remote end. For the `ext' and
+`server' methods, it is possible for CVS to become confused by the
+characters going along the same channel as the CVS protocol messages.
+See *Note Remote repositories::, for more information on client/server
+setups. In addition, at the time the `verifymsg' script runs, the CVS
+server has locks in place in the repository. If control is returned to
+the user here then other users may be stuck waiting for access to the
+repository.
+
+ This option can be useful if you find yourself using an rcstemplate
+that needs to be modified to remove empty elements or to fill in
+default values. It can also be useful if the rcstemplate has changed
+in the repository and the CVS/Template was not updated, but is able to
+be adapted to the new format by the verification script that is run by
+`verifymsg'.
+
+ An example of an update might be to change all occurrences of
+'BugId:' to be 'DefectId:' (which can be useful if the rcstemplate has
+recently been changed and there are still checked-out user trees with
+cached copies in the CVS/Template file of the older version).
+
+ Another example of an update might be to delete a line that contains
+'BugID: none' from the log message after validation of that value as
+being allowed is made.
+
+* Menu:
+
+* verifymsg example:: Verifymsg example
+
+
+File: cvs.info, Node: verifymsg example, Up: verifymsg
+
+C.3.5.1 Verifying log messages
+..............................
+
+The following is a little silly example of a `verifymsg' file, together
+with the corresponding `rcsinfo' file, the log message template and a
+verification script. We begin with the log message template. We want
+to always record a bug-id number on the first line of the log message.
+The rest of log message is free text. The following template is found
+in the file `/usr/cvssupport/tc.template'.
+
+ BugId:
+
+ The script `/usr/cvssupport/bugid.verify' is used to evaluate the
+log message.
+
+ #!/bin/sh
+ #
+ # bugid.verify filename
+ #
+ # Verify that the log message contains a valid bugid
+ # on the first line.
+ #
+ if sed 1q < $1 | grep '^BugId:[ ]*[0-9][0-9]*$' > /dev/null; then
+ exit 0
+ elif sed 1q < $1 | grep '^BugId:[ ]*none$' > /dev/null; then
+ # It is okay to allow commits with 'BugId: none',
+ # but do not put that text into the real log message.
+ grep -v '^BugId:[ ]*none$' > $1.rewrite
+ mv $1.rewrite $1
+ exit 0
+ else
+ echo "No BugId found."
+ exit 1
+ fi
+
+ The `verifymsg' file contains this line:
+
+ ^tc /usr/cvssupport/bugid.verify %l
+
+ The `rcsinfo' file contains this line:
+
+ ^tc /usr/cvssupport/tc.template
+
+ The `config' file contains this line:
+
+ RereadLogAfterVerify=always
+
+
+File: cvs.info, Node: loginfo, Next: postadmin, Prev: verifymsg, Up: Trigger Scripts
+
+C.3.6 Loginfo
+-------------
+
+The `loginfo' file is used to control where log information is sent
+after versioned changes are made to repository archive files and after
+directories are added ot the repository. *Note posttag:: for how to
+log tagging information and *Note postadmin:: for how to log changes
+due to the `admin' command.
+
+ The `loginfo' file has the standard form for script hooks (*note
+Trigger Scripts::), where each line is a regular expression followed by
+a command to execute. It supports the ALL and DEFAULT keywords.
+
+ Any specified scripts are called:
+
+`commit'
+ Once per directory, immediately after a successfully completing
+ the commit of all files within that directory.
+
+`import'
+ Once per import, immediately after completion of all write
+ operations.
+
+`add'
+ Immediately after the successful `add' of a directory.
+
+ Any script called via `loginfo' will be fed the log information on
+its standard input. Note that the filter program *must* read *all* of
+the log information from its standard input or CVS may fail with a
+broken pipe signal.
+
+ In addition to the common format strings (*note syntax::), `loginfo'
+supports:
+
+{stVv}
+ File attributes, where:
+ s
+ file name
+
+ T
+ tag name of destination, or the empty string when there is no
+ associated tag name (this usually means the trunk)
+
+ V
+ old version number (pre-checkin)
+
+ v
+ new version number (post-checkin)
+
+ For example, some valid format strings are `%%', `%s', `%{s}', and
+`%{stVv}'.
+
+ Currently, if `UseNewInfoFmtStrings' is not set in the `config'
+administration file (*note config::), the format strings will be
+substituted as they were in past versions of CVS, but this feature is
+deprecated. It is simply in place so that legacy repositories will
+remain compatible with the new CVS application. For information on
+updating, please see *Note Updating Commit Files::.
+
+ As an example, if `/u/src/master/yoyodyne/tc' is the repository, `%p'
+and `%{sVv}' are the format strings, and three files (ChangeLog,
+Makefile, foo.c) were modified, the output might be:
+
+ yoyodyne/tc ChangeLog 1.1 1.2 Makefile 1.3 1.4 foo.c 1.12 1.13
+
+ Note: when CVS is accessing a remote repository, `loginfo' will be
+run on the _remote_ (i.e., server) side, not the client side (*note
+Remote repositories::).
+
+* Menu:
+
+* loginfo example:: Loginfo example
+* Keeping a checked out copy:: Updating a tree on every checkin
+
+
+File: cvs.info, Node: loginfo example, Next: Keeping a checked out copy, Up: loginfo
+
+C.3.6.1 Loginfo example
+.......................
+
+The following `loginfo' file, together with the tiny shell-script
+below, appends all log messages to the file
+`$CVSROOT/CVSROOT/commitlog', and any commits to the administrative
+files (inside the `CVSROOT' directory) are also logged in
+`/usr/adm/cvsroot-log'. Commits to the `prog1' directory are mailed to
+ceder.
+
+ ALL /usr/local/bin/cvs-log $CVSROOT/CVSROOT/commitlog $USER
+ ^CVSROOT\(/\|$\) /usr/local/bin/cvs-log /usr/adm/cvsroot-log $USER
+ ^prog1\(/\|$\) Mail -s "%p %s" ceder
+
+ The shell-script `/usr/local/bin/cvs-log' looks like this:
+
+ #!/bin/sh
+ (echo "------------------------------------------------------";
+ echo -n "$2 ";
+ date;
+ echo;
+ cat) >> $1
+
+
+File: cvs.info, Node: Keeping a checked out copy, Prev: loginfo example, Up: loginfo
+
+C.3.6.2 Keeping a checked out copy
+..................................
+
+It is often useful to maintain a directory tree which contains files
+which correspond to the latest version in the repository. For example,
+other developers might want to refer to the latest sources without
+having to check them out, or you might be maintaining a web site with
+CVS and want every checkin to cause the files used by the web server to
+be updated.
+
+ The way to do this is by having loginfo invoke `cvs update'. Doing
+so in the naive way will cause a problem with locks, so the `cvs update'
+must be run in the background. Here is an example for unix (this
+should all be on one line):
+
+ ^cyclic-pages\(/\|$\) (date; cat; (sleep 2; cd /u/www/local-docs;
+ cvs -q update -d) &) >> $CVSROOT/CVSROOT/updatelog 2>&1
+
+ This will cause checkins to repository directory `cyclic-pages' and
+its subdirectories to update the checked out tree in
+`/u/www/local-docs'.
+
+
+File: cvs.info, Node: postadmin, Next: taginfo, Prev: loginfo, Up: Trigger Scripts
+
+C.3.7 Logging admin commands
+----------------------------
+
+The `postadmin' file defines programs to execute after an `admin'
+command modifies files. The `postadmin' file has the standard form for
+script hooks (*note Trigger Scripts::), where each line is a regular
+expression followed by a command to execute. It supports the ALL and
+DEFAULT keywords.
+
+ The `postadmin' file supports no format strings other than the common
+ones (*note syntax::),
+
+
+File: cvs.info, Node: taginfo, Next: posttag, Prev: postadmin, Up: Trigger Scripts
+
+C.3.8 Taginfo
+-------------
+
+The `taginfo' file defines programs to execute when someone executes a
+`tag' or `rtag' command. The `taginfo' file has the standard form for
+script hooks (*note Trigger Scripts::), where each line is a regular
+expression followed by a command to execute. It supports the ALL and
+DEFAULT keywords.
+
+ In addition to the common format strings (*note syntax::), `taginfo'
+supports:
+
+b
+ tag type (`T' for branch, `N' for not-branch, or `?' for unknown,
+ as during delete operations)
+
+o
+ operation (`add' for `tag', `mov' for `tag -F', or `del' for `tag
+ -d')
+
+t
+ new tag name
+
+{sTVv}
+ file attributes, where:
+ s
+ file name
+
+ T
+ tag name of destination, or the empty string when there is no
+ associated tag name (this usually means the trunk)
+
+ V
+ old version number (for a move or delete operation)
+
+ v
+ new version number (for an add or move operation)
+
+ For example, some valid format strings are `%%', `%p', `%t', `%s',
+`%{s}', and `%{sVv}'.
+
+ Currently, if no format strings are specified, a default string of `
+%t %o %p %{sv}' will be appended to the command line template before
+replacement is performed, but this feature is deprecated. It is simply
+in place so that legacy repositories will remain compatible with the
+new CVS application. For information on updating, *note Updating
+Commit Files::.
+
+ A non-zero exit of the filter program will cause the tag to be
+aborted.
+
+ Here is an example of using `taginfo' to log `tag' and `rtag'
+commands. In the `taginfo' file put:
+
+ ALL /usr/local/cvsroot/CVSROOT/loggit %t %b %o %p %{sVv}
+
+Where `/usr/local/cvsroot/CVSROOT/loggit' contains the following script:
+
+ #!/bin/sh
+ echo "$@" >>/home/kingdon/cvsroot/CVSROOT/taglog
+
+
+File: cvs.info, Node: posttag, Next: postwatch, Prev: taginfo, Up: Trigger Scripts
+
+C.3.9 Logging tags
+------------------
+
+The `posttag' file defines programs to execute after a `tag' or `rtag'
+command modifies files. The `posttag' file has the standard form for
+script hooks (*note Trigger Scripts::), where each line is a regular
+expression followed by a command to execute. It supports the ALL and
+DEFAULT keywords.
+
+ The `posttag' admin file supports the same format strings as the
+`taginfo' file (*note taginfo::),
+
+
+File: cvs.info, Node: postwatch, Next: preproxy, Prev: posttag, Up: Trigger Scripts
+
+C.3.10 Logging watch commands
+-----------------------------
+
+The `postwatch' file defines programs to execute after any command (for
+instance, `watch', `edit', `unedit', or `commit') modifies any
+`CVS/fileattr' file in the repository (*note Watches::). The
+`postwatch' file has the standard form for script hooks (*note Trigger
+Scripts::), where each line is a regular expression followed by a
+command to execute. It supports the ALL and DEFAULT keywords.
+
+ The `postwatch' file supports no format strings other than the common
+ones (*note syntax::), but it is worth noting that the `%c' format
+string may not be replaced as you might expect. Client runs of `edit'
+and `unedit' can sometimes skip contacting the CVS server and cache the
+notification of the file attribute change to be sent the next time the
+client contacts the server for whatever other reason,
+
+
+File: cvs.info, Node: preproxy, Next: postproxy, Prev: postwatch, Up: Trigger Scripts
+
+C.3.11 Launch a Script before Proxying
+--------------------------------------
+
+The `preproxy' file defines programs to execute after a secondary
+server receives a write request from a client, just before it starts up
+the primary server and becomes a write proxy. This hook could be used
+to dial a modem, launch an SSH tunnel, establish a VPN, or anything
+else that might be necessary to do before contacting the primary server.
+
+ `preproxy' scripts are called once, at the time of the write
+request, with the repository argument (if requested) set from the
+topmost directory sent by the client.
+
+ The `preproxy' file has the standard form for script hooks (*note
+Trigger Scripts::), where each line is a regular expression followed by
+a command to execute. It supports the ALL and DEFAULT keywords.
+
+ In addition to the common format strings, the `preproxy' file
+supports the following format string:
+
+P
+ the CVSROOT string which specifies the primary server
+
+
+File: cvs.info, Node: postproxy, Prev: preproxy, Up: Trigger Scripts
+
+C.3.12 Launch a Script after Proxying
+-------------------------------------
+
+The `postproxy' file defines programs to execute after a secondary
+server notes that the connection to the primary server has shut down
+and before it releases the client by shutting down the connection to
+the client. This could hook could be used to disconnect a modem, an
+SSH tunnel, a VPN, or anything else that might be necessary to do after
+contacting the primary server. This hook should also be used to pull
+updates from the primary server before allowing the client which did
+the write to disconnect since otherwise the client's next read request
+may generate error messages and fail upon encountering an out of date
+repository on the secondary server.
+
+ `postproxy' scripts are called once per directory.
+
+ The `postproxy' file has the standard form for script hooks (*note
+Trigger Scripts::), where each line is a regular expression followed by
+a command to execute. It supports the ALL and DEFAULT keywords.
+
+ In addition to the common format strings, the `postproxy' file
+supports the following format string:
+
+P
+ the CVSROOT string which specifies the primary server
+
+
+File: cvs.info, Node: rcsinfo, Next: cvsignore, Prev: Trigger Scripts, Up: Administrative files
+
+C.4 Rcsinfo
+===========
+
+The `rcsinfo' file can be used to specify a form to edit when filling
+out the commit log. The `rcsinfo' file has a syntax similar to the
+`verifymsg', `commitinfo' and `loginfo' files. *Note syntax::. Unlike
+the other files the second part is _not_ a command-line template.
+Instead, the part after the regular expression should be a full
+pathname to a file containing the log message template.
+
+ If the repository name does not match any of the regular expressions
+in this file, the `DEFAULT' line is used, if it is specified.
+
+ All occurrences of the name `ALL' appearing as a regular expression
+are used in addition to the first matching regular expression or
+`DEFAULT'.
+
+ The log message template will be used as a default log message. If
+you specify a log message with `cvs commit -m MESSAGE' or `cvs commit -f
+FILE' that log message will override the template.
+
+ *Note verifymsg::, for an example `rcsinfo' file.
+
+ When CVS is accessing a remote repository, the contents of `rcsinfo'
+at the time a directory is first checked out will specify a template.
+This template will be updated on all `cvs update' commands. It will
+also be added to new directories added with a `cvs add new-directory'
+command. In versions of CVS prior to version 1.12, the `CVS/Template'
+file was not updated. If the CVS server is at version 1.12 or higher an
+older client may be used and the `CVS/Template' will be updated from
+the server.
+
+
+File: cvs.info, Node: cvsignore, Next: checkoutlist, Prev: rcsinfo, Up: Administrative files
+
+C.5 Ignoring files via cvsignore
+================================
+
+There are certain file names that frequently occur inside your working
+copy, but that you don't want to put under CVS control. Examples are
+all the object files that you get while you compile your sources.
+Normally, when you run `cvs update', it prints a line for each file it
+encounters that it doesn't know about (*note update output::).
+
+ CVS has a list of files (or sh(1) file name patterns) that it should
+ignore while running `update', `import' and `release'. This list is
+constructed in the following way.
+
+ * The list is initialized to include certain file name patterns:
+ names associated with CVS administration, or with other common
+ source control systems; common names for patch files, object files,
+ archive files, and editor backup files; and other names that are
+ usually artifacts of assorted utilities. Currently, the default
+ list of ignored file name patterns is:
+
+ RCS SCCS CVS CVS.adm
+ RCSLOG cvslog.*
+ tags TAGS
+ .make.state .nse_depinfo
+ *~ #* .#* ,* _$* *$
+ *.old *.bak *.BAK *.orig *.rej .del-*
+ *.a *.olb *.o *.obj *.so *.exe
+ *.Z *.elc *.ln
+ core
+
+ * The per-repository list in `$CVSROOT/CVSROOT/cvsignore' is
+ appended to the list, if that file exists.
+
+ * The per-user list in `.cvsignore' in your home directory is
+ appended to the list, if it exists.
+
+ * Any entries in the environment variable `$CVSIGNORE' is appended
+ to the list.
+
+ * Any `-I' options given to CVS is appended.
+
+ * As CVS traverses through your directories, the contents of any
+ `.cvsignore' will be appended to the list. The patterns found in
+ `.cvsignore' are only valid for the directory that contains them,
+ not for any sub-directories.
+
+ In any of the 5 places listed above, a single exclamation mark (`!')
+clears the ignore list. This can be used if you want to store any file
+which normally is ignored by CVS.
+
+ Specifying `-I !' to `cvs import' will import everything, which is
+generally what you want to do if you are importing files from a
+pristine distribution or any other source which is known to not contain
+any extraneous files. However, looking at the rules above you will see
+there is a fly in the ointment; if the distribution contains any
+`.cvsignore' files, then the patterns from those files will be
+processed even if `-I !' is specified. The only workaround is to
+remove the `.cvsignore' files in order to do the import. Because this
+is awkward, in the future `-I !' might be modified to override
+`.cvsignore' files in each directory.
+
+ Note that the syntax of the ignore files consists of a series of
+lines, each of which contains a space separated list of filenames.
+This offers no clean way to specify filenames which contain spaces, but
+you can use a workaround like `foo?bar' to match a file named `foo bar'
+(it also matches `fooxbar' and the like). Also note that there is
+currently no way to specify comments.
+
+
+File: cvs.info, Node: checkoutlist, Next: history file, Prev: cvsignore, Up: Administrative files
+
+C.6 The checkoutlist file
+=========================
+
+It may be helpful to use CVS to maintain your own files in the
+`CVSROOT' directory. For example, suppose that you have a script
+`logcommit.pl' which you run by including the following line in the
+`commitinfo' administrative file:
+
+ ALL $CVSROOT/CVSROOT/logcommit.pl %r/%p %s
+
+ To maintain `logcommit.pl' with CVS you would add the following line
+to the `checkoutlist' administrative file:
+
+ logcommit.pl
+
+ The format of `checkoutlist' is one line for each file that you want
+to maintain using CVS, giving the name of the file, followed optionally
+by more whitespace and any error message that should print if the file
+cannot be checked out into CVSROOT after a commit:
+
+ logcommit.pl Could not update CVSROOT/logcommit.pl.
+
+ After setting up `checkoutlist' in this fashion, the files listed
+there will function just like CVS's built-in administrative files. For
+example, when checking in one of the files you should get a message
+such as:
+
+ cvs commit: Rebuilding administrative file database
+
+and the checked out copy in the `CVSROOT' directory should be updated.
+
+ Note that listing `passwd' (*note Password authentication server::)
+in `checkoutlist' is not recommended for security reasons.
+
+ For information about keeping a checkout out copy in a more general
+context than the one provided by `checkoutlist', see *Note Keeping a
+checked out copy::.
+
+
+File: cvs.info, Node: history file, Next: Variables, Prev: checkoutlist, Up: Administrative files
+
+C.7 The history file
+====================
+
+By default, the file `$CVSROOT/CVSROOT/history' is used to log
+information for the `history' command (*note history::). This file
+name may be changed with the `HistoryLogPath' and `HistorySearchPath'
+config options (*note config::).
+
+ The file format of the `history' file is documented only in comments
+in the CVS source code, but generally programs should use the `cvs
+history' command to access it anyway, in case the format changes with
+future releases of CVS.
+
+
+File: cvs.info, Node: Variables, Next: config, Prev: history file, Up: Administrative files
+
+C.8 Expansions in administrative files
+======================================
+
+Sometimes in writing an administrative file, you might want the file to
+be able to know various things based on environment CVS is running in.
+There are several mechanisms to do that.
+
+ To find the home directory of the user running CVS (from the `HOME'
+environment variable), use `~' followed by `/' or the end of the line.
+Likewise for the home directory of USER, use `~USER'. These variables
+are expanded on the server machine, and don't get any reasonable
+expansion if pserver (*note Password authenticated::) is in use;
+therefore user variables (see below) may be a better choice to
+customize behavior based on the user running CVS.
+
+ One may want to know about various pieces of information internal to
+CVS. A CVS internal variable has the syntax `${VARIABLE}', where
+VARIABLE starts with a letter and consists of alphanumeric characters
+and `_'. If the character following VARIABLE is a non-alphanumeric
+character other than `_', the `{' and `}' can be omitted. The CVS
+internal variables are:
+
+`CVSROOT'
+ This is the absolute path to the current CVS root directory.
+ *Note Repository::, for a description of the various ways to
+ specify this, but note that the internal variable contains just
+ the directory and not any of the access method information.
+
+`RCSBIN'
+ In CVS 1.9.18 and older, this specified the directory where CVS
+ was looking for RCS programs. Because CVS no longer runs RCS
+ programs, specifying this internal variable is now an error.
+
+`CVSEDITOR'
+`EDITOR'
+`VISUAL'
+ These all expand to the same value, which is the editor that CVS
+ is using. *Note Global options::, for how to specify this.
+
+`USER'
+ Username of the user running CVS (on the CVS server machine).
+ When using pserver, this is the user specified in the repository
+ specification which need not be the same as the username the
+ server is running as (*note Password authentication server::). Do
+ not confuse this with the environment variable of the same name.
+
+`SESSIONID'
+ Unique Session ID of the CVS process. This is a random string of
+ printable characters of at least 16 characters length. Users
+ should assume that it may someday grow to at most 256 characters
+ in length.
+
+`COMMITID'
+ Unique Session ID of the CVS process. This is a random string of
+ printable characters of at least 16 characters length. Users
+ should assume that it may someday grow to at most 256 characters
+ in length.
+
+ If you want to pass a value to the administrative files which the
+user who is running CVS can specify, use a user variable. To expand a
+user variable, the administrative file contains `${=VARIABLE}'. To set
+a user variable, specify the global option `-s' to CVS, with argument
+`VARIABLE=VALUE'. It may be particularly useful to specify this option
+via `.cvsrc' (*note ~/.cvsrc::).
+
+ For example, if you want the administrative file to refer to a test
+directory you might create a user variable `TESTDIR'. Then if CVS is
+invoked as
+
+ cvs -s TESTDIR=/work/local/tests
+
+and the administrative file contains `sh ${=TESTDIR}/runtests', then
+that string is expanded to `sh /work/local/tests/runtests'.
+
+ All other strings containing `$' are reserved; there is no way to
+quote a `$' character so that `$' represents itself.
+
+ Environment variables passed to administrative files are:
+
+`CVS_USER'
+ The CVS-specific username provided by the user, if it can be
+ provided (currently just for the pserver access method), and to
+ the empty string otherwise. (`CVS_USER' and `USER' may differ
+ when `$CVSROOT/CVSROOT/passwd' is used to map CVS usernames to
+ system usernames.)
+
+`LOGNAME'
+ The username of the system user.
+
+`USER'
+ Same as `LOGNAME'. Do not confuse this with the internal variable
+ of the same name.
+
+
+File: cvs.info, Node: config, Prev: Variables, Up: Administrative files
+
+C.9 The CVSROOT/config configuration file
+=========================================
+
+Usually, the `config' file is found at `$CVSROOT/CVSROOT/config', but
+this may be overridden on the `pserver' and `server' command lines
+(*note server & pserver::).
+
+ The administrative file `config' contains various miscellaneous
+settings which affect the behavior of CVS. The syntax is slightly
+different from the other administrative files.
+
+ Leading white space on any line is ignored, though the syntax is
+very strict and will reject spaces and tabs almost anywhere else.
+
+ Empty lines, lines containing nothing but white space, and lines
+which start with `#' (discounting any leading white space) are ignored.
+
+ Other lines consist of the optional leading white space, a keyword,
+`=', and a value. Please note again that this syntax is very strict.
+Extraneous spaces or tabs, other than the leading white space, are not
+permitted on these lines.
+
+ As of CVS 1.12.13, lines of the form `[CVSROOT]' mark the subsequent
+section of the config file as applying only to certain repositories.
+Multiple `[CVSROOT]' lines without intervening `KEYWORD=VALUE' pairs
+cause processing to fall through, processing subsequent keywords for
+any root in the list. Finally, keywords and values which appear before
+any `[CVSROOT]' lines are defaults, and may to apply to any repository.
+For example, consider the following file:
+
+ # Defaults
+ LogHistory=TMAR
+
+ [/cvsroots/team1]
+ LockDir=/locks/team1
+
+ [/cvsroots/team2]
+ LockDir=/locks/team2
+
+ [/cvsroots/team3]
+ LockDir=/locks/team3
+
+ [/cvsroots/team4]
+ LockDir=/locks/team4
+
+ [/cvsroots/team3]
+ [/cvsroots/team4]
+ # Override logged commands for teams 3 & 4.
+ LogHistory=all
+
+ This example file sets up separate lock directories for each
+project, as well as a default set of logged commands overridden for the
+example's team 3 & team 4. This syntax could be useful, for instance,
+if you wished to share a single config file, for instance
+`/etc/cvs.conf', among several repositories.
+
+ Currently defined keywords are:
+
+`HistorySearchPath=PATTERN'
+ Request that CVS look for its history information in files matching
+ PATTERN, which is a standard UNIX file glob. If PATTERN matches
+ multiple files, all will be searched in lexicographically sorted
+ order. *Note history::, and *Note history file::, for more.
+
+ If no value is supplied for this option, it defaults to
+ `$CVSROOT/CVSROOT/history'.
+
+`HistoryLogPath=PATH'
+ Control where CVS logs its history. If the file does not exist,
+ CVS will attempt to create it. Format strings, as available to
+ the GNU C `strftime' function and often the UNIX date command, and
+ the string $CVSROOT will be substituted in this path. For
+ example, consider the line:
+
+ HistoryLogPath=$CVSROOT/CVSROOT/history/%Y-%m-%d
+
+ This line would cause CVS to attempt to create its history file in
+ a subdirectory (`history') of the configuration directory
+ (`CVSROOT') with a name equal to the current date representation
+ in the ISO8601 format (for example, on May 11, 2005, CVS would
+ attempt to log its history under the repository root directory in
+ a file named `CVSROOT/history/2005-05-11'). *Note history::, and
+ *Note history file::, for more.
+
+ If no value is supplied for this option, it defaults to
+ `$CVSROOT/CVSROOT/history'.
+
+`ImportNewFilesToVendorBranchOnly=VALUE'
+ Specify whether `cvs import' should always behave as if the `-X'
+ flag was specified on the command line. VALUE may be either `yes'
+ or `no'. If set to `yes', all uses of `cvs import' on the
+ repository will behave as if the `-X' flag was set. The default
+ value is `no'.
+
+`KeywordExpand=VALUE'
+ Specify `i' followed by a list of keywords to be expanded (for
+ example, `KeywordExpand=iMYCVS,Name,Date'), or `e' followed by a
+ list of keywords not to be expanded (for example,
+ `KeywordExpand=eCVSHeader'). For more on keyword expansion, see
+ *Note Configuring keyword expansion::.
+
+`LocalKeyword=VALUE'
+ Specify a local alias for a standard keyword. For example,
+ `LocalKeyword=MYCVS=CVSHeader'. For more on local keywords, see
+ *Note Keyword substitution::.
+
+`LockDir=DIRECTORY'
+ Put CVS lock files in DIRECTORY rather than directly in the
+ repository. This is useful if you want to let users read from the
+ repository while giving them write access only to DIRECTORY, not
+ to the repository. It can also be used to put the locks on a very
+ fast in-memory file system to speed up locking and unlocking the
+ repository. You need to create DIRECTORY, but CVS will create
+ subdirectories of DIRECTORY as it needs them. For information on
+ CVS locks, see *Note Concurrency::.
+
+ Before enabling the LockDir option, make sure that you have
+ tracked down and removed any copies of CVS 1.9 or older. Such
+ versions neither support LockDir, nor will give an error
+ indicating that they don't support it. The result, if this is
+ allowed to happen, is that some CVS users will put the locks one
+ place, and others will put them another place, and therefore the
+ repository could become corrupted. CVS 1.10 does not support
+ LockDir but it will print a warning if run on a repository with
+ LockDir enabled.
+
+`LogHistory=VALUE'
+ Control what is logged to the `CVSROOT/history' file (*note
+ history::). Default of `TOEFWUPCGMAR' (or simply `all') will log
+ all transactions. Any subset of the default is legal. (For
+ example, to only log transactions that modify the `*,v' files, use
+ `LogHistory=TMAR'.) To disable history logging completely, use
+ `LogHistory='.
+
+`MaxCommentLeaderLength=LENGTH'
+ Set to some length, in bytes, where a trailing `k', `M', `G', or
+ `T' causes the preceding nubmer to be interpreted as kilobytes,
+ megabytes, gigabytes, or terrabytes, respectively, will cause
+ `$Log$' keywords (*note Keyword substitution::), with more than
+ LENGTH bytes preceding it on a line to be ignored (or to fall back
+ on the comment leader set in the RCS archive file - see
+ `UseArchiveCommentLeader' below). Defaults to 20 bytes to allow
+ checkouts to proceed normally when they include binary files
+ containing `$Log$' keywords and which users have neglected to mark
+ as binary.
+
+`MinCompressionLevel=VALUE'
+`MaxCompressionLevel=VALUE'
+ Restricts the level of compression used by the CVS server to a
+ VALUE between 0 and 9. VALUEs 1 through 9 are the same ZLIB
+ compression levels accepted by the `-z' option (*note Global
+ options::), and 0 means no compression. When one or both of these
+ keys are set and a client requests a level outside the specified
+ range, the server will simply use the closest permissable level.
+ Clients will continue compressing at the level requested by the
+ user.
+
+ The exception is when level 0 (no compression) is not available
+ and the client fails to request any compression. The CVS server
+ will then exit with an error message when it becomes apparent that
+ the client is not going to request compression. This will not
+ happen with clients version 1.12.13 and later since these client
+ versions allow the server to notify them that they must request
+ some level of compression.
+
+`PrimaryServer=CVSROOT'
+ When specified, and the repository specified by CVSROOT is not the
+ one currently being accessed, then the server will turn itself
+ into a transparent proxy to CVSROOT for write requests. The
+ HOSTNAME configured as part of CVSROOT must resolve to the same
+ string returned by the `uname' command on the primary server for
+ this to work. Host name resolution is performed via some
+ combination of `named', a broken out line from `/etc/hosts', and
+ the Network Information Service (NIS or YP), depending on the
+ configuration of the particular system.
+
+ Only the `:ext:' method is currently supported for primaries
+ (actually, `:fork:' is supported as well, but only for testing -
+ if you find another use for accessing a primary via the `:fork:'
+ method, please send a note to <bug-cvs@nongnu.org> about it). See
+ *Note Write proxies:: for more on configuring and using write
+ proxies.
+
+`RCSBIN=BINDIR'
+ For CVS 1.9.12 through 1.9.18, this setting told CVS to look for
+ RCS programs in the BINDIR directory. Current versions of CVS do
+ not run RCS programs; for compatibility this setting is accepted,
+ but it does nothing.
+
+`RereadLogAfterVerify=VALUE'
+ Modify the `commit' command such that CVS will reread the log
+ message after running the program specified by `verifymsg'. VALUE
+ may be one of `yes' or `always', indicating that the log message
+ should always be reread; `no' or `never', indicating that it
+ should never be reread; or VALUE may be `stat', indicating that
+ the file should be checked with the file system `stat()' function
+ to see if it has changed (see warning below) before rereading.
+ The default value is `always'.
+
+ *Note_ the `stat' mode can cause CVS to pause for up to one extra
+ second per directory committed. This can be less IO and CPU
+ intensive but is not recommended for use with large repositories*
+
+ *Note verifymsg::, for more information on how verifymsg may be
+ used.
+
+`SystemAuth=VALUE'
+ If VALUE is `yes', then pserver should check for users in the
+ system's user database if not found in `CVSROOT/passwd'. If it is
+ `no', then all pserver users must exist in `CVSROOT/passwd'. The
+ default is `yes'. For more on pserver, see *Note Password
+ authenticated::.
+
+`TmpDir=PATH'
+ Specify PATH as the directory to create temporary files in. *Note
+ Global options::, for more on setting the path to the temporary
+ directory. This option first appeared with CVS release 1.12.13.
+
+`TopLevelAdmin=VALUE'
+ Modify the `checkout' command to create a `CVS' directory at the
+ top level of the new working directory, in addition to `CVS'
+ directories created within checked-out directories. The default
+ value is `no'.
+
+ This option is useful if you find yourself performing many
+ commands at the top level of your working directory, rather than
+ in one of the checked out subdirectories. The `CVS' directory
+ created there will mean you don't have to specify `CVSROOT' for
+ each command. It also provides a place for the `CVS/Template'
+ file (*note Working directory storage::).
+
+`UseArchiveCommentLeader=VALUE'
+ Set to `true', if the text preceding a `$Log$' keyword is found to
+ exceed `MaxCommentLeaderLength' (above) bytes, then the comment
+ leader set in the RCS archive file (*note admin::), if any, will
+ be used instead. If there is no comment leader set in the archive
+ file or VALUE is set to `false', then the keyword will not be
+ expanded (*note Keyword list::). To force the comment leader in
+ the RCS archive file to be used exclusively (and `$Log$' expansion
+ skipped in files where the comment leader has not been set in the
+ archive file), set VALUE and set `MaxCommentLeaderLength' to `0'.
+
+`UseNewInfoFmtStrings=VALUE'
+ Specify whether CVS should support the new or old command line
+ template model for the commit support files (*note commit files::).
+ This configuration variable began life in deprecation and is only
+ here in order to give people time to update legacy repositories to
+ use the new format string syntax before support for the old syntax
+ is removed. For information on updating your repository to
+ support the new model, please see *Note Updating Commit Files::.
+
+ _Note that new repositories (created with the `cvs init' command)
+ will have this value set to `yes', but the default value is `no'._
+
+`UserAdminOptions=VALUE'
+ Control what options will be allowed with the `cvs admin' command
+ (*note admin::) for users not in the `cvsadmin' group. The VALUE
+ string is a list of single character options which should be
+ allowed. If a user who is not a member of the `cvsadmin' group
+ tries to execute any `cvs admin' option which is not listed they
+ will will receive an error message reporting that the option is
+ restricted.
+
+ If no `cvsadmin' group exists on the server, CVS will ignore the
+ `UserAdminOptions' keyword (*note admin::).
+
+ When not specified, `UserAdminOptions' defaults to `k'. In other
+ words, it defaults to allowing users outside of the `cvsadmin'
+ group to use the `cvs admin' command only to change the default
+ keyword expansion mode for files.
+
+ As an example, to restrict users not in the `cvsadmin' group to
+ using `cvs admin' to change the default keyword substitution mode,
+ lock revisions, unlock revisions, and replace the log message, use
+ `UserAdminOptions=klum'.
+
+
+File: cvs.info, Node: Environment variables, Next: Compatibility, Prev: Administrative files, Up: Top
+
+Appendix D All environment variables which affect CVS
+*****************************************************
+
+This is a complete list of all environment variables that affect CVS
+(Windows users, please bear with this list; $VAR is equivalent to %VAR%
+at the Windows command prompt).
+
+`$CVSIGNORE'
+ A whitespace-separated list of file name patterns that CVS should
+ ignore. *Note cvsignore::.
+
+`$CVSWRAPPERS'
+ A whitespace-separated list of file name patterns that CVS should
+ treat as wrappers. *Note Wrappers::.
+
+`$CVSREAD'
+ If this is set, `checkout' and `update' will try hard to make the
+ files in your working directory read-only. When this is not set,
+ the default behavior is to permit modification of your working
+ files.
+
+`$CVSREADONLYFS'
+ Turns on read-only repository mode. This allows one to check out
+ from a read-only repository, such as within an anoncvs server, or
+ from a CD-ROM repository.
+
+ It has the same effect as if the `-R' command-line option is used.
+ This can also allow the use of read-only NFS repositories.
+
+`$CVSUMASK'
+ Controls permissions of files in the repository. See *Note File
+ permissions::.
+
+`$CVSROOT'
+ Should contain the full pathname to the root of the CVS source
+ repository (where the RCS files are kept). This information must
+ be available to CVS for most commands to execute; if `$CVSROOT' is
+ not set, or if you wish to override it for one invocation, you can
+ supply it on the command line: `cvs -d cvsroot cvs_command...'
+ Once you have checked out a working directory, CVS stores the
+ appropriate root (in the file `CVS/Root'), so normally you only
+ need to worry about this when initially checking out a working
+ directory.
+
+`$CVSEDITOR'
+`$EDITOR'
+`$VISUAL'
+ Specifies the program to use for recording log messages during
+ commit. `$CVSEDITOR' overrides `$EDITOR', which overrides
+ `$VISUAL'. See *Note Committing your changes:: for more or *Note
+ Global options:: for alternative ways of specifying a log editor.
+
+`$PATH'
+ If `$RCSBIN' is not set, and no path is compiled into CVS, it will
+ use `$PATH' to try to find all programs it uses.
+
+`$HOME'
+
+`$HOMEPATH'
+
+`$HOMEDRIVE'
+ Used to locate the directory where the `.cvsrc' file, and other
+ such files, are searched. On Unix, CVS just checks for `HOME'.
+ On Windows NT, the system will set `HOMEDRIVE', for example to
+ `d:' and `HOMEPATH', for example to `\joe'. On Windows 95, you'll
+ probably need to set `HOMEDRIVE' and `HOMEPATH' yourself.
+
+`$CVS_RSH'
+ Specifies the external program which CVS connects with, when
+ `:ext:' access method is specified. *note Connecting via rsh::.
+
+`$CVS_SERVER'
+ Used in client-server mode when accessing a remote repository
+ using RSH. It specifies the name of the program to start on the
+ server side (and any necessary arguments) when accessing a remote
+ repository using the `:ext:', `:fork:', or `:server:' access
+ methods. The default value for `:ext:' and `:server:' is `cvs';
+ the default value for `:fork:' is the name used to run the client.
+ *note Connecting via rsh::
+
+`$CVS_PASSFILE'
+ Used in client-server mode when accessing the `cvs login server'.
+ Default value is `$HOME/.cvspass'. *note Password authentication
+ client::
+
+`$CVS_CLIENT_PORT'
+ Used in client-server mode to set the port to use when accessing
+ the server via Kerberos, GSSAPI, or CVS's password authentication
+ protocol if the port is not specified in the CVSROOT. *note
+ Remote repositories::
+
+`$CVS_PROXY_PORT'
+ Used in client-server mode to set the port to use when accessing a
+ server via a web proxy, if the port is not specified in the
+ CVSROOT. Works with GSSAPI, and the password authentication
+ protocol. *note Remote repositories::
+
+`$CVS_RCMD_PORT'
+ Used in client-server mode. If set, specifies the port number to
+ be used when accessing the RCMD demon on the server side.
+ (Currently not used for Unix clients).
+
+`$CVS_CLIENT_LOG'
+ Used for debugging only in client-server mode. If set, everything
+ sent to the server is logged into ``$CVS_CLIENT_LOG'.in' and
+ everything sent from the server is logged into
+ ``$CVS_CLIENT_LOG'.out'.
+
+`$CVS_SERVER_SLEEP'
+ Used only for debugging the server side in client-server mode. If
+ set, delays the start of the server child process the specified
+ amount of seconds so that you can attach to it with a debugger.
+
+`$CVS_IGNORE_REMOTE_ROOT'
+ For CVS 1.10 and older, setting this variable prevents CVS from
+ overwriting the `CVS/Root' file when the `-d' global option is
+ specified. Later versions of CVS do not rewrite `CVS/Root', so
+ `CVS_IGNORE_REMOTE_ROOT' has no effect.
+
+`$CVS_LOCAL_BRANCH_NUM'
+ Setting this variable allows some control over the branch number
+ that is assigned. This is specifically to support the local commit
+ feature of CVSup. If one sets `CVS_LOCAL_BRANCH_NUM' to (say) 1000
+ then branches the local repository, the revision numbers will look
+ like 1.66.1000.xx. There is almost a dead-set certainty that there
+ will be no conflicts with version numbers.
+
+`$COMSPEC'
+ Used under OS/2 only. It specifies the name of the command
+ interpreter and defaults to CMD.EXE.
+
+`$TMPDIR'
+ Directory in which temporary files are located. *Note Global
+ options::, for more on setting the temporary directory.
+
+`$CVS_PID'
+ This is the process identification (aka pid) number of the CVS
+ process. It is often useful in the programs and/or scripts
+ specified by the `commitinfo', `verifymsg', `loginfo' files.
+
+
+File: cvs.info, Node: Compatibility, Next: Troubleshooting, Prev: Environment variables, Up: Top
+
+Appendix E Compatibility between CVS Versions
+*********************************************
+
+The repository format is compatible going back to CVS 1.3. But see
+*Note Watches Compatibility::, if you have copies of CVS 1.6 or older
+and you want to use the optional developer communication features.
+
+ The working directory format is compatible going back to CVS 1.5.
+It did change between CVS 1.3 and CVS 1.5. If you run CVS 1.5 or newer
+on a working directory checked out with CVS 1.3, CVS will convert it,
+but to go back to CVS 1.3 you need to check out a new working directory
+with CVS 1.3.
+
+ The remote protocol is interoperable going back to CVS 1.5, but no
+further (1.5 was the first official release with the remote protocol,
+but some older versions might still be floating around). In many cases
+you need to upgrade both the client and the server to take advantage of
+new features and bug fixes, however.
+
+
+File: cvs.info, Node: Troubleshooting, Next: Credits, Prev: Compatibility, Up: Top
+
+Appendix F Troubleshooting
+**************************
+
+If you are having trouble with CVS, this appendix may help. If there
+is a particular error message which you are seeing, then you can look
+up the message alphabetically. If not, you can look through the
+section on other problems to see if your problem is mentioned there.
+
+* Menu:
+
+* Error messages:: Partial list of CVS errors
+* Connection:: Trouble making a connection to a CVS server
+* Other problems:: Problems not readily listed by error message
+
+
+File: cvs.info, Node: Error messages, Next: Connection, Up: Troubleshooting
+
+F.1 Partial list of error messages
+==================================
+
+Here is a partial list of error messages that you may see from CVS. It
+is not a complete list--CVS is capable of printing many, many error
+messages, often with parts of them supplied by the operating system,
+but the intention is to list the common and/or potentially confusing
+error messages.
+
+ The messages are alphabetical, but introductory text such as `cvs
+update: ' is not considered in ordering them.
+
+ In some cases the list includes messages printed by old versions of
+CVS (partly because users may not be sure which version of CVS they are
+using at any particular moment).
+
+`FILE:LINE: Assertion 'TEXT' failed'
+ The exact format of this message may vary depending on your
+ system. It indicates a bug in CVS, which can be handled as
+ described in *Note BUGS::.
+
+`cvs COMMAND: authorization failed: server HOST rejected access'
+ This is a generic response when trying to connect to a pserver
+ server which chooses not to provide a specific reason for denying
+ authorization. Check that the username and password specified are
+ correct and that the `CVSROOT' specified is allowed by
+ `--allow-root' in `inetd.conf'. See *Note Password
+ authenticated::.
+
+`cvs COMMAND: conflict: removed FILE was modified by second party'
+ This message indicates that you removed a file, and someone else
+ modified it. To resolve the conflict, first run `cvs add FILE'.
+ If desired, look at the other party's modification to decide
+ whether you still want to remove it. If you don't want to remove
+ it, stop here. If you do want to remove it, proceed with `cvs
+ remove FILE' and commit your removal.
+
+`cannot change permissions on temporary directory'
+ Operation not permitted
+ This message has been happening in a non-reproducible, occasional
+ way when we run the client/server testsuite, both on Red Hat Linux
+ 3.0.3 and 4.1. We haven't been able to figure out what causes it,
+ nor is it known whether it is specific to Linux (or even to this
+ particular machine!). If the problem does occur on other unices,
+ `Operation not permitted' would be likely to read `Not owner' or
+ whatever the system in question uses for the unix `EPERM' error.
+ If you have any information to add, please let us know as
+ described in *Note BUGS::. If you experience this error while
+ using CVS, retrying the operation which produced it should work
+ fine.
+
+`cvs [server aborted]: Cannot check out files into the repository itself'
+ The obvious cause for this message (especially for
+ non-client/server CVS) is that the CVS root is, for example,
+ `/usr/local/cvsroot' and you try to check out files when you are
+ in a subdirectory, such as `/usr/local/cvsroot/test'. However,
+ there is a more subtle cause, which is that the temporary
+ directory on the server is set to a subdirectory of the root
+ (which is also not allowed). If this is the problem, set the
+ temporary directory to somewhere else, for example `/var/tmp'; see
+ `TMPDIR' in *Note Environment variables::, for how to set the
+ temporary directory.
+
+`cannot commit files as 'root''
+ See `'root' is not allowed to commit files'.
+
+`cannot open CVS/Entries for reading: No such file or directory'
+ This generally indicates a CVS internal error, and can be handled
+ as with other CVS bugs (*note BUGS::). Usually there is a
+ workaround--the exact nature of which would depend on the
+ situation but which hopefully could be figured out.
+
+`cvs [init aborted]: cannot open CVS/Root: No such file or directory'
+ This message is harmless. Provided it is not accompanied by other
+ errors, the operation has completed successfully. This message
+ should not occur with current versions of CVS, but it is documented
+ here for the benefit of CVS 1.9 and older.
+
+`cvs server: cannot open /root/.cvsignore: Permission denied'
+`cvs [server aborted]: can't chdir(/root): Permission denied'
+ See *Note Connection::.
+
+`cvs [checkout aborted]: cannot rename file FILE to CVS/,,FILE: Invalid argument'
+ This message has been reported as intermittently happening with
+ CVS 1.9 on Solaris 2.5. The cause is unknown; if you know more
+ about what causes it, let us know as described in *Note BUGS::.
+
+`cvs [COMMAND aborted]: cannot start server via rcmd'
+ This, unfortunately, is a rather nonspecific error message which
+ CVS 1.9 will print if you are running the CVS client and it is
+ having trouble connecting to the server. Current versions of CVS
+ should print a much more specific error message. If you get this
+ message when you didn't mean to run the client at all, you
+ probably forgot to specify `:local:', as described in *Note
+ Repository::.
+
+`ci: FILE,v: bad diff output line: Binary files - and /tmp/T2a22651 differ'
+ CVS 1.9 and older will print this message when trying to check in
+ a binary file if RCS is not correctly installed. Re-read the
+ instructions that came with your RCS distribution and the INSTALL
+ file in the CVS distribution. Alternately, upgrade to a current
+ version of CVS, which checks in files itself rather than via RCS.
+
+`cvs checkout: could not check out FILE'
+ With CVS 1.9, this can mean that the `co' program (part of RCS)
+ returned a failure. It should be preceded by another error
+ message, however it has been observed without another error
+ message and the cause is not well-understood. With the current
+ version of CVS, which does not run `co', if this message occurs
+ without another error message, it is definitely a CVS bug (*note
+ BUGS::).
+
+`cvs [login aborted]: could not find out home directory'
+ This means that you need to set the environment variables that CVS
+ uses to locate your home directory. See the discussion of `HOME',
+ `HOMEDRIVE', and `HOMEPATH' in *Note Environment variables::.
+
+`cvs update: could not merge revision REV of FILE: No such file or directory'
+ CVS 1.9 and older will print this message if there was a problem
+ finding the `rcsmerge' program. Make sure that it is in your
+ `PATH', or upgrade to a current version of CVS, which does not
+ require an external `rcsmerge' program.
+
+`cvs [update aborted]: could not patch FILE: No such file or directory'
+ This means that there was a problem finding the `patch' program.
+ Make sure that it is in your `PATH'. Note that despite
+ appearances the message is _not_ referring to whether it can find
+ FILE. If both the client and the server are running a current
+ version of CVS, then there is no need for an external patch
+ program and you should not see this message. But if either client
+ or server is running CVS 1.9, then you need `patch'.
+
+`cvs update: could not patch FILE; will refetch'
+ This means that for whatever reason the client was unable to apply
+ a patch that the server sent. The message is nothing to be
+ concerned about, because inability to apply the patch only slows
+ things down and has no effect on what CVS does.
+
+`dying gasps from SERVER unexpected'
+ There is a known bug in the server for CVS 1.9.18 and older which
+ can cause this. For me, this was reproducible if I used the `-t'
+ global option. It was fixed by Andy Piper's 14 Nov 1997 change to
+ src/filesubr.c, if anyone is curious. If you see the message, you
+ probably can just retry the operation which failed, or if you have
+ discovered information concerning its cause, please let us know as
+ described in *Note BUGS::.
+
+`end of file from server (consult above messages if any)'
+ The most common cause for this message is if you are using an
+ external `rsh' program and it exited with an error. In this case
+ the `rsh' program should have printed a message, which will appear
+ before the above message. For more information on setting up a
+ CVS client and server, see *Note Remote repositories::.
+
+`cvs [update aborted]: EOF in key in RCS file FILE,v'
+`cvs [checkout aborted]: EOF while looking for end of string in RCS file FILE,v'
+ This means that there is a syntax error in the given RCS file.
+ Note that this might be true even if RCS can read the file OK; CVS
+ does more error checking of errors in the RCS file. That is why
+ you may see this message when upgrading from CVS 1.9 to CVS 1.10.
+ The likely cause for the original corruption is hardware, the
+ operating system, or the like. Of course, if you find a case in
+ which CVS seems to corrupting the file, by all means report it,
+ (*note BUGS::). There are quite a few variations of this error
+ message, depending on exactly where in the RCS file CVS finds the
+ syntax error.
+
+`cvs commit: Executing 'mkmodules''
+ This means that your repository is set up for a version of CVS
+ prior to CVS 1.8. When using CVS 1.8 or later, the above message
+ will be preceded by
+
+ cvs commit: Rebuilding administrative file database
+
+ If you see both messages, the database is being rebuilt twice,
+ which is unnecessary but harmless. If you wish to avoid the
+ duplication, and you have no versions of CVS 1.7 or earlier in
+ use, remove `-i mkmodules' every place it appears in your `modules'
+ file. For more information on the `modules' file, see *Note
+ modules::.
+
+`missing author'
+ Typically this can happen if you created an RCS file with your
+ username set to empty. CVS will, bogusly, create an illegal RCS
+ file with no value for the author field. The solution is to make
+ sure your username is set to a non-empty value and re-create the
+ RCS file.
+
+`cvs [checkout aborted]: no such tag TAG'
+ This message means that CVS isn't familiar with the tag TAG.
+ Usually the root cause is that you have mistyped a tag name.
+ Ocassionally this can also occur because the users creating tags
+ do not have permissions to write to the `CVSROOT/val-tags' file
+ (*note File permissions::, for more).
+
+ Prior to CVS version 1.12.10, there were a few relatively obscure
+ cases where a given tag could be created in an archive file in the
+ repository but CVS would require the user to try a few other CVS
+ commands involving that tag until one was found whch caused CVS to
+ update the `val-tags' file, at which point the originally failing
+ command would begin to work. This same method can be used to
+ repair a `val-tags' file that becomes out of date due to the
+ permissions problem mentioned above. This updating is only
+ required once per tag - once a tag is listed in `val-tags', it
+ stays there.
+
+ Note that using `tag -f' to not require tag matches did not and
+ does not override this check (*note Common options::).
+
+`*PANIC* administration files missing'
+ This typically means that there is a directory named CVS but it
+ does not contain the administrative files which CVS puts in a CVS
+ directory. If the problem is that you created a CVS directory via
+ some mechanism other than CVS, then the answer is simple, use a
+ name other than CVS. If not, it indicates a CVS bug (*note
+ BUGS::).
+
+`rcs error: Unknown option: -x,v/'
+ This message will be followed by a usage message for RCS. It
+ means that you have an old version of RCS (probably supplied with
+ your operating system), as well as an old version of CVS. CVS
+ 1.9.18 and earlier only work with RCS version 5 and later; current
+ versions of CVS do not run RCS programs.
+
+`cvs [server aborted]: received broken pipe signal'
+ This message can be caused by a loginfo program that fails to read
+ all of the log information from its standard input. If you find
+ it happening in any other circumstances, please let us know as
+ described in *Note BUGS::.
+
+`'root' is not allowed to commit files'
+ When committing a permanent change, CVS makes a log entry of who
+ committed the change. If you are committing the change logged in
+ as "root" (not under "su" or other root-priv giving program), CVS
+ cannot determine who is actually making the change. As such, by
+ default, CVS disallows changes to be committed by users logged in
+ as "root". (You can disable this option by passing the
+ `--enable-rootcommit' option to `configure' and recompiling CVS.
+ On some systems this means editing the appropriate `config.h' file
+ before building CVS.)
+
+`cvs [server aborted]: Secondary out of sync with primary!'
+ This usually means that the version of CVS running on a secondary
+ server is incompatible with the version running on the primary
+ server (*note Write proxies::). This will not occur if the client
+ supports redirection.
+
+ It is not the version number that is significant here, but the
+ list of supported requests that the servers provide to the client.
+ For example, even if both servers were the same version, if the
+ secondary was compiled with GSSAPI support and the primary was not,
+ the list of supported requests provided by the two servers would
+ be different and the secondary would not work as a transparent
+ proxy to the primary. Conversely, even if the two servers were
+ radically different versions but both provided the same list of
+ valid requests to the client, the transparent proxy would succeed.
+
+`Terminated with fatal signal 11'
+ This message usually indicates that CVS (the server, if you're
+ using client/server mode) has run out of (virtual) memory.
+ Although CVS tries to catch the error and issue a more meaningful
+ message, there are many circumstances where that is not possible.
+ If you appear to have lots of memory available to the system, the
+ problem is most likely that you're running into a system-wide
+ limit on the amount of memory a single process can use or a
+ similar process-specific limit. The mechanisms for displaying and
+ setting such limits vary from system to system, so you'll have to
+ consult an expert for your particular system if you don't know how
+ to do that.
+
+`Too many arguments!'
+ This message is typically printed by the `log.pl' script which is
+ in the `contrib' directory in the CVS source distribution. In
+ some versions of CVS, `log.pl' has been part of the default CVS
+ installation. The `log.pl' script gets called from the `loginfo'
+ administrative file. Check that the arguments passed in `loginfo'
+ match what your version of `log.pl' expects. In particular, the
+ `log.pl' from CVS 1.3 and older expects the log file as an
+ argument whereas the `log.pl' from CVS 1.5 and newer expects the
+ log file to be specified with a `-f' option. Of course, if you
+ don't need `log.pl' you can just comment it out of `loginfo'.
+
+`cvs [update aborted]: unexpected EOF reading FILE,v'
+ See `EOF in key in RCS file'.
+
+`cvs [login aborted]: unrecognized auth response from SERVER'
+ This message typically means that the server is not set up
+ properly. For example, if `inetd.conf' points to a nonexistent
+ cvs executable. To debug it further, find the log file which
+ inetd writes (`/var/log/messages' or whatever inetd uses on your
+ system). For details, see *Note Connection::, and *Note Password
+ authentication server::.
+
+`cvs commit: Up-to-date check failed for `FILE''
+ This means that someone else has committed a change to that file
+ since the last time that you did a `cvs update'. So before
+ proceeding with your `cvs commit' you need to `cvs update'. CVS
+ will merge the changes that you made and the changes that the
+ other person made. If it does not detect any conflicts it will
+ report `M FILE' and you are ready to `cvs commit'. If it detects
+ conflicts it will print a message saying so, will report `C FILE',
+ and you need to manually resolve the conflict. For more details
+ on this process see *Note Conflicts example::.
+
+`Usage: diff3 [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3'
+ Only one of [exEX3] allowed
+ This indicates a problem with the installation of `diff3' and
+ `rcsmerge'. Specifically `rcsmerge' was compiled to look for GNU
+ diff3, but it is finding unix diff3 instead. The exact text of
+ the message will vary depending on the system. The simplest
+ solution is to upgrade to a current version of CVS, which does not
+ rely on external `rcsmerge' or `diff3' programs.
+
+`warning: unrecognized response `TEXT' from cvs server'
+ If TEXT contains a valid response (such as `ok') followed by an
+ extra carriage return character (on many systems this will cause
+ the second part of the message to overwrite the first part), then
+ it probably means that you are using the `:ext:' access method
+ with a version of rsh, such as most non-unix rsh versions, which
+ does not by default provide a transparent data stream. In such
+ cases you probably want to try `:server:' instead of `:ext:'. If
+ TEXT is something else, this may signify a problem with your CVS
+ server. Double-check your installation against the instructions
+ for setting up the CVS server.
+
+`cvs commit: [TIME] waiting for USER's lock in DIRECTORY'
+ This is a normal message, not an error. See *Note Concurrency::,
+ for more details.
+
+`cvs commit: warning: editor session failed'
+ This means that the editor which CVS is using exits with a nonzero
+ exit status. Some versions of vi will do this even when there was
+ not a problem editing the file. If so, point the `CVSEDITOR'
+ environment variable to a small script such as:
+
+ #!/bin/sh
+ vi $*
+ exit 0
+
+`cvs update: warning: FILE was lost'
+ This means that the working copy of FILE has been deleted but it
+ has not been removed from CVS. This is nothing to be concerned
+ about, the update will just recreate the local file from the
+ repository. (This is a convenient way to discard local changes to
+ a file: just delete it and then run `cvs update'.)
+
+`cvs update: warning: FILE is not (any longer) pertinent'
+ This means that the working copy of FILE has been deleted, it has
+ not been removed from CVS in the current working directory, but it
+ has been removed from CVS in some other working directory. This
+ is nothing to be concerned about, the update would have removed
+ the local file anyway.
+
+
+
+File: cvs.info, Node: Connection, Next: Other problems, Prev: Error messages, Up: Troubleshooting
+
+F.2 Trouble making a connection to a CVS server
+===============================================
+
+This section concerns what to do if you are having trouble making a
+connection to a CVS server. If you are running the CVS command line
+client running on Windows, first upgrade the client to CVS 1.9.12 or
+later. The error reporting in earlier versions provided much less
+information about what the problem was. If the client is non-Windows,
+CVS 1.9 should be fine.
+
+ If the error messages are not sufficient to track down the problem,
+the next steps depend largely on which access method you are using.
+
+`:ext:'
+ Try running the rsh program from the command line. For example:
+ "rsh servername cvs -v" should print CVS version information. If
+ this doesn't work, you need to fix it before you can worry about
+ CVS problems.
+
+`:server:'
+ You don't need a command line rsh program to use this access
+ method, but if you have an rsh program around, it may be useful as
+ a debugging tool. Follow the directions given for :ext:.
+
+`:pserver:'
+ Errors along the lines of "connection refused" typically indicate
+ that inetd isn't even listening for connections on port 2401
+ whereas errors like "connection reset by peer", "received broken
+ pipe signal", "recv() from server: EOF", or "end of file from
+ server" typically indicate that inetd is listening for connections
+ but is unable to start CVS (this is frequently caused by having an
+ incorrect path in `inetd.conf' or by firewall software rejecting
+ the connection). "unrecognized auth response" errors are caused
+ by a bad command line in `inetd.conf', typically an invalid option
+ or forgetting to put the `pserver' command at the end of the line.
+ Another less common problem is invisible control characters that
+ your editor "helpfully" added without you noticing.
+
+ One good debugging tool is to "telnet servername 2401". After
+ connecting, send any text (for example "foo" followed by return).
+ If CVS is working correctly, it will respond with
+
+ cvs [pserver aborted]: bad auth protocol start: foo
+
+ If instead you get:
+
+ Usage: cvs [cvs-options] command [command-options-and-arguments]
+ ...
+
+ then you're missing the `pserver' command at the end of the line
+ in `inetd.conf'; check to make sure that the entire command is on
+ one line and that it's complete.
+
+ Likewise, if you get something like:
+
+ Unknown command: `pserved'
+
+ CVS commands are:
+ add Add a new file/directory to the repository
+ ...
+
+ then you've misspelled `pserver' in some way. If it isn't
+ obvious, check for invisible control characters (particularly
+ carriage returns) in `inetd.conf'.
+
+ If it fails to work at all, then make sure inetd is working right.
+ Change the invocation in `inetd.conf' to run the echo program
+ instead of cvs. For example:
+
+ 2401 stream tcp nowait root /bin/echo echo hello
+
+ After making that change and instructing inetd to re-read its
+ configuration file, "telnet servername 2401" should show you the
+ text hello and then the server should close the connection. If
+ this doesn't work, you need to fix it before you can worry about
+ CVS problems.
+
+ On AIX systems, the system will often have its own program trying
+ to use port 2401. This is AIX's problem in the sense that port
+ 2401 is registered for use with CVS. I hear that there is an AIX
+ patch available to address this problem.
+
+ Another good debugging tool is the `-d' (debugging) option to
+ inetd. Consult your system documentation for more information.
+
+ If you seem to be connecting but get errors like:
+
+ cvs server: cannot open /root/.cvsignore: Permission denied
+ cvs [server aborted]: can't chdir(/root): Permission denied
+
+ then you probably haven't specified `-f' in `inetd.conf'. (In
+ releases prior to CVS 1.11.1, this problem can be caused by your
+ system setting the `$HOME' environment variable for programs being
+ run by inetd. In this case, you can either have inetd run a shell
+ script that unsets `$HOME' and then runs CVS, or you can use `env'
+ to run CVS with a pristine environment.)
+
+ If you can connect successfully for a while but then can't, you've
+ probably hit inetd's rate limit. (If inetd receives too many
+ requests for the same service in a short period of time, it
+ assumes that something is wrong and temporarily disables the
+ service.) Check your inetd documentation to find out how to
+ adjust the rate limit (some versions of inetd have a single rate
+ limit, others allow you to set the limit for each service
+ separately.)
+
+
+File: cvs.info, Node: Other problems, Prev: Connection, Up: Troubleshooting
+
+F.3 Other common problems
+=========================
+
+Here is a list of problems which do not fit into the above categories.
+They are in no particular order.
+
+ * On Windows, if there is a 30 second or so delay when you run a CVS
+ command, it may mean that you have your home directory set to
+ `C:/', for example (see `HOMEDRIVE' and `HOMEPATH' in *Note
+ Environment variables::). CVS expects the home directory to not
+ end in a slash, for example `C:' or `C:\cvs'.
+
+ * If you are running CVS 1.9.18 or older, and `cvs update' finds a
+ conflict and tries to merge, as described in *Note Conflicts
+ example::, but doesn't tell you there were conflicts, then you may
+ have an old version of RCS. The easiest solution probably is to
+ upgrade to a current version of CVS, which does not rely on
+ external RCS programs.
+
+
+File: cvs.info, Node: Credits, Next: BUGS, Prev: Troubleshooting, Up: Top
+
+Appendix G Credits
+******************
+
+Roland Pesch, then of Cygnus Support <roland@wrs.com> wrote the manual
+pages which were distributed with CVS 1.3. Much of their text was
+copied into this manual. He also read an early draft of this manual
+and contributed many ideas and corrections.
+
+ The mailing-list `info-cvs' is sometimes informative. I have
+included information from postings made by the following persons: David
+G. Grubbs <dgg@think.com>.
+
+ Some text has been extracted from the man pages for RCS.
+
+ The CVS FAQ by David G. Grubbs has provided useful material. The
+FAQ is no longer maintained, however, and this manual is about the
+closest thing there is to a successor (with respect to documenting how
+to use CVS, at least).
+
+ In addition, the following persons have helped by telling me about
+mistakes I've made:
+
+ Roxanne Brunskill <rbrunski@datap.ca>,
+ Kathy Dyer <dyer@phoenix.ocf.llnl.gov>,
+ Karl Pingle <pingle@acuson.com>,
+ Thomas A Peterson <tap@src.honeywell.com>,
+ Inge Wallin <ingwa@signum.se>,
+ Dirk Koschuetzki <koschuet@fmi.uni-passau.de>
+ and Michael Brown <brown@wi.extrel.com>.
+
+ The list of contributors here is not comprehensive; for a more
+complete list of who has contributed to this manual see the file
+`doc/ChangeLog' in the CVS source distribution.
+
+
+File: cvs.info, Node: BUGS, Next: Index, Prev: Credits, Up: Top
+
+Appendix H Dealing with bugs in CVS or this manual
+**************************************************
+
+Neither CVS nor this manual is perfect, and they probably never will
+be. If you are having trouble using CVS, or think you have found a
+bug, there are a number of things you can do about it. Note that if
+the manual is unclear, that can be considered a bug in the manual, so
+these problems are often worth doing something about as well as
+problems with CVS itself.
+
+ * If you want someone to help you and fix bugs that you report,
+ there are companies which will do that for a fee. One such
+ company is:
+
+ Ximbiot
+ 319 S. River St.
+ Harrisburg, PA 17104-1657
+ USA
+ Email: info@ximbiot.com
+ Phone: (717) 579-6168
+ Fax: (717) 234-3125
+ `http://ximbiot.com/'
+
+ * If you got CVS through a distributor, such as an operating system
+ vendor or a vendor of freeware CD-ROMs, you may wish to see
+ whether the distributor provides support. Often, they will provide
+ no support or minimal support, but this may vary from distributor
+ to distributor.
+
+ * If you have the skills and time to do so, you may wish to fix the
+ bug yourself. If you wish to submit your fix for inclusion in
+ future releases of CVS, see the file HACKING in the CVS source
+ distribution. It contains much more information on the process of
+ submitting fixes.
+
+ * There may be resources on the net which can help. A good place to
+ start is:
+
+ `http://cvs.nongnu.org/'
+
+ If you are so inspired, increasing the information available on
+ the net is likely to be appreciated. For example, before the
+ standard CVS distribution worked on Windows 95, there was a web
+ page with some explanation and patches for running CVS on Windows
+ 95, and various people helped out by mentioning this page on
+ mailing lists or newsgroups when the subject came up.
+
+ * It is also possible to report bugs to <bug-cvs@nongnu.org>. Note
+ that someone may or may not want to do anything with your bug
+ report--if you need a solution consider one of the options
+ mentioned above. People probably do want to hear about bugs which
+ are particularly severe in consequences and/or easy to fix,
+ however. You can also increase your odds by being as clear as
+ possible about the exact nature of the bug and any other relevant
+ information. The way to report bugs is to send email to
+ <bug-cvs@nongnu.org>. Note that submissions to
+ <bug-cvs@nongnu.org> may be distributed under the terms of the GNU
+ Public License, so if you don't like this, don't submit them.
+ There is usually no justification for sending mail directly to one
+ of the CVS maintainers rather than to <bug-cvs@nongnu.org>; those
+ maintainers who want to hear about such bug reports read
+ <bug-cvs@nongnu.org>. Also note that sending a bug report to
+ other mailing lists or newsgroups is _not_ a substitute for
+ sending it to <bug-cvs@nongnu.org>. It is fine to discuss CVS
+ bugs on whatever forum you prefer, but there are not necessarily
+ any maintainers reading bug reports sent anywhere except
+ <bug-cvs@nongnu.org>.
+
+ People often ask if there is a list of known bugs or whether a
+particular bug is a known one. The file BUGS in the CVS source
+distribution is one list of known bugs, but it doesn't necessarily try
+to be comprehensive. Perhaps there will never be a comprehensive,
+detailed list of known bugs.
+
+
+File: cvs.info, Node: Index, Prev: BUGS, Up: Top
+
+Index
+*****
+
+
+* Menu:
+
+* !, in modules file: Excluding directories.
+ (line 6)
+* #cvs.lock, removing: Concurrency. (line 11)
+* #cvs.lock, technical details: Locks. (line 6)
+* #cvs.pfl, technical details: Locks. (line 6)
+* #cvs.rfl, and backups: Backing up. (line 10)
+* #cvs.rfl, removing: Concurrency. (line 11)
+* #cvs.rfl, technical details: Locks. (line 6)
+* #cvs.tfl: Locks. (line 14)
+* #cvs.wfl, removing: Concurrency. (line 11)
+* #cvs.wfl, technical details: Locks. (line 6)
+* &, in modules file: Ampersand modules. (line 6)
+* -a, in modules file: Alias modules. (line 6)
+* -d, in modules file: Module options. (line 9)
+* -e, in modules file <1>: Module program options.
+ (line 6)
+* -e, in modules file: Module options. (line 12)
+* -j (merging branches): Merging a branch. (line 6)
+* -j (merging branches), and keyword substitution: Merging and keywords.
+ (line 6)
+* -k (keyword substitution): Substitution modes. (line 6)
+* -kk, to avoid conflicts during a merge: Merging and keywords.
+ (line 6)
+* -o, in modules file <1>: Module program options.
+ (line 6)
+* -o, in modules file: Module options. (line 16)
+* -s, in modules file: Module options. (line 22)
+* -t, in modules file <1>: Module program options.
+ (line 6)
+* -t, in modules file: Module options. (line 30)
+* .# files: update output. (line 49)
+* .bashrc, setting CVSROOT in: Specifying a repository.
+ (line 12)
+* .cshrc, setting CVSROOT in: Specifying a repository.
+ (line 12)
+* .cvsrc file: ~/.cvsrc. (line 6)
+* .profile, setting CVSROOT in: Specifying a repository.
+ (line 12)
+* .tcshrc, setting CVSROOT in: Specifying a repository.
+ (line 12)
+* /usr/local/cvsroot, as example repository: Repository. (line 6)
+* :ext:, setting up: Connecting via rsh. (line 35)
+* :ext:, troubleshooting: Connection. (line 16)
+* :fork:, setting up: Connecting via fork. (line 6)
+* :gserver:, setting up: GSSAPI authenticated.
+ (line 6)
+* :kserver:, setting up: Kerberos authenticated.
+ (line 6)
+* :local:, setting up: Repository. (line 19)
+* :pserver:, setting up: Password authentication client.
+ (line 6)
+* :pserver:, troubleshooting: Connection. (line 27)
+* :server:, setting up: Connecting via rsh. (line 35)
+* :server:, troubleshooting: Connection. (line 22)
+* <<<<<<<: Conflicts example. (line 96)
+* =======: Conflicts example. (line 96)
+* >>>>>>>: Conflicts example. (line 96)
+* __ files (VMS): update output. (line 49)
+* Abandoning work: Editing files. (line 42)
+* abbreviations for months: Calendar date items. (line 38)
+* Access a branch: Accessing branches. (line 6)
+* add (subcommand): Adding files. (line 34)
+* Adding a tag: Tags. (line 45)
+* Adding files: Adding files. (line 6)
+* Admin (subcommand): admin. (line 6)
+* Admin commands, logging: postadmin. (line 6)
+* Administrative files (intro): Intro administrative files.
+ (line 6)
+* Administrative files (reference): Administrative files.
+ (line 6)
+* Administrative files, editing them: Intro administrative files.
+ (line 33)
+* Alias modules: Alias modules. (line 6)
+* ALL keyword, in lieu of regular expressions in script hooks: syntax.
+ (line 12)
+* Ampersand modules: Ampersand modules. (line 6)
+* annotate (subcommand): annotate. (line 6)
+* Atomic transactions, lack of: Concurrency. (line 27)
+* Attic: Attic. (line 6)
+* Authenticated client, using: Password authentication client.
+ (line 6)
+* Authenticating server, setting up: Password authentication server.
+ (line 10)
+* Authentication, stream: Global options. (line 16)
+* Author keyword: Keyword list. (line 8)
+* authors of get_date: Authors of get_date. (line 6)
+* Automatically ignored files: cvsignore. (line 23)
+* Avoiding editor invocation: Common options. (line 86)
+* Backing up, repository: Backing up. (line 6)
+* Base directory, in CVS directory: Working directory storage.
+ (line 178)
+* BASE, as reserved tag name: Tags. (line 25)
+* BASE, special tag: Common options. (line 122)
+* Baserev file, in CVS directory: Working directory storage.
+ (line 184)
+* Baserev.tmp file, in CVS directory: Working directory storage.
+ (line 192)
+* beginning of time, for POSIX: Seconds since the Epoch.
+ (line 13)
+* Bellovin, Steven M.: Authors of get_date. (line 6)
+* Berets, Jim: Authors of get_date. (line 6)
+* Berry, K.: Authors of get_date. (line 14)
+* Bill of materials: Builds. (line 25)
+* Binary files: Binary files. (line 6)
+* Branch merge example: Merging a branch. (line 15)
+* Branch number <1>: Branches and revisions.
+ (line 6)
+* Branch number: Revision numbers. (line 6)
+* Branch tags, deleting: Modifying tags. (line 19)
+* Branch tags, moving: Modifying tags. (line 37)
+* Branch, accessing: Accessing branches. (line 6)
+* Branch, check out: Accessing branches. (line 6)
+* Branch, creating a: Creating a branch. (line 6)
+* Branch, identifying: Accessing branches. (line 6)
+* Branch, retrieving: Accessing branches. (line 6)
+* Branch, vendor-: Tracking sources. (line 10)
+* Branches motivation: Branches motivation. (line 6)
+* Branches, copying changes between: Branching and merging.
+ (line 6)
+* Branches, sticky: Accessing branches. (line 37)
+* Branching: Branching and merging.
+ (line 6)
+* Bringing a file up to date: Updating a file. (line 6)
+* Bugs in this manual or CVS: BUGS. (line 6)
+* Bugs, reporting: BUGS. (line 13)
+* Builds: Builds. (line 6)
+* calendar date item: Calendar date items. (line 6)
+* case, ignored in dates: General date syntax. (line 64)
+* Changes, copying between branches: Branching and merging.
+ (line 6)
+* Changing a log message: admin options. (line 73)
+* Check out a branch: Accessing branches. (line 6)
+* Checked out copy, keeping: Keeping a checked out copy.
+ (line 6)
+* Checking out source: Getting the source. (line 6)
+* checkout (subcommand): checkout. (line 6)
+* Checkout program: Module options. (line 16)
+* Checkout, as term for getting ready to edit: Editing files. (line 6)
+* Checkout, example: Getting the source. (line 6)
+* checkoutlist: checkoutlist. (line 6)
+* Choosing, reserved or unreserved checkouts: Choosing a model.
+ (line 6)
+* Cleaning up: Cleaning up. (line 6)
+* Client/Server Operation: Remote repositories. (line 6)
+* Client/Server Operation, port specification <1>: Password authentication server.
+ (line 10)
+* Client/Server Operation, port specification: Remote repositories.
+ (line 6)
+* co (subcommand): checkout. (line 6)
+* Command reference: Invoking CVS. (line 6)
+* Command structure: Structure. (line 6)
+* Comment leader: admin options. (line 27)
+* comments, in dates: General date syntax. (line 64)
+* commit (subcommand): commit. (line 6)
+* commit files, see Info files: commit files. (line 6)
+* COMMITID, internal variable: Variables. (line 50)
+* commitinfo: commitinfo. (line 6)
+* commitinfo (admin file): commitinfo. (line 6)
+* commitinfo (admin file), exit status: commitinfo. (line 29)
+* commitinfo (admin file), updating legacy repositories: commitinfo.
+ (line 22)
+* commitinfo, command environment: commitinfo. (line 33)
+* commitinfo, working directory: commitinfo. (line 33)
+* Commits, administrative support files: commit files. (line 6)
+* Commits, precommit verification of: commitinfo. (line 6)
+* Committing changes to files: Committing your changes.
+ (line 6)
+* Committing, when to: When to commit. (line 6)
+* Common options: Common options. (line 6)
+* Common syntax of info files, format strings: syntax. (line 35)
+* Common syntax of info files, updating legacy repositories: Updating Commit Files.
+ (line 6)
+* compatibility notes, commitinfo admin file: commitinfo. (line 22)
+* compatibility notes, config admin file: config. (line 245)
+* compatibility notes, loginfo admin file: loginfo. (line 55)
+* compatibility notes, taginfo admin file: taginfo. (line 44)
+* compatibility notes, verifymsg admin file: verifymsg. (line 34)
+* Compatibility, between CVS versions: Compatibility. (line 6)
+* Compression <1>: Invoking CVS. (line 75)
+* Compression: Global options. (line 140)
+* Compression levels, restricting on server: config. (line 149)
+* COMSPEC, environment variable: Environment variables.
+ (line 130)
+* config (admin file), import: config. (line 90)
+* config (admin file), updating legacy repositories: config. (line 245)
+* config, in CVSROOT: config. (line 6)
+* configuration file <1>: config. (line 6)
+* configuration file: server & pserver. (line 26)
+* Configuring keyword expansion: Configuring keyword expansion.
+ (line 6)
+* Conflict markers: Conflicts example. (line 96)
+* Conflict resolution: Conflicts example. (line 101)
+* Conflicts (merge example): Conflicts example. (line 68)
+* connection method options: The connection method.
+ (line 16)
+* Contributors (CVS program): What is CVS?. (line 28)
+* Contributors (manual): Credits. (line 6)
+* Copying a repository: Moving a repository. (line 6)
+* Copying changes: Branching and merging.
+ (line 6)
+* Correcting a log message: admin options. (line 73)
+* Creating a branch: Creating a branch. (line 6)
+* Creating a project: Starting a new project.
+ (line 6)
+* Creating a repository: Creating a repository.
+ (line 6)
+* Credits (CVS program): What is CVS?. (line 28)
+* Credits (manual): Credits. (line 6)
+* CVS 1.6, and watches: Watches Compatibility.
+ (line 6)
+* CVS command structure: Structure. (line 6)
+* CVS directory, in repository: CVS in repository. (line 6)
+* CVS directory, in working directory: Working directory storage.
+ (line 6)
+* CVS passwd file: Password authentication server.
+ (line 67)
+* CVS, history of: What is CVS?. (line 28)
+* CVS, introduction to: What is CVS?. (line 6)
+* CVS, versions of: Compatibility. (line 6)
+* CVS/Base directory: Working directory storage.
+ (line 178)
+* CVS/Baserev file: Working directory storage.
+ (line 184)
+* CVS/Baserev.tmp file: Working directory storage.
+ (line 192)
+* CVS/Entries file: Working directory storage.
+ (line 60)
+* CVS/Entries.Backup file: Working directory storage.
+ (line 143)
+* CVS/Entries.Log file: Working directory storage.
+ (line 120)
+* CVS/Entries.Static file: Working directory storage.
+ (line 148)
+* CVS/Notify file: Working directory storage.
+ (line 167)
+* CVS/Notify.tmp file: Working directory storage.
+ (line 172)
+* CVS/Repository file: Working directory storage.
+ (line 32)
+* CVS/Root file: Specifying a repository.
+ (line 25)
+* CVS/Tag file: Working directory storage.
+ (line 156)
+* CVS/Template file: Working directory storage.
+ (line 198)
+* CVS_CLIENT_LOG, environment variable: Environment variables.
+ (line 105)
+* CVS_CLIENT_PORT: Environment variables.
+ (line 88)
+* CVS_IGNORE_REMOTE_ROOT, environment variable: Environment variables.
+ (line 116)
+* CVS_LOCAL_BRANCH_NUM, environment variable: Environment variables.
+ (line 122)
+* CVS_PASSFILE, environment variable: Password authentication client.
+ (line 46)
+* CVS_PID, environment variable: Environment variables.
+ (line 138)
+* CVS_PROXY_PORT <1>: Environment variables.
+ (line 94)
+* CVS_PROXY_PORT: The connection method.
+ (line 26)
+* CVS_RCMD_PORT, environment variable: Environment variables.
+ (line 100)
+* CVS_RSH method option: The connection method.
+ (line 51)
+* CVS_RSH, environment variable: Environment variables.
+ (line 70)
+* CVS_SERVER method option: The connection method.
+ (line 65)
+* CVS_SERVER, and :fork:: Connecting via fork. (line 24)
+* CVS_SERVER, environment variable: Connecting via rsh. (line 22)
+* CVS_SERVER_SLEEP, environment variable: Environment variables.
+ (line 111)
+* CVS_USER, environment variable: Variables. (line 83)
+* cvsadmin: admin. (line 18)
+* CVSEDITOR, environment variable <1>: Environment variables.
+ (line 48)
+* CVSEDITOR, environment variable: Committing your changes.
+ (line 17)
+* CVSEDITOR, internal variable: Variables. (line 37)
+* CVSHeader keyword: Keyword list. (line 11)
+* cvsignore (admin file), global: cvsignore. (line 6)
+* CVSIGNORE, environment variable: Environment variables.
+ (line 10)
+* CVSREAD, environment variable: Environment variables.
+ (line 18)
+* CVSREAD, overriding: Global options. (line 124)
+* CVSREADONLYFS, environment variable: Environment variables.
+ (line 24)
+* cvsroot: Repository. (line 6)
+* CVSROOT (file): Administrative files.
+ (line 6)
+* CVSROOT, environment variable: Specifying a repository.
+ (line 12)
+* CVSROOT, internal variable: Variables. (line 26)
+* CVSROOT, module name: Intro administrative files.
+ (line 6)
+* CVSROOT, multiple repositories: Multiple repositories.
+ (line 6)
+* CVSROOT, overriding: Global options. (line 53)
+* CVSROOT, storage of files: CVSROOT storage. (line 6)
+* CVSROOT/config: config. (line 6)
+* CVSROOT/Emptydir directory: Working directory storage.
+ (line 58)
+* CVSROOT/val-tags file, and read-only access to projects: File permissions.
+ (line 26)
+* CVSROOT/val-tags file, forcing tags into: Error messages. (line 202)
+* CVSUMASK, environment variable: File permissions. (line 35)
+* cvswrappers (admin file): Wrappers. (line 6)
+* CVSWRAPPERS, environment variable <1>: Environment variables.
+ (line 14)
+* CVSWRAPPERS, environment variable: Wrappers. (line 6)
+* date format, ISO 8601: Calendar date items. (line 30)
+* date input formats: Date input formats. (line 6)
+* Date keyword: Keyword list. (line 25)
+* Dates: Common options. (line 18)
+* day of week item: Day of week items. (line 6)
+* Dead state: Attic. (line 17)
+* Decimal revision number: Revision numbers. (line 6)
+* DEFAULT keyword, in lieu of regular expressions in script hooks: syntax.
+ (line 12)
+* Defining a module: Defining the module. (line 6)
+* Defining modules (intro): Intro administrative files.
+ (line 6)
+* Defining modules (reference manual): modules. (line 6)
+* Deleting branch tags: Modifying tags. (line 19)
+* Deleting files: Removing files. (line 6)
+* Deleting revisions: admin options. (line 95)
+* Deleting sticky tags: Sticky tags. (line 30)
+* Deleting tags: Modifying tags. (line 19)
+* Descending directories: Recursive behavior. (line 6)
+* Device nodes: Special Files. (line 6)
+* Diff: Viewing differences. (line 6)
+* diff (subcommand): diff. (line 6)
+* Differences, merging: Merging two revisions.
+ (line 6)
+* Directories, moving: Moving directories. (line 6)
+* Directories, removing: Removing directories.
+ (line 6)
+* Directory, descending: Recursive behavior. (line 6)
+* Disjoint repositories: Multiple repositories.
+ (line 6)
+* displacement of dates: Relative items in date strings.
+ (line 6)
+* Distributing log messages: loginfo. (line 6)
+* driver.c (merge example): Conflicts example. (line 6)
+* edit (subcommand): Editing files. (line 13)
+* Editing administrative files: Intro administrative files.
+ (line 33)
+* Editing the modules file: Defining the module. (line 6)
+* Editor, avoiding invocation of: Common options. (line 86)
+* EDITOR, environment variable <1>: Environment variables.
+ (line 49)
+* EDITOR, environment variable: Committing your changes.
+ (line 17)
+* EDITOR, internal variable: Variables. (line 38)
+* EDITOR, overriding: Global options. (line 58)
+* editors (subcommand): Watch information. (line 15)
+* Eggert, Paul: Authors of get_date. (line 6)
+* emerge: Conflicts example. (line 140)
+* Emptydir, in CVSROOT directory: Working directory storage.
+ (line 58)
+* Encryption: Global options. (line 130)
+* Entries file, in CVS directory: Working directory storage.
+ (line 60)
+* Entries.Backup file, in CVS directory: Working directory storage.
+ (line 143)
+* Entries.Log file, in CVS directory: Working directory storage.
+ (line 120)
+* Entries.Static file, in CVS directory: Working directory storage.
+ (line 148)
+* Environment variables: Environment variables.
+ (line 6)
+* environment variables, passed to administrative files: Variables.
+ (line 82)
+* epoch, for POSIX: Seconds since the Epoch.
+ (line 13)
+* Errors, reporting: BUGS. (line 13)
+* Example of a work-session: A sample session. (line 6)
+* Example of merge: Conflicts example. (line 6)
+* Example, branch merge: Merging a branch. (line 15)
+* Excluding directories, in modules file: Excluding directories.
+ (line 6)
+* Exit status, of commitinfo: commitinfo. (line 29)
+* Exit status, of CVS: Exit status. (line 6)
+* Exit status, of editor: Error messages. (line 333)
+* Exit status, of taginfo admin file: taginfo. (line 51)
+* Exit status, of verifymsg: verifymsg. (line 46)
+* export (subcommand): export. (line 6)
+* Export program: Module options. (line 12)
+* Fetching source: Getting the source. (line 6)
+* File had conflicts on merge: File status. (line 46)
+* File locking: Multiple developers. (line 6)
+* File permissions, general: File permissions. (line 6)
+* File permissions, Windows-specific: Windows permissions. (line 6)
+* File status: File status. (line 6)
+* Files, moving: Moving files. (line 6)
+* Files, reference manual: Administrative files.
+ (line 6)
+* Fixing a log message: admin options. (line 73)
+* Forcing a tag match: Common options. (line 43)
+* fork, access method: Connecting via fork. (line 6)
+* Form for log message: rcsinfo. (line 6)
+* Format of CVS commands: Structure. (line 6)
+* format strings: syntax. (line 35)
+* format strings, commitinfo admin file: commitinfo. (line 16)
+* format strings, common syntax: syntax. (line 35)
+* format strings, config admin file: config. (line 245)
+* format strings, loginfo admin file: loginfo. (line 34)
+* format strings, postadmin admin file: postadmin. (line 12)
+* format strings, postproxy admin file: postproxy. (line 23)
+* format strings, posttag admin file: posttag. (line 12)
+* format strings, postwatch admin file: postwatch. (line 13)
+* format strings, preproxy admin file: preproxy. (line 20)
+* format strings, taginfo admin file: taginfo. (line 12)
+* format strings, verifymsg admin file: verifymsg. (line 20)
+* general date syntax: General date syntax. (line 6)
+* Getting started: A sample session. (line 6)
+* Getting the source: Getting the source. (line 6)
+* Global cvsignore: cvsignore. (line 6)
+* Global options: Global options. (line 6)
+* Group, UNIX file permissions, in repository: File permissions.
+ (line 6)
+* gserver (client/server connection method), port specification <1>: Password authentication server.
+ (line 10)
+* gserver (client/server connection method), port specification: Remote repositories.
+ (line 6)
+* GSSAPI: GSSAPI authenticated.
+ (line 6)
+* Gzip <1>: Invoking CVS. (line 75)
+* Gzip: Global options. (line 140)
+* Hard links: Special Files. (line 6)
+* HEAD, as reserved tag name: Tags. (line 25)
+* HEAD, special tag: Common options. (line 122)
+* Header keyword: Keyword list. (line 28)
+* history (subcommand): history. (line 6)
+* History browsing: History browsing. (line 6)
+* History file: history file. (line 6)
+* History files: Repository files. (line 68)
+* History of CVS: What is CVS?. (line 28)
+* HistoryLogPath, in CVSROOT/config: config. (line 61)
+* HistorySearchPath, in CVSROOT/config: config. (line 70)
+* HOME, environment variable: Environment variables.
+ (line 59)
+* HOMEDRIVE, environment variable: Environment variables.
+ (line 62)
+* HOMEPATH, environment variable: Environment variables.
+ (line 60)
+* HTTP proxies, connecting via: The connection method.
+ (line 26)
+* Id keyword: Keyword list. (line 34)
+* Ident (shell command): Using keywords. (line 19)
+* Identifying a branch: Accessing branches. (line 6)
+* Identifying files: Keyword substitution.
+ (line 6)
+* Ignored files: cvsignore. (line 23)
+* Ignoring files: cvsignore. (line 6)
+* import (subcommand): import. (line 6)
+* import, config admin file: config. (line 90)
+* Importing files: From files. (line 6)
+* Importing files, from other version control systems: From other version control systems.
+ (line 6)
+* Importing modules: First import. (line 6)
+* ImportNewFilesToVendorBranchOnly, in CVSROOT/config: config.
+ (line 90)
+* Index: Index. (line 6)
+* inetd, configuring for pserver: Password authentication server.
+ (line 10)
+* info files: Trigger Scripts. (line 6)
+* info files, commitinfo: commitinfo. (line 6)
+* info files, common syntax: syntax. (line 6)
+* info files, common syntax, format strings: syntax. (line 35)
+* info files, common syntax, updating legacy repositories: Updating Commit Files.
+ (line 6)
+* info files, precommit verification of commits: commitinfo. (line 6)
+* info files, security: Trigger Script Security.
+ (line 6)
+* Informing others: Informing others. (line 6)
+* init (subcommand): Creating a repository.
+ (line 35)
+* Installed images (VMS): File permissions. (line 59)
+* Internal variables: Variables. (line 6)
+* Introduction to CVS: What is CVS?. (line 6)
+* Invoking CVS: Invoking CVS. (line 6)
+* ISO 8601 date format: Calendar date items. (line 30)
+* Isolation: History browsing. (line 6)
+* items in date strings: General date syntax. (line 6)
+* Join: Merging a branch. (line 13)
+* Keeping a checked out copy: Keeping a checked out copy.
+ (line 6)
+* Kerberos, using :gserver:: GSSAPI authenticated.
+ (line 6)
+* Kerberos, using :kserver:: Kerberos authenticated.
+ (line 6)
+* Kerberos, using kerberized rsh: Connecting via rsh. (line 35)
+* Keyword expansion: Keyword substitution.
+ (line 6)
+* Keyword List: Keyword list. (line 6)
+* Keyword substitution: Keyword substitution.
+ (line 6)
+* Keyword substitution, and merging: Merging and keywords.
+ (line 6)
+* Keyword substitution, changing modes: Substitution modes. (line 6)
+* KeywordExpand, in CVSROOT/config: config. (line 97)
+* Kflag: Substitution modes. (line 6)
+* kinit: Kerberos authenticated.
+ (line 27)
+* Known bugs in this manual or CVS: BUGS. (line 71)
+* kserver (client/server connection method), port specification <1>: Password authentication server.
+ (line 10)
+* kserver (client/server connection method), port specification: Remote repositories.
+ (line 6)
+* language, in dates: General date syntax. (line 40)
+* Layout of repository: Repository. (line 6)
+* Left-hand options: Global options. (line 6)
+* Linear development: Revision numbers. (line 6)
+* Link, symbolic, importing: import output. (line 23)
+* List, mailing list: What is CVS?. (line 44)
+* Local keyword: Keyword list. (line 97)
+* LocalKeyword, in CVSROOT/config: config. (line 104)
+* Locally Added: File status. (line 19)
+* Locally Modified: File status. (line 16)
+* Locally Removed: File status. (line 23)
+* LockDir, in CVSROOT/config: config. (line 109)
+* Locker keyword: Keyword list. (line 43)
+* Locking files: Multiple developers. (line 6)
+* Locks, cvs, and backups: Backing up. (line 10)
+* Locks, cvs, introduction: Concurrency. (line 6)
+* Locks, cvs, technical details: Locks. (line 6)
+* log (subcommand): log. (line 6)
+* Log information, saving: history file. (line 6)
+* Log keyword: Keyword list. (line 47)
+* Log keyword, configuring substitution behavior <1>: config. (line 137)
+* Log keyword, configuring substitution behavior: Keyword list.
+ (line 47)
+* Log message entry: Committing your changes.
+ (line 6)
+* Log message template: rcsinfo. (line 6)
+* Log message, correcting: admin options. (line 73)
+* Log message, verifying: verifymsg. (line 6)
+* Log messages: loginfo. (line 6)
+* logging, commits <1>: rcsinfo. (line 6)
+* logging, commits <2>: loginfo. (line 6)
+* logging, commits: verifymsg. (line 6)
+* LogHistory, in CVSROOT/config: config. (line 129)
+* Login (subcommand): Password authentication client.
+ (line 6)
+* loginfo (admin file): loginfo. (line 6)
+* loginfo (admin file), updating legacy repositories: loginfo.
+ (line 55)
+* LOGNAME, environment variable: Variables. (line 90)
+* Logout (subcommand): Password authentication client.
+ (line 70)
+* ls (subcommand): ls & rls. (line 6)
+* MacKenzie, David: Authors of get_date. (line 6)
+* Mail, automatic mail on commit: Informing others. (line 6)
+* Mailing list: What is CVS?. (line 44)
+* Mailing log messages: loginfo. (line 6)
+* Main trunk and branches: Branching and merging.
+ (line 6)
+* make: Builds. (line 6)
+* Many repositories: Multiple repositories.
+ (line 6)
+* Markers, conflict: Conflicts example. (line 96)
+* MaxCommentLeaderLength: Keyword list. (line 47)
+* MaxCommentLeaderLength, in CVSROOT/config: config. (line 137)
+* MaxCompressionLevel, in CVSROOT/config: config. (line 149)
+* Merge, an example: Conflicts example. (line 6)
+* Merge, branch example: Merging a branch. (line 15)
+* Merging: Branching and merging.
+ (line 6)
+* Merging a branch: Merging a branch. (line 6)
+* Merging a file: Updating a file. (line 6)
+* Merging two revisions: Merging two revisions.
+ (line 6)
+* Merging, and keyword substitution: Merging and keywords.
+ (line 6)
+* Meyering, Jim: Authors of get_date. (line 6)
+* MinCompressionLevel, in CVSROOT/config: config. (line 149)
+* minutes, time zone correction by: Time of day items. (line 29)
+* mkmodules: Error messages. (line 170)
+* Modifications, copying between branches: Branching and merging.
+ (line 6)
+* Module status: Module options. (line 22)
+* Module, defining: Defining the module. (line 6)
+* Modules (admin file): modules. (line 6)
+* Modules file: Intro administrative files.
+ (line 6)
+* Modules file program options: Module program options.
+ (line 6)
+* Modules file, changing: Defining the module. (line 6)
+* modules.db: CVSROOT storage. (line 25)
+* modules.dir: CVSROOT storage. (line 25)
+* modules.pag: CVSROOT storage. (line 25)
+* month names in date strings: Calendar date items. (line 38)
+* months, written-out: General date syntax. (line 36)
+* Motivation for branches: Branches motivation. (line 6)
+* Moving a repository: Moving a repository. (line 6)
+* Moving branch tags: Modifying tags. (line 37)
+* Moving directories: Moving directories. (line 6)
+* Moving files: Moving files. (line 6)
+* Moving tags: Modifying tags. (line 37)
+* Multiple developers: Multiple developers. (line 6)
+* Multiple repositories: Multiple repositories.
+ (line 6)
+* Name keyword: Keyword list. (line 37)
+* Name, symbolic (tag): Tags. (line 25)
+* Needs Checkout: File status. (line 27)
+* Needs Merge: File status. (line 37)
+* Needs Patch: File status. (line 32)
+* Newsgroups: What is CVS?. (line 44)
+* notify (admin file): Getting Notified. (line 60)
+* Notify file, in CVS directory: Working directory storage.
+ (line 167)
+* Notify.tmp file, in CVS directory: Working directory storage.
+ (line 172)
+* Number, branch <1>: Branches and revisions.
+ (line 6)
+* Number, branch: Revision numbers. (line 6)
+* Number, revision-: Revision numbers. (line 6)
+* numbers, written-out: General date syntax. (line 26)
+* Option defaults: ~/.cvsrc. (line 6)
+* options, connection method: The connection method.
+ (line 16)
+* Options, global: Global options. (line 6)
+* Options, in modules file: Module options. (line 6)
+* ordinal numbers: General date syntax. (line 26)
+* Outdating revisions: admin options. (line 95)
+* Overlap: Updating a file. (line 24)
+* Overriding CVSREAD: Global options. (line 124)
+* Overriding CVSROOT: Global options. (line 53)
+* Overriding EDITOR: Global options. (line 58)
+* Overriding RCSBIN: Global options. (line 24)
+* Overview: Overview. (line 6)
+* Ownership, saving in CVS: Special Files. (line 6)
+* Parallel repositories: Multiple repositories.
+ (line 6)
+* passwd (admin file): Password authentication server.
+ (line 67)
+* Password client, using: Password authentication client.
+ (line 6)
+* Password server, setting up: Password authentication server.
+ (line 10)
+* PATH, environment variable: Environment variables.
+ (line 55)
+* Per-directory sticky tags/dates: Working directory storage.
+ (line 156)
+* Permissions, general: File permissions. (line 6)
+* Permissions, saving in CVS: Special Files. (line 6)
+* Permissions, Windows-specific: Windows permissions. (line 6)
+* Pinard, F.: Authors of get_date. (line 14)
+* Policy: When to commit. (line 6)
+* port, specifying for remote repositories <1>: Password authentication server.
+ (line 10)
+* port, specifying for remote repositories: Remote repositories.
+ (line 6)
+* postadmin (admin file): postadmin. (line 6)
+* postproxy (admin file): postproxy. (line 6)
+* posttag (admin file): posttag. (line 6)
+* postwatch (admin file): postwatch. (line 6)
+* preproxy (admin file): preproxy. (line 6)
+* Primary server <1>: config. (line 168)
+* Primary server: Write proxies. (line 6)
+* PrimaryServer, in CVSROOT/config <1>: config. (line 168)
+* PrimaryServer, in CVSROOT/config: Write proxies. (line 6)
+* proxies, HTTP, connecting via: The connection method.
+ (line 26)
+* proxies, web, connecting via: The connection method.
+ (line 26)
+* proxy, method option: The connection method.
+ (line 26)
+* proxy, write <1>: config. (line 168)
+* proxy, write: Write proxies. (line 6)
+* proxyport, method option: The connection method.
+ (line 26)
+* pserver (client/server connection method), port specification <1>: Password authentication server.
+ (line 10)
+* pserver (client/server connection method), port specification: Remote repositories.
+ (line 6)
+* pserver (subcommand) <1>: server & pserver. (line 6)
+* pserver (subcommand): Password authentication server.
+ (line 10)
+* pure numbers in date strings: Pure numbers in date strings.
+ (line 6)
+* PVCS, importing files from: From other version control systems.
+ (line 45)
+* RCS history files: Repository files. (line 68)
+* RCS revision numbers: Tags. (line 10)
+* RCS, importing files from: From other version control systems.
+ (line 10)
+* RCS-style locking: Multiple developers. (line 6)
+* RCSBIN, in CVSROOT/config: config. (line 186)
+* RCSBIN, internal variable: Variables. (line 32)
+* RCSBIN, overriding: Global options. (line 24)
+* RCSfile keyword: Keyword list. (line 84)
+* rcsinfo (admin file): rcsinfo. (line 6)
+* rdiff (subcommand): rdiff. (line 6)
+* Read-only files, and -r: Global options. (line 105)
+* Read-only files, and CVSREAD: Environment variables.
+ (line 18)
+* Read-only files, and watches: Setting a watch. (line 10)
+* Read-only files, in repository: File permissions. (line 6)
+* Read-only mode: Global options. (line 86)
+* Read-only repository access: Read-only access. (line 6)
+* Read-only repository mode: Global options. (line 78)
+* readers (admin file): Read-only access. (line 6)
+* Recursive (directory descending): Recursive behavior. (line 6)
+* Redirect, method option: The connection method.
+ (line 86)
+* Reference manual (files): Administrative files.
+ (line 6)
+* Reference manual for variables: Environment variables.
+ (line 6)
+* Reference, commands: Invoking CVS. (line 6)
+* Regular expression syntax: syntax. (line 10)
+* Regular modules: Regular modules. (line 6)
+* relative items in date strings: Relative items in date strings.
+ (line 6)
+* release (subcommand): release. (line 6)
+* Releases, revisions and versions: Versions revisions releases.
+ (line 6)
+* Releasing your working copy: Cleaning up. (line 6)
+* Remote repositories: Remote repositories. (line 6)
+* Remote repositories, port specification <1>: Password authentication server.
+ (line 10)
+* Remote repositories, port specification: Remote repositories.
+ (line 6)
+* Remove (subcommand): Removing files. (line 34)
+* Removing a change: Merging two revisions.
+ (line 9)
+* Removing branch tags: Modifying tags. (line 19)
+* Removing directories: Removing directories.
+ (line 6)
+* Removing files: Removing files. (line 6)
+* Removing tags: Modifying tags. (line 19)
+* Removing your working copy: Cleaning up. (line 6)
+* Renaming directories: Moving directories. (line 6)
+* Renaming files: Moving files. (line 6)
+* Renaming tags: Modifying tags. (line 57)
+* Replacing a log message: admin options. (line 73)
+* Reporting bugs: BUGS. (line 13)
+* Repositories, multiple: Multiple repositories.
+ (line 6)
+* Repositories, remote: Remote repositories. (line 6)
+* Repositories, remote, port specification <1>: Password authentication server.
+ (line 10)
+* Repositories, remote, port specification: Remote repositories.
+ (line 6)
+* Repository (intro): Repository. (line 6)
+* Repository file, in CVS directory: Working directory storage.
+ (line 32)
+* Repository, backing up: Backing up. (line 6)
+* Repository, example: Repository. (line 6)
+* Repository, how data is stored: Repository storage. (line 6)
+* Repository, moving: Moving a repository. (line 6)
+* Repository, setting up: Creating a repository.
+ (line 6)
+* RereadLogAfterVerify, in CVSROOT/config: config. (line 192)
+* Reserved checkouts: Multiple developers. (line 6)
+* Resetting sticky tags: Sticky tags. (line 30)
+* Resolving a conflict: Conflicts example. (line 101)
+* Restoring old version of removed file: Merging two revisions.
+ (line 19)
+* Resurrecting old version of dead file: Merging two revisions.
+ (line 19)
+* Retrieve a branch: Accessing branches. (line 6)
+* Retrieving an old revision using tags: Tags. (line 84)
+* Reverting to repository version: Editing files. (line 42)
+* Revision keyword: Keyword list. (line 87)
+* Revision management: Revision management. (line 6)
+* Revision numbers: Revision numbers. (line 6)
+* Revision numbers (branches): Branches and revisions.
+ (line 6)
+* Revision tree: Revision numbers. (line 6)
+* Revision tree, making branches: Branching and merging.
+ (line 6)
+* Revisions, merging differences between: Merging two revisions.
+ (line 6)
+* Revisions, versions and releases: Versions revisions releases.
+ (line 6)
+* Right-hand options: Common options. (line 6)
+* rls (subcommand): ls & rls. (line 6)
+* Root file, in CVS directory: Specifying a repository.
+ (line 25)
+* rsh: Connecting via rsh. (line 6)
+* rsh replacements (Kerberized, SSH, &c): Connecting via rsh. (line 35)
+* rtag (subcommand): Tagging by date/tag. (line 6)
+* rtag (subcommand), creating a branch using: Creating a branch.
+ (line 6)
+* Salz, Rich: Authors of get_date. (line 6)
+* Saving space: admin options. (line 95)
+* SCCS, importing files from: From other version control systems.
+ (line 38)
+* script hook, postadmin: postadmin. (line 6)
+* script hook, postproxy: postproxy. (line 6)
+* script hook, posttag: posttag. (line 6)
+* script hook, postwatch: postwatch. (line 6)
+* script hook, preproxy: preproxy. (line 6)
+* script hook, taginfo: taginfo. (line 6)
+* script hooks: Trigger Scripts. (line 6)
+* script hooks, commitinfo: commitinfo. (line 6)
+* script hooks, common syntax: syntax. (line 6)
+* script hooks, precommit verification of commits: commitinfo.
+ (line 6)
+* script hooks, security: Trigger Script Security.
+ (line 6)
+* Secondary server <1>: config. (line 168)
+* Secondary server: Write proxies. (line 6)
+* secondary server, pull updates: postproxy. (line 6)
+* Security, file permissions in repository: File permissions. (line 6)
+* Security, GSSAPI: GSSAPI authenticated.
+ (line 6)
+* Security, Kerberos: Kerberos authenticated.
+ (line 6)
+* Security, of pserver: Password authentication security.
+ (line 6)
+* Security, setuid: File permissions. (line 59)
+* server (subcommand): server & pserver. (line 6)
+* Server, CVS: Remote repositories. (line 6)
+* Server, temporary directories: Server temporary directory.
+ (line 6)
+* Setgid: File permissions. (line 59)
+* Setting up a repository: Creating a repository.
+ (line 6)
+* Setuid: File permissions. (line 59)
+* Source keyword: Keyword list. (line 90)
+* Source, getting CVS source: What is CVS?. (line 38)
+* Source, getting from CVS: Getting the source. (line 6)
+* Special files: Special Files. (line 6)
+* Specifying dates: Common options. (line 18)
+* Spreading information: Informing others. (line 6)
+* SSH (rsh replacement): Connecting via rsh. (line 35)
+* Starting a project with CVS: Starting a new project.
+ (line 6)
+* State keyword: Keyword list. (line 93)
+* Status of a file: File status. (line 6)
+* Status of a module: Module options. (line 22)
+* Sticky date: Sticky tags. (line 36)
+* Sticky tags: Sticky tags. (line 6)
+* Sticky tags, resetting: Sticky tags. (line 30)
+* Sticky tags/dates, per-directory: Working directory storage.
+ (line 156)
+* Storing log messages: loginfo. (line 6)
+* Stream authentication: Global options. (line 16)
+* Structure: Structure. (line 6)
+* Subdirectories: Recursive behavior. (line 6)
+* Support, getting CVS support: BUGS. (line 17)
+* Symbolic link, importing: import output. (line 23)
+* Symbolic links: Special Files. (line 6)
+* Symbolic name (tag): Tags. (line 25)
+* Syntax of info files, updating legacy repositories: Updating Commit Files.
+ (line 6)
+* syntax of trigger script hooks: syntax. (line 6)
+* SystemAuth, in CVSROOT/config: config. (line 209)
+* tag (subcommand): Tagging the working directory.
+ (line 6)
+* tag (subcommand), creating a branch using: Creating a branch.
+ (line 6)
+* tag (subcommand), introduction: Tags. (line 25)
+* Tag file, in CVS directory: Working directory storage.
+ (line 156)
+* Tag program: Module options. (line 30)
+* taginfo (admin file): taginfo. (line 6)
+* taginfo (admin file), exit status: taginfo. (line 51)
+* taginfo (admin file), updating legacy repositories: taginfo.
+ (line 44)
+* Tags: Tags. (line 6)
+* Tags, deleting: Modifying tags. (line 19)
+* Tags, example: Tags. (line 45)
+* Tags, logging <1>: posttag. (line 6)
+* Tags, logging: taginfo. (line 6)
+* Tags, moving: Modifying tags. (line 37)
+* Tags, renaming: Modifying tags. (line 57)
+* Tags, retrieving old revisions: Tags. (line 84)
+* Tags, sticky: Sticky tags. (line 6)
+* Tags, symbolic name: Tags. (line 25)
+* Tags, verifying: taginfo. (line 6)
+* tc, Trivial Compiler (example): A sample session. (line 6)
+* Team of developers: Multiple developers. (line 6)
+* Template file, in CVS directory: Working directory storage.
+ (line 198)
+* Template for log message: rcsinfo. (line 6)
+* Temporary directories, and server: Server temporary directory.
+ (line 6)
+* temporary directory, set in config: config. (line 216)
+* temporary file directory, set via command line: Global options.
+ (line 30)
+* temporary file directory, set via config: Global options. (line 30)
+* temporary file directory, set via environment variable <1>: Environment variables.
+ (line 134)
+* temporary file directory, set via environment variable: Global options.
+ (line 30)
+* temporary files, location of <1>: Environment variables.
+ (line 134)
+* temporary files, location of <2>: config. (line 216)
+* temporary files, location of: Global options. (line 30)
+* Third-party sources: Tracking sources. (line 6)
+* Time: Common options. (line 18)
+* time of day item: Time of day items. (line 6)
+* time zone correction: Time of day items. (line 29)
+* time zone item <1>: Time zone items. (line 6)
+* time zone item: General date syntax. (line 44)
+* Timezone, in output <1>: log examples. (line 6)
+* Timezone, in output: log. (line 17)
+* TMPDIR, environment variable <1>: Environment variables.
+ (line 134)
+* TMPDIR, environment variable: Global options. (line 30)
+* TmpDir, in config: config. (line 216)
+* TopLevelAdmin, in CVSROOT/config: config. (line 221)
+* Trace: Global options. (line 114)
+* Traceability: History browsing. (line 6)
+* Tracking sources: Tracking sources. (line 6)
+* Transactions, atomic, lack of: Concurrency. (line 27)
+* trigger script hooks, common syntax: syntax. (line 6)
+* trigger scripts: Trigger Scripts. (line 6)
+* trigger scripts, commitinfo: commitinfo. (line 6)
+* trigger scripts, precommit verification of commits: commitinfo.
+ (line 6)
+* trigger scripts, security: Trigger Script Security.
+ (line 6)
+* Trivial Compiler (example): A sample session. (line 6)
+* Typical repository: Repository. (line 6)
+* Umask, for repository files: File permissions. (line 35)
+* Undoing a change: Merging two revisions.
+ (line 9)
+* unedit (subcommand): Editing files. (line 42)
+* Unknown: File status. (line 52)
+* Unreserved checkouts: Multiple developers. (line 6)
+* Unresolved Conflict: File status. (line 41)
+* Up-to-date: File status. (line 11)
+* update (subcommand): update. (line 6)
+* Update, introduction: Updating a file. (line 6)
+* update, to display file status: File status. (line 75)
+* Updating a file: Updating a file. (line 6)
+* UseArchiveCommentLeader: Keyword list. (line 47)
+* UseArchiveCommentLeader, in CVSROOT/config: config. (line 234)
+* UseNewInfoFmtStrings, in CVSROOT/config: config. (line 245)
+* User aliases: Password authentication server.
+ (line 96)
+* User variables: Variables. (line 62)
+* USER, environment variable: Variables. (line 93)
+* USER, internal variable: Variables. (line 43)
+* UserAdminOptions, in CVSROOT/config <1>: config. (line 257)
+* UserAdminOptions, in CVSROOT/config: admin. (line 18)
+* users (admin file): Getting Notified. (line 75)
+* val-tags file, and read-only access to projects: File permissions.
+ (line 26)
+* val-tags file, forcing tags into: Error messages. (line 202)
+* Variables: Variables. (line 6)
+* Vendor: Tracking sources. (line 10)
+* Vendor branch: Tracking sources. (line 10)
+* verifymsg (admin file): verifymsg. (line 6)
+* verifymsg (admin/commit file), updating legacy repositories: verifymsg.
+ (line 34)
+* verifymsg, changing the log message <1>: config. (line 192)
+* verifymsg, changing the log message: verifymsg. (line 49)
+* verifymsg, example: verifymsg example. (line 6)
+* version (subcommand): Invoking CVS. (line 821)
+* Versions, of CVS: Compatibility. (line 6)
+* Versions, revisions and releases: Versions revisions releases.
+ (line 6)
+* Viewing differences: Viewing differences. (line 6)
+* VISUAL, environment variable <1>: Environment variables.
+ (line 50)
+* VISUAL, environment variable: Committing your changes.
+ (line 23)
+* VISUAL, internal variable: Variables. (line 39)
+* watch add (subcommand): Getting Notified. (line 11)
+* Watch family of commands, logging: postwatch. (line 6)
+* watch off (subcommand): Setting a watch. (line 26)
+* watch on (subcommand): Setting a watch. (line 9)
+* watch remove (subcommand): Getting Notified. (line 54)
+* watchers (subcommand): Watch information. (line 6)
+* Watches: Watches. (line 6)
+* wdiff (import example): First import. (line 19)
+* Web pages, maintaining with CVS: Keeping a checked out copy.
+ (line 6)
+* web proxies, connecting via: The connection method.
+ (line 26)
+* What (shell command): Using keywords. (line 32)
+* What branches are good for: Branches motivation. (line 6)
+* What is CVS not?: What is CVS not?. (line 6)
+* What is CVS?: What is CVS?. (line 6)
+* When to commit: When to commit. (line 6)
+* Windows, and permissions: Windows permissions. (line 6)
+* Work-session, example of: A sample session. (line 6)
+* Working copy: Multiple developers. (line 6)
+* Working copy, removing: Cleaning up. (line 6)
+* Wrappers: Wrappers. (line 6)
+* write proxy <1>: config. (line 168)
+* write proxy: Write proxies. (line 6)
+* Write proxy, logging <1>: postproxy. (line 6)
+* Write proxy, logging: preproxy. (line 6)
+* Write proxy, pull updates: postproxy. (line 6)
+* Write proxy, verifying: preproxy. (line 6)
+* writers (admin file): Read-only access. (line 6)
+* Ximbiot: BUGS. (line 17)
+* xinetd, configuring for pserver: Password authentication server.
+ (line 10)
+* Zone, time, in output <1>: log examples. (line 6)
+* Zone, time, in output: log. (line 17)
+
+
diff --git a/doc/cvs.man.footer b/doc/cvs.man.footer
new file mode 100644
index 0000000..2987e1a
--- /dev/null
+++ b/doc/cvs.man.footer
@@ -0,0 +1,58 @@
+.SH "AUTHORS"
+.TP
+Dick Grune
+Original author of the
+.B cvs
+shell script version posted to
+.B comp.sources.unix
+in the volume6 release of December, 1986.
+Credited with much of the
+.B cvs
+conflict resolution algorithms.
+.TP
+Brian Berliner
+Coder and designer of the
+.B cvs
+program itself in April, 1989, based on the original work done by Dick.
+.TP
+Jeff Polk
+Helped Brian with the design of the
+.B cvs
+module and vendor branch support and author of the
+.BR checkin ( 1 )
+shell script (the ancestor of \fBcvs import\fP).
+.TP
+Larry Jones, Derek R. Price, and Mark D. Baushke
+Have helped maintain
+.B cvs
+for many years.
+.TP
+And many others too numerous to mention here.
+.SH "SEE ALSO"
+The most comprehensive manual for CVS is
+Version Management with CVS by Per Cederqvist et al. Depending on
+your system, you may be able to get it with the
+.B info CVS
+command or it may be available as cvs.pdf (Portable Document Format),
+cvs.ps (PostScript), cvs.texinfo (Texinfo source), or cvs.html.
+.SP
+For CVS updates, more information on documentation, software related
+to CVS, development of CVS, and more, see:
+.in +1i
+.SP
+.PD 0
+.IP "" 4
+.B http://www.nongnu.org/cvs/
+.in -1i
+.SP
+.BR ci ( 1 ),
+.BR co ( 1 ),
+.BR cvs ( 5 ),
+.BR cvsbug ( 8 ),
+.BR diff ( 1 ),
+.BR grep ( 1 ),
+.BR patch ( 1 ),
+.BR rcs ( 1 ),
+.BR rcsdiff ( 1 ),
+.BR rcsmerge ( 1 ),
+.BR rlog ( 1 ).
diff --git a/doc/cvs.man.header b/doc/cvs.man.header
new file mode 100644
index 0000000..cbc4f7d
--- /dev/null
+++ b/doc/cvs.man.header
@@ -0,0 +1,61 @@
+.\" This is the man page for CVS. It is auto-generated from the
+.\" cvs.man.header, cvs.texinfo, & cvs.man.footer files. Please make changes
+.\" there. A full copyright & license notice may also be found in cvs.texinfo.
+.\"
+.\" Man page autogeneration, including this header file, is
+.\" Copyright 2004-2005 The Free Software Foundation, Inc.,
+.\" Derek R. Price, & Ximbiot <http://ximbiot.com>.
+.\"
+.\" This documentation is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2, or (at your option)
+.\" any later version.
+.\"
+.\" This documentation is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this documentation; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.TH CVS 1 "\*(Dt"
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.\" quoted command
+.de `
+.RB ` "\|\\$1\|" '\\$2
+..
+.SH "NAME"
+cvs \- Concurrent Versions System
+.SH "SYNOPSIS"
+.TP
+\fBcvs\fP [ \fIcvs_options\fP ]
+.I cvs_command
+[
+.I command_options
+] [
+.I command_args
+]
+.SH "NOTE"
+.IX "revision control system" "\fLcvs\fR"
+.IX cvs "" "\fLcvs\fP \- concurrent versions system"
+.IX "concurrent versions system \- \fLcvs\fP"
+.IX "release control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system"
+.IX "source control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system"
+.IX revisions "cvs command" "" "\fLcvs\fP \- source control"
+This manpage is a summary of some of the features of
+\fBcvs\fP. It is auto-generated from an appendix of the CVS manual.
+For more in-depth documentation, please consult the
+Cederqvist manual (via the
+.B info CVS
+command or otherwise,
+as described in the SEE ALSO section of this manpage). Cross-references
+in this man page refer to nodes in the same.
diff --git a/doc/cvs.pdf b/doc/cvs.pdf
new file mode 100644
index 0000000..0facba6
--- /dev/null
+++ b/doc/cvs.pdf
Binary files differ
diff --git a/doc/cvs.texinfo b/doc/cvs.texinfo
new file mode 100644
index 0000000..b975de8
--- /dev/null
+++ b/doc/cvs.texinfo
@@ -0,0 +1,15923 @@
+\input texinfo @c -*-texinfo-*-
+@comment Documentation for CVS.
+@setfilename cvs.info
+@macro copyleftnotice
+@noindent
+Copyright @copyright{} 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+
+@multitable @columnfractions .12 .88
+@item Portions
+@item @tab Copyright @copyright{} 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Derek R. Price,
+@item @tab Copyright @copyright{} 2002, 2003, 2004, 2005
+ Ximbiot @url{http://ximbiot.com},
+@item @tab Copyright @copyright{} 1992, 1993, 1999 Signum Support AB,
+@item @tab and Copyright @copyright{} others.
+@end multitable
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+@end macro
+
+@comment This file is part of the CVS distribution.
+
+@comment CVS is free software; you can redistribute it and/or modify
+@comment it under the terms of the GNU General Public License as published by
+@comment the Free Software Foundation; either version 2, or (at your option)
+@comment any later version.
+
+@comment CVS is distributed in the hope that it will be useful,
+@comment but WITHOUT ANY WARRANTY; without even the implied warranty of
+@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+@comment GNU General Public License for more details.
+
+@c See ../README for A4 vs. US letter size.
+@c When we provided A4 postscript, and people tried to
+@c print it on US letter, the usual complaint was that the
+@c page numbers would get cut off.
+@c If one prints US letter on A4, reportedly there is
+@c some extra space at the top and/or bottom, and the side
+@c margins are a bit narrow, but no text is lost.
+@c
+@c See
+@c http://www.ft.uni-erlangen.de/~mskuhn/iso-paper.html
+@c for more on paper sizes. Insuring that margins are
+@c big enough to print on either A4 or US letter does
+@c indeed seem to be the usual approach (RFC2346).
+
+@c This document seems to get overfull hboxes with some
+@c frequency (probably because the tendency is to
+@c sanity-check it with "make info" and run TeX less
+@c often). The big ugly boxes just seem to add insult
+@c to injury, and I'm not aware of them helping to fix
+@c the overfull hboxes at all.
+@finalout
+
+@include version.texi
+@settitle CVS---Concurrent Versions System v@value{VERSION}
+@setchapternewpage odd
+
+@c -- TODO list:
+@c -- Fix all lines that match "^@c -- "
+@c -- Also places marked with FIXME should be manual
+@c problems (as opposed to FIXCVS for CVS problems).
+
+@c @splitrcskeyword{} is used to avoid keyword expansion. It is replaced by
+@c @asis when generating info and dvi, and by <i></i> in the generated html,
+@c such that keywords are not expanded in the generated html.
+@ifnothtml
+@macro splitrcskeyword {arg}
+@asis{}\arg\
+@end macro
+@end ifnothtml
+
+@ifhtml
+@macro splitrcskeyword {arg}
+@i{}\arg\
+@end macro
+@end ifhtml
+
+@dircategory GNU Packages
+@direntry
+* CVS: (cvs). Concurrent Versions System
+@end direntry
+@dircategory Individual utilities
+@direntry
+* cvs: (cvs)CVS commands. Concurrent Versions System
+@end direntry
+
+@comment The titlepage section does not appear in the Info file.
+@titlepage
+@sp 4
+@comment The title is printed in a large font.
+@center @titlefont{Version Management}
+@sp
+@center @titlefont{with}
+@sp
+@center @titlefont{CVS}
+@sp 2
+@center for @sc{cvs} @value{VERSION}
+@comment -release-
+@sp 3
+@center Per Cederqvist et al
+
+@comment The following two commands start the copyright page
+@comment for the printed manual. This will not appear in the Info file.
+@page
+@vskip 0pt plus 1filll
+@copyleftnotice
+@end titlepage
+
+@summarycontents
+
+@contents
+
+@comment ================================================================
+@comment The real text starts here
+@comment ================================================================
+
+@ifnottex
+@c ---------------------------------------------------------------------
+@node Top
+@top
+
+This info manual describes how to use and administer
+@sc{cvs} version @value{VERSION}.
+@end ifnottex
+
+@ifinfo
+@copyleftnotice
+@end ifinfo
+
+@c This menu is pretty long. Not sure how easily that
+@c can be fixed (no brilliant ideas right away)...
+@menu
+* Overview:: An introduction to CVS
+* Repository:: Where all your sources are stored
+* Starting a new project:: Starting a project with CVS
+* Revisions:: Numeric and symbolic names for revisions
+* Branching and merging:: Diverging/rejoining branches of development
+* Recursive behavior:: CVS descends directories
+* Adding and removing:: Adding/removing/renaming files/directories
+* History browsing:: Viewing the history of files in various ways
+
+CVS and the Real World.
+-----------------------
+* Binary files:: CVS can handle binary files
+* Multiple developers:: How CVS helps a group of developers
+* Revision management:: Policy questions for revision management
+* Keyword substitution:: CVS can include the revision inside the file
+* Tracking sources:: Tracking third-party sources
+* Builds:: Issues related to CVS and builds
+* Special Files:: Devices, links and other non-regular files
+
+References.
+-----------
+* CVS commands:: CVS commands share some things
+* Invoking CVS:: Quick reference to CVS commands
+* Administrative files:: Reference manual for the Administrative files
+* Environment variables:: All environment variables which affect CVS
+* Compatibility:: Upgrading CVS versions
+* Troubleshooting:: Some tips when nothing works
+* Credits:: Some of the contributors to this manual
+* BUGS:: Dealing with bugs in CVS or this manual
+* Index:: Index
+@end menu
+
+@c ---------------------------------------------------------------------
+@node Overview
+@chapter Overview
+@cindex Overview
+
+This chapter is for people who have never used
+@sc{cvs}, and perhaps have never used version control
+software before.
+
+If you are already familiar with @sc{cvs} and are just
+trying to learn a particular feature or remember a
+certain command, you can probably skip everything here.
+
+@menu
+* What is CVS?:: What you can do with @sc{cvs}
+* What is CVS not?:: Problems @sc{cvs} doesn't try to solve
+* A sample session:: A tour of basic @sc{cvs} usage
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node What is CVS?
+@section What is CVS?
+@cindex What is CVS?
+@cindex Introduction to CVS
+@cindex CVS, introduction to
+
+@sc{cvs} is a version control system. Using it, you can
+record the history of your source files.
+
+@c -- ///
+@c -- ///Those who cannot remember the past are condemned to repeat it.
+@c -- /// -- George Santayana
+@c -- //////
+
+@c -- Insert history quote here!
+For example, bugs sometimes creep in when
+software is modified, and you might not detect the bug
+until a long time after you make the modification.
+With @sc{cvs}, you can easily retrieve old versions to see
+exactly which change caused the bug. This can
+sometimes be a big help.
+
+You could of course save every version of every file
+you have ever created. This would
+however waste an enormous amount of disk space. @sc{cvs}
+stores all the versions of a file in a single file in a
+clever way that only stores the differences between
+versions.
+
+@sc{cvs} also helps you if you are part of a group of people working
+on the same project. It is all too easy to overwrite
+each others' changes unless you are extremely careful.
+Some editors, like @sc{gnu} Emacs, try to make sure that
+two people never modify the same file at the
+same time. Unfortunately, if someone is using another
+editor, that safeguard will not work. @sc{cvs} solves this problem
+by insulating the different developers from each other. Every
+developer works in his own directory, and @sc{cvs} merges
+the work when each developer is done.
+
+@cindex History of CVS
+@cindex CVS, history of
+@cindex Credits (CVS program)
+@cindex Contributors (CVS program)
+@sc{cvs} started out as a bunch of shell scripts written by
+Dick Grune, posted to the newsgroup
+@code{comp.sources.unix} in the volume 6
+release of July, 1986. While no actual code from
+these shell scripts is present in the current version
+of @sc{cvs} much of the @sc{cvs} conflict resolution algorithms
+come from them.
+
+In April, 1989, Brian Berliner designed and coded @sc{cvs}.
+Jeff Polk later helped Brian with the design of the @sc{cvs}
+module and vendor branch support.
+
+@cindex Source, getting CVS source
+You can get @sc{cvs} in a variety of ways, including
+free download from the Internet. For more information
+on downloading @sc{cvs} and other @sc{cvs} topics, see:
+
+@example
+@url{http://cvs.nongnu.org/}
+@end example
+
+@cindex Mailing list
+@cindex List, mailing list
+@cindex Newsgroups
+There is a mailing list, known as @email{info-cvs@@nongnu.org},
+devoted to @sc{cvs}. To subscribe or
+unsubscribe
+write to
+@email{info-cvs-request@@nongnu.org}.
+If you prefer a Usenet group, there is a one-way mirror (posts to the email
+list are usually sent to the news group, but not visa versa) of
+@email{info-cvs@@nongnu.org} at @url{news:gnu.cvs.help}. The right
+Usenet group for posts is @url{news:comp.software.config-mgmt} which is for
+@sc{cvs} discussions (along with other configuration
+management systems). In the future, it might be
+possible to create a
+@code{comp.software.config-mgmt.cvs}, but probably only
+if there is sufficient @sc{cvs} traffic on
+@url{news:comp.software.config-mgmt}.
+@c Other random data is that the tale was very
+@c skeptical of comp.software.config-mgmt.cvs when the
+@c subject came up around 1995 or so (for one
+@c thing, because creating it would be a "reorg" which
+@c would need to take a more comprehensive look at the
+@c whole comp.software.config-mgmt.* hierarchy).
+
+You can also subscribe to the @email{bug-cvs@@nongnu.org} mailing list,
+described in more detail in @ref{BUGS}. To subscribe
+send mail to @email{bug-cvs-request@@nongnu.org}. There is a two-way
+Usenet mirror (posts to the Usenet group are usually sent to the email list and
+visa versa) of @email{bug-cvs@@nongnu.org} named @url{news:gnu.cvs.bug}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node What is CVS not?
+@section What is CVS not?
+@cindex What is CVS not?
+
+@sc{cvs} can do a lot of things for you, but it does
+not try to be everything for everyone.
+
+@table @asis
+@item @sc{cvs} is not a build system.
+
+Though the structure of your repository and modules
+file interact with your build system
+(e.g. @file{Makefile}s), they are essentially
+independent.
+
+@sc{cvs} does not dictate how you build anything. It
+merely stores files for retrieval in a tree structure
+you devise.
+
+@sc{cvs} does not dictate how to use disk space in the
+checked out working directories. If you write your
+@file{Makefile}s or scripts in every directory so they
+have to know the relative positions of everything else,
+you wind up requiring the entire repository to be
+checked out.
+
+If you modularize your work, and construct a build
+system that will share files (via links, mounts,
+@code{VPATH} in @file{Makefile}s, etc.), you can
+arrange your disk usage however you like.
+
+But you have to remember that @emph{any} such system is
+a lot of work to construct and maintain. @sc{cvs} does
+not address the issues involved.
+
+Of course, you should place the tools created to
+support such a build system (scripts, @file{Makefile}s,
+etc) under @sc{cvs}.
+
+Figuring out what files need to be rebuilt when
+something changes is, again, something to be handled
+outside the scope of @sc{cvs}. One traditional
+approach is to use @code{make} for building, and use
+some automated tool for generating the dependencies which
+@code{make} uses.
+
+See @ref{Builds}, for more information on doing builds
+in conjunction with @sc{cvs}.
+
+@item @sc{cvs} is not a substitute for management.
+
+Your managers and project leaders are expected to talk
+to you frequently enough to make certain you are aware
+of schedules, merge points, branch names and release
+dates. If they don't, @sc{cvs} can't help.
+
+@sc{cvs} is an instrument for making sources dance to
+your tune. But you are the piper and the composer. No
+instrument plays itself or writes its own music.
+
+@item @sc{cvs} is not a substitute for developer communication.
+
+When faced with conflicts within a single file, most
+developers manage to resolve them without too much
+effort. But a more general definition of ``conflict''
+includes problems too difficult to solve without
+communication between developers.
+
+@sc{cvs} cannot determine when simultaneous changes
+within a single file, or across a whole collection of
+files, will logically conflict with one another. Its
+concept of a @dfn{conflict} is purely textual, arising
+when two changes to the same base file are near enough
+to spook the merge (i.e. @code{diff3}) command.
+
+@sc{cvs} does not claim to help at all in figuring out
+non-textual or distributed conflicts in program logic.
+
+For example: Say you change the arguments to function
+@code{X} defined in file @file{A}. At the same time,
+someone edits file @file{B}, adding new calls to
+function @code{X} using the old arguments. You are
+outside the realm of @sc{cvs}'s competence.
+
+Acquire the habit of reading specs and talking to your
+peers.
+
+
+@item @sc{cvs} does not have change control
+
+Change control refers to a number of things. First of
+all it can mean @dfn{bug-tracking}, that is being able
+to keep a database of reported bugs and the status of
+each one (is it fixed? in what release? has the bug
+submitter agreed that it is fixed?). For interfacing
+@sc{cvs} to an external bug-tracking system, see the
+@file{rcsinfo} and @file{verifymsg} files
+(@pxref{Administrative files}).
+
+Another aspect of change control is keeping track of
+the fact that changes to several files were in fact
+changed together as one logical change. If you check
+in several files in a single @code{cvs commit}
+operation, @sc{cvs} then forgets that those files were
+checked in together, and the fact that they have the
+same log message is the only thing tying them
+together. Keeping a @sc{gnu} style @file{ChangeLog}
+can help somewhat.
+@c FIXME: should have an xref to a section which talks
+@c more about keeping ChangeLog's with CVS, but that
+@c section hasn't been written yet.
+
+Another aspect of change control, in some systems, is
+the ability to keep track of the status of each
+change. Some changes have been written by a developer,
+others have been reviewed by a second developer, and so
+on. Generally, the way to do this with @sc{cvs} is to
+generate a diff (using @code{cvs diff} or @code{diff})
+and email it to someone who can then apply it using the
+@code{patch} utility. This is very flexible, but
+depends on mechanisms outside @sc{cvs} to make sure
+nothing falls through the cracks.
+
+@item @sc{cvs} is not an automated testing program
+
+It should be possible to enforce mandatory use of a
+test suite using the @code{commitinfo} file. I haven't
+heard a lot about projects trying to do that or whether
+there are subtle gotchas, however.
+
+@item @sc{cvs} does not have a built-in process model
+
+Some systems provide ways to ensure that changes or
+releases go through various steps, with various
+approvals as needed. Generally, one can accomplish
+this with @sc{cvs} but it might be a little more work.
+In some cases you'll want to use the @file{commitinfo},
+@file{loginfo}, @file{rcsinfo}, or @file{verifymsg}
+files, to require that certain steps be performed
+before cvs will allow a checkin. Also consider whether
+features such as branches and tags can be used to
+perform tasks such as doing work in a development tree
+and then merging certain changes over to a stable tree
+only once they have been proven.
+@end table
+
+@c ---------------------------------------------------------------------
+@node A sample session
+@section A sample session
+@cindex Example of a work-session
+@cindex Getting started
+@cindex Work-session, example of
+@cindex tc, Trivial Compiler (example)
+@cindex Trivial Compiler (example)
+
+@c I think an example is a pretty good way to start. But
+@c somewhere in here, maybe after the sample session,
+@c we need something which is kind of
+@c a "roadmap" which is more directed at sketching out
+@c the functionality of CVS and pointing people to
+@c various other parts of the manual. As it stands now
+@c people who read in order get dumped right into all
+@c manner of hair regarding remote repositories,
+@c creating a repository, etc.
+@c
+@c The following was in the old Basic concepts node. I don't
+@c know how good a job it does at introducing modules,
+@c or whether they need to be introduced so soon, but
+@c something of this sort might go into some
+@c introductory material somewhere.
+@ignore
+@cindex Modules (intro)
+The repository contains directories and files, in an
+arbitrary tree. The @dfn{modules} feature can be used
+to group together a set of directories or files into a
+single entity (@pxref{modules}). A typical usage is to
+define one module per project.
+@end ignore
+
+As a way of introducing @sc{cvs}, we'll go through a
+typical work-session using @sc{cvs}. The first thing
+to understand is that @sc{cvs} stores all files in a
+centralized @dfn{repository} (@pxref{Repository}); this
+section assumes that a repository is set up.
+@c I'm not sure that the sentence concerning the
+@c repository quite tells the user what they need to
+@c know at this point. Might need to expand on "centralized"
+@c slightly (maybe not here, maybe further down in the example?)
+
+Suppose you are working on a simple compiler. The source
+consists of a handful of C files and a @file{Makefile}.
+The compiler is called @samp{tc} (Trivial Compiler),
+and the repository is set up so that there is a module
+called @samp{tc}.
+
+@menu
+* Getting the source:: Creating a workspace
+* Committing your changes:: Making your work available to others
+* Cleaning up:: Cleaning up
+* Viewing differences:: Viewing differences
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Getting the source
+@subsection Getting the source
+@cindex Getting the source
+@cindex Checking out source
+@cindex Fetching source
+@cindex Source, getting from CVS
+@cindex Checkout, example
+
+The first thing you must do is to get your own working copy of the
+source for @samp{tc}. For this, you use the @code{checkout} command:
+
+@example
+$ cvs checkout tc
+@end example
+
+@noindent
+This will create a new directory called @file{tc} and populate it with
+the source files.
+
+@example
+$ cd tc
+$ ls
+CVS Makefile backend.c driver.c frontend.c parser.c
+@end example
+
+The @file{CVS} directory is used internally by
+@sc{cvs}. Normally, you should not modify or remove
+any of the files in it.
+
+You start your favorite editor, hack away at @file{backend.c}, and a couple
+of hours later you have added an optimization pass to the compiler.
+A note to @sc{rcs} and @sc{sccs} users: There is no need to lock the files that
+you want to edit. @xref{Multiple developers}, for an explanation.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Committing your changes
+@subsection Committing your changes
+@cindex Committing changes to files
+@cindex Log message entry
+
+When you have checked that the compiler is still compilable you decide
+to make a new version of @file{backend.c}. This will
+store your new @file{backend.c} in the repository and
+make it available to anyone else who is using that same
+repository.
+
+@example
+$ cvs commit backend.c
+@end example
+
+@noindent
+@sc{cvs} starts an editor, to allow you to enter a log
+message. You type in ``Added an optimization pass.'',
+save the temporary file, and exit the editor.
+
+@cindex CVSEDITOR, environment variable
+@cindex EDITOR, environment variable
+The environment variable @code{$CVSEDITOR} determines
+which editor is started. If @code{$CVSEDITOR} is not
+set, then if the environment variable @code{$EDITOR} is
+set, it will be used. If both @code{$CVSEDITOR} and
+@code{$EDITOR} are not set then there is a default
+which will vary with your operating system, for example
+@code{vi} for unix or @code{notepad} for Windows
+NT/95.
+
+@cindex VISUAL, environment variable
+In addition, @sc{cvs} checks the @code{$VISUAL} environment
+variable. Opinions vary on whether this behavior is desirable and
+whether future releases of @sc{cvs} should check @code{$VISUAL} or
+ignore it. You will be OK either way if you make sure that
+@code{$VISUAL} is either unset or set to the same thing as
+@code{$EDITOR}.
+
+@c This probably should go into some new node
+@c containing detailed info on the editor, rather than
+@c the intro. In fact, perhaps some of the stuff with
+@c CVSEDITOR and -m and so on should too.
+When @sc{cvs} starts the editor, it includes a list of
+files which are modified. For the @sc{cvs} client,
+this list is based on comparing the modification time
+of the file against the modification time that the file
+had when it was last gotten or updated. Therefore, if
+a file's modification time has changed but its contents
+have not, it will show up as modified. The simplest
+way to handle this is simply not to worry about it---if
+you proceed with the commit @sc{cvs} will detect that
+the contents are not modified and treat it as an
+unmodified file. The next @code{update} will clue
+@sc{cvs} in to the fact that the file is unmodified,
+and it will reset its stored timestamp so that the file
+will not show up in future editor sessions.
+@c FIXCVS: Might be nice if "commit" and other commands
+@c would reset that timestamp too, but currently commit
+@c doesn't.
+@c FIXME: Need to talk more about the process of
+@c prompting for the log message. Like show an example
+@c of what it pops up in the editor, for example. Also
+@c a discussion of how to get the "a)bort, c)ontinue,
+@c e)dit" prompt and what to do with it. Might also
+@c work in the suggestion that if you want a diff, you
+@c should make it before running commit (someone
+@c suggested that the diff pop up in the editor. I'm
+@c not sure that is better than telling people to run
+@c "cvs diff" first if that is what they want, but if
+@c we want to tell people that, the manual possibly
+@c should say it).
+
+If you want to avoid
+starting an editor you can specify the log message on
+the command line using the @samp{-m} flag instead, like
+this:
+
+@example
+$ cvs commit -m "Added an optimization pass" backend.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Cleaning up
+@subsection Cleaning up
+@cindex Cleaning up
+@cindex Working copy, removing
+@cindex Removing your working copy
+@cindex Releasing your working copy
+
+Before you turn to other tasks you decide to remove your working copy of
+tc. One acceptable way to do that is of course
+
+@example
+$ cd ..
+$ rm -r tc
+@end example
+
+@noindent
+but a better way is to use the @code{release} command (@pxref{release}):
+
+@example
+$ cd ..
+$ cvs release -d tc
+M driver.c
+? tc
+You have [1] altered files in this repository.
+Are you sure you want to release (and delete) directory `tc': n
+** `release' aborted by user choice.
+@end example
+
+The @code{release} command checks that all your modifications have been
+committed. If history logging is enabled it also makes a note in the
+history file. @xref{history file}.
+
+When you use the @samp{-d} flag with @code{release}, it
+also removes your working copy.
+
+In the example above, the @code{release} command wrote a couple of lines
+of output. @samp{? tc} means that the file @file{tc} is unknown to @sc{cvs}.
+That is nothing to worry about: @file{tc} is the executable compiler,
+and it should not be stored in the repository. @xref{cvsignore},
+for information about how to make that warning go away.
+@xref{release output}, for a complete explanation of
+all possible output from @code{release}.
+
+@samp{M driver.c} is more serious. It means that the
+file @file{driver.c} has been modified since it was
+checked out.
+
+The @code{release} command always finishes by telling
+you how many modified files you have in your working
+copy of the sources, and then asks you for confirmation
+before deleting any files or making any note in the
+history file.
+
+You decide to play it safe and answer @kbd{n @key{RET}}
+when @code{release} asks for confirmation.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Viewing differences
+@subsection Viewing differences
+@cindex Viewing differences
+@cindex Diff
+
+You do not remember modifying @file{driver.c}, so you want to see what
+has happened to that file.
+
+@example
+$ cd tc
+$ cvs diff driver.c
+@end example
+
+This command runs @code{diff} to compare the version of @file{driver.c}
+that you checked out with your working copy. When you see the output
+you remember that you added a command line option that enabled the
+optimization pass. You check it in, and release the module.
+@c FIXME: we haven't yet defined the term "check in".
+
+@example
+$ cvs commit -m "Added an optimization pass" driver.c
+Checking in driver.c;
+/usr/local/cvsroot/tc/driver.c,v <-- driver.c
+new revision: 1.2; previous revision: 1.1
+done
+$ cd ..
+$ cvs release -d tc
+? tc
+You have [0] altered files in this repository.
+Are you sure you want to release (and delete) directory `tc': y
+@end example
+
+@c ---------------------------------------------------------------------
+@node Repository
+@chapter The Repository
+@cindex Repository (intro)
+@cindex Repository, example
+@cindex Layout of repository
+@cindex Typical repository
+@cindex /usr/local/cvsroot, as example repository
+@cindex cvsroot
+
+The @sc{cvs} @dfn{repository} stores a complete copy of
+all the files and directories which are under version
+control.
+
+Normally, you never access any of the files in the
+repository directly. Instead, you use @sc{cvs}
+commands to get your own copy of the files into a
+@dfn{working directory}, and then
+work on that copy. When you've finished a set of
+changes, you check (or @dfn{commit}) them back into the
+repository. The repository then contains the changes
+which you have made, as well as recording exactly what
+you changed, when you changed it, and other such
+information. Note that the repository is not a
+subdirectory of the working directory, or vice versa;
+they should be in separate locations.
+@c Need some example, e.g. repository
+@c /usr/local/cvsroot; working directory
+@c /home/joe/sources. But this node is too long
+@c as it is; need a little reorganization...
+
+@cindex :local:, setting up
+@sc{cvs} can access a repository by a variety of
+means. It might be on the local computer, or it might
+be on a computer across the room or across the world.
+To distinguish various ways to access a repository, the
+repository name can start with an @dfn{access method}.
+For example, the access method @code{:local:} means to
+access a repository directory, so the repository
+@code{:local:/usr/local/cvsroot} means that the
+repository is in @file{/usr/local/cvsroot} on the
+computer running @sc{cvs}. For information on other
+access methods, see @ref{Remote repositories}.
+
+@c Can se say this more concisely? Like by passing
+@c more of the buck to the Remote repositories node?
+If the access method is omitted, then if the repository
+starts with @samp{/}, then @code{:local:} is
+assumed. If it does not start with @samp{/} then either
+@code{:ext:} or @code{:server:} is assumed. For
+example, if you have a local repository in
+@file{/usr/local/cvsroot}, you can use
+@code{/usr/local/cvsroot} instead of
+@code{:local:/usr/local/cvsroot}. But if (under
+Windows NT, for example) your local repository is
+@file{c:\src\cvsroot}, then you must specify the access
+method, as in @code{:local:c:/src/cvsroot}.
+
+@c This might appear to go in Repository storage, but
+@c actually it is describing something which is quite
+@c user-visible, when you do a "cvs co CVSROOT". This
+@c isn't necessary the perfect place for that, though.
+The repository is split in two parts. @file{$CVSROOT/CVSROOT} contains
+administrative files for @sc{cvs}. The other directories contain the actual
+user-defined modules.
+
+@menu
+* Specifying a repository:: Telling CVS where your repository is
+* Repository storage:: The structure of the repository
+* Working directory storage:: The structure of working directories
+* Intro administrative files:: Defining modules
+* Multiple repositories:: Multiple repositories
+* Creating a repository:: Creating a repository
+* Backing up:: Backing up a repository
+* Moving a repository:: Moving a repository
+* Remote repositories:: Accessing repositories on remote machines
+* Read-only access:: Granting read-only access to the repository
+* Server temporary directory:: The server creates temporary directories
+@end menu
+
+@node Specifying a repository
+@section Telling CVS where your repository is
+
+There are several ways to tell @sc{cvs}
+where to find the repository. You can name the
+repository on the command line explicitly, with the
+@code{-d} (for "directory") option:
+
+@example
+cvs -d /usr/local/cvsroot checkout yoyodyne/tc
+@end example
+
+@cindex .profile, setting CVSROOT in
+@cindex .cshrc, setting CVSROOT in
+@cindex .tcshrc, setting CVSROOT in
+@cindex .bashrc, setting CVSROOT in
+@cindex CVSROOT, environment variable
+ Or you can set the @code{$CVSROOT} environment
+variable to an absolute path to the root of the
+repository, @file{/usr/local/cvsroot} in this example.
+To set @code{$CVSROOT}, @code{csh} and @code{tcsh}
+users should have this line in their @file{.cshrc} or
+@file{.tcshrc} files:
+
+@example
+setenv CVSROOT /usr/local/cvsroot
+@end example
+
+@noindent
+@code{sh} and @code{bash} users should instead have these lines in their
+@file{.profile} or @file{.bashrc}:
+
+@example
+CVSROOT=/usr/local/cvsroot
+export CVSROOT
+@end example
+
+@cindex Root file, in CVS directory
+@cindex CVS/Root file
+ A repository specified with @code{-d} will
+override the @code{$CVSROOT} environment variable.
+Once you've checked a working copy out from the
+repository, it will remember where its repository is
+(the information is recorded in the
+@file{CVS/Root} file in the working copy).
+
+The @code{-d} option and the @file{CVS/Root} file both
+override the @code{$CVSROOT} environment variable. If
+@code{-d} option differs from @file{CVS/Root}, the
+former is used. Of course, for proper operation they
+should be two ways of referring to the same repository.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Repository storage
+@section How data is stored in the repository
+@cindex Repository, how data is stored
+
+For most purposes it isn't important @emph{how}
+@sc{cvs} stores information in the repository. In
+fact, the format has changed in the past, and is likely
+to change in the future. Since in almost all cases one
+accesses the repository via @sc{cvs} commands, such
+changes need not be disruptive.
+
+However, in some cases it may be necessary to
+understand how @sc{cvs} stores data in the repository,
+for example you might need to track down @sc{cvs} locks
+(@pxref{Concurrency}) or you might need to deal with
+the file permissions appropriate for the repository.
+
+@menu
+* Repository files:: What files are stored in the repository
+* File permissions:: File permissions
+* Windows permissions:: Issues specific to Windows
+* Attic:: Some files are stored in the Attic
+* CVS in repository:: Additional information in CVS directory
+* Locks:: CVS locks control concurrent accesses
+* CVSROOT storage:: A few things about CVSROOT are different
+@end menu
+
+@node Repository files
+@subsection Where files are stored within the repository
+
+@c @cindex Filenames, legal
+@c @cindex Legal filenames
+@c Somewhere we need to say something about legitimate
+@c characters in filenames in working directory and
+@c repository. Not "/" (not even on non-unix). And
+@c here is a specific set of issues:
+@c Files starting with a - are handled inconsistently. They can not
+@c be added to a repository with an add command, because it they are
+@c interpreted as a switch. They can appear in a repository if they are
+@c part of a tree that is imported. They can not be removed from the tree
+@c once they are there.
+@c Note that "--" *is* supported (as a
+@c consequence of using GNU getopt). Should document
+@c this somewhere ("Common options"?). The other usual technique,
+@c "./-foo", isn't as effective, at least for "cvs add"
+@c which doesn't support pathnames containing "/".
+
+The overall structure of the repository is a directory
+tree corresponding to the directories in the working
+directory. For example, supposing the repository is in
+
+@example
+/usr/local/cvsroot
+@end example
+
+@noindent
+here is a possible directory tree (showing only the
+directories):
+
+@example
+@t{/usr}
+ |
+ +--@t{local}
+ | |
+ | +--@t{cvsroot}
+ | | |
+ | | +--@t{CVSROOT}
+ | (administrative files)
+ |
+ +--@t{gnu}
+ | |
+ | +--@t{diff}
+ | | (source code to @sc{gnu} diff)
+ | |
+ | +--@t{rcs}
+ | | (source code to @sc{rcs})
+ | |
+ | +--@t{cvs}
+ | (source code to @sc{cvs})
+ |
+ +--@t{yoyodyne}
+ |
+ +--@t{tc}
+ | |
+ | +--@t{man}
+ | |
+ | +--@t{testing}
+ |
+ +--(other Yoyodyne software)
+@end example
+
+With the directories are @dfn{history files} for each file
+under version control. The name of the history file is
+the name of the corresponding file with @samp{,v}
+appended to the end. Here is what the repository for
+the @file{yoyodyne/tc} directory might look like:
+@c FIXME: Should also mention CVS (CVSREP)
+@c FIXME? Should we introduce Attic with an xref to
+@c Attic? Not sure whether that is a good idea or not.
+@example
+ @code{$CVSROOT}
+ |
+ +--@t{yoyodyne}
+ | |
+ | +--@t{tc}
+ | | |
+ +--@t{Makefile,v}
+ +--@t{backend.c,v}
+ +--@t{driver.c,v}
+ +--@t{frontend.c,v}
+ +--@t{parser.c,v}
+ +--@t{man}
+ | |
+ | +--@t{tc.1,v}
+ |
+ +--@t{testing}
+ |
+ +--@t{testpgm.t,v}
+ +--@t{test2.t,v}
+@end example
+
+@cindex History files
+@cindex RCS history files
+@c The first sentence, about what history files
+@c contain, is kind of redundant with our intro to what the
+@c repository does in node Repository....
+The history files contain, among other things, enough
+information to recreate any revision of the file, a log
+of all commit messages and the user-name of the person
+who committed the revision. The history files are
+known as @dfn{RCS files}, because the first program to
+store files in that format was a version control system
+known as @sc{rcs}. For a full
+description of the file format, see the @code{man} page
+@cite{rcsfile(5)}, distributed with @sc{rcs}, or the
+file @file{doc/RCSFILES} in the @sc{cvs} source
+distribution. This
+file format has become very common---many systems other
+than @sc{cvs} or @sc{rcs} can at least import history
+files in this format.
+@c FIXME: Think about including documentation for this
+@c rather than citing it? In the long run, getting
+@c this to be a standard (not sure if we can cope with
+@c a standards process as formal as IEEE/ANSI/ISO/etc,
+@c though...) is the way to go, so maybe citing is
+@c better.
+
+The @sc{rcs} files used in @sc{cvs} differ in a few
+ways from the standard format. The biggest difference
+is magic branches; for more information see @ref{Magic
+branch numbers}. Also in @sc{cvs} the valid tag names
+are a subset of what @sc{rcs} accepts; for @sc{cvs}'s
+rules see @ref{Tags}.
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node File permissions
+@subsection File permissions
+@c -- Move this to @node Creating a repository or similar
+@cindex Security, file permissions in repository
+@cindex File permissions, general
+@cindex Permissions, general
+@c FIXME: we need to somehow reflect "permissions in
+@c repository" versus "permissions in working
+@c directory" in the index entries.
+@cindex Group, UNIX file permissions, in repository
+@cindex Read-only files, in repository
+All @samp{,v} files are created read-only, and you
+should not change the permission of those files. The
+directories inside the repository should be writable by
+the persons that have permission to modify the files in
+each directory. This normally means that you must
+create a UNIX group (see group(5)) consisting of the
+persons that are to edit the files in a project, and
+set up the repository so that it is that group that
+owns the directory.
+(On some systems, you also need to set the set-group-ID-on-execution bit
+on the repository directories (see chmod(1)) so that newly-created files
+and directories get the group-ID of the parent directory rather than
+that of the current process.)
+
+@c See also comment in commitinfo node regarding cases
+@c which are really awkward with unix groups.
+
+This means that you can only control access to files on
+a per-directory basis.
+
+Note that users must also have write access to check
+out files, because @sc{cvs} needs to create lock files
+(@pxref{Concurrency}). You can use LockDir in CVSROOT/config
+to put the lock files somewhere other than in the repository
+if you want to allow read-only access to some directories
+(@pxref{config}).
+
+@c CVS seems to use CVSUMASK in picking permissions for
+@c val-tags, but maybe we should say more about this.
+@c Like val-tags gets created by someone who doesn't
+@c have CVSUMASK set right?
+@cindex CVSROOT/val-tags file, and read-only access to projects
+@cindex val-tags file, and read-only access to projects
+Also note that users must have write access to the
+@file{CVSROOT/val-tags} file. @sc{cvs} uses it to keep
+track of what tags are valid tag names (it is sometimes
+updated when tags are used, as well as when they are
+created).
+
+Each @sc{rcs} file will be owned by the user who last
+checked it in. This has little significance; what
+really matters is who owns the directories.
+
+@cindex CVSUMASK, environment variable
+@cindex Umask, for repository files
+@sc{cvs} tries to set up reasonable file permissions
+for new directories that are added inside the tree, but
+you must fix the permissions manually when a new
+directory should have different permissions than its
+parent directory. If you set the @code{CVSUMASK}
+environment variable that will control the file
+permissions which @sc{cvs} uses in creating directories
+and/or files in the repository. @code{CVSUMASK} does
+not affect the file permissions in the working
+directory; such files have the permissions which are
+typical for newly created files, except that sometimes
+@sc{cvs} creates them read-only (see the sections on
+watches, @ref{Setting a watch}; -r, @ref{Global
+options}; or @code{CVSREAD}, @ref{Environment variables}).
+@c FIXME: Need more discussion of which
+@c group should own the file in the repository.
+@c Include a somewhat detailed example of the usual
+@c case where CVSUMASK is 007, the developers are all
+@c in a group, and that group owns stuff in the
+@c repository. Need to talk about group ownership of
+@c newly-created directories/files (on some unices,
+@c such as SunOS4, setting the setgid bit on the
+@c directories will make files inherit the directory's
+@c group. On other unices, your mileage may vary. I
+@c can't remember what POSIX says about this, if
+@c anything).
+
+Note that using the client/server @sc{cvs}
+(@pxref{Remote repositories}), there is no good way to
+set @code{CVSUMASK}; the setting on the client machine
+has no effect. If you are connecting with @code{rsh}, you
+can set @code{CVSUMASK} in @file{.bashrc} or @file{.cshrc}, as
+described in the documentation for your operating
+system. This behavior might change in future versions
+of @sc{cvs}; do not rely on the setting of
+@code{CVSUMASK} on the client having no effect.
+@c FIXME: need to explain what a umask is or cite
+@c someplace which does.
+@c
+@c There is also a larger (largely separate) issue
+@c about the meaning of CVSUMASK in a non-unix context.
+@c For example, whether there is
+@c an equivalent which fits better into other
+@c protection schemes like POSIX.6, VMS, &c.
+@c
+@c FIXME: Need one place which discusses this
+@c read-only files thing. Why would one use -r or
+@c CVSREAD? Why would one use watches? How do they
+@c interact?
+@c
+@c FIXME: We need to state
+@c whether using CVSUMASK removes the need for manually
+@c fixing permissions (in fact, if we are going to mention
+@c manually fixing permission, we better document a lot
+@c better just what we mean by "fix").
+
+Using pserver, you will generally need stricter
+permissions on the @sc{cvsroot} directory and
+directories above it in the tree; see @ref{Password
+authentication security}.
+
+@cindex Setuid
+@cindex Setgid
+@cindex Security, setuid
+@cindex Installed images (VMS)
+Some operating systems have features which allow a
+particular program to run with the ability to perform
+operations which the caller of the program could not.
+For example, the set user ID (setuid) or set group ID
+(setgid) features of unix or the installed image
+feature of VMS. @sc{cvs} was not written to use such
+features and therefore attempting to install @sc{cvs} in
+this fashion will provide protection against only
+accidental lapses; anyone who is trying to circumvent
+the measure will be able to do so, and depending on how
+you have set it up may gain access to more than just
+@sc{cvs}. You may wish to instead consider pserver. It
+shares some of the same attributes, in terms of
+possibly providing a false sense of security or opening
+security holes wider than the ones you are trying to
+fix, so read the documentation on pserver security
+carefully if you are considering this option
+(@ref{Password authentication security}).
+
+@node Windows permissions
+@subsection File Permission issues specific to Windows
+@cindex Windows, and permissions
+@cindex File permissions, Windows-specific
+@cindex Permissions, Windows-specific
+
+Some file permission issues are specific to Windows
+operating systems (Windows 95, Windows NT, and
+presumably future operating systems in this family.
+Some of the following might apply to OS/2 but I'm not
+sure).
+
+If you are using local @sc{cvs} and the repository is on a
+networked file system which is served by the Samba SMB
+server, some people have reported problems with
+permissions. Enabling WRITE=YES in the samba
+configuration is said to fix/workaround it.
+Disclaimer: I haven't investigated enough to know the
+implications of enabling that option, nor do I know
+whether there is something which @sc{cvs} could be doing
+differently in order to avoid the problem. If you find
+something out, please let us know as described in
+@ref{BUGS}.
+
+@node Attic
+@subsection The attic
+@cindex Attic
+
+You will notice that sometimes @sc{cvs} stores an
+@sc{rcs} file in the @code{Attic}. For example, if the
+@sc{cvsroot} is @file{/usr/local/cvsroot} and we are
+talking about the file @file{backend.c} in the
+directory @file{yoyodyne/tc}, then the file normally
+would be in
+
+@example
+/usr/local/cvsroot/yoyodyne/tc/backend.c,v
+@end example
+
+@noindent
+but if it goes in the attic, it would be in
+
+@example
+/usr/local/cvsroot/yoyodyne/tc/Attic/backend.c,v
+@end example
+
+@noindent
+@cindex Dead state
+instead. It should not matter from a user point of
+view whether a file is in the attic; @sc{cvs} keeps
+track of this and looks in the attic when it needs to.
+But in case you want to know, the rule is that the RCS
+file is stored in the attic if and only if the head
+revision on the trunk has state @code{dead}. A
+@code{dead} state means that file has been removed, or
+never added, for that revision. For example, if you
+add a file on a branch, it will have a trunk revision
+in @code{dead} state, and a branch revision in a
+non-@code{dead} state.
+@c Probably should have some more concrete examples
+@c here, or somewhere (not sure exactly how we should
+@c arrange the discussion of the dead state, versus
+@c discussion of the attic).
+
+@node CVS in repository
+@subsection The CVS directory in the repository
+@cindex CVS directory, in repository
+
+The @file{CVS} directory in each repository directory
+contains information such as file attributes (in a file
+called @file{CVS/fileattr}. In the
+future additional files may be added to this directory,
+so implementations should silently ignore additional
+files.
+
+This behavior is implemented only by @sc{cvs} 1.7 and
+later; for details see @ref{Watches Compatibility}.
+
+The format of the @file{fileattr} file is a series of entries
+of the following form (where @samp{@{} and @samp{@}}
+means the text between the braces can be repeated zero
+or more times):
+
+@var{ent-type} @var{filename} <tab> @var{attrname} = @var{attrval}
+ @{; @var{attrname} = @var{attrval}@} <linefeed>
+
+@var{ent-type} is @samp{F} for a file, in which case the entry specifies the
+attributes for that file.
+
+@var{ent-type} is @samp{D},
+and @var{filename} empty, to specify default attributes
+to be used for newly added files.
+
+Other @var{ent-type} are reserved for future expansion. @sc{cvs} 1.9 and older
+will delete them any time it writes file attributes.
+@sc{cvs} 1.10 and later will preserve them.
+
+Note that the order of the lines is not significant;
+a program writing the fileattr file may
+rearrange them at its convenience.
+
+There is currently no way of quoting tabs or line feeds in the
+filename, @samp{=} in @var{attrname},
+@samp{;} in @var{attrval}, etc. Note: some implementations also
+don't handle a NUL character in any of the fields, but
+implementations are encouraged to allow it.
+
+By convention, @var{attrname} starting with @samp{_} is for an attribute given
+special meaning by @sc{cvs}; other @var{attrname}s are for user-defined attributes
+(or will be, once implementations start supporting user-defined attributes).
+
+Built-in attributes:
+
+@table @code
+@item _watched
+Present means the file is watched and should be checked out
+read-only.
+
+@item _watchers
+Users with watches for this file. Value is
+@var{watcher} > @var{type} @{ , @var{watcher} > @var{type} @}
+where @var{watcher} is a username, and @var{type}
+is zero or more of edit,unedit,commit separated by
+@samp{+} (that is, nothing if none; there is no "none" or "all" keyword).
+
+@item _editors
+Users editing this file. Value is
+@var{editor} > @var{val} @{ , @var{editor} > @var{val} @}
+where @var{editor} is a username, and @var{val} is
+@var{time}+@var{hostname}+@var{pathname}, where
+@var{time} is when the @code{cvs edit} command (or
+equivalent) happened,
+and @var{hostname} and @var{pathname} are for the working directory.
+@end table
+
+Example:
+
+@c FIXME: sanity.sh should contain a similar test case
+@c so we can compare this example from something from
+@c Real Life(TM). See cvsclient.texi (under Notify) for more
+@c discussion of the date format of _editors.
+@example
+Ffile1 _watched=;_watchers=joe>edit,mary>commit
+Ffile2 _watched=;_editors=sue>8 Jan 1975+workstn1+/home/sue/cvs
+D _watched=
+@end example
+
+@noindent
+means that the file @file{file1} should be checked out
+read-only. Furthermore, joe is watching for edits and
+mary is watching for commits. The file @file{file2}
+should be checked out read-only; sue started editing it
+on 8 Jan 1975 in the directory @file{/home/sue/cvs} on
+the machine @code{workstn1}. Future files which are
+added should be checked out read-only. To represent
+this example here, we have shown a space after
+@samp{D}, @samp{Ffile1}, and @samp{Ffile2}, but in fact
+there must be a single tab character there and no spaces.
+
+@node Locks
+@subsection CVS locks in the repository
+
+@cindex #cvs.rfl, technical details
+@cindex #cvs.pfl, technical details
+@cindex #cvs.wfl, technical details
+@cindex #cvs.lock, technical details
+@cindex Locks, cvs, technical details
+For an introduction to @sc{cvs} locks focusing on
+user-visible behavior, see @ref{Concurrency}. The
+following section is aimed at people who are writing
+tools which want to access a @sc{cvs} repository without
+interfering with other tools accessing the same
+repository. If you find yourself confused by concepts
+described here, like @dfn{read lock}, @dfn{write lock},
+and @dfn{deadlock}, you might consult the literature on
+operating systems or databases.
+
+@cindex #cvs.tfl
+Any file in the repository with a name starting
+with @file{#cvs.rfl.} is a read lock. Any file in
+the repository with a name starting with
+@file{#cvs.pfl} is a promotable read lock. Any file in
+the repository with a name starting with
+@file{#cvs.wfl} is a write lock. Old versions of @sc{cvs}
+(before @sc{cvs} 1.5) also created files with names starting
+with @file{#cvs.tfl}, but they are not discussed here.
+The directory @file{#cvs.lock} serves as a master
+lock. That is, one must obtain this lock first before
+creating any of the other locks.
+
+To obtain a read lock, first create the @file{#cvs.lock}
+directory. This operation must be atomic (which should
+be true for creating a directory under most operating
+systems). If it fails because the directory already
+existed, wait for a while and try again. After
+obtaining the @file{#cvs.lock} lock, create a file
+whose name is @file{#cvs.rfl.} followed by information
+of your choice (for example, hostname and process
+identification number). Then remove the
+@file{#cvs.lock} directory to release the master lock.
+Then proceed with reading the repository. When you are
+done, remove the @file{#cvs.rfl} file to release the
+read lock.
+
+Promotable read locks are a concept you may not find in other literature on
+concurrency. They are used to allow a two (or more) pass process to only lock
+a file for read on the first (read) pass(es), then upgrade its read locks to
+write locks if necessary for a final pass, still assured that the files have
+not changed since they were first read. @sc{cvs} uses promotable read locks,
+for example, to prevent commit and tag verification passes from interfering
+with other reading processes. It can then lock only a single directory at a
+time for write during the write pass.
+
+To obtain a promotable read lock, first create the @file{#cvs.lock} directory,
+as with a non-promotable read lock. Then check
+that there are no files that start with
+@file{#cvs.pfl}. If there are, remove the master @file{#cvs.lock} directory,
+wait awhile (CVS waits 30 seconds between lock attempts), and try again. If
+there are no other promotable locks, go ahead and create a file whose name is
+@file{#cvs.pfl} followed by information of your choice (for example, CVS uses
+its hostname and the process identification number of the CVS server process
+creating the lock). If versions of @sc{cvs} older than version 1.12.4 access
+your repository directly (not via a @sc{cvs} server of version 1.12.4 or
+later), then you should also create a read lock since older versions of CVS
+will ignore the promotable lock when attempting to create their own write lock.
+Then remove the master @file{#cvs.lock} directory in order to allow other
+processes to obtain read locks.
+
+To obtain a write lock, first create the
+@file{#cvs.lock} directory, as with read locks. Then
+check that there are no files whose names start with
+@file{#cvs.rfl.} and no files whose names start with @file{#cvs.pfl} that are
+not owned by the process attempting to get the write lock. If either exist,
+remove @file{#cvs.lock}, wait for a while, and try again. If
+there are no readers or promotable locks from other processes, then create a
+file whose name is @file{#cvs.wfl} followed by information of your choice
+(again, CVS uses the hostname and server process identification
+number). Remove your @file{#cvs.pfl} file if present. Hang on to the
+@file{#cvs.lock} lock. Proceed
+with writing the repository. When you are done, first
+remove the @file{#cvs.wfl} file and then the
+@file{#cvs.lock} directory. Note that unlike the
+@file{#cvs.rfl} file, the @file{#cvs.wfl} file is just
+informational; it has no effect on the locking operation
+beyond what is provided by holding on to the
+@file{#cvs.lock} lock itself.
+
+Note that each lock (write lock or read lock) only locks
+a single directory in the repository, including
+@file{Attic} and @file{CVS} but not including
+subdirectories which represent other directories under
+version control. To lock an entire tree, you need to
+lock each directory (note that if you fail to obtain
+any lock you need, you must release the whole tree
+before waiting and trying again, to avoid deadlocks).
+
+Note also that @sc{cvs} expects write locks to control
+access to individual @file{foo,v} files. @sc{rcs} has
+a scheme where the @file{,foo,} file serves as a lock,
+but @sc{cvs} does not implement it and so taking out a
+@sc{cvs} write lock is recommended. See the comments at
+rcs_internal_lockfile in the @sc{cvs} source code for
+further discussion/rationale.
+
+@node CVSROOT storage
+@subsection How files are stored in the CVSROOT directory
+@cindex CVSROOT, storage of files
+
+The @file{$CVSROOT/CVSROOT} directory contains the
+various administrative files. In some ways this
+directory is just like any other directory in the
+repository; it contains @sc{rcs} files whose names end
+in @samp{,v}, and many of the @sc{cvs} commands operate
+on it the same way. However, there are a few
+differences.
+
+For each administrative file, in addition to the
+@sc{rcs} file, there is also a checked out copy of the
+file. For example, there is an @sc{rcs} file
+@file{loginfo,v} and a file @file{loginfo} which
+contains the latest revision contained in
+@file{loginfo,v}. When you check in an administrative
+file, @sc{cvs} should print
+
+@example
+cvs commit: Rebuilding administrative file database
+@end example
+
+@noindent
+and update the checked out copy in
+@file{$CVSROOT/CVSROOT}. If it does not, there is
+something wrong (@pxref{BUGS}). To add your own files
+to the files to be updated in this fashion, you can add
+them to the @file{checkoutlist} administrative file
+(@pxref{checkoutlist}).
+
+@cindex modules.db
+@cindex modules.pag
+@cindex modules.dir
+By default, the @file{modules} file behaves as
+described above. If the modules file is very large,
+storing it as a flat text file may make looking up
+modules slow (I'm not sure whether this is as much of a
+concern now as when @sc{cvs} first evolved this
+feature; I haven't seen benchmarks). Therefore, by
+making appropriate edits to the @sc{cvs} source code
+one can store the modules file in a database which
+implements the @code{ndbm} interface, such as Berkeley
+db or GDBM. If this option is in use, then the modules
+database will be stored in the files @file{modules.db},
+@file{modules.pag}, and/or @file{modules.dir}.
+@c I think fileattr also will use the database stuff.
+@c Anything else?
+
+For information on the meaning of the various
+administrative files, see @ref{Administrative files}.
+
+@node Working directory storage
+@section How data is stored in the working directory
+
+@c FIXME: Somewhere we should discuss timestamps (test
+@c case "stamps" in sanity.sh). But not here. Maybe
+@c in some kind of "working directory" chapter which
+@c would encompass the "Builds" one? But I'm not sure
+@c whether that is a good organization (is it based on
+@c what the user wants to do?).
+
+@cindex CVS directory, in working directory
+While we are discussing @sc{cvs} internals which may
+become visible from time to time, we might as well talk
+about what @sc{cvs} puts in the @file{CVS} directories
+in the working directories. As with the repository,
+@sc{cvs} handles this information and one can usually
+access it via @sc{cvs} commands. But in some cases it
+may be useful to look at it, and other programs, such
+as the @code{jCVS} graphical user interface or the
+@code{VC} package for emacs, may need to look at it.
+Such programs should follow the recommendations in this
+section if they hope to be able to work with other
+programs which use those files, including future
+versions of the programs just mentioned and the
+command-line @sc{cvs} client.
+
+The @file{CVS} directory contains several files.
+Programs which are reading this directory should
+silently ignore files which are in the directory but
+which are not documented here, to allow for future
+expansion.
+
+The files are stored according to the text file
+convention for the system in question. This means that
+working directories are not portable between systems
+with differing conventions for storing text files.
+This is intentional, on the theory that the files being
+managed by @sc{cvs} probably will not be portable between
+such systems either.
+
+@table @file
+@item Root
+This file contains the current @sc{cvs} root, as
+described in @ref{Specifying a repository}.
+
+@cindex Repository file, in CVS directory
+@cindex CVS/Repository file
+@item Repository
+This file contains the directory within the repository
+which the current directory corresponds with. It can
+be either an absolute pathname or a relative pathname;
+@sc{cvs} has had the ability to read either format
+since at least version 1.3 or so. The relative
+pathname is relative to the root, and is the more
+sensible approach, but the absolute pathname is quite
+common and implementations should accept either. For
+example, after the command
+
+@example
+cvs -d :local:/usr/local/cvsroot checkout yoyodyne/tc
+@end example
+
+@noindent
+@file{Root} will contain
+
+@example
+:local:/usr/local/cvsroot
+@end example
+
+@noindent
+and @file{Repository} will contain either
+
+@example
+/usr/local/cvsroot/yoyodyne/tc
+@end example
+
+@noindent
+or
+
+@example
+yoyodyne/tc
+@end example
+
+If the particular working directory does not correspond
+to a directory in the repository, then @file{Repository}
+should contain @file{CVSROOT/Emptydir}.
+@cindex Emptydir, in CVSROOT directory
+@cindex CVSROOT/Emptydir directory
+
+@cindex Entries file, in CVS directory
+@cindex CVS/Entries file
+@item Entries
+This file lists the files and directories in the
+working directory.
+The first character of each line indicates what sort of
+line it is. If the character is unrecognized, programs
+reading the file should silently skip that line, to
+allow for future expansion.
+
+If the first character is @samp{/}, then the format is:
+
+@example
+/@var{name}/@var{revision}/@var{timestamp}[+@var{conflict}]/@var{options}/@var{tagdate}
+@end example
+
+@noindent
+where @samp{[} and @samp{]} are not part of the entry,
+but instead indicate that the @samp{+} and conflict
+marker are optional. @var{name} is the name of the
+file within the directory. @var{revision} is the
+revision that the file in the working derives from, or
+@samp{0} for an added file, or @samp{-} followed by a
+revision for a removed file. @var{timestamp} is the
+timestamp of the file at the time that @sc{cvs} created
+it; if the timestamp differs with the actual
+modification time of the file it means the file has
+been modified. It is stored in
+the format used by the ISO C asctime() function (for
+example, @samp{Sun Apr 7 01:29:26 1996}). One may
+write a string which is not in that format, for
+example, @samp{Result of merge}, to indicate that the
+file should always be considered to be modified. This
+is not a special case; to see whether a file is
+modified a program should take the timestamp of the file
+and simply do a string compare with @var{timestamp}.
+If there was a conflict, @var{conflict} can be set to
+the modification time of the file after the file has been
+written with conflict markers (@pxref{Conflicts example}).
+Thus if @var{conflict} is subsequently the same as the actual
+modification time of the file it means that the user
+has obviously not resolved the conflict. @var{options}
+contains sticky options (for example @samp{-kb} for a
+binary file). @var{tagdate} contains @samp{T} followed
+by a tag name, or @samp{D} for a date, followed by a
+sticky tag or date. Note that if @var{timestamp}
+contains a pair of timestamps separated by a space,
+rather than a single timestamp, you are dealing with a
+version of @sc{cvs} earlier than @sc{cvs} 1.5 (not
+documented here).
+
+The timezone on the timestamp in CVS/Entries (local or
+universal) should be the same as the operating system
+stores for the timestamp of the file itself. For
+example, on Unix the file's timestamp is in universal
+time (UT), so the timestamp in CVS/Entries should be
+too. On @sc{vms}, the file's timestamp is in local
+time, so @sc{cvs} on @sc{vms} should use local time.
+This rule is so that files do not appear to be modified
+merely because the timezone changed (for example, to or
+from summer time).
+@c See comments and calls to gmtime() and friends in
+@c src/vers_ts.c (function time_stamp).
+
+If the first character of a line in @file{Entries} is
+@samp{D}, then it indicates a subdirectory. @samp{D}
+on a line all by itself indicates that the program
+which wrote the @file{Entries} file does record
+subdirectories (therefore, if there is such a line and
+no other lines beginning with @samp{D}, one knows there
+are no subdirectories). Otherwise, the line looks
+like:
+
+@example
+D/@var{name}/@var{filler1}/@var{filler2}/@var{filler3}/@var{filler4}
+@end example
+
+@noindent
+where @var{name} is the name of the subdirectory, and
+all the @var{filler} fields should be silently ignored,
+for future expansion. Programs which modify
+@code{Entries} files should preserve these fields.
+
+The lines in the @file{Entries} file can be in any order.
+
+@cindex Entries.Log file, in CVS directory
+@cindex CVS/Entries.Log file
+@item Entries.Log
+This file does not record any information beyond that
+in @file{Entries}, but it does provide a way to update
+the information without having to rewrite the entire
+@file{Entries} file, including the ability to preserve
+the information even if the program writing
+@file{Entries} and @file{Entries.Log} abruptly aborts.
+Programs which are reading the @file{Entries} file
+should also check for @file{Entries.Log}. If the latter
+exists, they should read @file{Entries} and then apply
+the changes mentioned in @file{Entries.Log}. After
+applying the changes, the recommended practice is to
+rewrite @file{Entries} and then delete @file{Entries.Log}.
+The format of a line in @file{Entries.Log} is a single
+character command followed by a space followed by a
+line in the format specified for a line in
+@file{Entries}. The single character command is
+@samp{A} to indicate that the entry is being added,
+@samp{R} to indicate that the entry is being removed,
+or any other character to indicate that the entire line
+in @file{Entries.Log} should be silently ignored (for
+future expansion). If the second character of the line
+in @file{Entries.Log} is not a space, then it was
+written by an older version of @sc{cvs} (not documented
+here).
+
+Programs which are writing rather than reading can
+safely ignore @file{Entries.Log} if they so choose.
+
+@cindex Entries.Backup file, in CVS directory
+@cindex CVS/Entries.Backup file
+@item Entries.Backup
+This is a temporary file. Recommended usage is to
+write a new entries file to @file{Entries.Backup}, and
+then to rename it (atomically, where possible) to @file{Entries}.
+
+@cindex Entries.Static file, in CVS directory
+@cindex CVS/Entries.Static file
+@item Entries.Static
+The only relevant thing about this file is whether it
+exists or not. If it exists, then it means that only
+part of a directory was gotten and @sc{cvs} will
+not create additional files in that directory. To
+clear it, use the @code{update} command with the
+@samp{-d} option, which will get the additional files
+and remove @file{Entries.Static}.
+@c FIXME: This needs to be better documented, in places
+@c other than Working Directory Storage.
+@c FIXCVS: The fact that this setting exists needs to
+@c be more visible to the user. For example "cvs
+@c status foo", in the case where the file would be
+@c gotten except for Entries.Static, might say
+@c something to distinguish this from other cases.
+@c One thing that periodically gets suggested is to
+@c have "cvs update" print something when it skips
+@c files due to Entries.Static, but IMHO that kind of
+@c noise pretty much makes the Entries.Static feature
+@c useless.
+
+@cindex Tag file, in CVS directory
+@cindex CVS/Tag file
+@cindex Sticky tags/dates, per-directory
+@cindex Per-directory sticky tags/dates
+@item Tag
+This file contains per-directory sticky tags or dates.
+The first character is @samp{T} for a branch tag,
+@samp{N} for a non-branch tag, or @samp{D} for a date,
+or another character to mean the file should be
+silently ignored, for future expansion. This character
+is followed by the tag or date. Note that
+per-directory sticky tags or dates are used for things
+like applying to files which are newly added; they
+might not be the same as the sticky tags or dates on
+individual files. For general information on sticky
+tags and dates, see @ref{Sticky tags}.
+@c FIXME: This needs to be much better documented,
+@c preferably not in the context of "working directory
+@c storage".
+@c FIXME: The Sticky tags node needs to discuss, or xref to
+@c someplace which discusses, per-directory sticky
+@c tags and the distinction with per-file sticky tags.
+
+@cindex Notify file, in CVS directory
+@cindex CVS/Notify file
+@item Notify
+This file stores notifications (for example, for
+@code{edit} or @code{unedit}) which have not yet been
+sent to the server. Its format is not yet documented
+here.
+
+@cindex Notify.tmp file, in CVS directory
+@cindex CVS/Notify.tmp file
+@item Notify.tmp
+This file is to @file{Notify} as @file{Entries.Backup}
+is to @file{Entries}. That is, to write @file{Notify},
+first write the new contents to @file{Notify.tmp} and
+then (atomically where possible), rename it to
+@file{Notify}.
+
+@cindex Base directory, in CVS directory
+@cindex CVS/Base directory
+@item Base
+If watches are in use, then an @code{edit} command
+stores the original copy of the file in the @file{Base}
+directory. This allows the @code{unedit} command to
+operate even if it is unable to communicate with the
+server.
+
+@cindex Baserev file, in CVS directory
+@cindex CVS/Baserev file
+@item Baserev
+The file lists the revision for each of the files in
+the @file{Base} directory. The format is:
+
+@example
+B@var{name}/@var{rev}/@var{expansion}
+@end example
+
+@noindent
+where @var{expansion} should be ignored, to allow for
+future expansion.
+
+@cindex Baserev.tmp file, in CVS directory
+@cindex CVS/Baserev.tmp file
+@item Baserev.tmp
+This file is to @file{Baserev} as @file{Entries.Backup}
+is to @file{Entries}. That is, to write @file{Baserev},
+first write the new contents to @file{Baserev.tmp} and
+then (atomically where possible), rename it to
+@file{Baserev}.
+
+@cindex Template file, in CVS directory
+@cindex CVS/Template file
+@item Template
+This file contains the template specified by the
+@file{rcsinfo} file (@pxref{rcsinfo}). It is only used
+by the client; the non-client/server @sc{cvs} consults
+@file{rcsinfo} directly.
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Intro administrative files
+@section The administrative files
+@cindex Administrative files (intro)
+@cindex Modules file
+@cindex CVSROOT, module name
+@cindex Defining modules (intro)
+
+@c FIXME: this node should be reorganized into "general
+@c information about admin files" and put the "editing
+@c admin files" stuff up front rather than jumping into
+@c the details of modules right away. Then the
+@c Administrative files node can go away, the information
+@c on each admin file distributed to a place appropriate
+@c to its function, and this node can contain a table
+@c listing each file and a @ref to its detailed description.
+
+The directory @file{$CVSROOT/CVSROOT} contains some @dfn{administrative
+files}. @xref{Administrative files}, for a complete description.
+You can use @sc{cvs} without any of these files, but
+some commands work better when at least the
+@file{modules} file is properly set up.
+
+The most important of these files is the @file{modules}
+file. It defines all modules in the repository. This
+is a sample @file{modules} file.
+
+@c FIXME: The CVSROOT line is a goofy example now that
+@c mkmodules doesn't exist.
+@example
+CVSROOT CVSROOT
+modules CVSROOT modules
+cvs gnu/cvs
+rcs gnu/rcs
+diff gnu/diff
+tc yoyodyne/tc
+@end example
+
+The @file{modules} file is line oriented. In its
+simplest form each line contains the name of the
+module, whitespace, and the directory where the module
+resides. The directory is a path relative to
+@code{$CVSROOT}. The last four lines in the example
+above are examples of such lines.
+
+@c FIXME: might want to introduce the concept of options in modules file
+@c (the old example which was here, -i mkmodules, is obsolete).
+
+The line that defines the module called @samp{modules}
+uses features that are not explained here.
+@xref{modules}, for a full explanation of all the
+available features.
+
+@c FIXME: subsection without node is bogus
+@subsection Editing administrative files
+@cindex Editing administrative files
+@cindex Administrative files, editing them
+
+You edit the administrative files in the same way that you would edit
+any other module. Use @samp{cvs checkout CVSROOT} to get a working
+copy, edit it, and commit your changes in the normal way.
+
+It is possible to commit an erroneous administrative
+file. You can often fix the error and check in a new
+revision, but sometimes a particularly bad error in the
+administrative file makes it impossible to commit new
+revisions.
+@c @xref{Bad administrative files} for a hint
+@c about how to solve such situations.
+@c -- administrative file checking--
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Multiple repositories
+@section Multiple repositories
+@cindex Multiple repositories
+@cindex Repositories, multiple
+@cindex Many repositories
+@cindex Parallel repositories
+@cindex Disjoint repositories
+@cindex CVSROOT, multiple repositories
+
+In some situations it is a good idea to have more than
+one repository, for instance if you have two
+development groups that work on separate projects
+without sharing any code. All you have to do to have
+several repositories is to specify the appropriate
+repository, using the @code{CVSROOT} environment
+variable, the @samp{-d} option to @sc{cvs}, or (once
+you have checked out a working directory) by simply
+allowing @sc{cvs} to use the repository that was used
+to check out the working directory
+(@pxref{Specifying a repository}).
+
+The big advantage of having multiple repositories is
+that they can reside on different servers. With @sc{cvs}
+version 1.10, a single command cannot recurse into
+directories from different repositories. With development
+versions of @sc{cvs}, you can check out code from multiple
+servers into your working directory. @sc{cvs} will
+recurse and handle all the details of making
+connections to as many server machines as necessary to
+perform the requested command. Here is an example of
+how to set up a working directory:
+
+@example
+cvs -d server1:/cvs co dir1
+cd dir1
+cvs -d server2:/root co sdir
+cvs update
+@end example
+
+The @code{cvs co} commands set up the working
+directory, and then the @code{cvs update} command will
+contact server2, to update the dir1/sdir subdirectory,
+and server1, to update everything else.
+
+@c FIXME: Does the FAQ have more about this? I have a
+@c dim recollection, but I'm too lazy to check right now.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Creating a repository
+@section Creating a repository
+
+@cindex Repository, setting up
+@cindex Creating a repository
+@cindex Setting up a repository
+
+This section describes how to set up a @sc{cvs} repository for any
+sort of access method. After completing the setup described in this
+section, you should be able to access your @sc{cvs} repository immediately
+via the local access method and several remote access methods. For
+more information on setting up remote access to the repository you create
+in this section, please read the section on @xref{Remote repositories}.
+
+To set up a @sc{cvs} repository, first choose the
+machine and disk on which you want to store the
+revision history of the source files. CPU and memory
+requirements are modest, so most machines should be
+adequate. For details see @ref{Server requirements}.
+@c Possible that we should be providing a quick rule of
+@c thumb, like the 32M memory for the server. That
+@c might increase the number of people who are happy
+@c with the answer, without following the xref.
+
+To estimate disk space
+requirements, if you are importing RCS files from
+another system, the size of those files is the
+approximate initial size of your repository, or if you
+are starting without any version history, a rule of
+thumb is to allow for the server approximately three
+times the size of the code to be under @sc{cvs} for the
+repository (you will eventually outgrow this, but not
+for a while). On the machines on which the developers
+will be working, you'll want disk space for
+approximately one working directory for each developer
+(either the entire tree or a portion of it, depending
+on what each developer uses).
+
+The repository should be accessible
+(directly or via a networked file system) from all
+machines which want to use @sc{cvs} in server or local
+mode; the client machines need not have any access to
+it other than via the @sc{cvs} protocol. It is not
+possible to use @sc{cvs} to read from a repository
+which one only has read access to; @sc{cvs} needs to be
+able to create lock files (@pxref{Concurrency}).
+
+@cindex init (subcommand)
+To create a repository, run the @code{cvs init}
+command. It will set up an empty repository in the
+@sc{cvs} root specified in the usual way
+(@pxref{Repository}). For example,
+
+@example
+cvs -d /usr/local/cvsroot init
+@end example
+
+@code{cvs init} is careful to never overwrite any
+existing files in the repository, so no harm is done if
+you run @code{cvs init} on an already set-up
+repository.
+
+@code{cvs init} will enable history logging; if you
+don't want that, remove the history file after running
+@code{cvs init}. @xref{history file}.
+
+@node Backing up
+@section Backing up a repository
+@cindex Repository, backing up
+@cindex Backing up, repository
+
+There is nothing particularly magical about the files
+in the repository; for the most part it is possible to
+back them up just like any other files. However, there
+are a few issues to consider.
+
+@cindex Locks, cvs, and backups
+@cindex #cvs.rfl, and backups
+The first is that to be paranoid, one should either not
+use @sc{cvs} during the backup, or have the backup
+program lock @sc{cvs} while doing the backup. To not
+use @sc{cvs}, you might forbid logins to machines which
+can access the repository, turn off your @sc{cvs}
+server, or similar mechanisms. The details would
+depend on your operating system and how you have
+@sc{cvs} set up. To lock @sc{cvs}, you would create
+@file{#cvs.rfl} locks in each repository directory.
+See @ref{Concurrency}, for more on @sc{cvs} locks.
+Having said all this, if you just back up without any
+of these precautions, the results are unlikely to be
+particularly dire. Restoring from backup, the
+repository might be in an inconsistent state, but this
+would not be particularly hard to fix manually.
+
+When you restore a repository from backup, assuming
+that changes in the repository were made after the time
+of the backup, working directories which were not
+affected by the failure may refer to revisions which no
+longer exist in the repository. Trying to run @sc{cvs}
+in such directories will typically produce an error
+message. One way to get those changes back into the
+repository is as follows:
+
+@itemize @bullet
+@item
+Get a new working directory.
+
+@item
+Copy the files from the working directory from before
+the failure over to the new working directory (do not
+copy the contents of the @file{CVS} directories, of
+course).
+
+@item
+Working in the new working directory, use commands such
+as @code{cvs update} and @code{cvs diff} to figure out
+what has changed, and then when you are ready, commit
+the changes into the repository.
+@end itemize
+
+@node Moving a repository
+@section Moving a repository
+@cindex Repository, moving
+@cindex Moving a repository
+@cindex Copying a repository
+
+Just as backing up the files in the repository is
+pretty much like backing up any other files, if you
+need to move a repository from one place to another it
+is also pretty much like just moving any other
+collection of files.
+
+The main thing to consider is that working directories
+point to the repository. The simplest way to deal with
+a moved repository is to just get a fresh working
+directory after the move. Of course, you'll want to
+make sure that the old working directory had been
+checked in before the move, or you figured out some
+other way to make sure that you don't lose any
+changes. If you really do want to reuse the existing
+working directory, it should be possible with manual
+surgery on the @file{CVS/Repository} files. You can
+see @ref{Working directory storage}, for information on
+the @file{CVS/Repository} and @file{CVS/Root} files, but
+unless you are sure you want to bother, it probably
+isn't worth it.
+@c FIXME: Surgery on CVS/Repository should be avoided
+@c by making RELATIVE_REPOS the default.
+@c FIXME-maybe: might want some documented way to
+@c change the CVS/Root files in some particular tree.
+@c But then again, I don't know, maybe just having
+@c people do this in perl/shell/&c isn't so bad...
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Remote repositories
+@section Remote repositories
+@cindex Repositories, remote
+@cindex Remote repositories
+@cindex Client/Server Operation
+@cindex Server, CVS
+@cindex Remote repositories, port specification
+@cindex Repositories, remote, port specification
+@cindex Client/Server Operation, port specification
+@cindex pserver (client/server connection method), port specification
+@cindex kserver (client/server connection method), port specification
+@cindex gserver (client/server connection method), port specification
+@cindex port, specifying for remote repositories
+
+ Your working copy of the sources can be on a
+different machine than the repository. Using @sc{cvs}
+in this manner is known as @dfn{client/server}
+operation. You run @sc{cvs} on a machine which can
+mount your working directory, known as the
+@dfn{client}, and tell it to communicate to a machine
+which can mount the repository, known as the
+@dfn{server}. Generally, using a remote
+repository is just like using a local one, except that
+the format of the repository name is:
+
+@example
+[:@var{method}:][[@var{user}][:@var{password}]@@]@var{hostname}[:[@var{port}]]/path/to/repository
+@end example
+
+Specifying a password in the repository name is not recommended during
+checkout, since this will cause @sc{cvs} to store a cleartext copy of the
+password in each created directory. @code{cvs login} first instead
+(@pxref{Password authentication client}).
+
+The details of exactly what needs to be set up depend
+on how you are connecting to the server.
+
+@c Should we try to explain which platforms are which?
+@c Platforms like unix and VMS, which only allow
+@c privileged programs to bind to sockets <1024 lose on
+@c :server:
+@c Platforms like Mac and VMS, whose rsh program is
+@c unusable or nonexistent, lose on :ext:
+@c Platforms like OS/2 and NT probably could plausibly
+@c default either way (modulo -b troubles).
+
+@menu
+* Server requirements:: Memory and other resources for servers
+* The connection method:: Connection methods and method options
+* Connecting via rsh:: Using the @code{rsh} program to connect
+* Password authenticated:: Direct connections using passwords
+* GSSAPI authenticated:: Direct connections using GSSAPI
+* Kerberos authenticated:: Direct connections with Kerberos
+* Connecting via fork:: Using a forked @code{cvs server} to connect
+* Write proxies:: Distributing load across several CVS servers
+@end menu
+
+@node Server requirements
+@subsection Server requirements
+
+The quick answer to what sort of machine is suitable as
+a server is that requirements are modest---a server
+with 32M of memory or even less can handle a fairly
+large source tree with a fair amount of activity.
+@c Say something about CPU speed too? I'm even less sure
+@c what to say on that subject...
+
+The real answer, of course, is more complicated.
+Estimating the known areas of large memory consumption
+should be sufficient to estimate memory requirements.
+There are two such areas documented here; other memory
+consumption should be small by comparison (if you find
+that is not the case, let us know, as described in
+@ref{BUGS}, so we can update this documentation).
+
+The first area of big memory consumption is large
+checkouts, when using the @sc{cvs} server. The server
+consists of two processes for each client that it is
+serving. Memory consumption on the child process
+should remain fairly small. Memory consumption on the
+parent process, particularly if the network connection
+to the client is slow, can be expected to grow to
+slightly more than the size of the sources in a single
+directory, or two megabytes, whichever is larger.
+@c "two megabytes" of course is SERVER_HI_WATER. But
+@c we don't mention that here because we are
+@c documenting the default configuration of CVS. If it
+@c is a "standard" thing to change that value, it
+@c should be some kind of run-time configuration.
+@c
+@c See cvsclient.texi for more on the design decision
+@c to not have locks in place while waiting for the
+@c client, which is what results in memory consumption
+@c as high as this.
+
+Multiplying the size of each @sc{cvs} server by the
+number of servers which you expect to have active at
+one time should give an idea of memory requirements for
+the server. For the most part, the memory consumed by
+the parent process probably can be swap space rather
+than physical memory.
+@c Has anyone verified that notion about swap space?
+@c I say it based pretty much on guessing that the
+@c ->text of the struct buffer_data only gets accessed
+@c in a first in, first out fashion, but I haven't
+@c looked very closely.
+
+@c What about disk usage in /tmp on the server? I think that
+@c it can be substantial, but I haven't looked at this
+@c again and tried to figure it out ("cvs import" is
+@c probably the worst case...).
+
+The second area of large memory consumption is
+@code{diff}, when checking in large files. This is
+required even for binary files. The rule of thumb is
+to allow about ten times the size of the largest file
+you will want to check in, although five times may be
+adequate. For example, if you want to check in a file
+which is 10 megabytes, you should have 100 megabytes of
+memory on the machine doing the checkin (the server
+machine for client/server, or the machine running
+@sc{cvs} for non-client/server). This can be swap
+space rather than physical memory. Because the memory
+is only required briefly, there is no particular need
+to allow memory for more than one such checkin at a
+time.
+@c The 5-10 times rule of thumb is from Paul Eggert for
+@c GNU diff. I don't think it is in the GNU diff
+@c manual or anyplace like that.
+@c
+@c Probably we could be saying more about
+@c non-client/server CVS.
+@c I would guess for non-client/server CVS in an NFS
+@c environment the biggest issues are the network and
+@c the NFS server.
+
+Resource consumption for the client is even more
+modest---any machine with enough capacity to run the
+operating system in question should have little
+trouble.
+@c Is that true? I think the client still wants to
+@c (bogusly) store entire files in memory at times.
+
+For information on disk space requirements, see
+@ref{Creating a repository}.
+
+@node The connection method
+@subsection The connection method
+
+In its simplest form, the @var{method} portion of the repository string
+(@pxref{Remote repositories}) may be one of @samp{ext}, @samp{fork},
+@samp{gserver}, @samp{kserver}, @samp{local}, @samp{pserver}, and, on some
+platforms, @samp{server}.
+
+If @var{method} is not specified, and the repository
+name starts with a @samp{/}, then the default is @code{local}.
+If @var{method} is not specified, and the repository
+name does not start with a @samp{/}, then the default is @code{ext}
+or @code{server}, depending on your platform; both the @samp{ext}
+and @samp{server} methods are described in @ref{Connecting via rsh}.
+
+@cindex connection method options
+@cindex options, connection method
+The @code{ext}, @code{fork}, @code{gserver}, and @code{pserver} connection
+methods all accept optional method options, specified as part of the
+@var{method} string, like so:
+
+@example
+:@var{method}[;@var{option}=@var{arg}...]:@var{other_connection_data}
+@end example
+
+@sc{cvs} is not sensitive to the case of @var{method} or @var{option}, though
+it may sometimes be sensitive to the case of @var{arg}. The possible method
+options are as follows:
+
+@table @code
+@cindex CVS_PROXY_PORT
+@cindex proxy, method option
+@cindex proxyport, method option
+@cindex proxies, web, connecting via
+@cindex web proxies, connecting via
+@cindex proxies, HTTP, connecting via
+@cindex HTTP proxies, connecting via
+@item proxy=@var{hostname}
+@itemx proxyport=@var{port}
+These two method options can be used to connect via an HTTP tunnel style web
+proxy. @var{hostname} should be the name of the HTTP proxy server to connect
+through and @var{port} is the port number on the HTTP proxy server to connect
+via. @var{port} defaults to 8080.
+
+@strong{NOTE: An HTTP proxy server is not the same as a @sc{cvs} write proxy
+server - please see @ref{Write proxies} for more on @sc{cvs} write proxies.}
+
+For example, to connect pserver via a web proxy listening on port 8000 of
+www.myproxy.net, you would use a method of:
+
+@example
+:pserver;proxy=www.myproxy.net;proxyport=8000:@var{pserver_connection_string}
+@end example
+
+@strong{NOTE: In the above example, @var{pserver_connection_string} is still
+required to connect and authenticate to the CVS server, as noted in the
+upcoming sections on password authentication, @code{gserver}, and
+@code{kserver}. The example above only demonstrates a modification to the
+@var{method} portion of the repository name.}
+
+These options first appeared in @sc{cvs} version 1.12.7 and are valid as
+modifcations to the @code{gserver} and @code{pserver} connection methods.
+
+@cindex CVS_RSH method option
+@item CVS_RSH=@var{path}
+This method option can be used with the @code{ext} method to specify the path
+the @sc{cvs} client will use to find the remote shell used to contact the
+@sc{cvs} server and takes precedence over any path specified in the
+@code{$CVS_RSH} environment variable (@pxref{Connecting via rsh}). For
+example, to connect to a @sc{cvs} server via the local
+@file{/path/to/ssh/command} command, you could choose to specify the following
+@var{path} via the @code{CVS_RSH} method option:
+
+@example
+:ext;CVS_RSH=/path/to/ssh/command:@var{ext_connection_string}
+@end example
+
+This method option first appeared in @sc{cvs} version 1.12.11 and is valid only
+as a modifcation to the @code{ext} connection method.
+
+@cindex CVS_SERVER method option
+@item CVS_SERVER=@var{path}
+This method option can be used with the @code{ext} and @code{fork} methods to
+specify the path @sc{cvs} will use to find the @sc{cvs} executable on the
+@sc{cvs} server and takes precedence over any path specified in the
+@code{$CVS_SERVER} environment variable (@pxref{Connecting via rsh}). For
+example, to select the remote @file{/path/to/cvs/command} executable as your
+@sc{cvs} server application on the @sc{cvs} server machine, you could choose to
+specify the following @var{path} via the @code{CVS_SERVER} method option:
+
+@example
+:ext;CVS_SERVER=/path/to/cvs/command:@var{ext_connection_string}
+@end example
+
+@noindent
+or, to select an executable named @samp{cvs-1.12.11}, assuming it is in your
+@code{$PATH} on the @sc{cvs} server:
+
+@example
+:ext;CVS_SERVER=cvs-1.12.11:@var{ext_connection_string}
+@end example
+
+This method option first appeared in @sc{cvs} version 1.12.11 and is valid
+as a modifcation to both the @code{ext} and @code{fork} connection methods.
+
+@cindex Redirect, method option
+@item Redirect=@var{boolean-state}
+The @code{Redirect} method option determines whether the @sc{cvs} client will
+allow a @sc{cvs} server to redirect it to a different @sc{cvs} server, usually
+for write requests, as in a write proxy setup.
+
+A @var{boolean-state} of any value acceptable for boolean @file{CVSROOT/config}
+file options is acceptable here (@pxref{config}). For example, @samp{on},
+@samp{off}, @samp{true}, and @samp{false} are all valid values for
+@var{boolean-state}. @var{boolean-state} for the @code{Redirect} method option
+defaults to @samp{on}.
+
+This option will have no effect when talking to any non-secondary @sc{cvs}
+server. For more on write proxies and secondary servers, please see
+@ref{Write proxies}.
+
+This method option first appeared in @sc{cvs} version 1.12.11 and is valid only
+as a modifcation to the @code{ext} connection method.
+@end table
+
+As a further example, to combine both the @code{CVS_RSH} and @code{CVS_SERVER}
+options, a method specification like the following would work:
+
+@example
+:ext;CVS_RSH=/path/to/ssh/command;CVS_SERVER=/path/to/cvs/command:
+@end example
+
+This means that you would not need to have
+the @code{CVS_SERVER} or @code{CVS_RSH} environment
+variables set correctly. See @ref{Connecting via rsh}, for more details on
+these environment variables.
+
+@node Connecting via rsh
+@subsection Connecting with rsh
+
+@cindex rsh
+@sc{cvs} uses the @samp{rsh} protocol to perform these
+operations, so the remote user host needs to have a
+@file{.rhosts} file which grants access to the local
+user. Note that the program that @sc{cvs} uses for this
+purpose may be specified using the @file{--with-rsh}
+flag to configure.
+
+For example, suppose you are the user @samp{mozart} on
+the local machine @samp{toe.example.com}, and the
+server machine is @samp{faun.example.org}. On
+faun, put the following line into the file
+@file{.rhosts} in @samp{bach}'s home directory:
+
+@example
+toe.example.com mozart
+@end example
+
+@noindent
+Then test that @samp{rsh} is working with
+
+@example
+rsh -l bach faun.example.org 'echo $PATH'
+@end example
+
+@cindex CVS_SERVER, environment variable
+Next you have to make sure that @code{rsh} will be able
+to find the server. Make sure that the path which
+@code{rsh} printed in the above example includes the
+directory containing a program named @code{cvs} which
+is the server. You need to set the path in
+@file{.bashrc}, @file{.cshrc}, etc., not @file{.login}
+or @file{.profile}. Alternately, you can set the
+environment variable @code{CVS_SERVER} on the client
+machine to the filename of the server you want to use,
+for example @file{/usr/local/bin/cvs-1.6}.
+For the @code{ext} and @code{fork} methods, you may
+also specify @var{CVS_SERVER} as an otpion in the
+@var{CVSROOT} so that you may use different servers for
+differnt roots. See @ref{Remote repositories} for more
+details.
+
+There is no need to edit @file{inetd.conf} or start a
+@sc{cvs} server daemon.
+
+@cindex :server:, setting up
+@cindex :ext:, setting up
+@cindex Kerberos, using kerberized rsh
+@cindex SSH (rsh replacement)
+@cindex rsh replacements (Kerberized, SSH, &c)
+There are two access methods that you use in @code{CVSROOT}
+for rsh. @code{:server:} specifies an internal rsh
+client, which is supported only by some @sc{cvs} ports.
+@code{:ext:} specifies an external rsh program. By
+default this is @code{rsh} (unless otherwise specified
+by the @file{--with-rsh} flag to configure) but you may set the
+@code{CVS_RSH} environment variable to invoke another
+program which can access the remote server (for
+example, @code{remsh} on HP-UX 9 because @code{rsh} is
+something different). It must be a program which can
+transmit data to and from the server without modifying
+it; for example the Windows NT @code{rsh} is not
+suitable since it by default translates between CRLF
+and LF. The OS/2 @sc{cvs} port has a hack to pass @samp{-b}
+to @code{rsh} to get around this, but since this could
+potentially cause problems for programs other than the
+standard @code{rsh}, it may change in the future. If
+you set @code{CVS_RSH} to @code{SSH} or some other rsh
+replacement, the instructions in the rest of this
+section concerning @file{.rhosts} and so on are likely
+to be inapplicable; consult the documentation for your rsh
+replacement.
+
+You may choose to specify the @var{CVS_RSH} option as a method option
+in the @var{CVSROOT} string to allow you to use different connection tools
+for different roots (@pxref{The connection method}). For example, allowing
+some roots to use @code{CVS_RSH=remsh} and some to use
+@code{CVS_RSH=ssh} for the @code{ext} method. See also
+the @ref{Remote repositories} for more details.
+@c See also the comment in src/client.c for rationale
+@c concerning "rsh" being the default and never
+@c "remsh".
+
+Continuing our example, supposing you want to access
+the module @file{foo} in the repository
+@file{/usr/local/cvsroot/}, on machine
+@file{faun.example.org}, you are ready to go:
+
+@example
+cvs -d :ext:bach@@faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+@noindent
+(The @file{bach@@} can be omitted if the username is
+the same on both the local and remote hosts.)
+
+@c Should we mention "rsh host echo hi" and "rsh host
+@c cat" (the latter followed by typing text and ^D)
+@c as troubleshooting techniques? Probably yes
+@c (people tend to have trouble setting this up),
+@c but this kind of thing can be hard to spell out.
+
+@node Password authenticated
+@subsection Direct connection with password authentication
+
+The @sc{cvs} client can also connect to the server
+using a password protocol. This is particularly useful
+if using @code{rsh} is not feasible (for example,
+the server is behind a firewall), and Kerberos also is
+not available.
+
+ To use this method, it is necessary to make
+some adjustments on both the server and client sides.
+
+@menu
+* Password authentication server:: Setting up the server
+* Password authentication client:: Using the client
+* Password authentication security:: What this method does and does not do
+@end menu
+
+@node Password authentication server
+@subsubsection Setting up the server for password authentication
+
+First of all, you probably want to tighten the
+permissions on the @file{$CVSROOT} and
+@file{$CVSROOT/CVSROOT} directories. See @ref{Password
+authentication security}, for more details.
+
+@cindex pserver (subcommand)
+@cindex Remote repositories, port specification
+@cindex Repositories, remote, port specification
+@cindex Client/Server Operation, port specification
+@cindex pserver (client/server connection method), port specification
+@cindex kserver (client/server connection method), port specification
+@cindex gserver (client/server connection method), port specification
+@cindex port, specifying for remote repositories
+@cindex Password server, setting up
+@cindex Authenticating server, setting up
+@cindex inetd, configuring for pserver
+@cindex xinetd, configuring for pserver
+@c FIXME: this isn't quite right regarding port
+@c numbers; CVS looks up "cvspserver" in
+@c /etc/services (on unix, but what about non-unix?).
+On the server side, the file @file{/etc/inetd.conf}
+needs to be edited so @code{inetd} knows to run the
+command @code{cvs pserver} when it receives a
+connection on the right port. By default, the port
+number is 2401; it would be different if your client
+were compiled with @code{CVS_AUTH_PORT} defined to
+something else, though. This can also be specified in the CVSROOT variable
+(@pxref{Remote repositories}) or overridden with the CVS_CLIENT_PORT
+environment variable (@pxref{Environment variables}).
+
+ If your @code{inetd} allows raw port numbers in
+@file{/etc/inetd.conf}, then the following (all on a
+single line in @file{inetd.conf}) should be sufficient:
+
+@example
+2401 stream tcp nowait root /usr/local/bin/cvs
+cvs -f --allow-root=/usr/cvsroot pserver
+@end example
+
+@noindent
+(You could also use the
+@samp{-T} option to specify a temporary directory.)
+
+The @samp{--allow-root} option specifies the allowable
+@sc{cvsroot} directory. Clients which attempt to use a
+different @sc{cvsroot} directory will not be allowed to
+connect. If there is more than one @sc{cvsroot}
+directory which you want to allow, repeat the option.
+(Unfortunately, many versions of @code{inetd} have very small
+limits on the number of arguments and/or the total length
+of the command. The usual solution to this problem is
+to have @code{inetd} run a shell script which then invokes
+@sc{cvs} with the necessary arguments.)
+
+ If your @code{inetd} wants a symbolic service
+name instead of a raw port number, then put this in
+@file{/etc/services}:
+
+@example
+cvspserver 2401/tcp
+@end example
+
+@noindent
+and put @code{cvspserver} instead of @code{2401} in @file{inetd.conf}.
+
+If your system uses @code{xinetd} instead of @code{inetd},
+the procedure is slightly different.
+Create a file called @file{/etc/xinetd.d/cvspserver} containing the following:
+
+@example
+service cvspserver
+@{
+ port = 2401
+ socket_type = stream
+ protocol = tcp
+ wait = no
+ user = root
+ passenv = PATH
+ server = /usr/local/bin/cvs
+ server_args = -f --allow-root=/usr/cvsroot pserver
+@}
+@end example
+
+@noindent
+(If @code{cvspserver} is defined in @file{/etc/services}, you can omit
+the @code{port} line.)
+
+ Once the above is taken care of, restart your
+@code{inetd}, or do whatever is necessary to force it
+to reread its initialization files.
+
+If you are having trouble setting this up, see
+@ref{Connection}.
+
+@cindex CVS passwd file
+@cindex passwd (admin file)
+Because the client stores and transmits passwords in
+cleartext (almost---see @ref{Password authentication
+security}, for details), a separate @sc{cvs} password
+file is generally used, so people don't compromise
+their regular passwords when they access the
+repository. This file is
+@file{$CVSROOT/CVSROOT/passwd} (@pxref{Intro
+administrative files}). It uses a colon-separated
+format, similar to @file{/etc/passwd} on Unix systems,
+except that it has fewer fields: @sc{cvs} username,
+optional password, and an optional system username for
+@sc{cvs} to run as if authentication succeeds. Here is
+an example @file{passwd} file with five entries:
+
+@example
+anonymous:
+bach:ULtgRLXo7NRxs
+spwang:1sOp854gDF3DY
+melissa:tGX1fS8sun6rY:pubcvs
+qproj:XR4EZcEs0szik:pubcvs
+@end example
+
+@noindent
+(The passwords are encrypted according to the standard
+Unix @code{crypt()} function, so it is possible to
+paste in passwords directly from regular Unix
+@file{/etc/passwd} files.)
+
+The first line in the example will grant access to any
+@sc{cvs} client attempting to authenticate as user
+@code{anonymous}, no matter what password they use,
+including an empty password. (This is typical for
+sites granting anonymous read-only access; for
+information on how to do the "read-only" part, see
+@ref{Read-only access}.)
+
+The second and third lines will grant access to
+@code{bach} and @code{spwang} if they supply their
+respective plaintext passwords.
+
+@cindex User aliases
+The fourth line will grant access to @code{melissa}, if
+she supplies the correct password, but her @sc{cvs}
+operations will actually run on the server side under
+the system user @code{pubcvs}. Thus, there need not be
+any system user named @code{melissa}, but there
+@emph{must} be one named @code{pubcvs}.
+
+The fifth line shows that system user identities can be
+shared: any client who successfully authenticates as
+@code{qproj} will actually run as @code{pubcvs}, just
+as @code{melissa} does. That way you could create a
+single, shared system user for each project in your
+repository, and give each developer their own line in
+the @file{$CVSROOT/CVSROOT/passwd} file. The @sc{cvs}
+username on each line would be different, but the
+system username would be the same. The reason to have
+different @sc{cvs} usernames is that @sc{cvs} will log their
+actions under those names: when @code{melissa} commits
+a change to a project, the checkin is recorded in the
+project's history under the name @code{melissa}, not
+@code{pubcvs}. And the reason to have them share a
+system username is so that you can arrange permissions
+in the relevant area of the repository such that only
+that account has write-permission there.
+
+If the system-user field is present, all
+password-authenticated @sc{cvs} commands run as that
+user; if no system user is specified, @sc{cvs} simply
+takes the @sc{cvs} username as the system username and
+runs commands as that user. In either case, if there
+is no such user on the system, then the @sc{cvs}
+operation will fail (regardless of whether the client
+supplied a valid password).
+
+The password and system-user fields can both be omitted
+(and if the system-user field is omitted, then also
+omit the colon that would have separated it from the
+encrypted password). For example, this would be a
+valid @file{$CVSROOT/CVSROOT/passwd} file:
+
+@example
+anonymous::pubcvs
+fish:rKa5jzULzmhOo:kfogel
+sussman:1sOp854gDF3DY
+@end example
+
+@noindent
+When the password field is omitted or empty, then the
+client's authentication attempt will succeed with any
+password, including the empty string. However, the
+colon after the @sc{cvs} username is always necessary,
+even if the password is empty.
+
+@sc{cvs} can also fall back to use system authentication.
+When authenticating a password, the server first checks
+for the user in the @file{$CVSROOT/CVSROOT/passwd}
+file. If it finds the user, it will use that entry for
+authentication as described above. But if it does not
+find the user, or if the @sc{cvs} @file{passwd} file
+does not exist, then the server can try to authenticate
+the username and password using the operating system's
+user-lookup routines (this "fallback" behavior can be
+disabled by setting @code{SystemAuth=no} in the
+@sc{cvs} @file{config} file, @pxref{config}).
+
+The default fallback behavior is to look in
+@file{/etc/passwd} for this system user unless your
+system has PAM (Pluggable Authentication Modules)
+and your @sc{cvs} server executable was configured to
+use it at compile time (using @code{./configure --enable-pam} - see the
+INSTALL file for more). In this case, PAM will be consulted instead.
+This means that @sc{cvs} can be configured to use any password
+authentication source PAM can be configured to use (possibilities
+include a simple UNIX password, NIS, LDAP, and others) in its
+global configuration file (usually @file{/etc/pam.conf}
+or possibly @file{/etc/pam.d/cvs}). See your PAM documentation
+for more details on PAM configuration.
+
+Note that PAM is an experimental feature in @sc{cvs} and feedback is
+encouraged. Please send a mail to one of the @sc{cvs} mailing lists
+(@code{info-cvs@@nongnu.org} or @code{bug-cvs@@nongnu.org}) if you use the
+@sc{cvs} PAM support.
+
+@strong{WARNING: Using PAM gives the system administrator much more
+flexibility about how @sc{cvs} users are authenticated but
+no more security than other methods. See below for more.}
+
+CVS needs an "auth", "account" and "session" module in the
+PAM configuration file. A typical PAM configuration
+would therefore have the following lines
+in @file{/etc/pam.conf} to emulate the standard @sc{cvs}
+system @file{/etc/passwd} authentication:
+
+@example
+cvs auth required pam_unix.so
+cvs account required pam_unix.so
+cvs session required pam_unix.so
+@end example
+
+The the equivalent @file{/etc/pam.d/cvs} would contain
+
+@example
+auth required pam_unix.so
+account required pam_unix.so
+session required pam_unix.so
+@end example
+
+Some systems require a full path to the module so that
+@file{pam_unix.so} (Linux) would become something like
+@file{/usr/lib/security/$ISA/pam_unix.so.1} (Sun Solaris).
+See the @file{contrib/pam} subdirectory of the @sc{cvs}
+source distribution for further example configurations.
+
+The PAM service name given above as "cvs" is just
+the service name in the default configuration and can be
+set using
+@code{./configure --with-hardcoded-pam-service-name=<pam-service-name>}
+before compiling. @sc{cvs} can also be configured to use whatever
+name it is invoked as as its PAM service name using
+@code{./configure --without-hardcoded-pam-service-name}, but this
+feature should not be used if you may not have control of the name
+@sc{cvs} will be invoked as.
+
+Be aware, also, that falling back to system
+authentication might be a security risk: @sc{cvs}
+operations would then be authenticated with that user's
+regular login password, and the password flies across
+the network in plaintext. See @ref{Password
+authentication security} for more on this.
+This may be more of a problem with PAM authentication
+because it is likely that the source of the system
+password is some central authentication service like
+LDAP which is also used to authenticate other services.
+
+On the other hand, PAM makes it very easy to change your password
+regularly. If they are given the option of a one-password system for
+all of their activities, users are often more willing to change their
+password on a regular basis.
+
+In the non-PAM configuration where the password is stored in the
+@file{CVSROOT/passwd} file, it is difficult to change passwords on a
+regular basis since only administrative users (or in some cases
+processes that act as an administrative user) are typically given
+access to modify this file. Either there needs to be some
+hand-crafted web page or set-uid program to update the file, or the
+update needs to be done by submitting a request to an administrator to
+perform the duty by hand. In the first case, having to remember to
+update a separate password on a periodic basis can be difficult. In
+the second case, the manual nature of the change will typically mean
+that the password will not be changed unless it is absolutely
+necessary.
+
+Note that PAM administrators should probably avoid configuring
+one-time-passwords (OTP) for @sc{cvs} authentication/authorization. If
+OTPs are desired, the administrator may wish to encourage the use of
+one of the other Client/Server access methods. See the section on
+@pxref{Remote repositories} for a list of other methods.
+
+Right now, the only way to put a password in the
+@sc{cvs} @file{passwd} file is to paste it there from
+somewhere else. Someday, there may be a @code{cvs
+passwd} command.
+
+Unlike many of the files in @file{$CVSROOT/CVSROOT}, it
+is normal to edit the @file{passwd} file in-place,
+rather than via @sc{cvs}. This is because of the
+possible security risks of having the @file{passwd}
+file checked out to people's working copies. If you do
+want to include the @file{passwd} file in checkouts of
+@file{$CVSROOT/CVSROOT}, see @ref{checkoutlist}.
+
+@c We might also suggest using the @code{htpasswd} command
+@c from freely available web servers as well, but that
+@c would open up a can of worms in that the users next
+@c questions are likely to be "where do I get it?" and
+@c "how do I use it?"
+@c Also note that htpasswd, at least the version I had,
+@c likes to clobber the third field.
+
+@node Password authentication client
+@subsubsection Using the client with password authentication
+@cindex Login (subcommand)
+@cindex Password client, using
+@cindex Authenticated client, using
+@cindex :pserver:, setting up
+To run a @sc{cvs} command on a remote repository via
+the password-authenticating server, one specifies the
+@code{pserver} protocol, optional username, repository host, an
+optional port number, and path to the repository. For example:
+
+@example
+cvs -d :pserver:faun.example.org:/usr/local/cvsroot checkout someproj
+@end example
+
+@noindent
+or
+
+@example
+CVSROOT=:pserver:bach@@faun.example.org:2401/usr/local/cvsroot
+cvs checkout someproj
+@end example
+
+However, unless you're connecting to a public-access
+repository (i.e., one where that username doesn't
+require a password), you'll need to supply a password or @dfn{log in} first.
+Logging in verifies your password with the repository and stores it in a file.
+It's done with the @code{login} command, which will
+prompt you interactively for the password if you didn't supply one as part of
+@var{$CVSROOT}:
+
+@example
+cvs -d :pserver:bach@@faun.example.org:/usr/local/cvsroot login
+CVS password:
+@end example
+
+@noindent
+or
+
+@example
+cvs -d :pserver:bach:p4ss30rd@@faun.example.org:/usr/local/cvsroot login
+@end example
+
+After you enter the password, @sc{cvs} verifies it with
+the server. If the verification succeeds, then that
+combination of username, host, repository, and password
+is permanently recorded, so future transactions with
+that repository won't require you to run @code{cvs
+login}. (If verification fails, @sc{cvs} will exit
+complaining that the password was incorrect, and
+nothing will be recorded.)
+
+The records are stored, by default, in the file
+@file{$HOME/.cvspass}. That file's format is
+human-readable, and to a degree human-editable, but
+note that the passwords are not stored in
+cleartext---they are trivially encoded to protect them
+from "innocent" compromise (i.e., inadvertent viewing
+by a system administrator or other non-malicious
+person).
+
+@cindex CVS_PASSFILE, environment variable
+You can change the default location of this file by
+setting the @code{CVS_PASSFILE} environment variable.
+If you use this variable, make sure you set it
+@emph{before} @code{cvs login} is run. If you were to
+set it after running @code{cvs login}, then later
+@sc{cvs} commands would be unable to look up the
+password for transmission to the server.
+
+Once you have logged in, all @sc{cvs} commands using
+that remote repository and username will authenticate
+with the stored password. So, for example
+
+@example
+cvs -d :pserver:bach@@faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+@noindent
+should just work (unless the password changes on the
+server side, in which case you'll have to re-run
+@code{cvs login}).
+
+Note that if the @samp{:pserver:} were not present in
+the repository specification, @sc{cvs} would assume it
+should use @code{rsh} to connect with the server
+instead (@pxref{Connecting via rsh}).
+
+Of course, once you have a working copy checked out and
+are running @sc{cvs} commands from within it, there is
+no longer any need to specify the repository
+explicitly, because @sc{cvs} can deduce the repository
+from the working copy's @file{CVS} subdirectory.
+
+@c FIXME: seems to me this needs somewhat more
+@c explanation.
+@cindex Logout (subcommand)
+The password for a given remote repository can be
+removed from the @code{CVS_PASSFILE} by using the
+@code{cvs logout} command.
+
+@node Password authentication security
+@subsubsection Security considerations with password authentication
+
+@cindex Security, of pserver
+The passwords are stored on the client side in a
+trivial encoding of the cleartext, and transmitted in
+the same encoding. The encoding is done only to
+prevent inadvertent password compromises (i.e., a
+system administrator accidentally looking at the file),
+and will not prevent even a naive attacker from gaining
+the password.
+
+@c FIXME: The bit about "access to the repository
+@c implies general access to the system is *not* specific
+@c to pserver; it applies to kerberos and SSH and
+@c everything else too. Should reorganize the
+@c documentation to make this clear.
+The separate @sc{cvs} password file (@pxref{Password
+authentication server}) allows people
+to use a different password for repository access than
+for login access. On the other hand, once a user has
+non-read-only
+access to the repository, she can execute programs on
+the server system through a variety of means. Thus, repository
+access implies fairly broad system access as well. It
+might be possible to modify @sc{cvs} to prevent that,
+but no one has done so as of this writing.
+@c OpenBSD uses chroot() and copies the repository to
+@c provide anonymous read-only access (for details see
+@c http://www.openbsd.org/anoncvs.shar). While this
+@c closes the most obvious holes, I'm not sure it
+@c closes enough holes to recommend it (plus it is
+@c *very* easy to accidentally screw up a setup of this
+@c type).
+
+Note that because the @file{$CVSROOT/CVSROOT} directory
+contains @file{passwd} and other files which are used
+to check security, you must control the permissions on
+this directory as tightly as the permissions on
+@file{/etc}. The same applies to the @file{$CVSROOT}
+directory itself and any directory
+above it in the tree. Anyone who has write access to
+such a directory will have the ability to become any
+user on the system. Note that these permissions are
+typically tighter than you would use if you are not
+using pserver.
+@c TODO: Would be really nice to document/implement a
+@c scheme where the CVS server can run as some non-root
+@c user, e.g. "cvs". CVSROOT/passwd would contain a
+@c bunch of entries of the form foo:xxx:cvs (or the "cvs"
+@c would be implicit). This would greatly reduce
+@c security risks such as those hinted at in the
+@c previous paragraph. I think minor changes to CVS
+@c might be required but mostly this would just need
+@c someone who wants to play with it, document it, &c.
+
+In summary, anyone who gets the password gets
+repository access (which may imply some measure of general system
+access as well). The password is available to anyone
+who can sniff network packets or read a protected
+(i.e., user read-only) file. If you want real
+security, get Kerberos.
+
+@node GSSAPI authenticated
+@subsection Direct connection with GSSAPI
+
+@cindex GSSAPI
+@cindex Security, GSSAPI
+@cindex :gserver:, setting up
+@cindex Kerberos, using :gserver:
+GSSAPI is a generic interface to network security
+systems such as Kerberos 5.
+If you have a working GSSAPI library, you can have
+@sc{cvs} connect via a direct @sc{tcp} connection,
+authenticating with GSSAPI.
+
+To do this, @sc{cvs} needs to be compiled with GSSAPI
+support; when configuring @sc{cvs} it tries to detect
+whether GSSAPI libraries using Kerberos version 5 are
+present. You can also use the @file{--with-gssapi}
+flag to configure.
+
+The connection is authenticated using GSSAPI, but the
+message stream is @emph{not} authenticated by default.
+You must use the @code{-a} global option to request
+stream authentication.
+
+The data transmitted is @emph{not} encrypted by
+default. Encryption support must be compiled into both
+the client and the server; use the
+@file{--enable-encrypt} configure option to turn it on.
+You must then use the @code{-x} global option to
+request encryption.
+
+GSSAPI connections are handled on the server side by
+the same server which handles the password
+authentication server; see @ref{Password authentication
+server}. If you are using a GSSAPI mechanism such as
+Kerberos which provides for strong authentication, you
+will probably want to disable the ability to
+authenticate via cleartext passwords. To do so, create
+an empty @file{CVSROOT/passwd} password file, and set
+@code{SystemAuth=no} in the config file
+(@pxref{config}).
+
+The GSSAPI server uses a principal name of
+cvs/@var{hostname}, where @var{hostname} is the
+canonical name of the server host. You will have to
+set this up as required by your GSSAPI mechanism.
+
+To connect using GSSAPI, use the @samp{:gserver:} method. For
+example,
+
+@example
+cvs -d :gserver:faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+@node Kerberos authenticated
+@subsection Direct connection with Kerberos
+
+@cindex Kerberos, using :kserver:
+@cindex Security, Kerberos
+@cindex :kserver:, setting up
+The easiest way to use Kerberos is to use the Kerberos
+@code{rsh}, as described in @ref{Connecting via rsh}.
+The main disadvantage of using rsh is that all the data
+needs to pass through additional programs, so it may be
+slower. So if you have Kerberos installed you can
+connect via a direct @sc{tcp} connection,
+authenticating with Kerberos.
+
+This section concerns the Kerberos network security
+system, version 4. Kerberos version 5 is supported via
+the GSSAPI generic network security interface, as
+described in the previous section.
+
+To do this, @sc{cvs} needs to be compiled with Kerberos
+support; when configuring @sc{cvs} it tries to detect
+whether Kerberos is present or you can use the
+@file{--with-krb4} flag to configure.
+
+The data transmitted is @emph{not} encrypted by
+default. Encryption support must be compiled into both
+the client and server; use the
+@file{--enable-encryption} configure option to turn it
+on. You must then use the @code{-x} global option to
+request encryption.
+
+The CVS client will attempt to connect to port 1999 by default.
+
+@cindex kinit
+When you want to use @sc{cvs}, get a ticket in the
+usual way (generally @code{kinit}); it must be a ticket
+which allows you to log into the server machine. Then
+you are ready to go:
+
+@example
+cvs -d :kserver:faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+Previous versions of @sc{cvs} would fall back to a
+connection via rsh; this version will not do so.
+
+@node Connecting via fork
+@subsection Connecting with fork
+
+@cindex fork, access method
+@cindex :fork:, setting up
+This access method allows you to connect to a
+repository on your local disk via the remote protocol.
+In other words it does pretty much the same thing as
+@code{:local:}, but various quirks, bugs and the like are
+those of the remote @sc{cvs} rather than the local
+@sc{cvs}.
+
+For day-to-day operations you might prefer either
+@code{:local:} or @code{:fork:}, depending on your
+preferences. Of course @code{:fork:} comes in
+particularly handy in testing or
+debugging @code{cvs} and the remote protocol.
+Specifically, we avoid all of the network-related
+setup/configuration, timeouts, and authentication
+inherent in the other remote access methods but still
+create a connection which uses the remote protocol.
+
+To connect using the @code{fork} method, use
+@samp{:fork:} and the pathname to your local
+repository. For example:
+
+@example
+cvs -d :fork:/usr/local/cvsroot checkout foo
+@end example
+
+@cindex CVS_SERVER, and :fork:
+As with @code{:ext:}, the server is called @samp{cvs}
+by default, or the value of the @code{CVS_SERVER}
+environment variable.
+
+
+@node Write proxies
+@subsection Distributing load across several CVS servers
+
+@cindex PrimaryServer, in CVSROOT/config
+@cindex Primary server
+@cindex Secondary server
+@cindex proxy, write
+@cindex write proxy
+@sc{cvs} can be configured to distribute usage across several @sc{cvs}
+servers. This is accomplished by means of one or more @dfn{write proxies}, or
+@dfn{secondary servers}, for a single @dfn{primary server}.
+
+When a @sc{cvs} client accesses a secondary server and only sends read
+requests, then the secondary server handles the entire request. If the client
+sends any write requests, however, the secondary server asks the client to
+redirect its write request to the primary server, if the client supports
+redirect requests, and otherwise becomes a transparent proxy for the primary
+server, which actually handles the write request.
+
+In this manner, any number of read-only secondary servers may be configured as
+write proxies for the primary server, effectively distributing the load from
+all read operations between the secondary servers and restricting the load on
+the primary server to write operations and pushing changes to the secondaries.
+
+Primary servers will not automatically push changes to secondaries. This must
+be configured via @file{loginfo}, @file{postadmin}, @file{posttag}, &
+@file{postwatch} scripts (@pxref{Trigger Scripts}) like the following:
+
+@example
+ALL rsync -gopr -essh ./ secondary:/cvsroot/%p &
+@end example
+
+You would probably actually want to lock directories for write on the secondary
+and for read on the primary before running the @samp{rsync} in the above
+example, but describing such a setup is beyond the scope of this document.
+
+A secondary advantage of a write proxy setup is that users pointing at the
+secondary server can still execute fast read operations while on a network that
+connects to the primary over a slow link or even one where the link to the
+primary is periodically broken. Only write operations will require the network
+link to the primary.
+
+To configure write proxies, the primary must be specified with the
+@samp{PrimaryServer} option in @file{CVSROOT/config} (@pxref{config}). For the
+transparent proxy mode to work, all secondary servers must also be running the
+same version of the @sc{cvs} server, or at least one that provides the same
+list of supported requests to the client as the primary server. This is not
+necessary for redirection.
+
+Once a primary server is configured, secondary servers may be configured by:
+
+@enumerate
+@item
+Duplicating the primary repository at the new location.
+@item
+Setting up the @file{loginfo}, @file{postadmin}, @file{posttag}, and
+@file{postwatch} files on the primary to propagate writes to the new secondary.
+@item
+Configure remote access to the secondary(ies) as you would configure access
+to any other CVS server (@pxref{Remote repositories}).
+@item
+Ensuring that @code{--allow-root=@var{secondary-cvsroot}} is passed to
+@strong{all} incovations of the secondary server if the path to the @sc{cvs}
+repository directory is different on the two servers and you wish to support
+clients that do not handle the @samp{Redirect} resopnse (CVS 1.12.9 and earlier
+clients do not handle the @samp{Redirect} response).
+
+Please note, again, that writethrough proxy suport requires
+@code{--allow-root=@var{secondary-cvsroot}} to be specified for @strong{all}
+incovations of the secondary server, not just @samp{pserver} invocations.
+This may require a wrapper script for the @sc{cvs} executable
+on your server machine.
+@end enumerate
+
+
+@c ---------------------------------------------------------------------
+@node Read-only access
+@section Read-only repository access
+@cindex Read-only repository access
+@cindex readers (admin file)
+@cindex writers (admin file)
+
+ It is possible to grant read-only repository
+access to people using the password-authenticated
+server (@pxref{Password authenticated}). (The
+other access methods do not have explicit support for
+read-only users because those methods all assume login
+access to the repository machine anyway, and therefore
+the user can do whatever local file permissions allow
+her to do.)
+
+ A user who has read-only access can do only
+those @sc{cvs} operations which do not modify the
+repository, except for certain ``administrative'' files
+(such as lock files and the history file). It may be
+desirable to use this feature in conjunction with
+user-aliasing (@pxref{Password authentication server}).
+
+Unlike with previous versions of @sc{cvs}, read-only
+users should be able merely to read the repository, and
+not to execute programs on the server or otherwise gain
+unexpected levels of access. Or to be more accurate,
+the @emph{known} holes have been plugged. Because this
+feature is new and has not received a comprehensive
+security audit, you should use whatever level of
+caution seems warranted given your attitude concerning
+security.
+
+ There are two ways to specify read-only access
+for a user: by inclusion, and by exclusion.
+
+ "Inclusion" means listing that user
+specifically in the @file{$CVSROOT/CVSROOT/readers}
+file, which is simply a newline-separated list of
+users. Here is a sample @file{readers} file:
+
+@example
+melissa
+splotnik
+jrandom
+@end example
+
+@noindent
+ (Don't forget the newline after the last user.)
+
+ "Exclusion" means explicitly listing everyone
+who has @emph{write} access---if the file
+
+@example
+$CVSROOT/CVSROOT/writers
+@end example
+
+@noindent
+exists, then only
+those users listed in it have write access, and
+everyone else has read-only access (of course, even the
+read-only users still need to be listed in the
+@sc{cvs} @file{passwd} file). The
+@file{writers} file has the same format as the
+@file{readers} file.
+
+ Note: if your @sc{cvs} @file{passwd}
+file maps cvs users onto system users (@pxref{Password
+authentication server}), make sure you deny or grant
+read-only access using the @emph{cvs} usernames, not
+the system usernames. That is, the @file{readers} and
+@file{writers} files contain cvs usernames, which may
+or may not be the same as system usernames.
+
+ Here is a complete description of the server's
+behavior in deciding whether to grant read-only or
+read-write access:
+
+ If @file{readers} exists, and this user is
+listed in it, then she gets read-only access. Or if
+@file{writers} exists, and this user is NOT listed in
+it, then she also gets read-only access (this is true
+even if @file{readers} exists but she is not listed
+there). Otherwise, she gets full read-write access.
+
+ Of course there is a conflict if the user is
+listed in both files. This is resolved in the more
+conservative way, it being better to protect the
+repository too much than too little: such a user gets
+read-only access.
+
+@node Server temporary directory
+@section Temporary directories for the server
+@cindex Temporary directories, and server
+@cindex Server, temporary directories
+
+While running, the @sc{cvs} server creates temporary
+directories. They are named
+
+@example
+cvs-serv@var{pid}
+@end example
+
+@noindent
+where @var{pid} is the process identification number of
+the server.
+They are located in the directory specified by
+the @samp{-T} global option (@pxref{Global options}),
+the @code{TMPDIR} environment variable (@pxref{Environment variables}),
+or, failing that, @file{/tmp}.
+
+In most cases the server will remove the temporary
+directory when it is done, whether it finishes normally
+or abnormally. However, there are a few cases in which
+the server does not or cannot remove the temporary
+directory, for example:
+
+@itemize @bullet
+@item
+If the server aborts due to an internal server error,
+it may preserve the directory to aid in debugging
+
+@item
+If the server is killed in a way that it has no way of
+cleaning up (most notably, @samp{kill -KILL} on unix).
+
+@item
+If the system shuts down without an orderly shutdown,
+which tells the server to clean up.
+@end itemize
+
+In cases such as this, you will need to manually remove
+the @file{cvs-serv@var{pid}} directories. As long as
+there is no server running with process identification
+number @var{pid}, it is safe to do so.
+
+@c ---------------------------------------------------------------------
+@node Starting a new project
+@chapter Starting a project with CVS
+@cindex Starting a project with CVS
+@cindex Creating a project
+
+@comment --moduledb--
+Because renaming files and moving them between
+directories is somewhat inconvenient, the first thing
+you do when you start a new project should be to think
+through your file organization. It is not impossible
+to rename or move files, but it does increase the
+potential for confusion and @sc{cvs} does have some
+quirks particularly in the area of renaming
+directories. @xref{Moving files}.
+
+What to do next depends on the situation at hand.
+
+@menu
+* Setting up the files:: Getting the files into the repository
+* Defining the module:: How to make a module of the files
+@end menu
+@c -- File permissions!
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Setting up the files
+@section Setting up the files
+
+The first step is to create the files inside the repository. This can
+be done in a couple of different ways.
+
+@c -- The contributed scripts
+@menu
+* From files:: This method is useful with old projects
+ where files already exists.
+* From other version control systems:: Old projects where you want to
+ preserve history from another system.
+* From scratch:: Creating a directory tree from scratch.
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node From files
+@subsection Creating a directory tree from a number of files
+@cindex Importing files
+
+When you begin using @sc{cvs}, you will probably already have several
+projects that can be
+put under @sc{cvs} control. In these cases the easiest way is to use the
+@code{import} command. An example is probably the easiest way to
+explain how to use it. If the files you want to install in
+@sc{cvs} reside in @file{@var{wdir}}, and you want them to appear in the
+repository as @file{$CVSROOT/yoyodyne/@var{rdir}}, you can do this:
+
+@example
+$ cd @var{wdir}
+$ cvs import -m "Imported sources" yoyodyne/@var{rdir} yoyo start
+@end example
+
+Unless you supply a log message with the @samp{-m}
+flag, @sc{cvs} starts an editor and prompts for a
+message. The string @samp{yoyo} is a @dfn{vendor tag},
+and @samp{start} is a @dfn{release tag}. They may fill
+no purpose in this context, but since @sc{cvs} requires
+them they must be present. @xref{Tracking sources}, for
+more information about them.
+
+You can now verify that it worked, and remove your
+original source directory.
+@c FIXME: Need to say more about "verify that it
+@c worked". What should the user look for in the output
+@c from "diff -r"?
+
+@example
+$ cd ..
+$ cvs checkout yoyodyne/@var{rdir} # @r{Explanation below}
+$ diff -r @var{wdir} yoyodyne/@var{rdir}
+$ rm -r @var{wdir}
+@end example
+
+@noindent
+Erasing the original sources is a good idea, to make sure that you do
+not accidentally edit them in @var{wdir}, bypassing @sc{cvs}.
+Of course, it would be wise to make sure that you have
+a backup of the sources before you remove them.
+
+The @code{checkout} command can either take a module
+name as argument (as it has done in all previous
+examples) or a path name relative to @code{$CVSROOT},
+as it did in the example above.
+
+It is a good idea to check that the permissions
+@sc{cvs} sets on the directories inside @code{$CVSROOT}
+are reasonable, and that they belong to the proper
+groups. @xref{File permissions}.
+
+If some of the files you want to import are binary, you
+may want to use the wrappers features to specify which
+files are binary and which are not. @xref{Wrappers}.
+
+@c The node name is too long, but I am having trouble
+@c thinking of something more concise.
+@node From other version control systems
+@subsection Creating Files From Other Version Control Systems
+@cindex Importing files, from other version control systems
+
+If you have a project which you are maintaining with
+another version control system, such as @sc{rcs}, you
+may wish to put the files from that project into
+@sc{cvs}, and preserve the revision history of the
+files.
+
+@table @asis
+@cindex RCS, importing files from
+@item From RCS
+If you have been using @sc{rcs}, find the @sc{rcs}
+files---usually a file named @file{foo.c} will have its
+@sc{rcs} file in @file{RCS/foo.c,v} (but it could be
+other places; consult the @sc{rcs} documentation for
+details). Then create the appropriate directories in
+@sc{cvs} if they do not already exist. Then copy the
+files into the appropriate directories in the @sc{cvs}
+repository (the name in the repository must be the name
+of the source file with @samp{,v} added; the files go
+directly in the appropriate directory of the repository,
+not in an @file{RCS} subdirectory). This is one of the
+few times when it is a good idea to access the @sc{cvs}
+repository directly, rather than using @sc{cvs}
+commands. Then you are ready to check out a new
+working directory.
+@c Someday there probably should be a "cvs import -t
+@c rcs" or some such. It could even create magic
+@c branches. It could also do something about the case
+@c where the RCS file had a (non-magic) "0" branch.
+
+The @sc{rcs} file should not be locked when you move it
+into @sc{cvs}; if it is, @sc{cvs} will have trouble
+letting you operate on it.
+@c What is the easiest way to unlock your files if you
+@c have them locked? Especially if you have a lot of them?
+@c This is a CVS bug/misfeature; importing RCS files
+@c should ignore whether they are locked and leave them in
+@c an unlocked state. Yet another reason for a separate
+@c "import RCS file" command.
+
+@c How many is "many"? Or do they just import RCS files?
+@item From another version control system
+Many version control systems have the ability to export
+@sc{rcs} files in the standard format. If yours does,
+export the @sc{rcs} files and then follow the above
+instructions.
+
+Failing that, probably your best bet is to write a
+script that will check out the files one revision at a
+time using the command line interface to the other
+system, and then check the revisions into @sc{cvs}.
+The @file{sccs2rcs} script mentioned below may be a
+useful example to follow.
+
+@cindex SCCS, importing files from
+@item From SCCS
+There is a script in the @file{contrib} directory of
+the @sc{cvs} source distribution called @file{sccs2rcs}
+which converts @sc{sccs} files to @sc{rcs} files.
+Note: you must run it on a machine which has both
+@sc{sccs} and @sc{rcs} installed, and like everything
+else in contrib it is unsupported (your mileage may
+vary).
+
+@cindex PVCS, importing files from
+@item From PVCS
+There is a script in the @file{contrib} directory of
+the @sc{cvs} source distribution called @file{pvcs_to_rcs}
+which converts @sc{pvcs} archives to @sc{rcs} files.
+You must run it on a machine which has both
+@sc{pvcs} and @sc{rcs} installed, and like everything
+else in contrib it is unsupported (your mileage may
+vary). See the comments in the script for details.
+@end table
+@c CMZ and/or PATCHY were systems that were used in the
+@c high energy physics community (especially for
+@c CERNLIB). CERN has replaced them with CVS, but the
+@c CAR format seems to live on as a way to submit
+@c changes. There is a program car2cvs which converts
+@c but I'm not sure where one gets a copy.
+@c Not sure it is worth mentioning here, since it would
+@c appear to affect only one particular community.
+@c Best page for more information is:
+@c http://wwwcn1.cern.ch/asd/cvs/index.html
+@c See also:
+@c http://ecponion.cern.ch/ecpsa/cernlib.html
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node From scratch
+@subsection Creating a directory tree from scratch
+
+@c Also/instead should be documenting
+@c $ cvs co -l .
+@c $ mkdir tc
+@c $ cvs add tc
+@c $ cd tc
+@c $ mkdir man
+@c $ cvs add man
+@c etc.
+@c Using import to create the directories only is
+@c probably a somewhat confusing concept.
+For a new project, the easiest thing to do is probably
+to create an empty directory structure, like this:
+
+@example
+$ mkdir tc
+$ mkdir tc/man
+$ mkdir tc/testing
+@end example
+
+After that, you use the @code{import} command to create
+the corresponding (empty) directory structure inside
+the repository:
+
+@example
+$ cd tc
+$ cvs import -m "Created directory structure" yoyodyne/@var{dir} yoyo start
+@end example
+
+This will add yoyodyne/@var{dir} as a directory under
+@code{$CVSROOT}.
+
+Use @code{checkout} to get the new project. Then, use @code{add}
+to add files (and new directories) as needed.
+
+@example
+$ cd ..
+$ cvs co yoyodyne/@var{dir}
+@end example
+
+Check that the permissions @sc{cvs} sets on the
+directories inside @code{$CVSROOT} are reasonable.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Defining the module
+@section Defining the module
+@cindex Defining a module
+@cindex Editing the modules file
+@cindex Module, defining
+@cindex Modules file, changing
+
+The next step is to define the module in the
+@file{modules} file. This is not strictly necessary,
+but modules can be convenient in grouping together
+related files and directories.
+
+In simple cases these steps are sufficient to define a module.
+
+@enumerate
+@item
+Get a working copy of the modules file.
+
+@example
+$ cvs checkout CVSROOT/modules
+$ cd CVSROOT
+@end example
+
+@item
+Edit the file and insert a line that defines the module. @xref{Intro
+administrative files}, for an introduction. @xref{modules}, for a full
+description of the modules file. You can use the
+following line to define the module @samp{tc}:
+
+@example
+tc yoyodyne/tc
+@end example
+
+@item
+Commit your changes to the modules file.
+
+@example
+$ cvs commit -m "Added the tc module." modules
+@end example
+
+@item
+Release the modules module.
+
+@example
+$ cd ..
+$ cvs release -d CVSROOT
+@end example
+@end enumerate
+
+@c ---------------------------------------------------------------------
+@node Revisions
+@chapter Revisions
+
+For many uses of @sc{cvs}, one doesn't need to worry
+too much about revision numbers; @sc{cvs} assigns
+numbers such as @code{1.1}, @code{1.2}, and so on, and
+that is all one needs to know. However, some people
+prefer to have more knowledge and control concerning
+how @sc{cvs} assigns revision numbers.
+
+If one wants to keep track of a set of revisions
+involving more than one file, such as which revisions
+went into a particular release, one uses a @dfn{tag},
+which is a symbolic revision which can be assigned to a
+numeric revision in each file.
+
+@menu
+* Revision numbers:: The meaning of a revision number
+* Versions revisions releases:: Terminology used in this manual
+* Assigning revisions:: Assigning revisions
+* Tags:: Tags--Symbolic revisions
+* Tagging the working directory:: The cvs tag command
+* Tagging by date/tag:: The cvs rtag command
+* Modifying tags:: Adding, renaming, and deleting tags
+* Tagging add/remove:: Tags with adding and removing files
+* Sticky tags:: Certain tags are persistent
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Revision numbers
+@section Revision numbers
+@cindex Revision numbers
+@cindex Revision tree
+@cindex Linear development
+@cindex Number, revision-
+@cindex Decimal revision number
+@cindex Branch number
+@cindex Number, branch
+
+Each version of a file has a unique @dfn{revision
+number}. Revision numbers look like @samp{1.1},
+@samp{1.2}, @samp{1.3.2.2} or even @samp{1.3.2.2.4.5}.
+A revision number always has an even number of
+period-separated decimal integers. By default revision
+1.1 is the first revision of a file. Each successive
+revision is given a new number by increasing the
+rightmost number by one. The following figure displays
+a few revisions, with newer revisions to the right.
+
+@example
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+ +-----+ +-----+ +-----+ +-----+ +-----+
+@end example
+
+It is also possible to end up with numbers containing
+more than one period, for example @samp{1.3.2.2}. Such
+revisions represent revisions on branches
+(@pxref{Branching and merging}); such revision numbers
+are explained in detail in @ref{Branches and
+revisions}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Versions revisions releases
+@section Versions, revisions and releases
+@cindex Revisions, versions and releases
+@cindex Versions, revisions and releases
+@cindex Releases, revisions and versions
+
+A file can have several versions, as described above.
+Likewise, a software product can have several versions.
+A software product is often given a version number such
+as @samp{4.1.1}.
+
+Versions in the first sense are called @dfn{revisions}
+in this document, and versions in the second sense are
+called @dfn{releases}. To avoid confusion, the word
+@dfn{version} is almost never used in this document.
+
+@node Assigning revisions
+@section Assigning revisions
+
+@c We avoid the "major revision" terminology. It seems
+@c like jargon. Hopefully "first number" is clear enough.
+@c
+@c Well, in the context of software release numbers,
+@c "major" and "minor" release or version numbers are
+@c documented in at least the GNU Coding Standards, but I'm
+@c still not sure I find that a valid reason to apply the
+@c terminology to RCS revision numbers. "First", "Second",
+@c "subsequent", and so on is almost surely clearer,
+@c especially to a novice reader. -DRP
+By default, @sc{cvs} will assign numeric revisions by
+leaving the first number the same and incrementing the
+second number. For example, @code{1.1}, @code{1.2},
+@code{1.3}, etc.
+
+When adding a new file, the second number will always
+be one and the first number will equal the highest
+first number of any file in that directory. For
+example, the current directory contains files whose
+highest numbered revisions are @code{1.7}, @code{3.1},
+and @code{4.12}, then an added file will be given the
+numeric revision @code{4.1}.
+(When using client/server @sc{cvs},
+only files that are actually sent to the server are considered.)
+
+@c This is sort of redundant with something we said a
+@c while ago. Somewhere we need a better way of
+@c introducing how the first number can be anything
+@c except "1", perhaps. Also I don't think this
+@c presentation is clear on why we are discussing releases
+@c and first numbers of numeric revisions in the same
+@c breath.
+Normally there is no reason to care
+about the revision numbers---it is easier to treat them
+as internal numbers that @sc{cvs} maintains, and tags
+provide a better way to distinguish between things like
+release 1 versus release 2 of your product
+(@pxref{Tags}). However, if you want to set the
+numeric revisions, the @samp{-r} option to @code{cvs
+commit} can do that. The @samp{-r} option implies the
+@samp{-f} option, in the sense that it causes the
+files to be committed even if they are not modified.
+
+For example, to bring all your files up to
+revision 3.0 (including those that haven't changed),
+you might invoke:
+
+@example
+$ cvs commit -r 3.0
+@end example
+
+Note that the number you specify with @samp{-r} must be
+larger than any existing revision number. That is, if
+revision 3.0 exists, you cannot @samp{cvs commit
+-r 1.3}. If you want to maintain several releases in
+parallel, you need to use a branch (@pxref{Branching and merging}).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Tags
+@section Tags--Symbolic revisions
+@cindex Tags
+
+The revision numbers live a life of their own. They
+need not have anything at all to do with the release
+numbers of your software product. Depending
+on how you use @sc{cvs} the revision numbers might change several times
+between two releases. As an example, some of the
+source files that make up @sc{rcs} 5.6 have the following
+revision numbers:
+@cindex RCS revision numbers
+
+@example
+ci.c 5.21
+co.c 5.9
+ident.c 5.3
+rcs.c 5.12
+rcsbase.h 5.11
+rcsdiff.c 5.10
+rcsedit.c 5.11
+rcsfcmp.c 5.9
+rcsgen.c 5.10
+rcslex.c 5.11
+rcsmap.c 5.2
+rcsutil.c 5.10
+@end example
+
+@cindex tag (subcommand), introduction
+@cindex Tags, symbolic name
+@cindex Symbolic name (tag)
+@cindex Name, symbolic (tag)
+@cindex HEAD, as reserved tag name
+@cindex BASE, as reserved tag name
+You can use the @code{tag} command to give a symbolic name to a
+certain revision of a file. You can use the @samp{-v} flag to the
+@code{status} command to see all tags that a file has, and
+which revision numbers they represent. Tag names must
+start with an uppercase or lowercase letter and can
+contain uppercase and lowercase letters, digits,
+@samp{-}, and @samp{_}. The two tag names @code{BASE}
+and @code{HEAD} are reserved for use by @sc{cvs}. It
+is expected that future names which are special to
+@sc{cvs} will be specially named, for example by
+starting with @samp{.}, rather than being named analogously to
+@code{BASE} and @code{HEAD}, to avoid conflicts with
+actual tag names.
+@c Including a character such as % or = has also been
+@c suggested as the naming convention for future
+@c special tag names. Starting with . is nice because
+@c that is not a legal tag name as far as RCS is concerned.
+@c FIXME: CVS actually accepts quite a few characters
+@c in tag names, not just the ones documented above
+@c (see RCS_check_tag). RCS
+@c defines legitimate tag names by listing illegal
+@c characters rather than legal ones. CVS is said to lose its
+@c mind if you try to use "/" (try making such a tag sticky
+@c and using "cvs status" client/server--see remote
+@c protocol format for entries line for probable cause).
+@c TODO: The testsuite
+@c should test for whatever are documented above as
+@c officially-OK tag names, and CVS should at least reject
+@c characters that won't work, like "/".
+
+You'll want to choose some convention for naming tags,
+based on information such as the name of the program
+and the version number of the release. For example,
+one might take the name of the program, immediately
+followed by the version number with @samp{.} changed to
+@samp{-}, so that @sc{cvs} 1.9 would be tagged with the name
+@code{cvs1-9}. If you choose a consistent convention,
+then you won't constantly be guessing whether a tag is
+@code{cvs-1-9} or @code{cvs1_9} or what. You might
+even want to consider enforcing your convention in the
+@file{taginfo} file (@pxref{taginfo}).
+@c Might be nice to say more about using taginfo this
+@c way, like giving an example, or pointing out any particular
+@c issues which arise.
+
+@cindex Adding a tag
+@cindex Tags, example
+The following example shows how you can add a tag to a
+file. The commands must be issued inside your working
+directory. That is, you should issue the
+command in the directory where @file{backend.c}
+resides.
+
+@example
+$ cvs tag rel-0-4 backend.c
+T backend.c
+$ cvs status -v backend.c
+===================================================================
+File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-0-4 (revision: 1.4)
+
+@end example
+
+For a complete summary of the syntax of @code{cvs tag},
+including the various options, see @ref{Invoking CVS}.
+
+There is seldom reason to tag a file in isolation. A more common use is
+to tag all the files that constitute a module with the same tag at
+strategic points in the development life-cycle, such as when a release
+is made.
+
+@example
+$ cvs tag rel-1-0 .
+cvs tag: Tagging .
+T Makefile
+T backend.c
+T driver.c
+T frontend.c
+T parser.c
+@end example
+
+@noindent
+(When you give @sc{cvs} a directory as argument, it generally applies the
+operation to all the files in that directory, and (recursively), to any
+subdirectories that it may contain. @xref{Recursive behavior}.)
+
+@cindex Retrieving an old revision using tags
+@cindex Tags, retrieving old revisions
+The @code{checkout} command has a flag, @samp{-r}, that lets you check out
+a certain revision of a module. This flag makes it easy to
+retrieve the sources that make up release 1.0 of the module @samp{tc} at
+any time in the future:
+
+@example
+$ cvs checkout -r rel-1-0 tc
+@end example
+
+@noindent
+This is useful, for instance, if someone claims that there is a bug in
+that release, but you cannot find the bug in the current working copy.
+
+You can also check out a module as it was on any branch at any given date.
+@xref{checkout options}. When specifying @samp{-r} or @samp{-D} to
+any of these commands, you will need beware of sticky
+tags; see @ref{Sticky tags}.
+
+When you tag more than one file with the same tag you
+can think about the tag as "a curve drawn through a
+matrix of filename vs. revision number." Say we have 5
+files with the following revisions:
+
+@example
+@group
+ file1 file2 file3 file4 file5
+
+ 1.1 1.1 1.1 1.1 /--1.1* <-*- TAG
+ 1.2*- 1.2 1.2 -1.2*-
+ 1.3 \- 1.3*- 1.3 / 1.3
+ 1.4 \ 1.4 / 1.4
+ \-1.5*- 1.5
+ 1.6
+@end group
+@end example
+
+At some time in the past, the @code{*} versions were tagged.
+You can think of the tag as a handle attached to the curve
+drawn through the tagged revisions. When you pull on
+the handle, you get all the tagged revisions. Another
+way to look at it is that you "sight" through a set of
+revisions that is "flat" along the tagged revisions,
+like this:
+
+@example
+@group
+ file1 file2 file3 file4 file5
+
+ 1.1
+ 1.2
+ 1.1 1.3 _
+ 1.1 1.2 1.4 1.1 /
+ 1.2*----1.3*----1.5*----1.2*----1.1* (--- <--- Look here
+ 1.3 1.6 1.3 \_
+ 1.4 1.4
+ 1.5
+@end group
+@end example
+
+@node Tagging the working directory
+@section Specifying what to tag from the working directory
+
+@cindex tag (subcommand)
+The example in the previous section demonstrates one of
+the most common ways to choose which revisions to tag.
+Namely, running the @code{cvs tag} command without
+arguments causes @sc{cvs} to select the revisions which
+are checked out in the current working directory. For
+example, if the copy of @file{backend.c} in working
+directory was checked out from revision 1.4, then
+@sc{cvs} will tag revision 1.4. Note that the tag is
+applied immediately to revision 1.4 in the repository;
+tagging is not like modifying a file, or other
+operations in which one first modifies the working
+directory and then runs @code{cvs commit} to transfer
+that modification to the repository.
+
+One potentially surprising aspect of the fact that
+@code{cvs tag} operates on the repository is that you
+are tagging the checked-in revisions, which may differ
+from locally modified files in your working directory.
+If you want to avoid doing this by mistake, specify the
+@samp{-c} option to @code{cvs tag}. If there are any
+locally modified files, @sc{cvs} will abort with an
+error before it tags any files:
+
+@example
+$ cvs tag -c rel-0-4
+cvs tag: backend.c is locally modified
+cvs [tag aborted]: correct the above errors first!
+@end example
+
+@node Tagging by date/tag
+@section Specifying what to tag by date or revision
+@cindex rtag (subcommand)
+
+The @code{cvs rtag} command tags the repository as of a
+certain date or time (or can be used to tag the latest
+revision). @code{rtag} works directly on the
+repository contents (it requires no prior checkout and
+does not look for a working directory).
+
+The following options specify which date or revision to
+tag. See @ref{Common options}, for a complete
+description of them.
+
+@table @code
+@item -D @var{date}
+Tag the most recent revision no later than @var{date}.
+
+@item -f
+Only useful with the @samp{-D} or @samp{-r}
+flags. If no matching revision is found, use the most
+recent revision (instead of ignoring the file).
+
+@item -r @var{tag}[:@var{date}]
+Tag the revision already tagged with @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+@end table
+
+The @code{cvs tag} command also allows one to specify
+files by revision or date, using the same @samp{-r},
+@samp{-D}, and @samp{-f} options. However, this
+feature is probably not what you want. The reason is
+that @code{cvs tag} chooses which files to tag based on
+the files that exist in the working directory, rather
+than the files which existed as of the given tag/date.
+Therefore, you are generally better off using @code{cvs
+rtag}. The exceptions might be cases like:
+
+@example
+cvs tag -r 1.4 stable backend.c
+@end example
+
+@node Modifying tags
+@section Deleting, moving, and renaming tags
+
+@c Also see:
+@c "How do I move or rename a magic branch tag?"
+@c in the FAQ (I think the issues it talks about still
+@c apply, but this could use some sanity.sh work).
+
+Normally one does not modify tags. They exist in order
+to record the history of the repository and so deleting
+them or changing their meaning would, generally, not be
+what you want.
+
+However, there might be cases in which one uses a tag
+temporarily or accidentally puts one in the wrong
+place. Therefore, one might delete, move, or rename a
+tag.
+
+@noindent
+@strong{WARNING: the commands in this section are
+dangerous; they permanently discard historical
+information and it can be difficult or impossible to
+recover from errors. If you are a @sc{cvs}
+administrator, you may consider restricting these
+commands with the @file{taginfo} file (@pxref{taginfo}).}
+
+@cindex Deleting tags
+@cindex Deleting branch tags
+@cindex Removing tags
+@cindex Removing branch tags
+@cindex Tags, deleting
+@cindex Branch tags, deleting
+To delete a tag, specify the @samp{-d} option to either
+@code{cvs tag} or @code{cvs rtag}. For example:
+
+@example
+cvs rtag -d rel-0-4 tc
+@end example
+
+@noindent
+deletes the non-branch tag @code{rel-0-4} from the module @code{tc}.
+In the event that branch tags are encountered within the repository
+with the given name, a warning message will be issued and the branch
+tag will not be deleted. If you are absolutely certain you know what
+you are doing, the @code{-B} option may be specified to allow deletion
+of branch tags. In that case, any non-branch tags encountered will
+trigger warnings and will not be deleted.
+
+@noindent
+@strong{WARNING: Moving branch tags is very dangerous! If you think
+you need the @code{-B} option, think again and ask your @sc{cvs}
+administrator about it (if that isn't you). There is almost certainly
+another way to accomplish what you want to accomplish.}
+
+@cindex Moving tags
+@cindex Moving branch tags
+@cindex Tags, moving
+@cindex Branch tags, moving
+When we say @dfn{move} a tag, we mean to make the same
+name point to different revisions. For example, the
+@code{stable} tag may currently point to revision 1.4
+of @file{backend.c} and perhaps we want to make it
+point to revision 1.6. To move a non-branch tag, specify the
+@samp{-F} option to either @code{cvs tag} or @code{cvs
+rtag}. For example, the task just mentioned might be
+accomplished as:
+
+@example
+cvs tag -r 1.6 -F stable backend.c
+@end example
+
+@noindent
+If any branch tags are encountered in the repository
+with the given name, a warning is issued and the branch
+tag is not disturbed. If you are absolutely certain you
+wish to move the branch tag, the @code{-B} option may be specified.
+In that case, non-branch tags encountered with the given
+name are ignored with a warning message.
+
+@noindent
+@strong{WARNING: Moving branch tags is very dangerous! If you think you
+need the @code{-B} option, think again and ask your @sc{cvs}
+administrator about it (if that isn't you). There is almost certainly
+another way to accomplish what you want to accomplish.}
+
+@cindex Renaming tags
+@cindex Tags, renaming
+When we say @dfn{rename} a tag, we mean to make a
+different name point to the same revisions as the old
+tag. For example, one may have misspelled the tag name
+and want to correct it (hopefully before others are
+relying on the old spelling). To rename a tag, first
+create a new tag using the @samp{-r} option to
+@code{cvs rtag}, and then delete the old name. (Caution:
+this method will not work with branch tags.)
+This leaves the new tag on exactly the
+same files as the old tag. For example:
+
+@example
+cvs rtag -r old-name-0-4 rel-0-4 tc
+cvs rtag -d old-name-0-4 tc
+@end example
+
+@node Tagging add/remove
+@section Tagging and adding and removing files
+
+The subject of exactly how tagging interacts with
+adding and removing files is somewhat obscure; for the
+most part @sc{cvs} will keep track of whether files
+exist or not without too much fussing. By default,
+tags are applied to only files which have a revision
+corresponding to what is being tagged. Files which did
+not exist yet, or which were already removed, simply
+omit the tag, and @sc{cvs} knows to treat the absence
+of a tag as meaning that the file didn't exist as of
+that tag.
+
+However, this can lose a small amount of information.
+For example, suppose a file was added and then removed.
+Then, if the tag is missing for that file, there is no
+way to know whether the tag refers to the time before
+the file was added, or the time after it was removed.
+If you specify the @samp{-r} option to @code{cvs rtag},
+then @sc{cvs} tags the files which have been removed,
+and thereby avoids this problem. For example, one
+might specify @code{-r HEAD} to tag the head.
+
+On the subject of adding and removing files, the
+@code{cvs rtag} command has a @samp{-a} option which
+means to clear the tag from removed files that would
+not otherwise be tagged. For example, one might
+specify this option in conjunction with @samp{-F} when
+moving a tag. If one moved a tag without @samp{-a},
+then the tag in the removed files might still refer to
+the old revision, rather than reflecting the fact that
+the file had been removed. I don't think this is
+necessary if @samp{-r} is specified, as noted above.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Sticky tags
+@section Sticky tags
+@cindex Sticky tags
+@cindex Tags, sticky
+
+@c A somewhat related issue is per-directory sticky
+@c tags (see comment at CVS/Tag in node Working
+@c directory storage); we probably want to say
+@c something like "you can set a sticky tag for only
+@c some files, but you don't want to" or some such.
+
+Sometimes a working copy's revision has extra data
+associated with it, for example it might be on a branch
+(@pxref{Branching and merging}), or restricted to
+versions prior to a certain date by @samp{checkout -D}
+or @samp{update -D}. Because this data persists --
+that is, it applies to subsequent commands in the
+working copy -- we refer to it as @dfn{sticky}.
+
+Most of the time, stickiness is an obscure aspect of
+@sc{cvs} that you don't need to think about. However,
+even if you don't want to use the feature, you may need
+to know @emph{something} about sticky tags (for
+example, how to avoid them!).
+
+You can use the @code{status} command to see if any
+sticky tags or dates are set:
+
+@example
+$ cvs status driver.c
+===================================================================
+File: driver.c Status: Up-to-date
+
+ Version: 1.7.2.1 Sat Dec 5 19:35:03 1992
+ RCS Version: 1.7.2.1 /u/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+@end example
+
+@cindex Resetting sticky tags
+@cindex Sticky tags, resetting
+@cindex Deleting sticky tags
+The sticky tags will remain on your working files until
+you delete them with @samp{cvs update -A}. The
+@samp{-A} option merges local changes into the version of the
+file from the head of the trunk, removing any sticky tags,
+dates, or options. See @ref{update} for more on the operation
+of @code{cvs update}.
+
+@cindex Sticky date
+The most common use of sticky tags is to identify which
+branch one is working on, as described in
+@ref{Accessing branches}. However, non-branch
+sticky tags have uses as well. For example,
+suppose that you want to avoid updating your working
+directory, to isolate yourself from possibly
+destabilizing changes other people are making. You
+can, of course, just refrain from running @code{cvs
+update}. But if you want to avoid updating only a
+portion of a larger tree, then sticky tags can help.
+If you check out a certain revision (such as 1.4) it
+will become sticky. Subsequent @code{cvs update}
+commands will
+not retrieve the latest revision until you reset the
+tag with @code{cvs update -A}. Likewise, use of the
+@samp{-D} option to @code{update} or @code{checkout}
+sets a @dfn{sticky date}, which, similarly, causes that
+date to be used for future retrievals.
+
+People often want to retrieve an old version of
+a file without setting a sticky tag. This can
+be done with the @samp{-p} option to @code{checkout} or
+@code{update}, which sends the contents of the file to
+standard output. For example:
+@example
+$ cvs update -p -r 1.1 file1 >file1
+===================================================================
+Checking out file1
+RCS: /tmp/cvs-sanity/cvsroot/first-dir/Attic/file1,v
+VERS: 1.1
+***************
+$
+@end example
+
+However, this isn't the easiest way, if you are asking
+how to undo a previous checkin (in this example, put
+@file{file1} back to the way it was as of revision
+1.1). In that case you are better off using the
+@samp{-j} option to @code{update}; for further
+discussion see @ref{Merging two revisions}.
+
+@c ---------------------------------------------------------------------
+@node Branching and merging
+@chapter Branching and merging
+@cindex Branching
+@cindex Merging
+@cindex Copying changes
+@cindex Main trunk and branches
+@cindex Revision tree, making branches
+@cindex Branches, copying changes between
+@cindex Changes, copying between branches
+@cindex Modifications, copying between branches
+
+@sc{cvs} allows you to isolate changes onto a separate
+line of development, known as a @dfn{branch}. When you
+change files on a branch, those changes do not appear
+on the main trunk or other branches.
+
+Later you can move changes from one branch to another
+branch (or the main trunk) by @dfn{merging}. Merging
+involves first running @code{cvs update -j}, to merge
+the changes into the working directory.
+You can then commit that revision, and thus effectively
+copy the changes onto another branch.
+
+@menu
+* Branches motivation:: What branches are good for
+* Creating a branch:: Creating a branch
+* Accessing branches:: Checking out and updating branches
+* Branches and revisions:: Branches are reflected in revision numbers
+* Magic branch numbers:: Magic branch numbers
+* Merging a branch:: Merging an entire branch
+* Merging more than once:: Merging from a branch several times
+* Merging two revisions:: Merging differences between two revisions
+* Merging adds and removals:: What if files are added or removed?
+* Merging and keywords:: Avoiding conflicts due to keyword substitution
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Branches motivation
+@section What branches are good for
+@cindex Branches motivation
+@cindex What branches are good for
+@cindex Motivation for branches
+
+@c FIXME: this node mentions one way to use branches,
+@c but it is by no means the only way. For example,
+@c the technique of committing a new feature on a branch,
+@c until it is ready for the main trunk. The whole
+@c thing is generally speaking more akin to the
+@c "Revision management" node although it isn't clear to
+@c me whether policy matters should be centralized or
+@c distributed throughout the relevant sections.
+Suppose that release 1.0 of tc has been made. You are continuing to
+develop tc, planning to create release 1.1 in a couple of months. After a
+while your customers start to complain about a fatal bug. You check
+out release 1.0 (@pxref{Tags}) and find the bug
+(which turns out to have a trivial fix). However, the current revision
+of the sources are in a state of flux and are not expected to be stable
+for at least another month. There is no way to make a
+bug fix release based on the newest sources.
+
+The thing to do in a situation like this is to create a @dfn{branch} on
+the revision trees for all the files that make up
+release 1.0 of tc. You can then make
+modifications to the branch without disturbing the main trunk. When the
+modifications are finished you can elect to either incorporate them on
+the main trunk, or leave them on the branch.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Creating a branch
+@section Creating a branch
+@cindex Creating a branch
+@cindex Branch, creating a
+@cindex tag (subcommand), creating a branch using
+@cindex rtag (subcommand), creating a branch using
+
+You can create a branch with @code{tag -b}; for
+example, assuming you're in a working copy:
+
+@example
+$ cvs tag -b rel-1-0-patches
+@end example
+
+@c FIXME: we should be more explicit about the value of
+@c having a tag on the branchpoint. For example
+@c "cvs tag rel-1-0-patches-branchpoint" before
+@c the "cvs tag -b". This points out that
+@c rel-1-0-patches is a pretty awkward name for
+@c this example (more so than for the rtag example
+@c below).
+
+This splits off a branch based on the current revisions
+in the working copy, assigning that branch the name
+@samp{rel-1-0-patches}.
+
+It is important to understand that branches get created
+in the repository, not in the working copy. Creating a
+branch based on current revisions, as the above example
+does, will @emph{not} automatically switch the working
+copy to be on the new branch. For information on how
+to do that, see @ref{Accessing branches}.
+
+You can also create a branch without reference to any
+working copy, by using @code{rtag}:
+
+@example
+$ cvs rtag -b -r rel-1-0 rel-1-0-patches tc
+@end example
+
+@samp{-r rel-1-0} says that this branch should be
+rooted at the revision that
+corresponds to the tag @samp{rel-1-0}. It need not
+be the most recent revision -- it's often useful to
+split a branch off an old revision (for example, when
+fixing a bug in a past release otherwise known to be
+stable).
+
+As with @samp{tag}, the @samp{-b} flag tells
+@code{rtag} to create a branch (rather than just a
+symbolic revision name). Note that the numeric
+revision number that matches @samp{rel-1-0} will
+probably be different from file to file.
+
+So, the full effect of the command is to create a new
+branch -- named @samp{rel-1-0-patches} -- in module
+@samp{tc}, rooted in the revision tree at the point tagged
+by @samp{rel-1-0}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Accessing branches
+@section Accessing branches
+@cindex Check out a branch
+@cindex Retrieve a branch
+@cindex Access a branch
+@cindex Identifying a branch
+@cindex Branch, check out
+@cindex Branch, retrieving
+@cindex Branch, accessing
+@cindex Branch, identifying
+
+You can retrieve a branch in one of two ways: by
+checking it out fresh from the repository, or by
+switching an existing working copy over to the branch.
+
+To check out a branch from the repository, invoke
+@samp{checkout} with the @samp{-r} flag, followed by
+the tag name of the branch (@pxref{Creating a branch}):
+
+@example
+$ cvs checkout -r rel-1-0-patches tc
+@end example
+
+Or, if you already have a working copy, you can switch
+it to a given branch with @samp{update -r}:
+
+@example
+$ cvs update -r rel-1-0-patches tc
+@end example
+
+@noindent
+or equivalently:
+
+@example
+$ cd tc
+$ cvs update -r rel-1-0-patches
+@end example
+
+It does not matter if the working copy was originally
+on the main trunk or on some other branch -- the above
+command will switch it to the named branch. And
+similarly to a regular @samp{update} command,
+@samp{update -r} merges any changes you have made,
+notifying you of conflicts where they occur.
+
+Once you have a working copy tied to a particular
+branch, it remains there until you tell it otherwise.
+This means that changes checked in from the working
+copy will add new revisions on that branch, while
+leaving the main trunk and other branches unaffected.
+
+@cindex Branches, sticky
+To find out what branch a working copy is on, you can
+use the @samp{status} command. In its output, look for
+the field named @samp{Sticky tag} (@pxref{Sticky tags})
+-- that's @sc{cvs}'s way of telling you the branch, if
+any, of the current working files:
+
+@example
+$ cvs status -v driver.c backend.c
+===================================================================
+File: driver.c Status: Up-to-date
+
+ Version: 1.7 Sat Dec 5 18:25:54 1992
+ RCS Version: 1.7 /u/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-1-0-patches (branch: 1.7.2)
+ rel-1-0 (revision: 1.7)
+
+===================================================================
+File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.4.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-1-0-patches (branch: 1.4.2)
+ rel-1-0 (revision: 1.4)
+ rel-0-4 (revision: 1.4)
+
+@end example
+
+Don't be confused by the fact that the branch numbers
+for each file are different (@samp{1.7.2} and
+@samp{1.4.2} respectively). The branch tag is the
+same, @samp{rel-1-0-patches}, and the files are
+indeed on the same branch. The numbers simply reflect
+the point in each file's revision history at which the
+branch was made. In the above example, one can deduce
+that @samp{driver.c} had been through more changes than
+@samp{backend.c} before this branch was created.
+
+See @ref{Branches and revisions} for details about how
+branch numbers are constructed.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Branches and revisions
+@section Branches and revisions
+@cindex Branch number
+@cindex Number, branch
+@cindex Revision numbers (branches)
+
+Ordinarily, a file's revision history is a linear
+series of increments (@pxref{Revision numbers}):
+
+@example
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+ +-----+ +-----+ +-----+ +-----+ +-----+
+@end example
+
+However, @sc{cvs} is not limited to linear development. The
+@dfn{revision tree} can be split into @dfn{branches},
+where each branch is a self-maintained line of
+development. Changes made on one branch can easily be
+moved back to the main trunk.
+
+Each branch has a @dfn{branch number}, consisting of an
+odd number of period-separated decimal integers. The
+branch number is created by appending an integer to the
+revision number where the corresponding branch forked
+off. Having branch numbers allows more than one branch
+to be forked off from a certain revision.
+
+@need 3500
+All revisions on a branch have revision numbers formed
+by appending an ordinal number to the branch number.
+The following figure illustrates branching with an
+example.
+
+@example
+@c This example used to have a 1.2.2.4 revision, which
+@c might help clarify that development can continue on
+@c 1.2.2. Might be worth reinstating if it can be done
+@c without overfull hboxes.
+@group
+ +-------------+
+ Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 !
+ / +-------------+
+ /
+ /
+ +---------+ +---------+ +---------+
+Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
+ / +---------+ +---------+ +---------+
+ /
+ /
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+ +---------+
+Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 !
+ +---------+ +---------+ +---------+
+
+@end group
+@end example
+
+@c -- However, at least for me the figure is not enough. I suggest more
+@c -- text to accompany it. "A picture is worth a thousand words", so you
+@c -- have to make sure the reader notices the couple of hundred words
+@c -- *you* had in mind more than the others!
+
+@c -- Why an even number of segments? This section implies that this is
+@c -- how the main trunk is distinguished from branch roots, but you never
+@c -- explicitly say that this is the purpose of the [by itself rather
+@c -- surprising] restriction to an even number of segments.
+
+The exact details of how the branch number is
+constructed is not something you normally need to be
+concerned about, but here is how it works: When
+@sc{cvs} creates a branch number it picks the first
+unused even integer, starting with 2. So when you want
+to create a branch from revision 6.4 it will be
+numbered 6.4.2. All branch numbers ending in a zero
+(such as 6.4.0) are used internally by @sc{cvs}
+(@pxref{Magic branch numbers}). The branch 1.1.1 has a
+special meaning. @xref{Tracking sources}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Magic branch numbers
+@section Magic branch numbers
+
+@c Want xref to here from "log"?
+
+This section describes a @sc{cvs} feature called
+@dfn{magic branches}. For most purposes, you need not
+worry about magic branches; @sc{cvs} handles them for
+you. However, they are visible to you in certain
+circumstances, so it may be useful to have some idea of
+how it works.
+
+Externally, branch numbers consist of an odd number of
+dot-separated decimal integers. @xref{Revision
+numbers}. That is not the whole truth, however. For
+efficiency reasons @sc{cvs} sometimes inserts an extra 0
+in the second rightmost position (1.2.4 becomes
+1.2.0.4, 8.9.10.11.12 becomes 8.9.10.11.0.12 and so
+on).
+
+@sc{cvs} does a pretty good job at hiding these so
+called magic branches, but in a few places the hiding
+is incomplete:
+
+@itemize @bullet
+@ignore
+@c This is in ignore as I'm taking their word for it,
+@c that this was fixed
+@c a long time ago. But before deleting this
+@c entirely, I'd rather verify it (and add a test
+@c case to the testsuite).
+@item
+The magic branch can appear in the output from
+@code{cvs status} in vanilla @sc{cvs} 1.3. This is
+fixed in @sc{cvs} 1.3-s2.
+
+@end ignore
+@item
+The magic branch number appears in the output from
+@code{cvs log}.
+@c What output should appear instead?
+
+@item
+You cannot specify a symbolic branch name to @code{cvs
+admin}.
+
+@end itemize
+
+@c Can CVS do this automatically the first time
+@c you check something in to that branch? Should
+@c it?
+You can use the @code{admin} command to reassign a
+symbolic name to a branch the way @sc{rcs} expects it
+to be. If @code{R4patches} is assigned to the branch
+1.4.2 (magic branch number 1.4.0.2) in file
+@file{numbers.c} you can do this:
+
+@example
+$ cvs admin -NR4patches:1.4.2 numbers.c
+@end example
+
+It only works if at least one revision is already
+committed on the branch. Be very careful so that you
+do not assign the tag to the wrong number. (There is
+no way to see how the tag was assigned yesterday).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Merging a branch
+@section Merging an entire branch
+@cindex Merging a branch
+@cindex -j (merging branches)
+
+You can merge changes made on a branch into your working copy by giving
+the @samp{-j @var{branchname}} flag to the @code{update} subcommand. With one
+@samp{-j @var{branchname}} option it merges the changes made between the
+greatest common ancestor (GCA) of the branch and the destination revision (in
+the simple case below the GCA is the point where the branch forked) and the
+newest revision on that branch into your working copy.
+
+@cindex Join
+The @samp{-j} stands for ``join''.
+
+@cindex Branch merge example
+@cindex Example, branch merge
+@cindex Merge, branch example
+Consider this revision tree:
+
+@example
++-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+@end example
+
+@noindent
+The branch 1.2.2 has been given the tag (symbolic name) @samp{R1fix}. The
+following example assumes that the module @samp{mod} contains only one
+file, @file{m.c}.
+
+@example
+$ cvs checkout mod # @r{Retrieve the latest revision, 1.4}
+
+$ cvs update -j R1fix m.c # @r{Merge all changes made on the branch,}
+ # @r{i.e. the changes between revision 1.2}
+ # @r{and 1.2.2.2, into your working copy}
+ # @r{of the file.}
+
+$ cvs commit -m "Included R1fix" # @r{Create revision 1.5.}
+@end example
+
+A conflict can result from a merge operation. If that
+happens, you should resolve it before committing the
+new revision. @xref{Conflicts example}.
+
+If your source files contain keywords (@pxref{Keyword substitution}),
+you might be getting more conflicts than strictly necessary. See
+@ref{Merging and keywords}, for information on how to avoid this.
+
+The @code{checkout} command also supports the @samp{-j @var{branchname}} flag. The
+same effect as above could be achieved with this:
+
+@example
+$ cvs checkout -j R1fix mod
+$ cvs commit -m "Included R1fix"
+@end example
+
+It should be noted that @code{update -j @var{tagname}} will also work but may
+not produce the desired result. @xref{Merging adds and removals}, for more.
+
+@node Merging more than once
+@section Merging from a branch several times
+
+Continuing our example, the revision tree now looks
+like this:
+
+@example
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+@end example
+
+@noindent
+where the starred line represents the merge from the
+@samp{R1fix} branch to the main trunk, as just
+discussed.
+
+Now suppose that development continues on the
+@samp{R1fix} branch:
+
+@example
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
+ +---------+ +---------+ +---------+
+@end example
+
+@noindent
+and then you want to merge those new changes onto the
+main trunk. If you just use the @code{cvs update -j
+R1fix m.c} command again, @sc{cvs} will attempt to
+merge again the changes which you have already merged,
+which can have undesirable side effects.
+
+So instead you need to specify that you only want to
+merge the changes on the branch which have not yet been
+merged into the trunk. To do that you specify two
+@samp{-j} options, and @sc{cvs} merges the changes from
+the first revision to the second revision. For
+example, in this case the simplest way would be
+
+@example
+cvs update -j 1.2.2.2 -j R1fix m.c # @r{Merge changes from 1.2.2.2 to the}
+ # @r{head of the R1fix branch}
+@end example
+
+The problem with this is that you need to specify the
+1.2.2.2 revision manually. A slightly better approach
+might be to use the date the last merge was done:
+
+@example
+cvs update -j R1fix:yesterday -j R1fix m.c
+@end example
+
+Better yet, tag the R1fix branch after every merge into
+the trunk, and then use that tag for subsequent merges:
+
+@example
+cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Merging two revisions
+@section Merging differences between any two revisions
+@cindex Merging two revisions
+@cindex Revisions, merging differences between
+@cindex Differences, merging
+
+With two @samp{-j @var{revision}} flags, the @code{update}
+(and @code{checkout}) command can merge the differences
+between any two revisions into your working file.
+
+@cindex Undoing a change
+@cindex Removing a change
+@example
+$ cvs update -j 1.5 -j 1.3 backend.c
+@end example
+
+@noindent
+will undo all changes made between revision
+1.3 and 1.5. Note the order of the revisions!
+
+If you try to use this option when operating on
+multiple files, remember that the numeric revisions will
+probably be very different between the various files.
+You almost always use symbolic
+tags rather than revision numbers when operating on
+multiple files.
+
+@cindex Restoring old version of removed file
+@cindex Resurrecting old version of dead file
+Specifying two @samp{-j} options can also undo file
+removals or additions. For example, suppose you have
+a file
+named @file{file1} which existed as revision 1.1, and
+you then removed it (thus adding a dead revision 1.2).
+Now suppose you want to add it again, with the same
+contents it had previously. Here is how to do it:
+
+@example
+$ cvs update -j 1.2 -j 1.1 file1
+U file1
+$ cvs commit -m test
+Checking in file1;
+/tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1
+new revision: 1.3; previous revision: 1.2
+done
+$
+@end example
+
+@node Merging adds and removals
+@section Merging can add or remove files
+
+If the changes which you are merging involve removing
+or adding some files, @code{update -j} will reflect
+such additions or removals.
+
+@c FIXME: This example needs a lot more explanation.
+@c We also need other examples for some of the other
+@c cases (not all--there are too many--as long as we present a
+@c coherent general principle).
+For example:
+@example
+cvs update -A
+touch a b c
+cvs add a b c ; cvs ci -m "added" a b c
+cvs tag -b branchtag
+cvs update -r branchtag
+touch d ; cvs add d
+rm a ; cvs rm a
+cvs ci -m "added d, removed a"
+cvs update -A
+cvs update -jbranchtag
+@end example
+
+After these commands are executed and a @samp{cvs commit} is done,
+file @file{a} will be removed and file @file{d} added in the main branch.
+@c (which was determined by trying it)
+
+Note that using a single static tag (@samp{-j @var{tagname}})
+rather than a dynamic tag (@samp{-j @var{branchname}}) to merge
+changes from a branch will usually not remove files which were removed on the
+branch since @sc{cvs} does not automatically add static tags to dead revisions.
+The exception to this rule occurs when
+a static tag has been attached to a dead revision manually. Use the branch tag
+to merge all changes from the branch or use two static tags as merge endpoints
+to be sure that all intended changes are propagated in the merge.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Merging and keywords
+@section Merging and keywords
+@cindex Merging, and keyword substitution
+@cindex Keyword substitution, and merging
+@cindex -j (merging branches), and keyword substitution
+@cindex -kk, to avoid conflicts during a merge
+
+If you merge files containing keywords (@pxref{Keyword
+substitution}), you will normally get numerous
+conflicts during the merge, because the keywords are
+expanded differently in the revisions which you are
+merging.
+
+Therefore, you will often want to specify the
+@samp{-kk} (@pxref{Substitution modes}) switch to the
+merge command line. By substituting just the name of
+the keyword, not the expanded value of that keyword,
+this option ensures that the revisions which you are
+merging will be the same as each other, and avoid
+spurious conflicts.
+
+For example, suppose you have a file like this:
+
+@example
+ +---------+
+ _! 1.1.2.1 ! <- br1
+ / +---------+
+ /
+ /
++-----+ +-----+
+! 1.1 !----! 1.2 !
++-----+ +-----+
+@end example
+
+@noindent
+and your working directory is currently on the trunk
+(revision 1.2). Then you might get the following
+results from a merge:
+
+@example
+$ cat file1
+key $@splitrcskeyword{Revision}: 1.2 $
+. . .
+$ cvs update -j br1
+U file1
+RCS file: /cvsroot/first-dir/file1,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+Merging differences between 1.1 and 1.1.2.1 into file1
+rcsmerge: warning: conflicts during merge
+$ cat file1
+@asis{}<<<<<<< file1
+key $@splitrcskeyword{Revision}: 1.2 $
+@asis{}=======
+key $@splitrcskeyword{Revision}: 1.1.2.1 $
+@asis{}>>>>>>> 1.1.2.1
+. . .
+@end example
+
+What happened was that the merge tried to merge the
+differences between 1.1 and 1.1.2.1 into your working
+directory. So, since the keyword changed from
+@code{Revision: 1.1} to @code{Revision: 1.1.2.1},
+@sc{cvs} tried to merge that change into your working
+directory, which conflicted with the fact that your
+working directory had contained @code{Revision: 1.2}.
+
+Here is what happens if you had used @samp{-kk}:
+
+@example
+$ cat file1
+key $@splitrcskeyword{Revision}: 1.2 $
+. . .
+$ cvs update -kk -j br1
+U file1
+RCS file: /cvsroot/first-dir/file1,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+Merging differences between 1.1 and 1.1.2.1 into file1
+$ cat file1
+key $@splitrcskeyword{Revision}$
+. . .
+@end example
+
+What is going on here is that revision 1.1 and 1.1.2.1
+both expand as plain @code{Revision}, and therefore
+merging the changes between them into the working
+directory need not change anything. Therefore, there
+is no conflict.
+
+@strong{WARNING: In versions of @sc{cvs} prior to 1.12.2, there was a
+major problem with using @samp{-kk} on merges. Namely, @samp{-kk}
+overrode any default keyword expansion mode set in the archive file in
+the repository. This could, unfortunately for some users, cause data
+corruption in binary files (with a default keyword expansion mode set
+to @samp{-kb}). Therefore, when a repository contained binary files,
+conflicts had to be dealt with manually rather than using @samp{-kk} in
+a merge command.}
+
+In @sc{cvs} version 1.12.2 and later, the keyword expansion mode
+provided on the command line to any @sc{cvs} command no longer
+overrides the @samp{-kb} keyword expansion mode setting for binary
+files, though it will still override other default keyword expansion
+modes. You can now safely merge using @samp{-kk} to avoid spurious conflicts
+on lines containing RCS keywords, even when your repository contains
+binary files.
+
+@c ---------------------------------------------------------------------
+@node Recursive behavior
+@chapter Recursive behavior
+@cindex Recursive (directory descending)
+@cindex Directory, descending
+@cindex Descending directories
+@cindex Subdirectories
+
+Almost all of the subcommands of @sc{cvs} work
+recursively when you specify a directory as an
+argument. For instance, consider this directory
+structure:
+
+@example
+ @code{$HOME}
+ |
+ +--@t{tc}
+ | |
+ +--@t{CVS}
+ | (internal @sc{cvs} files)
+ +--@t{Makefile}
+ +--@t{backend.c}
+ +--@t{driver.c}
+ +--@t{frontend.c}
+ +--@t{parser.c}
+ +--@t{man}
+ | |
+ | +--@t{CVS}
+ | | (internal @sc{cvs} files)
+ | +--@t{tc.1}
+ |
+ +--@t{testing}
+ |
+ +--@t{CVS}
+ | (internal @sc{cvs} files)
+ +--@t{testpgm.t}
+ +--@t{test2.t}
+@end example
+
+@noindent
+If @file{tc} is the current working directory, the
+following is true:
+
+@itemize @bullet
+@item
+@samp{cvs update testing} is equivalent to
+
+@example
+cvs update testing/testpgm.t testing/test2.t
+@end example
+
+@item
+@samp{cvs update testing man} updates all files in the
+subdirectories
+
+@item
+@samp{cvs update .} or just @samp{cvs update} updates
+all files in the @code{tc} directory
+@end itemize
+
+If no arguments are given to @code{update} it will
+update all files in the current working directory and
+all its subdirectories. In other words, @file{.} is a
+default argument to @code{update}. This is also true
+for most of the @sc{cvs} subcommands, not only the
+@code{update} command.
+
+The recursive behavior of the @sc{cvs} subcommands can be
+turned off with the @samp{-l} option.
+Conversely, the @samp{-R} option can be used to force recursion if
+@samp{-l} is specified in @file{~/.cvsrc} (@pxref{~/.cvsrc}).
+
+@example
+$ cvs update -l # @r{Don't update files in subdirectories}
+@end example
+
+@c ---------------------------------------------------------------------
+@node Adding and removing
+@chapter Adding, removing, and renaming files and directories
+
+In the course of a project, one will often add new
+files. Likewise with removing or renaming, or with
+directories. The general concept to keep in mind in
+all these cases is that instead of making an
+irreversible change you want @sc{cvs} to record the
+fact that a change has taken place, just as with
+modifying an existing file. The exact mechanisms to do
+this in @sc{cvs} vary depending on the situation.
+
+@menu
+* Adding files:: Adding files
+* Removing files:: Removing files
+* Removing directories:: Removing directories
+* Moving files:: Moving and renaming files
+* Moving directories:: Moving and renaming directories
+@end menu
+
+@node Adding files
+@section Adding files to a directory
+@cindex Adding files
+
+To add a new file to a directory, follow these steps.
+
+@itemize @bullet
+@item
+You must have a working copy of the directory.
+@xref{Getting the source}.
+
+@item
+Create the new file inside your working copy of the directory.
+
+@item
+Use @samp{cvs add @var{filename}} to tell @sc{cvs} that you
+want to version control the file. If the file contains
+binary data, specify @samp{-kb} (@pxref{Binary files}).
+
+@item
+Use @samp{cvs commit @var{filename}} to actually check
+in the file into the repository. Other developers
+cannot see the file until you perform this step.
+@end itemize
+
+You can also use the @code{add} command to add a new
+directory.
+@c FIXCVS and/or FIXME: Adding a directory doesn't
+@c require the commit step. This probably can be
+@c considered a CVS bug, but it is possible we should
+@c warn people since this behavior probably won't be
+@c changing right away.
+
+Unlike most other commands, the @code{add} command is
+not recursive. You have to expcicitly name files and
+directories that you wish to add to the repository.
+However, each directory will need to be added
+separately before you will be able to add new files
+to those directories.
+
+@example
+$ mkdir -p foo/bar
+$ cp ~/myfile foo/bar/myfile
+$ cvs add foo foo/bar
+$ cvs add foo/bar/myfile
+@end example
+
+@cindex add (subcommand)
+@deffn Command {cvs add} [@code{-k} kflag] [@code{-m} message] files @dots{}
+
+Schedule @var{files} to be added to the repository.
+The files or directories specified with @code{add} must
+already exist in the current directory. To add a whole
+new directory hierarchy to the source repository (for
+example, files received from a third-party vendor), use
+the @code{import} command instead. @xref{import}.
+
+The added files are not placed in the source repository
+until you use @code{commit} to make the change
+permanent. Doing an @code{add} on a file that was
+removed with the @code{remove} command will undo the
+effect of the @code{remove}, unless a @code{commit}
+command intervened. @xref{Removing files}, for an
+example.
+
+The @samp{-k} option specifies the default way that
+this file will be checked out; for more information see
+@ref{Substitution modes}.
+
+@c As noted in BUGS, -m is broken client/server (Nov
+@c 96). Also see testsuite log2-* tests.
+The @samp{-m} option specifies a description for the
+file. This description appears in the history log (if
+it is enabled, @pxref{history file}). It will also be
+saved in the version history inside the repository when
+the file is committed. The @code{log} command displays
+this description. The description can be changed using
+@samp{admin -t}. @xref{admin}. If you omit the
+@samp{-m @var{description}} flag, an empty string will
+be used. You will not be prompted for a description.
+@end deffn
+
+For example, the following commands add the file
+@file{backend.c} to the repository:
+
+@c This example used to specify
+@c -m "Optimizer and code generation passes."
+@c to the cvs add command, but that doesn't work
+@c client/server (see log2 in sanity.sh). Should fix CVS,
+@c but also seems strange to document things which
+@c don't work...
+@example
+$ cvs add backend.c
+$ cvs commit -m "Early version. Not yet compilable." backend.c
+@end example
+
+When you add a file it is added only on the branch
+which you are working on (@pxref{Branching and merging}). You can
+later merge the additions to another branch if you want
+(@pxref{Merging adds and removals}).
+@c Should we mention that earlier versions of CVS
+@c lacked this feature (1.3) or implemented it in a buggy
+@c way (well, 1.8 had many bugs in cvs update -j)?
+@c Should we mention the bug/limitation regarding a
+@c file being a regular file on one branch and a directory
+@c on another?
+@c FIXME: This needs an example, or several, here or
+@c elsewhere, for it to make much sense.
+@c Somewhere we need to discuss the aspects of death
+@c support which don't involve branching, I guess.
+@c Like the ability to re-create a release from a tag.
+
+@c ---------------------------------------------------------------------
+@node Removing files
+@section Removing files
+@cindex Removing files
+@cindex Deleting files
+
+@c FIXME: this node wants to be split into several
+@c smaller nodes. Could make these children of
+@c "Adding and removing", probably (death support could
+@c be its own section, for example, as could the
+@c various bits about undoing mistakes in adding and
+@c removing).
+Directories change. New files are added, and old files
+disappear. Still, you want to be able to retrieve an
+exact copy of old releases.
+
+Here is what you can do to remove a file,
+but remain able to retrieve old revisions:
+
+@itemize @bullet
+@c FIXME: should probably be saying something about
+@c having a working directory in the first place.
+@item
+Make sure that you have not made any uncommitted
+modifications to the file. @xref{Viewing differences},
+for one way to do that. You can also use the
+@code{status} or @code{update} command. If you remove
+the file without committing your changes, you will of
+course not be able to retrieve the file as it was
+immediately before you deleted it.
+
+@item
+Remove the file from your working copy of the directory.
+You can for instance use @code{rm}.
+
+@item
+Use @samp{cvs remove @var{filename}} to tell @sc{cvs} that
+you really want to delete the file.
+
+@item
+Use @samp{cvs commit @var{filename}} to actually
+perform the removal of the file from the repository.
+@end itemize
+
+@c FIXME: Somehow this should be linked in with a more
+@c general discussion of death support. I don't know
+@c whether we want to use the term "death support" or
+@c not (we can perhaps get by without it), but we do
+@c need to discuss the "dead" state in "cvs log" and
+@c related subjects. The current discussion is
+@c scattered around, and not xref'd to each other.
+@c FIXME: I think this paragraph wants to be moved
+@c later down, at least after the first example.
+When you commit the removal of the file, @sc{cvs}
+records the fact that the file no longer exists. It is
+possible for a file to exist on only some branches and
+not on others, or to re-add another file with the same
+name later. @sc{cvs} will correctly create or not create
+the file, based on the @samp{-r} and @samp{-D} options
+specified to @code{checkout} or @code{update}.
+
+@c FIXME: This style seems to clash with how we
+@c document things in general.
+@cindex Remove (subcommand)
+@deffn Command {cvs remove} [options] files @dots{}
+
+Schedule file(s) to be removed from the repository
+(files which have not already been removed from the
+working directory are not processed). This command
+does not actually remove the file from the repository
+until you commit the removal. For a full list of
+options, see @ref{Invoking CVS}.
+@end deffn
+
+Here is an example of removing several files:
+
+@example
+$ cd test
+$ rm *.c
+$ cvs remove
+cvs remove: Removing .
+cvs remove: scheduling a.c for removal
+cvs remove: scheduling b.c for removal
+cvs remove: use 'cvs commit' to remove these files permanently
+$ cvs ci -m "Removed unneeded files"
+cvs commit: Examining .
+cvs commit: Committing .
+@end example
+
+As a convenience you can remove the file and @code{cvs
+remove} it in one step, by specifying the @samp{-f}
+option. For example, the above example could also be
+done like this:
+
+@example
+$ cd test
+$ cvs remove -f *.c
+cvs remove: scheduling a.c for removal
+cvs remove: scheduling b.c for removal
+cvs remove: use 'cvs commit' to remove these files permanently
+$ cvs ci -m "Removed unneeded files"
+cvs commit: Examining .
+cvs commit: Committing .
+@end example
+
+If you execute @code{remove} for a file, and then
+change your mind before you commit, you can undo the
+@code{remove} with an @code{add} command.
+@ignore
+@c is this worth saying or not? Somehow it seems
+@c confusing to me.
+Of course,
+since you have removed your copy of file in the working
+directory, @sc{cvs} does not necessarily bring back the
+contents of the file from right before you executed
+@code{remove}; instead it gets the file from the
+repository again.
+@end ignore
+
+@c FIXME: what if you change your mind after you commit
+@c it? (answer is also "cvs add" but we don't say that...).
+@c We need some index entries for thinks like "undoing
+@c removal" too.
+
+@example
+$ ls
+CVS ja.h oj.c
+$ rm oj.c
+$ cvs remove oj.c
+cvs remove: scheduling oj.c for removal
+cvs remove: use 'cvs commit' to remove this file permanently
+$ cvs add oj.c
+U oj.c
+cvs add: oj.c, version 1.1.1.1, resurrected
+@end example
+
+If you realize your mistake before you run the
+@code{remove} command you can use @code{update} to
+resurrect the file:
+
+@example
+$ rm oj.c
+$ cvs update oj.c
+cvs update: warning: oj.c was lost
+U oj.c
+@end example
+
+When you remove a file it is removed only on the branch
+which you are working on (@pxref{Branching and merging}). You can
+later merge the removals to another branch if you want
+(@pxref{Merging adds and removals}).
+
+@node Removing directories
+@section Removing directories
+@cindex Removing directories
+@cindex Directories, removing
+
+In concept, removing directories is somewhat similar to
+removing files---you want the directory to not exist in
+your current working directories, but you also want to
+be able to retrieve old releases in which the directory
+existed.
+
+The way that you remove a directory is to remove all
+the files in it. You don't remove the directory
+itself; there is no way to do that.
+Instead you specify the @samp{-P} option to
+@code{cvs update} or @code{cvs checkout},
+which will cause @sc{cvs} to remove empty
+directories from working directories.
+(Note that @code{cvs export} always removes empty directories.)
+Probably the
+best way to do this is to always specify @samp{-P}; if
+you want an empty directory then put a dummy file (for
+example @file{.keepme}) in it to prevent @samp{-P} from
+removing it.
+
+@c I'd try to give a rationale for this, but I'm not
+@c sure there is a particularly convincing one. What
+@c we would _like_ is for CVS to do a better job of version
+@c controlling whether directories exist, to eliminate the
+@c need for -P and so that a file can be a directory in
+@c one revision and a regular file in another.
+Note that @samp{-P} is implied by the @samp{-r} or @samp{-D}
+options of @code{checkout}. This way,
+@sc{cvs} will be able to correctly create the directory
+or not depending on whether the particular version you
+are checking out contains any files in that directory.
+
+@c ---------------------------------------------------------------------
+@node Moving files
+@section Moving and renaming files
+@cindex Moving files
+@cindex Renaming files
+@cindex Files, moving
+
+Moving files to a different directory or renaming them
+is not difficult, but some of the ways in which this
+works may be non-obvious. (Moving or renaming a
+directory is even harder. @xref{Moving directories}.).
+
+The examples below assume that the file @var{old} is renamed to
+@var{new}.
+
+@menu
+* Outside:: The normal way to Rename
+* Inside:: A tricky, alternative way
+* Rename by copying:: Another tricky, alternative way
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Outside
+@subsection The Normal way to Rename
+
+@c More rename issues. Not sure whether these are
+@c worth documenting; I'm putting them here because
+@c it seems to be as good a place as any to try to
+@c set down the issues.
+@c * "cvs annotate" will annotate either the new
+@c file or the old file; it cannot annotate _each
+@c line_ based on whether it was last changed in the
+@c new or old file. Unlike "cvs log", where the
+@c consequences of having to select either the new
+@c or old name seem fairly benign, this may be a
+@c real advantage to having CVS know about renames
+@c other than as a deletion and an addition.
+
+The normal way to move a file is to copy @var{old} to
+@var{new}, and then issue the normal @sc{cvs} commands
+to remove @var{old} from the repository, and add
+@var{new} to it.
+@c The following sentence is not true: one must cd into
+@c the directory to run "cvs add".
+@c (Both @var{old} and @var{new} could
+@c contain relative paths, for example @file{foo/bar.c}).
+
+@example
+$ mv @var{old} @var{new}
+$ cvs remove @var{old}
+$ cvs add @var{new}
+$ cvs commit -m "Renamed @var{old} to @var{new}" @var{old} @var{new}
+@end example
+
+This is the simplest way to move a file, it is not
+error-prone, and it preserves the history of what was
+done. Note that to access the history of the file you
+must specify the old or the new name, depending on what
+portion of the history you are accessing. For example,
+@code{cvs log @var{old}} will give the log up until the
+time of the rename.
+
+When @var{new} is committed its revision numbers will
+start again, usually at 1.1, so if that bothers you,
+use the @samp{-r @var{tag}} option to commit. For more
+information see @ref{Assigning revisions}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Inside
+@subsection Moving the history file
+
+This method is more dangerous, since it involves moving
+files inside the repository. Read this entire section
+before trying it out!
+
+@example
+$ cd $CVSROOT/@var{dir}
+$ mv @var{old},v @var{new},v
+@end example
+
+@noindent
+Advantages:
+
+@itemize @bullet
+@item
+The log of changes is maintained intact.
+
+@item
+The revision numbers are not affected.
+@end itemize
+
+@noindent
+Disadvantages:
+
+@itemize @bullet
+@item
+Old releases cannot easily be fetched from the
+repository. (The file will show up as @var{new} even
+in revisions from the time before it was renamed).
+
+@item
+There is no log information of when the file was renamed.
+
+@item
+Nasty things might happen if someone accesses the history file
+while you are moving it. Make sure no one else runs any of the @sc{cvs}
+commands while you move it.
+@end itemize
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Rename by copying
+@subsection Copying the history file
+
+This way also involves direct modifications to the
+repository. It is safe, but not without drawbacks.
+
+@example
+# @r{Copy the @sc{rcs} file inside the repository}
+$ cd $CVSROOT/@var{dir}
+$ cp @var{old},v @var{new},v
+# @r{Remove the old file}
+$ cd ~/@var{dir}
+$ rm @var{old}
+$ cvs remove @var{old}
+$ cvs commit @var{old}
+# @r{Remove all tags from @var{new}}
+$ cvs update @var{new}
+$ cvs log @var{new} # @r{Remember the non-branch tag names}
+$ cvs tag -d @var{tag1} @var{new}
+$ cvs tag -d @var{tag2} @var{new}
+@dots{}
+@end example
+
+By removing the tags you will be able to check out old
+revisions.
+
+@noindent
+Advantages:
+
+@itemize @bullet
+@item
+@c FIXME: Is this true about -D now that we have death
+@c support? See 5B.3 in the FAQ.
+Checking out old revisions works correctly, as long as
+you use @samp{-r @var{tag}} and not @samp{-D @var{date}}
+to retrieve the revisions.
+
+@item
+The log of changes is maintained intact.
+
+@item
+The revision numbers are not affected.
+@end itemize
+
+@noindent
+Disadvantages:
+
+@itemize @bullet
+@item
+You cannot easily see the history of the file across the rename.
+
+@ignore
+@c Is this true? I don't see how the revision numbers
+@c _could_ start over, when new,v is just old,v with
+@c the tags deleted.
+@c If there is some need to reinstate this text,
+@c it is "usually 1.1", not "1.0" and it needs an
+@c xref to Assigning revisions
+@item
+Unless you use the @samp{-r @var{tag}} (@pxref{commit
+options}) flag when @var{new} is committed its revision
+numbers will start at 1.0 again.
+@end ignore
+@end itemize
+
+@c ---------------------------------------------------------------------
+@node Moving directories
+@section Moving and renaming directories
+@cindex Moving directories
+@cindex Renaming directories
+@cindex Directories, moving
+
+The normal way to rename or move a directory is to
+rename or move each file within it as described in
+@ref{Outside}. Then check out with the @samp{-P}
+option, as described in @ref{Removing directories}.
+
+If you really want to hack the repository to rename or
+delete a directory in the repository, you can do it
+like this:
+
+@enumerate
+@item
+Inform everyone who has a checked out copy of the directory that the
+directory will be renamed. They should commit all their changes in all their
+copies of the project containing the directory to be removed, and remove
+all their working copies of said project, before you take the steps below.
+
+@item
+Rename the directory inside the repository.
+
+@example
+$ cd $CVSROOT/@var{parent-dir}
+$ mv @var{old-dir} @var{new-dir}
+@end example
+
+@item
+Fix the @sc{cvs} administrative files, if necessary (for
+instance if you renamed an entire module).
+
+@item
+Tell everyone that they can check out again and continue
+working.
+
+@end enumerate
+
+If someone had a working copy the @sc{cvs} commands will
+cease to work for him, until he removes the directory
+that disappeared inside the repository.
+
+It is almost always better to move the files in the
+directory instead of moving the directory. If you move the
+directory you are unlikely to be able to retrieve old
+releases correctly, since they probably depend on the
+name of the directories.
+
+@c ---------------------------------------------------------------------
+@node History browsing
+@chapter History browsing
+@cindex History browsing
+@cindex Traceability
+@cindex Isolation
+
+@ignore
+@c This is too long for an introduction (goal is
+@c one 20x80 character screen), and also mixes up a
+@c variety of issues (parallel development, history,
+@c maybe even touches on process control).
+
+@c -- @quote{To lose ones history is to lose ones soul.}
+@c -- ///
+@c -- ///Those who cannot remember the past are condemned to repeat it.
+@c -- /// -- George Santayana
+@c -- ///
+
+@sc{cvs} tries to make it easy for a group of people to work
+together. This is done in two ways:
+
+@itemize @bullet
+@item
+Isolation---You have your own working copy of the
+source. You are not affected by modifications made by
+others until you decide to incorporate those changes
+(via the @code{update} command---@pxref{update}).
+
+@item
+Traceability---When something has changed, you can
+always see @emph{exactly} what changed.
+@end itemize
+
+There are several features of @sc{cvs} that together lead
+to traceability:
+
+@itemize @bullet
+@item
+Each revision of a file has an accompanying log
+message.
+
+@item
+All commits are optionally logged to a central history
+database.
+
+@item
+Logging information can be sent to a user-defined
+program (@pxref{loginfo}).
+@end itemize
+
+@c -- More text here.
+
+This chapter should talk about the history file, the
+@code{log} command, the usefulness of ChangeLogs
+even when you run @sc{cvs}, and things like that.
+
+@end ignore
+
+@c kind of lame, in a lot of ways the above text inside
+@c the @ignore motivates this chapter better
+Once you have used @sc{cvs} to store a version control
+history---what files have changed when, how, and by
+whom, there are a variety of mechanisms for looking
+through the history.
+
+@c FIXME: should also be talking about how you look at
+@c old revisions (e.g. "cvs update -p -r 1.2 foo.c").
+@menu
+* log messages:: Log messages
+* history database:: The history database
+* user-defined logging:: User-defined logging
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node log messages
+@section Log messages
+
+@c FIXME: @xref to place where we talk about how to
+@c specify message to commit.
+Whenever you commit a file you specify a log message.
+
+@c FIXME: bring the information here, and get rid of or
+@c greatly shrink the "log" node.
+To look through the log messages which have been
+specified for every revision which has been committed,
+use the @code{cvs log} command (@pxref{log}).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node history database
+@section The history database
+
+@c FIXME: bring the information from the history file
+@c and history nodes here. Rewrite it to be motivated
+@c better (start out by clearly explaining what gets
+@c logged in history, for example).
+You can use the history file (@pxref{history file}) to
+log various @sc{cvs} actions. To retrieve the
+information from the history file, use the @code{cvs
+history} command (@pxref{history}).
+
+Note: you can control what is logged to this file by using the
+@samp{LogHistory} keyword in the @file{CVSROOT/config} file
+(@pxref{config}).
+
+@c
+@c The history database has many problems:
+@c * It is very unclear what field means what. This
+@c could be improved greatly by better documentation,
+@c but there are still non-orthogonalities (for
+@c example, tag does not record the "repository"
+@c field but most records do).
+@c * Confusion about files, directories, and modules.
+@c Some commands record one, some record others.
+@c * File removal is not logged. There is an 'R'
+@c record type documented, but CVS never uses it.
+@c * Tags are only logged for the "cvs rtag" command,
+@c not "cvs tag". The fix for this is not completely
+@c clear (see above about modules vs. files).
+@c * Are there other cases of operations that are not
+@c logged? One would hope for all changes to the
+@c repository to be logged somehow (particularly
+@c operations like tagging, "cvs admin -k", and other
+@c operations which do not record a history that one
+@c can get with "cvs log"). Operations on the working
+@c directory, like export, get, and release, are a
+@c second category also covered by the current "cvs
+@c history".
+@c * The history file does not record the options given
+@c to a command. The most serious manifestation of
+@c this is perhaps that it doesn't record whether a command
+@c was recursive. It is not clear to me whether one
+@c wants to log at a level very close to the command
+@c line, as a sort of way of logging each command
+@c (more or less), or whether one wants
+@c to log more at the level of what was changed (or
+@c something in between), but either way the current
+@c information has pretty big gaps.
+@c * Further details about a tag--like whether it is a
+@c branch tag or, if a non-branch tag, which branch it
+@c is on. One can find out this information about the
+@c tag as it exists _now_, but if the tag has been
+@c moved, one doesn't know what it was like at the time
+@c the history record was written.
+@c * Whether operating on a particular tag, date, or
+@c options was implicit (sticky) or explicit.
+@c
+@c Another item, only somewhat related to the above, is a
+@c way to control what is logged in the history file.
+@c This is probably the only good way to handle
+@c different people having different ideas about
+@c information/space tradeoffs.
+@c
+@c It isn't really clear that it makes sense to try to
+@c patch up the history file format as it exists now to
+@c include all that stuff. It might be better to
+@c design a whole new CVSROOT/nhistory file and "cvs
+@c nhistory" command, or some such, or in some other
+@c way trying to come up with a clean break from the
+@c past, which can address the above concerns. Another
+@c open question is how/whether this relates to
+@c taginfo/loginfo/etc.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node user-defined logging
+@section User-defined logging
+
+@c FIXME: probably should centralize this information
+@c here, at least to some extent. Maybe by moving the
+@c loginfo, etc., nodes here and replacing
+@c the "user-defined logging" node with one node for
+@c each method.
+You can customize @sc{cvs} to log various kinds of
+actions, in whatever manner you choose. These
+mechanisms operate by executing a script at various
+times. The script might append a message to a file
+listing the information and the programmer who created
+it, or send mail to a group of developers, or, perhaps,
+post a message to a particular newsgroup. To log
+commits, use the @file{loginfo} file (@pxref{loginfo}), and
+to log tagging operations, use the @file{taginfo} file
+(@pxref{taginfo}).
+
+@c FIXME: What is difference between doing it in the
+@c modules file and using loginfo/taginfo? Why should
+@c user use one or the other?
+To log commits, checkouts, exports, and tags,
+respectively, you can also use the @samp{-i},
+@samp{-o}, @samp{-e}, and @samp{-t} options in the
+modules file. For a more flexible way of giving
+notifications to various users, which requires less in
+the way of keeping centralized scripts up to date, use
+the @code{cvs watch add} command (@pxref{Getting
+Notified}); this command is useful even if you are not
+using @code{cvs watch on}.
+
+@c ---------------------------------------------------------------------
+@node Binary files
+@chapter Handling binary files
+@cindex Binary files
+
+The most common use for @sc{cvs} is to store text
+files. With text files, @sc{cvs} can merge revisions,
+display the differences between revisions in a
+human-visible fashion, and other such operations.
+However, if you are willing to give up a few of these
+abilities, @sc{cvs} can store binary files. For
+example, one might store a web site in @sc{cvs}
+including both text files and binary images.
+
+@menu
+* Binary why:: More details on issues with binary files
+* Binary howto:: How to store them
+@end menu
+
+@node Binary why
+@section The issues with binary files
+
+While the need to manage binary files may seem obvious
+if the files that you customarily work with are binary,
+putting them into version control does present some
+additional issues.
+
+One basic function of version control is to show the
+differences between two revisions. For example, if
+someone else checked in a new version of a file, you
+may wish to look at what they changed and determine
+whether their changes are good. For text files,
+@sc{cvs} provides this functionality via the @code{cvs
+diff} command. For binary files, it may be possible to
+extract the two revisions and then compare them with a
+tool external to @sc{cvs} (for example, word processing
+software often has such a feature). If there is no
+such tool, one must track changes via other mechanisms,
+such as urging people to write good log messages, and
+hoping that the changes they actually made were the
+changes that they intended to make.
+
+Another ability of a version control system is the
+ability to merge two revisions. For @sc{cvs} this
+happens in two contexts. The first is when users make
+changes in separate working directories
+(@pxref{Multiple developers}). The second is when one
+merges explicitly with the @samp{update -j} command
+(@pxref{Branching and merging}).
+
+In the case of text
+files, @sc{cvs} can merge changes made independently,
+and signal a conflict if the changes conflict. With
+binary files, the best that @sc{cvs} can do is present
+the two different copies of the file, and leave it to
+the user to resolve the conflict. The user may choose
+one copy or the other, or may run an external merge
+tool which knows about that particular file format, if
+one exists.
+Note that having the user merge relies primarily on the
+user to not accidentally omit some changes, and thus is
+potentially error prone.
+
+If this process is thought to be undesirable, the best
+choice may be to avoid merging. To avoid the merges
+that result from separate working directories, see the
+discussion of reserved checkouts (file locking) in
+@ref{Multiple developers}. To avoid the merges
+resulting from branches, restrict use of branches.
+
+@node Binary howto
+@section How to store binary files
+
+There are two issues with using @sc{cvs} to store
+binary files. The first is that @sc{cvs} by default
+converts line endings between the canonical form in
+which they are stored in the repository (linefeed
+only), and the form appropriate to the operating system
+in use on the client (for example, carriage return
+followed by line feed for Windows NT).
+
+The second is that a binary file might happen to
+contain data which looks like a keyword (@pxref{Keyword
+substitution}), so keyword expansion must be turned
+off.
+
+@c FIXME: the third is that one can't do merges with
+@c binary files. xref to Multiple Developers and the
+@c reserved checkout issues.
+
+The @samp{-kb} option available with some @sc{cvs}
+commands insures that neither line ending conversion
+nor keyword expansion will be done.
+
+Here is an example of how you can create a new file
+using the @samp{-kb} flag:
+
+@example
+$ echo '$@splitrcskeyword{Id}$' > kotest
+$ cvs add -kb -m"A test file" kotest
+$ cvs ci -m"First checkin; contains a keyword" kotest
+@end example
+
+If a file accidentally gets added without @samp{-kb},
+one can use the @code{cvs admin} command to recover.
+For example:
+
+@example
+$ echo '$@splitrcskeyword{Id}$' > kotest
+$ cvs add -m"A test file" kotest
+$ cvs ci -m"First checkin; contains a keyword" kotest
+$ cvs admin -kb kotest
+$ cvs update -A kotest
+# @r{For non-unix systems:}
+# @r{Copy in a good copy of the file from outside CVS}
+$ cvs commit -m "make it binary" kotest
+@end example
+
+@c Trying to describe this for both unix and non-unix
+@c in the same description is very confusing. Might
+@c want to split the two, or just ditch the unix "shortcut"
+@c (unixheads don't do much with binary files, anyway).
+@c This used to say "(Try the above example, and do a
+@c @code{cat kotest} after every command)". But that
+@c only really makes sense for the unix case.
+When you check in the file @file{kotest} the file is
+not preserved as a binary file, because you did not
+check it in as a binary file. The @code{cvs
+admin -kb} command sets the default keyword
+substitution method for this file, but it does not
+alter the working copy of the file that you have. If you need to
+cope with line endings (that is, you are using
+@sc{cvs} on a non-unix system), then you need to
+check in a new copy of the file, as shown by the
+@code{cvs commit} command above.
+On unix, the @code{cvs update -A} command suffices.
+@c FIXME: should also describe what the *other users*
+@c need to do, if they have checked out copies which
+@c have been corrupted by lack of -kb. I think maybe
+@c "cvs update -kb" or "cvs
+@c update -A" would suffice, although the user who
+@c reported this suggested removing the file, manually
+@c removing it from CVS/Entries, and then "cvs update"
+(Note that you can use @code{cvs log} to determine the default keyword
+substitution method for a file and @code{cvs status} to determine
+the keyword substitution method for a working copy.)
+
+However, in using @code{cvs admin -k} to change the
+keyword expansion, be aware that the keyword expansion
+mode is not version controlled. This means that, for
+example, that if you have a text file in old releases,
+and a binary file with the same name in new releases,
+@sc{cvs} provides no way to check out the file in text
+or binary mode depending on what version you are
+checking out. There is no good workaround for this
+problem.
+
+You can also set a default for whether @code{cvs add}
+and @code{cvs import} treat a file as binary based on
+its name; for example you could say that files who
+names end in @samp{.exe} are binary. @xref{Wrappers}.
+There is currently no way to have @sc{cvs} detect
+whether a file is binary based on its contents. The
+main difficulty with designing such a feature is that
+it is not clear how to distinguish between binary and
+non-binary files, and the rules to apply would vary
+considerably with the operating system.
+@c For example, it would be good on MS-DOS-family OSes
+@c for anything containing ^Z to be binary. Having
+@c characters with the 8th bit set imply binary is almost
+@c surely a bad idea in the context of ISO-8859-* and
+@c other such character sets. On VMS or the Mac, we
+@c could use the OS's file typing. This is a
+@c commonly-desired feature, and something of this sort
+@c may make sense. But there are a lot of pitfalls here.
+@c
+@c Another, probably better, way to tell is to read the
+@c file in text mode, write it to a temp file in text
+@c mode, and then do a binary mode compare of the two
+@c files. If they differ, it is a binary file. This
+@c might have problems on VMS (or some other system
+@c with several different text modes), but in general
+@c should be relatively portable. The only other
+@c downside I can think of is that it would be fairly
+@c slow, but that is perhaps a small price to pay for
+@c not having your files corrupted. Another issue is
+@c what happens if you import a text file with bare
+@c linefeeds on Windows. Such files will show up on
+@c Windows sometimes (I think some native windows
+@c programs even write them, on occasion). Perhaps it
+@c is reasonable to treat such files as binary; after
+@c all it is something of a presumption to assume that
+@c the user would want the linefeeds converted to CRLF.
+
+@c ---------------------------------------------------------------------
+@node Multiple developers
+@chapter Multiple developers
+@cindex Multiple developers
+@cindex Team of developers
+@cindex File locking
+@cindex Locking files
+@cindex Working copy
+@cindex Reserved checkouts
+@cindex Unreserved checkouts
+@cindex RCS-style locking
+
+When more than one person works on a software project
+things often get complicated. Often, two people try to
+edit the same file simultaneously. One solution, known
+as @dfn{file locking} or @dfn{reserved checkouts}, is
+to allow only one person to edit each file at a time.
+This is the only solution with some version control
+systems, including @sc{rcs} and @sc{sccs}. Currently
+the usual way to get reserved checkouts with @sc{cvs}
+is the @code{cvs admin -l} command (@pxref{admin
+options}). This is not as nicely integrated into
+@sc{cvs} as the watch features, described below, but it
+seems that most people with a need for reserved
+checkouts find it adequate.
+@c Or "find it better than worrying about implementing
+@c nicely integrated reserved checkouts" or ...?
+
+As of @sc{cvs} version 1.12.10, another technique for getting most of the
+effect of reserved checkouts is to enable advisory locks. To enable advisory
+locks, have all developers put "edit -c", "commit -c" in their
+.cvsrc file, and turn on watches in the repository. This
+prevents them from doing a @code{cvs edit} if anyone is
+already editting the file. It also may
+be possible to use plain watches together with suitable
+procedures (not enforced by software), to avoid having
+two people edit at the same time.
+
+@c Our unreserved checkout model might not
+@c be quite the same as others. For example, I
+@c think that some systems will tend to create a branch
+@c in the case where CVS prints "up-to-date check failed".
+@c It isn't clear to me whether we should try to
+@c explore these subtleties; it could easily just
+@c confuse people.
+The default model with @sc{cvs} is known as
+@dfn{unreserved checkouts}. In this model, developers
+can edit their own @dfn{working copy} of a file
+simultaneously. The first person that commits his
+changes has no automatic way of knowing that another
+has started to edit it. Others will get an error
+message when they try to commit the file. They must
+then use @sc{cvs} commands to bring their working copy
+up to date with the repository revision. This process
+is almost automatic.
+
+@c FIXME? should probably use the word "watch" here, to
+@c tie this into the text below and above.
+@sc{cvs} also supports mechanisms which facilitate
+various kinds of communication, without actually
+enforcing rules like reserved checkouts do.
+
+The rest of this chapter describes how these various
+models work, and some of the issues involved in
+choosing between them.
+
+@ignore
+Here is a draft reserved checkout design or discussion
+of the issues. This seems like as good a place as any
+for this.
+
+Might want a cvs lock/cvs unlock--in which the names
+differ from edit/unedit because the network must be up
+for these to work. unedit gives an error if there is a
+reserved checkout in place (so that people don't
+accidentally leave locks around); unlock gives an error
+if one is not in place (this is more arguable; perhaps
+it should act like unedit in that case).
+
+On the other hand, might want it so that emacs,
+scripts, etc., can get ready to edit a file without
+having to know which model is in use. In that case we
+would have a "cvs watch lock" (or .cvsrc?) (that is,
+three settings, "on", "off", and "lock"). Having cvs
+watch lock set would cause a get to record in the CVS
+directory which model is in use, and cause "cvs edit"
+to change behaviors. We'd want a way to query which
+setting is in effect (this would be handy even if it is
+only "on" or "off" as presently). If lock is in
+effect, then commit would require a lock before
+allowing a checkin; chmod wouldn't suffice (might be
+debatable--see chmod comment below, in watches--but it
+is the way people expect RCS to work and I can't think
+of any significant downside. On the other hand, maybe
+it isn't worth bothering, because people who are used
+to RCS wouldn't think to use chmod anyway).
+
+Implementation: use file attributes or use RCS
+locking. The former avoids more dependence on RCS
+behaviors we will need to re-implement as we librarify
+RCS, and makes it easier to import/export RCS files (in
+that context, want to ignore the locker field). But
+note that RCS locks are per-branch, which is the
+correct behavior (this is also an issue for the "watch
+on" features; they should be per-branch too).
+
+Here are a few more random notes about implementation
+details, assuming "cvs watch lock" and
+
+CVS/Watched file? Or try to fit this into CVS/Entries somehow?
+Cases: (1) file is checked out (unreserved or with watch on) by old
+version of @sc{cvs}, now we do something with new one, (2) file is checked
+out by new version, now we do something with old one.
+
+Remote protocol would have a "Watched" analogous to "Mode". Of course
+it would apply to all Updated-like requests. How do we keep this
+setting up to date? I guess that there wants to be a Watched request,
+and the server would send a new one if it isn't up to date? (Ugh--hard
+to implement and slows down "cvs -q update"--is there an easier way?)
+
+"cvs edit"--checks CVS/Watched, and if watch lock, then sends
+"edit-lock" request. Which comes back with a Checked-in with
+appropriate Watched (off, on, lock, locked, or some such?), or error
+message if already locked.
+
+"cvs commit"--only will commit if off/on/locked. lock is not OK.
+
+Doc:
+note that "cvs edit" must be connected to network if watch lock is in
+effect.
+
+Talk about what to do if someone has locked a file and you want to
+edit that file. (breaking locks, or lack thereof).
+
+
+One other idea (which could work along with the
+existing "cvs admin -l" reserved checkouts, as well as
+the above):
+
+"cvs editors" could show who has the file locked, if
+someone does.
+
+@end ignore
+
+@menu
+* File status:: A file can be in several states
+* Updating a file:: Bringing a file up-to-date
+* Conflicts example:: An informative example
+* Informing others:: To cooperate you must inform
+* Concurrency:: Simultaneous repository access
+* Watches:: Mechanisms to track who is editing files
+* Choosing a model:: Reserved or unreserved checkouts?
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node File status
+@section File status
+@cindex File status
+@cindex Status of a file
+
+@c Shouldn't this start with an example or something,
+@c introducing the unreserved checkout model? Before we
+@c dive into listing states?
+Based on what operations you have performed on a
+checked out file, and what operations others have
+performed to that file in the repository, one can
+classify a file in a number of states. The states, as
+reported by the @code{status} command, are:
+
+@c The order of items is chosen to group logically
+@c similar outputs together.
+@c People who want alphabetical can use the index...
+@table @asis
+@cindex Up-to-date
+@item Up-to-date
+The file is identical with the latest revision in the
+repository for the branch in use.
+@c FIXME: should we clarify "in use"? The answer is
+@c sticky tags, and trying to distinguish branch sticky
+@c tags from non-branch sticky tags seems rather awkward
+@c here.
+@c FIXME: What happens with non-branch sticky tags? Is
+@c a stuck file "Up-to-date" or "Needs checkout" or what?
+
+@item Locally Modified
+@cindex Locally Modified
+You have edited the file, and not yet committed your changes.
+
+@item Locally Added
+@cindex Locally Added
+You have added the file with @code{add}, and not yet
+committed your changes.
+@c There are many cases involving the file being
+@c added/removed/modified in the working directory, and
+@c added/removed/modified in the repository, which we
+@c don't try to describe here. I'm not sure that "cvs
+@c status" produces a non-confusing output in most of
+@c those cases.
+
+@item Locally Removed
+@cindex Locally Removed
+You have removed the file with @code{remove}, and not yet
+committed your changes.
+
+@item Needs Checkout
+@cindex Needs Checkout
+Someone else has committed a newer revision to the
+repository. The name is slightly misleading; you will
+ordinarily use @code{update} rather than
+@code{checkout} to get that newer revision.
+
+@item Needs Patch
+@cindex Needs Patch
+@c See also newb-123j0 in sanity.sh (although that case
+@c should probably be changed rather than documented).
+Like Needs Checkout, but the @sc{cvs} server will send
+a patch rather than the entire file. Sending a patch or
+sending an entire file accomplishes the same thing.
+
+@item Needs Merge
+@cindex Needs Merge
+Someone else has committed a newer revision to the repository, and you
+have also made modifications to the file.
+
+@item Unresolved Conflict
+@cindex Unresolved Conflict
+@c FIXCVS - This file status needs to be changed to some more informative
+@c text that distinguishes it more clearly from each of the Locally Added,
+@c File had conflicts on merge, and Unknown status types, but an exact and
+@c succinct wording escapes me at the moment.
+A file with the same name as this new file has been added to the repository
+from a second workspace. This file will need to be moved out of the way
+to allow an @code{update} to complete.
+
+@item File had conflicts on merge
+@cindex File had conflicts on merge
+@c is it worth saying that this message was "Unresolved
+@c Conflict" in CVS 1.9 and earlier? I'm inclined to
+@c think that is unnecessarily confusing to new users.
+This is like Locally Modified, except that a previous
+@code{update} command gave a conflict. If you have not
+already done so, you need to
+resolve the conflict as described in @ref{Conflicts example}.
+
+@item Unknown
+@cindex Unknown
+@sc{cvs} doesn't know anything about this file. For
+example, you have created a new file and have not run
+@code{add}.
+@c
+@c "Entry Invalid" and "Classify Error" are also in the
+@c status.c. The latter definitely indicates a CVS bug
+@c (should it be worded more like "internal error" so
+@c people submit bug reports if they see it?). The former
+@c I'm not as sure; I haven't tracked down whether/when it
+@c appears in "cvs status" output.
+
+@end table
+
+To help clarify the file status, @code{status} also
+reports the @code{Working revision} which is the
+revision that the file in the working directory derives
+from, and the @code{Repository revision} which is the
+latest revision in the repository for the branch in
+use.
+The @samp{Commit Identifier} reflects the unique commitid
+of the @code{commit}.
+@c FIXME: should we clarify "in use"? The answer is
+@c sticky tags, and trying to distinguish branch sticky
+@c tags from non-branch sticky tags seems rather awkward
+@c here.
+@c FIXME: What happens with non-branch sticky tags?
+@c What is the Repository Revision there? See the
+@c comment at vn_rcs in cvs.h, which is kind of
+@c confused--we really need to document better what this
+@c field contains.
+@c Q: Should we document "New file!" and other such
+@c outputs or are they self-explanatory?
+@c FIXME: what about the date to the right of "Working
+@c revision"? It doesn't appear with client/server and
+@c seems unnecessary (redundant with "ls -l") so
+@c perhaps it should be removed for non-client/server too?
+@c FIXME: Need some examples.
+@c FIXME: Working revision can also be something like
+@c "-1.3" for a locally removed file. Not at all
+@c self-explanatory (and it is possible that CVS should
+@c be changed rather than documenting this).
+
+@c Would be nice to have an @example showing output
+@c from cvs status, with comments showing the xref
+@c where each part of the output is described. This
+@c might fit in nicely if it is desirable to split this
+@c node in two; one to introduce "cvs status" and one
+@c to list each of the states.
+The options to @code{status} are listed in
+@ref{Invoking CVS}. For information on its @code{Sticky tag}
+and @code{Sticky date} output, see @ref{Sticky tags}.
+For information on its @code{Sticky options} output,
+see the @samp{-k} option in @ref{update options}.
+
+You can think of the @code{status} and @code{update}
+commands as somewhat complementary. You use
+@code{update} to bring your files up to date, and you
+can use @code{status} to give you some idea of what an
+@code{update} would do (of course, the state of the
+repository might change before you actually run
+@code{update}). In fact, if you want a command to
+display file status in a more brief format than is
+displayed by the @code{status} command, you can invoke
+
+@cindex update, to display file status
+@example
+$ cvs -n -q update
+@end example
+
+The @samp{-n} option means to not actually do the
+update, but merely to display statuses; the @samp{-q}
+option avoids printing the name of each directory. For
+more information on the @code{update} command, and
+these options, see @ref{Invoking CVS}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Updating a file
+@section Bringing a file up to date
+@cindex Bringing a file up to date
+@cindex Updating a file
+@cindex Merging a file
+@cindex Update, introduction
+
+When you want to update or merge a file, use the @code{cvs update -d}
+command. For files that are not up to date this is roughly equivalent
+to a @code{checkout} command: the newest revision of the file is
+extracted from the repository and put in your working directory. The
+@code{-d} option, not necessary with @code{checkout}, tells @sc{cvs}
+that you wish it to create directories added by other developers.
+
+Your modifications to a file are never lost when you
+use @code{update}. If no newer revision exists,
+running @code{update} has no effect. If you have
+edited the file, and a newer revision is available,
+@sc{cvs} will merge all changes into your working copy.
+
+For instance, imagine that you checked out revision 1.4 and started
+editing it. In the meantime someone else committed revision 1.5, and
+shortly after that revision 1.6. If you run @code{update} on the file
+now, @sc{cvs} will incorporate all changes between revision 1.4 and 1.6 into
+your file.
+
+@cindex Overlap
+If any of the changes between 1.4 and 1.6 were made too
+close to any of the changes you have made, an
+@dfn{overlap} occurs. In such cases a warning is
+printed, and the resulting file includes both
+versions of the lines that overlap, delimited by
+special markers.
+@xref{update}, for a complete description of the
+@code{update} command.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Conflicts example
+@section Conflicts example
+@cindex Merge, an example
+@cindex Example of merge
+@cindex driver.c (merge example)
+
+Suppose revision 1.4 of @file{driver.c} contains this:
+
+@example
+#include <stdio.h>
+
+void main()
+@{
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? 0 : 1);
+@}
+@end example
+
+@noindent
+Revision 1.6 of @file{driver.c} contains this:
+
+@example
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(!!nerr);
+@}
+@end example
+
+@noindent
+Your working copy of @file{driver.c}, based on revision
+1.4, contains this before you run @samp{cvs update}:
+@c -- Really include "cvs"?
+
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+void main()
+@{
+ init_scanner();
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@}
+@end example
+
+@noindent
+You run @samp{cvs update}:
+@c -- Really include "cvs"?
+
+@example
+$ cvs update driver.c
+RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v
+retrieving revision 1.4
+retrieving revision 1.6
+Merging differences between 1.4 and 1.6 into driver.c
+rcsmerge warning: overlaps during merge
+cvs update: conflicts found in driver.c
+C driver.c
+@end example
+
+@noindent
+@cindex Conflicts (merge example)
+@sc{cvs} tells you that there were some conflicts.
+Your original working file is saved unmodified in
+@file{.#driver.c.1.4}. The new version of
+@file{driver.c} contains this:
+
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ init_scanner();
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+@asis{}<<<<<<< driver.c
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@asis{}=======
+ exit(!!nerr);
+@asis{}>>>>>>> 1.6
+@}
+@end example
+
+@noindent
+@cindex Markers, conflict
+@cindex Conflict markers
+@cindex <<<<<<<
+@cindex >>>>>>>
+@cindex =======
+
+Note how all non-overlapping modifications are incorporated in your working
+copy, and that the overlapping section is clearly marked with
+@samp{<<<<<<<}, @samp{=======} and @samp{>>>>>>>}.
+
+@cindex Resolving a conflict
+@cindex Conflict resolution
+You resolve the conflict by editing the file, removing the markers and
+the erroneous line. Suppose you end up with this file:
+@c -- Add xref to the pcl-cvs manual when it talks
+@c -- about this.
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ init_scanner();
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@}
+@end example
+
+@noindent
+You can now go ahead and commit this as revision 1.7.
+
+@example
+$ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c
+Checking in driver.c;
+/usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c
+new revision: 1.7; previous revision: 1.6
+done
+@end example
+
+For your protection, @sc{cvs} will refuse to check in a
+file if a conflict occurred and you have not resolved
+the conflict. Currently to resolve a conflict, you
+must change the timestamp on the file. In previous
+versions of @sc{cvs}, you also needed to
+insure that the file contains no conflict markers.
+Because
+your file may legitimately contain conflict markers (that
+is, occurrences of @samp{>>>>>>> } at the start of a
+line that don't mark a conflict), the current
+version of @sc{cvs} will print a warning and proceed to
+check in the file.
+@c The old behavior was really icky; the only way out
+@c was to start hacking on
+@c the @code{CVS/Entries} file or other such workarounds.
+@c
+@c If the timestamp thing isn't considered nice enough,
+@c maybe there should be a "cvs resolved" command
+@c which clears the conflict indication. For a nice user
+@c interface, this should be invoked by an interactive
+@c merge tool like emerge rather than by the user
+@c directly--such a tool can verify that the user has
+@c really dealt with each conflict.
+
+@cindex emerge
+If you use release 1.04 or later of pcl-cvs (a @sc{gnu}
+Emacs front-end for @sc{cvs}) you can use an Emacs
+package called emerge to help you resolve conflicts.
+See the documentation for pcl-cvs.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Informing others
+@section Informing others about commits
+@cindex Informing others
+@cindex Spreading information
+@cindex Mail, automatic mail on commit
+
+It is often useful to inform others when you commit a
+new revision of a file. The @samp{-i} option of the
+@file{modules} file, or the @file{loginfo} file, can be
+used to automate this process. @xref{modules}.
+@xref{loginfo}. You can use these features of @sc{cvs}
+to, for instance, instruct @sc{cvs} to mail a
+message to all developers, or post a message to a local
+newsgroup.
+@c -- More text would be nice here.
+
+@node Concurrency
+@section Several developers simultaneously attempting to run CVS
+
+@cindex Locks, cvs, introduction
+@c For a discussion of *why* CVS creates locks, see
+@c the comment at the start of src/lock.c
+If several developers try to run @sc{cvs} at the same
+time, one may get the following message:
+
+@example
+[11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo
+@end example
+
+@cindex #cvs.rfl, removing
+@cindex #cvs.wfl, removing
+@cindex #cvs.lock, removing
+@sc{cvs} will try again every 30 seconds, and either
+continue with the operation or print the message again,
+if it still needs to wait. If a lock seems to stick
+around for an undue amount of time, find the person
+holding the lock and ask them about the cvs command
+they are running. If they aren't running a cvs
+command, look in the repository directory mentioned in
+the message and remove files which they own whose names
+start with @file{#cvs.rfl},
+@file{#cvs.wfl}, or @file{#cvs.lock}.
+
+Note that these locks are to protect @sc{cvs}'s
+internal data structures and have no relationship to
+the word @dfn{lock} in the sense used by
+@sc{rcs}---which refers to reserved checkouts
+(@pxref{Multiple developers}).
+
+Any number of people can be reading from a given
+repository at a time; only when someone is writing do
+the locks prevent other people from reading or writing.
+
+@cindex Atomic transactions, lack of
+@cindex Transactions, atomic, lack of
+@c the following talks about what one might call commit/update
+@c atomicity.
+@c Probably also should say something about
+@c commit/commit atomicity, that is, "An update will
+@c not get partial versions of more than one commit".
+@c CVS currently has this property and I guess we can
+@c make it a documented feature.
+@c For example one person commits
+@c a/one.c and b/four.c and another commits a/two.c and
+@c b/three.c. Then an update cannot get the new a/one.c
+@c and a/two.c and the old b/four.c and b/three.c.
+One might hope for the following property:
+
+@quotation
+If someone commits some changes in one cvs command,
+then an update by someone else will either get all the
+changes, or none of them.
+@end quotation
+
+@noindent
+but @sc{cvs} does @emph{not} have this property. For
+example, given the files
+
+@example
+a/one.c
+a/two.c
+b/three.c
+b/four.c
+@end example
+
+@noindent
+if someone runs
+
+@example
+cvs ci a/two.c b/three.c
+@end example
+
+@noindent
+and someone else runs @code{cvs update} at the same
+time, the person running @code{update} might get only
+the change to @file{b/three.c} and not the change to
+@file{a/two.c}.
+
+@node Watches
+@section Mechanisms to track who is editing files
+@cindex Watches
+
+For many groups, use of @sc{cvs} in its default mode is
+perfectly satisfactory. Users may sometimes go to
+check in a modification only to find that another
+modification has intervened, but they deal with it and
+proceed with their check in. Other groups prefer to be
+able to know who is editing what files, so that if two
+people try to edit the same file they can choose to
+talk about who is doing what when rather than be
+surprised at check in time. The features in this
+section allow such coordination, while retaining the
+ability of two developers to edit the same file at the
+same time.
+
+@c Some people might ask why CVS does not enforce the
+@c rule on chmod, by requiring a cvs edit before a cvs
+@c commit. The main reason is that it could always be
+@c circumvented--one could edit the file, and
+@c then when ready to check it in, do the cvs edit and put
+@c in the new contents and do the cvs commit. One
+@c implementation note: if we _do_ want to have cvs commit
+@c require a cvs edit, we should store the state on
+@c whether the cvs edit has occurred in the working
+@c directory, rather than having the server try to keep
+@c track of what working directories exist.
+@c FIXME: should the above discussion be part of the
+@c manual proper, somewhere, not just in a comment?
+For maximum benefit developers should use @code{cvs
+edit} (not @code{chmod}) to make files read-write to
+edit them, and @code{cvs release} (not @code{rm}) to
+discard a working directory which is no longer in use,
+but @sc{cvs} is not able to enforce this behavior.
+
+If a development team wants stronger enforcement of
+watches and all team members are using a @sc{cvs} client version 1.12.10 or
+greater to access a @sc{cvs} server version 1.12.10 or greater, they can
+enable advisory locks. To enable advisory locks, have all developers
+put "edit -c" and "commit -c" into all .cvsrc files,
+and make files default to read only by turning on watches
+or putting "cvs -r" into all .cvsrc files.
+This prevents multiple people from editting a file at
+the same time (unless explicitly overriden with @samp{-f}).
+
+@c I'm a little dissatisfied with this presentation,
+@c because "watch on"/"edit"/"editors" are one set of
+@c functionality, and "watch add"/"watchers" is another
+@c which is somewhat orthogonal even though they interact in
+@c various ways. But I think it might be
+@c confusing to describe them separately (e.g. "watch
+@c add" with loginfo). I don't know.
+
+@menu
+* Setting a watch:: Telling CVS to watch certain files
+* Getting Notified:: Telling CVS to notify you
+* Editing files:: How to edit a file which is being watched
+* Watch information:: Information about who is watching and editing
+* Watches Compatibility:: Watches interact poorly with CVS 1.6 or earlier
+@end menu
+
+@node Setting a watch
+@subsection Telling CVS to watch certain files
+
+To enable the watch features, you first specify that
+certain files are to be watched.
+
+@cindex watch on (subcommand)
+@deffn Command {cvs watch on} [@code{-lR}] [@var{files}]@dots{}
+
+@cindex Read-only files, and watches
+Specify that developers should run @code{cvs edit}
+before editing @var{files}. @sc{cvs} will create working
+copies of @var{files} read-only, to remind developers
+to run the @code{cvs edit} command before working on
+them.
+
+If @var{files} includes the name of a directory, @sc{cvs}
+arranges to watch all files added to the corresponding
+repository directory, and sets a default for files
+added in the future; this allows the user to set
+notification policies on a per-directory basis. The
+contents of the directory are processed recursively,
+unless the @code{-l} option is given.
+The @code{-R} option can be used to force recursion if the @code{-l}
+option is set in @file{~/.cvsrc} (@pxref{~/.cvsrc}).
+
+If @var{files} is omitted, it defaults to the current directory.
+
+@cindex watch off (subcommand)
+@end deffn
+
+@deffn Command {cvs watch off} [@code{-lR}] [@var{files}]@dots{}
+
+Do not create @var{files} read-only on checkout; thus,
+developers will not be reminded to use @code{cvs edit}
+and @code{cvs unedit}.
+@ignore
+@sc{cvs} will check out @var{files}
+read-write as usual, unless other permissions override
+due to the @code{PreservePermissions} option being
+enabled in the @file{config} administrative file
+(@pxref{Special Files}, @pxref{config})
+@end ignore
+
+The @var{files} and options are processed as for @code{cvs
+watch on}.
+
+@end deffn
+
+@node Getting Notified
+@subsection Telling CVS to notify you
+
+You can tell @sc{cvs} that you want to receive
+notifications about various actions taken on a file.
+You can do this without using @code{cvs watch on} for
+the file, but generally you will want to use @code{cvs
+watch on}, to remind developers to use the @code{cvs edit}
+command.
+
+@cindex watch add (subcommand)
+@deffn Command {cvs watch add} [@code{-lR}] [@code{-a} @var{action}]@dots{} [@var{files}]@dots{}
+
+Add the current user to the list of people to receive notification of
+work done on @var{files}.
+
+The @code{-a} option specifies what kinds of events @sc{cvs} should notify
+the user about. @var{action} is one of the following:
+
+@table @code
+
+@item edit
+Another user has applied the @code{cvs edit} command (described
+below) to a watched file.
+
+@item commit
+Another user has committed changes to one of the named @var{files}.
+
+@item unedit
+Another user has abandoned editing a file (other than by committing changes).
+They can do this in several ways, by:
+
+@itemize @bullet
+
+@item
+applying the @code{cvs unedit} command (described below) to the file
+
+@item
+applying the @code{cvs release} command (@pxref{release}) to the file's parent directory
+(or recursively to a directory more than one level up)
+
+@item
+deleting the file and allowing @code{cvs update} to recreate it
+
+@end itemize
+
+@item all
+All of the above.
+
+@item none
+None of the above. (This is useful with @code{cvs edit},
+described below.)
+
+@end table
+
+The @code{-a} option may appear more than once, or not at all. If
+omitted, the action defaults to @code{all}.
+
+The @var{files} and options are processed as for
+@code{cvs watch on}.
+
+@end deffn
+
+
+@cindex watch remove (subcommand)
+@deffn Command {cvs watch remove} [@code{-lR}] [@code{-a} @var{action}]@dots{} [@var{files}]@dots{}
+
+Remove a notification request established using @code{cvs watch add};
+the arguments are the same. If the @code{-a} option is present, only
+watches for the specified actions are removed.
+
+@end deffn
+
+@cindex notify (admin file)
+When the conditions exist for notification, @sc{cvs}
+calls the @file{notify} administrative file. Edit
+@file{notify} as one edits the other administrative
+files (@pxref{Intro administrative files}). This
+file follows the usual conventions for administrative
+files (@pxref{syntax}), where each line is a regular
+expression followed by a command to execute. The
+command should contain a single occurrence of @samp{%s}
+which will be replaced by the user to notify; the rest
+of the information regarding the notification will be
+supplied to the command on standard input. The
+standard thing to put in the @code{notify} file is the
+single line:
+
+@example
+ALL mail %s -s "CVS notification"
+@end example
+
+@noindent
+This causes users to be notified by electronic mail.
+@c FIXME: should it be this hard to set up this
+@c behavior (and the result when one fails to do so,
+@c silent failure to notify, so non-obvious)? Should
+@c CVS give a warning if no line in notify matches (and
+@c document the use of "DEFAULT :" for the case where
+@c skipping the notification is indeed desired)?
+
+@cindex users (admin file)
+Note that if you set this up in the straightforward
+way, users receive notifications on the server machine.
+One could of course write a @file{notify} script which
+directed notifications elsewhere, but to make this
+easy, @sc{cvs} allows you to associate a notification
+address for each user. To do so create a file
+@file{users} in @file{CVSROOT} with a line for each
+user in the format @var{user}:@var{value}. Then
+instead of passing the name of the user to be notified
+to @file{notify}, @sc{cvs} will pass the @var{value}
+(normally an email address on some other machine).
+
+@sc{cvs} does not notify you for your own changes.
+Currently this check is done based on whether the user
+name of the person taking the action which triggers
+notification matches the user name of the person
+getting notification. In fact, in general, the watches
+features only track one edit by each user. It probably
+would be more useful if watches tracked each working
+directory separately, so this behavior might be worth
+changing.
+@c "behavior might be worth changing" is an effort to
+@c point to future directions while also not promising
+@c that "they" (as in "why don't they fix CVS to....")
+@c will do this.
+@c one implementation issue is identifying whether a
+@c working directory is same or different. Comparing
+@c pathnames/hostnames is hopeless, but having the server
+@c supply a serial number which the client stores in the
+@c CVS directory as a magic cookie should work.
+
+@node Editing files
+@subsection How to edit a file which is being watched
+
+@cindex Checkout, as term for getting ready to edit
+Since a file which is being watched is checked out
+read-only, you cannot simply edit it. To make it
+read-write, and inform others that you are planning to
+edit it, use the @code{cvs edit} command. Some systems
+call this a @dfn{checkout}, but @sc{cvs} uses that term
+for obtaining a copy of the sources (@pxref{Getting the
+source}), an operation which those systems call a
+@dfn{get} or a @dfn{fetch}.
+@c Issue to think about: should we transition CVS
+@c towards the "get" terminology? "cvs get" is already a
+@c synonym for "cvs checkout" and that section of the
+@c manual refers to "Getting the source". If this is
+@c done, needs to be done gingerly (for example, we should
+@c still accept "checkout" in .cvsrc files indefinitely
+@c even if the CVS's messages are changed from "cvs checkout: "
+@c to "cvs get: ").
+@c There is a concern about whether "get" is not as
+@c good for novices because it is a more general term
+@c than "checkout" (and thus arguably harder to assign
+@c a technical meaning for).
+
+@cindex edit (subcommand)
+@deffn Command {cvs edit} [@code{-lR}] [@code{-a} @var{action}]@dots{} [@var{files}]@dots{}
+
+Prepare to edit the working files @var{files}. @sc{cvs} makes the
+@var{files} read-write, and notifies users who have requested
+@code{edit} notification for any of @var{files}.
+
+The @code{cvs edit} command accepts the same options as the
+@code{cvs watch add} command, and establishes a temporary watch for the
+user on @var{files}; @sc{cvs} will remove the watch when @var{files} are
+@code{unedit}ed or @code{commit}ted. If the user does not wish to
+receive notifications, she should specify @code{-a none}.
+
+The @var{files} and the options are processed as for the @code{cvs
+watch} commands.
+
+There are two additional options that @code{cvs edit} understands as of
+@sc{cvs} client and server versions 1.12.10 but @code{cvs watch} does not.
+The first is @code{-c}, which causes @code{cvs edit} to fail if anyone else
+is editting the file. This is probably only useful when @samp{edit -c} and
+@samp{commit -c} are specified in all developers' @file{.cvsrc} files. This
+behavior may be overriden this via the @code{-f} option, which overrides
+@code{-c} and allows multiple edits to succeed.
+
+@ignore
+@strong{Caution: If the @code{PreservePermissions}
+option is enabled in the repository (@pxref{config}),
+@sc{cvs} will not change the permissions on any of the
+@var{files}. The reason for this change is to ensure
+that using @samp{cvs edit} does not interfere with the
+ability to store file permissions in the @sc{cvs}
+repository.}
+@end ignore
+
+@end deffn
+
+Normally when you are done with a set of changes, you
+use the @code{cvs commit} command, which checks in your
+changes and returns the watched files to their usual
+read-only state. But if you instead decide to abandon
+your changes, or not to make any changes, you can use
+the @code{cvs unedit} command.
+
+@cindex unedit (subcommand)
+@cindex Abandoning work
+@cindex Reverting to repository version
+@deffn Command {cvs unedit} [@code{-lR}] [@var{files}]@dots{}
+
+Abandon work on the working files @var{files}, and revert them to the
+repository versions on which they are based. @sc{cvs} makes those
+@var{files} read-only for which users have requested notification using
+@code{cvs watch on}. @sc{cvs} notifies users who have requested @code{unedit}
+notification for any of @var{files}.
+
+The @var{files} and options are processed as for the
+@code{cvs watch} commands.
+
+If watches are not in use, the @code{unedit} command
+probably does not work, and the way to revert to the
+repository version is with the command @code{cvs update -C file}
+(@pxref{update}).
+The meaning is
+not precisely the same; the latter may also
+bring in some changes which have been made in the
+repository since the last time you updated.
+@c It would be a useful enhancement to CVS to make
+@c unedit work in the non-watch case as well.
+@end deffn
+
+When using client/server @sc{cvs}, you can use the
+@code{cvs edit} and @code{cvs unedit} commands even if
+@sc{cvs} is unable to successfully communicate with the
+server; the notifications will be sent upon the next
+successful @sc{cvs} command.
+
+@node Watch information
+@subsection Information about who is watching and editing
+
+@cindex watchers (subcommand)
+@deffn Command {cvs watchers} [@code{-lR}] [@var{files}]@dots{}
+
+List the users currently watching changes to @var{files}. The report
+includes the files being watched, and the mail address of each watcher.
+
+The @var{files} and options are processed as for the
+@code{cvs watch} commands.
+
+@end deffn
+
+
+@cindex editors (subcommand)
+@deffn Command {cvs editors} [@code{-lR}] [@var{files}]@dots{}
+
+List the users currently working on @var{files}. The report
+includes the mail address of each user, the time when the user began
+working with the file, and the host and path of the working directory
+containing the file.
+
+The @var{files} and options are processed as for the
+@code{cvs watch} commands.
+
+@end deffn
+
+@node Watches Compatibility
+@subsection Using watches with old versions of CVS
+
+@cindex CVS 1.6, and watches
+If you use the watch features on a repository, it
+creates @file{CVS} directories in the repository and
+stores the information about watches in that directory.
+If you attempt to use @sc{cvs} 1.6 or earlier with the
+repository, you get an error message such as the
+following (all on one line):
+
+@example
+cvs update: cannot open CVS/Entries for reading:
+No such file or directory
+@end example
+
+@noindent
+and your operation will likely be aborted. To use the
+watch features, you must upgrade all copies of @sc{cvs}
+which use that repository in local or server mode. If
+you cannot upgrade, use the @code{watch off} and
+@code{watch remove} commands to remove all watches, and
+that will restore the repository to a state which
+@sc{cvs} 1.6 can cope with.
+
+@node Choosing a model
+@section Choosing between reserved or unreserved checkouts
+@cindex Choosing, reserved or unreserved checkouts
+
+Reserved and unreserved checkouts each have pros and
+cons. Let it be said that a lot of this is a matter of
+opinion or what works given different groups' working
+styles, but here is a brief description of some of the
+issues. There are many ways to organize a team of
+developers. @sc{cvs} does not try to enforce a certain
+organization. It is a tool that can be used in several
+ways.
+
+Reserved checkouts can be very counter-productive. If
+two persons want to edit different parts of a file,
+there may be no reason to prevent either of them from
+doing so. Also, it is common for someone to take out a
+lock on a file, because they are planning to edit it,
+but then forget to release the lock.
+
+@c "many groups"? specifics? cites to papers on this?
+@c some way to weasel-word it a bit more so we don't
+@c need facts :-)?
+People, especially people who are familiar with
+reserved checkouts, often wonder how often conflicts
+occur if unreserved checkouts are used, and how
+difficult they are to resolve. The experience with
+many groups is that they occur rarely and usually are
+relatively straightforward to resolve.
+
+The rarity of serious conflicts may be surprising, until one realizes
+that they occur only when two developers disagree on the proper design
+for a given section of code; such a disagreement suggests that the
+team has not been communicating properly in the first place. In order
+to collaborate under @emph{any} source management regimen, developers
+must agree on the general design of the system; given this agreement,
+overlapping changes are usually straightforward to merge.
+
+In some cases unreserved checkouts are clearly
+inappropriate. If no merge tool exists for the kind of
+file you are managing (for example word processor files
+or files edited by Computer Aided Design programs), and
+it is not desirable to change to a program which uses a
+mergeable data format, then resolving conflicts is
+going to be unpleasant enough that you generally will
+be better off to simply avoid the conflicts instead, by
+using reserved checkouts.
+
+The watches features described above in @ref{Watches}
+can be considered to be an intermediate model between
+reserved checkouts and unreserved checkouts. When you
+go to edit a file, it is possible to find out who else
+is editing it. And rather than having the system
+simply forbid both people editing the file, it can tell
+you what the situation is and let you figure out
+whether it is a problem in that particular case or not.
+Therefore, for some groups watches can be
+considered the best of both the reserved checkout and unreserved
+checkout worlds.
+
+As of @sc{cvs} client and server versions 1.12.10, you may also enable
+advisory locks by putting @samp{edit -c} and @samp{commit -c} in all
+developers' @file{.cvsrc} files. After this is done, @code{cvs edit}
+will fail if there are any other editors, and @code{cvs commit} will
+fail if the committer has not registered to edit the file via @code{cvs edit}.
+This is most effective in conjunction with files checked out read-only by
+default, which may be enabled by turning on watches in the repository or by
+putting @samp{cvs -r} in all @file{.cvsrc} files.
+
+
+@c ---------------------------------------------------------------------
+@node Revision management
+@chapter Revision management
+@cindex Revision management
+
+@c -- This chapter could be expanded a lot.
+@c -- Experiences are very welcome!
+
+If you have read this far, you probably have a pretty
+good grasp on what @sc{cvs} can do for you. This
+chapter talks a little about things that you still have
+to decide.
+
+If you are doing development on your own using @sc{cvs}
+you could probably skip this chapter. The questions
+this chapter takes up become more important when more
+than one person is working in a repository.
+
+@menu
+* When to commit:: Some discussion on the subject
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node When to commit
+@section When to commit?
+@cindex When to commit
+@cindex Committing, when to
+@cindex Policy
+
+Your group should decide which policy to use regarding
+commits. Several policies are possible, and as your
+experience with @sc{cvs} grows you will probably find
+out what works for you.
+
+If you commit files too quickly you might commit files
+that do not even compile. If your partner updates his
+working sources to include your buggy file, he will be
+unable to compile the code. On the other hand, other
+persons will not be able to benefit from the
+improvements you make to the code if you commit very
+seldom, and conflicts will probably be more common.
+
+It is common to only commit files after making sure
+that they can be compiled. Some sites require that the
+files pass a test suite. Policies like this can be
+enforced using the commitinfo file
+(@pxref{commitinfo}), but you should think twice before
+you enforce such a convention. By making the
+development environment too controlled it might become
+too regimented and thus counter-productive to the real
+goal, which is to get software written.
+
+@c ---------------------------------------------------------------------
+@node Keyword substitution
+@chapter Keyword substitution
+@cindex Keyword substitution
+@cindex Keyword expansion
+@cindex Identifying files
+
+@comment Be careful when editing this chapter.
+@comment Remember that this file is kept under
+@comment version control, so we must not accidentally
+@comment include a valid keyword in the running text.
+
+As long as you edit source files inside a working
+directory you can always find out the state of
+your files via @samp{cvs status} and @samp{cvs log}.
+But as soon as you export the files from your
+development environment it becomes harder to identify
+which revisions they are.
+
+@sc{cvs} can use a mechanism known as @dfn{keyword
+substitution} (or @dfn{keyword expansion}) to help
+identifying the files. Embedded strings of the form
+@code{$@var{keyword}$} and
+@code{$@var{keyword}:@dots{}$} in a file are replaced
+with strings of the form
+@code{$@var{keyword}:@var{value}$} whenever you obtain
+a new revision of the file.
+
+@menu
+* Keyword list:: Keywords
+* Using keywords:: Using keywords
+* Avoiding substitution:: Avoiding substitution
+* Substitution modes:: Substitution modes
+* Configuring keyword expansion:: Configuring keyword expansion
+* Log keyword:: Problems with the $@splitrcskeyword{Log}$ keyword.
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Keyword list
+@section Keyword List
+@cindex Keyword List
+
+@c FIXME: need some kind of example here I think,
+@c perhaps in a
+@c "Keyword intro" node. The intro in the "Keyword
+@c substitution" node itself seems OK, but to launch
+@c into a list of the keywords somehow seems too abrupt.
+
+This is a list of the keywords:
+
+@table @code
+@cindex Author keyword
+@item $@splitrcskeyword{Author}$
+The login name of the user who checked in the revision.
+
+@cindex CVSHeader keyword
+@item $@splitrcskeyword{CVSHeader}$
+A standard header (similar to $@splitrcskeyword{Header}$, but with
+the CVS root stripped off). It contains the relative
+pathname of the @sc{rcs} file to the CVS root, the
+revision number, the date (UTC), the author, the state,
+and the locker (if locked). Files will normally never
+be locked when you use @sc{cvs}.
+
+Note that this keyword has only been recently
+introduced to @sc{cvs} and may cause problems with
+existing installations if $@splitrcskeyword{CVSHeader}$ is already
+in the files for a different purpose. This keyword may
+be excluded using the @code{KeywordExpand=eCVSHeader}
+in the @file{CVSROOT/config} file.
+See @ref{Configuring keyword expansion} for more details.
+
+@cindex Date keyword
+@item $@splitrcskeyword{Date}$
+The date and time (UTC) the revision was checked in.
+
+@cindex Header keyword
+@item $@splitrcskeyword{Header}$
+A standard header containing the full pathname of the
+@sc{rcs} file, the revision number, the date (UTC), the
+author, the state, and the locker (if locked). Files
+will normally never be locked when you use @sc{cvs}.
+
+@cindex Id keyword
+@item $@splitrcskeyword{Id}$
+Same as @code{$@splitrcskeyword{Header}$}, except that the @sc{rcs}
+filename is without a path.
+
+@cindex Name keyword
+@item $@splitrcskeyword{Name}$
+Tag name used to check out this file. The keyword is
+expanded only if one checks out with an explicit tag
+name. For example, when running the command @code{cvs
+co -r first}, the keyword expands to @samp{Name: first}.
+
+@cindex Locker keyword
+@item $@splitrcskeyword{Locker}$
+The login name of the user who locked the revision
+(empty if not locked, which is the normal case unless
+@code{cvs admin -l} is in use).
+
+@cindex Log keyword
+@cindex MaxCommentLeaderLength
+@cindex UseArchiveCommentLeader
+@cindex Log keyword, configuring substitution behavior
+@item $@splitrcskeyword{Log}$
+The log message supplied during commit, preceded by a
+header containing the @sc{rcs} filename, the revision
+number, the author, and the date (UTC). Existing log
+messages are @emph{not} replaced. Instead, the new log
+message is inserted after @code{$@splitrcskeyword{Log}:@dots{}$}.
+By default, each new line is prefixed with the same string which
+precedes the @code{$@splitrcskeyword{Log}$} keyword, unless it exceeds the
+@code{MaxCommentLeaderLength} set in @file{CVSROOT/config}.
+
+For example, if the file contains:
+
+@example
+ /* Here is what people have been up to:
+ *
+ * $@splitrcskeyword{Log}: frob.c,v $
+ * Revision 1.1 1997/01/03 14:23:51 joe
+ * Add the superfrobnicate option
+ *
+ */
+@end example
+
+@noindent
+then additional lines which are added when expanding
+the @code{$@splitrcskeyword{Log}$} keyword will be preceded by @samp{ * }.
+Unlike previous versions of @sc{cvs} and @sc{rcs}, the
+@dfn{comment leader} from the @sc{rcs} file is not used.
+The @code{$@splitrcskeyword{Log}$} keyword is useful for
+accumulating a complete change log in a source file,
+but for several reasons it can be problematic.
+
+If the prefix of the @code{$@splitrcskeyword{Log}$} keyword turns out to be
+longer than @code{MaxCommentLeaderLength}, CVS will skip expansion of this
+keyword unless @code{UseArchiveCommentLeader} is also set in
+@file{CVSROOT/config} and a @samp{comment leader} is set in the RCS archive
+file, in which case the comment leader will be used instead. For more on
+setting the comment leader in the RCS archive file, @xref{admin}. For more
+on configuring the default @code{$@splitrcskeyword{Log}$} substitution
+behavior, @xref{config}.
+
+@xref{Log keyword}.
+
+@cindex RCSfile keyword
+@item $@splitrcskeyword{RCSfile}$
+The name of the RCS file without a path.
+
+@cindex Revision keyword
+@item $@splitrcskeyword{Revision}$
+The revision number assigned to the revision.
+
+@cindex Source keyword
+@item $@splitrcskeyword{Source}$
+The full pathname of the RCS file.
+
+@cindex State keyword
+@item $@splitrcskeyword{State}$
+The state assigned to the revision. States can be
+assigned with @code{cvs admin -s}---see @ref{admin options}.
+
+@cindex Local keyword
+@item Local keyword
+The @code{LocalKeyword} option in the @file{CVSROOT/config} file
+may be used to specify a local keyword which is to be
+used as an alias for one of the keywords: $@splitrcskeyword{Id}$,
+$@splitrcskeyword{Header}$, or $@splitrcskeyword{CVSHeader}$. For
+example, if the @file{CVSROOT/config} file contains
+a line with @code{LocalKeyword=MYBSD=CVSHeader}, then a
+file with the local keyword $@splitrcskeyword{MYBSD}$ will be
+expanded as if it were a $@splitrcskeyword{CVSHeader}$ keyword. If
+the src/frob.c file contained this keyword, it might
+look something like this:
+
+@example
+ /*
+ * $@splitrcskeyword{MYBSD}: src/frob.c,v 1.1 2003/05/04 09:27:45 john Exp $
+ */
+@end example
+
+Many repositories make use of a such a ``local
+keyword'' feature. An old patch to @sc{cvs} provided
+the @code{LocalKeyword} feature using a @code{tag=}
+option and called this the ``custom tag'' or ``local
+tag'' feature. It was used in conjunction with the
+what they called the @code{tagexpand=} option. In
+@sc{cvs} this other option is known as the
+@code{KeywordExpand} option.
+See @ref{Configuring keyword expansion} for more
+details.
+
+Examples from popular projects include:
+$@splitrcskeyword{FreeBSD}$, $@splitrcskeyword{NetBSD}$,
+$@splitrcskeyword{OpenBSD}$, $@splitrcskeyword{XFree86}$,
+$@splitrcskeyword{Xorg}$.
+
+The advantage of this is that you can include your
+local version information in a file using this local
+keyword without disrupting the upstream version
+information (which may be a different local keyword or
+a standard keyword). Allowing bug reports and the like
+to more properly identify the source of the original
+bug to the third-party and reducing the number of
+conflicts that arise during an import of a new version.
+
+All keyword expansion except the local keyword may be
+disabled using the @code{KeywordExpand} option in
+the @file{CVSROOT/config} file---see
+@ref{Configuring keyword expansion} for more details.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Using keywords
+@section Using keywords
+
+To include a keyword string you simply include the
+relevant text string, such as @code{$@splitrcskeyword{Id}$}, inside the
+file, and commit the file. @sc{cvs} will automatically (Or,
+more accurately, as part of the update run that
+automatically happens after a commit.)
+expand the string as part of the commit operation.
+
+It is common to embed the @code{$@splitrcskeyword{Id}$} string in
+the source files so that it gets passed through to
+generated files. For example, if you are managing
+computer program source code, you might include a
+variable which is initialized to contain that string.
+Or some C compilers may provide a @code{#pragma ident}
+directive. Or a document management system might
+provide a way to pass a string through to generated
+files.
+
+@c Would be nice to give an example, but doing this in
+@c portable C is not possible and the problem with
+@c picking any one language (VMS HELP files, Ada,
+@c troff, whatever) is that people use CVS for all
+@c kinds of files.
+
+@cindex Ident (shell command)
+The @code{ident} command (which is part of the @sc{rcs}
+package) can be used to extract keywords and their
+values from a file. This can be handy for text files,
+but it is even more useful for extracting keywords from
+binary files.
+
+@example
+$ ident samp.c
+samp.c:
+ $@splitrcskeyword{Id}: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+$ gcc samp.c
+$ ident a.out
+a.out:
+ $@splitrcskeyword{Id}: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+@end example
+
+@cindex What (shell command)
+S@sc{ccs} is another popular revision control system.
+It has a command, @code{what}, which is very similar to
+@code{ident} and used for the same purpose. Many sites
+without @sc{rcs} have @sc{sccs}. Since @code{what}
+looks for the character sequence @code{@@(#)} it is
+easy to include keywords that are detected by either
+command. Simply prefix the keyword with the
+magic @sc{sccs} phrase, like this:
+
+@example
+static char *id="@@(#) $@splitrcskeyword{Id}: ab.c,v 1.5 1993/10/19 14:57:32 ceder Exp $";
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Avoiding substitution
+@section Avoiding substitution
+
+Keyword substitution has its disadvantages. Sometimes
+you might want the literal text string
+@samp{$@splitrcskeyword{Author}$} to appear inside a file without
+@sc{cvs} interpreting it as a keyword and expanding it
+into something like @samp{$@splitrcskeyword{Author}: ceder $}.
+
+There is unfortunately no way to selectively turn off
+keyword substitution. You can use @samp{-ko}
+(@pxref{Substitution modes}) to turn off keyword
+substitution entirely.
+
+In many cases you can avoid using keywords in
+the source, even though they appear in the final
+product. For example, the source for this manual
+contains @samp{$@@asis@{@}Author$} whenever the text
+@samp{$@splitrcskeyword{Author}$} should appear. In @code{nroff}
+and @code{troff} you can embed the null-character
+@code{\&} inside the keyword for a similar effect.
+
+It is also possible to specify an explicit list of
+keywords to include or exclude using the
+@code{KeywordExpand} option in the
+@file{CVSROOT/config} file--see @ref{Configuring keyword expansion}
+for more details. This feature is intended primarily
+for use with the @code{LocalKeyword} option--see
+@ref{Keyword list}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Substitution modes
+@section Substitution modes
+@cindex Keyword substitution, changing modes
+@cindex -k (keyword substitution)
+@cindex Kflag
+
+@c FIXME: This could be made more coherent, by expanding it
+@c with more examples or something.
+Each file has a stored default substitution mode, and
+each working directory copy of a file also has a
+substitution mode. The former is set by the @samp{-k}
+option to @code{cvs add} and @code{cvs admin}; the
+latter is set by the @samp{-k} or @samp{-A} options to @code{cvs
+checkout} or @code{cvs update}.
+@code{cvs diff} and @code{cvs rdiff} also
+have @samp{-k} options.
+For some examples,
+see @ref{Binary files}, and @ref{Merging and keywords}.
+@c The fact that -A is overloaded to mean both reset
+@c sticky options and reset sticky tags/dates is
+@c somewhat questionable. Perhaps there should be
+@c separate options to reset sticky options (e.g. -k
+@c A") and tags/dates (someone suggested -r HEAD could
+@c do this instead of setting a sticky tag of "HEAD"
+@c as in the status quo but I haven't thought much
+@c about that idea. Of course -r .reset or something
+@c could be coined if this needs to be a new option).
+@c On the other hand, having -A mean "get things back
+@c into the state after a fresh checkout" has a certain
+@c appeal, and maybe there is no sufficient reason for
+@c creeping featurism in this area.
+
+The modes available are:
+
+@table @samp
+@item -kkv
+Generate keyword strings using the default form, e.g.
+@code{$@splitrcskeyword{Revision}: 5.7 $} for the @code{Revision}
+keyword.
+
+@item -kkvl
+Like @samp{-kkv}, except that a locker's name is always
+inserted if the given revision is currently locked.
+The locker's name is only relevant if @code{cvs admin
+-l} is in use.
+
+@item -kk
+Generate only keyword names in keyword strings; omit
+their values. For example, for the @code{Revision}
+keyword, generate the string @code{$@splitrcskeyword{Revision}$}
+instead of @code{$@splitrcskeyword{Revision}: 5.7 $}. This option
+is useful to ignore differences due to keyword
+substitution when comparing different revisions of a
+file (@pxref{Merging and keywords}).
+
+@item -ko
+Generate the old keyword string, present in the working
+file just before it was checked in. For example, for
+the @code{Revision} keyword, generate the string
+@code{$@splitrcskeyword{Revision}: 1.1 $} instead of
+@code{$@splitrcskeyword{Revision}: 5.7 $} if that is how the
+string appeared when the file was checked in.
+
+@item -kb
+Like @samp{-ko}, but also inhibit conversion of line
+endings between the canonical form in which they are
+stored in the repository (linefeed only), and the form
+appropriate to the operating system in use on the
+client. For systems, like unix, which use linefeed
+only to terminate lines, this is very similar to
+@samp{-ko}. For more information on binary files, see
+@ref{Binary files}. In @sc{cvs} version 1.12.2 and later
+@samp{-kb}, as set by @code{cvs add}, @code{cvs admin}, or
+@code{cvs import} may not be overridden by a @samp{-k} option
+specified on the command line.
+
+@item -kv
+Generate only keyword values for keyword strings. For
+example, for the @code{Revision} keyword, generate the string
+@code{5.7} instead of @code{$@splitrcskeyword{Revision}: 5.7 $}.
+This can help generate files in programming languages
+where it is hard to strip keyword delimiters like
+@code{$@splitrcskeyword{Revision}: $} from a string. However,
+further keyword substitution cannot be performed once
+the keyword names are removed, so this option should be
+used with care.
+
+One often would like to use @samp{-kv} with @code{cvs
+export}---@pxref{export}. But be aware that doesn't
+handle an export containing binary files correctly.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Configuring keyword expansion
+@section Configuring Keyword Expansion
+@cindex Configuring keyword expansion
+
+In a repository that includes third-party software on
+vendor branches, it is sometimes helpful to configure
+CVS to use a local keyword instead of the standard
+$@splitrcskeyword{Id}$ or $@splitrcskeyword{Header}$ keywords. Examples from
+real projects include $@splitrcskeyword{Xorg}$, $@splitrcskeyword{XFree86}$,
+$@splitrcskeyword{FreeBSD}$, $@splitrcskeyword{NetBSD}$,
+$@splitrcskeyword{OpenBSD}$, and even $@splitrcskeyword{dotat}$.
+The advantage of this is that
+you can include your local version information in a
+file using this local keyword (sometimes called a
+``custom tag'' or a ``local tag'') without disrupting
+the upstream version information (which may be a
+different local keyword or a standard keyword). In
+these cases, it is typically desirable to disable the
+expansion of all keywords except the configured local
+keyword.
+
+The @code{KeywordExpand} option in the
+@file{CVSROOT/config} file is intended to allow for the
+either the explicit exclusion of a keyword or list of
+keywords, or for the explicit inclusion of a keyword or
+a list of keywords. This list may include the
+@code{LocalKeyword} that has been configured.
+
+The @code{KeywordExpand} option is followed by
+@code{=} and the next character may either be @code{i}
+to start an inclusion list or @code{e} to start an
+exclusion list. If the following lines were added to
+the @file{CVSROOT/config} file:
+
+@example
+ # Add a "MyBSD" keyword and restrict keyword
+ # expansion
+ LocalKeyword=MyBSD=CVSHeader
+ KeywordExpand=iMyBSD
+@end example
+
+then only the $@splitrcskeyword{MyBSD}$ keyword would be expanded.
+A list may be used. The this example:
+
+@example
+ # Add a "MyBSD" keyword and restrict keyword
+ # expansion to the MyBSD, Name and Date keywords.
+ LocalKeyword=MyBSD=CVSHeader
+ KeywordExpand=iMyBSD,Name,Date
+@end example
+
+would allow $@splitrcskeyword{MyBSD}$, $@splitrcskeyword{Name}$, and
+$@splitrcskeyword{Date}$ to be expanded.
+
+It is also possible to configure an exclusion list
+using the following:
+
+@example
+ # Do not expand the non-RCS keyword CVSHeader
+ KeywordExpand=eCVSHeader
+@end example
+
+This allows @sc{cvs} to ignore the recently introduced
+$@splitrcskeyword{CVSHeader}$ keyword and retain all of the
+others. The exclusion entry could also contain the
+standard RCS keyword list, but this could be confusing
+to users that expect RCS keywords to be expanded, so
+care should be taken to properly set user expectations
+for a repository that is configured in that manner.
+
+If there is a desire to not have any RCS keywords
+expanded and not use the @code{-ko} flags everywhere,
+an administrator may disable all keyword expansion
+using the @file{CVSROOT/config} line:
+
+@example
+ # Do not expand any RCS keywords
+ KeywordExpand=i
+@end example
+
+this could be confusing to users that expect RCS
+keywords like $@splitrcskeyword{Id}$ to be expanded properly,
+so care should be taken to properly set user
+expectations for a repository so configured.
+
+It should be noted that a patch to provide both the
+@code{KeywordExpand} and @code{LocalKeyword} features
+has been around a long time. However, that patch
+implemented these features using @code{tag=} and
+@code{tagexpand=} keywords and those keywords are NOT
+recognized.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Log keyword
+@section Problems with the $@splitrcskeyword{Log}$ keyword.
+
+The @code{$@splitrcskeyword{Log}$} keyword is somewhat
+controversial. As long as you are working on your
+development system the information is easily accessible
+even if you do not use the @code{$@splitrcskeyword{Log}$}
+keyword---just do a @code{cvs log}. Once you export
+the file the history information might be useless
+anyhow.
+
+A more serious concern is that @sc{cvs} is not good at
+handling @code{$@splitrcskeyword{Log}$} entries when a branch is
+merged onto the main trunk. Conflicts often result
+from the merging operation.
+@c Might want to check whether the CVS implementation
+@c of RCS_merge has this problem the same way rcsmerge
+@c does. I would assume so....
+
+People also tend to "fix" the log entries in the file
+(correcting spelling mistakes and maybe even factual
+errors). If that is done the information from
+@code{cvs log} will not be consistent with the
+information inside the file. This may or may not be a
+problem in real life.
+
+It has been suggested that the @code{$@splitrcskeyword{Log}$}
+keyword should be inserted @emph{last} in the file, and
+not in the files header, if it is to be used at all.
+That way the long list of change messages will not
+interfere with everyday source file browsing.
+
+@c ---------------------------------------------------------------------
+@node Tracking sources
+@chapter Tracking third-party sources
+@cindex Third-party sources
+@cindex Tracking sources
+
+@c FIXME: Need discussion of added and removed files.
+@c FIXME: This doesn't really adequately introduce the
+@c concepts of "vendor" and "you". They don't *have*
+@c to be separate organizations or separate people.
+@c We want a description which is somewhat more based on
+@c the technical issues of which sources go where, but
+@c also with enough examples of how this relates to
+@c relationships like customer-supplier, developer-QA,
+@c maintainer-contributor, or whatever, to make it
+@c seem concrete.
+If you modify a program to better fit your site, you
+probably want to include your modifications when the next
+release of the program arrives. @sc{cvs} can help you with
+this task.
+
+@cindex Vendor
+@cindex Vendor branch
+@cindex Branch, vendor-
+In the terminology used in @sc{cvs}, the supplier of the
+program is called a @dfn{vendor}. The unmodified
+distribution from the vendor is checked in on its own
+branch, the @dfn{vendor branch}. @sc{cvs} reserves branch
+1.1.1 for this use.
+
+When you modify the source and commit it, your revision
+will end up on the main trunk. When a new release is
+made by the vendor, you commit it on the vendor branch
+and copy the modifications onto the main trunk.
+
+Use the @code{import} command to create and update
+the vendor branch. When you import a new file,
+(usually) the vendor branch is made the `head' revision, so
+anyone that checks out a copy of the file gets that
+revision. When a local modification is committed it is
+placed on the main trunk, and made the `head'
+revision.
+
+@menu
+* First import:: Importing for the first time
+* Update imports:: Updating with the import command
+* Reverting local changes:: Reverting to the latest vendor release
+* Binary files in imports:: Binary files require special handling
+* Keywords in imports:: Keyword substitution might be undesirable
+* Multiple vendor branches:: What if you get sources from several places?
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node First import
+@section Importing for the first time
+@cindex Importing modules
+
+@c Should mention naming conventions for vendor tags,
+@c release tags, and perhaps directory names.
+Use the @code{import} command to check in the sources
+for the first time. When you use the @code{import}
+command to track third-party sources, the @dfn{vendor
+tag} and @dfn{release tags} are useful. The
+@dfn{vendor tag} is a symbolic name for the branch
+(which is always 1.1.1, unless you use the @samp{-b
+@var{branch}} flag---see @ref{Multiple vendor branches}.). The
+@dfn{release tags} are symbolic names for a particular
+release, such as @samp{FSF_0_04}.
+
+@c I'm not completely sure this belongs here. But
+@c we need to say it _somewhere_ reasonably obvious; it
+@c is a common misconception among people first learning CVS
+Note that @code{import} does @emph{not} change the
+directory in which you invoke it. In particular, it
+does not set up that directory as a @sc{cvs} working
+directory; if you want to work with the sources import
+them first and then check them out into a different
+directory (@pxref{Getting the source}).
+
+@cindex wdiff (import example)
+Suppose you have the sources to a program called
+@code{wdiff} in a directory @file{wdiff-0.04},
+and are going to make private modifications that you
+want to be able to use even when new releases are made
+in the future. You start by importing the source to
+your repository:
+
+@example
+$ cd wdiff-0.04
+$ cvs import -m "Import of FSF v. 0.04" fsf/wdiff FSF_DIST WDIFF_0_04
+@end example
+
+The vendor tag is named @samp{FSF_DIST} in the above
+example, and the only release tag assigned is
+@samp{WDIFF_0_04}.
+@c FIXME: Need to say where fsf/wdiff comes from.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Update imports
+@section Updating with the import command
+
+When a new release of the source arrives, you import it into the
+repository with the same @code{import} command that you used to set up
+the repository in the first place. The only difference is that you
+specify a different release tag this time:
+
+@example
+$ tar xfz wdiff-0.05.tar.gz
+$ cd wdiff-0.05
+$ cvs import -m "Import of FSF v. 0.05" fsf/wdiff FSF_DIST WDIFF_0_05
+@end example
+
+@strong{WARNING: If you use a release tag that already exists in one of the
+repository archives, files removed by an import may not be detected.}
+
+For files that have not been modified locally, the newly created
+revision becomes the head revision. If you have made local
+changes, @code{import} will warn you that you must merge the changes
+into the main trunk, and tell you to use @samp{checkout -j} to do so:
+
+@c FIXME: why "wdiff" here and "fsf/wdiff" in the
+@c "import"? I think the assumption is that one has
+@c "wdiff fsf/wdiff" or some such in modules, but it
+@c would be better to not use modules in this example.
+@example
+$ cvs checkout -jFSF_DIST:yesterday -jFSF_DIST wdiff
+@end example
+
+@noindent
+The above command will check out the latest revision of
+@samp{wdiff}, merging the changes made on the vendor branch @samp{FSF_DIST}
+since yesterday into the working copy. If any conflicts arise during
+the merge they should be resolved in the normal way (@pxref{Conflicts
+example}). Then, the modified files may be committed.
+
+However, it is much better to use the two release tags rather than using
+a date on the branch as suggested above:
+
+@example
+$ cvs checkout -jWDIFF_0_04 -jWDIFF_0_05 wdiff
+@end example
+
+@noindent
+The reason this is better is that
+using a date, as suggested above, assumes that you do
+not import more than one release of a product per day.
+More importantly, using the release tags allows @sc{cvs} to detect files
+that were removed between the two vendor releases and mark them for
+removal. Since @code{import} has no way to detect removed files, you
+should do a merge like this even if @code{import} doesn't tell you to.
+
+@node Reverting local changes
+@section Reverting to the latest vendor release
+
+You can also revert local changes completely and return
+to the latest vendor release by changing the `head'
+revision back to the vendor branch on all files. For
+example, if you have a checked-out copy of the sources
+in @file{~/work.d/wdiff}, and you want to revert to the
+vendor's version for all the files in that directory,
+you would type:
+
+@example
+$ cd ~/work.d/wdiff
+$ cvs admin -bFSF_DIST .
+@end example
+
+@noindent
+You must specify the @samp{-bFSF_DIST} without any space
+after the @samp{-b}. @xref{admin options}.
+
+@node Binary files in imports
+@section How to handle binary files with cvs import
+
+Use the @samp{-k} wrapper option to tell import which
+files are binary. @xref{Wrappers}.
+
+@node Keywords in imports
+@section How to handle keyword substitution with cvs import
+
+The sources which you are importing may contain
+keywords (@pxref{Keyword substitution}). For example,
+the vendor may use @sc{cvs} or some other system
+which uses similar keyword expansion syntax. If you
+just import the files in the default fashion, then
+the keyword expansions supplied by the vendor will
+be replaced by keyword expansions supplied by your
+own copy of @sc{cvs}. It may be more convenient to
+maintain the expansions supplied by the vendor, so
+that this information can supply information about
+the sources that you imported from the vendor.
+
+To maintain the keyword expansions supplied by the
+vendor, supply the @samp{-ko} option to @code{cvs
+import} the first time you import the file.
+This will turn off keyword expansion
+for that file entirely, so if you want to be more
+selective you'll have to think about what you want
+and use the @samp{-k} option to @code{cvs update} or
+@code{cvs admin} as appropriate.
+@c Supplying -ko to import if the file already existed
+@c has no effect. Not clear to me whether it should
+@c or not.
+
+@node Multiple vendor branches
+@section Multiple vendor branches
+
+All the examples so far assume that there is only one
+vendor from which you are getting sources. In some
+situations you might get sources from a variety of
+places. For example, suppose that you are dealing with
+a project where many different people and teams are
+modifying the software. There are a variety of ways to
+handle this, but in some cases you have a bunch of
+source trees lying around and what you want to do more
+than anything else is just to all put them in @sc{cvs} so
+that you at least have them in one place.
+
+For handling situations in which there may be more than
+one vendor, you may specify the @samp{-b} option to
+@code{cvs import}. It takes as an argument the vendor
+branch to import to. The default is @samp{-b 1.1.1}.
+
+For example, suppose that there are two teams, the red
+team and the blue team, that are sending you sources.
+You want to import the red team's efforts to branch
+1.1.1 and use the vendor tag RED. You want to import
+the blue team's efforts to branch 1.1.3 and use the
+vendor tag BLUE. So the commands you might use are:
+
+@example
+$ cvs import dir RED RED_1-0
+$ cvs import -b 1.1.3 dir BLUE BLUE_1-5
+@end example
+
+Note that if your vendor tag does not match your
+@samp{-b} option, @sc{cvs} will not detect this case! For
+example,
+
+@example
+$ cvs import -b 1.1.3 dir RED RED_1-0
+@end example
+
+@noindent
+Be careful; this kind of mismatch is sure to sow
+confusion or worse. I can't think of a useful purpose
+for the ability to specify a mismatch here, but if you
+discover such a use, don't. @sc{cvs} is likely to make this
+an error in some future release.
+
+@c Probably should say more about the semantics of
+@c multiple branches. What about the default branch?
+@c What about joining (perhaps not as useful with
+@c multiple branches, or perhaps it is. Either way
+@c should be mentioned).
+
+@c I'm not sure about the best location for this. In
+@c one sense, it might belong right after we've introduced
+@c CVS's basic version control model, because people need
+@c to figure out builds right away. The current location
+@c is based on the theory that it kind of akin to the
+@c "Revision management" section.
+@node Builds
+@chapter How your build system interacts with CVS
+@cindex Builds
+@cindex make
+
+As mentioned in the introduction, @sc{cvs} does not
+contain software for building your software from source
+code. This section describes how various aspects of
+your build system might interact with @sc{cvs}.
+
+@c Is there a way to discuss this without reference to
+@c tools other than CVS? I'm not sure there is; I
+@c wouldn't think that people who learn CVS first would
+@c even have this concern.
+One common question, especially from people who are
+accustomed to @sc{rcs}, is how to make their build get
+an up to date copy of the sources. The answer to this
+with @sc{cvs} is two-fold. First of all, since
+@sc{cvs} itself can recurse through directories, there
+is no need to modify your @file{Makefile} (or whatever
+configuration file your build tool uses) to make sure
+each file is up to date. Instead, just use two
+commands, first @code{cvs -q update} and then
+@code{make} or whatever the command is to invoke your
+build tool. Secondly, you do not necessarily
+@emph{want} to get a copy of a change someone else made
+until you have finished your own work. One suggested
+approach is to first update your sources, then
+implement, build and
+test the change you were thinking of, and then commit
+your sources (updating first if necessary). By
+periodically (in between changes, using the approach
+just described) updating your entire tree, you ensure
+that your sources are sufficiently up to date.
+
+@cindex Bill of materials
+One common need is to record which versions of which
+source files went into a particular build. This kind
+of functionality is sometimes called @dfn{bill of
+materials} or something similar. The best way to do
+this with @sc{cvs} is to use the @code{tag} command to
+record which versions went into a given build
+(@pxref{Tags}).
+
+Using @sc{cvs} in the most straightforward manner
+possible, each developer will have a copy of the entire
+source tree which is used in a particular build. If
+the source tree is small, or if developers are
+geographically dispersed, this is the preferred
+solution. In fact one approach for larger projects is
+to break a project down into smaller
+@c I say subsystem instead of module because they may or
+@c may not use the modules file.
+separately-compiled subsystems, and arrange a way of
+releasing them internally so that each developer need
+check out only those subsystems which they are
+actively working on.
+
+Another approach is to set up a structure which allows
+developers to have their own copies of some files, and
+for other files to access source files from a central
+location. Many people have come up with some such a
+@c two such people are paul@sander.cupertino.ca.us (for
+@c a previous employer)
+@c and gunnar.tornblom@se.abb.com (spicm and related tools),
+@c but as far as I know
+@c no one has nicely packaged or released such a system (or
+@c instructions for constructing one).
+system using features such as the symbolic link feature
+found in many operating systems, or the @code{VPATH}
+feature found in many versions of @code{make}. One build
+tool which is designed to help with this kind of thing
+is Odin (see
+@code{ftp://ftp.cs.colorado.edu/pub/distribs/odin}).
+@c Should we be saying more about Odin? Or how you use
+@c it with CVS? Also, the Prime Time Freeware for Unix
+@c disk (see http://www.ptf.com/) has Odin (with a nice
+@c paragraph summarizing it on the web), so that might be a
+@c semi-"official" place to point people.
+@c
+@c Of course, many non-CVS systems have this kind of
+@c functionality, for example OSF's ODE
+@c (http://www.osf.org/ode/) or mk
+@c (http://www.grin.net/~pzi/mk-3.18.4.docs/mk_toc.html
+@c He has changed providers in the past; a search engine search
+@c for "Peter Ziobrzynski" probably won't get too many
+@c spurious hits :-). A more stable URL might be
+@c ftp://ftp.uu.net/pub/cmvc/mk). But I'm not sure
+@c there is any point in mentioning them here unless they
+@c can work with CVS.
+
+@c ---------------------------------------------------------------------
+@node Special Files
+@chapter Special Files
+
+@cindex Special files
+@cindex Device nodes
+@cindex Ownership, saving in CVS
+@cindex Permissions, saving in CVS
+@cindex Hard links
+@cindex Symbolic links
+
+In normal circumstances, @sc{cvs} works only with regular
+files. Every file in a project is assumed to be
+persistent; it must be possible to open, read and close
+them; and so on. @sc{cvs} also ignores file permissions and
+ownerships, leaving such issues to be resolved by the
+developer at installation time. In other words, it is
+not possible to "check in" a device into a repository;
+if the device file cannot be opened, @sc{cvs} will refuse to
+handle it. Files also lose their ownerships and
+permissions during repository transactions.
+
+@ignore
+If the configuration variable @code{PreservePermissions}
+(@pxref{config}) is set in the repository, @sc{cvs} will
+save the following file characteristics in the
+repository:
+
+@itemize @bullet
+@item user and group ownership
+@item permissions
+@item major and minor device numbers
+@item symbolic links
+@item hard link structure
+@end itemize
+
+Using the @code{PreservePermissions} option affects the
+behavior of @sc{cvs} in several ways. First, some of the
+new operations supported by @sc{cvs} are not accessible to
+all users. In particular, file ownership and special
+file characteristics may only be changed by the
+superuser. When the @code{PreservePermissions}
+configuration variable is set, therefore, users will
+have to be `root' in order to perform @sc{cvs} operations.
+
+When @code{PreservePermissions} is in use, some @sc{cvs}
+operations (such as @samp{cvs status}) will not
+recognize a file's hard link structure, and so will
+emit spurious warnings about mismatching hard links.
+The reason is that @sc{cvs}'s internal structure does not
+make it easy for these operations to collect all the
+necessary data about hard links, so they check for file
+conflicts with inaccurate data.
+
+A more subtle difference is that @sc{cvs} considers a file
+to have changed only if its contents have changed
+(specifically, if the modification time of the working
+file does not match that of the repository's file).
+Therefore, if only the permissions, ownership or hard
+linkage have changed, or if a device's major or minor
+numbers have changed, @sc{cvs} will not notice. In order to
+commit such a change to the repository, you must force
+the commit with @samp{cvs commit -f}. This also means
+that if a file's permissions have changed and the
+repository file is newer than the working copy,
+performing @samp{cvs update} will silently change the
+permissions on the working copy.
+
+Changing hard links in a @sc{cvs} repository is particularly
+delicate. Suppose that file @file{foo} is linked to
+file @file{old}, but is later relinked to file
+@file{new}. You can wind up in the unusual situation
+where, although @file{foo}, @file{old} and @file{new}
+have all had their underlying link patterns changed,
+only @file{foo} and @file{new} have been modified, so
+@file{old} is not considered a candidate for checking
+in. It can be very easy to produce inconsistent
+results this way. Therefore, we recommend that when it
+is important to save hard links in a repository, the
+prudent course of action is to @code{touch} any file
+whose linkage or status has changed since the last
+checkin. Indeed, it may be wise to @code{touch *}
+before each commit in a directory with complex hard
+link structures.
+
+It is worth noting that only regular files may
+be merged, for reasons that hopefully are obvious. If
+@samp{cvs update} or @samp{cvs checkout -j} attempts to
+merge a symbolic link with a regular file, or two
+device files for different kinds of devices, @sc{cvs} will
+report a conflict and refuse to perform the merge. At
+the same time, @samp{cvs diff} will not report any
+differences between these files, since no meaningful
+textual comparisons can be made on files which contain
+no text.
+
+The @code{PreservePermissions} features do not work
+with client/server @sc{cvs}. Another limitation is
+that hard links must be to other files within the same
+directory; hard links across directories are not
+supported.
+@end ignore
+
+@c ---------------------------------------------------------------------
+@c ----- START MAN 1 -----
+@node CVS commands
+@appendix Guide to CVS commands
+
+This appendix describes the overall structure of
+@sc{cvs} commands, and describes some commands in
+detail (others are described elsewhere; for a quick
+reference to @sc{cvs} commands, @pxref{Invoking CVS}).
+@c The idea is that we want to move the commands which
+@c are described here into the main body of the manual,
+@c in the process reorganizing the manual to be
+@c organized around what the user wants to do, not
+@c organized around CVS commands.
+@c
+@c Note that many users do expect a manual which is
+@c organized by command. At least some users do.
+@c One good addition to the "organized by command"
+@c section (if any) would be "see also" links.
+@c The awk manual might be a good example; it has a
+@c reference manual which is more verbose than Invoking
+@c CVS but probably somewhat less verbose than CVS
+@c Commands.
+
+@menu
+* Structure:: Overall structure of CVS commands
+* Exit status:: Indicating CVS's success or failure
+* ~/.cvsrc:: Default options with the ~/.cvsrc file
+* Global options:: Options you give to the left of cvs_command
+* Common options:: Options you give to the right of cvs_command
+* Date input formats:: Acceptable formats for date specifications
+* admin:: Administration
+* annotate:: What revision modified each line of a file?
+* checkout:: Checkout sources for editing
+* commit:: Check files into the repository
+* diff:: Show differences between revisions
+* export:: Export sources from CVS, similar to checkout
+* history:: Show status of files and users
+* import:: Import sources into CVS, using vendor branches
+* log:: Show log messages for files
+* ls & rls:: List files in the repository
+* rdiff:: 'patch' format diffs between releases
+* release:: Indicate that a directory is no longer in use
+* server & pserver:: Act as a server for a client on stdin/stdout
+* update:: Bring work tree in sync with repository
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Structure
+@appendixsec Overall structure of CVS commands
+@cindex Structure
+@cindex CVS command structure
+@cindex Command structure
+@cindex Format of CVS commands
+
+The overall format of all @sc{cvs} commands is:
+
+@example
+cvs [ cvs_options ] cvs_command [ command_options ] [ command_args ]
+@end example
+
+@table @code
+@item cvs
+The name of the @sc{cvs} program.
+
+@item cvs_options
+Some options that affect all sub-commands of @sc{cvs}. These are
+described below.
+
+@item cvs_command
+One of several different sub-commands. Some of the commands have
+aliases that can be used instead; those aliases are noted in the
+reference manual for that command. There are only two situations
+where you may omit @samp{cvs_command}: @samp{cvs -H} elicits a
+list of available commands, and @samp{cvs -v} displays version
+information on @sc{cvs} itself.
+
+@item command_options
+Options that are specific for the command.
+
+@item command_args
+Arguments to the commands.
+@end table
+
+There is unfortunately some confusion between
+@code{cvs_options} and @code{command_options}.
+When given as a @code{cvs_option}, some options only
+affect some of the commands. When given as a
+@code{command_option} it may have a different meaning, and
+be accepted by more commands. In other words, do not
+take the above categorization too seriously. Look at
+the documentation instead.
+
+@node Exit status
+@appendixsec CVS's exit status
+@cindex Exit status, of CVS
+
+@sc{cvs} can indicate to the calling environment whether it
+succeeded or failed by setting its @dfn{exit status}.
+The exact way of testing the exit status will vary from
+one operating system to another. For example in a unix
+shell script the @samp{$?} variable will be 0 if the
+last command returned a successful exit status, or
+greater than 0 if the exit status indicated failure.
+
+If @sc{cvs} is successful, it returns a successful status;
+if there is an error, it prints an error message and
+returns a failure status. The one exception to this is
+the @code{cvs diff} command. It will return a
+successful status if it found no differences, or a
+failure status if there were differences or if there
+was an error. Because this behavior provides no good
+way to detect errors, in the future it is possible that
+@code{cvs diff} will be changed to behave like the
+other @sc{cvs} commands.
+@c It might seem like checking whether cvs -q diff
+@c produces empty or non-empty output can tell whether
+@c there were differences or not. But it seems like
+@c there are cases with output but no differences
+@c (testsuite basica-8b). It is not clear to me how
+@c useful it is for a script to be able to check
+@c whether there were differences.
+@c FIXCVS? In previous versions of CVS, cvs diff
+@c returned 0 for no differences, 1 for differences, or
+@c 2 for errors. Is this behavior worth trying to
+@c bring back (but what does it mean for VMS?)?
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node ~/.cvsrc
+@appendixsec Default options and the ~/.cvsrc file
+@cindex .cvsrc file
+@cindex Option defaults
+
+There are some @code{command_options} that are used so
+often that you might have set up an alias or some other
+means to make sure you always specify that option. One
+example (the one that drove the implementation of the
+@file{.cvsrc} support, actually) is that many people find the
+default output of the @samp{diff} command to be very
+hard to read, and that either context diffs or unidiffs
+are much easier to understand.
+
+The @file{~/.cvsrc} file is a way that you can add
+default options to @code{cvs_commands} within cvs,
+instead of relying on aliases or other shell scripts.
+
+The format of the @file{~/.cvsrc} file is simple. The
+file is searched for a line that begins with the same
+name as the @code{cvs_command} being executed. If a
+match is found, then the remainder of the line is split
+up (at whitespace characters) into separate options and
+added to the command arguments @emph{before} any
+options from the command line.
+
+If a command has two names (e.g., @code{checkout} and
+@code{co}), the official name, not necessarily the one
+used on the command line, will be used to match against
+the file. So if this is the contents of the user's
+@file{~/.cvsrc} file:
+
+@example
+log -N
+diff -uN
+rdiff -u
+update -Pd
+checkout -P
+release -d
+@end example
+
+@noindent
+the command @samp{cvs checkout foo} would have the
+@samp{-P} option added to the arguments, as well as
+@samp{cvs co foo}.
+
+With the example file above, the output from @samp{cvs
+diff foobar} will be in unidiff format. @samp{cvs diff
+-c foobar} will provide context diffs, as usual.
+Getting "old" format diffs would be slightly more
+complicated, because @code{diff} doesn't have an option
+to specify use of the "old" format, so you would need
+@samp{cvs -f diff foobar}.
+
+In place of the command name you can use @code{cvs} to
+specify global options (@pxref{Global options}). For
+example the following line in @file{.cvsrc}
+
+@example
+cvs -z6
+@end example
+
+@noindent
+causes @sc{cvs} to use compression level 6.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Global options
+@appendixsec Global options
+@cindex Options, global
+@cindex Global options
+@cindex Left-hand options
+
+The available @samp{cvs_options} (that are given to the
+left of @samp{cvs_command}) are:
+
+@table @code
+@item --allow-root=@var{rootdir}
+May be invoked multiple times to specify one legal @sc{cvsroot} directory with
+each invocation. Also causes CVS to preparse the configuration file for each
+specified root, which can be useful when configuring write proxies, See
+@ref{Password authentication server} & @ref{Write proxies}.
+
+@cindex Authentication, stream
+@cindex Stream authentication
+@item -a
+Authenticate all communication between the client and
+the server. Only has an effect on the @sc{cvs} client.
+As of this writing, this is only implemented when using
+a GSSAPI connection (@pxref{GSSAPI authenticated}).
+Authentication prevents certain sorts of attacks
+involving hijacking the active @sc{tcp} connection.
+Enabling authentication does not enable encryption.
+
+@cindex RCSBIN, overriding
+@cindex Overriding RCSBIN
+@item -b @var{bindir}
+In @sc{cvs} 1.9.18 and older, this specified that
+@sc{rcs} programs are in the @var{bindir} directory.
+Current versions of @sc{cvs} do not run @sc{rcs}
+programs; for compatibility this option is accepted,
+but it does nothing.
+
+@cindex TMPDIR, environment variable
+@cindex temporary file directory, set via command line
+@cindex temporary file directory, set via environment variable
+@cindex temporary file directory, set via config
+@cindex temporary files, location of
+@item -T @var{tempdir}
+Use @var{tempdir} as the directory where temporary files are
+located.
+
+The @sc{cvs} client and server store temporary files in a temporary directory.
+The path to this temporary directory is set via, in order of precedence:
+
+@itemize @bullet
+@item
+The argument to the global @samp{-T} option.
+
+@item
+The value set for @code{TmpDir} in the config file (server only -
+@pxref{config}).
+
+@item
+The contents of the @code{$TMPDIR} environment variable (@code{%TMPDIR%} on
+Windows - @pxref{Environment variables}).
+
+@item
+/tmp
+
+@end itemize
+
+Temporary directories should always be specified as an absolute pathname.
+When running a CVS client, @samp{-T} affects only the local process;
+specifying @samp{-T} for the client has no effect on the server and
+vice versa.
+
+@cindex CVSROOT, overriding
+@cindex Overriding CVSROOT
+@item -d @var{cvs_root_directory}
+Use @var{cvs_root_directory} as the root directory
+pathname of the repository. Overrides the setting of
+the @code{$CVSROOT} environment variable. @xref{Repository}.
+
+@cindex EDITOR, overriding
+@cindex Overriding EDITOR
+@item -e @var{editor}
+Use @var{editor} to enter revision log information. Overrides the
+setting of the @code{$CVSEDITOR} and @code{$EDITOR}
+environment variables. For more information, see
+@ref{Committing your changes}.
+
+@item -f
+Do not read the @file{~/.cvsrc} file. This
+option is most often used because of the
+non-orthogonality of the @sc{cvs} option set. For
+example, the @samp{cvs log} option @samp{-N} (turn off
+display of tag names) does not have a corresponding
+option to turn the display on. So if you have
+@samp{-N} in the @file{~/.cvsrc} entry for @samp{log},
+you may need to use @samp{-f} to show the tag names.
+
+@item -H
+@itemx --help
+Display usage information about the specified @samp{cvs_command}
+(but do not actually execute the command). If you don't specify
+a command name, @samp{cvs -H} displays overall help for
+@sc{cvs}, including a list of other help options.
+@c It seems to me it is better to document it this way
+@c rather than trying to update this documentation
+@c every time that we add a --help-foo option. But
+@c perhaps that is confusing...
+
+@cindex Read-only repository mode
+@item -R
+Turns on read-only repository mode. This allows one to check out from a
+read-only repository, such as within an anoncvs server, or from a @sc{cd-rom}
+repository.
+
+Same effect as if the @code{CVSREADONLYFS} environment
+variable is set. Using @samp{-R} can also considerably
+speed up checkouts over NFS.
+
+@cindex Read-only mode
+@item -n
+Do not change any files. Attempt to execute the
+@samp{cvs_command}, but only to issue reports; do not remove,
+update, or merge any existing files, or create any new files.
+
+Note that @sc{cvs} will not necessarily produce exactly
+the same output as without @samp{-n}. In some cases
+the output will be the same, but in other cases
+@sc{cvs} will skip some of the processing that would
+have been required to produce the exact same output.
+
+@item -Q
+Cause the command to be really quiet; the command will only
+generate output for serious problems.
+
+@item -q
+Cause the command to be somewhat quiet; informational messages,
+such as reports of recursion through subdirectories, are
+suppressed.
+
+@cindex Read-only files, and -r
+@item -r
+Make new working files read-only. Same effect
+as if the @code{$CVSREAD} environment variable is set
+(@pxref{Environment variables}). The default is to
+make working files writable, unless watches are on
+(@pxref{Watches}).
+
+@item -s @var{variable}=@var{value}
+Set a user variable (@pxref{Variables}).
+
+@cindex Trace
+@item -t
+Trace program execution; display messages showing the steps of
+@sc{cvs} activity. Particularly useful with @samp{-n} to explore the
+potential impact of an unfamiliar command.
+
+@item -v
+@item --version
+Display version and copyright information for @sc{cvs}.
+
+@cindex CVSREAD, overriding
+@cindex Overriding CVSREAD
+@item -w
+Make new working files read-write. Overrides the
+setting of the @code{$CVSREAD} environment variable.
+Files are created read-write by default, unless @code{$CVSREAD} is
+set or @samp{-r} is given.
+@c Note that -w only overrides -r and CVSREAD; it has
+@c no effect on files which are readonly because of
+@c "cvs watch on". My guess is that is the way it
+@c should be (or should "cvs -w get" on a watched file
+@c be the same as a get and a cvs edit?), but I'm not
+@c completely sure whether to document it this way.
+
+@item -x
+@cindex Encryption
+Encrypt all communication between the client and the
+server. Only has an effect on the @sc{cvs} client. As
+of this writing, this is only implemented when using a
+GSSAPI connection (@pxref{GSSAPI authenticated}) or a
+Kerberos connection (@pxref{Kerberos authenticated}).
+Enabling encryption implies that message traffic is
+also authenticated. Encryption support is not
+available by default; it must be enabled using a
+special configure option, @file{--enable-encryption},
+when you build @sc{cvs}.
+
+@item -z @var{level}
+@cindex Compression
+@cindex Gzip
+Request compression @var{level} for network traffic.
+@sc{cvs} interprets @var{level} identically to the @code{gzip} program.
+Valid levels are 1 (high speed, low compression) to
+9 (low speed, high compression), or 0 to disable
+compression (the default). Data sent to the server will
+be compressed at the requested level and the client will request
+the server use the same compression level for data returned. The
+server will use the closest level allowed by the server administrator to
+compress returned data. This option only has an effect when passed to
+the @sc{cvs} client.
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Common options
+@appendixsec Common command options
+@cindex Common options
+@cindex Right-hand options
+
+This section describes the @samp{command_options} that
+are available across several @sc{cvs} commands. These
+options are always given to the right of
+@samp{cvs_command}. Not all
+commands support all of these options; each option is
+only supported for commands where it makes sense.
+However, when a command has one of these options you
+can almost always count on the same behavior of the
+option as in other commands. (Other command options,
+which are listed with the individual commands, may have
+different behavior from one @sc{cvs} command to the other).
+
+@strong{Note: the @samp{history} command is an exception; it supports
+many options that conflict even with these standard options.}
+
+@table @code
+@cindex Dates
+@cindex Time
+@cindex Specifying dates
+@item -D @var{date_spec}
+Use the most recent revision no later than @var{date_spec}.
+@var{date_spec} is a single argument, a date description
+specifying a date in the past.
+
+The specification is @dfn{sticky} when you use it to make a
+private copy of a source file; that is, when you get a working
+file using @samp{-D}, @sc{cvs} records the date you specified, so that
+further updates in the same directory will use the same date
+(for more information on sticky tags/dates, @pxref{Sticky tags}).
+
+@samp{-D} is available with the @code{annotate}, @code{checkout},
+@code{diff}, @code{export}, @code{history}, @code{ls},
+@code{rdiff}, @code{rls}, @code{rtag}, @code{tag}, and @code{update} commands.
+(The @code{history} command uses this option in a
+slightly different way; @pxref{history options}).
+
+For a complete description of the date formats accepted by @sc{cvs},
+@ref{Date input formats}.
+@c What other formats should we accept? I don't want
+@c to start accepting a whole mess of non-standard
+@c new formats (there are a lot which are in wide use in
+@c one context or another), but practicality does
+@c dictate some level of flexibility.
+@c * POSIX.2 (e.g. touch, ls output, date) and other
+@c POSIX and/or de facto unix standards (e.g. at). The
+@c practice here is too inconsistent to be of any use.
+@c * VMS dates. This is not a formal standard, but
+@c there is a published specification (see SYS$ASCTIM
+@c and SYS$BINTIM in the _VMS System Services Reference
+@c Manual_), it is implemented consistently in VMS
+@c utilities, and VMS users will expect CVS running on
+@c VMS to support this format (and if we're going to do
+@c that, better to make CVS support it on all
+@c platforms. Maybe).
+@c
+@c One more note: In output, CVS should consistently
+@c use one date format, and that format should be one that
+@c it accepts in input as well. The former isn't
+@c really true (see survey below), and I'm not
+@c sure that either of those formats is accepted in
+@c input.
+@c
+@c cvs log
+@c current 1996/01/02 13:45:31
+@c Internet 02 Jan 1996 13:45:31 UT
+@c ISO 1996-01-02 13:45:31
+@c cvs ann
+@c current 02-Jan-96
+@c Internet-like 02 Jan 96
+@c ISO 96-01-02
+@c cvs status
+@c current Tue Jun 11 02:54:53 1996
+@c Internet [Tue,] 11 Jun 1996 02:54:53
+@c ISO 1996-06-11 02:54:53
+@c note: date possibly should be omitted entirely for
+@c other reasons.
+@c cvs editors
+@c current Tue Jun 11 02:54:53 1996 GMT
+@c cvs history
+@c current 06/11 02:54 +0000
+@c any others?
+@c There is a good chance the proper solution has to
+@c involve at least some level of letting the user
+@c decide which format (with the default being the
+@c formats CVS has always used; changing these might be
+@c _very_ disruptive since scripts may very well be
+@c parsing them).
+@c
+@c Another random bit of prior art concerning dates is
+@c the strptime function which takes templates such as
+@c "%m/%d/%y", and apparent a variant of getdate()
+@c which also honors them. See
+@c X/Open CAE Specification, System Interfaces and
+@c Headers Issue 4, Version 2 (September 1994), in the
+@c entry for getdate() on page 231
+
+Remember to quote the argument to the @samp{-D}
+flag so that your shell doesn't interpret spaces as
+argument separators. A command using the @samp{-D}
+flag can look like this:
+
+@example
+$ cvs diff -D "1 hour ago" cvs.texinfo
+@end example
+
+@cindex Forcing a tag match
+@item -f
+When you specify a particular date or tag to @sc{cvs} commands, they
+normally ignore files that do not contain the tag (or did not
+exist prior to the date) that you specified. Use the @samp{-f} option
+if you want files retrieved even when there is no match for the
+tag or date. (The most recent revision of the file
+will be used).
+
+Note that even with @samp{-f}, a tag that you specify
+must exist (that is, in some file, not necessary in
+every file). This is so that @sc{cvs} will continue to
+give an error if you mistype a tag name.
+
+@need 800
+@samp{-f} is available with these commands:
+@code{annotate}, @code{checkout}, @code{export},
+@code{rdiff}, @code{rtag}, and @code{update}.
+
+@strong{WARNING: The @code{commit} and @code{remove}
+commands also have a
+@samp{-f} option, but it has a different behavior for
+those commands. See @ref{commit options}, and
+@ref{Removing files}.}
+
+@item -k @var{kflag}
+Override the default processing of RCS keywords other than
+@samp{-kb}. @xref{Keyword substitution}, for the meaning of
+@var{kflag}. Used with the @code{checkout} and @code{update}
+commands, your @var{kflag} specification is
+@dfn{sticky}; that is, when you use this option
+with a @code{checkout} or @code{update} command,
+@sc{cvs} associates your selected @var{kflag} with any files
+it operates on, and continues to use that @var{kflag} with future
+commands on the same files until you specify otherwise.
+
+The @samp{-k} option is available with the @code{add},
+@code{checkout}, @code{diff}, @code{export}, @code{import},
+@code{rdiff}, and @code{update} commands.
+
+@strong{WARNING: Prior to CVS version 1.12.2, the @samp{-k} flag
+overrode the @samp{-kb} indication for a binary file. This could
+sometimes corrupt binary files. @xref{Merging and keywords}, for
+more.}
+
+@item -l
+Local; run only in current working directory, rather than
+recursing through subdirectories.
+
+Available with the following commands: @code{annotate}, @code{checkout},
+@code{commit}, @code{diff}, @code{edit}, @code{editors}, @code{export},
+@code{log}, @code{rdiff}, @code{remove}, @code{rtag},
+@code{status}, @code{tag}, @code{unedit}, @code{update}, @code{watch},
+and @code{watchers}.
+
+@cindex Editor, avoiding invocation of
+@cindex Avoiding editor invocation
+@item -m @var{message}
+Use @var{message} as log information, instead of
+invoking an editor.
+
+Available with the following commands: @code{add},
+@code{commit} and @code{import}.
+
+@item -n
+Do not run any tag program. (A program can be
+specified to run in the modules
+database (@pxref{modules}); this option bypasses it).
+
+@strong{Note: this is not the same as the @samp{cvs -n}
+program option, which you can specify to the left of a cvs command!}
+
+Available with the @code{checkout}, @code{commit}, @code{export},
+and @code{rtag} commands.
+
+@item -P
+Prune empty directories. See @ref{Removing directories}.
+
+@item -p
+Pipe the files retrieved from the repository to standard output,
+rather than writing them in the current directory. Available
+with the @code{checkout} and @code{update} commands.
+
+@item -R
+Process directories recursively. This is the default for all @sc{cvs}
+commands, with the exception of @code{ls} & @code{rls}.
+
+Available with the following commands: @code{annotate}, @code{checkout},
+@code{commit}, @code{diff}, @code{edit}, @code{editors}, @code{export},
+@code{ls}, @code{rdiff}, @code{remove}, @code{rls}, @code{rtag},
+@code{status}, @code{tag}, @code{unedit}, @code{update}, @code{watch},
+and @code{watchers}.
+
+@item -r @var{tag}
+@item -r @var{tag}[:@var{date}]
+@cindex HEAD, special tag
+@cindex BASE, special tag
+Use the revision specified by the @var{tag} argument (and the @var{date}
+argument for the commands which accept it) instead of the
+default @dfn{head} revision. As well as arbitrary tags defined
+with the @code{tag} or @code{rtag} command, two special tags are
+always available: @samp{HEAD} refers to the most recent version
+available in the repository, and @samp{BASE} refers to the
+revision you last checked out into the current working directory.
+
+@c FIXME: What does HEAD really mean? I believe that
+@c the current answer is the head of the default branch
+@c for all cvs commands except diff. For diff, it
+@c seems to be (a) the head of the trunk (or the default
+@c branch?) if there is no sticky tag, (b) the head of the
+@c branch for the sticky tag, if there is a sticky tag.
+@c (b) is ugly as it differs
+@c from what HEAD means for other commands, but people
+@c and/or scripts are quite possibly used to it.
+@c See "head" tests in sanity.sh.
+@c Probably the best fix is to introduce two new
+@c special tags, ".thead" for the head of the trunk,
+@c and ".bhead" for the head of the current branch.
+@c Then deprecate HEAD. This has the advantage of
+@c not surprising people with a change to HEAD, and a
+@c side benefit of also phasing out the poorly-named
+@c HEAD (see discussion of reserved tag names in node
+@c "Tags"). Of course, .thead and .bhead should be
+@c carefully implemented (with the implementation the
+@c same for "diff" as for everyone else), test cases
+@c written (similar to the ones in "head"), new tests
+@c cases written for things like default branches, &c.
+
+The tag specification is sticky when you use this
+with @code{checkout} or @code{update} to make your own
+copy of a file: @sc{cvs} remembers the tag and continues to use it on
+future update commands, until you specify otherwise (for more information
+on sticky tags/dates, @pxref{Sticky tags}).
+
+The tag can be either a symbolic or numeric tag, as
+described in @ref{Tags}, or the name of a branch, as
+described in @ref{Branching and merging}.
+When @var{tag} is the name of a
+branch, some commands accept the optional @var{date} argument to specify
+the revision as of the given date on the branch.
+When a command expects a specific revision,
+the name of a branch is interpreted as the most recent
+revision on that branch.
+
+Specifying the @samp{-q} global option along with the
+@samp{-r} command option is often useful, to suppress
+the warning messages when the @sc{rcs} file
+does not contain the specified tag.
+
+@strong{Note: this is not the same as the overall @samp{cvs -r} option,
+which you can specify to the left of a @sc{cvs} command!}
+
+@samp{-r @var{tag}} is available with the @code{commit} and @code{history}
+commands.
+
+@samp{-r @var{tag}[:@var{date}]} is available with the @code{annotate},
+@code{checkout}, @code{diff}, @code{export}, @code{rdiff}, @code{rtag},
+and @code{update} commands.
+
+@item -W
+Specify file names that should be filtered. You can
+use this option repeatedly. The spec can be a file
+name pattern of the same type that you can specify in
+the @file{.cvswrappers} file.
+Available with the following commands: @code{import},
+and @code{update}.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@include getdate-cvs.texi
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node admin
+@appendixsec admin---Administration
+@cindex Admin (subcommand)
+
+@itemize @bullet
+@item
+Requires: repository, working directory.
+@item
+Changes: repository.
+@item
+Synonym: rcs
+@end itemize
+
+This is the @sc{cvs} interface to assorted
+administrative facilities. Some of them have
+questionable usefulness for @sc{cvs} but exist for
+historical purposes. Some of the questionable options
+are likely to disappear in the future. This command
+@emph{does} work recursively, so extreme care should be
+used.
+
+@cindex cvsadmin
+@cindex UserAdminOptions, in CVSROOT/config
+On unix, if there is a group named @code{cvsadmin},
+only members of that group can run @code{cvs admin}
+commands, except for those specified using the
+@code{UserAdminOptions} configuration option in the
+@file{CVSROOT/config} file. Options specified using
+@code{UserAdminOptions} can be run by any user. See
+@ref{config} for more on @code{UserAdminOptions}.
+
+The @code{cvsadmin} group should exist on the server,
+or any system running the non-client/server @sc{cvs}.
+To disallow @code{cvs admin} for all users, create a
+group with no users in it. On NT, the @code{cvsadmin}
+feature does not exist and all users
+can run @code{cvs admin}.
+
+@menu
+* admin options:: admin options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node admin options
+@appendixsubsec admin options
+
+Some of these options have questionable usefulness for
+@sc{cvs} but exist for historical purposes. Some even
+make it impossible to use @sc{cvs} until you undo the
+effect!
+
+@table @code
+@item -A@var{oldfile}
+Might not work together with @sc{cvs}. Append the
+access list of @var{oldfile} to the access list of the
+@sc{rcs} file.
+
+@item -a@var{logins}
+Might not work together with @sc{cvs}. Append the
+login names appearing in the comma-separated list
+@var{logins} to the access list of the @sc{rcs} file.
+
+@item -b[@var{rev}]
+Set the default branch to @var{rev}. In @sc{cvs}, you
+normally do not manipulate default branches; sticky
+tags (@pxref{Sticky tags}) are a better way to decide
+which branch you want to work on. There is one reason
+to run @code{cvs admin -b}: to revert to the vendor's
+version when using vendor branches (@pxref{Reverting
+local changes}).
+There can be no space between @samp{-b} and its argument.
+@c Hmm, we don't document the usage where rev is
+@c omitted. Maybe that usage can/should be deprecated
+@c (and replaced with -bHEAD or something?) (so we can toss
+@c the optional argument). Note that -bHEAD does not
+@c work, as of 17 Sep 1997, but probably will once "cvs
+@c admin" is internal to CVS.
+
+@cindex Comment leader
+@item -c@var{string}
+Sets the comment leader to @var{string}. The comment
+leader is not used by current versions of @sc{cvs} or
+@sc{rcs} 5.7. Therefore, you can almost surely not
+worry about it. @xref{Keyword substitution}.
+
+@item -e[@var{logins}]
+Might not work together with @sc{cvs}. Erase the login
+names appearing in the comma-separated list
+@var{logins} from the access list of the RCS file. If
+@var{logins} is omitted, erase the entire access list.
+There can be no space between @samp{-e} and its argument.
+
+@item -I
+Run interactively, even if the standard input is not a
+terminal. This option does not work with the
+client/server @sc{cvs} and is likely to disappear in
+a future release of @sc{cvs}.
+
+@item -i
+Useless with @sc{cvs}. This creates and initializes a
+new @sc{rcs} file, without depositing a revision. With
+@sc{cvs}, add files with the @code{cvs add} command
+(@pxref{Adding files}).
+
+@item -k@var{subst}
+Set the default keyword
+substitution to @var{subst}. @xref{Keyword
+substitution}. Giving an explicit @samp{-k} option to
+@code{cvs update}, @code{cvs export}, or @code{cvs
+checkout} overrides this default.
+
+@item -l[@var{rev}]
+Lock the revision with number @var{rev}. If a branch
+is given, lock the latest revision on that branch. If
+@var{rev} is omitted, lock the latest revision on the
+default branch. There can be no space between
+@samp{-l} and its argument.
+
+This can be used in conjunction with the
+@file{rcslock.pl} script in the @file{contrib}
+directory of the @sc{cvs} source distribution to
+provide reserved checkouts (where only one user can be
+editing a given file at a time). See the comments in
+that file for details (and see the @file{README} file
+in that directory for disclaimers about the unsupported
+nature of contrib). According to comments in that
+file, locking must set to strict (which is the default).
+
+@item -L
+Set locking to strict. Strict locking means that the
+owner of an RCS file is not exempt from locking for
+checkin. For use with @sc{cvs}, strict locking must be
+set; see the discussion under the @samp{-l} option above.
+
+@cindex Changing a log message
+@cindex Replacing a log message
+@cindex Correcting a log message
+@cindex Fixing a log message
+@cindex Log message, correcting
+@item -m@var{rev}:@var{msg}
+Replace the log message of revision @var{rev} with
+@var{msg}.
+
+@c The rcs -M option, to suppress sending mail, has never been
+@c documented as a cvs admin option.
+
+@item -N@var{name}[:[@var{rev}]]
+Act like @samp{-n}, except override any previous
+assignment of @var{name}. For use with magic branches,
+see @ref{Magic branch numbers}.
+
+@item -n@var{name}[:[@var{rev}]]
+Associate the symbolic name @var{name} with the branch
+or revision @var{rev}. It is normally better to use
+@samp{cvs tag} or @samp{cvs rtag} instead. Delete the
+symbolic name if both @samp{:} and @var{rev} are
+omitted; otherwise, print an error message if
+@var{name} is already associated with another number.
+If @var{rev} is symbolic, it is expanded before
+association. A @var{rev} consisting of a branch number
+followed by a @samp{.} stands for the current latest
+revision in the branch. A @samp{:} with an empty
+@var{rev} stands for the current latest revision on the
+default branch, normally the trunk. For example,
+@samp{cvs admin -n@var{name}:} associates @var{name} with the
+current latest revision of all the RCS files;
+this contrasts with @samp{cvs admin -n@var{name}:$} which
+associates @var{name} with the revision numbers
+extracted from keyword strings in the corresponding
+working files.
+
+@cindex Deleting revisions
+@cindex Outdating revisions
+@cindex Saving space
+@item -o@var{range}
+Deletes (@dfn{outdates}) the revisions given by
+@var{range}.
+
+Note that this command can be quite dangerous unless
+you know @emph{exactly} what you are doing (for example
+see the warnings below about how the
+@var{rev1}:@var{rev2} syntax is confusing).
+
+If you are short on disc this option might help you.
+But think twice before using it---there is no way short
+of restoring the latest backup to undo this command!
+If you delete different revisions than you planned,
+either due to carelessness or (heaven forbid) a @sc{cvs}
+bug, there is no opportunity to correct the error
+before the revisions are deleted. It probably would be
+a good idea to experiment on a copy of the repository
+first.
+
+Specify @var{range} in one of the following ways:
+
+@table @code
+@item @var{rev1}::@var{rev2}
+Collapse all revisions between rev1 and rev2, so that
+@sc{cvs} only stores the differences associated with going
+from rev1 to rev2, not intermediate steps. For
+example, after @samp{-o 1.3::1.5} one can retrieve
+revision 1.3, revision 1.5, or the differences to get
+from 1.3 to 1.5, but not the revision 1.4, or the
+differences between 1.3 and 1.4. Other examples:
+@samp{-o 1.3::1.4} and @samp{-o 1.3::1.3} have no
+effect, because there are no intermediate revisions to
+remove.
+
+@item ::@var{rev}
+Collapse revisions between the beginning of the branch
+containing @var{rev} and @var{rev} itself. The
+branchpoint and @var{rev} are left intact. For
+example, @samp{-o ::1.3.2.6} deletes revision 1.3.2.1,
+revision 1.3.2.5, and everything in between, but leaves
+1.3 and 1.3.2.6 intact.
+
+@item @var{rev}::
+Collapse revisions between @var{rev} and the end of the
+branch containing @var{rev}. Revision @var{rev} is
+left intact but the head revision is deleted.
+
+@item @var{rev}
+Delete the revision @var{rev}. For example, @samp{-o
+1.3} is equivalent to @samp{-o 1.2::1.4}.
+
+@item @var{rev1}:@var{rev2}
+Delete the revisions from @var{rev1} to @var{rev2},
+inclusive, on the same branch. One will not be able to
+retrieve @var{rev1} or @var{rev2} or any of the
+revisions in between. For example, the command
+@samp{cvs admin -oR_1_01:R_1_02 .} is rarely useful.
+It means to delete revisions up to, and including, the
+tag R_1_02. But beware! If there are files that have not
+changed between R_1_02 and R_1_03 the file will have
+@emph{the same} numerical revision number assigned to
+the tags R_1_02 and R_1_03. So not only will it be
+impossible to retrieve R_1_02; R_1_03 will also have to
+be restored from the tapes! In most cases you want to
+specify @var{rev1}::@var{rev2} instead.
+
+@item :@var{rev}
+Delete revisions from the beginning of the
+branch containing @var{rev} up to and including
+@var{rev}.
+
+@item @var{rev}:
+Delete revisions from revision @var{rev}, including
+@var{rev} itself, to the end of the branch containing
+@var{rev}.
+@end table
+
+None of the revisions to be deleted may have
+branches or locks.
+
+If any of the revisions to be deleted have symbolic
+names, and one specifies one of the @samp{::} syntaxes,
+then @sc{cvs} will give an error and not delete any
+revisions. If you really want to delete both the
+symbolic names and the revisions, first delete the
+symbolic names with @code{cvs tag -d}, then run
+@code{cvs admin -o}. If one specifies the
+non-@samp{::} syntaxes, then @sc{cvs} will delete the
+revisions but leave the symbolic names pointing to
+nonexistent revisions. This behavior is preserved for
+compatibility with previous versions of @sc{cvs}, but
+because it isn't very useful, in the future it may
+change to be like the @samp{::} case.
+
+Due to the way @sc{cvs} handles branches @var{rev}
+cannot be specified symbolically if it is a branch.
+@xref{Magic branch numbers}, for an explanation.
+@c FIXME: is this still true? I suspect not.
+
+Make sure that no-one has checked out a copy of the
+revision you outdate. Strange things will happen if he
+starts to edit it and tries to check it back in. For
+this reason, this option is not a good way to take back
+a bogus commit; commit a new revision undoing the bogus
+change instead (@pxref{Merging two revisions}).
+
+@item -q
+Run quietly; do not print diagnostics.
+
+@item -s@var{state}[:@var{rev}]
+Useful with @sc{cvs}. Set the state attribute of the
+revision @var{rev} to @var{state}. If @var{rev} is a
+branch number, assume the latest revision on that
+branch. If @var{rev} is omitted, assume the latest
+revision on the default branch. Any identifier is
+acceptable for @var{state}. A useful set of states is
+@samp{Exp} (for experimental), @samp{Stab} (for
+stable), and @samp{Rel} (for released). By default,
+the state of a new revision is set to @samp{Exp} when
+it is created. The state is visible in the output from
+@var{cvs log} (@pxref{log}), and in the
+@samp{$@splitrcskeyword{Log}$} and @samp{$@splitrcskeyword{State}$} keywords
+(@pxref{Keyword substitution}). Note that @sc{cvs}
+uses the @code{dead} state for its own purposes (@pxref{Attic}); to
+take a file to or from the @code{dead} state use
+commands like @code{cvs remove} and @code{cvs add}
+(@pxref{Adding and removing}), not @code{cvs admin -s}.
+
+@item -t[@var{file}]
+Useful with @sc{cvs}. Write descriptive text from the
+contents of the named @var{file} into the RCS file,
+deleting the existing text. The @var{file} pathname
+may not begin with @samp{-}. The descriptive text can be seen in the
+output from @samp{cvs log} (@pxref{log}).
+There can be no space between @samp{-t} and its argument.
+
+If @var{file} is omitted,
+obtain the text from standard input, terminated by
+end-of-file or by a line containing @samp{.} by itself.
+Prompt for the text if interaction is possible; see
+@samp{-I}.
+
+@item -t-@var{string}
+Similar to @samp{-t@var{file}}. Write descriptive text
+from the @var{string} into the @sc{rcs} file, deleting
+the existing text.
+There can be no space between @samp{-t} and its argument.
+
+@c The rcs -T option, do not update last-mod time for
+@c minor changes, has never been documented as a
+@c cvs admin option.
+
+@item -U
+Set locking to non-strict. Non-strict locking means
+that the owner of a file need not lock a revision for
+checkin. For use with @sc{cvs}, strict locking must be
+set; see the discussion under the @samp{-l} option
+above.
+
+@item -u[@var{rev}]
+See the option @samp{-l} above, for a discussion of
+using this option with @sc{cvs}. Unlock the revision
+with number @var{rev}. If a branch is given, unlock
+the latest revision on that branch. If @var{rev} is
+omitted, remove the latest lock held by the caller.
+Normally, only the locker of a revision may unlock it;
+somebody else unlocking a revision breaks the lock.
+This causes the original locker to be sent a @code{commit}
+notification (@pxref{Getting Notified}).
+There can be no space between @samp{-u} and its argument.
+
+@item -V@var{n}
+In previous versions of @sc{cvs}, this option meant to
+write an @sc{rcs} file which would be acceptable to
+@sc{rcs} version @var{n}, but it is now obsolete and
+specifying it will produce an error.
+@c Note that -V without an argument has never been
+@c documented as a cvs admin option.
+
+@item -x@var{suffixes}
+In previous versions of @sc{cvs}, this was documented
+as a way of specifying the names of the @sc{rcs}
+files. However, @sc{cvs} has always required that the
+@sc{rcs} files used by @sc{cvs} end in @samp{,v}, so
+this option has never done anything useful.
+
+@c The rcs -z option, to specify the timezone, has
+@c never been documented as a cvs admin option.
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node annotate
+@appendixsec annotate---What revision modified each line of a file?
+@cindex annotate (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: annotate [options] files@dots{}
+@item
+Requires: repository.
+@item
+Changes: nothing.
+@end itemize
+
+For each file in @var{files}, print the head revision
+of the trunk, together with information on the last
+modification for each line.
+
+@menu
+* annotate options:: annotate options
+* annotate example:: annotate example
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node annotate options
+@appendixsubsec annotate options
+
+These standard options are supported by @code{annotate}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -l
+Local directory only, no recursion.
+
+@item -R
+Process directories recursively.
+
+@item -f
+Use head revision if tag/date not found.
+
+@item -F
+Annotate binary files.
+
+@item -r @var{tag}[:@var{date}]
+Annotate file as of specified revision/tag or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+
+@item -D @var{date}
+Annotate file as of specified date.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node annotate example
+@appendixsubsec annotate example
+
+For example:
+
+@example
+$ cvs annotate ssfile
+Annotations for ssfile
+***************
+1.1 (mary 27-Mar-96): ssfile line 1
+1.2 (joe 28-Mar-96): ssfile line 2
+@end example
+
+The file @file{ssfile} currently contains two lines.
+The @code{ssfile line 1} line was checked in by
+@code{mary} on March 27. Then, on March 28, @code{joe}
+added a line @code{ssfile line 2}, without modifying
+the @code{ssfile line 1} line. This report doesn't
+tell you anything about lines which have been deleted
+or replaced; you need to use @code{cvs diff} for that
+(@pxref{diff}).
+
+The options to @code{cvs annotate} are listed in
+@ref{Invoking CVS}, and can be used to select the files
+and revisions to annotate. The options are described
+in more detail there and in @ref{Common options}.
+
+@c FIXME: maybe an example using the options? Just
+@c what it means to select a revision might be worth a
+@c few words of explanation ("you want to see who
+@c changed this line *before* 1.4"...).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node checkout
+@appendixsec checkout---Check out sources for editing
+@cindex checkout (subcommand)
+@cindex co (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: checkout [options] modules@dots{}
+@item
+Requires: repository.
+@item
+Changes: working directory.
+@item
+Synonyms: co, get
+@end itemize
+
+Create or update a working directory containing copies of the
+source files specified by @var{modules}. You must execute
+@code{checkout} before using most of the other @sc{cvs}
+commands, since most of them operate on your working
+directory.
+
+The @var{modules} are either
+symbolic names for some
+collection of source directories and files, or paths to
+directories or files in the repository. The symbolic
+names are defined in the @samp{modules} file.
+@xref{modules}.
+@c Needs an example, particularly of the non-"modules"
+@c case but probably of both.
+
+@c FIXME: this seems like a very odd place to introduce
+@c people to how CVS works. The bit about unreserved
+@c checkouts is also misleading as it depends on how
+@c things are set up.
+Depending on the modules you specify, @code{checkout} may
+recursively create directories and populate them with
+the appropriate source files. You can then edit these
+source files at any time (regardless of whether other
+software developers are editing their own copies of the
+sources); update them to include new changes applied by
+others to the source repository; or commit your work as
+a permanent change to the source repository.
+
+Note that @code{checkout} is used to create
+directories. The top-level directory created is always
+added to the directory where @code{checkout} is
+invoked, and usually has the same name as the specified
+module. In the case of a module alias, the created
+sub-directory may have a different name, but you can be
+sure that it will be a sub-directory, and that
+@code{checkout} will show the relative path leading to
+each file as it is extracted into your private work
+area (unless you specify the @samp{-Q} global option).
+
+The files created by @code{checkout} are created
+read-write, unless the @samp{-r} option to @sc{cvs}
+(@pxref{Global options}) is specified, the
+@code{CVSREAD} environment variable is specified
+(@pxref{Environment variables}), or a watch is in
+effect for that file (@pxref{Watches}).
+
+Note that running @code{checkout} on a directory that was already
+built by a prior @code{checkout} is also permitted.
+This is similar to specifying the @samp{-d} option
+to the @code{update} command in the sense that new
+directories that have been created in the repository
+will appear in your work area.
+However, @code{checkout} takes a module name whereas
+@code{update} takes a directory name. Also
+to use @code{checkout} this way it must be run from the
+top level directory (where you originally ran
+@code{checkout} from), so before you run
+@code{checkout} to update an existing directory, don't
+forget to change your directory to the top level
+directory.
+
+For the output produced by the @code{checkout} command
+see @ref{update output}.
+
+@menu
+* checkout options:: checkout options
+* checkout examples:: checkout examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node checkout options
+@appendixsubsec checkout options
+
+These standard options are supported by @code{checkout}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+This option is sticky, and implies @samp{-P}. See
+@ref{Sticky tags}, for more information on sticky tags/dates.
+
+@item -f
+Only useful with the @samp{-D} or @samp{-r} flags. If no matching revision is
+found, retrieve the most recent revision (instead of ignoring the file).
+
+@item -k @var{kflag}
+Process keywords according to @var{kflag}. See
+@ref{Keyword substitution}.
+This option is sticky; future updates of
+this file in this working directory will use the same
+@var{kflag}. The @code{status} command can be viewed
+to see the sticky options. See @ref{Invoking CVS}, for
+more information on the @code{status} command.
+
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any checkout program (as specified
+with the @samp{-o} option in the modules file;
+@pxref{modules}).
+
+@item -P
+Prune empty directories. See @ref{Moving directories}.
+
+@item -p
+Pipe files to the standard output.
+
+@item -R
+Checkout directories recursively. This option is on by default.
+
+@item -r @var{tag}[:@var{date}]
+Checkout the revision specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. This option is sticky, and implies @samp{-P}.
+See @ref{Sticky tags}, for more information on sticky tags/dates. Also,
+see @ref{Common options}.
+@end table
+
+In addition to those, you can use these special command
+options with @code{checkout}:
+
+@table @code
+@item -A
+Reset any sticky tags, dates, or @samp{-k} options.
+See @ref{Sticky tags}, for more information on sticky tags/dates.
+
+@item -c
+Copy the module file, sorted, to the standard output,
+instead of creating or modifying any files or
+directories in your working directory.
+
+@item -d @var{dir}
+Create a directory called @var{dir} for the working
+files, instead of using the module name. In general,
+using this flag is equivalent to using @samp{mkdir
+@var{dir}; cd @var{dir}} followed by the checkout
+command without the @samp{-d} flag.
+
+There is an important exception, however. It is very
+convenient when checking out a single item to have the
+output appear in a directory that doesn't contain empty
+intermediate directories. In this case @emph{only},
+@sc{cvs} tries to ``shorten'' pathnames to avoid those empty
+directories.
+
+For example, given a module @samp{foo} that contains
+the file @samp{bar.c}, the command @samp{cvs co -d dir
+foo} will create directory @samp{dir} and place
+@samp{bar.c} inside. Similarly, given a module
+@samp{bar} which has subdirectory @samp{baz} wherein
+there is a file @samp{quux.c}, the command @samp{cvs co
+-d dir bar/baz} will create directory @samp{dir} and
+place @samp{quux.c} inside.
+
+Using the @samp{-N} flag will defeat this behavior.
+Given the same module definitions above, @samp{cvs co
+-N -d dir foo} will create directories @samp{dir/foo}
+and place @samp{bar.c} inside, while @samp{cvs co -N -d
+dir bar/baz} will create directories @samp{dir/bar/baz}
+and place @samp{quux.c} inside.
+
+@item -j @var{tag}
+With two @samp{-j} options, merge changes from the
+revision specified with the first @samp{-j} option to
+the revision specified with the second @samp{j} option,
+into the working directory.
+
+With one @samp{-j} option, merge changes from the
+ancestor revision to the revision specified with the
+@samp{-j} option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the @samp{-j} option.
+
+In addition, each -j option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}.
+
+@xref{Branching and merging}.
+
+@item -N
+Only useful together with @samp{-d @var{dir}}. With
+this option, @sc{cvs} will not ``shorten'' module paths
+in your working directory when you check out a single
+module. See the @samp{-d} flag for examples and a
+discussion.
+
+@item -s
+Like @samp{-c}, but include the status of all modules,
+and sort it by the status string. @xref{modules}, for
+info about the @samp{-s} option that is used inside the
+modules file to set the module status.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node checkout examples
+@appendixsubsec checkout examples
+
+Get a copy of the module @samp{tc}:
+
+@example
+$ cvs checkout tc
+@end example
+
+Get a copy of the module @samp{tc} as it looked one day
+ago:
+
+@example
+$ cvs checkout -D yesterday tc
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node commit
+@appendixsec commit---Check files into the repository
+@cindex commit (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: commit [-lnRf] [-m 'log_message' |
+-F file] [-r revision] [files@dots{}]
+@item
+Requires: working directory, repository.
+@item
+Changes: repository.
+@item
+Synonym: ci
+@end itemize
+
+Use @code{commit} when you want to incorporate changes
+from your working source files into the source
+repository.
+
+If you don't specify particular files to commit, all of
+the files in your working current directory are
+examined. @code{commit} is careful to change in the
+repository only those files that you have really
+changed. By default (or if you explicitly specify the
+@samp{-R} option), files in subdirectories are also
+examined and committed if they have changed; you can
+use the @samp{-l} option to limit @code{commit} to the
+current directory only.
+
+@code{commit} verifies that the selected files are up
+to date with the current revisions in the source
+repository; it will notify you, and exit without
+committing, if any of the specified files must be made
+current first with @code{update} (@pxref{update}).
+@code{commit} does not call the @code{update} command
+for you, but rather leaves that for you to do when the
+time is right.
+
+When all is well, an editor is invoked to allow you to
+enter a log message that will be written to one or more
+logging programs (@pxref{modules}, and @pxref{loginfo})
+and placed in the @sc{rcs} file inside the
+repository. This log message can be retrieved with the
+@code{log} command; see @ref{log}. You can specify the
+log message on the command line with the @samp{-m
+@var{message}} option, and thus avoid the editor invocation,
+or use the @samp{-F @var{file}} option to specify
+that the argument file contains the log message.
+
+At @code{commit}, a unique commitid is placed in the @sc{rcs}
+file inside the repository. All files committed at once
+get the same commitid. The commitid can be retrieved with
+the @code{log} and @code{status} command; see @ref{log},
+@ref{File status}.
+
+@menu
+* commit options:: commit options
+* commit examples:: commit examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node commit options
+@appendixsubsec commit options
+
+These standard options are supported by @code{commit}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Commit directories recursively. This is on by default.
+
+@item -r @var{revision}
+Commit to @var{revision}. @var{revision} must be
+either a branch, or a revision on the main trunk that
+is higher than any existing revision number
+(@pxref{Assigning revisions}). You
+cannot commit to a specific revision on a branch.
+@c FIXME: Need xref for branch case.
+@end table
+
+@code{commit} also supports these options:
+
+@table @code
+@item -c
+Refuse to commit files unless the user has registered a valid edit on the
+file via @code{cvs edit}. This is most useful when @samp{commit -c}
+and @samp{edit -c} have been placed in all @file{.cvsrc} files.
+A commit can be forced anyways by either regestering an edit retroactively
+via @code{cvs edit} (no changes to the file will be lost) or using the
+@code{-f} option to commit. Support for @code{commit -c} requires both
+client and a server versions 1.12.10 or greater.
+
+@item -F @var{file}
+Read the log message from @var{file}, instead
+of invoking an editor.
+
+@item -f
+Note that this is not the standard behavior of
+the @samp{-f} option as defined in @ref{Common options}.
+
+Force @sc{cvs} to commit a new revision even if you haven't
+made any changes to the file. As of @sc{cvs} version 1.12.10,
+it also causes the @code{-c} option to be ignored. If the current revision
+of @var{file} is 1.7, then the following two commands
+are equivalent:
+
+@example
+$ cvs commit -f @var{file}
+$ cvs commit -r 1.8 @var{file}
+@end example
+
+@c This is odd, but it's how CVS has worked for some
+@c time.
+The @samp{-f} option disables recursion (i.e., it
+implies @samp{-l}). To force @sc{cvs} to commit a new
+revision for all files in all subdirectories, you must
+use @samp{-f -R}.
+
+@item -m @var{message}
+Use @var{message} as the log message, instead of
+invoking an editor.
+@end table
+
+@need 2000
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node commit examples
+@appendixsubsec commit examples
+
+@c FIXME: this material wants to be somewhere
+@c in "Branching and merging".
+
+@appendixsubsubsec Committing to a branch
+
+You can commit to a branch revision (one that has an
+even number of dots) with the @samp{-r} option. To
+create a branch revision, use the @samp{-b} option
+of the @code{rtag} or @code{tag} commands
+(@pxref{Branching and merging}). Then, either @code{checkout} or
+@code{update} can be used to base your sources on the
+newly created branch. From that point on, all
+@code{commit} changes made within these working sources
+will be automatically added to a branch revision,
+thereby not disturbing main-line development in any
+way. For example, if you had to create a patch to the
+1.2 version of the product, even though the 2.0 version
+is already under development, you might do:
+
+@example
+$ cvs rtag -b -r FCS1_2 FCS1_2_Patch product_module
+$ cvs checkout -r FCS1_2_Patch product_module
+$ cd product_module
+[[ hack away ]]
+$ cvs commit
+@end example
+
+@noindent
+This works automatically since the @samp{-r} option is
+sticky.
+
+@appendixsubsubsec Creating the branch after editing
+
+Say you have been working on some extremely
+experimental software, based on whatever revision you
+happened to checkout last week. If others in your
+group would like to work on this software with you, but
+without disturbing main-line development, you could
+commit your change to a new branch. Others can then
+checkout your experimental stuff and utilize the full
+benefit of @sc{cvs} conflict resolution. The scenario might
+look like:
+
+@c FIXME: Should we be recommending tagging the branchpoint?
+@example
+[[ hacked sources are present ]]
+$ cvs tag -b EXPR1
+$ cvs update -r EXPR1
+$ cvs commit
+@end example
+
+The @code{update} command will make the @samp{-r
+EXPR1} option sticky on all files. Note that your
+changes to the files will never be removed by the
+@code{update} command. The @code{commit} will
+automatically commit to the correct branch, because the
+@samp{-r} is sticky. You could also do like this:
+
+@c FIXME: Should we be recommending tagging the branchpoint?
+@example
+[[ hacked sources are present ]]
+$ cvs tag -b EXPR1
+$ cvs commit -r EXPR1
+@end example
+
+@noindent
+but then, only those files that were changed by you
+will have the @samp{-r EXPR1} sticky flag. If you hack
+away, and commit without specifying the @samp{-r EXPR1}
+flag, some files may accidentally end up on the main
+trunk.
+
+To work with you on the experimental change, others
+would simply do
+
+@example
+$ cvs checkout -r EXPR1 whatever_module
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node diff
+@appendixsec diff---Show differences between revisions
+@cindex diff (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: diff [-lR] [-k kflag] [format_options] [(-r rev1[:date1] | -D date1) [-r rev2[:date2] | -D date2]] [files@dots{}]
+@item
+Requires: working directory, repository.
+@item
+Changes: nothing.
+@end itemize
+
+The @code{diff} command is used to compare different
+revisions of files. The default action is to compare
+your working files with the revisions they were based
+on, and report any differences that are found.
+
+If any file names are given, only those files are
+compared. If any directories are given, all files
+under them will be compared.
+
+The exit status for diff is different than for other
+@sc{cvs} commands; for details @ref{Exit status}.
+
+@menu
+* diff options:: diff options
+* diff examples:: diff examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node diff options
+@appendixsubsec diff options
+
+These standard options are supported by @code{diff}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+See @samp{-r} for how this affects the comparison.
+
+@item -k @var{kflag}
+Process keywords according to @var{kflag}. See
+@ref{Keyword substitution}.
+
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Examine directories recursively. This option is on by
+default.
+
+@item -r @var{tag}[:@var{date}]
+Compare with revision specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. Zero, one or two
+@samp{-r} options can be present. With no @samp{-r}
+option, the working file will be compared with the
+revision it was based on. With one @samp{-r}, that
+revision will be compared to your current working file.
+With two @samp{-r} options those two revisions will be
+compared (and your working file will not affect the
+outcome in any way).
+@c We should be a lot more explicit, with examples,
+@c about the difference between "cvs diff" and "cvs
+@c diff -r HEAD". This often confuses new users.
+
+One or both @samp{-r} options can be replaced by a
+@samp{-D @var{date}} option, described above.
+@end table
+
+@c Conceptually, this is a disaster. There are 3
+@c zillion diff formats that we support via the diff
+@c library. It is not obvious to me that we should
+@c document them all. Maybe just the most common ones
+@c like -c and -u, and think about phasing out the
+@c obscure ones.
+@c FIXCVS: also should be a way to specify an external
+@c diff program (which can be different for different
+@c file types) and pass through
+@c arbitrary options, so that the user can do
+@c "--pass=-Z --pass=foo" or something even if CVS
+@c doesn't know about the "-Z foo" option to diff.
+@c This would fit nicely with deprecating/eliminating
+@c the obscure options of the diff library, because it
+@c would let people specify an external GNU diff if
+@c they are into that sort of thing.
+The following options specify the format of the
+output. They have the same meaning as in GNU diff.
+Most options have two equivalent names, one of which is a single letter
+preceded by @samp{-}, and the other of which is a long name preceded by
+@samp{--}.
+
+@table @samp
+@item -@var{lines}
+Show @var{lines} (an integer) lines of context. This option does not
+specify an output format by itself; it has no effect unless it is
+combined with @samp{-c} or @samp{-u}. This option is obsolete. For proper
+operation, @code{patch} typically needs at least two lines of context.
+
+@item -a
+Treat all files as text and compare them line-by-line, even if they
+do not seem to be text.
+
+@item -b
+Ignore trailing white space and consider all other sequences of one or
+more white space characters to be equivalent.
+
+@item -B
+Ignore changes that just insert or delete blank lines.
+
+@item --binary
+Read and write data in binary mode.
+
+@item --brief
+Report only whether the files differ, not the details of the
+differences.
+
+@item -c
+Use the context output format.
+
+@item -C @var{lines}
+@itemx --context@r{[}=@var{lines}@r{]}
+Use the context output format, showing @var{lines} (an integer) lines of
+context, or three if @var{lines} is not given.
+For proper operation, @code{patch} typically needs at least two lines of
+context.
+
+@item --changed-group-format=@var{format}
+Use @var{format} to output a line group containing differing lines from
+both files in if-then-else format. @xref{Line group formats}.
+
+@item -d
+Change the algorithm to perhaps find a smaller set of changes. This makes
+@code{diff} slower (sometimes much slower).
+
+@item -e
+@itemx --ed
+Make output that is a valid @code{ed} script.
+
+@item --expand-tabs
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+
+@item -f
+Make output that looks vaguely like an @code{ed} script but has changes
+in the order they appear in the file.
+
+@item -F @var{regexp}
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches @var{regexp}.
+
+@item --forward-ed
+Make output that looks vaguely like an @code{ed} script but has changes
+in the order they appear in the file.
+
+@item -H
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+
+@item --horizon-lines=@var{lines}
+Do not discard the last @var{lines} lines of the common prefix
+and the first @var{lines} lines of the common suffix.
+
+@item -i
+Ignore changes in case; consider upper- and lower-case letters
+equivalent.
+
+@item -I @var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+
+@item --ifdef=@var{name}
+Make merged if-then-else output using @var{name}.
+
+@item --ignore-all-space
+Ignore white space when comparing lines.
+
+@item --ignore-blank-lines
+Ignore changes that just insert or delete blank lines.
+
+@item --ignore-case
+Ignore changes in case; consider upper- and lower-case to be the same.
+
+@item --ignore-matching-lines=@var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+
+@item --ignore-space-change
+Ignore trailing white space and consider all other sequences of one or
+more white space characters to be equivalent.
+
+@item --initial-tab
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+
+@item -L @var{label}
+Use @var{label} instead of the file name in the context format
+and unified format headers.
+
+@item --label=@var{label}
+Use @var{label} instead of the file name in the context format
+and unified format headers.
+
+@item --left-column
+Print only the left column of two common lines in side by side format.
+
+@item --line-format=@var{format}
+Use @var{format} to output all input lines in if-then-else format.
+@xref{Line formats}.
+
+@item --minimal
+Change the algorithm to perhaps find a smaller set of changes. This
+makes @code{diff} slower (sometimes much slower).
+
+@item -n
+Output RCS-format diffs; like @samp{-f} except that each command
+specifies the number of lines affected.
+
+@item -N
+@itemx --new-file
+In directory comparison, if a file is found in only one directory,
+treat it as present but empty in the other directory.
+
+@item --new-group-format=@var{format}
+Use @var{format} to output a group of lines taken from just the second
+file in if-then-else format. @xref{Line group formats}.
+
+@item --new-line-format=@var{format}
+Use @var{format} to output a line taken from just the second file in
+if-then-else format. @xref{Line formats}.
+
+@item --old-group-format=@var{format}
+Use @var{format} to output a group of lines taken from just the first
+file in if-then-else format. @xref{Line group formats}.
+
+@item --old-line-format=@var{format}
+Use @var{format} to output a line taken from just the first file in
+if-then-else format. @xref{Line formats}.
+
+@item -p
+Show which C function each change is in.
+
+@item --rcs
+Output RCS-format diffs; like @samp{-f} except that each command
+specifies the number of lines affected.
+
+@item --report-identical-files
+@itemx -s
+Report when two files are the same.
+
+@item --show-c-function
+Show which C function each change is in.
+
+@item --show-function-line=@var{regexp}
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches @var{regexp}.
+
+@item --side-by-side
+Use the side by side output format.
+
+@item --speed-large-files
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+
+@item --suppress-common-lines
+Do not print common lines in side by side format.
+
+@item -t
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+
+@item -T
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+
+@item --text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+
+@item -u
+Use the unified output format.
+
+@item --unchanged-group-format=@var{format}
+Use @var{format} to output a group of common lines taken from both files
+in if-then-else format. @xref{Line group formats}.
+
+@item --unchanged-line-format=@var{format}
+Use @var{format} to output a line common to both files in if-then-else
+format. @xref{Line formats}.
+
+@item -U @var{lines}
+@itemx --unified@r{[}=@var{lines}@r{]}
+Use the unified output format, showing @var{lines} (an integer) lines of
+context, or three if @var{lines} is not given.
+For proper operation, @code{patch} typically needs at least two lines of
+context.
+
+@item -w
+Ignore white space when comparing lines.
+
+@item -W @var{columns}
+@itemx --width=@var{columns}
+Use an output width of @var{columns} in side by side format.
+
+@item -y
+Use the side by side output format.
+@end table
+
+@menu
+* Line group formats:: Line group formats
+* Line formats:: Line formats
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node Line group formats
+@appendixsubsubsec Line group formats
+
+Line group formats let you specify formats suitable for many
+applications that allow if-then-else input, including programming
+languages and text formatting languages. A line group format specifies
+the output format for a contiguous group of similar lines.
+
+For example, the following command compares the TeX file @file{myfile}
+with the original version from the repository,
+and outputs a merged file in which old regions are
+surrounded by @samp{\begin@{em@}}-@samp{\end@{em@}} lines, and new
+regions are surrounded by @samp{\begin@{bf@}}-@samp{\end@{bf@}} lines.
+
+@example
+cvs diff \
+ --old-group-format='\begin@{em@}
+%<\end@{em@}
+' \
+ --new-group-format='\begin@{bf@}
+%>\end@{bf@}
+' \
+ myfile
+@end example
+
+The following command is equivalent to the above example, but it is a
+little more verbose, because it spells out the default line group formats.
+
+@example
+cvs diff \
+ --old-group-format='\begin@{em@}
+%<\end@{em@}
+' \
+ --new-group-format='\begin@{bf@}
+%>\end@{bf@}
+' \
+ --unchanged-group-format='%=' \
+ --changed-group-format='\begin@{em@}
+%<\end@{em@}
+\begin@{bf@}
+%>\end@{bf@}
+' \
+ myfile
+@end example
+
+Here is a more advanced example, which outputs a diff listing with
+headers containing line numbers in a ``plain English'' style.
+
+@example
+cvs diff \
+ --unchanged-group-format='' \
+ --old-group-format='-------- %dn line%(n=1?:s) deleted at %df:
+%<' \
+ --new-group-format='-------- %dN line%(N=1?:s) added after %de:
+%>' \
+ --changed-group-format='-------- %dn line%(n=1?:s) changed at %df:
+%<-------- to:
+%>' \
+ myfile
+@end example
+
+To specify a line group format, use one of the options
+listed below. You can specify up to four line group formats, one for
+each kind of line group. You should quote @var{format}, because it
+typically contains shell metacharacters.
+
+@table @samp
+@item --old-group-format=@var{format}
+These line groups are hunks containing only lines from the first file.
+The default old group format is the same as the changed group format if
+it is specified; otherwise it is a format that outputs the line group as-is.
+
+@item --new-group-format=@var{format}
+These line groups are hunks containing only lines from the second
+file. The default new group format is same as the changed group
+format if it is specified; otherwise it is a format that outputs the
+line group as-is.
+
+@item --changed-group-format=@var{format}
+These line groups are hunks containing lines from both files. The
+default changed group format is the concatenation of the old and new
+group formats.
+
+@item --unchanged-group-format=@var{format}
+These line groups contain lines common to both files. The default
+unchanged group format is a format that outputs the line group as-is.
+@end table
+
+In a line group format, ordinary characters represent themselves;
+conversion specifications start with @samp{%} and have one of the
+following forms.
+
+@table @samp
+@item %<
+stands for the lines from the first file, including the trailing newline.
+Each line is formatted according to the old line format (@pxref{Line formats}).
+
+@item %>
+stands for the lines from the second file, including the trailing newline.
+Each line is formatted according to the new line format.
+
+@item %=
+stands for the lines common to both files, including the trailing newline.
+Each line is formatted according to the unchanged line format.
+
+@item %%
+stands for @samp{%}.
+
+@item %c'@var{C}'
+where @var{C} is a single character, stands for @var{C}.
+@var{C} may not be a backslash or an apostrophe.
+For example, @samp{%c':'} stands for a colon, even inside
+the then-part of an if-then-else format, which a colon would
+normally terminate.
+
+@item %c'\@var{O}'
+where @var{O} is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code @var{O}.
+For example, @samp{%c'\0'} stands for a null character.
+
+@item @var{F}@var{n}
+where @var{F} is a @code{printf} conversion specification and @var{n} is one
+of the following letters, stands for @var{n}'s value formatted with @var{F}.
+
+@table @samp
+@item e
+The line number of the line just before the group in the old file.
+
+@item f
+The line number of the first line in the group in the old file;
+equals @var{e} + 1.
+
+@item l
+The line number of the last line in the group in the old file.
+
+@item m
+The line number of the line just after the group in the old file;
+equals @var{l} + 1.
+
+@item n
+The number of lines in the group in the old file; equals @var{l} - @var{f} + 1.
+
+@item E, F, L, M, N
+Likewise, for lines in the new file.
+
+@end table
+
+The @code{printf} conversion specification can be @samp{%d},
+@samp{%o}, @samp{%x}, or @samp{%X}, specifying decimal, octal,
+lower case hexadecimal, or upper case hexadecimal output
+respectively. After the @samp{%} the following options can appear in
+sequence: a @samp{-} specifying left-justification; an integer
+specifying the minimum field width; and a period followed by an
+optional integer specifying the minimum number of digits.
+For example, @samp{%5dN} prints the number of new lines in the group
+in a field of width 5 characters, using the @code{printf} format @code{"%5d"}.
+
+@item (@var{A}=@var{B}?@var{T}:@var{E})
+If @var{A} equals @var{B} then @var{T} else @var{E}.
+@var{A} and @var{B} are each either a decimal constant
+or a single letter interpreted as above.
+This format spec is equivalent to @var{T} if
+@var{A}'s value equals @var{B}'s; otherwise it is equivalent to @var{E}.
+
+For example, @samp{%(N=0?no:%dN) line%(N=1?:s)} is equivalent to
+@samp{no lines} if @var{N} (the number of lines in the group in the
+new file) is 0, to @samp{1 line} if @var{N} is 1, and to @samp{%dN lines}
+otherwise.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node Line formats
+@appendixsubsubsec Line formats
+
+Line formats control how each line taken from an input file is
+output as part of a line group in if-then-else format.
+
+For example, the following command outputs text with a one-column
+change indicator to the left of the text. The first column of output
+is @samp{-} for deleted lines, @samp{|} for added lines, and a space
+for unchanged lines. The formats contain newline characters where
+newlines are desired on output.
+
+@example
+cvs diff \
+ --old-line-format='-%l
+' \
+ --new-line-format='|%l
+' \
+ --unchanged-line-format=' %l
+' \
+ myfile
+@end example
+
+To specify a line format, use one of the following options. You should
+quote @var{format}, since it often contains shell metacharacters.
+
+@table @samp
+@item --old-line-format=@var{format}
+formats lines just from the first file.
+
+@item --new-line-format=@var{format}
+formats lines just from the second file.
+
+@item --unchanged-line-format=@var{format}
+formats lines common to both files.
+
+@item --line-format=@var{format}
+formats all lines; in effect, it sets all three above options simultaneously.
+@end table
+
+In a line format, ordinary characters represent themselves;
+conversion specifications start with @samp{%} and have one of the
+following forms.
+
+@table @samp
+@item %l
+stands for the contents of the line, not counting its trailing
+newline (if any). This format ignores whether the line is incomplete.
+
+@item %L
+stands for the contents of the line, including its trailing newline
+(if any). If a line is incomplete, this format preserves its
+incompleteness.
+
+@item %%
+stands for @samp{%}.
+
+@item %c'@var{C}'
+where @var{C} is a single character, stands for @var{C}.
+@var{C} may not be a backslash or an apostrophe.
+For example, @samp{%c':'} stands for a colon.
+
+@item %c'\@var{O}'
+where @var{O} is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code @var{O}.
+For example, @samp{%c'\0'} stands for a null character.
+
+@item @var{F}n
+where @var{F} is a @code{printf} conversion specification,
+stands for the line number formatted with @var{F}.
+For example, @samp{%.5dn} prints the line number using the
+@code{printf} format @code{"%.5d"}. @xref{Line group formats}, for
+more about printf conversion specifications.
+
+@end table
+
+The default line format is @samp{%l} followed by a newline character.
+
+If the input contains tab characters and it is important that they line
+up on output, you should ensure that @samp{%l} or @samp{%L} in a line
+format is just after a tab stop (e.g.@: by preceding @samp{%l} or
+@samp{%L} with a tab character), or you should use the @samp{-t} or
+@samp{--expand-tabs} option.
+
+Taken together, the line and line group formats let you specify many
+different formats. For example, the following command uses a format
+similar to @code{diff}'s normal format. You can tailor this command
+to get fine control over @code{diff}'s output.
+
+@example
+cvs diff \
+ --old-line-format='< %l
+' \
+ --new-line-format='> %l
+' \
+ --old-group-format='%df%(f=l?:,%dl)d%dE
+%<' \
+ --new-group-format='%dea%dF%(F=L?:,%dL)
+%>' \
+ --changed-group-format='%df%(f=l?:,%dl)c%dF%(F=L?:,%dL)
+%<---
+%>' \
+ --unchanged-group-format='' \
+ myfile
+@end example
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node diff examples
+@appendixsubsec diff examples
+
+The following line produces a Unidiff (@samp{-u} flag)
+between revision 1.14 and 1.19 of
+@file{backend.c}. Due to the @samp{-kk} flag no
+keywords are substituted, so differences that only depend
+on keyword substitution are ignored.
+
+@example
+$ cvs diff -kk -u -r 1.14 -r 1.19 backend.c
+@end example
+
+Suppose the experimental branch EXPR1 was based on a
+set of files tagged RELEASE_1_0. To see what has
+happened on that branch, the following can be used:
+
+@example
+$ cvs diff -r RELEASE_1_0 -r EXPR1
+@end example
+
+A command like this can be used to produce a context
+diff between two releases:
+
+@example
+$ cvs diff -c -r RELEASE_1_0 -r RELEASE_1_1 > diffs
+@end example
+
+If you are maintaining ChangeLogs, a command like the following
+just before you commit your changes may help you write
+the ChangeLog entry. All local modifications that have
+not yet been committed will be printed.
+
+@example
+$ cvs diff -u | less
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node export
+@appendixsec export---Export sources from CVS, similar to checkout
+@cindex export (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: export [-flNnR] (-r rev[:date] | -D date) [-k subst] [-d dir] module@dots{}
+@item
+Requires: repository.
+@item
+Changes: current directory.
+@end itemize
+
+This command is a variant of @code{checkout}; use it
+when you want a copy of the source for module without
+the @sc{cvs} administrative directories. For example, you
+might use @code{export} to prepare source for shipment
+off-site. This command requires that you specify a
+date or tag (with @samp{-D} or @samp{-r}), so that you
+can count on reproducing the source you ship to others
+(and thus it always prunes empty directories).
+
+One often would like to use @samp{-kv} with @code{cvs
+export}. This causes any keywords to be
+expanded such that an import done at some other site
+will not lose the keyword revision information. But be
+aware that doesn't handle an export containing binary
+files correctly. Also be aware that after having used
+@samp{-kv}, one can no longer use the @code{ident}
+command (which is part of the @sc{rcs} suite---see
+ident(1)) which looks for keyword strings. If
+you want to be able to use @code{ident} you must not
+use @samp{-kv}.
+
+@menu
+* export options:: export options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node export options
+@appendixsubsec export options
+
+These standard options are supported by @code{export}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+
+@item -f
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any checkout program.
+
+@item -R
+Export directories recursively. This is on by default.
+
+@item -r @var{tag}[:@var{date}]
+Export the revision specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+@end table
+
+In addition, these options (that are common to
+@code{checkout} and @code{export}) are also supported:
+
+@table @code
+@item -d @var{dir}
+Create a directory called @var{dir} for the working
+files, instead of using the module name.
+@xref{checkout options}, for complete details on how
+@sc{cvs} handles this flag.
+
+@item -k @var{subst}
+Set keyword expansion mode (@pxref{Substitution modes}).
+
+@item -N
+Only useful together with @samp{-d @var{dir}}.
+@xref{checkout options}, for complete details on how
+@sc{cvs} handles this flag.
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node export examples
+@appendixsubsec export examples
+
+Contributed examples are gratefully accepted.
+@c -- Examples here!!
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node history
+@appendixsec history---Show status of files and users
+@cindex history (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: history [-report] [-flags] [-options args] [files@dots{}]
+@item
+Requires: the file @file{$CVSROOT/CVSROOT/history}
+@item
+Changes: nothing.
+@end itemize
+
+@sc{cvs} can keep a history log that tracks each use of most @sc{cvs}
+commands. You can use @code{history} to display this information in
+various formats.
+
+To enable logging, the @samp{LogHistory} config option must be set to
+some value other than the empty string and the history file specified by
+the @samp{HistoryLogPath} option must be writable by all users who may run
+the @sc{cvs} executable (@pxref{config}).
+
+To enable the @code{history} command, logging must be enabled as above and
+the @samp{HistorySearchPath} config option (@pxref{config}) must be set to
+specify some number of the history logs created thereby and these files must
+be readable by each user who might run the @code{history} command.
+
+Creating a repository via the @code{cvs init} command will enable logging of
+all possible events to a single history log file
+(@file{$CVSROOT/CVSROOT/history}) with read and write permissions for all
+users (@pxref{Creating a repository}).
+
+@strong{Note: @code{history} uses @samp{-f}, @samp{-l},
+@samp{-n}, and @samp{-p} in ways that conflict with the
+normal use inside @sc{cvs} (@pxref{Common options}).}
+
+@menu
+* history options:: history options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node history options
+@appendixsubsec history options
+
+Several options (shown above as @samp{-report}) control what
+kind of report is generated:
+
+@table @code
+@item -c
+Report on each time commit was used (i.e., each time
+the repository was modified).
+
+@item -e
+Everything (all record types). Equivalent to
+specifying @samp{-x} with all record types. Of course,
+@samp{-e} will also include record types which are
+added in a future version of @sc{cvs}; if you are
+writing a script which can only handle certain record
+types, you'll want to specify @samp{-x}.
+
+@item -m @var{module}
+Report on a particular module. (You can meaningfully
+use @samp{-m} more than once on the command line.)
+
+@item -o
+Report on checked-out modules. This is the default report type.
+
+@item -T
+Report on all tags.
+
+@item -x @var{type}
+Extract a particular set of record types @var{type} from the @sc{cvs}
+history. The types are indicated by single letters,
+which you may specify in combination.
+
+Certain commands have a single record type:
+
+@table @code
+@item F
+release
+@item O
+checkout
+@item E
+export
+@item T
+rtag
+@end table
+
+@noindent
+One of five record types may result from an update:
+
+@table @code
+@item C
+A merge was necessary but collisions were
+detected (requiring manual merging).
+@item G
+A merge was necessary and it succeeded.
+@item U
+A working file was copied from the repository.
+@item P
+A working file was patched to match the repository.
+@item W
+The working copy of a file was deleted during
+update (because it was gone from the repository).
+@end table
+
+@noindent
+One of three record types results from commit:
+
+@table @code
+@item A
+A file was added for the first time.
+@item M
+A file was modified.
+@item R
+A file was removed.
+@end table
+@end table
+
+The options shown as @samp{-flags} constrain or expand
+the report without requiring option arguments:
+
+@table @code
+@item -a
+Show data for all users (the default is to show data
+only for the user executing @code{history}).
+
+@item -l
+Show last modification only.
+
+@item -w
+Show only the records for modifications done from the
+same working directory where @code{history} is
+executing.
+@end table
+
+The options shown as @samp{-options @var{args}} constrain the report
+based on an argument:
+
+@table @code
+@item -b @var{str}
+Show data back to a record containing the string
+@var{str} in either the module name, the file name, or
+the repository path.
+
+@item -D @var{date}
+Show data since @var{date}. This is slightly different
+from the normal use of @samp{-D @var{date}}, which
+selects the newest revision older than @var{date}.
+
+@item -f @var{file}
+Show data for a particular file
+(you can specify several @samp{-f} options on the same command line).
+This is equivalent to specifying the file on the command line.
+
+@item -n @var{module}
+Show data for a particular module
+(you can specify several @samp{-n} options on the same command line).
+
+@item -p @var{repository}
+Show data for a particular source repository (you
+can specify several @samp{-p} options on the same command
+line).
+
+@item -r @var{rev}
+Show records referring to revisions since the revision
+or tag named @var{rev} appears in individual @sc{rcs}
+files. Each @sc{rcs} file is searched for the revision or
+tag.
+
+@item -t @var{tag}
+Show records since tag @var{tag} was last added to the
+history file. This differs from the @samp{-r} flag
+above in that it reads only the history file, not the
+@sc{rcs} files, and is much faster.
+
+@item -u @var{name}
+Show records for user @var{name}.
+
+@item -z @var{timezone}
+Show times in the selected records using the specified
+time zone instead of UTC.
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node history examples
+@appendixsubsec history examples
+
+Contributed examples will gratefully be accepted.
+@c -- Examples here!
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node import
+@appendixsec import---Import sources into CVS, using vendor branches
+@cindex import (subcommand)
+
+@c FIXME: This node is way too long for one which has subnodes.
+
+@itemize @bullet
+@item
+Synopsis: import [-options] repository vendortag releasetag@dots{}
+@item
+Requires: Repository, source distribution directory.
+@item
+Changes: repository.
+@end itemize
+
+Use @code{import} to incorporate an entire source
+distribution from an outside source (e.g., a source
+vendor) into your source repository directory. You can
+use this command both for initial creation of a
+repository, and for wholesale updates to the module
+from the outside source. @xref{Tracking sources}, for
+a discussion on this subject.
+
+The @var{repository} argument gives a directory name
+(or a path to a directory) under the @sc{cvs} root directory
+for repositories; if the directory did not exist,
+import creates it.
+
+When you use import for updates to source that has been
+modified in your source repository (since a prior
+import), it will notify you of any files that conflict
+in the two branches of development; use @samp{checkout
+-j} to reconcile the differences, as import instructs
+you to do.
+
+If @sc{cvs} decides a file should be ignored
+(@pxref{cvsignore}), it does not import it and prints
+@samp{I } followed by the filename (@pxref{import output}, for a
+complete description of the output).
+
+If the file @file{$CVSROOT/CVSROOT/cvswrappers} exists,
+any file whose names match the specifications in that
+file will be treated as packages and the appropriate
+filtering will be performed on the file/directory
+before being imported. @xref{Wrappers}.
+
+The outside source is saved in a first-level
+branch, by default 1.1.1. Updates are leaves of this
+branch; for example, files from the first imported
+collection of source will be revision 1.1.1.1, then
+files from the first imported update will be revision
+1.1.1.2, and so on.
+
+At least three arguments are required.
+@var{repository} is needed to identify the collection
+of source. @var{vendortag} is a tag for the entire
+branch (e.g., for 1.1.1). You must also specify at
+least one @var{releasetag} to uniquely identify the files at
+the leaves created each time you execute @code{import}. The
+@var{releasetag} should be new, not previously existing in the
+repository file, and uniquely identify the imported release,
+
+@c I'm not completely sure this belongs here. But
+@c we need to say it _somewhere_ reasonably obvious; it
+@c is a common misconception among people first learning CVS
+Note that @code{import} does @emph{not} change the
+directory in which you invoke it. In particular, it
+does not set up that directory as a @sc{cvs} working
+directory; if you want to work with the sources import
+them first and then check them out into a different
+directory (@pxref{Getting the source}).
+
+@menu
+* import options:: import options
+* import output:: import output
+* import examples:: import examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import options
+@appendixsubsec import options
+
+This standard option is supported by @code{import}
+(@pxref{Common options}, for a complete description):
+
+@table @code
+@item -m @var{message}
+Use @var{message} as log information, instead of
+invoking an editor.
+@end table
+
+There are the following additional special options.
+
+@table @code
+@item -b @var{branch}
+See @ref{Multiple vendor branches}.
+
+@item -k @var{subst}
+Indicate the keyword expansion mode desired. This
+setting will apply to all files created during the
+import, but not to any files that previously existed in
+the repository. See @ref{Substitution modes}, for a
+list of valid @samp{-k} settings.
+
+@item -I @var{name}
+Specify file names that should be ignored during
+import. You can use this option repeatedly. To avoid
+ignoring any files at all (even those ignored by
+default), specify `-I !'.
+
+@var{name} can be a file name pattern of the same type
+that you can specify in the @file{.cvsignore} file.
+@xref{cvsignore}.
+@c -- Is this really true?
+
+@item -W @var{spec}
+Specify file names that should be filtered during
+import. You can use this option repeatedly.
+
+@var{spec} can be a file name pattern of the same type
+that you can specify in the @file{.cvswrappers}
+file. @xref{Wrappers}.
+
+@item -X
+Modify the algorithm used by @sc{cvs} when importing new files
+so that new files do not immediately appear on the main trunk.
+
+Specifically, this flag causes @sc{cvs} to mark new files as
+if they were deleted on the main trunk, by taking the following
+steps for each file in addition to those normally taken on import:
+creating a new revision on the main trunk indicating that
+the new file is @code{dead}, resetting the new file's default branch,
+and placing the file in the Attic (@pxref{Attic}) directory.
+
+Use of this option can be forced on a repository-wide basis
+by setting the @samp{ImportNewFilesToVendorBranchOnly} option in
+CVSROOT/config (@pxref{config}).
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import output
+@appendixsubsec import output
+
+@code{import} keeps you informed of its progress by printing a line
+for each file, preceded by one character indicating the status of the file:
+
+@table @code
+@item U @var{file}
+The file already exists in the repository and has not been locally
+modified; a new revision has been created (if necessary).
+
+@item N @var{file}
+The file is a new file which has been added to the repository.
+
+@item C @var{file}
+The file already exists in the repository but has been locally modified;
+you will have to merge the changes.
+
+@item I @var{file}
+The file is being ignored (@pxref{cvsignore}).
+
+@cindex Symbolic link, importing
+@cindex Link, symbolic, importing
+@c FIXME: also (somewhere else) probably
+@c should be documenting what happens if you "cvs add"
+@c a symbolic link. Also maybe what happens if
+@c you manually create symbolic links within the
+@c repository (? - not sure why we'd want to suggest
+@c doing that).
+@item L @var{file}
+The file is a symbolic link; @code{cvs import} ignores symbolic links.
+People periodically suggest that this behavior should
+be changed, but if there is a consensus on what it
+should be changed to, it is not apparent.
+(Various options in the @file{modules} file can be used
+to recreate symbolic links on checkout, update, etc.;
+@pxref{modules}.)
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import examples
+@appendixsubsec import examples
+
+See @ref{Tracking sources}, and @ref{From files}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node log
+@appendixsec log---Print out log information for files
+@cindex log (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: log [options] [files@dots{}]
+@item
+Requires: repository, working directory.
+@item
+Changes: nothing.
+@end itemize
+
+Display log information for files. @code{log} used to
+call the @sc{rcs} utility @code{rlog}. Although this
+is no longer true in the current sources, this history
+determines the format of the output and the options,
+which are not quite in the style of the other @sc{cvs}
+commands.
+
+@cindex Timezone, in output
+@cindex Zone, time, in output
+The output includes the location of the @sc{rcs} file,
+the @dfn{head} revision (the latest revision on the
+trunk), all symbolic names (tags) and some other
+things. For each revision, the revision number, the
+date, the author, the number of lines added/deleted, the commitid
+and the log message are printed. All dates are displayed
+in local time at the client. This is typically specified in
+the @code{$TZ} environment variable, which can be set to
+govern how @code{log} displays dates.
+
+@strong{Note: @code{log} uses @samp{-R} in a way that conflicts
+with the normal use inside @sc{cvs} (@pxref{Common options}).}
+
+@menu
+* log options:: log options
+* log examples:: log examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node log options
+@appendixsubsec log options
+
+By default, @code{log} prints all information that is
+available. All other options restrict the output. Note that the revision
+selection options (@code{-d}, @code{-r}, @code{-s}, and @code{-w}) have no
+effect, other than possibly causing a search for files in Attic directories,
+when used in conjunction with the options that restrict the output to only
+@code{log} header fields (@code{-b}, @code{-h}, @code{-R}, and @code{-t})
+unless the @code{-S} option is also specified.
+
+@table @code
+@item -b
+Print information about the revisions on the default
+branch, normally the highest branch on the trunk.
+
+@item -d @var{dates}
+Print information about revisions with a checkin
+date/time in the range given by the
+semicolon-separated list of dates. The date formats
+accepted are those accepted by the @samp{-D} option to
+many other @sc{cvs} commands (@pxref{Common options}).
+Dates can be combined into ranges as follows:
+
+@c Should we be thinking about accepting ISO8601
+@c ranges? For example "1972-09-10/1972-09-12".
+@table @code
+@item @var{d1}<@var{d2}
+@itemx @var{d2}>@var{d1}
+Select the revisions that were deposited between
+@var{d1} and @var{d2}.
+
+@item <@var{d}
+@itemx @var{d}>
+Select all revisions dated @var{d} or earlier.
+
+@item @var{d}<
+@itemx >@var{d}
+Select all revisions dated @var{d} or later.
+
+@item @var{d}
+Select the single, latest revision dated @var{d} or
+earlier.
+@end table
+
+The @samp{>} or @samp{<} characters may be followed by
+@samp{=} to indicate an inclusive range rather than an
+exclusive one.
+
+Note that the separator is a semicolon (;).
+
+@item -h
+Print only the name of the @sc{rcs} file, name
+of the file in the working directory, head,
+default branch, access list, locks, symbolic names, and
+suffix.
+
+@item -l
+Local; run only in current working directory. (Default
+is to run recursively).
+
+@item -N
+Do not print the list of tags for this file. This
+option can be very useful when your site uses a lot of
+tags, so rather than "more"'ing over 3 pages of tag
+information, the log information is presented without
+tags at all.
+
+@item -R
+Print only the name of the @sc{rcs} file.
+
+@c Note that using a bare revision (in addition to not
+@c being explicitly documented here) is potentially
+@c confusing; it shows the log message to get from the
+@c previous revision to that revision. "-r1.3 -r1.6"
+@c (equivalent to "-r1.3,1.6") is even worse; it
+@c prints the messages to get from 1.2 to 1.3 and 1.5
+@c to 1.6. By analogy with "cvs diff", users might
+@c expect that it is more like specifying a range.
+@c It is not 100% clear to me how much of this should
+@c be documented (for example, multiple -r options
+@c perhaps could/should be deprecated given the false
+@c analogy with "cvs diff").
+@c In general, this section should be rewritten to talk
+@c about messages to get from revision rev1 to rev2,
+@c rather than messages for revision rev2 (that is, the
+@c messages are associated with a change not a static
+@c revision and failing to make this distinction causes
+@c much confusion).
+@item -r@var{revisions}
+Print information about revisions given in the
+comma-separated list @var{revisions} of revisions and
+ranges. The following table explains the available
+range formats:
+
+@table @code
+@item @var{rev1}:@var{rev2}
+Revisions @var{rev1} to @var{rev2} (which must be on
+the same branch).
+
+@item @var{rev1}::@var{rev2}
+The same, but excluding @var{rev1}.
+
+@item :@var{rev}
+@itemx ::@var{rev}
+Revisions from the beginning of the branch up to
+and including @var{rev}.
+
+@item @var{rev}:
+Revisions starting with @var{rev} to the end of the
+branch containing @var{rev}.
+
+@item @var{rev}::
+Revisions starting just after @var{rev} to the end of the
+branch containing @var{rev}.
+
+@item @var{branch}
+An argument that is a branch means all revisions on
+that branch.
+
+@item @var{branch1}:@var{branch2}
+@itemx @var{branch1}::@var{branch2}
+A range of branches means all revisions
+on the branches in that range.
+
+@item @var{branch}.
+The latest revision in @var{branch}.
+@end table
+
+A bare @samp{-r} with no revisions means the latest
+revision on the default branch, normally the trunk.
+There can be no space between the @samp{-r} option and
+its argument.
+
+@item -S
+Suppress the header if no revisions are selected.
+
+@item -s @var{states}
+Print information about revisions whose state
+attributes match one of the states given in the
+comma-separated list @var{states}. Individual states may
+be any text string, though @sc{cvs} commonly only uses two
+states, @samp{Exp} and @samp{dead}. See @ref{admin options}
+for more information.
+
+@item -t
+Print the same as @samp{-h}, plus the descriptive text.
+
+@item -w@var{logins}
+Print information about revisions checked in by users
+with login names appearing in the comma-separated list
+@var{logins}. If @var{logins} is omitted, the user's
+login is assumed. There can be no space between the
+@samp{-w} option and its argument.
+@end table
+
+@code{log} prints the intersection of the revisions
+selected with the options @samp{-d}, @samp{-s}, and
+@samp{-w}, intersected with the union of the revisions
+selected by @samp{-b} and @samp{-r}.
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node log examples
+@appendixsubsec log examples
+
+@cindex Timezone, in output
+@cindex Zone, time, in output
+Since @code{log} shows dates in local time,
+you might want to see them in Coordinated Universal Time (UTC) or
+some other timezone.
+To do this you can set your @code{$TZ} environment
+variable before invoking @sc{cvs}:
+
+@example
+$ TZ=UTC cvs log foo.c
+$ TZ=EST cvs log bar.c
+@end example
+
+(If you are using a @code{csh}-style shell, like @code{tcsh},
+you would need to prefix the examples above with @code{env}.)
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node ls & rls
+@appendixsec ls & rls
+@cindex ls (subcommand)
+@cindex rls (subcommand)
+
+@itemize @bullet
+@item
+ls [-e | -l] [-RP] [-r tag[:date]] [-D date] [path@dots{}]
+@item
+Requires: repository for @code{rls}, repository & working directory for
+@code{ls}.
+@item
+Changes: nothing.
+@item
+Synonym: @code{dir} & @code{list} are synonyms for @code{ls} and @code{rdir}
+& @code{rlist} are synonyms for @code{rls}.
+@end itemize
+
+The @code{ls} and @code{rls} commands are used to list
+files and directories in the repository.
+
+By default @code{ls} lists the files and directories
+that belong in your working directory, what would be
+there after an @code{update}.
+
+By default @code{rls} lists the files and directories
+on the tip of the trunk in the topmost directory of the
+repository.
+
+Both commands accept an optional list of file and
+directory names, relative to the working directory for
+@code{ls} and the topmost directory of the repository
+for @code{rls}. Neither is recursive by default.
+
+@menu
+* ls & rls options:: ls & rls options
+* rls examples: rls examples
+@end menu
+
+@node ls & rls options
+@appendixsubsec ls & rls options
+
+These standard options are supported by @code{ls} & @code{rls}:
+
+@table @code
+@item -d
+Show dead revisions (with tag when specified).
+
+@item -e
+Display in CVS/Entries format. This format is meant to remain easily parsable
+by automation.
+
+@item -l
+Display all details.
+
+@item -P
+Don't list contents of empty directories when recursing.
+
+@item -R
+List recursively.
+
+@item -r @var{tag}[:@var{date}]
+Show files specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+
+@item -D @var{date}
+Show files from date.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rls examples
+@appendixsubsec rls examples
+
+@example
+$ cvs rls
+cvs rls: Listing module: `.'
+CVSROOT
+first-dir
+@end example
+
+@example
+$ cvs rls CVSROOT
+cvs rls: Listing module: `CVSROOT'
+checkoutlist
+commitinfo
+config
+cvswrappers
+loginfo
+modules
+notify
+rcsinfo
+taginfo
+verifymsg
+
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node rdiff
+@appendixsec rdiff---'patch' format diffs between releases
+@cindex rdiff (subcommand)
+
+@itemize @bullet
+@item
+rdiff [-flags] [-V vn] (-r tag1[:date1] | -D date1) [-r tag2[:date2] | -D date2] modules@dots{}
+@item
+Requires: repository.
+@item
+Changes: nothing.
+@item
+Synonym: patch
+@end itemize
+
+Builds a Larry Wall format patch(1) file between two
+releases, that can be fed directly into the @code{patch}
+program to bring an old release up-to-date with the new
+release. (This is one of the few @sc{cvs} commands that
+operates directly from the repository, and doesn't
+require a prior checkout.) The diff output is sent to
+the standard output device.
+
+You can specify (using the standard @samp{-r} and
+@samp{-D} options) any combination of one or two
+revisions or dates. If only one revision or date is
+specified, the patch file reflects differences between
+that revision or date and the current head revisions in
+the @sc{rcs} file.
+
+Note that if the software release affected is contained
+in more than one directory, then it may be necessary to
+specify the @samp{-p} option to the @code{patch} command when
+patching the old sources, so that @code{patch} is able to find
+the files that are located in other directories.
+
+@menu
+* rdiff options:: rdiff options
+* rdiff examples:: rdiff examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rdiff options
+@appendixsubsec rdiff options
+
+These standard options are supported by @code{rdiff}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+
+@item -f
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+
+@item -k @var{kflag}
+Process keywords according to @var{kflag}. See
+@ref{Keyword substitution}.
+
+@item -l
+Local; don't descend subdirectories.
+
+@item -R
+Examine directories recursively. This option is on by default.
+
+@item -r @var{tag}
+Use the revision specified by @var{tag}, or when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+@end table
+
+In addition to the above, these options are available:
+
+@table @code
+@item -c
+Use the context diff format. This is the default format.
+
+@item -s
+Create a summary change report instead of a patch. The
+summary includes information about files that were
+changed or added between the releases. It is sent to
+the standard output device. This is useful for finding
+out, for example, which files have changed between two
+dates or revisions.
+
+@item -t
+A diff of the top two revisions is sent to the standard
+output device. This is most useful for seeing what the
+last change to a file was.
+
+@item -u
+Use the unidiff format for the context diffs.
+Remember that old versions
+of the @code{patch} program can't handle the unidiff
+format, so if you plan to post this patch to the net
+you should probably not use @samp{-u}.
+
+@item -V @var{vn}
+Expand keywords according to the rules current in
+@sc{rcs} version @var{vn} (the expansion format changed with
+@sc{rcs} version 5). Note that this option is no
+longer accepted. @sc{cvs} will always expand keywords the
+way that @sc{rcs} version 5 does.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rdiff examples
+@appendixsubsec rdiff examples
+
+Suppose you receive mail from @t{foo@@example.net} asking for an
+update from release 1.2 to 1.4 of the tc compiler. You
+have no such patches on hand, but with @sc{cvs} that can
+easily be fixed with a command such as this:
+
+@example
+$ cvs rdiff -c -r FOO1_2 -r FOO1_4 tc | \
+$$ Mail -s 'The patches you asked for' foo@@example.net
+@end example
+
+Suppose you have made release 1.3, and forked a branch
+called @samp{R_1_3fix} for bug fixes. @samp{R_1_3_1}
+corresponds to release 1.3.1, which was made some time
+ago. Now, you want to see how much development has been
+done on the branch. This command can be used:
+
+@example
+$ cvs patch -s -r R_1_3_1 -r R_1_3fix module-name
+cvs rdiff: Diffing module-name
+File ChangeLog,v changed from revision 1.52.2.5 to 1.52.2.6
+File foo.c,v changed from revision 1.52.2.3 to 1.52.2.4
+File bar.h,v changed from revision 1.29.2.1 to 1.2
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node release
+@appendixsec release---Indicate that a Module is no longer in use
+@cindex release (subcommand)
+
+@itemize @bullet
+@item
+release [-d] directories@dots{}
+@item
+Requires: Working directory.
+@item
+Changes: Working directory, history log.
+@end itemize
+
+This command is meant to safely cancel the effect of
+@samp{cvs checkout}. Since @sc{cvs} doesn't lock files, it
+isn't strictly necessary to use this command. You can
+always simply delete your working directory, if you
+like; but you risk losing changes you may have
+forgotten, and you leave no trace in the @sc{cvs} history
+file (@pxref{history file}) that you've abandoned your
+checkout.
+
+Use @samp{cvs release} to avoid these problems. This
+command checks that no uncommitted changes are
+present; that you are executing it from immediately
+above a @sc{cvs} working directory; and that the repository
+recorded for your files is the same as the repository
+defined in the module database.
+
+If all these conditions are true, @samp{cvs release}
+leaves a record of its execution (attesting to your
+intentionally abandoning your checkout) in the @sc{cvs}
+history log.
+
+@menu
+* release options:: release options
+* release output:: release output
+* release examples:: release examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release options
+@appendixsubsec release options
+
+The @code{release} command supports one command option:
+
+@table @code
+@item -d
+Delete your working copy of the file if the release
+succeeds. If this flag is not given your files will
+remain in your working directory.
+
+@strong{WARNING: The @code{release} command deletes
+all directories and files recursively. This
+has the very serious side-effect that any directory
+that you have created inside your checked-out sources,
+and not added to the repository (using the @code{add}
+command; @pxref{Adding files}) will be silently deleted---even
+if it is non-empty!}
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release output
+@appendixsubsec release output
+
+Before @code{release} releases your sources it will
+print a one-line message for any file that is not
+up-to-date.
+
+@table @code
+@item U @var{file}
+@itemx P @var{file}
+There exists a newer revision of this file in the
+repository, and you have not modified your local copy
+of the file (@samp{U} and @samp{P} mean the same thing).
+
+@item A @var{file}
+The file has been added to your private copy of the
+sources, but has not yet been committed to the
+repository. If you delete your copy of the sources
+this file will be lost.
+
+@item R @var{file}
+The file has been removed from your private copy of the
+sources, but has not yet been removed from the
+repository, since you have not yet committed the
+removal. @xref{commit}.
+
+@item M @var{file}
+The file is modified in your working directory. There
+might also be a newer revision inside the repository.
+
+@item ? @var{file}
+@var{file} is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for @sc{cvs} to ignore (see the
+description of the @samp{-I} option, and
+@pxref{cvsignore}). If you remove your working
+sources, this file will be lost.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release examples
+@appendixsubsec release examples
+
+Release the @file{tc} directory, and delete your local working copy
+of the files.
+
+@example
+$ cd .. # @r{You must stand immediately above the}
+ # @r{sources when you issue @samp{cvs release}.}
+$ cvs release -d tc
+You have [0] altered files in this repository.
+Are you sure you want to release (and delete) directory `tc': y
+$
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node server & pserver
+@appendixsec server & pserver---Act as a server for a client on stdin/stdout
+@cindex pserver (subcommand)
+@cindex server (subcommand)
+
+@itemize @bullet
+@item
+pserver [-c path]
+
+server [-c path]
+@item
+Requires: repository, client conversation on stdin/stdout
+@item
+Changes: Repository or, indirectly, client working directory.
+@end itemize
+
+The @sc{cvs} @code{server} and @code{pserver} commands are used to provide
+repository access to remote clients and expect a client conversation on
+stdin & stdout. Typically these commands are launched from @code{inetd} or
+via @code{ssh} (@pxref{Remote repositories}).
+
+@code{server} expects that the client has already been authenticated somehow,
+typically via @sc{ssh}, and @code{pserver} attempts to authenticate the client
+itself.
+
+Only one option is available with the @code{server} and @code{pserver}
+commands:
+
+@cindex configuration file
+@table @code
+@item -c path
+Load configuration from @var{path} rather than the default location
+@file{$CVSROOT/CVSROOT/config} (@pxref{config}). @var{path} must be
+@file{/etc/cvs.conf} or prefixed by @file{/etc/cvs/}. This option is
+supported beginning with @sc{cvs} release 1.12.13.
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node update
+@appendixsec update---Bring work tree in sync with repository
+@cindex update (subcommand)
+
+@itemize @bullet
+@item
+update [-ACdflPpR] [-I name] [-j rev [-j rev]] [-k kflag] [-r tag[:date] | -D date] [-W spec] files@dots{}
+@item
+Requires: repository, working directory.
+@item
+Changes: working directory.
+@end itemize
+
+After you've run checkout to create your private copy
+of source from the common repository, other developers
+will continue changing the central source. From time
+to time, when it is convenient in your development
+process, you can use the @code{update} command from
+within your working directory to reconcile your work
+with any revisions applied to the source repository
+since your last checkout or update. Without the @code{-C}
+option, @code{update} will also merge any differences
+between the local copy of files and their base revisions
+into any destination revisions specified with @code{-r},
+@code{-D}, or @code{-A}.
+
+@menu
+* update options:: update options
+* update output:: update output
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node update options
+@appendixsubsec update options
+
+These standard options are available with @code{update}
+(@pxref{Common options}, for a complete description of
+them):
+
+@table @code
+@item -D date
+Use the most recent revision no later than @var{date}.
+This option is sticky, and implies @samp{-P}.
+See @ref{Sticky tags}, for more information on sticky tags/dates.
+
+@item -f
+Only useful with the @samp{-D} or @samp{-r} flags. If no matching revision
+is found, retrieve the most recent revision (instead of ignoring the file).
+
+@item -k @var{kflag}
+Process keywords according to @var{kflag}. See
+@ref{Keyword substitution}.
+This option is sticky; future updates of
+this file in this working directory will use the same
+@var{kflag}. The @code{status} command can be viewed
+to see the sticky options. See @ref{Invoking CVS}, for
+more information on the @code{status} command.
+
+@item -l
+Local; run only in current working directory. @xref{Recursive behavior}.
+
+@item -P
+Prune empty directories. See @ref{Moving directories}.
+
+@item -p
+Pipe files to the standard output.
+
+@item -R
+Update directories recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Retrieve the revisions specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. This option is sticky, and implies @samp{-P}.
+See @ref{Sticky tags}, for more information on sticky tags/dates. Also
+see @ref{Common options}.
+@end table
+
+@need 800
+These special options are also available with
+@code{update}.
+
+@table @code
+@item -A
+Reset any sticky tags, dates, or @samp{-k} options.
+See @ref{Sticky tags}, for more information on sticky tags/dates.
+
+@item -C
+Overwrite locally modified files with clean copies from
+the repository (the modified file is saved in
+@file{.#@var{file}.@var{revision}}, however).
+
+@item -d
+Create any directories that exist in the repository if
+they're missing from the working directory. Normally,
+@code{update} acts only on directories and files that
+were already enrolled in your working directory.
+
+This is useful for updating directories that were
+created in the repository since the initial checkout;
+but it has an unfortunate side effect. If you
+deliberately avoided certain directories in the
+repository when you created your working directory
+(either through use of a module name or by listing
+explicitly the files and directories you wanted on the
+command line), then updating with @samp{-d} will create
+those directories, which may not be what you want.
+
+@item -I @var{name}
+Ignore files whose names match @var{name} (in your
+working directory) during the update. You can specify
+@samp{-I} more than once on the command line to specify
+several files to ignore. Use @samp{-I !} to avoid
+ignoring any files at all. @xref{cvsignore}, for other
+ways to make @sc{cvs} ignore some files.
+
+@item -W@var{spec}
+Specify file names that should be filtered during
+update. You can use this option repeatedly.
+
+@var{spec} can be a file name pattern of the same type
+that you can specify in the @file{.cvswrappers}
+file. @xref{Wrappers}.
+
+@item -j@var{revision}
+With two @samp{-j} options, merge changes from the
+revision specified with the first @samp{-j} option to
+the revision specified with the second @samp{j} option,
+into the working directory.
+
+With one @samp{-j} option, merge changes from the
+ancestor revision to the revision specified with the
+@samp{-j} option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the @samp{-j} option.
+
+Note that using a single @samp{-j @var{tagname}} option rather than
+@samp{-j @var{branchname}} to merge changes from a branch will
+often not remove files which were removed on the branch.
+@xref{Merging adds and removals}, for more.
+
+In addition, each @samp{-j} option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}.
+
+@xref{Branching and merging}.
+
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node update output
+@appendixsubsec update output
+
+@code{update} and @code{checkout} keep you informed of
+their progress by printing a line for each file, preceded
+by one character indicating the status of the file:
+
+@table @code
+@item U @var{file}
+The file was brought up to date with respect to the
+repository. This is done for any file that exists in
+the repository but not in your working directory, and for files
+that you haven't changed but are not the most recent
+versions available in the repository.
+
+@item P @var{file}
+Like @samp{U}, but the @sc{cvs} server sends a patch instead of an entire
+file. This accomplishes the same thing as @samp{U} using less bandwidth.
+
+@item A @var{file}
+The file has been added to your private copy of the
+sources, and will be added to the source repository
+when you run @code{commit} on the file. This is a
+reminder to you that the file needs to be committed.
+
+@item R @var{file}
+The file has been removed from your private copy of the
+sources, and will be removed from the source repository
+when you run @code{commit} on the file. This is a
+reminder to you that the file needs to be committed.
+
+@item M @var{file}
+The file is modified in your working directory.
+
+@samp{M} can indicate one of two states for a file
+you're working on: either there were no modifications
+to the same file in the repository, so that your file
+remains as you last saw it; or there were modifications
+in the repository as well as in your copy, but they
+were merged successfully, without conflict, in your
+working directory.
+
+@sc{cvs} will print some messages if it merges your work,
+and a backup copy of your working file (as it looked
+before you ran @code{update}) will be made. The exact
+name of that file is printed while @code{update} runs.
+
+@item C @var{file}
+@cindex .# files
+@cindex __ files (VMS)
+A conflict was detected while trying to merge your
+changes to @var{file} with changes from the source
+repository. @var{file} (the copy in your working
+directory) is now the result of attempting to merge
+the two revisions; an unmodified copy of your file
+is also in your working directory, with the name
+@file{.#@var{file}.@var{revision}} where @var{revision}
+is the revision that your modified file started
+from. Resolve the conflict as described in
+@ref{Conflicts example}.
+@c "some systems" as in out-of-the-box OSes? Not as
+@c far as I know. We need to advise sysadmins as well
+@c as users how to set up this kind of purge, if that is
+@c what they want.
+@c We also might want to think about cleaner solutions,
+@c like having CVS remove the .# file once the conflict
+@c has been resolved or something like that.
+(Note that some systems automatically purge
+files that begin with @file{.#} if they have not been
+accessed for a few days. If you intend to keep a copy
+of your original file, it is a very good idea to rename
+it.) Under @sc{vms}, the file name starts with
+@file{__} rather than @file{.#}.
+
+@item ? @var{file}
+@var{file} is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for @sc{cvs} to ignore (see the
+description of the @samp{-I} option, and
+@pxref{cvsignore}).
+@end table
+
+@c ----- END MAN 1 -----
+@c ---------------------------------------------------------------------
+@node Invoking CVS
+@appendix Quick reference to CVS commands
+@cindex Command reference
+@cindex Reference, commands
+@cindex Invoking CVS
+
+This appendix describes how to invoke @sc{cvs}, with
+references to where each command or feature is
+described in detail. For other references run the
+@code{cvs --help} command, or see @ref{Index}.
+
+A @sc{cvs} command looks like:
+
+@example
+cvs [ @var{global_options} ] @var{command} [ @var{command_options} ] [ @var{command_args} ]
+@end example
+
+Global options:
+
+@table @code
+@item --allow-root=@var{rootdir}
+Specify legal @sc{cvsroot} directory (server only) (not
+in @sc{cvs} 1.9 and older). See @ref{Password
+authentication server}.
+
+@item -a
+Authenticate all communication (client only) (not in @sc{cvs}
+1.9 and older). See @ref{Global options}.
+
+@item -b
+Specify RCS location (@sc{cvs} 1.9 and older). See
+@ref{Global options}.
+
+@item -d @var{root}
+Specify the @sc{cvsroot}. See @ref{Repository}.
+
+@item -e @var{editor}
+Edit messages with @var{editor}. See @ref{Committing
+your changes}.
+
+@item -f
+Do not read the @file{~/.cvsrc} file. See @ref{Global
+options}.
+
+@item -H
+@itemx --help
+Print a help message. See @ref{Global options}.
+
+@item -n
+Do not change any files. See @ref{Global options}.
+
+@item -Q
+Be really quiet. See @ref{Global options}.
+
+@item -q
+Be somewhat quiet. See @ref{Global options}.
+
+@item -r
+Make new working files read-only. See @ref{Global options}.
+
+@item -s @var{variable}=@var{value}
+Set a user variable. See @ref{Variables}.
+
+@item -T @var{tempdir}
+Put temporary files in @var{tempdir}. See @ref{Global
+options}.
+
+@item -t
+Trace @sc{cvs} execution. See @ref{Global options}.
+
+@item -v
+@item --version
+Display version and copyright information for @sc{cvs}.
+
+@item -w
+Make new working files read-write. See @ref{Global
+options}.
+
+@item -x
+Encrypt all communication (client only).
+See @ref{Global options}.
+
+@item -z @var{gzip-level}
+@cindex Compression
+@cindex Gzip
+Set the compression level (client only).
+See @ref{Global options}.
+@end table
+
+Keyword expansion modes (@pxref{Substitution modes}):
+
+@example
+-kkv $@splitrcskeyword{Id}: file1,v 1.1 1993/12/09 03:21:13 joe Exp $
+-kkvl $@splitrcskeyword{Id}: file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+-kk $@splitrcskeyword{Id}$
+-kv file1,v 1.1 1993/12/09 03:21:13 joe Exp
+-ko @i{no expansion}
+-kb @i{no expansion, file is binary}
+@end example
+
+Keywords (@pxref{Keyword list}):
+
+@example
+$@splitrcskeyword{Author}: joe $
+$@splitrcskeyword{Date}: 1993/12/09 03:21:13 $
+$@splitrcskeyword{CVSHeader}: files/file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+$@splitrcskeyword{Header}: /home/files/file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+$@splitrcskeyword{Id}: file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+$@splitrcskeyword{Locker}: harry $
+$@splitrcskeyword{Name}: snapshot_1_14 $
+$@splitrcskeyword{RCSfile}: file1,v $
+$@splitrcskeyword{Revision}: 1.1 $
+$@splitrcskeyword{Source}: /home/files/file1,v $
+$@splitrcskeyword{State}: Exp $
+$@splitrcskeyword{Log}: file1,v $
+Revision 1.1 1993/12/09 03:30:17 joe
+Initial revision
+
+@end example
+
+@c The idea behind this table is that we want each item
+@c to be a sentence or two at most. Preferably a
+@c single line.
+@c
+@c In some cases refs to "foo options" are just to get
+@c this thing written quickly, not because the "foo
+@c options" node is really the best place to point.
+Commands, command options, and command arguments:
+
+@table @code
+@c ------------------------------------------------------------
+@item add [@var{options}] [@var{files}@dots{}]
+Add a new file/directory. See @ref{Adding files}.
+
+@table @code
+@item -k @var{kflag}
+Set keyword expansion.
+
+@item -m @var{msg}
+Set file description.
+@end table
+
+@c ------------------------------------------------------------
+@item admin [@var{options}] [@var{files}@dots{}]
+Administration of history files in the repository. See
+@ref{admin}.
+@c This list omits those options which are not
+@c documented as being useful with CVS. That might be
+@c a mistake...
+
+@table @code
+@item -b[@var{rev}]
+Set default branch. See @ref{Reverting local changes}.
+
+@item -c@var{string}
+Set comment leader.
+
+@item -k@var{subst}
+Set keyword substitution. See @ref{Keyword
+substitution}.
+
+@item -l[@var{rev}]
+Lock revision @var{rev}, or latest revision.
+
+@item -m@var{rev}:@var{msg}
+Replace the log message of revision @var{rev} with
+@var{msg}.
+
+@item -o@var{range}
+Delete revisions from the repository. See
+@ref{admin options}.
+
+@item -q
+Run quietly; do not print diagnostics.
+
+@item -s@var{state}[:@var{rev}]
+Set the state. See @ref{admin options} for more information on possible
+states.
+
+@c Does not work for client/server CVS
+@item -t
+Set file description from standard input.
+
+@item -t@var{file}
+Set file description from @var{file}.
+
+@item -t-@var{string}
+Set file description to @var{string}.
+
+@item -u[@var{rev}]
+Unlock revision @var{rev}, or latest revision.
+@end table
+
+@c ------------------------------------------------------------
+@item annotate [@var{options}] [@var{files}@dots{}]
+Show last revision where each line was modified. See
+@ref{annotate}.
+
+@table @code
+@item -D @var{date}
+Annotate the most recent revision no later than
+@var{date}. See @ref{Common options}.
+
+@item -F
+Force annotation of binary files. (Without this option,
+binary files are skipped with a message.)
+
+@item -f
+Use head revision if tag/date not found. See
+@ref{Common options}.
+
+@item -l
+Local; run only in current working directory. @xref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Annotate revisions specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+@end table
+
+@c ------------------------------------------------------------
+@item checkout [@var{options}] @var{modules}@dots{}
+Get a copy of the sources. See @ref{checkout}.
+
+@table @code
+@item -A
+Reset any sticky tags/date/options. See @ref{Sticky
+tags} and @ref{Keyword substitution}.
+
+@item -c
+Output the module database. See @ref{checkout options}.
+
+@item -D @var{date}
+Check out revisions as of @var{date} (is sticky). See
+@ref{Common options}.
+
+@item -d @var{dir}
+Check out into @var{dir}. See @ref{checkout options}.
+
+@item -f
+Use head revision if tag/date not found. See
+@ref{Common options}.
+
+@c Probably want to use rev1/rev2 style like for diff
+@c -r. Here and in on-line help.
+@item -j @var{tag}[:@var{date}]
+Merge in the change specified by @var{tag}, or when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{checkout options}.
+
+@item -k @var{kflag}
+Use @var{kflag} keyword expansion. See
+@ref{Substitution modes}.
+
+@item -l
+Local; run only in current working directory. @xref{Recursive behavior}.
+
+@item -N
+Don't ``shorten'' module paths if -d specified. See
+@ref{checkout options}.
+
+@item -n
+Do not run module program (if any). See @ref{checkout options}.
+
+@item -P
+Prune empty directories. See @ref{Moving directories}.
+
+@item -p
+Check out files to standard output (avoids
+stickiness). See @ref{checkout options}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Checkout the revision already tagged with @var{tag} or, when @var{date} is
+specified and @var{tag} is a branch tag, the version from the branch @var{tag}
+as it existed on @var{date}. This . See @ref{Common options}.
+
+@item -s
+Like -c, but include module status. See @ref{checkout options}.
+@end table
+
+@c ------------------------------------------------------------
+@item commit [@var{options}] [@var{files}@dots{}]
+Check changes into the repository. See @ref{commit}.
+
+@table @code
+@item -c
+Check for valid edits before committing. Requires a @sc{cvs} client and server
+both version 1.12.10 or greater.
+
+@item -F @var{file}
+Read log message from @var{file}. See @ref{commit options}.
+
+@item -f
+@c What is this "disables recursion"? It is from the
+@c on-line help; is it documented in this manual?
+Force the file to be committed; disables recursion.
+See @ref{commit options}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -m @var{msg}
+Use @var{msg} as log message. See @ref{commit options}.
+
+@item -n
+Do not run module program (if any). See @ref{commit options}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{rev}
+Commit to @var{rev}. See @ref{commit options}.
+@c FIXME: should be dragging over text from
+@c commit options, especially if it can be cleaned up
+@c and made concise enough.
+@end table
+
+@c ------------------------------------------------------------
+@item diff [@var{options}] [@var{files}@dots{}]
+Show differences between revisions. See @ref{diff}.
+In addition to the options shown below, accepts a wide
+variety of options to control output style, for example
+@samp{-c} for context diffs.
+
+@table @code
+@item -D @var{date1}
+Diff revision for date against working file. See
+@ref{diff options}.
+
+@item -D @var{date2}
+Diff @var{rev1}/@var{date1} against @var{date2}. See
+@ref{diff options}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -N
+Include diffs for added and removed files. See
+@ref{diff options}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag1}[:@var{date1}]
+Diff the revisions specified by @var{tag1} or, when @var{date1} is specified
+and @var{tag1} is a branch tag, the version from the branch @var{tag1} as it
+existed on @var{date1}, against the working file. See @ref{diff options}
+and @ref{Common options}.
+
+@item -r @var{tag2}[:@var{date2}]
+Diff the revisions specified by @var{tag2} or, when @var{date2} is specified
+and @var{tag2} is a branch tag, the version from the branch @var{tag2} as it
+existed on @var{date2}, against @var{rev1}/@var{date1}. See @ref{diff options}
+and @ref{Common options}.
+@end table
+
+@c ------------------------------------------------------------
+@item edit [@var{options}] [@var{files}@dots{}]
+Get ready to edit a watched file. See @ref{Editing files}.
+
+@table @code
+@item -a @var{actions}
+Specify actions for temporary watch, where
+@var{actions} is @code{edit}, @code{unedit},
+@code{commit}, @code{all}, or @code{none}. See
+@ref{Editing files}.
+
+@item -c
+Check edits: Edit fails if someone else is already editting the file.
+Requires a @sc{cvs} client and server both of version 1.12.10 or greater.
+
+@item -f
+Force edit; ignore other edits. Added in CVS 1.12.10.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+@end table
+
+@c ------------------------------------------------------------
+@item editors [@var{options}] [@var{files}@dots{}]
+See who is editing a watched file. See @ref{Watch information}.
+
+@table @code
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+@end table
+
+@c ------------------------------------------------------------
+@item export [@var{options}] @var{modules}@dots{}
+Export files from @sc{cvs}. See @ref{export}.
+
+@table @code
+@item -D @var{date}
+Check out revisions as of @var{date}. See
+@ref{Common options}.
+
+@item -d @var{dir}
+Check out into @var{dir}. See @ref{export options}.
+
+@item -f
+Use head revision if tag/date not found. See
+@ref{Common options}.
+
+@item -k @var{kflag}
+Use @var{kflag} keyword expansion. See
+@ref{Substitution modes}.
+
+@item -l
+Local; run only in current working directory. @xref{Recursive behavior}.
+
+@item -N
+Don't ``shorten'' module paths if -d specified. See
+@ref{export options}.
+
+@item -n
+Do not run module program (if any). See @ref{export options}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Export the revisions specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+@end table
+
+@c ------------------------------------------------------------
+@item history [@var{options}] [@var{files}@dots{}]
+Show repository access history. See @ref{history}.
+
+@table @code
+@item -a
+All users (default is self). See @ref{history options}.
+
+@item -b @var{str}
+Back to record with @var{str} in module/file/repos
+field. See @ref{history options}.
+
+@item -c
+Report on committed (modified) files. See @ref{history options}.
+
+@item -D @var{date}
+Since @var{date}. See @ref{history options}.
+
+@item -e
+Report on all record types. See @ref{history options}.
+
+@item -l
+Last modified (committed or modified report). See @ref{history options}.
+
+@item -m @var{module}
+Report on @var{module} (repeatable). See @ref{history options}.
+
+@item -n @var{module}
+In @var{module}. See @ref{history options}.
+
+@item -o
+Report on checked out modules. See @ref{history options}.
+
+@item -p @var{repository}
+In @var{repository}. See @ref{history options}.
+
+@item -r @var{rev}
+Since revision @var{rev}. See @ref{history options}.
+
+@item -T
+@c What the @#$@# is a TAG? Same as a tag? This
+@c wording is also in the online-line help.
+Produce report on all TAGs. See @ref{history options}.
+
+@item -t @var{tag}
+Since tag record placed in history file (by anyone).
+See @ref{history options}.
+
+@item -u @var{user}
+For user @var{user} (repeatable). See @ref{history options}.
+
+@item -w
+Working directory must match. See @ref{history options}.
+
+@item -x @var{types}
+Report on @var{types}, one or more of
+@code{TOEFWUPCGMAR}. See @ref{history options}.
+
+@item -z @var{zone}
+Output for time zone @var{zone}. See @ref{history options}.
+@end table
+
+@c ------------------------------------------------------------
+@item import [@var{options}] @var{repository} @var{vendor-tag} @var{release-tags}@dots{}
+Import files into @sc{cvs}, using vendor branches. See
+@ref{import}.
+
+@table @code
+@item -b @var{bra}
+Import to vendor branch @var{bra}. See
+@ref{Multiple vendor branches}.
+
+@item -d
+Use the file's modification time as the time of
+import. See @ref{import options}.
+
+@item -k @var{kflag}
+Set default keyword substitution mode. See
+@ref{import options}.
+
+@item -m @var{msg}
+Use @var{msg} for log message. See
+@ref{import options}.
+
+@item -I @var{ign}
+More files to ignore (! to reset). See
+@ref{import options}.
+
+@item -W @var{spec}
+More wrappers. See @ref{import options}.
+@end table
+
+@c ------------------------------------------------------------
+@item init
+Create a @sc{cvs} repository if it doesn't exist. See
+@ref{Creating a repository}.
+
+@c ------------------------------------------------------------
+@item kserver
+Kerberos authenticated server.
+See @ref{Kerberos authenticated}.
+
+@c ------------------------------------------------------------
+@item log [@var{options}] [@var{files}@dots{}]
+Print out history information for files. See @ref{log}.
+
+@table @code
+@item -b
+Only list revisions on the default branch. See @ref{log options}.
+
+@item -d @var{dates}
+Specify dates (@var{d1}<@var{d2} for range, @var{d} for
+latest before). See @ref{log options}.
+
+@item -h
+Only print header. See @ref{log options}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -N
+Do not list tags. See @ref{log options}.
+
+@item -R
+Only print name of RCS file. See @ref{log options}.
+
+@item -r@var{revs}
+Only list revisions @var{revs}. See @ref{log options}.
+
+@item -s @var{states}
+Only list revisions with specified states. See @ref{log options}.
+
+@item -t
+Only print header and descriptive text. See @ref{log
+options}.
+
+@item -w@var{logins}
+Only list revisions checked in by specified logins. See @ref{log options}.
+@end table
+
+@c ------------------------------------------------------------
+@item login
+Prompt for password for authenticating server. See
+@ref{Password authentication client}.
+
+@c ------------------------------------------------------------
+@item logout
+Remove stored password for authenticating server. See
+@ref{Password authentication client}.
+
+@c ------------------------------------------------------------
+@item pserver
+Password authenticated server.
+See @ref{Password authentication server}.
+
+@c ------------------------------------------------------------
+@item rannotate [@var{options}] [@var{modules}@dots{}]
+Show last revision where each line was modified. See
+@ref{annotate}.
+
+@table @code
+@item -D @var{date}
+Annotate the most recent revision no later than
+@var{date}. See @ref{Common options}.
+
+@item -F
+Force annotation of binary files. (Without this option,
+binary files are skipped with a message.)
+
+@item -f
+Use head revision if tag/date not found. See
+@ref{Common options}.
+
+@item -l
+Local; run only in current working directory. @xref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Annotate the revision specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag}
+as it existed on @var{date}. See @ref{Common options}.
+@end table
+
+@c ------------------------------------------------------------
+@item rdiff [@var{options}] @var{modules}@dots{}
+Show differences between releases. See @ref{rdiff}.
+
+@table @code
+@item -c
+Context diff output format (default). See @ref{rdiff options}.
+
+@item -D @var{date}
+Select revisions based on @var{date}. See @ref{Common options}.
+
+@item -f
+Use head revision if tag/date not found. See
+@ref{Common options}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Select the revisions specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{diff options} and @ref{Common options}.
+
+@item -s
+Short patch - one liner per file. See @ref{rdiff options}.
+
+@item -t
+Top two diffs - last change made to the file. See
+@ref{diff options}.
+
+@item -u
+Unidiff output format. See @ref{rdiff options}.
+
+@item -V @var{vers}
+Use RCS Version @var{vers} for keyword expansion (obsolete). See
+@ref{rdiff options}.
+@end table
+
+@c ------------------------------------------------------------
+@item release [@var{options}] @var{directory}
+Indicate that a directory is no longer in use. See
+@ref{release}.
+
+@table @code
+@item -d
+Delete the given directory. See @ref{release options}.
+@end table
+
+@c ------------------------------------------------------------
+@item remove [@var{options}] [@var{files}@dots{}]
+Remove an entry from the repository. See @ref{Removing files}.
+
+@table @code
+@item -f
+Delete the file before removing it. See @ref{Removing files}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+@end table
+
+@c ------------------------------------------------------------
+@item rlog [@var{options}] [@var{files}@dots{}]
+Print out history information for modules. See @ref{log}.
+
+@table @code
+@item -b
+Only list revisions on the default branch. See @ref{log options}.
+
+@item -d @var{dates}
+Specify dates (@var{d1}<@var{d2} for range, @var{d} for
+latest before). See @ref{log options}.
+
+@item -h
+Only print header. See @ref{log options}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -N
+Do not list tags. See @ref{log options}.
+
+@item -R
+Only print name of RCS file. See @ref{log options}.
+
+@item -r@var{revs}
+Only list revisions @var{revs}. See @ref{log options}.
+
+@item -s @var{states}
+Only list revisions with specified states. See @ref{log options}.
+
+@item -t
+Only print header and descriptive text. See @ref{log options}.
+
+@item -w@var{logins}
+Only list revisions checked in by specified logins. See @ref{log options}.
+@end table
+
+@c ------------------------------------------------------------
+@item rtag [@var{options}] @var{tag} @var{modules}@dots{}
+Add a symbolic tag to a module.
+See @ref{Revisions} and @ref{Branching and merging}.
+
+@table @code
+@item -a
+Clear tag from removed files that would not otherwise
+be tagged. See @ref{Tagging add/remove}.
+
+@item -b
+Create a branch named @var{tag}. See @ref{Branching and merging}.
+
+@item -B
+Used in conjunction with -F or -d, enables movement and deletion of
+branch tags. Use with extreme caution.
+
+@item -D @var{date}
+Tag revisions as of @var{date}. See @ref{Tagging by date/tag}.
+
+@item -d
+Delete @var{tag}. See @ref{Modifying tags}.
+
+@item -F
+Move @var{tag} if it already exists. See @ref{Modifying tags}.
+
+@item -f
+Force a head revision match if tag/date not found.
+See @ref{Tagging by date/tag}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -n
+No execution of tag program. See @ref{Common options}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Tag the revision already tagged with @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Tagging by date/tag} and @ref{Common options}.
+@end table
+
+@c ------------------------------------------------------------
+@item server
+Rsh server. See @ref{Connecting via rsh}.
+
+@c ------------------------------------------------------------
+@item status [@var{options}] @var{files}@dots{}
+Display status information in a working directory. See
+@ref{File status}.
+
+@table @code
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive behavior}.
+
+@item -v
+Include tag information for file. See @ref{Tags}.
+@end table
+
+@c ------------------------------------------------------------
+@item tag [@var{options}] @var{tag} [@var{files}@dots{}]
+Add a symbolic tag to checked out version of files.
+See @ref{Revisions} and @ref{Branching and merging}.
+
+@table @code
+@item -b
+Create a branch named @var{tag}. See @ref{Branching and merging}.
+
+@item -c
+Check that working files are unmodified. See
+@ref{Tagging the working directory}.
+
+@item -D @var{date}
+Tag revisions as of @var{date}. See @ref{Tagging by date/tag}.
+
+@item -d
+Delete @var{tag}. See @ref{Modifying tags}.
+
+@item -F
+Move @var{tag} if it already exists. See @ref{Modifying tags}.
+
+@item -f
+Force a head revision match if tag/date not found.
+See @ref{Tagging by date/tag}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Tag the revision already tagged with @var{tag}, or when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Tagging by date/tag} and @ref{Common options}.
+@end table
+
+@c ------------------------------------------------------------
+@item unedit [@var{options}] [@var{files}@dots{}]
+Undo an edit command. See @ref{Editing files}.
+
+@table @code
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive behavior}.
+@end table
+
+@c ------------------------------------------------------------
+@item update [@var{options}] [@var{files}@dots{}]
+Bring work tree in sync with repository. See
+@ref{update}.
+
+@table @code
+@item -A
+Reset any sticky tags/date/options. See @ref{Sticky
+tags} and @ref{Keyword substitution}.
+
+@item -C
+Overwrite locally modified files with clean copies from
+the repository (the modified file is saved in
+@file{.#@var{file}.@var{revision}}, however).
+
+@item -D @var{date}
+Check out revisions as of @var{date} (is sticky). See
+@ref{Common options}.
+
+@item -d
+Create directories. See @ref{update options}.
+
+@item -f
+Use head revision if tag/date not found. See
+@ref{Common options}.
+
+@item -I @var{ign}
+More files to ignore (! to reset). See
+@ref{import options}.
+
+@c Probably want to use rev1/rev2 style like for diff
+@c -r. Here and in on-line help.
+@item -j @var{tag}[:@var{date}]
+Merge in changes from revisions specified by @var{tag} or, when @var{date} is
+specified and @var{tag} is a branch tag, the version from the branch @var{tag}
+as it existed on @var{date}. See @ref{update options}.
+
+@item -k @var{kflag}
+Use @var{kflag} keyword expansion. See
+@ref{Substitution modes}.
+
+@item -l
+Local; run only in current working directory. @xref{Recursive behavior}.
+
+@item -P
+Prune empty directories. See @ref{Moving directories}.
+
+@item -p
+Check out files to standard output (avoids
+stickiness). See @ref{update options}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+
+@item -r @var{tag}[:@var{date}]
+Checkout the revisions specified by @var{tag} or, when @var{date} is specified
+and @var{tag} is a branch tag, the version from the branch @var{tag} as it
+existed on @var{date}. See @ref{Common options}.
+
+@item -W @var{spec}
+More wrappers. See @ref{import options}.
+@end table
+
+@c ------------------------------------------------------------
+@item version
+@cindex version (subcommand)
+
+Display the version of @sc{cvs} being used. If the repository
+is remote, display both the client and server versions.
+
+@c ------------------------------------------------------------
+@item watch [on|off|add|remove] [@var{options}] [@var{files}@dots{}]
+
+on/off: turn on/off read-only checkouts of files. See
+@ref{Setting a watch}.
+
+add/remove: add or remove notification on actions. See
+@ref{Getting Notified}.
+
+@table @code
+@item -a @var{actions}
+Specify actions for temporary watch, where
+@var{actions} is @code{edit}, @code{unedit},
+@code{commit}, @code{all}, or @code{none}. See
+@ref{Editing files}.
+
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+@end table
+
+@c ------------------------------------------------------------
+@item watchers [@var{options}] [@var{files}@dots{}]
+See who is watching a file. See @ref{Watch information}.
+
+@table @code
+@item -l
+Local; run only in current working directory. See @ref{Recursive behavior}.
+
+@item -R
+Operate recursively (default). @xref{Recursive
+behavior}.
+@end table
+
+@end table
+
+@c ---------------------------------------------------------------------
+@node Administrative files
+@appendix Reference manual for Administrative files
+@cindex Administrative files (reference)
+@cindex Files, reference manual
+@cindex Reference manual (files)
+@cindex CVSROOT (file)
+
+Inside the repository, in the directory
+@file{$CVSROOT/CVSROOT}, there are a number of
+supportive files for @sc{cvs}. You can use @sc{cvs} in a limited
+fashion without any of them, but if they are set up
+properly they can help make life easier. For a
+discussion of how to edit them, see @ref{Intro
+administrative files}.
+
+The most important of these files is the @file{modules}
+file, which defines the modules inside the repository.
+
+@menu
+* modules:: Defining modules
+* Wrappers:: Specify binary-ness based on file name
+* Trigger Scripts:: Launch scripts in response to server events
+* rcsinfo:: Templates for the log messages
+* cvsignore:: Ignoring files via cvsignore
+* checkoutlist:: Adding your own administrative files
+* history file:: History information
+* Variables:: Various variables are expanded
+* config:: Miscellaneous CVS configuration
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node modules
+@appendixsec The modules file
+@cindex Modules (admin file)
+@cindex Defining modules (reference manual)
+
+The @file{modules} file records your definitions of
+names for collections of source code. @sc{cvs} will
+use these definitions if you use @sc{cvs} to update the
+modules file (use normal commands like @code{add},
+@code{commit}, etc).
+
+The @file{modules} file may contain blank lines and
+comments (lines beginning with @samp{#}) as well as
+module definitions. Long lines can be continued on the
+next line by specifying a backslash (@samp{\}) as the
+last character on the line.
+
+There are three basic types of modules: alias modules,
+regular modules, and ampersand modules. The difference
+between them is the way that they map files in the
+repository to files in the working directory. In all
+of the following examples, the top-level repository
+contains a directory called @file{first-dir}, which
+contains two files, @file{file1} and @file{file2}, and a
+directory @file{sdir}. @file{first-dir/sdir} contains
+a file @file{sfile}.
+
+@c FIXME: should test all the examples in this section.
+
+@menu
+* Alias modules:: The simplest kind of module
+* Regular modules::
+* Ampersand modules::
+* Excluding directories:: Excluding directories from a module
+* Module options:: Regular and ampersand modules can take options
+* Module program options:: How the modules ``program options'' programs
+ are run.
+@end menu
+
+@node Alias modules
+@appendixsubsec Alias modules
+@cindex Alias modules
+@cindex -a, in modules file
+
+Alias modules are the simplest kind of module:
+
+@table @code
+@item @var{mname} -a @var{aliases}@dots{}
+This represents the simplest way of defining a module
+@var{mname}. The @samp{-a} flags the definition as a
+simple alias: @sc{cvs} will treat any use of @var{mname} (as
+a command argument) as if the list of names
+@var{aliases} had been specified instead.
+@var{aliases} may contain either other module names or
+paths. When you use paths in aliases, @code{checkout}
+creates all intermediate directories in the working
+directory, just as if the path had been specified
+explicitly in the @sc{cvs} arguments.
+@end table
+
+For example, if the modules file contains:
+
+@example
+amodule -a first-dir
+@end example
+
+@noindent
+then the following two commands are equivalent:
+
+@example
+$ cvs co amodule
+$ cvs co first-dir
+@end example
+
+@noindent
+and they each would provide output such as:
+
+@example
+cvs checkout: Updating first-dir
+U first-dir/file1
+U first-dir/file2
+cvs checkout: Updating first-dir/sdir
+U first-dir/sdir/sfile
+@end example
+
+@node Regular modules
+@appendixsubsec Regular modules
+@cindex Regular modules
+
+@table @code
+@item @var{mname} [ options ] @var{dir} [ @var{files}@dots{} ]
+In the simplest case, this form of module definition
+reduces to @samp{@var{mname} @var{dir}}. This defines
+all the files in directory @var{dir} as module mname.
+@var{dir} is a relative path (from @code{$CVSROOT}) to a
+directory of source in the source repository. In this
+case, on checkout, a single directory called
+@var{mname} is created as a working directory; no
+intermediate directory levels are used by default, even
+if @var{dir} was a path involving several directory
+levels.
+@end table
+
+For example, if a module is defined by:
+
+@example
+regmodule first-dir
+@end example
+
+@noindent
+then regmodule will contain the files from first-dir:
+
+@example
+$ cvs co regmodule
+cvs checkout: Updating regmodule
+U regmodule/file1
+U regmodule/file2
+cvs checkout: Updating regmodule/sdir
+U regmodule/sdir/sfile
+$
+@end example
+
+By explicitly specifying files in the module definition
+after @var{dir}, you can select particular files from
+directory @var{dir}. Here is
+an example:
+
+@example
+regfiles first-dir/sdir sfile
+@end example
+
+@noindent
+With this definition, getting the regfiles module
+will create a single working directory
+@file{regfiles} containing the file listed, which
+comes from a directory deeper
+in the @sc{cvs} source repository:
+
+@example
+$ cvs co regfiles
+U regfiles/sfile
+$
+@end example
+
+@node Ampersand modules
+@appendixsubsec Ampersand modules
+@cindex Ampersand modules
+@cindex &, in modules file
+
+A module definition can refer to other modules by
+including @samp{&@var{module}} in its definition.
+@example
+@var{mname} [ options ] @var{&module}@dots{}
+@end example
+
+Then getting the module creates a subdirectory for each such
+module, in the directory containing the module. For
+example, if modules contains
+
+@example
+ampermod &first-dir
+@end example
+
+@noindent
+then a checkout will create an @code{ampermod} directory
+which contains a directory called @code{first-dir},
+which in turns contains all the directories and files
+which live there. For example, the command
+
+@example
+$ cvs co ampermod
+@end example
+
+@noindent
+will create the following files:
+
+@example
+ampermod/first-dir/file1
+ampermod/first-dir/file2
+ampermod/first-dir/sdir/sfile
+@end example
+
+There is one quirk/bug: the messages that @sc{cvs}
+prints omit the @file{ampermod}, and thus do not
+correctly display the location to which it is checking
+out the files:
+
+@example
+$ cvs co ampermod
+cvs checkout: Updating first-dir
+U first-dir/file1
+U first-dir/file2
+cvs checkout: Updating first-dir/sdir
+U first-dir/sdir/sfile
+$
+@end example
+
+Do not rely on this buggy behavior; it may get fixed in
+a future release of @sc{cvs}.
+
+@c FIXCVS: What happens if regular and & modules are
+@c combined, as in "ampermodule first-dir &second-dir"?
+@c When I tried it, it seemed to just ignore the
+@c "first-dir". I think perhaps it should be an error
+@c (but this needs further investigation).
+@c In addition to discussing what each one does, we
+@c should put in a few words about why you would use one or
+@c the other in various situations.
+
+@node Excluding directories
+@appendixsubsec Excluding directories
+@cindex Excluding directories, in modules file
+@cindex !, in modules file
+
+An alias module may exclude particular directories from
+other modules by using an exclamation mark (@samp{!})
+before the name of each directory to be excluded.
+
+For example, if the modules file contains:
+
+@example
+exmodule -a !first-dir/sdir first-dir
+@end example
+
+@noindent
+then checking out the module @samp{exmodule} will check
+out everything in @samp{first-dir} except any files in
+the subdirectory @samp{first-dir/sdir}.
+@c Note that the "!first-dir/sdir" sometimes must be listed
+@c before "first-dir". That seems like a probable bug, in which
+@c case perhaps it should be fixed (to allow either
+@c order) rather than documented. See modules4 in testsuite.
+
+@node Module options
+@appendixsubsec Module options
+@cindex Options, in modules file
+
+Either regular modules or ampersand modules can contain
+options, which supply additional information concerning
+the module.
+
+@table @code
+@cindex -d, in modules file
+@item -d @var{name}
+Name the working directory something other than the
+module name.
+@c FIXME: Needs a bunch of examples, analogous to the
+@c examples for alias, regular, and ampersand modules
+@c which show where the files go without -d.
+
+@cindex Export program
+@cindex -e, in modules file
+@item -e @var{prog}
+Specify a program @var{prog} to run whenever files in a
+module are exported. @var{prog} runs with a single
+argument, the module name.
+@c FIXME: Is it run on server? client?
+
+@cindex Checkout program
+@cindex -o, in modules file
+@item -o @var{prog}
+Specify a program @var{prog} to run whenever files in a
+module are checked out. @var{prog} runs with a single
+argument, the module name. See @ref{Module program options} for
+information on how @var{prog} is called.
+@c FIXME: Is it run on server? client?
+
+@cindex Status of a module
+@cindex Module status
+@cindex -s, in modules file
+@item -s @var{status}
+Assign a status to the module. When the module file is
+printed with @samp{cvs checkout -s} the modules are
+sorted according to primarily module status, and
+secondarily according to the module name. This option
+has no other meaning. You can use this option for
+several things besides status: for instance, list the
+person that is responsible for this module.
+
+@cindex Tag program
+@cindex -t, in modules file
+@item -t @var{prog}
+Specify a program @var{prog} to run whenever files in a
+module are tagged with @code{rtag}. @var{prog} runs
+with two arguments: the module name and the symbolic
+tag specified to @code{rtag}. It is not run
+when @code{tag} is executed. Generally you will find
+that the @file{taginfo} file is a better solution (@pxref{taginfo}).
+@c FIXME: Is it run on server? client?
+@c Problems with -t include:
+@c * It is run after the tag not before
+@c * It doesn't get passed all the information that
+@c taginfo does ("mov", &c).
+@c * It only is run for rtag, not tag.
+@end table
+
+You should also see @pxref{Module program options} about how the
+``program options'' programs are run.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@node Module program options
+@appendixsubsec How the modules file ``program options'' programs are run
+@cindex Modules file program options
+@cindex -t, in modules file
+@cindex -o, in modules file
+@cindex -e, in modules file
+
+@noindent
+For checkout, rtag, and export, the program is server-based, and as such the
+following applies:-
+
+If using remote access methods (pserver, ext, etc.),
+@sc{cvs} will execute this program on the server from a temporary
+directory. The path is searched for this program.
+
+If using ``local access'' (on a local or remote NFS file system, i.e.
+repository set just to a path),
+the program will be executed from the newly checked-out tree, if
+found there, or alternatively searched for in the path if not.
+
+The programs are all run after the operation has effectively
+completed.
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Wrappers
+@appendixsec The cvswrappers file
+@cindex cvswrappers (admin file)
+@cindex CVSWRAPPERS, environment variable
+@cindex Wrappers
+
+@c FIXME: need some better way of separating this out
+@c by functionality. -m is
+@c one feature, and -k is a another. And this discussion
+@c should be better motivated (e.g. start with the
+@c problems, then explain how the feature solves it).
+
+Wrappers refers to a @sc{cvs} feature which lets you
+control certain settings based on the name of the file
+which is being operated on. The settings are @samp{-k}
+for binary files, and @samp{-m} for nonmergeable text
+files.
+
+The @samp{-m} option
+specifies the merge methodology that should be used when
+a non-binary file is updated. @code{MERGE} means the usual
+@sc{cvs} behavior: try to merge the files. @code{COPY}
+means that @code{cvs update} will refuse to merge
+files, as it also does for files specified as binary
+with @samp{-kb} (but if the file is specified as
+binary, there is no need to specify @samp{-m 'COPY'}).
+@sc{cvs} will provide the user with the
+two versions of the files, and require the user using
+mechanisms outside @sc{cvs}, to insert any necessary
+changes.
+
+@strong{WARNING: do not use @code{COPY} with
+@sc{cvs} 1.9 or earlier - such versions of @sc{cvs} will
+copy one version of your file over the other, wiping
+out the previous contents.}
+@c Ordinarily we don't document the behavior of old
+@c versions. But this one is so dangerous, I think we
+@c must. I almost renamed it to -m 'NOMERGE' so we
+@c could say "never use -m 'COPY'".
+The @samp{-m} wrapper option only affects behavior when
+merging is done on update; it does not affect how files
+are stored. See @ref{Binary files}, for more on
+binary files.
+
+The basic format of the file @file{cvswrappers} is:
+
+@c FIXME: @example is all wrong for this. Use @deffn or
+@c something more sensible.
+@example
+wildcard [option value][option value]...
+
+where option is one of
+-m update methodology value: MERGE or COPY
+-k keyword expansion value: expansion mode
+
+and value is a single-quote delimited value.
+@end example
+
+@ignore
+@example
+*.nib -f 'unwrap %s' -t 'wrap %s %s' -m 'COPY'
+*.c -t 'indent %s %s'
+@end example
+@c When does the filter need to be an absolute pathname
+@c and when will something like the above work? I
+@c suspect it relates to the PATH of the server (which
+@c in turn depends on all kinds of stuff, e.g. inetd
+@c for pserver). I'm not sure whether/where to discuss
+@c this.
+@c FIXME: What do the %s's stand for?
+
+@noindent
+The above example of a @file{cvswrappers} file
+states that all files/directories that end with a @code{.nib}
+should be filtered with the @file{wrap} program before
+checking the file into the repository. The file should
+be filtered though the @file{unwrap} program when the
+file is checked out of the repository. The
+@file{cvswrappers} file also states that a @code{COPY}
+methodology should be used when updating the files in
+the repository (that is, no merging should be performed).
+
+@c What pitfalls arise when using indent this way? Is
+@c it a winning thing to do? Would be nice to at least
+@c hint at those issues; we want our examples to tell
+@c how to solve problems, not just to say that cvs can
+@c do certain things.
+The last example line says that all files that end with
+@code{.c} should be filtered with @file{indent}
+before being checked into the repository. Unlike the previous
+example, no filtering of the @code{.c} file is done when
+it is checked out of the repository.
+@noindent
+The @code{-t} filter is called with two arguments,
+the first is the name of the file/directory to filter
+and the second is the pathname to where the resulting
+filtered file should be placed.
+
+@noindent
+The @code{-f} filter is called with one argument,
+which is the name of the file to filter from. The end
+result of this filter will be a file in the users directory
+that they can work on as they normally would.
+
+Note that the @samp{-t}/@samp{-f} features do not
+conveniently handle one portion of @sc{cvs}'s operation:
+determining when files are modified. @sc{cvs} will still
+want a file (or directory) to exist, and it will use
+its modification time to determine whether a file is
+modified. If @sc{cvs} erroneously thinks a file is
+unmodified (for example, a directory is unchanged but
+one of the files within it is changed), you can force
+it to check in the file anyway by specifying the
+@samp{-f} option to @code{cvs commit} (@pxref{commit
+options}).
+@c This is, of course, a serious design flaw in -t/-f.
+@c Probably the whole functionality needs to be
+@c redesigned (starting from requirements) to fix this.
+@end ignore
+
+@c FIXME: We don't document -W or point to where it is
+@c documented. Or .cvswrappers.
+For example, the following command imports a
+directory, treating files whose name ends in
+@samp{.exe} as binary:
+
+@example
+cvs import -I ! -W "*.exe -k 'b'" first-dir vendortag reltag
+@end example
+
+@c Another good example, would be storing files
+@c (e.g. binary files) compressed in the repository.
+@c ::::::::::::::::::
+@c cvswrappers
+@c ::::::::::::::::::
+@c *.t12 -m 'COPY'
+@c *.t[0-9][0-9] -f 'gunzipcp %s' -t 'gzipcp %s %s' -m 'COPY'
+@c
+@c ::::::::::::::::::
+@c gunzipcp
+@c ::::::::::::::::::
+@c :
+@c [ -f $1 ] || exit 1
+@c zcat $1 > /tmp/.#$1.$$
+@c mv /tmp/.#$1.$$ $1
+@c
+@c ::::::::::::::::::
+@c gzipcp
+@c ::::::::::::::::::
+@c :
+@c DIRNAME=`echo $1 | sed -e "s|/.*/||g"`
+@c if [ ! -d $DIRNAME ] ; then
+@c DIRNAME=`echo $1 | sed -e "s|.*/||g"`
+@c fi
+@c gzip -c $DIRNAME > $2
+@c One catch--"cvs diff" will not invoke the wrappers
+@c (probably a CVS bug, although I haven't thought it out).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Trigger Scripts
+@appendixsec The Trigger Scripts
+@cindex info files
+@cindex trigger scripts
+@cindex script hooks
+
+@c FIXME
+@c Somewhere there needs to be a more "how-to" guide to writing these.
+@c One particular issue that people sometimes are worried about is performance,
+@c and the impact of writing in perl or sh or ____. Performance comparisons
+@c should probably remain outside the scope of this document, but at least
+@c _that_ much could be referenced, perhaps with links to other sources.
+
+Several of the administrative files support triggers, or the launching external
+scripts or programs at specific times before or after particular events, during
+the execution of @sc{cvs} commands. These hooks can be used to prevent certain
+actions, log them, and/or maintain anything else you deem practical.
+
+All the trigger scripts are launched in a copy of the user sandbox being
+committed, on the server, in client-server mode. In local mode, the scripts
+are actually launched directly from the user sandbox directory being committed.
+For most intents and purposes, the same scripts can be run in both locations
+without alteration.
+
+@menu
+* syntax:: The common syntax
+* Trigger Script Security:: Trigger script security
+
+* commit files:: The commit support files (commitinfo,
+ verifymsg, loginfo)
+* commitinfo:: Pre-commit checking
+* verifymsg:: How are log messages evaluated?
+* loginfo:: Where should log messages be sent?
+
+* postadmin:: Logging admin commands
+* taginfo:: Verifying/Logging tags
+* posttag:: Logging tags
+* postwatch:: Logging watch commands
+
+* preproxy:: Launch a script on a secondary server prior
+ to becoming a write proxy
+* postproxy:: Launch a script on a secondary server after
+ completing proxy operations
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node syntax
+@appendixsubsec The common syntax
+@cindex info files, common syntax
+@cindex script hooks, common syntax
+@cindex trigger script hooks, common syntax
+@cindex syntax of trigger script hooks
+
+@c FIXME: having this so totally separate from the
+@c Variables node is rather bogus.
+
+The administrative files such as @file{commitinfo},
+@file{loginfo}, @file{rcsinfo}, @file{verifymsg}, etc.,
+all have a common format. The purpose of the files are
+described later on. The common syntax is described
+here.
+
+@cindex Regular expression syntax
+Each line contains the following:
+
+@itemize @bullet
+@cindex @samp{ALL} keyword, in lieu of regular expressions in script hooks
+@cindex @samp{DEFAULT} keyword, in lieu of regular expressions in script hooks
+@item
+A regular expression or the literal string @samp{DEFAULT}. Some script hooks
+also support the literal string @samp{ALL}. Other than the @samp{ALL} and
+@samp{DEFAULT} keywords, this is a basic regular expression in the syntax used
+by GNU emacs. See the descriptions of the individual script hooks for
+information on whether the @samp{ALL} keyword is supported
+(@pxref{Trigger Scripts}).
+@c FIXME: What we probably should be saying is "POSIX Basic
+@c Regular Expression with the following extensions (`\('
+@c `\|' '+' etc)"
+@c rather than define it with reference to emacs.
+@c The reference to emacs is not strictly speaking
+@c true, as we don't support \=, \s, or \S. Also it isn't
+@c clear we should document and/or promise to continue to
+@c support all the obscure emacs extensions like \<.
+@c Also need to better cite (or include) full
+@c documentation for the syntax.
+@c Also see comment in configure.in about what happens to the
+@c syntax if we pick up a system-supplied regexp matcher.
+
+@item
+A whitespace separator---one or more spaces and/or tabs.
+
+@item
+A file name or command-line template.
+@end itemize
+
+@noindent
+Blank lines are ignored. Lines that start with the
+character @samp{#} are treated as comments. Long lines
+unfortunately can @emph{not} be broken in two parts in
+any way.
+
+The first regular expression that matches the current
+directory name in the repository or the first line containing @samp{DEFAULT}
+in lieu of a regular expression is used and all lines containing @samp{ALL} is
+used for the hooks which support the @samp{ALL} keyword. The rest of the line
+is used as a file name or command-line template as appropriate. See the
+descriptions of the individual script hooks for information on whether the
+@samp{ALL} keyword is supported (@pxref{Trigger Scripts}).
+
+@cindex format strings
+@cindex format strings, common syntax
+@cindex info files, common syntax, format strings
+@cindex Common syntax of info files, format strings
+@noindent
+@emph{Note: The following information on format strings is valid
+as long as the line @code{UseNewInfoFmtStrings=yes} appears in
+your repository's config file (@pxref{config}). Otherwise,
+default format strings may be appended to the command line and
+the @samp{loginfo} file, especially, can exhibit slightly
+different behavior. For more information,
+@xref{Updating Commit Files}.}
+
+In the cases where the second segment of the matched line is a
+command line template (e.g. @file{commitinfo}, @file{loginfo},
+& @file{verifymsg}), the command line template may contain format
+strings which will be replaced with specific values before the
+script is run.
+@c FIXCVS then FIXME - it really would make sense to allow %r & maybe even %p
+@c to be used in rcsinfo to construct a path, but I haven't
+@c coded this yet.
+
+Format strings can represent a single variable or one or more
+attributes of a list variable. An example of a list variable
+would be the list available to scripts hung on the loginfo hooks
+- the list of files which were just committed. In the case of
+loginfo, three attributes are available for each list item: file
+name, precommit version, and postcommit version.
+
+Format strings consist of a @samp{%} character followed by an optional
+@samp{@{} (required in the multiple list attribute case), a
+single format character representing a variable or a single attribute of
+list elements or multiple format characters representing attributes of
+list elements, and a closing @samp{@}} when the open bracket was present.
+
+@emph{Flat format strings}, or single format characters which get replaced
+with a single value, will generate a single argument
+to the called script, regardless of whether the replacement variable contains
+white space or other special characters.
+
+@emph{List attributes} will generate an argument for each attribute
+requested for each list item. For example, @samp{%@{sVv@}}
+in a @file{loginfo} command template will generate three
+arguments (file name, precommit version, postcommit version,
+...) for each file committed. As in the flat format string
+case, each attribute will be passed in as a single argument
+regardless of whether it contains white space or other
+special characters.
+
+@samp{%%} will be replaced with a literal @samp{%}.
+
+The format strings available to all script hooks are:
+
+@table @t
+@item c
+The canonical name of the command being executed. For instance, in the case of
+a hook run from @code{cvs up}, @sc{cvs} would replace @samp{%c} with the string
+@samp{update} and, in the case of a hook run from @code{cvs ci}, @sc{cvs} would
+replace @samp{%c} with the string @samp{commit}.
+@item n
+The null, or empty, string.
+@item p
+The name of the directory being operated on within the repository.
+@item r
+The name of the repository (the path portion of @code{$CVSROOT}).
+@item R
+On a server, the name of the referrer, if any. The referrer is the CVSROOT the
+client reports it used to contact a server which then referred it to this
+server. Should usually be set on a primary server with a write proxy setup.
+@end table
+
+Other format strings are file specific. See the docs on the
+particular script hooks for more information
+(@pxref{Trigger Scripts}).
+
+As an example, the following line in a @file{loginfo} file would
+match only the directory @file{module} and any subdirectories of
+@file{module}:
+
+@example
+^module\(/\|$\) (echo; echo %p; echo %@{sVv@}; cat) >>$CVSROOT/CVSROOT/commitlog
+@end example
+
+Using this same line and assuming a commit of new revisions
+1.5.4.4 and 1.27.4.1 based on old revisions 1.5.4.3 and 1.27,
+respectively, of file1 and file2 in module, something like the
+following log message should be appended to commitlog:
+
+@example
+
+module
+file1 1.5.4.3 1.5.4.4 file2 1.27 1.27.4.1
+Update of /cvsroot/module
+In directory localhost.localdomain:/home/jrandom/work/module
+
+Modified Files:
+ file1 file2
+Log Message:
+A log message.
+@end example
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node Trigger Script Security
+@appendixsubsec Security and the Trigger Scripts
+@cindex info files, security
+@cindex script hooks, security
+@cindex trigger scripts, security
+
+Security is a huge subject, and implementing a secure system is a non-trivial
+task. This section will barely touch on all the issues involved, but it is
+well to note that, as with any script you will be allowing an untrusted
+user to run on your server, there are measures you can take to help prevent
+your trigger scripts from being abused.
+
+For instance, since the CVS trigger scripts all run in a copy of the user's
+sandbox on the server, a naively coded Perl trigger script which attempts to
+use a Perl module that is not installed on the system can be hijacked by any
+user with commit access who is checking in a file with the correct name. Other
+scripting languages may be vulnerable to similar hacks.
+
+One way to make a script more secure, at least with Perl, is to use scripts
+which invoke the @code{-T}, or "taint-check" switch on their @code{#!} line.
+In the most basic terms, this causes Perl to avoid running code that may have
+come from an external source. Please run the @code{perldoc perlsec} command
+for more on Perl security. Again, other languages may implement other security
+verification hooks which look more or less like Perl's "taint-check" mechanism.
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node commit files
+@appendixsubsec The commit support files
+@cindex Commits, administrative support files
+@cindex commit files, see Info files
+
+The @samp{-i} flag in the @file{modules} file can be
+used to run a certain program whenever files are
+committed (@pxref{modules}). The files described in
+this section provide other, more flexible, ways to run
+programs whenever something is committed.
+
+There are three kinds of programs that can be run on
+commit. They are specified in files in the repository,
+as described below. The following table summarizes the
+file names and the purpose of the corresponding
+programs.
+
+@table @file
+@item commitinfo
+The program is responsible for checking that the commit
+is allowed. If it exits with a non-zero exit status
+the commit will be aborted. @xref{commitinfo}.
+
+@item verifymsg
+The specified program is used to evaluate the log message,
+and possibly verify that it contains all required
+fields. This is most useful in combination with the
+@file{rcsinfo} file, which can hold a log message
+template (@pxref{rcsinfo}). @xref{verifymsg}.
+
+@item loginfo
+The specified program is called when the commit is
+complete. It receives the log message and some
+additional information and can store the log message in
+a file, or mail it to appropriate persons, or maybe
+post it to a local newsgroup, or@dots{} Your
+imagination is the limit! @xref{loginfo}.
+@end table
+
+@menu
+* Updating Commit Files:: Updating legacy repositories to stop using
+ deprecated command line template formats
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node Updating Commit Files
+@appendixsubsubsec Updating legacy repositories to stop using deprecated command line template formats
+@cindex info files, common syntax, updating legacy repositories
+@cindex Syntax of info files, updating legacy repositories
+@cindex Common syntax of info files, updating legacy repositories
+New repositories are created set to use the new format strings by default, so
+if you are creating a new repository, you shouldn't have to worry about this
+section.
+
+If you are attempting to maintain a legacy repository which was
+making use of the @file{commitinfo}, @file{editinfo}, @file{verifymsg},
+@file{loginfo}, and/or @file{taginfo} script hooks, you should have no
+immediate problems with using the current @sc{cvs} executable, but your users
+will probably start to see deprecation warnings.
+
+The reason for this is that all of the script hooks have been updated to
+use a new command line parser that extensibly supports multiple
+@file{loginfo} & @file{notify} style format strings (@pxref{syntax})
+and this support is not completely compatible with the old style format
+strings.
+
+The quick upgrade method is to stick a @samp{1} after each format string
+in your old @file{loginfo} file. For example:
+
+@example
+DEFAULT (echo ""; id; echo %@{sVv@}; date; cat) >> $CVSROOT/CVSROOT/commitlog
+@end example
+
+would become:
+
+@example
+DEFAULT (echo ""; id; echo %1@{sVv@}; date; cat) >> $CVSROOT/CVSROOT/commitlog
+@end example
+
+If you were counting on the fact that only the first @samp{%} in the line was
+replaced as a format string, you may also have to double up any further
+percent signs on the line.
+
+If you did this all at once and checked it in, everything should still be
+running properly.
+
+Now add the following line to your config file (@pxref{config}):
+@example
+UseNewInfoFmtStrings=yes
+@end example
+
+Everything should still be running properly, but your users will probably
+start seeing new deprecation warnings.
+
+Dealing with the deprecation warnings now generated by @file{commitinfo},
+@file{editinfo}, @file{verifymsg}, and @file{taginfo} should be easy. Simply
+specify what are currently implicit arguments explicitly. This means appending
+the following strings to each active command line template in each file:
+@table @code
+@item commitinfo
+@samp{ %r/%p %s}
+@item editinfo
+@samp{ %l}
+@item taginfo
+@samp{ %t %o %p %@{sv@}}
+@item verifymsg
+@samp{ %l}
+@end table
+
+If you don't desire that any of the newly available information be passed to
+the scripts hanging off of these hooks, no further modifications to these
+files should be necessary to insure current and future compatibility with
+@sc{cvs}'s format strings.
+
+Fixing @file{loginfo} could be a little tougher. The old style
+@file{loginfo} format strings caused a single space and comma separated
+argument to be passed in in place of the format string. This is what will
+continue to be generated due to the deprecated @samp{1} you inserted into
+the format strings.
+
+Since the new format separates each individual item and passes it into the
+script as a separate argument (for a good reason - arguments containing commas
+and/or white space are now parsable), to remove the deprecated @samp{1} from
+your @file{loginfo} command line templates, you will most likely have to
+rewrite any scripts called by the hook to handle the new argument format.
+
+Also note that the way @samp{%} followed by unrecognized characters and by
+@samp{@{@}} was treated in past versions of CVS is not strictly adhered to as
+there were bugs in the old versions. Specifically, @samp{%@{@}} would eat the
+next character and unrecognized strings resolved only to the empty string,
+which was counter to what was stated in the documentation. This version will
+do what the documentation said it should have (if you were using only some
+combination of @samp{%@{sVv@}}, e.g. @samp{%@{sVv@}}, @samp{%@{sV@}}, or
+@samp{%v}, you should have no troubles).
+
+On the bright side, you should have plenty of time to do this before all
+support for the old format strings is removed from @sc{cvs}, so you can just
+put up with the deprecation warnings for awhile if you like.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node commitinfo
+@appendixsubsec Commitinfo
+@cindex @file{commitinfo}
+@cindex Commits, precommit verification of
+@cindex commitinfo (admin file)
+@cindex info files, commitinfo
+@cindex script hooks, commitinfo
+@cindex trigger scripts, commitinfo
+@cindex info files, precommit verification of commits
+@cindex script hooks, precommit verification of commits
+@cindex trigger scripts, precommit verification of commits
+
+The @file{commitinfo} file defines programs to execute
+whenever @samp{cvs commit} is about to execute. These
+programs are used for pre-commit checking to verify
+that the modified, added and removed files are really
+ready to be committed. This could be used, for
+instance, to verify that the changed files conform to
+to your site's standards for coding practice.
+
+The @file{commitinfo} file has the standard form for script hooks
+(@pxref{Trigger Scripts}), where each line is a regular expression followed by
+a command to execute. It supports only the DEFAULT keywords.
+
+@cindex format strings, commitinfo admin file
+In addition to the common format strings (@pxref{syntax}),
+@file{commitinfo} supports:
+
+@table @t
+@item @{s@}
+a list of the names of files to be committed
+@end table
+
+@cindex commitinfo (admin file), updating legacy repositories
+@cindex compatibility notes, commitinfo admin file
+Currently, if no format strings are specified, a default
+string of @samp{ %r/%p %@{s@}} will be appended to the command
+line template before replacement is performed, but this
+feature is deprecated. It is simply in place so that legacy
+repositories will remain compatible with the new @sc{cvs} application.
+For information on updating, @pxref{Updating Commit Files}.
+
+@cindex Exit status, of commitinfo
+@cindex commitinfo (admin file), exit status
+The first line with a regular expression matching the
+directory within the repository will be used. If the
+command returns a non-zero exit status the commit will
+be aborted.
+@c FIXME: need example(s) of what "directory within the
+@c repository" means.
+
+@cindex @file{commitinfo}, working directory
+@cindex @file{commitinfo}, command environment
+The command will be run in the root of the workspace
+containing the new versions of any files the user would like
+to modify (commit), @emph{or in a copy of the workspace on
+the server (@pxref{Remote repositories})}. If a file is
+being removed, there will be no copy of the file under the
+current directory. If a file is being added, there will be
+no corresponding archive file in the repository unless the
+file is being resurrected.
+
+Note that both the repository directory and the corresponding
+Attic (@pxref{Attic}) directory may need to be checked to
+locate the archive file corresponding to any given file being
+committed. Much of the information about the specific commit
+request being made, including the destination branch, commit
+message, and command line options specified, is not available
+to the command.
+
+@c FIXME: should discuss using commitinfo to control
+@c who has checkin access to what (e.g. Joe can check into
+@c directories a, b, and c, and Mary can check into
+@c directories b, c, and d--note this case cannot be
+@c conveniently handled with unix groups). Of course,
+@c adding a new set of features to CVS might be a more
+@c natural way to fix this problem than telling people to
+@c use commitinfo.
+@c FIXME: Should make some reference, especially in
+@c the context of controlling who has access, to the fact
+@c that commitinfo can be circumvented. Perhaps
+@c mention SETXID (but has it been carefully examined
+@c for holes?). This fits in with the discussion of
+@c general CVS security in "Password authentication
+@c security" (the bit which is not pserver-specific).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node verifymsg
+@appendixsubsec Verifying log messages
+@cindex @file{verifymsg} (admin file)
+@cindex Log message, verifying
+@cindex logging, commits
+
+Once you have entered a log message, you can evaluate
+that message to check for specific content, such as
+a bug ID. Use the @file{verifymsg} file to
+specify a program that is used to verify the log message.
+This program could be a simple script that checks
+that the entered message contains the required fields.
+
+The @file{verifymsg} file is often most useful together
+with the @file{rcsinfo} file, which can be used to
+specify a log message template (@pxref{rcsinfo}).
+
+The @file{verifymsg} file has the standard form for script hooks
+(@pxref{Trigger Scripts}), where each line is a regular expression followed by
+a command to execute. It supports only the DEFAULT keywords.
+
+@cindex format strings, verifymsg admin file
+In addition to the common format strings (@pxref{syntax}),
+@file{verifymsg} supports:
+
+@table @t
+@item l
+the full path to the file containing the log message to be verified
+@item @{sV@}
+File attributes, where:
+@table @t
+@item s
+file name
+@item V
+old version number (pre-checkin)
+@end table
+@end table
+
+@cindex verifymsg (admin/commit file), updating legacy repositories
+@cindex compatibility notes, verifymsg admin file
+Currently, if no format strings are specified, a default
+string of @samp{ %l} will be appended to the command
+line template before replacement is performed, but this
+feature is deprecated. It is simply in place so that legacy
+repositories will remain compatible with the new @sc{cvs} application.
+For information on updating, @pxref{Updating Commit Files}.
+
+One thing that should be noted is that the @samp{ALL}
+keyword is not supported. If more than one matching
+line is found, the first one is used. This can be
+useful for specifying a default verification script in a
+directory, and then overriding it in a subdirectory.
+
+@cindex Exit status, of @file{verifymsg}
+If the verification script exits with a non-zero exit status,
+the commit is aborted.
+
+@cindex @file{verifymsg}, changing the log message
+In the default configuration, CVS allows the
+verification script to change the log message. This is
+controlled via the RereadLogAfterVerify CVSROOT/config
+option.
+
+When @samp{RereadLogAfterVerify=always} or
+@samp{RereadLogAfterVerify=stat}, the log message will
+either always be reread after the verification script
+is run or reread only if the log message file status
+has changed.
+
+@xref{config}, for more on CVSROOT/config options.
+
+It is NOT a good idea for a @file{verifymsg} script to
+interact directly with the user in the various
+client/server methods. For the @code{pserver} method,
+there is no protocol support for communicating between
+@file{verifymsg} and the client on the remote end. For the
+@code{ext} and @code{server} methods, it is possible
+for CVS to become confused by the characters going
+along the same channel as the CVS protocol
+messages. See @ref{Remote repositories}, for more
+information on client/server setups. In addition, at the time
+the @file{verifymsg} script runs, the CVS
+server has locks in place in the repository. If control is
+returned to the user here then other users may be stuck waiting
+for access to the repository.
+
+This option can be useful if you find yourself using an
+rcstemplate that needs to be modified to remove empty
+elements or to fill in default values. It can also be
+useful if the rcstemplate has changed in the repository
+and the CVS/Template was not updated, but is able to be
+adapted to the new format by the verification script
+that is run by @file{verifymsg}.
+
+An example of an update might be to change all
+occurrences of 'BugId:' to be 'DefectId:' (which can be
+useful if the rcstemplate has recently been changed and
+there are still checked-out user trees with cached
+copies in the CVS/Template file of the older version).
+
+Another example of an update might be to delete a line
+that contains 'BugID: none' from the log message after
+validation of that value as being allowed is made.
+
+@menu
+* verifymsg example:: Verifymsg example
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node verifymsg example
+@appendixsubsubsec Verifying log messages
+@cindex verifymsg, example
+The following is a little silly example of a
+@file{verifymsg} file, together with the corresponding
+@file{rcsinfo} file, the log message template and a
+verification script. We begin with the log message template.
+We want to always record a bug-id number on the first
+line of the log message. The rest of log message is
+free text. The following template is found in the file
+@file{/usr/cvssupport/tc.template}.
+
+@example
+BugId:
+@end example
+
+The script @file{/usr/cvssupport/bugid.verify} is used to
+evaluate the log message.
+
+@example
+#!/bin/sh
+#
+# bugid.verify filename
+#
+# Verify that the log message contains a valid bugid
+# on the first line.
+#
+if sed 1q < $1 | grep '^BugId:[ ]*[0-9][0-9]*$' > /dev/null; then
+ exit 0
+elif sed 1q < $1 | grep '^BugId:[ ]*none$' > /dev/null; then
+ # It is okay to allow commits with 'BugId: none',
+ # but do not put that text into the real log message.
+ grep -v '^BugId:[ ]*none$' > $1.rewrite
+ mv $1.rewrite $1
+ exit 0
+else
+ echo "No BugId found."
+ exit 1
+fi
+@end example
+
+The @file{verifymsg} file contains this line:
+
+@example
+^tc /usr/cvssupport/bugid.verify %l
+@end example
+
+The @file{rcsinfo} file contains this line:
+
+@example
+^tc /usr/cvssupport/tc.template
+@end example
+
+The @file{config} file contains this line:
+
+@example
+RereadLogAfterVerify=always
+@end example
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node loginfo
+@appendixsubsec Loginfo
+@cindex loginfo (admin file)
+@cindex logging, commits
+@cindex Storing log messages
+@cindex Mailing log messages
+@cindex Distributing log messages
+@cindex Log messages
+
+The @file{loginfo} file is used to control where log information is sent after
+versioned changes are made to repository archive files and after directories
+are added ot the repository. @ref{posttag} for how to log tagging
+information and @ref{postadmin} for how to log changes due to the @code{admin}
+command.
+
+The @file{loginfo} file has the standard form for script hooks
+(@pxref{Trigger Scripts}), where each line is a regular expression followed by
+a command to execute. It supports the ALL and DEFAULT keywords.
+
+Any specified scripts are called:
+
+@table @code
+@item commit
+Once per directory, immediately after a successfully completing the commit of
+all files within that directory.
+@item import
+Once per import, immediately after completion of all write operations.
+@item add
+Immediately after the successful @code{add} of a directory.
+@end table
+
+Any script called via @file{loginfo} will be fed the log information on its
+standard input. Note that the filter program @strong{must} read @strong{all}
+of the log information from its standard input or @sc{cvs} may fail with a
+broken pipe signal.
+
+@cindex format strings, loginfo admin file
+In addition to the common format strings (@pxref{syntax}),
+@file{loginfo} supports:
+
+@table @t
+@item @{stVv@}
+File attributes, where:
+@table @t
+@item s
+file name
+@item T
+tag name of destination, or the empty string when there is no associated
+tag name (this usually means the trunk)
+@item V
+old version number (pre-checkin)
+@item v
+new version number (post-checkin)
+@end table
+@end table
+
+For example, some valid format strings are @samp{%%},
+@samp{%s}, @samp{%@{s@}}, and @samp{%@{stVv@}}.
+
+@cindex loginfo (admin file), updating legacy repositories
+@cindex compatibility notes, loginfo admin file
+Currently, if @samp{UseNewInfoFmtStrings} is not set in the @file{config}
+administration file (@pxref{config}), the format strings will be substituted
+as they were in past versions of @sc{cvs}, but this feature is deprecated.
+It is simply in place so that legacy repositories will remain compatible with
+the new @sc{cvs} application. For information on updating,
+please see @ref{Updating Commit Files}.
+
+As an example, if @samp{/u/src/master/yoyodyne/tc} is the repository, @samp{%p}
+and @samp{%@{sVv@}} are the format strings, and three files (@t{ChangeLog},
+@t{Makefile}, @t{foo.c}) were modified, the output might be:
+
+@example
+yoyodyne/tc ChangeLog 1.1 1.2 Makefile 1.3 1.4 foo.c 1.12 1.13
+@end example
+
+Note: when @sc{cvs} is accessing a remote repository,
+@file{loginfo} will be run on the @emph{remote}
+(i.e., server) side, not the client side (@pxref{Remote
+repositories}).
+
+@menu
+* loginfo example:: Loginfo example
+* Keeping a checked out copy:: Updating a tree on every checkin
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node loginfo example
+@appendixsubsubsec Loginfo example
+
+The following @file{loginfo} file, together with the
+tiny shell-script below, appends all log messages
+to the file @file{$CVSROOT/CVSROOT/commitlog},
+and any commits to the administrative files (inside
+the @file{CVSROOT} directory) are also logged in
+@file{/usr/adm/cvsroot-log}.
+Commits to the @file{prog1} directory are mailed to @t{ceder}.
+
+@c FIXME: is it a CVS feature or bug that only the
+@c first matching line is used? It is documented
+@c above, but is it useful? For example, if we wanted
+@c to run both "cvs-log" and "Mail" for the CVSROOT
+@c directory, it is kind of awkward if
+@c only the first matching line is used.
+@example
+ALL /usr/local/bin/cvs-log $CVSROOT/CVSROOT/commitlog $USER
+^CVSROOT\(/\|$\) /usr/local/bin/cvs-log /usr/adm/cvsroot-log $USER
+^prog1\(/\|$\) Mail -s "%p %s" ceder
+@end example
+
+The shell-script @file{/usr/local/bin/cvs-log} looks
+like this:
+
+@example
+#!/bin/sh
+(echo "------------------------------------------------------";
+ echo -n "$2 ";
+ date;
+ echo;
+ cat) >> $1
+@end example
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Keeping a checked out copy
+@appendixsubsubsec Keeping a checked out copy
+
+@c What other index entries? It seems like
+@c people might want to use a lot of different
+@c words for this functionality.
+@cindex Keeping a checked out copy
+@cindex Checked out copy, keeping
+@cindex Web pages, maintaining with CVS
+
+It is often useful to maintain a directory tree which
+contains files which correspond to the latest version
+in the repository. For example, other developers might
+want to refer to the latest sources without having to
+check them out, or you might be maintaining a web site
+with @sc{cvs} and want every checkin to cause the files
+used by the web server to be updated.
+@c Can we offer more details on the web example? Or
+@c point the user at how to figure it out? This text
+@c strikes me as sufficient for someone who already has
+@c some idea of what we mean but not enough for the naive
+@c user/sysadmin to understand it and set it up.
+
+The way to do this is by having loginfo invoke
+@code{cvs update}. Doing so in the naive way will
+cause a problem with locks, so the @code{cvs update}
+must be run in the background.
+@c Should we try to describe the problem with locks?
+@c It seems like a digression for someone who just
+@c wants to know how to make it work.
+@c Another choice which might work for a single file
+@c is to use "cvs -n update -p" which doesn't take
+@c out locks (I think) but I don't see many advantages
+@c of that and we might as well document something which
+@c works for multiple files.
+Here is an example for unix (this should all be on one line):
+
+@example
+^cyclic-pages\(/\|$\) (date; cat; (sleep 2; cd /u/www/local-docs;
+ cvs -q update -d) &) >> $CVSROOT/CVSROOT/updatelog 2>&1
+@end example
+
+This will cause checkins to repository directory @code{cyclic-pages}
+and its subdirectories to update the checked
+out tree in @file{/u/www/local-docs}.
+@c More info on some of the details? The "sleep 2" is
+@c so if we are lucky the lock will be gone by the time
+@c we start and we can wait 2 seconds instead of 30.
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node postadmin
+@appendixsubsec Logging admin commands
+@cindex postadmin (admin file)
+@cindex script hook, postadmin
+@cindex Admin commands, logging
+
+The @file{postadmin} file defines programs to execute after an @code{admin}
+command modifies files. The @file{postadmin} file has the standard form
+for script hooks (@pxref{Trigger Scripts}), where each line is a regular
+expression followed by a command to execute. It supports the ALL and DEFAULT
+keywords.
+
+@cindex format strings, postadmin admin file
+The @file{postadmin} file supports no format strings other than the common
+ones (@pxref{syntax}),
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node taginfo
+@appendixsubsec Taginfo
+@cindex taginfo (admin file)
+@cindex script hook, taginfo
+@cindex Tags, logging
+@cindex Tags, verifying
+The @file{taginfo} file defines programs to execute
+when someone executes a @code{tag} or @code{rtag}
+command. The @file{taginfo} file has the standard form
+for script hooks (@pxref{Trigger Scripts}), where each line
+is a regular expression followed by a command to execute.
+It supports the ALL and DEFAULT keywords.
+
+@cindex format strings, taginfo admin file
+In addition to the common format strings (@pxref{syntax}),
+@file{taginfo} supports:
+
+@table @t
+@item b
+tag type (@code{T} for branch, @code{N} for not-branch, or @code{?} for
+unknown, as during delete operations)
+@item o
+operation (@code{add} for @code{tag}, @code{mov} for @code{tag -F}, or
+@code{del} for @code{tag -d})
+@item t
+new tag name
+@item @{sTVv@}
+file attributes, where:
+@table @t
+@item s
+file name
+@item T
+tag name of destination, or the empty string when there is no associated
+tag name (this usually means the trunk)
+@item V
+old version number (for a move or delete operation)
+@item v
+new version number (for an add or move operation)
+@end table
+@end table
+
+For example, some valid format strings are @samp{%%}, @samp{%p}, @samp{%t},
+@samp{%s}, @samp{%@{s@}}, and @samp{%@{sVv@}}.
+
+@cindex taginfo (admin file), updating legacy repositories
+@cindex compatibility notes, taginfo admin file
+Currently, if no format strings are specified, a default
+string of @samp{ %t %o %p %@{sv@}} will be appended to the command
+line template before replacement is performed, but this
+feature is deprecated. It is simply in place so that legacy
+repositories will remain compatible with the new @sc{cvs} application.
+For information on updating, @pxref{Updating Commit Files}.
+
+@cindex Exit status, of taginfo admin file
+@cindex taginfo (admin file), exit status
+A non-zero exit of the filter program will cause the tag to be
+aborted.
+
+Here is an example of using @file{taginfo} to log @code{tag} and @code{rtag}
+commands. In the @file{taginfo} file put:
+
+@example
+ALL /usr/local/cvsroot/CVSROOT/loggit %t %b %o %p %@{sVv@}
+@end example
+
+@noindent
+Where @file{/usr/local/cvsroot/CVSROOT/loggit} contains the
+following script:
+
+@example
+#!/bin/sh
+echo "$@@" >>/home/kingdon/cvsroot/CVSROOT/taglog
+@end example
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node posttag
+@appendixsubsec Logging tags
+@cindex posttag (admin file)
+@cindex script hook, posttag
+@cindex Tags, logging
+
+The @file{posttag} file defines programs to execute after a @code{tag} or
+@code{rtag} command modifies files. The @file{posttag} file has the standard
+form for script hooks (@pxref{Trigger Scripts}), where each line is a regular
+expression followed by a command to execute. It supports the ALL and DEFAULT
+keywords.
+
+@cindex format strings, posttag admin file
+The @file{posttag} admin file supports the same format strings as the
+@file{taginfo} file (@pxref{taginfo}),
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node postwatch
+@appendixsubsec Logging watch commands
+@cindex postwatch (admin file)
+@cindex script hook, postwatch
+@cindex Watch family of commands, logging
+
+The @file{postwatch} file defines programs to execute after any command (for
+instance, @code{watch}, @code{edit}, @code{unedit}, or @code{commit}) modifies
+any @file{CVS/fileattr} file in the repository (@pxref{Watches}). The
+@file{postwatch} file has the standard form for script hooks
+(@pxref{Trigger Scripts}), where each line is a regular expression followed by
+a command to execute. It supports the ALL and DEFAULT keywords.
+
+@cindex format strings, postwatch admin file
+The @file{postwatch} file supports no format strings other than the common
+ones (@pxref{syntax}), but it is worth noting that the @code{%c} format string
+may not be replaced as you might expect. Client runs of @code{edit} and
+@code{unedit} can sometimes skip contacting the @sc{cvs} server and cache the
+notification of the file attribute change to be sent the next time the client
+contacts the server for whatever other reason,
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node preproxy
+@appendixsubsec Launch a Script before Proxying
+@cindex preproxy (admin file)
+@cindex script hook, preproxy
+@cindex Write proxy, verifying
+@cindex Write proxy, logging
+
+The @file{preproxy} file defines programs to execute after a secondary
+server receives a write request from a client, just before it starts up the
+primary server and becomes a write proxy. This hook could be used to
+dial a modem, launch an SSH tunnel, establish a VPN, or anything else that
+might be necessary to do before contacting the primary server.
+
+@file{preproxy} scripts are called once, at the time of the write request, with
+the repository argument (if requested) set from the topmost directory sent by
+the client.
+
+The @file{preproxy} file has the standard form
+for script hooks (@pxref{Trigger Scripts}), where each line is a regular
+expression followed by a command to execute. It supports the ALL and DEFAULT
+keywords.
+
+@cindex format strings, preproxy admin file
+In addition to the common format strings, the @file{preproxy} file supports the
+following format string:
+
+@table @t
+@item P
+the CVSROOT string which specifies the primary server
+@end table
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node postproxy
+@appendixsubsec Launch a Script after Proxying
+@cindex postproxy (admin file)
+@cindex script hook, postproxy
+@cindex Write proxy, logging
+@cindex Write proxy, pull updates
+@cindex secondary server, pull updates
+
+The @file{postproxy} file defines programs to execute after a secondary
+server notes that the connection to the primary server has shut down and before
+it releases the client by shutting down the connection to the client.
+This could hook could be used to
+disconnect a modem, an SSH tunnel, a VPN, or anything else that
+might be necessary to do after contacting the primary server. This hook should
+also be used to pull updates from the primary server before allowing the client
+which did the write to disconnect since otherwise the client's next read
+request may generate error messages and fail upon encountering an out of date
+repository on the secondary server.
+
+@file{postproxy} scripts are called once per directory.
+
+The @file{postproxy} file has the standard form
+for script hooks (@pxref{Trigger Scripts}), where each line is a regular
+expression followed by a command to execute. It supports the ALL and DEFAULT
+keywords.
+
+@cindex format strings, postproxy admin file
+In addition to the common format strings, the @file{postproxy} file supports
+the following format string:
+
+@table @t
+@item P
+the CVSROOT string which specifies the primary server
+@end table
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node rcsinfo
+@appendixsec Rcsinfo
+@cindex rcsinfo (admin file)
+@cindex Form for log message
+@cindex Log message template
+@cindex Template for log message
+@cindex logging, commits
+
+The @file{rcsinfo} file can be used to specify a form to
+edit when filling out the commit log. The
+@file{rcsinfo} file has a syntax similar to the
+@file{verifymsg}, @file{commitinfo} and @file{loginfo}
+files. @xref{syntax}. Unlike the other files the second
+part is @emph{not} a command-line template. Instead,
+the part after the regular expression should be a full pathname to
+a file containing the log message template.
+
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+All occurrences of the name @samp{ALL} appearing as a
+regular expression are used in addition to the first
+matching regular expression or @samp{DEFAULT}.
+
+@c FIXME: should be offering advice, somewhere around
+@c here, about where to put the template file. The
+@c verifymsg example uses /usr/cvssupport but doesn't
+@c say anything about what that directory is for or
+@c whether it is hardwired into CVS or who creates
+@c it or anything. In particular we should say
+@c how to version control the template file. A
+@c probably better answer than the /usr/cvssupport
+@c stuff is to use checkoutlist (with xref to the
+@c checkoutlist doc).
+@c Also I am starting to see a connection between
+@c this and the Keeping a checked out copy node.
+@c Probably want to say something about that.
+The log message template will be used as a default log
+message. If you specify a log message with @samp{cvs
+commit -m @var{message}} or @samp{cvs commit -f
+@var{file}} that log message will override the
+template.
+
+@xref{verifymsg}, for an example @file{rcsinfo}
+file.
+
+When @sc{cvs} is accessing a remote repository,
+the contents of @file{rcsinfo} at the time a directory
+is first checked out will specify a template. This
+template will be updated on all @samp{cvs update}
+commands. It will also be added to new directories
+added with a @samp{cvs add new-directory} command.
+In versions of @sc{cvs} prior to version 1.12, the
+@file{CVS/Template} file was not updated. If the
+@sc{cvs} server is at version 1.12 or higher an older
+client may be used and the @file{CVS/Template} will
+be updated from the server.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node cvsignore
+@appendixsec Ignoring files via cvsignore
+@cindex cvsignore (admin file), global
+@cindex Global cvsignore
+@cindex Ignoring files
+@c -- This chapter should maybe be moved to the
+@c tutorial part of the manual?
+
+There are certain file names that frequently occur
+inside your working copy, but that you don't want to
+put under @sc{cvs} control. Examples are all the object
+files that you get while you compile your sources.
+Normally, when you run @samp{cvs update}, it prints a
+line for each file it encounters that it doesn't know
+about (@pxref{update output}).
+
+@sc{cvs} has a list of files (or sh(1) file name patterns)
+that it should ignore while running @code{update},
+@code{import} and @code{release}.
+@c -- Are those the only three commands affected?
+This list is constructed in the following way.
+
+@itemize @bullet
+@item
+The list is initialized to include certain file name
+patterns: names associated with @sc{cvs}
+administration, or with other common source control
+systems; common names for patch files, object files,
+archive files, and editor backup files; and other names
+that are usually artifacts of assorted utilities.
+Currently, the default list of ignored file name
+patterns is:
+
+@cindex Ignored files
+@cindex Automatically ignored files
+@example
+ RCS SCCS CVS CVS.adm
+ RCSLOG cvslog.*
+ tags TAGS
+ .make.state .nse_depinfo
+ *~ #* .#* ,* _$* *$
+ *.old *.bak *.BAK *.orig *.rej .del-*
+ *.a *.olb *.o *.obj *.so *.exe
+ *.Z *.elc *.ln
+ core
+@end example
+
+@item
+The per-repository list in
+@file{$CVSROOT/CVSROOT/cvsignore} is appended to
+the list, if that file exists.
+
+@item
+The per-user list in @file{.cvsignore} in your home
+directory is appended to the list, if it exists.
+
+@item
+Any entries in the environment variable
+@code{$CVSIGNORE} is appended to the list.
+
+@item
+Any @samp{-I} options given to @sc{cvs} is appended.
+
+@item
+As @sc{cvs} traverses through your directories, the contents
+of any @file{.cvsignore} will be appended to the list.
+The patterns found in @file{.cvsignore} are only valid
+for the directory that contains them, not for
+any sub-directories.
+@end itemize
+
+In any of the 5 places listed above, a single
+exclamation mark (@samp{!}) clears the ignore list.
+This can be used if you want to store any file which
+normally is ignored by @sc{cvs}.
+
+Specifying @samp{-I !} to @code{cvs import} will import
+everything, which is generally what you want to do if
+you are importing files from a pristine distribution or
+any other source which is known to not contain any
+extraneous files. However, looking at the rules above
+you will see there is a fly in the ointment; if the
+distribution contains any @file{.cvsignore} files, then
+the patterns from those files will be processed even if
+@samp{-I !} is specified. The only workaround is to
+remove the @file{.cvsignore} files in order to do the
+import. Because this is awkward, in the future
+@samp{-I !} might be modified to override
+@file{.cvsignore} files in each directory.
+
+Note that the syntax of the ignore files consists of a
+series of lines, each of which contains a space
+separated list of filenames. This offers no clean way
+to specify filenames which contain spaces, but you can
+use a workaround like @file{foo?bar} to match a file
+named @file{foo bar} (it also matches @file{fooxbar}
+and the like). Also note that there is currently no
+way to specify comments.
+@c FIXCVS? I don't _like_ this syntax at all, but
+@c changing it raises all the usual compatibility
+@c issues and I'm also not sure what to change it to.
+
+@node checkoutlist
+@appendixsec The checkoutlist file
+@cindex checkoutlist
+
+It may be helpful to use @sc{cvs} to maintain your own
+files in the @file{CVSROOT} directory. For example,
+suppose that you have a script @file{logcommit.pl}
+which you run by including the following line in the
+@file{commitinfo} administrative file:
+
+@example
+ALL $CVSROOT/CVSROOT/logcommit.pl %r/%p %s
+@end example
+
+To maintain @file{logcommit.pl} with @sc{cvs} you would
+add the following line to the @file{checkoutlist}
+administrative file:
+
+@example
+logcommit.pl
+@end example
+
+The format of @file{checkoutlist} is one line for each
+file that you want to maintain using @sc{cvs}, giving
+the name of the file, followed optionally by more whitespace
+and any error message that should print if the file cannot be
+checked out into CVSROOT after a commit:
+
+@example
+logcommit.pl Could not update CVSROOT/logcommit.pl.
+@end example
+
+After setting up @file{checkoutlist} in this fashion,
+the files listed there will function just like
+@sc{cvs}'s built-in administrative files. For example,
+when checking in one of the files you should get a
+message such as:
+
+@example
+cvs commit: Rebuilding administrative file database
+@end example
+
+@noindent
+and the checked out copy in the @file{CVSROOT}
+directory should be updated.
+
+Note that listing @file{passwd} (@pxref{Password
+authentication server}) in @file{checkoutlist} is not
+recommended for security reasons.
+
+For information about keeping a checkout out copy in a
+more general context than the one provided by
+@file{checkoutlist}, see @ref{Keeping a checked out
+copy}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node history file
+@appendixsec The history file
+@cindex History file
+@cindex Log information, saving
+
+By default, the file @file{$CVSROOT/CVSROOT/history} is used
+to log information for the @code{history} command (@pxref{history}).
+This file name may be changed with the @samp{HistoryLogPath} and
+@samp{HistorySearchPath} config options (@pxref{config}).
+
+The file format of the @file{history} file is
+documented only in comments in the @sc{cvs} source
+code, but generally programs should use the @code{cvs
+history} command to access it anyway, in case the
+format changes with future releases of @sc{cvs}.
+
+@node Variables
+@appendixsec Expansions in administrative files
+@cindex Internal variables
+@cindex Variables
+
+Sometimes in writing an administrative file, you might
+want the file to be able to know various things based
+on environment @sc{cvs} is running in. There are
+several mechanisms to do that.
+
+To find the home directory of the user running @sc{cvs}
+(from the @code{HOME} environment variable), use
+@samp{~} followed by @samp{/} or the end of the line.
+Likewise for the home directory of @var{user}, use
+@samp{~@var{user}}. These variables are expanded on
+the server machine, and don't get any reasonable
+expansion if pserver (@pxref{Password authenticated})
+is in use; therefore user variables (see below) may be
+a better choice to customize behavior based on the user
+running @sc{cvs}.
+@c Based on these limitations, should we deprecate ~?
+@c What is it good for? Are people using it?
+
+One may want to know about various pieces of
+information internal to @sc{cvs}. A @sc{cvs} internal
+variable has the syntax @code{$@{@var{variable}@}},
+where @var{variable} starts with a letter and consists
+of alphanumeric characters and @samp{_}. If the
+character following @var{variable} is a
+non-alphanumeric character other than @samp{_}, the
+@samp{@{} and @samp{@}} can be omitted. The @sc{cvs}
+internal variables are:
+
+@table @code
+@item CVSROOT
+@cindex CVSROOT, internal variable
+This is the absolute path to the current @sc{cvs} root directory.
+@xref{Repository}, for a description of the various
+ways to specify this, but note that the internal
+variable contains just the directory and not any
+of the access method information.
+
+@item RCSBIN
+@cindex RCSBIN, internal variable
+In @sc{cvs} 1.9.18 and older, this specified the
+directory where @sc{cvs} was looking for @sc{rcs}
+programs. Because @sc{cvs} no longer runs @sc{rcs}
+programs, specifying this internal variable is now an
+error.
+
+@item CVSEDITOR
+@cindex CVSEDITOR, internal variable
+@itemx EDITOR
+@cindex EDITOR, internal variable
+@itemx VISUAL
+@cindex VISUAL, internal variable
+These all expand to the same value, which is the editor
+that @sc{cvs} is using. @xref{Global options}, for how
+to specify this.
+
+@item USER
+@cindex USER, internal variable
+Username of the user running @sc{cvs} (on the @sc{cvs}
+server machine).
+When using pserver, this is the user specified in the repository
+specification which need not be the same as the username the
+server is running as (@pxref{Password authentication server}).
+Do not confuse this with the environment variable of the same name.
+
+@item SESSIONID
+@cindex COMMITID, internal variable
+Unique Session ID of the @sc{cvs} process. This is a
+random string of printable characters of at least 16
+characters length. Users should assume that it may
+someday grow to at most 256 characters in length.
+
+@item COMMITID
+@cindex COMMITID, internal variable
+Unique Session ID of the @sc{cvs} process. This is a
+random string of printable characters of at least 16
+characters length. Users should assume that it may
+someday grow to at most 256 characters in length.
+@end table
+
+If you want to pass a value to the administrative files
+which the user who is running @sc{cvs} can specify,
+use a user variable.
+@cindex User variables
+To expand a user variable, the
+administrative file contains
+@code{$@{=@var{variable}@}}. To set a user variable,
+specify the global option @samp{-s} to @sc{cvs}, with
+argument @code{@var{variable}=@var{value}}. It may be
+particularly useful to specify this option via
+@file{.cvsrc} (@pxref{~/.cvsrc}).
+
+For example, if you want the administrative file to
+refer to a test directory you might create a user
+variable @code{TESTDIR}. Then if @sc{cvs} is invoked
+as
+
+@example
+cvs -s TESTDIR=/work/local/tests
+@end example
+
+@noindent
+and the
+administrative file contains @code{sh
+$@{=TESTDIR@}/runtests}, then that string is expanded
+to @code{sh /work/local/tests/runtests}.
+
+All other strings containing @samp{$} are reserved;
+there is no way to quote a @samp{$} character so that
+@samp{$} represents itself.
+
+Environment variables passed to administrative files are:
+
+@table @code
+@cindex environment variables, passed to administrative files
+
+@item CVS_USER
+@cindex CVS_USER, environment variable
+The @sc{cvs}-specific username provided by the user, if it
+can be provided (currently just for the pserver access
+method), and to the empty string otherwise. (@code{CVS_USER}
+and @code{USER} may differ when @file{$CVSROOT/CVSROOT/passwd}
+is used to map @sc{cvs} usernames to system usernames.)
+
+@item LOGNAME
+@cindex LOGNAME, environment variable
+The username of the system user.
+
+@item USER
+@cindex USER, environment variable
+Same as @code{LOGNAME}.
+Do not confuse this with the internal variable of the same name.
+@end table
+
+@node config
+@appendixsec The CVSROOT/config configuration file
+
+@cindex configuration file
+@cindex config, in CVSROOT
+@cindex CVSROOT/config
+
+Usually, the @file{config} file is found at @file{$CVSROOT/CVSROOT/config},
+but this may be overridden on the @code{pserver} and @code{server} command
+lines (@pxref{server & pserver}).
+
+The administrative file @file{config} contains various
+miscellaneous settings which affect the behavior of
+@sc{cvs}. The syntax is slightly different from the
+other administrative files.
+
+Leading white space on any line is ignored, though the syntax is very strict
+and will reject spaces and tabs almost anywhere else.
+
+Empty lines, lines containing nothing but white space, and lines which start
+with @samp{#} (discounting any leading white space) are ignored.
+
+@c FIXME: where do we define comments for the other
+@c administrative files.
+Other lines consist of the optional leading white space, a keyword, @samp{=},
+and a value. Please note again that this syntax is very strict.
+Extraneous spaces or tabs, other than the leading white space, are not
+permitted on these lines.
+@c See comments in parseinfo.c:parse_config for more
+@c discussion of this strictness.
+
+As of CVS 1.12.13, lines of the form @samp{[@var{CVSROOT}]} mark the subsequent
+section of the config file as applying only to certain repositories. Multiple
+@samp{[@var{CVSROOT}]} lines without intervening
+@samp{@var{KEYWORD}=@var{VALUE}} pairs cause processing to fall through,
+processing subsequent keywords for any root in the list. Finally, keywords
+and values which appear before any @samp{[@var{CVSROOT}]} lines are defaults,
+and may to apply to any repository. For example, consider the following file:
+
+@example
+# Defaults
+LogHistory=TMAR
+
+[/cvsroots/team1]
+ LockDir=/locks/team1
+
+[/cvsroots/team2]
+ LockDir=/locks/team2
+
+[/cvsroots/team3]
+ LockDir=/locks/team3
+
+[/cvsroots/team4]
+ LockDir=/locks/team4
+
+[/cvsroots/team3]
+[/cvsroots/team4]
+ # Override logged commands for teams 3 & 4.
+ LogHistory=all
+@end example
+
+This example file sets up separate lock directories for each project, as well
+as a default set of logged commands overridden for the example's team 3 &
+team 4. This syntax could be useful, for instance, if you wished to share a
+single config file, for instance @file{/etc/cvs.conf}, among several
+repositories.
+
+Currently defined keywords are:
+
+@table @code
+@cindex HistoryLogPath, in CVSROOT/config
+@item HistorySearchPath=@var{pattern}
+Request that @sc{cvs} look for its history information in files matching
+@var{pattern}, which is a standard UNIX file glob. If @var{pattern} matches
+multiple files, all will be searched in lexicographically sorted order.
+@xref{history}, and @ref{history file}, for more.
+
+If no value is supplied for this option, it defaults to
+@file{$CVSROOT/CVSROOT/history}.
+
+@cindex HistorySearchPath, in CVSROOT/config
+@item HistoryLogPath=@var{path}
+Control where @sc{cvs} logs its history. If the file does not exist, @sc{cvs}
+will attempt to create it. Format strings, as available to the GNU C
+@code{strftime} function and often the UNIX date command, and the string
+@var{$CVSROOT} will be substituted in this path. For example, consider the
+line:
+
+@example
+HistoryLogPath=$CVSROOT/CVSROOT/history/%Y-%m-%d
+@end example
+
+This line would cause @sc{cvs} to attempt to create its history file in a
+subdirectory (@file{history}) of the configuration directory (@file{CVSROOT})
+with a name equal to the current date representation in the ISO8601 format (for
+example, on May 11, 2005, @sc{cvs} would attempt to log its history under the
+repository root directory in a file named @file{CVSROOT/history/2005-05-11}).
+@xref{history}, and @ref{history file}, for more.
+
+If no value is supplied for this option, it defaults to
+@file{$CVSROOT/CVSROOT/history}.
+
+@cindex ImportNewFilesToVendorBranchOnly, in CVSROOT/config
+@cindex import, config admin file
+@cindex config (admin file), import
+@item ImportNewFilesToVendorBranchOnly=@var{value}
+Specify whether @code{cvs import} should always behave as if the
+@samp{-X} flag was specified on the command line.
+@var{value} may be either @samp{yes} or @samp{no}. If set to @samp{yes},
+all uses of @code{cvs import} on the repository will behave as if the
+@samp{-X} flag was set. The default value is @samp{no}.
+
+@cindex KeywordExpand, in CVSROOT/config
+@item KeywordExpand=@var{value}
+Specify @samp{i} followed by a list of keywords to be expanded
+(for example, @samp{KeywordExpand=iMYCVS,Name,Date}),
+or @samp{e} followed by a list of keywords not to be expanded
+(for example, @samp{KeywordExpand=eCVSHeader}).
+For more on keyword expansion, see @ref{Configuring keyword expansion}.
+
+@cindex LocalKeyword, in CVSROOT/config
+@item LocalKeyword=@var{value}
+Specify a local alias for a standard keyword.
+For example, @samp{LocalKeyword=MYCVS=CVSHeader}.
+For more on local keywords, see @ref{Keyword substitution}.
+
+@cindex LockDir, in CVSROOT/config
+@item LockDir=@var{directory}
+Put @sc{cvs} lock files in @var{directory} rather than
+directly in the repository. This is useful if you want
+to let users read from the repository while giving them
+write access only to @var{directory}, not to the
+repository.
+It can also be used to put the locks on a very fast
+in-memory file system to speed up locking and unlocking
+the repository.
+You need to create @var{directory}, but
+@sc{cvs} will create subdirectories of @var{directory} as it
+needs them. For information on @sc{cvs} locks, see
+@ref{Concurrency}.
+
+@c Mention this in Compatibility section?
+Before enabling the LockDir option, make sure that you
+have tracked down and removed any copies of @sc{cvs} 1.9 or
+older. Such versions neither support LockDir, nor will
+give an error indicating that they don't support it.
+The result, if this is allowed to happen, is that some
+@sc{cvs} users will put the locks one place, and others will
+put them another place, and therefore the repository
+could become corrupted. @sc{cvs} 1.10 does not support
+LockDir but it will print a warning if run on a
+repository with LockDir enabled.
+
+@cindex LogHistory, in CVSROOT/config
+@item LogHistory=@var{value}
+Control what is logged to the @file{CVSROOT/history} file (@pxref{history}).
+Default of @samp{TOEFWUPCGMAR} (or simply @samp{all}) will log
+all transactions. Any subset of the default is
+legal. (For example, to only log transactions that modify the
+@file{*,v} files, use @samp{LogHistory=TMAR}.) To disable history logging
+completely, use @samp{LogHistory=}.
+
+@cindex MaxCommentLeaderLength, in CVSROOT/config
+@cindex Log keyword, configuring substitution behavior
+@item MaxCommentLeaderLength=@var{length}
+Set to some length, in bytes, where a trailing @samp{k}, @samp{M}, @samp{G},
+or @samp{T} causes the preceding nubmer to be interpreted as kilobytes,
+megabytes, gigabytes, or terrabytes, respectively, will cause
+@code{$@splitrcskeyword{Log}$} keywords (@pxref{Keyword substitution}), with
+more than @var{length} bytes preceding it on a line to be ignored (or to fall
+back on the comment leader set in the RCS archive file - see
+@code{UseArchiveCommentLeader} below). Defaults to 20 bytes to allow checkouts
+to proceed normally when they include binary files containing
+@code{$@splitrcskeyword{Log}$} keywords and which users have neglected to mark
+as binary.
+
+@cindex MinCompressionLevel, in CVSROOT/config
+@cindex MaxCompressionLevel, in CVSROOT/config
+@cindex Compression levels, restricting on server
+@item MinCompressionLevel=@var{value}
+@itemx MaxCompressionLevel=@var{value}
+Restricts the level of compression used by the @sc{cvs} server to a @var{value}
+between 0 and 9. @var{value}s 1 through 9 are the same @sc{zlib} compression
+levels accepted by the @samp{-z} option (@pxref{Global options}), and 0 means
+no compression. When one or both of these keys are set and a client requests a
+level outside the specified range, the server will simply use the closest
+permissable level. Clients will continue compressing at the level requested by
+the user.
+
+The exception is when level 0 (no compression) is not available and the client
+fails to request any compression. The @sc{cvs} server will then exit with an
+error message when it becomes apparent that the client is not going to request
+compression. This will not happen with clients version 1.12.13 and later since
+these client versions allow the server to notify them that they must request
+some level of compression.
+
+@ignore
+@cindex PreservePermissions, in CVSROOT/config
+@item PreservePermissions=@var{value}
+Enable support for saving special device files,
+symbolic links, file permissions and ownerships in the
+repository. The default value is @samp{no}.
+@xref{Special Files}, for the full implications of using
+this keyword.
+@end ignore
+
+@cindex PrimaryServer, in CVSROOT/config
+@cindex Primary server
+@cindex Secondary server
+@cindex proxy, write
+@cindex write proxy
+@item PrimaryServer=@var{CVSROOT}
+When specified, and the repository specified by @var{CVSROOT} is not the one
+currently being accessed, then the server will turn itself into a transparent
+proxy to @var{CVSROOT} for write requests. The @var{hostname} configured as
+part of @var{CVSROOT} must resolve to the same string returned by the
+@command{uname} command on the primary server for this to work. Host name
+resolution is performed via some combination of @command{named}, a broken out
+line from @file{/etc/hosts}, and the Network Information Service (NIS or YP),
+depending on the configuration of the particular system.
+
+Only the @samp{:ext:} method is
+currently supported for primaries (actually, @samp{:fork:} is supported as
+well, but only for testing - if you find another use for accessing a primary
+via the @samp{:fork:} method, please send a note to @email{bug-cvs@@nongnu.org}
+about it). See @ref{Write proxies} for more on configuring and using write
+proxies.
+
+@cindex RCSBIN, in CVSROOT/config
+@item RCSBIN=@var{bindir}
+For @sc{cvs} 1.9.12 through 1.9.18, this setting told
+@sc{cvs} to look for @sc{rcs} programs in the
+@var{bindir} directory. Current versions of @sc{cvs}
+do not run @sc{rcs} programs; for compatibility this
+setting is accepted, but it does nothing.
+
+@cindex RereadLogAfterVerify, in CVSROOT/config
+@cindex @file{verifymsg}, changing the log message
+@item RereadLogAfterVerify=@var{value}
+Modify the @samp{commit} command such that CVS will reread the
+log message after running the program specified by @file{verifymsg}.
+@var{value} may be one of @samp{yes} or @samp{always}, indicating that
+the log message should always be reread; @samp{no}
+or @samp{never}, indicating that it should never be
+reread; or @var{value} may be @samp{stat}, indicating
+that the file should be checked with the file system
+@samp{stat()} function to see if it has changed (see warning below)
+before rereading. The default value is @samp{always}.
+
+@strong{Note: the `stat' mode can cause CVS to pause for up to
+one extra second per directory committed. This can be less IO and
+CPU intensive but is not recommended for use with large repositories}
+
+@xref{verifymsg}, for more information on how verifymsg
+may be used.
+
+@cindex SystemAuth, in CVSROOT/config
+@item SystemAuth=@var{value}
+If @var{value} is @samp{yes}, then pserver should check
+for users in the system's user database if not found in
+@file{CVSROOT/passwd}. If it is @samp{no}, then all
+pserver users must exist in @file{CVSROOT/passwd}.
+The default is @samp{yes}. For more on pserver, see
+@ref{Password authenticated}.
+
+@cindex TmpDir, in config
+@cindex temporary files, location of
+@cindex temporary directory, set in config
+@item TmpDir=@var{path}
+Specify @var{path} as the directory to create temporary files in.
+@xref{Global options}, for more on setting the path to the temporary
+directory. This option first appeared with @sc{cvs} release 1.12.13.
+
+@cindex TopLevelAdmin, in CVSROOT/config
+@item TopLevelAdmin=@var{value}
+Modify the @samp{checkout} command to create a
+@samp{CVS} directory at the top level of the new
+working directory, in addition to @samp{CVS}
+directories created within checked-out directories.
+The default value is @samp{no}.
+
+This option is useful if you find yourself performing
+many commands at the top level of your working
+directory, rather than in one of the checked out
+subdirectories. The @file{CVS} directory created there
+will mean you don't have to specify @code{CVSROOT} for
+each command. It also provides a place for the
+@file{CVS/Template} file (@pxref{Working directory
+storage}).
+
+@cindex UseArchiveCommentLeader, in CVSROOT/config
+@cindex Log keyword, configuring substitution behavior
+@item UseArchiveCommentLeader=@var{value}
+Set to @code{true}, if the text preceding a @code{$@splitrcskeyword{Log}$}
+keyword is found to exceed @code{MaxCommentLeaderLength} (above) bytes, then
+the comment leader set in the RCS archive file (@pxref{admin}), if any, will
+be used instead. If there is no comment leader set in the archive file or
+@var{value} is set to @samp{false}, then the keyword will not be expanded
+(@pxref{Keyword list}). To force the comment leader in the RCS archive file to
+be used exclusively (and @code{$@splitrcskeyword{Log}$} expansion skipped in
+files where the comment leader has not been set in the archive file), set
+@var{value} and set @code{MaxCommentLeaderLength} to @code{0}.
+
+@cindex UseNewInfoFmtStrings, in CVSROOT/config
+@cindex format strings, config admin file
+@cindex config (admin file), updating legacy repositories
+@cindex compatibility notes, config admin file
+@item UseNewInfoFmtStrings=@var{value}
+Specify whether @sc{cvs} should support the new or old command line
+template model for the commit support files (@pxref{commit files}).
+This configuration variable began life in deprecation and is only here
+in order to give people time to update legacy repositories to use the new
+format string syntax before support for the old syntax is removed. For
+information on updating your repository to support the new model,
+please see @ref{Updating Commit Files}.
+
+@emph{Note that new repositories (created with the @code{cvs init} command)
+will have this value set to @samp{yes}, but the default value is @samp{no}.}
+
+@cindex UserAdminOptions, in CVSROOT/config
+@item UserAdminOptions=@var{value}
+Control what options will be allowed with the @code{cvs admin}
+command (@pxref{admin}) for users not in the @code{cvsadmin} group.
+The @var{value} string is a list of single character options
+which should be allowed. If a user who is not a member of the
+@code{cvsadmin} group tries to execute any @code{cvs admin}
+option which is not listed they will will receive an error message
+reporting that the option is restricted.
+
+If no @code{cvsadmin} group exists on the server, @sc{cvs} will
+ignore the @code{UserAdminOptions} keyword (@pxref{admin}).
+
+When not specified, @code{UserAdminOptions} defaults to
+@samp{k}. In other words, it defaults to allowing
+users outside of the @code{cvsadmin} group to use the
+@code{cvs admin} command only to change the default keyword
+expansion mode for files.
+
+As an example, to restrict users not in the @code{cvsadmin}
+group to using @code{cvs admin} to change the default keyword
+substitution mode, lock revisions, unlock revisions, and
+replace the log message, use @samp{UserAdminOptions=klum}.
+@end table
+
+
+
+@c ---------------------------------------------------------------------
+@node Environment variables
+@appendix All environment variables which affect CVS
+@cindex Environment variables
+@cindex Reference manual for variables
+
+This is a complete list of all environment variables
+that affect @sc{cvs} (Windows users, please bear with this list;
+$VAR is equivalent to %VAR% at the Windows command prompt).
+
+@table @code
+@cindex CVSIGNORE, environment variable
+@item $CVSIGNORE
+A whitespace-separated list of file name patterns that
+@sc{cvs} should ignore. @xref{cvsignore}.
+
+@cindex CVSWRAPPERS, environment variable
+@item $CVSWRAPPERS
+A whitespace-separated list of file name patterns that
+@sc{cvs} should treat as wrappers. @xref{Wrappers}.
+
+@cindex CVSREAD, environment variable
+@cindex Read-only files, and CVSREAD
+@item $CVSREAD
+If this is set, @code{checkout} and @code{update} will
+try hard to make the files in your working directory
+read-only. When this is not set, the default behavior
+is to permit modification of your working files.
+
+@cindex CVSREADONLYFS, environment variable
+@item $CVSREADONLYFS
+Turns on read-only repository mode. This allows one to
+check out from a read-only repository, such as within
+an anoncvs server, or from a @sc{cd-rom} repository.
+
+It has the same effect as if the @samp{-R} command-line
+option is used. This can also allow the use of
+read-only NFS repositories.
+
+@item $CVSUMASK
+Controls permissions of files in the repository. See
+@ref{File permissions}.
+
+@item $CVSROOT
+Should contain the full pathname to the root of the @sc{cvs}
+source repository (where the @sc{rcs} files are
+kept). This information must be available to @sc{cvs} for
+most commands to execute; if @code{$CVSROOT} is not set,
+or if you wish to override it for one invocation, you
+can supply it on the command line: @samp{cvs -d cvsroot
+cvs_command@dots{}} Once you have checked out a working
+directory, @sc{cvs} stores the appropriate root (in
+the file @file{CVS/Root}), so normally you only need to
+worry about this when initially checking out a working
+directory.
+
+@item $CVSEDITOR
+@cindex CVSEDITOR, environment variable
+@itemx $EDITOR
+@cindex EDITOR, environment variable
+@itemx $VISUAL
+@cindex VISUAL, environment variable
+Specifies the program to use for recording log messages
+during commit. @code{$CVSEDITOR} overrides
+@code{$EDITOR}, which overrides @code{$VISUAL}.
+See @ref{Committing your changes} for more or
+@ref{Global options} for alternative ways of specifying a
+log editor.
+
+@cindex PATH, environment variable
+@item $PATH
+If @code{$RCSBIN} is not set, and no path is compiled
+into @sc{cvs}, it will use @code{$PATH} to try to find all
+programs it uses.
+
+@cindex HOME, environment variable
+@item $HOME
+@cindex HOMEPATH, environment variable
+@item $HOMEPATH
+@cindex HOMEDRIVE, environment variable
+@item $HOMEDRIVE
+Used to locate the directory where the @file{.cvsrc}
+file, and other such files, are searched. On Unix, @sc{cvs}
+just checks for @code{HOME}. On Windows NT, the system will
+set @code{HOMEDRIVE}, for example to @samp{d:} and @code{HOMEPATH},
+for example to @file{\joe}. On Windows 95, you'll
+probably need to set @code{HOMEDRIVE} and @code{HOMEPATH} yourself.
+@c We are being vague about whether HOME works on
+@c Windows; see long comment in windows-NT/filesubr.c.
+
+@cindex CVS_RSH, environment variable
+@item $CVS_RSH
+Specifies the external program which @sc{cvs} connects with,
+when @code{:ext:} access method is specified.
+@pxref{Connecting via rsh}.
+
+@item $CVS_SERVER
+Used in client-server mode when accessing a remote
+repository using @sc{rsh}. It specifies the name of
+the program to start on the server side (and any
+necessary arguments) when accessing a remote repository
+using the @code{:ext:}, @code{:fork:}, or @code{:server:} access methods.
+The default value for @code{:ext:} and @code{:server:} is @code{cvs};
+the default value for @code{:fork:} is the name used to run the client.
+@pxref{Connecting via rsh}
+
+@item $CVS_PASSFILE
+Used in client-server mode when accessing the @code{cvs
+login server}. Default value is @file{$HOME/.cvspass}.
+@pxref{Password authentication client}
+
+@cindex CVS_CLIENT_PORT
+@item $CVS_CLIENT_PORT
+Used in client-server mode to set the port to use when accessing the server
+via Kerberos, GSSAPI, or @sc{cvs}'s password authentication protocol
+if the port is not specified in the CVSROOT.
+@pxref{Remote repositories}
+
+@cindex CVS_PROXY_PORT
+@item $CVS_PROXY_PORT
+Used in client-server mode to set the port to use when accessing a server
+via a web proxy, if the port is not specified in the CVSROOT. Works with
+GSSAPI, and the password authentication protocol.
+@pxref{Remote repositories}
+
+@cindex CVS_RCMD_PORT, environment variable
+@item $CVS_RCMD_PORT
+Used in client-server mode. If set, specifies the port
+number to be used when accessing the @sc{rcmd} demon on
+the server side. (Currently not used for Unix clients).
+
+@cindex CVS_CLIENT_LOG, environment variable
+@item $CVS_CLIENT_LOG
+Used for debugging only in client-server
+mode. If set, everything sent to the server is logged
+into @file{@code{$CVS_CLIENT_LOG}.in} and everything
+sent from the server is logged into
+@file{@code{$CVS_CLIENT_LOG}.out}.
+
+@cindex CVS_SERVER_SLEEP, environment variable
+@item $CVS_SERVER_SLEEP
+Used only for debugging the server side in
+client-server mode. If set, delays the start of the
+server child process the specified amount of
+seconds so that you can attach to it with a debugger.
+
+@cindex CVS_IGNORE_REMOTE_ROOT, environment variable
+@item $CVS_IGNORE_REMOTE_ROOT
+For @sc{cvs} 1.10 and older, setting this variable
+prevents @sc{cvs} from overwriting the @file{CVS/Root}
+file when the @samp{-d} global option is specified.
+Later versions of @sc{cvs} do not rewrite
+@file{CVS/Root}, so @code{CVS_IGNORE_REMOTE_ROOT} has no
+effect.
+
+@cindex CVS_LOCAL_BRANCH_NUM, environment variable
+@item $CVS_LOCAL_BRANCH_NUM
+Setting this variable allows some control over the
+branch number that is assigned. This is specifically to
+support the local commit feature of CVSup. If one sets
+@code{CVS_LOCAL_BRANCH_NUM} to (say) 1000 then branches
+the local repository, the revision numbers will look
+like 1.66.1000.xx. There is almost a dead-set certainty
+that there will be no conflicts with version numbers.
+
+@cindex COMSPEC, environment variable
+@item $COMSPEC
+Used under OS/2 only. It specifies the name of the
+command interpreter and defaults to @sc{cmd.exe}.
+
+@cindex TMPDIR, environment variable
+@cindex temporary file directory, set via environment variable
+@cindex temporary files, location of
+@item $TMPDIR
+Directory in which temporary files are located.
+@xref{Global options}, for more on setting the temporary directory.
+
+@cindex CVS_PID, environment variable
+@item $CVS_PID
+This is the process identification (aka pid) number of
+the @sc{cvs} process. It is often useful in the
+programs and/or scripts specified by the
+@file{commitinfo}, @file{verifymsg}, @file{loginfo}
+files.
+@end table
+
+@node Compatibility
+@appendix Compatibility between CVS Versions
+
+@cindex CVS, versions of
+@cindex Versions, of CVS
+@cindex Compatibility, between CVS versions
+@c We don't mention versions older than CVS 1.3
+@c on the theory that it would clutter it up for the vast
+@c majority of people, who don't have anything that old.
+@c
+The repository format is compatible going back to
+@sc{cvs} 1.3. But see @ref{Watches Compatibility}, if
+you have copies of @sc{cvs} 1.6 or older and you want
+to use the optional developer communication features.
+@c If you "cvs rm" and commit using 1.3, then you'll
+@c want to run "rcs -sdead <file,v>" on each of the
+@c files in the Attic if you then want 1.5 and
+@c later to recognize those files as dead (I think the
+@c symptom if this is not done is that files reappear
+@c in joins). (Wait: the above will work but really to
+@c be strictly correct we should suggest checking
+@c in a new revision rather than just changing the
+@c state of the head revision, shouldn't we?).
+@c The old convert.sh script was for this, but it never
+@c did get updated to reflect use of the RCS "dead"
+@c state.
+@c Note: this is tricky to document without confusing
+@c people--need to carefully say what CVS version we
+@c are talking about and keep in mind the distinction
+@c between a
+@c repository created with 1.3 and on which one now
+@c uses 1.5+, and a repository on which one wants to
+@c use both versions side by side (e.g. during a
+@c transition period).
+@c Wait, can't CVS just detect the case in which a file
+@c is in the Attic but the head revision is not dead?
+@c Not sure whether this should produce a warning or
+@c something, and probably needs further thought, but
+@c it would appear that the situation can be detected.
+@c
+@c We might want to separate out the 1.3 compatibility
+@c section (for repository & working directory) from the
+@c rest--that might help avoid confusing people who
+@c are upgrading (for example) from 1.6 to 1.8.
+@c
+@c A minor incompatibility is if a current version of CVS
+@c puts "Nfoo" into CVS/Tag, then CVS 1.9 or older will
+@c see this as if there is no tag. Seems to me this is
+@c too obscure to mention.
+
+The working directory format is compatible going back
+to @sc{cvs} 1.5. It did change between @sc{cvs} 1.3
+and @sc{cvs} 1.5. If you run @sc{cvs} 1.5 or newer on
+a working directory checked out with @sc{cvs} 1.3,
+@sc{cvs} will convert it, but to go back to @sc{cvs}
+1.3 you need to check out a new working directory with
+@sc{cvs} 1.3.
+
+The remote protocol is interoperable going back to @sc{cvs} 1.5, but no
+further (1.5 was the first official release with the remote protocol,
+but some older versions might still be floating around). In many
+cases you need to upgrade both the client and the server to take
+advantage of new features and bug fixes, however.
+
+@c Perhaps should be saying something here about the
+@c "D" lines in Entries (written by CVS 1.9; 1.8 and
+@c older don't use them). These are supposed to be
+@c compatible in both directions, but I'm not sure
+@c they quite are 100%. One common gripe is if you
+@c "rm -r" a directory and 1.9 gets confused, as it
+@c still sees it in Entries. That one is fixed in
+@c (say) 1.9.6. Someone else reported problems with
+@c starting with a directory which was checked out with
+@c an old version, and then using a new version, and
+@c some "D" lines appeared, but not for every
+@c directory, causing some directories to be skipped.
+@c They weren't sure how to reproduce this, though.
+
+@c ---------------------------------------------------------------------
+@node Troubleshooting
+@appendix Troubleshooting
+
+If you are having trouble with @sc{cvs}, this appendix
+may help. If there is a particular error message which
+you are seeing, then you can look up the message
+alphabetically. If not, you can look through the
+section on other problems to see if your problem is
+mentioned there.
+
+@menu
+* Error messages:: Partial list of CVS errors
+* Connection:: Trouble making a connection to a CVS server
+* Other problems:: Problems not readily listed by error message
+@end menu
+
+@ignore
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c @node Bad administrative files
+@appendixsec Bad administrative files
+
+@c -- Give hints on how to fix them
+@end ignore
+
+@node Error messages
+@appendixsec Partial list of error messages
+
+Here is a partial list of error messages that you may
+see from @sc{cvs}. It is not a complete list---@sc{cvs}
+is capable of printing many, many error messages, often
+with parts of them supplied by the operating system,
+but the intention is to list the common and/or
+potentially confusing error messages.
+
+The messages are alphabetical, but introductory text
+such as @samp{cvs update: } is not considered in
+ordering them.
+
+In some cases the list includes messages printed by old
+versions of @sc{cvs} (partly because users may not be
+sure which version of @sc{cvs} they are using at any
+particular moment).
+@c If we want to start retiring messages, perhaps we
+@c should pick a cutoff version (for example, no more
+@c messages which are specific to versions before 1.9)
+@c and then move the old messages to an "old messages"
+@c node rather than deleting them completely.
+
+@table @code
+@c FIXME: What is the correct way to format a multiline
+@c error message here? Maybe @table is the wrong
+@c choice? Texinfo gurus?
+@item @var{file}:@var{line}: Assertion '@var{text}' failed
+The exact format of this message may vary depending on
+your system. It indicates a bug in @sc{cvs}, which can
+be handled as described in @ref{BUGS}.
+
+@item cvs @var{command}: authorization failed: server @var{host} rejected access
+This is a generic response when trying to connect to a
+pserver server which chooses not to provide a
+specific reason for denying authorization. Check that
+the username and password specified are correct and
+that the @code{CVSROOT} specified is allowed by @samp{--allow-root}
+in @file{inetd.conf}. See @ref{Password authenticated}.
+
+@item cvs @var{command}: conflict: removed @var{file} was modified by second party
+This message indicates that you removed a file, and
+someone else modified it. To resolve the conflict,
+first run @samp{cvs add @var{file}}. If desired, look
+at the other party's modification to decide whether you
+still want to remove it. If you don't want to remove
+it, stop here. If you do want to remove it, proceed
+with @samp{cvs remove @var{file}} and commit your
+removal.
+@c Tests conflicts2-142b* in sanity.sh test for this.
+
+@item cannot change permissions on temporary directory
+@example
+Operation not permitted
+@end example
+This message has been happening in a non-reproducible,
+occasional way when we run the client/server testsuite,
+both on Red Hat Linux 3.0.3 and 4.1. We haven't been
+able to figure out what causes it, nor is it known
+whether it is specific to Linux (or even to this
+particular machine!). If the problem does occur on
+other unices, @samp{Operation not permitted} would be
+likely to read @samp{Not owner} or whatever the system
+in question uses for the unix @code{EPERM} error. If
+you have any information to add, please let us know as
+described in @ref{BUGS}. If you experience this error
+while using @sc{cvs}, retrying the operation which
+produced it should work fine.
+@c This has been seen in a variety of tests, including
+@c multibranch-2, multibranch-5, and basic1-24-rm-rm,
+@c so it doesn't seem particularly specific to any one
+@c test.
+
+@item cvs [server aborted]: Cannot check out files into the repository itself
+The obvious cause for this message (especially for
+non-client/server @sc{cvs}) is that the @sc{cvs} root
+is, for example, @file{/usr/local/cvsroot} and you try
+to check out files when you are in a subdirectory, such
+as @file{/usr/local/cvsroot/test}. However, there is a
+more subtle cause, which is that the temporary
+directory on the server is set to a subdirectory of the
+root (which is also not allowed). If this is the
+problem, set the temporary directory to somewhere else,
+for example @file{/var/tmp}; see @code{TMPDIR} in
+@ref{Environment variables}, for how to set the
+temporary directory.
+
+@item cannot commit files as 'root'
+See @samp{'root' is not allowed to commit files}.
+
+@c For one example see basica-1a10 in the testsuite
+@c For another example, "cvs co ." on NT; see comment
+@c at windows-NT/filesubr.c (expand_wild).
+@c For another example, "cvs co foo/bar" where foo exists.
+@item cannot open CVS/Entries for reading: No such file or directory
+This generally indicates a @sc{cvs} internal error, and
+can be handled as with other @sc{cvs} bugs
+(@pxref{BUGS}). Usually there is a workaround---the
+exact nature of which would depend on the situation but
+which hopefully could be figured out.
+
+@c This is more obscure than it might sound; it only
+@c happens if you run "cvs init" from a directory which
+@c contains a CVS/Root file at the start.
+@item cvs [init aborted]: cannot open CVS/Root: No such file or directory
+This message is harmless. Provided it is not
+accompanied by other errors, the operation has
+completed successfully. This message should not occur
+with current versions of @sc{cvs}, but it is documented
+here for the benefit of @sc{cvs} 1.9 and older.
+
+@item cvs server: cannot open /root/.cvsignore: Permission denied
+@itemx cvs [server aborted]: can't chdir(/root): Permission denied
+See @ref{Connection}.
+
+@item cvs [checkout aborted]: cannot rename file @var{file} to CVS/,,@var{file}: Invalid argument
+This message has been reported as intermittently
+happening with @sc{cvs} 1.9 on Solaris 2.5. The cause is
+unknown; if you know more about what causes it, let us
+know as described in @ref{BUGS}.
+
+@item cvs [@var{command} aborted]: cannot start server via rcmd
+This, unfortunately, is a rather nonspecific error
+message which @sc{cvs} 1.9 will print if you are
+running the @sc{cvs} client and it is having trouble
+connecting to the server. Current versions of @sc{cvs}
+should print a much more specific error message. If
+you get this message when you didn't mean to run the
+client at all, you probably forgot to specify
+@code{:local:}, as described in @ref{Repository}.
+
+@item ci: @var{file},v: bad diff output line: Binary files - and /tmp/T2a22651 differ
+@sc{cvs} 1.9 and older will print this message
+when trying to check in a binary file if
+@sc{rcs} is not correctly installed. Re-read the
+instructions that came with your @sc{rcs} distribution
+and the @sc{install} file in the @sc{cvs}
+distribution. Alternately, upgrade to a current
+version of @sc{cvs}, which checks in files itself
+rather than via @sc{rcs}.
+
+@item cvs checkout: could not check out @var{file}
+With @sc{cvs} 1.9, this can mean that the @code{co} program
+(part of @sc{rcs}) returned a failure. It should be
+preceded by another error message, however it has been
+observed without another error message and the cause is
+not well-understood. With the current version of @sc{cvs},
+which does not run @code{co}, if this message occurs
+without another error message, it is definitely a @sc{cvs}
+bug (@pxref{BUGS}).
+@c My current suspicion is that the RCS in the rcs (not
+@c cvs/winnt/rcs57nt.zip) directory on the _Practical_
+@c CD is bad (remains to be confirmed).
+@c There is also a report of something which looks
+@c very similar on SGI, Irix 5.2, so I dunno.
+
+@item cvs [login aborted]: could not find out home directory
+This means that you need to set the environment
+variables that @sc{cvs} uses to locate your home directory.
+See the discussion of @code{HOME}, @code{HOMEDRIVE}, and @code{HOMEPATH} in
+@ref{Environment variables}.
+
+@item cvs update: could not merge revision @var{rev} of @var{file}: No such file or directory
+@sc{cvs} 1.9 and older will print this message if there was
+a problem finding the @code{rcsmerge} program. Make
+sure that it is in your @code{PATH}, or upgrade to a
+current version of @sc{cvs}, which does not require
+an external @code{rcsmerge} program.
+
+@item cvs [update aborted]: could not patch @var{file}: No such file or directory
+This means that there was a problem finding the
+@code{patch} program. Make sure that it is in your
+@code{PATH}. Note that despite appearances the message
+is @emph{not} referring to whether it can find @var{file}.
+If both the client and the server are running a current
+version of @sc{cvs}, then there is no need for an
+external patch program and you should not see this
+message. But if either client or server is running
+@sc{cvs} 1.9, then you need @code{patch}.
+
+@item cvs update: could not patch @var{file}; will refetch
+This means that for whatever reason the client was
+unable to apply a patch that the server sent. The
+message is nothing to be concerned about, because
+inability to apply the patch only slows things down and
+has no effect on what @sc{cvs} does.
+@c xref to update output. Or File status?
+@c Or some place else that
+@c explains this whole "patch"/P/Needs Patch thing?
+
+@item dying gasps from @var{server} unexpected
+There is a known bug in the server for @sc{cvs} 1.9.18
+and older which can cause this. For me, this was
+reproducible if I used the @samp{-t} global option. It
+was fixed by Andy Piper's 14 Nov 1997 change to
+src/filesubr.c, if anyone is curious.
+If you see the message,
+you probably can just retry the operation which failed,
+or if you have discovered information concerning its
+cause, please let us know as described in @ref{BUGS}.
+
+@item end of file from server (consult above messages if any)
+The most common cause for this message is if you are
+using an external @code{rsh} program and it exited with
+an error. In this case the @code{rsh} program should
+have printed a message, which will appear before the
+above message. For more information on setting up a
+@sc{cvs} client and server, see @ref{Remote repositories}.
+
+@item cvs [update aborted]: EOF in key in RCS file @var{file},v
+@itemx cvs [checkout aborted]: EOF while looking for end of string in RCS file @var{file},v
+This means that there is a syntax error in the given
+@sc{rcs} file. Note that this might be true even if @sc{rcs} can
+read the file OK; @sc{cvs} does more error checking of
+errors in the RCS file. That is why you may see this
+message when upgrading from @sc{cvs} 1.9 to @sc{cvs}
+1.10. The likely cause for the original corruption is
+hardware, the operating system, or the like. Of
+course, if you find a case in which @sc{cvs} seems to
+corrupting the file, by all means report it,
+(@pxref{BUGS}).
+There are quite a few variations of this error message,
+depending on exactly where in the @sc{rcs} file @sc{cvs}
+finds the syntax error.
+
+@cindex mkmodules
+@item cvs commit: Executing 'mkmodules'
+This means that your repository is set up for a version
+of @sc{cvs} prior to @sc{cvs} 1.8. When using @sc{cvs}
+1.8 or later, the above message will be preceded by
+
+@example
+cvs commit: Rebuilding administrative file database
+@end example
+
+If you see both messages, the database is being rebuilt
+twice, which is unnecessary but harmless. If you wish
+to avoid the duplication, and you have no versions of
+@sc{cvs} 1.7 or earlier in use, remove @code{-i mkmodules}
+every place it appears in your @code{modules}
+file. For more information on the @code{modules} file,
+see @ref{modules}.
+
+@c This message comes from "co", and I believe is
+@c possible only with older versions of CVS which call
+@c co. The problem with being able to create the bogus
+@c RCS file still exists, though (and I think maybe
+@c there is a different symptom(s) now).
+@c FIXME: Would be nice to have a more exact wording
+@c for this message.
+@item missing author
+Typically this can happen if you created an RCS file
+with your username set to empty. @sc{cvs} will, bogusly,
+create an illegal RCS file with no value for the author
+field. The solution is to make sure your username is
+set to a non-empty value and re-create the RCS file.
+@c "make sure your username is set" is complicated in
+@c and of itself, as there are the environment
+@c variables the system login name, &c, and it depends
+@c on the version of CVS.
+
+@item cvs [checkout aborted]: no such tag @var{tag}
+This message means that @sc{cvs} isn't familiar with
+the tag @var{tag}. Usually the root cause is that you have
+mistyped a tag name. Ocassionally this can also occur because the
+users creating tags do not have permissions to write to the
+@file{CVSROOT/val-tags} file (@pxref{File permissions}, for more).
+
+Prior to @sc{cvs} version 1.12.10, there were a few relatively
+obscure cases where a given tag could be created in an archive
+file in the repository but @sc{cvs} would require the user to
+@c Search sanity.sh for "no such tag" to see some of
+@c the relatively obscure cases.
+try a few other @sc{cvs} commands involving that tag
+until one was found whch caused @sc{cvs} to update
+@cindex CVSROOT/val-tags file, forcing tags into
+@cindex val-tags file, forcing tags into
+the @file{val-tags} file, at which point the originally failing command
+would begin to work. This same method can be used to repair a @file{val-tags}
+file that becomes out of date due to the permissions problem mentioned above.
+This updating is only required once per tag - once a tag is listed in
+@file{val-tags}, it stays there.
+
+Note that using @samp{tag -f} to not require tag matches did not and
+does not override this check (@pxref{Common options}).
+
+@item *PANIC* administration files missing
+This typically means that there is a directory named
+@sc{cvs} but it does not contain the administrative files
+which @sc{cvs} puts in a CVS directory. If the problem is
+that you created a CVS directory via some mechanism
+other than @sc{cvs}, then the answer is simple, use a name
+other than @sc{cvs}. If not, it indicates a @sc{cvs} bug
+(@pxref{BUGS}).
+
+@item rcs error: Unknown option: -x,v/
+This message will be followed by a usage message for
+@sc{rcs}. It means that you have an old version of
+@sc{rcs} (probably supplied with your operating
+system), as well as an old version of @sc{cvs}.
+@sc{cvs} 1.9.18 and earlier only work with @sc{rcs} version 5 and
+later; current versions of @sc{cvs} do not run @sc{rcs} programs.
+@c For more information on installing @sc{cvs}, see
+@c (FIXME: where? it depends on whether you are
+@c getting binaries or sources or what).
+@c The message can also say "ci error" or something
+@c instead of "rcs error", I suspect.
+
+@item cvs [server aborted]: received broken pipe signal
+This message can be caused by a loginfo program that fails to
+read all of the log information from its standard input.
+If you find it happening in any other circumstances,
+please let us know as described in @ref{BUGS}.
+
+@item 'root' is not allowed to commit files
+When committing a permanent change, @sc{cvs} makes a log entry of
+who committed the change. If you are committing the change logged
+in as "root" (not under "su" or other root-priv giving program),
+@sc{cvs} cannot determine who is actually making the change.
+As such, by default, @sc{cvs} disallows changes to be committed by users
+logged in as "root". (You can disable this option by passing the
+@code{--enable-rootcommit} option to @file{configure} and recompiling @sc{cvs}.
+On some systems this means editing the appropriate @file{config.h} file
+before building @sc{cvs}.)
+
+@item cvs [server aborted]: Secondary out of sync with primary!
+
+This usually means that the version of @sc{cvs} running on a secondary
+server is incompatible with the version running on the primary server
+(@pxref{Write proxies}).
+This will not occur if the client supports redirection.
+
+It is not the version number that is significant here, but the list of
+supported requests that the servers provide to the client.
+For example, even if both servers were the same version,
+if the secondary was compiled with GSSAPI support and the primary was not,
+the list of supported requests provided by the two servers
+would be different and the secondary would not work as a transparent
+proxy to the primary.
+Conversely, even if the two servers were radically different versions
+but both provided the same list of valid requests to the client,
+the transparent proxy would succeed.
+
+@item Terminated with fatal signal 11
+This message usually indicates that @sc{cvs} (the server, if you're
+using client/server mode) has run out of (virtual) memory.
+Although @sc{cvs} tries to catch the error and issue a more meaningful
+message, there are many circumstances where that is not possible.
+If you appear to have lots of memory available to the system,
+the problem is most likely that you're running into a system-wide
+limit on the amount of memory a single process can use or a
+similar process-specific limit.
+The mechanisms for displaying and setting such limits vary from
+system to system, so you'll have to consult an expert for your
+particular system if you don't know how to do that.
+
+@item Too many arguments!
+This message is typically printed by the @file{log.pl}
+script which is in the @file{contrib} directory in the
+@sc{cvs} source distribution. In some versions of
+@sc{cvs}, @file{log.pl} has been part of the default
+@sc{cvs} installation. The @file{log.pl} script gets
+called from the @file{loginfo} administrative file.
+Check that the arguments passed in @file{loginfo} match
+what your version of @file{log.pl} expects. In
+particular, the @file{log.pl} from @sc{cvs} 1.3 and
+older expects the log file as an argument whereas the
+@file{log.pl} from @sc{cvs} 1.5 and newer expects the
+log file to be specified with a @samp{-f} option. Of
+course, if you don't need @file{log.pl} you can just
+comment it out of @file{loginfo}.
+
+@item cvs [update aborted]: unexpected EOF reading @var{file},v
+See @samp{EOF in key in RCS file}.
+
+@item cvs [login aborted]: unrecognized auth response from @var{server}
+This message typically means that the server is not set
+up properly. For example, if @file{inetd.conf} points
+to a nonexistent cvs executable. To debug it further,
+find the log file which inetd writes
+(@file{/var/log/messages} or whatever inetd uses on
+your system). For details, see @ref{Connection}, and
+@ref{Password authentication server}.
+
+@item cvs commit: Up-to-date check failed for `@var{file}'
+This means that someone else has committed a change to
+that file since the last time that you did a @code{cvs
+update}. So before proceeding with your @code{cvs
+commit} you need to @code{cvs update}. @sc{cvs} will merge
+the changes that you made and the changes that the
+other person made. If it does not detect any conflicts
+it will report @samp{M @var{file}} and you are ready
+to @code{cvs commit}. If it detects conflicts it will
+print a message saying so, will report @samp{C @var{file}},
+and you need to manually resolve the
+conflict. For more details on this process see
+@ref{Conflicts example}.
+
+@item Usage: diff3 [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3
+@example
+Only one of [exEX3] allowed
+@end example
+This indicates a problem with the installation of
+@code{diff3} and @code{rcsmerge}. Specifically
+@code{rcsmerge} was compiled to look for GNU diff3, but
+it is finding unix diff3 instead. The exact text of
+the message will vary depending on the system. The
+simplest solution is to upgrade to a current version of
+@sc{cvs}, which does not rely on external
+@code{rcsmerge} or @code{diff3} programs.
+
+@item warning: unrecognized response `@var{text}' from cvs server
+If @var{text} contains a valid response (such as
+@samp{ok}) followed by an extra carriage return
+character (on many systems this will cause the second
+part of the message to overwrite the first part), then
+it probably means that you are using the @samp{:ext:}
+access method with a version of rsh, such as most
+non-unix rsh versions, which does not by default
+provide a transparent data stream. In such cases you
+probably want to try @samp{:server:} instead of
+@samp{:ext:}. If @var{text} is something else, this
+may signify a problem with your @sc{cvs} server.
+Double-check your installation against the instructions
+for setting up the @sc{cvs} server.
+@c FIXCVS: should be printing CR as \r or \015 or some
+@c such, probably.
+
+@item cvs commit: [@var{time}] waiting for @var{user}'s lock in @var{directory}
+This is a normal message, not an error. See
+@ref{Concurrency}, for more details.
+
+@item cvs commit: warning: editor session failed
+@cindex Exit status, of editor
+This means that the editor which @sc{cvs} is using exits with a nonzero
+exit status. Some versions of vi will do this even when there was not
+a problem editing the file. If so, point the
+@code{CVSEDITOR} environment variable to a small script
+such as:
+
+@example
+#!/bin/sh
+vi $*
+exit 0
+@end example
+
+@item cvs update: warning: @var{file} was lost
+This means that the working copy of @var{file} has been deleted
+but it has not been removed from @sc{cvs}.
+This is nothing to be concerned about,
+the update will just recreate the local file from the repository.
+(This is a convenient way to discard local changes to a file:
+just delete it and then run @code{cvs update}.)
+
+@item cvs update: warning: @var{file} is not (any longer) pertinent
+This means that the working copy of @var{file} has been deleted,
+it has not been removed from @sc{cvs} in the current working directory,
+but it has been removed from @sc{cvs} in some other working directory.
+This is nothing to be concerned about,
+the update would have removed the local file anyway.
+
+@end table
+
+@node Connection
+@appendixsec Trouble making a connection to a CVS server
+
+This section concerns what to do if you are having
+trouble making a connection to a @sc{cvs} server. If
+you are running the @sc{cvs} command line client
+running on Windows, first upgrade the client to
+@sc{cvs} 1.9.12 or later. The error reporting in
+earlier versions provided much less information about
+what the problem was. If the client is non-Windows,
+@sc{cvs} 1.9 should be fine.
+
+If the error messages are not sufficient to track down
+the problem, the next steps depend largely on which
+access method you are using.
+
+@table @code
+@cindex :ext:, troubleshooting
+@item :ext:
+Try running the rsh program from the command line. For
+example: "rsh servername cvs -v" should print @sc{cvs}
+version information. If this doesn't work, you need to
+fix it before you can worry about @sc{cvs} problems.
+
+@cindex :server:, troubleshooting
+@item :server:
+You don't need a command line rsh program to use this
+access method, but if you have an rsh program around,
+it may be useful as a debugging tool. Follow the
+directions given for :ext:.
+
+@cindex :pserver:, troubleshooting
+@item :pserver:
+Errors along the lines of "connection refused" typically indicate
+that inetd isn't even listening for connections on port 2401
+whereas errors like "connection reset by peer",
+"received broken pipe signal", "recv() from server: EOF",
+or "end of file from server"
+typically indicate that inetd is listening for
+connections but is unable to start @sc{cvs} (this is frequently
+caused by having an incorrect path in @file{inetd.conf}
+or by firewall software rejecting the connection).
+"unrecognized auth response" errors are caused by a bad command
+line in @file{inetd.conf}, typically an invalid option or forgetting
+to put the @samp{pserver} command at the end of the line.
+Another less common problem is invisible control characters that
+your editor "helpfully" added without you noticing.
+
+One good debugging tool is to "telnet servername
+2401". After connecting, send any text (for example
+"foo" followed by return). If @sc{cvs} is working
+correctly, it will respond with
+
+@example
+cvs [pserver aborted]: bad auth protocol start: foo
+@end example
+
+If instead you get:
+
+@example
+Usage: cvs [cvs-options] command [command-options-and-arguments]
+...
+@end example
+
+@noindent
+then you're missing the @samp{pserver} command at the end of the
+line in @file{inetd.conf}; check to make sure that the entire command
+is on one line and that it's complete.
+
+Likewise, if you get something like:
+
+@example
+Unknown command: `pserved'
+
+CVS commands are:
+ add Add a new file/directory to the repository
+...
+@end example
+
+@noindent
+then you've misspelled @samp{pserver} in some way. If it isn't
+obvious, check for invisible control characters (particularly
+carriage returns) in @file{inetd.conf}.
+
+If it fails to work at all, then make sure inetd is working
+right. Change the invocation in @file{inetd.conf} to run the
+echo program instead of cvs. For example:
+
+@example
+2401 stream tcp nowait root /bin/echo echo hello
+@end example
+
+After making that change and instructing inetd to
+re-read its configuration file, "telnet servername
+2401" should show you the text hello and then the
+server should close the connection. If this doesn't
+work, you need to fix it before you can worry about
+@sc{cvs} problems.
+
+On AIX systems, the system will often have its own
+program trying to use port 2401. This is AIX's problem
+in the sense that port 2401 is registered for use with
+@sc{cvs}. I hear that there is an AIX patch available
+to address this problem.
+
+Another good debugging tool is the @samp{-d}
+(debugging) option to inetd. Consult your system
+documentation for more information.
+
+If you seem to be connecting but get errors like:
+
+@example
+cvs server: cannot open /root/.cvsignore: Permission denied
+cvs [server aborted]: can't chdir(/root): Permission denied
+@end example
+
+@noindent
+then you probably haven't specified @samp{-f} in @file{inetd.conf}.
+(In releases prior to @sc{cvs} 1.11.1, this problem can be caused by
+your system setting the @code{$HOME} environment variable
+for programs being run by inetd. In this case, you can either
+have inetd run a shell script that unsets @code{$HOME} and then runs
+@sc{cvs}, or you can use @code{env} to run @sc{cvs} with a pristine
+environment.)
+
+If you can connect successfully for a while but then can't,
+you've probably hit inetd's rate limit.
+(If inetd receives too many requests for the same service
+in a short period of time, it assumes that something is wrong
+and temporarily disables the service.)
+Check your inetd documentation to find out how to adjust the
+rate limit (some versions of inetd have a single rate limit,
+others allow you to set the limit for each service separately.)
+@end table
+
+@node Other problems
+@appendixsec Other common problems
+
+Here is a list of problems which do not fit into the
+above categories. They are in no particular order.
+
+@itemize @bullet
+@item
+On Windows, if there is a 30 second or so delay when
+you run a @sc{cvs} command, it may mean that you have
+your home directory set to @file{C:/}, for example (see
+@code{HOMEDRIVE} and @code{HOMEPATH} in
+@ref{Environment variables}). @sc{cvs} expects the home
+directory to not end in a slash, for example @file{C:}
+or @file{C:\cvs}.
+@c FIXCVS: CVS should at least detect this and print an
+@c error, presumably.
+
+@item
+If you are running @sc{cvs} 1.9.18 or older, and
+@code{cvs update} finds a conflict and tries to
+merge, as described in @ref{Conflicts example}, but
+doesn't tell you there were conflicts, then you may
+have an old version of @sc{rcs}. The easiest solution
+probably is to upgrade to a current version of
+@sc{cvs}, which does not rely on external @sc{rcs}
+programs.
+@end itemize
+
+@c ---------------------------------------------------------------------
+@node Credits
+@appendix Credits
+
+@cindex Contributors (manual)
+@cindex Credits (manual)
+Roland Pesch, then of Cygnus Support <@t{roland@@wrs.com}>
+wrote the manual pages which were distributed with
+@sc{cvs} 1.3. Much of their text was copied into this
+manual. He also read an early draft
+of this manual and contributed many ideas and
+corrections.
+
+The mailing-list @code{info-cvs} is sometimes
+informative. I have included information from postings
+made by the following persons:
+David G. Grubbs <@t{dgg@@think.com}>.
+
+Some text has been extracted from the man pages for
+@sc{rcs}.
+
+The @sc{cvs} @sc{faq} by David G. Grubbs has provided
+useful material. The @sc{faq} is no longer maintained,
+however, and this manual is about the closest thing there
+is to a successor (with respect to documenting how to
+use @sc{cvs}, at least).
+
+In addition, the following persons have helped by
+telling me about mistakes I've made:
+
+@display
+Roxanne Brunskill <@t{rbrunski@@datap.ca}>,
+Kathy Dyer <@t{dyer@@phoenix.ocf.llnl.gov}>,
+Karl Pingle <@t{pingle@@acuson.com}>,
+Thomas A Peterson <@t{tap@@src.honeywell.com}>,
+Inge Wallin <@t{ingwa@@signum.se}>,
+Dirk Koschuetzki <@t{koschuet@@fmi.uni-passau.de}>
+and Michael Brown <@t{brown@@wi.extrel.com}>.
+@end display
+
+The list of contributors here is not comprehensive; for a more
+complete list of who has contributed to this manual see
+the file @file{doc/ChangeLog} in the @sc{cvs} source
+distribution.
+
+@c ---------------------------------------------------------------------
+@node BUGS
+@appendix Dealing with bugs in CVS or this manual
+
+@cindex Bugs in this manual or CVS
+Neither @sc{cvs} nor this manual is perfect, and they
+probably never will be. If you are having trouble
+using @sc{cvs}, or think you have found a bug, there
+are a number of things you can do about it. Note that
+if the manual is unclear, that can be considered a bug
+in the manual, so these problems are often worth doing
+something about as well as problems with @sc{cvs} itself.
+
+@cindex Reporting bugs
+@cindex Bugs, reporting
+@cindex Errors, reporting
+@itemize @bullet
+@item
+If you want someone to help you and fix bugs that you
+report, there are companies which will do that for a
+fee. One such company is:
+
+@cindex Ximbiot
+@cindex Support, getting CVS support
+@example
+Ximbiot
+319 S. River St.
+Harrisburg, PA 17104-1657
+USA
+Email: info@@ximbiot.com
+Phone: (717) 579-6168
+Fax: (717) 234-3125
+@url{http://ximbiot.com/}
+
+@end example
+
+@item
+If you got @sc{cvs} through a distributor, such as an
+operating system vendor or a vendor of freeware
+@sc{cd-rom}s, you may wish to see whether the
+distributor provides support. Often, they will provide
+no support or minimal support, but this may vary from
+distributor to distributor.
+
+@item
+If you have the skills and time to do so, you may wish
+to fix the bug yourself. If you wish to submit your
+fix for inclusion in future releases of @sc{cvs}, see
+the file @sc{hacking} in the @sc{cvs} source
+distribution. It contains much more information on the
+process of submitting fixes.
+
+@item
+There may be resources on the net which can help. A
+good place to start is:
+
+@example
+@url{http://cvs.nongnu.org/}
+@end example
+
+If you are so inspired, increasing the information
+available on the net is likely to be appreciated. For
+example, before the standard @sc{cvs} distribution
+worked on Windows 95, there was a web page with some
+explanation and patches for running @sc{cvs} on Windows
+95, and various people helped out by mentioning this
+page on mailing lists or newsgroups when the subject
+came up.
+
+@item
+It is also possible to report bugs to @email{bug-cvs@@nongnu.org}.
+Note that someone may or may not want to do anything
+with your bug report---if you need a solution consider
+one of the options mentioned above. People probably do
+want to hear about bugs which are particularly severe
+in consequences and/or easy to fix, however. You can
+also increase your odds by being as clear as possible
+about the exact nature of the bug and any other
+relevant information. The way to report bugs is to
+send email to @email{bug-cvs@@nongnu.org}. Note
+that submissions to @email{bug-cvs@@nongnu.org} may be distributed
+under the terms of the @sc{gnu} Public License, so if
+you don't like this, don't submit them. There is
+usually no justification for sending mail directly to
+one of the @sc{cvs} maintainers rather than to
+@email{bug-cvs@@nongnu.org}; those maintainers who want to hear
+about such bug reports read @email{bug-cvs@@nongnu.org}. Also note
+that sending a bug report to other mailing lists or
+newsgroups is @emph{not} a substitute for sending it to
+@email{bug-cvs@@nongnu.org}. It is fine to discuss @sc{cvs} bugs on
+whatever forum you prefer, but there are not
+necessarily any maintainers reading bug reports sent
+anywhere except @email{bug-cvs@@nongnu.org}.
+@end itemize
+
+@cindex Known bugs in this manual or CVS
+People often ask if there is a list of known bugs or
+whether a particular bug is a known one. The file
+@sc{bugs} in the @sc{cvs} source distribution is one
+list of known bugs, but it doesn't necessarily try to
+be comprehensive. Perhaps there will never be a
+comprehensive, detailed list of known bugs.
+
+@c ---------------------------------------------------------------------
+@node Index
+@unnumbered Index
+@cindex Index
+
+@printindex cp
+
+@bye
+
+Local Variables:
+fill-column: 55
+End:
diff --git a/doc/cvsclient.info b/doc/cvsclient.info
new file mode 100644
index 0000000..93ed7a3
--- /dev/null
+++ b/doc/cvsclient.info
@@ -0,0 +1,2118 @@
+This is cvsclient.info, produced by makeinfo version 4.8 from
+cvsclient.texi.
+
+INFO-DIR-SECTION Programming
+START-INFO-DIR-ENTRY
+* cvsclient: (cvsclient). The CVS client/server protocol.
+END-INFO-DIR-ENTRY
+
+
+File: cvsclient.info, Node: Top, Next: Introduction, Up: (dir)
+
+CVS Client/Server
+*****************
+
+This document describes the client/server protocol used by CVS. It does
+not describe how to use or administer client/server CVS; see the regular
+CVS manual for that. This is version 1.12.13 of the protocol
+specification--*Note Introduction::, for more on what this version
+number means.
+
+* Menu:
+
+* Introduction:: What is CVS and what is the client/server protocol for?
+* Goals:: Basic design decisions, requirements, scope, etc.
+* Connection and Authentication:: Various ways to connect to the server
+* Password scrambling:: Scrambling used by pserver
+* Protocol:: Complete description of the protocol
+* Protocol Notes:: Possible enhancements, limitations, etc. of the protocol
+
+
+File: cvsclient.info, Node: Introduction, Next: Goals, Prev: Top, Up: Top
+
+1 Introduction
+**************
+
+CVS is a version control system (with some additional configuration
+management functionality). It maintains a central "repository" which
+stores files (often source code), including past versions, information
+about who modified them and when, and so on. People who wish to look
+at or modify those files, known as "developers", use CVS to "check out"
+a "working directory" from the repository, to "check in" new versions
+of files to the repository, and other operations such as viewing the
+modification history of a file. If developers are connected to the
+repository by a network, particularly a slow or flaky one, the most
+efficient way to use the network is with the CVS-specific protocol
+described in this document.
+
+ Developers, using the machine on which they store their working
+directory, run the CVS "client" program. To perform operations which
+cannot be done locally, it connects to the CVS "server" program, which
+maintains the repository. For more information on how to connect see
+*Note Connection and Authentication::.
+
+ This document describes the CVS protocol. Unfortunately, it does not
+yet completely document one aspect of the protocol--the detailed
+operation of each CVS command and option--and one must look at the CVS
+user documentation, `cvs.texinfo', for that information. The protocol
+is non-proprietary (anyone who wants to is encouraged to implement it)
+and an implementation, known as CVS, is available under the GNU Public
+License. The CVS distribution, containing this implementation,
+`cvs.texinfo', and a copy (possibly more or less up to date than what
+you are reading now) of this document, `cvsclient.texi', can be found
+at the usual GNU FTP sites, with a filename such as
+`cvs-VERSION.tar.gz'.
+
+ This is version 1.12.13 of the protocol specification. This version
+number is intended only to aid in distinguishing different versions of
+this specification. Although the specification is currently maintained
+in conjunction with the CVS implementation, and carries the same
+version number, it also intends to document what is involved with
+interoperating with other implementations (such as other versions of
+CVS); see *Note Requirements::. This version number should not be used
+by clients or servers to determine what variant of the protocol to
+speak; they should instead use the `valid-requests' and
+`Valid-responses' mechanism (*note Protocol::), which is more flexible.
+
+
+File: cvsclient.info, Node: Goals, Next: Connection and Authentication, Prev: Introduction, Up: Top
+
+2 Goals
+*******
+
+ * Do not assume any access to the repository other than via this
+ protocol. It does not depend on NFS, rdist, etc.
+
+ * Providing a reliable transport is outside this protocol. The
+ protocol expects a reliable transport that is transparent (that
+ is, there is no translation of characters, including characters
+ such as linefeeds or carriage returns), and can transmit all 256
+ octets (for example for proper handling of binary files,
+ compression, and encryption). The encoding of characters
+ specified by the protocol (the names of requests and so on) is the
+ invariant ISO 646 character set (a subset of most popular
+ character sets including ASCII and others). For more details on
+ running the protocol over the TCP reliable transport, see *Note
+ Connection and Authentication::.
+
+ * Security and authentication are handled outside this protocol (but
+ see below about `cvs kserver' and `cvs pserver').
+
+ * The protocol makes it possible for updates to be atomic with
+ respect to checkins; that is if someone commits changes to several
+ files in one cvs command, then an update by someone else would
+ either get all the changes, or none of them. The current CVS
+ server can't do this, but that isn't the protocol's fault.
+
+ * The protocol is, with a few exceptions, transaction-based. That
+ is, the client sends all its requests (without waiting for server
+ responses), and then waits for the server to send back all
+ responses (without waiting for further client requests). This has
+ the advantage of minimizing network turnarounds and the
+ disadvantage of sometimes transferring more data than would be
+ necessary if there were a richer interaction. Another, more
+ subtle, advantage is that there is no need for the protocol to
+ provide locking for features such as making checkins atomic with
+ respect to updates. Any such locking can be handled entirely by
+ the server. A good server implementation (such as the current CVS
+ server) will make sure that it does not have any such locks in
+ place whenever it is waiting for communication with the client;
+ this prevents one client on a slow or flaky network from
+ interfering with the work of others.
+
+ * It is a general design goal to provide only one way to do a given
+ operation (where possible). For example, implementations have no
+ choice about whether to terminate lines with linefeeds or some
+ other character(s), and request and response names are
+ case-sensitive. This is to enhance interoperability. If a
+ protocol allows more than one way to do something, it is all too
+ easy for some implementations to support only some of them
+ (perhaps accidentally).
+
+
+File: cvsclient.info, Node: Connection and Authentication, Next: Password scrambling, Prev: Goals, Up: Top
+
+3 How to Connect to and Authenticate Oneself to the CVS server
+**************************************************************
+
+Connection and authentication occurs before the CVS protocol itself is
+started. There are several ways to connect.
+
+server
+ If the client has a way to execute commands on the server, and
+ provide input to the commands and output from them, then it can
+ connect that way. This could be the usual rsh (port 514)
+ protocol, Kerberos rsh, SSH, or any similar mechanism. The client
+ may allow the user to specify the name of the server program; the
+ default is `cvs'. It is invoked with one argument, `server'.
+ Once it invokes the server, the client proceeds to start the cvs
+ protocol.
+
+kserver
+ The kerberized server listens on a port (in the current
+ implementation, by having inetd call "cvs kserver") which defaults
+ to 1999. The client connects, sends the usual kerberos
+ authentication information, and then starts the cvs protocol.
+ Note: port 1999 is officially registered for another use, and in
+ any event one cannot register more than one port for CVS, so
+ GSS-API (see below) is recommended instead of kserver as a way to
+ support kerberos.
+
+pserver
+ The name "pserver" is somewhat confusing. It refers to both a
+ generic framework which allows the CVS protocol to support several
+ authentication mechanisms, and a name for a specific mechanism
+ which transfers a username and a cleartext password. Servers need
+ not support all mechanisms, and in fact servers will typically
+ want to support only those mechanisms which meet the relevant
+ security needs.
+
+ The pserver server listens on a port (in the current
+ implementation, by having inetd call "cvs pserver") which defaults
+ to 2401 (this port is officially registered). The client
+ connects, and sends the following:
+
+ * the string `BEGIN AUTH REQUEST', a linefeed,
+
+ * the cvs root, a linefeed,
+
+ * the username, a linefeed,
+
+ * the password trivially encoded (see *Note Password
+ scrambling::), a linefeed,
+
+ * the string `END AUTH REQUEST', and a linefeed.
+
+ The client must send the identical string for cvs root both here
+ and later in the `Root' request of the cvs protocol itself.
+ Servers are encouraged to enforce this restriction. The possible
+ server responses (each of which is followed by a linefeed) are the
+ following. Note that although there is a small similarity between
+ this authentication protocol and the cvs protocol, they are
+ separate.
+
+ `I LOVE YOU'
+ The authentication is successful. The client proceeds with
+ the cvs protocol itself.
+
+ `I HATE YOU'
+ The authentication fails. After sending this response, the
+ server may close the connection. It is up to the server to
+ decide whether to give this response, which is generic, or a
+ more specific response using `E' and/or `error'.
+
+ `E TEXT'
+ Provide a message for the user. After this reponse, the
+ authentication protocol continues with another response.
+ Typically the server will provide a series of `E' responses
+ followed by `error'. Compatibility note: CVS 1.9.10 and
+ older clients will print `unrecognized auth response' and
+ TEXT, and then exit, upon receiving this response.
+
+ `error CODE TEXT'
+ The authentication fails. After sending this response, the
+ server may close the connection. The CODE is a code
+ describing why it failed, intended for computer consumption.
+ The only code currently defined is `0' which is nonspecific,
+ but clients must silently treat any unrecognized codes as
+ nonspecific. The TEXT should be supplied to the user.
+ Compatibility note: CVS 1.9.10 and older clients will print
+ `unrecognized auth response' and TEXT, and then exit, upon
+ receiving this response. Note that TEXT for this response,
+ or the TEXT in an `E' response, is not designed for machine
+ parsing. More vigorous use of CODE, or future extensions,
+ will be needed to prove a cleaner machine-parseable
+ indication of what the error was.
+
+ If the client wishes to merely authenticate without starting the
+ cvs protocol, the procedure is the same, except BEGIN AUTH REQUEST
+ is replaced with BEGIN VERIFICATION REQUEST, END AUTH REQUEST is
+ replaced with END VERIFICATION REQUEST, and upon receipt of I LOVE
+ YOU the connection is closed rather than continuing.
+
+ Another mechanism is GSSAPI authentication. GSSAPI is a generic
+ interface to security services such as kerberos. GSSAPI is
+ specified in RFC2078 (GSSAPI version 2) and RFC1508 (GSSAPI
+ version 1); we are not aware of differences between the two which
+ affect the protocol in incompatible ways, so we make no attempt to
+ specify one version or the other. The procedure here is to start
+ with `BEGIN GSSAPI REQUEST'. GSSAPI authentication information is
+ then exchanged between the client and the server. Each packet of
+ information consists of a two byte big endian length, followed by
+ that many bytes of data. After the GSSAPI authentication is
+ complete, the server continues with the responses described above
+ (`I LOVE YOU', etc.).
+
+future possibilities
+ There are a nearly unlimited number of ways to connect and
+ authenticate. One might want to allow access based on IP address
+ (similar to the usual rsh protocol but with different/no
+ restrictions on ports < 1024), to adopt mechanisms such as
+ Pluggable Authentication Modules (PAM), to allow users to run
+ their own servers under their own usernames without root access,
+ or any number of other possibilities. The way to add future
+ mechanisms, for the most part, should be to continue to use port
+ 2401, but to use different strings in place of `BEGIN AUTH
+ REQUEST'.
+
+
+File: cvsclient.info, Node: Password scrambling, Next: Protocol, Prev: Connection and Authentication, Up: Top
+
+4 Password scrambling algorithm
+*******************************
+
+The pserver authentication protocol, as described in *Note Connection
+and Authentication::, trivially encodes the passwords. This is only to
+prevent inadvertent compromise; it provides no protection against even a
+relatively unsophisticated attacker. For comparison, HTTP Basic
+Authentication (as described in RFC2068) uses BASE64 for a similar
+purpose. CVS uses its own algorithm, described here.
+
+ The scrambled password starts with `A', which serves to identify the
+scrambling algorithm in use. After that follows a single octet for
+each character in the password, according to a fixed encoding. The
+values are shown here, with the encoded values in decimal. Control
+characters, space, and characters outside the invariant ISO 646
+character set are not shown; such characters are not recommended for use
+in passwords. There is a long discussion of character set issues in
+*Note Protocol Notes::.
+
+ 0 111 P 125 p 58
+ ! 120 1 52 A 57 Q 55 a 121 q 113
+ " 53 2 75 B 83 R 54 b 117 r 32
+ 3 119 C 43 S 66 c 104 s 90
+ 4 49 D 46 T 124 d 101 t 44
+ % 109 5 34 E 102 U 126 e 100 u 98
+ & 72 6 82 F 40 V 59 f 69 v 60
+ ' 108 7 81 G 89 W 47 g 73 w 51
+ ( 70 8 95 H 38 X 92 h 99 x 33
+ ) 64 9 65 I 103 Y 71 i 63 y 97
+ * 76 : 112 J 45 Z 115 j 94 z 62
+ + 67 ; 86 K 50 k 93
+ , 116 < 118 L 42 l 39
+ - 74 = 110 M 123 m 37
+ . 68 > 122 N 91 n 61
+ / 87 ? 105 O 35 _ 56 o 48
+
+
+File: cvsclient.info, Node: Protocol, Next: Protocol Notes, Prev: Password scrambling, Up: Top
+
+5 The CVS client/server protocol
+********************************
+
+In the following, `\n' refers to a linefeed and `\t' refers to a
+horizontal tab; "requests" are what the client sends and "responses"
+are what the server sends. In general, the connection is governed by
+the client--the server does not send responses without first receiving
+requests to do so; see *Note Response intro:: for more details of this
+convention.
+
+ It is typical, early in the connection, for the client to transmit a
+`Valid-responses' request, containing all the responses it supports,
+followed by a `valid-requests' request, which elicits from the server a
+`Valid-requests' response containing all the requests it understands.
+In this way, the client and server each find out what the other
+supports before exchanging large amounts of data (such as file
+contents).
+
+* Menu:
+
+
+General protocol conventions:
+
+* Entries Lines:: Transmitting RCS data
+* File Modes:: Read, write, execute, and possibly more...
+* Filenames:: Conventions regarding filenames
+* File transmissions:: How file contents are transmitted
+* Strings:: Strings in various requests and responses
+* Dates:: Times and dates
+
+The protocol itself:
+
+* Request intro:: General conventions relating to requests
+* Requests:: List of requests
+* Response intro:: General conventions relating to responses
+* Response pathnames:: The "pathname" in responses
+* Responses:: List of responses
+* Text tags:: More details about the MT response
+
+An example session, and some further observations:
+
+* Example:: A conversation between client and server
+* Requirements:: Things not to omit from an implementation
+* Obsolete:: Former protocol features
+
+
+File: cvsclient.info, Node: Entries Lines, Next: File Modes, Up: Protocol
+
+5.1 Entries Lines
+=================
+
+Entries lines are transmitted as:
+
+ / NAME / VERSION / CONFLICT / OPTIONS / TAG_OR_DATE
+
+ TAG_OR_DATE is either `T' TAG or `D' DATE or empty. If it is
+followed by a slash, anything after the slash shall be silently ignored.
+
+ VERSION can be empty, or start with `0' or `-', for no user file,
+new user file, or user file to be removed, respectively.
+
+ CONFLICT, if it starts with `+', indicates that the file had
+conflicts in it. The rest of CONFLICT is `=' if the timestamp matches
+the file, or anything else if it doesn't. If CONFLICT does not start
+with a `+', it is silently ignored.
+
+ OPTIONS signifies the keyword expansion options (for example `-ko').
+In an `Entry' request, this indicates the options that were specified
+with the file from the previous file updating response (*note Response
+intro::, for a list of file updating responses); if the client is
+specifying the `-k' or `-A' option to `update', then it is the server
+which figures out what overrides what.
+
+
+File: cvsclient.info, Node: File Modes, Next: Filenames, Prev: Entries Lines, Up: Protocol
+
+5.2 File Modes
+==============
+
+A mode is any number of repetitions of
+
+ MODE-TYPE = DATA
+
+ separated by `,'.
+
+ MODE-TYPE is an identifier composed of alphanumeric characters.
+Currently specified: `u' for user, `g' for group, `o' for other (see
+below for discussion of whether these have their POSIX meaning or are
+more loose). Unrecognized values of MODE-TYPE are silently ignored.
+
+ DATA consists of any data not containing `,', `\0' or `\n'. For
+`u', `g', and `o' mode types, data consists of alphanumeric characters,
+where `r' means read, `w' means write, `x' means execute, and
+unrecognized letters are silently ignored.
+
+ The two most obvious ways in which the mode matters are: (1) is it
+writeable? This is used by the developer communication features, and
+is implemented even on OS/2 (and could be implemented on DOS), whose
+notion of mode is limited to a readonly bit. (2) is it executable?
+Unix CVS users need CVS to store this setting (for shell scripts and
+the like). The current CVS implementation on unix does a little bit
+more than just maintain these two settings, but it doesn't really have
+a nice general facility to store or version control the mode, even on
+unix, much less across operating systems with diverse protection
+features. So all the ins and outs of what the mode means across
+operating systems haven't really been worked out (e.g. should the VMS
+port use ACLs to get POSIX semantics for groups?).
+
+
+File: cvsclient.info, Node: Filenames, Next: File transmissions, Prev: File Modes, Up: Protocol
+
+5.3 Conventions regarding transmission of file names
+====================================================
+
+In most contexts, `/' is used to separate directory and file names in
+filenames, and any use of other conventions (for example, that the user
+might type on the command line) is converted to that form. The only
+exceptions might be a few cases in which the server provides a magic
+cookie which the client then repeats verbatim, but as the server has
+not yet been ported beyond unix, the two rules provide the same answer
+(and what to do if future server ports are operating on a repository
+like e:/foo or CVS_ROOT:[FOO.BAR] has not been carefully thought out).
+
+ Characters outside the invariant ISO 646 character set should be
+avoided in filenames. This restriction may need to be relaxed to allow
+for characters such as `[' and `]' (see above about non-unix servers);
+this has not been carefully considered (and currently implementations
+probably use whatever character sets that the operating systems they
+are running on allow, and/or that users specify). Of course the most
+portable practice is to restrict oneself further, to the POSIX portable
+filename character set as specified in POSIX.1.
+
+
+File: cvsclient.info, Node: File transmissions, Next: Strings, Prev: Filenames, Up: Protocol
+
+5.4 File transmissions
+======================
+
+File contents (noted below as FILE TRANSMISSION) can be sent in one of
+two forms. The simpler form is a number of bytes, followed by a
+linefeed, followed by the specified number of bytes of file contents.
+These are the entire contents of the specified file. Second, if both
+client and server support `gzip-file-contents', a `z' may precede the
+length, and the `file contents' sent are actually compressed with
+`gzip' (RFC1952/1951) compression. The length specified is that of the
+compressed version of the file.
+
+ In neither case are the file content followed by any additional data.
+The transmission of a file will end with a linefeed iff that file (or
+its compressed form) ends with a linefeed.
+
+ The encoding of file contents depends on the value for the `-k'
+option. If the file is binary (as specified by the `-kb' option in the
+appropriate place), then it is just a certain number of octets, and the
+protocol contributes nothing towards determining the encoding (using
+the file name is one widespread, if not universally popular, mechanism).
+If the file is text (not binary), then the file is sent as a series of
+lines, separated by linefeeds. If the keyword expansion is set to
+something other than `-ko', then it is expected that the file conform
+to the RCS expectations regarding keyword expansion--in particular,
+that it is in a character set such as ASCII in which 0x24 is a dollar
+sign (`$').
+
+
+File: cvsclient.info, Node: Strings, Next: Dates, Prev: File transmissions, Up: Protocol
+
+5.5 Strings
+===========
+
+In various contexts, for example the `Argument' request and the `M'
+response, one transmits what is essentially an arbitrary string. Often
+this will have been supplied by the user (for example, the `-m' option
+to the `ci' request). The protocol has no mechanism to specify the
+character set of such strings; it would be fairly safe to stick to the
+invariant ISO 646 character set but the existing practice is probably
+to just transmit whatever the user specifies, and hope that everyone
+involved agrees which character set is in use, or sticks to a common
+subset.
+
+
+File: cvsclient.info, Node: Dates, Next: Request intro, Prev: Strings, Up: Protocol
+
+5.6 Dates
+=========
+
+The protocol contains times and dates in various places.
+
+ For the `-D' option to the `annotate', `co', `diff', `export',
+`history', `rannotate', `rdiff', `rtag', `tag', and `update' requests,
+the server should support two formats:
+
+ 26 May 1997 13:01:40 -0000 ; RFC 822 as modified by RFC 1123
+ 5/26/1997 13:01:40 GMT ; traditional
+
+ The former format is preferred; the latter however is sent by the CVS
+command line client (versions 1.5 through at least 1.9).
+
+ For the `-d' option to the `log' and `rlog' requests, servers should
+at least support RFC 822/1123 format. Clients are encouraged to use
+this format too (the command line CVS client, version 1.10 and older,
+just passed along the date format specified by the user, however).
+
+ The `Mod-time' response and `Checkin-time' request use RFC 822/1123
+format (see the descriptions of that response and request for details).
+
+ For `Notify', see the description of that request.
+
+
+File: cvsclient.info, Node: Request intro, Next: Requests, Prev: Dates, Up: Protocol
+
+5.7 Request intro
+=================
+
+By convention, requests which begin with a capital letter do not elicit
+a response from the server, while all others do - save one. The
+exception is `gzip-file-contents'. Unrecognized requests will always
+elicit a response from the server, even if that request begins with a
+capital letter.
+
+ The term "command" means a request which expects a response (except
+`valid-requests'). The general model is that the client transmits a
+great number of requests, but nothing happens until the very end when
+the client transmits a command. Although the intention is that
+transmitting several commands in one connection should be legal,
+existing servers probably have some bugs with some combinations of more
+than one command, and so clients may find it necessary to make several
+connections in some cases. This should be thought of as a workaround
+rather than a desired attribute of the protocol.
+
+
+File: cvsclient.info, Node: Requests, Next: Response intro, Prev: Request intro, Up: Protocol
+
+5.8 Requests
+============
+
+Here are the requests:
+
+`Root PATHNAME \n'
+ Response expected: no. Tell the server which `CVSROOT' to use.
+ Note that PATHNAME is a local directory and _not_ a fully
+ qualified `CVSROOT' variable. PATHNAME must already exist; if
+ creating a new root, use the `init' request, not `Root'. PATHNAME
+ does not include the hostname of the server, how to access the
+ server, etc.; by the time the CVS protocol is in use, connection,
+ authentication, etc., are already taken care of.
+
+ The `Root' request must be sent only once, and it must be sent
+ before any requests other than `Valid-responses',
+ `valid-requests', `UseUnchanged', `Set', `Global_option', `init',
+ `noop', or `version'.
+
+`Valid-responses REQUEST-LIST \n'
+ Response expected: no. Tell the server what responses the client
+ will accept. request-list is a space separated list of tokens.
+ The `Root' request need not have been previously sent.
+
+`valid-requests \n'
+ Response expected: yes. Ask the server to send back a
+ `Valid-requests' response. The `Root' request need not have been
+ previously sent.
+
+`Command-prep COMMAND \n'
+ Response expected: yes. Notify the server of the command that we
+ are leading up to. Intended to allow the server to send a
+ redirect for write operations. Requires either an `ok' or
+ `Redirect' respnose.
+
+`Referrer CVSROOT \n'
+ Response expected: no. Notify a primary server of a server which
+ referred us. Intended to allow a primary (write) server to update
+ the read-only mirror a client is using for reads to minimize races
+ on any subsequent updates from the client.
+
+`Directory LOCAL-DIRECTORY \n'
+`Relative-directory LOCAL-DIRECTORY \n'
+ Additional data: REPOSITORY \n. Response expected: no. Tell the
+ server what directory to use.
+
+ The REPOSITORY should be a directory name from a previous server
+ response and may be specified either relative to the PATHNAME
+ provided with the `Root' request or absolute. Relative or
+ absolute, it must specify a path within PATHNAME.
+
+ Prior to CVS version *FIXME - release number 1.12.10?*, REPOSITORY
+ had to be absolute and `Relative-directory' was not a valid
+ request. The `Relative-directory' request is synonymous with
+ `Directory' and is provided to alert modern clients that a relative
+ REPOSITORY is acceptable.
+
+ Note that this both gives a default for `Entry' and `Modified' and
+ also for `ci' and the other commands; normal usage is to send
+ `Directory' for each directory in which there will be an `Entry'
+ or `Modified', and then a final `Directory' for the original
+ directory, then the command. The LOCAL-DIRECTORY is relative to
+ the top level at which the command is occurring (i.e. the last
+ `Directory' which is sent before the command); to indicate that
+ top level, `.' should be sent for LOCAL-DIRECTORY.
+
+ Here is an example of where a client gets REPOSITORY and
+ LOCAL-DIRECTORY. Suppose that there is a module defined by
+
+ moddir 1dir
+
+ That is, one can check out `moddir' and it will take `1dir' in the
+ repository and check it out to `moddir' in the working directory.
+ Then an initial check out could proceed like this:
+
+ C: Root /home/kingdon/zwork/cvsroot
+ . . .
+ C: Argument moddir
+ C: Directory .
+ C: .
+ C: co
+ S: Clear-sticky moddir/
+ S: 1dir/
+ . . .
+ S: ok
+
+ In this example the response shown is `Clear-sticky', but it could
+ be another response instead. Note that it returns two pathnames.
+ The first one, `moddir/', indicates the working directory to check
+ out into. The second one, ending in `1dir/', indicates the
+ directory to pass back to the server in a subsequent `Directory'
+ request. For example, a subsequent `update' request might look
+ like:
+
+ C: Directory moddir
+ C: 1dir
+ . . .
+ C: update
+
+ For a given LOCAL-DIRECTORY, the repository will be the same for
+ each of the responses, so one can use the repository from whichever
+ response is most convenient. Typically a client will store the
+ repository along with the sources for each LOCAL-DIRECTORY, use
+ that same setting whenever operating on that LOCAL-DIRECTORY, and
+ not update the setting as long as the LOCAL-DIRECTORY exists.
+
+ A client is free to rename a LOCAL-DIRECTORY at any time (for
+ example, in response to an explicit user request). While it is
+ true that the server supplies a LOCAL-DIRECTORY to the client, as
+ noted above, this is only the default place to put the directory.
+ Of course, the various `Directory' requests for a single command
+ (for example, `update' or `ci' request) should name a particular
+ directory with the same LOCAL-DIRECTORY.
+
+ Each `Directory' request specifies a brand-new LOCAL-DIRECTORY and
+ REPOSITORY; that is, LOCAL-DIRECTORY and REPOSITORY are never
+ relative to paths specified in any previous `Directory' request.
+
+ Here's a more complex example, in which we request an update of a
+ working directory which has been checked out from multiple places
+ in the repository.
+
+ C: Argument dir1
+ C: Directory dir1
+ C: mod1
+ . . .
+ C: Argument dir2
+ C: Directory dir2
+ C: mod2
+ . . .
+ C: Argument dir3
+ C: Directory dir3/subdir3
+ C: mod3
+ . . .
+ C: update
+
+ While directories `dir1' and `dir2' will be handled in similar
+ fashion to the other examples given above, `dir3' is slightly
+ different from the server's standpoint. Notice that module `mod3'
+ is actually checked out into `dir3/subdir3', meaning that directory
+ `dir3' is either empty or does not contain data checked out from
+ this repository.
+
+ The above example will work correctly in CVS 1.10.1 and later. The
+ server will descend the tree starting from all directories
+ mentioned in `Argument' requests and update those directories
+ specifically mentioned in `Directory' requests.
+
+ Previous versions of CVS (1.10 and earlier) do not behave the same
+ way. While the descent of the tree begins at all directories
+ mentioned in `Argument' requests, descent into subdirectories only
+ occurs if a directory has been mentioned in a `Directory' request.
+ Therefore, the above example would succeed in updating `dir1' and
+ `dir2', but would skip `dir3' because that directory was not
+ specifically mentioned in a `Directory' request. A functional
+ version of the above that would run on a 1.10 or earlier server is
+ as follows:
+
+ C: Argument dir1
+ C: Directory dir1
+ C: mod1
+ . . .
+ C: Argument dir2
+ C: Directory dir2
+ C: mod2
+ . . .
+ C: Argument dir3
+ C: Directory dir3
+ C: .
+ . . .
+ C: Directory dir3/subdir3
+ C: mod3
+ . . .
+ C: update
+
+ Note the extra `Directory dir3' request. It might be better to use
+ `Emptydir' as the repository for the `dir3' directory, but the
+ above will certainly work.
+
+ One more peculiarity of the 1.10 and earlier protocol is the
+ ordering of `Directory' arguments. In order for a subdirectory to
+ be registered correctly for descent by the recursion processor,
+ its parent must be sent first. For example, the following would
+ not work to update `dir3/subdir3':
+
+ . . .
+ C: Argument dir3
+ C: Directory dir3/subdir3
+ C: mod3
+ . . .
+ C: Directory dir3
+ C: .
+ . . .
+ C: update
+
+ The implementation of the server in 1.10 and earlier writes the
+ administration files for a given directory at the time of the
+ `Directory' request. It also tries to register the directory with
+ its parent to mark it for recursion. In the above example, at the
+ time `dir3/subdir3' is created, the physical directory for `dir3'
+ will be created on disk, but the administration files will not
+ have been created. Therefore, when the server tries to register
+ `dir3/subdir3' for recursion, the operation will silently fail
+ because the administration files do not yet exist for `dir3'.
+
+`Max-dotdot LEVEL \n'
+ Response expected: no. Tell the server that LEVEL levels of
+ directories above the directory which `Directory' requests are
+ relative to will be needed. For example, if the client is
+ planning to use a `Directory' request for `../../foo', it must
+ send a `Max-dotdot' request with a LEVEL of at least 2.
+ `Max-dotdot' must be sent before the first `Directory' request.
+
+`Static-directory \n'
+ Response expected: no. Tell the server that the directory most
+ recently specified with `Directory' should not have additional
+ files checked out unless explicitly requested. The client sends
+ this if the `Entries.Static' flag is set, which is controlled by
+ the `Set-static-directory' and `Clear-static-directory' responses.
+
+`Sticky TAGSPEC \n'
+ Response expected: no. Tell the server that the directory most
+ recently specified with `Directory' has a sticky tag or date
+ TAGSPEC. The first character of TAGSPEC is `T' for a tag, `D' for
+ a date, or some other character supplied by a Set-sticky response
+ from a previous request to the server. The remainder of TAGSPEC
+ contains the actual tag or date, again as supplied by Set-sticky.
+
+ The server should remember `Static-directory' and `Sticky'
+ requests for a particular directory; the client need not resend
+ them each time it sends a `Directory' request for a given
+ directory. However, the server is not obliged to remember them
+ beyond the context of a single command.
+
+`Checkin-prog PROGRAM \n'
+ Response expected: no. Tell the server that the directory most
+ recently specified with `Directory' has a checkin program PROGRAM.
+ Such a program would have been previously set with the
+ `Set-checkin-prog' response.
+
+`Update-prog PROGRAM \n'
+ Response expected: no. Tell the server that the directory most
+ recently specified with `Directory' has an update program PROGRAM.
+ Such a program would have been previously set with the
+ `Set-update-prog' response.
+
+`Entry ENTRY-LINE \n'
+ Response expected: no. Tell the server what version of a file is
+ on the local machine. The name in ENTRY-LINE is a name relative
+ to the directory most recently specified with `Directory'. If the
+ user is operating on only some files in a directory, `Entry'
+ requests for only those files need be included. If an `Entry'
+ request is sent without `Modified', `Is-modified', or `Unchanged',
+ it means the file is lost (does not exist in the working
+ directory). If both `Entry' and one of `Modified', `Is-modified',
+ or `Unchanged' are sent for the same file, `Entry' must be sent
+ first. For a given file, one can send `Modified', `Is-modified',
+ or `Unchanged', but not more than one of these three.
+
+`Kopt OPTION \n'
+ This indicates to the server which keyword expansion options to
+ use for the file specified by the next `Modified' or `Is-modified'
+ request (for example `-kb' for a binary file). This is similar to
+ `Entry', but is used for a file for which there is no entries line.
+ Typically this will be a file being added via an `add' or `import'
+ request. The client may not send both `Kopt' and `Entry' for the
+ same file.
+
+`Checkin-time TIME \n'
+ For the file specified by the next `Modified' request, use TIME as
+ the time of the checkin. The TIME is in the format specified by
+ RFC822 as modified by RFC1123. The client may specify any
+ timezone it chooses; servers will want to convert that to their own
+ timezone as appropriate. An example of this format is:
+
+ 26 May 1997 13:01:40 -0400
+
+ There is no requirement that the client and server clocks be
+ synchronized. The client just sends its recommendation for a
+ timestamp (based on file timestamps or whatever), and the server
+ should just believe it (this means that the time might be in the
+ future, for example).
+
+ Note that this is not a general-purpose way to tell the server
+ about the timestamp of a file; that would be a separate request
+ (if there are servers which can maintain timestamp and time of
+ checkin separately).
+
+ This request should affect the `import' request, and may optionally
+ affect the `ci' request or other relevant requests if any.
+
+`Modified FILENAME \n'
+ Response expected: no. Additional data: mode, \n, file
+ transmission. Send the server a copy of one locally modified
+ file. FILENAME is a file within the most recent directory sent
+ with `Directory'; it must not contain `/'. If the user is
+ operating on only some files in a directory, only those files need
+ to be included. This can also be sent without `Entry', if there
+ is no entry for the file.
+
+`Is-modified FILENAME \n'
+ Response expected: no. Additional data: none. Like `Modified',
+ but used if the server only needs to know whether the file is
+ modified, not the contents.
+
+ The commands which can take `Is-modified' instead of `Modified'
+ with no known change in behavior are: `admin', `diff' (if and only
+ if two `-r' or `-D' options are specified), `watch-on',
+ `watch-off', `watch-add', `watch-remove', `watchers', `editors',
+ `log', and `annotate'.
+
+ For the `status' command, one can send `Is-modified' but if the
+ client is using imperfect mechanisms such as timestamps to
+ determine whether to consider a file modified, then the behavior
+ will be different. That is, if one sends `Modified', then the
+ server will actually compare the contents of the file sent and the
+ one it derives from to determine whether the file is genuinely
+ modified. But if one sends `Is-modified', then the server takes
+ the client's word for it. A similar situation exists for `tag',
+ if the `-c' option is specified.
+
+ Commands for which `Modified' is necessary are `co', `ci',
+ `update', and `import'.
+
+ Commands which do not need to inform the server about a working
+ directory, and thus should not be sending either `Modified' or
+ `Is-modified': `rdiff', `rtag', `history', `init', and `release'.
+
+ Commands for which further investigation is warranted are:
+ `remove', `add', and `export'. Pending such investigation, the
+ more conservative course of action is to stick to `Modified'.
+
+`Unchanged FILENAME \n'
+ Response expected: no. Tell the server that FILENAME has not been
+ modified in the checked out directory. The FILENAME is a file
+ within the most recent directory sent with `Directory'; it must
+ not contain `/'.
+
+`UseUnchanged \n'
+ Response expected: no. To specify the version of the protocol
+ described in this document, servers must support this request
+ (although it need not do anything) and clients must issue it. The
+ `Root' request need not have been previously sent.
+
+`Notify FILENAME \n'
+ Response expected: no. Tell the server that an `edit' or `unedit'
+ command has taken place. The server needs to send a `Notified'
+ response, but such response is deferred until the next time that
+ the server is sending responses. The FILENAME is a file within
+ the most recent directory sent with `Directory'; it must not
+ contain `/'. Additional data:
+ NOTIFICATION-TYPE \t TIME \t CLIENTHOST \t
+ WORKING-DIR \t WATCHES \n
+ where NOTIFICATION-TYPE is `E' for edit, `U' for unedit, undefined
+ behavior if `C', and all other letters should be silently ignored
+ for future expansion. TIME is the time at which the edit or
+ unedit took place, in a user-readable format of the client's
+ choice (the server should treat the time as an opaque string
+ rather than interpreting it). CLIENTHOST is the name of the host
+ on which the edit or unedit took place, and WORKING-DIR is the
+ pathname of the working directory where the edit or unedit took
+ place. WATCHES are the temporary watches, zero or more of the
+ following characters in the following order: `E' for edit, `U' for
+ unedit, `C' for commit, and all other letters should be silently
+ ignored for future expansion. If NOTIFICATION-TYPE is `E' the
+ temporary watches are set; if it is `U' they are cleared. If
+ WATCHES is followed by \t then the \t and the rest of the line
+ should be ignored, for future expansion.
+
+ The TIME, CLIENTHOST, and WORKING-DIR fields may not contain the
+ characters `+', `,', `>', `;', or `='.
+
+ Note that a client may be capable of performing an `edit' or
+ `unedit' operation without connecting to the server at that time,
+ and instead connecting to the server when it is convenient (for
+ example, when a laptop is on the net again) to send the `Notify'
+ requests. Even if a client is capable of deferring notifications,
+ it should attempt to send them immediately (one can send `Notify'
+ requests together with a `noop' request, for example), unless
+ perhaps if it can know that a connection would be impossible.
+
+`Questionable FILENAME \n'
+ Response expected: no. Additional data: no. Tell the server to
+ check whether FILENAME should be ignored, and if not, next time the
+ server sends responses, send (in a `M' response) `?' followed by
+ the directory and filename. FILENAME must not contain `/'; it
+ needs to be a file in the directory named by the most recent
+ `Directory' request.
+
+`Case \n'
+ Response expected: no. Tell the server that filenames should be
+ matched in a case-insensitive fashion. Note that this is not the
+ primary mechanism for achieving case-insensitivity; for the most
+ part the client keeps track of the case which the server wants to
+ use and takes care to always use that case regardless of what the
+ user specifies. For example the filenames given in `Entry' and
+ `Modified' requests for the same file must match in case
+ regardless of whether the `Case' request is sent. The latter
+ mechanism is more general (it could also be used for 8.3
+ filenames, VMS filenames with more than one `.', and any other
+ situation in which there is a predictable mapping between
+ filenames in the working directory and filenames in the protocol),
+ but there are some situations it cannot handle (ignore patterns, or
+ situations where the user specifies a filename and the client does
+ not know about that file).
+
+ Though this request will be supported into the forseeable future,
+ it has been the source of numerous bug reports in the past due to
+ the complexity of testing this functionality via the test suite
+ and client developers are encouraged not to use it. Instead,
+ please consider munging conflicting names and maintaining a map
+ for communicating with the server. For example, suppose the
+ server sends files `case', `CASE', and `CaSe'. The client could
+ write all three files to names such as, `case',
+ `case_prefix_case', and `case_prefix_2_case' and maintain a
+ mapping between the file names in, for instance a new `CVS/Map'
+ file.
+
+`Argument TEXT \n'
+ Response expected: no. Save argument for use in a subsequent
+ command. Arguments accumulate until an argument-using command is
+ given, at which point they are forgotten.
+
+`Argumentx TEXT \n'
+ Response expected: no. Append \n followed by text to the current
+ argument being saved.
+
+`Global_option OPTION \n'
+ Response expected: no. Transmit one of the global options `-q',
+ `-Q', `-l', `-t', `-r', or `-n'. OPTION must be one of those
+ strings, no variations (such as combining of options) are allowed.
+ For graceful handling of `valid-requests', it is probably better
+ to make new global options separate requests, rather than trying
+ to add them to this request. The `Root' request need not have
+ been previously sent.
+
+`Gzip-stream LEVEL \n'
+ Response expected: no. Use zlib (RFC 1950/1951) compression to
+ compress all further communication between the client and the
+ server. As of CVS 1.12.13, this request needs to be sent as the
+ first non-rootless request if the server is configured with
+ compression level restrictions and LEVEL is outside the restricted
+ range. After this request is sent, all further communication must
+ be compressed. All further data received from the server will
+ also be compressed. The LEVEL argument suggests to the server the
+ level of compression that it should apply; it should be an integer
+ between 0 and 9, inclusive, where `0' means no compression and
+ higher numbers indicate more compression.
+
+`Kerberos-encrypt \n'
+ Response expected: no. Use Kerberos encryption to encrypt all
+ further communication between the client and the server. This
+ will only work if the connection was made over Kerberos in the
+ first place. If both the `Gzip-stream' and the `Kerberos-encrypt'
+ requests are used, the `Kerberos-encrypt' request should be used
+ first. This will make the client and server encrypt the
+ compressed data, as opposed to compressing the encrypted data.
+ Encrypted data is generally incompressible.
+
+ Note that this request does not fully prevent an attacker from
+ hijacking the connection, in the sense that it does not prevent
+ hijacking the connection between the initial authentication and the
+ `Kerberos-encrypt' request.
+
+`Gssapi-encrypt \n'
+ Response expected: no. Use GSSAPI encryption to encrypt all
+ further communication between the client and the server. This
+ will only work if the connection was made over GSSAPI in the first
+ place. See `Kerberos-encrypt', above, for the relation between
+ `Gssapi-encrypt' and `Gzip-stream'.
+
+ Note that this request does not fully prevent an attacker from
+ hijacking the connection, in the sense that it does not prevent
+ hijacking the connection between the initial authentication and the
+ `Gssapi-encrypt' request.
+
+`Gssapi-authenticate \n'
+ Response expected: no. Use GSSAPI authentication to authenticate
+ all further communication between the client and the server. This
+ will only work if the connection was made over GSSAPI in the first
+ place. Encrypted data is automatically authenticated, so using
+ both `Gssapi-authenticate' and `Gssapi-encrypt' has no effect
+ beyond that of `Gssapi-encrypt'. Unlike encrypted data, it is
+ reasonable to compress authenticated data.
+
+ Note that this request does not fully prevent an attacker from
+ hijacking the connection, in the sense that it does not prevent
+ hijacking the connection between the initial authentication and the
+ `Gssapi-authenticate' request.
+
+`Set VARIABLE=VALUE \n'
+ Response expected: no. Set a user variable VARIABLE to VALUE.
+ The `Root' request need not have been previously sent.
+
+`Hostname HOSTNAME \n'
+ Response expected: no. Set the client hostname for an upcoming
+ `edit' request.
+
+`LocalDir HOSTNAME \n'
+ Response expected: no. Set the local client directory name for an
+ upcoming `edit' request.
+
+`expand-modules \n'
+ Response expected: yes. Expand the modules which are specified in
+ the arguments. Returns the data in `Module-expansion' responses.
+ Note that the server can assume that this is checkout or export,
+ not rtag or rdiff; the latter do not access the working directory
+ and thus have no need to expand modules on the client side.
+
+ Expand may not be the best word for what this request does. It
+ does not necessarily tell you all the files contained in a module,
+ for example. Basically it is a way of telling you which working
+ directories the server needs to know about in order to handle a
+ checkout of the specified modules.
+
+ For example, suppose that the server has a module defined by
+
+ aliasmodule -a 1dir
+
+ That is, one can check out `aliasmodule' and it will take `1dir'
+ in the repository and check it out to `1dir' in the working
+ directory. Now suppose the client already has this module checked
+ out and is planning on using the `co' request to update it.
+ Without using `expand-modules', the client would have two bad
+ choices: it could either send information about _all_ working
+ directories under the current directory, which could be
+ unnecessarily slow, or it could be ignorant of the fact that
+ `aliasmodule' stands for `1dir', and neglect to send information
+ for `1dir', which would lead to incorrect operation.
+
+ With `expand-modules', the client would first ask for the module to
+ be expanded:
+
+ C: Root /home/kingdon/zwork/cvsroot
+ . . .
+ C: Argument aliasmodule
+ C: Directory .
+ C: .
+ C: expand-modules
+ S: Module-expansion 1dir
+ S: ok
+
+ and then it knows to check the `1dir' directory and send requests
+ such as `Entry' and `Modified' for the files in that directory.
+
+`ci \n'
+`diff \n'
+`list \n'
+`tag \n'
+`status \n'
+`admin \n'
+`history \n'
+`watchers \n'
+`editors \n'
+`annotate \n'
+ Response expected: yes. Actually do a cvs command. This uses any
+ previous `Argument', `Directory', `Entry', or `Modified' requests,
+ if they have been sent. The last `Directory' sent specifies the
+ working directory at the time of the operation. No provision is
+ made for any input from the user. This means that `ci' must use a
+ `-m' argument if it wants to specify a log message.
+
+`log \n'
+ Response expected: yes. Show information for past revisions.
+ This uses any previous `Directory', `Entry', or `Modified'
+ requests, if they have been sent. The last `Directory' sent
+ specifies the working directory at the time of the operation.
+ Also uses previous `Argument''s of which the canonical forms are
+ the following (CVS 1.10 and older clients sent what the user
+ specified, but clients are encouraged to use the canonical forms
+ and other forms are deprecated):
+
+ `-b, -h, -l, -N, -R, -t'
+ These options go by themselves, one option per `Argument'
+ request.
+
+ `-d DATE1<DATE2'
+ Select revisions between DATE1 and DATE2. Either date may be
+ omitted in which case there is no date limit at that end of
+ the range (clients may specify dates such as 1 Jan 1970 or 1
+ Jan 2038 for similar purposes but this is problematic as it
+ makes assumptions about what dates the server supports).
+ Dates are in RFC822/1123 format. The `-d' is one `Argument'
+ request and the date range is a second one.
+
+ `-d DATE1<=DATE2'
+ Likewise but compare dates for equality.
+
+ `-d SINGLEDATE'
+ Select the single, latest revision dated SINGLEDATE or
+ earlier.
+
+ To include several date ranges and/or singledates, repeat the
+ `-d' option as many times as necessary.
+
+ `-rREV1:REV2'
+ `-rBRANCH'
+ `-rBRANCH.'
+ `-r'
+ Specify revisions (note that REV1 or REV2 can be omitted, or
+ can refer to branches). Send both the `-r' and the revision
+ information in a single `Argument' request. To include
+ several revision selections, repeat the `-r' option.
+
+ `-s STATE'
+ `-w'
+ `-wLOGIN'
+ Select on states or users. To include more than one state or
+ user, repeat the option. Send the `-s' option as a separate
+ argument from the state being selected. Send the `-w' option
+ as part of the same argument as the user being selected.
+
+`co \n'
+ Response expected: yes. Get files from the repository. This uses
+ any previous `Argument', `Directory', `Entry', or `Modified'
+ requests, if they have been sent. Arguments to this command are
+ module names; the client cannot know what directories they
+ correspond to except by (1) just sending the `co' request, and then
+ seeing what directory names the server sends back in its
+ responses, and (2) the `expand-modules' request.
+
+`export \n'
+ Response expected: yes. Get files from the repository. This uses
+ any previous `Argument', `Directory', `Entry', or `Modified'
+ requests, if they have been sent. Arguments to this command are
+ module names, as described for the `co' request. The intention
+ behind this command is that a client can get sources from a server
+ without storing CVS information about those sources. That is, a
+ client probably should not count on being able to take the entries
+ line returned in the `Created' response from an `export' request
+ and send it in a future `Entry' request. Note that the entries
+ line in the `Created' response must indicate whether the file is
+ binary or text, so the client can create it correctly.
+
+`ls \n'
+`rannotate \n'
+`rdiff \n'
+`rlist \n'
+`rlog \n'
+`rtag \n'
+ Response expected: yes. Actually do a cvs command. This uses any
+ previous `Argument' requests, if they have been sent. The client
+ should not send `Directory', `Entry', or `Modified' requests for
+ these commands; they are not used. Arguments to these commands
+ are module names, as described for `co'. `ls' is a synonym for
+ `rlist', for compatibility with CVSNT.
+
+`init ROOT-NAME \n'
+ Response expected: yes. If it doesn't already exist, create a CVS
+ repository ROOT-NAME. Note that ROOT-NAME is a local directory
+ and _not_ a fully qualified `CVSROOT' variable. The `Root'
+ request need not have been previously sent.
+
+`update \n'
+ Response expected: yes. Actually do a `cvs update' command. This
+ uses any previous `Argument', `Directory', `Entry', or `Modified'
+ requests, if they have been sent. The last `Directory' sent
+ specifies the working directory at the time of the operation. The
+ `-I' option is not used-files which the client can decide whether
+ to ignore are not mentioned and the client sends the
+ `Questionable' request for others.
+
+`import \n'
+ Response expected: yes. Actually do a `cvs import' command. This
+ uses any previous `Argument', `Directory', `Entry', or `Modified'
+ requests, if they have been sent. The last `Directory' sent
+ specifies the working directory at the time of the operation -
+ unlike most commands, the repository field of each `Directory'
+ request is ignored (it merely must point somewhere within the
+ root). The files to be imported are sent in `Modified' requests
+ (files which the client knows should be ignored are not sent; the
+ server must still process the CVSROOT/cvsignore file unless -I ! is
+ sent). A log message must have been specified with a `-m'
+ argument.
+
+`add \n'
+ Response expected: yes. Add a file or directory. This uses any
+ previous `Argument', `Directory', `Entry', or `Modified' requests,
+ if they have been sent. The last `Directory' sent specifies the
+ working directory at the time of the operation.
+
+ To add a directory, send the directory to be added using
+ `Directory' and `Argument' requests. For example:
+
+ C: Root /u/cvsroot
+ . . .
+ C: Argument nsdir
+ C: Directory nsdir
+ C: 1dir/nsdir
+ C: Directory .
+ C: 1dir
+ C: add
+ S: M Directory /u/cvsroot/1dir/nsdir added to the repository
+ S: ok
+
+ You will notice that the server does not signal to the client in
+ any particular way that the directory has been successfully added.
+ The client is supposed to just assume that the directory has been
+ added and update its records accordingly. Note also that adding a
+ directory is immediate; it does not wait until a `ci' request as
+ files do.
+
+ To add a file, send the file to be added using a `Modified'
+ request. For example:
+
+ C: Argument nfile
+ C: Directory .
+ C: 1dir
+ C: Modified nfile
+ C: u=rw,g=r,o=r
+ C: 6
+ C: hello
+ C: add
+ S: E cvs server: scheduling file `nfile' for addition
+ S: Mode u=rw,g=r,o=r
+ S: Checked-in ./
+ S: /u/cvsroot/1dir/nfile
+ S: /nfile/0///
+ S: E cvs server: use 'cvs commit' to add this file permanently
+ S: ok
+
+ Note that the file has not been added to the repository; the only
+ effect of a successful `add' request, for a file, is to supply the
+ client with a new entries line containing `0' to indicate an added
+ file. In fact, the client probably could perform this operation
+ without contacting the server, although using `add' does cause the
+ server to perform a few more checks.
+
+ The client sends a subsequent `ci' to actually add the file to the
+ repository.
+
+ Another quirk of the `add' request is that with CVS 1.9 and older,
+ a pathname specified in an `Argument' request cannot contain `/'.
+ There is no good reason for this restriction, and in fact more
+ recent CVS servers don't have it. But the way to interoperate
+ with the older servers is to ensure that all `Directory' requests
+ for `add' (except those used to add directories, as described
+ above), use `.' for LOCAL-DIRECTORY. Specifying another string for
+ LOCAL-DIRECTORY may not get an error, but it will get you strange
+ `Checked-in' responses from the buggy servers.
+
+`remove \n'
+ Response expected: yes. Remove a file. This uses any previous
+ `Argument', `Directory', `Entry', or `Modified' requests, if they
+ have been sent. The last `Directory' sent specifies the working
+ directory at the time of the operation.
+
+ Note that this request does not actually do anything to the
+ repository; the only effect of a successful `remove' request is to
+ supply the client with a new entries line containing `-' to
+ indicate a removed file. In fact, the client probably could
+ perform this operation without contacting the server, although
+ using `remove' may cause the server to perform a few more checks.
+
+ The client sends a subsequent `ci' request to actually record the
+ removal in the repository.
+
+`edit \n'
+ Response expected: yes. Actually do the `cvs edit' command. This
+ uses any previous `Argument', `Directory', `Entry', `LocalDir', or
+ `Hostname' requests, if they have been sent. Unless the user has
+ requested that edits not be granted unless no one else is editing
+ a file, a local edit followed by an attempt to send `Notify'
+ requests to the server is preferred.
+
+`watch-on \n'
+`watch-off \n'
+`watch-add \n'
+`watch-remove \n'
+ Response expected: yes. Actually do the `cvs watch on', `cvs
+ watch off', `cvs watch add', and `cvs watch remove' commands,
+ respectively. This uses any previous `Argument', `Directory',
+ `Entry', or `Modified' requests, if they have been sent. The last
+ `Directory' sent specifies the working directory at the time of
+ the operation.
+
+`release \n'
+ Response expected: yes. Note that a `cvs release' command has
+ taken place and update the history file accordingly.
+
+`global-list-quiet \n'
+ Response expected: yes. This request is a synonym for noop, but
+ its existance notifies the client that a `-q' option to `list' and
+ `rlist' will be rejected. This, in a reverse-logic sort of way,
+ is here so that when it _isn't_ received, as for instance from
+ CVSNT, the client will know that the quiet option has to be sent
+ as a command option rather than a global option.
+
+`noop \n'
+ Response expected: yes. This request is a null command in the
+ sense that it doesn't do anything, but merely (as with any other
+ requests expecting a response) sends back any responses pertaining
+ to pending errors, pending `Notified' responses, etc. The `Root'
+ request need not have been previously sent.
+
+`update-patches \n'
+ Response expected: yes. This request does not actually do
+ anything. It is used as a signal that the server is able to
+ generate patches when given an `update' request. The client must
+ issue the `-u' argument to `update' in order to receive patches.
+
+`gzip-file-contents LEVEL \n'
+ Response expected: no. Note that this request does not follow the
+ response convention stated above. `Gzip-stream' is suggested
+ instead of `gzip-file-contents' as it gives better compression; the
+ only reason to implement the latter is to provide compression with
+ CVS 1.8 and earlier. The `gzip-file-contents' request asks the
+ server to compress files it sends to the client using `gzip'
+ (RFC1952/1951) compression, using the specified level of
+ compression. If this request is not made, the server must not
+ compress files.
+
+ This is only a hint to the server. It may still decide (for
+ example, in the case of very small files, or files that already
+ appear to be compressed) not to do the compression. Compression
+ is indicated by a `z' preceding the file length.
+
+ Availability of this request in the server indicates to the client
+ that it may compress files sent to the server, regardless of
+ whether the client actually uses this request.
+
+`wrapper-sendme-rcsOptions \n'
+ Response expected: yes. Request that the server transmit mappings
+ from filenames to keyword expansion modes in `Wrapper-rcsOption'
+ responses.
+
+`version \n'
+ Response expected: yes. Request that the server transmit its
+ version message. The `Root' request need not have been previously
+ sent.
+
+`OTHER-REQUEST TEXT \n'
+ Response expected: yes. Any unrecognized request expects a
+ response, and does not contain any additional data. The response
+ will normally be something like `error unrecognized request', but
+ it could be a different error if a previous request which doesn't
+ expect a response produced an error.
+
+ When the client is done, it drops the connection.
+
+
+File: cvsclient.info, Node: Response intro, Next: Response pathnames, Prev: Requests, Up: Protocol
+
+5.9 Introduction to Responses
+=============================
+
+After a command which expects a response, the server sends however many
+of the following responses are appropriate. The server should not send
+data at other times (the current implementation may violate this
+principle in a few minor places, where the server is printing an error
+message and exiting--this should be investigated further).
+
+ Any set of responses always ends with `error' or `ok'. This
+indicates that the response is over.
+
+ The responses `Checked-in', `New-entry', `Updated', `Created',
+`Update-existing', `Merged', and `Patched' are refered to as "file
+updating" responses, because they change the status of a file in the
+working directory in some way. The responses `Mode', `Mod-time', and
+`Checksum' are referred to as "file update modifying" responses because
+they modify the next file updating response. In no case shall a file
+update modifying response apply to a file updating response other than
+the next one. Nor can the same file update modifying response occur
+twice for a given file updating response (if servers diagnose this
+problem, it may aid in detecting the case where clients send an update
+modifying response without following it by a file updating response).
+
+
+File: cvsclient.info, Node: Response pathnames, Next: Responses, Prev: Response intro, Up: Protocol
+
+5.10 The "pathname" in responses
+================================
+
+Many of the responses contain something called PATHNAME. The name is
+somewhat misleading; it actually indicates a pair of pathnames. First,
+a local directory name relative to the directory in which the command
+was given (i.e. the last `Directory' before the command). Then a
+linefeed and a repository name. Then a slash and the filename (without
+a `,v' ending).
+
+ The repository name may be absolute or relative to the PATHNAME sent
+with the `Root' request. If absolute, the repository name must begin
+with the PATHNAME sent with the `Root' request. Relative or absolute,
+the repository name must specify a path underneath the `Root' PATHNAME.
+
+ For example, for a file `i386.mh' which is in the local directory
+`gas.clean/config' and for which the repository name is
+`devo/gas/config':
+
+ gas.clean/config/
+ devo/gas/config/i386.mh
+
+ If the server wants to tell the client to create a directory, then it
+merely uses the directory in any response, as described above, and the
+client should create the directory if it does not exist. Note that this
+should only be done one directory at a time, in order to permit the
+client to correctly store the repository for each directory. Servers
+can use requests such as `Clear-sticky', `Clear-static-directory', or
+any other requests, to create directories.
+
+ Some server implementations may poorly distinguish between a
+directory which should not exist and a directory which contains no
+files; in order to refrain from creating empty directories a client
+should both send the `-P' option to `update' or `co', and should also
+detect the case in which the server asks to create a directory but not
+any files within it (in that case the client should remove the
+directory or refrain from creating it in the first place). Note that
+servers could clean this up greatly by only telling the client to
+create directories if the directory in question should exist, but until
+servers do this, clients will need to offer the `-P' behavior described
+above.
+
+
+File: cvsclient.info, Node: Responses, Next: Text tags, Prev: Response pathnames, Up: Protocol
+
+5.11 Responses
+==============
+
+Here are the responses:
+
+`Valid-requests REQUEST-LIST \n'
+ Indicate what requests the server will accept. REQUEST-LIST is a
+ space separated list of tokens. If the server supports sending
+ patches, it will include `update-patches' in this list. The
+ `update-patches' request does not actually do anything.
+
+`Force-gzip \n'
+ Response expected: no. Indicates that the server requires
+ compression. The client must send a `Gzip-stream' request, though
+ the requested LEVEL may be `0'.
+
+`Referrer CVSROOT'
+ Request that the client store CVSROOT as the name of this server
+ and that this name be passed via a `Referrer' _request_ to any
+ subsequent servers contacted as a result of a `Redirect' response.
+ This can be useful to allow the secondary administrator to
+ configure the `CVSROOT' the primary should use to update the
+ secondary in case the client uses a non-standard name or even a
+ name that is unique to the client for some reason.
+
+`Redirect CVSROOT'
+ Request that the client redirect its connection to CVSROOT and
+ begin again. This response is only valid in response to a
+ `Command-prep' request. If a client receives this response, it is
+ expected to notify the write server it subsequently contacts of
+ the CVSROOT of the server which redirected it using the `Referrer'
+ request. This information makes it possible for primary servers
+ to update the client's mirror first, hopefully minimizing race
+ conditions on subsequent updates from the same client.
+
+`Checked-in PATHNAME \n'
+ Additional data: New Entries line, \n. This means a file PATHNAME
+ has been successfully operated on (checked in, added, etc.). name
+ in the Entries line is the same as the last component of PATHNAME.
+
+`New-entry PATHNAME \n'
+ Additional data: New Entries line, \n. Like `Checked-in', but the
+ file is not up to date.
+
+`Updated PATHNAME \n'
+ Additional data: New Entries line, \n, mode, \n, file
+ transmission. A new copy of the file is enclosed. This is used
+ for a new revision of an existing file, or for a new file, or for
+ any other case in which the local (client-side) copy of the file
+ needs to be updated, and after being updated it will be up to
+ date. If any directory in pathname does not exist, create it.
+ This response is not used if `Created' and `Update-existing' are
+ supported.
+
+`Created PATHNAME \n'
+ This is just like `Updated' and takes the same additional data, but
+ is used only if no `Entry', `Modified', or `Unchanged' request has
+ been sent for the file in question. The distinction between
+ `Created' and `Update-existing' is so that the client can give an
+ error message in several cases: (1) there is a file in the working
+ directory, but not one for which `Entry', `Modified', or
+ `Unchanged' was sent (for example, a file which was ignored, or a
+ file for which `Questionable' was sent), (2) there is a file in
+ the working directory whose name differs from the one mentioned in
+ `Created' in ways that the client is unable to use to distinguish
+ files. For example, the client is case-insensitive and the names
+ differ only in case.
+
+`Update-existing PATHNAME \n'
+ This is just like `Updated' and takes the same additional data, but
+ is used only if a `Entry', `Modified', or `Unchanged' request has
+ been sent for the file in question.
+
+ This response, or `Merged', indicates that the server has
+ determined that it is OK to overwrite the previous contents of the
+ file specified by PATHNAME. Provided that the client has correctly
+ sent `Modified' or `Is-modified' requests for a modified file, and
+ the file was not modified while CVS was running, the server can
+ ensure that a user's modifications are not lost.
+
+`Merged PATHNAME \n'
+ This is just like `Updated' and takes the same additional data,
+ with the one difference that after the new copy of the file is
+ enclosed, it will still not be up to date. Used for the results
+ of a merge, with or without conflicts.
+
+ It is useful to preserve an copy of what the file looked like
+ before the merge. This is basically handled by the server; before
+ sending `Merged' it will send a `Copy-file' response. For
+ example, if the file is `aa' and it derives from revision 1.3, the
+ `Copy-file' response will tell the client to copy `aa' to
+ `.#aa.1.3'. It is up to the client to decide how long to keep this
+ file around; traditionally clients have left it around forever,
+ thus letting the user clean it up as desired. But another answer,
+ such as until the next commit, might be preferable.
+
+`Rcs-diff PATHNAME \n'
+ This is just like `Updated' and takes the same additional data,
+ with the one difference that instead of sending a new copy of the
+ file, the server sends an RCS change text. This change text is
+ produced by `diff -n' (the GNU diff `-a' option may also be used).
+ The client must apply this change text to the existing file.
+ This will only be used when the client has an exact copy of an
+ earlier revision of a file. This response is only used if the
+ `update' command is given the `-u' argument.
+
+`Patched PATHNAME \n'
+ This is just like `Rcs-diff' and takes the same additional data,
+ except that it sends a standard patch rather than an RCS change
+ text. The patch is produced by `diff -c' for CVS 1.6 and later
+ (see POSIX.2 for a description of this format), or `diff -u' for
+ previous versions of CVS; clients are encouraged to accept either
+ format. Like `Rcs-diff', this response is only used if the
+ `update' command is given the `-u' argument.
+
+ The `Patched' response is deprecated in favor of the `Rcs-diff'
+ response. However, older clients (CVS 1.9 and earlier) only
+ support `Patched'.
+
+`Edit-file PATHNAME \n'
+ Do the client-side portion of editing a file.
+
+`Mode MODE \n'
+ This MODE applies to the next file mentioned in `Checked-in'.
+ `Mode' is a file update modifying response as described in *Note
+ Response intro::.
+
+`Mod-time TIME \n'
+ Set the modification time of the next file sent to TIME.
+ `Mod-time' is a file update modifying response as described in
+ *Note Response intro::. The TIME is in the format specified by
+ RFC822 as modified by RFC1123. The server may specify any
+ timezone it chooses; clients will want to convert that to their
+ own timezone as appropriate. An example of this format is:
+
+ 26 May 1997 13:01:40 -0400
+
+ There is no requirement that the client and server clocks be
+ synchronized. The server just sends its recommendation for a
+ timestamp (based on its own clock, presumably), and the client
+ should just believe it (this means that the time might be in the
+ future, for example).
+
+ If the server does not send `Mod-time' for a given file, the client
+ should pick a modification time in the usual way (usually, just
+ let the operating system set the modification time to the time
+ that the CVS command is running).
+
+`Checksum CHECKSUM\n'
+ The CHECKSUM applies to the next file sent (that is, `Checksum' is
+ a file update modifying response as described in *Note Response
+ intro::). In the case of `Patched', the checksum applies to the
+ file after being patched, not to the patch itself. The client
+ should compute the checksum itself, after receiving the file or
+ patch, and signal an error if the checksums do not match. The
+ checksum is the 128 bit MD5 checksum represented as 32 hex digits
+ (MD5 is described in RFC1321). This response is optional, and is
+ only used if the client supports it (as judged by the
+ `Valid-responses' request).
+
+`Copy-file PATHNAME \n'
+ Additional data: NEWNAME \n. Copy file PATHNAME to NEWNAME in the
+ same directory where it already is. This does not affect
+ `CVS/Entries'.
+
+ This can optionally be implemented as a rename instead of a copy.
+ The only use for it which currently has been identified is prior
+ to a `Merged' response as described under `Merged'. Clients can
+ probably assume that is how it is being used, if they want to worry
+ about things like how long to keep the NEWNAME file around.
+
+`Removed PATHNAME \n'
+ The file has been removed from the repository (this is the case
+ where cvs prints `file foobar.c is no longer pertinent').
+
+`Remove-entry PATHNAME \n'
+ The file needs its entry removed from `CVS/Entries', but the file
+ itself is already gone (this happens in response to a `ci' request
+ which involves committing the removal of a file).
+
+`Set-static-directory PATHNAME \n'
+ This instructs the client to set the `Entries.Static' flag, which
+ it should then send back to the server in a `Static-directory'
+ request whenever the directory is operated on. PATHNAME ends in a
+ slash; its purpose is to specify a directory, not a file within a
+ directory.
+
+`Clear-static-directory PATHNAME \n'
+ Like `Set-static-directory', but clear, not set, the flag.
+
+`Set-sticky PATHNAME \n'
+ Additional data: TAGSPEC \n. Tell the client to set a sticky tag
+ or date, which should be supplied with the `Sticky' request for
+ future operations. PATHNAME ends in a slash; its purpose is to
+ specify a directory, not a file within a directory. The client
+ should store TAGSPEC and pass it back to the server as-is, to
+ allow for future expansion. The first character of TAGSPEC is `T'
+ for a tag, `D' for a date, or something else for future expansion.
+ The remainder of TAGSPEC contains the actual tag or date.
+
+`Clear-sticky PATHNAME \n'
+ Clear any sticky tag or date set by `Set-sticky'.
+
+`Template PATHNAME \n'
+ Additional data: file transmission (note: compressed file
+ transmissions are not supported). PATHNAME ends in a slash; its
+ purpose is to specify a directory, not a file within a directory.
+ Tell the client to store the file transmission as the template log
+ message, and then use that template in the future when prompting
+ the user for a log message.
+
+`Set-checkin-prog DIR \n'
+ Additional data: PROG \n. Tell the client to set a checkin
+ program, which should be supplied with the `Checkin-prog' request
+ for future operations.
+
+`Set-update-prog DIR \n'
+ Additional data: PROG \n. Tell the client to set an update
+ program, which should be supplied with the `Update-prog' request
+ for future operations.
+
+`Notified PATHNAME \n'
+ Indicate to the client that the notification for PATHNAME has been
+ done. There should be one such response for every `Notify'
+ request; if there are several `Notify' requests for a single file,
+ the requests should be processed in order; the first `Notified'
+ response pertains to the first `Notify' request, etc.
+
+`Module-expansion PATHNAME \n'
+ Return a file or directory which is included in a particular
+ module. PATHNAME is relative to cvsroot, unlike most pathnames in
+ responses. PATHNAME should be used to look and see whether some
+ or all of the module exists on the client side; it is not
+ necessarily suitable for passing as an argument to a `co' request
+ (for example, if the modules file contains the `-d' option, it
+ will be the directory specified with `-d', not the name of the
+ module).
+
+`Wrapper-rcsOption PATTERN -k 'OPTION' \n'
+ Transmit to the client a filename pattern which implies a certain
+ keyword expansion mode. The PATTERN is a wildcard pattern (for
+ example, `*.exe'. The OPTION is `b' for binary, and so on. Note
+ that although the syntax happens to resemble the syntax in certain
+ CVS configuration files, it is more constrained; there must be
+ exactly one space between PATTERN and `-k' and exactly one space
+ between `-k' and `'', and no string is permitted in place of `-k'
+ (extensions should be done with new responses, not by extending
+ this one, for graceful handling of `Valid-responses').
+
+`M TEXT \n'
+ A one-line message for the user. Note that the format of TEXT is
+ not designed for machine parsing. Although sometimes scripts and
+ clients will have little choice, the exact text which is output is
+ subject to vary at the discretion of the server and the example
+ output given in this document is just that, example output.
+ Servers are encouraged to use the `MT' response, and future
+ versions of this document will hopefully standardize more of the
+ `MT' tags; see *Note Text tags::.
+
+`Mbinary \n'
+ Additional data: file transmission (note: compressed file
+ transmissions are not supported). This is like `M', except the
+ contents of the file transmission are binary and should be copied
+ to standard output without translation to local text file
+ conventions. To transmit a text file to standard output, servers
+ should use a series of `M' requests.
+
+`E TEXT \n'
+ Same as `M' but send to stderr not stdout.
+
+`F \n'
+ Flush stderr. That is, make it possible for the user to see what
+ has been written to stderr (it is up to the implementation to
+ decide exactly how far it should go to ensure this).
+
+`MT TAGNAME DATA \n'
+ This response provides for tagged text. It is similar to
+ SGML/HTML/XML in that the data is structured and a naive
+ application can also make some sense of it without understanding
+ the structure. The syntax is not SGML-like, however, in order to
+ fit into the CVS protocol better and (more importantly) to make it
+ easier to parse, especially in a language like perl or awk.
+
+ The TAGNAME can have several forms. If it starts with `a' to `z'
+ or `A' to `Z', then it represents tagged text. If the
+ implementation recognizes TAGNAME, then it may interpret DATA in
+ some particular fashion. If the implementation does not recognize
+ TAGNAME, then it should simply treat DATA as text to be sent to
+ the user (similar to an `M' response). There are two tags which
+ are general purpose. The `text' tag is similar to an unrecognized
+ tag in that it provides text which will ordinarily be sent to the
+ user. The `newline' tag is used without DATA and indicates that a
+ newline will ordinarily be sent to the user (there is no provision
+ for embedding newlines in the DATA of other tagged text responses).
+
+ If TAGNAME starts with `+' it indicates a start tag and if it
+ starts with `-' it indicates an end tag. The remainder of TAGNAME
+ should be the same for matching start and end tags, and tags
+ should be nested (for example one could have tags in the following
+ order `+bold' `+italic' `text' `-italic' `-bold' but not `+bold'
+ `+italic' `text' `-bold' `-italic'). A particular start and end
+ tag may be documented to constrain the tagged text responses which
+ are valid between them.
+
+ Note that if DATA is present there will always be exactly one
+ space between TAGNAME and DATA; if there is more than one space,
+ then the spaces beyond the first are part of DATA.
+
+ Here is an example of some tagged text responses. Note that there
+ is a trailing space after `Checking in' and `initial revision:'
+ and there are two trailing spaces after `<--'. Such trailing
+ spaces are, of course, part of DATA.
+
+ MT +checking-in
+ MT text Checking in
+ MT fname gz.tst
+ MT text ;
+ MT newline
+ MT rcsfile /home/kingdon/zwork/cvsroot/foo/gz.tst,v
+ MT text <--
+ MT fname gz.tst
+ MT newline
+ MT text initial revision:
+ MT init-rev 1.1
+ MT newline
+ MT text done
+ MT newline
+ MT -checking-in
+
+ If the client does not support the `MT' response, the same
+ responses might be sent as:
+
+ M Checking in gz.tst;
+ M /home/kingdon/zwork/cvsroot/foo/gz.tst,v <-- gz.tst
+ M initial revision: 1.1
+ M done
+
+ For a list of specific tags, see *Note Text tags::.
+
+`error ERRNO-CODE ` ' TEXT \n'
+ The command completed with an error. ERRNO-CODE is a symbolic
+ error code (e.g. `ENOENT'); if the server doesn't support this
+ feature, or if it's not appropriate for this particular message,
+ it just omits the errno-code (in that case there are two spaces
+ after `error'). Text is an error message such as that provided by
+ strerror(), or any other message the server wants to use. The
+ TEXT is like the `M' response, in the sense that it is not
+ particularly intended to be machine-parsed; servers may wish to
+ print an error message with `MT' responses, and then issue a
+ `error' response without TEXT (although it should be noted that
+ `MT' currently has no way of flagging the output as intended for
+ standard error, the way that the `E' response does).
+
+`ok \n'
+ The command completed successfully.
+
+
+File: cvsclient.info, Node: Text tags, Next: Example, Prev: Responses, Up: Protocol
+
+5.12 Tags for the MT tagged text response
+=========================================
+
+The `MT' response, as described in *Note Responses::, offers a way for
+the server to send tagged text to the client. This section describes
+specific tags. The intention is to update this section as servers add
+new tags.
+
+ In the following descriptions, `text' and `newline' tags are
+omitted. Such tags contain information which is intended for users (or
+to be discarded), and are subject to change at the whim of the server.
+To avoid being vulnerable to such whim, clients should look for the tags
+listed here, not `text', `newline', or other tags.
+
+ The following tag means to indicate to the user that a file has been
+updated. It is more or less redundant with the `Created' and
+`Update-existing' responses, but we don't try to specify here whether
+it occurs in exactly the same circumstances as `Created' and
+`Update-existing'. The NAME is the pathname of the file being updated
+relative to the directory in which the command is occurring (that is,
+the last `Directory' request which is sent before the command).
+
+ MT +updated
+ MT fname NAME
+ MT -updated
+
+ The `importmergecmd' tag is used when doing an import which has
+conflicts, or when doing an import with the `-X' flag. The client can
+use it to report how to merge in the newly imported changes. The COUNT
+is the number of conflicts, or the string `No' if no conflicts
+occurred. (The latter will only be sent for imports run with the `-X'
+flag.) The newly imported changes can be merged by running the
+following command:
+ cvs checkout -j TAG1 -j TAG2 REPOSITORY
+
+ MT +importmergecmd
+ MT conflicts COUNT
+ MT mergetag1 TAG1
+ MT mergetag2 TAG2
+ MT repository REPOSITORY
+ MT -importmergecmd
+
+
+File: cvsclient.info, Node: Example, Next: Requirements, Prev: Text tags, Up: Protocol
+
+5.13 Example
+============
+
+Here is an example; lines are prefixed by `C: ' to indicate the client
+sends them or `S: ' to indicate the server sends them.
+
+ The client starts by connecting, sending the root, and completing the
+protocol negotiation. In actual practice the lists of valid responses
+and requests would be longer.
+
+ C: Root /u/cvsroot
+ C: Valid-responses ok error Checked-in M E
+ C: valid-requests
+ S: Valid-requests Root Directory Entry Modified Argument Argumentx ci co
+ S: ok
+ C: UseUnchanged
+
+ The client wants to check out the `supermunger' module into a fresh
+working directory. Therefore it first expands the `supermunger'
+module; this step would be omitted if the client was operating on a
+directory rather than a module.
+
+ C: Argument supermunger
+ C: Directory .
+ C: .
+ C: expand-modules
+
+ The server replies that the `supermunger' module expands to the
+directory `supermunger' (the simplest case):
+
+ S: Module-expansion supermunger
+ S: ok
+
+ The client then proceeds to check out the directory. The fact that
+it sends only a single `Directory' request which specifies `.' for the
+working directory means that there is not already a `supermunger'
+directory on the client.
+
+ C: Argument -N
+ C: Argument supermunger
+ C: Directory .
+ C: .
+ C: co
+
+ The server replies with the requested files. In this example, there
+is only one file, `mungeall.c'. The `Clear-sticky' and
+`Clear-static-directory' requests are sent by the current
+implementation but they have no effect because the default is for those
+settings to be clear when a directory is newly created.
+
+ S: Clear-sticky supermunger/
+ S: /u/cvsroot/supermunger/
+ S: Clear-static-directory supermunger/
+ S: /u/cvsroot/supermunger/
+ S: E cvs server: Updating supermunger
+ S: M U supermunger/mungeall.c
+ S: Created supermunger/
+ S: /u/cvsroot/supermunger/mungeall.c
+ S: /mungeall.c/1.1///
+ S: u=rw,g=r,o=r
+ S: 26
+ S: int mein () { abort (); }
+ S: ok
+
+ The current client implementation would break the connection here
+and make a new connection for the next command. However, the protocol
+allows it to keep the connection open and continue, which is what we
+show here.
+
+ After the user modifies the file and instructs the client to check it
+back in. The client sends arguments to specify the log message and file
+to check in:
+
+ C: Argument -m
+ C: Argument Well, you see, it took me hours and hours to find
+ C: Argumentx this typo and I searched and searched and eventually
+ C: Argumentx had to ask John for help.
+ C: Argument mungeall.c
+
+ It also sends information about the contents of the working
+directory, including the new contents of the modified file. Note that
+the user has changed into the `supermunger' directory before executing
+this command; the top level directory is a user-visible concept because
+the server should print filenames in `M' and `E' responses relative to
+that directory.
+
+ C: Directory .
+ C: supermunger
+ C: Entry /mungeall.c/1.1///
+ C: Modified mungeall.c
+ C: u=rw,g=r,o=r
+ C: 26
+ C: int main () { abort (); }
+
+ And finally, the client issues the checkin command (which makes use
+of the data just sent):
+
+ C: ci
+
+ And the server tells the client that the checkin succeeded:
+
+ S: M Checking in mungeall.c;
+ S: E /u/cvsroot/supermunger/mungeall.c,v <-- mungeall.c
+ S: E new revision: 1.2; previous revision: 1.1
+ S: E done
+ S: Mode u=rw,g=r,o=r
+ S: Checked-in ./
+ S: /u/cvsroot/supermunger/mungeall.c
+ S: /mungeall.c/1.2///
+ S: ok
+
+
+File: cvsclient.info, Node: Requirements, Next: Obsolete, Prev: Example, Up: Protocol
+
+5.14 Required versus optional parts of the protocol
+===================================================
+
+The following are part of every known implementation of the CVS protocol
+(except obsolete, pre-1.5, versions of CVS) and it is considered
+reasonable behavior to completely fail to work if you are connected with
+an implementation which attempts to not support them. Requests:
+`Root', `Valid-responses', `valid-requests', `Directory', `Entry',
+`Modified', `Unchanged', `Argument', `Argumentx', `ci', `co', `update'.
+Responses: `ok', `error', `Valid-requests', `Checked-in', `Updated',
+`Merged', `Removed', `M', `E'.
+
+ A server need not implement `Repository', but in order to
+interoperate with CVS 1.5 through 1.9 it must claim to implement it (in
+`Valid-requests'). The client will not actually send the request.
+
+
+File: cvsclient.info, Node: Obsolete, Prev: Requirements, Up: Protocol
+
+5.15 Obsolete protocol elements
+===============================
+
+This section briefly describes protocol elements which are obsolete.
+There is no attempt to document them in full detail.
+
+ There was a `Repository' request which was like `Directory' except
+it only provided REPOSITORY, and the local directory was assumed to be
+similarly named.
+
+ If the `UseUnchanged' request was not sent, there was a `Lost'
+request which was sent to indicate that a file did not exist in the
+working directory, and the meaning of sending `Entries' without `Lost'
+or `Modified' was different. All current clients (CVS 1.5 and later)
+will send `UseUnchanged' if it is supported.
+
+
+File: cvsclient.info, Node: Protocol Notes, Prev: Protocol, Up: Top
+
+6 Notes on the Protocol
+***********************
+
+A number of enhancements are possible. Also see the file TODO in the
+CVS source distribution, which has further ideas concerning various
+aspects of CVS, some of which impact the protocol. Similarly, the
+`http://www.nongnu.org/cvs/' site, in particular the `Development'
+pages.
+
+ * The `Modified' request could be speeded up by sending diffs rather
+ than entire files. The client would need some way to keep the
+ version of the file which was originally checked out; probably
+ requiring the use of "cvs edit" in this case is the most sensible
+ course (the "cvs edit" could be handled by a package like VC for
+ emacs). This would also allow local operation of `cvs diff'
+ without arguments.
+
+ * The fact that `pserver' requires an extra network turnaround in
+ order to perform authentication would be nice to avoid. This
+ relates to the issue of reporting errors; probably the clean
+ solution is to defer the error until the client has issued a
+ request which expects a response. To some extent this might
+ relate to the next item (in terms of how easy it is to skip a
+ whole bunch of requests until we get to one that expects a
+ response). I know that the kerberos code doesn't wait in this
+ fashion, but that probably can cause network deadlocks and perhaps
+ future problems running over a transport which is more transaction
+ oriented than TCP. On the other hand I'm not sure it is wise to
+ make the client conduct a lengthy upload only to find there is an
+ authentication failure.
+
+ * The protocol uses an extra network turnaround for protocol
+ negotiation (`valid-requests'). It might be nice to avoid this by
+ having the client be able to send requests and tell the server to
+ ignore them if they are unrecognized (different requests could
+ produce a fatal error if unrecognized). To do this there should
+ be a standard syntax for requests. For example, perhaps all
+ future requests should be a single line, with mechanisms analogous
+ to `Argumentx', or several requests working together, to provide
+ greater amounts of information. Or there might be a standard
+ mechanism for counted data (analogous to that used by `Modified')
+ or continuation lines (like a generalized `Argumentx'). It would
+ be useful to compare what HTTP is planning in this area; last I
+ looked they were contemplating something called Protocol Extension
+ Protocol but I haven't looked at the relevant IETF documents in
+ any detail. Obviously, we want something as simple as possible
+ (but no simpler).
+
+ * The scrambling algorithm in the CVS client and server actually
+ support more characters than those documented in *Note Password
+ scrambling::. Someday we are going to either have to document
+ them all (but this is not as easy as it may look, see below), or
+ (gradually and with adequate process) phase out the support for
+ other characters in the CVS implementation. This business of
+ having the feature partly undocumented isn't a desirable state
+ long-term.
+
+ The problem with documenting other characters is that unless we
+ know what character set is in use, there is no way to make a
+ password portable from one system to another. For example, a with
+ a circle on top might have different encodings in different
+ character sets.
+
+ It _almost_ works to say that the client picks an arbitrary,
+ unknown character set (indeed, having the CVS client know what
+ character set the user has in mind is a hard problem otherwise),
+ and scrambles according to a certain octet<->octet mapping. There
+ are two problems with this. One is that the protocol has no way
+ to transmit character 10 decimal (linefeed), and the current
+ server and clients have no way to handle 0 decimal (NUL). This
+ may cause problems with certain multibyte character sets, in which
+ octets 10 and 0 will appear in the middle of other characters.
+ The other problem, which is more minor and possibly not worth
+ worrying about, is that someone can type a password on one system
+ and then go to another system which uses a different encoding for
+ the same characters, and have their password not work.
+
+ The restriction to the ISO646 invariant subset is the best
+ approach for strings which are not particularly significant to
+ users. Passwords are visible enough that this is somewhat
+ doubtful as applied here. ISO646 does, however, have the virtue
+ (!?) of offending everyone. It is easy to say "But the $ is right
+ on people's keyboards! Surely we can't forbid that". From a
+ human factors point of view, that makes quite a bit of sense. The
+ contrary argument, of course, is that a with a circle on top, or
+ some of the characters poorly handled by Unicode, are on
+ _someone_'s keyboard.
+
+
+
+
+Tag Table:
+Node: Top212
+Node: Introduction1031
+Node: Goals3567
+Node: Connection and Authentication6487
+Node: Password scrambling12726
+Node: Protocol14594
+Node: Entries Lines16680
+Node: File Modes17787
+Node: Filenames19330
+Node: File transmissions20642
+Node: Strings22205
+Node: Dates22893
+Node: Request intro23962
+Node: Requests24987
+Node: Response intro63870
+Node: Response pathnames65242
+Node: Responses67427
+Node: Text tags84766
+Node: Example86644
+Node: Requirements90401
+Node: Obsolete91316
+Node: Protocol Notes92061
+
+End Tag Table
diff --git a/doc/cvsclient.pdf b/doc/cvsclient.pdf
new file mode 100644
index 0000000..e481a90
--- /dev/null
+++ b/doc/cvsclient.pdf
Binary files differ
diff --git a/doc/cvsclient.texi b/doc/cvsclient.texi
new file mode 100644
index 0000000..5c288f0
--- /dev/null
+++ b/doc/cvsclient.texi
@@ -0,0 +1,2188 @@
+\input texinfo @c -*- texinfo -*-
+
+@setfilename cvsclient.info
+@include version-client.texi
+
+@dircategory Programming
+@direntry
+* cvsclient: (cvsclient). The CVS client/server protocol.
+@end direntry
+
+@node Top
+@top CVS Client/Server
+
+This document describes the client/server protocol used by CVS. It does
+not describe how to use or administer client/server CVS; see the regular
+CVS manual for that. This is version @value{VERSION} of the protocol
+specification---@xref{Introduction}, for more on what this version number
+means.
+
+@menu
+* Introduction:: What is CVS and what is the client/server protocol for?
+* Goals:: Basic design decisions, requirements, scope, etc.
+* Connection and Authentication:: Various ways to connect to the server
+* Password scrambling:: Scrambling used by pserver
+* Protocol:: Complete description of the protocol
+* Protocol Notes:: Possible enhancements, limitations, etc. of the protocol
+@end menu
+
+@node Introduction
+@chapter Introduction
+
+CVS is a version control system (with some additional configuration
+management functionality). It maintains a central @dfn{repository}
+which stores files (often source code), including past versions,
+information about who modified them and when, and so on. People who
+wish to look at or modify those files, known as @dfn{developers}, use
+CVS to @dfn{check out} a @dfn{working directory} from the repository, to
+@dfn{check in} new versions of files to the repository, and other
+operations such as viewing the modification history of a file. If
+developers are connected to the repository by a network, particularly a
+slow or flaky one, the most efficient way to use the network is with the
+CVS-specific protocol described in this document.
+
+Developers, using the machine on which they store their working
+directory, run the CVS @dfn{client} program. To perform operations
+which cannot be done locally, it connects to the CVS @dfn{server}
+program, which maintains the repository. For more information on how
+to connect see @ref{Connection and Authentication}.
+
+This document describes the CVS protocol. Unfortunately, it does not
+yet completely document one aspect of the protocol---the detailed
+operation of each CVS command and option---and one must look at the CVS
+user documentation, @file{cvs.texinfo}, for that information. The
+protocol is non-proprietary (anyone who wants to is encouraged to
+implement it) and an implementation, known as CVS, is available under
+the GNU Public License. The CVS distribution, containing this
+implementation, @file{cvs.texinfo}, and a copy (possibly more or less up
+to date than what you are reading now) of this document,
+@file{cvsclient.texi}, can be found at the usual GNU FTP sites, with a
+filename such as @file{cvs-@var{version}.tar.gz}.
+
+This is version @value{VERSION} of the protocol specification. This
+version number is intended only to aid in distinguishing different
+versions of this specification. Although the specification is currently
+maintained in conjunction with the CVS implementation, and carries the
+same version number, it also intends to document what is involved with
+interoperating with other implementations (such as other versions of
+CVS); see @ref{Requirements}. This version number should not be used
+by clients or servers to determine what variant of the protocol to
+speak; they should instead use the @code{valid-requests} and
+@code{Valid-responses} mechanism (@pxref{Protocol}), which is more
+flexible.
+
+@node Goals
+@chapter Goals
+
+@itemize @bullet
+@item
+Do not assume any access to the repository other than via this protocol.
+It does not depend on NFS, rdist, etc.
+
+@item
+Providing a reliable transport is outside this protocol. The protocol
+expects a reliable transport that is transparent (that is, there is no
+translation of characters, including characters such as
+linefeeds or carriage returns), and can transmit all 256 octets (for
+example for proper handling of binary files, compression, and
+encryption). The encoding of characters specified by the protocol (the
+names of requests and so on) is the invariant ISO 646 character set (a
+subset of most popular character sets including ASCII and others). For
+more details on running the protocol over the TCP reliable transport,
+see @ref{Connection and Authentication}.
+
+@item
+Security and authentication are handled outside this protocol (but see
+below about @samp{cvs kserver} and @samp{cvs pserver}).
+
+@item
+The protocol makes it possible for updates to be atomic with respect to
+checkins; that is if someone commits changes to several files in one cvs
+command, then an update by someone else would either get all the
+changes, or none of them. The current @sc{cvs} server can't do this,
+but that isn't the protocol's fault.
+
+@item
+The protocol is, with a few exceptions, transaction-based. That is, the
+client sends all its requests (without waiting for server responses),
+and then waits for the server to send back all responses (without
+waiting for further client requests). This has the advantage of
+minimizing network turnarounds and the disadvantage of sometimes
+transferring more data than would be necessary if there were a richer
+interaction. Another, more subtle, advantage is that there is no need
+for the protocol to provide locking for features such as making checkins
+atomic with respect to updates. Any such locking can be handled
+entirely by the server. A good server implementation (such as the
+current @sc{cvs} server) will make sure that it does not have any such
+locks in place whenever it is waiting for communication with the client;
+this prevents one client on a slow or flaky network from interfering
+with the work of others.
+
+@item
+It is a general design goal to provide only one way to do a given
+operation (where possible). For example, implementations have no choice
+about whether to terminate lines with linefeeds or some other
+character(s), and request and response names are case-sensitive. This
+is to enhance interoperability. If a protocol allows more than one way
+to do something, it is all too easy for some implementations to support
+only some of them (perhaps accidentally).
+@c I vaguely remember reading, probably in an RFC, about the problems
+@c that were caused when some people decided that SMTP should accept
+@c other line termination (in the message ("DATA")?) than CRLF. However, I
+@c can't seem to track down the reference.
+@end itemize
+
+@node Connection and Authentication
+@chapter How to Connect to and Authenticate Oneself to the CVS server
+
+Connection and authentication occurs before the CVS protocol itself is
+started. There are several ways to connect.
+
+@table @asis
+@item server
+If the client has a way to execute commands on the server, and provide
+input to the commands and output from them, then it can connect that
+way. This could be the usual rsh (port 514) protocol, Kerberos rsh,
+SSH, or any similar mechanism. The client may allow the user to specify
+the name of the server program; the default is @code{cvs}. It is
+invoked with one argument, @code{server}. Once it invokes the server,
+the client proceeds to start the cvs protocol.
+
+@item kserver
+The kerberized server listens on a port (in the current implementation,
+by having inetd call "cvs kserver") which defaults to 1999. The client
+connects, sends the usual kerberos authentication information, and then
+starts the cvs protocol. Note: port 1999 is officially registered for
+another use, and in any event one cannot register more than one port for
+CVS, so GSS-API (see below) is recommended instead of kserver as a way
+to support kerberos.
+
+@item pserver
+The name @dfn{pserver} is somewhat confusing. It refers to both a
+generic framework which allows the CVS protocol to support several
+authentication mechanisms, and a name for a specific mechanism which
+transfers a username and a cleartext password. Servers need not support
+all mechanisms, and in fact servers will typically want to support only
+those mechanisms which meet the relevant security needs.
+
+The pserver server listens on a port (in the current
+implementation, by having inetd call "cvs pserver") which defaults to
+2401 (this port is officially registered). The client
+connects, and sends the following:
+
+@itemize @bullet
+@item
+the string @samp{BEGIN AUTH REQUEST}, a linefeed,
+@item
+the cvs root, a linefeed,
+@item
+the username, a linefeed,
+@item
+the password trivially encoded (see @ref{Password scrambling}), a
+linefeed,
+@item
+the string @samp{END AUTH REQUEST}, and a linefeed.
+@end itemize
+
+The client must send the
+identical string for cvs root both here and later in the
+@code{Root} request of the cvs
+protocol itself. Servers are encouraged to enforce this restriction.
+The possible server responses (each of which is followed by a linefeed)
+are the following. Note that although there is a small similarity
+between this authentication protocol and the cvs protocol, they are
+separate.
+
+@table @code
+@item I LOVE YOU
+The authentication is successful. The client proceeds with the cvs
+protocol itself.
+
+@item I HATE YOU
+The authentication fails. After sending this response, the server may
+close the connection. It is up to the server to decide whether to give
+this response, which is generic, or a more specific response using
+@samp{E} and/or @samp{error}.
+
+@item E @var{text}
+Provide a message for the user. After this reponse, the authentication
+protocol continues with another response. Typically the server will
+provide a series of @samp{E} responses followed by @samp{error}.
+Compatibility note: @sc{cvs} 1.9.10 and older clients will print
+@code{unrecognized auth response} and @var{text}, and then exit, upon
+receiving this response.
+
+@item error @var{code} @var{text}
+The authentication fails. After sending this response, the server may
+close the connection. The @var{code} is a code describing why it
+failed, intended for computer consumption. The only code currently
+defined is @samp{0} which is nonspecific, but clients must silently
+treat any unrecognized codes as nonspecific.
+The @var{text} should be supplied to the
+user. Compatibility note: @sc{cvs} 1.9.10 and older clients will print
+@code{unrecognized auth response} and @var{text}, and then exit, upon
+receiving this response.
+Note that @var{text} for this response, or the @var{text} in an @code{E}
+response, is not designed for machine parsing. More vigorous use of
+@var{code}, or future extensions, will be needed to prove a cleaner
+machine-parseable indication of what the error was.
+@end table
+
+@c If you are thinking of putting samp or code around BEGIN AUTH REQUEST
+@c and friends, watch for overfull hboxes.
+If the client wishes to merely authenticate without starting the cvs
+protocol, the procedure is the same, except BEGIN AUTH REQUEST is
+replaced with BEGIN VERIFICATION REQUEST, END AUTH REQUEST
+is replaced with END VERIFICATION REQUEST, and upon receipt of
+I LOVE YOU the connection is closed rather than continuing.
+
+Another mechanism is GSSAPI authentication. GSSAPI is a
+generic interface to security services such as kerberos. GSSAPI is
+specified in RFC2078 (GSSAPI version 2) and RFC1508 (GSSAPI version 1);
+we are not aware of differences between the two which affect the
+protocol in incompatible ways, so we make no attempt to specify one
+version or the other.
+The procedure here is to start with @samp{BEGIN
+GSSAPI REQUEST}. GSSAPI authentication information is then exchanged
+between the client and the server. Each packet of information consists
+of a two byte big endian length, followed by that many bytes of data.
+After the GSSAPI authentication is complete, the server continues with
+the responses described above (@samp{I LOVE YOU}, etc.).
+
+@item future possibilities
+There are a nearly unlimited number of ways to connect and authenticate.
+One might want to allow access based on IP address (similar to the usual
+rsh protocol but with different/no restrictions on ports < 1024), to
+adopt mechanisms such as Pluggable Authentication Modules (PAM), to
+allow users to run their own servers under their own usernames without
+root access, or any number of other possibilities. The way to add
+future mechanisms, for the most part, should be to continue to use port
+2401, but to use different strings in place of @samp{BEGIN AUTH
+REQUEST}.
+@end table
+
+@node Password scrambling
+@chapter Password scrambling algorithm
+
+The pserver authentication protocol, as described in @ref{Connection and
+Authentication}, trivially encodes the passwords. This is only to
+prevent inadvertent compromise; it provides no protection against even a
+relatively unsophisticated attacker. For comparison, HTTP Basic
+Authentication (as described in RFC2068) uses BASE64 for a similar
+purpose. CVS uses its own algorithm, described here.
+
+The scrambled password starts with @samp{A}, which serves to identify
+the scrambling algorithm in use. After that follows a single octet for
+each character in the password, according to a fixed encoding. The
+values are shown here, with the encoded values in decimal. Control
+characters, space, and characters outside the invariant ISO 646
+character set are not shown; such characters are not recommended for use
+in passwords. There is a long discussion of character set issues in
+@ref{Protocol Notes}.
+
+@example
+ 0 111 P 125 p 58
+! 120 1 52 A 57 Q 55 a 121 q 113
+" 53 2 75 B 83 R 54 b 117 r 32
+ 3 119 C 43 S 66 c 104 s 90
+ 4 49 D 46 T 124 d 101 t 44
+% 109 5 34 E 102 U 126 e 100 u 98
+& 72 6 82 F 40 V 59 f 69 v 60
+' 108 7 81 G 89 W 47 g 73 w 51
+( 70 8 95 H 38 X 92 h 99 x 33
+) 64 9 65 I 103 Y 71 i 63 y 97
+* 76 : 112 J 45 Z 115 j 94 z 62
++ 67 ; 86 K 50 k 93
+, 116 < 118 L 42 l 39
+- 74 = 110 M 123 m 37
+. 68 > 122 N 91 n 61
+/ 87 ? 105 O 35 _ 56 o 48
+@end example
+
+@node Protocol
+@chapter The CVS client/server protocol
+
+In the following, @samp{\n} refers to a linefeed and @samp{\t} refers to
+a horizontal tab; @dfn{requests} are what the client sends and
+@dfn{responses} are what the server sends. In general, the connection is
+governed by the client---the server does not send responses without
+first receiving requests to do so; see @ref{Response intro} for more
+details of this convention.
+
+It is typical, early in the connection, for the client to transmit a
+@code{Valid-responses} request, containing all the responses it
+supports, followed by a @code{valid-requests} request, which elicits
+from the server a @code{Valid-requests} response containing all the
+requests it understands. In this way, the client and server each find
+out what the other supports before exchanging large amounts of data
+(such as file contents).
+
+@c Hmm, having 3 sections in this menu makes a certain amount of sense
+@c but that structure gets lost in the printed manual (not sure about
+@c HTML). Perhaps there is a better way.
+@menu
+
+General protocol conventions:
+
+* Entries Lines:: Transmitting RCS data
+* File Modes:: Read, write, execute, and possibly more...
+* Filenames:: Conventions regarding filenames
+* File transmissions:: How file contents are transmitted
+* Strings:: Strings in various requests and responses
+* Dates:: Times and dates
+
+The protocol itself:
+
+* Request intro:: General conventions relating to requests
+* Requests:: List of requests
+* Response intro:: General conventions relating to responses
+* Response pathnames:: The "pathname" in responses
+* Responses:: List of responses
+* Text tags:: More details about the MT response
+
+An example session, and some further observations:
+
+* Example:: A conversation between client and server
+* Requirements:: Things not to omit from an implementation
+* Obsolete:: Former protocol features
+@end menu
+
+@node Entries Lines
+@section Entries Lines
+
+Entries lines are transmitted as:
+
+@example
+/ @var{name} / @var{version} / @var{conflict} / @var{options} / @var{tag_or_date}
+@end example
+
+@var{tag_or_date} is either @samp{T} @var{tag} or @samp{D} @var{date}
+or empty. If it is followed by a slash, anything after the slash
+shall be silently ignored.
+
+@var{version} can be empty, or start with @samp{0} or @samp{-}, for no
+user file, new user file, or user file to be removed, respectively.
+
+@c FIXME: should distinguish sender and receiver behavior here; the
+@c "anything else" and "does not start with" are intended for future
+@c expansion, and we should specify a sender behavior.
+@var{conflict}, if it starts with @samp{+}, indicates that the file had
+conflicts in it. The rest of @var{conflict} is @samp{=} if the
+timestamp matches the file, or anything else if it doesn't. If
+@var{conflict} does not start with a @samp{+}, it is silently ignored.
+
+@var{options} signifies the keyword expansion options (for example
+@samp{-ko}). In an @code{Entry} request, this indicates the options
+that were specified with the file from the previous file updating
+response (@pxref{Response intro}, for a list of file updating
+responses); if the client is specifying the @samp{-k} or @samp{-A}
+option to @code{update}, then it is the server which figures out what
+overrides what.
+
+@node File Modes
+@section File Modes
+
+A mode is any number of repetitions of
+
+@example
+@var{mode-type} = @var{data}
+@end example
+
+separated by @samp{,}.
+
+@var{mode-type} is an identifier composed of alphanumeric characters.
+Currently specified: @samp{u} for user, @samp{g} for group, @samp{o}
+for other (see below for discussion of whether these have their POSIX
+meaning or are more loose). Unrecognized values of @var{mode-type}
+are silently ignored.
+
+@var{data} consists of any data not containing @samp{,}, @samp{\0} or
+@samp{\n}. For @samp{u}, @samp{g}, and @samp{o} mode types, data
+consists of alphanumeric characters, where @samp{r} means read, @samp{w}
+means write, @samp{x} means execute, and unrecognized letters are
+silently ignored.
+
+The two most obvious ways in which the mode matters are: (1) is it
+writeable? This is used by the developer communication features, and
+is implemented even on OS/2 (and could be implemented on DOS), whose
+notion of mode is limited to a readonly bit. (2) is it executable?
+Unix CVS users need CVS to store this setting (for shell scripts and
+the like). The current CVS implementation on unix does a little bit
+more than just maintain these two settings, but it doesn't really have
+a nice general facility to store or version control the mode, even on
+unix, much less across operating systems with diverse protection
+features. So all the ins and outs of what the mode means across
+operating systems haven't really been worked out (e.g. should the VMS
+port use ACLs to get POSIX semantics for groups?).
+
+@node Filenames
+@section Conventions regarding transmission of file names
+
+In most contexts, @samp{/} is used to separate directory and file
+names in filenames, and any use of other conventions (for example,
+that the user might type on the command line) is converted to that
+form. The only exceptions might be a few cases in which the server
+provides a magic cookie which the client then repeats verbatim, but as
+the server has not yet been ported beyond unix, the two rules provide
+the same answer (and what to do if future server ports are operating
+on a repository like e:/foo or CVS_ROOT:[FOO.BAR] has not been
+carefully thought out).
+
+Characters outside the invariant ISO 646 character set should be avoided
+in filenames. This restriction may need to be relaxed to allow for
+characters such as @samp{[} and @samp{]} (see above about non-unix
+servers); this has not been carefully considered (and currently
+implementations probably use whatever character sets that the operating
+systems they are running on allow, and/or that users specify). Of
+course the most portable practice is to restrict oneself further, to the
+POSIX portable filename character set as specified in POSIX.1.
+
+@node File transmissions
+@section File transmissions
+
+File contents (noted below as @var{file transmission}) can be sent in
+one of two forms. The simpler form is a number of bytes, followed by a
+linefeed, followed by the specified number of bytes of file contents.
+These are the entire contents of the specified file. Second, if both
+client and server support @samp{gzip-file-contents}, a @samp{z} may
+precede the length, and the `file contents' sent are actually compressed
+with @samp{gzip} (RFC1952/1951) compression. The length specified is
+that of the compressed version of the file.
+
+In neither case are the file content followed by any additional data.
+The transmission of a file will end with a linefeed iff that file (or its
+compressed form) ends with a linefeed.
+
+The encoding of file contents depends on the value for the @samp{-k}
+option. If the file is binary (as specified by the @samp{-kb} option in
+the appropriate place), then it is just a certain number of octets, and
+the protocol contributes nothing towards determining the encoding (using
+the file name is one widespread, if not universally popular, mechanism).
+If the file is text (not binary), then the file is sent as a series of
+lines, separated by linefeeds. If the keyword expansion is set to
+something other than @samp{-ko}, then it is expected that the file
+conform to the RCS expectations regarding keyword expansion---in
+particular, that it is in a character set such as ASCII in which 0x24 is
+a dollar sign (@samp{$}).
+
+@node Strings
+@section Strings
+
+In various contexts, for example the @code{Argument} request and the
+@code{M} response, one transmits what is essentially an arbitrary
+string. Often this will have been supplied by the user (for example,
+the @samp{-m} option to the @code{ci} request). The protocol has no
+mechanism to specify the character set of such strings; it would be
+fairly safe to stick to the invariant ISO 646 character set but the
+existing practice is probably to just transmit whatever the user
+specifies, and hope that everyone involved agrees which character set is
+in use, or sticks to a common subset.
+
+@node Dates
+@section Dates
+
+The protocol contains times and dates in various places.
+
+For the @samp{-D} option to the @code{annotate}, @code{co}, @code{diff},
+@code{export}, @code{history}, @code{rannotate}, @code{rdiff},
+@code{rtag}, @code{tag},
+and @code{update} requests, the server should support two formats:
+
+@example
+26 May 1997 13:01:40 -0000 ; @r{RFC 822 as modified by RFC 1123}
+5/26/1997 13:01:40 GMT ; @r{traditional}
+@end example
+
+The former format is preferred; the latter however is sent by the CVS
+command line client (versions 1.5 through at least 1.9).
+
+For the @samp{-d} option to the @code{log} and @code{rlog} requests,
+servers should at
+least support RFC 822/1123 format. Clients are encouraged to use this
+format too (the command line CVS client, version 1.10 and older, just passed
+along the date format specified by the user, however).
+
+The @code{Mod-time} response and @code{Checkin-time} request use RFC
+822/1123 format (see the descriptions of that response and request for
+details).
+
+For @code{Notify}, see the description of that request.
+
+@node Request intro
+@section Request intro
+
+By convention, requests which begin with a capital letter do not elicit
+a response from the server, while all others do -- save one. The
+exception is @samp{gzip-file-contents}. Unrecognized requests will
+always elicit a response from the server, even if that request begins
+with a capital letter.
+
+The term @dfn{command} means a request which expects a response (except
+@code{valid-requests}). The general model is that the client transmits
+a great number of requests, but nothing happens until the very end when
+the client transmits a command. Although the intention is that
+transmitting several commands in one connection should be legal,
+existing servers probably have some bugs with some combinations of more
+than one command, and so clients may find it necessary to make several
+connections in some cases. This should be thought of as a workaround
+rather than a desired attribute of the protocol.
+
+@node Requests
+@section Requests
+
+Here are the requests:
+
+@table @code
+@item Root @var{pathname} \n
+Response expected: no. Tell the server which @code{CVSROOT} to use.
+Note that @var{pathname} is a local directory and @emph{not} a fully
+qualified @code{CVSROOT} variable. @var{pathname} must
+already exist; if creating a new root, use the @code{init} request, not
+@code{Root}. @var{pathname} does not include the hostname of the
+server, how to access the server, etc.; by the time the CVS protocol is
+in use, connection, authentication, etc., are already taken care of.
+
+The @code{Root} request must be sent only once, and it must be sent
+before any requests other than @code{Valid-responses},
+@code{valid-requests}, @code{UseUnchanged}, @code{Set},
+@code{Global_option}, @code{init}, @code{noop}, or @code{version}.
+
+@item Valid-responses @var{request-list} \n
+Response expected: no.
+Tell the server what responses the client will accept.
+request-list is a space separated list of tokens.
+The @code{Root} request need not have been previously sent.
+
+@item valid-requests \n
+Response expected: yes.
+Ask the server to send back a @code{Valid-requests} response.
+The @code{Root} request need not have been previously sent.
+
+@item Command-prep @var{command} \n
+Response expected: yes.
+Notify the server of the command that we are leading up to. Intended to allow
+the server to send a redirect for write operations. Requires either an
+@code{ok} or @code{Redirect} respnose.
+
+@item Referrer @var{CVSROOT} \n
+Response expected: no.
+Notify a primary server of a server which referred us. Intended to allow
+a primary (write) server to update the read-only mirror a client is using
+for reads to minimize races on any subsequent updates from the client.
+
+@item Directory @var{local-directory} \n
+@itemx Relative-directory @var{local-directory} \n
+Additional data: @var{repository} \n. Response expected: no.
+Tell the server what directory to use.
+
+The @var{repository} should be a directory name from a previous server
+response and may be specified either relative to the @var{pathname} provided
+with the @code{Root} request or absolute. Relative or absolute, it must
+specify a path within @var{pathname}.
+
+Prior to @sc{cvs} version @strong{FIXME - release number 1.12.10?},
+@var{repository} had to be absolute and @code{Relative-directory} was not a
+valid request. The @code{Relative-directory} request is synonymous with
+@code{Directory} and is provided to alert modern clients that a relative
+@var{repository} is acceptable.
+
+Note that this both gives a default for @code{Entry} and @code{Modified} and
+also for @code{ci} and the other commands; normal usage is to send
+@code{Directory} for each directory in which there will be an
+@code{Entry} or @code{Modified}, and then a final @code{Directory}
+for the original directory, then the command.
+The @var{local-directory} is relative to
+the top level at which the command is occurring (i.e. the last
+@code{Directory} which is sent before the command);
+to indicate that top level, @samp{.} should be sent for
+@var{local-directory}.
+
+Here is an example of where a client gets @var{repository} and
+@var{local-directory}. Suppose that there is a module defined by
+
+@example
+moddir 1dir
+@end example
+
+That is, one can check out @code{moddir} and it will take @code{1dir} in
+the repository and check it out to @code{moddir} in the working
+directory. Then an initial check out could proceed like this:
+
+@example
+C: Root /home/kingdon/zwork/cvsroot
+. . .
+C: Argument moddir
+C: Directory .
+C: .
+C: co
+S: Clear-sticky moddir/
+S: 1dir/
+. . .
+S: ok
+@end example
+
+In this example the response shown is @code{Clear-sticky}, but it could
+be another response instead. Note that it returns two pathnames.
+The first one, @file{moddir/}, indicates the working
+directory to check out into. The second one, ending in @file{1dir/},
+indicates the directory to pass back to the server in a subsequent
+@code{Directory} request. For example, a subsequent @code{update}
+request might look like:
+
+@example
+C: Directory moddir
+C: 1dir
+. . .
+C: update
+@end example
+
+For a given @var{local-directory}, the repository will be the same for
+each of the responses, so one can use the repository from whichever
+response is most convenient. Typically a client will store the
+repository along with the sources for each @var{local-directory}, use
+that same setting whenever operating on that @var{local-directory}, and
+not update the setting as long as the @var{local-directory} exists.
+
+A client is free to rename a @var{local-directory} at any time (for
+example, in response to an explicit user request). While it is true
+that the server supplies a @var{local-directory} to the client, as noted
+above, this is only the default place to put the directory. Of course,
+the various @code{Directory} requests for a single command (for example,
+@code{update} or @code{ci} request) should name a particular directory
+with the same @var{local-directory}.
+
+Each @code{Directory} request specifies a brand-new
+@var{local-directory} and @var{repository}; that is,
+@var{local-directory} and @var{repository} are never relative to paths
+specified in any previous @code{Directory} request.
+
+Here's a more complex example, in which we request an update of a
+working directory which has been checked out from multiple places in the
+repository.
+
+@example
+C: Argument dir1
+C: Directory dir1
+C: mod1
+. . .
+C: Argument dir2
+C: Directory dir2
+C: mod2
+. . .
+C: Argument dir3
+C: Directory dir3/subdir3
+C: mod3
+. . .
+C: update
+@end example
+
+While directories @code{dir1} and @code{dir2} will be handled in similar
+fashion to the other examples given above, @code{dir3} is slightly
+different from the server's standpoint. Notice that module @code{mod3}
+is actually checked out into @code{dir3/subdir3}, meaning that directory
+@code{dir3} is either empty or does not contain data checked out from
+this repository.
+
+The above example will work correctly in @sc{cvs} 1.10.1 and later. The
+server will descend the tree starting from all directories mentioned in
+@code{Argument} requests and update those directories specifically
+mentioned in @code{Directory} requests.
+
+Previous versions of @sc{cvs} (1.10 and earlier) do not behave the same
+way. While the descent of the tree begins at all directories mentioned
+in @code{Argument} requests, descent into subdirectories only occurs if
+a directory has been mentioned in a @code{Directory} request.
+Therefore, the above example would succeed in updating @code{dir1} and
+@code{dir2}, but would skip @code{dir3} because that directory was not
+specifically mentioned in a @code{Directory} request. A functional
+version of the above that would run on a 1.10 or earlier server is as
+follows:
+
+@example
+C: Argument dir1
+C: Directory dir1
+C: mod1
+. . .
+C: Argument dir2
+C: Directory dir2
+C: mod2
+. . .
+C: Argument dir3
+C: Directory dir3
+C: .
+. . .
+C: Directory dir3/subdir3
+C: mod3
+. . .
+C: update
+@end example
+
+Note the extra @code{Directory dir3} request. It might be better to use
+@code{Emptydir} as the repository for the @code{dir3} directory, but the
+above will certainly work.
+
+One more peculiarity of the 1.10 and earlier protocol is the ordering of
+@code{Directory} arguments. In order for a subdirectory to be
+registered correctly for descent by the recursion processor, its parent
+must be sent first. For example, the following would not work to update
+@code{dir3/subdir3}:
+
+@example
+. . .
+C: Argument dir3
+C: Directory dir3/subdir3
+C: mod3
+. . .
+C: Directory dir3
+C: .
+. . .
+C: update
+@end example
+
+The implementation of the server in 1.10 and earlier writes the
+administration files for a given directory at the time of the
+@code{Directory} request. It also tries to register the directory with
+its parent to mark it for recursion. In the above example, at the time
+@code{dir3/subdir3} is created, the physical directory for @code{dir3}
+will be created on disk, but the administration files will not have been
+created. Therefore, when the server tries to register
+@code{dir3/subdir3} for recursion, the operation will silently fail
+because the administration files do not yet exist for @code{dir3}.
+
+@item Max-dotdot @var{level} \n
+Response expected: no.
+Tell the server that @var{level} levels of directories above the
+directory which @code{Directory} requests are relative to will be
+needed. For example, if the client is planning to use a
+@code{Directory} request for @file{../../foo}, it must send a
+@code{Max-dotdot} request with a @var{level} of at least 2.
+@code{Max-dotdot} must be sent before the first @code{Directory}
+request.
+
+@item Static-directory \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Directory} should not have
+additional files checked out unless explicitly requested. The client
+sends this if the @code{Entries.Static} flag is set, which is controlled
+by the @code{Set-static-directory} and @code{Clear-static-directory}
+responses.
+
+@item Sticky @var{tagspec} \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Directory} has a sticky tag or date @var{tagspec}.
+The first character of @var{tagspec} is @samp{T} for a tag, @samp{D}
+for a date, or some other character supplied by a Set-sticky response
+from a previous request to the server. The remainder of @var{tagspec}
+contains the actual tag or date, again as supplied by Set-sticky.
+
+The server should remember @code{Static-directory} and @code{Sticky}
+requests for a particular directory; the client need not resend them
+each time it sends a @code{Directory} request for a given directory.
+However, the server is not obliged to remember them beyond the context
+of a single command.
+
+@item Checkin-prog @var{program} \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Directory} has a checkin program @var{program}.
+Such a program would have been previously set with the
+@code{Set-checkin-prog} response.
+
+@item Update-prog @var{program} \n
+Response expected: no. Tell the server that the directory most recently
+specified with @code{Directory} has an update program @var{program}.
+Such a program would have been previously set with the
+@code{Set-update-prog} response.
+
+@item Entry @var{entry-line} \n
+Response expected: no. Tell the server what version of a file is on the
+local machine. The name in @var{entry-line} is a name relative to the
+directory most recently specified with @code{Directory}. If the user
+is operating on only some files in a directory, @code{Entry} requests
+for only those files need be included. If an @code{Entry} request is
+sent without @code{Modified}, @code{Is-modified}, or @code{Unchanged},
+it means the file is
+lost (does not exist in the working directory). If both @code{Entry}
+and one of @code{Modified}, @code{Is-modified}, or @code{Unchanged} are
+sent for the same file, @code{Entry} must be sent first. For a
+given file, one can send @code{Modified}, @code{Is-modified}, or
+@code{Unchanged}, but not more than one of these three.
+
+@item Kopt @var{option} \n
+This indicates to the server which keyword expansion options to use for
+the file specified by the next @code{Modified} or @code{Is-modified}
+request (for example @samp{-kb} for a binary file). This is similar to
+@code{Entry}, but is used for a file for which there is no entries line.
+Typically this will be a file being added via an @code{add} or
+@code{import} request. The client may not send both @code{Kopt} and
+@code{Entry} for the same file.
+
+@item Checkin-time @var{time} \n
+For the file specified by the next @code{Modified} request, use
+@var{time} as the time of the checkin. The @var{time} is in the format
+specified by RFC822 as modified by RFC1123. The client may specify any
+timezone it chooses; servers will want to convert that to their own
+timezone as appropriate. An example of this format is:
+
+@example
+26 May 1997 13:01:40 -0400
+@end example
+
+There is no requirement that the client and server clocks be
+synchronized. The client just sends its recommendation for a timestamp
+(based on file timestamps or whatever), and the server should just believe
+it (this means that the time might be in the future, for example).
+
+Note that this is not a general-purpose way to tell the server about the
+timestamp of a file; that would be a separate request (if there are
+servers which can maintain timestamp and time of checkin separately).
+
+This request should affect the @code{import} request, and may optionally
+affect the @code{ci} request or other relevant requests if any.
+
+@item Modified @var{filename} \n
+Response expected: no. Additional data: mode, \n, file transmission.
+Send the server a copy of one locally modified file. @var{filename} is
+a file within the most recent directory sent with @code{Directory}; it
+must not contain @samp{/}. If
+the user is operating on only some files in a directory, only those
+files need to be included. This can also be sent without @code{Entry},
+if there is no entry for the file.
+
+@item Is-modified @var{filename} \n
+Response expected: no. Additional data: none. Like @code{Modified},
+but used if the server only needs
+to know whether the file is modified, not the contents.
+
+The commands which can take @code{Is-modified} instead of
+@code{Modified} with no known change in behavior are: @code{admin},
+@code{diff} (if and only if two @samp{-r} or @samp{-D} options are
+specified), @code{watch-on}, @code{watch-off}, @code{watch-add},
+@code{watch-remove}, @code{watchers}, @code{editors},
+@code{log}, and @code{annotate}.
+
+For the @code{status} command, one can send @code{Is-modified} but if
+the client is using imperfect mechanisms such as timestamps to determine
+whether to consider a file modified, then the behavior will be
+different. That is, if one sends @code{Modified}, then the server will
+actually compare the contents of the file sent and the one it derives
+from to determine whether the file is genuinely modified. But if one
+sends @code{Is-modified}, then the server takes the client's word for
+it. A similar situation exists for @code{tag}, if the @samp{-c} option
+is specified.
+
+Commands for which @code{Modified} is necessary are @code{co},
+@code{ci}, @code{update}, and @code{import}.
+
+Commands which do not need to inform the server about a working
+directory, and thus should not be sending either @code{Modified} or
+@code{Is-modified}: @code{rdiff}, @code{rtag}, @code{history},
+@code{init}, and @code{release}.
+
+Commands for which further investigation is warranted are:
+@code{remove}, @code{add}, and @code{export}. Pending such
+investigation, the more conservative course of action is to stick to
+@code{Modified}.
+
+@item Unchanged @var{filename} \n
+Response expected: no. Tell the server that @var{filename} has not been
+modified in the checked out directory. The @var{filename} is
+a file within the most recent directory sent with @code{Directory}; it
+must not contain @samp{/}.
+
+@item UseUnchanged \n
+Response expected: no. To specify the version of the protocol described
+in this document, servers must support this request (although it need
+not do anything) and clients must issue it.
+The @code{Root} request need not have been previously sent.
+
+@item Notify @var{filename} \n
+Response expected: no.
+Tell the server that an @code{edit} or @code{unedit} command has taken
+place. The server needs to send a @code{Notified} response, but such
+response is deferred until the next time that the server is sending
+responses.
+The @var{filename} is a file within the most recent directory sent with
+@code{Directory}; it must not contain @samp{/}.
+Additional data:
+@example
+@var{notification-type} \t @var{time} \t @var{clienthost} \t
+@var{working-dir} \t @var{watches} \n
+@end example
+where @var{notification-type} is @samp{E} for edit, @samp{U} for
+unedit, undefined behavior if @samp{C}, and all other letters should be
+silently ignored for future expansion.
+@var{time} is the time at which the edit or unedit took place, in a
+user-readable format of the client's choice (the server should treat the
+time as an opaque string rather than interpreting it).
+@c Might be useful to specify a format, but I don't know if we want to
+@c specify the status quo (ISO C asctime() format plus timezone) without
+@c offering the option of ISO8601 and/or RFC822/1123 (see cvs.texinfo
+@c for much much more on date formats).
+@var{clienthost} is the name of the host on which the edit or unedit
+took place, and @var{working-dir} is the pathname of the working
+directory where the edit or unedit took place. @var{watches} are the
+temporary watches, zero or more of the following characters in the
+following order: @samp{E} for edit, @samp{U} for unedit, @samp{C} for
+commit, and all other letters should be silently ignored for future
+expansion. If @var{notification-type} is @samp{E} the temporary watches
+are set; if it is @samp{U} they are cleared.
+If @var{watches} is followed by \t then the
+\t and the rest of the line should be ignored, for future expansion.
+
+The @var{time}, @var{clienthost}, and @var{working-dir} fields may not
+contain the characters @samp{+}, @samp{,}, @samp{>}, @samp{;}, or @samp{=}.
+
+Note that a client may be capable of performing an @code{edit} or
+@code{unedit} operation without connecting to the server at that time,
+and instead connecting to the server when it is convenient (for example,
+when a laptop is on the net again) to send the @code{Notify} requests.
+Even if a client is capable of deferring notifications, it should
+attempt to send them immediately (one can send @code{Notify} requests
+together with a @code{noop} request, for example), unless perhaps if
+it can know that a connection would be impossible.
+
+@item Questionable @var{filename} \n
+Response expected: no. Additional data: no. Tell the server to check
+whether @var{filename} should be ignored, and if not, next time the
+server sends responses, send (in a @code{M} response) @samp{?} followed
+by the directory and filename. @var{filename} must not contain
+@samp{/}; it needs to be a file in the directory named by the most
+recent @code{Directory} request.
+@c FIXME: the bit about not containing / is true of most of the
+@c requests, but isn't documented and should be.
+
+@item Case \n
+Response expected: no. Tell the server that filenames should be matched
+in a case-insensitive fashion. Note that this is not the primary
+mechanism for achieving case-insensitivity; for the most part the client
+keeps track of the case which the server wants to use and takes care to
+always use that case regardless of what the user specifies. For example
+the filenames given in @code{Entry} and @code{Modified} requests for the
+same file must match in case regardless of whether the @code{Case}
+request is sent. The latter mechanism is more general (it could also be
+used for 8.3 filenames, VMS filenames with more than one @samp{.}, and
+any other situation in which there is a predictable mapping between
+filenames in the working directory and filenames in the protocol), but
+there are some situations it cannot handle (ignore patterns, or
+situations where the user specifies a filename and the client does not
+know about that file).
+
+Though this request will be supported into the forseeable future, it has been
+the source of numerous bug reports in the past due to the complexity of testing
+this functionality via the test suite and client developers are encouraged not
+to use it. Instead, please consider munging conflicting names and maintaining
+a map for communicating with the server. For example, suppose the server sends
+files @file{case}, @file{CASE}, and @file{CaSe}. The client could write all
+three files to names such as, @file{case}, @file{case_prefix_case}, and
+@file{case_prefix_2_case} and maintain a mapping between the file names in, for
+instance a new @file{CVS/Map} file.
+
+@item Argument @var{text} \n
+Response expected: no.
+Save argument for use in a subsequent command. Arguments
+accumulate until an argument-using command is given, at which point
+they are forgotten.
+
+@item Argumentx @var{text} \n
+Response expected: no. Append \n followed by text to the current
+argument being saved.
+
+@item Global_option @var{option} \n
+Response expected: no.
+Transmit one of the global options @samp{-q}, @samp{-Q}, @samp{-l},
+@samp{-t}, @samp{-r}, or @samp{-n}. @var{option} must be one of those
+strings, no variations (such as combining of options) are allowed. For
+graceful handling of @code{valid-requests}, it is probably better to
+make new global options separate requests, rather than trying to add
+them to this request.
+The @code{Root} request need not have been previously sent.
+
+@item Gzip-stream @var{level} \n
+Response expected: no.
+Use zlib (RFC 1950/1951) compression to compress all further communication
+between the client and the server. As of @sc{cvs} 1.12.13, this request needs
+to be sent as the first non-rootless request if the server is configured
+with compression level restrictions and @var{level} is outside the restricted
+range. After this request is sent, all further communication must be
+compressed. All further data received from the server will also be
+compressed. The @var{level} argument suggests to the server the level of
+compression that it should apply; it should be an integer between 0 and 9,
+inclusive, where @samp{0} means no compression and higher numbers indicate more
+compression.
+
+@item Kerberos-encrypt \n
+Response expected: no.
+Use Kerberos encryption to encrypt all further communication between the
+client and the server. This will only work if the connection was made
+over Kerberos in the first place. If both the @code{Gzip-stream} and
+the @code{Kerberos-encrypt} requests are used, the
+@code{Kerberos-encrypt} request should be used first. This will make
+the client and server encrypt the compressed data, as opposed to
+compressing the encrypted data. Encrypted data is generally
+incompressible.
+
+Note that this request does not fully prevent an attacker from hijacking
+the connection, in the sense that it does not prevent hijacking the
+connection between the initial authentication and the
+@code{Kerberos-encrypt} request.
+
+@item Gssapi-encrypt \n
+Response expected: no.
+Use GSSAPI encryption to encrypt all further communication between the
+client and the server. This will only work if the connection was made
+over GSSAPI in the first place. See @code{Kerberos-encrypt}, above, for
+the relation between @code{Gssapi-encrypt} and @code{Gzip-stream}.
+
+Note that this request does not fully prevent an attacker from hijacking
+the connection, in the sense that it does not prevent hijacking the
+connection between the initial authentication and the
+@code{Gssapi-encrypt} request.
+
+@item Gssapi-authenticate \n
+Response expected: no.
+Use GSSAPI authentication to authenticate all further communication
+between the client and the server. This will only work if the
+connection was made over GSSAPI in the first place. Encrypted data is
+automatically authenticated, so using both @code{Gssapi-authenticate}
+and @code{Gssapi-encrypt} has no effect beyond that of
+@code{Gssapi-encrypt}. Unlike encrypted data, it is reasonable to
+compress authenticated data.
+
+Note that this request does not fully prevent an attacker from hijacking
+the connection, in the sense that it does not prevent hijacking the
+connection between the initial authentication and the
+@code{Gssapi-authenticate} request.
+
+@item Set @var{variable}=@var{value} \n
+Response expected: no.
+Set a user variable @var{variable} to @var{value}.
+The @code{Root} request need not have been previously sent.
+
+@item Hostname @var{hostname} \n
+Response expected: no. Set the client hostname for an upcoming @code{edit}
+request.
+
+@item LocalDir @var{hostname} \n
+Response expected: no. Set the local client directory name for an upcoming
+@code{edit} request.
+
+@item expand-modules \n
+Response expected: yes. Expand the modules which are specified in the
+arguments. Returns the data in @code{Module-expansion} responses. Note
+that the server can assume that this is checkout or export, not rtag or
+rdiff; the latter do not access the working directory and thus have no
+need to expand modules on the client side.
+
+Expand may not be the best word for what this request does. It does not
+necessarily tell you all the files contained in a module, for example.
+Basically it is a way of telling you which working directories the
+server needs to know about in order to handle a checkout of the
+specified modules.
+
+For example, suppose that the server has a module defined by
+
+@example
+aliasmodule -a 1dir
+@end example
+
+That is, one can check out @code{aliasmodule} and it will take
+@code{1dir} in the repository and check it out to @code{1dir} in the
+working directory. Now suppose the client already has this module
+checked out and is planning on using the @code{co} request to update it.
+Without using @code{expand-modules}, the client would have two bad
+choices: it could either send information about @emph{all} working
+directories under the current directory, which could be unnecessarily
+slow, or it could be ignorant of the fact that @code{aliasmodule} stands
+for @code{1dir}, and neglect to send information for @code{1dir}, which
+would lead to incorrect operation.
+@c Those don't really seem like the only two options. I mean, what
+@c about keeping track of the correspondence from when we first checked
+@c out a fresh directory? Not that the CVS client does this, or that
+@c I've really thought about whether it would be a good idea...
+
+With @code{expand-modules}, the client would first ask for the module to
+be expanded:
+
+@example
+C: Root /home/kingdon/zwork/cvsroot
+. . .
+C: Argument aliasmodule
+C: Directory .
+C: .
+C: expand-modules
+S: Module-expansion 1dir
+S: ok
+@end example
+
+and then it knows to check the @file{1dir} directory and send
+requests such as @code{Entry} and @code{Modified} for the files in that
+directory.
+
+@item ci \n
+@itemx diff \n
+@itemx list \n
+@itemx tag \n
+@itemx status \n
+@itemx admin \n
+@itemx history \n
+@itemx watchers \n
+@itemx editors \n
+@itemx annotate \n
+Response expected: yes. Actually do a cvs command. This uses any
+previous @code{Argument}, @code{Directory}, @code{Entry}, or
+@code{Modified} requests, if they have been sent. The
+last @code{Directory} sent specifies the working directory at the time
+of the operation. No provision is made for any input from the user.
+This means that @code{ci} must use a @code{-m} argument if it wants to
+specify a log message.
+
+@item log \n
+Response expected: yes. Show information for past revisions. This uses
+any previous @code{Directory}, @code{Entry}, or @code{Modified}
+requests, if they have been sent. The last @code{Directory} sent
+specifies the working directory at the time of the operation. Also uses
+previous @code{Argument}'s of which the canonical forms are the
+following (@sc{cvs} 1.10 and older clients sent what the user specified,
+but clients are encouraged to use the canonical forms and other forms
+are deprecated):
+
+@table @code
+@item -b, -h, -l, -N, -R, -t
+These options go by themselves, one option per @code{Argument} request.
+
+@item -d @var{date1}<@var{date2}
+Select revisions between @var{date1} and @var{date2}. Either date
+may be omitted in which case there is no date limit at that end of the
+range (clients may specify dates such as 1 Jan 1970 or 1 Jan 2038 for
+similar purposes but this is problematic as it makes assumptions about
+what dates the server supports). Dates are in RFC822/1123 format. The
+@samp{-d} is one @code{Argument} request and the date range is a second
+one.
+
+@item -d @var{date1}<=@var{date2}
+Likewise but compare dates for equality.
+
+@item -d @var{singledate}
+Select the single, latest revision dated @var{singledate} or earlier.
+
+To include several date ranges and/or singledates, repeat the @samp{-d}
+option as many times as necessary.
+
+@item -r@var{rev1}:@var{rev2}
+@itemx -r@var{branch}
+@itemx -r@var{branch}.
+@itemx -r
+Specify revisions (note that @var{rev1} or @var{rev2} can be omitted, or
+can refer to branches). Send both the @samp{-r} and the revision
+information in a single @code{Argument} request. To include several
+revision selections, repeat the @samp{-r} option.
+
+@item -s @var{state}
+@itemx -w
+@itemx -w@var{login}
+Select on states or users. To include more than one state or user,
+repeat the option. Send the @samp{-s} option as a separate argument
+from the state being selected. Send the @samp{-w} option as part of the
+same argument as the user being selected.
+@end table
+
+@item co \n
+Response expected: yes. Get files from the repository. This uses any
+previous @code{Argument}, @code{Directory}, @code{Entry}, or
+@code{Modified} requests, if they have been sent. Arguments to this
+command are module names; the client cannot know what directories they
+correspond to except by (1) just sending the @code{co} request, and then
+seeing what directory names the server sends back in its responses, and
+(2) the @code{expand-modules} request.
+
+@item export \n
+Response expected: yes. Get files from the repository. This uses any
+previous @code{Argument}, @code{Directory}, @code{Entry}, or
+@code{Modified} requests, if they have been sent. Arguments to this
+command are module names, as described for the @code{co} request. The
+intention behind this command is that a client can get sources from a
+server without storing CVS information about those sources. That is, a
+client probably should not count on being able to take the entries line
+returned in the @code{Created} response from an @code{export} request
+and send it in a future @code{Entry} request. Note that the entries
+line in the @code{Created} response must indicate whether the file is
+binary or text, so the client can create it correctly.
+
+@item ls \n
+@itemx rannotate \n
+@itemx rdiff \n
+@itemx rlist \n
+@itemx rlog \n
+@itemx rtag \n
+Response expected: yes. Actually do a cvs command. This uses any
+previous @code{Argument} requests, if they have been sent. The client
+should not send @code{Directory}, @code{Entry}, or @code{Modified}
+requests for these commands; they are not used. Arguments to these
+commands are module names, as described for @code{co}. @code{ls} is a
+synonym for @code{rlist}, for compatibility with CVSNT.
+
+@item init @var{root-name} \n
+Response expected: yes. If it doesn't already exist, create a @sc{cvs}
+repository @var{root-name}. Note that @var{root-name} is a local
+directory and @emph{not} a fully qualified @code{CVSROOT} variable.
+The @code{Root} request need not have been previously sent.
+
+@item update \n
+Response expected: yes. Actually do a @code{cvs update} command. This
+uses any previous @code{Argument}, @code{Directory}, @code{Entry},
+or @code{Modified} requests, if they have been sent. The
+last @code{Directory} sent specifies the working directory at the time
+of the operation. The @code{-I} option is not used--files which the
+client can decide whether to ignore are not mentioned and the client
+sends the @code{Questionable} request for others.
+
+@item import \n
+Response expected: yes. Actually do a @code{cvs import} command. This
+uses any previous @code{Argument}, @code{Directory}, @code{Entry}, or
+@code{Modified} requests, if they have been sent. The
+last @code{Directory} sent specifies the working directory at the time
+of the operation - unlike most commands, the repository field of each
+@code{Directory} request is ignored (it merely must point somewhere
+within the root). The files to be imported are sent in @code{Modified}
+requests (files which the client knows should be ignored are not sent;
+the server must still process the CVSROOT/cvsignore file unless -I ! is
+sent). A log message must have been specified with a @code{-m}
+argument.
+
+@item add \n
+Response expected: yes. Add a file or directory. This uses any
+previous @code{Argument}, @code{Directory}, @code{Entry}, or
+@code{Modified} requests, if they have been sent. The
+last @code{Directory} sent specifies the working directory at the time
+of the operation.
+
+To add a directory, send the directory to be added using
+@code{Directory} and @code{Argument} requests. For example:
+
+@example
+C: Root /u/cvsroot
+. . .
+C: Argument nsdir
+C: Directory nsdir
+C: 1dir/nsdir
+C: Directory .
+C: 1dir
+C: add
+S: M Directory /u/cvsroot/1dir/nsdir added to the repository
+S: ok
+@end example
+
+You will notice that the server does not signal to the client in any
+particular way that the directory has been successfully added. The
+client is supposed to just assume that the directory has been added and
+update its records accordingly. Note also that adding a directory is
+immediate; it does not wait until a @code{ci} request as files do.
+
+To add a file, send the file to be added using a @code{Modified}
+request. For example:
+
+@example
+C: Argument nfile
+C: Directory .
+C: 1dir
+C: Modified nfile
+C: u=rw,g=r,o=r
+C: 6
+C: hello
+C: add
+S: E cvs server: scheduling file `nfile' for addition
+S: Mode u=rw,g=r,o=r
+S: Checked-in ./
+S: /u/cvsroot/1dir/nfile
+S: /nfile/0///
+S: E cvs server: use 'cvs commit' to add this file permanently
+S: ok
+@end example
+
+Note that the file has not been added to the repository; the only effect
+of a successful @code{add} request, for a file, is to supply the client
+with a new entries line containing @samp{0} to indicate an added file.
+In fact, the client probably could perform this operation without
+contacting the server, although using @code{add} does cause the server
+to perform a few more checks.
+
+The client sends a subsequent @code{ci} to actually add the file to the
+repository.
+
+Another quirk of the @code{add} request is that with CVS 1.9 and older,
+a pathname specified in
+an @code{Argument} request cannot contain @samp{/}. There is no good
+reason for this restriction, and in fact more recent CVS servers don't
+have it.
+But the way to interoperate with the older servers is to ensure that
+all @code{Directory} requests for @code{add} (except those used to add
+directories, as described above), use @samp{.} for
+@var{local-directory}. Specifying another string for
+@var{local-directory} may not get an error, but it will get you strange
+@code{Checked-in} responses from the buggy servers.
+
+@item remove \n
+Response expected: yes. Remove a file. This uses any
+previous @code{Argument}, @code{Directory}, @code{Entry}, or
+@code{Modified} requests, if they have been sent. The
+last @code{Directory} sent specifies the working directory at the time
+of the operation.
+
+Note that this request does not actually do anything to the repository;
+the only effect of a successful @code{remove} request is to supply the
+client with a new entries line containing @samp{-} to indicate a removed
+file. In fact, the client probably could perform this operation without
+contacting the server, although using @code{remove} may cause the server
+to perform a few more checks.
+
+The client sends a subsequent @code{ci} request to actually record the
+removal in the repository.
+
+@item edit \n
+Response expected: yes. Actually do the @code{cvs edit} command. This uses
+any previous @code{Argument}, @code{Directory}, @code{Entry}, @code{LocalDir},
+or @code{Hostname} requests, if they have been sent. Unless the user has
+requested that edits not be granted unless no one else is editing a file, a
+local edit followed by an attempt to send @code{Notify} requests to the
+server is preferred.
+
+@item watch-on \n
+@itemx watch-off \n
+@itemx watch-add \n
+@itemx watch-remove \n
+Response expected: yes. Actually do the @code{cvs watch on}, @code{cvs
+watch off}, @code{cvs watch add}, and @code{cvs watch remove} commands,
+respectively. This uses any previous @code{Argument},
+@code{Directory}, @code{Entry}, or @code{Modified}
+requests, if they have been sent. The last @code{Directory} sent
+specifies the working directory at the time of the operation.
+
+@item release \n
+Response expected: yes. Note that a @code{cvs release} command has
+taken place and update the history file accordingly.
+
+@item global-list-quiet \n
+Response expected: yes. This request is a synonym for noop, but its existance
+notifies the client that a @code{-q} option to @code{list} and @code{rlist}
+will be rejected. This, in a reverse-logic sort of way, is here so that when
+it @emph{isn't} received, as for instance from CVSNT, the client will know that
+the quiet option has to be sent as a command option rather than a global
+option.
+
+@item noop \n
+Response expected: yes. This request is a null command in the sense
+that it doesn't do anything, but merely (as with any other requests
+expecting a response) sends back any responses pertaining to pending
+errors, pending @code{Notified} responses, etc.
+The @code{Root} request need not have been previously sent.
+
+@item update-patches \n
+Response expected: yes.
+This request does not actually do anything. It is used as a signal that
+the server is able to generate patches when given an @code{update}
+request. The client must issue the @code{-u} argument to @code{update}
+in order to receive patches.
+
+@item gzip-file-contents @var{level} \n
+Response expected: no. Note that this request does not follow the
+response convention stated above. @code{Gzip-stream} is suggested
+instead of @code{gzip-file-contents} as it gives better compression; the
+only reason to implement the latter is to provide compression with
+@sc{cvs} 1.8 and earlier. The @code{gzip-file-contents} request asks
+the server to compress files it sends to the client using @code{gzip}
+(RFC1952/1951) compression, using the specified level of compression.
+If this request is not made, the server must not compress files.
+
+This is only a hint to the server. It may still decide (for example, in
+the case of very small files, or files that already appear to be
+compressed) not to do the compression. Compression is indicated by a
+@samp{z} preceding the file length.
+
+Availability of this request in the server indicates to the client that
+it may compress files sent to the server, regardless of whether the
+client actually uses this request.
+
+@item wrapper-sendme-rcsOptions \n
+Response expected: yes.
+Request that the server transmit mappings from filenames to keyword
+expansion modes in @code{Wrapper-rcsOption} responses.
+
+@item version \n
+Response expected: yes.
+Request that the server transmit its version message.
+The @code{Root} request need not have been previously sent.
+
+@item @var{other-request} @var{text} \n
+Response expected: yes.
+Any unrecognized request expects a response, and does not
+contain any additional data. The response will normally be something like
+@samp{error unrecognized request}, but it could be a different error if
+a previous request which doesn't expect a response produced an error.
+@end table
+
+When the client is done, it drops the connection.
+
+@node Response intro
+@section Introduction to Responses
+
+After a command which expects a response, the server sends however many
+of the following responses are appropriate. The server should not send
+data at other times (the current implementation may violate this
+principle in a few minor places, where the server is printing an error
+message and exiting---this should be investigated further).
+
+Any set of responses always ends with @samp{error} or @samp{ok}. This
+indicates that the response is over.
+
+@c "file updating response" and "file update modifying response" are
+@c lame terms (mostly because they are so awkward). Any better ideas?
+The responses @code{Checked-in}, @code{New-entry}, @code{Updated},
+@code{Created}, @code{Update-existing}, @code{Merged}, and
+@code{Patched} are refered to as @dfn{file updating} responses, because
+they change the status of a file in the working directory in some way.
+The responses @code{Mode}, @code{Mod-time}, and @code{Checksum} are
+referred to as @dfn{file update modifying} responses because they modify
+the next file updating response. In no case shall a file update
+modifying response apply to a file updating response other than the next
+one. Nor can the same file update modifying response occur twice for
+a given file updating response (if servers diagnose this problem, it may
+aid in detecting the case where clients send an update modifying
+response without following it by a file updating response).
+
+@node Response pathnames
+@section The "pathname" in responses
+
+Many of the responses contain something called @var{pathname}.
+@c FIXME: should better document when the specified repository needs to
+@c end in "/.".
+The name is somewhat misleading; it actually indicates a pair of
+pathnames. First, a local directory name
+relative to the directory in which the command was given (i.e. the last
+@code{Directory} before the command). Then a linefeed and a repository
+name. Then a slash and the filename (without a @samp{,v} ending).
+
+The repository name may be absolute or relative to the @var{pathname}
+sent with the @code{Root} request. If absolute, the repository name must begin
+with the @var{pathname} sent with the @code{Root} request. Relative or
+absolute, the repository name must specify a path underneath the @code{Root}
+@var{pathname}.
+
+For example, for a file @file{i386.mh}
+which is in the local directory @file{gas.clean/config} and for which
+the repository name is @file{devo/gas/config}:
+
+@example
+gas.clean/config/
+devo/gas/config/i386.mh
+@end example
+
+If the server wants to tell the client to create a directory, then it
+merely uses the directory in any response, as described above, and the
+client should create the directory if it does not exist. Note that this
+should only be done one directory at a time, in order to permit the
+client to correctly store the repository for each directory. Servers
+can use requests such as @code{Clear-sticky},
+@code{Clear-static-directory}, or any other requests, to create
+directories.
+@c FIXME: Need example here of how "repository" needs to be sent for
+@c each directory, and cannot be correctly deduced from, say, the most
+@c deeply nested directory.
+
+Some server
+implementations may poorly distinguish between a directory which should
+not exist and a directory which contains no files; in order to refrain
+from creating empty directories a client should both send the @samp{-P}
+option to @code{update} or @code{co}, and should also detect the case in
+which the server asks to create a directory but not any files within it
+(in that case the client should remove the directory or refrain from
+creating it in the first place). Note that servers could clean this up
+greatly by only telling the client to create directories if the
+directory in question should exist, but until servers do this, clients
+will need to offer the @samp{-P} behavior described above.
+
+@node Responses
+@section Responses
+
+Here are the responses:
+
+@table @code
+@item Valid-requests @var{request-list} \n
+Indicate what requests the server will accept. @var{request-list}
+is a space separated list of tokens. If the server supports sending
+patches, it will include @samp{update-patches} in this list. The
+@samp{update-patches} request does not actually do anything.
+
+@item Force-gzip \n
+Response expected: no.
+Indicates that the server requires compression. The client must send a
+@code{Gzip-stream} request, though the requested @var{level} may be @samp{0}.
+
+@item Referrer @var{CVSROOT}
+Request that the client store @var{CVSROOT} as the name of this server and that
+this name be passed via a @code{Referrer} @emph{request} to any subsequent
+servers contacted as a result of a @code{Redirect} response. This can be
+useful to allow the secondary administrator to configure the @code{CVSROOT} the
+primary should use to update the secondary in case the client uses a
+non-standard name or even a name that is unique to the client for some reason.
+
+@item Redirect @var{CVSROOT}
+Request that the client redirect its connection to @var{CVSROOT} and begin
+again. This response is only valid in response to a @code{Command-prep}
+request. If a client receives this response, it is expected to notify the
+write server it subsequently contacts of the CVSROOT of the server which
+redirected it using the @samp{Referrer} request. This information makes it
+possible for primary servers to update the client's mirror first, hopefully
+minimizing race conditions on subsequent updates from the same client.
+
+@item Checked-in @var{pathname} \n
+Additional data: New Entries line, \n. This means a file @var{pathname}
+has been successfully operated on (checked in, added, etc.). name in
+the Entries line is the same as the last component of @var{pathname}.
+
+@item New-entry @var{pathname} \n
+Additional data: New Entries line, \n. Like @code{Checked-in}, but the
+file is not up to date.
+
+@item Updated @var{pathname} \n
+Additional data: New Entries line, \n, mode, \n, file transmission. A
+new copy of the file is enclosed. This is used for a new revision of an
+existing file, or for a new file, or for any other case in which the
+local (client-side) copy of the file needs to be updated, and after
+being updated it will be up to date. If any directory in pathname does
+not exist, create it. This response is not used if @code{Created} and
+@code{Update-existing} are supported.
+
+@item Created @var{pathname} \n
+This is just like @code{Updated} and takes the same additional data, but
+is used only if no @code{Entry}, @code{Modified}, or
+@code{Unchanged} request has been sent for the file in question. The
+distinction between @code{Created} and @code{Update-existing} is so
+that the client can give an error message in several cases: (1) there is
+a file in the working directory, but not one for which @code{Entry},
+@code{Modified}, or @code{Unchanged} was sent (for example, a file which
+was ignored, or a file for which @code{Questionable} was sent), (2)
+there is a file in the working directory whose name differs from the one
+mentioned in @code{Created} in ways that the client is unable to use to
+distinguish files. For example, the client is case-insensitive and the
+names differ only in case.
+
+@item Update-existing @var{pathname} \n
+This is just like @code{Updated} and takes the same additional data, but
+is used only if a @code{Entry}, @code{Modified}, or @code{Unchanged}
+request has been sent for the file in question.
+
+This response, or @code{Merged}, indicates that the server has
+determined that it is OK to overwrite the previous contents of the file
+specified by @var{pathname}. Provided that the client has correctly
+sent @code{Modified} or @code{Is-modified} requests for a modified file,
+and the file was not modified while CVS was running, the server can
+ensure that a user's modifications are not lost.
+
+@item Merged @var{pathname} \n
+This is just like @code{Updated} and takes the same additional data,
+with the one difference that after the new copy of the file is enclosed,
+it will still not be up to date. Used for the results of a merge, with
+or without conflicts.
+
+It is useful to preserve an copy of what the file looked like before the
+merge. This is basically handled by the server; before sending
+@code{Merged} it will send a @code{Copy-file} response. For example, if
+the file is @file{aa} and it derives from revision 1.3, the
+@code{Copy-file} response will tell the client to copy @file{aa} to
+@file{.#aa.1.3}. It is up to the client to decide how long to keep this
+file around; traditionally clients have left it around forever, thus
+letting the user clean it up as desired. But another answer, such as
+until the next commit, might be preferable.
+
+@item Rcs-diff @var{pathname} \n
+This is just like @code{Updated} and takes the same additional data,
+with the one difference that instead of sending a new copy of the file,
+the server sends an RCS change text. This change text is produced by
+@samp{diff -n} (the GNU diff @samp{-a} option may also be used). The
+client must apply this change text to the existing file. This will only
+be used when the client has an exact copy of an earlier revision of a
+file. This response is only used if the @code{update} command is given
+the @samp{-u} argument.
+
+@item Patched @var{pathname} \n
+This is just like @code{Rcs-diff} and takes the same additional data,
+except that it sends a standard patch rather than an RCS change text.
+The patch is produced by @samp{diff -c} for @sc{cvs} 1.6 and later (see
+POSIX.2 for a description of this format), or @samp{diff -u} for
+previous versions of @sc{cvs}; clients are encouraged to accept either
+format. Like @code{Rcs-diff}, this response is only used if the
+@code{update} command is given the @samp{-u} argument.
+
+The @code{Patched} response is deprecated in favor of the
+@code{Rcs-diff} response. However, older clients (CVS 1.9 and earlier)
+only support @code{Patched}.
+
+@item Edit-file @var{pathname} \n
+Do the client-side portion of editing a file.
+
+@item Mode @var{mode} \n
+This @var{mode} applies to the next file mentioned in
+@code{Checked-in}. @code{Mode} is a file update modifying response
+as described in @ref{Response intro}.
+
+@item Mod-time @var{time} \n
+Set the modification time of the next file sent to @var{time}.
+@code{Mod-time} is a file update modifying response
+as described in @ref{Response intro}.
+The
+@var{time} is in the format specified by RFC822 as modified by RFC1123.
+The server may specify any timezone it chooses; clients will want to
+convert that to their own timezone as appropriate. An example of this
+format is:
+
+@example
+26 May 1997 13:01:40 -0400
+@end example
+
+There is no requirement that the client and server clocks be
+synchronized. The server just sends its recommendation for a timestamp
+(based on its own clock, presumably), and the client should just believe
+it (this means that the time might be in the future, for example).
+
+If the server does not send @code{Mod-time} for a given file, the client
+should pick a modification time in the usual way (usually, just let the
+operating system set the modification time to the time that the CVS
+command is running).
+
+@item Checksum @var{checksum}\n
+The @var{checksum} applies to the next file sent (that is,
+@code{Checksum} is a file update modifying response
+as described in @ref{Response intro}).
+In the case of
+@code{Patched}, the checksum applies to the file after being patched,
+not to the patch itself. The client should compute the checksum itself,
+after receiving the file or patch, and signal an error if the checksums
+do not match. The checksum is the 128 bit MD5 checksum represented as
+32 hex digits (MD5 is described in RFC1321).
+This response is optional, and is only used if the
+client supports it (as judged by the @code{Valid-responses} request).
+
+@item Copy-file @var{pathname} \n
+Additional data: @var{newname} \n. Copy file @var{pathname} to
+@var{newname} in the same directory where it already is. This does not
+affect @code{CVS/Entries}.
+
+This can optionally be implemented as a rename instead of a copy. The
+only use for it which currently has been identified is prior to a
+@code{Merged} response as described under @code{Merged}. Clients can
+probably assume that is how it is being used, if they want to worry
+about things like how long to keep the @var{newname} file around.
+
+@item Removed @var{pathname} \n
+The file has been removed from the repository (this is the case where
+cvs prints @samp{file foobar.c is no longer pertinent}).
+
+@item Remove-entry @var{pathname} \n
+The file needs its entry removed from @code{CVS/Entries}, but the file
+itself is already gone (this happens in response to a @code{ci} request
+which involves committing the removal of a file).
+
+@item Set-static-directory @var{pathname} \n
+This instructs the client to set the @code{Entries.Static} flag, which
+it should then send back to the server in a @code{Static-directory}
+request whenever the directory is operated on. @var{pathname} ends in a
+slash; its purpose is to specify a directory, not a file within a
+directory.
+
+@item Clear-static-directory @var{pathname} \n
+Like @code{Set-static-directory}, but clear, not set, the flag.
+
+@item Set-sticky @var{pathname} \n
+Additional data: @var{tagspec} \n. Tell the client to set a sticky tag
+or date, which should be supplied with the @code{Sticky} request for
+future operations. @var{pathname} ends in a slash; its purpose is to
+specify a directory, not a file within a directory. The client should
+store @var{tagspec} and pass it back to the server as-is, to allow for
+future expansion. The first character of @var{tagspec} is @samp{T} for
+a tag, @samp{D} for a date, or something else for future expansion. The
+remainder of @var{tagspec} contains the actual tag or date.
+
+@item Clear-sticky @var{pathname} \n
+Clear any sticky tag or date set by @code{Set-sticky}.
+
+@item Template @var{pathname} \n
+Additional data: file transmission (note: compressed file transmissions
+are not supported). @var{pathname} ends in a slash; its purpose is to
+specify a directory, not a file within a directory. Tell the client to
+store the file transmission as the template log message, and then use
+that template in the future when prompting the user for a log message.
+
+@item Set-checkin-prog @var{dir} \n
+Additional data: @var{prog} \n. Tell the client to set a checkin
+program, which should be supplied with the @code{Checkin-prog} request
+for future operations.
+
+@item Set-update-prog @var{dir} \n
+Additional data: @var{prog} \n. Tell the client to set an update
+program, which should be supplied with the @code{Update-prog} request
+for future operations.
+
+@item Notified @var{pathname} \n
+Indicate to the client that the notification for @var{pathname} has been
+done. There should be one such response for every @code{Notify}
+request; if there are several @code{Notify} requests for a single file,
+the requests should be processed in order; the first @code{Notified}
+response pertains to the first @code{Notify} request, etc.
+
+@item Module-expansion @var{pathname} \n
+Return a file or directory
+which is included in a particular module. @var{pathname} is relative
+to cvsroot, unlike most pathnames in responses. @var{pathname} should
+be used to look and see whether some or all of the module exists on
+the client side; it is not necessarily suitable for passing as an
+argument to a @code{co} request (for example, if the modules file
+contains the @samp{-d} option, it will be the directory specified with
+@samp{-d}, not the name of the module).
+
+@item Wrapper-rcsOption @var{pattern} -k '@var{option}' \n
+Transmit to the client a filename pattern which implies a certain
+keyword expansion mode. The @var{pattern} is a wildcard pattern (for
+example, @samp{*.exe}. The @var{option} is @samp{b} for binary, and so
+on. Note that although the syntax happens to resemble the syntax in
+certain CVS configuration files, it is more constrained; there must be
+exactly one space between @var{pattern} and @samp{-k} and exactly one
+space between @samp{-k} and @samp{'}, and no string is permitted in
+place of @samp{-k} (extensions should be done with new responses, not by
+extending this one, for graceful handling of @code{Valid-responses}).
+
+@item M @var{text} \n
+A one-line message for the user.
+Note that the format of @var{text} is not designed for machine parsing.
+Although sometimes scripts and clients will have little choice, the
+exact text which is output is subject to vary at the discretion of the
+server and the example output given in this document is just that,
+example output. Servers are encouraged to use the @samp{MT} response,
+and future versions of this document will hopefully standardize more of
+the @samp{MT} tags; see @ref{Text tags}.
+
+@item Mbinary \n
+Additional data: file transmission (note: compressed file transmissions
+are not supported). This is like @samp{M}, except the contents of the
+file transmission are binary and should be copied to standard output
+without translation to local text file conventions. To transmit a text
+file to standard output, servers should use a series of @samp{M} requests.
+
+@item E @var{text} \n
+Same as @code{M} but send to stderr not stdout.
+
+@item F \n
+@c FIXME: The second sentence, defining "flush", is somewhat off the top
+@c of my head. Is there some text we can steal from ANSI C or someplace
+@c which is more carefully thought out?
+Flush stderr. That is, make it possible for the user to see what has
+been written to stderr (it is up to the implementation to decide exactly
+how far it should go to ensure this).
+
+@item MT @var{tagname} @var{data} \n
+
+This response provides for tagged text. It is similar to
+SGML/HTML/XML in that the data is structured and a naive application
+can also make some sense of it without understanding the structure.
+The syntax is not SGML-like, however, in order to fit into the CVS
+protocol better and (more importantly) to make it easier to parse,
+especially in a language like perl or awk.
+
+The @var{tagname} can have several forms. If it starts with @samp{a}
+to @samp{z} or @samp{A} to @samp{Z}, then it represents tagged text.
+If the implementation recognizes @var{tagname}, then it may interpret
+@var{data} in some particular fashion. If the implementation does not
+recognize @var{tagname}, then it should simply treat @var{data} as
+text to be sent to the user (similar to an @samp{M} response). There
+are two tags which are general purpose. The @samp{text} tag is
+similar to an unrecognized tag in that it provides text which will
+ordinarily be sent to the user. The @samp{newline} tag is used
+without @var{data} and indicates that a newline will ordinarily be
+sent to the user (there is no provision for embedding newlines in the
+@var{data} of other tagged text responses).
+
+If @var{tagname} starts with @samp{+} it indicates a start tag and if
+it starts with @samp{-} it indicates an end tag. The remainder of
+@var{tagname} should be the same for matching start and end tags, and
+tags should be nested (for example one could have tags in the
+following order @code{+bold} @code{+italic} @code{text} @code{-italic}
+@code{-bold} but not @code{+bold} @code{+italic} @code{text}
+@code{-bold} @code{-italic}). A particular start and end tag may be
+documented to constrain the tagged text responses which are valid
+between them.
+
+Note that if @var{data} is present there will always be exactly one
+space between @var{tagname} and @var{data}; if there is more than one
+space, then the spaces beyond the first are part of @var{data}.
+
+Here is an example of some tagged text responses. Note that there is
+a trailing space after @samp{Checking in} and @samp{initial revision:}
+and there are two trailing spaces after @samp{<--}. Such trailing
+spaces are, of course, part of @var{data}.
+
+@example
+MT +checking-in
+MT text Checking in
+MT fname gz.tst
+MT text ;
+MT newline
+MT rcsfile /home/kingdon/zwork/cvsroot/foo/gz.tst,v
+MT text <--
+MT fname gz.tst
+MT newline
+MT text initial revision:
+MT init-rev 1.1
+MT newline
+MT text done
+MT newline
+MT -checking-in
+@end example
+
+If the client does not support the @samp{MT} response, the same
+responses might be sent as:
+
+@example
+M Checking in gz.tst;
+M /home/kingdon/zwork/cvsroot/foo/gz.tst,v <-- gz.tst
+M initial revision: 1.1
+M done
+@end example
+
+For a list of specific tags, see @ref{Text tags}.
+
+@item error @var{errno-code} @samp{ } @var{text} \n
+The command completed with an error. @var{errno-code} is a symbolic
+error code (e.g. @code{ENOENT}); if the server doesn't support this
+feature, or if it's not appropriate for this particular message, it just
+omits the errno-code (in that case there are two spaces after
+@samp{error}). Text is an error message such as that provided by
+strerror(), or any other message the server wants to use.
+The @var{text} is like the @code{M} response, in the sense that it is
+not particularly intended to be machine-parsed; servers may wish to
+print an error message with @code{MT} responses, and then issue a
+@code{error} response without @var{text} (although it should be noted
+that @code{MT} currently has no way of flagging the output as intended
+for standard error, the way that the @code{E} response does).
+
+@item ok \n
+The command completed successfully.
+@end table
+
+@node Text tags
+@section Tags for the MT tagged text response
+
+The @code{MT} response, as described in @ref{Responses}, offers a
+way for the server to send tagged text to the client. This section
+describes specific tags. The intention is to update this section as
+servers add new tags.
+
+In the following descriptions, @code{text} and @code{newline} tags are
+omitted. Such tags contain information which is intended for users (or
+to be discarded), and are subject to change at the whim of the server.
+To avoid being vulnerable to such whim, clients should look for the tags
+listed here, not @code{text}, @code{newline}, or other tags.
+
+The following tag means to indicate to the user that a file has been
+updated. It is more or less redundant with the @code{Created} and
+@code{Update-existing} responses, but we don't try to specify here
+whether it occurs in exactly the same circumstances as @code{Created}
+and @code{Update-existing}. The @var{name} is the pathname of the file
+being updated relative to the directory in which the command is
+occurring (that is, the last @code{Directory} request which is sent
+before the command).
+
+@example
+MT +updated
+MT fname @var{name}
+MT -updated
+@end example
+
+The @code{importmergecmd} tag is used when doing an import which has
+conflicts, or when doing an import with the @samp{-X} flag.
+The client can use it to report how to merge in the newly
+imported changes. The @var{count} is the number of conflicts, or the
+string @code{No} if no conflicts occurred. (The latter will only be
+sent for imports run with the @samp{-X} flag.) The
+newly imported changes can be merged by running the following command:
+@smallexample
+cvs checkout -j @var{tag1} -j @var{tag2} @var{repository}
+@end smallexample
+
+@example
+MT +importmergecmd
+MT conflicts @var{count}
+MT mergetag1 @var{tag1}
+MT mergetag2 @var{tag2}
+MT repository @var{repository}
+MT -importmergecmd
+@end example
+
+@node Example
+@section Example
+
+@c The C:/S: convention is in imitation of RFC1869 (and presumably
+@c other RFC's). In other formatting concerns, we might want to think
+@c about whether there is an easy way to provide RFC1543 formatting
+@c (without negating the advantages of texinfo), and whether we should
+@c use RFC2234 BNF (I fear that would be less clear than
+@c what we do now, however). Plus what about RFC2119 terminology (MUST,
+@c SHOULD, &c) or ISO terminology (shall, should, or whatever they are)?
+Here is an example; lines are prefixed by @samp{C: } to indicate the
+client sends them or @samp{S: } to indicate the server sends them.
+
+The client starts by connecting, sending the root, and completing the
+protocol negotiation. In actual practice the lists of valid responses
+and requests would be longer.
+@c The reason that we artificially shorten the lists is to avoid phony
+@c line breaks. Any better solutions?
+@c Other than that, this exchange is taken verbatim from the data
+@c exchanged by CVS (as of Nov 1996). That is why some of the requests and
+@c reponses are not quite what you would pick for pedagogical purposes.
+
+@example
+C: Root /u/cvsroot
+C: Valid-responses ok error Checked-in M E
+C: valid-requests
+S: Valid-requests Root Directory Entry Modified Argument Argumentx ci co
+S: ok
+C: UseUnchanged
+@end example
+
+The client wants to check out the @code{supermunger} module into a fresh
+working directory. Therefore it first expands the @code{supermunger}
+module; this step would be omitted if the client was operating on a
+directory rather than a module.
+@c Why does it send Directory here? The description of expand-modules
+@c doesn't really say much of anything about what use, if any, it makes of
+@c Directory and similar requests sent previously.
+
+@example
+C: Argument supermunger
+C: Directory .
+C: .
+C: expand-modules
+@end example
+
+The server replies that the @code{supermunger} module expands to the
+directory @code{supermunger} (the simplest case):
+
+@example
+S: Module-expansion supermunger
+S: ok
+@end example
+
+The client then proceeds to check out the directory. The fact that it
+sends only a single @code{Directory} request which specifies @samp{.}
+for the working directory means that there is not already a
+@code{supermunger} directory on the client.
+@c What is -N doing here?
+
+@example
+C: Argument -N
+C: Argument supermunger
+C: Directory .
+C: .
+C: co
+@end example
+
+The server replies with the requested files. In this example, there is
+only one file, @file{mungeall.c}. The @code{Clear-sticky} and
+@code{Clear-static-directory} requests are sent by the current
+implementation but they have no effect because the default is for those
+settings to be clear when a directory is newly created.
+
+@example
+S: Clear-sticky supermunger/
+S: /u/cvsroot/supermunger/
+S: Clear-static-directory supermunger/
+S: /u/cvsroot/supermunger/
+S: E cvs server: Updating supermunger
+S: M U supermunger/mungeall.c
+S: Created supermunger/
+S: /u/cvsroot/supermunger/mungeall.c
+S: /mungeall.c/1.1///
+S: u=rw,g=r,o=r
+S: 26
+S: int mein () @{ abort (); @}
+S: ok
+@end example
+
+The current client implementation would break the connection here and make a
+new connection for the next command. However, the protocol allows it
+to keep the connection open and continue, which is what we show here.
+
+After the user modifies the file and instructs the client to check it
+back in. The client sends arguments to specify the log message and file
+to check in:
+
+@example
+C: Argument -m
+C: Argument Well, you see, it took me hours and hours to find
+C: Argumentx this typo and I searched and searched and eventually
+C: Argumentx had to ask John for help.
+C: Argument mungeall.c
+@end example
+
+It also sends information about the contents of the working directory,
+including the new contents of the modified file. Note that the user has
+changed into the @file{supermunger} directory before executing this
+command; the top level directory is a user-visible concept because the
+server should print filenames in @code{M} and @code{E} responses
+relative to that directory.
+@c We are waving our hands about the order of the requests. "Directory"
+@c and "Argument" can be in any order, but this probably isn't specified
+@c very well.
+
+@example
+C: Directory .
+C: supermunger
+C: Entry /mungeall.c/1.1///
+C: Modified mungeall.c
+C: u=rw,g=r,o=r
+C: 26
+C: int main () @{ abort (); @}
+@end example
+
+And finally, the client issues the checkin command (which makes use of
+the data just sent):
+
+@example
+C: ci
+@end example
+
+And the server tells the client that the checkin succeeded:
+
+@example
+S: M Checking in mungeall.c;
+S: E /u/cvsroot/supermunger/mungeall.c,v <-- mungeall.c
+S: E new revision: 1.2; previous revision: 1.1
+S: E done
+S: Mode u=rw,g=r,o=r
+S: Checked-in ./
+S: /u/cvsroot/supermunger/mungeall.c
+S: /mungeall.c/1.2///
+S: ok
+@end example
+
+@node Requirements
+@section Required versus optional parts of the protocol
+
+The following are part of every known implementation of the CVS protocol
+(except obsolete, pre-1.5, versions of CVS) and it is considered
+reasonable behavior to completely fail to work if you are connected with
+an implementation which attempts to not support them. Requests:
+@code{Root}, @code{Valid-responses}, @code{valid-requests},
+@code{Directory}, @code{Entry}, @code{Modified}, @code{Unchanged},
+@code{Argument}, @code{Argumentx}, @code{ci}, @code{co}, @code{update}.
+Responses: @code{ok}, @code{error}, @code{Valid-requests},
+@code{Checked-in}, @code{Updated}, @code{Merged}, @code{Removed},
+@code{M}, @code{E}.
+
+A server need not implement @code{Repository}, but in order to interoperate
+with CVS 1.5 through 1.9 it must claim to implement it (in
+@code{Valid-requests}). The client will not actually send the request.
+
+@node Obsolete
+@section Obsolete protocol elements
+
+This section briefly describes protocol elements which are obsolete.
+There is no attempt to document them in full detail.
+
+There was a @code{Repository} request which was like @code{Directory}
+except it only provided @var{repository}, and the local directory was
+assumed to be similarly named.
+
+If the @code{UseUnchanged} request was not sent, there was a @code{Lost}
+request which was sent to indicate that a file did not exist in the
+working directory, and the meaning of sending @code{Entries} without
+@code{Lost} or @code{Modified} was different. All current clients (CVS
+1.5 and later) will send @code{UseUnchanged} if it is supported.
+
+@node Protocol Notes
+@chapter Notes on the Protocol
+
+A number of enhancements are possible. Also see the file @sc{todo} in
+the @sc{cvs} source distribution, which has further ideas concerning
+various aspects of @sc{cvs}, some of which impact the protocol.
+Similarly, the @url{http://www.nongnu.org/cvs/} site, in particular the
+@cite{Development} pages.
+
+@itemize @bullet
+@item
+The @code{Modified} request could be speeded up by sending diffs rather
+than entire files. The client would need some way to keep the version
+of the file which was originally checked out; probably requiring the use
+of "cvs edit" in this case is the most sensible course (the "cvs edit"
+could be handled by a package like VC for emacs). This would also allow
+local operation of @code{cvs diff} without arguments.
+
+@item
+The fact that @code{pserver} requires an extra network turnaround in
+order to perform authentication would be nice to avoid. This relates to
+the issue of reporting errors; probably the clean solution is to defer
+the error until the client has issued a request which expects a
+response. To some extent this might relate to the next item (in terms
+of how easy it is to skip a whole bunch of requests until we get to one
+that expects a response). I know that the kerberos code doesn't wait in
+this fashion, but that probably can cause network deadlocks and perhaps
+future problems running over a transport which is more transaction
+oriented than TCP. On the other hand I'm not sure it is wise to make
+the client conduct a lengthy upload only to find there is an
+authentication failure.
+
+@item
+The protocol uses an extra network turnaround for protocol negotiation
+(@code{valid-requests}). It might be nice to avoid this by having the
+client be able to send requests and tell the server to ignore them if
+they are unrecognized (different requests could produce a fatal error if
+unrecognized). To do this there should be a standard syntax for
+requests. For example, perhaps all future requests should be a single
+line, with mechanisms analogous to @code{Argumentx}, or several requests
+working together, to provide greater amounts of information. Or there
+might be a standard mechanism for counted data (analogous to that used
+by @code{Modified}) or continuation lines (like a generalized
+@code{Argumentx}). It would be useful to compare what HTTP is planning
+in this area; last I looked they were contemplating something called
+Protocol Extension Protocol but I haven't looked at the relevant IETF
+documents in any detail. Obviously, we want something as simple as
+possible (but no simpler).
+
+@item
+The scrambling algorithm in the CVS client and server actually support
+more characters than those documented in @ref{Password scrambling}.
+Someday we are going to either have to document them all (but this is
+not as easy as it may look, see below), or (gradually and with adequate
+process) phase out the support for other characters in the CVS
+implementation. This business of having the feature partly undocumented
+isn't a desirable state long-term.
+
+The problem with documenting other characters is that unless we know
+what character set is in use, there is no way to make a password
+portable from one system to another. For example, a with a circle on
+top might have different encodings in different character sets.
+
+It @emph{almost} works to say that the client picks an arbitrary,
+unknown character set (indeed, having the CVS client know what character
+set the user has in mind is a hard problem otherwise), and scrambles
+according to a certain octet<->octet mapping. There are two problems
+with this. One is that the protocol has no way to transmit character 10
+decimal (linefeed), and the current server and clients have no way to
+handle 0 decimal (NUL). This may cause problems with certain multibyte
+character sets, in which octets 10 and 0 will appear in the middle of
+other characters. The other problem, which is more minor and possibly
+not worth worrying about, is that someone can type a password on one
+system and then go to another system which uses a different encoding for
+the same characters, and have their password not work.
+
+The restriction to the ISO646 invariant subset is the best approach for
+strings which are not particularly significant to users. Passwords are
+visible enough that this is somewhat doubtful as applied here. ISO646
+does, however, have the virtue (!?) of offending everyone. It is easy
+to say "But the $ is right on people's keyboards! Surely we can't
+forbid that". From a human factors point of view, that makes quite a
+bit of sense. The contrary argument, of course, is that a with a circle
+on top, or some of the characters poorly handled by Unicode, are on
+@emph{someone}'s keyboard.
+
+@end itemize
+
+@bye
diff --git a/doc/getdate-cvs.texi b/doc/getdate-cvs.texi
new file mode 100644
index 0000000..e4fb6fe
--- /dev/null
+++ b/doc/getdate-cvs.texi
@@ -0,0 +1,554 @@
+@c This file is generated via a rule in Makefile.am from the
+@c getdate.texi file.
+@c
+@c *** DO NOT EDIT THIS FILE DIRECTLY ***
+@c
+@c Edit getdate.texi instead.
+
+@c GNU date syntax documentation
+
+@c Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+@c 2003, 2004, 2005 Free Software Foundation, Inc.
+
+@c Permission is granted to copy, distribute and/or modify this document
+@c under the terms of the GNU Free Documentation License, Version 1.1 or
+@c any later version published by the Free Software Foundation; with no
+@c Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+@c Texts. A copy of the license is included in the ``GNU Free
+@c Documentation License'' file as part of this distribution.
+
+@node Date input formats
+@appendixsec Date input formats
+
+@cindex date input formats
+@findex get_date
+
+First, a quote:
+
+@quotation
+Our units of temporal measurement, from seconds on up to months, are so
+complicated, asymmetrical and disjunctive so as to make coherent mental
+reckoning in time all but impossible. Indeed, had some tyrannical god
+contrived to enslave our minds to time, to make it all but impossible
+for us to escape subjection to sodden routines and unpleasant surprises,
+he could hardly have done better than handing down our present system.
+It is like a set of trapezoidal building blocks, with no vertical or
+horizontal surfaces, like a language in which the simplest thought
+demands ornate constructions, useless particles and lengthy
+circumlocutions. Unlike the more successful patterns of language and
+science, which enable us to face experience boldly or at least
+level-headedly, our system of temporal calculation silently and
+persistently encourages our terror of time.
+
+@dots{} It is as though architects had to measure length in feet, width
+in meters and height in ells; as though basic instruction manuals
+demanded a knowledge of five different languages. It is no wonder then
+that we often look into our own immediate past or future, last Tuesday
+or a week from Sunday, with feelings of helpless confusion. @dots{}
+
+--- Robert Grudin, @cite{Time and the Art of Living}.
+@end quotation
+
+This section describes the textual date representations that @sc{gnu}
+programs accept. These are the strings you, as a user, can supply as
+arguments to the various programs. The C interface (via the
+@code{get_date} function) is not described here.
+
+@menu
+* General date syntax:: Common rules.
+* Calendar date items:: 19 Dec 1994.
+* Time of day items:: 9:20pm.
+* Time zone items:: @sc{est}, @sc{pdt}, @sc{gmt}.
+* Day of week items:: Monday and others.
+* Relative items in date strings:: next tuesday, 2 years ago.
+* Pure numbers in date strings:: 19931219, 1440.
+* Seconds since the Epoch:: @@1078100502.
+* Specifying time zone rules:: TZ="America/New_York", TZ="UTC0".
+* Authors of get_date:: Bellovin, Eggert, Salz, Berets, et al.
+@end menu
+
+
+@node General date syntax
+@appendixsubsec General date syntax
+
+@cindex general date syntax
+
+@cindex items in date strings
+A @dfn{date} is a string, possibly empty, containing many items
+separated by whitespace. The whitespace may be omitted when no
+ambiguity arises. The empty string means the beginning of today (i.e.,
+midnight). Order of the items is immaterial. A date string may contain
+many flavors of items:
+
+@itemize @bullet
+@item calendar date items
+@item time of day items
+@item time zone items
+@item day of the week items
+@item relative items
+@item pure numbers.
+@end itemize
+
+@noindent We describe each of these item types in turn, below.
+
+@cindex numbers, written-out
+@cindex ordinal numbers
+@findex first @r{in date strings}
+@findex next @r{in date strings}
+@findex last @r{in date strings}
+A few ordinal numbers may be written out in words in some contexts. This is
+most useful for specifying day of the week items or relative items (see
+below). Among the most commonly used ordinal numbers, the word
+@samp{last} stands for @math{-1}, @samp{this} stands for 0, and
+@samp{first} and @samp{next} both stand for 1. Because the word
+@samp{second} stands for the unit of time there is no way to write the
+ordinal number 2, but for convenience @samp{third} stands for 3,
+@samp{fourth} for 4, @samp{fifth} for 5,
+@samp{sixth} for 6, @samp{seventh} for 7, @samp{eighth} for 8,
+@samp{ninth} for 9, @samp{tenth} for 10, @samp{eleventh} for 11 and
+@samp{twelfth} for 12.
+
+@cindex months, written-out
+When a month is written this way, it is still considered to be written
+numerically, instead of being ``spelled in full''; this changes the
+allowed strings.
+
+@cindex language, in dates
+In the current implementation, only English is supported for words and
+abbreviations like @samp{AM}, @samp{DST}, @samp{EST}, @samp{first},
+@samp{January}, @samp{Sunday}, @samp{tomorrow}, and @samp{year}.
+
+@cindex language, in dates
+@cindex time zone item
+The output of the @command{date} command
+is not always acceptable as a date string,
+not only because of the language problem, but also because there is no
+standard meaning for time zone items like @samp{IST}. When using
+@command{date} to generate a date string intended to be parsed later,
+specify a date format that is independent of language and that does not
+use time zone items other than @samp{UTC} and @samp{Z}. Here are some
+ways to do this:
+
+@example
+$ LC_ALL=C TZ=UTC0 date
+Mon Mar 1 00:21:42 UTC 2004
+$ TZ=UTC0 date +'%Y-%m-%d %H:%M:%SZ'
+2004-03-01 00:21:42Z
+$ date --iso-8601=ns | tr T ' ' # --iso-8601 is a GNU extension.
+2004-02-29 16:21:42,692722128-0800
+$ date --rfc-2822 # a GNU extension
+Sun, 29 Feb 2004 16:21:42 -0800
+$ date +'%Y-%m-%d %H:%M:%S %z' # %z is a GNU extension.
+2004-02-29 16:21:42 -0800
+$ date +'@@%s.%N' # %s and %N are GNU extensions.
+@@1078100502.692722128
+@end example
+
+@cindex case, ignored in dates
+@cindex comments, in dates
+Alphabetic case is completely ignored in dates. Comments may be introduced
+between round parentheses, as long as included parentheses are properly
+nested. Hyphens not followed by a digit are currently ignored. Leading
+zeros on numbers are ignored.
+
+
+@node Calendar date items
+@appendixsubsec Calendar date items
+
+@cindex calendar date item
+
+A @dfn{calendar date item} specifies a day of the year. It is
+specified differently, depending on whether the month is specified
+numerically or literally. All these strings specify the same calendar date:
+
+@example
+1972-09-24 # @sc{iso} 8601.
+72-9-24 # Assume 19xx for 69 through 99,
+ # 20xx for 00 through 68.
+72-09-24 # Leading zeros are ignored.
+9/24/72 # Common U.S. writing.
+24 September 1972
+24 Sept 72 # September has a special abbreviation.
+24 Sep 72 # Three-letter abbreviations always allowed.
+Sep 24, 1972
+24-sep-72
+24sep72
+@end example
+
+The year can also be omitted. In this case, the last specified year is
+used, or the current year if none. For example:
+
+@example
+9/24
+sep 24
+@end example
+
+Here are the rules.
+
+@cindex @sc{iso} 8601 date format
+@cindex date format, @sc{iso} 8601
+For numeric months, the @sc{iso} 8601 format
+@samp{@var{year}-@var{month}-@var{day}} is allowed, where @var{year} is
+any positive number, @var{month} is a number between 01 and 12, and
+@var{day} is a number between 01 and 31. A leading zero must be present
+if a number is less than ten. If @var{year} is 68 or smaller, then 2000
+is added to it; otherwise, if @var{year} is less than 100,
+then 1900 is added to it. The construct
+@samp{@var{month}/@var{day}/@var{year}}, popular in the United States,
+is accepted. Also @samp{@var{month}/@var{day}}, omitting the year.
+
+@cindex month names in date strings
+@cindex abbreviations for months
+Literal months may be spelled out in full: @samp{January},
+@samp{February}, @samp{March}, @samp{April}, @samp{May}, @samp{June},
+@samp{July}, @samp{August}, @samp{September}, @samp{October},
+@samp{November} or @samp{December}. Literal months may be abbreviated
+to their first three letters, possibly followed by an abbreviating dot.
+It is also permitted to write @samp{Sept} instead of @samp{September}.
+
+When months are written literally, the calendar date may be given as any
+of the following:
+
+@example
+@var{day} @var{month} @var{year}
+@var{day} @var{month}
+@var{month} @var{day} @var{year}
+@var{day}-@var{month}-@var{year}
+@end example
+
+Or, omitting the year:
+
+@example
+@var{month} @var{day}
+@end example
+
+
+@node Time of day items
+@appendixsubsec Time of day items
+
+@cindex time of day item
+
+A @dfn{time of day item} in date strings specifies the time on a given
+day. Here are some examples, all of which represent the same time:
+
+@example
+20:02:00.000000
+20:02
+8:02pm
+20:02-0500 # In @sc{est} (U.S. Eastern Standard Time).
+@end example
+
+More generally, the time of day may be given as
+@samp{@var{hour}:@var{minute}:@var{second}}, where @var{hour} is
+a number between 0 and 23, @var{minute} is a number between 0 and
+59, and @var{second} is a number between 0 and 59 possibly followed by
+@samp{.} or @samp{,} and a fraction containing one or more digits.
+Alternatively,
+@samp{:@var{second}} can be omitted, in which case it is taken to
+be zero.
+
+@findex am @r{in date strings}
+@findex pm @r{in date strings}
+@findex midnight @r{in date strings}
+@findex noon @r{in date strings}
+If the time is followed by @samp{am} or @samp{pm} (or @samp{a.m.}
+or @samp{p.m.}), @var{hour} is restricted to run from 1 to 12, and
+@samp{:@var{minute}} may be omitted (taken to be zero). @samp{am}
+indicates the first half of the day, @samp{pm} indicates the second
+half of the day. In this notation, 12 is the predecessor of 1:
+midnight is @samp{12am} while noon is @samp{12pm}.
+(This is the zero-oriented interpretation of @samp{12am} and @samp{12pm},
+as opposed to the old tradition derived from Latin
+which uses @samp{12m} for noon and @samp{12pm} for midnight.)
+
+@cindex time zone correction
+@cindex minutes, time zone correction by
+The time may alternatively be followed by a time zone correction,
+expressed as @samp{@var{s}@var{hh}@var{mm}}, where @var{s} is @samp{+}
+or @samp{-}, @var{hh} is a number of zone hours and @var{mm} is a number
+of zone minutes. You can also separate @var{hh} from @var{mm} with a colon.
+When a time zone correction is given this way, it
+forces interpretation of the time relative to
+Coordinated Universal Time (@sc{utc}), overriding any previous
+specification for the time zone or the local time zone. For example,
+@samp{+0530} and @samp{+05:30} both stand for the time zone 5.5 hours
+ahead of @sc{utc} (e.g., India). The @var{minute}
+part of the time of day may not be elided when a time zone correction
+is used. This is the best way to specify a time zone correction by
+fractional parts of an hour.
+
+Either @samp{am}/@samp{pm} or a time zone correction may be specified,
+but not both.
+
+
+@node Time zone items
+@appendixsubsec Time zone items
+
+@cindex time zone item
+
+A @dfn{time zone item} specifies an international time zone, indicated
+by a small set of letters, e.g., @samp{UTC} or @samp{Z}
+for Coordinated Universal
+Time. Any included periods are ignored. By following a
+non-daylight-saving time zone by the string @samp{DST} in a separate
+word (that is, separated by some white space), the corresponding
+daylight saving time zone may be specified.
+Alternatively, a non-daylight-saving time zone can be followed by a
+time zone correction, to add the two values. This is normally done
+only for @samp{UTC}; for example, @samp{UTC+05:30} is equivalent to
+@samp{+05:30}.
+
+Time zone items other than @samp{UTC} and @samp{Z}
+are obsolescent and are not recommended, because they
+are ambiguous; for example, @samp{EST} has a different meaning in
+Australia than in the United States. Instead, it's better to use
+unambiguous numeric time zone corrections like @samp{-0500}, as
+described in the previous section.
+
+If neither a time zone item nor a time zone correction is supplied,
+time stamps are interpreted using the rules of the default time zone
+(@pxref{Specifying time zone rules}).
+
+
+@node Day of week items
+@appendixsubsec Day of week items
+
+@cindex day of week item
+
+The explicit mention of a day of the week will forward the date
+(only if necessary) to reach that day of the week in the future.
+
+Days of the week may be spelled out in full: @samp{Sunday},
+@samp{Monday}, @samp{Tuesday}, @samp{Wednesday}, @samp{Thursday},
+@samp{Friday} or @samp{Saturday}. Days may be abbreviated to their
+first three letters, optionally followed by a period. The special
+abbreviations @samp{Tues} for @samp{Tuesday}, @samp{Wednes} for
+@samp{Wednesday} and @samp{Thur} or @samp{Thurs} for @samp{Thursday} are
+also allowed.
+
+@findex next @var{day}
+@findex last @var{day}
+A number may precede a day of the week item to move forward
+supplementary weeks. It is best used in expression like @samp{third
+monday}. In this context, @samp{last @var{day}} or @samp{next
+@var{day}} is also acceptable; they move one week before or after
+the day that @var{day} by itself would represent.
+
+A comma following a day of the week item is ignored.
+
+
+@node Relative items in date strings
+@appendixsubsec Relative items in date strings
+
+@cindex relative items in date strings
+@cindex displacement of dates
+
+@dfn{Relative items} adjust a date (or the current date if none) forward
+or backward. The effects of relative items accumulate. Here are some
+examples:
+
+@example
+1 year
+1 year ago
+3 years
+2 days
+@end example
+
+@findex year @r{in date strings}
+@findex month @r{in date strings}
+@findex fortnight @r{in date strings}
+@findex week @r{in date strings}
+@findex day @r{in date strings}
+@findex hour @r{in date strings}
+@findex minute @r{in date strings}
+The unit of time displacement may be selected by the string @samp{year}
+or @samp{month} for moving by whole years or months. These are fuzzy
+units, as years and months are not all of equal duration. More precise
+units are @samp{fortnight} which is worth 14 days, @samp{week} worth 7
+days, @samp{day} worth 24 hours, @samp{hour} worth 60 minutes,
+@samp{minute} or @samp{min} worth 60 seconds, and @samp{second} or
+@samp{sec} worth one second. An @samp{s} suffix on these units is
+accepted and ignored.
+
+@findex ago @r{in date strings}
+The unit of time may be preceded by a multiplier, given as an optionally
+signed number. Unsigned numbers are taken as positively signed. No
+number at all implies 1 for a multiplier. Following a relative item by
+the string @samp{ago} is equivalent to preceding the unit by a
+multiplier with value @math{-1}.
+
+@findex day @r{in date strings}
+@findex tomorrow @r{in date strings}
+@findex yesterday @r{in date strings}
+The string @samp{tomorrow} is worth one day in the future (equivalent
+to @samp{day}), the string @samp{yesterday} is worth
+one day in the past (equivalent to @samp{day ago}).
+
+@findex now @r{in date strings}
+@findex today @r{in date strings}
+@findex this @r{in date strings}
+The strings @samp{now} or @samp{today} are relative items corresponding
+to zero-valued time displacement, these strings come from the fact
+a zero-valued time displacement represents the current time when not
+otherwise changed by previous items. They may be used to stress other
+items, like in @samp{12:00 today}. The string @samp{this} also has
+the meaning of a zero-valued time displacement, but is preferred in
+date strings like @samp{this thursday}.
+
+When a relative item causes the resulting date to cross a boundary
+where the clocks were adjusted, typically for daylight saving time,
+the resulting date and time are adjusted accordingly.
+
+The fuzz in units can cause problems with relative items. For
+example, @samp{2003-07-31 -1 month} might evaluate to 2003-07-01,
+because 2003-06-31 is an invalid date. To determine the previous
+month more reliably, you can ask for the month before the 15th of the
+current month. For example:
+
+@example
+$ date -R
+Thu, 31 Jul 2003 13:02:39 -0700
+$ date --date='-1 month' +'Last month was %B?'
+Last month was July?
+$ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
+Last month was June!
+@end example
+
+Also, take care when manipulating dates around clock changes such as
+daylight saving leaps. In a few cases these have added or subtracted
+as much as 24 hours from the clock, so it is often wise to adopt
+universal time by setting the @env{TZ} environment variable to
+@samp{UTC0} before embarking on calendrical calculations.
+
+@node Pure numbers in date strings
+@appendixsubsec Pure numbers in date strings
+
+@cindex pure numbers in date strings
+
+The precise interpretation of a pure decimal number depends
+on the context in the date string.
+
+If the decimal number is of the form @var{yyyy}@var{mm}@var{dd} and no
+other calendar date item (@pxref{Calendar date items}) appears before it
+in the date string, then @var{yyyy} is read as the year, @var{mm} as the
+month number and @var{dd} as the day of the month, for the specified
+calendar date.
+
+If the decimal number is of the form @var{hh}@var{mm} and no other time
+of day item appears before it in the date string, then @var{hh} is read
+as the hour of the day and @var{mm} as the minute of the hour, for the
+specified time of day. @var{mm} can also be omitted.
+
+If both a calendar date and a time of day appear to the left of a number
+in the date string, but no relative item, then the number overrides the
+year.
+
+
+@node Seconds since the Epoch
+@appendixsubsec Seconds since the Epoch
+
+If you precede a number with @samp{@@}, it represents an internal time
+stamp as a count of seconds. The number can contain an internal
+decimal point (either @samp{.} or @samp{,}); any excess precision not
+supported by the internal representation is truncated toward minus
+infinity. Such a number cannot be combined with any other date
+item, as it specifies a complete time stamp.
+
+@cindex beginning of time, for @acronym{POSIX}
+@cindex epoch, for @acronym{POSIX}
+Internally, computer times are represented as a count of seconds since
+an epoch---a well-defined point of time. On @acronym{GNU} and
+@acronym{POSIX} systems, the epoch is 1970-01-01 00:00:00 @sc{utc}, so
+@samp{@@0} represents this time, @samp{@@1} represents 1970-01-01
+00:00:01 @sc{utc}, and so forth. @acronym{GNU} and most other
+@acronym{POSIX}-compliant systems support such times as an extension
+to @acronym{POSIX}, using negative counts, so that @samp{@@-1}
+represents 1969-12-31 23:59:59 @sc{utc}.
+
+Traditional Unix systems count seconds with 32-bit two's-complement
+integers and can represent times from 1901-12-13 20:45:52 through
+2038-01-19 03:14:07 @sc{utc}. More modern systems use 64-bit counts
+of seconds with nanosecond subcounts, and can represent all the times
+in the known lifetime of the universe to a resolution of 1 nanosecond.
+
+On most systems, these counts ignore the presence of leap seconds.
+For example, on most systems @samp{@@915148799} represents 1998-12-31
+23:59:59 @sc{utc}, @samp{@@915148800} represents 1999-01-01 00:00:00
+@sc{utc}, and there is no way to represent the intervening leap second
+1998-12-31 23:59:60 @sc{utc}.
+
+@node Specifying time zone rules
+@appendixsubsec Specifying time zone rules
+
+@vindex TZ
+Normally, dates are interpreted using the rules of the current time
+zone, which in turn are specified by the @env{TZ} environment
+variable, or by a system default if @env{TZ} is not set. To specify a
+different set of default time zone rules that apply just to one date,
+start the date with a string of the form @samp{TZ="@var{rule}"}. The
+two quote characters (@samp{"}) must be present in the date, and any
+quotes or backslashes within @var{rule} must be escaped by a
+backslash.
+
+For example, with the @acronym{GNU} @command{date} command you can
+answer the question ``What time is it in New York when a Paris clock
+shows 6:30am on October 31, 2004?'' by using a date beginning with
+@samp{TZ="Europe/Paris"} as shown in the following shell transcript:
+
+@example
+$ export TZ="America/New_York"
+$ date --date='TZ="Europe/Paris" 2004-10-31 06:30'
+Sun Oct 31 01:30:00 EDT 2004
+@end example
+
+In this example, the @option{--date} operand begins with its own
+@env{TZ} setting, so the rest of that operand is processed according
+to @samp{Europe/Paris} rules, treating the string @samp{2004-10-31
+06:30} as if it were in Paris. However, since the output of the
+@command{date} command is processed according to the overall time zone
+rules, it uses New York time. (Paris was normally six hours ahead of
+New York in 2004, but this example refers to a brief Halloween period
+when the gap was five hours.)
+
+A @env{TZ} value is a rule that typically names a location in the
+@uref{http://www.twinsun.com/tz/tz-link.htm, @samp{tz} database}.
+A recent catalog of location names appears in the
+@uref{http://twiki.org/cgi-bin/xtra/tzdate, TWiki Date and Time
+Gateway}. A few non-@acronym{GNU} hosts require a colon before a
+location name in a @env{TZ} setting, e.g.,
+@samp{TZ=":America/New_York"}.
+
+The @samp{tz} database includes a wide variety of locations ranging
+from @samp{Arctic/Longyearbyen} to @samp{Antarctica/South_Pole}, but
+if you are at sea and have your own private time zone, or if you are
+using a non-@acronym{GNU} host that does not support the @samp{tz}
+database, you may need to use a @acronym{POSIX} rule instead. Simple
+@acronym{POSIX} rules like @samp{UTC0} specify a time zone without
+daylight saving time; other rules can specify simple daylight saving
+regimes. @xref{TZ Variable,, Specifying the Time Zone with @code{TZ},
+libc, The GNU C Library}.
+
+@node Authors of get_date
+@appendixsubsec Authors of @code{get_date}
+
+@cindex authors of @code{get_date}
+
+@cindex Bellovin, Steven M.
+@cindex Salz, Rich
+@cindex Berets, Jim
+@cindex MacKenzie, David
+@cindex Meyering, Jim
+@cindex Eggert, Paul
+@code{get_date} was originally implemented by Steven M. Bellovin
+(@email{smb@@research.att.com}) while at the University of North Carolina
+at Chapel Hill. The code was later tweaked by a couple of people on
+Usenet, then completely overhauled by Rich $alz (@email{rsalz@@bbn.com})
+and Jim Berets (@email{jberets@@bbn.com}) in August, 1990. Various
+revisions for the @sc{gnu} system were made by David MacKenzie, Jim Meyering,
+Paul Eggert and others.
+
+@cindex Pinard, F.
+@cindex Berry, K.
+This chapter was originally produced by Fran@,{c}ois Pinard
+(@email{pinard@@iro.umontreal.ca}) from the @file{getdate.y} source code,
+and then edited by K.@: Berry (@email{kb@@cs.umb.edu}).
diff --git a/doc/getdate.texi b/doc/getdate.texi
new file mode 100644
index 0000000..0150ff2
--- /dev/null
+++ b/doc/getdate.texi
@@ -0,0 +1,547 @@
+@c GNU date syntax documentation
+
+@c Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+@c 2003, 2004, 2005 Free Software Foundation, Inc.
+
+@c Permission is granted to copy, distribute and/or modify this document
+@c under the terms of the GNU Free Documentation License, Version 1.1 or
+@c any later version published by the Free Software Foundation; with no
+@c Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+@c Texts. A copy of the license is included in the ``GNU Free
+@c Documentation License'' file as part of this distribution.
+
+@node Date input formats
+@chapter Date input formats
+
+@cindex date input formats
+@findex get_date
+
+First, a quote:
+
+@quotation
+Our units of temporal measurement, from seconds on up to months, are so
+complicated, asymmetrical and disjunctive so as to make coherent mental
+reckoning in time all but impossible. Indeed, had some tyrannical god
+contrived to enslave our minds to time, to make it all but impossible
+for us to escape subjection to sodden routines and unpleasant surprises,
+he could hardly have done better than handing down our present system.
+It is like a set of trapezoidal building blocks, with no vertical or
+horizontal surfaces, like a language in which the simplest thought
+demands ornate constructions, useless particles and lengthy
+circumlocutions. Unlike the more successful patterns of language and
+science, which enable us to face experience boldly or at least
+level-headedly, our system of temporal calculation silently and
+persistently encourages our terror of time.
+
+@dots{} It is as though architects had to measure length in feet, width
+in meters and height in ells; as though basic instruction manuals
+demanded a knowledge of five different languages. It is no wonder then
+that we often look into our own immediate past or future, last Tuesday
+or a week from Sunday, with feelings of helpless confusion. @dots{}
+
+--- Robert Grudin, @cite{Time and the Art of Living}.
+@end quotation
+
+This section describes the textual date representations that @sc{gnu}
+programs accept. These are the strings you, as a user, can supply as
+arguments to the various programs. The C interface (via the
+@code{get_date} function) is not described here.
+
+@menu
+* General date syntax:: Common rules.
+* Calendar date items:: 19 Dec 1994.
+* Time of day items:: 9:20pm.
+* Time zone items:: @sc{est}, @sc{pdt}, @sc{gmt}.
+* Day of week items:: Monday and others.
+* Relative items in date strings:: next tuesday, 2 years ago.
+* Pure numbers in date strings:: 19931219, 1440.
+* Seconds since the Epoch:: @@1078100502.
+* Specifying time zone rules:: TZ="America/New_York", TZ="UTC0".
+* Authors of get_date:: Bellovin, Eggert, Salz, Berets, et al.
+@end menu
+
+
+@node General date syntax
+@section General date syntax
+
+@cindex general date syntax
+
+@cindex items in date strings
+A @dfn{date} is a string, possibly empty, containing many items
+separated by whitespace. The whitespace may be omitted when no
+ambiguity arises. The empty string means the beginning of today (i.e.,
+midnight). Order of the items is immaterial. A date string may contain
+many flavors of items:
+
+@itemize @bullet
+@item calendar date items
+@item time of day items
+@item time zone items
+@item day of the week items
+@item relative items
+@item pure numbers.
+@end itemize
+
+@noindent We describe each of these item types in turn, below.
+
+@cindex numbers, written-out
+@cindex ordinal numbers
+@findex first @r{in date strings}
+@findex next @r{in date strings}
+@findex last @r{in date strings}
+A few ordinal numbers may be written out in words in some contexts. This is
+most useful for specifying day of the week items or relative items (see
+below). Among the most commonly used ordinal numbers, the word
+@samp{last} stands for @math{-1}, @samp{this} stands for 0, and
+@samp{first} and @samp{next} both stand for 1. Because the word
+@samp{second} stands for the unit of time there is no way to write the
+ordinal number 2, but for convenience @samp{third} stands for 3,
+@samp{fourth} for 4, @samp{fifth} for 5,
+@samp{sixth} for 6, @samp{seventh} for 7, @samp{eighth} for 8,
+@samp{ninth} for 9, @samp{tenth} for 10, @samp{eleventh} for 11 and
+@samp{twelfth} for 12.
+
+@cindex months, written-out
+When a month is written this way, it is still considered to be written
+numerically, instead of being ``spelled in full''; this changes the
+allowed strings.
+
+@cindex language, in dates
+In the current implementation, only English is supported for words and
+abbreviations like @samp{AM}, @samp{DST}, @samp{EST}, @samp{first},
+@samp{January}, @samp{Sunday}, @samp{tomorrow}, and @samp{year}.
+
+@cindex language, in dates
+@cindex time zone item
+The output of the @command{date} command
+is not always acceptable as a date string,
+not only because of the language problem, but also because there is no
+standard meaning for time zone items like @samp{IST}. When using
+@command{date} to generate a date string intended to be parsed later,
+specify a date format that is independent of language and that does not
+use time zone items other than @samp{UTC} and @samp{Z}. Here are some
+ways to do this:
+
+@example
+$ LC_ALL=C TZ=UTC0 date
+Mon Mar 1 00:21:42 UTC 2004
+$ TZ=UTC0 date +'%Y-%m-%d %H:%M:%SZ'
+2004-03-01 00:21:42Z
+$ date --iso-8601=ns | tr T ' ' # --iso-8601 is a GNU extension.
+2004-02-29 16:21:42,692722128-0800
+$ date --rfc-2822 # a GNU extension
+Sun, 29 Feb 2004 16:21:42 -0800
+$ date +'%Y-%m-%d %H:%M:%S %z' # %z is a GNU extension.
+2004-02-29 16:21:42 -0800
+$ date +'@@%s.%N' # %s and %N are GNU extensions.
+@@1078100502.692722128
+@end example
+
+@cindex case, ignored in dates
+@cindex comments, in dates
+Alphabetic case is completely ignored in dates. Comments may be introduced
+between round parentheses, as long as included parentheses are properly
+nested. Hyphens not followed by a digit are currently ignored. Leading
+zeros on numbers are ignored.
+
+
+@node Calendar date items
+@section Calendar date items
+
+@cindex calendar date item
+
+A @dfn{calendar date item} specifies a day of the year. It is
+specified differently, depending on whether the month is specified
+numerically or literally. All these strings specify the same calendar date:
+
+@example
+1972-09-24 # @sc{iso} 8601.
+72-9-24 # Assume 19xx for 69 through 99,
+ # 20xx for 00 through 68.
+72-09-24 # Leading zeros are ignored.
+9/24/72 # Common U.S. writing.
+24 September 1972
+24 Sept 72 # September has a special abbreviation.
+24 Sep 72 # Three-letter abbreviations always allowed.
+Sep 24, 1972
+24-sep-72
+24sep72
+@end example
+
+The year can also be omitted. In this case, the last specified year is
+used, or the current year if none. For example:
+
+@example
+9/24
+sep 24
+@end example
+
+Here are the rules.
+
+@cindex @sc{iso} 8601 date format
+@cindex date format, @sc{iso} 8601
+For numeric months, the @sc{iso} 8601 format
+@samp{@var{year}-@var{month}-@var{day}} is allowed, where @var{year} is
+any positive number, @var{month} is a number between 01 and 12, and
+@var{day} is a number between 01 and 31. A leading zero must be present
+if a number is less than ten. If @var{year} is 68 or smaller, then 2000
+is added to it; otherwise, if @var{year} is less than 100,
+then 1900 is added to it. The construct
+@samp{@var{month}/@var{day}/@var{year}}, popular in the United States,
+is accepted. Also @samp{@var{month}/@var{day}}, omitting the year.
+
+@cindex month names in date strings
+@cindex abbreviations for months
+Literal months may be spelled out in full: @samp{January},
+@samp{February}, @samp{March}, @samp{April}, @samp{May}, @samp{June},
+@samp{July}, @samp{August}, @samp{September}, @samp{October},
+@samp{November} or @samp{December}. Literal months may be abbreviated
+to their first three letters, possibly followed by an abbreviating dot.
+It is also permitted to write @samp{Sept} instead of @samp{September}.
+
+When months are written literally, the calendar date may be given as any
+of the following:
+
+@example
+@var{day} @var{month} @var{year}
+@var{day} @var{month}
+@var{month} @var{day} @var{year}
+@var{day}-@var{month}-@var{year}
+@end example
+
+Or, omitting the year:
+
+@example
+@var{month} @var{day}
+@end example
+
+
+@node Time of day items
+@section Time of day items
+
+@cindex time of day item
+
+A @dfn{time of day item} in date strings specifies the time on a given
+day. Here are some examples, all of which represent the same time:
+
+@example
+20:02:00.000000
+20:02
+8:02pm
+20:02-0500 # In @sc{est} (U.S. Eastern Standard Time).
+@end example
+
+More generally, the time of day may be given as
+@samp{@var{hour}:@var{minute}:@var{second}}, where @var{hour} is
+a number between 0 and 23, @var{minute} is a number between 0 and
+59, and @var{second} is a number between 0 and 59 possibly followed by
+@samp{.} or @samp{,} and a fraction containing one or more digits.
+Alternatively,
+@samp{:@var{second}} can be omitted, in which case it is taken to
+be zero.
+
+@findex am @r{in date strings}
+@findex pm @r{in date strings}
+@findex midnight @r{in date strings}
+@findex noon @r{in date strings}
+If the time is followed by @samp{am} or @samp{pm} (or @samp{a.m.}
+or @samp{p.m.}), @var{hour} is restricted to run from 1 to 12, and
+@samp{:@var{minute}} may be omitted (taken to be zero). @samp{am}
+indicates the first half of the day, @samp{pm} indicates the second
+half of the day. In this notation, 12 is the predecessor of 1:
+midnight is @samp{12am} while noon is @samp{12pm}.
+(This is the zero-oriented interpretation of @samp{12am} and @samp{12pm},
+as opposed to the old tradition derived from Latin
+which uses @samp{12m} for noon and @samp{12pm} for midnight.)
+
+@cindex time zone correction
+@cindex minutes, time zone correction by
+The time may alternatively be followed by a time zone correction,
+expressed as @samp{@var{s}@var{hh}@var{mm}}, where @var{s} is @samp{+}
+or @samp{-}, @var{hh} is a number of zone hours and @var{mm} is a number
+of zone minutes. You can also separate @var{hh} from @var{mm} with a colon.
+When a time zone correction is given this way, it
+forces interpretation of the time relative to
+Coordinated Universal Time (@sc{utc}), overriding any previous
+specification for the time zone or the local time zone. For example,
+@samp{+0530} and @samp{+05:30} both stand for the time zone 5.5 hours
+ahead of @sc{utc} (e.g., India). The @var{minute}
+part of the time of day may not be elided when a time zone correction
+is used. This is the best way to specify a time zone correction by
+fractional parts of an hour.
+
+Either @samp{am}/@samp{pm} or a time zone correction may be specified,
+but not both.
+
+
+@node Time zone items
+@section Time zone items
+
+@cindex time zone item
+
+A @dfn{time zone item} specifies an international time zone, indicated
+by a small set of letters, e.g., @samp{UTC} or @samp{Z}
+for Coordinated Universal
+Time. Any included periods are ignored. By following a
+non-daylight-saving time zone by the string @samp{DST} in a separate
+word (that is, separated by some white space), the corresponding
+daylight saving time zone may be specified.
+Alternatively, a non-daylight-saving time zone can be followed by a
+time zone correction, to add the two values. This is normally done
+only for @samp{UTC}; for example, @samp{UTC+05:30} is equivalent to
+@samp{+05:30}.
+
+Time zone items other than @samp{UTC} and @samp{Z}
+are obsolescent and are not recommended, because they
+are ambiguous; for example, @samp{EST} has a different meaning in
+Australia than in the United States. Instead, it's better to use
+unambiguous numeric time zone corrections like @samp{-0500}, as
+described in the previous section.
+
+If neither a time zone item nor a time zone correction is supplied,
+time stamps are interpreted using the rules of the default time zone
+(@pxref{Specifying time zone rules}).
+
+
+@node Day of week items
+@section Day of week items
+
+@cindex day of week item
+
+The explicit mention of a day of the week will forward the date
+(only if necessary) to reach that day of the week in the future.
+
+Days of the week may be spelled out in full: @samp{Sunday},
+@samp{Monday}, @samp{Tuesday}, @samp{Wednesday}, @samp{Thursday},
+@samp{Friday} or @samp{Saturday}. Days may be abbreviated to their
+first three letters, optionally followed by a period. The special
+abbreviations @samp{Tues} for @samp{Tuesday}, @samp{Wednes} for
+@samp{Wednesday} and @samp{Thur} or @samp{Thurs} for @samp{Thursday} are
+also allowed.
+
+@findex next @var{day}
+@findex last @var{day}
+A number may precede a day of the week item to move forward
+supplementary weeks. It is best used in expression like @samp{third
+monday}. In this context, @samp{last @var{day}} or @samp{next
+@var{day}} is also acceptable; they move one week before or after
+the day that @var{day} by itself would represent.
+
+A comma following a day of the week item is ignored.
+
+
+@node Relative items in date strings
+@section Relative items in date strings
+
+@cindex relative items in date strings
+@cindex displacement of dates
+
+@dfn{Relative items} adjust a date (or the current date if none) forward
+or backward. The effects of relative items accumulate. Here are some
+examples:
+
+@example
+1 year
+1 year ago
+3 years
+2 days
+@end example
+
+@findex year @r{in date strings}
+@findex month @r{in date strings}
+@findex fortnight @r{in date strings}
+@findex week @r{in date strings}
+@findex day @r{in date strings}
+@findex hour @r{in date strings}
+@findex minute @r{in date strings}
+The unit of time displacement may be selected by the string @samp{year}
+or @samp{month} for moving by whole years or months. These are fuzzy
+units, as years and months are not all of equal duration. More precise
+units are @samp{fortnight} which is worth 14 days, @samp{week} worth 7
+days, @samp{day} worth 24 hours, @samp{hour} worth 60 minutes,
+@samp{minute} or @samp{min} worth 60 seconds, and @samp{second} or
+@samp{sec} worth one second. An @samp{s} suffix on these units is
+accepted and ignored.
+
+@findex ago @r{in date strings}
+The unit of time may be preceded by a multiplier, given as an optionally
+signed number. Unsigned numbers are taken as positively signed. No
+number at all implies 1 for a multiplier. Following a relative item by
+the string @samp{ago} is equivalent to preceding the unit by a
+multiplier with value @math{-1}.
+
+@findex day @r{in date strings}
+@findex tomorrow @r{in date strings}
+@findex yesterday @r{in date strings}
+The string @samp{tomorrow} is worth one day in the future (equivalent
+to @samp{day}), the string @samp{yesterday} is worth
+one day in the past (equivalent to @samp{day ago}).
+
+@findex now @r{in date strings}
+@findex today @r{in date strings}
+@findex this @r{in date strings}
+The strings @samp{now} or @samp{today} are relative items corresponding
+to zero-valued time displacement, these strings come from the fact
+a zero-valued time displacement represents the current time when not
+otherwise changed by previous items. They may be used to stress other
+items, like in @samp{12:00 today}. The string @samp{this} also has
+the meaning of a zero-valued time displacement, but is preferred in
+date strings like @samp{this thursday}.
+
+When a relative item causes the resulting date to cross a boundary
+where the clocks were adjusted, typically for daylight saving time,
+the resulting date and time are adjusted accordingly.
+
+The fuzz in units can cause problems with relative items. For
+example, @samp{2003-07-31 -1 month} might evaluate to 2003-07-01,
+because 2003-06-31 is an invalid date. To determine the previous
+month more reliably, you can ask for the month before the 15th of the
+current month. For example:
+
+@example
+$ date -R
+Thu, 31 Jul 2003 13:02:39 -0700
+$ date --date='-1 month' +'Last month was %B?'
+Last month was July?
+$ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
+Last month was June!
+@end example
+
+Also, take care when manipulating dates around clock changes such as
+daylight saving leaps. In a few cases these have added or subtracted
+as much as 24 hours from the clock, so it is often wise to adopt
+universal time by setting the @env{TZ} environment variable to
+@samp{UTC0} before embarking on calendrical calculations.
+
+@node Pure numbers in date strings
+@section Pure numbers in date strings
+
+@cindex pure numbers in date strings
+
+The precise interpretation of a pure decimal number depends
+on the context in the date string.
+
+If the decimal number is of the form @var{yyyy}@var{mm}@var{dd} and no
+other calendar date item (@pxref{Calendar date items}) appears before it
+in the date string, then @var{yyyy} is read as the year, @var{mm} as the
+month number and @var{dd} as the day of the month, for the specified
+calendar date.
+
+If the decimal number is of the form @var{hh}@var{mm} and no other time
+of day item appears before it in the date string, then @var{hh} is read
+as the hour of the day and @var{mm} as the minute of the hour, for the
+specified time of day. @var{mm} can also be omitted.
+
+If both a calendar date and a time of day appear to the left of a number
+in the date string, but no relative item, then the number overrides the
+year.
+
+
+@node Seconds since the Epoch
+@section Seconds since the Epoch
+
+If you precede a number with @samp{@@}, it represents an internal time
+stamp as a count of seconds. The number can contain an internal
+decimal point (either @samp{.} or @samp{,}); any excess precision not
+supported by the internal representation is truncated toward minus
+infinity. Such a number cannot be combined with any other date
+item, as it specifies a complete time stamp.
+
+@cindex beginning of time, for @acronym{POSIX}
+@cindex epoch, for @acronym{POSIX}
+Internally, computer times are represented as a count of seconds since
+an epoch---a well-defined point of time. On @acronym{GNU} and
+@acronym{POSIX} systems, the epoch is 1970-01-01 00:00:00 @sc{utc}, so
+@samp{@@0} represents this time, @samp{@@1} represents 1970-01-01
+00:00:01 @sc{utc}, and so forth. @acronym{GNU} and most other
+@acronym{POSIX}-compliant systems support such times as an extension
+to @acronym{POSIX}, using negative counts, so that @samp{@@-1}
+represents 1969-12-31 23:59:59 @sc{utc}.
+
+Traditional Unix systems count seconds with 32-bit two's-complement
+integers and can represent times from 1901-12-13 20:45:52 through
+2038-01-19 03:14:07 @sc{utc}. More modern systems use 64-bit counts
+of seconds with nanosecond subcounts, and can represent all the times
+in the known lifetime of the universe to a resolution of 1 nanosecond.
+
+On most systems, these counts ignore the presence of leap seconds.
+For example, on most systems @samp{@@915148799} represents 1998-12-31
+23:59:59 @sc{utc}, @samp{@@915148800} represents 1999-01-01 00:00:00
+@sc{utc}, and there is no way to represent the intervening leap second
+1998-12-31 23:59:60 @sc{utc}.
+
+@node Specifying time zone rules
+@section Specifying time zone rules
+
+@vindex TZ
+Normally, dates are interpreted using the rules of the current time
+zone, which in turn are specified by the @env{TZ} environment
+variable, or by a system default if @env{TZ} is not set. To specify a
+different set of default time zone rules that apply just to one date,
+start the date with a string of the form @samp{TZ="@var{rule}"}. The
+two quote characters (@samp{"}) must be present in the date, and any
+quotes or backslashes within @var{rule} must be escaped by a
+backslash.
+
+For example, with the @acronym{GNU} @command{date} command you can
+answer the question ``What time is it in New York when a Paris clock
+shows 6:30am on October 31, 2004?'' by using a date beginning with
+@samp{TZ="Europe/Paris"} as shown in the following shell transcript:
+
+@example
+$ export TZ="America/New_York"
+$ date --date='TZ="Europe/Paris" 2004-10-31 06:30'
+Sun Oct 31 01:30:00 EDT 2004
+@end example
+
+In this example, the @option{--date} operand begins with its own
+@env{TZ} setting, so the rest of that operand is processed according
+to @samp{Europe/Paris} rules, treating the string @samp{2004-10-31
+06:30} as if it were in Paris. However, since the output of the
+@command{date} command is processed according to the overall time zone
+rules, it uses New York time. (Paris was normally six hours ahead of
+New York in 2004, but this example refers to a brief Halloween period
+when the gap was five hours.)
+
+A @env{TZ} value is a rule that typically names a location in the
+@uref{http://www.twinsun.com/tz/tz-link.htm, @samp{tz} database}.
+A recent catalog of location names appears in the
+@uref{http://twiki.org/cgi-bin/xtra/tzdate, TWiki Date and Time
+Gateway}. A few non-@acronym{GNU} hosts require a colon before a
+location name in a @env{TZ} setting, e.g.,
+@samp{TZ=":America/New_York"}.
+
+The @samp{tz} database includes a wide variety of locations ranging
+from @samp{Arctic/Longyearbyen} to @samp{Antarctica/South_Pole}, but
+if you are at sea and have your own private time zone, or if you are
+using a non-@acronym{GNU} host that does not support the @samp{tz}
+database, you may need to use a @acronym{POSIX} rule instead. Simple
+@acronym{POSIX} rules like @samp{UTC0} specify a time zone without
+daylight saving time; other rules can specify simple daylight saving
+regimes. @xref{TZ Variable,, Specifying the Time Zone with @code{TZ},
+libc, The GNU C Library}.
+
+@node Authors of get_date
+@section Authors of @code{get_date}
+
+@cindex authors of @code{get_date}
+
+@cindex Bellovin, Steven M.
+@cindex Salz, Rich
+@cindex Berets, Jim
+@cindex MacKenzie, David
+@cindex Meyering, Jim
+@cindex Eggert, Paul
+@code{get_date} was originally implemented by Steven M. Bellovin
+(@email{smb@@research.att.com}) while at the University of North Carolina
+at Chapel Hill. The code was later tweaked by a couple of people on
+Usenet, then completely overhauled by Rich $alz (@email{rsalz@@bbn.com})
+and Jim Berets (@email{jberets@@bbn.com}) in August, 1990. Various
+revisions for the @sc{gnu} system were made by David MacKenzie, Jim Meyering,
+Paul Eggert and others.
+
+@cindex Pinard, F.
+@cindex Berry, K.
+This chapter was originally produced by Fran@,{c}ois Pinard
+(@email{pinard@@iro.umontreal.ca}) from the @file{getdate.y} source code,
+and then edited by K.@: Berry (@email{kb@@cs.umb.edu}).
diff --git a/doc/i18n/.cvsignore b/doc/i18n/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/doc/i18n/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/doc/i18n/ChangeLog b/doc/i18n/ChangeLog
new file mode 100644
index 0000000..47ff29d
--- /dev/null
+++ b/doc/i18n/ChangeLog
@@ -0,0 +1,11 @@
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore, Makefile.am: New files.
+
+2003-12-15 Derek Price <derek@ximbiot.com>
+
+ * ChangeLog, README: New files.
diff --git a/doc/i18n/Makefile.am b/doc/i18n/Makefile.am
new file mode 100644
index 0000000..0e8400a
--- /dev/null
+++ b/doc/i18n/Makefile.am
@@ -0,0 +1,22 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for GNU translated CVS documentation
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+# 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+SUBDIRS = pt_BR
+
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ README
diff --git a/doc/i18n/Makefile.in b/doc/i18n/Makefile.in
new file mode 100644
index 0000000..6679d7c
--- /dev/null
+++ b/doc/i18n/Makefile.in
@@ -0,0 +1,578 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for GNU translated CVS documentation
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+# 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/i18n
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+SUBDIRS = pt_BR
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ README
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/i18n/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu doc/i18n/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+ clean clean-generic clean-recursive ctags ctags-recursive \
+ distclean distclean-generic distclean-recursive distclean-tags \
+ distdir dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-generic \
+ mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/i18n/README b/doc/i18n/README
new file mode 100644
index 0000000..0a947ff
--- /dev/null
+++ b/doc/i18n/README
@@ -0,0 +1,11 @@
+The subdirectories of this directory contain translations of the Cederqvist
+(CVS manual). For now, you can build these files by copying them into place
+of the cvs.texinfo manual in the `doc' directory and running `make doc',
+`make pdf', `make info', or whatever would have built the regular manual in the
+form you were looking for. If anyone would like to contribute `Makefile.am's
+for the new directories, we would love to see them.
+
+P.S. I'm not sure about the organizational scheme I am using for these files.
+If anyone would like to suggest another and point me to a few example projects
+which contain translations of documentation, I would appreciate it. I've
+never dealt with translations before. (Derek Price: <derek@ximbiot.com>.)
diff --git a/doc/i18n/pt_BR/.cvsignore b/doc/i18n/pt_BR/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/doc/i18n/pt_BR/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/doc/i18n/pt_BR/ChangeLog b/doc/i18n/pt_BR/ChangeLog
new file mode 100644
index 0000000..017b68e
--- /dev/null
+++ b/doc/i18n/pt_BR/ChangeLog
@@ -0,0 +1,68 @@
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * README, cvs.texinfo: Update email addresses and links.
+
+2005-07-20 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: s/cvshome.org/nongnu.org.etc.../.
+
+2005-05-01 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore, Makefile.am: New files.
+
+2004-12-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (BUGS, What is CVS?): Remove references to Dr.
+ Pascal Molli's cvs document which is no longer available.
+
+2004-11-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo: Add some missing text.
+
+2004-10-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo (Common options): The -r TAG option works with
+ the cvs annotate command.
+ (Original patch from Ville Skytta <scop@cvshome.org>.)
+
+2004-04-01 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Latest update.
+ (From Fred Ulisses Maranhão <fred.maranhao@click21.com.br>.)
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Explain English words Fred could not translate in
+ English again.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Latest update.
+ (From Fred Ulisses Maranhão <fredm@chesf.gov.br>.)
+
+2003-12-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo: Latest update.
+ (From Fred Ulisses Maranhão <fredm@chesf.gov.br>.)
+
+2003-12-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.texinfo: Lastest update from Fred.
+
+2003-12-15 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Explain in the English comments what some English
+ colloquialisms that Fred did not know how to translate mean.
+
+2003-12-15 Derek Price <derek@ximbiot.com>
+
+ * cvs.texinfo: Translation of the Cederqvist to Brazilian Portuguese.
+ (From Fred Ulisses Maranhão <fredm@chesf.gov.br>.)
diff --git a/doc/i18n/pt_BR/Makefile.am b/doc/i18n/pt_BR/Makefile.am
new file mode 100644
index 0000000..36a9163
--- /dev/null
+++ b/doc/i18n/pt_BR/Makefile.am
@@ -0,0 +1,20 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for GNU translated CVS documentation
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+# 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ cvs.texinfo
diff --git a/doc/i18n/pt_BR/Makefile.in b/doc/i18n/pt_BR/Makefile.in
new file mode 100644
index 0000000..b51cfa1
--- /dev/null
+++ b/doc/i18n/pt_BR/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for GNU translated CVS documentation
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+# 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/i18n/pt_BR
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ cvs.texinfo
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/i18n/pt_BR/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu doc/i18n/pt_BR/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/i18n/pt_BR/README b/doc/i18n/pt_BR/README
new file mode 100644
index 0000000..993a919
--- /dev/null
+++ b/doc/i18n/pt_BR/README
@@ -0,0 +1,21 @@
+Hi,
+
+To just generate the manual in portuguese, download the file
+cvs.texinfo from the actual directory and compile the manual with:
+
+makeinfo --html cvs.texinfo
+
+If you what to help with the translation, send a message to
+bug-cvs@nongnu.org and told us what peace you want to translate.
+
+Some policy:
+
+* commit just a compileable version
+
+* don't erase original text. comment original text with '@c <en>'.
+
+* don't translate comments in english (starting with '@c '. leave them
+ untouched
+
+* don't translate examples. let's concentrate in finish the work
+ first.
diff --git a/doc/i18n/pt_BR/cvs.texinfo b/doc/i18n/pt_BR/cvs.texinfo
new file mode 100644
index 0000000..5b38ae5
--- /dev/null
+++ b/doc/i18n/pt_BR/cvs.texinfo
@@ -0,0 +1,21184 @@
+\input texinfo @c -*-texinfo-*-
+@comment Documentation for CVS.
+@setfilename cvs.info
+@macro copyleftnotice
+@noindent
+Copyright @copyright{} 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003 Free Software Foundation, Inc.
+
+@multitable @columnfractions .12 .88
+@item Portions
+@item @tab Copyright @copyright{} 1999, 2000, 2001, 2002, 2003 Derek R. Price,
+@item @tab Copyright @copyright{} 2002, 2003 Ximbiot @url{http://ximbiot.com},
+@item @tab Copyright @copyright{} 1992, 1993, 1999 Signum Support AB,
+@item @tab and Copyright @copyright{} others.
+@end multitable
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+@end macro
+
+@comment This file is part of the CVS distribution.
+
+@comment CVS is free software; you can redistribute it and/or modify
+@comment it under the terms of the GNU General Public License as published by
+@comment the Free Software Foundation; either version 2, or (at your option)
+@comment any later version.
+
+@comment CVS is distributed in the hope that it will be useful,
+@comment but WITHOUT ANY WARRANTY; without even the implied warranty of
+@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+@comment GNU General Public License for more details.
+
+@c See ../README for A4 vs. US letter size.
+@c When we provided A4 postscript, and people tried to
+@c print it on US letter, the usual complaint was that the
+@c page numbers would get cut off.
+@c If one prints US letter on A4, reportedly there is
+@c some extra space at the top and/or bottom, and the side
+@c margins are a bit narrow, but no text is lost.
+@c
+@c See
+@c http://www.ft.uni-erlangen.de/~mskuhn/iso-paper.html
+@c for more on paper sizes. Insuring that margins are
+@c big enough to print on either A4 or US letter does
+@c indeed seem to be the usual approach (RFC2346).
+
+@c This document seems to get overfull hboxes with some
+@c frequency (probably because the tendency is to
+@c sanity-check it with "make info" and run TeX less
+@c often). The big ugly boxes just seem to add insult
+@c to injury, and I'm not aware of them helping to fix
+@c the overfull hboxes at all.
+@finalout
+
+@c ???@include version.texi???
+@settitle CVS---Concurrent Versions System v@c ???@value{VERSION}???
+@setchapternewpage odd
+
+@c -- TODO list:
+@c -- Fix all lines that match "^@c -- "
+@c -- Also places marked with FIXME should be manual
+@c problems (as opposed to FIXCVS for CVS problems).
+
+@c @splitrcskeyword{} is used to avoid keyword expansion. It is replaced by
+@c @asis when generating info and dvi, and by <i></i> in the generated html,
+@c such that keywords are not expanded in the generated html.
+@ifnothtml
+@macro splitrcskeyword {arg}
+@asis{}\arg\
+@end macro
+@end ifnothtml
+
+@ifhtml
+@macro splitrcskeyword {arg}
+@i{}\arg\
+@end macro
+@end ifhtml
+
+@dircategory GNU Packages
+@direntry
+* CVS: (cvs). Concurrent Versions System
+@end direntry
+@dircategory Individual utilities
+@direntry
+* cvs: (cvs)CVS commands. Concurrent Versions System
+@end direntry
+
+@comment The titlepage section does not appear in the Info file.
+@titlepage
+@sp 4
+@comment The title is printed in a large font.
+@center @titlefont{Version Management}
+@sp
+@center @titlefont{with}
+@sp
+@center @titlefont{CVS}
+@sp 2
+@center for @sc{cvs} @c ???@value{VERSION}???
+@comment -release-
+@sp 3
+@center Per Cederqvist et al
+
+@comment The following two commands start the copyright page
+@comment for the printed manual. This will not appear in the Info file.
+@page
+@vskip 0pt plus 1filll
+@copyleftnotice
+@end titlepage
+
+@comment ================================================================
+@comment The real text starts here
+@comment ================================================================
+
+@ifnottex
+@c ---------------------------------------------------------------------
+@node Top
+@top
+
+@c <en> This info manual describes how to use and administer
+Esta página manual ensina a como usar e administrar o
+@c <en> @sc{cvs} version @value{VERSION}.
+@sc{cvs} versão @c ???@value{VERSION}???.
+@end ifnottex
+
+@ifinfo
+@copyleftnotice
+@end ifinfo
+
+@c This menu is pretty long. Not sure how easily that
+@c can be fixed (no brilliant ideas right away)...
+@menu
+@c <en>* Overview:: An introduction to CVS
+* Visão Geral:: Uma introdução ao CVS
+@c <en>* Repository:: Where all your sources are stored
+* Repositório:: Onde todos os seus fontes são guardados
+@c <en>* Starting a new project:: Starting a project with CVS
+* Começando um novo projeto:: Começando um projeto com CVS
+@c <en>* Revisions:: Numeric and symbolic names for revisions
+* Revisões:: Nomes numéricos e simbólicos para revisões
+@c <en>* Branching and merging:: Diverging/rejoining branches of development
+* Ramificando e mesclando:: Divergindo/reunindo ramos de desenvolvimento
+@c <en>* Recursive behavior:: CVS descends directories
+* Comportamento recursivo:: CVS adentra nos diretórios
+@c <en>* Adding and removing:: Adding/removing/renaming files/directories
+* Adicionando e removendo:: Adicionando/apagando/renomeando arquivos/diretórios
+@c <en>* History browsing:: Viewing the history of files in various ways
+* Navegação no Histórico:: Vendo o histórico dos arquivos de várias formas
+
+@c <en>CVS and the Real World.
+CVS e o mundo Real.
+-----------------------
+@c <en>* Binary files:: CVS can handle binary files
+* Arquivos binários:: CVS pode lidar com arquivos binários
+@c <en>* Multiple developers:: How CVS helps a group of developers
+* Múltiplos desenvolvedores:: Como CVS ajuda um grupo de desenvolvedores
+@c <en>* Revision management:: Policy questions for revision management
+* Gerenciamento de revisões:: Questões de política para gerenciamento de revisões
+@c <en>* Keyword substitution:: CVS can include the revision inside the file
+* Substituição de palavra-chave:: CVS inclui a revisão dentro do arquivo
+@c <en>* Tracking sources:: Tracking third-party sources
+* Acompanhando fontes:: Acompanhando fontes de terceiros
+@c <en>* Builds:: Issues related to CVS and builds
+* Builds:: Issues related to CVS and builds
+@c <en>* Special Files:: Devices, links and other non-regular files
+* Arquivos especiais:: Dispositivos, ligações e outros arquivos diferentes
+
+@c <en>References.
+Referências.
+-----------
+@c <en>* CVS commands:: CVS commands share some things
+* Comandos do CVS:: Comandos do CVS têm algo em comum
+@c <en>* Invoking CVS:: Quick reference to CVS commands
+* Chamando o CVS:: Referência rápida aos comandos do CVS
+@c <en>* Administrative files:: Reference manual for the Administrative files
+* Arquivos administrativos:: Manual de referência para os arquivos administrativos
+@c <en>* Environment variables:: All environment variables which affect CVS
+* Variáveis de ambiente:: Todas as variáveis de ambiente que afetam o CVS
+@c <en>* Compatibility:: Upgrading CVS versions
+* Compatibilidade:: Upgrading CVS versions
+@c <en>* Troubleshooting:: Some tips when nothing works
+* Resolução de problemas:: Algumas dicas quando nada funciona
+@c <en>* Credits:: Some of the contributors to this manual
+* Créditos:: Alguns dos contribuidores deste manual
+@c <en>* BUGS:: Dealing with bugs in CVS or this manual
+* Paus:: Lidando com paus no CVS ou neste manual
+@c <en>* Index:: Index
+* Indice:: Índice
+@end menu
+
+@c ---------------------------------------------------------------------
+@c <en>@node Overview
+@c <en>@chapter Overview
+@c <en>@cindex Overview
+@node Visão Geral
+@chapter Visão Geral
+@cindex Visão Geral
+
+@c <en>This chapter is for people who have never used
+@c <en>@sc{cvs}, and perhaps have never used version control
+@c <en>software before.
+Este capítulo é para aqueles que nunca usaram o
+@sc{cvs} antes, e talvez nunca tenham usado um programa
+de controle de versões antes.
+
+@c <en>If you are already familiar with @sc{cvs} and are just
+@c <en>trying to learn a particular feature or remember a
+@c <en>certain command, you can probably skip everything here.
+Se você já conhece o @sc{cvs} e está apenas tentando
+aprender sobre uma habilidade em particular ou lembrar
+um certo comando, você provavelmente pode pular tudo
+aqui.
+
+@menu
+@c <en>* What is CVS?:: What you can do with @sc{cvs}
+* O que é CVS?:: O que você pode fazer com @sc{cvs}
+@c <en>* What is CVS not?:: Problems @sc{cvs} doesn't try to solve
+* O que CVS não é?:: Problemas que o @sc{cvs} não tenta resolver
+@c <en>* A sample session:: A tour of basic @sc{cvs} usage
+* Uma sessão de exemplo:: Um tour pelo uso básico do @sc{cvs}
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node What is CVS?
+@c <en>@section What is CVS?
+@c <en>@cindex What is CVS?
+@c <en>@cindex Introduction to CVS
+@c <en>@cindex CVS, introduction to
+@node O que é CVS?
+@section O que é CVS?
+@cindex O que é CVS?
+@cindex Introdução ao CVS
+@cindex CVS, introdução ao
+
+@c <en>@sc{cvs} is a version control system. Using it, you can
+@c <en>record the history of your source files.
+@sc{cvs} é um sistema de controle de versões. Ao
+usá-lo, você pode registrar a história dos seus códigos
+fonte.
+
+@c -- ///
+@c -- ///Those who cannot remember the past are condemned to repeat it.
+@c -- /// -- George Santayana
+@c -- //////
+
+@c -- Insert history quote here!
+@c <en>For example, bugs sometimes creep in when
+@c <en>software is modified, and you might not detect the bug
+@c <en>until a long time after you make the modification.
+@c <en>With @sc{cvs}, you can easily retrieve old versions to see
+@c <en>exactly which change caused the bug. This can
+@c <en>sometimes be a big help.
+Por exemplo, às vezes aparecem erros quando um programa
+é modificado e você não detecta o problema até muito
+tempo depois de você ter feito a modificação. Com
+@sc{cvs}, você pode recuperar versões antigas para ver
+exatamente o que causou o erro. Isto às vezes é de
+grande ajuda.
+
+@c <en>You could of course save every version of every file
+@c <en>you have ever created. This would
+@c <en>however waste an enormous amount of disk space. @sc{cvs}
+@c <en>stores all the versions of a file in a single file in a
+@c <en>clever way that only stores the differences between
+@c <en>versions.
+Você pode, é claro, salvar toda versão de todo arquivo
+que um dia você criou. Mas isto vai consumir um enorme
+espaço no disco. O @sc{cvs} guarda todas as versões de um
+arquivo em um único arquivo em uma forma inteligente
+que guarda apenas as diferenças entre versões.
+
+@c <en>@sc{cvs} also helps you if you are part of a group of people working
+@c <en>on the same project. It is all too easy to overwrite
+@c <en>each others' changes unless you are extremely careful.
+@c <en>Some editors, like @sc{gnu} Emacs, try to make sure that
+@c <en>the same file is never modified by two people at the
+@c <en>same time. Unfortunately, if someone is using another
+@c <en>editor, that safeguard will not work. @sc{cvs} solves this problem
+@c <en>by insulating the different developers from each other. Every
+@c <en>developer works in his own directory, and @sc{cvs} merges
+@c <en>the work when each developer is done.
+@sc{cvs} também ajuda se você é parte de um grupo de
+pessoas trabalhando no mesmo projeto. É muito fácil uns
+sobreescreverem as mudanças de outros se não forem
+extremamente cuidadosos. Alguns editores, como o
+@sc{gnu} Emacs, tentam se certificar de que o mesmo
+arquivo nunca seja modificado por duas pessoas ao mesmo
+tempo. Infelizmente, se alguém estiver usando outro
+editor, está segurança não vai funcionar. O @sc{cvs}
+resolve este problema isolando os desenvolvedores uns
+dos outros. Todo desenvolvedor trabalha em seu próprio
+diretório e o @sc{cvs} mescla o trabalho quando cada
+desenvolvedor tiver terminado.
+
+@c <en>@cindex History of CVS
+@cindex História do CVS
+@c <en>@cindex CVS, history of
+@cindex CVS, história do
+@c <en>@cindex Credits (CVS program)
+@cindex Créditos (programa CVS)
+@c <en>@cindex Contributors (CVS program)
+@cindex Contribuidores (programa CVS)
+@c <en>@sc{cvs} started out as a bunch of shell scripts written by
+@c <en>Dick Grune, posted to the newsgroup
+@c <en>@code{comp.sources.unix} in the volume 6
+@c <en>release of July, 1986. While no actual code from
+@c <en>these shell scripts is present in the current version
+@c <en>of @sc{cvs} much of the @sc{cvs} conflict resolution algorithms
+@c <en>come from them.
+@sc{cvs} começou como um monte de shell scripts
+escritos por Dick Grune, postados no newsgroup
+@code{comp.sources.unix} no volume 6, de Julho de
+1986. Na verdade, nenhum código daqueles scripts está
+presente na versão atual do @sc{cvs}, mas muito dos
+algoritmos de resolução de conflitos do @sc{cvs} vem
+deles.
+
+@c <en>In April, 1989, Brian Berliner designed and coded @sc{cvs}.
+@c <en>Jeff Polk later helped Brian with the design of the @sc{cvs}
+@c <en>module and vendor branch support.
+Em abril de 1989, Brian Berliner projetou e codificou
+@sc{cvs}. Depois, Jeff Polk ajudou Brian com o projeto
+do módulo @sc{cvs} e o suporte ao ramo do fornecedor.
+
+@c <en>@cindex Source, getting CVS source
+@cindex Fontes, adquirindo os fontes do CVS
+@c <en>You can get @sc{cvs} in a variety of ways, including
+@c <en>free download from the internet. For more information
+@c <en>on downloading @sc{cvs} and other @sc{cvs} topics, see:
+Você pode conseguir o @sc{cvs} de várias formas,
+inclusive baixando gratuitamente da internet. Para
+maiores informações sobre baixar o @sc{cvs} e para
+outros tópicos sobre @sc{cvs}, veja:
+
+@example
+@url{http://cvs.nongnu.org/}
+@end example
+
+@c <en>@cindex Mailing list
+@cindex Lista de Discussão
+@c <en>@cindex List, mailing list
+@cindex Lista, lista de discussão
+@c <en>@cindex Newsgroups
+@cindex Newsgroups
+@c <en>There is a mailing list, known as @email{info-cvs@@nongnu.org},
+@c <en>devoted to @sc{cvs}. To subscribe or
+@c <en>unsubscribe
+@c <en>write to
+@c <en>@email{info-cvs-request@@nongnu.org}.
+@c <en>If you prefer a usenet group, there is a one-way mirror (posts to the email
+@c <en>list are usually sent to the news group, but not visa versa) of
+@c <en>@email{info-cvs@@nongnu.org} at @url{news:gnu.cvs.help}. The right
+@c <en>usenet group for posts is @url{news:comp.software.config-mgmt} which is for
+@c <en>@sc{cvs} discussions (along with other configuration
+@c <en>management systems). In the future, it might be
+@c <en>possible to create a
+@c <en>@code{comp.software.config-mgmt.cvs}, but probably only
+@c <en>if there is sufficient @sc{cvs} traffic on
+@c <en>@url{news:comp.software.config-mgmt}.
+Existe uma lista de discussão, conhecida como @email{info-cvs@@nongnu.org},
+dedicada ao @sc{cvs}. Para se cadastrar ou descadastrar nela
+escreva para @email{info-cvs-request@@nongnu.org}. Se você
+preferir um grupo de usenet, existe um espelho de mão
+única (postagens para a lista de email são usualmente
+mandadas para o news group, mas não vice-versa) da lista
+@email{info-cvs@@nongnu.org} em @url{news:gnu.cvs.help}. O
+grupo usenet correto para postagens é o
+@url{news:comp.software.config-mgmt} que é para
+discussões sobre @sc{cvs} (juntamente com outros
+sistemas de gerência de configuração). No futuro, poderá ser criada uma
+@code{comp.software.config-mgmt.cvs}, mas apenas se
+houver bastante tráfego sobre o @sc{cvs} na
+@url{news:comp.software.config-mgmt}.
+@c Other random data is that the tale was very
+@c skeptical of comp.software.config-mgmt.cvs when the
+@c subject came up around 1995 or so (for one
+@c thing, because creating it would be a "reorg" which
+@c would need to take a more comprehensive look at the
+@c whole comp.software.config-mgmt.* hierarchy).
+
+@c <en>You can also subscribe to the @email{bug-cvs@@nongnu.org} mailing list,
+@c <en>described in more detail in @ref{BUGS}. To subscribe
+@c <en>send mail to @email{bug-cvs-request@@nongnu.org}. There is a two-way
+@c <en>usenet mirror (posts to the usenet group are usually sent to the email list and
+@c <en>visa versa) of @email{bug-cvs@@nongnu.org} named @url{news:gnu.cvs.bug}.
+Você também pode se cadastrar na lista de discussão
+@email{bug-cvs@@nongnu.org}, descrita em maiores detalhes
+em @ref{Paus}. Para se cadastrar mande um e-mail para
+@email{bug-cvs-request@@nongnu.org}. Existe um espelho
+usenet de mão-dupla (postagens para o grupo usenet são
+usualmente mandadas para a lista e vice-versa) de
+@email{bug-cvs@@nongnu.org} chamado
+@url{news:gnu.cvs.bug}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node What is CVS not?
+@node O que CVS não é?
+@c <en>@section What is CVS not?
+@section O que CVS não é?
+@c <en>@cindex What is CVS not?
+@cindex O que CVS não é?
+
+@c <en>@sc{cvs} can do a lot of things for you, but it does
+@c <en>not try to be everything for everyone.
+@sc{cvs} pode fazer várias coisas para você, mas não
+tenta fazer tudo para todo mundo.
+
+@table @asis
+@c <en>@item @sc{cvs} is not a build system.
+@item @sc{cvs} não é um sistema de construção (build system).
+
+@c <en>Though the structure of your repository and modules
+@c <en>file interact with your build system
+@c <en>(e.g. @file{Makefile}s), they are essentially
+@c <en>independent.
+Embora a estrutura do seu repositório e arquivos de
+módulo interajam com seu sistema de construção
+(e.g. @file{Makefile}s), eles são essencialmente
+independentes.
+
+@c <en>@sc{cvs} does not dictate how you build anything. It
+@c <en>merely stores files for retrieval in a tree structure
+@c <en>you devise.
+@sc{cvs} não dita como você constroi nada. Ele apenas
+guarda arquivos para recuperação numa estrutura de
+árvore que você concebeu.
+
+@c <en>@sc{cvs} does not dictate how to use disk space in the
+@c <en>checked out working directories. If you write your
+@c <en>@file{Makefile}s or scripts in every directory so they
+@c <en>have to know the relative positions of everything else,
+@c <en>you wind up requiring the entire repository to be
+@c <en>checked out.
+@sc{cvs} não dita como usar o espaço em disco em
+diretórios de trabalho locais. Se você
+escreve seus @file{Makefile}s ou scripts em cada
+diretório, eles têm que saber a posição relativa de
+todo o resto, logo você acaba tendo que pegar todo o
+repositório.
+
+@c <en>If you modularize your work, and construct a build
+@c <en>system that will share files (via links, mounts,
+@c <en>@code{VPATH} in @file{Makefile}s, etc.), you can
+@c <en>arrange your disk usage however you like.
+Se você modularizar o seu trabalho e fizer um sistema
+de construção (build) que irá compartilhar arquivos
+(via links, mounts, @code{VPATH} em @file{Makefile}s,
+etc.), você pode organizar a sua utilização de disco de
+qualquer forma.
+
+@c <en>But you have to remember that @emph{any} such system is
+@c <en>a lot of work to construct and maintain. @sc{cvs} does
+@c <en>not address the issues involved.
+Mas você tem que lembrar que @emph{qualquer} sistema
+desse é muito trabalhoso para construir e
+manter. O @sc{cvs} não se importa com tais questões.
+
+@c <en>Of course, you should place the tools created to
+@c <en>support such a build system (scripts, @file{Makefile}s,
+@c <en>etc) under @sc{cvs}.
+Obviamente, você pode botar as ferramentas criadas para
+auxiliar tal sistema de construção (scripts,
+@file{Makefile}s, etc) dentro do @sc{cvs}.
+
+@c <en>Figuring out what files need to be rebuilt when
+@c <en>something changes is, again, something to be handled
+@c <en>outside the scope of @sc{cvs}. One traditional
+@c <en>approach is to use @code{make} for building, and use
+@c <en>some automated tool for generating the dependencies which
+@c <en>@code{make} uses.
+Definir quais arquivos precisam ser reconstruídos
+quando algo muda é, novamente, algo para ser visto fora
+do escopo do @sc{cvs}. Uma abordagem tradicional é
+usar o @code{make} para construir, e usar alguma
+ferramenta automatizada para gerar as dependências que
+o @code{make} usa.
+
+@c <en>Veja em @ref{Builds}, for more information on doing builds
+@c <en>in conjunction with @sc{cvs}.
+See @ref{Builds}, para mais informações sobre
+construção com @sc{cvs}.
+
+@c <en>@item @sc{cvs} is not a substitute for management.
+@item @sc{cvs} não substitui gerenciamento.
+
+@c <en>Your managers and project leaders are expected to talk
+@c <en>to you frequently enough to make certain you are aware
+@c <en>of schedules, merge points, branch names and release
+@c <en>dates. If they don't, @sc{cvs} can't help.
+Espera-se que seus gerentes e líderes de projetos falem
+com você com a frequência suficiente para que você
+saiba de prazos, pontos de mescla, nomes de ramos e
+datas de lançamento (release). Se eles não o fizerem, o
+@sc{cvs} não pode ajudar.
+
+@c <en>@sc{cvs} is an instrument for making sources dance to
+@c <en>your tune. But you are the piper and the composer. No
+@c <en>instrument plays itself or writes its own music.
+@sc{cvs} é um instrumento para fazer o fonte dançar
+conforme a sua música. Mas você é o maestro e o
+compositor. Nenhum instrumento toca sozinho ou escreve
+sua própria música.
+
+@c <en>@item @sc{cvs} is not a substitute for developer communication.
+@item @sc{cvs} não é um substituto para comunicação entre desenvolvedores.
+
+@c <en>When faced with conflicts within a single file, most
+@c <en>developers manage to resolve them without too much
+@c <en>effort. But a more general definition of ``conflict''
+@c <en>includes problems too difficult to solve without
+@c <en>communication between developers.
+Quando se deparam com conflitos num único arquivo, a
+maioria dos desenvolvedores conseguem resolvê-los sem
+muito esforço. Mas uma definição mais geral de
+``conflito'' inclui problemas tão difíceis de resolver
+que é necessária a comunicação entre os desenvolvedores.
+
+@c <en>@sc{cvs} cannot determine when simultaneous changes
+@c <en>within a single file, or across a whole collection of
+@c <en>files, will logically conflict with one another. Its
+@c <en>concept of a @dfn{conflict} is purely textual, arising
+@c <en>when two changes to the same base file are near enough
+@c <en>to spook the merge (i.e. @code{diff3}) command.
+@sc{cvs} não pode determinar quando é que alterações
+simultâneas em um arquivo, ou vários, vão conflitar
+logicamente umas com as outras. Seu conceito de
+@dfn{conflito} é puramente textual, surgindo quando
+duas alterações num mesmo arquivo base são próximas o
+suficiente para intimidar o comando de mescla
+(i.e. @code{diff3}).
+
+@c <en>@sc{cvs} does not claim to help at all in figuring out
+@c <en>non-textual or distributed conflicts in program logic.
+@sc{cvs} não se propõe a dar qualquer ajuda quanto a
+localizar conflitos não-textuais ou distribuídos na
+lógica de programação.
+
+@c <en>For example: Say you change the arguments to function
+@c <en>@code{X} defined in file @file{A}. At the same time,
+@c <en>someone edits file @file{B}, adding new calls to
+@c <en>function @code{X} using the old arguments. You are
+@c <en>outside the realm of @sc{cvs}'s competence.
+Por exemplo: Digamos que você altere os argumentos da
+função @code{X} definida no arquivo @file{A}. Neste
+instante, alguem altera o arquivo @file{B}, adicionando
+novas chamadas à função @code{X} usando os argumentos
+antigos. Vocês estão fora do escopo da competência do
+@sc{cvs}.
+
+@c <en>Acquire the habit of reading specs and talking to your
+@c <en>peers.
+Adquira o hábito de ler documentação e conversar com
+seus parceiros.
+
+
+@c <en>@item @sc{cvs} does not have change control
+@item @sc{cvs} não tem controle de mudanças
+
+@c <en>Change control refers to a number of things. First of
+@c <en>all it can mean @dfn{bug-tracking}, that is being able
+@c <en>to keep a database of reported bugs and the status of
+@c <en>each one (is it fixed? in what release? has the bug
+@c <en>submitter agreed that it is fixed?). For interfacing
+@c <en>@sc{cvs} to an external bug-tracking system, see the
+@c <en>@file{rcsinfo} and @file{verifymsg} files
+@c <en>(@pxref{Administrative files}).
+Controle de mudanças se refere a várias coisas. Em
+primeiro lugar, pode significar @dfn{bug-tracking
+(busca de erros)}, que é manter uma base de dados de
+erros relatados e o status de cada um (foi consertado?
+em qual lançamento? o submissor do erro concordou que o
+erro foi corrigido?). Para fazer a interface do
+@sc{cvs} com um sistema de bug-tracking externo, veja
+os arquivos @file{rcsinfo} e @file{verifymsg}
+(@pxref{Arquivos administrativos}).
+
+@c <en>Another aspect of change control is keeping track of
+@c <en>the fact that changes to several files were in fact
+@c <en>changed together as one logical change. If you check
+@c <en>in several files in a single @code{cvs commit}
+@c <en>operation, @sc{cvs} then forgets that those files were
+@c <en>checked in together, and the fact that they have the
+@c <en>same log message is the only thing tying them
+@c <en>together. Keeping a @sc{gnu} style @file{ChangeLog}
+@c <en>can help somewhat.
+Outra característica de controle de mudanças é manter
+um controle no fato de que mudanças em vários arquivos
+foram, de fato, uma única mudança lógica. Se você
+devolve vários arquivos numa única operação com
+@code{cvs commit} (efetivar), @sc{cvs} esquece que os arquivos
+foram devolvidos juntos, e o fato de eles terem a mesma
+mensagem de log é a única coisa que os une. Manter um
+@file{ChangeLog} no estilo @sc{gnu} pode de certa forma
+ajudar.
+@c FIXME: should have an xref to a section which talks
+@c more about keeping ChangeLog's with CVS, but that
+@c section hasn't been written yet.
+
+@c <en>Another aspect of change control, in some systems, is
+@c <en>the ability to keep track of the status of each
+@c <en>change. Some changes have been written by a developer,
+@c <en>others have been reviewed by a second developer, and so
+@c <en>on. Generally, the way to do this with @sc{cvs} is to
+@c <en>generate a diff (using @code{cvs diff} or @code{diff})
+@c <en>and email it to someone who can then apply it using the
+@c <en>@code{patch} utility. This is very flexible, but
+@c <en>depends on mechanisms outside @sc{cvs} to make sure
+@c <en>nothing falls through the cracks.
+Outro aspecto do controle de mudanças, em alguns
+sistemas, é a habilidade de se obter informação sobre o
+status de cada mudança. Algumas mudanças foram escritas
+por um certo desenvolvedor, outras foram revisadas por
+um segundo desenvolvedor, e por aí vai. Geralmente, a
+forma de fazer isto com o @sc{cvs} é gerando um diff
+(usando @code{cvs diff} ou @code{diff}) e mandando por
+email para alguem que possa resolver as diferenças usando o
+utilitário @code{patch}. Isto é muito flexível, mas
+depende de mecanismos externos ao @sc{cvs} para
+garantir que nada dê problema.
+
+@c <en>@item @sc{cvs} is not an automated testing program
+@item @sc{cvs} não é um programa de testes automático
+
+@c <en>It should be possible to enforce mandatory use of a
+@c <en>testsuite using the @code{commitinfo} file. I haven't
+@c <en>heard a lot about projects trying to do that or whether
+@c <en>there are subtle gotchas, however.
+é possível reforçar o uso obrigatório de uma suíte de
+testes usando o arquivo @code{commitinfo}. Eu nunca
+ouvi falar muito sobre projetos que tentam fazer isto,
+ou se existem armadilhas sutís nestes casos.
+
+@c <en>@item @sc{cvs} does not have a builtin process model
+@item @sc{cvs} não tem um modelo de processo inerente
+
+@c <en>Some systems provide ways to ensure that changes or
+@c <en>releases go through various steps, with various
+@c <en>approvals as needed. Generally, one can accomplish
+@c <en>this with @sc{cvs} but it might be a little more work.
+@c <en>In some cases you'll want to use the @file{commitinfo},
+@c <en>@file{loginfo}, @file{rcsinfo}, or @file{verifymsg}
+@c <en>files, to require that certain steps be performed
+@c <en>before cvs will allow a checkin. Also consider whether
+@c <en>features such as branches and tags can be used to
+@c <en>perform tasks such as doing work in a development tree
+@c <en>and then merging certain changes over to a stable tree
+@c <en>only once they have been proven.
+alguns sistemas fornecem formas de garantir que
+mudanças ou lançamentos sigam vários passos, com várias
+aprovações obrigatórias. Geralmente, pode-se obter
+isto com o @sc{cvs}, mas acarreta em um pouco mais de
+trabalho. Em alguns casos você vai querer usar o
+arquivo @file{commitinfo}, @file{loginfo},
+@file{rcsinfo}, ou @file{verifymsg} para exigir que
+certos passos sejam executados antes que o cvs permita
+uma devolução (checkin). Também considere se
+características tais como ramos e etiquetas (tags) podem ser usadas
+para realizar tarefas como desenvolver numa árvore de
+desenvolvimento e então mesclar certas mudanças numa
+árvore estável apenas quando eles tenham sido confirmados.
+@end table
+
+@c ---------------------------------------------------------------------
+@c <en>@node A sample session
+@node Uma sessão de exemplo
+@c <en>@section A sample session
+@section Uma sessão de exemplo
+@c <en>@cindex Example of a work-session
+@cindex Exemplo de uma sessão de trabalho
+@c <en>@cindex Getting started
+@cindex Iniciando
+@c <en>@cindex Work-session, example of
+@cindex Sessão de trabalho, exemplo de uma
+@c <en>@cindex tc, Trivial Compiler (example)
+@cindex tc, Trivial Compiler (Compilador trivial) (exemplo)
+@c <en>@cindex Trivial Compiler (example)
+@cindex Trivial Compiler (Compilador trivial) (exemplo)
+
+@c I think an example is a pretty good way to start. But
+@c somewhere in here, maybe after the sample session,
+@c we need something which is kind of
+@c a "roadmap" which is more directed at sketching out
+@c the functionality of CVS and pointing people to
+@c various other parts of the manual. As it stands now
+@c people who read in order get dumped right into all
+@c manner of hair regarding remote repositories,
+@c creating a repository, etc.
+@c
+@c The following was in the old Basic concepts node. I don't
+@c know how good a job it does at introducing modules,
+@c or whether they need to be introduced so soon, but
+@c something of this sort might go into some
+@c introductory material somewhere.
+@ignore
+@cindex Modules (intro)
+The repository contains directories and files, in an
+arbitrary tree. The @dfn{modules} feature can be used
+to group together a set of directories or files into a
+single entity (@pxref{modules}). A typical usage is to
+define one module per project.
+@end ignore
+
+@c <en>As a way of introducing @sc{cvs}, we'll go through a
+@c <en>typical work-session using @sc{cvs}. The first thing
+@c <en>to understand is that @sc{cvs} stores all files in a
+@c <en>centralized @dfn{repository} (@pxref{Repository}); this
+@c <en>section assumes that a repository is set up.
+Vamos apresentar o @sc{cvs} usando numa sessão de
+trabalho típica. A primeira coisa a saber é que
+@sc{cvs} guarda todos os arquivos em um
+@dfn{repository} centralizado (@pxref{Repositório});
+esta sessão assume que um repositório esteja ativo.
+@c I'm not sure that the sentence concerning the
+@c repository quite tells the user what they need to
+@c know at this point. Might need to expand on "centralized"
+@c slightly (maybe not here, maybe further down in the example?)
+
+@c <en>Suppose you are working on a simple compiler. The source
+@c <en>consists of a handful of C files and a @file{Makefile}.
+@c <en>The compiler is called @samp{tc} (Trivial Compiler),
+@c <en>and the repository is set up so that there is a module
+@c <en>called @samp{tc}.
+Suponha que você esteja trabalhando num compilador
+simples. O fonte é um monte de arquivos C e um
+@file{Makefile}. O compilador é chamado @samp{tc}
+(Trivial Compiler, ou Compilador trivial), e o repositório é feito de
+forma que exista um módulo chamado @samp{tc}.
+
+@menu
+@c <en>* Getting the source:: Creating a workspace
+* Obtendo os fontes:: Criando uma área de trabalho
+@c <en>* Committing your changes:: Making your work available to others
+* Efetivando suas alterações:: Disponibilizando seu trabalho para outros
+@c <en>* Cleaning up:: Cleaning up
+* Limpando:: Limpando
+@c <en>* Viewing differences:: Viewing differences
+* Vendo as diferenças:: Vendo as diferenças
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Getting the source
+@node Obtendo os fontes
+@c <en>@subsection Getting the source
+@subsection Obtendo os fontes
+@c <en>@cindex Getting the source
+@cindex Obtendo os fontes
+@c <en>@cindex Checking out source
+@cindex Pegando emprestado os fontes
+@c <en>@cindex Fetching source
+@cindex Recuperando os fontes
+@c <en>@cindex Source, getting from CVS
+@cindex Fonte, pegando do CVS
+@c <en>@cindex Checkout, example
+@cindex Checkout, exemplo
+
+@c <en>The first thing you must do is to get your own working copy of the
+@c <en>source for @samp{tc}. For this, you use the @code{checkout} command:
+A primeira coisa a fazer é pegar sua própria cópia de
+trabalho dos fontes de @samp{tc}. Para isto, use o comando
+@code{checkout} (pegar emprestado):
+
+@example
+$ cvs checkout tc
+@end example
+
+@noindent
+@c <en>This will create a new directory called @file{tc} and populate it with
+@c <en>the source files.
+Isto vai criar um novo diretório chamado @file{tc} e
+povoa-lo com os fontes.
+
+@example
+$ cd tc
+$ ls
+CVS Makefile backend.c driver.c frontend.c parser.c
+@end example
+
+@c <en>The @file{CVS} directory is used internally by
+@c <en>@sc{cvs}. Normally, you should not modify or remove
+@c <en>any of the files in it.
+O diretório @file{CVS} é usado internamente pelo
+@sc{cvs}. Normalmente, você não deve modificar ou
+remover quaisquer arquivos dele.
+
+@c <en>You start your favorite editor, hack away at @file{backend.c}, and a couple
+@c <en>of hours later you have added an optimization pass to the compiler.
+@c <en>A note to @sc{rcs} and @sc{sccs} users: There is no need to lock the files that
+@c <en>you want to edit. @xref{Multiple developers}, for an explanation.
+Você abre o seu editor favorito, trabalha no arquivo
+@file{backend.c}, e algumas horas depois você deixou o
+compilador mais otimizado. Uma observação para usuários
+de @sc{rcs} e @sc{sccs}: Não é necessário travar (lock)
+os arquivos que você quer editar. @xref{Múltiplos
+desenvolvedores}, para uma explicação.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Committing your changes
+@node Efetivando suas alterações
+@c <en>@subsection Committing your changes
+@subsection Efetivando suas alterações
+@c <en>@cindex Committing changes to files
+@cindex Efetivando mudanças nos arquivos
+@c <en>@cindex Log message entry
+@cindex Registro de mensagens de log
+
+@c <en>When you have checked that the compiler is still compilable you decide
+@c <en>to make a new version of @file{backend.c}. This will
+@c <en>store your new @file{backend.c} in the repository and
+@c <en>make it available to anyone else who is using that same
+@c <en>repository.
+Quando você se certificar que o compilador ainda é
+compilável você decide criar uma nova versão de
+@file{backend.c}. Tal ato vai botar o seu novo
+@file{backend.c} no repositório e torná-lo disponível
+para qualquer outra pessoa que esteja usando o mesmo
+repositório.
+
+@example
+$ cvs commit backend.c
+@end example
+
+@noindent
+@c <en>@sc{cvs} starts an editor, to allow you to enter a log
+@c <en>message. You type in ``Added an optimization pass.'',
+@c <en>save the temporary file, and exit the editor.
+@sc{cvs} inicia um editor, para que você possa digitar
+uma messagem de log. Você digita ``Uma otimização adicionada.'',
+salva o arquivo temporário e sai do editor.
+
+@c <en>@cindex CVSEDITOR, environment variable
+@cindex CVSEDITOR, variável de ambiente
+@c <en>@cindex EDITOR, environment variable
+@cindex EDITOR, variável de ambiente
+@c <en>The environment variable @code{$CVSEDITOR} determines
+@c <en>which editor is started. If @code{$CVSEDITOR} is not
+@c <en>set, then if the environment variable @code{$EDITOR} is
+@c <en>set, it will be used. If both @code{$CVSEDITOR} and
+@c <en>@code{$EDITOR} are not set then there is a default
+@c <en>which will vary with your operating system, for example
+@c <en>@code{vi} for unix or @code{notepad} for Windows
+@c <en>NT/95.
+A variável de ambiente @code{$CVSEDITOR} determina qual
+editor vai ser aberto. Se @code{$CVSEDITOR} não existe,
+e se a variável de ambiente @code{$EDITOR} existe, esta
+última é usada. Se nenhuma das duas @code{$CVSEDITOR} e
+@code{$EDITOR} existem então o padrão vai variar
+dependendo do sistema operacional, por exemplo,
+@code{vi} para unix ou @code{notepad} para Windows
+NT/95.
+
+@c <en>@cindex VISUAL, environment variable
+@cindex VISUAL, variável de ambiente
+@c <en>In addition, @sc{cvs} checks the @code{$VISUAL} environment
+@c <en>variable. Opinions vary on whether this behavior is desirable and
+@c <en>whether future releases of @sc{cvs} should check @code{$VISUAL} or
+@c <en>ignore it. You will be OK either way if you make sure that
+@c <en>@code{$VISUAL} is either unset or set to the same thing as
+@c <en>@code{$EDITOR}.
+Adicionalmente, @sc{cvs} busca pela variável de
+ambiente @code{$VISUAL}. Isto gera duas opiniões
+divergentes, se este é um comportamento desejável ou se
+releases futuras do @sc{cvs} devem verificar
+@code{$VISUAL} ou ignorá-la. Você vai estar OK se não
+tiver a variável @code{$VISUAL} ou se ela for igual à
+@code{$EDITOR}.
+
+@c This probably should go into some new node
+@c containing detailed info on the editor, rather than
+@c the intro. In fact, perhaps some of the stuff with
+@c CVSEDITOR and -m and so on should too.
+@c <en>When @sc{cvs} starts the editor, it includes a list of
+@c <en>files which are modified. For the @sc{cvs} client,
+@c <en>this list is based on comparing the modification time
+@c <en>of the file against the modification time that the file
+@c <en>had when it was last gotten or updated. Therefore, if
+@c <en>a file's modification time has changed but its contents
+@c <en>have not, it will show up as modified. The simplest
+@c <en>way to handle this is simply not to worry about it---if
+@c <en>you proceed with the commit @sc{cvs} will detect that
+@c <en>the contents are not modified and treat it as an
+@c <en>unmodified file. The next @code{update} will clue
+@c <en>@sc{cvs} in to the fact that the file is unmodified,
+@c <en>and it will reset its stored timestamp so that the file
+@c <en>will not show up in future editor sessions.
+Quando o @sc{cvs} inicia o editor, ele inclui uma lista
+de arquivos que foram modificados. Para o @sc{cvs}
+cliente, esta lista é baseada na comparação da data de
+modificação do arquivo com a data de modificação que o
+arquivo tinha da última vez que foi pego ou
+atualizado. Entretanto, se a data de modificação de um
+arquivo mudou mas seu conteúdo não, ele vai ser
+considerado modificado. A maneira mais fácil de lidar
+com isto é desconsidarando---se você seguir efetivando,
+o @sc{cvs} vai notar que o conteúdo está intacto e vai
+tratar o arquivo como não-modificado. O próximo
+@code{update} vai dar a dica para o @sc{cvs} de que o
+arquivo está igual, e isto vai restaurar a data,
+fazendo com que o arquivo não apareça nas próximas
+aparições do editor.
+@c FIXCVS: Might be nice if "commit" and other commands
+@c would reset that timestamp too, but currently commit
+@c doesn't.
+@c FIXME: Need to talk more about the process of
+@c prompting for the log message. Like show an example
+@c of what it pops up in the editor, for example. Also
+@c a discussion of how to get the "a)bort, c)ontinue,
+@c e)dit" prompt and what to do with it. Might also
+@c work in the suggestion that if you want a diff, you
+@c should make it before running commit (someone
+@c suggested that the diff pop up in the editor. I'm
+@c not sure that is better than telling people to run
+@c "cvs diff" first if that is what they want, but if
+@c we want to tell people that, the manual possibly
+@c should say it).
+
+@c <en>If you want to avoid
+@c <en>starting an editor you can specify the log message on
+@c <en>the command line using the @samp{-m} flag instead, like
+@c <en>this:
+Se você quer evitar o aparecimento de um editor, você
+pode especificar a mensagem de log na linha de comando
+usando a opção @samp{-m}, desta forma:
+
+@example
+$ cvs commit -m "Uma otimização adicionada" backend.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Cleaning up
+@node Limpando
+@c <en>@subsection Cleaning up
+@subsection Limpando
+@c <en>@cindex Cleaning up
+@cindex Limpando
+@c <en>@cindex Working copy, removing
+@cindex Cópia de trabalho, removendo
+@c <en>@cindex Removing your working copy
+@cindex Removendo sua cópia de trabalho
+@c <en>@cindex Releasing your working copy
+@cindex Lançando sua cópia de trabalho
+
+@c <en>Before you turn to other tasks you decide to remove your working copy of
+@c <en>tc. One acceptable way to do that is of course
+Antes de ir fazer outras tarefas, você decide remover
+sua cópia de trabalho de tc. Uma forma aceitável de
+fazer isto é, obviamente:
+
+@example
+$ cd ..
+$ rm -r tc
+@end example
+
+@noindent
+mas uma forma melhor é usando o comando @code{release} (@pxref{release}):
+
+@example
+$ cd ..
+$ cvs release -d tc
+M driver.c
+? tc
+You have [1] altered files in this repository.
+Are you sure you want to release (and delete) directory `tc': n
+** `release' aborted by user choice.
+@end example
+
+@c <en>The @code{release} command checks that all your modifications have been
+@c <en>committed. If history logging is enabled it also makes a note in the
+@c <en>history file. @xref{history file}.
+O comando @code{release} verifica se todas as suas
+modificações foram efetivadas. Se o registro
+histórico (history log) está ativo ele também escreve uma
+observação no arquivo de histórico. @xref{arquivo
+history (histórico)}.
+
+@c <en>When you use the @samp{-d} flag with @code{release}, it
+@c <en>also removes your working copy.
+Quando você usa a opção @samp{-d} com o @code{release},
+ele também remove a sua cópia de trabalho local.
+
+@c <en>In the example above, the @code{release} command wrote a couple of lines
+@c <en>of output. @samp{? tc} means that the file @file{tc} is unknown to @sc{cvs}.
+@c <en>That is nothing to worry about: @file{tc} is the executable compiler,
+@c <en>and it should not be stored in the repository. @xref{cvsignore},
+@c <en>for information about how to make that warning go away.
+@c <en>@xref{release output}, for a complete explanation of
+@c <en>all possible output from @code{release}.
+No exemplo acima, o comando @code{release} escreve
+poucas linhas de saída. @samp{? tc} significa que o
+arquivo @file{tc} é desconhecido pelo @sc{cvs}. Não há
+nada com que se preocupar: @file{tc} é um compilador
+executável, e não deve ser guardado no
+repositório. @xref{cvsignore}, para ver como fazer para
+sumir com este aviso. @xref{release output}, para uma
+explicação geral de todas as possíveis saídas do
+@code{release}.
+
+@c <en>@samp{M driver.c} is more serious. It means that the
+@c <en>file @file{driver.c} has been modified since it was
+@c <en>checked out.
+@samp{M driver.c} é mais sério. Significa que o arquivo
+@file{driver.c} foi modificado desde quando foi pego.
+
+@c <en>The @code{release} command always finishes by telling
+@c <en>you how many modified files you have in your working
+@c <en>copy of the sources, and then asks you for confirmation
+@c <en>before deleting any files or making any note in the
+@c <en>history file.
+O comando @code{release} sempre termina dizendo quantos
+arquivos modificados você tem em sua cópia de trabalho
+dos fontes, e então pergunta por confirmação antes de
+apagar qualquer arquivo ou escrever qualquer coisa no
+arquivo de histórico.
+
+@c <en>You decide to play it safe and answer @kbd{n @key{RET}}
+@c <en>when @code{release} asks for confirmation.
+Você decide que executar isto é seguro e responde @kbd{n @key{RET}}
+quando @code{release} pede uma confirmação.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Viewing differences
+@node Vendo as diferenças
+@c <en>@subsection Viewing differences
+@subsection Vendo diferenças
+@c <en>@cindex Viewing differences
+@cindex Vendo diferenças
+@c <en>@cindex Diff
+@cindex Diff
+
+@c <en>You do not remember modifying @file{driver.c}, so you want to see what
+@c <en>has happened to that file.
+Você não lembra se modificou @file{driver.c}. Logo,
+você precisa ver o que aconteceu com este arquivo.
+
+@example
+$ cd tc
+$ cvs diff driver.c
+@end example
+
+@c <en>This command runs @code{diff} to compare the version of @file{driver.c}
+@c <en>that you checked out with your working copy. When you see the output
+@c <en>you remember that you added a command line option that enabled the
+@c <en>optimization pass. You check it in, and release the module.
+Este comando roda o @code{diff} para comparar a versão
+de @file{driver.c} que você pegou com a da sua cópia de
+trabalho. Quando você vê a saída, você lembra de ter
+adicionado uma opção de linha de comando que permite a
+otimização. Você devolve e lança (release) o módulo.
+@c FIXME: we haven't yet defined the term "check in".
+
+@example
+@c <en>$ cvs commit -m "Added an optimization pass" driver.c
+$ cvs commit -m "Uma otimização adicionada" driver.c
+Checking in driver.c;
+/usr/local/cvsroot/tc/driver.c,v <-- driver.c
+new revision: 1.2; previous revision: 1.1
+done
+$ cd ..
+$ cvs release -d tc
+? tc
+You have [0] altered files in this repository.
+Are you sure you want to release (and delete) directory `tc': y
+@end example
+
+@c ---------------------------------------------------------------------
+@c <en>@node Repository
+@node Repositório
+@c <en>@chapter The Repository
+@chapter O Repositório
+@c <en>@cindex Repository (intro)
+@cindex Repositório (intro)
+@c <en>@cindex Repository, example
+@cindex Repositório, exemplo
+@c <en>@cindex Layout of repository
+@cindex Estrutura do repositório
+@c <en>@cindex Typical repository
+@cindex Repositório típico
+@c <en>@cindex /usr/local/cvsroot, as example repository
+@cindex /usr/local/cvsroot, como um repositório de exemplo
+@c <en>@cindex cvsroot
+@cindex cvsroot
+
+@c <en>The @sc{cvs} @dfn{repository} stores a complete copy of
+@c <en>all the files and directories which are under version
+@c <en>control.
+O @dfn{repositório} do @sc{cvs} guarda uma cópia
+completa de todos os arquivos e diretórios que estão
+sob controle de versão.
+
+@c <en>Normally, you never access any of the files in the
+@c <en>repository directly. Instead, you use @sc{cvs}
+@c <en>commands to get your own copy of the files into a
+@c <en>@dfn{working directory}, and then
+@c <en>work on that copy. When you've finished a set of
+@c <en>changes, you check (or @dfn{commit}) them back into the
+@c <en>repository. The repository then contains the changes
+@c <en>which you have made, as well as recording exactly what
+@c <en>you changed, when you changed it, and other such
+@c <en>information. Note that the repository is not a
+@c <en>subdirectory of the working directory, or vice versa;
+@c <en>they should be in separate locations.
+Normalmente, você nunca acessa qualquer dos arquivos do
+repositório diretamente. Ao invés disso, você usa os
+comandos do @sc{cvs} para pegar emprestada a sua cópia
+dos arquivos num @dfn{diretório de trabalho}, e então
+trabalhar nesta cópia. Quando você termina um conjunto
+de mudanças, você as @dfn{efetiva} no repositório. O
+repositório então passa a conter as mudanças que você
+fez, assim como gravar exatamente o que você fez,
+quando você fez e outras informações deste
+tipo. Observe que o repositório não é um subdiretório
+do diretório de trabalho nem vice-versa; eles estão em
+locais diferentes.
+@c Need some example, e.g. repository
+@c /usr/local/cvsroot; working directory
+@c /home/joe/sources. But this node is too long
+@c as it is; need a little reorganization...
+
+@c <en>@cindex :local:, setting up
+@cindex :local:, ajustando
+@c <en>@sc{cvs} can access a repository by a variety of
+@c <en>means. It might be on the local computer, or it might
+@c <en>be on a computer across the room or across the world.
+@c <en>To distinguish various ways to access a repository, the
+@c <en>repository name can start with an @dfn{access method}.
+@c <en>For example, the access method @code{:local:} means to
+@c <en>access a repository directory, so the repository
+@c <en>@code{:local:/usr/local/cvsroot} means that the
+@c <en>repository is in @file{/usr/local/cvsroot} on the
+@c <en>computer running @sc{cvs}. For information on other
+@c <en>access methods, see @ref{Remote repositories}.
+@sc{cvs} pode acessar um repositório de várias
+formas. Ele pode estar no mesmo computador, ou num
+computador do outro lado da sala, ou do outro lado do
+mundo. Para distinguir as várias formas de acessar um
+repositório o seu nome deve começar com um
+@dfn{método de acesso}. Por exemplo, o método de acesso
+@code{:local:} significa acessar um diretório que é um
+repositório. Logo, @code{:local:/usr/local/cvsroot}
+significa que o repositório está em
+@file{/usr/local/cvsroot} no computador rodando
+@sc{cvs}. Para informações sobre outros métodos de
+acesso, vá em @ref{Repositórios remotos}.
+
+@c Can se say this more concisely? Like by passing
+@c more of the buck to the Remote repositories node?
+@c <en>If the access method is omitted, then if the repository
+@c <en>starts with @samp{/}, then @code{:local:} is
+@c <en>assumed. If it does not start with @samp{/} then either
+@c <en>@code{:ext:} or @code{:server:} is assumed. For
+@c <en>example, if you have a local repository in
+@c <en>@file{/usr/local/cvsroot}, you can use
+@c <en>@code{/usr/local/cvsroot} instead of
+@c <en>@code{:local:/usr/local/cvsroot}. But if (under
+@c <en>Windows NT, for example) your local repository is
+@c <en>@file{c:\src\cvsroot}, then you must specify the access
+@c <en>method, as in @code{:local:c:/src/cvsroot}.
+Se o método de acesso é omitido e se o repositório
+começa com @samp{/}, então assume-se @code{:local:}. Se
+não começa com @samp{/} então ou @code{:ext:} ou
+@code{:server:} é assumido. Por exemplo, se você tem um
+repositório local em @file{/usr/local/cvsroot}, você
+pode usar @code{/usr/local/cvsroot} ao invés de
+@code{:local:/usr/local/cvsroot}. Mas se (no Windows
+NT, por exemplo) seu repositório local é
+@file{c:\src\cvsroot}, então você deve especificar o
+método de acesso, como em @code{:local:c:/src/cvsroot}.
+
+@c This might appear to go in Repository storage, but
+@c actually it is describing something which is quite
+@c user-visible, when you do a "cvs co CVSROOT". This
+@c isn't necessary the perfect place for that, though.
+@c <en>The repository is split in two parts. @file{$CVSROOT/CVSROOT} contains
+@c <en>administrative files for @sc{cvs}. The other directories contain the actual
+@c <en>user-defined modules.
+O repositório é separado em duas
+partes. @file{$CVSROOT/CVSROOT} contém arquivos
+administrativos do @sc{cvs}. Os outros diretórios
+contém os módulos definidos pelo usuário.
+
+@menu
+@c <en>* Specifying a repository:: Telling CVS where your repository is
+* Especificando um repositório:: Dizendo ao CVS onde está o seu repositório
+@c <en>* Repository storage:: The structure of the repository
+* Armazenamento do repositório:: A estrutura do repositório
+@c <en>* Working directory storage:: The structure of working directories
+* Armazenamento do Diretório de trabalho:: A estrutura dos diretórios de trabalho
+@c <en>* Intro administrative files:: Defining modules
+* Intro aos arquivos administrativos:: Definindo módulos
+@c <en>* Multiple repositories:: Multiple repositories
+* Repositórios múltiplos:: Repositórios múltiplos
+@c <en>* Creating a repository:: Creating a repository
+* Criando um repositório:: Criando um repositório
+@c <en>* Backing up:: Backing up a repository
+* Fazendo backup:: Criando Backup de um repositório
+@c <en>* Moving a repository:: Moving a repository
+* Movendo um repositório:: Movendo um repositório
+@c <en>* Remote repositories:: Accessing repositories on remote machines
+* Repositórios remotos:: Acessando repositórios em máquinas remotas
+@c <en>* Read-only access:: Granting read-only access to the repository
+* Acesso somente-leitura:: Dando acesso somente-leitura ao repositório
+@c <en>* Server temporary directory:: The server creates temporary directories
+* Diretório temporário do servidor:: O servidor cria diretórios temporários
+@end menu
+
+@c <en>@node Specifying a repository
+@node Especificando um repositório
+@c <en>@section Telling CVS where your repository is
+@section Dizendo ao CVS onde está o seu repositório
+
+@c <en>There are several ways to tell @sc{cvs}
+@c <en>where to find the repository. You can name the
+@c <en>repository on the command line explicitly, with the
+@c <en>@code{-d} (for "directory") option:
+Existem várias formas de dizer ao @sc{cvs} onde
+encontrar o repositório. Você pode dar o nome do
+repositório explicitamente na linha de comando, com a
+opção @code{-d} (de "diretório"):
+
+@example
+cvs -d /usr/local/cvsroot checkout yoyodyne/tc
+@end example
+
+@c <en>@cindex .profile, setting CVSROOT in
+@cindex .profile, configurando o CVSROOT no
+@c <en>@cindex .cshrc, setting CVSROOT in
+@cindex .cshrc, configurando o CVSROOT no
+@c <en>@cindex .tcshrc, setting CVSROOT in
+@cindex .tcshrc, configurando o CVSROOT no
+@c <en>@cindex .bashrc, setting CVSROOT in
+@cindex .bashrc, configurando o CVSROOT no
+@c <en>@cindex CVSROOT, environment variable
+@cindex CVSROOT, variável de ambiente
+@c <en> Or you can set the @code{$CVSROOT} environment
+@c <en>variable to an absolute path to the root of the
+@c <en>repository, @file{/usr/local/cvsroot} in this example.
+@c <en>To set @code{$CVSROOT}, @code{csh} and @code{tcsh}
+@c <en>users should have this line in their @file{.cshrc} or
+@c <en>@file{.tcshrc} files:
+ Ou você pode ajustar a variável de ambiente
+@code{$CVSROOT} para um caminho absoluto para a raiz
+(root) do repositório, @file{/usr/local/cvsroot} neste
+exemplo. Para ajustar o @code{$CVSROOT}, usuário de
+@code{csh} e @code{tcsh} devem ter esta linha no seu
+arquivo @file{.cshrc} ou @file{.tcshrc}:
+
+@example
+setenv CVSROOT /usr/local/cvsroot
+@end example
+
+@noindent
+@c <en>@code{sh} and @code{bash} users should instead have these lines in their
+@c <en>@file{.profile} or @file{.bashrc}:
+usuários de @code{sh} e @code{bash} devem, por sua vez,
+ter estas linhas nos seus @file{.profile} ou @file{.bashrc}:
+
+@example
+CVSROOT=/usr/local/cvsroot
+export CVSROOT
+@end example
+
+@c <en>@cindex Root file, in CVS directory
+@cindex O arquivo Root, no diretório CVS
+@c <en>@cindex CVS/Root file
+@cindex O arquivo CVS/Root
+@c <en> A repository specified with @code{-d} will
+@c <en>override the @code{$CVSROOT} environment variable.
+@c <en>Once you've checked a working copy out from the
+@c <en>repository, it will remember where its repository is
+@c <en>(the information is recorded in the
+@c <en>@file{CVS/Root} file in the working copy).
+ Um repositório especificado com @code{-d} se
+sobrepõe à variável de ambiente @code{$CVSROOT}. Uma
+vez que você tenha pego emprestada uma cópia de
+trabalho do repositório, ela vai se lembrar onde está o
+seu repositório (a informação é registrada no arquivo
+@file{CVS/Root} na cópia de trabalho).
+
+@c <en>The @code{-d} option and the @file{CVS/Root} file both
+@c <en>override the @code{$CVSROOT} environment variable. If
+@c <en>@code{-d} option differs from @file{CVS/Root}, the
+@c <en>former is used. Of course, for proper operation they
+@c <en>should be two ways of referring to the same repository.
+Tanto a opção @code{-d} quanto o arquivo
+@file{CVS/Root} sobreescrevem a variável de ambiente
+@code{$CVSROOT}. Se a opção @code{-d} é diferente do
+@file{CVS/Root}, a primeira é usada. Obviamente, para
+operações corretas, elas devem ser duas formas de
+referenciar o mesmo repositório.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Repository storage
+@node Armazenamento do repositório
+@c <en>@section How data is stored in the repository
+@section Como os dados são guardados no repositório
+@c <en>@cindex Repository, how data is stored
+@cindex Repositório, como os dados são guardados no
+
+@c <en>For most purposes it isn't important @emph{how}
+@c <en>@sc{cvs} stores information in the repository. In
+@c <en>fact, the format has changed in the past, and is likely
+@c <en>to change in the future. Since in almost all cases one
+@c <en>accesses the repository via @sc{cvs} commands, such
+@c <en>changes need not be disruptive.
+Para a maioria das aplicações, não importa @emph{como}
+o @sc{cvs} guarda as informações no repositório. De
+fato, o formato mudou no passado, e provavelmente vai
+mudar no futuro. Já que em quase todo os casos o acesso
+ao repositório é feito via comandos do @sc{cvs}, tais
+mudanças não serão radicais.
+
+@c <en>However, in some cases it may be necessary to
+@c <en>understand how @sc{cvs} stores data in the repository,
+@c <en>for example you might need to track down @sc{cvs} locks
+@c <en>(@pxref{Concurrency}) or you might need to deal with
+@c <en>the file permissions appropriate for the repository.
+Entretanto, em alguns casos pode ser necessário
+entender como o @sc{cvs} guarda os dados no
+repositório. Por exemplo, você pode precisar localizar
+travas do @sc{cvs} (@pxref{Concorrência}) ou você pode
+precisar lidar com permissões de arquivos apropriadas
+para o repositório.
+
+@menu
+@c <en>* Repository files:: What files are stored in the repository
+* Arquivos do repositório:: Quais arquivos são guardados no repositório
+@c <en>* File permissions:: File permissions
+* Permissões de arquivos:: Permisões de arquivos
+@c <en>* Windows permissions:: Issues specific to Windows
+* Permissões no Windows:: Questões específicas ao Windows
+@c <en>* Attic:: Some files are stored in the Attic
+* Attic:: Alguns arquivos são guardados no Attic
+@c <en>* CVS in repository:: Additional information in CVS directory
+* CVS no repositório:: Informações adicionais no diretório CVS
+@c <en>* Locks:: CVS locks control concurrent accesses
+* Travas:: Travas do CVS controlam acesso concorrente
+@c <en>* CVSROOT storage:: A few things about CVSROOT are different
+* Armazenamento do CVSROOT:: Umas poucas coisas sobre CVSROOT são diferentes
+@end menu
+
+@c <en>@node Repository files
+@node Arquivos do repositório
+@c <en>@subsection Where files are stored within the repository
+@subsection Onde arquivos são guardados dentro do repositório
+
+@c @cindex Filenames, legal
+@c @cindex Legal filenames
+@c Somewhere we need to say something about legitimate
+@c characters in filenames in working directory and
+@c repository. Not "/" (not even on non-unix). And
+@c here is a specific set of issues:
+@c Files starting with a - are handled inconsistently. They can not
+@c be added to a repository with an add command, because it they are
+@c interpreted as a switch. They can appear in a repository if they are
+@c part of a tree that is imported. They can not be removed from the tree
+@c once they are there.
+@c Note that "--" *is* supported (as a
+@c consequence of using GNU getopt). Should document
+@c this somewhere ("Common options"?). The other usual technique,
+@c "./-foo", isn't as effective, at least for "cvs add"
+@c which doesn't support pathnames containing "/".
+
+@c <en>The overall structure of the repository is a directory
+@c <en>tree corresponding to the directories in the working
+@c <en>directory. For example, supposing the repository is in
+A estrutura geral do repositório é uma árvore de
+diretórios correspondendo aos diretórios no diretório
+de trabalho. Por exemplo, suponha que o repositório
+está em
+
+@example
+/usr/local/cvsroot
+@end example
+
+@noindent
+@c <en>here is a possible directory tree (showing only the
+@c <en>directories):
+Aqui está uma possível árvore de diretórios (mostrando
+apenas os diretórios):
+
+@example
+@t{/usr}
+ |
+ +--@t{local}
+ | |
+ | +--@t{cvsroot}
+ | | |
+ | | +--@t{CVSROOT}
+@c <en> | (administrative files)
+ | (arquivos administrativos)
+ |
+ +--@t{gnu}
+ | |
+ | +--@t{diff}
+@c <en> | | (source code to @sc{gnu} diff)
+ | | (código fonte do @sc{gnu} diff)
+ | |
+ | +--@t{rcs}
+@c <en> | | (source code to @sc{rcs})
+ | | (código fonte do @sc{rcs})
+ | |
+ | +--@t{cvs}
+@c <en> | (source code to @sc{cvs})
+ | (código fonte do @sc{cvs})
+ |
+ +--@t{yoyodyne}
+ |
+ +--@t{tc}
+ | |
+ | +--@t{man}
+ | |
+ | +--@t{testing}
+ |
+ +--(other Yoyodyne software)
+@end example
+
+@c <en>With the directories are @dfn{history files} for each file
+@c <en>under version control. The name of the history file is
+@c <en>the name of the corresponding file with @samp{,v}
+@c <en>appended to the end. Here is what the repository for
+@c <en>the @file{yoyodyne/tc} directory might look like:
+Nos diretórios estão os @dfn{arquivos de histórico} para
+cada arquivo sob controle de versão. O nome do arquivo
+de histórico é o nome do arquivo correspondente com um
+@samp{,v} no final. Aqui está como o repositório do
+diretório @file{yoyodyne/tc} deve se parecer:
+@c FIXME: Should also mention CVS (CVSREP)
+@c FIXME? Should we introduce Attic with an xref to
+@c Attic? Not sure whether that is a good idea or not.
+@example
+ @code{$CVSROOT}
+ |
+ +--@t{yoyodyne}
+ | |
+ | +--@t{tc}
+ | | |
+ +--@t{Makefile,v}
+ +--@t{backend.c,v}
+ +--@t{driver.c,v}
+ +--@t{frontend.c,v}
+ +--@t{parser.c,v}
+ +--@t{man}
+ | |
+ | +--@t{tc.1,v}
+ |
+ +--@t{testing}
+ |
+ +--@t{testpgm.t,v}
+ +--@t{test2.t,v}
+@end example
+
+@c <en>@cindex History files
+@cindex Arquivos de histórico
+@c <en>@cindex RCS history files
+@cindex Arquivos de histórico do RCS
+@c The first sentence, about what history files
+@c contain, is kind of redundant with our intro to what the
+@c repository does in node Repository....
+@c <en>The history files contain, among other things, enough
+@c <en>information to recreate any revision of the file, a log
+@c <en>of all commit messages and the user-name of the person
+@c <en>who committed the revision. The history files are
+@c <en>known as @dfn{RCS files}, because the first program to
+@c <en>store files in that format was a version control system
+@c <en>known as @sc{rcs}. For a full
+@c <en>description of the file format, see the @code{man} page
+@c <en>@cite{rcsfile(5)}, distributed with @sc{rcs}, or the
+@c <en>file @file{doc/RCSFILES} in the @sc{cvs} source
+@c <en>distribution. This
+@c <en>file format has become very common---many systems other
+@c <en>than @sc{cvs} or @sc{rcs} can at least import history
+@c <en>files in this format.
+Os arquivos de histórico contém, entre outras coisas,
+informações suficientes para recriar qualquer revisão
+do arquivo, um log com todas as mensagens ???de
+commit??? e o usuário que efetivou (commit) a
+@comment This is the same as a "log message", "log entry", or whatever else
+@comment you might want to call it. It is sometimes called a "commit message"
+@comment in this manual because it is entered into the log at commit time.
+@comment -DRP
+revisão. Os arquivos de histórico são conhecidos como
+@dfn{arquivos RCS} (RCS files), pois o primeiro
+programa a guardar arquivos neste formato foi o sistema
+de controle de versões conhecido como @sc{rcs}. Para
+uma descrição completa do formato de arquivo, leia a
+página @code{man} @cite{rcsfile(5)}, distribuída com o
+@sc{rcs}, ou o arquivo @file{doc/RCSFILES} na
+distribuição dos fontes do @sc{cvs}. Este formato de
+arquivo se tornou muito comum---muitos sistemas além do
+@sc{cvs} e do @sc{rcs} podem, pelo menos, importar
+arquivos de histórico neste formato.
+@c FIXME: Think about including documentation for this
+@c rather than citing it? In the long run, getting
+@c this to be a standard (not sure if we can cope with
+@c a standards process as formal as IEEE/ANSI/ISO/etc,
+@c though...) is the way to go, so maybe citing is
+@c better.
+
+@c <en>The @sc{rcs} files used in @sc{cvs} differ in a few
+@c <en>ways from the standard format. The biggest difference
+@c <en>is magic branches; for more information see @ref{Magic
+@c <en>branch numbers}. Also in @sc{cvs} the valid tag names
+@c <en>are a subset of what @sc{rcs} accepts; for @sc{cvs}'s
+@c <en>rules see @ref{Tags}.
+Os arquivos @sc{rcs} usados no @sc{cvs} diferem em
+algumas poucas coisas do formato padrão. A maior
+diferença são os ramos mágicos; para mais informações
+veja em @ref{Números de ramos mágicos}. Além disso, no
+@sc{cvs} os nomes válidos de etiquetas (tags) é um subconjunto dos
+que são aceitos pelo @sc{rcs}; para regras do @sc{cvs},
+leia em @ref{Etiquetas}.
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c <en>@node File permissions
+@node Permissões de arquivos
+@c <en>@subsection File permissions
+@subsection Permissões de arquivos
+@c -- Move this to @node Creating a repository or similar
+@c <en>@cindex Security, file permissions in repository
+@cindex Segurança, permissões de arquivos no repositório
+@c <en>@cindex File permissions, general
+@cindex Permissões de arquivos, geral
+@c <en>@cindex Permissions, general
+@cindex Permissões, geral
+@c FIXME: we need to somehow reflect "permissions in
+@c repository" versus "permissions in working
+@c directory" in the index entries.
+@c <en>@cindex Group, UNIX file permissions, in repository
+@cindex Grupo, permissões de arquivos UNIX, no repositório
+@c <en>@cindex Read-only files, in repository
+@cindex Arquivos somente-leitura, no repositório
+@c <en>All @samp{,v} files are created read-only, and you
+@c <en>should not change the permission of those files. The
+@c <en>directories inside the repository should be writable by
+@c <en>the persons that have permission to modify the files in
+@c <en>each directory. This normally means that you must
+@c <en>create a UNIX group (see group(5)) consisting of the
+@c <en>persons that are to edit the files in a project, and
+@c <en>set up the repository so that it is that group that
+@c <en>owns the directory.
+@c <en>(On some systems, you also need to set the set-group-ID-on-execution bit
+@c <en>on the repository directories (see chmod(1)) so that newly-created files
+@c <en>and directories get the group-ID of the parent directory rather than
+@c <en>that of the current process.)
+Todos os arquivos @samp{,v} são criados
+somente-leitura, e você não deve mudar as permissões
+destes arquivos. Os diretórios dentro do repositório
+devem dar permissão de escrita para as pessoas que tem
+permissão para modificar os arquivos em cada diretório.
+Isto normalmente significa que você deve criar um grupo
+do UNIX (veja em group(5)) consistindo nas pessoas que
+vão editar os arquivos num projeto, e ajustar o
+repositório tal que aquele grupo seja o dono do
+diretório. (Em alguns sistemas, você também vai
+precisar ajustar o bit set-group-ID-on-execution nos
+diretórios do repositório (veja em chmod(1)) de forma
+que arquivos e diretório criados recebam o ID de grupo
+do diretório pai e não do processo atual.)
+
+@c See also comment in commitinfo node regarding cases
+@c which are really awkward with unix groups.
+
+@c <en>This means that you can only control access to files on
+@c <en>a per-directory basis.
+Isto significa que você pode apenas controlar o acesso
+aos arquivos por diretório.
+
+@c <en>Note that users must also have write access to check
+@c <en>out files, because @sc{cvs} needs to create lock files
+@c <en>(@pxref{Concurrency}). You can use LockDir in CVSROOT/config
+@c <en>to put the lock files somewhere other than in the repository
+@c <en>if you want to allow read-only access to some directories
+@c <en>(@pxref{config}).
+Observe que os usuários devem ter direito de escrita
+para pegar arquivos emprestados, já que o @sc{cvs} tem
+que criar arquivos de trava (@pxref{Concorrência}). Você
+pode usar LockDir (diretório de trava) no CVSROOT/config
+para botar os arquivos de trava num lugar fora do
+repositório se você quer permitir acesso
+somente-leitura a alguns diretórios (@pxref{config}).
+
+@c CVS seems to use CVSUMASK in picking permissions for
+@c val-tags, but maybe we should say more about this.
+@c Like val-tags gets created by someone who doesn't
+@c have CVSUMASK set right?
+@c <en>@cindex CVSROOT/val-tags file, and read-only access to projects
+@cindex O arquivo CVSROOT/val-tags, e acesso somente-leitura a projetos
+@c <en>@cindex val-tags file, and read-only access to projects
+@cindex O arquivo val-tags, e acesso somente-leitura a projetos
+@c <en>Also note that users must have write access to the
+@c <en>@file{CVSROOT/val-tags} file. @sc{cvs} uses it to keep
+@c <en>track of what tags are valid tag names (it is sometimes
+@c <en>updated when tags are used, as well as when they are
+@c <en>created).
+Observe também que os usuários devem ter permissão de
+escrita ao arquivo @file{CVSROOT/val-tags}. O @sc{cvs} usa
+tal arquivo para ter controle sobre quais etiquetas
+(tags) são nomes de etiquetas válidos (é às vezes
+atualizado quando etiquetas são usadas ou criadas).
+
+@c <en>Each @sc{rcs} file will be owned by the user who last
+@c <en>checked it in. This has little significance; what
+@c <en>really matters is who owns the directories.
+Cada arquivo @sc{rcs} vai pertencer ao usuário que o
+devolveu por último. Isto tem pouco significado; o que
+realmente importa é quem possui os diretórios.
+
+@c <en>@cindex CVSUMASK, environment variable
+@cindex CVSUMASK, variável de ambiente
+@c <en>@cindex Umask, for repository files
+@cindex Umask, para arquivos do repositório
+@c <en>@sc{cvs} tries to set up reasonable file permissions
+@c <en>for new directories that are added inside the tree, but
+@c <en>you must fix the permissions manually when a new
+@c <en>directory should have different permissions than its
+@c <en>parent directory. If you set the @code{CVSUMASK}
+@c <en>environment variable that will control the file
+@c <en>permissions which @sc{cvs} uses in creating directories
+@c <en>and/or files in the repository. @code{CVSUMASK} does
+@c <en>not affect the file permissions in the working
+@c <en>directory; such files have the permissions which are
+@c <en>typical for newly created files, except that sometimes
+@c <en>@sc{cvs} creates them read-only (see the sections on
+@c <en>watches, @ref{Setting a watch}; -r, @ref{Global
+@c <en>options}; or @code{CVSREAD}, @ref{Environment variables}).
+O @sc{cvs} tenta ajustar de forma razoável as permissões para novos
+diretórios que vão sendo adicionados na árvore, mas
+você vai ter que mudar as permissões manualmente quando
+um novo diretório deve ter permissões diferentes das do
+seu diretório pai. Se você ajusta a variável de
+ambiente @code{CVSUMASK} ela vai controlar as
+permissões que o @sc{cvs} usa na criação de diretórios
+e/ou arquivos no repositório. @code{CVSUMASK} não mexe
+nas permissões do diretório de trabalho; tais arquivos
+têm as permissões que são típicas para novos arquivos,
+exceto que algumas vezes o @sc{cvs} cria os arquivos
+somente-leitura (veja as seções em ???watches???,
+@comment From Webster's:
+@comment 1. The act of watching; forbearance of sleep; vigil; wakeful,
+@comment vigilant, or constantly observant attention; close
+@comment observation; guard; preservative or preventive vigilance;
+@comment formerly, a watching or guarding by night.
+@comment
+@comment A "watch" in CVS terminology, is the command run to request
+@comment notifications of file status changes. Thus CVS keeps a "watch" on the
+@comment file for you and notifies you of changes. When you have requested
+@comment that CVS "watch" several files, it is said to be keeping "watches".
+@comment -DRP
+@ref{Ajustando um ???watch???}; -r, @ref{Opções globais}; or
+@code{CVSREAD}, @ref{Variáveis de ambiente}).
+@c FIXME: Need more discussion of which
+@c group should own the file in the repository.
+@c Include a somewhat detailed example of the usual
+@c case where CVSUMASK is 007, the developers are all
+@c in a group, and that group owns stuff in the
+@c repository. Need to talk about group ownership of
+@c newly-created directories/files (on some unices,
+@c such as SunOS4, setting the setgid bit on the
+@c directories will make files inherit the directory's
+@c group. On other unices, your mileage may vary. I
+@c can't remember what POSIX says about this, if
+@c anything).
+
+@c <en>Note that using the client/server @sc{cvs}
+@c <en>(@pxref{Remote repositories}), there is no good way to
+@c <en>set @code{CVSUMASK}; the setting on the client machine
+@c <en>has no effect. If you are connecting with @code{rsh}, you
+@c <en>can set @code{CVSUMASK} in @file{.bashrc} or @file{.cshrc}, as
+@c <en>described in the documentation for your operating
+@c <en>system. This behavior might change in future versions
+@c <en>of @sc{cvs}; do not rely on the setting of
+@c <en>@code{CVSUMASK} on the client having no effect.
+Observe que ao usar o @sc{cvs} cliente/servidor
+(@pxref{Repositórios remotos}), não há uma boa maneira
+de ajustar o @code{CVSUMASK}; o ajuste na máquina
+cliente não tem efeito. Se você está se conectando com
+@code{rsh}, você pode ajustar o @code{CVSUMASK} em
+@file{.bashrc} ou @file{.cshrc}, como descrito na
+documentação de seu sistema operacional. Este
+comportamento pode mudar em futuras versões do
+@sc{cvs}; Não se basear na configuração do @code{CVSUMASK}
+no cliente não afeta nada.
+@c FIXME: need to explain what a umask is or cite
+@c someplace which does.
+@c
+@c There is also a larger (largely separate) issue
+@c about the meaning of CVSUMASK in a non-unix context.
+@c For example, whether there is
+@c an equivalent which fits better into other
+@c protection schemes like POSIX.6, VMS, &c.
+@c
+@c FIXME: Need one place which discusses this
+@c read-only files thing. Why would one use -r or
+@c CVSREAD? Why would one use watches? How do they
+@c interact?
+@c
+@c FIXME: We need to state
+@c whether using CVSUMASK removes the need for manually
+@c fixing permissions (in fact, if we are going to mention
+@c manually fixing permission, we better document a lot
+@c better just what we mean by "fix").
+
+@c <en>Using pserver, you will generally need stricter
+@c <en>permissions on the @sc{cvsroot} directory and
+@c <en>directories above it in the tree; see @ref{Password
+@c <en>authentication security}.
+Quando usar pserver, você deve ser, em geral, mais mais
+restritivo com permissões no diretório @sc{cvsroot} e
+nos diretórios abaixo dele na árvore; veja em
+@ref{Segurança com autenticação por senha}.
+
+@c <en>@cindex Setuid
+@cindex Setuid
+@c <en>@cindex Setgid
+@cindex Setgid
+@c <en>@cindex Security, setuid
+@cindex Segurança, setuid
+@c <en>@cindex Installed images (VMS)
+@cindex ???Installed images??? (VMS)
+@comment I have no idea what I could tell you to help you translate this since
+@comment I know little of the VMS operating system. Perhaps you could look
+@comment this up in some VMS documentation somewhere?
+@comment -DRP
+@c <en>Some operating systems have features which allow a
+@c <en>particular program to run with the ability to perform
+@c <en>operations which the caller of the program could not.
+@c <en>For example, the set user ID (setuid) or set group ID
+@c <en>(setgid) features of unix or the installed image
+@c <en>feature of VMS. @sc{cvs} was not written to use such
+@c <en>features and therefore attempting to install @sc{cvs} in
+@c <en>this fashion will provide protection against only
+@c <en>accidental lapses; anyone who is trying to circumvent
+@c <en>the measure will be able to do so, and depending on how
+@c <en>you have set it up may gain access to more than just
+@c <en>@sc{cvs}. You may wish to instead consider pserver. It
+@c <en>shares some of the same attributes, in terms of
+@c <en>possibly providing a false sense of security or opening
+@c <en>security holes wider than the ones you are trying to
+@c <en>fix, so read the documentation on pserver security
+@c <en>carefully if you are considering this option
+@c <en>(@ref{Password authentication security}).
+alguns sistemas operacionais têm a habilidade de
+permitir que um programa execute com a habilidade de
+executar certas operações que quem chamou o programa
+não não tem. Por exemplo, os set user ID (setuid) ou
+set group ID (setgid) do unix ou a caracteristica de
+installed image do VMS. @sc{cvs} não foi escrito para
+usar tais habilidades, logo, tentar instalar o @sc{cvs}
+nesta forma vai gerar proteção apenas contra erros
+acidentais; qualquer um que esteja tentando driblar a
+segurança vai ser capaz de fazê-lo,
+e dependendo de como você configurou, o invasor pode ganhar
+acesso até a mais do que apenas o @sc{cvs}. Você pode
+estar considerando o uso do pserver. Ele compartilha
+alguns dos mesmos atributos, em termos de possivelmente
+fornecer uma falsa sensação de segurança ou de abrir
+buracos de segurança ainda maiores dos que os que você
+quer fechar. Portanto leia a documentação de segurança
+com pserver cuidadosamente se você está pensando nesta
+opção (@ref{Segurança com autenticação por senha}).
+
+@c <en>@node Windows permissions
+@node Permissões no Windows
+@c <en>@subsection File Permission issues specific to Windows
+@subsection Questões sobre permissões de arquivos específicas ao Windows
+@c <en>@cindex Windows, and permissions
+@cindex Windows, e permissões
+@c <en>@cindex File permissions, Windows-specific
+@cindex Permissões de arquivos, específicas ao Windows
+@c <en>@cindex Permissions, Windows-specific
+@cindex Permissões, específicas ao Windows
+
+@c <en>Some file permission issues are specific to Windows
+@c <en>operating systems (Windows 95, Windows NT, and
+@c <en>presumably future operating systems in this family.
+@c <en>Some of the following might apply to OS/2 but I'm not
+@c <en>sure).
+Algumas questões sobre permissões de arquivos são
+específicas ao sistema operacional Windows (Windows 95,
+Windows NT e presumivelmente futuros sistemas
+operacionais nesta família. Algumas coisas abaixo se
+aplicam ao OS/2 mas não estou bem certo).
+
+@c <en>If you are using local @sc{cvs} and the repository is on a
+@c <en>networked file system which is served by the Samba SMB
+@c <en>server, some people have reported problems with
+@c <en>permissions. Enabling WRITE=YES in the samba
+@c <en>configuration is said to fix/workaround it.
+@c <en>Disclaimer: I haven't investigated enough to know the
+@c <en>implications of enabling that option, nor do I know
+@c <en>whether there is something which @sc{cvs} could be doing
+@c <en>differently in order to avoid the problem. If you find
+@c <en>something out, please let us know as described in
+@c <en>@ref{BUGS}.
+Se você está usando um @sc{cvs} local e o repositório
+está num sistema de arquivos em rede de um servidor
+Samba SMB, algumas pessoas relataram problemas com
+permissões. Habilitando WRITE=YES na configuração do
+samba conserta/resolve. ???Disclaimer:??? Eu não
+@comment "Webster's Revised Unabridged Dictionary (1913)"
+@comment Disclaimer Dis*claim"er, n.
+@comment 1. One who disclaims, disowns, or renounces.
+@comment
+@comment 2. (Law) A denial, disavowal, or renunciation, as of a title,
+@comment claim, interest, estate, or trust; relinquishment or
+@comment waiver of an interest or estate. --Burrill.
+@comment
+@comment 3. A public disavowal, as of pretensions, claims, opinions,
+@comment and the like. --Burke.
+@comment
+@comment In other words, "Warning:", or "Caution:", might be appropriate.
+@comment -DRP
+investiguei o suficiente as implicações de habilitar
+esta opção, nem sei se há algo que o @sc{cvs} poderia
+fazer de diferente para evitar este problema. Se você
+souber de algo, por favor nos ponha a par como descrito
+em @ref{Paus}.
+
+@c <en>@node Attic
+@node Attic
+@c <en>@subsection The attic
+@subsection O attic
+@c <en>@cindex Attic
+@cindex Attic
+
+@c <en>You will notice that sometimes @sc{cvs} stores an
+@c <en>@sc{rcs} file in the @code{Attic}. For example, if the
+@c <en>@sc{cvsroot} is @file{/usr/local/cvsroot} and we are
+@c <en>talking about the file @file{backend.c} in the
+@c <en>directory @file{yoyodyne/tc}, then the file normally
+@c <en>would be in
+Você deve ter notado que às vezes o @sc{cvs} guarda um
+arquivo @sc{rcs} no @code{Attic}. Por exemplo, se o
+@sc{cvsroot} é @file{/usr/local/cvsroot} e nós estamos
+falando sobre o arquivo @file{backend.c} no diretório
+@file{yoyodyne/tc}, então o arquivo normalmente deve
+estar em
+
+@example
+/usr/local/cvsroot/yoyodyne/tc/backend.c,v
+@end example
+
+@noindent
+@c <en>but if it goes in the attic, it would be in
+mas se ele vai para o attic, ele deve estar em
+
+@example
+/usr/local/cvsroot/yoyodyne/tc/Attic/backend.c,v
+@end example
+
+@noindent
+@c <en>@cindex Dead state
+@cindex Estado morto
+@c <en>. It should not matter from a user point of
+@c <en>view whether a file is in the attic; @sc{cvs} keeps
+@c <en>track of this and looks in the attic when it needs to.
+@c <en>But in case you want to know, the rule is that the RCS
+@c <en>file is stored in the attic if and only if the head
+@c <en>revision on the trunk has state @code{dead}. A
+@c <en>@code{dead} state means that file has been removed, or
+@c <en>never added, for that revision. For example, if you
+@c <en>add a file on a branch, it will have a trunk revision
+@c <en>in @code{dead} state, and a branch revision in a
+@c <en>non-@code{dead} state.
+ao invés. Não importa ao usuário onde, dentro do Attic,
+fica o arquivo; @sc{cvs} mantém controle disto e busca
+no Attic quando é preciso. Mas caso você queira saber,
+a regra é que o arquivo RCS é guardado no attic se e
+somente se a ???head revision??? no tronco está no
+@comment "Head", at the front, etc. In this case, refers to the most recent
+@comment revision on the trunk, like the head of a snake would be in front.
+@comment In English, the "head of a line" is the person in front and the "tail"
+@comment the person in back.
+@comment -DRP
+estado @code{morto} (dead). Um estado @code{morto} significa
+que o arquivo foi removido, ou nunca foi adicionado,
+naquela revisão. Por exemplo, se você adiciona um
+arquivo num ramo, ele vai ter uma revisão de
+tronco num estado @code{morto} e uma revisão de
+ramo num estado não-@code{morto}.
+@c Probably should have some more concrete examples
+@c here, or somewhere (not sure exactly how we should
+@c arrange the discussion of the dead state, versus
+@c discussion of the attic).
+
+@c <en>@node CVS in repository
+@node CVS no repositório
+@c <en>@subsection The CVS directory in the repository
+@subsection O diretório CVS no repositório
+@c <en>@cindex CVS directory, in repository
+@cindex diretório CVS, no repositório
+
+@c <en>The @file{CVS} directory in each repository directory
+@c <en>contains information such as file attributes (in a file
+@c <en>called @file{CVS/fileattr}. In the
+@c <en>future additional files may be added to this directory,
+@c <en>so implementations should silently ignore additional
+@c <en>files.
+O diretório @file{CVS} em cada diretório do repositório
+contém informações tais como atributos de arquivos (num
+arquivo chamado @file{CVS/fileattr}. No futuro novos
+arquivos ficarão neste diretório, logo, implementações
+devem ignorar em silêncio arquivos adicionais.
+
+@c <en>This behavior is implemented only by @sc{cvs} 1.7 and
+@c <en>later; for details see @ref{Watches Compatibility}.
+Este comportamento é implementado apenas pelo @sc{cvs}
+1.7 e posteriores; para detalhes veja em
+@ref{Compatibilidade de ???Watches???}.
+@comment As "watches", previously.
+@comment -DRP
+
+@c <en>The format of the fileattr file is a series of entries
+@c <en>of the following form (where @samp{@{} and @samp{@}}
+@c <en>means the text between the braces can be repeated zero
+@c <en>or more times):
+O formato do arquivo fileattr é uma série de entradas
+da seguinte forma (onde @samp{@{} e @samp{@}}
+significam que o texto entre chaves pode ser repetido
+zero ou várias vezes):
+
+@var{ent-type} @var{filename} <tab> @var{attrname} = @var{attrval}
+ @{; @var{attrname} = @var{attrval}@} <linefeed>
+
+@c <en>@var{ent-type} is @samp{F} for a file, in which case the entry specifies the
+@c <en>attributes for that file.
+@var{ent-type} é @samp{F} para arquivo, neste caso a
+entrada especifica os atributos para tal arquivo.
+
+@c <en>@var{ent-type} is @samp{D},
+@c <en>and @var{filename} empty, to specify default attributes
+@c <en>to be used for newly added files.
+@var{ent-type} é @samp{D},
+e @var{filename} vazio, para especificar atributos
+padrão para serem usados em novos arquivos adicionados.
+
+@c <en>Other @var{ent-type} are reserved for future expansion. @sc{cvs} 1.9 and older
+@c <en>will delete them any time it writes file attributes.
+@c <en>@sc{cvs} 1.10 and later will preserve them.
+Outros @var{ent-type} são reservados para futuras
+expansões. @sc{cvs} 1.9 e anteriores vão deletá-los a
+toda hora que ele escrever atributos de
+arquivos. @sc{cvs} 1.10 e posteriores vão preservá-los.
+
+@c <en>Note that the order of the lines is not significant;
+@c <en>a program writing the fileattr file may
+@c <en>rearrange them at its convenience.
+Observe que a ordem das linhas não é significante; um
+programa escrevendo o arquivo fileattr pode
+rearranjá-las de acordo com sua própria conveniência.
+
+@c <en>There is currently no way of quoting tabs or linefeeds in the
+@c <en>filename, @samp{=} in @var{attrname},
+@c <en>@samp{;} in @var{attrval}, etc. Note: some implementations also
+@c <en>don't handle a NUL character in any of the fields, but
+@c <en>implementations are encouraged to allow it.
+Não existe atualmente uma forma de tratar tabulações ou quebras de linha
+como caractere no nome do arquivo, @samp{=} em @var{attrname},
+@samp{;} em @var{attrval}, etc. Obs.: algumas
+implementações também não manipulam o caractere NUL em
+nenhum dos campos, mas encorajamos implementações que
+permitam isto.
+
+@c <en>By convention, @var{attrname} starting with @samp{_} is for an attribute given
+@c <en>special meaning by @sc{cvs}; other @var{attrname}s are for user-defined attributes
+@c <en>(or will be, once implementations start supporting user-defined attributes).
+Por convenção, @var{attrname} começando com @samp{_} é
+para um atributo ao qual foi dado significado especial
+pelo @sc{cvs}; outros @var{attrname}s são para
+atributos definidos pelo usuário (ou que vão ser, já
+que implementações começaram suporte a atributos
+definidos pelo usuário).
+
+@c <en>Builtin attributes:
+Atributos internos:
+
+@table @code
+@item _watched
+@c <en>Present means the file is watched and should be checked out
+@c <en>read-only.
+Quando presente significa que o arquivo está
+???watched??? (watched) e deve ser emprestado como
+@comment As "watches", before.
+@comment -DRP
+somente-leitura.
+
+@item _watchers
+@c <en>Users with watches for this file. Value is
+@c <en>@var{watcher} > @var{type} @{ , @var{watcher} > @var{type} @}
+@c <en>where @var{watcher} is a username, and @var{type}
+@c <en>is zero or more of edit,unedit,commit separated by
+@c <en>@samp{+} (that is, nothing if none; there is no "none" or "all" keyword).
+Usuários com ???watches??? para este arquivo. O valor é
+@comment As "watches", before.
+@comment -DRP
+@var{watcher} > @var{type} @{ , @var{watcher} > @var{type} @}
+onde @var{watcher} é um nome de usuário, e @var{type} é
+zero ou mais de edit,unedit,commit separados por
+@samp{+} (isto é, deixe em branco para nenhum; não há
+palavras-chave para "nenhum" ou "todos").
+
+@item _editors
+@c <en>Users editing this file. Value is
+@c <en>@var{editor} > @var{val} @{ , @var{editor} > @var{val} @}
+@c <en>@c <en>where @var{editor} is a username, and @var{val} is
+@c <en>@var{time}+@var{hostname}+@var{pathname}, where
+@c <en>@var{time} is when the @code{cvs edit} command (or
+@c <en>equivalent) happened,
+@c <en>and @var{hostname} and @var{pathname} are for the working directory.
+Usuários editando este arquivo. O valor é
+@var{editor} > @var{val} @{ , @var{editor} > @var{val} @}
+onde @var{editor} é um username, e @var{val} é
+@var{time}+@var{hostname}+@var{pathname}, onde
+@var{time} é quando o comando @code{cvs edit} (ou outro
+equivalente) aconteceu, e @var{hostname} e
+@var{pathname} são do diretório de trabalho.
+@end table
+
+Example:
+
+@c FIXME: sanity.sh should contain a similar test case
+@c so we can compare this example from something from
+@c Real Life(TM). See cvsclient.texi (under Notify) for more
+@c discussion of the date format of _editors.
+@example
+Ffile1 _watched=;_watchers=joe>edit,mary>commit
+Ffile2 _watched=;_editors=sue>8 Jan 1975+workstn1+/home/sue/cvs
+D _watched=
+@end example
+
+@noindent
+@c <en>means that the file @file{file1} should be checked out
+@c <en>read-only. Furthermore, joe is watching for edits and
+@c <en>mary is watching for commits. The file @file{file2}
+@c <en>should be checked out read-only; sue started editing it
+@c <en>on 8 Jan 1975 in the directory @file{/home/sue/cvs} on
+@c <en>the machine @code{workstn1}. Future files which are
+@c <en>added should be checked out read-only. To represent
+@c <en>this example here, we have shown a space after
+@c <en>@samp{D}, @samp{Ffile1}, and @samp{Ffile2}, but in fact
+@c <en>there must be a single tab character there and no spaces.
+significa que o arquivo @file{file1} deve ser pego como
+somente-leitura. Além disso, joe está ???watching???
+edições e mary está ???watching??? ???commits???. O
+@comment "Watching", as "watches", before.
+@comment "Commits" are checkins, i.e. via the `cvs commit' command.
+@comment -DRP
+arquivo @file{file2} deve ser pego somente-leitura; sue
+comecou a edita-lo em 8 Jan 1975 no diretorio
+@file{/home/sue/cvs} na maquina
+@code{workstn1}. Futuros arquivos que forem adicionados
+devem ser pegos somente-leitura. Para representar este
+exemplo aqui, nós mostramos um espaco depois de
+@samp{D}, @samp{Ffile1}, e @samp{Ffile2}, mas de fato
+existe um caractere de tab e nenhum espaco.
+
+@c <en>@node Locks
+@node Travas
+@c <en>@subsection CVS locks in the repository
+@subsection travas CVS no repositório
+
+@c <en>@cindex #cvs.rfl, technical details
+@cindex #cvs.rfl, detalhes técnicos
+@c <en>@cindex #cvs.pfl, technical details
+@cindex #cvs.pfl, detalhes técnicos
+@c <en>@cindex #cvs.wfl, technical details
+@cindex #cvs.wfl, detalhes técnicos
+@c <en>@cindex #cvs.lock, technical details
+@cindex #cvs.lock, detalhes técnicos
+@c <en>@cindex Locks, cvs, technical details
+@cindex Travas, cvs, detalhes técnicos
+@c <en>For an introduction to @sc{cvs} locks focusing on
+@c <en>user-visible behavior, see @ref{Concurrency}. The
+@c <en>following section is aimed at people who are writing
+@c <en>tools which want to access a @sc{cvs} repository without
+@c <en>interfering with other tools accessing the same
+@c <en>repository. If you find yourself confused by concepts
+@c <en>described here, like @dfn{read lock}, @dfn{write lock},
+@c <en>and @dfn{deadlock}, you might consult the literature on
+@c <en>operating systems or databases.
+Para uma introdução às travas (locks) no @sc{cvs}
+focando no comportamento visível ao usuário, veja em
+@ref{Concorrência}. A seção seguinte foi feita para
+para pessoas que escrevem ferramentas as quais precisam
+acessar um repositório @sc{cvs} sem interferir com
+outras ferramentas acessando o mesmo repositório. Se
+você se sentir confuso com os conceitos descritos aqui,
+como @dfn{read lock}, @dfn{write lock} e
+@dfn{deadlock}, você deve consultar a literatura de
+sistemas operacionais e bancos de dados.
+
+@c <en>@cindex #cvs.tfl
+@cindex #cvs.tfl
+@c <en>Any file in the repository with a name starting
+@c <en>with @file{#cvs.rfl.} is a read lock. Any file in
+@c <en>the repository with a name starting with
+@c <en>@file{#cvs.pfl} is a promotable read lock. Any file in
+@c <en>the repository with a name starting with
+@c <en>@file{#cvs.wfl} is a write lock. Old versions of @sc{cvs}
+@c <en>(before @sc{cvs} 1.5) also created files with names starting
+@c <en>with @file{#cvs.tfl}, but they are not discussed here.
+@c <en>The directory @file{#cvs.lock} serves as a master
+@c <en>lock. That is, one must obtain this lock first before
+@c <en>creating any of the other locks.
+Qualquer arquivo no repositório com um nome começando
+com @file{#cvs.rfl.} é uma trava de leitura. Qualquer
+arquivo no repositório com um nome comçando com
+@file{#cvs.pfl} é uma trava de leitura
+???promotable???. Qualquer arquivo no repositório com
+um nome começando com
+@file{#cvs.wfl} é uma trava de escrita. Versões antigas
+do @sc{cvs} (antes do @sc{cvs} 1.5) também criavam
+arquivos com nomes começando com @file{#cvs.tfl}, mas
+estes não são discutidos aqui.
+
+@c <en>The directory @file{#cvs.lock} serves as a master
+@c <en>lock. That is, one must obtain this lock first before
+@c <en>creating any of the other locks.
+O diretório @file{#cvs.lock} funciona como uma trava
+mestra. Isto é, deve-se obter esta trava antes de
+criar qualquer das outras travas.
+
+@c <en>To obtain a readlock, first create the @file{#cvs.lock}
+@c <en>directory. This operation must be atomic (which should
+@c <en>be true for creating a directory under most operating
+@c <en>systems). If it fails because the directory already
+@c <en>existed, wait for a while and try again. After
+@c <en>obtaining the @file{#cvs.lock} lock, create a file
+@c <en>whose name is @file{#cvs.rfl.} followed by information
+@c <en>of your choice (for example, hostname and process
+@c <en>identification number). Then remove the
+@c <en>@file{#cvs.lock} directory to release the master lock.
+@c <en>Then proceed with reading the repository. When you are
+@c <en>done, remove the @file{#cvs.rfl} file to release the
+@c <en>read lock.
+Para obter uma trava de leitura, primeiro crie o diretório
+@file{#cvs.lock}. Esta operação deve ser atômica (o
+que deve ser verdade para a criação de um diretório na
+maioria dos sistemas operacionais). Se isto falha por
+que o diretório já existe, espere um tempinho e tente de
+novo. Depois de obter a trava @file{#cvs.lock}, crie
+um arquivo cujo nome seja @file{#cvs.rfl.} seguido pela
+informação de sua escolha (por exemplo, nome de host e
+nmero de identificaçao de processo). Então remova o
+diretório @file{#cvs.lock} para ativar a trava
+mestra. Então começe a ler o repositório. Quando você
+terminar, remova o arquivo @file{#cvs.rfl} para
+liberar a trava de leitura.
+
+@c <en>Promotable read locks are a concept you may not find in other literature on
+@c <en>concurrency. They are used to allow a two (or more) pass process to only lock
+@c <en>a file for read on the first (read) pass(es), then upgrade its read locks to
+@c <en>write locks if necessary for a final pass, still assured that the files have
+@c <en>not changed since they were first read. @sc{cvs} uses promotable read locks,
+@c <en>for example, to prevent commit and tag verification passes from interfering
+@c <en>with other reading processes. It can then lock only a single directory at a
+@c <en>time for write during the write pass.
+Promotable read locks are a concept you may not find in other literature on
+concurrency. They are used to allow a two (or more) pass process to only lock
+a file for read on the first (read) pass(es), then upgrade its read locks to
+write locks if necessary for a final pass, still assured that the files have
+not changed since they were first read. @sc{cvs} uses promotable read locks,
+for example, to prevent commit and tag verification passes from interfering
+with other reading processes. It can then lock only a single directory at a
+time for write during the write pass.
+
+@c <en>To obtain a promotable read lock, first create the @file{#cvs.lock} directory,
+@c <en>as with a non-promotable read lock. Then check
+@c <en>that there are no files that start with
+@c <en>@file{#cvs.pfl}. If there are, remove the master @file{#cvs.lock} directory,
+@c <en>wait awhile (CVS waits 30 seconds between lock attempts), and try again. If
+@c <en>there are no other promotable locks, go ahead and create a file whose name is
+@c <en>@file{#cvs.pfl} followed by information of your choice (for example, CVS uses
+@c <en>its hostname and the process identification number of the CVS server process
+@c <en>creating the lock). If versions of @sc{cvs} older than version 1.12.4 access
+@c <en>your repository directly (not via a @sc{cvs} server of version 1.12.4 or
+@c <en>later), then you should also create a read lock since older versions of CVS
+@c <en>will ignore the promotable lock when attempting to create their own write lock.
+@c <en>Then remove the master @file{#cvs.lock} directory in order to allow other
+@c <en>processes to obtain read locks.
+To obtain a promotable read lock, first create the @file{#cvs.lock} directory,
+as with a non-promotable read lock. Then check
+that there are no files that start with
+@file{#cvs.pfl}. If there are, remove the master @file{#cvs.lock} directory,
+wait awhile (CVS waits 30 seconds between lock attempts), and try again. If
+there are no other promotable locks, go ahead and create a file whose name is
+@file{#cvs.pfl} followed by information of your choice (for example, CVS uses
+its hostname and the process identification number of the CVS server process
+creating the lock). If versions of @sc{cvs} older than version 1.12.4 access
+your repository directly (not via a @sc{cvs} server of version 1.12.4 or
+later), then you should also create a read lock since older versions of CVS
+will ignore the promotable lock when attempting to create their own write lock.
+Then remove the master @file{#cvs.lock} directory in order to allow other
+processes to obtain read locks.
+
+@c <en>To obtain a writelock, first create the
+@c <en>@file{#cvs.lock} directory, as with readlocks. Then
+@c <en>check that there are no files whose names start with
+@c <en>@file{#cvs.rfl.} and no files whose names start with @file{#cvs.pfl} that are
+@c <en>not owned by the process attempting to get the write lock. If either exist,
+@c <en>remove @file{#cvs.lock}, wait for a while, and try again. If
+@c <en>there are no readers or promotable locks from other processes, then create a
+@c <en>file whose name is @file{#cvs.wfl} followed by information of your choice
+@c <en>(again, CVS uses the hostname and server process identification
+@c <en>number). Remove your @file{#cvs.pfl} file if present. Hang on to the
+@c <en>@file{#cvs.lock} lock. Proceed
+@c <en>with writing the repository. When you are done, first
+@c <en>remove the @file{#cvs.wfl} file and then the
+@c <en>@file{#cvs.lock} directory. Note that unlike the
+@c <en>@file{#cvs.rfl} file, the @file{#cvs.wfl} file is just
+@c <en>informational; it has no effect on the locking operation
+@c <en>beyond what is provided by holding on to the
+@c <en>@file{#cvs.lock} lock itself.
+Para obter uma trava de escrita, primeiro crie o
+diretório @file{#cvs.lock}, da mesma forma que com as
+travas de leitura. Então verifique se não existem
+arquivos cujos nomes começam com @file{#cvs.rfl.} e se
+não existem arquivos cujo nome começa com
+@file{#cvs.pfl} que não tenha como dono o processo
+tentando ter a trava de escrita. Se ???either???
+existe, remova o @file{#cvs.lock}, espere um momento, e
+tente de novo. Se não existem ???readers??? ou travas
+???promotable??? de outros processos, então crie um
+arquivo cujo nome é @file{#cvs.wfl} seguido de
+informações da sua escolha (novamente, o CVS usa o
+hostname e o ???server process identification
+number??). Remove your @file{#cvs.pfl} file if present. Hang on to the
+@file{#cvs.lock} lock. Escreva no repositório. Quando
+tiver terminado, primeiro remova o arquivo
+@file{#cvs.wfl} e então o diretório
+@file{#cvs.lock}. Observe que ao contrário do arquivo
+@file{#cvs.rfl}, o arquivo @file{#cvs.wfl} é apenas
+informativo; ele não tem efeito na operação de trava
+além do que é feito pelo ato de manter a trava
+@file{#cvs.lock}.
+
+@c <en>Note that each lock (writelock or readlock) only locks
+@c <en>a single directory in the repository, including
+@c <en>@file{Attic} and @file{CVS} but not including
+@c <en>subdirectories which represent other directories under
+@c <en>version control. To lock an entire tree, you need to
+@c <en>lock each directory (note that if you fail to obtain
+@c <en>any lock you need, you must release the whole tree
+@c <en>before waiting and trying again, to avoid deadlocks).
+Observe que cada trava (de escrita ou leitura) apenas trava um
+único diretório no
+repositório, inclusive no caso do @file{Attic} e do @file{CVS}
+sem incluir os subdiretórios que representam outros
+diretórios sob controle de versão. Para travar uma
+árvore inteira, voc precisa travar cada diretório
+(observe que se você não conseguir obter alguma trava
+que você precise, você deve liberar a árvore toda antes
+para esperar e tentar novamente, para evitar ???deadlocks???).
+@comment "Deadlock" is a computer science term which refers to the scenario
+@comment where two processes end up waiting on each other in such a way that
+@comment neither will ever get the lock and therefore neither process will
+@comment ever run again, and therefore both are said to be "dead".
+@comment
+@comment For example, say process 1 wants to lock files "A" and "B", and so
+@comment does process 2. If process 1 locks "A" first, and process 2 locks
+@comment file "B" first, then process begins waiting to lock "B" while process
+@comment 2 waits to lock "A", then both processes will wait indefinately, a
+@comment commonly encountered problem with file locking, especially for
+@comment inexperienced programmers.
+@comment -DRP
+
+@c <en>Note also that @sc{cvs} expects writelocks to control
+@c <en>access to individual @file{foo,v} files. @sc{rcs} has
+@c <en>a scheme where the @file{,foo,} file serves as a lock,
+@c <en>but @sc{cvs} does not implement it and so taking out a
+@c <en>@sc{cvs} writelock is recommended. See the comments at
+@c <en>rcs_internal_lockfile in the @sc{cvs} source code for
+@c <en>further discussion/rationale.
+Observe também que o @sc{cvs} espera travas de escrita
+para controlar o acesso a arquivos @file{foo,v}
+individuais. O @sc{rcs} tem um esquema onde o arquivo
+@file{,foo,} funciona como uma trava, mas o @sc{cvs}
+não implementa isso. Portanto, fazer uma trava de escrita
+no @sc{cvs} é recomendado. Veja os comentários no
+rcs_internal_lockfile no código fonte do @sc{cvs} para
+mais discussões/explicações.
+
+@c <en>@node CVSROOT storage
+@node Armazenamento do CVSROOT
+@c <en>@subsection How files are stored in the CVSROOT directory
+@subsection Como os arquivos são guardados no diretório CVSROOT
+@c <en>@cindex CVSROOT, storage of files
+@cindex CVSROOT, armazenamento de arquivos
+
+@c <en>The @file{$CVSROOT/CVSROOT} directory contains the
+@c <en>various administrative files. In some ways this
+@c <en>directory is just like any other directory in the
+@c <en>repository; it contains @sc{rcs} files whose names end
+@c <en>in @samp{,v}, and many of the @sc{cvs} commands operate
+@c <en>on it the same way. However, there are a few
+@c <en>differences.
+O diretório @file{$CVSROOT/CVSROOT} contém os vários
+arquivos administrativos. Em alguns aspectos este
+diretório é igual a qualquer outro diretório no
+repositório; ele contém arquivos @sc{rcs} cujos nomes
+terminam em @samp{,v}, e muitos dos comandos do
+@sc{cvs} operam neles do mesmo jeito. Entretanto,
+existem algumas poucas diferenças.
+
+@c <en>For each administrative file, in addition to the
+@c <en>@sc{rcs} file, there is also a checked out copy of the
+@c <en>file. For example, there is an @sc{rcs} file
+@c <en>@file{loginfo,v} and a file @file{loginfo} which
+@c <en>contains the latest revision contained in
+@c <en>@file{loginfo,v}. When you check in an administrative
+@c <en>file, @sc{cvs} should print
+Para cada arquivo administrativo, além do arquivo
+@sc{rcs}, existe também uma cópia de trabalho do
+arquivo. Por exemplo, existe um arquivo @sc{rcs}
+@file{loginfo,v} e um arquivo @file{loginfo} que contém
+a ultima revisão contida em @file{loginfo,v}. Quando
+você devolve um arquivo administrativo, o @sc{cvs} vai
+mostrar
+
+@example
+cvs commit: Rebuilding administrative file database
+@end example
+
+@noindent
+@c <en>and update the checked out copy in
+@c <en>@file{$CVSROOT/CVSROOT}. If it does not, there is
+@c <en>something wrong (@pxref{BUGS}). To add your own files
+@c <en>to the files to be updated in this fashion, you can add
+@c <en>them to the @file{checkoutlist} administrative file
+@c <en>(@pxref{checkoutlist}).
+e atualizar a cópia de trabalho em
+@file{$CVSROOT/CVSROOT}. Se não fizer, tem algo errado
+(@pxref{Paus}). Para adicionar os seus próprios
+arquivos aos arquivos a serem atualizados desta
+maneira, você pode adicioná-los ao arquivo
+administrativo @file{checkoutlist}
+(@pxref{checkoutlist}).
+
+@c <en>@cindex modules.db
+@cindex modules.db
+@c <en>@cindex modules.pag
+@cindex modules.pag
+@c <en>@cindex modules.dir
+@cindex modules.dir
+@c <en>By default, the @file{modules} file behaves as
+@c <en>described above. If the modules file is very large,
+@c <en>storing it as a flat text file may make looking up
+@c <en>modules slow (I'm not sure whether this is as much of a
+@c <en>concern now as when @sc{cvs} first evolved this
+@c <en>feature; I haven't seen benchmarks). Therefore, by
+@c <en>making appropriate edits to the @sc{cvs} source code
+@c <en>one can store the modules file in a database which
+@c <en>implements the @code{ndbm} interface, such as Berkeley
+@c <en>db or GDBM. If this option is in use, then the modules
+@c <en>database will be stored in the files @file{modules.db},
+@c <en>@file{modules.pag}, and/or @file{modules.dir}.
+Por padrão o arquivo @file{modules} se comporta como
+descrito acima. Se o arquivo modules é muito grande,
+guardar ele como um arquivo de texto normal faz a busca
+por módulos lenta (Não estou bem certo se isso importa
+tanto agora como quando o @sc{cvs} primeiramente
+desenvolveu esta habilidade; não vi avaliações).
+Entretanto, fazendo edições apropriadas no código fonte
+do @sc{cvs} pode-se guardar o arquivo modules num banco
+de dados que implementa a interface @code{ndbm}, tais
+como o Berkeley db ou GDBM. Se esta opção está em uso,
+então o banco de dados modules será guardado nos
+arquivos @file{modules.db}, @file{modules.pag}, e/ou @file{modules.dir}.
+@c I think fileattr also will use the database stuff.
+@c Anything else?
+
+@c <en>For information on the meaning of the various
+@c <en>administrative files, see @ref{Administrative files}.
+Para informações sobre o significado dos vários arquivos administrativos,
+veja em @ref{Arquivos administrativos}.
+
+@c <en>@node Working directory storage
+@node Armazenamento do Diretório de trabalho
+@c <en>@section How data is stored in the working directory
+@section Como os dados são guardados no diretório de trabalho
+
+@c FIXME: Somewhere we should discuss timestamps (test
+@c case "stamps" in sanity.sh). But not here. Maybe
+@c in some kind of "working directory" chapter which
+@c would encompass the "Builds" one? But I'm not sure
+@c whether that is a good organization (is it based on
+@c what the user wants to do?).
+
+@c <en>@cindex CVS directory, in working directory
+@cindex diretório CVS, no diretório de trabalho
+@c <en>While we are discussing @sc{cvs} internals which may
+@c <en>become visible from time to time, we might as well talk
+@c <en>about what @sc{cvs} puts in the @file{CVS} directories
+@c <en>in the working directories. As with the repository,
+@c <en>@sc{cvs} handles this information and one can usually
+@c <en>access it via @sc{cvs} commands. But in some cases it
+@c <en>may be useful to look at it, and other programs, such
+@c <en>as the @code{jCVS} graphical user interface or the
+@c <en>@code{VC} package for emacs, may need to look at it.
+@c <en>Such programs should follow the recommendations in this
+@c <en>section if they hope to be able to work with other
+@c <en>programs which use those files, including future
+@c <en>versions of the programs just mentioned and the
+@c <en>command-line @sc{cvs} client.
+Assim como estamos conversando sobre as entranhas do
+@sc{cvs}, que podem ficar visíveis de tempos em tempos,
+também devemos falar sobre o que o @sc{cvs} bota nos
+diretórios @file{CVS} nos diretórios de trabalho.
+Assim como com o repositório, o @sc{cvs} manipula esta
+informação e pode-se acessá-la normalmente via comandos
+@sc{cvs}. Mas em alguns casos pode ser útil dar uma
+olhada, e outros programas, como a interface de usuário
+gráfica @code{jCVS} ou o pacote para emacs @code{VC},
+precisarem ver o que tem lá. Tais programas devem
+seguir as recomendações nesta seção se eles querem
+interagir com outros programas que usam estes arquivos,
+inclusive versões futuras dos programas mencinados logo
+acima e o cliente em linha-de-comando do @sc{cvs}.
+
+@c <en>The @file{CVS} directory contains several files.
+@c <en>Programs which are reading this directory should
+@c <en>silently ignore files which are in the directory but
+@c <en>which are not documented here, to allow for future
+@c <en>expansion.
+O diretório @file{CVS} contém vários
+arquivos. Programas que estão lendo este diretório
+devem ignorar em silêncio arquivos que encontrem no
+diretório mas que não estejam documentados aqui, para
+permitir expansões futuras.
+
+@c <en>The files are stored according to the text file
+@c <en>convention for the system in question. This means that
+@c <en>working directories are not portable between systems
+@c <en>with differing conventions for storing text files.
+@c <en>This is intentional, on the theory that the files being
+@c <en>managed by @sc{cvs} probably will not be portable between
+@c <en>such systems either.
+Os arquivos são guardados de acordo com a convenção de
+arquivo de texto do sistema em questão. Isto significa
+que diretórios de trabalho não são portáveis entre
+sistemas com diferentes convenções para armazenar
+arquivos de texto. Isto é de propósito, baseado na
+teoria de que os arquivos sendo gerenciados pelo
+@sc{cvs} provavelmente também não seriam portáveis
+entre tais sistemas.
+
+@table @file
+@item Root
+@c <en>This file contains the current @sc{cvs} root, as
+@c <en>described in @ref{Specifying a repository}.
+Este arquivo contém a raiz atual do @sc{cvs}, como
+descrito em @ref{Especificando um repositório}.
+
+@c <en>@cindex Repository file, in CVS directory
+@cindex O arquivo Repository, no diretório CVS
+@c <en>@cindex CVS/Repository file
+@cindex O arquivo CVS/Repository
+@c <en>@item Repository
+@item Repositório
+@c <en>This file contains the directory within the repository
+@c <en>which the current directory corresponds with. It can
+@c <en>be either an absolute pathname or a relative pathname;
+@c <en>@sc{cvs} has had the ability to read either format
+@c <en>since at least version 1.3 or so. The relative
+@c <en>pathname is relative to the root, and is the more
+@c <en>sensible approach, but the absolute pathname is quite
+@c <en>common and implementations should accept either. For
+@c <en>example, after the command
+Este arquivo contém o diretório no qual está o
+repositório correspondente ao diretório atual. Pode
+ser um caminho absoluto ou relativo; @sc{cvs} adquiriu
+a habilidade de ler ambos os formatos desde a versão
+1.3. O caminho é relativo à raiz (root), e é a
+abordagem mais racional, mas o caminho absoluto é
+mais comum e ambos devem ser aceitos. Por exemplo,
+depois do comando
+
+@example
+cvs -d :local:/usr/local/cvsroot checkout yoyodyne/tc
+@end example
+
+@noindent
+@c <en>@file{Root} will contain
+o @file{Root} vai conter
+
+@example
+:local:/usr/local/cvsroot
+@end example
+
+@noindent
+@c <en>and @file{Repository} will contain either
+e o @file{Repositório} vai conter ou
+
+@example
+/usr/local/cvsroot/yoyodyne/tc
+@end example
+
+@noindent
+@c <en>or
+ou
+
+@example
+yoyodyne/tc
+@end example
+
+@c <en>If the particular working directory does not correspond
+@c <en>to a directory in the repository, then @file{Repository}
+@c <en>should contain @file{CVSROOT/Emptydir}.
+Se o diretório de trabalho particular não corresponde a
+um diretório no repositório, então o @file{Repositório}
+deve conter @file{CVSROOT/Emptydir}.
+@c <en>@cindex Emptydir, in CVSROOT directory
+@cindex Emptydir, no diretório CVSROOT
+@c <en>@cindex CVSROOT/Emptydir directory
+@cindex O diretório CVSROOT/Emptydir
+
+@c <en>@cindex Entries file, in CVS directory
+@cindex O arquivo Entries, no diretório do CVS
+@c <en>@cindex CVS/Entries file
+@cindex O arquivo CVS/Entries
+@c <en>@item Entries
+@item Entries
+@c <en>This file lists the files and directories in the
+@c <en>working directory.
+@c <en>The first character of each line indicates what sort of
+@c <en>line it is. If the character is unrecognized, programs
+@c <en>reading the file should silently skip that line, to
+@c <en>allow for future expansion.
+Este arquivo relaciona os arquivos e diretórios no
+diretório de trabalho. O primeiro caractere de cada
+linha indica de que tipo é a linha. Se caractere não
+for reconhecido, os programas lendo o arquivo devem
+pular de linha em silêncio, para permitir futuras expansões.
+
+@c <en>If the first character is @samp{/}, then the format is:
+Se o primeiro caractere é @samp{/}, então o formato é:
+
+@example
+/@var{name}/@var{revision}/@var{timestamp}[+@var{conflict}]/@var{options}/@var{tagdate}
+@end example
+
+@noindent
+@c <en>where @samp{[} and @samp{]} are not part of the entry,
+@c <en>but instead indicate that the @samp{+} and conflict
+@c <en>marker are optional. @var{name} is the name of the
+@c <en>file within the directory. @var{revision} is the
+@c <en>revision that the file in the working derives from, or
+@c <en>@samp{0} for an added file, or @samp{-} followed by a
+@c <en>revision for a removed file. @var{timestamp} is the
+@c <en>timestamp of the file at the time that @sc{cvs} created
+@c <en>it; if the timestamp differs with the actual
+@c <en>modification time of the file it means the file has
+@c <en>been modified. It is stored in
+@c <en>the format used by the ISO C asctime() function (for
+@c <en>example, @samp{Sun Apr 7 01:29:26 1996}). One may
+@c <en>write a string which is not in that format, for
+@c <en>example, @samp{Result of merge}, to indicate that the
+@c <en>file should always be considered to be modified. This
+@c <en>is not a special case; to see whether a file is
+@c <en>modified a program should take the timestamp of the file
+@c <en>and simply do a string compare with @var{timestamp}.
+@c <en>If there was a conflict, @var{conflict} can be set to
+@c <en>the modification time of the file after the file has been
+@c <en>written with conflict markers (@pxref{Conflicts example}).
+@c <en>Thus if @var{conflict} is subsequently the same as the actual
+@c <en>modification time of the file it means that the user
+@c <en>has obviously not resolved the conflict. @var{options}
+@c <en>contains sticky options (for example @samp{-kb} for a
+@c <en>binary file). @var{tagdate} contains @samp{T} followed
+@c <en>by a tag name, or @samp{D} for a date, followed by a
+@c <en>sticky tag or date. Note that if @var{timestamp}
+@c <en>contains a pair of timestamps separated by a space,
+@c <en>rather than a single timestamp, you are dealing with a
+@c <en>version of @sc{cvs} earlier than @sc{cvs} 1.5 (not
+@c <en>documented here).
+Onde @samp{[} e @samp{]} não são partes da entrada, mas
+indicam que o @samp{+} e o marcador de conflito são
+opcionais. @var{name} é o nome do arquivo no
+diretório. @var{revision} e a revisão da qual o
+arquivo no diretório de trabalho deriva, ou @samp{0}
+para um arquivo adicionado, ou @samp{-} seguido de uma
+revisão para um arquivo removido. @var{timestamp} é o
+???timestamp??? do arquivo quando o @sc{cvs} o criou;
+@comment As a file system timestamp. Usually a creation time or modification
+@comment time or something. I'm not sure what they were prior to CVS 1.5.
+@comment -DRP
+se o timestamp difere da hora de modificação do
+arquivo, significa que o arquivo foi modificado. É
+armazenado no formato usando pela função ISO C
+asctime() (por exemplo, @samp{Sun Apr 7 01:29:26
+1996}). Pode-se escrever uma string que não esteja
+neste formato, por exemplo, @samp{Result of merge},
+para indicar que o arquivo deve ser sempre considerado
+como modificado. Este não é um caso especial; para ver
+se um arquivo é modificado, um programa pode pegar o
+timestamp do arquivo e simplesmente criar uma string e
+comparar com @var{timestamp}. Se existe um conflito,
+@var{conflict} pode ser ajustada para o tempo de
+modificação do arquivo depois do arquivo ter sido
+escrito com marcações de conflito (@pxref{Exemplo de conflitos}).
+Logo, se @var{conflict} é posteriormente o mesmo que o
+tempo de modificação real do arquivo significa que o
+usuário obviamente não resolveu o conflito. @var{options}
+contém opções adesivas (por exemplo @samp{-kb} para um
+arquivo binário). @var{tagdate} contém @samp{T}
+seguindo de um nome de etiqueta (tag), ou @samp{D} para
+uma data, seguido de uma data ou etiqueta adesiva.
+Observe que se @var{timestamp} contém um par de
+timestamps separados por um espaço, ao invés de um
+único timestamp, você está lidando com uma versão do
+@sc{cvs} anterior ao @sc{cvs} 1.5 (sem documentação aqui).
+
+@c <en>The timezone on the timestamp in CVS/Entries (local or
+@c <en>universal) should be the same as the operating system
+@c <en>stores for the timestamp of the file itself. For
+@c <en>example, on Unix the file's timestamp is in universal
+@c <en>time (UT), so the timestamp in CVS/Entries should be
+@c <en>too. On @sc{vms}, the file's timestamp is in local
+@c <en>time, so @sc{cvs} on @sc{vms} should use local time.
+@c <en>This rule is so that files do not appear to be modified
+@c <en>merely because the timezone changed (for example, to or
+@c <en>from summer time).
+O fuso horário do timestamp no CVS/Entries (local ou
+universal) deve ser igual ao que o sistema
+operacional guarda para o timestamp do próprio arquivo.
+Por exemplo, no Unix o timestamp do arquivo está em
+tempo universal (universal time - UT). Logo, o
+timestamp em CVS/Entries deve estar assim também. No
+@sc{vms}, o timestamp do arquivo está em hora
+local, logo, o @sc{cvs} no @sc{vms} deve usar hora
+local. Esta regra é para que arquivos não pareçam estar
+modificados simplesmente por que o fuso horário mudou
+(por exemplo, saindo ou entrando no horário de verão).
+@c See comments and calls to gmtime() and friends in
+@c src/vers_ts.c (function time_stamp).
+
+@c <en>If the first character of a line in @file{Entries} is
+@c <en>@samp{D}, then it indicates a subdirectory. @samp{D}
+@c <en>on a line all by itself indicates that the program
+@c <en>which wrote the @file{Entries} file does record
+@c <en>subdirectories (therefore, if there is such a line and
+@c <en>no other lines beginning with @samp{D}, one knows there
+@c <en>are no subdirectories). Otherwise, the line looks
+@c <en>like:
+Se o primeiro caractere de uma linha em @file{Entries}
+é @samp{D}, então ele indica um subdiretório. @samp{D}
+sozinho em uma linha indica que o programa
+que escreveu o arquivo @file{Entries} registra
+subdiretórios (portanto, se existe tal linha e nenhuma
+outra linha começando com @samp{D}, conclui-se que não
+há subdiretórios). Caso contrário, a linha vai se
+parecer com:
+
+@example
+D/@var{name}/@var{filler1}/@var{filler2}/@var{filler3}/@var{filler4}
+@end example
+
+@noindent
+@c <en>where @var{name} is the name of the subdirectory, and
+@c <en>all the @var{filler} fields should be silently ignored,
+@c <en>for future expansion. Programs which modify
+@c <en>@code{Entries} files should preserve these fields.
+onde @var{name} é o nome do subdiretório, e todos os
+campos @var{filler} devem ser ignorados em silêncio,
+para expansões futuras. Programas que modificam
+arquivos @code{Entries} devem manter estes campos.
+
+@c <en>The lines in the @file{Entries} file can be in any order.
+As linhas no arquivo @file{Entries} podem estar em
+qualquer ordem.
+
+@c <en>@cindex Entries.Log file, in CVS directory
+@cindex O arquivo Entries.Log, no diretório CVS
+@c <en>@cindex CVS/Entries.Log file
+@cindex O arquivo CVS/Entries.Log
+@c <en>@item Entries.Log
+@item Entries.Log
+@c <en>This file does not record any information beyond that
+@c <en>in @file{Entries}, but it does provide a way to update
+@c <en>the information without having to rewrite the entire
+@c <en>@file{Entries} file, including the ability to preserve
+@c <en>the information even if the program writing
+@c <en>@file{Entries} and @file{Entries.Log} abruptly aborts.
+@c <en>Programs which are reading the @file{Entries} file
+@c <en>should also check for @file{Entries.Log}. If the latter
+@c <en>exists, they should read @file{Entries} and then apply
+@c <en>the changes mentioned in @file{Entries.Log}. After
+@c <en>applying the changes, the recommended practice is to
+@c <en>rewrite @file{Entries} and then delete @file{Entries.Log}.
+@c <en>The format of a line in @file{Entries.Log} is a single
+@c <en>character command followed by a space followed by a
+@c <en>line in the format specified for a line in
+@c <en>@file{Entries}. The single character command is
+@c <en>@samp{A} to indicate that the entry is being added,
+@c <en>@samp{R} to indicate that the entry is being removed,
+@c <en>or any other character to indicate that the entire line
+@c <en>in @file{Entries.Log} should be silently ignored (for
+@c <en>future expansion). If the second character of the line
+@c <en>in @file{Entries.Log} is not a space, then it was
+@c <en>written by an older version of @sc{cvs} (not documented
+@c <en>here).
+Este arquivo não registra qualquer informação a mais
+que no @file{Entries}, mas fornece um jeito de
+atualizar a informação sem ter que reescrever todo o
+arquivo @file{Entries}, incluindo a habilidade de
+preservar a informação mesmo se o programa que estava
+escrevendo o @file{Entries} e o @file{Entries.Log}
+aborta abruptamente. Programas que estão lendo o
+arquivo @file{Entries} devem também verificar pelo
+@file{Entries.Log}. Se este último existe, eles devem
+ler o @file{Entries} e então aplicar as mudanças
+mencionadas no @file{Entries.Log}. Depois de aplicar
+as mudanças, a prática recomendada é reescrever o
+@file{Entries} e depois apagar o @file{Entries.Log}. O
+formato de uma linha no @file{Entries.Log} é um comando
+de um caractere seguido de um espaço seguido por uma
+linha no formato especificado para uma linha no
+@file{Entries}. O caractere de comando é
+@samp{A} para indicar que a entrada está sendo
+adicionada, @samp{R} para indicar que a entrada está
+sendo removida, ou qualquer outro caractere para
+indicar que a linha inteira em @file{Entries.Log} deve
+ser ignorada em silêncio (para expansão futura). Se o
+segundo caractere da linha em @file{Entries.Log} não é
+um espaço, então foi escrito por uma versão antiga do
+@sc{cvs} (não documentada aqui).
+
+@c <en>Programs which are writing rather than reading can
+@c <en>safely ignore @file{Entries.Log} if they so choose.
+Programas que estão escrevendo ao invés de lendo podem
+seguramente ignorar @file{Entries.Log} se assim escolherem.
+
+@c <en>@cindex Entries.Backup file, in CVS directory
+@cindex O arquivo Entries.Backup, no diretório CVS
+@c <en>@cindex CVS/Entries.Backup file
+@cindex O arquivo CVS/Entries.Backup
+@c <en>@item Entries.Backup
+@item Entries.Backup
+@c <en>This is a temporary file. Recommended usage is to
+@c <en>write a new entries file to @file{Entries.Backup}, and
+@c <en>then to rename it (atomically, where possible) to @file{Entries}.
+Este é um arquivo temporário. O uso recomendado é
+escrever um novo arquivo entries para o
+@file{Entries.Backup}, e então renomeá-lo
+(atomicamente, quando possível) para @file{Entries}.
+
+@c <en>@cindex Entries.Static file, in CVS directory
+@cindex O arquivo Entries.Static, no diretório CVS
+@c <en>@cindex CVS/Entries.Static file
+@cindex O arquivo CVS/Entries.Static
+@c <en>@item Entries.Static
+@item Entries.Static
+@c <en>The only relevant thing about this file is whether it
+@c <en>exists or not. If it exists, then it means that only
+@c <en>part of a directory was gotten and @sc{cvs} will
+@c <en>not create additional files in that directory. To
+@c <en>clear it, use the @code{update} command with the
+@c <en>@samp{-d} option, which will get the additional files
+@c <en>and remove @file{Entries.Static}.
+A única coisa relevante sobre este arquivo é se ele
+existe ou não. Se ele existe, então quer dizer que
+apenas parte de um diretório foi pego e o @sc{cvs} não
+vai criar arquivos adicionais neste diretório. Para
+limpar isto, use o comando @code{update} com a opção
+@samp{-d}, a qual vai pegar os arquivos adicionais e
+remover @file{Entries.Static}.
+@c FIXME: This needs to be better documented, in places
+@c other than Working Directory Storage.
+@c FIXCVS: The fact that this setting exists needs to
+@c be more visible to the user. For example "cvs
+@c status foo", in the case where the file would be
+@c gotten except for Entries.Static, might say
+@c something to distinguish this from other cases.
+@c One thing that periodically gets suggested is to
+@c have "cvs update" print something when it skips
+@c files due to Entries.Static, but IMHO that kind of
+@c noise pretty much makes the Entries.Static feature
+@c useless.
+
+@c <en>@cindex Tag file, in CVS directory
+@cindex O arquivo Tag, no diretório CVS
+@c <en>@cindex CVS/Tag file
+@cindex O arquivo CVS/Tag
+@c <en>@cindex Sticky tags/dates, per-directory
+@cindex Por diretório, etiquetas/datas adesivas
+@c <en>@cindex Per-directory sticky tags/dates
+@cindex Etiquetas/datas adesivas por diretório
+@c <en>@item Tag
+@item Tag (Etiqueta)
+@c <en>This file contains per-directory sticky tags or dates.
+@c <en>The first character is @samp{T} for a branch tag,
+@c <en>@samp{N} for a non-branch tag, or @samp{D} for a date,
+@c <en>or another character to mean the file should be
+@c <en>silently ignored, for future expansion. This character
+@c <en>is followed by the tag or date. Note that
+@c <en>per-directory sticky tags or dates are used for things
+@c <en>like applying to files which are newly added; they
+@c <en>might not be the same as the sticky tags or dates on
+@c <en>individual files. For general information on sticky
+@c <en>tags and dates, see @ref{Sticky tags}.
+Este arquivo contém as etiquetas (tags) ou datas
+adesivas por diretório. O primeiro caractere é @samp{T}
+para uma etiqueta de ramo, @samp{N} para uma etiqueta
+que não é de ramo, ou @samp{D} para uma data, ou outro
+caractere que quer dizer que o arquivo deve ser
+ignorado em silêncio, para expansão futura. Este
+caractere é seguido de uma etiqueta ou data. Observe
+que etiquetas ou data adesivas por diretório são usadas
+para coisas como ???applying to??? arquivos que
+acabaram de ser adicionados; ???they (the tags or the files)???
+podem não ser os mesmos assim como as etiquetas
+adesivas ou datas em arquivos isolados. Para
+informações gerais sobre etiquetas adesivas ou datas,
+veja em @ref{Etiquetas adesivas}.
+@c FIXME: This needs to be much better documented,
+@c preferably not in the context of "working directory
+@c storage".
+@c FIXME: The Sticky tags node needs to discuss, or xref to
+@c someplace which discusses, per-directory sticky
+@c tags and the distinction with per-file sticky tags.
+
+@c <en>@cindex Notify file, in CVS directory
+@cindex O arquivo Notify, no diretório CVS
+@c <en>@cindex CVS/Notify file
+@cindex O arquivo CVS/Notify
+@c <en>@item Notify
+@item Notify
+@c <en>This file stores notifications (for example, for
+@c <en>@code{edit} or @code{unedit}) which have not yet been
+@c <en>sent to the server. Its format is not yet documented
+@c <en>here.
+Este arquivo guarda notificações (por exemplo, sobre
+@code{edit} ou @code{unedit}) que ainda não foram
+mandadas para o servidor. Seu formato ainda não está
+documentado aqui.
+
+@c <en>@cindex Notify.tmp file, in CVS directory
+@cindex O arquivo Notify.tmp, no diretório CVS
+@c <en>@cindex CVS/Notify.tmp file
+@cindex O arquivo CVS/Notify.tmp
+@c <en>@item Notify.tmp
+@item Notify.tmp
+@c <en>This file is to @file{Notify} as @file{Entries.Backup}
+@c <en>is to @file{Entries}. That is, to write @file{Notify},
+@c <en>first write the new contents to @file{Notify.tmp} and
+@c <en>then (atomically where possible), rename it to
+@c <en>@file{Notify}.
+Este arquivo está para @file{Notify} como o @file{Entries.Backup}
+está para @file{Entries}. Ou seja, para escrever em
+@file{Notify}, escreva o novo conteúdo primeiro em
+@file{Notify.tmp} e então (atomicamente, quando
+possível), renomeie-o para @file{Notify}.
+
+@c <en>@cindex Base directory, in CVS directory
+@cindex Diretório Base, no diretório CVS
+@c <en>@cindex CVS/Base directory
+@cindex Diretório CVS/Base
+@c <en>@item Base
+@item Base
+@c <en>If watches are in use, then an @code{edit} command
+@c <en>stores the original copy of the file in the @file{Base}
+@c <en>directory. This allows the @code{unedit} command to
+@c <en>operate even if it is unable to communicate with the
+@c <en>server.
+Se os ???watches??? estão em uso, então um comando
+@code{edit} guarda a cópia original do arquivo no
+diretório @file{Base}. Isto permite que o comando
+@code{unedit} opere mesmo se estiver sem comunicação
+com o servidor.
+
+@c <en>@cindex Baserev file, in CVS directory
+@cindex O arquivo Baserev, no diretório CVS
+@c <en>@cindex CVS/Baserev file
+@cindex O arquivo CVS/Baserev
+@c <en>@item Baserev
+@item Baserev
+@c <en>The file lists the revision for each of the files in
+@c <en>the @file{Base} directory. The format is:
+O arquivo lista a revisão de cada arquivo no diretório
+@file{Base}. O formato é:
+
+@example
+B@var{name}/@var{rev}/@var{expansion}
+@end example
+
+@noindent
+@c <en>where @var{expansion} should be ignored, to allow for
+@c <en>future expansion.
+Onde @var{expansion} deve ser ignorada para permitir
+expansão futura.
+
+@c <en>@cindex Baserev.tmp file, in CVS directory
+@cindex O arquivo Baserev.tmp, no diretório CVS
+@c <en>@cindex CVS/Baserev.tmp file
+@cindex O arquivo CVS/Baserev.tmp
+@c <en>@item Baserev.tmp
+@item Baserev.tmp
+@c <en>This file is to @file{Baserev} as @file{Entries.Backup}
+@c <en>is to @file{Entries}. That is, to write @file{Baserev},
+@c <en>first write the new contents to @file{Baserev.tmp} and
+@c <en>then (atomically where possible), rename it to
+@c <en>@file{Baserev}.
+Este arquivo está para @file{Baserev} assim como
+@file{Entries.Backup} está para @file{Entries}. Ou
+seja, para escrever em @file{Baserev}, escreva o novo
+conteúdo primeiro em @file{Baserev.tmp} e então
+(atomicamente, quando possível), renomei-o para @file{Baserev}.
+
+@c <en>@cindex Template file, in CVS directory
+@cindex O arquivo Template, no diretório CVS
+@c <en>@cindex CVS/Template file
+@cindex O arquivo CVS/Template
+@c <en>@item Template
+@item Template
+@c <en>This file contains the template specified by the
+@c <en>@file{rcsinfo} file (@pxref{rcsinfo}). It is only used
+@c <en>by the client; the non-client/server @sc{cvs} consults
+@c <en>@file{rcsinfo} directly.
+Este arquivo contém o modelo (template) especificado
+pelo arquivo @file{rcsinfo} (@pxref{rcsinfo}). Ele é
+usado apenas pelo cliente; o ???non-client/server???
+@sc{cvs} consulta o @file{rcsinfo} diretamente.
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Intro administrative files
+@node Intro aos arquivos administrativos
+@c <en>@section The administrative files
+@section Os arquivos administrativos
+@c <en>@cindex Administrative files (intro)
+@cindex Arquivos administrativos (intro)
+@c <en>@cindex Modules file
+@cindex O arquivo Modules
+@c <en>@cindex CVSROOT, module name
+@cindex CVSROOT, nome de módulo
+@c <en>@cindex Defining modules (intro)
+@cindex Definindo módulos (intro)
+
+@c FIXME: this node should be reorganized into "general
+@c information about admin files" and put the "editing
+@c admin files" stuff up front rather than jumping into
+@c the details of modules right away. Then the
+@c Administrative files node can go away, the information
+@c on each admin file distributed to a place appropriate
+@c to its function, and this node can contain a table
+@c listing each file and a @ref to its detailed description.
+
+@c <en>The directory @file{$CVSROOT/CVSROOT} contains some @dfn{administrative
+@c <en>files}. @xref{Administrative files}, for a complete description.
+@c <en>You can use @sc{cvs} without any of these files, but
+@c <en>some commands work better when at least the
+@c <en>@file{modules} file is properly set up.
+O diretório @file{$CVSROOT/CVSROOT} contém alguns
+@dfn{Arquivos administrativos}. @xref{Arquivos
+administrativos}, para uma descrição completa. Você
+pode usar o @sc{cvs} sem nenhum destes arquivos, mas
+alguns comandos funcionam melhor quando pelo menos o
+arquivo @file{modules} está bem configurado.
+
+@c <en>The most important of these files is the @file{modules}
+@c <en>file. It defines all modules in the repository. This
+@c <en>is a sample @file{modules} file.
+O mais importante destes arquivos é o arquivo
+@file{modules}. Ele define todos os módulos no
+repositório. Este é um exemplo de um arquivo @file{modules}.
+
+@c FIXME: The CVSROOT line is a goofy example now that
+@c mkmodules doesn't exist.
+@example
+CVSROOT CVSROOT
+modules CVSROOT modules
+cvs gnu/cvs
+rcs gnu/rcs
+diff gnu/diff
+tc yoyodyne/tc
+@end example
+
+@c <en>The @file{modules} file is line oriented. In its
+@c <en>simplest form each line contains the name of the
+@c <en>module, whitespace, and the directory where the module
+@c <en>resides. The directory is a path relative to
+@c <en>@code{$CVSROOT}. The last four lines in the example
+@c <en>above are examples of such lines.
+O arquivo @file{modules} é baseado em linha. Na sua
+forma simples, cada linha contém o nome do módulo, um
+espaço e o diretório onde o módulo está. O diretório é
+um caminho relativo em @code{$CVSROOT}. As últimas
+quatro linhas no exemplo acima são exemplos de tais linhas.
+
+@c FIXME: might want to introduce the concept of options in modules file
+@c (the old example which was here, -i mkmodules, is obsolete).
+
+@c <en>The line that defines the module called @samp{modules}
+@c <en>uses features that are not explained here.
+@c <en>@xref{modules}, for a full explanation of all the
+@c <en>available features.
+A linha que define o módulo chamado @samp{modules} usa
+funcionalidades que não são explicadas
+aqui. @xref{modules}, para uma explicação completa
+destas funcionalidades.
+
+@c FIXME: subsection without node is bogus
+@c <en>@subsection Editing administrative files
+@subsection Editando arquivos administrativos
+@c <en>@cindex Editing administrative files
+@cindex Editando arquivos administrativos
+@c <en>@cindex Administrative files, editing them
+@cindex Arquivos administrativos, editando
+
+@c <en>You edit the administrative files in the same way that you would edit
+@c <en>any other module. Use @samp{cvs checkout CVSROOT} to get a working
+@c <en>copy, edit it, and commit your changes in the normal way.
+Você edita os arquivos administrativos da mesma forma
+que você deve deve editar qualquer outro módulo. Use
+@samp{cvs checkout CVSROOT} para obter uma cópia de
+trabalho, edite-a e ???commit??? suas mudanças normalmente.
+
+@c <en>It is possible to commit an erroneous administrative
+@c <en>file. You can often fix the error and check in a new
+@c <en>revision, but sometimes a particularly bad error in the
+@c <en>administrative file makes it impossible to commit new
+@c <en>revisions.
+É possível ???commit??? um arquivo administrativo
+corrompido. Em geral, você pode consertar o erro e
+devolvê-lo numa nova revisão, mas às vezes um erro
+particularmente ruim nos arquivos administrativos torna
+impossível ???commit??? novas revisões.
+@c @xref{Bad administrative files} for a hint
+@c about how to solve such situations.
+@c -- administrative file checking--
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Multiple repositories
+@node Repositórios múltiplos
+@c <en>@section Multiple repositories
+@section Repositórios múltiplos
+@c <en>@cindex Multiple repositories
+@cindex Repositórios múltiplos
+@c <en>@cindex Repositories, multiple
+@cindex Repositórios, múltiplos
+@c <en>@cindex Many repositories
+@cindex Muitos repositórios
+@c <en>@cindex Parallel repositories
+@cindex Repositórios paralelos
+@c <en>@cindex Disjoint repositories
+@cindex Repositórios Disjuntos
+@c <en>@cindex CVSROOT, multiple repositories
+@cindex CVSROOT, Repositórios Múltiplos
+
+@c <en>In some situations it is a good idea to have more than
+@c <en>one repository, for instance if you have two
+@c <en>development groups that work on separate projects
+@c <en>without sharing any code. All you have to do to have
+@c <en>several repositories is to specify the appropriate
+@c <en>repository, using the @code{CVSROOT} environment
+@c <en>variable, the @samp{-d} option to @sc{cvs}, or (once
+@c <en>you have checked out a working directory) by simply
+@c <en>allowing @sc{cvs} to use the repository that was used
+@c <en>to check out the working directory
+@c <en>(@pxref{Specifying a repository}).
+Em algumas situações é uma boa idéia ter mais de um
+repositório. Por exemplo, se você tem duas equipes de
+desenvolvimento que trabalham em projetos separados sem
+compartilhar nenhum código. Tudo que você tem que
+fazer para ter vários repositórios é especificar o
+repositório apropriado, usando a variável de ambiente
+@code{CVSROOT} ou a opção @samp{-d} com o @sc{cvs}, ou
+(depois de ter pego um diretório de trabalho)
+simplesmente deixando o @sc{cvs} usar o repositório de
+onde veio o diretório de trabalho (@pxref{Especificando
+um repositório}).
+
+@c <en>The big advantage of having multiple repositories is
+@c <en>that they can reside on different servers. With @sc{cvs}
+@c <en>version 1.10, a single command cannot recurse into
+@c <en>directories from different repositories. With development
+@c <en>versions of @sc{cvs}, you can check out code from multiple
+@c <en>servers into your working directory. @sc{cvs} will
+@c <en>recurse and handle all the details of making
+@c <en>connections to as many server machines as necessary to
+@c <en>perform the requested command. Here is an example of
+@c <en>how to set up a working directory:
+A grande vantagem de ter múltiplos repositórios é que
+eles podem residir em diferentes servidores. Com o
+@sc{cvs} versão 1.10, um comando não pode fazer
+recursão ???into??? diretórios ???from??? repositórios
+diferentes. Com ???development versions??? do
+@sc{cvs}, você pode obter código de múltiplos
+servidores para o seu diretório de trabalho. @sc{cvs}
+vai fazer a recursão e cuidar dos detalhes para fazer
+conexão em quantas máquinas quantas forem necessárias
+para executar o comando pedido. Aqui está um exemplo
+de como preparar um diretório de trabalho:
+
+@example
+cvs -d server1:/cvs co dir1
+cd dir1
+cvs -d server2:/root co sdir
+cvs update
+@end example
+
+@c <en>The @code{cvs co} commands set up the working
+@c <en>directory, and then the @code{cvs update} command will
+@c <en>contact server2, to update the dir1/sdir subdirectory,
+@c <en>and server1, to update everything else.
+Os comandos @code{cvs co} acima preparam o diretório de
+trabalho. Depois de feitos, o comando @code{cvs update}
+vai contactar o server2, para atualizar o subdiretório
+dir1/sdir e o server1, para atualizar o resto.
+
+@c FIXME: Does the FAQ have more about this? I have a
+@c dim recollection, but I'm too lazy to check right now.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Creating a repository
+@node Criando um repositório
+@c <en>@section Creating a repository
+@section Criando um repositório
+
+@c <en>@cindex Repository, setting up
+@cindex Repositório, preparando
+@c <en>@cindex Creating a repository
+@cindex Criando um repositório
+@c <en>@cindex Setting up a repository
+@cindex Preparando um repositório
+
+@c <en>To set up a @sc{cvs} repository, first choose the
+@c <en>machine and disk on which you want to store the
+@c <en>revision history of the source files. CPU and memory
+@c <en>requirements are modest, so most machines should be
+@c <en>adequate. For details see @ref{Server requirements}.
+Para preparar um repositório do @sc{cvs}, escolha
+primeiramente a máquina e o disco onde você deseja
+armazenar o histórico de revisões dos fontes.
+requisitos de CPU e memória são modestos. Portanto,
+muitas máquinas serão adequadas. Para detalhes, veja
+em @ref{Requisitos do servidor}.
+@c Possible that we should be providing a quick rule of
+@c thumb, like the 32M memory for the server. That
+@c might increase the number of people who are happy
+@c with the answer, without following the xref.
+
+@c <en>To estimate disk space
+@c <en>requirements, if you are importing RCS files from
+@c <en>another system, the size of those files is the
+@c <en>approximate initial size of your repository, or if you
+@c <en>are starting without any version history, a rule of
+@c <en>thumb is to allow for the server approximately three
+@c <en>times the size of the code to be under @sc{cvs} for the
+@c <en>repository (you will eventually outgrow this, but not
+@c <en>for a while). On the machines on which the developers
+@c <en>will be working, you'll want disk space for
+@c <en>approximately one working directory for each developer
+@c <en>(either the entire tree or a portion of it, depending
+@c <en>on what each developer uses).
+Para estimar os requisitos de espaço em disco, se você
+estiver importando arquivos RCS de outro sistema, o
+tamanho destes arquivos vai ser o tamanho inicial do
+seu repositório, ou se você está começando sem nenhum
+histórico de versões, uma boa regra é reservar para o
+repositório do servidor três vezes o tamanho do código
+que estará sob os cuidados do @sc{cvs} (Isto vai
+eventualmente estourar, mas não por enquanto).
+Nas máquinas dos desenvolvedores, você vai pracisar de
+aproximadamente o espaço em disco de um diretório de
+trabalho para cada desenvolvedor (ou a árvore inteira
+ou uma porção dela, dependendo do que o desenvolvedor
+usa).
+
+@c <en>The repository should be accessible
+@c <en>(directly or via a networked file system) from all
+@c <en>machines which want to use @sc{cvs} in server or local
+@c <en>mode; the client machines need not have any access to
+@c <en>it other than via the @sc{cvs} protocol. It is not
+@c <en>possible to use @sc{cvs} to read from a repository
+@c <en>which one only has read access to; @sc{cvs} needs to be
+@c <en>able to create lock files (@pxref{Concurrency}).
+O repositório deve estar acessível (diretamente ou
+através de um sistema de arquivos de rede) ???from???
+@c from-translator-to-reviewer: "from" or "to"?
+todas as máquinas que queiram usar o @sc{cvs} em modo
+servidor ou localmente; a máquina cliente só precisa
+ter acesso a ele através do protocolo do @sc{cvs}. Não
+é possível usar o @sc{cvs} para ler de um repositório
+onde só se tem permissão de leitura, pois o @sc{cvs}
+tem que ser capaz de criar arquivos de trava
+(@pxref{Concorrência}).
+
+@c <en>@cindex init (subcommand)
+@cindex init (subcommand)
+@c <en>To create a repository, run the @code{cvs init}
+@c <en>command. It will set up an empty repository in the
+@c <en>@sc{cvs} root specified in the usual way
+@c <en>(@pxref{Repository}). For example,
+Para criar um repositório, rode o comando @code{cvs
+init}. Ele vai criar um repositório vazio no raiz do
+@sc{cvs} especificado da forma usual
+(@pxref{Repositório}). For example,
+
+@example
+cvs -d /usr/local/cvsroot init
+@end example
+
+@c <en>@code{cvs init} is careful to never overwrite any
+@c <en>existing files in the repository, so no harm is done if
+@c <en>you run @code{cvs init} on an already set-up
+@c <en>repository.
+O @code{cvs init} tem o cuidado de nunca sobreescrever
+nenhum arquivo no repositório, logo, não há perigo em
+rodar o @code{cvs init} num repositório já criado.
+
+@c <en>@code{cvs init} will enable history logging; if you
+@c <en>don't want that, remove the history file after running
+@c <en>@code{cvs init}. @xref{history file}.
+@code{cvs init} pode guardar um registro histórico
+(history log); se
+você não quer guardar isto, remova o arquivo history
+depois de rodar o @code{cvs init}. @xref{arquivo
+history (histórico)}.
+
+@c <en>@node Backing up
+@node Fazendo backup
+@c <en>@section Backing up a repository
+@section Fazendo backup de um repositório
+@c <en>@cindex Repository, backing up
+@cindex Repositório, fazendo backup
+@c <en>@cindex Backing up, repository
+@cindex Fazendo backup, repositório
+
+@c <en>There is nothing particularly magical about the files
+@c <en>in the repository; for the most part it is possible to
+@c <en>back them up just like any other files. However, there
+@c <en>are a few issues to consider.
+Não há nada particularmente mágico sobre os arquivos no
+repositório; Para a maior parte deles é possível fazer
+backup da mesma forma que com qualquer
+arquivo. Entretanto, existem alguns fatos a considerar.
+
+@c <en>@cindex Locks, cvs, and backups
+@cindex Travas, cvs e backups
+@c <en>@cindex #cvs.rfl, and backups
+@cindex #cvs.rfl, and backups
+@c <en>The first is that to be paranoid, one should either not
+@c <en>use @sc{cvs} during the backup, or have the backup
+@c <en>program lock @sc{cvs} while doing the backup. To not
+@c <en>use @sc{cvs}, you might forbid logins to machines which
+@c <en>can access the repository, turn off your @sc{cvs}
+@c <en>server, or similar mechanisms. The details would
+@c <en>depend on your operating system and how you have
+@c <en>@sc{cvs} set up. To lock @sc{cvs}, you would create
+@c <en>@file{#cvs.rfl} locks in each repository directory.
+@c <en>See @ref{Concurrency}, for more on @sc{cvs} locks.
+@c <en>Having said all this, if you just back up without any
+@c <en>of these precautions, the results are unlikely to be
+@c <en>particularly dire. Restoring from backup, the
+@c <en>repository might be in an inconsistent state, but this
+@c <en>would not be particularly hard to fix manually.
+Primeiramente, para ser paranóico, alguem não deve nem
+sequer usar o @sc{cvs} durante o backup, ou fazer o
+programa de backup travar o @sc{cvs} enquanto estiver
+executando. Para o @sc{cvs} não ser usado, você deve
+proibir logins para máquinas que possam acessar o
+repositório ou desligar o seu servidor @sc{cvs} or
+algum mecanismo similar. Os detalhes vão depender do
+seu sistema operacional e de como você configurou o seu
+@sc{cvs}. Para travar o @sc{cvs}, você deve criar
+travas @file{#cvs.rfl} em cada diretório do
+repositório. Veja em @ref{Concorrência}, para saber
+mais sobre travas no @sc{cvs}. ???Having said all
+this???,
+@c from-translator-to-reviewer can I substitute for
+@c "nevertheless"?
+se você apenas fizer o backup sem nenhuma
+destas precauções, os resultados dificilmente vão ser
+catastróficos. Ao recuperar do backup, o repositório
+pode estar em um estado inconsistente, mas isto não
+deve ser muito difícil de consertar manualmente.
+
+@c <en>When you restore a repository from backup, assuming
+@c <en>that changes in the repository were made after the time
+@c <en>of the backup, working directories which were not
+@c <en>affected by the failure may refer to revisions which no
+@c <en>longer exist in the repository. Trying to run @sc{cvs}
+@c <en>in such directories will typically produce an error
+@c <en>message. One way to get those changes back into the
+@c <en>repository is as follows:
+Quando você recupera um repositório de um backup,
+supondo que mudanças no repositório foram feitas depois
+da criação do backup, diretório de trabalho que não
+foram afetados pela falha podem se referenciar a
+revisões que não mais existam no repositório. Tentar
+rodar o @sc{cvs} em tais diretórios vai gerar uma
+mensagem de erro. uma forma de desfazer estas mudanças
+no repositório é dada a seguir:
+
+@itemize @bullet
+@item
+@c <en>Get a new working directory.
+Gere um novo diretório de trabalho.
+
+@item
+@c <en>Copy the files from the working directory from before
+@c <en>the failure over to the new working directory (do not
+@c <en>copy the contents of the @file{CVS} directories, of
+@c <en>course).
+Copie os arquivos do diretório de trabalho de
+antes da falha para o novo diretório de trabalho (não
+copie o conteúdo dos diretórios @file{CVS}, obviamente).
+
+@item
+@c <en>Working in the new working directory, use commands such
+@c <en>as @code{cvs update} and @code{cvs diff} to figure out
+@c <en>what has changed, and then when you are ready, commit
+@c <en>the changes into the repository.
+Mexa no novo diretório de trabalho, usando comandos
+como @code{cvs update} e @code{cvs diff} para descobrir
+o que mudou, e quando terminar, faça ???commit??? nas
+mudanças para o repositório.
+@end itemize
+
+@c <en>@node Moving a repository
+@node Movendo um repositório
+@c <en>@section Moving a repository
+@section Movendo um repositório
+@c <en>@cindex Repository, moving
+@cindex Repositório, movendo
+@c <en>@cindex Moving a repository
+@cindex Movendo um repositório
+@c <en>@cindex Copying a repository
+@cindex Copiando um repositório
+
+@c <en>Just as backing up the files in the repository is
+@c <en>pretty much like backing up any other files, if you
+@c <en>need to move a repository from one place to another it
+@c <en>is also pretty much like just moving any other
+@c <en>collection of files.
+Assim como fazer backup dos arquivos no repositório é
+muito parecido com fazer backup de quaisquer outros
+arquivos, se você precisar mover um repositório de um
+lugar para outro, é muito parecido com simplesmente
+mover uma coleção de arquivos.
+
+@c <en>The main thing to consider is that working directories
+@c <en>point to the repository. The simplest way to deal with
+@c <en>a moved repository is to just get a fresh working
+@c <en>directory after the move. Of course, you'll want to
+@c <en>make sure that the old working directory had been
+@c <en>checked in before the move, or you figured out some
+@c <en>other way to make sure that you don't lose any
+@c <en>changes. If you really do want to reuse the existing
+@c <en>working directory, it should be possible with manual
+@c <en>surgery on the @file{CVS/Repository} files. You can
+@c <en>see @ref{Working directory storage}, for information on
+@c <en>the @file{CVS/Repository} and @file{CVS/Root} files, but
+@c <en>unless you are sure you want to bother, it probably
+@c <en>isn't worth it.
+O mais importante a se considerar é que diretórios de
+trabalho apontam para o repositório. A forma mais
+simples de lidar com um repositório movido é
+simplesmente pegar um diretório de trabalho novo logo
+após da mudança. É claro que você vai querer se
+certificar que o diretório de trabalho antigo foi
+devolvido antes da mudança, ou usar de qualquer outro
+artifício para se certificar de que não perderá nenhuma
+mudança. Se você realmente quer reusar o antigo diretório de
+trabalho, é possível, desde que você faça uma operação
+manual nos arquivos @file{CVS/Repository}. Você pode
+ver em @ref{Armazenamento do Diretório de trabalho},
+para informações sobre os arquivos
+@file{CVS/Repository} e @file{CVS/Root}, mas só se você
+quiser ter aborrecimentos, caso contrário esta opção
+não é boa.
+@c FIXME: Surgery on CVS/Repository should be avoided
+@c by making RELATIVE_REPOS the default.
+@c FIXME-maybe: might want some documented way to
+@c change the CVS/Root files in some particular tree.
+@c But then again, I don't know, maybe just having
+@c people do this in perl/shell/&c isn't so bad...
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Remote repositories
+@node Repositórios remotos
+@c <en>@section Remote repositories
+@section Repositórios remotos
+@c <en>@cindex Repositories, remote
+@cindex Repositórios, remotos
+@c <en>@cindex Remote repositories
+@cindex Repositórios remotos
+@c <en>@cindex Client/Server Operation
+@cindex Operação cliente/Servidor
+@c <en>@cindex Server, CVS
+@cindex Servidor, CVS
+@c <en>@cindex Remote repositories, port specification
+@cindex Repositórios remotos, especificação de porta
+@c <en>@cindex Repositories, remote, port specification
+@cindex Repositórios, remotos, especificação de porta
+@c <en>@cindex Client/Server Operation, port specification
+@cindex Operação cliente/Servidor, especificação de porta
+@c <en>@cindex pserver (client/server connection method), port specification
+@cindex pserver (método de conexão cliente/servidor), especificação de porta
+@c <en>@cindex kserver (client/server connection method), port specification
+@cindex kserver (método de conexão cliente/servidor), especificação de porta
+@c <en>@cindex gserver (client/server connection method), port specification
+@cindex gserver (método de conexão cliente/servidor), especificação de porta
+@c <en>@cindex port, specifying for remote repositories
+@cindex porta, especificação para repositórios remotos
+
+@c <en> Your working copy of the sources can be on a
+@c <en>different machine than the repository. Using @sc{cvs}
+@c <en>in this manner is known as @dfn{client/server}
+@c <en>operation. You run @sc{cvs} on a machine which can
+@c <en>mount your working directory, known as the
+@c <en>@dfn{client}, and tell it to communicate to a machine
+@c <en>which can mount the repository, known as the
+@c <en>@dfn{server}. Generally, using a remote
+@c <en>repository is just like using a local one, except that
+@c <en>the format of the repository name is:
+Sua cópia de trabalho dos fontes pode estar em
+uma máquina diferente da do repositório. Esta forma de
+usar o @sc{cvs} é chamada operação
+@dfn{client/server}. Você roda o @sc{cvs} numa máquina
+que possa montar seu diretório de trabalho, conhecida
+como o @dfn{cliente}, e diz a ela para se comunicar com
+uma máquina que pode montar o repositório, chamada de
+@dfn{servidor}. No geral, usar um repositório remoto
+é a mesma coisa que usar um local, exceto que o formato
+do nome do repositório é:
+
+@example
+[:@var{method}:][[@var{user}][:@var{password}]@@]@var{hostname}[:[@var{port}]]/path/to/repository
+@end example
+
+@c <en>Specifying a password in the repository name is not recommended during
+@c <en>checkout, since this will cause @sc{cvs} to store a cleartext copy of the
+@c <en>password in each created directory. @code{cvs login} first instead
+@c <en>(@pxref{Password authentication client}).
+Colocar a senha no nome do repositório durante
+operações de checkout não é recomendado, já que isto
+vai fazer com que o @sc{cvs} guarde uma cópia da senha
+em texto em cada diretório criado. Dê um @code{cvs
+login} primeiro ao invés disto
+(@pxref{Cliente de autenticação por senha}).
+
+@c <en>The details of exactly what needs to be set up depend
+@c <en>on how you are connecting to the server.
+Os detalhes de exatamente o que precisa ser preparado
+depende de como você está conectado ao seu servidor.
+
+@c <en>If @var{method} is not specified, and the repository
+@c <en>name contains @samp{:}, then the default is @code{ext}
+@c <en>or @code{server}, depending on your platform; both are
+@c <en>described in @ref{Connecting via rsh}.
+Se @var{method} não está especificado, e se o nome do
+repositório contém @samp{:}, então o padrão é
+@code{ext} ou @code{server}, dependendo de sua
+plataforma; ambos estão descritos em
+@ref{Se conectando via rsh}.
+@c Should we try to explain which platforms are which?
+@c Platforms like unix and VMS, which only allow
+@c privileged programs to bind to sockets <1024 lose on
+@c :server:
+@c Platforms like Mac and VMS, whose rsh program is
+@c unusable or nonexistent, lose on :ext:
+@c Platforms like OS/2 and NT probably could plausibly
+@c default either way (modulo -b troubles).
+
+@c FIXME: We need to have a better way of explaining
+@c what method to use. This presentation totally
+@c obscures the fact that :ext: and CVS_RSH is the way to
+@c use SSH, for example. Plus it incorrectly implies
+@c that you need an @code{rsh} binary on the client to use
+@c :server:.
+@c Also note that rsh not pserver is the right choice if you want
+@c users to be able to create their own repositories
+@c (because of the --allow-root related issues).
+@menu
+@c <en>* Server requirements:: Memory and other resources for servers
+* Requisitos do servidor:: Memória e outros recursos para servidores
+@c <en>* Connecting via rsh:: Using the @code{rsh} program to connect
+* Se conectando via rsh:: Usando o programa @code{rsh} para se conectar
+@c <en>* Password authenticated:: Direct connections using passwords
+* Autenticação por senha:: Conexões diretas usando senhas
+@c <en>* GSSAPI authenticated:: Direct connections using GSSAPI
+* Autenticação GSSAPI:: Conexões diretas usando GSSAPI
+@c <en>* Kerberos authenticated:: Direct connections with kerberos
+* Autenticação kerberos:: Conexões diretas com kerberos
+@c <en>* Connecting via fork:: Using a forked @code{cvs server} to connect
+* Conectando via fork:: Usando um forked @code{cvs server} para conectar
+@end menu
+
+@c <en>@node Server requirements
+@node Requisitos do servidor
+@c <en>@subsection Server requirements
+@subsection Requisitos do servidor
+
+@c <en>The quick answer to what sort of machine is suitable as
+@c <en>a server is that requirements are modest---a server
+@c <en>with 32M of memory or even less can handle a fairly
+@c <en>large source tree with a fair amount of activity.
+A resposta rápida para que tipo de máquina é adequada
+para um servidor é que os requisitos são modestos---um
+servidor com 32M de memória ou até menos pode manipular
+uma árvore de fontes realmente grande com uma boa
+quantidade de atividade.
+@c Say something about CPU speed too? I'm even less sure
+@c what to say on that subject...
+
+@c <en>The real answer, of course, is more complicated.
+@c <en>Estimating the known areas of large memory consumption
+@c <en>should be sufficient to estimate memory requirements.
+@c <en>There are two such areas documented here; other memory
+@c <en>consumption should be small by comparison (if you find
+@c <en>that is not the case, let us know, as described in
+@c <en>@ref{BUGS}, so we can update this documentation).
+A resposta real, obviamente, é mais complicada. Estimar
+as áreas conhecidas de grande consumo de memória deve
+ser suficiente para estimar os requisitos de
+memória. Existem duas destas tais áreas documentadas
+aqui; Outros consumos de memória devem ser pequenos
+relativamente (se você notar que este não é o caso, nos
+faça saber, como descrito em @ref{Paus}, assim
+poderemos atualizar este documento).
+
+@c <en>The first area of big memory consumption is large
+@c <en>checkouts, when using the @sc{cvs} server. The server
+@c <en>consists of two processes for each client that it is
+@c <en>serving. Memory consumption on the child process
+@c <en>should remain fairly small. Memory consumption on the
+@c <en>parent process, particularly if the network connection
+@c <en>to the client is slow, can be expected to grow to
+@c <en>slightly more than the size of the sources in a single
+@c <en>directory, or two megabytes, whichever is larger.
+A primeira área de grande consumo de memória são os
+grandes checkouts, quando usando o servidor @sc{cvs}.
+O servidor consiste de dois processos para cada cliente
+que está servindo. O consumo de memória no processo
+filho deve permanecer pequeno. O consumo de memória no
+processo pai, perticularmente se a conexão de rede com
+o cliente é pequena, pode crescer para algo um pouco
+maior que o tamanho dos fontes num diretório, ou dois
+megabytes, o que for maior.
+@c "two megabytes" of course is SERVER_HI_WATER. But
+@c we don't mention that here because we are
+@c documenting the default configuration of CVS. If it
+@c is a "standard" thing to change that value, it
+@c should be some kind of run-time configuration.
+@c
+@c See cvsclient.texi for more on the design decision
+@c to not have locks in place while waiting for the
+@c client, which is what results in memory consumption
+@c as high as this.
+
+@c <en>Multiplying the size of each @sc{cvs} server by the
+@c <en>number of servers which you expect to have active at
+@c <en>one time should give an idea of memory requirements for
+@c <en>the server. For the most part, the memory consumed by
+@c <en>the parent process probably can be swap space rather
+@c <en>than physical memory.
+Multiplicando o tamanho de cada servidor @sc{cvs} pelo
+número de servidores que você espera ter ativos em cada
+momento deve dar uma idéia dos requisitos de memória
+para cada servidor. Para a maior parte, a memória
+consumida pelo processo pai pode provavelmente ser
+espaço de troca ao invés de memória física.
+@c Has anyone verified that notion about swap space?
+@c I say it based pretty much on guessing that the
+@c ->text of the struct buffer_data only gets accessed
+@c in a first in, first out fashion, but I haven't
+@c looked very closely.
+
+@c What about disk usage in /tmp on the server? I think that
+@c it can be substantial, but I haven't looked at this
+@c again and tried to figure it out ("cvs import" is
+@c probably the worst case...).
+
+@c <en>The second area of large memory consumption is
+@c <en>@code{diff}, when checking in large files. This is
+@c <en>required even for binary files. The rule of thumb is
+@c <en>to allow about ten times the size of the largest file
+@c <en>you will want to check in, although five times may be
+@c <en>adequate. For example, if you want to check in a file
+@c <en>which is 10 megabytes, you should have 100 megabytes of
+@c <en>memory on the machine doing the checkin (the server
+@c <en>machine for client/server, or the machine running
+@c <en>@sc{cvs} for non-client/server). This can be swap
+@c <en>space rather than physical memory. Because the memory
+@c <en>is only required briefly, there is no particular need
+@c <en>to allow memory for more than one such checkin at a
+@c <en>time.
+A segunda área de grande consumo de memória é o
+@code{diff}, quando trazendo grandes arquivos. Isto é
+preciso mesmo para arquivos binários. A boa prática é
+permitir cerca de dez vezes o tamanho do maior arquivo
+que você vai devolver ao servidor, embora cinco vezes
+seja adequado. Por exemplo, se você quer devolver um
+arquivo de 10 megabytes, você deve ter 100 megabytes of
+memory na máquina fazendo a devolução (o servidor para
+o caso cliente/servidor, ou a máquina rodando o
+@sc{cvs} para não-cliente/servidor). Esta memória pode
+ser espaço de troca ao invés de memória física. Já que
+a memória é requerida apenas brevemente, não existe
+necessidade especial para fornecer memória para mais
+de uma devolução ao mesmo tempo.
+@c The 5-10 times rule of thumb is from Paul Eggert for
+@c GNU diff. I don't think it is in the GNU diff
+@c manual or anyplace like that.
+@c
+@c Probably we could be saying more about
+@c non-client/server CVS.
+@c I would guess for non-client/server CVS in an NFS
+@c environment the biggest issues are the network and
+@c the NFS server.
+
+@c <en>Resource consumption for the client is even more
+@c <en>modest---any machine with enough capacity to run the
+@c <en>operating system in question should have little
+@c <en>trouble.
+O consumo de recursos no cliente é ainda mais
+modesto---qualquer máquina com capacidade suficiente
+para rodar o SO em questão não deve ter muitos
+problemas.
+@c Is that true? I think the client still wants to
+@c (bogusly) store entire files in memory at times.
+
+@c <en>For information on disk space requirements, see
+@c <en>@ref{Creating a repository}.
+Para informações sobre requisitos de espaço em disco,
+veja em @ref{Criando um repositório}.
+
+@c <en>@node Connecting via rsh
+@node Se conectando via rsh
+@c <en>@subsection Connecting with rsh
+@subsection Se conectando via rsh
+
+@c <en>@cindex rsh
+@cindex rsh
+@c <en>@sc{cvs} uses the @samp{rsh} protocol to perform these
+@c <en>operations, so the remote user host needs to have a
+@c <en>@file{.rhosts} file which grants access to the local
+@c <en>user. Note that the program that @sc{cvs} uses for this
+@c <en>purpose may be specified using the @file{--with-rsh}
+@c <en>flag to configure.
+O @sc{cvs} usa o protocolo @samp{rsh} para realizar
+estas operações, logo, a máquina do usuário remoto tem
+que ter um arquivo @file{.rhosts} que dê acesso para o
+usuário local. Observe que o programa que o @sc{cvs}
+usa para este objetivo deve ser especificado usando a
+opção @file{--with-rsh} para configurar.
+
+@c <en>For example, suppose you are the user @samp{mozart} on
+@c <en>the local machine @samp{toe.example.com}, and the
+@c <en>server machine is @samp{faun.example.org}. On
+@c <en>faun, put the following line into the file
+@c <en>@file{.rhosts} in @samp{bach}'s home directory:
+Por exemplo, suponha que você é o usuário @samp{mozart}
+na máquina local @samp{toe.example.com}, e a máquina
+servidora é @samp{faun.example.org}. Em faun, ponha a
+seguinte linha no arquivo @file{.rhosts} no diretório
+pessoal de @samp{bach}:
+
+@example
+toe.example.com mozart
+@end example
+
+@noindent
+@c <en>Then test that @samp{rsh} is working with
+E faça o teste para ver que o @samp{rsh} está
+funcionando com
+
+@example
+rsh -l bach faun.example.org 'echo $PATH'
+@end example
+
+@c <en>@cindex CVS_SERVER, environment variable
+@cindex CVS_SERVER, variável de ambiente
+@c <en>Next you have to make sure that @code{rsh} will be able
+@c <en>to find the server. Make sure that the path which
+@c <en>@code{rsh} printed in the above example includes the
+@c <en>directory containing a program named @code{cvs} which
+@c <en>is the server. You need to set the path in
+@c <en>@file{.bashrc}, @file{.cshrc}, etc., not @file{.login}
+@c <en>or @file{.profile}. Alternately, you can set the
+@c <en>environment variable @code{CVS_SERVER} on the client
+@c <en>machine to the filename of the server you want to use,
+@c <en>for example @file{/usr/local/bin/cvs-1.6}.
+A seguir você vai ter que se certificar que o
+@code{rsh} vai ser capaz de acessar o servidor.
+Verifique se o caminho que o @code{rsh} mostrou no
+exemplo acima inclui o diretório contendo um programa
+chamado @code{cvs} que está no servidor. Você precisa
+ajustar o caminho no @file{.bashrc}, @file{.cshrc},
+etc., não no @file{.login} ou no @file{.profile}.
+Alternativamente, você pode ajustar a variável de
+ambiente @code{CVS_SERVER} na máquina cliente para o
+nome do arquivo do servidor que você quer usar, por
+exemplo @file{/usr/local/bin/cvs-1.6}.
+@c FIXME: there should be a way to specify the
+@c program in CVSROOT, not CVS_SERVER, so that one can use
+@c different ones for different roots. e.g. ":server;cvs=cvs-1.6:"
+@c instead of ":server:".
+
+@c <en>There is no need to edit @file{inetd.conf} or start a
+@c <en>@sc{cvs} server daemon.
+Não há necessidade de se editar o @file{inetd.conf} ou
+iniciar um daemon (serviço) servidor de @sc{cvs}.
+
+@c <en>@cindex :server:, setting up
+@cindex :servidor:, ajustando
+@c <en>@cindex :ext:, setting up
+@cindex :ext:, ajustando
+@c <en>@cindex Kerberos, using kerberized rsh
+@cindex Kerberos, usando rsh kerberizado
+@c <en>@cindex SSH (rsh replacement)
+@cindex SSH (substituto do rsh)
+@c <en>@cindex rsh replacements (Kerberized, SSH, &c)
+@cindex Substitutos do rsh (Kerberizado, SSH, &c)
+@c <en>There are two access methods that you use in @code{CVSROOT}
+@c <en>for rsh. @code{:server:} specifies an internal rsh
+@c <en>client, which is supported only by some @sc{cvs} ports.
+@c <en>@code{:ext:} specifies an external rsh program. By
+@c <en>default this is @code{rsh} (unless otherwise specified
+@c <en>by the @file{--with-rsh} flag to configure) but you may set the
+@c <en>@code{CVS_RSH} environment variable to invoke another
+@c <en>program which can access the remote server (for
+@c <en>example, @code{remsh} on HP-UX 9 because @code{rsh} is
+@c <en>something different). It must be a program which can
+@c <en>transmit data to and from the server without modifying
+@c <en>it; for example the Windows NT @code{rsh} is not
+@c <en>suitable since it by default translates between CRLF
+@c <en>and LF. The OS/2 @sc{cvs} port has a hack to pass @samp{-b}
+@c <en>to @code{rsh} to get around this, but since this could
+@c <en>potentially cause problems for programs other than the
+@c <en>standard @code{rsh}, it may change in the future. If
+@c <en>you set @code{CVS_RSH} to @code{SSH} or some other rsh
+@c <en>replacement, the instructions in the rest of this
+@c <en>section concerning @file{.rhosts} and so on are likely
+@c <en>to be inapplicable; consult the documentation for your rsh
+@c <en>replacement.
+Existem dois métodos de acesso que você pode usar no
+@code{CVSROOT} para rsh. @code{:server:} especifica um
+cliente rsh interno, que é suportado apenas por
+alguns portes do @sc{cvs}. @code{:ext:} especifica um
+programa rsh externo. Por padrão é o @code{rsh} (a
+menos que se especifique o contrário pela opção
+@file{--with-rsh}) mas você pode ajustar a variável de
+ambiente @code{CVS_RSH} para invocar outro programa que
+pode acessar o servidor remoto (por exemplo,
+@code{remsh} num HP-UX 9 já que o @code{rsh} é de certa
+forma diferente). Deve ser um programa que transmita
+dados de e para o servidor sem modificar nada; por
+exemplo, o @code{rsh} do Windows NT não é adequado já
+que por padrão ele permuta CRLF com LF. O porte do
+@sc{cvs} para OS/2 tem um ???hack??? para passar
+@samp{-b} para o @code{rsh} para contornar isso, mas
+já que isso pode potencialmente causar problemas para
+outros programas que não sejam o @code{rsh} padrão,
+isso deve mudar no futuro. Se você ajustar o
+@code{CVS_RSH} para @code{SSH} ou algum outro
+substituto do rsh, as instruções no restante desta seção a
+respeito do arquivo @file{.rhosts} e outros
+provavelmente não se aplicarão; consulte a documentação
+do seu substituto do rsh.
+@c FIXME: there should be a way to specify the
+@c program in CVSROOT, not CVS_RSH, so that one can use
+@c different ones for different roots. e.g. ":ext;rsh=remsh:"
+@c instead of ":ext:".
+@c See also the comment in src/client.c for rationale
+@c concerning "rsh" being the default and never
+@c "remsh".
+
+@c <en>Continuing our example, supposing you want to access
+@c <en>the module @file{foo} in the repository
+@c <en>@file{/usr/local/cvsroot/}, on machine
+@c <en>@file{faun.example.org}, you are ready to go:
+Continuando nosso exemplo, supondo que você quer
+acessar o módulo @file{foo} no repositório
+@file{/usr/local/cvsroot/}, da máquina
+@file{faun.example.org}, você está pronto para seguir:
+
+@example
+cvs -d :ext:bach@@faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+@noindent
+@c <en>(The @file{bach@@} can be omitted if the username is
+@c <en>the same on both the local and remote hosts.)
+(O @file{bach@@} pode ser omitido se o nome de usuário
+é o mesmo tanto no servidor como no cliente.)
+
+@c Should we mention "rsh host echo hi" and "rsh host
+@c cat" (the latter followed by typing text and ^D)
+@c as troubleshooting techniques? Probably yes
+@c (people tend to have trouble setting this up),
+@c but this kind of thing can be hard to spell out.
+
+@c <en>@node Password authenticated
+@node Autenticação por senha
+@c <en>@subsection Direct connection with password authentication
+@subsection Conexões diretas com autenticação por senha
+
+@c <en>The @sc{cvs} client can also connect to the server
+@c <en>using a password protocol. This is particularly useful
+@c <en>if using @code{rsh} is not feasible (for example,
+@c <en>the server is behind a firewall), and Kerberos also is
+@c <en>not available.
+O cliente @sc{cvs} também pode se conectar ao servidor
+usando um protocolo de senha. Isto é particularmente
+útil se não se pode usar o @code{rsh} (por exemplo, se
+o servidor está atrás de um firewall), e o Kerberos
+também não está disponível.
+
+@c <en> To use this method, it is necessary to make
+@c <en>some adjustments on both the server and client sides.
+ Para usar este método é necessário fazer
+ajustes tanto do lado do cliente como no do servidor.
+
+@menu
+@c <en>* Password authentication server:: Setting up the server
+* Servidor de autenticação por senha:: Ajustando o servidor
+@c <en>* Password authentication client:: Using the client
+* Cliente de autenticação por senha:: Usando o cliente
+@c <en>* Password authentication security:: What this method does and does not do
+* Segurança com autenticação por senha:: O que este método faz e o que ele não faz
+@end menu
+
+@c <en>@node Password authentication server
+@node Servidor de autenticação por senha
+@c <en>@subsubsection Setting up the server for password authentication
+@subsubsection Ajustando o servidor para autenticação por senha
+
+@c <en>First of all, you probably want to tighten the
+@c <en>permissions on the @file{$CVSROOT} and
+@c <en>@file{$CVSROOT/CVSROOT} directories. See @ref{Password
+@c <en>authentication security}, for more details.
+Antes de tudo, você provavelmente vai querer amarrar as
+permissões nos diretórios @file{$CVSROOT} e
+@file{$CVSROOT/CVSROOT}. Veja em
+@ref{Segurança com autenticação por senha}
+para mais informações.
+
+@c <en>@cindex pserver (subcommand)
+@cindex pserver (subcomando)
+@c <en>@cindex Remote repositories, port specification
+@cindex Repositórios remotos, especificação de porta
+@c <en>@cindex Repositories, remote, port specification
+@cindex Repositórios, remotos, especificação de porta
+@c <en>@cindex Client/Server Operation, port specification
+@cindex Operação cliente/Servidor, especificação de porta
+@c <en>@cindex pserver (client/server connection method), port specification
+@cindex pserver (método de conexão cliente/servidor), especificação de porta
+@c <en>@cindex kserver (client/server connection method), port specification
+@cindex kserver (método de conexão cliente/servidor), especificação de porta
+@c <en>@cindex gserver (client/server connection method), port specification
+@cindex gserver (método de conexão cliente/servidor), especificação de porta
+@c <en>@cindex port, specifying for remote repositories
+@cindex porta, especificação para repositórios remotos
+@c <en>@cindex Password server, setting up
+@cindex Servidor por senha, ajustando
+@c <en>@cindex Authenticating server, setting up
+@cindex Servidor por autenticação, ajustando
+@c <en>@cindex inetd, configuring for pserver
+@cindex inetd, configurando para pserver
+@c <en>@cindex xinetd, configuring for pserver
+@cindex xinetd, configurando para pserver
+@c FIXME: this isn't quite right regarding port
+@c numbers; CVS looks up "cvspserver" in
+@c /etc/services (on unix, but what about non-unix?).
+@c <en>On the server side, the file @file{/etc/inetd.conf}
+@c <en>needs to be edited so @code{inetd} knows to run the
+@c <en>command @code{cvs pserver} when it receives a
+@c <en>connection on the right port. By default, the port
+@c <en>number is 2401; it would be different if your client
+@c <en>were compiled with @code{CVS_AUTH_PORT} defined to
+@c <en>something else, though. This can also be specified in the CVSROOT variable
+@c <en>(@pxref{Remote repositories}) or overridden with the CVS_CLIENT_PORT
+@c <en>environment variable (@pxref{Environment variables}).
+No lado do servidor, o arquivo @file{/etc/inetd.conf}
+precisa ser editado para que o @code{inetd} saiba rodar
+o comando @code{cvs pserver} quando ele recebe uma
+conexão pela porta certa. Por padrão, a porta de
+número 2401; entretanto, isto pode ser diferente se seu
+cliente foi compilado com @code{CVS_AUTH_PORT} definido
+para outra coisa. Esta porta também pode ser
+especificada na variável CVSROOT
+(@pxref{Repositórios remotos}) ou sobreescrita com a variável de
+ambiente CVS_CLIENT_PORT (@pxref{Variáveis de ambiente}).
+
+@c <en> If your @code{inetd} allows raw port numbers in
+@c <en>@file{/etc/inetd.conf}, then the following (all on a
+@c <en>single line in @file{inetd.conf}) should be sufficient:
+ Se seu @code{inetd} permite ???raw port
+numbers??? no @file{/etc/inetd.conf}, então o seguinte
+(tudo na mesma linha do @file{inetd.conf}) deve ser suficiente:
+
+@example
+2401 stream tcp nowait root /usr/local/bin/cvs
+cvs -f --allow-root=/usr/cvsroot pserver
+@end example
+
+@noindent
+@c <en>(You could also use the
+@c <en>@samp{-T} option to specify a temporary directory.)
+(Você pode usar também a opção @samp{-T} para
+especificar um diretório temporário.)
+
+@c <en>The @samp{--allow-root} option specifies the allowable
+@c <en>@sc{cvsroot} directory. Clients which attempt to use a
+@c <en>different @sc{cvsroot} directory will not be allowed to
+@c <en>connect. If there is more than one @sc{cvsroot}
+@c <en>directory which you want to allow, repeat the option.
+@c <en>(Unfortunately, many versions of @code{inetd} have very small
+@c <en>limits on the number of arguments and/or the total length
+@c <en>of the command. The usual solution to this problem is
+@c <en>to have @code{inetd} run a shell script which then invokes
+@c <en>@sc{cvs} with the necessary arguments.)
+A opção @samp{--allow-root} especifica o diretório
+@sc{cvsroot} permitido. Clientes que tentem usar um
+diretório @sc{cvsroot} diferente não conseguirão se
+conectar. Se você quer permitir mais de um diretório
+@sc{cvsroot}, repita a opção.
+(Infelismente, muitas versões do @code{inetd} têm um
+limite muito baixo do número de argumentos e/ou do
+comprimento total do comando. A solução usual para
+este problema é fazer o @code{inetd} rodar um script de
+shell que invoque o @sc{cvs} com os argumentos
+necessários.)
+
+@c <en> If your @code{inetd} wants a symbolic service
+@c <en>name instead of a raw port number, then put this in
+@c <en>@file{/etc/services}:
+ Se seu @code{inetd} precisa de um nome
+simbólico de serviço ao invés de um número de porta,
+ponha em @file{/etc/services}:
+
+@example
+cvspserver 2401/tcp
+@end example
+
+@noindent
+@c <en>and put @code{cvspserver} instead of @code{2401} in @file{inetd.conf}.
+e ponha @code{cvspserver} no lugar de @code{2401} no @file{inetd.conf}.
+
+@c <en>If your system uses @code{xinetd} instead of @code{inetd},
+@c <en>the procedure is slightly different.
+@c <en>Create a file called @file{/etc/xinetd.d/cvspserver} containing the following:
+Se seu sistema usa @code{xinetd} no lugar de @code{inetd},
+o procedimento é um pouco diferente. Crie um arquivo
+chamado @file{/etc/xinetd.d/cvspserver} contendo o seguinte:
+
+@example
+service cvspserver
+@{
+ port = 2401
+ socket_type = stream
+ protocol = tcp
+ wait = no
+ user = root
+ passenv = PATH
+ server = /usr/local/bin/cvs
+ server_args = -f --allow-root=/usr/cvsroot pserver
+@}
+@end example
+
+@noindent
+@c <en>(If @code{cvspserver} is defined in @file{/etc/services}, you can omit
+@c <en>the @code{port} line.)
+(Se @code{cvspserver} é definido no
+@file{/etc/services}, você pode omitir a linha @code{port}.)
+
+@c <en> Once the above is taken care of, restart your
+@c <en>@code{inetd}, or do whatever is necessary to force it
+@c <en>to reread its initialization files.
+ Uma vez que as instruções acima foram seguidas,
+reinicie seu @code{inetd}, ou faça o que for necessário
+para forçá-lo a reler seus arquivos de inicialização.
+
+@c <en>If you are having trouble setting this up, see
+@c <en>@ref{Connection}.
+Se você enfrentar problemas, veja em @ref{Conexão}.
+
+@c <en>@cindex CVS passwd file
+@cindex Arquivo passwd do CVS
+@c <en>@cindex passwd (admin file)
+@cindex passwd (arquivo administrativo)
+@c <en>Because the client stores and transmits passwords in
+@c <en>cleartext (almost---see @ref{Password authentication
+@c <en>security}, for details), a separate @sc{cvs} password
+@c <en>file is generally used, so people don't compromise
+@c <en>their regular passwords when they access the
+@c <en>repository. This file is
+@c <en>@file{$CVSROOT/CVSROOT/passwd} (@pxref{Intro
+@c <en>administrative files}). It uses a colon-separated
+@c <en>format, similar to @file{/etc/passwd} on Unix systems,
+@c <en>except that it has fewer fields: @sc{cvs} username,
+@c <en>optional password, and an optional system username for
+@c <en>@sc{cvs} to run as if authentication succeeds. Here is
+@c <en>an example @file{passwd} file with five entries:
+Como o cliente guarda e transmite as senhas em texto simples
+(praticamente---veja @ref{Segurança com autenticação por senha}
+para detalhes), um arquivo de senhas do @sc{cvs} é
+geralmente usado, de forma que as pessoas nao
+comprometam suas senhas regulares quando acessam o
+repositório. Este arquivo é o
+@file{$CVSROOT/CVSROOT/passwd} (@pxref{Intro aos
+arquivos administrativos}). Ele usa um formato
+separado por dois pontos, similar ao do
+@file{/etc/passwd} dos sistemas Unix, exceto que este
+tem menos campos: nome do usuário @sc{cvs}, senha
+opcional, e um nome de usuário de sistema opcional para
+o @sc{cvs} rodar como ele se ocorrer a autenticação.
+Aqui está um exemplo de arquivo @file{passwd} com cinco
+entradas:
+
+@example
+anonymous:
+bach:ULtgRLXo7NRxs
+spwang:1sOp854gDF3DY
+melissa:tGX1fS8sun6rY:pubcvs
+qproj:XR4EZcEs0szik:pubcvs
+@end example
+
+@noindent
+@c <en>(The passwords are encrypted according to the standard
+@c <en>Unix @code{crypt()} function, so it is possible to
+@c <en>paste in passwords directly from regular Unix
+@c <en>@file{/etc/passwd} files.)
+(As senhas são criptografadas de acordo com a função
+Unix @code{crypt()} padrão, portanto é possível copiar
+senhas diretamente de arquivos @file{/etc/passwd}
+normais do Unix.)
+
+@c <en>The first line in the example will grant access to any
+@c <en>@sc{cvs} client attempting to authenticate as user
+@c <en>@code{anonymous}, no matter what password they use,
+@c <en>including an empty password. (This is typical for
+@c <en>sites granting anonymous read-only access; for
+@c <en>information on how to do the "read-only" part, see
+@c <en>@ref{Read-only access}.)
+A primeira linha no exemplo vai dar acesso a qualquer
+cliente @sc{cvs} que tente se autenticar como o usuário
+@code{anonymous} (anônimo), qualquer que seja a senha
+que ele esteja usando, até mesmo uma senha vazia.
+(Isto é típico de sítios que dão acesso somente-leitura
+anônimo; para informações sobre como fazer a parte
+"somente-leitura", veja em @ref{Acesso somente-leitura}.)
+
+@c <en>The second and third lines will grant access to
+@c <en>@code{bach} and @code{spwang} if they supply their
+@c <en>respective plaintext passwords.
+As segunda e terceira linhas vão fornecer acesso a
+@code{bach} e @code{spwang} se eles fornecerem suas
+respectivas senhas em texto simples.
+
+@c <en>@cindex User aliases
+@cindex User aliases
+@c <en>The fourth line will grant access to @code{melissa}, if
+@c <en>she supplies the correct password, but her @sc{cvs}
+@c <en>operations will actually run on the server side under
+@c <en>the system user @code{pubcvs}. Thus, there need not be
+@c <en>any system user named @code{melissa}, but there
+@c <en>@emph{must} be one named @code{pubcvs}.
+A quarta linha vai dar acesso a @code{melissa}, se ela
+fornecer a senha correta, mas suas opareções no
+@sc{cvs} vão ser rodadas, na verdade, como o usuário de
+sistema @code{pubcvs} no lado do servidor. Logo, não
+há a necessidade de haver qualquer usuário chamado
+@code{melissa}, mas @emph{tem que} haver um chamado
+@code{pubcvs}.
+
+@c <en>The fifth line shows that system user identities can be
+@c <en>shared: any client who successfully authenticates as
+@c <en>@code{qproj} will actually run as @code{pubcvs}, just
+@c <en>as @code{melissa} does. That way you could create a
+@c <en>single, shared system user for each project in your
+@c <en>repository, and give each developer their own line in
+@c <en>the @file{$CVSROOT/CVSROOT/passwd} file. The @sc{cvs}
+@c <en>username on each line would be different, but the
+@c <en>system username would be the same. The reason to have
+@c <en>different @sc{cvs} usernames is that @sc{cvs} will log their
+@c <en>actions under those names: when @code{melissa} commits
+@c <en>a change to a project, the checkin is recorded in the
+@c <en>project's history under the name @code{melissa}, not
+@c <en>@code{pubcvs}. And the reason to have them share a
+@c <en>system username is so that you can arrange permissions
+@c <en>in the relevant area of the repository such that only
+@c <en>that account has write-permission there.
+A quinta linha mostra que identidades de usuários de
+sistema podem ser compartilhadas: qualquer cliente que
+se autentique com sucesso como @code{qproj} vai na
+verdade rodar como @code{pubcvs}, da mesma forma que
+@code{melissa} faz. Desta forma você pode criar um
+único e compartilhado usuário de sistema para cada
+projeto no seu repositório, e dar a cada desenvolvedor
+sua própria linha no arquivo
+@file{$CVSROOT/CVSROOT/passwd}. O nome de usuário do
+@sc{cvs} em cada linha vai ser diferente, mas o usuário
+de sistema vai ser o mesmo. A razão para se ter
+diferentes nomes de usuários do @sc{cvs} é que o
+@sc{cvs} vai registrar suas ações sob estes nomes:
+quando @code{melissa} submete (commit) uma mudança ao
+projeto, o checkin é gravado no histórico do projeto em
+nome de @code{melissa}, não de @code{pubcvs}. E a
+razão para tê-los compartilhando um usuário de sistema
+é que você pode ajeitar as permissões da área relevante
+do repositório de forma que apenas aquela conta tenha
+permissão de leitura lá.
+
+@c <en>If the system-user field is present, all
+@c <en>password-authenticated @sc{cvs} commands run as that
+@c <en>user; if no system user is specified, @sc{cvs} simply
+@c <en>takes the @sc{cvs} username as the system username and
+@c <en>runs commands as that user. In either case, if there
+@c <en>is no such user on the system, then the @sc{cvs}
+@c <en>operation will fail (regardless of whether the client
+@c <en>supplied a valid password).
+Se o campo do usuário de sistema está presente, todos
+os comandos do @sc{cvs} com autenticação por senha
+rodarão como aquele usuário; se nenhum usuário é
+especificado, o @sc{cvs} simplesmente vai usar o nome
+de usuário do @sc{cvs} como o nome de usuário de
+sistema e rodar os comandos como este usuário. Em
+qualquer caso, se não existir tal usuário no sistema, a
+operação do @sc{cvs} vai falhar (independente do
+cliente ter fornecido uma senha válida).
+
+@c <en>The password and system-user fields can both be omitted
+@c <en>(and if the system-user field is omitted, then also
+@c <en>omit the colon that would have separated it from the
+@c <en>encrypted password). For example, this would be a
+@c <en>valid @file{$CVSROOT/CVSROOT/passwd} file:
+Os campos de senha e usuário de sistema podem ser ambos
+omitidos (e se o campo de usuário de sistema for
+omitido, então a vírgula que o separava da senha
+criptografada também pode ser omitida). Por exemplo,
+isto pode ser um arquivo @file{$CVSROOT/CVSROOT/passwd} válido:
+
+@example
+anonymous::pubcvs
+fish:rKa5jzULzmhOo:kfogel
+sussman:1sOp854gDF3DY
+@end example
+
+@noindent
+@c <en>When the password field is omitted or empty, then the
+@c <en>client's authentication attempt will succeed with any
+@c <en>password, including the empty string. However, the
+@c <en>colon after the @sc{cvs} username is always necessary,
+@c <en>even if the password is empty.
+Quando o campo senha não existe ou é vazio, então uma
+tentativa de autenticação do cliente vai funcionar
+qualquer que seja a senha, inclusive a senha vazia.
+Entretanto, o dois pontos antes do nome de usuário do
+@sc{cvs} é sempre necessário, mesmo se a senha for vazia.
+
+@c <en>@sc{cvs} can also fall back to use system authentication.
+@c <en>When authenticating a password, the server first checks
+@c <en>for the user in the @file{$CVSROOT/CVSROOT/passwd}
+@c <en>file. If it finds the user, it will use that entry for
+@c <en>authentication as described above. But if it does not
+@c <en>find the user, or if the @sc{cvs} @file{passwd} file
+@c <en>does not exist, then the server can try to authenticate
+@c <en>the username and password using the operating system's
+@c <en>user-lookup routines (this "fallback" behavior can be
+@c <en>disabled by setting @code{SystemAuth=no} in the
+@c <en>@sc{cvs} @file{config} file, @pxref{config}).
+O @sc{cvs} também pode recorrer à autenticação do
+sistema. Quando autenticando uma senha, o servidor
+primeiro procura pelo usuário no arquivo
+@file{$CVSROOT/CVSROOT/passwd}. Se ele encontra o
+usuário, ele vai usar aquela entrada para autenticar
+como descrito acima. Mas se o usuário não for
+encontrado, ou se o arquivo @file{passwd} do @sc{cvs}
+não existe, então o servidor pode tentar autenticar o
+nome de usuário e a senha usando as rotinas de
+???user-lookup??? do sistema operacional (Este
+comportamento "alternativo" pode ser desabilitado ajustando
+o @code{SystemAuth=no} no arquivo @file{config} do
+@sc{cvs}, @pxref{config}).
+
+@c <en>The default fallback behaviour is to look in
+@c <en>@file{/etc/passwd} for this system password unless your
+@c <en>system has PAM (Pluggable Authentication Modules)
+@c <en>and your @sc{cvs} server executable was configured to
+@c <en>use it at compile time (using @code{./configure --enable-pam} - see the
+@c <en>INSTALL file for more). In this case, PAM will be consulted instead.
+@c <en>This means that @sc{cvs} can be configured to use any password
+@c <en>authentication source PAM can be configured to use (possibilities
+@c <en>include a simple UNIX password, NIS, LDAP, and others) in its
+@c <en>global configuration file (usually @file{/etc/pam.conf}
+@c <en>or possibly @file{/etc/pam.d/cvs}). See your PAM documentation
+@c <en>for more details on PAM configuration.
+O comportamento alternativo é procurar no
+@file{/etc/passwd} por este usuário de sistema a menos
+que seu sistema tenha PAM (Pluggable Authentication
+Modules) e seu servidor do @sc{cvs} executável foi
+configurado para usar PAM em tempo de compilação
+(usando @code{./configure --enable-pam} - veja no
+arquivo INSTALL para saber mais). Neste caso, PAM é
+que vai autenticar. Isto significa que o @sc{cvs} pode
+ser configurado para usar qualquer fonte de
+autenticação por senha que PAM possa ser configurada
+para usar (as possibilidades incluem senha simples de
+UNIX, NIS, LDAP, e outras) no seu arquivo de
+configuração global (em geral @file{/etc/pam.conf}
+ou possivelmente @file{/etc/pam.d/cvs}). Veja em sua
+documentação do PAM para mais detalhes sobre a
+configuração do PAM.
+
+@c <en>Note that PAM is an experimental feature in @sc{cvs} and feedback is
+@c <en>encouraged. Please send a mail to one of the @sc{cvs} mailing lists
+@c <en>(@code{info-cvs@@nongnu.org} or @code{bug-cvs@@nongnu.org}) if you use the
+@c <en>@sc{cvs} PAM support.
+Observe que PAM é uma funcionalidade experimental no
+@sc{cvs} e feedback é encorajado. Por favor, mande
+e-mail para uma das listas do @sc{cvs}
+(@code{info-cvs@@nongnu.org} ou @code{bug-cvs@@nongnu.org})
+se você usa o suporte a PAM do @sc{cvs}. As listas são
+em inglês.
+
+@c <en>@strong{WARNING: Using PAM gives the system administrator much more
+@c <en>flexibility about how @sc{cvs} users are authenticated but
+@c <en>no more security than other methods. See below for more.}
+@strong{ATENÇÃO: Usar PAM dá ao administrador do
+sistema muito mais flexibilidade sobre como os usuários
+do @sc{cvs} são autenticados mas não dá mais segurança
+que outros métodos. Veja abaixo mais detalhes.}
+
+@c <en>CVS needs an "auth" and "account" module in the
+@c <en>PAM configuration file. A typical PAM configuration
+@c <en>would therefore have the following lines
+@c <en>in @file{/etc/pam.conf} to emulate the standard @sc{cvs}
+@c <en>system @file{/etc/passwd} authentication:
+CVS precisa de um módulo "auth" e "account" no arquivo
+de configuração PAM. Uma configuração PAM típica deve
+portanto ter as seguintes linhas no
+@file{/etc/pam.conf} para simular a autenticação
+@file{/etc/passwd} do sistema @sc{cvs} padrão:
+
+@example
+cvs auth required pam_unix.so
+cvs account required pam_unix.so
+@end example
+
+@c <en>The the equivalent @file{/etc/pam.d/cvs} would contain
+O @file{/etc/pam.d/cvs} equivalente deve conter
+
+@example
+auth required pam_unix.so
+account required pam_unix.so
+@end example
+
+@c <en>Some systems require a full path to the module so that
+@c <en>@file{pam_unix.so} (Linux) would become something like
+@c <en>@file{/usr/lib/security/$ISA/pam_unix.so.1} (Sun Solaris).
+@c <en>See the @file{contrib/pam} subdirectory of the @sc{cvs}
+@c <en>source distribution for further example configurations.
+Alguns sistemas necessitam de um caminho completo para
+o módulo de forma que @file{pam_unix.so} (Linux) vai se
+tornar algo do tipo
+@file{/usr/lib/security/$ISA/pam_unix.so.1} (Sun
+Solaris). Veja o subdiretório @file{contrib/pam} da
+distribuição em código fonte do @sc{cvs} para mais
+exemplos de configuração.
+
+@c <en>The PAM service name given above as "cvs" is just
+@c <en>the service name in the default configuration amd can be
+@c <en>set using
+@c <en>@code{./configure --with-hardcoded-pam-service-name=<pam-service-name>}
+@c <en>before compiling. @sc{cvs} can also be configured to use whatever
+@c <en>name it is invoked as as its PAM service name using
+@c <en>@code{./configure --without-hardcoded-pam-service-name}, but this
+@c <en>feature should not be used if you may not have control of the name
+@c <en>@sc{cvs} will be invoked as.
+O nome de serviço PAM dado abaixo como "cvs" é apenas o
+nome do serviço na configuração padrão e pode ser
+mudado usando
+@code{./configure --with-hardcoded-pam-service-name=<pam-service-name>}
+antes de compilar. ??? @sc{cvs} can also be configured to use whatever
+name it is invoked as as its PAM service name using
+@code{./configure
+--without-hardcoded-pam-service-name}???, mas esta
+característica não deve ser usada se você não tiver
+controle do nome com o qual o @sc{cvs} será chamado.
+
+@c <en>Be aware, also, that falling back to system
+@c <en>authentication might be a security risk: @sc{cvs}
+@c <en>operations would then be authenticated with that user's
+@c <en>regular login password, and the password flies across
+@c <en>the network in plaintext. See @ref{Password
+@c <en>authentication security} for more on this.
+@c <en>This may be more of a problem with PAM authentication
+@c <en>because it is likely that the source of the system
+@c <en>password is some central authentication service like
+@c <en>LDAP which is also used to authenticate other services.
+Esteja avisado, além disso, que recorrer a autenticação
+do sistema pode ser um risco de segurança: as operações
+do @sc{cvs} deveram ser autenticadas com a senha do
+usuário regular, e a senha vai passar pela rede em
+texto plano. Veja em @ref{Segurança com autenticação por senha}
+para saber mais. Isto pode ser um problema a mais com
+autenticação PAM por que é provável que a fonte do
+sistema de senhas é algum serviço de autenticação
+central como o LDAP, que é usado para autenticar outros
+serviços.
+
+@c <en>On the other hand, PAM makes it very easy to change your password
+@c <en>regularly. If they are given the option of a one-password system for
+@c <en>all of their activities, users are often more willing to change their
+@c <en>password on a regular basis.
+Por outro lado, PAM faz com que seja fácil mudar a
+senha regularmente. Se os usuários têm um sistema de
+senha única, são mais fáceis de convencer a trocar de
+senha regularmente.
+
+@c <en>In the non-PAM configuration where the password is stored in the
+@c <en>@file{CVSROOT/passwd} file, it is difficult to change passwords on a
+@c <en>regular basis since only administrative users (or in some cases
+@c <en>processes that act as an administrative user) are typicaly given
+@c <en>access to modify this file. Either there needs to be some
+@c <en>hand-crafted web page or set-uid program to update the file, or the
+@c <en>update needs to be done by submitting a request to an administrator to
+@c <en>perform the duty by hand. In the first case, having to remember to
+@c <en>update a separate password on a periodic basis can be difficult. In
+@c <en>the second case, the manual nature of the change will typically mean
+@c <en>that the password will not be changed unless it is absolutely
+@c <en>necessary.
+Numa configuração não-PAM, onde a senha é guardada no
+arquivo @file{CVSROOT/passwd}, é difícil mudar as
+senhas regularmente já que apenas usuários
+administradores (ou em alguns casos, processos que agem
+como usuários administradores) têm acesso de escrita ao
+arquivo. ???Either there needs to be some
+hand-crafted web page or set-uid program to update the file, or the
+update needs to be done by submitting a request to an administrator to
+perform the duty by hand???. No primeiro caso, ter que
+lembrar de uma senha a parte periodicamente pode ser
+difícil. No segundo caso, a natureza manual da mudança
+vai significar que a senha não vai ser mudada até que
+seja absolutamente necessário.
+
+@c <en>Note that PAM administrators should probably avoid configuring
+@c <en>one-time-passwords (OTP) for @sc{cvs} authentication/authorization. If
+@c <en>OTPs are desired, the administrator may wish to encourage the use of
+@c <en>one of the other Client/Server access methods. See the section on
+@c <en>@pxref{Remote repositories} for a list of other methods.
+Observe que os administradores do PAM vão evitar
+configurar one-time-passwords (OTP) para
+autenticação/autorização do @sc{cvs}. Se os OTPs são
+desejados, o administrador vai querer encorajar o uso
+de um dos outros métodos de acesso cliente/servidor.
+Veja a seção em @pxref{Repositórios remotos} para uma
+lista de outros métodos.
+
+@c <en>Right now, the only way to put a password in the
+@c <en>@sc{cvs} @file{passwd} file is to paste it there from
+@c <en>somewhere else. Someday, there may be a @code{cvs
+@c <en>passwd} command.
+Por agora, a única forma de botar uma senha no arquivo
+@file{passwd} do @sc{cvs} é colar de algum outro lugar.
+Algum dia vai haver um comando @code{cvs passwd}.
+
+@c <en>Unlike many of the files in @file{$CVSROOT/CVSROOT}, it
+@c <en>is normal to edit the @file{passwd} file in-place,
+@c <en>rather than via @sc{cvs}. This is because of the
+@c <en>possible security risks of having the @file{passwd}
+@c <en>file checked out to people's working copies. If you do
+@c <en>want to include the @file{passwd} file in checkouts of
+@c <en>@file{$CVSROOT/CVSROOT}, see @ref{checkoutlist}.
+Ao contrário da maioria dos arquivos no
+@file{$CVSROOT/CVSROOT}, é normal editar o arquivo
+@file{passwd} in loco, ao invés de pelo @sc{cvs}. Isto
+é devido a possíveis riscos de segurança ao se ter
+cópias do arquivo @file{passwd} baixadas para o
+diretório de trabalho das pessoas. Se você quer
+incluir o arquivo @file{passwd} nos checkouts de
+@file{$CVSROOT/CVSROOT}, veja em @ref{checkoutlist}.
+
+@c We might also suggest using the @code{htpasswd} command
+@c from freely available web servers as well, but that
+@c would open up a can of worms in that the users next
+@c questions are likely to be "where do I get it?" and
+@c "how do I use it?"
+@c Also note that htpasswd, at least the version I had,
+@c likes to clobber the third field.
+
+@c <en>@node Password authentication client
+@node Cliente de autenticação por senha
+@c <en>@subsubsection Using the client with password authentication
+@subsubsection Usando o cliente com autenticação por senha
+@c <en>@cindex Login (subcommand)
+@cindex Login (subcomando)
+@c <en>@cindex Password client, using
+@cindex Cliente por senha, usando
+@c <en>@cindex Authenticated client, using
+@cindex Cliente autenticado, usando
+@c <en>@cindex :pserver:, setting up
+@cindex :pserver:, ajustando
+@c <en>To run a @sc{cvs} command on a remote repository via
+@c <en>the password-authenticating server, one specifies the
+@c <en>@code{pserver} protocol, optional username, repository host, an
+@c <en>optional port number, and path to the repository. For example:
+Para rodar um comando @sc{cvs} num repositório remoto
+via servidor de autenticação por senha, deve-se
+espedificar o protocolo @code{pserver}, um nome de
+usuário opcional, a máquina do repositório, uma porta
+opcional, e o caminho para o repositório. Por exemplo:
+
+@example
+cvs -d :pserver:faun.example.org:/usr/local/cvsroot checkout someproj
+@end example
+
+@noindent
+@c <en>or
+or
+
+@example
+CVSROOT=:pserver:bach@@faun.example.org:2401/usr/local/cvsroot
+cvs checkout someproj
+@end example
+
+@c <en>However, unless you're connecting to a public-access
+@c <en>repository (i.e., one where that username doesn't
+@c <en>require a password), you'll need to supply a password or @dfn{log in} first.
+@c <en>Logging in verifies your password with the repository and stores it in a file.
+@c <en>It's done with the @code{login} command, which will
+@c <en>prompt you interactively for the password if you didn't supply one as part of
+@c <en>@var{$CVSROOT}:
+Entretanto, a menos que você esteja conectado a um
+repositório de acesso público (i.e., um daqueles que o
+usuário não precisa de senha), você vai precisar
+fornecer uma senha ou @dfn{se logar} antes. Ao se
+logar, a sua senha é comparada com a do repositório e
+guardada num arquivo. Isto é feito com o comando
+@code{login}, que vai pedir a sua senha interativamente
+se você não forneceu ela como parte do @var{$CVSROOT}:
+
+@example
+cvs -d :pserver:bach@@faun.example.org:/usr/local/cvsroot login
+CVS password:
+@end example
+
+@noindent
+@c <en>or
+or
+
+@example
+cvs -d :pserver:bach:p4ss30rd@@faun.example.org:/usr/local/cvsroot login
+@end example
+
+@c <en>After you enter the password, @sc{cvs} verifies it with
+@c <en>the server. If the verification succeeds, then that
+@c <en>combination of username, host, repository, and password
+@c <en>is permanently recorded, so future transactions with
+@c <en>that repository won't require you to run @code{cvs
+@c <en>login}. (If verification fails, @sc{cvs} will exit
+@c <en>complaining that the password was incorrect, and
+@c <en>nothing will be recorded.)
+Depois de fornecer a senha, o @sc{cvs} a verifica no
+servidor. Se a verificação procede, então esta
+combinação de usuário, máquina, repositório e senha é
+gravada permanentemente de forma que futuras transações
+com este repositório não vão requerer a execução de
+@code{cvs login}. (Se a verificação falhar, @sc{cvs}
+vai sair avisando que a senha está incorreta e nada vai
+ser gravado.)
+
+@c <en>The records are stored, by default, in the file
+@c <en>@file{$HOME/.cvspass}. That file's format is
+@c <en>human-readable, and to a degree human-editable, but
+@c <en>note that the passwords are not stored in
+@c <en>cleartext---they are trivially encoded to protect them
+@c <en>from "innocent" compromise (i.e., inadvertent viewing
+@c <en>by a system administrator or other non-malicious
+@c <en>person).
+A gravação é feita, por padrão, no arquivo
+@file{$HOME/.cvspass}. O arquivo tem formato
+legível, e num certo nível, editável, mas observe que
+as senhas não são guardadas em texto plano---elas são
+codificadas trivialmente para proteger contra
+???compromise??? "inocente" (i.e., um administrador
+desavisado dar uma olhada ou outra pessoa sem segundas
+intenções).
+
+@c <en>@cindex CVS_PASSFILE, environment variable
+@c <en>You can change the default location of this file by
+@c <en>setting the @code{CVS_PASSFILE} environment variable.
+@c <en>If you use this variable, make sure you set it
+@c <en>@emph{before} @code{cvs login} is run. If you were to
+@c <en>set it after running @code{cvs login}, then later
+@c <en>@sc{cvs} commands would be unable to look up the
+@c <en>password for transmission to the server.
+@cindex CVS_PASSFILE, variável de ambiente
+Você pode mudar o local padrão deste arquivo ajustando
+a variável de ambiente @code{CVS_PASSFILE}. Se você
+usar esta variável, certifique-se de fazer isto
+@emph{antes} de rodar @code{cvs login}. Se você fizer
+isto depois de rodar o @code{cvs login}, então mais
+tarde os comandos do @sc{cvs} vão ser incapazes de
+encontrar a senha para mandar para o servidor.
+
+@c <en>Once you have logged in, all @sc{cvs} commands using
+@c <en>that remote repository and username will authenticate
+@c <en>with the stored password. So, for example
+Uma vez que você esteja autenticado, todos os comandos
+do @sc{cvs} que usam o repositório remoto e senha vão
+se autenticar com a senha armazenada. Então, por exemplo
+
+@example
+cvs -d :pserver:bach@@faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+@c <en>@noindent
+@c <en>should just work (unless the password changes on the
+@c <en>server side, in which case you'll have to re-run
+@c <en>@code{cvs login}).
+@noindent
+vai funcionar (a menos que a senha mude no servidor,
+onde neste caso você vai ter que rodar de novo
+@code{cvs login}).
+
+@c <en>Note that if the @samp{:pserver:} were not present in
+@c <en>the repository specification, @sc{cvs} would assume it
+@c <en>should use @code{rsh} to connect with the server
+@c <en>instead (@pxref{Connecting via rsh}).
+Observe que se o @samp{:pserver:} não estiver presente
+na especificação do repositório, o @sc{cvs} vai assumir
+que deve usar o @code{rsh} para se conectar com o
+servidor, neste caso (@pxref{Se conectando via rsh}).
+
+@c <en>Of course, once you have a working copy checked out and
+@c <en>are running @sc{cvs} commands from within it, there is
+@c <en>no longer any need to specify the repository
+@c <en>explicitly, because @sc{cvs} can deduce the repository
+@c <en>from the working copy's @file{CVS} subdirectory.
+É claro que, uma vez que você tenha uma cópia de
+trabalho baixada e está rodando comandos @sc{cvs} de
+dentro dela, não existe mais a necessidade de
+explicitar o repositório, já que o @sc{cvs} pode
+deduzir o repositório a partir do subdiretório
+@file{CVS} da cópia de trabalho.
+
+@c FIXME: seems to me this needs somewhat more
+@c explanation.
+@c <en>@cindex Logout (subcommand)
+@c <en>The password for a given remote repository can be
+@c <en>removed from the @code{CVS_PASSFILE} by using the
+@c <en>@code{cvs logout} command.
+@cindex Logout (subcomando)
+A senha para um dado repositório remoto pode ser
+removida do @code{CVS_PASSFILE} usando o comando
+@code{cvs logout}.
+
+@c <en>@node Password authentication security
+@node Segurança com autenticação por senha
+@c <en>@subsubsection Security considerations with password authentication
+@subsubsection Considerações de segurança com autenticação por senha
+
+@c <en>@cindex Security, of pserver
+@cindex Segurança com pserver
+@c <en>The passwords are stored on the client side in a
+@c <en>trivial encoding of the cleartext, and transmitted in
+@c <en>the same encoding. The encoding is done only to
+@c <en>prevent inadvertent password compromises (i.e., a
+@c <en>system administrator accidentally looking at the file),
+@c <en>and will not prevent even a naive attacker from gaining
+@c <en>the password.
+As senhas são guardadas no cliente com uma codificação
+trivial de texto, e transmitidas na mesma codificação.
+Esta codificação é feita apenas para prevenir uma
+quebra de segredo inadvertida (i.e., um administrador
+de sistema acidentalmente olhar o arquivo), e não
+evita nem mesmo que um atacante ingênuo consiga a
+senha.
+
+@c FIXME: The bit about "access to the repository
+@c implies general access to the system is *not* specific
+@c to pserver; it applies to kerberos and SSH and
+@c everything else too. Should reorganize the
+@c documentation to make this clear.
+@c <en>The separate @sc{cvs} password file (@pxref{Password
+@c <en>authentication server}) allows people
+@c <en>to use a different password for repository access than
+@c <en>for login access. On the other hand, once a user has
+@c <en>non-read-only
+@c <en>access to the repository, she can execute programs on
+@c <en>the server system through a variety of means. Thus, repository
+@c <en>access implies fairly broad system access as well. It
+@c <en>might be possible to modify @sc{cvs} to prevent that,
+@c <en>but no one has done so as of this writing.
+O arquivo de senhas do @sc{cvs} em separado
+(@pxref{Servidor de autenticação por senha}) permite
+que as pessoas usem uma senha de acesso ao repositório
+deferente da senha de login. Por outro lado, uma vez
+que um usuário tenha acesso maior que somente-leitura,
+ele pode executar programas no sistema do servidor de
+várias formas. Então, o acesso ao repositório implica
+acesso ao sistema como um todo. É possível modificar o
+@sc{cvs} para evitar isto, mas até agora ninguem agiu
+neste sentido.
+@c OpenBSD uses chroot() and copies the repository to
+@c provide anonymous read-only access (for details see
+@c http://www.openbsd.org/anoncvs.shar). While this
+@c closes the most obvious holes, I'm not sure it
+@c closes enough holes to recommend it (plus it is
+@c *very* easy to accidentally screw up a setup of this
+@c type).
+
+@c <en>Note that because the @file{$CVSROOT/CVSROOT} directory
+@c <en>contains @file{passwd} and other files which are used
+@c <en>to check security, you must control the permissions on
+@c <en>this directory as tightly as the permissions on
+@c <en>@file{/etc}. The same applies to the @file{$CVSROOT}
+@c <en>directory itself and any directory
+@c <en>above it in the tree. Anyone who has write access to
+@c <en>such a directory will have the ability to become any
+@c <en>user on the system. Note that these permissions are
+@c <en>typically tighter than you would use if you are not
+@c <en>using pserver.
+observe que já que o diretório @file{$CVSROOT/CVSROOT}
+contém o arquivo @file{passwd} e outros arquivos que
+são usados para verificações de segurança, você deve
+controlar as permissões neste diretório com o mesmo
+cuidado que tem com as permissões em @file{/etc}. O
+mesmo se aplica ao próprio diretório @file{$CVSROOT} e
+qualquer diretório acima dele na árvore de diretórios.
+Qualquer pessoas que tenha permissão de escrita a algum
+destes diretórios vai ter a habilidade de se tornar
+qualquer usuário do sistema. Observe que estas
+permissões são em geral mais rígidas que as que você
+usaria se você não estivesse usando o pserver.
+@c TODO: Would be really nice to document/implement a
+@c scheme where the CVS server can run as some non-root
+@c user, e.g. "cvs". CVSROOT/passwd would contain a
+@c bunch of entries of the form foo:xxx:cvs (or the "cvs"
+@c would be implicit). This would greatly reduce
+@c security risks such as those hinted at in the
+@c previous paragraph. I think minor changes to CVS
+@c might be required but mostly this would just need
+@c someone who wants to play with it, document it, &c.
+
+@c <en>In summary, anyone who gets the password gets
+@c <en>repository access (which may imply some measure of general system
+@c <en>access as well). The password is available to anyone
+@c <en>who can sniff network packets or read a protected
+@c <en>(i.e., user read-only) file. If you want real
+@c <en>security, get Kerberos.
+Resumindo, qualquer um que consiga as senhas vai ter
+acesso ao repositório (que implica de certa forma
+acesso ao sistema em geral). A senha está disponível
+para qualquer um que possa ???sniff??? pacotes de rede
+ou ler um arquivo protegido (i.e., somente-leitura para
+usuários). Se você quer segurança real, use Kerberos.
+
+@c <en>@node GSSAPI authenticated
+@node Autenticação GSSAPI
+@c <en>@subsection Direct connection with GSSAPI
+@subsection Conexão direta com GSSAPI
+
+@c <en>@cindex GSSAPI
+@cindex GSSAPI
+@c <en>@cindex Security, GSSAPI
+@cindex Segurança, GSSAPI
+@c <en>@cindex :gserver:, setting up
+@cindex :gserver:, ajustando
+@c <en>@cindex Kerberos, using :gserver:
+@cindex Kerberos, usando :gserver:
+@c <en>GSSAPI is a generic interface to network security
+@c <en>systems such as Kerberos 5.
+@c <en>If you have a working GSSAPI library, you can have
+@c <en>@sc{cvs} connect via a direct @sc{tcp} connection,
+@c <en>authenticating with GSSAPI.
+GSSAPI é uma interface genérica para sistemas de
+segurança em rede como o Kerberos 5. Se você tem uma
+biblioteca GSSAPI funcionando, você pode ter seu
+@sc{cvs} conectado via uma conexão @sc{tcp} direta, se
+autenticando com GSSAPI.
+
+@c <en>To do this, @sc{cvs} needs to be compiled with GSSAPI
+@c <en>support; when configuring @sc{cvs} it tries to detect
+@c <en>whether GSSAPI libraries using kerberos version 5 are
+@c <en>present. You can also use the @file{--with-gssapi}
+@c <en>flag to configure.
+Para isto, o @sc{cvs} precisa ter sido compilado com
+suporte a GSSAPI; quando você estiver configurando o
+@sc{cvs} ele vai tentar detectar se as bibliotecas
+GSSAPI usando kerberos versão 5 estão presentes. Você
+também pode configurar isto com opção @file{--with-gssapi}.
+
+@c <en>The connection is authenticated using GSSAPI, but the
+@c <en>message stream is @emph{not} authenticated by default.
+@c <en>You must use the @code{-a} global option to request
+@c <en>stream authentication.
+A conexão é autenticada usando GSSAPI, mas o fluxo de
+mensagem @emph{não é} autenticado por padrão. Você deve
+usar a opção global @code{-a} para pedir autenticação
+de fluxo.
+
+@c <en>The data transmitted is @emph{not} encrypted by
+@c <en>default. Encryption support must be compiled into both
+@c <en>the client and the server; use the
+@c <en>@file{--enable-encrypt} configure option to turn it on.
+@c <en>You must then use the @code{-x} global option to
+@c <en>request encryption.
+Os dados transmitidos @emph{não} são criptografados por
+padrão. Suporte a criptografia deve ser compilado
+tanto no cliente quanto no servidor; use a opção de
+configuração @file{--enable-encrypt} para ativar isto.
+Com isto você deve usar a opção global @code{-x} para
+pedir criptografia.
+
+@c <en>GSSAPI connections are handled on the server side by
+@c <en>the same server which handles the password
+@c <en>authentication server; see @ref{Password authentication
+@c <en>server}. If you are using a GSSAPI mechanism such as
+@c <en>Kerberos which provides for strong authentication, you
+@c <en>will probably want to disable the ability to
+@c <en>authenticate via cleartext passwords. To do so, create
+@c <en>an empty @file{CVSROOT/passwd} password file, and set
+@c <en>@code{SystemAuth=no} in the config file
+@c <en>(@pxref{config}).
+Conexões GSSAPI são tratadas no lado servidor pelo
+mesmo servidor que cuida de autenticação por senha;
+veja em @ref{Servidor de autenticação por senha}. Se
+você está usando um mecanismo GSSAPI como o Kerberos,
+que fornece autenticação forte, você vai provavelmente
+querer impedir autenticação via senhas em texto plano.
+Para tal, crie um arquivo de senha
+@file{CVSROOT/passwd} vazio e faça @code{SystemAuth=no}
+no arquivo config (@pxref{config}).
+
+@c <en>The GSSAPI server uses a principal name of
+@c <en>cvs/@var{hostname}, where @var{hostname} is the
+@c <en>canonical name of the server host. You will have to
+@c <en>set this up as required by your GSSAPI mechanism.
+O servidor GSSAPI usa um nome principal de
+cvs/@var{hostname}, onde @var{hostname} é o nome
+canônico da máquina servidora. Você vai ter que
+ajustar isto como é exigido pelo seu mecanismo GSSAPI.
+
+@c <en>To connect using GSSAPI, use @samp{:gserver:}. For
+@c <en>example,
+Para se conectar usando GSSAPI, use @samp{:gserver:}. Por
+exemplo,
+
+@example
+cvs -d :gserver:faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+@c <en>@node Kerberos authenticated
+@node Autenticação kerberos
+@c <en>@subsection Direct connection with kerberos
+@subsection Conexão direta com kerberos
+
+@c <en>@cindex Kerberos, using :kserver:
+@cindex Kerberos, usando :kserver:
+@c <en>@cindex Security, kerberos
+@cindex Segurança, kerberos
+@c <en>@cindex :kserver:, setting up
+@cindex :kserver:, ajustando
+@c <en>The easiest way to use kerberos is to use the kerberos
+@c <en>@code{rsh}, as described in @ref{Connecting via rsh}.
+@c <en>The main disadvantage of using rsh is that all the data
+@c <en>needs to pass through additional programs, so it may be
+@c <en>slower. So if you have kerberos installed you can
+@c <en>connect via a direct @sc{tcp} connection,
+@c <en>authenticating with kerberos.
+A forma mais fácil de usar kerberos é usar o @code{rsh}
+kerberos, como descrito em @ref{Se conectando via
+rsh}. A principal desvantagem de usar rsh é que todos
+os dados precisam passar por outros programas, o que é
+mais lento. Portanto, se você tem kerberos instalado,
+você pode se conectar via conexão @sc{tcp} direta,
+autenticando com kerberos.
+
+@c <en>This section concerns the kerberos network security
+@c <en>system, version 4. Kerberos version 5 is supported via
+@c <en>the GSSAPI generic network security interface, as
+@c <en>described in the previous section.
+Esta seção diz respeito ao sistema de segurança de rede
+kerberos (kerberos network security system), versão 4.
+Kerberos versão 5 é suportado pela interface de
+segurança de rede genérica GSSAPI, como descrito na
+seção anterior.
+
+@c <en>To do this, @sc{cvs} needs to be compiled with kerberos
+@c <en>support; when configuring @sc{cvs} it tries to detect
+@c <en>whether kerberos is present or you can use the
+@c <en>@file{--with-krb4} flag to configure.
+Para isto, o @sc{cvs} precisa ter sido compilado com
+suporte a kerberos; quando você estiver configurando o
+@sc{cvs} ele vai tentar detectar se as bibliotecas
+kerberos estão presentes ou você pode configurar isto
+com a opção @file{--with-krb4}.
+
+@c <en>The data transmitted is @emph{not} encrypted by
+@c <en>default. Encryption support must be compiled into both
+@c <en>the client and server; use the
+@c <en>@file{--enable-encryption} configure option to turn it
+@c <en>on. You must then use the @code{-x} global option to
+@c <en>request encryption.
+Os dados transmitidos @emph{não} são criptografados por
+padrão. Suporte a criptografia deve ser compilado
+tanto no cliente quanto no servidor; use a opção de
+configuração @file{--enable-encryption} para ativar
+isto. Você deve então usar a opção global @code{-x}
+para pedir criptografia.
+
+@c <en>@cindex CVS_CLIENT_PORT
+@cindex CVS_CLIENT_PORT
+@c <en>You need to edit @file{inetd.conf} on the server
+@c <en>machine to run @code{cvs kserver}. The client uses
+@c <en>port 1999 by default; if you want to use another port
+@c <en>specify it in the @code{CVSROOT} (@pxref{Remote repositories})
+@c <en>or the @code{CVS_CLIENT_PORT} environment variable
+@c <en>(@pxref{Environment variables}) on the client.
+Você precisa editar o @file{inetd.conf} no servidor
+para rodar @code{cvs kserver}. O cliente usa a porta
+1999 por padrão; se você quer usar outra porta
+especifique ela no @code{CVSROOT} (@pxref{Repositórios remotos})
+ou na variável de ambiente @code{CVS_CLIENT_PORT}
+(@pxref{Variáveis de ambiente}) no cliente.
+
+@c <en>@cindex kinit
+@cindex kinit
+@c <en>When you want to use @sc{cvs}, get a ticket in the
+@c <en>usual way (generally @code{kinit}); it must be a ticket
+@c <en>which allows you to log into the server machine. Then
+@c <en>you are ready to go:
+Quando você quiser usar o @sc{cvs}, pegue um tíquete da
+forma usual (geralmente @code{kinit}); ele pode ser um
+tíquete que te permite se autenticar na máquina
+servidora. Então você estará pronto para seguir:
+
+@example
+cvs -d :kserver:faun.example.org:/usr/local/cvsroot checkout foo
+@end example
+
+@c <en>Previous versions of @sc{cvs} would fall back to a
+@c <en>connection via rsh; this version will not do so.
+Versões anteriores do @sc{cvs} podem recair numa
+conexão via rsh; esta versão não vai fazer isso.
+
+@c <en>@node Connecting via fork
+@node Conectando via fork
+@c <en>@subsection Connecting with fork
+@subsection Conectando via fork
+
+@c <en>@cindex fork, access method
+@cindex fork, método de acesso
+@c <en>@cindex :fork:, setting up
+@cindex :fork:, ajustando
+@c <en>This access method allows you to connect to a
+@c <en>repository on your local disk via the remote protocol.
+@c <en>In other words it does pretty much the same thing as
+@c <en>@code{:local:}, but various quirks, bugs and the like are
+@c <en>those of the remote @sc{cvs} rather than the local
+@c <en>@sc{cvs}.
+Este método de acesso permite a você conectar a um
+repositório no seu disco local via um protocolo
+remoto. Em outras palavras, ele faz praticamente a
+mesma coisa que @code{:local:}, mas várias peduliaridades, paus
+e coisas do gênero são os mesmos do @sc{cvs} remoto ao
+invés do @sc{cvs} local.
+
+@c <en>For day-to-day operations you might prefer either
+@c <en>@code{:local:} or @code{:fork:}, depending on your
+@c <en>preferences. Of course @code{:fork:} comes in
+@c <en>particularly handy in testing or
+@c <en>debugging @code{cvs} and the remote protocol.
+@c <en>Specifically, we avoid all of the network-related
+@c <en>setup/configuration, timeouts, and authentication
+@c <en>inherent in the other remote access methods but still
+@c <en>create a connection which uses the remote protocol.
+Para trabalhar no dia-a-dia você vai preferir ou o
+@code{:local:} ou o @code{:fork:}, dependendo de suas
+preferências. É claro que @code{:fork:} é bastante
+útil em testes ou depuração do @code{cvs} e o protocolo
+remoto. Especificamente, nós evitamos todas as
+configurações/ajustes relacionados a redes, sessões
+expirando e autenticação inerentes de métodos de acesso
+remoto mas ainda assim criamos uma conexão que usa o
+protocolo remoto.
+
+@c <en>To connect using the @code{fork} method, use
+@c <en>@samp{:fork:} and the pathname to your local
+@c <en>repository. For example:
+Para se conectar usando o método @code{fork}, use
+@samp{:fork:} e o caminho para seu repositório local.
+Por exemplo:
+
+@example
+cvs -d :fork:/usr/local/cvsroot checkout foo
+@end example
+
+@c <en>@cindex CVS_SERVER, and :fork:
+@cindex CVS_SERVER, and :fork:
+@c <en>As with @code{:ext:}, the server is called @samp{cvs}
+@c <en>by default, or the value of the @code{CVS_SERVER}
+@c <en>environment variable.
+Assim como com @code{:ext:}, o servidor é chamado
+@samp{cvs} por padrão, ou o valor da variável de
+ambiente @code{CVS_SERVER}.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Read-only access
+@node Acesso somente-leitura
+@c <en>@section Read-only repository access
+@section Acesso somente-leitura ao repositório
+@c <en>@cindex Read-only repository access
+@cindex Acesso somente-leitura ao repositório
+@c <en>@cindex readers (admin file)
+@cindex readers (arquivo administrativo)
+@c <en>@cindex writers (admin file)
+@cindex writers (arquivo administrativo)
+
+@c <en> It is possible to grant read-only repository
+@c <en>access to people using the password-authenticated
+@c <en>server (@pxref{Password authenticated}). (The
+@c <en>other access methods do not have explicit support for
+@c <en>read-only users because those methods all assume login
+@c <en>access to the repository machine anyway, and therefore
+@c <en>the user can do whatever local file permissions allow
+@c <en>her to do.)
+ É possível permitir acesso somente-leitura ao
+repositório a pessoas usando o servidor de autenticação
+por senha (@pxref{Autenticação por senha}). (Os outros
+métodos de acesso não tem suporte explícito para
+somente-leitura de usuários, já que todos estes métodos
+assumem acesso por login à máquina do repositório de
+qualquer forma, e portanto o usuário pode fazer o que
+as permissões de arquivos locais permitirem.)
+
+@c <en> A user who has read-only access can do only
+@c <en>those @sc{cvs} operations which do not modify the
+@c <en>repository, except for certain ``administrative'' files
+@c <en>(such as lock files and the history file). It may be
+@c <en>desirable to use this feature in conjunction with
+@c <en>user-aliasing (@pxref{Password authentication server}).
+Um usuário que tem acesso somente-leitura pode realizar
+apenas as operações do @sc{cvs} que não modificam o
+repositório, exceto alguns arquivos ``administrativos''
+(tais como arquivos de trava e o arquivo history).
+Pode ser desejável usar esta habilidade em conjunto com
+???``user-aliasing''??? (@pxref{Servidor de autenticação por
+senha}).
+
+@c <en>Unlike with previous versions of @sc{cvs}, read-only
+@c <en>users should be able merely to read the repository, and
+@c <en>not to execute programs on the server or otherwise gain
+@c <en>unexpected levels of access. Or to be more accurate,
+@c <en>the @emph{known} holes have been plugged. Because this
+@c <en>feature is new and has not received a comprehensive
+@c <en>security audit, you should use whatever level of
+@c <en>caution seems warranted given your attitude concerning
+@c <en>security.
+Ao contrário de versões anteriores do @sc{cvs},
+usuários somente-leitura são capazes de simplesmente
+ler o repositório, e não de executar programas no
+servidor ou ainda conseguir níveis de acessos extras.
+Ou, para ser mais preciso, os papéis @emph{conhecidos}
+foram ???plugged???. Pelo fato de esta característica
+ser nova e ainda não ter recebido uma auditoria de
+segurança abrangente, você deve usar quaisquer níveis
+de precaução que pareçam seguros de acordo com a sua
+forma de agir com respeito a segurança.
+
+@c <en> There are two ways to specify read-only access
+@c <en>for a user: by inclusion, and by exclusion.
+ Existem duas formas de estabelecer acesso
+somente-leitura para um usuário: por inclusão ou por exclusão.
+
+@c <en> "Inclusion" means listing that user
+@c <en>specifically in the @file{$CVSROOT/CVSROOT/readers}
+@c <en>file, which is simply a newline-separated list of
+@c <en>users. Here is a sample @file{readers} file:
+ "Inclusão" significa botar aquele usuário
+específico no arquivo @file{$CVSROOT/CVSROOT/readers},
+que é simplesmente uma lista de usuários separados por
+quebra de linha. Aqui está um exemplo do @file{readers}:
+
+@example
+melissa
+splotnik
+jrandom
+@end example
+
+@noindent
+@c <en> (Don't forget the newline after the last user.)
+ (Não esqueça a quebra de linha depois do último
+usuário.)
+
+@c <en> "Exclusion" means explicitly listing everyone
+@c <en>who has @emph{write} access---if the file
+ "Exclusão" significa listar explicitamente
+todos que têm acesso de @emph{escrita}---se o arquivo
+
+@example
+$CVSROOT/CVSROOT/writers
+@end example
+
+@noindent
+@c <en>exists, then only
+@c <en>those users listed in it have write access, and
+@c <en>everyone else has read-only access (of course, even the
+@c <en>read-only users still need to be listed in the
+@c <en>@sc{cvs} @file{passwd} file). The
+@c <en>@file{writers} file has the same format as the
+@c <en>@file{readers} file.
+existe, então apenas os usuários que constam nele teram
+acesso de escrita, e qualquer outra pessoa acesso
+somente-leitura (obviamente, mesmo os usuários
+somente-leitura devem ainda ser listados no arquivo
+@file{passwd} do @sc{cvs}). O arquivo @file{writers}
+tem o mesmo formato do arquivo @file{readers}.
+
+@c <en> Note: if your @sc{cvs} @file{passwd}
+@c <en>file maps cvs users onto system users (@pxref{Password
+@c <en>authentication server}), make sure you deny or grant
+@c <en>read-only access using the @emph{cvs} usernames, not
+@c <en>the system usernames. That is, the @file{readers} and
+@c <en>@file{writers} files contain cvs usernames, which may
+@c <en>or may not be the same as system usernames.
+ Observação: se seu arquivo @file{passwd} do
+@sc{cvs} associa usuários do cvs com usuários do
+sistema (@pxref{Servidor de autenticação por
+senha}), certifique-se de que você esteja
+negando ou fornecendo acesso somente-leitura usando os
+usuários @emph{do cvs}, e não os do sistema. Ou seja,
+os arquivos @file{readers} e @file{writers} contêm
+nomes de usuários do cvs, que não necessáriamente têm o
+mesmo nome que usuários do sistema.
+
+@c <en> Here is a complete description of the server's
+@c <en>behavior in deciding whether to grant read-only or
+@c <en>read-write access:
+ Here is a complete description of the server's
+behavior in deciding whether to grant read-only or
+read-write access:
+
+@c <en> If @file{readers} exists, and this user is
+@c <en>listed in it, then she gets read-only access. Or if
+@c <en>@file{writers} exists, and this user is NOT listed in
+@c <en>it, then she also gets read-only access (this is true
+@c <en>even if @file{readers} exists but she is not listed
+@c <en>there). Otherwise, she gets full read-write access.
+ If @file{readers} exists, and this user is
+listed in it, then she gets read-only access. Or if
+@file{writers} exists, and this user is NOT listed in
+it, then she also gets read-only access (this is true
+even if @file{readers} exists but she is not listed
+there). Otherwise, she gets full read-write access.
+
+@c <en> Of course there is a conflict if the user is
+@c <en>listed in both files. This is resolved in the more
+@c <en>conservative way, it being better to protect the
+@c <en>repository too much than too little: such a user gets
+@c <en>read-only access.
+ Of course there is a conflict if the user is
+listed in both files. This is resolved in the more
+conservative way, it being better to protect the
+repository too much than too little: such a user gets
+read-only access.
+
+@c <en>@node Server temporary directory
+@node Diretório temporário do servidor
+@c <en>@section Temporary directories for the server
+@section Temporary directories for the server
+@c <en>@cindex Temporary directories, and server
+@cindex Temporary directories, and server
+@c <en>@cindex Server, temporary directories
+@cindex Server, temporary directories
+
+@c <en>While running, the @sc{cvs} server creates temporary
+@c <en>directories. They are named
+While running, the @sc{cvs} server creates temporary
+directories. They are named
+
+@example
+cvs-serv@var{pid}
+@end example
+
+@noindent
+@c <en>where @var{pid} is the process identification number of
+@c <en>the server.
+@c <en>They are located in the directory specified by
+@c <en>the @samp{-T} global option (@pxref{Global options}),
+@c <en>the @code{TMPDIR} environment variable (@pxref{Environment variables}),
+@c <en>or, failing that, @file{/tmp}.
+where @var{pid} is the process identification number of
+the server.
+They are located in the directory specified by
+the @samp{-T} global option (@pxref{Opções globais}),
+the @code{TMPDIR} environment variable (@pxref{Variáveis de ambiente}),
+or, failing that, @file{/tmp}.
+
+@c <en>In most cases the server will remove the temporary
+@c <en>directory when it is done, whether it finishes normally
+@c <en>or abnormally. However, there are a few cases in which
+@c <en>the server does not or cannot remove the temporary
+@c <en>directory, for example:
+In most cases the server will remove the temporary
+directory when it is done, whether it finishes normally
+or abnormally. However, there are a few cases in which
+the server does not or cannot remove the temporary
+directory, for example:
+
+@itemize @bullet
+@item
+@c <en>If the server aborts due to an internal server error,
+@c <en>it may preserve the directory to aid in debugging
+If the server aborts due to an internal server error,
+it may preserve the directory to aid in debugging
+
+@item
+@c <en>If the server is killed in a way that it has no way of
+@c <en>cleaning up (most notably, @samp{kill -KILL} on unix).
+If the server is killed in a way that it has no way of
+cleaning up (most notably, @samp{kill -KILL} on unix).
+
+@item
+@c <en>If the system shuts down without an orderly shutdown,
+@c <en>which tells the server to clean up.
+If the system shuts down without an orderly shutdown,
+which tells the server to clean up.
+@end itemize
+
+@c <en>In cases such as this, you will need to manually remove
+@c <en>the @file{cvs-serv@var{pid}} directories. As long as
+@c <en>there is no server running with process identification
+@c <en>number @var{pid}, it is safe to do so.
+In cases such as this, you will need to manually remove
+the @file{cvs-serv@var{pid}} directories. As long as
+there is no server running with process identification
+number @var{pid}, it is safe to do so.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Starting a new project
+@node Começando um novo projeto
+@c <en>@chapter Starting a project with CVS
+@chapter Começando um projeto com o CVS
+@c <en>@cindex Starting a project with CVS
+@cindex Começando um projeto com CVS
+@c <en>@cindex Creating a project
+@cindex Criando um projeto
+
+@comment --moduledb--
+@c <en>Because renaming files and moving them between
+@c <en>directories is somewhat inconvenient, the first thing
+@c <en>you do when you start a new project should be to think
+@c <en>through your file organization. It is not impossible
+@c <en>to rename or move files, but it does increase the
+@c <en>potential for confusion and @sc{cvs} does have some
+@c <en>quirks particularly in the area of renaming
+@c <en>directories. @xref{Moving files}.
+Já que renomear e mover arquivos entre diretórios é um
+tanto quanto inconveniente, a primeira coisa a fazer
+quando você começa um novo projeto deve ser ponderar a
+respeito da organização dos arquivos. Não é impossível
+renomear ou mover arquivos, mas isto aumenta as chances
+de erro e o @sc{cvs} tem algumas idiossincrasias em
+especial quanto a renomear diretórios. @xref{Movendo arquivos}.
+
+@c <en>What to do next depends on the situation at hand.
+O que fazer depende da situação em que você está.
+
+@menu
+@c <en>* Setting up the files:: Getting the files into the repository
+* Ajustando os arquivos:: Botando os arquivos no repositório
+@c <en>* Defining the module:: How to make a module of the files
+* Definindo o módulo:: How to make a module of the files
+@end menu
+@c -- File permissions!
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Setting up the files
+@node Ajustando os arquivos
+@c <en>@section Setting up the files
+@section Ajustando os arquivos
+
+@c <en>The first step is to create the files inside the repository. This can
+@c <en>be done in a couple of different ways.
+O primeiro passo é criar os arquivos dentro do
+repositório. Isto pode ser feito de algumas maneiras diferentes.
+
+@c -- The contributed scripts
+@menu
+@c <en>* From files:: This method is useful with old projects
+@c <en> where files already exists.
+* De arquivos:: Este método é útil para projetos
+ antigos cujos arquivos já existem.
+@c <en>* From other version control systems:: Old projects where you want to
+@c <en> preserve history from another system.
+* De outros sistemas de controle de versão:: Projetos antigos onde você quer
+ preservar o histórico de outro sistema.
+@c <en>* From scratch:: Creating a directory tree from scratch.
+* Do zero:: Criando uma árvore de diretórios
+ do zero.
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c <en>@node From files
+@node De arquivos
+@c <en>@subsection Creating a directory tree from a number of files
+@subsection Criando uma árvore de diretórios de uma quantidade de arquivos
+@c <en>@cindex Importing files
+@cindex Importando arquivos
+
+@c <en>When you begin using @sc{cvs}, you will probably already have several
+@c <en>projects that can be
+@c <en>put under @sc{cvs} control. In these cases the easiest way is to use the
+@c <en>@code{import} command. An example is probably the easiest way to
+@c <en>explain how to use it. If the files you want to install in
+@c <en>@sc{cvs} reside in @file{@var{wdir}}, and you want them to appear in the
+@c <en>repository as @file{$CVSROOT/yoyodyne/@var{rdir}}, you can do this:
+Quando você começa a usar o @sc{cvs}, provavelmente vai
+ter vários projetos que podem ser postos sob controle
+do @sc{cvs}. Nestes casos a forma mais fácil é usar o
+comando @code{import}. Um exemplo é provavelmente a
+forma mais fácil de explicar como se usa o
+@code{import}. Se os arquivos que você quer instalar
+no @sc{cvs} estão em @file{@var{wdir}}, e você quer que
+eles estejam no repositório
+@file{$CVSROOT/yoyodyne/@var{rdir}}, você pode fazer isto:
+
+@example
+$ cd @var{wdir}
+$ cvs import -m "Imported sources" yoyodyne/@var{rdir} yoyo start
+@end example
+
+@c <en>Unless you supply a log message with the @samp{-m}
+@c <en>flag, @sc{cvs} starts an editor and prompts for a
+@c <en>message. The string @samp{yoyo} is a @dfn{vendor tag},
+@c <en>and @samp{start} is a @dfn{release tag}. They may fill
+@c <en>no purpose in this context, but since @sc{cvs} requires
+@c <en>them they must be present. @xref{Tracking sources}, for
+@c <en>more information about them.
+A menos que você forneca uma mensagem de log (registro)
+com a opção @samp{-m}, o @sc{cvs} vai iniciar um editor
+e esperar uma mensagem. A string @samp{yoyo} é uma
+@dfn{etiqueta de fornecedor} (vendor tag), e
+@samp{start} é uma @dfn{etiqueta de release} (release
+tag). Eles podem não fazer sentido neste contexto, mas
+já que o @sc{cvs} exige, elas devem estar presentes.
+@xref{Acompanhando fontes}, para mais informações sobre
+isto.
+
+@c <en>You can now verify that it worked, and remove your
+@c <en>original source directory.
+Você agora pode verificar se está funcionando, e então
+apagar seu diretório do código fonte original.
+@c FIXME: Need to say more about "verify that it
+@c worked". What should the user look for in the output
+@c from "diff -r"?
+
+@example
+$ cd ..
+@c <en>$ cvs checkout yoyodyne/@var{rdir} # @r{Explanation below}
+$ cvs checkout yoyodyne/@var{rdir} # @r{Explanation below}
+$ diff -r @var{wdir} yoyodyne/@var{rdir}
+$ rm -r @var{wdir}
+@end example
+
+@noindent
+@c <en>Erasing the original sources is a good idea, to make sure that you do
+@c <en>not accidentally edit them in @var{wdir}, bypassing @sc{cvs}.
+@c <en>Of course, it would be wise to make sure that you have
+@c <en>a backup of the sources before you remove them.
+Erasing the original sources is a good idea, to make sure that you do
+not accidentally edit them in @var{wdir}, bypassing @sc{cvs}.
+Of course, it would be wise to make sure that you have
+a backup of the sources before you remove them.
+
+@c <en>The @code{checkout} command can either take a module
+@c <en>name as argument (as it has done in all previous
+@c <en>examples) or a path name relative to @code{$CVSROOT},
+@c <en>as it did in the example above.
+The @code{checkout} command can either take a module
+name as argument (as it has done in all previous
+examples) or a path name relative to @code{$CVSROOT},
+as it did in the example above.
+
+@c <en>It is a good idea to check that the permissions
+@c <en>@sc{cvs} sets on the directories inside @code{$CVSROOT}
+@c <en>are reasonable, and that they belong to the proper
+@c <en>groups. @xref{File permissions}.
+It is a good idea to check that the permissions
+@sc{cvs} sets on the directories inside @code{$CVSROOT}
+are reasonable, and that they belong to the proper
+groups. @xref{Permissões de arquivos}.
+
+@c <en>If some of the files you want to import are binary, you
+@c <en>may want to use the wrappers features to specify which
+@c <en>files are binary and which are not. @xref{Wrappers}.
+If some of the files you want to import are binary, you
+may want to use the wrappers features to specify which
+files are binary and which are not. @xref{Wrappers}.
+
+@c The node name is too long, but I am having trouble
+@c thinking of something more concise.
+@c <en>@node From other version control systems
+@node De outros sistemas de controle de versão
+@c <en>@subsection Creating Files From Other Version Control Systems
+@subsection Criando os Arquivos de Outros Sistemas de Controle de Versões
+@c <en>@cindex Importing files, from other version control systems
+@cindex Outros Sistemas de Controle de Versões, Importando Arquivos de
+
+@c <en>If you have a project which you are maintaining with
+@c <en>another version control system, such as @sc{rcs}, you
+@c <en>may wish to put the files from that project into
+@c <en>@sc{cvs}, and preserve the revision history of the
+@c <en>files.
+If you have a project which you are maintaining with
+another version control system, such as @sc{rcs}, you
+may wish to put the files from that project into
+@sc{cvs}, and preserve the revision history of the
+files.
+
+@table @asis
+@cindex RCS, importing files from
+@cindex RCS, importing files from
+@item From RCS
+@item From RCS
+@c <en>If you have been using @sc{rcs}, find the @sc{rcs}
+@c <en>files---usually a file named @file{foo.c} will have its
+@c <en>@sc{rcs} file in @file{RCS/foo.c,v} (but it could be
+@c <en>other places; consult the @sc{rcs} documentation for
+@c <en>details). Then create the appropriate directories in
+@c <en>@sc{cvs} if they do not already exist. Then copy the
+@c <en>files into the appropriate directories in the @sc{cvs}
+@c <en>repository (the name in the repository must be the name
+@c <en>of the source file with @samp{,v} added; the files go
+@c <en>directly in the appropriate directory of the repository,
+@c <en>not in an @file{RCS} subdirectory). This is one of the
+@c <en>few times when it is a good idea to access the @sc{cvs}
+@c <en>repository directly, rather than using @sc{cvs}
+@c <en>commands. Then you are ready to check out a new
+@c <en>working directory.
+If you have been using @sc{rcs}, find the @sc{rcs}
+files---usually a file named @file{foo.c} will have its
+@sc{rcs} file in @file{RCS/foo.c,v} (but it could be
+other places; consult the @sc{rcs} documentation for
+details). Then create the appropriate directories in
+@sc{cvs} if they do not already exist. Then copy the
+files into the appropriate directories in the @sc{cvs}
+repository (the name in the repository must be the name
+of the source file with @samp{,v} added; the files go
+directly in the appropriate directory of the repository,
+not in an @file{RCS} subdirectory). This is one of the
+few times when it is a good idea to access the @sc{cvs}
+repository directly, rather than using @sc{cvs}
+commands. Then you are ready to check out a new
+working directory.
+@c Someday there probably should be a "cvs import -t
+@c rcs" or some such. It could even create magic
+@c branches. It could also do something about the case
+@c where the RCS file had a (non-magic) "0" branch.
+
+@c <en>The @sc{rcs} file should not be locked when you move it
+@c <en>into @sc{cvs}; if it is, @sc{cvs} will have trouble
+@c <en>letting you operate on it.
+The @sc{rcs} file should not be locked when you move it
+into @sc{cvs}; if it is, @sc{cvs} will have trouble
+letting you operate on it.
+@c What is the easiest way to unlock your files if you
+@c have them locked? Especially if you have a lot of them?
+@c This is a CVS bug/misfeature; importing RCS files
+@c should ignore whether they are locked and leave them in
+@c an unlocked state. Yet another reason for a separate
+@c "import RCS file" command.
+
+@c How many is "many"? Or do they just import RCS files?
+@c <en>@item From another version control system
+@item From another version control system
+@c <en>Many version control systems have the ability to export
+@c <en>@sc{rcs} files in the standard format. If yours does,
+@c <en>export the @sc{rcs} files and then follow the above
+@c <en>instructions.
+Many version control systems have the ability to export
+@sc{rcs} files in the standard format. If yours does,
+export the @sc{rcs} files and then follow the above
+instructions.
+
+@c <en>Failing that, probably your best bet is to write a
+@c <en>script that will check out the files one revision at a
+@c <en>time using the command line interface to the other
+@c <en>system, and then check the revisions into @sc{cvs}.
+@c <en>The @file{sccs2rcs} script mentioned below may be a
+@c <en>useful example to follow.
+Failing that, probably your best bet is to write a
+script that will check out the files one revision at a
+time using the command line interface to the other
+system, and then check the revisions into @sc{cvs}.
+The @file{sccs2rcs} script mentioned below may be a
+useful example to follow.
+
+@c <en>@cindex SCCS, importing files from
+@cindex SCCS, importing files from
+@c <en>@item From SCCS
+@item From SCCS
+@c <en>There is a script in the @file{contrib} directory of
+@c <en>the @sc{cvs} source distribution called @file{sccs2rcs}
+@c <en>which converts @sc{sccs} files to @sc{rcs} files.
+@c <en>Note: you must run it on a machine which has both
+@c <en>@sc{sccs} and @sc{rcs} installed, and like everything
+@c <en>else in contrib it is unsupported (your mileage may
+@c <en>vary).
+There is a script in the @file{contrib} directory of
+the @sc{cvs} source distribution called @file{sccs2rcs}
+which converts @sc{sccs} files to @sc{rcs} files.
+Note: you must run it on a machine which has both
+@sc{sccs} and @sc{rcs} installed, and like everything
+else in contrib it is unsupported (your mileage may
+vary).
+
+@c <en>@cindex PVCS, importing files from
+@cindex PVCS, importing files from
+@c <en>@item From PVCS
+@item From PVCS
+@c <en>There is a script in the @file{contrib} directory of
+@c <en>the @sc{cvs} source distribution called @file{pvcs_to_rcs}
+@c <en>which converts @sc{pvcs} archives to @sc{rcs} files.
+@c <en>You must run it on a machine which has both
+@c <en>@sc{pvcs} and @sc{rcs} installed, and like everything
+@c <en>else in contrib it is unsupported (your mileage may
+@c <en>vary). See the comments in the script for details.
+There is a script in the @file{contrib} directory of
+the @sc{cvs} source distribution called @file{pvcs_to_rcs}
+which converts @sc{pvcs} archives to @sc{rcs} files.
+You must run it on a machine which has both
+@sc{pvcs} and @sc{rcs} installed, and like everything
+else in contrib it is unsupported (your mileage may
+vary). See the comments in the script for details.
+@end table
+@c CMZ and/or PATCHY were systems that were used in the
+@c high energy physics community (especially for
+@c CERNLIB). CERN has replaced them with CVS, but the
+@c CAR format seems to live on as a way to submit
+@c changes. There is a program car2cvs which converts
+@c but I'm not sure where one gets a copy.
+@c Not sure it is worth mentioning here, since it would
+@c appear to affect only one particular community.
+@c Best page for more information is:
+@c http://wwwcn1.cern.ch/asd/cvs/index.html
+@c See also:
+@c http://ecponion.cern.ch/ecpsa/cernlib.html
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c <en>@node From scratch
+@node Do zero
+@c <en>@subsection Creating a directory tree from scratch
+@subsection Criando uma árvore de diretórios do zero
+
+@c Also/instead should be documenting
+@c $ cvs co -l .
+@c $ mkdir tc
+@c $ cvs add tc
+@c $ cd tc
+@c $ mkdir man
+@c $ cvs add man
+@c etc.
+@c Using import to create the directories only is
+@c probably a somewhat confusing concept.
+@c <en>For a new project, the easiest thing to do is probably
+@c <en>to create an empty directory structure, like this:
+For a new project, the easiest thing to do is probably
+to create an empty directory structure, like this:
+
+@example
+$ mkdir tc
+$ mkdir tc/man
+$ mkdir tc/testing
+@end example
+
+@c <en>After that, you use the @code{import} command to create
+@c <en>the corresponding (empty) directory structure inside
+@c <en>the repository:
+After that, you use the @code{import} command to create
+the corresponding (empty) directory structure inside
+the repository:
+
+@example
+$ cd tc
+@c <en>$ cvs import -m "Created directory structure" yoyodyne/@var{dir} yoyo start
+$ cvs import -m "Created directory structure" yoyodyne/@var{dir} yoyo start
+@end example
+
+@c <en>Then, use @code{add} to add files (and new directories)
+@c <en>as they appear.
+Then, use @code{add} to add files (and new directories)
+as they appear.
+
+@c <en>Check that the permissions @sc{cvs} sets on the
+@c <en>directories inside @code{$CVSROOT} are reasonable.
+Check that the permissions @sc{cvs} sets on the
+directories inside @code{$CVSROOT} are reasonable.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Defining the module
+@node Definindo o módulo
+@c <en>@section Defining the module
+@section Definindo o módulo
+@c <en>@cindex Defining a module
+@cindex Defining a module
+@c <en>@cindex Editing the modules file
+@cindex Editing the modules file
+@c <en>@cindex Module, defining
+@cindex Module, defining
+@c <en>@cindex Modules file, changing
+@cindex Modules file, changing
+
+@c <en>The next step is to define the module in the
+@c <en>@file{modules} file. This is not strictly necessary,
+@c <en>but modules can be convenient in grouping together
+@c <en>related files and directories.
+The next step is to define the module in the
+@file{modules} file. This is not strictly necessary,
+but modules can be convenient in grouping together
+related files and directories.
+
+@c <en>In simple cases these steps are sufficient to define a module.
+In simple cases these steps are sufficient to define a module.
+
+@enumerate
+@item
+@c <en>Get a working copy of the modules file.
+Get a working copy of the modules file.
+
+@example
+$ cvs checkout CVSROOT/modules
+$ cd CVSROOT
+@end example
+
+@item
+@c <en>Edit the file and insert a line that defines the module. @xref{Intro
+@c <en>administrative files}, for an introduction. @xref{modules}, for a full
+@c <en>description of the modules file. You can use the
+@c <en>following line to define the module @samp{tc}:
+Edit the file and insert a line that defines the module.
+@xref{Intro aos arquivos administrativos}, for an
+introduction. @xref{modules}, for a full description
+of the modules file. You can use the following line to
+define the module @samp{tc}:
+
+@example
+tc yoyodyne/tc
+@end example
+
+@item
+@c <en>Commit your changes to the modules file.
+Commit your changes to the modules file.
+
+@example
+@c <en>$ cvs commit -m "Added the tc module." modules
+$ cvs commit -m "Added the tc module." modules
+@end example
+
+@item
+@c <en>Release the modules module.
+Release the modules module.
+
+@example
+$ cd ..
+$ cvs release -d CVSROOT
+@end example
+@end enumerate
+
+@c ---------------------------------------------------------------------
+@c <en>@node Revisions
+@node Revisões
+@c <en>@chapter Revisions
+@chapter Revisões
+
+@comment <en>For many uses of @sc{cvs}, one doesn't need to worry
+@comment <en>too much about revision numbers; @sc{cvs} assigns
+@comment <en>numbers such as @code{1.1}, @code{1.2}, and so on, and
+@comment <en>that is all one needs to know. However, some people
+@comment <en>prefer to have more knowledge and control concerning
+@comment <en>how @sc{cvs} assigns revision numbers.
+Para muitos usos do @sc{cvs}, não é necessário se
+preocupar com o número de revisões; o @sc{cvs} atribui
+números tais como @code{1.1}, @code{1.2} e por aí vai,
+e isto é tudo que se precisa saber. Entretanto,
+Algumas pessoas preferem ter mais conhecimento e
+controle a respeito de como o @sc{cvs} atribui números
+de revisão.
+
+@c <en>If one wants to keep track of a set of revisions
+@c <en>involving more than one file, such as which revisions
+@c <en>went into a particular release, one uses a @dfn{tag},
+@c <en>which is a symbolic revision which can be assigned to a
+@c <en>numeric revision in each file.
+Se você quiser marcar um conjunto de revisões
+envolvendo mais de um arquivo, tais como as revisões
+que integram uma release, pode usar uma @dfn{etiqueta} (tag),
+que é uma revisão simbólica que pode ser associada a uma
+revisão numérica em cada um dos arquivos.
+
+@menu
+@c <en>* Revision numbers:: The meaning of a revision number
+* Números de revisão:: O significado dos números de revisão
+@c <en>* Versions revisions releases:: Terminology used in this manual
+* Versões revisões releases:: Terminologia usada neste manual
+@c <en>* Assigning revisions:: Assigning revisions
+* Atribuindo revisões:: Atribuindo revisões
+@c <en>* Tags:: Tags--Symbolic revisions
+* Etiquetas:: Etiquetas (Tags)--Revisões Simbólicas
+@c <en>* Tagging the working directory:: The cvs tag command
+* Etiquetando o diretório de trabalho:: O comando cvs tag
+@c <en>* Tagging by date/tag:: The cvs rtag command
+* Etiquetando por data/etiqueta:: O comando cvs rtag
+@c <en>* Modifying tags:: Adding, renaming, and deleting tags
+* Modificando etiquetas:: Adicionando, renomeando e apagando etiquetas
+@c <en>* Tagging add/remove:: Tags with adding and removing files
+* Etiquetando adicionados/removidos:: Etiquetas com arquivos adicionados e removidos
+@c <en>* Sticky tags:: Certain tags are persistent
+* Etiquetas adesivas:: Certas etiquetas são persistentes
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Revision numbers
+@node Números de revisão
+@c <en>@section Revision numbers
+@section Números de revisão
+@c <en>@cindex Revision numbers
+@cindex Números de revisão
+@c <en>@cindex Revision tree
+@cindex Árvore de revisão
+@c <en>@cindex Linear development
+@cindex Desenvolvimento linear
+@c <en>@cindex Number, revision-
+@cindex Revisão, número de
+@c <en>@cindex Decimal revision number
+@cindex Número de revisão decimal
+@c <en>@cindex Branch number
+@cindex Número de ramo
+@c <en>@cindex Number, branch
+@cindex Ramo, número de
+
+@c <en>Each version of a file has a unique @dfn{revision
+@c <en>number}. Revision numbers look like @samp{1.1},
+@c <en>@samp{1.2}, @samp{1.3.2.2} or even @samp{1.3.2.2.4.5}.
+@c <en>A revision number always has an even number of
+@c <en>period-separated decimal integers. By default revision
+@c <en>1.1 is the first revision of a file. Each successive
+@c <en>revision is given a new number by increasing the
+@c <en>rightmost number by one. The following figure displays
+@c <en>a few revisions, with newer revisions to the right.
+Cada versão de um arquivo tem um @dfn{número de
+revisão} único. Números de revisão são coisas do tipo
+@samp{1.1}, @samp{1.2}, @samp{1.3.2.2} ou até mesmo
+@samp{1.3.2.2.4.5}. Um número de revisão sempre tem uma
+quantidade par de números inteiros na base dez
+separados por ponto. Por padrão, a revisão 1.1 é a
+primeira revisão de um arquivo. Cada revisão sucessiva
+ganha um novo número somando um ao número mais a
+direita. A figura a seguir mostra mostra algumas
+revisões, com a revisão mais nova mais à direita.
+
+@example
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+ +-----+ +-----+ +-----+ +-----+ +-----+
+@end example
+
+@c <en>It is also possible to end up with numbers containing
+@c <en>more than one period, for example @samp{1.3.2.2}. Such
+@c <en>revisions represent revisions on branches
+@c <en>(@pxref{Branching and merging}); such revision numbers
+@c <en>are explained in detail in @ref{Branches and
+@c <en>revisions}.
+Também é possível ter números com mais de um ponto, por
+exemplo @samp{1.3.2.2}. Tais revisões representam
+revisões em ramos (@pxref{Ramificando e mesclando});
+estes números de revisão são explicados em detalhes em
+@ref{Ramos e revisões}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Versions revisions releases
+@node Versões revisões releases
+@c <en>@section Versions, revisions and releases
+@section Versões, revisões e releases
+@c <en>@cindex Revisions, versions and releases
+@cindex Revisões, versões e releases
+@c <en>@cindex Versions, revisions and releases
+@cindex Versões, revisões e releases
+@c <en>@cindex Releases, revisions and versions
+@cindex Releases, revisões e versões
+
+@c <en>A file can have several versions, as described above.
+@c <en>Likewise, a software product can have several versions.
+@c <en>A software product is often given a version number such
+@c <en>as @samp{4.1.1}.
+Um arquivo pode ter várias versões, como descrito
+acima. Da mesma forma, um produto de software também
+pode ter várias versões. Frequentemente um produto de
+software recebe um número de versão, tal como @samp{4.1.1}.
+
+@c <en>Versions in the first sense are called @dfn{revisions}
+@c <en>in this document, and versions in the second sense are
+@c <en>called @dfn{releases}. To avoid confusion, the word
+@c <en>@dfn{version} is almost never used in this document.
+Versões, neste documento são chamadas, principalmente,
+de @dfn{revisões} , e também de @dfn{releases}. Para evitar
+confusão, o termo @dfn{versão} praticamente não é usado
+neste documento.
+
+@c <en>@node Assigning revisions
+@node Atribuindo revisões
+@c <en>@section Assigning revisions
+@section Atribuindo revisões
+
+@c We avoid the "major revision" terminology. It seems
+@c like jargon. Hopefully "first number" is clear enough.
+@c
+@c Well, in the context of software release numbers,
+@c "major" and "minor" release or version numbers are
+@c documented in at least the GNU Coding Standards, but I'm
+@c still not sure I find that a valid reason to apply the
+@c terminology to RCS revision numbers. "First", "Second",
+@c "subsequent", and so on is almost surely clearer,
+@c especially to a novice reader. -DRP
+@c <en>By default, @sc{cvs} will assign numeric revisions by
+@c <en>leaving the first number the same and incrementing the
+@c <en>second number. For example, @code{1.1}, @code{1.2},
+@c <en>@code{1.3}, etc.
+Por padrão, @sc{cvs} vai atribuir revisões numéricas
+mantendo o primeiro número e aumentando o segundo. Por
+exemplo, @code{1.1}, @code{1.2}, @code{1.3}, etc.
+
+@c <en>When adding a new file, the second number will always
+@c <en>be one and the first number will equal the highest
+@c <en>first number of any file in that directory. For
+@c <en>example, the current directory contains files whose
+@c <en>highest numbered revisions are @code{1.7}, @code{3.1},
+@c <en>and @code{4.12}, then an added file will be given the
+@c <en>numeric revision @code{4.1}.
+Quando um novo arquivo é adicionado, o segundo número
+vai ser sempre o um e o primeiro número vai ser igual
+ao maior primeiro número de qualquer arquivo no
+diretório. Por exemplo, se o diretório atual contiver
+arquivos os quais o maior número de revisão seram
+@code{1.7}, @code{3.1} e @code{4.12}, então um arquivo
+adicionado vai receber a revisão numérica @code{4.1}.
+
+@c This is sort of redundant with something we said a
+@c while ago. Somewhere we need a better way of
+@c introducing how the first number can be anything
+@c except "1", perhaps. Also I don't think this
+@c presentation is clear on why we are discussing releases
+@c and first numbers of numeric revisions in the same
+@c breath.
+@c <en>Normally there is no reason to care
+@c <en>about the revision numbers---it is easier to treat them
+@c <en>as internal numbers that @sc{cvs} maintains, and tags
+@c <en>provide a better way to distinguish between things like
+@c <en>release 1 versus release 2 of your product
+@c <en>(@pxref{Tags}). However, if you want to set the
+@c <en>numeric revisions, the @samp{-r} option to @code{cvs
+@c <en>commit} can do that. The @samp{-r} option implies the
+@c <en>@samp{-f} option, in the sense that it causes the
+@c <en>files to be committed even if they are not modified.
+Normalmente não há razão para se preocupar com números
+de revisão---é melhor tratá-los como numeração interna
+que o @sc{cvs} mantém, e etiquetas (tags) fornecem uma
+forma melhor de distinguir entre coisas tais como
+release 1 e release 2 de seu produto
+(@pxref{Etiquetas}). Entretando, se você quiser
+ajustar as revisões numéricas, a opção @samp{-r} do
+@code{cvs commit} pode fazer isto. A opção @samp{-r}
+implica na opção @samp{-f}, no sentido de que ela faz
+com que os arquivos sejam submetidos mesmo caso eles
+não estejam modificados.
+
+@c <en>For example, to bring all your files up to
+@c <en>revision 3.0 (including those that haven't changed),
+@c <en>you might invoke:
+Por exemplo, para subir todos os arquivos para a
+revisão 3.0 (inclusive os que não sofreram mudanças),
+você deve invocar:
+
+@example
+$ cvs commit -r 3.0
+@end example
+
+@c <en>Note that the number you specify with @samp{-r} must be
+@c <en>larger than any existing revision number. That is, if
+@c <en>revision 3.0 exists, you cannot @samp{cvs commit
+@c <en>-r 1.3}. If you want to maintain several releases in
+@c <en>parallel, you need to use a branch (@pxref{Branching and merging}).
+Observe que o número que você especificar com a opção
+@samp{-r} deve ser maior que qualquer número de revisão
+existente. Ou seja, se a revisão 3.0 existe, você não
+pode fazer @samp{cvs commit -r 1.3}. Se você quiser
+manter várias releases em paralelo, você deve usar um ramo
+(@pxref{Ramificando e mesclando}).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Tags
+@node Etiquetas
+@c <en>@section Tags--Symbolic revisions
+@section Etiquetas (Tags)--Revisões simbólicas
+@c <en>@cindex Tags
+@cindex Etiquetas
+
+@c <en>The revision numbers live a life of their own. They
+@c <en>need not have anything at all to do with the release
+@c <en>numbers of your software product. Depending
+@c <en>on how you use @sc{cvs} the revision numbers might change several times
+@c <en>between two releases. As an example, some of the
+@c <en>source files that make up @sc{rcs} 5.6 have the following
+@c <en>revision numbers:
+Os números de revisão tem uma vida a parte. Eles não
+precisam ter nada a ver com os números de release de
+seu produto de software. Dependendo de como você usa o
+@sc{cvs}, os números de revisão podem mudar várias
+vezes entre duas releases. Como um exemplo, alguns dos
+arquivos fonte do @sc{rcs} 5.6 tinham os seguintes
+números de revisão:
+@c <en>@cindex RCS revision numbers
+@cindex números de revisão do RCS
+
+@example
+ci.c 5.21
+co.c 5.9
+ident.c 5.3
+rcs.c 5.12
+rcsbase.h 5.11
+rcsdiff.c 5.10
+rcsedit.c 5.11
+rcsfcmp.c 5.9
+rcsgen.c 5.10
+rcslex.c 5.11
+rcsmap.c 5.2
+rcsutil.c 5.10
+@end example
+
+@c <en>@cindex tag (subcommand), introduction
+@cindex tag (subcomando), introdução
+@c <en>@cindex Tags, symbolic name
+@cindex Etiquetas, nome simbólico
+@c <en>@cindex Symbolic name (tag)
+@cindex Nome simbólico (etiqueta)
+@c <en>@cindex Name, symbolic (tag)
+@cindex Simbólico, nome (etiqueta)
+@c <en>@cindex HEAD, as reserved tag name
+@cindex HEAD, nome de etiqueta reservado
+@c <en>@cindex BASE, as reserved tag name
+@cindex BASE, nome de etiqueta reservado
+@c <en>You can use the @code{tag} command to give a symbolic name to a
+@c <en>certain revision of a file. You can use the @samp{-v} flag to the
+@c <en>@code{status} command to see all tags that a file has, and
+@c <en>which revision numbers they represent. Tag names must
+@c <en>start with an uppercase or lowercase letter and can
+@c <en>contain uppercase and lowercase letters, digits,
+@c <en>@samp{-}, and @samp{_}. The two tag names @code{BASE}
+@c <en>and @code{HEAD} are reserved for use by @sc{cvs}. It
+@c <en>is expected that future names which are special to
+@c <en>@sc{cvs} will be specially named, for example by
+@c <en>starting with @samp{.}, rather than being named analogously to
+@c <en>@code{BASE} and @code{HEAD}, to avoid conflicts with
+@c <en>actual tag names.
+Você pode usar o comando @code{tag} para dar um nome
+simbólico para uma certa revisão de um arquivo. Você
+pode usar a opção @samp{-v} com o comando @code{status}
+para ver todas as etiquetas que um arquivo possui, e
+que números de revisão elas representam. Nomes de
+etiqueta devem começar com letra maiúscula ou minúscula
+e pode conter letras maiúsculas e minúsculas, dígitos,
+@samp{-} e @samp{_}. Os dois nomes de etiqueta
+@code{BASE} e @code{HEAD} são reservados para o
+@sc{cvs}. É esperado que nomes futuros que sejam
+especiais para o @sc{cvs} recebam nomes especiais, por
+exemplo começando com @samp{.}, sendo então nomeados de
+forma análoga a @code{BASE} e @code{HEAD}, para evitar
+conflitos com os nomes de etiqueta atuais.
+@c Including a character such as % or = has also been
+@c suggested as the naming convention for future
+@c special tag names. Starting with . is nice because
+@c that is not a legal tag name as far as RCS is concerned.
+@c FIXME: CVS actually accepts quite a few characters
+@c in tag names, not just the ones documented above
+@c (see RCS_check_tag). RCS
+@c defines legitimate tag names by listing illegal
+@c characters rather than legal ones. CVS is said to lose its
+@c mind if you try to use "/" (try making such a tag sticky
+@c and using "cvs status" client/server--see remote
+@c protocol format for entries line for probable cause).
+@c TODO: The testsuite
+@c should test for whatever are documented above as
+@c officially-OK tag names, and CVS should at least reject
+@c characters that won't work, like "/".
+
+@c <en>You'll want to choose some convention for naming tags,
+@c <en>based on information such as the name of the program
+@c <en>and the version number of the release. For example,
+@c <en>one might take the name of the program, immediately
+@c <en>followed by the version number with @samp{.} changed to
+@c <en>@samp{-}, so that @sc{cvs} 1.9 would be tagged with the name
+@c <en>@code{cvs1-9}. If you choose a consistent convention,
+@c <en>then you won't constantly be guessing whether a tag is
+@c <en>@code{cvs-1-9} or @code{cvs1_9} or what. You might
+@c <en>even want to consider enforcing your convention in the
+@c <en>@file{taginfo} file (@pxref{taginfo}).
+Você vai querer definir algumas convenções para nomear
+etiquetas, baseado em informações tais como nome do
+programa e número da versão da release. Por exemplo,
+algume pode pegar o nome do programa, seguindo pelo
+número de versão com o @samp{.} trocado por @samp{-},
+de forma que o @sc{cvs} 1.9 seja etiquetado com o nome
+de @code{cvs1-9}. Se você escolhe uma convenção
+consistente, você não vai precisar ficar constantemente
+adivinhando se a etiqueta é @code{cvs-1-9} ou
+@code{cvs1_9} ou sei lá o que. Você pode até mesmo
+considerar reforçar esta convenção no arquivo
+@file{taginfo} (@pxref{taginfo}).
+@c Might be nice to say more about using taginfo this
+@c way, like giving an example, or pointing out any particular
+@c issues which arise.
+
+@c <en>@cindex Adding a tag
+@cindex Adicionando uma etiqueta
+@c <en>@cindex Tags, example
+@cindex Etiquetas, exemplo
+@c <en>The following example shows how you can add a tag to a
+@c <en>file. The commands must be issued inside your working
+@c <en>directory. That is, you should issue the
+@c <en>command in the directory where @file{backend.c}
+@c <en>resides.
+O exemplo seguinte mostra como você pode adicionar uma
+etiqueta a um arquivo. Os comandos devem ser
+executados de dentro do seu diretório de trabalho. Ou
+seja, você deve executar o comando no diretório onde @file{backend.c}
+fica.
+
+@example
+$ cvs tag rel-0-4 backend.c
+T backend.c
+$ cvs status -v backend.c
+===================================================================
+File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-0-4 (revision: 1.4)
+
+@end example
+
+@c <en>For a complete summary of the syntax of @code{cvs tag},
+@c <en>including the various options, see @ref{Invoking CVS}.
+Para um resumo completo da sintaxe de @code{cvs tag},
+incluindo as várias opções, veja em @ref{Chamando o CVS}.
+
+@c <en>There is seldom reason to tag a file in isolation. A more common use is
+@c <en>to tag all the files that constitute a module with the same tag at
+@c <en>strategic points in the development life-cycle, such as when a release
+@c <en>is made.
+Existem poucas razões para etiquetar um arquivo em
+separado. Um uso mais comum é etiquetar todos os
+arquivos que fazem parte de um módulo com a mesma
+etiqueta em momentos estratégicos do ciclo de vida do
+desenvolvimento, como por exemplo, quando fica pronta
+uma release.
+
+@example
+$ cvs tag rel-1-0 .
+cvs tag: Tagging .
+T Makefile
+T backend.c
+T driver.c
+T frontend.c
+T parser.c
+@end example
+
+@noindent
+@c <en>(When you give @sc{cvs} a directory as argument, it generally applies the
+@c <en>operation to all the files in that directory, and (recursively), to any
+@c <en>subdirectories that it may contain. @xref{Recursive behavior}.)
+(Quando você passa um diretório para o @sc{cvs} como
+argumento, ele geralmente realiza a operação em todos
+os arquivos do diretório e (recursivamente) a todo
+subdiretório que ele contenha.
+@xref{Comportamento recursivo}.)
+
+@c <en>@cindex Retrieving an old revision using tags
+@cindex Retrieving an old revision using tags
+@c <en>@cindex Tags, retrieving old revisions
+@cindex Tags, retrieving old revisions
+@c <en>The @code{checkout} command has a flag, @samp{-r}, that lets you check out
+@c <en>a certain revision of a module. This flag makes it easy to
+@c <en>retrieve the sources that make up release 1.0 of the module @samp{tc} at
+@c <en>any time in the future:
+O comando @code{checkout} tem uma opção, @samp{-r}, que
+permite pegar uma certa revisão de um módulo. Esta
+opção torna fácil recuperar as ontes que fizeram parte
+da release 1.0 do módulo @samp{tc} a qualquer momento
+no futuro:
+
+@example
+$ cvs checkout -r rel-1-0 tc
+@end example
+
+@noindent
+@c <en>This is useful, for instance, if someone claims that there is a bug in
+@c <en>that release, but you cannot find the bug in the current working copy.
+Isto pode ser útil, por exemplo, se alguem afirma que
+tem um pau naquela versão, mas você não acha o pau na
+cópia de trabalho mais recente.
+
+@c <en>You can also check out a module as it was at any given date.
+@c <en>@xref{checkout options}. When specifying @samp{-r} to
+@c <en>any of these commands, you will need beware of sticky
+@c <en>tags; see @ref{Sticky tags}.
+Você também pode pegar um módulo do jeito que ele
+estava em qualquer data. @xref{checkout options}.
+Quando usar @samp{-r} em qualquer destes comandos, você
+vai precisar estar atento às etiquetas adesivas; veja
+em @ref{Etiquetas adesivas}.
+
+@c <en>When you tag more than one file with the same tag you
+@c <en>can think about the tag as "a curve drawn through a
+@c <en>matrix of filename vs. revision number." Say we have 5
+@c <en>files with the following revisions:
+Quando você etiqueta mais de um arquivo com a mesma
+etiqueta você pode pensar na etiqueta como "uma curva
+desenhada ao longo da matriz de nomes de arquivo por
+números de revisão". Digamos que temos 5 arquivos com
+as seguintes revisões:
+
+@example
+@group
+ file1 file2 file3 file4 file5
+
+ 1.1 1.1 1.1 1.1 /--1.1* <-*- TAG
+ 1.2*- 1.2 1.2 -1.2*-
+ 1.3 \- 1.3*- 1.3 / 1.3
+ 1.4 \ 1.4 / 1.4
+ \-1.5*- 1.5
+ 1.6
+@end group
+@end example
+
+@c <en>At some time in the past, the @code{*} versions were tagged.
+@c <en>You can think of the tag as a handle attached to the curve
+@c <en>drawn through the tagged revisions. When you pull on
+@c <en>the handle, you get all the tagged revisions. Another
+@c <en>way to look at it is that you "sight" through a set of
+@c <en>revisions that is "flat" along the tagged revisions,
+@c <en>like this:
+Em algum momento no passado, as versões com @code{*}
+foram etiquetadas. Você pode pensar na etiqueta como
+uma alça presa à curva que passa pelas revisões
+marcadas. Quando você puxa a alça, vem as revisões
+etiquetadas. outra maneira de perceber isto é ver
+através de um conjunto de revisões que foram alinhadas
+pelas revisões etiquetadas, como isto:
+
+@example
+@group
+ file1 file2 file3 file4 file5
+
+ 1.1
+ 1.2
+ 1.1 1.3 _
+ 1.1 1.2 1.4 1.1 /
+ 1.2*----1.3*----1.5*----1.2*----1.1* (--- <--- Look here
+ 1.3 1.6 1.3 \_
+ 1.4 1.4
+ 1.5
+@end group
+@end example
+
+@c <en>@node Tagging the working directory
+@node Etiquetando o diretório de trabalho
+@c <en>@section Specifying what to tag from the working directory
+@section Especificando o que etiquetar no diretório de trabalho
+
+@c <en>@cindex tag (subcommand)
+@cindex tag (subcomando)
+@c <en>The example in the previous section demonstrates one of
+@c <en>the most common ways to choose which revisions to tag.
+@c <en>Namely, running the @code{cvs tag} command without
+@c <en>arguments causes @sc{cvs} to select the revisions which
+@c <en>are checked out in the current working directory. For
+@c <en>example, if the copy of @file{backend.c} in working
+@c <en>directory was checked out from revision 1.4, then
+@c <en>@sc{cvs} will tag revision 1.4. Note that the tag is
+@c <en>applied immediately to revision 1.4 in the repository;
+@c <en>tagging is not like modifying a file, or other
+@c <en>operations in which one first modifies the working
+@c <en>directory and then runs @code{cvs commit} to transfer
+@c <en>that modification to the repository.
+O exemplo na seção anterior demonstra uma das formas
+mais comuns de escolher que revisões etiquetar. A
+saber, rodando o comando @code{cvs tag} sem argumentos
+faz com que o @sc{cvs} selecione as revisões que estão
+presentes no diretório de trabalho atual. Por exemplo,
+se a cópia do arquivo @file{backend.c} no diretório de
+trabalho foi pega da revisão 1.4, então o @sc{cvs} vai
+etiquetar a revisão 1.4. Observe que a etiqueta é
+aplicada na revisão 1.4 no repositório imediatamente;
+Etiquetar não funciona como modificar arquivos ou
+outras operações nas quais primeiros você modifica o
+diretório de trabalho e então roda o @code{cvs commit}
+para mandar as modificações para o repositório.
+
+@c <en>One potentially surprising aspect of the fact that
+@c <en>@code{cvs tag} operates on the repository is that you
+@c <en>are tagging the checked-in revisions, which may differ
+@c <en>from locally modified files in your working directory.
+@c <en>If you want to avoid doing this by mistake, specify the
+@c <en>@samp{-c} option to @code{cvs tag}. If there are any
+@c <en>locally modified files, @sc{cvs} will abort with an
+@c <en>error before it tags any files:
+Um aspecto potencialmente confuso no fato de o comando
+@code{cvs tag} operar no repositório é que você está
+etiquetando revisões devolvidas, que podem diferir de
+arquivos localmente modificados no seu diretório de
+trabalho. Se você quer evitar fazer isto por engano,
+use a opção @samp{-c} no @code{cvs tag}. Se existe
+qualquer arquivo localmente modificado, o @sc{cvs} vai
+abortar com erro antes de etiquetar qualquer arquivo:
+
+@example
+$ cvs tag -c rel-0-4
+cvs tag: backend.c is locally modified
+cvs [tag aborted]: correct the above errors first!
+@end example
+
+@c <en>@node Tagging by date/tag
+@node Etiquetando por data/etiqueta
+@c <en>@section Specifying what to tag by date or revision
+@section Especificando o que etiquetar por data ou revisão
+@c <en>@cindex rtag (subcommand)
+@cindex rtag (subcomando)
+
+@c <en>The @code{cvs rtag} command tags the repository as of a
+@c <en>certain date or time (or can be used to tag the latest
+@c <en>revision). @code{rtag} works directly on the
+@c <en>repository contents (it requires no prior checkout and
+@c <en>does not look for a working directory).
+O comando @code{cvs rtag} etiqueta o repositório em uma
+certa data ou hora (ou pode ser usado para etiquetar a
+última revisão). @code{rtag} trabalha diretamente no
+repositório (não requer um checkout e não procura por
+um diretório de trabalho).
+
+@c <en>The following options specify which date or revision to
+@c <en>tag. See @ref{Common options}, for a complete
+@c <en>description of them.
+As seguintes opções especificam que data ou revisão
+etiquetar. Veja em @ref{Opções comuns}, para uma
+descrição completa delas.
+
+@table @code
+@c <en>@item -D @var{data}
+@item -D @var{data}
+@c <en>Tag the most recent revision no later than @var{date}.
+Etiqueta a revisão mais recente que seja anterior a @var{data}.
+
+@c <en>@item -f
+@item -f
+@c <en>Only useful with the @samp{-D @var{date}} or @samp{-r @var{tag}}
+@c <en>flags. If no matching revision is found, use the most
+@c <en>recent revision (instead of ignoring the file).
+Útil apenas em conjunto com @samp{-D @var{data}} ou
+@samp{-r @var{etiqueta}}. Se não encontrar uma revisã
+casando com o padrão, usar a revisão mais recente (ao
+invés de ignorar o arquivo).
+
+@c <en>@item -r @var{tag}
+@item -r @var{etiqueta}
+@c <en>Only tag those files that contain existing tag @var{tag}.
+Etiqueta apenas os arquivos que contém a etiqueta
+@var{etiqueta} existente.
+@end table
+
+@c <en>The @code{cvs tag} command also allows one to specify
+@c <en>files by revision or date, using the same @samp{-r},
+@c <en>@samp{-D}, and @samp{-f} options. However, this
+@c <en>feature is probably not what you want. The reason is
+@c <en>that @code{cvs tag} chooses which files to tag based on
+@c <en>the files that exist in the working directory, rather
+@c <en>than the files which existed as of the given tag/date.
+@c <en>Therefore, you are generally better off using @code{cvs
+@c <en>rtag}. The exceptions might be cases like:
+O comando @code{cvs tag} também permite que você
+especifique arquivos por revisão ou data, usando as
+mesmas opções @samp{-r}, @samp{-D} e @samp{-f}.
+Entretanto, este característica não é provavelmente o
+que você quer. A razão é que o @code{cvs tag} escolhe
+que arquivos etiquetar baseado nos arquivos que existem
+no diretório de trabalho, ao invés de arquivos que
+existem na dada etiqueta/data. Portanto, você é
+geralmente ???better off??? usar @code{cvs rtag}. As
+exceções devem ser casos como:
+
+@example
+cvs tag -r 1.4 stable backend.c
+@end example
+
+@c <en>@node Modifying tags
+@node Modificando etiquetas
+@c <en>@section Deleting, moving, and renaming tags
+@section Apagando, movendo e renomeando etiquetas
+
+@c Also see:
+@c "How do I move or rename a magic branch tag?"
+@c in the FAQ (I think the issues it talks about still
+@c apply, but this could use some sanity.sh work).
+
+@c <en>Normally one does not modify tags. They exist in order
+@c <en>to record the history of the repository and so deleting
+@c <en>them or changing their meaning would, generally, not be
+@c <en>what you want.
+Normalmente não se modificam etiquetas. Elas existem
+para registrar o histórico do repositório e, portanto,
+apagá-las ou alterar o significado delas não é, em
+geral, o que você quer.
+
+@c <en>However, there might be cases in which one uses a tag
+@c <en>temporarily or accidentally puts one in the wrong
+@c <en>place. Therefore, one might delete, move, or rename a
+@c <en>tag.
+Entretanto, podem haver casos nos quais alguem usa a
+etiqueta temporariamente ou bota no lugar errado por
+acidente. Logo, é possível apagar, mover, ou renomear
+uma etiqueta.
+
+@noindent
+@c <en>@strong{WARNING: the commands in this section are
+@c <en>dangerous; they permanently discard historical
+@c <en>information and it can be difficult or impossible to
+@c <en>recover from errors. If you are a @sc{cvs}
+@c <en>administrator, you may consider restricting these
+@c <en>commands with the @file{taginfo} file (@pxref{taginfo}).}
+@strong{ATENÇÃO: os comandos nesta seção são perigosos;
+eles apagam permanentemente informações históricas e
+pode ser difícil ou impossível recuperar tais
+informações em caso de erro. Se você é um
+administrador do @sc{cvs}, você deve considerar
+restringir estes comandos com o arquivo @file{taginfo}
+(@pxref{taginfo}).}
+
+@c <en>@cindex Deleting tags
+@cindex Apagando etiquetas
+@c <en>@cindex Deleting branch tags
+@cindex Apagando etiquetas de ramos
+@c <en>@cindex Removing tags
+@cindex Removendo etiquetas
+@c <en>@cindex Removing branch tags
+@cindex Removendo etiquetas de ramos
+@c <en>@cindex Tags, deleting
+@cindex Etiquetas, apagando
+@c <en>@cindex Branch tags, deleting
+@cindex Etiquetas de ramos, apagando
+@c <en>To delete a tag, specify the @samp{-d} option to either
+@c <en>@code{cvs tag} or @code{cvs rtag}. For example:
+Para apagar uma etiqueta, especifique a opção @samp{-d}
+tanto para @code{cvs tag} quanto para @code{cvs rtag}. Por exemplo:
+
+@example
+cvs rtag -d rel-0-4 tc
+@end example
+
+@noindent
+@c <en>deletes the non-branch tag @code{rel-0-4} from the module @code{tc}.
+@c <en>In the event that branch tags are encountered within the repository
+@c <en>with the given name, a warning message will be issued and the branch
+@c <en>tag will not be deleted. If you are absolutely certain you know what
+@c <en>you are doing, the @code{-B} option may be specified to allow deletion
+@c <en>of branch tags. In that case, any non-branch tags encountered will
+@c <en>trigger warnings and will not be deleted.
+apaga a etiqueta ???non-branch??? @code{rel-0-4} do
+módulo @code{tc}. No caso de etiquetas de ramos serem
+encontradas no repositório com o nome dado, uma
+mensagem de aviso vai ser mostrada e a etiqueta de ramo
+não vai ser apagada. Se você está absolutamente certo
+de que sabe o que está fazendo, a opção @code{-B} pode
+ser especificada para permitir que se apague as
+etiquetas de ramos. Neste caso, qualquer etiqueta
+???non-branch??? encontrada vai disparar avisos e não
+vai ser apagada.
+
+@noindent
+@c <en>@strong{WARNING: Moving branch tags is very dangerous! If you think
+@c <en>you need the @code{-B} option, think again and ask your @sc{cvs}
+@c <en>administrator about it (if that isn't you). There is almost certainly
+@c <en>another way to accomplish what you want to accomplish.}
+@strong{ATENÇÃO: Mover etiquetas de ramos é muito
+perigoso! Se você pensa que precisa da opção
+@code{-B}, pense duas vezes e pergunte a seu
+administrador do @sc{cvs} sobre ela (se não for você).
+É quase certo que existe outra forma de alcançar o seu objetivo.}
+
+@c <en>@cindex Moving tags
+@cindex Movendo etiquetas
+@c <en>@cindex Moving branch tags
+@cindex Movendo etiquetas de ramos
+@c <en>@cindex Tags, moving
+@cindex Etiquetas, movendo
+@c <en>@cindex Branch tags, moving
+@cindex Etiquetas de ramos, movendo
+@c <en>When we say @dfn{move} a tag, we mean to make the same
+@c <en>name point to different revisions. For example, the
+@c <en>@code{stable} tag may currently point to revision 1.4
+@c <en>of @file{backend.c} and perhaps we want to make it
+@c <en>point to revision 1.6. To move a non-branch tag, specify the
+@c <en>@samp{-F} option to either @code{cvs tag} or @code{cvs
+@c <en>rtag}. For example, the task just mentioned might be
+@c <en>accomplished as:
+Quando falamos em @dfn{mover} uma etiqueta, queremos
+dizer fazer com que o mesmo nome aponte para diferentes
+revisões. Por exemplo, a etiqueta @code{stable} pode
+atualmente apontar para a revisão 1.4 do arquivo
+@file{backend.c} e talvez nós queiramos fazé-la apontar
+para a revisão 1.6. Para mover uma etiqueta
+???non-branch???, Use a opção @samp{-F} tanto com o
+@code{cvs tag} oquanto com o @code{cvs rtag}. Por
+exemplo, esta mudança pode ser alcançada com:
+
+@example
+cvs tag -r 1.6 -F stable backend.c
+@end example
+
+@noindent
+@c <en>If any branch tags are encountered in the repository
+@c <en>with the given name, a warning is issued and the branch
+@c <en>tag is not disturbed. If you are absolutely certain you
+@c <en>wish to move the branch tag, the @code{-B} option may be specified.
+@c <en>In that case, non-branch tags encountered with the given
+@c <en>name are ignored with a warning message.
+Se alguma etiqueta de ramo for encontrada no
+repositório com o nome dado, um aviso é mostrado e a
+etiqueta de ramo não é alterada. Se você está
+absolutamente certo de que você quer mover a etiquta de
+ramo, a opção @code{-B} pode ser especificada. Neste
+caso, etiquetas ???non-branch??? encontradas com o nome
+dado serão ignoradas com uma mensagem de aviso.
+
+@noindent
+@c <en>@strong{WARNING: Moving branch tags is very dangerous! If you think you
+@c <en>need the @code{-B} option, think again and ask your @sc{cvs}
+@c <en>administrator about it (if that isn't you). There is almost certainly
+@c <en>another way to accomplish what you want to accomplish.}
+@strong{ATENÇÃO: Mover etiquetas de ramos é muito
+perigoso! Se você pensa que precisa da opção
+@code{-B}, pense duas vezes e pergunte a seu
+administrador do @sc{cvs} sobre ela (se não for você).
+É quase certo que existe outra forma de alcançar o seu objetivo.}
+
+@c <en>@cindex Renaming tags
+@cindex Renomeando etiquetas
+@c <en>@cindex Tags, renaming
+@cindex Etiquetas, renomeando
+@c <en>When we say @dfn{rename} a tag, we mean to make a
+@c <en>different name point to the same revisions as the old
+@c <en>tag. For example, one may have misspelled the tag name
+@c <en>and want to correct it (hopefully before others are
+@c <en>relying on the old spelling). To rename a tag, first
+@c <en>create a new tag using the @samp{-r} option to
+@c <en>@code{cvs rtag}, and then delete the old name. (Caution:
+@c <en>this method will not work with branch tags.)
+@c <en>This leaves the new tag on exactly the
+@c <en>same files as the old tag. For example:
+Quando falamos em @dfn{renomear} uma etiqueta, queremos
+dizer fazer com que um nome diferente aponte para para
+as mesmas revisões que a etiqueta antiga. Por exemplo,
+alguem pode ter digitado errado o nome de uma etiqueta
+e quer corrigir isto (de preferência antes que outros
+caiam no mesmo erro). Para renomear uma etiqueta,
+primeiro crie uma nova etiqueta usando a opção
+@samp{-r} para o @code{cvs rtag}, e então apague o nome
+antigo. (Cuidado: este método não vai funcionar com
+etiquetas de ramos). Isto deixa a nova etiqueta
+exatamente nos mesmos arquivos que a etiqueta antiga.
+Por exemplo:
+
+@example
+cvs rtag -r old-name-0-4 rel-0-4 tc
+cvs rtag -d old-name-0-4 tc
+@end example
+
+@c <en>@node Tagging add/remove
+@node Etiquetando adicionados/removidos
+@c <en>@section Tagging and adding and removing files
+@section Etiquetando e adicionando e removendo arquivos
+
+@c <en>The subject of exactly how tagging interacts with
+@c <en>adding and removing files is somewhat obscure; for the
+@c <en>most part @sc{cvs} will keep track of whether files
+@c <en>exist or not without too much fussing. By default,
+@c <en>tags are applied to only files which have a revision
+@c <en>corresponding to what is being tagged. Files which did
+@c <en>not exist yet, or which were already removed, simply
+@c <en>omit the tag, and @sc{cvs} knows to treat the absence
+@c <en>of a tag as meaning that the file didn't exist as of
+@c <en>that tag.
+O tema a respeito de como exatamente etiquetas
+interagem com arquivos adicionados e removidos é de
+certa forma obscuro; Normalmente, o @sc{cvs} vai
+verificar quais arquivos existem ou não sem muita
+confusão. Por padrão, etiquetas são aplicadas apenas a
+arquivos que tenham uma revisão correspondendo ao que
+está sendo etiquetado. Arquivos que ainda não existem,
+ou que já foram removidos, simplesmente omitem a
+etiqueta, e o @sc{cvs} trata a ausência de uma
+etiqueta como significando que o arquivo não existia na
+criação da etiqueta.
+
+@c <en>However, this can lose a small amount of information.
+@c <en>For example, suppose a file was added and then removed.
+@c <en>Then, if the tag is missing for that file, there is no
+@c <en>way to know whether the tag refers to the time before
+@c <en>the file was added, or the time after it was removed.
+@c <en>If you specify the @samp{-r} option to @code{cvs rtag},
+@c <en>then @sc{cvs} tags the files which have been removed,
+@c <en>and thereby avoids this problem. For example, one
+@c <en>might specify @code{-r HEAD} to tag the head.
+Entretanto, Isto pode perder uma pequena quantidade de
+informação. Por exemplo, suponha que um arquivo foi
+adicionado e então removido. Então, se a etiqueta está
+faltando para aquele arquivo, não há como se descobrir
+se a data da etiqueta é posterior à adição ou anterior
+à remoção do arquivo. Se você usa a opção @samp{-r}
+para @code{cvs rtag}, então o @sc{cvs} etiqueta os
+arquivos que foram removidos, e portanto remove este
+problema. Por exemplo, alguem pode especificar @code{-r
+HEAD} para etiquetar a head.
+
+@c <en>On the subject of adding and removing files, the
+@c <en>@code{cvs rtag} command has a @samp{-a} option which
+@c <en>means to clear the tag from removed files that would
+@c <en>not otherwise be tagged. For example, one might
+@c <en>specify this option in conjunction with @samp{-F} when
+@c <en>moving a tag. If one moved a tag without @samp{-a},
+@c <en>then the tag in the removed files might still refer to
+@c <en>the old revision, rather than reflecting the fact that
+@c <en>the file had been removed. I don't think this is
+@c <en>necessary if @samp{-r} is specified, as noted above.
+A respeito de adicionar e remover arquivos, o comando
+@code{cvs rtag} tem a opção @samp{-a} que significa
+limpar a etiqueta de arquivos removidos que ???would
+not otherwise be tagged???. Por exemplo, alguem pode
+especificar esta opção em conjunto com @samp{-F} quando
+mover uma etiqueta. Se alguem mover uma etiqueta sem o
+@samp{-a}, então a etiqueta nos arquivos removidos vai
+continuar fazendo referência à revisão antiga, Ao invés
+de refletir o fato de que o arquivo foi removido. Eu
+não acho que isto seja necessário se @samp{-r} é
+especificado, como falado acima.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Sticky tags
+@node Etiquetas adesivas
+@c <en>@section Sticky tags
+@section Etiquetas adesivas
+@c <en>@cindex Sticky tags
+@cindex Etiquetas adesivas
+@c <en>@cindex Tags, sticky
+@cindex Adesivas, etiquetas
+
+@c A somewhat related issue is per-directory sticky
+@c tags (see comment at CVS/Tag in node Working
+@c directory storage); we probably want to say
+@c something like "you can set a sticky tag for only
+@c some files, but you don't want to" or some such.
+
+@c <en>Sometimes a working copy's revision has extra data
+@c <en>associated with it, for example it might be on a branch
+@c <en>(@pxref{Branching and merging}), or restricted to
+@c <en>versions prior to a certain date by @samp{checkout -D}
+@c <en>or @samp{update -D}. Because this data persists --
+@c <en>that is, it applies to subsequent commands in the
+@c <en>working copy -- we refer to it as @dfn{sticky}.
+Algumas vezes, um cópia de tabalho de uma revisão tem
+dados extra associados a ela, por exemplo, ela pode
+estar num ramo (@pxref{Ramificando e mesclando}), ou
+restrita a uma versão anterior a uma certa data por
+@samp{checkout -D} ou @samp{update -D}. Já que este
+dado persiste -- ou seja, ele se aplica a comandos
+subseqüentes na cópia de trabalho -- nós o chamamos de
+@dfn{adesivos}.
+
+@c <en>Most of the time, stickiness is an obscure aspect of
+@c <en>@sc{cvs} that you don't need to think about. However,
+@c <en>even if you don't want to use the feature, you may need
+@c <en>to know @emph{something} about sticky tags (for
+@c <en>example, how to avoid them!).
+Na maioria das vezes, ser adesivo é um aspecto obscuro
+do @sc{cvs} que você não precisa saber a respeito.
+Entretanto, mesmo se você não quiser usar esta
+habilidade, você vai precisar saber @emph{alguma
+coisa} sobre etiquetas adesivas (sticky tags) (por
+exemplo, como evitá-las!).
+
+@c <en>You can use the @code{status} command to see if any
+@c <en>sticky tags or dates are set:
+Você pode usar o comando @code{status} para ver se
+alguma etiqueta ou data adesiva estão ligadas:
+
+@example
+$ cvs status driver.c
+===================================================================
+File: driver.c Status: Up-to-date
+
+ Version: 1.7.2.1 Sat Dec 5 19:35:03 1992
+ RCS Version: 1.7.2.1 /u/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+@end example
+
+@c <en>@cindex Resetting sticky tags
+@cindex Zerando etiquetas adesivas
+@c <en>@cindex Sticky tags, resetting
+@cindex Etiquetas adesivas, zerando
+@c <en>@cindex Deleting sticky tags
+@cindex Apagando etiquetas adesivas
+@c <en>The sticky tags will remain on your working files until
+@c <en>you delete them with @samp{cvs update -A}. The
+@c <en>@samp{-A} option merges local changes into the version of the
+@c <en>file from the head of the trunk, removing any sticky tags,
+@c <en>dates, or options. See @ref{update} for more on the operation
+@c <en>of @code{cvs update}.
+As etiquetas adesivas vão permanecer nos seus arquivos
+de trabalho até que você apague elas com @samp{cvs
+update -A}. A opção @samp{-A} mescla as alterações
+locais na versão do arquivo na cabeça (head) do tronco,
+removendo qualquer etiqueta, data ou opção adesiva.
+Veja em @ref{update} para mais a respeito desta
+operação do @code{cvs update}.
+
+@c <en>@cindex Sticky date
+@cindex Data adesiva
+@c <en>The most common use of sticky tags is to identify which
+@c <en>branch one is working on, as described in
+@c <en>@ref{Accessing branches}. However, non-branch
+@c <en>sticky tags have uses as well. For example,
+@c <en>suppose that you want to avoid updating your working
+@c <en>directory, to isolate yourself from possibly
+@c <en>destabilizing changes other people are making. You
+@c <en>can, of course, just refrain from running @code{cvs
+@c <en>update}. But if you want to avoid updating only a
+@c <en>portion of a larger tree, then sticky tags can help.
+@c <en>If you check out a certain revision (such as 1.4) it
+@c <en>will become sticky. Subsequent @code{cvs update}
+@c <en>commands will
+@c <en>not retrieve the latest revision until you reset the
+@c <en>tag with @code{cvs update -A}. Likewise, use of the
+@c <en>@samp{-D} option to @code{update} or @code{checkout}
+@c <en>sets a @dfn{sticky date}, which, similarly, causes that
+@c <en>date to be used for future retrievals.
+O uso mais comum de etiquetas adesivas é identificar em
+que ramo se está trabalhando, como descrito em
+@ref{Acessando ramos}. Entretanto, etiquetas adesivas
+em ???non-branch??? também têm seu uso. Por exemplo,
+suponha que você quer evitar atualizar seu diretório de
+trabalho, para se isolar de mudanças que outras pessoas
+estão fazendo que possam que possam desestabilizar seu
+trabalho. Você pode, claro, simplesmente não rodar o @code{cvs
+update}. Mas se você quer evitar atualizar (fazer
+update) apenas uma parte de uma grande árvore, então
+etiquetas adesivas podem ajudar. Se você pega uma certa
+revsão (como a 1.4) ela vai se tornar adesiva.
+comandos @code{cvs update} subsequentes não vão trazer
+a revisão mais nova até que você limpe a etiqueta com os
+comandos @code{cvs update -A}. Da mesma forma, o uso da
+opção @samp{-D} em @code{update} ou @code{checkout}
+define uma @dfn{data adesiva}, que, similarmente, faz
+com que a data seja usada para futuras ???retrievals???.
+
+@c <en>People often want to retrieve an old version of
+@c <en>a file without setting a sticky tag. This can
+@c <en>be done with the @samp{-p} option to @code{checkout} or
+@c <en>@code{update}, which sends the contents of the file to
+@c <en>standard output. For example:
+É normal as pessoas quererem recuperar uma versão
+antiga de um arquivo sem definir uma etiqueta adesiva.
+Isto pode ser feito com a opção @samp{-p} no
+@code{checkout} ou @code{update}, que manda o conteúdo
+do arquivo para a saída padrão. Por exemplo:
+@example
+$ cvs update -p -r 1.1 file1 >file1
+===================================================================
+Checking out file1
+RCS: /tmp/cvs-sanity/cvsroot/first-dir/Attic/file1,v
+VERS: 1.1
+***************
+$
+@end example
+
+@c <en>However, this isn't the easiest way, if you are asking
+@c <en>how to undo a previous checkin (in this example, put
+@c <en>@file{file1} back to the way it was as of revision
+@c <en>1.1). In that case you are better off using the
+@c <en>@samp{-j} option to @code{update}; for further
+@c <en>discussion see @ref{Merging two revisions}.
+Entretanto, esta não é a forma mais fácil, se você está
+querendo desfazer um envio anterior (neste exemplo,
+devolver o arquivo @file{file1} ao que ele era na
+revisão 1.1). Neste caso é melhor usar a opção
+@samp{-j} com o @code{update}; Para maiores detalhes,
+veja em @ref{Mesclando duas revisões}.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Branching and merging
+@node Ramificando e mesclando
+@c <en>@chapter Branching and merging
+@chapter Ramificando e mesclando
+@c <en>@cindex Branching
+@cindex Ramificando
+@c <en>@cindex Merging
+@cindex Mesclando
+@c <en>@cindex Copying changes
+@cindex Copying changes
+@c <en>@cindex Main trunk and branches
+@cindex Tronco principal e ramos
+@c <en>@cindex Revision tree, making branches
+@cindex Revision tree, making branches
+@c <en>@cindex Branches, copying changes between
+@cindex Branches, copying changes between
+@c <en>@cindex Changes, copying between branches
+@cindex Changes, copying between branches
+@c <en>@cindex Modifications, copying between branches
+@cindex Modifications, copying between branches
+
+@c <en>@sc{cvs} allows you to isolate changes onto a separate
+@c <en>line of development, known as a @dfn{branch}. When you
+@c <en>change files on a branch, those changes do not appear
+@c <en>on the main trunk or other branches.
+O @sc{cvs} permite isolar mudanças em uma linha de
+desenvolvimento separada, chamada de @dfn{ramo}.
+Quando você muda os arquivos de um ramo, aquelas
+mudanças não aparecem no tronco principal ou em outros ramos.
+
+@c <en>Later you can move changes from one branch to another
+@c <en>branch (or the main trunk) by @dfn{merging}. Merging
+@c <en>involves first running @code{cvs update -j}, to merge
+@c <en>the changes into the working directory.
+@c <en>You can then commit that revision, and thus effectively
+@c <en>copy the changes onto another branch.
+Mais tarde você pode mover as mudanças de um ramo para
+outro (ou para o tronco principal) com uma
+@dfn{mesclagem}. Mesclar é primeiro rodar um @code{cvs
+update -j}, para mesclar as mudanças no seu diretório
+de trabalho. Depois efetivar (commit) esta revisão, e
+finalmente fazer a efetiva destas mudanças de um ramo
+para outro.
+
+@menu
+@c <en>* Branches motivation:: What branches are good for
+* Motivação para ramos:: Para que ramos são bons
+@c <en>* Creating a branch:: Creating a branch
+* Criando um ramo:: Criando um ramo
+@c <en>* Accessing branches:: Checking out and updating branches
+* Acessando ramos:: Pegando e devolvendo ramos
+@c <en>* Branches and revisions:: Branches are reflected in revision numbers
+* Ramos e revisões:: Ramificar se reflete nos números de revisão
+@c <en>* Magic branch numbers:: Magic branch numbers
+* Números de ramos mágicos:: Magic branch numbers
+@c <en>* Merging a branch:: Merging an entire branch
+* Mesclando um ramo:: Mesclando um ramo inteiro
+@c <en>* Merging more than once:: Merging from a branch several times
+* Mesclando mais de uma vez:: Mesclando a partir de um ramo várias vezes
+@c <en>* Merging two revisions:: Merging differences between two revisions
+* Mesclando duas revisões:: Mesclando diferenças entre duas revisões
+@c <en>* Merging adds and removals:: What if files are added or removed?
+* Mesclando adicionados e removidos:: E se arquivos forem adicionados ou removidos?
+@c <en>* Merging and keywords:: Avoiding conflicts due to keyword substitution
+* Mesclagem e palavras-chave:: Evitando conflitos devido a substituição de palavras-chave
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Branches motivation
+@node Motivação para ramos
+@c <en>@section What branches are good for
+@section Para que ramos são bons
+@c <en>@cindex Branches motivation
+@cindex Motivação para ramos
+@c <en>@cindex What branches are good for
+@cindex Para que ramos são bons
+@c <en>@cindex Motivation for branches
+@cindex Motivation for branches
+
+@c FIXME: this node mentions one way to use branches,
+@c but it is by no means the only way. For example,
+@c the technique of committing a new feature on a branch,
+@c until it is ready for the main trunk. The whole
+@c thing is generally speaking more akin to the
+@c "Revision management" node although it isn't clear to
+@c me whether policy matters should be centralized or
+@c distributed throughout the relevant sections.
+@c <en>Suppose that release 1.0 of tc has been made. You are continuing to
+@c <en>develop tc, planning to create release 1.1 in a couple of months. After a
+@c <en>while your customers start to complain about a fatal bug. You check
+@c <en>out release 1.0 (@pxref{Tags}) and find the bug
+@c <en>(which turns out to have a trivial fix). However, the current revision
+@c <en>of the sources are in a state of flux and are not expected to be stable
+@c <en>for at least another month. There is no way to make a
+@c <en>bugfix release based on the newest sources.
+Suponha que a release 1.0 de tc está pronta. Você está
+continua desenvolvendo tc, e planeja lançar a release
+1.1 em alguns meses. Depois de um tempo seus
+consumidores começam a reclamar de um erro fatal. Você
+baixa a release 1.0 (@pxref{Etiquetas}) e encontra o
+erro (que tem um conserto fácil). Entretanto, a
+revisão atual dos fontes está num estado do fluxo de
+desenvolvimento que você não espera que estaja estável
+em pelo menos um mês. Não tem jeito de lançar uma
+release baseada nos fontes mais novos.
+
+@c <en>The thing to do in a situation like this is to create a @dfn{branch} on
+@c <en>the revision trees for all the files that make up
+@c <en>release 1.0 of tc. You can then make
+@c <en>modifications to the branch without disturbing the main trunk. When the
+@c <en>modifications are finished you can elect to either incorporate them on
+@c <en>the main trunk, or leave them on the branch.
+O que se há para fazer numa situação como esta é criar
+um @dfn{ramo} na árvore de revisões para todos os
+arquivos que integram a release 1.0 de tc. Você pode
+então fazer modificações no ramo sem perturbar o tronco
+principal. Quando as modificações terminarem você pode
+decidir se incorporam elas ao tronco ou deixa elas no ramo.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Creating a branch
+@node Criando um ramo
+@c <en>@section Creating a branch
+@section Criando um ramo
+@c <en>@cindex Creating a branch
+@cindex Criando um ramo
+@c <en>@cindex Branch, creating a
+@cindex Ramo, criando um
+@c <en>@cindex tag (subcommand), creating a branch using
+@cindex tag (subcomando), criando um ramo usando
+@c <en>@cindex rtag (subcommand), creating a branch using
+@cindex rtag (subcomando), criando um ramo usando
+
+@c <en>You can create a branch with @code{tag -b}; for
+@c <en>example, assuming you're in a working copy:
+Você pode criar um ramo com @code{tag -b}; por exemplo,
+supondo que você está numa cópia de trabalho:
+
+@example
+$ cvs tag -b rel-1-0-patches
+@end example
+
+@c FIXME: we should be more explicit about the value of
+@c having a tag on the branchpoint. For example
+@c "cvs tag rel-1-0-patches-branchpoint" before
+@c the "cvs tag -b". This points out that
+@c rel-1-0-patches is a pretty awkward name for
+@c this example (more so than for the rtag example
+@c below).
+
+@c <en>This splits off a branch based on the current revisions
+@c <en>in the working copy, assigning that branch the name
+@c <en>@samp{rel-1-0-patches}.
+Isto inicia um ramo baseado nas revisões atuais na
+cópia de trabalho, dando a este ramo o nome
+@samp{rel-1-0-patches}.
+
+@c <en>It is important to understand that branches get created
+@c <en>in the repository, not in the working copy. Creating a
+@c <en>branch based on current revisions, as the above example
+@c <en>does, will @emph{not} automatically switch the working
+@c <en>copy to be on the new branch. For information on how
+@c <en>to do that, see @ref{Accessing branches}.
+É importante entender que ramos são criados no
+repositório, e não na cópia de tarbalho. Criar um ramo
+baseado nas revisões atuais, como no exemplo acima,
+@emph{Não} vai mudar automaticamente a cópia de
+trabalho para o novo ramo. Para informações sobre
+como fazer isto, veja em @ref{Acessando ramos}.
+
+@c <en>You can also create a branch without reference to any
+@c <en>working copy, by using @code{rtag}:
+Você também pode criar um ramo sem referência a
+qualquer cópia de trabalho usando @code{rtag}:
+
+@example
+$ cvs rtag -b -r rel-1-0 rel-1-0-patches tc
+@end example
+
+@c <en>@samp{-r rel-1-0} says that this branch should be
+@c <en>rooted at the revision that
+@c <en>corresponds to the tag @samp{rel-1-0}. It need not
+@c <en>be the most recent revision -- it's often useful to
+@c <en>split a branch off an old revision (for example, when
+@c <en>fixing a bug in a past release otherwise known to be
+@c <en>stable).
+@samp{-r rel-1-0} diz que este ramo deve ser iniciado
+na revisão que corresponde à etiqueta (tag)
+@samp{rel-1-0}. Não precisa ser a revisão mais recente
+-- é útil às vezes separar um ramo a partir de uma
+revisão antiga (por exemplo, quando se está consertando
+um erro numa release anterior que se pensava estar
+estável).
+
+@c <en>As with @samp{tag}, the @samp{-b} flag tells
+@c <en>@code{rtag} to create a branch (rather than just a
+@c <en>symbolic revision name). Note that the numeric
+@c <en>revision number that matches @samp{rel-1-0} will
+@c <en>probably be different from file to file.
+Assim como no @samp{tag}, a opção @samp{-b} diz ao
+@code{rtag} para criar um ramo (ao invés de
+simplesmente um nome de revisão simbólico). Observe
+que o número de revisão simbólico que casa com
+@samp{rel-1-0} provavelmente ser diferente de arquivo
+para arquivo.
+
+@c <en>So, the full effect of the command is to create a new
+@c <en>branch -- named @samp{rel-1-0-patches} -- in module
+@c <en>@samp{tc}, rooted in the revision tree at the point tagged
+@c <en>by @samp{rel-1-0}.
+Então, O efeito total do comando é criar um novo ramo
+-- chamado @samp{rel-1-0-patches} -- no módulo
+@samp{tc}, partindo da árvore de revisão no ponto
+etiquetado como @samp{rel-1-0}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Accessing branches
+@node Acessando ramos
+@c <en>@section Accessing branches
+@section Acessando ramos
+@c <en>@cindex Check out a branch
+@cindex Check out a branch
+@c <en>@cindex Retrieve a branch
+@cindex Retrieve a branch
+@c <en>@cindex Access a branch
+@cindex Access a branch
+@c <en>@cindex Identifying a branch
+@cindex Identifying a branch
+@c <en>@cindex Branch, check out
+@cindex Branch, check out
+@c <en>@cindex Branch, retrieving
+@cindex Branch, retrieving
+@c <en>@cindex Branch, accessing
+@cindex Branch, accessing
+@c <en>@cindex Branch, identifying
+@cindex Branch, identifying
+
+@c <en>You can retrieve a branch in one of two ways: by
+@c <en>checking it out fresh from the repository, or by
+@c <en>switching an existing working copy over to the branch.
+Você pode recuperar um ramo de duas formas: pegando um
+cópia zerada dele do repositório, ou alternando de uma
+cópia de trabalho já existente para o ramo.
+
+@c <en>To check out a branch from the repository, invoke
+@c <en>@samp{checkout} with the @samp{-r} flag, followed by
+@c <en>the tag name of the branch (@pxref{Creating a branch}):
+Para pegar um ramo do repositório, chame o
+@samp{checkout} com a opção @samp{-r}, seguida pelo
+nome da etiqueta do ramo (@pxref{Criando um ramo}):
+
+@example
+$ cvs checkout -r rel-1-0-patches tc
+@end example
+
+@c <en>Or, if you already have a working copy, you can switch
+@c <en>it to a given branch with @samp{update -r}:
+Ou, se você já tem uma cópia de trabalho, você pode
+alternar dela para um dado ramo com @samp{update -r}:
+
+@example
+$ cvs update -r rel-1-0-patches tc
+@end example
+
+@noindent
+@c <en>or equivalently:
+ou equivalentemente:
+
+@example
+$ cd tc
+$ cvs update -r rel-1-0-patches
+@end example
+
+@c <en>It does not matter if the working copy was originally
+@c <en>on the main trunk or on some other branch -- the above
+@c <en>command will switch it to the named branch. And
+@c <en>similarly to a regular @samp{update} command,
+@c <en>@samp{update -r} merges any changes you have made,
+@c <en>notifying you of conflicts where they occur.
+Não importa se a cópia de tabalho estava originalmente
+no tronco principal ou em algum outro ramo -- o comando
+acima vai alternar ela para o ramo dado. E
+similarmente ao comando @samp{update} normal,
+@samp{update -r} mescla quaisquer mudanças que você
+tenha feito, notificando você sobre conflitos onde eles
+ocorrerem.
+
+@c <en>Once you have a working copy tied to a particular
+@c <en>branch, it remains there until you tell it otherwise.
+@c <en>This means that changes checked in from the working
+@c <en>copy will add new revisions on that branch, while
+@c <en>leaving the main trunk and other branches unaffected.
+Uma vez que você tenha uma cópia de trabalho referente
+a um dado, ela continua no ramo até que se diga o
+contrário. Isto significa que mudanças inseridas a
+partir da cópia de trabalho vão adicionar novas
+revisões naquele ramo, enquanto que não afeta o tronco
+principal nem os outros ramos.
+
+@c <en>@cindex Branches, sticky
+@cindex Ramos, adesivos
+@c <en>To find out what branch a working copy is on, you can
+@c <en>use the @samp{status} command. In its output, look for
+@c <en>the field named @samp{Sticky tag} (@pxref{Sticky tags})
+@c <en>-- that's @sc{cvs}'s way of telling you the branch, if
+@c <en>any, of the current working files:
+Para saber em qual ramo uma cópia de trabalho está,
+você precisa usar o comando @samp{status}. Na saída do
+comando procure pelo campo chamado @samp{Sticky tag}
+(etiqueta adesiva) (@pxref{Etiquetas adesivas})
+-- esta é a forma do @sc{cvs} de dizer a você o ramo,
+se é que se está num, dos arquivos de trabalho atuais:
+
+@example
+$ cvs status -v driver.c backend.c
+===================================================================
+File: driver.c Status: Up-to-date
+
+ Version: 1.7 Sat Dec 5 18:25:54 1992
+ RCS Version: 1.7 /u/cvsroot/yoyodyne/tc/driver.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.7.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-1-0-patches (branch: 1.7.2)
+ rel-1-0 (revision: 1.7)
+
+===================================================================
+File: backend.c Status: Up-to-date
+
+ Version: 1.4 Tue Dec 1 14:39:01 1992
+ RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
+ Sticky Tag: rel-1-0-patches (branch: 1.4.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ rel-1-0-patches (branch: 1.4.2)
+ rel-1-0 (revision: 1.4)
+ rel-0-4 (revision: 1.4)
+
+@end example
+
+@c <en>Don't be confused by the fact that the branch numbers
+@c <en>for each file are different (@samp{1.7.2} and
+@c <en>@samp{1.4.2} respectively). The branch tag is the
+@c <en>same, @samp{rel-1-0-patches}, and the files are
+@c <en>indeed on the same branch. The numbers simply reflect
+@c <en>the point in each file's revision history at which the
+@c <en>branch was made. In the above example, one can deduce
+@c <en>that @samp{driver.c} had been through more changes than
+@c <en>@samp{backend.c} before this branch was created.
+Não se confunda pelo fato de que os números de ramo de
+cada arquivo serem diferentes (@samp{1.7.2} e
+@samp{1.4.2} respectivamente). A etiqueta do ramo é a
+mesma, @samp{rel-1-0-patches}, e os arquivos estão na
+verdade no mesmo ramo. Os números simplesmente
+refletem o ponto em que cada arquivo estava no
+histórico de revisão quando o ramo foi criado. No
+exemplo acima, pode-se deduzir que @samp{driver.c}
+tinha tido mais alterações que @samp{backend.c} antes
+do ramo ter sido criado.
+
+@c <en>See @ref{Branches and revisions} for details about how
+@c <en>branch numbers are constructed.
+Veja em @ref{Ramos e revisões} para detalhes a respeito
+de como números de ramos são criados.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Branches and revisions
+@node Ramos e revisões
+@c <en>@section Branches and revisions
+@section Ramos e revisões
+@c <en>@cindex Branch number
+@cindex Número de ramo
+@c <en>@cindex Number, branch
+@cindex Ramo, número de
+@c <en>@cindex Revision numbers (branches)
+@cindex Números de revisão (ramos)
+
+@c <en>Ordinarily, a file's revision history is a linear
+@c <en>series of increments (@pxref{Revision numbers}):
+Normalmente, um histórico da revisão do arquivo é uma
+séria linear de incrementos (@pxref{Números de
+revisão}):
+
+@example
+ +-----+ +-----+ +-----+ +-----+ +-----+
+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+ +-----+ +-----+ +-----+ +-----+ +-----+
+@end example
+
+@c <en>However, @sc{cvs} is not limited to linear development. The
+@c <en>@dfn{revision tree} can be split into @dfn{branches},
+@c <en>where each branch is a self-maintained line of
+@c <en>development. Changes made on one branch can easily be
+@c <en>moved back to the main trunk.
+Entretanto, o @sc{cvs} não está limitado a
+desenvolvimento linear. A @dfn{árvore de revisões}
+pode ser separada em @dfn{ramos},
+onde cada ramo é uma linha de desenvolvimento que se
+mantém. Mudanças feitas em um ramo podem ser facilmente
+movidas para o tronco principal.
+
+@c <en>Each branch has a @dfn{branch number}, consisting of an
+@c <en>odd number of period-separated decimal integers. The
+@c <en>branch number is created by appending an integer to the
+@c <en>revision number where the corresponding branch forked
+@c <en>off. Having branch numbers allows more than one branch
+@c <en>to be forked off from a certain revision.
+Cada ramo tem um @dfn{número de ramo}, formado por uma
+quantidade ímpar de números inteiros decimais separados
+por ponto. O número do ramo é criado anexando um
+inteiro ao número de revisão de onde o ramo
+correpondente saiu. Com números de ramo é possível se
+ter mais de uma ramificação partindo de uma certa revisão.
+
+@need 3500
+@c <en>All revisions on a branch have revision numbers formed
+@c <en>by appending an ordinal number to the branch number.
+@c <en>The following figure illustrates branching with an
+@c <en>example.
+Todas as revisões num ramo têm números de revisão
+formados pela anexação de um número ordinal ao número
+do ramo. A figura seguinte ilustra a ramificação com um exemplo.
+
+@example
+@c This example used to have a 1.2.2.4 revision, which
+@c might help clarify that development can continue on
+@c 1.2.2. Might be worth reinstating if it can be done
+@c without overfull hboxes.
+@group
+ +-------------+
+ Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 !
+ / +-------------+
+ /
+ /
+ +---------+ +---------+ +---------+
+Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
+ / +---------+ +---------+ +---------+
+ /
+ /
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+ +---------+
+Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 !
+ +---------+ +---------+ +---------+
+
+@end group
+@end example
+
+@c -- However, at least for me the figure is not enough. I suggest more
+@c -- text to accompany it. "A picture is worth a thousand words", so you
+@c -- have to make sure the reader notices the couple of hundred words
+@c -- *you* had in mind more than the others!
+
+@c -- Why an even number of segments? This section implies that this is
+@c -- how the main trunk is distinguished from branch roots, but you never
+@c -- explicitly say that this is the purpose of the [by itself rather
+@c -- surprising] restriction to an even number of segments.
+
+@c <en>The exact details of how the branch number is
+@c <en>constructed is not something you normally need to be
+@c <en>concerned about, but here is how it works: When
+@c <en>@sc{cvs} creates a branch number it picks the first
+@c <en>unused even integer, starting with 2. So when you want
+@c <en>to create a branch from revision 6.4 it will be
+@c <en>numbered 6.4.2. All branch numbers ending in a zero
+@c <en>(such as 6.4.0) are used internally by @sc{cvs}
+@c <en>(@pxref{Magic branch numbers}). The branch 1.1.1 has a
+@c <en>special meaning. @xref{Tracking sources}.
+Os detalhes exatos de como o número de ramo é
+construído não são algo com os quais você precisa estar
+preocupado, mas aqui vai como a coisa funciona: quando
+o @sc{cvs} cria um número de ramo ele pega o primeiro
+número par não usado, a partir de 2. Logo, quando você
+quer criar um ramo a partir da revisão 6.4 ele vai ser
+numerado 6.4.2. Todos os números de ramos terminados
+com um zero (tal como 6.4.0) são usados internamente
+pelo @sc{cvs} (@pxref{Números de ramos mágicos}). O
+ramo 1.1.1 tem um significado especial.
+@xref{Acompanhando fontes}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Magic branch numbers
+@node Números de ramos mágicos
+@c <en>@section Magic branch numbers
+@section Números de ramos mágicos
+
+@c Want xref to here from "log"?
+
+@c <en>This section describes a @sc{cvs} feature called
+@c <en>@dfn{magic branches}. For most purposes, you need not
+@c <en>worry about magic branches; @sc{cvs} handles them for
+@c <en>you. However, they are visible to you in certain
+@c <en>circumstances, so it may be useful to have some idea of
+@c <en>how it works.
+Esta seção descreve uma habilidade do @sc{cvs} chamada
+@dfn{ramos mágicos}. Para a maioria dos casos, você
+não precisa se preocupar com os ramos mágicos; o
+@sc{cvs} cuida deles para você. Entretanto, eles
+aparecem em algumas situações, sendo importante se ter
+alguma idéia de como eles funcionam.
+
+@c <en>Externally, branch numbers consist of an odd number of
+@c <en>dot-separated decimal integers. @xref{Revision
+@c <en>numbers}. That is not the whole truth, however. For
+@c <en>efficiency reasons @sc{cvs} sometimes inserts an extra 0
+@c <en>in the second rightmost position (1.2.4 becomes
+@c <en>1.2.0.4, 8.9.10.11.12 becomes 8.9.10.11.0.12 and so
+@c <en>on).
+Externamente, números de ramos consistem de uma quantidade
+ímpar de inteiros decimais separados por
+ponto. @xref{Números de revisão}. Isto não é toda a
+verdade, entretanto. Por questões de eficiência, o
+@sc{cvs} insere, em alguns momentos, um 0 extra na
+segunda posição da direita para a esquerda (1.2.4 se torna
+1.2.0.4, 8.9.10.11.12 se torna 8.9.10.11.0.12 e assim
+por diante).
+
+@c <en>@sc{cvs} does a pretty good job at hiding these so
+@c <en>called magic branches, but in a few places the hiding
+@c <en>is incomplete:
+O @sc{cvs} faz um bom trabalho escondendo estes tais
+ramos mágicos, mas em alguns lugares alguma coisa aparece:
+
+@itemize @bullet
+@ignore
+@c This is in ignore as I'm taking their word for it,
+@c that this was fixed
+@c a long time ago. But before deleting this
+@c entirely, I'd rather verify it (and add a test
+@c case to the testsuite).
+@item
+@c <en>The magic branch can appear in the output from
+@c <en>@code{cvs status} in vanilla @sc{cvs} 1.3. This is
+@c <en>fixed in @sc{cvs} 1.3-s2.
+The magic branch can appear in the output from
+@code{cvs status} in vanilla @sc{cvs} 1.3. This is
+fixed in @sc{cvs} 1.3-s2.
+
+@end ignore
+@item
+@c <en>The magic branch number appears in the output from
+@c <en>@code{cvs log}.
+O número de ramo mágico aparece na saída do
+@code{cvs log}.
+@c What output should appear instead?
+
+@item
+@c <en>You cannot specify a symbolic branch name to @code{cvs
+@c <en>admin}.
+Você não pode especificar um nome de ramo simbólico
+para o @code{cvs admin}.
+
+@end itemize
+
+@c Can CVS do this automatically the first time
+@c you check something in to that branch? Should
+@c it?
+@c <en>You can use the @code{admin} command to reassign a
+@c <en>symbolic name to a branch the way @sc{rcs} expects it
+@c <en>to be. If @code{R4patches} is assigned to the branch
+@c <en>1.4.2 (magic branch number 1.4.0.2) in file
+@c <en>@file{numbers.c} you can do this:
+Você pode usar o comando @code{admin} para reatribuir
+um nome simbólico para um ramo da forma que o @sc{rcs}
+espera que seja. Se o @code{R4patches} está atribuído
+para o ramo 1.4.2 (número de ramo mágico 1.4.0.2) no
+arquivo @file{numbers.c} você pode fazer isto:
+
+@example
+$ cvs admin -NR4patches:1.4.2 numbers.c
+@end example
+
+@c <en>It only works if at least one revision is already
+@c <en>committed on the branch. Be very careful so that you
+@c <en>do not assign the tag to the wrong number. (There is
+@c <en>no way to see how the tag was assigned yesterday).
+Isto apenas funciona se pelo menos uma revisão já está
+efetivada no ramo. Seja bastante cuidadoso para não
+atribuir a etiqueta ao número errado. (Não existe
+jeito de ver como a etiqueta estava atribuída ontem).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Merging a branch
+@node Mesclando um ramo
+@c <en>@section Merging an entire branch
+@section Mesclando um ramo inteiro
+@c <en>@cindex Merging a branch
+@cindex Mesclando um ramo
+@c <en>@cindex -j (merging branches)
+@cindex -j (mesclando ramos)
+
+@c <en>You can merge changes made on a branch into your working copy by giving
+@c <en>the @samp{-j @var{branchname}} flag to the @code{update} subcommand. With one
+@c <en>@samp{-j @var{branchname}} option it merges the changes made between the
+@c <en>greatest common ancestor (GCA) of the branch and the destination revision (in
+@c <en>the simple case below the GCA is the point where the branch forked) and the
+@c <en>newest revision on that branch into your working copy.
+Você pode mesclar mudanças feitas num ramo em seu
+diretório de trabalho passando a opção @samp{-j
+@var{nome_do_ramo}} para o subcomando @code{update}.
+Com uma opção @samp{-j @var{nome_do_ramo}} ele mescla
+as mudançãs feitas entre o maior ancestral comum
+(greatest common ancestor - GCA) do ramo e a revisão de
+destino (no caso mais simples abaixo, o GCA é o ponto
+onde o ramo bifurcou) e a nova revisão neste ramo na
+sua cópia de trabalho.
+
+@cindex Join
+@c <en>The @samp{-j} stands for ``join''.
+O @samp{-j} significa ``join'', ``juntar''.
+
+@c <en>@cindex Branch merge example
+@cindex Exemplo de mesclagem de ramo
+@c <en>@cindex Example, branch merge
+@cindex Mesclagem de ramo, exemplo
+@c <en>@cindex Merge, branch example
+@cindex Mesclagem, de ramo, exemplo
+@c <en>Consider this revision tree:
+Considere esta árvore de revisão:
+
+@example
++-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+
+ !
+ !
+ ! +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+@end example
+
+@noindent
+@c <en>The branch 1.2.2 has been given the tag (symbolic name) @samp{R1fix}. The
+@c <en>following example assumes that the module @samp{mod} contains only one
+@c <en>file, @file{m.c}.
+O ramo 1.2.2 recebeu a etiqueta (nome simbólico)
+@samp{R1fix}. O exemplo seguinte assume que o módulo
+@samp{mod} contém apenas um arquivo, @file{m.c}.
+
+@example
+$ cvs checkout mod # @r{Retrieve the latest revision, 1.4}
+
+$ cvs update -j R1fix m.c # @r{Merge all changes made on the branch,}
+ # @r{i.e. the changes between revision 1.2}
+ # @r{and 1.2.2.2, into your working copy}
+ # @r{of the file.}
+
+$ cvs commit -m "Included R1fix" # @r{Create revision 1.5.}
+@end example
+
+@c <en>A conflict can result from a merge operation. If that
+@c <en>happens, you should resolve it before committing the
+@c <en>new revision. @xref{Conflicts example}.
+Um conflito pode resultar de uma operação de mesclagem.
+Se isto acontecer, você deve resolver isto antes de
+efetivar a nova revisão. @xref{Exemplo de conflitos}.
+
+@c <en>If your source files contain keywords (@pxref{Keyword substitution}),
+@c <en>you might be getting more conflicts than strictly necessary. See
+@c <en>@ref{Merging and keywords}, for information on how to avoid this.
+Se seu código fonte contém palavras-chave
+(@pxref{Substituição de palavra-chave}), você deve
+obter mais conflitos que os ???strictly necessary???.
+Veja em @ref{Mesclagem e palavras-chave}, para saber
+como evitar isto.
+
+@c <en>The @code{checkout} command also supports the @samp{-j @var{branchname}} flag. The
+@c <en>same effect as above could be achieved with this:
+O comando @code{checkout} também suporta a opção
+@samp{-j @var{branchname}}. O mesmo efeito que o visto
+logo acima pode ser obtido com isto:
+
+@example
+$ cvs checkout -j R1fix mod
+$ cvs commit -m "Included R1fix"
+@end example
+
+@c <en>It should be noted that @code{update -j @var{tagname}} will also work but may
+@c <en>not produce the desired result. @xref{Merging adds and removals}, for more.
+Observe que o @code{update -j @var{tagname}} também vai
+funcionar mas pode não produzir o efeito desejado.
+@xref{Mesclando adicionados e removidos}, para mais informações.
+
+@c <en>@node Merging more than once
+@node Mesclando mais de uma vez
+@c <en>@section Merging from a branch several times
+@section Mesclando a partir de um ramo várias vezes
+
+@c <en>Continuing our example, the revision tree now looks
+@c <en>like this:
+Continuando nosso exemplo, a árvore de revisão agora
+vai parecer com isto:
+
+@example
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
+ +---------+ +---------+
+@end example
+
+@noindent
+@c <en>where the starred line represents the merge from the
+@c <en>@samp{R1fix} branch to the main trunk, as just
+@c <en>discussed.
+Onde a linha de asteriscos representa a mescla entre o
+ramo @samp{R1fix} e o tronco principal, como acabamos
+de ver.
+
+@c <en>Now suppose that development continues on the
+@c <en>@samp{R1fix} branch:
+Agora suponha que o desenvolvimento continua no ramo @samp{R1fix}:
+
+@example
++-----+ +-----+ +-----+ +-----+ +-----+
+! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk
++-----+ +-----+ +-----+ +-----+ +-----+
+ ! *
+ ! *
+ ! +---------+ +---------+ +---------+
+Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
+ +---------+ +---------+ +---------+
+@end example
+
+@noindent
+@c <en>and then you want to merge those new changes onto the
+@c <en>main trunk. If you just use the @code{cvs update -j
+@c <en>R1fix m.c} command again, @sc{cvs} will attempt to
+@c <en>merge again the changes which you have already merged,
+@c <en>which can have undesirable side effects.
+e então você quer mesclar as novas mudanças dentro do
+tronco principal. Se você usar simplesmente o comando
+@code{cvs update -j R1fix m.c} de novo, o @sc{cvs} vai
+tentar mesclar de novo as mudanças que você já mesclou,
+o que pode gerar efeitos indesejados.
+
+@c <en>So instead you need to specify that you only want to
+@c <en>merge the changes on the branch which have not yet been
+@c <en>merged into the trunk. To do that you specify two
+@c <en>@samp{-j} options, and @sc{cvs} merges the changes from
+@c <en>the first revision to the second revision. For
+@c <en>example, in this case the simplest way would be
+Então, ao invés disto, você precisa especificar que você
+quer apenas mesclar no tronco as mudanças que ainda não
+foram mescladas. Para fazer isto você especifica duas
+opções @samp{-j}, e o @sc{cvs} mescla as mudanças da
+primeira revisão na segunda revisão. Por exemplo,
+neste caso a forma mais simples será
+
+@example
+cvs update -j 1.2.2.2 -j R1fix m.c # @r{Merge changes from 1.2.2.2 to the}
+ # @r{head of the R1fix branch}
+@end example
+
+@c <en>The problem with this is that you need to specify the
+@c <en>1.2.2.2 revision manually. A slightly better approach
+@c <en>might be to use the date the last merge was done:
+O problema com isto é que você precisa especificar a
+revisão 1.2.2.2 manualmente. Uma abordagem um pouco
+melhor seria usar a data em que a última mesclagem foi
+feita:
+
+@example
+cvs update -j R1fix:yesterday -j R1fix m.c
+@end example
+
+@c <en>Better yet, tag the R1fix branch after every merge into
+@c <en>the trunk, and then use that tag for subsequent merges:
+Ou ainda melhor, etiquete o ramo R1fix depois de cada
+mesclagem no tronco, e então use a etiqueta para
+mesclagens subseqüentes:
+
+@example
+cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Merging two revisions
+@node Mesclando duas revisões
+@c <en>@section Merging differences between any two revisions
+@section Mesclando diferenças entre duas revisões quaisquer
+@c <en>@cindex Merging two revisions
+@cindex Mesclando duas revisões
+@c <en>@cindex Revisions, merging differences between
+@cindex Revisões, mesclando diferenças entre
+@c <en>@cindex Differences, merging
+@cindex Diferenças, mesclando
+
+@c <en>With two @samp{-j @var{revision}} flags, the @code{update}
+@c <en>(and @code{checkout}) command can merge the differences
+@c <en>between any two revisions into your working file.
+Com duas opções @samp{-j @var{revisão}}, o comando @code{update}
+(e @code{checkout}) pode mesclar as diferenças entre
+quaisquer duas revisões no arquivo do diretório de trabalho.
+
+@c <en>@cindex Undoing a change
+@cindex Desfazendo uma alteração
+@c <en>@cindex Removing a change
+@cindex Removendo uma alteração
+@example
+$ cvs update -j 1.5 -j 1.3 backend.c
+@end example
+
+@noindent
+@c <en>will undo all changes made between revision
+@c <en>1.3 and 1.5. Note the order of the revisions!
+vai desfazer todas as alterações feitas entre as
+revisões 1.3 e 1.5. Observe a ordem das revisões!
+
+@c <en>If you try to use this option when operating on
+@c <en>multiple files, remember that the numeric revisions will
+@c <en>probably be very different between the various files.
+@c <en>You almost always use symbolic
+@c <en>tags rather than revision numbers when operating on
+@c <en>multiple files.
+Se você tentar usar esta opção quando estiver agindo em
+vários arquivos, lembre-se que as revisões numéricas
+provavelmente vão ser bastante diferentes nos vários
+arquivos. Você vai quase sempre usar etiquetas
+simbólicas ao invés de números de revisão quando
+estiver operando em vários arquivos.
+
+@c <en>@cindex Restoring old version of removed file
+@cindex Recuperando uma versão antiga de um arquivo removido
+@c <en>@cindex Resurrecting old version of dead file
+@cindex Ressucitando uma versão antiga de um arquivo morto
+@c <en>Specifying two @samp{-j} options can also undo file
+@c <en>removals or additions. For example, suppose you have
+@c <en>a file
+@c <en>named @file{file1} which existed as revision 1.1, and
+@c <en>you then removed it (thus adding a dead revision 1.2).
+@c <en>Now suppose you want to add it again, with the same
+@c <en>contents it had previously. Here is how to do it:
+Ao especificar duas opções @samp{-j} você pode também
+desfazer uma remoção ou adição de arquivo. Por
+exemplo, suponhao que você tem um arquivo chamado
+@file{file1} que existia numa revisão 1.1, e você
+removeu ele (adicionando então uma revisão morta 1.2).
+Agora suponha que você quer adicioná-lo novamente, com
+o mesmo conteúdo que ele tinha anteriormente. Aqui
+está como fazer isto:
+
+@example
+$ cvs update -j 1.2 -j 1.1 file1
+U file1
+$ cvs commit -m test
+Checking in file1;
+/tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1
+new revision: 1.3; previous revision: 1.2
+done
+$
+@end example
+
+@c <en>@node Merging adds and removals
+@node Mesclando adicionados e removidos
+@c <en>@section Merging can add or remove files
+@section Mesclar pode adicionar ou remover arquivos
+
+@c <en>If the changes which you are merging involve removing
+@c <en>or adding some files, @code{update -j} will reflect
+@c <en>such additions or removals.
+Se as mudanças que você está mesclando envolvem remover
+ou adicionar alguns arquivos, @code{update -j} vai
+resultar em algumas adições ou remoções.
+
+@c FIXME: This example needs a lot more explanation.
+@c We also need other examples for some of the other
+@c cases (not all--there are too many--as long as we present a
+@c coherent general principle).
+@c <en>For example:
+Por exemplo:
+@example
+cvs update -A
+touch a b c
+cvs add a b c ; cvs ci -m "added" a b c
+cvs tag -b branchtag
+cvs update -r branchtag
+touch d ; cvs add d
+rm a ; cvs rm a
+cvs ci -m "added d, removed a"
+cvs update -A
+cvs update -jbranchtag
+@end example
+
+@c <en>After these commands are executed and a @samp{cvs commit} is done,
+@c <en>file @file{a} will be removed and file @file{d} added in the main branch.
+Depois destes comandos terem sido executados e um
+@samp{cvs commit} ser feito, o arquivo @file{a} vai ser
+removido e o arquivo @file{d} adicionado no ramo principal.
+@c (which was determined by trying it)
+
+@c <en>Note that using a single static tag (@samp{-j @var{tagname}})
+@c <en>rather than a dynamic tag (@samp{-j @var{branchname}}) to merge
+@c <en>changes from a branch will usually not remove files which were removed on the
+@c <en>branch since @sc{cvs} does not automatically add static tags to dead revisions.
+@c <en>The exception to this rule occurs when
+@c <en>a static tag has been attached to a dead revision manually. Use the branch tag
+@c <en>to merge all changes from the branch or use two static tags as merge endpoints
+@c <en>to be sure that all intended changes are propagated in the merge.
+Observe que ao se usar uma única etiqueta estática
+(@samp{-j @var{tagname}}) ao invés de uma etiqueta
+dinâmica (@samp{-j @var{branchname}}) para mesclar
+mudanças a partir de um ramo normalmente não vai
+remover arquivos que foram removidos do ramo, já que o
+@sc{cvs} não adiona etiquetas estáticas a revisões
+mortas. A exceção a esta regra ocorre quando uma
+etiqueta estática foi colocada numa revisão morta
+manualmente. Use a etiqueta do ramo para mesclar todas
+as mudanças a partir do ramo ou use duas etiquetas
+estáticas como limites da mescla para ter certeza que
+todas as mudanças pretendidas vão ser propagadas na mesclagem.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Merging and keywords
+@node Mesclagem e palavras-chave
+@c <en>@section Merging and keywords
+@section Mesclagem e palavras-chave
+@c <en>@cindex Merging, and keyword substitution
+@cindex Mesclagem, e substituição de palavra-chave
+@c <en>@cindex Keyword substitution, and merging
+@cindex Substituição de palavra-chave, e mesclagem
+@c <en>@cindex -j (merging branches), and keyword substitution
+@cindex -j (mesclando ramos), e substituição de palavra-chave
+@c <en>@cindex -kk, to avoid conflicts during a merge
+@cindex -kk, para evitar conflitos durante uma mesclagem
+
+@c <en>If you merge files containing keywords (@pxref{Keyword
+@c <en>substitution}), you will normally get numerous
+@c <en>conflicts during the merge, because the keywords are
+@c <en>expanded differently in the revisions which you are
+@c <en>merging.
+Se você mescla arquivos contendo palavras-chave
+(@pxref{Substituição de palavra-chave}), você
+normalmente vai ter muitos conflitos durante a
+mesclagem, já que as palavras-chave são expandidas de
+forma diferente nas revisões que você está mesclando.
+
+@c <en>Therefore, you will often want to specify the
+@c <en>@samp{-kk} (@pxref{Substitution modes}) switch to the
+@c <en>merge command line. By substituting just the name of
+@c <en>the keyword, not the expanded value of that keyword,
+@c <en>this option ensures that the revisions which you are
+@c <en>merging will be the same as each other, and avoid
+@c <en>spurious conflicts.
+Portanto, você vai freqüentemente querer especificar a opção
+@samp{-kk} (@pxref{Modos de substituição}) na linha de
+comando do merge. Simplesmente substituindo o nome da
+palavra-chave, e não o valor expandido dela, vai
+garantir que as revisões que você vai estar mesclando
+???will be the same as each other???, e assim evitar
+conflitos falsos.
+
+@c <en>For example, suppose you have a file like this:
+Por exemplo, suponha que você tenha um arquivo como este:
+
+@example
+ +---------+
+ _! 1.1.2.1 ! <- br1
+ / +---------+
+ /
+ /
++-----+ +-----+
+! 1.1 !----! 1.2 !
++-----+ +-----+
+@end example
+
+@noindent
+@c <en>and your working directory is currently on the trunk
+@c <en>(revision 1.2). Then you might get the following
+@c <en>results from a merge:
+E seu diretório de trabalho está no momento no tronco
+(revisão 1.2). Então pode acontecer de você obter os
+seguintes resultados de uma mescla:
+
+@example
+$ cat file1
+key $@splitrcskeyword{}Revision: 1.2 $
+. . .
+$ cvs update -j br1
+U file1
+RCS file: /cvsroot/first-dir/file1,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+Merging differences between 1.1 and 1.1.2.1 into file1
+rcsmerge: warning: conflicts during merge
+$ cat file1
+@asis{}<<<<<<< file1
+key $@splitrcskeyword{}Revision: 1.2 $
+@asis{}=======
+key $@splitrcskeyword{}Revision: 1.1.2.1 $
+@asis{}>>>>>>> 1.1.2.1
+. . .
+@end example
+
+@c <en>What happened was that the merge tried to merge the
+@c <en>differences between 1.1 and 1.1.2.1 into your working
+@c <en>directory. So, since the keyword changed from
+@c <en>@code{Revision: 1.1} to @code{Revision: 1.1.2.1},
+@c <en>@sc{cvs} tried to merge that change into your working
+@c <en>directory, which conflicted with the fact that your
+@c <en>working directory had contained @code{Revision: 1.2}.
+O que aconteceu é que a mesclagem tentou mesclar as
+diferenças entre 1.1 e 1.1.2.1 dentro de seu diretório
+de trabalho. Então, uma vez que a palavra-chave mudou
+de @code{Revision: 1.1} para @code{Revision: 1.1.2.1},
+o @sc{cvs} tentou mesclar esta mudança no seu diretório
+de trabalho, o que gerou um conflito com o fato de seu
+diretório de trabalho continha @code{Revision: 1.2}.
+
+@c <en>Here is what happens if you had used @samp{-kk}:
+Isto é o que aconteceria se você tivesse usado @samp{-kk}:
+
+@example
+$ cat file1
+key $@splitrcskeyword{}Revision: 1.2 $
+. . .
+$ cvs update -kk -j br1
+U file1
+RCS file: /cvsroot/first-dir/file1,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+Merging differences between 1.1 and 1.1.2.1 into file1
+$ cat file1
+key $@splitrcskeyword{}Revision$
+. . .
+@end example
+
+@c <en>What is going on here is that revision 1.1 and 1.1.2.1
+@c <en>both expand as plain @code{Revision}, and therefore
+@c <en>merging the changes between them into the working
+@c <en>directory need not change anything. Therefore, there
+@c <en>is no conflict.
+O que está acontecendo aqui é que ambas as revisões 1.1
+e 1.1.2.1 expandem em um simples @code{Revision}, e
+consequentemente, não há nenhuma mudança para mesclar entre elas no
+diretório de trabalho. Portanto, não há conflito.
+
+@c <en>@strong{WARNING: In versions of @sc{cvs} prior to 1.12.2, there was a
+@c <en>major problem with using @samp{-kk} on merges. Namely, @samp{-kk}
+@c <en>overrode any default keyword expansion mode set in the archive file in
+@c <en>the repository. This could, unfortunately for some users, cause data
+@c <en>corruption in binary files (with a default keyword expansion mode set
+@c <en>to @samp{-kb}). Therefore, when a repository contained binary files,
+@c <en>conflicts had to be dealt with manually rather than using @samp{-kk} in
+@c <en>a merge command.}
+@strong{WARNING: Em versões do @sc{cvs} anteriores à
+1.12.2, existia um grande problema ao usar @samp{-kk}
+em mesclagens. A saber, @samp{-kk} sobreescrevia
+qualquer modo de expansão de palavra-chave padrão
+ajustado no arquivo do repositório. Isto podia,
+infelizmente para alguns usuários, corromper arquivos
+binários (com um modo de expansão de palavra-chave
+padrão em @samp{-kb}). Portanto, quando um repositório
+contém arquivos binários, conflitos têm que ser
+tratados manualmente ao invés de serem tratados com
+@samp{-kk} no comando de mescla.}
+
+@c <en>In @sc{cvs} version 1.12.2 and later, the keyword expansion mode
+@c <en>provided on the command line to any @sc{cvs} command no longer
+@c <en>overrides the @samp{-kb} keyword expansion mode setting for binary
+@c <en>files, though it will still override other default keyword expansion
+@c <en>modes. You can now safely merge using @samp{-kk} to avoid spurious conflicts
+@c <en>on lines containing RCS keywords, even when your repository contains
+@c <en>binary files.
+Da versão 1.12.2 para frente do @sc{cvs}, a expansão
+por palavra-chave disponível na linha de comando para
+qualquer comando do @sc{cvs} não mais sobreescreve o
+modo de expansão de palavra-chave @samp{-kb} para
+arquivos binários, embora ainda sobreescreva os outros
+modos de expansão de palavra-chave. Você pode agora
+mesclar com tranquilidade usando @samp{-kk} para evitar
+conflitos falsos em linhas contendo palavras-chave do
+RCS, mesmo quando seu repositório contém arquivos binários.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Recursive behavior
+@node Comportamento recursivo
+@c <en>@chapter Recursive behavior
+@chapter Comportamento recursivo
+@c <en>@cindex Recursive (directory descending)
+@cindex Recursivo (directory descending)
+@c <en>@cindex Directory, descending
+@cindex Directory, descending
+@c <en>@cindex Descending directories
+@cindex Descending directories
+@c <en>@cindex Subdirectories
+@cindex Subdiretórios
+
+@c <en>Almost all of the subcommands of @sc{cvs} work
+@c <en>recursively when you specify a directory as an
+@c <en>argument. For instance, consider this directory
+@c <en>structure:
+Quase todos os subcomandos do @sc{cvs} trabalham de
+forma recursiva quando você passa um diretório como
+argumento. Por exemplo, considere esta estrutura:
+
+@example
+ @code{$HOME}
+ |
+ +--@t{tc}
+ | |
+ +--@t{CVS}
+@c <en> | (internal @sc{cvs} files)
+ | (internal @sc{cvs} files)
+ +--@t{Makefile}
+ +--@t{backend.c}
+ +--@t{driver.c}
+ +--@t{frontend.c}
+ +--@t{parser.c}
+ +--@t{man}
+ | |
+ | +--@t{CVS}
+@c <en> | | (internal @sc{cvs} files)
+ | | (internal @sc{cvs} files)
+ | +--@t{tc.1}
+ |
+ +--@t{testing}
+ |
+ +--@t{CVS}
+@c <en> | (internal @sc{cvs} files)
+ | (internal @sc{cvs} files)
+ +--@t{testpgm.t}
+ +--@t{test2.t}
+@end example
+
+@noindent
+@c <en>If @file{tc} is the current working directory, the
+@c <en>following is true:
+Se @file{tc} é o diretório atual, então é verdade que:
+
+@itemize @bullet
+@item
+@c <en>@samp{cvs update testing} is equivalent to
+@samp{cvs update testing} é equivalente a
+
+@example
+cvs update testing/testpgm.t testing/test2.t
+@end example
+
+@item
+@c <en>@samp{cvs update testing man} updates all files in the
+@c <en>subdirectories
+@samp{cvs update testing man} atualiza todos os
+arquivos nos subdiretórios
+
+@item
+@c <en>@samp{cvs update .} or just @samp{cvs update} updates
+@c <en>all files in the @code{tc} directory
+@samp{cvs update .} ou simplesmente @samp{cvs update}
+atualiza todos os arquivos no diretório @code{tc}
+@end itemize
+
+@c <en>If no arguments are given to @code{update} it will
+@c <en>update all files in the current working directory and
+@c <en>all its subdirectories. In other words, @file{.} is a
+@c <en>default argument to @code{update}. This is also true
+@c <en>for most of the @sc{cvs} subcommands, not only the
+@c <en>@code{update} command.
+Se nenhum argumento é dado ao @code{update} ele
+atualiza todos os arquivos no diretório atual e nos
+seus subdiretórios recursivamente. Em outras palavras,
+O @file{.} é um argumento padrão para o @code{update}.
+O mesmo vale para a maioria dos subcomandos do
+@sc{cvs}, e não apenas para o @code{update}.
+
+@c <en>The recursive behavior of the @sc{cvs} subcommands can be
+@c <en>turned off with the @samp{-l} option.
+@c <en>Conversely, the @samp{-R} option can be used to force recursion if
+@c <en>@samp{-l} is specified in @file{~/.cvsrc} (@pxref{~/.cvsrc}).
+O comportamento recursivo dos subcomandos do @sc{cvs}
+pode ser desligado com a opção @samp{-l}. De forma
+oposta, a opção @samp{-R} pode ser usada para forçar a
+recursão se o @samp{-l} estiver especificado no
+@file{~/.cvsrc} (@pxref{~/.cvsrc}).
+
+@example
+$ cvs update -l # @r{Don't update files in subdirectories}
+@end example
+
+@c ---------------------------------------------------------------------
+@c <en>@node Adding and removing
+@node Adicionando e removendo
+@c <en>@chapter Adding, removing, and renaming files and directories
+@chapter Adicionando, removendo e renomeando arquivos e diretórios
+
+@c <en>In the course of a project, one will often add new
+@c <en>files. Likewise with removing or renaming, or with
+@c <en>directories. The general concept to keep in mind in
+@c <en>all these cases is that instead of making an
+@c <en>irreversible change you want @sc{cvs} to record the
+@c <en>fact that a change has taken place, just as with
+@c <en>modifying an existing file. The exact mechanisms to do
+@c <en>this in @sc{cvs} vary depending on the situation.
+No decorrer de um projeto, normalmente se adicionam
+arquivos. Da mesma forma se remove e se renomeia. E
+tudo isto também para diretórios. O conceito geral que
+se deve ter em mente em todos estes casos é que ao
+invés de fazer uma mudança irreversível você vai querer
+que o @sc{cvs} registre o fato de que uma mudança
+ocorreu, da mesma forma que é feito com a modificação
+de um arquivo existente. O mecanismo exato para se
+fazer isto com o @sc{cvs} varia conforme o caso.
+
+@menu
+@c <en>* Adding files:: Adding files
+* Adicionando arquivos:: Adicionando arquivos
+@c <en>* Removing files:: Removing files
+* Removendo arquivos:: Removendo arquivos
+@c <en>* Removing directories:: Removing directories
+* Removendo diretórios:: Removendo diretórios
+@c <en>* Moving files:: Moving and renaming files
+* Movendo arquivos:: Movendo e renomeando arquivos
+@c <en>* Moving directories:: Moving and renaming directories
+* Movendo diretórios:: Movendo e renomeando diretórios
+@end menu
+
+@c <en>@node Adding files
+@node Adicionando arquivos
+@c <en>@section Adding files to a directory
+@section Adicionando arquivos a um diretório
+@c <en>@cindex Adding files
+@cindex Adicionando arquivos
+
+@c <en>To add a new file to a directory, follow these steps.
+Para adicionar um novo arquivo a um diretório, siga
+estes passos.
+
+@itemize @bullet
+@item
+@c <en>You must have a working copy of the directory.
+@c <en>@xref{Getting the source}.
+Você deve ter uma cópia de trabalho do diretório.
+@xref{Obtendo os fontes}.
+
+@item
+@c <en>Create the new file inside your working copy of the directory.
+Crie o novo arquivo dentro da cópia local do diretório.
+
+@item
+@c <en>Use @samp{cvs add @var{filename}} to tell @sc{cvs} that you
+@c <en>want to version control the file. If the file contains
+@c <en>binary data, specify @samp{-kb} (@pxref{Binary files}).
+Use @samp{cvs add @var{filename}} para dizer ao
+@sc{cvs} que você quer fazer controle de versões no
+arquivo. Se o arquivo contém dados em binário,
+especifique @samp{-kb} (@pxref{Arquivos binários}).
+
+@item
+@c <en>Use @samp{cvs commit @var{filename}} to actually check
+@c <en>in the file into the repository. Other developers
+@c <en>cannot see the file until you perform this step.
+Use @samp{cvs commit @var{filename}} para de fato
+colocar o arquivo no repositório. Outros
+desenvolvedores não poderam ver o arquivo até que você
+tenha feito isto.
+@end itemize
+
+@c <en>You can also use the @code{add} command to add a new
+@c <en>directory.
+Você também pode usar o comando @code{add} para
+adicionar um novo diretório.
+@c FIXCVS and/or FIXME: Adding a directory doesn't
+@c require the commit step. This probably can be
+@c considered a CVS bug, but it is possible we should
+@c warn people since this behavior probably won't be
+@c changing right away.
+
+@c <en>Unlike most other commands, the @code{add} command is
+@c <en>not recursive. You cannot even type @samp{cvs add
+@c <en>foo/bar}! Instead, you have to
+Ao contrário da maioria dos outros comandos, o comando
+@code{add} não é recursivo. Você não pode sequer digitar @samp{cvs add
+foo/bar}! Ao invés disso, você tem que fazer
+@c FIXCVS: This is, of course, not a feature. It is
+@c just that no one has gotten around to fixing "cvs add
+@c foo/bar".
+
+@example
+$ cd foo
+$ cvs add bar
+@end example
+
+@c <en>@cindex add (subcommand)
+@cindex add (subcomando)
+@c <en>@deffn Command {cvs add} [@code{-k} kflag] [@code{-m} message] files @dots{}
+@deffn Comando {cvs add} [@code{-k} kflag] [@code{-m} mensagem] arquivos @dots{}
+
+@c <en>Schedule @var{files} to be added to the repository.
+@c <en>The files or directories specified with @code{add} must
+@c <en>already exist in the current directory. To add a whole
+@c <en>new directory hierarchy to the source repository (for
+@c <en>example, files received from a third-party vendor), use
+@c <en>the @code{import} command instead. @xref{import}.
+Agenda @var{arquivos} para serem adicionados ao repositório.
+Os arquivos ou diretórios especificados com @code{add}
+já devem existir no diretório atual. Para adicionar
+toda uma estrutura de diretórios nova ao repositório
+de fontes (por exemplo, arquivos recebidos de um
+fornecedor terceiro), use o comando @code{import} ao
+invés do @code{add}. @xref{import}.
+
+@c <en>The added files are not placed in the source repository
+@c <en>until you use @code{commit} to make the change
+@c <en>permanent. Doing an @code{add} on a file that was
+@c <en>removed with the @code{remove} command will undo the
+@c <en>effect of the @code{remove}, unless a @code{commit}
+@c <en>command intervened. @xref{Removing files}, for an
+@c <en>example.
+Os arquivos adicionados não são colocados no
+repositório de fontes até que você use o @code{commit}
+para tornar a mudança permanente. Aplicar um
+@code{add} num arquivo que foi removido com o comando
+@code{remove} vai desfazer o efeito do @code{remove}, a
+menos que haja um @code{commit} entre os dois.
+@xref{Removendo arquivos}, para um exemplo.
+
+@c <en>The @samp{-k} option specifies the default way that
+@c <en>this file will be checked out; for more information see
+@c <en>@ref{Substitution modes}.
+A opção @samp{-k} especifica a forma padrão como este
+arquivo vai ser ???checked out???; para mais
+informações veja @ref{Modos de substituição}.
+
+@c As noted in BUGS, -m is broken client/server (Nov
+@c 96). Also see testsuite log2-* tests.
+@c <en>The @samp{-m} option specifies a description for the
+@c <en>file. This description appears in the history log (if
+@c <en>it is enabled, @pxref{history file}). It will also be
+@c <en>saved in the version history inside the repository when
+@c <en>the file is committed. The @code{log} command displays
+@c <en>this description. The description can be changed using
+@c <en>@samp{admin -t}. @xref{admin}. If you omit the
+@c <en>@samp{-m @var{description}} flag, an empty string will
+@c <en>be used. You will not be prompted for a description.
+A opção @samp{-m} especifica uma descrição para o
+arquivo. Esta descrição aparece no registro histórico (history log)
+(se este estiver habilitado, @pxref{arquivo history (histórico)}).
+Ela também vai ser guardada no histórico de versões
+dentro do repositório quando o arquivo é
+???committed???. O comando @code{log} mostra esta
+descrição. A descrição pode ser alterada usando-se
+@samp{admin -t}. @xref{admin}. Se você omitir a opção
+@samp{-m @var{description}}, uma string vazia vai ser
+usada. Não vai ser pedido a você uma descrição.
+@end deffn
+
+@c <en>For example, the following commands add the file
+@c <en>@file{backend.c} to the repository:
+Por exemplo, os seguintes comandos adicionam o arquivo
+@file{backend.c} ao repositório:
+
+@c This example used to specify
+@c -m "Optimizer and code generation passes."
+@c to the cvs add command, but that doesn't work
+@c client/server (see log2 in sanity.sh). Should fix CVS,
+@c but also seems strange to document things which
+@c don't work...
+@example
+$ cvs add backend.c
+$ cvs commit -m "Early version. Not yet compilable." backend.c
+@end example
+
+@c <en>When you add a file it is added only on the branch
+@c <en>which you are working on (@pxref{Branching and merging}). You can
+@c <en>later merge the additions to another branch if you want
+@c <en>(@pxref{Merging adds and removals}).
+Quando você adiciona um arquivo ele é adicionado apenas
+no ramo no qual você está trabalhando
+(@pxref{Ramificando e mesclando}). Você pode mais
+tarde mesclar as adições a outro ramo se você quiser
+(@pxref{Mesclando adicionados e removidos}).
+@c Should we mention that earlier versions of CVS
+@c lacked this feature (1.3) or implemented it in a buggy
+@c way (well, 1.8 had many bugs in cvs update -j)?
+@c Should we mention the bug/limitation regarding a
+@c file being a regular file on one branch and a directory
+@c on another?
+@c FIXME: This needs an example, or several, here or
+@c elsewhere, for it to make much sense.
+@c Somewhere we need to discuss the aspects of death
+@c support which don't involve branching, I guess.
+@c Like the ability to re-create a release from a tag.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Removing files
+@node Removendo arquivos
+@c <en>@section Removing files
+@section Removendo arquivos
+@c <en>@cindex Removing files
+@cindex Removendo arquivos
+@c <en>@cindex Deleting files
+@cindex Apagando arquivos
+
+@c FIXME: this node wants to be split into several
+@c smaller nodes. Could make these children of
+@c "Adding and removing", probably (death support could
+@c be its own section, for example, as could the
+@c various bits about undoing mistakes in adding and
+@c removing).
+@c <en>Directories change. New files are added, and old files
+@c <en>disappear. Still, you want to be able to retrieve an
+@c <en>exact copy of old releases.
+Diretórios mudam. Novos arquivos são adicionados, e
+arquivos velhos somem. Ainda assim, você vai querer
+poder recuperar uma cópia exata de releases antigas.
+
+@c <en>Here is what you can do to remove a file,
+@c <en>but remain able to retrieve old revisions:
+Aqui está o que você pode fazer para remover um
+arquivo, mas continuar sendo capaz de recuperar
+revisões antigas dele:
+
+@itemize @bullet
+@c FIXME: should probably be saying something about
+@c having a working directory in the first place.
+@item
+@c <en>Make sure that you have not made any uncommitted
+@c <en>modifications to the file. @xref{Viewing differences},
+@c <en>for one way to do that. You can also use the
+@c <en>@code{status} or @code{update} command. If you remove
+@c <en>the file without committing your changes, you will of
+@c <en>course not be able to retrieve the file as it was
+@c <en>immediately before you deleted it.
+Certifique-se de não ter feito nenhuma alteração que
+falte fazer ???commit??? nele. @xref{Vendo as diferenças},
+para uma forma de fazer isto. Você também pode usar o comando
+@code{status} ou o @code{update}. Se você remove o
+arquivo sem fazer ???commit??? nas suas mudanças,
+obviamente você não vai ser capaz de recuperar o
+arquivo na forma como ele era imediatamente antes da remoção.
+
+@item
+@c <en>Remove the file from your working copy of the directory.
+@c <en>You can for instance use @code{rm}.
+Remova o arquivo da cópia local do seu diretório.
+Você pode usar o @code{rm}, por exemplo.
+
+@item
+@c <en>Use @samp{cvs remove @var{filename}} to tell @sc{cvs} that
+@c <en>you really want to delete the file.
+Use @samp{cvs remove @var{filename}} para dizer ao
+@sc{cvs} que você quer realmente apagar o arquivo.
+
+@item
+@c <en>Use @samp{cvs commit @var{filename}} to actually
+@c <en>perform the removal of the file from the repository.
+Use @samp{cvs commit @var{filename}} para realizar a
+remoção de fato do arquivo do repositório.
+@end itemize
+
+@c FIXME: Somehow this should be linked in with a more
+@c general discussion of death support. I don't know
+@c whether we want to use the term "death support" or
+@c not (we can perhaps get by without it), but we do
+@c need to discuss the "dead" state in "cvs log" and
+@c related subjects. The current discussion is
+@c scattered around, and not xref'd to each other.
+@c FIXME: I think this paragraph wants to be moved
+@c later down, at least after the first example.
+@c <en>When you commit the removal of the file, @sc{cvs}
+@c <en>records the fact that the file no longer exists. It is
+@c <en>possible for a file to exist on only some branches and
+@c <en>not on others, or to re-add another file with the same
+@c <en>name later. @sc{cvs} will correctly create or not create
+@c <en>the file, based on the @samp{-r} and @samp{-D} options
+@c <en>specified to @code{checkout} or @code{update}.
+Quando você faz ???commit??? na remoção do arquivo, o
+@sc{cvs} registra o fato de que o arquivo não existe
+mais. É possível para um arquivo existir apenas em
+alguns ramos e não em outros, ou re-adicionar outro
+arquivo com o mesmo nome depois. O @sc{cvs} vai de
+forma correta criar ou não criar o arquivo, baseado nas
+opões @samp{-r} e @samp{-D} especificadas no
+@code{checkout} ou no @code{update}.
+
+@c FIXME: This style seems to clash with how we
+@c document things in general.
+@c <en>@cindex Remove (subcommand)
+@cindex Remove (subcomando)
+@c <en>@deffn Command {cvs remove} [options] files @dots{}
+@deffn Comando {cvs remove} [options] files @dots{}
+
+@c <en>Schedule file(s) to be removed from the repository
+@c <en>(files which have not already been removed from the
+@c <en>working directory are not processed). This command
+@c <en>does not actually remove the file from the repository
+@c <en>until you commit the removal. For a full list of
+@c <en>options, see @ref{Invoking CVS}.
+Prepara arquivo(s) para ser removido do reporitório
+(arquivos que ainda não foram removidos do diretório de
+trabalho não são processados). Na verdade este comando
+não remove o arquivo do repositório até que você faça
+???commit??? no removido. Para uma lista completa de
+opções, veja em @ref{Chamando o CVS}.
+@end deffn
+
+@c <en>Here is an example of removing several files:
+Aqui está um exemplo de remoção de vários arquivos:
+
+@example
+$ cd test
+$ rm *.c
+$ cvs remove
+cvs remove: Removing .
+cvs remove: scheduling a.c for removal
+cvs remove: scheduling b.c for removal
+cvs remove: use 'cvs commit' to remove these files permanently
+$ cvs ci -m "Removed unneeded files"
+cvs commit: Examining .
+cvs commit: Committing .
+@end example
+
+@c <en>As a convenience you can remove the file and @code{cvs
+@c <en>remove} it in one step, by specifying the @samp{-f}
+@c <en>option. For example, the above example could also be
+@c <en>done like this:
+Por conveniência você pode remover o arquivo e fazer @code{cvs
+remove} nele de uma só vez, especificando a opção
+@samp{-f}. Por exemplo, o exemplo acima poderia ser
+feito assim:
+
+@example
+$ cd test
+$ cvs remove -f *.c
+cvs remove: scheduling a.c for removal
+cvs remove: scheduling b.c for removal
+cvs remove: use 'cvs commit' to remove these files permanently
+$ cvs ci -m "Removed unneeded files"
+cvs commit: Examining .
+cvs commit: Committing .
+@end example
+
+@c <en>If you execute @code{remove} for a file, and then
+@c <en>change your mind before you commit, you can undo the
+@c <en>@code{remove} with an @code{add} command.
+Se você executa @code{remove} para um arquivo, e então
+muda de idéia antes do ???commit???, você pode desfazer
+o @code{remove} com um @code{add}.
+@ignore
+@c is this worth saying or not? Somehow it seems
+@c confusing to me.
+@c <en>Of course,
+@c <en>since you have removed your copy of file in the working
+@c <en>directory, @sc{cvs} does not necessarily bring back the
+@c <en>contents of the file from right before you executed
+@c <en>@code{remove}; instead it gets the file from the
+@c <en>repository again.
+Obviamente, uma vez que você removeu a sua cópia local
+do arquivo no diretório de trabalho, o @sc{cvs} não vai
+trazer de volta necessariamente o conteúdo do arquivo
+exatamente como estava antes do @code{remove}; No lugar
+disto ele vai buscar o arquivo no repositório de novo.
+@end ignore
+
+@c FIXME: what if you change your mind after you commit
+@c it? (answer is also "cvs add" but we don't say that...).
+@c We need some index entries for thinks like "undoing
+@c removal" too.
+
+@example
+$ ls
+CVS ja.h oj.c
+$ rm oj.c
+$ cvs remove oj.c
+cvs remove: scheduling oj.c for removal
+cvs remove: use 'cvs commit' to remove this file permanently
+$ cvs add oj.c
+U oj.c
+cvs add: oj.c, version 1.1.1.1, resurrected
+@end example
+
+@c <en>If you realize your mistake before you run the
+@c <en>@code{remove} command you can use @code{update} to
+@c <en>resurrect the file:
+Se você notar o erro antes de rodar o comando
+@code{remove} você pode usar o @code{update} para
+resuscitar o arquivo:
+
+@example
+$ rm oj.c
+$ cvs update oj.c
+cvs update: warning: oj.c was lost
+U oj.c
+@end example
+
+@c <en>When you remove a file it is removed only on the branch
+@c <en>which you are working on (@pxref{Branching and merging}). You can
+@c <en>later merge the removals to another branch if you want
+@c <en>(@pxref{Merging adds and removals}).
+Quando você remove um arquivo ele é removido apenas do
+ramo no qual você está trabalhando (@pxref{Ramificando
+e mesclando}). Você pode depois mesclar as remoções em
+outro ramo se quiser
+(@pxref{Mesclando adicionados e removidos}).
+
+@c <en>@node Removing directories
+@node Removendo diretórios
+@c <en>@section Removing directories
+@section Removendo diretórios
+@c <en>@cindex Removing directories
+@cindex Removendo diretórios
+@c <en>@cindex Directories, removing
+@cindex Diretórios, removendo
+
+@c <en>In concept removing directories is somewhat similar to
+@c <en>removing files---you want the directory to not exist in
+@c <en>your current working directories, but you also want to
+@c <en>be able to retrieve old releases in which the directory
+@c <en>existed.
+Conceitualmente, remover diretórios é num certo sentido
+similar a remover arquivos---você quer que o diretório
+não exista mais no seu diretório de trabalho atual,
+mas você também quer ser capaz de recuperar releases
+antigas nas quais o diretório existe.
+
+@c <en>The way that you remove a directory is to remove all
+@c <en>the files in it. You don't remove the directory
+@c <en>itself; there is no way to do that.
+@c <en>Instead you specify the @samp{-P} option to
+@c <en>@code{cvs update} or @code{cvs checkout},
+@c <en>which will cause @sc{cvs} to remove empty
+@c <en>directories from working directories.
+@c <en>(Note that @code{cvs export} always removes empty directories.)
+@c <en>Probably the
+@c <en>best way to do this is to always specify @samp{-P}; if
+@c <en>you want an empty directory then put a dummy file (for
+@c <en>example @file{.keepme}) in it to prevent @samp{-P} from
+@c <en>removing it.
+A forma de remover um diretório é removendo todos os
+arquivos nele. Você não remove o diretório mesmo; não
+há jeito de fazer isto. Ao invés disto você especifica
+a opção @samp{-P} no @code{cvs update} ou no @code{cvs
+checkout}, que vai fazer com que o @sc{cvs} remova
+diretórios vazios de seus diretórios de
+trabalho. (Observe que o @code{cvs export} sempre
+remove diretórios vazios.) Provavelmente, a melhor
+maneira de fazer isto é sempre usar o @samp{-P}; se
+você quiser manter um diretório vazio, ponha um arquivo
+sem importância nele (por exemplo @file{.keepme}) para
+evitar que o @samp{-P} apague o diretório.
+
+@c I'd try to give a rationale for this, but I'm not
+@c sure there is a particularly convincing one. What
+@c we would _like_ is for CVS to do a better job of version
+@c controlling whether directories exist, to eliminate the
+@c need for -P and so that a file can be a directory in
+@c one revision and a regular file in another.
+@c <en>Note that @samp{-P} is implied by the @samp{-r} or @samp{-D}
+@c <en>options of @code{checkout}. This way
+@c <en>@sc{cvs} will be able to correctly create the directory
+@c <en>or not depending on whether the particular version you
+@c <en>are checking out contains any files in that directory.
+Observe que o @samp{-P} está implícito nas opções
+@samp{-r} ou @samp{-D} do @code{checkout}. Desta forma
+o @sc{cvs} vai ser capaz de criar ou não criar corretamente o
+diretório dependendo de ter ou não algum arquivo na
+versão que você está fazendo ???check out???.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Moving files
+@node Movendo arquivos
+@c <en>@section Moving and renaming files
+@section Movendo e renomeando arquivos
+@c <en>@cindex Moving files
+@cindex Movendo arquivos
+@c <en>@cindex Renaming files
+@cindex Renomeando arquivos
+@c <en>@cindex Files, moving
+@cindex Arquivos, movendo
+
+@c <en>Moving files to a different directory or renaming them
+@c <en>is not difficult, but some of the ways in which this
+@c <en>works may be non-obvious. (Moving or renaming a
+@c <en>directory is even harder. @xref{Moving directories}.).
+Mover arquivos para um diretório diferente ou
+renomeá-los não é difícil, mas algumas das formas de
+faze-lo podem não ser óbvias. (Mover ou renomear
+diretórios é ainda mais difícil. @xref{Movendo
+diretórios}.).
+
+@c <en>The examples below assume that the file @var{old} is renamed to
+@c <en>@var{new}.
+O exemplos abaixo assumem que o arquivo @var{antigo} foi
+renomeado para @var{novo}.
+
+@menu
+@c <en>* Outside:: The normal way to Rename
+* Outside:: A forma normal de renomear
+@c <en>* Inside:: A tricky, alternative way
+* Inside:: Uma forma ???tricky???, alternativa
+@c <en>* Rename by copying:: Another tricky, alternative way
+* Renomeando na base da cópia:: Outra forma ???tricky???, alternativa
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Outside
+@node Outside
+@c <en>@subsection The Normal way to Rename
+@subsection A forma normal de renomear
+
+@c More rename issues. Not sure whether these are
+@c worth documenting; I'm putting them here because
+@c it seems to be as good a place as any to try to
+@c set down the issues.
+@c * "cvs annotate" will annotate either the new
+@c file or the old file; it cannot annotate _each
+@c line_ based on whether it was last changed in the
+@c new or old file. Unlike "cvs log", where the
+@c consequences of having to select either the new
+@c or old name seem fairly benign, this may be a
+@c real advantage to having CVS know about renames
+@c other than as a deletion and an addition.
+
+@c <en>The normal way to move a file is to copy @var{old} to
+@c <en>@var{new}, and then issue the normal @sc{cvs} commands
+@c <en>to remove @var{old} from the repository, and add
+@c <en>@var{new} to it.
+A forma normal de mover um arquivo é copiar
+@var{antigo} para @var{novo}, e então aplicar os
+comandos normais do @sc{cvs} para, no repositório,
+remover @var{antigo} e adicionar @var{novo}.
+@c The following sentence is not true: one must cd into
+@c the directory to run "cvs add".
+@c (Both @var{old} and @var{new} could
+@c contain relative paths, for example @file{foo/bar.c}).
+
+@example
+$ mv @var{old} @var{new}
+$ cvs remove @var{old}
+$ cvs add @var{new}
+$ cvs commit -m "Renamed @var{old} to @var{new}" @var{old} @var{new}
+@end example
+
+@c <en>This is the simplest way to move a file, it is not
+@c <en>error-prone, and it preserves the history of what was
+@c <en>done. Note that to access the history of the file you
+@c <en>must specify the old or the new name, depending on what
+@c <en>portion of the history you are accessing. For example,
+@c <en>@code{cvs log @var{old}} will give the log up until the
+@c <en>time of the rename.
+Esta é a forma mais simples de mover um arquivo, não é
+anti-falhas, e vai preservar o histórico do que foi
+feito. Observe que para acessar o histórico do arquivo
+você vai precisar especificar o nome antigo ou o novo,
+dependendo de que porção do histórico você vai estar
+acessando. Por exemplo, @code{cvs log @var{antigo}}
+vai mostrar o registro (log) até o momento onde o
+arquivo foi renomeado.
+
+@c <en>When @var{new} is committed its revision numbers will
+@c <en>start again, usually at 1.1, so if that bothers you,
+@c <en>use the @samp{-r rev} option to commit. For more
+@c <en>information see @ref{Assigning revisions}.
+Quando @var{novo} é ???committed??? seus números de
+revisão vão recomeçar, normalmente em 1.1. Portanto, se
+isto te incomoda, lembre de usar a opção @samp{-r rev}
+na hora do ???commit???. Para mais informações veja em
+@ref{Atribuindo revisões}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Inside
+@node Inside
+@c <en>@subsection Moving the history file
+@subsection Movendo o arquivo com o histórico
+
+@c <en>This method is more dangerous, since it involves moving
+@c <en>files inside the repository. Read this entire section
+@c <en>before trying it out!
+Este método é mais perigoso, já que envolve
+movimentação de arquivos no repositório. Leia a seção
+toda antes de sair tentando!
+
+@example
+$ cd $CVSROOT/@var{dir}
+$ mv @var{old},v @var{new},v
+@end example
+
+@noindent
+@c <en>Advantages:
+Vantagens:
+
+@itemize @bullet
+@item
+@c <en>The log of changes is maintained intact.
+O registro (log) de alterações permanece intacto.
+
+@item
+@c <en>The revision numbers are not affected.
+Os números de revisão não são alterados.
+@end itemize
+
+@noindent
+@c <en>Disadvantages:
+Desvantagens:
+
+@itemize @bullet
+@item
+@c <en>Old releases cannot easily be fetched from the
+@c <en>repository. (The file will show up as @var{new} even
+@c <en>in revisions from the time before it was renamed).
+Releases antigas não serão mais facilmente recuperadas
+a partir do repositório. (O arquivo vai aparecer como
+@var{novo} mesmo em revisões do tempo anterior a ter
+sido renomeado).
+
+@item
+@c <en>There is no log information of when the file was renamed.
+Não há informação nos registros de quando o arquivo foi
+renomeado.
+
+@item
+@c <en>Nasty things might happen if someone accesses the history file
+@c <en>while you are moving it. Make sure no one else runs any of the @sc{cvs}
+@c <en>commands while you move it.
+Coisas ???Nasty??? podem acontecer se alguém acessar o
+arquivo de histórico enquanto você estier movendo ele.
+Certifique-se de que ninguém mais rode qualquer dos
+comandos do @sc{cvs} durante a movimentação.
+@end itemize
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Rename by copying
+@node Renomeando na base da cópia
+@c <en>@subsection Copying the history file
+@subsection Copiando o arquivo de histórico
+
+@c <en>This way also involves direct modifications to the
+@c <en>repository. It is safe, but not without drawbacks.
+Esta forma também envolve modificações diretas no
+repositório. É segura, mas tem seus incovenientes.
+
+@example
+# @r{Copy the @sc{rcs} file inside the repository}
+$ cd $CVSROOT/@var{dir}
+$ cp @var{old},v @var{new},v
+# @r{Remove the old file}
+$ cd ~/@var{dir}
+$ rm @var{old}
+$ cvs remove @var{old}
+$ cvs commit @var{old}
+# @r{Remove all tags from @var{new}}
+$ cvs update @var{new}
+$ cvs log @var{new} # @r{Remember the non-branch tag names}
+$ cvs tag -d @var{tag1} @var{new}
+$ cvs tag -d @var{tag2} @var{new}
+@dots{}
+@end example
+
+@c <en>By removing the tags you will be able to check out old
+@c <en>revisions.
+Ao remover as etiquetas você vai ser capaz de ???check
+out??? revisões antigas.
+
+@noindent
+@c <en>Advantages:
+Vantagens:
+
+@itemize @bullet
+@item
+@c FIXME: Is this true about -D now that we have death
+@c support? See 5B.3 in the FAQ.
+@c <en>Checking out old revisions works correctly, as long as
+@c <en>you use @samp{-r@var{tag}} and not @samp{-D@var{date}}
+@c <en>to retrieve the revisions.
+O ???check out??? de revisões antigas funciona corretamente,
+???as long as??? você usa @samp{-r@var{tag}} e não
+@samp{-D@var{date}} para recuperar as revisões.
+
+@item
+@c <en>The log of changes is maintained intact.
+O registro (log) de mudanças é mantido intacto.
+
+@item
+@c <en>The revision numbers are not affected.
+Os números de revisão não são afetados.
+@end itemize
+
+@noindent
+@c <en>Disadvantages:
+Desvantagens:
+
+@itemize @bullet
+@item
+@c <en>You cannot easily see the history of the file across the rename.
+Você não pode ver de forma fácil os histórico do
+arquivo através das ações de renomear.
+
+@ignore
+@c Is this true? I don't see how the revision numbers
+@c _could_ start over, when new,v is just old,v with
+@c the tags deleted.
+@c If there is some need to reinstate this text,
+@c it is "usually 1.1", not "1.0" and it needs an
+@c xref to Assigning revisions
+@item
+@c <en>Unless you use the @samp{-r rev} (@pxref{commit
+@c <en>options}) flag when @var{new} is committed its revision
+@c <en>numbers will start at 1.0 again.
+A menos que você use a opção @samp{-r rev} (@pxref{commit
+options}) quando o @var{new} for ???committed??? seus
+números de revisão vão sempre recomeçar com 1.0.
+@end ignore
+@end itemize
+
+@c ---------------------------------------------------------------------
+@c <en>@node Moving directories
+@node Movendo diretórios
+@c <en>@section Moving and renaming directories
+@section Movendo e renomeando diretórios
+@c <en>@cindex Moving directories
+@cindex Movendo diretórios
+@c <en>@cindex Renaming directories
+@cindex Renomeando diretórios
+@c <en>@cindex Directories, moving
+@cindex Diretórios, movendo
+
+@c <en>The normal way to rename or move a directory is to
+@c <en>rename or move each file within it as described in
+@c <en>@ref{Outside}. Then check out with the @samp{-P}
+@c <en>option, as described in @ref{Removing directories}.
+A forma normal de renomear ou mover um diretório é
+renomear ou mover cada arquivo dentro dele como
+descrito em @ref{Outside}. Então fazer um ???check
+out??? com a opção @samp{-P}, como descrito em
+@ref{Removendo diretórios}.
+
+@c <en>If you really want to hack the repository to rename or
+@c <en>delete a directory in the repository, you can do it
+@c <en>like this:
+Se você realmente quer ???to hack??? o repositório para
+renomear ou apagar um diretório no repositório, você
+pode fazê-lo da seguinte forma:
+
+@enumerate
+@item
+@c <en>Inform everyone who has a checked out copy of the directory that the
+@c <en>directory will be renamed. They should commit all
+@c <en>their changes, and remove their working copies,
+@c <en>before you take the steps below.
+Avise a todos que fizeram checkout do diretório que o
+diretório vai ser renomeado. Eles vão ter que fazer
+???commit??? de todas as mudanças, e remover suas
+cópias de trabalho antes que você faça os passos
+seguintes.
+
+@item
+@c <en>Rename the directory inside the repository.
+Renomeie o diretório dentro do repositório.
+
+@example
+$ cd $CVSROOT/@var{parent-dir}
+$ mv @var{old-dir} @var{new-dir}
+@end example
+
+@item
+@c <en>Fix the @sc{cvs} administrative files, if necessary (for
+@c <en>instance if you renamed an entire module).
+Conserte os arquivos administrativos do @sc{cvs}, se
+necessário (por exemplo, se você está renomeando um
+módulo inteiro).
+
+@item
+@c <en>Tell everyone that they can check out again and continue
+@c <en>working.
+Diga a todo mundo que eles podem fazer check out
+novamente e continuar o trabalho.
+
+@end enumerate
+
+@c <en>If someone had a working copy the @sc{cvs} commands will
+@c <en>cease to work for him, until he removes the directory
+@c <en>that disappeared inside the repository.
+Se alguém manteve uma cópia de trabalho, os comandos do
+@sc{cvs} vão parar de funcionar para esta pessoa até
+que ela remova o diretório que desapareceu do repositório.
+
+@c <en>It is almost always better to move the files in the
+@c <en>directory instead of moving the directory. If you move the
+@c <en>directory you are unlikely to be able to retrieve old
+@c <en>releases correctly, since they probably depend on the
+@c <en>name of the directories.
+Na maioria das vezes é melhor mover os arquivos do
+diretório ao invés de mover o diretório. Se você mover
+o diretório não há garantias de que você seja capaz de
+recuperar releases antigas corretamente, já que elas
+dependem provavelmente do nome dos diretórios.
+
+@c ---------------------------------------------------------------------
+@c <en>@node History browsing
+@node Navegação no Histórico
+@c <en>@chapter History browsing
+@chapter Navegação no Histórico
+@c <en>@cindex History browsing
+@cindex Navegação no Histórico
+@c <en>@cindex Traceability
+@cindex Rastreabilidade
+@c <en>@cindex Isolation
+@cindex Isolamento
+
+@ignore
+@c This is too long for an introduction (goal is
+@c one 20x80 character screen), and also mixes up a
+@c variety of issues (parallel development, history,
+@c maybe even touches on process control).
+
+@c -- @quote{To lose ones history is to lose ones soul.}
+@c -- ///
+@c -- ///Those who cannot remember the past are condemned to repeat it.
+@c -- /// -- George Santayana
+@c -- ///
+
+@c <en>@sc{cvs} tries to make it easy for a group of people to work
+@c <en>together. This is done in two ways:
+O @sc{cvs} tenta ajudar um grupo a trabalhar junto.
+Isto é feito de duas formas:
+
+@itemize @bullet
+@item
+@c <en>Isolation---You have your own working copy of the
+@c <en>source. You are not affected by modifications made by
+@c <en>others until you decide to incorporate those changes
+@c <en>(via the @code{update} command---@pxref{update}).
+Isolamento---Você tem a sua própria cópia de trabalho
+dos fontes. Você não é afetado por modificações feitas
+por outros até que você decida incorporar estas
+modificações (através do comando
+@code{update}---@pxref{update}).
+
+@item
+@c <en>Traceability---When something has changed, you can
+@c <en>always see @emph{exactly} what changed.
+Rastreabilidade---Quando alguma coisa mudou, você pode
+ver @emph{exatamente} o que mudou.
+@end itemize
+
+@c <en>There are several features of @sc{cvs} that together lead
+@c <en>to traceability:
+Existem várias características do @sc{cvs} que juntas
+possibilitam a rastreabilidade:
+
+@itemize @bullet
+@item
+@c <en>Each revision of a file has an accompanying log
+@c <en>message.
+Each revision of a file has an accompanying log
+message.
+
+@item
+@c <en>All commits are optionally logged to a central history
+@c <en>database.
+All commits are optionally logged to a central history
+database.
+
+@item
+@c <en>Logging information can be sent to a user-defined
+@c <en>program (@pxref{loginfo}).
+Logging information can be sent to a user-defined
+program (@pxref{loginfo}).
+@end itemize
+
+@c -- More text here.
+
+@c <en>This chapter should talk about the history file, the
+@c <en>@code{log} command, the usefulness of ChangeLogs
+@c <en>even when you run @sc{cvs}, and things like that.
+This chapter should talk about the history file, the
+@code{log} command, the usefulness of ChangeLogs
+even when you run @sc{cvs}, and things like that.
+
+@end ignore
+
+@c kind of lame, in a lot of ways the above text inside
+@c the @ignore motivates this chapter better
+@c <en>Once you have used @sc{cvs} to store a version control
+@c <en>history---what files have changed when, how, and by
+@c <en>whom, there are a variety of mechanisms for looking
+@c <en>through the history.
+Uma vez usando o @sc{cvs} para guardar um histórico do
+controle de versões---que arquivos foram mudandos,
+quando, como e por quem, existe uma variedade de
+mecanismos para procurar ao longo do histórico.
+
+@c FIXME: should also be talking about how you look at
+@c old revisions (e.g. "cvs update -p -r 1.2 foo.c").
+@menu
+@c <en>* log messages:: Log messages
+* mensagens de registro:: Mensagens de registro (log)
+@c <en>* history database:: The history database
+* history database:: The history database
+@c <en>* user-defined logging:: User-defined logging
+* user-defined logging:: User-defined logging
+@c <en>* annotate:: What revision modified each line of a file?
+* annotate:: Que revisão modificou cada linha de um arquivo?
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node log messages
+@node mensagens de registro
+@c <en>@section Log messages
+@section Mensagens de registro (log)
+
+@c FIXME: @xref to place where we talk about how to
+@c specify message to commit.
+@c <en>Whenever you commit a file you specify a log message.
+Sempre que você ???commit??? um arquivo você especifica
+uma mensagem de registro (log).
+
+@c FIXME: bring the information here, and get rid of or
+@c greatly shrink the "log" node.
+@c <en>To look through the log messages which have been
+@c <en>specified for every revision which has been committed,
+@c <en>use the @code{cvs log} command (@pxref{log}).
+Para ver todas as mensagens de registro que foram
+especificadas para cada revisão que foi
+???committed???, use o comando @code{cvs log}
+(@pxref{log}).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node history database
+@node history database
+@c <en>@section The history database
+@section The history database
+
+@c FIXME: bring the information from the history file
+@c and history nodes here. Rewrite it to be motivated
+@c better (start out by clearly explaining what gets
+@c logged in history, for example).
+@c <en>You can use the history file (@pxref{history file}) to
+@c <en>log various @sc{cvs} actions. To retrieve the
+@c <en>information from the history file, use the @code{cvs
+@c <en>history} command (@pxref{history}).
+Você pode usar o arquivo history (@pxref{arquivo
+history (histórico)}) para registrar várias ações do @sc{cvs}.
+Para recuperar a informação do arquivo history, use o
+comando @code{cvs history} (@pxref{history}).
+
+@c <en>Note: you can control what is logged to this file by using the
+@c <en>@samp{LogHistory} keyword in the @file{CVSROOT/config} file
+@c <en>(@pxref{config}).
+Observação: você pode controlar o que vai ser
+registrado neste arquivo usando a palavra-chave
+@samp{LogHistory} no arquivo @file{CVSROOT/config}
+(@pxref{config}).
+
+@c
+@c The history database has many problems:
+@c * It is very unclear what field means what. This
+@c could be improved greatly by better documentation,
+@c but there are still non-orthogonalities (for
+@c example, tag does not record the "repository"
+@c field but most records do).
+@c * Confusion about files, directories, and modules.
+@c Some commands record one, some record others.
+@c * File removal is not logged. There is an 'R'
+@c record type documented, but CVS never uses it.
+@c * Tags are only logged for the "cvs rtag" command,
+@c not "cvs tag". The fix for this is not completely
+@c clear (see above about modules vs. files).
+@c * Are there other cases of operations that are not
+@c logged? One would hope for all changes to the
+@c repository to be logged somehow (particularly
+@c operations like tagging, "cvs admin -k", and other
+@c operations which do not record a history that one
+@c can get with "cvs log"). Operations on the working
+@c directory, like export, get, and release, are a
+@c second category also covered by the current "cvs
+@c history".
+@c * The history file does not record the options given
+@c to a command. The most serious manifestation of
+@c this is perhaps that it doesn't record whether a command
+@c was recursive. It is not clear to me whether one
+@c wants to log at a level very close to the command
+@c line, as a sort of way of logging each command
+@c (more or less), or whether one wants
+@c to log more at the level of what was changed (or
+@c something in between), but either way the current
+@c information has pretty big gaps.
+@c * Further details about a tag--like whether it is a
+@c branch tag or, if a non-branch tag, which branch it
+@c is on. One can find out this information about the
+@c tag as it exists _now_, but if the tag has been
+@c moved, one doesn't know what it was like at the time
+@c the history record was written.
+@c * Whether operating on a particular tag, date, or
+@c options was implicit (sticky) or explicit.
+@c
+@c Another item, only somewhat related to the above, is a
+@c way to control what is logged in the history file.
+@c This is probably the only good way to handle
+@c different people having different ideas about
+@c information/space tradeoffs.
+@c
+@c It isn't really clear that it makes sense to try to
+@c patch up the history file format as it exists now to
+@c include all that stuff. It might be better to
+@c design a whole new CVSROOT/nhistory file and "cvs
+@c nhistory" command, or some such, or in some other
+@c way trying to come up with a clean break from the
+@c past, which can address the above concerns. Another
+@c open question is how/whether this relates to
+@c taginfo/loginfo/etc.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node user-defined logging
+@node user-defined logging
+@c <en>@section User-defined logging
+@section User-defined logging
+
+@c FIXME: should probably also mention the fact the -l
+@c global option can disable most of the mechanisms
+@c discussed here (why? What is the -l global option for?).
+@c
+@c FIXME: probably should centralize this information
+@c here, at least to some extent. Maybe by moving the
+@c loginfo, etc., nodes here and replacing
+@c the "user-defined logging" node with one node for
+@c each method.
+@c <en>You can customize @sc{cvs} to log various kinds of
+@c <en>actions, in whatever manner you choose. These
+@c <en>mechanisms operate by executing a script at various
+@c <en>times. The script might append a message to a file
+@c <en>listing the information and the programmer who created
+@c <en>it, or send mail to a group of developers, or, perhaps,
+@c <en>post a message to a particular newsgroup. To log
+@c <en>commits, use the @file{loginfo} file (@pxref{loginfo}).
+@c <en>To log tags, use the @file{taginfo} file (@pxref{taginfo}).
+Você pode personalizar o @sc{cvs} para registrar vários
+tipos de ação, da forma que você escolher. Estes
+mecanismos operam executando um script várias vezes. O
+script deve anexar uma mensagem a um arquivo que lista
+as informações e o programador que as criou, ou mandar
+um e-mail para um grupo de desenvolvedores, ou, talvez,
+mandar uma mensagem para um newsgroup em particular.
+Para registrar os commits, usar o arquivo
+@file{loginfo} (@pxref{loginfo}). Para registrar
+etiquetamentos, use o comando @file{taginfo}
+(@pxref{taginfo}).
+@c FIXME: What is difference between doing it in the
+@c modules file and using loginfo/taginfo? Why should
+@c user use one or the other?
+@c <en>To log commits, checkouts, exports, and tags,
+@c <en>respectively, you can also use the @samp{-i},
+@c <en>@samp{-o}, @samp{-e}, and @samp{-t} options in the
+@c <en>modules file. For a more flexible way of giving
+@c <en>notifications to various users, which requires less in
+@c <en>the way of keeping centralized scripts up to date, use
+@c <en>the @code{cvs watch add} command (@pxref{Getting
+@c <en>Notified}); this command is useful even if you are not
+@c <en>using @code{cvs watch on}.
+Para registrar ???commits???, ???checkouts???,
+exportações, e etiquetagens, você pode
+usar, respectivamente, as opções @samp{-i}, @samp{-o},
+@samp{-e} e @samp{-t} no arquivo modules. Para uma
+forma mais flexível de notificar vários usuários, ???which requires less in
+the way of??? manter scripts centralizados atualizados,
+use o comando @code{cvs watch add} (@pxref{Recebendo
+Notificações}); este comando é útil mesmo se você não
+estiver usando @code{cvs watch on}.
+
+@c <en>@node annotate
+@node annotate
+@c <en>@section Annotate command
+@section O comando annotate
+@c <en>@cindex annotate (subcommand)
+@cindex annotate (subcomando)
+
+@c <en>@deffn Command {cvs annotate} [@code{-FflR}] [@code{-r rev}|@code{-D date}] files @dots{}
+@deffn Comando {cvs annotate} [@code{-FflR}] [@code{-r revisão}|@code{-D data}] arquivos @dots{}
+
+@c <en>For each file in @var{files}, print the head revision
+@c <en>of the trunk, together with information on the last
+@c <en>modification for each line. For example:
+Para cada arquivo em @var{arquivos}, imprime a revisão no topo
+ do tronco, junto com informações a respeito
+da última modificação em cada linha. Por exemplo:
+
+@example
+$ cvs annotate ssfile
+Annotations for ssfile
+***************
+1.1 (mary 27-Mar-96): ssfile line 1
+1.2 (joe 28-Mar-96): ssfile line 2
+@end example
+
+@c <en>The file @file{ssfile} currently contains two lines.
+@c <en>The @code{ssfile line 1} line was checked in by
+@c <en>@code{mary} on March 27. Then, on March 28, @code{joe}
+@c <en>added a line @code{ssfile line 2}, without modifying
+@c <en>the @code{ssfile line 1} line. This report doesn't
+@c <en>tell you anything about lines which have been deleted
+@c <en>or replaced; you need to use @code{cvs diff} for that
+@c <en>(@pxref{diff}).
+O arquivo @file{ssfile} atualmente contém duas
+linhas. A @code{linha 1 de ssfile} foi submetida por
+@code{mary} em March 27 (27 de março). Então, em March
+28 (28 de março), @code{joe} adicionou a
+@code{linha 2 de ssfile}, sem modificar a
+@code{linha 1 de ssfile}. Este relatório não te diz nada a
+respeito de linhas que foram deletadas ou substituídas;
+Você precisa usar o @code{cvs diff} para isto
+(@pxref{diff}).
+
+@end deffn
+
+@c <en>The options to @code{cvs annotate} are listed in
+@c <en>@ref{Invoking CVS}, and can be used to select the files
+@c <en>and revisions to annotate. The options are described
+@c <en>in more detail there and in @ref{Common options}.
+As opções para o @code{cvs annotate} são listadas em
+@ref{Chamando o CVS} e podem ser usadas para selecionar
+os arquivos e revisões para o annotate. As opções
+são descritas com mais detalhes lá e em @ref{Opções comuns}.
+
+@c FIXME: maybe an example using the options? Just
+@c what it means to select a revision might be worth a
+@c few words of explanation ("you want to see who
+@c changed this line *before* 1.4"...).
+
+@c ---------------------------------------------------------------------
+@c <en>@node Binary files
+@node Arquivos binários
+@c <en>@chapter Handling binary files
+@chapter Manipulando arquivos binários
+@c <en>@cindex Binary files
+@cindex Arquivos binários
+
+@c <en>The most common use for @sc{cvs} is to store text
+@c <en>files. With text files, @sc{cvs} can merge revisions,
+@c <en>display the differences between revisions in a
+@c <en>human-visible fashion, and other such operations.
+@c <en>However, if you are willing to give up a few of these
+@c <en>abilities, @sc{cvs} can store binary files. For
+@c <en>example, one might store a web site in @sc{cvs}
+@c <en>including both text files and binary images.
+O @sc{cvs} é usado normalmente para guardar arquivos
+texto. Com arquivos texto o @sc{cvs} pode mesclar
+revisões, mostrar diferenças entre revisões de uma
+forma legível para humanos, e outras operações do
+tipo. Entretanto, se você está disposto a abrir mão de
+algumas destas habilidades, o @sc{cvs} pode guardar
+arquivos binários. Por exemplo, pode-se guardar um
+site no @sc{cvs} incluindo tanto os arquivos texto
+quanto as imagens em binário.
+
+@menu
+@c <en>* Binary why:: More details on issues with binary files
+* Binary why:: Mais detalhes no que concerne a arquivos binários
+@c <en>* Binary howto:: How to store them
+* Binary howto:: Como guardá-los
+@end menu
+
+@c <en>@node Binary why
+@node Binary why
+@c <en>@section The issues with binary files
+@section The issues with binary files
+
+@c <en>While the need to manage binary files may seem obvious
+@c <en>if the files that you customarily work with are binary,
+@c <en>putting them into version control does present some
+@c <en>additional issues.
+???While??? a necessidade de armazenar arquivos
+binários se mostra óbvia se os arquivos com os quais
+você normalmente trabalha são binários, botá-los
+dentro do controle de versões requer alguns cuidados
+adicionais.
+
+@c <en>One basic function of version control is to show the
+@c <en>differences between two revisions. For example, if
+@c <en>someone else checked in a new version of a file, you
+@c <en>may wish to look at what they changed and determine
+@c <en>whether their changes are good. For text files,
+@c <en>@sc{cvs} provides this functionality via the @code{cvs
+@c <en>diff} command. For binary files, it may be possible to
+@c <en>extract the two revisions and then compare them with a
+@c <en>tool external to @sc{cvs} (for example, word processing
+@c <en>software often has such a feature). If there is no
+@c <en>such tool, one must track changes via other mechanisms,
+@c <en>such as urging people to write good log messages, and
+@c <en>hoping that the changes they actually made were the
+@c <en>changes that they intended to make.
+Uma habilidade básica de um controle de versões é mostrar
+as diferenças entre duas revisões. Por exemplo, se
+outra pessoa submete (check in) uma nova versão de um
+arquivo, você pode querer ver o que foi mudado e
+determinar quais destas mudanças foram boas. Para
+arquivos texto, o @sc{cvs} oferece esta funcionalidade
+através do comando @code{cvs diff}. Para arquivos
+binários, existe uma chance de extrair as duas
+revisões e então compará-las com uma ferramenta externa
+ao @sc{cvs} (por exemplo, alguns processadores de texto
+têm esta habilidade). Se não existe tal ferramenta, é
+possível rastrear mudanças por outros meios, como por
+exemplo convencendo as pessoas a escreverem boas
+mensagens de registro (log), e torcendo para que as
+mudanças que eles realmente fizeram foram as que eles
+tinham intenção de fazer.
+
+@c <en>Another ability of a version control system is the
+@c <en>ability to merge two revisions. For @sc{cvs} this
+@c <en>happens in two contexts. The first is when users make
+@c <en>changes in separate working directories
+@c <en>(@pxref{Multiple developers}). The second is when one
+@c <en>merges explicitly with the @samp{update -j} command
+@c <en>(@pxref{Branching and merging}).
+Outra habilidade de um sistema de controle de versões é
+a capacidade de mesclar duas revisões. No @sc{cvs}
+isto acontece em dois contextos. O primeiro é quando
+os usuáriso fazem mudanças em diretórios de trabalho
+separados (@pxref{Múltiplos desenvolvedores}). A
+segunda é quando alguém mescla explicitamente com o
+comando @samp{update -j} (@pxref{Ramificando e mesclando}).
+
+@c <en>In the case of text
+@c <en>files, @sc{cvs} can merge changes made independently,
+@c <en>and signal a conflict if the changes conflict. With
+@c <en>binary files, the best that @sc{cvs} can do is present
+@c <en>the two different copies of the file, and leave it to
+@c <en>the user to resolve the conflict. The user may choose
+@c <en>one copy or the other, or may run an external merge
+@c <en>tool which knows about that particular file format, if
+@c <en>one exists.
+@c <en>Note that having the user merge relies primarily on the
+@c <en>user to not accidentally omit some changes, and thus is
+@c <en>potentially error prone.
+No caso de arquivos texto, o @sc{cvs} pode mesclar
+mudanças feitas independentemente, e avisar sobre um
+conflito se as mudanças conflitarem. Com arquivos
+binários, o melhor que o @sc{cvs} pode fazer é
+fornecer as duas cópias diferentes do arquivo, e deixar
+a cargo do usuário a resolução do conflito. O usuário
+pode escolher uma cópia ou a outra, ou pode rodar uma
+ferramenta externa de mesclagem que entenda aquele
+formato de arquivo em particular, se é que tal
+ferramenta exista. Observe que mesclagem feita pelo
+usuário se baseia no fato de o usuário não omitir
+acidentalmente algumas mudanças, e portanto é sujeita a erros.
+
+@c <en>If this process is thought to be undesirable, the best
+@c <en>choice may be to avoid merging. To avoid the merges
+@c <en>that result from separate working directories, see the
+@c <en>discussion of reserved checkouts (file locking) in
+@c <en>@ref{Multiple developers}. To avoid the merges
+@c <en>resulting from branches, restrict use of branches.
+Se você acha que este processo é indesejável, a melhor
+escolha é evitar mesclagem. Para evitar mesclagens
+resultantes de diretórios de trabalho separados, veja a
+discussão a respeito de ???reserved checkouts??? (travas
+de arquivo) em @ref{Múltiplos desenvolvedores}. Para
+ecitar mesclagens resultantes de ramificações,
+restrinja o uso de ramos.
+
+@c <en>@node Binary howto
+@node Binary howto
+@c <en>@section How to store binary files
+@section Como guardar arquivos binários
+
+@c <en>There are two issues with using @sc{cvs} to store
+@c <en>binary files. The first is that @sc{cvs} by default
+@c <en>converts line endings between the canonical form in
+@c <en>which they are stored in the repository (linefeed
+@c <en>only), and the form appropriate to the operating system
+@c <en>in use on the client (for example, carriage return
+@c <en>followed by line feed for Windows NT).
+Existem dois aspectos a considerar quando se usa o
+@sc{cvs} para guardar arquivos binários. O primeiro é
+que o @sc{cvs}, por padrão, converte quebras de linhas
+entre a forma canônica na qual elas são guardadas no
+repositório (apenas ???linefeed???), e a forma
+apropriada para o sistema operacional no qual o cliente
+é usado (por exemplo, carriage return (retorno do
+carro) seguido por line feed (alimentação de linha)
+para o Windows NT).
+
+@c <en>The second is that a binary file might happen to
+@c <en>contain data which looks like a keyword (@pxref{Keyword
+@c <en>substitution}), so keyword expansion must be turned
+@c <en>off.
+O segundo aspecto é que um arquivo binário pode conter
+dados que se pareçam com uma palavra-chave
+(@pxref{Substituição de palavra-chave}). Logo, a
+expansão de palavra-chave deve ser desativada.
+
+@c FIXME: the third is that one can't do merges with
+@c binary files. xref to Multiple Developers and the
+@c reserved checkout issues.
+
+@c <en>The @samp{-kb} option available with some @sc{cvs}
+@c <en>commands insures that neither line ending conversion
+@c <en>nor keyword expansion will be done.
+A opção @samp{-kb} disponível com alguns comandos do
+@sc{cvs} garante que nem conversão de terminação de
+linha nem expansão de palavra-chave sejam usadas.
+
+@c <en>Here is an example of how you can create a new file
+@c <en>using the @samp{-kb} flag:
+Aqui está um exemplo de como você pode criar um novo
+arquivo usando a opção @samp{-kb}:
+
+@example
+$ echo '$@splitrcskeyword{}Id$' > kotest
+$ cvs add -kb -m"A test file" kotest
+$ cvs ci -m"First checkin; contains a keyword" kotest
+@end example
+
+@c <en>If a file accidentally gets added without @samp{-kb},
+@c <en>one can use the @code{cvs admin} command to recover.
+@c <en>For example:
+Se um arquivo for acidentalmente adicionado sem o
+@samp{-kb}, é possível usar o comando @code{cvs admin}
+para reverter. Por exemplo:
+
+@example
+$ echo '$@splitrcskeyword{}Id$' > kotest
+$ cvs add -m"A test file" kotest
+$ cvs ci -m"First checkin; contains a keyword" kotest
+$ cvs admin -kb kotest
+$ cvs update -A kotest
+# @r{For non-unix systems:}
+# @r{Copy in a good copy of the file from outside CVS}
+$ cvs commit -m "make it binary" kotest
+@end example
+
+@c Trying to describe this for both unix and non-unix
+@c in the same description is very confusing. Might
+@c want to split the two, or just ditch the unix "shortcut"
+@c (unixheads don't do much with binary files, anyway).
+@c This used to say "(Try the above example, and do a
+@c @code{cat kotest} after every command)". But that
+@c only really makes sense for the unix case.
+@c <en>When you check in the file @file{kotest} the file is
+@c <en>not preserved as a binary file, because you did not
+@c <en>check it in as a binary file. The @code{cvs
+@c <en>admin -kb} command sets the default keyword
+@c <en>substitution method for this file, but it does not
+@c <en>alter the working copy of the file that you have. If you need to
+@c <en>cope with line endings (that is, you are using
+@c <en>@sc{cvs} on a non-unix system), then you need to
+@c <en>check in a new copy of the file, as shown by the
+@c <en>@code{cvs commit} command above.
+@c <en>On unix, the @code{cvs update -A} command suffices.
+Quando você submete o arquivo @file{kotest} o arquivo
+não é mantido como um arquivo binário, por que você não
+o submeteu como arquivo binário. O comando @code{cvs
+admin -kb} ajusta o método de substituição da
+palavra-chave padrão para este arquivo, mas não altera
+a cópia de trabalho que você tem. Se você tem que
+lidar com terminações de linha (ou seja, você está usando
+o @sc{cvs} em um sistema não-unix), então você precisa
+submeter uma nova cópia do arquivo, como mostrado no comando
+@code{cvs commit} acima. No unix, o comando @code{cvs
+update -A} basta.
+@c FIXME: should also describe what the *other users*
+@c need to do, if they have checked out copies which
+@c have been corrupted by lack of -kb. I think maybe
+@c "cvs update -kb" or "cvs
+@c update -A" would suffice, although the user who
+@c reported this suggested removing the file, manually
+@c removing it from CVS/Entries, and then "cvs update"
+@c <en>(Note that you can use @code{cvs log} to determine the default keyword
+@c <en>substitution method for a file and @code{cvs status} to determine
+@c <en>the keyword substitution method for a working copy.)
+(Note que você pode usar o @code{cvs log} para
+determinar o métido de substituição de palavra-chave
+padrão para um arquivo e @code{cvs status} para
+determinar o método de substituição de palavra-chave
+para uma cópia de trabalho.)
+
+@c <en>However, in using @code{cvs admin -k} to change the
+@c <en>keyword expansion, be aware that the keyword expansion
+@c <en>mode is not version controlled. This means that, for
+@c <en>example, that if you have a text file in old releases,
+@c <en>and a binary file with the same name in new releases,
+@c <en>@sc{cvs} provides no way to check out the file in text
+@c <en>or binary mode depending on what version you are
+@c <en>checking out. There is no good workaround for this
+@c <en>problem.
+Entretanto, ao usar @code{cvs admin -k} para mudar a
+expansão de palavra-chave, esteja atento para o fato de
+que o modo de expansão de palavra-chave não tem
+controle de versão. Isto significa que, por exemplo,
+se você tem um arquivo texto em versões antigas, e um
+arquivo binário com o mesmo nome em novos releases,
+o @sc{cvs} não fornece uma forma de obter o arquivo em
+formato texto, ou binário, dependendo da versão que
+você estpa pegando. Não existe uma boa solução
+alternativa para este problema.
+
+@c <en>You can also set a default for whether @code{cvs add}
+@c <en>and @code{cvs import} treat a file as binary based on
+@c <en>its name; for example you could say that files who
+@c <en>names end in @samp{.exe} are binary. @xref{Wrappers}.
+@c <en>There is currently no way to have @sc{cvs} detect
+@c <en>whether a file is binary based on its contents. The
+@c <en>main difficulty with designing such a feature is that
+@c <en>it is not clear how to distinguish between binary and
+@c <en>non-binary files, and the rules to apply would vary
+@c <en>considerably with the operating system.
+Você também pode ajustar um padrão para quando o
+@code{cvs add} e o @code{cvs import} tratarem um
+arquivo como binário de acordo como o seu nome; por
+exemplo, você pode dizer que arquivos cujos nomes
+terminem com @samp{.exe} são binário. @xref{Wrappers}.
+Não existe atualmente uma forma de fazer o @sc{cvs}
+detectar quando um arquivo é binário baseado em seu
+conteúdo. A dificuldade principal em fazer isto é que
+não é claro como se faz para distinguir entre arquivos
+binários e não-binários, e as regras para serem
+aplicadas variam consideravelmente com o sistema
+operacional.
+@c For example, it would be good on MS-DOS-family OSes
+@c for anything containing ^Z to be binary. Having
+@c characters with the 8th bit set imply binary is almost
+@c surely a bad idea in the context of ISO-8859-* and
+@c other such character sets. On VMS or the Mac, we
+@c could use the OS's file typing. This is a
+@c commonly-desired feature, and something of this sort
+@c may make sense. But there are a lot of pitfalls here.
+@c
+@c Another, probably better, way to tell is to read the
+@c file in text mode, write it to a temp file in text
+@c mode, and then do a binary mode compare of the two
+@c files. If they differ, it is a binary file. This
+@c might have problems on VMS (or some other system
+@c with several different text modes), but in general
+@c should be relatively portable. The only other
+@c downside I can think of is that it would be fairly
+@c slow, but that is perhaps a small price to pay for
+@c not having your files corrupted. Another issue is
+@c what happens if you import a text file with bare
+@c linefeeds on Windows. Such files will show up on
+@c Windows sometimes (I think some native windows
+@c programs even write them, on occasion). Perhaps it
+@c is reasonable to treat such files as binary; after
+@c all it is something of a presumption to assume that
+@c the user would want the linefeeds converted to CRLF.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Multiple developers
+@node Múltiplos desenvolvedores
+@c <en>@chapter Multiple developers
+@chapter Múltiplos desenvolvedores
+@c <en>@cindex Multiple developers
+@cindex Múltiplos desenvolvedores
+@c <en>@cindex Team of developers
+@cindex Team of developers
+@c <en>@cindex File locking
+@cindex File locking
+@c <en>@cindex Locking files
+@cindex Locking files
+@c <en>@cindex Working copy
+@cindex Working copy
+@c <en>@cindex Reserved checkouts
+@cindex Reserved checkouts
+@c <en>@cindex Unreserved checkouts
+@cindex checkouts não-reservados
+@c <en>@cindex RCS-style locking
+@cindex RCS-style locking
+
+@c <en>When more than one person works on a software project
+@c <en>things often get complicated. Often, two people try to
+@c <en>edit the same file simultaneously. One solution, known
+@c <en>as @dfn{file locking} or @dfn{reserved checkouts}, is
+@c <en>to allow only one person to edit each file at a time.
+@c <en>This is the only solution with some version control
+@c <en>systems, including @sc{rcs} and @sc{sccs}. Currently
+@c <en>the usual way to get reserved checkouts with @sc{cvs}
+@c <en>is the @code{cvs admin -l} command (@pxref{admin
+@c <en>options}). This is not as nicely integrated into
+@c <en>@sc{cvs} as the watch features, described below, but it
+@c <en>seems that most people with a need for reserved
+@c <en>checkouts find it adequate.
+Quando mais de uma pessoa trabalham em um projeto de
+software freqüentemente surgem complicações. Às vezes
+duas pessoas tentam editar o mesmo arquivo
+simultaneamente. Uma solução, conhecida como
+@dfn{trava de arquivo} ou @dfn{???checkout???
+reservado}, é permitir, para cada arquivo, que apenas
+uma pessoa por vez edite o arquivo. Esta é a única
+solução em alguns sistemas de controle de versão,
+incluindo @sc{rcs} e @sc{sccs}. Atualmente, a forma
+normal de se ter ???checkouts??? reservados com o @sc{cvs}
+é com o comando @code{cvs admin -l} (@pxref{admin
+options}). Isto não é tão integrado com o @sc{cvs}
+quanto a habilidade de ???watch???, descrita abaixo,
+mas vemos que a maioria das pessoas que necessitam de
+???checkouts??? reservados acham isto adequado.
+@c Or "find it better than worrying about implementing
+@c nicely integrated reserved checkouts" or ...?
+@c <en>It also may be possible to use the watches
+@c <en>features described below, together with suitable
+@c <en>procedures (not enforced by software), to avoid having
+@c <en>two people edit at the same time.
+Também é possível usar a habilidade de trabalhar com
+descrita a seguir, junto com alguns procedimentos
+adequados (que o sotware não obriga), para evitar que
+duas pessoas editem o mesmo arquivo ao mesmo tempo.
+
+@c Our unreserved checkout model might not
+@c be quite the same as others. For example, I
+@c think that some systems will tend to create a branch
+@c in the case where CVS prints "up-to-date check failed".
+@c It isn't clear to me whether we should try to
+@c explore these subtleties; it could easily just
+@c confuse people.
+@c <en>The default model with @sc{cvs} is known as
+@c <en>@dfn{unreserved checkouts}. In this model, developers
+@c <en>can edit their own @dfn{working copy} of a file
+@c <en>simultaneously. The first person that commits his
+@c <en>changes has no automatic way of knowing that another
+@c <en>has started to edit it. Others will get an error
+@c <en>message when they try to commit the file. They must
+@c <en>then use @sc{cvs} commands to bring their working copy
+@c <en>up to date with the repository revision. This process
+@c <en>is almost automatic.
+O modelo padrão no @sc{cvs} é conhecido como
+@dfn{???checkouts??? não-reservados}. Neste modelo, os
+desenvolvedores podem editar sua própria @dfn{cópia de
+trabalho} de um arquivo simultaneamente. A primeira
+pessoa que ???commits??? suas mudanças não tem uma
+forma automática de saber que outra pessoa começou a
+editar o mesmo arquivo. Os outros vão receber uma
+mensagem de erro quando tentarem ???commit??? o
+arquivo. Eles então terão que usar comandos do
+@sc{cvs} para tornar sua cópia local atualizada em
+relação à revisão no repositório. Este processo é
+quase automático.
+
+@c FIXME? should probably use the word "watch" here, to
+@c tie this into the text below and above.
+@c <en>@sc{cvs} also supports mechanisms which facilitate
+@c <en>various kinds of communication, without actually
+@c <en>enforcing rules like reserved checkouts do.
+O @sc{cvs} também dá suporte a mecanismos que facilitam
+várias formas de comunicação, sem regras realmente
+obrigatórias como acontece com os ???checkouts??? reservados.
+
+@c <en>The rest of this chapter describes how these various
+@c <en>models work, and some of the issues involved in
+@c <en>choosing between them.
+O restante deste capítulo descreve como estes vários
+modelos funcionam, e alguns dos aspectos envolvidos na
+hora de escolher entre eles.
+
+@ignore
+@c <en>Here is a draft reserved checkout design or discussion
+@c <en>of the issues. This seems like as good a place as any
+@c <en>for this.
+Here is a draft reserved checkout design or discussion
+of the issues. This seems like as good a place as any
+for this.
+
+@c <en>Might want a cvs lock/cvs unlock--in which the names
+@c <en>differ from edit/unedit because the network must be up
+@c <en>for these to work. unedit gives an error if there is a
+@c <en>reserved checkout in place (so that people don't
+@c <en>accidentally leave locks around); unlock gives an error
+@c <en>if one is not in place (this is more arguable; perhaps
+@c <en>it should act like unedit in that case).
+Might want a cvs lock/cvs unlock--in which the names
+differ from edit/unedit because the network must be up
+for these to work. unedit gives an error if there is a
+reserved checkout in place (so that people don't
+accidentally leave locks around); unlock gives an error
+if one is not in place (this is more arguable; perhaps
+it should act like unedit in that case).
+
+@c <en>On the other hand, might want it so that emacs,
+@c <en>scripts, etc., can get ready to edit a file without
+@c <en>having to know which model is in use. In that case we
+@c <en>would have a "cvs watch lock" (or .cvsrc?) (that is,
+@c <en>three settings, "on", "off", and "lock"). Having cvs
+@c <en>watch lock set would cause a get to record in the CVS
+@c <en>directory which model is in use, and cause "cvs edit"
+@c <en>to change behaviors. We'd want a way to query which
+@c <en>setting is in effect (this would be handy even if it is
+@c <en>only "on" or "off" as presently). If lock is in
+@c <en>effect, then commit would require a lock before
+@c <en>allowing a checkin; chmod wouldn't suffice (might be
+@c <en>debatable--see chmod comment below, in watches--but it
+@c <en>is the way people expect RCS to work and I can't think
+@c <en>of any significant downside. On the other hand, maybe
+@c <en>it isn't worth bothering, because people who are used
+@c <en>to RCS wouldn't think to use chmod anyway).
+On the other hand, might want it so that emacs,
+scripts, etc., can get ready to edit a file without
+having to know which model is in use. In that case we
+would have a "cvs watch lock" (or .cvsrc?) (that is,
+three settings, "on", "off", and "lock"). Having cvs
+watch lock set would cause a get to record in the CVS
+directory which model is in use, and cause "cvs edit"
+to change behaviors. We'd want a way to query which
+setting is in effect (this would be handy even if it is
+only "on" or "off" as presently). If lock is in
+effect, then commit would require a lock before
+allowing a checkin; chmod wouldn't suffice (might be
+debatable--see chmod comment below, in watches--but it
+is the way people expect RCS to work and I can't think
+of any significant downside. On the other hand, maybe
+it isn't worth bothering, because people who are used
+to RCS wouldn't think to use chmod anyway).
+
+@c <en>Implementation: use file attributes or use RCS
+@c <en>locking. The former avoids more dependence on RCS
+@c <en>behaviors we will need to reimplement as we librarify
+@c <en>RCS, and makes it easier to import/export RCS files (in
+@c <en>that context, want to ignore the locker field). But
+@c <en>note that RCS locks are per-branch, which is the
+@c <en>correct behavior (this is also an issue for the "watch
+@c <en>on" features; they should be per-branch too).
+Implementation: use file attributes or use RCS
+locking. The former avoids more dependence on RCS
+behaviors we will need to reimplement as we librarify
+RCS, and makes it easier to import/export RCS files (in
+that context, want to ignore the locker field). But
+note that RCS locks are per-branch, which is the
+correct behavior (this is also an issue for the "watch
+on" features; they should be per-branch too).
+
+@c <en>Here are a few more random notes about implementation
+@c <en>details, assuming "cvs watch lock" and
+Here are a few more random notes about implementation
+details, assuming "cvs watch lock" and
+
+@c <en>CVS/Watched file? Or try to fit this into CVS/Entries somehow?
+@c <en>Cases: (1) file is checked out (unreserved or with watch on) by old
+@c <en>version of @sc{cvs}, now we do something with new one, (2) file is checked
+@c <en>out by new version, now we do something with old one.
+CVS/Watched file? Or try to fit this into CVS/Entries somehow?
+Cases: (1) file is checked out (não-reservado or with watch on) by old
+version of @sc{cvs}, now we do something with new one, (2) file is checked
+out by new version, now we do something with old one.
+
+@c <en>Remote protocol would have a "Watched" analogous to "Mode". Of course
+@c <en>it would apply to all Updated-like requests. How do we keep this
+@c <en>setting up to date? I guess that there wants to be a Watched request,
+@c <en>and the server would send a new one if it isn't up to date? (Ugh--hard
+@c <en>to implement and slows down "cvs -q update"--is there an easier way?)
+Remote protocol would have a "Watched" analogous to "Mode". Of course
+it would apply to all Updated-like requests. How do we keep this
+setting up to date? I guess that there wants to be a Watched request,
+and the server would send a new one if it isn't up to date? (Ugh--hard
+to implement and slows down "cvs -q update"--is there an easier way?)
+
+@c <en>"cvs edit"--checks CVS/Watched, and if watch lock, then sends
+@c <en>"edit-lock" request. Which comes back with a Checked-in with
+@c <en>appropriate Watched (off, on, lock, locked, or some such?), or error
+@c <en>message if already locked.
+"cvs edit"--checks CVS/Watched, and if watch lock, then sends
+"edit-lock" request. Which comes back with a Checked-in with
+appropriate Watched (off, on, lock, locked, or some such?), or error
+message if already locked.
+
+@c <en>"cvs commit"--only will commit if off/on/locked. lock is not OK.
+"cvs commit"--only will commit if off/on/locked. lock is not OK.
+
+@c <en>Doc:
+@c <en>note that "cvs edit" must be connected to network if watch lock is in
+@c <en>effect.
+Doc:
+note that "cvs edit" must be connected to network if watch lock is in
+effect.
+
+@c <en>Talk about what to do if someone has locked a file and you want to
+@c <en>edit that file. (breaking locks, or lack thereof).
+Talk about what to do if someone has locked a file and you want to
+edit that file. (breaking locks, or lack thereof).
+
+
+@c <en>One other idea (which could work along with the
+@c <en>existing "cvs admin -l" reserved checkouts, as well as
+@c <en>the above):
+One other idea (which could work along with the
+existing "cvs admin -l" reserved checkouts, as well as
+the above):
+
+@c <en>"cvs editors" could show who has the file locked, if
+@c <en>someone does.
+"cvs editors" could show who has the file locked, if
+someone does.
+
+@end ignore
+
+@menu
+@c <en>* File status:: A file can be in several states
+* Estado de arquivo:: Um arquivo pode ter vários estados
+@c <en>* Updating a file:: Bringing a file up-to-date
+* Atualizando um arquivo:: Deixando um arquivo atualizado
+@c <en>* Conflicts example:: An informative example
+* Exemplo de conflitos:: Um exemplo informativo
+@c <en>* Informing others:: To cooperate you must inform
+* Informando os outros:: Para cooperar você deve informar
+@c <en>* Concurrency:: Simultaneous repository access
+* Concorrência:: Acesso simultâneo ao repositório
+@c <en>* Watches:: Mechanisms to track who is editing files
+* ???Watches???:: Mecanismos para rastrear quem está editando arquivos
+@c <en>* Choosing a model:: Reserved or unreserved checkouts?
+* Escolhendo um modelo:: ???checkout??? reservado ou não-reservado?
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node File status
+@node Estado de arquivo
+@c <en>@section File status
+@section Estado de arquivo
+@c <en>@cindex File status
+@cindex Estado de arquivo
+@c <en>@cindex Status of a file
+@cindex Estado de um arquivo
+
+@c Shouldn't this start with an example or something,
+@c introducing the unreserved checkout model? Before we
+@c dive into listing states?
+@c <en>Based on what operations you have performed on a
+@c <en>checked out file, and what operations others have
+@c <en>performed to that file in the repository, one can
+@c <en>classify a file in a number of states. The states, as
+@c <en>reported by the @code{status} command, are:
+Baseado em quais operações você realizou num arquivo
+???checked out???, e quais operações outros realizaram
+neste arquivo no repositório, podemos classificar o
+arquivo em vários estados. Os estados, como são
+mostrados pelo comando @code{status}, são:
+
+@c The order of items is chosen to group logically
+@c similar outputs together.
+@c People who want alphabetical can use the index...
+@table @asis
+@c <en>@cindex Up-to-date
+@cindex Up-to-date (Atualizado)
+@c <en>@item Up-to-date
+@item Up-to-date (Atualizado)
+@c <en>The file is identical with the latest revision in the
+@c <en>repository for the branch in use.
+O arquivo é identico à última revisão no repositório,
+para o ramo em questão.
+@c FIXME: should we clarify "in use"? The answer is
+@c sticky tags, and trying to distinguish branch sticky
+@c tags from non-branch sticky tags seems rather awkward
+@c here.
+@c FIXME: What happens with non-branch sticky tags? Is
+@c a stuck file "Up-to-date" or "Needs checkout" or what?
+
+@c <en>@item Locally Modified
+@item Locally Modified (Modificado localmente)
+@c <en>@cindex Locally Modified
+@cindex Locally Modified (Modificado localmente)
+@c <en>You have edited the file, and not yet committed your changes.
+Você alterou o arquivo, e ainda não ???committed???
+suas mudanças.
+
+@c <en>@item Locally Added
+@item Locally Added (Adicionado localmente)
+@c <en>@cindex Locally Added
+@cindex Locally Added (Adicionado localmente)
+@c <en>You have added the file with @code{add}, and not yet
+@c <en>committed your changes.
+Você adicionou o arquivo com @code{add}, e ainda não
+???committed??? suas mudanças.
+@c There are many cases involving the file being
+@c added/removed/modified in the working directory, and
+@c added/removed/modified in the repository, which we
+@c don't try to describe here. I'm not sure that "cvs
+@c status" produces a non-confusing output in most of
+@c those cases.
+
+@c <en>@item Locally Removed
+@item Locally Removed (Removido localmente)
+@c <en>@cindex Locally Removed
+@cindex Locally Removed (Removido localmente)
+@c <en>You have removed the file with @code{remove}, and not yet
+@c <en>committed your changes.
+Você removeu o arquivo com @code{remove}, e ainda não
+???committed??? suas mudanças.
+
+@c <en>@item Needs Checkout
+@item Needs Checkout (Precisa de ???checkout???)
+@c <en>@cindex Needs Checkout
+@cindex Needs Checkout (Precisa de ???checkout???)
+@c <en>Someone else has committed a newer revision to the
+@c <en>repository. The name is slightly misleading; you will
+@c <en>ordinarily use @code{update} rather than
+@c <en>@code{checkout} to get that newer revision.
+Alguém ???committed??? uma revisão nova no repositório.
+O nome está um pouco confuso; você normalmente vai usar
+@code{update} ao invés de @code{checkout} para obter a
+nova revisão.
+
+@c <en>@item Needs Patch
+@item Needs Patch (Precisa de ???patch???)
+@c <en>@cindex Needs Patch
+@cindex Needs Patch (Precisa de ???patch???)
+@c See also newb-123j0 in sanity.sh (although that case
+@c should probably be changed rather than documented).
+@c <en>Like Needs Checkout, but the @sc{cvs} server will send
+@c <en>a patch rather than the entire file. Sending a patch or
+@c <en>sending an entire file accomplishes the same thing.
+Igual a 'Needs Checkout', mas o servidor do @sc{cvs}
+vai mandar um ???patch??? ao invés de um arquivo
+inteiro. Mandar um ???patch??? ou um arquivo inteiro
+dá no mesmo.
+
+@c <en>@item Needs Merge
+@item Needs Merge (Precisa mesclar)
+@c <en>@cindex Needs Merge
+@cindex Needs Merge (Precisa mesclar)
+@c <en>Someone else has committed a newer revision to the repository, and you
+@c <en>have also made modifications to the file.
+Outra pessoa ???committed??? uma nova revisão no
+repositório, e você fez modificações no arquivo.
+
+@c <en>@item Unresolved Conflict
+@item Unresolved Conflict (Conflito não-solucionado)
+@c <en>@cindex Unresolved Conflict
+@cindex Unresolved Conflict (Conflito não-solucionado)
+@c FIXCVS - This file status needs to be changed to some more informative
+@c text that distinguishes it more clearly from each of the Locally Added,
+@c File had conflicts on merge, and Unknown status types, but an exact and
+@c succinct wording escapes me at the moment.
+@c <en>A file with the same name as this new file has been added to the repository
+@c <en>from a second workspace. This file will need to be moved out of the way
+@c <en>to allow an @code{update} to complete.
+Um arquivo com o mesmo nome deste arquivo novo foi
+adicionado ao repositório a partir de outra área de
+trabalho. Este arquivo vai ter que ser movido para que
+não atrapalhe um @code{update} de completar.
+
+@c <en>@item File had conflicts on merge
+@item File had conflicts on merge (Arquivo teve conflitos na mescla)
+@c <en>@cindex File had conflicts on merge
+@cindex File had conflicts on merge (Arquivo teve conflitos na mescla)
+@c is it worth saying that this message was "Unresolved
+@c Conflict" in CVS 1.9 and earlier? I'm inclined to
+@c think that is unnecessarily confusing to new users.
+@c <en>This is like Locally Modified, except that a previous
+@c <en>@code{update} command gave a conflict. If you have not
+@c <en>already done so, you need to
+@c <en>resolve the conflict as described in @ref{Conflicts example}.
+Isto é parecido com 'Locally Modified', com a diferença que o comando
+@code{update} anterior produziu um conflito. Se você
+ainda não o fez, precisa resolver o conflito, como é
+descrito em @ref{Exemplo de conflitos}.
+
+@c <en>@item Unknown
+@item Unknown (Desconhecido)
+@c <en>@cindex Unknown
+@cindex Unknown (Desconhecido)
+@c <en>@sc{cvs} doesn't know anything about this file. For
+@c <en>example, you have created a new file and have not run
+@c <en>@code{add}.
+O @sc{cvs} não sabe nada a respeito deste arquivo. Por
+exemplo, você criou um novo arquivo e não rodou um
+@code{add}.
+@c
+@c "Entry Invalid" and "Classify Error" are also in the
+@c status.c. The latter definitely indicates a CVS bug
+@c (should it be worded more like "internal error" so
+@c people submit bug reports if they see it?). The former
+@c I'm not as sure; I haven't tracked down whether/when it
+@c appears in "cvs status" output.
+
+@end table
+
+@c <en>To help clarify the file status, @code{status} also
+@c <en>reports the @code{Working revision} which is the
+@c <en>revision that the file in the working directory derives
+@c <en>from, and the @code{Repository revision} which is the
+@c <en>latest revision in the repository for the branch in
+@c <en>use.
+Para facilitar o entendimento do estado do arquivo, o
+comando @code{status} também relata a @code{revisão de
+trabalho}, que é a revisão da qual o arquivo no
+diretório de trabalho deriva, e a @code{Revisão de
+repositório} que é a mais recente revisão no
+repositório, para o ramo em uso.
+@c FIXME: should we clarify "in use"? The answer is
+@c sticky tags, and trying to distinguish branch sticky
+@c tags from non-branch sticky tags seems rather awkward
+@c here.
+@c FIXME: What happens with non-branch sticky tags?
+@c What is the Repository Revision there? See the
+@c comment at vn_rcs in cvs.h, which is kind of
+@c confused--we really need to document better what this
+@c field contains.
+@c Q: Should we document "New file!" and other such
+@c outputs or are they self-explanatory?
+@c FIXME: what about the date to the right of "Working
+@c revision"? It doesn't appear with client/server and
+@c seems unnecessary (redundant with "ls -l") so
+@c perhaps it should be removed for non-client/server too?
+@c FIXME: Need some examples.
+@c FIXME: Working revision can also be something like
+@c "-1.3" for a locally removed file. Not at all
+@c self-explanatory (and it is possible that CVS should
+@c be changed rather than documenting this).
+
+@c Would be nice to have an @example showing output
+@c from cvs status, with comments showing the xref
+@c where each part of the output is described. This
+@c might fit in nicely if it is desirable to split this
+@c node in two; one to introduce "cvs status" and one
+@c to list each of the states.
+@c <en>The options to @code{status} are listed in
+@c <en>@ref{Invoking CVS}. For information on its @code{Sticky tag}
+@c <en>and @code{Sticky date} output, see @ref{Sticky tags}.
+@c <en>For information on its @code{Sticky options} output,
+@c <en>see the @samp{-k} option in @ref{update options}.
+As opções para o comando @code{status} são listadas em
+@ref{Chamando o CVS}. Para informações sobre suas
+saídas @code{Sticky tag (Etiqueta adesiva)} e
+@code{Sticky date (data adesiva)} veja em
+@ref{Etiquetas adesivas}. Para informações na saída
+@code{Sticky options (Opções adesivas)}, veja a
+opção @samp{-k} em @ref{update options}.
+
+@c <en>You can think of the @code{status} and @code{update}
+@c <en>commands as somewhat complementary. You use
+@c <en>@code{update} to bring your files up to date, and you
+@c <en>can use @code{status} to give you some idea of what an
+@c <en>@code{update} would do (of course, the state of the
+@c <en>repository might change before you actually run
+@c <en>@code{update}). In fact, if you want a command to
+@c <en>display file status in a more brief format than is
+@c <en>displayed by the @code{status} command, you can invoke
+Você pode pensar nos comandos @code{status} e
+@code{update} como complementares. Você usa o
+@code{update} para atualizar seus arquivos, e você pode
+usar o @code{status} para ter idéia do que um
+@code{update} deve fazer (obviamente, o estado do
+repositório pode mudar depois que você rodar o
+@code{update}). De fato, se você quiser um comando
+para mostrar o estado de arquivos num formato mais
+conciso do que o comando @code{status} mostra, você
+pode invocar
+
+@c <en>@cindex update, to display file status
+@cindex update, para mostrar o estado dos arquivos
+@example
+$ cvs -n -q update
+@end example
+
+@c <en>The @samp{-n} option means to not actually do the
+@c <en>update, but merely to display statuses; the @samp{-q}
+@c <en>option avoids printing the name of each directory. For
+@c <en>more information on the @code{update} command, and
+@c <en>these options, see @ref{Invoking CVS}.
+A opção @samp{-n} significa fingir que faz a
+atualização, mas simplesmente mostrar o estado; a opção
+@samp{-q} suprime a exibição do nome de cada
+diretório. Para mais informações sobre o comando
+@code{update}, e opções, veja em @ref{Chamando o CVS}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Updating a file
+@node Atualizando um arquivo
+@c <en>@section Bringing a file up to date
+@section Deixando um arquivo atualizado
+@c <en>@cindex Bringing a file up to date
+@cindex Deixando um arquivo atualizado
+@c <en>@cindex Updating a file
+@cindex Atualizando um arquivo
+@c <en>@cindex Merging a file
+@cindex Mesclando um arquivo
+@c <en>@cindex Update, introduction
+@cindex Update, introdução
+
+@c <en>When you want to update or merge a file, use the @code{update}
+@c <en>command. For files that are not up to date this is roughly equivalent
+@c <en>to a @code{checkout} command: the newest revision of the file is
+@c <en>extracted from the repository and put in your working directory.
+Quando você quiser atualizar ou mesclar um arquivo, use o
+comando @code{update}. Para arquivos que não estão
+atualizados isto é mais ou menos equivalente ao comando
+@code{checkout}: a revisão mais nova do arquivo é
+extraída do repositório e posta no diretório de trabalho.
+
+@c <en>Your modifications to a file are never lost when you
+@c <en>use @code{update}. If no newer revision exists,
+@c <en>running @code{update} has no effect. If you have
+@c <en>edited the file, and a newer revision is available,
+@c <en>@sc{cvs} will merge all changes into your working copy.
+Suas modificações num arquivo nunca são perdidas quando
+você usa @code{update}. Se não existe uma revisão mais
+nova, o @code{update} não faz nada. Se você
+editou o arquivo, e uma nova revisão está disponível, o
+@sc{cvs} vai mesclar todas as alterações na sua cópia
+de trabalho.
+
+@c <en>For instance, imagine that you checked out revision 1.4 and started
+@c <en>editing it. In the meantime someone else committed revision 1.5, and
+@c <en>shortly after that revision 1.6. If you run @code{update} on the file
+@c <en>now, @sc{cvs} will incorporate all changes between revision 1.4 and 1.6 into
+@c <en>your file.
+Por exemplo, imagine que você ???checked out??? a
+revisão 1.4 e começou a editá-la. Enquanto isto, outra
+pessoa ???committed??? a revisão 1.5, e logo depois a
+revisão 1.6. Se você rodar @code{update} no arquivo
+agora, o @sc{cvs} vai incorporar todas as mudanças
+entre a revisão 1.4 e 1.6 no seu arquivo.
+
+@c <en>@cindex Overlap
+@cindex Sobreposição
+@c <en>If any of the changes between 1.4 and 1.6 were made too
+@c <en>close to any of the changes you have made, an
+@c <en>@dfn{overlap} occurs. In such cases a warning is
+@c <en>printed, and the resulting file includes both
+@c <en>versions of the lines that overlap, delimited by
+@c <en>special markers.
+@c <en>@xref{update}, for a complete description of the
+@c <en>@code{update} command.
+Se quaisquer das mudanças entre 1.4 e 1.6 ocorreram
+suficientemente próximas de quaisquer das suas
+mudanças, uma @dfn{sobreposição} ocorre. Nestes casos
+um aviso é mostrado, e o arquivo resultante contém
+ambas as versões das linhas que se sobrepuseram,
+delimitadas por marcadores especiais. @xref{update},
+para uma descrição completa do comando @code{update}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Conflicts example
+@node Exemplo de conflitos
+@c <en>@section Conflicts example
+@section Exemplo de conflitos
+@c <en>@cindex Merge, an example
+@cindex Merge, an example
+@c <en>@cindex Example of merge
+@cindex Example of merge
+@c <en>@cindex driver.c (merge example)
+@cindex driver.c (merge example)
+
+@c <en>Suppose revision 1.4 of @file{driver.c} contains this:
+Suponha que a revisão 1.4 de @file{driver.c} contém isto:
+
+@example
+#include <stdio.h>
+
+void main()
+@{
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? 0 : 1);
+@}
+@end example
+
+@noindent
+@c <en>Revision 1.6 of @file{driver.c} contains this:
+A revisão 1.6 de @file{driver.c} contém isto:
+
+@example
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(!!nerr);
+@}
+@end example
+
+@noindent
+@c <en>Your working copy of @file{driver.c}, based on revision
+@c <en>1.4, contains this before you run @samp{cvs update}:
+@c <en>@c -- Really include "cvs"?
+Sua cópia de trabalho de @file{driver.c}, baseada na
+revisão 1.4, contém isto, antes de você rodar um @samp{cvs update}:
+@c -- Really include "cvs"?
+
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+void main()
+@{
+ init_scanner();
+ parse();
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@}
+@end example
+
+@noindent
+@c <en>You run @samp{cvs update}:
+@c <en>@c -- Really include "cvs"?
+Então você roda o @samp{cvs update}:
+@c -- Really include "cvs"?
+
+@example
+$ cvs update driver.c
+RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v
+retrieving revision 1.4
+retrieving revision 1.6
+Merging differences between 1.4 and 1.6 into driver.c
+rcsmerge warning: overlaps during merge
+cvs update: conflicts found in driver.c
+C driver.c
+@end example
+
+@noindent
+@c <en>@cindex Conflicts (merge example)
+@cindex Conflitos (exemplo de mesclagem)
+@c <en>@sc{cvs} tells you that there were some conflicts.
+@c <en>Your original working file is saved unmodified in
+@c <en>@file{.#driver.c.1.4}. The new version of
+@c <en>@file{driver.c} contains this:
+O @sc{cvs} disse a você que existem conflitos.
+Seu arquivo de trabalho original é guardado sem
+modificações em @file{.#driver.c.1.4}. A nova versão
+de @file{driver.c} contém isto:
+
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ init_scanner();
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+@asis{}<<<<<<< driver.c
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@asis{}=======
+ exit(!!nerr);
+@asis{}>>>>>>> 1.6
+@}
+@end example
+
+@noindent
+@c <en>@cindex Markers, conflict
+@cindex Marcadores, conflito
+@c <en>@cindex Conflict markers
+@cindex Marcadores de conflito
+@c <en>@cindex <<<<<<<
+@cindex <<<<<<<
+@c <en>@cindex >>>>>>>
+@cindex >>>>>>>
+@c <en>@cindex =======
+@cindex =======
+
+@c <en>Note how all non-overlapping modifications are incorporated in your working
+@c <en>copy, and that the overlapping section is clearly marked with
+@c <en>@samp{<<<<<<<}, @samp{=======} and @samp{>>>>>>>}.
+Observe como todas as modificações sem sobreposição
+foram incorporadas na sua cópia de trabalho, e que as
+seções com sobreposição são marcadas de forma clara com
+@samp{<<<<<<<}, @samp{=======} e @samp{>>>>>>>}.
+
+@c <en>@cindex Resolving a conflict
+@cindex Resolvendo um conflito
+@c <en>@cindex Conflict resolution
+@cindex Resolução de conflitos
+@c <en>You resolve the conflict by editing the file, removing the markers and
+@c <en>the erroneous line. Suppose you end up with this file:
+@c <en>@c -- Add xref to the pcl-cvs manual when it talks
+@c <en>@c -- about this.
+Você resolve o conflito editando o arquivo, removendo os
+marcadores e as linhas erradas. Suponha que você ficou
+com este arquivo:
+@c -- Add xref to the pcl-cvs manual when it talks
+@c -- about this.
+@example
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc,
+ char **argv)
+@{
+ init_scanner();
+ parse();
+ if (argc != 1)
+ @{
+ fprintf(stderr, "tc: No args expected.\n");
+ exit(1);
+ @}
+ if (nerr == 0)
+ gencode();
+ else
+ fprintf(stderr, "No code generated.\n");
+ exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+@}
+@end example
+
+@noindent
+@c <en>You can now go ahead and commit this as revision 1.7.
+Você agora pode seguir em frente e ???commit??? ele
+como a revisão 1.7.
+
+@example
+$ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c
+Checking in driver.c;
+/usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c
+new revision: 1.7; previous revision: 1.6
+done
+@end example
+
+@c <en>For your protection, @sc{cvs} will refuse to check in a
+@c <en>file if a conflict occurred and you have not resolved
+@c <en>the conflict. Currently to resolve a conflict, you
+@c <en>must change the timestamp on the file. In previous
+@c <en>versions of @sc{cvs}, you also needed to
+@c <en>insure that the file contains no conflict markers.
+@c <en>Because
+@c <en>your file may legitimately contain conflict markers (that
+@c <en>is, occurrences of @samp{>>>>>>> } at the start of a
+@c <en>line that don't mark a conflict), the current
+@c <en>version of @sc{cvs} will print a warning and proceed to
+@c <en>check in the file.
+Para sua segurança, o @sc{cvs} não vai aceitar o check
+in de um arquivo se um conflito ocorreu e você não
+resolveu o conflito. Atualmente, para resolver um
+conflito, você deve mudar a data do arquivo. Em
+versões anteriores do @sc{cvs}, você também precisava
+ter certeza de que o arquivo não continha marcadores de
+conflito. Já que seu arquivo pode conter marcadores de
+conflito ???de forma legítima??? (isto é, a ocorrência
+de @samp{>>>>>>> } no começo de uma linha que não marca
+um conflito), a versão atual do @sc{cvs} vai mostrar um
+aviso e continuar a fazer o ???check in??? do arquivo.
+@c The old behavior was really icky; the only way out
+@c was to start hacking on
+@c the @code{CVS/Entries} file or other such workarounds.
+@c
+@c If the timestamp thing isn't considered nice enough,
+@c maybe there should be a "cvs resolved" command
+@c which clears the conflict indication. For a nice user
+@c interface, this should be invoked by an interactive
+@c merge tool like emerge rather than by the user
+@c directly--such a tool can verify that the user has
+@c really dealt with each conflict.
+
+@c <en>@cindex emerge
+@cindex emerge
+@c <en>If you use release 1.04 or later of pcl-cvs (a @sc{gnu}
+@c <en>Emacs front-end for @sc{cvs}) you can use an Emacs
+@c <en>package called emerge to help you resolve conflicts.
+@c <en>See the documentation for pcl-cvs.
+Se você usa a release 1.04 ou posterior do pcl-cvs (uma
+interface amigável para o @sc{cvs} de dentro do
+@sc{gnu} Emacs) você pode usar um pacote do Emacs
+chamado emerge para te ajudar a resolver os
+conflitos. Veja na documentação do pcl-cvs.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Informing others
+@node Informando os outros
+@c <en>@section Informing others about commits
+@section Informando os outros sobre ???commits???
+@c <en>@cindex Informing others
+@cindex Informando os outros
+@c <en>@cindex Spreading information
+@cindex Divulgando informação
+@c <en>@cindex Mail, automatic mail on commit
+@cindex e-mail, mensagens automáticas no ???commit???
+
+@c <en>It is often useful to inform others when you commit a
+@c <en>new revision of a file. The @samp{-i} option of the
+@c <en>@file{modules} file, or the @file{loginfo} file, can be
+@c <en>used to automate this process. @xref{modules}.
+@c <en>@xref{loginfo}. You can use these features of @sc{cvs}
+@c <en>to, for instance, instruct @sc{cvs} to mail a
+@c <en>message to all developers, or post a message to a local
+@c <en>newsgroup.
+Às vezes é útil informar os outros quando você
+???commit??? uma nova revisão de um arquivo. A opção
+@samp{-i} do arquivo @file{modules}, ou do arquivo
+@file{loginfo}, pode ser usada para automatizar este
+processo. @xref{modules}. @xref{loginfo}. Você pode
+usar estas funcionalidades do @sc{cvs} para, por
+exemplo, instruir o @sc{cvs} a enviar uma mensagem a
+todos os desenvolvedores, ou enviar uma mensagem para
+um newsgroup local.
+@c -- More text would be nice here.
+
+@c <en>@node Concurrency
+@node Concorrência
+@c <en>@section Several developers simultaneously attempting to run CVS
+@section Vários desenvolvedores tentando rodar o CVS simultâneamente
+
+@c <en>@cindex Locks, cvs, introduction
+@cindex Locks, cvs, introdução
+@c For a discussion of *why* CVS creates locks, see
+@c the comment at the start of src/lock.c
+@c <en>If several developers try to run @sc{cvs} at the same
+@c <en>time, one may get the following message:
+Se vários desenvolvedores tentam rodar o @sc{cvs} no
+mesmo momento, alguém vai receber esta mensagem:
+
+@example
+[11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo
+@end example
+
+@c <en>@cindex #cvs.rfl, removing
+@cindex #cvs.rfl, removendo
+@c <en>@cindex #cvs.wfl, removing
+@cindex #cvs.wfl, removendo
+@c <en>@cindex #cvs.lock, removing
+@cindex #cvs.lock, removendo
+@c <en>@sc{cvs} will try again every 30 seconds, and either
+@c <en>continue with the operation or print the message again,
+@c <en>if it still needs to wait. If a lock seems to stick
+@c <en>around for an undue amount of time, find the person
+@c <en>holding the lock and ask them about the cvs command
+@c <en>they are running. If they aren't running a cvs
+@c <en>command, look in the repository directory mentioned in
+@c <en>the message and remove files which they own whose names
+@c <en>start with @file{#cvs.rfl},
+@c <en>@file{#cvs.wfl}, or @file{#cvs.lock}.
+O @sc{cvs} vai tentar de novo a cada 30 segundos, e vai
+ou continuar com a operação ou mostrar a mensagem de
+novo, se ainda precisar esperar. Se uma trava (lock)
+permanece por muito tempo, procure a pessoa que é dona
+da trava e pergunte que comando do cvs ele está
+rodando. Se ele/ela não estiver rodando um comando do
+cvs, procure no diretório do repositório que está
+referenciado na mensagem e remova os arquivos cujos
+nomes começam com @file{#cvs.rfl},
+@file{#cvs.wfl}, or @file{#cvs.lock}.
+
+@c <en>Note that these locks are to protect @sc{cvs}'s
+@c <en>internal data structures and have no relationship to
+@c <en>the word @dfn{lock} in the sense used by
+@c <en>@sc{rcs}---which refers to reserved checkouts
+@c <en>(@pxref{Multiple developers}).
+Observe que estas travas são feitas para proteger a
+estrutura de dados interna do @sc{cvs} e não tem
+relação com a palavra @dfn{lock (trava)} no sentido
+usado pelo @sc{rcs}---que se refere a ???checkouts???
+reservados (@pxref{Múltiplos desenvolvedores}).
+
+@c <en>Any number of people can be reading from a given
+@c <en>repository at a time; only when someone is writing do
+@c <en>the locks prevent other people from reading or writing.
+Qualquer quantidade de pessoas pode ler de um
+repositório num determinado momento; apenas quando
+alguém está gravando é que as travas evitam que outras
+pessoas leiam ou gravem.
+
+@c <en>@cindex Atomic transactions, lack of
+@cindex Transações atômicas, falta de
+@c <en>@cindex Transactions, atomic, lack of
+@cindex Atômicas, transações, falta de
+@c the following talks about what one might call commit/update
+@c atomicity.
+@c Probably also should say something about
+@c commit/commit atomicity, that is, "An update will
+@c not get partial versions of more than one commit".
+@c CVS currently has this property and I guess we can
+@c make it a documented feature.
+@c For example one person commits
+@c a/one.c and b/four.c and another commits a/two.c and
+@c b/three.c. Then an update cannot get the new a/one.c
+@c and a/two.c and the old b/four.c and b/three.c.
+@c <en>One might hope for the following property:
+Espera-se que a seguinte propriedade valha:
+
+@quotation
+@c <en>If someone commits some changes in one cvs command,
+@c <en>then an update by someone else will either get all the
+@c <en>changes, or none of them.
+Se alguém ???commits??? algumas mudanças com um comando
+cvs, então um ???update??? por outra pessoa vai obter
+ou todas as mudanças, ou nenhuma.
+@end quotation
+
+@noindent
+@c <en>but @sc{cvs} does @emph{not} have this property. For
+@c <en>example, given the files
+mas o @sc{cvs} @emph{não} tem esta propriedade. Por
+exemplo, dados os arquivos
+
+@example
+a/one.c
+a/two.c
+b/three.c
+b/four.c
+@end example
+
+@noindent
+@c <en>if someone runs
+se alguém rodar
+
+@example
+cvs ci a/two.c b/three.c
+@end example
+
+@noindent
+@c <en>and someone else runs @code{cvs update} at the same
+@c <en>time, the person running @code{update} might get only
+@c <en>the change to @file{b/three.c} and not the change to
+@c <en>@file{a/two.c}.
+e outra pessoa rodar @code{cvs update} no mesmo
+momento, a pessoa rodando @code{update} pode receber
+apenas as alterações feitas em @file{b/three.c} e não
+receber as feitas em @file{a/two.c}.
+
+@c <en>@node Watches
+@node ???Watches???
+@c <en>@section Mechanisms to track who is editing files
+@section Mechanisms to track who is editing files
+@c <en>@cindex Watches
+@cindex ???Watches???
+
+@c <en>For many groups, use of @sc{cvs} in its default mode is
+@c <en>perfectly satisfactory. Users may sometimes go to
+@c <en>check in a modification only to find that another
+@c <en>modification has intervened, but they deal with it and
+@c <en>proceed with their check in. Other groups prefer to be
+@c <en>able to know who is editing what files, so that if two
+@c <en>people try to edit the same file they can choose to
+@c <en>talk about who is doing what when rather than be
+@c <en>surprised at check in time. The features in this
+@c <en>section allow such coordination, while retaining the
+@c <en>ability of two developers to edit the same file at the
+@c <en>same time.
+Para muitos grupos, o uso do @sc{cvs} em sua forma
+padrão é perfeitamente satisfatório. Os usuários vão
+algumas vezes ???check in??? uma modificação e
+descobrir que outras intervenções foram feitas, mas
+eles tratam isto e seguem em frente com o ???check
+in???. Outros grupos preferem ser capazes de saber
+quem está editando quais arquivos, de forma que se duas
+pessoas tentam editar o mesmo arquivo elas podem
+conversar sobre quem vai editar o que ao invés de serem
+surpreendidos na hora do ???check in???. As
+funcionalidades nesta seção permitem tal nível de
+coordenação, sem abrir mão da possibilidade de que dois
+desenvolvedores editem o mesmo arquivo ao mesmo tempo.
+
+@c Some people might ask why CVS does not enforce the
+@c rule on chmod, by requiring a cvs edit before a cvs
+@c commit. The main reason is that it could always be
+@c circumvented--one could edit the file, and
+@c then when ready to check it in, do the cvs edit and put
+@c in the new contents and do the cvs commit. One
+@c implementation note: if we _do_ want to have cvs commit
+@c require a cvs edit, we should store the state on
+@c whether the cvs edit has occurred in the working
+@c directory, rather than having the server try to keep
+@c track of what working directories exist.
+@c FIXME: should the above discussion be part of the
+@c manual proper, somewhere, not just in a comment?
+@c <en>For maximum benefit developers should use @code{cvs
+@c <en>edit} (not @code{chmod}) to make files read-write to
+@c <en>edit them, and @code{cvs release} (not @code{rm}) to
+@c <en>discard a working directory which is no longer in use,
+@c <en>but @sc{cvs} is not able to enforce this behavior.
+Para um máximo apreveitamento, os desenvolvedores devem
+usar @code{cvs edit} (e não @code{chmod}) para tornar
+os arquivos com permissão de leitura e escrita para
+editá-los, e @code{cvs release} (não @code{rm}) para
+descartar um diretório de trabalho que não está mais em
+uso, mas o @sc{cvs} não é capaz de obrigar tal
+comportamento.
+
+@c I'm a little dissatisfied with this presentation,
+@c because "watch on"/"edit"/"editors" are one set of
+@c functionality, and "watch add"/"watchers" is another
+@c which is somewhat orthogonal even though they interact in
+@c various ways. But I think it might be
+@c confusing to describe them separately (e.g. "watch
+@c add" with loginfo). I don't know.
+
+@menu
+@c <en>* Setting a watch:: Telling CVS to watch certain files
+* Ajustando um ???watch???:: Dizendo ao CVS para ???watch??? certos arquivos
+@c <en>* Getting Notified:: Telling CVS to notify you
+* Recebendo Notificações:: Dizendo ao CVS para te notificar
+@c <en>* Editing files:: How to edit a file which is being watched
+* Editando arquivos:: Como editar um arquivo que está sendo ???watched???
+@c <en>* Watch information:: Information about who is watching and editing
+* Informações de ???Watch???:: Informações a respeito de quem
+ está ???watching??? e quem está editando
+@c <en>* Watches Compatibility:: Watches interact poorly with CVS 1.6 or earlier
+* Compatibilidade de ???Watches???:: ???Watches??? interagem fracamente
+ com CVS 1.6 ou anteriores
+@end menu
+
+@c <en>@node Setting a watch
+@node Ajustando um ???watch???
+@c <en>@subsection Telling CVS to watch certain files
+@subsection Dizendo ao CVS para ???watch??? certos arquivos
+
+@c <en>To enable the watch features, you first specify that
+@c <en>certain files are to be watched.
+Para habilitar a funcionalidade de ???watch???, você
+deve primeiro especificar que certos arquivos devem ser
+???watched???.
+
+@c <en>@cindex watch on (subcommand)
+@cindex watch on (subcomando)
+@c <en>@deffn Command {cvs watch on} [@code{-lR}] [@var{files}]@dots{}
+@deffn Comando {cvs watch on} [@code{-lR}] [@var{arquivos}]@dots{}
+
+@c <en>@cindex Read-only files, and watches
+@cindex Arquivos somente leitura, e ???watches???
+@c <en>Specify that developers should run @code{cvs edit}
+@c <en>before editing @var{files}. @sc{cvs} will create working
+@c <en>copies of @var{files} read-only, to remind developers
+@c <en>to run the @code{cvs edit} command before working on
+@c <en>them.
+Especifique que os desenvolvedores devem rodar o
+@code{cvs edit} antes de editar arquivos
+@var{arquivos}. O @sc{cvs} vai criar cópias de
+trabalho dos @var{arquivos} como somente-leitura, para
+lembrar os desenvolvedores de rodarem o comando
+@code{cvs edit} antes de trabalhar neles.
+
+@c <en>If @var{files} includes the name of a directory, @sc{cvs}
+@c <en>arranges to watch all files added to the corresponding
+@c <en>repository directory, and sets a default for files
+@c <en>added in the future; this allows the user to set
+@c <en>notification policies on a per-directory basis. The
+@c <en>contents of the directory are processed recursively,
+@c <en>unless the @code{-l} option is given.
+@c <en>The @code{-R} option can be used to force recursion if the @code{-l}
+@c <en>option is set in @file{~/.cvsrc} (@pxref{~/.cvsrc}).
+Se @var{arquivos} inclui o nome de uma diretório, o
+@sc{cvs} faz ???watch??? em todos os arquivos
+adicionados ao diretório correspondente do repositório,
+e ajusta um padrão para arquivos adicionados no futuro;
+isto permite que o usuário ajuste as políticas de
+notificação baseada em diretórios. O conteúdo do
+diretório é processado recursivamente, a menos que a
+opção @code{-l} seja dada. A opção @code{-R} pode ser
+usada para forçar recursão se a opção @code{-l} está
+ativada em @file{~/.cvsrc} (@pxref{~/.cvsrc}).
+
+@c <en>If @var{files} is omitted, it defaults to the current directory.
+Se @var{arquivos} é omitido, o padrão é o diretório atual.
+
+@c <en>@cindex watch off (subcommand)
+@cindex watch off (subcomando)
+@end deffn
+
+@c <en>@deffn Command {cvs watch off} [@code{-lR}] [@var{files}]@dots{}
+@deffn Comando {cvs watch off} [@code{-lR}] [@var{arquivos}]@dots{}
+
+@c <en>Do not create @var{files} read-only on checkout; thus,
+@c <en>developers will not be reminded to use @code{cvs edit}
+@c <en>and @code{cvs unedit}.
+Não cria @var{arquivos} somente-leitura no
+???checkout???; portanto, os desenvolvedores não serão
+lembrados de usar @code{cvs edit} e @code{cvs unedit}.
+@ignore
+@sc{cvs} will check out @var{files}
+read-write as usual, unless other permissions override
+due to the @code{PreservePermissions} option being
+enabled in the @file{config} administrative file
+(@pxref{Special Files}, @pxref{config})
+@end ignore
+
+@c <en>The @var{files} and options are processed as for @code{cvs
+@c <en>watch on}.
+Os @var{arquivos} e opções são processados como no
+@code{cvs watch on}.
+
+@end deffn
+
+@c <en>@node Getting Notified
+@node Recebendo Notificações
+@c <en>@subsection Telling CVS to notify you
+@subsection Dizendo ao CVS para te notificar
+
+@c <en>You can tell @sc{cvs} that you want to receive
+@c <en>notifications about various actions taken on a file.
+@c <en>You can do this without using @code{cvs watch on} for
+@c <en>the file, but generally you will want to use @code{cvs
+@c <en>watch on}, to remind developers to use the @code{cvs edit}
+@c <en>command.
+Você pode dizer ao @sc{cvs} que você quer receber
+notificações sobre várias ações tomadas em um
+arquivo. Você pode fazer isto sem usar o @code{cvs
+watch on} para o arquivo, mas geralmente você vai
+querer usar @code{cvs watch on}, para lembrar os
+desenvolvedores de usar o comando @code{cvs edit}.
+
+@c <en>@cindex watch add (subcommand)
+@cindex watch add (subcomando)
+@c <en>@deffn Command {cvs watch add} [@code{-lR}] [@code{-a} @var{action}]@dots{} [@var{files}]@dots{}
+@deffn Comando {cvs watch add} [@code{-lR}] [@code{-a} @var{ação}]@dots{} [@var{arquivos}]@dots{}
+
+@c <en>Add the current user to the list of people to receive notification of
+@c <en>work done on @var{files}.
+Adiciona o usuário atual à lista de pessoas que recebem
+notificações sobre o trabalho feito em @var{arquivos}.
+
+@c <en>The @code{-a} option specifies what kinds of events @sc{cvs} should notify
+@c <en>the user about. @var{action} is one of the following:
+A opção @code{-a} especifica quais tipos de eventos o
+@sc{cvs} deve notificar o usuário. @var{ação} é uma
+das seguintes:
+
+@table @code
+
+@c <en>@item edit
+@item edit
+@c <en>Another user has applied the @code{cvs edit} command (described
+@c <en>below) to a watched file.
+Outro usuário executou o comando @code{cvs edit}
+(descrito abaixo) para um arquivo ???watched???.
+
+@c <en>@item commit
+@item commit
+@c <en>Another user has committed changes to one of the named @var{files}.
+Outro usuário fez ???commit??? em mudanças em um dos @var{arquivos}.
+
+@c <en>@item unedit
+@item unedit
+@c <en>Another user has abandoned editing a file (other than by committing changes).
+@c <en>They can do this in several ways, by:
+Outro usuário abandonou a edição de um arquivo (sem ser
+por ???committing??? mudanças). Eles podem fazer isto
+de várias maneiras:
+
+@itemize @bullet
+
+@item
+@c <en>applying the @code{cvs unedit} command (described below) to the file
+rodando o comando @code{cvs unedit} (descrito abaixo)
+no arquivo
+
+@item
+@c <en>applying the @code{cvs release} command (@pxref{release}) to the file's parent directory
+@c <en>(or recursively to a directory more than one level up)
+rodando o comando @code{cvs release} (@pxref{release})
+no diretório pai do arquivo
+(ou num diretório mais acima recursivamente)
+
+@item
+@c <en>deleting the file and allowing @code{cvs update} to recreate it
+apagando o arquivo e permitindo que o @code{cvs update} o recrie
+
+@end itemize
+
+@c <en>@item all
+@item all
+@c <en>All of the above.
+Todos acima.
+
+@c <en>@item none
+@item none
+@c <en>None of the above. (This is useful with @code{cvs edit},
+@c <en>described below.)
+Nenhum dos acima. (Isto é útil com o @code{cvs edit},
+descrito abaixo.)
+
+@end table
+
+@c <en>The @code{-a} option may appear more than once, or not at all. If
+@c <en>omitted, the action defaults to @code{all}.
+A opção @code{-a} pode aparecer mais de uma vez, ou
+nenhuma vez. Se não aparecer, a ação padrão é @code{all}.
+
+@c <en>The @var{files} and options are processed as for
+@c <en>@code{cvs watch on}.
+Os @var{arquivos} e opções são processados como no
+@code{cvs watch on}.
+
+@end deffn
+
+
+@c <en>@cindex watch remove (subcommand)
+@cindex watch remove (subcomando)
+@c <en>@deffn Command {cvs watch remove} [@code{-lR}] [@code{-a} @var{action}]@dots{} [@var{files}]@dots{}
+@deffn Comando {cvs watch remove} [@code{-lR}] [@code{-a} @var{ação}]@dots{} [@var{arquivos}]@dots{}
+
+@c <en>Remove a notification request established using @code{cvs watch add};
+@c <en>the arguments are the same. If the @code{-a} option is present, only
+@c <en>watches for the specified actions are removed.
+Remove um pedido de notificação posto por um @code{cvs
+watch add}; Os argumentos são os mesmos. Se a opção
+@code{-a} está presente, apenas os ???watches??? para as
+ações especificadas são removidos.
+
+@end deffn
+
+@c <en>@cindex notify (admin file)
+@cindex notify (arquivo administrativo)
+@c <en>When the conditions exist for notification, @sc{cvs}
+@c <en>calls the @file{notify} administrative file. Edit
+@c <en>@file{notify} as one edits the other administrative
+@c <en>files (@pxref{Intro administrative files}). This
+@c <en>file follows the usual conventions for administrative
+@c <en>files (@pxref{syntax}), where each line is a regular
+@c <en>expression followed by a command to execute. The
+@c <en>command should contain a single occurrence of @samp{%s}
+@c <en>which will be replaced by the user to notify; the rest
+@c <en>of the information regarding the notification will be
+@c <en>supplied to the command on standard input. The
+@c <en>standard thing to put in the @code{notify} file is the
+@c <en>single line:
+Quando as condições existem para a notificação, o
+@sc{cvs} chama o arquivo administrativo @file{notify}.
+Edite o @file{notify} da mesma forma que se edita os
+outros arquivos administrativos (@pxref{Intro aos
+arquivos administrativos}). Este arquivo segue as
+convenções usuais para arquivos administrativos
+(@pxref{syntax}), onde cada linha é uma expressão
+regular seguida de um comando para executar. O comando
+pode conter uma única ocorrência de @samp{%s} que é
+substituída pelo usuário a ser notificado; o resto da
+informação a respeito da notificação vai ser fornecida
+ao comando na entrada padrão. O padrão para botar no
+arquivo @code{notify} é esta única linha:
+
+@example
+ALL mail %s -s "CVS notification"
+@end example
+
+@noindent
+@c <en>This causes users to be notified by electronic mail.
+Isto faz com que os usuários sejam avisados por correio
+eletrônico.
+@c FIXME: should it be this hard to set up this
+@c behavior (and the result when one fails to do so,
+@c silent failure to notify, so non-obvious)? Should
+@c CVS give a warning if no line in notify matches (and
+@c document the use of "DEFAULT :" for the case where
+@c skipping the notification is indeed desired)?
+
+@c <en>@cindex users (admin file)
+@cindex users (arquivo administrativo)
+@c <en>Note that if you set this up in the straightforward
+@c <en>way, users receive notifications on the server machine.
+@c <en>One could of course write a @file{notify} script which
+@c <en>directed notifications elsewhere, but to make this
+@c <en>easy, @sc{cvs} allows you to associate a notification
+@c <en>address for each user. To do so create a file
+@c <en>@file{users} in @file{CVSROOT} with a line for each
+@c <en>user in the format @var{user}:@var{value}. Then
+@c <en>instead of passing the name of the user to be notified
+@c <en>to @file{notify}, @sc{cvs} will pass the @var{value}
+@c <en>(normally an email address on some other machine).
+Observe que se você ajusta isto na forma que está, os
+usuários vão receber as notificações na máquina
+servidora. Alguém pode escrever um script
+@file{notify} que direcione notificações para outro
+lugar, mas para tornar isto fácil, o @sc{cvs} permite
+associar um endereço de notificação para cada usuário.
+Para isto crie um arquivo @file{users} em
+@file{CVSROOT} com uma linha para cada usuário no
+formato @var{usuário}:@var{valor}. Então, ao invés de
+passar o nome do usuário a ser notificado para
+@file{notify}, o @sc{cvs} vai passar @var{valor}
+(normalmente um endereço de email em alguma outra máquina).
+
+@c <en>@sc{cvs} does not notify you for your own changes.
+@c <en>Currently this check is done based on whether the user
+@c <en>name of the person taking the action which triggers
+@c <en>notification matches the user name of the person
+@c <en>getting notification. In fact, in general, the watches
+@c <en>features only track one edit by each user. It probably
+@c <en>would be more useful if watches tracked each working
+@c <en>directory separately, so this behavior might be worth
+@c <en>changing.
+O @sc{cvs} não notifica você de suas próprias
+mudanças. Atualmente esta checagem é feita baseada
+comparando o nome de usuário da pessoa que executou a
+ação que disparou a notificação com o nome de usuário
+da pessoa sendo notificada. De fato, em geral, as
+funcionalidades de ???watches??? ???only track one
+edit??? para cada usuário. Seria provavelmente mais
+útil se ???watches??? ???tracked??? cada diretório de
+trabalho separadamente, logo este comportamento ???might be worth
+changing???.
+@c "behavior might be worth changing" is an effort to
+@c point to future directions while also not promising
+@c that "they" (as in "why don't they fix CVS to....")
+@c will do this.
+@c one implementation issue is identifying whether a
+@c working directory is same or different. Comparing
+@c pathnames/hostnames is hopeless, but having the server
+@c supply a serial number which the client stores in the
+@c CVS directory as a magic cookie should work.
+
+@c <en>@node Editing files
+@node Editando arquivos
+@c <en>@subsection How to edit a file which is being watched
+@subsection Como editar um arquivo que está sendo ???watched???
+
+@c <en>@cindex Checkout, as term for getting ready to edit
+@cindex Checkout, as term for getting ready to edit
+@c <en>Since a file which is being watched is checked out
+@c <en>read-only, you cannot simply edit it. To make it
+@c <en>read-write, and inform others that you are planning to
+@c <en>edit it, use the @code{cvs edit} command. Some systems
+@c <en>call this a @dfn{checkout}, but @sc{cvs} uses that term
+@c <en>for obtaining a copy of the sources (@pxref{Getting the
+@c <en>source}), an operation which those systems call a
+@c <en>@dfn{get} or a @dfn{fetch}.
+Já que um arquivo que está sendo ???watched??? é
+???checked out??? somente-leitura, você não pode
+simplesmente editá-lo. Para torná-lo leitura-escrita,
+e informaar outros que você está planejando editá-lo,
+use o comando @code{cvs edit}. Alguns sistemas chamam
+isto de @dfn{checkout}, mas o @sc{cvs} usa este termo
+para obter uma cópia dos fontes (@pxref{Obtendo os
+fontes}), uma operação que estes sistemas chamam de
+@dfn{get} ou @dfn{fetch}.
+@c Issue to think about: should we transition CVS
+@c towards the "get" terminology? "cvs get" is already a
+@c synonym for "cvs checkout" and that section of the
+@c manual refers to "Getting the source". If this is
+@c done, needs to be done gingerly (for example, we should
+@c still accept "checkout" in .cvsrc files indefinitely
+@c even if the CVS's messages are changed from "cvs checkout: "
+@c to "cvs get: ").
+@c There is a concern about whether "get" is not as
+@c good for novices because it is a more general term
+@c than "checkout" (and thus arguably harder to assign
+@c a technical meaning for).
+
+@c <en>@cindex edit (subcommand)
+@cindex edit (subcomando)
+@c <en>@deffn Command {cvs edit} [@code{-lR}] [@code{-a} @var{action}]@dots{} [@var{files}]@dots{}
+@deffn Comando {cvs edit} [@code{-lR}] [@code{-a} @var{ação}]@dots{} [@var{arquivos}]@dots{}
+
+@c <en>Prepare to edit the working files @var{files}. @sc{cvs} makes the
+@c <en>@var{files} read-write, and notifies users who have requested
+@c <en>@code{edit} notification for any of @var{files}.
+Prepara para serem editados os @var{files} do diretório
+de trabalho. O @sc{cvs} faz os @var{arquivos}
+leitura-escrita, e notifica os usuários que pediram
+notificação de @code{edit} para quaisquer dos @var{arquivos}.
+
+@c <en>The @code{cvs edit} command accepts the same options as the
+@c <en>@code{cvs watch add} command, and establishes a temporary watch for the
+@c <en>user on @var{files}; @sc{cvs} will remove the watch when @var{files} are
+@c <en>@code{unedit}ed or @code{commit}ted. If the user does not wish to
+@c <en>receive notifications, she should specify @code{-a none}.
+O comando @code{cvs edit} acita as mesmas opções que o
+comando @code{cvs watch add}, e estabelece um
+???watch??? temporário para o usuário nos
+@var{arquivos}; @sc{cvs} vai remover o ???watch??? quando @var{arquivos} forem
+@code{unedit}ados ou @code{commit}ados (argh!!!,
+''commitados'' é horrível). Se o usuário não deseja
+receber notificações, deve especificar @code{-a none}.
+
+@c <en>The @var{files} and the options are processed as for the @code{cvs
+@c <en>watch} commands.
+Os @var{arquivos} e as opções são processadas como nos comandos @code{cvs
+watch}.
+
+@ignore
+@strong{Caution: If the @code{PreservePermissions}
+option is enabled in the repository (@pxref{config}),
+@sc{cvs} will not change the permissions on any of the
+@var{files}. The reason for this change is to ensure
+that using @samp{cvs edit} does not interfere with the
+ability to store file permissions in the @sc{cvs}
+repository.}
+@end ignore
+
+@end deffn
+
+@c <en>Normally when you are done with a set of changes, you
+@c <en>use the @code{cvs commit} command, which checks in your
+@c <en>changes and returns the watched files to their usual
+@c <en>read-only state. But if you instead decide to abandon
+@c <en>your changes, or not to make any changes, you can use
+@c <en>the @code{cvs unedit} command.
+Normalmente quando você termina com um conjunto de
+mudanças, você usa o comando @code{cvs commit}, que
+???checks in??? suas mudanças e retorna os arquivos
+???watched??? a seus estados usuais de somente-leitura.
+Mas se você ao invés disto decide abandonar suas
+mudanças, ou não fazer nenhuma mudança, você pode usar
+o comando @code{cvs unedit}.
+
+@c <en>@cindex unedit (subcommand)
+@cindex unedit (subcomando)
+@c <en>@cindex Abandoning work
+@cindex Abandonando o trabalho
+@c <en>@cindex Reverting to repository version
+@cindex Revertendo para a versão do repositório
+@c <en>@deffn Command {cvs unedit} [@code{-lR}] [@var{files}]@dots{}
+@deffn Comando {cvs unedit} [@code{-lR}] [@var{arquivos}]@dots{}
+
+@c <en>Abandon work on the working files @var{files}, and revert them to the
+@c <en>repository versions on which they are based. @sc{cvs} makes those
+@c <en>@var{files} read-only for which users have requested notification using
+@c <en>@code{cvs watch on}. @sc{cvs} notifies users who have requested @code{unedit}
+@c <en>notification for any of @var{files}.
+Abandona o trabalho nos @var{arquivos} no diretório de
+tabalho, e reverte eles às versões do repositório nas
+quais eles foram baseados. O @sc{cvs} faz estes
+@var{arquivos} somente-leitura ???for which users have
+requested notification??? usando @code{cvs watch on}.
+@sc{cvs} notifica os usuários que pediram notificações
+do tipo @code{unedit} para quaisquer dos @var{arquivos}.
+
+@c <en>The @var{files} and options are processed as for the
+@c <en>@code{cvs watch} commands.
+Os @var{arquivos} e opções são processados como nos comandos
+@code{cvs watch}.
+
+@c <en>If watches are not in use, the @code{unedit} command
+@c <en>probably does not work, and the way to revert to the
+@c <en>repository version is with the command @code{cvs update -C file}
+@c <en>(@pxref{update}).
+@c <en>The meaning is
+@c <en>not precisely the same; the latter may also
+@c <en>bring in some changes which have been made in the
+@c <en>repository since the last time you updated.
+Se ???watches??? não estão em uso, o comando
+@code{unedit} provavelmente não vai fazer nada, e a
+forma de reverter à versão do repositório é com o
+comando @code{cvs update -C arquivo} (@pxref{update}).
+O significado não é exatamente o mesmo; a última forma
+pode também trazer algumas mudanças que foram feitas no
+repositório desde a última vez que você atualizou (fez
+update).
+@c It would be a useful enhancement to CVS to make
+@c unedit work in the non-watch case as well.
+@end deffn
+
+@c <en>When using client/server @sc{cvs}, you can use the
+@c <en>@code{cvs edit} and @code{cvs unedit} commands even if
+@c <en>@sc{cvs} is unable to successfully communicate with the
+@c <en>server; the notifications will be sent upon the next
+@c <en>successful @sc{cvs} command.
+Quando usando o @sc{cvs} como cliente/servidor, você
+pode usar os comandos @code{cvs edit} e @code{cvs
+unedit} mesmo se o @sc{cvs} é incapaz de estabelecer
+comunicação com o servidor; as notificações vão ser
+mandadas junto com o próximo comando bem sucedido do
+@sc{cvs}.
+
+@c <en>@node Watch information
+@node Informações de ???Watch???
+@c <en>@subsection Information about who is watching and editing
+@subsection Informações sobre quem está ???watching??? e editando
+
+@c <en>@cindex watchers (subcommand)
+@cindex watchers (subcomando)
+@c <en>@deffn Command {cvs watchers} [@code{-lR}] [@var{files}]@dots{}
+@deffn Comando {cvs watchers} [@code{-lR}] [@var{arquivos}]@dots{}
+
+@c <en>List the users currently watching changes to @var{files}. The report
+@c <en>includes the files being watched, and the mail address of each watcher.
+Lista os usuários que estão atualmente ???watching???
+mudanças em @var{arquivos}. O relatório inclui os
+arquivos sendo ???watched???, e o endereço de e-mail de
+cada ???watcher???.
+
+@c <en>The @var{files} and options are processed as for the
+@c <en>@code{cvs watch} commands.
+Os @var{arquivos} e opções são processados como nos comandos
+@code{cvs watch}.
+
+@end deffn
+
+
+@c <en>@cindex editors (subcommand)
+@cindex editors (subcommand)
+@c <en>@deffn Command {cvs editors} [@code{-lR}] [@var{files}]@dots{}
+@deffn Command {cvs editors} [@code{-lR}] [@var{files}]@dots{}
+
+@c <en>List the users currently working on @var{files}. The report
+@c <en>includes the mail address of each user, the time when the user began
+@c <en>working with the file, and the host and path of the working directory
+@c <en>containing the file.
+Lista os usuários atualmente trabalhando em
+@var{arquivos}. O relatório inclui o endereço de
+e-mail de cada usuário, o momento no qual o usuário
+começou a trabalhar com o arquivo, e a máquina e
+caminho do diretório de trabalho contendo o arquivo.
+
+@c <en>The @var{files} and options are processed as for the
+@c <en>@code{cvs watch} commands.
+Os @var{arquivos} e opções são processados como nos comandos
+@code{cvs watch}.
+
+@end deffn
+
+@c <en>@node Watches Compatibility
+@node Compatibilidade de ???Watches???
+@c <en>@subsection Using watches with old versions of CVS
+@subsection Using watches with old versions of CVS
+
+@c <en>@cindex CVS 1.6, and watches
+@cindex CVS 1.6, and watches
+@c <en>If you use the watch features on a repository, it
+@c <en>creates @file{CVS} directories in the repository and
+@c <en>stores the information about watches in that directory.
+@c <en>If you attempt to use @sc{cvs} 1.6 or earlier with the
+@c <en>repository, you get an error message such as the
+@c <en>following (all on one line):
+If you use the watch features on a repository, it
+creates @file{CVS} directories in the repository and
+stores the information about watches in that directory.
+If you attempt to use @sc{cvs} 1.6 or earlier with the
+repository, you get an error message such as the
+following (all on one line):
+
+@example
+cvs update: cannot open CVS/Entries for reading:
+No such file or directory
+@end example
+
+@noindent
+@c <en>and your operation will likely be aborted. To use the
+@c <en>watch features, you must upgrade all copies of @sc{cvs}
+@c <en>which use that repository in local or server mode. If
+@c <en>you cannot upgrade, use the @code{watch off} and
+@c <en>@code{watch remove} commands to remove all watches, and
+@c <en>that will restore the repository to a state which
+@c <en>@sc{cvs} 1.6 can cope with.
+and your operation will likely be aborted. To use the
+watch features, you must upgrade all copies of @sc{cvs}
+which use that repository in local or server mode. If
+you cannot upgrade, use the @code{watch off} and
+@code{watch remove} commands to remove all watches, and
+that will restore the repository to a state which
+@sc{cvs} 1.6 can cope with.
+
+@c <en>@node Choosing a model
+@node Escolhendo um modelo
+@c <en>@section Choosing between reserved or unreserved checkouts
+@section Escolhendo entre ???checkouts??? reservados ou não-reservados
+@c <en>@cindex Choosing, reserved or unreserved checkouts
+@cindex Escolhendo, ???checkouts??? reservados ou não-reservados
+
+@c <en>Reserved and unreserved checkouts each have pros and
+@c <en>cons. Let it be said that a lot of this is a matter of
+@c <en>opinion or what works given different groups' working
+@c <en>styles, but here is a brief description of some of the
+@c <en>issues. There are many ways to organize a team of
+@c <en>developers. @sc{cvs} does not try to enforce a certain
+@c <en>organization. It is a tool that can be used in several
+@c <en>ways.
+???Checkouts??? reservados e não-reservados têem cada
+um prós e contras. Digamos que muito disto é
+uma questão de opinião ou que funciona dependendo dos
+diferentes estilos de trabalho em grupo, mas aqui está
+uma breve descrição de alguns dos aspectos. Existem
+muitas formas de organizar um time de desenvolvedores.
+O @sc{cvs} não tenta induzir uma determinada forma de se
+organizar. Ele é uma ferramenta que pode ser usada de
+várias maneiras.
+
+@c <en>Reserved checkouts can be very counter-productive. If
+@c <en>two persons want to edit different parts of a file,
+@c <en>there may be no reason to prevent either of them from
+@c <en>doing so. Also, it is common for someone to take out a
+@c <en>lock on a file, because they are planning to edit it,
+@c <en>but then forget to release the lock.
+Checkout reservado pode ser bastante improdutivo. Se
+duas pessoas quiserem editar diferentes partes de um
+mesmo arquivo, não há motivos para proibir nenhuma
+delas. Além disto, é normal alguém travar um arquivo
+por que planeja editá-lo, mas então esquecer de destravar.
+
+@c "many groups"? specifics? cites to papers on this?
+@c some way to weasel-word it a bit more so we don't
+@c need facts :-)?
+@c <en>People, especially people who are familiar with
+@c <en>reserved checkouts, often wonder how often conflicts
+@c <en>occur if unreserved checkouts are used, and how
+@c <en>difficult they are to resolve. The experience with
+@c <en>many groups is that they occur rarely and usually are
+@c <en>relatively straightforward to resolve.
+As pessoas, especialmente aquelas acostumadas com
+???checkouts??? reservados, freqüentemente pensam sobre
+a freqüencia com que conlitos acontecem quando
+???checkouts??? não-reservados estão em uso, e o quão
+difíceis eles são de resolver. A experiência de muitos
+grupos é que os conflitos ocorrem raramente e em geral
+são relativamente fáceis de resolver.
+
+@c <en>The rarity of serious conflicts may be surprising, until one realizes
+@c <en>that they occur only when two developers disagree on the proper design
+@c <en>for a given section of code; such a disagreement suggests that the
+@c <en>team has not been communicating properly in the first place. In order
+@c <en>to collaborate under @emph{any} source management regimen, developers
+@c <en>must agree on the general design of the system; given this agreement,
+@c <en>overlapping changes are usually straightforward to merge.
+A dificuldade para encontrar conflitos sérios pode ser
+surpreendente, até se perceber que eles ocorrem apenas
+quando dois desenvolvedores discordam mesmo é no
+projeto de uma dada seção do código; tal desacordo
+indica a princípio que a equipe não está se comunicando
+direito. Para colaborar em @emph{qualquer} regime de
+gerenciamento de código, os desenvolvedores devem
+concordar com o projeto geral do sistema; com este
+acordo, mudanças sobrepostas são em geral simples de
+mesclar.
+
+@c <en>In some cases unreserved checkouts are clearly
+@c <en>inappropriate. If no merge tool exists for the kind of
+@c <en>file you are managing (for example word processor files
+@c <en>or files edited by Computer Aided Design programs), and
+@c <en>it is not desirable to change to a program which uses a
+@c <en>mergeable data format, then resolving conflicts is
+@c <en>going to be unpleasant enough that you generally will
+@c <en>be better off to simply avoid the conflicts instead, by
+@c <en>using reserved checkouts.
+Em alguns casos, ???checkouts??? não-reservados são
+claramente inapropriados. Se não existe uma ferramenta
+de mescla para o tipo de arquivo que você está lidando
+(por exemplo, arquivos de processadores de texto ou
+arquivos editados por programas de ???Computer Aided
+Design???), e não é desejável mudar para um programa
+que usa um formato de dados que se possa mesclar, então
+resolver conflitos se torna tão desagradável que você
+vai estar melhor simplesmente evitando-os, com o uso de
+???checkouts??? não-reservados.
+
+@c <en>The watches features described above in @ref{Watches}
+@c <en>can be considered to be an intermediate model between
+@c <en>reserved checkouts and unreserved checkouts. When you
+@c <en>go to edit a file, it is possible to find out who else
+@c <en>is editing it. And rather than having the system
+@c <en>simply forbid both people editing the file, it can tell
+@c <en>you what the situation is and let you figure out
+@c <en>whether it is a problem in that particular case or not.
+@c <en>Therefore, for some groups it can be considered the
+@c <en>best of both the reserved checkout and unreserved
+@c <en>checkout worlds.
+As funcionalidade de ???watches??? descritas acima em
+@ref{???Watches???} podem ser consideradas um modelo
+intermediário entre ???checkouts??? reservados e
+???checkouts??? não-reservados. Quando você vai editar
+um arquivo, é possível descobrir quem o está editando.
+E ao invés de simplesmente o sistema proibir os dois de
+trabalhar, ele pode dizer como está a situação e deixar
+você decidir se isto é ou não é um problema neste caso
+específico. Portanto, para alguns grupos esta é o
+melhor dos dois mundos de ???checkouts??? reservados e
+???checkouts??? não-reservados.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Revision management
+@node Gerenciamento de revisões
+@c <en>@chapter Revision management
+@chapter Gerenciamento de revisões
+@c <en>@cindex Revision management
+@cindex Gerenciamento de revisões
+
+@c -- This chapter could be expanded a lot.
+@c -- Experiences are very welcome!
+
+@c <en>If you have read this far, you probably have a pretty
+@c <en>good grasp on what @sc{cvs} can do for you. This
+@c <en>chapter talks a little about things that you still have
+@c <en>to decide.
+Se você leu até este ponto, você provavelmente tem uma
+boa noção do que o @sc{cvs} pode fazer por você. Este
+capítulo fala um pouco sobre coisas que ainda cabe a
+você decidir.
+
+@c <en>If you are doing development on your own using @sc{cvs}
+@c <en>you could probably skip this chapter. The questions
+@c <en>this chapter takes up become more important when more
+@c <en>than one person is working in a repository.
+Se você está desenvolvendo sozinho com o @sc{cvs}, você
+provavelmente pode pular este capítulo. As questões
+que este capítulo levanta são mais importante quando
+mais de uma pessoa está trabalhando num mesmo repositório.
+
+@menu
+@c <en>* When to commit:: Some discussion on the subject
+* Quando ???commit???:: Alguma discussão sobre o assunto
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node When to commit
+@node Quando ???commit???
+@c <en>@section When to commit?
+@section Quando ???commit??? ?
+@c <en>@cindex When to commit
+@cindex Quando ???commit???
+@c <en>@cindex Committing, when to
+@cindex ???Committing???, quando
+@c <en>@cindex Policy
+@cindex Política
+
+@c <en>Your group should decide which policy to use regarding
+@c <en>commits. Several policies are possible, and as your
+@c <en>experience with @sc{cvs} grows you will probably find
+@c <en>out what works for you.
+Seu grupo deve decidir qual vai ser a política a
+respeito de ???commits???. Várias políticas são
+possíveis, e à medida que sua experiência com o
+@sc{cvs} crescer, você provavelmente vai encontrar a
+que funciona com você.
+
+@c <en>If you commit files too quickly you might commit files
+@c <en>that do not even compile. If your partner updates his
+@c <en>working sources to include your buggy file, he will be
+@c <en>unable to compile the code. On the other hand, other
+@c <en>persons will not be able to benefit from the
+@c <en>improvements you make to the code if you commit very
+@c <en>seldom, and conflicts will probably be more common.
+Se você ???commit??? arquivos muito rapidamente
+provavelmente você vai ???commit??? arquivos que nem
+mesmo compilam. Se seu parceiro atualiza as cópias de
+trabalho dele e inclui seu arquivo bichado, ele não vai
+conseguir compilar o código. Por outro lado, as outras
+pessoas não vão poder se beneficiar das melhorias que
+você fizer no código se você ???commit??? muito
+raramente, e os conflitos provavelmente vão aumentar.
+
+@c <en>It is common to only commit files after making sure
+@c <en>that they can be compiled. Some sites require that the
+@c <en>files pass a test suite. Policies like this can be
+@c <en>enforced using the commitinfo file
+@c <en>(@pxref{commitinfo}), but you should think twice before
+@c <en>you enforce such a convention. By making the
+@c <en>development environment too controlled it might become
+@c <en>too regimented and thus counter-productive to the real
+@c <en>goal, which is to get software written.
+É comum apenas ???commit??? arquivos depois de se
+certificar que eles podem ser compilados. Alguns
+lugares exigem que os arquivos passem num conjunto de
+testes. Políticas deste tipo podem ser impostas usando
+o arquivo commitinfo (@pxref{commitinfo}), mas você
+deve pensar duas vezes antes de impor tal convenção.
+Tornando o ambiente de desenvolvimento muito controlado
+ele se torna muito rígido e contraprodutivo para o
+objetivo real, que é ter o software escrito.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Keyword substitution
+@node Substituição de palavra-chave
+@c <en>@chapter Keyword substitution
+@chapter Substituição de palavra-chave
+@c <en>@cindex Keyword substitution
+@cindex Substituição de palavra-chave
+@c <en>@cindex Keyword expansion
+@cindex Expansão de palavra-chave
+@c <en>@cindex Identifying files
+@cindex Identificando arquivos
+
+@comment Be careful when editing this chapter.
+@comment Remember that this file is kept under
+@comment version control, so we must not accidentally
+@comment include a valid keyword in the running text.
+
+@c <en>As long as you edit source files inside a working
+@c <en>directory you can always find out the state of
+@c <en>your files via @samp{cvs status} and @samp{cvs log}.
+@c <en>But as soon as you export the files from your
+@c <en>development environment it becomes harder to identify
+@c <en>which revisions they are.
+À medida em que você edita arquivos fonte dentro de um
+diretório de trabalho você pode sempre obter o estado
+de seus arquivos via @samp{cvs status} e @samp{cvs
+log}. Mas assim que você exporta os arquivos de seu
+ambiente de desenvolvimento se torna mais difícil dizer
+de quais revisões eles são.
+
+@c <en>@sc{cvs} can use a mechanism known as @dfn{keyword
+@c <en>substitution} (or @dfn{keyword expansion}) to help
+@c <en>identifying the files. Embedded strings of the form
+@c <en>@code{$@var{keyword}$} and
+@c <en>@code{$@var{keyword}:@dots{}$} in a file are replaced
+@c <en>with strings of the form
+@c <en>@code{$@var{keyword}:@var{value}$} whenever you obtain
+@c <en>a new revision of the file.
+O @sc{cvs} pode usar um mecanismo chamado de
+@dfn{substituição de palavra-chave} (ou @dfn{expansão
+de palavra-chave}) para ajudar na identificação de
+arquivos. Strings embutidas na forma @code{$@var{keyword}$} e
+@code{$@var{keyword}:@dots{}$} em um arquivo são
+substituídas por strings da forma
+@code{$@var{keyword}:@var{value}$} sempre que você obtém
+uma nova revisão do arquivo.
+
+@menu
+@c <en>* Keyword list:: Keywords
+* Lista de palavras-chave:: Palavras-chave
+@c <en>* Using keywords:: Using keywords
+* Usando palavras-chave:: Usando Palavras-chave
+@c <en>* Avoiding substitution:: Avoiding substitution
+* Evitando substituições:: Evitando substituições
+@c <en>* Substitution modes:: Substitution modes
+* Modos de substituição:: Modos de substituição
+@c <en>* Configuring keyword expansion:: Configuring keyword expansion
+* Configurando a expansão do teclado:: Configurando a expansão do teclado
+@c <en>* Log keyword:: Problems with the $@splitrcskeyword{}Log$ keyword.
+* Log keyword:: Problemas com a palavra-chave $@splitrcskeyword{}Log$.
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Keyword list
+@node Lista de palavras-chave
+@c <en>@section Keyword List
+@section Lista de Palavras-chave
+@c <en>@cindex Keyword List
+@cindex Lista de Palavras-chave
+
+@c FIXME: need some kind of example here I think,
+@c perhaps in a
+@c "Keyword intro" node. The intro in the "Keyword
+@c substitution" node itself seems OK, but to launch
+@c into a list of the keywords somehow seems too abrupt.
+
+@c <en>This is a list of the keywords:
+Esta é uma lista de palavras-chave:
+
+@table @code
+@c <en>@cindex Author keyword
+@cindex Palavra-chave Author (autor)
+@c <en>@item $@splitrcskeyword{Author}$
+@item $@splitrcskeyword{Author}$
+@c <en>The login name of the user who checked in the revision.
+O login do usuário que ???checked in??? a revisão.
+
+@c <en>@cindex CVSHeader keyword
+@cindex Palavra-chave CVSHeader (cabeçalho CVS)
+@c <en>@item $@splitrcskeyword{CVSHeader}
+@item $@splitrcskeyword{CVSHeader}
+@c <en>A standard header (similar to $@splitrcskeyword{Header}$, but with
+@c <en>the CVS root stripped off). It contains the relative
+@c <en>pathname of the @sc{rcs} file to the CVS root, the
+@c <en>revision number, the date (UTC), the author, the state,
+@c <en>and the locker (if locked). Files will normally never
+@c <en>be locked when you use @sc{cvs}.
+Um cabeçalho padrão (similar ao
+$@splitrcskeyword{Header}$, mas com a raíz do CVS
+retirada). Ele contém o caminho do arquivo
+@sc{rcs} relativo à raíz do CVS, o número da revisão, a
+data (UTC), o autor, o estado, e o ???locker??? (se
+estiver travado). Arquivos normalmente nunca são
+travados quando você usa @sc{cvs}.
+
+@c <en>Note that this keyword has only been recently
+@c <en>introduced to @sc{cvs} and may cause problems with
+@c <en>existing installations if $@splitrcskeyword{CVSHeader}$ is already
+@c <en>in the files for a different purpose. This keyword may
+@c <en>be excluded using the @code{KeywordExpansion=eCVSHeader}
+@c <en>in the @file{CVSROOT/config} file.
+@c <en>See @ref{Configuring keyword expansion} for more details.
+Observe que esta palavra-chave foi adicionada apenas
+recentemente no @sc{cvs} e pode causar problemas com
+instalações existentes se $@splitrcskeyword{CVSHeader}$
+já está nos arquivos por um motivo diferente. Esta
+palavra-chave deve ser excluída usando o
+@code{KeywordExpansion=eCVSHeader} no arquivo
+@file{CVSROOT/config}. Veja em @ref{Configurando a
+expansão do teclado} para maiores detalhes.
+
+@c <en>@cindex Date keyword
+@cindex Palavra-chave Date (data)
+@c <en>@item $@splitrcskeyword{Date}$
+@item $@splitrcskeyword{Date}$
+@c <en>The date and time (UTC) the revision was checked in.
+A data e hora (UTC) na qual a revisão foi ???checked in???.
+
+@c <en>@cindex Header keyword
+@cindex Palavra-chave Header (cabeçalho)
+@c <en>@item $@splitrcskeyword{Header}$
+@item $@splitrcskeyword{Header}$
+@c <en>A standard header containing the full pathname of the
+@c <en>@sc{rcs} file, the revision number, the date (UTC), the
+@c <en>author, the state, and the locker (if locked). Files
+@c <en>will normally never be locked when you use @sc{cvs}.
+Um cabeçalho padrão contendo o caminho completo do arquivo
+@sc{rcs}, o número da revisão, a data (UTC), o autor, o
+estado, e o ???locker??? (se estiver travado).
+Arquivos normalmente nunca são travados quando você usa
+@sc{cvs}.
+
+@c <en>@cindex Id keyword
+@cindex Palavra-chave Id
+@c <en>@item $@splitrcskeyword{Id}$
+@item $@splitrcskeyword{Id}$
+@c <en>Same as @code{$@splitrcskeyword{Header}$}, except that the @sc{rcs}
+@c <en>filename is without a path.
+Similar ao @code{$@splitrcskeyword{Header}$}, exceto
+que o nome do arquivo @sc{rcs} não tem o caminho.
+
+@c <en>@cindex Name keyword
+@cindex Palavra-chave Name (nome)
+@c <en>@item $@splitrcskeyword{Name}$
+@item $@splitrcskeyword{Name}$
+@c <en>Tag name used to check out this file. The keyword is
+@c <en>expanded only if one checks out with an explicit tag
+@c <en>name. For example, when running the command @code{cvs
+@c <en>co -r first}, the keyword expands to @samp{Name: first}.
+Nome da etiqueta (tag) usada para ???check out??? este
+arquivo. A palavra-chave é expandida apenas se foi
+???check out??? com um nome de etiqueta explícito. Por
+exemplo, quando rodou o comando @code{cvs co -r
+inicio}, a palavra-chave expande para @samp{Name: inicio}.
+
+@c <en>@cindex Locker keyword
+@cindex Palavra-chave Locker (???locker???)
+@c <en>@item $@splitrcskeyword{Locker}$
+@item $@splitrcskeyword{Locker}$
+@c <en>The login name of the user who locked the revision
+@c <en>(empty if not locked, which is the normal case unless
+@c <en>@code{cvs admin -l} is in use).
+O login do usuário que travou a revisão (vazio se não
+estiver travado, que é o normal a menos que @code{cvs
+admin -l} esteja em uso).
+
+@c <en>@cindex Log keyword
+@cindex Palvra-chave Log (registro)
+@c <en>@cindex MaxCommentLeaderLength
+@cindex MaxCommentLeaderLength
+@c <en>@cindex UseArchiveCommentLeader
+@cindex UseArchiveCommentLeader
+@c <en>@cindex Log keyword, configuring substitution behavior
+@cindex Palavra-chave Log, configurando o comportamento na substituição
+@c <en>@item $@splitrcskeyword{Log}$
+@item $@splitrcskeyword{Log}$
+@c <en>The log message supplied during commit, preceded by a
+@c <en>header containing the @sc{rcs} filename, the revision
+@c <en>number, the author, and the date (UTC). Existing log
+@c <en>messages are @emph{not} replaced. Instead, the new log
+@c <en>message is inserted after @code{$@splitrcskeyword{Log:@dots{}}$}.
+@c <en>Each new line is prefixed with the same string which
+@c <en>precedes the @code{$Log} keyword. For example, if the
+@c <en>file contains:
+A mensagem de log (registro) fornecida durante o
+???commit???, precedida por um cabeçalho contendo o
+nome do arquivo @sc{rcs}, o número de revisão, o autor,
+e a data (UTC). Mensagens de log (registro) @emph{não}
+são substituídas. Ao invés disto, A nova mensagem de
+log (registro) é inserida depois do
+@code{$@splitrcskeyword{Log:@dots{}}$}. Cada nova linha
+é prefixada com a mesma string que precede a
+palavra-chave @code{$Log}. Por exemplo, se o arquivo contém:
+
+@example
+ /* Here is what people have been up to:
+ *
+ * $@splitrcskeyword{}Log: frob.c,v $
+ * Revision 1.1 1997/01/03 14:23:51 joe
+ * Add the superfrobnicate option
+ *
+ */
+@end example
+
+@noindent
+@c <en>then additional lines which are added when expanding
+@c <en>the @code{$Log} keyword will be preceded by @samp{ * }.
+@c <en>Unlike previous versions of @sc{cvs} and @sc{rcs}, the
+@c <en>@dfn{comment leader} from the @sc{rcs} file is not used.
+@c <en>The @code{$Log} keyword is useful for
+@c <en>accumulating a complete change log in a source file,
+@c <en>but for several reasons it can be problematic.
+@c <en>@xref{Log keyword}.
+Então, linhas adicionais que são adicionadas quando a
+palavra-chave @code{$Log} é expandida vão ser
+precedidas por @samp{ * }. Ao contrário de versões
+prévias do @sc{cvs} e do @sc{rcs}, o @dfn{comment
+leader} do arquivo @sc{rcs} não é usado. A
+palavra-chave @code{$Log} é útil para acumular um
+???change log??? completo num fonte, mas pode ser
+problemática por várias razões. Veja em @ref{Log keyword}.
+
+@c <en>@cindex RCSfile keyword
+@cindex Palavra-chave RCSfile (arquivo RCS)
+@c <en>@item $@splitrcskeyword{RCSfile}$
+@item $@splitrcskeyword{RCSfile}$
+@c <en>The name of the RCS file without a path.
+O nome do arquivo RCS sem o caminho.
+
+@c <en>@cindex Revision keyword
+@cindex Palavra-chave Revision (revisão)
+@c <en>@item $@splitrcskeyword{Revision}$
+@item $@splitrcskeyword{Revision}$
+@c <en>The revision number assigned to the revision.
+O número de revisão atribuído à revisão.
+
+@c <en>@cindex Source keyword
+@cindex Palavra-chave Source (fonte)
+@c <en>@item $@splitrcskeyword{Source}$
+@item $@splitrcskeyword{Source}$
+@c <en>The full pathname of the RCS file.
+O caminho completo do arquivo RCS.
+
+@c <en>@cindex State keyword
+@cindex Palavra-chave State (estado)
+@c <en>@item $@splitrcskeyword{State}$
+@item $@splitrcskeyword{State}$
+@c <en>The state assigned to the revision. States can be
+@c <en>assigned with @code{cvs admin -s}---see @ref{admin options}.
+O estado atribuído à revisão. Estados podem ser
+atribuídos com @code{cvs admin -s}---veja em @ref{admin options}.
+
+@c <en>@cindex Local keyword
+@cindex Palavra-chave Local
+@c <en>@item Local keyword
+@item Palavra-chave Local
+@c <en>The @code{LocalKeyword} option in the @file{CVSROOT/config} file
+@c <en>may be used to specify a local keyword which is to be
+@c <en>used as an alias for one of the keywords: $@splitrcskeyword{}Id$,
+@c <en>$@splitrcskeyword{}Header$, or $@splitrcskeyword{}CVSHeader$. For
+@c <en>example, if the @file{CVSROOT/config} file contains
+@c <en>a line with @code{LocalKeyword=MYBSD=CVSHeader}, then a
+@c <en>file with the local keyword $@splitrcskeyword{}MYBSD$ will be
+@c <en>expanded as if it were a $@splitrcskeyword{}CVSHeader$ keyword. If
+@c <en>the src/frob.c file contained this keyword, it might
+@c <en>look something like this:
+A opção @code{LocalKeyword} no arquivo
+@file{CVSROOT/config} pode ser usada para especificar
+uma palavra-chave que não é usada como um alias para
+uma das seguintes palavras-chave: $@splitrcskeyword{}Id$,
+$@splitrcskeyword{}Header$, ou $@splitrcskeyword{}CVSHeader$. Por
+exemplo, se o arquivo @file{CVSROOT/config} contém uma
+linha com @code{LocalKeyword=MYBSD=CVSHeader}, então um
+arquivo com a palavra-chave local
+$@splitrcskeyword{}MYBSD$ vai ser expandido como se ele
+fosse uma palavra-chave
+$@splitrcskeyword{}CVSHeader$. Se o arquivo src/frob.c
+contiver esta palavra-chave, ele pode parecer com algo assim:
+
+@example
+ /*
+ * $@splitrcskeyword{}MYBSD: src/frob.c,v 1.1 2003/05/04 09:27:45 john Exp $
+ */
+@end example
+
+@c <en>Many repositories make use of a such a ``local
+@c <en>keyword'' feature. An old patch to @sc{cvs} provided
+@c <en>the @code{LocalKeyword} feature using a @code{tag=}
+@c <en>option and called this the ``custom tag'' or ``local
+@c <en>tag'' feature. It was used in conjunction with the
+@c <en>what they called the @code{tagexpand=} option. In
+@c <en>@sc{cvs} this other option is known as the
+@c <en>@code{KeywordExpand} option.
+@c <en>See @ref{Configuring keyword expansion} for more
+@c <en>details.
+Muitos repositórios fazem uso de tal ``palavra-chave
+local''. Uma ???patch??? antiga ao @sc{cvs} fornecia a
+funcionalidade @code{LocalKeyword} usando uma opção
+@code{tag=} e chamava esta funcionalidade de ``custom tag'' ou ``local
+tag''. ela foi usada em conjunto com o que chamavam de
+opção @code{tagexpand=}. No @sc{cvs} esta outra opção é
+conhecida como a opção @code{KeywordExpand}. Veja em
+@ref{Configurando a expansão do teclado} para maiores
+detalhes.
+
+@c <en>Examples from popular projects include:
+@c <en>$@splitrcskeyword{FreeBSD}$, $@splitrcskeyword{NetBSD}$,
+@c <en>$@splitrcskeyword{OpenBSD}$, $@splitrcskeyword{XFree86}$,
+@c <en>$@splitrcskeyword{Xorg}$.
+Exemplos de projetos populares incluem:
+$@splitrcskeyword{FreeBSD}$, $@splitrcskeyword{NetBSD}$,
+$@splitrcskeyword{OpenBSD}$, $@splitrcskeyword{XFree86}$,
+$@splitrcskeyword{Xorg}$.
+
+@c <en>The advantage of this is that you can include your
+@c <en>local version information in a file using this local
+@c <en>keyword without disrupting the upstream version
+@c <en>information (which may be a different local keyword or
+@c <en>a standard keyword). Allowing bug reports and the like
+@c <en>to more properly identify the source of the original
+@c <en>bug to the third-party and reducing the number of
+@c <en>conflicts that arise during an import of a new version.
+A vantagem disto é que você pode incluir sua informação
+de versão local num arquivo usando esta palavra-chave
+local sem romper com a informação da versão principal
+(que pode ser uma palavra-chave local diferente ou uma
+palavra-chave padrão). Permitir relatório de bug (bug
+report) e coisas do gênero para identificar mais
+adequadamente a origem do bug original para o terceiro
+e reduzir o número de conflitos que surgem durante uma
+importação de uma nova versão.
+
+@c <en>All keyword expansion except the local keyword may be
+@c <en>disabled using the @code{KeywordExpand} option in
+@c <en>the @file{CVSROOT/config} file---see
+@c <en>@ref{Configuring keyword expansion} for more details.
+Toda expansão de palavra-chave com exceção da
+palavra-chave local deve ser disabilitada usando a
+opção @code{KeywordExpand} no arquivo
+@file{CVSROOT/config}---veja em @ref{Configurando a
+expansão do teclado} para mais detalhes.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Using keywords
+@node Usando palavras-chave
+@c <en>@section Using keywords
+@section Usando palavras-chave
+
+@c <en>To include a keyword string you simply include the
+@c <en>relevant text string, such as @code{$@splitrcskeyword{Id}$}, inside the
+@c <en>file, and commit the file. @sc{cvs} will automatically (Or,
+@c <en>more accurately, as part of the update run that
+@c <en>automatically happens after a commit.)
+@c <en>expand the string as part of the commit operation.
+Para incluir uma string de palavra-chave você deve
+simplesmente incluir o a string de texto relevante,
+como @code{$@splitrcskeyword{Id}$}, dentro do arquivo,
+e ???commit??? o arquivo. O @sc{cvs} vai automaticamente (Ou,
+mais precisamente, como parte da execução do
+???update??? que acontece automaticamente depois do
+???commit???.) expandir a string como parte da operação
+de commit.
+
+@c <en>It is common to embed the @code{$@splitrcskeyword{}Id$} string in
+@c <en>the source files so that it gets passed through to
+@c <en>generated files. For example, if you are managing
+@c <en>computer program source code, you might include a
+@c <en>variable which is initialized to contain that string.
+@c <en>Or some C compilers may provide a @code{#pragma ident}
+@c <en>directive. Or a document management system might
+@c <en>provide a way to pass a string through to generated
+@c <en>files.
+É normal imergir a string @code{$@splitrcskeyword{}Id$}
+nos arquivos fonte de forma que ela seja ignorada nos
+arquivos gerados. Por exemplo, se você está
+gerenciando código fonte de programas de computador,
+você deve incluir uma variável que é inicializada para
+conter aquela string. Ou alguns compiladores C podem
+fornecer uma diretiva @code{#pragma ident}. Ou um
+sistema de gerência de documentos pode fornecer um
+jeito de entregar a string diretamente ao arquivos
+gerados.
+
+@c Would be nice to give an example, but doing this in
+@c portable C is not possible and the problem with
+@c picking any one language (VMS HELP files, Ada,
+@c troff, whatever) is that people use CVS for all
+@c kinds of files.
+
+@c <en>@cindex Ident (shell command)
+@cindex Ident (shell command)
+@c <en>The @code{ident} command (which is part of the @sc{rcs}
+@c <en>package) can be used to extract keywords and their
+@c <en>values from a file. This can be handy for text files,
+@c <en>but it is even more useful for extracting keywords from
+@c <en>binary files.
+O comando @code{ident} (que é parte do pacote @sc{rcs})
+pode ser usado para extrair palavras-chave e seus
+valores de um arquivo. Isto pode ser útil para
+arquivos texto, mas é mais útil para extração de
+palavras-chave de arquivos binários.
+
+@example
+$ ident samp.c
+samp.c:
+ $@splitrcskeyword{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+$ gcc samp.c
+$ ident a.out
+a.out:
+ $@splitrcskeyword{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $
+@end example
+
+@c <en>@cindex What (shell command)
+@cindex What (shell command)
+@c <en>S@sc{ccs} is another popular revision control system.
+@c <en>It has a command, @code{what}, which is very similar to
+@c <en>@code{ident} and used for the same purpose. Many sites
+@c <en>without @sc{rcs} have @sc{sccs}. Since @code{what}
+@c <en>looks for the character sequence @code{@@(#)} it is
+@c <en>easy to include keywords that are detected by either
+@c <en>command. Simply prefix the keyword with the
+@c <en>magic @sc{sccs} phrase, like this:
+S@sc{ccs} é outro sistema de controle de revisões
+popular. Ele tem um comando, @code{what} (o que, em
+português), que é bastante similar ao @code{ident} e
+usado para o mesmo propósito. Muitos ???sites??? sem
+@sc{rcs} tem @sc{sccs}. Uma vez que o @code{what}
+procura pela seqüência de caracteres @code{@@(#)} é
+fácil incluir palavras-chave que são detectadas por
+qualquer comando. Simplesmente bote um prefixo na
+palavra-chave com a frase mágica @sc{sccs}, como esta:
+
+@example
+static char *id="@@(#) $@splitrcskeyword{}Id: ab.c,v 1.5 1993/10/19 14:57:32 ceder Exp $";
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Avoiding substitution
+@node Evitando substituições
+@c <en>@section Avoiding substitution
+@section Evitando substituições
+
+@c <en>Keyword substitution has its disadvantages. Sometimes
+@c <en>you might want the literal text string
+@c <en>@samp{$@splitrcskeyword{}Author$} to appear inside a file without
+@c <en>@sc{cvs} interpreting it as a keyword and expanding it
+@c <en>into something like @samp{$@splitrcskeyword{}Author: ceder $}.
+Substituição de palavra-chave tem suas desvantagens.
+Algumas vezes você pode querer que a string de texto
+literal @samp{$@splitrcskeyword{}Author$} apareça
+dentro de um arquivo sem que o @sc{cvs} a interprete
+como uma palavra-chave e a expanda em algo como
+@samp{$@splitrcskeyword{}Author: ceder $}.
+
+@c <en>There is unfortunately no way to selectively turn off
+@c <en>keyword substitution. You can use @samp{-ko}
+@c <en>(@pxref{Substitution modes}) to turn off keyword
+@c <en>substitution entirely.
+Infelizmente não há como desligar a substituição de
+palavra-chave de forma seletiva. Você pode usar @samp{-ko}
+(@pxref{Modos de substituição}) para desligar a
+substituição de palavra-chave completamente.
+
+@c <en>In many cases you can avoid using keywords in
+@c <en>the source, even though they appear in the final
+@c <en>product. For example, the source for this manual
+@c <en>contains @samp{$@@asis@{@}Author$} whenever the text
+@c <en>@samp{$@splitrcskeyword{}Author$} should appear. In @code{nroff}
+@c <en>and @code{troff} you can embed the null-character
+@c <en>@code{\&} inside the keyword for a similar effect.
+Em muitos casos você pode evitar o uso de palavra-chave
+nos fontes, mesmo que elas apareçam no produto final.
+Por exemplo, o código-fonte deste manual contém
+@samp{$@@asis@{@}Author$} sempre que o texto
+@samp{$@splitrcskeyword{}Author$} deva aparecer. Em
+@code{nroff} e @code{troff} você pode imergir o
+caractere nulo @code{\&} dentro de uma palavra-chave
+para obter um efeito similar.
+
+@c <en>It is also possible to specify an explicit list of
+@c <en>keywords to include or exclude using the
+@c <en>@code{KeywordExpand} option in the
+@c <en>@file{CVSROOT/config} file--see @ref{Configuring keyword expansion}
+@c <en>for more details. This feature is intended primarily
+@c <en>for use with the @code{LocalKeyword} option--see
+@c <en>@ref{Keyword list}.
+Também é possível especificar explicitamente uma lista
+de palavras-chave para incluir ou excluir usando a
+opção @code{KeywordExpand} no arquivo
+@file{CVSROOT/config}--veja em @ref{Configurando a
+expansão do teclado} para maiores detalhes. Esta
+funcionalidade foi pensada para ser usada a princípio
+com a opção @code{LocalKeyword}--veja @ref{Lista de
+palavras-chave}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Substitution modes
+@node Modos de substituição
+@c <en>@section Substitution modes
+@section Modos de substituição
+@c <en>@cindex Keyword substitution, changing modes
+@cindex Substituição de palavra-chave, mudando os modos
+@c <en>@cindex -k (keyword substitution)
+@cindex -k (substituição de palavra-chave)
+@c <en>@cindex Kflag
+@cindex Kflag
+
+@c FIXME: This could be made more coherent, by expanding it
+@c with more examples or something.
+@c <en>Each file has a stored default substitution mode, and
+@c <en>each working directory copy of a file also has a
+@c <en>substitution mode. The former is set by the @samp{-k}
+@c <en>option to @code{cvs add} and @code{cvs admin}; the
+@c <en>latter is set by the @samp{-k} or @samp{-A} options to @code{cvs
+@c <en>checkout} or @code{cvs update}. @code{cvs diff} also
+@c <en>has a @samp{-k} option. For some examples,
+@c <en>see @ref{Binary files}, and @ref{Merging and keywords}.
+Cada arquivo tem um modo de substituição padrão
+armazenado, e cada cópia de um arquivo num diretório de
+trabalho também tem um modo de substituição. O
+primeiro é ajustado pela opção @samp{-k} no @code{cvs
+add} e no @code{cvs admin}; o último é ajustado pelas
+opções @samp{-k} ou @samp{-A} do @code{cvs checkout} ou
+do @code{cvs update}. O @code{cvs diff} também tem uma
+opção @samp{-k}. Para alguns exemplos, veja em
+@ref{Arquivos binários}, e @ref{Mesclagem e
+palavras-chave}.
+@c The fact that -A is overloaded to mean both reset
+@c sticky options and reset sticky tags/dates is
+@c somewhat questionable. Perhaps there should be
+@c separate options to reset sticky options (e.g. -k
+@c A") and tags/dates (someone suggested -r HEAD could
+@c do this instead of setting a sticky tag of "HEAD"
+@c as in the status quo but I haven't thought much
+@c about that idea. Of course -r .reset or something
+@c could be coined if this needs to be a new option).
+@c On the other hand, having -A mean "get things back
+@c into the state after a fresh checkout" has a certain
+@c appeal, and maybe there is no sufficient reason for
+@c creeping featurism in this area.
+
+@c <en>The modes available are:
+Os modos disponíveis são:
+
+@table @samp
+@c <en>@item -kkv
+@item -kkv
+@c <en>Generate keyword strings using the default form, e.g.
+@c <en>@code{$@splitrcskeyword{}Revision: 5.7 $} for the @code{Revision}
+@c <en>keyword.
+Gera strings de palavras-chave usando a forma padrão, e.g.
+@code{$@splitrcskeyword{}Revision: 5.7 $} para a
+palavra-chave @code{Revision}.
+
+@c <en>@item -kkvl
+@item -kkvl
+@c <en>Like @samp{-kkv}, except that a locker's name is always
+@c <en>inserted if the given revision is currently locked.
+@c <en>The locker's name is only relevant if @code{cvs admin
+@c <en>-l} is in use.
+Parecido com o @samp{-kkv}, exceto que um nome de
+???locker??? é sempre inserido se a revisão dada
+estiver atualmente ???locked???. O nome do ???locker???
+é relevante apenas se @code{cvs admin -l} estiver em uso.
+
+@c <en>@item -kk
+@item -kk
+@c <en>Generate only keyword names in keyword strings; omit
+@c <en>their values. For example, for the @code{Revision}
+@c <en>keyword, generate the string @code{$@splitrcskeyword{}Revision$}
+@c <en>instead of @code{$@splitrcskeyword{}Revision: 5.7 $}. This option
+@c <en>is useful to ignore differences due to keyword
+@c <en>substitution when comparing different revisions of a
+@c <en>file (@pxref{Merging and keywords}).
+Gera nomes de palavras-chave apenas nas strings da palavras-chave; omite
+seus valores. Por exemplo, para a palavra-chave @code{Revision}
+, gera a string @code{$@splitrcskeyword{}Revision$}
+ao invés de @code{$@splitrcskeyword{}Revision: 5.7 $}.
+Esta opção é útil para ignorar diferenças devido a
+substituição de palavras-chave quando comparando
+revisões diferentes de um mesmo arquivo
+(@pxref{Mesclagem e palavras-chave}).
+
+@c <en>@item -ko
+@item -ko
+@c <en>Generate the old keyword string, present in the working
+@c <en>file just before it was checked in. For example, for
+@c <en>the @code{Revision} keyword, generate the string
+@c <en>@code{$@splitrcskeyword{}Revision: 1.1 $} instead of
+@c <en>@code{$@splitrcskeyword{}Revision: 5.7 $} if that is how the
+@c <en>string appeared when the file was checked in.
+Gera a antiga string da palavra-chave, presente no
+arquivo de trabalho antes dele ter sido ???checked
+in???. Por exemplo, para a palavra-chave
+@code{Revision}, gera a string
+@code{$@splitrcskeyword{}Revision: 1.1 $} ao invés de
+@code{$@splitrcskeyword{}Revision: 5.7 $} se era assim
+que a string aparecia quando o arquivo foi ???checked
+in???.
+
+@c <en>@item -kb
+@item -kb
+@c <en>Like @samp{-ko}, but also inhibit conversion of line
+@c <en>endings between the canonical form in which they are
+@c <en>stored in the repository (linefeed only), and the form
+@c <en>appropriate to the operating system in use on the
+@c <en>client. For systems, like unix, which use linefeed
+@c <en>only to terminate lines, this is very similar to
+@c <en>@samp{-ko}. For more information on binary files, see
+@c <en>@ref{Binary files}. In @sc{cvs} version 1.12.2 and later
+@c <en>@samp{-kb}, as set by @code{cvs add}, @code{cvs admin}, or
+@c <en>@code{cvs import} may not be overridden by a @samp{-k} option
+@c <en>specified on the command line.
+Como o @samp{-ko}, mas também inibindo conversão de
+fim-de-linhas entre a forma canônica nas qual os
+arquivo são arquivados no repositório (apenas
+linefeed), e a forma apropriada para o sistema
+operacional em uso no cliente. Para sistemas, como o
+unix, que usam apenas o linefeed para terminar linhas,
+isto é bastante similar ao @samp{-ko}. Para mais
+informações sobre arquivos binários, veja em
+@ref{Arquivos binários}. No @sc{cvs} versão 1.12.2 ou
+mais novas @samp{-kb}, ajustado por @code{cvs add}, @code{cvs admin}, ou
+@code{cvs import} não vai ser sobreescrito pela opção
+@samp{-k} especificada na linha de comando.
+
+@c <en>@item -kv
+@item -kv
+@c <en>Generate only keyword values for keyword strings. For
+@c <en>example, for the @code{Revision} keyword, generate the string
+@c <en>@code{5.7} instead of @code{$@splitrcskeyword{}Revision: 5.7 $}.
+@c <en>This can help generate files in programming languages
+@c <en>where it is hard to strip keyword delimiters like
+@c <en>@code{$@splitrcskeyword{}Revision: $} from a string. However,
+@c <en>further keyword substitution cannot be performed once
+@c <en>the keyword names are removed, so this option should be
+@c <en>used with care.
+Gera apenas os valores das palavras-chaves para strings
+de palavras-chave. Por exemplo, para a palavra-chave
+@code{Revision}, gera a string @code{5.7} ao invés de
+@code{$@splitrcskeyword{}Revision: 5.7 $}. Isto pode
+ajudar a gerar arquivos em linguagens de programação
+onde é difícil ???strip??? delimitadores de
+palavras-chave, como o
+@code{$@splitrcskeyword{}Revision: $} para uma string.
+Entretanto, outras substituições de palavras-chave não
+poderam ser feitas, uma vez que os nomes de
+palavras-chave foram removidos. Logo, esta opção deve
+ser usada com cuidado.
+
+@c <en>One often would like to use @samp{-kv} with @code{cvs
+@c <en>export}---@pxref{export}. But be aware that doesn't
+@c <en>handle an export containing binary files correctly.
+É comum querer usar o @samp{-kv} com @code{cvs
+export}---@pxref{export}. Mas lembre-se que isto não
+trata um export contendo binários direito.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Configuring keyword expansion
+@node Configurando a expansão do teclado
+@c <en>@section Configuring Keyword Expansion
+@section Configurando a Expansão do Teclado
+@c <en>@cindex Configuring keyword expansion
+@cindex Configurando a Expansão do Teclado
+
+@c <en>In a repository that includes third-party software on
+@c <en>vendor branches, it is sometimes helpful to configure
+@c <en>CVS to use a local keyword instead of the standard
+@c <en>$@splitrcskeyword{Id}$ or $@splitrcskeyword{Header}$ keywords. Examples from
+@c <en>real projects includ, $@splitrcskeyword{Xorg}$, $@splitrcskeyword{XFree86}$,
+@c <en>$@splitrcskeyword{FreeBSD}$, $@splitrcskeyword{NetBSD}$,
+@c <en>$@splitrcskeyword{OpenBSD}$, and even $@splitrcskeyword{dotat}$.
+@c <en>The advantage of this is that
+@c <en>you can include your local version information in a
+@c <en>file using this local keyword (sometimes called a
+@c <en>``custom tag'' or a ``local tag'') without disrupting
+@c <en>the upstream version information (which may be a
+@c <en>different local keyword or a standard keyword). In
+@c <en>these cases, it is typically desirable to disable the
+@c <en>expansion of all keywords except the configured local
+@c <en>keyword.
+Num repositório que inclua software de terceiros em
+ramos de fornecedor, às vezes é útil configurar o CVS
+para usar uma palavra-chave local ao invés das
+palavras-chave padrão $@splitrcskeyword{Id}$ ou
+$@splitrcskeyword{Header}$. Exemplos de projetos reais incluem, $@splitrcskeyword{Xorg}$, $@splitrcskeyword{XFree86}$,
+$@splitrcskeyword{FreeBSD}$, $@splitrcskeyword{NetBSD}$,
+$@splitrcskeyword{OpenBSD}$, e ainda
+$@splitrcskeyword{dotat}$. A vantagem disto é que você
+pode incluir sua ???local version information??? num
+arquivo usando esta palavra-chave local (algumas vezes
+chamada de ``custom tag'' ou ``local tag'') sem romper
+com a ???upstream version information??? (que pode ser
+uma palavra-chave local diferente ou uma palavra-chave
+padrão). Nestes casos, é normalmente desejável
+desabilitar a expansão de todas as palavras-chave
+exceto a palavra-chave local configurada.
+
+@c <en>The @code{KeywordExpansion} option in the
+@c <en>@file{CVSROOT/config} file is intended to allow for the
+@c <en>either the explicit exclusion of a keyword or list of
+@c <en>keywords, or for the explicit inclusion of a keyword or
+@c <en>a list of keywords. This list may include the
+@c <en>@code{LocalKeyword} that has been configured.
+The @code{KeywordExpansion} option in the
+@file{CVSROOT/config} file is intended to allow for the
+either the explicit exclusion of a keyword or list of
+keywords, or for the explicit inclusion of a keyword or
+a list of keywords. This list may include the
+@code{LocalKeyword} that has been configured.
+
+@c <en>The @code{KeywordExpansion} option is followed by
+@c <en>@code{=} and the next character may either be @code{i}
+@c <en>to start an inclusion list or @code{e} to start an
+@c <en>exclusion list. If the following lines were added to
+@c <en>the @file{CVSROOT/config} file:
+The @code{KeywordExpansion} option is followed by
+@code{=} and the next character may either be @code{i}
+to start an inclusion list or @code{e} to start an
+exclusion list. If the following lines were added to
+the @file{CVSROOT/config} file:
+
+@example
+ # Add a "MyBSD" keyword and restrict keyword
+ # expansion
+ LocalKeyword=MyBSD=CVSHeader
+ KeywordExpand=iMyBSD
+@end example
+
+@c <en>then only the $@splitrcskeyword{MyBSD}$ keyword would be expanded.
+@c <en>A list may be used. The this example:
+then only the $@splitrcskeyword{MyBSD}$ keyword would be expanded.
+A list may be used. The this example:
+
+@example
+ # Add a "MyBSD" keyword and restrict keyword
+ # expansion to the MyBSD, Name and Date keywords.
+ LocalKeyword=MyBSD=CVSHeader
+ KeywordExpand=iMyBSD,Name,Date
+@end example
+
+@c <en>would allow $@splitrcskeyword{MyBSD}$, $@splitrcskeyword{Name}$, and
+@c <en>$@splitrcskeyword{Date}$ to be expanded.
+@c <en>would allow $@splitrcskeyword{MyBSD}$, $@splitrcskeyword{Name}$, and
+@c <en>$@splitrcskeyword{Date}$ to be expanded.
+would allow $@splitrcskeyword{MyBSD}$, $@splitrcskeyword{Name}$, and
+$@splitrcskeyword{Date}$ to be expanded.
+would allow $@splitrcskeyword{MyBSD}$, $@splitrcskeyword{Name}$, and
+$@splitrcskeyword{Date}$ to be expanded.
+
+@c <en>It is also possible to configure an exclusion list
+@c <en>using the following:
+@c <en>It is also possible to configure an exclusion list
+@c <en>using the following:
+It is also possible to configure an exclusion list
+using the following:
+It is also possible to configure an exclusion list
+using the following:
+
+@example
+ # Do not expand the non-RCS keyword CVSHeader
+ KeywordExpand=eCVSHeader
+@end example
+
+@c <en>This allows @sc{cvs} to ignore the recently introduced
+@c <en>$@splitrcskeyword{CVSHeader}$ keyword and retain all of the
+@c <en>others. The exclusion entry could also contain the
+@c <en>standard RCS keyword list, but this could be confusing
+@c <en>to users that expect RCS keywords to be expanded, so
+@c <en>ycare should be taken to properly set user expectations
+@c <en>for a repository that is configured in that manner.
+This allows @sc{cvs} to ignore the recently introduced
+$@splitrcskeyword{CVSHeader}$ keyword and retain all of the
+others. The exclusion entry could also contain the
+standard RCS keyword list, but this could be confusing
+to users that expect RCS keywords to be expanded, so
+ycare should be taken to properly set user expectations
+for a repository that is configured in that manner.
+
+@c <en>If there is a desire to not have any RCS keywords
+@c <en>expanded and not use the @code{-ko} flags everywhere,
+@c <en>an administrator may disable all keyword expansion
+@c <en>using the @file{CVSROOT/config} line:
+If there is a desire to not have any RCS keywords
+expanded and not use the @code{-ko} flags everywhere,
+an administrator may disable all keyword expansion
+using the @file{CVSROOT/config} line:
+
+@example
+ # Do not expand any RCS keywords
+ KeywordExpand=i
+@end example
+
+@c <en>this could be confusing to users that expect RCS
+@c <en>keywords like $@splitrcskeyword{Id}$ to be expanded properly,
+@c <en>so care should be taken to properly set user
+@c <en>expectations for a repository so configured.
+this could be confusing to users that expect RCS
+keywords like $@splitrcskeyword{Id}$ to be expanded properly,
+so care should be taken to properly set user
+expectations for a repository so configured.
+
+@c <en>It should be noted that a patch to provide both the
+@c <en>@code{KeywordExpand} and @code{LocalKeyword} features
+@c <en>has been around a long time. However, that patch
+@c <en>implemented these features using @code{tag=} and
+@c <en>@code{tagexpand=} keywords and those keywords are NOT
+@c <en>recognized.
+It should be noted that a patch to provide both the
+@code{KeywordExpand} and @code{LocalKeyword} features
+has been around a long time. However, that patch
+implemented these features using @code{tag=} and
+@code{tagexpand=} keywords and those keywords are NOT
+recognized.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Log keyword
+@node Log keyword
+@c <en>@section Problems with the $@splitrcskeyword{}Log$ keyword.
+@section Problems with the $@splitrcskeyword{}Log$ keyword.
+
+@c <en>The @code{$@splitrcskeyword{}Log$} keyword is somewhat
+@c <en>controversial. As long as you are working on your
+@c <en>development system the information is easily accessible
+@c <en>even if you do not use the @code{$@splitrcskeyword{}Log$}
+@c <en>keyword---just do a @code{cvs log}. Once you export
+@c <en>the file the history information might be useless
+@c <en>anyhow.
+The @code{$@splitrcskeyword{}Log$} keyword is somewhat
+controversial. As long as you are working on your
+development system the information is easily accessible
+even if you do not use the @code{$@splitrcskeyword{}Log$}
+keyword---just do a @code{cvs log}. Once you export
+the file the history information might be useless
+anyhow.
+
+@c <en>A more serious concern is that @sc{cvs} is not good at
+@c <en>handling @code{$@splitrcskeyword{}Log$} entries when a branch is
+@c <en>merged onto the main trunk. Conflicts often result
+@c <en>from the merging operation.
+A more serious concern is that @sc{cvs} is not good at
+handling @code{$@splitrcskeyword{}Log$} entries when a branch is
+merged onto the main trunk. Conflicts often result
+from the merging operation.
+@c Might want to check whether the CVS implementation
+@c of RCS_merge has this problem the same way rcsmerge
+@c does. I would assume so....
+
+@c <en>People also tend to "fix" the log entries in the file
+@c <en>(correcting spelling mistakes and maybe even factual
+@c <en>errors). If that is done the information from
+@c <en>@code{cvs log} will not be consistent with the
+@c <en>information inside the file. This may or may not be a
+@c <en>problem in real life.
+People also tend to "fix" the log entries in the file
+(correcting spelling mistakes and maybe even factual
+errors). If that is done the information from
+@code{cvs log} will not be consistent with the
+information inside the file. This may or may not be a
+problem in real life.
+
+@c <en>It has been suggested that the @code{$@splitrcskeyword{}Log$}
+@c <en>keyword should be inserted @emph{last} in the file, and
+@c <en>not in the files header, if it is to be used at all.
+@c <en>That way the long list of change messages will not
+@c <en>interfere with everyday source file browsing.
+It has been suggested that the @code{$@splitrcskeyword{}Log$}
+keyword should be inserted @emph{last} in the file, and
+not in the files header, if it is to be used at all.
+That way the long list of change messages will not
+interfere with everyday source file browsing.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Tracking sources
+@node Acompanhando fontes
+@c <en>@chapter Tracking third-party sources
+@chapter Tracking third-party sources
+@c <en>@cindex Third-party sources
+@cindex Fontes de terceiros
+@c <en>@cindex Tracking sources
+@cindex Tracking sources
+
+@c FIXME: Need discussion of added and removed files.
+@c FIXME: This doesn't really adequately introduce the
+@c concepts of "vendor" and "you". They don't *have*
+@c to be separate organizations or separate people.
+@c We want a description which is somewhat more based on
+@c the technical issues of which sources go where, but
+@c also with enough examples of how this relates to
+@c relationships like customer-supplier, developer-QA,
+@c maintainer-contributor, or whatever, to make it
+@c seem concrete.
+@c <en>If you modify a program to better fit your site, you
+@c <en>probably want to include your modifications when the next
+@c <en>release of the program arrives. @sc{cvs} can help you with
+@c <en>this task.
+Se você modificar um programa para se adequar melhor ao
+seu ambiente, você provavelmente vai querer incluir
+suas modificações quando a nova release do do programa
+chegar. O @sc{cvs} pode te ajudar nesta tarefa.
+
+@c <en>@cindex Vendor
+@cindex Vendor
+@cindex Vendor (fornecedor)
+@c <en>@cindex Vendor branch
+@cindex Vendor branch (ramo do forncedor)
+@cindex Ramo do fornecedor
+@c <en>@cindex Branch, vendor-
+@cindex Branch, vendor-
+@c <en>In the terminology used in @sc{cvs}, the supplier of the
+@c <en>program is called a @dfn{vendor}. The unmodified
+@c <en>distribution from the vendor is checked in on its own
+@c <en>branch, the @dfn{vendor branch}. @sc{cvs} reserves branch
+@c <en>1.1.1 for this use.
+Na terminologia usada no @sc{cvs}, quem fornece um
+programa é chamado de @dfn{vendor} (fornecedor, em
+português). A distribuição não modificada do
+fornecedor é ???checked in??? no seu próprio ramo, o
+@dfn{vendor branch} (ramo do fornecedor). O @sc{cvs}
+reserva o ramo 1.1.1 para isto.
+
+@c <en>When you modify the source and commit it, your revision
+@c <en>will end up on the main trunk. When a new release is
+@c <en>made by the vendor, you commit it on the vendor branch
+@c <en>and copy the modifications onto the main trunk.
+Quando você modifica a fonte e a ???commit???, sua
+revisão vai terminar na ???main trunk???. Quando uma
+nova release é feita pelo fornecedor, você ???commit???
+ela no ramo do fornecedor e copia as modificações no
+???main trunk???.
+
+@c <en>Use the @code{import} command to create and update
+@c <en>the vendor branch. When you import a new file,
+@c <en>the vendor branch is made the `head' revision, so
+@c <en>anyone that checks out a copy of the file gets that
+@c <en>revision. When a local modification is committed it is
+@c <en>placed on the main trunk, and made the `head'
+@c <en>revision.
+Use o comando @code{import} para criar e atualizar o
+ramo do fornecedor. Quando você importa um novo
+arquivo, o ramo do fornecedor se torna a revisão
+`head', logo qualquer um que ???checks out??? uma cópia
+do arquivo pega esta revisão. Quando uma modificação
+local é ???committed???, ela é posta no ???main
+trunk???, e se torna a revisão `head'.
+
+@menu
+@c <en>* First import:: Importing for the first time
+* Primeira importação:: Importando pela primeira vez
+@c <en>* Update imports:: Updating with the import command
+* Importações de atualização:: Atualizando com o comando import
+@c <en>* Reverting local changes:: Reverting to the latest vendor release
+* Reverting local changes:: Reverting to the latest vendor release
+@c <en>* Binary files in imports:: Binary files require special handling
+* Arquivos binários em importações:: Arquivos binários requerem tratamento especial
+@c <en>* Keywords in imports:: Keyword substitution might be undesirable
+* Palavras-chave em importações:: Substituição de palavras-chave pode ser indesejável
+@c <en>* Multiple vendor branches:: What if you get sources from several places?
+* Ramos de fornecedor múltiplos:: E se você obtém fontes de vários lugares?
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node First import
+@node Primeira importação
+@c <en>@section Importing for the first time
+@section Importing for the first time
+@c <en>@cindex Importing modules
+@cindex Importing modules
+
+@c Should mention naming conventions for vendor tags,
+@c release tags, and perhaps directory names.
+@c <en>Use the @code{import} command to check in the sources
+@c <en>for the first time. When you use the @code{import}
+@c <en>command to track third-party sources, the @dfn{vendor
+@c <en>tag} and @dfn{release tags} are useful. The
+@c <en>@dfn{vendor tag} is a symbolic name for the branch
+@c <en>(which is always 1.1.1, unless you use the @samp{-b
+@c <en>@var{branch}} flag---see @ref{Multiple vendor branches}.). The
+@c <en>@dfn{release tags} are symbolic names for a particular
+@c <en>release, such as @samp{FSF_0_04}.
+Use the @code{import} command to check in the sources
+for the first time. When you use the @code{import}
+command to track third-party sources, the @dfn{vendor
+tag} and @dfn{release tags} are useful. The
+@dfn{vendor tag} is a symbolic name for the branch
+(which is always 1.1.1, unless you use the @samp{-b
+@var{branch}} flag---see @ref{Ramos de fornecedor múltiplos}.). The
+@dfn{release tags} are symbolic names for a particular
+release, such as @samp{FSF_0_04}.
+
+@c I'm not completely sure this belongs here. But
+@c we need to say it _somewhere_ reasonably obvious; it
+@c is a common misconception among people first learning CVS
+@c <en>Note that @code{import} does @emph{not} change the
+@c <en>directory in which you invoke it. In particular, it
+@c <en>does not set up that directory as a @sc{cvs} working
+@c <en>directory; if you want to work with the sources import
+@c <en>them first and then check them out into a different
+@c <en>directory (@pxref{Getting the source}).
+Note that @code{import} does @emph{not} change the
+directory in which you invoke it. In particular, it
+does not set up that directory as a @sc{cvs} working
+directory; if you want to work with the sources import
+them first and then check them out into a different
+directory (@pxref{Obtendo os fontes}).
+
+@c <en>@cindex wdiff (import example)
+@cindex wdiff (import example)
+@c <en>Suppose you have the sources to a program called
+@c <en>@code{wdiff} in a directory @file{wdiff-0.04},
+@c <en>and are going to make private modifications that you
+@c <en>want to be able to use even when new releases are made
+@c <en>in the future. You start by importing the source to
+@c <en>your repository:
+Suppose you have the sources to a program called
+@code{wdiff} in a directory @file{wdiff-0.04},
+and are going to make private modifications that you
+want to be able to use even when new releases are made
+in the future. You start by importing the source to
+your repository:
+
+@example
+$ cd wdiff-0.04
+$ cvs import -m "Import of FSF v. 0.04" fsf/wdiff FSF_DIST WDIFF_0_04
+@end example
+
+@c <en>The vendor tag is named @samp{FSF_DIST} in the above
+@c <en>example, and the only release tag assigned is
+@c <en>@samp{WDIFF_0_04}.
+The vendor tag is named @samp{FSF_DIST} in the above
+example, and the only release tag assigned is
+@samp{WDIFF_0_04}.
+@c FIXME: Need to say where fsf/wdiff comes from.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Update imports
+@node Importações de atualização
+@c <en>@section Updating with the import command
+@section Updating with the import command
+
+@c <en>When a new release of the source arrives, you import it into the
+@c <en>repository with the same @code{import} command that you used to set up
+@c <en>the repository in the first place. The only difference is that you
+@c <en>specify a different release tag this time:
+When a new release of the source arrives, you import it into the
+repository with the same @code{import} command that you used to set up
+the repository in the first place. The only difference is that you
+specify a different release tag this time:
+
+@example
+$ tar xfz wdiff-0.05.tar.gz
+$ cd wdiff-0.05
+$ cvs import -m "Import of FSF v. 0.05" fsf/wdiff FSF_DIST WDIFF_0_05
+@end example
+
+@c <en>For files that have not been modified locally, the newly created
+@c <en>revision becomes the head revision. If you have made local
+@c <en>changes, @code{import} will warn you that you must merge the changes
+@c <en>into the main trunk, and tell you to use @samp{checkout -j} to do so:
+For files that have not been modified locally, the newly created
+revision becomes the head revision. If you have made local
+changes, @code{import} will warn you that you must merge the changes
+into the main trunk, and tell you to use @samp{checkout -j} to do so:
+
+@c FIXME: why "wdiff" here and "fsf/wdiff" in the
+@c "import"? I think the assumption is that one has
+@c "wdiff fsf/wdiff" or some such in modules, but it
+@c would be better to not use modules in this example.
+@example
+$ cvs checkout -jFSF_DIST:yesterday -jFSF_DIST wdiff
+@end example
+
+@noindent
+@c <en>The above command will check out the latest revision of
+@c <en>@samp{wdiff}, merging the changes made on the vendor branch @samp{FSF_DIST}
+@c <en>since yesterday into the working copy. If any conflicts arise during
+@c <en>the merge they should be resolved in the normal way (@pxref{Conflicts
+@c <en>example}). Then, the modified files may be committed.
+The above command will check out the latest revision of
+@samp{wdiff}, merging the changes made on the vendor branch @samp{FSF_DIST}
+since yesterday into the working copy. If any conflicts arise during
+the merge they should be resolved in the normal way
+(@pxref{Exemplo de conflitos}). Then, the modified files may be committed.
+
+@c <en>However, it is much better to use the two release tags rather than using
+@c <en>a date on the branch as suggested above:
+However, it is much better to use the two release tags rather than using
+a date on the branch as suggested above:
+
+@example
+$ cvs checkout -jWDIFF_0_04 -jWDIFF_0_05 wdiff
+@end example
+
+@noindent
+@c <en>The reason this is better is that
+@c <en>using a date, as suggested above, assumes that you do
+@c <en>not import more than one release of a product per day.
+@c <en>More importantly, using the release tags allows @sc{cvs} to detect files
+@c <en>that were removed between the two vendor releases and mark them for
+@c <en>removal. Since @code{import} has no way to detect removed files, you
+@c <en>should do a merge like this even if @code{import} doesn't tell you to.
+The reason this is better is that
+using a date, as suggested above, assumes that you do
+not import more than one release of a product per day.
+More importantly, using the release tags allows @sc{cvs} to detect files
+that were removed between the two vendor releases and mark them for
+removal. Since @code{import} has no way to detect removed files, you
+should do a merge like this even if @code{import} doesn't tell you to.
+
+@c <en>@node Reverting local changes
+@node Reverting local changes
+@c <en>@section Reverting to the latest vendor release
+@section Reverting to the latest vendor release
+
+@c <en>You can also revert local changes completely and return
+@c <en>to the latest vendor release by changing the `head'
+@c <en>revision back to the vendor branch on all files. For
+@c <en>example, if you have a checked-out copy of the sources
+@c <en>in @file{~/work.d/wdiff}, and you want to revert to the
+@c <en>vendor's version for all the files in that directory,
+@c <en>you would type:
+You can also revert local changes completely and return
+to the latest vendor release by changing the `head'
+revision back to the vendor branch on all files. For
+example, if you have a checked-out copy of the sources
+in @file{~/work.d/wdiff}, and you want to revert to the
+vendor's version for all the files in that directory,
+you would type:
+
+@example
+$ cd ~/work.d/wdiff
+$ cvs admin -bFSF_DIST .
+@end example
+
+@noindent
+@c <en>You must specify the @samp{-bFSF_DIST} without any space
+@c <en>after the @samp{-b}. @xref{admin options}.
+You must specify the @samp{-bFSF_DIST} without any space
+after the @samp{-b}. @xref{admin options}.
+
+@c <en>@node Binary files in imports
+@node Arquivos binários em importações
+@c <en>@section How to handle binary files with cvs import
+@section How to handle binary files with cvs import
+
+@c <en>Use the @samp{-k} wrapper option to tell import which
+@c <en>files are binary. @xref{Wrappers}.
+Use the @samp{-k} wrapper option to tell import which
+files are binary. @xref{Wrappers}.
+
+@c <en>@node Keywords in imports
+@node Palavras-chave em importações
+@c <en>@section How to handle keyword substitution with cvs import
+@section Como lidar com substituição de palavras-chave com o cvs import
+
+@c <en>The sources which you are importing may contain
+@c <en>keywords (@pxref{Keyword substitution}). For example,
+@c <en>the vendor may use @sc{cvs} or some other system
+@c <en>which uses similar keyword expansion syntax. If you
+@c <en>just import the files in the default fashion, then
+@c <en>the keyword expansions supplied by the vendor will
+@c <en>be replaced by keyword expansions supplied by your
+@c <en>own copy of @sc{cvs}. It may be more convenient to
+@c <en>maintain the expansions supplied by the vendor, so
+@c <en>that this information can supply information about
+@c <en>the sources that you imported from the vendor.
+The sources which you are importing may contain
+keywords (@pxref{Substituição de palavra-chave}). For example,
+the vendor may use @sc{cvs} or some other system
+which uses similar keyword expansion syntax. If you
+just import the files in the default fashion, then
+the keyword expansions supplied by the vendor will
+be replaced by keyword expansions supplied by your
+own copy of @sc{cvs}. It may be more convenient to
+maintain the expansions supplied by the vendor, so
+that this information can supply information about
+the sources that you imported from the vendor.
+
+@c <en>To maintain the keyword expansions supplied by the
+@c <en>vendor, supply the @samp{-ko} option to @code{cvs
+@c <en>import} the first time you import the file.
+@c <en>This will turn off keyword expansion
+@c <en>for that file entirely, so if you want to be more
+@c <en>selective you'll have to think about what you want
+@c <en>and use the @samp{-k} option to @code{cvs update} or
+@c <en>@code{cvs admin} as appropriate.
+To maintain the keyword expansions supplied by the
+vendor, supply the @samp{-ko} option to @code{cvs
+import} the first time you import the file.
+This will turn off keyword expansion
+for that file entirely, so if you want to be more
+selective you'll have to think about what you want
+and use the @samp{-k} option to @code{cvs update} or
+@code{cvs admin} as appropriate.
+@c Supplying -ko to import if the file already existed
+@c has no effect. Not clear to me whether it should
+@c or not.
+
+@c <en>@node Multiple vendor branches
+@node Ramos de fornecedor múltiplos
+@c <en>@section Multiple vendor branches
+@section Ramos de fornecedor múltiplos
+
+@c <en>All the examples so far assume that there is only one
+@c <en>vendor from which you are getting sources. In some
+@c <en>situations you might get sources from a variety of
+@c <en>places. For example, suppose that you are dealing with
+@c <en>a project where many different people and teams are
+@c <en>modifying the software. There are a variety of ways to
+@c <en>handle this, but in some cases you have a bunch of
+@c <en>source trees lying around and what you want to do more
+@c <en>than anything else is just to all put them in @sc{cvs} so
+@c <en>that you at least have them in one place.
+All the examples so far assume that there is only one
+vendor from which you are getting sources. In some
+situations you might get sources from a variety of
+places. For example, suppose that you are dealing with
+a project where many different people and teams are
+modifying the software. There are a variety of ways to
+handle this, but in some cases you have a bunch of
+source trees lying around and what you want to do more
+than anything else is just to all put them in @sc{cvs} so
+that you at least have them in one place.
+
+@c <en>For handling situations in which there may be more than
+@c <en>one vendor, you may specify the @samp{-b} option to
+@c <en>@code{cvs import}. It takes as an argument the vendor
+@c <en>branch to import to. The default is @samp{-b 1.1.1}.
+For handling situations in which there may be more than
+one vendor, you may specify the @samp{-b} option to
+@code{cvs import}. It takes as an argument the vendor
+branch to import to. The default is @samp{-b 1.1.1}.
+
+@c <en>For example, suppose that there are two teams, the red
+@c <en>team and the blue team, that are sending you sources.
+@c <en>You want to import the red team's efforts to branch
+@c <en>1.1.1 and use the vendor tag RED. You want to import
+@c <en>the blue team's efforts to branch 1.1.3 and use the
+@c <en>vendor tag BLUE. So the commands you might use are:
+For example, suppose that there are two teams, the red
+team and the blue team, that are sending you sources.
+You want to import the red team's efforts to branch
+1.1.1 and use the vendor tag RED. You want to import
+the blue team's efforts to branch 1.1.3 and use the
+vendor tag BLUE. So the commands you might use are:
+
+@example
+$ cvs import dir RED RED_1-0
+$ cvs import -b 1.1.3 dir BLUE BLUE_1-5
+@end example
+
+Note that if your vendor tag does not match your
+@samp{-b} option, @sc{cvs} will not detect this case! For
+example,
+
+@example
+$ cvs import -b 1.1.3 dir RED RED_1-0
+@end example
+
+@noindent
+@c <en>Be careful; this kind of mismatch is sure to sow
+@c <en>confusion or worse. I can't think of a useful purpose
+@c <en>for the ability to specify a mismatch here, but if you
+@c <en>discover such a use, don't. @sc{cvs} is likely to make this
+@c <en>an error in some future release.
+Be careful; this kind of mismatch is sure to sow
+confusion or worse. I can't think of a useful purpose
+for the ability to specify a mismatch here, but if you
+discover such a use, don't. @sc{cvs} is likely to make this
+an error in some future release.
+
+@c Probably should say more about the semantics of
+@c multiple branches. What about the default branch?
+@c What about joining (perhaps not as useful with
+@c multiple branches, or perhaps it is. Either way
+@c should be mentioned).
+
+@c I'm not sure about the best location for this. In
+@c one sense, it might belong right after we've introduced
+@c CVS's basic version control model, because people need
+@c to figure out builds right away. The current location
+@c is based on the theory that it kind of akin to the
+@c "Revision management" section.
+@c <en>@node Builds
+@node Builds
+@c <en>@chapter How your build system interacts with CVS
+@chapter How your build system interacts with CVS
+@c <en>@cindex Builds
+@cindex Builds
+@c <en>@cindex make
+@cindex make
+
+@c <en>As mentioned in the introduction, @sc{cvs} does not
+@c <en>contain software for building your software from source
+@c <en>code. This section describes how various aspects of
+@c <en>your build system might interact with @sc{cvs}.
+As mentioned in the introduction, @sc{cvs} does not
+contain software for building your software from source
+code. This section describes how various aspects of
+your build system might interact with @sc{cvs}.
+
+@c Is there a way to discuss this without reference to
+@c tools other than CVS? I'm not sure there is; I
+@c wouldn't think that people who learn CVS first would
+@c even have this concern.
+@c <en>One common question, especially from people who are
+@c <en>accustomed to @sc{rcs}, is how to make their build get
+@c <en>an up to date copy of the sources. The answer to this
+@c <en>with @sc{cvs} is two-fold. First of all, since
+@c <en>@sc{cvs} itself can recurse through directories, there
+@c <en>is no need to modify your @file{Makefile} (or whatever
+@c <en>configuration file your build tool uses) to make sure
+@c <en>each file is up to date. Instead, just use two
+@c <en>commands, first @code{cvs -q update} and then
+@c <en>@code{make} or whatever the command is to invoke your
+@c <en>build tool. Secondly, you do not necessarily
+@c <en>@emph{want} to get a copy of a change someone else made
+@c <en>until you have finished your own work. One suggested
+@c <en>approach is to first update your sources, then
+@c <en>implement, build and
+@c <en>test the change you were thinking of, and then commit
+@c <en>your sources (updating first if necessary). By
+@c <en>periodically (in between changes, using the approach
+@c <en>xjust described) updating your entire tree, you ensure
+@c <en>that your sources are sufficiently up to date.
+One common question, especially from people who are
+accustomed to @sc{rcs}, is how to make their build get
+an up to date copy of the sources. The answer to this
+with @sc{cvs} is two-fold. First of all, since
+@sc{cvs} itself can recurse through directories, there
+is no need to modify your @file{Makefile} (or whatever
+configuration file your build tool uses) to make sure
+each file is up to date. Instead, just use two
+commands, first @code{cvs -q update} and then
+@code{make} or whatever the command is to invoke your
+build tool. Secondly, you do not necessarily
+@emph{want} to get a copy of a change someone else made
+until you have finished your own work. One suggested
+approach is to first update your sources, then
+implement, build and
+test the change you were thinking of, and then commit
+your sources (updating first if necessary). By
+periodically (in between changes, using the approach
+just described) updating your entire tree, you ensure
+that your sources are sufficiently up to date.
+
+@c <en>@cindex Bill of materials
+@cindex Bill of materials
+@c <en>One common need is to record which versions of which
+@c <en>source files went into a particular build. This kind
+@c <en>of functionality is sometimes called @dfn{bill of
+@c <en>materials} or something similar. The best way to do
+@c <en>this with @sc{cvs} is to use the @code{tag} command to
+@c <en>record which versions went into a given build
+@c <en>(@pxref{Tags}).
+One common need is to record which versions of which
+source files went into a particular build. This kind
+of functionality is sometimes called @dfn{bill of
+materials} or something similar. The best way to do
+this with @sc{cvs} is to use the @code{tag} command to
+record which versions went into a given build
+(@pxref{Etiquetas}).
+
+@c <en>Using @sc{cvs} in the most straightforward manner
+@c <en>possible, each developer will have a copy of the entire
+@c <en>source tree which is used in a particular build. If
+@c <en>the source tree is small, or if developers are
+@c <en>geographically dispersed, this is the preferred
+@c <en>solution. In fact one approach for larger projects is
+@c <en>to break a project down into smaller
+Using @sc{cvs} in the most straightforward manner
+possible, each developer will have a copy of the entire
+source tree which is used in a particular build. If
+the source tree is small, or if developers are
+geographically dispersed, this is the preferred
+solution. In fact one approach for larger projects is
+to break a project down into smaller
+@c I say subsystem instead of module because they may or
+@c may not use the modules file.
+@c <en>separately-compiled subsystems, and arrange a way of
+@c <en>releasing them internally so that each developer need
+@c <en>check out only those subsystems which they are
+@c <en>actively working on.
+separately-compiled subsystems, and arrange a way of
+releasing them internally so that each developer need
+check out only those subsystems which they are
+actively working on.
+
+@c <en>Another approach is to set up a structure which allows
+@c <en>developers to have their own copies of some files, and
+@c <en>for other files to access source files from a central
+@c <en>location. Many people have come up with some such a
+Another approach is to set up a structure which allows
+developers to have their own copies of some files, and
+for other files to access source files from a central
+location. Many people have come up with some such a
+@c two such people are paul@sander.cupertino.ca.us (for
+@c a previous employer)
+@c and gtornblo@senet.abb.se (spicm and related tools),
+@c but as far as I know
+@c no one has nicely packaged or released such a system (or
+@c instructions for constructing one).
+@c <en>system using features such as the symbolic link feature
+@c <en>found in many operating systems, or the @code{VPATH}
+@c <en>feature found in many versions of @code{make}. One build
+@c <en>tool which is designed to help with this kind of thing
+@c <en>is Odin (see
+@c <en>@code{ftp://ftp.cs.colorado.edu/pub/distribs/odin}).
+system using features such as the symbolic link feature
+found in many operating systems, or the @code{VPATH}
+feature found in many versions of @code{make}. One build
+tool which is designed to help with this kind of thing
+is Odin (see
+@code{ftp://ftp.cs.colorado.edu/pub/distribs/odin}).
+@c Should we be saying more about Odin? Or how you use
+@c it with CVS? Also, the Prime Time Freeware for Unix
+@c disk (see http://www.ptf.com/) has Odin (with a nice
+@c paragraph summarizing it on the web), so that might be a
+@c semi-"official" place to point people.
+@c
+@c Of course, many non-CVS systems have this kind of
+@c functionality, for example OSF's ODE
+@c (http://www.osf.org/ode/) or mk
+@c (http://www.grin.net/~pzi/mk-3.18.4.docs/mk_toc.html
+@c He has changed providers in the past; a search engine search
+@c for "Peter Ziobrzynski" probably won't get too many
+@c spurious hits :-). A more stable URL might be
+@c ftp://ftp.uu.net/pub/cmvc/mk). But I'm not sure
+@c there is any point in mentioning them here unless they
+@c can work with CVS.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Special Files
+@node Arquivos especiais
+@c <en>@chapter Special Files
+@chapter Arquivos especiais
+
+@c <en>@cindex Special files
+@cindex Arquivos especiais
+@c <en>@cindex Device nodes
+@cindex Device nodes
+@c <en>@cindex Ownership, saving in CVS
+@cindex Ownership, saving in CVS
+@c <en>@cindex Permissions, saving in CVS
+@cindex Permissions, saving in CVS
+@c <en>@cindex Hard links
+@cindex Hard links
+@c <en>@cindex Symbolic links
+@cindex Symbolic links
+
+@c <en>In normal circumstances, @sc{cvs} works only with regular
+@c <en>files. Every file in a project is assumed to be
+@c <en>persistent; it must be possible to open, read and close
+@c <en>them; and so on. @sc{cvs} also ignores file permissions and
+@c <en>ownerships, leaving such issues to be resolved by the
+@c <en>developer at installation time. In other words, it is
+@c <en>not possible to "check in" a device into a repository;
+@c <en>if the device file cannot be opened, @sc{cvs} will refuse to
+@c <en>handle it. Files also lose their ownerships and
+@c <en>permissions during repository transactions.
+In normal circumstances, @sc{cvs} works only with regular
+files. Every file in a project is assumed to be
+persistent; it must be possible to open, read and close
+them; and so on. @sc{cvs} also ignores file permissions and
+ownerships, leaving such issues to be resolved by the
+developer at installation time. In other words, it is
+not possible to "check in" a device into a repository;
+if the device file cannot be opened, @sc{cvs} will refuse to
+handle it. Files also lose their ownerships and
+permissions during repository transactions.
+
+@ignore
+If the configuration variable @code{PreservePermissions}
+(@pxref{config}) is set in the repository, @sc{cvs} will
+save the following file characteristics in the
+repository:
+
+@itemize @bullet
+@item user and group ownership
+@item permissions
+@item major and minor device numbers
+@item symbolic links
+@item hard link structure
+@end itemize
+
+Using the @code{PreservePermissions} option affects the
+behavior of @sc{cvs} in several ways. First, some of the
+new operations supported by @sc{cvs} are not accessible to
+all users. In particular, file ownership and special
+file characteristics may only be changed by the
+superuser. When the @code{PreservePermissions}
+configuration variable is set, therefore, users will
+have to be `root' in order to perform @sc{cvs} operations.
+
+When @code{PreservePermissions} is in use, some @sc{cvs}
+operations (such as @samp{cvs status}) will not
+recognize a file's hard link structure, and so will
+emit spurious warnings about mismatching hard links.
+The reason is that @sc{cvs}'s internal structure does not
+make it easy for these operations to collect all the
+necessary data about hard links, so they check for file
+conflicts with inaccurate data.
+
+A more subtle difference is that @sc{cvs} considers a file
+to have changed only if its contents have changed
+(specifically, if the modification time of the working
+file does not match that of the repository's file).
+Therefore, if only the permissions, ownership or hard
+linkage have changed, or if a device's major or minor
+numbers have changed, @sc{cvs} will not notice. In order to
+commit such a change to the repository, you must force
+the commit with @samp{cvs commit -f}. This also means
+that if a file's permissions have changed and the
+repository file is newer than the working copy,
+performing @samp{cvs update} will silently change the
+permissions on the working copy.
+
+Changing hard links in a @sc{cvs} repository is particularly
+delicate. Suppose that file @file{foo} is linked to
+file @file{old}, but is later relinked to file
+@file{new}. You can wind up in the unusual situation
+where, although @file{foo}, @file{old} and @file{new}
+have all had their underlying link patterns changed,
+only @file{foo} and @file{new} have been modified, so
+@file{old} is not considered a candidate for checking
+in. It can be very easy to produce inconsistent
+results this way. Therefore, we recommend that when it
+is important to save hard links in a repository, the
+prudent course of action is to @code{touch} any file
+whose linkage or status has changed since the last
+checkin. Indeed, it may be wise to @code{touch *}
+before each commit in a directory with complex hard
+link structures.
+
+It is worth noting that only regular files may
+be merged, for reasons that hopefully are obvious. If
+@samp{cvs update} or @samp{cvs checkout -j} attempts to
+merge a symbolic link with a regular file, or two
+device files for different kinds of devices, @sc{cvs} will
+report a conflict and refuse to perform the merge. At
+the same time, @samp{cvs diff} will not report any
+differences between these files, since no meaningful
+textual comparisons can be made on files which contain
+no text.
+
+The @code{PreservePermissions} features do not work
+with client/server @sc{cvs}. Another limitation is
+that hard links must be to other files within the same
+directory; hard links across directories are not
+supported.
+@end ignore
+
+@c ---------------------------------------------------------------------
+@c <en>@node Comandos do CVS
+@node Comandos do CVS
+@c <en>@appendix Guia dos comandos do CVS
+@appendix Guia dos comandos do CVS
+
+@c <en>This appendix describes the overall structure of
+@c <en>@sc{cvs} commands, and describes some commands in
+@c <en>detail (others are described elsewhere; for a quick
+@c <en>reference to @sc{cvs} commands, @pxref{Invoking CVS}).
+Este apêndice descreve a estrutura geral dos comandos
+do @sc{cvs}, e descreve alguns comandos em detalhe
+(outros são descritos em outra parte; para
+uma referência rápida dos comandos do @sc{cvs},
+@pxref{Chamando o CVS}).
+@c The idea is that we want to move the commands which
+@c are described here into the main body of the manual,
+@c in the process reorganizing the manual to be
+@c organized around what the user wants to do, not
+@c organized around CVS commands.
+@c
+@c Note that many users do expect a manual which is
+@c organized by command. At least some users do.
+@c One good addition to the "organized by command"
+@c section (if any) would be "see also" links.
+@c The awk manual might be a good example; it has a
+@c reference manual which is more verbose than Invoking
+@c CVS but probably somewhat less verbose than CVS
+@c Commands.
+
+@menu
+@c <en>* Structure:: Overall structure of CVS commands
+* Estrutura:: Estrutura geral dos comandos do CVS
+@c <en>* Exit status:: Indicating CVS's success or failure
+* Estados de saída:: Indicando o sucesso ou falha do CVS
+@c <en>* ~/.cvsrc:: Default options with the ~/.cvsrc file
+* ~/.cvsrc:: Opções padrão com o arquivo ~/.cvsrc
+@c <en>* Global options:: Options you give to the left of cvs_command
+* Opções globais:: Opções que você bota a esquerda do comando_do_cvs
+@c <en>* Common options:: Options you give to the right of cvs_command
+* Opções comuns:: Opções que você bota a direita do comando_do_cvs
+@c <en>* admin:: Administration
+* admin:: Administração
+@c <en>* checkout:: Checkout sources for editing
+* checkout:: ???Checkout??? fontes para edição
+@c <en>* commit:: Check files into the repository
+* commit:: Colocar arquivos no repositório
+@c <en>* diff:: Show differences between revisions
+* diff:: Mostrar diferenças entre revisões
+@c <en>* export:: Export sources from CVS, similar to checkout
+* export:: Exportar fontes para fora do CVS, similar ao ???checkout???
+@c <en>* history:: Show status of files and users
+* history:: Mostrar estado de arquivos e usuários
+@c <en>* import:: Import sources into CVS, using vendor branches
+* import:: Importar fontes para dentro do CVS, usando ramos de fornecedor
+@c <en>* log:: Show log messages for files
+* log:: Mostrar mensagens de log para arquivos
+@c <en>* rdiff:: 'patch' format diffs between releases
+* rdiff:: 'patch' format diffs between releases
+@c <en>* release:: Indicate that a directory is no longer in use
+* release:: Avisar que um diretorio não está mais em uso
+@c <en>* update:: Bring work tree in sync with repository
+* update:: Deixar árvore de trabalho em sincronia com o repositório
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Structure
+@node Estrutura
+@c <en>@appendixsec Overall structure of CVS commands
+@appendixsec Estrutura geral dos comandos do CVS
+@c <en>@cindex Structure
+@cindex Estrutura
+@c <en>@cindex CVS command structure
+@cindex Estrutura do comando CVS
+@c <en>@cindex Command structure
+@cindex Estrutura do comando
+@c <en>@cindex Format of CVS commands
+@cindex Formato dos comandos do CVS
+
+@c <en>The overall format of all @sc{cvs} commands is:
+O formato geral de todos os comandos do @sc{cvs} é:
+
+@example
+cvs [ cvs_options ] cvs_command [ command_options ] [ command_args ]
+@end example
+
+@table @code
+@c <en>@item cvs
+@item cvs
+@c <en>The name of the @sc{cvs} program.
+O nome do programa @sc{cvs}.
+
+@c <en>@item cvs_options
+@item cvs_options
+@c <en>Some options that affect all sub-commands of @sc{cvs}. These are
+@c <en>described below.
+Algumas opções que afetam todos os sub-comandos do
+@sc{cvs}. Estes estão descritos abaixo.
+
+@c <en>@item cvs_command
+@item cvs_command
+@c <en>One of several different sub-commands. Some of the commands have
+@c <en>aliases that can be used instead; those aliases are noted in the
+@c <en>reference manual for that command. There are only two situations
+@c <en>where you may omit @samp{cvs_command}: @samp{cvs -H} elicits a
+@c <en>list of available commands, and @samp{cvs -v} displays version
+@c <en>information on @sc{cvs} itself.
+Um dos vários sub-comandos. Alguns dos comandos têm
+???aliases??? substituí-los; estes ???aliases??? são
+listados no manual de referência do comando. Existem
+apenas duas situações onde você pode omitir o
+@samp{cvs_command}: @samp{cvs -H} retorna uma lista de
+comandos disponíveis, e @samp{cvs -v} mostra
+informações sobre a versão do próprio @sc{cvs}.
+
+@c <en>@item command_options
+@item command_options
+@c <en>Options that are specific for the command.
+Opções que são específicas para o comando.
+
+@c <en>@item command_args
+@item command_args
+@c <en>Arguments to the commands.
+Argumentos para os comandos.
+@end table
+
+@c <en>There is unfortunately some confusion between
+@c <en>@code{cvs_options} and @code{command_options}.
+@c <en>@samp{-l}, when given as a @code{cvs_option}, only
+@c <en>affects some of the commands. When it is given as a
+@c <en>@code{command_option} is has a different meaning, and
+@c <en>is accepted by more commands. In other words, do not
+@c <en>take the above categorization too seriously. Look at
+@c <en>the documentation instead.
+Infelizmente, existe alguma confusão entre
+@code{cvs_options} e @code{command_options}. @samp{-l},
+quando passado como @code{cvs_option}, afeta apenas
+alguns dos comandos. Quando é passado como um
+@code{command_option} tem um significado diferente, e é
+aceito por mais comandos. Em outras palavras, não leve
+a categorização acima tão a sério. Olhe a
+documentação, ao invés disto.
+
+@c <en>@node Exit status
+@node Estados de saída
+@c <en>@appendixsec CVS's exit status
+@appendixsec estado de saída do CVS
+@c <en>@cindex Exit status, of CVS
+@cindex Estados de saída do CVS
+
+@c <en>@sc{cvs} can indicate to the calling environment whether it
+@c <en>succeeded or failed by setting its @dfn{exit status}.
+@c <en>The exact way of testing the exit status will vary from
+@c <en>one operating system to another. For example in a unix
+@c <en>shell script the @samp{$?} variable will be 0 if the
+@c <en>last command returned a successful exit status, or
+@c <en>greater than 0 if the exit status indicated failure.
+O @sc{cvs} pode indicar para o ambiente que o chamou se
+ele foi bem-sucedido ou falhou ao ajustar seu
+@dfn{estado de saída}. A forma exata de testar o
+estado de saída varia de um sistema operacional para
+outro. Por exemplo, num shell script do unix a
+variável @samp{$?} será 0 se o último comando retornar
+um estado de saída bem-sucedido, ou maior que 0 se o
+estado de saída indicar uma falha.
+
+@c <en>If @sc{cvs} is successful, it returns a successful status;
+@c <en>if there is an error, it prints an error message and
+@c <en>returns a failure status. The one exception to this is
+@c <en>the @code{cvs diff} command. It will return a
+@c <en>successful status if it found no differences, or a
+@c <en>failure status if there were differences or if there
+@c <en>was an error. Because this behavior provides no good
+@c <en>way to detect errors, in the future it is possible that
+@c <en>@code{cvs diff} will be changed to behave like the
+@c <en>other @sc{cvs} commands.
+Se o @sc{cvs} é bem-sucedido, retorna um estado de sucesso;
+se existe um erro, mostra uma mensagem de erro e
+retorna um estado de falha. A única exceção para isto
+é o comando @code{cvs diff}. Ele retornará um estado
+de sucesso se não encontrar diferenças, ou um estado de
+sucesso se existirem diferenças ou acontecer um erro.
+Já que este comportamento não fornece uma boa maneira
+de detectar erros, é possível que no futuro o @code{cvs
+diff} seja mudado para se comportar como os outros
+comandos do @sc{cvs}.
+@c It might seem like checking whether cvs -q diff
+@c produces empty or non-empty output can tell whether
+@c there were differences or not. But it seems like
+@c there are cases with output but no differences
+@c (testsuite basica-8b). It is not clear to me how
+@c useful it is for a script to be able to check
+@c whether there were differences.
+@c FIXCVS? In previous versions of CVS, cvs diff
+@c returned 0 for no differences, 1 for differences, or
+@c 2 for errors. Is this behavior worth trying to
+@c bring back (but what does it mean for VMS?)?
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node ~/.cvsrc
+@node ~/.cvsrc
+@c <en>@appendixsec Default options and the ~/.cvsrc file
+@appendixsec Opções padrão e o arquivo ~/.cvsrc
+@c <en>@cindex .cvsrc file
+@cindex Arquivo .cvsrc
+@c <en>@cindex Option defaults
+@cindex Padrão, opções
+
+@c <en>There are some @code{command_options} that are used so
+@c <en>often that you might have set up an alias or some other
+@c <en>means to make sure you always specify that option. One
+@c <en>example (the one that drove the implementation of the
+@c <en>@file{.cvsrc} support, actually) is that many people find the
+@c <en>default output of the @samp{diff} command to be very
+@c <en>hard to read, and that either context diffs or unidiffs
+@c <en>are much easier to understand.
+Existem algumas @code{opções_de_comando} que são tão
+usadas que você vai querer preparar um atalho ou
+alguma outra forma de ter certeza que tais opções
+sempre vão ser especificadas. Um exemplo (o que
+motivou a implementação do suporte ao arquivo
+@file{.cvsrc}, na verdade) é que muitas pessoas acham a
+saída do comando @samp{diff} muito difícil de ler, e
+que tanto diffs de contexto quanto unidiffs são muito
+mais fáceis de entender.
+
+@c <en>The @file{~/.cvsrc} file is a way that you can add
+@c <en>default options to @code{cvs_commands} within cvs,
+@c <en>instead of relying on aliases or other shell scripts.
+O arquivo @file{~/.cvsrc} é uma forma de você adicionar
+opções padrão aos @code{comandos_cvs} dentro do cvs, ao
+invés de usar alias (apelidos) ou outros scripts de shell.
+
+@c <en>The format of the @file{~/.cvsrc} file is simple. The
+@c <en>file is searched for a line that begins with the same
+@c <en>name as the @code{cvs_command} being executed. If a
+@c <en>match is found, then the remainder of the line is split
+@c <en>up (at whitespace characters) into separate options and
+@c <en>added to the command arguments @emph{before} any
+@c <en>options from the command line.
+O formato do arquivo @file{~/.cvsrc} é simples. O
+arquivo é varrido por uma linha que comece com o mesmo
+nome do @code{comando_cvs} sendo executado. Se
+encontra, então o restante da linha é dividido (pelos
+espaços) em opções distintas e adicionadas aos
+argumentos do comando @emph{antes} de quaisquer opções
+da linha de comando.
+
+@c <en>If a command has two names (e.g., @code{checkout} and
+@c <en>@code{co}), the official name, not necessarily the one
+@c <en>used on the command line, will be used to match against
+@c <en>the file. So if this is the contents of the user's
+@c <en>@file{~/.cvsrc} file:
+Se um comando tem dois nomes (e.g., @code{checkout} e
+@code{co}), o nome oficial, que não é necessariamente o
+usado na linha de comando, vai ser usado para fazer a
+busca no arquivo. Logo, se este é o conteúdo do
+arquivo @file{~/.cvsrc} do usuário:
+
+@example
+log -N
+diff -uN
+rdiff -u
+update -Pd
+checkout -P
+release -d
+@end example
+
+@noindent
+@c <en>the command @samp{cvs checkout foo} would have the
+@c <en>@samp{-P} option added to the arguments, as well as
+@c <en>@samp{cvs co foo}.
+o comando @samp{cvs checkout foo} vai ter a opção
+@samp{-P} adicionada a seus argumentos, assim como
+@samp{cvs co foo}.
+
+@c <en>With the example file above, the output from @samp{cvs
+@c <en>diff foobar} will be in unidiff format. @samp{cvs diff
+@c <en>-c foobar} will provide context diffs, as usual.
+@c <en>Getting "old" format diffs would be slightly more
+@c <en>complicated, because @code{diff} doesn't have an option
+@c <en>to specify use of the "old" format, so you would need
+@c <en>@samp{cvs -f diff foobar}.
+Com o arquivo de exemplo acima, a saída de @samp{cvs
+diff foobar} vai ser no formato unidiff. @samp{cvs
+diff -c foobar} vai dar diffs de contexto, que é o normal.
+Obter o diff no formato "velho" vai ser um pouco mais
+complicado, já que o @code{diff} não tem uma opção para
+especificar o uso do formato "velho", logo você vai ter
+que usar @samp{cvs -f diff foobar}.
+
+@c <en>In place of the command name you can use @code{cvs} to
+@c <en>specify global options (@pxref{Global options}). For
+@c <en>example the following line in @file{.cvsrc}
+Ao invés de no nome do comando você pode usar o
+@code{cvs} especificando opções globais (@pxref{Opções globais}). Por
+exemplo a seguinte linha em @file{.cvsrc}
+
+@example
+cvs -z6
+@end example
+
+@noindent
+@c <en>causes @sc{cvs} to use compression level 6.
+faz com que o @sc{cvs} use compressão de nível 6.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Global options
+@node Opções globais
+@c <en>@appendixsec Global options
+@appendixsec Opções globais
+@c <en>@cindex Options, global
+@cindex Options, global
+@c <en>@cindex Global options
+@cindex Opções globais
+@c <en>@cindex Left-hand options
+@cindex Left-hand options
+
+The available @samp{cvs_options} (that are given to the
+left of @samp{cvs_command}) are:
+
+@table @code
+@c <en>@item --allow-root=@var{rootdir}
+@item --allow-root=@var{rootdir}
+@c <en>Specify legal @sc{cvsroot} directory. See
+@c <en>@ref{Password authentication server}.
+Specify legal @sc{cvsroot} directory. See
+@ref{Servidor de autenticação por senha}.
+
+@c <en>@cindex Authentication, stream
+@cindex Authentication, stream
+@c <en>@cindex Stream authentication
+@cindex Stream authentication
+@c <en>@item -a
+@item -a
+@c <en>Authenticate all communication between the client and
+@c <en>the server. Only has an effect on the @sc{cvs} client.
+@c <en>As of this writing, this is only implemented when using
+@c <en>a GSSAPI connection (@pxref{GSSAPI authenticated}).
+@c <en>Authentication prevents certain sorts of attacks
+@c <en>involving hijacking the active @sc{tcp} connection.
+@c <en>Enabling authentication does not enable encryption.
+Authenticate all communication between the client and
+the server. Only has an effect on the @sc{cvs} client.
+As of this writing, this is only implemented when using
+a GSSAPI connection (@pxref{Autenticação GSSAPI}).
+Authentication prevents certain sorts of attacks
+involving hijacking the active @sc{tcp} connection.
+Enabling authentication does not enable encryption.
+
+@cindex RCSBIN, overriding
+@cindex Overriding RCSBIN
+@item -b @var{bindir}
+In @sc{cvs} 1.9.18 and older, this specified that
+@sc{rcs} programs are in the @var{bindir} directory.
+Current versions of @sc{cvs} do not run @sc{rcs}
+programs; for compatibility this option is accepted,
+but it does nothing.
+
+@cindex TMPDIR, overriding
+@cindex Overriding TMPDIR
+@item -T @var{tempdir}
+Use @var{tempdir} as the directory where temporary files are
+located. Overrides the setting of the @code{$TMPDIR} environment
+variable and any precompiled directory. This parameter should be
+specified as an absolute pathname.
+(When running client/server, @samp{-T} affects only the local process;
+specifying @samp{-T} for the client has no effect on the server and
+vice versa.)
+
+@cindex CVSROOT, overriding
+@cindex Overriding CVSROOT
+@item -d @var{cvs_root_directory}
+Use @var{cvs_root_directory} as the root directory
+pathname of the repository. Overrides the setting of
+the @code{$CVSROOT} environment variable. @xref{Repositório}.
+
+@c <en>@cindex EDITOR, overriding
+@cindex EDITOR, overriding
+@c <en>@cindex Overriding EDITOR
+@cindex Overriding EDITOR
+@c <en>@item -e @var{editor}
+@item -e @var{editor}
+@c <en>Use @var{editor} to enter revision log information. Overrides the
+@c <en>setting of the @code{$CVSEDITOR} and @code{$EDITOR}
+@c <en>environment variables. For more information, see
+@c <en>@ref{Committing your changes}.
+Use @var{editor} to enter revision log information. Overrides the
+setting of the @code{$CVSEDITOR} and @code{$EDITOR}
+environment variables. For more information, see
+@ref{Efetivando suas alterações}.
+
+@item -f
+Do not read the @file{~/.cvsrc} file. This
+option is most often used because of the
+non-orthogonality of the @sc{cvs} option set. For
+example, the @samp{cvs log} option @samp{-N} (turn off
+display of tag names) does not have a corresponding
+option to turn the display on. So if you have
+@samp{-N} in the @file{~/.cvsrc} entry for @samp{log},
+you may need to use @samp{-f} to show the tag names.
+
+@item -H
+@itemx --help
+Display usage information about the specified @samp{cvs_command}
+(but do not actually execute the command). If you don't specify
+a command name, @samp{cvs -H} displays overall help for
+@sc{cvs}, including a list of other help options.
+@c It seems to me it is better to document it this way
+@c rather than trying to update this documentation
+@c every time that we add a --help-foo option. But
+@c perhaps that is confusing...
+
+@item -l
+Do not log the @samp{cvs_command} in the command history (but execute it
+anyway). @xref{history}, for information on command history.
+
+@cindex Read-only repository mode
+@item -R
+Turns on read-only repository mode. This allows one to check out from a
+read-only repository, such as within an anoncvs server, or from a CDROM
+repository.
+
+Same effect as if the @code{CVSREADONLYFS} environment
+variable is set. Using @samp{-R} can also considerably
+speed up checkout's over NFS.
+
+@cindex Read-only mode
+@item -n
+Do not change any files. Attempt to execute the
+@samp{cvs_command}, but only to issue reports; do not remove,
+update, or merge any existing files, or create any new files.
+
+Note that @sc{cvs} will not necessarily produce exactly
+the same output as without @samp{-n}. In some cases
+the output will be the same, but in other cases
+@sc{cvs} will skip some of the processing that would
+have been required to produce the exact same output.
+
+@item -Q
+Cause the command to be really quiet; the command will only
+generate output for serious problems.
+
+@item -q
+Cause the command to be somewhat quiet; informational messages,
+such as reports of recursion through subdirectories, are
+suppressed.
+
+@c <en>@cindex Read-only files, and -r
+@cindex Read-only files, and -r
+@c <en>@item -r
+@item -r
+@c <en>Make new working files read-only. Same effect
+@c <en>as if the @code{$CVSREAD} environment variable is set
+@c <en>(@pxref{Environment variables}). The default is to
+@c <en>make working files writable, unless watches are on
+@c <en>(@pxref{Watches}).
+Make new working files read-only. Same effect
+as if the @code{$CVSREAD} environment variable is set
+(@pxref{Variáveis de ambiente}). The default is to
+make working files writable, unless watches are on
+(@pxref{???Watches???}).
+
+@item -s @var{variable}=@var{value}
+Set a user variable (@pxref{Variables}).
+
+@cindex Trace
+@item -t
+Trace program execution; display messages showing the steps of
+@sc{cvs} activity. Particularly useful with @samp{-n} to explore the
+potential impact of an unfamiliar command.
+
+@item -v
+@item --version
+Display version and copyright information for @sc{cvs}.
+
+@cindex CVSREAD, overriding
+@cindex Overriding CVSREAD
+@item -w
+Make new working files read-write. Overrides the
+setting of the @code{$CVSREAD} environment variable.
+Files are created read-write by default, unless @code{$CVSREAD} is
+set or @samp{-r} is given.
+@c Note that -w only overrides -r and CVSREAD; it has
+@c no effect on files which are readonly because of
+@c "cvs watch on". My guess is that is the way it
+@c should be (or should "cvs -w get" on a watched file
+@c be the same as a get and a cvs edit?), but I'm not
+@c completely sure whether to document it this way.
+
+@item -x
+@c <en>@cindex Encryption
+@cindex Encryption
+@c <en>Encrypt all communication between the client and the
+@c <en>server. Only has an effect on the @sc{cvs} client. As
+@c <en>of this writing, this is only implemented when using a
+@c <en>GSSAPI connection (@pxref{GSSAPI authenticated}) or a
+@c <en>Kerberos connection (@pxref{Kerberos authenticated}).
+@c <en>Enabling encryption implies that message traffic is
+@c <en>also authenticated. Encryption support is not
+@c <en>available by default; it must be enabled using a
+@c <en>special configure option, @file{--enable-encryption},
+@c <en>when you build @sc{cvs}.
+Encrypt all communication between the client and the
+server. Only has an effect on the @sc{cvs} client. As
+of this writing, this is only implemented when using a
+GSSAPI connection (@pxref{Autenticação GSSAPI}) or a
+Kerberos connection (@pxref{Autenticação kerberos}).
+Enabling encryption implies that message traffic is
+also authenticated. Encryption support is not
+available by default; it must be enabled using a
+special configure option, @file{--enable-encryption},
+when you build @sc{cvs}.
+
+@item -z @var{gzip-level}
+@cindex Compression
+@cindex Gzip
+Set the compression level.
+Valid levels are 1 (high speed, low compression) to
+9 (low speed, high compression), or 0 to disable
+compression (the default).
+Only has an effect on the @sc{cvs} client.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node Common options
+@node Opções comuns
+@c <en>@appendixsec Common command options
+@appendixsec Common command options
+@c <en>@cindex Common options
+@cindex Opções comuns
+@c <en>@cindex Right-hand options
+@cindex Right-hand options
+
+This section describes the @samp{command_options} that
+are available across several @sc{cvs} commands. These
+options are always given to the right of
+@samp{cvs_command}. Not all
+commands support all of these options; each option is
+only supported for commands where it makes sense.
+However, when a command has one of these options you
+can almost always count on the same behavior of the
+option as in other commands. (Other command options,
+which are listed with the individual commands, may have
+different behavior from one @sc{cvs} command to the other).
+
+@strong{Note: the @samp{history} command is an exception; it supports
+many options that conflict even with these standard options.}
+
+@table @code
+@cindex Dates
+@cindex Time
+@cindex Specifying dates
+@item -D @var{date_spec}
+Use the most recent revision no later than @var{date_spec}.
+@var{date_spec} is a single argument, a date description
+specifying a date in the past.
+
+@c <en>The specification is @dfn{sticky} when you use it to make a
+@c <en>private copy of a source file; that is, when you get a working
+@c <en>file using @samp{-D}, @sc{cvs} records the date you specified, so that
+@c <en>further updates in the same directory will use the same date
+@c <en>(for more information on sticky tags/dates, @pxref{Sticky tags}).
+The specification is @dfn{sticky} when you use it to make a
+private copy of a source file; that is, when you get a working
+file using @samp{-D}, @sc{cvs} records the date you specified, so that
+further updates in the same directory will use the same date
+(for more information on sticky tags/dates, @pxref{Etiquetas adesivas}).
+
+@samp{-D} is available with the @code{annotate}, @code{checkout},
+@code{diff}, @code{export}, @code{history},
+@code{rdiff}, @code{rtag}, @code{tag}, and @code{update} commands.
+(The @code{history} command uses this option in a
+slightly different way; @pxref{history options}).
+
+@c What other formats should we accept? I don't want
+@c to start accepting a whole mess of non-standard
+@c new formats (there are a lot which are in wide use in
+@c one context or another), but practicality does
+@c dictate some level of flexibility.
+@c * POSIX.2 (e.g. touch, ls output, date) and other
+@c POSIX and/or de facto unix standards (e.g. at). The
+@c practice here is too inconsistent to be of any use.
+@c * VMS dates. This is not a formal standard, but
+@c there is a published specification (see SYS$ASCTIM
+@c and SYS$BINTIM in the _VMS System Services Reference
+@c Manual_), it is implemented consistently in VMS
+@c utilities, and VMS users will expect CVS running on
+@c VMS to support this format (and if we're going to do
+@c that, better to make CVS support it on all
+@c platforms. Maybe).
+@c
+@c NOTE: The tar manual has some documentation for
+@c getdate.y (just for our info; we don't want to
+@c attempt to document all the formats accepted by
+@c getdate.y).
+@c
+@c One more note: In output, CVS should consistently
+@c use one date format, and that format should be one that
+@c it accepts in input as well. The former isn't
+@c really true (see survey below), and I'm not
+@c sure that either of those formats is accepted in
+@c input.
+@c
+@c cvs log
+@c current 1996/01/02 13:45:31
+@c Internet 02 Jan 1996 13:45:31 UT
+@c ISO 1996-01-02 13:45:31
+@c cvs ann
+@c current 02-Jan-96
+@c Internet-like 02 Jan 96
+@c ISO 96-01-02
+@c cvs status
+@c current Tue Jun 11 02:54:53 1996
+@c Internet [Tue,] 11 Jun 1996 02:54:53
+@c ISO 1996-06-11 02:54:53
+@c note: date possibly should be omitted entirely for
+@c other reasons.
+@c cvs editors
+@c current Tue Jun 11 02:54:53 1996 GMT
+@c cvs history
+@c current 06/11 02:54 +0000
+@c any others?
+@c There is a good chance the proper solution has to
+@c involve at least some level of letting the user
+@c decide which format (with the default being the
+@c formats CVS has always used; changing these might be
+@c _very_ disruptive since scripts may very well be
+@c parsing them).
+@c
+@c Another random bit of prior art concerning dates is
+@c the strptime function which takes templates such as
+@c "%m/%d/%y", and apparent a variant of getdate()
+@c which also honors them. See
+@c X/Open CAE Specification, System Interfaces and
+@c Headers Issue 4, Version 2 (September 1994), in the
+@c entry for getdate() on page 231
+
+@cindex Timezone, in input
+@cindex Zone, time, in input
+A wide variety of date formats are supported by
+@sc{cvs}. The most standard ones are ISO8601 (from the
+International Standards Organization) and the Internet
+e-mail standard (specified in RFC822 as amended by
+RFC1123).
+
+@c Probably should be doing more to spell out just what
+@c the rules are, rather than just giving examples.
+@c But I want to keep this simple too.
+@c So I don't know....
+@c A few specific issues: (1) Maybe should reassure
+@c people that years after 2000
+@c work (they are in the testsuite, so they do indeed
+@c work). (2) What do two digit years
+@c mean? Where do we accept them? (3) Local times can
+@c be ambiguous or nonexistent if they fall during the
+@c hour when daylight savings time goes into or out of
+@c effect. Pretty obscure, so I'm not at all sure we
+@c should be documenting the behavior in that case.
+ISO8601 dates have many variants but a few examples
+are:
+
+@example
+1972-09-24
+1972-09-24 20:05
+@end example
+@c I doubt we really accept all ISO8601 format dates
+@c (for example, decimal hours like 1972-09-24 20,2)
+@c I'm not sure we should, many of them are pretty
+@c bizarre and it has lots of gratuitous multiple ways
+@c to specify the same thing.
+
+There are a lot more ISO8601 date formats, and @sc{cvs}
+accepts many of them, but you probably don't want to
+hear the @emph{whole} long story :-).
+
+@c Citing a URL here is kind of problematic given how
+@c much they change and people who have old versions of
+@c this manual, but in case we want to reinstate an
+@c ISO8601 URL, a few are:
+@c http://www.saqqara.demon.co.uk/datefmt.htm
+@c http://www.cl.cam.ac.uk/~mgk25/iso-time.html
+@c Citing some other ISO8601 source is probably even
+@c worse :-).
+
+In addition to the dates allowed in Internet e-mail
+itself, @sc{cvs} also allows some of the fields to be
+omitted. For example:
+@c FIXME: Need to figure out better, and document,
+@c what we want to allow the user to omit.
+@c NOTE: "omit" does not imply "reorder".
+@c FIXME: Need to cite a web page describing how to get
+@c RFC's.
+
+@example
+24 Sep 1972 20:05
+24 Sep
+@end example
+
+The date is interpreted as being in the
+local timezone, unless a specific timezone is
+specified.
+
+These two date formats are preferred. However,
+@sc{cvs} currently accepts a wide variety of other date
+formats. They are intentionally not documented here in
+any detail, and future versions of @sc{cvs} might not
+accept all of them.
+@c We should document and testsuite "now" and
+@c "yesterday". "now" is mentioned in the FAQ and
+@c "yesterday" is mentioned in this document (and the
+@c message from "cvs import" suggesting a merge
+@c command). What else? Probably some/all of the "3
+@c weeks ago" family.
+@c
+@c Maybe at
+@c some point have CVS start give warnings on "unofficial"
+@c formats (many of which might be typos or user
+@c misunderstandings, and/or formats people never/rarely
+@c use to specify dates)?
+
+One such format is
+@code{@var{month}/@var{day}/@var{year}}. This may
+confuse people who are accustomed to having the month
+and day in the other order; @samp{1/4/96} is January 4,
+not April 1.
+
+Remember to quote the argument to the @samp{-D}
+flag so that your shell doesn't interpret spaces as
+argument separators. A command using the @samp{-D}
+flag can look like this:
+
+@example
+$ cvs diff -D "1 hour ago" cvs.texinfo
+@end example
+
+@cindex Forcing a tag match
+@item -f
+When you specify a particular date or tag to @sc{cvs} commands, they
+normally ignore files that do not contain the tag (or did not
+exist prior to the date) that you specified. Use the @samp{-f} option
+if you want files retrieved even when there is no match for the
+tag or date. (The most recent revision of the file
+will be used).
+
+Note that even with @samp{-f}, a tag that you specify
+must exist (that is, in some file, not necessary in
+every file). This is so that @sc{cvs} will continue to
+give an error if you mistype a tag name.
+
+@need 800
+@samp{-f} is available with these commands:
+@code{annotate}, @code{checkout}, @code{export},
+@code{rdiff}, @code{rtag}, and @code{update}.
+
+@c <en>@strong{WARNING: The @code{commit} and @code{remove}
+@c <en>commands also have a
+@c <en>@samp{-f} option, but it has a different behavior for
+@c <en>those commands. See @ref{commit options}, and
+@c <en>@ref{Removing files}.}
+@strong{WARNING: The @code{commit} and @code{remove}
+commands also have a
+@samp{-f} option, but it has a different behavior for
+those commands. See @ref{commit options}, and
+@ref{Removendo arquivos}.}
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Override the default processing of RCS keywords other than
+@c <en>@samp{-kb}. @xref{Keyword substitution}, for the meaning of
+@c <en>@var{kflag}. Used with the @code{checkout} and @code{update}
+@c <en>commands, your @var{kflag} specification is
+@c <en>@dfn{sticky}; that is, when you use this option
+@c <en>with a @code{checkout} or @code{update} command,
+@c <en>@sc{cvs} associates your selected @var{kflag} with any files
+@c <en>it operates on, and continues to use that @var{kflag} with future
+@c <en>commands on the same files until you specify otherwise.
+Override the default processing of RCS keywords other than
+@samp{-kb}. @xref{Substituição de palavra-chave}, for the meaning of
+@var{kflag}. Used with the @code{checkout} and @code{update}
+commands, your @var{kflag} specification is
+@dfn{sticky}; that is, when you use this option
+with a @code{checkout} or @code{update} command,
+@sc{cvs} associates your selected @var{kflag} with any files
+it operates on, and continues to use that @var{kflag} with future
+commands on the same files until you specify otherwise.
+
+@c <en>The @samp{-k} option is available with the @code{add},
+@c <en>@code{checkout}, @code{diff}, @code{export}, @code{import} and
+@c <en>@code{update} commands.
+The @samp{-k} option is available with the @code{add},
+@code{checkout}, @code{diff}, @code{export}, @code{import} and
+@code{update} commands.
+
+@c <en>@strong{WARNING: Prior to CVS version 1.12.2, the @samp{-k} flag
+@c <en>overrode the @samp{-kb} indication for a binary file. This could
+@c <en>sometimes corrupt binary files. @xref{Merging and keywords}, for
+@c <en>more.}
+@strong{WARNING: Prior to CVS version 1.12.2, the @samp{-k} flag
+overrode the @samp{-kb} indication for a binary file. This could
+sometimes corrupt binary files. @xref{Mesclagem e palavras-chave}, for
+more.}
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory, rather than
+@c <en>recursing through subdirectories.
+Local; run only in current working directory, rather than
+recursing through subdirectories.
+
+@c <en>Available with the following commands: @code{annotate}, @code{checkout},
+@c <en>@code{commit}, @code{diff}, @code{edit}, @code{editors}, @code{export},
+@c <en>@code{log}, @code{rdiff}, @code{remove}, @code{rtag},
+@c <en>@code{status}, @code{tag}, @code{unedit}, @code{update}, @code{watch},
+@c <en>and @code{watchers}.
+Available with the following commands: @code{annotate}, @code{checkout},
+@code{commit}, @code{diff}, @code{edit}, @code{editors}, @code{export},
+@code{log}, @code{rdiff}, @code{remove}, @code{rtag},
+@code{status}, @code{tag}, @code{unedit}, @code{update}, @code{watch},
+and @code{watchers}.
+
+@c <en>@cindex Editor, avoiding invocation of
+@cindex Editor, avoiding invocation of
+@c <en>@cindex Avoiding editor invocation
+@cindex Avoiding editor invocation
+@c <en>@item -m @var{message}
+@item -m @var{message}
+@c <en>Use @var{message} as log information, instead of
+@c <en>invoking an editor.
+Use @var{message} as log information, instead of
+invoking an editor.
+
+@c <en>Available with the following commands: @code{add},
+@c <en>@code{commit} and @code{import}.
+Available with the following commands: @code{add},
+@code{commit} and @code{import}.
+
+@c <en>@item -n
+@item -n
+@c <en>Do not run any tag program. (A program can be
+@c <en>specified to run in the modules
+@c <en>database (@pxref{modules}); this option bypasses it).
+Do not run any tag program. (A program can be
+specified to run in the modules
+database (@pxref{modules}); this option bypasses it).
+
+@c <en>@strong{Note: this is not the same as the @samp{cvs -n}
+@c <en>program option, which you can specify to the left of a cvs command!}
+@strong{Note: this is not the same as the @samp{cvs -n}
+program option, which you can specify to the left of a cvs command!}
+
+Available with the @code{checkout}, @code{commit}, @code{export},
+and @code{rtag} commands.
+
+@item -P
+@c <en>Prune empty directories. See @ref{Removing directories}.
+Prune empty directories. See @ref{Removendo diretórios}.
+
+@item -p
+Pipe the files retrieved from the repository to standard output,
+rather than writing them in the current directory. Available
+with the @code{checkout} and @code{update} commands.
+
+@item -R
+Process directories recursively. This is on by default.
+
+Available with the following commands: @code{annotate}, @code{checkout},
+@code{commit}, @code{diff}, @code{edit}, @code{editors}, @code{export},
+@code{rdiff}, @code{remove}, @code{rtag},
+@code{status}, @code{tag}, @code{unedit}, @code{update}, @code{watch},
+and @code{watchers}.
+
+@item -r @var{tag}
+@cindex HEAD, special tag
+@cindex BASE, special tag
+Use the revision specified by the @var{tag} argument instead of the
+default @dfn{head} revision. As well as arbitrary tags defined
+with the @code{tag} or @code{rtag} command, two special tags are
+always available: @samp{HEAD} refers to the most recent version
+available in the repository, and @samp{BASE} refers to the
+revision you last checked out into the current working directory.
+
+@c FIXME: What does HEAD really mean? I believe that
+@c the current answer is the head of the default branch
+@c for all cvs commands except diff. For diff, it
+@c seems to be (a) the head of the trunk (or the default
+@c branch?) if there is no sticky tag, (b) the head of the
+@c branch for the sticky tag, if there is a sticky tag.
+@c (b) is ugly as it differs
+@c from what HEAD means for other commands, but people
+@c and/or scripts are quite possibly used to it.
+@c See "head" tests in sanity.sh.
+@c Probably the best fix is to introduce two new
+@c special tags, ".thead" for the head of the trunk,
+@c and ".bhead" for the head of the current branch.
+@c Then deprecate HEAD. This has the advantage of
+@c not surprising people with a change to HEAD, and a
+@c side benefit of also phasing out the poorly-named
+@c HEAD (see discussion of reserved tag names in node
+@c "Tags"). Of course, .thead and .bhead should be
+@c carefully implemented (with the implementation the
+@c same for "diff" as for everyone else), test cases
+@c written (similar to the ones in "head"), new tests
+@c cases written for things like default branches, &c.
+
+@c <en>The tag specification is sticky when you use this
+@c <en>@c option
+@c <en>with @code{checkout} or @code{update} to make your own
+@c <en>copy of a file: @sc{cvs} remembers the tag and continues to use it on
+@c <en>future update commands, until you specify otherwise (for more information
+@c <en>on sticky tags/dates, @pxref{Sticky tags}).
+The tag specification is sticky when you use this
+@c option
+with @code{checkout} or @code{update} to make your own
+copy of a file: @sc{cvs} remembers the tag and continues to use it on
+future update commands, until you specify otherwise (for more information
+on sticky tags/dates, @pxref{Etiquetas adesivas}).
+
+@c <en>The tag can be either a symbolic or numeric tag, as
+@c <en>described in @ref{Tags}, or the name of a branch, as
+@c <en>described in @ref{Branching and merging}.
+The tag can be either a symbolic or numeric tag, as
+described in @ref{Etiquetas}, or the name of a branch, as
+described in @ref{Ramificando e mesclando}.
+
+Specifying the @samp{-q} global option along with the
+@samp{-r} command option is often useful, to suppress
+the warning messages when the @sc{rcs} file
+does not contain the specified tag.
+
+@strong{Note: this is not the same as the overall @samp{cvs -r} option,
+which you can specify to the left of a @sc{cvs} command!}
+
+@samp{-r} is available with the @code{annotate}, @code{checkout},
+@code{commit}, @code{diff}, @code{history}, @code{export}, @code{rdiff},
+@code{rtag}, and @code{update} commands.
+
+@item -W
+Specify file names that should be filtered. You can
+use this option repeatedly. The spec can be a file
+name pattern of the same type that you can specify in
+the @file{.cvswrappers} file.
+Available with the following commands: @code{import},
+and @code{update}.
+
+@end table
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node admin
+@appendixsec admin---Administration
+@cindex Admin (subcommand)
+
+@itemize @bullet
+@item
+Requires: repository, working directory.
+@item
+Changes: repository.
+@item
+Synonym: rcs
+@end itemize
+
+This is the @sc{cvs} interface to assorted
+administrative facilities. Some of them have
+questionable usefulness for @sc{cvs} but exist for
+historical purposes. Some of the questionable options
+are likely to disappear in the future. This command
+@emph{does} work recursively, so extreme care should be
+used.
+
+@cindex cvsadmin
+@cindex UserAdminOptions, in CVSROOT/config
+On unix, if there is a group named @code{cvsadmin},
+only members of that group can run @code{cvs admin}
+commands, except for those specified using the
+@code{UserAdminOptions} configuration option in the
+@file{CVSROOT/config} file. Options specified using
+@code{UserAdminOptions} can be run by any user. See
+@ref{config} for more on @code{UserAdminOptions}.
+
+The @code{cvsadmin} group should exist on the server,
+or any system running the non-client/server @sc{cvs}.
+To disallow @code{cvs admin} for all users, create a
+group with no users in it. On NT, the @code{cvsadmin}
+feature does not exist and all users
+can run @code{cvs admin}.
+
+@menu
+* admin options:: admin options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node admin options
+@appendixsubsec admin options
+
+Some of these options have questionable usefulness for
+@sc{cvs} but exist for historical purposes. Some even
+make it impossible to use @sc{cvs} until you undo the
+effect!
+
+@table @code
+@item -A@var{oldfile}
+Might not work together with @sc{cvs}. Append the
+access list of @var{oldfile} to the access list of the
+@sc{rcs} file.
+
+@item -a@var{logins}
+Might not work together with @sc{cvs}. Append the
+login names appearing in the comma-separated list
+@var{logins} to the access list of the @sc{rcs} file.
+
+@c <en>@item -b[@var{rev}]
+@item -b[@var{rev}]
+@c <en>Set the default branch to @var{rev}. In @sc{cvs}, you
+@c <en>normally do not manipulate default branches; sticky
+@c <en>tags (@pxref{Sticky tags}) are a better way to decide
+@c <en>which branch you want to work on. There is one reason
+@c <en>to run @code{cvs admin -b}: to revert to the vendor's
+@c <en>version when using vendor branches (@pxref{Reverting
+@c <en>local changes}).
+@c <en>There can be no space between @samp{-b} and its argument.
+Set the default branch to @var{rev}. In @sc{cvs}, you
+normally do not manipulate default branches; sticky
+tags (@pxref{Etiquetas adesivas}) are a better way to decide
+which branch you want to work on. There is one reason
+to run @code{cvs admin -b}: to revert to the vendor's
+version when using vendor branches (@pxref{Reverting
+local changes}).
+There can be no space between @samp{-b} and its argument.
+@c Hmm, we don't document the usage where rev is
+@c omitted. Maybe that usage can/should be deprecated
+@c (and replaced with -bHEAD or something?) (so we can toss
+@c the optional argument). Note that -bHEAD does not
+@c work, as of 17 Sep 1997, but probably will once "cvs
+@c admin" is internal to CVS.
+
+@c <en>@cindex Comment leader
+@cindex Comment leader
+@c <en>@item -c@var{string}
+@item -c@var{string}
+@c <en>Sets the comment leader to @var{string}. The comment
+@c <en>leader is not used by current versions of @sc{cvs} or
+@c <en>@sc{rcs} 5.7. Therefore, you can almost surely not
+@c <en>worry about it. @xref{Keyword substitution}.
+Sets the comment leader to @var{string}. The comment
+leader is not used by current versions of @sc{cvs} or
+@sc{rcs} 5.7. Therefore, you can almost surely not
+worry about it. @xref{Substituição de palavra-chave}.
+
+@item -e[@var{logins}]
+Might not work together with @sc{cvs}. Erase the login
+names appearing in the comma-separated list
+@var{logins} from the access list of the RCS file. If
+@var{logins} is omitted, erase the entire access list.
+There can be no space between @samp{-e} and its argument.
+
+@item -I
+Run interactively, even if the standard input is not a
+terminal. This option does not work with the
+client/server @sc{cvs} and is likely to disappear in
+a future release of @sc{cvs}.
+
+@item -i
+@c <en>Useless with @sc{cvs}. This creates and initializes a
+@c <en>new @sc{rcs} file, without depositing a revision. With
+@c <en>@sc{cvs}, add files with the @code{cvs add} command
+@c <en>(@pxref{Adding files}).
+Useless with @sc{cvs}. This creates and initializes a
+new @sc{rcs} file, without depositing a revision. With
+@sc{cvs}, add files with the @code{cvs add} command
+(@pxref{Adicionando arquivos}).
+
+@c <en>@item -k@var{subst}
+@item -k@var{subst}
+@c <en>Set the default keyword
+@c <en>substitution to @var{subst}. @xref{Keyword
+@c <en>substitution}. Giving an explicit @samp{-k} option to
+@c <en>@code{cvs update}, @code{cvs export}, or @code{cvs
+@c <en>checkout} overrides this default.
+Set the default keyword
+substitution to @var{subst}.
+@xref{Substituição de palavra-chave}. Giving an explicit @samp{-k} option to
+@code{cvs update}, @code{cvs export}, or @code{cvs
+checkout} overrides this default.
+
+@item -l[@var{rev}]
+Lock the revision with number @var{rev}. If a branch
+is given, lock the latest revision on that branch. If
+@var{rev} is omitted, lock the latest revision on the
+default branch. There can be no space between
+@samp{-l} and its argument.
+
+This can be used in conjunction with the
+@file{rcslock.pl} script in the @file{contrib}
+directory of the @sc{cvs} source distribution to
+provide reserved checkouts (where only one user can be
+editing a given file at a time). See the comments in
+that file for details (and see the @file{README} file
+in that directory for disclaimers about the unsupported
+nature of contrib). According to comments in that
+file, locking must set to strict (which is the default).
+
+@item -L
+Set locking to strict. Strict locking means that the
+owner of an RCS file is not exempt from locking for
+checkin. For use with @sc{cvs}, strict locking must be
+set; see the discussion under the @samp{-l} option above.
+
+@cindex Changing a log message
+@cindex Replacing a log message
+@cindex Correcting a log message
+@cindex Fixing a log message
+@cindex Log message, correcting
+@item -m@var{rev}:@var{msg}
+Replace the log message of revision @var{rev} with
+@var{msg}.
+
+@c The rcs -M option, to suppress sending mail, has never been
+@c documented as a cvs admin option.
+
+@c <en>@item -N@var{name}[:[@var{rev}]]
+@item -N@var{name}[:[@var{rev}]]
+@c <en>Act like @samp{-n}, except override any previous
+@c <en>assignment of @var{name}. For use with magic branches,
+@c <en>see @ref{Magic branch numbers}.
+Act like @samp{-n}, except override any previous
+assignment of @var{name}. For use with magic branches,
+see @ref{Números de ramos mágicos}.
+
+@item -n@var{name}[:[@var{rev}]]
+Associate the symbolic name @var{name} with the branch
+or revision @var{rev}. It is normally better to use
+@samp{cvs tag} or @samp{cvs rtag} instead. Delete the
+symbolic name if both @samp{:} and @var{rev} are
+omitted; otherwise, print an error message if
+@var{name} is already associated with another number.
+If @var{rev} is symbolic, it is expanded before
+association. A @var{rev} consisting of a branch number
+followed by a @samp{.} stands for the current latest
+revision in the branch. A @samp{:} with an empty
+@var{rev} stands for the current latest revision on the
+default branch, normally the trunk. For example,
+@samp{cvs admin -n@var{name}:} associates @var{name} with the
+current latest revision of all the RCS files;
+this contrasts with @samp{cvs admin -n@var{name}:$} which
+associates @var{name} with the revision numbers
+extracted from keyword strings in the corresponding
+working files.
+
+@cindex Deleting revisions
+@cindex Outdating revisions
+@cindex Saving space
+@item -o@var{range}
+Deletes (@dfn{outdates}) the revisions given by
+@var{range}.
+
+Note that this command can be quite dangerous unless
+you know @emph{exactly} what you are doing (for example
+see the warnings below about how the
+@var{rev1}:@var{rev2} syntax is confusing).
+
+If you are short on disc this option might help you.
+But think twice before using it---there is no way short
+of restoring the latest backup to undo this command!
+If you delete different revisions than you planned,
+either due to carelessness or (heaven forbid) a @sc{cvs}
+bug, there is no opportunity to correct the error
+before the revisions are deleted. It probably would be
+a good idea to experiment on a copy of the repository
+first.
+
+Specify @var{range} in one of the following ways:
+
+@table @code
+@item @var{rev1}::@var{rev2}
+Collapse all revisions between rev1 and rev2, so that
+@sc{cvs} only stores the differences associated with going
+from rev1 to rev2, not intermediate steps. For
+example, after @samp{-o 1.3::1.5} one can retrieve
+revision 1.3, revision 1.5, or the differences to get
+from 1.3 to 1.5, but not the revision 1.4, or the
+differences between 1.3 and 1.4. Other examples:
+@samp{-o 1.3::1.4} and @samp{-o 1.3::1.3} have no
+effect, because there are no intermediate revisions to
+remove.
+
+@item ::@var{rev}
+Collapse revisions between the beginning of the branch
+containing @var{rev} and @var{rev} itself. The
+branchpoint and @var{rev} are left intact. For
+example, @samp{-o ::1.3.2.6} deletes revision 1.3.2.1,
+revision 1.3.2.5, and everything in between, but leaves
+1.3 and 1.3.2.6 intact.
+
+@item @var{rev}::
+Collapse revisions between @var{rev} and the end of the
+branch containing @var{rev}. Revision @var{rev} is
+left intact but the head revision is deleted.
+
+@item @var{rev}
+Delete the revision @var{rev}. For example, @samp{-o
+1.3} is equivalent to @samp{-o 1.2::1.4}.
+
+@c <en>@item @var{rev1}:@var{rev2}
+@item @var{rev1}:@var{rev2}
+@c <en>Delete the revisions from @var{rev1} to @var{rev2},
+@c <en>inclusive, on the same branch. One will not be able to
+@c <en>retrieve @var{rev1} or @var{rev2} or any of the
+@c <en>revisions in between. For example, the command
+@c <en>@samp{cvs admin -oR_1_01:R_1_02 .} is rarely useful.
+@c <en>It means to delete revisions up to, and including, the
+@c <en>tag R_1_02. But beware! If there are files that have not
+@c <en>changed between R_1_02 and R_1_03 the file will have
+@c <en>@emph{the same} numerical revision number assigned to
+@c <en>the tags R_1_02 and R_1_03. So not only will it be
+@c <en>impossible to retrieve R_1_02; R_1_03 will also have to
+@c <en>be restored from the tapes! In most cases you want to
+@c <en>specify @var{rev1}::@var{rev2} instead.
+Delete the revisions from @var{rev1} to @var{rev2},
+inclusive, on the same branch. One will not be able to
+retrieve @var{rev1} or @var{rev2} or any of the
+revisions in between. For example, the command
+@samp{cvs admin -oR_1_01:R_1_02 .} is rarely useful.
+It means to delete revisions up to, and including, the
+tag R_1_02. But beware! If there are files that have not
+changed between R_1_02 and R_1_03 the file will have
+@emph{the same} numerical revision number assigned to
+the tags R_1_02 and R_1_03. So not only will it be
+impossible to retrieve R_1_02; R_1_03 will also have to
+be restored from the tapes! In most cases you want to
+specify @var{rev1}::@var{rev2} instead.
+
+@c <en>@item :@var{rev}
+@item :@var{rev}
+@c <en>Delete revisions from the beginning of the
+@c <en>branch containing @var{rev} up to and including
+@c <en>@var{rev}.
+Delete revisions from the beginning of the
+branch containing @var{rev} up to and including
+@var{rev}.
+
+@c <en>@item @var{rev}:
+@item @var{rev}:
+@c <en>Delete revisions from revision @var{rev}, including
+@c <en>@var{rev} itself, to the end of the branch containing
+@c <en>@var{rev}.
+Delete revisions from revision @var{rev}, including
+@var{rev} itself, to the end of the branch containing
+@var{rev}.
+@end table
+
+@c <en>None of the revisions to be deleted may have
+@c <en>branches or locks.
+None of the revisions to be deleted may have
+branches or locks.
+
+@c <en>If any of the revisions to be deleted have symbolic
+@c <en>names, and one specifies one of the @samp{::} syntaxes,
+@c <en>then @sc{cvs} will give an error and not delete any
+@c <en>revisions. If you really want to delete both the
+@c <en>symbolic names and the revisions, first delete the
+@c <en>symbolic names with @code{cvs tag -d}, then run
+@c <en>@code{cvs admin -o}. If one specifies the
+@c <en>non-@samp{::} syntaxes, then @sc{cvs} will delete the
+@c <en>revisions but leave the symbolic names pointing to
+@c <en>nonexistent revisions. This behavior is preserved for
+@c <en>compatibility with previous versions of @sc{cvs}, but
+@c <en>because it isn't very useful, in the future it may
+@c <en>change to be like the @samp{::} case.
+If any of the revisions to be deleted have symbolic
+names, and one specifies one of the @samp{::} syntaxes,
+then @sc{cvs} will give an error and not delete any
+revisions. If you really want to delete both the
+symbolic names and the revisions, first delete the
+symbolic names with @code{cvs tag -d}, then run
+@code{cvs admin -o}. If one specifies the
+non-@samp{::} syntaxes, then @sc{cvs} will delete the
+revisions but leave the symbolic names pointing to
+nonexistent revisions. This behavior is preserved for
+compatibility with previous versions of @sc{cvs}, but
+because it isn't very useful, in the future it may
+change to be like the @samp{::} case.
+
+@c <en>Due to the way @sc{cvs} handles branches @var{rev}
+@c <en>cannot be specified symbolically if it is a branch.
+@c <en>@xref{Magic branch numbers}, for an explanation.
+Due to the way @sc{cvs} handles branches @var{rev}
+cannot be specified symbolically if it is a branch.
+@xref{Números de ramos mágicos}, for an explanation.
+@c FIXME: is this still true? I suspect not.
+
+@c <en>Make sure that no-one has checked out a copy of the
+@c <en>revision you outdate. Strange things will happen if he
+@c <en>starts to edit it and tries to check it back in. For
+@c <en>this reason, this option is not a good way to take back
+@c <en>a bogus commit; commit a new revision undoing the bogus
+@c <en>change instead (@pxref{Merging two revisions}).
+Make sure that no-one has checked out a copy of the
+revision you outdate. Strange things will happen if he
+starts to edit it and tries to check it back in. For
+this reason, this option is not a good way to take back
+a bogus commit; commit a new revision undoing the bogus
+change instead (@pxref{Mesclando duas revisões}).
+
+@item -q
+@c <en>Run quietly; do not print diagnostics.
+Run quietly; do not print diagnostics.
+
+@c <en>@item -s@var{state}[:@var{rev}]
+@item -s@var{state}[:@var{rev}]
+@c <en>Useful with @sc{cvs}. Set the state attribute of the
+@c <en>revision @var{rev} to @var{state}. If @var{rev} is a
+@c <en>branch number, assume the latest revision on that
+@c <en>branch. If @var{rev} is omitted, assume the latest
+@c <en>revision on the default branch. Any identifier is
+@c <en>acceptable for @var{state}. A useful set of states is
+@c <en>@samp{Exp} (for experimental), @samp{Stab} (for
+@c <en>stable), and @samp{Rel} (for released). By default,
+@c <en>the state of a new revision is set to @samp{Exp} when
+@c <en>it is created. The state is visible in the output from
+@c <en>@var{cvs log} (@pxref{log}), and in the
+@c <en>@samp{$@splitrcskeyword{}Log$} and @samp{$@splitrcskeyword{}State$} keywords
+@c <en>(@pxref{Keyword substitution}). Note that @sc{cvs}
+@c <en>uses the @code{dead} state for its own purposes; to
+@c <en>take a file to or from the @code{dead} state use
+@c <en>commands like @code{cvs remove} and @code{cvs add}, not
+@c <en>@code{cvs admin -s}.
+Useful with @sc{cvs}. Set the state attribute of the
+revision @var{rev} to @var{state}. If @var{rev} is a
+branch number, assume the latest revision on that
+branch. If @var{rev} is omitted, assume the latest
+revision on the default branch. Any identifier is
+acceptable for @var{state}. A useful set of states is
+@samp{Exp} (for experimental), @samp{Stab} (for
+stable), and @samp{Rel} (for released). By default,
+the state of a new revision is set to @samp{Exp} when
+it is created. The state is visible in the output from
+@var{cvs log} (@pxref{log}), and in the
+@samp{$@splitrcskeyword{}Log$} and @samp{$@splitrcskeyword{}State$} keywords
+(@pxref{Substituição de palavra-chave}). Note that @sc{cvs}
+uses the @code{dead} state for its own purposes; to
+take a file to or from the @code{dead} state use
+commands like @code{cvs remove} and @code{cvs add}, not
+@code{cvs admin -s}.
+
+@item -t[@var{file}]
+Useful with @sc{cvs}. Write descriptive text from the
+contents of the named @var{file} into the RCS file,
+deleting the existing text. The @var{file} pathname
+may not begin with @samp{-}. The descriptive text can be seen in the
+output from @samp{cvs log} (@pxref{log}).
+There can be no space between @samp{-t} and its argument.
+
+If @var{file} is omitted,
+obtain the text from standard input, terminated by
+end-of-file or by a line containing @samp{.} by itself.
+Prompt for the text if interaction is possible; see
+@samp{-I}.
+
+@item -t-@var{string}
+Similar to @samp{-t@var{file}}. Write descriptive text
+from the @var{string} into the @sc{rcs} file, deleting
+the existing text.
+There can be no space between @samp{-t} and its argument.
+
+@c The rcs -T option, do not update last-mod time for
+@c minor changes, has never been documented as a
+@c cvs admin option.
+
+@item -U
+Set locking to non-strict. Non-strict locking means
+that the owner of a file need not lock a revision for
+checkin. For use with @sc{cvs}, strict locking must be
+set; see the discussion under the @samp{-l} option
+above.
+
+@c <en>@item -u[@var{rev}]
+@item -u[@var{rev}]
+@c <en>See the option @samp{-l} above, for a discussion of
+@c <en>using this option with @sc{cvs}. Unlock the revision
+@c <en>with number @var{rev}. If a branch is given, unlock
+@c <en>the latest revision on that branch. If @var{rev} is
+@c <en>omitted, remove the latest lock held by the caller.
+@c <en>Normally, only the locker of a revision may unlock it;
+@c <en>somebody else unlocking a revision breaks the lock.
+@c <en>This causes the original locker to be sent a @code{commit}
+@c <en>notification (@pxref{Getting Notified}).
+@c <en>There can be no space between @samp{-u} and its argument.
+See the option @samp{-l} above, for a discussion of
+using this option with @sc{cvs}. Unlock the revision
+with number @var{rev}. If a branch is given, unlock
+the latest revision on that branch. If @var{rev} is
+omitted, remove the latest lock held by the caller.
+Normally, only the locker of a revision may unlock it;
+somebody else unlocking a revision breaks the lock.
+This causes the original locker to be sent a @code{commit}
+notification (@pxref{Recebendo Notificações}).
+There can be no space between @samp{-u} and its argument.
+
+@item -V@var{n}
+In previous versions of @sc{cvs}, this option meant to
+write an @sc{rcs} file which would be acceptable to
+@sc{rcs} version @var{n}, but it is now obsolete and
+specifying it will produce an error.
+@c Note that -V without an argument has never been
+@c documented as a cvs admin option.
+
+@item -x@var{suffixes}
+In previous versions of @sc{cvs}, this was documented
+as a way of specifying the names of the @sc{rcs}
+files. However, @sc{cvs} has always required that the
+@sc{rcs} files used by @sc{cvs} end in @samp{,v}, so
+this option has never done anything useful.
+
+@c The rcs -z option, to specify the timezone, has
+@c never been documented as a cvs admin option.
+@end table
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node checkout
+@appendixsec checkout---Check out sources for editing
+@cindex checkout (subcommand)
+@cindex co (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: checkout [options] modules@dots{}
+@item
+Requires: repository.
+@item
+Changes: working directory.
+@item
+Synonyms: co, get
+@end itemize
+
+Create or update a working directory containing copies of the
+source files specified by @var{modules}. You must execute
+@code{checkout} before using most of the other @sc{cvs}
+commands, since most of them operate on your working
+directory.
+
+The @var{modules} are either
+symbolic names for some
+collection of source directories and files, or paths to
+directories or files in the repository. The symbolic
+names are defined in the @samp{modules} file.
+@xref{modules}.
+@c Needs an example, particularly of the non-"modules"
+@c case but probably of both.
+
+@c FIXME: this seems like a very odd place to introduce
+@c people to how CVS works. The bit about unreserved
+@c checkouts is also misleading as it depends on how
+@c things are set up.
+Depending on the modules you specify, @code{checkout} may
+recursively create directories and populate them with
+the appropriate source files. You can then edit these
+source files at any time (regardless of whether other
+software developers are editing their own copies of the
+sources); update them to include new changes applied by
+others to the source repository; or commit your work as
+a permanent change to the source repository.
+
+Note that @code{checkout} is used to create
+directories. The top-level directory created is always
+added to the directory where @code{checkout} is
+invoked, and usually has the same name as the specified
+module. In the case of a module alias, the created
+sub-directory may have a different name, but you can be
+sure that it will be a sub-directory, and that
+@code{checkout} will show the relative path leading to
+each file as it is extracted into your private work
+area (unless you specify the @samp{-Q} global option).
+
+@c <en>The files created by @code{checkout} are created
+@c <en>read-write, unless the @samp{-r} option to @sc{cvs}
+@c <en>(@pxref{Global options}) is specified, the
+@c <en>@code{CVSREAD} environment variable is specified
+@c <en>(@pxref{Environment variables}), or a watch is in
+@c <en>effect for that file (@pxref{Watches}).
+The files created by @code{checkout} are created
+read-write, unless the @samp{-r} option to @sc{cvs}
+(@pxref{Opções globais}) is specified, the
+@code{CVSREAD} environment variable is specified
+(@pxref{Variáveis de ambiente}), or a watch is in
+effect for that file (@pxref{???Watches???}).
+
+Note that running @code{checkout} on a directory that was already
+built by a prior @code{checkout} is also permitted.
+This is similar to specifying the @samp{-d} option
+to the @code{update} command in the sense that new
+directories that have been created in the repository
+will appear in your work area.
+However, @code{checkout} takes a module name whereas
+@code{update} takes a directory name. Also
+to use @code{checkout} this way it must be run from the
+top level directory (where you originally ran
+@code{checkout} from), so before you run
+@code{checkout} to update an existing directory, don't
+forget to change your directory to the top level
+directory.
+
+For the output produced by the @code{checkout} command
+see @ref{update output}.
+
+@menu
+* checkout options:: checkout options
+* checkout examples:: checkout examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node checkout options
+@appendixsubsec checkout options
+
+@c <en>These standard options are supported by @code{checkout}
+@c <en>(@pxref{Common options}, for a complete description of
+@c <en>them):
+These standard options are supported by @code{checkout}
+(@pxref{Opções comuns}, for a complete description of
+them):
+
+@table @code
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Use the most recent revision no later than @var{date}.
+@c <en>This option is sticky, and implies @samp{-P}. See
+@c <en>@ref{Sticky tags}, for more information on sticky tags/dates.
+@c <en>Use the most recent revision no later than @var{date}.
+@c <en>This option is sticky, and implies @samp{-P}. See
+@c <en>@ref{Sticky tags}, for more information on sticky tags/dates.
+Use the most recent revision no later than @var{date}.
+This option is sticky, and implies @samp{-P}. See
+@ref{Etiquetas adesivas}, for more information on sticky tags/dates.
+Use the most recent revision no later than @var{date}.
+This option is sticky, and implies @samp{-P}. See
+@ref{Etiquetas adesivas}, for more information on sticky tags/dates.
+
+@item -f
+Only useful with the @samp{-D @var{date}} or @samp{-r
+@var{tag}} flags. If no matching revision is found,
+retrieve the most recent revision (instead of ignoring
+the file).
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Process keywords according to @var{kflag}. See
+@c <en>@ref{Keyword substitution}.
+@c <en>This option is sticky; future updates of
+@c <en>this file in this working directory will use the same
+@c <en>@var{kflag}. The @code{status} command can be viewed
+@c <en>to see the sticky options. See @ref{Invoking CVS}, for
+@c <en>more information on the @code{status} command.
+Process keywords according to @var{kflag}. See
+@ref{Substituição de palavra-chave}.
+This option is sticky; future updates of
+this file in this working directory will use the same
+@var{kflag}. The @code{status} command can be viewed
+to see the sticky options. See @ref{Chamando o CVS}, for
+more information on the @code{status} command.
+
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any checkout program (as specified
+with the @samp{-o} option in the modules file;
+@pxref{modules}).
+
+@item -P
+@c <en>Prune empty directories. See @ref{Moving directories}.
+Prune empty directories. See @ref{Movendo diretórios}.
+
+@item -p
+Pipe files to the standard output.
+
+@item -R
+Checkout directories recursively. This option is on by default.
+
+@c <en>@item -r @var{tag}
+@item -r @var{tag}
+@c <en>Use revision @var{tag}. This option is sticky, and implies @samp{-P}.
+@c <en>See @ref{Sticky tags}, for more information on sticky tags/dates.
+Use revision @var{tag}. This option is sticky, and implies @samp{-P}.
+See @ref{Etiquetas adesivas}, for more information on sticky tags/dates.
+@end table
+
+In addition to those, you can use these special command
+options with @code{checkout}:
+
+@table @code
+@c <en>@item -A
+@item -A
+@c <en>Reset any sticky tags, dates, or @samp{-k} options.
+@c <en>See @ref{Sticky tags}, for more information on sticky tags/dates.
+Reset any sticky tags, dates, or @samp{-k} options.
+See @ref{Etiquetas adesivas}, for more information on sticky tags/dates.
+
+@item -c
+Copy the module file, sorted, to the standard output,
+instead of creating or modifying any files or
+directories in your working directory.
+
+@item -d @var{dir}
+Create a directory called @var{dir} for the working
+files, instead of using the module name. In general,
+using this flag is equivalent to using @samp{mkdir
+@var{dir}; cd @var{dir}} followed by the checkout
+command without the @samp{-d} flag.
+
+There is an important exception, however. It is very
+convenient when checking out a single item to have the
+output appear in a directory that doesn't contain empty
+intermediate directories. In this case @emph{only},
+@sc{cvs} tries to ``shorten'' pathnames to avoid those empty
+directories.
+
+For example, given a module @samp{foo} that contains
+the file @samp{bar.c}, the command @samp{cvs co -d dir
+foo} will create directory @samp{dir} and place
+@samp{bar.c} inside. Similarly, given a module
+@samp{bar} which has subdirectory @samp{baz} wherein
+there is a file @samp{quux.c}, the command @samp{cvs co
+-d dir bar/baz} will create directory @samp{dir} and
+place @samp{quux.c} inside.
+
+Using the @samp{-N} flag will defeat this behavior.
+Given the same module definitions above, @samp{cvs co
+-N -d dir foo} will create directories @samp{dir/foo}
+and place @samp{bar.c} inside, while @samp{cvs co -N -d
+dir bar/baz} will create directories @samp{dir/bar/baz}
+and place @samp{quux.c} inside.
+
+@item -j @var{tag}
+With two @samp{-j} options, merge changes from the
+revision specified with the first @samp{-j} option to
+the revision specified with the second @samp{j} option,
+into the working directory.
+
+With one @samp{-j} option, merge changes from the
+ancestor revision to the revision specified with the
+@samp{-j} option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the @samp{-j} option.
+
+In addition, each -j option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}.
+
+@c <en>@xref{Branching and merging}.
+@xref{Ramificando e mesclando}.
+
+@item -N
+Only useful together with @samp{-d @var{dir}}. With
+this option, @sc{cvs} will not ``shorten'' module paths
+in your working directory when you check out a single
+module. See the @samp{-d} flag for examples and a
+discussion.
+
+@item -s
+Like @samp{-c}, but include the status of all modules,
+and sort it by the status string. @xref{modules}, for
+info about the @samp{-s} option that is used inside the
+modules file to set the module status.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node checkout examples
+@appendixsubsec checkout examples
+
+Get a copy of the module @samp{tc}:
+
+@example
+$ cvs checkout tc
+@end example
+
+Get a copy of the module @samp{tc} as it looked one day
+ago:
+
+@example
+$ cvs checkout -D yesterday tc
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node commit
+@appendixsec commit---Check files into the repository
+@cindex commit (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: commit [-lnRf] [-m 'log_message' |
+-F file] [-r revision] [files@dots{}]
+@item
+Requires: working directory, repository.
+@item
+Changes: repository.
+@item
+Synonym: ci
+@end itemize
+
+Use @code{commit} when you want to incorporate changes
+from your working source files into the source
+repository.
+
+If you don't specify particular files to commit, all of
+the files in your working current directory are
+examined. @code{commit} is careful to change in the
+repository only those files that you have really
+changed. By default (or if you explicitly specify the
+@samp{-R} option), files in subdirectories are also
+examined and committed if they have changed; you can
+use the @samp{-l} option to limit @code{commit} to the
+current directory only.
+
+@code{commit} verifies that the selected files are up
+to date with the current revisions in the source
+repository; it will notify you, and exit without
+committing, if any of the specified files must be made
+current first with @code{update} (@pxref{update}).
+@code{commit} does not call the @code{update} command
+for you, but rather leaves that for you to do when the
+time is right.
+
+When all is well, an editor is invoked to allow you to
+enter a log message that will be written to one or more
+logging programs (@pxref{modules}, and @pxref{loginfo})
+and placed in the @sc{rcs} file inside the
+repository. This log message can be retrieved with the
+@code{log} command; see @ref{log}. You can specify the
+log message on the command line with the @samp{-m
+@var{message}} option, and thus avoid the editor invocation,
+or use the @samp{-F @var{file}} option to specify
+that the argument file contains the log message.
+
+@menu
+* commit options:: commit options
+* commit examples:: commit examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node commit options
+@appendixsubsec commit options
+
+@c <en>These standard options are supported by @code{commit}
+@c <en>(@pxref{Common options}, for a complete description of
+@c <en>them):
+These standard options are supported by @code{commit}
+(@pxref{Opções comuns}, for a complete description of
+them):
+
+@table @code
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Commit directories recursively. This is on by default.
+
+@c <en>@item -r @var{revision}
+@item -r @var{revision}
+@c <en>Commit to @var{revision}. @var{revision} must be
+@c <en>either a branch, or a revision on the main trunk that
+@c <en>is higher than any existing revision number
+@c <en>(@pxref{Assigning revisions}). You
+@c <en>cannot commit to a specific revision on a branch.
+Commit to @var{revision}. @var{revision} must be
+either a branch, or a revision on the main trunk that
+is higher than any existing revision number
+(@pxref{Atribuindo revisões}). You
+cannot commit to a specific revision on a branch.
+@c FIXME: Need xref for branch case.
+@end table
+
+@code{commit} also supports these options:
+
+@table @code
+@item -F @var{file}
+Read the log message from @var{file}, instead
+of invoking an editor.
+
+@c <en>@item -f
+@item -f
+@c <en>Note that this is not the standard behavior of
+@c <en>the @samp{-f} option as defined in @ref{Common options}.
+Note that this is not the standard behavior of
+the @samp{-f} option as defined in @ref{Opções comuns}.
+
+Force @sc{cvs} to commit a new revision even if you haven't
+made any changes to the file. If the current revision
+of @var{file} is 1.7, then the following two commands
+are equivalent:
+
+@example
+$ cvs commit -f @var{file}
+$ cvs commit -r 1.8 @var{file}
+@end example
+
+@c This is odd, but it's how CVS has worked for some
+@c time.
+The @samp{-f} option disables recursion (i.e., it
+implies @samp{-l}). To force @sc{cvs} to commit a new
+revision for all files in all subdirectories, you must
+use @samp{-f -R}.
+
+@item -m @var{message}
+Use @var{message} as the log message, instead of
+invoking an editor.
+@end table
+
+@need 2000
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node commit examples
+@appendixsubsec commit examples
+
+@c FIXME: this material wants to be somewhere
+@c in "Branching and merging".
+
+@appendixsubsubsec Committing to a branch
+
+@c <en>You can commit to a branch revision (one that has an
+@c <en>even number of dots) with the @samp{-r} option. To
+@c <en>create a branch revision, use the @samp{-b} option
+@c <en>of the @code{rtag} or @code{tag} commands
+@c <en>(@pxref{Branching and merging}). Then, either @code{checkout} or
+@c <en>@code{update} can be used to base your sources on the
+@c <en>newly created branch. From that point on, all
+@c <en>@code{commit} changes made within these working sources
+@c <en>will be automatically added to a branch revision,
+@c <en>thereby not disturbing main-line development in any
+@c <en>way. For example, if you had to create a patch to the
+@c <en>1.2 version of the product, even though the 2.0 version
+@c <en>is already under development, you might do:
+You can commit to a branch revision (one that has an
+even number of dots) with the @samp{-r} option. To
+create a branch revision, use the @samp{-b} option
+of the @code{rtag} or @code{tag} commands
+(@pxref{Ramificando e mesclando}). Then, either @code{checkout} or
+@code{update} can be used to base your sources on the
+newly created branch. From that point on, all
+@code{commit} changes made within these working sources
+will be automatically added to a branch revision,
+thereby not disturbing main-line development in any
+way. For example, if you had to create a patch to the
+1.2 version of the product, even though the 2.0 version
+is already under development, you might do:
+
+@example
+$ cvs rtag -b -r FCS1_2 FCS1_2_Patch product_module
+$ cvs checkout -r FCS1_2_Patch product_module
+$ cd product_module
+[[ hack away ]]
+$ cvs commit
+@end example
+
+@noindent
+This works automatically since the @samp{-r} option is
+sticky.
+
+@appendixsubsubsec Creating the branch after editing
+
+Say you have been working on some extremely
+experimental software, based on whatever revision you
+happened to checkout last week. If others in your
+group would like to work on this software with you, but
+without disturbing main-line development, you could
+commit your change to a new branch. Others can then
+checkout your experimental stuff and utilize the full
+benefit of @sc{cvs} conflict resolution. The scenario might
+look like:
+
+@c FIXME: Should we be recommending tagging the branchpoint?
+@example
+[[ hacked sources are present ]]
+$ cvs tag -b EXPR1
+$ cvs update -r EXPR1
+$ cvs commit
+@end example
+
+The @code{update} command will make the @samp{-r
+EXPR1} option sticky on all files. Note that your
+changes to the files will never be removed by the
+@code{update} command. The @code{commit} will
+automatically commit to the correct branch, because the
+@samp{-r} is sticky. You could also do like this:
+
+@c FIXME: Should we be recommending tagging the branchpoint?
+@example
+[[ hacked sources are present ]]
+$ cvs tag -b EXPR1
+$ cvs commit -r EXPR1
+@end example
+
+@noindent
+but then, only those files that were changed by you
+will have the @samp{-r EXPR1} sticky flag. If you hack
+away, and commit without specifying the @samp{-r EXPR1}
+flag, some files may accidentally end up on the main
+trunk.
+
+To work with you on the experimental change, others
+would simply do
+
+@example
+$ cvs checkout -r EXPR1 whatever_module
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node diff
+@appendixsec diff---Show differences between revisions
+@cindex diff (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: diff [-lR] [-k kflag] [format_options] [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files@dots{}]
+@item
+Requires: working directory, repository.
+@item
+Changes: nothing.
+@end itemize
+
+The @code{diff} command is used to compare different
+revisions of files. The default action is to compare
+your working files with the revisions they were based
+on, and report any differences that are found.
+
+If any file names are given, only those files are
+compared. If any directories are given, all files
+under them will be compared.
+
+@c <en>The exit status for diff is different than for other
+@c <en>@sc{cvs} commands; for details @ref{Exit status}.
+The exit status for diff is different than for other
+@sc{cvs} commands; for details @ref{Estados de saída}.
+
+@menu
+* diff options:: diff options
+* diff examples:: diff examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node diff options
+@appendixsubsec diff options
+
+@c <en>These standard options are supported by @code{diff}
+@c <en>(@pxref{Common options}, for a complete description of
+@c <en>them):
+These standard options are supported by @code{diff}
+(@pxref{Opções comuns}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+See @samp{-r} for how this affects the comparison.
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Process keywords according to @var{kflag}. See
+@c <en>@ref{Keyword substitution}.
+Process keywords according to @var{kflag}. See
+@ref{Substituição de palavra-chave}.
+
+@item -l
+Local; run only in current working directory.
+
+@item -R
+Examine directories recursively. This option is on by
+default.
+
+@item -r @var{tag}
+Compare with revision @var{tag}. Zero, one or two
+@samp{-r} options can be present. With no @samp{-r}
+option, the working file will be compared with the
+revision it was based on. With one @samp{-r}, that
+revision will be compared to your current working file.
+With two @samp{-r} options those two revisions will be
+compared (and your working file will not affect the
+outcome in any way).
+@c We should be a lot more explicit, with examples,
+@c about the difference between "cvs diff" and "cvs
+@c diff -r HEAD". This often confuses new users.
+
+One or both @samp{-r} options can be replaced by a
+@samp{-D @var{date}} option, described above.
+@end table
+
+@c Conceptually, this is a disaster. There are 3
+@c zillion diff formats that we support via the diff
+@c library. It is not obvious to me that we should
+@c document them all. Maybe just the most common ones
+@c like -c and -u, and think about phasing out the
+@c obscure ones.
+@c FIXCVS: also should be a way to specify an external
+@c diff program (which can be different for different
+@c file types) and pass through
+@c arbitrary options, so that the user can do
+@c "--pass=-Z --pass=foo" or something even if CVS
+@c doesn't know about the "-Z foo" option to diff.
+@c This would fit nicely with deprecating/eliminating
+@c the obscure options of the diff library, because it
+@c would let people specify an external GNU diff if
+@c they are into that sort of thing.
+The following options specify the format of the
+output. They have the same meaning as in GNU diff.
+Most options have two equivalent names, one of which is a single letter
+preceded by @samp{-}, and the other of which is a long name preceded by
+@samp{--}.
+
+@table @samp
+@item -@var{lines}
+Show @var{lines} (an integer) lines of context. This option does not
+specify an output format by itself; it has no effect unless it is
+combined with @samp{-c} or @samp{-u}. This option is obsolete. For proper
+operation, @code{patch} typically needs at least two lines of context.
+
+@item -a
+Treat all files as text and compare them line-by-line, even if they
+do not seem to be text.
+
+@item -b
+Ignore trailing white space and consider all other sequences of one or
+more white space characters to be equivalent.
+
+@item -B
+Ignore changes that just insert or delete blank lines.
+
+@item --binary
+Read and write data in binary mode.
+
+@item --brief
+Report only whether the files differ, not the details of the
+differences.
+
+@item -c
+Use the context output format.
+
+@item -C @var{lines}
+@itemx --context@r{[}=@var{lines}@r{]}
+Use the context output format, showing @var{lines} (an integer) lines of
+context, or three if @var{lines} is not given.
+For proper operation, @code{patch} typically needs at least two lines of
+context.
+
+@item --changed-group-format=@var{format}
+Use @var{format} to output a line group containing differing lines from
+both files in if-then-else format. @xref{Line group formats}.
+
+@item -d
+Change the algorithm to perhaps find a smaller set of changes. This makes
+@code{diff} slower (sometimes much slower).
+
+@item -e
+@itemx --ed
+Make output that is a valid @code{ed} script.
+
+@item --expand-tabs
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+
+@item -f
+Make output that looks vaguely like an @code{ed} script but has changes
+in the order they appear in the file.
+
+@item -F @var{regexp}
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches @var{regexp}.
+
+@item --forward-ed
+Make output that looks vaguely like an @code{ed} script but has changes
+in the order they appear in the file.
+
+@item -H
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+
+@item --horizon-lines=@var{lines}
+Do not discard the last @var{lines} lines of the common prefix
+and the first @var{lines} lines of the common suffix.
+
+@item -i
+Ignore changes in case; consider upper- and lower-case letters
+equivalent.
+
+@item -I @var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+
+@item --ifdef=@var{name}
+Make merged if-then-else output using @var{name}.
+
+@item --ignore-all-space
+Ignore white space when comparing lines.
+
+@item --ignore-blank-lines
+Ignore changes that just insert or delete blank lines.
+
+@item --ignore-case
+Ignore changes in case; consider upper- and lower-case to be the same.
+
+@item --ignore-matching-lines=@var{regexp}
+Ignore changes that just insert or delete lines that match @var{regexp}.
+
+@item --ignore-space-change
+Ignore trailing white space and consider all other sequences of one or
+more white space characters to be equivalent.
+
+@item --initial-tab
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+
+@item -L @var{label}
+Use @var{label} instead of the file name in the context format
+and unified format headers.
+
+@item --label=@var{label}
+Use @var{label} instead of the file name in the context format
+and unified format headers.
+
+@item --left-column
+Print only the left column of two common lines in side by side format.
+
+@item --line-format=@var{format}
+Use @var{format} to output all input lines in if-then-else format.
+@xref{Line formats}.
+
+@item --minimal
+Change the algorithm to perhaps find a smaller set of changes. This
+makes @code{diff} slower (sometimes much slower).
+
+@item -n
+Output RCS-format diffs; like @samp{-f} except that each command
+specifies the number of lines affected.
+
+@item -N
+@itemx --new-file
+In directory comparison, if a file is found in only one directory,
+treat it as present but empty in the other directory.
+
+@item --new-group-format=@var{format}
+Use @var{format} to output a group of lines taken from just the second
+file in if-then-else format. @xref{Line group formats}.
+
+@item --new-line-format=@var{format}
+Use @var{format} to output a line taken from just the second file in
+if-then-else format. @xref{Line formats}.
+
+@item --old-group-format=@var{format}
+Use @var{format} to output a group of lines taken from just the first
+file in if-then-else format. @xref{Line group formats}.
+
+@item --old-line-format=@var{format}
+Use @var{format} to output a line taken from just the first file in
+if-then-else format. @xref{Line formats}.
+
+@item -p
+Show which C function each change is in.
+
+@item --rcs
+Output RCS-format diffs; like @samp{-f} except that each command
+specifies the number of lines affected.
+
+@item --report-identical-files
+@itemx -s
+Report when two files are the same.
+
+@item --show-c-function
+Show which C function each change is in.
+
+@item --show-function-line=@var{regexp}
+In context and unified format, for each hunk of differences, show some
+of the last preceding line that matches @var{regexp}.
+
+@item --side-by-side
+Use the side by side output format.
+
+@item --speed-large-files
+Use heuristics to speed handling of large files that have numerous
+scattered small changes.
+
+@item --suppress-common-lines
+Do not print common lines in side by side format.
+
+@item -t
+Expand tabs to spaces in the output, to preserve the alignment of tabs
+in the input files.
+
+@item -T
+Output a tab rather than a space before the text of a line in normal or
+context format. This causes the alignment of tabs in the line to look
+normal.
+
+@item --text
+Treat all files as text and compare them line-by-line, even if they
+do not appear to be text.
+
+@item -u
+Use the unified output format.
+
+@item --unchanged-group-format=@var{format}
+Use @var{format} to output a group of common lines taken from both files
+in if-then-else format. @xref{Line group formats}.
+
+@item --unchanged-line-format=@var{format}
+Use @var{format} to output a line common to both files in if-then-else
+format. @xref{Line formats}.
+
+@item -U @var{lines}
+@itemx --unified@r{[}=@var{lines}@r{]}
+Use the unified output format, showing @var{lines} (an integer) lines of
+context, or three if @var{lines} is not given.
+For proper operation, @code{patch} typically needs at least two lines of
+context.
+
+@item -w
+Ignore white space when comparing lines.
+
+@item -W @var{columns}
+@itemx --width=@var{columns}
+Use an output width of @var{columns} in side by side format.
+
+@item -y
+Use the side by side output format.
+@end table
+
+@menu
+* Line group formats:: Line group formats
+* Line formats:: Line formats
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node Line group formats
+@appendixsubsubsec Line group formats
+
+Line group formats let you specify formats suitable for many
+applications that allow if-then-else input, including programming
+languages and text formatting languages. A line group format specifies
+the output format for a contiguous group of similar lines.
+
+For example, the following command compares the TeX file @file{myfile}
+with the original version from the repository,
+and outputs a merged file in which old regions are
+surrounded by @samp{\begin@{em@}}-@samp{\end@{em@}} lines, and new
+regions are surrounded by @samp{\begin@{bf@}}-@samp{\end@{bf@}} lines.
+
+@example
+cvs diff \
+ --old-group-format='\begin@{em@}
+%<\end@{em@}
+' \
+ --new-group-format='\begin@{bf@}
+%>\end@{bf@}
+' \
+ myfile
+@end example
+
+The following command is equivalent to the above example, but it is a
+little more verbose, because it spells out the default line group formats.
+
+@example
+cvs diff \
+ --old-group-format='\begin@{em@}
+%<\end@{em@}
+' \
+ --new-group-format='\begin@{bf@}
+%>\end@{bf@}
+' \
+ --unchanged-group-format='%=' \
+ --changed-group-format='\begin@{em@}
+%<\end@{em@}
+\begin@{bf@}
+%>\end@{bf@}
+' \
+ myfile
+@end example
+
+Here is a more advanced example, which outputs a diff listing with
+headers containing line numbers in a ``plain English'' style.
+
+@example
+cvs diff \
+ --unchanged-group-format='' \
+ --old-group-format='-------- %dn line%(n=1?:s) deleted at %df:
+%<' \
+ --new-group-format='-------- %dN line%(N=1?:s) added after %de:
+%>' \
+ --changed-group-format='-------- %dn line%(n=1?:s) changed at %df:
+%<-------- to:
+%>' \
+ myfile
+@end example
+
+To specify a line group format, use one of the options
+listed below. You can specify up to four line group formats, one for
+each kind of line group. You should quote @var{format}, because it
+typically contains shell metacharacters.
+
+@table @samp
+@item --old-group-format=@var{format}
+These line groups are hunks containing only lines from the first file.
+The default old group format is the same as the changed group format if
+it is specified; otherwise it is a format that outputs the line group as-is.
+
+@item --new-group-format=@var{format}
+These line groups are hunks containing only lines from the second
+file. The default new group format is same as the changed group
+format if it is specified; otherwise it is a format that outputs the
+line group as-is.
+
+@item --changed-group-format=@var{format}
+These line groups are hunks containing lines from both files. The
+default changed group format is the concatenation of the old and new
+group formats.
+
+@item --unchanged-group-format=@var{format}
+These line groups contain lines common to both files. The default
+unchanged group format is a format that outputs the line group as-is.
+@end table
+
+In a line group format, ordinary characters represent themselves;
+conversion specifications start with @samp{%} and have one of the
+following forms.
+
+@table @samp
+@item %<
+stands for the lines from the first file, including the trailing newline.
+Each line is formatted according to the old line format (@pxref{Line formats}).
+
+@item %>
+stands for the lines from the second file, including the trailing newline.
+Each line is formatted according to the new line format.
+
+@item %=
+stands for the lines common to both files, including the trailing newline.
+Each line is formatted according to the unchanged line format.
+
+@item %%
+stands for @samp{%}.
+
+@item %c'@var{C}'
+where @var{C} is a single character, stands for @var{C}.
+@var{C} may not be a backslash or an apostrophe.
+For example, @samp{%c':'} stands for a colon, even inside
+the then-part of an if-then-else format, which a colon would
+normally terminate.
+
+@item %c'\@var{O}'
+where @var{O} is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code @var{O}.
+For example, @samp{%c'\0'} stands for a null character.
+
+@item @var{F}@var{n}
+where @var{F} is a @code{printf} conversion specification and @var{n} is one
+of the following letters, stands for @var{n}'s value formatted with @var{F}.
+
+@table @samp
+@item e
+The line number of the line just before the group in the old file.
+
+@item f
+The line number of the first line in the group in the old file;
+equals @var{e} + 1.
+
+@item l
+The line number of the last line in the group in the old file.
+
+@item m
+The line number of the line just after the group in the old file;
+equals @var{l} + 1.
+
+@item n
+The number of lines in the group in the old file; equals @var{l} - @var{f} + 1.
+
+@item E, F, L, M, N
+Likewise, for lines in the new file.
+
+@end table
+
+The @code{printf} conversion specification can be @samp{%d},
+@samp{%o}, @samp{%x}, or @samp{%X}, specifying decimal, octal,
+lower case hexadecimal, or upper case hexadecimal output
+respectively. After the @samp{%} the following options can appear in
+sequence: a @samp{-} specifying left-justification; an integer
+specifying the minimum field width; and a period followed by an
+optional integer specifying the minimum number of digits.
+For example, @samp{%5dN} prints the number of new lines in the group
+in a field of width 5 characters, using the @code{printf} format @code{"%5d"}.
+
+@item (@var{A}=@var{B}?@var{T}:@var{E})
+If @var{A} equals @var{B} then @var{T} else @var{E}.
+@var{A} and @var{B} are each either a decimal constant
+or a single letter interpreted as above.
+This format spec is equivalent to @var{T} if
+@var{A}'s value equals @var{B}'s; otherwise it is equivalent to @var{E}.
+
+For example, @samp{%(N=0?no:%dN) line%(N=1?:s)} is equivalent to
+@samp{no lines} if @var{N} (the number of lines in the group in the
+new file) is 0, to @samp{1 line} if @var{N} is 1, and to @samp{%dN lines}
+otherwise.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node Line formats
+@appendixsubsubsec Line formats
+
+Line formats control how each line taken from an input file is
+output as part of a line group in if-then-else format.
+
+For example, the following command outputs text with a one-column
+change indicator to the left of the text. The first column of output
+is @samp{-} for deleted lines, @samp{|} for added lines, and a space
+for unchanged lines. The formats contain newline characters where
+newlines are desired on output.
+
+@example
+cvs diff \
+ --old-line-format='-%l
+' \
+ --new-line-format='|%l
+' \
+ --unchanged-line-format=' %l
+' \
+ myfile
+@end example
+
+To specify a line format, use one of the following options. You should
+quote @var{format}, since it often contains shell metacharacters.
+
+@table @samp
+@item --old-line-format=@var{format}
+formats lines just from the first file.
+
+@item --new-line-format=@var{format}
+formats lines just from the second file.
+
+@item --unchanged-line-format=@var{format}
+formats lines common to both files.
+
+@item --line-format=@var{format}
+formats all lines; in effect, it sets all three above options simultaneously.
+@end table
+
+In a line format, ordinary characters represent themselves;
+conversion specifications start with @samp{%} and have one of the
+following forms.
+
+@table @samp
+@item %l
+stands for the contents of the line, not counting its trailing
+newline (if any). This format ignores whether the line is incomplete.
+
+@item %L
+stands for the contents of the line, including its trailing newline
+(if any). If a line is incomplete, this format preserves its
+incompleteness.
+
+@item %%
+stands for @samp{%}.
+
+@item %c'@var{C}'
+where @var{C} is a single character, stands for @var{C}.
+@var{C} may not be a backslash or an apostrophe.
+For example, @samp{%c':'} stands for a colon.
+
+@item %c'\@var{O}'
+where @var{O} is a string of 1, 2, or 3 octal digits,
+stands for the character with octal code @var{O}.
+For example, @samp{%c'\0'} stands for a null character.
+
+@item @var{F}n
+where @var{F} is a @code{printf} conversion specification,
+stands for the line number formatted with @var{F}.
+For example, @samp{%.5dn} prints the line number using the
+@code{printf} format @code{"%.5d"}. @xref{Line group formats}, for
+more about printf conversion specifications.
+
+@end table
+
+The default line format is @samp{%l} followed by a newline character.
+
+If the input contains tab characters and it is important that they line
+up on output, you should ensure that @samp{%l} or @samp{%L} in a line
+format is just after a tab stop (e.g.@: by preceding @samp{%l} or
+@samp{%L} with a tab character), or you should use the @samp{-t} or
+@samp{--expand-tabs} option.
+
+Taken together, the line and line group formats let you specify many
+different formats. For example, the following command uses a format
+similar to @code{diff}'s normal format. You can tailor this command
+to get fine control over @code{diff}'s output.
+
+@example
+cvs diff \
+ --old-line-format='< %l
+' \
+ --new-line-format='> %l
+' \
+ --old-group-format='%df%(f=l?:,%dl)d%dE
+%<' \
+ --new-group-format='%dea%dF%(F=L?:,%dL)
+%>' \
+ --changed-group-format='%df%(f=l?:,%dl)c%dF%(F=L?:,%dL)
+%<---
+%>' \
+ --unchanged-group-format='' \
+ myfile
+@end example
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node diff examples
+@appendixsubsec diff examples
+
+The following line produces a Unidiff (@samp{-u} flag)
+between revision 1.14 and 1.19 of
+@file{backend.c}. Due to the @samp{-kk} flag no
+keywords are substituted, so differences that only depend
+on keyword substitution are ignored.
+
+@example
+$ cvs diff -kk -u -r 1.14 -r 1.19 backend.c
+@end example
+
+Suppose the experimental branch EXPR1 was based on a
+set of files tagged RELEASE_1_0. To see what has
+happened on that branch, the following can be used:
+
+@example
+$ cvs diff -r RELEASE_1_0 -r EXPR1
+@end example
+
+A command like this can be used to produce a context
+diff between two releases:
+
+@example
+$ cvs diff -c -r RELEASE_1_0 -r RELEASE_1_1 > diffs
+@end example
+
+If you are maintaining ChangeLogs, a command like the following
+just before you commit your changes may help you write
+the ChangeLog entry. All local modifications that have
+not yet been committed will be printed.
+
+@example
+$ cvs diff -u | less
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node export
+@appendixsec export---Export sources from CVS, similar to checkout
+@cindex export (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: export [-flNnR] [-r rev|-D date] [-k subst] [-d dir] module@dots{}
+@item
+Requires: repository.
+@item
+Changes: current directory.
+@end itemize
+
+This command is a variant of @code{checkout}; use it
+when you want a copy of the source for module without
+the @sc{cvs} administrative directories. For example, you
+might use @code{export} to prepare source for shipment
+off-site. This command requires that you specify a
+date or tag (with @samp{-D} or @samp{-r}), so that you
+can count on reproducing the source you ship to others
+(and thus it always prunes empty directories).
+
+One often would like to use @samp{-kv} with @code{cvs
+export}. This causes any keywords to be
+expanded such that an import done at some other site
+will not lose the keyword revision information. But be
+aware that doesn't handle an export containing binary
+files correctly. Also be aware that after having used
+@samp{-kv}, one can no longer use the @code{ident}
+command (which is part of the @sc{rcs} suite---see
+ident(1)) which looks for keyword strings. If
+you want to be able to use @code{ident} you must not
+use @samp{-kv}.
+
+@menu
+* export options:: export options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node export options
+@appendixsubsec export options
+
+@c <en>These standard options are supported by @code{export}
+@c <en>(@pxref{Common options}, for a complete description of
+@c <en>them):
+These standard options are supported by @code{export}
+(@pxref{Opções comuns}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+
+@item -f
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+
+@item -l
+Local; run only in current working directory.
+
+@item -n
+Do not run any checkout program.
+
+@item -R
+Export directories recursively. This is on by default.
+
+@item -r @var{tag}
+Use revision @var{tag}.
+@end table
+
+In addition, these options (that are common to
+@code{checkout} and @code{export}) are also supported:
+
+@table @code
+@item -d @var{dir}
+Create a directory called @var{dir} for the working
+files, instead of using the module name.
+@xref{checkout options}, for complete details on how
+@sc{cvs} handles this flag.
+
+@c <en>@item -k @var{subst}
+@item -k @var{subst}
+@c <en>Set keyword expansion mode (@pxref{Substitution modes}).
+Set keyword expansion mode (@pxref{Modos de substituição}).
+
+@item -N
+Only useful together with @samp{-d @var{dir}}.
+@xref{checkout options}, for complete details on how
+@sc{cvs} handles this flag.
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node export examples
+@appendixsubsec export examples
+
+Contributed examples are gratefully accepted.
+@c -- Examples here!!
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node history
+@appendixsec history---Show status of files and users
+@cindex history (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: history [-report] [-flags] [-options args] [files@dots{}]
+@item
+Requires: the file @file{$CVSROOT/CVSROOT/history}
+@item
+Changes: nothing.
+@end itemize
+
+@sc{cvs} can keep a history file that tracks each use of the
+@code{checkout}, @code{commit}, @code{rtag},
+@code{update}, and @code{release} commands. You can
+use @code{history} to display this information in
+various formats.
+
+Logging must be enabled by creating the file
+@file{$CVSROOT/CVSROOT/history}.
+
+@c <en>@strong{Note: @code{history} uses @samp{-f}, @samp{-l},
+@c <en>@samp{-n}, and @samp{-p} in ways that conflict with the
+@c <en>normal use inside @sc{cvs} (@pxref{Common options}).}
+@strong{Note: @code{history} uses @samp{-f}, @samp{-l},
+@samp{-n}, and @samp{-p} in ways that conflict with the
+normal use inside @sc{cvs} (@pxref{Opções comuns}).}
+
+@menu
+* history options:: history options
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node history options
+@appendixsubsec history options
+
+Several options (shown above as @samp{-report}) control what
+kind of report is generated:
+
+@table @code
+@item -c
+Report on each time commit was used (i.e., each time
+the repository was modified).
+
+@item -e
+Everything (all record types). Equivalent to
+specifying @samp{-x} with all record types. Of course,
+@samp{-e} will also include record types which are
+added in a future version of @sc{cvs}; if you are
+writing a script which can only handle certain record
+types, you'll want to specify @samp{-x}.
+
+@item -m @var{module}
+Report on a particular module. (You can meaningfully
+use @samp{-m} more than once on the command line.)
+
+@item -o
+Report on checked-out modules. This is the default report type.
+
+@item -T
+Report on all tags.
+
+@item -x @var{type}
+Extract a particular set of record types @var{type} from the @sc{cvs}
+history. The types are indicated by single letters,
+which you may specify in combination.
+
+Certain commands have a single record type:
+
+@table @code
+@item F
+release
+@item O
+checkout
+@item E
+export
+@item T
+rtag
+@end table
+
+@noindent
+One of five record types may result from an update:
+
+@table @code
+@item C
+A merge was necessary but collisions were
+detected (requiring manual merging).
+@item G
+A merge was necessary and it succeeded.
+@item U
+A working file was copied from the repository.
+@item P
+A working file was patched to match the repository.
+@item W
+The working copy of a file was deleted during
+update (because it was gone from the repository).
+@end table
+
+@noindent
+One of three record types results from commit:
+
+@table @code
+@item A
+A file was added for the first time.
+@item M
+A file was modified.
+@item R
+A file was removed.
+@end table
+@end table
+
+The options shown as @samp{-flags} constrain or expand
+the report without requiring option arguments:
+
+@table @code
+@item -a
+Show data for all users (the default is to show data
+only for the user executing @code{history}).
+
+@item -l
+Show last modification only.
+
+@item -w
+Show only the records for modifications done from the
+same working directory where @code{history} is
+executing.
+@end table
+
+The options shown as @samp{-options @var{args}} constrain the report
+based on an argument:
+
+@table @code
+@item -b @var{str}
+Show data back to a record containing the string
+@var{str} in either the module name, the file name, or
+the repository path.
+
+@item -D @var{date}
+Show data since @var{date}. This is slightly different
+from the normal use of @samp{-D @var{date}}, which
+selects the newest revision older than @var{date}.
+
+@item -f @var{file}
+Show data for a particular file
+(you can specify several @samp{-f} options on the same command line).
+This is equivalent to specifying the file on the command line.
+
+@item -n @var{module}
+Show data for a particular module
+(you can specify several @samp{-n} options on the same command line).
+
+@item -p @var{repository}
+Show data for a particular source repository (you
+can specify several @samp{-p} options on the same command
+line).
+
+@item -r @var{rev}
+Show records referring to revisions since the revision
+or tag named @var{rev} appears in individual @sc{rcs}
+files. Each @sc{rcs} file is searched for the revision or
+tag.
+
+@item -t @var{tag}
+Show records since tag @var{tag} was last added to the
+history file. This differs from the @samp{-r} flag
+above in that it reads only the history file, not the
+@sc{rcs} files, and is much faster.
+
+@item -u @var{name}
+Show records for user @var{name}.
+
+@item -z @var{timezone}
+Show times in the selected records using the specified
+time zone instead of UTC.
+@end table
+
+@ignore
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c @node history examples
+@appendixsubsec history examples
+
+Contributed examples will gratefully be accepted.
+@c -- Examples here!
+@end ignore
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node import
+@appendixsec import---Import sources into CVS, using vendor branches
+@cindex import (subcommand)
+
+@c FIXME: This node is way too long for one which has subnodes.
+
+@itemize @bullet
+@item
+Synopsis: import [-options] repository vendortag releasetag@dots{}
+@item
+Requires: Repository, source distribution directory.
+@item
+Changes: repository.
+@end itemize
+
+Use @code{import} to incorporate an entire source
+distribution from an outside source (e.g., a source
+vendor) into your source repository directory. You can
+use this command both for initial creation of a
+repository, and for wholesale updates to the module
+from the outside source. @xref{Acompanhando fontes}, for
+a discussion on this subject.
+
+The @var{repository} argument gives a directory name
+(or a path to a directory) under the @sc{cvs} root directory
+for repositories; if the directory did not exist,
+import creates it.
+
+When you use import for updates to source that has been
+modified in your source repository (since a prior
+import), it will notify you of any files that conflict
+in the two branches of development; use @samp{checkout
+-j} to reconcile the differences, as import instructs
+you to do.
+
+If @sc{cvs} decides a file should be ignored
+(@pxref{cvsignore}), it does not import it and prints
+@samp{I } followed by the filename (@pxref{import output}, for a
+complete description of the output).
+
+If the file @file{$CVSROOT/CVSROOT/cvswrappers} exists,
+any file whose names match the specifications in that
+file will be treated as packages and the appropriate
+filtering will be performed on the file/directory
+before being imported. @xref{Wrappers}.
+
+The outside source is saved in a first-level
+branch, by default 1.1.1. Updates are leaves of this
+branch; for example, files from the first imported
+collection of source will be revision 1.1.1.1, then
+files from the first imported update will be revision
+1.1.1.2, and so on.
+
+At least three arguments are required.
+@var{repository} is needed to identify the collection
+of source. @var{vendortag} is a tag for the entire
+branch (e.g., for 1.1.1). You must also specify at
+least one @var{releasetag} to identify the files at
+the leaves created each time you execute @code{import}.
+
+@c I'm not completely sure this belongs here. But
+@c we need to say it _somewhere_ reasonably obvious; it
+@c is a common misconception among people first learning CVS
+@c <en>Note that @code{import} does @emph{not} change the
+@c <en>directory in which you invoke it. In particular, it
+@c <en>does not set up that directory as a @sc{cvs} working
+@c <en>directory; if you want to work with the sources import
+@c <en>them first and then check them out into a different
+@c <en>directory (@pxref{Getting the source}).
+Note that @code{import} does @emph{not} change the
+directory in which you invoke it. In particular, it
+does not set up that directory as a @sc{cvs} working
+directory; if you want to work with the sources import
+them first and then check them out into a different
+directory (@pxref{Obtendo os fontes}).
+
+@menu
+* import options:: import options
+* import output:: import output
+* import examples:: import examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import options
+@appendixsubsec import options
+
+@c <en>This standard option is supported by @code{import}
+@c <en>(@pxref{Common options}, for a complete description):
+This standard option is supported by @code{import}
+(@pxref{Opções comuns}, for a complete description):
+
+@table @code
+@item -m @var{message}
+Use @var{message} as log information, instead of
+invoking an editor.
+@end table
+
+There are the following additional special options.
+
+@table @code
+@c <en>@item -b @var{branch}
+@item -b @var{branch}
+@c <en>See @ref{Multiple vendor branches}.
+See @ref{Ramos de fornecedor múltiplos}.
+
+@c <en>@item -k @var{subst}
+@item -k @var{subst}
+@c <en>Indicate the keyword expansion mode desired. This
+@c <en>setting will apply to all files created during the
+@c <en>import, but not to any files that previously existed in
+@c <en>the repository. See @ref{Substitution modes}, for a
+@c <en>list of valid @samp{-k} settings.
+Indicate the keyword expansion mode desired. This
+setting will apply to all files created during the
+import, but not to any files that previously existed in
+the repository. See @ref{Modos de substituição}, for a
+list of valid @samp{-k} settings.
+
+@item -I @var{name}
+Specify file names that should be ignored during
+import. You can use this option repeatedly. To avoid
+ignoring any files at all (even those ignored by
+default), specify `-I !'.
+
+@var{name} can be a file name pattern of the same type
+that you can specify in the @file{.cvsignore} file.
+@xref{cvsignore}.
+@c -- Is this really true?
+
+@item -W @var{spec}
+Specify file names that should be filtered during
+import. You can use this option repeatedly.
+
+@var{spec} can be a file name pattern of the same type
+that you can specify in the @file{.cvswrappers}
+file. @xref{Wrappers}.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import output
+@appendixsubsec import output
+
+@c <en>@code{import} keeps you informed of its progress by printing a line
+@c <en>for each file, preceded by one character indicating the status of the file:
+O @code{import} mantém você informado de seu progresso
+escrevendo uma linha para cada arquivo, iniciando com
+um caractere que indica o status do arquivo:
+
+@table @code
+@c <en>@item U @var{file}
+@item U @var{arquivo}
+@c <en>The file already exists in the repository and has not been locally
+@c <en>modified; a new revision has been created (if necessary).
+O arquivo já existe no repositório não foi modificado
+localmente; uma nova revisão foi criada (se necessário).
+
+@c <en>@item N @var{file}
+@item N @var{arquivo}
+@c <en>The file is a new file which has been added to the repository.
+O arquivo é um arquivo novo que foi adicionado ao repositório.
+
+@c <en>@item C @var{file}
+@item C @var{arquivo}
+@c <en>The file already exists in the repository but has been locally modified;
+@c <en>you will have to merge the changes.
+O arquivo já existe no repositório mas foi modificado
+localmente; Você vai ter que mesclar as mudanças.
+
+@c <en>@item I @var{file}
+@item I @var{arquivo}
+@c <en>The file is being ignored (@pxref{cvsignore}).
+O arquivo foi ignorado (@pxref{cvsignore}).
+
+@c <en>@cindex Symbolic link, importing
+@cindex Ligações simbólicas, importando
+@c <en>@cindex Link, symbolic, importing
+@cindex Simbólica, ligação, importando
+@c FIXME: also (somewhere else) probably
+@c should be documenting what happens if you "cvs add"
+@c a symbolic link. Also maybe what happens if
+@c you manually create symbolic links within the
+@c repository (? - not sure why we'd want to suggest
+@c doing that).
+@c <en>@item L @var{file}
+@item L @var{arquivo}
+@c <en>The file is a symbolic link; @code{cvs import} ignores symbolic links.
+@c <en>People periodically suggest that this behavior should
+@c <en>be changed, but if there is a consensus on what it
+@c <en>should be changed to, it is not apparent.
+@c <en>(Various options in the @file{modules} file can be used
+@c <en>to recreate symbolic links on checkout, update, etc.;
+@c <en>@pxref{modules}.)
+O arquivo é uma ligação simbólica; O @code{cvs import}
+ignora ligações simbólicas. De vez em quando alguem
+sugere que este comportamento seja mudado, mas se há um
+consenso quanto a que mudança fazer, não é
+claro. (Várias opções no arquivo @file{modules} podem
+ser usadas para recriar ligações simbólicas no checkout, update, etc.;
+@pxref{modules}.)
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node import examples
+@appendixsubsec import examples
+
+@c <en>See @ref{Tracking sources}, and @ref{From files}.
+See @ref{Acompanhando fontes}, and @ref{De arquivos}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node log
+@appendixsec log---Print out log information for files
+@cindex log (subcommand)
+
+@itemize @bullet
+@item
+Synopsis: log [options] [files@dots{}]
+@item
+Requires: repository, working directory.
+@item
+Changes: nothing.
+@end itemize
+
+Display log information for files. @code{log} used to
+call the @sc{rcs} utility @code{rlog}. Although this
+is no longer true in the current sources, this history
+determines the format of the output and the options,
+which are not quite in the style of the other @sc{cvs}
+commands.
+
+@cindex Timezone, in output
+@cindex Zone, time, in output
+@c Kind of a funny place to document the timezone used
+@c in output from commands other than @code{log}.
+@c There is also more we need to say about this,
+@c including what happens in a client/server environment.
+The output includes the location of the @sc{rcs} file,
+the @dfn{head} revision (the latest revision on the
+trunk), all symbolic names (tags) and some other
+things. For each revision, the revision number, the
+author, the number of lines added/deleted and the log
+message are printed. All times are displayed in
+Coordinated Universal Time (UTC). (Other parts of
+@sc{cvs} print times in the local timezone).
+@c FIXCVS: need a better way to control the timezone
+@c used in output. Previous/current versions of CVS did/do
+@c sometimes support -z in RCSINIT, and/or an
+@c undocumented (except by reference to 'rlog') -z option
+@c to cvs log, but this has not been a consistent,
+@c documented feature. Perhaps a new global option,
+@c where LT means the client's timezone, which the
+@c client then communicates to the server, is the
+@c right solution.
+
+@c <en>@strong{Note: @code{log} uses @samp{-R} in a way that conflicts
+@c <en>with the normal use inside @sc{cvs} (@pxref{Common options}).}
+@strong{Note: @code{log} uses @samp{-R} in a way that conflicts
+with the normal use inside @sc{cvs} (@pxref{Opções comuns}).}
+
+@menu
+* log options:: log options
+* log examples:: log examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node log options
+@appendixsubsec log options
+
+By default, @code{log} prints all information that is
+available. All other options restrict the output.
+
+@table @code
+@item -b
+Print information about the revisions on the default
+branch, normally the highest branch on the trunk.
+
+@c <en>@item -d @var{dates}
+@item -d @var{dates}
+@c <en>Print information about revisions with a checkin
+@c <en>date/time in the range given by the
+@c <en>semicolon-separated list of dates. The date formats
+@c <en>accepted are those accepted by the @samp{-D} option to
+@c <en>many other @sc{cvs} commands (@pxref{Common options}).
+@c <en>Dates can be combined into ranges as follows:
+Print information about revisions with a checkin
+date/time in the range given by the
+semicolon-separated list of dates. The date formats
+accepted are those accepted by the @samp{-D} option to
+many other @sc{cvs} commands (@pxref{Opções comuns}).
+Dates can be combined into ranges as follows:
+
+@c Should we be thinking about accepting ISO8601
+@c ranges? For example "1972-09-10/1972-09-12".
+@table @code
+@item @var{d1}<@var{d2}
+@itemx @var{d2}>@var{d1}
+Select the revisions that were deposited between
+@var{d1} and @var{d2}.
+
+@item <@var{d}
+@itemx @var{d}>
+Select all revisions dated @var{d} or earlier.
+
+@item @var{d}<
+@itemx >@var{d}
+Select all revisions dated @var{d} or later.
+
+@item @var{d}
+Select the single, latest revision dated @var{d} or
+earlier.
+@end table
+
+The @samp{>} or @samp{<} characters may be followed by
+@samp{=} to indicate an inclusive range rather than an
+exclusive one.
+
+Note that the separator is a semicolon (;).
+
+@item -h
+Print only the name of the @sc{rcs} file, name
+of the file in the working directory, head,
+default branch, access list, locks, symbolic names, and
+suffix.
+
+@item -l
+Local; run only in current working directory. (Default
+is to run recursively).
+
+@item -N
+Do not print the list of tags for this file. This
+option can be very useful when your site uses a lot of
+tags, so rather than "more"'ing over 3 pages of tag
+information, the log information is presented without
+tags at all.
+
+@item -R
+Print only the name of the @sc{rcs} file.
+
+@c Note that using a bare revision (in addition to not
+@c being explicitly documented here) is potentially
+@c confusing; it shows the log message to get from the
+@c previous revision to that revision. "-r1.3 -r1.6"
+@c (equivalent to "-r1.3,1.6") is even worse; it
+@c prints the messages to get from 1.2 to 1.3 and 1.5
+@c to 1.6. By analogy with "cvs diff", users might
+@c expect that it is more like specifying a range.
+@c It is not 100% clear to me how much of this should
+@c be documented (for example, multiple -r options
+@c perhaps could/should be deprecated given the false
+@c analogy with "cvs diff").
+@c In general, this section should be rewritten to talk
+@c about messages to get from revision rev1 to rev2,
+@c rather than messages for revision rev2 (that is, the
+@c messages are associated with a change not a static
+@c revision and failing to make this distinction causes
+@c much confusion).
+@item -r@var{revisions}
+Print information about revisions given in the
+comma-separated list @var{revisions} of revisions and
+ranges. The following table explains the available
+range formats:
+
+@table @code
+@item @var{rev1}:@var{rev2}
+Revisions @var{rev1} to @var{rev2} (which must be on
+the same branch).
+
+@item @var{rev1}::@var{rev2}
+The same, but excluding @var{rev1}.
+
+@item :@var{rev}
+@itemx ::@var{rev}
+Revisions from the beginning of the branch up to
+and including @var{rev}.
+
+@item @var{rev}:
+Revisions starting with @var{rev} to the end of the
+branch containing @var{rev}.
+
+@item @var{rev}::
+Revisions starting just after @var{rev} to the end of the
+branch containing @var{rev}.
+
+@item @var{branch}
+An argument that is a branch means all revisions on
+that branch.
+
+@item @var{branch1}:@var{branch2}
+@itemx @var{branch1}::@var{branch2}
+A range of branches means all revisions
+on the branches in that range.
+
+@item @var{branch}.
+The latest revision in @var{branch}.
+@end table
+
+A bare @samp{-r} with no revisions means the latest
+revision on the default branch, normally the trunk.
+There can be no space between the @samp{-r} option and
+its argument.
+
+@item -S
+Suppress the header if no revisions are selected.
+
+@item -s @var{states}
+Print information about revisions whose state
+attributes match one of the states given in the
+comma-separated list @var{states}.
+
+@item -t
+Print the same as @samp{-h}, plus the descriptive text.
+
+@item -w@var{logins}
+Print information about revisions checked in by users
+with login names appearing in the comma-separated list
+@var{logins}. If @var{logins} is omitted, the user's
+login is assumed. There can be no space between the
+@samp{-w} option and its argument.
+@end table
+
+@code{log} prints the intersection of the revisions
+selected with the options @samp{-d}, @samp{-s}, and
+@samp{-w}, intersected with the union of the revisions
+selected by @samp{-b} and @samp{-r}.
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node log examples
+@appendixsubsec log examples
+
+Contributed examples are gratefully accepted.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node rdiff
+@appendixsec rdiff---'patch' format diffs between releases
+@cindex rdiff (subcommand)
+
+@itemize @bullet
+@item
+rdiff [-flags] [-V vn] [-r t|-D d [-r t2|-D d2]] modules@dots{}
+@item
+Requires: repository.
+@item
+Changes: nothing.
+@item
+Synonym: patch
+@end itemize
+
+Builds a Larry Wall format patch(1) file between two
+releases, that can be fed directly into the @code{patch}
+program to bring an old release up-to-date with the new
+release. (This is one of the few @sc{cvs} commands that
+operates directly from the repository, and doesn't
+require a prior checkout.) The diff output is sent to
+the standard output device.
+
+You can specify (using the standard @samp{-r} and
+@samp{-D} options) any combination of one or two
+revisions or dates. If only one revision or date is
+specified, the patch file reflects differences between
+that revision or date and the current head revisions in
+the @sc{rcs} file.
+
+Note that if the software release affected is contained
+in more than one directory, then it may be necessary to
+specify the @samp{-p} option to the @code{patch} command when
+patching the old sources, so that @code{patch} is able to find
+the files that are located in other directories.
+
+@menu
+* rdiff options:: rdiff options
+* rdiff examples:: rdiff examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rdiff options
+@appendixsubsec rdiff options
+
+@c <en>These standard options are supported by @code{rdiff}
+@c <en>(@pxref{Common options}, for a complete description of
+@c <en>them):
+These standard options are supported by @code{rdiff}
+(@pxref{Opções comuns}, for a complete description of
+them):
+
+@table @code
+@item -D @var{date}
+Use the most recent revision no later than @var{date}.
+
+@item -f
+If no matching revision is found, retrieve the most
+recent revision (instead of ignoring the file).
+
+@item -l
+Local; don't descend subdirectories.
+
+@item -R
+Examine directories recursively. This option is on by default.
+
+@item -r @var{tag}
+Use revision @var{tag}.
+@end table
+
+In addition to the above, these options are available:
+
+@table @code
+@item -c
+Use the context diff format. This is the default format.
+
+@item -s
+Create a summary change report instead of a patch. The
+summary includes information about files that were
+changed or added between the releases. It is sent to
+the standard output device. This is useful for finding
+out, for example, which files have changed between two
+dates or revisions.
+
+@item -t
+A diff of the top two revisions is sent to the standard
+output device. This is most useful for seeing what the
+last change to a file was.
+
+@item -u
+Use the unidiff format for the context diffs.
+Remember that old versions
+of the @code{patch} program can't handle the unidiff
+format, so if you plan to post this patch to the net
+you should probably not use @samp{-u}.
+
+@item -V @var{vn}
+Expand keywords according to the rules current in
+@sc{rcs} version @var{vn} (the expansion format changed with
+@sc{rcs} version 5). Note that this option is no
+longer accepted. @sc{cvs} will always expand keywords the
+way that @sc{rcs} version 5 does.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node rdiff examples
+@appendixsubsec rdiff examples
+
+Suppose you receive mail from @t{foo@@example.net} asking for an
+update from release 1.2 to 1.4 of the tc compiler. You
+have no such patches on hand, but with @sc{cvs} that can
+easily be fixed with a command such as this:
+
+@example
+$ cvs rdiff -c -r FOO1_2 -r FOO1_4 tc | \
+$$ Mail -s 'The patches you asked for' foo@@example.net
+@end example
+
+Suppose you have made release 1.3, and forked a branch
+called @samp{R_1_3fix} for bugfixes. @samp{R_1_3_1}
+corresponds to release 1.3.1, which was made some time
+ago. Now, you want to see how much development has been
+done on the branch. This command can be used:
+
+@example
+$ cvs patch -s -r R_1_3_1 -r R_1_3fix module-name
+cvs rdiff: Diffing module-name
+File ChangeLog,v changed from revision 1.52.2.5 to 1.52.2.6
+File foo.c,v changed from revision 1.52.2.3 to 1.52.2.4
+File bar.h,v changed from revision 1.29.2.1 to 1.2
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node release
+@appendixsec release---Indicate that a Module is no longer in use
+@cindex release (subcommand)
+
+@itemize @bullet
+@item
+release [-d] directories@dots{}
+@item
+Requires: Working directory.
+@item
+Changes: Working directory, history log.
+@end itemize
+
+@c <en>This command is meant to safely cancel the effect of
+@c <en>@samp{cvs checkout}. Since @sc{cvs} doesn't lock files, it
+@c <en>isn't strictly necessary to use this command. You can
+@c <en>always simply delete your working directory, if you
+@c <en>like; but you risk losing changes you may have
+@c <en>forgotten, and you leave no trace in the @sc{cvs} history
+@c <en>file (@pxref{history file}) that you've abandoned your
+@c <en>checkout.
+This command is meant to safely cancel the effect of
+@samp{cvs checkout}. Since @sc{cvs} doesn't lock files, it
+isn't strictly necessary to use this command. You can
+always simply delete your working directory, if you
+like; but you risk losing changes you may have
+forgotten, and you leave no trace in the @sc{cvs} history
+file (@pxref{arquivo history (histórico)}) that you've abandoned your
+checkout.
+
+Use @samp{cvs release} to avoid these problems. This
+command checks that no uncommitted changes are
+present; that you are executing it from immediately
+above a @sc{cvs} working directory; and that the repository
+recorded for your files is the same as the repository
+defined in the module database.
+
+If all these conditions are true, @samp{cvs release}
+leaves a record of its execution (attesting to your
+intentionally abandoning your checkout) in the @sc{cvs}
+history log.
+
+@menu
+* release options:: release options
+* release output:: release output
+* release examples:: release examples
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release options
+@appendixsubsec release options
+
+The @code{release} command supports one command option:
+
+@table @code
+@item -d
+Delete your working copy of the file if the release
+succeeds. If this flag is not given your files will
+remain in your working directory.
+
+@c <en>@strong{WARNING: The @code{release} command deletes
+@c <en>all directories and files recursively. This
+@c <en>has the very serious side-effect that any directory
+@c <en>that you have created inside your checked-out sources,
+@c <en>and not added to the repository (using the @code{add}
+@c <en>command; @pxref{Adding files}) will be silently deleted---even
+@c <en>if it is non-empty!}
+@strong{WARNING: The @code{release} command deletes
+all directories and files recursively. This
+has the very serious side-effect that any directory
+that you have created inside your checked-out sources,
+and not added to the repository (using the @code{add}
+command; @pxref{Adicionando arquivos}) will be silently deleted---even
+if it is non-empty!}
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release output
+@appendixsubsec release output
+
+Before @code{release} releases your sources it will
+print a one-line message for any file that is not
+up-to-date.
+
+@table @code
+@item U @var{file}
+@itemx P @var{file}
+There exists a newer revision of this file in the
+repository, and you have not modified your local copy
+of the file (@samp{U} and @samp{P} mean the same thing).
+
+@item A @var{file}
+The file has been added to your private copy of the
+sources, but has not yet been committed to the
+repository. If you delete your copy of the sources
+this file will be lost.
+
+@item R @var{file}
+The file has been removed from your private copy of the
+sources, but has not yet been removed from the
+repository, since you have not yet committed the
+removal. @xref{commit}.
+
+@item M @var{file}
+The file is modified in your working directory. There
+might also be a newer revision inside the repository.
+
+@item ? @var{file}
+@var{file} is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for @sc{cvs} to ignore (see the
+description of the @samp{-I} option, and
+@pxref{cvsignore}). If you remove your working
+sources, this file will be lost.
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node release examples
+@appendixsubsec release examples
+
+Release the @file{tc} directory, and delete your local working copy
+of the files.
+
+@example
+$ cd .. # @r{You must stand immediately above the}
+ # @r{sources when you issue @samp{cvs release}.}
+$ cvs release -d tc
+You have [0] altered files in this repository.
+Are you sure you want to release (and delete) directory `tc': y
+$
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node update
+@appendixsec update---Bring work tree in sync with repository
+@cindex update (subcommand)
+
+@itemize @bullet
+@item
+update [-ACdflPpR] [-I name] [-j rev [-j rev]] [-k kflag] [-r tag|-D date] [-W spec] files@dots{}
+@item
+Requires: repository, working directory.
+@item
+Changes: working directory.
+@end itemize
+
+After you've run checkout to create your private copy
+of source from the common repository, other developers
+will continue changing the central source. From time
+to time, when it is convenient in your development
+process, you can use the @code{update} command from
+within your working directory to reconcile your work
+with any revisions applied to the source repository
+since your last checkout or update. Without the @code{-C}
+option, @code{update} will also merge any differences
+between the local copy of files and their base revisions
+into any destination revisions specified with @code{-r},
+@code{-D}, or @code{-A}.
+
+@menu
+* update options:: update options
+* update output:: update output
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node update options
+@appendixsubsec update options
+
+@c <en>These standard options are available with @code{update}
+@c <en>(@pxref{Common options}, for a complete description of
+@c <en>them):
+These standard options are available with @code{update}
+(@pxref{Opções comuns}, for a complete description of
+them):
+
+@table @code
+@c <en>@item -D date
+@item -D date
+@c <en>Use the most recent revision no later than @var{date}.
+@c <en>This option is sticky, and implies @samp{-P}.
+@c <en>See @ref{Sticky tags}, for more information on sticky tags/dates.
+Use the most recent revision no later than @var{date}.
+This option is sticky, and implies @samp{-P}.
+See @ref{Etiquetas adesivas}, for more information on sticky tags/dates.
+
+@item -f
+Only useful with the @samp{-D @var{date}} or @samp{-r
+@var{tag}} flags. If no matching revision is found,
+retrieve the most recent revision (instead of ignoring
+the file).
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Process keywords according to @var{kflag}. See
+@c <en>@ref{Keyword substitution}.
+@c <en>This option is sticky; future updates of
+@c <en>this file in this working directory will use the same
+@c <en>@var{kflag}. The @code{status} command can be viewed
+@c <en>to see the sticky options. See @ref{Invoking CVS}, for
+@c <en>more information on the @code{status} command.
+Process keywords according to @var{kflag}. See
+@ref{Substituição de palavra-chave}.
+This option is sticky; future updates of
+this file in this working directory will use the same
+@var{kflag}. The @code{status} command can be viewed
+to see the sticky options. See @ref{Chamando o CVS}, for
+more information on the @code{status} command.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. @xref{Recursive behavior}.
+Local; run only in current working directory. @xref{Comportamento recursivo}.
+
+@c <en>@item -P
+@item -P
+@c <en>Prune empty directories. See @ref{Moving directories}.
+Prune empty directories. See @ref{Movendo diretórios}.
+
+@c <en>@item -p
+@item -p
+@c <en>Pipe files to the standard output.
+Pipe files to the standard output.
+
+@c <en>@item -R
+@item -R
+@c <en>Update directories recursively (default). @xref{Recursive
+@c <en>behavior}.
+Update directories recursively (default).
+@xref{Comportamento recursivo}.
+
+@c <en>@item -r rev
+@item -r rev
+@c <en>Retrieve revision/tag @var{rev}. This option is sticky,
+@c <en>and implies @samp{-P}.
+@c <en>See @ref{Sticky tags}, for more information on sticky tags/dates.
+Retrieve revision/tag @var{rev}. This option is sticky,
+and implies @samp{-P}.
+See @ref{Etiquetas adesivas}, for more information on sticky tags/dates.
+@end table
+
+@need 800
+These special options are also available with
+@code{update}.
+
+@table @code
+@c <en>@item -A
+@item -A
+@c <en>Reset any sticky tags, dates, or @samp{-k} options.
+@c <en>See @ref{Sticky tags}, for more information on sticky tags/dates.
+Reset any sticky tags, dates, or @samp{-k} options.
+See @ref{Etiquetas adesivas}, for more information on sticky tags/dates.
+
+@item -C
+Overwrite locally modified files with clean copies from
+the repository (the modified file is saved in
+@file{.#@var{file}.@var{revision}}, however).
+
+@item -d
+Create any directories that exist in the repository if
+they're missing from the working directory. Normally,
+@code{update} acts only on directories and files that
+were already enrolled in your working directory.
+
+This is useful for updating directories that were
+created in the repository since the initial checkout;
+but it has an unfortunate side effect. If you
+deliberately avoided certain directories in the
+repository when you created your working directory
+(either through use of a module name or by listing
+explicitly the files and directories you wanted on the
+command line), then updating with @samp{-d} will create
+those directories, which may not be what you want.
+
+@item -I @var{name}
+Ignore files whose names match @var{name} (in your
+working directory) during the update. You can specify
+@samp{-I} more than once on the command line to specify
+several files to ignore. Use @samp{-I !} to avoid
+ignoring any files at all. @xref{cvsignore}, for other
+ways to make @sc{cvs} ignore some files.
+
+@item -W@var{spec}
+Specify file names that should be filtered during
+update. You can use this option repeatedly.
+
+@var{spec} can be a file name pattern of the same type
+that you can specify in the @file{.cvswrappers}
+file. @xref{Wrappers}.
+
+@item -j@var{revision}
+With two @samp{-j} options, merge changes from the
+revision specified with the first @samp{-j} option to
+the revision specified with the second @samp{j} option,
+into the working directory.
+
+With one @samp{-j} option, merge changes from the
+ancestor revision to the revision specified with the
+@samp{-j} option, into the working directory. The
+ancestor revision is the common ancestor of the
+revision which the working directory is based on, and
+the revision specified in the @samp{-j} option.
+
+@c <en>Note that using a single @samp{-j @var{tagname}} option rather than
+@c <en>@samp{-j @var{branchname}} to merge changes from a branch will
+@c <en>often not remove files which were removed on the branch.
+@c <en>@xref{Merging adds and removals}, for more.
+Note that using a single @samp{-j @var{tagname}} option rather than
+@samp{-j @var{branchname}} to merge changes from a branch will
+often not remove files which were removed on the branch.
+@xref{Mesclando adicionados e removidos}, for more.
+
+In addition, each @samp{-j} option can contain an optional
+date specification which, when used with branches, can
+limit the chosen revision to one within a specific
+date. An optional date is specified by adding a colon
+(:) to the tag:
+@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}.
+
+@c <en>@xref{Branching and merging}.
+@xref{Ramificando e mesclando}.
+
+@end table
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@c <en>@node update output
+@node update output
+@c <en>@appendixsubsec update output
+@appendixsubsec update output
+
+@c <en>@code{update} and @code{checkout} keep you informed of
+@c <en>their progress by printing a line for each file, preceded
+@c <en>by one character indicating the status of the file:
+O @code{update} e o @code{checkout} mantém você
+informado de seu progresso escrevendo uma linha para
+cada arquivo, iniciando com um caractere que indica o
+status do arquivo:
+
+@table @code
+@c <en>@item U @var{file}
+@item U @var{arquivo}
+@c <en>The file was brought up to date with respect to the
+@c <en>repository. This is done for any file that exists in
+@c <en>the repository but not in your source, and for files
+@c <en>that you haven't changed but are not the most recent
+@c <en>versions available in the repository.
+O arquivo foi atualizado com base no repositório. Isto
+é feito para qualquer arquivo que exista no
+repositório mas não esteja nos seus fontes (no seu
+diretório da trabalho) e para arquivos que você não
+mudou mas não estão na versão mais recente que está
+disponível no repositório.
+
+@c <en>@item P @var{file}
+@item P @var{arquivo}
+@c <en>Like @samp{U}, but the @sc{cvs} server sends a patch instead of an entire
+@c <en>file. This accomplishes the same thing as @samp{U} using less bandwidth.
+
+Como o @samp{U}, mas o servidor @sc{cvs} manda um patch
+(remendo) ao invés de mandar um arquivo inteiro. Tem o
+mesmo resultado que @samp{U} usando menos largura de banda.
+
+@c <en>@item A @var{file}
+@item A @var{arquivo}
+@c <en>The file has been added to your private copy of the
+@c <en>sources, and will be added to the source repository
+@c <en>when you run @code{commit} on the file. This is a
+@c <en>reminder to you that the file needs to be committed.
+O arquivo foi adicionado a sua cópia local dos fontes,
+e vai ser adicionado ao repositório quando você rodar o
+@code{commit} no arquivo. Funciona como um lembrete de
+que o arquivo precisa ser ???commitado???.
+
+@c <en>@item R @var{file}
+@item R @var{arquivo}
+@c <en>The file has been removed from your private copy of the
+@c <en>sources, and will be removed from the source repository
+@c <en>when you run @code{commit} on the file. This is a
+@c <en>reminder to you that the file needs to be committed.
+O arquivo foi removido de sua cópia local dos fontes, e
+será removido do repositório quando você executar um
+@code{commit} no arquivo. Funciona como um lembrete de
+que o arquivo precisa ser ???commitado???.
+
+@c <en>@item M @var{file}
+@item M @var{arquivo}
+@c <en>The file is modified in your working directory.
+O arquivo está modificado no seu diretório de trabalho.
+
+@c <en>@samp{M} can indicate one of two states for a file
+@c <en>you're working on: either there were no modifications
+@c <en>to the same file in the repository, so that your file
+@c <en>remains as you last saw it; or there were modifications
+@c <en>in the repository as well as in your copy, but they
+@c <en>were merged successfully, without conflict, in your
+@c <en>working directory.
+O @samp{M} pode indicar um dos dois estados para um
+arquivo no qual você esteja trabalhando: ou não existem
+modificações do arquivo equivalente no repositório, de forma
+que seu arquivo continua da forma como você o deixou;
+ou existem modificações no repositório assim como na
+sua cópia, mas elas foram mescladas com sucesso, sem
+conflito, no seu diretório de trabalho.
+
+@c <en>@sc{cvs} will print some messages if it merges your work,
+@c <en>and a backup copy of your working file (as it looked
+@c <en>before you ran @code{update}) will be made. The exact
+@c <en>name of that file is printed while @code{update} runs.
+O @sc{cvs} vai escrever algumas mensagens se ele
+mesclar seu trabalho, e colocará uma cópia de segurança no seu
+diretório de trabalho (na forma que estava antes de
+executar o @code{update}). O nome exato do arquivo
+será escrito quando o @code{update} rodar.
+
+@c <en>@item C @var{file}
+@item C @var{arquivo}
+@c <en>@cindex .# files
+@cindex arquivos .#
+@c <en>@cindex __ files (VMS)
+@cindex __ arquivos (VMS)
+@c <en>A conflict was detected while trying to merge your
+@c <en>changes to @var{file} with changes from the source
+@c <en>repository. @var{file} (the copy in your working
+@c <en>directory) is now the result of attempting to merge
+@c <en>the two revisions; an unmodified copy of your file
+@c <en>is also in your working directory, with the name
+@c <en>@file{.#@var{file}.@var{revision}} where @var{revision}
+@c <en>is the revision that your modified file started
+@c <en>from. Resolve the conflict as described in
+@c <en>@ref{Conflicts example}.
+Um conflito foi detectado quando se tentava mesclar
+suas mudanças no @var{arquivo} com as mudanças no
+repositório. O @var{arquivo} (a cópia no seu diretório
+de trabalho) é agora o resultado da tentativa de
+mesclar as duas revisões; uma cópia inalterada do
+arquivo também está no diretório de trabalho, com o
+nome de @file{.#@var{arquivo}.@var{revisão}} onde
+@var{revisão} é a revisão de onde o seu arquivo
+modificado saiu. Resolva o conflito como é mostrado em
+@ref{Exemplo de conflitos}.
+@c "some systems" as in out-of-the-box OSes? Not as
+@c far as I know. We need to advise sysadmins as well
+@c as users how to set up this kind of purge, if that is
+@c what they want.
+@c We also might want to think about cleaner solutions,
+@c like having CVS remove the .# file once the conflict
+@c has been resolved or something like that.
+@c <en>(Note that some systems automatically purge
+@c <en>files that begin with @file{.#} if they have not been
+@c <en>accessed for a few days. If you intend to keep a copy
+@c <en>of your original file, it is a very good idea to rename
+@c <en>it.) Under @sc{vms}, the file name starts with
+@c <en>@file{__} rather than @file{.#}.
+(Note que alguns sistemas eliminam automaticamente
+arquivos que começam com @file{.#} se eles não são
+acessados por alguns dias. Se você pretende manter uma
+cópia do arquivo original, é um ótima idéia
+renomeá-lo.) No @sc{vms}, o nome do arquivo começa com
+@file{__} ao invés de @file{.#}.
+
+@c <en>@item ? @var{file}
+@item ? @var{arquivo}
+@c <en>@var{file} is in your working directory, but does not
+@c <en>correspond to anything in the source repository, and is
+@c <en>not in the list of files for @sc{cvs} to ignore (see the
+@c <en>description of the @samp{-I} option, and
+@c <en>@pxref{cvsignore}).
+O @var{arquivo} is in your working directory, but does not
+correspond to anything in the source repository, and is
+not in the list of files for @sc{cvs} to ignore (see the
+description of the @samp{-I} option, and
+@pxref{cvsignore}).
+@end table
+
+@c <en>@node Invoking CVS
+@node Chamando o CVS
+@c <en>@appendix Quick reference to CVS commands
+@appendix Quick reference to CVS commands
+@c <en>@cindex Command reference
+@cindex Command reference
+@c <en>@cindex Reference, commands
+@cindex Reference, commands
+@c <en>@cindex Invoking CVS
+@cindex Chamando o CVS
+
+@c <en>This appendix describes how to invoke @sc{cvs}, with
+@c <en>references to where each command or feature is
+@c <en>described in detail. For other references run the
+@c <en>@code{cvs --help} command, or see @ref{Index}.
+This appendix describes how to invoke @sc{cvs}, with
+references to where each command or feature is
+described in detail. For other references run the
+@code{cvs --help} command, or see @ref{Indice}.
+
+@c <en>A @sc{cvs} command looks like:
+A @sc{cvs} command looks like:
+
+@example
+cvs [ @var{global_options} ] @var{command} [ @var{command_options} ] [ @var{command_args} ]
+@end example
+
+Global options:
+
+@table @code
+@c <en>@item --allow-root=@var{rootdir}
+@item --allow-root=@var{rootdir}
+@c <en>Specify legal @sc{cvsroot} directory (server only) (not
+@c <en>in @sc{cvs} 1.9 and older). See @ref{Password
+@c <en>authentication server}.
+Specify legal @sc{cvsroot} directory (server only) (not
+in @sc{cvs} 1.9 and older). See
+@ref{Servidor de autenticação por senha}.
+
+@c <en>@item -a
+@item -a
+@c <en>Authenticate all communication (client only) (not in @sc{cvs}
+@c <en>1.9 and older). See @ref{Global options}.
+Authenticate all communication (client only) (not in @sc{cvs}
+1.9 and older). See @ref{Opções globais}.
+
+@c <en>@item -b
+@item -b
+@c <en>Specify RCS location (@sc{cvs} 1.9 and older). See
+@c <en>@ref{Global options}.
+Specify RCS location (@sc{cvs} 1.9 and older). See
+@ref{Opções globais}.
+
+@c <en>@item -d @var{root}
+@item -d @var{root}
+@c <en>Specify the @sc{cvsroot}. See @ref{Repository}.
+Specify the @sc{cvsroot}. See @ref{Repositório}.
+
+@c <en>@item -e @var{editor}
+@item -e @var{editor}
+@c <en>Edit messages with @var{editor}. See @ref{Committing
+@c <en>your changes}.
+Edit messages with @var{editor}. See
+@ref{Efetivando suas alterações}.
+
+@c <en>@item -f
+@item -f
+@c <en>Do not read the @file{~/.cvsrc} file. See @ref{Global
+@c <en>options}.
+Do not read the @file{~/.cvsrc} file. See @ref{Opções globais}.
+
+@c <en>@item -H
+@item -H
+@c <en>@itemx --help
+@itemx --help
+@c <en>Print a help message. See @ref{Global options}.
+Print a help message. See @ref{Opções globais}.
+
+@c <en>@item -l
+@item -l
+@c <en>Do not log in @file{$CVSROOT/CVSROOT/history} file. See @ref{Global
+@c <en>options}.
+Do not log in @file{$CVSROOT/CVSROOT/history} file. See
+@ref{Opções globais}.
+
+@c <en>@item -n
+@item -n
+@c <en>Do not change any files. See @ref{Global options}.
+Do not change any files. See @ref{Opções globais}.
+
+@c <en>@item -Q
+@item -Q
+@c <en>Be really quiet. See @ref{Global options}.
+Be really quiet. See @ref{Opções globais}.
+
+@c <en>@item -q
+@item -q
+@c <en>Be somewhat quiet. See @ref{Global options}.
+Be somewhat quiet. See @ref{Opções globais}.
+
+@c <en>@item -r
+@item -r
+@c <en>Make new working files read-only. See @ref{Global options}.
+Make new working files read-only. See @ref{Opções globais}.
+
+@c <en>@item -s @var{variable}=@var{value}
+@item -s @var{variable}=@var{value}
+@c <en>Set a user variable. See @ref{Variables}.
+Set a user variable. See @ref{Variables}.
+
+@c <en>@item -T @var{tempdir}
+@item -T @var{tempdir}
+@c <en>Put temporary files in @var{tempdir}. See @ref{Global
+@c <en>options}.
+Put temporary files in @var{tempdir}. See
+@ref{Opções globais}.
+
+@c <en>@item -t
+@item -t
+@c <en>Trace @sc{cvs} execution. See @ref{Global options}.
+Trace @sc{cvs} execution. See @ref{Opções globais}.
+
+@c <en>@item -v
+@item -v
+@c <en>@item --version
+@item --version
+@c <en>Display version and copyright information for @sc{cvs}.
+Display version and copyright information for @sc{cvs}.
+
+@c <en>@item -w
+@item -w
+@c <en>Make new working files read-write. See @ref{Global
+@c <en>options}.
+Make new working files read-write. See @ref{Opções globais}.
+
+@c <en>@item -x
+@item -x
+@c <en>Encrypt all communication (client only).
+@c <en>See @ref{Global options}.
+Encrypt all communication (client only).
+See @ref{Opções globais}.
+
+@c <en>@item -z @var{gzip-level}
+@item -z @var{gzip-level}
+@c <en>@cindex Compression
+@cindex Compression
+@c <en>@cindex Gzip
+@cindex Gzip
+@c <en>Set the compression level (client only).
+@c <en>See @ref{Global options}.
+Set the compression level (client only).
+See @ref{Opções globais}.
+@end table
+
+@c <en>Keyword expansion modes (@pxref{Substitution modes}):
+Keyword expansion modes (@pxref{Modos de substituição}):
+
+@example
+-kkv $@splitrcskeyword{}Id: file1,v 1.1 1993/12/09 03:21:13 joe Exp $
+-kkvl $@splitrcskeyword{}Id: file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+-kk $@splitrcskeyword{}Id$
+-kv file1,v 1.1 1993/12/09 03:21:13 joe Exp
+-ko @i{no expansion}
+-kb @i{no expansion, file is binary}
+@end example
+
+@c <en>Keywords (@pxref{Keyword list}):
+Keywords (@pxref{Lista de palavras-chave}):
+
+@example
+$@splitrcskeyword{}Author: joe $
+$@splitrcskeyword{}Date: 1993/12/09 03:21:13 $
+$@splitrcskeyword{}CVSHeader: files/file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+$@splitrcskeyword{}Header: /home/files/file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+$@splitrcskeyword{}Id: file1,v 1.1 1993/12/09 03:21:13 joe Exp harry $
+$@splitrcskeyword{}Locker: harry $
+$@splitrcskeyword{}Name: snapshot_1_14 $
+$@splitrcskeyword{}RCSfile: file1,v $
+$@splitrcskeyword{}Revision: 1.1 $
+$@splitrcskeyword{}Source: /home/files/file1,v $
+$@splitrcskeyword{}State: Exp $
+$@splitrcskeyword{}Log: file1,v $
+Revision 1.1 1993/12/09 03:30:17 joe
+Initial revision
+
+@end example
+
+@c The idea behind this table is that we want each item
+@c to be a sentence or two at most. Preferably a
+@c single line.
+@c
+@c In some cases refs to "foo options" are just to get
+@c this thing written quickly, not because the "foo
+@c options" node is really the best place to point.
+Commands, command options, and command arguments:
+
+@table @code
+@c ------------------------------------------------------------
+@c <en>@item add [@var{options}] [@var{files}@dots{}]
+@item add [@var{options}] [@var{files}@dots{}]
+@c <en>Add a new file/directory. See @ref{Adding files}.
+Add a new file/directory. See @ref{Adicionando arquivos}.
+
+@table @code
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Set keyword expansion.
+Set keyword expansion.
+
+@c <en>@item -m @var{msg}
+@item -m @var{msg}
+@c <en>Set file description.
+Set file description.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item admin [@var{options}] [@var{files}@dots{}]
+@item admin [@var{options}] [@var{files}@dots{}]
+@c <en>Administration of history files in the repository. See
+@c <en>@ref{admin}.
+Administration of history files in the repository. See
+@ref{admin}.
+@c This list omits those options which are not
+@c documented as being useful with CVS. That might be
+@c a mistake...
+
+@table @code
+@c <en>@item -b[@var{rev}]
+@item -b[@var{rev}]
+@c <en>Set default branch. See @ref{Reverting local changes}.
+Set default branch. See @ref{Reverting local changes}.
+
+@c <en>@item -c@var{string}
+@item -c@var{string}
+@c <en>Set comment leader.
+Set comment leader.
+
+@c <en>@item -k@var{subst}
+@item -k@var{subst}
+@c <en>Set keyword substitution. See @ref{Keyword
+@c <en>substitution}.
+Set keyword substitution. See @ref{Substituição de palavra-chave}.
+
+@c <en>@item -l[@var{rev}]
+@item -l[@var{rev}]
+@c <en>Lock revision @var{rev}, or latest revision.
+Lock revision @var{rev}, or latest revision.
+
+@c <en>@item -m@var{rev}:@var{msg}
+@item -m@var{rev}:@var{msg}
+@c <en>Replace the log message of revision @var{rev} with
+@c <en>@var{msg}.
+Replace the log message of revision @var{rev} with
+@var{msg}.
+
+@c <en>@item -o@var{range}
+@item -o@var{range}
+@c <en>Delete revisions from the repository. See
+@c <en>@ref{admin options}.
+Delete revisions from the repository. See
+@ref{admin options}.
+
+@c <en>@item -q
+@item -q
+@c <en>Run quietly; do not print diagnostics.
+Run quietly; do not print diagnostics.
+
+@c <en>@item -s@var{state}[:@var{rev}]
+@item -s@var{state}[:@var{rev}]
+@c <en>Set the state.
+Set the state.
+
+@c Does not work for client/server CVS
+@c <en>@item -t
+@item -t
+@c <en>Set file description from standard input.
+Set file description from standard input.
+
+@c <en>@item -t@var{file}
+@item -t@var{file}
+@c <en>Set file description from @var{file}.
+Set file description from @var{file}.
+
+@c <en>@item -t-@var{string}
+@item -t-@var{string}
+@c <en>Set file description to @var{string}.
+Set file description to @var{string}.
+
+@c <en>@item -u[@var{rev}]
+@item -u[@var{rev}]
+@c <en>Unlock revision @var{rev}, or latest revision.
+Unlock revision @var{rev}, or latest revision.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item annotate [@var{options}] [@var{files}@dots{}]
+@item annotate [@var{options}] [@var{files}@dots{}]
+@c <en>Show last revision where each line was modified. See
+@c <en>@ref{annotate}.
+Show last revision where each line was modified. See
+@ref{annotate}.
+
+@table @code
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Annotate the most recent revision no later than
+@c <en>@var{date}. See @ref{Common options}.
+Annotate the most recent revision no later than
+@var{date}. See @ref{Opções comuns}.
+
+@c <en>@item -F
+@item -F
+@c <en>Force annotation of binary files. (Without this option,
+@c <en>binary files are skipped with a message.)
+Force annotation of binary files. (Without this option,
+binary files are skipped with a message.)
+
+@c <en>@item -f
+@item -f
+@c <en>Use head revision if tag/date not found. See
+@c <en>@ref{Common options}.
+Use head revision if tag/date not found. See
+@ref{Opções comuns}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. @xref{Recursive behavior}.
+Local; run only in current working directory. @xref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default).
+@xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{tag}
+@item -r @var{tag}
+@c <en>Annotate revision @var{tag}. See @ref{Common options}.
+Annotate revision @var{tag}. See @ref{Opções comuns}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item checkout [@var{options}] @var{modules}@dots{}
+@item checkout [@var{options}] @var{modules}@dots{}
+@c <en>Get a copy of the sources. See @ref{checkout}.
+Get a copy of the sources. See @ref{checkout}.
+
+@table @code
+@c <en>@item -A
+@item -A
+@c <en>Reset any sticky tags/date/options. See @ref{Sticky
+@c <en>tags} and @ref{Keyword substitution}.
+Reset any sticky tags/date/options. See @ref{Etiquetas adesivas}
+and @ref{Substituição de palavra-chave}.
+
+@c <en>@item -c
+@item -c
+@c <en>Output the module database. See @ref{checkout options}.
+Output the module database. See @ref{checkout options}.
+
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Check out revisions as of @var{date} (is sticky). See
+@c <en>@ref{Common options}.
+Check out revisions as of @var{date} (is sticky). See
+@ref{Opções comuns}.
+
+@c <en>@item -d @var{dir}
+@item -d @var{dir}
+@c <en>Check out into @var{dir}. See @ref{checkout options}.
+Check out into @var{dir}. See @ref{checkout options}.
+
+@c <en>@item -f
+@item -f
+@c <en>Use head revision if tag/date not found. See
+@c <en>@ref{Common options}.
+Use head revision if tag/date not found. See
+@ref{Opções comuns}.
+
+@c Probably want to use rev1/rev2 style like for diff
+@c -r. Here and in on-line help.
+@c <en>@item -j @var{rev}
+@item -j @var{rev}
+@c <en>Merge in changes. See @ref{checkout options}.
+Merge in changes. See @ref{checkout options}.
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Use @var{kflag} keyword expansion. See
+@c <en>@ref{Substitution modes}.
+Use @var{kflag} keyword expansion. See
+@ref{Modos de substituição}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. @xref{Recursive behavior}.
+Local; run only in current working directory. @xref{Comportamento recursivo}.
+
+@c <en>@item -N
+@item -N
+@c <en>Don't ``shorten'' module paths if -d specified. See
+@c <en>@ref{checkout options}.
+Don't ``shorten'' module paths if -d specified. See
+@ref{checkout options}.
+
+@c <en>@item -n
+@item -n
+@c <en>Do not run module program (if any). See @ref{checkout options}.
+Do not run module program (if any). See @ref{checkout options}.
+
+@c <en>@item -P
+@item -P
+@c <en>Prune empty directories. See @ref{Moving directories}.
+Prune empty directories. See @ref{Movendo diretórios}.
+
+@c <en>@item -p
+@item -p
+@c <en>Check out files to standard output (avoids
+@c <en>stickiness). See @ref{checkout options}.
+Check out files to standard output (avoids
+stickiness). See @ref{checkout options}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{tag}
+@item -r @var{tag}
+@c <en>Checkout revision @var{tag} (is sticky). See @ref{Common options}.
+Checkout revision @var{tag} (is sticky). See @ref{Opções comuns}.
+
+@c <en>@item -s
+@item -s
+@c <en>Like -c, but include module status. See @ref{checkout options}.
+Like -c, but include module status. See @ref{checkout options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item commit [@var{options}] [@var{files}@dots{}]
+@item commit [@var{options}] [@var{files}@dots{}]
+@c <en>Check changes into the repository. See @ref{commit}.
+Check changes into the repository. See @ref{commit}.
+
+@table @code
+@c <en>@item -F @var{file}
+@item -F @var{file}
+@c <en>Read log message from @var{file}. See @ref{commit options}.
+Read log message from @var{file}. See @ref{commit options}.
+
+@c <en>@item -f
+@item -f
+@c What is this "disables recursion"? It is from the
+@c on-line help; is it documented in this manual?
+@c <en>Force the file to be committed; disables recursion.
+@c <en>See @ref{commit options}.
+Force the file to be committed; disables recursion.
+See @ref{commit options}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -m @var{msg}
+@item -m @var{msg}
+@c <en>Use @var{msg} as log message. See @ref{commit options}.
+Use @var{msg} as log message. See @ref{commit options}.
+
+@c <en>@item -n
+@item -n
+@c <en>Do not run module program (if any). See @ref{commit options}.
+Do not run module program (if any). See @ref{commit options}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{rev}
+@item -r @var{rev}
+@c <en>Commit to @var{rev}. See @ref{commit options}.
+Commit to @var{rev}. See @ref{commit options}.
+@c FIXME: should be dragging over text from
+@c commit options, especially if it can be cleaned up
+@c and made concise enough.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item diff [@var{options}] [@var{files}@dots{}]
+@item diff [@var{options}] [@var{files}@dots{}]
+@c <en>Show differences between revisions. See @ref{diff}.
+@c <en>In addition to the options shown below, accepts a wide
+@c <en>variety of options to control output style, for example
+@c <en>@samp{-c} for context diffs.
+Show differences between revisions. See @ref{diff}.
+In addition to the options shown below, accepts a wide
+variety of options to control output style, for example
+@samp{-c} for context diffs.
+
+@table @code
+@c <en>@item -D @var{date1}
+@item -D @var{date1}
+@c <en>Diff revision for date against working file. See
+@c <en>@ref{diff options}.
+Diff revision for date against working file. See
+@ref{diff options}.
+
+@c <en>@item -D @var{date2}
+@item -D @var{date2}
+@c <en>Diff @var{rev1}/@var{date1} against @var{date2}. See
+@c <en>@ref{diff options}.
+Diff @var{rev1}/@var{date1} against @var{date2}. See
+@ref{diff options}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -N
+@item -N
+@c <en>Include diffs for added and removed files. See
+@c <en>@ref{diff options}.
+Include diffs for added and removed files. See
+@ref{diff options}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{rev1}
+@item -r @var{rev1}
+@c <en>Diff revision for @var{rev1} against working file. See
+@c <en>@ref{diff options}.
+Diff revision for @var{rev1} against working file. See
+@ref{diff options}.
+
+@c <en>@item -r @var{rev2}
+@item -r @var{rev2}
+@c <en>Diff @var{rev1}/@var{date1} against @var{rev2}. See @ref{diff options}.
+Diff @var{rev1}/@var{date1} against @var{rev2}. See @ref{diff options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item edit [@var{options}] [@var{files}@dots{}]
+@item edit [@var{options}] [@var{files}@dots{}]
+@c <en>Get ready to edit a watched file. See @ref{Editing files}.
+Get ready to edit a watched file. See @ref{Editando arquivos}.
+
+@table @code
+@c <en>@item -a @var{actions}
+@item -a @var{actions}
+@c <en>Specify actions for temporary watch, where
+@c <en>@var{actions} is @code{edit}, @code{unedit},
+@c <en>@code{commit}, @code{all}, or @code{none}. See
+@c <en>@ref{Editing files}.
+Specify actions for temporary watch, where
+@var{actions} is @code{edit}, @code{unedit},
+@code{commit}, @code{all}, or @code{none}. See
+@ref{Editando arquivos}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item editors [@var{options}] [@var{files}@dots{}]
+@item editors [@var{options}] [@var{files}@dots{}]
+@c <en>See who is editing a watched file. See @ref{Watch information}.
+See who is editing a watched file. See @ref{Informações de ???Watch???}.
+
+@table @code
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item export [@var{options}] @var{modules}@dots{}
+@item export [@var{options}] @var{modules}@dots{}
+@c <en>Export files from @sc{cvs}. See @ref{export}.
+Export files from @sc{cvs}. See @ref{export}.
+
+@table @code
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Check out revisions as of @var{date}. See
+@c <en>@ref{Common options}.
+Check out revisions as of @var{date}. See
+@ref{Opções comuns}.
+
+@c <en>@item -d @var{dir}
+@item -d @var{dir}
+@c <en>Check out into @var{dir}. See @ref{export options}.
+Check out into @var{dir}. See @ref{export options}.
+
+@c <en>@item -f
+@item -f
+@c <en>Use head revision if tag/date not found. See
+@c <en>@ref{Common options}.
+Use head revision if tag/date not found. See
+@ref{Opções comuns}.
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Use @var{kflag} keyword expansion. See
+@c <en>@ref{Substitution modes}.
+Use @var{kflag} keyword expansion. See
+@ref{Modos de substituição}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. @xref{Recursive behavior}.
+Local; run only in current working directory. @xref{Comportamento recursivo}.
+
+@c <en>@item -N
+@item -N
+@c <en>Don't ``shorten'' module paths if -d specified. See
+@c <en>@ref{export options}.
+Don't ``shorten'' module paths if -d specified. See
+@ref{export options}.
+
+@c <en>@item -n
+@item -n
+@c <en>Do not run module program (if any). See @ref{export options}.
+Do not run module program (if any). See @ref{export options}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{tag}
+@item -r @var{tag}
+@c <en>Checkout revision @var{tag}. See @ref{Common options}.
+Checkout revision @var{tag}. See @ref{Opções comuns}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item history [@var{options}] [@var{files}@dots{}]
+@item history [@var{options}] [@var{files}@dots{}]
+@c <en>Show repository access history. See @ref{history}.
+Show repository access history. See @ref{history}.
+
+@table @code
+@c <en>@item -a
+@item -a
+@c <en>All users (default is self). See @ref{history options}.
+All users (default is self). See @ref{history options}.
+
+@c <en>@item -b @var{str}
+@item -b @var{str}
+@c <en>Back to record with @var{str} in module/file/repos
+@c <en>field. See @ref{history options}.
+Back to record with @var{str} in module/file/repos
+field. See @ref{history options}.
+
+@c <en>@item -c
+@item -c
+@c <en>Report on committed (modified) files. See @ref{history options}.
+Report on committed (modified) files. See @ref{history options}.
+
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Since @var{date}. See @ref{history options}.
+Since @var{date}. See @ref{history options}.
+
+@c <en>@item -e
+@item -e
+@c <en>Report on all record types. See @ref{history options}.
+Report on all record types. See @ref{history options}.
+
+@c <en>@item -l
+@item -l
+@c <en>Last modified (committed or modified report). See @ref{history options}.
+Last modified (committed or modified report). See @ref{history options}.
+
+@c <en>@item -m @var{module}
+@item -m @var{module}
+@c <en>Report on @var{module} (repeatable). See @ref{history options}.
+Report on @var{module} (repeatable). See @ref{history options}.
+
+@c <en>@item -n @var{module}
+@item -n @var{module}
+@c <en>In @var{module}. See @ref{history options}.
+In @var{module}. See @ref{history options}.
+
+@c <en>@item -o
+@item -o
+@c <en>Report on checked out modules. See @ref{history options}.
+Report on checked out modules. See @ref{history options}.
+
+@c <en>@item -p @var{repository}
+@item -p @var{repository}
+@c <en>In @var{repository}. See @ref{history options}.
+In @var{repository}. See @ref{history options}.
+
+@c <en>@item -r @var{rev}
+@item -r @var{rev}
+@c <en>Since revision @var{rev}. See @ref{history options}.
+Since revision @var{rev}. See @ref{history options}.
+
+@c <en>@item -T
+@item -T
+@c What the @#$@# is a TAG? Same as a tag? This
+@c wording is also in the online-line help.
+@c <en>Produce report on all TAGs. See @ref{history options}.
+Produce report on all TAGs. See @ref{history options}.
+
+@c <en>@item -t @var{tag}
+@item -t @var{tag}
+@c <en>Since tag record placed in history file (by anyone).
+@c <en>See @ref{history options}.
+Since tag record placed in history file (by anyone).
+See @ref{history options}.
+
+@c <en>@item -u @var{user}
+@item -u @var{user}
+@c <en>For user @var{user} (repeatable). See @ref{history options}.
+For user @var{user} (repeatable). See @ref{history options}.
+
+@c <en>@item -w
+@item -w
+@c <en>Working directory must match. See @ref{history options}.
+Working directory must match. See @ref{history options}.
+
+@c <en>@item -x @var{types}
+@item -x @var{types}
+@c <en>Report on @var{types}, one or more of
+@c <en>@code{TOEFWUPCGMAR}. See @ref{history options}.
+Report on @var{types}, one or more of
+@code{TOEFWUPCGMAR}. See @ref{history options}.
+
+@c <en>@item -z @var{zone}
+@item -z @var{zone}
+@c <en>Output for time zone @var{zone}. See @ref{history options}.
+Output for time zone @var{zone}. See @ref{history options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item import [@var{options}] @var{repository} @var{vendor-tag} @var{release-tags}@dots{}
+@item import [@var{options}] @var{repository} @var{vendor-tag} @var{release-tags}@dots{}
+@c <en>Import files into @sc{cvs}, using vendor branches. See
+@c <en>@ref{import}.
+Import files into @sc{cvs}, using vendor branches. See
+@ref{import}.
+
+@table @code
+@c <en>@item -b @var{bra}
+@item -b @var{bra}
+@c <en>Import to vendor branch @var{bra}. See
+@c <en>@ref{Multiple vendor branches}.
+Import to vendor branch @var{bra}. See
+@ref{Ramos de fornecedor múltiplos}.
+
+@c <en>@item -d
+@item -d
+@c <en>Use the file's modification time as the time of
+@c <en>import. See @ref{import options}.
+Use the file's modification time as the time of
+import. See @ref{import options}.
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Set default keyword substitution mode. See
+@c <en>@ref{import options}.
+Set default keyword substitution mode. See
+@ref{import options}.
+
+@c <en>@item -m @var{msg}
+@item -m @var{msg}
+@c <en>Use @var{msg} for log message. See
+@c <en>@ref{import options}.
+Use @var{msg} for log message. See
+@ref{import options}.
+
+@c <en>@item -I @var{ign}
+@item -I @var{ign}
+@c <en>More files to ignore (! to reset). See
+@c <en>@ref{import options}.
+More files to ignore (! to reset). See
+@ref{import options}.
+
+@c <en>@item -W @var{spec}
+@item -W @var{spec}
+@c <en>More wrappers. See @ref{import options}.
+More wrappers. See @ref{import options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item init
+@item init
+@c <en>Create a @sc{cvs} repository if it doesn't exist. See
+@c <en>@ref{Creating a repository}.
+Create a @sc{cvs} repository if it doesn't exist. See
+@ref{Criando um repositório}.
+
+@c ------------------------------------------------------------
+@c <en>@item kserver
+@item kserver
+@c <en>Kerberos authenticated server.
+@c <en>See @ref{Kerberos authenticated}.
+Kerberos authenticated server.
+See @ref{Autenticação kerberos}.
+
+@c ------------------------------------------------------------
+@c <en>@item log [@var{options}] [@var{files}@dots{}]
+@item log [@var{options}] [@var{files}@dots{}]
+@c <en>Print out history information for files. See @ref{log}.
+Print out history information for files. See @ref{log}.
+
+@table @code
+@c <en>@item -b
+@item -b
+@c <en>Only list revisions on the default branch. See @ref{log options}.
+Only list revisions on the default branch. See @ref{log options}.
+
+@c <en>@item -d @var{dates}
+@item -d @var{dates}
+@c <en>Specify dates (@var{d1}<@var{d2} for range, @var{d} for
+@c <en>latest before). See @ref{log options}.
+Specify dates (@var{d1}<@var{d2} for range, @var{d} for
+latest before). See @ref{log options}.
+
+@c <en>@item -h
+@item -h
+@c <en>Only print header. See @ref{log options}.
+Only print header. See @ref{log options}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -N
+@item -N
+@c <en>Do not list tags. See @ref{log options}.
+Do not list tags. See @ref{log options}.
+
+@c <en>@item -R
+@item -R
+@c <en>Only print name of RCS file. See @ref{log options}.
+Only print name of RCS file. See @ref{log options}.
+
+@c <en>@item -r@var{revs}
+@item -r@var{revs}
+@c <en>Only list revisions @var{revs}. See @ref{log options}.
+Only list revisions @var{revs}. See @ref{log options}.
+
+@c <en>@item -s @var{states}
+@item -s @var{states}
+@c <en>Only list revisions with specified states. See @ref{log options}.
+Only list revisions with specified states. See @ref{log options}.
+
+@c <en>@item -t
+@item -t
+@c <en>Only print header and descriptive text. See @ref{log
+@c <en>options}.
+Only print header and descriptive text. See @ref{log
+options}.
+
+@c <en>@item -w@var{logins}
+@item -w@var{logins}
+@c <en>Only list revisions checked in by specified logins. See @ref{log options}.
+Only list revisions checked in by specified logins. See @ref{log options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item login
+@item login
+@c <en>Prompt for password for authenticating server. See
+@c <en>@ref{Password authentication client}.
+Pede por uma senha para o servidor de autenticação. Veja em
+@ref{Cliente de autenticação por senha}.
+
+@c ------------------------------------------------------------
+@c <en>@item logout
+@item logout
+@c <en>Remove stored password for authenticating server. See
+@c <en>@ref{Password authentication client}.
+Remove senhas armazenadas para a autenticação no servidor. Veja em
+@ref{Cliente de autenticação por senha}.
+
+@c ------------------------------------------------------------
+@c <en>@item pserver
+@item pserver
+@c <en>Password authenticated server.
+@c <en>See @ref{Password authentication server}.
+Password authenticated server.
+See @ref{Servidor de autenticação por senha}.
+
+@c ------------------------------------------------------------
+@c <en>@item rannotate [@var{options}] [@var{modules}@dots{}]
+@item rannotate [@var{options}] [@var{modules}@dots{}]
+@c <en>Show last revision where each line was modified. See
+@c <en>@ref{annotate}.
+Show last revision where each line was modified. See
+@ref{annotate}.
+
+@table @code
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Annotate the most recent revision no later than
+@c <en>@var{date}. See @ref{Common options}.
+Annotate the most recent revision no later than
+@var{date}. See @ref{Opções comuns}.
+
+@c <en>@item -F
+@item -F
+@c <en>Force annotation of binary files. (Without this option,
+@c <en>binary files are skipped with a message.)
+Force annotation of binary files. (Without this option,
+binary files are skipped with a message.)
+
+@c <en>@item -f
+@item -f
+@c <en>Use head revision if tag/date not found. See
+@c <en>@ref{Common options}.
+Use head revision if tag/date not found. See
+@ref{Opções comuns}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. @xref{Recursive behavior}.
+Local; run only in current working directory. @xref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{tag}
+@item -r @var{tag}
+@c <en>Annotate revision @var{tag}. See @ref{Common options}.
+Annotate revision @var{tag}. See @ref{Opções comuns}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item rdiff [@var{options}] @var{modules}@dots{}
+@item rdiff [@var{options}] @var{modules}@dots{}
+@c <en>Show differences between releases. See @ref{rdiff}.
+Show differences between releases. See @ref{rdiff}.
+
+@table @code
+@c <en>@item -c
+@item -c
+@c <en>Context diff output format (default). See @ref{rdiff options}.
+Context diff output format (default). See @ref{rdiff options}.
+
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Select revisions based on @var{date}. See @ref{Common options}.
+Select revisions based on @var{date}. See @ref{Opções comuns}.
+
+@c <en>@item -f
+@item -f
+@c <en>Use head revision if tag/date not found. See
+@c <en>@ref{Common options}.
+Use head revision if tag/date not found. See
+@ref{Opções comuns}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{rev}
+@item -r @var{rev}
+@c <en>Select revisions based on @var{rev}. See @ref{Common options}.
+Select revisions based on @var{rev}. See @ref{Opções comuns}.
+
+@c <en>@item -s
+@item -s
+@c <en>Short patch - one liner per file. See @ref{rdiff options}.
+Short patch - one liner per file. See @ref{rdiff options}.
+
+@c <en>@item -t
+@item -t
+@c <en>Top two diffs - last change made to the file. See
+@c <en>@ref{diff options}.
+Top two diffs - last change made to the file. See
+@ref{diff options}.
+
+@c <en>@item -u
+@item -u
+@c <en>Unidiff output format. See @ref{rdiff options}.
+Unidiff output format. See @ref{rdiff options}.
+
+@c <en>@item -V @var{vers}
+@item -V @var{vers}
+@c <en>Use RCS Version @var{vers} for keyword expansion (obsolete). See
+@c <en>@ref{rdiff options}.
+Use RCS Version @var{vers} for keyword expansion (obsolete). See
+@ref{rdiff options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item release [@var{options}] @var{directory}
+@item release [@var{options}] @var{directory}
+@c <en>Indicate that a directory is no longer in use. See
+@c <en>@ref{release}.
+Indicate that a directory is no longer in use. See
+@ref{release}.
+
+@table @code
+@c <en>@item -d
+@item -d
+@c <en>Delete the given directory. See @ref{release options}.
+Delete the given directory. See @ref{release options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item remove [@var{options}] [@var{files}@dots{}]
+@item remove [@var{options}] [@var{files}@dots{}]
+@c <en>Remove an entry from the repository. See @ref{Removing files}.
+Remove an entry from the repository. See @ref{Removendo arquivos}.
+
+@table @code
+@c <en>@item -f
+@item -f
+@c <en>Delete the file before removing it. See @ref{Removing files}.
+Delete the file before removing it. See @ref{Removendo arquivos}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item rlog [@var{options}] [@var{files}@dots{}]
+@item rlog [@var{options}] [@var{files}@dots{}]
+@c <en>Print out history information for modules. See @ref{log}.
+Print out history information for modules. See @ref{log}.
+
+@table @code
+@c <en>@item -b
+@item -b
+@c <en>Only list revisions on the default branch. See @ref{log options}.
+Only list revisions on the default branch. See @ref{log options}.
+
+@c <en>@item -d @var{dates}
+@item -d @var{dates}
+@c <en>Specify dates (@var{d1}<@var{d2} for range, @var{d} for
+@c <en>latest before). See @ref{log options}.
+Specify dates (@var{d1}<@var{d2} for range, @var{d} for
+latest before). See @ref{log options}.
+
+@c <en>@item -h
+@item -h
+@c <en>Only print header. See @ref{log options}.
+Only print header. See @ref{log options}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -N
+@item -N
+@c <en>Do not list tags. See @ref{log options}.
+Do not list tags. See @ref{log options}.
+
+@c <en>@item -R
+@item -R
+@c <en>Only print name of RCS file. See @ref{log options}.
+Only print name of RCS file. See @ref{log options}.
+
+@c <en>@item -r@var{revs}
+@item -r@var{revs}
+@c <en>Only list revisions @var{revs}. See @ref{log options}.
+Only list revisions @var{revs}. See @ref{log options}.
+
+@c <en>@item -s @var{states}
+@item -s @var{states}
+@c <en>Only list revisions with specified states. See @ref{log options}.
+Only list revisions with specified states. See @ref{log options}.
+
+@c <en>@item -t
+@item -t
+@c <en>Only print header and descriptive text. See @ref{log options}.
+Only print header and descriptive text. See @ref{log options}.
+
+@c <en>@item -w@var{logins}
+@item -w@var{logins}
+@c <en>Only list revisions checked in by specified logins. See @ref{log options}.
+Only list revisions checked in by specified logins. See @ref{log options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item rtag [@var{options}] @var{tag} @var{modules}@dots{}
+@item rtag [@var{options}] @var{tag} @var{modules}@dots{}
+@c <en>Add a symbolic tag to a module.
+@c <en>See @ref{Revisions} and @ref{Branching and merging}.
+Add a symbolic tag to a module.
+See @ref{Revisões} and @ref{Ramificando e mesclando}.
+
+@table @code
+@c <en>@item -a
+@item -a
+@c <en>Clear tag from removed files that would not otherwise
+@c <en>be tagged. See @ref{Tagging add/remove}.
+Clear tag from removed files that would not otherwise
+be tagged. See @ref{Etiquetando adicionados/removidos}.
+
+@c <en>@item -b
+@item -b
+@c <en>Create a branch named @var{tag}. See @ref{Branching and merging}.
+Create a branch named @var{tag}. See @ref{Ramificando e mesclando}.
+
+@c <en>@item -B
+@item -B
+@c <en>Used in conjunction with -F or -d, enables movement and deletion of
+@c <en>branch tags. Use with extreme caution.
+Used in conjunction with -F or -d, enables movement and deletion of
+branch tags. Use with extreme caution.
+
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Tag revisions as of @var{date}. See @ref{Tagging by date/tag}.
+Tag revisions as of @var{date}. See @ref{Etiquetando por data/etiqueta}.
+
+@c <en>@item -d
+@item -d
+@c <en>Delete @var{tag}. See @ref{Modifying tags}.
+Delete @var{tag}. See @ref{Modificando etiquetas}.
+
+@c <en>@item -F
+@item -F
+@c <en>Move @var{tag} if it already exists. See @ref{Modifying tags}.
+Move @var{tag} if it already exists. See @ref{Modificando etiquetas}.
+
+@c <en>@item -f
+@item -f
+@c <en>Force a head revision match if tag/date not found.
+@c <en>See @ref{Tagging by date/tag}.
+Force a head revision match if tag/date not found.
+See @ref{Etiquetando por data/etiqueta}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -n
+@item -n
+@c <en>No execution of tag program. See @ref{Common options}.
+No execution of tag program. See @ref{Opções comuns}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{rev}
+@item -r @var{rev}
+@c <en>Tag existing tag @var{rev}. See @ref{Tagging by date/tag}.
+Tag existing tag @var{rev}. See @ref{Etiquetando por data/etiqueta}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item server
+@item server
+@c <en>Rsh server. See @ref{Connecting via rsh}.
+Rsh server. See @ref{Se conectando via rsh}.
+
+@c ------------------------------------------------------------
+@c <en>@item status [@var{options}] @var{files}@dots{}
+@item status [@var{options}] @var{files}@dots{}
+@c <en>Display status information in a working directory. See
+@c <en>@ref{File status}.
+Display status information in a working directory. See
+@ref{Estado de arquivo}.
+
+@table @code
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -v
+@item -v
+@c <en>Include tag information for file. See @ref{Tags}.
+Include tag information for file. See @ref{Etiquetas}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item tag [@var{options}] @var{tag} [@var{files}@dots{}]
+@item tag [@var{options}] @var{tag} [@var{files}@dots{}]
+@c <en>Add a symbolic tag to checked out version of files.
+@c <en>See @ref{Revisions} and @ref{Branching and merging}.
+Add a symbolic tag to checked out version of files.
+See @ref{Revisões} and @ref{Ramificando e mesclando}.
+
+@table @code
+@c <en>@item -b
+@item -b
+@c <en>Create a branch named @var{tag}. See @ref{Branching and merging}.
+Create a branch named @var{tag}. See @ref{Ramificando e mesclando}.
+
+@c <en>@item -c
+@item -c
+@c <en>Check that working files are unmodified. See
+@c <en>@ref{Tagging the working directory}.
+Check that working files are unmodified. See
+@ref{Etiquetando o diretório de trabalho}.
+
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Tag revisions as of @var{date}. See @ref{Tagging by date/tag}.
+Tag revisions as of @var{date}. See @ref{Etiquetando por data/etiqueta}.
+
+@c <en>@item -d
+@item -d
+@c <en>Delete @var{tag}. See @ref{Modifying tags}.
+Delete @var{tag}. See @ref{Modificando etiquetas}.
+
+@c <en>@item -F
+@item -F
+@c <en>Move @var{tag} if it already exists. See @ref{Modifying tags}.
+Move @var{tag} if it already exists. See @ref{Modificando etiquetas}.
+
+@c <en>@item -f
+@item -f
+@c <en>Force a head revision match if tag/date not found.
+@c <en>See @ref{Tagging by date/tag}.
+Force a head revision match if tag/date not found.
+See @ref{Etiquetando por data/etiqueta}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{rev}
+@item -r @var{rev}
+@c <en>Tag existing tag @var{rev}. See @ref{Tagging by date/tag}.
+Tag existing tag @var{rev}. See @ref{Etiquetando por data/etiqueta}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item unedit [@var{options}] [@var{files}@dots{}]
+@item unedit [@var{options}] [@var{files}@dots{}]
+@c <en>Undo an edit command. See @ref{Editing files}.
+Undo an edit command. See @ref{Editando arquivos}.
+
+@table @code
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item update [@var{options}] [@var{files}@dots{}]
+@item update [@var{options}] [@var{files}@dots{}]
+@c <en>Bring work tree in sync with repository. See
+@c <en>@ref{update}.
+Bring work tree in sync with repository. See
+@ref{update}.
+
+@table @code
+@c <en>@item -A
+@item -A
+@c <en>Reset any sticky tags/date/options. See @ref{Sticky
+@c <en>tags} and @ref{Keyword substitution}.
+Reset any sticky tags/date/options. See
+@ref{Etiquetas adesivas} and @ref{Substituição de palavra-chave}.
+
+@c <en>@item -C
+@item -C
+@c <en>Overwrite locally modified files with clean copies from
+@c <en>the repository (the modified file is saved in
+@c <en>@file{.#@var{file}.@var{revision}}, however).
+Overwrite locally modified files with clean copies from
+the repository (the modified file is saved in
+@file{.#@var{file}.@var{revision}}, however).
+
+@c <en>@item -D @var{date}
+@item -D @var{date}
+@c <en>Check out revisions as of @var{date} (is sticky). See
+@c <en>@ref{Common options}.
+Check out revisions as of @var{date} (is sticky). See
+@ref{Opções comuns}.
+
+@c <en>@item -d
+@item -d
+@c <en>Create directories. See @ref{update options}.
+Create directories. See @ref{update options}.
+
+@c <en>@item -f
+@item -f
+@c <en>Use head revision if tag/date not found. See
+@c <en>@ref{Common options}.
+Use head revision if tag/date not found. See
+@ref{Opções comuns}.
+
+@c <en>@item -I @var{ign}
+@item -I @var{ign}
+@c <en>More files to ignore (! to reset). See
+@c <en>@ref{import options}.
+More files to ignore (! to reset). See
+@ref{import options}.
+
+@c Probably want to use rev1/rev2 style like for diff
+@c -r. Here and in on-line help.
+@c <en>@item -j @var{rev}
+@item -j @var{rev}
+@c <en>Merge in changes. See @ref{update options}.
+Merge in changes. See @ref{update options}.
+
+@c <en>@item -k @var{kflag}
+@item -k @var{kflag}
+@c <en>Use @var{kflag} keyword expansion. See
+@c <en>@ref{Substitution modes}.
+Use @var{kflag} keyword expansion. See
+@ref{Modos de substituição}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. @xref{Recursive behavior}.
+Local; run only in current working directory. @xref{Comportamento recursivo}.
+
+@c <en>@item -P
+@item -P
+@c <en>Prune empty directories. See @ref{Moving directories}.
+Prune empty directories. See @ref{Movendo diretórios}.
+
+@c <en>@item -p
+@item -p
+@c <en>Check out files to standard output (avoids
+@c <en>stickiness). See @ref{update options}.
+Check out files to standard output (avoids
+stickiness). See @ref{update options}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+
+@c <en>@item -r @var{tag}
+@item -r @var{tag}
+@c <en>Checkout revision @var{tag} (is sticky). See @ref{Common options}.
+Checkout revision @var{tag} (is sticky). See @ref{Opções comuns}.
+
+@c <en>@item -W @var{spec}
+@item -W @var{spec}
+@c <en>More wrappers. See @ref{import options}.
+More wrappers. See @ref{import options}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item version
+@item version
+@c <en>@cindex version (subcommand)
+@cindex version (subcommand)
+
+@c <en>Display the version of @sc{cvs} being used. If the repository
+@c <en>is remote, display both the client and server versions.
+Display the version of @sc{cvs} being used. If the repository
+is remote, display both the client and server versions.
+
+@c ------------------------------------------------------------
+@c <en>@item watch [on|off|add|remove] [@var{options}] [@var{files}@dots{}]
+@item watch [on|off|add|remove] [@var{options}] [@var{files}@dots{}]
+
+@c <en>on/off: turn on/off read-only checkouts of files. See
+@c <en>@ref{Setting a watch}.
+on/off: turn on/off read-only checkouts of files. See
+@ref{Ajustando um ???watch???}.
+
+@c <en>add/remove: add or remove notification on actions. See
+@c <en>@ref{Getting Notified}.
+add/remove: add or remove notification on actions. See
+@ref{Recebendo Notificações}.
+
+@table @code
+@c <en>@item -a @var{actions}
+@item -a @var{actions}
+@c <en>Specify actions for temporary watch, where
+@c <en>@var{actions} is @code{edit}, @code{unedit},
+@c <en>@code{commit}, @code{all}, or @code{none}. See
+@c <en>@ref{Editing files}.
+Specify actions for temporary watch, where
+@var{actions} is @code{edit}, @code{unedit},
+@code{commit}, @code{all}, or @code{none}. See
+@ref{Editando arquivos}.
+
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+@end table
+
+@c ------------------------------------------------------------
+@c <en>@item watchers [@var{options}] [@var{files}@dots{}]
+@item watchers [@var{options}] [@var{files}@dots{}]
+@c <en>See who is watching a file. See @ref{Watch information}.
+See who is watching a file. See @ref{Informações de ???Watch???}.
+
+@table @code
+@c <en>@item -l
+@item -l
+@c <en>Local; run only in current working directory. See @ref{Recursive behavior}.
+Local; run only in current working directory. See @ref{Comportamento recursivo}.
+
+@c <en>@item -R
+@item -R
+@c <en>Operate recursively (default). @xref{Recursive
+@c <en>behavior}.
+Operate recursively (default). @xref{Comportamento recursivo}.
+@end table
+
+@end table
+
+@c ---------------------------------------------------------------------
+@c <en>@node Administrative files
+@node Arquivos administrativos
+@c <en>@appendix Reference manual for Administrative files
+@appendix Manual de referência para Arquivos administrativos
+@c <en>@cindex Administrative files (reference)
+@cindex Arquivos administrativos (referência)
+@c <en>@cindex Files, reference manual
+@cindex Files, reference manual
+@c <en>@cindex Reference manual (files)
+@cindex Reference manual (files)
+@c <en>@cindex CVSROOT (file)
+@cindex CVSROOT (file)
+
+@c FIXME? Somewhere there needs to be a more "how-to"
+@c guide to writing these. I think the triggers
+@c (commitinfo, loginfo, taginfo, &c) are perhaps a
+@c different case than files like modules. One
+@c particular issue that people sometimes are
+@c (unnecessarily?) worried about is performance, and
+@c the impact of writing in perl or sh or ____.
+@c <en>Inside the repository, in the directory
+@c <en>@file{$CVSROOT/CVSROOT}, there are a number of
+@c <en>supportive files for @sc{cvs}. You can use @sc{cvs} in a limited
+@c <en>fashion without any of them, but if they are set up
+@c <en>properly they can help make life easier. For a
+@c <en>discussion of how to edit them, see @ref{Intro
+@c <en>administrative files}.
+Dentro do repositório, no diretório
+@file{$CVSROOT/CVSROOT}, existem vários arquivos de
+suporte para o @sc{cvs}. Você pode usar o @sc{cvs} de
+uma forma limitada sem se aproveitar deles, mas se eles
+estiverem ajustados corretamente eles podem facilitar
+muito seu trabalho. Para uma discussão sobre como
+editá-los, veja em @ref{Intro aos arquivos administrativos}.
+
+@c <en>The most important of these files is the @file{modules}
+@c <en>file, which defines the modules inside the repository.
+O mais importante destes arquivos é o arquivo
+@file{modules}, que define os módulos dentro do repositório.
+
+@menu
+@c <en>* modules:: Defining modules
+* modules:: Definindo módulos
+@c <en>* Wrappers:: Specify binary-ness based on file name
+* Wrappers:: Specify binary-ness based on file name
+@c <en>* commit files:: The commit support files (commitinfo,
+@c <en> verifymsg, loginfo)
+* Arquivos de ???commit???:: Os arquivos de suporte a commit (commitinfo,
+ verifymsg, loginfo)
+@c <en>* taginfo:: Verifying/Logging tags
+* taginfo:: Verifcando/Registrando etiquetas
+@c <en>* rcsinfo:: Templates for the log messages
+* rcsinfo:: Templates for the log messages
+@c <en>* cvsignore:: Ignoring files via cvsignore
+* cvsignore:: Ignoring files via cvsignore
+@c <en>* checkoutlist:: Adding your own administrative files
+* checkoutlist:: Adding your own administrative files
+@c <en>* history file:: History information
+* arquivo history (histórico):: History information
+@c <en>* Variables:: Various variables are expanded
+* Variables:: Various variables are expanded
+@c <en>* config:: Miscellaneous CVS configuration
+* config:: Miscellaneous CVS configuration
+@end menu
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node modules
+@node modules
+@c <en>@appendixsec The modules file
+@appendixsec O arquivo modules
+@c <en>@cindex Modules (admin file)
+@cindex Modules (arquivo administrativo)
+@c <en>@cindex Defining modules (reference manual)
+@cindex Definindo módulos (manual de referência)
+
+@c <en>The @file{modules} file records your definitions of
+@c <en>names for collections of source code. @sc{cvs} will
+@c <en>use these definitions if you use @sc{cvs} to update the
+@c <en>modules file (use normal commands like @code{add},
+@c <en>@code{commit}, etc).
+O arquivo @file{modules} registra suas definições de
+nomes para coleções de código fonte. @sc{cvs} vai usar
+estas definições se você usar o @sc{cvs} para atualizar
+o arquivo modules (use comandos normais, como @code{add},
+@code{commit}, etc).
+
+@c <en>The @file{modules} file may contain blank lines and
+@c <en>comments (lines beginning with @samp{#}) as well as
+@c <en>module definitions. Long lines can be continued on the
+@c <en>next line by specifying a backslash (@samp{\}) as the
+@c <en>last character on the line.
+The @file{modules} file may contain blank lines and
+comments (lines beginning with @samp{#}) as well as
+module definitions. Long lines can be continued on the
+next line by specifying a backslash (@samp{\}) as the
+last character on the line.
+
+@c <en>There are three basic types of modules: alias modules,
+@c <en>regular modules, and ampersand modules. The difference
+@c <en>between them is the way that they map files in the
+@c <en>repository to files in the working directory. In all
+@c <en>of the following examples, the top-level repository
+@c <en>contains a directory called @file{first-dir}, which
+@c <en>contains two files, @file{file1} and @file{file2}, and a
+@c <en>directory @file{sdir}. @file{first-dir/sdir} contains
+@c <en>a file @file{sfile}.
+There are three basic types of modules: alias modules,
+regular modules, and ampersand modules. The difference
+between them is the way that they map files in the
+repository to files in the working directory. In all
+of the following examples, the top-level repository
+contains a directory called @file{first-dir}, which
+contains two files, @file{file1} and @file{file2}, and a
+directory @file{sdir}. @file{first-dir/sdir} contains
+a file @file{sfile}.
+
+@c FIXME: should test all the examples in this section.
+
+@menu
+@c <en>* Alias modules:: The simplest kind of module
+* Alias modules:: The simplest kind of module
+@c <en>* Regular modules::
+* Regular modules::
+@c <en>* Ampersand modules::
+* Ampersand modules::
+@c <en>* Excluding directories:: Excluding directories from a module
+* Excluding directories:: Excluding directories from a module
+@c <en>* Module options:: Regular and ampersand modules can take options
+* Module options:: Regular and ampersand modules can take options
+@c <en>* Module program options:: How the modules ``program options'' programs
+@c <en> are run.
+* Module program options:: How the modules ``program options'' programs
+ are run.
+@end menu
+
+@c <en>@node Alias modules
+@node Alias modules
+@c <en>@appendixsubsec Alias modules
+@appendixsubsec Alias modules
+@c <en>@cindex Alias modules
+@cindex Alias modules
+@c <en>@cindex -a, in modules file
+@cindex -a, in modules file
+
+@c <en>Alias modules are the simplest kind of module:
+Alias modules are the simplest kind of module:
+
+@table @code
+@c <en>@item @var{mname} -a @var{aliases}@dots{}
+@c <en>This represents the simplest way of defining a module
+@c <en>@var{mname}. The @samp{-a} flags the definition as a
+@c <en>simple alias: @sc{cvs} will treat any use of @var{mname} (as
+@c <en>a command argument) as if the list of names
+@c <en>@var{aliases} had been specified instead.
+@c <en>@var{aliases} may contain either other module names or
+@c <en>paths. When you use paths in aliases, @code{checkout}
+@c <en>creates all intermediate directories in the working
+@c <en>directory, just as if the path had been specified
+@c <en>explicitly in the @sc{cvs} arguments.
+@item @var{mname} -a @var{aliases}@dots{}
+This represents the simplest way of defining a module
+@var{mname}. The @samp{-a} flags the definition as a
+simple alias: @sc{cvs} will treat any use of @var{mname} (as
+a command argument) as if the list of names
+@var{aliases} had been specified instead.
+@var{aliases} may contain either other module names or
+paths. When you use paths in aliases, @code{checkout}
+creates all intermediate directories in the working
+directory, just as if the path had been specified
+explicitly in the @sc{cvs} arguments.
+@end table
+
+@c <en>For example, if the modules file contains:
+For example, if the modules file contains:
+
+@example
+amodule -a first-dir
+@end example
+
+@noindent
+@c <en>then the following two commands are equivalent:
+then the following two commands are equivalent:
+
+@example
+$ cvs co amodule
+$ cvs co first-dir
+@end example
+
+@noindent
+@c <en>and they each would provide output such as:
+and they each would provide output such as:
+
+@example
+cvs checkout: Updating first-dir
+U first-dir/file1
+U first-dir/file2
+cvs checkout: Updating first-dir/sdir
+U first-dir/sdir/sfile
+@end example
+
+@c <en>@node Regular modules
+@node Regular modules
+@c <en>@appendixsubsec Regular modules
+@appendixsubsec Regular modules
+@c <en>@cindex Regular modules
+@cindex Regular modules
+
+@table @code
+@c <en>@item @var{mname} [ options ] @var{dir} [ @var{files}@dots{} ]
+@c <en>In the simplest case, this form of module definition
+@c <en>reduces to @samp{@var{mname} @var{dir}}. This defines
+@c <en>all the files in directory @var{dir} as module mname.
+@c <en>@var{dir} is a relative path (from @code{$CVSROOT}) to a
+@c <en>directory of source in the source repository. In this
+@c <en>case, on checkout, a single directory called
+@c <en>@var{mname} is created as a working directory; no
+@c <en>intermediate directory levels are used by default, even
+@c <en>if @var{dir} was a path involving several directory
+@c <en>levels.
+@item @var{mname} [ options ] @var{dir} [ @var{files}@dots{} ]
+In the simplest case, this form of module definition
+reduces to @samp{@var{mname} @var{dir}}. This defines
+all the files in directory @var{dir} as module mname.
+@var{dir} is a relative path (from @code{$CVSROOT}) to a
+directory of source in the source repository. In this
+case, on checkout, a single directory called
+@var{mname} is created as a working directory; no
+intermediate directory levels are used by default, even
+if @var{dir} was a path involving several directory
+levels.
+@end table
+
+@c <en>For example, if a module is defined by:
+For example, if a module is defined by:
+
+@example
+regmodule first-dir
+@end example
+
+@noindent
+@c <en>then regmodule will contain the files from first-dir:
+then regmodule will contain the files from first-dir:
+
+@example
+$ cvs co regmodule
+cvs checkout: Updating regmodule
+U regmodule/file1
+U regmodule/file2
+cvs checkout: Updating regmodule/sdir
+U regmodule/sdir/sfile
+$
+@end example
+
+@c <en>By explicitly specifying files in the module definition
+@c <en>after @var{dir}, you can select particular files from
+@c <en>directory @var{dir}. Here is
+@c <en>an example:
+By explicitly specifying files in the module definition
+after @var{dir}, you can select particular files from
+directory @var{dir}. Here is
+an example:
+
+@example
+regfiles first-dir/sdir sfile
+@end example
+
+@noindent
+@c <en>With this definition, getting the regfiles module
+@c <en>will create a single working directory
+@c <en>@file{regfiles} containing the file listed, which
+@c <en>comes from a directory deeper
+@c <en>in the @sc{cvs} source repository:
+With this definition, getting the regfiles module
+will create a single working directory
+@file{regfiles} containing the file listed, which
+comes from a directory deeper
+in the @sc{cvs} source repository:
+
+@example
+$ cvs co regfiles
+U regfiles/sfile
+$
+@end example
+
+@c <en>@node Ampersand modules
+@node Ampersand modules
+@c <en>@appendixsubsec Ampersand modules
+@appendixsubsec Ampersand modules
+@c <en>@cindex Ampersand modules
+@cindex Ampersand modules
+@c <en>@cindex &, in modules file
+@cindex &, in modules file
+
+@c <en>A module definition can refer to other modules by
+@c <en>including @samp{&@var{module}} in its definition.
+A module definition can refer to other modules by
+including @samp{&@var{module}} in its definition.
+@example
+@var{mname} [ options ] @var{&module}@dots{}
+@end example
+
+@c <en>Then getting the module creates a subdirectory for each such
+@c <en>module, in the directory containing the module. For
+@c <en>example, if modules contains
+Then getting the module creates a subdirectory for each such
+module, in the directory containing the module. For
+example, if modules contains
+
+@example
+ampermod &first-dir
+@end example
+
+@noindent
+@c <en>then a checkout will create an @code{ampermod} directory
+@c <en>which contains a directory called @code{first-dir},
+@c <en>which in turns contains all the directories and files
+@c <en>which live there. For example, the command
+then a checkout will create an @code{ampermod} directory
+which contains a directory called @code{first-dir},
+which in turns contains all the directories and files
+which live there. For example, the command
+
+@example
+$ cvs co ampermod
+@end example
+
+@noindent
+@c <en>will create the following files:
+will create the following files:
+
+@example
+ampermod/first-dir/file1
+ampermod/first-dir/file2
+ampermod/first-dir/sdir/sfile
+@end example
+
+@c <en>There is one quirk/bug: the messages that @sc{cvs}
+@c <en>prints omit the @file{ampermod}, and thus do not
+@c <en>correctly display the location to which it is checking
+@c <en>out the files:
+There is one quirk/bug: the messages that @sc{cvs}
+prints omit the @file{ampermod}, and thus do not
+correctly display the location to which it is checking
+out the files:
+
+@example
+$ cvs co ampermod
+cvs checkout: Updating first-dir
+U first-dir/file1
+U first-dir/file2
+cvs checkout: Updating first-dir/sdir
+U first-dir/sdir/sfile
+$
+@end example
+
+@c <en>Do not rely on this buggy behavior; it may get fixed in
+@c <en>a future release of @sc{cvs}.
+Do not rely on this buggy behavior; it may get fixed in
+a future release of @sc{cvs}.
+
+@c FIXCVS: What happens if regular and & modules are
+@c combined, as in "ampermodule first-dir &second-dir"?
+@c When I tried it, it seemed to just ignore the
+@c "first-dir". I think perhaps it should be an error
+@c (but this needs further investigation).
+@c In addition to discussing what each one does, we
+@c should put in a few words about why you would use one or
+@c the other in various situations.
+
+@c <en>@node Excluding directories
+@node Excluding directories
+@c <en>@appendixsubsec Excluding directories
+@appendixsubsec Excluding directories
+@c <en>@cindex Excluding directories, in modules file
+@cindex Excluding directories, in modules file
+@c <en>@cindex !, in modules file
+@cindex !, in modules file
+
+@c <en>An alias module may exclude particular directories from
+@c <en>other modules by using an exclamation mark (@samp{!})
+@c <en>before the name of each directory to be excluded.
+An alias module may exclude particular directories from
+other modules by using an exclamation mark (@samp{!})
+before the name of each directory to be excluded.
+
+@c <en>For example, if the modules file contains:
+For example, if the modules file contains:
+
+@example
+exmodule -a !first-dir/sdir first-dir
+@end example
+
+@noindent
+@c <en>then checking out the module @samp{exmodule} will check
+@c <en>out everything in @samp{first-dir} except any files in
+@c <en>the subdirectory @samp{first-dir/sdir}.
+then checking out the module @samp{exmodule} will check
+out everything in @samp{first-dir} except any files in
+the subdirectory @samp{first-dir/sdir}.
+@c Note that the "!first-dir/sdir" sometimes must be listed
+@c before "first-dir". That seems like a probable bug, in which
+@c case perhaps it should be fixed (to allow either
+@c order) rather than documented. See modules4 in testsuite.
+
+@c <en>@node Module options
+@node Module options
+@c <en>@appendixsubsec Module options
+@appendixsubsec Module options
+@c <en>@cindex Options, in modules file
+@cindex Options, in modules file
+
+@c <en>Either regular modules or ampersand modules can contain
+@c <en>options, which supply additional information concerning
+@c <en>the module.
+Either regular modules or ampersand modules can contain
+options, which supply additional information concerning
+the module.
+
+@table @code
+@c <en>@cindex -d, in modules file
+@cindex -d, in modules file
+@c <en>@item -d @var{name}
+@item -d @var{name}
+@c <en>Name the working directory something other than the
+@c <en>module name.
+Name the working directory something other than the
+module name.
+@c FIXME: Needs a bunch of examples, analogous to the
+@c examples for alias, regular, and ampersand modules
+@c which show where the files go without -d.
+
+@c <en>@cindex Export program
+@cindex Export program
+@c <en>@cindex -e, in modules file
+@cindex -e, in modules file
+@c <en>@item -e @var{prog}
+@item -e @var{prog}
+@c <en>Specify a program @var{prog} to run whenever files in a
+@c <en>module are exported. @var{prog} runs with a single
+@c <en>argument, the module name.
+Specify a program @var{prog} to run whenever files in a
+module are exported. @var{prog} runs with a single
+argument, the module name.
+@c FIXME: Is it run on server? client?
+
+@c <en>@cindex Checkout program
+@cindex Checkout program
+@c <en>@cindex -o, in modules file
+@cindex -o, in modules file
+@c <en>@item -o @var{prog}
+@item -o @var{prog}
+@c <en>Specify a program @var{prog} to run whenever files in a
+@c <en>module are checked out. @var{prog} runs with a single
+@c <en>argument, the module name. See @ref{Module program options} for
+@c <en>information on how @var{prog} is called.
+Specify a program @var{prog} to run whenever files in a
+module are checked out. @var{prog} runs with a single
+argument, the module name. See @ref{Module program options} for
+information on how @var{prog} is called.
+@c FIXME: Is it run on server? client?
+
+@c <en>@cindex Status of a module
+@cindex Status of a module
+@c <en>@cindex Module status
+@cindex Module status
+@c <en>@cindex -s, in modules file
+@cindex -s, in modules file
+@c <en>@item -s @var{status}
+@item -s @var{status}
+@c <en>Assign a status to the module. When the module file is
+@c <en>printed with @samp{cvs checkout -s} the modules are
+@c <en>sorted according to primarily module status, and
+@c <en>secondarily according to the module name. This option
+@c <en>has no other meaning. You can use this option for
+@c <en>several things besides status: for instance, list the
+@c <en>person that is responsible for this module.
+Assign a status to the module. When the module file is
+printed with @samp{cvs checkout -s} the modules are
+sorted according to primarily module status, and
+secondarily according to the module name. This option
+has no other meaning. You can use this option for
+several things besides status: for instance, list the
+person that is responsible for this module.
+
+@c <en>@cindex Tag program
+@cindex Tag program
+@c <en>@cindex -t, in modules file
+@cindex -t, in modules file
+@c <en>@item -t @var{prog}
+@item -t @var{prog}
+@c <en>Specify a program @var{prog} to run whenever files in a
+@c <en>module are tagged with @code{rtag}. @var{prog} runs
+@c <en>with two arguments: the module name and the symbolic
+@c <en>tag specified to @code{rtag}. It is not run
+@c <en>when @code{tag} is executed. Generally you will find
+@c <en>that the @file{taginfo} file is a better solution(@pxref{taginfo}).
+Specify a program @var{prog} to run whenever files in a
+module are tagged with @code{rtag}. @var{prog} runs
+with two arguments: the module name and the symbolic
+tag specified to @code{rtag}. It is not run
+when @code{tag} is executed. Generally you will find
+that the @file{taginfo} file is a better solution(@pxref{taginfo}).
+@c FIXME: Is it run on server? client?
+@c Problems with -t include:
+@c * It is run after the tag not before
+@c * It doesn't get passed all the information that
+@c taginfo does ("mov", &c).
+@c * It only is run for rtag, not tag.
+@end table
+
+@c <en>You should also see @pxref{Module program options} about how the
+@c <en>``program options'' programs are run.
+You should also see @pxref{Module program options} about how the
+``program options'' programs are run.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@c <en>@node Module program options
+@node Module program options
+@c <en>@appendixsubsec How the modules file ``program options'' programs are run
+@appendixsubsec How the modules file ``program options'' programs are run
+@c <en>@cindex Modules file program options
+@cindex Modules file program options
+@c <en>@cindex -t, in modules file
+@cindex -t, in modules file
+@c <en>@cindex -o, in modules file
+@cindex -o, in modules file
+@c <en>@cindex -e, in modules file
+@cindex -e, in modules file
+
+@noindent
+@c <en>For checkout, rtag, and export, the program is server-based, and as such the
+@c <en>following applies:-
+For checkout, rtag, and export, the program is server-based, and as such the
+following applies:-
+
+@c <en>If using remote access methods (pserver, ext, etc.),
+@c <en>@sc{cvs} will execute this program on the server from a temporary
+@c <en>directory. The path is searched for this program.
+If using remote access methods (pserver, ext, etc.),
+@sc{cvs} will execute this program on the server from a temporary
+directory. The path is searched for this program.
+
+@c <en>If using ``local access'' (on a local or remote NFS file system, i.e.
+@c <en>repository set just to a path),
+@c <en>the program will be executed from the newly checked-out tree, if
+@c <en>found there, or alternatively searched for in the path if not.
+If using ``local access'' (on a local or remote NFS file system, i.e.
+repository set just to a path),
+the program will be executed from the newly checked-out tree, if
+found there, or alternatively searched for in the path if not.
+
+@c <en>The programs are all run after the operation has effectively
+@c <en>completed.
+The programs are all run after the operation has effectively
+completed.
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Wrappers
+@appendixsec The cvswrappers file
+@cindex cvswrappers (admin file)
+@cindex CVSWRAPPERS, environment variable
+@cindex Wrappers
+
+@c FIXME: need some better way of separating this out
+@c by functionality. -m is
+@c one feature, and -k is a another. And this discussion
+@c should be better motivated (e.g. start with the
+@c problems, then explain how the feature solves it).
+
+Wrappers refers to a @sc{cvs} feature which lets you
+control certain settings based on the name of the file
+which is being operated on. The settings are @samp{-k}
+for binary files, and @samp{-m} for nonmergeable text
+files.
+
+The @samp{-m} option
+specifies the merge methodology that should be used when
+a non-binary file is updated. @code{MERGE} means the usual
+@sc{cvs} behavior: try to merge the files. @code{COPY}
+means that @code{cvs update} will refuse to merge
+files, as it also does for files specified as binary
+with @samp{-kb} (but if the file is specified as
+binary, there is no need to specify @samp{-m 'COPY'}).
+@sc{cvs} will provide the user with the
+two versions of the files, and require the user using
+mechanisms outside @sc{cvs}, to insert any necessary
+changes.
+
+@c <en>@strong{WARNING: do not use @code{COPY} with
+@c <en>@sc{cvs} 1.9 or earlier - such versions of @sc{cvs} will
+@c <en>copy one version of your file over the other, wiping
+@c <en>out the previous contents.}
+@strong{WARNING: do not use @code{COPY} with
+@sc{cvs} 1.9 or earlier - such versions of @sc{cvs} will
+copy one version of your file over the other, wiping
+out the previous contents.}
+@c Ordinarily we don't document the behavior of old
+@c versions. But this one is so dangerous, I think we
+@c must. I almost renamed it to -m 'NOMERGE' so we
+@c could say "never use -m 'COPY'".
+@c <en>The @samp{-m} wrapper option only affects behavior when
+@c <en>merging is done on update; it does not affect how files
+@c <en>are stored. See @ref{Binary files}, for more on
+@c <en>binary files.
+The @samp{-m} wrapper option only affects behavior when
+merging is done on update; it does not affect how files
+are stored. See @ref{Arquivos binários}, for more on
+binary files.
+
+The basic format of the file @file{cvswrappers} is:
+
+@c FIXME: @example is all wrong for this. Use @deffn or
+@c something more sensible.
+@example
+wildcard [option value][option value]...
+
+where option is one of
+-m update methodology value: MERGE or COPY
+-k keyword expansion value: expansion mode
+
+and value is a single-quote delimited value.
+@end example
+
+@ignore
+@example
+*.nib -f 'unwrap %s' -t 'wrap %s %s' -m 'COPY'
+*.c -t 'indent %s %s'
+@end example
+@c When does the filter need to be an absolute pathname
+@c and when will something like the above work? I
+@c suspect it relates to the PATH of the server (which
+@c in turn depends on all kinds of stuff, e.g. inetd
+@c for pserver). I'm not sure whether/where to discuss
+@c this.
+@c FIXME: What do the %s's stand for?
+
+@noindent
+The above example of a @file{cvswrappers} file
+states that all files/directories that end with a @code{.nib}
+should be filtered with the @file{wrap} program before
+checking the file into the repository. The file should
+be filtered though the @file{unwrap} program when the
+file is checked out of the repository. The
+@file{cvswrappers} file also states that a @code{COPY}
+methodology should be used when updating the files in
+the repository (that is, no merging should be performed).
+
+@c What pitfalls arise when using indent this way? Is
+@c it a winning thing to do? Would be nice to at least
+@c hint at those issues; we want our examples to tell
+@c how to solve problems, not just to say that cvs can
+@c do certain things.
+The last example line says that all files that end with
+@code{.c} should be filtered with @file{indent}
+before being checked into the repository. Unlike the previous
+example, no filtering of the @code{.c} file is done when
+it is checked out of the repository.
+@noindent
+The @code{-t} filter is called with two arguments,
+the first is the name of the file/directory to filter
+and the second is the pathname to where the resulting
+filtered file should be placed.
+
+@noindent
+The @code{-f} filter is called with one argument,
+which is the name of the file to filter from. The end
+result of this filter will be a file in the users directory
+that they can work on as they normally would.
+
+Note that the @samp{-t}/@samp{-f} features do not
+conveniently handle one portion of @sc{cvs}'s operation:
+determining when files are modified. @sc{cvs} will still
+want a file (or directory) to exist, and it will use
+its modification time to determine whether a file is
+modified. If @sc{cvs} erroneously thinks a file is
+unmodified (for example, a directory is unchanged but
+one of the files within it is changed), you can force
+it to check in the file anyway by specifying the
+@samp{-f} option to @code{cvs commit} (@pxref{commit
+options}).
+@c This is, of course, a serious design flaw in -t/-f.
+@c Probably the whole functionality needs to be
+@c redesigned (starting from requirements) to fix this.
+@end ignore
+
+@c FIXME: We don't document -W or point to where it is
+@c documented. Or .cvswrappers.
+For example, the following command imports a
+directory, treating files whose name ends in
+@samp{.exe} as binary:
+
+@example
+cvs import -I ! -W "*.exe -k 'b'" first-dir vendortag reltag
+@end example
+
+@c Another good example, would be storing files
+@c (e.g. binary files) compressed in the repository.
+@c ::::::::::::::::::
+@c cvswrappers
+@c ::::::::::::::::::
+@c *.t12 -m 'COPY'
+@c *.t[0-9][0-9] -f 'gunzipcp %s' -t 'gzipcp %s %s' -m 'COPY'
+@c
+@c ::::::::::::::::::
+@c gunzipcp
+@c ::::::::::::::::::
+@c :
+@c [ -f $1 ] || exit 1
+@c zcat $1 > /tmp/.#$1.$$
+@c mv /tmp/.#$1.$$ $1
+@c
+@c ::::::::::::::::::
+@c gzipcp
+@c ::::::::::::::::::
+@c :
+@c DIRNAME=`echo $1 | sed -e "s|/.*/||g"`
+@c if [ ! -d $DIRNAME ] ; then
+@c DIRNAME=`echo $1 | sed -e "s|.*/||g"`
+@c fi
+@c gzip -c $DIRNAME > $2
+@c One catch--"cvs diff" will not invoke the wrappers
+@c (probably a CVS bug, although I haven't thought it out).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node commit files
+@node Arquivos de ???commit???
+@c <en>@appendixsec The commit support files
+@appendixsec The commit support files
+@c <en>@cindex Committing, administrative support files
+@cindex Committing, administrative support files
+
+The @samp{-i} flag in the @file{modules} file can be
+used to run a certain program whenever files are
+committed (@pxref{modules}). The files described in
+this section provide other, more flexible, ways to run
+programs whenever something is committed.
+
+There are three kind of programs that can be run on
+commit. They are specified in files in the repository,
+as described below. The following table summarizes the
+file names and the purpose of the corresponding
+programs.
+
+@table @file
+@item commitinfo
+The program is responsible for checking that the commit
+is allowed. If it exits with a non-zero exit status
+the commit will be aborted.
+
+@item verifymsg
+The specified program is used to evaluate the log message,
+and possibly verify that it contains all required
+fields. This is most useful in combination with the
+@file{rcsinfo} file, which can hold a log message
+template (@pxref{rcsinfo}).
+
+@item loginfo
+The specified program is called when the commit is
+complete. It receives the log message and some
+additional information and can store the log message in
+a file, or mail it to appropriate persons, or maybe
+post it to a local newsgroup, or@dots{} Your
+imagination is the limit!
+@end table
+
+@menu
+* syntax:: The common syntax
+* commitinfo:: Pre-commit checking
+* verifymsg:: How are log messages evaluated?
+* loginfo:: Where should log messages be sent?
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node syntax
+@appendixsubsec The common syntax
+@cindex Info files (syntax)
+@cindex Syntax of info files
+@cindex Common syntax of info files
+
+@c FIXME: having this so totally separate from the
+@c Variables node is rather bogus.
+
+The administrative files such as @file{commitinfo},
+@file{loginfo}, @file{rcsinfo}, @file{verifymsg}, etc.,
+all have a common format. The purpose of the files are
+described later on. The common syntax is described
+here.
+
+@cindex Regular expression syntax
+Each line contains the following:
+@itemize @bullet
+@item
+@c Say anything about DEFAULT and ALL? Right now we
+@c leave that to the description of each file (and in fact
+@c the practice is inconsistent which is really annoying).
+A regular expression. This is a basic regular
+expression in the syntax used by GNU emacs.
+@c FIXME: What we probably should be saying is "POSIX Basic
+@c Regular Expression with the following extensions (`\('
+@c `\|' '+' etc)"
+@c rather than define it with reference to emacs.
+@c The reference to emacs is not strictly speaking
+@c true, as we don't support \=, \s, or \S. Also it isn't
+@c clear we should document and/or promise to continue to
+@c support all the obscure emacs extensions like \<.
+@c Also need to better cite (or include) full
+@c documentation for the syntax.
+@c Also see comment in configure.in about what happens to the
+@c syntax if we pick up a system-supplied regexp matcher.
+
+@item
+A whitespace separator---one or more spaces and/or tabs.
+
+@item
+A file name or command-line template.
+@end itemize
+
+@noindent
+Blank lines are ignored. Lines that start with the
+character @samp{#} are treated as comments. Long lines
+unfortunately can @emph{not} be broken in two parts in
+any way.
+
+The first regular expression that matches the current
+directory name in the repository is used. The rest of the line
+is used as a file name or command-line as appropriate.
+
+@c FIXME: need an example. In particular, show what
+@c the regular expression is matched against (one
+@c ordinarily clueful person got confused about whether it
+@c includes the filename--"directory name" above should be
+@c unambiguous but there is nothing like an example to
+@c confirm people's understanding of this sort of thing).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node commitinfo
+@appendixsubsec Commitinfo
+@cindex @file{commitinfo}
+@cindex Commits, precommit verification of
+@cindex Precommit checking
+
+The @file{commitinfo} file defines programs to execute
+whenever @samp{cvs commit} is about to execute. These
+programs are used for pre-commit checking to verify
+that the modified, added and removed files are really
+ready to be committed. This could be used, for
+instance, to verify that the changed files conform to
+to your site's standards for coding practice.
+
+As mentioned earlier, each line in the
+@file{commitinfo} file consists of a regular expression
+and a command-line template. The template can include
+a program name and any number of arguments you wish to
+supply to it. The full path to the current source
+repository is appended to the template, followed by the
+file names of any files involved in the commit (added,
+removed, and modified files).
+
+@cindex Exit status, of commitinfo
+The first line with a regular expression matching the
+directory within the repository will be used. If the
+command returns a non-zero exit status the commit will
+be aborted.
+@c FIXME: need example(s) of what "directory within the
+@c repository" means.
+
+@cindex DEFAULT in commitinfo
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+@cindex ALL in commitinfo
+All occurrences of the name @samp{ALL} appearing as a
+regular expression are used in addition to the first
+matching regular expression or the name @samp{DEFAULT}.
+
+@c <en>@cindex @file{commitinfo}, working directory
+@cindex @file{commitinfo}, working directory
+@c <en>@cindex @file{commitinfo}, command environment
+@cindex @file{commitinfo}, command environment
+@c <en>The command will be run in the root of the workspace
+@c <en>containing the new versions of any files the user would like
+@c <en>to modify (commit), @emph{or in a copy of the workspace on
+@c <en>the server (@pxref{Remote repositories})}. If a file is
+@c <en>being removed, there will be no copy of the file under the
+@c <en>current directory. If a file is being added, there will be
+@c <en>no corresponding archive file in the repository unless the
+@c <en>file is being resurrected.
+The command will be run in the root of the workspace
+containing the new versions of any files the user would like
+to modify (commit), @emph{or in a copy of the workspace on
+the server (@pxref{Repositórios remotos})}. If a file is
+being removed, there will be no copy of the file under the
+current directory. If a file is being added, there will be
+no corresponding archive file in the repository unless the
+file is being resurrected.
+
+Note that both the repository directory and the corresponding
+Attic (@pxref{Attic}) directory may need to be checked to
+locate the archive file corresponding to any given file being
+committed. Much of the information about the specific commit
+request being made, including the destination branch, commit
+message, and command line options specified, is not available
+to the command.
+
+@c FIXME: should discuss using commitinfo to control
+@c who has checkin access to what (e.g. Joe can check into
+@c directories a, b, and c, and Mary can check into
+@c directories b, c, and d--note this case cannot be
+@c conveniently handled with unix groups). Of course,
+@c adding a new set of features to CVS might be a more
+@c natural way to fix this problem than telling people to
+@c use commitinfo.
+@c FIXME: Should make some reference, especially in
+@c the context of controlling who has access, to the fact
+@c that commitinfo can be circumvented. Perhaps
+@c mention SETXID (but has it been carefully examined
+@c for holes?). This fits in with the discussion of
+@c general CVS security in "Password authentication
+@c security" (the bit which is not pserver-specific).
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node verifymsg
+@appendixsubsec Verifying log messages
+@cindex @file{verifymsg} (admin file)
+@cindex Log message, verifying
+
+Once you have entered a log message, you can evaluate
+that message to check for specific content, such as
+a bug ID. Use the @file{verifymsg} file to
+specify a program that is used to verify the log message.
+This program could be a simple script that checks
+that the entered message contains the required fields.
+
+The @file{verifymsg} file is often most useful together
+with the @file{rcsinfo} file, which can be used to
+specify a log message template.
+
+Each line in the @file{verifymsg} file consists of a
+regular expression and a command-line template. The
+template must include a program name, and can include
+any number of arguments. The full path to the current
+log message template file is appended to the template.
+
+One thing that should be noted is that the @samp{ALL}
+keyword is not supported. If more than one matching
+line is found, the first one is used. This can be
+useful for specifying a default verification script in a
+directory, and then overriding it in a subdirectory.
+
+@cindex DEFAULT in @file{verifymsg}
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+@cindex Exit status, of @file{verifymsg}
+If the verification script exits with a non-zero exit status,
+the commit is aborted.
+
+@cindex @file{verifymsg}, changing the log message
+In the default configuration, CVS allows the
+verification script to change the log message. This is
+controlled via the RereadLogAfterVerify CVSROOT/config
+option.
+
+When @samp{RereadLogAfterVerify=always} or
+@samp{RereadLogAfterVerify=stat}, the log message will
+either always be reread after the verification script
+is run or reread only if the log message file status
+has changed.
+
+@xref{config}, for more on CVSROOT/config options.
+
+@c <en>It is NOT a good idea for a @file{verifymsg} script to
+@c <en>interact directly with the user in the various
+@c <en>client/server methods. For the @code{pserver} method,
+@c <en>there is no protocol support for communicating between
+@c <en>@file{verifymsg} and the client on the remote end. For the
+@c <en>@code{ext} and @code{server} methods, it is possible
+@c <en>for CVS to become confused by the characters going
+@c <en>along the same channel as the CVS protocol
+@c <en>messages. See @ref{Remote repositories}, for more
+@c <en>information on client/server setups. In addition, at the time
+@c <en>the @file{verifymsg} script runs, the CVS
+@c <en>server has locks in place in the repository. If control is
+@c <en>returned to the user here then other users may be stuck waiting
+@c <en>for access to the repository.
+It is NOT a good idea for a @file{verifymsg} script to
+interact directly with the user in the various
+client/server methods. For the @code{pserver} method,
+there is no protocol support for communicating between
+@file{verifymsg} and the client on the remote end. For the
+@code{ext} and @code{server} methods, it is possible
+for CVS to become confused by the characters going
+along the same channel as the CVS protocol
+messages. See @ref{Repositórios remotos}, for more
+information on client/server setups. In addition, at the time
+the @file{verifymsg} script runs, the CVS
+server has locks in place in the repository. If control is
+returned to the user here then other users may be stuck waiting
+for access to the repository.
+
+This option can be useful if you find yourself using an
+rcstemplate that needs to be modified to remove empty
+elements or to fill in default values. It can also be
+useful if the rcstemplate has changed in the repository
+and the CVS/Template was not updated, but is able to be
+adapted to the new format by the verification script
+that is run by @file{verifymsg}.
+
+An example of an update might be to change all
+occurrences of 'BugId:' to be 'DefectId:' (which can be
+useful if the rcstemplate has recently been changed and
+there are still checked-out user trees with cached
+copies in the CVS/Template file of the older version).
+
+Another example of an update might be to delete a line
+that contains 'BugID: none' from the log message after
+validation of that value as being allowed is made.
+
+The following is a little silly example of a
+@file{verifymsg} file, together with the corresponding
+@file{rcsinfo} file, the log message template and an
+verification script. We begin with the log message template.
+We want to always record a bug-id number on the first
+line of the log message. The rest of log message is
+free text. The following template is found in the file
+@file{/usr/cvssupport/tc.template}.
+
+@example
+BugId:
+@end example
+
+The script @file{/usr/cvssupport/bugid.verify} is used to
+evaluate the log message.
+
+@example
+#!/bin/sh
+#
+# bugid.verify filename
+#
+# Verify that the log message contains a valid bugid
+# on the first line.
+#
+if sed 1q < $1 | grep '^BugId:[ ]*[0-9][0-9]*$' > /dev/null; then
+ exit 0
+elif sed 1q < $1 | grep '^BugId:[ ]*none$' > /dev/null; then
+ # It is okay to allow commits with 'BugId: none',
+ # but do not put that text into the real log message.
+ grep -v '^BugId:[ ]*none$' > $1.rewrite
+ mv $1.rewrite $1
+ exit 0
+else
+ echo "No BugId found."
+ exit 1
+fi
+@end example
+
+The @file{verifymsg} file contains this line:
+
+@example
+^tc /usr/cvssupport/bugid.verify
+@end example
+
+The @file{rcsinfo} file contains this line:
+
+@example
+^tc /usr/cvssupport/tc.template
+@end example
+
+The @file{config} file contains this line:
+
+@example
+RereadLogAfterVerify=always
+@end example
+
+
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node loginfo
+@appendixsubsec Loginfo
+@cindex loginfo (admin file)
+@cindex Storing log messages
+@cindex Mailing log messages
+@cindex Distributing log messages
+@cindex Log messages
+
+@c "cvs commit" is not quite right. What we
+@c mean is "when the repository gets changed" which
+@c also includes "cvs import" and "cvs add" on a directory.
+The @file{loginfo} file is used to control where
+@samp{cvs commit} log information is sent. The first
+entry on a line is a regular expression which is tested
+against the directory that the change is being made to,
+relative to the @code{$CVSROOT}. If a match is found, then
+the remainder of the line is a filter program that
+should expect log information on its standard input.
+
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+All occurrences of the name @samp{ALL} appearing as a
+regular expression are used in addition to the first
+matching regular expression or @samp{DEFAULT}.
+
+The first matching regular expression is used.
+
+@xref{Arquivos de ???commit???}, for a description of the syntax of
+the @file{loginfo} file.
+
+The user may specify a format string as
+part of the filter. The string is composed of a
+@samp{%} followed by a space, or followed by a single
+format character, or followed by a set of format
+characters surrounded by @samp{@{} and @samp{@}} as
+separators. The format characters are:
+
+@table @t
+@item s
+file name
+@item V
+old version number (pre-checkin)
+@item v
+new version number (post-checkin)
+@end table
+
+All other characters that appear in a format string
+expand to an empty field (commas separating fields are
+still provided).
+
+For example, some valid format strings are @samp{%},
+@samp{%s}, @samp{%@{s@}}, and @samp{%@{sVv@}}.
+
+The output will be a space separated string of tokens enclosed in
+quotation marks (@t{"}).
+Any embedded dollar signs (@t{$}), backticks (@t{`}),
+backslashes (@t{\}), or quotation marks will be preceded
+by a backslash (this allows the shell to correctly parse it
+as a single string, regardless of the characters it contains).
+For backwards compatibility, the first
+token will be the repository subdirectory. The rest of the
+tokens will be comma-delimited lists of the information
+requested in the format string. For example, if
+@samp{/u/src/master/yoyodyne/tc} is the repository, @samp{%@{sVv@}}
+is the format string, and three files (@t{ChangeLog},
+@t{Makefile}, @t{foo.c}) were modified, the output
+might be:
+
+@example
+"yoyodyne/tc ChangeLog,1.1,1.2 Makefile,1.3,1.4 foo.c,1.12,1.13"
+@end example
+
+As another example, @samp{%@{@}} means that only the
+name of the repository will be generated.
+
+Note: when @sc{cvs} is accessing a remote repository,
+@file{loginfo} will be run on the @emph{remote}
+(i.e., server) side, not the client side (@pxref{Repositórios remotos}).
+
+@menu
+* loginfo example:: Loginfo example
+* Keeping a checked out copy:: Updating a tree on every checkin
+@end menu
+
+@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+@node loginfo example
+@appendixsubsubsec Loginfo example
+
+The following @file{loginfo} file, together with the
+tiny shell-script below, appends all log messages
+to the file @file{$CVSROOT/CVSROOT/commitlog},
+and any commits to the administrative files (inside
+the @file{CVSROOT} directory) are also logged in
+@file{/usr/adm/cvsroot-log}.
+Commits to the @file{prog1} directory are mailed to @t{ceder}.
+
+@c FIXME: is it a CVS feature or bug that only the
+@c first matching line is used? It is documented
+@c above, but is it useful? For example, if we wanted
+@c to run both "cvs-log" and "Mail" for the CVSROOT
+@c directory, it is kind of awkward if
+@c only the first matching line is used.
+@example
+ALL /usr/local/bin/cvs-log $CVSROOT/CVSROOT/commitlog $USER
+^CVSROOT /usr/local/bin/cvs-log /usr/adm/cvsroot-log
+^prog1 Mail -s %s ceder
+@end example
+
+The shell-script @file{/usr/local/bin/cvs-log} looks
+like this:
+
+@example
+#!/bin/sh
+(echo "------------------------------------------------------";
+ echo -n $2" ";
+ date;
+ echo;
+ cat) >> $1
+@end example
+
+@node Keeping a checked out copy
+@appendixsubsubsec Keeping a checked out copy
+
+@c What other index entries? It seems like
+@c people might want to use a lot of different
+@c words for this functionality.
+@cindex Keeping a checked out copy
+@cindex Checked out copy, keeping
+@cindex Web pages, maintaining with CVS
+
+It is often useful to maintain a directory tree which
+contains files which correspond to the latest version
+in the repository. For example, other developers might
+want to refer to the latest sources without having to
+check them out, or you might be maintaining a web site
+with @sc{cvs} and want every checkin to cause the files
+used by the web server to be updated.
+@c Can we offer more details on the web example? Or
+@c point the user at how to figure it out? This text
+@c strikes me as sufficient for someone who already has
+@c some idea of what we mean but not enough for the naive
+@c user/sysadmin to understand it and set it up.
+
+The way to do this is by having loginfo invoke
+@code{cvs update}. Doing so in the naive way will
+cause a problem with locks, so the @code{cvs update}
+must be run in the background.
+@c Should we try to describe the problem with locks?
+@c It seems like a digression for someone who just
+@c wants to know how to make it work.
+@c Another choice which might work for a single file
+@c is to use "cvs -n update -p" which doesn't take
+@c out locks (I think) but I don't see many advantages
+@c of that and we might as well document something which
+@c works for multiple files.
+Here is an example for unix (this should all be on one line):
+
+@example
+^cyclic-pages (date; cat; (sleep 2; cd /u/www/local-docs;
+ cvs -q update -d) &) >> $CVSROOT/CVSROOT/updatelog 2>&1
+@end example
+
+This will cause checkins to repository directories
+starting with @code{cyclic-pages} to update the checked
+out tree in @file{/u/www/local-docs}.
+@c More info on some of the details? The "sleep 2" is
+@c so if we are lucky the lock will be gone by the time
+@c we start and we can wait 2 seconds instead of 30.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node rcsinfo
+@appendixsec Rcsinfo
+@cindex rcsinfo (admin file)
+@cindex Form for log message
+@cindex Log message template
+@cindex Template for log message
+
+The @file{rcsinfo} file can be used to specify a form to
+edit when filling out the commit log. The
+@file{rcsinfo} file has a syntax similar to the
+@file{verifymsg}, @file{commitinfo} and @file{loginfo}
+files. @xref{syntax}. Unlike the other files the second
+part is @emph{not} a command-line template. Instead,
+the part after the regular expression should be a full pathname to
+a file containing the log message template.
+
+If the repository name does not match any of the
+regular expressions in this file, the @samp{DEFAULT}
+line is used, if it is specified.
+
+All occurrences of the name @samp{ALL} appearing as a
+regular expression are used in addition to the first
+matching regular expression or @samp{DEFAULT}.
+
+@c FIXME: should be offering advice, somewhere around
+@c here, about where to put the template file. The
+@c verifymsg example uses /usr/cvssupport but doesn't
+@c say anything about what that directory is for or
+@c whether it is hardwired into CVS or who creates
+@c it or anything. In particular we should say
+@c how to version control the template file. A
+@c probably better answer than the /usr/cvssupport
+@c stuff is to use checkoutlist (with xref to the
+@c checkoutlist doc).
+@c Also I am starting to see a connection between
+@c this and the Keeping a checked out copy node.
+@c Probably want to say something about that.
+The log message template will be used as a default log
+message. If you specify a log message with @samp{cvs
+commit -m @var{message}} or @samp{cvs commit -f
+@var{file}} that log message will override the
+template.
+
+@xref{verifymsg}, for an example @file{rcsinfo}
+file.
+
+When @sc{cvs} is accessing a remote repository,
+the contents of @file{rcsinfo} at the time a directory
+is first checked out will specify a template. This
+template will be updated on all @samp{cvs update}
+commands. It will also be added to new directories
+added with a @samp{cvs add new-directry} command.
+In versions of @sc{cvs} prior to version 1.12, the
+@file{CVS/Template} file was not updated. If the
+@sc{cvs} server is at version 1.12 or higher an older
+client may be used and the @file{CVS/Template} will
+be updated from the server.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node taginfo
+@node taginfo
+@c <en>@appendixsec Taginfo
+@appendixsec Taginfo
+@c <en>@cindex taginfo (admin file)
+@cindex taginfo (admin file)
+@c <en>@cindex Tags, logging
+@cindex Tags, logging
+@c <en>@cindex Tags, verifying
+@cindex Tags, verifying
+@c <en>The @file{taginfo} file defines programs to execute
+@c <en>when someone executes a @code{tag} or @code{rtag}
+@c <en>command. The @file{taginfo} file has the standard form
+@c <en>for administrative files (@pxref{syntax}),
+@c <en>where each line is a regular expression
+@c <en>followed by a command to execute. The arguments passed
+@c <en>to the command are, in order, the @var{tagname},
+@c <en>@var{operation} (@code{add} for @code{tag},
+@c <en>@code{mov} for @code{tag -F}, and @code{del} for
+@c <en>@code{tag -d}), @var{repository}, and any remaining are
+@c <en>pairs of @var{filename} @var{revision}. A non-zero
+@c <en>exit of the filter program will cause the tag to be
+@c <en>aborted.
+The @file{taginfo} file defines programs to execute
+when someone executes a @code{tag} or @code{rtag}
+command. The @file{taginfo} file has the standard form
+for administrative files (@pxref{syntax}),
+where each line is a regular expression
+followed by a command to execute. The arguments passed
+to the command are, in order, the @var{tagname},
+@var{operation} (@code{add} for @code{tag},
+@code{mov} for @code{tag -F}, and @code{del} for
+@code{tag -d}), @var{repository}, and any remaining are
+pairs of @var{filename} @var{revision}. A non-zero
+exit of the filter program will cause the tag to be
+aborted.
+
+@c <en>Here is an example of using the @file{taginfo} file
+@c <en>to log @code{tag} and @code{rtag}
+@c <en>commands. In the @file{taginfo} file put:
+Here is an example of using the @file{taginfo} file
+to log @code{tag} and @code{rtag}
+commands. In the @file{taginfo} file put:
+
+@example
+ALL /usr/local/cvsroot/CVSROOT/loggit
+@end example
+
+@noindent
+@c <en>Where @file{/usr/local/cvsroot/CVSROOT/loggit} contains the
+@c <en>following script:
+Where @file{/usr/local/cvsroot/CVSROOT/loggit} contains the
+following script:
+
+@example
+#!/bin/sh
+echo "$@@" >>/home/kingdon/cvsroot/CVSROOT/taglog
+@end example
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node cvsignore
+@appendixsec Ignoring files via cvsignore
+@cindex cvsignore (admin file), global
+@cindex Global cvsignore
+@cindex Ignoring files
+@c -- This chapter should maybe be moved to the
+@c tutorial part of the manual?
+
+There are certain file names that frequently occur
+inside your working copy, but that you don't want to
+put under @sc{cvs} control. Examples are all the object
+files that you get while you compile your sources.
+Normally, when you run @samp{cvs update}, it prints a
+line for each file it encounters that it doesn't know
+about (@pxref{update output}).
+
+@sc{cvs} has a list of files (or sh(1) file name patterns)
+that it should ignore while running @code{update},
+@code{import} and @code{release}.
+@c -- Are those the only three commands affected?
+This list is constructed in the following way.
+
+@itemize @bullet
+@item
+The list is initialized to include certain file name
+patterns: names associated with @sc{cvs}
+administration, or with other common source control
+systems; common names for patch files, object files,
+archive files, and editor backup files; and other names
+that are usually artifacts of assorted utilities.
+Currently, the default list of ignored file name
+patterns is:
+
+@cindex Ignored files
+@cindex Automatically ignored files
+@example
+ RCS SCCS CVS CVS.adm
+ RCSLOG cvslog.*
+ tags TAGS
+ .make.state .nse_depinfo
+ *~ #* .#* ,* _$* *$
+ *.old *.bak *.BAK *.orig *.rej .del-*
+ *.a *.olb *.o *.obj *.so *.exe
+ *.Z *.elc *.ln
+ core
+@end example
+
+@item
+The per-repository list in
+@file{$CVSROOT/CVSROOT/cvsignore} is appended to
+the list, if that file exists.
+
+@item
+The per-user list in @file{.cvsignore} in your home
+directory is appended to the list, if it exists.
+
+@item
+Any entries in the environment variable
+@code{$CVSIGNORE} is appended to the list.
+
+@item
+Any @samp{-I} options given to @sc{cvs} is appended.
+
+@item
+As @sc{cvs} traverses through your directories, the contents
+of any @file{.cvsignore} will be appended to the list.
+The patterns found in @file{.cvsignore} are only valid
+for the directory that contains them, not for
+any sub-directories.
+@end itemize
+
+In any of the 5 places listed above, a single
+exclamation mark (@samp{!}) clears the ignore list.
+This can be used if you want to store any file which
+normally is ignored by @sc{cvs}.
+
+Specifying @samp{-I !} to @code{cvs import} will import
+everything, which is generally what you want to do if
+you are importing files from a pristine distribution or
+any other source which is known to not contain any
+extraneous files. However, looking at the rules above
+you will see there is a fly in the ointment; if the
+distribution contains any @file{.cvsignore} files, then
+the patterns from those files will be processed even if
+@samp{-I !} is specified. The only workaround is to
+remove the @file{.cvsignore} files in order to do the
+import. Because this is awkward, in the future
+@samp{-I !} might be modified to override
+@file{.cvsignore} files in each directory.
+
+Note that the syntax of the ignore files consists of a
+series of lines, each of which contains a space
+separated list of filenames. This offers no clean way
+to specify filenames which contain spaces, but you can
+use a workaround like @file{foo?bar} to match a file
+named @file{foo bar} (it also matches @file{fooxbar}
+and the like). Also note that there is currently no
+way to specify comments.
+@c FIXCVS? I don't _like_ this syntax at all, but
+@c changing it raises all the usual compatibility
+@c issues and I'm also not sure what to change it to.
+
+@node checkoutlist
+@appendixsec The checkoutlist file
+@cindex checkoutlist
+
+It may be helpful to use @sc{cvs} to maintain your own
+files in the @file{CVSROOT} directory. For example,
+suppose that you have a script @file{logcommit.pl}
+which you run by including the following line in the
+@file{commitinfo} administrative file:
+
+@example
+ALL $CVSROOT/CVSROOT/logcommit.pl
+@end example
+
+To maintain @file{logcommit.pl} with @sc{cvs} you would
+add the following line to the @file{checkoutlist}
+administrative file:
+
+@example
+logcommit.pl
+@end example
+
+The format of @file{checkoutlist} is one line for each
+file that you want to maintain using @sc{cvs}, giving
+the name of the file, followed optionally by more whitespace
+and any error message that should print if the file cannot be
+checked out into CVSROOT after a commit:
+
+@example
+logcommit.pl Could not update CVSROOT/logcommit.pl.
+@end example
+
+After setting up @file{checkoutlist} in this fashion,
+the files listed there will function just like
+@sc{cvs}'s built-in administrative files. For example,
+when checking in one of the files you should get a
+message such as:
+
+@example
+cvs commit: Rebuilding administrative file database
+@end example
+
+@noindent
+and the checked out copy in the @file{CVSROOT}
+directory should be updated.
+
+@c <en>Note that listing @file{passwd} (@pxref{Password
+@c <en>authentication server}) in @file{checkoutlist} is not
+@c <en>recommended for security reasons.
+Note that listing @file{passwd}
+(@pxref{Servidor de autenticação por senha}) in @file{checkoutlist} is not
+recommended for security reasons.
+
+For information about keeping a checkout out copy in a
+more general context than the one provided by
+@file{checkoutlist}, see @ref{Keeping a checked out
+copy}.
+
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c <en>@node history file
+@node arquivo history (histórico)
+@c <en>@appendixsec The history file
+@appendixsec O arquivo history (histórico)
+@c <en>@cindex History file
+@cindex Arquivo history (histórico)
+@c <en>@cindex Log information, saving
+@cindex Log information, saving
+
+@c <en>The file @file{$CVSROOT/CVSROOT/history} is used
+@c <en>to log information for the @code{history} command
+@c <en>(@pxref{history}). This file must be created to turn
+@c <en>on logging. This is done automatically if the
+@c <en>@code{cvs init} command is used to set up the
+@c <en>repository (@pxref{Creating a repository}).
+The file @file{$CVSROOT/CVSROOT/history} is used
+to log information for the @code{history} command
+(@pxref{history}). This file must be created to turn
+on logging. This is done automatically if the
+@code{cvs init} command is used to set up the
+repository (@pxref{Criando um repositório}).
+
+The file format of the @file{history} file is
+documented only in comments in the @sc{cvs} source
+code, but generally programs should use the @code{cvs
+history} command to access it anyway, in case the
+format changes with future releases of @sc{cvs}.
+
+@node Variables
+@appendixsec Expansions in administrative files
+@cindex Internal variables
+@cindex Variables
+
+Sometimes in writing an administrative file, you might
+want the file to be able to know various things based
+on environment @sc{cvs} is running in. There are
+several mechanisms to do that.
+
+@c <en>To find the home directory of the user running @sc{cvs}
+@c <en>(from the @code{HOME} environment variable), use
+@c <en>@samp{~} followed by @samp{/} or the end of the line.
+@c <en>Likewise for the home directory of @var{user}, use
+@c <en>@samp{~@var{user}}. These variables are expanded on
+@c <en>the server machine, and don't get any reasonable
+@c <en>expansion if pserver (@pxref{Password authenticated})
+@c <en>is in use; therefore user variables (see below) may be
+@c <en>a better choice to customize behavior based on the user
+@c <en>running @sc{cvs}.
+To find the home directory of the user running @sc{cvs}
+(from the @code{HOME} environment variable), use
+@samp{~} followed by @samp{/} or the end of the line.
+Likewise for the home directory of @var{user}, use
+@samp{~@var{user}}. These variables are expanded on
+the server machine, and don't get any reasonable
+expansion if pserver (@pxref{Autenticação por senha})
+is in use; therefore user variables (see below) may be
+a better choice to customize behavior based on the user
+running @sc{cvs}.
+@c Based on these limitations, should we deprecate ~?
+@c What is it good for? Are people using it?
+
+One may want to know about various pieces of
+information internal to @sc{cvs}. A @sc{cvs} internal
+variable has the syntax @code{$@{@var{variable}@}},
+where @var{variable} starts with a letter and consists
+of alphanumeric characters and @samp{_}. If the
+character following @var{variable} is a
+non-alphanumeric character other than @samp{_}, the
+@samp{@{} and @samp{@}} can be omitted. The @sc{cvs}
+internal variables are:
+
+@table @code
+@c <en>@item CVSROOT
+@item CVSROOT
+@c <en>@cindex CVSROOT, internal variable
+@cindex CVSROOT, internal variable
+@c <en>This is the absolute path to the current @sc{cvs} root directory.
+@c <en>@xref{Repository}, for a description of the various
+@c <en>ways to specify this, but note that the internal
+@c <en>variable contains just the directory and not any
+@c <en>of the access method information.
+This is the absolute path to the current @sc{cvs} root directory.
+@xref{Repositório}, for a description of the various
+ways to specify this, but note that the internal
+variable contains just the directory and not any
+of the access method information.
+
+@item RCSBIN
+@cindex RCSBIN, internal variable
+In @sc{cvs} 1.9.18 and older, this specified the
+directory where @sc{cvs} was looking for @sc{rcs}
+programs. Because @sc{cvs} no longer runs @sc{rcs}
+programs, specifying this internal variable is now an
+error.
+
+@c <en>@item CVSEDITOR
+@item CVSEDITOR
+@c <en>@cindex CVSEDITOR, internal variable
+@cindex CVSEDITOR, internal variable
+@c <en>@itemx EDITOR
+@itemx EDITOR
+@c <en>@cindex EDITOR, internal variable
+@cindex EDITOR, internal variable
+@c <en>@itemx VISUAL
+@itemx VISUAL
+@c <en>@cindex VISUAL, internal variable
+@cindex VISUAL, internal variable
+@c <en>These all expand to the same value, which is the editor
+@c <en>that @sc{cvs} is using. @xref{Global options}, for how
+@c <en>to specify this.
+These all expand to the same value, which is the editor
+that @sc{cvs} is using. @xref{Opções globais}, for how
+to specify this.
+
+@c <en>@item USER
+@item USER
+@c <en>@cindex USER, internal variable
+@cindex USER, internal variable
+@c <en>Username of the user running @sc{cvs} (on the @sc{cvs}
+@c <en>server machine).
+@c <en>When using pserver, this is the user specified in the repository
+@c <en>specification which need not be the same as the username the
+@c <en>server is running as (@pxref{Password authentication server}).
+@c <en>Do not confuse this with the environment variable of the same name.
+Username of the user running @sc{cvs} (on the @sc{cvs}
+server machine).
+When using pserver, this is the user specified in the repository
+specification which need not be the same as the username the
+server is running as (@pxref{Servidor de autenticação por senha}).
+Do not confuse this with the environment variable of the same name.
+@end table
+
+If you want to pass a value to the administrative files
+which the user who is running @sc{cvs} can specify,
+use a user variable.
+@cindex User variables
+To expand a user variable, the
+administrative file contains
+@code{$@{=@var{variable}@}}. To set a user variable,
+specify the global option @samp{-s} to @sc{cvs}, with
+argument @code{@var{variable}=@var{value}}. It may be
+particularly useful to specify this option via
+@file{.cvsrc} (@pxref{~/.cvsrc}).
+
+For example, if you want the administrative file to
+refer to a test directory you might create a user
+variable @code{TESTDIR}. Then if @sc{cvs} is invoked
+as
+
+@example
+cvs -s TESTDIR=/work/local/tests
+@end example
+
+@noindent
+and the
+administrative file contains @code{sh
+$@{=TESTDIR@}/runtests}, then that string is expanded
+to @code{sh /work/local/tests/runtests}.
+
+All other strings containing @samp{$} are reserved;
+there is no way to quote a @samp{$} character so that
+@samp{$} represents itself.
+
+Environment variables passed to administrative files are:
+
+@table @code
+@cindex environment variables, passed to administrative files
+
+@item CVS_USER
+@cindex CVS_USER, environment variable
+The @sc{cvs}-specific username provided by the user, if it
+can be provided (currently just for the pserver access
+method), and to the empty string otherwise. (@code{CVS_USER}
+and @code{USER} may differ when @file{$CVSROOT/CVSROOT/passwd}
+is used to map @sc{cvs} usernames to system usernames.)
+
+@item LOGNAME
+@cindex LOGNAME, environment variable
+The username of the system user.
+
+@item USER
+@cindex USER, environment variable
+Same as @code{LOGNAME}.
+Do not confuse this with the internal variable of the same name.
+@end table
+
+@node config
+@appendixsec The CVSROOT/config configuration file
+
+@cindex config, in CVSROOT
+@cindex CVSROOT/config
+
+The administrative file @file{config} contains various
+miscellaneous settings which affect the behavior of
+@sc{cvs}. The syntax is slightly different from the
+other administrative files. Variables are not
+expanded. Lines which start with @samp{#} are
+considered comments.
+@c FIXME: where do we define comments for the other
+@c administrative files.
+Other lines consist of a keyword, @samp{=}, and a
+value. Note that this syntax is very strict.
+Extraneous spaces or tabs are not permitted.
+@c See comments in parseinfo.c:parse_config for more
+@c discussion of this strictness.
+
+Currently defined keywords are:
+
+@table @code
+@cindex RCSBIN, in CVSROOT/config
+@item RCSBIN=@var{bindir}
+For @sc{cvs} 1.9.12 through 1.9.18, this setting told
+@sc{cvs} to look for @sc{rcs} programs in the
+@var{bindir} directory. Current versions of @sc{cvs}
+do not run @sc{rcs} programs; for compatibility this
+setting is accepted, but it does nothing.
+
+@c <en>@cindex SystemAuth, in CVSROOT/config
+@cindex SystemAuth, in CVSROOT/config
+@c <en>@item SystemAuth=@var{value}
+@item SystemAuth=@var{value}
+@c <en>If @var{value} is @samp{yes}, then pserver should check
+@c <en>for users in the system's user database if not found in
+@c <en>@file{CVSROOT/passwd}. If it is @samp{no}, then all
+@c <en>pserver users must exist in @file{CVSROOT/passwd}.
+@c <en>The default is @samp{yes}. For more on pserver, see
+@c <en>@ref{Password authenticated}.
+If @var{value} is @samp{yes}, then pserver should check
+for users in the system's user database if not found in
+@file{CVSROOT/passwd}. If it is @samp{no}, then all
+pserver users must exist in @file{CVSROOT/passwd}.
+The default is @samp{yes}. For more on pserver, see
+@ref{Autenticação por senha}.
+
+@ignore
+@cindex PreservePermissions, in CVSROOT/config
+@item PreservePermissions=@var{value}
+Enable support for saving special device files,
+symbolic links, file permissions and ownerships in the
+repository. The default value is @samp{no}.
+@xref{Special Files}, for the full implications of using
+this keyword.
+@end ignore
+
+@cindex TopLevelAdmin, in CVSROOT/config
+@item TopLevelAdmin=@var{value}
+Modify the @samp{checkout} command to create a
+@samp{CVS} directory at the top level of the new
+working directory, in addition to @samp{CVS}
+directories created within checked-out directories.
+The default value is @samp{no}.
+
+@c <en>This option is useful if you find yourself performing
+@c <en>many commands at the top level of your working
+@c <en>directory, rather than in one of the checked out
+@c <en>subdirectories. The @file{CVS} directory created there
+@c <en>will mean you don't have to specify @code{CVSROOT} for
+@c <en>each command. It also provides a place for the
+@c <en>@file{CVS/Template} file (@pxref{Working directory
+@c <en>storage}).
+This option is useful if you find yourself performing
+many commands at the top level of your working
+directory, rather than in one of the checked out
+subdirectories. The @file{CVS} directory created there
+will mean you don't have to specify @code{CVSROOT} for
+each command. It also provides a place for the
+@file{CVS/Template} file
+(@pxref{Armazenamento do Diretório de trabalho}).
+
+@c <en>@cindex LockDir, in CVSROOT/config
+@cindex LockDir, in CVSROOT/config
+@c <en>@item LockDir=@var{directory}
+@item LockDir=@var{directory}
+@c <en>Put @sc{cvs} lock files in @var{directory} rather than
+@c <en>directly in the repository. This is useful if you want
+@c <en>to let users read from the repository while giving them
+@c <en>write access only to @var{directory}, not to the
+@c <en>repository.
+@c <en>It can also be used to put the locks on a very fast
+@c <en>in-memory file system to speed up locking and unlocking
+@c <en>the repository.
+@c <en>You need to create @var{directory}, but
+@c <en>@sc{cvs} will create subdirectories of @var{directory} as it
+@c <en>needs them. For information on @sc{cvs} locks, see
+@c <en>@ref{Concurrency}.
+Put @sc{cvs} lock files in @var{directory} rather than
+directly in the repository. This is useful if you want
+to let users read from the repository while giving them
+write access only to @var{directory}, not to the
+repository.
+It can also be used to put the locks on a very fast
+in-memory file system to speed up locking and unlocking
+the repository.
+You need to create @var{directory}, but
+@sc{cvs} will create subdirectories of @var{directory} as it
+needs them. For information on @sc{cvs} locks, see
+@ref{Concorrência}.
+
+@c Mention this in Compatibility section?
+Before enabling the LockDir option, make sure that you
+have tracked down and removed any copies of @sc{cvs} 1.9 or
+older. Such versions neither support LockDir, nor will
+give an error indicating that they don't support it.
+The result, if this is allowed to happen, is that some
+@sc{cvs} users will put the locks one place, and others will
+put them another place, and therefore the repository
+could become corrupted. @sc{cvs} 1.10 does not support
+LockDir but it will print a warning if run on a
+repository with LockDir enabled.
+
+@cindex LogHistory, in CVSROOT/config
+@item LogHistory=@var{value}
+Control what is logged to the @file{CVSROOT/history} file (@pxref{history}).
+Default of @samp{TOEFWUPCGMAR} (or simply @samp{all}) will log
+all transactions. Any subset of the default is
+legal. (For example, to only log transactions that modify the
+@file{*,v} files, use @samp{LogHistory=TMAR}.)
+
+@cindex RereadLogAfterVerify, in CVSROOT/config
+@cindex @file{verifymsg}, changing the log message
+@item RereadLogAfterVerify=@var{value}
+Modify the @samp{commit} command such that CVS will reread the
+log message after running the program specified by @file{verifymsg}.
+@var{value} may be one of @samp{yes} or @samp{always}, indicating that
+the log message should always be reread; @samp{no}
+or @samp{never}, indicating that it should never be
+reread; or @var{value} may be @samp{stat}, indicating
+that the file should be checked with the filesystem
+@samp{stat()} function to see if it has changed (see warning below)
+before rereading. The default value is @samp{always}.
+
+@strong{Note: the `stat' mode can cause CVS to pause for up to
+one extra second per directory committed. This can be less IO and
+CPU intensive but is not recommended for use with large repositories}
+
+@xref{verifymsg}, for more information on how verifymsg
+may be used.
+
+@cindex UserAdminOptions, in CVSROOT/config
+@item UserAdminOptions=@var{value}
+Control what options will be allowed with the @code{cvs admin}
+command (@pxref{admin}) for users not in the @code{cvsadmin} group.
+The @var{value} string is a list of single character options
+which should be allowed. If a user who is not a member of the
+@code{cvsadmin} group tries to execute any @code{cvs admin}
+option which is not listed they will will receive an error message
+reporting that the option is restricted.
+
+If no @code{cvsadmin} group exists on the server, @sc{cvs} will
+ignore the @code{UserAdminOptions} keyword (@pxref{admin}).
+
+When not specified, @code{UserAdminOptions} defaults to
+@samp{k}. In other words, it defaults to allowing
+users outside of the @code{cvsadmin} group to use the
+@code{cvs admin} command only to change the default keyword
+expansion mode for files.
+
+As an example, to restrict users not in the @code{cvsadmin}
+group to using @code{cvs admin} to change the default keyword
+substitution mode, lock revisions, unlock revisions, and
+replace the log message, use @samp{UserAdminOptions=klum}.
+@end table
+
+@c ---------------------------------------------------------------------
+@c <en>@node Environment variables
+@node Variáveis de ambiente
+@c <en>@appendix All environment variables which affect CVS
+@appendix Todas as variáveis de ambiente que afetam o CVS
+@c <en>@cindex Environment variables
+@cindex Environment variables
+@c <en>@cindex Reference manual for variables
+@cindex Reference manual for variables
+
+This is a complete list of all environment variables
+that affect @sc{cvs}.
+
+@table @code
+@cindex CVSIGNORE, environment variable
+@item $CVSIGNORE
+A whitespace-separated list of file name patterns that
+@sc{cvs} should ignore. @xref{cvsignore}.
+
+@cindex CVSWRAPPERS, environment variable
+@item $CVSWRAPPERS
+A whitespace-separated list of file name patterns that
+@sc{cvs} should treat as wrappers. @xref{Wrappers}.
+
+@cindex CVSREAD, environment variable
+@cindex Read-only files, and CVSREAD
+@item $CVSREAD
+If this is set, @code{checkout} and @code{update} will
+try hard to make the files in your working directory
+read-only. When this is not set, the default behavior
+is to permit modification of your working files.
+
+@cindex CVSREADONLYFS, environment variable
+@item $CVSREADONLYFS
+Turns on read-only repository mode. This allows one to
+check out from a read-only repository, such as within
+an anoncvs server, or from a CDROM repository.
+
+It has the same effect as if the @samp{-R} command-line
+option is used. This can also allow the use of
+read-only NFS repositories.
+
+@c <en>@item $CVSUMASK
+@item $CVSUMASK
+@c <en>Controls permissions of files in the repository. See
+@c <en>@ref{File permissions}.
+Controls permissions of files in the repository. See
+@ref{Permissões de arquivos}.
+
+@item $CVSROOT
+Should contain the full pathname to the root of the @sc{cvs}
+source repository (where the @sc{rcs} files are
+kept). This information must be available to @sc{cvs} for
+most commands to execute; if @code{$CVSROOT} is not set,
+or if you wish to override it for one invocation, you
+can supply it on the command line: @samp{cvs -d cvsroot
+cvs_command@dots{}} Once you have checked out a working
+directory, @sc{cvs} stores the appropriate root (in
+the file @file{CVS/Root}), so normally you only need to
+worry about this when initially checking out a working
+directory.
+
+@c <en>@item $CVSEDITOR
+@item $CVSEDITOR
+@c <en>@cindex CVSEDITOR, environment variable
+@cindex CVSEDITOR, environment variable
+@c <en>@itemx $EDITOR
+@itemx $EDITOR
+@c <en>@cindex EDITOR, environment variable
+@cindex EDITOR, environment variable
+@c <en>@itemx $VISUAL
+@itemx $VISUAL
+@c <en>@cindex VISUAL, environment variable
+@cindex VISUAL, environment variable
+@c <en>Specifies the program to use for recording log messages
+@c <en>during commit. @code{$CVSEDITOR} overrides
+@c <en>@code{$EDITOR}, which overrides @code{$VISUAL}.
+@c <en>See @ref{Committing your changes} for more or
+@c <en>@ref{Global options} for alternative ways of specifying a
+@c <en>log editor.
+Specifies the program to use for recording log messages
+during commit. @code{$CVSEDITOR} overrides
+@code{$EDITOR}, which overrides @code{$VISUAL}.
+See @ref{Efetivando suas alterações} for more or
+@ref{Opções globais} for alternative ways of specifying a
+log editor.
+
+@cindex PATH, environment variable
+@item $PATH
+If @code{$RCSBIN} is not set, and no path is compiled
+into @sc{cvs}, it will use @code{$PATH} to try to find all
+programs it uses.
+
+@cindex HOME, environment variable
+@item $HOME
+@cindex HOMEPATH, environment variable
+@item $HOMEPATH
+@cindex HOMEDRIVE, environment variable
+@item $HOMEDRIVE
+Used to locate the directory where the @file{.cvsrc}
+file, and other such files, are searched. On Unix, @sc{cvs}
+just checks for @code{HOME}. On Windows NT, the system will
+set @code{HOMEDRIVE}, for example to @samp{d:} and @code{HOMEPATH},
+for example to @file{\joe}. On Windows 95, you'll
+probably need to set @code{HOMEDRIVE} and @code{HOMEPATH} yourself.
+@c We are being vague about whether HOME works on
+@c Windows; see long comment in windows-NT/filesubr.c.
+
+@c <en>@cindex CVS_RSH, environment variable
+@cindex CVS_RSH, environment variable
+@c <en>@item $CVS_RSH
+@item $CVS_RSH
+@c <en>Specifies the external program which @sc{cvs} connects with,
+@c <en>when @code{:ext:} access method is specified.
+@c <en>@pxref{Connecting via rsh}.
+Specifies the external program which @sc{cvs} connects with,
+when @code{:ext:} access method is specified.
+@pxref{Se conectando via rsh}.
+
+@c <en>@item $CVS_SERVER
+@item $CVS_SERVER
+@c <en>Used in client-server mode when accessing a remote
+@c <en>repository using @sc{rsh}. It specifies the name of
+@c <en>the program to start on the server side (and any
+@c <en>necessary arguments) when accessing a remote repository
+@c <en>using the @code{:ext:}, @code{:fork:}, or @code{:server:} access methods.
+@c <en>The default value for @code{:ext:} and @code{:server:} is @code{cvs};
+@c <en>the default value for @code{:fork:} is the name used to run the client.
+@c <en>@pxref{Connecting via rsh}
+Used in client-server mode when accessing a remote
+repository using @sc{rsh}. It specifies the name of
+the program to start on the server side (and any
+necessary arguments) when accessing a remote repository
+using the @code{:ext:}, @code{:fork:}, or @code{:server:} access methods.
+The default value for @code{:ext:} and @code{:server:} is @code{cvs};
+the default value for @code{:fork:} is the name used to run the client.
+@pxref{Se conectando via rsh}
+
+@c <en>@item $CVS_PASSFILE
+@item $CVS_PASSFILE
+@c <en>Used in client-server mode when accessing the @code{cvs
+@c <en>login server}. Default value is @file{$HOME/.cvspass}.
+@c <en>@pxref{Password authentication client}
+Used in client-server mode when accessing the @code{cvs
+login server}. Default value is @file{$HOME/.cvspass}.
+@pxref{Cliente de autenticação por senha}
+
+@c <en>@item $CVS_CLIENT_PORT
+@item $CVS_CLIENT_PORT
+@c <en>Used in client-server mode to set the port to use when accessing the server
+@c <en>via Kerberos, GSSAPI, or @sc{cvs}'s password authentication protocol
+@c <en>if the port is not specified in the CVSROOT.
+@c <en>@pxref{Remote repositories}
+Used in client-server mode to set the port to use when accessing the server
+via Kerberos, GSSAPI, or @sc{cvs}'s password authentication protocol
+if the port is not specified in the CVSROOT.
+@pxref{Repositórios remotos}
+
+@cindex CVS_RCMD_PORT, environment variable
+@item $CVS_RCMD_PORT
+Used in client-server mode. If set, specifies the port
+number to be used when accessing the @sc{rcmd} demon on
+the server side. (Currently not used for Unix clients).
+
+@cindex CVS_CLIENT_LOG, environment variable
+@item $CVS_CLIENT_LOG
+Used for debugging only in client-server
+mode. If set, everything sent to the server is logged
+into @file{@code{$CVS_CLIENT_LOG}.in} and everything
+sent from the server is logged into
+@file{@code{$CVS_CLIENT_LOG}.out}.
+
+@cindex CVS_SERVER_SLEEP, environment variable
+@item $CVS_SERVER_SLEEP
+Used only for debugging the server side in
+client-server mode. If set, delays the start of the
+server child process the specified amount of
+seconds so that you can attach to it with a debugger.
+
+@cindex CVS_IGNORE_REMOTE_ROOT, environment variable
+@item $CVS_IGNORE_REMOTE_ROOT
+For @sc{cvs} 1.10 and older, setting this variable
+prevents @sc{cvs} from overwriting the @file{CVS/Root}
+file when the @samp{-d} global option is specified.
+Later versions of @sc{cvs} do not rewrite
+@file{CVS/Root}, so @code{CVS_IGNORE_REMOTE_ROOT} has no
+effect.
+
+@cindex CVS_LOCAL_BRANCH_NUM, environment variable
+@item $CVS_LOCAL_BRANCH_NUM
+Setting this variable allows some control over the
+branch number that is assigned. This is specifically to
+support the local commit feature of CVSup. If one sets
+@code{CVS_LOCAL_BRANCH_NUM} to (say) 1000 then branches
+the local repository, the revision numbers will look
+like 1.66.1000.xx. There is almost a dead-set certainty
+that there will be no conflicts with version numbers.
+
+@cindex COMSPEC, environment variable
+@item $COMSPEC
+Used under OS/2 only. It specifies the name of the
+command interpreter and defaults to @sc{cmd.exe}.
+
+@c <en>@cindex TMPDIR, environment variable
+@cindex TMPDIR, environment variable
+@c <en>@item $TMPDIR
+@item $TMPDIR
+@c <en>@cindex TMP, environment variable
+@cindex TMP, environment variable
+@c <en>@itemx $TMP
+@itemx $TMP
+@c <en>@cindex TEMP, environment variable
+@cindex TEMP, environment variable
+@c <en>@itemx $TEMP
+@itemx $TEMP
+@c <en>@cindex Temporary files, location of
+@cindex Temporary files, location of
+@c This is quite nuts. We don't talk about tempnam
+@c or mkstemp which we sometimes use. The discussion
+@c of "Global options" is semi-incoherent.
+@c I'm not even sure those are the only inaccuracies.
+@c Furthermore, the conventions are
+@c pretty crazy and they should be simplified.
+@c <en>Directory in which temporary files are located.
+@c <en>The @sc{cvs} server uses
+@c <en>@code{TMPDIR}. @xref{Global options}, for a
+@c <en>description of how to specify this.
+@c <en>Some parts of @sc{cvs} will always use @file{/tmp} (via
+@c <en>the @code{tmpnam} function provided by the system).
+Directory in which temporary files are located.
+The @sc{cvs} server uses
+@code{TMPDIR}. @xref{Opções globais}, for a
+description of how to specify this.
+Some parts of @sc{cvs} will always use @file{/tmp} (via
+the @code{tmpnam} function provided by the system).
+
+On Windows NT, @code{TMP} is used (via the @code{_tempnam}
+function provided by the system).
+
+The @code{patch} program which is used by the @sc{cvs}
+client uses @code{TMPDIR}, and if it is not set, uses
+@file{/tmp} (at least with GNU patch 2.1). Note that
+if your server and client are both running @sc{cvs}
+1.9.10 or later, @sc{cvs} will not invoke an external
+@code{patch} program.
+
+@cindex CVS_PID, environment variable
+@item $CVS_PID
+This is the process identification (aka pid) number of
+the @sc{cvs} process. It is often useful in the
+programs and/or scripts specified by the
+@file{commitinfo}, @file{verifymsg}, @file{loginfo}
+files.
+@end table
+
+@c <en>@node Compatibility
+@node Compatibilidade
+@c <en>@appendix Compatibility between CVS Versions
+@appendix Compatibility between CVS Versions
+
+@cindex CVS, versions of
+@cindex Versions, of CVS
+@cindex Compatibility, between CVS versions
+@c We don't mention versions older than CVS 1.3
+@c on the theory that it would clutter it up for the vast
+@c majority of people, who don't have anything that old.
+@c
+@c <en>The repository format is compatible going back to
+@c <en>@sc{cvs} 1.3. But see @ref{Watches Compatibility}, if
+@c <en>you have copies of @sc{cvs} 1.6 or older and you want
+@c <en>to use the optional developer communication features.
+The repository format is compatible going back to
+@sc{cvs} 1.3. But see @ref{Compatibilidade de ???Watches???}, if
+you have copies of @sc{cvs} 1.6 or older and you want
+to use the optional developer communication features.
+@c If you "cvs rm" and commit using 1.3, then you'll
+@c want to run "rcs -sdead <file,v>" on each of the
+@c files in the Attic if you then want 1.5 and
+@c later to recognize those files as dead (I think the
+@c symptom if this is not done is that files reappear
+@c in joins). (Wait: the above will work but really to
+@c be strictly correct we should suggest checking
+@c in a new revision rather than just changing the
+@c state of the head revision, shouldn't we?).
+@c The old convert.sh script was for this, but it never
+@c did get updated to reflect use of the RCS "dead"
+@c state.
+@c Note: this is tricky to document without confusing
+@c people--need to carefully say what CVS version we
+@c are talking about and keep in mind the distinction
+@c between a
+@c repository created with 1.3 and on which one now
+@c uses 1.5+, and a repository on which one wants to
+@c use both versions side by side (e.g. during a
+@c transition period).
+@c Wait, can't CVS just detect the case in which a file
+@c is in the Attic but the head revision is not dead?
+@c Not sure whether this should produce a warning or
+@c something, and probably needs further thought, but
+@c it would appear that the situation can be detected.
+@c
+@c We might want to separate out the 1.3 compatibility
+@c section (for repository & working directory) from the
+@c rest--that might help avoid confusing people who
+@c are upgrading (for example) from 1.6 to 1.8.
+@c
+@c A minor incompatibility is if a current version of CVS
+@c puts "Nfoo" into CVS/Tag, then CVS 1.9 or older will
+@c see this as if there is no tag. Seems to me this is
+@c too obscure to mention.
+
+The working directory format is compatible going back
+to @sc{cvs} 1.5. It did change between @sc{cvs} 1.3
+and @sc{cvs} 1.5. If you run @sc{cvs} 1.5 or newer on
+a working directory checked out with @sc{cvs} 1.3,
+@sc{cvs} will convert it, but to go back to @sc{cvs}
+1.3 you need to check out a new working directory with
+@sc{cvs} 1.3.
+
+The remote protocol is interoperable going back to @sc{cvs} 1.5, but no
+further (1.5 was the first official release with the remote protocol,
+but some older versions might still be floating around). In many
+cases you need to upgrade both the client and the server to take
+advantage of new features and bugfixes, however.
+
+@c Perhaps should be saying something here about the
+@c "D" lines in Entries (written by CVS 1.9; 1.8 and
+@c older don't use them). These are supposed to be
+@c compatible in both directions, but I'm not sure
+@c they quite are 100%. One common gripe is if you
+@c "rm -r" a directory and 1.9 gets confused, as it
+@c still sees it in Entries. That one is fixed in
+@c (say) 1.9.6. Someone else reported problems with
+@c starting with a directory which was checked out with
+@c an old version, and then using a new version, and
+@c some "D" lines appeared, but not for every
+@c directory, causing some directories to be skipped.
+@c They weren't sure how to reproduce this, though.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Troubleshooting
+@node Resolução de problemas
+@c <en>@appendix Troubleshooting
+@appendix Resolução de problemas
+
+If you are having trouble with @sc{cvs}, this appendix
+may help. If there is a particular error message which
+you are seeing, then you can look up the message
+alphabetically. If not, you can look through the
+section on other problems to see if your problem is
+mentioned there.
+
+@menu
+@c <en>* Error messages:: Partial list of CVS errors
+* Mensagens de erro:: Partial list of CVS errors
+@c <en>* Connection:: Trouble making a connection to a CVS server
+* Conexão:: Trouble making a connection to a CVS server
+@c <en>* Other problems:: Problems not readily listed by error message
+* Outros problemas:: Problems not readily listed by error message
+@end menu
+
+@ignore
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@c @node Bad administrative files
+@appendixsec Bad administrative files
+
+@c -- Give hints on how to fix them
+@end ignore
+
+@c <en>@node Error messages
+@node Mensagens de erro
+@c <en>@appendixsec Partial list of error messages
+@appendixsec Partial list of error messages
+
+Here is a partial list of error messages that you may
+see from @sc{cvs}. It is not a complete list---@sc{cvs}
+is capable of printing many, many error messages, often
+with parts of them supplied by the operating system,
+but the intention is to list the common and/or
+potentially confusing error messages.
+
+The messages are alphabetical, but introductory text
+such as @samp{cvs update: } is not considered in
+ordering them.
+
+In some cases the list includes messages printed by old
+versions of @sc{cvs} (partly because users may not be
+sure which version of @sc{cvs} they are using at any
+particular moment).
+@c If we want to start retiring messages, perhaps we
+@c should pick a cutoff version (for example, no more
+@c messages which are specific to versions before 1.9)
+@c and then move the old messages to an "old messages"
+@c node rather than deleting them completely.
+
+@table @code
+@c FIXME: What is the correct way to format a multiline
+@c error message here? Maybe @table is the wrong
+@c choice? Texinfo gurus?
+@c <en>@item @var{file}:@var{line}: Assertion '@var{text}' failed
+@item @var{file}:@var{line}: Assertion '@var{text}' failed
+@c <en>The exact format of this message may vary depending on
+@c <en>your system. It indicates a bug in @sc{cvs}, which can
+@c <en>be handled as described in @ref{BUGS}.
+The exact format of this message may vary depending on
+your system. It indicates a bug in @sc{cvs}, which can
+be handled as described in @ref{Paus}.
+
+@c <en>@item cvs @var{command}: authorization failed: server @var{host} rejected access
+@item cvs @var{command}: authorization failed: server @var{host} rejected access
+@c <en>This is a generic response when trying to connect to a
+@c <en>pserver server which chooses not to provide a
+@c <en>specific reason for denying authorization. Check that
+@c <en>the username and password specified are correct and
+@c <en>that the @code{CVSROOT} specified is allowed by @samp{--allow-root}
+@c <en>in @file{inetd.conf}. See @ref{Password authenticated}.
+This is a generic response when trying to connect to a
+pserver server which chooses not to provide a
+specific reason for denying authorization. Check that
+the username and password specified are correct and
+that the @code{CVSROOT} specified is allowed by @samp{--allow-root}
+in @file{inetd.conf}. See @ref{Autenticação por senha}.
+
+@item cvs @var{command}: conflict: removed @var{file} was modified by second party
+This message indicates that you removed a file, and
+someone else modified it. To resolve the conflict,
+first run @samp{cvs add @var{file}}. If desired, look
+at the other party's modification to decide whether you
+still want to remove it. If you don't want to remove
+it, stop here. If you do want to remove it, proceed
+with @samp{cvs remove @var{file}} and commit your
+removal.
+@c Tests conflicts2-142b* in sanity.sh test for this.
+
+@item cannot change permissions on temporary directory
+@example
+Operation not permitted
+@end example
+This message has been happening in a non-reproducible,
+occasional way when we run the client/server testsuite,
+both on Red Hat Linux 3.0.3 and 4.1. We haven't been
+able to figure out what causes it, nor is it known
+whether it is specific to linux (or even to this
+particular machine!). If the problem does occur on
+other unices, @samp{Operation not permitted} would be
+likely to read @samp{Not owner} or whatever the system
+in question uses for the unix @code{EPERM} error. If
+you have any information to add, please let us know as
+described in @ref{Paus}. If you experience this error
+while using @sc{cvs}, retrying the operation which
+produced it should work fine.
+@c This has been seen in a variety of tests, including
+@c multibranch-2, multibranch-5, and basic1-24-rm-rm,
+@c so it doesn't seem particularly specific to any one
+@c test.
+
+@c <en>@item cvs [server aborted]: Cannot check out files into the repository itself
+@item cvs [server aborted]: Cannot check out files into the repository itself
+@c <en>The obvious cause for this message (especially for
+@c <en>non-client/server @sc{cvs}) is that the @sc{cvs} root
+@c <en>is, for example, @file{/usr/local/cvsroot} and you try
+@c <en>to check out files when you are in a subdirectory, such
+@c <en>as @file{/usr/local/cvsroot/test}. However, there is a
+@c <en>more subtle cause, which is that the temporary
+@c <en>directory on the server is set to a subdirectory of the
+@c <en>root (which is also not allowed). If this is the
+@c <en>problem, set the temporary directory to somewhere else,
+@c <en>for example @file{/var/tmp}; see @code{TMPDIR} in
+@c <en>@ref{Environment variables}, for how to set the
+@c <en>temporary directory.
+The obvious cause for this message (especially for
+non-client/server @sc{cvs}) is that the @sc{cvs} root
+is, for example, @file{/usr/local/cvsroot} and you try
+to check out files when you are in a subdirectory, such
+as @file{/usr/local/cvsroot/test}. However, there is a
+more subtle cause, which is that the temporary
+directory on the server is set to a subdirectory of the
+root (which is also not allowed). If this is the
+problem, set the temporary directory to somewhere else,
+for example @file{/var/tmp}; see @code{TMPDIR} in
+@ref{Variáveis de ambiente}, for how to set the
+temporary directory.
+
+@item cannot commit files as 'root'
+See @samp{'root' is not allowed to commit files}.
+
+@c For one example see basica-1a10 in the testsuite
+@c For another example, "cvs co ." on NT; see comment
+@c at windows-NT/filesubr.c (expand_wild).
+@c For another example, "cvs co foo/bar" where foo exists.
+@c <en>@item cannot open CVS/Entries for reading: No such file or directory
+@item cannot open CVS/Entries for reading: No such file or directory
+@c <en>This generally indicates a @sc{cvs} internal error, and
+@c <en>can be handled as with other @sc{cvs} bugs
+@c <en>(@pxref{BUGS}). Usually there is a workaround---the
+@c <en>exact nature of which would depend on the situation but
+@c <en>which hopefully could be figured out.
+This generally indicates a @sc{cvs} internal error, and
+can be handled as with other @sc{cvs} bugs
+(@pxref{Paus}). Usually there is a workaround---the
+exact nature of which would depend on the situation but
+which hopefully could be figured out.
+
+@c This is more obscure than it might sound; it only
+@c happens if you run "cvs init" from a directory which
+@c contains a CVS/Root file at the start.
+@item cvs [init aborted]: cannot open CVS/Root: No such file or directory
+This message is harmless. Provided it is not
+accompanied by other errors, the operation has
+completed successfully. This message should not occur
+with current versions of @sc{cvs}, but it is documented
+here for the benefit of @sc{cvs} 1.9 and older.
+
+@c <en>@item cvs server: cannot open /root/.cvsignore: Permission denied
+@item cvs server: cannot open /root/.cvsignore: Permission denied
+@c <en>@itemx cvs [server aborted]: can't chdir(/root): Permission denied
+@itemx cvs [server aborted]: can't chdir(/root): Permission denied
+@c <en>See @ref{Connection}.
+See @ref{Conexão}.
+
+@c <en>@item cvs [checkout aborted]: cannot rename file @var{file} to CVS/,,@var{file}: Invalid argument
+@item cvs [checkout aborted]: cannot rename file @var{file} to CVS/,,@var{file}: Invalid argument
+@c <en>This message has been reported as intermittently
+@c <en>happening with @sc{cvs} 1.9 on Solaris 2.5. The cause is
+@c <en>unknown; if you know more about what causes it, let us
+@c <en>know as described in @ref{BUGS}.
+This message has been reported as intermittently
+happening with @sc{cvs} 1.9 on Solaris 2.5. The cause is
+unknown; if you know more about what causes it, let us
+know as described in @ref{Paus}.
+
+@c <en>@item cvs [@var{command} aborted]: cannot start server via rcmd
+@item cvs [@var{command} aborted]: cannot start server via rcmd
+@c <en>This, unfortunately, is a rather nonspecific error
+@c <en>message which @sc{cvs} 1.9 will print if you are
+@c <en>running the @sc{cvs} client and it is having trouble
+@c <en>connecting to the server. Current versions of @sc{cvs}
+@c <en>should print a much more specific error message. If
+@c <en>you get this message when you didn't mean to run the
+@c <en>client at all, you probably forgot to specify
+@c <en>@code{:local:}, as described in @ref{Repository}.
+This, unfortunately, is a rather nonspecific error
+message which @sc{cvs} 1.9 will print if you are
+running the @sc{cvs} client and it is having trouble
+connecting to the server. Current versions of @sc{cvs}
+should print a much more specific error message. If
+you get this message when you didn't mean to run the
+client at all, you probably forgot to specify
+@code{:local:}, as described in @ref{Repositório}.
+
+@item ci: @var{file},v: bad diff output line: Binary files - and /tmp/T2a22651 differ
+@sc{cvs} 1.9 and older will print this message
+when trying to check in a binary file if
+@sc{rcs} is not correctly installed. Re-read the
+instructions that came with your @sc{rcs} distribution
+and the @sc{install} file in the @sc{cvs}
+distribution. Alternately, upgrade to a current
+version of @sc{cvs}, which checks in files itself
+rather than via @sc{rcs}.
+
+@c <en>@item cvs checkout: could not check out @var{file}
+@item cvs checkout: could not check out @var{file}
+@c <en>With @sc{cvs} 1.9, this can mean that the @code{co} program
+@c <en>(part of @sc{rcs}) returned a failure. It should be
+@c <en>preceded by another error message, however it has been
+@c <en>observed without another error message and the cause is
+@c <en>not well-understood. With the current version of @sc{cvs},
+@c <en>which does not run @code{co}, if this message occurs
+@c <en>without another error message, it is definitely a @sc{cvs}
+@c <en>bug (@pxref{BUGS}).
+With @sc{cvs} 1.9, this can mean that the @code{co} program
+(part of @sc{rcs}) returned a failure. It should be
+preceded by another error message, however it has been
+observed without another error message and the cause is
+not well-understood. With the current version of @sc{cvs},
+which does not run @code{co}, if this message occurs
+without another error message, it is definitely a @sc{cvs}
+bug (@pxref{Paus}).
+@c My current suspicion is that the RCS in the rcs (not
+@c cvs/winnt/rcs57nt.zip) directory on the _Practical_
+@c CD is bad (remains to be confirmed).
+@c There is also a report of something which looks
+@c very similar on SGI, Irix 5.2, so I dunno.
+
+@c <en>@item cvs [login aborted]: could not find out home directory
+@item cvs [login aborted]: could not find out home directory
+@c <en>This means that you need to set the environment
+@c <en>variables that @sc{cvs} uses to locate your home directory.
+@c <en>See the discussion of @code{HOME}, @code{HOMEDRIVE}, and @code{HOMEPATH} in
+@c <en>@ref{Environment variables}.
+This means that you need to set the environment
+variables that @sc{cvs} uses to locate your home directory.
+See the discussion of @code{HOME}, @code{HOMEDRIVE}, and @code{HOMEPATH} in
+@ref{Variáveis de ambiente}.
+
+@item cvs update: could not merge revision @var{rev} of @var{file}: No such file or directory
+@sc{cvs} 1.9 and older will print this message if there was
+a problem finding the @code{rcsmerge} program. Make
+sure that it is in your @code{PATH}, or upgrade to a
+current version of @sc{cvs}, which does not require
+an external @code{rcsmerge} program.
+
+@item cvs [update aborted]: could not patch @var{file}: No such file or directory
+This means that there was a problem finding the
+@code{patch} program. Make sure that it is in your
+@code{PATH}. Note that despite appearances the message
+is @emph{not} referring to whether it can find @var{file}.
+If both the client and the server are running a current
+version of @sc{cvs}, then there is no need for an
+external patch program and you should not see this
+message. But if either client or server is running
+@sc{cvs} 1.9, then you need @code{patch}.
+
+@item cvs update: could not patch @var{file}; will refetch
+This means that for whatever reason the client was
+unable to apply a patch that the server sent. The
+message is nothing to be concerned about, because
+inability to apply the patch only slows things down and
+has no effect on what @sc{cvs} does.
+@c xref to update output. Or File status?
+@c Or some place else that
+@c explains this whole "patch"/P/Needs Patch thing?
+
+@c <en>@item dying gasps from @var{server} unexpected
+@item dying gasps from @var{server} unexpected
+@c <en>There is a known bug in the server for @sc{cvs} 1.9.18
+@c <en>and older which can cause this. For me, this was
+@c <en>reproducible if I used the @samp{-t} global option. It
+@c <en>was fixed by Andy Piper's 14 Nov 1997 change to
+@c <en>src/filesubr.c, if anyone is curious.
+@c <en>If you see the message,
+@c <en>you probably can just retry the operation which failed,
+@c <en>or if you have discovered information concerning its
+@c <en>cause, please let us know as described in @ref{BUGS}.
+There is a known bug in the server for @sc{cvs} 1.9.18
+and older which can cause this. For me, this was
+reproducible if I used the @samp{-t} global option. It
+was fixed by Andy Piper's 14 Nov 1997 change to
+src/filesubr.c, if anyone is curious.
+If you see the message,
+you probably can just retry the operation which failed,
+or if you have discovered information concerning its
+cause, please let us know as described in @ref{Paus}.
+
+@c <en>@item end of file from server (consult above messages if any)
+@item end of file from server (consult above messages if any)
+@c <en>The most common cause for this message is if you are
+@c <en>using an external @code{rsh} program and it exited with
+@c <en>an error. In this case the @code{rsh} program should
+@c <en>have printed a message, which will appear before the
+@c <en>above message. For more information on setting up a
+@c <en>@sc{cvs} client and server, see @ref{Remote repositories}.
+The most common cause for this message is if you are
+using an external @code{rsh} program and it exited with
+an error. In this case the @code{rsh} program should
+have printed a message, which will appear before the
+above message. For more information on setting up a
+@sc{cvs} client and server, see @ref{Repositórios remotos}.
+
+@c <en>@item cvs [update aborted]: EOF in key in RCS file @var{file},v
+@item cvs [update aborted]: EOF in key in RCS file @var{file},v
+@c <en>@itemx cvs [checkout aborted]: EOF while looking for end of string in RCS file @var{file},v
+@itemx cvs [checkout aborted]: EOF while looking for end of string in RCS file @var{file},v
+@c <en>This means that there is a syntax error in the given
+@c <en>@sc{rcs} file. Note that this might be true even if @sc{rcs} can
+@c <en>read the file OK; @sc{cvs} does more error checking of
+@c <en>errors in the RCS file. That is why you may see this
+@c <en>message when upgrading from @sc{cvs} 1.9 to @sc{cvs}
+@c <en>1.10. The likely cause for the original corruption is
+@c <en>hardware, the operating system, or the like. Of
+@c <en>course, if you find a case in which @sc{cvs} seems to
+@c <en>corrupting the file, by all means report it,
+@c <en>(@pxref{BUGS}).
+@c <en>There are quite a few variations of this error message,
+@c <en>depending on exactly where in the @sc{rcs} file @sc{cvs}
+@c <en>finds the syntax error.
+This means that there is a syntax error in the given
+@sc{rcs} file. Note that this might be true even if @sc{rcs} can
+read the file OK; @sc{cvs} does more error checking of
+errors in the RCS file. That is why you may see this
+message when upgrading from @sc{cvs} 1.9 to @sc{cvs}
+1.10. The likely cause for the original corruption is
+hardware, the operating system, or the like. Of
+course, if you find a case in which @sc{cvs} seems to
+corrupting the file, by all means report it,
+(@pxref{Paus}).
+There are quite a few variations of this error message,
+depending on exactly where in the @sc{rcs} file @sc{cvs}
+finds the syntax error.
+
+@cindex mkmodules
+@item cvs commit: Executing 'mkmodules'
+This means that your repository is set up for a version
+of @sc{cvs} prior to @sc{cvs} 1.8. When using @sc{cvs}
+1.8 or later, the above message will be preceded by
+
+@example
+cvs commit: Rebuilding administrative file database
+@end example
+
+If you see both messages, the database is being rebuilt
+twice, which is unnecessary but harmless. If you wish
+to avoid the duplication, and you have no versions of
+@sc{cvs} 1.7 or earlier in use, remove @code{-i mkmodules}
+every place it appears in your @code{modules}
+file. For more information on the @code{modules} file,
+see @ref{modules}.
+
+@c This message comes from "co", and I believe is
+@c possible only with older versions of CVS which call
+@c co. The problem with being able to create the bogus
+@c RCS file still exists, though (and I think maybe
+@c there is a different symptom(s) now).
+@c FIXME: Would be nice to have a more exact wording
+@c for this message.
+@item missing author
+Typically this can happen if you created an RCS file
+with your username set to empty. @sc{cvs} will, bogusly,
+create an illegal RCS file with no value for the author
+field. The solution is to make sure your username is
+set to a non-empty value and re-create the RCS file.
+@c "make sure your username is set" is complicated in
+@c and of itself, as there are the environment
+@c variables the system login name, &c, and it depends
+@c on the version of CVS.
+
+@c <en>@item cvs [checkout aborted]: no such tag @var{tag}
+@item cvs [checkout aborted]: no such tag @var{tag}
+@c <en>This message means that @sc{cvs} isn't familiar with
+@c <en>the tag @var{tag}. Usually this means that you have
+@c <en>mistyped a tag name; however there are (relatively
+@c <en>obscure) cases in which @sc{cvs} will require you to
+@c <en>@c Search sanity.sh for "no such tag" to see some of
+@c <en>@c the relatively obscure cases.
+@c <en>try a few other @sc{cvs} commands involving that tag,
+@c <en>before you find one which will cause @sc{cvs} to update
+This message means that @sc{cvs} isn't familiar with
+the tag @var{tag}. Usually this means that you have
+mistyped a tag name; however there are (relatively
+obscure) cases in which @sc{cvs} will require you to
+@c Search sanity.sh for "no such tag" to see some of
+@c the relatively obscure cases.
+try a few other @sc{cvs} commands involving that tag,
+before you find one which will cause @sc{cvs} to update
+@c <en>@cindex CVSROOT/val-tags file, forcing tags into
+@cindex CVSROOT/val-tags file, forcing tags into
+@c <en>@cindex val-tags file, forcing tags into
+@cindex val-tags file, forcing tags into
+@c <en>the @file{val-tags} file; see discussion of val-tags in
+@c <en>@ref{File permissions}. You only need to worry about
+@c <en>this once for a given tag; when a tag is listed in
+@c <en>@file{val-tags}, it stays there. Note that using
+@c <en>@samp{-f} to not require tag matches does not override
+@c <en>this check; see @ref{Common options}.
+the @file{val-tags} file; see discussion of val-tags in
+@ref{Permissões de arquivos}. You only need to worry about
+this once for a given tag; when a tag is listed in
+@file{val-tags}, it stays there. Note that using
+@samp{-f} to not require tag matches does not override
+this check; see @ref{Opções comuns}.
+
+@c <en>@item *PANIC* administration files missing
+@item *PANIC* administration files missing
+@c <en>This typically means that there is a directory named
+@c <en>@sc{cvs} but it does not contain the administrative files
+@c <en>which @sc{cvs} puts in a CVS directory. If the problem is
+@c <en>that you created a CVS directory via some mechanism
+@c <en>other than @sc{cvs}, then the answer is simple, use a name
+@c <en>other than @sc{cvs}. If not, it indicates a @sc{cvs} bug
+@c <en>(@pxref{BUGS}).
+This typically means that there is a directory named
+@sc{cvs} but it does not contain the administrative files
+which @sc{cvs} puts in a CVS directory. If the problem is
+that you created a CVS directory via some mechanism
+other than @sc{cvs}, then the answer is simple, use a name
+other than @sc{cvs}. If not, it indicates a @sc{cvs} bug
+(@pxref{Paus}).
+
+@item rcs error: Unknown option: -x,v/
+This message will be followed by a usage message for
+@sc{rcs}. It means that you have an old version of
+@sc{rcs} (probably supplied with your operating
+system), as well as an old version of @sc{cvs}.
+@sc{cvs} 1.9.18 and earlier only work with @sc{rcs} version 5 and
+later; current versions of @sc{cvs} do not run @sc{rcs} programs.
+@c For more information on installing @sc{cvs}, see
+@c (FIXME: where? it depends on whether you are
+@c getting binaries or sources or what).
+@c The message can also say "ci error" or something
+@c instead of "rcs error", I suspect.
+
+@c <en>@item cvs [server aborted]: received broken pipe signal
+@item cvs [server aborted]: received broken pipe signal
+@c <en>This message seems to be caused by a hard-to-track-down
+@c <en>bug in @sc{cvs} or the systems it runs on (we don't
+@c <en>know---we haven't tracked it down yet!). It seems to
+@c <en>happen only after a @sc{cvs} command has completed, and
+@c <en>you should be able to just ignore the message.
+@c <en>However, if you have discovered information concerning its
+@c <en>cause, please let us know as described in @ref{BUGS}.
+This message seems to be caused by a hard-to-track-down
+bug in @sc{cvs} or the systems it runs on (we don't
+know---we haven't tracked it down yet!). It seems to
+happen only after a @sc{cvs} command has completed, and
+you should be able to just ignore the message.
+However, if you have discovered information concerning its
+cause, please let us know as described in @ref{Paus}.
+
+@item 'root' is not allowed to commit files
+When committing a permanent change, @sc{cvs} makes a log entry of
+who committed the change. If you are committing the change logged
+in as "root" (not under "su" or other root-priv giving program),
+@sc{cvs} cannot determine who is actually making the change.
+As such, by default, @sc{cvs} disallows changes to be committed by users
+logged in as "root". (You can disable this option by passing the
+@code{--enable-rootcommit} option to @file{configure} and recompiling @sc{cvs}.
+On some systems this means editing the appropriate @file{config.h} file
+before building @sc{cvs}.)
+
+@item Too many arguments!
+This message is typically printed by the @file{log.pl}
+script which is in the @file{contrib} directory in the
+@sc{cvs} source distribution. In some versions of
+@sc{cvs}, @file{log.pl} has been part of the default
+@sc{cvs} installation. The @file{log.pl} script gets
+called from the @file{loginfo} administrative file.
+Check that the arguments passed in @file{loginfo} match
+what your version of @file{log.pl} expects. In
+particular, the @file{log.pl} from @sc{cvs} 1.3 and
+older expects the logfile as an argument whereas the
+@file{log.pl} from @sc{cvs} 1.5 and newer expects the
+logfile to be specified with a @samp{-f} option. Of
+course, if you don't need @file{log.pl} you can just
+comment it out of @file{loginfo}.
+
+@item cvs [update aborted]: unexpected EOF reading @var{file},v
+See @samp{EOF in key in RCS file}.
+
+@c <en>@item cvs [login aborted]: unrecognized auth response from @var{server}
+@item cvs [login aborted]: unrecognized auth response from @var{server}
+@c <en>This message typically means that the server is not set
+@c <en>up properly. For example, if @file{inetd.conf} points
+@c <en>to a nonexistent cvs executable. To debug it further,
+@c <en>find the log file which inetd writes
+@c <en>(@file{/var/log/messages} or whatever inetd uses on
+@c <en>your system). For details, see @ref{Connection}, and
+@c <en>@ref{Password authentication server}.
+This message typically means that the server is not set
+up properly. For example, if @file{inetd.conf} points
+to a nonexistent cvs executable. To debug it further,
+find the log file which inetd writes
+(@file{/var/log/messages} or whatever inetd uses on
+your system). For details, see @ref{Conexão}, and
+@ref{Servidor de autenticação por senha}.
+
+@c <en>@item cvs commit: Up-to-date check failed for `@var{file}'
+@item cvs commit: Up-to-date check failed for `@var{file}'
+@c <en>This means that someone else has committed a change to
+@c <en>that file since the last time that you did a @code{cvs
+@c <en>update}. So before proceeding with your @code{cvs
+@c <en>commit} you need to @code{cvs update}. @sc{cvs} will merge
+@c <en>the changes that you made and the changes that the
+@c <en>other person made. If it does not detect any conflicts
+@c <en>it will report @samp{M @var{file}} and you are ready
+@c <en>to @code{cvs commit}. If it detects conflicts it will
+@c <en>print a message saying so, will report @samp{C @var{file}},
+@c <en>and you need to manually resolve the
+@c <en>conflict. For more details on this process see
+@c <en>@ref{Conflicts example}.
+This means that someone else has committed a change to
+that file since the last time that you did a @code{cvs
+update}. So before proceeding with your @code{cvs
+commit} you need to @code{cvs update}. @sc{cvs} will merge
+the changes that you made and the changes that the
+other person made. If it does not detect any conflicts
+it will report @samp{M @var{file}} and you are ready
+to @code{cvs commit}. If it detects conflicts it will
+print a message saying so, will report @samp{C @var{file}},
+and you need to manually resolve the
+conflict. For more details on this process see
+@ref{Exemplo de conflitos}.
+
+@item Usage: diff3 [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3
+@example
+Only one of [exEX3] allowed
+@end example
+This indicates a problem with the installation of
+@code{diff3} and @code{rcsmerge}. Specifically
+@code{rcsmerge} was compiled to look for GNU diff3, but
+it is finding unix diff3 instead. The exact text of
+the message will vary depending on the system. The
+simplest solution is to upgrade to a current version of
+@sc{cvs}, which does not rely on external
+@code{rcsmerge} or @code{diff3} programs.
+
+@item warning: unrecognized response `@var{text}' from cvs server
+If @var{text} contains a valid response (such as
+@samp{ok}) followed by an extra carriage return
+character (on many systems this will cause the second
+part of the message to overwrite the first part), then
+it probably means that you are using the @samp{:ext:}
+access method with a version of rsh, such as most
+non-unix rsh versions, which does not by default
+provide a transparent data stream. In such cases you
+probably want to try @samp{:server:} instead of
+@samp{:ext:}. If @var{text} is something else, this
+may signify a problem with your @sc{cvs} server.
+Double-check your installation against the instructions
+for setting up the @sc{cvs} server.
+@c FIXCVS: should be printing CR as \r or \015 or some
+@c such, probably.
+
+@c <en>@item cvs commit: [@var{time}] waiting for @var{user}'s lock in @var{directory}
+@item cvs commit: [@var{time}] waiting for @var{user}'s lock in @var{directory}
+@c <en>This is a normal message, not an error. See
+@c <en>@ref{Concurrency}, for more details.
+This is a normal message, not an error. See
+@ref{Concorrência}, for more details.
+
+@item cvs commit: warning: editor session failed
+@cindex Exit status, of editor
+This means that the editor which @sc{cvs} is using exits with a nonzero
+exit status. Some versions of vi will do this even when there was not
+a problem editing the file. If so, point the
+@code{CVSEDITOR} environment variable to a small script
+such as:
+
+@example
+#!/bin/sh
+vi $*
+exit 0
+@end example
+
+@c "warning: foo was lost" and "no longer pertinent" (both normal).
+@c Would be nice to write these up--they are
+@c potentially confusing for the new user.
+@end table
+
+@c <en>@node Connection
+@node Conexão
+@c <en>@appendixsec Trouble making a connection to a CVS server
+@appendixsec Trouble making a connection to a CVS server
+
+This section concerns what to do if you are having
+trouble making a connection to a @sc{cvs} server. If
+you are running the @sc{cvs} command line client
+running on Windows, first upgrade the client to
+@sc{cvs} 1.9.12 or later. The error reporting in
+earlier versions provided much less information about
+what the problem was. If the client is non-Windows,
+@sc{cvs} 1.9 should be fine.
+
+If the error messages are not sufficient to track down
+the problem, the next steps depend largely on which
+access method you are using.
+
+@table @code
+@cindex :ext:, troubleshooting
+@item :ext:
+Try running the rsh program from the command line. For
+example: "rsh servername cvs -v" should print @sc{cvs}
+version information. If this doesn't work, you need to
+fix it before you can worry about @sc{cvs} problems.
+
+@cindex :server:, troubleshooting
+@item :server:
+You don't need a command line rsh program to use this
+access method, but if you have an rsh program around,
+it may be useful as a debugging tool. Follow the
+directions given for :ext:.
+
+@cindex :pserver:, troubleshooting
+@item :pserver:
+Errors along the lines of "connection refused" typically indicate
+that inetd isn't even listening for connections on port 2401
+whereas errors like "connection reset by peer",
+"received broken pipe signal", "recv() from server: EOF",
+or "end of file from server"
+typically indicate that inetd is listening for
+connections but is unable to start @sc{cvs} (this is frequently
+caused by having an incorrect path in @file{inetd.conf}
+or by firewall software rejecting the connection).
+"unrecognized auth response" errors are caused by a bad command
+line in @file{inetd.conf}, typically an invalid option or forgetting
+to put the @samp{pserver} command at the end of the line.
+Another less common problem is invisible control characters that
+your editor "helpfully" added without you noticing.
+
+One good debugging tool is to "telnet servername
+2401". After connecting, send any text (for example
+"foo" followed by return). If @sc{cvs} is working
+correctly, it will respond with
+
+@example
+cvs [pserver aborted]: bad auth protocol start: foo
+@end example
+
+If instead you get:
+
+@example
+Usage: cvs [cvs-options] command [command-options-and-arguments]
+...
+@end example
+
+@noindent
+then you're missing the @samp{pserver} command at the end of the
+line in @file{inetd.conf}; check to make sure that the entire command
+is on one line and that it's complete.
+
+Likewise, if you get something like:
+
+@example
+Unknown command: `pserved'
+
+CVS commands are:
+ add Add a new file/directory to the repository
+...
+@end example
+
+@noindent
+then you've misspelled @samp{pserver} in some way. If it isn't
+obvious, check for invisible control characters (particularly
+carriage returns) in @file{inetd.conf}.
+
+If it fails to work at all, then make sure inetd is working
+right. Change the invocation in @file{inetd.conf} to run the
+echo program instead of cvs. For example:
+
+@example
+2401 stream tcp nowait root /bin/echo echo hello
+@end example
+
+After making that change and instructing inetd to
+re-read its configuration file, "telnet servername
+2401" should show you the text hello and then the
+server should close the connection. If this doesn't
+work, you need to fix it before you can worry about
+@sc{cvs} problems.
+
+On AIX systems, the system will often have its own
+program trying to use port 2401. This is AIX's problem
+in the sense that port 2401 is registered for use with
+@sc{cvs}. I hear that there is an AIX patch available
+to address this problem.
+
+Another good debugging tool is the @samp{-d}
+(debugging) option to inetd. Consult your system
+documentation for more information.
+
+If you seem to be connecting but get errors like:
+
+@example
+cvs server: cannot open /root/.cvsignore: Permission denied
+cvs [server aborted]: can't chdir(/root): Permission denied
+@end example
+
+@noindent
+then you probably haven't specified @samp{-f} in @file{inetd.conf}.
+(In releases prior to @sc{cvs} 1.11.1, this problem can be caused by
+your system setting the @code{$HOME} environment variable
+for programs being run by inetd. In this case, you can either
+have inetd run a shell script that unsets @code{$HOME} and then runs
+@sc{cvs}, or you can use @code{env} to run @sc{cvs} with a pristine
+environment.)
+
+If you can connect successfully for a while but then can't,
+you've probably hit inetd's rate limit.
+(If inetd receives too many requests for the same service
+in a short period of time, it assumes that something is wrong
+and temporarily disables the service.)
+Check your inetd documentation to find out how to adjust the
+rate limit (some versions of inetd have a single rate limit,
+others allow you to set the limit for each service separately.)
+@end table
+
+@c <en>@node Other problems
+@node Outros problemas
+@c <en>@appendixsec Other common problems
+@appendixsec Other common problems
+
+Here is a list of problems which do not fit into the
+above categories. They are in no particular order.
+
+@itemize @bullet
+@item
+@c <en>On Windows, if there is a 30 second or so delay when
+@c <en>you run a @sc{cvs} command, it may mean that you have
+@c <en>your home directory set to @file{C:/}, for example (see
+@c <en>@code{HOMEDRIVE} and @code{HOMEPATH} in
+@c <en>@ref{Environment variables}). @sc{cvs} expects the home
+@c <en>directory to not end in a slash, for example @file{C:}
+@c <en>or @file{C:\cvs}.
+On Windows, if there is a 30 second or so delay when
+you run a @sc{cvs} command, it may mean that you have
+your home directory set to @file{C:/}, for example (see
+@code{HOMEDRIVE} and @code{HOMEPATH} in
+@ref{Variáveis de ambiente}). @sc{cvs} expects the home
+directory to not end in a slash, for example @file{C:}
+or @file{C:\cvs}.
+@c FIXCVS: CVS should at least detect this and print an
+@c error, presumably.
+
+@item
+@c <en>If you are running @sc{cvs} 1.9.18 or older, and
+@c <en>@code{cvs update} finds a conflict and tries to
+@c <en>merge, as described in @ref{Conflicts example}, but
+@c <en>doesn't tell you there were conflicts, then you may
+@c <en>have an old version of @sc{rcs}. The easiest solution
+@c <en>probably is to upgrade to a current version of
+@c <en>@sc{cvs}, which does not rely on external @sc{rcs}
+@c <en>programs.
+If you are running @sc{cvs} 1.9.18 or older, and
+@code{cvs update} finds a conflict and tries to
+merge, as described in @ref{Exemplo de conflitos}, but
+doesn't tell you there were conflicts, then you may
+have an old version of @sc{rcs}. The easiest solution
+probably is to upgrade to a current version of
+@sc{cvs}, which does not rely on external @sc{rcs}
+programs.
+@end itemize
+
+@c ---------------------------------------------------------------------
+@c <en>@node Credits
+@node Créditos
+@c <en>@appendix Credits
+@appendix Créditos
+
+@cindex Contributors (manual)
+@cindex Credits (manual)
+Roland Pesch, then of Cygnus Support <@t{roland@@wrs.com}>
+wrote the manual pages which were distributed with
+@sc{cvs} 1.3. Much of their text was copied into this
+manual. He also read an early draft
+of this manual and contributed many ideas and
+corrections.
+
+The mailing-list @code{info-cvs} is sometimes
+informative. I have included information from postings
+made by the following persons:
+David G. Grubbs <@t{dgg@@think.com}>.
+
+Some text has been extracted from the man pages for
+@sc{rcs}.
+
+The @sc{cvs} @sc{faq} by David G. Grubbs has provided
+useful material. The @sc{faq} is no longer maintained,
+however, and this manual is about the closest thing there
+is to a successor (with respect to documenting how to
+use @sc{cvs}, at least).
+
+In addition, the following persons have helped by
+telling me about mistakes I've made:
+
+@display
+Roxanne Brunskill <@t{rbrunski@@datap.ca}>,
+Kathy Dyer <@t{dyer@@phoenix.ocf.llnl.gov}>,
+Karl Pingle <@t{pingle@@acuson.com}>,
+Thomas A Peterson <@t{tap@@src.honeywell.com}>,
+Inge Wallin <@t{ingwa@@signum.se}>,
+Dirk Koschuetzki <@t{koschuet@@fmi.uni-passau.de}>
+and Michael Brown <@t{brown@@wi.extrel.com}>.
+@end display
+
+The list of contributors here is not comprehensive; for a more
+complete list of who has contributed to this manual see
+the file @file{doc/ChangeLog} in the @sc{cvs} source
+distribution.
+
+@c ---------------------------------------------------------------------
+@c <en>@node BUGS
+@node Paus
+@c <en>@appendix Dealing with bugs in CVS or this manual
+@appendix Dealing with bugs in CVS or this manual
+
+@cindex Bugs in this manual or CVS
+Neither @sc{cvs} nor this manual is perfect, and they
+probably never will be. If you are having trouble
+using @sc{cvs}, or think you have found a bug, there
+are a number of things you can do about it. Note that
+if the manual is unclear, that can be considered a bug
+in the manual, so these problems are often worth doing
+something about as well as problems with @sc{cvs} itself.
+
+@cindex Reporting bugs
+@cindex Bugs, reporting
+@cindex Errors, reporting
+@itemize @bullet
+@item
+If you want someone to help you and fix bugs that you
+report, there are companies which will do that for a
+fee. One such company is:
+
+@cindex Ximbiot
+@cindex Support, getting CVS support
+@example
+Ximbiot
+319 S. River St.
+Harrisburg, PA 17104-1657
+USA
+Email: info@@ximbiot.com
+Phone: (717) 579-6168
+Fax: (717) 234-3125
+@url{http://ximbiot.com/}
+
+@end example
+
+@item
+If you got @sc{cvs} through a distributor, such as an
+operating system vendor or a vendor of freeware
+@sc{cd-rom}s, you may wish to see whether the
+distributor provides support. Often, they will provide
+no support or minimal support, but this may vary from
+distributor to distributor.
+
+@item
+If you have the skills and time to do so, you may wish
+to fix the bug yourself. If you wish to submit your
+fix for inclusion in future releases of @sc{cvs}, see
+the file @sc{hacking} in the @sc{cvs} source
+distribution. It contains much more information on the
+process of submitting fixes.
+
+@item
+There may be resources on the net which can help. Two
+good places to start are:
+
+@example
+@url{http://cvs.nongnu.org/}
+@end example
+
+If you are so inspired, increasing the information
+available on the net is likely to be appreciated. For
+example, before the standard @sc{cvs} distribution
+worked on Windows 95, there was a web page with some
+explanation and patches for running @sc{cvs} on Windows
+95, and various people helped out by mentioning this
+page on mailing lists or newsgroups when the subject
+came up.
+
+@item
+It is also possible to report bugs to @email{bug-cvs@@nongnu.org}.
+Note that someone may or may not want to do anything
+with your bug report---if you need a solution consider
+one of the options mentioned above. People probably do
+want to hear about bugs which are particularly severe
+in consequences and/or easy to fix, however. You can
+also increase your odds by being as clear as possible
+about the exact nature of the bug and any other
+relevant information. The way to report bugs is to
+send email to @email{bug-cvs@@nongnu.org}. Note
+that submissions to @email{bug-cvs@@nongnu.org} may be distributed
+under the terms of the @sc{gnu} Public License, so if
+you don't like this, don't submit them. There is
+usually no justification for sending mail directly to
+one of the @sc{cvs} maintainers rather than to
+@email{bug-cvs@@nongnu.org}; those maintainers who want to hear
+about such bug reports read @email{bug-cvs@@nongnu.org}. Also note
+that sending a bug report to other mailing lists or
+newsgroups is @emph{not} a substitute for sending it to
+@email{bug-cvs@@nongnu.org}. It is fine to discuss @sc{cvs} bugs on
+whatever forum you prefer, but there are not
+necessarily any maintainers reading bug reports sent
+anywhere except @email{bug-cvs@@nongnu.org}.
+@end itemize
+
+@cindex Known bugs in this manual or CVS
+People often ask if there is a list of known bugs or
+whether a particular bug is a known one. The file
+@sc{bugs} in the @sc{cvs} source distribution is one
+list of known bugs, but it doesn't necessarily try to
+be comprehensive. Perhaps there will never be a
+comprehensive, detailed list of known bugs.
+
+@c ---------------------------------------------------------------------
+@c <en>@node Index
+@node Indice
+@c <en>@unnumbered Index
+@unnumbered Índice
+@c <en>@cindex Index
+@cindex Índice
+
+@printindex cp
+
+@summarycontents
+
+@contents
+
+@bye
+
+Local Variables:
+fill-column: 55
+End:
diff --git a/doc/mdate-sh b/doc/mdate-sh
new file mode 100755
index 0000000..4b2efdf
--- /dev/null
+++ b/doc/mdate-sh
@@ -0,0 +1,193 @@
+#!/bin/sh
+# Get modification time of a file or directory and pretty-print it.
+
+scriptversion=2005-02-07.09
+
+# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005 Free Software
+# Foundation, Inc.
+# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No file. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: mdate-sh [--help] [--version] FILE
+
+Pretty-print the modification time of FILE.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "mdate-sh $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Prevent date giving response in another language.
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+LC_TIME=C
+export LC_TIME
+
+save_arg1="$1"
+
+# Find out how to get the extended ls output of a file or directory.
+if ls -L /dev/null 1>/dev/null 2>&1; then
+ ls_command='ls -L -l -d'
+else
+ ls_command='ls -l -d'
+fi
+
+# A `ls -l' line looks as follows on OS/2.
+# drwxrwx--- 0 Aug 11 2001 foo
+# This differs from Unix, which adds ownership information.
+# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
+#
+# To find the date, we split the line on spaces and iterate on words
+# until we find a month. This cannot work with files whose owner is a
+# user named `Jan', or `Feb', etc. However, it's unlikely that `/'
+# will be owned by a user whose name is a month. So we first look at
+# the extended ls output of the root directory to decide how many
+# words should be skipped to get the date.
+
+# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
+set x`ls -l -d /`
+
+# Find which argument is the month.
+month=
+command=
+until test $month
+do
+ shift
+ # Add another shift to the command.
+ command="$command shift;"
+ case $1 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+ esac
+done
+
+# Get the extended ls output of the file or directory.
+set dummy x`eval "$ls_command \"\$save_arg1\""`
+
+# Remove all preceding arguments
+eval $command
+
+# Because of the dummy argument above, month is in $2.
+#
+# On a POSIX system, we should have
+#
+# $# = 5
+# $1 = file size
+# $2 = month
+# $3 = day
+# $4 = year or time
+# $5 = filename
+#
+# On Darwin 7.7.0 and 7.6.0, we have
+#
+# $# = 4
+# $1 = day
+# $2 = month
+# $3 = year or time
+# $4 = filename
+
+# Get the month.
+case $2 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+esac
+
+case $3 in
+ ???*) day=$1;;
+ *) day=$3; shift;;
+esac
+
+# Here we have to deal with the problem that the ls output gives either
+# the time of day or the year.
+case $3 in
+ *:*) set `date`; eval year=\$$#
+ case $2 in
+ Jan) nummonthtod=1;;
+ Feb) nummonthtod=2;;
+ Mar) nummonthtod=3;;
+ Apr) nummonthtod=4;;
+ May) nummonthtod=5;;
+ Jun) nummonthtod=6;;
+ Jul) nummonthtod=7;;
+ Aug) nummonthtod=8;;
+ Sep) nummonthtod=9;;
+ Oct) nummonthtod=10;;
+ Nov) nummonthtod=11;;
+ Dec) nummonthtod=12;;
+ esac
+ # For the first six month of the year the time notation can also
+ # be used for files modified in the last year.
+ if (expr $nummonth \> $nummonthtod) > /dev/null;
+ then
+ year=`expr $year - 1`
+ fi;;
+ *) year=$3;;
+esac
+
+# The result.
+echo $day $month $year
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/doc/mkman.pl b/doc/mkman.pl
new file mode 100644
index 0000000..ecc2ea1
--- /dev/null
+++ b/doc/mkman.pl
@@ -0,0 +1,369 @@
+#! @PERL@
+#
+# Generate a man page from sections of a Texinfo manual.
+#
+# Copyright 2004 The Free Software Foundation,
+# Derek R. Price,
+# & Ximbiot <http://ximbiot.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+
+# Need Perl 5.005 or greater for re 'eval'.
+require 5.005;
+
+# The usual.
+use strict;
+use IO::File;
+
+
+
+###
+### GLOBALS
+###
+my $texi_num = 0; # Keep track of how many texinfo files have been encountered.
+my @parent; # This needs to be global to be used inside of a regex later.
+my $nk; # Ditto.
+my $ret; # The RE match Type, used in debug prints.
+my $debug = 0; # Debug mode?
+
+
+
+###
+### FUNCTIONS
+###
+sub debug_print
+{
+ print @_ if $debug;
+}
+
+
+
+sub keyword_mode
+{
+ my ($keyword, $file) = @_;
+
+ return "\\fR"
+ if $keyword =~ /^(|r|t)$/;
+ return "\\fB"
+ if $keyword =~ /^(strong|sc|code|file|samp)$/;
+ return "\\fI"
+ if $keyword =~ /^(emph|var|dfn)$/;
+ die "no handler for keyword \`$keyword', found at line $. of file \`$file'\n";
+}
+
+
+
+# Return replacement for \@$keyword{$content}.
+sub do_keyword
+{
+ my ($file, $parent, $keyword, $content) = @_;
+
+ return "see node \`$content\\(aq in the CVS manual"
+ if $keyword =~ /^(p?x)?ref$/;
+ return "\\fP\\fP$content"
+ if $keyword =~ /^splitrcskeyword$/;
+
+ my $endmode = keyword_mode $parent;
+ my $startmode = keyword_mode $keyword, $file;
+
+ return "$startmode$content$endmode";
+}
+
+
+
+###
+### MAIN
+###
+for my $file (@ARGV)
+{
+ my $fh = new IO::File "< $file"
+ or die "Failed to open file \`$file': $!";
+
+ if ($file !~ /\.(texinfo|texi|txi)$/)
+ {
+ print stderr "Passing \`$file' through unprocessed.\n";
+ # Just cat any file that doesn't look like a Texinfo source.
+ while (my $line = $fh->getline)
+ {
+ print $line;
+ }
+ next;
+ }
+
+ print stderr "Processing \`$file'.\n";
+ $texi_num++;
+ my $gotone = 0;
+ my $inblank = 0;
+ my $indent = 0;
+ my $inexample = 0;
+ my $inmenu = 0;
+ my $intable = 0;
+ my $last_header = "";
+ my @table_headers;
+ my @table_footers;
+ my $table_header = "";
+ my $table_footer = "";
+ my $last;
+ while ($_ = $fh->getline)
+ {
+ if (!$gotone && /^\@c ----- START MAN $texi_num -----$/)
+ {
+ $gotone = 1;
+ next;
+ }
+
+ # Skip ahead until our man section.
+ next unless $gotone;
+
+ # If we find the end tag we are done.
+ last if /^\@c ----- END MAN $texi_num -----$/;
+
+ # Need to do this everywhere. i.e., before we print example
+ # lines, since literal back slashes can appear there too.
+ s/\\/\\\\/g;
+ s/^\./\\&./;
+ s/([\s])\./$1\\&./;
+ s/'/\\(aq/g;
+ s/`/\\`/g;
+ s/(?<!-)---(?!-)/\\(em/g;
+ s/\@bullet({}|\b)/\\(bu/g;
+ s/\@dots({}|\b)/\\&.../g;
+
+ # Examples should be indented and otherwise untouched
+ if (/^\@example$/)
+ {
+ $indent += 2;
+ print qq{.SP\n.PD 0\n};
+ $inexample = 1;
+ next;
+ }
+ if ($inexample)
+ {
+ if (/^\@end example$/)
+ {
+ $indent -= 2;
+ print qq{\n.PD\n.IP "" $indent\n};
+ $inexample = 0;
+ next;
+ }
+ if (/^[ ]*$/)
+ {
+ print ".SP\n";
+ next;
+ }
+
+ # Preserve the newline.
+ $_ = qq{.IP "" $indent\n} . $_;
+ }
+
+ # Compress blank lines into a single line. This and its
+ # corresponding skip purposely bracket the @menu and comment
+ # removal so that blanks on either side of a menu are
+ # compressed after the menu is removed.
+ if (/^[ ]*$/)
+ {
+ $inblank = 1;
+ next;
+ }
+
+ # Not used
+ if (/^\@(ignore|menu)$/)
+ {
+ $inmenu++;
+ next;
+ }
+ # Delete menu contents.
+ if ($inmenu)
+ {
+ next unless /^\@end (ignore|menu)$/;
+ $inmenu--;
+ next;
+ }
+
+ # Remove comments
+ next if /^\@c(omment)?\b/;
+
+ # Ignore includes.
+ next if /^\@include\b/;
+
+ # It's okay to ignore this keyword - we're not using any
+ # first-line indent commands at all.
+ next if s/^\@noindent\s*$//;
+
+ # @need is only significant in printed manuals.
+ next if s/^\@need\s+.*$//;
+
+ # If we didn't hit the previous check and $inblank is set, then
+ # we just finished with some number of blanks. Print the man
+ # page blank symbol before continuing processing of this line.
+ if ($inblank)
+ {
+ print ".SP\n";
+ $inblank = 0;
+ }
+
+ # Chapter headers.
+ $last_header = $1 if s/^\@node\s+(.*)$/.SH "$1"/;
+ if (/^\@appendix\w*\s+(.*)$/)
+ {
+ my $content = $1;
+ $content =~ s/^$last_header(\\\(em|\s+)?//;
+ next if $content =~ /^\s*$/;
+ s/^\@appendix\w*\s+.*$/.SS "$content"/;
+ }
+
+ # Tables are similar to examples, except we need to handle the
+ # keywords.
+ if (/^\@(itemize|table)(\s+(.*))?$/)
+ {
+ $indent += 2;
+ push @table_headers, $table_header;
+ push @table_footers, $table_footer;
+ my $content = $3;
+ if (/^\@itemize/)
+ {
+ my $bullet = $content;
+ $table_header = qq{.IP "$bullet" $indent\n};
+ $table_footer = "";
+ }
+ else
+ {
+ my $hi = $indent - 2;
+ $table_header = qq{.IP "" $hi\n};
+ $table_footer = qq{\n.IP "" $indent};
+ if ($content)
+ {
+ $table_header .= "$content\{";
+ $table_footer = "\}$table_footer";
+ }
+ }
+ $intable++;
+ next;
+ }
+
+ if ($intable)
+ {
+ if (/^\@end (itemize|table)$/)
+ {
+ $table_header = pop @table_headers;
+ $table_footer = pop @table_footers;
+ $indent -= 2;
+ $intable--;
+ next;
+ }
+ s/^\@itemx?(\s+(.*))?$/$table_header$2$table_footer/;
+ # Fall through so the rest of the table lines are
+ # processed normally.
+ }
+
+ # Index entries.
+ s/^\@cindex\s+(.*)$/.IX "$1"/;
+
+ $_ = "$last$_" if $last;
+ undef $last;
+
+ # Trap keywords
+ $nk = qr/
+ \@(\w+)\{
+ (?{ debug_print "$ret MATCHED $&\nPUSHING $1\n";
+ push @parent, $1; }) # Keep track of the last keyword
+ # keyword we encountered.
+ ((?>
+ [^{}]|(?<=\@)[{}] # Non-braces...
+ | # ...or...
+ (??{ $nk }) # ...nested keywords...
+ )*) # ...without backtracking.
+ \}
+ (?{ debug_print "$ret MATCHED $&\nPOPPING ",
+ pop (@parent), "\n"; }) # Lose track of the current keyword.
+ /x;
+
+ $ret = "m//";
+ if (/\@\w+\{(?:[^{}]|(?<=\@)[{}]|(??{ $nk }))*$/)
+ {
+ # If there is an opening keyword on this line without a
+ # close bracket, we need to find the close bracket
+ # before processing the line. Set $last to append the
+ # next line in the next pass.
+ $last = $_;
+ next;
+ }
+
+ # Okay, the following works somewhat counter-intuitively. $nk
+ # processes the whole line, so @parent gets loaded properly,
+ # then, since no closing brackets have been found for the
+ # outermost matches, the innermost matches match and get
+ # replaced first.
+ #
+ # For example:
+ #
+ # Processing the line:
+ #
+ # yadda yadda @code{yadda @var{foo} yadda @var{bar} yadda}
+ #
+ # Happens something like this:
+ #
+ # 1. Ignores "yadda yadda "
+ # 2. Sees "@code{" and pushes "code" onto @parent.
+ # 3. Ignores "yadda " (backtracks and ignores "yadda yadda
+ # @code{yadda "?)
+ # 4. Sees "@var{" and pushes "var" onto @parent.
+ # 5. Sees "foo}", pops "var", and realizes that "@var{foo}"
+ # matches the overall pattern ($nk).
+ # 6. Replaces "@var{foo}" with the result of:
+ #
+ # do_keyword $file, $parent[$#parent], $1, $2;
+ #
+ # which would be "\Ifoo\B", in this case, because "var"
+ # signals a request for italics, or "\I", and "code" is
+ # still on the stack, which means the previous style was
+ # bold, or "\B".
+ #
+ # Then the while loop restarts and a similar series of events
+ # replaces "@var{bar}" with "\Ibar\B".
+ #
+ # Then the while loop restarts and a similar series of events
+ # replaces "@code{yadda \Ifoo\B yadda \Ibar\B yadda}" with
+ # "\Byadda \Ifoo\B yadda \Ibar\B yadda\R".
+ #
+ $ret = "s///";
+ @parent = ("");
+ while (s/$nk/do_keyword $file, $parent[$#parent], $1, $2/e)
+ {
+ # Do nothing except reset our last-replacement
+ # tracker - the replacement regex above is handling
+ # everything else.
+ debug_print "FINAL MATCH $&\n";
+ @parent = ("");
+ }
+
+ # Finally, unprotect texinfo special characters.
+ s/\@://g;
+ s/\@([{}])/$1/g;
+
+ # Verify we haven't left commands unprocessed.
+ die "Unprocessed command at line $. of file \`$file': "
+ . ($1 ? "$1\n" : "<EOL>\n")
+ if /^(?>(?:[^\@]|\@\@)*)\@(\w+|.|$)/;
+
+ # Unprotect @@.
+ s/\@\@/\@/g;
+
+ # And print whatever's left.
+ print $_;
+ }
+}
diff --git a/doc/stamp-1 b/doc/stamp-1
new file mode 100644
index 0000000..73be364
--- /dev/null
+++ b/doc/stamp-1
@@ -0,0 +1,4 @@
+@set UPDATED 20 July 2005
+@set UPDATED-MONTH July 2005
+@set EDITION 1.12.13
+@set VERSION 1.12.13
diff --git a/doc/stamp-vti b/doc/stamp-vti
new file mode 100644
index 0000000..85cc927
--- /dev/null
+++ b/doc/stamp-vti
@@ -0,0 +1,4 @@
+@set UPDATED 22 September 2005
+@set UPDATED-MONTH September 2005
+@set EDITION 1.12.13
+@set VERSION 1.12.13
diff --git a/doc/version-client.texi b/doc/version-client.texi
new file mode 100644
index 0000000..73be364
--- /dev/null
+++ b/doc/version-client.texi
@@ -0,0 +1,4 @@
+@set UPDATED 20 July 2005
+@set UPDATED-MONTH July 2005
+@set EDITION 1.12.13
+@set VERSION 1.12.13
diff --git a/doc/version.texi b/doc/version.texi
new file mode 100644
index 0000000..85cc927
--- /dev/null
+++ b/doc/version.texi
@@ -0,0 +1,4 @@
+@set UPDATED 22 September 2005
+@set UPDATED-MONTH September 2005
+@set EDITION 1.12.13
+@set VERSION 1.12.13
diff --git a/doc/writeproxy.rtf b/doc/writeproxy.rtf
new file mode 100644
index 0000000..5069326
--- /dev/null
+++ b/doc/writeproxy.rtf
@@ -0,0 +1,652 @@
+{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
+{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f14\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;}
+{\f28\fswiss\fcharset0\fprq2{\*\panose 020b0a04020102020204}Arial Black;}{\f29\froman\fcharset238\fprq2 Times New Roman CE;}{\f30\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f32\froman\fcharset161\fprq2 Times New Roman Greek;}
+{\f33\froman\fcharset162\fprq2 Times New Roman Tur;}{\f34\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f35\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f36\froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\f37\fswiss\fcharset238\fprq2 Arial CE;}{\f38\fswiss\fcharset204\fprq2 Arial Cyr;}{\f40\fswiss\fcharset161\fprq2 Arial Greek;}{\f41\fswiss\fcharset162\fprq2 Arial Tur;}{\f42\fswiss\fcharset177\fprq2 Arial (Hebrew);}
+{\f43\fswiss\fcharset178\fprq2 Arial (Arabic);}{\f44\fswiss\fcharset186\fprq2 Arial Baltic;}{\f45\fmodern\fcharset238\fprq1 Courier New CE;}{\f46\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f48\fmodern\fcharset161\fprq1 Courier New Greek;}
+{\f49\fmodern\fcharset162\fprq1 Courier New Tur;}{\f50\fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f51\fmodern\fcharset178\fprq1 Courier New (Arabic);}{\f52\fmodern\fcharset186\fprq1 Courier New Baltic;}
+{\f253\fswiss\fcharset238\fprq2 Arial Black CE;}{\f254\fswiss\fcharset204\fprq2 Arial Black Cyr;}{\f256\fswiss\fcharset161\fprq2 Arial Black Greek;}{\f257\fswiss\fcharset162\fprq2 Arial Black Tur;}{\f260\fswiss\fcharset186\fprq2 Arial Black Baltic;}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;
+\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red255\green255\blue255;}{\stylesheet{\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+\f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\s1\ql \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+\f28\fs20\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 \sbasedon27 \snext20 heading 1;}{\s2\ql \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+\f28\fs18\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 \sbasedon27 \snext20 heading 2;}{\s3\ql \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+\f1\fs22\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 \sbasedon27 \snext20 heading 3;}{\s4\qj \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+\i\f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 \sbasedon27 \snext20 heading 4;}{\s5\qj \li720\ri0\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0
+\f28\fs18\expnd-1\expndtw-5\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 \sbasedon27 \snext20 heading 5;}{\s6\qj \li1080\ri0\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\adjustright\rin0\lin1080\itap0
+\f28\fs18\expnd-1\expndtw-5\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 \sbasedon27 \snext20 heading 6;}{\*\cs10 \additive Default Paragraph Font;}{\s15\qj \li0\ri0\sa220\sl220\slmult0
+\widctlpar\abslock1\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext29 Date;}{\s16\qj \li0\ri0\widctlpar
+\tqc\tx4320\tqr\tx8640\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext16 header;}{\s17\qj \li0\ri0\widctlpar
+\tqc\tx4320\tqr\tx8640\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext17 footer;}{\s18\qj \li0\ri0\sb220\sa220\sl220\slmult0
+\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext19 Attention Line;}{\s19\ql \li0\ri0\sb220\sa220\sl220\slmult0
+\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext37 Salutation;}{\s20\qj \li0\ri0\sa220\sl220\slmult0
+\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext20 Body Text;}{\s21\qj \fi-360\li360\ri0\sl220\slmult0
+\keep\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext21 Cc List;}{\s22\qj \li0\ri0\sa60\sl220\slmult0
+\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext23 Closing;}{\s23\ql \li0\ri0\sb880\sl220\slmult0
+\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext35 Signature;}{\s24\qj \li0\ri0\sl280\slmult0
+\widctlpar\pvpg\phmrg\posy893\absh1584\absw3845\abslock1\dxfrtext187\dfrmtxtx187\dfrmtxty187\nowrap\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f28\fs32\expnd-5\expndtw-25\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext24
+Company Name;}{\*\cs25 \additive \f28\fs18 Emphasis;}{\s26\qj \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033
+\sbasedon0 \snext21 Enclosure;}{\s27\qj \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f28\fs20\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext20
+Heading Base;}{\s28\qj \li0\ri0\sl220\slmult0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext28 Inside Address;}{
+\s29\qj \li0\ri0\sb220\sl220\slmult0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon28 \snext28 Inside Address Name;}{\s30\qj \li0\ri0\sa220\sl220\slmult0
+\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \caps\f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext29 Mailing Instructions;}{\s31\qj \li0\ri0\sb220\sl220\slmult0
+\keep\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext26 Reference Initials;}{\s32\ql \li0\ri0\sa220\sl220\slmult0
+\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext30 Reference Line;}{\s33\ql \li0\ri0\sl160\slmult0\keep\widctlpar
+\tx2160\pvpg\phmrg\posxr\posy965\absh965\absw4320\abslock1\dxfrtext187\dfrmtxtx187\dfrmtxty187\nowrap\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs14\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext33 Return Address;}{
+\s34\ql \li0\ri0\sl220\slmult0\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon23 \snext31 Signature Company;}{\s35\ql \li0\ri0\sl220\slmult0
+\keepn\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon23 \snext34 Signature Job Title;}{\*\cs36 \additive \f28\fs18 \sbasedon10 Slogan;}{
+\s37\ql \li0\ri0\sa220\sl220\slmult0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f28\fs20\expnd-2\expndtw-10\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext20 Subject Line;}{
+\s38\qj \fi-360\li360\ri0\sa220\sl220\slmult0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon20 \snext38 List;}{
+\s39\qj \fi-360\li360\ri0\sa220\sl220\slmult0\widctlpar\jclisttab\tx360{\*\pn \pnlvlbody\ilvl0\ls3\pnrnot0\pndec }\aspalpha\aspnum\faauto\ls3\adjustright\rin0\lin360\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033
+\sbasedon38 \snext39 \sautoupd List Bullet;}{\s40\qj \fi-360\li360\ri0\sa220\sl220\slmult0\widctlpar\jclisttab\tx360{\*\pn \pnlvlbody\ilvl0\ls4\pnrnot0\pndec }\aspalpha\aspnum\faauto\ls4\adjustright\rin0\lin360\itap0
+\f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon20 \snext40 List Number;}}{\*\listtable{\list\listtemplateid-233686978\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1
+\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid-120}{\list\listtemplateid1125679728\listsimple{\listlevel\levelnfc23\levelnfcn23
+\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid-119}
+{\list\listtemplateid937579172\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0
+\s39\fi-360\li360\jclisttab\tx360 }{\listname ;}\listid680279710}{\list\listtemplateid-896887238\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}
+\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \s40\fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1713573880}}{\*\listoverridetable{\listoverride\listid-119\listoverridecount0\ls1}{\listoverride\listid-120\listoverridecount0\ls2}
+{\listoverride\listid680279710\listoverridecount0\ls3}{\listoverride\listid1713573880\listoverridecount0\ls4}}{\*\revtbl {Unknown;}{Derek R. Price;}}{\info{\title Ximbiot}{\author Derek R. Price}{\operator Derek R. Price}{\creatim\yr2004\mo6\dy10\hr18\min22}
+{\revtim\yr2004\mo6\dy10\hr18\min22}{\printim\yr2002\mo10\dy21\hr15\min9}{\version2}{\edmins13}{\nofpages4}{\nofwords1284}{\nofchars7323}{\*\company The Nature Conservancy}{\nofcharsws8993}{\vern8229}}
+\widowctrl\ftnbj\aenddoc\revisions\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dghspace180\dgvspace180\dghorigin1701\dgvorigin1984\dghshow0\dgvshow0
+\jexpand\doctype1\viewkind1\viewscale114\viewzk2\pgbrdrhead\pgbrdrfoot\nolnhtadjtbl \fet0{\*\template \\\\RECOGNITION\\SharedDocs\\derek\\Ximbiot Cover Letter Template.dot}\sectd \linex0\endnhere\titlepg\sectdefaultcl {\header \pard\plain
+\s16\qj \li0\ri0\widctlpar\tqc\tx4320\tqr\tx8640\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {{\field{\*\fldinst SYMBOL 108 \\f "Wingdings" \\s 10}{\fldrslt\f14\fs20}}}{
+ Page }{\field{\*\fldinst { PAGE \\* Arabic \\* MERGEFORMAT }}{\fldrslt {\lang1024\langfe1024\noproof 4}}}{\tab \tab }{\field{\*\fldinst { TIME \\@ "MMMM d, yyyy" }}{\fldrslt {\lang1024\langfe1024\noproof June 10, 2004}}}{
+\par }}{\headerf \pard\plain \s33\ql \li0\ri0\sl160\slmult0\keep\widctlpar\tx2160\pvpg\phmrg\posxr\posy965\absh965\absw4320\abslock1\dxfrtext187\dfrmtxtx187\dfrmtxty187\nowrap\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+\f1\fs14\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {Ximbiot
+\par 319 S. River St.
+\par Harrisburg, PA 17104-1657
+\par }\pard\plain \s16\qj \li0\ri0\widctlpar\tqc\tx4320\tqr\tx8640\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {{\*\shppict
+{\pict{\*\picprop\shplid1025{\sp{\sn shapeType}{\sv 75}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn pibName}{\sv C:\'5cMy Documents\'5cderek\'5clogo-122x62.bmp}}{\sp{\sn pibFlags}{\sv 2}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}}
+\picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0\picw4306\pich2187\picwgoal2441\pichgoal1240\pngblip\bliptag1030499068{\*\blipuid 3d6c2afc3a1742ff238b2c9643563b41}
+89504e470d0a1a0a0000000d494844520000007a0000003e08020000006bf298c9000000017352474200aece1ce9000000097048597300000b1200000b1201d2
+dd7efc0000149149444154785eed9c0958cd591bc0555ab42f4ad2265ba8ec4cf665c63e962144c5d89b92b2642711b233441431d977c932f6b52c635fc796c1
+50a850a494ef57c7dcb9eecdedd637cf37bef47f3c9edbf9bfef59def39e773f7f950f1f3e14cbff93fe3e5dbdb8ba4a3195fca37ed518aaf95d7d5a46daca03
+e1df8d6f16171f376695ffaa832bf2dbc3d70c9f6f725f89bb3c3c6ca8b37dfd6b7f5c8d3810ee685b2d57f2a5a4a53c497c92f521eb6b26aefcdaf34dee981b
+2733b3325d1a76db19bbad7685bad5ed6ac8778a805aba7bf1ca0361c50a24a90af10ee58fdc371fdd58be2f1472a8aaa83d7af1e8d2bd8be919e9f2d4b978ef
+fc1f090f52d3529f263f2dc4b42bc0d2f241ee47cf1f0e59eaf92021cea56177075bc7e2aac551981f8ac96ada94b729fe2b477472fea18943d3cbf72f15604e
+8518251fe40efb75d9e95bb1d0a25ad9eaea6aea9f238a8e964ecd72b59e263d397ff7b772a5cb1762da156069ca92fb7de67bd1bba981d937f6f5f9a1a6aa96
+fefeddf030df53374e4a0f7cf7e99d62c53eb4aad9e6e48d132f5ebf28c09c0a330a6a2dcf272139c16d760f7d17ad2a9e158e5d3d22e097ee09b17037d5efaa
+d57c4c23490f8f5f3cf65e3238e975e2818bfbbbcdf8814dcab3f3af0a206fee4e7c9dd87781c78ed86d18217b26ef6f54b589e0be01ad069d9b7fd144df24f5
+5daa6881704b762fda7862c386e3ebf17f1c6d9c3801859955f3bfb63cc80d0587867a1dbd72989eaf3eb8323a62e4bb8c7762145515d5d2c616d204c5ca7efb
+ee6d538766ba5a3ad5ec6ac4dc3c85f59dff2915668cbcb91bfeb531b3d12ba197f13ee3e0c5fde76e9f91d0e3e2bd0b1054a236717c2edc3dff67e26333c352
+872e1db02c695542a34461265efed79607b9555454e60f5c7465f1adfead06c1ce6fd3dffe7a619f6494053be7625ceb96d0132d8f5f3c72b4751cf1c3a86f2a
+39ff7a7e6f53c766a0e47f4a8519435972d42a5f5b488f9e4ddd043d32323384b952d1a2a2687995fa8a4664cea2e88595adab74a8d789dd2accc4cbffdaf226
+378eccc14bfb7170de67bd4f7cfde269d2474771e3f175bbceec6c50a5d114f7e962dce7af9ec1d7d885ce95ea5b95b4d6d6d4ceff7c0a3946dee44e79fbda2b
+6470524a12ac5ab18cbd55492b4872e3e1b571abc79432320ff359a9afad2f88e4d5dea765cd36152c2a24a52655b57128626d79dec99bdcea6a1a6686666036
+a8dcf0e0b4a376e6e530f9bc9678c2e9595959fd16f4f65d3604992eba4ecf7857b694ddfbcc8cca56550a39a316687979937beba9cd8863071bc7309f082d75
+ad9c51542c8c2db055925212111d5b6336bf7af38a560cc1b54723dbd5f91ecf333333f3d48d13d71e5c3df3fbe917af9f17686e851149815387265cbe77a959
+2f23ab3ee697ef5f948624067b35ee7255cf8a263df4561d58019bf396ff1f3e7b78f0d28117af5eec39b79bb76c552d1f47625b5f95eba860b18ab83bf2f0ea
+912b86991998adf25b239d46c8cacadc732ebadb8c2ec4a166f79fefdea28f10d3fc6f59d2b27ad91a86ba866857db52659fbd4ca86455b98c89656164d402ad
+e9735b7135ee8aed8f161506d810b99686494b4ff35de66dd45d877fd3374d85cde57bd87d7697594fc3512b87cfde1afccdf05a45ac2da140eedc8dbbe83acb
+25393579c1a0102b536be97d3cfbfbe995fbc39133107a51d4c27b4fefc9ec321ced193210f3b167137772c7054b3d178873fe0f90722137f6f5a045fd9e24fe
+39b8ed4f088d199b8210ca92a5100c19df63520dbb9ad0514753dbe02f2b5000a02d4929105771b66f6053ca564b438bc3f153c8c0e4d4a4ff0362fc0fa6287f
+d2d71e8924d66ad9dbccb66f19bdae9ad5bcab20a3a5c1a24eef28d5cba87c7f6bf29632fa3324fa6773376376ebc5abe7bc02714498af710fdddfee9c2b1229
+502017eede707c2d2f5ea6be8464683fd8bcf3d4efff78f640ec3d14f45eea89a1fd53bb21752ad6936688ad27374d8c1c47f692b8a08e962eaf4a199afb74f4
+5353512b12298250b2e4bef5e826ff2444844c5016bbbbf75c378435ed98dee549897d283675fd64d2edd2e4d6d731685fa78386ba26c1712c13f18ae02d725c
+41b2ed7f7082bf9c213e21f7db776f7e9cef41460615271e3151633d132253aaaad9c086ba46d101bf8eeb3111ea9fbaf949daac658dd6e1beab5a546b012291
+42817be4ca6162e29a1a9a5fce9affc5997c42eef4cc0c1c4566a3a7ad478c891f849908ec1d9a769cdc8da4444d535d53af843e5af1fc9ddf304224694cc1cb
+27af9fa09e2dc7d72f76fd8f6b84c8fbb51c58cebc28472c274c0cb40db68d8f5a337243af661e64092a95b13f161cb36ad89afbf1f796ed5d2a4d56827f6013
+e03e7ef5a810323c1824a32246920eae59ae36ced1cbd464bfe543ec4a97f76ce75d14aefa78a4640c0668ba60c75c836e25eaf855a7a424f6e6a946fedf60a8
+1877d725692980e393e3490763b4541c607be3e175490fcf5e3eabe9e3d878943314a71123d2a89b0e88d82a846a8b2c1359cb043efd396a41c0da09f6969597
+7baf5873e497ce411d7079a8e099e01a60a86328b6c86fd990b33929b427494f24853b582cd8d7e8d508bf48635d63de36716cb6c67f83b991b9a58955556b87
+7f51627e41434b980e5f06be86196b0d755abc6b217c0afff20f679d76e91286fe0bfad06ee052a2ef7c8fe72f9fd1038ab143601b0ec4995bb1a243243bb6f6
+77e39ad2cfcd87378a585b5020bb5a219b3a59590b77ce33eca68ddcb0eb67c50f1c99d26e26907544b81fd15409bd30c6bb4ceb483bbe0cc29a76fe1fbf7a4c
+d9be65b0202560d0ddb27729b684000b39e522720b0a7cb44c769fdb858722941e769b6b935e4e65ab93656f5dabede45e538509c883a4ae37ac16695f8c93f8
+a4f83111238958e14952ecead2b0c789ebc7a1ac80d4d6d4a95da10e8804c449607e41c7f95f9dca473ae234c2e03a9a3ac33bfb9f9e7b1e318d926c53bb5df8
+d00849ca312ee1feac2d33e2738a5ae1e843970f6c8fdd0ae292e845d8881107574c5937e9c2bdf3623965cdcb927fc0ab0cf50e2b2a7ff87b8b059313fcdb16
+b385e40bba8e2c3042a0d9e886344a0b81c0b5939021045228f4d911bbfd7efc7d4c91fd17f609112fa4b9fda07254f38045e01089547f781d4cef224922a1c0
+47d92dfe26ffdb23b82be2bbf3d4f6844a64c844e5dff93be7dea4a5de797267ddd135bc85dc04b020342882e2d67dcc1135bc42aaac3fb6163540884ae47a8a
+9ebf6537dc4eb136776da2cf46916c5c3d7c9db95169192987fb5e5c4ddd636e2f8cee981cf79d243da7816a2933835214f7746fe47a78fa8916d5bee35571b5
+e24d1d9b33005a81acd0bf2a30bfa0c13f86fff121fd96fbecfd6db7936db51d13a2d5548b63591fb8b80fa33b3327d8ada9ae31aefbc4db8f6f0f09f544912e
+f60c15d581949d046d08dc756647a877381510a17b97903c1bda7118af7e7f7cabe9e8061aea1a4bbdc25bd76af3052dfa5f9c8a38e34b762f4614b418db3874
+4f48bff9bdcbf5b34210d352d2d580e4af10141b8eadc3b11cb57284857b4981c5811819ee67d3a734afa6ae0f34ed6960ea6ab0e5e4265ebd79f786db696095
+eb6f8daf5f24490405b22d93ccacf7f5ed1b34736a8eb7e2bf6238850c7adafafd5b0ddc3276c73aff8dd87c1827411ec15d1b7633d235faa17e170485304e26
+fc3276d5a188efeb759cb13968e6966934ce1fb4a8b373979c3e33935392103ebd5bfc5852dff473fc8436660bd99b5c011882b76814260a00e515fcfe6f6eb3
+e16610c96162f2775ca4278084645c98e99f3f06ac64eeb659383570a2694fc34e53da13d243d1118cc5b7b4ee539a24efee73d112f64474f49edb0b2773ecaa
+519c00a22256bd4b397957266533655d80d08a4c943ecddd4c5ca67792f67de479dc37d49b711bf93b73a347e62d4350c3cfdb5eb3ba0b47a9d584e6845ffe9b
+320abc84ea43aaa0c0f9a1e0c0cddc3c9d71379dd8f08f1fca6cee26a0d1bcdab7c37ff03f1e1c03473b57aebfeffc9e3693be83a06fdea52288b9d424f699ca
+296c92ae0dbaa124230faf2aa1a90dd6548f19a47efab71ce4df750c913f28beedd416022fa96929fbceef1db0f04749c8509e5926bb4db531b3e5a61a710299
+b75b4e6e8c3ab3d3d4c07456bf79e23c7dc90fecd23db88be7e201794c527e0331a5615521afb1f0889920af01838e04a73a04b6e58c43c1e3d78e61a763f695
+ed6b3960615f09bf24bc4c70f4b26f3da1c5d2dd21685a2eb32ae691a3578e10a841e85fba774102199ff414fdc1e8db63b64a1a09af039c96feb6c04ca72477
+c7c5df3f74e92073507e20f20418c1757cab2b46c92557594243bba245a50a16152b59da1be91a73a84bea9764d3e0415ca1d9fde66914d7a0f8b841958618e0
+7de6b973a575c1a0458878b1b1a6faa69c92f13d0228bcd22fa14f4450f1863772683cb08d2777bf7d97fb88ab11cc1893946d736fde07c52041af51ae666387
+269a1f0be73ee995ed671b648e11bdd1ad82d1515af258c073e0d0645c0a90c7055e727fa320a74dc16e3c487860d5db9cda33dc19c090a11455097816b6f1f8
+7af89a4015e7889bdbe42dc95ef26ff5a108d8b0a4ab3e353dd9172f95789253929d87d7d6ebaa3567db2cc077c66e87af71a01292e3a5b117ec9ce7bf6218de
+96689cb77df6b8d5a3116b8ba216341c59cfc9cb1e4f185947400d1bd47db66bf52155e90405c029142812ee462a066f9a567f441db01afb3b076f9e863c948c
+c591c57396ae1e60211428b40f680d3cdd922ba71c4112b9239a8f1861c954f7818860fcdca21515ad6d8bd94c7d886fa7e170370b3876ede890ef7dc59662c3
+4c881c4b99ab918ed1b7e39a604142dcd50757326fa6c5754a18134342c98cb0818ec1dcfe0b31ede76d9b858c1a153102a37e4efff994764a73d0eeb351eca5
+e4e615927dcde1d55e4b06cfdd3e9b8368675e1e02b1ec29eb035a4d684130a76ec57ac4c8c853bbceec0a35255d2115d128411b03611412d997e32ec1259da6
+b61785a539e7f8c28afd61f79ede157f72be31d8e8f9c4f563eac5356821f1ed3ec775f2ba09c24ce232f5dedff6a0cfd97b484f2dea6719ff73fb80b58424c2
+121056f3ac2dc144b725c0389f9da6b42be3615a69a01d2c76ecca112a31a93c210640ae07b0b07dcbe03e2538fb6f904991e38575c4ffc41ae571652c93e663
+1b03d960445d710820220c2b540e2e9b08d043d0da43abd1426a49c2ddfc89b9853e874080c1fb22b8cfd11183ca5826a459b8cf587970792ea513dd048bf89d
+5d3f4b836edabbce44014f27cc2147765743d4280838e7cedd7481e3c3a60deb34d2c2b80c028bbb0ae488259bb6f9c4c637e96f037a4e39312b76509b9fa2cf
+45b9ce7481a9170e0a214bc9f05167767093355fd26db4cbb8b2e6768c451c716cf7894ae2121f168700a3c8ad796f7e7016037a060aa7972bcc5d1a74e50706
+bb7487deed7db8468ec1035815ebaa4bbc96a390220fff227f550e52a0f3f970cbcf83429cca5623b10556bd4ace33facca63475f9bea530389d900dcfe95f85
+7e14d851b9939bb836821259e1d9d68b3eb6c76ea35362df9219870d8dd813b09ffb5194eff49ce91212bd083b9d6b67bf1c8a000676e09203075c499209b0d3
+b762b0a9f941de19f6511297af4e482045a4b77ce90ab8699246addc6ebfb9fe75c34880d5a9509732bc94b4d7f297f85fbd7979e9fe05f27fce951b484f0966
+32d133e11e1efa40c9a902960bb9392f63578f7a979116e81644e009e54ea2c7e77b5f89ed918da68254ccc6453a0f6eeb059b538892fe3e031233bf657b9704
+9094c8cfb533e4e6b0301f940fdf37a05b140e69236596217f535655554df167842838b0fcb4069a93e160eb0423c7c5cb5698c625c4d14ef1b4cc5523ce0db1
+39a68d1da1cc3c054c2ee4a63cfef0a5833d9bb87d5bbd2510b71ffffefcd5738e5eae9d72707a35751fd67924d6451387262d6bb65e7324123f9e9d577e12ac
+67ec2affdb7fde6e5fb743e89070d01f3e7fc8955905fe91f29dcb4372dee50b31c4c9c027968117a92869561300d9b54a3926297ca9fc6464c97df7c99de99b
+82ca989409749f2618e7e4f5e37cc1415fdb4041a75c60254946750a1c8d85e4d1bc8ff2330012c5cb2d13422b33fbce41380679cc60b7369fdcc8e5877cf5a3
+2470624aa2bced4c4c1474f9b0b3a82aa08a5a26568369886bc3b611475272dc5cb81b0388ae47761d2386e1397ce5101e8d821e993ab6175f38419792c44153
+09b748c9277bb815c3d0aed37a07a396c1e2f6261131581b0617d2fc9f7de899b890749fc884d89b3170bd93ad93cc58d6a636081fb8f069e213e95714e1e07c
+5a9b5a2b664499de3ee16e2273bbceee34d031ecdea88780236207db7e57a3958205c3ce27ae1d0bec1584765e1cfd332e22d25349021199e3131dd89aad6bb6
+11525b3cdd1af5685ba73d3b814987a851b237e5c182b74c97dc96836d7f8e9a0f7737cdcd93445ae2d962b1ccdf3147c2e0fcc05447ce908a9197330aa6f109
+b9a96e9dd86372a857187974810329b9144cf5dae7baa09a677ce4184c949ae56b916fc39ba8f76915b262126c3abe81fc32a26366dfb9d24a8f454ef30836d6
+33265816feeb72e5e9a80c241203d3ab5d404bfc32c27e382ca4bc6132ccc75cd1b9768eadc9074508856201939cc2ab249e81afefd769c45f2894afaa24bc8c
+47ae72143e378d4fc88db1d1a5810b6c25a0d9c39da7b7d3f2b90a3f7873dac6299c35df8ec390da1882843584dfa5cc436d1b1fe460d293dd8250fd32281475
+06f4cc8e17461c0cff33f14fde628f5b99da90691290446378aba2faf73d70e64f8b4c9486c34e2386042894f45a185b1278a13ee0ee93bb14aa732f14960260
+cd880d0e361f2509a4cf46f98be798c9a6d15bf946110e2adf1aa1588cca53be35b771f456a624264326ab865d0da2e4442300f8dcf215dd9db9f6e00a199933
+f32e729f2c577c1cc8ba7ed527ba06f66b991d781cbaccab63bdcec47295a13530c85011c2e754e5baa3d97e608ede47aac2fb28093840022cfe94aeaa60fbb1
+82d978e9038e56e0d48b1ee80a00c6caae93498e27e3fa2c39a19c4505dc7ddd9cfa7ff1c8a088462c103ef774f3e1cde26a78460e8eb64ef429bdd2d76f5f53
+ee8bd350d9ba2a577e732782023f9b53437d9a020022277c784d1460122e6836a6a17c96205f7e7ca107fec76e8671d008cd04ff384749d6fe3ac1144504f34511a43ce644be50be42e07f8cbb1123a8a3a2b279c53cf41f28e010a17baaa1700000000049454e44ae426082}}{\nonshppict
+{\pict\picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0\picw4306\pich2187\picwgoal2441\pichgoal1240\wmetafile8\bliptag1030499068\blipupi71{\*\blipuid 3d6c2afc3a1742ff238b2c9643563b41}
+010009000003d62c00000000b22c000000000400000003010800050000000b0200000000050000000c023e007a0005000000070104000000b22c0000430f2000
+cc0000003e007a00000000003e007a0000000000280000007a0000003e000000010018000000000020590000120b0000120b00000000000000000000ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffff3f6f3fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5e9062cadbccffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaec7b0729e76ffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffa2bfa4609164ffffffffffffffffffffffffffffffffffffff
+fffffffffffffffff5f8f599b99bedf3edfffffff3f7f43c7941f4f7f4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffd2e0d4135c19e3ebe3ffffffffffffffffffffffffffffffffffffffffffffffffe8efe818601e9ab9
+9cffffffffffff6a996ebbd0bdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfdfcf6f9f6f6f9f6
+fefefefffffffffffffffffffffffffffffffffffffffffffefefef6f9f6f6f9f6fcfdfcfffffff8faf8f6f9f6fefefefffffffffffff8faf8f6f9f6ffffffff
+fffffffffffffffffefffef6f9f6f8faf8fffffffffffffffffffffffffbfcfbf6f9f6fcfdfcfffffffffffff7f9f7f8faf8ffffffe8efe8adc7af97b79abcd1
+bdf3f7f3fffffffffffffffffffffffffbfcfbf6f9f6fcfdfcfffffffffffffffffffffffff7faf8c4d7c69cba9e9fbda2cbdbccf9fbf9ffffffffffffffffff
+fffffffffffff2f6f2adc6af98b89bc3d6c4ffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffdfefd50865492b495fffffffffffffffffffffffffffffffffffffffffffffffffefffe69986d317136eef4efffffffb1c9b37ba47effffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecf2ec3b7840276a2c9fbda1ffffffffffffffffffffffffff
+ffffffffffffffff9dbb9f276a2c36753be5ede5ffffff5a8d5e317135e7eee7ffffffffffff568b5a276a2cf4f8f4fffffffffffffffffff0f5f0276a2c5b8e
+5fffffffffffffffffffffffff9bba9d276a2cafc8b1fffffff8fbf9467f4a5f9163adc7af19601e07540d07540d07540d296b2ec0d3c1ffffffffffffffffff
+97b799276a2cb4cbb6ffffffffffffffffffcbdbcd37753c07540d07540d07540d09550f417c46d5e2d6fffffffffffffffffffdfefd4a824f07540d07540d41
+7c46ffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffffffffffffffdfdfdaac4acb3cab5ffffffffffffffffffa0bda23d7942
+fefefeffffffffffffffffffffffffffffffffffffffffffffffffe6eee72267277ca57ffdfefde3ece449814df9fbfaffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffa7c2a907540d1a6120dee8dfffffffffffffffffffffffffffffffdce7dd19611f07540d99b8
+9bffffffffffff427d47125c18e3ece4ffffffffffff3e7a4207540df3f6f3ffffffffffffffffffeef3ee07540d437d47ffffffffffffffffffffffff8cb08f
+07540da4c0a6fffffff8faf82a6d30206525115b163c79419ebca1a8c3aa568b5a09550f175f1cd1e0d3ffffffffffff87ac8a07540da9c4abffffffffffffdc
+e7dd1d632207540d588c5ca9c3aba1bea34a824e07540d276a2ce7efe8ffffffffffffeff4ef19601e19611fd3e1d4dbe6dcffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffff5f8f5296c2e175f1cf4f8f5ffffffffffffeff4ef175f1cd6e3d7ffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffa9c3ab155e1bcadacbfdfefd588c5cc2d5c3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffefffe598c5d07540d508655fcfdfcfffffffffffffffffffbfcfb53895707540d508654fefefeffffffffffff427d47125c18e3ece4
+ffffffffffff3e7a4207540df3f6f3ffffffffffffffffffeef3ee07540d437d47ffffffffffffffffffffffff8cb08f07540da4c0a6fffffff8faf82a6d3007
+540d3b783ff6f9f6fffffffffffffdfefd81a88407540d4f8653ffffffffffff87ac8a07540da9c4abffffffffffff65956907540d719d75fdfefdffffffffff
+fffdfefd5a8d5e07540d739f77ffffffffffffeef4ef18601e307035ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffff77a17a07540d9cbb9effffffffffffffffff5288568fb292fffffffffffffffffffffffffffffffffffffffffffffffffffffff8fa
+f8538957457f49f8faf8c5d7c7598c5dfcfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9f0ea
+23672807540da5c1a7ffffffffffffffffffa3bfa507540d1d6322e2ebe3ffffffffffffffffff427d47125c18e3ece4ffffffffffff3e7a4207540df3f6f3ff
+ffffffffffffffffeef3ee07540d437d47ffffffffffffffffffffffff8cb08f07540da4c0a6fffffff8faf82a6d3007540db4cbb6ffffffffffffffffffffff
+fff1f5f12266270d5813e8efe9ffffff87ac8a07540da9c4abfffffffbfcfb165e1c135c19e4ece5ffffffffffffffffffffffffd9e5da0c5712266a2cf8faf8
+ffffffeef4ef18601e307035ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffdbe6dc1d63
+22236729edf3edffffffffffff94b597538857ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3e1d4185f1da8c3aafcfdfc457e49
+e8efe9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb1c9b30b57111c6221e4ede5ffffffe5
+ede61a61200a5610a8c3aaffffffffffffffffffffffff427d47125c18e3ece4ffffffffffff3e7a4207540df3f6f3ffffffffffffffffffeef3ee07540d437d
+47ffffffffffffffffffffffff8cb08f07540da4c0a6fffffff8faf82a6d300a5610f0f5f1ffffffffffffffffffffffffffffff5b8e5f07540dbacfbbffffff
+87ac8a07540da9c4abffffffdce7dd07540d37753cfdfefdfffffffffffffffffffffffff9fbf92d6e3208550ee9f0eaffffffeef4ef18601e307035ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffff98b89b08540e67966bfcfdfcffffffd1dfd2
+206525f0f5f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5388574a824ffafcfa94b59688ad8bffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe67966b07540d578b5bfbfdfb5d8f6107540d609164fcfdfcffffffffff
+ffffffffffffff427d47125c18e3ece4ffffffffffff3e7a4207540df3f6f3ffffffffffffffffffeef3ee07540d437d47ffffffffffffffffffffffff8cb08f
+07540da4c0a6fffffff8faf82a6d301c6222f7faf8ffffffffffffffffffffffffffffff76a07907540da1bea3ffffff87ac8a07540da9c4abffffffcadbcb07
+540d4d8451ffffffffffffffffffffffffffffffffffff3f7a4307540dd8e4d9ffffffeef4ef18601e307035ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffafcfa4b834f0b5711b6cdb8fffffff7faf73473399ebca1ffffffffffffffffffff
+fffffffffffffffffffffffbfcfba2bfa48aae8d6394670b5610b2cab4f0f5f135743aecf2ecffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff1f5f12c6e3209550f5e90620a561024682aebf1ecffffffffffffffffffffffffffffff427d47125c18e3ece4
+ffffffffffff3e7a4207540df3f6f3ffffffffffffffffffeef3ee07540d437d47ffffffffffffffffffffffff8cb08f07540da4c0a6fffffff8faf82a6d3016
+5e1cf6f9f7ffffffffffffffffffffffffffffff6d9a7007540da2bfa5ffffff87ac8a07540da9c4abffffffcfded007540d467f4affffffffffffffffffffff
+fffffffffcfdfc37753c07540de0e9e0ffffffeef4ef18601e307035ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffd4e1d5135c18317136f2f6f3ffffffa5c1a72e6f33f8faf8fffffffffffffffffffdfefdfdfdfdfffffff6f9f63775
+3c07540d07540d105a168aae8dffffff9ebca068976cfdfefdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffbed2c00c581207540d0a5610b9cfbbffffffffffffffffffffffffffffffffffff427d47125c18e3ece4ffffffffffff3e7a4207540df0f4f0ff
+ffffffffffffffffeef3ee07540d407b45fefffeffffffffffffffffff8cb08f07540da4c0a6fffffff8faf82a6d3007540ddae6dbffffffffffffffffffffff
+fffefefe3f7a4408550ec4d6c5ffffff87ac8a07540da9c4abffffffeff4f008550e25682af5f8f5fffffffffffffffffffffffff1f5f11a6120155e1bf5f8f5
+ffffffeef4ef18601e307035ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+fffefefe84aa8707540d87ac8afffffff6f9f7307035aec7b0ffffffffffffffffff5d8f61427d4698b89beaf1ebe2ebe2739f77115b16427d47eaf0eaffffff
+fbfcfb4b834fd5e2d6fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9f7296c2e07540d1f
+6424f3f7f3ffffffffffffffffffffffffffffffffffff427d47125c18e3ece4ffffffffffff3e7a4207540dbacfbcffffffffffffffffffe5ede507540d1b62
+21f0f5f1ffffffffffffffffff83aa8707540da4c0a6fffffff8faf82a6d3007540d7ea682ffffffffffffffffffffffffc8d9c90d5813155d1af3f7f3ffffff
+87ac8a07540da9c4abfffffffefefe39763d08550ebacfbcffffffffffffffffffffffffa8c3aa07540d4b834ffdfefdffffffeef4ef18601e307035ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffeff4f0307035125c18e4ede5
+ffffff89ad8b5e9062ffffffffffffffffffb3cbb54b8350155e1b22662778a27bc0d3c2bcd1bd1e6424548958e9f0e9ffffff9ab99c8cb08fffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ca47f07540d105a1507540d75a079ffffffffffffffffffffff
+ffffffffffffff427d47125c18e3ece4ffffffffffff3e7a4207540d36743be9f0eafffffffefefe86ab8907540d07540d6e9b71fcfdfcfffffff4f7f42f6f34
+07540db5ccb7fffffff8faf82a6d3007540d105a16adc6affbfcfbfcfdfcd4e1d52d6e3207540d729e76ffffffffffff87ac8a07540da9c4abffffffffffffa3
+c0a508540e246829d0ded1fbfdfbfbfcfbc6d8c81c63220a560fb3cab4fffffffcfdfce9f0ea18601e2f7035f9fbf9fbfcfbffffffffffffffffffffffffffff
+ffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff8db19007540d99b99bffffffd8e4d918601de2ebe2ffffffff
+fffff2f6f2226727467f4a749f78337238105a161e642420652607540d447e48f1f5f16e9b717ba47effffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffc6d7c70e5914165e1cc1d4c22468290b5711bad0bcffffffffffffffffffffffffffffff427d47125c18e3ece4
+ffffffffffff3e7a421a61205b8e5f1d63225f91634c835008540e0a56107da5801c62213a773f6293662c6e3107540d286b2ef0f4f0fffffff8faf82a6d301b
+61204e855308550e296b2e2f70340a561007540d3d7941f1f5f1ffffffffffff87ac8a07540da9c4abfffffffffffffbfcfb6d9a7009550f0a56102e6f332b6d
+3008550e0a56107aa47efdfefdffffff89ae8c1c622109550f0b57111d6323528857ffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffe1eae1185f1d26692bebf1ebffffff578b5b729e75fffffffffffffdfefda8c3aa1c6221639467f4f7
+f4d2e0d395b69881a88481a884a0bea2cddcce0e591489ae8cfafcfaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+f0f4f034733908540d8baf8dffffffb0c8b208550e2a6c2fe9f0eaffffffffffffffffffffffff8fb291729e76eef3efffffffffffff8cb08f78a27bf3f7f491
+b39437753c286b2e3c7841a5c1a7fdfdfdd9e5da598c5d2b6d302a6c2f588c5cd4e1d5fffffffffffff8faf82a6d301d6322edf3ee86ab8935743a286b2e3976
+3e86ac89f1f5f1ffffffffffffffffffb8ceba6b996fccdccdfffffffffffffffffffafcfaa4c0a648804c286b2e2b6d304d8451b1c9b3fdfdfdffffffffffff
+b2cab46595690e591418601d6b996f8eb191ffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffc3d5
+c43372382d6e322f70341a611f07540d88ad8bffffffccdcce1a6120d9e5dafffffffffffffefffeb0c8b1155d1a729e76f6f9f6ffffffffffffffffffffffff
+eff4f0c3d5c466956adde7defffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffe75a07807540d3d7941f8faf8fffffffe
+fefe5e906207540d68976bfdfefdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfdfcf6f9f7fcfdfcffffffffff
+fffffffffffffff8faf8f7faf7fffffffffffffffffffffffff8faf82a6d301d6322f8faf8fffffffbfdfcf6f9f7fcfdfcffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffff6f9f7f8faf8ffffffffffffffffffffffffffffffffffffeef4ef18601e307035ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffb9cfbb0c581207540d07540d08550e0b5711
+749f77fffffffefefe6d9a714a824ef9fbf9fdfefdc2d5c3d4e1d5b8ceba1c6221629265f8faf8ffffffffffffeaf1ea286b2d437d4896b698cfded0e7eee7ff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0d3c10c57120f5915cfded1ffffffffffffffffffe8efe91d632308550eaec7b0ffff
+ffffffffffffffcddccec0d3c1f7faf8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffff8faf82a6d301d6322f8faf8ffffffffffffffffffffffffffffffffffffffffffffffffffffffdfe9e0bdd1bee8efe9ffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeef4ef18601e307035ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000ffffffb7cdb9558a597da680d7e3d8fdfdfdfefffeb2cab43b784009550f0e591482a985f5f8f5ffffffffffffecf2ed276a2cb1
+c9b3eff4f018601e135c1881a8849fbda11a611f739e76f9fbf9fffffffdfdfda7c2a908550e07540d08550e39763efcfdfcffffffffffffffffffffffffffff
+fffffffffffffffffffff0f5f1276a2c07540d82a885ffffffffffffffffffffffffffffffa6c2a90a560f1c6322e6eee6ffffffffffff427d47125c18e3ece4
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8faf82a6d301d
+6322f8faf8ffffffffffffffffffffffffffffffffffffffffffffffffffffff87ac8a07540da9c4abffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffff3f6f3528856649468ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff8b
+af8e115b1707540d105a154c8350c4d6c5fbfcfbf6f9f792b49519601e105a16b5ccb6ffffffffffffffffff82a9855b8e5ffcfdfc77a17a09550f0b5611175f
+1d296c2e0c581280a783fefefefffffffafcfa8baf8e135c18508755d8e4d9ffffffffffffffffffffffffffffffffffffffffffffffffffffff6c997007540d
+39763df4f7f4fffffffffffffffffffffffffffffffcfdfc588c5c07540d578b5bfbfcfbffffff427d47125c18e3ece4ffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8faf82a6d301d6322f8faf8ffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff87ac8a07540da9c4abffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffbfdfcd0ded149824e33723809550f0b57
+112b6d306f9c73b8cebab9cfbb145d1a115b1790b292fdfefdffffffc7d9c918601efffffff8faf8749f77115b1668976c2c6e3108550e0f5a15a3c0a5fefefe
+fffffff3f7f33070350c57117fa782f9fbf9ffffffffffffffffffffffffffffffffffffffffffffffffeff4efedf2edf5f8f5ffffffffffffffffffffffffff
+fffffffffffffffff8faf8edf2edeef3eefefefefffffff1f5f1eef3eefdfefdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffefffeeff4f0eef3effefffeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+f6f9f6edf2edf9fbf9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff95b69707540d3e7a4396b7995f90631d632309550f07540d0f59140d5813
+07540d07540da7c2a9eef3ee749f77145d1afffffffffffffafcfa719d7519601fa7c2a982a8840f5a150f5915abc5adfffffff6f9f6417c4507540d1e6423e4
+ede5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000ffffffffffffe4ede552885608550e37753cecf2edf0f4f0bacfbb739f77427d47407b44407b4446804bc4d7c69fbca108550e63
+9467fcfdfcffffffffffffe7eee769976c1a6120b7cdb9c5d7c75c8f608db090ffffffffffffd8e4d9135c1919611fb6ccb7ffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+fffffffffff9fbf965956807540d558a59f3f7f3ffffffffffffffffffffffffffffffffffffffffffd1dfd250865419601e6a996effffffdee8df2166262468
+291f6424145d19609164dce7ddfdfdfdffffffffffffe8efe81c622124682aa0bda2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffeff4ef5489580855
+0e4c8451e6eee7ffffffffffffffffffffffffffffffeef3efccdccef5f8f6dce7dca5c1a7ffffffebf1eb2a6c2f07540d08550e07540d07540d18601eb8ceba
+fffffffbfcfba6c2a81d6322709c74fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffffffff0f5f0adc7afd4e1d5f7faf769986d09550f3c7841f0f5f0ffffffffffff
+ffffffffffff7fa68207540d1b62206b996fb0c8b1dfe9dfebf1ebb9cfbb07540d07540d07540d09550f236728c6d8c7ffffffc9dacb0a561035733ad5e2d6ff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000ffffffffffff93b59608540e125b187ea681eef3ee75a07907540d528856f1f6f2ffffffffffffffffffdee9df5d8f6107540d07
+540d07540d08550e1c6322d8e4d9206526165e1c115b161a6120c8d9c9fffffffffffff4f8f5598d5d236728cdddcfffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffb2cab40a561007540d08550e206525659569417c4507540d518755f5f8f5ffffffffffffffffffd5e2d61f642407540d0e59144c83506e9b72f7f9f78cb0
+8f155e1b739e769bba9dfafbfaffffffffffffd3e0d44c84500b5711317136f6f9f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffefefe8fb2920a561008550e1d63
+220a5610115b17135c1907540d719d74fdfdfdffffffffffffffffffecf2ed4f865307540d639467f9fbf9fffffff9fbf979a27c1b6221d8e4d9ffffffffffff
+ffffffc8d9ca175f1c09550f6c9a70fbfcfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffffffffefefe8eb1910c57122e6f3392b4952d6e3207540d07540d0b5711
+8eb191fcfdfcffffffffffffffffff60916407540d09550f5e9062ebf1ecfffffff5f8f549824e307135c8d9cafffffffffffffefffeccdccd407b452d6e32d7
+e3d8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffffcfdfc8db08f0b5711327237ceddd083aa86145d1907540d0c57128cb08ffefefeffffffffffff56
+8a5a07540d07540d07540da7c2a9ffffffffffffe6eee7518755246829dde8defffffffffffff6f9f6b4ccb624682a2f6f34dee8dfffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+fffffffffffffffffffffffcfdfc8eb19109560f307135e0eae1c6d8c838763d08550e0c5712eef3eeffffffffffffe9f0e93d794207540d206526d6e3d7ffff
+ffffffffffffffebf1eb2d6e3239773eedf3edffffffb5ccb70b56110c5712125c18b2cab4ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffd6e3d7b0c9
+b2739f760b5711307035d8e4d9fcfdfcbbd0bc97b799fbfcfbffffffffffffffffff7fa78207540d07540d26692bf8faf8fffffffffffff8faf831713507540d
+437d47e1eae2eff4f0417c463e7a42e3ece3fcfdfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffffffffffffff0f5f023672807540d155e1b26692b08550e115b17578b5b
+dde7ddffffffffffffffffffffffffffffff94b59607540d236728659568fbfcfbffffffffffffffffffbcd1be1a61200f5a15cbdbccffffffd4e1d51a612077
+a17afbfcfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffff5f8f635733907540d08540e08550e08550e07540d07540d1a611f98b89afefffefffffffffffff8
+faf886ac8909550f568b5afffffffffffffffffffffffffffffffdfefd568b5b0a5610a8c3aaffffffffffff5f9163115b17d7e4d8ffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffd7e3d822672807540d07540d07540d07540d07540d07540d3c7840fcfdfcffffffeef3ef3e7a4308540e0c571291b394ffffffffff
+ffffffffffffffb7ceb95c8e60135c1809550fb3cbb5ffffffffffffa0bea30e5914d0ded1ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffff4a83
+4f07540d07540d07540d08550e105a16347339e0eae1ffffffffffffe6eee71a611f08550e8baf8efcfdfcffffffffffffffffffffffffa8c3ab0e59140c5712
+5a8d5ef8faf8ffffffffffffe1ebe20f5915cbdbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffa4c0a608550e165f1c1b622007540d2a6c2f
+e7efe8ffffffffffffffffffffffffb1c9b3115b171e6424c5d7c7fffffffffffffffffffffffffdfefd93b596125c18639467ecf2edffffffe7efe8709c740c
+5812ccdccdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffbfdfb3171360e591474a0786a986d84aa87fdfdfdfffffffffffffffffff2f6f288
+ad8b39763e07540d206526e9f0eafffffffffffffffffffffffffdfefdbacfbc135c184a824ef0f5f092b495135c19659569eef4efffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffceddcf286b2d0a5610b5ccb6ffffffffffffffffffffffffffffffc1d4c309550f07540d08550e165e1bdbe6dbffff
+ffffffffffffffffffffffffffe9f0ea1a611f0f5a15d0ded18aae8d327237ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+ffffffffd3e0d41a61201f6525e1eae2fffffffffffffffffffffffff8faf86c9a700b57110b571184ab87fdfefdffffffffffffffffffffffffffffffffffff
+b4cbb6105a16739f7789ae8c337338ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff9ebca00a5610276a2c
+bdd1befffffffffffffffffffffffffcfdfdb2cab425682a0d58139dbc9ffefffeffffffffffffffffffffffffedf2edfdfefd719d7447804b96b799568b5aff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffffffffffffffffffffcfdfc98b89b115b1618601dd0dfd2ffffffffffffffffffff
+fffffdfefdd2e0d426692b0d58139ebca1fefefefffffffefefee3ebe3bcd1bdedf2edb6ccb726692bacc6ae2d6e33e3ece4ffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa3bfa50b5711347339e4ece5ffffffffffffffffff578b5b145d1a0e591407540d1860
+1de8efe8fffffffdfefd85ab88dae5dbbdd2bffbfcfbc3d6c5d3e0d4c8d9c9ebf2ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffff7f9f738763d07540d447e49f7faf7fffffffeffff3d794107540d206525427d476c996ff6f9f6ffffffffffffe1eae28db090
+a7c3aafefffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f6f2
+22662707540d08550e36743adce7ddffffffd4e2d61a611f226727e3ece4ffffffffffffffffffffffffe8efe86b996facc6aed4e2d5ffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffebad0bc18601e07540d0e5914bfd3c0ff
+ffffffffffa1bfa40a5610447e48f1f5f1ffffffffffff91b3949fbda2467f4abdd1bfa8c3aafefefeffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafc8b10b5611216626d7e4d8fffffffffffffafcfa588c5c07540d6a98
+6effffffffffffa6c1a866966a81a88483aa868aaf8df4f7f4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff7ba47e09550f07540d7ba47effffffffffffffffff5c8f6007540d447e48ffffffffffffb4ccb66b996faec7b0
+f1f5f2609164a4c0a6fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe6b996f
+266a2c145d1a07540d105a16c2d5c4ffffffffffffffffffceddcf125c1837753cffffffffffffd0dfd13e794237753cb8cebaa8c3aa639366fcfdfcffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe588b5c07540d07540d0c5812558a59f8faf8ff
+ffffffffffffffffffffff1e6424327237fffffffffffffcfdfc709c73528756a1bea4ecf2ec467f4af3f7f3ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedf2ed48814c07540d39773ee0eae1fffffffffffffffffffdfefde5ede61b62213272
+37fffffffffffffefefe79a37c115b1696b698bbd0bd80a783ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffeaf0ea588c5c08550e25692ac0d4c2ffffffffffff96b798155d1a08540e3d7942ffffffffffffffffffe5ede568976c
+eef3efbbd0bc528856fcfdfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffbfcfb7ca57f07540d1d6322c9dacaffffff4c83500b5711669569c4d6c5ffffffffffffffffffffffffdae6db729e76ebf1ec48814cc6d8c7ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ca57f07540d07540d8f
+b292ffffff49814d125b17f6f9f6fffffffffffffffffffffffffffffffefefe739e76a2bfa584aa87d9e5daffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe2ebe33f7b4407540d5f9163fafcfa49814d125b17f6f9f6ffff
+fffffffffffffffffffffffffff3f6f3407b44bbd0bdb7cdb9b5ccb7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffd6e3d7276a2c08550ecddcce457f49185f1df7f9f7ffffffffffffffffffffffffffffffffffff
+ccdcce69976d77a17ae4ede5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff8eb19108550ecadbcc61926548814cfdfefdfffffffffffffffffffffffffffffffffffffefefe88ad8b82a985fcfdfdffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9daca0b
+5711749f77b2cab3125c18ccdccdfffffffffffffffffffffffffffffffffffffffffff3f7f3e6ede6fdfefdffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7faf79cbb9e3a773edee8de75a0789dbca0ffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9fbf9fefffeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000005000000070101000000030000000000}}
+\par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}
+{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8
+\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \s1\ql \li0\ri0\sa220\sl220\slmult0
+\keep\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 \f28\fs20\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {CVS Improvement for Remote Development \endash Exhibit A
+\par }\pard\plain \s2\ql \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \f28\fs18\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {
+\par Abstract
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+\par This document discusses the redesign of CVS to support multiple repository servers slaved to a single primary server that accepts write requests. Writes to the primary will be pushed to secondaries as quickly as possible.
+\par
+\par
+\par }\pard\plain \s2\ql \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \f28\fs18\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {Introduction
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+\par CVS easily supports multiple read-only repositories, but not multiple write repositories. The locking scheme used by CVS prevents multiple write repositories from cooperating easily.
+\par
+\par When dealing with distributed environments, where some groups of developers may be connected to the network via slow links, it becomes useful to provide groups of developers behind slow network connections with a \'93mirror\'94, or \'93read-only\'94
+, CVS repository to speed up the common day-
+to-day development tasks that CVS is used for but which only require read access to the repository. This could also be useful to divide up a large group of developers into smaller groups to reduce the loading on individual servers.
+\par
+\par To avoid having to tra
+in developers to manually specify a separate write repository for write operations, it would be useful if the secondary repository servers had some way to refer a CVS client to the primary server for write operations, or to act as a proxy for the write op
+erations.
+\par
+\par This paper proposes a method of having secondary repositories become transparent proxies for a primary repository server upon receiving write operation requests. To support keeping the secondary repositories up to date, this method will be used
+in conjunction with an rsync data push after completion of each write request on the primary.
+\par \line
+\par }\pard\plain \s2\ql \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \f28\fs18\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {Additional Requirements
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+\par Configuration should be as simple as possible.
+\par
+\par If secondary servers become out of date for any reason, resynchronizing with the primary repository should be a one step process.
+\par
+\par Queued push requests to push new data to the secondaries should not clog the network.
+\par
+\par Write requests should introduce as few new delays into the write process as possible.
+\par
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\pnrdate0\pnrnot1\adjustright\rin0\lin0\itap0 {\revised\revauth1\revdttm-2038016926 Secondary}{\revised\revauth1\revdttm-2038016936
+ repository servers should stay as closely synchronized with the primary server as possible. }{\deleted\revauthdel1\revdttmdel-2038016936 Secondary repository servers should}{\deleted\revauthdel1\revdttmdel-2038016937
+ stay as closely synchronized with the primary server as possible.}{\deleted\revauthdel1\revdttmdel-2038016936 }{This includes updating a secondary }{\revised\revauth1\revdttm-2038016925 that}{\deleted\revauthdel1\revdttmdel-2038016925 which}{
+ just served as a proxy before releasing its client since otherwise the client may find its workspace out of sync with its read repository.
+\par }{\revised\revauth1\revdttm-2038016934
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\revised\revauth1\revdttm-2038016934 Regression tests should be provided to insure that these new features are not broken by future work on CVS.
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\pnrauth1\pnrdate-2038016934\pnrnot1\adjustright\rin0\lin0\itap0 {\revised\revauth1\revdttm-2038016934
+\par
+\par }\pard\plain \s2\ql \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel1\keep\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel1\pnrauth1\pnrdate-2038016934\pnrnot1\adjustright\rin0\lin0\itap0
+\f28\fs18\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {\revised\revauth1\revdttm-2038016934 Implementation}{\revised\revauth1\revdttm-2038016933
+\par }\pard\plain \s3\ql \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel2\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel2\pnrauth1\pnrdate-2038016931\pnrnot1\adjustright\rin0\lin0\itap0
+\f1\fs22\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {\revised\revauth1\revdttm-2038016932
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\pnrauth1\pnrdate-2038016933\pnrnot1\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+\revised\revauth1\revdttm-2038016933 Configuration}{\revised\revauth1\revdttm-2038016930 \line
+\par All rysnc processes, whether push or pull, will lock the primary before any secondaries to avoid deadlock. In the case of updates from a secondary to a tertiary, the server }{\revised\revauth1\revdttm-2038016929 \'93closest\'94
+ to the primary will always be locked first.
+\par }{\revised\revauth1\revdttm-2038016933
+\par }\pard\plain \s4\qj \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel3\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel3\pnrauth1\pnrdate-2038016933\pnrnot1\adjustright\rin0\lin0\itap0
+\i\f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {\revised\revauth1\revdttm-2038016933 Configuration of }{\revised\revauth1\revdttm-2038016932 Secondary}{\revised\revauth1\revdttm-2038016933 Repository Servers
+
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\pnrauth1\pnrdate-2038016932\pnrnot1\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+\deleted\revauthdel1\revdttmdel-2038016932
+\par }{
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {Secondary repository servers will need, initially, a copy of the primary repository.
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\pnrauth1\pnrdate-2038016932\pnrnot1\adjustright\rin0\lin0\itap0 {\deleted\revauthdel1\revdttmdel-2038016932
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\revised\revauth1\revdttm-2038016932
+\par }{Secondary repository servers will need to know how to talk to the primary repository. This should be a simple matter of setting a CVSROOT string attached to an option in the }{\f2 CVSROOT/config}{ file.
+\par
+\par Secondary repository servers will need to be set up in such a way as to allow the data push from the primary. This will probably simply involve setting up an SSH server daemon on each secondary and an account which has write
+ privileges to the entire repository on each secondary and installing the }{\f2 rsync}{ & }{\f2 cvslock}{ applications on each secondary machine.}{\revised\revauth1\revdttm-2038016901
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\pnrauth1\pnrdate-2038016901\pnrnot1\adjustright\rin0\lin0\itap0 {\revised\revauth1\revdttm-2038016901
+\par Secondary servers will need to be configured to pull data from the primary before releasing the client}{\revised\revauth1\revdttm-2038016896 via the CVSROOT/postproxy file}{\revised\revauth1\revdttm-2038016901 .}{
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {
+\par }{\deleted\revauthdel1\revdttmdel-2038016924
+Secondary repository servers will also need to be set up to pull updates from the primary following a proxy event. This will require an SSH server daemon on the primary similar to the secondary SSH server daemon specified in the previous paragraph.
+
+\par }{
+\par }\pard\plain \s4\qj \li0\ri0\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel3\adjustright\rin0\lin0\itap0 \i\f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {
+Primary Repository Server Configuration
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+\par The primary repository servers will need to have a single SSH private key available to any account the CVS server may run under. This SSH key should allow access to any secondary CVS server via an account whi
+ch has write access to the entire CVS repository on each secondary.
+\par
+\par The }{\f2 CVSROOT/loginfo}{ file in the primary repository will need to be configured to push changes to secondaries on commit. To queue updates, }{\f2 cvslock}{ should be used to lock a single, arbitrary, \'93update\'94
+ directory with every commit. This will allow only a single }{\f2 rsync}{ process to run on any secondary at any given time and avoid over-utilization of bandwidth.
+\par
+\par There should exist a script that can be run to resynchronize the entire repository of each secondary server in the event that synchronization is lost since unsynchronized secondaries could prevent commits.
+\par \line The primary server will intuit its status as the primary by noting that its hostname is the one specified in CVSROOT/config as the pr
+imary. Thus, all the secondary repositories may be configured and reconfigured by simply configuring or reconfiguring the primary repository since the primary will know to ignore secondary configuration options.
+\par
+\par }{\revised\revauth1\revdttm-2038016924 New}{\deleted\revauthdel1\revdttmdel-2038016924 A n}{\deleted\revauthdel1\revdttmdel-2038016923 ew}{ }{\revised\revauth1\revdttm-2038016924 scripting}{\deleted\revauthdel1\revdttmdel-2038016924 CVSROOT/posttag}{ hook
+}{\revised\revauth1\revdttm-2038016924 s}{ will be needed to synchronize }{\revised\revauth1\revdttm-2038016924 files}{\deleted\revauthdel1\revdttmdel-2038016924 CVSROOT/val-tags}{ after }{\deleted\revauthdel1\revdttmdel-2038016924 a }{tag}{
+\revised\revauth1\revdttm-2038016924 , admin, and the watch family of}{ operation}{\revised\revauth1\revdttm-2038016923 s}{.
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\pnrauth1\pnrdate-2038016924\pnrnot1\adjustright\rin0\lin0\itap0 {\revised\revauth1\revdttm-2038016924
+\par Secondary repository servers will also need to be set up to pull updates from the primary following a proxy event. This will require an SSH server daemon on the primary similar to the secondary SSH server daemon specified in the previous paragraph.
+
+\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {
+\par
+\par }\pard\plain \s3\ql \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin0\itap0 \f1\fs22\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {Authentication
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+Secondaries will authenticate client connections to the primary server using the same method and authentication tokens used to authenticate to it.
+\par
+\par
+\par }\pard\plain \s3\ql \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin0\itap0 \f1\fs22\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {
+CVS Server Modifications
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+Only modifications to the behavior of the CVS secondary servers are necessary, other than knowing to ignore secondary configuration options in CVSROOT/config and the addition of the extra scripting hooks to allow for fil
+e synchronization after tag, admin, and watch commands. The primary could continue running a stock CVS without problems using this design if it could ignore unknown configuration options and pull updates could be relied upon.
+\par
+\par When a CVS server discovers that it is configured as a secondary, it will only record client communication streams, with the exception of a few requests, like the \'93expand-modules\'94
+ request, until it discovers whether the command request will require writing. If the command will not r
+equire writing, then the secondary will rewind the communication stream and process the stream itself. If the command does require writing, then the secondary will open a connection to the server, replay the communication stream from the client, then tur
+n itself into a transparent proxy for the client-primary connection. These modifications will require that most of the request handlers in }{\f2 src/server.c}{
+ become dual-mode and that the command handlers each be altered to either launch the playback processor or the connection to the primary server.
+\par
+\par Several new scripting hooks will need to be added:
+\par }\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\clbrdrt\brdrs\brdrw30\brdrcf11 \clbrdrb\brdrs\brdrw15\brdrcf11
+\cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\clbrdrt\brdrs\brdrw30\brdrcf11 \clbrdrb\brdrs\brdrw15\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\pard \qj \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {
+Hook File Name\cell Description\cell }\pard \ql \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11
+\trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\clbrdrt\brdrs\brdrw30\brdrcf11 \clbrdrb\brdrs\brdrw15\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\clbrdrt\brdrs\brdrw30\brdrcf11 \clbrdrb
+\brdrs\brdrw15\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\row }\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\clbrdrt
+\brdrs\brdrw15\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\clbrdrt\brdrs\brdrw15\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\pard \qj \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {
+CVSROOT/prewriteproxy\cell Called when the secondary receives a write request from the client, just prior to becoming a write proxy. Can be passed the CVSROOT of the primary.\cell }\pard
+\ql \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\clbrdrt
+\brdrs\brdrw15\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\clbrdrt\brdrs\brdrw15\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\row }\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11
+\trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\pard
+\qj \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {CVSROOT/postwriteproxy\cell
+Called by the secondary when the primary closes the connection, prior to closing the connection to the client and releasing it. Can be passed the CVSROOT of the primary and a list of updated direc
+tories. May also want to know what command was executed to decide whether to pull CVSROOT/val-tags if it is decided that it is impractical to pull this file every time.\cell }\pard
+\ql \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3
+\clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\row }\pard \qj \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {CVSROOT/posttag\cell
+Can be passed info similar to taginfo. Can be used to push files updated after a tag to secondaries.\cell }\pard \ql \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11
+\trbrdrb\brdrs\brdrw30\brdrcf11 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\row }\pard
+\qj \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {CVSROOT/postadmin\cell Passed at least a list of directories updated. Can be used to push files updated after an admin command to secondaries.\cell }\pard
+\ql \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3
+\clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\row }\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11
+\trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\clbrdrb\brdrs\brdrw30\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\clbrdrb\brdrs\brdrw30\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\pard
+\qj \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {CVSROOT/postwatch\cell Passed at least a list of directories updated. Can be used to push CVS/fileattr files updated after a watch or edit command to secondaries.\cell }\pard
+\ql \li0\ri0\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw30\brdrcf11 \trbrdrb\brdrs\brdrw30\brdrcf11 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3 \clvertalt\clbrdrb
+\brdrs\brdrw30\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx4320\clvertalt\clbrdrb\brdrs\brdrw30\brdrcf11 \cltxlrtb\clftsWidth3\clwWidth4428 \cellx8748\row }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {
+\par
+\par }\pard\plain \s3\ql \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin0\itap0 \f1\fs22\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {Tests
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+Most of the existing CVS test suite should usable, with minor modifications, to test a secondary/primary configuration. The steps involved will be to set up two reposito
+ries, with the secondary configured to access the primary repository via a :fork: method and a copy-back routine set up in }{\f2 CVSROOT/loginfo}{
+. Most of the tests will then need to be modified to account for the different paths that will be generated in status messages from the client and server. The existing tests that modify the }{\f2 CVSROOT/config}{ or }{\f2 CVSROOT/loginfo}{
+ files will either need to be skipped or modified to insure that they do not interfere with the secondary/primary configuration.
+\par
+\par Tests are covered in more detail in the Test Plan document.
+\par
+\par
+\par }\pard\plain \s3\ql \li0\ri0\sa220\sl220\slmult0\keep\keepn\widctlpar\abslock1\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin0\itap0 \f1\fs22\expnd-2\expndtw-10\lang1033\langfe1033\kerning20\cgrid\langnp1033\langfenp1033 {Documentation
+\par }\pard\plain \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \f1\fs20\expnd-1\expndtw-5\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {
+Documentation requirements to have these changes accepted as part of the main CVS source distribution should be minimal.
+\par }} \ No newline at end of file
diff --git a/emx/.cvsignore b/emx/.cvsignore
new file mode 100644
index 0000000..0bc6703
--- /dev/null
+++ b/emx/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+cvs.exe
+cvs.out
diff --git a/emx/ChangeLog b/emx/ChangeLog
new file mode 100644
index 0000000..a6e7c7a
--- /dev/null
+++ b/emx/ChangeLog
@@ -0,0 +1,237 @@
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * README: Update bug-cvs email.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (open_file): Remove this function.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * config.h: Remove obsolete timeb cruft.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (LIB_SOURCES): Remove stripslash.c.
+ (OS2_OBJECTS): Remove stripslash.o.
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * stripslash.c: Remove file.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (isabsolute): Remove this function.
+ * config.h (ISABSOLUTE): Define.
+
+2003-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (xresolvepath): New function.
+
+2003-08-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (pdf ps): New recursive targets to be ignored for
+ Automake's benefit.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c: s/PROTO/.
+ * savecwd.c: Ditto.
+
+2002-03-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Remove unecessary dependence on $(srcdir) to
+ fix the dist target.
+ (distdir): Use new automake generated target (copied from src).
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h (RSH_DFLT): Default to "rsh".
+
+2002-12-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Remove reference to options.h.
+ * startserver.c: Ditto.
+ * options.h: Remove file and move relevant content...
+ * config.h: ...here.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove prototype of STDC exit().
+
+2002-08-24 Larry Jones <lawrence.jones@eds.com>
+
+ * options.h: Remove PATCH_PROGRAM.
+
+2002-08-16 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove RELATIVE_REPOS & move CVS_BADROOT...
+ * config.h: ...here.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in (installcheck): New target.
+
+2001-02-14 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Remove references to rtag.c & rtag.o.
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Targets added to please Automake
+
+1999-03-27 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (LIB_OBJECTS, LIB_SOURCES): Remove vasprintf.
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * options.h: Make RELATIVE_REPOS the default, as in
+ ../src/options.h.in.
+
+1998-08-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (rcscmds.o): New rule, so we can supply -I for
+ diffrun.h.
+
+1998-04-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (link_file): Remove; no longer used.
+
+Tue Feb 17 02:28:20 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * filesubr.c (last_component): return the top-level directory when
+ asked about the top-level directory.
+
+Tue Jan 13 13:17:33 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (DIFF, RCSBIN_DFLT): Remove; no longer used.
+
+Wed Dec 31 10:56:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h, filesubr.c (convert_file): Remove; no longer used
+ (except for BROKEN_READWRITE_CONVERSION which doesn't apply).
+
+Sat Dec 27 16:57:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (HAVE_RCS5): Remove; no longer used.
+
+ * config.h (LINES_CRLF_TERMINATED): Remove; no longer used.
+
+Tue Dec 23 08:28:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Change bug-cvs address from prep.ai.mit.edu to gnu.org
+ per email from Martin Hamilton.
+
+Sat Nov 29 22:20:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove declaration of getwd; see lib/ChangeLog for
+ rationale.
+
+Fri Nov 14 13:37:33 1997 Abe Feldman and Jim Kingdon
+
+ * savecwd.c: New file, copied from lib/savecwd.c except it calls
+ _chdir2 not chdir.
+ * Makefile.in: Put savecwd in emx directory not lib directory.
+
+Tue Nov 4 18:20:08 1997 Abe Feldman <feldman@cyclic.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Adjust to add diff directory.
+
+Sun Sep 7 19:49:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.c (os2_stat): Adjust comment to reflect removal of
+ same_directories from src/root.c.
+
+Sat Sep 06 14:45:13 1997 Jim Kingdon
+
+ * Makefile.in: Add a cvs-static.exe rule for generating
+ executables which don't need emx.dll (doesn't work yet).
+
+Fri Sep 05 12:21:56 1997 Jim Kingdon
+
+ * filesubr.c (xchmod): Replace with "attrib"-based code from
+ os2/filesubr.c.
+ * config.h (CHMOD_BROKEN): Define.
+
+Wed Jul 30 15:35:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: In comment about Makefile rule, remove note about
+ this not being a problem for os2/Makefile.in. It is a problem
+ there too.
+
+ * README: Add note about srcdir and top_srcdir.
+
+Mon Jul 21 15:36:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Makefile is not in srcdir.
+
+Wed Jun 18 12:07:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (OS2_SOURCES): Fix comment so this is not commented
+ out. Remove windows-NT/rcmd.c; the make dist for the windows-NT
+ directory can take care of that one.
+
+ * Makefile.in, README: Add comments about Makefile rule.
+
+Tue Jun 17 14:44:02 1997 Jim Kingdon (unknown@beezley)
+
+ * rcmd.c: Removed; no longer used.
+ * rcmd.h: Updated to have similar contents as
+ windows-NT/rcmd.h.
+ * Makefile.in (OS2_HEADERS): Change back to ${srcdir}/rcmd.h.
+ That is the one that the -I options specify anyway.
+ * startserver.c (os2_start_server): Pass a const char ** not
+ a char ** to rcmd.
+
+ * README: Replace text concerning warnings with a more
+ specific list of exactly what the warnings are. For the
+ most part there should be no warnings.
+ Update note about -lufc.
+ * Makefile.in (LIB): Remove -lufc.
+ * config.h (RSH_NOT_TRANSPARENT): Define.
+ * Makefile.in: Use ${top_srcdir}/windows-NT/rcmd.* not our
+ own rcmd.* (for better error messages).
+ * .cvsignore: Add cvs.out.
+
+Tue Jun 17 13:19:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Revise paragraph on -Zsys to discuss problem with
+ sockets being missing.
+
+Mon Jun 16 10:58:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Change bug submission address to include bug-cvs.
+ Add paragraph (from the mail message of the submission) concerning
+ HPFS and such. Cosmetic changes (two spaces after periods for
+ example). Say that ufc-crypt shouldn't be needed currently.
+ Add comment about emx.dll.
+ * config.h, startserver.c, rcmd.h, rcmd.c, system.c: Add
+ "copyright" notice.
+ * system.c (os2_initialize): Add comment about whether we should
+ be expanding wildcards here. Cosmetic changes throughout
+ (for example, reindenting just about everything).
+ * system.c (xgetwd): Rewritten and renamed from os2_getwd.
+ * config.h (CVS_GETWD, os2_getwd): Removed.
+ * rcmd.c: Add comment about portable versus OS-specific
+ implementations of this functionality.
+ * config.h: Remove SIZEOF_INT, SIZEOF_LONG, HAVE_MKFIFO,
+ HAVE_SETVBUF, and USE_DIRECT_TCP; no longer used.
+ * config.h: Add USE_SETMODE_BINARY.
+ * config.h: Define NO_EXT_METHOD.
+ * Makefile.in (LIB_SOURCES): Remove lib/xgetwd.c; replaced by
+ xgetwd in system.c.
+ (LIB_OBJECTS): Likewise, remove lib/xgetwd.o.
+ * Makefile.in (DISTFILES): Add missing "/".
+ * .cvsignore: Added.
+
+ * New directory. This consists of the port that Thomas Epting
+ sent to bug-cvs on 18 Mar 97. He also sent some diffs which go
+ with this; I'll subsequently be checking in some of those diffs
+ and my various tweaks to the code.
+
diff --git a/emx/Makefile b/emx/Makefile
new file mode 100644
index 0000000..4b906ba
--- /dev/null
+++ b/emx/Makefile
@@ -0,0 +1,409 @@
+# Makefile for OS/2. Generated from Makefile.in when CVS is
+# configured for a dist-build. Configure never gets run on OS/2, so
+# we must include the generated Makefile in the distribution. See the
+# `dist-dir' rule.
+
+project: cvs.exe
+# .SUFFIXES .c .o .exe
+
+# Directory in which to install executables.
+install_dir = s:/gnu/util
+
+# srcdir is usually "."
+srcdir = .
+
+# top_srcdir is usually ".."
+top_srcdir = ..
+
+
+subdir = emx
+
+lib_dir = ${top_srcdir}/lib
+cvs_srcdir = ${top_srcdir}/src
+diff_srcdir = ${top_srcdir}/diff
+zlib_dir = ${top_srcdir}/zlib
+
+# Do we need these?
+# prefix = /usr/local
+# exec_prefix = ${prefix}
+
+# Used to say -lufc, but that would only be needed for crypt().
+LIB = -lsocket
+
+CINC =
+# This says we are building an object file, not a full executable.
+OBJ_CFLAGS = -c
+CFLAGS = -pedantic -Wall -fno-builtin ${CINC} \
+ -I${srcdir} -I${lib_dir} -I${cvs_srcdir} -I${zlib_dir} \
+ -DUNIX -DHAVE_CONFIG_H
+
+
+# headers specific to OS/2
+
+# We list OS2_HEADERS so we know what to include when we make dist-dir
+# here.
+OS2_HEADERS = \
+ config.h \
+ rcmd.h
+
+# headers we use from the common src dir, ../src
+COMMON_HEADERS = \
+ ${cvs_srcdir}/client.h \
+ ${cvs_srcdir}/cvs.h \
+ ${cvs_srcdir}/rcs.h \
+ ${cvs_srcdir}/hash.h \
+ ${cvs_srcdir}/myndbm.h \
+ ${cvs_srcdir}/patchlevel.h \
+ ${cvs_srcdir}/update.h \
+ ${cvs_srcdir}/server.h \
+ ${cvs_srcdir}/error.h
+
+# headers in ../diff
+DIFF_HEADERS = \
+ ${diff_srcdir}/cmpbuf.h \
+ ${diff_srcdir}/diff.h \
+ ${diff_srcdir}/system.h
+
+# sources specific to OS/2
+OS2_SOURCES = \
+ filesubr.c \
+ startserver.c \
+ savecwd.c \
+ system.c
+
+# sources we use from the common src dir, ../src
+# FIXME: Is this used anywhere? I don't think it is.
+COMMON_SOURCES = \
+ ${cvs_srcdir}/add.c \
+ ${cvs_srcdir}/admin.c \
+ ${cvs_srcdir}/buffer.c \
+ ${cvs_srcdir}/checkin.c \
+ ${cvs_srcdir}/checkout.c \
+ ${cvs_srcdir}/classify.c \
+ ${cvs_srcdir}/client.c \
+ ${cvs_srcdir}/commit.c \
+ ${cvs_srcdir}/create_adm.c \
+ ${cvs_srcdir}/cvsrc.c \
+ ${cvs_srcdir}/diff.c \
+ ${cvs_srcdir}/edit.c \
+ ${cvs_srcdir}/entries.c \
+ ${cvs_srcdir}/error.c \
+ ${cvs_srcdir}/expand_path.c \
+ ${cvs_srcdir}/fileattr.c \
+ ${cvs_srcdir}/find_names.c \
+ ${cvs_srcdir}/hash.c \
+ ${cvs_srcdir}/history.c \
+ ${cvs_srcdir}/ignore.c \
+ ${cvs_srcdir}/import.c \
+ ${cvs_srcdir}/lock.c \
+ ${cvs_srcdir}/log.c \
+ ${cvs_srcdir}/login.c \
+ ${cvs_srcdir}/logmsg.c \
+ ${cvs_srcdir}/main.c \
+ ${cvs_srcdir}/mkmodules.c \
+ ${cvs_srcdir}/modules.c \
+ ${cvs_srcdir}/myndbm.c \
+ ${cvs_srcdir}/no_diff.c \
+ ${cvs_srcdir}/parseinfo.c \
+ ${cvs_srcdir}/patch.c \
+ ${cvs_srcdir}/rcs.c \
+ ${cvs_srcdir}/rcscmds.c \
+ ${cvs_srcdir}/recurse.c \
+ ${cvs_srcdir}/release.c \
+ ${cvs_srcdir}/remove.c \
+ ${cvs_srcdir}/repos.c \
+ ${cvs_srcdir}/root.c \
+ ${cvs_srcdir}/scramble.c \
+ ${cvs_srcdir}/server.c \
+ ${cvs_srcdir}/status.c \
+ ${cvs_srcdir}/subr.c \
+ ${cvs_srcdir}/run.c \
+ ${cvs_srcdir}/tag.c \
+ ${cvs_srcdir}/update.c \
+ ${cvs_srcdir}/watch.c \
+ ${cvs_srcdir}/wrapper.c \
+ ${cvs_srcdir}/vers_ts.c \
+ ${cvs_srcdir}/version.c \
+ ${cvs_srcdir}/zlib.c
+# end of $COMMON_SOURCES
+
+# sources in ../diff
+DIFF_SOURCES = \
+ ${diff_srcdir}/analyze.c \
+ ${diff_srcdir}/cmpbuf.c \
+ ${diff_srcdir}/context.c \
+ ${diff_srcdir}/diff.c \
+ ${diff_srcdir}/diff3.c \
+ ${diff_srcdir}/dir.c \
+ ${diff_srcdir}/ed.c \
+ ${diff_srcdir}/ifdef.c \
+ ${diff_srcdir}/io.c \
+ ${diff_srcdir}/normal.c \
+ ${diff_srcdir}/side.c \
+ ${diff_srcdir}/util.c \
+ ${diff_srcdir}/version.c
+
+# sources from ../lib
+# FIXME: Is this used anywhere? I don't think it is.
+LIB_SOURCES = \
+ ${lib_dir}/argmatch.c \
+ ${lib_dir}/getline.c \
+ ${lib_dir}/getopt.c \
+ ${lib_dir}/getopt1.c \
+ ${lib_dir}/md5.c \
+ ${lib_dir}/regex.c \
+ ${lib_dir}/sighandle.c \
+ ${lib_dir}/valloc.c \
+ ${lib_dir}/yesno.c \
+ ${lib_dir}/getdate.c
+
+# object files from OS/2 sources
+# was ${srcdir}/rcmd.o
+OS2_OBJECTS = \
+ ${srcdir}/filesubr.o \
+ ${srcdir}/startserver.o \
+ ${top_srcdir}/windows-NT/rcmd.o \
+ ${srcdir}/savecwd.o \
+ ${srcdir}/system.o
+
+# object files from ../src
+COMMON_OBJECTS = \
+ ${cvs_srcdir}/add.o \
+ ${cvs_srcdir}/admin.o \
+ ${cvs_srcdir}/buffer.o \
+ ${cvs_srcdir}/checkin.o \
+ ${cvs_srcdir}/checkout.o \
+ ${cvs_srcdir}/classify.o \
+ ${cvs_srcdir}/client.o \
+ ${cvs_srcdir}/commit.o \
+ ${cvs_srcdir}/create_adm.o \
+ ${cvs_srcdir}/cvsrc.o \
+ ${cvs_srcdir}/diff.o \
+ ${cvs_srcdir}/edit.o \
+ ${cvs_srcdir}/entries.o \
+ ${cvs_srcdir}/expand_path.o \
+ ${cvs_srcdir}/fileattr.o \
+ ${cvs_srcdir}/find_names.o \
+ ${cvs_srcdir}/hash.o \
+ ${cvs_srcdir}/history.o \
+ ${cvs_srcdir}/ignore.o \
+ ${cvs_srcdir}/import.o \
+ ${cvs_srcdir}/lock.o \
+ ${cvs_srcdir}/log.o \
+ ${cvs_srcdir}/login.o \
+ ${cvs_srcdir}/logmsg.o \
+ ${cvs_srcdir}/main.o \
+ ${cvs_srcdir}/mkmodules.o \
+ ${cvs_srcdir}/modules.o \
+ ${cvs_srcdir}/myndbm.o \
+ ${cvs_srcdir}/no_diff.o \
+ ${cvs_srcdir}/parseinfo.o \
+ ${cvs_srcdir}/patch.o \
+ ${cvs_srcdir}/rcs.o \
+ ${cvs_srcdir}/rcscmds.o \
+ ${cvs_srcdir}/recurse.o \
+ ${cvs_srcdir}/release.o \
+ ${cvs_srcdir}/remove.o \
+ ${cvs_srcdir}/repos.o \
+ ${cvs_srcdir}/root.o \
+ ${cvs_srcdir}/scramble.o \
+ ${cvs_srcdir}/server.o \
+ ${cvs_srcdir}/status.o \
+ ${cvs_srcdir}/tag.o \
+ ${cvs_srcdir}/update.o \
+ ${cvs_srcdir}/watch.o \
+ ${cvs_srcdir}/wrapper.o \
+ ${cvs_srcdir}/vers_ts.o \
+ ${cvs_srcdir}/subr.o \
+ ${cvs_srcdir}/run.o \
+ ${cvs_srcdir}/version.o \
+ ${cvs_srcdir}/error.o \
+ ${cvs_srcdir}/zlib.o
+# end of $COMMON_OBJECTS
+
+# object files in ../diff
+DIFF_OBJECTS = \
+ ${diff_srcdir}/analyze.o \
+ ${diff_srcdir}/cmpbuf.o \
+ ${diff_srcdir}/context.o \
+ ${diff_srcdir}/diff.o \
+ ${diff_srcdir}/diff3.o \
+ ${diff_srcdir}/dir.o \
+ ${diff_srcdir}/ed.o \
+ ${diff_srcdir}/ifdef.o \
+ ${diff_srcdir}/io.o \
+ ${diff_srcdir}/normal.o \
+ ${diff_srcdir}/side.o \
+ ${diff_srcdir}/util.o \
+ ${diff_srcdir}/version.o
+
+# objects from ../lib
+LIB_OBJECTS = \
+ ${lib_dir}/argmatch.o \
+ ${lib_dir}/getline.o \
+ ${lib_dir}/getopt.o \
+ ${lib_dir}/getopt1.o \
+ ${lib_dir}/md5.o \
+ ${lib_dir}/regex.o \
+ ${lib_dir}/sighandle.o \
+ ${lib_dir}/valloc.o \
+ ${lib_dir}/yesno.o \
+ ${lib_dir}/getdate.o
+
+ZLIB_OBJECTS = ${zlib_dir}/adler32.o \
+ ${zlib_dir}/compress.o \
+ ${zlib_dir}/crc32.o \
+ ${zlib_dir}/gzio.o \
+ ${zlib_dir}/uncompr.o \
+ ${zlib_dir}/deflate.o \
+ ${zlib_dir}/trees.o \
+ ${zlib_dir}/zutil.o \
+ ${zlib_dir}/inflate.o \
+ ${zlib_dir}/infblock.o \
+ ${zlib_dir}/inftrees.o \
+ ${zlib_dir}/infcodes.o \
+ ${zlib_dir}/infutil.o \
+ ${zlib_dir}/inffast.o
+
+SOURCES = ${COMMON_SOURCES} ${LIB_SOURCES} ${OS2_SOURCES} ${DIFF_SOURCES}
+HEADERS = ${COMMON_HEADERS} ${OS2_HEADERS} ${DIFF_HEADERS}
+OBJECTS = ${COMMON_OBJECTS} ${LIB_OBJECTS} ${OS2_OBJECTS} ${DIFF_OBJECTS} \
+ ${ZLIB_OBJECTS}
+
+DISTFILES = ${OS2_HEADERS} ${OS2_SOURCES} \
+ README ChangeLog \
+ Makefile.in .cvsignore \
+ Makefile
+
+all:
+
+# Automake
+.PHONY: all install installcheck uninstall check info dvi
+all install installcheck uninstall check:
+
+.PHONY: dvi info pdf ps
+dvi info pdf ps:
+
+installdirs:
+.PHONY: installdirs
+
+.PHONY: tags TAGS
+tags TAGS:
+
+.PHONY: clean distclean realclean mostlyclean
+clean distclean realclean maintainer-clean mostlyclean:
+
+.PHONY: lint
+lint:
+
+# distdir added for compatibility with CVS automake.
+top_distdir = ..
+PACKAGE = cvs
+VERSION = 1.12.13
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+distdir: $(DISTFILES)
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" \
+ distdir=../$(distdir)/$$subdir \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+.PHONY: distdir
+
+# We don't have a real distclean or anything like that, but at least
+# we can get rid of the obj files and cvs.exe.
+.PHONY: clean distclean realclean mostlyclean maintainer-clean
+clean distclean realclean maintainer-clean mostlyclean:
+ rm -f cvs.exe cvs.out
+ rm -f ${srcdir}/*.o
+ rm -f ${diff_srcdir}/*.o
+ rm -f ${lib_dir}/*.o ${lib_dir}/*.a
+ rm -f ${zlib_dir}/*.o ${zlib_dir}/*.a
+ rm -f ${cvs_srcdir}/*.o
+
+clean-cvs:
+ del cvs.exe cvs.out
+ del $(subst /,\,${srcdir}/*.o)
+ del $(subst /,\,${diff_srcdir}/*.o)
+ del $(subst /,\,${lib_dir}/*.o ${lib_dir}/*.a)
+ del $(subst /,\,${zlib_dir}/*.o ${zlib_dir}/*.a)
+ del $(subst /,\,${cvs_srcdir}/*.o)
+
+install-cvs: cvs.exe
+ copy $(subst /,\,${srcdir}/cvs.exe ${install_dir}/cvs.exe)
+
+%.o: %.c
+ gcc ${OBJ_CFLAGS} ${CFLAGS} -o $@ -c $*.c
+
+${cvs_srcdir}/rcscmds.o: ${cvs_srcdir}/rcscmds.c ${top_srcdir}/diff/diffrun.h
+ gcc ${OBJ_CFLAGS} ${CFLAGS} -I${top_srcdir}/diff -o $@ -c $*.c
+
+${lib_dir}/libcvs.a: $(LIB_OBJECTS)
+ $(AR) cr $@ $(LIB_OBJECTS)
+
+${zlib_dir}/libz.a: $(ZLIB_OBJECTS)
+ $(AR) cr $@ $(ZLIB_OBJECTS)
+
+# Eventually probably static linking (cvs-static.exe) will be the
+# default, but even so we'll want to preserve this rule so we can
+# create a dynamically linked executable when we want coredumps.
+cvs.exe: ${OBJECTS} ${lib_dir}/libcvs.a ${zlib_dir}/libz.a
+ gcc $(COMMON_OBJECTS) $(OS2_OBJECTS) ${DIFF_OBJECTS} ${lib_dir}/libcvs.a ${zlib_dir}/libz.a $(LIB) -o cvs.out
+ emxbind -w -o $@.exe cvs.out
+
+${lib_dir}/libcvs.lib: ${lib_dir}/libcvs.a
+ emxomf ${lib_dir}/libcvs.a
+
+${zlib_dir}/libz.lib: ${zlib_dir}/libz.a
+ emxomf ${zlib_dir}/libz.a
+
+# Where do -Zomf -Zsys go? When we compile the .o's?
+# When I tried this rule, I had problems with (1) could not find
+# socket.lib. Hmm. I thought I converted it from socket.a
+# in the EMX distribution. Probably my EMX installation at fault.
+# (2) could not find miscellaneous system routines like strerror.
+# This might be a matter of learning to live without them (EMX
+# doc is supposed to describe which are present and which are not).
+# (3) some linker errors like no stack and the like. Maybe I am
+# missing some options?
+cvs-static.exe: ${OBJECTS} ${lib_dir}/libcvs.lib ${zlib_dir}/libz.lib
+ emxomf ${OBJECTS}
+ emxomfld -o $@ $(subst .o,.obj,${OBJECTS}) \
+ ${lib_dir}/libcvs.lib ${zlib_dir}/libz.lib ${LIB}
+
+# cvs.o: ${OBJECTS} ${SOURCES} ${HEADERS}
+
+# Hmm. This rule wants to exist on unix, so that "make dist" works.
+# And it doesn't want to exist on OS/2, because configure doesn't
+# run on OS/2 and so ../config.status won't exist. For now we just
+# say, in emx/README, that people will need to comment it out.
+Makefile: ../config.status $(srcdir)/Makefile.in
+ cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
diff --git a/emx/Makefile.in b/emx/Makefile.in
new file mode 100644
index 0000000..8954713
--- /dev/null
+++ b/emx/Makefile.in
@@ -0,0 +1,409 @@
+# Makefile for OS/2. Generated from Makefile.in when CVS is
+# configured for a dist-build. Configure never gets run on OS/2, so
+# we must include the generated Makefile in the distribution. See the
+# `dist-dir' rule.
+
+project: cvs.exe
+# .SUFFIXES .c .o .exe
+
+# Directory in which to install executables.
+install_dir = s:/gnu/util
+
+# srcdir is usually "."
+srcdir = @srcdir@
+
+# top_srcdir is usually ".."
+top_srcdir = @top_srcdir@
+
+VPATH = @srcdir@
+subdir = emx
+
+lib_dir = ${top_srcdir}/lib
+cvs_srcdir = ${top_srcdir}/src
+diff_srcdir = ${top_srcdir}/diff
+zlib_dir = ${top_srcdir}/zlib
+
+# Do we need these?
+# prefix = /usr/local
+# exec_prefix = ${prefix}
+
+# Used to say -lufc, but that would only be needed for crypt().
+LIB = -lsocket
+
+CINC =
+# This says we are building an object file, not a full executable.
+OBJ_CFLAGS = -c
+CFLAGS = -pedantic -Wall -fno-builtin ${CINC} \
+ -I${srcdir} -I${lib_dir} -I${cvs_srcdir} -I${zlib_dir} \
+ -DUNIX -DHAVE_CONFIG_H
+
+
+# headers specific to OS/2
+
+# We list OS2_HEADERS so we know what to include when we make dist-dir
+# here.
+OS2_HEADERS = \
+ config.h \
+ rcmd.h
+
+# headers we use from the common src dir, ../src
+COMMON_HEADERS = \
+ ${cvs_srcdir}/client.h \
+ ${cvs_srcdir}/cvs.h \
+ ${cvs_srcdir}/rcs.h \
+ ${cvs_srcdir}/hash.h \
+ ${cvs_srcdir}/myndbm.h \
+ ${cvs_srcdir}/patchlevel.h \
+ ${cvs_srcdir}/update.h \
+ ${cvs_srcdir}/server.h \
+ ${cvs_srcdir}/error.h
+
+# headers in ../diff
+DIFF_HEADERS = \
+ ${diff_srcdir}/cmpbuf.h \
+ ${diff_srcdir}/diff.h \
+ ${diff_srcdir}/system.h
+
+# sources specific to OS/2
+OS2_SOURCES = \
+ filesubr.c \
+ startserver.c \
+ savecwd.c \
+ system.c
+
+# sources we use from the common src dir, ../src
+# FIXME: Is this used anywhere? I don't think it is.
+COMMON_SOURCES = \
+ ${cvs_srcdir}/add.c \
+ ${cvs_srcdir}/admin.c \
+ ${cvs_srcdir}/buffer.c \
+ ${cvs_srcdir}/checkin.c \
+ ${cvs_srcdir}/checkout.c \
+ ${cvs_srcdir}/classify.c \
+ ${cvs_srcdir}/client.c \
+ ${cvs_srcdir}/commit.c \
+ ${cvs_srcdir}/create_adm.c \
+ ${cvs_srcdir}/cvsrc.c \
+ ${cvs_srcdir}/diff.c \
+ ${cvs_srcdir}/edit.c \
+ ${cvs_srcdir}/entries.c \
+ ${cvs_srcdir}/error.c \
+ ${cvs_srcdir}/expand_path.c \
+ ${cvs_srcdir}/fileattr.c \
+ ${cvs_srcdir}/find_names.c \
+ ${cvs_srcdir}/hash.c \
+ ${cvs_srcdir}/history.c \
+ ${cvs_srcdir}/ignore.c \
+ ${cvs_srcdir}/import.c \
+ ${cvs_srcdir}/lock.c \
+ ${cvs_srcdir}/log.c \
+ ${cvs_srcdir}/login.c \
+ ${cvs_srcdir}/logmsg.c \
+ ${cvs_srcdir}/main.c \
+ ${cvs_srcdir}/mkmodules.c \
+ ${cvs_srcdir}/modules.c \
+ ${cvs_srcdir}/myndbm.c \
+ ${cvs_srcdir}/no_diff.c \
+ ${cvs_srcdir}/parseinfo.c \
+ ${cvs_srcdir}/patch.c \
+ ${cvs_srcdir}/rcs.c \
+ ${cvs_srcdir}/rcscmds.c \
+ ${cvs_srcdir}/recurse.c \
+ ${cvs_srcdir}/release.c \
+ ${cvs_srcdir}/remove.c \
+ ${cvs_srcdir}/repos.c \
+ ${cvs_srcdir}/root.c \
+ ${cvs_srcdir}/scramble.c \
+ ${cvs_srcdir}/server.c \
+ ${cvs_srcdir}/status.c \
+ ${cvs_srcdir}/subr.c \
+ ${cvs_srcdir}/run.c \
+ ${cvs_srcdir}/tag.c \
+ ${cvs_srcdir}/update.c \
+ ${cvs_srcdir}/watch.c \
+ ${cvs_srcdir}/wrapper.c \
+ ${cvs_srcdir}/vers_ts.c \
+ ${cvs_srcdir}/version.c \
+ ${cvs_srcdir}/zlib.c
+# end of $COMMON_SOURCES
+
+# sources in ../diff
+DIFF_SOURCES = \
+ ${diff_srcdir}/analyze.c \
+ ${diff_srcdir}/cmpbuf.c \
+ ${diff_srcdir}/context.c \
+ ${diff_srcdir}/diff.c \
+ ${diff_srcdir}/diff3.c \
+ ${diff_srcdir}/dir.c \
+ ${diff_srcdir}/ed.c \
+ ${diff_srcdir}/ifdef.c \
+ ${diff_srcdir}/io.c \
+ ${diff_srcdir}/normal.c \
+ ${diff_srcdir}/side.c \
+ ${diff_srcdir}/util.c \
+ ${diff_srcdir}/version.c
+
+# sources from ../lib
+# FIXME: Is this used anywhere? I don't think it is.
+LIB_SOURCES = \
+ ${lib_dir}/argmatch.c \
+ ${lib_dir}/getline.c \
+ ${lib_dir}/getopt.c \
+ ${lib_dir}/getopt1.c \
+ ${lib_dir}/md5.c \
+ ${lib_dir}/regex.c \
+ ${lib_dir}/sighandle.c \
+ ${lib_dir}/valloc.c \
+ ${lib_dir}/yesno.c \
+ ${lib_dir}/getdate.c
+
+# object files from OS/2 sources
+# was ${srcdir}/rcmd.o
+OS2_OBJECTS = \
+ ${srcdir}/filesubr.o \
+ ${srcdir}/startserver.o \
+ ${top_srcdir}/windows-NT/rcmd.o \
+ ${srcdir}/savecwd.o \
+ ${srcdir}/system.o
+
+# object files from ../src
+COMMON_OBJECTS = \
+ ${cvs_srcdir}/add.o \
+ ${cvs_srcdir}/admin.o \
+ ${cvs_srcdir}/buffer.o \
+ ${cvs_srcdir}/checkin.o \
+ ${cvs_srcdir}/checkout.o \
+ ${cvs_srcdir}/classify.o \
+ ${cvs_srcdir}/client.o \
+ ${cvs_srcdir}/commit.o \
+ ${cvs_srcdir}/create_adm.o \
+ ${cvs_srcdir}/cvsrc.o \
+ ${cvs_srcdir}/diff.o \
+ ${cvs_srcdir}/edit.o \
+ ${cvs_srcdir}/entries.o \
+ ${cvs_srcdir}/expand_path.o \
+ ${cvs_srcdir}/fileattr.o \
+ ${cvs_srcdir}/find_names.o \
+ ${cvs_srcdir}/hash.o \
+ ${cvs_srcdir}/history.o \
+ ${cvs_srcdir}/ignore.o \
+ ${cvs_srcdir}/import.o \
+ ${cvs_srcdir}/lock.o \
+ ${cvs_srcdir}/log.o \
+ ${cvs_srcdir}/login.o \
+ ${cvs_srcdir}/logmsg.o \
+ ${cvs_srcdir}/main.o \
+ ${cvs_srcdir}/mkmodules.o \
+ ${cvs_srcdir}/modules.o \
+ ${cvs_srcdir}/myndbm.o \
+ ${cvs_srcdir}/no_diff.o \
+ ${cvs_srcdir}/parseinfo.o \
+ ${cvs_srcdir}/patch.o \
+ ${cvs_srcdir}/rcs.o \
+ ${cvs_srcdir}/rcscmds.o \
+ ${cvs_srcdir}/recurse.o \
+ ${cvs_srcdir}/release.o \
+ ${cvs_srcdir}/remove.o \
+ ${cvs_srcdir}/repos.o \
+ ${cvs_srcdir}/root.o \
+ ${cvs_srcdir}/scramble.o \
+ ${cvs_srcdir}/server.o \
+ ${cvs_srcdir}/status.o \
+ ${cvs_srcdir}/tag.o \
+ ${cvs_srcdir}/update.o \
+ ${cvs_srcdir}/watch.o \
+ ${cvs_srcdir}/wrapper.o \
+ ${cvs_srcdir}/vers_ts.o \
+ ${cvs_srcdir}/subr.o \
+ ${cvs_srcdir}/run.o \
+ ${cvs_srcdir}/version.o \
+ ${cvs_srcdir}/error.o \
+ ${cvs_srcdir}/zlib.o
+# end of $COMMON_OBJECTS
+
+# object files in ../diff
+DIFF_OBJECTS = \
+ ${diff_srcdir}/analyze.o \
+ ${diff_srcdir}/cmpbuf.o \
+ ${diff_srcdir}/context.o \
+ ${diff_srcdir}/diff.o \
+ ${diff_srcdir}/diff3.o \
+ ${diff_srcdir}/dir.o \
+ ${diff_srcdir}/ed.o \
+ ${diff_srcdir}/ifdef.o \
+ ${diff_srcdir}/io.o \
+ ${diff_srcdir}/normal.o \
+ ${diff_srcdir}/side.o \
+ ${diff_srcdir}/util.o \
+ ${diff_srcdir}/version.o
+
+# objects from ../lib
+LIB_OBJECTS = \
+ ${lib_dir}/argmatch.o \
+ ${lib_dir}/getline.o \
+ ${lib_dir}/getopt.o \
+ ${lib_dir}/getopt1.o \
+ ${lib_dir}/md5.o \
+ ${lib_dir}/regex.o \
+ ${lib_dir}/sighandle.o \
+ ${lib_dir}/valloc.o \
+ ${lib_dir}/yesno.o \
+ ${lib_dir}/getdate.o
+
+ZLIB_OBJECTS = ${zlib_dir}/adler32.o \
+ ${zlib_dir}/compress.o \
+ ${zlib_dir}/crc32.o \
+ ${zlib_dir}/gzio.o \
+ ${zlib_dir}/uncompr.o \
+ ${zlib_dir}/deflate.o \
+ ${zlib_dir}/trees.o \
+ ${zlib_dir}/zutil.o \
+ ${zlib_dir}/inflate.o \
+ ${zlib_dir}/infblock.o \
+ ${zlib_dir}/inftrees.o \
+ ${zlib_dir}/infcodes.o \
+ ${zlib_dir}/infutil.o \
+ ${zlib_dir}/inffast.o
+
+SOURCES = ${COMMON_SOURCES} ${LIB_SOURCES} ${OS2_SOURCES} ${DIFF_SOURCES}
+HEADERS = ${COMMON_HEADERS} ${OS2_HEADERS} ${DIFF_HEADERS}
+OBJECTS = ${COMMON_OBJECTS} ${LIB_OBJECTS} ${OS2_OBJECTS} ${DIFF_OBJECTS} \
+ ${ZLIB_OBJECTS}
+
+DISTFILES = ${OS2_HEADERS} ${OS2_SOURCES} \
+ README ChangeLog \
+ Makefile.in .cvsignore \
+ Makefile
+
+all:
+
+# Automake
+.PHONY: all install installcheck uninstall check info dvi
+all install installcheck uninstall check:
+
+.PHONY: dvi info pdf ps
+dvi info pdf ps:
+
+installdirs:
+.PHONY: installdirs
+
+.PHONY: tags TAGS
+tags TAGS:
+
+.PHONY: clean distclean realclean mostlyclean
+clean distclean realclean maintainer-clean mostlyclean:
+
+.PHONY: lint
+lint:
+
+# distdir added for compatibility with CVS automake.
+top_distdir = ..
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+distdir: $(DISTFILES)
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" \
+ distdir=../$(distdir)/$$subdir \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+.PHONY: distdir
+
+# We don't have a real distclean or anything like that, but at least
+# we can get rid of the obj files and cvs.exe.
+.PHONY: clean distclean realclean mostlyclean maintainer-clean
+clean distclean realclean maintainer-clean mostlyclean:
+ rm -f cvs.exe cvs.out
+ rm -f ${srcdir}/*.o
+ rm -f ${diff_srcdir}/*.o
+ rm -f ${lib_dir}/*.o ${lib_dir}/*.a
+ rm -f ${zlib_dir}/*.o ${zlib_dir}/*.a
+ rm -f ${cvs_srcdir}/*.o
+
+clean-cvs:
+ del cvs.exe cvs.out
+ del $(subst /,\,${srcdir}/*.o)
+ del $(subst /,\,${diff_srcdir}/*.o)
+ del $(subst /,\,${lib_dir}/*.o ${lib_dir}/*.a)
+ del $(subst /,\,${zlib_dir}/*.o ${zlib_dir}/*.a)
+ del $(subst /,\,${cvs_srcdir}/*.o)
+
+install-cvs: cvs.exe
+ copy $(subst /,\,${srcdir}/cvs.exe ${install_dir}/cvs.exe)
+
+%.o: %.c
+ gcc ${OBJ_CFLAGS} ${CFLAGS} -o $@ -c $*.c
+
+${cvs_srcdir}/rcscmds.o: ${cvs_srcdir}/rcscmds.c ${top_srcdir}/diff/diffrun.h
+ gcc ${OBJ_CFLAGS} ${CFLAGS} -I${top_srcdir}/diff -o $@ -c $*.c
+
+${lib_dir}/libcvs.a: $(LIB_OBJECTS)
+ $(AR) cr $@ $(LIB_OBJECTS)
+
+${zlib_dir}/libz.a: $(ZLIB_OBJECTS)
+ $(AR) cr $@ $(ZLIB_OBJECTS)
+
+# Eventually probably static linking (cvs-static.exe) will be the
+# default, but even so we'll want to preserve this rule so we can
+# create a dynamically linked executable when we want coredumps.
+cvs.exe: ${OBJECTS} ${lib_dir}/libcvs.a ${zlib_dir}/libz.a
+ gcc $(COMMON_OBJECTS) $(OS2_OBJECTS) ${DIFF_OBJECTS} ${lib_dir}/libcvs.a ${zlib_dir}/libz.a $(LIB) -o cvs.out
+ emxbind -w -o $@.exe cvs.out
+
+${lib_dir}/libcvs.lib: ${lib_dir}/libcvs.a
+ emxomf ${lib_dir}/libcvs.a
+
+${zlib_dir}/libz.lib: ${zlib_dir}/libz.a
+ emxomf ${zlib_dir}/libz.a
+
+# Where do -Zomf -Zsys go? When we compile the .o's?
+# When I tried this rule, I had problems with (1) could not find
+# socket.lib. Hmm. I thought I converted it from socket.a
+# in the EMX distribution. Probably my EMX installation at fault.
+# (2) could not find miscellaneous system routines like strerror.
+# This might be a matter of learning to live without them (EMX
+# doc is supposed to describe which are present and which are not).
+# (3) some linker errors like no stack and the like. Maybe I am
+# missing some options?
+cvs-static.exe: ${OBJECTS} ${lib_dir}/libcvs.lib ${zlib_dir}/libz.lib
+ emxomf ${OBJECTS}
+ emxomfld -o $@ $(subst .o,.obj,${OBJECTS}) \
+ ${lib_dir}/libcvs.lib ${zlib_dir}/libz.lib ${LIB}
+
+# cvs.o: ${OBJECTS} ${SOURCES} ${HEADERS}
+
+# Hmm. This rule wants to exist on unix, so that "make dist" works.
+# And it doesn't want to exist on OS/2, because configure doesn't
+# run on OS/2 and so ../config.status won't exist. For now we just
+# say, in emx/README, that people will need to comment it out.
+Makefile: ../config.status $(srcdir)/Makefile.in
+ cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
diff --git a/emx/README b/emx/README
new file mode 100644
index 0000000..e0b3211
--- /dev/null
+++ b/emx/README
@@ -0,0 +1,70 @@
+
+CVS for OS/2
+based on EMX 0.9c (patch 02)
+
+
+This port works well in local mode. It fully respects the OS/2
+filename conventions, but only works on HPFS or other filesystem types
+which support long filenames (like ext2fs or Netware FS with OS/2
+namespace). It does _not_ work on FAT partitions or any other fs which
+does not support long filenames. The port also works in client mode.
+
+This port requires EMX 0.9c (patch 02) and the BSD libraries. It should
+work in local mode, in client mode and also in server mode. nServer mode
+will only work if the client uses the :server: method, because the CRLF
+handling of IBM's RSHD.EXE is not "compatible" with CVS. (If you find a
+better rshd for OS/2, please let us know!)
+
+To compile CVS for OS/2, you must install the following packages:
+
+ - EMX 0.9c (patch 02) and the GNU-C-Compiler
+
+ EMXDEV1.ZIP
+ EMXDEV2.ZIP
+ EMXRT.ZIP
+ GNUDEV1.ZIP
+ GNUDEV2.ZIP
+ BSDDEV.ZIP
+ EMXFIX02.ZIP
+
+ - GNU make for OS/2
+
+ GNUMAKE.ZIP
+
+ - ufc.a (ufc-crypt) as a replacement for crypt (this may be something
+ different if you live inside the USA). You don't need this one currently,
+ because the port of the server to OS/2 isn't done yet, but I'm mentioning
+ in case it is useful for future reference (we're probably better off
+ using a different password hash instead, as noted in item #184 of ../TODO).
+
+ GNUUFC.ZIP
+
+All packages can be found on ftp://ftp.leo.org/pub/comp/os/os2/leo/gnu
+(You may also try http://www.leo.org/pub/comp/os/os2/leo/gnu).
+
+Change to the `emx' directory, do "make" and get emx\cvs.exe. I had
+to comment out the "Makefile" rule in emx/Makefile to avoid a
+complaint about ../config.status not existing. You also might need to
+edit srcdir to be "." and top_srcdir to be "..".
+
+Assuming you have edited the `install_dir' variable in the Makefile,
+you may type "make install-cvs" to put cvs.exe in the right place.
+You may also "make clean-cvs" to clean up object and library files.
+
+The cvs.exe generated will require emx.dll to run. You can try
+compiling with -Zomf -Zsys to generate a cvs.exe without this
+requirement, but that almost surely will require significant changes
+to make it work. For the client, the big known problem would be that
+EMX 0.9c doesn't have sockets with -Zsys (according to the
+documentation). That seems like it would be hard to get around. For
+local, the big known problem is that -Zsys doesn't have fork(). This
+one isn't as bad--using os2/run.c or something similar instead of
+src/run.c should solve this problem.
+
+You will get warnings in lib/getdate.c. These are yacc's fault; ignore
+them.
+
+You will get about 5 warnings in lib/regex.c concerning "unused variable
+destination". Ignore them.
+
+Report bugs to tepting@swol.de and bug-cvs@nongnu.org.
diff --git a/emx/config.h b/emx/config.h
new file mode 100644
index 0000000..1cc6474
--- /dev/null
+++ b/emx/config.h
@@ -0,0 +1,446 @@
+/* config.h --- configuration file for OS/2 EMX
+ Thomas Epting <tepting@swol.de> --- Feb 1997 */
+
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This file lives in the emx/ subdirectory, which is only included
+ * in your header search path if you use emx/Makefile (with GNU make
+ * for OS/2). Thus, this is the right place to put configuration
+ * information for OS/2.
+ */
+
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define if utime(file, NULL) sets file's timestamp to the present. */
+#define HAVE_UTIME_NULL 1
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* #undef STAT_MACROS_BROKEN */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define if you have MIT Kerberos version 4 available. */
+#undef HAVE_KERBEROS
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#define CLIENT_SUPPORT 1
+
+#if 0
+/* This doesn't work yet, and I'm sure I don't want the hassles of seeing
+ whether it will compile. */
+/* Define if you want CVS to be able to serve repositories to remote
+ clients. */
+#define SERVER_SUPPORT 1
+
+/* Define if you want to use the password authenticated server. */
+#define AUTH_SERVER_SUPPORT
+#endif /* 0 */
+
+/* Define if you want encryption support. */
+/* #undef ENCRYPTION */
+
+/* Define if you have the connect function. */
+#define HAVE_CONNECT 1
+
+/* Define if you have the crypt function. */
+#define HAVE_CRYPT 1
+
+/* Define if you have the fchdir function. */
+/* #define HAVE_FCHDIR */
+
+/* Define if you have the fchmod function. */
+/* #define HAVE_FCHMOD */
+
+/* Define if you have the fsync function. */
+#define HAVE_FSYNC 1
+
+/* Define if you have the ftime function. */
+#define HAVE_FTIME 1
+
+/* Define if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define if you have the getpagesize function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the getspnam function. */
+/* #define HAVE_GETSPNAM */
+
+/* Define if you have the initgroups function. */
+/* #define HAVE_INITGROUPS */
+
+/* Define if you have the krb_get_err_text function. */
+/* #undef HAVE_KRB_GET_ERR_TEXT */
+
+/* Define if you have the putenv function. */
+#define HAVE_PUTENV 1
+
+/* Define if you have the readlink function. */
+/* #define HAVE_READLINK */
+
+/* Define if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define if you have the sigblock function. */
+/* #undef HAVE_SIGBLOCK */
+
+/* Define if you have the sigprocmask function. */
+#define HAVE_SIGPROCMASK 1
+
+/* Define if you have the sigsetmask function. */
+/* #undef HAVE_SIGSETMASK */
+
+/* Define if you have the sigvec function. */
+/* #undef HAVE_SIGVEC */
+
+/* Define if you have the timezone function. */
+#define HAVE_TIMEZONE 1
+
+/* Define if you have the tzset function. */
+#define HAVE_TZSET 1
+
+/* Define if you have the vfork function. */
+/* #undef HAVE_VFORK */
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the <direct.h> header file. */
+/* #undef HAVE_DIRECT_H */
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndbm.h> header file. */
+/* #undef HAVE_NDBM_H 1 */
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/bsdtypes.h> header file. */
+/* #undef HAVE_SYS_BSDTYPES_H */
+
+/* Define if you have the <sys/dir.h> header file. */
+#define HAVE_SYS_DIR_H 1
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define if you have the crypt library (-lcrypt). */
+#define HAVE_LIBCRYPT 1
+
+/* Define if you have the inet library (-linet). */
+/* #undef HAVE_LIBINET */
+
+/* Define if you have the nsl library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define if you have the nsl_s library (-lnsl_s). */
+/* #undef HAVE_LIBNSL_S */
+
+/* Define if you have the sec library (-lsec). */
+/* #undef HAVE_LIBSEC 1 */
+
+/* Define if you have the socket library (-lsocket). */
+#define HAVE_LIBSOCKET 1
+
+/* Under OS/2, filenames are case-insensitive, and both / and \
+ are path component separators. */
+#define FOLD_FN_CHAR(c) (OS2_filename_classes[(unsigned char) (c)])
+extern unsigned char OS2_filename_classes[];
+
+/* Is the character C a path name separator? Under OS/2, you can use
+ either / or \. */
+#define ISDIRSEP(c) (FOLD_FN_CHAR(c) == '/')
+
+/* Like strcmp, but with the appropriate tweaks for file names.
+ Under OS/2, filenames are case-insensitive but case-preserving,
+ and both \ and / are path element separators. */
+extern int fncmp (const char *n1, const char *n2);
+
+/* Fold characters in FILENAME to their canonical forms.
+ If FOLD_FN_CHAR is not #defined, the system provides a default
+ definition for this. */
+extern void fnfold (char *FILENAME);
+
+/* This is where old bits go to die under OS/2 as well as WinNT. */
+#define DEVNULL "nul"
+
+/* We actually do have a transparent rsh, whew. */
+#undef RSH_NOT_TRANSPARENT
+/* But it won't be transparent unless we ask it nicely! */
+#define RSH_NEEDS_BINARY_FLAG 1
+
+#define START_SERVER os2_start_server
+#define SHUTDOWN_SERVER os2_shutdown_server
+
+extern void START_SERVER (int *tofd, int *fromfd,
+ char *client_user,
+ char *server_user,
+ char *server_host,
+ char *server_cvsroot);
+extern void SHUTDOWN_SERVER (int fd);
+
+/* Call our own os2_initialize function */
+#define SYSTEM_INITIALIZE(pargc,pargv) os2_initialize (pargc, pargv)
+extern void os2_initialize (int *pargc, char ***pargv);
+
+/* Under EMX, we already have popen() and pclose()... */
+/* #undef USE_OWN_POPEN */
+/* ... and we too have no need for popenRW to start the rsh server. */
+/* #define START_RSH_WITH_POPEN_RW */
+
+/* Socket handles and file handles share a command handle space under EMX. */
+/* #undef NO_SOCKET_TO_FD */
+
+
+
+#define CVS_STAT os2_stat
+#define CVS_CHDIR os2_chdir
+#define CVS_FNMATCH os2_fnmatch
+
+extern int os2_stat(const char *name, struct stat *buffer);
+extern int os2_chdir(const char *name);
+extern int os2_fnmatch(const char *pattern, const char *name, int flags);
+
+/* Pipes need to be put into binary mode using setmode (). */
+#define USE_SETMODE_BINARY 1
+
+/* The reason for this is that we don't know whether to pass -b to
+ rsh. The system-supplied rsh on OS/2 wants it. Some other rsh
+ replacement might not accept it. Historically, the NT port of CVS
+ has not passed -b, and the OS/2 port has. What a mess. If we can
+ get away with just not accepting :ext: until we can figure out how
+ we should deal with this, then it will avoid having people rely on
+ behaviors which will need to change. */
+#define NO_EXT_METHOD 1
+
+/* See above; we can't use rsh without -b. */
+#define RSH_NOT_TRANSPARENT 1
+
+/* See discussion at xchmod in filesubr.c. */
+#define CHMOD_BROKEN 1
+
+/*
+ * The following configuration options used to be defined in options.h.
+ */
+
+/*
+ * When committing a permanent change, CVS and RCS make a log entry of
+ * who committed the change. If you are committing the change logged in
+ * as "root" (not under "su" or other root-priv giving program), CVS/RCS
+ * cannot determine who is actually making the change.
+ *
+ * As such, by default, CVS disallows changes to be committed by users
+ * logged in as "root". You can disable this option by commenting
+ * out the lines below.
+ *
+ * Under Windows NT, privileges are associated with groups, not users,
+ * so the case in which someone has logged in as root does not occur.
+ * Thus, there is no need for this hack.
+ *
+ * todo: I don't know why emx had CVS_BADROOT commented out too, but
+ * historically it has been in the obsolete options.h file. -DRP
+ */
+#undef CVS_BADROOT
+
+/*
+ * For portability and heterogeneity reasons, CVS is shipped by
+ * default using my own text-file version of the ndbm database library
+ * in the src/myndbm.c file. If you want better performance and are
+ * not concerned about heterogeneous hosts accessing your modules
+ * file, turn this option off.
+ */
+#ifndef MY_NDBM
+#define MY_NDBM
+#endif
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little
+ need to change this (-T is a better mechanism if you need to use a
+ different directory for temporary files). */
+#ifndef TMPDIR_DFLT
+#define TMPDIR_DFLT "/tmp"
+#endif
+
+/*
+ * The default editor to use, if one does not specify the "-e" option
+ * to cvs, or does not have an EDITOR environment variable. I set
+ * this to just "vi", and use the shell to find where "vi" actually
+ * is. This allows sites with /usr/bin/vi or /usr/ucb/vi to work
+ * equally well (assuming that your PATH is reasonable).
+ */
+#ifndef EDITOR_DFLT
+#define EDITOR_DFLT "e"
+#endif
+
+/*
+ * The default umask to use when creating or otherwise setting file or
+ * directory permissions in the repository. Must be a value in the
+ * range of 0 through 0777. For example, a value of 002 allows group
+ * rwx access and world rx access; a value of 007 allows group rwx
+ * access but no world access. This value is overridden by the value
+ * of the CVSUMASK environment variable, which is interpreted as an
+ * octal number.
+ */
+#ifndef UMASK_DFLT
+#define UMASK_DFLT 002
+#endif
+
+/*
+ * The cvs admin command is restricted to the members of the group
+ * CVS_ADMIN_GROUP. If this group does not exist, all users are
+ * allowed to run cvs admin. To disable the cvs admin for all users,
+ * create an empty group CVS_ADMIN_GROUP. To disable access control
+ * for cvs admin, comment out the define below.
+ */
+#ifndef CVS_ADMIN_GROUP
+#define CVS_ADMIN_GROUP "cvsadmin"
+#endif
+
+/*
+ * When committing or importing files, you must enter a log message.
+ * Normally, you can do this either via the -m flag on the command
+ * line or an editor will be started for you. If you like to use
+ * logging templates (the rcsinfo file within the $CVSROOT/CVSROOT
+ * directory), you might want to force people to use the editor even
+ * if they specify a message with -m. Enabling FORCE_USE_EDITOR will
+ * cause the -m message to be appended to the temp file when the
+ * editor is started.
+ */
+#ifndef FORCE_USE_EDITOR
+/* #define FORCE_USE_EDITOR */
+#endif
+
+#ifndef CVS_FUDGELOCKS
+/* #define CVS_FUDGELOCKS */
+#endif
+
+/*
+ * Should we build the password-authenticating client? Whether to
+ * include the password-authenticating _server_, on the other hand, is
+ * set in config.h.
+ */
+#ifdef CLIENT_SUPPORT
+#define AUTH_CLIENT_SUPPORT 1
+#endif
+
+/*
+ * If you are working with a large remote repository and a 'cvs
+ * checkout' is swamping your network and memory, define these to
+ * enable flow control. You will end up with even less probability of
+ * a consistent checkout (see Concurrency in cvs.texinfo), but CVS
+ * doesn't try to guarantee that anyway. The master server process
+ * will monitor how far it is getting behind, if it reaches the high
+ * water mark, it will signal the child process to stop generating
+ * data when convenient (ie: no locks are held, currently at the
+ * beginning of a new directory). Once the buffer has drained
+ * sufficiently to reach the low water mark, it will be signalled to
+ * start again. You may override the default hi/low watermarks here
+ * too.
+ */
+#define SERVER_FLOWCONTROL
+#define SERVER_HI_WATER (2 * 1024 * 1024)
+#define SERVER_LO_WATER (1 * 1024 * 1024)
+
+/* End of CVS options.h section */
+
+/* Return non-zero iff FILENAME is absolute.
+ Trivial under Unix, but more complicated under other systems.
+ Under EMX let _fnisabs do all this work. */
+#define ISABSOLUTE(filename) _fnisabs(filename);
diff --git a/emx/filesubr.c b/emx/filesubr.c
new file mode 100644
index 0000000..145d5a3
--- /dev/null
+++ b/emx/filesubr.c
@@ -0,0 +1,804 @@
+/* filesubr.c --- subroutines for dealing with files
+ Jim Blandy <jimb@cyclic.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* These functions were moved out of subr.c because they need different
+ definitions under operating systems (like, say, Windows NT) with different
+ file system semantics. */
+
+#include "cvs.h"
+#include <sys/param.h>
+
+/*
+ * I don't know of a convenient way to test this at configure time, or else
+ * I'd certainly do it there.
+ */
+#if defined(NeXT)
+#define LOSING_TMPNAM_FUNCTION
+#endif
+
+static int deep_remove_dir( const char *path );
+
+/*
+ * Copies "from" to "to".
+ */
+void
+copy_file (from, to)
+ const char *from;
+ const char *to;
+{
+ struct stat sb;
+ struct utimbuf t;
+ int fdin, fdout;
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open %s for copying", from);
+ if (fstat (fdin, &sb) < 0)
+ error (1, errno, "cannot fstat %s", from);
+ if ((fdout = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
+ (int) sb.st_mode & 07777)) < 0)
+ error (1, errno, "cannot create %s for copying", to);
+ if (sb.st_size > 0)
+ {
+ char buf[BUFSIZ];
+ int n;
+
+ for (;;)
+ {
+ n = read (fdin, buf, sizeof(buf));
+ if (n == -1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ error (1, errno, "cannot read file %s for copying", from);
+ }
+ else if (n == 0)
+ break;
+
+ if (write(fdout, buf, n) != n) {
+ error (1, errno, "cannot write file %s for copying", to);
+ }
+ }
+
+#ifdef HAVE_FSYNC
+ if (fsync (fdout))
+ error (1, errno, "cannot fsync file %s after copying", to);
+#endif
+ }
+
+ if (close (fdin) < 0)
+ error (0, errno, "cannot close %s", from);
+ if (close (fdout) < 0)
+ error (1, errno, "cannot close %s", to);
+
+ /* now, set the times for the copied file to match those of the original */
+ memset ((char *) &t, 0, sizeof (t));
+ t.actime = sb.st_atime;
+ t.modtime = sb.st_mtime;
+ (void) utime (to, &t);
+}
+
+/* FIXME-krp: these functions would benefit from caching the char * &
+ stat buf. */
+
+/*
+ * Returns non-zero if the argument file is a directory, or is a symbolic
+ * link which points to a directory.
+ */
+int
+isdir (file)
+ const char *file;
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return (0);
+ return (S_ISDIR (sb.st_mode));
+}
+
+/*
+ * Returns non-zero if the argument file is a symbolic link.
+ */
+int
+islink (file)
+ const char *file;
+{
+#ifdef S_ISLNK
+ struct stat sb;
+
+ if (lstat (file, &sb) < 0)
+ return (0);
+ return (S_ISLNK (sb.st_mode));
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Returns non-zero if the argument file exists.
+ */
+int
+isfile (file)
+ const char *file;
+{
+ return isaccessible(file, F_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is readable.
+ */
+int
+isreadable (file)
+ const char *file;
+{
+ return isaccessible(file, R_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is writable.
+ */
+int
+iswritable (file)
+ const char *file;
+{
+ return isaccessible(file, W_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is accessable according to
+ * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
+ * bits set.
+ */
+int
+isaccessible (file, mode)
+ const char *file;
+ const int mode;
+{
+#ifdef SETXID_SUPPORT
+ struct stat sb;
+ int umask = 0;
+ int gmask = 0;
+ int omask = 0;
+ int uid;
+
+ if (stat(file, &sb) == -1)
+ return 0;
+ if (mode == F_OK)
+ return 1;
+
+ uid = geteuid();
+ if (uid == 0) /* superuser */
+ {
+ if (mode & X_OK)
+ return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
+ else
+ return 1;
+ }
+
+ if (mode & R_OK)
+ {
+ umask |= S_IRUSR;
+ gmask |= S_IRGRP;
+ omask |= S_IROTH;
+ }
+ if (mode & W_OK)
+ {
+ umask |= S_IWUSR;
+ gmask |= S_IWGRP;
+ omask |= S_IWOTH;
+ }
+ if (mode & X_OK)
+ {
+ umask |= S_IXUSR;
+ gmask |= S_IXGRP;
+ omask |= S_IXOTH;
+ }
+
+ if (sb.st_uid == uid)
+ return (sb.st_mode & umask) == umask;
+ else if (sb.st_gid == getegid())
+ return (sb.st_mode & gmask) == gmask;
+ else
+ return (sb.st_mode & omask) == omask;
+#else
+ return access(file, mode) == 0;
+#endif
+}
+
+
+
+/*
+ * Make a directory and die if it fails
+ */
+void
+make_directory (name)
+ const char *name;
+{
+ struct stat sb;
+
+ if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
+ error (0, 0, "%s already exists but is not a directory", name);
+ if (!noexec && mkdir (name, 0777) < 0)
+ error (1, errno, "cannot make directory %s", name);
+}
+
+/*
+ * Make a path to the argument directory, printing a message if something
+ * goes wrong.
+ */
+void
+make_directories (name)
+ const char *name;
+{
+ char *cp;
+
+ if (noexec)
+ return;
+
+ if (mkdir (name, 0777) == 0 || errno == EEXIST)
+ return;
+ if (! existence_error (errno))
+ {
+ error (0, errno, "cannot make path to %s", name);
+ return;
+ }
+ if ((cp = strrchr (name, '/')) == NULL)
+ return;
+ *cp = '\0';
+ make_directories (name);
+ *cp++ = '/';
+ if (*cp == '\0')
+ return;
+ (void) mkdir (name, 0777);
+}
+
+/* Create directory NAME if it does not already exist; fatal error for
+ other errors. Returns 0 if directory was created; 1 if it already
+ existed. */
+int
+mkdir_if_needed (name)
+ char *name;
+{
+ if (mkdir (name, 0777) < 0)
+ {
+ if (errno != EEXIST)
+ error (1, errno, "cannot make directory %s", name);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Change the mode of a file, either adding write permissions, or removing
+ * all write permissions. Either change honors the current umask setting.
+ * The EMX doc (0.9c, emxlib.doc) says that chmod sets/clears the readonly
+ * bit. But it always seemed to be a noop when I tried it. Therefore,
+ * I've copied over the "attrib" code from os2/filesubr.c.
+ */
+void
+xchmod (fname, writable)
+ char *fname;
+ int writable;
+{
+ char *attrib_cmd;
+ char *attrib_option;
+ char *whole_cmd;
+ char *p;
+ char *q;
+
+ if (!isfile (fname))
+ {
+ error (0, 0, "cannot change mode of file %s; it does not exist",
+ fname);
+ return;
+ }
+
+ attrib_cmd = "attrib "; /* No, really? */
+
+ if (writable)
+ attrib_option = "-r "; /* make writeable */
+ else
+ attrib_option = "+r "; /* make read-only */
+
+ whole_cmd = xmalloc (strlen (attrib_cmd)
+ + strlen (attrib_option)
+ + strlen (fname)
+ + 1);
+
+ strcpy (whole_cmd, attrib_cmd);
+ strcat (whole_cmd, attrib_option);
+
+ /* Copy fname to the end of whole_cmd, translating / to \.
+ Attrib doesn't take / but many parts of CVS rely
+ on being able to use it. */
+ p = whole_cmd + strlen (whole_cmd);
+ q = fname;
+ while (*q)
+ {
+ if (*q == '/')
+ *p++ = '\\';
+ else
+ *p++ = *q;
+ ++q;
+ }
+ *p = '\0';
+
+ system (whole_cmd);
+ free (whole_cmd);
+}
+
+/*
+ * Rename a file and die if it fails
+ */
+void
+rename_file (from, to)
+ const char *from;
+ const char *to;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ unlink_file (to);
+ if (rename (from, to) != 0)
+ error (1, errno, "cannot rename file %s to %s", from, to);
+}
+
+/*
+ * unlink a file, if possible.
+ */
+int
+unlink_file (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ if (isfile (f))
+ xchmod ((char *)f, 1);
+ return (unlink (f));
+}
+
+/*
+ * Unlink a file or dir, if possible. If it is a directory do a deep
+ * removal of all of the files in the directory. Return -1 on error
+ * (in which case errno is set).
+ */
+int
+unlink_file_dir (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ /* For at least some unices, if root tries to unlink() a directory,
+ instead of doing something rational like returning EISDIR,
+ the system will gleefully go ahead and corrupt the filesystem.
+ So we first call isdir() to see if it is OK to call unlink(). This
+ doesn't quite work--if someone creates a directory between the
+ call to isdir() and the call to unlink(), we'll still corrupt
+ the filesystem. Where is the Unix Haters Handbook when you need
+ it? */
+ if (isdir(f))
+ return deep_remove_dir(f);
+ else
+ {
+ if (unlink (f) != 0)
+ return -1;
+ }
+ /* We were able to remove the file from the disk */
+ return 0;
+}
+
+/* Remove a directory and everything it contains. Returns 0 for
+ * success, -1 for failure (in which case errno is set).
+ */
+
+static int
+deep_remove_dir (path)
+ const char *path;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char buf[PATH_MAX];
+
+ if (rmdir (path) != 0)
+ {
+ if (errno == ENOTEMPTY
+ || errno == EEXIST
+ /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug
+ (it defines ENOTEMPTY and EEXIST to 17 but actually
+ returns 87). */
+ || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
+ {
+ if ((dirp = opendir (path)) == NULL)
+ /* If unable to open the directory return
+ * an error
+ */
+ return -1;
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0)
+ continue;
+
+ sprintf (buf, "%s/%s", path, dp->d_name);
+
+ /* See comment in unlink_file_dir explanation of why we use
+ isdir instead of just calling unlink and checking the
+ status. */
+ if (isdir(buf))
+ {
+ if (deep_remove_dir(buf))
+ {
+ closedir(dirp);
+ return -1;
+ }
+ }
+ else
+ {
+ if (unlink (buf) != 0)
+ {
+ closedir(dirp);
+ return -1;
+ }
+ }
+ }
+ closedir (dirp);
+ return rmdir (path);
+ }
+ else
+ return -1;
+ }
+
+ /* Was able to remove the directory return 0 */
+ return 0;
+}
+
+/* Read NCHARS bytes from descriptor FD into BUF.
+ Return the number of characters successfully read.
+ The number returned is always NCHARS unless end-of-file or error. */
+static size_t
+block_read (fd, buf, nchars)
+ int fd;
+ char *buf;
+ size_t nchars;
+{
+ char *bp = buf;
+ size_t nread;
+
+ do
+ {
+ nread = read (fd, bp, nchars);
+ if (nread == (size_t)-1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ return (size_t)-1;
+ }
+
+ if (nread == 0)
+ break;
+
+ bp += nread;
+ nchars -= nread;
+ } while (nchars != 0);
+
+ return bp - buf;
+}
+
+
+/*
+ * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
+ */
+int
+xcmp (file1, file2)
+ const char *file1;
+ const char *file2;
+{
+ char *buf1, *buf2;
+ struct stat sb1, sb2;
+ int fd1, fd2;
+ int ret;
+
+ if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file1);
+ if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file2);
+ if (fstat (fd1, &sb1) < 0)
+ error (1, errno, "cannot fstat %s", file1);
+ if (fstat (fd2, &sb2) < 0)
+ error (1, errno, "cannot fstat %s", file2);
+
+ /* A generic file compare routine might compare st_dev & st_ino here
+ to see if the two files being compared are actually the same file.
+ But that won't happen in CVS, so we won't bother. */
+
+ if (sb1.st_size != sb2.st_size)
+ ret = 1;
+ else if (sb1.st_size == 0)
+ ret = 0;
+ else
+ {
+ /* FIXME: compute the optimal buffer size by computing the least
+ common multiple of the files st_blocks field */
+ size_t buf_size = 8 * 1024;
+ size_t read1;
+ size_t read2;
+
+ buf1 = xmalloc (buf_size);
+ buf2 = xmalloc (buf_size);
+
+ do
+ {
+ read1 = block_read (fd1, buf1, buf_size);
+ if (read1 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file1);
+
+ read2 = block_read (fd2, buf2, buf_size);
+ if (read2 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file2);
+
+ /* assert (read1 == read2); */
+
+ ret = memcmp(buf1, buf2, read1);
+ } while (ret == 0 && read1 == buf_size);
+
+ free (buf1);
+ free (buf2);
+ }
+
+ (void) close (fd1);
+ (void) close (fd2);
+ return (ret);
+}
+
+
+/* Just in case this implementation does not define this. */
+#ifndef L_tmpnam
+#define L_tmpnam 50
+#endif
+
+
+#ifdef LOSING_TMPNAM_FUNCTION
+char *
+cvs_temp_name ()
+{
+ char value[L_tmpnam + 1];
+
+ /* FIXME: Should be using TMPDIR. */
+ strcpy (value, "/tmp/cvsXXXXXX");
+ mktemp (value);
+ return xstrdup (value);
+}
+#else
+/* Generate a unique temporary filename. Returns a pointer to a newly
+ malloc'd string containing the name. Returns successfully or not at
+ all. */
+char *
+cvs_temp_name ()
+{
+ char value[L_tmpnam + 1];
+ char *retval;
+
+ /* FIXME: should be using TMPDIR, perhaps by using tempnam on systems
+ which have it. */
+ retval = tmpnam (value);
+ if (retval == NULL)
+ error (1, errno, "cannot generate temporary filename");
+ return xstrdup (retval);
+}
+#endif
+
+
+
+/* char *
+ * xresolvepath ( const char *path )
+ *
+ * Like xreadlink(), but resolve all links in a path.
+ *
+ * INPUTS
+ * path The original path.
+ *
+ * RETURNS
+ * The path with any symbolic links expanded.
+ *
+ * ERRORS
+ * This function exits with a fatal error if it fails to read the link for
+ * any reason.
+ */
+char *
+xresolvepath ( path )
+ const char *path;
+{
+ char *hardpath;
+ char *owd;
+
+ /* assert ( isdir ( path ) ); */
+
+ /* FIXME - If HAVE_READLINK is defined, we should probably walk the path
+ * bit by bit calling xreadlink().
+ */
+
+ owd = xgetwd();
+ if ( CVS_CHDIR ( path ) < 0)
+ error ( 1, errno, "cannot chdir to %s", path );
+ if ( ( hardpath = xgetwd() ) == NULL )
+ error (1, errno, "cannot readlink %s", hardpath);
+ if ( CVS_CHDIR ( owd ) < 0)
+ error ( 1, errno, "cannot chdir to %s", owd );
+ free (owd);
+ return hardpath;
+}
+
+/* Return a pointer into PATH's last component. */
+char *
+last_component (path)
+ char *path;
+{
+ char *last;
+
+ /* We can't be sure here if 'path' is already slashified. */
+ _fnslashify (path);
+
+ last = strrchr (path, '/');
+
+ if (last && (last != path))
+ return last + 1;
+ else
+ return path;
+}
+
+/* Return the home directory. Returns a pointer to storage
+ managed by this function or its callees (currently getenv).
+ This function will return the same thing every time it is
+ called. */
+char *
+get_homedir ()
+{
+ static char *home = NULL;
+ char *env = getenv ("HOME");
+ struct passwd *pw;
+
+ if (home != NULL)
+ return home;
+
+ if (env)
+ home = env;
+ else if ((pw = (struct passwd *) getpwuid (getuid ()))
+ && pw->pw_dir)
+ home = xstrdup (pw->pw_dir);
+ else
+ return 0;
+
+ return home;
+}
+
+/* See cvs.h for description. On unix this does nothing, because the
+ shell expands the wildcards. Under EMX, use _fnexplode to get the
+ expanded filenames */
+void
+expand_wild (argc, argv, pargc, pargv)
+ int argc;
+ char **argv;
+ int *pargc;
+ char ***pargv;
+{
+ int i;
+ *pargc = argc;
+ *pargv = (char **) xmalloc (argc * sizeof (char *));
+ for (i = 0; i < argc; ++i)
+ (*pargv)[i] = xstrdup (argv[i]);
+}
+
+unsigned char
+OS2_filename_classes[] =
+{
+ 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
+ 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
+ 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
+ 0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
+ 0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
+ 0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
+ 0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
+ 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
+};
+
+
+/* Like strcmp, but with the appropriate tweaks for file names.
+ Under OS/2, filenames are case-insensitive but case-preserving, and
+ both \ and / are path element separators. */
+int
+fncmp (const char *n1, const char *n2)
+{
+ char fn1[MAXNAMLEN], fn2[MAXNAMLEN];
+
+ strcpy (fn1, n1); _fnslashify(fn1);
+ strcpy (fn2, n2); _fnslashify(fn2);
+
+ return _fncmp ((unsigned char *) fn1, (unsigned char *) fn2);
+}
+
+
+/* Fold characters in FILENAME to their canonical forms.
+ If FOLD_FN_CHAR is not #defined, the system provides a default
+ definition for this. */
+void
+fnfold (char *filename)
+{
+ while (*filename)
+ {
+ *filename = FOLD_FN_CHAR (*filename);
+ filename++;
+ }
+}
diff --git a/emx/rcmd.h b/emx/rcmd.h
new file mode 100644
index 0000000..a1fbf02
--- /dev/null
+++ b/emx/rcmd.h
@@ -0,0 +1,46 @@
+/* rcmd.h --- interface to executing commands on remote hosts
+ Karl Fogel <kfogel@cyclic.com> --- November 1995 */
+
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* Run the command CMD on the host *AHOST, and return a file descriptor for
+ a bidirectional stream socket connected to the command's standard input
+ and output.
+
+ rcmd looks up *AHOST using gethostbyname, and sets *AHOST to the host's
+ canonical name. If *AHOST is not found, rcmd returns -1.
+
+ rcmd connects to the remote host at TCP port INPORT. This should
+ probably be the "shell" service, port 514.
+
+ LOCUSER is the name of the user on the local machine, and REMUSER is
+ the name of the user on the remote machine; the remote machine uses this,
+ along with the source address of the TCP connection, to authenticate
+ the connection.
+
+ CMD is the command to execute. The remote host will tokenize it any way
+ it damn well pleases. Welcome to Unix.
+
+ FD2P is a feature we don't support, but there's no point in making mindless
+ deviations from the interface. Callers should always pass this argument
+ as zero. */
+
+/* Note that because we are using windows-NT/rcmd.c, this declaration
+ must match windows-NT/rcmd.h (and rcmd.c). It would be much
+ more sensible to use a common header file. But I haven't bothered to
+ adjust the makefile accordingly, yet. Probably the best long-term
+ home for this would be in lib/rcmd.*, or perhaps src. */
+extern int rcmd (const char **AHOST,
+ unsigned short INPORT,
+ char *LOCUSER,
+ char *REMUSER,
+ char *CMD,
+ int *fd2p);
diff --git a/emx/savecwd.c b/emx/savecwd.c
new file mode 100644
index 0000000..c1fe9a7
--- /dev/null
+++ b/emx/savecwd.c
@@ -0,0 +1,141 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# include <sys/file.h>
+#endif
+
+#ifdef HAVE_DIRECT_H
+# include <direct.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include <errno.h>
+# ifndef errno
+extern int errno;
+#endif
+
+#include "savecwd.h"
+#include "error.h"
+
+char *xgetwd( void );
+
+/* Record the location of the current working directory in CWD so that
+ the program may change to other directories and later use restore_cwd
+ to return to the recorded location. This function may allocate
+ space using malloc (via xgetwd) or leave a file descriptor open;
+ use free_cwd to perform the necessary free or close. Upon failure,
+ no memory is allocated, any locally opened file descriptors are
+ closed; return non-zero -- in that case, free_cwd need not be
+ called, but doing so is ok. Otherwise, return zero. */
+
+int
+save_cwd (cwd)
+ struct saved_cwd *cwd;
+{
+ static int have_working_fchdir = 1;
+
+ cwd->desc = -1;
+ cwd->name = NULL;
+
+ if (have_working_fchdir)
+ {
+#ifdef HAVE_FCHDIR
+ cwd->desc = open (".", O_RDONLY);
+ if (cwd->desc < 0)
+ {
+ error (0, errno, "cannot open current directory");
+ return 1;
+ }
+
+# if __sun__ || sun
+ /* On SunOS 4, fchdir returns EINVAL if accounting is enabled,
+ so we have to fall back to chdir. */
+ if (fchdir (cwd->desc))
+ {
+ if (errno == EINVAL)
+ {
+ close (cwd->desc);
+ cwd->desc = -1;
+ have_working_fchdir = 0;
+ }
+ else
+ {
+ error (0, errno, "current directory");
+ close (cwd->desc);
+ cwd->desc = -1;
+ return 1;
+ }
+ }
+# endif /* __sun__ || sun */
+#else
+#define fchdir(x) (abort (), 0)
+ have_working_fchdir = 0;
+#endif
+ }
+
+ if (!have_working_fchdir)
+ {
+ cwd->name = xgetwd ();
+ if (cwd->name == NULL)
+ {
+ error (0, errno, "cannot get current directory");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Change to recorded location, CWD, in directory hierarchy.
+ If "saved working directory", NULL))
+ */
+
+int
+restore_cwd (cwd, dest)
+ const struct saved_cwd *cwd;
+ const char *dest;
+{
+ int fail = 0;
+ if (cwd->desc >= 0)
+ {
+ if (fchdir (cwd->desc))
+ {
+ error (0, errno, "cannot return to %s",
+ (dest ? dest : "saved working directory"));
+ fail = 1;
+ }
+ }
+ else if (_chdir2 (cwd->name) < 0)
+ {
+ error (0, errno, "%s", cwd->name);
+ fail = 1;
+ }
+ return fail;
+}
+
+void
+free_cwd (cwd)
+ struct saved_cwd *cwd;
+{
+ if (cwd->desc >= 0)
+ close (cwd->desc);
+ if (cwd->name)
+ free (cwd->name);
+}
+
diff --git a/emx/startserver.c b/emx/startserver.c
new file mode 100644
index 0000000..d7e4189
--- /dev/null
+++ b/emx/startserver.c
@@ -0,0 +1,82 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <assert.h>
+#include "cvs.h"
+#include "rcmd.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+static char *cvs_server;
+static char *command;
+
+extern int trace;
+
+void
+os2_start_server (int *tofd, int *fromfd,
+ char *client_user,
+ char *server_user,
+ char *server_host,
+ char *server_cvsroot)
+{
+ int fd, port;
+ char *portenv;
+ struct servent *sptr;
+ const char *rcmd_host = (const char *) server_host;
+
+ if (! (cvs_server = getenv ("CVS_SERVER")))
+ cvs_server = "cvs";
+ command = xmalloc (strlen (cvs_server)
+ + strlen (server_cvsroot)
+ + 50);
+ sprintf (command, "%s server", cvs_server);
+
+ portenv = getenv ("CVS_RCMD_PORT");
+ if (portenv)
+ port = atoi (portenv);
+ else if ((sptr = getservbyname ("shell", "tcp")) != NULL)
+ port = sptr->s_port;
+ else
+ port = 514; /* shell/tcp */
+
+ if (trace)
+ {
+ fprintf (stderr, "os2_start_server(): connecting to %s:%d\n",
+ server_host, port);
+ fprintf (stderr, "local_user = %s, remote_user = %s, CVSROOT = %s\n",
+ client_user, (server_user ? server_user : client_user),
+ server_cvsroot);
+ }
+
+ fd = rcmd (&rcmd_host, port,
+ client_user,
+ (server_user ? server_user : client_user),
+ command, 0);
+
+ if (fd < 0)
+ error (1, errno, "cannot start server via rcmd()");
+
+ *tofd = fd;
+ *fromfd = fd;
+ free (command);
+}
+
+void
+os2_shutdown_server (int fd)
+{
+ /* FIXME: shutdown on files seems to have no bad effects */
+ if (shutdown (fd, 2) < 0 && errno != ENOTSOCK)
+ error (1, 0, "couldn't shutdown server connection");
+ if (close (fd) < 0)
+ error (1, 0, "couldn't close server connection");
+}
+
diff --git a/emx/system.c b/emx/system.c
new file mode 100644
index 0000000..f4481b3
--- /dev/null
+++ b/emx/system.c
@@ -0,0 +1,91 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fnmatch.h>
+
+
+/* Expand wildcards in argv. We probably should be expanding wildcards
+ via expand_wild instead; that way we could expand only filenames and
+ not tag names and the like. */
+
+void
+os2_initialize (pargc, pargv)
+ int *pargc;
+ char **pargv[];
+{
+ _wildcard (pargc, pargv);
+}
+
+
+/* Modifies 'stat' so that always the same inode is returned. EMX never
+ returns the same value for st_ino. Without this modification,
+ release_delete in module src/release.c refuses to work. Care must
+ be taken if someone is using the value of st_ino (but as far as I know,
+ no callers are). */
+
+int
+os2_stat (name, buffer)
+ const char *name;
+ struct stat *buffer;
+{
+ int rc = stat (name, buffer);
+
+ /* There are no inodes on OS/2. */
+ buffer->st_ino = 42;
+
+ return rc;
+}
+
+
+/* We must not only change the directory, but also the current drive.
+ Otherwise it is be impossible to have the working directory and the
+ repository on different drives. */
+
+int
+os2_chdir (name)
+ const char *name;
+{
+ return _chdir2 (name);
+}
+
+
+/* getwd must return a drive specification. */
+
+char *
+xgetwd ()
+{
+ return _getcwd2 (NULL, 1);
+}
+
+
+/* fnmatch must recognize OS/2 filename conventions: Filename case
+ must be preserved, but ignored in searches. It would perhaps be better
+ to just have CVS pick how to match based on FILENAMES_CASE_INSENSITIVE
+ or something rather than having an OS/2-specific version of CVS_FNMATCH.
+ Note that lib/fnmatch.c uses FOLD_FN_CHAR; that is how we get
+ case-insensitivity on NT (and VMS, I think). */
+
+#define _FNM_OS2 1
+#define _FNM_IGNORECASE 128
+
+int
+os2_fnmatch (pattern, name, flags)
+ const char *pattern;
+ const char *name;
+ int flags;
+{
+ return fnmatch (pattern, name, _FNM_IGNORECASE | _FNM_OS2 | flags);
+}
diff --git a/lib/.cvsignore b/lib/.cvsignore
new file mode 100644
index 0000000..5e41225
--- /dev/null
+++ b/lib/.cvsignore
@@ -0,0 +1,17 @@
+*.bb
+*.bbg
+*.da
+*.plg
+.deps
+.pure
+Makefile
+WinDebug
+WinRel
+alloca.h
+fnmatch.h
+glob.h
+getopt.h
+stdbool.h
+stdint.h
+getdate
+getdate.log
diff --git a/lib/ChangeLog b/lib/ChangeLog
new file mode 100644
index 0000000..077df81
--- /dev/null
+++ b/lib/ChangeLog
@@ -0,0 +1,2726 @@
+2005-09-29 Derek Price <derek@ximbiot.com>
+
+ * system.h: #define fd_select select when not already defined.
+
+2005-09-25 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add files (mkstemp.c tempname.c) to project.
+
+ * libcvs.dep, libcvs.mak: Regenerated for "libcvs.dsp" changes.
+
+2005-09-21 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dep: Regenerated for "../windows-NT/fix-msvc-mak.pl" change
+ to remove "basetsd" references.
+
+2005-09-20 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add files (canon-host.c gai_strerror.c getaddrinfo.c
+ getdelim.c mbchar.c strnlen1.c canon-host.h getaddrinfo.h getdelim.h
+ glob-libc.h mbchar.h mbuiter.h regex_internal.h strcase.h strnlen1.h
+ ..\windows-NT\netdb.h ..\windows-NT\sys\socket.h) to project.
+
+ * libcvs.dep libcvs.mak: Regenerated for "libcvs.dsp" changes.
+
+2005-09-20 Derek Price <derek@ximbiot.com>
+
+ * getaddrinfo.c: Update from GNULIB.
+
+2005-09-20 Derek Price <derek@ximbiot.com>
+ Paul Eggert <eggert@cs.ucla.edu>
+
+ * regcomp.c, regex_internal.c, regex_internal.h, regexec.c: New,
+ simpler replacement fix for the previous.
+
+2005-09-19 Derek Price <derek@ximbiot.com>
+
+ * regcomp.c, regex_internal.c, regex_internal.h, regexec.c: Fix some
+ __attribute definition problems (submitted to GNULIB).
+
+ * __fpending.c, __fpending.h, atexit.c, basename.c, chdir-long.c,
+ closeout.c, cycle-check.c, dirname.c, dup-safer.c, dup2.c, exitfail.c,
+ fd-safer.c, filenamecat.c, fnmatch.c, ftruncate.c, getaddrinfo.c,
+ getcwd.c, getdate.h, getdelim.c, getline.c, getlogin_r.c, getndelim2.c,
+ getnline.c, getopt1.c, getpass.c, gettimeofday.c, lstat.c, malloc.c,
+ memmove.c, mkdir.c, mkstemp.c, nanosleep.c, openat.c, pipe-safer.c,
+ quotearg.c, readlink.c, realloc.c, regex.c, rename.c, rpmatch.c,
+ save-cwd.c, strerror.c, stripslash.c, strncasecmp.c, strnlen1.c,
+ strstr.c, strtol.c, tempname.c, time_r.c, timespec.h, xalloc-die.c,
+ xgetcwd.c, xmalloc.c, xreadlink.c, yesno.c: Update from GNULIB.
+
+ * canon-host.h, md5.c, md5.h, mktime.c, timespec.h: Update from GNULIB.
+
+2005-09-15 Derek Price <derek@ximbiot.com>
+
+ * regcomp.c, regex_internal.c, regex_internal.h, regexec.c: Update from
+ GNULIB, again.
+
+ * regcomp.c, regex_internal.c, regex_internal.h, regexec.c: Update from
+ GNULIB.
+
+ * strstr.h: Update from GNULIB.
+
+2005-09-13 Derek Price <derek@ximbiot.com>
+
+ * canon-host.c: Update from GNULIB.
+
+2005-09-12 Derek Price <derek@ximbiot.com>
+
+ * gai_strerror.c: Include config.h when available. Include
+ getaddrinfo.h before other headers to test interface.
+
+2005-09-10 Larry Jones <lawrence.jones@ugs.com>
+
+ * canon-host.c (canon_host_r): Designated initializers are C99 only.
+ * getaddrinfo.c (getaddrinfo): Can't do arithmetic on void *. Fix
+ incorrect hints member name. Fix const mismatch.
+
+2005-09-09 Derek Price <derek@ximbiot.com>
+
+ Install glibc porting changes.
+ * glob.c, glob_.h: Update with alpha-GNULIB.
+ * glob-libc.h: New file from same.
+
+2005-09-08 Derek Price <derek@ximbiot.com>
+
+ * getaddrinfo.h: Don't assume HAVE_GETADDRINFO will be defined when the
+ system does not haev getaddrinfo.
+
+2005-09-06 Derek Price <derek@ximbiot.com>
+
+ * regex_internal.h: Update from GNULIB.
+
+ * getpass.c, regcomp.c, regex_internal.c, regex_internal.h, regexec.c:
+ Update from GNULIB.
+
+ Update from GNULIB with alpha-quality patch.
+ * Makefile.am: Add getaddrinfo cruft.
+ * canon-host.c: Updated to use getaddrinfo module.
+ * canon-host.h, gai_strerror.c, getaddrinfo.c, getaddrinfo.h: New
+ files.
+
+2005-09-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (mbchar): Remove obsolete module cruft.
+
+2005-09-04 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB.
+ * glob.c, glob_.h: Updated.
+ * Makefile.am: Move glob targets into alpha order. Add size_max
+ module.
+
+ Add canon-host module from GNULIB.
+ * canon-host.c: New file.
+
+ Update from GNULIB.
+ * Makefile.am: Import modifications from...
+ * Makefile.gnulib: ...here.
+ * dup-safer.c, fd-safer.c, getpass.c, regcomp.c, regex.c, regex.h,
+ regex_internal.c, regex_internal.h, regexec.c, strcase.h,
+ strcasecmp.c, strftime.c, strncasecmp.c, strstr.c, strstr.h,
+ unistd-safer.h: Updated.
+ * mbchar.c, mbchar.h, mbuiter.h, memchr.c, pipe-safer.c, strnlen1.c,
+ strnlen1.h, unistd--.h: New files.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * getdelim.c (getdelim): Return EOF on EOF, revisited.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * getdelim.c (getdelim): Return EOF on EOF.
+
+2005-08-12 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB.
+ * Makefile.am: Update using Makefile.gnulib changes.
+ * Makefile.gnulib, dup-safer.c, dup2.c, fnmatch.c, getcwd.c, getcwd.h,
+ getline.c, getline.h, getlogin_r.h, mktime.c, openat.h,
+ pagealign_alloc.c, quotearg.c, regex.c, regex.h, save-cwd.c,
+ strftime.c, tempname.c, time_r.h, xmalloc.c: Updated.
+ * getdelim.c, getdelim.h, regcomp.c, regex_internal.c,
+ regex_internal.h, regexec.c, size_max.h: New files.
+
+2005-06-12 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add files "filenamecat.h" and "lstat.c" to project.
+ * libcvs.dep, libcvs.mak: Regenerate for "libcvs.dsp" changes.
+
+2005-06-10 Derek Price <derek@ximbiot.com>
+
+ Sync with GNULIB.
+ * basename.c, canonicalize.c, canonicalize.h, dirname.c, dirname.h,
+ fnmatch_.h, fnmatch_loop.c, getcwd.c, getlogin_r.c, mkstemp.c,
+ openat.c, openat.h, pathmax.h, rename.c, stripslash.c, tempname.c,
+ xreadlink.c: Update from GNULIB.
+ * path-concat.c, path-concat.h: Rename to...
+ * filenamecat.c, filenamecat.h: ...this.
+
+ Test new stat module.
+ * lstat.h: New file.
+ * stat.c: Remove this file and...
+ * lstat.c: ...move most functionality here.
+
+2005-05-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add file "windows-NT/woe32.h" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" change.
+
+2005-05-28 Derek Price <derek@ximbiot.com>
+
+ * glob_.h: s/MISSING_SYS_CDEFS_H/_SYS_CDEFS_H/. Add comment.
+
+2005-05-27 Derek Price <derek@ximbiot.com>
+
+ * getlogin_r.h: Import new version from GNULIB.
+
+2005-05-26 Derek Price <derek@ximbiot.com>
+
+ * glob_.h: Protect __THROW separately from __BEGIN_DECLS.
+
+2005-05-26 Derek Price <derek@ximbiot.com>
+
+ * system.h: Move non-system substitute GNULIB headers into cvs.h.
+ Remove stat macros in favor of GNULIB stat-macros module. Assume
+ <sys/stat.h> and <stdlib.h> per HACKING.
+
+2004-05-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add files "getlogin_r.c" and "getlogin_r.h" to project.
+ * libcvs.dep, libcvs.mak: Regenerated for "libcvs.dsp" change.
+
+2004-05-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * glob_.h: Windows build fakes "ndir.h" which defines "struct direct"
+ which differs from "dirent.h" which defines "struct dirent".
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * glob.c (LOGIN_NAME_MAX): Wrap sysconf for Windows.
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * glob_.h: Simplify <sys/cdefs.h> include and GLIBC macro use. Replace
+ use of defined _LIBC with !defined GLOB_PREFIX. Restore some GLIBC
+ stuff we don't care about anyhow. Separate some #defines into their
+ own section for clarity.
+ (__glob_pattern_p): Move this definition...
+ * glob.c (__glob_pattern_p): ...here.
+ (HAVE_D_TYPE): Remove this macro for simplicity's sake.
+ (HAVE__POSIX_GETPWNAM_R): Ditto.
+ * getlogin_r.c, getlogin_r.h: Update from GNULIB.
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * glob.c: Remove HAVE_GETLOGIN_R complexity in favor of the GNULIB
+ getlogin_r module. Redefine "struct_stat64" rather than "stat64" to
+ avoid macro collisions on Solaris.
+ * getlogin_r.c, getlogin_r.h: New files from GNULIB.
+
+2004-05-24 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add files "canonicalize.c", "cycle-check.c",
+ "canonicalize.h", "cycle-check.h", "dev-ino.h", "glob.h", "mempcpy.h",
+ "path-concat.h", "stat-macros.h" and "strdup.h" to project.
+ * libcvs.dep, libcvs.mak: Regenerated for "libcvs.dsp" change.
+
+2005-05-24 Conrad T. Pino <Conrad@Pino.com>
+
+ * glob_.h: Remove "struct stat;" forward declaration and update comment.
+
+2005-05-24 Conrad T. Pino <Conrad@Pino.com>
+
+ * glob_.h: "#include <sys/stat.h>" for Solaris "#define stat stat64"
+ case.
+
+2005-05-24 Derek Price <derek@ximbiot.com>
+
+ * stat.c: Use system stat & lstat functions in this file.
+ * system.h (CVS_STAT, CVS_LSTAT): Remove these macros.
+
+2005-05-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (BUILT_SOURCES, EXTRA_DIST, MAINTAINERCLEANFILES): Add
+ getdate.c due to automake bug.
+
+2005-05-24 Derek Price <derek@ximbiot.com>
+
+ * glob_.h, glob.c: Don't attempt to handle 64 bit file information
+ explicitly when not compiling as part of glibc.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * canonicalize.c, canonicalize.h, cycle-check.c, cycle-check.h,
+ dev-ino.h, path-concat.c, path-concat.h: New files from GNULIB.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Remove unnecessary comment.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * __fpending.c, alloca_.h, allocsa.c, allocsa.h, asnprintf.c,
+ asprintf.c, basename.c, chdir-long.c, chdir-long.h, closeout.c,
+ closeout.h, dirname.c, dirname.h, dup-safer.c, dup2.c, error.c,
+ error.h, exit.h, exitfail.c, exitfail.h, fd-safer.c, fnmatch.c,
+ fnmatch_.h, fnmatch_loop.c, getcwd.c, getcwd.h, getdate.c, getdate.h,
+ getdate.y, gethostname.c, getline.c, getline.h, getndelim2.c,
+ getndelim2.h, getnline.c, getnline.h, getopt.c, getopt1.c, getopt_.h,
+ getopt_int.h, getpagesize.h, getpass.c, getpass.h, gettext.h,
+ gettime.c, gettimeofday.c, lstat.c, malloc.c, md5.c, md5.h, mempcpy.c,
+ mempcpy.h, memrchr.c, memrchr.h, minmax.h, mkdir.c, mkstemp.c,
+ mktime.c, nanosleep.c, openat.c, openat.h, pagealign_alloc.c,
+ pagealign_alloc.h, pathmax.h, printf-args.c, printf-args.h,
+ printf-parse.c, printf-parse.h, quotearg.c, quotearg.h, readlink.c,
+ realloc.c, regex.c, regex.h, rename.c, rpmatch.c, save-cwd.c,
+ save-cwd.h, setenv.c, setenv.h, stat-macros.h, stat.c, stdbool_.h,
+ stdint_.h, strcase.h, strcasecmp.c, strdup.c, strdup.h, strerror.c,
+ strftime.c, strftime.h, stripslash.c, strstr.c, strstr.h, strtol.c,
+ strtoul.c, tempname.c, time_r.c, time_r.h, timespec.h, unistd-safer.h,
+ unlocked-io.h, unsetenv.c, vasnprintf.c, vasnprintf.h, vasprintf.c,
+ vasprintf.h, xalloc-die.c, xalloc.h, xgetcwd.c, xgetcwd.h,
+ xgethostname.c, xmalloc.c, xreadlink.c, xreadlink.h, xsize.h, yesno.c,
+ yesno.h: Update from GNULIB.
+
+2005-05-20 Derek Price <derek@ximbiot.com>
+
+ * glob.c (__stat64): Add args to macro definition for clarity.
+
+2005-05-19 Derek Price <derek@ximbiot.com>
+
+ * glob.c: Use POSIX getpwnam_r on Solaris.
+
+2005-05-19 Derek Price <derek@ximbiot.com>
+
+ * glob.c: Don't delcare protos for getlogin or getlogin_r if we got one
+ from <unistd.h>.
+
+2005-05-18 Derek Price <derek@ximbiot.com>
+
+ * glob.c (GETPW_R_SIZE_MAX): Remove `;' from macro definition.
+
+2005-05-18 Derek Price <derek@ximbiot.com>
+
+ More misc cleanup for compatibility with GNULIB & glibc, mostly
+ suggested by Paul Eggert <eggert@cs.ucla.edu>.
+ * glob.c: Improve comments.
+ (GETPW_R_SIZE_MAX): Add parens to definition.
+ (glob): Use GNU coding conventions (formatting change).
+ * glob_.h: Include <sys/cdefs.h> when possible.
+
+2005-05-17 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "glob.c", "glob_.h" and "mempcpy.c" to project.
+ * libcvs.dep, libcvs.mak: Regenerated for "libcvs.dsp" change.
+
+2005-05-17 Derek Price <derek@ximbiot.com>
+
+ More misc cleanup for compatibility with GNULIB & glibc, mostly
+ suggested by Paul Eggert <eggert@cs.ucla.edu>.
+ * glob.c: Improve comments.
+ (GETPW_R_SIZE_MAX): New macro to avoid undefined sysconf macros.
+ (glob): Use new macro.
+ * glob_.h: Define __const, __restrict, and __USE_GNU when necessary.
+ Protect use of __BEGIN_DECLS & __END_DECLS. Remove include of
+ <sys/types.h>. Reorganize definitions for GNULIB. Remove #undefs
+ which work around what is now probably a non-existant problem.
+
+2005-05-15 Derek Price <derek@ximbiot.com>
+
+ * glob_.h, glob.c: More misc cleanup for compatibility with GNULIB &
+ glibc, mostly suggested by Paul Eggert <eggert@cs.ucla.edu>. Remove
+ casts to and from void * - they are not needed in C89.
+
+2005-05-13 Derek Price <derek@ximbiot.com>
+
+ * glob_.h: Enable GNU features by default. Remove copy/pasted getopt
+ #define.
+ * glob.c: s/__strdup/strdup/ (Fixes BSD compilation issue).
+
+2005-05-13 Derek Price <derek@ximbiot.com>
+
+ * glob.c, glob_.h: Misc cleanup for compatibility with GNULIB & glibc,
+ mostly suggested by Paul Eggert <eggert@cs.ucla.edu>.
+
+2005-05-12 Derek Price <derek@ximbiot.com>
+
+ * glob.c, glob_.h: Misc improvements suggested by Paul Eggert, bringing
+ these files closer to their glibc sources. Simplify & reorganize for
+ clarity. Use protos.
+ (glob_in_dir): Fix GLOB_ONLYDIR bug/typo.
+
+2005-05-11 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore glob.h.
+ * Makefile.am (BUILT_SOURCES, EXTRA_DIST, MOSTLYCLEANFILES): Add glob
+ files.
+ (glob.h): New target.
+ * glob.c, glob_.h: New files.
+ * strdup.c, strdup.h: New files from GNULIB.
+
+2005-05-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dep, libcvs.mak: Regenerated after Windows full rebuild.
+
+2005-05-08 Mark D. Baushke <mdb@cvshome.org>
+
+ * libcvs.dsp: unistd-safer.h is in lib, not windows-NT.
+ * libcvs.dep: Regenerate.
+
+2005-05-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * libcvs.dep: Use a relative path for unistd-safer.h.
+
+ * libcvs.dsp: Update from GNULIB.
+ Add files dup-safer.c, fd-safer.c, and unistd-safer.h.
+ * libcvs.dep, libcvs.mak: Regenerate.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB.
+ * chdir-long.c, nanosleep.c, save-cwd.c, tempname.c: Updated.
+ * dup-safer.c, fd-safer.c, unistd-safer.h: New files.
+
+2005-05-01 Mark D. Baushke <mdb@cvshome.org>
+
+ * regex.c: Update from GNULIB.
+
+2005-04-25 Derek Price <derek@ximbiot.com>
+
+ * getdate.y: Update from GNULIB.
+
+2005-04-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (DISTCLEANFILES): Add getdate.log.
+ * .cvsignore: Ditto.
+ * test-getdate.sh: Add new tests.
+ (verify, skip, valid_timezone): New functions.
+
+2005-04-12 Derek Price <derek@ximbiot.com>
+
+ * getdate.y: Update from GNULIB.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * getdate.y: Update from GNULIB.
+
+2005-04-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * strtol.c: Update from GNULIB.
+
+2005-03-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * mktime.c, strftime.c: Update from GNULIB.
+
+2005-03-23 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (getdate_SOURCES): Remove sources that are now included
+ via $(noinst_LIBRARIES).
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * mktime.c, regex.c, stdint_.h, strftime.c, strtol.c: Update from
+ GNULIB.
+
+2005-03-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * mktime.c, save-cwd.c, strftime.c, strtol.c: Update from GNULIB.
+
+2005-03-08 Conrad T. Pino <Conrad@Pino.com>
+
+ * .cvsignore: Add stdint.h entry.
+
+2005-03-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Synchronize with GNULIB updates.
+ Remove valloc.c file. Add files __fpending.c, __fpending.h,
+ chdir-long.h, closeout.c, closeout.h, getcwd.h,
+ pagealign_alloc.c, pagealign_alloc.h, quotearg.c, quotearg.h.
+ * libcvs.dep, libcvs.mak: Regenerate for libcvs.dsp change.
+
+2005-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * pagealign_alloc.c: Update from GNULIB.
+
+2005-03-04 Jim Hyslop <jhyslop@ieee.org>
+
+ * xtime.h: added include guards to fix compile errors on IRIX 5.3
+ (Patch from Georg Schwarz <georg.scwarz@freenet.de>.)
+
+2005-03-03 Derek Price <derek@ximbiot.com>
+
+ * pagealign_alloc.c, pagealign_alloc.h: New files from GNULIB.
+ * valloc.c: Remove this obsolete file.
+
+2005-03-02 Jim Meyering <jim@meyering.net>
+
+ * Makefile.am (libcvs_a_SOURCES): Add the following to support
+ the GNULIB closeout module: closeout.c, closeout.h, quotearg.c,
+ quotearg.h, __fpending.h.
+ * closeout.c, closeout.h: New files.
+ * quotearg.c, quotearg.h: New files.
+ * __fpending.c, __fpending.h: New files.
+ * Makefile.gnulib: Regenerate.
+
+2005-03-02 Derek Price <derek@ximbiot.com>
+
+ * gettext.h, setenv.c, vasnprintf.c, vasprintf.c: Update from GNULIB.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ Update installed GNULIB modules.
+ * Makefile.am: Tweak for new GNULIB updates.
+ * alloca_.h, dup2.c, error.c, ftruncate.c, getdate.c, getdate.y,
+ getopt_.h, gettext.h, gettime.c, malloc.c, mkdir.c, mktime.c,
+ realloc.c, rename.c, save-cwd.c, strstr.c, strtoul.c, timespec.h,
+ xgetcwd.c: Update these files.
+ * chdir-long.c, chdir-long.h, getcwd.c, getcwd.h, mempcpy.c, mempcpy.h,
+ memrchr.c, memrchr.h, openat.c, openat.h, strstr.h, strtol.c: New files
+ from GNULIB.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * xtime.h: Remove obsolete timeb stuff.
+
+2005-02-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * xgethostname.c (xgethostname): Check for ENOMEM, which is
+ returned by OSX/Darwin if the specified buffer is not large
+ enough for the hostname.
+ (Problem reported by Neil Conway <neilc@samurai.com>.)
+
+2005-02-08 Derek Price <derek@ximbiot.com>
+
+ * fncase.c (OSX_filename_classes): Mac OSX doesn't need \ mapped to /.
+ * system.h (FOLD_FN_CASE): Clarify comment.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notices.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add Makefile.gnulib.
+
+2004-11-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dep: Regenerated for "../cvsnt.dsp" change.
+ * libcvs.mak: Regenerated for "../cvsnt.dsp" change.
+
+2004-11-21 Mark D. Baushke <mdb@cvshome.org>
+
+ * libcvs.dep, libcvs.dsp, libcvs.mak: Add "xgethostname.c" to
+ project.
+
+2004-11-19 Derek Price <derek@ximbiot.com>
+
+ * xgethostname.h, xgethostname.c: New files from GNULIB.
+ * Makefile.am (libcvs_a_SOURCES): Add new files.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * getdate.y, getopt.c, getopt1.c, getopt_.h, getopt_int.h, xgetcwd.c:
+ Update from GNULIB.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_LIBADD): Add @ALLOCA@.
+
+2004-11-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add test-getdate.sh.
+
+2004-11-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * alloca_.h, allocsa.h, mktime.c: Update from GNULIB.
+
+2004-11-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * strftime.c, getdate.y: Update from GNULIB.
+ * getdate.c: Regenerated.
+
+2004-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * test-getdate.sh: Remove non-portable 'Feb 29, 2096 8 years'
+ test case. Add comments about portable dates.
+
+2004-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * test-getdate.sh (TZ): Set to UTC0 instead of UTC to fix MacOS X
+ problem.
+
+2004-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * mktime.c (SHR): New macro, which is a portable substitute for >>
+ that should work even on Crays.
+ Problem reported by Mark D. Baushke.
+ (TIME_T_MIDPOINT, ydhms_diff, __mktime_internal): Use it.
+ (Patch from Paul Eggert of GNULIB.)
+
+ * Makefile.am (getdate_LDADD): Add @ALLOCA@.
+ * Makefile.in: Regenerated.
+
+2004-11-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * strftime.c: Update from GNULIB.
+
+2004-11-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "readlink.c" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" change.
+ * libcvs.mak: Regenerate for "libcvs.dsp" change.
+
+2004-11-05 Mark D. Baushke <mdb@cvshome.org>
+
+ * readlink.c: Update from GNULIB.
+
+2004-11-04 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "xreadlink.c" and "xreadlink.h" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" change.
+ * libcvs.mak: Regenerate for "libcvs.dsp" change.
+
+2004-11-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * allocsa.h, allocsa.valgrind: Update from GNULIB.
+ * Makefile.in: Regenerated.
+
+2004-11-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * sunos57-select.c: Move '#undef select' before system #include
+ statements to avoid conflicting declarations on BSDI BSD/OS 4.2.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am: Update from GNULIB.
+ * readlink.c, xreadlink.c, xreadlink.h: Add from GNULIB.
+ * Makefile.gnulib, Makefile.in: Regenerated.
+
+2004-11-03 Derek Price <derek@ximbiot.com>
+
+ * getdate.y: Update from GNULIB.
+
+2004-11-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * getpass.c, setenv.h: Update from GNULIB.
+
+2004-11-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * test-getdate.sh (getdate): Do not assume 'diff -u' is
+ universally available.
+ * Makefile.am (getdate_SOURCES): Add allocsa.c sources needed by
+ getdate on Solaris.
+ * Makefile.in: Regenerated.
+
+2004-11-01 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "setenv.c", "unsetenv.c", "allocsa.h" and "setenv.h" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" change.
+ * libcvs.mak: Regenerate for "libcvs.dsp" change.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * test-getdate.sh: Test a date relative to a specified date and one of
+ the failing dates from the rcs2-7 test in src/sanity.sh.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (TESTS): Add test-getdate.sh.
+ (check_PROGRAMS): Add getdate.
+ (getdate_*): Add info to build getdate.
+ (MOSTLYCLEANFILES): Add files that might be generated by
+ test-getdate.sh.
+ * allocsa.c, allocsa.h, setenv.c setenv.h, unsetenv.c: New files from
+ GNULIB.
+ * test-getdate.sh: Add some new dates and expect correct output.
+
+2004-10-27 Mark D. Baushke <mdb@cvshome.org>
+
+ * mktime.c (not_equal_tm): New patch from GNULIB.
+
+2004-10-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "rpmatch.c" and "yesno.h" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" change.
+ * libcvs.mak: Regenerate for "libcvs.dsp" change.
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move error.h to its own section.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add yesno.h.
+ * rpmatch.c, yesno.h: New files from GNULIB.
+ * yesno.c: Update from GNULIB.
+
+2004-10-23 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "../windows-NT/stdint.h" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" change.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am (libcvs_a_OBJECTS): Fix typo for $(ALLOCA_H) and
+ ($STDBOOL_H). Also update rules for stdint GNULIB module.
+ * Makefile.in: Regenerated.
+
+2004-10-22 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Remove "argmatch.c" from project.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am (libcvs_a_SOURCES): Add stdint GNULIB module.
+ Fix typos in alloca and stdbool sections.
+ * stdint_.h: New file from GNULIB.
+ * getpagesize.h: Update from GNULIB.
+ * mktime.c: Update from GNULIB.
+
+2004-10-22 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move md5 to its own section.
+ * md5.c, md5.h: Update from GNULIB.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am, rpmatch.c, yesno.h, yesno.c: Back out recent changes.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * error.c, error.h: Update from GNULIB.
+
+2004-10-21 Mark Baushke <mdb@cvshome.org>
+
+ * libcvs.dep, libcvs.mak: Remove argmatch references.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move yesno to its own section.
+ * rpmatch.c, yesno.h: New files from GNULIB.
+ * yesno.c: Update from GNULIB.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move getpagesize to its own section.
+ * getpagesize.h: Update from GNULIB.
+
+2004-10-21 Mark Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Remove argmatch.c.
+ * argmatch.c: Remove this unused file.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move strftime to its own section.
+ * strftime.h: New file.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * malloc.c: Update from GNULIB.
+
+2004-10-21 Mark Baushke <mdb@cvshome.org>
+
+ * Makefile.am (all-local): Fix typo.
+ * Makefile.in: Regenerated.
+
+2004-10-21 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.mak: Regenerated for "../zlib/lib.dsp" change.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * sunos57-select.c: New file. Work around Solaris 7 select()
+ hang.
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-10-18 Derek Price <derek@ximbiot.com>
+
+ * system.h: Define DEVNULL here when necessary. Don't include
+ unistd.h twice.
+
+2004-10-16 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "vasprintf.c" and "vasprintf.h" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" change.
+ * libcvs.mak: Regenerate for "libcvs.dsp" change.
+
+2004-10-15 Derek Price <derek@ximbiot.com>
+
+ * asprintf.c, vasprintf.c, vasprintf.h: New files from GNULIB.
+
+2004-10-15 Derek Price <derek@ximbiot.com>
+
+ * getpass.c: Update from GNULIB.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add stat-macros.h.
+ * stat.c: Update from GNULIB.
+ * stat-macros.c: New file from GNULIB.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * nanosleep.c: Update from GNULIB.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * memmove.c: Update from GNULIB.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move minmax.h to its own section.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * system.h: Reorganize slightly.
+
+2004-10-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Remove "xstrdup.c" from project.
+ Add "strcasecmp.c", "getopt_.h" and "getopt_int.h" to project.
+ * libcvs.dep: Regenerate for "libcvs.dsp" changes.
+ * libcvs.mak: Regenerate for "libcvs.dsp" changes.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * system.h: Include getopt.h.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add getpass.h.
+ * getpass.h: New file from GNULIB.
+ * getpass.c: Update from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add strcase.h.
+ * strcase.h, strcasecmp.c, strncasecmp.c: New files from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * gethostname.c: Update from gnulib.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move getline, getnline, & getndelim2
+ sources to their own sections.
+ * getline.c, getndelim2.c, getndelim2.h, getnline.c, getnline.h: Update
+ from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Add getopt.h.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Add new configuration for getopt.
+ * getopt.h: Remove file.
+ * getopt_.h, getopt_int.h: New files from GNULIB.
+ * getopt.c, getopt1.c: Update from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * mkstemp.c, tempname.c: Update from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Remove xstrdup.c.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * xstrdup.c: Remove this obsolete file.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (fnmatch, fnmatch-posix): Improve comment.
+ * fnmatch.c, fnmatch_loop.c: Update from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move exit.h to its own section.
+
+2004-10-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Remove "savecwd.c", "savecwd.h", "xgetwd.c" from project.
+ Add "save-cwd.c", "save-cwd.h", "xgetcwd.c", "xgetcwd.h" to project.
+ * libcvs.dep: Regenerated for "libcvs.dsp" change.
+ * libcvs.mak: Regenerated for "libcvs.dsp" change.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * basename.c, dirname.c, dirname.h, stripslash.c: Updated from GNULIB.
+ * system.h: s/FILESYSTEM_PREFIX_LEN/FILE_SYSTEM_PREFIX_LEN/.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.gnulib: New file.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add xalloc-die.c.
+ * xalloc-die.c: New file from GNULIB.
+ * xalloc.h, xmalloc.c: Update from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move gettext.h to its own section.
+ * gettext.h, vasnprintf.c, vasnprintf.h: Update from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * savecwd.c: Rename to...
+ * save-cwd.c: ...this and replace with the newest version from GNULIB.
+ * savecwd.h: Ditto, but to...
+ * save-cwd.h: ...this name.
+ * Makefile.am (libcvs_a_SOURCES): Remove savecwd.[ch]. Add save-cwd.h
+ & save-cwd.c in their own section.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Remove xgetwd.c, add xgetcwd.h &
+ xgetcwd.c in their own section.
+ * xgetwd.c: Removed.
+ * xgetcwd.h, xgetcwd.c: New files imported from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * alloca_.h, alloca.c: Import latest versions from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move pathmax.h to its own section.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move unlocked-io.h to its own
+ section.
+ * unlocked-io.h: Import most recent version from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Move regex.h to its own section.
+ * regex.c: Import most recent version from GNULIB.
+
+2004-10-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.dsp: Add "dirname.c" to project to resolve link error.
+ * libcvs.dep: Regenerated for "libcvs.dsp" change.
+ * libcvs.mak: Regenerated for "libcvs.dsp" change.
+
+2004-10-05 Mark D. Baushke <mdb@cvshome.org>
+
+ * regex.c (re_comp): Cast gettext return value to char * to
+ avoid warning in !ENABLE_NLS case. Patch imported from GNULIB.
+ (Problem report from Martin Neitzel <neitzel@sco.gaertner.de>.)
+
+2004-09-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * libcvs.mak: Regenerated for "../cvsnt.dsp" changes made 2004-09-08.
+
+2004-08-27 Derek Price <derek@ximbiot.com>
+
+ Import minmax module from GNULIB.
+
+ * Makefile.am (libcvs_A_SOURCES): Add minmax.h.
+ * minmax.h: New file.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore GCC profiling data.
+
+2004-06-24 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp: Add "./xsize.h" to Header file list. Add "./strftime.c"
+ & "./time_r.c" to Source file list.
+ * libcvs.dep, libcvs.mak: Regenerated for "./libcvs.dsp" change.
+ (Patch submitted by Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (xsize): Move GNULIB xsize module into its own section.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add strftime.c.
+ * strftime.c: New file.
+
+2004-05-17 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp: Add "lib/xtime.h" to project header files.
+ * libcvs.dep: Regnerated for "libcvs.dsp" file change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ Back out GNULIB getdate update until date parsing problem is fixed.
+ * Makefile.am: Temporarily comment out getdate.y test targets.
+ * getdate.y: Restored from version 1.19.
+ * xtime.h: Readded from version 1.1.
+ * Makefile.in, getdate.c: Regenerated.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp: Move all "../lib/*.c" files to this project. Header file
+ list updated for GNULIB updates.
+ * libcvs.dep: Regenerated for "libcvs.dsp" changes.
+ * libcvs.mak: Regenerated for "libcvs.dsp" changes.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-05-14 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp: Add basename.c & gettime.c for Windows build.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-05-14 Derek Price <derek@ximbiot.com>
+
+ * gettime.c, nanosleep.c: Updated from GNULIB.
+
+2004-05-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in (check-TESTS): Correct the script to deal with some
+ make (BSD) that use 'sh -e' which will terminate whenever a
+ command (such as test -n "") fails.
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (getdate_LDADD): Add $(LIBINTL), needed on some systems.
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (BUILT_SOURCES, MAINTAINERCLEANFILES): Remove getdate.c,
+ Automake determines this automatically.
+ * Makefile.in: Regenerated.
+
+2004-05-02 Derek Price <derek@ximbiot.com>
+
+ * progname.c (progname): Assume = "getdate" for now.
+
+2004-05-02 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (getdate_SOURCES): Add xmalloc, xstrdup, error, exitfail,
+ and progname for getdate test program on some systems.
+ * error.c, progname.c: New file.
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-04-29 Derek Price <derek@ximbiot.com>
+
+ * getdate.y: Restore unforked version from GNULIB.
+ * unlocked-io.h: Update to most recent version from GNULIB.
+ * getdate.y: Regenerated.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Add getdate executable.
+ * Makefile.am: Remove out-of-date comment about regex. Use Automake
+ comments where the comments won't look good in the Makefile.
+ (AM_CPPFLAGS): Remove obsolescent include.
+ (TESTS, MOSTLYCLEANFILES, check_PROGRAMS, getdate_*): Add support for
+ testing getdate.
+ * test-getdate.sh: New file.
+ * getdate.y: Move include to compile in test mode.
+ * Makefile.in, getdate.c: Regenerated.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * system.h: Include timespec.h instead of xtime.h.
+ * xtime.h: Removed.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add getdate.h, getdate.y in their own
+ section.
+ (BUILT_SOURCES, MAINTAINERCLEANFILES): Add getdate.c.
+ * getdate.h, getdate.y: Import updated versions from GNULIB.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * mktime.c: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add time_r.h.
+ * time_r.h: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * nanosleep.c: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add gettime.c.
+ * gettime.c: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * gettimeofday.c: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add timespec.h.
+ * timespec.h: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * system.h: Move definition of FILENAMES_CASE_INSENSITIVE to
+ windows-NT/config.h.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ Add dirname module from GNULIB.
+
+ * Makefile.am (libcvs_SOURCES): Add new files.
+ * basename.c, dirname.c, dirname.h: New files.
+ * stripslash.c: Update from GNULIB.
+ * system.h (ISDIRSEP): Remove.
+ (ISABSOLUTE): s/ISDIRSEP/ISSLASH/. Use FILESYSTEM_PREFIX_LEN to search
+ for DOS drive spec rather than reimplementing.
+ * Makefile.in: Regenerated.
+
+2004-04-26 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp: Add stdbool.h from windows-NT as source dependency.
+ * libcvs.mak: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp, libcvs.dep, libcvs.mak: Back out recent stdbool.h change.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Add stdbool.h.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp: Create stdbool.h.
+ * libcvs.dep, libcvs.mak: Regenerated.
+
+2004-04-22 Derek Price <derek@ximbiot.com>
+
+ * system.h: #include <fnmatch.h>.
+
+2004-04-22 Derek Price <derek@ximbiot.com>
+
+ * system.h: #include <stdbool.h>.
+
+2004-04-21 Derek Price <derek@ximbiot.com>
+
+ Add stdbool module from GNULIB.
+
+ * stdbool_.h: New file.
+ * Makefile.am (stdbool.h, BUILT_SOURCES, EXTRA_DIST, MOSTLYCLEANFILES):
+ Add stdbool cruft.
+ * Makefile.in: Regenerated.
+
+2004-04-20 Derek Price <derek@ximbiot.com>
+
+ * system.h: Correct comments.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * system.h: Gratuitous reformatting.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): s/lib\.\w+/libcvs.*/i.
+ * Makefile.in: Regenerated.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * libcvs.mak: Regenerated for "zlib/libz.dsp" change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-17 Derek Price <derek@ximbiot.com>
+
+ * libcvs.dsp, libcvs.dep, libcvs.mak: Move...
+ * lib.dsp, lib.dep, lib.mak: ...here.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-17 Derek Price <derek@ximbiot.com>
+
+ * LIB.dsp: Rename to...
+ * lib.dsp: ...this.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * lib.dsp: Set PROP BASE directories to projet standard
+ has "Reset" function use project defaults.
+ Change "..\lib\" paths to ".\" for consistency.
+ * lib.mak: Regenerated for lib.dsp change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * lib.dsp: Dropped "alloca.c" from project.
+ * lib.dep: Regenerated for "lib.dsp" change.
+ * lib.mak: Regenerated for "lib.dsp" change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add LIB.dep.
+ * Makefile.in: Regenerated.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * lib.dsp: Update to compile fnmatch.
+ * LIB.dep: New generated file.
+ * lib.mak: Regenerated.
+ (Patch from Conrad T. Pino <conrad@pino.com>.)
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ Update to current fnmatch module from GNULIB.
+
+ * Makefile.am (BUILT_SOURCES, EXTRA_DIST): Add fnmatch sources.
+ (MOSTLYCLEANFILES): Initialize & add fnmatch & alloca headers.
+ (libcvs_a_OBJECTS): Make dependent on $(FNMATCH_H).
+ (fnmatch.h): New target.
+ * fnmatch.h.in: Rename to...
+ * fnmatch_.h: ...this.
+ * fnmatch.c: New version from GNULIB.
+ * fnmatch_loop.c: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Remove lib.dep.
+ * Makefile.in: Regenerated.
+
+2004-04-07 Derek Price <derek@ximbiot.com>
+
+ * regex.c: Revise "FREE_VAR" macro to eliminate C4090/C4022 warnings
+ in Windows build with Visual C++ 6.0 compiler.
+ (Original patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-07 Derek Price <derek@ximbiot.com>
+
+ Update regex module from GNULIB.
+
+ * Makefile.am (libcvs_a_SOURCES): Remove regex.c.
+ * regex.c, regex.h: Import new versions from GNULIB.
+ * Makefile.in: Regenerated.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * system.h: Correct comment.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * system.h: Restore complete path folding for Cygwin under Windows.
+ Add ISABSOLUTE macro for determining whether a path is absolute to
+ handle X:\ style paths under Windows (& Cygwin).
+
+2004-03-29 Derek Price <derek@ximbiot.com>
+
+ * lib.mak: Regenerated with VC++ 5.0.
+ (Sent by Dennis Jones <djones@oregon.com>.)
+ * LIB.dep: Removed.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * lib.mak: Regenerated.
+
+2004-03-27 Derek Price <derek@ximbiot.com>
+
+ * LIB.dep, lib.mak: Regenerated.
+
+2004-03-26 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2004-03-26 Derek Price <derek@ximbiot.com>
+
+ * LIB.dep, lib.dsp, lib.mak: New files.
+ * Makefile.am (EXTRA_DIST): Add new files.
+ * .cvsignore: Ignore MSVC build cruft.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * system.h: No longer fold back slashes in paths into slashes.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * realloc.c: Update to more recent version from GNULIB to fix a WOE32
+ compilation problem.
+
+2004-03-20 Derek Price <derek@ximbiot.com>
+
+ * mkdir.c (mkdir): Declare string args const.
+
+2004-03-13 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add error.h.
+ * Makefile.in: Regenerated.
+
+2004-03-11 Derek Price <derek@ximbiot.com>
+
+ * xsize.h: Move the default definition of SIZE_MAX into
+ windows-NT/config.h.in.
+
+2004-03-07 Derek Price <derek@ximbiot.com>
+
+ * xsize.h: Provide a default definition of SIZE_MAX for Windows.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ Import xalloc module from GNULIB, as well as its remaining unimported
+ dependency, the exitfail module.
+
+ * Makefile.am (libcvs_a_SOURCES): Add new sources.
+ * exitfail.c, exitfail.h, xalloc.h, xmalloc.c, xstrdup.c: New files.
+ * Makefile.in: Regenerated.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import vasnprintf module from GNULIB.
+ * asnprintf.c, printf-args.c, printf-args.h, printf-parse.c,
+ printf-parse.h, vasnprintf.c, vasnprintf.h: New files.
+ * Makefile.am (libcvs_a_SOURCES): Add header files.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import xsize module from GNULIB for vasnprintf().
+ * xsize.h: New file.
+ * Makefile.am (libcvs_a_SOURCES): Add xsize.h.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import alloca module from GNULIB for vasnprintf().
+ * alloca_.h, alloca.c: New files.
+ * .cvsignore: Ignore alloca.h.
+ * Makefile.am: Compile alloca() when necessary.
+ * Makefile.in: Regenerated.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Make error() accessible to the GNULIB functions.
+
+ * error.h: Move in from ../src.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ * strerror.c: Update to latest version from gnulib.
+
+2003-12-14 Mark D. Baushke <mdb@cvshome.org>
+
+ * fseeko.c: Remove unnecessary #ifdef code.
+ * ftello.c: Ditto.
+ * system.h: Ditto.
+
+2003-12-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * ftello.c: Rework for AC_FUNC_FSEEKO.
+ * system.h: Rework fseeko and ftello prototypes.
+
+2003-12-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * xgetwd.c (pathmax.h): Add new include.
+ (Patch from Rob Clevenger <rob@robsite.org>.)
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * system.h: Correct spelling in comment.
+
+2003-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * fseeko.c (fseeko): New file and function to help with largefile
+ support.
+ * ftello.c (ftello): Ditto.
+ * system.h (ftello): Add prototype if !defined(HAVE_FTELLO).
+ * Makefile.in: Regenerated.
+
+2003-12-09 Larry Jones <lawrence.jones@eds.com>
+
+ * getdate.c: Regenerated.
+
+2003-12-08 Mark D. Baushke <mdb@cvshome.org>
+
+ * getdate.y: Remove #include <stdio.h> to avoid problems compiling
+ AIX with '#define _LARGE_FILES 1' with Redeclaration of fgetpos64
+ and ftello64. This may be an autoconf problem with
+ AC_SYS_LARGEFILE.
+ * getdate.c: Regenerated.
+
+2003-12-03 Derek Price <derek@ximbiot.com>
+
+ * fncase.c (OSX_filename_classes): New array.
+ (fncmp): Use FOLD_FN_CASE rather relying on the fact that it will be
+ #defined to use WNT_filename_classes.
+ * system.h: Define FOLD_FN_CASE, fncmp, and fnfold for all case
+ insensitive filesystems. Share some code between the new generic case
+ insensitive section and the old WOE32 section.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Remove obsolete PROTO.h.
+ * Makefile.in: Regenerated.
+
+2003-10-22 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_LIBADD): Undo the previous change and move it
+ into the program linking step in `../src'.
+ * Makefile.in: Regenerated.
+
+2003-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_LIBADD): Add $(LIBINTL) for gettext.
+ * Makefile.in: Regenerated.
+
+2003-10-04 Derek Price <derek@ximbiot.com>
+
+ * sighandle.c (SIG_handle): With the last commit, avoid allowing a
+ second interrupt while this interrupt handler runs.
+ (SIG_beginCrSect, SIG_endCrSect): With the last change, move these two
+ functions to the top of this file to avoid prototyping them for
+ SIG_handle().
+ (*): C89ify some prototypes.
+
+2003-10-04 Derek Price <derek@ximbiot.com>
+
+ * system.h (EXIT_FAILURE): Don't define here since it's defined in
+ exit.h.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * getpass.c: Update to new version from GNULIB with Larry's fix
+ incorporated.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * getopt.h, getopt.c, getopt1.c: Update from GNULIB.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * getline.c, getndelim2.c: Merge changes from GNULIB.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * system.h: Assume <string.h> and <sys/types.h> per the notes in
+ HACKING.
+
+2003-09-30 Larry Jones <lawrence.jones@eds.com>
+
+ * getpass.c: Fix bug that caused password to be echoed on many
+ systems (input may not be followed by output on the same stream
+ without an intervening call to a file positioning function).
+ (Reported by David Everly <david.everly@mci.com>.)
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ Provide an atexit() function on systems which provide on_exit() but not
+ atexit().
+
+ * atexit.c: New file.
+ * Makefile.in: Regenerated.
+
+2003-08-19 Derek Price <derek@ximbiot.com>
+
+ * system.h: Assume more headers, re C89 & GNULIB.
+
+2003-08-12 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Remove getndelim2 - it is now in
+ LIBOBJ.
+
+2003-07-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Remove getpass.c per new getpass-gnu
+ API from GNULIB.
+ * Makefile: Regenerated.
+
+2003-07-29 Derek Price <derek@ximbiot.com>
+
+ * getpass.c: New file, almost identical to GNULIB's currect version.
+ * Makefile.am (libcvs_a_SOURCES): Add getpass.c.
+ * Makefile.in: Regenerated.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * lstat.c: Sync with GNULIB.
+ * stat.c: Almost sync'd with GNULIB.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * getline.h: Sync this file with GNULIB.
+
+2003-07-24 Derek Price <derek@ximbiot.com>
+
+ * getline.c, getline.h, getndelim2.c, getndelim2.h, getnline.c,
+ getnline.h: Merge some more changes from GNULIB.
+
+2003-07-24 Derek Price <derek@ximbiot.com>
+
+ * gethostname.c: Update from GNULIB.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * system.h: Move some includes from src/cvs.h.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * system.h: Assume <stddef.h> per C89.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * strerror.c: Import current version from GNULIB.
+ * Makefile.in: Regenerated.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Make a comment more specific about LIBOBJ, while
+ removing a list of LIBOBJ'd file maintained elsewhere.
+ * memmove.c: Import current version from GNULIB.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * exit.h: Really add this file this time.
+ * Makefile.in: Regenerated.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * exit.h: New file from GNULIB.
+ * Makefile.am (lib_SOURCES): Add exit.h.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * stat.c: Sync us with GNULIB, except for the xalloc.h requirement.
+ xalloc.h is waiting on $GNULIB/modules/error for import.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Add getndelim.c & getnline.c as part of the new API.
+ * getline.c: Merge more of Bruno Habile's GNULIB changes to this file
+ so our fork is less divergent.
+ * getline.h: Ditto.
+ * getndelim2.c: Ditto.
+ * getndelim2.h: Ditto.
+ * getnline.c: Ditto.
+ * getnline.h: Ditto.
+
+ * Makefile.in: Regenerated.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * savecwd.c: Move the MD5 stuff that shifted here a few commits back...
+ * md5.c: ...back to here.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * getndelim2.c: Make limit an ssize_t rather than int, as per the
+ return type.
+ * getndelim2.h: Ditto.
+ * getnline.c: Ditto.
+ * getnline.h: Ditto.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * getline.c (getdelim): Return ssize_t, as per getline.h.
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * getline.c: Merge some of Bruno Habile's changes from GNULIB including
+ some he didn't quite finish, like renaming of n => linesize.
+ * getline.h: Ditto.
+ * getndelim2.c: Ditto.
+ * getndelim2.h: Ditto.
+ * getnline.c: Ditto.
+ * getnline.h: Ditto.
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * getndelim2.c: New file.
+ * getndelim2.h: Ditto.
+
+ * Makefile.am (libcvs_a_SOURCES): Add getndelim2.h.
+ * getline.h: Return ssize_t.
+ * getnline.h: Ditto.
+ * getline.c: Ditto and depend on getndelim2.
+ * getnline.c: Ditto.
+
+ * Makefile.in: Regenerated.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * getline.c: Don't include the unneeded unlocked-io.h.
+ * getnline.c: Remove extra blank line. Use GETNDELIM_NO_LIMIT rather
+ than GETNLINE_NO_LIMIT.
+ * getnline.h: Define GETNDELIM_NO_LIMIT rather than GETNLINE_NO_LIMIT.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * PROTO.h: Remove this file since some of our GNULIB sources no longer
+ support compilers that can't handle prototypes.
+
+ * md5.c: s/PROTO//.
+ * md5.h: Ditto.
+ * savecwd.c: Ditto.
+ * savecwd.h: Ditto.
+ * sighandle.c: Ditto.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * getline.h: Include config.h so to use the macros it defines.
+ (Thanks to Steve McIntyre <stevem@cvshome.org> for the report.)
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * pathmax.h: New file.
+
+ * Makefile.am (libcvs_a_SOURCES): Add pathmax.h.
+ * system.h: Remove PATH_MAX stuff.
+
+ * Makefile.in: Regenerated.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * getnline.c: New file based on GNULIB and resubmitted to GNULIB.
+ * getnline.h: Ditto.
+
+ * Makefile.am (libcvs_a_SOURCES): Add new getnline.h.
+ * getline.c: Import and hack version from GNULIB to prevent double
+ prototype problem on 64-bit machines. Resubmitted to GNULIB.
+ * getline.h: Ditto.
+ (Thanks to Steve McIntyre <stevem@cvshome.org> for the report.)
+
+ * Makefile.in: Regenerated.
+
+2003-07-15 Derek Price <derek@ximbiot.com>
+
+ * unlocked-io.h: s/LGPL/GPL/g, imported from GNULIB.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * mkstemp.c: New file.
+ * tempname.c: Ditto.
+
+ * Makefile.in: Regenerated.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add gettext.h.
+ * system.h: Include gettext.h.
+
+ * gettext.h: New file from GNULIB.
+
+ * Makefile.in: Regenerated.
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * system.h: Reference the WIN32 macro only in order to define WOE32,
+ in accordance with the GNU convention to avoid implying that we
+ consider the Microsoft Windows Operating Environment any sort of "win".
+
+2003-05-29 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: xgssapi.h is no more.
+ * xgssapi.h: Move its contents to src/gssapi-client.h
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-05-28 Derek Price <derek@ximbiot.com>
+
+ * getline.h, md5.c, sighandle.c, savecwd.h: Use PROTO.h.
+ * savecwd.c: Use standard PROTO macro.
+ * Makefile.am: Add PROTO.h
+ * PROTO.h: PROTO macro definition is finally here, as specified in
+ Autoconf documentation.
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-05-28 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: get rid of $(includeopt); -Isrc/ is ok, so remove
+ lengthy explanation.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-05-27 Derek Price <derek@ximbiot.com>
+
+ * README: New file explaining the GNULIB origin of many of the lib
+ files.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * unlocked-io.h: New file from GNULIB.
+ * system.h: Include unlocked-io.h.
+ * Makefile.am (libcvs_a_SOURCES): Add unlocked-io.h.
+
+ * Makefile.in: Regenerated.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * realloc.c: New file from GNULIB.
+ * system.h (HAVE_REALLOC, CVS_REALLOC): Add support for realloc.c.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * stat.c: Don't compile LSTAT code unless configure detected that we
+ need to be trailing-slash-safe.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * system.h: Move in the standard includes from cvs.h. Define
+ CVS_MALLOC & CVS_REALLOC.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * malloc.c: New file from <https://savannah.gnu.org/projects/gnulib>.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * lstat.c: New file from <https://savannah.gnu.org/projects/gnulib>.
+ * stat.c: Ditto.
+ * system.h: Define CVS_STAT and CVS_LSTAT properly when the system
+ versions of stat and lstat are broken.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Add fnmatch.h for Windows.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * xgssapi.h: #include config.h.
+ (Reported by Boyd Lynn Gerber <gerberb@zenez.com>.)
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * system.h: Define S_ISSOCK on SCO OpenServer.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-03 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (distclean-local): New target to remove fnmatch.h when
+ necessary. This should be handled by Automake, but until then...
+ (Resolves issue #100
+ <http://ccvs.cvshome.org/issues/show_bug.cgi?id=100> from
+ Serguei E. Leontiev <Serge3lse@cvshome.org>.)
+
+ * Makefile.in: Regenerated.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-01-23 Larry Jones <lawrence.jones@eds.com>
+
+ * getdate.y: Add RCS/CVS timestamp format (Y.mm.dd.hh.mm.ss).
+ * getdate.c: Regenerated.
+
+ * wait.h (WCOREDUMP): New macro.
+
+2002-12-27 Derek Price <derek@ximbiot.com>
+
+ * getdate.c: Regenerated with Bison 1.35.
+
+2002-11-04 Derek Price <derek@ximbiot.com>
+
+ * getdate.y (Convert): Add comment as to the effectiveness of
+ descriptive error messages.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-09-15 Larry Jones <lawrence.jones@eds.com>
+
+ * system.h: Add FOPEN_BINARY_READWRITE.
+ (Patch submitted by Josh Lehan <cvs@krellan.com>.)
+
+2002-08-12 Derek Price <oberon@umich.edu>
+
+ * Makefile.am: Remove obsolete reference to `ftruncate.c'.
+ (Symptoms reported by
+ Andrey Aristarkhov <Aristarkhov@bitechnology.ru>.)
+ * Makefile.in: Regenerated.
+
+2002-08-08 Derek Price <oberon@umich.edu>
+
+ * regex.c: Removed unused `compile_range' declaration.
+ (Patch from John Tytgat <John.Tytgat@aaug.net>.)
+
+2002-05-09 Larry Jones <lawrence.jones@eds.com>
+
+ * getline.c (getstr): Make terminator int instead of char to avoid
+ promotion problems.
+ * getline.h (getstr): Change to match.
+
+2002-05-08 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated.
+ * fnmatch.h: Move this file...
+ * fnmatch.h.in: here.
+
+2002-05-08 Derek Price <oberon@umich.edu>
+
+ * strerror.c: Use HAVE_CONFIG_H and put config.h in brackets rather
+ than quotes.
+
+2002-05-02 Derek Price <oberon@umich.edu>
+
+ * fnmatch.h: More #defines to avoid Mac OS X namespace conflicts.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * hostname.c: Rename to...
+ * gethostname.c: this.
+ * Makefile.am: Change comment to reflect above.
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2002-04-28 Derek Price <oberon@umich.edu>
+
+ * getopt.h: #define new names for functions and variables when they
+ might conflict with system definitions (namely on Mac OS X 10.1 with
+ the most recent dev packages - This should be removable after the Mac
+ dev packages are fixed.).
+ * regex.h: Ditto.
+ * Makefile.am (libcvs_a_SOURCES): Remove fnmatch.h.
+
+2002-04-20 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add getpagesize.h.
+ * Makefile.in: Regenerated.
+
+2001-09-18 Derek Price <dprice@collab.net>
+
+ * fnmatch.c: The header file for a system function we're replacing with
+ our own should be #included using double quotes.
+ (Patch from Corey Minyard <minyard@acm.org> via
+ Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * getpagesize.h: Only include sys/param.h when HAVE_SYS_PARAM_H has
+ been defined by configure.
+
+2001-08-07 Derek Price <dprice@collab.net>
+
+ * build_lib.com: Verify.
+ * getdate.y: Move the include of xtime.h out from underneath the ifdef
+ so that it is always included.
+ (Patch from Mike Marciniszyn <Mike.Marciniszyn@sanchez.com>.)
+
+ * getdate.c: Regenerated.
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-05 Larry Jones <larry.jones@sdrc.com>
+
+ * getpagesize.h: New file to define getpagesize() for systems that
+ don't already have it.
+ * valloc.c (valloc): Use it.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-06-15 Derek Price <dprice@collab.net>
+
+ * xselect.h: Don't include xtime.h.
+ (Thanks to Martin Neitzel <neitzel@sco.gaertner.de>.)
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-04-02 Derek Price <dprice@collab.net>
+ for Alon Ziv <alonz@zapper.com>
+
+ * getdate.y: Add a declaration for yyparse().
+
+ * getdate.c: Regenerated.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2001-02-20 Derek Price <derek.price@openavenue.com>
+
+ * xgssapi.h: New file to perform GSSAPI include magic.
+ * Makefile.am (EXTRA_DIST): Add xgssapi.h.
+
+ * Makefile.in: Regenerated.
+
+2001-02-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (libcvs_a_SOURCES): Add xtime.h & xselect.h.
+ * Makefile.in: Regenerated.
+ * getdate.y: Include xtime.h.
+ * getdate.c: Regenerated.
+ * system.h: Include xtime.h.
+ * xtime.h: New file to do include magic for time functions.
+ * xselect.h: New file to do select include magic.
+
+2001-02-06 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+ Shawn Smith <Shawn_Smith@notes.ymp.gov>
+
+ * system.h: definitions of CVS_OPENDIR, CVS_READDIR, & CVS_CLOSEDIR
+ provided here in support of changes to handle VMS DEC C 5.7
+ {open,read,close}dir problems. Check today's entry in the vms subdir
+ for more.
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+
+ * rename.c: replace calls to unlink() with CVS_UNLINK() for VMS
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (INCLUDES): Fixed typo
+ * Makefile.in: Regenerated
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (INCLUDES): Added $(top_srcdir)/src
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * .cvsignore: Added .deps directory and alphabetized
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+
+2000-11-15 Derek Price <derek.price@openavenue.com>
+
+ * system.h: Added CVS_FDOPEN to conform to CVS_FOPEN precedent
+
+2000-07-10 Larry Jones <larry.jones@sdrc.com>
+
+ * savecwd.c: #include <sys/types.h> before <fcntl.h>.
+
+2000-07-04 Karl Fogel <kfogel@red-bean.com>
+
+ * getline.h, getline.c (getstr): take new limit arg.
+ (GETLINE_NO_LIMIT): new #define.
+ (getline_safe): new function, takes limit arg and passes it on.
+ (getline): pass GETLINE_NO_LIMIT to getstr().
+
+ See related change of same date in ../src/ChangeLog.
+
+2000-06-19 Larry Jones <larry.jones@sdrc.com>
+
+ * regex.c, regex.h: Version from emacs 20.7 to plug memory leaks
+ and avoid potential portability problems.
+
+2000-03-22 Larry Jones <larry.jones@sdrc.com>
+
+ * getdate.y: Add logic to allow yyyy/mm/dd in addition to mm/dd/yy
+ (since that is the format CVS frequently uses).
+ * getdate.c: Regenerated.
+
+2000-02-16 Jim Meyering <meyering@lucent.com>
+
+ * sighandle.c (SIG_inCrSect): New function.
+
+2000-01-03 Larry Jones <larry.jones@sdrc.com>
+
+ * getdate.y (Convert): Add window to determine whether 2-digit dates
+ are 19xx (69-99) or 20xx (00-68).
+ (get_date): Fix y2k bug: initialize yyYear to tm_year + 1900,
+ not just tm_year.
+ * getdate.c: Regenerated.
+
+1999-12-29 Jim Kingdon <http://developer.redhat.com/>
+
+ * Makefile.in: There was a comment here which referred to a long
+ comment in configure.in about regex.o (the configure.in comment
+ isn't there any more). Replace our comment with a conciser
+ version of the former configure.in comment.
+
+1999-03-26 Jim Kingdon <http://www.cyclic.com>
+
+ * getopt.h: Don't declare the arguments to getopt.
+
+1999-02-09 Jim Kingdon <http://www.cyclic.com>
+
+ * vasprintf.c: Removed; there is apparently no clean, portable
+ solution to the VA_LIST_IS_ARRAY problem (C9X drafts have va_copy,
+ but we aren't even assuming C90 yet!).
+ * Makefile.in (SOURCES): Remove vasprintf.c.
+ * build_lib.com: Remove vasprintf.c and vasprintf.obj.
+
+1999-01-26 Jim Kingdon <http://www.cyclic.com>
+ and Joerg Bullmann <http://www.glink.net.hk/~jb/MacCVSClient/>
+
+ * fnmatch.c: Use FOLD_FN_CHAR in two cases where it had been
+ omitted.
+
+1999-01-22 Jim Kingdon <http://www.cyclic.com>
+
+ * fnmatch.c: Include system.h; FOLD_FN_CHAR has moved there from
+ config.h (from Alexey Milov). Don't define our own FOLD_FN_CHAR;
+ that just masks cases in which we got the includes tangled up.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * memmove.c: Remove paragraph which contained the FSF's old
+ snail mail address; it has changed.
+
+1999-01-05 Jim Kingdon <http://www.cyclic.com>
+
+ * md5.c, md5.h: Rename all the external interfaces to start with
+ cvs_* to avoid namespace pollution problems. Include string.h
+ unconditionally, to avoid gcc -Wall warnings on memset.
+
+1998-12-29 Jim Kingdon <http://www.cyclic.com>
+
+ * getdate.y (RelativeMonth): Add 1900 to tm_year, so that in 2000,
+ we pass 2000, not 100, to Convert.
+ (Convert): Add comment about Year argument.
+ * getdate.c: Regenerated using byacc.
+
+Tue Mar 24 16:08:00 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * Makefile.in (CFLAGS): Set to @CFLAGS@, not -g.
+
+1998-02-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * regex.c: Partial merge with version from emacs 20.2. Brings
+ over some trivial changes (whitespace and so on) (most such
+ changes I didn't bother with, for this time). Don't cast to int
+ before comparing old_regend[r] to regstart[r] (this is the point
+ of bothering; the old code was broken for 64 bit machines.
+ Reported by Paul Vixie).
+
+Tue Feb 17 18:33:26 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * memmove.c: New file, resurrecting the old one.
+ * Makefile.in (SOURCES): Add memmove.c.
+
+1998-02-03 Tim Pierce <twp@skepsis.com>
+
+ * system.h (CVS_LSTAT): New macro.
+
+Sat Feb 7 17:33:39 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * getline.h (getstr): Declare.
+
+13 Jan 1998 Jim Kingdon
+
+ * fncase.c: Include config.h before system.h.
+
+ * system.h: Just include string.h unconditionally. We already
+ include it unconditionally elsewhere.
+
+Tue Jan 13 16:51:59 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * fncase.c: New file, taken from windows-NT/filesubr.c.
+ * system.h: If __CYGWIN32__ or WIN32 are defined, define
+ FOLD_FN_CHAR, FILENAMES_CASE_INSENSITIVE, and ISDIRSEP, and
+ declare fncmp and fnfold. Taken from windows-NT/config.h.
+ * Makefile.in (SOURCES): Add fncase.c.
+
+Sat Jan 10 10:51:26 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getline.c (getstr): Make sure to set errno when appropriate. I
+ didn't test the error case for the new code but inspection shows
+ the old code was rather broken.
+
+Sat Nov 29 22:03:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ getwd and getcwd were a big big mess. Although Jim's fix might
+ indeed be fixing a typo, the code is so tangled that I would guess
+ it probably breaks some system. So clean this up:
+ * xgetwd.c: Always assume we have getcwd (we had been anyway,
+ before Jim's change).
+ * getwd.c: Removed.
+ * Makefile.in: Remove getwd.c
+ * system.h: Remove declarations of getwd and getcwd. Move getcwd
+ declaration to the !HAVE_UNISTD_H section.
+
+1997-11-29 Jim Meyering <meyering@na-net.ornl.gov>
+
+ * xgetwd.c: Fix typo s/ifndef/ifdef/ in test of HAVE_GETWD.
+
+Wed Nov 26 10:12:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: Always use "rb" and "wb". Check for O_BINARY with an
+ #ifdef, not the error-prone LINES_CRLF_TERMINATED.
+
+Thu Sep 25 10:57:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.y (get_date): If gmtime returns NULL, try to cope.
+ * getdate.c: Regenerated using byacc.
+
+ * getdate.y: Remove comment about sending email concerning this file
+ to Rich Salz.
+ * getdate.c: Regenerated using byacc.
+
+Wed Sep 24 10:35:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (OBJECTS): Add regex.o.
+
+Wed Sep 17 16:37:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.y (ToSeconds): For am or pm, a hour of "12" really means 0.
+ * getdate.c: Regenerated using byacc (not bison per comment).
+
+Tue Sep 9 20:51:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * build_lib.com: Add vasprintf.c and vasprintf.obj.
+
+ * build_lib.com: Remove strippath.obj from library/create command.
+
+Sun Sep 7 17:35:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: Replace comment referring to ChangeLog with a
+ comment based on the ChangeLog entries.
+
+ * strdup.c: Removed, per change to ../configure.in
+ * Makefile.in (SOURCES): Remove strdup.c.
+
+Mon Jun 16 18:59:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: Add CVS_FNMATCH.
+
+Sun Jun 8 23:41:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h (mkfifo): Remove; not used anywhere.
+
+Thu Mar 6 17:14:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * regex.c: Partial merge with version from emacs 19.34. I brought
+ over most trivial changes (whitespace and so on). Most of the
+ changes to portability cruft I did not bring over, on the theory
+ of sticking to the devil that we know. I did bring over the
+ change to undef MAX and MIN (this is a better solution to a
+ problem we had been handling a different way). There were a
+ variety of changes I probably could/should have brought over, but
+ elected not to try to understand them and whether they would cause
+ trouble (printchar -> putchar, changes to output format in
+ print_partial_compiled_pattern, internationalization,
+ FREE_STACK_RETURN and friends which would appear to be fixing
+ memory leaks in error cases, RE_TRANSLATE_TYPE, and others). I
+ did merge the changes (union fail_stack_elt, PUSH_FAILURE_POINTER,
+ etc.) to use a union for the failure stack rather than playing
+ games with pointers and integers (that was my reason for
+ bothering; the code had been broken on the Alpha).
+
+Mon Feb 10 18:52:18 1997 Ullrich von Bassewitz <uz@musoftware.com>
+
+ * md5.c: Make the parameter to getu32 const since the function will
+ only read the values and this will avoid compiler warnings in other
+ places.
+
+Mon Feb 10 18:29:04 1997 Ullrich von Bassewitz <uz@musoftware.com>
+
+ * vasprintf.c: Added a #define for systems where a va_list is
+ defined as an array, not as a pointer.
+
+Mon Feb 10 09:31:38 1997 Ken Raeburn <raeburn@cygnus.com>
+
+ * md5.c (MD5STEP): Truncate to 32 bits before shifting right.
+
+Thu Jan 30 11:35:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * regex.h: Don't prototype re_comp and re_exec.
+
+Tue Jan 28 17:45:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * md5.c, md5.h: Changes so these work without having an integer
+ type which is exactly 32 bits. Modeled after changes by Tatu Ylonen
+ <ylo@cs.hut.fi> as part of SSH but rewritten.
+
+Wed Jan 8 14:50:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, getopt.h, sighandle.c, system.h: Remove CVSid; we
+ decided to get rid of these some time ago.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, argmatch.c, fnmatch.c, fnmatch.h, getline.c,
+ getopt.c, getopt.h, getopt1.c, getwd.c, hostname.c, mkdir.c,
+ regex.c, regex.h, rename.c, sighandle.c, strdup.c, strerror.c,
+ stripslash.c, system.h, vasprintf.c, wait.h, xgetwd.c, yesno.c:
+ Remove "675" paragraph; see ../ChangeLog for rationale.
+
+Sun Nov 24 13:34:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.y (Convert): Change last acceptable year from 1999 to
+ 2038.
+ * getdate.c: Regenerated using byacc 1.9.
+
+Tue Nov 19 17:11:17 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (OBJECTS): Remove strippath.o; we don't use
+ strip_path anymore.
+ (SOURCES): Remove strippath.c.
+ * strippath.c: Removed.
+ * build_lib.com: Remove strippath.c.
+
+Wed Oct 2 10:43:35 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * getdate.y: removed CVSid variable
+
+ * getdate.c: regenerated (using byacc 1.9)
+
+Wed Sep 25 10:25:00 1996 Larry Jones <larry.jones@sdrc.com>
+
+ * vasprintf.c: Fix type clashes in calls to strtoul.
+
+Wed Sep 11 15:55:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * build_lib.com: Add valloc.c.
+
+Tue Sep 10 23:04:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add build_lib.com.
+
+Fri Aug 16 16:01:57 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in (installdirs): new (empty) target
+
+Mon Aug 12 11:03:43 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: Don't use #elif. It is said to cause problems with
+ one of the HP compilers on HPUX 9.01.
+
+Sun Jul 7 23:25:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * memmove.c: Removed. The memove function was used by a very old
+ version of the CVS server for nefarious purposes and it has been
+ long gone.
+ * Makefile.in (SOURCES): Remove memmove.c.
+
+Thu Jun 6 15:12:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vasprintf.c: If STDC_HEADERS, include stdlib.h rather than
+ declaring its functions ourself.
+
+Wed Jun 05 10:14:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * system.h: If ERRNO_H_MISSING is defined, don't include errno.h.
+
+Wed Jun 05 10:14:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * regex.c: Don't define MAX and MIN if already defined.
+
+Sun May 12 09:40:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.y: Replace alloca.h include with a comment explaining
+ why we avoid alloca and the consequences of that.
+ * getdate.c: Regenerated.
+
+Wed May 8 09:31:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.c: Regenerate with the version of byacc in Red Hat 3.0.3
+ (which I believe is byacc 1.9). byacc, unlike bison, does not
+ require alloca in the generated parser.
+
+Thu Apr 25 18:26:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.y (get_date): Set Start from nowtime, not now->time,
+ which may not be set.
+ * getdate.c: Regenerated.
+
+Wed Apr 10 17:55:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.y (get_date): Use a time_t variable rather than a field
+ in a struct timeb. Works around Solaris compiler bug. Sure, it
+ is a compiler bug, but the workaround is completely painless.
+ * getdate.c: Regenerated.
+
+Fri Mar 22 11:17:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: If EXIT_FAILURE is not defined by stdlib.h, define it
+ ourself.
+
+Thu Mar 14 16:27:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: Remove alloca cruft.
+
+Wed Feb 28 03:16:48 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * build_lib.com: Changed definition of symbol CC to search
+ for include files in [-.VMS] so VMS config.h can be picked
+ up without copying.
+
+Tue Feb 27 21:26:34 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * build_lib.com: Added. DCL File to build contents of [.lib]
+
+Tue Feb 27 21:18:38 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * system.h: added an existence_error macro check for EVMSERR
+ necessary for happiness under VMS
+
+Thu Feb 22 22:30:04 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (OBJECTS): Remove @ALLOCA@
+ (SOURCES): Remove alloca.c
+ * alloca.c: Removed.
+ * regex.c (REGEX_MALLOC): Define.
+
+Thu Feb 15 14:00:00 Jim Kingdon <kingdon@cyclic.com>
+
+ * vasprintf.c: Declare abs().
+
+Wed Feb 14 14:48:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vasprintf.c (int_vasprintf): Don't cast arguments to memcpy.
+ * vasprintf.c, strtoul.c: Don't include ansidecl.h. Do include
+ config.h if HAVE_CONFIG_H (for const).
+ * strtoul.c: Change CONST to const.
+
+Tue Feb 13 20:04:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * strtoul.c: Added (needed by vasprintf.c, and missing on SunOS4).
+ * Makefile.in (SOURCES): Add strtoul.c.
+
+Mon Feb 12 10:04:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vasprintf.c: Added (same contents as before).
+ * Makefile.in (SOURCES): Add vasprintf.c.
+
+Thu Feb 1 14:33:17 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * Makefile.in (xlint): new rule; does nothing, as I'm not sure
+ running lint is actually advisable in here, but the top-level
+ Makefile thinks it can `make xlint' here.
+
+Thu Feb 1 15:07:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getopt.c: Remove rcsid.
+
+Tue Jan 30 18:20:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getline.c: Don't define NDEBUG.
+ (getstr): Rewrite assertions in a way which should stay clear of
+ signed/unsigned problems and compiler warnings thereof.
+
+Thu Jan 25 00:14:06 1996 Jim Kingdon <kingdon@beezley.cyclic.com>
+
+ * yesno.c (yesno): fflush stdout as well as stderr.
+
+Wed Jan 3 18:16:50 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sighandle.c (SIG_register): Use memset not bzero.
+ * system.h: Remove defines for index, rindex, bcmp, and bzero.
+ All the calls to those functions are gone from CVS.
+
+Tue Jan 2 13:00:00 1996 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ Visual C++ lint:
+ * sighandle.c: Prototype SIG_handle and SIG_defaults.
+ Use SIG_ERR where appropriate.
+
+Mon Dec 18 10:15:05 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rename.c: Check ENOENT rather than existence_error. The latter
+ is undefined in this file, and including system.h is said to cause
+ (unspecified) problems.
+
+Sun Dec 17 23:58:06 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vasprintf.c: Removed (it is no longer used).
+ * Makefile.in (SOURCES): Remove vasprintf.c.
+
+Sat Dec 16 17:18:33 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vasprintf.c: Added.
+ * Makefile.in (SOURCES): Add vasprintf.c
+
+Mon Dec 4 10:54:04 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getdate.c: Remove #line directives. I know, this is a kludge,
+ but Visual C++ 2.1 seems to require it (why, I have no idea. It
+ has no trouble with the #line directives in getdate in CVS 1.6).
+
+Sat Nov 18 16:20:37 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * rename.c: same.
+
+ * mkdir.c: Use new macro `existence_error', instead of comparing
+ errno to ENOENT directly.
+
+ * system.h (existence_error): new macro, tries to portably ask if
+ errno represents a file-not-exist error.
+
+Fri Nov 17 20:08:58 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h (NEED_DECOY_PERMISSIONS): moved this section to where
+ it belongs, duh.
+
+ * getdate.c: if STDC_HEADERS, then just include <stdlib.h> instead
+ of declaring malloc() and realloc() to be char *.
+
+ * system.h: ifdef NEED_DECOY_PERMISSIONS, then define the S_I*
+ permission masks for USR, GRP, and OTH in terms of the simpler
+ OS/2 masks.
+
+Wed Nov 15 15:36:03 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h: ifdef USE_OWN_TCPIP_H, then include "tcpip.h". Only
+ OS/2 does this right now.
+
+Tue Nov 14 18:44:57 1995 Greg A. Woods <woods@most.weird.com>
+
+ * getdate.c: OK, this one is from SunOS-4.1 yacc and may be more
+ portable -- at least it compiles silently here! ;-)
+
+Mon Nov 13 03:53:45 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * fnmatch.c: conform to 80 column standard (yes, I'm a pedant).
+
+Wed Nov 8 11:10:59 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h (STAT_MACROS): ifdef S_IFMT, then use it as before; but
+ if it's not defined, then just do a single mask and assume
+ acceptance any of non-zero result. Norbert, I trust you'll let me
+ know if this is unsatisfactory. :-)
+ Ifdef HAVE_SYS_UTIME_H, then include <sys/utime.h>. Only OS/2
+ defines this right now.
+
+Wed Nov 8 13:18:51 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * valloc.c: omit malloc declaration (it's already in system.h
+ which is included and conflicts with <stdlib.h> on some
+ systems).
+
+Tue Nov 7 19:38:48 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * system.h (STAT_MACROS_BROKEN): undo previous change, because
+ else all regular files will be identified as links (the mask for
+ links is S_IFREG|S_IFCHR).
+
+Mon Nov 6 19:20:56 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * system.h (STAT_MACROS_BROKEN): in defining the S_IF* macros,
+ don't fold to 1 or 0 by first masking with S_IFMT; not all
+ systems have that macro, and anyway it's only necessary that we
+ return non-zero.
+
+Fri Oct 27 13:43:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * save-cwd.c: use __PROTO instead of __P (see below).
+
+ * getline.h (__PROTO): same as below.
+
+ * save-cwd.h (__PROTO): replaces __P. New name, so don't ask if
+ already defined. The conflict was that OS/2 w/ IBM C/C++ uses
+ `__P' for something else, in <ctype.h> of all places.
+
+ * system.h: do nothing about alloca ifdef ALLOCA_IN_STDLIB (see
+ ../src/ChangeLog).
+
+Tue Oct 24 13:01:25 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * wait.h: include sys/resource.h if available. This is needed at
+ least under AIX-3.2 where <sys/wait.h> doesn't include it.
+
+Mon Oct 23 17:39:11 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * valloc.c (valloc): change parameter definition
+
+Sun Oct 22 14:15:44 1995 Jim Meyering (meyering@comco.com)
+
+ * getline.c, getline.h: New files.
+ * Makefile.in (SOURCES, OBJECTS, HEADERS): Add getline.c, getline.o,
+ and getline.h, respectively.
+
+Tue Oct 10 18:01:50 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * Makefile.in (cvs_srcdir): define cvs_srcdir to be ../src, then
+ include it with -I so save_cwd.c can find error.h (for example).
+
+Sun Oct 8 12:27:57 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * system.h: define POSIX_SIGNALS or BSD_SIGNALS if configure has
+ located all the necessary functions for each "type".
+ * sighandle.c: detect/use POSIX/BSD reliable signals (especially
+ for blocking signals in critical sections). Helps prevent stray
+ locks on interruption.
+
+Mon Oct 2 18:11:23 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * system.h: Doc fix.
+
+Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * regex.c: compile 4.2 BSD compatible functions even when
+ _POSIX_SOURCE is defined since we need them and we wouldn't be
+ compiling this file unless they don't exist.
+
+Mon Oct 2 10:32:20 1995 Michael Finken <finken@conware.de>
+
+ * strstr.c (strstr): new file and func.
+
+ * Makefile.in (SOURCES): added strstr.c.
+
+Sun Oct 1 21:03:40 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * regex.c: reverted below change.
+
+Thu Sep 28 13:37:04 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * regexp.c: check for ISC.
+
+Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * save-cwd.c: #include <direct.h> and <io.h>, on systems that
+ have them.
+
+ * getopt.c (_getopt_internal): Cast the return value of strlen,
+ which is unsigned, before comparing it with the difference between
+ two pointers, which is unsigned.
+
+Thu Aug 31 11:31:42 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * getdate.y [STDC_HEADERS]: #include <stdlib.h>, for abort.
+ [HAVE_ALLOCA_H]: #include <alloca.h>, for alloca on Windows NT.
+
+Wed Aug 30 18:48:44 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * system.h [HAVE_IO_H]: #include <io.h>, for Windows NT.
+ [HAVE_DIRECT_H]: #include <direct.h>, for Windows NT.
+ (CVS_MKDIR, FOLD_FN_CHAR, fnfold, fncmp, ISDIRSEP, OPEN_BINARY,
+ FOPEN_BINARY_READ, FOPEN_BINARY_WRITE): New macros/functions, for
+ use in system-sensitive code.
+
+ * regex.c (re_set_registers): start and end are pointers, not
+ integers. Cast the initializing value appropriately.
+
+ * getopt.c [HAVE_STRING_H]: #include <string.h>, to avoid
+ warnings.
+
+ * fnmatch.c (FOLD_FN_CHAR): Give this a dummy #definition if
+ config.h didn't #define it.
+ (fnmatch): Pass filename characters through FOLD_FN_CHAR before
+ comparing them.
+
+ * argmatch.c: #include <sys/types.h>.
+ (argmatch): Declare arglen to be a size_t, rather than an int,
+ to avoid signed/unsigned comparison "problems".
+
+ * .cvsignore: Remove getdate.c from this file. We want to
+ distribute it, for systems that don't have a Yacc-equivalent
+ installed (like Windows NT).
+
+Sat Aug 19 22:00:51 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * error.c: Don't #define CVS_SUPPORT here. config.h takes care of
+ that for us.
+ [CVS_SUPPORT] (error_use_protocol): New variable, with apology.
+ (error): If error_use_protocol is set, report errors using the
+ client/server protocol.
+ * error.h [CVS_SUPPORT]: Extern decl for error_use_protocol.
+
+Fri Aug 4 00:01:24 1995 Jim Meyering (meyering@comco.com)
+
+ * xgetwd.c: Don't declare free. A K&R style declaration gets
+ a conflict on some Sun systems when compiling with acc.
+
+ * save-cwd.c: New file.
+ * save-cwd.h: New file.
+ * Makefile.in (SOURCES): Add save-cwd.c
+ (OBJECTS): Add save-cwd.o.
+ (HEADERS): Add save-cwd.h.
+
+Thu Aug 3 00:55:54 1995 Jim Meyering (meyering@comco.com)
+
+ * error.h: New file.
+ * Makefile.in (HEADERS): Add error.h.
+
+Sat Jul 29 15:53:55 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (SOURCES): Add getdate.c.
+
+Thu Jul 27 09:11:41 1995 Robert Lipe <robertl@rjlhome.arnet.com>
+
+ * system.h: Check for PATHSIZE before falling back to _POSIX_PATH_MAX.
+
+Thu Jul 20 12:38:03 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.c: Instead of calling cvs functions to clean up, allow cvs
+ to register a callback via error_set_cleanup. Avoids hassles with
+ include files and SERVER_SUPPORT and so on.
+
+Tue Jul 18 21:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * system.h: Include <sys/param.h> only if HAVE_SYS_PARAM_H
+ is #defined. We've added a test to configure.in to #define this
+ on most systems.
+
+Thu Jul 13 11:22:21 1995 Jim Meyering (meyering@comco.com)
+
+ * xgetwd.c: New file.
+ * Makefile.in (SOURCES): Add xgetwd.c
+ (OBJECTS): Add xgetwd.o.
+
+Wed Jul 12 09:18:49 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (OBJECTS): Remove fnmatch.o. Now configure adds it
+ to LIBOBJS when necessary.
+
+Fri Jun 30 16:27:18 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * rename.c (rename): If MVDIR is not defined, just give an error
+ on attempt to rename a directory.
+
+Thu Jun 29 00:46:31 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: Check HAVE_SYS_TIMEB_H not non-existent HAVE_TIMEB_H.
+
+ * system.h: Don't define alloca if it is already defined.
+
+Wed Jun 28 15:24:51 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * system.h: If NeXT, define utimbuf ourself.
+
+Mon May 29 22:32:40 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * system.h: Handle time and directory headers as recommended in
+ the autoconf manual.
+ Undefine the S_FOO() macros if STAT_MACROS_BROKEN is set.
+ Don't define mode_t, as it is handled by config.h.
+
+Sat May 27 08:46:00 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (Makefile): Regenerate only Makefile in current
+ directory when Makefile.in is out of date. Depend on ../config.status.
+
+Fri Apr 28 22:49:25 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (SOURCES, OBJECTS): Updated.
+ (HEADERS): New variable.
+ (DISTFILES): Updated.
+ (dist-dir): Renamed from dist; changed to work with DISTDIR
+ variable passed from parent.
+
+Wed Feb 8 06:37:53 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * system.h (S_IRUSR et al): Define if not already defined.
+
+ * waitpid.c [HAVE_CONFIG_H]: Include "config.h".
+ (ualloc): Return OLDPTR rather than running off the end.
+
+Mon Aug 22 22:48:19 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * error.c (strerror): Replaced conditional static definition
+ (always used, since the condition variable was never set) with an
+ extern declaration, since it's provided by libc or strerror.c.
+
+Wed Aug 10 14:54:25 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * Makefile.in (SOURCES): Add waitpid.c.
+ * waitpid.c: New file.
+
+Tue Aug 9 16:00:12 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * md5.h (uint32): If SIZEOF_LONG isn't 4, don't define this to be
+ "unsigned long"; try SIZEOF_INT and "unsigned int", otherwise
+ complain.
+
+ * md5.c: Include config.h.
+ (const): Don't bother defining here, config.h should take care of
+ it.
+
+ * valloc.c (malloc): Declare.
+
+Fri Jul 15 12:57:20 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * getopt.c: Do not include <stdlib.h> unless __GNU_LIBRARY__ is
+ defined. On Irix 5.2, <stdlib.h> includes <getopt.h>, which
+ causes a multiple definition of struct option.
+
+Fri Jul 8 10:04:59 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * md5.h, md5.c: Remove ANSI-isms.
+
+Thu Jul 7 20:24:18 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * md5.h, md5.c: New files.
+ * Makefile.in (SOURCES): Add md5.c.
+ (OBJECTS): Add md5.o.
+ (DISTFILES): Add md5.h.
+ (md5.o): New target; depend upon md5.h.
+
+Fri May 27 18:15:34 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * valloc.c: New file.
+
+Tue May 17 08:18:26 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * error.c (error, fperror): If server_active, call server_cleanup
+ as well as Lock_Cleanup.
+
+Thu Jan 6 13:45:04 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * system.h: Fix Dec 27 change to work correctly. Makes Sep 9
+ change unnecessary, so backed that one out. Never define PATH_MAX
+ in terms of pathconf, because that doesn't produce a constant, and
+ PATH_MAX is used to set array sizes.
+
+Mon Dec 27 14:22:07 1993 Mark Eichin (eichin@cygnus.com)
+
+ * system.h: don't touch PATH_MAX or MAXPATHLEN if *both* of them
+ are already defined, as one may be defined in terms of the other.
diff --git a/lib/ChangeLog.fsf b/lib/ChangeLog.fsf
new file mode 100644
index 0000000..176d791
--- /dev/null
+++ b/lib/ChangeLog.fsf
@@ -0,0 +1,90 @@
+Thu Sep 15 00:18:26 1994 david d `zoo' zuhn <zoo@monad.armadillo.com>
+
+ * system.h: remove a bunch of "extern int " declarations of system
+ functions (could conflict with vendor header files, and didn't
+ do anything *too* useful to begin with).
+
+ * Makefile.in: update getdate.y message (now has 10 s/r conflicts)
+
+Wed Sep 14 22:12:21 1994 david d `zoo' zuhn <zoo@monad.armadillo.com>
+
+ * strerror.c: more complete, from the Cygnus libiberty package
+
+ * error.c (strerror): removed, functionality is in strerror.c
+
+ * cvs.h: remove duplicate prototype for Reader_Lock
+ * history.c: printf argument mismatch
+ (Both fixes thanks to J.T. Conklin (jtc@cygnus.com)
+
+Sat Jul 30 13:50:11 1994 david d `zoo' zuhn (zoo@monad.armadillo.com)
+
+ * getopt1.c, getopt.c, getopt.h, getdate.y: latest versions from FSF
+
+Wed Jul 13 22:11:17 1994 david d `zoo' zuhn (zoo@monad.armadillo.com)
+
+ * system.h: don't set PATH_MAX to pathconf(), since PATH_MAX is
+ used to size arrays. (thanks to kingdon@cygnus.com)
+
+ * getopt1.c: remove #ifdef __STDC__ around const usages (which
+ isn't correct and weren't complete)
+
+Wed Apr 20 14:57:16 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * getopt.h: Prevent multiple inclusion.
+
+Tue Jan 25 17:34:42 1994 david d zuhn (zoo@monad.armadillo.com)
+
+ * Makefile.in: make sure that no blank lines are in the $(OBJECTS)
+ list (from Brad Figg)
+
+Mon Jan 24 12:27:13 1994 david d zuhn (zoo@monad.armadillo.com)
+
+ * system.h: remove alloca checks (added to src/cvs.h); revamped
+ the MAXPATHLEN and PATH_MAX tests (from Brad Figg
+ <bradf@wv.MENTORG.COM>); handle index,rindex,bcmp,bzero better
+ (don't redefine if already defined); added S_IWRITE, S_IWGRP,
+ S_IWOTH definitions (header file reorganization)
+
+ * strippath.c: use strchr, not index
+
+ * getopt1.c: match prototypes when __STDC__ compiler (lint fixes)
+
+ * getdate.c: alloca checks for when using bison
+
+ * Makefile.in: added CC and YACC definitions; use YACC not BISON;
+ better getdate.c tests (also from Brad Figg)
+
+Sat Dec 18 00:55:43 1993 david d zuhn (zoo@monad.armadillo.com)
+
+ * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead
+
+ * memmove.c: new file, implements memmove in terms of bcopy
+
+ * wait.h: include <sys/wait.h> if HAVE_SYS_WAIT_H, not if POSIX
+
+Thu Sep 9 18:02:11 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com)
+
+ * system.h: only #undef PATH_MAX if not on an Alpha. The #undef
+ causes problems with the Alpha C compiler.
+
+Thu Apr 8 12:39:56 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * system.h: Removed several incorrect declarations which fail
+ on Solaris.
+
+Wed Jan 20 17:57:24 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * system.h: add externs for sun4 so that gcc -Wall becomes useful
+ again.
+
+Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in, configure.in: removed traces of namesubdir,
+ -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced
+ copyrights to '92, changed some from Cygnus to FSF.
+
+Sat Dec 28 02:42:06 1991 K. Richard Pixley (rich at cygnus.com)
+
+ * mkdir.c, rename.c: change fork() to vfork().
+
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..1b8ffa5
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,321 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for library files used by GNU CVS.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+noinst_LIBRARIES = libcvs.a
+
+# Should look into unifying regular expression matching in CVS
+# with the diff library (perhaps to have the caller, CVS, do the
+# matching?)
+libcvs_a_SOURCES = \
+ sighandle.c \
+ system.h \
+ wait.h \
+ xselect.h \
+ xtime.h
+## Because @LIBOBJS@ is included below and AC_LIBOBJ is sometimes called on
+## these files from configure.in, automake automatically knows about many of
+## the *.c files in this directory.
+libcvs_a_LIBADD = \
+ @LIBOBJS@
+
+
+
+## Zero some variables so Automake will allow us to use += on them.
+BUILT_SOURCES =
+MOSTLYCLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+TESTS =
+check_PROGRAMS =
+
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog.fsf \
+ Makefile.gnulib \
+ build_lib.com \
+ libcvs.dep \
+ libcvs.dsp \
+ libcvs.mak \
+ test-getdate.sh
+
+## begin gnulib module alloca
+
+
+libcvs_a_LIBADD += @ALLOCA@
+## end gnulib module alloca
+
+## begin gnulib module alloca-opt
+
+BUILT_SOURCES += $(ALLOCA_H)
+EXTRA_DIST += alloca_.h
+
+# We need the following in order to create <alloca.h> when the system
+# doesn't have one that works with the given compiler.
+alloca.h: alloca_.h
+ cp $(srcdir)/alloca_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += alloca.h alloca.h-t
+
+## end gnulib module alloca-opt
+
+## begin gnulib module allocsa
+
+libcvs_a_SOURCES += allocsa.h allocsa.c
+EXTRA_DIST += allocsa.valgrind
+
+## end gnulib module allocsa
+
+## begin gnulib module cycle-check
+
+libcvs_a_SOURCES += cycle-check.c cycle-check.h dev-ino.h
+
+## end gnulib module cycle-check
+
+## begin gnulib module dirname
+
+libcvs_a_SOURCES += basename.c stripslash.c
+
+## end gnulib module dirname
+
+## For GNULIB's error module.
+##
+## This module isn't fully imported since GNULIB's error.c would conflict with
+## src/error.c (which knows how to send error messages over the network). We
+## don't compile error.c into libcvs on purpose. It can get compiled later as
+## part of the getdate test program,
+libcvs_a_SOURCES += error.h
+
+## begin gnulib module exit
+
+libcvs_a_SOURCES += exit.h
+
+## end gnulib module exit
+
+## begin gnulib module fnmatch
+
+BUILT_SOURCES += $(FNMATCH_H)
+EXTRA_DIST += fnmatch_.h fnmatch_loop.c
+
+# We need the following in order to create <fnmatch.h> when the system
+# doesn't have one that supports the required API.
+fnmatch.h: fnmatch_.h
+ cp $(srcdir)/fnmatch_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += fnmatch.h fnmatch.h-t
+
+## end gnulib module fnmatch
+
+## begin gnulib module getaddrinfo
+
+libcvs_a_SOURCES += getaddrinfo.h
+
+## end gnulib module getaddrinfo
+
+## begin gnulib module getdate
+
+## CVS test scripts for getdate.
+TESTS += test-getdate.sh
+MOSTLYCLEANFILES += getdate-expected getdate-got getdate.diff
+DISTCLEANFILES += getdate.log
+# Program required by test-getdate.sh for testing getdate.y.
+check_PROGRAMS += getdate
+getdate_SOURCES = \
+ error.c \
+ getdate.y
+## This source file was added only for the getdate test program when compiled
+## with GNULIB's error.c.
+getdate_SOURCES += \
+ progname.c
+getdate_CPPFLAGS = -DTEST
+getdate_LDADD = \
+ $(noinst_LIBRARIES) \
+ $(LIB_CLOCK_GETTIME) \
+ $(LIBINTL)
+
+BUILT_SOURCES += getdate.c
+MAINTAINERCLEANFILES += getdate.c
+EXTRA_DIST += getdate.c
+
+## end gnulib module getdate
+
+## begin gnulib module getndelim2
+
+EXTRA_DIST += getndelim2.h getndelim2.c
+
+## end gnulib module getndelim2
+
+## begin gnulib module getnline
+
+libcvs_a_SOURCES += getnline.h getnline.c
+
+## end gnulib module getnline
+
+## begin gnulib module getopt
+
+BUILT_SOURCES += $(GETOPT_H)
+EXTRA_DIST += getopt_.h getopt_int.h
+
+# We need the following in order to create <getopt.h> when the system
+# doesn't have one that works with the given compiler.
+getopt.h: getopt_.h
+ cp $(srcdir)/getopt_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += getopt.h getopt.h-t
+
+## end gnulib module getopt
+
+## begin gnulib module gettext-h
+
+libcvs_a_SOURCES += gettext.h
+
+## end gnulib module gettext-h
+
+## begin gnulib module glob
+
+BUILT_SOURCES += $(GLOB_H)
+
+# We need the following in order to create an <getopt.h> when the system
+# doesn't have one that works with the given compiler.
+all-local $(libcvs_a_OBJECTS): $(GLOB_H)
+glob.h: glob_.h
+ cp $(srcdir)/glob_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += glob.h glob.h-t
+
+## end gnulib module glob.c
+
+## begin gnulib module mbuiter
+
+libcvs_a_SOURCES += mbuiter.h
+
+## end gnulib module mbuiter
+
+## begin gnulib module minmax
+
+libcvs_a_SOURCES += minmax.h
+
+## end gnulib module minmax
+
+## begin gnulib module setenv
+
+libcvs_a_SOURCES += setenv.h
+
+## end gnulib module setenv
+
+## begin gnulib module size_max
+
+libcvs_a_SOURCES += size_max.h
+
+## end gnulib module size_max
+
+## begin gnulib module stdbool
+
+BUILT_SOURCES += $(STDBOOL_H)
+EXTRA_DIST += stdbool_.h
+
+# We need the following in order to create <stdbool.h> when the system
+# doesn't have one that works.
+stdbool.h: stdbool_.h
+ sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' \
+ < $(srcdir)/stdbool_.h > $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += stdbool.h stdbool.h-t
+
+## end gnulib module stdbool
+
+## begin gnulib module stdint
+
+BUILT_SOURCES += $(STDINT_H)
+EXTRA_DIST += stdint_.h
+
+# We need the following in order to create <stdint.h> when the system
+# doesn't have one that works with the given compiler.
+stdint.h: stdint_.h
+ sed -e 's/@''HAVE_LONG_64BIT''@/$(HAVE_LONG_64BIT)/g;s/@''HAVE_LONG_LONG_64BIT@/$(HAVE_LONG_LONG_64BIT)/g' < $(srcdir)/stdint_.h > $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += stdint.h stdint.h-t
+
+## end gnulib module stdint
+
+## begin gnulib module strcase
+
+libcvs_a_SOURCES += strcase.h
+
+## end gnulib module strcase
+
+## begin gnulib module strnlen1
+
+libcvs_a_SOURCES += strnlen1.h strnlen1.c
+
+## end gnulib module strnlen1
+
+## begin gnulib module strstr
+
+libcvs_a_SOURCES += strstr.h
+
+## end gnulib module strstr
+
+## begin gnulib module time_r
+
+libcvs_a_SOURCES += time_r.h
+
+## end gnulib module time_r
+
+## begin gnulib module vasnprintf
+
+libcvs_a_SOURCES += printf-args.h printf-parse.h vasnprintf.h
+
+## end gnulib module vasnprintf
+
+## begin gnulib module vasprintf
+
+libcvs_a_SOURCES += vasprintf.h
+
+## end gnulib module vasprintf
+
+## begin gnulib module xalloc-die
+
+libcvs_a_SOURCES += xalloc-die.c
+
+## end gnulib module xalloc-die
+
+## begin gnulib module xgethostname
+
+libcvs_a_SOURCES += xgethostname.h xgethostname.c
+
+## end gnulib module xgethostname
+
+## begin gnulib module xreadlink
+
+libcvs_a_SOURCES += xreadlink.h xreadlink.c
+
+## end gnulib module xreadlink
+
+## begin gnulib module xsize
+
+libcvs_a_SOURCES += xsize.h
+
+## end gnulib module xsize
+
+# Until Automake gets its act together
+distclean-local:
+ rm -f fnmatch.h
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/lib/Makefile.gnulib b/lib/Makefile.gnulib
new file mode 100644
index 0000000..0ec0d06
--- /dev/null
+++ b/lib/Makefile.gnulib
@@ -0,0 +1,258 @@
+## Process this file with automake to produce Makefile.in.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+#
+# This file is free software, distributed under the terms of the GNU
+# General Public License. As a special exception to the GNU General
+# Public License, this file may be distributed as part of a program
+# that contains a configuration script generated by Automake, under
+# the same distribution terms as the rest of that program.
+#
+# Generated by gnulib-tool.
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --aux-dir=build-aux --macro-prefix=gl allocsa atexit canon-host canonicalize closeout dirname dup2 error exit exitfail extensions fnmatch fnmatch-posix ftruncate getdate gethostname getline getlogin_r getndelim2 getnline getopt getpagesize getpass-gnu gettext gettime gettimeofday glob lstat malloc md5 memmove minmax mkdir mkstemp mktime nanosleep pagealign_alloc pathmax quotearg readlink realloc regex rename restrict save-cwd setenv stat-macros stdbool stdint strcase strdup strerror strftime strstr strtoul time_r timespec tzset unlocked-io vasnprintf vasprintf xalloc-die xgethostname xreadlink xsize yesno
+
+AUTOMAKE_OPTIONS = 1.5 gnits no-dependencies
+
+noinst_LIBRARIES = libgnu.a
+
+libgnu_a_SOURCES =
+libgnu_a_LIBADD = @LIBOBJS@
+EXTRA_DIST =
+BUILT_SOURCES =
+SUFFIXES =
+MOSTLYCLEANFILES =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+
+## begin gnulib module alloca
+
+
+libgnu_a_LIBADD += @ALLOCA@
+## end gnulib module alloca
+
+## begin gnulib module alloca-opt
+
+BUILT_SOURCES += $(ALLOCA_H)
+EXTRA_DIST += alloca_.h
+
+# We need the following in order to create <alloca.h> when the system
+# doesn't have one that works with the given compiler.
+alloca.h: alloca_.h
+ cp $(srcdir)/alloca_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += alloca.h alloca.h-t
+
+## end gnulib module alloca-opt
+
+## begin gnulib module allocsa
+
+libgnu_a_SOURCES += allocsa.h allocsa.c
+EXTRA_DIST += allocsa.valgrind
+
+## end gnulib module allocsa
+
+## begin gnulib module cycle-check
+
+libgnu_a_SOURCES += cycle-check.c cycle-check.h dev-ino.h
+
+## end gnulib module cycle-check
+
+## begin gnulib module dirname
+
+libgnu_a_SOURCES += basename.c stripslash.c
+
+## end gnulib module dirname
+
+## begin gnulib module exit
+
+libgnu_a_SOURCES += exit.h
+
+## end gnulib module exit
+
+## begin gnulib module fnmatch
+
+BUILT_SOURCES += $(FNMATCH_H)
+EXTRA_DIST += fnmatch_.h fnmatch_loop.c
+
+# We need the following in order to create <fnmatch.h> when the system
+# doesn't have one that supports the required API.
+fnmatch.h: fnmatch_.h
+ cp $(srcdir)/fnmatch_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += fnmatch.h fnmatch.h-t
+
+## end gnulib module fnmatch
+
+## begin gnulib module getaddrinfo
+
+libgnu_a_SOURCES += getaddrinfo.h
+
+## end gnulib module getaddrinfo
+
+## begin gnulib module getdate
+
+BUILT_SOURCES += getdate.c
+MAINTAINERCLEANFILES += getdate.c
+EXTRA_DIST += getdate.c
+
+## end gnulib module getdate
+
+## begin gnulib module getndelim2
+
+EXTRA_DIST += getndelim2.h getndelim2.c
+
+## end gnulib module getndelim2
+
+## begin gnulib module getnline
+
+libgnu_a_SOURCES += getnline.h getnline.c
+
+## end gnulib module getnline
+
+## begin gnulib module getopt
+
+BUILT_SOURCES += $(GETOPT_H)
+EXTRA_DIST += getopt_.h getopt_int.h
+
+# We need the following in order to create <getopt.h> when the system
+# doesn't have one that works with the given compiler.
+getopt.h: getopt_.h
+ cp $(srcdir)/getopt_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += getopt.h getopt.h-t
+
+## end gnulib module getopt
+
+## begin gnulib module gettext-h
+
+libgnu_a_SOURCES += gettext.h
+
+## end gnulib module gettext-h
+
+## begin gnulib module glob
+
+BUILT_SOURCES += $(GLOB_H)
+
+# We need the following in order to create <glob.h> when the system
+# doesn't have one that works with the given compiler.
+glob.h: glob_.h
+ cp $(srcdir)/glob_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += glob.h glob.h-t
+
+## end gnulib module glob
+
+## begin gnulib module mbuiter
+
+libgnu_a_SOURCES += mbuiter.h
+
+## end gnulib module mbuiter
+
+## begin gnulib module minmax
+
+libgnu_a_SOURCES += minmax.h
+
+## end gnulib module minmax
+
+## begin gnulib module setenv
+
+libgnu_a_SOURCES += setenv.h
+
+## end gnulib module setenv
+
+## begin gnulib module size_max
+
+libgnu_a_SOURCES += size_max.h
+
+## end gnulib module size_max
+
+## begin gnulib module stdbool
+
+BUILT_SOURCES += $(STDBOOL_H)
+EXTRA_DIST += stdbool_.h
+
+# We need the following in order to create <stdbool.h> when the system
+# doesn't have one that works.
+stdbool.h: stdbool_.h
+ sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' < $(srcdir)/stdbool_.h > $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += stdbool.h stdbool.h-t
+
+## end gnulib module stdbool
+
+## begin gnulib module stdint
+
+BUILT_SOURCES += $(STDINT_H)
+EXTRA_DIST += stdint_.h
+
+# We need the following in order to create <stdint.h> when the system
+# doesn't have one that works with the given compiler.
+stdint.h: stdint_.h
+ sed -e 's/@''HAVE_LONG_64BIT''@/$(HAVE_LONG_64BIT)/g;s/@''HAVE_LONG_LONG_64BIT@/$(HAVE_LONG_LONG_64BIT)/g' < $(srcdir)/stdint_.h > $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += stdint.h stdint.h-t
+
+## end gnulib module stdint
+
+## begin gnulib module strcase
+
+libgnu_a_SOURCES += strcase.h
+
+## end gnulib module strcase
+
+## begin gnulib module strnlen1
+
+libgnu_a_SOURCES += strnlen1.h strnlen1.c
+
+## end gnulib module strnlen1
+
+## begin gnulib module strstr
+
+libgnu_a_SOURCES += strstr.h
+
+## end gnulib module strstr
+
+## begin gnulib module time_r
+
+libgnu_a_SOURCES += time_r.h
+
+## end gnulib module time_r
+
+## begin gnulib module vasnprintf
+
+libgnu_a_SOURCES += printf-args.h printf-parse.h vasnprintf.h
+
+## end gnulib module vasnprintf
+
+## begin gnulib module vasprintf
+
+libgnu_a_SOURCES += vasprintf.h
+
+## end gnulib module vasprintf
+
+## begin gnulib module xalloc-die
+
+libgnu_a_SOURCES += xalloc-die.c
+
+## end gnulib module xalloc-die
+
+## begin gnulib module xgethostname
+
+libgnu_a_SOURCES += xgethostname.h xgethostname.c
+
+## end gnulib module xgethostname
+
+## begin gnulib module xreadlink
+
+libgnu_a_SOURCES += xreadlink.h xreadlink.c
+
+## end gnulib module xreadlink
+
+## begin gnulib module xsize
+
+libgnu_a_SOURCES += xsize.h
+
+## end gnulib module xsize
+
+
+# Makefile.am ends here
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..1dc29df
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,855 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for library files used by GNU CVS.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = getdate$(EXEEXT)
+subdir = lib
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ ChangeLog __fpending.c __fpending.h alloca.c asnprintf.c \
+ asprintf.c atexit.c canon-host.c canon-host.h canonicalize.c \
+ canonicalize.h chdir-long.c chdir-long.h closeout.c closeout.h \
+ dirname.c dirname.h dup-safer.c dup2.c exitfail.c exitfail.h \
+ fd-safer.c filenamecat.c filenamecat.h fncase.c fnmatch.c \
+ fseeko.c ftello.c ftruncate.c gai_strerror.c getaddrinfo.c \
+ getcwd.c getcwd.h getdate.c getdate.h getdate.y getdelim.c \
+ getdelim.h gethostname.c getline.c getline.h getlogin_r.c \
+ getlogin_r.h getndelim2.c getopt.c getopt1.c getpagesize.h \
+ getpass.c getpass.h gettime.c gettimeofday.c glob-libc.h \
+ glob.c glob_.h lstat.c lstat.h malloc.c mbchar.c mbchar.h \
+ md5.c md5.h memchr.c memmove.c mempcpy.c mempcpy.h memrchr.c \
+ memrchr.h mkdir.c mkstemp.c mktime.c nanosleep.c openat.c \
+ openat.h pagealign_alloc.c pagealign_alloc.h pathmax.h \
+ pipe-safer.c printf-args.c printf-parse.c quotearg.c \
+ quotearg.h readlink.c realloc.c regcomp.c regex.c regex.h \
+ regex_internal.c regex_internal.h regexec.c rename.c rpmatch.c \
+ save-cwd.c save-cwd.h setenv.c stat-macros.h strcasecmp.c \
+ strdup.c strdup.h strerror.c strftime.c strftime.h \
+ strncasecmp.c strstr.c strtol.c strtoul.c sunos57-select.c \
+ tempname.c time_r.c timespec.h unistd--.h unistd-safer.h \
+ unlocked-io.h unsetenv.c vasnprintf.c vasprintf.c waitpid.c \
+ xalloc.h xgetcwd.c xgetcwd.h xmalloc.c yesno.c yesno.h
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+AR = ar
+ARFLAGS = cru
+libcvs_a_AR = $(AR) $(ARFLAGS)
+libcvs_a_DEPENDENCIES = @LIBOBJS@ @ALLOCA@
+am_libcvs_a_OBJECTS = sighandle.$(OBJEXT) allocsa.$(OBJEXT) \
+ cycle-check.$(OBJEXT) basename.$(OBJEXT) stripslash.$(OBJEXT) \
+ getnline.$(OBJEXT) strnlen1.$(OBJEXT) xalloc-die.$(OBJEXT) \
+ xgethostname.$(OBJEXT) xreadlink.$(OBJEXT)
+libcvs_a_OBJECTS = $(am_libcvs_a_OBJECTS)
+am_getdate_OBJECTS = getdate-error.$(OBJEXT) getdate-getdate.$(OBJEXT) \
+ getdate-progname.$(OBJEXT)
+getdate_OBJECTS = $(am_getdate_OBJECTS)
+am__DEPENDENCIES_1 = libcvs.a
+am__DEPENDENCIES_2 =
+getdate_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_2)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS)
+YLWRAP = $(top_srcdir)/build-aux/ylwrap
+SOURCES = $(libcvs_a_SOURCES) $(getdate_SOURCES)
+DIST_SOURCES = $(libcvs_a_SOURCES) $(getdate_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+noinst_LIBRARIES = libcvs.a
+
+# Should look into unifying regular expression matching in CVS
+# with the diff library (perhaps to have the caller, CVS, do the
+# matching?)
+libcvs_a_SOURCES = sighandle.c system.h wait.h xselect.h xtime.h \
+ allocsa.h allocsa.c cycle-check.c cycle-check.h dev-ino.h \
+ basename.c stripslash.c error.h exit.h getaddrinfo.h \
+ getnline.h getnline.c gettext.h mbuiter.h minmax.h setenv.h \
+ size_max.h strcase.h strnlen1.h strnlen1.c strstr.h time_r.h \
+ printf-args.h printf-parse.h vasnprintf.h vasprintf.h \
+ xalloc-die.c xgethostname.h xgethostname.c xreadlink.h \
+ xreadlink.c xsize.h
+libcvs_a_LIBADD = @LIBOBJS@ @ALLOCA@
+BUILT_SOURCES = $(ALLOCA_H) $(FNMATCH_H) getdate.c $(GETOPT_H) \
+ $(GLOB_H) $(STDBOOL_H) $(STDINT_H)
+MOSTLYCLEANFILES = alloca.h alloca.h-t fnmatch.h fnmatch.h-t \
+ getdate-expected getdate-got getdate.diff getopt.h getopt.h-t \
+ glob.h glob.h-t stdbool.h stdbool.h-t stdint.h stdint.h-t
+DISTCLEANFILES = getdate.log
+MAINTAINERCLEANFILES = getdate.c
+TESTS = test-getdate.sh
+EXTRA_DIST = .cvsignore ChangeLog.fsf Makefile.gnulib build_lib.com \
+ libcvs.dep libcvs.dsp libcvs.mak test-getdate.sh alloca_.h \
+ allocsa.valgrind fnmatch_.h fnmatch_loop.c getdate.c \
+ getndelim2.h getndelim2.c getopt_.h getopt_int.h stdbool_.h \
+ stdint_.h
+getdate_SOURCES = error.c getdate.y progname.c
+getdate_CPPFLAGS = -DTEST
+getdate_LDADD = \
+ $(noinst_LIBRARIES) \
+ $(LIB_CLOCK_GETTIME) \
+ $(LIBINTL)
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libcvs.a: $(libcvs_a_OBJECTS) $(libcvs_a_DEPENDENCIES)
+ -rm -f libcvs.a
+ $(libcvs_a_AR) libcvs.a $(libcvs_a_OBJECTS) $(libcvs_a_LIBADD)
+ $(RANLIB) libcvs.a
+
+clean-checkPROGRAMS:
+ -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS)
+getdate$(EXEEXT): $(getdate_OBJECTS) $(getdate_DEPENDENCIES)
+ @rm -f getdate$(EXEEXT)
+ $(LINK) $(getdate_LDFLAGS) $(getdate_OBJECTS) $(getdate_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/__fpending.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/alloca.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asnprintf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asprintf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/atexit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/canon-host.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/canonicalize.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/chdir-long.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/closeout.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/dirname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/dup-safer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/dup2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/exitfail.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fd-safer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/filenamecat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fncase.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fnmatch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fseeko.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ftello.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ftruncate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/gai_strerror.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getaddrinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getcwd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getdate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getdate.y@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getdelim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/gethostname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getline.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getlogin_r.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getndelim2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getopt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getopt1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getpass.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/gettime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/gettimeofday.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/glob.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/lstat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/malloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mbchar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/md5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/memchr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/memmove.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mempcpy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/memrchr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mkdir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mkstemp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mktime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/nanosleep.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/openat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pagealign_alloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pipe-safer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/printf-args.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/printf-parse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/quotearg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/readlink.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/realloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/regcomp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/regex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/regex_internal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/regexec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/rename.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/rpmatch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/save-cwd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/setenv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strcasecmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strdup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strerror.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strftime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strncasecmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strstr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strtol.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strtoul.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/sunos57-select.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/tempname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/time_r.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/unsetenv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/vasnprintf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/vasprintf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/waitpid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/xgetcwd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/xmalloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/yesno.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/allocsa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basename.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cycle-check.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdate-error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdate-getdate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdate-progname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getnline.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sighandle.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stripslash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnlen1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xalloc-die.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xgethostname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xreadlink.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+getdate-error.o: error.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getdate-error.o -MD -MP -MF "$(DEPDIR)/getdate-error.Tpo" -c -o getdate-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/getdate-error.Tpo" "$(DEPDIR)/getdate-error.Po"; else rm -f "$(DEPDIR)/getdate-error.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='error.c' object='getdate-error.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getdate-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c
+
+getdate-error.obj: error.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getdate-error.obj -MD -MP -MF "$(DEPDIR)/getdate-error.Tpo" -c -o getdate-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/getdate-error.Tpo" "$(DEPDIR)/getdate-error.Po"; else rm -f "$(DEPDIR)/getdate-error.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='error.c' object='getdate-error.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getdate-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi`
+
+getdate-getdate.o: getdate.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getdate-getdate.o -MD -MP -MF "$(DEPDIR)/getdate-getdate.Tpo" -c -o getdate-getdate.o `test -f 'getdate.c' || echo '$(srcdir)/'`getdate.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/getdate-getdate.Tpo" "$(DEPDIR)/getdate-getdate.Po"; else rm -f "$(DEPDIR)/getdate-getdate.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='getdate.c' object='getdate-getdate.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getdate-getdate.o `test -f 'getdate.c' || echo '$(srcdir)/'`getdate.c
+
+getdate-getdate.obj: getdate.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getdate-getdate.obj -MD -MP -MF "$(DEPDIR)/getdate-getdate.Tpo" -c -o getdate-getdate.obj `if test -f 'getdate.c'; then $(CYGPATH_W) 'getdate.c'; else $(CYGPATH_W) '$(srcdir)/getdate.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/getdate-getdate.Tpo" "$(DEPDIR)/getdate-getdate.Po"; else rm -f "$(DEPDIR)/getdate-getdate.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='getdate.c' object='getdate-getdate.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getdate-getdate.obj `if test -f 'getdate.c'; then $(CYGPATH_W) 'getdate.c'; else $(CYGPATH_W) '$(srcdir)/getdate.c'; fi`
+
+getdate-progname.o: progname.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getdate-progname.o -MD -MP -MF "$(DEPDIR)/getdate-progname.Tpo" -c -o getdate-progname.o `test -f 'progname.c' || echo '$(srcdir)/'`progname.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/getdate-progname.Tpo" "$(DEPDIR)/getdate-progname.Po"; else rm -f "$(DEPDIR)/getdate-progname.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='progname.c' object='getdate-progname.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getdate-progname.o `test -f 'progname.c' || echo '$(srcdir)/'`progname.c
+
+getdate-progname.obj: progname.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getdate-progname.obj -MD -MP -MF "$(DEPDIR)/getdate-progname.Tpo" -c -o getdate-progname.obj `if test -f 'progname.c'; then $(CYGPATH_W) 'progname.c'; else $(CYGPATH_W) '$(srcdir)/progname.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/getdate-progname.Tpo" "$(DEPDIR)/getdate-progname.Po"; else rm -f "$(DEPDIR)/getdate-progname.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='progname.c' object='getdate-progname.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(getdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getdate-progname.obj `if test -f 'progname.c'; then $(CYGPATH_W) 'progname.c'; else $(CYGPATH_W) '$(srcdir)/progname.c'; fi`
+
+.y.c:
+ $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE)
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list='$(TESTS)'; \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *" $$tst "*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ echo "XPASS: $$tst"; \
+ ;; \
+ *) \
+ echo "PASS: $$tst"; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *" $$tst "*) \
+ xfail=`expr $$xfail + 1`; \
+ echo "XFAIL: $$tst"; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ echo "FAIL: $$tst"; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ echo "SKIP: $$tst"; \
+ fi; \
+ done; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="All $$all tests passed"; \
+ else \
+ banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all tests failed"; \
+ else \
+ banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ skipped="($$skip tests were not run)"; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ test -z "$$skipped" || echo "$$skipped"; \
+ test -z "$$report" || echo "$$report"; \
+ echo "$$dashes"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f getdate.c
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-local distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-checkPROGRAMS clean-generic clean-noinstLIBRARIES ctags \
+ distclean distclean-compile distclean-generic distclean-local \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am
+
+
+# We need the following in order to create <alloca.h> when the system
+# doesn't have one that works with the given compiler.
+alloca.h: alloca_.h
+ cp $(srcdir)/alloca_.h $@-t
+ mv $@-t $@
+
+# We need the following in order to create <fnmatch.h> when the system
+# doesn't have one that supports the required API.
+fnmatch.h: fnmatch_.h
+ cp $(srcdir)/fnmatch_.h $@-t
+ mv $@-t $@
+
+# We need the following in order to create <getopt.h> when the system
+# doesn't have one that works with the given compiler.
+getopt.h: getopt_.h
+ cp $(srcdir)/getopt_.h $@-t
+ mv $@-t $@
+
+# We need the following in order to create an <getopt.h> when the system
+# doesn't have one that works with the given compiler.
+all-local $(libcvs_a_OBJECTS): $(GLOB_H)
+glob.h: glob_.h
+ cp $(srcdir)/glob_.h $@-t
+ mv $@-t $@
+
+# We need the following in order to create <stdbool.h> when the system
+# doesn't have one that works.
+stdbool.h: stdbool_.h
+ sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' \
+ < $(srcdir)/stdbool_.h > $@-t
+ mv $@-t $@
+
+# We need the following in order to create <stdint.h> when the system
+# doesn't have one that works with the given compiler.
+stdint.h: stdint_.h
+ sed -e 's/@''HAVE_LONG_64BIT''@/$(HAVE_LONG_64BIT)/g;s/@''HAVE_LONG_LONG_64BIT@/$(HAVE_LONG_LONG_64BIT)/g' < $(srcdir)/stdint_.h > $@-t
+ mv $@-t $@
+
+# Until Automake gets its act together
+distclean-local:
+ rm -f fnmatch.h
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/README b/lib/README
new file mode 100644
index 0000000..ce1cc7f
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,9 @@
+Many of the source files in this directory come from the GNULIB project
+<http://savannah.gnu.org/projects/gnulib/>/<mailto:bug-gnulib@gnu.org>, and,
+if they don't, they should.
+
+What this means is that there is often at least one corresponding Autoconf
+macro in the CVS/m4 directory and that bug fixes and enhancements to this code
+should be sent to the GNULIB project and then reimported here after the GNULIB
+developers approve and adopt the change. Changes should not be made locally
+without good reason!
diff --git a/lib/__fpending.c b/lib/__fpending.c
new file mode 100644
index 0000000..63fb7d7
--- /dev/null
+++ b/lib/__fpending.c
@@ -0,0 +1,32 @@
+/* __fpending.c -- return the number of pending output bytes on a stream
+ Copyright (C) 2000, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "__fpending.h"
+
+/* Return the number of pending (aka buffered, unflushed)
+ bytes on the stream, FP, that is open for writing. */
+size_t
+__fpending (FILE *fp)
+{
+ return PENDING_OUTPUT_N_BYTES;
+}
diff --git a/lib/__fpending.h b/lib/__fpending.h
new file mode 100644
index 0000000..36a842e
--- /dev/null
+++ b/lib/__fpending.h
@@ -0,0 +1,13 @@
+#include <stddef.h>
+#include <stdio.h>
+
+#if HAVE_STDIO_EXT_H
+# include <stdio_ext.h>
+#endif
+
+#ifndef HAVE_DECL___FPENDING
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL___FPENDING
+size_t __fpending (FILE *);
+#endif
diff --git a/lib/alloca.c b/lib/alloca.c
new file mode 100644
index 0000000..d1d5447
--- /dev/null
+++ b/lib/alloca.c
@@ -0,0 +1,491 @@
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <alloca.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef emacs
+# include "lisp.h"
+# include "blockinput.h"
+# ifdef EMACS_FREE
+# undef free
+# define free EMACS_FREE
+# endif
+#else
+# define memory_full() abort ()
+#endif
+
+/* If compiling with GCC 2, this file's not needed. */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+# ifndef alloca
+
+# ifdef emacs
+# ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+# ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+/* Using #error here is not wise since this file should work for
+ old and obscure compilers. */
+# endif /* STACK_DIRECTION undefined */
+# endif /* static */
+# endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+# if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+# define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+# else
+# define ADDRESS_FUNCTION(arg) &(arg)
+# endif
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+# ifndef STACK_DIRECTION
+# define STACK_DIRECTION 0 /* Direction unknown. */
+# endif
+
+# if STACK_DIRECTION != 0
+
+# define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+# else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+# define STACK_DIR stack_dir
+
+static void
+find_stack_direction (void)
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+# endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+# ifndef ALIGN_SIZE
+# define ALIGN_SIZE sizeof(double)
+# endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+void *
+alloca (size_t size)
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+# if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+# endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+# ifdef emacs
+ BLOCK_INPUT;
+# endif
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free (hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+
+# ifdef emacs
+ UNBLOCK_INPUT;
+# endif
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ /* Address of header. */
+ register header *new;
+
+ size_t combined_size = sizeof (header) + size;
+ if (combined_size < sizeof (header))
+ memory_full ();
+
+ new = malloc (combined_size);
+
+ if (! new)
+ memory_full ();
+
+ new->h.next = last_alloca_header;
+ new->h.deep = depth;
+
+ last_alloca_header = new;
+
+ /* User storage begins just after header. */
+
+ return (void *) (new + 1);
+ }
+}
+
+# if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+# ifdef DEBUG_I00AFUNC
+# include <stdio.h>
+# endif
+
+# ifndef CRAY_STACK
+# define CRAY_STACK
+# ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+# else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+# endif /* CRAY2 */
+# endif /* not CRAY_STACK */
+
+# ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+# else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+# ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+# endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+# ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+# endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+# endif /* not CRAY2 */
+# endif /* CRAY */
+
+# endif /* no alloca */
+#endif /* not GCC version 2 */
diff --git a/lib/alloca_.h b/lib/alloca_.h
new file mode 100644
index 0000000..3e3fdf4
--- /dev/null
+++ b/lib/alloca_.h
@@ -0,0 +1,52 @@
+/* Memory allocation on the stack.
+
+ Copyright (C) 1995, 1999, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H
+ means there is a real alloca function. */
+#ifndef _GNULIB_ALLOCA_H
+# define _GNULIB_ALLOCA_H
+
+/* alloca (N) returns a pointer to N bytes of memory
+ allocated on the stack, which will last until the function returns.
+ Use of alloca should be avoided:
+ - inside arguments of function calls - undefined behaviour,
+ - in inline functions - the allocation may actually last until the
+ calling function returns,
+ - for huge N (say, N >= 65536) - you never know how large (or small)
+ the stack is, and when the stack cannot fulfill the memory allocation
+ request, the program just crashes.
+ */
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#endif /* _GNULIB_ALLOCA_H */
diff --git a/lib/allocsa.c b/lib/allocsa.c
new file mode 100644
index 0000000..a54e2d0
--- /dev/null
+++ b/lib/allocsa.c
@@ -0,0 +1,139 @@
+/* Safe automatic memory allocation.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "allocsa.h"
+
+/* The speed critical point in this file is freesa() applied to an alloca()
+ result: it must be fast, to match the speed of alloca(). The speed of
+ mallocsa() and freesa() in the other case are not critical, because they
+ are only invoked for big memory sizes. */
+
+#if HAVE_ALLOCA
+
+/* Store the mallocsa() results in a hash table. This is needed to reliably
+ distinguish a mallocsa() result and an alloca() result.
+
+ Although it is possible that the same pointer is returned by alloca() and
+ by mallocsa() at different times in the same application, it does not lead
+ to a bug in freesa(), because:
+ - Before a pointer returned by alloca() can point into malloc()ed memory,
+ the function must return, and once this has happened the programmer must
+ not call freesa() on it anyway.
+ - Before a pointer returned by mallocsa() can point into the stack, it
+ must be freed. The only function that can free it is freesa(), and
+ when freesa() frees it, it also removes it from the hash table. */
+
+#define MAGIC_NUMBER 0x1415fb4a
+#define MAGIC_SIZE sizeof (int)
+/* This is how the header info would look like without any alignment
+ considerations. */
+struct preliminary_header { void *next; char room[MAGIC_SIZE]; };
+/* But the header's size must be a multiple of sa_alignment_max. */
+#define HEADER_SIZE \
+ (((sizeof (struct preliminary_header) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max)
+struct header { void *next; char room[HEADER_SIZE - sizeof (struct preliminary_header) + MAGIC_SIZE]; };
+/* Verify that HEADER_SIZE == sizeof (struct header). */
+typedef int verify1[2 * (HEADER_SIZE == sizeof (struct header)) - 1];
+/* We make the hash table quite big, so that during lookups the probability
+ of empty hash buckets is quite high. There is no need to make the hash
+ table resizable, because when the hash table gets filled so much that the
+ lookup becomes slow, it means that the application has memory leaks. */
+#define HASH_TABLE_SIZE 257
+static void * mallocsa_results[HASH_TABLE_SIZE];
+
+#endif
+
+void *
+mallocsa (size_t n)
+{
+#if HAVE_ALLOCA
+ /* Allocate one more word, that serves as an indicator for malloc()ed
+ memory, so that freesa() of an alloca() result is fast. */
+ size_t nplus = n + HEADER_SIZE;
+
+ if (nplus >= n)
+ {
+ char *p = (char *) malloc (nplus);
+
+ if (p != NULL)
+ {
+ size_t slot;
+
+ p += HEADER_SIZE;
+
+ /* Put a magic number into the indicator word. */
+ ((int *) p)[-1] = MAGIC_NUMBER;
+
+ /* Enter p into the hash table. */
+ slot = (unsigned long) p % HASH_TABLE_SIZE;
+ ((struct header *) (p - HEADER_SIZE))->next = mallocsa_results[slot];
+ mallocsa_results[slot] = p;
+
+ return p;
+ }
+ }
+ /* Out of memory. */
+ return NULL;
+#else
+# if !MALLOC_0_IS_NONNULL
+ if (n == 0)
+ n = 1;
+# endif
+ return malloc (n);
+#endif
+}
+
+#if HAVE_ALLOCA
+void
+freesa (void *p)
+{
+ /* mallocsa() may have returned NULL. */
+ if (p != NULL)
+ {
+ /* Attempt to quickly distinguish the mallocsa() result - which has
+ a magic indicator word - and the alloca() result - which has an
+ uninitialized indicator word. It is for this test that sa_increment
+ additional bytes are allocated in the alloca() case. */
+ if (((int *) p)[-1] == MAGIC_NUMBER)
+ {
+ /* Looks like a mallocsa() result. To see whether it really is one,
+ perform a lookup in the hash table. */
+ size_t slot = (unsigned long) p % HASH_TABLE_SIZE;
+ void **chain = &mallocsa_results[slot];
+ for (; *chain != NULL;)
+ {
+ if (*chain == p)
+ {
+ /* Found it. Remove it from the hash table and free it. */
+ char *p_begin = (char *) p - HEADER_SIZE;
+ *chain = ((struct header *) p_begin)->next;
+ free (p_begin);
+ return;
+ }
+ chain = &((struct header *) ((char *) *chain - HEADER_SIZE))->next;
+ }
+ }
+ /* At this point, we know it was not a mallocsa() result. */
+ }
+}
+#endif
diff --git a/lib/allocsa.h b/lib/allocsa.h
new file mode 100644
index 0000000..cb6893a
--- /dev/null
+++ b/lib/allocsa.h
@@ -0,0 +1,113 @@
+/* Safe automatic memory allocation.
+ Copyright (C) 2003-2004 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _ALLOCSA_H
+#define _ALLOCSA_H
+
+#include <alloca.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/* safe_alloca(N) is equivalent to alloca(N) when it is safe to call
+ alloca(N); otherwise it returns NULL. It either returns N bytes of
+ memory allocated on the stack, that lasts until the function returns,
+ or NULL.
+ Use of safe_alloca should be avoided:
+ - inside arguments of function calls - undefined behaviour,
+ - in inline functions - the allocation may actually last until the
+ calling function returns.
+*/
+#if HAVE_ALLOCA
+/* The OS usually guarantees only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ allocate anything larger than 4096 bytes. Also care for the possibility
+ of a few compiler-allocated temporary stack slots.
+ This must be a macro, not an inline function. */
+# define safe_alloca(N) ((N) < 4032 ? alloca (N) : NULL)
+#else
+# define safe_alloca(N) ((N), NULL)
+#endif
+
+/* allocsa(N) is a safe variant of alloca(N). It allocates N bytes of
+ memory allocated on the stack, that must be freed using freesa() before
+ the function returns. Upon failure, it returns NULL. */
+#if HAVE_ALLOCA
+# define allocsa(N) \
+ ((N) < 4032 - sa_increment \
+ ? (void *) ((char *) alloca ((N) + sa_increment) + sa_increment) \
+ : mallocsa (N))
+#else
+# define allocsa(N) \
+ mallocsa (N)
+#endif
+extern void * mallocsa (size_t n);
+
+/* Free a block of memory allocated through allocsa(). */
+#if HAVE_ALLOCA
+extern void freesa (void *p);
+#else
+# define freesa free
+#endif
+
+/* Maybe we should also define a variant
+ nallocsa (size_t n, size_t s) - behaves like allocsa (n * s)
+ If this would be useful in your application. please speak up. */
+
+
+/* ------------------- Auxiliary, non-public definitions ------------------- */
+
+/* Determine the alignment of a type at compile time. */
+#if defined __GNUC__
+# define sa_alignof __alignof__
+#elif defined __cplusplus
+ template <class type> struct sa_alignof_helper { char __slot1; type __slot2; };
+# define sa_alignof(type) offsetof (sa_alignof_helper<type>, __slot2)
+#elif defined __hpux
+ /* Work around a HP-UX 10.20 cc bug with enums constants defined as offsetof
+ values. */
+# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8)
+#else
+# define sa_alignof(type) offsetof (struct { char __slot1; type __slot2; }, __slot2)
+#endif
+
+enum
+{
+/* The desired alignment of memory allocations is the maximum alignment
+ among all elementary types. */
+ sa_alignment_long = sa_alignof (long),
+ sa_alignment_double = sa_alignof (double),
+#ifdef HAVE_LONG_LONG
+ sa_alignment_longlong = sa_alignof (long long),
+#endif
+#ifdef HAVE_LONG_DOUBLE
+ sa_alignment_longdouble = sa_alignof (long double),
+#endif
+ sa_alignment_max = ((sa_alignment_long - 1) | (sa_alignment_double - 1)
+#ifdef HAVE_LONG_LONG
+ | (sa_alignment_longlong - 1)
+#endif
+#ifdef HAVE_LONG_DOUBLE
+ | (sa_alignment_longdouble - 1)
+#endif
+ ) + 1,
+/* The increment that guarantees room for a magic word must be >= sizeof (int)
+ and a multiple of sa_alignment_max. */
+ sa_increment = ((sizeof (int) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max
+};
+
+#endif /* _ALLOCSA_H */
diff --git a/lib/allocsa.valgrind b/lib/allocsa.valgrind
new file mode 100644
index 0000000..f4c77d6
--- /dev/null
+++ b/lib/allocsa.valgrind
@@ -0,0 +1,7 @@
+# Suppress a valgrind message about use of uninitialized memory in freesa().
+# This use is OK because it provides only a speedup.
+{
+ freesa
+ Memcheck:Cond
+ fun:freesa
+}
diff --git a/lib/asnprintf.c b/lib/asnprintf.c
new file mode 100644
index 0000000..1b7f4ba
--- /dev/null
+++ b/lib/asnprintf.c
@@ -0,0 +1,37 @@
+/* Formatted output to strings.
+ Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "vasnprintf.h"
+
+#include <stdarg.h>
+
+char *
+asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+{
+ va_list args;
+ char *result;
+
+ va_start (args, format);
+ result = vasnprintf (resultbuf, lengthp, format, args);
+ va_end (args);
+ return result;
+}
diff --git a/lib/asprintf.c b/lib/asprintf.c
new file mode 100644
index 0000000..7c4e64a
--- /dev/null
+++ b/lib/asprintf.c
@@ -0,0 +1,37 @@
+/* Formatted output to strings.
+ Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "vasprintf.h"
+
+#include <stdarg.h>
+
+int
+asprintf (char **resultp, const char *format, ...)
+{
+ va_list args;
+ int result;
+
+ va_start (args, format);
+ result = vasprintf (resultp, format, args);
+ va_end (args);
+ return result;
+}
diff --git a/lib/atexit.c b/lib/atexit.c
new file mode 100644
index 0000000..f4873c9
--- /dev/null
+++ b/lib/atexit.c
@@ -0,0 +1,15 @@
+/* Wrapper to implement ANSI C's atexit using SunOS's on_exit. */
+/* This function is in the public domain. --Mike Stump. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+int
+atexit (void (*f) (void))
+{
+ /* If the system doesn't provide a definition for atexit, use on_exit
+ if the system provides that. */
+ on_exit (f, 0);
+ return 0;
+}
diff --git a/lib/basename.c b/lib/basename.c
new file mode 100644
index 0000000..5cc97cd
--- /dev/null
+++ b/lib/basename.c
@@ -0,0 +1,79 @@
+/* basename.c -- return the last element in a file name
+
+ Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "dirname.h"
+#include <string.h>
+
+/* In general, we can't use the builtin `basename' function if available,
+ since it has different meanings in different environments.
+ In some environments the builtin `basename' modifies its argument.
+
+ Return the address of the last file name component of NAME. If
+ NAME has no file name components because it is all slashes, return
+ NAME if it is empty, the address of its last slash otherwise. */
+
+char *
+base_name (char const *name)
+{
+ char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
+ char const *p;
+
+ for (p = base; *p; p++)
+ {
+ if (ISSLASH (*p))
+ {
+ /* Treat multiple adjacent slashes like a single slash. */
+ do p++;
+ while (ISSLASH (*p));
+
+ /* If the file name ends in slash, use the trailing slash as
+ the basename if no non-slashes have been found. */
+ if (! *p)
+ {
+ if (ISSLASH (*base))
+ base = p - 1;
+ break;
+ }
+
+ /* *P is a non-slash preceded by a slash. */
+ base = p;
+ }
+ }
+
+ return (char *) base;
+}
+
+/* Return the length of of the basename NAME. Typically NAME is the
+ value returned by base_name. Act like strlen (NAME), except omit
+ redundant trailing slashes. */
+
+size_t
+base_len (char const *name)
+{
+ size_t len;
+
+ for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--)
+ continue;
+
+ return len;
+}
diff --git a/lib/build_lib.com b/lib/build_lib.com
new file mode 100755
index 0000000..2b19926
--- /dev/null
+++ b/lib/build_lib.com
@@ -0,0 +1,20 @@
+$ set verify
+$ CC :== CC/DEBUG/NOOPTIMIZE/STANDARD=VAXC/DEFINE=HAVE_CONFIG_H-
+/INCLUDE_DIRECTORY=([-],[-.LIB],[-.SRC],[-.VMS])/PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
+$ CC fnmatch.c
+$ CC getdate.c
+$ CC getline.c
+$ CC getopt.c
+$ CC getopt1.c
+$ CC md5.c
+$ CC regex.c
+$ CC savecwd.c
+$ CC sighandle.c
+$ CC stripslash.c
+$ CC valloc.c
+$ CC xgetwd.c
+$ CC yesno.c
+$ library/create gnulib.olb fnmatch.obj,getdate.obj,getline.obj,-
+getopt.obj,getopt1.obj,md5.obj,regex.obj,savecwd.obj,sighandle.obj,-
+stripslash.obj,valloc.obj,xgetwd.obj,yesno.obj
+$ set noverify
diff --git a/lib/canon-host.c b/lib/canon-host.c
new file mode 100644
index 0000000..e2bd1a7
--- /dev/null
+++ b/lib/canon-host.c
@@ -0,0 +1,90 @@
+/* Host name canonicalization
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Derek Price <derek@ximbiot.com>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "canon-host.h"
+
+#include "getaddrinfo.h"
+#include "strdup.h"
+
+/* Store the last error for the single-threaded version of this function. */
+static int last_cherror;
+
+/* Single-threaded of wrapper for canon_host_r. After a NULL return, error
+ messages may be retrieved via ch_strerror(). */
+char *
+canon_host (const char *host)
+{
+ return canon_host_r (host, &last_cherror);
+}
+
+/* Return a malloc'd string containing the canonical hostname associated with
+ HOST, or NULL if a canonical name cannot be determined. On NULL return,
+ if CHERROR is not NULL, set *CHERROR to an error code as returned by
+ getaddrinfo(). Use ch_strerror_r() or gai_strerror() to convert a *CHERROR
+ value to a string suitable for error messages.
+
+ WARNINGS
+ HOST must be a string representation of a resolvable name for this host.
+ Strings containing an IP address in dotted decimal notation will be
+ returned as-is, without further resolution.
+
+ The use of the word "canonical" in this context is unfortunate but
+ entrenched. The value returned by this function will be the end result
+ of the resolution of any CNAME chains in the DNS. There may only be one
+ such value for any given hostname, though the actual IP address
+ referenced by this value and the device using that IP address may each
+ actually have any number of such "canonical" hostnames. See the POSIX
+ getaddrinfo spec <http://www.opengroup.org/susv3xsh/getaddrinfo.html">,
+ RFC 1034 <http://www.faqs.org/rfcs/rfc1034.html>, & RFC 2181
+ <http://www.faqs.org/rfcs/rfc2181.html> for more on what this confusing
+ term really refers to. */
+char *
+canon_host_r (char const *host, int *cherror)
+{
+ char *retval = NULL;
+ static struct addrinfo hints;
+ struct addrinfo *res = NULL;
+ int status;
+
+ hints.ai_flags = AI_CANONNAME;
+ status = getaddrinfo (host, NULL, &hints, &res);
+ if (!status)
+ {
+ retval = strdup (res->ai_canonname);
+ if (!retval && cherror)
+ *cherror = EAI_MEMORY;
+ freeaddrinfo (res);
+ }
+ else if (cherror)
+ *cherror = status;
+
+ return retval;
+}
+
+/* Return a string describing the last error encountered by canon_host. */
+const char *
+ch_strerror (void)
+{
+ return gai_strerror (last_cherror);
+}
diff --git a/lib/canon-host.h b/lib/canon-host.h
new file mode 100644
index 0000000..c1f6cb1
--- /dev/null
+++ b/lib/canon-host.h
@@ -0,0 +1,30 @@
+/* Host name canonicalization
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Derek Price <derek@ximbiot.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef CANON_HOST_H
+# define CANON_HOST_H 1
+
+char *canon_host (char const *host);
+char *canon_host_r (char const *host, int *cherror);
+
+const char *ch_strerror (void);
+# define ch_strerror_r(cherror) gai_strerror (cherror);
+
+#endif /* !CANON_HOST_H */
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
new file mode 100644
index 0000000..571fa19
--- /dev/null
+++ b/lib/canonicalize.c
@@ -0,0 +1,318 @@
+/* Return the canonical absolute name of a given file.
+ Copyright (C) 1996-2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "canonicalize.h"
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+#else
+void free ();
+#endif
+
+#if defined STDC_HEADERS || defined HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#include <sys/stat.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <stddef.h>
+
+#include "cycle-check.h"
+#include "filenamecat.h"
+#include "stat-macros.h"
+#include "xalloc.h"
+#include "xgetcwd.h"
+
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#include "pathmax.h"
+#include "xreadlink.h"
+
+#if !HAVE_CANONICALIZE_FILE_NAME
+/* Return the canonical absolute name of file NAME. A canonical name
+ does not contain any `.', `..' components nor any repeated file name
+ separators ('/') or symlinks. All components must exist.
+ The result is malloc'd. */
+
+char *
+canonicalize_file_name (const char *name)
+{
+# if HAVE_RESOLVEPATH
+
+ char *resolved, *extra_buf = NULL;
+ size_t resolved_size;
+ ssize_t resolved_len;
+
+ if (name == NULL)
+ {
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ __set_errno (ENOENT);
+ return NULL;
+ }
+
+ /* All known hosts with resolvepath (e.g. Solaris 7) don't turn
+ relative names into absolute ones, so prepend the working
+ directory if the file name is not absolute. */
+ if (name[0] != '/')
+ {
+ char *wd;
+
+ if (!(wd = xgetcwd ()))
+ return NULL;
+
+ extra_buf = file_name_concat (wd, name, NULL);
+ name = extra_buf;
+ free (wd);
+ }
+
+ resolved_size = strlen (name);
+ while (1)
+ {
+ resolved_size = 2 * resolved_size + 1;
+ resolved = xmalloc (resolved_size);
+ resolved_len = resolvepath (name, resolved, resolved_size);
+ if (resolved_len < 0)
+ {
+ free (resolved);
+ free (extra_buf);
+ return NULL;
+ }
+ if (resolved_len < resolved_size)
+ break;
+ free (resolved);
+ }
+
+ free (extra_buf);
+
+ /* NUL-terminate the resulting name. */
+ resolved[resolved_len] = '\0';
+
+ return resolved;
+
+# else
+
+ return canonicalize_filename_mode (name, CAN_EXISTING);
+
+# endif /* !HAVE_RESOLVEPATH */
+}
+#endif /* !HAVE_CANONICALIZE_FILE_NAME */
+
+/* Return the canonical absolute name of file NAME. A canonical name
+ does not contain any `.', `..' components nor any repeated file name
+ separators ('/') or symlinks. Whether components must exist
+ or not depends on canonicalize mode. The result is malloc'd. */
+
+char *
+canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
+{
+ char *rname, *dest, *extra_buf = NULL;
+ char const *start;
+ char const *end;
+ char const *rname_limit;
+ size_t extra_len = 0;
+ struct cycle_check_state cycle_state;
+
+ if (name == NULL)
+ {
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ __set_errno (ENOENT);
+ return NULL;
+ }
+
+ if (name[0] != '/')
+ {
+ rname = xgetcwd ();
+ if (!rname)
+ return NULL;
+ dest = strchr (rname, '\0');
+ if (dest - rname < PATH_MAX)
+ {
+ char *p = xrealloc (rname, PATH_MAX);
+ dest = p + (dest - rname);
+ rname = p;
+ rname_limit = rname + PATH_MAX;
+ }
+ else
+ {
+ rname_limit = dest;
+ }
+ }
+ else
+ {
+ rname = xmalloc (PATH_MAX);
+ rname_limit = rname + PATH_MAX;
+ rname[0] = '/';
+ dest = rname + 1;
+ }
+
+ cycle_check_init (&cycle_state);
+ for (start = end = name; *start; start = end)
+ {
+ /* Skip sequence of multiple file name separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rname + 1)
+ while ((--dest)[-1] != '/');
+ }
+ else
+ {
+ struct stat st;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rname_limit)
+ {
+ ptrdiff_t dest_offset = dest - rname;
+ size_t new_size = rname_limit - rname;
+
+ if (end - start + 1 > PATH_MAX)
+ new_size += end - start + 1;
+ else
+ new_size += PATH_MAX;
+ rname = xrealloc (rname, new_size);
+ rname_limit = rname + new_size;
+
+ dest = rname + dest_offset;
+ }
+
+ dest = memcpy (dest, start, end - start);
+ dest += end - start;
+ *dest = '\0';
+
+ if (lstat (rname, &st) != 0)
+ {
+ if (can_mode == CAN_EXISTING)
+ goto error;
+ if (can_mode == CAN_ALL_BUT_LAST && *end)
+ goto error;
+ st.st_mode = 0;
+ }
+
+ if (S_ISLNK (st.st_mode))
+ {
+ char *buf;
+ size_t n, len;
+
+ if (cycle_check (&cycle_state, &st))
+ {
+ __set_errno (ELOOP);
+ if (can_mode == CAN_MISSING)
+ continue;
+ else
+ goto error;
+ }
+
+ buf = xreadlink (rname, st.st_size);
+ if (!buf)
+ {
+ if (can_mode == CAN_MISSING)
+ continue;
+ else
+ goto error;
+ }
+
+ n = strlen (buf);
+ len = strlen (end);
+
+ if (!extra_len)
+ {
+ extra_len =
+ ((n + len + 1) > PATH_MAX) ? (n + len + 1) : PATH_MAX;
+ extra_buf = xmalloc (extra_len);
+ }
+ else if ((n + len + 1) > extra_len)
+ {
+ extra_len = n + len + 1;
+ extra_buf = xrealloc (extra_buf, extra_len);
+ }
+
+ /* Careful here, end may be a pointer into extra_buf... */
+ memmove (&extra_buf[n], end, len + 1);
+ name = end = memcpy (extra_buf, buf, n);
+
+ if (buf[0] == '/')
+ dest = rname + 1; /* It's an absolute symlink */
+ else
+ /* Back up to previous component, ignore if at root already: */
+ if (dest > rname + 1)
+ while ((--dest)[-1] != '/');
+
+ free (buf);
+ }
+ else
+ {
+ if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
+ {
+ errno = ENOTDIR;
+ goto error;
+ }
+ }
+ }
+ }
+ if (dest > rname + 1 && dest[-1] == '/')
+ --dest;
+ *dest = '\0';
+
+ free (extra_buf);
+ return rname;
+
+error:
+ free (extra_buf);
+ free (rname);
+ return NULL;
+}
diff --git a/lib/canonicalize.h b/lib/canonicalize.h
new file mode 100644
index 0000000..4cae3c5
--- /dev/null
+++ b/lib/canonicalize.h
@@ -0,0 +1,41 @@
+/* Return the canonical absolute name of a given file.
+ Copyright (C) 1996-2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef CANONICALIZE_H_
+# define CANONICALIZE_H_
+
+enum canonicalize_mode_t
+ {
+ /* All components must exist. */
+ CAN_EXISTING = 0,
+
+ /* All components excluding last one must exist. */
+ CAN_ALL_BUT_LAST = 1,
+
+ /* No requirements on components existence. */
+ CAN_MISSING = 2
+ };
+typedef enum canonicalize_mode_t canonicalize_mode_t;
+
+char *canonicalize_filename_mode (const char *, canonicalize_mode_t);
+
+# if !HAVE_CANONICALIZE_FILE_NAME
+char *canonicalize_file_name (const char *);
+# endif
+
+#endif /* !CANONICALIZE_H_ */
diff --git a/lib/chdir-long.c b/lib/chdir-long.c
new file mode 100644
index 0000000..a727817
--- /dev/null
+++ b/lib/chdir-long.c
@@ -0,0 +1,276 @@
+/* provide a chdir function that tries not to fail due to ENAMETOOLONG
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "chdir-long.h"
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+#include "memrchr.h"
+#include "openat.h"
+
+#ifndef O_DIRECTORY
+# define O_DIRECTORY 0
+#endif
+
+#ifndef PATH_MAX
+# error "compile this file only if your system defines PATH_MAX"
+#endif
+
+struct cd_buf
+{
+ int fd;
+};
+
+static inline void
+cdb_init (struct cd_buf *cdb)
+{
+ cdb->fd = AT_FDCWD;
+}
+
+static inline int
+cdb_fchdir (struct cd_buf const *cdb)
+{
+ return fchdir (cdb->fd);
+}
+
+static inline void
+cdb_free (struct cd_buf const *cdb)
+{
+ if (0 <= cdb->fd)
+ {
+ bool close_fail = close (cdb->fd);
+ assert (! close_fail);
+ }
+}
+
+/* Given a file descriptor of an open directory (or AT_FDCWD), CDB->fd,
+ try to open the CDB->fd-relative directory, DIR. If the open succeeds,
+ update CDB->fd with the resulting descriptor, close the incoming file
+ descriptor, and return zero. Upon failure, return -1 and set errno. */
+static int
+cdb_advance_fd (struct cd_buf *cdb, char const *dir)
+{
+ int new_fd = openat (cdb->fd, dir, O_RDONLY | O_DIRECTORY);
+ if (new_fd < 0)
+ {
+ new_fd = openat (cdb->fd, dir, O_WRONLY | O_DIRECTORY);
+ if (new_fd < 0)
+ return -1;
+ }
+
+ cdb_free (cdb);
+ cdb->fd = new_fd;
+
+ return 0;
+}
+
+/* Return a pointer to the first non-slash in S. */
+static inline char *
+find_non_slash (char const *s)
+{
+ size_t n_slash = strspn (s, "/");
+ return (char *) s + n_slash;
+}
+
+/* This is a function much like chdir, but without the PATH_MAX limitation
+ on the length of the directory name. A significant difference is that
+ it must be able to modify (albeit only temporarily) the directory
+ name. It handles an arbitrarily long directory name by operating
+ on manageable portions of the name. On systems without the openat
+ syscall, this means changing the working directory to more and more
+ `distant' points along the long directory name and then restoring
+ the working directory. If any of those attempts to save or restore
+ the working directory fails, this function exits nonzero.
+
+ Note that this function may still fail with errno == ENAMETOOLONG, but
+ only if the specified directory name contains a component that is long
+ enough to provoke such a failure all by itself (e.g. if the component
+ has length PATH_MAX or greater on systems that define PATH_MAX). */
+
+int
+chdir_long (char *dir)
+{
+ int e = chdir (dir);
+ if (e == 0 || errno != ENAMETOOLONG)
+ return e;
+
+ {
+ size_t len = strlen (dir);
+ char *dir_end = dir + len;
+ struct cd_buf cdb;
+ size_t n_leading_slash;
+
+ cdb_init (&cdb);
+
+ /* If DIR is the empty string, then the chdir above
+ must have failed and set errno to ENOENT. */
+ assert (0 < len);
+ assert (PATH_MAX <= len);
+
+ /* Count leading slashes. */
+ n_leading_slash = strspn (dir, "/");
+
+ /* Handle any leading slashes as well as any name that matches
+ the regular expression, m!^//hostname[/]*! . Handling this
+ prefix separately usually results in a single additional
+ cdb_advance_fd call, but it's worthwhile, since it makes the
+ code in the following loop cleaner. */
+ if (n_leading_slash == 2)
+ {
+ int err;
+ /* Find next slash.
+ We already know that dir[2] is neither a slash nor '\0'. */
+ char *slash = memchr (dir + 3, '/', dir_end - (dir + 3));
+ if (slash == NULL)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ *slash = '\0';
+ err = cdb_advance_fd (&cdb, dir);
+ *slash = '/';
+ if (err != 0)
+ goto Fail;
+ dir = find_non_slash (slash + 1);
+ }
+ else if (n_leading_slash)
+ {
+ if (cdb_advance_fd (&cdb, "/") != 0)
+ goto Fail;
+ dir += n_leading_slash;
+ }
+
+ assert (*dir != '/');
+ assert (dir <= dir_end);
+
+ while (PATH_MAX <= dir_end - dir)
+ {
+ int err;
+ /* Find a slash that is PATH_MAX or fewer bytes away from dir.
+ I.e. see if there is a slash that will give us a name of
+ length PATH_MAX-1 or less. */
+ char *slash = memrchr (dir, '/', PATH_MAX);
+ if (slash == NULL)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ *slash = '\0';
+ assert (slash - dir < PATH_MAX);
+ err = cdb_advance_fd (&cdb, dir);
+ *slash = '/';
+ if (err != 0)
+ goto Fail;
+
+ dir = find_non_slash (slash + 1);
+ }
+
+ if (dir < dir_end)
+ {
+ if (cdb_advance_fd (&cdb, dir) != 0)
+ goto Fail;
+ }
+
+ if (cdb_fchdir (&cdb) != 0)
+ goto Fail;
+
+ cdb_free (&cdb);
+ return 0;
+
+ Fail:
+ {
+ int saved_errno = errno;
+ cdb_free (&cdb);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+}
+
+#if TEST_CHDIR
+
+# include <stdio.h>
+# include "closeout.h"
+# include "error.h"
+
+char *program_name;
+
+int
+main (int argc, char *argv[])
+{
+ char *line = NULL;
+ size_t n = 0;
+ int len;
+
+ program_name = argv[0];
+ atexit (close_stdout);
+
+ len = getline (&line, &n, stdin);
+ if (len < 0)
+ {
+ int saved_errno = errno;
+ if (feof (stdin))
+ exit (0);
+
+ error (EXIT_FAILURE, saved_errno,
+ "reading standard input");
+ }
+ else if (len == 0)
+ exit (0);
+
+ if (line[len-1] == '\n')
+ line[len-1] = '\0';
+
+ if (chdir_long (line) != 0)
+ error (EXIT_FAILURE, errno,
+ "chdir_long failed: %s", line);
+
+ if (argc <= 1)
+ {
+ /* Using `pwd' here makes sense only if it is a robust implementation,
+ like the one in coreutils after the 2004-04-19 changes. */
+ char const *cmd = "pwd";
+ execlp (cmd, (char *) NULL);
+ error (EXIT_FAILURE, errno, "%s", cmd);
+ }
+
+ fclose (stdin);
+ fclose (stderr);
+
+ exit (EXIT_SUCCESS);
+}
+#endif
+
+/*
+Local Variables:
+compile-command: "gcc -DTEST_CHDIR=1 -DHAVE_CONFIG_H -I.. -g -O -W -Wall chdir-long.c libcoreutils.a"
+End:
+*/
diff --git a/lib/chdir-long.h b/lib/chdir-long.h
new file mode 100644
index 0000000..4852b40
--- /dev/null
+++ b/lib/chdir-long.h
@@ -0,0 +1,35 @@
+/* provide a chdir function that tries not to fail due to ENAMETOOLONG
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#include <unistd.h>
+#include <limits.h>
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# endif
+#endif
+
+/* On systems without PATH_MAX, presume that chdir accepts
+ arbitrarily long directory names. */
+#ifndef PATH_MAX
+# define chdir_long(Dir) chdir (Dir)
+#else
+int chdir_long (char *dir);
+#endif
diff --git a/lib/closeout.c b/lib/closeout.c
new file mode 100644
index 0000000..5d0509d
--- /dev/null
+++ b/lib/closeout.c
@@ -0,0 +1,101 @@
+/* closeout.c - close standard output
+
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "closeout.h"
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+#include "error.h"
+#include "exitfail.h"
+#include "quotearg.h"
+#include "__fpending.h"
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+static const char *file_name;
+
+/* Set the file name to be reported in the event an error is detected
+ by close_stdout. */
+void
+close_stdout_set_file_name (const char *file)
+{
+ file_name = file;
+}
+
+/* Close standard output, exiting with status 'exit_failure' on failure.
+ If a program writes *anything* to stdout, that program should close
+ stdout and make sure that it succeeds before exiting. Otherwise,
+ suppose that you go to the extreme of checking the return status
+ of every function that does an explicit write to stdout. The last
+ printf can succeed in writing to the internal stream buffer, and yet
+ the fclose(stdout) could still fail (due e.g., to a disk full error)
+ when it tries to write out that buffered data. Thus, you would be
+ left with an incomplete output file and the offending program would
+ exit successfully. Even calling fflush is not always sufficient,
+ since some file systems (NFS and CODA) buffer written/flushed data
+ until an actual close call.
+
+ Besides, it's wasteful to check the return value from every call
+ that writes to stdout -- just let the internal stream state record
+ the failure. That's what the ferror test is checking below.
+
+ It's important to detect such failures and exit nonzero because many
+ tools (most notably `make' and other build-management systems) depend
+ on being able to detect failure in other tools via their exit status. */
+
+void
+close_stdout (void)
+{
+ bool prev_fail = ferror (stdout);
+ bool none_pending = (0 == __fpending (stdout));
+ bool fclose_fail = fclose (stdout);
+
+ if (prev_fail || fclose_fail)
+ {
+ int e = fclose_fail ? errno : 0;
+ char const *write_error;
+
+ /* If ferror returned zero, no data remains to be flushed, and we'd
+ otherwise fail with EBADF due to a failed fclose, then assume that
+ it's ok to ignore the fclose failure. That can happen when a
+ program like cp is invoked like this `cp a b >&-' (i.e., with
+ stdout closed) and doesn't generate any output (hence no previous
+ error and nothing to be flushed). */
+ if (e == EBADF && !prev_fail && none_pending)
+ return;
+
+ write_error = _("write error");
+ if (file_name)
+ error (exit_failure, e, "%s: %s", quotearg_colon (file_name),
+ write_error);
+ else
+ error (exit_failure, e, "%s", write_error);
+ }
+}
diff --git a/lib/closeout.h b/lib/closeout.h
new file mode 100644
index 0000000..589a14f
--- /dev/null
+++ b/lib/closeout.h
@@ -0,0 +1,33 @@
+/* Close standard output.
+
+ Copyright (C) 1998, 2000, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef CLOSEOUT_H
+# define CLOSEOUT_H 1
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+void close_stdout_set_file_name (const char *file);
+void close_stdout (void);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/lib/cycle-check.c b/lib/cycle-check.c
new file mode 100644
index 0000000..401dd86
--- /dev/null
+++ b/lib/cycle-check.c
@@ -0,0 +1,93 @@
+/* help detect directory cycles efficiently
+
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <stdbool.h>
+
+#include "cycle-check.h"
+
+#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
+ ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
+ && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
+
+#define CC_MAGIC 9827862
+
+/* Return true if I is a power of 2, or is zero. */
+
+static inline bool
+is_zero_or_power_of_two (uintmax_t i)
+{
+ return (i & (i - 1)) == 0;
+}
+
+void
+cycle_check_init (struct cycle_check_state *state)
+{
+ state->chdir_counter = 0;
+ state->magic = CC_MAGIC;
+}
+
+/* In traversing a directory hierarchy, call this function once for each
+ descending chdir call, with SB corresponding to the chdir operand.
+ If SB corresponds to a directory that has already been seen,
+ return true to indicate that there is a directory cycle.
+ Note that this is done `lazily', which means that some of
+ the directories in the cycle may be processed twice before
+ the cycle is detected. */
+
+bool
+cycle_check (struct cycle_check_state *state, struct stat const *sb)
+{
+ assert (state->magic == CC_MAGIC);
+
+ /* If the current directory ever happens to be the same
+ as the one we last recorded for the cycle detection,
+ then it's obviously part of a cycle. */
+ if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino))
+ return true;
+
+ /* If the number of `descending' chdir calls is a power of two,
+ record the dev/ino of the current directory. */
+ if (is_zero_or_power_of_two (++(state->chdir_counter)))
+ {
+ /* On all architectures that we know about, if the counter
+ overflows then there is a directory cycle here somewhere,
+ even if we haven't detected it yet. Typically this happens
+ only after the counter is incremented 2**64 times, so it's a
+ fairly theoretical point. */
+ if (state->chdir_counter == 0)
+ return true;
+
+ state->dev_ino.st_dev = sb->st_dev;
+ state->dev_ino.st_ino = sb->st_ino;
+ }
+
+ return false;
+}
diff --git a/lib/cycle-check.h b/lib/cycle-check.h
new file mode 100644
index 0000000..0551bf2
--- /dev/null
+++ b/lib/cycle-check.h
@@ -0,0 +1,44 @@
+/* help detect directory cycles efficiently
+
+ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering */
+
+#ifndef CYCLE_CHECK_H
+# define CYCLE_CHECK_H 1
+
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# endif
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+# include <stdbool.h>
+# include "dev-ino.h"
+
+struct cycle_check_state
+{
+ struct dev_ino dev_ino;
+ uintmax_t chdir_counter;
+ int magic;
+};
+
+void cycle_check_init (struct cycle_check_state *state);
+bool cycle_check (struct cycle_check_state *state, struct stat const *sb);
+
+#endif
diff --git a/lib/dev-ino.h b/lib/dev-ino.h
new file mode 100644
index 0000000..695d38c
--- /dev/null
+++ b/lib/dev-ino.h
@@ -0,0 +1,13 @@
+#ifndef DEV_INO_H
+# define DEV_INO_H 1
+
+# include <sys/types.h>
+# include <sys/stat.h>
+
+struct dev_ino
+{
+ ino_t st_ino;
+ dev_t st_dev;
+};
+
+#endif
diff --git a/lib/dirname.c b/lib/dirname.c
new file mode 100644
index 0000000..e2b9d64
--- /dev/null
+++ b/lib/dirname.c
@@ -0,0 +1,121 @@
+/* dirname.c -- return all but the last element in a file name
+
+ Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "dirname.h"
+
+#include <string.h>
+#include "xalloc.h"
+
+/* Return the length of `dirname (FILE)', or zero if FILE is
+ in the working directory. Works properly even if
+ there are trailing slashes (by effectively ignoring them). */
+size_t
+dir_len (char const *file)
+{
+ size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file);
+ size_t length;
+
+ /* Strip the basename and any redundant slashes before it. */
+ for (length = base_name (file) - file; prefix_length < length; length--)
+ if (! ISSLASH (file[length - 1]))
+ return length;
+
+ /* But don't strip the only slash from "/". */
+ return prefix_length + ISSLASH (file[prefix_length]);
+}
+
+/* Return the leading directories part of FILE,
+ allocated with xmalloc.
+ Works properly even if there are trailing slashes
+ (by effectively ignoring them). */
+
+char *
+dir_name (char const *file)
+{
+ size_t length = dir_len (file);
+ bool append_dot = (length == FILE_SYSTEM_PREFIX_LEN (file));
+ char *dir = xmalloc (length + append_dot + 1);
+ memcpy (dir, file, length);
+ if (append_dot)
+ dir[length++] = '.';
+ dir[length] = 0;
+ return dir;
+}
+
+#ifdef TEST_DIRNAME
+/*
+
+Run the test like this (expect no output):
+ gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall \
+ basename.c dirname.c xmalloc.c error.c
+ sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out
+
+If it's been built on a DOS or Windows platforms, run another test like
+this (again, expect no output):
+ sed -n '/^BEGIN-DOS-DATA$/,/^END-DOS-DATA$/p' dirname.c|grep -v DATA|./a.out
+
+BEGIN-DATA
+foo//// .
+bar/foo//// bar
+foo/ .
+/ /
+. .
+a .
+END-DATA
+
+BEGIN-DOS-DATA
+c:///// c:/
+c:/ c:/
+c:/. c:/
+c:foo c:.
+c:foo/bar c:foo
+END-DOS-DATA
+
+*/
+
+# define MAX_BUFF_LEN 1024
+# include <stdio.h>
+
+char *program_name;
+
+int
+main (int argc, char *argv[])
+{
+ char buff[MAX_BUFF_LEN + 1];
+
+ program_name = argv[0];
+
+ buff[MAX_BUFF_LEN] = 0;
+ while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
+ {
+ char file[MAX_BUFF_LEN];
+ char expected_result[MAX_BUFF_LEN];
+ char const *result;
+ sscanf (buff, "%s %s", file, expected_result);
+ result = dir_name (file);
+ if (strcmp (result, expected_result))
+ printf ("%s: got %s, expected %s\n", file, result, expected_result);
+ }
+ return 0;
+}
+#endif
diff --git a/lib/dirname.h b/lib/dirname.h
new file mode 100644
index 0000000..1688ae8
--- /dev/null
+++ b/lib/dirname.h
@@ -0,0 +1,47 @@
+/* Take file names apart into directory and base names.
+
+ Copyright (C) 1998, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef DIRNAME_H_
+# define DIRNAME_H_ 1
+
+# include <stdbool.h>
+# include <stddef.h>
+
+# ifndef DIRECTORY_SEPARATOR
+# define DIRECTORY_SEPARATOR '/'
+# endif
+
+# ifndef ISSLASH
+# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
+# endif
+
+# ifndef FILE_SYSTEM_PREFIX_LEN
+# define FILE_SYSTEM_PREFIX_LEN(File_name) 0
+# endif
+
+# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)])
+# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F))
+
+char *base_name (char const *file);
+char *dir_name (char const *file);
+size_t base_len (char const *file);
+size_t dir_len (char const *file);
+
+bool strip_trailing_slashes (char *file);
+
+#endif /* not DIRNAME_H_ */
diff --git a/lib/dup-safer.c b/lib/dup-safer.c
new file mode 100644
index 0000000..8cbee70
--- /dev/null
+++ b/lib/dup-safer.c
@@ -0,0 +1,46 @@
+/* Invoke dup, but avoid some glitches.
+ Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unistd-safer.h"
+
+#include <fcntl.h>
+
+#include <unistd.h>
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif
+
+/* Like dup, but do not return STDIN_FILENO, STDOUT_FILENO, or
+ STDERR_FILENO. */
+
+int
+dup_safer (int fd)
+{
+#ifdef F_DUPFD
+ return fcntl (fd, F_DUPFD, STDERR_FILENO + 1);
+#else
+ /* fd_safer calls us back, but eventually the recursion unwinds and
+ does the right thing. */
+ return fd_safer (dup (fd));
+#endif
+}
diff --git a/lib/dup2.c b/lib/dup2.c
new file mode 100644
index 0000000..d934da1
--- /dev/null
+++ b/lib/dup2.c
@@ -0,0 +1,61 @@
+/* Duplicate an open file descriptor to a specified file descriptor.
+ Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Paul Eggert */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <fcntl.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef F_DUPFD
+static int
+dupfd (int fd, int desired_fd)
+{
+ int duplicated_fd = dup (fd);
+ if (duplicated_fd < 0 || duplicated_fd == desired_fd)
+ return duplicated_fd;
+ else
+ {
+ int r = dupfd (fd, desired_fd);
+ int e = errno;
+ close (duplicated_fd);
+ errno = e;
+ return r;
+ }
+}
+#endif
+
+int
+dup2 (int fd, int desired_fd)
+{
+ if (fd == desired_fd)
+ return fd;
+ close (desired_fd);
+#ifdef F_DUPFD
+ return fcntl (fd, F_DUPFD, desired_fd);
+#else
+ return dupfd (fd, desired_fd);
+#endif
+}
diff --git a/lib/error.c b/lib/error.c
new file mode 100644
index 0000000..45698be
--- /dev/null
+++ b/lib/error.c
@@ -0,0 +1,304 @@
+/* Error handler for noninteractive utilities
+ Copyright (C) 1990-1998, 2000-2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "error.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !_LIBC && ENABLE_NLS
+# include "gettext.h"
+#endif
+
+#ifdef _LIBC
+# include <wchar.h>
+# define mbsrtowcs __mbsrtowcs
+#endif
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+#ifndef _
+# define _(String) String
+#endif
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+void (*error_print_progname) (void);
+
+/* This variable is incremented each time `error' is called. */
+unsigned int error_message_count;
+
+#ifdef _LIBC
+/* In the GNU C library, there is a predefined variable for this. */
+
+# define program_name program_invocation_name
+# include <errno.h>
+# include <libio/libioP.h>
+
+/* In GNU libc we want do not want to use the common name `error' directly.
+ Instead make it a weak alias. */
+extern void __error (int status, int errnum, const char *message, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+extern void __error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message,
+ ...)
+ __attribute__ ((__format__ (__printf__, 5, 6)));;
+# define error __error
+# define error_at_line __error_at_line
+
+# include <libio/iolibio.h>
+# define fflush(s) INTUSE(_IO_fflush) (s)
+# undef putc
+# define putc(c, fp) INTUSE(_IO_putc) (c, fp)
+
+# include <bits/libc-lock.h>
+
+#else /* not _LIBC */
+
+# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
+# ifndef HAVE_DECL_STRERROR_R
+"this configure-time declaration test was not run"
+# endif
+char *strerror_r ();
+# endif
+
+# ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+# endif
+
+/* The calling program should define program_name and set it to the
+ name of the executing program. */
+extern char *program_name;
+
+# if HAVE_STRERROR_R || defined strerror_r
+# define __strerror_r strerror_r
+# endif
+#endif /* not _LIBC */
+
+static void
+print_errno_message (int errnum)
+{
+ char const *s = NULL;
+
+#if defined HAVE_STRERROR_R || _LIBC
+ char errbuf[1024];
+# if STRERROR_R_CHAR_P || _LIBC
+ s = __strerror_r (errnum, errbuf, sizeof errbuf);
+# else
+ if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
+ s = errbuf;
+# endif
+#endif
+
+#if !_LIBC
+ if (! s && ! (s = strerror (errnum)))
+ s = _("Unknown system error");
+#endif
+
+#if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ {
+ __fwprintf (stderr, L": %s", s);
+ return;
+ }
+#endif
+
+ fprintf (stderr, ": %s", s);
+}
+
+static void
+error_tail (int status, int errnum, const char *message, va_list args)
+{
+#if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ {
+# define ALLOCA_LIMIT 2000
+ size_t len = strlen (message) + 1;
+ const wchar_t *wmessage = L"out of memory";
+ wchar_t *wbuf = (len < ALLOCA_LIMIT
+ ? alloca (len * sizeof *wbuf)
+ : len <= SIZE_MAX / sizeof *wbuf
+ ? malloc (len * sizeof *wbuf)
+ : NULL);
+
+ if (wbuf)
+ {
+ size_t res;
+ mbstate_t st;
+ const char *tmp = message;
+ memset (&st, '\0', sizeof (st));
+ res = mbsrtowcs (wbuf, &tmp, len, &st);
+ wmessage = res == (size_t) -1 ? L"???" : wbuf;
+ }
+
+ __vfwprintf (stderr, wmessage, args);
+ if (! (len < ALLOCA_LIMIT))
+ free (wbuf);
+ }
+ else
+#endif
+ vfprintf (stderr, message, args);
+ va_end (args);
+
+ ++error_message_count;
+ if (errnum)
+ print_errno_message (errnum);
+#if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ putwc (L'\n', stderr);
+ else
+#endif
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
+
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+void
+error (int status, int errnum, const char *message, ...)
+{
+ va_list args;
+
+#if defined _LIBC && defined __libc_ptf_call
+ /* We do not want this call to be cut short by a thread
+ cancellation. Therefore disable cancellation for now. */
+ int state = PTHREAD_CANCEL_ENABLE;
+ __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
+ 0);
+#endif
+
+ fflush (stdout);
+#ifdef _LIBC
+ _IO_flockfile (stderr);
+#endif
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+#if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s: ", program_name);
+ else
+#endif
+ fprintf (stderr, "%s: ", program_name);
+ }
+
+ va_start (args, message);
+ error_tail (status, errnum, message, args);
+
+#ifdef _LIBC
+ _IO_funlockfile (stderr);
+# ifdef __libc_ptf_call
+ __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+# endif
+#endif
+}
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+int error_one_per_line;
+
+void
+error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message, ...)
+{
+ va_list args;
+
+ if (error_one_per_line)
+ {
+ static const char *old_file_name;
+ static unsigned int old_line_number;
+
+ if (old_line_number == line_number
+ && (file_name == old_file_name
+ || strcmp (old_file_name, file_name) == 0))
+ /* Simply return and print nothing. */
+ return;
+
+ old_file_name = file_name;
+ old_line_number = line_number;
+ }
+
+#if defined _LIBC && defined __libc_ptf_call
+ /* We do not want this call to be cut short by a thread
+ cancellation. Therefore disable cancellation for now. */
+ int state = PTHREAD_CANCEL_ENABLE;
+ __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
+ 0);
+#endif
+
+ fflush (stdout);
+#ifdef _LIBC
+ _IO_flockfile (stderr);
+#endif
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+#if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s: ", program_name);
+ else
+#endif
+ fprintf (stderr, "%s:", program_name);
+ }
+
+ if (file_name != NULL)
+ {
+#if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s:%d: ", file_name, line_number);
+ else
+#endif
+ fprintf (stderr, "%s:%d: ", file_name, line_number);
+ }
+
+ va_start (args, message);
+ error_tail (status, errnum, message, args);
+
+#ifdef _LIBC
+ _IO_funlockfile (stderr);
+# ifdef __libc_ptf_call
+ __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+# endif
+#endif
+}
+
+#ifdef _LIBC
+/* Make the weak alias. */
+# undef error
+# undef error_at_line
+weak_alias (__error, error)
+weak_alias (__error_at_line, error_at_line)
+#endif
diff --git a/lib/error.h b/lib/error.h
new file mode 100644
index 0000000..e5220a2
--- /dev/null
+++ b/lib/error.h
@@ -0,0 +1,66 @@
+/* Declaration for error-reporting function
+ Copyright (C) 1995, 1996, 1997, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _ERROR_H
+#define _ERROR_H 1
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Print a message with `fprintf (stderr, FORMAT, ...)';
+ if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
+ If STATUS is nonzero, terminate the program with `exit (STATUS)'. */
+
+extern void error (int __status, int __errnum, const char *__format, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+extern void error_at_line (int __status, int __errnum, const char *__fname,
+ unsigned int __lineno, const char *__format, ...)
+ __attribute__ ((__format__ (__printf__, 5, 6)));
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+extern void (*error_print_progname) (void);
+
+/* This variable is incremented each time `error' is called. */
+extern unsigned int error_message_count;
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+extern int error_one_per_line;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* error.h */
diff --git a/lib/exit.h b/lib/exit.h
new file mode 100644
index 0000000..9dbfb7c
--- /dev/null
+++ b/lib/exit.h
@@ -0,0 +1,32 @@
+/* exit() function.
+ Copyright (C) 1995, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _EXIT_H
+#define _EXIT_H
+
+/* Get exit() declaration. */
+#include <stdlib.h>
+
+/* Some systems do not define EXIT_*, even with STDC_HEADERS. */
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#endif /* _EXIT_H */
diff --git a/lib/exitfail.c b/lib/exitfail.c
new file mode 100644
index 0000000..27d38c3
--- /dev/null
+++ b/lib/exitfail.c
@@ -0,0 +1,27 @@
+/* Failure exit status
+
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "exitfail.h"
+#include "exit.h"
+
+int volatile exit_failure = EXIT_FAILURE;
diff --git a/lib/exitfail.h b/lib/exitfail.h
new file mode 100644
index 0000000..e46cf9c
--- /dev/null
+++ b/lib/exitfail.h
@@ -0,0 +1,20 @@
+/* Failure exit status
+
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+extern int volatile exit_failure;
diff --git a/lib/fd-safer.c b/lib/fd-safer.c
new file mode 100644
index 0000000..5933bcb
--- /dev/null
+++ b/lib/fd-safer.c
@@ -0,0 +1,59 @@
+/* Return a safer copy of a file descriptor.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unistd-safer.h"
+
+#include <errno.h>
+
+#include <unistd.h>
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif
+
+/* Return FD, unless FD would be a copy of standard input, output, or
+ error; in that case, return a duplicate of FD, closing FD. On
+ failure to duplicate, close FD, set errno, and return -1. Preserve
+ errno if FD is negative, so that the caller can always inspect
+ errno when the returned value is negative.
+
+ This function is usefully wrapped around functions that return file
+ descriptors, e.g., fd_safer (open ("file", O_RDONLY)). */
+
+int
+fd_safer (int fd)
+{
+ if (STDIN_FILENO <= fd && fd <= STDERR_FILENO)
+ {
+ int f = dup_safer (fd);
+ int e = errno;
+ close (fd);
+ errno = e;
+ fd = f;
+ }
+
+ return fd;
+}
diff --git a/lib/filenamecat.c b/lib/filenamecat.c
new file mode 100644
index 0000000..f947346
--- /dev/null
+++ b/lib/filenamecat.c
@@ -0,0 +1,126 @@
+/* Concatenate two arbitrary file names.
+
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "filenamecat.h"
+
+#include <string.h>
+
+#include "dirname.h"
+#include "xalloc.h"
+
+#if ! HAVE_MEMPCPY && ! defined mempcpy
+# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
+#endif
+
+/* Return the longest suffix of F that is a relative file name.
+ If it has no such suffix, return the empty string. */
+
+static char const *
+longest_relative_suffix (char const *f)
+{
+ for (f += FILE_SYSTEM_PREFIX_LEN (f); ISSLASH (*f); f++)
+ continue;
+ return f;
+}
+
+/* Concatenate two file name components, DIR and ABASE, in
+ newly-allocated storage and return the result.
+ The resulting file name F is such that the commands "ls F" and "(cd
+ DIR; ls BASE)" refer to the same file, where BASE is ABASE with any
+ file system prefixes and leading separators removed.
+ Arrange for a directory separator if necessary between DIR and BASE
+ in the result, removing any redundant separators.
+ In any case, if BASE_IN_RESULT is non-NULL, set
+ *BASE_IN_RESULT to point to the copy of ABASE in the returned
+ concatenation. However, if ABASE begins with more than one slash,
+ set *BASE_IN_RESULT to point to the sole corresponding slash that
+ is copied into the result buffer.
+
+ Report an error if memory is exhausted. */
+
+char *
+file_name_concat (char const *dir, char const *abase, char **base_in_result)
+{
+ char const *dirbase = base_name (dir);
+ size_t dirbaselen = base_len (dirbase);
+ size_t dirlen = dirbase - dir + dirbaselen;
+ size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1]));
+
+ char const *base = longest_relative_suffix (abase);
+ size_t baselen = strlen (base);
+
+ char *p_concat = xmalloc (dirlen + needs_separator + baselen + 1);
+ char *p;
+
+ p = mempcpy (p_concat, dir, dirlen);
+ *p = DIRECTORY_SEPARATOR;
+ p += needs_separator;
+
+ if (base_in_result)
+ *base_in_result = p - IS_ABSOLUTE_FILE_NAME (abase);
+
+ p = mempcpy (p, base, baselen);
+ *p = '\0';
+
+ return p_concat;
+}
+
+#ifdef TEST_FILE_NAME_CONCAT
+# include <stdlib.h>
+# include <stdio.h>
+int
+main ()
+{
+ static char const *const tests[][3] =
+ {
+ {"a", "b", "a/b"},
+ {"a/", "b", "a/b"},
+ {"a/", "/b", "a/b"},
+ {"a", "/b", "a/b"},
+
+ {"/", "b", "/b"},
+ {"/", "/b", "/b"},
+ {"/", "/", "/"},
+ {"a", "/", "a/"}, /* this might deserve a diagnostic */
+ {"/a", "/", "/a/"}, /* this might deserve a diagnostic */
+ {"a", "//b", "a/b"},
+ };
+ size_t i;
+ bool fail = false;
+ for (i = 0; i < sizeof tests / sizeof tests[0]; i++)
+ {
+ char *base_in_result;
+ char const *const *t = tests[i];
+ char *res = file_name_concat (t[0], t[1], &base_in_result);
+ if (strcmp (res, t[2]) != 0)
+ {
+ printf ("got %s, expected %s\n", res, t[2]);
+ fail = true;
+ }
+ }
+ exit (fail ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+#endif
diff --git a/lib/filenamecat.h b/lib/filenamecat.h
new file mode 100644
index 0000000..c943b67
--- /dev/null
+++ b/lib/filenamecat.h
@@ -0,0 +1,22 @@
+/* Concatenate two arbitrary file names.
+
+ Copyright (C) 1996, 1997, 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+char *file_name_concat (char const *dir, char const *base,
+ char **base_in_result);
diff --git a/lib/fncase.c b/lib/fncase.c
new file mode 100644
index 0000000..2842428
--- /dev/null
+++ b/lib/fncase.c
@@ -0,0 +1,155 @@
+/* fncase.c -- CVS support for case insensitive file systems.
+ Jim Blandy <jimb@cyclic.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "system.h"
+
+/* The equivalence class mapping for filenames.
+ Windows NT filenames are case-insensitive, but case-preserving.
+ Both / and \ are path element separators.
+ Thus, this table maps both upper and lower case to lower case, and
+ both / and \ to /. */
+
+#if 0
+main ()
+{
+ int c;
+
+ for (c = 0; c < 256; c++)
+ {
+ int t;
+
+ if (c == '\\')
+ t = '/';
+ else
+ t = tolower (c);
+
+ if ((c & 0x7) == 0x0)
+ printf (" ");
+ printf ("0x%02x,", t);
+ if ((c & 0x7) == 0x7)
+ putchar ('\n');
+ else if ((c & 0x7) == 0x3)
+ putchar (' ');
+ }
+}
+#endif
+
+/* Under Windows NT, filenames are case-insensitive but case-preserving,
+ and both \ and / are path element separators. */
+unsigned char
+WNT_filename_classes[] =
+{
+ 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
+ 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
+ 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
+ 0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
+ 0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
+ 0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
+ 0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
+ 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
+};
+
+/* Same as WNT_filename_classes, but do not fold `\' into `/'. */
+unsigned char
+OSX_filename_classes[] =
+{
+ 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
+ 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x5b, 0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
+ 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
+ 0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
+ 0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
+ 0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
+ 0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
+ 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
+};
+
+/* Like strcmp, but with the appropriate tweaks for file names.
+ Under Windows NT, filenames are case-insensitive but case-preserving,
+ and both \ and / are path element separators. Under Mac OS X, filenames
+ are case-insensitive but case-preserving. */
+int
+fncmp (const char *n1, const char *n2)
+{
+ while (*n1 && *n2
+ && (FOLD_FN_CHAR(*n1)
+ == FOLD_FN_CHAR(*n2)))
+ n1++, n2++;
+ return (FOLD_FN_CHAR(*n1) - FOLD_FN_CHAR(*n2));
+}
+
+/* Fold characters in FILENAME to their canonical forms.
+ If FOLD_FN_CHAR is not #defined, the system provides a default
+ definition for this. */
+void
+fnfold (char *filename)
+{
+ while (*filename)
+ {
+ *filename = FOLD_FN_CHAR (*filename);
+ filename++;
+ }
+}
diff --git a/lib/fnmatch.c b/lib/fnmatch.c
new file mode 100644
index 0000000..06416f6
--- /dev/null
+++ b/lib/fnmatch.c
@@ -0,0 +1,383 @@
+/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Enable GNU extensions in fnmatch.h. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#if ! defined __builtin_expect && __GNUC__ < 3
+# define __builtin_expect(expr, expected) (expr)
+#endif
+
+#include <fnmatch.h>
+
+#include <alloca.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define WIDE_CHAR_SUPPORT \
+ (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC \
+ && HAVE_WMEMCHR && (HAVE_WMEMCPY || HAVE_WMEMPCPY))
+
+/* For platform which support the ISO C amendement 1 functionality we
+ support user defined character classes. */
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+/* We need some of the locale data (the collation sequence information)
+ but there is no interface to get this information in general. Therefore
+ we support a correct implementation only in glibc. */
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# include "../locale/elem-hash.h"
+# include "../locale/coll-lookup.h"
+# include <shlib-compat.h>
+
+# define CONCAT(a,b) __CONCAT(a,b)
+# define mbsrtowcs __mbsrtowcs
+# define fnmatch __fnmatch
+extern int fnmatch (const char *pattern, const char *string, int flags);
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */
+#define NO_LEADING_PERIOD(flags) \
+ ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself, and have not detected a bug
+ in the library. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined _LIBC || !defined __GNU_LIBRARY__ || !HAVE_FNMATCH_GNU
+
+
+# if defined STDC_HEADERS || !defined isascii
+# define ISASCII(c) 1
+# else
+# define ISASCII(c) isascii(c)
+# endif
+
+# ifdef isblank
+# define ISBLANK(c) (ISASCII (c) && isblank (c))
+# else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+# endif
+# ifdef isgraph
+# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+# else
+# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+# endif
+
+# define ISPRINT(c) (ISASCII (c) && isprint (c))
+# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+# define ISALNUM(c) (ISASCII (c) && isalnum (c))
+# define ISALPHA(c) (ISASCII (c) && isalpha (c))
+# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+# define ISLOWER(c) (ISASCII (c) && islower (c))
+# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+# define ISSPACE(c) (ISASCII (c) && isspace (c))
+# define ISUPPER(c) (ISASCII (c) && isupper (c))
+# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+# if defined _LIBC || WIDE_CHAR_SUPPORT
+/* The GNU C library provides support for user-defined character classes
+ and the functions from ISO C amendement 1. */
+# ifdef CHARCLASS_NAME_MAX
+# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+# else
+/* This shouldn't happen but some implementation might still have this
+ problem. Use a reasonable default value. */
+# define CHAR_CLASS_MAX_LENGTH 256
+# endif
+
+# ifdef _LIBC
+# define IS_CHAR_CLASS(string) __wctype (string)
+# else
+# define IS_CHAR_CLASS(string) wctype (string)
+# endif
+
+# ifdef _LIBC
+# define ISWCTYPE(WC, WT) __iswctype (WC, WT)
+# else
+# define ISWCTYPE(WC, WT) iswctype (WC, WT)
+# endif
+
+# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
+/* In this case we are implementing the multibyte character handling. */
+# define HANDLE_MULTIBYTE 1
+# endif
+
+# else
+# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
+
+# define IS_CHAR_CLASS(string) \
+ (STREQ (string, "alpha") || STREQ (string, "upper") \
+ || STREQ (string, "lower") || STREQ (string, "digit") \
+ || STREQ (string, "alnum") || STREQ (string, "xdigit") \
+ || STREQ (string, "space") || STREQ (string, "print") \
+ || STREQ (string, "punct") || STREQ (string, "graph") \
+ || STREQ (string, "cntrl") || STREQ (string, "blank"))
+# endif
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+/* Global variable. */
+static int posixly_correct;
+
+# ifndef internal_function
+/* Inside GNU libc we mark some function in a special way. In other
+ environments simply ignore the marking. */
+# define internal_function
+# endif
+
+/* Note that this evaluates C many times. */
+# ifdef _LIBC
+# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
+# else
+# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+# endif
+# define CHAR char
+# define UCHAR unsigned char
+# define INT int
+# define FCT internal_fnmatch
+# define EXT ext_match
+# define END end_pattern
+# define L(CS) CS
+# ifdef _LIBC
+# define BTOWC(C) __btowc (C)
+# else
+# define BTOWC(C) btowc (C)
+# endif
+# define STRLEN(S) strlen (S)
+# define STRCAT(D, S) strcat (D, S)
+# ifdef _LIBC
+# define MEMPCPY(D, S, N) __mempcpy (D, S, N)
+# else
+# if HAVE_MEMPCPY
+# define MEMPCPY(D, S, N) mempcpy (D, S, N)
+# else
+# define MEMPCPY(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
+# endif
+# endif
+# define MEMCHR(S, C, N) memchr (S, C, N)
+# define STRCOLL(S1, S2) strcoll (S1, S2)
+# include "fnmatch_loop.c"
+
+
+# if HANDLE_MULTIBYTE
+# define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c))
+# define CHAR wchar_t
+# define UCHAR wint_t
+# define INT wint_t
+# define FCT internal_fnwmatch
+# define EXT ext_wmatch
+# define END end_wpattern
+# define L(CS) L##CS
+# define BTOWC(C) (C)
+# ifdef _LIBC
+# define STRLEN(S) __wcslen (S)
+# define STRCAT(D, S) __wcscat (D, S)
+# define MEMPCPY(D, S, N) __wmempcpy (D, S, N)
+# else
+# define STRLEN(S) wcslen (S)
+# define STRCAT(D, S) wcscat (D, S)
+# if HAVE_WMEMPCPY
+# define MEMPCPY(D, S, N) wmempcpy (D, S, N)
+# else
+# define MEMPCPY(D, S, N) (wmemcpy (D, S, N) + (N))
+# endif
+# endif
+# define MEMCHR(S, C, N) wmemchr (S, C, N)
+# define STRCOLL(S1, S2) wcscoll (S1, S2)
+# define WIDE_CHAR_VERSION 1
+
+# undef IS_CHAR_CLASS
+/* We have to convert the wide character string in a multibyte string. But
+ we know that the character class names consist of alphanumeric characters
+ from the portable character set, and since the wide character encoding
+ for a member of the portable character set is the same code point as
+ its single-byte encoding, we can use a simplified method to convert the
+ string to a multibyte character string. */
+static wctype_t
+is_char_class (const wchar_t *wcs)
+{
+ char s[CHAR_CLASS_MAX_LENGTH + 1];
+ char *cp = s;
+
+ do
+ {
+ /* Test for a printable character from the portable character set. */
+# ifdef _LIBC
+ if (*wcs < 0x20 || *wcs > 0x7e
+ || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
+ return (wctype_t) 0;
+# else
+ switch (*wcs)
+ {
+ case L' ': case L'!': case L'"': case L'#': case L'%':
+ case L'&': case L'\'': case L'(': case L')': case L'*':
+ case L'+': case L',': case L'-': case L'.': case L'/':
+ case L'0': case L'1': case L'2': case L'3': case L'4':
+ case L'5': case L'6': case L'7': case L'8': case L'9':
+ case L':': case L';': case L'<': case L'=': case L'>':
+ case L'?':
+ case L'A': case L'B': case L'C': case L'D': case L'E':
+ case L'F': case L'G': case L'H': case L'I': case L'J':
+ case L'K': case L'L': case L'M': case L'N': case L'O':
+ case L'P': case L'Q': case L'R': case L'S': case L'T':
+ case L'U': case L'V': case L'W': case L'X': case L'Y':
+ case L'Z':
+ case L'[': case L'\\': case L']': case L'^': case L'_':
+ case L'a': case L'b': case L'c': case L'd': case L'e':
+ case L'f': case L'g': case L'h': case L'i': case L'j':
+ case L'k': case L'l': case L'm': case L'n': case L'o':
+ case L'p': case L'q': case L'r': case L's': case L't':
+ case L'u': case L'v': case L'w': case L'x': case L'y':
+ case L'z': case L'{': case L'|': case L'}': case L'~':
+ break;
+ default:
+ return (wctype_t) 0;
+ }
+# endif
+
+ /* Avoid overrunning the buffer. */
+ if (cp == s + CHAR_CLASS_MAX_LENGTH)
+ return (wctype_t) 0;
+
+ *cp++ = (char) *wcs++;
+ }
+ while (*wcs != L'\0');
+
+ *cp = '\0';
+
+# ifdef _LIBC
+ return __wctype (s);
+# else
+ return wctype (s);
+# endif
+}
+# define IS_CHAR_CLASS(string) is_char_class (string)
+
+# include "fnmatch_loop.c"
+# endif
+
+
+int
+fnmatch (const char *pattern, const char *string, int flags)
+{
+# if HANDLE_MULTIBYTE
+# define ALLOCA_LIMIT 2000
+ if (__builtin_expect (MB_CUR_MAX, 1) != 1)
+ {
+ mbstate_t ps;
+ size_t patsize;
+ size_t strsize;
+ size_t totsize;
+ wchar_t *wpattern;
+ wchar_t *wstring;
+ int res;
+
+ /* Calculate the size needed to convert the strings to
+ wide characters. */
+ memset (&ps, '\0', sizeof (ps));
+ patsize = mbsrtowcs (NULL, &pattern, 0, &ps) + 1;
+ if (__builtin_expect (patsize != 0, 1))
+ {
+ assert (mbsinit (&ps));
+ strsize = mbsrtowcs (NULL, &string, 0, &ps) + 1;
+ if (__builtin_expect (strsize != 0, 1))
+ {
+ assert (mbsinit (&ps));
+ totsize = patsize + strsize;
+ if (__builtin_expect (! (patsize <= totsize
+ && totsize <= SIZE_MAX / sizeof (wchar_t)),
+ 0))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* Allocate room for the wide characters. */
+ if (__builtin_expect (totsize < ALLOCA_LIMIT, 1))
+ wpattern = (wchar_t *) alloca (totsize * sizeof (wchar_t));
+ else
+ {
+ wpattern = malloc (totsize * sizeof (wchar_t));
+ if (__builtin_expect (! wpattern, 0))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ wstring = wpattern + patsize;
+
+ /* Convert the strings into wide characters. */
+ mbsrtowcs (wpattern, &pattern, patsize, &ps);
+ assert (mbsinit (&ps));
+ mbsrtowcs (wstring, &string, strsize, &ps);
+
+ res = internal_fnwmatch (wpattern, wstring, wstring + strsize - 1,
+ flags & FNM_PERIOD, flags);
+
+ if (__builtin_expect (! (totsize < ALLOCA_LIMIT), 0))
+ free (wpattern);
+ return res;
+ }
+ }
+ }
+
+# endif /* HANDLE_MULTIBYTE */
+
+ return internal_fnmatch (pattern, string, string + strlen (string),
+ flags & FNM_PERIOD, flags);
+}
+
+# ifdef _LIBC
+# undef fnmatch
+versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
+# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
+strong_alias (__fnmatch, __fnmatch_old)
+compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
+# endif
+libc_hidden_ver (__fnmatch, fnmatch)
+# endif
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/lib/fnmatch_.h b/lib/fnmatch_.h
new file mode 100644
index 0000000..fecada5
--- /dev/null
+++ b/lib/fnmatch_.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999, 2001, 2002, 2003,
+ 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _FNMATCH_H
+# define _FNMATCH_H 1
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* We #undef these before defining them because some losing systems
+ (HP-UX A.08.07 for example) define these in <unistd.h>. */
+# undef FNM_PATHNAME
+# undef FNM_NOESCAPE
+# undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+# define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+# define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
+# define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
+
+# if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
+# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+# define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */
+# endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+# define FNM_NOMATCH 1
+
+/* This value is returned if the implementation does not support
+ `fnmatch'. Since this is not the case here it will never be
+ returned but the conformance test suites still require the symbol
+ to be defined. */
+# ifdef _XOPEN_SOURCE
+# define FNM_NOSYS (-1)
+# endif
+
+/* Match NAME against the file name pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+extern int fnmatch (const char *__pattern, const char *__name,
+ int __flags);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* fnmatch.h */
diff --git a/lib/fnmatch_loop.c b/lib/fnmatch_loop.c
new file mode 100644
index 0000000..35d5980
--- /dev/null
+++ b/lib/fnmatch_loop.c
@@ -0,0 +1,1192 @@
+/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Match STRING against the file name pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+static int EXT (INT opt, const CHAR *pattern, const CHAR *string,
+ const CHAR *string_end, bool no_leading_period, int flags)
+ internal_function;
+static const CHAR *END (const CHAR *patternp) internal_function;
+
+static int
+internal_function
+FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
+ bool no_leading_period, int flags)
+{
+ register const CHAR *p = pattern, *n = string;
+ register UCHAR c;
+#ifdef _LIBC
+# if WIDE_CHAR_VERSION
+ const char *collseq = (const char *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+# else
+ const UCHAR *collseq = (const UCHAR *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+# endif
+#endif
+
+ while ((c = *p++) != L('\0'))
+ {
+ bool new_no_leading_period = false;
+ c = FOLD (c);
+
+ switch (c)
+ {
+ case L('?'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period,
+ flags);
+ if (res != -1)
+ return res;
+ }
+
+ if (n == string_end)
+ return FNM_NOMATCH;
+ else if (*n == L('/') && (flags & FNM_FILE_NAME))
+ return FNM_NOMATCH;
+ else if (*n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+ break;
+
+ case L('\\'):
+ if (!(flags & FNM_NOESCAPE))
+ {
+ c = *p++;
+ if (c == L('\0'))
+ /* Trailing \ loses. */
+ return FNM_NOMATCH;
+ c = FOLD (c);
+ }
+ if (n == string_end || FOLD ((UCHAR) *n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case L('*'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period,
+ flags);
+ if (res != -1)
+ return res;
+ }
+
+ if (n != string_end && *n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == L('?') || c == L('*'); c = *p++)
+ {
+ if (*p == L('(') && (flags & FNM_EXTMATCH) != 0)
+ {
+ const CHAR *endp = END (p);
+ if (endp != p)
+ {
+ /* This is a pattern. Skip over it. */
+ p = endp;
+ continue;
+ }
+ }
+
+ if (c == L('?'))
+ {
+ /* A ? needs to match one character. */
+ if (n == string_end)
+ /* There isn't another character; no match. */
+ return FNM_NOMATCH;
+ else if (*n == L('/')
+ && __builtin_expect (flags & FNM_FILE_NAME, 0))
+ /* A slash does not match a wildcard under
+ FNM_FILE_NAME. */
+ return FNM_NOMATCH;
+ else
+ /* One character of the string is consumed in matching
+ this ? wildcard, so *??? won't match if there are
+ less than three characters. */
+ ++n;
+ }
+ }
+
+ if (c == L('\0'))
+ /* The wildcard(s) is/are the last element of the pattern.
+ If the name is a file name and contains another slash
+ this means it cannot match, unless the FNM_LEADING_DIR
+ flag is set. */
+ {
+ int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
+
+ if (flags & FNM_FILE_NAME)
+ {
+ if (flags & FNM_LEADING_DIR)
+ result = 0;
+ else
+ {
+ if (MEMCHR (n, L('/'), string_end - n) == NULL)
+ result = 0;
+ }
+ }
+
+ return result;
+ }
+ else
+ {
+ const CHAR *endp;
+
+ endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'),
+ string_end - n);
+ if (endp == NULL)
+ endp = string_end;
+
+ if (c == L('[')
+ || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0
+ && (c == L('@') || c == L('+') || c == L('!'))
+ && *p == L('(')))
+ {
+ int flags2 = ((flags & FNM_FILE_NAME)
+ ? flags : (flags & ~FNM_PERIOD));
+ bool no_leading_period2 = no_leading_period;
+
+ for (--p; n < endp; ++n, no_leading_period2 = false)
+ if (FCT (p, n, string_end, no_leading_period2, flags2)
+ == 0)
+ return 0;
+ }
+ else if (c == L('/') && (flags & FNM_FILE_NAME))
+ {
+ while (n < string_end && *n != L('/'))
+ ++n;
+ if (n < string_end && *n == L('/')
+ && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags)
+ == 0))
+ return 0;
+ }
+ else
+ {
+ int flags2 = ((flags & FNM_FILE_NAME)
+ ? flags : (flags & ~FNM_PERIOD));
+ int no_leading_period2 = no_leading_period;
+
+ if (c == L('\\') && !(flags & FNM_NOESCAPE))
+ c = *p;
+ c = FOLD (c);
+ for (--p; n < endp; ++n, no_leading_period2 = false)
+ if (FOLD ((UCHAR) *n) == c
+ && (FCT (p, n, string_end, no_leading_period2, flags2)
+ == 0))
+ return 0;
+ }
+ }
+
+ /* If we come here no match is possible with the wildcard. */
+ return FNM_NOMATCH;
+
+ case L('['):
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register bool not;
+ CHAR cold;
+ UCHAR fn;
+
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ if (n == string_end)
+ return FNM_NOMATCH;
+
+ if (*n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+
+ if (*n == L('/') && (flags & FNM_FILE_NAME))
+ /* `/' cannot be matched. */
+ return FNM_NOMATCH;
+
+ not = (*p == L('!') || (posixly_correct < 0 && *p == L('^')));
+ if (not)
+ ++p;
+
+ fn = FOLD ((UCHAR) *n);
+
+ c = *p++;
+ for (;;)
+ {
+ if (!(flags & FNM_NOESCAPE) && c == L('\\'))
+ {
+ if (*p == L('\0'))
+ return FNM_NOMATCH;
+ c = FOLD ((UCHAR) *p);
+ ++p;
+
+ if (c == fn)
+ goto matched;
+ }
+ else if (c == L('[') && *p == L(':'))
+ {
+ /* Leave room for the null. */
+ CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
+ size_t c1 = 0;
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+ wctype_t wt;
+#endif
+ const CHAR *startp = p;
+
+ for (;;)
+ {
+ if (c1 == CHAR_CLASS_MAX_LENGTH)
+ /* The name is too long and therefore the pattern
+ is ill-formed. */
+ return FNM_NOMATCH;
+
+ c = *++p;
+ if (c == L(':') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c < L('a') || c >= L('z'))
+ {
+ /* This cannot possibly be a character class name.
+ Match it as a normal range. */
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ str[c1++] = c;
+ }
+ str[c1] = L('\0');
+
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+ wt = IS_CHAR_CLASS (str);
+ if (wt == 0)
+ /* Invalid character class name. */
+ return FNM_NOMATCH;
+
+# if defined _LIBC && ! WIDE_CHAR_VERSION
+ /* The following code is glibc specific but does
+ there a good job in speeding up the code since
+ we can avoid the btowc() call. */
+ if (_ISCTYPE ((UCHAR) *n, wt))
+ goto matched;
+# else
+ if (ISWCTYPE (BTOWC ((UCHAR) *n), wt))
+ goto matched;
+# endif
+#else
+ if ((STREQ (str, L("alnum")) && ISALNUM ((UCHAR) *n))
+ || (STREQ (str, L("alpha")) && ISALPHA ((UCHAR) *n))
+ || (STREQ (str, L("blank")) && ISBLANK ((UCHAR) *n))
+ || (STREQ (str, L("cntrl")) && ISCNTRL ((UCHAR) *n))
+ || (STREQ (str, L("digit")) && ISDIGIT ((UCHAR) *n))
+ || (STREQ (str, L("graph")) && ISGRAPH ((UCHAR) *n))
+ || (STREQ (str, L("lower")) && ISLOWER ((UCHAR) *n))
+ || (STREQ (str, L("print")) && ISPRINT ((UCHAR) *n))
+ || (STREQ (str, L("punct")) && ISPUNCT ((UCHAR) *n))
+ || (STREQ (str, L("space")) && ISSPACE ((UCHAR) *n))
+ || (STREQ (str, L("upper")) && ISUPPER ((UCHAR) *n))
+ || (STREQ (str, L("xdigit")) && ISXDIGIT ((UCHAR) *n)))
+ goto matched;
+#endif
+ c = *p++;
+ }
+#ifdef _LIBC
+ else if (c == L('[') && *p == L('='))
+ {
+ UCHAR str[1];
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+
+ c = *++p;
+ if (c == L('\0'))
+ {
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ str[0] = c;
+
+ c = *++p;
+ if (c != L('=') || p[1] != L(']'))
+ {
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ p += 2;
+
+ if (nrules == 0)
+ {
+ if ((UCHAR) *n == str[0])
+ goto matched;
+ }
+ else
+ {
+ const int32_t *table;
+# if WIDE_CHAR_VERSION
+ const int32_t *weights;
+ const int32_t *extra;
+# else
+ const unsigned char *weights;
+ const unsigned char *extra;
+# endif
+ const int32_t *indirect;
+ int32_t idx;
+ const UCHAR *cp = (const UCHAR *) str;
+
+ /* This #include defines a local function! */
+# if WIDE_CHAR_VERSION
+# include <locale/weightwc.h>
+# else
+# include <locale/weight.h>
+# endif
+
+# if WIDE_CHAR_VERSION
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
+ weights = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
+ extra = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
+# else
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+# endif
+
+ idx = findidx (&cp);
+ if (idx != 0)
+ {
+ /* We found a table entry. Now see whether the
+ character we are currently at has the same
+ equivalance class value. */
+ int len = weights[idx];
+ int32_t idx2;
+ const UCHAR *np = (const UCHAR *) n;
+
+ idx2 = findidx (&np);
+ if (idx2 != 0 && len == weights[idx2])
+ {
+ int cnt = 0;
+
+ while (cnt < len
+ && (weights[idx + 1 + cnt]
+ == weights[idx2 + 1 + cnt]))
+ ++cnt;
+
+ if (cnt == len)
+ goto matched;
+ }
+ }
+ }
+
+ c = *p++;
+ }
+#endif
+ else if (c == L('\0'))
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+ else
+ {
+ bool is_range = false;
+
+#ifdef _LIBC
+ bool is_seqval = false;
+
+ if (c == L('[') && *p == L('.'))
+ {
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+ size_t c1 = 0;
+
+ while (1)
+ {
+ c = *++p;
+ if (c == L('.') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c == '\0')
+ return FNM_NOMATCH;
+ ++c1;
+ }
+
+ /* We have to handling the symbols differently in
+ ranges since then the collation sequence is
+ important. */
+ is_range = *p == L('-') && p[1] != L('\0');
+
+ if (nrules == 0)
+ {
+ /* There are no names defined in the collation
+ data. Therefore we only accept the trivial
+ names consisting of the character itself. */
+ if (c1 != 1)
+ return FNM_NOMATCH;
+
+ if (!is_range && *n == startp[1])
+ goto matched;
+
+ cold = startp[1];
+ c = *p++;
+ }
+ else
+ {
+ int32_t table_size;
+ const int32_t *symb_table;
+# ifdef WIDE_CHAR_VERSION
+ char str[c1];
+ size_t strcnt;
+# else
+# define str (startp + 1)
+# endif
+ const unsigned char *extra;
+ int32_t idx;
+ int32_t elem;
+ int32_t second;
+ int32_t hash;
+
+# ifdef WIDE_CHAR_VERSION
+ /* We have to convert the name to a single-byte
+ string. This is possible since the names
+ consist of ASCII characters and the internal
+ representation is UCS4. */
+ for (strcnt = 0; strcnt < c1; ++strcnt)
+ str[strcnt] = startp[1 + strcnt];
+# endif
+
+ table_size =
+ _NL_CURRENT_WORD (LC_COLLATE,
+ _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+
+ /* Locate the character in the hashing table. */
+ hash = elem_hash (str, c1);
+
+ idx = 0;
+ elem = hash % table_size;
+ second = hash % (table_size - 2);
+ while (symb_table[2 * elem] != 0)
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ && c1 == extra[symb_table[2 * elem + 1]]
+ && memcmp (str,
+ &extra[symb_table[2 * elem + 1]
+ + 1], c1) == 0)
+ {
+ /* Yep, this is the entry. */
+ idx = symb_table[2 * elem + 1];
+ idx += 1 + extra[idx];
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+
+ if (symb_table[2 * elem] != 0)
+ {
+ /* Compare the byte sequence but only if
+ this is not part of a range. */
+# ifdef WIDE_CHAR_VERSION
+ int32_t *wextra;
+
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+
+ wextra = (int32_t *) &extra[idx + 4];
+# endif
+
+ if (! is_range)
+ {
+# ifdef WIDE_CHAR_VERSION
+ for (c1 = 0;
+ (int32_t) c1 < wextra[idx];
+ ++c1)
+ if (n[c1] != wextra[1 + c1])
+ break;
+
+ if ((int32_t) c1 == wextra[idx])
+ goto matched;
+# else
+ for (c1 = 0; c1 < extra[idx]; ++c1)
+ if (n[c1] != extra[1 + c1])
+ break;
+
+ if (c1 == extra[idx])
+ goto matched;
+# endif
+ }
+
+ /* Get the collation sequence value. */
+ is_seqval = true;
+# ifdef WIDE_CHAR_VERSION
+ cold = wextra[1 + wextra[idx]];
+# else
+ /* Adjust for the alignment. */
+ idx += 1 + extra[idx];
+ idx = (idx + 3) & ~4;
+ cold = *((int32_t *) &extra[idx]);
+# endif
+
+ c = *p++;
+ }
+ else if (c1 == 1)
+ {
+ /* No valid character. Match it as a
+ single byte. */
+ if (!is_range && *n == str[0])
+ goto matched;
+
+ cold = str[0];
+ c = *p++;
+ }
+ else
+ return FNM_NOMATCH;
+ }
+ }
+ else
+# undef str
+#endif
+ {
+ c = FOLD (c);
+ normal_bracket:
+
+ /* We have to handling the symbols differently in
+ ranges since then the collation sequence is
+ important. */
+ is_range = (*p == L('-') && p[1] != L('\0')
+ && p[1] != L(']'));
+
+ if (!is_range && c == fn)
+ goto matched;
+
+ cold = c;
+ c = *p++;
+ }
+
+ if (c == L('-') && *p != L(']'))
+ {
+#if _LIBC
+ /* We have to find the collation sequence
+ value for C. Collation sequence is nothing
+ we can regularly access. The sequence
+ value is defined by the order in which the
+ definitions of the collation values for the
+ various characters appear in the source
+ file. A strange concept, nowhere
+ documented. */
+ uint32_t fcollseq;
+ uint32_t lcollseq;
+ UCHAR cend = *p++;
+
+# ifdef WIDE_CHAR_VERSION
+ /* Search in the `names' array for the characters. */
+ fcollseq = __collseq_table_lookup (collseq, fn);
+ if (fcollseq == ~((uint32_t) 0))
+ /* XXX We don't know anything about the character
+ we are supposed to match. This means we are
+ failing. */
+ goto range_not_matched;
+
+ if (is_seqval)
+ lcollseq = cold;
+ else
+ lcollseq = __collseq_table_lookup (collseq, cold);
+# else
+ fcollseq = collseq[fn];
+ lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
+# endif
+
+ is_seqval = false;
+ if (cend == L('[') && *p == L('.'))
+ {
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE,
+ _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+ size_t c1 = 0;
+
+ while (1)
+ {
+ c = *++p;
+ if (c == L('.') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c == '\0')
+ return FNM_NOMATCH;
+ ++c1;
+ }
+
+ if (nrules == 0)
+ {
+ /* There are no names defined in the
+ collation data. Therefore we only
+ accept the trivial names consisting
+ of the character itself. */
+ if (c1 != 1)
+ return FNM_NOMATCH;
+
+ cend = startp[1];
+ }
+ else
+ {
+ int32_t table_size;
+ const int32_t *symb_table;
+# ifdef WIDE_CHAR_VERSION
+ char str[c1];
+ size_t strcnt;
+# else
+# define str (startp + 1)
+# endif
+ const unsigned char *extra;
+ int32_t idx;
+ int32_t elem;
+ int32_t second;
+ int32_t hash;
+
+# ifdef WIDE_CHAR_VERSION
+ /* We have to convert the name to a single-byte
+ string. This is possible since the names
+ consist of ASCII characters and the internal
+ representation is UCS4. */
+ for (strcnt = 0; strcnt < c1; ++strcnt)
+ str[strcnt] = startp[1 + strcnt];
+# endif
+
+ table_size =
+ _NL_CURRENT_WORD (LC_COLLATE,
+ _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+
+ /* Locate the character in the hashing
+ table. */
+ hash = elem_hash (str, c1);
+
+ idx = 0;
+ elem = hash % table_size;
+ second = hash % (table_size - 2);
+ while (symb_table[2 * elem] != 0)
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ && (c1
+ == extra[symb_table[2 * elem + 1]])
+ && memcmp (str,
+ &extra[symb_table[2 * elem + 1]
+ + 1], c1) == 0)
+ {
+ /* Yep, this is the entry. */
+ idx = symb_table[2 * elem + 1];
+ idx += 1 + extra[idx];
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+
+ if (symb_table[2 * elem] != 0)
+ {
+ /* Compare the byte sequence but only if
+ this is not part of a range. */
+# ifdef WIDE_CHAR_VERSION
+ int32_t *wextra;
+
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~4;
+
+ wextra = (int32_t *) &extra[idx + 4];
+# endif
+ /* Get the collation sequence value. */
+ is_seqval = true;
+# ifdef WIDE_CHAR_VERSION
+ cend = wextra[1 + wextra[idx]];
+# else
+ /* Adjust for the alignment. */
+ idx += 1 + extra[idx];
+ idx = (idx + 3) & ~4;
+ cend = *((int32_t *) &extra[idx]);
+# endif
+ }
+ else if (symb_table[2 * elem] != 0 && c1 == 1)
+ {
+ cend = str[0];
+ c = *p++;
+ }
+ else
+ return FNM_NOMATCH;
+ }
+# undef str
+ }
+ else
+ {
+ if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
+ cend = *p++;
+ if (cend == L('\0'))
+ return FNM_NOMATCH;
+ cend = FOLD (cend);
+ }
+
+ /* XXX It is not entirely clear to me how to handle
+ characters which are not mentioned in the
+ collation specification. */
+ if (
+# ifdef WIDE_CHAR_VERSION
+ lcollseq == 0xffffffff ||
+# endif
+ lcollseq <= fcollseq)
+ {
+ /* We have to look at the upper bound. */
+ uint32_t hcollseq;
+
+ if (is_seqval)
+ hcollseq = cend;
+ else
+ {
+# ifdef WIDE_CHAR_VERSION
+ hcollseq =
+ __collseq_table_lookup (collseq, cend);
+ if (hcollseq == ~((uint32_t) 0))
+ {
+ /* Hum, no information about the upper
+ bound. The matching succeeds if the
+ lower bound is matched exactly. */
+ if (lcollseq != fcollseq)
+ goto range_not_matched;
+
+ goto matched;
+ }
+# else
+ hcollseq = collseq[cend];
+# endif
+ }
+
+ if (lcollseq <= hcollseq && fcollseq <= hcollseq)
+ goto matched;
+ }
+# ifdef WIDE_CHAR_VERSION
+ range_not_matched:
+# endif
+#else
+ /* We use a boring value comparison of the character
+ values. This is better than comparing using
+ `strcoll' since the latter would have surprising
+ and sometimes fatal consequences. */
+ UCHAR cend = *p++;
+
+ if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
+ cend = *p++;
+ if (cend == L('\0'))
+ return FNM_NOMATCH;
+
+ /* It is a range. */
+ if (cold <= fn && fn <= cend)
+ goto matched;
+#endif
+
+ c = *p++;
+ }
+ }
+
+ if (c == L(']'))
+ break;
+ }
+
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:
+ /* Skip the rest of the [...] that already matched. */
+ do
+ {
+ ignore_next:
+ c = *p++;
+
+ if (c == L('\0'))
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ if (!(flags & FNM_NOESCAPE) && c == L('\\'))
+ {
+ if (*p == L('\0'))
+ return FNM_NOMATCH;
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ else if (c == L('[') && *p == L(':'))
+ {
+ int c1 = 0;
+ const CHAR *startp = p;
+
+ while (1)
+ {
+ c = *++p;
+ if (++c1 == CHAR_CLASS_MAX_LENGTH)
+ return FNM_NOMATCH;
+
+ if (*p == L(':') && p[1] == L(']'))
+ break;
+
+ if (c < L('a') || c >= L('z'))
+ {
+ p = startp;
+ goto ignore_next;
+ }
+ }
+ p += 2;
+ c = *p++;
+ }
+ else if (c == L('[') && *p == L('='))
+ {
+ c = *++p;
+ if (c == L('\0'))
+ return FNM_NOMATCH;
+ c = *++p;
+ if (c != L('=') || p[1] != L(']'))
+ return FNM_NOMATCH;
+ p += 2;
+ c = *p++;
+ }
+ else if (c == L('[') && *p == L('.'))
+ {
+ ++p;
+ while (1)
+ {
+ c = *++p;
+ if (c == '\0')
+ return FNM_NOMATCH;
+
+ if (*p == L('.') && p[1] == L(']'))
+ break;
+ }
+ p += 2;
+ c = *p++;
+ }
+ }
+ while (c != L(']'));
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ case L('+'):
+ case L('@'):
+ case L('!'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period, flags);
+ if (res != -1)
+ return res;
+ }
+ goto normal_match;
+
+ case L('/'):
+ if (NO_LEADING_PERIOD (flags))
+ {
+ if (n == string_end || c != (UCHAR) *n)
+ return FNM_NOMATCH;
+
+ new_no_leading_period = true;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ normal_match:
+ if (n == string_end || c != FOLD ((UCHAR) *n))
+ return FNM_NOMATCH;
+ }
+
+ no_leading_period = new_no_leading_period;
+ ++n;
+ }
+
+ if (n == string_end)
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L('/'))
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+}
+
+
+static const CHAR *
+internal_function
+END (const CHAR *pattern)
+{
+ const CHAR *p = pattern;
+
+ while (1)
+ if (*++p == L('\0'))
+ /* This is an invalid pattern. */
+ return pattern;
+ else if (*p == L('['))
+ {
+ /* Handle brackets special. */
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ /* Skip the not sign. We have to recognize it because of a possibly
+ following ']'. */
+ if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
+ ++p;
+ /* A leading ']' is recognized as such. */
+ if (*p == L(']'))
+ ++p;
+ /* Skip over all characters of the list. */
+ while (*p != L(']'))
+ if (*p++ == L('\0'))
+ /* This is no valid pattern. */
+ return pattern;
+ }
+ else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
+ || *p == L('!')) && p[1] == L('('))
+ p = END (p + 1);
+ else if (*p == L(')'))
+ break;
+
+ return p + 1;
+}
+
+
+static int
+internal_function
+EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
+ bool no_leading_period, int flags)
+{
+ const CHAR *startp;
+ size_t level;
+ struct patternlist
+ {
+ struct patternlist *next;
+ CHAR str[1];
+ } *list = NULL;
+ struct patternlist **lastp = &list;
+ size_t pattern_len = STRLEN (pattern);
+ const CHAR *p;
+ const CHAR *rs;
+ enum { ALLOCA_LIMIT = 8000 };
+
+ /* Parse the pattern. Store the individual parts in the list. */
+ level = 0;
+ for (startp = p = pattern + 1; ; ++p)
+ if (*p == L('\0'))
+ /* This is an invalid pattern. */
+ return -1;
+ else if (*p == L('['))
+ {
+ /* Handle brackets special. */
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ /* Skip the not sign. We have to recognize it because of a possibly
+ following ']'. */
+ if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
+ ++p;
+ /* A leading ']' is recognized as such. */
+ if (*p == L(']'))
+ ++p;
+ /* Skip over all characters of the list. */
+ while (*p != L(']'))
+ if (*p++ == L('\0'))
+ /* This is no valid pattern. */
+ return -1;
+ }
+ else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
+ || *p == L('!')) && p[1] == L('('))
+ /* Remember the nesting level. */
+ ++level;
+ else if (*p == L(')'))
+ {
+ if (level-- == 0)
+ {
+ /* This means we found the end of the pattern. */
+#define NEW_PATTERN \
+ struct patternlist *newp; \
+ size_t plen; \
+ size_t plensize; \
+ size_t newpsize; \
+ \
+ plen = (opt == L('?') || opt == L('@') \
+ ? pattern_len \
+ : p - startp + 1); \
+ plensize = plen * sizeof (CHAR); \
+ newpsize = offsetof (struct patternlist, str) + plensize; \
+ if ((size_t) -1 / sizeof (CHAR) < plen \
+ || newpsize < offsetof (struct patternlist, str) \
+ || ALLOCA_LIMIT <= newpsize) \
+ return -1; \
+ newp = (struct patternlist *) alloca (newpsize); \
+ *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0'); \
+ newp->next = NULL; \
+ *lastp = newp; \
+ lastp = &newp->next
+ NEW_PATTERN;
+ break;
+ }
+ }
+ else if (*p == L('|'))
+ {
+ if (level == 0)
+ {
+ NEW_PATTERN;
+ startp = p + 1;
+ }
+ }
+ assert (list != NULL);
+ assert (p[-1] == L(')'));
+#undef NEW_PATTERN
+
+ switch (opt)
+ {
+ case L('*'):
+ if (FCT (p, string, string_end, no_leading_period, flags) == 0)
+ return 0;
+ /* FALLTHROUGH */
+
+ case L('+'):
+ do
+ {
+ for (rs = string; rs <= string_end; ++rs)
+ /* First match the prefix with the current pattern with the
+ current pattern. */
+ if (FCT (list->str, string, rs, no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0
+ /* This was successful. Now match the rest with the rest
+ of the pattern. */
+ && (FCT (p, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
+ flags & FNM_FILE_NAME
+ ? flags : flags & ~FNM_PERIOD) == 0
+ /* This didn't work. Try the whole pattern. */
+ || (rs != string
+ && FCT (pattern - 1, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
+ flags & FNM_FILE_NAME
+ ? flags : flags & ~FNM_PERIOD) == 0)))
+ /* It worked. Signal success. */
+ return 0;
+ }
+ while ((list = list->next) != NULL);
+
+ /* None of the patterns lead to a match. */
+ return FNM_NOMATCH;
+
+ case L('?'):
+ if (FCT (p, string, string_end, no_leading_period, flags) == 0)
+ return 0;
+ /* FALLTHROUGH */
+
+ case L('@'):
+ do
+ /* I cannot believe it but `strcat' is actually acceptable
+ here. Match the entire string with the prefix from the
+ pattern list and the rest of the pattern following the
+ pattern list. */
+ if (FCT (STRCAT (list->str, p), string, string_end,
+ no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
+ /* It worked. Signal success. */
+ return 0;
+ while ((list = list->next) != NULL);
+
+ /* None of the patterns lead to a match. */
+ return FNM_NOMATCH;
+
+ case L('!'):
+ for (rs = string; rs <= string_end; ++rs)
+ {
+ struct patternlist *runp;
+
+ for (runp = list; runp != NULL; runp = runp->next)
+ if (FCT (runp->str, string, rs, no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
+ break;
+
+ /* If none of the patterns matched see whether the rest does. */
+ if (runp == NULL
+ && (FCT (p, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD)
+ == 0))
+ /* This is successful. */
+ return 0;
+ }
+
+ /* None of the patterns together with the rest of the pattern
+ lead to a match. */
+ return FNM_NOMATCH;
+
+ default:
+ assert (! "Invalid extended matching operator");
+ break;
+ }
+
+ return -1;
+}
+
+
+#undef FOLD
+#undef CHAR
+#undef UCHAR
+#undef INT
+#undef FCT
+#undef EXT
+#undef END
+#undef MEMPCPY
+#undef MEMCHR
+#undef STRCOLL
+#undef STRLEN
+#undef STRCAT
+#undef L
+#undef BTOWC
diff --git a/lib/fseeko.c b/lib/fseeko.c
new file mode 100644
index 0000000..d4c0ee0
--- /dev/null
+++ b/lib/fseeko.c
@@ -0,0 +1,48 @@
+/* fseeko.c -- an implementation of fseek() with an off_t argument.
+ Copyright (C) 2003, Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef LONG_MAX
+#define LONG_MAX ((long) ((unsigned long) ~0 >> 1))
+#endif
+#ifndef LONG_MIN
+#define LONG_MIN (-1 - LONG_MAX)
+#endif
+
+/*
+ * A replacement/substitute for fseeko, for hosts that don't have it.
+ */
+
+int
+fseeko (FILE *stream, off_t offset, int whence)
+{
+ while (offset != (long) offset)
+ {
+ long pos = (offset < 0) ? LONG_MIN : LONG_MAX;
+
+ if (fseek (stream, pos, whence) != 0)
+ return -1;
+ offset -= pos;
+ whence = SEEK_CUR;
+ }
+ return fseek (stream, (long) offset, whence);
+}
diff --git a/lib/ftello.c b/lib/ftello.c
new file mode 100644
index 0000000..82fe70e
--- /dev/null
+++ b/lib/ftello.c
@@ -0,0 +1,28 @@
+/* ftello.c -- an implementation of ftell() that returns an off_t
+ Copyright (C) 2003, Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+off_t
+ftello (FILE *stream)
+{
+ long pos;
+ pos = ftell (stream);
+
+ return (off_t) pos;
+}
diff --git a/lib/ftruncate.c b/lib/ftruncate.c
new file mode 100644
index 0000000..d5e1add
--- /dev/null
+++ b/lib/ftruncate.c
@@ -0,0 +1,92 @@
+/* ftruncate emulations that work on some System V's.
+ This file is in the public domain. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+ return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+# ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>. */
+
+# include <sys/stat.h>
+# include <errno.h>
+# if HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+
+int
+ftruncate (int fd, off_t length)
+{
+ struct flock fl;
+ struct stat filebuf;
+
+ if (fstat (fd, &filebuf) < 0)
+ return -1;
+
+ if (filebuf.st_size < length)
+ {
+ /* Extend file length. */
+ if (lseek (fd, (length - 1), SEEK_SET) < 0)
+ return -1;
+
+ /* Write a "0" byte. */
+ if (write (fd, "", 1) != 1)
+ return -1;
+ }
+ else
+ {
+
+ /* Truncate length. */
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = length;
+ fl.l_type = F_WRLCK; /* write lock on file space */
+
+ /* This relies on the *undocumented* F_FREESP argument to fcntl,
+ which truncates the file so that it ends at the position
+ indicated by fl.l_start. Will minor miracles never cease? */
+
+ if (fcntl (fd, F_FREESP, &fl) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+# else /* not F_CHSIZE nor F_FREESP */
+# if HAVE_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+ return chsize (fd, length);
+}
+
+# else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+# include <errno.h>
+
+int
+ftruncate (int fd, off_t length)
+{
+ errno = EIO;
+ return -1;
+}
+
+# endif /* not HAVE_CHSIZE */
+# endif /* not F_FREESP */
+#endif /* not F_CHSIZE */
diff --git a/lib/gai_strerror.c b/lib/gai_strerror.c
new file mode 100644
index 0000000..f289870
--- /dev/null
+++ b/lib/gai_strerror.c
@@ -0,0 +1,78 @@
+/* Copyright (C) 1997, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Philip Blundell <pjb27@cam.ac.uk>, 1997.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef _LIBC
+# include "getaddrinfo.h"
+#endif
+
+#include <stdio.h>
+#include <netdb.h>
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "gettext.h"
+# define _(String) gettext (String)
+# define N_(String) String
+#endif
+
+static struct
+ {
+ int code;
+ const char *msg;
+ }
+values[] =
+ {
+ { EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
+ { EAI_AGAIN, N_("Temporary failure in name resolution") },
+ { EAI_BADFLAGS, N_("Bad value for ai_flags") },
+ { EAI_FAIL, N_("Non-recoverable failure in name resolution") },
+ { EAI_FAMILY, N_("ai_family not supported") },
+ { EAI_MEMORY, N_("Memory allocation failure") },
+ { EAI_NODATA, N_("No address associated with hostname") },
+ { EAI_NONAME, N_("Name or service not known") },
+ { EAI_SERVICE, N_("Servname not supported for ai_socktype") },
+ { EAI_SOCKTYPE, N_("ai_socktype not supported") },
+ { EAI_SYSTEM, N_("System error") },
+#ifdef __USE_GNU
+ { EAI_INPROGRESS, N_("Processing request in progress") },
+ { EAI_CANCELED, N_("Request canceled") },
+ { EAI_NOTCANCELED, N_("Request not canceled") },
+ { EAI_ALLDONE, N_("All requests done") },
+ { EAI_INTR, N_("Interrupted by a signal") },
+ { EAI_IDN_ENCODE, N_("Parameter string not correctly encoded") }
+#endif
+ };
+
+const char *
+gai_strerror (int code)
+{
+ size_t i;
+ for (i = 0; i < sizeof (values) / sizeof (values[0]); ++i)
+ if (values[i].code == code)
+ return _(values[i].msg);
+
+ return _("Unknown error");
+}
+#ifdef _LIBC
+libc_hidden_def (gai_strerror)
+#endif
diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c
new file mode 100644
index 0000000..594b764
--- /dev/null
+++ b/lib/getaddrinfo.c
@@ -0,0 +1,210 @@
+/* Get address information (partial implementation).
+ Copyright (C) 1997, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
+ Contributed by Simon Josefsson <simon@josefsson.org>.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getaddrinfo.h"
+
+/* Get calloc. */
+#include <stdlib.h>
+
+/* Get memcpy. */
+#include <string.h>
+
+#include <stdbool.h>
+
+#include "gettext.h"
+#define _(String) gettext (String)
+#define N_(String) String
+
+#include "strdup.h"
+
+static inline bool
+validate_family (int family)
+{
+ /* FIXME: Support more families. */
+#if HAVE_IPV4
+ if (family == PF_INET)
+ return true;
+#endif
+#if HAVE_IPV6
+ if (family == PF_INET6)
+ return true;
+#endif
+ if (family == PF_UNSPEC)
+ return true;
+ return false;
+}
+
+/* Translate name of a service location and/or a service name to set of
+ socket addresses. */
+int
+getaddrinfo (const char *restrict nodename,
+ const char *restrict servname,
+ const struct addrinfo *restrict hints,
+ struct addrinfo **restrict res)
+{
+ struct addrinfo *tmp;
+ struct servent *se;
+ struct hostent *he;
+ size_t sinlen;
+
+ if (hints && (hints->ai_flags & ~AI_CANONNAME))
+ /* FIXME: Support more flags. */
+ return EAI_BADFLAGS;
+
+ if (hints && !validate_family (hints->ai_family))
+ return EAI_FAMILY;
+
+ if (hints &&
+ hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
+ /* FIXME: Support other socktype. */
+ return EAI_SOCKTYPE; /* FIXME: Better return code? */
+
+ if (!nodename)
+ /* FIXME: Support server bind mode. */
+ return EAI_NONAME;
+
+ if (servname)
+ {
+ const char *proto =
+ (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
+
+ /* FIXME: Use getservbyname_r if available. */
+ se = getservbyname (servname, proto);
+
+ if (!se)
+ return EAI_SERVICE;
+ }
+
+ /* FIXME: Use gethostbyname_r if available. */
+ he = gethostbyname (nodename);
+ if (!he || he->h_addr_list[0] == NULL)
+ return EAI_NONAME;
+
+ switch (he->h_addrtype)
+ {
+#if HAVE_IPV6
+ case PF_INET6:
+ sinlen = sizeof (struct sockaddr_in6);
+ break;
+#endif
+
+#if HAVE_IPV4
+ case PF_INET:
+ sinlen = sizeof (struct sockaddr_in);
+ break;
+#endif
+
+ default:
+ return EAI_NODATA;
+ }
+
+ tmp = calloc (1, sizeof (*tmp) + sinlen);
+ if (!tmp)
+ return EAI_MEMORY;
+
+ switch (he->h_addrtype)
+ {
+#if HAVE_IPV6
+ case PF_INET6:
+ {
+ struct sockaddr_in6 *sinp = (char *) tmp + sizeof (*tmp);
+
+ if (se)
+ sinp->sin6_port = se->s_port;
+
+ if (he->h_length != sizeof (sinp->sin6_addr))
+ return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
+
+ memcpy (&sinp->sin6_addr, he->h_addr_list[0], he->h_length);
+
+ tmp->ai_addr = (struct sockaddr *) sinp;
+ tmp->ai_addrlen = sinlen;
+ }
+ break;
+#endif
+
+#if HAVE_IPV4
+ case PF_INET:
+ {
+ struct sockaddr_in *sinp = (char *) tmp + sizeof (*tmp);
+
+ if (se)
+ sinp->sin_port = se->s_port;
+
+ if (he->h_length != sizeof (sinp->sin_addr))
+ return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
+
+ memcpy (&sinp->sin_addr, he->h_addr_list[0], he->h_length);
+
+ tmp->ai_addr = (struct sockaddr *) sinp;
+ tmp->ai_addrlen = sinlen;
+ }
+ break;
+#endif
+
+ default:
+ free (tmp);
+ return EAI_NODATA;
+ }
+
+ if (hints && hints->ai_flags & AI_CANONNAME)
+ {
+ const char *cn;
+ if (he->h_name)
+ cn = he->h_name;
+ else
+ cn = nodename;
+
+ tmp->ai_canonname = strdup (cn);
+ if (!tmp->ai_canonname)
+ {
+ free (tmp);
+ return EAI_MEMORY;
+ }
+ }
+
+ tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
+ tmp->ai_socktype = (hints) ? hints->ai_socktype : 0;
+ tmp->ai_addr->sa_family = he->h_addrtype;
+
+ /* FIXME: If more than one address, create linked list of addrinfo's. */
+
+ *res = tmp;
+
+ return 0;
+}
+
+/* Free `addrinfo' structure AI including associated storage. */
+void
+freeaddrinfo (struct addrinfo *ai)
+{
+ while (ai)
+ {
+ struct addrinfo *cur;
+
+ cur = ai;
+ ai = ai->ai_next;
+
+ if (cur->ai_canonname) free (cur->ai_canonname);
+ free (cur);
+ }
+}
diff --git a/lib/getaddrinfo.h b/lib/getaddrinfo.h
new file mode 100644
index 0000000..5d14562
--- /dev/null
+++ b/lib/getaddrinfo.h
@@ -0,0 +1,95 @@
+/* Get address information.
+ Copyright (C) 1996-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Contributed by Simon Josefsson <simon@josefsson.org>.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef GETADDRINFO_H
+# define GETADDRINFO_H
+
+/* Get getaddrinfo declarations, if available. Also get 'socklen_t',
+ and 'struct sockaddr' via sys/types.h which are used below. */
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netdb.h>
+
+# if !HAVE_GETADDRINFO
+
+/* Structure to contain information about address of a service provider. */
+struct addrinfo
+{
+ int ai_flags; /* Input flags. */
+ int ai_family; /* Protocol family for socket. */
+ int ai_socktype; /* Socket type. */
+ int ai_protocol; /* Protocol for socket. */
+ socklen_t ai_addrlen; /* Length of socket address. */
+ struct sockaddr *ai_addr; /* Socket address for socket. */
+ char *ai_canonname; /* Canonical name for service location. */
+ struct addrinfo *ai_next; /* Pointer to next in list. */
+};
+
+/* Possible values for `ai_flags' field in `addrinfo' structure. */
+# define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */
+# define AI_CANONNAME 0x0002 /* Request for canonical name. */
+# define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */
+# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */
+# define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */
+# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
+ returned address type.. */
+
+/* Error values for `getaddrinfo' function. */
+# define EAI_BADFLAGS -1 /* Invalid value for `ai_flags' field. */
+# define EAI_NONAME -2 /* NAME or SERVICE is unknown. */
+# define EAI_AGAIN -3 /* Temporary failure in name resolution. */
+# define EAI_FAIL -4 /* Non-recoverable failure in name res. */
+# define EAI_NODATA -5 /* No address associated with NAME. */
+# define EAI_FAMILY -6 /* `ai_family' not supported. */
+# define EAI_SOCKTYPE -7 /* `ai_socktype' not supported. */
+# define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype'. */
+# define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */
+# define EAI_MEMORY -10 /* Memory allocation failure. */
+# define EAI_SYSTEM -11 /* System error returned in `errno'. */
+# define EAI_OVERFLOW -12 /* Argument buffer overflow. */
+# ifdef __USE_GNU
+# define EAI_INPROGRESS -100 /* Processing request in progress. */
+# define EAI_CANCELED -101 /* Request canceled. */
+# define EAI_NOTCANCELED -102 /* Request not canceled. */
+# define EAI_ALLDONE -103 /* All requests done. */
+# define EAI_INTR -104 /* Interrupted by a signal. */
+# define EAI_IDN_ENCODE -105 /* IDN encoding failed. */
+# endif
+
+/* Translate name of a service location and/or a service name to set of
+ socket addresses.
+ For more details, see the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/getaddrinfo.html>. */
+extern int getaddrinfo (const char *restrict nodename,
+ const char *restrict servname,
+ const struct addrinfo *restrict hints,
+ struct addrinfo **restrict res);
+
+/* Free `addrinfo' structure AI including associated storage.
+ For more details, see the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/getaddrinfo.html>. */
+extern void freeaddrinfo (struct addrinfo *ai);
+
+/* Convert error return from getaddrinfo() to a string.
+ For more details, see the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/gai_strerror.html>. */
+extern const char *gai_strerror (int ecode);
+
+# endif /* !HAVE_GETADDRINFO */
+
+#endif /* GETADDRINFO_H */
diff --git a/lib/getcwd.c b/lib/getcwd.c
new file mode 100644
index 0000000..9f8c4cc
--- /dev/null
+++ b/lib/getcwd.c
@@ -0,0 +1,407 @@
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99,2004,2005 Free Software
+ Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !_LIBC
+# include "getcwd.h"
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <fcntl.h> /* For AT_FDCWD on Solaris 9. */
+
+#ifndef __set_errno
+# define __set_errno(val) (errno = (val))
+#endif
+
+#if HAVE_DIRENT_H || _LIBC
+# include <dirent.h>
+# ifndef _D_EXACT_NAMLEN
+# define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
+# endif
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+#ifndef _D_EXACT_NAMLEN
+# define _D_EXACT_NAMLEN(d) ((d)->d_namlen)
+#endif
+#ifndef _D_ALLOC_NAMLEN
+# define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
+#endif
+
+#if HAVE_UNISTD_H || _LIBC
+# include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#if _LIBC
+# ifndef mempcpy
+# define mempcpy __mempcpy
+# endif
+#else
+# include "mempcpy.h"
+#endif
+
+#include <limits.h>
+
+#ifdef ENAMETOOLONG
+# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
+#else
+# define is_ENAMETOOLONG(x) 0
+#endif
+
+#ifndef MAX
+# define MAX(a, b) ((a) < (b) ? (b) : (a))
+#endif
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# else
+# define PATH_MAX 1024
+# endif
+#endif
+
+#if D_INO_IN_DIRENT
+# define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino))
+#else
+# define MATCHING_INO(dp, ino) true
+#endif
+
+#if !_LIBC
+# define __getcwd getcwd
+# define __lstat lstat
+# define __closedir closedir
+# define __opendir opendir
+# define __readdir readdir
+#endif
+
+/* Get the name of the current working directory, and put it in SIZE
+ bytes of BUF. Returns NULL if the directory couldn't be determined or
+ SIZE was too small. If successful, returns BUF. In GNU, if BUF is
+ NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
+ unless SIZE == 0, in which case it is as big as necessary. */
+
+char *
+__getcwd (char *buf, size_t size)
+{
+ /* Lengths of big file name components and entire file names, and a
+ deep level of file name nesting. These numbers are not upper
+ bounds; they are merely large values suitable for initial
+ allocations, designed to be large enough for most real-world
+ uses. */
+ enum
+ {
+ BIG_FILE_NAME_COMPONENT_LENGTH = 255,
+ BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
+ DEEP_NESTING = 100
+ };
+
+#ifdef AT_FDCWD
+ int fd = AT_FDCWD;
+ bool fd_needs_closing = false;
+#else
+ char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
+ char *dotlist = dots;
+ size_t dotsize = sizeof dots;
+ size_t dotlen = 0;
+#endif
+ DIR *dirstream = NULL;
+ dev_t rootdev, thisdev;
+ ino_t rootino, thisino;
+ char *dir;
+ register char *dirp;
+ struct stat st;
+ size_t allocated = size;
+ size_t used;
+
+#if HAVE_PARTLY_WORKING_GETCWD && !defined AT_FDCWD
+ /* The system getcwd works, except it sometimes fails when it
+ shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If
+ AT_FDCWD is not defined, the algorithm below is O(N**2) and this
+ is much slower than the system getcwd (at least on GNU/Linux).
+ So trust the system getcwd's results unless they look
+ suspicious. */
+# undef getcwd
+ dir = getcwd (buf, size);
+ if (dir || (errno != ERANGE && !is_ENAMETOOLONG (errno) && errno != ENOENT))
+ return dir;
+#endif
+
+ if (size == 0)
+ {
+ if (buf != NULL)
+ {
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ allocated = BIG_FILE_NAME_LENGTH + 1;
+ }
+
+ if (buf == NULL)
+ {
+ dir = malloc (allocated);
+ if (dir == NULL)
+ return NULL;
+ }
+ else
+ dir = buf;
+
+ dirp = dir + allocated;
+ *--dirp = '\0';
+
+ if (__lstat (".", &st) < 0)
+ goto lose;
+ thisdev = st.st_dev;
+ thisino = st.st_ino;
+
+ if (__lstat ("/", &st) < 0)
+ goto lose;
+ rootdev = st.st_dev;
+ rootino = st.st_ino;
+
+ while (!(thisdev == rootdev && thisino == rootino))
+ {
+ struct dirent *d;
+ dev_t dotdev;
+ ino_t dotino;
+ bool mount_point;
+ int parent_status;
+
+ /* Look at the parent directory. */
+#ifdef AT_FDCWD
+ fd = openat (fd, "..", O_RDONLY);
+ if (fd < 0)
+ goto lose;
+ fd_needs_closing = true;
+ parent_status = fstat (fd, &st);
+#else
+ dotlist[dotlen++] = '.';
+ dotlist[dotlen++] = '.';
+ dotlist[dotlen] = '\0';
+ parent_status = __lstat (dotlist, &st);
+#endif
+ if (parent_status != 0)
+ goto lose;
+
+ if (dirstream && __closedir (dirstream) != 0)
+ {
+ dirstream = NULL;
+ goto lose;
+ }
+
+ /* Figure out if this directory is a mount point. */
+ dotdev = st.st_dev;
+ dotino = st.st_ino;
+ mount_point = dotdev != thisdev;
+
+ /* Search for the last directory. */
+#ifdef AT_FDCWD
+ dirstream = fdopendir (fd);
+ if (dirstream == NULL)
+ goto lose;
+ fd_needs_closing = false;
+#else
+ dirstream = __opendir (dotlist);
+ if (dirstream == NULL)
+ goto lose;
+ dotlist[dotlen++] = '/';
+#endif
+ /* Clear errno to distinguish EOF from error if readdir returns
+ NULL. */
+ __set_errno (0);
+ while ((d = __readdir (dirstream)) != NULL)
+ {
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue;
+ if (MATCHING_INO (d, thisino) || mount_point)
+ {
+ int entry_status;
+#ifdef AT_FDCWD
+ entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
+#else
+ /* Compute size needed for this file name, or for the file
+ name ".." in the same directory, whichever is larger.
+ Room for ".." might be needed the next time through
+ the outer loop. */
+ size_t name_alloc = _D_ALLOC_NAMLEN (d);
+ size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
+
+ if (filesize < dotlen)
+ goto memory_exhausted;
+
+ if (dotsize < filesize)
+ {
+ /* My, what a deep directory tree you have, Grandma. */
+ size_t newsize = MAX (filesize, dotsize * 2);
+ size_t i;
+ if (newsize < dotsize)
+ goto memory_exhausted;
+ if (dotlist != dots)
+ free (dotlist);
+ dotlist = malloc (newsize);
+ if (dotlist == NULL)
+ goto lose;
+ dotsize = newsize;
+
+ i = 0;
+ do
+ {
+ dotlist[i++] = '.';
+ dotlist[i++] = '.';
+ dotlist[i++] = '/';
+ }
+ while (i < dotlen);
+ }
+
+ strcpy (dotlist + dotlen, d->d_name);
+ entry_status = __lstat (dotlist, &st);
+#endif
+ /* We don't fail here if we cannot stat() a directory entry.
+ This can happen when (network) file systems fail. If this
+ entry is in fact the one we are looking for we will find
+ out soon as we reach the end of the directory without
+ having found anything. */
+ if (entry_status == 0 && S_ISDIR (st.st_mode)
+ && st.st_dev == thisdev && st.st_ino == thisino)
+ break;
+ }
+ }
+ if (d == NULL)
+ {
+ if (errno == 0)
+ /* EOF on dirstream, which means that the current directory
+ has been removed. */
+ __set_errno (ENOENT);
+ goto lose;
+ }
+ else
+ {
+ size_t dirroom = dirp - dir;
+ size_t namlen = _D_EXACT_NAMLEN (d);
+
+ if (dirroom <= namlen)
+ {
+ if (size != 0)
+ {
+ __set_errno (ERANGE);
+ goto lose;
+ }
+ else
+ {
+ char *tmp;
+ size_t oldsize = allocated;
+
+ allocated += MAX (allocated, namlen);
+ if (allocated < oldsize
+ || ! (tmp = realloc (dir, allocated)))
+ goto memory_exhausted;
+
+ /* Move current contents up to the end of the buffer.
+ This is guaranteed to be non-overlapping. */
+ dirp = memcpy (tmp + allocated - (oldsize - dirroom),
+ tmp + dirroom,
+ oldsize - dirroom);
+ dir = tmp;
+ }
+ }
+ dirp -= namlen;
+ memcpy (dirp, d->d_name, namlen);
+ *--dirp = '/';
+ }
+
+ thisdev = dotdev;
+ thisino = dotino;
+ }
+
+ if (dirstream && __closedir (dirstream) != 0)
+ {
+ dirstream = NULL;
+ goto lose;
+ }
+
+ if (dirp == &dir[allocated - 1])
+ *--dirp = '/';
+
+#ifndef AT_FDCWD
+ if (dotlist != dots)
+ free (dotlist);
+#endif
+
+ used = dir + allocated - dirp;
+ memmove (dir, dirp, used);
+
+ if (buf == NULL && size == 0)
+ /* Ensure that the buffer is only as large as necessary. */
+ buf = realloc (dir, used);
+
+ if (buf == NULL)
+ /* Either buf was NULL all along, or `realloc' failed but
+ we still have the original string. */
+ buf = dir;
+
+ return buf;
+
+ memory_exhausted:
+ __set_errno (ENOMEM);
+ lose:
+ {
+ int save = errno;
+ if (dirstream)
+ __closedir (dirstream);
+#ifdef AT_FDCWD
+ if (fd_needs_closing)
+ close (fd);
+#else
+ if (dotlist != dots)
+ free (dotlist);
+#endif
+ if (buf == NULL)
+ free (dir);
+ __set_errno (save);
+ }
+ return NULL;
+}
+
+#ifdef weak_alias
+weak_alias (__getcwd, getcwd)
+#endif
diff --git a/lib/getcwd.h b/lib/getcwd.h
new file mode 100644
index 0000000..200a3d3
--- /dev/null
+++ b/lib/getcwd.h
@@ -0,0 +1,42 @@
+/* Get the working directory, compatibly with the GNU C Library.
+
+ Copyright (C) 2004-2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+/* Include the headers that might declare getcwd so that they will not
+ cause confusion if included after this file. */
+
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* If necessary, systematically rename identifiers so that they do not
+ collide with the system function. Renaming avoids problems with
+ some compilers and linkers. */
+
+#ifdef __GETCWD_PREFIX
+# undef getcwd
+# define __GETCWD_CONCAT(x, y) x ## y
+# define __GETCWD_XCONCAT(x, y) __GETCWD_CONCAT (x, y)
+# define __GETCWD_ID(y) __GETCWD_XCONCAT (__GETCWD_PREFIX, y)
+# define getcwd __GETCWD_ID (getcwd)
+/* See the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/getcwd.html>. */
+char *getcwd (char *, size_t);
+#endif
diff --git a/lib/getdate.c b/lib/getdate.c
new file mode 100644
index 0000000..7e0f763
--- /dev/null
+++ b/lib/getdate.c
@@ -0,0 +1,2936 @@
+/* A Bison parser, made by GNU Bison 1.875c. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ tAGO = 258,
+ tDST = 259,
+ tDAY = 260,
+ tDAY_UNIT = 261,
+ tDAYZONE = 262,
+ tHOUR_UNIT = 263,
+ tLOCAL_ZONE = 264,
+ tMERIDIAN = 265,
+ tMINUTE_UNIT = 266,
+ tMONTH = 267,
+ tMONTH_UNIT = 268,
+ tORDINAL = 269,
+ tSEC_UNIT = 270,
+ tYEAR_UNIT = 271,
+ tZONE = 272,
+ tSNUMBER = 273,
+ tUNUMBER = 274,
+ tSDECIMAL_NUMBER = 275,
+ tUDECIMAL_NUMBER = 276
+ };
+#endif
+#define tAGO 258
+#define tDST 259
+#define tDAY 260
+#define tDAY_UNIT 261
+#define tDAYZONE 262
+#define tHOUR_UNIT 263
+#define tLOCAL_ZONE 264
+#define tMERIDIAN 265
+#define tMINUTE_UNIT 266
+#define tMONTH 267
+#define tMONTH_UNIT 268
+#define tORDINAL 269
+#define tSEC_UNIT 270
+#define tYEAR_UNIT 271
+#define tZONE 272
+#define tSNUMBER 273
+#define tUNUMBER 274
+#define tSDECIMAL_NUMBER 275
+#define tUDECIMAL_NUMBER 276
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "getdate.y"
+
+/* Parse a string into an internal time stamp.
+
+ Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Originally written by Steven M. Bellovin <smb@research.att.com> while
+ at the University of North Carolina at Chapel Hill. Later tweaked by
+ a couple of people on Usenet. Completely overhauled by Rich $alz
+ <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+
+ Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
+ the right thing about local DST. Also modified by Paul Eggert
+ <eggert@cs.ucla.edu> in February 2004 to support
+ nanosecond-resolution time stamps, and in October 2004 to support
+ TZ strings in dates. */
+
+/* FIXME: Check for arithmetic overflow in all cases, not just
+ some of them. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getdate.h"
+
+/* There's no need to extend the stack, so there's no need to involve
+ alloca. */
+#define YYSTACK_USE_ALLOCA 0
+
+/* Tell Bison how much stack space is needed. 20 should be plenty for
+ this grammar, which is not right recursive. Beware setting it too
+ high, since that might cause problems on machines whose
+ implementations have lame stack-overflow checking. */
+#define YYMAXDEPTH 20
+#define YYINITDEPTH YYMAXDEPTH
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+# undef static
+#endif
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "setenv.h"
+#include "xalloc.h"
+
+#if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii (c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
+
+/* ISDIGIT differs from isdigit, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
+ isdigit unless it's important to use the locale's definition
+ of `digit' even when the host does not conform to POSIX. */
+#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+/* Shift A right by B bits portably, by dividing A by 2**B and
+ truncating towards minus infinity. A and B should be free of side
+ effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
+ INT_BITS is the number of useful bits in an int. GNU code can
+ assume that INT_BITS is at least 32.
+
+ ISO C99 says that A >> B is implementation-defined if A < 0. Some
+ implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
+ right in the usual way when A < 0, so SHR falls back on division if
+ ordinary A >> B doesn't seem to be the usual signed shift. */
+#define SHR(a, b) \
+ (-1 >> 1 == -1 \
+ ? (a) >> (b) \
+ : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
+
+#define EPOCH_YEAR 1970
+#define TM_YEAR_BASE 1900
+
+#define HOUR(x) ((x) * 60)
+
+/* An integer value, and the number of digits in its textual
+ representation. */
+typedef struct
+{
+ bool negative;
+ long int value;
+ size_t digits;
+} textint;
+
+/* An entry in the lexical lookup table. */
+typedef struct
+{
+ char const *name;
+ int type;
+ int value;
+} table;
+
+/* Meridian: am, pm, or 24-hour style. */
+enum { MERam, MERpm, MER24 };
+
+enum { BILLION = 1000000000, LOG10_BILLION = 9 };
+
+/* Information passed to and from the parser. */
+typedef struct
+{
+ /* The input string remaining to be parsed. */
+ const char *input;
+
+ /* N, if this is the Nth Tuesday. */
+ long int day_ordinal;
+
+ /* Day of week; Sunday is 0. */
+ int day_number;
+
+ /* tm_isdst flag for the local zone. */
+ int local_isdst;
+
+ /* Time zone, in minutes east of UTC. */
+ long int time_zone;
+
+ /* Style used for time. */
+ int meridian;
+
+ /* Gregorian year, month, day, hour, minutes, seconds, and nanoseconds. */
+ textint year;
+ long int month;
+ long int day;
+ long int hour;
+ long int minutes;
+ struct timespec seconds; /* includes nanoseconds */
+
+ /* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */
+ long int rel_year;
+ long int rel_month;
+ long int rel_day;
+ long int rel_hour;
+ long int rel_minutes;
+ long int rel_seconds;
+ long int rel_ns;
+
+ /* Presence or counts of nonterminals of various flavors parsed so far. */
+ bool timespec_seen;
+ bool rels_seen;
+ size_t dates_seen;
+ size_t days_seen;
+ size_t local_zones_seen;
+ size_t dsts_seen;
+ size_t times_seen;
+ size_t zones_seen;
+
+ /* Table of local time zone abbrevations, terminated by a null entry. */
+ table local_time_zone_table[3];
+} parser_control;
+
+union YYSTYPE;
+static int yylex (union YYSTYPE *, parser_control *);
+static int yyerror (parser_control *, char *);
+static long int time_zone_hhmm (textint, long int);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 209 "getdate.y"
+typedef union YYSTYPE {
+ long int intval;
+ textint textintval;
+ struct timespec timespec;
+} YYSTYPE;
+/* Line 191 of yacc.c. */
+#line 322 "getdate.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 214 of yacc.c. */
+#line 334 "getdate.c"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+# ifndef YYFREE
+# define YYFREE free
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# endif
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# endif
+# else
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 12
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 88
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 26
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 19
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 78
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 96
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 276
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 24, 2, 2, 25, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 23, 2,
+ 2, 2, 2, 2, 22, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 10, 11, 14, 16, 18,
+ 20, 22, 24, 26, 28, 31, 36, 42, 49, 57,
+ 59, 62, 64, 67, 71, 73, 76, 78, 81, 84,
+ 87, 91, 97, 101, 105, 109, 112, 117, 120, 124,
+ 127, 129, 132, 135, 137, 140, 143, 145, 148, 151,
+ 153, 156, 159, 161, 164, 167, 169, 172, 175, 178,
+ 181, 183, 185, 188, 191, 194, 197, 200, 203, 205,
+ 207, 209, 211, 213, 215, 217, 218, 221, 222
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 27, 0, -1, 28, -1, 29, -1, 22, 39, -1,
+ -1, 29, 30, -1, 31, -1, 32, -1, 33, -1,
+ 35, -1, 34, -1, 36, -1, 42, -1, 19, 10,
+ -1, 19, 23, 19, 44, -1, 19, 23, 19, 18,
+ 43, -1, 19, 23, 19, 23, 41, 44, -1, 19,
+ 23, 19, 23, 41, 18, 43, -1, 9, -1, 9,
+ 4, -1, 17, -1, 17, 38, -1, 17, 18, 43,
+ -1, 7, -1, 17, 4, -1, 5, -1, 5, 24,
+ -1, 14, 5, -1, 19, 5, -1, 19, 25, 19,
+ -1, 19, 25, 19, 25, 19, -1, 19, 18, 18,
+ -1, 19, 12, 18, -1, 12, 18, 18, -1, 12,
+ 19, -1, 12, 19, 24, 19, -1, 19, 12, -1,
+ 19, 12, 19, -1, 37, 3, -1, 37, -1, 14,
+ 16, -1, 19, 16, -1, 16, -1, 14, 13, -1,
+ 19, 13, -1, 13, -1, 14, 6, -1, 19, 6,
+ -1, 6, -1, 14, 8, -1, 19, 8, -1, 8,
+ -1, 14, 11, -1, 19, 11, -1, 11, -1, 14,
+ 15, -1, 19, 15, -1, 20, 15, -1, 21, 15,
+ -1, 15, -1, 38, -1, 18, 16, -1, 18, 13,
+ -1, 18, 6, -1, 18, 8, -1, 18, 11, -1,
+ 18, 15, -1, 40, -1, 41, -1, 20, -1, 18,
+ -1, 21, -1, 19, -1, 19, -1, -1, 23, 19,
+ -1, -1, 10, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 230, 230, 231, 235, 242, 244, 248, 250, 252,
+ 254, 256, 258, 260, 264, 272, 280, 290, 297, 309,
+ 314, 322, 324, 326, 328, 330, 335, 340, 345, 350,
+ 358, 363, 383, 390, 398, 406, 411, 417, 422, 431,
+ 441, 445, 447, 449, 451, 453, 455, 457, 459, 461,
+ 463, 465, 467, 469, 471, 473, 475, 477, 479, 481,
+ 483, 485, 489, 491, 493, 495, 497, 499, 503, 503,
+ 506, 507, 512, 513, 518, 556, 557, 563, 564
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "tAGO", "tDST", "tDAY", "tDAY_UNIT",
+ "tDAYZONE", "tHOUR_UNIT", "tLOCAL_ZONE", "tMERIDIAN", "tMINUTE_UNIT",
+ "tMONTH", "tMONTH_UNIT", "tORDINAL", "tSEC_UNIT", "tYEAR_UNIT", "tZONE",
+ "tSNUMBER", "tUNUMBER", "tSDECIMAL_NUMBER", "tUDECIMAL_NUMBER", "'@'",
+ "':'", "','", "'/'", "$accept", "spec", "timespec", "items", "item",
+ "time", "local_zone", "zone", "day", "date", "rel", "relunit",
+ "relunit_snumber", "seconds", "signed_seconds", "unsigned_seconds",
+ "number", "o_colon_minutes", "o_merid", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 64, 58, 44, 47
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 26, 27, 27, 28, 29, 29, 30, 30, 30,
+ 30, 30, 30, 30, 31, 31, 31, 31, 31, 32,
+ 32, 33, 33, 33, 33, 33, 34, 34, 34, 34,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 36,
+ 36, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 38, 38, 38, 38, 38, 38, 39, 39,
+ 40, 40, 41, 41, 42, 43, 43, 44, 44
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 1, 1, 2, 0, 2, 1, 1, 1,
+ 1, 1, 1, 1, 2, 4, 5, 6, 7, 1,
+ 2, 1, 2, 3, 1, 2, 1, 2, 2, 2,
+ 3, 5, 3, 3, 3, 2, 4, 2, 3, 2,
+ 1, 2, 2, 1, 2, 2, 1, 2, 2, 1,
+ 2, 2, 1, 2, 2, 1, 2, 2, 2, 2,
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 0, 2, 0, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 5, 0, 0, 2, 3, 71, 73, 70, 72, 4,
+ 68, 69, 1, 26, 49, 24, 52, 19, 55, 0,
+ 46, 0, 60, 43, 21, 0, 74, 0, 0, 6,
+ 7, 8, 9, 11, 10, 12, 40, 61, 13, 27,
+ 20, 0, 35, 28, 47, 50, 53, 44, 56, 41,
+ 25, 75, 22, 64, 65, 66, 63, 67, 62, 29,
+ 48, 51, 14, 54, 37, 45, 57, 42, 0, 0,
+ 0, 58, 59, 39, 34, 0, 0, 23, 33, 38,
+ 32, 77, 30, 36, 76, 78, 75, 0, 15, 0,
+ 16, 77, 31, 75, 17, 18
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 2, 3, 4, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 9, 10, 11, 38, 77, 88
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -43
+static const yysigned_char yypact[] =
+{
+ -18, 48, 9, -43, 19, -43, -43, -43, -43, -43,
+ -43, -43, -43, 32, -43, -43, -43, 54, -43, 28,
+ -43, 37, -43, -43, -2, 49, -5, 57, 58, -43,
+ -43, -43, -43, -43, -43, -43, 60, -43, -43, -43,
+ -43, 56, 51, -43, -43, -43, -43, -43, -43, -43,
+ -43, 6, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, 52, -43, -43, -43, 59, 61,
+ 62, -43, -43, -43, -43, 63, 64, -43, -43, -43,
+ -43, 31, 53, -43, -43, -43, 65, 40, -43, 66,
+ -43, 5, -43, 65, -43, -43
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, 55, -43, -43, -11, -43, -42, -7
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 59, 60, 50, 61, 1, 62, 63, 64, 65, 12,
+ 66, 67, 53, 68, 54, 85, 51, 55, 69, 56,
+ 70, 57, 58, 93, 13, 14, 15, 16, 17, 76,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 85, 43, 44, 90, 45, 41, 42, 46, 86,
+ 47, 95, 48, 49, 87, 53, 39, 54, 40, 6,
+ 55, 8, 56, 73, 57, 58, 5, 6, 7, 8,
+ 78, 79, 71, 72, 74, 75, 91, 80, 89, 52,
+ 81, 82, 83, 84, 94, 92, 0, 0, 76
+};
+
+static const yysigned_char yycheck[] =
+{
+ 5, 6, 4, 8, 22, 10, 11, 12, 13, 0,
+ 15, 16, 6, 18, 8, 10, 18, 11, 23, 13,
+ 25, 15, 16, 18, 5, 6, 7, 8, 9, 23,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 10, 5, 6, 86, 8, 18, 19, 11, 18,
+ 13, 93, 15, 16, 23, 6, 24, 8, 4, 19,
+ 11, 21, 13, 3, 15, 16, 18, 19, 20, 21,
+ 18, 19, 15, 15, 18, 24, 87, 18, 25, 24,
+ 19, 19, 19, 19, 91, 19, -1, -1, 23
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 22, 27, 28, 29, 18, 19, 20, 21, 39,
+ 40, 41, 0, 5, 6, 7, 8, 9, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 42, 24,
+ 4, 18, 19, 5, 6, 8, 11, 13, 15, 16,
+ 4, 18, 38, 6, 8, 11, 13, 15, 16, 5,
+ 6, 8, 10, 11, 12, 13, 15, 16, 18, 23,
+ 25, 15, 15, 3, 18, 24, 23, 43, 18, 19,
+ 18, 19, 19, 19, 19, 10, 18, 23, 44, 25,
+ 43, 41, 19, 18, 44, 43
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (pc, "syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ ((Current).first_line = (Rhs)[1].first_line, \
+ (Current).first_column = (Rhs)[1].first_column, \
+ (Current).last_line = (Rhs)[N].last_line, \
+ (Current).last_column = (Rhs)[N].last_column)
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, pc)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse ( parser_control *pc );
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse ( parser_control *pc )
+#else
+int
+yyparse (pc)
+ parser_control *pc ;
+#endif
+#endif
+{
+ /* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 236 "getdate.y"
+ {
+ pc->seconds = yyvsp[0].timespec;
+ pc->timespec_seen = true;
+ }
+ break;
+
+ case 7:
+#line 249 "getdate.y"
+ { pc->times_seen++; }
+ break;
+
+ case 8:
+#line 251 "getdate.y"
+ { pc->local_zones_seen++; }
+ break;
+
+ case 9:
+#line 253 "getdate.y"
+ { pc->zones_seen++; }
+ break;
+
+ case 10:
+#line 255 "getdate.y"
+ { pc->dates_seen++; }
+ break;
+
+ case 11:
+#line 257 "getdate.y"
+ { pc->days_seen++; }
+ break;
+
+ case 12:
+#line 259 "getdate.y"
+ { pc->rels_seen = true; }
+ break;
+
+ case 14:
+#line 265 "getdate.y"
+ {
+ pc->hour = yyvsp[-1].textintval.value;
+ pc->minutes = 0;
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = yyvsp[0].intval;
+ }
+ break;
+
+ case 15:
+#line 273 "getdate.y"
+ {
+ pc->hour = yyvsp[-3].textintval.value;
+ pc->minutes = yyvsp[-1].textintval.value;
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = yyvsp[0].intval;
+ }
+ break;
+
+ case 16:
+#line 281 "getdate.y"
+ {
+ pc->hour = yyvsp[-4].textintval.value;
+ pc->minutes = yyvsp[-2].textintval.value;
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = MER24;
+ pc->zones_seen++;
+ pc->time_zone = time_zone_hhmm (yyvsp[-1].textintval, yyvsp[0].intval);
+ }
+ break;
+
+ case 17:
+#line 291 "getdate.y"
+ {
+ pc->hour = yyvsp[-5].textintval.value;
+ pc->minutes = yyvsp[-3].textintval.value;
+ pc->seconds = yyvsp[-1].timespec;
+ pc->meridian = yyvsp[0].intval;
+ }
+ break;
+
+ case 18:
+#line 298 "getdate.y"
+ {
+ pc->hour = yyvsp[-6].textintval.value;
+ pc->minutes = yyvsp[-4].textintval.value;
+ pc->seconds = yyvsp[-2].timespec;
+ pc->meridian = MER24;
+ pc->zones_seen++;
+ pc->time_zone = time_zone_hhmm (yyvsp[-1].textintval, yyvsp[0].intval);
+ }
+ break;
+
+ case 19:
+#line 310 "getdate.y"
+ {
+ pc->local_isdst = yyvsp[0].intval;
+ pc->dsts_seen += (0 < yyvsp[0].intval);
+ }
+ break;
+
+ case 20:
+#line 315 "getdate.y"
+ {
+ pc->local_isdst = 1;
+ pc->dsts_seen += (0 < yyvsp[-1].intval) + 1;
+ }
+ break;
+
+ case 21:
+#line 323 "getdate.y"
+ { pc->time_zone = yyvsp[0].intval; }
+ break;
+
+ case 22:
+#line 325 "getdate.y"
+ { pc->time_zone = yyvsp[-1].intval; pc->rels_seen = true; }
+ break;
+
+ case 23:
+#line 327 "getdate.y"
+ { pc->time_zone = yyvsp[-2].intval + time_zone_hhmm (yyvsp[-1].textintval, yyvsp[0].intval); }
+ break;
+
+ case 24:
+#line 329 "getdate.y"
+ { pc->time_zone = yyvsp[0].intval + 60; }
+ break;
+
+ case 25:
+#line 331 "getdate.y"
+ { pc->time_zone = yyvsp[-1].intval + 60; }
+ break;
+
+ case 26:
+#line 336 "getdate.y"
+ {
+ pc->day_ordinal = 1;
+ pc->day_number = yyvsp[0].intval;
+ }
+ break;
+
+ case 27:
+#line 341 "getdate.y"
+ {
+ pc->day_ordinal = 1;
+ pc->day_number = yyvsp[-1].intval;
+ }
+ break;
+
+ case 28:
+#line 346 "getdate.y"
+ {
+ pc->day_ordinal = yyvsp[-1].intval;
+ pc->day_number = yyvsp[0].intval;
+ }
+ break;
+
+ case 29:
+#line 351 "getdate.y"
+ {
+ pc->day_ordinal = yyvsp[-1].textintval.value;
+ pc->day_number = yyvsp[0].intval;
+ }
+ break;
+
+ case 30:
+#line 359 "getdate.y"
+ {
+ pc->month = yyvsp[-2].textintval.value;
+ pc->day = yyvsp[0].textintval.value;
+ }
+ break;
+
+ case 31:
+#line 364 "getdate.y"
+ {
+ /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
+ otherwise as MM/DD/YY.
+ The goal in recognizing YYYY/MM/DD is solely to support legacy
+ machine-generated dates like those in an RCS log listing. If
+ you want portability, use the ISO 8601 format. */
+ if (4 <= yyvsp[-4].textintval.digits)
+ {
+ pc->year = yyvsp[-4].textintval;
+ pc->month = yyvsp[-2].textintval.value;
+ pc->day = yyvsp[0].textintval.value;
+ }
+ else
+ {
+ pc->month = yyvsp[-4].textintval.value;
+ pc->day = yyvsp[-2].textintval.value;
+ pc->year = yyvsp[0].textintval;
+ }
+ }
+ break;
+
+ case 32:
+#line 384 "getdate.y"
+ {
+ /* ISO 8601 format. YYYY-MM-DD. */
+ pc->year = yyvsp[-2].textintval;
+ pc->month = -yyvsp[-1].textintval.value;
+ pc->day = -yyvsp[0].textintval.value;
+ }
+ break;
+
+ case 33:
+#line 391 "getdate.y"
+ {
+ /* e.g. 17-JUN-1992. */
+ pc->day = yyvsp[-2].textintval.value;
+ pc->month = yyvsp[-1].intval;
+ pc->year.value = -yyvsp[0].textintval.value;
+ pc->year.digits = yyvsp[0].textintval.digits;
+ }
+ break;
+
+ case 34:
+#line 399 "getdate.y"
+ {
+ /* e.g. JUN-17-1992. */
+ pc->month = yyvsp[-2].intval;
+ pc->day = -yyvsp[-1].textintval.value;
+ pc->year.value = -yyvsp[0].textintval.value;
+ pc->year.digits = yyvsp[0].textintval.digits;
+ }
+ break;
+
+ case 35:
+#line 407 "getdate.y"
+ {
+ pc->month = yyvsp[-1].intval;
+ pc->day = yyvsp[0].textintval.value;
+ }
+ break;
+
+ case 36:
+#line 412 "getdate.y"
+ {
+ pc->month = yyvsp[-3].intval;
+ pc->day = yyvsp[-2].textintval.value;
+ pc->year = yyvsp[0].textintval;
+ }
+ break;
+
+ case 37:
+#line 418 "getdate.y"
+ {
+ pc->day = yyvsp[-1].textintval.value;
+ pc->month = yyvsp[0].intval;
+ }
+ break;
+
+ case 38:
+#line 423 "getdate.y"
+ {
+ pc->day = yyvsp[-2].textintval.value;
+ pc->month = yyvsp[-1].intval;
+ pc->year = yyvsp[0].textintval;
+ }
+ break;
+
+ case 39:
+#line 432 "getdate.y"
+ {
+ pc->rel_ns = -pc->rel_ns;
+ pc->rel_seconds = -pc->rel_seconds;
+ pc->rel_minutes = -pc->rel_minutes;
+ pc->rel_hour = -pc->rel_hour;
+ pc->rel_day = -pc->rel_day;
+ pc->rel_month = -pc->rel_month;
+ pc->rel_year = -pc->rel_year;
+ }
+ break;
+
+ case 41:
+#line 446 "getdate.y"
+ { pc->rel_year += yyvsp[-1].intval * yyvsp[0].intval; }
+ break;
+
+ case 42:
+#line 448 "getdate.y"
+ { pc->rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 43:
+#line 450 "getdate.y"
+ { pc->rel_year += yyvsp[0].intval; }
+ break;
+
+ case 44:
+#line 452 "getdate.y"
+ { pc->rel_month += yyvsp[-1].intval * yyvsp[0].intval; }
+ break;
+
+ case 45:
+#line 454 "getdate.y"
+ { pc->rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 46:
+#line 456 "getdate.y"
+ { pc->rel_month += yyvsp[0].intval; }
+ break;
+
+ case 47:
+#line 458 "getdate.y"
+ { pc->rel_day += yyvsp[-1].intval * yyvsp[0].intval; }
+ break;
+
+ case 48:
+#line 460 "getdate.y"
+ { pc->rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 49:
+#line 462 "getdate.y"
+ { pc->rel_day += yyvsp[0].intval; }
+ break;
+
+ case 50:
+#line 464 "getdate.y"
+ { pc->rel_hour += yyvsp[-1].intval * yyvsp[0].intval; }
+ break;
+
+ case 51:
+#line 466 "getdate.y"
+ { pc->rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 52:
+#line 468 "getdate.y"
+ { pc->rel_hour += yyvsp[0].intval; }
+ break;
+
+ case 53:
+#line 470 "getdate.y"
+ { pc->rel_minutes += yyvsp[-1].intval * yyvsp[0].intval; }
+ break;
+
+ case 54:
+#line 472 "getdate.y"
+ { pc->rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 55:
+#line 474 "getdate.y"
+ { pc->rel_minutes += yyvsp[0].intval; }
+ break;
+
+ case 56:
+#line 476 "getdate.y"
+ { pc->rel_seconds += yyvsp[-1].intval * yyvsp[0].intval; }
+ break;
+
+ case 57:
+#line 478 "getdate.y"
+ { pc->rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 58:
+#line 480 "getdate.y"
+ { pc->rel_seconds += yyvsp[-1].timespec.tv_sec * yyvsp[0].intval; pc->rel_ns += yyvsp[-1].timespec.tv_nsec * yyvsp[0].intval; }
+ break;
+
+ case 59:
+#line 482 "getdate.y"
+ { pc->rel_seconds += yyvsp[-1].timespec.tv_sec * yyvsp[0].intval; pc->rel_ns += yyvsp[-1].timespec.tv_nsec * yyvsp[0].intval; }
+ break;
+
+ case 60:
+#line 484 "getdate.y"
+ { pc->rel_seconds += yyvsp[0].intval; }
+ break;
+
+ case 62:
+#line 490 "getdate.y"
+ { pc->rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 63:
+#line 492 "getdate.y"
+ { pc->rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 64:
+#line 494 "getdate.y"
+ { pc->rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 65:
+#line 496 "getdate.y"
+ { pc->rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 66:
+#line 498 "getdate.y"
+ { pc->rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 67:
+#line 500 "getdate.y"
+ { pc->rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 71:
+#line 508 "getdate.y"
+ { yyval.timespec.tv_sec = yyvsp[0].textintval.value; yyval.timespec.tv_nsec = 0; }
+ break;
+
+ case 73:
+#line 514 "getdate.y"
+ { yyval.timespec.tv_sec = yyvsp[0].textintval.value; yyval.timespec.tv_nsec = 0; }
+ break;
+
+ case 74:
+#line 519 "getdate.y"
+ {
+ if (pc->dates_seen && ! pc->year.digits
+ && ! pc->rels_seen && (pc->times_seen || 2 < yyvsp[0].textintval.digits))
+ pc->year = yyvsp[0].textintval;
+ else
+ {
+ if (4 < yyvsp[0].textintval.digits)
+ {
+ pc->dates_seen++;
+ pc->day = yyvsp[0].textintval.value % 100;
+ pc->month = (yyvsp[0].textintval.value / 100) % 100;
+ pc->year.value = yyvsp[0].textintval.value / 10000;
+ pc->year.digits = yyvsp[0].textintval.digits - 4;
+ }
+ else
+ {
+ pc->times_seen++;
+ if (yyvsp[0].textintval.digits <= 2)
+ {
+ pc->hour = yyvsp[0].textintval.value;
+ pc->minutes = 0;
+ }
+ else
+ {
+ pc->hour = yyvsp[0].textintval.value / 100;
+ pc->minutes = yyvsp[0].textintval.value % 100;
+ }
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = MER24;
+ }
+ }
+ }
+ break;
+
+ case 75:
+#line 556 "getdate.y"
+ { yyval.intval = -1; }
+ break;
+
+ case 76:
+#line 558 "getdate.y"
+ { yyval.intval = yyvsp[0].textintval.value; }
+ break;
+
+ case 77:
+#line 563 "getdate.y"
+ { yyval.intval = MER24; }
+ break;
+
+ case 78:
+#line 565 "getdate.y"
+ { yyval.intval = yyvsp[0].intval; }
+ break;
+
+
+ }
+
+/* Line 1000 of yacc.c. */
+#line 1782 "getdate.c"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ const char* yyprefix;
+ char *yymsg;
+ int yyx;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 0;
+
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+ yycount += 1;
+ if (yycount == 5)
+ {
+ yysize = 0;
+ break;
+ }
+ }
+ yysize += (sizeof ("syntax error, unexpected ")
+ + yystrlen (yytname[yytype]));
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yyp = yystpcpy (yyp, yyprefix);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yyprefix = " or ";
+ }
+ }
+ yyerror (pc, yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror (pc, "syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror (pc, "syntax error");
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* If at end of input, pop the error token,
+ then the rest of the stack, then return failure. */
+ if (yychar == YYEOF)
+ for (;;)
+ {
+ YYPOPSTACK;
+ if (yyssp == yyss)
+ YYABORT;
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ }
+ }
+ else
+ {
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+ /* Pacify GCC when the user code never invokes YYERROR and the label
+ yyerrorlab therefore never appears in user code. */
+ if (0)
+ goto yyerrorlab;
+#endif
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror (pc, "parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 568 "getdate.y"
+
+
+static table const meridian_table[] =
+{
+ { "AM", tMERIDIAN, MERam },
+ { "A.M.", tMERIDIAN, MERam },
+ { "PM", tMERIDIAN, MERpm },
+ { "P.M.", tMERIDIAN, MERpm },
+ { NULL, 0, 0 }
+};
+
+static table const dst_table[] =
+{
+ { "DST", tDST, 0 }
+};
+
+static table const month_and_day_table[] =
+{
+ { "JANUARY", tMONTH, 1 },
+ { "FEBRUARY", tMONTH, 2 },
+ { "MARCH", tMONTH, 3 },
+ { "APRIL", tMONTH, 4 },
+ { "MAY", tMONTH, 5 },
+ { "JUNE", tMONTH, 6 },
+ { "JULY", tMONTH, 7 },
+ { "AUGUST", tMONTH, 8 },
+ { "SEPTEMBER",tMONTH, 9 },
+ { "SEPT", tMONTH, 9 },
+ { "OCTOBER", tMONTH, 10 },
+ { "NOVEMBER", tMONTH, 11 },
+ { "DECEMBER", tMONTH, 12 },
+ { "SUNDAY", tDAY, 0 },
+ { "MONDAY", tDAY, 1 },
+ { "TUESDAY", tDAY, 2 },
+ { "TUES", tDAY, 2 },
+ { "WEDNESDAY",tDAY, 3 },
+ { "WEDNES", tDAY, 3 },
+ { "THURSDAY", tDAY, 4 },
+ { "THUR", tDAY, 4 },
+ { "THURS", tDAY, 4 },
+ { "FRIDAY", tDAY, 5 },
+ { "SATURDAY", tDAY, 6 },
+ { NULL, 0, 0 }
+};
+
+static table const time_units_table[] =
+{
+ { "YEAR", tYEAR_UNIT, 1 },
+ { "MONTH", tMONTH_UNIT, 1 },
+ { "FORTNIGHT",tDAY_UNIT, 14 },
+ { "WEEK", tDAY_UNIT, 7 },
+ { "DAY", tDAY_UNIT, 1 },
+ { "HOUR", tHOUR_UNIT, 1 },
+ { "MINUTE", tMINUTE_UNIT, 1 },
+ { "MIN", tMINUTE_UNIT, 1 },
+ { "SECOND", tSEC_UNIT, 1 },
+ { "SEC", tSEC_UNIT, 1 },
+ { NULL, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static table const relative_time_table[] =
+{
+ { "TOMORROW", tDAY_UNIT, 1 },
+ { "YESTERDAY",tDAY_UNIT, -1 },
+ { "TODAY", tDAY_UNIT, 0 },
+ { "NOW", tDAY_UNIT, 0 },
+ { "LAST", tORDINAL, -1 },
+ { "THIS", tORDINAL, 0 },
+ { "NEXT", tORDINAL, 1 },
+ { "FIRST", tORDINAL, 1 },
+/*{ "SECOND", tORDINAL, 2 }, */
+ { "THIRD", tORDINAL, 3 },
+ { "FOURTH", tORDINAL, 4 },
+ { "FIFTH", tORDINAL, 5 },
+ { "SIXTH", tORDINAL, 6 },
+ { "SEVENTH", tORDINAL, 7 },
+ { "EIGHTH", tORDINAL, 8 },
+ { "NINTH", tORDINAL, 9 },
+ { "TENTH", tORDINAL, 10 },
+ { "ELEVENTH", tORDINAL, 11 },
+ { "TWELFTH", tORDINAL, 12 },
+ { "AGO", tAGO, 1 },
+ { NULL, 0, 0 }
+};
+
+/* The universal time zone table. These labels can be used even for
+ time stamps that would not otherwise be valid, e.g., GMT time
+ stamps in London during summer. */
+static table const universal_time_zone_table[] =
+{
+ { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */
+ { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
+ { "UTC", tZONE, HOUR ( 0) },
+ { NULL, 0, 0 }
+};
+
+/* The time zone table. This table is necessarily incomplete, as time
+ zone abbreviations are ambiguous; e.g. Australians interpret "EST"
+ as Eastern time in Australia, not as US Eastern Standard Time.
+ You cannot rely on getdate to handle arbitrary time zone
+ abbreviations; use numeric abbreviations like `-0500' instead. */
+static table const time_zone_table[] =
+{
+ { "WET", tZONE, HOUR ( 0) }, /* Western European */
+ { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */
+ { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */
+ { "ART", tZONE, -HOUR ( 3) }, /* Argentina */
+ { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */
+ { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
+ { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */
+ { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */
+ { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */
+ { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
+ { "CLT", tZONE, -HOUR ( 4) }, /* Chile */
+ { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
+ { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */
+ { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
+ { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */
+ { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
+ { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */
+ { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
+ { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */
+ { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
+ { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */
+ { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
+ { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */
+ { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */
+ { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
+ { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */
+ { "WAT", tZONE, HOUR ( 1) }, /* West Africa */
+ { "CET", tZONE, HOUR ( 1) }, /* Central European */
+ { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */
+ { "MET", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "EET", tZONE, HOUR ( 2) }, /* Eastern European */
+ { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */
+ { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */
+ { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */
+ { "EAT", tZONE, HOUR ( 3) }, /* East Africa */
+ { "MSK", tZONE, HOUR ( 3) }, /* Moscow */
+ { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */
+ { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */
+ { "SGT", tZONE, HOUR ( 8) }, /* Singapore */
+ { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */
+ { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */
+ { "GST", tZONE, HOUR (10) }, /* Guam Standard */
+ { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */
+ { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */
+ { NULL, 0, 0 }
+};
+
+/* Military time zone table. */
+static table const military_table[] =
+{
+ { "A", tZONE, -HOUR ( 1) },
+ { "B", tZONE, -HOUR ( 2) },
+ { "C", tZONE, -HOUR ( 3) },
+ { "D", tZONE, -HOUR ( 4) },
+ { "E", tZONE, -HOUR ( 5) },
+ { "F", tZONE, -HOUR ( 6) },
+ { "G", tZONE, -HOUR ( 7) },
+ { "H", tZONE, -HOUR ( 8) },
+ { "I", tZONE, -HOUR ( 9) },
+ { "K", tZONE, -HOUR (10) },
+ { "L", tZONE, -HOUR (11) },
+ { "M", tZONE, -HOUR (12) },
+ { "N", tZONE, HOUR ( 1) },
+ { "O", tZONE, HOUR ( 2) },
+ { "P", tZONE, HOUR ( 3) },
+ { "Q", tZONE, HOUR ( 4) },
+ { "R", tZONE, HOUR ( 5) },
+ { "S", tZONE, HOUR ( 6) },
+ { "T", tZONE, HOUR ( 7) },
+ { "U", tZONE, HOUR ( 8) },
+ { "V", tZONE, HOUR ( 9) },
+ { "W", tZONE, HOUR (10) },
+ { "X", tZONE, HOUR (11) },
+ { "Y", tZONE, HOUR (12) },
+ { "Z", tZONE, HOUR ( 0) },
+ { NULL, 0, 0 }
+};
+
+
+
+/* Convert a time zone expressed as HH:MM into an integer count of
+ minutes. If MM is negative, then S is of the form HHMM and needs
+ to be picked apart; otherwise, S is of the form HH. */
+
+static long int
+time_zone_hhmm (textint s, long int mm)
+{
+ if (mm < 0)
+ return (s.value / 100) * 60 + s.value % 100;
+ else
+ return s.value * 60 + (s.negative ? -mm : mm);
+}
+
+static int
+to_hour (long int hours, int meridian)
+{
+ switch (meridian)
+ {
+ default: /* Pacify GCC. */
+ case MER24:
+ return 0 <= hours && hours < 24 ? hours : -1;
+ case MERam:
+ return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
+ case MERpm:
+ return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
+ }
+}
+
+static long int
+to_year (textint textyear)
+{
+ long int year = textyear.value;
+
+ if (year < 0)
+ year = -year;
+
+ /* XPG4 suggests that years 00-68 map to 2000-2068, and
+ years 69-99 map to 1969-1999. */
+ else if (textyear.digits == 2)
+ year += year < 69 ? 2000 : 1900;
+
+ return year;
+}
+
+static table const *
+lookup_zone (parser_control const *pc, char const *name)
+{
+ table const *tp;
+
+ for (tp = universal_time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ /* Try local zone abbreviations before those in time_zone_table, as
+ the local ones are more likely to be right. */
+ for (tp = pc->local_time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ for (tp = time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ return NULL;
+}
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds.
+ The body of this function is taken directly from the GNU C Library;
+ see src/strftime.c. */
+static long int
+tm_diff (struct tm const *a, struct tm const *b)
+{
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations. */
+ int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
+ int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = SHR (a100, 2);
+ int b400 = SHR (b100, 2);
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ long int ayear = a->tm_year;
+ long int years = ayear - b->tm_year;
+ long int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+static table const *
+lookup_word (parser_control const *pc, char *word)
+{
+ char *p;
+ char *q;
+ size_t wordlen;
+ table const *tp;
+ bool period_found;
+ bool abbrev;
+
+ /* Make it uppercase. */
+ for (p = word; *p; p++)
+ {
+ unsigned char ch = *p;
+ if (ISLOWER (ch))
+ *p = toupper (ch);
+ }
+
+ for (tp = meridian_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* See if we have an abbreviation for a month. */
+ wordlen = strlen (word);
+ abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
+
+ for (tp = month_and_day_table; tp->name; tp++)
+ if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
+ return tp;
+
+ if ((tp = lookup_zone (pc, word)))
+ return tp;
+
+ if (strcmp (word, dst_table[0].name) == 0)
+ return dst_table;
+
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Strip off any plural and try the units table again. */
+ if (word[wordlen - 1] == 'S')
+ {
+ word[wordlen - 1] = '\0';
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+ word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */
+ }
+
+ for (tp = relative_time_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Military time zones. */
+ if (wordlen == 1)
+ for (tp = military_table; tp->name; tp++)
+ if (word[0] == tp->name[0])
+ return tp;
+
+ /* Drop out any periods and try the time zone table again. */
+ for (period_found = false, p = q = word; (*p = *q); q++)
+ if (*q == '.')
+ period_found = true;
+ else
+ p++;
+ if (period_found && (tp = lookup_zone (pc, word)))
+ return tp;
+
+ return NULL;
+}
+
+static int
+yylex (YYSTYPE *lvalp, parser_control *pc)
+{
+ unsigned char c;
+ size_t count;
+
+ for (;;)
+ {
+ while (c = *pc->input, ISSPACE (c))
+ pc->input++;
+
+ if (ISDIGIT (c) || c == '-' || c == '+')
+ {
+ char const *p;
+ int sign;
+ unsigned long int value;
+ if (c == '-' || c == '+')
+ {
+ sign = c == '-' ? -1 : 1;
+ while (c = *++pc->input, ISSPACE (c))
+ continue;
+ if (! ISDIGIT (c))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ p = pc->input;
+ for (value = 0; ; value *= 10)
+ {
+ unsigned long int value1 = value + (c - '0');
+ if (value1 < value)
+ return '?';
+ value = value1;
+ c = *++p;
+ if (! ISDIGIT (c))
+ break;
+ if (ULONG_MAX / 10 < value)
+ return '?';
+ }
+ if ((c == '.' || c == ',') && ISDIGIT (p[1]))
+ {
+ time_t s;
+ int ns;
+ int digits;
+ unsigned long int value1;
+
+ /* Check for overflow when converting value to time_t. */
+ if (sign < 0)
+ {
+ s = - value;
+ if (0 < s)
+ return '?';
+ value1 = -s;
+ }
+ else
+ {
+ s = value;
+ if (s < 0)
+ return '?';
+ value1 = s;
+ }
+ if (value != value1)
+ return '?';
+
+ /* Accumulate fraction, to ns precision. */
+ p++;
+ ns = *p++ - '0';
+ for (digits = 2; digits <= LOG10_BILLION; digits++)
+ {
+ ns *= 10;
+ if (ISDIGIT (*p))
+ ns += *p++ - '0';
+ }
+
+ /* Skip excess digits, truncating toward -Infinity. */
+ if (sign < 0)
+ for (; ISDIGIT (*p); p++)
+ if (*p != '0')
+ {
+ ns++;
+ break;
+ }
+ while (ISDIGIT (*p))
+ p++;
+
+ /* Adjust to the timespec convention, which is that
+ tv_nsec is always a positive offset even if tv_sec is
+ negative. */
+ if (sign < 0 && ns)
+ {
+ s--;
+ if (! (s < 0))
+ return '?';
+ ns = BILLION - ns;
+ }
+
+ lvalp->timespec.tv_sec = s;
+ lvalp->timespec.tv_nsec = ns;
+ pc->input = p;
+ return sign ? tSDECIMAL_NUMBER : tUDECIMAL_NUMBER;
+ }
+ else
+ {
+ lvalp->textintval.negative = sign < 0;
+ if (sign < 0)
+ {
+ lvalp->textintval.value = - value;
+ if (0 < lvalp->textintval.value)
+ return '?';
+ }
+ else
+ {
+ lvalp->textintval.value = value;
+ if (lvalp->textintval.value < 0)
+ return '?';
+ }
+ lvalp->textintval.digits = p - pc->input;
+ pc->input = p;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ }
+
+ if (ISALPHA (c))
+ {
+ char buff[20];
+ char *p = buff;
+ table const *tp;
+
+ do
+ {
+ if (p < buff + sizeof buff - 1)
+ *p++ = c;
+ c = *++pc->input;
+ }
+ while (ISALPHA (c) || c == '.');
+
+ *p = '\0';
+ tp = lookup_word (pc, buff);
+ if (! tp)
+ return '?';
+ lvalp->intval = tp->value;
+ return tp->type;
+ }
+
+ if (c != '(')
+ return *pc->input++;
+ count = 0;
+ do
+ {
+ c = *pc->input++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ count++;
+ else if (c == ')')
+ count--;
+ }
+ while (count != 0);
+ }
+}
+
+/* Do nothing if the parser reports an error. */
+static int
+yyerror (parser_control *pc ATTRIBUTE_UNUSED, char *s ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* If *TM0 is the old and *TM1 is the new value of a struct tm after
+ passing it to mktime, return true if it's OK that mktime returned T.
+ It's not OK if *TM0 has out-of-range members. */
+
+static bool
+mktime_ok (struct tm const *tm0, struct tm const *tm1, time_t t)
+{
+ if (t == (time_t) -1)
+ {
+ /* Guard against falsely reporting an error when parsing a time
+ stamp that happens to equal (time_t) -1, on a host that
+ supports such a time stamp. */
+ tm1 = localtime (&t);
+ if (!tm1)
+ return false;
+ }
+
+ return ! ((tm0->tm_sec ^ tm1->tm_sec)
+ | (tm0->tm_min ^ tm1->tm_min)
+ | (tm0->tm_hour ^ tm1->tm_hour)
+ | (tm0->tm_mday ^ tm1->tm_mday)
+ | (tm0->tm_mon ^ tm1->tm_mon)
+ | (tm0->tm_year ^ tm1->tm_year));
+}
+
+/* A reasonable upper bound for the size of ordinary TZ strings.
+ Use heap allocation if TZ's length exceeds this. */
+enum { TZBUFSIZE = 100 };
+
+/* Return a copy of TZ, stored in TZBUF if it fits, and heap-allocated
+ otherwise. */
+static char *
+get_tz (char tzbuf[TZBUFSIZE])
+{
+ char *tz = getenv ("TZ");
+ if (tz)
+ {
+ size_t tzsize = strlen (tz) + 1;
+ tz = (tzsize <= TZBUFSIZE
+ ? memcpy (tzbuf, tz, tzsize)
+ : xmemdup (tz, tzsize));
+ }
+ return tz;
+}
+
+/* Parse a date/time string, storing the resulting time value into *RESULT.
+ The string itself is pointed to by P. Return true if successful.
+ P can be an incomplete or relative time specification; if so, use
+ *NOW as the basis for the returned time. */
+bool
+get_date (struct timespec *result, char const *p, struct timespec const *now)
+{
+ time_t Start;
+ long int Start_ns;
+ struct tm const *tmp;
+ struct tm tm;
+ struct tm tm0;
+ parser_control pc;
+ struct timespec gettime_buffer;
+ unsigned char c;
+ bool tz_was_altered = false;
+ char *tz0 = NULL;
+ char tz0buf[TZBUFSIZE];
+ bool ok = true;
+
+ if (! now)
+ {
+ gettime (&gettime_buffer);
+ now = &gettime_buffer;
+ }
+
+ Start = now->tv_sec;
+ Start_ns = now->tv_nsec;
+
+ tmp = localtime (&now->tv_sec);
+ if (! tmp)
+ return false;
+
+ while (c = *p, ISSPACE (c))
+ p++;
+
+ if (strncmp (p, "TZ=\"", 4) == 0)
+ {
+ char const *tzbase = p + 4;
+ size_t tzsize = 1;
+ char const *s;
+
+ for (s = tzbase; *s; s++, tzsize++)
+ if (*s == '\\')
+ {
+ s++;
+ if (! (*s == '\\' || *s == '"'))
+ break;
+ }
+ else if (*s == '"')
+ {
+ char *z;
+ char *tz1;
+ char tz1buf[TZBUFSIZE];
+ bool large_tz = TZBUFSIZE < tzsize;
+ bool setenv_ok;
+ tz0 = get_tz (tz0buf);
+ z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf;
+ for (s = tzbase; *s != '"'; s++)
+ *z++ = *(s += *s == '\\');
+ *z = '\0';
+ setenv_ok = setenv ("TZ", tz1, 1) == 0;
+ if (large_tz)
+ free (tz1);
+ if (!setenv_ok)
+ goto fail;
+ tz_was_altered = true;
+ p = s + 1;
+ }
+ }
+
+ pc.input = p;
+ pc.year.value = tmp->tm_year;
+ pc.year.value += TM_YEAR_BASE;
+ pc.year.digits = 0;
+ pc.month = tmp->tm_mon + 1;
+ pc.day = tmp->tm_mday;
+ pc.hour = tmp->tm_hour;
+ pc.minutes = tmp->tm_min;
+ pc.seconds.tv_sec = tmp->tm_sec;
+ pc.seconds.tv_nsec = Start_ns;
+ tm.tm_isdst = tmp->tm_isdst;
+
+ pc.meridian = MER24;
+ pc.rel_ns = 0;
+ pc.rel_seconds = 0;
+ pc.rel_minutes = 0;
+ pc.rel_hour = 0;
+ pc.rel_day = 0;
+ pc.rel_month = 0;
+ pc.rel_year = 0;
+ pc.timespec_seen = false;
+ pc.rels_seen = false;
+ pc.dates_seen = 0;
+ pc.days_seen = 0;
+ pc.times_seen = 0;
+ pc.local_zones_seen = 0;
+ pc.dsts_seen = 0;
+ pc.zones_seen = 0;
+
+#if HAVE_STRUCT_TM_TM_ZONE
+ pc.local_time_zone_table[0].name = tmp->tm_zone;
+ pc.local_time_zone_table[0].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[0].value = tmp->tm_isdst;
+ pc.local_time_zone_table[1].name = NULL;
+
+ /* Probe the names used in the next three calendar quarters, looking
+ for a tm_isdst different from the one we already have. */
+ {
+ int quarter;
+ for (quarter = 1; quarter <= 3; quarter++)
+ {
+ time_t probe = Start + quarter * (90 * 24 * 60 * 60);
+ struct tm const *probe_tm = localtime (&probe);
+ if (probe_tm && probe_tm->tm_zone
+ && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
+ {
+ {
+ pc.local_time_zone_table[1].name = probe_tm->tm_zone;
+ pc.local_time_zone_table[1].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
+ pc.local_time_zone_table[2].name = NULL;
+ }
+ break;
+ }
+ }
+ }
+#else
+#if HAVE_TZNAME
+ {
+# ifndef tzname
+ extern char *tzname[];
+# endif
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ pc.local_time_zone_table[i].name = tzname[i];
+ pc.local_time_zone_table[i].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[i].value = i;
+ }
+ pc.local_time_zone_table[i].name = NULL;
+ }
+#else
+ pc.local_time_zone_table[0].name = NULL;
+#endif
+#endif
+
+ if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
+ && ! strcmp (pc.local_time_zone_table[0].name,
+ pc.local_time_zone_table[1].name))
+ {
+ /* This locale uses the same abbrevation for standard and
+ daylight times. So if we see that abbreviation, we don't
+ know whether it's daylight time. */
+ pc.local_time_zone_table[0].value = -1;
+ pc.local_time_zone_table[1].name = NULL;
+ }
+
+ if (yyparse (&pc) != 0)
+ goto fail;
+
+ if (pc.timespec_seen)
+ *result = pc.seconds;
+ else
+ {
+ if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen
+ | (pc.local_zones_seen + pc.zones_seen)))
+ goto fail;
+
+ tm.tm_year = to_year (pc.year) - TM_YEAR_BASE;
+ tm.tm_mon = pc.month - 1;
+ tm.tm_mday = pc.day;
+ if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
+ {
+ tm.tm_hour = to_hour (pc.hour, pc.meridian);
+ if (tm.tm_hour < 0)
+ goto fail;
+ tm.tm_min = pc.minutes;
+ tm.tm_sec = pc.seconds.tv_sec;
+ }
+ else
+ {
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ pc.seconds.tv_nsec = 0;
+ }
+
+ /* Let mktime deduce tm_isdst if we have an absolute time stamp. */
+ if (!pc.rels_seen)
+ tm.tm_isdst = -1;
+
+ /* But if the input explicitly specifies local time with or without
+ DST, give mktime that information. */
+ if (pc.local_zones_seen)
+ tm.tm_isdst = pc.local_isdst;
+
+ tm0 = tm;
+
+ Start = mktime (&tm);
+
+ if (! mktime_ok (&tm0, &tm, Start))
+ {
+ if (! pc.zones_seen)
+ goto fail;
+ else
+ {
+ /* Guard against falsely reporting errors near the time_t
+ boundaries when parsing times in other time zones. For
+ example, suppose the input string "1969-12-31 23:00:00 -0100",
+ the current time zone is 8 hours ahead of UTC, and the min
+ time_t value is 1970-01-01 00:00:00 UTC. Then the min
+ localtime value is 1970-01-01 08:00:00, and mktime will
+ therefore fail on 1969-12-31 23:00:00. To work around the
+ problem, set the time zone to 1 hour behind UTC temporarily
+ by setting TZ="XXX1:00" and try mktime again. */
+
+ long int time_zone = pc.time_zone;
+ long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone;
+ long int abs_time_zone_hour = abs_time_zone / 60;
+ int abs_time_zone_min = abs_time_zone % 60;
+ char tz1buf[sizeof "XXX+0:00"
+ + sizeof pc.time_zone * CHAR_BIT / 3];
+ if (!tz_was_altered)
+ tz0 = get_tz (tz0buf);
+ sprintf (tz1buf, "XXX%s%ld:%02d", "-" + (time_zone < 0),
+ abs_time_zone_hour, abs_time_zone_min);
+ if (setenv ("TZ", tz1buf, 1) != 0)
+ goto fail;
+ tz_was_altered = true;
+ tm = tm0;
+ Start = mktime (&tm);
+ if (! mktime_ok (&tm0, &tm, Start))
+ goto fail;
+ }
+ }
+
+ if (pc.days_seen && ! pc.dates_seen)
+ {
+ tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
+ + 7 * (pc.day_ordinal - (0 < pc.day_ordinal)));
+ tm.tm_isdst = -1;
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ goto fail;
+ }
+
+ if (pc.zones_seen)
+ {
+ long int delta = pc.time_zone * 60;
+ time_t t1;
+#ifdef HAVE_TM_GMTOFF
+ delta -= tm.tm_gmtoff;
+#else
+ time_t t = Start;
+ struct tm const *gmt = gmtime (&t);
+ if (! gmt)
+ goto fail;
+ delta -= tm_diff (&tm, gmt);
+#endif
+ t1 = Start - delta;
+ if ((Start < t1) != (delta < 0))
+ goto fail; /* time_t overflow */
+ Start = t1;
+ }
+
+ /* Add relative date. */
+ if (pc.rel_year | pc.rel_month | pc.rel_day)
+ {
+ int year = tm.tm_year + pc.rel_year;
+ int month = tm.tm_mon + pc.rel_month;
+ int day = tm.tm_mday + pc.rel_day;
+ if (((year < tm.tm_year) ^ (pc.rel_year < 0))
+ | ((month < tm.tm_mon) ^ (pc.rel_month < 0))
+ | ((day < tm.tm_mday) ^ (pc.rel_day < 0)))
+ goto fail;
+ tm.tm_year = year;
+ tm.tm_mon = month;
+ tm.tm_mday = day;
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ goto fail;
+ }
+
+ /* Add relative hours, minutes, and seconds. On hosts that support
+ leap seconds, ignore the possibility of leap seconds; e.g.,
+ "+ 10 minutes" adds 600 seconds, even if one of them is a
+ leap second. Typically this is not what the user wants, but it's
+ too hard to do it the other way, because the time zone indicator
+ must be applied before relative times, and if mktime is applied
+ again the time zone will be lost. */
+ {
+ long int sum_ns = pc.seconds.tv_nsec + pc.rel_ns;
+ long int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION;
+ time_t t0 = Start;
+ long int d1 = 60 * 60 * pc.rel_hour;
+ time_t t1 = t0 + d1;
+ long int d2 = 60 * pc.rel_minutes;
+ time_t t2 = t1 + d2;
+ long int d3 = pc.rel_seconds;
+ time_t t3 = t2 + d3;
+ long int d4 = (sum_ns - normalized_ns) / BILLION;
+ time_t t4 = t3 + d4;
+
+ if ((d1 / (60 * 60) ^ pc.rel_hour)
+ | (d2 / 60 ^ pc.rel_minutes)
+ | ((t1 < t0) ^ (d1 < 0))
+ | ((t2 < t1) ^ (d2 < 0))
+ | ((t3 < t2) ^ (d3 < 0))
+ | ((t4 < t3) ^ (d4 < 0)))
+ goto fail;
+
+ result->tv_sec = t4;
+ result->tv_nsec = normalized_ns;
+ }
+ }
+
+ goto done;
+
+ fail:
+ ok = false;
+ done:
+ if (tz_was_altered)
+ ok &= (tz0 ? setenv ("TZ", tz0, 1) : unsetenv ("TZ")) == 0;
+ if (tz0 != tz0buf)
+ free (tz0);
+ return ok;
+}
+
+#if TEST
+
+int
+main (int ac, char **av)
+{
+ char buff[BUFSIZ];
+
+ printf ("Enter date, or blank line to exit.\n\t> ");
+ fflush (stdout);
+
+ buff[BUFSIZ - 1] = '\0';
+ while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
+ {
+ struct timespec d;
+ struct tm const *tm;
+ if (! get_date (&d, buff, NULL))
+ printf ("Bad format - couldn't convert.\n");
+ else if (! (tm = localtime (&d.tv_sec)))
+ {
+ long int sec = d.tv_sec;
+ printf ("localtime (%ld) failed\n", sec);
+ }
+ else
+ {
+ int ns = d.tv_nsec;
+ printf ("%04ld-%02d-%02d %02d:%02d:%02d.%09d\n",
+ tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, ns);
+ }
+ printf ("\t> ");
+ fflush (stdout);
+ }
+ return 0;
+}
+#endif /* TEST */
+
+
diff --git a/lib/getdate.h b/lib/getdate.h
new file mode 100644
index 0000000..4694cdb
--- /dev/null
+++ b/lib/getdate.h
@@ -0,0 +1,22 @@
+/* Parse a string into an internal time stamp.
+
+ Copyright (C) 1995, 1997, 1998, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <stdbool.h>
+#include "timespec.h"
+
+bool get_date (struct timespec *, char const *, struct timespec const *);
diff --git a/lib/getdate.y b/lib/getdate.y
new file mode 100644
index 0000000..868f983
--- /dev/null
+++ b/lib/getdate.y
@@ -0,0 +1,1495 @@
+%{
+/* Parse a string into an internal time stamp.
+
+ Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Originally written by Steven M. Bellovin <smb@research.att.com> while
+ at the University of North Carolina at Chapel Hill. Later tweaked by
+ a couple of people on Usenet. Completely overhauled by Rich $alz
+ <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+
+ Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
+ the right thing about local DST. Also modified by Paul Eggert
+ <eggert@cs.ucla.edu> in February 2004 to support
+ nanosecond-resolution time stamps, and in October 2004 to support
+ TZ strings in dates. */
+
+/* FIXME: Check for arithmetic overflow in all cases, not just
+ some of them. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getdate.h"
+
+/* There's no need to extend the stack, so there's no need to involve
+ alloca. */
+#define YYSTACK_USE_ALLOCA 0
+
+/* Tell Bison how much stack space is needed. 20 should be plenty for
+ this grammar, which is not right recursive. Beware setting it too
+ high, since that might cause problems on machines whose
+ implementations have lame stack-overflow checking. */
+#define YYMAXDEPTH 20
+#define YYINITDEPTH YYMAXDEPTH
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+# undef static
+#endif
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "setenv.h"
+#include "xalloc.h"
+
+#if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii (c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
+
+/* ISDIGIT differs from isdigit, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
+ isdigit unless it's important to use the locale's definition
+ of `digit' even when the host does not conform to POSIX. */
+#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+/* Shift A right by B bits portably, by dividing A by 2**B and
+ truncating towards minus infinity. A and B should be free of side
+ effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
+ INT_BITS is the number of useful bits in an int. GNU code can
+ assume that INT_BITS is at least 32.
+
+ ISO C99 says that A >> B is implementation-defined if A < 0. Some
+ implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
+ right in the usual way when A < 0, so SHR falls back on division if
+ ordinary A >> B doesn't seem to be the usual signed shift. */
+#define SHR(a, b) \
+ (-1 >> 1 == -1 \
+ ? (a) >> (b) \
+ : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
+
+#define EPOCH_YEAR 1970
+#define TM_YEAR_BASE 1900
+
+#define HOUR(x) ((x) * 60)
+
+/* An integer value, and the number of digits in its textual
+ representation. */
+typedef struct
+{
+ bool negative;
+ long int value;
+ size_t digits;
+} textint;
+
+/* An entry in the lexical lookup table. */
+typedef struct
+{
+ char const *name;
+ int type;
+ int value;
+} table;
+
+/* Meridian: am, pm, or 24-hour style. */
+enum { MERam, MERpm, MER24 };
+
+enum { BILLION = 1000000000, LOG10_BILLION = 9 };
+
+/* Information passed to and from the parser. */
+typedef struct
+{
+ /* The input string remaining to be parsed. */
+ const char *input;
+
+ /* N, if this is the Nth Tuesday. */
+ long int day_ordinal;
+
+ /* Day of week; Sunday is 0. */
+ int day_number;
+
+ /* tm_isdst flag for the local zone. */
+ int local_isdst;
+
+ /* Time zone, in minutes east of UTC. */
+ long int time_zone;
+
+ /* Style used for time. */
+ int meridian;
+
+ /* Gregorian year, month, day, hour, minutes, seconds, and nanoseconds. */
+ textint year;
+ long int month;
+ long int day;
+ long int hour;
+ long int minutes;
+ struct timespec seconds; /* includes nanoseconds */
+
+ /* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */
+ long int rel_year;
+ long int rel_month;
+ long int rel_day;
+ long int rel_hour;
+ long int rel_minutes;
+ long int rel_seconds;
+ long int rel_ns;
+
+ /* Presence or counts of nonterminals of various flavors parsed so far. */
+ bool timespec_seen;
+ bool rels_seen;
+ size_t dates_seen;
+ size_t days_seen;
+ size_t local_zones_seen;
+ size_t dsts_seen;
+ size_t times_seen;
+ size_t zones_seen;
+
+ /* Table of local time zone abbrevations, terminated by a null entry. */
+ table local_time_zone_table[3];
+} parser_control;
+
+union YYSTYPE;
+static int yylex (union YYSTYPE *, parser_control *);
+static int yyerror (parser_control *, char *);
+static long int time_zone_hhmm (textint, long int);
+
+%}
+
+/* We want a reentrant parser, even if the TZ manipulation and the calls to
+ localtime and gmtime are not reentrant. */
+%pure-parser
+%parse-param { parser_control *pc }
+%lex-param { parser_control *pc }
+
+/* This grammar has 20 shift/reduce conflicts. */
+%expect 20
+
+%union
+{
+ long int intval;
+ textint textintval;
+ struct timespec timespec;
+}
+
+%token tAGO tDST
+
+%token <intval> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tLOCAL_ZONE tMERIDIAN
+%token <intval> tMINUTE_UNIT tMONTH tMONTH_UNIT tORDINAL
+%token <intval> tSEC_UNIT tYEAR_UNIT tZONE
+
+%token <textintval> tSNUMBER tUNUMBER
+%token <timespec> tSDECIMAL_NUMBER tUDECIMAL_NUMBER
+
+%type <intval> o_colon_minutes o_merid
+%type <timespec> seconds signed_seconds unsigned_seconds
+
+%%
+
+spec:
+ timespec
+ | items
+ ;
+
+timespec:
+ '@' seconds
+ {
+ pc->seconds = $2;
+ pc->timespec_seen = true;
+ }
+ ;
+
+items:
+ /* empty */
+ | items item
+ ;
+
+item:
+ time
+ { pc->times_seen++; }
+ | local_zone
+ { pc->local_zones_seen++; }
+ | zone
+ { pc->zones_seen++; }
+ | date
+ { pc->dates_seen++; }
+ | day
+ { pc->days_seen++; }
+ | rel
+ { pc->rels_seen = true; }
+ | number
+ ;
+
+time:
+ tUNUMBER tMERIDIAN
+ {
+ pc->hour = $1.value;
+ pc->minutes = 0;
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid
+ {
+ pc->hour = $1.value;
+ pc->minutes = $3.value;
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER o_colon_minutes
+ {
+ pc->hour = $1.value;
+ pc->minutes = $3.value;
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = MER24;
+ pc->zones_seen++;
+ pc->time_zone = time_zone_hhmm ($4, $5);
+ }
+ | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid
+ {
+ pc->hour = $1.value;
+ pc->minutes = $3.value;
+ pc->seconds = $5;
+ pc->meridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER o_colon_minutes
+ {
+ pc->hour = $1.value;
+ pc->minutes = $3.value;
+ pc->seconds = $5;
+ pc->meridian = MER24;
+ pc->zones_seen++;
+ pc->time_zone = time_zone_hhmm ($6, $7);
+ }
+ ;
+
+local_zone:
+ tLOCAL_ZONE
+ {
+ pc->local_isdst = $1;
+ pc->dsts_seen += (0 < $1);
+ }
+ | tLOCAL_ZONE tDST
+ {
+ pc->local_isdst = 1;
+ pc->dsts_seen += (0 < $1) + 1;
+ }
+ ;
+
+zone:
+ tZONE
+ { pc->time_zone = $1; }
+ | tZONE relunit_snumber
+ { pc->time_zone = $1; pc->rels_seen = true; }
+ | tZONE tSNUMBER o_colon_minutes
+ { pc->time_zone = $1 + time_zone_hhmm ($2, $3); }
+ | tDAYZONE
+ { pc->time_zone = $1 + 60; }
+ | tZONE tDST
+ { pc->time_zone = $1 + 60; }
+ ;
+
+day:
+ tDAY
+ {
+ pc->day_ordinal = 1;
+ pc->day_number = $1;
+ }
+ | tDAY ','
+ {
+ pc->day_ordinal = 1;
+ pc->day_number = $1;
+ }
+ | tORDINAL tDAY
+ {
+ pc->day_ordinal = $1;
+ pc->day_number = $2;
+ }
+ | tUNUMBER tDAY
+ {
+ pc->day_ordinal = $1.value;
+ pc->day_number = $2;
+ }
+ ;
+
+date:
+ tUNUMBER '/' tUNUMBER
+ {
+ pc->month = $1.value;
+ pc->day = $3.value;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER
+ {
+ /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
+ otherwise as MM/DD/YY.
+ The goal in recognizing YYYY/MM/DD is solely to support legacy
+ machine-generated dates like those in an RCS log listing. If
+ you want portability, use the ISO 8601 format. */
+ if (4 <= $1.digits)
+ {
+ pc->year = $1;
+ pc->month = $3.value;
+ pc->day = $5.value;
+ }
+ else
+ {
+ pc->month = $1.value;
+ pc->day = $3.value;
+ pc->year = $5;
+ }
+ }
+ | tUNUMBER tSNUMBER tSNUMBER
+ {
+ /* ISO 8601 format. YYYY-MM-DD. */
+ pc->year = $1;
+ pc->month = -$2.value;
+ pc->day = -$3.value;
+ }
+ | tUNUMBER tMONTH tSNUMBER
+ {
+ /* e.g. 17-JUN-1992. */
+ pc->day = $1.value;
+ pc->month = $2;
+ pc->year.value = -$3.value;
+ pc->year.digits = $3.digits;
+ }
+ | tMONTH tSNUMBER tSNUMBER
+ {
+ /* e.g. JUN-17-1992. */
+ pc->month = $1;
+ pc->day = -$2.value;
+ pc->year.value = -$3.value;
+ pc->year.digits = $3.digits;
+ }
+ | tMONTH tUNUMBER
+ {
+ pc->month = $1;
+ pc->day = $2.value;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER
+ {
+ pc->month = $1;
+ pc->day = $2.value;
+ pc->year = $4;
+ }
+ | tUNUMBER tMONTH
+ {
+ pc->day = $1.value;
+ pc->month = $2;
+ }
+ | tUNUMBER tMONTH tUNUMBER
+ {
+ pc->day = $1.value;
+ pc->month = $2;
+ pc->year = $3;
+ }
+ ;
+
+rel:
+ relunit tAGO
+ {
+ pc->rel_ns = -pc->rel_ns;
+ pc->rel_seconds = -pc->rel_seconds;
+ pc->rel_minutes = -pc->rel_minutes;
+ pc->rel_hour = -pc->rel_hour;
+ pc->rel_day = -pc->rel_day;
+ pc->rel_month = -pc->rel_month;
+ pc->rel_year = -pc->rel_year;
+ }
+ | relunit
+ ;
+
+relunit:
+ tORDINAL tYEAR_UNIT
+ { pc->rel_year += $1 * $2; }
+ | tUNUMBER tYEAR_UNIT
+ { pc->rel_year += $1.value * $2; }
+ | tYEAR_UNIT
+ { pc->rel_year += $1; }
+ | tORDINAL tMONTH_UNIT
+ { pc->rel_month += $1 * $2; }
+ | tUNUMBER tMONTH_UNIT
+ { pc->rel_month += $1.value * $2; }
+ | tMONTH_UNIT
+ { pc->rel_month += $1; }
+ | tORDINAL tDAY_UNIT
+ { pc->rel_day += $1 * $2; }
+ | tUNUMBER tDAY_UNIT
+ { pc->rel_day += $1.value * $2; }
+ | tDAY_UNIT
+ { pc->rel_day += $1; }
+ | tORDINAL tHOUR_UNIT
+ { pc->rel_hour += $1 * $2; }
+ | tUNUMBER tHOUR_UNIT
+ { pc->rel_hour += $1.value * $2; }
+ | tHOUR_UNIT
+ { pc->rel_hour += $1; }
+ | tORDINAL tMINUTE_UNIT
+ { pc->rel_minutes += $1 * $2; }
+ | tUNUMBER tMINUTE_UNIT
+ { pc->rel_minutes += $1.value * $2; }
+ | tMINUTE_UNIT
+ { pc->rel_minutes += $1; }
+ | tORDINAL tSEC_UNIT
+ { pc->rel_seconds += $1 * $2; }
+ | tUNUMBER tSEC_UNIT
+ { pc->rel_seconds += $1.value * $2; }
+ | tSDECIMAL_NUMBER tSEC_UNIT
+ { pc->rel_seconds += $1.tv_sec * $2; pc->rel_ns += $1.tv_nsec * $2; }
+ | tUDECIMAL_NUMBER tSEC_UNIT
+ { pc->rel_seconds += $1.tv_sec * $2; pc->rel_ns += $1.tv_nsec * $2; }
+ | tSEC_UNIT
+ { pc->rel_seconds += $1; }
+ | relunit_snumber
+ ;
+
+relunit_snumber:
+ tSNUMBER tYEAR_UNIT
+ { pc->rel_year += $1.value * $2; }
+ | tSNUMBER tMONTH_UNIT
+ { pc->rel_month += $1.value * $2; }
+ | tSNUMBER tDAY_UNIT
+ { pc->rel_day += $1.value * $2; }
+ | tSNUMBER tHOUR_UNIT
+ { pc->rel_hour += $1.value * $2; }
+ | tSNUMBER tMINUTE_UNIT
+ { pc->rel_minutes += $1.value * $2; }
+ | tSNUMBER tSEC_UNIT
+ { pc->rel_seconds += $1.value * $2; }
+ ;
+
+seconds: signed_seconds | unsigned_seconds;
+
+signed_seconds:
+ tSDECIMAL_NUMBER
+ | tSNUMBER
+ { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
+ ;
+
+unsigned_seconds:
+ tUDECIMAL_NUMBER
+ | tUNUMBER
+ { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
+ ;
+
+number:
+ tUNUMBER
+ {
+ if (pc->dates_seen && ! pc->year.digits
+ && ! pc->rels_seen && (pc->times_seen || 2 < $1.digits))
+ pc->year = $1;
+ else
+ {
+ if (4 < $1.digits)
+ {
+ pc->dates_seen++;
+ pc->day = $1.value % 100;
+ pc->month = ($1.value / 100) % 100;
+ pc->year.value = $1.value / 10000;
+ pc->year.digits = $1.digits - 4;
+ }
+ else
+ {
+ pc->times_seen++;
+ if ($1.digits <= 2)
+ {
+ pc->hour = $1.value;
+ pc->minutes = 0;
+ }
+ else
+ {
+ pc->hour = $1.value / 100;
+ pc->minutes = $1.value % 100;
+ }
+ pc->seconds.tv_sec = 0;
+ pc->seconds.tv_nsec = 0;
+ pc->meridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_colon_minutes:
+ /* empty */
+ { $$ = -1; }
+ | ':' tUNUMBER
+ { $$ = $2.value; }
+ ;
+
+o_merid:
+ /* empty */
+ { $$ = MER24; }
+ | tMERIDIAN
+ { $$ = $1; }
+ ;
+
+%%
+
+static table const meridian_table[] =
+{
+ { "AM", tMERIDIAN, MERam },
+ { "A.M.", tMERIDIAN, MERam },
+ { "PM", tMERIDIAN, MERpm },
+ { "P.M.", tMERIDIAN, MERpm },
+ { NULL, 0, 0 }
+};
+
+static table const dst_table[] =
+{
+ { "DST", tDST, 0 }
+};
+
+static table const month_and_day_table[] =
+{
+ { "JANUARY", tMONTH, 1 },
+ { "FEBRUARY", tMONTH, 2 },
+ { "MARCH", tMONTH, 3 },
+ { "APRIL", tMONTH, 4 },
+ { "MAY", tMONTH, 5 },
+ { "JUNE", tMONTH, 6 },
+ { "JULY", tMONTH, 7 },
+ { "AUGUST", tMONTH, 8 },
+ { "SEPTEMBER",tMONTH, 9 },
+ { "SEPT", tMONTH, 9 },
+ { "OCTOBER", tMONTH, 10 },
+ { "NOVEMBER", tMONTH, 11 },
+ { "DECEMBER", tMONTH, 12 },
+ { "SUNDAY", tDAY, 0 },
+ { "MONDAY", tDAY, 1 },
+ { "TUESDAY", tDAY, 2 },
+ { "TUES", tDAY, 2 },
+ { "WEDNESDAY",tDAY, 3 },
+ { "WEDNES", tDAY, 3 },
+ { "THURSDAY", tDAY, 4 },
+ { "THUR", tDAY, 4 },
+ { "THURS", tDAY, 4 },
+ { "FRIDAY", tDAY, 5 },
+ { "SATURDAY", tDAY, 6 },
+ { NULL, 0, 0 }
+};
+
+static table const time_units_table[] =
+{
+ { "YEAR", tYEAR_UNIT, 1 },
+ { "MONTH", tMONTH_UNIT, 1 },
+ { "FORTNIGHT",tDAY_UNIT, 14 },
+ { "WEEK", tDAY_UNIT, 7 },
+ { "DAY", tDAY_UNIT, 1 },
+ { "HOUR", tHOUR_UNIT, 1 },
+ { "MINUTE", tMINUTE_UNIT, 1 },
+ { "MIN", tMINUTE_UNIT, 1 },
+ { "SECOND", tSEC_UNIT, 1 },
+ { "SEC", tSEC_UNIT, 1 },
+ { NULL, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static table const relative_time_table[] =
+{
+ { "TOMORROW", tDAY_UNIT, 1 },
+ { "YESTERDAY",tDAY_UNIT, -1 },
+ { "TODAY", tDAY_UNIT, 0 },
+ { "NOW", tDAY_UNIT, 0 },
+ { "LAST", tORDINAL, -1 },
+ { "THIS", tORDINAL, 0 },
+ { "NEXT", tORDINAL, 1 },
+ { "FIRST", tORDINAL, 1 },
+/*{ "SECOND", tORDINAL, 2 }, */
+ { "THIRD", tORDINAL, 3 },
+ { "FOURTH", tORDINAL, 4 },
+ { "FIFTH", tORDINAL, 5 },
+ { "SIXTH", tORDINAL, 6 },
+ { "SEVENTH", tORDINAL, 7 },
+ { "EIGHTH", tORDINAL, 8 },
+ { "NINTH", tORDINAL, 9 },
+ { "TENTH", tORDINAL, 10 },
+ { "ELEVENTH", tORDINAL, 11 },
+ { "TWELFTH", tORDINAL, 12 },
+ { "AGO", tAGO, 1 },
+ { NULL, 0, 0 }
+};
+
+/* The universal time zone table. These labels can be used even for
+ time stamps that would not otherwise be valid, e.g., GMT time
+ stamps in London during summer. */
+static table const universal_time_zone_table[] =
+{
+ { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */
+ { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
+ { "UTC", tZONE, HOUR ( 0) },
+ { NULL, 0, 0 }
+};
+
+/* The time zone table. This table is necessarily incomplete, as time
+ zone abbreviations are ambiguous; e.g. Australians interpret "EST"
+ as Eastern time in Australia, not as US Eastern Standard Time.
+ You cannot rely on getdate to handle arbitrary time zone
+ abbreviations; use numeric abbreviations like `-0500' instead. */
+static table const time_zone_table[] =
+{
+ { "WET", tZONE, HOUR ( 0) }, /* Western European */
+ { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */
+ { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */
+ { "ART", tZONE, -HOUR ( 3) }, /* Argentina */
+ { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */
+ { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
+ { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */
+ { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */
+ { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */
+ { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
+ { "CLT", tZONE, -HOUR ( 4) }, /* Chile */
+ { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
+ { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */
+ { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
+ { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */
+ { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
+ { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */
+ { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
+ { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */
+ { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
+ { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */
+ { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
+ { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */
+ { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */
+ { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
+ { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */
+ { "WAT", tZONE, HOUR ( 1) }, /* West Africa */
+ { "CET", tZONE, HOUR ( 1) }, /* Central European */
+ { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */
+ { "MET", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "EET", tZONE, HOUR ( 2) }, /* Eastern European */
+ { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */
+ { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */
+ { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */
+ { "EAT", tZONE, HOUR ( 3) }, /* East Africa */
+ { "MSK", tZONE, HOUR ( 3) }, /* Moscow */
+ { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */
+ { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */
+ { "SGT", tZONE, HOUR ( 8) }, /* Singapore */
+ { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */
+ { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */
+ { "GST", tZONE, HOUR (10) }, /* Guam Standard */
+ { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */
+ { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */
+ { NULL, 0, 0 }
+};
+
+/* Military time zone table. */
+static table const military_table[] =
+{
+ { "A", tZONE, -HOUR ( 1) },
+ { "B", tZONE, -HOUR ( 2) },
+ { "C", tZONE, -HOUR ( 3) },
+ { "D", tZONE, -HOUR ( 4) },
+ { "E", tZONE, -HOUR ( 5) },
+ { "F", tZONE, -HOUR ( 6) },
+ { "G", tZONE, -HOUR ( 7) },
+ { "H", tZONE, -HOUR ( 8) },
+ { "I", tZONE, -HOUR ( 9) },
+ { "K", tZONE, -HOUR (10) },
+ { "L", tZONE, -HOUR (11) },
+ { "M", tZONE, -HOUR (12) },
+ { "N", tZONE, HOUR ( 1) },
+ { "O", tZONE, HOUR ( 2) },
+ { "P", tZONE, HOUR ( 3) },
+ { "Q", tZONE, HOUR ( 4) },
+ { "R", tZONE, HOUR ( 5) },
+ { "S", tZONE, HOUR ( 6) },
+ { "T", tZONE, HOUR ( 7) },
+ { "U", tZONE, HOUR ( 8) },
+ { "V", tZONE, HOUR ( 9) },
+ { "W", tZONE, HOUR (10) },
+ { "X", tZONE, HOUR (11) },
+ { "Y", tZONE, HOUR (12) },
+ { "Z", tZONE, HOUR ( 0) },
+ { NULL, 0, 0 }
+};
+
+
+
+/* Convert a time zone expressed as HH:MM into an integer count of
+ minutes. If MM is negative, then S is of the form HHMM and needs
+ to be picked apart; otherwise, S is of the form HH. */
+
+static long int
+time_zone_hhmm (textint s, long int mm)
+{
+ if (mm < 0)
+ return (s.value / 100) * 60 + s.value % 100;
+ else
+ return s.value * 60 + (s.negative ? -mm : mm);
+}
+
+static int
+to_hour (long int hours, int meridian)
+{
+ switch (meridian)
+ {
+ default: /* Pacify GCC. */
+ case MER24:
+ return 0 <= hours && hours < 24 ? hours : -1;
+ case MERam:
+ return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
+ case MERpm:
+ return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
+ }
+}
+
+static long int
+to_year (textint textyear)
+{
+ long int year = textyear.value;
+
+ if (year < 0)
+ year = -year;
+
+ /* XPG4 suggests that years 00-68 map to 2000-2068, and
+ years 69-99 map to 1969-1999. */
+ else if (textyear.digits == 2)
+ year += year < 69 ? 2000 : 1900;
+
+ return year;
+}
+
+static table const *
+lookup_zone (parser_control const *pc, char const *name)
+{
+ table const *tp;
+
+ for (tp = universal_time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ /* Try local zone abbreviations before those in time_zone_table, as
+ the local ones are more likely to be right. */
+ for (tp = pc->local_time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ for (tp = time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ return NULL;
+}
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds.
+ The body of this function is taken directly from the GNU C Library;
+ see src/strftime.c. */
+static long int
+tm_diff (struct tm const *a, struct tm const *b)
+{
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations. */
+ int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
+ int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = SHR (a100, 2);
+ int b400 = SHR (b100, 2);
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ long int ayear = a->tm_year;
+ long int years = ayear - b->tm_year;
+ long int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+static table const *
+lookup_word (parser_control const *pc, char *word)
+{
+ char *p;
+ char *q;
+ size_t wordlen;
+ table const *tp;
+ bool period_found;
+ bool abbrev;
+
+ /* Make it uppercase. */
+ for (p = word; *p; p++)
+ {
+ unsigned char ch = *p;
+ if (ISLOWER (ch))
+ *p = toupper (ch);
+ }
+
+ for (tp = meridian_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* See if we have an abbreviation for a month. */
+ wordlen = strlen (word);
+ abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
+
+ for (tp = month_and_day_table; tp->name; tp++)
+ if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
+ return tp;
+
+ if ((tp = lookup_zone (pc, word)))
+ return tp;
+
+ if (strcmp (word, dst_table[0].name) == 0)
+ return dst_table;
+
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Strip off any plural and try the units table again. */
+ if (word[wordlen - 1] == 'S')
+ {
+ word[wordlen - 1] = '\0';
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+ word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */
+ }
+
+ for (tp = relative_time_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Military time zones. */
+ if (wordlen == 1)
+ for (tp = military_table; tp->name; tp++)
+ if (word[0] == tp->name[0])
+ return tp;
+
+ /* Drop out any periods and try the time zone table again. */
+ for (period_found = false, p = q = word; (*p = *q); q++)
+ if (*q == '.')
+ period_found = true;
+ else
+ p++;
+ if (period_found && (tp = lookup_zone (pc, word)))
+ return tp;
+
+ return NULL;
+}
+
+static int
+yylex (YYSTYPE *lvalp, parser_control *pc)
+{
+ unsigned char c;
+ size_t count;
+
+ for (;;)
+ {
+ while (c = *pc->input, ISSPACE (c))
+ pc->input++;
+
+ if (ISDIGIT (c) || c == '-' || c == '+')
+ {
+ char const *p;
+ int sign;
+ unsigned long int value;
+ if (c == '-' || c == '+')
+ {
+ sign = c == '-' ? -1 : 1;
+ while (c = *++pc->input, ISSPACE (c))
+ continue;
+ if (! ISDIGIT (c))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ p = pc->input;
+ for (value = 0; ; value *= 10)
+ {
+ unsigned long int value1 = value + (c - '0');
+ if (value1 < value)
+ return '?';
+ value = value1;
+ c = *++p;
+ if (! ISDIGIT (c))
+ break;
+ if (ULONG_MAX / 10 < value)
+ return '?';
+ }
+ if ((c == '.' || c == ',') && ISDIGIT (p[1]))
+ {
+ time_t s;
+ int ns;
+ int digits;
+ unsigned long int value1;
+
+ /* Check for overflow when converting value to time_t. */
+ if (sign < 0)
+ {
+ s = - value;
+ if (0 < s)
+ return '?';
+ value1 = -s;
+ }
+ else
+ {
+ s = value;
+ if (s < 0)
+ return '?';
+ value1 = s;
+ }
+ if (value != value1)
+ return '?';
+
+ /* Accumulate fraction, to ns precision. */
+ p++;
+ ns = *p++ - '0';
+ for (digits = 2; digits <= LOG10_BILLION; digits++)
+ {
+ ns *= 10;
+ if (ISDIGIT (*p))
+ ns += *p++ - '0';
+ }
+
+ /* Skip excess digits, truncating toward -Infinity. */
+ if (sign < 0)
+ for (; ISDIGIT (*p); p++)
+ if (*p != '0')
+ {
+ ns++;
+ break;
+ }
+ while (ISDIGIT (*p))
+ p++;
+
+ /* Adjust to the timespec convention, which is that
+ tv_nsec is always a positive offset even if tv_sec is
+ negative. */
+ if (sign < 0 && ns)
+ {
+ s--;
+ if (! (s < 0))
+ return '?';
+ ns = BILLION - ns;
+ }
+
+ lvalp->timespec.tv_sec = s;
+ lvalp->timespec.tv_nsec = ns;
+ pc->input = p;
+ return sign ? tSDECIMAL_NUMBER : tUDECIMAL_NUMBER;
+ }
+ else
+ {
+ lvalp->textintval.negative = sign < 0;
+ if (sign < 0)
+ {
+ lvalp->textintval.value = - value;
+ if (0 < lvalp->textintval.value)
+ return '?';
+ }
+ else
+ {
+ lvalp->textintval.value = value;
+ if (lvalp->textintval.value < 0)
+ return '?';
+ }
+ lvalp->textintval.digits = p - pc->input;
+ pc->input = p;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ }
+
+ if (ISALPHA (c))
+ {
+ char buff[20];
+ char *p = buff;
+ table const *tp;
+
+ do
+ {
+ if (p < buff + sizeof buff - 1)
+ *p++ = c;
+ c = *++pc->input;
+ }
+ while (ISALPHA (c) || c == '.');
+
+ *p = '\0';
+ tp = lookup_word (pc, buff);
+ if (! tp)
+ return '?';
+ lvalp->intval = tp->value;
+ return tp->type;
+ }
+
+ if (c != '(')
+ return *pc->input++;
+ count = 0;
+ do
+ {
+ c = *pc->input++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ count++;
+ else if (c == ')')
+ count--;
+ }
+ while (count != 0);
+ }
+}
+
+/* Do nothing if the parser reports an error. */
+static int
+yyerror (parser_control *pc ATTRIBUTE_UNUSED, char *s ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* If *TM0 is the old and *TM1 is the new value of a struct tm after
+ passing it to mktime, return true if it's OK that mktime returned T.
+ It's not OK if *TM0 has out-of-range members. */
+
+static bool
+mktime_ok (struct tm const *tm0, struct tm const *tm1, time_t t)
+{
+ if (t == (time_t) -1)
+ {
+ /* Guard against falsely reporting an error when parsing a time
+ stamp that happens to equal (time_t) -1, on a host that
+ supports such a time stamp. */
+ tm1 = localtime (&t);
+ if (!tm1)
+ return false;
+ }
+
+ return ! ((tm0->tm_sec ^ tm1->tm_sec)
+ | (tm0->tm_min ^ tm1->tm_min)
+ | (tm0->tm_hour ^ tm1->tm_hour)
+ | (tm0->tm_mday ^ tm1->tm_mday)
+ | (tm0->tm_mon ^ tm1->tm_mon)
+ | (tm0->tm_year ^ tm1->tm_year));
+}
+
+/* A reasonable upper bound for the size of ordinary TZ strings.
+ Use heap allocation if TZ's length exceeds this. */
+enum { TZBUFSIZE = 100 };
+
+/* Return a copy of TZ, stored in TZBUF if it fits, and heap-allocated
+ otherwise. */
+static char *
+get_tz (char tzbuf[TZBUFSIZE])
+{
+ char *tz = getenv ("TZ");
+ if (tz)
+ {
+ size_t tzsize = strlen (tz) + 1;
+ tz = (tzsize <= TZBUFSIZE
+ ? memcpy (tzbuf, tz, tzsize)
+ : xmemdup (tz, tzsize));
+ }
+ return tz;
+}
+
+/* Parse a date/time string, storing the resulting time value into *RESULT.
+ The string itself is pointed to by P. Return true if successful.
+ P can be an incomplete or relative time specification; if so, use
+ *NOW as the basis for the returned time. */
+bool
+get_date (struct timespec *result, char const *p, struct timespec const *now)
+{
+ time_t Start;
+ long int Start_ns;
+ struct tm const *tmp;
+ struct tm tm;
+ struct tm tm0;
+ parser_control pc;
+ struct timespec gettime_buffer;
+ unsigned char c;
+ bool tz_was_altered = false;
+ char *tz0 = NULL;
+ char tz0buf[TZBUFSIZE];
+ bool ok = true;
+
+ if (! now)
+ {
+ gettime (&gettime_buffer);
+ now = &gettime_buffer;
+ }
+
+ Start = now->tv_sec;
+ Start_ns = now->tv_nsec;
+
+ tmp = localtime (&now->tv_sec);
+ if (! tmp)
+ return false;
+
+ while (c = *p, ISSPACE (c))
+ p++;
+
+ if (strncmp (p, "TZ=\"", 4) == 0)
+ {
+ char const *tzbase = p + 4;
+ size_t tzsize = 1;
+ char const *s;
+
+ for (s = tzbase; *s; s++, tzsize++)
+ if (*s == '\\')
+ {
+ s++;
+ if (! (*s == '\\' || *s == '"'))
+ break;
+ }
+ else if (*s == '"')
+ {
+ char *z;
+ char *tz1;
+ char tz1buf[TZBUFSIZE];
+ bool large_tz = TZBUFSIZE < tzsize;
+ bool setenv_ok;
+ tz0 = get_tz (tz0buf);
+ z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf;
+ for (s = tzbase; *s != '"'; s++)
+ *z++ = *(s += *s == '\\');
+ *z = '\0';
+ setenv_ok = setenv ("TZ", tz1, 1) == 0;
+ if (large_tz)
+ free (tz1);
+ if (!setenv_ok)
+ goto fail;
+ tz_was_altered = true;
+ p = s + 1;
+ }
+ }
+
+ pc.input = p;
+ pc.year.value = tmp->tm_year;
+ pc.year.value += TM_YEAR_BASE;
+ pc.year.digits = 0;
+ pc.month = tmp->tm_mon + 1;
+ pc.day = tmp->tm_mday;
+ pc.hour = tmp->tm_hour;
+ pc.minutes = tmp->tm_min;
+ pc.seconds.tv_sec = tmp->tm_sec;
+ pc.seconds.tv_nsec = Start_ns;
+ tm.tm_isdst = tmp->tm_isdst;
+
+ pc.meridian = MER24;
+ pc.rel_ns = 0;
+ pc.rel_seconds = 0;
+ pc.rel_minutes = 0;
+ pc.rel_hour = 0;
+ pc.rel_day = 0;
+ pc.rel_month = 0;
+ pc.rel_year = 0;
+ pc.timespec_seen = false;
+ pc.rels_seen = false;
+ pc.dates_seen = 0;
+ pc.days_seen = 0;
+ pc.times_seen = 0;
+ pc.local_zones_seen = 0;
+ pc.dsts_seen = 0;
+ pc.zones_seen = 0;
+
+#if HAVE_STRUCT_TM_TM_ZONE
+ pc.local_time_zone_table[0].name = tmp->tm_zone;
+ pc.local_time_zone_table[0].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[0].value = tmp->tm_isdst;
+ pc.local_time_zone_table[1].name = NULL;
+
+ /* Probe the names used in the next three calendar quarters, looking
+ for a tm_isdst different from the one we already have. */
+ {
+ int quarter;
+ for (quarter = 1; quarter <= 3; quarter++)
+ {
+ time_t probe = Start + quarter * (90 * 24 * 60 * 60);
+ struct tm const *probe_tm = localtime (&probe);
+ if (probe_tm && probe_tm->tm_zone
+ && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
+ {
+ {
+ pc.local_time_zone_table[1].name = probe_tm->tm_zone;
+ pc.local_time_zone_table[1].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
+ pc.local_time_zone_table[2].name = NULL;
+ }
+ break;
+ }
+ }
+ }
+#else
+#if HAVE_TZNAME
+ {
+# ifndef tzname
+ extern char *tzname[];
+# endif
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ pc.local_time_zone_table[i].name = tzname[i];
+ pc.local_time_zone_table[i].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[i].value = i;
+ }
+ pc.local_time_zone_table[i].name = NULL;
+ }
+#else
+ pc.local_time_zone_table[0].name = NULL;
+#endif
+#endif
+
+ if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
+ && ! strcmp (pc.local_time_zone_table[0].name,
+ pc.local_time_zone_table[1].name))
+ {
+ /* This locale uses the same abbrevation for standard and
+ daylight times. So if we see that abbreviation, we don't
+ know whether it's daylight time. */
+ pc.local_time_zone_table[0].value = -1;
+ pc.local_time_zone_table[1].name = NULL;
+ }
+
+ if (yyparse (&pc) != 0)
+ goto fail;
+
+ if (pc.timespec_seen)
+ *result = pc.seconds;
+ else
+ {
+ if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen
+ | (pc.local_zones_seen + pc.zones_seen)))
+ goto fail;
+
+ tm.tm_year = to_year (pc.year) - TM_YEAR_BASE;
+ tm.tm_mon = pc.month - 1;
+ tm.tm_mday = pc.day;
+ if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
+ {
+ tm.tm_hour = to_hour (pc.hour, pc.meridian);
+ if (tm.tm_hour < 0)
+ goto fail;
+ tm.tm_min = pc.minutes;
+ tm.tm_sec = pc.seconds.tv_sec;
+ }
+ else
+ {
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ pc.seconds.tv_nsec = 0;
+ }
+
+ /* Let mktime deduce tm_isdst if we have an absolute time stamp. */
+ if (!pc.rels_seen)
+ tm.tm_isdst = -1;
+
+ /* But if the input explicitly specifies local time with or without
+ DST, give mktime that information. */
+ if (pc.local_zones_seen)
+ tm.tm_isdst = pc.local_isdst;
+
+ tm0 = tm;
+
+ Start = mktime (&tm);
+
+ if (! mktime_ok (&tm0, &tm, Start))
+ {
+ if (! pc.zones_seen)
+ goto fail;
+ else
+ {
+ /* Guard against falsely reporting errors near the time_t
+ boundaries when parsing times in other time zones. For
+ example, suppose the input string "1969-12-31 23:00:00 -0100",
+ the current time zone is 8 hours ahead of UTC, and the min
+ time_t value is 1970-01-01 00:00:00 UTC. Then the min
+ localtime value is 1970-01-01 08:00:00, and mktime will
+ therefore fail on 1969-12-31 23:00:00. To work around the
+ problem, set the time zone to 1 hour behind UTC temporarily
+ by setting TZ="XXX1:00" and try mktime again. */
+
+ long int time_zone = pc.time_zone;
+ long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone;
+ long int abs_time_zone_hour = abs_time_zone / 60;
+ int abs_time_zone_min = abs_time_zone % 60;
+ char tz1buf[sizeof "XXX+0:00"
+ + sizeof pc.time_zone * CHAR_BIT / 3];
+ if (!tz_was_altered)
+ tz0 = get_tz (tz0buf);
+ sprintf (tz1buf, "XXX%s%ld:%02d", "-" + (time_zone < 0),
+ abs_time_zone_hour, abs_time_zone_min);
+ if (setenv ("TZ", tz1buf, 1) != 0)
+ goto fail;
+ tz_was_altered = true;
+ tm = tm0;
+ Start = mktime (&tm);
+ if (! mktime_ok (&tm0, &tm, Start))
+ goto fail;
+ }
+ }
+
+ if (pc.days_seen && ! pc.dates_seen)
+ {
+ tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
+ + 7 * (pc.day_ordinal - (0 < pc.day_ordinal)));
+ tm.tm_isdst = -1;
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ goto fail;
+ }
+
+ if (pc.zones_seen)
+ {
+ long int delta = pc.time_zone * 60;
+ time_t t1;
+#ifdef HAVE_TM_GMTOFF
+ delta -= tm.tm_gmtoff;
+#else
+ time_t t = Start;
+ struct tm const *gmt = gmtime (&t);
+ if (! gmt)
+ goto fail;
+ delta -= tm_diff (&tm, gmt);
+#endif
+ t1 = Start - delta;
+ if ((Start < t1) != (delta < 0))
+ goto fail; /* time_t overflow */
+ Start = t1;
+ }
+
+ /* Add relative date. */
+ if (pc.rel_year | pc.rel_month | pc.rel_day)
+ {
+ int year = tm.tm_year + pc.rel_year;
+ int month = tm.tm_mon + pc.rel_month;
+ int day = tm.tm_mday + pc.rel_day;
+ if (((year < tm.tm_year) ^ (pc.rel_year < 0))
+ | ((month < tm.tm_mon) ^ (pc.rel_month < 0))
+ | ((day < tm.tm_mday) ^ (pc.rel_day < 0)))
+ goto fail;
+ tm.tm_year = year;
+ tm.tm_mon = month;
+ tm.tm_mday = day;
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ goto fail;
+ }
+
+ /* Add relative hours, minutes, and seconds. On hosts that support
+ leap seconds, ignore the possibility of leap seconds; e.g.,
+ "+ 10 minutes" adds 600 seconds, even if one of them is a
+ leap second. Typically this is not what the user wants, but it's
+ too hard to do it the other way, because the time zone indicator
+ must be applied before relative times, and if mktime is applied
+ again the time zone will be lost. */
+ {
+ long int sum_ns = pc.seconds.tv_nsec + pc.rel_ns;
+ long int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION;
+ time_t t0 = Start;
+ long int d1 = 60 * 60 * pc.rel_hour;
+ time_t t1 = t0 + d1;
+ long int d2 = 60 * pc.rel_minutes;
+ time_t t2 = t1 + d2;
+ long int d3 = pc.rel_seconds;
+ time_t t3 = t2 + d3;
+ long int d4 = (sum_ns - normalized_ns) / BILLION;
+ time_t t4 = t3 + d4;
+
+ if ((d1 / (60 * 60) ^ pc.rel_hour)
+ | (d2 / 60 ^ pc.rel_minutes)
+ | ((t1 < t0) ^ (d1 < 0))
+ | ((t2 < t1) ^ (d2 < 0))
+ | ((t3 < t2) ^ (d3 < 0))
+ | ((t4 < t3) ^ (d4 < 0)))
+ goto fail;
+
+ result->tv_sec = t4;
+ result->tv_nsec = normalized_ns;
+ }
+ }
+
+ goto done;
+
+ fail:
+ ok = false;
+ done:
+ if (tz_was_altered)
+ ok &= (tz0 ? setenv ("TZ", tz0, 1) : unsetenv ("TZ")) == 0;
+ if (tz0 != tz0buf)
+ free (tz0);
+ return ok;
+}
+
+#if TEST
+
+int
+main (int ac, char **av)
+{
+ char buff[BUFSIZ];
+
+ printf ("Enter date, or blank line to exit.\n\t> ");
+ fflush (stdout);
+
+ buff[BUFSIZ - 1] = '\0';
+ while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
+ {
+ struct timespec d;
+ struct tm const *tm;
+ if (! get_date (&d, buff, NULL))
+ printf ("Bad format - couldn't convert.\n");
+ else if (! (tm = localtime (&d.tv_sec)))
+ {
+ long int sec = d.tv_sec;
+ printf ("localtime (%ld) failed\n", sec);
+ }
+ else
+ {
+ int ns = d.tv_nsec;
+ printf ("%04ld-%02d-%02d %02d:%02d:%02d.%09d\n",
+ tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, ns);
+ }
+ printf ("\t> ");
+ fflush (stdout);
+ }
+ return 0;
+}
+#endif /* TEST */
diff --git a/lib/getdelim.c b/lib/getdelim.c
new file mode 100644
index 0000000..8498b75
--- /dev/null
+++ b/lib/getdelim.c
@@ -0,0 +1,119 @@
+/* getdelim.c --- Implementation of replacement getdelim function.
+ Copyright (C) 1994, 1996, 1997, 1998, 2001, 2003, 2005 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* Ported from glibc by Simon Josefsson. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "getdelim.h"
+
+#if !HAVE_FLOCKFILE
+# undef flockfile
+# define flockfile(x) ((void) 0)
+#endif
+#if !HAVE_FUNLOCKFILE
+# undef funlockfile
+# define funlockfile(x) ((void) 0)
+#endif
+
+/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
+ NUL-terminate it). *LINEPTR is a pointer returned from malloc (or
+ NULL), pointing to *N characters of space. It is realloc'ed as
+ necessary. Returns the number of characters read (not including
+ the null terminator), or -1 on error or EOF. */
+
+ssize_t
+getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
+{
+ int result = 0;
+ ssize_t cur_len = 0;
+ ssize_t len;
+
+ if (lineptr == NULL || n == NULL || fp == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ flockfile (fp);
+
+ if (*lineptr == NULL || *n == 0)
+ {
+ *n = 120;
+ *lineptr = (char *) malloc (*n);
+ if (*lineptr == NULL)
+ {
+ result = -1;
+ goto unlock_return;
+ }
+ }
+
+ for (;;)
+ {
+ char *t;
+ int i;
+
+ i = getc (fp);
+ if (i == EOF)
+ {
+ result = -1;
+ break;
+ }
+
+ /* Make enough space for len+1 (for final NUL) bytes. */
+ if (cur_len + 1 >= *n)
+ {
+ size_t needed = 2 * (cur_len + 1) + 1; /* Be generous. */
+ char *new_lineptr;
+
+ if (needed < cur_len)
+ {
+ result = -1;
+ goto unlock_return;
+ }
+
+ new_lineptr = (char *) realloc (*lineptr, needed);
+ if (new_lineptr == NULL)
+ {
+ result = -1;
+ goto unlock_return;
+ }
+
+ *lineptr = new_lineptr;
+ *n = needed;
+ }
+
+ (*lineptr)[cur_len] = i;
+ cur_len++;
+
+ if (i == delimiter)
+ break;
+ }
+ (*lineptr)[cur_len] = '\0';
+ result = cur_len ? cur_len : result;
+
+ unlock_return:
+ funlockfile (fp);
+ return result;
+}
diff --git a/lib/getdelim.h b/lib/getdelim.h
new file mode 100644
index 0000000..8bc6130
--- /dev/null
+++ b/lib/getdelim.h
@@ -0,0 +1,28 @@
+/* getdelim.h --- Prototype for replacement getdelim function.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* Written by Simon Josefsson. */
+
+/* Get size_t, FILE, ssize_t. And getdelim, if available. */
+# include <stddef.h>
+# include <stdio.h>
+# include <sys/types.h>
+
+#if !HAVE_DECL_GETDELIM
+ssize_t getdelim (char **lineptr, size_t *n, int delimiter, FILE *stream);
+#endif /* !HAVE_GETDELIM */
diff --git a/lib/gethostname.c b/lib/gethostname.c
new file mode 100644
index 0000000..f05ed85
--- /dev/null
+++ b/lib/gethostname.c
@@ -0,0 +1,53 @@
+/* gethostname emulation for SysV and POSIX.1.
+ Copyright (C) 1992, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_UNAME
+# include <sys/utsname.h>
+#endif
+
+/* Put up to LEN chars of the host name into NAME.
+ Null terminate it if the name is shorter than LEN.
+ Return 0 if ok, -1 if error. */
+
+#include <stddef.h>
+
+int
+gethostname (char *name, size_t len)
+{
+#ifdef HAVE_UNAME
+ struct utsname uts;
+
+ if (uname (&uts) == -1)
+ return -1;
+ if (len > sizeof (uts.nodename))
+ {
+ /* More space than we need is available. */
+ name[sizeof (uts.nodename)] = '\0';
+ len = sizeof (uts.nodename);
+ }
+ strncpy (name, uts.nodename, len);
+#else
+ strcpy (name, ""); /* Hardcode your system name if you want. */
+#endif
+ return 0;
+}
diff --git a/lib/getline.c b/lib/getline.c
new file mode 100644
index 0000000..ab054fb
--- /dev/null
+++ b/lib/getline.c
@@ -0,0 +1,32 @@
+/* getline.c --- Implementation of replacement getline function.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* Written by Simon Josefsson. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getdelim.h"
+#include "getline.h"
+
+ssize_t
+getline (char **lineptr, size_t *n, FILE *stream)
+{
+ return getdelim (lineptr, n, '\n', stream);
+}
diff --git a/lib/getline.h b/lib/getline.h
new file mode 100644
index 0000000..f0f61c4
--- /dev/null
+++ b/lib/getline.h
@@ -0,0 +1,28 @@
+/* getline.h --- Prototype for replacement getline function.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* Written by Simon Josefsson. */
+
+/* Get size_t, FILE, ssize_t. And getline, if available. */
+# include <stddef.h>
+# include <stdio.h>
+# include <sys/types.h>
+
+#if !HAVE_DECL_GETLINE
+ssize_t getline (char **lineptr, size_t *n, FILE *stream);
+#endif /* !HAVE_GETLINE */
diff --git a/lib/getlogin_r.c b/lib/getlogin_r.c
new file mode 100644
index 0000000..b9b76c6
--- /dev/null
+++ b/lib/getlogin_r.c
@@ -0,0 +1,61 @@
+/* Provide a working getlogin_r for systems which lack it.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Paul Eggert and Derek Price */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getlogin_r.h"
+
+#include <errno.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !HAVE_DECL_GETLOGIN
+char *getlogin (void);
+#endif
+
+/* See getlogin_r.h for documentation. */
+int
+getlogin_r (char *name, size_t size)
+{
+ char *n;
+ size_t nlen;
+
+ errno = 0;
+ n = getlogin ();
+
+ /* A system function like getlogin_r is never supposed to set errno
+ to zero, so make sure errno is nonzero here. ENOENT is a
+ reasonable errno value if getlogin returns NULL. */
+ if (!errno)
+ errno = ENOENT;
+
+ if (!n)
+ return errno;
+ nlen = strlen (n);
+ if (size <= nlen)
+ return ERANGE;
+ memcpy (name, n, nlen + 1);
+ return 0;
+}
diff --git a/lib/getlogin_r.h b/lib/getlogin_r.h
new file mode 100644
index 0000000..3ff3caf
--- /dev/null
+++ b/lib/getlogin_r.h
@@ -0,0 +1,38 @@
+/* getlogin_r declaration
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert and Derek Price. */
+
+#include <stddef.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* Copies the user's login name to NAME.
+ The array pointed to by NAME has room for SIZE bytes.
+
+ Returns 0 if successful. Upon error, an error number is returned, or -1 in
+ the case that the login name cannot be found but no specific error is
+ provided (this case is hopefully rare but is left open by the POSIX spec).
+
+ See <http://www.opengroup.org/susv3xsh/getlogin.html>.
+ */
+#if !HAVE_DECL_GETLOGIN_R
+int getlogin_r (char *name, size_t size);
+#endif
diff --git a/lib/getndelim2.c b/lib/getndelim2.c
new file mode 100644
index 0000000..3c0fa3f
--- /dev/null
+++ b/lib/getndelim2.c
@@ -0,0 +1,155 @@
+/* getndelim2 - Read a line from a stream, stopping at one of 2 delimiters,
+ with bounded memory allocation.
+
+ Copyright (C) 1993, 1996, 1997, 1998, 2000, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Originally written by Jan Brittenson, bson@gnu.ai.mit.edu. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getndelim2.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+#include <limits.h>
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifndef PTRDIFF_MAX
+# define PTRDIFF_MAX ((ptrdiff_t) (SIZE_MAX / 2))
+#endif
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+#ifndef SSIZE_MAX
+# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
+#endif
+
+/* The maximum value that getndelim2 can return without suffering from
+ overflow problems, either internally (because of pointer
+ subtraction overflow) or due to the API (because of ssize_t). */
+#define GETNDELIM2_MAXIMUM (PTRDIFF_MAX < SSIZE_MAX ? PTRDIFF_MAX : SSIZE_MAX)
+
+/* Try to add at least this many bytes when extending the buffer.
+ MIN_CHUNK must be no greater than GETNDELIM2_MAXIMUM. */
+#define MIN_CHUNK 64
+
+ssize_t
+getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
+ int delim1, int delim2, FILE *stream)
+{
+ size_t nbytes_avail; /* Allocated but unused bytes in *LINEPTR. */
+ char *read_pos; /* Where we're reading into *LINEPTR. */
+ ssize_t bytes_stored = -1;
+ char *ptr = *lineptr;
+ size_t size = *linesize;
+
+ if (!ptr)
+ {
+ size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK;
+ ptr = malloc (size);
+ if (!ptr)
+ return -1;
+ }
+
+ if (size < offset)
+ goto done;
+
+ nbytes_avail = size - offset;
+ read_pos = ptr + offset;
+
+ if (nbytes_avail == 0 && nmax <= size)
+ goto done;
+
+ for (;;)
+ {
+ /* Here always ptr + size == read_pos + nbytes_avail. */
+
+ int c;
+
+ /* We always want at least one byte left in the buffer, since we
+ always (unless we get an error while reading the first byte)
+ NUL-terminate the line buffer. */
+
+ if (nbytes_avail < 2 && size < nmax)
+ {
+ size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size;
+ char *newptr;
+
+ if (! (size < newsize && newsize <= nmax))
+ newsize = nmax;
+
+ if (GETNDELIM2_MAXIMUM < newsize - offset)
+ {
+ size_t newsizemax = offset + GETNDELIM2_MAXIMUM + 1;
+ if (size == newsizemax)
+ goto done;
+ newsize = newsizemax;
+ }
+
+ nbytes_avail = newsize - (read_pos - ptr);
+ newptr = realloc (ptr, newsize);
+ if (!newptr)
+ goto done;
+ ptr = newptr;
+ size = newsize;
+ read_pos = size - nbytes_avail + ptr;
+ }
+
+ c = getc (stream);
+ if (c == EOF)
+ {
+ /* Return partial line, if any. */
+ if (read_pos == ptr)
+ goto done;
+ else
+ break;
+ }
+
+ if (nbytes_avail >= 2)
+ {
+ *read_pos++ = c;
+ nbytes_avail--;
+ }
+
+ if (c == delim1 || c == delim2)
+ /* Return the line. */
+ break;
+ }
+
+ /* Done - NUL terminate and return the number of bytes read.
+ At this point we know that nbytes_avail >= 1. */
+ *read_pos = '\0';
+
+ bytes_stored = read_pos - (ptr + offset);
+
+ done:
+ *lineptr = ptr;
+ *linesize = size;
+ return bytes_stored;
+}
diff --git a/lib/getndelim2.h b/lib/getndelim2.h
new file mode 100644
index 0000000..fb0a8c3
--- /dev/null
+++ b/lib/getndelim2.h
@@ -0,0 +1,43 @@
+/* getndelim2 - Read a line from a stream, stopping at one of 2 delimiters,
+ with bounded memory allocation.
+
+ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef GETNDELIM2_H
+#define GETNDELIM2_H 1
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#define GETNLINE_NO_LIMIT ((size_t) -1)
+
+/* Read into a buffer *LINEPTR returned from malloc (or NULL),
+ pointing to *LINESIZE bytes of space. Store the input bytes
+ starting at *LINEPTR + OFFSET, and null-terminate them. Reallocate
+ the buffer as necessary, but if NMAX is not GETNLINE_NO_LIMIT
+ then do not allocate more than NMAX bytes; if the line is longer
+ than that, read and discard the extra bytes. Stop reading after
+ after the first occurrence of DELIM1 or DELIM2, whichever comes
+ first; a delimiter equal to EOF stands for no delimiter. Read the
+ input bytes from STREAM.
+ Return the number of bytes read and stored at *LINEPTR + OFFSET (not
+ including the NUL terminator), or -1 on error or EOF. */
+extern ssize_t getndelim2 (char **lineptr, size_t *linesize, size_t offset,
+ size_t nmax, int delim1, int delim2,
+ FILE *stream);
+
+#endif /* GETNDELIM2_H */
diff --git a/lib/getnline.c b/lib/getnline.c
new file mode 100644
index 0000000..c8cd38c
--- /dev/null
+++ b/lib/getnline.c
@@ -0,0 +1,39 @@
+/* getnline - Read a line from a stream, with bounded memory allocation.
+
+ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "getnline.h"
+
+#include "getndelim2.h"
+
+ssize_t
+getndelim (char **lineptr, size_t *linesize, size_t nmax,
+ int delimiter, FILE *stream)
+{
+ return getndelim2 (lineptr, linesize, 0, nmax, delimiter, EOF, stream);
+}
+
+ssize_t
+getnline (char **lineptr, size_t *linesize, size_t nmax, FILE *stream)
+{
+ return getndelim (lineptr, linesize, nmax, '\n', stream);
+}
diff --git a/lib/getnline.h b/lib/getnline.h
new file mode 100644
index 0000000..ac389bc
--- /dev/null
+++ b/lib/getnline.h
@@ -0,0 +1,48 @@
+/* getnline - Read a line from a stream, with bounded memory allocation.
+
+ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef GETNLINE_H
+#define GETNLINE_H 1
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#define GETNLINE_NO_LIMIT ((size_t) -1)
+
+/* Read a line, up to the next newline, from STREAM, and store it in *LINEPTR.
+ *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE
+ bytes of space. It is realloc'd as necessary. Reallocation is limited to
+ NMAX bytes; if the line is longer than that, the extra bytes are read but
+ thrown away.
+ Return the number of bytes read and stored at *LINEPTR (not including the
+ NUL terminator), or -1 on error or EOF. */
+extern ssize_t getnline (char **lineptr, size_t *linesize, size_t nmax,
+ FILE *stream);
+
+/* Read a line, up to the next occurrence of DELIMITER, from STREAM, and store
+ it in *LINEPTR.
+ *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE
+ bytes of space. It is realloc'd as necessary. Reallocation is limited to
+ NMAX bytes; if the line is longer than that, the extra bytes are read but
+ thrown away.
+ Return the number of bytes read and stored at *LINEPTR (not including the
+ NUL terminator), or -1 on error or EOF. */
+extern ssize_t getndelim (char **lineptr, size_t *linesize, size_t nmax,
+ int delimiter, FILE *stream);
+
+#endif /* GETNLINE_H */
diff --git a/lib/getopt.c b/lib/getopt.c
new file mode 100644
index 0000000..bcb81c8
--- /dev/null
+++ b/lib/getopt.c
@@ -0,0 +1,1241 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to drepper@gnu.org
+ before changing it!
+ Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library. */
+
+#include <string.h>
+
+#ifdef VMS
+# include <unixlib.h>
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "gettext.h"
+# define _(msgid) gettext (msgid)
+#endif
+
+#if defined _LIBC && defined USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+#ifndef attribute_hidden
+# define attribute_hidden
+#endif
+
+/* Unlike standard Unix `getopt', functions like `getopt_long'
+ let the user intersperse the options with the other arguments.
+
+ As `getopt_long' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Using `getopt' or setting the environment variable POSIXLY_CORRECT
+ disables permutation.
+ Then the application's behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+#include "getopt_int.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Keep a global copy of all internal members of getopt_data. */
+
+static struct _getopt_data getopt_data;
+
+
+#ifndef __GNU_LIBRARY__
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+#endif /* not __GNU_LIBRARY__ */
+
+#ifdef _LIBC
+/* Stored original parameters.
+ XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+extern int __libc_argc;
+extern char **__libc_argv;
+
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+# ifdef USE_NONOPTION_FLAGS
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+# endif
+
+# ifdef USE_NONOPTION_FLAGS
+# define SWAP_FLAGS(ch1, ch2) \
+ if (d->__nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+# else
+# define SWAP_FLAGS(ch1, ch2)
+# endif
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (char **argv, struct _getopt_data *d)
+{
+ int bottom = d->__first_nonopt;
+ int middle = d->__last_nonopt;
+ int top = d->optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0;
+ else
+ {
+ memset (__mempcpy (new_str, __getopt_nonoption_flags,
+ d->__nonoption_flags_max_len),
+ '\0', top + 1 - d->__nonoption_flags_max_len);
+ d->__nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ d->__first_nonopt += (d->optind - d->__last_nonopt);
+ d->__last_nonopt = d->optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (int argc, char **argv, const char *optstring,
+ int posixly_correct, struct _getopt_data *d)
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ d->__first_nonopt = d->__last_nonopt = d->optind;
+
+ d->__nextchar = NULL;
+
+ d->__posixly_correct = posixly_correct || !!getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ d->__ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ d->__ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (d->__posixly_correct)
+ d->__ordering = REQUIRE_ORDER;
+ else
+ d->__ordering = PERMUTE;
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ if (!d->__posixly_correct
+ && argc == __libc_argc && argv == __libc_argv)
+ {
+ if (d->__nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ d->__nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = d->__nonoption_flags_max_len = strlen (orig_str);
+ if (d->__nonoption_flags_max_len < argc)
+ d->__nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (d->__nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ d->__nonoption_flags_max_len = -1;
+ else
+ memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+ '\0', d->__nonoption_flags_max_len - len);
+ }
+ }
+ d->__nonoption_flags_len = d->__nonoption_flags_max_len;
+ }
+ else
+ d->__nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options.
+
+ If POSIXLY_CORRECT is nonzero, behave as if the POSIXLY_CORRECT
+ environment variable were set. */
+
+int
+_getopt_internal_r (int argc, char **argv, const char *optstring,
+ const struct option *longopts, int *longind,
+ int long_only, int posixly_correct, struct _getopt_data *d)
+{
+ int print_errors = d->opterr;
+ if (optstring[0] == ':')
+ print_errors = 0;
+
+ if (argc < 1)
+ return -1;
+
+ d->optarg = NULL;
+
+ if (d->optind == 0 || !d->__initialized)
+ {
+ if (d->optind == 0)
+ d->optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring,
+ posixly_correct, d);
+ d->__initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \
+ || (d->optind < d->__nonoption_flags_len \
+ && __getopt_nonoption_flags[d->optind] == '1'))
+#else
+# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')
+#endif
+
+ if (d->__nextchar == NULL || *d->__nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (d->__last_nonopt > d->optind)
+ d->__last_nonopt = d->optind;
+ if (d->__first_nonopt > d->optind)
+ d->__first_nonopt = d->optind;
+
+ if (d->__ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (d->__first_nonopt != d->__last_nonopt
+ && d->__last_nonopt != d->optind)
+ exchange ((char **) argv, d);
+ else if (d->__last_nonopt != d->optind)
+ d->__first_nonopt = d->optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (d->optind < argc && NONOPTION_P)
+ d->optind++;
+ d->__last_nonopt = d->optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (d->optind != argc && !strcmp (argv[d->optind], "--"))
+ {
+ d->optind++;
+
+ if (d->__first_nonopt != d->__last_nonopt
+ && d->__last_nonopt != d->optind)
+ exchange ((char **) argv, d);
+ else if (d->__first_nonopt == d->__last_nonopt)
+ d->__first_nonopt = d->optind;
+ d->__last_nonopt = argc;
+
+ d->optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (d->optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (d->__first_nonopt != d->__last_nonopt)
+ d->optind = d->__first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (d->__ordering == REQUIRE_ORDER)
+ return -1;
+ d->optarg = argv[d->optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ d->__nextchar = (argv[d->optind] + 1
+ + (longopts != NULL && argv[d->optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[d->optind][1] == '-'
+ || (long_only && (argv[d->optind][2]
+ || !strchr (optstring, argv[d->optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
+ {
+ if ((unsigned int) (nameend - d->__nextchar)
+ == (unsigned int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else if (long_only
+ || pfound->has_arg != p->has_arg
+ || pfound->flag != p->flag
+ || pfound->val != p->val)
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[d->optind]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[d->optind]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ d->optind++;
+ d->optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ d->optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ d->optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+ int n;
+#endif
+
+ if (argv[d->optind - 1][1] == '-')
+ {
+ /* --option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("\
+%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+#else
+ fprintf (stderr, _("\
+%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+#endif
+ }
+ else
+ {
+ /* +option or -option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("\
+%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[d->optind - 1][0],
+ pfound->name);
+#else
+ fprintf (stderr, _("\
+%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[d->optind - 1][0],
+ pfound->name);
+#endif
+ }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+ if (n >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#endif
+ }
+
+ d->__nextchar += strlen (d->__nextchar);
+
+ d->optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (d->optind < argc)
+ d->optarg = argv[d->optind++];
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ d->optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[d->optind][1] == '-'
+ || strchr (optstring, *d->__nextchar) == NULL)
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+ int n;
+#endif
+
+ if (argv[d->optind][1] == '-')
+ {
+ /* --option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"),
+ argv[0], d->__nextchar);
+#else
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], d->__nextchar);
+#endif
+ }
+ else
+ {
+ /* +option or -option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[d->optind][0], d->__nextchar);
+#else
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[d->optind][0], d->__nextchar);
+#endif
+ }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+ if (n >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#endif
+ }
+ d->__nextchar = (char *) "";
+ d->optind++;
+ d->optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *d->__nextchar++;
+ char *temp = strchr (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*d->__nextchar == '\0')
+ ++d->optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+ int n;
+#endif
+
+ if (d->__posixly_correct)
+ {
+ /* 1003.2 specifies the format of this message. */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+#else
+ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c);
+#endif
+ }
+ else
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+#else
+ fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c);
+#endif
+ }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+ if (n >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#endif
+ }
+ d->optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*d->__nextchar != '\0')
+ {
+ d->optarg = d->__nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ d->optind++;
+ }
+ else if (d->optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+#endif
+ }
+ d->optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `d->optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ d->optarg = argv[d->optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '=';
+ nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
+ {
+ if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[d->optind]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[d->optind]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ d->optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ d->optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+#endif
+ }
+
+ d->__nextchar += strlen (d->__nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (d->optind < argc)
+ d->optarg = argv[d->optind++];
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ d->__nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*d->__nextchar != '\0')
+ {
+ d->optarg = d->__nextchar;
+ d->optind++;
+ }
+ else
+ d->optarg = NULL;
+ d->__nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*d->__nextchar != '\0')
+ {
+ d->optarg = d->__nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ d->optind++;
+ }
+ else if (d->optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option requires an argument -- %c\n"),
+ argv[0], c) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+ fputs (buf, stderr);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+#endif
+ }
+ d->optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ d->optarg = argv[d->optind++];
+ d->__nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+_getopt_internal (int argc, char **argv, const char *optstring,
+ const struct option *longopts, int *longind,
+ int long_only, int posixly_correct)
+{
+ int result;
+
+ getopt_data.optind = optind;
+ getopt_data.opterr = opterr;
+
+ result = _getopt_internal_r (argc, argv, optstring, longopts, longind,
+ long_only, posixly_correct, &getopt_data);
+
+ optind = getopt_data.optind;
+ optarg = getopt_data.optarg;
+ optopt = getopt_data.optopt;
+
+ return result;
+}
+
+/* glibc gets a LSB-compliant getopt.
+ Standalone applications get a POSIX-compliant getopt. */
+#if _LIBC
+enum { POSIXLY_CORRECT = 0 };
+#else
+enum { POSIXLY_CORRECT = 1 };
+#endif
+
+int
+getopt (int argc, char *const *argv, const char *optstring)
+{
+ return _getopt_internal (argc, (char **) argv, optstring, NULL, NULL, 0,
+ POSIXLY_CORRECT);
+}
+
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (int argc, char **argv)
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/getopt1.c b/lib/getopt1.c
new file mode 100644
index 0000000..25d7926
--- /dev/null
+++ b/lib/getopt1.c
@@ -0,0 +1,174 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# include <getopt.h>
+#else
+# include "getopt.h"
+#endif
+#include "getopt_int.h"
+
+#include <stdio.h>
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (int argc, char *__getopt_argv_const *argv, const char *options,
+ const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, (char **) argv, options, long_options,
+ opt_index, 0, 0);
+}
+
+int
+_getopt_long_r (int argc, char **argv, const char *options,
+ const struct option *long_options, int *opt_index,
+ struct _getopt_data *d)
+{
+ return _getopt_internal_r (argc, argv, options, long_options, opt_index,
+ 0, 0, d);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (int argc, char *__getopt_argv_const *argv,
+ const char *options,
+ const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, (char **) argv, options, long_options,
+ opt_index, 1, 0);
+}
+
+int
+_getopt_long_only_r (int argc, char **argv, const char *options,
+ const struct option *long_options, int *opt_index,
+ struct _getopt_data *d)
+{
+ return _getopt_internal_r (argc, argv, options, long_options, opt_index,
+ 1, 0, d);
+}
+
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/getopt_.h b/lib/getopt_.h
new file mode 100644
index 0000000..a4e78cb
--- /dev/null
+++ b/lib/getopt_.h
@@ -0,0 +1,227 @@
+/* Declarations for getopt.
+ Copyright (C) 1989-1994,1996-1999,2001,2003,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _GETOPT_H
+
+#ifndef __need_getopt
+# define _GETOPT_H 1
+#endif
+
+/* Standalone applications should #define __GETOPT_PREFIX to an
+ identifier that prefixes the external functions and variables
+ defined in this header. When this happens, include the
+ headers that might declare getopt so that they will not cause
+ confusion if included after this file. Then systematically rename
+ identifiers so that they do not collide with the system functions
+ and variables. Renaming avoids problems with some compilers and
+ linkers. */
+#if defined __GETOPT_PREFIX && !defined __need_getopt
+# include <stdlib.h>
+# include <stdio.h>
+# if HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+# undef __need_getopt
+# undef getopt
+# undef getopt_long
+# undef getopt_long_only
+# undef optarg
+# undef opterr
+# undef optind
+# undef optopt
+# define __GETOPT_CONCAT(x, y) x ## y
+# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y)
+# define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y)
+# define getopt __GETOPT_ID (getopt)
+# define getopt_long __GETOPT_ID (getopt_long)
+# define getopt_long_only __GETOPT_ID (getopt_long_only)
+# define optarg __GETOPT_ID (optarg)
+# define opterr __GETOPT_ID (opterr)
+# define optind __GETOPT_ID (optind)
+# define optopt __GETOPT_ID (optopt)
+#endif
+
+/* Standalone applications get correct prototypes for getopt_long and
+ getopt_long_only; they declare "char **argv". libc uses prototypes
+ with "char *const *argv" that are incorrect because getopt_long and
+ getopt_long_only can permute argv; this is required for backward
+ compatibility (e.g., for LSB 2.0.1).
+
+ This used to be `#if defined __GETOPT_PREFIX && !defined __need_getopt',
+ but it caused redefinition warnings if both unistd.h and getopt.h were
+ included, since unistd.h includes getopt.h having previously defined
+ __need_getopt.
+
+ The only place where __getopt_argv_const is used is in definitions
+ of getopt_long and getopt_long_only below, but these are visible
+ only if __need_getopt is not defined, so it is quite safe to rewrite
+ the conditional as follows:
+*/
+#if !defined __need_getopt
+# if defined __GETOPT_PREFIX
+# define __getopt_argv_const /* empty */
+# else
+# define __getopt_argv_const const
+# endif
+#endif
+
+/* If __GNU_LIBRARY__ is not already defined, either we are being used
+ standalone, or this is the first header included in the source file.
+ If we are being used with glibc, we need to include <features.h>, but
+ that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
+ not defined, include <ctype.h>, which will pull in <features.h> for us
+ if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
+ doesn't flood the namespace with stuff the way some other headers do.) */
+#if !defined __GNU_LIBRARY__
+# include <ctype.h>
+#endif
+
+#ifndef __THROW
+# ifndef __GNUC_PREREQ
+# define __GNUC_PREREQ(maj, min) (0)
+# endif
+# if defined __cplusplus && __GNUC_PREREQ (2,8)
+# define __THROW throw ()
+# else
+# define __THROW
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+#ifndef __need_getopt
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+ const char *name;
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+# define no_argument 0
+# define required_argument 1
+# define optional_argument 2
+#endif /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+ arguments in ARGV (ARGC of them, minus the program name) for
+ options given in OPTS.
+
+ Return the option character from OPTS just read. Return -1 when
+ there are no more options. For unrecognized options, or options
+ missing arguments, `optopt' is set to the option letter, and '?' is
+ returned.
+
+ The OPTS string is a list of characters which are recognized option
+ letters, optionally followed by colons, specifying that that letter
+ takes an argument, to be placed in `optarg'.
+
+ If a letter in OPTS is followed by two colons, its argument is
+ optional. This behavior is specific to the GNU `getopt'.
+
+ The argument `--' causes premature termination of argument
+ scanning, explicitly telling `getopt' that there are no more
+ options.
+
+ If OPTS begins with `--', then non-option arguments are treated as
+ arguments to the option '\0'. This behavior is specific to the GNU
+ `getopt'. */
+
+extern int getopt (int ___argc, char *const *___argv, const char *__shortopts)
+ __THROW;
+
+#ifndef __need_getopt
+extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind)
+ __THROW;
+extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind)
+ __THROW;
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations. */
+#undef __need_getopt
+
+#endif /* getopt.h */
diff --git a/lib/getopt_int.h b/lib/getopt_int.h
new file mode 100644
index 0000000..401579f
--- /dev/null
+++ b/lib/getopt_int.h
@@ -0,0 +1,131 @@
+/* Internal declarations for getopt.
+ Copyright (C) 1989-1994,1996-1999,2001,2003,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _GETOPT_INT_H
+#define _GETOPT_INT_H 1
+
+extern int _getopt_internal (int ___argc, char **___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind,
+ int __long_only, int __posixly_correct);
+
+
+/* Reentrant versions which can handle parsing multiple argument
+ vectors at the same time. */
+
+/* Data type for reentrant functions. */
+struct _getopt_data
+{
+ /* These have exactly the same meaning as the corresponding global
+ variables, except that they are used for the reentrant
+ versions of getopt. */
+ int optind;
+ int opterr;
+ int optopt;
+ char *optarg;
+
+ /* Internal members. */
+
+ /* True if the internal members have been initialized. */
+ int __initialized;
+
+ /* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+ char *__nextchar;
+
+ /* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters, or by calling getopt.
+
+ PERMUTE is the default. We permute the contents of ARGV as we
+ scan, so that eventually all the non-options are at the end.
+ This allows options to be given in any order, even with programs
+ that were not written to expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were
+ written to expect options and other ARGV-elements in any order
+ and that care about the ordering of the two. We describe each
+ non-option ARGV-element as if it were the argument of an option
+ with character code 1. Using `-' as the first character of the
+ list of option characters selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+ enum
+ {
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+ } __ordering;
+
+ /* If the POSIXLY_CORRECT environment variable is set
+ or getopt was called. */
+ int __posixly_correct;
+
+
+ /* Handle permutation of arguments. */
+
+ /* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first
+ of them; `last_nonopt' is the index after the last of them. */
+
+ int __first_nonopt;
+ int __last_nonopt;
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ int __nonoption_flags_max_len;
+ int __nonoption_flags_len;
+# endif
+};
+
+/* The initializer is necessary to set OPTIND and OPTERR to their
+ default values and to clear the initialization flag. */
+#define _GETOPT_DATA_INITIALIZER { 1, 1 }
+
+extern int _getopt_internal_r (int ___argc, char **___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind,
+ int __long_only, int __posixly_correct,
+ struct _getopt_data *__data);
+
+extern int _getopt_long_r (int ___argc, char **___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind,
+ struct _getopt_data *__data);
+
+extern int _getopt_long_only_r (int ___argc, char **___argv,
+ const char *__shortopts,
+ const struct option *__longopts,
+ int *__longind,
+ struct _getopt_data *__data);
+
+#endif /* getopt_int.h */
diff --git a/lib/getpagesize.h b/lib/getpagesize.h
new file mode 100644
index 0000000..17f070f
--- /dev/null
+++ b/lib/getpagesize.h
@@ -0,0 +1,65 @@
+/* Emulate getpagesize on systems that lack it.
+ Copyright (C) 1999, 2000, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef HAVE_GETPAGESIZE
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !defined getpagesize && defined _SC_PAGESIZE
+# if !(defined VMS && __VMS_VER < 70000000)
+# define getpagesize() sysconf (_SC_PAGESIZE)
+# endif
+#endif
+
+#if !defined getpagesize && defined VMS
+# ifdef __ALPHA
+# define getpagesize() 8192
+# else
+# define getpagesize() 512
+# endif
+#endif
+
+/* This is for BeOS. */
+#if !defined getpagesize && HAVE_OS_H
+# include <OS.h>
+# if defined B_PAGE_SIZE
+# define getpagesize() B_PAGE_SIZE
+# endif
+#endif
+
+#if !defined getpagesize && HAVE_SYS_PARAM_H
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define getpagesize() EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define CLSIZE 1
+# endif
+# define getpagesize() (NBPG * CLSIZE)
+# else
+# ifdef NBPC
+# define getpagesize() NBPC
+# endif
+# endif
+# endif
+#endif
+
+#endif /* not HAVE_GETPAGESIZE */
diff --git a/lib/getpass.c b/lib/getpass.c
new file mode 100644
index 0000000..f0b3184
--- /dev/null
+++ b/lib/getpass.c
@@ -0,0 +1,226 @@
+/* Copyright (C) 1992-2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getpass.h"
+
+#include <stdio.h>
+
+#if !defined _WIN32
+
+#include <stdbool.h>
+
+#if HAVE_STDIO_EXT_H
+# include <stdio_ext.h>
+#endif
+#if !HAVE___FSETLOCKING
+# define __fsetlocking(stream, type) /* empty */
+#endif
+
+#if HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+
+#include "getline.h"
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#else
+# if !HAVE_DECL_FFLUSH_UNLOCKED
+# undef fflush_unlocked
+# define fflush_unlocked(x) fflush (x)
+# endif
+# if !HAVE_DECL_FLOCKFILE
+# undef flockfile
+# define flockfile(x) ((void) 0)
+# endif
+# if !HAVE_DECL_FUNLOCKFILE
+# undef funlockfile
+# define funlockfile(x) ((void) 0)
+# endif
+# if !HAVE_DECL_FPUTS_UNLOCKED
+# undef fputs_unlocked
+# define fputs_unlocked(str,stream) fputs (str, stream)
+# endif
+# if !HAVE_DECL_PUTC_UNLOCKED
+# undef putc_unlocked
+# define putc_unlocked(c,stream) putc (c, stream)
+# endif
+#endif
+
+/* It is desirable to use this bit on systems that have it.
+ The only bit of terminal state we want to twiddle is echoing, which is
+ done in software; there is no need to change the state of the terminal
+ hardware. */
+
+#ifndef TCSASOFT
+# define TCSASOFT 0
+#endif
+
+static void
+call_fclose (void *arg)
+{
+ if (arg != NULL)
+ fclose (arg);
+}
+
+char *
+getpass (const char *prompt)
+{
+ FILE *tty;
+ FILE *in, *out;
+ struct termios s, t;
+ bool tty_changed = false;
+ static char *buf;
+ static size_t bufsize;
+ ssize_t nread;
+
+ /* Try to write to and read from the terminal if we can.
+ If we can't open the terminal, use stderr and stdin. */
+
+ tty = fopen ("/dev/tty", "w+");
+ if (tty == NULL)
+ {
+ in = stdin;
+ out = stderr;
+ }
+ else
+ {
+ /* We do the locking ourselves. */
+ __fsetlocking (tty, FSETLOCKING_BYCALLER);
+
+ out = in = tty;
+ }
+
+ flockfile (out);
+
+ /* Turn echoing off if it is on now. */
+#if HAVE_TCGETATTR
+ if (tcgetattr (fileno (in), &t) == 0)
+ {
+ /* Save the old one. */
+ s = t;
+ /* Tricky, tricky. */
+ t.c_lflag &= ~(ECHO | ISIG);
+ tty_changed = (tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &t) == 0);
+ }
+#endif
+
+ /* Write the prompt. */
+ fputs_unlocked (prompt, out);
+ fflush_unlocked (out);
+
+ /* Read the password. */
+ nread = getline (&buf, &bufsize, in);
+
+ /* According to the C standard, input may not be followed by output
+ on the same stream without an intervening call to a file
+ positioning function. Suppose in == out; then without this fseek
+ call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
+ echoed, whereas on IRIX, the following newline is not output as
+ it should be. POSIX imposes similar restrictions if fileno (in)
+ == fileno (out). The POSIX restrictions are tricky and change
+ from POSIX version to POSIX version, so play it safe and invoke
+ fseek even if in != out. */
+ fseek (out, 0, SEEK_CUR);
+
+ if (buf != NULL)
+ {
+ if (nread < 0)
+ buf[0] = '\0';
+ else if (buf[nread - 1] == '\n')
+ {
+ /* Remove the newline. */
+ buf[nread - 1] = '\0';
+ if (tty_changed)
+ {
+ /* Write the newline that was not echoed. */
+ putc_unlocked ('\n', out);
+ }
+ }
+ }
+
+ /* Restore the original setting. */
+#if HAVE_TCSETATTR
+ if (tty_changed)
+ tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &s);
+#endif
+
+ funlockfile (out);
+
+ call_fclose (tty);
+
+ return buf;
+}
+
+#else /* WIN32 */
+
+/* Windows implementation by Martin Lambers <marlam@marlam.de>,
+ improved by Simon Josefsson. */
+
+/* For PASS_MAX. */
+#include <limits.h>
+
+#ifndef PASS_MAX
+# define PASS_MAX 512
+#endif
+
+char *
+getpass (const char *prompt)
+{
+ char getpassbuf[PASS_MAX + 1];
+ size_t i = 0;
+ int c;
+
+ if (prompt)
+ {
+ fputs (prompt, stderr);
+ fflush (stderr);
+ }
+
+ for (;;)
+ {
+ c = _getch ();
+ if (c == '\r')
+ {
+ getpassbuf[i] = '\0';
+ break;
+ }
+ else if (i < PASS_MAX)
+ {
+ getpassbuf[i++] = c;
+ }
+
+ if (i >= PASS_MAX)
+ {
+ getpassbuf[i] = '\0';
+ break;
+ }
+ }
+
+ if (prompt)
+ {
+ fputs ("\r\n", stderr);
+ fflush (stderr);
+ }
+
+ return strdup (getpassbuf);
+}
+#endif
diff --git a/lib/getpass.h b/lib/getpass.h
new file mode 100644
index 0000000..bdff875
--- /dev/null
+++ b/lib/getpass.h
@@ -0,0 +1,31 @@
+/* getpass.h -- Read a password of arbitrary length from /dev/tty or stdin.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ Contributed by Simon Josefsson <jas@extundo.com>, 2004.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef GETPASS_H
+# define GETPASS_H
+
+/* Get getpass declaration, if available. */
+# include <unistd.h>
+
+# if defined HAVE_DECL_GETPASS && !HAVE_DECL_GETPASS
+/* Read a password of arbitrary length from /dev/tty or stdin. */
+char *getpass (const char *prompt);
+
+# endif
+
+#endif /* GETPASS_H */
diff --git a/lib/gettext.h b/lib/gettext.h
new file mode 100644
index 0000000..285cb31
--- /dev/null
+++ b/lib/gettext.h
@@ -0,0 +1,78 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+ Copyright (C) 1995-1998, 2000-2002, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option. */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions. */
+# include <libintl.h>
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+ chokes if dcgettext is defined as a macro. So include it now, to make
+ later inclusions of <locale.h> a NOP. We don't include <libintl.h>
+ as well because people using "gettext.h" will not include <libintl.h>,
+ and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+ is OK. */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
+ <libintl.h>, which chokes if dcgettext is defined as a macro. So include
+ it now, to make later inclusions of <libintl.h> a NOP. */
+#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
+# include <cstdlib>
+# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
+# include <libintl.h>
+# endif
+#endif
+
+/* Disabled NLS.
+ The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions.
+ On pre-ANSI systems without 'const', the config.h file is supposed to
+ contain "#define const". */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+ extraction of messages, but does not call gettext(). The run-time
+ translation is done at a different place in the code.
+ The argument, String, should be a literal string. Concatenated strings
+ and other string expressions won't work.
+ The macro's expansion is not parenthesized, so that it is suitable as
+ initializer for static 'char[]' or 'const char[]' variables. */
+#define gettext_noop(String) String
+
+#endif /* _LIBGETTEXT_H */
diff --git a/lib/gettime.c b/lib/gettime.c
new file mode 100644
index 0000000..0f94297
--- /dev/null
+++ b/lib/gettime.c
@@ -0,0 +1,53 @@
+/* gettime -- get the system clock
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "timespec.h"
+
+/* Get the system time into *TS. */
+
+void
+gettime (struct timespec *ts)
+{
+#if HAVE_NANOTIME
+ nanotime (ts);
+#else
+
+# if defined CLOCK_REALTIME && HAVE_CLOCK_GETTIME
+ if (clock_gettime (CLOCK_REALTIME, ts) == 0)
+ return;
+# endif
+
+# if HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+ }
+# else
+ ts->tv_sec = time (NULL);
+ ts->tv_nsec = 0;
+# endif
+
+#endif
+}
diff --git a/lib/gettimeofday.c b/lib/gettimeofday.c
new file mode 100644
index 0000000..eb6de94
--- /dev/null
+++ b/lib/gettimeofday.c
@@ -0,0 +1,123 @@
+/* Work around the bug in some systems whereby gettimeofday clobbers the
+ static buffer that localtime uses for it's return value. The gettimeofday
+ function from Mac OS X 10.0.4, i.e. Darwin 1.3.7 has this problem.
+ The tzset replacement is necessary for at least Solaris 2.5, 2.5.1, and 2.6.
+ Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Disable the definitions of these functions (from config.h)
+ so we can use the library versions here. */
+#undef gettimeofday
+#undef gmtime
+#undef localtime
+#undef tzset
+
+#include <sys/types.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <stdlib.h>
+
+static struct tm *localtime_buffer_addr;
+
+/* This is a wrapper for localtime. It is used only on systems for which
+ gettimeofday clobbers the static buffer used for localtime's result.
+
+ On the first call, record the address of the static buffer that
+ localtime uses for its result. */
+
+struct tm *
+rpl_localtime (const time_t *timep)
+{
+ struct tm *tm = localtime (timep);
+
+ if (! localtime_buffer_addr)
+ localtime_buffer_addr = tm;
+
+ return tm;
+}
+
+/* Same as above, since gmtime and localtime use the same buffer. */
+struct tm *
+rpl_gmtime (const time_t *timep)
+{
+ struct tm *tm = gmtime (timep);
+
+ if (! localtime_buffer_addr)
+ localtime_buffer_addr = tm;
+
+ return tm;
+}
+
+/* This is a wrapper for gettimeofday. It is used only on systems for which
+ gettimeofday clobbers the static buffer used for localtime's result.
+
+ Save and restore the contents of the buffer used for localtime's result
+ around the call to gettimeofday. */
+
+int
+rpl_gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+ struct tm save;
+ int result;
+
+ if (! localtime_buffer_addr)
+ {
+ time_t t = 0;
+ localtime_buffer_addr = localtime (&t);
+ }
+
+ save = *localtime_buffer_addr;
+ result = gettimeofday (tv, tz);
+ *localtime_buffer_addr = save;
+
+ return result;
+}
+
+/* This is a wrapper for tzset. It is used only on systems for which
+ tzset may clobber the static buffer used for localtime's result.
+ Save and restore the contents of the buffer used for localtime's
+ result around the call to tzset. */
+void
+rpl_tzset (void)
+{
+ struct tm save;
+
+ if (! localtime_buffer_addr)
+ {
+ time_t t = 0;
+ localtime_buffer_addr = localtime (&t);
+ }
+
+ save = *localtime_buffer_addr;
+ tzset ();
+ *localtime_buffer_addr = save;
+}
diff --git a/lib/glob-libc.h b/lib/glob-libc.h
new file mode 100644
index 0000000..95b76c8
--- /dev/null
+++ b/lib/glob-libc.h
@@ -0,0 +1,196 @@
+/* Copyright (C) 1991,92,95-98,2000,2001,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _GLOB_H
+#define _GLOB_H 1
+
+#ifndef __GLOB_GNULIB
+# include <sys/cdefs.h>
+#endif
+
+__BEGIN_DECLS
+
+/* We need `size_t' for the following definitions. */
+#ifndef __size_t
+# if defined __GNUC__ && __GNUC__ >= 2
+typedef __SIZE_TYPE__ __size_t;
+# ifdef __USE_XOPEN
+typedef __SIZE_TYPE__ size_t;
+# endif
+# else
+# include <stddef.h>
+# ifndef __size_t
+# define __size_t size_t
+# endif
+# endif
+#else
+/* The GNU CC stddef.h version defines __size_t as empty. We need a real
+ definition. */
+# undef __size_t
+# define __size_t size_t
+#endif
+
+/* Bits set in the FLAGS argument to `glob'. */
+#define GLOB_ERR (1 << 0)/* Return on read errors. */
+#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
+#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
+#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
+#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
+#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
+#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
+#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
+
+#if !defined __USE_POSIX2 || defined __USE_BSD || defined __USE_GNU
+# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
+# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
+# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
+# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
+# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
+# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
+# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
+ if the user name is not available. */
+# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+ GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
+ GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
+#else
+# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+ GLOB_PERIOD)
+#endif
+
+/* Error returns from `glob'. */
+#define GLOB_NOSPACE 1 /* Ran out of memory. */
+#define GLOB_ABORTED 2 /* Read error. */
+#define GLOB_NOMATCH 3 /* No matches found. */
+#define GLOB_NOSYS 4 /* Not implemented. */
+#ifdef __USE_GNU
+/* Previous versions of this file defined GLOB_ABEND instead of
+ GLOB_ABORTED. Provide a compatibility definition here. */
+# define GLOB_ABEND GLOB_ABORTED
+#endif
+
+/* Structure describing a globbing run. */
+#ifdef __USE_GNU
+struct stat;
+#endif
+typedef struct
+ {
+ __size_t gl_pathc; /* Count of paths matched by the pattern. */
+ char **gl_pathv; /* List of matched pathnames. */
+ __size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
+ int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
+
+ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+ are used instead of the normal file access functions. */
+ void (*gl_closedir) (void *);
+#ifdef __USE_GNU
+ struct dirent *(*gl_readdir) (void *);
+#else
+ void *(*gl_readdir) (void *);
+#endif
+ void *(*gl_opendir) (__const char *);
+#ifdef __USE_GNU
+ int (*gl_lstat) (__const char *__restrict, struct stat *__restrict);
+ int (*gl_stat) (__const char *__restrict, struct stat *__restrict);
+#else
+ int (*gl_lstat) (__const char *__restrict, void *__restrict);
+ int (*gl_stat) (__const char *__restrict, void *__restrict);
+#endif
+ } glob_t;
+
+#if defined __USE_LARGEFILE64 && !defined __GLOB_GNULIB
+# ifdef __USE_GNU
+struct stat64;
+# endif
+typedef struct
+ {
+ __size_t gl_pathc;
+ char **gl_pathv;
+ __size_t gl_offs;
+ int gl_flags;
+
+ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+ are used instead of the normal file access functions. */
+ void (*gl_closedir) (void *);
+# ifdef __USE_GNU
+ struct dirent64 *(*gl_readdir) (void *);
+# else
+ void *(*gl_readdir) (void *);
+# endif
+ void *(*gl_opendir) (__const char *);
+# ifdef __USE_GNU
+ int (*gl_lstat) (__const char *__restrict, struct stat64 *__restrict);
+ int (*gl_stat) (__const char *__restrict, struct stat64 *__restrict);
+# else
+ int (*gl_lstat) (__const char *__restrict, void *__restrict);
+ int (*gl_stat) (__const char *__restrict, void *__restrict);
+# endif
+ } glob64_t;
+#endif
+
+#if __USE_FILE_OFFSET64 && __GNUC__ < 2 && !defined __GLOB_GNULIB
+# define glob glob64
+# define globfree globfree64
+#endif
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ `errno' value from the failing call; if it returns non-zero
+ `glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, `glob' returns zero. */
+#if !defined __USE_FILE_OFFSET64 || __GNUC__ < 2 || defined __GLOB_GNULIB
+extern int glob (__const char *__restrict __pattern, int __flags,
+ int (*__errfunc) (__const char *, int),
+ glob_t *__restrict __pglob) __THROW;
+
+/* Free storage allocated in PGLOB by a previous `glob' call. */
+extern void globfree (glob_t *__pglob) __THROW;
+#else
+extern int __REDIRECT_NTH (glob, (__const char *__restrict __pattern,
+ int __flags,
+ int (*__errfunc) (__const char *, int),
+ glob_t *__restrict __pglob), glob64);
+
+extern void __REDIRECT_NTH (globfree, (glob_t *__pglob), globfree64);
+#endif
+
+#if defined __USE_LARGEFILE64 && !defined __GLOB_GNULIB
+extern int glob64 (__const char *__restrict __pattern, int __flags,
+ int (*__errfunc) (__const char *, int),
+ glob64_t *__restrict __pglob) __THROW;
+
+extern void globfree64 (glob64_t *__pglob) __THROW;
+#endif
+
+
+#ifdef __USE_GNU
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero.
+
+ This function is not part of the interface specified by POSIX.2
+ but several programs want to use it. */
+extern int glob_pattern_p (__const char *__pattern, int __quote) __THROW;
+#endif
+
+__END_DECLS
+
+#endif /* glob.h */
diff --git a/lib/glob.c b/lib/glob.c
new file mode 100644
index 0000000..0567902
--- /dev/null
+++ b/lib/glob.c
@@ -0,0 +1,1289 @@
+/* Copyright (C) 1991-2002,2003,2004,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glob.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+/* Outcomment the following line for production quality code. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include <stdio.h> /* Needed on stupid SunOS for assert. */
+
+#if !defined _LIBC || !defined GLOB_ONLY_P
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+# ifndef POSIX
+# ifdef _POSIX_VERSION
+# define POSIX
+# endif
+# endif
+#endif
+
+#include <pwd.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# ifdef HAVE_VMSDIR_H
+# include "vmsdir.h"
+# endif /* HAVE_VMSDIR_H */
+#endif
+
+
+/* In GNU systems, <dirent.h> defines this macro for us. */
+#ifdef _D_NAMLEN
+# undef NAMLEN
+# define NAMLEN(d) _D_NAMLEN(d)
+#endif
+
+/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+ if the `d_type' member for `struct dirent' is available.
+ HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+/* True if the directory entry D must be of type T. */
+# define DIRENT_MUST_BE(d, t) ((d)->d_type == (t))
+
+/* True if the directory entry D might be a symbolic link. */
+# define DIRENT_MIGHT_BE_SYMLINK(d) \
+ ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
+
+/* True if the directory entry D might be a directory. */
+# define DIRENT_MIGHT_BE_DIR(d) \
+ ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
+
+#else /* !HAVE_D_TYPE */
+# define DIRENT_MUST_BE(d, t) false
+# define DIRENT_MIGHT_BE_SYMLINK(d) true
+# define DIRENT_MIGHT_BE_DIR(d) true
+#endif /* HAVE_D_TYPE */
+
+/* If the system has the `struct dirent64' type we use it internally. */
+#if defined _LIBC && !defined COMPILE_GLOB64
+# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+# define CONVERT_D_NAMLEN(d64, d32)
+# else
+# define CONVERT_D_NAMLEN(d64, d32) \
+ (d64)->d_namlen = (d32)->d_namlen;
+# endif
+
+# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+# define CONVERT_D_INO(d64, d32)
+# else
+# define CONVERT_D_INO(d64, d32) \
+ (d64)->d_ino = (d32)->d_ino;
+# endif
+
+# ifdef _DIRENT_HAVE_D_TYPE
+# define CONVERT_D_TYPE(d64, d32) \
+ (d64)->d_type = (d32)->d_type;
+# else
+# define CONVERT_D_TYPE(d64, d32)
+# endif
+
+# define CONVERT_DIRENT_DIRENT64(d64, d32) \
+ memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \
+ CONVERT_D_NAMLEN (d64, d32) \
+ CONVERT_D_INO (d64, d32) \
+ CONVERT_D_TYPE (d64, d32)
+#endif
+
+
+#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+/* 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 /* POSIX */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* NAME_MAX is usually defined in <dirent.h> or <limits.h>. */
+#include <limits.h>
+#ifndef NAME_MAX
+# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name))
+#endif
+
+#include <alloca.h>
+
+#ifdef _LIBC
+# undef strdup
+# define strdup(str) __strdup (str)
+# define sysconf(id) __sysconf (id)
+# define closedir(dir) __closedir (dir)
+# define opendir(name) __opendir (name)
+# define readdir(str) __readdir64 (str)
+# define getpwnam_r(name, bufp, buf, len, res) \
+ __getpwnam_r (name, bufp, buf, len, res)
+# ifndef __stat64
+# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
+# endif
+# define struct_stat64 struct stat64
+#else /* !_LIBC */
+# include "getlogin_r.h"
+# include "mempcpy.h"
+# include "stat-macros.h"
+# include "strdup.h"
+# define __stat64(fname, buf) stat (fname, buf)
+# define struct_stat64 struct stat
+# define __stat(fname, buf) stat (fname, buf)
+# define __alloca alloca
+# define __readdir readdir
+# define __readdir64 readdir64
+# define __glob_pattern_p glob_pattern_p
+#endif /* _LIBC */
+
+#include <stdbool.h>
+#include <fnmatch.h>
+
+#ifdef _SC_GETPW_R_SIZE_MAX
+# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX)
+#else
+# define GETPW_R_SIZE_MAX() (-1)
+#endif
+#ifdef _SC_LOGIN_NAME_MAX
+# define GET_LOGIN_NAME_MAX() sysconf (_SC_LOGIN_NAME_MAX)
+#else
+# define GET_LOGIN_NAME_MAX() (-1)
+#endif
+
+static const char *next_brace_sub (const char *begin, int flags) __THROW;
+
+#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+
+static int glob_in_dir (const char *pattern, const char *directory,
+ int flags, int (*errfunc) (const char *, int),
+ glob_t *pglob);
+
+#if !defined _LIBC || !defined GLOB_ONLY_P
+static int prefix_array (const char *prefix, char **array, size_t n) __THROW;
+static int collated_compare (const void *, const void *) __THROW;
+
+
+/* Find the end of the sub-pattern in a brace expression. */
+static const char *
+next_brace_sub (const char *cp, int flags)
+{
+ unsigned int depth = 0;
+ while (*cp != '\0')
+ if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
+ {
+ if (*++cp == '\0')
+ break;
+ ++cp;
+ }
+ else
+ {
+ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+ break;
+
+ if (*cp++ == '{')
+ depth++;
+ }
+
+ return *cp != '\0' ? cp : NULL;
+}
+
+#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ `errno' value from the failing call; if it returns non-zero
+ `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, `glob' returns zero. */
+int
+#ifdef GLOB_ATTRIBUTE
+GLOB_ATTRIBUTE
+#endif
+glob (pattern, flags, errfunc, pglob)
+ const char *pattern;
+ int flags;
+ int (*errfunc) (const char *, int);
+ glob_t *pglob;
+{
+ const char *filename;
+ const char *dirname;
+ size_t dirlen;
+ int status;
+ size_t oldcount;
+
+ if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ if (!(flags & GLOB_DOOFFS))
+ /* Have to do this so `globfree' knows where to start freeing. It
+ also makes all the code that uses gl_offs simpler. */
+ pglob->gl_offs = 0;
+
+ if (flags & GLOB_BRACE)
+ {
+ const char *begin;
+
+ if (flags & GLOB_NOESCAPE)
+ begin = strchr (pattern, '{');
+ else
+ {
+ begin = pattern;
+ while (1)
+ {
+ if (*begin == '\0')
+ {
+ begin = NULL;
+ break;
+ }
+
+ if (*begin == '\\' && begin[1] != '\0')
+ ++begin;
+ else if (*begin == '{')
+ break;
+
+ ++begin;
+ }
+ }
+
+ if (begin != NULL)
+ {
+ /* Allocate working buffer large enough for our work. Note that
+ we have at least an opening and closing brace. */
+ size_t firstc;
+ char *alt_start;
+ const char *p;
+ const char *next;
+ const char *rest;
+ size_t rest_len;
+#ifdef __GNUC__
+ char onealt[strlen (pattern) - 1];
+#else
+ char *onealt = malloc (strlen (pattern) - 1);
+ if (onealt == NULL)
+ {
+ if (!(flags & GLOB_APPEND))
+ {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ }
+ return GLOB_NOSPACE;
+ }
+#endif
+
+ /* We know the prefix for all sub-patterns. */
+ alt_start = mempcpy (onealt, pattern, begin - pattern);
+
+ /* Find the first sub-pattern and at the same time find the
+ rest after the closing brace. */
+ next = next_brace_sub (begin + 1, flags);
+ if (next == NULL)
+ {
+ /* It is an illegal expression. */
+#ifndef __GNUC__
+ free (onealt);
+#endif
+ return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+ }
+
+ /* Now find the end of the whole brace expression. */
+ rest = next;
+ while (*rest != '}')
+ {
+ rest = next_brace_sub (rest + 1, flags);
+ if (rest == NULL)
+ {
+ /* It is an illegal expression. */
+#ifndef __GNUC__
+ free (onealt);
+#endif
+ return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+ }
+ }
+ /* Please note that we now can be sure the brace expression
+ is well-formed. */
+ rest_len = strlen (++rest) + 1;
+
+ /* We have a brace expression. BEGIN points to the opening {,
+ NEXT points past the terminator of the first element, and END
+ points past the final }. We will accumulate result names from
+ recursive runs for each brace alternative in the buffer using
+ GLOB_APPEND. */
+
+ if (!(flags & GLOB_APPEND))
+ {
+ /* This call is to set a new vector, so clear out the
+ vector so we can append to it. */
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ }
+ firstc = pglob->gl_pathc;
+
+ p = begin + 1;
+ while (1)
+ {
+ int result;
+
+ /* Construct the new glob expression. */
+ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+
+ result = glob (onealt,
+ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+ | GLOB_APPEND), errfunc, pglob);
+
+ /* If we got an error, return it. */
+ if (result && result != GLOB_NOMATCH)
+ {
+#ifndef __GNUC__
+ free (onealt);
+#endif
+ if (!(flags & GLOB_APPEND))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ }
+ return result;
+ }
+
+ if (*next == '}')
+ /* We saw the last entry. */
+ break;
+
+ p = next + 1;
+ next = next_brace_sub (p, flags);
+ assert (next != NULL);
+ }
+
+#ifndef __GNUC__
+ free (onealt);
+#endif
+
+ if (pglob->gl_pathc != firstc)
+ /* We found some entries. */
+ return 0;
+ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ return GLOB_NOMATCH;
+ }
+ }
+
+ /* Find the filename. */
+ filename = strrchr (pattern, '/');
+#if defined __MSDOS__ || defined WINDOWS32
+ /* The case of "d:pattern". Since `:' is not allowed in
+ file names, we can safely assume that wherever it
+ happens in pattern, it signals the filename part. This
+ is so we could some day support patterns like "[a-z]:foo". */
+ if (filename == NULL)
+ filename = strchr (pattern, ':');
+#endif /* __MSDOS__ || WINDOWS32 */
+ if (filename == NULL)
+ {
+ /* This can mean two things: a simple name or "~name". The latter
+ case is nothing but a notation for a directory. */
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
+ {
+ dirname = pattern;
+ dirlen = strlen (pattern);
+
+ /* Set FILENAME to NULL as a special flag. This is ugly but
+ other solutions would require much more code. We test for
+ this special case below. */
+ filename = NULL;
+ }
+ else
+ {
+ filename = pattern;
+#ifdef _AMIGA
+ dirname = "";
+#else
+ dirname = ".";
+#endif
+ dirlen = 0;
+ }
+ }
+ else if (filename == pattern)
+ {
+ /* "/pattern". */
+ dirname = "/";
+ dirlen = 1;
+ ++filename;
+ }
+ else
+ {
+ char *newp;
+ dirlen = filename - pattern;
+#if defined __MSDOS__ || defined WINDOWS32
+ if (*filename == ':'
+ || (filename > pattern + 1 && filename[-1] == ':'))
+ {
+ char *drive_spec;
+
+ ++dirlen;
+ drive_spec = __alloca (dirlen + 1);
+ *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
+ /* For now, disallow wildcards in the drive spec, to
+ prevent infinite recursion in glob. */
+ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
+ return GLOB_NOMATCH;
+ /* If this is "d:pattern", we need to copy `:' to DIRNAME
+ as well. If it's "d:/pattern", don't remove the slash
+ from "d:/", since "d:" and "d:/" are not the same.*/
+ }
+#endif
+ newp = __alloca (dirlen + 1);
+ *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
+ dirname = newp;
+ ++filename;
+
+ if (filename[0] == '\0'
+#if defined __MSDOS__ || defined WINDOWS32
+ && dirname[dirlen - 1] != ':'
+ && (dirlen < 3 || dirname[dirlen - 2] != ':'
+ || dirname[dirlen - 1] != '/')
+#endif
+ && dirlen > 1)
+ /* "pattern/". Expand "pattern", appending slashes. */
+ {
+ int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+ if (val == 0)
+ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
+ | (flags & GLOB_MARK));
+ return val;
+ }
+ }
+
+ if (!(flags & GLOB_APPEND))
+ {
+ pglob->gl_pathc = 0;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_pathv = NULL;
+ else
+ {
+ size_t i;
+ pglob->gl_pathv = malloc ((pglob->gl_offs + 1) * sizeof (char *));
+ if (pglob->gl_pathv == NULL)
+ return GLOB_NOSPACE;
+
+ for (i = 0; i <= pglob->gl_offs; ++i)
+ pglob->gl_pathv[i] = NULL;
+ }
+ }
+
+ oldcount = pglob->gl_pathc + pglob->gl_offs;
+
+#ifndef VMS
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
+ {
+ if (dirname[1] == '\0' || dirname[1] == '/')
+ {
+ /* Look up home directory. */
+ const char *home_dir = getenv ("HOME");
+# ifdef _AMIGA
+ if (home_dir == NULL || home_dir[0] == '\0')
+ home_dir = "SYS:";
+# else
+# ifdef WINDOWS32
+ if (home_dir == NULL || home_dir[0] == '\0')
+ home_dir = "c:/users/default"; /* poor default */
+# else
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ int success;
+ char *name;
+ size_t buflen = GET_LOGIN_NAME_MAX () + 1;
+
+ if (buflen == 0)
+ /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
+ a moderate value. */
+ buflen = 20;
+ name = __alloca (buflen);
+
+ success = getlogin_r (name, buflen) == 0;
+ if (success)
+ {
+ struct passwd *p;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int pwbuflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+# ifndef _LIBC
+ if (pwbuflen == -1)
+ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+ Try a moderate value. */
+ pwbuflen = 1024;
+# endif
+ pwtmpbuf = __alloca (pwbuflen);
+
+ while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+ != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+# ifdef _LIBC
+ pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
+ 2 * pwbuflen);
+# else
+ pwbuflen *= 2;
+ pwtmpbuf = __alloca (pwbuflen);
+# endif
+ __set_errno (save);
+ }
+# else
+ p = getpwnam (name);
+# endif
+ if (p != NULL)
+ home_dir = p->pw_dir;
+ }
+ }
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ if (flags & GLOB_TILDE_CHECK)
+ return GLOB_NOMATCH;
+ else
+ home_dir = "~"; /* No luck. */
+ }
+# endif /* WINDOWS32 */
+# endif
+ /* Now construct the full directory. */
+ if (dirname[1] == '\0')
+ dirname = home_dir;
+ else
+ {
+ char *newp;
+ size_t home_len = strlen (home_dir);
+ newp = __alloca (home_len + dirlen);
+ mempcpy (mempcpy (newp, home_dir, home_len),
+ &dirname[1], dirlen);
+ dirname = newp;
+ }
+ }
+# if !defined _AMIGA && !defined WINDOWS32
+ else
+ {
+ char *end_name = strchr (dirname, '/');
+ const char *user_name;
+ const char *home_dir;
+
+ if (end_name == NULL)
+ user_name = dirname + 1;
+ else
+ {
+ char *newp;
+ newp = __alloca (end_name - dirname);
+ *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+ = '\0';
+ user_name = newp;
+ }
+
+ /* Look up specific user's home directory. */
+ {
+ struct passwd *p;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int buflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+# ifndef _LIBC
+ if (buflen == -1)
+ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
+ moderate value. */
+ buflen = 1024;
+# endif
+ pwtmpbuf = __alloca (buflen);
+
+ while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+# ifdef _LIBC
+ pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
+# else
+ buflen *= 2;
+ pwtmpbuf = __alloca (buflen);
+# endif
+ __set_errno (save);
+ }
+# else
+ p = getpwnam (user_name);
+# endif
+ if (p != NULL)
+ home_dir = p->pw_dir;
+ else
+ home_dir = NULL;
+ }
+ /* If we found a home directory use this. */
+ if (home_dir != NULL)
+ {
+ char *newp;
+ size_t home_len = strlen (home_dir);
+ size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+ newp = __alloca (home_len + rest_len + 1);
+ *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
+ end_name, rest_len)) = '\0';
+ dirname = newp;
+ }
+ else
+ if (flags & GLOB_TILDE_CHECK)
+ /* We have to regard it as an error if we cannot find the
+ home directory. */
+ return GLOB_NOMATCH;
+ }
+# endif /* Not Amiga && not WINDOWS32. */
+ }
+#endif /* Not VMS. */
+
+ /* Now test whether we looked for "~" or "~NAME". In this case we
+ can give the answer now. */
+ if (filename == NULL)
+ {
+ struct stat st;
+ struct_stat64 st64;
+
+ /* Return the directory if we don't check for error or if it exists. */
+ if ((flags & GLOB_NOCHECK)
+ || (((flags & GLOB_ALTDIRFUNC)
+ ? ((*pglob->gl_stat) (dirname, &st) == 0
+ && S_ISDIR (st.st_mode))
+ : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
+ {
+ int newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ new_gl_pathv
+ = realloc (pglob->gl_pathv, (newcount + 1 + 1) * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ nospace:
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = strdup (dirname);
+ if (pglob->gl_pathv[newcount] == NULL)
+ goto nospace;
+ pglob->gl_pathv[++newcount] = NULL;
+ ++pglob->gl_pathc;
+ pglob->gl_flags = flags;
+
+ return 0;
+ }
+
+ /* Not found. */
+ return GLOB_NOMATCH;
+ }
+
+ if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
+ {
+ /* The directory name contains metacharacters, so we
+ have to glob for the directory, and then glob for
+ the pattern in each directory found. */
+ glob_t dirs;
+ size_t i;
+
+ if ((flags & GLOB_ALTDIRFUNC) != 0)
+ {
+ /* Use the alternative access functions also in the recursive
+ call. */
+ dirs.gl_opendir = pglob->gl_opendir;
+ dirs.gl_readdir = pglob->gl_readdir;
+ dirs.gl_closedir = pglob->gl_closedir;
+ dirs.gl_stat = pglob->gl_stat;
+ dirs.gl_lstat = pglob->gl_lstat;
+ }
+
+ status = glob (dirname,
+ ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
+ | GLOB_ALTDIRFUNC))
+ | GLOB_NOSORT | GLOB_ONLYDIR),
+ errfunc, &dirs);
+ if (status != 0)
+ return status;
+
+ /* We have successfully globbed the preceding directory name.
+ For each name we found, call glob_in_dir on it and FILENAME,
+ appending the results to PGLOB. */
+ for (i = 0; i < dirs.gl_pathc; ++i)
+ {
+ int old_pathc;
+
+#ifdef SHELL
+ {
+ /* Make globbing interruptible in the bash shell. */
+ extern int interrupt_state;
+
+ if (interrupt_state)
+ {
+ globfree (&dirs);
+ return GLOB_ABORTED;
+ }
+ }
+#endif /* SHELL. */
+
+ old_pathc = pglob->gl_pathc;
+ status = glob_in_dir (filename, dirs.gl_pathv[i],
+ ((flags | GLOB_APPEND)
+ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
+ errfunc, pglob);
+ if (status == GLOB_NOMATCH)
+ /* No matches in this directory. Try the next. */
+ continue;
+
+ if (status != 0)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return status;
+ }
+
+ /* Stick the directory on the front of each name. */
+ if (prefix_array (dirs.gl_pathv[i],
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+
+ flags |= GLOB_MAGCHAR;
+
+ /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
+ But if we have not found any matching entry and the GLOB_NOCHECK
+ flag was set we must return the input pattern itself. */
+ if (pglob->gl_pathc + pglob->gl_offs == oldcount)
+ {
+ /* No matches. */
+ if (flags & GLOB_NOCHECK)
+ {
+ int newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ new_gl_pathv = realloc (pglob->gl_pathv,
+ (newcount + 2) * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ globfree (&dirs);
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = strdup (pattern);
+ if (pglob->gl_pathv[newcount] == NULL)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+
+ ++pglob->gl_pathc;
+ ++newcount;
+
+ pglob->gl_pathv[newcount] = NULL;
+ pglob->gl_flags = flags;
+ }
+ else
+ {
+ globfree (&dirs);
+ return GLOB_NOMATCH;
+ }
+ }
+
+ globfree (&dirs);
+ }
+ else
+ {
+ int old_pathc = pglob->gl_pathc;
+
+ status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
+ if (status != 0)
+ return status;
+
+ if (dirlen > 0)
+ {
+ /* Stick the directory on the front of each name. */
+ if (prefix_array (dirname,
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+ }
+
+ if (!(flags & GLOB_NOSORT))
+ {
+ /* Sort the vector. */
+ qsort (&pglob->gl_pathv[oldcount],
+ pglob->gl_pathc + pglob->gl_offs - oldcount,
+ sizeof (char *), collated_compare);
+ }
+
+ return 0;
+}
+#if defined _LIBC && !defined glob
+libc_hidden_def (glob)
+#endif
+
+
+#if !defined _LIBC || !defined GLOB_ONLY_P
+
+/* Free storage allocated in PGLOB by a previous `glob' call. */
+void
+globfree (pglob)
+ register glob_t *pglob;
+{
+ if (pglob->gl_pathv != NULL)
+ {
+ size_t i;
+ for (i = 0; i < pglob->gl_pathc; ++i)
+ if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
+ free (pglob->gl_pathv[pglob->gl_offs + i]);
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+#if defined _LIBC && !defined globfree
+libc_hidden_def (globfree)
+#endif
+
+
+/* Do a collated comparison of A and B. */
+static int
+collated_compare (const void *a, const void *b)
+{
+ const char *const s1 = *(const char *const * const) a;
+ const char *const s2 = *(const char *const * const) b;
+
+ if (s1 == s2)
+ return 0;
+ if (s1 == NULL)
+ return 1;
+ if (s2 == NULL)
+ return -1;
+ return strcoll (s1, s2);
+}
+
+
+/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
+ elements in place. Return nonzero if out of memory, zero if successful.
+ A slash is inserted between DIRNAME and each elt of ARRAY,
+ unless DIRNAME is just "/". Each old element of ARRAY is freed. */
+static int
+prefix_array (const char *dirname, char **array, size_t n)
+{
+ register size_t i;
+ size_t dirlen = strlen (dirname);
+#if defined __MSDOS__ || defined WINDOWS32
+ int sep_char = '/';
+# define DIRSEP_CHAR sep_char
+#else
+# define DIRSEP_CHAR '/'
+#endif
+
+ if (dirlen == 1 && dirname[0] == '/')
+ /* DIRNAME is just "/", so normal prepending would get us "//foo".
+ We want "/foo" instead, so don't prepend any chars from DIRNAME. */
+ dirlen = 0;
+#if defined __MSDOS__ || defined WINDOWS32
+ else if (dirlen > 1)
+ {
+ if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
+ /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
+ --dirlen;
+ else if (dirname[dirlen - 1] == ':')
+ {
+ /* DIRNAME is "d:". Use `:' instead of `/'. */
+ --dirlen;
+ sep_char = ':';
+ }
+ }
+#endif
+
+ for (i = 0; i < n; ++i)
+ {
+ size_t eltlen = strlen (array[i]) + 1;
+ char *new = malloc (dirlen + 1 + eltlen);
+ if (new == NULL)
+ {
+ while (i > 0)
+ free (array[--i]);
+ return 1;
+ }
+
+ {
+ char *endp = mempcpy (new, dirname, dirlen);
+ *endp++ = DIRSEP_CHAR;
+ mempcpy (endp, array[i], eltlen);
+ }
+ free (array[i]);
+ array[i] = new;
+ }
+
+ return 0;
+}
+
+
+/* We must not compile this function twice. */
+#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
+int
+__glob_pattern_p (pattern, quote)
+ const char *pattern;
+ int quote;
+{
+ register const char *p;
+ int open = 0;
+
+ for (p = pattern; *p != '\0'; ++p)
+ switch (*p)
+ {
+ case '?':
+ case '*':
+ return 1;
+
+ case '\\':
+ if (quote && p[1] != '\0')
+ ++p;
+ break;
+
+ case '[':
+ open = 1;
+ break;
+
+ case ']':
+ if (open)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+# ifdef _LIBC
+weak_alias (__glob_pattern_p, glob_pattern_p)
+# endif
+#endif
+
+#endif /* !GLOB_ONLY_P */
+
+
+/* We put this in a separate function mainly to allow the memory
+ allocated with alloca to be recycled. */
+#if !defined _LIBC || !defined GLOB_ONLY_P
+static bool
+is_dir_p (const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob, int flags)
+{
+ size_t fnamelen = strlen (fname);
+ char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
+ struct stat st;
+ struct_stat64 st64;
+
+ mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
+ fname, fnamelen + 1);
+
+ return ((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_stat) (fullname, &st) == 0 && S_ISDIR (st.st_mode)
+ : __stat64 (fullname, &st64) == 0 && S_ISDIR (st64.st_mode));
+}
+#endif
+
+
+/* Like `glob', but PATTERN is a final pathname component,
+ and matches are searched for in DIRECTORY.
+ The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
+ The GLOB_APPEND flag is assumed to be set (always appends). */
+static int
+glob_in_dir (const char *pattern, const char *directory, int flags,
+ int (*errfunc) (const char *, int),
+ glob_t *pglob)
+{
+ size_t dirlen = strlen (directory);
+ void *stream = NULL;
+ struct globlink
+ {
+ struct globlink *next;
+ char *name;
+ };
+ struct globlink *names = NULL;
+ size_t nfound;
+ int meta;
+ int save;
+
+ meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+ if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ {
+ /* We need not do any tests. The PATTERN contains no meta
+ characters and we must not return an error therefore the
+ result will always contain exactly one name. */
+ flags |= GLOB_NOCHECK;
+ nfound = 0;
+ }
+ else if (meta == 0 &&
+ ((flags & GLOB_NOESCAPE) || strchr (pattern, '\\') == NULL))
+ {
+ /* Since we use the normal file functions we can also use stat()
+ to verify the file is there. */
+ struct stat st;
+ struct_stat64 st64;
+ size_t patlen = strlen (pattern);
+ char *fullname = __alloca (dirlen + 1 + patlen + 1);
+
+ mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+ "/", 1),
+ pattern, patlen + 1);
+ if (((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_stat) (fullname, &st)
+ : __stat64 (fullname, &st64)) == 0)
+ /* We found this file to be existing. Now tell the rest
+ of the function to copy this name into the result. */
+ flags |= GLOB_NOCHECK;
+
+ nfound = 0;
+ }
+ else
+ {
+ if (pattern[0] == '\0')
+ {
+ /* This is a special case for matching directories like in
+ "*a/". */
+ names = __alloca (sizeof (struct globlink));
+ names->name = malloc (1);
+ if (names->name == NULL)
+ goto memory_error;
+ names->name[0] = '\0';
+ names->next = NULL;
+ nfound = 1;
+ meta = 0;
+ }
+ else
+ {
+ stream = ((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_opendir) (directory)
+ : opendir (directory));
+ if (stream == NULL)
+ {
+ if (errno != ENOTDIR
+ && ((errfunc != NULL && (*errfunc) (directory, errno))
+ || (flags & GLOB_ERR)))
+ return GLOB_ABORTED;
+ nfound = 0;
+ meta = 0;
+ }
+ else
+ {
+ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
+#if defined _AMIGA || defined VMS
+ | FNM_CASEFOLD
+#endif
+ );
+ nfound = 0;
+ flags |= GLOB_MAGCHAR;
+
+ while (1)
+ {
+ const char *name;
+ size_t len;
+#if defined _LIBC && !defined COMPILE_GLOB64
+ struct dirent64 *d;
+ union
+ {
+ struct dirent64 d64;
+ char room [offsetof (struct dirent64, d_name[0])
+ + NAME_MAX + 1];
+ }
+ d64buf;
+
+ if (flags & GLOB_ALTDIRFUNC)
+ {
+ struct dirent *d32 = (*pglob->gl_readdir) (stream);
+ if (d32 != NULL)
+ {
+ CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
+ d = &d64buf.d64;
+ }
+ else
+ d = NULL;
+ }
+ else
+ d = __readdir64 (stream);
+#else
+ struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
+ ? ((*pglob->gl_readdir) (stream))
+ : __readdir (stream));
+#endif
+ if (d == NULL)
+ break;
+ if (! REAL_DIR_ENTRY (d))
+ continue;
+
+ /* If we shall match only directories use the information
+ provided by the dirent call if possible. */
+ if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
+ continue;
+
+ name = d->d_name;
+
+ if (fnmatch (pattern, name, fnm_flags) == 0)
+ {
+ /* ISDIR will often be incorrectly set to false
+ when not in GLOB_ONLYDIR || GLOB_MARK mode, but we
+ don't care. It won't be used and we save the
+ expensive call to stat. */
+ int need_dir_test =
+ (GLOB_MARK | (DIRENT_MIGHT_BE_SYMLINK (d)
+ ? GLOB_ONLYDIR : 0));
+ bool isdir = (DIRENT_MUST_BE (d, DT_DIR)
+ || ((flags & need_dir_test)
+ && is_dir_p (directory, dirlen, name,
+ pglob, flags)));
+
+ /* In GLOB_ONLYDIR mode, skip non-dirs. */
+ if ((flags & GLOB_ONLYDIR) && !isdir)
+ continue;
+
+ {
+ struct globlink *new =
+ __alloca (sizeof (struct globlink));
+ char *p;
+ len = NAMLEN (d);
+ new->name =
+ malloc (len + 1 + ((flags & GLOB_MARK) && isdir));
+ if (new->name == NULL)
+ goto memory_error;
+ p = mempcpy (new->name, name, len);
+ if ((flags & GLOB_MARK) && isdir)
+ *p++ = '/';
+ *p = '\0';
+ new->next = names;
+ names = new;
+ ++nfound;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (nfound == 0 && (flags & GLOB_NOCHECK))
+ {
+ size_t len = strlen (pattern);
+ nfound = 1;
+ names = __alloca (sizeof (struct globlink));
+ names->next = NULL;
+ names->name = malloc (len + 1);
+ if (names->name == NULL)
+ goto memory_error;
+ *((char *) mempcpy (names->name, pattern, len)) = '\0';
+ }
+
+ if (nfound != 0)
+ {
+ char **new_gl_pathv;
+
+ new_gl_pathv
+ = realloc (pglob->gl_pathv,
+ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ goto memory_error;
+ pglob->gl_pathv = new_gl_pathv;
+
+ for (; names != NULL; names = names->next)
+ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc++] = names->name;
+ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+ pglob->gl_flags = flags;
+ }
+
+ save = errno;
+ if (stream != NULL)
+ {
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ }
+ __set_errno (save);
+
+ return nfound == 0 ? GLOB_NOMATCH : 0;
+
+ memory_error:
+ {
+ int save = errno;
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ __set_errno (save);
+ }
+ while (names != NULL)
+ {
+ if (names->name != NULL)
+ free (names->name);
+ names = names->next;
+ }
+ return GLOB_NOSPACE;
+}
diff --git a/lib/glob_.h b/lib/glob_.h
new file mode 100644
index 0000000..a1bd70c
--- /dev/null
+++ b/lib/glob_.h
@@ -0,0 +1,65 @@
+/* glob_.h -- Find a path matching a pattern.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Derek Price <derek@ximbiot.com> & Paul Eggert <eggert@CS.UCLA.EDU>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef GLOB_H
+#define GLOB_H 1
+
+#ifdef HAVE_SYS_CDEFS_H
+# include <sys/cdefs.h>
+#endif
+
+#include <stddef.h>
+
+#ifndef __BEGIN_DECLS
+# define __BEGIN_DECLS
+# define __END_DECLS
+#endif
+#ifndef __THROW
+# define __THROW
+#endif
+
+#ifndef __size_t
+# define __size_t size_t
+#endif
+#ifndef __const
+# define __const const
+#endif
+#ifndef __restrict
+# define __restrict restrict
+#endif
+#ifndef __USE_GNU
+# define __USE_GNU 1
+#endif
+
+
+#ifndef HAVE_DIRENT_H
+# define dirent direct
+#endif
+
+#define glob rpl_glob
+#define globfree rpl_globfree
+#define glob_pattern_p rpl_glob_pattern_p
+
+#define __GLOB_GNULIB 1
+
+/* Now the standard GNU C Library header should work. */
+#include "glob-libc.h"
+
+#endif /* GLOB_H */
diff --git a/lib/libcvs.dep b/lib/libcvs.dep
new file mode 100644
index 0000000..3330a17
--- /dev/null
+++ b/lib/libcvs.dep
@@ -0,0 +1,548 @@
+# Microsoft Developer Studio Generated Dependency File, included by libcvs.mak
+
+.\__fpending.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\__fpending.h"\
+ ".\timespec.h"\
+
+
+.\asnprintf.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+ ".\vasnprintf.h"\
+
+
+.\basename.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\dirname.h"\
+ ".\timespec.h"\
+
+
+".\canon-host.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\netdb.h"\
+ "..\windows-NT\sys\socket.h"\
+ "..\windows-NT\woe32.h"\
+ ".\canon-host.h"\
+ ".\getaddrinfo.h"\
+ ".\strdup.h"\
+ ".\timespec.h"\
+
+
+.\canonicalize.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\canonicalize.h"\
+ ".\cycle-check.h"\
+ ".\dev-ino.h"\
+ ".\filenamecat.h"\
+ ".\pathmax.h"\
+ ".\stat-macros.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+ ".\xgetcwd.h"\
+ ".\xreadlink.h"\
+
+
+.\closeout.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\__fpending.h"\
+ ".\closeout.h"\
+ ".\error.h"\
+ ".\exitfail.h"\
+ ".\gettext.h"\
+ ".\quotearg.h"\
+ ".\timespec.h"\
+
+
+".\cycle-check.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\woe32.h"\
+ ".\cycle-check.h"\
+ ".\dev-ino.h"\
+ ".\timespec.h"\
+
+
+.\dirname.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\dirname.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+
+
+".\dup-safer.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+ ".\unistd-safer.h"\
+
+
+.\exitfail.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\exit.h"\
+ ".\exitfail.h"\
+ ".\timespec.h"\
+
+
+".\fd-safer.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+ ".\unistd-safer.h"\
+
+
+.\fncase.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\pwd.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\fnmatch.h"\
+ ".\getopt.h"\
+ ".\gettext.h"\
+ ".\system.h"\
+ ".\timespec.h"\
+
+
+.\fnmatch.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\alloca.h"\
+ ".\fnmatch.h"\
+ ".\fnmatch_loop.c"\
+ ".\timespec.h"\
+
+
+.\fseeko.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+.\ftello.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+.\gai_strerror.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\netdb.h"\
+ "..\windows-NT\sys\socket.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getaddrinfo.h"\
+ ".\gettext.h"\
+ ".\timespec.h"\
+
+
+.\getaddrinfo.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\netdb.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\sys\socket.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getaddrinfo.h"\
+ ".\gettext.h"\
+ ".\strdup.h"\
+ ".\timespec.h"\
+
+
+.\getdate.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getdate.h"\
+ ".\setenv.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+
+
+.\getdelim.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getdelim.h"\
+ ".\timespec.h"\
+
+
+.\getline.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getdelim.h"\
+ ".\getline.h"\
+ ".\timespec.h"\
+
+
+.\getlogin_r.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getlogin_r.h"\
+ ".\timespec.h"\
+
+
+.\getndelim2.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getndelim2.h"\
+ ".\timespec.h"\
+
+
+.\getopt.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getopt.h"\
+ ".\getopt_int.h"\
+ ".\gettext.h"\
+ ".\timespec.h"\
+
+
+.\getopt1.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getopt.h"\
+ ".\getopt_int.h"\
+ ".\timespec.h"\
+
+
+.\gettime.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+.\glob.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\pwd.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\alloca.h"\
+ ".\fnmatch.h"\
+ ".\getlogin_r.h"\
+ ".\glob-libc.h"\
+ ".\glob.h"\
+ ".\mempcpy.h"\
+ ".\stat-macros.h"\
+ ".\strdup.h"\
+ ".\timespec.h"\
+
+
+.\lstat.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\stat-macros.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+
+
+.\mbchar.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\mbchar.h"\
+ ".\timespec.h"\
+
+
+.\md5.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\woe32.h"\
+ ".\md5.h"\
+ ".\timespec.h"\
+
+
+.\mempcpy.c : \
+ ".\mempcpy.h"\
+
+
+.\mkstemp.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+.\pagealign_alloc.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\error.h"\
+ ".\exit.h"\
+ ".\getpagesize.h"\
+ ".\gettext.h"\
+ ".\pagealign_alloc.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+
+
+".\printf-args.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\printf-args.h"\
+ ".\timespec.h"\
+
+
+".\printf-parse.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\woe32.h"\
+ ".\printf-args.h"\
+ ".\printf-parse.h"\
+ ".\timespec.h"\
+ ".\xsize.h"\
+
+
+.\quotearg.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\gettext.h"\
+ ".\quotearg.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+
+
+.\readlink.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+.\realloc.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+.\regex.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\alloca.h"\
+ ".\regcomp.c"\
+ ".\regex.h"\
+ ".\regex_internal.c"\
+ ".\regex_internal.h"\
+ ".\regexec.c"\
+ ".\timespec.h"\
+
+
+.\rpmatch.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+".\save-cwd.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\chdir-long.h"\
+ ".\save-cwd.h"\
+ ".\timespec.h"\
+ ".\unistd-safer.h"\
+ ".\xgetcwd.h"\
+
+
+.\setenv.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\alloca.h"\
+ ".\allocsa.h"\
+ ".\timespec.h"\
+
+
+.\sighandle.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\ndir.h"\
+ "..\windows-NT\pwd.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\fnmatch.h"\
+ ".\getopt.h"\
+ ".\gettext.h"\
+ ".\system.h"\
+ ".\timespec.h"\
+
+
+.\strcasecmp.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\mbchar.h"\
+ ".\mbuiter.h"\
+ ".\strcase.h"\
+ ".\strnlen1.h"\
+ ".\timespec.h"\
+
+
+.\strftime.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\time_r.h"\
+ ".\timespec.h"\
+
+
+.\stripslash.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\dirname.h"\
+ ".\timespec.h"\
+
+
+.\strnlen1.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\strnlen1.h"\
+ ".\timespec.h"\
+
+
+.\tempname.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\stat-macros.h"\
+ ".\timespec.h"\
+
+
+.\time_r.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\time_r.h"\
+ ".\timespec.h"\
+
+
+.\unsetenv.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+
+
+.\vasnprintf.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdint.h"\
+ "..\windows-NT\woe32.h"\
+ ".\alloca.h"\
+ ".\printf-args.h"\
+ ".\printf-parse.h"\
+ ".\timespec.h"\
+ ".\vasnprintf.h"\
+ ".\xsize.h"\
+
+
+.\vasprintf.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+ ".\vasnprintf.h"\
+ ".\vasprintf.h"\
+
+
+".\xalloc-die.c" : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\error.h"\
+ ".\exitfail.h"\
+ ".\gettext.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+
+
+.\xgetcwd.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getcwd.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+ ".\xgetcwd.h"\
+
+
+.\xgethostname.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+ ".\xgethostname.h"\
+
+
+.\xmalloc.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+
+
+.\xreadlink.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\unistd.h"\
+ "..\windows-NT\woe32.h"\
+ ".\timespec.h"\
+ ".\xalloc.h"\
+ ".\xreadlink.h"\
+
+
+.\yesno.c : \
+ "..\windows-NT\config.h"\
+ "..\windows-NT\stdbool.h"\
+ "..\windows-NT\woe32.h"\
+ ".\getline.h"\
+ ".\timespec.h"\
+ ".\yesno.h"\
+
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+!ENDIF
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+!ENDIF
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+!ENDIF
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+!ENDIF
+
diff --git a/lib/libcvs.dsp b/lib/libcvs.dsp
new file mode 100644
index 0000000..b8565bc
--- /dev/null
+++ b/lib/libcvs.dsp
@@ -0,0 +1,704 @@
+# Microsoft Developer Studio Project File - Name="libcvs" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libcvs - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libcvs.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libcvs.mak" CFG="libcvs - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libcvs - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libcvs - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "WinRel"
+# PROP BASE Intermediate_Dir "WinRel"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "WinRel"
+# PROP Intermediate_Dir "WinRel"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\windows-NT" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "WinDebug"
+# PROP BASE Intermediate_Dir "WinDebug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "WinDebug"
+# PROP Intermediate_Dir "WinDebug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\windows-NT" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "libcvs - Win32 Release"
+# Name "libcvs - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\__fpending.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\asnprintf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\basename.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\canon-host.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\canonicalize.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\closeout.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\cycle-check.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\dirname.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\dup-safer.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\exitfail.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\fd-safer.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\fncase.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fnmatch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fseeko.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftello.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\gai_strerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getaddrinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getdate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getdelim.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getline.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getlogin_r.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getndelim2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\gettime.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\glob.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\lstat.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mbchar.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mempcpy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mkstemp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\pagealign_alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\printf-args.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\printf-parse.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\quotearg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\readlink.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\realloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regex.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rpmatch.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\save-cwd.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\setenv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sighandle.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strcasecmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strftime.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\stripslash.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strnlen1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tempname.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\time_r.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\unsetenv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\vasnprintf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\vasprintf.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\xalloc-die.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\xgetcwd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\xgethostname.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\xmalloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\xreadlink.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\yesno.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\__fpending.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\alloca.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\alloca_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\alloca_.h
+
+".\alloca.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\alloca_.h .\alloca.h
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\alloca_.h
+
+".\alloca.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\alloca_.h .\alloca.h
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\allocsa.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\canon-host.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\canonicalize.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\chdir-long.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\closeout.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\cycle-check.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\dev-ino.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\dirname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\error.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\exit.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\exitfail.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\filenamecat.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\fnmatch.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\fnmatch_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\fnmatch_.h
+
+".\fnmatch.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\fnmatch_.h .\fnmatch.h
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\fnmatch_.h
+
+".\fnmatch.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\fnmatch_.h .\fnmatch.h
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\getaddrinfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getcwd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getdate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getdelim.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getline.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getlogin_r.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getndelim2.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\getopt_.h
+
+".\getopt.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\getopt_.h .\getopt.h
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\getopt_.h
+
+".\getopt.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\getopt_.h .\getopt.h
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt_int.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\getpagesize.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\gettext.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\glob-libc.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\glob.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\glob_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\glob_.h
+
+".\glob.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\glob_.h .\glob.h
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\glob_.h
+
+".\glob.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\glob_.h .\glob.h
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\mbchar.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mbuiter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mempcpy.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\ndir.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\netdb.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\pagealign_alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\path-concat.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\pathmax.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\printf-args.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\printf-parse.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\pwd.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\quotearg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\regex.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\regex_internal.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\save-cwd.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\setenv.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\sys\socket.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\stat-macros.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\stdbool.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\stdint.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\strcase.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\strdup.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\strnlen1.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\system.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\time_r.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\timespec.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\unistd-safer.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\unistd.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\unlocked-io.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\vasnprintf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vasprintf.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\windows-NT\woe32.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\xalloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\xgetcwd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\xgethostname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\xreadlink.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\xsize.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\xtime.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\yesno.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/libcvs.mak b/lib/libcvs.mak
new file mode 100644
index 0000000..1b0d532
--- /dev/null
+++ b/lib/libcvs.mak
@@ -0,0 +1,795 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on libcvs.dsp
+!IF "$(CFG)" == ""
+CFG=libcvs - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to libcvs - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "libcvs - Win32 Release" && "$(CFG)" != "libcvs - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libcvs.mak" CFG="libcvs - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libcvs - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libcvs - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+OUTDIR=.\WinRel
+INTDIR=.\WinRel
+# Begin Custom Macros
+OutDir=.\WinRel
+# End Custom Macros
+
+ALL : ".\glob.h" ".\getopt.h" ".\fnmatch.h" ".\alloca.h" "$(OUTDIR)\libcvs.lib"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\__fpending.obj"
+ -@erase "$(INTDIR)\asnprintf.obj"
+ -@erase "$(INTDIR)\basename.obj"
+ -@erase "$(INTDIR)\canon-host.obj"
+ -@erase "$(INTDIR)\canonicalize.obj"
+ -@erase "$(INTDIR)\closeout.obj"
+ -@erase "$(INTDIR)\cycle-check.obj"
+ -@erase "$(INTDIR)\dirname.obj"
+ -@erase "$(INTDIR)\dup-safer.obj"
+ -@erase "$(INTDIR)\exitfail.obj"
+ -@erase "$(INTDIR)\fd-safer.obj"
+ -@erase "$(INTDIR)\fncase.obj"
+ -@erase "$(INTDIR)\fnmatch.obj"
+ -@erase "$(INTDIR)\fseeko.obj"
+ -@erase "$(INTDIR)\ftello.obj"
+ -@erase "$(INTDIR)\gai_strerror.obj"
+ -@erase "$(INTDIR)\getaddrinfo.obj"
+ -@erase "$(INTDIR)\getdate.obj"
+ -@erase "$(INTDIR)\getdelim.obj"
+ -@erase "$(INTDIR)\getline.obj"
+ -@erase "$(INTDIR)\getlogin_r.obj"
+ -@erase "$(INTDIR)\getndelim2.obj"
+ -@erase "$(INTDIR)\getopt.obj"
+ -@erase "$(INTDIR)\getopt1.obj"
+ -@erase "$(INTDIR)\gettime.obj"
+ -@erase "$(INTDIR)\glob.obj"
+ -@erase "$(INTDIR)\lstat.obj"
+ -@erase "$(INTDIR)\mbchar.obj"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\mempcpy.obj"
+ -@erase "$(INTDIR)\mkstemp.obj"
+ -@erase "$(INTDIR)\pagealign_alloc.obj"
+ -@erase "$(INTDIR)\printf-args.obj"
+ -@erase "$(INTDIR)\printf-parse.obj"
+ -@erase "$(INTDIR)\quotearg.obj"
+ -@erase "$(INTDIR)\readlink.obj"
+ -@erase "$(INTDIR)\realloc.obj"
+ -@erase "$(INTDIR)\regex.obj"
+ -@erase "$(INTDIR)\rpmatch.obj"
+ -@erase "$(INTDIR)\save-cwd.obj"
+ -@erase "$(INTDIR)\setenv.obj"
+ -@erase "$(INTDIR)\sighandle.obj"
+ -@erase "$(INTDIR)\strcasecmp.obj"
+ -@erase "$(INTDIR)\strftime.obj"
+ -@erase "$(INTDIR)\stripslash.obj"
+ -@erase "$(INTDIR)\strnlen1.obj"
+ -@erase "$(INTDIR)\tempname.obj"
+ -@erase "$(INTDIR)\time_r.obj"
+ -@erase "$(INTDIR)\unsetenv.obj"
+ -@erase "$(INTDIR)\vasnprintf.obj"
+ -@erase "$(INTDIR)\vasprintf.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\xalloc-die.obj"
+ -@erase "$(INTDIR)\xgetcwd.obj"
+ -@erase "$(INTDIR)\xgethostname.obj"
+ -@erase "$(INTDIR)\xmalloc.obj"
+ -@erase "$(INTDIR)\xreadlink.obj"
+ -@erase "$(INTDIR)\yesno.obj"
+ -@erase "$(OUTDIR)\libcvs.lib"
+ -@erase ".\alloca.h"
+ -@erase ".\fnmatch.h"
+ -@erase ".\getopt.h"
+ -@erase ".\glob.h"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "..\windows-NT" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /Fp"$(INTDIR)\libcvs.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libcvs.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)\libcvs.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\__fpending.obj" \
+ "$(INTDIR)\asnprintf.obj" \
+ "$(INTDIR)\basename.obj" \
+ "$(INTDIR)\canon-host.obj" \
+ "$(INTDIR)\canonicalize.obj" \
+ "$(INTDIR)\closeout.obj" \
+ "$(INTDIR)\cycle-check.obj" \
+ "$(INTDIR)\dirname.obj" \
+ "$(INTDIR)\dup-safer.obj" \
+ "$(INTDIR)\exitfail.obj" \
+ "$(INTDIR)\fd-safer.obj" \
+ "$(INTDIR)\fncase.obj" \
+ "$(INTDIR)\fnmatch.obj" \
+ "$(INTDIR)\fseeko.obj" \
+ "$(INTDIR)\ftello.obj" \
+ "$(INTDIR)\gai_strerror.obj" \
+ "$(INTDIR)\getaddrinfo.obj" \
+ "$(INTDIR)\getdate.obj" \
+ "$(INTDIR)\getdelim.obj" \
+ "$(INTDIR)\getline.obj" \
+ "$(INTDIR)\getlogin_r.obj" \
+ "$(INTDIR)\getndelim2.obj" \
+ "$(INTDIR)\getopt.obj" \
+ "$(INTDIR)\getopt1.obj" \
+ "$(INTDIR)\gettime.obj" \
+ "$(INTDIR)\glob.obj" \
+ "$(INTDIR)\lstat.obj" \
+ "$(INTDIR)\mbchar.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\mempcpy.obj" \
+ "$(INTDIR)\mkstemp.obj" \
+ "$(INTDIR)\pagealign_alloc.obj" \
+ "$(INTDIR)\printf-args.obj" \
+ "$(INTDIR)\printf-parse.obj" \
+ "$(INTDIR)\quotearg.obj" \
+ "$(INTDIR)\readlink.obj" \
+ "$(INTDIR)\realloc.obj" \
+ "$(INTDIR)\regex.obj" \
+ "$(INTDIR)\rpmatch.obj" \
+ "$(INTDIR)\save-cwd.obj" \
+ "$(INTDIR)\setenv.obj" \
+ "$(INTDIR)\sighandle.obj" \
+ "$(INTDIR)\strcasecmp.obj" \
+ "$(INTDIR)\strftime.obj" \
+ "$(INTDIR)\stripslash.obj" \
+ "$(INTDIR)\strnlen1.obj" \
+ "$(INTDIR)\tempname.obj" \
+ "$(INTDIR)\time_r.obj" \
+ "$(INTDIR)\unsetenv.obj" \
+ "$(INTDIR)\vasnprintf.obj" \
+ "$(INTDIR)\vasprintf.obj" \
+ "$(INTDIR)\xalloc-die.obj" \
+ "$(INTDIR)\xgetcwd.obj" \
+ "$(INTDIR)\xgethostname.obj" \
+ "$(INTDIR)\xmalloc.obj" \
+ "$(INTDIR)\xreadlink.obj" \
+ "$(INTDIR)\yesno.obj"
+
+"$(OUTDIR)\libcvs.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+OUTDIR=.\WinDebug
+INTDIR=.\WinDebug
+# Begin Custom Macros
+OutDir=.\WinDebug
+# End Custom Macros
+
+ALL : "$(OUTDIR)\libcvs.lib"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\__fpending.obj"
+ -@erase "$(INTDIR)\asnprintf.obj"
+ -@erase "$(INTDIR)\basename.obj"
+ -@erase "$(INTDIR)\canon-host.obj"
+ -@erase "$(INTDIR)\canonicalize.obj"
+ -@erase "$(INTDIR)\closeout.obj"
+ -@erase "$(INTDIR)\cycle-check.obj"
+ -@erase "$(INTDIR)\dirname.obj"
+ -@erase "$(INTDIR)\dup-safer.obj"
+ -@erase "$(INTDIR)\exitfail.obj"
+ -@erase "$(INTDIR)\fd-safer.obj"
+ -@erase "$(INTDIR)\fncase.obj"
+ -@erase "$(INTDIR)\fnmatch.obj"
+ -@erase "$(INTDIR)\fseeko.obj"
+ -@erase "$(INTDIR)\ftello.obj"
+ -@erase "$(INTDIR)\gai_strerror.obj"
+ -@erase "$(INTDIR)\getaddrinfo.obj"
+ -@erase "$(INTDIR)\getdate.obj"
+ -@erase "$(INTDIR)\getdelim.obj"
+ -@erase "$(INTDIR)\getline.obj"
+ -@erase "$(INTDIR)\getlogin_r.obj"
+ -@erase "$(INTDIR)\getndelim2.obj"
+ -@erase "$(INTDIR)\getopt.obj"
+ -@erase "$(INTDIR)\getopt1.obj"
+ -@erase "$(INTDIR)\gettime.obj"
+ -@erase "$(INTDIR)\glob.obj"
+ -@erase "$(INTDIR)\lstat.obj"
+ -@erase "$(INTDIR)\mbchar.obj"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\mempcpy.obj"
+ -@erase "$(INTDIR)\mkstemp.obj"
+ -@erase "$(INTDIR)\pagealign_alloc.obj"
+ -@erase "$(INTDIR)\printf-args.obj"
+ -@erase "$(INTDIR)\printf-parse.obj"
+ -@erase "$(INTDIR)\quotearg.obj"
+ -@erase "$(INTDIR)\readlink.obj"
+ -@erase "$(INTDIR)\realloc.obj"
+ -@erase "$(INTDIR)\regex.obj"
+ -@erase "$(INTDIR)\rpmatch.obj"
+ -@erase "$(INTDIR)\save-cwd.obj"
+ -@erase "$(INTDIR)\setenv.obj"
+ -@erase "$(INTDIR)\sighandle.obj"
+ -@erase "$(INTDIR)\strcasecmp.obj"
+ -@erase "$(INTDIR)\strftime.obj"
+ -@erase "$(INTDIR)\stripslash.obj"
+ -@erase "$(INTDIR)\strnlen1.obj"
+ -@erase "$(INTDIR)\tempname.obj"
+ -@erase "$(INTDIR)\time_r.obj"
+ -@erase "$(INTDIR)\unsetenv.obj"
+ -@erase "$(INTDIR)\vasnprintf.obj"
+ -@erase "$(INTDIR)\vasprintf.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\xalloc-die.obj"
+ -@erase "$(INTDIR)\xgetcwd.obj"
+ -@erase "$(INTDIR)\xgethostname.obj"
+ -@erase "$(INTDIR)\xmalloc.obj"
+ -@erase "$(INTDIR)\xreadlink.obj"
+ -@erase "$(INTDIR)\yesno.obj"
+ -@erase "$(OUTDIR)\libcvs.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od /I "..\windows-NT" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /Fp"$(INTDIR)\libcvs.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libcvs.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)\libcvs.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\__fpending.obj" \
+ "$(INTDIR)\asnprintf.obj" \
+ "$(INTDIR)\basename.obj" \
+ "$(INTDIR)\canon-host.obj" \
+ "$(INTDIR)\canonicalize.obj" \
+ "$(INTDIR)\closeout.obj" \
+ "$(INTDIR)\cycle-check.obj" \
+ "$(INTDIR)\dirname.obj" \
+ "$(INTDIR)\dup-safer.obj" \
+ "$(INTDIR)\exitfail.obj" \
+ "$(INTDIR)\fd-safer.obj" \
+ "$(INTDIR)\fncase.obj" \
+ "$(INTDIR)\fnmatch.obj" \
+ "$(INTDIR)\fseeko.obj" \
+ "$(INTDIR)\ftello.obj" \
+ "$(INTDIR)\gai_strerror.obj" \
+ "$(INTDIR)\getaddrinfo.obj" \
+ "$(INTDIR)\getdate.obj" \
+ "$(INTDIR)\getdelim.obj" \
+ "$(INTDIR)\getline.obj" \
+ "$(INTDIR)\getlogin_r.obj" \
+ "$(INTDIR)\getndelim2.obj" \
+ "$(INTDIR)\getopt.obj" \
+ "$(INTDIR)\getopt1.obj" \
+ "$(INTDIR)\gettime.obj" \
+ "$(INTDIR)\glob.obj" \
+ "$(INTDIR)\lstat.obj" \
+ "$(INTDIR)\mbchar.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\mempcpy.obj" \
+ "$(INTDIR)\mkstemp.obj" \
+ "$(INTDIR)\pagealign_alloc.obj" \
+ "$(INTDIR)\printf-args.obj" \
+ "$(INTDIR)\printf-parse.obj" \
+ "$(INTDIR)\quotearg.obj" \
+ "$(INTDIR)\readlink.obj" \
+ "$(INTDIR)\realloc.obj" \
+ "$(INTDIR)\regex.obj" \
+ "$(INTDIR)\rpmatch.obj" \
+ "$(INTDIR)\save-cwd.obj" \
+ "$(INTDIR)\setenv.obj" \
+ "$(INTDIR)\sighandle.obj" \
+ "$(INTDIR)\strcasecmp.obj" \
+ "$(INTDIR)\strftime.obj" \
+ "$(INTDIR)\stripslash.obj" \
+ "$(INTDIR)\strnlen1.obj" \
+ "$(INTDIR)\tempname.obj" \
+ "$(INTDIR)\time_r.obj" \
+ "$(INTDIR)\unsetenv.obj" \
+ "$(INTDIR)\vasnprintf.obj" \
+ "$(INTDIR)\vasprintf.obj" \
+ "$(INTDIR)\xalloc-die.obj" \
+ "$(INTDIR)\xgetcwd.obj" \
+ "$(INTDIR)\xgethostname.obj" \
+ "$(INTDIR)\xmalloc.obj" \
+ "$(INTDIR)\xreadlink.obj" \
+ "$(INTDIR)\yesno.obj"
+
+"$(OUTDIR)\libcvs.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("libcvs.dep")
+!INCLUDE "libcvs.dep"
+!ELSE
+!MESSAGE Warning: cannot find "libcvs.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "libcvs - Win32 Release" || "$(CFG)" == "libcvs - Win32 Debug"
+SOURCE=.\__fpending.c
+
+"$(INTDIR)\__fpending.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\asnprintf.c
+
+"$(INTDIR)\asnprintf.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\basename.c
+
+"$(INTDIR)\basename.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\canon-host.c"
+
+"$(INTDIR)\canon-host.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\canonicalize.c
+
+"$(INTDIR)\canonicalize.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\closeout.c
+
+"$(INTDIR)\closeout.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\cycle-check.c"
+
+"$(INTDIR)\cycle-check.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\dirname.c
+
+"$(INTDIR)\dirname.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\dup-safer.c"
+
+"$(INTDIR)\dup-safer.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\exitfail.c
+
+"$(INTDIR)\exitfail.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\fd-safer.c"
+
+"$(INTDIR)\fd-safer.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\fncase.c
+
+"$(INTDIR)\fncase.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\fnmatch.c
+
+"$(INTDIR)\fnmatch.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\fseeko.c
+
+"$(INTDIR)\fseeko.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\ftello.c
+
+"$(INTDIR)\ftello.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\gai_strerror.c
+
+"$(INTDIR)\gai_strerror.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getaddrinfo.c
+
+"$(INTDIR)\getaddrinfo.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getdate.c
+
+"$(INTDIR)\getdate.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getdelim.c
+
+"$(INTDIR)\getdelim.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getline.c
+
+"$(INTDIR)\getline.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getlogin_r.c
+
+"$(INTDIR)\getlogin_r.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getndelim2.c
+
+"$(INTDIR)\getndelim2.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getopt.c
+
+"$(INTDIR)\getopt.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getopt1.c
+
+"$(INTDIR)\getopt1.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\gettime.c
+
+"$(INTDIR)\gettime.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\glob.c
+
+"$(INTDIR)\glob.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\lstat.c
+
+"$(INTDIR)\lstat.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\mbchar.c
+
+"$(INTDIR)\mbchar.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\md5.c
+
+"$(INTDIR)\md5.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\mempcpy.c
+
+"$(INTDIR)\mempcpy.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\mkstemp.c
+
+"$(INTDIR)\mkstemp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\pagealign_alloc.c
+
+"$(INTDIR)\pagealign_alloc.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\printf-args.c"
+
+"$(INTDIR)\printf-args.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\printf-parse.c"
+
+"$(INTDIR)\printf-parse.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\quotearg.c
+
+"$(INTDIR)\quotearg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\readlink.c
+
+"$(INTDIR)\readlink.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\realloc.c
+
+"$(INTDIR)\realloc.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\regex.c
+
+"$(INTDIR)\regex.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rpmatch.c
+
+"$(INTDIR)\rpmatch.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\save-cwd.c"
+
+"$(INTDIR)\save-cwd.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\setenv.c
+
+"$(INTDIR)\setenv.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\sighandle.c
+
+"$(INTDIR)\sighandle.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\strcasecmp.c
+
+"$(INTDIR)\strcasecmp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\strftime.c
+
+"$(INTDIR)\strftime.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\stripslash.c
+
+"$(INTDIR)\stripslash.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\strnlen1.c
+
+"$(INTDIR)\strnlen1.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\tempname.c
+
+"$(INTDIR)\tempname.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\time_r.c
+
+"$(INTDIR)\time_r.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\unsetenv.c
+
+"$(INTDIR)\unsetenv.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\vasnprintf.c
+
+"$(INTDIR)\vasnprintf.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\vasprintf.c
+
+"$(INTDIR)\vasprintf.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=".\xalloc-die.c"
+
+"$(INTDIR)\xalloc-die.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\xgetcwd.c
+
+"$(INTDIR)\xgetcwd.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\xgethostname.c
+
+"$(INTDIR)\xgethostname.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\xmalloc.c
+
+"$(INTDIR)\xmalloc.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\xreadlink.c
+
+"$(INTDIR)\xreadlink.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\yesno.c
+
+"$(INTDIR)\yesno.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\alloca_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+InputPath=.\alloca_.h
+
+".\alloca.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\alloca_.h .\alloca.h
+<<
+
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+InputPath=.\alloca_.h
+
+".\alloca.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\alloca_.h .\alloca.h
+<<
+
+
+!ENDIF
+
+SOURCE=.\fnmatch_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+InputPath=.\fnmatch_.h
+
+".\fnmatch.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\fnmatch_.h .\fnmatch.h
+<<
+
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+InputPath=.\fnmatch_.h
+
+".\fnmatch.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\fnmatch_.h .\fnmatch.h
+<<
+
+
+!ENDIF
+
+SOURCE=.\getopt_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+InputPath=.\getopt_.h
+
+".\getopt.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\getopt_.h .\getopt.h
+<<
+
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+InputPath=.\getopt_.h
+
+".\getopt.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\getopt_.h .\getopt.h
+<<
+
+
+!ENDIF
+
+SOURCE=.\glob_.h
+
+!IF "$(CFG)" == "libcvs - Win32 Release"
+
+InputPath=.\glob_.h
+
+".\glob.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\glob_.h .\glob.h
+<<
+
+
+!ELSEIF "$(CFG)" == "libcvs - Win32 Debug"
+
+InputPath=.\glob_.h
+
+".\glob.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ copy .\glob_.h .\glob.h
+<<
+
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/lib/lstat.c b/lib/lstat.c
new file mode 100644
index 0000000..f5a22b0
--- /dev/null
+++ b/lib/lstat.c
@@ -0,0 +1,77 @@
+/* Work around a bug of lstat on some systems
+
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* The specification of these functions is in sys_stat.h. But we cannot
+ include this include file here, because on some systems, a
+ "#define lstat lstat64" is being used, and sys_stat.h deletes this
+ definition. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stat-macros.h"
+#include "xalloc.h"
+
+/* lstat works differently on Linux and Solaris systems. POSIX (see
+ `pathname resolution' in the glossary) requires that programs like `ls'
+ take into consideration the fact that FILE has a trailing slash when
+ FILE is a symbolic link. On Linux systems, the lstat function already
+ has the desired semantics (in treating `lstat("symlink/",sbuf)' just like
+ `lstat("symlink/.",sbuf)', but on Solaris it does not.
+
+ If FILE has a trailing slash and specifies a symbolic link,
+ then append a `.' to FILE and call lstat a second time. */
+
+int
+rpl_lstat (const char *file, struct stat *sbuf)
+{
+ size_t len;
+ char *new_file;
+
+ int lstat_result = lstat (file, sbuf);
+
+ if (lstat_result != 0 || !S_ISLNK (sbuf->st_mode))
+ return lstat_result;
+
+ len = strlen (file);
+ if (len == 0 || file[len - 1] != '/')
+ return lstat_result;
+
+ /* FILE refers to a symbolic link and the name ends with a slash.
+ Append a `.' to FILE and repeat the lstat call. */
+
+ /* Add one for the `.' we'll append, and one more for the trailing NUL. */
+ new_file = xmalloc (len + 1 + 1);
+ memcpy (new_file, file, len);
+ new_file[len] = '.';
+ new_file[len + 1] = 0;
+
+ lstat_result = lstat (new_file, sbuf);
+ free (new_file);
+
+ return lstat_result;
+}
diff --git a/lib/lstat.h b/lib/lstat.h
new file mode 100644
index 0000000..6a83fbf
--- /dev/null
+++ b/lib/lstat.h
@@ -0,0 +1,24 @@
+/* Retrieving information about files.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <sys/stat.h>
+
+#if !LSTAT_FOLLOWS_SLASHED_SYMLINK
+extern int rpl_lstat (const char *name, struct stat *buf);
+# undef lstat
+# define lstat rpl_lstat
+#endif
diff --git a/lib/malloc.c b/lib/malloc.c
new file mode 100644
index 0000000..58fa611
--- /dev/null
+++ b/lib/malloc.c
@@ -0,0 +1,36 @@
+/* malloc() function that is glibc compatible.
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#undef malloc
+
+#include <stdlib.h>
+
+/* Allocate an N-byte block of memory from the heap.
+ If N is zero, allocate a 1-byte block. */
+
+void *
+rpl_malloc (size_t n)
+{
+ if (n == 0)
+ n = 1;
+ return malloc (n);
+}
diff --git a/lib/mbchar.c b/lib/mbchar.c
new file mode 100644
index 0000000..6facc14
--- /dev/null
+++ b/lib/mbchar.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <limits.h>
+
+#include "mbchar.h"
+
+#if IS_BASIC_ASCII
+
+/* Bit table of characters in the ISO C "basic character set". */
+unsigned int is_basic_table [UCHAR_MAX / 32 + 1] =
+{
+ 0x00001a00, /* '\t' '\v' '\f' */
+ 0xffffffef, /* ' '...'#' '%'...'?' */
+ 0xfffffffe, /* 'A'...'Z' '[' '\\' ']' '^' '_' */
+ 0x7ffffffe /* 'a'...'z' '{' '|' '}' '~' */
+ /* The remaining bits are 0. */
+};
+
+#endif /* IS_BASIC_ASCII */
diff --git a/lib/mbchar.h b/lib/mbchar.h
new file mode 100644
index 0000000..4472aa0
--- /dev/null
+++ b/lib/mbchar.h
@@ -0,0 +1,352 @@
+/* Multibyte character data type.
+ Copyright (C) 2001, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Bruno Haible <bruno@clisp.org>. */
+
+/* A multibyte character is a short subsequence of a char* string,
+ representing a single wide character.
+
+ We use multibyte characters instead of wide characters because of
+ the following goals:
+ 1) correct multibyte handling, i.e. operate according to the LC_CTYPE
+ locale,
+ 2) ease of maintenance, i.e. the maintainer needs not know all details
+ of the ISO C 99 standard,
+ 3) don't fail grossly if the input is not in the encoding set by the
+ locale, because often different encodings are in use in the same
+ countries (ISO-8859-1/UTF-8, EUC-JP/Shift_JIS, ...),
+ 4) fast in the case of ASCII characters,
+ 5) portability, i.e. don't make unportable assumptions about wchar_t.
+
+ Multibyte characters are only accessed through the mb* macros.
+
+ mb_ptr (mbc)
+ return a pointer to the beginning of the multibyte sequence.
+
+ mb_len (mbc)
+ returns the number of bytes occupied by the multibyte sequence.
+ Always > 0.
+
+ mb_iseq (mbc, sc)
+ returns true if mbc is the standard ASCII character sc.
+
+ mb_isnul (mbc)
+ returns true if mbc is the nul character.
+
+ mb_cmp (mbc1, mbc2)
+ returns a positive, zero, or negative value depending on whether mbc1
+ sorts after, same or before mbc2.
+
+ mb_casecmp (mbc1, mbc2)
+ returns a positive, zero, or negative value depending on whether mbc1
+ sorts after, same or before mbc2, modulo upper/lowercase conversion.
+
+ mb_equal (mbc1, mbc2)
+ returns true if mbc1 and mbc2 are equal.
+
+ mb_caseequal (mbc1, mbc2)
+ returns true if mbc1 and mbc2 are equal modulo upper/lowercase conversion.
+
+ mb_isalnum (mbc)
+ returns true if mbc is alphanumeric.
+
+ mb_isalpha (mbc)
+ returns true if mbc is alphabetic.
+
+ mb_isascii(mbc)
+ returns true if mbc is plain ASCII.
+
+ mb_isblank (mbc)
+ returns true if mbc is a blank.
+
+ mb_iscntrl (mbc)
+ returns true if mbc is a control character.
+
+ mb_isdigit (mbc)
+ returns true if mbc is a decimal digit.
+
+ mb_isgraph (mbc)
+ returns true if mbc is a graphic character.
+
+ mb_islower (mbc)
+ returns true if mbc is lowercase.
+
+ mb_isprint (mbc)
+ returns true if mbc is a printable character.
+
+ mb_ispunct (mbc)
+ returns true if mbc is a punctuation character.
+
+ mb_isspace (mbc)
+ returns true if mbc is a space character.
+
+ mb_isupper (mbc)
+ returns true if mbc is uppercase.
+
+ mb_isxdigit (mbc)
+ returns true if mbc is a hexadecimal digit.
+
+ mb_width (mbc)
+ returns the number of columns on the output device occupied by mbc.
+ Always >= 0.
+
+ mb_putc (mbc, stream)
+ outputs mbc on stream, a byte oriented FILE stream opened for output.
+
+ mb_setascii (&mbc, sc)
+ assigns the standard ASCII character sc to mbc.
+
+ mb_copy (&destmbc, &srcmbc)
+ copies srcmbc to destmbc.
+
+ Here are the function prototypes of the macros.
+
+ extern const char * mb_ptr (const mbchar_t mbc);
+ extern size_t mb_len (const mbchar_t mbc);
+ extern bool mb_iseq (const mbchar_t mbc, char sc);
+ extern bool mb_isnul (const mbchar_t mbc);
+ extern int mb_cmp (const mbchar_t mbc1, const mbchar_t mbc2);
+ extern int mb_casecmp (const mbchar_t mbc1, const mbchar_t mbc2);
+ extern bool mb_equal (const mbchar_t mbc1, const mbchar_t mbc2);
+ extern bool mb_caseequal (const mbchar_t mbc1, const mbchar_t mbc2);
+ extern bool mb_isalnum (const mbchar_t mbc);
+ extern bool mb_isalpha (const mbchar_t mbc);
+ extern bool mb_isascii (const mbchar_t mbc);
+ extern bool mb_isblank (const mbchar_t mbc);
+ extern bool mb_iscntrl (const mbchar_t mbc);
+ extern bool mb_isdigit (const mbchar_t mbc);
+ extern bool mb_isgraph (const mbchar_t mbc);
+ extern bool mb_islower (const mbchar_t mbc);
+ extern bool mb_isprint (const mbchar_t mbc);
+ extern bool mb_ispunct (const mbchar_t mbc);
+ extern bool mb_isspace (const mbchar_t mbc);
+ extern bool mb_isupper (const mbchar_t mbc);
+ extern bool mb_isxdigit (const mbchar_t mbc);
+ extern int mb_width (const mbchar_t mbc);
+ extern void mb_putc (const mbchar_t mbc, FILE *stream);
+ extern void mb_setascii (mbchar_t *new, char sc);
+ extern void mb_copy (mbchar_t *new, const mbchar_t *old);
+ */
+
+#ifndef _MBCHAR_H
+#define _MBCHAR_H 1
+
+#include <stdbool.h>
+#include <string.h>
+
+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
+ <wchar.h>.
+ BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
+ <wchar.h>. */
+#include <stdio.h>
+#include <time.h>
+#include <wchar.h>
+
+#include <wctype.h>
+
+#define MBCHAR_BUF_SIZE 24
+
+struct mbchar
+{
+ const char *ptr; /* pointer to current character */
+ size_t bytes; /* number of bytes of current character, > 0 */
+ bool wc_valid; /* true if wc is a valid wide character */
+ wchar_t wc; /* if wc_valid: the current character */
+ char buf[MBCHAR_BUF_SIZE]; /* room for the bytes, used for file input only */
+};
+
+/* EOF (not a real character) is represented with bytes = 0 and
+ wc_valid = false. */
+
+typedef struct mbchar mbchar_t;
+
+/* Access the current character. */
+#define mb_ptr(mbc) ((mbc).ptr)
+#define mb_len(mbc) ((mbc).bytes)
+
+/* Comparison of characters. */
+#define mb_iseq(mbc, sc) ((mbc).wc_valid && (mbc).wc == (sc))
+#define mb_isnul(mbc) ((mbc).wc_valid && (mbc).wc == 0)
+#define mb_cmp(mbc1, mbc2) \
+ ((mbc1).wc_valid \
+ ? ((mbc2).wc_valid \
+ ? (int) (mbc1).wc - (int) (mbc2).wc \
+ : -1) \
+ : ((mbc2).wc_valid \
+ ? 1 \
+ : (mbc1).bytes == (mbc2).bytes \
+ ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
+ : (mbc1).bytes < (mbc2).bytes \
+ ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
+ : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
+#define mb_casecmp(mbc1, mbc2) \
+ ((mbc1).wc_valid \
+ ? ((mbc2).wc_valid \
+ ? (int) towlower ((mbc1).wc) - (int) towlower ((mbc2).wc) \
+ : -1) \
+ : ((mbc2).wc_valid \
+ ? 1 \
+ : (mbc1).bytes == (mbc2).bytes \
+ ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
+ : (mbc1).bytes < (mbc2).bytes \
+ ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
+ : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
+#define mb_equal(mbc1, mbc2) \
+ ((mbc1).wc_valid && (mbc2).wc_valid \
+ ? (mbc1).wc == (mbc2).wc \
+ : (mbc1).bytes == (mbc2).bytes \
+ && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
+#define mb_caseequal(mbc1, mbc2) \
+ ((mbc1).wc_valid && (mbc2).wc_valid \
+ ? towlower ((mbc1).wc) == towlower ((mbc2).wc) \
+ : (mbc1).bytes == (mbc2).bytes \
+ && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
+
+/* <ctype.h>, <wctype.h> classification. */
+#define mb_isascii(mbc) \
+ ((mbc).wc_valid && (mbc).wc >= 0 && (mbc).wc <= 127)
+#define mb_isalnum(mbc) ((mbc).wc_valid && iswalnum ((mbc).wc))
+#define mb_isalpha(mbc) ((mbc).wc_valid && iswalpha ((mbc).wc))
+#define mb_isblank(mbc) ((mbc).wc_valid && iswblank ((mbc).wc))
+#define mb_iscntrl(mbc) ((mbc).wc_valid && iswcntrl ((mbc).wc))
+#define mb_isdigit(mbc) ((mbc).wc_valid && iswdigit ((mbc).wc))
+#define mb_isgraph(mbc) ((mbc).wc_valid && iswgraph ((mbc).wc))
+#define mb_islower(mbc) ((mbc).wc_valid && iswlower ((mbc).wc))
+#define mb_isprint(mbc) ((mbc).wc_valid && iswprint ((mbc).wc))
+#define mb_ispunct(mbc) ((mbc).wc_valid && iswpunct ((mbc).wc))
+#define mb_isspace(mbc) ((mbc).wc_valid && iswspace ((mbc).wc))
+#define mb_isupper(mbc) ((mbc).wc_valid && iswupper ((mbc).wc))
+#define mb_isxdigit(mbc) ((mbc).wc_valid && iswxdigit ((mbc).wc))
+
+/* Extra <wchar.h> function. */
+
+/* Unprintable characters appear as a small box of width 1. */
+#define MB_UNPRINTABLE_WIDTH 1
+
+static inline int
+mb_width_aux (wint_t wc)
+{
+ int w = wcwidth (wc);
+ /* For unprintable characters, arbitrarily return 0 for control characters
+ and MB_UNPRINTABLE_WIDTH otherwise. */
+ return (w >= 0 ? w : iswcntrl (wc) ? 0 : MB_UNPRINTABLE_WIDTH);
+}
+
+#define mb_width(mbc) \
+ ((mbc).wc_valid ? mb_width_aux ((mbc).wc) : MB_UNPRINTABLE_WIDTH)
+
+/* Output. */
+#define mb_putc(mbc, stream) fwrite ((mbc).ptr, 1, (mbc).bytes, (stream))
+
+/* Assignment. */
+#define mb_setascii(mbc, sc) \
+ ((mbc)->ptr = (mbc)->buf, (mbc)->bytes = 1, (mbc)->wc_valid = 1, \
+ (mbc)->wc = (mbc)->buf[0] = (sc))
+
+/* Copying a character. */
+static inline void
+mb_copy (mbchar_t *new, const mbchar_t *old)
+{
+ if (old->ptr == &old->buf[0])
+ {
+ memcpy (&new->buf[0], &old->buf[0], old->bytes);
+ new->ptr = &new->buf[0];
+ }
+ else
+ new->ptr = old->ptr;
+ new->bytes = old->bytes;
+ if ((new->wc_valid = old->wc_valid))
+ new->wc = old->wc;
+}
+
+
+/* is_basic(c) tests whether the single-byte character c is in the
+ ISO C "basic character set".
+ This is a convenience function, and is in this file only to share code
+ between mbiter_multi.h and mbfile_multi.h. */
+#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
+/* The character set is ISO-646, not EBCDIC. */
+# define IS_BASIC_ASCII 1
+
+extern unsigned int is_basic_table[];
+
+static inline bool
+is_basic (char c)
+{
+ return (is_basic_table [(unsigned char) c >> 5] >> ((unsigned char) c & 31))
+ & 1;
+}
+
+#else
+
+static inline bool
+is_basic (char c)
+{
+ switch (c)
+ {
+ case '\t': case '\v': case '\f':
+ case ' ': case '!': case '"': case '#': case '%':
+ case '&': case '\'': case '(': case ')': case '*':
+ case '+': case ',': case '-': case '.': case '/':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case ':': case ';': case '<': case '=': case '>':
+ case '?':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z':
+ case '[': case '\\': case ']': case '^': case '_':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y':
+ case 'z': case '{': case '|': case '}': case '~':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+#endif
+
+#endif /* _MBCHAR_H */
diff --git a/lib/mbuiter.h b/lib/mbuiter.h
new file mode 100644
index 0000000..9da3a6c
--- /dev/null
+++ b/lib/mbuiter.h
@@ -0,0 +1,203 @@
+/* Iterating through multibyte strings: macros for multi-byte encodings.
+ Copyright (C) 2001, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Bruno Haible <bruno@clisp.org>. */
+
+/* The macros in this file implement forward iteration through a
+ multi-byte string, without knowing its length a-priori.
+
+ With these macros, an iteration loop that looks like
+
+ char *iter;
+ for (iter = buf; *iter != '\0'; iter++)
+ {
+ do_something (*iter);
+ }
+
+ becomes
+
+ mbui_iterator_t iter;
+ for (mbui_init (iter, buf); mbui_avail (iter); mbui_advance (iter))
+ {
+ do_something (mbui_cur_ptr (iter), mb_len (mbui_cur (iter)));
+ }
+
+ The benefit of these macros over plain use of mbrtowc is:
+ - Handling of invalid multibyte sequences is possible without
+ making the code more complicated, while still preserving the
+ invalid multibyte sequences.
+
+ Compared to mbiter.h, the macros here don't need to know the string's
+ length a-priori. The downside is that at each step, the look-ahead
+ that guards against overrunning the terminating '\0' is more expensive.
+ The mbui_* macros are therefore suitable when there is a high probability
+ that only the first few multibyte characters need to be inspected.
+ Whereas the mbi_* macros are better if usually the iteration runs
+ through the entire string.
+
+ mbui_iterator_t
+ is a type usable for variable declarations.
+
+ mbui_init (iter, startptr)
+ initializes the iterator, starting at startptr.
+
+ mbui_avail (iter)
+ returns true if there are more multibyte chracters available before
+ the end of string is reached. In this case, mbui_cur (iter) is
+ initialized to the next multibyte chracter.
+
+ mbui_advance (iter)
+ advances the iterator by one multibyte character.
+
+ mbui_cur (iter)
+ returns the current multibyte character, of type mbchar_t. All the
+ macros defined in mbchar.h can be used on it.
+
+ mbui_cur_ptr (iter)
+ return a pointer to the beginning of the current multibyte character.
+
+ mbui_reloc (iter, ptrdiff)
+ relocates iterator when the string is moved by ptrdiff bytes.
+
+ Here are the function prototypes of the macros.
+
+ extern void mbui_init (mbui_iterator_t iter, const char *startptr);
+ extern bool mbui_avail (mbui_iterator_t iter);
+ extern void mbui_advance (mbui_iterator_t iter);
+ extern mbchar_t mbui_cur (mbui_iterator_t iter);
+ extern const char * mbui_cur_ptr (mbui_iterator_t iter);
+ extern void mbui_reloc (mbui_iterator_t iter, ptrdiff_t ptrdiff);
+ */
+
+#ifndef _MBUITER_H
+#define _MBUITER_H 1
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
+ <wchar.h>.
+ BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
+ <wchar.h>. */
+#include <stdio.h>
+#include <time.h>
+#include <wchar.h>
+
+#include "mbchar.h"
+#include "strnlen1.h"
+
+struct mbuiter_multi
+{
+ bool in_shift; /* true if next byte may not be interpreted as ASCII */
+ mbstate_t state; /* if in_shift: current shift state */
+ bool next_done; /* true if mbui_avail has already filled the following */
+ struct mbchar cur; /* the current character:
+ const char *cur.ptr pointer to current character
+ The following are only valid after mbui_avail.
+ size_t cur.bytes number of bytes of current character
+ bool cur.wc_valid true if wc is a valid wide character
+ wchar_t cur.wc if wc_valid: the current character
+ */
+};
+
+static inline void
+mbuiter_multi_next (struct mbuiter_multi *iter)
+{
+ if (iter->next_done)
+ return;
+ if (iter->in_shift)
+ goto with_shift;
+ /* Handle most ASCII characters quickly, without calling mbrtowc(). */
+ if (is_basic (*iter->cur.ptr))
+ {
+ /* These characters are part of the basic character set. ISO C 99
+ guarantees that their wide character code is identical to their
+ char code. */
+ iter->cur.bytes = 1;
+ iter->cur.wc = *iter->cur.ptr;
+ iter->cur.wc_valid = true;
+ }
+ else
+ {
+ assert (mbsinit (&iter->state));
+ iter->in_shift = true;
+ with_shift:
+ iter->cur.bytes = mbrtowc (&iter->cur.wc, iter->cur.ptr,
+ strnlen1 (iter->cur.ptr, MB_CUR_MAX),
+ &iter->state);
+ if (iter->cur.bytes == (size_t) -1)
+ {
+ /* An invalid multibyte sequence was encountered. */
+ iter->cur.bytes = 1;
+ iter->cur.wc_valid = false;
+ /* Whether to set iter->in_shift = false and reset iter->state
+ or not is not very important; the string is bogus anyway. */
+ }
+ else if (iter->cur.bytes == (size_t) -2)
+ {
+ /* An incomplete multibyte character at the end. */
+ iter->cur.bytes = strlen (iter->cur.ptr);
+ iter->cur.wc_valid = false;
+ /* Whether to set iter->in_shift = false and reset iter->state
+ or not is not important; the string end is reached anyway. */
+ }
+ else
+ {
+ if (iter->cur.bytes == 0)
+ {
+ /* A null wide character was encountered. */
+ iter->cur.bytes = 1;
+ assert (*iter->cur.ptr == '\0');
+ assert (iter->cur.wc == 0);
+ }
+ iter->cur.wc_valid = true;
+
+ /* When in the initial state, we can go back treating ASCII
+ characters more quickly. */
+ if (mbsinit (&iter->state))
+ iter->in_shift = false;
+ }
+ }
+ iter->next_done = true;
+}
+
+static inline void
+mbuiter_multi_reloc (struct mbuiter_multi *iter, ptrdiff_t ptrdiff)
+{
+ iter->cur.ptr += ptrdiff;
+}
+
+/* Iteration macros. */
+typedef struct mbuiter_multi mbui_iterator_t;
+#define mbui_init(iter, startptr) \
+ ((iter).cur.ptr = (startptr), \
+ (iter).in_shift = false, memset (&(iter).state, '\0', sizeof (mbstate_t)), \
+ (iter).next_done = false)
+#define mbui_avail(iter) \
+ (mbuiter_multi_next (&(iter)), !mb_isnul ((iter).cur))
+#define mbui_advance(iter) \
+ ((iter).cur.ptr += (iter).cur.bytes, (iter).next_done = false)
+
+/* Access to the current character. */
+#define mbui_cur(iter) (iter).cur
+#define mbui_cur_ptr(iter) (iter).cur.ptr
+
+/* Relocation. */
+#define mbui_reloc(iter, ptrdiff) mbuiter_multi_reloc (&iter, ptrdiff)
+
+#endif /* _MBUITER_H */
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644
index 0000000..87db8f9
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,452 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ according to the definition of MD5 in RFC 1321 from April 1992.
+ Copyright (C) 1995, 1996, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "md5.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define WORDS_BIGENDIAN 1
+# endif
+/* We need to keep the namespace clean so define the MD5 function
+ protected using leading __ . */
+# define md5_init_ctx __md5_init_ctx
+# define md5_process_block __md5_process_block
+# define md5_process_bytes __md5_process_bytes
+# define md5_finish_ctx __md5_finish_ctx
+# define md5_read_ctx __md5_read_ctx
+# define md5_stream __md5_stream
+# define md5_buffer __md5_buffer
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+#define BLOCKSIZE 4096
+#if BLOCKSIZE % 64 != 0
+# error "invalid BLOCKSIZE"
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void
+md5_init_ctx (struct md5_ctx *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_read_ctx (const struct md5_ctx *ctx, void *resbuf)
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int
+md5_stream (FILE *stream, void *resblock)
+{
+ struct md5_ctx ctx;
+ char buffer[BLOCKSIZE + 72];
+ size_t sum;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Iterate over full file contents. */
+ while (1)
+ {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ while (1)
+ {
+ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+ sum += n;
+
+ if (sum == BLOCKSIZE)
+ break;
+
+ if (n == 0)
+ {
+ /* Check for the error flag IFF N == 0, so that we don't
+ exit the loop after a partial read due to e.g., EAGAIN
+ or EWOULDBLOCK. */
+ if (ferror (stream))
+ return 1;
+ goto process_partial_block;
+ }
+
+ /* We've read at least one byte, so ignore errors. But always
+ check for EOF, since feof may be true even though N > 0.
+ Otherwise, we could end up calling fread after EOF. */
+ if (feof (stream))
+ goto process_partial_block;
+ }
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ md5_process_block (buffer, BLOCKSIZE, &ctx);
+ }
+
+ process_partial_block:;
+
+ /* Process any remaining bytes. */
+ if (sum > 0)
+ md5_process_bytes (buffer, sum, &ctx);
+
+ /* Construct result in desired memory. */
+ md5_finish_ctx (&ctx, resblock);
+ return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+md5_buffer (const char *buffer, size_t len, void *resblock)
+{
+ struct md5_ctx ctx;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 64)
+ {
+ md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ ctx->buflen);
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len >= 64)
+ {
+#if !_STRING_ARCH_unaligned
+# define alignof(type) offsetof (struct { char c; type x; }, x)
+# define UNALIGNED_P(p) (((size_t) p) % alignof (md5_uint32) != 0)
+ if (UNALIGNED_P (buffer))
+ while (len > 64)
+ {
+ md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *) buffer + 64;
+ len -= 64;
+ }
+ else
+#endif
+ {
+ md5_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ size_t left_over = ctx->buflen;
+
+ memcpy (&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 64)
+ {
+ md5_process_block (ctx->buffer, 64, ctx);
+ left_over -= 64;
+ memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+ }
+ ctx->buflen = left_over;
+ }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+
+void
+md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp)
+ {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+
+ Here is an equivalent invocation using Perl:
+
+ perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, 0xd76aa478);
+ OP (D, A, B, C, 12, 0xe8c7b756);
+ OP (C, D, A, B, 17, 0x242070db);
+ OP (B, C, D, A, 22, 0xc1bdceee);
+ OP (A, B, C, D, 7, 0xf57c0faf);
+ OP (D, A, B, C, 12, 0x4787c62a);
+ OP (C, D, A, B, 17, 0xa8304613);
+ OP (B, C, D, A, 22, 0xfd469501);
+ OP (A, B, C, D, 7, 0x698098d8);
+ OP (D, A, B, C, 12, 0x8b44f7af);
+ OP (C, D, A, B, 17, 0xffff5bb1);
+ OP (B, C, D, A, 22, 0x895cd7be);
+ OP (A, B, C, D, 7, 0x6b901122);
+ OP (D, A, B, C, 12, 0xfd987193);
+ OP (C, D, A, B, 17, 0xa679438e);
+ OP (B, C, D, A, 22, 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP (FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP (FG, D, A, B, C, 10, 9, 0x02441453);
+ OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP (FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP (FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP (FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP (FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP (FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
diff --git a/lib/md5.h b/lib/md5.h
new file mode 100644
index 0000000..1c29e67
--- /dev/null
+++ b/lib/md5.h
@@ -0,0 +1,136 @@
+/* Declaration of functions and data types used for MD5 sum computing
+ library functions.
+ Copyright (C) 1995-1997,1999-2005 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if HAVE_STDINT_H || _LIBC
+# include <stdint.h>
+#endif
+
+#ifndef __GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+# define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+
+#ifndef __THROW
+# if defined __cplusplus && __GNUC_PREREQ (2,8)
+# define __THROW throw ()
+# else
+# define __THROW
+# endif
+#endif
+
+#ifndef __attribute__
+# if ! __GNUC_PREREQ (2,8) || __STRICT_ANSI__
+# define __attribute__(x)
+# endif
+#endif
+
+#ifndef _LIBC
+# define __md5_buffer md5_buffer
+# define __md5_finish_ctx md5_finish_ctx
+# define __md5_init_ctx md5_init_ctx
+# define __md5_process_block md5_process_block
+# define __md5_process_bytes md5_process_bytes
+# define __md5_read_ctx md5_read_ctx
+# define __md5_stream md5_stream
+#endif
+
+typedef uint32_t md5_uint32;
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW;
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void __md5_process_block (const void *buffer, size_t len,
+ struct md5_ctx *ctx) __THROW;
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void __md5_process_bytes (const void *buffer, size_t len,
+ struct md5_ctx *ctx) __THROW;
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF be correctly
+ aligned for a 32 bits value. */
+extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW;
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW;
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+extern int __md5_stream (FILE *stream, void *resblock) __THROW;
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *__md5_buffer (const char *buffer, size_t len,
+ void *resblock) __THROW;
+
+#endif /* md5.h */
diff --git a/lib/memchr.c b/lib/memchr.c
new file mode 100644
index 0000000..3c5ecfd
--- /dev/null
+++ b/lib/memchr.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
+ with help from Dan Sahlin (dan@sics.se) and
+ commentary by Jim Blandy (jimb@ai.mit.edu);
+ adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
+ and implemented by Roland McGrath (roland@ai.mit.edu).
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <stddef.h>
+
+#if defined _LIBC
+# include <memcopy.h>
+#else
+# define reg_char char
+#endif
+
+#include <limits.h>
+
+#if HAVE_BP_SYM_H || defined _LIBC
+# include <bp-sym.h>
+#else
+# define BP_SYM(sym) sym
+#endif
+
+#undef memchr
+#undef __memchr
+
+/* Search no more than N bytes of S for C. */
+void *
+__memchr (void const *s, int c_in, size_t n)
+{
+ const unsigned char *char_ptr;
+ const unsigned long int *longword_ptr;
+ unsigned long int longword, magic_bits, charmask;
+ unsigned reg_char c;
+ int i;
+
+ c = (unsigned char) c_in;
+
+ /* Handle the first few characters by reading one character at a time.
+ Do this until CHAR_PTR is aligned on a longword boundary. */
+ for (char_ptr = (const unsigned char *) s;
+ n > 0 && (size_t) char_ptr % sizeof longword != 0;
+ --n, ++char_ptr)
+ if (*char_ptr == c)
+ return (void *) char_ptr;
+
+ /* All these elucidatory comments refer to 4-byte longwords,
+ but the theory applies equally well to any size longwords. */
+
+ longword_ptr = (const unsigned long int *) char_ptr;
+
+ /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
+ the "holes." Note that there is a hole just to the left of
+ each byte, with an extra at the end:
+
+ bits: 01111110 11111110 11111110 11111111
+ bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
+
+ The 1-bits make sure that carries propagate to the next 0-bit.
+ The 0-bits provide holes for carries to fall into. */
+
+ /* Set MAGIC_BITS to be this pattern of 1 and 0 bits.
+ Set CHARMASK to be a longword, each of whose bytes is C. */
+
+ magic_bits = 0xfefefefe;
+ charmask = c | (c << 8);
+ charmask |= charmask << 16;
+#if 0xffffffffU < ULONG_MAX
+ magic_bits |= magic_bits << 32;
+ charmask |= charmask << 32;
+ if (8 < sizeof longword)
+ for (i = 64; i < sizeof longword * 8; i *= 2)
+ {
+ magic_bits |= magic_bits << i;
+ charmask |= charmask << i;
+ }
+#endif
+ magic_bits = (ULONG_MAX >> 1) & (magic_bits | 1);
+
+ /* Instead of the traditional loop which tests each character,
+ we will test a longword at a time. The tricky part is testing
+ if *any of the four* bytes in the longword in question are zero. */
+ while (n >= sizeof longword)
+ {
+ /* We tentatively exit the loop if adding MAGIC_BITS to
+ LONGWORD fails to change any of the hole bits of LONGWORD.
+
+ 1) Is this safe? Will it catch all the zero bytes?
+ Suppose there is a byte with all zeros. Any carry bits
+ propagating from its left will fall into the hole at its
+ least significant bit and stop. Since there will be no
+ carry from its most significant bit, the LSB of the
+ byte to the left will be unchanged, and the zero will be
+ detected.
+
+ 2) Is this worthwhile? Will it ignore everything except
+ zero bytes? Suppose every byte of LONGWORD has a bit set
+ somewhere. There will be a carry into bit 8. If bit 8
+ is set, this will carry into bit 16. If bit 8 is clear,
+ one of bits 9-15 must be set, so there will be a carry
+ into bit 16. Similarly, there will be a carry into bit
+ 24. If one of bits 24-30 is set, there will be a carry
+ into bit 31, so all of the hole bits will be changed.
+
+ The one misfire occurs when bits 24-30 are clear and bit
+ 31 is set; in this case, the hole at bit 31 is not
+ changed. If we had access to the processor carry flag,
+ we could close this loophole by putting the fourth hole
+ at bit 32!
+
+ So it ignores everything except 128's, when they're aligned
+ properly.
+
+ 3) But wait! Aren't we looking for C, not zero?
+ Good point. So what we do is XOR LONGWORD with a longword,
+ each of whose bytes is C. This turns each byte that is C
+ into a zero. */
+
+ longword = *longword_ptr++ ^ charmask;
+
+ /* Add MAGIC_BITS to LONGWORD. */
+ if ((((longword + magic_bits)
+
+ /* Set those bits that were unchanged by the addition. */
+ ^ ~longword)
+
+ /* Look at only the hole bits. If any of the hole bits
+ are unchanged, most likely one of the bytes was a
+ zero. */
+ & ~magic_bits) != 0)
+ {
+ /* Which of the bytes was C? If none of them were, it was
+ a misfire; continue the search. */
+
+ const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);
+
+ if (cp[0] == c)
+ return (void *) cp;
+ if (cp[1] == c)
+ return (void *) &cp[1];
+ if (cp[2] == c)
+ return (void *) &cp[2];
+ if (cp[3] == c)
+ return (void *) &cp[3];
+ if (4 < sizeof longword && cp[4] == c)
+ return (void *) &cp[4];
+ if (5 < sizeof longword && cp[5] == c)
+ return (void *) &cp[5];
+ if (6 < sizeof longword && cp[6] == c)
+ return (void *) &cp[6];
+ if (7 < sizeof longword && cp[7] == c)
+ return (void *) &cp[7];
+ if (8 < sizeof longword)
+ for (i = 8; i < sizeof longword; i++)
+ if (cp[i] == c)
+ return (void *) &cp[i];
+ }
+
+ n -= sizeof longword;
+ }
+
+ char_ptr = (const unsigned char *) longword_ptr;
+
+ while (n-- > 0)
+ {
+ if (*char_ptr == c)
+ return (void *) char_ptr;
+ else
+ ++char_ptr;
+ }
+
+ return 0;
+}
+#ifdef weak_alias
+weak_alias (__memchr, BP_SYM (memchr))
+#endif
diff --git a/lib/memmove.c b/lib/memmove.c
new file mode 100644
index 0000000..753c899
--- /dev/null
+++ b/lib/memmove.c
@@ -0,0 +1,28 @@
+/* memmove.c -- copy memory.
+ Copy LENGTH bytes from SOURCE to DEST. Does not null-terminate.
+ In the public domain.
+ By David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+
+void *
+memmove (void *dest0, void const *source0, size_t length)
+{
+ char *dest = dest0;
+ char const *source = source0;
+ if (source < dest)
+ /* Moving from low mem to hi mem; start at end. */
+ for (source += length, dest += length; length; --length)
+ *--dest = *--source;
+ else if (source != dest)
+ {
+ /* Moving from hi mem to low mem; start at beginning. */
+ for (; length; --length)
+ *dest++ = *source++;
+ }
+ return dest0;
+}
diff --git a/lib/mempcpy.c b/lib/mempcpy.c
new file mode 100644
index 0000000..3502da2
--- /dev/null
+++ b/lib/mempcpy.c
@@ -0,0 +1,29 @@
+/* Copy memory area and return pointer after last written byte.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Specification. */
+#include "mempcpy.h"
+
+#include <string.h>
+
+/* Copy N bytes of SRC to DEST, return pointer to bytes after the
+ last written byte. */
+void *
+mempcpy (void *dest, const void *src, size_t n)
+{
+ return (char *) memcpy (dest, src, n) + n;
+}
diff --git a/lib/mempcpy.h b/lib/mempcpy.h
new file mode 100644
index 0000000..fa20321
--- /dev/null
+++ b/lib/mempcpy.h
@@ -0,0 +1,36 @@
+/* Copy memory area and return pointer after last written byte.
+ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef mempcpy
+
+# if HAVE_MEMPCPY
+
+/* Get mempcpy() declaration. */
+# include <string.h>
+
+# else
+
+/* Get size_t */
+# include <stddef.h>
+
+/* Copy N bytes of SRC to DEST, return pointer to bytes after the
+ last written byte. */
+extern void *mempcpy (void *dest, const void *src, size_t n);
+
+# endif
+
+#endif
diff --git a/lib/memrchr.c b/lib/memrchr.c
new file mode 100644
index 0000000..0b6659f
--- /dev/null
+++ b/lib/memrchr.c
@@ -0,0 +1,194 @@
+/* memrchr -- find the last occurrence of a byte in a memory block
+
+ Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+
+ Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
+ with help from Dan Sahlin (dan@sics.se) and
+ commentary by Jim Blandy (jimb@ai.mit.edu);
+ adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
+ and implemented by Roland McGrath (roland@ai.mit.edu).
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _LIBC
+# include <string.h>
+# include <memcopy.h>
+#else
+# include "memrchr.h"
+# define reg_char char
+#endif
+
+#include <limits.h>
+
+#undef __memrchr
+#undef memrchr
+
+#ifndef weak_alias
+# define __memrchr memrchr
+#endif
+
+/* Search no more than N bytes of S for C. */
+void *
+__memrchr (void const *s, int c_in, size_t n)
+{
+ const unsigned char *char_ptr;
+ const unsigned long int *longword_ptr;
+ unsigned long int longword, magic_bits, charmask;
+ unsigned reg_char c;
+ int i;
+
+ c = (unsigned char) c_in;
+
+ /* Handle the last few characters by reading one character at a time.
+ Do this until CHAR_PTR is aligned on a longword boundary. */
+ for (char_ptr = (const unsigned char *) s + n;
+ n > 0 && (size_t) char_ptr % sizeof longword != 0;
+ --n)
+ if (*--char_ptr == c)
+ return (void *) char_ptr;
+
+ /* All these elucidatory comments refer to 4-byte longwords,
+ but the theory applies equally well to any size longwords. */
+
+ longword_ptr = (const unsigned long int *) char_ptr;
+
+ /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
+ the "holes." Note that there is a hole just to the left of
+ each byte, with an extra at the end:
+
+ bits: 01111110 11111110 11111110 11111111
+ bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
+
+ The 1-bits make sure that carries propagate to the next 0-bit.
+ The 0-bits provide holes for carries to fall into. */
+
+ /* Set MAGIC_BITS to be this pattern of 1 and 0 bits.
+ Set CHARMASK to be a longword, each of whose bytes is C. */
+
+ magic_bits = 0xfefefefe;
+ charmask = c | (c << 8);
+ charmask |= charmask << 16;
+#if 0xffffffffU < ULONG_MAX
+ magic_bits |= magic_bits << 32;
+ charmask |= charmask << 32;
+ if (8 < sizeof longword)
+ for (i = 64; i < sizeof longword * 8; i *= 2)
+ {
+ magic_bits |= magic_bits << i;
+ charmask |= charmask << i;
+ }
+#endif
+ magic_bits = (ULONG_MAX >> 1) & (magic_bits | 1);
+
+ /* Instead of the traditional loop which tests each character,
+ we will test a longword at a time. The tricky part is testing
+ if *any of the four* bytes in the longword in question are zero. */
+ while (n >= sizeof longword)
+ {
+ /* We tentatively exit the loop if adding MAGIC_BITS to
+ LONGWORD fails to change any of the hole bits of LONGWORD.
+
+ 1) Is this safe? Will it catch all the zero bytes?
+ Suppose there is a byte with all zeros. Any carry bits
+ propagating from its left will fall into the hole at its
+ least significant bit and stop. Since there will be no
+ carry from its most significant bit, the LSB of the
+ byte to the left will be unchanged, and the zero will be
+ detected.
+
+ 2) Is this worthwhile? Will it ignore everything except
+ zero bytes? Suppose every byte of LONGWORD has a bit set
+ somewhere. There will be a carry into bit 8. If bit 8
+ is set, this will carry into bit 16. If bit 8 is clear,
+ one of bits 9-15 must be set, so there will be a carry
+ into bit 16. Similarly, there will be a carry into bit
+ 24. If one of bits 24-30 is set, there will be a carry
+ into bit 31, so all of the hole bits will be changed.
+
+ The one misfire occurs when bits 24-30 are clear and bit
+ 31 is set; in this case, the hole at bit 31 is not
+ changed. If we had access to the processor carry flag,
+ we could close this loophole by putting the fourth hole
+ at bit 32!
+
+ So it ignores everything except 128's, when they're aligned
+ properly.
+
+ 3) But wait! Aren't we looking for C, not zero?
+ Good point. So what we do is XOR LONGWORD with a longword,
+ each of whose bytes is C. This turns each byte that is C
+ into a zero. */
+
+ longword = *--longword_ptr ^ charmask;
+
+ /* Add MAGIC_BITS to LONGWORD. */
+ if ((((longword + magic_bits)
+
+ /* Set those bits that were unchanged by the addition. */
+ ^ ~longword)
+
+ /* Look at only the hole bits. If any of the hole bits
+ are unchanged, most likely one of the bytes was a
+ zero. */
+ & ~magic_bits) != 0)
+ {
+ /* Which of the bytes was C? If none of them were, it was
+ a misfire; continue the search. */
+
+ const unsigned char *cp = (const unsigned char *) longword_ptr;
+
+ if (8 < sizeof longword)
+ for (i = sizeof longword - 1; 8 <= i; i--)
+ if (cp[i] == c)
+ return (void *) &cp[i];
+ if (7 < sizeof longword && cp[7] == c)
+ return (void *) &cp[7];
+ if (6 < sizeof longword && cp[6] == c)
+ return (void *) &cp[6];
+ if (5 < sizeof longword && cp[5] == c)
+ return (void *) &cp[5];
+ if (4 < sizeof longword && cp[4] == c)
+ return (void *) &cp[4];
+ if (cp[3] == c)
+ return (void *) &cp[3];
+ if (cp[2] == c)
+ return (void *) &cp[2];
+ if (cp[1] == c)
+ return (void *) &cp[1];
+ if (cp[0] == c)
+ return (void *) cp;
+ }
+
+ n -= sizeof longword;
+ }
+
+ char_ptr = (const unsigned char *) longword_ptr;
+
+ while (n-- > 0)
+ {
+ if (*--char_ptr == c)
+ return (void *) char_ptr;
+ }
+
+ return 0;
+}
+#ifdef weak_alias
+weak_alias (__memrchr, memrchr)
+#endif
diff --git a/lib/memrchr.h b/lib/memrchr.h
new file mode 100644
index 0000000..d4785c2
--- /dev/null
+++ b/lib/memrchr.h
@@ -0,0 +1,27 @@
+/* memrchr -- Find the last occurrence of a byte in a memory block.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#if HAVE_DECL_MEMRCHR
+# include <string.h>
+#else
+# include <stddef.h>
+
+/* Search backwards through a block for a byte (specified as an int). */
+void *memrchr (void const *, int, size_t);
+
+#endif
diff --git a/lib/minmax.h b/lib/minmax.h
new file mode 100644
index 0000000..975ea76
--- /dev/null
+++ b/lib/minmax.h
@@ -0,0 +1,60 @@
+/* MIN, MAX macros.
+ Copyright (C) 1995, 1998, 2001, 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _MINMAX_H
+#define _MINMAX_H
+
+/* Note: MIN, MAX are also defined in <sys/param.h> on some systems
+ (glibc, IRIX, HP-UX, OSF/1). Therefore you might get warnings about
+ MIN, MAX macro redefinitions on some systems; the workaround is to
+ #include this file as the last one among the #include list. */
+
+/* Before we define the following symbols we get the <limits.h> file
+ since otherwise we get redefinitions on some systems if <limits.h> is
+ included after this file. Likewise for <sys/param.h>.
+ If more than one of these system headers define MIN and MAX, pick just
+ one of the headers (because the definitions most likely are the same). */
+#if HAVE_MINMAX_IN_LIMITS_H
+# include <limits.h>
+#elif HAVE_MINMAX_IN_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+/* Note: MIN and MAX should be used with two arguments of the
+ same type. They might not return the minimum and maximum of their two
+ arguments, if the arguments have different types or have unusual
+ floating-point values. For example, on a typical host with 32-bit 'int',
+ 64-bit 'long long', and 64-bit IEEE 754 'double' types:
+
+ MAX (-1, 2147483648) returns 4294967295.
+ MAX (9007199254740992.0, 9007199254740993) returns 9007199254740992.0.
+ MAX (NaN, 0.0) returns 0.0.
+ MAX (+0.0, -0.0) returns -0.0.
+
+ and in each case the answer is in some sense bogus. */
+
+/* MAX(a,b) returns the maximum of A and B. */
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* MIN(a,b) returns the minimum of A and B. */
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#endif /* _MINMAX_H */
diff --git a/lib/mkdir.c b/lib/mkdir.c
new file mode 100644
index 0000000..c921ecf
--- /dev/null
+++ b/lib/mkdir.c
@@ -0,0 +1,65 @@
+/* On some systems, mkdir ("foo/", 0700) fails because of the trailing
+ slash. On those systems, this wrapper removes the trailing slash.
+
+ Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Disable the definition of mkdir to rpl_mkdir (from config.h) in this
+ file. Otherwise, we'd get conflicting prototypes for rpl_mkdir on
+ most systems. */
+#undef mkdir
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dirname.h"
+#include "xalloc.h"
+
+/* This function is required at least for NetBSD 1.5.2. */
+
+int
+rpl_mkdir (char const *dir, mode_t mode)
+{
+ int ret_val;
+ char *tmp_dir;
+ size_t len = strlen (dir);
+
+ if (len && dir[len - 1] == '/')
+ {
+ tmp_dir = xstrdup (dir);
+ strip_trailing_slashes (tmp_dir);
+ }
+ else
+ {
+ tmp_dir = (char *) dir;
+ }
+
+ ret_val = mkdir (tmp_dir, mode);
+
+ if (tmp_dir != dir)
+ free (tmp_dir);
+
+ return ret_val;
+}
diff --git a/lib/mkstemp.c b/lib/mkstemp.c
new file mode 100644
index 0000000..cec5ba8
--- /dev/null
+++ b/lib/mkstemp.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
+ This file is derived from the one in the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Disable the definition of mkstemp to rpl_mkstemp (from config.h) in this
+ file. Otherwise, we'd get conflicting prototypes for rpl_mkstemp on
+ most systems. */
+#undef mkstemp
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef __GT_FILE
+# define __GT_FILE 0
+#endif
+
+int __gen_tempname ();
+
+/* Generate a unique temporary file name from TEMPLATE.
+ The last six characters of TEMPLATE must be "XXXXXX";
+ they are replaced with a string that makes the file name unique.
+ Then open the file and return a fd. */
+int
+rpl_mkstemp (char *template)
+{
+ return __gen_tempname (template, __GT_FILE);
+}
diff --git a/lib/mktime.c b/lib/mktime.c
new file mode 100644
index 0000000..b2d9e52
--- /dev/null
+++ b/lib/mktime.c
@@ -0,0 +1,664 @@
+/* Convert a `struct tm' to a time_t value.
+ Copyright (C) 1993-1999, 2002-2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Paul Eggert (eggert@twinsun.com).
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Define this to have a standalone program to test this implementation of
+ mktime. */
+/* #define DEBUG 1 */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Assume that leap seconds are possible, unless told otherwise.
+ If the host has a `zic' command with a `-L leapsecondfilename' option,
+ then it supports leap seconds; otherwise it probably doesn't. */
+#ifndef LEAP_SECONDS_POSSIBLE
+# define LEAP_SECONDS_POSSIBLE 1
+#endif
+
+#include <sys/types.h> /* Some systems define `time_t' here. */
+#include <time.h>
+
+#include <limits.h>
+
+#include <string.h> /* For the real memcpy prototype. */
+
+#if DEBUG
+# include <stdio.h>
+# include <stdlib.h>
+/* Make it work even if the system's libc has its own mktime routine. */
+# define mktime my_mktime
+#endif /* DEBUG */
+
+/* Shift A right by B bits portably, by dividing A by 2**B and
+ truncating towards minus infinity. A and B should be free of side
+ effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
+ INT_BITS is the number of useful bits in an int. GNU code can
+ assume that INT_BITS is at least 32.
+
+ ISO C99 says that A >> B is implementation-defined if A < 0. Some
+ implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
+ right in the usual way when A < 0, so SHR falls back on division if
+ ordinary A >> B doesn't seem to be the usual signed shift. */
+#define SHR(a, b) \
+ (-1 >> 1 == -1 \
+ ? (a) >> (b) \
+ : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
+
+/* The extra casts in the following macros work around compiler bugs,
+ e.g., in Cray C 5.0.3.0. */
+
+/* True if the arithmetic type T is an integer type. bool counts as
+ an integer. */
+#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
+
+/* True if negative values of the signed integer type T use two's
+ complement, ones' complement, or signed magnitude representation,
+ respectively. Much GNU code assumes two's complement, but some
+ people like to be portable to all possible C hosts. */
+#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
+#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
+#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
+
+/* True if the arithmetic type T is signed. */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+
+/* The maximum and minimum values for the integer type T. These
+ macros have undefined behavior if T is signed and has padding bits.
+ If this is a problem for you, please let us know how to fix it for
+ your host. */
+#define TYPE_MINIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) 0 \
+ : TYPE_SIGNED_MAGNITUDE (t) \
+ ? ~ (t) 0 \
+ : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
+#define TYPE_MAXIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) -1 \
+ : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
+
+#ifndef TIME_T_MIN
+# define TIME_T_MIN TYPE_MINIMUM (time_t)
+#endif
+#ifndef TIME_T_MAX
+# define TIME_T_MAX TYPE_MAXIMUM (time_t)
+#endif
+#define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
+
+/* Verify a requirement at compile-time (unlike assert, which is runtime). */
+#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
+
+verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
+verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
+/* The code also assumes that signed integer overflow silently wraps
+ around, but this assumption can't be stated without causing a
+ diagnostic on some hosts. */
+
+#define EPOCH_YEAR 1970
+#define TM_YEAR_BASE 1900
+verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
+
+/* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
+static inline int
+leapyear (long int year)
+{
+ /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
+ Also, work even if YEAR is negative. */
+ return
+ ((year & 3) == 0
+ && (year % 100 != 0
+ || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
+}
+
+/* How many days come before each month (0-12). */
+#ifndef _LIBC
+static
+#endif
+const unsigned short int __mon_yday[2][13] =
+ {
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ };
+
+
+#ifndef _LIBC
+/* Portable standalone applications should supply a "time_r.h" that
+ declares a POSIX-compliant localtime_r, for the benefit of older
+ implementations that lack localtime_r or have a nonstandard one.
+ See the gnulib time_r module for one way to implement this. */
+# include "time_r.h"
+# undef __localtime_r
+# define __localtime_r localtime_r
+# define __mktime_internal mktime_internal
+#endif
+
+/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
+ (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
+ were not adjusted between the time stamps.
+
+ The YEAR values uses the same numbering as TP->tm_year. Values
+ need not be in the usual range. However, YEAR1 must not be less
+ than 2 * INT_MIN or greater than 2 * INT_MAX.
+
+ The result may overflow. It is the caller's responsibility to
+ detect overflow. */
+
+static inline time_t
+ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
+ int year0, int yday0, int hour0, int min0, int sec0)
+{
+ verify (C99_integer_division, -1 / 2 == 0);
+ verify (long_int_year_and_yday_are_wide_enough,
+ INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
+
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid integer overflow here. */
+ int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
+ int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = SHR (a100, 2);
+ int b400 = SHR (b100, 2);
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+
+ /* Compute the desired time in time_t precision. Overflow might
+ occur here. */
+ time_t tyear1 = year1;
+ time_t years = tyear1 - year0;
+ time_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
+ time_t hours = 24 * days + hour1 - hour0;
+ time_t minutes = 60 * hours + min1 - min0;
+ time_t seconds = 60 * minutes + sec1 - sec0;
+ return seconds;
+}
+
+
+/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
+ assuming that *T corresponds to *TP and that no clock adjustments
+ occurred between *TP and the desired time.
+ If TP is null, return a value not equal to *T; this avoids false matches.
+ If overflow occurs, yield the minimal or maximal value, except do not
+ yield a value equal to *T. */
+static time_t
+guess_time_tm (long int year, long int yday, int hour, int min, int sec,
+ const time_t *t, const struct tm *tp)
+{
+ if (tp)
+ {
+ time_t d = ydhms_diff (year, yday, hour, min, sec,
+ tp->tm_year, tp->tm_yday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ time_t t1 = *t + d;
+ if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d))
+ return t1;
+ }
+
+ /* Overflow occurred one way or another. Return the nearest result
+ that is actually in range, except don't report a zero difference
+ if the actual difference is nonzero, as that would cause a false
+ match. */
+ return (*t < TIME_T_MIDPOINT
+ ? TIME_T_MIN + (*t == TIME_T_MIN)
+ : TIME_T_MAX - (*t == TIME_T_MAX));
+}
+
+/* Use CONVERT to convert *T to a broken down time in *TP.
+ If *T is out of range for conversion, adjust it so that
+ it is the nearest in-range value and then convert that. */
+static struct tm *
+ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
+ time_t *t, struct tm *tp)
+{
+ struct tm *r = convert (t, tp);
+
+ if (!r && *t)
+ {
+ time_t bad = *t;
+ time_t ok = 0;
+
+ /* BAD is a known unconvertible time_t, and OK is a known good one.
+ Use binary search to narrow the range between BAD and OK until
+ they differ by 1. */
+ while (bad != ok + (bad < 0 ? -1 : 1))
+ {
+ time_t mid = *t = (bad < 0
+ ? bad + ((ok - bad) >> 1)
+ : ok + ((bad - ok) >> 1));
+ r = convert (t, tp);
+ if (r)
+ ok = mid;
+ else
+ bad = mid;
+ }
+
+ if (!r && ok)
+ {
+ /* The last conversion attempt failed;
+ revert to the most recent successful attempt. */
+ *t = ok;
+ r = convert (t, tp);
+ }
+ }
+
+ return r;
+}
+
+
+/* Convert *TP to a time_t value, inverting
+ the monotonic and mostly-unit-linear conversion function CONVERT.
+ Use *OFFSET to keep track of a guess at the offset of the result,
+ compared to what the result would be for UTC without leap seconds.
+ If *OFFSET's guess is correct, only one CONVERT call is needed.
+ This function is external because it is used also by timegm.c. */
+time_t
+__mktime_internal (struct tm *tp,
+ struct tm *(*convert) (const time_t *, struct tm *),
+ time_t *offset)
+{
+ time_t t, gt, t0, t1, t2;
+ struct tm tm;
+
+ /* The maximum number of probes (calls to CONVERT) should be enough
+ to handle any combinations of time zone rule changes, solar time,
+ leap seconds, and oscillations around a spring-forward gap.
+ POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
+ int remaining_probes = 6;
+
+ /* Time requested. Copy it in case CONVERT modifies *TP; this can
+ occur if TP is localtime's returned value and CONVERT is localtime. */
+ int sec = tp->tm_sec;
+ int min = tp->tm_min;
+ int hour = tp->tm_hour;
+ int mday = tp->tm_mday;
+ int mon = tp->tm_mon;
+ int year_requested = tp->tm_year;
+ int isdst = tp->tm_isdst;
+
+ /* 1 if the previous probe was DST. */
+ int dst2;
+
+ /* Ensure that mon is in range, and set year accordingly. */
+ int mon_remainder = mon % 12;
+ int negative_mon_remainder = mon_remainder < 0;
+ int mon_years = mon / 12 - negative_mon_remainder;
+ long int lyear_requested = year_requested;
+ long int year = lyear_requested + mon_years;
+
+ /* The other values need not be in range:
+ the remaining code handles minor overflows correctly,
+ assuming int and time_t arithmetic wraps around.
+ Major overflows are caught at the end. */
+
+ /* Calculate day of year from year, month, and day of month.
+ The result need not be in range. */
+ int mon_yday = ((__mon_yday[leapyear (year)]
+ [mon_remainder + 12 * negative_mon_remainder])
+ - 1);
+ long int lmday = mday;
+ long int yday = mon_yday + lmday;
+
+ time_t guessed_offset = *offset;
+
+ int sec_requested = sec;
+
+ if (LEAP_SECONDS_POSSIBLE)
+ {
+ /* Handle out-of-range seconds specially,
+ since ydhms_tm_diff assumes every minute has 60 seconds. */
+ if (sec < 0)
+ sec = 0;
+ if (59 < sec)
+ sec = 59;
+ }
+
+ /* Invert CONVERT by probing. First assume the same offset as last
+ time. */
+
+ t0 = ydhms_diff (year, yday, hour, min, sec,
+ EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
+
+ if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
+ {
+ /* time_t isn't large enough to rule out overflows, so check
+ for major overflows. A gross check suffices, since if t0
+ has overflowed, it is off by a multiple of TIME_T_MAX -
+ TIME_T_MIN + 1. So ignore any component of the difference
+ that is bounded by a small value. */
+
+ /* Approximate log base 2 of the number of time units per
+ biennium. A biennium is 2 years; use this unit instead of
+ years to avoid integer overflow. For example, 2 average
+ Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
+ which is 63113904 seconds, and rint (log2 (63113904)) is
+ 26. */
+ int ALOG2_SECONDS_PER_BIENNIUM = 26;
+ int ALOG2_MINUTES_PER_BIENNIUM = 20;
+ int ALOG2_HOURS_PER_BIENNIUM = 14;
+ int ALOG2_DAYS_PER_BIENNIUM = 10;
+ int LOG2_YEARS_PER_BIENNIUM = 1;
+
+ int approx_requested_biennia =
+ (SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
+ - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
+ + SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
+ + SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
+ + SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
+ + (LEAP_SECONDS_POSSIBLE
+ ? 0
+ : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
+
+ int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
+ int diff = approx_biennia - approx_requested_biennia;
+ int abs_diff = diff < 0 ? - diff : diff;
+
+ /* IRIX 4.0.5 cc miscaculates TIME_T_MIN / 3: it erroneously
+ gives a positive value of 715827882. Setting a variable
+ first then doing math on it seems to work.
+ (ghazi@caip.rutgers.edu) */
+ time_t time_t_max = TIME_T_MAX;
+ time_t time_t_min = TIME_T_MIN;
+ time_t overflow_threshold =
+ (time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
+
+ if (overflow_threshold < abs_diff)
+ {
+ /* Overflow occurred. Try repairing it; this might work if
+ the time zone offset is enough to undo the overflow. */
+ time_t repaired_t0 = -1 - t0;
+ approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
+ diff = approx_biennia - approx_requested_biennia;
+ abs_diff = diff < 0 ? - diff : diff;
+ if (overflow_threshold < abs_diff)
+ return -1;
+ guessed_offset += repaired_t0 - t0;
+ t0 = repaired_t0;
+ }
+ }
+
+ /* Repeatedly use the error to improve the guess. */
+
+ for (t = t1 = t2 = t0, dst2 = 0;
+ (gt = guess_time_tm (year, yday, hour, min, sec, &t,
+ ranged_convert (convert, &t, &tm)),
+ t != gt);
+ t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
+ if (t == t1 && t != t2
+ && (tm.tm_isdst < 0
+ || (isdst < 0
+ ? dst2 <= (tm.tm_isdst != 0)
+ : (isdst != 0) != (tm.tm_isdst != 0))))
+ /* We can't possibly find a match, as we are oscillating
+ between two values. The requested time probably falls
+ within a spring-forward gap of size GT - T. Follow the common
+ practice in this case, which is to return a time that is GT - T
+ away from the requested time, preferring a time whose
+ tm_isdst differs from the requested value. (If no tm_isdst
+ was requested and only one of the two values has a nonzero
+ tm_isdst, prefer that value.) In practice, this is more
+ useful than returning -1. */
+ goto offset_found;
+ else if (--remaining_probes == 0)
+ return -1;
+
+ /* We have a match. Check whether tm.tm_isdst has the requested
+ value, if any. */
+ if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
+ {
+ /* tm.tm_isdst has the wrong value. Look for a neighboring
+ time with the right value, and use its UTC offset.
+
+ Heuristic: probe the adjacent timestamps in both directions,
+ looking for the desired isdst. This should work for all real
+ time zone histories in the tz database. */
+
+ /* Distance between probes when looking for a DST boundary. In
+ tzdata2003a, the shortest period of DST is 601200 seconds
+ (e.g., America/Recife starting 2000-10-08 01:00), and the
+ shortest period of non-DST surrounded by DST is 694800
+ seconds (Africa/Tunis starting 1943-04-17 01:00). Use the
+ minimum of these two values, so we don't miss these short
+ periods when probing. */
+ int stride = 601200;
+
+ /* The longest period of DST in tzdata2003a is 536454000 seconds
+ (e.g., America/Jujuy starting 1946-10-01 01:00). The longest
+ period of non-DST is much longer, but it makes no real sense
+ to search for more than a year of non-DST, so use the DST
+ max. */
+ int duration_max = 536454000;
+
+ /* Search in both directions, so the maximum distance is half
+ the duration; add the stride to avoid off-by-1 problems. */
+ int delta_bound = duration_max / 2 + stride;
+
+ int delta, direction;
+
+ for (delta = stride; delta < delta_bound; delta += stride)
+ for (direction = -1; direction <= 1; direction += 2)
+ {
+ time_t ot = t + delta * direction;
+ if ((ot < t) == (direction < 0))
+ {
+ struct tm otm;
+ ranged_convert (convert, &ot, &otm);
+ if (otm.tm_isdst == isdst)
+ {
+ /* We found the desired tm_isdst.
+ Extrapolate back to the desired time. */
+ t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
+ ranged_convert (convert, &t, &tm);
+ goto offset_found;
+ }
+ }
+ }
+ }
+
+ offset_found:
+ *offset = guessed_offset + t - t0;
+
+ if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
+ {
+ /* Adjust time to reflect the tm_sec requested, not the normalized value.
+ Also, repair any damage from a false match due to a leap second. */
+ int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
+ t1 = t + sec_requested;
+ t2 = t1 + sec_adjustment;
+ if (((t1 < t) != (sec_requested < 0))
+ | ((t2 < t1) != (sec_adjustment < 0))
+ | ! convert (&t2, &tm))
+ return -1;
+ t = t2;
+ }
+
+ *tp = tm;
+ return t;
+}
+
+
+/* FIXME: This should use a signed type wide enough to hold any UTC
+ offset in seconds. 'int' should be good enough for GNU code. We
+ can't fix this unilaterally though, as other modules invoke
+ __mktime_internal. */
+static time_t localtime_offset;
+
+/* Convert *TP to a time_t value. */
+time_t
+mktime (struct tm *tp)
+{
+#ifdef _LIBC
+ /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
+ time zone names contained in the external variable `tzname' shall
+ be set as if the tzset() function had been called. */
+ __tzset ();
+#endif
+
+ return __mktime_internal (tp, __localtime_r, &localtime_offset);
+}
+
+#ifdef weak_alias
+weak_alias (mktime, timelocal)
+#endif
+
+#ifdef _LIBC
+libc_hidden_def (mktime)
+libc_hidden_weak (timelocal)
+#endif
+
+#if DEBUG
+
+static int
+not_equal_tm (const struct tm *a, const struct tm *b)
+{
+ return ((a->tm_sec ^ b->tm_sec)
+ | (a->tm_min ^ b->tm_min)
+ | (a->tm_hour ^ b->tm_hour)
+ | (a->tm_mday ^ b->tm_mday)
+ | (a->tm_mon ^ b->tm_mon)
+ | (a->tm_year ^ b->tm_year)
+ | (a->tm_yday ^ b->tm_yday)
+ | (a->tm_isdst ^ b->tm_isdst));
+}
+
+static void
+print_tm (const struct tm *tp)
+{
+ if (tp)
+ printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
+ tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec,
+ tp->tm_yday, tp->tm_wday, tp->tm_isdst);
+ else
+ printf ("0");
+}
+
+static int
+check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
+{
+ if (tk != tl || !lt || not_equal_tm (&tmk, lt))
+ {
+ printf ("mktime (");
+ print_tm (lt);
+ printf (")\nyields (");
+ print_tm (&tmk);
+ printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ int status = 0;
+ struct tm tm, tmk, tml;
+ struct tm *lt;
+ time_t tk, tl, tl1;
+ char trailer;
+
+ if ((argc == 3 || argc == 4)
+ && (sscanf (argv[1], "%d-%d-%d%c",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
+ == 3)
+ && (sscanf (argv[2], "%d:%d:%d%c",
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
+ == 3))
+ {
+ tm.tm_year -= TM_YEAR_BASE;
+ tm.tm_mon--;
+ tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
+ tmk = tm;
+ tl = mktime (&tmk);
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tml = *lt;
+ lt = &tml;
+ }
+ printf ("mktime returns %ld == ", (long int) tl);
+ print_tm (&tmk);
+ printf ("\n");
+ status = check_result (tl, tmk, tl, lt);
+ }
+ else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
+ {
+ time_t from = atol (argv[1]);
+ time_t by = atol (argv[2]);
+ time_t to = atol (argv[3]);
+
+ if (argc == 4)
+ for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
+ {
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tmk = tml = *lt;
+ tk = mktime (&tmk);
+ status |= check_result (tk, tmk, tl, &tml);
+ }
+ else
+ {
+ printf ("localtime (%ld) yields 0\n", (long int) tl);
+ status = 1;
+ }
+ tl1 = tl + by;
+ if ((tl1 < tl) != (by < 0))
+ break;
+ }
+ else
+ for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
+ {
+ /* Null benchmark. */
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tmk = tml = *lt;
+ tk = tl;
+ status |= check_result (tk, tmk, tl, &tml);
+ }
+ else
+ {
+ printf ("localtime (%ld) yields 0\n", (long int) tl);
+ status = 1;
+ }
+ tl1 = tl + by;
+ if ((tl1 < tl) != (by < 0))
+ break;
+ }
+ }
+ else
+ printf ("Usage:\
+\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
+\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
+\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
+ argv[0], argv[0], argv[0]);
+
+ return status;
+}
+
+#endif /* DEBUG */
+
+/*
+Local Variables:
+compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime"
+End:
+*/
diff --git a/lib/nanosleep.c b/lib/nanosleep.c
new file mode 100644
index 0000000..fa20785
--- /dev/null
+++ b/lib/nanosleep.c
@@ -0,0 +1,124 @@
+/* Provide a replacement for the POSIX nanosleep function.
+ Copyright (C) 1999, 2000, 2002, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Undefine nanosleep here so any prototype is not redefined to be a
+ prototype for rpl_nanosleep. (they'd conflict e.g., on alpha-dec-osf3.2) */
+#undef nanosleep
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <errno.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "timespec.h"
+
+/* Some systems (MSDOS) don't have SIGCONT.
+ Using SIGTERM here turns the signal-handling code below
+ into a no-op on such systems. */
+#ifndef SIGCONT
+# define SIGCONT SIGTERM
+#endif
+
+#if ! HAVE_SIGINTERRUPT
+# define siginterrupt(sig, flag) /* empty */
+#endif
+
+static sig_atomic_t volatile suspended;
+
+/* Handle SIGCONT. */
+
+static void
+sighandler (int sig)
+{
+ suspended = 1;
+}
+
+/* FIXME: comment */
+
+static void
+my_usleep (const struct timespec *ts_delay)
+{
+ struct timeval tv_delay;
+ tv_delay.tv_sec = ts_delay->tv_sec;
+ tv_delay.tv_usec = (ts_delay->tv_nsec + 999) / 1000;
+ if (tv_delay.tv_usec == 1000000)
+ {
+ tv_delay.tv_sec++;
+ tv_delay.tv_usec = 0;
+ }
+ select (0, NULL, NULL, NULL, &tv_delay);
+}
+
+/* FIXME: comment */
+
+int
+rpl_nanosleep (const struct timespec *requested_delay,
+ struct timespec *remaining_delay)
+{
+ static bool initialized;
+
+ /* set up sig handler */
+ if (! initialized)
+ {
+#ifdef SA_NOCLDSTOP
+ struct sigaction oldact, newact;
+ newact.sa_handler = sighandler;
+ sigemptyset (&newact.sa_mask);
+ newact.sa_flags = 0;
+
+ sigaction (SIGCONT, NULL, &oldact);
+ if (oldact.sa_handler != SIG_IGN)
+ sigaction (SIGCONT, &newact, NULL);
+#else
+ if (signal (SIGCONT, SIG_IGN) != SIG_IGN)
+ {
+ signal (SIGCONT, sighandler);
+ siginterrupt (SIGCONT, 1);
+ }
+#endif
+ initialized = true;
+ }
+
+ suspended = 0;
+
+ my_usleep (requested_delay);
+
+ if (suspended)
+ {
+ /* Calculate time remaining. */
+ /* FIXME: the code in sleep doesn't use this, so there's no
+ rush to implement it. */
+
+ errno = EINTR;
+ }
+
+ /* FIXME: Restore sig handler? */
+
+ return suspended;
+}
diff --git a/lib/openat.c b/lib/openat.c
new file mode 100644
index 0000000..443cb3d
--- /dev/null
+++ b/lib/openat.c
@@ -0,0 +1,181 @@
+/* provide a replacement openat function
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "openat.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "error.h"
+#include "exitfail.h"
+#include "save-cwd.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Replacement for Solaris' openat function.
+ <http://www.google.com/search?q=openat+site:docs.sun.com>
+ Simulate it by doing save_cwd/fchdir/open/restore_cwd.
+ If either the save_cwd or the restore_cwd fails (relatively unlikely,
+ and usually indicative of a problem that deserves close attention),
+ then give a diagnostic and exit nonzero.
+ Otherwise, upon failure, set errno and return -1, as openat does.
+ Upon successful completion, return a file descriptor. */
+int
+rpl_openat (int fd, char const *file, int flags, ...)
+{
+ struct saved_cwd saved_cwd;
+ int saved_errno;
+ int new_fd;
+ mode_t mode = 0;
+
+ if (flags & O_CREAT)
+ {
+ va_list arg;
+ va_start (arg, flags);
+
+ /* Assume that mode_t is passed compatibly with mode_t's type
+ after argument promotion. */
+ mode = va_arg (arg, mode_t);
+
+ va_end (arg);
+ }
+
+ if (fd == AT_FDCWD || *file == '/')
+ return open (file, flags, mode);
+
+ if (save_cwd (&saved_cwd) != 0)
+ error (exit_failure, errno,
+ _("openat: unable to record current working directory"));
+
+ if (fchdir (fd) != 0)
+ {
+ saved_errno = errno;
+ free_cwd (&saved_cwd);
+ errno = saved_errno;
+ return -1;
+ }
+
+ new_fd = open (file, flags, mode);
+ saved_errno = errno;
+
+ if (restore_cwd (&saved_cwd) != 0)
+ error (exit_failure, errno,
+ _("openat: unable to restore working directory"));
+
+ free_cwd (&saved_cwd);
+
+ errno = saved_errno;
+ return new_fd;
+}
+
+/* Replacement for Solaris' function by the same name.
+ <http://www.google.com/search?q=fdopendir+site:docs.sun.com>
+ Simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd.
+ If either the save_cwd or the restore_cwd fails (relatively unlikely,
+ and usually indicative of a problem that deserves close attention),
+ then give a diagnostic and exit nonzero.
+ Otherwise, this function works just like Solaris' fdopendir. */
+DIR *
+fdopendir (int fd)
+{
+ struct saved_cwd saved_cwd;
+ int saved_errno;
+ DIR *dir;
+
+ if (fd == AT_FDCWD)
+ return opendir (".");
+
+ if (save_cwd (&saved_cwd) != 0)
+ error (exit_failure, errno,
+ _("fdopendir: unable to record current working directory"));
+
+ if (fchdir (fd) != 0)
+ {
+ saved_errno = errno;
+ free_cwd (&saved_cwd);
+ errno = saved_errno;
+ return NULL;
+ }
+
+ dir = opendir (".");
+ saved_errno = errno;
+
+ if (restore_cwd (&saved_cwd) != 0)
+ error (exit_failure, errno,
+ _("fdopendir: unable to restore working directory"));
+
+ free_cwd (&saved_cwd);
+
+ errno = saved_errno;
+ return dir;
+}
+
+/* Replacement for Solaris' function by the same name.
+ <http://www.google.com/search?q=fstatat+site:docs.sun.com>
+ Simulate it by doing save_cwd/fchdir/(stat|lstat)/restore_cwd.
+ If either the save_cwd or the restore_cwd fails (relatively unlikely,
+ and usually indicative of a problem that deserves close attention),
+ then give a diagnostic and exit nonzero.
+ Otherwise, this function works just like Solaris' fstatat. */
+int
+fstatat (int fd, char const *file, struct stat *st, int flag)
+{
+ struct saved_cwd saved_cwd;
+ int saved_errno;
+ int err;
+
+ if (fd == AT_FDCWD)
+ return (flag == AT_SYMLINK_NOFOLLOW
+ ? lstat (file, st)
+ : stat (file, st));
+
+ if (save_cwd (&saved_cwd) != 0)
+ error (exit_failure, errno,
+ _("fstatat: unable to record current working directory"));
+
+ if (fchdir (fd) != 0)
+ {
+ saved_errno = errno;
+ free_cwd (&saved_cwd);
+ errno = saved_errno;
+ return -1;
+ }
+
+ err = (flag == AT_SYMLINK_NOFOLLOW
+ ? lstat (file, st)
+ : stat (file, st));
+ saved_errno = errno;
+
+ if (restore_cwd (&saved_cwd) != 0)
+ error (exit_failure, errno,
+ _("fstatat: unable to restore working directory"));
+
+ free_cwd (&saved_cwd);
+
+ errno = saved_errno;
+ return err;
+}
diff --git a/lib/openat.h b/lib/openat.h
new file mode 100644
index 0000000..76ad46b
--- /dev/null
+++ b/lib/openat.h
@@ -0,0 +1,44 @@
+/* provide a replacement openat function
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#ifndef AT_FDCWD
+# define AT_FDCWD (-3041965) /* same value as Solaris 9 */
+# define AT_SYMLINK_NOFOLLOW 4096 /* same value as Solaris 9 */
+
+# ifdef __OPENAT_PREFIX
+# undef openat
+# define __OPENAT_CONCAT(x, y) x ## y
+# define __OPENAT_XCONCAT(x, y) __OPENAT_CONCAT (x, y)
+# define __OPENAT_ID(y) __OPENAT_XCONCAT (__OPENAT_PREFIX, y)
+# define openat __OPENAT_ID (openat)
+int openat (int fd, char const *file, int flags, /* mode_t mode */ ...);
+# define fdopendir __OPENAT_ID (fdopendir)
+DIR *fdopendir (int fd);
+# define fstatat __OPENAT_ID (fstatat)
+int fstatat (int fd, char const *file, struct stat *st, int flag);
+# endif
+
+#endif
diff --git a/lib/pagealign_alloc.c b/lib/pagealign_alloc.c
new file mode 100644
index 0000000..28e8209
--- /dev/null
+++ b/lib/pagealign_alloc.c
@@ -0,0 +1,198 @@
+/* Memory allocation aligned to system page boundaries.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Written by Derek R. Price <derek@ximbiot.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "pagealign_alloc.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <fcntl.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_MMAP
+# include <sys/mman.h>
+#endif
+
+#include "error.h"
+#include "exit.h"
+#include "getpagesize.h"
+#include "xalloc.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+#if HAVE_MMAP
+/* Define MAP_FILE when it isn't otherwise. */
+# ifndef MAP_FILE
+# define MAP_FILE 0
+# endif
+/* Define MAP_FAILED for old systems which neglect to. */
+# ifndef MAP_FAILED
+# define MAP_FAILED ((void *)-1)
+# endif
+#endif
+
+
+#if HAVE_MMAP || ! HAVE_POSIX_MEMALIGN
+
+# if HAVE_MMAP
+/* For each memory region, we store its size. */
+typedef size_t info_t;
+# else
+/* For each memory region, we store the original pointer returned by
+ malloc(). */
+typedef void * info_t;
+# endif
+
+/* A simple linked list of allocated memory regions. It is probably not the
+ most efficient way to store these, but anyway... */
+typedef struct memnode_s memnode_t;
+struct memnode_s
+{
+ void *aligned_ptr;
+ info_t info;
+ memnode_t *next;
+};
+
+/* The list of currently allocated memory regions. */
+static memnode_t *memnode_table = NULL;
+
+
+static void
+new_memnode (void *aligned_ptr, info_t info)
+{
+ memnode_t *new_node = (memnode_t *) xmalloc (sizeof (memnode_t));
+ new_node->aligned_ptr = aligned_ptr;
+ new_node->info = info;
+ new_node->next = memnode_table;
+ memnode_table = new_node;
+}
+
+
+/* Dispose of the memnode containing a map for the ALIGNED_PTR in question
+ and return the content of the node's INFO field. */
+static info_t
+get_memnode (void *aligned_ptr)
+{
+ info_t ret;
+ memnode_t *c;
+ memnode_t **p_next = &memnode_table;
+
+ for (c = *p_next; c != NULL; p_next = &c->next, c = c->next)
+ if (c->aligned_ptr == aligned_ptr)
+ break;
+
+ if (c == NULL)
+ /* An attempt to free untracked memory. A wrong pointer was passed
+ to pagealign_free(). */
+ abort ();
+
+ /* Remove this entry from the list, save the return value, and free it. */
+ *p_next = c->next;
+ ret = c->info;
+ free (c);
+
+ return ret;
+}
+
+#endif /* HAVE_MMAP || !HAVE_POSIX_MEMALIGN */
+
+
+void *
+pagealign_alloc (size_t size)
+{
+ void *ret;
+#if HAVE_MMAP
+# ifdef HAVE_MAP_ANONYMOUS
+ const int fd = -1;
+ const int flags = MAP_ANONYMOUS | MAP_PRIVATE;
+# else /* !HAVE_MAP_ANONYMOUS */
+ static int fd = -1; /* Only open /dev/zero once in order to avoid limiting
+ the amount of memory we may allocate based on the
+ number of open file descriptors. */
+ const int flags = MAP_FILE | MAP_PRIVATE;
+ if (fd == -1)
+ {
+ fd = open ("/dev/zero", O_RDONLY, 0666);
+ if (fd < 0)
+ error (EXIT_FAILURE, errno, _("Failed to open /dev/zero for read"));
+ }
+# endif /* HAVE_MAP_ANONYMOUS */
+ ret = mmap (NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
+ if (ret == MAP_FAILED)
+ return NULL;
+ new_memnode (ret, size);
+#elif HAVE_POSIX_MEMALIGN
+ int status = posix_memalign (&ret, getpagesize (), size);
+ if (status)
+ {
+ errno = status;
+ return NULL;
+ }
+#else /* !HAVE_MMAP && !HAVE_POSIX_MEMALIGN */
+ size_t pagesize = getpagesize ();
+ void *unaligned_ptr = malloc (size + pagesize - 1);
+ if (unaligned_ptr == NULL)
+ {
+ /* Set errno. We don't know whether malloc already set errno: some
+ implementations of malloc do, some don't. */
+ errno = ENOMEM;
+ return NULL;
+ }
+ ret = (char *) unaligned_ptr
+ + ((- (unsigned long) unaligned_ptr) & (pagesize - 1));
+ new_memnode (ret, unaligned_ptr);
+#endif /* HAVE_MMAP && HAVE_POSIX_MEMALIGN */
+ return ret;
+}
+
+
+void *
+pagealign_xalloc (size_t size)
+{
+ void *ret;
+
+ ret = pagealign_alloc (size);
+ if (ret == NULL)
+ xalloc_die ();
+ return ret;
+}
+
+
+void
+pagealign_free (void *aligned_ptr)
+{
+#if HAVE_MMAP
+ if (munmap (aligned_ptr, get_memnode (aligned_ptr)) < 0)
+ error (EXIT_FAILURE, errno, "Failed to unmap memory");
+#elif HAVE_POSIX_MEMALIGN
+ free (aligned_ptr);
+#else
+ free (get_memnode (aligned_ptr));
+#endif
+}
diff --git a/lib/pagealign_alloc.h b/lib/pagealign_alloc.h
new file mode 100644
index 0000000..abad1aa
--- /dev/null
+++ b/lib/pagealign_alloc.h
@@ -0,0 +1,42 @@
+/* Memory allocation aligned to system page boundaries.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _PAGEALIGN_ALLOC_H
+# define _PAGEALIGN_ALLOC_H
+
+# include <stddef.h>
+
+/* Allocate a block of memory of SIZE bytes, aligned on a system page
+ boundary.
+ If SIZE is not a multiple of the system page size, it will be rounded up
+ to the next multiple.
+ Return a pointer to the start of the memory block. Upon allocation failure,
+ return NULL and set errno. */
+extern void *pagealign_alloc (size_t size);
+
+/* Like pagealign_alloc, except it exits the program if the allocation
+ fails. */
+extern void *pagealign_xalloc (size_t size);
+
+/* Free a memory block.
+ PTR must be a non-NULL pointer returned by pagealign_alloc or
+ pagealign_xalloc. */
+extern void pagealign_free (void *ptr);
+
+#endif /* _PAGEALIGN_ALLOC_H */
diff --git a/lib/pathmax.h b/lib/pathmax.h
new file mode 100644
index 0000000..613c56c
--- /dev/null
+++ b/lib/pathmax.h
@@ -0,0 +1,49 @@
+/* Define PATH_MAX somehow. Requires sys/types.h.
+ Copyright (C) 1992, 1999, 2001, 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _PATHMAX_H
+# define _PATHMAX_H
+
+# if HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+
+# include <limits.h>
+
+# ifndef _POSIX_PATH_MAX
+# define _POSIX_PATH_MAX 256
+# endif
+
+# if !defined PATH_MAX && defined _PC_PATH_MAX
+# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 \
+ : pathconf ("/", _PC_PATH_MAX))
+# endif
+
+/* Don't include sys/param.h if it already has been. */
+# if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
+# include <sys/param.h>
+# endif
+
+# if !defined PATH_MAX && defined MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# endif
+
+# ifndef PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# endif
+
+#endif /* _PATHMAX_H */
diff --git a/lib/pipe-safer.c b/lib/pipe-safer.c
new file mode 100644
index 0000000..fb02d72
--- /dev/null
+++ b/lib/pipe-safer.c
@@ -0,0 +1,50 @@
+/* Invoke pipe, but avoid some glitches.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unistd-safer.h"
+
+#include <unistd.h>
+
+/* Like pipe, but ensure that neither of the file descriptors is
+ STDIN_FILENO, STDOUT_FILENO, or STDERR_FILENO. */
+
+int
+pipe_safer (int fd[2])
+{
+ int fail = pipe (fd);
+ if (fail)
+ return fail;
+
+ {
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ int f = fd_safer (fd[i]);
+ if (f < 0)
+ return -1;
+ fd[i] = f;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/printf-args.c b/lib/printf-args.c
new file mode 100644
index 0000000..0ed1acb
--- /dev/null
+++ b/lib/printf-args.c
@@ -0,0 +1,118 @@
+/* Decomposed printf argument list.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "printf-args.h"
+
+#ifdef STATIC
+STATIC
+#endif
+int
+printf_fetchargs (va_list args, arguments *a)
+{
+ size_t i;
+ argument *ap;
+
+ for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
+ switch (ap->type)
+ {
+ case TYPE_SCHAR:
+ ap->a.a_schar = va_arg (args, /*signed char*/ int);
+ break;
+ case TYPE_UCHAR:
+ ap->a.a_uchar = va_arg (args, /*unsigned char*/ int);
+ break;
+ case TYPE_SHORT:
+ ap->a.a_short = va_arg (args, /*short*/ int);
+ break;
+ case TYPE_USHORT:
+ ap->a.a_ushort = va_arg (args, /*unsigned short*/ int);
+ break;
+ case TYPE_INT:
+ ap->a.a_int = va_arg (args, int);
+ break;
+ case TYPE_UINT:
+ ap->a.a_uint = va_arg (args, unsigned int);
+ break;
+ case TYPE_LONGINT:
+ ap->a.a_longint = va_arg (args, long int);
+ break;
+ case TYPE_ULONGINT:
+ ap->a.a_ulongint = va_arg (args, unsigned long int);
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_LONGLONGINT:
+ ap->a.a_longlongint = va_arg (args, long long int);
+ break;
+ case TYPE_ULONGLONGINT:
+ ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
+ break;
+#endif
+ case TYPE_DOUBLE:
+ ap->a.a_double = va_arg (args, double);
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ ap->a.a_longdouble = va_arg (args, long double);
+ break;
+#endif
+ case TYPE_CHAR:
+ ap->a.a_char = va_arg (args, int);
+ break;
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+ ap->a.a_wide_char = va_arg (args, wint_t);
+ break;
+#endif
+ case TYPE_STRING:
+ ap->a.a_string = va_arg (args, const char *);
+ break;
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+ ap->a.a_wide_string = va_arg (args, const wchar_t *);
+ break;
+#endif
+ case TYPE_POINTER:
+ ap->a.a_pointer = va_arg (args, void *);
+ break;
+ case TYPE_COUNT_SCHAR_POINTER:
+ ap->a.a_count_schar_pointer = va_arg (args, signed char *);
+ break;
+ case TYPE_COUNT_SHORT_POINTER:
+ ap->a.a_count_short_pointer = va_arg (args, short *);
+ break;
+ case TYPE_COUNT_INT_POINTER:
+ ap->a.a_count_int_pointer = va_arg (args, int *);
+ break;
+ case TYPE_COUNT_LONGINT_POINTER:
+ ap->a.a_count_longint_pointer = va_arg (args, long int *);
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_COUNT_LONGLONGINT_POINTER:
+ ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
+ break;
+#endif
+ default:
+ /* Unknown type. */
+ return -1;
+ }
+ return 0;
+}
diff --git a/lib/printf-args.h b/lib/printf-args.h
new file mode 100644
index 0000000..cec1cc6
--- /dev/null
+++ b/lib/printf-args.h
@@ -0,0 +1,136 @@
+/* Decomposed printf argument list.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _PRINTF_ARGS_H
+#define _PRINTF_ARGS_H
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get wchar_t. */
+#ifdef HAVE_WCHAR_T
+# include <stddef.h>
+#endif
+
+/* Get wint_t. */
+#ifdef HAVE_WINT_T
+# include <wchar.h>
+#endif
+
+/* Get va_list. */
+#include <stdarg.h>
+
+
+/* Argument types */
+typedef enum
+{
+ TYPE_NONE,
+ TYPE_SCHAR,
+ TYPE_UCHAR,
+ TYPE_SHORT,
+ TYPE_USHORT,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_LONGINT,
+ TYPE_ULONGINT,
+#ifdef HAVE_LONG_LONG
+ TYPE_LONGLONGINT,
+ TYPE_ULONGLONGINT,
+#endif
+ TYPE_DOUBLE,
+#ifdef HAVE_LONG_DOUBLE
+ TYPE_LONGDOUBLE,
+#endif
+ TYPE_CHAR,
+#ifdef HAVE_WINT_T
+ TYPE_WIDE_CHAR,
+#endif
+ TYPE_STRING,
+#ifdef HAVE_WCHAR_T
+ TYPE_WIDE_STRING,
+#endif
+ TYPE_POINTER,
+ TYPE_COUNT_SCHAR_POINTER,
+ TYPE_COUNT_SHORT_POINTER,
+ TYPE_COUNT_INT_POINTER,
+ TYPE_COUNT_LONGINT_POINTER
+#ifdef HAVE_LONG_LONG
+, TYPE_COUNT_LONGLONGINT_POINTER
+#endif
+} arg_type;
+
+/* Polymorphic argument */
+typedef struct
+{
+ arg_type type;
+ union
+ {
+ signed char a_schar;
+ unsigned char a_uchar;
+ short a_short;
+ unsigned short a_ushort;
+ int a_int;
+ unsigned int a_uint;
+ long int a_longint;
+ unsigned long int a_ulongint;
+#ifdef HAVE_LONG_LONG
+ long long int a_longlongint;
+ unsigned long long int a_ulonglongint;
+#endif
+ float a_float;
+ double a_double;
+#ifdef HAVE_LONG_DOUBLE
+ long double a_longdouble;
+#endif
+ int a_char;
+#ifdef HAVE_WINT_T
+ wint_t a_wide_char;
+#endif
+ const char* a_string;
+#ifdef HAVE_WCHAR_T
+ const wchar_t* a_wide_string;
+#endif
+ void* a_pointer;
+ signed char * a_count_schar_pointer;
+ short * a_count_short_pointer;
+ int * a_count_int_pointer;
+ long int * a_count_longint_pointer;
+#ifdef HAVE_LONG_LONG
+ long long int * a_count_longlongint_pointer;
+#endif
+ }
+ a;
+}
+argument;
+
+typedef struct
+{
+ size_t count;
+ argument *arg;
+}
+arguments;
+
+
+/* Fetch the arguments, putting them into a. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_fetchargs (va_list args, arguments *a);
+
+#endif /* _PRINTF_ARGS_H */
diff --git a/lib/printf-parse.c b/lib/printf-parse.c
new file mode 100644
index 0000000..3d2fb17
--- /dev/null
+++ b/lib/printf-parse.c
@@ -0,0 +1,536 @@
+/* Formatted output to strings.
+ Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#if WIDE_CHAR_VERSION
+# include "wprintf-parse.h"
+#else
+# include "printf-parse.h"
+#endif
+
+/* Get size_t, NULL. */
+#include <stddef.h>
+
+/* Get intmax_t. */
+#if HAVE_STDINT_H_WITH_UINTMAX
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+# include <inttypes.h>
+#endif
+
+/* malloc(), realloc(), free(). */
+#include <stdlib.h>
+
+/* Checked size_t computations. */
+#include "xsize.h"
+
+#if WIDE_CHAR_VERSION
+# define PRINTF_PARSE wprintf_parse
+# define CHAR_T wchar_t
+# define DIRECTIVE wchar_t_directive
+# define DIRECTIVES wchar_t_directives
+#else
+# define PRINTF_PARSE printf_parse
+# define CHAR_T char
+# define DIRECTIVE char_directive
+# define DIRECTIVES char_directives
+#endif
+
+#ifdef STATIC
+STATIC
+#endif
+int
+PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
+{
+ const CHAR_T *cp = format; /* pointer into format */
+ size_t arg_posn = 0; /* number of regular arguments consumed */
+ size_t d_allocated; /* allocated elements of d->dir */
+ size_t a_allocated; /* allocated elements of a->arg */
+ size_t max_width_length = 0;
+ size_t max_precision_length = 0;
+
+ d->count = 0;
+ d_allocated = 1;
+ d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
+ if (d->dir == NULL)
+ /* Out of memory. */
+ return -1;
+
+ a->count = 0;
+ a_allocated = 0;
+ a->arg = NULL;
+
+#define REGISTER_ARG(_index_,_type_) \
+ { \
+ size_t n = (_index_); \
+ if (n >= a_allocated) \
+ { \
+ size_t memory_size; \
+ argument *memory; \
+ \
+ a_allocated = xtimes (a_allocated, 2); \
+ if (a_allocated <= n) \
+ a_allocated = xsum (n, 1); \
+ memory_size = xtimes (a_allocated, sizeof (argument)); \
+ if (size_overflow_p (memory_size)) \
+ /* Overflow, would lead to out of memory. */ \
+ goto error; \
+ memory = (a->arg \
+ ? realloc (a->arg, memory_size) \
+ : malloc (memory_size)); \
+ if (memory == NULL) \
+ /* Out of memory. */ \
+ goto error; \
+ a->arg = memory; \
+ } \
+ while (a->count <= n) \
+ a->arg[a->count++].type = TYPE_NONE; \
+ if (a->arg[n].type == TYPE_NONE) \
+ a->arg[n].type = (_type_); \
+ else if (a->arg[n].type != (_type_)) \
+ /* Ambiguous type for positional argument. */ \
+ goto error; \
+ }
+
+ while (*cp != '\0')
+ {
+ CHAR_T c = *cp++;
+ if (c == '%')
+ {
+ size_t arg_index = ARG_NONE;
+ DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
+
+ /* Initialize the next directive. */
+ dp->dir_start = cp - 1;
+ dp->flags = 0;
+ dp->width_start = NULL;
+ dp->width_end = NULL;
+ dp->width_arg_index = ARG_NONE;
+ dp->precision_start = NULL;
+ dp->precision_end = NULL;
+ dp->precision_arg_index = ARG_NONE;
+ dp->arg_index = ARG_NONE;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory later. */
+ goto error;
+ arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+
+ /* Read the flags. */
+ for (;;)
+ {
+ if (*cp == '\'')
+ {
+ dp->flags |= FLAG_GROUP;
+ cp++;
+ }
+ else if (*cp == '-')
+ {
+ dp->flags |= FLAG_LEFT;
+ cp++;
+ }
+ else if (*cp == '+')
+ {
+ dp->flags |= FLAG_SHOWSIGN;
+ cp++;
+ }
+ else if (*cp == ' ')
+ {
+ dp->flags |= FLAG_SPACE;
+ cp++;
+ }
+ else if (*cp == '#')
+ {
+ dp->flags |= FLAG_ALT;
+ cp++;
+ }
+ else if (*cp == '0')
+ {
+ dp->flags |= FLAG_ZERO;
+ cp++;
+ }
+ else
+ break;
+ }
+
+ /* Parse the field width. */
+ if (*cp == '*')
+ {
+ dp->width_start = cp;
+ cp++;
+ dp->width_end = cp;
+ if (max_width_length < 1)
+ max_width_length = 1;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory later. */
+ goto error;
+ dp->width_arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+ if (dp->width_arg_index == ARG_NONE)
+ {
+ dp->width_arg_index = arg_posn++;
+ if (dp->width_arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->width_arg_index, TYPE_INT);
+ }
+ else if (*cp >= '0' && *cp <= '9')
+ {
+ size_t width_length;
+
+ dp->width_start = cp;
+ for (; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+ dp->width_end = cp;
+ width_length = dp->width_end - dp->width_start;
+ if (max_width_length < width_length)
+ max_width_length = width_length;
+ }
+
+ /* Parse the precision. */
+ if (*cp == '.')
+ {
+ cp++;
+ if (*cp == '*')
+ {
+ dp->precision_start = cp - 1;
+ cp++;
+ dp->precision_end = cp;
+ if (max_precision_length < 2)
+ max_precision_length = 2;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory
+ later. */
+ goto error;
+ dp->precision_arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+ if (dp->precision_arg_index == ARG_NONE)
+ {
+ dp->precision_arg_index = arg_posn++;
+ if (dp->precision_arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
+ }
+ else
+ {
+ size_t precision_length;
+
+ dp->precision_start = cp - 1;
+ for (; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+ dp->precision_end = cp;
+ precision_length = dp->precision_end - dp->precision_start;
+ if (max_precision_length < precision_length)
+ max_precision_length = precision_length;
+ }
+ }
+
+ {
+ arg_type type;
+
+ /* Parse argument type/size specifiers. */
+ {
+ int flags = 0;
+
+ for (;;)
+ {
+ if (*cp == 'h')
+ {
+ flags |= (1 << (flags & 1));
+ cp++;
+ }
+ else if (*cp == 'L')
+ {
+ flags |= 4;
+ cp++;
+ }
+ else if (*cp == 'l')
+ {
+ flags += 8;
+ cp++;
+ }
+#ifdef HAVE_INTMAX_T
+ else if (*cp == 'j')
+ {
+ if (sizeof (intmax_t) > sizeof (long))
+ {
+ /* intmax_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (intmax_t) > sizeof (int))
+ {
+ /* intmax_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+#endif
+ else if (*cp == 'z' || *cp == 'Z')
+ {
+ /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
+ because the warning facility in gcc-2.95.2 understands
+ only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
+ if (sizeof (size_t) > sizeof (long))
+ {
+ /* size_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (size_t) > sizeof (int))
+ {
+ /* size_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+ else if (*cp == 't')
+ {
+ if (sizeof (ptrdiff_t) > sizeof (long))
+ {
+ /* ptrdiff_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (ptrdiff_t) > sizeof (int))
+ {
+ /* ptrdiff_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+ else
+ break;
+ }
+
+ /* Read the conversion character. */
+ c = *cp++;
+ switch (c)
+ {
+ case 'd': case 'i':
+#ifdef HAVE_LONG_LONG
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_LONGLONGINT;
+ else
+#endif
+ if (flags >= 8)
+ type = TYPE_LONGINT;
+ else if (flags & 2)
+ type = TYPE_SCHAR;
+ else if (flags & 1)
+ type = TYPE_SHORT;
+ else
+ type = TYPE_INT;
+ break;
+ case 'o': case 'u': case 'x': case 'X':
+#ifdef HAVE_LONG_LONG
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_ULONGLONGINT;
+ else
+#endif
+ if (flags >= 8)
+ type = TYPE_ULONGINT;
+ else if (flags & 2)
+ type = TYPE_UCHAR;
+ else if (flags & 1)
+ type = TYPE_USHORT;
+ else
+ type = TYPE_UINT;
+ break;
+ case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+ case 'a': case 'A':
+#ifdef HAVE_LONG_DOUBLE
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_LONGDOUBLE;
+ else
+#endif
+ type = TYPE_DOUBLE;
+ break;
+ case 'c':
+ if (flags >= 8)
+#ifdef HAVE_WINT_T
+ type = TYPE_WIDE_CHAR;
+#else
+ goto error;
+#endif
+ else
+ type = TYPE_CHAR;
+ break;
+#ifdef HAVE_WINT_T
+ case 'C':
+ type = TYPE_WIDE_CHAR;
+ c = 'c';
+ break;
+#endif
+ case 's':
+ if (flags >= 8)
+#ifdef HAVE_WCHAR_T
+ type = TYPE_WIDE_STRING;
+#else
+ goto error;
+#endif
+ else
+ type = TYPE_STRING;
+ break;
+#ifdef HAVE_WCHAR_T
+ case 'S':
+ type = TYPE_WIDE_STRING;
+ c = 's';
+ break;
+#endif
+ case 'p':
+ type = TYPE_POINTER;
+ break;
+ case 'n':
+#ifdef HAVE_LONG_LONG
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_COUNT_LONGLONGINT_POINTER;
+ else
+#endif
+ if (flags >= 8)
+ type = TYPE_COUNT_LONGINT_POINTER;
+ else if (flags & 2)
+ type = TYPE_COUNT_SCHAR_POINTER;
+ else if (flags & 1)
+ type = TYPE_COUNT_SHORT_POINTER;
+ else
+ type = TYPE_COUNT_INT_POINTER;
+ break;
+ case '%':
+ type = TYPE_NONE;
+ break;
+ default:
+ /* Unknown conversion character. */
+ goto error;
+ }
+ }
+
+ if (type != TYPE_NONE)
+ {
+ dp->arg_index = arg_index;
+ if (dp->arg_index == ARG_NONE)
+ {
+ dp->arg_index = arg_posn++;
+ if (dp->arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->arg_index, type);
+ }
+ dp->conversion = c;
+ dp->dir_end = cp;
+ }
+
+ d->count++;
+ if (d->count >= d_allocated)
+ {
+ size_t memory_size;
+ DIRECTIVE *memory;
+
+ d_allocated = xtimes (d_allocated, 2);
+ memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
+ if (size_overflow_p (memory_size))
+ /* Overflow, would lead to out of memory. */
+ goto error;
+ memory = realloc (d->dir, memory_size);
+ if (memory == NULL)
+ /* Out of memory. */
+ goto error;
+ d->dir = memory;
+ }
+ }
+ }
+ d->dir[d->count].dir_start = cp;
+
+ d->max_width_length = max_width_length;
+ d->max_precision_length = max_precision_length;
+ return 0;
+
+error:
+ if (a->arg)
+ free (a->arg);
+ if (d->dir)
+ free (d->dir);
+ return -1;
+}
+
+#undef DIRECTIVES
+#undef DIRECTIVE
+#undef CHAR_T
+#undef PRINTF_PARSE
diff --git a/lib/printf-parse.h b/lib/printf-parse.h
new file mode 100644
index 0000000..82a0d37
--- /dev/null
+++ b/lib/printf-parse.h
@@ -0,0 +1,74 @@
+/* Parse printf format string.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _PRINTF_PARSE_H
+#define _PRINTF_PARSE_H
+
+#include "printf-args.h"
+
+
+/* Flags */
+#define FLAG_GROUP 1 /* ' flag */
+#define FLAG_LEFT 2 /* - flag */
+#define FLAG_SHOWSIGN 4 /* + flag */
+#define FLAG_SPACE 8 /* space flag */
+#define FLAG_ALT 16 /* # flag */
+#define FLAG_ZERO 32
+
+/* arg_index value indicating that no argument is consumed. */
+#define ARG_NONE (~(size_t)0)
+
+/* A parsed directive. */
+typedef struct
+{
+ const char* dir_start;
+ const char* dir_end;
+ int flags;
+ const char* width_start;
+ const char* width_end;
+ size_t width_arg_index;
+ const char* precision_start;
+ const char* precision_end;
+ size_t precision_arg_index;
+ char conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+ size_t arg_index;
+}
+char_directive;
+
+/* A parsed format string. */
+typedef struct
+{
+ size_t count;
+ char_directive *dir;
+ size_t max_width_length;
+ size_t max_precision_length;
+}
+char_directives;
+
+
+/* Parses the format string. Fills in the number N of directives, and fills
+ in directives[0], ..., directives[N-1], and sets directives[N].dir_start
+ to the end of the format string. Also fills in the arg_type fields of the
+ arguments and the needed count of arguments. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_parse (const char *format, char_directives *d, arguments *a);
+
+#endif /* _PRINTF_PARSE_H */
diff --git a/lib/progname.c b/lib/progname.c
new file mode 100644
index 0000000..9f1be28
--- /dev/null
+++ b/lib/progname.c
@@ -0,0 +1,24 @@
+/* Declare program_name for support functions compiled with the getdate.y test
+ program.
+
+ Copyright (C) 1990-1998, 2000-2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Derek R. Price <derek@ximbiot.com>. */
+
+/* This gets set to the name of the executing program. */
+char *program_name = "getdate";
diff --git a/lib/quotearg.c b/lib/quotearg.c
new file mode 100644
index 0000000..13bd16f
--- /dev/null
+++ b/lib/quotearg.c
@@ -0,0 +1,679 @@
+/* quotearg.c - quote arguments for output
+
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "quotearg.h"
+
+#include "xalloc.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+#if HAVE_WCHAR_H
+
+/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared. */
+# include <stdio.h>
+# include <time.h>
+
+# include <wchar.h>
+#endif
+
+#if !HAVE_MBRTOWC
+/* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the
+ other macros are defined only for documentation and to satisfy C
+ syntax. */
+# undef MB_CUR_MAX
+# define MB_CUR_MAX 1
+# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
+# define iswprint(wc) isprint ((unsigned char) (wc))
+# undef HAVE_MBSINIT
+#endif
+
+#if !defined mbsinit && !HAVE_MBSINIT
+# define mbsinit(ps) 1
+#endif
+
+#ifndef iswprint
+# if HAVE_WCTYPE_H
+# include <wctype.h>
+# endif
+# if !defined iswprint && !HAVE_ISWPRINT
+# define iswprint(wc) 1
+# endif
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+#define INT_BITS (sizeof (int) * CHAR_BIT)
+
+struct quoting_options
+{
+ /* Basic quoting style. */
+ enum quoting_style style;
+
+ /* Quote the characters indicated by this bit vector even if the
+ quoting style would not normally require them to be quoted. */
+ unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
+};
+
+/* Names of quoting styles. */
+char const *const quoting_style_args[] =
+{
+ "literal",
+ "shell",
+ "shell-always",
+ "c",
+ "escape",
+ "locale",
+ "clocale",
+ 0
+};
+
+/* Correspondences to quoting style names. */
+enum quoting_style const quoting_style_vals[] =
+{
+ literal_quoting_style,
+ shell_quoting_style,
+ shell_always_quoting_style,
+ c_quoting_style,
+ escape_quoting_style,
+ locale_quoting_style,
+ clocale_quoting_style
+};
+
+/* The default quoting options. */
+static struct quoting_options default_quoting_options;
+
+/* Allocate a new set of quoting options, with contents initially identical
+ to O if O is not null, or to the default if O is null.
+ It is the caller's responsibility to free the result. */
+struct quoting_options *
+clone_quoting_options (struct quoting_options *o)
+{
+ int e = errno;
+ struct quoting_options *p = xmalloc (sizeof *p);
+ *p = *(o ? o : &default_quoting_options);
+ errno = e;
+ return p;
+}
+
+/* Get the value of O's quoting style. If O is null, use the default. */
+enum quoting_style
+get_quoting_style (struct quoting_options *o)
+{
+ return (o ? o : &default_quoting_options)->style;
+}
+
+/* In O (or in the default if O is null),
+ set the value of the quoting style to S. */
+void
+set_quoting_style (struct quoting_options *o, enum quoting_style s)
+{
+ (o ? o : &default_quoting_options)->style = s;
+}
+
+/* In O (or in the default if O is null),
+ set the value of the quoting options for character C to I.
+ Return the old value. Currently, the only values defined for I are
+ 0 (the default) and 1 (which means to quote the character even if
+ it would not otherwise be quoted). */
+int
+set_char_quoting (struct quoting_options *o, char c, int i)
+{
+ unsigned char uc = c;
+ unsigned int *p =
+ (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
+ int shift = uc % INT_BITS;
+ int r = (*p >> shift) & 1;
+ *p ^= ((i & 1) ^ r) << shift;
+ return r;
+}
+
+/* MSGID approximates a quotation mark. Return its translation if it
+ has one; otherwise, return either it or "\"", depending on S. */
+static char const *
+gettext_quote (char const *msgid, enum quoting_style s)
+{
+ char const *translation = _(msgid);
+ if (translation == msgid && s == clocale_quoting_style)
+ translation = "\"";
+ return translation;
+}
+
+/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
+ argument ARG (of size ARGSIZE), using QUOTING_STYLE and the
+ non-quoting-style part of O to control quoting.
+ Terminate the output with a null character, and return the written
+ size of the output, not counting the terminating null.
+ If BUFFERSIZE is too small to store the output string, return the
+ value that would have been returned had BUFFERSIZE been large enough.
+ If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE.
+
+ This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
+ ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting
+ style specified by O, and O may not be null. */
+
+static size_t
+quotearg_buffer_restyled (char *buffer, size_t buffersize,
+ char const *arg, size_t argsize,
+ enum quoting_style quoting_style,
+ struct quoting_options const *o)
+{
+ size_t i;
+ size_t len = 0;
+ char const *quote_string = 0;
+ size_t quote_string_len = 0;
+ bool backslash_escapes = false;
+ bool unibyte_locale = MB_CUR_MAX == 1;
+
+#define STORE(c) \
+ do \
+ { \
+ if (len < buffersize) \
+ buffer[len] = (c); \
+ len++; \
+ } \
+ while (0)
+
+ switch (quoting_style)
+ {
+ case c_quoting_style:
+ STORE ('"');
+ backslash_escapes = true;
+ quote_string = "\"";
+ quote_string_len = 1;
+ break;
+
+ case escape_quoting_style:
+ backslash_escapes = true;
+ break;
+
+ case locale_quoting_style:
+ case clocale_quoting_style:
+ {
+ /* TRANSLATORS:
+ Get translations for open and closing quotation marks.
+
+ The message catalog should translate "`" to a left
+ quotation mark suitable for the locale, and similarly for
+ "'". If the catalog has no translation,
+ locale_quoting_style quotes `like this', and
+ clocale_quoting_style quotes "like this".
+
+ For example, an American English Unicode locale should
+ translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
+ should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
+ MARK). A British English Unicode locale should instead
+ translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
+ U+2019 (RIGHT SINGLE QUOTATION MARK), respectively.
+
+ If you don't know what to put here, please see
+ <http://en.wikipedia.org/wiki/Quotation_mark#Glyphs>
+ and use glyphs suitable for your language. */
+
+ char const *left = gettext_quote (N_("`"), quoting_style);
+ char const *right = gettext_quote (N_("'"), quoting_style);
+ for (quote_string = left; *quote_string; quote_string++)
+ STORE (*quote_string);
+ backslash_escapes = true;
+ quote_string = right;
+ quote_string_len = strlen (quote_string);
+ }
+ break;
+
+ case shell_always_quoting_style:
+ STORE ('\'');
+ quote_string = "'";
+ quote_string_len = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ for (i = 0; ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize); i++)
+ {
+ unsigned char c;
+ unsigned char esc;
+
+ if (backslash_escapes
+ && quote_string_len
+ && i + quote_string_len <= argsize
+ && memcmp (arg + i, quote_string, quote_string_len) == 0)
+ STORE ('\\');
+
+ c = arg[i];
+ switch (c)
+ {
+ case '\0':
+ if (backslash_escapes)
+ {
+ STORE ('\\');
+ STORE ('0');
+ STORE ('0');
+ c = '0';
+ }
+ break;
+
+ case '?':
+ switch (quoting_style)
+ {
+ case shell_quoting_style:
+ goto use_shell_always_quoting_style;
+
+ case c_quoting_style:
+ if (i + 2 < argsize && arg[i + 1] == '?')
+ switch (arg[i + 2])
+ {
+ case '!': case '\'':
+ case '(': case ')': case '-': case '/':
+ case '<': case '=': case '>':
+ /* Escape the second '?' in what would otherwise be
+ a trigraph. */
+ c = arg[i + 2];
+ i += 2;
+ STORE ('?');
+ STORE ('\\');
+ STORE ('?');
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case '\a': esc = 'a'; goto c_escape;
+ case '\b': esc = 'b'; goto c_escape;
+ case '\f': esc = 'f'; goto c_escape;
+ case '\n': esc = 'n'; goto c_and_shell_escape;
+ case '\r': esc = 'r'; goto c_and_shell_escape;
+ case '\t': esc = 't'; goto c_and_shell_escape;
+ case '\v': esc = 'v'; goto c_escape;
+ case '\\': esc = c; goto c_and_shell_escape;
+
+ c_and_shell_escape:
+ if (quoting_style == shell_quoting_style)
+ goto use_shell_always_quoting_style;
+ c_escape:
+ if (backslash_escapes)
+ {
+ c = esc;
+ goto store_escape;
+ }
+ break;
+
+ case '{': case '}': /* sometimes special if isolated */
+ if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1))
+ break;
+ /* Fall through. */
+ case '#': case '~':
+ if (i != 0)
+ break;
+ /* Fall through. */
+ case ' ':
+ case '!': /* special in bash */
+ case '"': case '$': case '&':
+ case '(': case ')': case '*': case ';':
+ case '<':
+ case '=': /* sometimes special in 0th or (with "set -k") later args */
+ case '>': case '[':
+ case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
+ case '`': case '|':
+ /* A shell special character. In theory, '$' and '`' could
+ be the first bytes of multibyte characters, which means
+ we should check them with mbrtowc, but in practice this
+ doesn't happen so it's not worth worrying about. */
+ if (quoting_style == shell_quoting_style)
+ goto use_shell_always_quoting_style;
+ break;
+
+ case '\'':
+ switch (quoting_style)
+ {
+ case shell_quoting_style:
+ goto use_shell_always_quoting_style;
+
+ case shell_always_quoting_style:
+ STORE ('\'');
+ STORE ('\\');
+ STORE ('\'');
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case '%': case '+': case ',': case '-': case '.': case '/':
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case ':':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
+ case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
+ case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+ case 'o': case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+ /* These characters don't cause problems, no matter what the
+ quoting style is. They cannot start multibyte sequences. */
+ break;
+
+ default:
+ /* If we have a multibyte sequence, copy it until we reach
+ its end, find an error, or come back to the initial shift
+ state. For C-like styles, if the sequence has
+ unprintable characters, escape the whole sequence, since
+ we can't easily escape single characters within it. */
+ {
+ /* Length of multibyte sequence found so far. */
+ size_t m;
+
+ bool printable;
+
+ if (unibyte_locale)
+ {
+ m = 1;
+ printable = isprint (c) != 0;
+ }
+ else
+ {
+ mbstate_t mbstate;
+ memset (&mbstate, 0, sizeof mbstate);
+
+ m = 0;
+ printable = true;
+ if (argsize == SIZE_MAX)
+ argsize = strlen (arg);
+
+ do
+ {
+ wchar_t w;
+ size_t bytes = mbrtowc (&w, &arg[i + m],
+ argsize - (i + m), &mbstate);
+ if (bytes == 0)
+ break;
+ else if (bytes == (size_t) -1)
+ {
+ printable = false;
+ break;
+ }
+ else if (bytes == (size_t) -2)
+ {
+ printable = false;
+ while (i + m < argsize && arg[i + m])
+ m++;
+ break;
+ }
+ else
+ {
+ /* Work around a bug with older shells that "see" a '\'
+ that is really the 2nd byte of a multibyte character.
+ In practice the problem is limited to ASCII
+ chars >= '@' that are shell special chars. */
+ if ('[' == 0x5b && quoting_style == shell_quoting_style)
+ {
+ size_t j;
+ for (j = 1; j < bytes; j++)
+ switch (arg[i + m + j])
+ {
+ case '[': case '\\': case '^':
+ case '`': case '|':
+ goto use_shell_always_quoting_style;
+ }
+ }
+
+ if (! iswprint (w))
+ printable = false;
+ m += bytes;
+ }
+ }
+ while (! mbsinit (&mbstate));
+ }
+
+ if (1 < m || (backslash_escapes && ! printable))
+ {
+ /* Output a multibyte sequence, or an escaped
+ unprintable unibyte character. */
+ size_t ilim = i + m;
+
+ for (;;)
+ {
+ if (backslash_escapes && ! printable)
+ {
+ STORE ('\\');
+ STORE ('0' + (c >> 6));
+ STORE ('0' + ((c >> 3) & 7));
+ c = '0' + (c & 7);
+ }
+ if (ilim <= i + 1)
+ break;
+ STORE (c);
+ c = arg[++i];
+ }
+
+ goto store_c;
+ }
+ }
+ }
+
+ if (! (backslash_escapes
+ && o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
+ goto store_c;
+
+ store_escape:
+ STORE ('\\');
+
+ store_c:
+ STORE (c);
+ }
+
+ if (i == 0 && quoting_style == shell_quoting_style)
+ goto use_shell_always_quoting_style;
+
+ if (quote_string)
+ for (; *quote_string; quote_string++)
+ STORE (*quote_string);
+
+ if (len < buffersize)
+ buffer[len] = '\0';
+ return len;
+
+ use_shell_always_quoting_style:
+ return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
+ shell_always_quoting_style, o);
+}
+
+/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
+ argument ARG (of size ARGSIZE), using O to control quoting.
+ If O is null, use the default.
+ Terminate the output with a null character, and return the written
+ size of the output, not counting the terminating null.
+ If BUFFERSIZE is too small to store the output string, return the
+ value that would have been returned had BUFFERSIZE been large enough.
+ If ARGSIZE is SIZE_MAX, use the string length of the argument for
+ ARGSIZE. */
+size_t
+quotearg_buffer (char *buffer, size_t buffersize,
+ char const *arg, size_t argsize,
+ struct quoting_options const *o)
+{
+ struct quoting_options const *p = o ? o : &default_quoting_options;
+ int e = errno;
+ size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
+ p->style, p);
+ errno = e;
+ return r;
+}
+
+/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
+ allocated storage containing the quoted string. */
+char *
+quotearg_alloc (char const *arg, size_t argsize,
+ struct quoting_options const *o)
+{
+ int e = errno;
+ size_t bufsize = quotearg_buffer (0, 0, arg, argsize, o) + 1;
+ char *buf = xmalloc (bufsize);
+ quotearg_buffer (buf, bufsize, arg, argsize, o);
+ errno = e;
+ return buf;
+}
+
+/* Use storage slot N to return a quoted version of argument ARG.
+ ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a
+ null-terminated string.
+ OPTIONS specifies the quoting options.
+ The returned value points to static storage that can be
+ reused by the next call to this function with the same value of N.
+ N must be nonnegative. N is deliberately declared with type "int"
+ to allow for future extensions (using negative values). */
+static char *
+quotearg_n_options (int n, char const *arg, size_t argsize,
+ struct quoting_options const *options)
+{
+ int e = errno;
+
+ /* Preallocate a slot 0 buffer, so that the caller can always quote
+ one small component of a "memory exhausted" message in slot 0. */
+ static char slot0[256];
+ static unsigned int nslots = 1;
+ unsigned int n0 = n;
+ struct slotvec
+ {
+ size_t size;
+ char *val;
+ };
+ static struct slotvec slotvec0 = {sizeof slot0, slot0};
+ static struct slotvec *slotvec = &slotvec0;
+
+ if (n < 0)
+ abort ();
+
+ if (nslots <= n0)
+ {
+ unsigned int n1 = n0 + 1;
+
+ if (xalloc_oversized (n1, sizeof *slotvec))
+ xalloc_die ();
+
+ if (slotvec == &slotvec0)
+ {
+ slotvec = xmalloc (sizeof *slotvec);
+ *slotvec = slotvec0;
+ }
+ slotvec = xrealloc (slotvec, n1 * sizeof *slotvec);
+ memset (slotvec + nslots, 0, (n1 - nslots) * sizeof *slotvec);
+ nslots = n1;
+ }
+
+ {
+ size_t size = slotvec[n].size;
+ char *val = slotvec[n].val;
+ size_t qsize = quotearg_buffer (val, size, arg, argsize, options);
+
+ if (size <= qsize)
+ {
+ slotvec[n].size = size = qsize + 1;
+ if (val != slot0)
+ free (val);
+ slotvec[n].val = val = xmalloc (size);
+ quotearg_buffer (val, size, arg, argsize, options);
+ }
+
+ errno = e;
+ return val;
+ }
+}
+
+char *
+quotearg_n (int n, char const *arg)
+{
+ return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options);
+}
+
+char *
+quotearg (char const *arg)
+{
+ return quotearg_n (0, arg);
+}
+
+/* Return quoting options for STYLE, with no extra quoting. */
+static struct quoting_options
+quoting_options_from_style (enum quoting_style style)
+{
+ struct quoting_options o;
+ o.style = style;
+ memset (o.quote_these_too, 0, sizeof o.quote_these_too);
+ return o;
+}
+
+char *
+quotearg_n_style (int n, enum quoting_style s, char const *arg)
+{
+ struct quoting_options const o = quoting_options_from_style (s);
+ return quotearg_n_options (n, arg, SIZE_MAX, &o);
+}
+
+char *
+quotearg_n_style_mem (int n, enum quoting_style s,
+ char const *arg, size_t argsize)
+{
+ struct quoting_options const o = quoting_options_from_style (s);
+ return quotearg_n_options (n, arg, argsize, &o);
+}
+
+char *
+quotearg_style (enum quoting_style s, char const *arg)
+{
+ return quotearg_n_style (0, s, arg);
+}
+
+char *
+quotearg_char (char const *arg, char ch)
+{
+ struct quoting_options options;
+ options = default_quoting_options;
+ set_char_quoting (&options, ch, 1);
+ return quotearg_n_options (0, arg, SIZE_MAX, &options);
+}
+
+char *
+quotearg_colon (char const *arg)
+{
+ return quotearg_char (arg, ':');
+}
diff --git a/lib/quotearg.h b/lib/quotearg.h
new file mode 100644
index 0000000..24f26f7
--- /dev/null
+++ b/lib/quotearg.h
@@ -0,0 +1,137 @@
+/* quotearg.h - quote arguments for output
+
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#ifndef QUOTEARG_H_
+# define QUOTEARG_H_ 1
+
+# include <stddef.h>
+
+/* Basic quoting styles. */
+enum quoting_style
+ {
+ /* Output names as-is (ls --quoting-style=literal). */
+ literal_quoting_style,
+
+ /* Quote names for the shell if they contain shell metacharacters
+ or would cause ambiguous output (ls --quoting-style=shell). */
+ shell_quoting_style,
+
+ /* Quote names for the shell, even if they would normally not
+ require quoting (ls --quoting-style=shell-always). */
+ shell_always_quoting_style,
+
+ /* Quote names as for a C language string (ls --quoting-style=c). */
+ c_quoting_style,
+
+ /* Like c_quoting_style except omit the surrounding double-quote
+ characters (ls --quoting-style=escape). */
+ escape_quoting_style,
+
+ /* Like clocale_quoting_style, but quote `like this' instead of
+ "like this" in the default C locale (ls --quoting-style=locale). */
+ locale_quoting_style,
+
+ /* Like c_quoting_style except use quotation marks appropriate for
+ the locale (ls --quoting-style=clocale). */
+ clocale_quoting_style
+ };
+
+/* For now, --quoting-style=literal is the default, but this may change. */
+# ifndef DEFAULT_QUOTING_STYLE
+# define DEFAULT_QUOTING_STYLE literal_quoting_style
+# endif
+
+/* Names of quoting styles and their corresponding values. */
+extern char const *const quoting_style_args[];
+extern enum quoting_style const quoting_style_vals[];
+
+struct quoting_options;
+
+/* The functions listed below set and use a hidden variable
+ that contains the default quoting style options. */
+
+/* Allocate a new set of quoting options, with contents initially identical
+ to O if O is not null, or to the default if O is null.
+ It is the caller's responsibility to free the result. */
+struct quoting_options *clone_quoting_options (struct quoting_options *o);
+
+/* Get the value of O's quoting style. If O is null, use the default. */
+enum quoting_style get_quoting_style (struct quoting_options *o);
+
+/* In O (or in the default if O is null),
+ set the value of the quoting style to S. */
+void set_quoting_style (struct quoting_options *o, enum quoting_style s);
+
+/* In O (or in the default if O is null),
+ set the value of the quoting options for character C to I.
+ Return the old value. Currently, the only values defined for I are
+ 0 (the default) and 1 (which means to quote the character even if
+ it would not otherwise be quoted). */
+int set_char_quoting (struct quoting_options *o, char c, int i);
+
+/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
+ argument ARG (of size ARGSIZE), using O to control quoting.
+ If O is null, use the default.
+ Terminate the output with a null character, and return the written
+ size of the output, not counting the terminating null.
+ If BUFFERSIZE is too small to store the output string, return the
+ value that would have been returned had BUFFERSIZE been large enough.
+ If ARGSIZE is -1, use the string length of the argument for ARGSIZE. */
+size_t quotearg_buffer (char *buffer, size_t buffersize,
+ char const *arg, size_t argsize,
+ struct quoting_options const *o);
+
+/* Like quotearg_buffer, except return the result in a newly allocated
+ buffer. It is the caller's responsibility to free the result. */
+char *quotearg_alloc (char const *arg, size_t argsize,
+ struct quoting_options const *o);
+
+/* Use storage slot N to return a quoted version of the string ARG.
+ Use the default quoting options.
+ The returned value points to static storage that can be
+ reused by the next call to this function with the same value of N.
+ N must be nonnegative. */
+char *quotearg_n (int n, char const *arg);
+
+/* Equivalent to quotearg_n (0, ARG). */
+char *quotearg (char const *arg);
+
+/* Use style S and storage slot N to return a quoted version of the string ARG.
+ This is like quotearg_n (N, ARG), except that it uses S with no other
+ options to specify the quoting method. */
+char *quotearg_n_style (int n, enum quoting_style s, char const *arg);
+
+/* Use style S and storage slot N to return a quoted version of the
+ argument ARG of size ARGSIZE. This is like quotearg_n_style
+ (N, S, ARG), except it can quote null bytes. */
+char *quotearg_n_style_mem (int n, enum quoting_style s,
+ char const *arg, size_t argsize);
+
+/* Equivalent to quotearg_n_style (0, S, ARG). */
+char *quotearg_style (enum quoting_style s, char const *arg);
+
+/* Like quotearg (ARG), except also quote any instances of CH. */
+char *quotearg_char (char const *arg, char ch);
+
+/* Equivalent to quotearg_char (ARG, ':'). */
+char *quotearg_colon (char const *arg);
+
+#endif /* !QUOTEARG_H_ */
diff --git a/lib/readlink.c b/lib/readlink.c
new file mode 100644
index 0000000..3196aec
--- /dev/null
+++ b/lib/readlink.c
@@ -0,0 +1,49 @@
+/* Stub for readlink().
+ Copyright (C) 2003-2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+#if !HAVE_READLINK
+
+/* readlink() substitute for systems that don't have a readlink() function,
+ such as DJGPP 2.03 and mingw32. */
+
+/* The official POSIX return type of readlink() is ssize_t, but since here
+ we have no declaration in a public header file, we use 'int' as return
+ type. */
+
+int
+readlink (const char *path, char *buf, size_t bufsize)
+{
+ struct stat statbuf;
+
+ /* In general we should use lstat() here, not stat(). But on platforms
+ without symbolic links lstat() - if it exists - would be equivalent to
+ stat(), therefore we can use stat(). This saves us a configure check. */
+ if (stat (path, &statbuf) >= 0)
+ errno = EINVAL;
+ return -1;
+}
+
+#endif
diff --git a/lib/realloc.c b/lib/realloc.c
new file mode 100644
index 0000000..fe94822
--- /dev/null
+++ b/lib/realloc.c
@@ -0,0 +1,46 @@
+/* realloc() function that is glibc compatible.
+ Copyright (C) 1997, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#undef realloc
+
+#include <stdlib.h>
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking. If N is zero, change it to 1. If P is NULL,
+ use malloc. */
+
+void *
+rpl_realloc (void *p, size_t n)
+{
+ if (n == 0)
+ {
+ n = 1;
+
+ /* In theory realloc might fail, so don't rely on it to free. */
+ free (p);
+ p = NULL;
+ }
+
+ if (p == NULL)
+ return malloc (n);
+ return realloc (p, n);
+}
diff --git a/lib/regcomp.c b/lib/regcomp.c
new file mode 100644
index 0000000..279b20c
--- /dev/null
+++ b/lib/regcomp.c
@@ -0,0 +1,3779 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ Idx length, reg_syntax_t syntax);
+static void re_compile_fastmap_iter (regex_t *bufp,
+ const re_dfastate_t *init_state,
+ char *fastmap);
+static reg_errcode_t init_dfa (re_dfa_t *dfa, Idx pat_len);
+#ifdef RE_ENABLE_I18N
+static void free_charset (re_charset_t *cset);
+#endif /* RE_ENABLE_I18N */
+static void free_workarea_compile (regex_t *preg);
+static reg_errcode_t create_initial_state (re_dfa_t *dfa);
+#ifdef RE_ENABLE_I18N
+static void optimize_utf8 (re_dfa_t *dfa);
+#endif
+static reg_errcode_t analyze (regex_t *preg);
+static reg_errcode_t preorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t postorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
+static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
+static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
+ bin_tree_t *node);
+static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
+static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
+static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
+static Idx duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint);
+static Idx search_duplicated_node (const re_dfa_t *dfa, Idx org_node,
+ unsigned int constraint);
+static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
+static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
+ Idx node, bool root);
+static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
+static Idx fetch_number (re_string_t *input, re_token_t *token,
+ reg_syntax_t syntax);
+static int peek_token (re_token_t *token, re_string_t *input,
+ reg_syntax_t syntax);
+static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ Idx nest, reg_errcode_t *err);
+static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ Idx nest, reg_errcode_t *err);
+static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ Idx nest, reg_errcode_t *err);
+static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ Idx nest, reg_errcode_t *err);
+static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
+ re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax,
+ reg_errcode_t *err);
+static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token, int token_len,
+ re_dfa_t *dfa,
+ reg_syntax_t syntax,
+ bool accept_hyphen);
+static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token);
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t build_equiv_class (bitset sbcset,
+ re_charset_t *mbcset,
+ Idx *equiv_class_alloc,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (unsigned REG_TRANSLATE_TYPE trans,
+ bitset sbcset,
+ re_charset_t *mbcset,
+ Idx *char_class_alloc,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#else /* not RE_ENABLE_I18N */
+static reg_errcode_t build_equiv_class (bitset sbcset,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (unsigned REG_TRANSLATE_TYPE trans,
+ bitset sbcset,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#endif /* not RE_ENABLE_I18N */
+static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
+ unsigned REG_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra,
+ bool non_match, reg_errcode_t *err);
+static bin_tree_t *create_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type);
+static bin_tree_t *create_token_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token);
+static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
+static void free_token (re_token_t *node);
+static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
+static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
+
+/* This table gives an error message for each of the error codes listed
+ in regex.h. Obviously the order here has to be same as there.
+ POSIX doesn't require that we do anything for REG_NOERROR,
+ but why not be nice? */
+
+const char __re_error_msgid[] attribute_hidden =
+ {
+#define REG_NOERROR_IDX 0
+ gettext_noop ("Success") /* REG_NOERROR */
+ "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+ gettext_noop ("No match") /* REG_NOMATCH */
+ "\0"
+#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
+ gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+ "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+ gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
+ "\0"
+#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+ gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+ "\0"
+#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
+ gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+ "\0"
+#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
+ gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+ "\0"
+#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
+ gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
+ "\0"
+#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+ gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+ "\0"
+#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+ gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+ "\0"
+#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
+ gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+ "\0"
+#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+ gettext_noop ("Invalid range end") /* REG_ERANGE */
+ "\0"
+#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
+ gettext_noop ("Memory exhausted") /* REG_ESPACE */
+ "\0"
+#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
+ gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+ "\0"
+#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+ gettext_noop ("Premature end of regular expression") /* REG_EEND */
+ "\0"
+#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
+ gettext_noop ("Regular expression too big") /* REG_ESIZE */
+ "\0"
+#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
+ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
+ };
+
+const size_t __re_error_msgid_idx[] attribute_hidden =
+ {
+ REG_NOERROR_IDX,
+ REG_NOMATCH_IDX,
+ REG_BADPAT_IDX,
+ REG_ECOLLATE_IDX,
+ REG_ECTYPE_IDX,
+ REG_EESCAPE_IDX,
+ REG_ESUBREG_IDX,
+ REG_EBRACK_IDX,
+ REG_EPAREN_IDX,
+ REG_EBRACE_IDX,
+ REG_BADBR_IDX,
+ REG_ERANGE_IDX,
+ REG_ESPACE_IDX,
+ REG_BADRPT_IDX,
+ REG_EEND_IDX,
+ REG_ESIZE_IDX,
+ REG_ERPAREN_IDX
+ };
+
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length LENGTH) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `re_allocated' (and perhaps `re_buffer') and `translate' fields
+ are set in BUFP on entry. */
+
+const char *
+re_compile_pattern (const char *pattern, size_t length,
+ struct re_pattern_buffer *bufp)
+{
+ reg_errcode_t ret;
+
+ /* And GNU code determines whether or not to get register information
+ by passing null for the REGS argument to re_match, etc., not by
+ setting re_no_sub, unless REG_NO_SUB is set. */
+ bufp->re_no_sub = !!(re_syntax_options & REG_NO_SUB);
+
+ /* Match anchors at newline. */
+ bufp->re_newline_anchor = 1;
+
+ ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
+
+ if (!ret)
+ return NULL;
+ return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+#ifdef _LIBC
+weak_alias (__re_compile_pattern, re_compile_pattern)
+#endif
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
+ also be assigned to arbitrarily: each pattern buffer stores its own
+ syntax, so it can be changed between regex compilations. */
+/* This has no initializer because initialized variables in Emacs
+ become read-only after dumping. */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation. This provides
+ for compatibility for various utilities which historically have
+ different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit mask comprised of the various bits
+ defined in regex.h. We return the old syntax. */
+
+reg_syntax_t
+re_set_syntax (reg_syntax_t syntax)
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+#ifdef _LIBC
+weak_alias (__re_set_syntax, re_set_syntax)
+#endif
+
+int
+re_compile_fastmap (struct re_pattern_buffer *bufp)
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->re_buffer;
+ char *fastmap = bufp->re_fastmap;
+
+ memset (fastmap, '\0', sizeof (char) * SBC_MAX);
+ re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
+ if (dfa->init_state != dfa->init_state_word)
+ re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
+ if (dfa->init_state != dfa->init_state_nl)
+ re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
+ if (dfa->init_state != dfa->init_state_begbuf)
+ re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
+ bufp->re_fastmap_accurate = 1;
+ return 0;
+}
+#ifdef _LIBC
+weak_alias (__re_compile_fastmap, re_compile_fastmap)
+#endif
+
+static inline void
+__attribute ((always_inline))
+re_set_fastmap (char *fastmap, bool icase, int ch)
+{
+ fastmap[ch] = 1;
+ if (icase)
+ fastmap[tolower (ch)] = 1;
+}
+
+/* Helper function for re_compile_fastmap.
+ Compile fastmap for the initial_state INIT_STATE. */
+
+static void
+re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
+ char *fastmap)
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->re_buffer;
+ Idx node_cnt;
+ bool icase = (dfa->mb_cur_max == 1 && (bufp->re_syntax & REG_IGNORE_CASE));
+ for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
+ {
+ Idx node = init_state->nodes.elems[node_cnt];
+ re_token_type_t type = dfa->nodes[node].type;
+
+ if (type == CHARACTER)
+ {
+ re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
+#ifdef RE_ENABLE_I18N
+ if ((bufp->re_syntax & REG_IGNORE_CASE) && dfa->mb_cur_max > 1)
+ {
+ unsigned char buf[MB_LEN_MAX];
+ unsigned char *p;
+ wchar_t wc;
+ mbstate_t state;
+
+ p = buf;
+ *p++ = dfa->nodes[node].opr.c;
+ while (++node < dfa->nodes_len
+ && dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].mb_partial)
+ *p++ = dfa->nodes[node].opr.c;
+ memset (&state, 0, sizeof (state));
+ if (mbrtowc (&wc, (const char *) buf, p - buf,
+ &state) == p - buf
+ && (__wcrtomb ((char *) buf, towlower (wc), &state)
+ != (size_t) -1))
+ re_set_fastmap (fastmap, false, buf[0]);
+ }
+#endif
+ }
+ else if (type == SIMPLE_BRACKET)
+ {
+ int i, j, ch;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (dfa->nodes[node].opr.sbcset[i] & ((bitset_word) 1 << j))
+ re_set_fastmap (fastmap, icase, ch);
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == COMPLEX_BRACKET)
+ {
+ Idx i;
+ re_charset_t *cset = dfa->nodes[node].opr.mbcset;
+ if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes
+ || cset->nranges || cset->nchar_classes)
+ {
+# ifdef _LIBC
+ if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0)
+ {
+ /* In this case we want to catch the bytes which are
+ the first byte of any collation elements.
+ e.g. In da_DK, we want to catch 'a' since "aa"
+ is a valid collation element, and don't catch
+ 'b' since 'b' is the only collation element
+ which starts from 'b'. */
+ const int32_t *table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ for (i = 0; i < SBC_MAX; ++i)
+ if (table[i] < 0)
+ re_set_fastmap (fastmap, icase, i);
+ }
+# else
+ if (dfa->mb_cur_max > 1)
+ for (i = 0; i < SBC_MAX; ++i)
+ if (__btowc (i) == WEOF)
+ re_set_fastmap (fastmap, icase, i);
+# endif /* not _LIBC */
+ }
+ for (i = 0; i < cset->nmbchars; ++i)
+ {
+ char buf[256];
+ mbstate_t state;
+ memset (&state, '\0', sizeof (state));
+ if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
+ re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
+ if ((bufp->re_syntax & REG_IGNORE_CASE) && dfa->mb_cur_max > 1)
+ {
+ if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
+ != (size_t) -1)
+ re_set_fastmap (fastmap, false, *(unsigned char *) buf);
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ else if (type == OP_PERIOD
+#ifdef RE_ENABLE_I18N
+ || type == OP_UTF8_PERIOD
+#endif /* RE_ENABLE_I18N */
+ || type == END_OF_RE)
+ {
+ memset (fastmap, '\1', sizeof (char) * SBC_MAX);
+ if (type == END_OF_RE)
+ bufp->re_can_be_null = 1;
+ return;
+ }
+ }
+}
+
+/* Entry point for POSIX code. */
+/* regcomp takes a regular expression as a string and compiles it.
+
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
+
+ `re_buffer' to the compiled pattern;
+ `re_used' to the length of the compiled pattern;
+ `re_syntax' to REG_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ REG_SYNTAX_POSIX_BASIC;
+ `re_newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `re_fastmap' to an allocated space for the fastmap;
+ `re_fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
+
+ PATTERN is the address of the pattern string.
+
+ CFLAGS is a series of bits which affect compilation.
+
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
+
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
+
+ If REG_ICASE is set, then we considers upper- and lowercase
+ versions of letters to be equivalent when matching.
+
+ If REG_NOSUB is set, then when PREG is passed to regexec, that
+ routine will report only success or failure, and nothing about the
+ registers.
+
+ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
+ the return codes and their meanings.) */
+
+int
+regcomp (regex_t *__restrict preg, const char *__restrict pattern, int cflags)
+{
+ reg_errcode_t ret;
+ reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? REG_SYNTAX_POSIX_EXTENDED
+ : REG_SYNTAX_POSIX_BASIC);
+
+ preg->re_buffer = NULL;
+ preg->re_allocated = 0;
+ preg->re_used = 0;
+
+ /* Try to allocate space for the fastmap. */
+ preg->re_fastmap = re_malloc (char, SBC_MAX);
+ if (BE (preg->re_fastmap == NULL, 0))
+ return REG_ESPACE;
+
+ syntax |= (cflags & REG_ICASE) ? REG_IGNORE_CASE : 0;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~REG_DOT_NEWLINE;
+ syntax |= REG_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->re_newline_anchor = 1;
+ }
+ else
+ preg->re_newline_anchor = 0;
+ preg->re_no_sub = !!(cflags & REG_NOSUB);
+ preg->re_translate = NULL;
+
+ ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
+
+ /* POSIX doesn't distinguish between an unmatched open-group and an
+ unmatched close-group: both are REG_EPAREN. */
+ if (ret == REG_ERPAREN)
+ ret = REG_EPAREN;
+
+ /* We have already checked preg->re_fastmap != NULL. */
+ if (BE (ret == REG_NOERROR, 1))
+ /* Compute the fastmap now, since regexec cannot modify the pattern
+ buffer. This function never fails in this implementation. */
+ (void) re_compile_fastmap (preg);
+ else
+ {
+ /* Some error occurred while compiling the expression. */
+ re_free (preg->re_fastmap);
+ preg->re_fastmap = NULL;
+ }
+
+ return (int) ret;
+}
+#ifdef _LIBC
+weak_alias (__regcomp, regcomp)
+#endif
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+
+size_t
+regerror (int errcode, const regex_t *__restrict preg,
+ char *__restrict errbuf, size_t errbuf_size)
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (BE (errcode < 0
+ || errcode >= (int) (sizeof (__re_error_msgid_idx)
+ / sizeof (__re_error_msgid_idx[0])), 0))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (BE (errbuf_size != 0, 1))
+ {
+ if (BE (msg_size > errbuf_size, 0))
+ {
+#if defined HAVE_MEMPCPY || defined _LIBC
+ *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+ memcpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+#endif
+ }
+ else
+ memcpy (errbuf, msg, msg_size);
+ }
+
+ return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+#ifdef RE_ENABLE_I18N
+/* This static array is used for the map to single-byte characters when
+ UTF-8 is used. Otherwise we would allocate memory just to initialize
+ it the same all the time. UTF-8 is the preferred encoding so this is
+ a worthwhile optimization. */
+static const bitset utf8_sb_map =
+{
+ /* Set the first 128 bits. */
+# if 2 < BITSET_WORDS
+ BITSET_WORD_MAX,
+# endif
+# if 4 < BITSET_WORDS
+ BITSET_WORD_MAX,
+# endif
+# if 6 < BITSET_WORDS
+ BITSET_WORD_MAX,
+# endif
+# if 8 < BITSET_WORDS
+# error "Invalid BITSET_WORDS"
+# endif
+ (BITSET_WORD_MAX
+ >> (SBC_MAX % BITSET_WORD_BITS == 0
+ ? 0
+ : BITSET_WORD_BITS - SBC_MAX % BITSET_WORD_BITS))
+};
+#endif
+
+
+static void
+free_dfa_content (re_dfa_t *dfa)
+{
+ Idx i, j;
+
+ if (dfa->nodes)
+ for (i = 0; i < dfa->nodes_len; ++i)
+ free_token (dfa->nodes + i);
+ re_free (dfa->nexts);
+ for (i = 0; i < dfa->nodes_len; ++i)
+ {
+ if (dfa->eclosures != NULL)
+ re_node_set_free (dfa->eclosures + i);
+ if (dfa->inveclosures != NULL)
+ re_node_set_free (dfa->inveclosures + i);
+ if (dfa->edests != NULL)
+ re_node_set_free (dfa->edests + i);
+ }
+ re_free (dfa->edests);
+ re_free (dfa->eclosures);
+ re_free (dfa->inveclosures);
+ re_free (dfa->nodes);
+
+ if (dfa->state_table)
+ for (i = 0; i <= dfa->state_hash_mask; ++i)
+ {
+ struct re_state_table_entry *entry = dfa->state_table + i;
+ for (j = 0; j < entry->num; ++j)
+ {
+ re_dfastate_t *state = entry->array[j];
+ free_state (state);
+ }
+ re_free (entry->array);
+ }
+ re_free (dfa->state_table);
+#ifdef RE_ENABLE_I18N
+ if (dfa->sb_char != utf8_sb_map)
+ re_free (dfa->sb_char);
+#endif
+ re_free (dfa->subexp_map);
+#ifdef DEBUG
+ re_free (dfa->re_str);
+#endif
+
+ re_free (dfa);
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ if (BE (dfa != NULL, 1))
+ free_dfa_content (dfa);
+ preg->re_buffer = NULL;
+ preg->re_allocated = 0;
+
+ re_free (preg->re_fastmap);
+ preg->re_fastmap = NULL;
+
+ re_free (preg->re_translate);
+ preg->re_translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+# ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec above without link errors. */
+weak_function
+# endif
+re_comp (const char *s)
+{
+ reg_errcode_t ret;
+ char *fastmap;
+
+ if (!s)
+ {
+ if (!re_comp_buf.re_buffer)
+ return gettext ("No previous regular expression");
+ return 0;
+ }
+
+ if (re_comp_buf.re_buffer)
+ {
+ fastmap = re_comp_buf.re_fastmap;
+ re_comp_buf.re_fastmap = NULL;
+ __regfree (&re_comp_buf);
+ memset (&re_comp_buf, '\0', sizeof (re_comp_buf));
+ re_comp_buf.re_fastmap = fastmap;
+ }
+
+ if (re_comp_buf.re_fastmap == NULL)
+ {
+ re_comp_buf.re_fastmap = (char *) malloc (SBC_MAX);
+ if (re_comp_buf.re_fastmap == NULL)
+ return (char *) gettext (__re_error_msgid
+ + __re_error_msgid_idx[(int) REG_ESPACE]);
+ }
+
+ /* Since `re_exec' always passes NULL for the `regs' argument, we
+ don't need to initialize the pattern buffer fields which affect it. */
+
+ /* Match anchors at newlines. */
+ re_comp_buf.re_newline_anchor = 1;
+
+ ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options);
+
+ if (!ret)
+ return NULL;
+
+ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
+ return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+
+#ifdef _LIBC
+libc_freeres_fn (free_mem)
+{
+ __regfree (&re_comp_buf);
+}
+#endif
+
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point.
+ Compile the regular expression PATTERN, whose length is LENGTH.
+ SYNTAX indicate regular expression's syntax. */
+
+static reg_errcode_t
+re_compile_internal (regex_t *preg, const char *pattern, Idx length,
+ reg_syntax_t syntax)
+{
+ reg_errcode_t err = REG_NOERROR;
+ re_dfa_t *dfa;
+ re_string_t regexp;
+
+ /* Initialize the pattern buffer. */
+ preg->re_fastmap_accurate = 0;
+ preg->re_syntax = syntax;
+ preg->re_not_bol = preg->re_not_eol = 0;
+ preg->re_used = 0;
+ preg->re_nsub = 0;
+ preg->re_can_be_null = 0;
+ preg->re_regs_allocated = REG_UNALLOCATED;
+
+ /* Initialize the dfa. */
+ dfa = (re_dfa_t *) preg->re_buffer;
+ if (BE (preg->re_allocated < sizeof (re_dfa_t), 0))
+ {
+ /* If zero allocated, but buffer is non-null, try to realloc
+ enough space. This loses if buffer's address is bogus, but
+ that is the user's responsibility. If buffer is null this
+ is a simple allocation. */
+ dfa = re_realloc (preg->re_buffer, re_dfa_t, 1);
+ if (dfa == NULL)
+ return REG_ESPACE;
+ preg->re_allocated = sizeof (re_dfa_t);
+ preg->re_buffer = (unsigned char *) dfa;
+ }
+ preg->re_used = sizeof (re_dfa_t);
+
+ __libc_lock_init (dfa->lock);
+
+ err = init_dfa (dfa, length);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->re_buffer = NULL;
+ preg->re_allocated = 0;
+ return err;
+ }
+#ifdef DEBUG
+ dfa->re_str = re_malloc (char, length + 1);
+ strncpy (dfa->re_str, pattern, length + 1);
+#endif
+
+ err = re_string_construct (&regexp, pattern, length, preg->re_translate,
+ syntax & REG_IGNORE_CASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_compile_internal_free_return:
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+ free_dfa_content (dfa);
+ preg->re_buffer = NULL;
+ preg->re_allocated = 0;
+ return err;
+ }
+
+ /* Parse the regular expression, and build a structure tree. */
+ preg->re_nsub = 0;
+ dfa->str_tree = parse (&regexp, preg, syntax, &err);
+ if (BE (dfa->str_tree == NULL, 0))
+ goto re_compile_internal_free_return;
+
+ /* Analyze the tree and create the nfa. */
+ err = analyze (preg);
+ if (BE (err != REG_NOERROR, 0))
+ goto re_compile_internal_free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* If possible, do searching in single byte encoding to speed things up. */
+ if (dfa->is_utf8 && !(syntax & REG_IGNORE_CASE) && preg->re_translate == NULL)
+ optimize_utf8 (dfa);
+#endif
+
+ /* Then create the initial state of the dfa. */
+ err = create_initial_state (dfa);
+
+ /* Release work areas. */
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->re_buffer = NULL;
+ preg->re_allocated = 0;
+ }
+
+ return err;
+}
+
+/* Initialize DFA. We use the length of the regular expression PAT_LEN
+ as the initial length of some arrays. */
+
+static reg_errcode_t
+init_dfa (re_dfa_t *dfa, Idx pat_len)
+{
+ __re_size_t table_size;
+#ifndef _LIBC
+ char *codeset_name;
+#endif
+
+ memset (dfa, '\0', sizeof (re_dfa_t));
+
+ /* Force allocation of str_tree_storage the first time. */
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+
+ dfa->nodes_alloc = pat_len + 1;
+ dfa->nodes = re_xmalloc (re_token_t, dfa->nodes_alloc);
+
+ /* table_size = 2 ^ ceil(log pat_len) */
+ for (table_size = 1; table_size <= pat_len; table_size <<= 1)
+ if (0 < (Idx) -1 && table_size == 0)
+ return REG_ESPACE;
+
+ dfa->state_table = re_calloc (struct re_state_table_entry, table_size);
+ dfa->state_hash_mask = table_size - 1;
+
+ dfa->mb_cur_max = MB_CUR_MAX;
+#ifdef _LIBC
+ if (dfa->mb_cur_max == 6
+ && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
+ dfa->is_utf8 = 1;
+ dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
+ != 0);
+#else
+# ifdef HAVE_LANGINFO_CODESET
+ codeset_name = nl_langinfo (CODESET);
+# else
+ codeset_name = getenv ("LC_ALL");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LC_CTYPE");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LANG");
+ if (codeset_name == NULL)
+ codeset_name = "";
+ else if (strchr (codeset_name, '.') != NULL)
+ codeset_name = strchr (codeset_name, '.') + 1;
+# endif
+
+ if (strcasecmp (codeset_name, "UTF-8") == 0
+ || strcasecmp (codeset_name, "UTF8") == 0)
+ dfa->is_utf8 = 1;
+
+ /* We check exhaustively in the loop below if this charset is a
+ superset of ASCII. */
+ dfa->map_notascii = 0;
+#endif
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ if (dfa->is_utf8)
+ dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
+ else
+ {
+ int i, j, ch;
+
+ dfa->sb_char = re_calloc (bitset_word, BITSET_WORDS);
+ if (BE (dfa->sb_char == NULL, 0))
+ return REG_ESPACE;
+
+ /* Set the bits corresponding to single byte chars. */
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ {
+ wint_t wch = __btowc (ch);
+ if (wch != WEOF)
+ dfa->sb_char[i] |= (bitset_word) 1 << j;
+# ifndef _LIBC
+ if (isascii (ch) && wch != ch)
+ dfa->map_notascii = 1;
+# endif
+ }
+ }
+ }
+#endif
+
+ if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+/* Initialize WORD_CHAR table, which indicate which character is
+ "word". In this case "word" means that it is the word construction
+ character used by some operators like "\<", "\>", etc. */
+
+static void
+init_word_char (re_dfa_t *dfa)
+{
+ int i, j, ch;
+ dfa->word_ops_used = 1;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (isalnum (ch) || ch == '_')
+ dfa->word_char[i] |= (bitset_word) 1 << j;
+}
+
+/* Free the work area which are only used while compiling. */
+
+static void
+free_workarea_compile (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ bin_tree_storage_t *storage, *next;
+ for (storage = dfa->str_tree_storage; storage; storage = next)
+ {
+ next = storage->next;
+ re_free (storage);
+ }
+ dfa->str_tree_storage = NULL;
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+ dfa->str_tree = NULL;
+ re_free (dfa->org_indices);
+ dfa->org_indices = NULL;
+}
+
+/* Create initial states for all contexts. */
+
+static reg_errcode_t
+create_initial_state (re_dfa_t *dfa)
+{
+ Idx first, i;
+ reg_errcode_t err;
+ re_node_set init_nodes;
+
+ /* Initial states have the epsilon closure of the node which is
+ the first node of the regular expression. */
+ first = dfa->str_tree->first->node_idx;
+ dfa->init_node = first;
+ err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* The back-references which are in initial states can epsilon transit,
+ since in this case all of the subexpressions can be null.
+ Then we add epsilon closures of the nodes which are the next nodes of
+ the back-references. */
+ if (dfa->nbackref > 0)
+ for (i = 0; i < init_nodes.nelem; ++i)
+ {
+ Idx node_idx = init_nodes.elems[i];
+ re_token_type_t type = dfa->nodes[node_idx].type;
+
+ Idx clexp_idx;
+ if (type != OP_BACK_REF)
+ continue;
+ for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
+ {
+ re_token_t *clexp_node;
+ clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
+ if (clexp_node->type == OP_CLOSE_SUBEXP
+ && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
+ break;
+ }
+ if (clexp_idx == init_nodes.nelem)
+ continue;
+
+ if (type == OP_BACK_REF)
+ {
+ Idx dest_idx = dfa->edests[node_idx].elems[0];
+ if (!re_node_set_contains (&init_nodes, dest_idx))
+ {
+ re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
+ i = 0;
+ }
+ }
+ }
+
+ /* It must be the first time to invoke acquire_state. */
+ dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
+ /* We don't check ERR here, since the initial state must not be NULL. */
+ if (BE (dfa->init_state == NULL, 0))
+ return err;
+ if (dfa->init_state->has_constraint)
+ {
+ dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_WORD);
+ dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_NEWLINE);
+ dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
+ &init_nodes,
+ CONTEXT_NEWLINE
+ | CONTEXT_BEGBUF);
+ if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return err;
+ }
+ else
+ dfa->init_state_word = dfa->init_state_nl
+ = dfa->init_state_begbuf = dfa->init_state;
+
+ re_node_set_free (&init_nodes);
+ return REG_NOERROR;
+}
+
+#ifdef RE_ENABLE_I18N
+/* If it is possible to do searching in single byte encoding instead of UTF-8
+ to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
+ DFA nodes where needed. */
+
+static void
+optimize_utf8 (re_dfa_t *dfa)
+{
+ Idx node;
+ int i;
+ bool mb_chars = false;
+ bool has_period = false;
+
+ for (node = 0; node < dfa->nodes_len; ++node)
+ switch (dfa->nodes[node].type)
+ {
+ case CHARACTER:
+ if (dfa->nodes[node].opr.c >= 0x80)
+ mb_chars = true;
+ break;
+ case ANCHOR:
+ switch (dfa->nodes[node].opr.idx)
+ {
+ case LINE_FIRST:
+ case LINE_LAST:
+ case BUF_FIRST:
+ case BUF_LAST:
+ break;
+ default:
+ /* Word anchors etc. cannot be handled. */
+ return;
+ }
+ break;
+ case OP_PERIOD:
+ has_period = true;
+ break;
+ case OP_BACK_REF:
+ case OP_ALT:
+ case END_OF_RE:
+ case OP_DUP_ASTERISK:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ break;
+ case COMPLEX_BRACKET:
+ return;
+ case SIMPLE_BRACKET:
+ /* Just double check. */
+ {
+ int rshift =
+ (SBC_MAX / 2 % BITSET_WORD_BITS == 0
+ ? 0
+ : BITSET_WORD_BITS - SBC_MAX / 2 % BITSET_WORD_BITS);
+ for (i = SBC_MAX / 2 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i)
+ {
+ if (dfa->nodes[node].opr.sbcset[i] >> rshift != 0)
+ return;
+ rshift = 0;
+ }
+ }
+ break;
+ default:
+ abort ();
+ }
+
+ if (mb_chars || has_period)
+ for (node = 0; node < dfa->nodes_len; ++node)
+ {
+ if (dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].opr.c >= 0x80)
+ dfa->nodes[node].mb_partial = 0;
+ else if (dfa->nodes[node].type == OP_PERIOD)
+ dfa->nodes[node].type = OP_UTF8_PERIOD;
+ }
+
+ /* The search can be in single byte locale. */
+ dfa->mb_cur_max = 1;
+ dfa->is_utf8 = 0;
+ dfa->has_mb_node = dfa->nbackref > 0 || has_period;
+}
+#endif
+
+/* Analyze the structure tree, and calculate "first", "next", "edest",
+ "eclosure", and "inveclosure". */
+
+static reg_errcode_t
+analyze (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ reg_errcode_t ret;
+
+ /* Allocate arrays. */
+ dfa->nexts = re_malloc (Idx, dfa->nodes_alloc);
+ dfa->org_indices = re_malloc (Idx, dfa->nodes_alloc);
+ dfa->edests = re_xmalloc (re_node_set, dfa->nodes_alloc);
+ dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
+ if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
+ || dfa->eclosures == NULL, 0))
+ return REG_ESPACE;
+
+ dfa->subexp_map = re_xmalloc (Idx, preg->re_nsub);
+ if (dfa->subexp_map != NULL)
+ {
+ Idx i;
+ for (i = 0; i < preg->re_nsub; i++)
+ dfa->subexp_map[i] = i;
+ preorder (dfa->str_tree, optimize_subexps, dfa);
+ for (i = 0; i < preg->re_nsub; i++)
+ if (dfa->subexp_map[i] != i)
+ break;
+ if (i == preg->re_nsub)
+ {
+ free (dfa->subexp_map);
+ dfa->subexp_map = NULL;
+ }
+ }
+
+ ret = postorder (dfa->str_tree, lower_subexps, preg);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = postorder (dfa->str_tree, calc_first, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ preorder (dfa->str_tree, calc_next, dfa);
+ ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = calc_eclosure (dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ /* We only need this during the prune_impossible_nodes pass in regexec.c;
+ skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
+ if ((!preg->re_no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ dfa->inveclosures = re_xmalloc (re_node_set, dfa->nodes_len);
+ if (BE (dfa->inveclosures == NULL, 0))
+ return REG_ESPACE;
+ ret = calc_inveclosure (dfa);
+ }
+
+ return ret;
+}
+
+/* Our parse trees are very unbalanced, so we cannot use a stack to
+ implement parse tree visits. Instead, we use parent pointers and
+ some hairy code in these two functions. */
+static reg_errcode_t
+postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node, *prev;
+
+ for (node = root; ; )
+ {
+ /* Descend down the tree, preferably to the left (or to the right
+ if that's the only child). */
+ while (node->left || node->right)
+ if (node->left)
+ node = node->left;
+ else
+ node = node->right;
+
+ do
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ if (node->parent == NULL)
+ return REG_NOERROR;
+ prev = node;
+ node = node->parent;
+ }
+ /* Go up while we have a node that is reached from the right. */
+ while (node->right == prev || node->right == NULL);
+ node = node->right;
+ }
+}
+
+static reg_errcode_t
+preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node;
+
+ for (node = root; ; )
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ node = node->left;
+ else
+ {
+ bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ if (!node)
+ return REG_NOERROR;
+ }
+ node = node->right;
+ }
+ }
+}
+
+/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
+ re_search_internal to map the inner one's opr.idx to this one's. Adjust
+ backreferences as well. Requires a preorder visit. */
+static reg_errcode_t
+optimize_subexps (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+
+ if (node->token.type == OP_BACK_REF && dfa->subexp_map)
+ {
+ int idx = node->token.opr.idx;
+ node->token.opr.idx = dfa->subexp_map[idx];
+ dfa->used_bkref_map |= 1 << node->token.opr.idx;
+ }
+
+ else if (node->token.type == SUBEXP
+ && node->left && node->left->token.type == SUBEXP)
+ {
+ Idx other_idx = node->left->token.opr.idx;
+
+ node->left = node->left->left;
+ if (node->left)
+ node->left->parent = node;
+
+ dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
+ if (other_idx < BITSET_WORD_BITS)
+ dfa->used_bkref_map &= ~ ((bitset_word) 1 << other_idx);
+ }
+
+ return REG_NOERROR;
+}
+
+/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
+ of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
+static reg_errcode_t
+lower_subexps (void *extra, bin_tree_t *node)
+{
+ regex_t *preg = (regex_t *) extra;
+ reg_errcode_t err = REG_NOERROR;
+
+ if (node->left && node->left->token.type == SUBEXP)
+ {
+ node->left = lower_subexp (&err, preg, node->left);
+ if (node->left)
+ node->left->parent = node;
+ }
+ if (node->right && node->right->token.type == SUBEXP)
+ {
+ node->right = lower_subexp (&err, preg, node->right);
+ if (node->right)
+ node->right->parent = node;
+ }
+
+ return err;
+}
+
+static bin_tree_t *
+lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ bin_tree_t *body = node->left;
+ bin_tree_t *op, *cls, *tree1, *tree;
+
+ if (preg->re_no_sub
+ /* We do not optimize empty subexpressions, because otherwise we may
+ have bad CONCAT nodes with NULL children. This is obviously not
+ very common, so we do not lose much. An example that triggers
+ this case is the sed "script" /\(\)/x. */
+ && node->left != NULL
+ && ! (node->token.opr.idx < BITSET_WORD_BITS
+ && dfa->used_bkref_map & ((bitset_word) 1 << node->token.opr.idx)))
+ return node->left;
+
+ /* Convert the SUBEXP node to the concatenation of an
+ OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
+ op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
+ cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
+ tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
+ tree = create_tree (dfa, op, tree1, CONCAT);
+ if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
+ op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
+ return tree;
+}
+
+/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
+ nodes. Requires a postorder visit. */
+static reg_errcode_t
+calc_first (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ if (node->token.type == CONCAT)
+ {
+ node->first = node->left->first;
+ node->node_idx = node->left->node_idx;
+ }
+ else
+ {
+ node->first = node;
+ node->node_idx = re_dfa_add_node (dfa, node->token);
+ if (BE (node->node_idx == REG_MISSING, 0))
+ return REG_ESPACE;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 2: compute NEXT on the tree. Preorder visit. */
+static reg_errcode_t
+calc_next (void *extra, bin_tree_t *node)
+{
+ switch (node->token.type)
+ {
+ case OP_DUP_ASTERISK:
+ node->left->next = node;
+ break;
+ case CONCAT:
+ node->left->next = node->right->first;
+ node->right->next = node->next;
+ break;
+ default:
+ if (node->left)
+ node->left->next = node->next;
+ if (node->right)
+ node->right->next = node->next;
+ break;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
+static reg_errcode_t
+link_nfa_nodes (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ Idx idx = node->node_idx;
+ reg_errcode_t err = REG_NOERROR;
+
+ switch (node->token.type)
+ {
+ case CONCAT:
+ break;
+
+ case END_OF_RE:
+ assert (node->next == NULL);
+ break;
+
+ case OP_DUP_ASTERISK:
+ case OP_ALT:
+ {
+ Idx left, right;
+ dfa->has_plural_match = 1;
+ if (node->left != NULL)
+ left = node->left->first->node_idx;
+ else
+ left = node->next->node_idx;
+ if (node->right != NULL)
+ right = node->right->first->node_idx;
+ else
+ right = node->next->node_idx;
+ assert (REG_VALID_INDEX (left));
+ assert (REG_VALID_INDEX (right));
+ err = re_node_set_init_2 (dfa->edests + idx, left, right);
+ }
+ break;
+
+ case ANCHOR:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
+ break;
+
+ case OP_BACK_REF:
+ dfa->nexts[idx] = node->next->node_idx;
+ if (node->token.type == OP_BACK_REF)
+ re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
+ break;
+
+ default:
+ assert (!IS_EPSILON_NODE (node->token.type));
+ dfa->nexts[idx] = node->next->node_idx;
+ break;
+ }
+
+ return err;
+}
+
+/* Duplicate the epsilon closure of the node ROOT_NODE.
+ Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
+ to their own constraint. */
+
+static reg_errcode_t
+duplicate_node_closure (re_dfa_t *dfa, Idx top_org_node,
+ Idx top_clone_node, Idx root_node,
+ unsigned int init_constraint)
+{
+ Idx org_node, clone_node;
+ bool ok;
+ unsigned int constraint = init_constraint;
+ for (org_node = top_org_node, clone_node = top_clone_node;;)
+ {
+ Idx org_dest, clone_dest;
+ if (dfa->nodes[org_node].type == OP_BACK_REF)
+ {
+ /* If the back reference epsilon-transit, its destination must
+ also have the constraint. Then duplicate the epsilon closure
+ of the destination of the back reference, and store it in
+ edests of the back reference. */
+ org_dest = dfa->nexts[org_node];
+ re_node_set_empty (dfa->edests + clone_node);
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == REG_MISSING, 0))
+ return REG_ESPACE;
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+ else if (dfa->edests[org_node].nelem == 0)
+ {
+ /* In case of the node can't epsilon-transit, don't duplicate the
+ destination and store the original destination as the
+ destination of the node. */
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ break;
+ }
+ else if (dfa->edests[org_node].nelem == 1)
+ {
+ /* In case of the node can epsilon-transit, and it has only one
+ destination. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ if (dfa->nodes[org_node].type == ANCHOR)
+ {
+ /* In case of the node has another constraint, append it. */
+ if (org_node == root_node && clone_node != org_node)
+ {
+ /* ...but if the node is root_node itself, it means the
+ epsilon closure have a loop, then tie it to the
+ destination of the root_node. */
+ ok = re_node_set_insert (dfa->edests + clone_node,
+ org_dest);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ break;
+ }
+ constraint |= dfa->nodes[org_node].opr.ctx_type;
+ }
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == REG_MISSING, 0))
+ return REG_ESPACE;
+ ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+ else /* dfa->edests[org_node].nelem == 2 */
+ {
+ /* In case of the node can epsilon-transit, and it has two
+ destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ /* Search for a duplicated node which satisfies the constraint. */
+ clone_dest = search_duplicated_node (dfa, org_dest, constraint);
+ if (clone_dest == REG_MISSING)
+ {
+ /* There are no such a duplicated node, create a new one. */
+ reg_errcode_t err;
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == REG_MISSING, 0))
+ return REG_ESPACE;
+ ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ err = duplicate_node_closure (dfa, org_dest, clone_dest,
+ root_node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ {
+ /* There are a duplicated node which satisfy the constraint,
+ use it to avoid infinite loop. */
+ ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+
+ org_dest = dfa->edests[org_node].elems[1];
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == REG_MISSING, 0))
+ return REG_ESPACE;
+ ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+ org_node = org_dest;
+ clone_node = clone_dest;
+ }
+ return REG_NOERROR;
+}
+
+/* Search for a node which is duplicated from the node ORG_NODE, and
+ satisfies the constraint CONSTRAINT. */
+
+static Idx
+search_duplicated_node (const re_dfa_t *dfa, Idx org_node,
+ unsigned int constraint)
+{
+ Idx idx;
+ for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
+ {
+ if (org_node == dfa->org_indices[idx]
+ && constraint == dfa->nodes[idx].constraint)
+ return idx; /* Found. */
+ }
+ return REG_MISSING; /* Not found. */
+}
+
+/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
+ Return the index of the new node, or REG_MISSING if insufficient storage is
+ available. */
+
+static Idx
+duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint)
+{
+ Idx dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
+ if (BE (dup_idx != REG_MISSING, 1))
+ {
+ dfa->nodes[dup_idx].constraint = constraint;
+ if (dfa->nodes[org_idx].type == ANCHOR)
+ dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type;
+ dfa->nodes[dup_idx].duplicated = 1;
+
+ /* Store the index of the original node. */
+ dfa->org_indices[dup_idx] = org_idx;
+ }
+ return dup_idx;
+}
+
+static reg_errcode_t
+calc_inveclosure (re_dfa_t *dfa)
+{
+ Idx src, idx;
+ bool ok;
+ for (idx = 0; idx < dfa->nodes_len; ++idx)
+ re_node_set_init_empty (dfa->inveclosures + idx);
+
+ for (src = 0; src < dfa->nodes_len; ++src)
+ {
+ Idx *elems = dfa->eclosures[src].elems;
+ for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
+ {
+ ok = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Calculate "eclosure" for all the node in DFA. */
+
+static reg_errcode_t
+calc_eclosure (re_dfa_t *dfa)
+{
+ Idx node_idx;
+ bool incomplete;
+#ifdef DEBUG
+ assert (dfa->nodes_len > 0);
+#endif
+ incomplete = false;
+ /* For each nodes, calculate epsilon closure. */
+ for (node_idx = 0; ; ++node_idx)
+ {
+ reg_errcode_t err;
+ re_node_set eclosure_elem;
+ if (node_idx == dfa->nodes_len)
+ {
+ if (!incomplete)
+ break;
+ incomplete = false;
+ node_idx = 0;
+ }
+
+#ifdef DEBUG
+ assert (dfa->eclosures[node_idx].nelem != REG_MISSING);
+#endif
+
+ /* If we have already calculated, skip it. */
+ if (dfa->eclosures[node_idx].nelem != 0)
+ continue;
+ /* Calculate epsilon closure of `node_idx'. */
+ err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, true);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (dfa->eclosures[node_idx].nelem == 0)
+ {
+ incomplete = true;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Calculate epsilon closure of NODE. */
+
+static reg_errcode_t
+calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
+{
+ reg_errcode_t err;
+ unsigned int constraint;
+ Idx i;
+ bool incomplete;
+ bool ok;
+ re_node_set eclosure;
+ incomplete = false;
+ err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* This indicates that we are calculating this node now.
+ We reference this value to avoid infinite loop. */
+ dfa->eclosures[node].nelem = REG_MISSING;
+
+ constraint = ((dfa->nodes[node].type == ANCHOR)
+ ? dfa->nodes[node].opr.ctx_type : 0);
+ /* If the current node has constraints, duplicate all nodes.
+ Since they must inherit the constraints. */
+ if (constraint
+ && dfa->edests[node].nelem
+ && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
+ {
+ Idx org_node, cur_node;
+ org_node = cur_node = node;
+ err = duplicate_node_closure (dfa, node, node, node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Expand each epsilon destination nodes. */
+ if (IS_EPSILON_NODE(dfa->nodes[node].type))
+ for (i = 0; i < dfa->edests[node].nelem; ++i)
+ {
+ re_node_set eclosure_elem;
+ Idx edest = dfa->edests[node].elems[i];
+ /* If calculating the epsilon closure of `edest' is in progress,
+ return intermediate result. */
+ if (dfa->eclosures[edest].nelem == REG_MISSING)
+ {
+ incomplete = true;
+ continue;
+ }
+ /* If we haven't calculated the epsilon closure of `edest' yet,
+ calculate now. Otherwise use calculated epsilon closure. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ eclosure_elem = dfa->eclosures[edest];
+ /* Merge the epsilon closure of `edest'. */
+ re_node_set_merge (&eclosure, &eclosure_elem);
+ /* If the epsilon closure of `edest' is incomplete,
+ the epsilon closure of this node is also incomplete. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ incomplete = true;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+
+ /* Epsilon closures include itself. */
+ ok = re_node_set_insert (&eclosure, node);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ if (incomplete && !root)
+ dfa->eclosures[node].nelem = 0;
+ else
+ dfa->eclosures[node] = eclosure;
+ *new_set = eclosure;
+ return REG_NOERROR;
+}
+
+/* Functions for token which are used in the parser. */
+
+/* Fetch a token from INPUT.
+ We must not use this function inside bracket expressions. */
+
+static void
+fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax)
+{
+ re_string_skip_bytes (input, peek_token (result, input, syntax));
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function inside bracket expressions. */
+
+static int
+peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+ token->word_char = 0;
+#ifdef RE_ENABLE_I18N
+ token->mb_partial = 0;
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ token->mb_partial = 1;
+ return 1;
+ }
+#endif
+ if (c == '\\')
+ {
+ unsigned char c2;
+ if (re_string_cur_idx (input) + 1 >= re_string_length (input))
+ {
+ token->type = BACK_SLASH;
+ return 1;
+ }
+
+ c2 = re_string_peek_byte_case (input, 1);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input,
+ re_string_cur_idx (input) + 1);
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (c2) != 0;
+
+ switch (c2)
+ {
+ case '|':
+ if (!(syntax & REG_LIMITED_OPS) && !(syntax & REG_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (!(syntax & REG_NO_BK_REFS))
+ {
+ token->type = OP_BACK_REF;
+ token->opr.idx = c2 - '1';
+ }
+ break;
+ case '<':
+ if (!(syntax & REG_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_FIRST;
+ }
+ break;
+ case '>':
+ if (!(syntax & REG_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_LAST;
+ }
+ break;
+ case 'b':
+ if (!(syntax & REG_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_DELIM;
+ }
+ break;
+ case 'B':
+ if (!(syntax & REG_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = NOT_WORD_DELIM;
+ }
+ break;
+ case 'w':
+ if (!(syntax & REG_NO_GNU_OPS))
+ token->type = OP_WORD;
+ break;
+ case 'W':
+ if (!(syntax & REG_NO_GNU_OPS))
+ token->type = OP_NOTWORD;
+ break;
+ case 's':
+ if (!(syntax & REG_NO_GNU_OPS))
+ token->type = OP_SPACE;
+ break;
+ case 'S':
+ if (!(syntax & REG_NO_GNU_OPS))
+ token->type = OP_NOTSPACE;
+ break;
+ case '`':
+ if (!(syntax & REG_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_FIRST;
+ }
+ break;
+ case '\'':
+ if (!(syntax & REG_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_LAST;
+ }
+ break;
+ case '(':
+ if (!(syntax & REG_NO_BK_PARENS))
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (!(syntax & REG_NO_BK_PARENS))
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '+':
+ if (!(syntax & REG_LIMITED_OPS) && (syntax & REG_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & REG_LIMITED_OPS) && (syntax & REG_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & REG_INTERVALS) && (!(syntax & REG_NO_BK_BRACES)))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & REG_INTERVALS) && (!(syntax & REG_NO_BK_BRACES)))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ default:
+ break;
+ }
+ return 2;
+ }
+
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (token->opr.c);
+
+ switch (c)
+ {
+ case '\n':
+ if (syntax & REG_NEWLINE_ALT)
+ token->type = OP_ALT;
+ break;
+ case '|':
+ if (!(syntax & REG_LIMITED_OPS) && (syntax & REG_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '*':
+ token->type = OP_DUP_ASTERISK;
+ break;
+ case '+':
+ if (!(syntax & REG_LIMITED_OPS) && !(syntax & REG_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & REG_LIMITED_OPS) && !(syntax & REG_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & REG_INTERVALS) && (syntax & REG_NO_BK_BRACES))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & REG_INTERVALS) && (syntax & REG_NO_BK_BRACES))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ case '(':
+ if (syntax & REG_NO_BK_PARENS)
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (syntax & REG_NO_BK_PARENS)
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '[':
+ token->type = OP_OPEN_BRACKET;
+ break;
+ case '.':
+ token->type = OP_PERIOD;
+ break;
+ case '^':
+ if (!(syntax & (REG_CONTEXT_INDEP_ANCHORS | REG_CARET_ANCHORS_HERE)) &&
+ re_string_cur_idx (input) != 0)
+ {
+ char prev = re_string_peek_byte (input, -1);
+ if (!(syntax & REG_NEWLINE_ALT) || prev != '\n')
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_FIRST;
+ break;
+ case '$':
+ if (!(syntax & REG_CONTEXT_INDEP_ANCHORS) &&
+ re_string_cur_idx (input) + 1 != re_string_length (input))
+ {
+ re_token_t next;
+ re_string_skip_bytes (input, 1);
+ peek_token (&next, input, syntax);
+ re_string_skip_bytes (input, -1);
+ if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_LAST;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function out of bracket expressions. */
+
+static int
+peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ return 1;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ if (c == '\\' && (syntax & REG_BACKSLASH_ESCAPE_IN_LISTS)
+ && re_string_cur_idx (input) + 1 < re_string_length (input))
+ {
+ /* In this case, '\' escape a character. */
+ unsigned char c2;
+ re_string_skip_bytes (input, 1);
+ c2 = re_string_peek_byte (input, 0);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+ return 1;
+ }
+ if (c == '[') /* '[' is a special char in a bracket exps. */
+ {
+ unsigned char c2;
+ int token_len;
+ if (re_string_cur_idx (input) + 1 < re_string_length (input))
+ c2 = re_string_peek_byte (input, 1);
+ else
+ c2 = 0;
+ token->opr.c = c2;
+ token_len = 2;
+ switch (c2)
+ {
+ case '.':
+ token->type = OP_OPEN_COLL_ELEM;
+ break;
+ case '=':
+ token->type = OP_OPEN_EQUIV_CLASS;
+ break;
+ case ':':
+ if (syntax & REG_CHAR_CLASSES)
+ {
+ token->type = OP_OPEN_CHAR_CLASS;
+ break;
+ }
+ /* else fall through. */
+ default:
+ token->type = CHARACTER;
+ token->opr.c = c;
+ token_len = 1;
+ break;
+ }
+ return token_len;
+ }
+ switch (c)
+ {
+ case '-':
+ token->type = OP_CHARSET_RANGE;
+ break;
+ case ']':
+ token->type = OP_CLOSE_BRACKET;
+ break;
+ case '^':
+ token->type = OP_NON_MATCH_LIST;
+ break;
+ default:
+ token->type = CHARACTER;
+ }
+ return 1;
+}
+
+/* Functions for parser. */
+
+/* Entry point of the parser.
+ Parse the regular expression REGEXP and return the structure tree.
+ If an error is occured, ERR is set by error code, and return NULL.
+ This function build the following tree, from regular expression <reg_exp>:
+ CAT
+ / \
+ / \
+ <reg_exp> EOR
+
+ CAT means concatenation.
+ EOR means end of regular expression. */
+
+static bin_tree_t *
+parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax,
+ reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ bin_tree_t *tree, *eor, *root;
+ re_token_t current_token;
+ dfa->syntax = syntax;
+ fetch_token (&current_token, regexp, syntax | REG_CARET_ANCHORS_HERE);
+ tree = parse_reg_exp (regexp, preg, &current_token, syntax, 0, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ eor = create_tree (dfa, NULL, NULL, END_OF_RE);
+ if (tree != NULL)
+ root = create_tree (dfa, tree, eor, CONCAT);
+ else
+ root = eor;
+ if (BE (eor == NULL || root == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ return root;
+}
+
+/* This function build the following tree, from regular expression
+ <branch1>|<branch2>:
+ ALT
+ / \
+ / \
+ <branch1> <branch2>
+
+ ALT means alternative, which represents the operator `|'. */
+
+static bin_tree_t *
+parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ bin_tree_t *tree, *branch = NULL;
+ tree = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type == OP_ALT)
+ {
+ fetch_token (token, regexp, syntax | REG_CARET_ANCHORS_HERE);
+ if (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ branch = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && branch == NULL, 0))
+ return NULL;
+ }
+ else
+ branch = NULL;
+ tree = create_tree (dfa, tree, branch, OP_ALT);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ <exp1><exp2>:
+ CAT
+ / \
+ / \
+ <exp1> <exp2>
+
+ CAT means concatenation. */
+
+static bin_tree_t *
+parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
+{
+ bin_tree_t *tree, *exp;
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ tree = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ exp = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && exp == NULL, 0))
+ {
+ return NULL;
+ }
+ if (tree != NULL && exp != NULL)
+ {
+ tree = create_tree (dfa, tree, exp, CONCAT);
+ if (tree == NULL)
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else if (tree == NULL)
+ tree = exp;
+ /* Otherwise exp == NULL, we don't need to create new tree. */
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression a*:
+ *
+ |
+ a
+*/
+
+static bin_tree_t *
+parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ bin_tree_t *tree;
+ switch (token->type)
+ {
+ case CHARACTER:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (!re_string_eoi (regexp)
+ && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
+ {
+ bin_tree_t *mbc_remain;
+ fetch_token (token, regexp, syntax);
+ mbc_remain = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree, mbc_remain, CONCAT);
+ if (BE (mbc_remain == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ }
+#endif
+ break;
+ case OP_OPEN_SUBEXP:
+ tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_OPEN_BRACKET:
+ tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_BACK_REF:
+ if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
+ {
+ *err = REG_ESUBREG;
+ return NULL;
+ }
+ dfa->used_bkref_map |= 1 << token->opr.idx;
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ ++dfa->nbackref;
+ dfa->has_mb_node = 1;
+ break;
+ case OP_OPEN_DUP_NUM:
+ if (syntax & REG_CONTEXT_INVALID_DUP)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ /* FALLTHROUGH */
+ case OP_DUP_ASTERISK:
+ case OP_DUP_PLUS:
+ case OP_DUP_QUESTION:
+ if (syntax & REG_CONTEXT_INVALID_OPS)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ else if (syntax & REG_CONTEXT_INDEP_OPS)
+ {
+ fetch_token (token, regexp, syntax);
+ return parse_expression (regexp, preg, token, syntax, nest, err);
+ }
+ /* else fall through */
+ case OP_CLOSE_SUBEXP:
+ if ((token->type == OP_CLOSE_SUBEXP) &&
+ !(syntax & REG_UNMATCHED_RIGHT_PAREN_ORD))
+ {
+ *err = REG_ERPAREN;
+ return NULL;
+ }
+ /* else fall through */
+ case OP_CLOSE_DUP_NUM:
+ /* We treat it as a normal character. */
+
+ /* Then we can these characters as normal characters. */
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be initialized already
+ by peek_token. */
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ break;
+ case ANCHOR:
+ if ((token->opr.ctx_type
+ & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
+ && dfa->word_ops_used == 0)
+ init_word_char (dfa);
+ if (token->opr.ctx_type == WORD_DELIM
+ || token->opr.ctx_type == NOT_WORD_DELIM)
+ {
+ bin_tree_t *tree_first, *tree_last;
+ if (token->opr.ctx_type == WORD_DELIM)
+ {
+ token->opr.ctx_type = WORD_FIRST;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = WORD_LAST;
+ }
+ else
+ {
+ token->opr.ctx_type = INSIDE_WORD;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = INSIDE_NOTWORD;
+ }
+ tree_last = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
+ if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else
+ {
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ /* We must return here, since ANCHORs can't be followed
+ by repetition operators.
+ eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
+ it must not be "<ANCHOR(^)><REPEAT(*)>". */
+ fetch_token (token, regexp, syntax);
+ return tree;
+ case OP_PERIOD:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ if (dfa->mb_cur_max > 1)
+ dfa->has_mb_node = 1;
+ break;
+ case OP_WORD:
+ case OP_NOTWORD:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "alnum",
+ (const unsigned char *) "_",
+ token->type == OP_NOTWORD, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_SPACE:
+ case OP_NOTSPACE:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "space",
+ (const unsigned char *) "",
+ token->type == OP_NOTSPACE, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_ALT:
+ case END_OF_RE:
+ return NULL;
+ case BACK_SLASH:
+ *err = REG_EESCAPE;
+ return NULL;
+ default:
+ /* Must not happen? */
+#ifdef DEBUG
+ assert (0);
+#endif
+ return NULL;
+ }
+ fetch_token (token, regexp, syntax);
+
+ while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
+ || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
+ {
+ tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ /* In BRE consecutive duplications are not allowed. */
+ if ((syntax & REG_CONTEXT_INVALID_DUP)
+ && (token->type == OP_DUP_ASTERISK
+ || token->type == OP_OPEN_DUP_NUM))
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ }
+
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ (<reg_exp>):
+ SUBEXP
+ |
+ <reg_exp>
+*/
+
+static bin_tree_t *
+parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ bin_tree_t *tree;
+ size_t cur_nsub;
+ cur_nsub = preg->re_nsub++;
+
+ fetch_token (token, regexp, syntax | REG_CARET_ANCHORS_HERE);
+
+ /* The subexpression may be a null string. */
+ if (token->type == OP_CLOSE_SUBEXP)
+ tree = NULL;
+ else
+ {
+ tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
+ if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
+ *err = REG_EPAREN;
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+
+ if (cur_nsub <= '9' - '1')
+ dfa->completed_bkref_map |= 1 << cur_nsub;
+
+ tree = create_tree (dfa, tree, NULL, SUBEXP);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ tree->token.opr.idx = cur_nsub;
+ return tree;
+}
+
+/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
+
+static bin_tree_t *
+parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
+{
+ bin_tree_t *tree = NULL, *old_tree = NULL;
+ Idx i, start, end, start_idx = re_string_cur_idx (regexp);
+ re_token_t start_token = *token;
+
+ if (token->type == OP_OPEN_DUP_NUM)
+ {
+ end = 0;
+ start = fetch_number (regexp, token, syntax);
+ if (start == REG_MISSING)
+ {
+ if (token->type == CHARACTER && token->opr.c == ',')
+ start = 0; /* We treat "{,m}" as "{0,m}". */
+ else
+ {
+ *err = REG_BADBR; /* <re>{} is invalid. */
+ return NULL;
+ }
+ }
+ if (BE (start != REG_ERROR, 1))
+ {
+ /* We treat "{n}" as "{n,n}". */
+ end = ((token->type == OP_CLOSE_DUP_NUM) ? start
+ : ((token->type == CHARACTER && token->opr.c == ',')
+ ? fetch_number (regexp, token, syntax) : REG_ERROR));
+ }
+ if (BE (start == REG_ERROR || end == REG_ERROR, 0))
+ {
+ /* Invalid sequence. */
+ if (BE (!(syntax & REG_INVALID_INTERVAL_ORD), 0))
+ {
+ if (token->type == END_OF_RE)
+ *err = REG_EBRACE;
+ else
+ *err = REG_BADBR;
+
+ return NULL;
+ }
+
+ /* If the syntax bit is set, rollback. */
+ re_string_set_index (regexp, start_idx);
+ *token = start_token;
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be already initialized by
+ peek_token. */
+ return elem;
+ }
+
+ if (BE (end != REG_MISSING && start > end, 0))
+ {
+ /* First number greater than second. */
+ *err = REG_BADBR;
+ return NULL;
+ }
+ }
+ else
+ {
+ start = (token->type == OP_DUP_PLUS) ? 1 : 0;
+ end = (token->type == OP_DUP_QUESTION) ? 1 : REG_MISSING;
+ }
+
+ fetch_token (token, regexp, syntax);
+
+ if (BE (elem == NULL, 0))
+ return NULL;
+ if (BE (start == 0 && end == 0, 0))
+ {
+ postorder (elem, free_tree, NULL);
+ return NULL;
+ }
+
+ /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
+ if (BE (start > 0, 0))
+ {
+ tree = elem;
+ for (i = 2; i <= start; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (start == end)
+ return tree;
+
+ /* Duplicate ELEM before it is marked optional. */
+ elem = duplicate_tree (elem, dfa);
+ old_tree = tree;
+ }
+ else
+ old_tree = NULL;
+
+ if (elem->token.type == SUBEXP)
+ postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx);
+
+ tree = create_tree (dfa, elem, NULL,
+ (end == REG_MISSING ? OP_DUP_ASTERISK : OP_ALT));
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ /* This loop is actually executed only when end != REG_MISSING,
+ to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
+ already created the start+1-th copy. */
+ if ((Idx) -1 < 0 || end != REG_MISSING)
+ for (i = start + 2; i <= end; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ tree = create_tree (dfa, tree, NULL, OP_ALT);
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (old_tree)
+ tree = create_tree (dfa, old_tree, tree, CONCAT);
+
+ return tree;
+
+ parse_dup_op_espace:
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* Size of the names for collating symbol/equivalence_class/character_class.
+ I'm not sure, but maybe enough. */
+#define BRACKET_NAME_BUF_SIZE 32
+
+#ifndef _LIBC
+ /* Local function for parse_bracket_exp only used in case of NOT _LIBC.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+static reg_errcode_t
+build_range_exp (bitset sbcset,
+# ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset, Idx *range_alloc,
+# endif
+ bracket_elem_t *start_elem, bracket_elem_t *end_elem)
+{
+ unsigned int start_ch, end_ch;
+ /* Equivalence Classes and Character Classes can't be a range start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ /* We can handle no multi character collating elements without libc
+ support. */
+ if (BE ((start_elem->type == COLL_SYM
+ && strlen ((char *) start_elem->opr.name) > 1)
+ || (end_elem->type == COLL_SYM
+ && strlen ((char *) end_elem->opr.name) > 1), 0))
+ return REG_ECOLLATE;
+
+# ifdef RE_ENABLE_I18N
+ {
+ wchar_t wc;
+ wint_t start_wc, end_wc;
+ wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+
+ start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
+ ? __btowc (start_ch) : start_elem->opr.wch);
+ end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
+ ? __btowc (end_ch) : end_elem->opr.wch);
+ if (start_wc == WEOF || end_wc == WEOF)
+ return REG_ECOLLATE;
+ cmp_buf[0] = start_wc;
+ cmp_buf[4] = end_wc;
+ if (wcscoll (cmp_buf, cmp_buf + 4) > 0)
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, for !_LIBC we have no collation elements: if the
+ character set is single byte, the single byte character set
+ that we build below suffices. parse_bracket_exp passes
+ no MBCSET if dfa->mb_cur_max == 1. */
+ if (mbcset)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ wchar_t *new_array_start, *new_array_end;
+ Idx new_nranges;
+
+ new_nranges = mbcset->nranges;
+ /* Use realloc since mbcset->range_starts and mbcset->range_ends
+ are NULL if *range_alloc == 0. */
+ new_array_start = re_x2realloc (mbcset->range_starts, wchar_t,
+ &new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, wchar_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_wc;
+ mbcset->range_ends[mbcset->nranges++] = end_wc;
+ }
+
+ /* Build the table for single byte characters. */
+ for (wc = 0; wc < SBC_MAX; ++wc)
+ {
+ cmp_buf[2] = wc;
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ bitset_set (sbcset, wc);
+ }
+ }
+# else /* not RE_ENABLE_I18N */
+ {
+ unsigned int ch;
+ start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ if (start_ch > end_ch)
+ return REG_ERANGE;
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ if (start_ch <= ch && ch <= end_ch)
+ bitset_set (sbcset, ch);
+ }
+# endif /* not RE_ENABLE_I18N */
+ return REG_NOERROR;
+}
+#endif /* not _LIBC */
+
+#ifndef _LIBC
+/* Helper function for parse_bracket_exp only used in case of NOT _LIBC..
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument since we may update it. */
+
+static reg_errcode_t
+build_collating_symbol (bitset sbcset,
+# ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset, Idx *coll_sym_alloc,
+# endif
+ const unsigned char *name)
+{
+ size_t name_len = strlen ((const char *) name);
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+}
+#endif /* not _LIBC */
+
+/* This function parse bracket expression like "[abc]", "[a-c]",
+ "[[.a-a.]]" etc. */
+
+static bin_tree_t *
+parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err)
+{
+#ifdef _LIBC
+ const unsigned char *collseqmb;
+ const char *collseqwc;
+ uint32_t nrules;
+ int32_t table_size;
+ const int32_t *symb_table;
+ const unsigned char *extra;
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Seek the collating symbol entry correspondings to NAME.
+ Return the index of the symbol in the SYMB_TABLE. */
+
+ auto inline int32_t
+ __attribute ((always_inline))
+ seek_collating_symbol_entry (const unsigned char *name, size_t name_len)
+ {
+ int32_t hash = elem_hash ((const char *) name, name_len);
+ int32_t elem = hash % table_size;
+ int32_t second = hash % (table_size - 2);
+ while (symb_table[2 * elem] != 0)
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ /* Compare the length of the name. */
+ && name_len == extra[symb_table[2 * elem + 1]]
+ /* Compare the name. */
+ && memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
+ name_len) == 0)
+ {
+ /* Yep, this is the entry. */
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+ return elem;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Look up the collation sequence value of BR_ELEM.
+ Return the value if succeeded, UINT_MAX otherwise. */
+
+ auto inline unsigned int
+ __attribute ((always_inline))
+ lookup_collation_sequence_value (bracket_elem_t *br_elem)
+ {
+ if (br_elem->type == SB_CHAR)
+ {
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ return collseqmb[br_elem->opr.ch];
+ else
+ {
+ wint_t wc = __btowc (br_elem->opr.ch);
+ return __collseq_table_lookup (collseqwc, wc);
+ }
+ }
+ else if (br_elem->type == MB_CHAR)
+ {
+ return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
+ }
+ else if (br_elem->type == COLL_SYM)
+ {
+ size_t sym_name_len = strlen ((char *) br_elem->opr.name);
+ if (nrules != 0)
+ {
+ int32_t elem, idx;
+ elem = seek_collating_symbol_entry (br_elem->opr.name,
+ sym_name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ /* Skip the byte sequence of the collating element. */
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the multibyte collation sequence value. */
+ idx += sizeof (unsigned int);
+ /* Skip the wide char sequence of the collating element. */
+ idx += sizeof (unsigned int) *
+ (1 + *(unsigned int *) (extra + idx));
+ /* Return the collation sequence value. */
+ return *(unsigned int *) (extra + idx);
+ }
+ else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
+ {
+ /* No valid character. Match it as a single byte
+ character. */
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ }
+ else if (sym_name_len == 1)
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ return UINT_MAX;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_range_exp (bitset sbcset, re_charset_t *mbcset,
+ Idx *range_alloc,
+ bracket_elem_t *start_elem, bracket_elem_t *end_elem)
+ {
+ unsigned int ch;
+ uint32_t start_collseq;
+ uint32_t end_collseq;
+
+ /* Equivalence Classes and Character Classes can't be a range
+ start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ start_collseq = lookup_collation_sequence_value (start_elem);
+ end_collseq = lookup_collation_sequence_value (end_elem);
+ /* Check start/end collation sequence values. */
+ if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
+ return REG_ECOLLATE;
+ if (BE ((syntax & REG_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, if we have no collation elements, and the character set
+ is single byte, the single byte character set that we
+ build below suffices. */
+ if (nrules > 0 || dfa->mb_cur_max > 1)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ uint32_t *new_array_start;
+ uint32_t *new_array_end;
+ Idx new_nranges;
+
+ new_nranges = mbcset->nranges;
+ new_array_start = re_x2realloc (mbcset->range_starts, uint32_t,
+ &new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, uint32_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_collseq;
+ mbcset->range_ends[mbcset->nranges++] = end_collseq;
+ }
+
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ch++)
+ {
+ uint32_t ch_collseq;
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ ch_collseq = collseqmb[ch];
+ else
+ ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
+ if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
+ bitset_set (sbcset, ch);
+ }
+ return REG_NOERROR;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument sinse we may update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_collating_symbol (bitset sbcset, re_charset_t *mbcset,
+ Idx *coll_sym_alloc, const unsigned char *name)
+ {
+ int32_t elem, idx;
+ size_t name_len = strlen ((const char *) name);
+ if (nrules != 0)
+ {
+ elem = seek_collating_symbol_entry (name, name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ }
+ else if (symb_table[2 * elem] == 0 && name_len == 1)
+ {
+ /* No valid character, treat it as a normal
+ character. */
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ else
+ return REG_ECOLLATE;
+
+ /* Got valid collation sequence, add it as a new entry. */
+ /* Check the space of the arrays. */
+ if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
+ {
+ /* Not enough, realloc it. */
+ Idx new_coll_sym_alloc = mbcset->ncoll_syms;
+ /* Use realloc since mbcset->coll_syms is NULL
+ if *alloc == 0. */
+ int32_t *new_coll_syms = re_x2realloc (mbcset->coll_syms, int32_t,
+ &new_coll_sym_alloc);
+ if (BE (new_coll_syms == NULL, 0))
+ return REG_ESPACE;
+ mbcset->coll_syms = new_coll_syms;
+ *coll_sym_alloc = new_coll_sym_alloc;
+ }
+ mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
+ return REG_NOERROR;
+ }
+ else
+ {
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ }
+ }
+#endif
+
+ re_token_t br_token;
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ Idx coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
+ Idx equiv_class_alloc = 0, char_class_alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ bool non_match = false;
+ bin_tree_t *work_tree;
+ int token_len;
+ bool first_round = true;
+#ifdef _LIBC
+ collseqmb = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules)
+ {
+ /*
+ if (MB_CUR_MAX > 1)
+ */
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+ }
+#endif
+ sbcset = re_calloc (bitset_word, BITSET_WORDS);
+#ifdef RE_ENABLE_I18N
+ mbcset = re_calloc (re_charset_t, 1);
+#endif /* RE_ENABLE_I18N */
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else
+ if (BE (sbcset == NULL, 0))
+#endif /* RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_NON_MATCH_LIST)
+ {
+#ifdef RE_ENABLE_I18N
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ non_match = true;
+ if (syntax & REG_HAT_LISTS_NOT_NEWLINE)
+ bitset_set (sbcset, '\0');
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ }
+
+ /* We treat the first ']' as a normal character. */
+ if (token->type == OP_CLOSE_BRACKET)
+ token->type = CHARACTER;
+
+ while (1)
+ {
+ bracket_elem_t start_elem, end_elem;
+ unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
+ unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
+ reg_errcode_t ret;
+ int token_len2 = 0;
+ bool is_range_exp = false;
+ re_token_t token2;
+
+ start_elem.opr.name = start_name_buf;
+ ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
+ syntax, first_round);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+ first_round = false;
+
+ /* Get information about the next token. We need it in any case. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+ /* Do not check for ranges if we know they are not allowed. */
+ if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
+ {
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CHARSET_RANGE)
+ {
+ re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
+ token_len2 = peek_token_bracket (&token2, regexp, syntax);
+ if (BE (token2.type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token2.type == OP_CLOSE_BRACKET)
+ {
+ /* We treat the last '-' as a normal character. */
+ re_string_skip_bytes (regexp, -token_len);
+ token->type = CHARACTER;
+ }
+ else
+ is_range_exp = true;
+ }
+ }
+
+ if (is_range_exp == true)
+ {
+ end_elem.opr.name = end_name_buf;
+ ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
+ dfa, syntax, true);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+#ifdef _LIBC
+ *err = build_range_exp (sbcset, mbcset, &range_alloc,
+ &start_elem, &end_elem);
+#else
+# ifdef RE_ENABLE_I18N
+ *err = build_range_exp (sbcset,
+ dfa->mb_cur_max > 1 ? mbcset : NULL,
+ &range_alloc, &start_elem, &end_elem);
+# else
+ *err = build_range_exp (sbcset, &start_elem, &end_elem);
+# endif
+#endif /* RE_ENABLE_I18N */
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ }
+ else
+ {
+ switch (start_elem.type)
+ {
+ case SB_CHAR:
+ bitset_set (sbcset, start_elem.opr.ch);
+ break;
+#ifdef RE_ENABLE_I18N
+ case MB_CHAR:
+ /* Check whether the array has enough space. */
+ if (BE (mbchar_alloc == mbcset->nmbchars, 0))
+ {
+ wchar_t *new_mbchars;
+ /* Not enough, realloc it. */
+ mbchar_alloc = mbcset->nmbchars;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ new_mbchars = re_x2realloc (mbcset->mbchars, wchar_t,
+ &mbchar_alloc);
+ if (BE (new_mbchars == NULL, 0))
+ goto parse_bracket_exp_espace;
+ mbcset->mbchars = new_mbchars;
+ }
+ mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
+ break;
+#endif /* RE_ENABLE_I18N */
+ case EQUIV_CLASS:
+ *err = build_equiv_class (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &equiv_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case COLL_SYM:
+ *err = build_collating_symbol (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &coll_sym_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case CHAR_CLASS:
+ *err = build_charclass (regexp->trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &char_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name, syntax);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ default:
+ assert (0);
+ break;
+ }
+ }
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CLOSE_BRACKET)
+ break;
+ }
+
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+
+ if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
+ || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
+ || mbcset->non_match)))
+ {
+ bin_tree_t *mbc_tree;
+ int sbc_idx;
+ /* Build a tree for complex bracket. */
+ dfa->has_mb_node = 1;
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
+ if (sbcset[sbc_idx])
+ break;
+ /* If there are no bits set in sbcset, there is no point
+ of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
+ if (sbc_idx < BITSET_WORDS)
+ {
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+
+ /* Then join them by ALT node. */
+ work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ else
+ {
+ re_free (sbcset);
+ work_tree = mbc_tree;
+ }
+ }
+ else
+#endif /* not RE_ENABLE_I18N */
+ {
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ return work_tree;
+
+ parse_bracket_exp_espace:
+ *err = REG_ESPACE;
+ parse_bracket_exp_free_return:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ return NULL;
+}
+
+/* Parse an element in the bracket expression. */
+
+static reg_errcode_t
+parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp,
+ re_token_t *token, int token_len, re_dfa_t *dfa,
+ reg_syntax_t syntax, bool accept_hyphen)
+{
+#ifdef RE_ENABLE_I18N
+ int cur_char_size;
+ cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
+ if (cur_char_size > 1)
+ {
+ elem->type = MB_CHAR;
+ elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
+ re_string_skip_bytes (regexp, cur_char_size);
+ return REG_NOERROR;
+ }
+#endif /* RE_ENABLE_I18N */
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
+ || token->type == OP_OPEN_EQUIV_CLASS)
+ return parse_bracket_symbol (elem, regexp, token);
+ if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
+ {
+ /* A '-' must only appear as anything but a range indicator before
+ the closing bracket. Everything else is an error. */
+ re_token_t token2;
+ (void) peek_token_bracket (&token2, regexp, syntax);
+ if (token2.type != OP_CLOSE_BRACKET)
+ /* The actual error value is not standardized since this whole
+ case is undefined. But ERANGE makes good sense. */
+ return REG_ERANGE;
+ }
+ elem->type = SB_CHAR;
+ elem->opr.ch = token->opr.c;
+ return REG_NOERROR;
+}
+
+/* Parse a bracket symbol in the bracket expression. Bracket symbols are
+ such as [:<character_class>:], [.<collating_element>.], and
+ [=<equivalent_class>=]. */
+
+static reg_errcode_t
+parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
+ re_token_t *token)
+{
+ unsigned char ch, delim = token->opr.c;
+ int i = 0;
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ for (;; ++i)
+ {
+ if (i >= BRACKET_NAME_BUF_SIZE)
+ return REG_EBRACK;
+ if (token->type == OP_OPEN_CHAR_CLASS)
+ ch = re_string_fetch_byte_case (regexp);
+ else
+ ch = re_string_fetch_byte (regexp);
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
+ break;
+ elem->opr.name[i] = ch;
+ }
+ re_string_skip_bytes (regexp, 1);
+ elem->opr.name[i] = '\0';
+ switch (token->type)
+ {
+ case OP_OPEN_COLL_ELEM:
+ elem->type = COLL_SYM;
+ break;
+ case OP_OPEN_EQUIV_CLASS:
+ elem->type = EQUIV_CLASS;
+ break;
+ case OP_OPEN_CHAR_CLASS:
+ elem->type = CHAR_CLASS;
+ break;
+ default:
+ break;
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the equivalence class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+build_equiv_class (bitset sbcset,
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset, Idx *equiv_class_alloc,
+#endif
+ const unsigned char *name)
+{
+#if defined _LIBC
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra, *cp;
+ unsigned char char_buf[2];
+ int32_t idx1, idx2;
+ unsigned int ch;
+ size_t len;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+ /* Calculate the index for equivalence class. */
+ cp = name;
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ idx1 = findidx (&cp);
+ if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0))
+ /* This isn't a valid character. */
+ return REG_ECOLLATE;
+
+ /* Build single byte matcing table for this equivalence class. */
+ char_buf[1] = (unsigned char) '\0';
+ len = weights[idx1];
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ {
+ char_buf[0] = ch;
+ cp = char_buf;
+ idx2 = findidx (&cp);
+/*
+ idx2 = table[ch];
+*/
+ if (idx2 == 0)
+ /* This isn't a valid character. */
+ continue;
+ if (len == weights[idx2])
+ {
+ int cnt = 0;
+ while (cnt <= len &&
+ weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt])
+ ++cnt;
+
+ if (cnt > len)
+ bitset_set (sbcset, ch);
+ }
+ }
+ /* Check whether the array has enough space. */
+ if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ Idx new_equiv_class_alloc = mbcset->nequiv_classes;
+ /* Use realloc since the array is NULL if *alloc == 0. */
+ int32_t *new_equiv_classes = re_x2realloc (mbcset->equiv_classes,
+ int32_t,
+ &new_equiv_class_alloc);
+ if (BE (new_equiv_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->equiv_classes = new_equiv_classes;
+ *equiv_class_alloc = new_equiv_class_alloc;
+ }
+ mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
+ }
+ else
+#endif /* _LIBC */
+ {
+ if (BE (strlen ((const char *) name) != 1, 0))
+ return REG_ECOLLATE;
+ bitset_set (sbcset, *name);
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the character class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+build_charclass (unsigned REG_TRANSLATE_TYPE trans, bitset sbcset,
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset, Idx *char_class_alloc,
+#endif
+ const unsigned char *class_name, reg_syntax_t syntax)
+{
+ int i;
+ const char *name = (const char *) class_name;
+
+ /* In case of REG_ICASE "upper" and "lower" match the both of
+ upper and lower cases. */
+ if ((syntax & REG_IGNORE_CASE)
+ && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
+ name = "alpha";
+
+#ifdef RE_ENABLE_I18N
+ /* Check the space of the arrays. */
+ if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ Idx new_char_class_alloc = mbcset->nchar_classes;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ wctype_t *new_char_classes = re_x2realloc (mbcset->char_classes, wctype_t,
+ &new_char_class_alloc);
+ if (BE (new_char_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->char_classes = new_char_classes;
+ *char_class_alloc = new_char_class_alloc;
+ }
+ mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
+#endif /* RE_ENABLE_I18N */
+
+#define BUILD_CHARCLASS_LOOP(ctype_func) \
+ for (i = 0; i < SBC_MAX; ++i) \
+ { \
+ if (ctype_func (i)) \
+ { \
+ int ch = trans ? trans[i] : i; \
+ bitset_set (sbcset, ch); \
+ } \
+ }
+
+ if (strcmp (name, "alnum") == 0)
+ BUILD_CHARCLASS_LOOP (isalnum)
+ else if (strcmp (name, "cntrl") == 0)
+ BUILD_CHARCLASS_LOOP (iscntrl)
+ else if (strcmp (name, "lower") == 0)
+ BUILD_CHARCLASS_LOOP (islower)
+ else if (strcmp (name, "space") == 0)
+ BUILD_CHARCLASS_LOOP (isspace)
+ else if (strcmp (name, "alpha") == 0)
+ BUILD_CHARCLASS_LOOP (isalpha)
+ else if (strcmp (name, "digit") == 0)
+ BUILD_CHARCLASS_LOOP (isdigit)
+ else if (strcmp (name, "print") == 0)
+ BUILD_CHARCLASS_LOOP (isprint)
+ else if (strcmp (name, "upper") == 0)
+ BUILD_CHARCLASS_LOOP (isupper)
+ else if (strcmp (name, "blank") == 0)
+ BUILD_CHARCLASS_LOOP (isblank)
+ else if (strcmp (name, "graph") == 0)
+ BUILD_CHARCLASS_LOOP (isgraph)
+ else if (strcmp (name, "punct") == 0)
+ BUILD_CHARCLASS_LOOP (ispunct)
+ else if (strcmp (name, "xdigit") == 0)
+ BUILD_CHARCLASS_LOOP (isxdigit)
+ else
+ return REG_ECTYPE;
+
+ return REG_NOERROR;
+}
+
+static bin_tree_t *
+build_charclass_op (re_dfa_t *dfa, unsigned REG_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra,
+ bool non_match, reg_errcode_t *err)
+{
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ Idx alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ reg_errcode_t ret;
+ re_token_t br_token;
+ bin_tree_t *tree;
+
+ sbcset = re_calloc (bitset_word, BITSET_WORDS);
+#ifdef RE_ENABLE_I18N
+ mbcset = re_calloc (re_charset_t, 1);
+#endif /* RE_ENABLE_I18N */
+
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else /* not RE_ENABLE_I18N */
+ if (BE (sbcset == NULL, 0))
+#endif /* not RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ if (non_match)
+ {
+#ifdef RE_ENABLE_I18N
+ /*
+ if (syntax & REG_HAT_LISTS_NOT_NEWLINE)
+ bitset_set(cset->sbcset, '\0');
+ */
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ }
+
+ /* We don't care the syntax in this case. */
+ ret = build_charclass (trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &alloc,
+#endif /* RE_ENABLE_I18N */
+ class_name, 0);
+
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = ret;
+ return NULL;
+ }
+ /* \w match '_' also. */
+ for (; *extra; extra++)
+ bitset_set (sbcset, *extra);
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+#endif
+
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (tree == NULL, 0))
+ goto build_word_op_espace;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ bin_tree_t *mbc_tree;
+ /* Build a tree for complex bracket. */
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ dfa->has_mb_node = 1;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto build_word_op_espace;
+ /* Then join them by ALT node. */
+ tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
+ if (BE (mbc_tree != NULL, 1))
+ return tree;
+ }
+ else
+ {
+ free_charset (mbcset);
+ return tree;
+ }
+#else /* not RE_ENABLE_I18N */
+ return tree;
+#endif /* not RE_ENABLE_I18N */
+
+ build_word_op_espace:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* This is intended for the expressions like "a{1,3}".
+ Fetch a number from `input', and return the number.
+ Return REG_MISSING if the number field is empty like "{,1}".
+ Return REG_ERROR if an error occurred. */
+
+static Idx
+fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
+{
+ Idx num = REG_MISSING;
+ unsigned char c;
+ while (1)
+ {
+ fetch_token (token, input, syntax);
+ c = token->opr.c;
+ if (BE (token->type == END_OF_RE, 0))
+ return REG_ERROR;
+ if (token->type == OP_CLOSE_DUP_NUM || c == ',')
+ break;
+ num = ((token->type != CHARACTER || c < '0' || '9' < c
+ || num == REG_ERROR)
+ ? REG_ERROR
+ : ((num == REG_MISSING) ? c - '0' : num * 10 + c - '0'));
+ num = (num > REG_DUP_MAX) ? REG_ERROR : num;
+ }
+ return num;
+}
+
+#ifdef RE_ENABLE_I18N
+static void
+free_charset (re_charset_t *cset)
+{
+ re_free (cset->mbchars);
+# ifdef _LIBC
+ re_free (cset->coll_syms);
+ re_free (cset->equiv_classes);
+ re_free (cset->range_starts);
+ re_free (cset->range_ends);
+# endif
+ re_free (cset->char_classes);
+ re_free (cset);
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Functions for binary tree operation. */
+
+/* Create a tree node. */
+
+static bin_tree_t *
+create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type)
+{
+ re_token_t t;
+ t.type = type;
+ return create_token_tree (dfa, left, right, &t);
+}
+
+static bin_tree_t *
+create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token)
+{
+ bin_tree_t *tree;
+ if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
+ {
+ bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
+
+ if (storage == NULL)
+ return NULL;
+ storage->next = dfa->str_tree_storage;
+ dfa->str_tree_storage = storage;
+ dfa->str_tree_storage_idx = 0;
+ }
+ tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
+
+ tree->parent = NULL;
+ tree->left = left;
+ tree->right = right;
+ tree->token = *token;
+ tree->token.duplicated = 0;
+ tree->token.opt_subexp = 0;
+ tree->first = NULL;
+ tree->next = NULL;
+ tree->node_idx = REG_MISSING;
+
+ if (left != NULL)
+ left->parent = tree;
+ if (right != NULL)
+ right->parent = tree;
+ return tree;
+}
+
+/* Mark the tree SRC as an optional subexpression.
+ To be called from preorder or postorder. */
+
+static reg_errcode_t
+mark_opt_subexp (void *extra, bin_tree_t *node)
+{
+ Idx idx = (Idx) (long) extra;
+ if (node->token.type == SUBEXP && node->token.opr.idx == idx)
+ node->token.opt_subexp = 1;
+
+ return REG_NOERROR;
+}
+
+/* Free the allocated memory inside NODE. */
+
+static void
+free_token (re_token_t *node)
+{
+#ifdef RE_ENABLE_I18N
+ if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
+ free_charset (node->opr.mbcset);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
+ re_free (node->opr.sbcset);
+}
+
+/* Worker function for tree walking. Free the allocated memory inside NODE
+ and its children. */
+
+static reg_errcode_t
+free_tree (void *extra, bin_tree_t *node)
+{
+ free_token (&node->token);
+ return REG_NOERROR;
+}
+
+
+/* Duplicate the node SRC, and return new node. This is a preorder
+ visit similar to the one implemented by the generic visitor, but
+ we need more infrastructure to maintain two parallel trees --- so,
+ it's easier to duplicate. */
+
+static bin_tree_t *
+duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa)
+{
+ const bin_tree_t *node;
+ bin_tree_t *dup_root;
+ bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
+
+ for (node = root; ; )
+ {
+ /* Create a new tree and link it back to the current parent. */
+ *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
+ if (*p_new == NULL)
+ return NULL;
+ (*p_new)->parent = dup_node;
+ (*p_new)->token.duplicated = 1;
+ dup_node = *p_new;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ {
+ node = node->left;
+ p_new = &dup_node->left;
+ }
+ else
+ {
+ const bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ dup_node = dup_node->parent;
+ if (!node)
+ return dup_root;
+ }
+ node = node->right;
+ p_new = &dup_node->right;
+ }
+ }
+}
diff --git a/lib/regex.c b/lib/regex.c
new file mode 100644
index 0000000..82e76c0
--- /dev/null
+++ b/lib/regex.c
@@ -0,0 +1,68 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+/* We have to keep the namespace clean. */
+# define regfree(preg) __regfree (preg)
+# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+# define regerror(errcode, preg, errbuf, errbuf_size) \
+ __regerror(errcode, preg, errbuf, errbuf_size)
+# define re_set_registers(bu, re, nu, st, en) \
+ __re_set_registers (bu, re, nu, st, en)
+# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+# define re_match(bufp, string, size, pos, regs) \
+ __re_match (bufp, string, size, pos, regs)
+# define re_search(bufp, string, size, startpos, range, regs) \
+ __re_search (bufp, string, size, startpos, range, regs)
+# define re_compile_pattern(pattern, length, bufp) \
+ __re_compile_pattern (pattern, length, bufp)
+# define re_set_syntax(syntax) __re_set_syntax (syntax)
+# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+# include "../locale/localeinfo.h"
+#endif
+
+/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
+ GNU regex allows. Include it before <regex.h>, which correctly
+ #undefs RE_DUP_MAX and sets it to the right value. */
+#include <limits.h>
+
+#include <regex.h>
+#include "regex_internal.h"
+
+#include "regex_internal.c"
+#include "regcomp.c"
+#include "regexec.c"
+
+/* Binary backward compatibility. */
+#if _LIBC
+# include <shlib-compat.h>
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
+link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
+int re_max_failures = 2000;
+# endif
+#endif
diff --git a/lib/regex.h b/lib/regex.h
new file mode 100644
index 0000000..c06a062
--- /dev/null
+++ b/lib/regex.h
@@ -0,0 +1,769 @@
+/* Definitions for data structures and routines for the regular
+ expression library.
+ Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+#include <sys/types.h>
+
+/* Allow the use in C++ code. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Define _REGEX_SOURCE to get definitions that are incompatible with
+ POSIX. */
+#if (!defined _REGEX_SOURCE \
+ && (defined _GNU_SOURCE \
+ || (!defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE \
+ && !defined _XOPEN_SOURCE)))
+# define _REGEX_SOURCE 1
+#endif
+
+#if defined _REGEX_SOURCE && defined VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+# include <stddef.h>
+#endif
+
+#ifdef _REGEX_LARGE_OFFSETS
+
+/* Use types and values that are wide enough to represent signed and
+ unsigned byte offsets in memory. This currently works only when
+ the regex code is used outside of the GNU C library; it is not yet
+ supported within glibc itself, and glibc users should not define
+ _REGEX_LARGE_OFFSETS. */
+
+/* The type of the offset of a byte within a string.
+ For historical reasons POSIX 1003.1-2004 requires that regoff_t be
+ at least as wide as off_t. This is a bit odd (and many common
+ POSIX platforms set it to the more-sensible ssize_t) but we might
+ as well conform. We don't know of any hosts where ssize_t is wider
+ than off_t, so off_t is safe. */
+typedef off_t regoff_t;
+
+/* The type of nonnegative object indexes. Traditionally, GNU regex
+ uses 'int' for these. Code that uses __re_idx_t should work
+ regardless of whether the type is signed. */
+typedef size_t __re_idx_t;
+
+/* The type of object sizes. */
+typedef size_t __re_size_t;
+
+/* The type of object sizes, in places where the traditional code
+ uses unsigned long int. */
+typedef size_t __re_long_size_t;
+
+#else
+
+/* Use types that are binary-compatible with the traditional GNU regex
+ implementation, which mishandles strings longer than INT_MAX. */
+
+typedef int regoff_t;
+typedef int __re_idx_t;
+typedef unsigned int __re_size_t;
+typedef unsigned long int __re_long_size_t;
+
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+ wide enough to hold a value of a pointer. For most ANSI compilers
+ ptrdiff_t and size_t should be likely OK. Still size of these two
+ types is 2 for Microsoft C. Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define REG_BACKSLASH_ESCAPE_IN_LISTS 1ul
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define REG_BK_PLUS_QM (1ul << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define REG_CHAR_CLASSES (1ul << 2)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with REG_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define REG_CONTEXT_INDEP_ANCHORS (1ul << 3)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define REG_CONTEXT_INDEP_OPS (1ul << 4)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define REG_CONTEXT_INVALID_OPS (1ul << 5)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define REG_DOT_NEWLINE (1ul << 6)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define REG_DOT_NOT_NULL (1ul << 7)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define REG_HAT_LISTS_NOT_NEWLINE (1ul << 8)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on REG_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define REG_INTERVALS (1ul << 9)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define REG_LIMITED_OPS (1ul << 10)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define REG_NEWLINE_ALT (1ul << 11)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define REG_NO_BK_BRACES (1ul << 12)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define REG_NO_BK_PARENS (1ul << 13)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define REG_NO_BK_REFS (1ul << 14)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define REG_NO_BK_VBAR (1ul << 15)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, the containing range is empty and does not match any string. */
+#define REG_NO_EMPTY_RANGES (1ul << 16)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define REG_UNMATCHED_RIGHT_PAREN_ORD (1ul << 17)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define REG_NO_POSIX_BACKTRACKING (1ul << 18)
+
+/* If this bit is set, do not process the GNU regex operators.
+ If not set, then the GNU regex operators are recognized. */
+#define REG_NO_GNU_OPS (1ul << 19)
+
+/* If this bit is set, turn on internal regex debugging.
+ If not set, and debugging was on, turn it off.
+ This only works if regex.c is compiled -DDEBUG.
+ We define this bit always, so that all that's needed to turn on
+ debugging is to recompile regex.c; the calling code can always have
+ this bit set, and it won't affect anything in the normal case. */
+#define REG_DEBUG (1ul << 20)
+
+/* If this bit is set, a syntactically invalid interval is treated as
+ a string of ordinary characters. For example, the ERE 'a{1' is
+ treated as 'a\{1'. */
+#define REG_INVALID_INTERVAL_ORD (1ul << 21)
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_IGNORE_CASE (1ul << 22)
+
+/* This bit is used internally like REG_CONTEXT_INDEP_ANCHORS but only
+ for ^, because it is difficult to scan the regex backwards to find
+ whether ^ should be special. */
+#define REG_CARET_ANCHORS_HERE (1ul << 23)
+
+/* If this bit is set, then \{ cannot be first in an bre or
+ immediately after an alternation or begin-group operator. */
+#define REG_CONTEXT_INVALID_DUP (1ul << 24)
+
+/* If this bit is set, then no_sub will be set to 1 during
+ re_compile_pattern. */
+#define REG_NO_SUB (1ul << 25)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define REG_SYNTAX_EMACS 0
+
+#define REG_SYNTAX_AWK \
+ (REG_BACKSLASH_ESCAPE_IN_LISTS | REG_DOT_NOT_NULL \
+ | REG_NO_BK_PARENS | REG_NO_BK_REFS \
+ | REG_NO_BK_VBAR | REG_NO_EMPTY_RANGES \
+ | REG_DOT_NEWLINE | REG_CONTEXT_INDEP_ANCHORS \
+ | REG_UNMATCHED_RIGHT_PAREN_ORD | REG_NO_GNU_OPS)
+
+#define REG_SYNTAX_GNU_AWK \
+ ((REG_SYNTAX_POSIX_EXTENDED | REG_BACKSLASH_ESCAPE_IN_LISTS \
+ | REG_DEBUG) \
+ & ~(REG_DOT_NOT_NULL | REG_INTERVALS | REG_CONTEXT_INDEP_OPS \
+ | REG_CONTEXT_INVALID_OPS ))
+
+#define REG_SYNTAX_POSIX_AWK \
+ (REG_SYNTAX_POSIX_EXTENDED | REG_BACKSLASH_ESCAPE_IN_LISTS \
+ | REG_INTERVALS | REG_NO_GNU_OPS)
+
+#define REG_SYNTAX_GREP \
+ (REG_BK_PLUS_QM | REG_CHAR_CLASSES \
+ | REG_HAT_LISTS_NOT_NEWLINE | REG_INTERVALS \
+ | REG_NEWLINE_ALT)
+
+#define REG_SYNTAX_EGREP \
+ (REG_CHAR_CLASSES | REG_CONTEXT_INDEP_ANCHORS \
+ | REG_CONTEXT_INDEP_OPS | REG_HAT_LISTS_NOT_NEWLINE \
+ | REG_NEWLINE_ALT | REG_NO_BK_PARENS \
+ | REG_NO_BK_VBAR)
+
+#define REG_SYNTAX_POSIX_EGREP \
+ (REG_SYNTAX_EGREP | REG_INTERVALS | REG_NO_BK_BRACES \
+ | REG_INVALID_INTERVAL_ORD)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define REG_SYNTAX_ED REG_SYNTAX_POSIX_BASIC
+
+#define REG_SYNTAX_SED REG_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _REG_SYNTAX_POSIX_COMMON \
+ (REG_CHAR_CLASSES | REG_DOT_NEWLINE | REG_DOT_NOT_NULL \
+ | REG_INTERVALS | REG_NO_EMPTY_RANGES)
+
+#define REG_SYNTAX_POSIX_BASIC \
+ (_REG_SYNTAX_POSIX_COMMON | REG_BK_PLUS_QM | REG_CONTEXT_INVALID_DUP)
+
+/* Differs from ..._POSIX_BASIC only in that REG_BK_PLUS_QM becomes
+ REG_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define REG_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_REG_SYNTAX_POSIX_COMMON | REG_LIMITED_OPS)
+
+#define REG_SYNTAX_POSIX_EXTENDED \
+ (_REG_SYNTAX_POSIX_COMMON | REG_CONTEXT_INDEP_ANCHORS \
+ | REG_CONTEXT_INDEP_OPS | REG_NO_BK_BRACES \
+ | REG_NO_BK_PARENS | REG_NO_BK_VBAR \
+ | REG_CONTEXT_INVALID_OPS | REG_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that REG_CONTEXT_INDEP_OPS is
+ removed and REG_NO_BK_REFS is added. */
+#define REG_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_REG_SYNTAX_POSIX_COMMON | REG_CONTEXT_INDEP_ANCHORS \
+ | REG_CONTEXT_INVALID_OPS | REG_NO_BK_BRACES \
+ | REG_NO_BK_PARENS | REG_NO_BK_REFS \
+ | REG_NO_BK_VBAR | REG_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. This is
+ distinct from RE_DUP_MAX, to conform to POSIX name space rules and
+ to avoid collisions with <limits.h>. */
+#define REG_DUP_MAX 32767
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (1 << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (1 << 2)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (1 << 3)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+/* Use PMATCH[0] to delimit the start and end of the search in the
+ buffer. */
+#define REG_STARTEND (1 << 2)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `__re_error_msgid' table in regcomp.c. */
+
+typedef enum
+{
+ _REG_ENOSYS = -1, /* This will never happen for this implementation. */
+#define REG_ENOSYS _REG_ENOSYS
+
+ _REG_NOERROR, /* Success. */
+#define REG_NOERROR _REG_NOERROR
+
+ _REG_NOMATCH, /* Didn't find a match (for regexec). */
+#define REG_NOMATCH _REG_NOMATCH
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+
+ _REG_BADPAT, /* Invalid pattern. */
+#define REG_BADPAT _REG_BADPAT
+
+ _REG_ECOLLATE, /* Inalid collating element. */
+#define REG_ECOLLATE _REG_ECOLLATE
+
+ _REG_ECTYPE, /* Invalid character class name. */
+#define REG_ECTYPE _REG_ECTYPE
+
+ _REG_EESCAPE, /* Trailing backslash. */
+#define REG_EESCAPE _REG_EESCAPE
+
+ _REG_ESUBREG, /* Invalid back reference. */
+#define REG_ESUBREG _REG_ESUBREG
+
+ _REG_EBRACK, /* Unmatched left bracket. */
+#define REG_EBRACK _REG_EBRACK
+
+ _REG_EPAREN, /* Parenthesis imbalance. */
+#define REG_EPAREN _REG_EPAREN
+
+ _REG_EBRACE, /* Unmatched \{. */
+#define REG_EBRACE _REG_EBRACE
+
+ _REG_BADBR, /* Invalid contents of \{\}. */
+#define REG_BADBR _REG_BADBR
+
+ _REG_ERANGE, /* Invalid range end. */
+#define REG_ERANGE _REG_ERANGE
+
+ _REG_ESPACE, /* Ran out of memory. */
+#define REG_ESPACE _REG_ESPACE
+
+ _REG_BADRPT, /* No preceding re for repetition op. */
+#define REG_BADRPT _REG_BADRPT
+
+ /* Error codes we've added. */
+
+ _REG_EEND, /* Premature end. */
+#define REG_EEND _REG_EEND
+
+ _REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+#define REG_ESIZE _REG_ESIZE
+
+ _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+#define REG_ERPAREN _REG_ERPAREN
+
+} reg_errcode_t;
+
+/* In the traditional GNU implementation, regex.h defined member names
+ like `buffer' that POSIX does not allow. These members now have
+ names with leading `re_' (e.g., `re_buffer'). Support the old
+ names only if _REGEX_SOURCE is defined. New programs should use
+ the new names. */
+#ifdef _REGEX_SOURCE
+# define _REG_RE_NAME(id) id
+# define _REG_RM_NAME(id) id
+#else
+# define _REG_RE_NAME(id) re_##id
+# define _REG_RM_NAME(id) rm_##id
+#endif
+
+/* The user can specify the type of the re_translate member by
+ defining the macro REG_TRANSLATE_TYPE. In the traditional GNU
+ implementation, this macro was named RE_TRANSLATE_TYPE, but POSIX
+ does not allow this. Support the old name only if _REGEX_SOURCE
+ and if the new name is not defined. New programs should use the new
+ name. */
+#ifndef REG_TRANSLATE_TYPE
+# if defined _REGEX_SOURCE && defined RE_TRANSLATE_TYPE
+# define REG_TRANSLATE_TYPE RE_TRANSLATE_TYPE
+# else
+# define REG_TRANSLATE_TYPE char *
+# endif
+#endif
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler), the fields `re_buffer', `re_allocated', `re_fastmap',
+ `re_translate', and `re_no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *_REG_RE_NAME (buffer);
+
+ /* Number of bytes to which `re_buffer' points. */
+ __re_long_size_t _REG_RE_NAME (allocated);
+
+ /* Number of bytes actually used in `re_buffer'. */
+ __re_long_size_t _REG_RE_NAME (used);
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t _REG_RE_NAME (syntax);
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *_REG_RE_NAME (fastmap);
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ REG_TRANSLATE_TYPE _REG_RE_NAME (translate);
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned int _REG_RE_NAME (can_be_null) : 1;
+
+ /* If REG_UNALLOCATED, allocate space in the `regs' structure
+ for `max (REG_NREGS, re_nsub + 1)' groups.
+ If REG_REALLOCATE, reallocate space if necessary.
+ If REG_FIXED, use what's there. */
+#define REG_UNALLOCATED 0
+#define REG_REALLOCATE 1
+#define REG_FIXED 2
+ unsigned int _REG_RE_NAME (regs_allocated) : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned int _REG_RE_NAME (fastmap_accurate) : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned int _REG_RE_NAME (no_sub) : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned int _REG_RE_NAME (not_bol) : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned int _REG_RE_NAME (not_eol) : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned int _REG_RE_NAME (newline_anchor) : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ __re_size_t _REG_RM_NAME (num_regs);
+ regoff_t *_REG_RM_NAME (start);
+ regoff_t *_REG_RM_NAME (end);
+};
+
+
+/* If `regs_allocated' is REG_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef REG_NREGS
+# define REG_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern (const char *__pattern, size_t __length,
+ struct re_pattern_buffer *__buffer);
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->re_no_sub are nonzero). */
+extern regoff_t re_search (struct re_pattern_buffer *__buffer,
+ const char *__string, __re_idx_t __length,
+ __re_idx_t __start, regoff_t __range,
+ struct re_registers *__regs);
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer,
+ const char *__string1, __re_idx_t __length1,
+ const char *__string2, __re_idx_t __length2,
+ __re_idx_t __start, regoff_t __range,
+ struct re_registers *__regs,
+ __re_idx_t __stop);
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern regoff_t re_match (struct re_pattern_buffer *__buffer,
+ const char *__string, __re_idx_t __length,
+ __re_idx_t __start, struct re_registers *__regs);
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer,
+ const char *__string1, __re_idx_t __length1,
+ const char *__string2, __re_idx_t __length2,
+ __re_idx_t __start, struct re_registers *__regs,
+ __re_idx_t __stop);
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void re_set_registers (struct re_pattern_buffer *__buffer,
+ struct re_registers *__regs,
+ __re_size_t __num_regs,
+ regoff_t *__starts, regoff_t *__ends);
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+# ifndef _CRAY
+/* 4.2 bsd compatibility. */
+extern char *re_comp (const char *);
+extern int re_exec (const char *);
+# endif
+#endif
+
+/* GCC 2.95 and later have "__restrict"; C99 compilers have
+ "restrict", and "configure" may have defined "restrict". */
+#ifndef __restrict
+# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
+# if defined restrict || 199901L <= __STDC_VERSION__
+# define __restrict restrict
+# else
+# define __restrict
+# endif
+# endif
+#endif
+/* gcc 3.1 and up support the [restrict] syntax, but g++ doesn't. */
+#ifndef __restrict_arr
+# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) && !defined __cplusplus
+# define __restrict_arr __restrict
+# else
+# define __restrict_arr
+# endif
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp (regex_t *__restrict __preg,
+ const char *__restrict __pattern,
+ int __cflags);
+
+extern int regexec (const regex_t *__restrict __preg,
+ const char *__restrict __string, size_t __nmatch,
+ regmatch_t __pmatch[__restrict_arr],
+ int __eflags);
+
+extern size_t regerror (int __errcode, const regex_t *__restrict __preg,
+ char *__restrict __errbuf, size_t __errbuf_size);
+
+extern void regfree (regex_t *__preg);
+
+
+#ifdef _REGEX_SOURCE
+
+/* Define the POSIX-compatible member names in terms of the
+ incompatible (and deprecated) names established by _REG_RE_NAME.
+ New programs should use the re_* names. */
+
+# define re_allocated allocated
+# define re_buffer buffer
+# define re_can_be_null can_be_null
+# define re_fastmap fastmap
+# define re_fastmap_accurate fastmap_accurate
+# define re_newline_anchor newline_anchor
+# define re_no_sub no_sub
+# define re_not_bol not_bol
+# define re_not_eol not_eol
+# define re_regs_allocated regs_allocated
+# define re_syntax syntax
+# define re_translate translate
+# define re_used used
+
+/* Similarly for _REG_RM_NAME. */
+
+# define rm_end end
+# define rm_num_regs num_regs
+# define rm_start start
+
+/* Undef RE_DUP_MAX first, in case the user has already included a
+ <limits.h> with an incompatible definition.
+
+ On GNU systems, the most common spelling for RE_DUP_MAX's value in
+ <limits.h> is (0x7ffff), so define RE_DUP_MAX to that, not to
+ REG_DUP_MAX. This avoid some duplicate-macro-definition warnings
+ with programs that include <limits.h> after this file.
+
+ New programs should not assume that regex.h defines RE_DUP_MAX; to
+ get the value of RE_DUP_MAX, they should instead include <limits.h>
+ and possibly invoke the sysconf function. */
+
+# undef RE_DUP_MAX
+# define RE_DUP_MAX (0x7fff)
+
+/* Define the following symbols for backward source compatibility.
+ These symbols violate the POSIX name space rules, and new programs
+ should avoid them. */
+
+# define REGS_FIXED REG_FIXED
+# define REGS_REALLOCATE REG_REALLOCATE
+# define REGS_UNALLOCATED REG_UNALLOCATED
+# define RE_BACKSLASH_ESCAPE_IN_LISTS REG_BACKSLASH_ESCAPE_IN_LISTS
+# define RE_BK_PLUS_QM REG_BK_PLUS_QM
+# define RE_CARET_ANCHORS_HERE REG_CARET_ANCHORS_HERE
+# define RE_CHAR_CLASSES REG_CHAR_CLASSES
+# define RE_CONTEXT_INDEP_ANCHORS REG_CONTEXT_INDEP_ANCHORS
+# define RE_CONTEXT_INDEP_OPS REG_CONTEXT_INDEP_OPS
+# define RE_CONTEXT_INVALID_DUP REG_CONTEXT_INVALID_DUP
+# define RE_CONTEXT_INVALID_OPS REG_CONTEXT_INVALID_OPS
+# define RE_DEBUG REG_DEBUG
+# define RE_DOT_NEWLINE REG_DOT_NEWLINE
+# define RE_DOT_NOT_NULL REG_DOT_NOT_NULL
+# define RE_HAT_LISTS_NOT_NEWLINE REG_HAT_LISTS_NOT_NEWLINE
+# define RE_ICASE REG_IGNORE_CASE /* avoid collision with REG_ICASE */
+# define RE_INTERVALS REG_INTERVALS
+# define RE_INVALID_INTERVAL_ORD REG_INVALID_INTERVAL_ORD
+# define RE_LIMITED_OPS REG_LIMITED_OPS
+# define RE_NEWLINE_ALT REG_NEWLINE_ALT
+# define RE_NO_BK_BRACES REG_NO_BK_BRACES
+# define RE_NO_BK_PARENS REG_NO_BK_PARENS
+# define RE_NO_BK_REFS REG_NO_BK_REFS
+# define RE_NO_BK_VBAR REG_NO_BK_VBAR
+# define RE_NO_EMPTY_RANGES REG_NO_EMPTY_RANGES
+# define RE_NO_GNU_OPS REG_NO_GNU_OPS
+# define RE_NO_POSIX_BACKTRACKING REG_NO_POSIX_BACKTRACKING
+# define RE_NO_SUB REG_NO_SUB
+# define RE_NREGS REG_NREGS
+# define RE_SYNTAX_AWK REG_SYNTAX_AWK
+# define RE_SYNTAX_ED REG_SYNTAX_ED
+# define RE_SYNTAX_EGREP REG_SYNTAX_EGREP
+# define RE_SYNTAX_EMACS REG_SYNTAX_EMACS
+# define RE_SYNTAX_GNU_AWK REG_SYNTAX_GNU_AWK
+# define RE_SYNTAX_GREP REG_SYNTAX_GREP
+# define RE_SYNTAX_POSIX_AWK REG_SYNTAX_POSIX_AWK
+# define RE_SYNTAX_POSIX_BASIC REG_SYNTAX_POSIX_BASIC
+# define RE_SYNTAX_POSIX_EGREP REG_SYNTAX_POSIX_EGREP
+# define RE_SYNTAX_POSIX_EXTENDED REG_SYNTAX_POSIX_EXTENDED
+# define RE_SYNTAX_POSIX_MINIMAL_BASIC REG_SYNTAX_POSIX_MINIMAL_BASIC
+# define RE_SYNTAX_POSIX_MINIMAL_EXTENDED REG_SYNTAX_POSIX_MINIMAL_EXTENDED
+# define RE_SYNTAX_SED REG_SYNTAX_SED
+# define RE_UNMATCHED_RIGHT_PAREN_ORD REG_UNMATCHED_RIGHT_PAREN_ORD
+# ifndef RE_TRANSLATE_TYPE
+# define RE_TRANSLATE_TYPE REG_TRANSLATE_TYPE
+# endif
+
+#endif /* defined _REGEX_SOURCE */
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
+
+#endif /* regex.h */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/lib/regex_internal.c b/lib/regex_internal.c
new file mode 100644
index 0000000..ad618cf
--- /dev/null
+++ b/lib/regex_internal.c
@@ -0,0 +1,1656 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+static void re_string_construct_common (const char *str, Idx len,
+ re_string_t *pstr,
+ REG_TRANSLATE_TYPE trans, bool icase,
+ const re_dfa_t *dfa) internal_function;
+static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ re_hashval_t hash) internal_function;
+static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int context,
+ re_hashval_t hash) internal_function;
+
+/* Functions for string operation. */
+
+/* This function allocate the buffers. It is necessary to call
+ re_string_reconstruct before using the object. */
+
+static reg_errcode_t
+internal_function
+re_string_allocate (re_string_t *pstr, const char *str, Idx len, Idx init_len,
+ REG_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ Idx init_buf_len;
+
+ /* Ensure at least one character fits into the buffers. */
+ if (init_len < dfa->mb_cur_max)
+ init_len = dfa->mb_cur_max;
+ init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ ret = re_string_realloc_buffers (pstr, init_buf_len);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ pstr->word_char = dfa->word_char;
+ pstr->word_ops_used = dfa->word_ops_used;
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+ pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
+ pstr->valid_raw_len = pstr->valid_len;
+ return REG_NOERROR;
+}
+
+/* This function allocate the buffers, and initialize them. */
+
+static reg_errcode_t
+internal_function
+re_string_construct (re_string_t *pstr, const char *str, Idx len,
+ REG_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ memset (pstr, '\0', sizeof (re_string_t));
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ if (len > 0)
+ {
+ ret = re_string_realloc_buffers (pstr, len + 1);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+
+ if (icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ if (pstr->valid_raw_len >= len)
+ break;
+ if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
+ break;
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (trans != NULL)
+ re_string_translate_buffer (pstr);
+ else
+ {
+ pstr->valid_len = pstr->bufs_len;
+ pstr->valid_raw_len = pstr->bufs_len;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions for re_string_allocate, and re_string_construct. */
+
+static reg_errcode_t
+internal_function
+re_string_realloc_buffers (re_string_t *pstr, Idx new_buf_len)
+{
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ wint_t *new_wcs = re_xrealloc (pstr->wcs, wint_t, new_buf_len);
+ if (BE (new_wcs == NULL, 0))
+ return REG_ESPACE;
+ pstr->wcs = new_wcs;
+ if (pstr->offsets != NULL)
+ {
+ Idx *new_offsets = re_xrealloc (pstr->offsets, Idx, new_buf_len);
+ if (BE (new_offsets == NULL, 0))
+ return REG_ESPACE;
+ pstr->offsets = new_offsets;
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ {
+ unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char,
+ new_buf_len);
+ if (BE (new_mbs == NULL, 0))
+ return REG_ESPACE;
+ pstr->mbs = new_mbs;
+ }
+ pstr->bufs_len = new_buf_len;
+ return REG_NOERROR;
+}
+
+
+static void
+internal_function
+re_string_construct_common (const char *str, Idx len, re_string_t *pstr,
+ REG_TRANSLATE_TYPE trans, bool icase,
+ const re_dfa_t *dfa)
+{
+ pstr->raw_mbs = (const unsigned char *) str;
+ pstr->len = len;
+ pstr->raw_len = len;
+ pstr->trans = (unsigned REG_TRANSLATE_TYPE) trans;
+ pstr->icase = icase;
+ pstr->mbs_allocated = (trans != NULL || icase);
+ pstr->mb_cur_max = dfa->mb_cur_max;
+ pstr->is_utf8 = dfa->is_utf8;
+ pstr->map_notascii = dfa->map_notascii;
+ pstr->stop = pstr->len;
+ pstr->raw_stop = pstr->stop;
+}
+
+#ifdef RE_ENABLE_I18N
+
+/* Build wide character buffer PSTR->WCS.
+ If the byte sequence of the string are:
+ <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
+ Then wide character buffer will be:
+ <wc1> , WEOF , <wc2> , WEOF , <wc3>
+ We use WEOF for padding, they indicate that the position isn't
+ a first byte of a multibyte character.
+
+ Note that this function assumes PSTR->VALID_LEN elements are already
+ built and starts from PSTR->VALID_LEN. */
+
+static void
+internal_function
+build_wcs_buffer (re_string_t *pstr)
+{
+#ifdef _LIBC
+ unsigned char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ unsigned char buf[64];
+#endif
+ mbstate_t prev_st;
+ Idx byte_idx, end_idx, remain_len;
+ size_t mbclen;
+
+ /* Build the buffers from pstr->valid_len to either pstr->len or
+ pstr->bufs_len. */
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+ for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ /* Apply the translation if we need. */
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
+ buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2, 0))
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ if (BE (pstr->trans != NULL, 0))
+ wc = pstr->trans[wc];
+ pstr->cur_state = prev_st;
+ }
+
+ /* Write wide character and padding. */
+ pstr->wcs[byte_idx++] = wc;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+}
+
+/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
+ but for REG_ICASE. */
+
+static reg_errcode_t
+internal_function
+build_wcs_upper_buffer (re_string_t *pstr)
+{
+ mbstate_t prev_st;
+ Idx src_idx, byte_idx, end_idx, remain_len;
+ size_t mbclen;
+#ifdef _LIBC
+ char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ char buf[64];
+#endif
+
+ byte_idx = pstr->valid_len;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ /* The following optimization assumes that ASCII characters can be
+ mapped to wide characters with a simple cast. */
+ if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
+ {
+ while (byte_idx < end_idx)
+ {
+ wchar_t wc;
+
+ if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
+ && mbsinit (&pstr->cur_state))
+ {
+ /* In case of a singlebyte character. */
+ pstr->mbs[byte_idx]
+ = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
+ /* The next step uses the assumption that wchar_t is encoded
+ ASCII-safe: all ASCII values can be converted like this. */
+ pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
+ ++byte_idx;
+ continue;
+ }
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc,
+ ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
+ + byte_idx), remain_len, &pstr->cur_state);
+ if (BE ((size_t) (mbclen + 2) > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb (buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else
+ {
+ src_idx = byte_idx;
+ goto offsets_needed;
+ }
+ }
+ else
+ memcpy (pstr->mbs + byte_idx,
+ pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ pstr->mbs[byte_idx] = ch;
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+ return REG_NOERROR;
+ }
+ else
+ for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+ offsets_needed:
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
+ buf[i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE ((size_t) (mbclen + 2) > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else if (mbcdlen != (size_t) -1)
+ {
+ size_t i;
+
+ if (byte_idx + mbcdlen > pstr->bufs_len)
+ {
+ pstr->cur_state = prev_st;
+ break;
+ }
+
+ if (pstr->offsets == NULL)
+ {
+ pstr->offsets = re_xmalloc (Idx, pstr->bufs_len);
+
+ if (pstr->offsets == NULL)
+ return REG_ESPACE;
+ }
+ if (!pstr->offsets_needed)
+ {
+ for (i = 0; i < (size_t) byte_idx; ++i)
+ pstr->offsets[i] = i;
+ pstr->offsets_needed = 1;
+ }
+
+ memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
+ pstr->wcs[byte_idx] = wcu;
+ pstr->offsets[byte_idx] = src_idx;
+ for (i = 1; i < mbcdlen; ++i)
+ {
+ pstr->offsets[byte_idx + i]
+ = src_idx + (i < mbclen ? i : mbclen - 1);
+ pstr->wcs[byte_idx + i] = WEOF;
+ }
+ pstr->len += mbcdlen - mbclen;
+ if (pstr->raw_stop > src_idx)
+ pstr->stop += mbcdlen - mbclen;
+ end_idx = (pstr->bufs_len > pstr->len)
+ ? pstr->len : pstr->bufs_len;
+ byte_idx += mbcdlen;
+ src_idx += mbclen;
+ continue;
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ {
+ size_t i;
+ for (i = 0; i < mbclen; ++i)
+ pstr->offsets[byte_idx + i] = src_idx + i;
+ }
+ src_idx += mbclen;
+
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
+
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans [ch];
+ pstr->mbs[byte_idx] = ch;
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ pstr->offsets[byte_idx] = src_idx;
+ ++src_idx;
+
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = src_idx;
+ return REG_NOERROR;
+}
+
+/* Skip characters until the index becomes greater than NEW_RAW_IDX.
+ Return the index. */
+
+static Idx
+internal_function
+re_string_skip_chars (re_string_t *pstr, Idx new_raw_idx, wint_t *last_wc)
+{
+ mbstate_t prev_st;
+ Idx rawbuf_idx;
+ size_t mbclen;
+ wchar_t wc = 0;
+
+ /* Skip the characters which are not necessary to check. */
+ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
+ rawbuf_idx < new_raw_idx;)
+ {
+ Idx remain_len;
+ remain_len = pstr->len - rawbuf_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc, (const char *) pstr->raw_mbs + rawbuf_idx,
+ remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ pstr->cur_state = prev_st;
+ }
+ /* Then proceed the next character. */
+ rawbuf_idx += mbclen;
+ }
+ *last_wc = (wint_t) wc;
+ return rawbuf_idx;
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Build the buffer PSTR->MBS, and apply the translation if we need.
+ This function is used in case of REG_ICASE. */
+
+static void
+internal_function
+build_upper_buffer (re_string_t *pstr)
+{
+ Idx char_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans[ch];
+ if (islower (ch))
+ pstr->mbs[char_idx] = toupper (ch);
+ else
+ pstr->mbs[char_idx] = ch;
+ }
+ pstr->valid_len = char_idx;
+ pstr->valid_raw_len = char_idx;
+}
+
+/* Apply TRANS to the buffer in PSTR. */
+
+static void
+internal_function
+re_string_translate_buffer (re_string_t *pstr)
+{
+ Idx buf_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
+ pstr->mbs[buf_idx] = pstr->trans[ch];
+ }
+
+ pstr->valid_len = buf_idx;
+ pstr->valid_raw_len = buf_idx;
+}
+
+/* This function re-construct the buffers.
+ Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
+ convert to upper case in case of REG_ICASE, apply translation. */
+
+static reg_errcode_t
+internal_function
+re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags)
+{
+ Idx offset;
+
+ if (BE (pstr->raw_mbs_idx <= idx, 0))
+ offset = idx - pstr->raw_mbs_idx;
+ else
+ {
+ /* Reset buffer. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+#endif /* RE_ENABLE_I18N */
+ pstr->len = pstr->raw_len;
+ pstr->stop = pstr->raw_stop;
+ pstr->valid_len = 0;
+ pstr->raw_mbs_idx = 0;
+ pstr->valid_raw_len = 0;
+ pstr->offsets_needed = 0;
+ pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
+ if (!pstr->mbs_allocated)
+ pstr->mbs = (unsigned char *) pstr->raw_mbs;
+ offset = idx;
+ }
+
+ if (BE (offset != 0, 1))
+ {
+ /* Are the characters which are already checked remain? */
+ if (BE (offset < pstr->valid_raw_len, 1)
+#ifdef RE_ENABLE_I18N
+ /* Handling this would enlarge the code too much.
+ Accept a slowdown in that case. */
+ && pstr->offsets_needed == 0
+#endif
+ )
+ {
+ /* Yes, move them to the front of the buffer. */
+ pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags);
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ memmove (pstr->mbs, pstr->mbs + offset,
+ pstr->valid_len - offset);
+ pstr->valid_len -= offset;
+ pstr->valid_raw_len -= offset;
+#if DEBUG
+ assert (pstr->valid_len > 0);
+#endif
+ }
+ else
+ {
+ /* No, skip all characters until IDX. */
+#ifdef RE_ENABLE_I18N
+ if (BE (pstr->offsets_needed, 0))
+ {
+ pstr->len = pstr->raw_len - idx + offset;
+ pstr->stop = pstr->raw_stop - idx + offset;
+ pstr->offsets_needed = 0;
+ }
+#endif
+ pstr->valid_len = 0;
+ pstr->valid_raw_len = 0;
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ Idx wcs_idx;
+ wint_t wc = WEOF;
+
+ if (pstr->is_utf8)
+ {
+ const unsigned char *raw, *p, *q, *end;
+
+ /* Special case UTF-8. Multi-byte chars start with any
+ byte other than 0x80 - 0xbf. */
+ raw = pstr->raw_mbs + pstr->raw_mbs_idx;
+ end = raw + (offset - pstr->mb_cur_max);
+ for (p = raw + offset - 1; p >= end; --p)
+ if ((*p & 0xc0) != 0x80)
+ {
+ mbstate_t cur_state;
+ wchar_t wc2;
+ Idx mlen = raw + pstr->len - p;
+ unsigned char buf[6];
+ size_t mbclen;
+
+ q = p;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i = mlen < 6 ? mlen : 6;
+ while (--i >= 0)
+ buf[i] = pstr->trans[p[i]];
+ q = buf;
+ }
+ /* XXX Don't use mbrtowc, we know which conversion
+ to use (UTF-8 -> UCS4). */
+ memset (&cur_state, 0, sizeof (cur_state));
+ mbclen = mbrtowc (&wc2, (const char *) p, mlen,
+ &cur_state);
+ if (raw + offset - p <= mbclen && mbclen < (size_t) -2)
+ {
+ memset (&pstr->cur_state, '\0',
+ sizeof (mbstate_t));
+ pstr->valid_len = mbclen - (raw + offset - p);
+ wc = wc2;
+ }
+ break;
+ }
+ }
+
+ if (wc == WEOF)
+ pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
+ if (BE (pstr->valid_len, 0))
+ {
+ for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
+ pstr->wcs[wcs_idx] = WEOF;
+ if (pstr->mbs_allocated)
+ memset (pstr->mbs, -1, pstr->valid_len);
+ }
+ pstr->valid_raw_len = pstr->valid_len;
+ pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
+ && IS_WIDE_WORD_CHAR (wc))
+ ? CONTEXT_WORD
+ : ((IS_WIDE_NEWLINE (wc)
+ && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
+ if (pstr->trans)
+ c = pstr->trans[c];
+ pstr->tip_context = (bitset_contain (pstr->word_char, c)
+ ? CONTEXT_WORD
+ : ((IS_NEWLINE (c) && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ }
+ if (!BE (pstr->mbs_allocated, 0))
+ pstr->mbs += offset;
+ }
+ pstr->raw_mbs_idx = idx;
+ pstr->len -= offset;
+ pstr->stop -= offset;
+
+ /* Then build the buffers. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ if (pstr->icase)
+ {
+ reg_errcode_t ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+ build_wcs_buffer (pstr);
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ {
+ if (pstr->icase)
+ build_upper_buffer (pstr);
+ else if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ else
+ pstr->valid_len = pstr->len;
+
+ pstr->cur_idx = 0;
+ return REG_NOERROR;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_peek_byte_case (const re_string_t *pstr, Idx idx)
+{
+ int ch;
+ Idx off;
+
+ /* Handle the common (easiest) cases first. */
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_peek_byte (pstr, idx);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1
+ && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ off = pstr->cur_idx + idx;
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ off = pstr->offsets[off];
+#endif
+
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
+ this function returns CAPITAL LETTER I instead of first byte of
+ DOTLESS SMALL LETTER I. The latter would confuse the parser,
+ since peek_byte_case doesn't advance cur_idx in any way. */
+ if (pstr->offsets_needed && !isascii (ch))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ return ch;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_fetch_byte_case (re_string_t *pstr)
+{
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_fetch_byte (pstr);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ {
+ Idx off;
+ int ch;
+
+ /* For tr_TR.UTF-8 [[:islower:]] there is
+ [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
+ in that case the whole multi-byte character and return
+ the original letter. On the other side, with
+ [[: DOTLESS SMALL LETTER I return [[:I, as doing
+ anything else would complicate things too much. */
+
+ if (!re_string_first_byte (pstr, pstr->cur_idx))
+ return re_string_fetch_byte (pstr);
+
+ off = pstr->offsets[pstr->cur_idx];
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+ if (! isascii (ch))
+ return re_string_fetch_byte (pstr);
+
+ re_string_skip_bytes (pstr,
+ re_string_char_size_at (pstr, pstr->cur_idx));
+ return ch;
+ }
+#endif
+
+ return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
+}
+
+static void
+internal_function
+re_string_destruct (re_string_t *pstr)
+{
+#ifdef RE_ENABLE_I18N
+ re_free (pstr->wcs);
+ re_free (pstr->offsets);
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ re_free (pstr->mbs);
+}
+
+/* Return the context at IDX in INPUT. */
+
+static unsigned int
+internal_function
+re_string_context_at (const re_string_t *input, Idx idx, int eflags)
+{
+ int c;
+ if (BE (! REG_VALID_INDEX (idx), 0))
+ /* In this case, we use the value stored in input->tip_context,
+ since we can't know the character in input->mbs[-1] here. */
+ return input->tip_context;
+ if (BE (idx == input->len, 0))
+ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
+ : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc;
+ Idx wc_idx = idx;
+ while(input->wcs[wc_idx] == WEOF)
+ {
+#ifdef DEBUG
+ /* It must not happen. */
+ assert (REG_VALID_INDEX (wc_idx));
+#endif
+ --wc_idx;
+ if (! REG_VALID_INDEX (wc_idx))
+ return input->tip_context;
+ }
+ wc = input->wcs[wc_idx];
+ if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
+ return CONTEXT_WORD;
+ return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
+ ? CONTEXT_NEWLINE : 0);
+ }
+ else
+#endif
+ {
+ c = re_string_byte_at (input, idx);
+ if (bitset_contain (input->word_char, c))
+ return CONTEXT_WORD;
+ return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
+ }
+}
+
+/* Functions for set operation. */
+
+static reg_errcode_t
+internal_function
+re_node_set_alloc (re_node_set *set, Idx size)
+{
+ set->alloc = size;
+ set->nelem = 0;
+ set->elems = re_xmalloc (Idx, size);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_1 (re_node_set *set, Idx elem)
+{
+ set->alloc = 1;
+ set->nelem = 1;
+ set->elems = re_malloc (Idx, 1);
+ if (BE (set->elems == NULL, 0))
+ {
+ set->alloc = set->nelem = 0;
+ return REG_ESPACE;
+ }
+ set->elems[0] = elem;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_2 (re_node_set *set, Idx elem1, Idx elem2)
+{
+ set->alloc = 2;
+ set->elems = re_malloc (Idx, 2);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ if (elem1 == elem2)
+ {
+ set->nelem = 1;
+ set->elems[0] = elem1;
+ }
+ else
+ {
+ set->nelem = 2;
+ if (elem1 < elem2)
+ {
+ set->elems[0] = elem1;
+ set->elems[1] = elem2;
+ }
+ else
+ {
+ set->elems[0] = elem2;
+ set->elems[1] = elem1;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_copy (re_node_set *dest, const re_node_set *src)
+{
+ dest->nelem = src->nelem;
+ if (src->nelem > 0)
+ {
+ dest->alloc = dest->nelem;
+ dest->elems = re_malloc (Idx, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ {
+ dest->alloc = dest->nelem = 0;
+ return REG_ESPACE;
+ }
+ memcpy (dest->elems, src->elems, src->nelem * sizeof dest->elems[0]);
+ }
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+}
+
+/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded.
+ Note: We assume dest->elems is NULL, when dest->alloc is 0. */
+
+static reg_errcode_t
+internal_function
+re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ Idx i1, i2, is, id, delta, sbase;
+ if (src1->nelem == 0 || src2->nelem == 0)
+ return REG_NOERROR;
+
+ /* We need dest->nelem + 2 * elems_in_intersection; this is a
+ conservative estimate. */
+ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
+ {
+ Idx new_alloc = src1->nelem + src2->nelem + dest->alloc;
+ Idx *new_elems;
+ if (sizeof (Idx) < 3
+ && (new_alloc < dest->alloc
+ || ((Idx) (src1->nelem + src2->nelem) < src1->nelem)))
+ return REG_ESPACE;
+ new_elems = re_xrealloc (dest->elems, Idx, new_alloc);
+ if (BE (new_elems == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_elems;
+ dest->alloc = new_alloc;
+ }
+
+ /* Find the items in the intersection of SRC1 and SRC2, and copy
+ into the top of DEST those that are not already in DEST itself. */
+ sbase = dest->nelem + src1->nelem + src2->nelem;
+ i1 = src1->nelem - 1;
+ i2 = src2->nelem - 1;
+ id = dest->nelem - 1;
+ for (;;)
+ {
+ if (src1->elems[i1] == src2->elems[i2])
+ {
+ /* Try to find the item in DEST. Maybe we could binary search? */
+ while (REG_VALID_INDEX (id) && dest->elems[id] > src1->elems[i1])
+ --id;
+
+ if (! REG_VALID_INDEX (id) || dest->elems[id] != src1->elems[i1])
+ dest->elems[--sbase] = src1->elems[i1];
+
+ if (! REG_VALID_INDEX (--i1) || ! REG_VALID_INDEX (--i2))
+ break;
+ }
+
+ /* Lower the highest of the two items. */
+ else if (src1->elems[i1] < src2->elems[i2])
+ {
+ if (! REG_VALID_INDEX (--i2))
+ break;
+ }
+ else
+ {
+ if (! REG_VALID_INDEX (--i1))
+ break;
+ }
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + src1->nelem + src2->nelem - 1;
+ delta = is - sbase + 1;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place; this is more or
+ less the same loop that is in re_node_set_merge. */
+ dest->nelem += delta;
+ if (delta > 0 && REG_VALID_INDEX (id))
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (! REG_VALID_INDEX (--id))
+ break;
+ }
+ }
+
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase, delta * sizeof dest->elems[0]);
+
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets SRC1 and SRC2. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_init_union (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ Idx i1, i2, id;
+ if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
+ {
+ dest->alloc = src1->nelem + src2->nelem;
+ if (sizeof (Idx) < 2 && dest->alloc < src1->nelem)
+ return REG_ESPACE;
+ dest->elems = re_xmalloc (Idx, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ return REG_ESPACE;
+ }
+ else
+ {
+ if (src1 != NULL && src1->nelem > 0)
+ return re_node_set_init_copy (dest, src1);
+ else if (src2 != NULL && src2->nelem > 0)
+ return re_node_set_init_copy (dest, src2);
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+ }
+ for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
+ {
+ if (src1->elems[i1] > src2->elems[i2])
+ {
+ dest->elems[id++] = src2->elems[i2++];
+ continue;
+ }
+ if (src1->elems[i1] == src2->elems[i2])
+ ++i2;
+ dest->elems[id++] = src1->elems[i1++];
+ }
+ if (i1 < src1->nelem)
+ {
+ memcpy (dest->elems + id, src1->elems + i1,
+ (src1->nelem - i1) * sizeof dest->elems[0]);
+ id += src1->nelem - i1;
+ }
+ else if (i2 < src2->nelem)
+ {
+ memcpy (dest->elems + id, src2->elems + i2,
+ (src2->nelem - i2) * sizeof dest->elems[0]);
+ id += src2->nelem - i2;
+ }
+ dest->nelem = id;
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets DEST and SRC. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_merge (re_node_set *dest, const re_node_set *src)
+{
+ Idx is, id, sbase, delta;
+ if (src == NULL || src->nelem == 0)
+ return REG_NOERROR;
+ if (sizeof (Idx) < 3
+ && ((Idx) (2 * src->nelem) < src->nelem
+ || (Idx) (2 * src->nelem + dest->nelem) < dest->nelem))
+ return REG_ESPACE;
+ if (dest->alloc < 2 * src->nelem + dest->nelem)
+ {
+ Idx new_alloc = src->nelem + dest->alloc;
+ Idx *new_buffer;
+ if (sizeof (Idx) < 4 && new_alloc < dest->alloc)
+ return REG_ESPACE;
+ new_buffer = re_x2realloc (dest->elems, Idx, &new_alloc);
+ if (BE (new_buffer == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_buffer;
+ dest->alloc = new_alloc;
+ }
+
+ if (BE (dest->nelem == 0, 0))
+ {
+ dest->nelem = src->nelem;
+ memcpy (dest->elems, src->elems, src->nelem * sizeof dest->elems[0]);
+ return REG_NOERROR;
+ }
+
+ /* Copy into the top of DEST the items of SRC that are not
+ found in DEST. Maybe we could binary search in DEST? */
+ for (sbase = dest->nelem + 2 * src->nelem,
+ is = src->nelem - 1, id = dest->nelem - 1;
+ REG_VALID_INDEX (is) && REG_VALID_INDEX (id); )
+ {
+ if (dest->elems[id] == src->elems[is])
+ is--, id--;
+ else if (dest->elems[id] < src->elems[is])
+ dest->elems[--sbase] = src->elems[is--];
+ else /* if (dest->elems[id] > src->elems[is]) */
+ --id;
+ }
+
+ if (REG_VALID_INDEX (is))
+ {
+ /* If DEST is exhausted, the remaining items of SRC must be unique. */
+ sbase -= is + 1;
+ memcpy (dest->elems + sbase, src->elems,
+ (is + 1) * sizeof dest->elems[0]);
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + 2 * src->nelem - 1;
+ delta = is - sbase + 1;
+ if (delta == 0)
+ return REG_NOERROR;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place. */
+ dest->nelem += delta;
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (! REG_VALID_INDEX (--id))
+ {
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase,
+ delta * sizeof dest->elems[0]);
+ break;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have ELEM.
+ Return true if successful. */
+
+static bool
+internal_function
+re_node_set_insert (re_node_set *set, Idx elem)
+{
+ Idx idx;
+ /* In case the set is empty. */
+ if (set->alloc == 0)
+ return re_node_set_init_1 (set, elem) == REG_NOERROR;
+
+ if (BE (set->nelem, 0) == 0)
+ {
+ /* We already guaranteed above that set->alloc != 0. */
+ set->elems[0] = elem;
+ ++set->nelem;
+ return true;
+ }
+
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ Idx *new_elems = re_x2realloc (set->elems, Idx, &set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return false;
+ set->elems = new_elems;
+ }
+
+ /* Move the elements which follows the new element. Test the
+ first element separately to skip a check in the inner loop. */
+ if (elem < set->elems[0])
+ {
+ idx = 0;
+ for (idx = set->nelem; idx > 0; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+ else
+ {
+ for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+
+ /* Insert the new element. */
+ set->elems[idx] = elem;
+ ++set->nelem;
+ return true;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have any element greater than or equal to ELEM.
+ Return true if successful. */
+
+static bool
+internal_function
+re_node_set_insert_last (re_node_set *set, Idx elem)
+{
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ Idx *new_elems;
+ new_elems = re_x2realloc (set->elems, Idx, &set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return false;
+ set->elems = new_elems;
+ }
+
+ /* Insert the new element. */
+ set->elems[set->nelem++] = elem;
+ return true;
+}
+
+/* Compare two node sets SET1 and SET2.
+ Return true if SET1 and SET2 are equivalent. */
+
+static bool
+internal_function __attribute ((pure))
+re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
+{
+ Idx i;
+ if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
+ return false;
+ for (i = set1->nelem ; REG_VALID_INDEX (--i) ; )
+ if (set1->elems[i] != set2->elems[i])
+ return false;
+ return true;
+}
+
+/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
+
+static Idx
+internal_function __attribute ((pure))
+re_node_set_contains (const re_node_set *set, Idx elem)
+{
+ __re_size_t idx, right, mid;
+ if (! REG_VALID_NONZERO_INDEX (set->nelem))
+ return 0;
+
+ /* Binary search the element. */
+ idx = 0;
+ right = set->nelem - 1;
+ while (idx < right)
+ {
+ mid = (idx + right) / 2;
+ if (set->elems[mid] < elem)
+ idx = mid + 1;
+ else
+ right = mid;
+ }
+ return set->elems[idx] == elem ? idx + 1 : 0;
+}
+
+static void
+internal_function
+re_node_set_remove_at (re_node_set *set, Idx idx)
+{
+ if (idx < 0 || idx >= set->nelem)
+ return;
+ --set->nelem;
+ for (; idx < set->nelem; idx++)
+ set->elems[idx] = set->elems[idx + 1];
+}
+
+
+/* Add the token TOKEN to dfa->nodes, and return the index of the token.
+ Or return REG_MISSING if an error occurred. */
+
+static Idx
+internal_function
+re_dfa_add_node (re_dfa_t *dfa, re_token_t token)
+{
+ int type = token.type;
+ if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
+ {
+ Idx new_nodes_alloc = dfa->nodes_alloc;
+ Idx *new_nexts, *new_indices;
+ re_node_set *new_edests, *new_eclosures;
+
+ re_token_t *new_nodes = re_x2realloc (dfa->nodes, re_token_t,
+ &new_nodes_alloc);
+ if (BE (new_nodes == NULL, 0))
+ return REG_MISSING;
+ dfa->nodes = new_nodes;
+ new_nexts = re_realloc (dfa->nexts, Idx, new_nodes_alloc);
+ new_indices = re_realloc (dfa->org_indices, Idx, new_nodes_alloc);
+ new_edests = re_xrealloc (dfa->edests, re_node_set, new_nodes_alloc);
+ new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
+ if (BE (new_nexts == NULL || new_indices == NULL
+ || new_edests == NULL || new_eclosures == NULL, 0))
+ return REG_MISSING;
+ dfa->nexts = new_nexts;
+ dfa->org_indices = new_indices;
+ dfa->edests = new_edests;
+ dfa->eclosures = new_eclosures;
+ dfa->nodes_alloc = new_nodes_alloc;
+ }
+ dfa->nodes[dfa->nodes_len] = token;
+ dfa->nodes[dfa->nodes_len].constraint = 0;
+#ifdef RE_ENABLE_I18N
+ dfa->nodes[dfa->nodes_len].accept_mb =
+ (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET;
+#endif
+ dfa->nexts[dfa->nodes_len] = REG_MISSING;
+ re_node_set_init_empty (dfa->edests + dfa->nodes_len);
+ re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
+ return dfa->nodes_len++;
+}
+
+static inline re_hashval_t
+internal_function
+calc_state_hash (const re_node_set *nodes, unsigned int context)
+{
+ re_hashval_t hash = nodes->nelem + context;
+ Idx i;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ hash += nodes->elems[i];
+ return hash;
+}
+
+/* Search for the state whose node_set is equivalent to NODES.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t*
+internal_function
+re_acquire_state (reg_errcode_t *err, re_dfa_t *dfa, const re_node_set *nodes)
+{
+ re_hashval_t hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ Idx i;
+#ifdef lint
+ /* Suppress bogus uninitialized-variable warnings. */
+ *err = REG_NOERROR;
+#endif
+ if (BE (nodes->nelem == 0, 0))
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, 0);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (hash != state->hash)
+ continue;
+ if (re_node_set_compare (&state->nodes, nodes))
+ return state;
+ }
+
+ /* There are no appropriate state in the dfa, create the new one. */
+ new_state = create_ci_newstate (dfa, nodes, hash);
+ if (BE (new_state != NULL, 1))
+ return new_state;
+ else
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+}
+
+/* Search for the state whose node_set is equivalent to NODES and
+ whose context is equivalent to CONTEXT.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t*
+internal_function
+re_acquire_state_context (reg_errcode_t *err, re_dfa_t *dfa,
+ const re_node_set *nodes, unsigned int context)
+{
+ re_hashval_t hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ Idx i;
+#ifdef lint
+ /* Suppress bogus uninitialized-variable warnings. */
+ *err = REG_NOERROR;
+#endif
+ if (nodes->nelem == 0)
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, context);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (state->hash == hash
+ && state->context == context
+ && re_node_set_compare (state->entrance_nodes, nodes))
+ return state;
+ }
+ /* There are no appropriate state in `dfa', create the new one. */
+ new_state = create_cd_newstate (dfa, nodes, context, hash);
+ if (BE (new_state != NULL, 1))
+ return new_state;
+ else
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+}
+
+/* Finish initialization of the new state NEWSTATE, and using its hash value
+ HASH put in the appropriate bucket of DFA's state table. Return value
+ indicates the error code if failed. */
+
+static reg_errcode_t
+internal_function
+register_state (const re_dfa_t *dfa, re_dfastate_t *newstate, re_hashval_t hash)
+{
+ struct re_state_table_entry *spot;
+ reg_errcode_t err;
+ Idx i;
+
+ newstate->hash = hash;
+ err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < newstate->nodes.nelem; i++)
+ {
+ Idx elem = newstate->nodes.elems[i];
+ if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
+ {
+ bool ok = re_node_set_insert_last (&newstate->non_eps_nodes, elem);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+ }
+
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+ if (BE (spot->alloc <= spot->num, 0))
+ {
+ Idx new_alloc = spot->num;
+ re_dfastate_t **new_array = re_x2realloc (spot->array, re_dfastate_t *,
+ &new_alloc);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ spot->array = new_array;
+ spot->alloc = new_alloc;
+ }
+ spot->array[spot->num++] = newstate;
+ return REG_NOERROR;
+}
+
+/* Create the new state which is independ of contexts.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ re_hashval_t hash)
+{
+ Idx i;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = re_calloc (re_dfastate_t, 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->entrance_nodes = &newstate->nodes;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (type == CHARACTER && !node->constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR || node->constraint)
+ newstate->has_constraint = 1;
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
+
+/* Create the new state which is depend on the context CONTEXT.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ unsigned int context, re_hashval_t hash)
+{
+ Idx i, nctx_nodes = 0;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = re_calloc (re_dfastate_t, 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->context = context;
+ newstate->entrance_nodes = &newstate->nodes;
+
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ unsigned int constraint = 0;
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (node->constraint)
+ constraint = node->constraint;
+
+ if (type == CHARACTER && !constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR)
+ constraint = node->opr.ctx_type;
+
+ if (constraint)
+ {
+ if (newstate->entrance_nodes == &newstate->nodes)
+ {
+ newstate->entrance_nodes = re_malloc (re_node_set, 1);
+ if (BE (newstate->entrance_nodes == NULL, 0))
+ {
+ free_state (newstate);
+ return NULL;
+ }
+ re_node_set_init_copy (newstate->entrance_nodes, nodes);
+ nctx_nodes = 0;
+ newstate->has_constraint = 1;
+ }
+
+ if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
+ {
+ re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
+ ++nctx_nodes;
+ }
+ }
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
+
+static void
+internal_function
+free_state (re_dfastate_t *state)
+{
+ re_node_set_free (&state->non_eps_nodes);
+ re_node_set_free (&state->inveclosure);
+ if (state->entrance_nodes != &state->nodes)
+ {
+ re_node_set_free (state->entrance_nodes);
+ re_free (state->entrance_nodes);
+ }
+ re_node_set_free (&state->nodes);
+ re_free (state->word_trtable);
+ re_free (state->trtable);
+ re_free (state);
+}
diff --git a/lib/regex_internal.h b/lib/regex_internal.h
new file mode 100644
index 0000000..b94473a
--- /dev/null
+++ b/lib/regex_internal.h
@@ -0,0 +1,907 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _REGEX_INTERNAL_H
+#define _REGEX_INTERNAL_H 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
+# include <langinfo.h>
+#endif
+#if defined HAVE_LOCALE_H || defined _LIBC
+# include <locale.h>
+#endif
+#if defined HAVE_WCHAR_H || defined _LIBC
+# include <wchar.h>
+#endif /* HAVE_WCHAR_H || _LIBC */
+#if defined HAVE_WCTYPE_H || defined _LIBC
+# include <wctype.h>
+#endif /* HAVE_WCTYPE_H || _LIBC */
+#if defined _LIBC
+# include <bits/libc-lock.h>
+#else
+# define __libc_lock_define(CLASS,NAME)
+# define __libc_lock_init(NAME) do { } while (0)
+# define __libc_lock_lock(NAME) do { } while (0)
+# define __libc_lock_unlock(NAME) do { } while (0)
+#endif
+
+/* In case that the system doesn't have isblank(). */
+#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank
+# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
+#endif
+
+#ifdef _LIBC
+# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
+# define _RE_DEFINE_LOCALE_FUNCTIONS 1
+# include <locale/localeinfo.h>
+# include <locale/elem-hash.h>
+# include <locale/coll-lookup.h>
+# endif
+#endif
+
+/* This is for other GNU distributions with internationalized messages. */
+#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
+# include <libintl.h>
+# ifdef _LIBC
+# undef gettext
+# define gettext(msgid) \
+ INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES)
+# endif
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+ strings. */
+# define gettext_noop(String) String
+#endif
+
+#if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC
+# define RE_ENABLE_I18N
+#endif
+
+#if __GNUC__ >= 3
+# define BE(expr, val) __builtin_expect (expr, val)
+#else
+# define BE(expr, val) (expr)
+#endif
+
+/* Number of single byte character. */
+#define SBC_MAX 256
+
+#define COLL_ELEM_LEN_MAX 8
+
+/* The character which represents newline. */
+#define NEWLINE_CHAR '\n'
+#define WIDE_NEWLINE_CHAR L'\n'
+
+/* Rename to standard API for using out of glibc. */
+#ifndef _LIBC
+# define __wctype wctype
+# define __iswctype iswctype
+# define __btowc btowc
+# ifndef __mempcpy
+# define __mempcpy mempcpy
+# endif
+# define __wcrtomb wcrtomb
+# define __regfree regfree
+# define attribute_hidden
+#endif /* not _LIBC */
+
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+# define __attribute(arg) __attribute__ (arg)
+#else
+# define __attribute(arg)
+#endif
+
+extern const char __re_error_msgid[] attribute_hidden;
+extern const size_t __re_error_msgid_idx[] attribute_hidden;
+
+typedef __re_idx_t Idx;
+
+/* Special return value for failure to match. */
+#define REG_MISSING ((Idx) -1)
+
+/* Special return value for internal error. */
+#define REG_ERROR ((Idx) -2)
+
+/* Test whether N is a valid index, and is not one of the above. */
+#ifdef _REGEX_LARGE_OFFSETS
+# define REG_VALID_INDEX(n) ((Idx) (n) < REG_ERROR)
+#else
+# define REG_VALID_INDEX(n) (0 <= (n))
+#endif
+
+/* Test whether N is a valid nonzero index. */
+#ifdef _REGEX_LARGE_OFFSETS
+# define REG_VALID_NONZERO_INDEX(n) ((Idx) ((n) - 1) < (Idx) (REG_ERROR - 1))
+#else
+# define REG_VALID_NONZERO_INDEX(n) (0 < (n))
+#endif
+
+/* A hash value, suitable for computing hash tables. */
+typedef __re_size_t re_hashval_t;
+
+/* An integer used to represent a set of bits. It must be unsigned,
+ and must be at least as wide as unsigned int. */
+typedef unsigned long int bitset_word;
+
+/* Maximum value of a bitset word. It must be useful in preprocessor
+ contexts, and must be consistent with bitset_word. */
+#define BITSET_WORD_MAX ULONG_MAX
+
+/* Number of bits in a bitset word. Avoid greater-than-32-bit
+ integers and unconditional shifts by more than 31 bits, as they're
+ not portable. */
+#if BITSET_WORD_MAX == 0xffffffff
+# define BITSET_WORD_BITS 32
+#elif BITSET_WORD_MAX >> 31 >> 5 == 1
+# define BITSET_WORD_BITS 36
+#elif BITSET_WORD_MAX >> 31 >> 16 == 1
+# define BITSET_WORD_BITS 48
+#elif BITSET_WORD_MAX >> 31 >> 28 == 1
+# define BITSET_WORD_BITS 60
+#elif BITSET_WORD_MAX >> 31 >> 31 >> 1 == 1
+# define BITSET_WORD_BITS 64
+#elif BITSET_WORD_MAX >> 31 >> 31 >> 9 == 1
+# define BITSET_WORD_BITS 72
+#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 == 1
+# define BITSET_WORD_BITS 128
+#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 == 1
+# define BITSET_WORD_BITS 256
+#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 > 1
+# define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */
+# if BITSET_WORD_BITS <= SBC_MAX
+# error "Invalid SBC_MAX"
+# endif
+#else
+# error "Add case for new bitset_word size"
+#endif
+
+/* Number of bitset words in a bitset. */
+#define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS)
+
+typedef bitset_word bitset[BITSET_WORDS];
+typedef bitset_word *re_bitset_ptr_t;
+typedef const bitset_word *re_const_bitset_ptr_t;
+
+#define PREV_WORD_CONSTRAINT 0x0001
+#define PREV_NOTWORD_CONSTRAINT 0x0002
+#define NEXT_WORD_CONSTRAINT 0x0004
+#define NEXT_NOTWORD_CONSTRAINT 0x0008
+#define PREV_NEWLINE_CONSTRAINT 0x0010
+#define NEXT_NEWLINE_CONSTRAINT 0x0020
+#define PREV_BEGBUF_CONSTRAINT 0x0040
+#define NEXT_ENDBUF_CONSTRAINT 0x0080
+#define WORD_DELIM_CONSTRAINT 0x0100
+#define NOT_WORD_DELIM_CONSTRAINT 0x0200
+
+typedef enum
+{
+ INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
+ LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
+ BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
+ BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
+ WORD_DELIM = WORD_DELIM_CONSTRAINT,
+ NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
+} re_context_type;
+
+typedef struct
+{
+ Idx alloc;
+ Idx nelem;
+ Idx *elems;
+} re_node_set;
+
+typedef enum
+{
+ NON_TYPE = 0,
+
+ /* Node type, These are used by token, node, tree. */
+ CHARACTER = 1,
+ END_OF_RE = 2,
+ SIMPLE_BRACKET = 3,
+ OP_BACK_REF = 4,
+ OP_PERIOD = 5,
+#ifdef RE_ENABLE_I18N
+ COMPLEX_BRACKET = 6,
+ OP_UTF8_PERIOD = 7,
+#endif /* RE_ENABLE_I18N */
+
+ /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
+ when the debugger shows values of this enum type. */
+#define EPSILON_BIT 8
+ OP_OPEN_SUBEXP = EPSILON_BIT | 0,
+ OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
+ OP_ALT = EPSILON_BIT | 2,
+ OP_DUP_ASTERISK = EPSILON_BIT | 3,
+ ANCHOR = EPSILON_BIT | 4,
+
+ /* Tree type, these are used only by tree. */
+ CONCAT = 16,
+ SUBEXP = 17,
+
+ /* Token type, these are used only by token. */
+ OP_DUP_PLUS = 18,
+ OP_DUP_QUESTION,
+ OP_OPEN_BRACKET,
+ OP_CLOSE_BRACKET,
+ OP_CHARSET_RANGE,
+ OP_OPEN_DUP_NUM,
+ OP_CLOSE_DUP_NUM,
+ OP_NON_MATCH_LIST,
+ OP_OPEN_COLL_ELEM,
+ OP_CLOSE_COLL_ELEM,
+ OP_OPEN_EQUIV_CLASS,
+ OP_CLOSE_EQUIV_CLASS,
+ OP_OPEN_CHAR_CLASS,
+ OP_CLOSE_CHAR_CLASS,
+ OP_WORD,
+ OP_NOTWORD,
+ OP_SPACE,
+ OP_NOTSPACE,
+ BACK_SLASH
+
+} re_token_type_t;
+
+#ifdef RE_ENABLE_I18N
+typedef struct
+{
+ /* Multibyte characters. */
+ wchar_t *mbchars;
+
+ /* Collating symbols. */
+# ifdef _LIBC
+ int32_t *coll_syms;
+# endif
+
+ /* Equivalence classes. */
+# ifdef _LIBC
+ int32_t *equiv_classes;
+# endif
+
+ /* Range expressions. */
+# ifdef _LIBC
+ uint32_t *range_starts;
+ uint32_t *range_ends;
+# else /* not _LIBC */
+ wchar_t *range_starts;
+ wchar_t *range_ends;
+# endif /* not _LIBC */
+
+ /* Character classes. */
+ wctype_t *char_classes;
+
+ /* If this character set is the non-matching list. */
+ unsigned int non_match : 1;
+
+ /* # of multibyte characters. */
+ Idx nmbchars;
+
+ /* # of collating symbols. */
+ Idx ncoll_syms;
+
+ /* # of equivalence classes. */
+ Idx nequiv_classes;
+
+ /* # of range expressions. */
+ Idx nranges;
+
+ /* # of character classes. */
+ Idx nchar_classes;
+} re_charset_t;
+#endif /* RE_ENABLE_I18N */
+
+typedef struct
+{
+ union
+ {
+ unsigned char c; /* for CHARACTER */
+ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset; /* for COMPLEX_BRACKET */
+#endif /* RE_ENABLE_I18N */
+ Idx idx; /* for BACK_REF */
+ re_context_type ctx_type; /* for ANCHOR */
+ } opr;
+#if __GNUC__ >= 2
+ re_token_type_t type : 8;
+#else
+ re_token_type_t type;
+#endif
+ unsigned int constraint : 10; /* context constraint */
+ unsigned int duplicated : 1;
+ unsigned int opt_subexp : 1;
+#ifdef RE_ENABLE_I18N
+ unsigned int accept_mb : 1;
+ /* These 2 bits can be moved into the union if needed (e.g. if running out
+ of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
+ unsigned int mb_partial : 1;
+#endif
+ unsigned int word_char : 1;
+} re_token_t;
+
+#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
+
+struct re_string_t
+{
+ /* Indicate the raw buffer which is the original string passed as an
+ argument of regexec(), re_search(), etc.. */
+ const unsigned char *raw_mbs;
+ /* Store the multibyte string. In case of "case insensitive mode" like
+ REG_ICASE, upper cases of the string are stored, otherwise MBS points
+ the same address that RAW_MBS points. */
+ unsigned char *mbs;
+#ifdef RE_ENABLE_I18N
+ /* Store the wide character string which is corresponding to MBS. */
+ wint_t *wcs;
+ Idx *offsets;
+ mbstate_t cur_state;
+#endif
+ /* Index in RAW_MBS. Each character mbs[i] corresponds to
+ raw_mbs[raw_mbs_idx + i]. */
+ Idx raw_mbs_idx;
+ /* The length of the valid characters in the buffers. */
+ Idx valid_len;
+ /* The corresponding number of bytes in raw_mbs array. */
+ Idx valid_raw_len;
+ /* The length of the buffers MBS and WCS. */
+ Idx bufs_len;
+ /* The index in MBS, which is updated by re_string_fetch_byte. */
+ Idx cur_idx;
+ /* length of RAW_MBS array. */
+ Idx raw_len;
+ /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
+ Idx len;
+ /* End of the buffer may be shorter than its length in the cases such
+ as re_match_2, re_search_2. Then, we use STOP for end of the buffer
+ instead of LEN. */
+ Idx raw_stop;
+ /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
+ Idx stop;
+
+ /* The context of mbs[0]. We store the context independently, since
+ the context of mbs[0] may be different from raw_mbs[0], which is
+ the beginning of the input string. */
+ unsigned int tip_context;
+ /* The translation passed as a part of an argument of re_compile_pattern. */
+ unsigned REG_TRANSLATE_TYPE trans;
+ /* Copy of re_dfa_t's word_char. */
+ re_const_bitset_ptr_t word_char;
+ /* true if REG_ICASE. */
+ unsigned char icase;
+ unsigned char is_utf8;
+ unsigned char map_notascii;
+ unsigned char mbs_allocated;
+ unsigned char offsets_needed;
+ unsigned char newline_anchor;
+ unsigned char word_ops_used;
+ int mb_cur_max;
+};
+typedef struct re_string_t re_string_t;
+
+
+struct re_dfa_t;
+typedef struct re_dfa_t re_dfa_t;
+
+#ifndef _LIBC
+# ifdef __i386__
+# define internal_function __attribute ((regparm (3), stdcall))
+# else
+# define internal_function
+# endif
+#endif
+
+static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
+ Idx new_buf_len)
+ internal_function;
+#ifdef RE_ENABLE_I18N
+static void build_wcs_buffer (re_string_t *pstr) internal_function;
+static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr)
+ internal_function;
+#endif /* RE_ENABLE_I18N */
+static void build_upper_buffer (re_string_t *pstr) internal_function;
+static void re_string_translate_buffer (re_string_t *pstr) internal_function;
+static unsigned int re_string_context_at (const re_string_t *input,
+ Idx idx, int eflags)
+ internal_function __attribute ((pure));
+
+#define re_string_peek_byte(pstr, offset) \
+ ((pstr)->mbs[(pstr)->cur_idx + offset])
+#define re_string_fetch_byte(pstr) \
+ ((pstr)->mbs[(pstr)->cur_idx++])
+#define re_string_first_byte(pstr, idx) \
+ ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
+#define re_string_is_single_byte_char(pstr, idx) \
+ ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
+ || (pstr)->wcs[(idx) + 1] != WEOF))
+#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
+#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
+#define re_string_get_buffer(pstr) ((pstr)->mbs)
+#define re_string_length(pstr) ((pstr)->len)
+#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
+#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
+#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
+
+#include <alloca.h>
+
+#ifndef _LIBC
+# if HAVE_ALLOCA
+/* The OS usually guarantees only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ allocate anything larger than 4096 bytes. Also care for the possibility
+ of a few compiler-allocated temporary stack slots. */
+# define __libc_use_alloca(n) ((n) < 4032)
+# else
+/* alloca is implemented with malloc, so just use malloc. */
+# define __libc_use_alloca(n) 0
+# endif
+#endif
+
+#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
+#define re_xmalloc(t,n) ((t *) re_xnmalloc (n, sizeof (t)))
+#define re_calloc(t,n) ((t *) calloc (n, sizeof (t)))
+#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t)))
+#define re_xrealloc(p,t,n) ((t *) re_xnrealloc (p, n, sizeof (t)))
+#define re_x2realloc(p,t,pn) ((t *) re_x2nrealloc (p, pn, sizeof (t)))
+#define re_free(p) free (p)
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+/* Return true if an array of N objects, each of size S, cannot exist
+ due to size arithmetic overflow. S must be nonzero. */
+static inline bool
+re_alloc_oversized (size_t n, size_t s)
+{
+ return BE (SIZE_MAX / s < n, 0);
+}
+
+/* Return true if an array of (2 * N + 1) objects, each of size S,
+ cannot exist due to size arithmetic overflow. S must be nonzero. */
+static inline bool
+re_x2alloc_oversized (size_t n, size_t s)
+{
+ return BE ((SIZE_MAX / s - 1) / 2 < n, 0);
+}
+
+/* Allocate an array of N objects, each with S bytes of memory,
+ dynamically, with error checking. S must be nonzero. */
+static inline void *
+re_xnmalloc (size_t n, size_t s)
+{
+ return re_alloc_oversized (n, s) ? NULL : malloc (n * s);
+}
+
+/* Change the size of an allocated block of memory P to an array of N
+ objects each of S bytes, with error checking. S must be nonzero. */
+static inline void *
+re_xnrealloc (void *p, size_t n, size_t s)
+{
+ return re_alloc_oversized (n, s) ? NULL : realloc (p, n * s);
+}
+
+/* Reallocate a block of memory P to an array of (2 * (*PN) + 1)
+ objects each of S bytes, with error checking. S must be nonzero.
+ If the allocation is successful, set *PN to the new allocation
+ count and return the resulting pointer. Otherwise, return
+ NULL. */
+static inline void *
+re_x2nrealloc (void *p, size_t *pn, size_t s)
+{
+ if (re_x2alloc_oversized (*pn, s))
+ return NULL;
+ else
+ {
+ /* Add 1 in case *PN is zero. */
+ size_t n1 = 2 * *pn + 1;
+ p = realloc (p, n1 * s);
+ if (BE (p != NULL, 1))
+ *pn = n1;
+ return p;
+ }
+}
+
+struct bin_tree_t
+{
+ struct bin_tree_t *parent;
+ struct bin_tree_t *left;
+ struct bin_tree_t *right;
+ struct bin_tree_t *first;
+ struct bin_tree_t *next;
+
+ re_token_t token;
+
+ /* `node_idx' is the index in dfa->nodes, if `type' == 0.
+ Otherwise `type' indicate the type of this node. */
+ Idx node_idx;
+};
+typedef struct bin_tree_t bin_tree_t;
+
+#define BIN_TREE_STORAGE_SIZE \
+ ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
+
+struct bin_tree_storage_t
+{
+ struct bin_tree_storage_t *next;
+ bin_tree_t data[BIN_TREE_STORAGE_SIZE];
+};
+typedef struct bin_tree_storage_t bin_tree_storage_t;
+
+#define CONTEXT_WORD 1
+#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
+#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
+#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
+
+#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
+#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
+#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
+#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
+#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
+
+#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
+#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
+#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
+#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
+
+#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
+ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
+ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
+
+#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
+ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
+ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
+
+struct re_dfastate_t
+{
+ re_hashval_t hash;
+ re_node_set nodes;
+ re_node_set non_eps_nodes;
+ re_node_set inveclosure;
+ re_node_set *entrance_nodes;
+ struct re_dfastate_t **trtable, **word_trtable;
+ unsigned int context : 4;
+ unsigned int halt : 1;
+ /* If this state can accept `multi byte'.
+ Note that we refer to multibyte characters, and multi character
+ collating elements as `multi byte'. */
+ unsigned int accept_mb : 1;
+ /* If this state has backreference node(s). */
+ unsigned int has_backref : 1;
+ unsigned int has_constraint : 1;
+};
+typedef struct re_dfastate_t re_dfastate_t;
+
+struct re_state_table_entry
+{
+ Idx num;
+ Idx alloc;
+ re_dfastate_t **array;
+};
+
+/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
+
+typedef struct
+{
+ Idx next_idx;
+ Idx alloc;
+ re_dfastate_t **array;
+} state_array_t;
+
+/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
+
+typedef struct
+{
+ Idx node;
+ Idx str_idx; /* The position NODE match at. */
+ state_array_t path;
+} re_sub_match_last_t;
+
+/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
+ And information about the node, whose type is OP_CLOSE_SUBEXP,
+ corresponding to NODE is stored in LASTS. */
+
+typedef struct
+{
+ Idx str_idx;
+ Idx node;
+ state_array_t *path;
+ Idx alasts; /* Allocation size of LASTS. */
+ Idx nlasts; /* The number of LASTS. */
+ re_sub_match_last_t **lasts;
+} re_sub_match_top_t;
+
+struct re_backref_cache_entry
+{
+ Idx node;
+ Idx str_idx;
+ Idx subexp_from;
+ Idx subexp_to;
+ char more;
+ char unused;
+ unsigned short int eps_reachable_subexps_map;
+};
+
+typedef struct
+{
+ /* The string object corresponding to the input string. */
+ re_string_t input;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ re_dfa_t *const dfa;
+#else
+ re_dfa_t *dfa;
+#endif
+ /* EFLAGS of the argument of regexec. */
+ int eflags;
+ /* Where the matching ends. */
+ Idx match_last;
+ Idx last_node;
+ /* The state log used by the matcher. */
+ re_dfastate_t **state_log;
+ Idx state_log_top;
+ /* Back reference cache. */
+ Idx nbkref_ents;
+ Idx abkref_ents;
+ struct re_backref_cache_entry *bkref_ents;
+ int max_mb_elem_len;
+ Idx nsub_tops;
+ Idx asub_tops;
+ re_sub_match_top_t **sub_tops;
+} re_match_context_t;
+
+typedef struct
+{
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **limited_states;
+ Idx last_node;
+ Idx last_str_idx;
+ re_node_set limits;
+} re_sift_context_t;
+
+struct re_fail_stack_ent_t
+{
+ Idx idx;
+ Idx node;
+ regmatch_t *regs;
+ re_node_set eps_via_nodes;
+};
+
+struct re_fail_stack_t
+{
+ Idx num;
+ Idx alloc;
+ struct re_fail_stack_ent_t *stack;
+};
+
+struct re_dfa_t
+{
+ re_token_t *nodes;
+ Idx nodes_alloc;
+ Idx nodes_len;
+ Idx *nexts;
+ Idx *org_indices;
+ re_node_set *edests;
+ re_node_set *eclosures;
+ re_node_set *inveclosures;
+ struct re_state_table_entry *state_table;
+ re_dfastate_t *init_state;
+ re_dfastate_t *init_state_word;
+ re_dfastate_t *init_state_nl;
+ re_dfastate_t *init_state_begbuf;
+ bin_tree_t *str_tree;
+ bin_tree_storage_t *str_tree_storage;
+ re_bitset_ptr_t sb_char;
+ int str_tree_storage_idx;
+
+ /* number of subexpressions `re_nsub' is in regex_t. */
+ re_hashval_t state_hash_mask;
+ Idx init_node;
+ Idx nbackref; /* The number of backreference in this dfa. */
+
+ /* Bitmap expressing which backreference is used. */
+ bitset_word used_bkref_map;
+ bitset_word completed_bkref_map;
+
+ unsigned int has_plural_match : 1;
+ /* If this dfa has "multibyte node", which is a backreference or
+ a node which can accept multibyte character or multi character
+ collating element. */
+ unsigned int has_mb_node : 1;
+ unsigned int is_utf8 : 1;
+ unsigned int map_notascii : 1;
+ unsigned int word_ops_used : 1;
+ int mb_cur_max;
+ bitset word_char;
+ reg_syntax_t syntax;
+ Idx *subexp_map;
+#ifdef DEBUG
+ char* re_str;
+#endif
+ __libc_lock_define (, lock)
+};
+
+#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
+#define re_node_set_remove(set,id) \
+ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
+#define re_node_set_empty(p) ((p)->nelem = 0)
+#define re_node_set_free(set) re_free ((set)->elems)
+
+static void free_state (re_dfastate_t *state) internal_function;
+
+
+typedef enum
+{
+ SB_CHAR,
+ MB_CHAR,
+ EQUIV_CLASS,
+ COLL_SYM,
+ CHAR_CLASS
+} bracket_elem_type;
+
+typedef struct
+{
+ bracket_elem_type type;
+ union
+ {
+ unsigned char ch;
+ unsigned char *name;
+ wchar_t wch;
+ } opr;
+} bracket_elem_t;
+
+
+/* Inline functions for bitset operation. */
+
+static inline void
+bitset_set (bitset set, Idx i)
+{
+ set[i / BITSET_WORD_BITS] |= (bitset_word) 1 << i % BITSET_WORD_BITS;
+}
+
+static inline void
+bitset_clear (bitset set, Idx i)
+{
+ set[i / BITSET_WORD_BITS] &= ~ ((bitset_word) 1 << i % BITSET_WORD_BITS);
+}
+
+static inline bool
+bitset_contain (const bitset set, Idx i)
+{
+ return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1;
+}
+
+static inline void
+bitset_empty (bitset set)
+{
+ memset (set, 0, sizeof (bitset));
+}
+
+static inline void
+bitset_set_all (bitset set)
+{
+ memset (set, -1, sizeof (bitset_word) * (SBC_MAX / BITSET_WORD_BITS));
+ if (SBC_MAX % BITSET_WORD_BITS != 0)
+ set[BITSET_WORDS - 1] =
+ ((bitset_word) 1 << SBC_MAX % BITSET_WORD_BITS) - 1;
+}
+
+static inline void
+bitset_copy (bitset dest, const bitset src)
+{
+ memcpy (dest, src, sizeof (bitset));
+}
+
+static inline void
+bitset_not (bitset set)
+{
+ int i;
+ for (i = 0; i < SBC_MAX / BITSET_WORD_BITS; ++i)
+ set[i] = ~set[i];
+ if (SBC_MAX % BITSET_WORD_BITS != 0)
+ set[BITSET_WORDS - 1] =
+ ((((bitset_word) 1 << SBC_MAX % BITSET_WORD_BITS) - 1)
+ & ~set[BITSET_WORDS - 1]);
+}
+
+static inline void
+bitset_merge (bitset dest, const bitset src)
+{
+ int i;
+ for (i = 0; i < BITSET_WORDS; ++i)
+ dest[i] |= src[i];
+}
+
+static inline void
+bitset_mask (bitset dest, const bitset src)
+{
+ int i;
+ for (i = 0; i < BITSET_WORDS; ++i)
+ dest[i] &= src[i];
+}
+
+#if defined RE_ENABLE_I18N
+/* Inline functions for re_string. */
+static inline int
+internal_function __attribute ((pure))
+re_string_char_size_at (const re_string_t *pstr, Idx idx)
+{
+ int byte_idx;
+ if (pstr->mb_cur_max == 1)
+ return 1;
+ for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
+ if (pstr->wcs[idx + byte_idx] != WEOF)
+ break;
+ return byte_idx;
+}
+
+static inline wint_t
+internal_function __attribute ((pure))
+re_string_wchar_at (const re_string_t *pstr, Idx idx)
+{
+ if (pstr->mb_cur_max == 1)
+ return (wint_t) pstr->mbs[idx];
+ return (wint_t) pstr->wcs[idx];
+}
+
+static int
+internal_function __attribute ((pure))
+re_string_elem_size_at (const re_string_t *pstr, Idx idx)
+{
+#ifdef _LIBC
+ const unsigned char *p, *extra;
+ const int32_t *table, *indirect;
+ int32_t tmp;
+# include <locale/weight.h>
+ uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+
+ if (nrules != 0)
+ {
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ p = pstr->mbs + idx;
+ tmp = findidx (&p);
+ return p - pstr->mbs - idx;
+ }
+ else
+#endif /* _LIBC */
+ return 1;
+}
+#endif /* RE_ENABLE_I18N */
+
+#endif /* _REGEX_INTERNAL_H */
diff --git a/lib/regexec.c b/lib/regexec.c
new file mode 100644
index 0000000..a85077c
--- /dev/null
+++ b/lib/regexec.c
@@ -0,0 +1,4333 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
+ Idx n) internal_function;
+static void match_ctx_clean (re_match_context_t *mctx) internal_function;
+static void match_ctx_free (re_match_context_t *cache) internal_function;
+static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, Idx node,
+ Idx str_idx, Idx from, Idx to)
+ internal_function;
+static Idx search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx)
+ internal_function;
+static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, Idx node,
+ Idx str_idx) internal_function;
+static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
+ Idx node, Idx str_idx)
+ internal_function;
+static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, Idx last_node,
+ Idx last_str_idx)
+ internal_function;
+static reg_errcode_t re_search_internal (const regex_t *preg,
+ const char *string, Idx length,
+ Idx start, Idx last_start, Idx stop,
+ size_t nmatch, regmatch_t pmatch[],
+ int eflags) internal_function;
+static regoff_t re_search_2_stub (struct re_pattern_buffer *bufp,
+ const char *string1, Idx length1,
+ const char *string2, Idx length2,
+ Idx start, regoff_t range,
+ struct re_registers *regs,
+ Idx stop, bool ret_len) internal_function;
+static regoff_t re_search_stub (struct re_pattern_buffer *bufp,
+ const char *string, Idx length, Idx start,
+ regoff_t range, Idx stop,
+ struct re_registers *regs,
+ bool ret_len) internal_function;
+static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
+ Idx nregs, int regs_allocated) internal_function;
+static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx)
+ internal_function;
+static Idx check_matching (re_match_context_t *mctx, bool fl_longest_match,
+ Idx *p_match_first)
+ internal_function;
+static Idx check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, Idx idx)
+ internal_function;
+static void update_regs (re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, Idx cur_node,
+ Idx cur_idx, Idx nmatch) internal_function;
+static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
+ Idx str_idx, Idx dest_node, Idx nregs,
+ regmatch_t *regs,
+ re_node_set *eps_via_nodes) internal_function;
+static reg_errcode_t set_regs (const regex_t *preg,
+ const re_match_context_t *mctx,
+ size_t nmatch, regmatch_t *pmatch,
+ bool fl_backtrack) internal_function;
+static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) internal_function;
+
+#ifdef RE_ENABLE_I18N
+static int sift_states_iter_mb (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ Idx node_idx, Idx str_idx, Idx max_str_idx) internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t sift_states_backward (re_match_context_t *mctx,
+ re_sift_context_t *sctx) internal_function;
+static reg_errcode_t build_sifted_states (re_match_context_t *mctx,
+ re_sift_context_t *sctx, Idx str_idx,
+ re_node_set *cur_dest) internal_function;
+static reg_errcode_t update_cur_sifted_state (re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ Idx str_idx,
+ re_node_set *dest_nodes) internal_function;
+static reg_errcode_t add_epsilon_src_nodes (re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates) internal_function;
+static bool check_dst_limits (const re_match_context_t *mctx,
+ const re_node_set *limits,
+ Idx dst_node, Idx dst_idx, Idx src_node,
+ Idx src_idx) internal_function;
+static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx,
+ int boundaries, Idx subexp_idx,
+ Idx from_node, Idx bkref_idx) internal_function;
+static int check_dst_limits_calc_pos (const re_match_context_t *mctx,
+ Idx limit, Idx subexp_idx,
+ Idx node, Idx str_idx,
+ Idx bkref_idx) internal_function;
+static reg_errcode_t check_subexp_limits (re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates,
+ re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents,
+ Idx str_idx) internal_function;
+static reg_errcode_t sift_states_bkref (re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ Idx str_idx, const re_node_set *candidates) internal_function;
+static reg_errcode_t merge_state_array (re_dfa_t *dfa, re_dfastate_t **dst,
+ re_dfastate_t **src, Idx num) internal_function;
+static re_dfastate_t *find_recover_state (reg_errcode_t *err,
+ re_match_context_t *mctx) internal_function;
+static re_dfastate_t *transit_state (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *state) internal_function;
+static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *next_state) internal_function;
+static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
+ re_node_set *cur_nodes,
+ Idx str_idx) internal_function;
+#if 0
+static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *pstate) internal_function;
+#endif
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
+ re_dfastate_t *pstate) internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
+ const re_node_set *nodes) internal_function;
+static reg_errcode_t get_subexp (re_match_context_t *mctx,
+ Idx bkref_node, Idx bkref_str_idx) internal_function;
+static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
+ const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last,
+ Idx bkref_node, Idx bkref_str) internal_function;
+static Idx find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ Idx subexp_idx, int type) internal_function;
+static reg_errcode_t check_arrival (re_match_context_t *mctx,
+ state_array_t *path, Idx top_node,
+ Idx top_str, Idx last_node, Idx last_str,
+ int type) internal_function;
+static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
+ Idx str_idx,
+ re_node_set *cur_nodes,
+ re_node_set *next_nodes) internal_function;
+static reg_errcode_t check_arrival_expand_ecl (re_dfa_t *dfa,
+ re_node_set *cur_nodes,
+ Idx ex_subexp, int type) internal_function;
+static reg_errcode_t check_arrival_expand_ecl_sub (re_dfa_t *dfa,
+ re_node_set *dst_nodes,
+ Idx target, Idx ex_subexp,
+ int type) internal_function;
+static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
+ re_node_set *cur_nodes, Idx cur_str,
+ Idx subexp_num, int type) internal_function;
+static bool build_trtable (re_dfa_t *dfa,
+ re_dfastate_t *state) internal_function;
+#ifdef RE_ENABLE_I18N
+static int check_node_accept_bytes (re_dfa_t *dfa, Idx node_idx,
+ const re_string_t *input, Idx idx) internal_function;
+# ifdef _LIBC
+static unsigned int find_collation_sequence_value (const unsigned char *mbs,
+ size_t name_len) internal_function;
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+static Idx group_nodes_into_DFAstates (const re_dfa_t *dfa,
+ const re_dfastate_t *state,
+ re_node_set *states_node,
+ bitset *states_ch) internal_function;
+static bool check_node_accept (const re_match_context_t *mctx,
+ const re_token_t *node, Idx idx)
+ internal_function;
+static reg_errcode_t extend_buffers (re_match_context_t *mctx) internal_function;
+
+/* Entry point for POSIX code. */
+
+/* regexec searches for a given pattern, specified by PREG, in the
+ string STRING.
+
+ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
+ least NMATCH elements, and we set them to the offsets of the
+ corresponding matched substrings.
+
+ EFLAGS specifies `execution flags' which affect matching: if
+ REG_NOTBOL is set, then ^ does not match at the beginning of the
+ string; if REG_NOTEOL is set, then $ does not match at the end.
+
+ We return 0 if we find a match and REG_NOMATCH if not. */
+
+int
+regexec (const regex_t *__restrict preg, const char *__restrict string,
+ size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+ reg_errcode_t err;
+ Idx start, length;
+#ifdef _LIBC
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+#endif
+
+ if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
+ return REG_BADPAT;
+
+ if (eflags & REG_STARTEND)
+ {
+ start = pmatch[0].rm_so;
+ length = pmatch[0].rm_eo;
+ }
+ else
+ {
+ start = 0;
+ length = strlen (string);
+ }
+
+ __libc_lock_lock (dfa->lock);
+ if (preg->re_no_sub)
+ err = re_search_internal (preg, string, length, start, length,
+ length, 0, NULL, eflags);
+ else
+ err = re_search_internal (preg, string, length, start, length,
+ length, nmatch, pmatch, eflags);
+ __libc_lock_unlock (dfa->lock);
+ return err != REG_NOERROR;
+}
+
+#ifdef _LIBC
+# include <shlib-compat.h>
+versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
+
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+__typeof__ (__regexec) __compat_regexec;
+
+int
+attribute_compat_text_section
+__compat_regexec (const regex_t *__restrict preg,
+ const char *__restrict string, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+ return regexec (preg, string, nmatch, pmatch,
+ eflags & (REG_NOTBOL | REG_NOTEOL));
+}
+compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
+# endif
+#endif
+
+/* Entry points for GNU code. */
+
+/* re_match, re_search, re_match_2, re_search_2
+
+ The former two functions operate on STRING with length LENGTH,
+ while the later two operate on concatenation of STRING1 and STRING2
+ with lengths LENGTH1 and LENGTH2, respectively.
+
+ re_match() matches the compiled pattern in BUFP against the string,
+ starting at index START.
+
+ re_search() first tries matching at index START, then it tries to match
+ starting from index START + 1, and so on. The last start position tried
+ is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
+ way as re_match().)
+
+ The parameter STOP of re_{match,search}_2 specifies that no match exceeding
+ the first STOP characters of the concatenation of the strings should be
+ concerned.
+
+ If REGS is not NULL, and BUFP->re_no_sub is not set, the offsets of the match
+ and all groups is stroed in REGS. (For the "_2" variants, the offsets are
+ computed relative to the concatenation, not relative to the individual
+ strings.)
+
+ On success, re_match* functions return the length of the match, re_search*
+ return the position of the start of the match. Return value -1 means no
+ match was found and -2 indicates an internal error. */
+
+regoff_t
+re_match (struct re_pattern_buffer *bufp, const char *string,
+ Idx length, Idx start, struct re_registers *regs)
+{
+ return re_search_stub (bufp, string, length, start, 0, length, regs, true);
+}
+#ifdef _LIBC
+weak_alias (__re_match, re_match)
+#endif
+
+regoff_t
+re_search (struct re_pattern_buffer *bufp, const char *string,
+ Idx length, Idx start, regoff_t range, struct re_registers *regs)
+{
+ return re_search_stub (bufp, string, length, start, range, length, regs,
+ false);
+}
+#ifdef _LIBC
+weak_alias (__re_search, re_search)
+#endif
+
+regoff_t
+re_match_2 (struct re_pattern_buffer *bufp,
+ const char *string1, Idx length1,
+ const char *string2, Idx length2,
+ Idx start, struct re_registers *regs, Idx stop)
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, 0, regs, stop, true);
+}
+#ifdef _LIBC
+weak_alias (__re_match_2, re_match_2)
+#endif
+
+regoff_t
+re_search_2 (struct re_pattern_buffer *bufp,
+ const char *string1, Idx length1,
+ const char *string2, Idx length2,
+ Idx start, regoff_t range, struct re_registers *regs, Idx stop)
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, range, regs, stop, false);
+}
+#ifdef _LIBC
+weak_alias (__re_search_2, re_search_2)
+#endif
+
+static regoff_t
+internal_function
+re_search_2_stub (struct re_pattern_buffer *bufp,
+ const char *string1, Idx length1,
+ const char *string2, Idx length2,
+ Idx start, regoff_t range, struct re_registers *regs,
+ Idx stop, bool ret_len)
+{
+ const char *str;
+ regoff_t rval;
+ Idx len = length1 + length2;
+ char *s = NULL;
+
+ if (BE (length1 < 0 || length2 < 0 || stop < 0 || len < length1, 0))
+ return -2;
+
+ /* Concatenate the strings. */
+ if (length2 > 0)
+ if (length1 > 0)
+ {
+ s = re_malloc (char, len);
+
+ if (BE (s == NULL, 0))
+ return -2;
+ memcpy (s, string1, length1);
+ memcpy (s + length1, string2, length2);
+ str = s;
+ }
+ else
+ str = string2;
+ else
+ str = string1;
+
+ rval = re_search_stub (bufp, str, len, start, range, stop, regs,
+ ret_len);
+ re_free (s);
+ return rval;
+}
+
+/* The parameters have the same meaning as those of re_search.
+ Additional parameters:
+ If RET_LEN is true the length of the match is returned (re_match style);
+ otherwise the position of the match is returned. */
+
+static regoff_t
+internal_function
+re_search_stub (struct re_pattern_buffer *bufp,
+ const char *string, Idx length,
+ Idx start, regoff_t range, Idx stop, struct re_registers *regs,
+ bool ret_len)
+{
+ reg_errcode_t result;
+ regmatch_t *pmatch;
+ Idx nregs;
+ regoff_t rval;
+ int eflags = 0;
+#ifdef _LIBC
+ re_dfa_t *dfa = (re_dfa_t *) bufp->re_buffer;
+#endif
+ Idx last_start = start + range;
+
+ /* Check for out-of-range. */
+ if (BE (start < 0 || start > length, 0))
+ return -1;
+ if (sizeof start < sizeof range)
+ {
+ regoff_t length_offset = length;
+ regoff_t start_offset = start;
+ if (BE (length_offset - start_offset < range, 0))
+ last_start = length;
+ else if (BE (range < - start_offset, 0))
+ last_start = 0;
+ }
+ else
+ {
+ if (BE ((last_start < start) != (range < 0), 0))
+ {
+ /* Overflow occurred when computing last_start; substitute
+ the extreme value. */
+ last_start = range < 0 ? 0 : length;
+ }
+ else
+ {
+ if (BE (length < last_start, 0))
+ last_start = length;
+ else if (BE (last_start < 0, 0))
+ last_start = 0;
+ }
+ }
+
+ __libc_lock_lock (dfa->lock);
+
+ eflags |= (bufp->re_not_bol) ? REG_NOTBOL : 0;
+ eflags |= (bufp->re_not_eol) ? REG_NOTEOL : 0;
+
+ /* Compile fastmap if we haven't yet. */
+ if (start < last_start && bufp->re_fastmap != NULL
+ && !bufp->re_fastmap_accurate)
+ re_compile_fastmap (bufp);
+
+ if (BE (bufp->re_no_sub, 0))
+ regs = NULL;
+
+ /* We need at least 1 register. */
+ if (regs == NULL)
+ nregs = 1;
+ else if (BE (bufp->re_regs_allocated == REG_FIXED
+ && regs->rm_num_regs <= bufp->re_nsub, 0))
+ {
+ nregs = regs->rm_num_regs;
+ if (BE (nregs < 1, 0))
+ {
+ /* Nothing can be copied to regs. */
+ regs = NULL;
+ nregs = 1;
+ }
+ }
+ else
+ nregs = bufp->re_nsub + 1;
+ pmatch = re_xmalloc (regmatch_t, nregs);
+ if (BE (pmatch == NULL, 0))
+ {
+ rval = -2;
+ goto out;
+ }
+
+ result = re_search_internal (bufp, string, length, start, last_start, stop,
+ nregs, pmatch, eflags);
+
+ rval = 0;
+
+ /* I hope we needn't fill ther regs with -1's when no match was found. */
+ if (result != REG_NOERROR)
+ rval = -1;
+ else if (regs != NULL)
+ {
+ /* If caller wants register contents data back, copy them. */
+ bufp->re_regs_allocated = re_copy_regs (regs, pmatch, nregs,
+ bufp->re_regs_allocated);
+ if (BE (bufp->re_regs_allocated == REG_UNALLOCATED, 0))
+ rval = -2;
+ }
+
+ if (BE (rval == 0, 1))
+ {
+ if (ret_len)
+ {
+ assert (pmatch[0].rm_so == start);
+ rval = pmatch[0].rm_eo - start;
+ }
+ else
+ rval = pmatch[0].rm_so;
+ }
+ re_free (pmatch);
+ out:
+ __libc_lock_unlock (dfa->lock);
+ return rval;
+}
+
+static unsigned
+internal_function
+re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, Idx nregs,
+ int regs_allocated)
+{
+ int rval = REG_REALLOCATE;
+ Idx i;
+ Idx need_regs = nregs + 1;
+ /* We need one extra element beyond `rm_num_regs' for the `-1' marker GNU code
+ uses. */
+
+ /* Have the register data arrays been allocated? */
+ if (regs_allocated == REG_UNALLOCATED)
+ { /* No. So allocate them with malloc. */
+ regs->rm_start = re_xmalloc (regoff_t, need_regs);
+ regs->rm_end = re_malloc (regoff_t, need_regs);
+ if (BE (regs->rm_start == NULL, 0) || BE (regs->rm_end == NULL, 0))
+ return REG_UNALLOCATED;
+ regs->rm_num_regs = need_regs;
+ }
+ else if (regs_allocated == REG_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (BE (need_regs > regs->rm_num_regs, 0))
+ {
+ regoff_t *new_start =
+ re_xrealloc (regs->rm_start, regoff_t, need_regs);
+ regoff_t *new_end = re_realloc (regs->rm_end, regoff_t, need_regs);
+ if (BE (new_start == NULL, 0) || BE (new_end == NULL, 0))
+ return REG_UNALLOCATED;
+ regs->rm_start = new_start;
+ regs->rm_end = new_end;
+ regs->rm_num_regs = need_regs;
+ }
+ }
+ else
+ {
+ assert (regs_allocated == REG_FIXED);
+ /* This function may not be called with REG_FIXED and nregs too big. */
+ assert (regs->rm_num_regs >= nregs);
+ rval = REG_FIXED;
+ }
+
+ /* Copy the regs. */
+ for (i = 0; i < nregs; ++i)
+ {
+ regs->rm_start[i] = pmatch[i].rm_so;
+ regs->rm_end[i] = pmatch[i].rm_eo;
+ }
+ for ( ; i < regs->rm_num_regs; ++i)
+ regs->rm_start[i] = regs->rm_end[i] = -1;
+
+ return rval;
+}
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
+ this memory for recording register information. STARTS and ENDS
+ must be allocated using the malloc library routine, and must each
+ be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+
+void
+re_set_registers (struct re_pattern_buffer *bufp, struct re_registers *regs,
+ __re_size_t num_regs, regoff_t *starts, regoff_t *ends)
+{
+ if (num_regs)
+ {
+ bufp->re_regs_allocated = REG_REALLOCATE;
+ regs->rm_num_regs = num_regs;
+ regs->rm_start = starts;
+ regs->rm_end = ends;
+ }
+ else
+ {
+ bufp->re_regs_allocated = REG_UNALLOCATED;
+ regs->rm_num_regs = 0;
+ regs->rm_start = regs->rm_end = NULL;
+ }
+}
+#ifdef _LIBC
+weak_alias (__re_set_registers, re_set_registers)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+int
+# ifdef _LIBC
+weak_function
+# endif
+re_exec (const char *s)
+{
+ return 0 == regexec (&re_comp_buf, s, 0, NULL, 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point. */
+
+/* Searches for a compiled pattern PREG in the string STRING, whose
+ length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
+ meaning as with regexec. LAST_START is START + RANGE, where
+ START and RANGE have the same meaning as with re_search.
+ Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
+ otherwise return the error code.
+ Note: We assume front end functions already check ranges.
+ (0 <= LAST_START && LAST_START <= LENGTH) */
+
+static reg_errcode_t
+internal_function
+re_search_internal (const regex_t *preg,
+ const char *string, Idx length,
+ Idx start, Idx last_start, Idx stop,
+ size_t nmatch, regmatch_t pmatch[],
+ int eflags)
+{
+ reg_errcode_t err;
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ Idx left_lim, right_lim;
+ int incr;
+ bool fl_longest_match;
+ int match_kind;
+ Idx match_first, match_last = REG_MISSING;
+ Idx extra_nmatch;
+ bool sb;
+ int ch;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ re_match_context_t mctx = { .dfa = dfa };
+#else
+ re_match_context_t mctx;
+#endif
+ char *fastmap = ((preg->re_fastmap != NULL && preg->re_fastmap_accurate
+ && start != last_start && !preg->re_can_be_null)
+ ? preg->re_fastmap : NULL);
+ unsigned REG_TRANSLATE_TYPE t =
+ (unsigned REG_TRANSLATE_TYPE) preg->re_translate;
+
+#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
+ memset (&mctx, '\0', sizeof (re_match_context_t));
+ mctx.dfa = dfa;
+#endif
+
+ extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
+ nmatch -= extra_nmatch;
+
+ /* Check if the DFA haven't been compiled. */
+ if (BE (preg->re_used == 0 || dfa->init_state == NULL
+ || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return REG_NOMATCH;
+
+#ifdef DEBUG
+ /* We assume front-end functions already check them. */
+ assert (0 <= last_start && last_start <= length);
+#endif
+
+ /* If initial states with non-begbuf contexts have no elements,
+ the regex must be anchored. If preg->re_newline_anchor is set,
+ we'll never use init_state_nl, so do not check it. */
+ if (dfa->init_state->nodes.nelem == 0
+ && dfa->init_state_word->nodes.nelem == 0
+ && (dfa->init_state_nl->nodes.nelem == 0
+ || !preg->re_newline_anchor))
+ {
+ if (start != 0 && last_start != 0)
+ return REG_NOMATCH;
+ start = last_start = 0;
+ }
+
+ /* We must check the longest matching, if nmatch > 0. */
+ fl_longest_match = (nmatch != 0 || dfa->nbackref);
+
+ err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
+ preg->re_translate,
+ preg->re_syntax & REG_IGNORE_CASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ mctx.input.stop = stop;
+ mctx.input.raw_stop = stop;
+ mctx.input.newline_anchor = preg->re_newline_anchor;
+
+ err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* We will log all the DFA states through which the dfa pass,
+ if nmatch > 1, or this dfa has "multibyte node", which is a
+ back-reference or a node which can accept multibyte character or
+ multi character collating element. */
+ if (nmatch > 1 || dfa->has_mb_node)
+ {
+ mctx.state_log = re_xmalloc (re_dfastate_t *, mctx.input.bufs_len + 1);
+ if (BE (mctx.state_log == NULL, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ }
+ else
+ mctx.state_log = NULL;
+
+ match_first = start;
+ mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
+
+ /* Check incrementally whether of not the input string match. */
+ incr = (last_start < start) ? -1 : 1;
+ left_lim = (last_start < start) ? last_start : start;
+ right_lim = (last_start < start) ? start : last_start;
+ sb = dfa->mb_cur_max == 1;
+ match_kind =
+ (fastmap
+ ? ((sb || !(preg->re_syntax & REG_IGNORE_CASE || t) ? 4 : 0)
+ | (start <= last_start ? 2 : 0)
+ | (t != NULL ? 1 : 0))
+ : 8);
+
+ for (;; match_first += incr)
+ {
+ err = REG_NOMATCH;
+ if (match_first < left_lim || right_lim < match_first)
+ goto free_return;
+
+ /* Advance as rapidly as possible through the string, until we
+ find a plausible place to start matching. This may be done
+ with varying efficiency, so there are various possibilities:
+ only the most common of them are specialized, in order to
+ save on code size. We use a switch statement for speed. */
+ switch (match_kind)
+ {
+ case 8:
+ /* No fastmap. */
+ break;
+
+ case 7:
+ /* Fastmap with single-byte translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[t[(unsigned char) string[match_first]]])
+ ++match_first;
+ goto forward_match_found_start_or_reached_end;
+
+ case 6:
+ /* Fastmap without translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[(unsigned char) string[match_first]])
+ ++match_first;
+
+ forward_match_found_start_or_reached_end:
+ if (BE (match_first == right_lim, 0))
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (!fastmap[t ? t[ch] : ch])
+ goto free_return;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* Fastmap without multi-byte translation, match backwards. */
+ while (match_first >= left_lim)
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (fastmap[t ? t[ch] : ch])
+ break;
+ --match_first;
+ }
+ if (match_first < left_lim)
+ goto free_return;
+ break;
+
+ default:
+ /* In this case, we can't determine easily the current byte,
+ since it might be a component byte of a multibyte
+ character. Then we use the constructed buffer instead. */
+ for (;;)
+ {
+ /* If MATCH_FIRST is out of the valid range, reconstruct the
+ buffers. */
+ __re_size_t offset = match_first - mctx.input.raw_mbs_idx;
+ if (BE (offset >= (__re_size_t) mctx.input.valid_raw_len, 0))
+ {
+ err = re_string_reconstruct (&mctx.input, match_first,
+ eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ offset = match_first - mctx.input.raw_mbs_idx;
+ }
+ /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
+ Note that MATCH_FIRST must not be smaller than 0. */
+ ch = (match_first >= length
+ ? 0 : re_string_byte_at (&mctx.input, offset));
+ if (fastmap[ch])
+ break;
+ match_first += incr;
+ if (match_first < left_lim || match_first > right_lim)
+ {
+ err = REG_NOMATCH;
+ goto free_return;
+ }
+ }
+ break;
+ }
+
+ /* Reconstruct the buffers so that the matcher can assume that
+ the matching starts from the beginning of the buffer. */
+ err = re_string_reconstruct (&mctx.input, match_first, eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* Don't consider this char as a possible match start if it part,
+ yet isn't the head, of a multibyte character. */
+ if (!sb && !re_string_first_byte (&mctx.input, 0))
+ continue;
+#endif
+
+ /* It seems to be appropriate one, then use the matcher. */
+ /* We assume that the matching starts from 0. */
+ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
+ match_last = check_matching (&mctx, fl_longest_match,
+ start <= last_start ? &match_first : NULL);
+ if (match_last != REG_MISSING)
+ {
+ if (BE (match_last == REG_ERROR, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ else
+ {
+ mctx.match_last = match_last;
+ if ((!preg->re_no_sub && nmatch > 1) || dfa->nbackref)
+ {
+ re_dfastate_t *pstate = mctx.state_log[match_last];
+ mctx.last_node = check_halt_state_context (&mctx, pstate,
+ match_last);
+ }
+ if ((!preg->re_no_sub && nmatch > 1 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ err = prune_impossible_nodes (&mctx);
+ if (err == REG_NOERROR)
+ break;
+ if (BE (err != REG_NOMATCH, 0))
+ goto free_return;
+ match_last = REG_MISSING;
+ }
+ else
+ break; /* We found a match. */
+ }
+ }
+
+ match_ctx_clean (&mctx);
+ }
+
+#ifdef DEBUG
+ assert (match_last != REG_MISSING);
+ assert (err == REG_NOERROR);
+#endif
+
+ /* Set pmatch[] if we need. */
+ if (nmatch > 0)
+ {
+ Idx reg_idx;
+
+ /* Initialize registers. */
+ for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
+ pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
+
+ /* Set the points where matching start/end. */
+ pmatch[0].rm_so = 0;
+ pmatch[0].rm_eo = mctx.match_last;
+ /* FIXME: This function should fail if mctx.match_last exceeds
+ the maximum possible regoff_t value. We need a new error
+ code REG_OVERFLOW. */
+
+ if (!preg->re_no_sub && nmatch > 1)
+ {
+ err = set_regs (preg, &mctx, nmatch, pmatch,
+ dfa->has_plural_match && dfa->nbackref > 0);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* At last, add the offset to the each registers, since we slided
+ the buffers so that we could assume that the matching starts
+ from 0. */
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so != -1)
+ {
+#ifdef RE_ENABLE_I18N
+ if (BE (mctx.input.offsets_needed != 0, 0))
+ {
+ pmatch[reg_idx].rm_so =
+ (pmatch[reg_idx].rm_so == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_so]);
+ pmatch[reg_idx].rm_eo =
+ (pmatch[reg_idx].rm_eo == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
+ }
+#else
+ assert (mctx.input.offsets_needed == 0);
+#endif
+ pmatch[reg_idx].rm_so += match_first;
+ pmatch[reg_idx].rm_eo += match_first;
+ }
+ for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
+ {
+ pmatch[nmatch + reg_idx].rm_so = -1;
+ pmatch[nmatch + reg_idx].rm_eo = -1;
+ }
+
+ if (dfa->subexp_map)
+ for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
+ if (dfa->subexp_map[reg_idx] != reg_idx)
+ {
+ pmatch[reg_idx + 1].rm_so
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
+ pmatch[reg_idx + 1].rm_eo
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
+ }
+ }
+
+ free_return:
+ re_free (mctx.state_log);
+ if (dfa->nbackref)
+ match_ctx_free (&mctx);
+ re_string_destruct (&mctx.input);
+ return err;
+}
+
+static reg_errcode_t
+internal_function
+prune_impossible_nodes (re_match_context_t *mctx)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ Idx halt_node, match_last;
+ reg_errcode_t ret;
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **lim_states = NULL;
+ re_sift_context_t sctx;
+#ifdef DEBUG
+ assert (mctx->state_log != NULL);
+#endif
+ match_last = mctx->match_last;
+ halt_node = mctx->last_node;
+ sifted_states = re_xmalloc (re_dfastate_t *, match_last + 1);
+ if (BE (sifted_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ if (dfa->nbackref)
+ {
+ lim_states = re_xmalloc (re_dfastate_t *, match_last + 1);
+ if (BE (lim_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ while (1)
+ {
+ memset (lim_states, '\0',
+ sizeof (re_dfastate_t *) * (match_last + 1));
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
+ match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ if (sifted_states[0] != NULL || lim_states[0] != NULL)
+ break;
+ do
+ {
+ --match_last;
+ if (! REG_VALID_INDEX (match_last))
+ {
+ ret = REG_NOMATCH;
+ goto free_return;
+ }
+ } while (mctx->state_log[match_last] == NULL
+ || !mctx->state_log[match_last]->halt);
+ halt_node = check_halt_state_context (mctx,
+ mctx->state_log[match_last],
+ match_last);
+ }
+ ret = merge_state_array (dfa, sifted_states, lim_states,
+ match_last + 1);
+ re_free (lim_states);
+ lim_states = NULL;
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ re_free (mctx->state_log);
+ mctx->state_log = sifted_states;
+ sifted_states = NULL;
+ mctx->last_node = halt_node;
+ mctx->match_last = match_last;
+ ret = REG_NOERROR;
+ free_return:
+ re_free (sifted_states);
+ re_free (lim_states);
+ return ret;
+}
+
+/* Acquire an initial state and return it.
+ We must select appropriate initial state depending on the context,
+ since initial states may have constraints like "\<", "^", etc.. */
+
+static inline re_dfastate_t *
+__attribute ((always_inline)) internal_function
+acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
+ Idx idx)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ if (dfa->init_state->has_constraint)
+ {
+ unsigned int context;
+ context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return dfa->init_state_word;
+ else if (IS_ORDINARY_CONTEXT (context))
+ return dfa->init_state;
+ else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_begbuf;
+ else if (IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_nl;
+ else if (IS_BEGBUF_CONTEXT (context))
+ {
+ /* It is relatively rare case, then calculate on demand. */
+ return re_acquire_state_context (err, dfa,
+ dfa->init_state->entrance_nodes,
+ context);
+ }
+ else
+ /* Must not happen? */
+ return dfa->init_state;
+ }
+ else
+ return dfa->init_state;
+}
+
+/* Check whether the regular expression match input string INPUT or not,
+ and return the index where the matching end. Return REG_MISSING if
+ there is no match, and return REG_ERROR in case of an error.
+ FL_LONGEST_MATCH means we want the POSIX longest matching.
+ If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
+ next place where we may want to try matching.
+ Note that the matcher assume that the maching starts from the current
+ index of the buffer. */
+
+static Idx
+internal_function
+check_matching (re_match_context_t *mctx, bool fl_longest_match,
+ Idx *p_match_first)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ Idx match = 0;
+ Idx match_last = REG_MISSING;
+ Idx cur_str_idx = re_string_cur_idx (&mctx->input);
+ re_dfastate_t *cur_state;
+ bool at_init_state = p_match_first != NULL;
+ Idx next_start_idx = cur_str_idx;
+
+ err = REG_NOERROR;
+ cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
+ /* An initial state must not be NULL (invalid). */
+ if (BE (cur_state == NULL, 0))
+ {
+ assert (err == REG_ESPACE);
+ return REG_ERROR;
+ }
+
+ if (mctx->state_log != NULL)
+ {
+ mctx->state_log[cur_str_idx] = cur_state;
+
+ /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
+ later. E.g. Processing back references. */
+ if (BE (dfa->nbackref, 0))
+ {
+ at_init_state = false;
+ err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (cur_state->has_backref)
+ {
+ err = transit_state_bkref (mctx, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+
+ /* If the RE accepts NULL string. */
+ if (BE (cur_state->halt, 0))
+ {
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state, cur_str_idx))
+ {
+ if (!fl_longest_match)
+ return cur_str_idx;
+ else
+ {
+ match_last = cur_str_idx;
+ match = 1;
+ }
+ }
+ }
+
+ while (!re_string_eoi (&mctx->input))
+ {
+ re_dfastate_t *old_state = cur_state;
+ Idx next_char_idx = re_string_cur_idx (&mctx->input) + 1;
+
+ if (BE (next_char_idx >= mctx->input.bufs_len, 0)
+ || (BE (next_char_idx >= mctx->input.valid_len, 0)
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ assert (err == REG_ESPACE);
+ return REG_ERROR;
+ }
+ }
+
+ cur_state = transit_state (&err, mctx, cur_state);
+ if (mctx->state_log != NULL)
+ cur_state = merge_state_with_log (&err, mctx, cur_state);
+
+ if (cur_state == NULL)
+ {
+ /* Reached the invalid state or an error. Try to recover a valid
+ state using the state log, if available and if we have not
+ already found a valid (even if not the longest) match. */
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ERROR;
+
+ if (mctx->state_log == NULL
+ || (match && !fl_longest_match)
+ || (cur_state = find_recover_state (&err, mctx)) == NULL)
+ break;
+ }
+
+ if (BE (at_init_state, 0))
+ {
+ if (old_state == cur_state)
+ next_start_idx = next_char_idx;
+ else
+ at_init_state = false;
+ }
+
+ if (cur_state->halt)
+ {
+ /* Reached a halt state.
+ Check the halt state can satisfy the current context. */
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state,
+ re_string_cur_idx (&mctx->input)))
+ {
+ /* We found an appropriate halt state. */
+ match_last = re_string_cur_idx (&mctx->input);
+ match = 1;
+
+ /* We found a match, do not modify match_first below. */
+ p_match_first = NULL;
+ if (!fl_longest_match)
+ break;
+ }
+ }
+ }
+
+ if (p_match_first)
+ *p_match_first += next_start_idx;
+
+ return match_last;
+}
+
+/* Check NODE match the current context. */
+
+static bool
+internal_function
+check_halt_node_context (const re_dfa_t *dfa, Idx node, unsigned int context)
+{
+ re_token_type_t type = dfa->nodes[node].type;
+ unsigned int constraint = dfa->nodes[node].constraint;
+ if (type != END_OF_RE)
+ return false;
+ if (!constraint)
+ return true;
+ if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
+ return false;
+ return true;
+}
+
+/* Check the halt state STATE match the current context.
+ Return 0 if not match, if the node, STATE has, is a halt node and
+ match the context, return the node. */
+
+static Idx
+internal_function
+check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, Idx idx)
+{
+ Idx i;
+ unsigned int context;
+#ifdef DEBUG
+ assert (state->halt);
+#endif
+ context = re_string_context_at (&mctx->input, idx, mctx->eflags);
+ for (i = 0; i < state->nodes.nelem; ++i)
+ if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
+ return state->nodes.elems[i];
+ return 0;
+}
+
+/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
+ corresponding to the DFA).
+ Return the destination node, and update EPS_VIA_NODES;
+ return REG_MISSING in case of errors. */
+
+static Idx
+internal_function
+proceed_next_node (const re_match_context_t *mctx,
+ Idx nregs, regmatch_t *regs, Idx *pidx, Idx node,
+ re_node_set *eps_via_nodes, struct re_fail_stack_t *fs)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ Idx i;
+ bool ok;
+ if (IS_EPSILON_NODE (dfa->nodes[node].type))
+ {
+ re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
+ re_node_set *edests = &dfa->edests[node];
+ Idx dest_node;
+ ok = re_node_set_insert (eps_via_nodes, node);
+ if (BE (! ok, 0))
+ return REG_ERROR;
+ /* Pick up a valid destination, or return REG_MISSING if none
+ is found. */
+ for (dest_node = REG_MISSING, i = 0; i < edests->nelem; ++i)
+ {
+ Idx candidate = edests->elems[i];
+ if (!re_node_set_contains (cur_nodes, candidate))
+ continue;
+ if (dest_node == REG_MISSING)
+ dest_node = candidate;
+
+ else
+ {
+ /* In order to avoid infinite loop like "(a*)*", return the second
+ epsilon-transition if the first was already considered. */
+ if (re_node_set_contains (eps_via_nodes, dest_node))
+ return candidate;
+
+ /* Otherwise, push the second epsilon-transition on the fail stack. */
+ else if (fs != NULL
+ && push_fail_stack (fs, *pidx, candidate, nregs, regs,
+ eps_via_nodes))
+ return REG_ERROR;
+
+ /* We know we are going to exit. */
+ break;
+ }
+ }
+ return dest_node;
+ }
+ else
+ {
+ Idx naccepted = 0;
+ re_token_type_t type = dfa->nodes[node].type;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->nodes[node].accept_mb)
+ naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (type == OP_BACK_REF)
+ {
+ Idx subexp_idx = dfa->nodes[node].opr.idx + 1;
+ naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
+ if (fs != NULL)
+ {
+ if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
+ return REG_MISSING;
+ else if (naccepted)
+ {
+ char *buf = (char *) re_string_get_buffer (&mctx->input);
+ if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+ naccepted) != 0)
+ return REG_MISSING;
+ }
+ }
+
+ if (naccepted == 0)
+ {
+ Idx dest_node;
+ ok = re_node_set_insert (eps_via_nodes, node);
+ if (BE (! ok, 0))
+ return REG_ERROR;
+ dest_node = dfa->edests[node].elems[0];
+ if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node))
+ return dest_node;
+ }
+ }
+
+ if (naccepted != 0
+ || check_node_accept (mctx, dfa->nodes + node, *pidx))
+ {
+ Idx dest_node = dfa->nexts[node];
+ *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
+ if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
+ || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node)))
+ return REG_MISSING;
+ re_node_set_empty (eps_via_nodes);
+ return dest_node;
+ }
+ }
+ return REG_MISSING;
+}
+
+static reg_errcode_t
+internal_function
+push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node,
+ Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ reg_errcode_t err;
+ Idx num = fs->num++;
+ if (fs->num == fs->alloc)
+ {
+ struct re_fail_stack_ent_t *new_array =
+ re_x2realloc (fs->stack, struct re_fail_stack_ent_t, &fs->alloc);
+ if (new_array == NULL)
+ return REG_ESPACE;
+ fs->stack = new_array;
+ }
+ fs->stack[num].idx = str_idx;
+ fs->stack[num].node = dest_node;
+ fs->stack[num].regs = re_xmalloc (regmatch_t, nregs);
+ if (fs->stack[num].regs == NULL)
+ return REG_ESPACE;
+ memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
+ err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
+ return err;
+}
+
+static Idx
+internal_function
+pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx,
+ Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ Idx num = --fs->num;
+ assert (REG_VALID_INDEX (num));
+ *pidx = fs->stack[num].idx;
+ memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
+ re_node_set_free (eps_via_nodes);
+ re_free (fs->stack[num].regs);
+ *eps_via_nodes = fs->stack[num].eps_via_nodes;
+ return fs->stack[num].node;
+}
+
+/* Set the positions where the subexpressions are starts/ends to registers
+ PMATCH.
+ Note: We assume that pmatch[0] is already set, and
+ pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
+
+static reg_errcode_t
+internal_function
+set_regs (const regex_t *preg, const re_match_context_t *mctx,
+ size_t nmatch, regmatch_t *pmatch, bool fl_backtrack)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer;
+ Idx idx, cur_node;
+ re_node_set eps_via_nodes;
+ struct re_fail_stack_t *fs;
+ struct re_fail_stack_t fs_body = { 0, 2, NULL };
+ regmatch_t *prev_idx_match;
+ bool prev_idx_match_malloced = false;
+
+#ifdef DEBUG
+ assert (nmatch > 1);
+ assert (mctx->state_log != NULL);
+#endif
+ if (fl_backtrack)
+ {
+ fs = &fs_body;
+ fs->stack = re_xmalloc (struct re_fail_stack_ent_t, fs->alloc);
+ if (fs->stack == NULL)
+ return REG_ESPACE;
+ }
+ else
+ fs = NULL;
+
+ cur_node = dfa->init_node;
+ re_node_set_init_empty (&eps_via_nodes);
+
+ if (re_alloc_oversized (nmatch, sizeof (regmatch_t)))
+ {
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ if (__libc_use_alloca (nmatch * sizeof (regmatch_t)))
+ prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t));
+ else
+ {
+ prev_idx_match = re_malloc (regmatch_t, nmatch);
+ if (prev_idx_match == NULL)
+ {
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ prev_idx_match_malloced = true;
+ }
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+
+ for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
+ {
+ update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
+
+ if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
+ {
+ Idx reg_idx;
+ if (fs)
+ {
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
+ break;
+ if (reg_idx == nmatch)
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+ }
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ }
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOERROR;
+ }
+ }
+
+ /* Proceed to next node. */
+ cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
+ &eps_via_nodes, fs);
+
+ if (BE (! REG_VALID_INDEX (cur_node), 0))
+ {
+ if (BE (cur_node == REG_ERROR, 0))
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ if (fs)
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOMATCH;
+ }
+ }
+ }
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+}
+
+static reg_errcode_t
+internal_function
+free_fail_stack_return (struct re_fail_stack_t *fs)
+{
+ if (fs)
+ {
+ Idx fs_idx;
+ for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
+ {
+ re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
+ re_free (fs->stack[fs_idx].regs);
+ }
+ re_free (fs->stack);
+ }
+ return REG_NOERROR;
+}
+
+static void
+internal_function
+update_regs (re_dfa_t *dfa, regmatch_t *pmatch, regmatch_t *prev_idx_match,
+ Idx cur_node, Idx cur_idx, Idx nmatch)
+{
+ int type = dfa->nodes[cur_node].type;
+ if (type == OP_OPEN_SUBEXP)
+ {
+ Idx reg_num = dfa->nodes[cur_node].opr.idx + 1;
+
+ /* We are at the first node of this sub expression. */
+ if (reg_num < nmatch)
+ {
+ pmatch[reg_num].rm_so = cur_idx;
+ pmatch[reg_num].rm_eo = -1;
+ }
+ }
+ else if (type == OP_CLOSE_SUBEXP)
+ {
+ Idx reg_num = dfa->nodes[cur_node].opr.idx + 1;
+ if (reg_num < nmatch)
+ {
+ /* We are at the last node of this sub expression. */
+ if (pmatch[reg_num].rm_so < cur_idx)
+ {
+ pmatch[reg_num].rm_eo = cur_idx;
+ /* This is a non-empty match or we are not inside an optional
+ subexpression. Accept this right away. */
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+ }
+ else
+ {
+ if (dfa->nodes[cur_node].opt_subexp
+ && prev_idx_match[reg_num].rm_so != -1)
+ /* We transited through an empty match for an optional
+ subexpression, like (a?)*, and this is not the subexp's
+ first match. Copy back the old content of the registers
+ so that matches of an inner subexpression are undone as
+ well, like in ((a?))*. */
+ memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
+ else
+ /* We completed a subexpression, but it may be part of
+ an optional one, so do not update PREV_IDX_MATCH. */
+ pmatch[reg_num].rm_eo = cur_idx;
+ }
+ }
+ }
+}
+
+/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
+ and sift the nodes in each states according to the following rules.
+ Updated state_log will be wrote to STATE_LOG.
+
+ Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if...
+ 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
+ If `a' isn't the LAST_NODE and `a' can't epsilon transit to
+ the LAST_NODE, we throw away the node `a'.
+ 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts
+ string `s' and transit to `b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
+ away the node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
+ thrown away, we throw away the node `a'.
+ 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
+ node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
+ we throw away the node `a'. */
+
+#define STATE_NODE_CONTAINS(state,node) \
+ ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
+
+static reg_errcode_t
+internal_function
+sift_states_backward (re_match_context_t *mctx, re_sift_context_t *sctx)
+{
+ reg_errcode_t err;
+ int null_cnt = 0;
+ Idx str_idx = sctx->last_str_idx;
+ re_node_set cur_dest;
+
+#ifdef DEBUG
+ assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
+#endif
+
+ /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
+ transit to the last_node and the last_node itself. */
+ err = re_node_set_init_1 (&cur_dest, sctx->last_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* Then check each states in the state_log. */
+ while (str_idx > 0)
+ {
+ /* Update counters. */
+ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
+ if (null_cnt > mctx->max_mb_elem_len)
+ {
+ memset (sctx->sifted_states, '\0',
+ sizeof (re_dfastate_t *) * str_idx);
+ re_node_set_free (&cur_dest);
+ return REG_NOERROR;
+ }
+ re_node_set_empty (&cur_dest);
+ --str_idx;
+
+ if (mctx->state_log[str_idx])
+ {
+ err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* Add all the nodes which satisfy the following conditions:
+ - It can epsilon transit to a node in CUR_DEST.
+ - It is in CUR_SRC.
+ And update state_log. */
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ err = REG_NOERROR;
+ free_return:
+ re_node_set_free (&cur_dest);
+ return err;
+}
+
+static reg_errcode_t
+internal_function
+build_sifted_states (re_match_context_t *mctx, re_sift_context_t *sctx,
+ Idx str_idx, re_node_set *cur_dest)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
+ Idx i;
+
+ /* Then build the next sifted state.
+ We build the next sifted state on `cur_dest', and update
+ `sifted_states[str_idx]' with `cur_dest'.
+ Note:
+ `cur_dest' is the sifted state from `state_log[str_idx + 1]'.
+ `cur_src' points the node_set of the old `state_log[str_idx]'
+ (with the epsilon nodes pre-filtered out). */
+ for (i = 0; i < cur_src->nelem; i++)
+ {
+ Idx prev_node = cur_src->elems[i];
+ int naccepted = 0;
+ bool ok;
+
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[prev_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[prev_node].accept_mb)
+ naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
+ str_idx, sctx->last_str_idx);
+#endif /* RE_ENABLE_I18N */
+
+ /* We don't check backreferences here.
+ See update_cur_sifted_state(). */
+ if (!naccepted
+ && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
+ && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
+ dfa->nexts[prev_node]))
+ naccepted = 1;
+
+ if (naccepted == 0)
+ continue;
+
+ if (sctx->limits.nelem)
+ {
+ Idx to_idx = str_idx + naccepted;
+ if (check_dst_limits (mctx, &sctx->limits,
+ dfa->nexts[prev_node], to_idx,
+ prev_node, str_idx))
+ continue;
+ }
+ ok = re_node_set_insert (cur_dest, prev_node);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions. */
+
+static reg_errcode_t
+internal_function
+clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx)
+{
+ Idx top = mctx->state_log_top;
+
+ if (next_state_log_idx >= mctx->input.bufs_len
+ || (next_state_log_idx >= mctx->input.valid_len
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ reg_errcode_t err;
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (top < next_state_log_idx)
+ {
+ memset (mctx->state_log + top + 1, '\0',
+ sizeof (re_dfastate_t *) * (next_state_log_idx - top));
+ mctx->state_log_top = next_state_log_idx;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+merge_state_array (re_dfa_t *dfa, re_dfastate_t **dst, re_dfastate_t **src,
+ Idx num)
+{
+ Idx st_idx;
+ reg_errcode_t err;
+ for (st_idx = 0; st_idx < num; ++st_idx)
+ {
+ if (dst[st_idx] == NULL)
+ dst[st_idx] = src[st_idx];
+ else if (src[st_idx] != NULL)
+ {
+ re_node_set merged_set;
+ err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
+ &src[st_idx]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
+ re_node_set_free (&merged_set);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+update_cur_sifted_state (re_match_context_t *mctx, re_sift_context_t *sctx,
+ Idx str_idx, re_node_set *dest_nodes)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ const re_node_set *candidates;
+ candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
+ : &mctx->state_log[str_idx]->nodes);
+
+ if (dest_nodes->nelem == 0)
+ sctx->sifted_states[str_idx] = NULL;
+ else
+ {
+ if (candidates)
+ {
+ /* At first, add the nodes which can epsilon transit to a node in
+ DEST_NODE. */
+ err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Then, check the limitations in the current sift_context. */
+ if (sctx->limits.nelem)
+ {
+ err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
+ mctx->bkref_ents, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+
+ sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (candidates && mctx->state_log[str_idx]->has_backref)
+ {
+ err = sift_states_bkref (mctx, sctx, str_idx, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+add_epsilon_src_nodes (re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ reg_errcode_t err = REG_NOERROR;
+ Idx i;
+
+ re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (!state->inveclosure.alloc)
+ {
+ err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < dest_nodes->nelem; i++)
+ re_node_set_merge (&state->inveclosure,
+ dfa->inveclosures + dest_nodes->elems[i]);
+ }
+ return re_node_set_add_intersect (dest_nodes, candidates,
+ &state->inveclosure);
+}
+
+static reg_errcode_t
+internal_function
+sub_epsilon_src_nodes (re_dfa_t *dfa, Idx node, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ Idx ecl_idx;
+ reg_errcode_t err;
+ re_node_set *inv_eclosure = dfa->inveclosures + node;
+ re_node_set except_nodes;
+ re_node_set_init_empty (&except_nodes);
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ Idx cur_node = inv_eclosure->elems[ecl_idx];
+ if (cur_node == node)
+ continue;
+ if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
+ {
+ Idx edst1 = dfa->edests[cur_node].elems[0];
+ Idx edst2 = ((dfa->edests[cur_node].nelem > 1)
+ ? dfa->edests[cur_node].elems[1] : REG_MISSING);
+ if ((!re_node_set_contains (inv_eclosure, edst1)
+ && re_node_set_contains (dest_nodes, edst1))
+ || (REG_VALID_NONZERO_INDEX (edst2)
+ && !re_node_set_contains (inv_eclosure, edst2)
+ && re_node_set_contains (dest_nodes, edst2)))
+ {
+ err = re_node_set_add_intersect (&except_nodes, candidates,
+ dfa->inveclosures + cur_node);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&except_nodes);
+ return err;
+ }
+ }
+ }
+ }
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ Idx cur_node = inv_eclosure->elems[ecl_idx];
+ if (!re_node_set_contains (&except_nodes, cur_node))
+ {
+ Idx idx = re_node_set_contains (dest_nodes, cur_node) - 1;
+ re_node_set_remove_at (dest_nodes, idx);
+ }
+ }
+ re_node_set_free (&except_nodes);
+ return REG_NOERROR;
+}
+
+static bool
+internal_function
+check_dst_limits (const re_match_context_t *mctx, const re_node_set *limits,
+ Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ Idx lim_idx, src_pos, dst_pos;
+
+ Idx dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
+ Idx src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ Idx subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = mctx->bkref_ents + limits->elems[lim_idx];
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+
+ dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, dst_node, dst_idx,
+ dst_bkref_idx);
+ src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, src_node, src_idx,
+ src_bkref_idx);
+
+ /* In case of:
+ <src> <dst> ( <subexp> )
+ ( <subexp> ) <src> <dst>
+ ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
+ if (src_pos == dst_pos)
+ continue; /* This is unrelated limitation. */
+ else
+ return true;
+ }
+ return false;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries,
+ Idx subexp_idx, Idx from_node, Idx bkref_idx)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ re_node_set *eclosures = dfa->eclosures + from_node;
+ Idx node_idx;
+
+ /* Else, we are on the boundary: examine the nodes on the epsilon
+ closure. */
+ for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
+ {
+ Idx node = eclosures->elems[node_idx];
+ switch (dfa->nodes[node].type)
+ {
+ case OP_BACK_REF:
+ if (bkref_idx != REG_MISSING)
+ {
+ struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
+ do
+ {
+ Idx dst;
+ int cpos;
+
+ if (ent->node != node)
+ continue;
+
+ if (subexp_idx < BITSET_WORD_BITS
+ && !(ent->eps_reachable_subexps_map
+ & ((bitset_word) 1 << subexp_idx)))
+ continue;
+
+ /* Recurse trying to reach the OP_OPEN_SUBEXP and
+ OP_CLOSE_SUBEXP cases below. But, if the
+ destination node is the same node as the source
+ node, don't recurse because it would cause an
+ infinite loop: a regex that exhibits this behavior
+ is ()\1*\1* */
+ dst = dfa->edests[node].elems[0];
+ if (dst == from_node)
+ {
+ if (boundaries & 1)
+ return -1;
+ else /* if (boundaries & 2) */
+ return 0;
+ }
+
+ cpos =
+ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ dst, bkref_idx);
+ if (cpos == -1 /* && (boundaries & 1) */)
+ return -1;
+ if (cpos == 0 && (boundaries & 2))
+ return 0;
+
+ if (subexp_idx < BITSET_WORD_BITS)
+ ent->eps_reachable_subexps_map &=
+ ~ ((bitset_word) 1 << subexp_idx);
+ }
+ while (ent++->more);
+ }
+ break;
+
+ case OP_OPEN_SUBEXP:
+ if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
+ return -1;
+ break;
+
+ case OP_CLOSE_SUBEXP:
+ if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
+ return 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (boundaries & 2) ? 1 : 0;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos (const re_match_context_t *mctx,
+ Idx limit, Idx subexp_idx,
+ Idx from_node, Idx str_idx, Idx bkref_idx)
+{
+ struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
+ int boundaries;
+
+ /* If we are outside the range of the subexpression, return -1 or 1. */
+ if (str_idx < lim->subexp_from)
+ return -1;
+
+ if (lim->subexp_to < str_idx)
+ return 1;
+
+ /* If we are within the subexpression, return 0. */
+ boundaries = (str_idx == lim->subexp_from);
+ boundaries |= (str_idx == lim->subexp_to) << 1;
+ if (boundaries == 0)
+ return 0;
+
+ /* Else, examine epsilon closure. */
+ return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ from_node, bkref_idx);
+}
+
+/* Check the limitations of sub expressions LIMITS, and remove the nodes
+ which are against limitations from DEST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_subexp_limits (re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates, re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents, Idx str_idx)
+{
+ reg_errcode_t err;
+ Idx node_idx, lim_idx;
+
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ Idx subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = bkref_ents + limits->elems[lim_idx];
+
+ if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
+ continue; /* This is unrelated limitation. */
+
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+ if (ent->subexp_to == str_idx)
+ {
+ Idx ops_node = REG_MISSING;
+ Idx cls_node = REG_MISSING;
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ Idx node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_OPEN_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ ops_node = node;
+ else if (type == OP_CLOSE_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ cls_node = node;
+ }
+
+ /* Check the limitation of the open subexpression. */
+ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
+ if (REG_VALID_INDEX (ops_node))
+ {
+ err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Check the limitation of the close subexpression. */
+ if (REG_VALID_INDEX (cls_node))
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ Idx node = dest_nodes->elems[node_idx];
+ if (!re_node_set_contains (dfa->inveclosures + node,
+ cls_node)
+ && !re_node_set_contains (dfa->eclosures + node,
+ cls_node))
+ {
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ --node_idx;
+ }
+ }
+ }
+ else /* (ent->subexp_to != str_idx) */
+ {
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ Idx node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
+ {
+ if (subexp_idx != dfa->nodes[node].opr.idx)
+ continue;
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+sift_states_bkref (re_match_context_t *mctx, re_sift_context_t *sctx,
+ Idx str_idx, const re_node_set *candidates)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ Idx node_idx, node;
+ re_sift_context_t local_sctx;
+ Idx first_idx = search_cur_bkref_entry (mctx, str_idx);
+
+ if (first_idx == REG_MISSING)
+ return REG_NOERROR;
+
+ local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
+
+ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
+ {
+ Idx enabled_idx;
+ re_token_type_t type;
+ struct re_backref_cache_entry *entry;
+ node = candidates->elems[node_idx];
+ type = dfa->nodes[node].type;
+ /* Avoid infinite loop for the REs like "()\1+". */
+ if (node == sctx->last_node && str_idx == sctx->last_str_idx)
+ continue;
+ if (type != OP_BACK_REF)
+ continue;
+
+ entry = mctx->bkref_ents + first_idx;
+ enabled_idx = first_idx;
+ do
+ {
+ bool ok;
+ Idx subexp_len, to_idx, dst_node;
+ re_dfastate_t *cur_state;
+
+ if (entry->node != node)
+ continue;
+ subexp_len = entry->subexp_to - entry->subexp_from;
+ to_idx = str_idx + subexp_len;
+ dst_node = (subexp_len ? dfa->nexts[node]
+ : dfa->edests[node].elems[0]);
+
+ if (to_idx > sctx->last_str_idx
+ || sctx->sifted_states[to_idx] == NULL
+ || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
+ || check_dst_limits (mctx, &sctx->limits, node,
+ str_idx, dst_node, to_idx))
+ continue;
+
+ if (local_sctx.sifted_states == NULL)
+ {
+ local_sctx = *sctx;
+ err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.last_node = node;
+ local_sctx.last_str_idx = str_idx;
+ ok = re_node_set_insert (&local_sctx.limits, enabled_idx);
+ if (BE (! ok, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ cur_state = local_sctx.sifted_states[str_idx];
+ err = sift_states_backward (mctx, &local_sctx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ if (sctx->limited_states != NULL)
+ {
+ err = merge_state_array (dfa, sctx->limited_states,
+ local_sctx.sifted_states,
+ str_idx + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.sifted_states[str_idx] = cur_state;
+ re_node_set_remove (&local_sctx.limits, enabled_idx);
+
+ /* mctx->bkref_ents may have changed, reload the pointer. */
+ entry = mctx->bkref_ents + enabled_idx;
+ }
+ while (enabled_idx++, entry++->more);
+ }
+ err = REG_NOERROR;
+ free_return:
+ if (local_sctx.sifted_states != NULL)
+ {
+ re_node_set_free (&local_sctx.limits);
+ }
+
+ return err;
+}
+
+
+#ifdef RE_ENABLE_I18N
+static int
+internal_function
+sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ Idx node_idx, Idx str_idx, Idx max_str_idx)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int naccepted;
+ /* Check the node can accept `multi byte'. */
+ naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
+ if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
+ !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
+ dfa->nexts[node_idx]))
+ /* The node can't accept the `multi byte', or the
+ destination was already thrown away, then the node
+ could't accept the current input `multi byte'. */
+ naccepted = 0;
+ /* Otherwise, it is sure that the node could accept
+ `naccepted' bytes input. */
+ return naccepted;
+}
+#endif /* RE_ENABLE_I18N */
+
+
+/* Functions for state transition. */
+
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte, and update STATE_LOG if necessary.
+ If STATE can accept a multibyte char/collating element/back reference
+ update the destination of STATE_LOG. */
+
+static re_dfastate_t *
+internal_function
+transit_state (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ re_dfastate_t **trtable;
+ unsigned char ch;
+
+#ifdef RE_ENABLE_I18N
+ /* If the current state can accept multibyte. */
+ if (BE (state->accept_mb, 0))
+ {
+ *err = transit_state_mb (mctx, state);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ /* Then decide the next state with the single byte. */
+#if 0
+ if (0)
+ /* don't use transition table */
+ return transit_state_sb (err, mctx, state);
+#endif
+
+ /* Use transition table */
+ ch = re_string_fetch_byte (&mctx->input);
+ for (;;)
+ {
+ trtable = state->trtable;
+ if (BE (trtable != NULL, 1))
+ return trtable[ch];
+
+ trtable = state->word_trtable;
+ if (BE (trtable != NULL, 1))
+ {
+ unsigned int context;
+ context
+ = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return trtable[ch + SBC_MAX];
+ else
+ return trtable[ch];
+ }
+
+ if (!build_trtable (mctx->dfa, state))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ /* Retry, we now have a transition table. */
+ }
+}
+
+/* Update the state_log if we need */
+re_dfastate_t *
+internal_function
+merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *next_state)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ Idx cur_idx = re_string_cur_idx (&mctx->input);
+
+ if (cur_idx > mctx->state_log_top)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ mctx->state_log_top = cur_idx;
+ }
+ else if (mctx->state_log[cur_idx] == 0)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ }
+ else
+ {
+ re_dfastate_t *pstate;
+ unsigned int context;
+ re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
+ /* If (state_log[cur_idx] != 0), it implies that cur_idx is
+ the destination of a multibyte char/collating element/
+ back reference. Then the next state is the union set of
+ these destinations and the results of the transition table. */
+ pstate = mctx->state_log[cur_idx];
+ log_nodes = pstate->entrance_nodes;
+ if (next_state != NULL)
+ {
+ table_nodes = next_state->entrance_nodes;
+ *err = re_node_set_init_union (&next_nodes, table_nodes,
+ log_nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+ else
+ next_nodes = *log_nodes;
+ /* Note: We already add the nodes of the initial state,
+ then we don't need to add them here. */
+
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ next_state = mctx->state_log[cur_idx]
+ = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ if (table_nodes != NULL)
+ re_node_set_free (&next_nodes);
+ }
+
+ if (BE (dfa->nbackref, 0) && next_state != NULL)
+ {
+ /* Check OP_OPEN_SUBEXP in the current state in case that we use them
+ later. We must check them here, since the back references in the
+ next state might use them. */
+ *err = check_subexp_matching_top (mctx, &next_state->nodes,
+ cur_idx);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+
+ /* If the next state has back references. */
+ if (next_state->has_backref)
+ {
+ *err = transit_state_bkref (mctx, &next_state->nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ next_state = mctx->state_log[cur_idx];
+ }
+ }
+
+ return next_state;
+}
+
+/* Skip bytes in the input that correspond to part of a
+ multi-byte match, then look in the log for a state
+ from which to restart matching. */
+static re_dfastate_t *
+internal_function
+find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
+{
+ re_dfastate_t *cur_state = NULL;
+ do
+ {
+ Idx max = mctx->state_log_top;
+ Idx cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ do
+ {
+ if (++cur_str_idx > max)
+ return NULL;
+ re_string_skip_bytes (&mctx->input, 1);
+ }
+ while (mctx->state_log[cur_str_idx] == NULL);
+
+ cur_state = merge_state_with_log (err, mctx, NULL);
+ }
+ while (*err == REG_NOERROR && cur_state == NULL);
+ return cur_state;
+}
+
+/* Helper functions for transit_state. */
+
+/* From the node set CUR_NODES, pick up the nodes whose types are
+ OP_OPEN_SUBEXP and which have corresponding back references in the regular
+ expression. And register them to use them later for evaluating the
+ correspoding back references. */
+
+static reg_errcode_t
+internal_function
+check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes,
+ Idx str_idx)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ Idx node_idx;
+ reg_errcode_t err;
+
+ /* TODO: This isn't efficient.
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
+ {
+ Idx node = cur_nodes->elems[node_idx];
+ if (dfa->nodes[node].type == OP_OPEN_SUBEXP
+ && dfa->nodes[node].opr.idx < BITSET_WORD_BITS
+ && (dfa->used_bkref_map
+ & ((bitset_word) 1 << dfa->nodes[node].opr.idx)))
+ {
+ err = match_ctx_add_subtop (mctx, node, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+#if 0
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte. */
+
+static re_dfastate_t *
+transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ re_node_set next_nodes;
+ re_dfastate_t *next_state;
+ Idx node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
+ unsigned int context;
+
+ *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
+ {
+ Idx cur_node = state->nodes.elems[node_cnt];
+ if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
+ {
+ *err = re_node_set_merge (&next_nodes,
+ dfa->eclosures + dfa->nexts[cur_node]);
+ if (BE (*err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return NULL;
+ }
+ }
+ }
+ context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
+ next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ re_node_set_free (&next_nodes);
+ re_string_skip_bytes (&mctx->input, 1);
+ return next_state;
+}
+#endif
+
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t
+internal_function
+transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ Idx i;
+
+ for (i = 0; i < pstate->nodes.nelem; ++i)
+ {
+ re_node_set dest_nodes, *new_nodes;
+ Idx cur_node_idx = pstate->nodes.elems[i];
+ int naccepted;
+ Idx dest_idx;
+ unsigned int context;
+ re_dfastate_t *dest_state;
+
+ if (!dfa->nodes[cur_node_idx].accept_mb)
+ continue;
+
+ if (dfa->nodes[cur_node_idx].constraint)
+ {
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input),
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
+ context))
+ continue;
+ }
+
+ /* How many bytes the node can accept? */
+ naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
+ re_string_cur_idx (&mctx->input));
+ if (naccepted == 0)
+ continue;
+
+ /* The node can accepts `naccepted' bytes. */
+ dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
+ mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
+ : mctx->max_mb_elem_len);
+ err = clean_state_log_if_needed (mctx, dest_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+#ifdef DEBUG
+ assert (dfa->nexts[cur_node_idx] != REG_MISSING);
+#endif
+ new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
+
+ dest_state = mctx->state_log[dest_idx];
+ if (dest_state == NULL)
+ dest_nodes = *new_nodes;
+ else
+ {
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes, new_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ context = re_string_context_at (&mctx->input, dest_idx - 1, mctx->eflags);
+ mctx->state_log[dest_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ if (dest_state != NULL)
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+#endif /* RE_ENABLE_I18N */
+
+static reg_errcode_t
+internal_function
+transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ Idx i;
+ Idx cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ for (i = 0; i < nodes->nelem; ++i)
+ {
+ Idx dest_str_idx, prev_nelem, bkc_idx;
+ Idx node_idx = nodes->elems[i];
+ unsigned int context;
+ const re_token_t *node = dfa->nodes + node_idx;
+ re_node_set *new_dest_nodes;
+
+ /* Check whether `node' is a backreference or not. */
+ if (node->type != OP_BACK_REF)
+ continue;
+
+ if (node->constraint)
+ {
+ context = re_string_context_at (&mctx->input, cur_str_idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ continue;
+ }
+
+ /* `node' is a backreference.
+ Check the substring which the substring matched. */
+ bkc_idx = mctx->nbkref_ents;
+ err = get_subexp (mctx, node_idx, cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* And add the epsilon closures (which is `new_dest_nodes') of
+ the backreference to appropriate state_log. */
+#ifdef DEBUG
+ assert (dfa->nexts[node_idx] != REG_MISSING);
+#endif
+ for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
+ {
+ Idx subexp_len;
+ re_dfastate_t *dest_state;
+ struct re_backref_cache_entry *bkref_ent;
+ bkref_ent = mctx->bkref_ents + bkc_idx;
+ if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
+ continue;
+ subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
+ new_dest_nodes = (subexp_len == 0
+ ? dfa->eclosures + dfa->edests[node_idx].elems[0]
+ : dfa->eclosures + dfa->nexts[node_idx]);
+ dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
+ - bkref_ent->subexp_from);
+ context = re_string_context_at (&mctx->input, dest_str_idx - 1,
+ mctx->eflags);
+ dest_state = mctx->state_log[dest_str_idx];
+ prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
+ : mctx->state_log[cur_str_idx]->nodes.nelem);
+ /* Add `new_dest_node' to state_log. */
+ if (dest_state == NULL)
+ {
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, new_dest_nodes,
+ context);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ re_node_set dest_nodes;
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes,
+ new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&dest_nodes);
+ goto free_return;
+ }
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ /* We need to check recursively if the backreference can epsilon
+ transit. */
+ if (subexp_len == 0
+ && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
+ {
+ err = check_subexp_matching_top (mctx, new_dest_nodes,
+ cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ err = transit_state_bkref (mctx, new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ }
+ }
+ err = REG_NOERROR;
+ free_return:
+ return err;
+}
+
+/* Enumerate all the candidates which the backreference BKREF_NODE can match
+ at BKREF_STR_IDX, and register them by match_ctx_add_entry().
+ Note that we might collect inappropriate candidates here.
+ However, the cost of checking them strictly here is too high, then we
+ delay these checking for prune_impossible_nodes(). */
+
+static reg_errcode_t
+internal_function
+get_subexp (re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ Idx subexp_num, sub_top_idx;
+ const char *buf = (const char *) re_string_get_buffer (&mctx->input);
+ /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
+ Idx cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
+ if (cache_idx != REG_MISSING)
+ {
+ const struct re_backref_cache_entry *entry = mctx->bkref_ents + cache_idx;
+ do
+ if (entry->node == bkref_node)
+ return REG_NOERROR; /* We already checked it. */
+ while (entry++->more);
+ }
+
+ subexp_num = dfa->nodes[bkref_node].opr.idx;
+
+ /* For each sub expression */
+ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
+ {
+ reg_errcode_t err;
+ re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
+ re_sub_match_last_t *sub_last;
+ Idx sub_last_idx, sl_str, bkref_str_off;
+
+ if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
+ continue; /* It isn't related. */
+
+ sl_str = sub_top->str_idx;
+ bkref_str_off = bkref_str_idx;
+ /* At first, check the last node of sub expressions we already
+ evaluated. */
+ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
+ {
+ regoff_t sl_str_diff;
+ sub_last = sub_top->lasts[sub_last_idx];
+ sl_str_diff = sub_last->str_idx - sl_str;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_diff > 0)
+ {
+ if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
+ {
+ /* Not enough chars for a successful match. */
+ if (bkref_str_off + sl_str_diff > mctx->input.len)
+ break;
+
+ err = clean_state_log_if_needed (mctx,
+ bkref_str_off
+ + sl_str_diff);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
+ break; /* We don't need to search this sub expression any more. */
+ }
+ bkref_str_off += sl_str_diff;
+ sl_str += sl_str_diff;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+
+ /* Reload buf, since the preceding call might have reallocated
+ the buffer. */
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (sub_last_idx < sub_top->nlasts)
+ continue;
+ if (sub_last_idx > 0)
+ ++sl_str;
+ /* Then, search for the other last nodes of the sub expression. */
+ for (; sl_str <= bkref_str_idx; ++sl_str)
+ {
+ Idx cls_node;
+ regoff_t sl_str_off;
+ const re_node_set *nodes;
+ sl_str_off = sl_str - sub_top->str_idx;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_off > 0)
+ {
+ if (BE (bkref_str_off >= mctx->input.valid_len, 0))
+ {
+ /* If we are at the end of the input, we cannot match. */
+ if (bkref_str_off >= mctx->input.len)
+ break;
+
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (buf [bkref_str_off++] != buf[sl_str - 1])
+ break; /* We don't need to search this sub expression
+ any more. */
+ }
+ if (mctx->state_log[sl_str] == NULL)
+ continue;
+ /* Does this state have a ')' of the sub expression? */
+ nodes = &mctx->state_log[sl_str]->nodes;
+ cls_node = find_subexp_node (dfa, nodes, subexp_num, OP_CLOSE_SUBEXP);
+ if (cls_node == REG_MISSING)
+ continue; /* No. */
+ if (sub_top->path == NULL)
+ {
+ sub_top->path = re_calloc (state_array_t,
+ sl_str - sub_top->str_idx + 1);
+ if (sub_top->path == NULL)
+ return REG_ESPACE;
+ }
+ /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
+ in the current context? */
+ err = check_arrival (mctx, sub_top->path, sub_top->node,
+ sub_top->str_idx, cls_node, sl_str, OP_CLOSE_SUBEXP);
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
+ if (BE (sub_last == NULL, 0))
+ return REG_ESPACE;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+ if (err == REG_NOMATCH)
+ continue;
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Helper functions for get_subexp(). */
+
+/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
+ If it can arrive, register the sub expression expressed with SUB_TOP
+ and SUB_LAST. */
+
+static reg_errcode_t
+internal_function
+get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last, Idx bkref_node, Idx bkref_str)
+{
+ reg_errcode_t err;
+ Idx to_idx;
+ /* Can the subexpression arrive the back reference? */
+ err = check_arrival (mctx, &sub_last->path, sub_last->node,
+ sub_last->str_idx, bkref_node, bkref_str, OP_OPEN_SUBEXP);
+ if (err != REG_NOERROR)
+ return err;
+ err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
+ sub_last->str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
+ return clean_state_log_if_needed (mctx, to_idx);
+}
+
+/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
+ Search '(' if FL_OPEN, or search ')' otherwise.
+ TODO: This function isn't efficient...
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+
+static Idx
+internal_function
+find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ Idx subexp_idx, int type)
+{
+ Idx cls_idx;
+ for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
+ {
+ Idx cls_node = nodes->elems[cls_idx];
+ const re_token_t *node = dfa->nodes + cls_node;
+ if (node->type == type
+ && node->opr.idx == subexp_idx)
+ return cls_node;
+ }
+ return REG_MISSING;
+}
+
+/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
+ LAST_NODE at LAST_STR. We record the path onto PATH since it will be
+ heavily reused.
+ Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
+
+static reg_errcode_t
+internal_function
+check_arrival (re_match_context_t *mctx, state_array_t *path,
+ Idx top_node, Idx top_str, Idx last_node, Idx last_str,
+ int type)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ Idx subexp_num, backup_cur_idx, str_idx, null_cnt;
+ re_dfastate_t *cur_state = NULL;
+ re_node_set *cur_nodes, next_nodes;
+ re_dfastate_t **backup_state_log;
+ unsigned int context;
+
+ subexp_num = dfa->nodes[top_node].opr.idx;
+ /* Extend the buffer if we need. */
+ if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
+ {
+ re_dfastate_t **new_array;
+ Idx old_alloc = path->alloc;
+ Idx new_alloc = old_alloc + last_str + mctx->max_mb_elem_len + 1;
+ if (BE (new_alloc < old_alloc, 0))
+ return REG_ESPACE;
+ new_array = re_xrealloc (path->array, re_dfastate_t *, new_alloc);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ path->array = new_array;
+ path->alloc = new_alloc;
+ memset (new_array + old_alloc, '\0',
+ sizeof (re_dfastate_t *) * (new_alloc - old_alloc));
+ }
+
+ str_idx = path->next_idx == 0 ? top_str : path->next_idx;
+
+ /* Temporary modify MCTX. */
+ backup_state_log = mctx->state_log;
+ backup_cur_idx = mctx->input.cur_idx;
+ mctx->state_log = path->array;
+ mctx->input.cur_idx = str_idx;
+
+ /* Setup initial node set. */
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ if (str_idx == top_str)
+ {
+ err = re_node_set_init_1 (&next_nodes, top_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ cur_state = mctx->state_log[str_idx];
+ if (cur_state && cur_state->has_backref)
+ {
+ err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
+ if (BE ( err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ re_node_set_init_empty (&next_nodes);
+ }
+ if (str_idx == top_str || (cur_state && cur_state->has_backref))
+ {
+ if (next_nodes.nelem)
+ {
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE ( err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ }
+
+ for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
+ {
+ re_node_set_empty (&next_nodes);
+ if (mctx->state_log[str_idx + 1])
+ {
+ err = re_node_set_merge (&next_nodes,
+ &mctx->state_log[str_idx + 1]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ if (cur_state)
+ {
+ err = check_arrival_add_next_nodes (mctx, str_idx,
+ &cur_state->non_eps_nodes, &next_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ ++str_idx;
+ if (next_nodes.nelem)
+ {
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE ( err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
+ }
+ re_node_set_free (&next_nodes);
+ cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
+ : &mctx->state_log[last_str]->nodes);
+ path->next_idx = str_idx;
+
+ /* Fix MCTX. */
+ mctx->state_log = backup_state_log;
+ mctx->input.cur_idx = backup_cur_idx;
+
+ /* Then check the current node set has the node LAST_NODE. */
+ if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
+ return REG_NOERROR;
+
+ return REG_NOMATCH;
+}
+
+/* Helper functions for check_arrival. */
+
+/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
+ to NEXT_NODES.
+ TODO: This function is similar to the functions transit_state*(),
+ however this function has many additional works.
+ Can't we unify them? */
+
+static reg_errcode_t
+internal_function
+check_arrival_add_next_nodes (re_match_context_t *mctx, Idx str_idx,
+ re_node_set *cur_nodes,
+ re_node_set *next_nodes)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ bool ok;
+ Idx cur_idx;
+ reg_errcode_t err;
+ re_node_set union_set;
+ re_node_set_init_empty (&union_set);
+ for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
+ {
+ int naccepted = 0;
+ Idx cur_node = cur_nodes->elems[cur_idx];
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[cur_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[cur_node].accept_mb)
+ {
+ naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
+ str_idx);
+ if (naccepted > 1)
+ {
+ re_dfastate_t *dest_state;
+ Idx next_node = dfa->nexts[cur_node];
+ Idx next_idx = str_idx + naccepted;
+ dest_state = mctx->state_log[next_idx];
+ re_node_set_empty (&union_set);
+ if (dest_state)
+ {
+ err = re_node_set_merge (&union_set, &dest_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ ok = re_node_set_insert (&union_set, next_node);
+ if (BE (! ok, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
+ &union_set);
+ if (BE (mctx->state_log[next_idx] == NULL
+ && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (naccepted
+ || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
+ {
+ ok = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
+ if (BE (! ok, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ }
+ }
+ re_node_set_free (&union_set);
+ return REG_NOERROR;
+}
+
+/* For all the nodes in CUR_NODES, add the epsilon closures of them to
+ CUR_NODES, however exclude the nodes which are:
+ - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
+ - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
+*/
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl (re_dfa_t *dfa, re_node_set *cur_nodes,
+ Idx ex_subexp, int type)
+{
+ reg_errcode_t err;
+ Idx idx, outside_node;
+ re_node_set new_nodes;
+#ifdef DEBUG
+ assert (cur_nodes->nelem);
+#endif
+ err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ /* Create a new node set NEW_NODES with the nodes which are epsilon
+ closures of the node in CUR_NODES. */
+
+ for (idx = 0; idx < cur_nodes->nelem; ++idx)
+ {
+ Idx cur_node = cur_nodes->elems[idx];
+ re_node_set *eclosure = dfa->eclosures + cur_node;
+ outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
+ if (outside_node == REG_MISSING)
+ {
+ /* There are no problematic nodes, just merge them. */
+ err = re_node_set_merge (&new_nodes, eclosure);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ /* There are problematic nodes, re-calculate incrementally. */
+ err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ }
+ re_node_set_free (cur_nodes);
+ *cur_nodes = new_nodes;
+ return REG_NOERROR;
+}
+
+/* Helper function for check_arrival_expand_ecl.
+ Check incrementally the epsilon closure of TARGET, and if it isn't
+ problematic append it to DST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl_sub (re_dfa_t *dfa, re_node_set *dst_nodes,
+ Idx target, Idx ex_subexp, int type)
+{
+ Idx cur_node;
+ for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
+ {
+ bool ok;
+
+ if (dfa->nodes[cur_node].type == type
+ && dfa->nodes[cur_node].opr.idx == ex_subexp)
+ {
+ if (type == OP_CLOSE_SUBEXP)
+ {
+ ok = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ }
+ break;
+ }
+ ok = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (! ok, 0))
+ return REG_ESPACE;
+ if (dfa->edests[cur_node].nelem == 0)
+ break;
+ if (dfa->edests[cur_node].nelem == 2)
+ {
+ reg_errcode_t ret =
+ check_arrival_expand_ecl_sub (dfa, dst_nodes,
+ dfa->edests[cur_node].elems[1],
+ ex_subexp, type);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ cur_node = dfa->edests[cur_node].elems[0];
+ }
+ return REG_NOERROR;
+}
+
+
+/* For all the back references in the current state, calculate the
+ destination of the back references by the appropriate entry
+ in MCTX->BKREF_ENTS. */
+
+static reg_errcode_t
+internal_function
+expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes,
+ Idx cur_str, Idx subexp_num, int type)
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ Idx cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
+ struct re_backref_cache_entry *ent;
+
+ if (cache_idx_start == REG_MISSING)
+ return REG_NOERROR;
+
+ restart:
+ ent = mctx->bkref_ents + cache_idx_start;
+ do
+ {
+ Idx to_idx, next_node;
+
+ /* Is this entry ENT is appropriate? */
+ if (!re_node_set_contains (cur_nodes, ent->node))
+ continue; /* No. */
+
+ to_idx = cur_str + ent->subexp_to - ent->subexp_from;
+ /* Calculate the destination of the back reference, and append it
+ to MCTX->STATE_LOG. */
+ if (to_idx == cur_str)
+ {
+ /* The backreference did epsilon transit, we must re-check all the
+ node in the current state. */
+ re_node_set new_dests;
+ reg_errcode_t err2, err3;
+ next_node = dfa->edests[ent->node].elems[0];
+ if (re_node_set_contains (cur_nodes, next_node))
+ continue;
+ err = re_node_set_init_1 (&new_dests, next_node);
+ err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
+ err3 = re_node_set_merge (cur_nodes, &new_dests);
+ re_node_set_free (&new_dests);
+ if (BE (err != REG_NOERROR || err2 != REG_NOERROR
+ || err3 != REG_NOERROR, 0))
+ {
+ err = (err != REG_NOERROR ? err
+ : (err2 != REG_NOERROR ? err2 : err3));
+ return err;
+ }
+ /* TODO: It is still inefficient... */
+ goto restart;
+ }
+ else
+ {
+ re_node_set union_set;
+ next_node = dfa->nexts[ent->node];
+ if (mctx->state_log[to_idx])
+ {
+ bool ok;
+ if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
+ next_node))
+ continue;
+ err = re_node_set_init_copy (&union_set,
+ &mctx->state_log[to_idx]->nodes);
+ ok = re_node_set_insert (&union_set, next_node);
+ if (BE (err != REG_NOERROR || ! ok, 0))
+ {
+ re_node_set_free (&union_set);
+ err = err != REG_NOERROR ? err : REG_ESPACE;
+ return err;
+ }
+ }
+ else
+ {
+ err = re_node_set_init_1 (&union_set, next_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
+ re_node_set_free (&union_set);
+ if (BE (mctx->state_log[to_idx] == NULL
+ && err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ while (ent++->more);
+ return REG_NOERROR;
+}
+
+/* Build transition table for the state.
+ Return true if successful. */
+
+static bool
+internal_function
+build_trtable (re_dfa_t *dfa, re_dfastate_t *state)
+{
+ reg_errcode_t err;
+ Idx i, j;
+ int ch;
+ bool need_word_trtable = false;
+ bitset_word elem, mask;
+ bool dests_node_malloced = false, dest_states_malloced = false;
+ Idx ndests; /* Number of the destination states from `state'. */
+ re_dfastate_t **trtable;
+ re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
+ re_node_set follows, *dests_node;
+ bitset *dests_ch;
+ bitset acceptable;
+
+ struct dests_alloc
+ {
+ re_node_set dests_node[SBC_MAX];
+ bitset dests_ch[SBC_MAX];
+ } *dests_alloc;
+
+ /* We build DFA states which corresponds to the destination nodes
+ from `state'. `dests_node[i]' represents the nodes which i-th
+ destination state contains, and `dests_ch[i]' represents the
+ characters which i-th destination state accepts. */
+ if (__libc_use_alloca (sizeof (struct dests_alloc)))
+ dests_alloc = (struct dests_alloc *) alloca (sizeof dests_alloc[0]);
+ else
+ {
+ dests_alloc = re_malloc (struct dests_alloc, 1);
+ if (BE (dests_alloc == NULL, 0))
+ return false;
+ dests_node_malloced = true;
+ }
+ dests_node = dests_alloc->dests_node;
+ dests_ch = dests_alloc->dests_ch;
+
+ /* Initialize transiton table. */
+ state->word_trtable = state->trtable = NULL;
+
+ /* At first, group all nodes belonging to `state' into several
+ destinations. */
+ ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
+ if (BE (! REG_VALID_NONZERO_INDEX (ndests), 0))
+ {
+ if (dests_node_malloced)
+ free (dests_alloc);
+ if (ndests == 0)
+ {
+ state->trtable = re_calloc (re_dfastate_t *, SBC_MAX);
+ return true;
+ }
+ return false;
+ }
+
+ err = re_node_set_alloc (&follows, ndests + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+
+ /* Avoid arithmetic overflow in size calculation. */
+ if (BE (((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX)
+ / (3 * sizeof (re_dfastate_t *)))
+ < ndests, 0))
+ goto out_free;
+
+ if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX
+ + ndests * 3 * sizeof (re_dfastate_t *)))
+ dest_states = (re_dfastate_t **)
+ alloca (ndests * 3 * sizeof (re_dfastate_t *));
+ else
+ {
+ dest_states = (re_dfastate_t **)
+ malloc (ndests * 3 * sizeof (re_dfastate_t *));
+ if (BE (dest_states == NULL, 0))
+ {
+out_free:
+ if (dest_states_malloced)
+ free (dest_states);
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+ if (dests_node_malloced)
+ free (dests_alloc);
+ return false;
+ }
+ dest_states_malloced = true;
+ }
+ dest_states_word = dest_states + ndests;
+ dest_states_nl = dest_states_word + ndests;
+ bitset_empty (acceptable);
+
+ /* Then build the states for all destinations. */
+ for (i = 0; i < ndests; ++i)
+ {
+ Idx next_node;
+ re_node_set_empty (&follows);
+ /* Merge the follows of this destination states. */
+ for (j = 0; j < dests_node[i].nelem; ++j)
+ {
+ next_node = dfa->nexts[dests_node[i].elems[j]];
+ if (next_node != REG_MISSING)
+ {
+ err = re_node_set_merge (&follows, dfa->eclosures + next_node);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ }
+ dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
+ if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ /* If the new state has context constraint,
+ build appropriate states for these contexts. */
+ if (dest_states[i]->has_constraint)
+ {
+ dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_WORD);
+ if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+
+ if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
+ need_word_trtable = true;
+
+ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_NEWLINE);
+ if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ else
+ {
+ dest_states_word[i] = dest_states[i];
+ dest_states_nl[i] = dest_states[i];
+ }
+ bitset_merge (acceptable, dests_ch[i]);
+ }
+
+ if (!BE (need_word_trtable, 0))
+ {
+ /* We don't care about whether the following character is a word
+ character, or we are in a single-byte character set so we can
+ discern by looking at the character code: allocate a
+ 256-entry transition table. */
+ trtable = state->trtable = re_calloc (re_dfastate_t *, SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ if (dfa->word_char[i] & mask)
+ trtable[ch] = dest_states_word[j];
+ else
+ trtable[ch] = dest_states[j];
+ }
+ }
+ else
+ {
+ /* We care about whether the following character is a word
+ character, and we are in a multi-byte character set: discern
+ by looking at the character code: build two 256-entry
+ transition tables, one starting at trtable[0] and one
+ starting at trtable[SBC_MAX]. */
+ trtable = state->word_trtable = re_calloc (re_dfastate_t *, 2 * SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ trtable[ch] = dest_states[j];
+ trtable[ch + SBC_MAX] = dest_states_word[j];
+ }
+ }
+
+ /* new line */
+ if (bitset_contain (acceptable, NEWLINE_CHAR))
+ {
+ /* The current state accepts newline character. */
+ for (j = 0; j < ndests; ++j)
+ if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
+ {
+ /* k-th destination accepts newline character. */
+ trtable[NEWLINE_CHAR] = dest_states_nl[j];
+ if (need_word_trtable)
+ trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
+ /* There must be only one destination which accepts
+ newline. See group_nodes_into_DFAstates. */
+ break;
+ }
+ }
+
+ if (dest_states_malloced)
+ free (dest_states);
+
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+
+ if (dests_node_malloced)
+ free (dests_alloc);
+
+ return true;
+}
+
+/* Group all nodes belonging to STATE into several destinations.
+ Then for all destinations, set the nodes belonging to the destination
+ to DESTS_NODE[i] and set the characters accepted by the destination
+ to DEST_CH[i]. This function return the number of destinations. */
+
+static Idx
+internal_function
+group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
+ re_node_set *dests_node, bitset *dests_ch)
+{
+ reg_errcode_t err;
+ bool ok;
+ Idx i, j, k;
+ Idx ndests; /* Number of the destinations from `state'. */
+ bitset accepts; /* Characters a node can accept. */
+ const re_node_set *cur_nodes = &state->nodes;
+ bitset_empty (accepts);
+ ndests = 0;
+
+ /* For all the nodes belonging to `state', */
+ for (i = 0; i < cur_nodes->nelem; ++i)
+ {
+ re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
+ re_token_type_t type = node->type;
+ unsigned int constraint = node->constraint;
+
+ /* Enumerate all single byte character this node can accept. */
+ if (type == CHARACTER)
+ bitset_set (accepts, node->opr.c);
+ else if (type == SIMPLE_BRACKET)
+ {
+ bitset_merge (accepts, node->opr.sbcset);
+ }
+ else if (type == OP_PERIOD)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ bitset_merge (accepts, dfa->sb_char);
+ else
+#endif
+ bitset_set_all (accepts);
+ if (!(dfa->syntax & REG_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & REG_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == OP_UTF8_PERIOD)
+ {
+ if (SBC_MAX / 2 % BITSET_WORD_BITS == 0)
+ memset (accepts, -1, sizeof accepts / 2);
+ else
+ bitset_merge (accepts, utf8_sb_map);
+ if (!(dfa->syntax & REG_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & REG_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#endif
+ else
+ continue;
+
+ /* Check the `accepts' and sift the characters which are not
+ match it the context. */
+ if (constraint)
+ {
+ if (constraint & NEXT_NEWLINE_CONSTRAINT)
+ {
+ bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
+ bitset_empty (accepts);
+ if (accepts_newline)
+ bitset_set (accepts, NEWLINE_CHAR);
+ else
+ continue;
+ }
+ if (constraint & NEXT_ENDBUF_CONSTRAINT)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+
+ if (constraint & NEXT_WORD_CONSTRAINT)
+ {
+ bitset_word any_set = 0;
+ if (type == CHARACTER && !node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ if (constraint & NEXT_NOTWORD_CONSTRAINT)
+ {
+ bitset_word any_set = 0;
+ if (type == CHARACTER && node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ }
+
+ /* Then divide `accepts' into DFA states, or create a new
+ state. Above, we make sure that accepts is not empty. */
+ for (j = 0; j < ndests; ++j)
+ {
+ bitset intersec; /* Intersection sets, see below. */
+ bitset remains;
+ /* Flags, see below. */
+ bitset_word has_intersec, not_subset, not_consumed;
+
+ /* Optimization, skip if this state doesn't accept the character. */
+ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
+ continue;
+
+ /* Enumerate the intersection set of this state and `accepts'. */
+ has_intersec = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
+ /* And skip if the intersection set is empty. */
+ if (!has_intersec)
+ continue;
+
+ /* Then check if this state is a subset of `accepts'. */
+ not_subset = not_consumed = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ {
+ not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
+ not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
+ }
+
+ /* If this state isn't a subset of `accepts', create a
+ new group state, which has the `remains'. */
+ if (not_subset)
+ {
+ bitset_copy (dests_ch[ndests], remains);
+ bitset_copy (dests_ch[j], intersec);
+ err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ }
+
+ /* Put the position in the current group. */
+ ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
+ if (BE (! ok, 0))
+ goto error_return;
+
+ /* If all characters are consumed, go to next node. */
+ if (!not_consumed)
+ break;
+ }
+ /* Some characters remain, create a new group. */
+ if (j == ndests)
+ {
+ bitset_copy (dests_ch[ndests], accepts);
+ err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ bitset_empty (accepts);
+ }
+ }
+ return ndests;
+ error_return:
+ for (j = 0; j < ndests; ++j)
+ re_node_set_free (dests_node + j);
+ return REG_MISSING;
+}
+
+#ifdef RE_ENABLE_I18N
+/* Check how many bytes the node `dfa->nodes[node_idx]' accepts.
+ Return the number of the bytes the node accepts.
+ STR_IDX is the current index of the input string.
+
+ This function handles the nodes which can accept one character, or
+ one collating element like '.', '[a-z]', opposite to the other nodes
+ can only accept one byte. */
+
+static int
+internal_function
+check_node_accept_bytes (re_dfa_t *dfa, Idx node_idx,
+ const re_string_t *input, Idx str_idx)
+{
+ const re_token_t *node = dfa->nodes + node_idx;
+ int char_len, elem_len;
+ Idx i;
+
+ if (BE (node->type == OP_UTF8_PERIOD, 0))
+ {
+ unsigned char c = re_string_byte_at (input, str_idx), d;
+ if (BE (c < 0xc2, 1))
+ return 0;
+
+ if (str_idx + 2 > input->len)
+ return 0;
+
+ d = re_string_byte_at (input, str_idx + 1);
+ if (c < 0xe0)
+ return (d < 0x80 || d > 0xbf) ? 0 : 2;
+ else if (c < 0xf0)
+ {
+ char_len = 3;
+ if (c == 0xe0 && d < 0xa0)
+ return 0;
+ }
+ else if (c < 0xf8)
+ {
+ char_len = 4;
+ if (c == 0xf0 && d < 0x90)
+ return 0;
+ }
+ else if (c < 0xfc)
+ {
+ char_len = 5;
+ if (c == 0xf8 && d < 0x88)
+ return 0;
+ }
+ else if (c < 0xfe)
+ {
+ char_len = 6;
+ if (c == 0xfc && d < 0x84)
+ return 0;
+ }
+ else
+ return 0;
+
+ if (str_idx + char_len > input->len)
+ return 0;
+
+ for (i = 1; i < char_len; ++i)
+ {
+ d = re_string_byte_at (input, str_idx + i);
+ if (d < 0x80 || d > 0xbf)
+ return 0;
+ }
+ return char_len;
+ }
+
+ char_len = re_string_char_size_at (input, str_idx);
+ if (node->type == OP_PERIOD)
+ {
+ if (char_len <= 1)
+ return 0;
+ /* FIXME: I don't think this if is needed, as both '\n'
+ and '\0' are char_len == 1. */
+ /* '.' accepts any one character except the following two cases. */
+ if ((!(dfa->syntax & REG_DOT_NEWLINE) &&
+ re_string_byte_at (input, str_idx) == '\n') ||
+ ((dfa->syntax & REG_DOT_NOT_NULL) &&
+ re_string_byte_at (input, str_idx) == '\0'))
+ return 0;
+ return char_len;
+ }
+
+ elem_len = re_string_elem_size_at (input, str_idx);
+ if ((elem_len <= 1 && char_len <= 1) || char_len == 0)
+ return 0;
+
+ if (node->type == COMPLEX_BRACKET)
+ {
+ const re_charset_t *cset = node->opr.mbcset;
+# ifdef _LIBC
+ const unsigned char *pin
+ = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+ Idx j;
+ uint32_t nrules;
+# endif /* _LIBC */
+ int match_len = 0;
+ wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
+ ? re_string_wchar_at (input, str_idx) : 0);
+
+ /* match with multibyte character? */
+ for (i = 0; i < cset->nmbchars; ++i)
+ if (wc == cset->mbchars[i])
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ /* match with character_class? */
+ for (i = 0; i < cset->nchar_classes; ++i)
+ {
+ wctype_t wt = cset->char_classes[i];
+ if (__iswctype (wc, wt))
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+# ifdef _LIBC
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ unsigned int in_collseq = 0;
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra;
+ const char *collseqwc;
+ int32_t idx;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+
+ /* match with collating_symbol? */
+ if (cset->ncoll_syms)
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ for (i = 0; i < cset->ncoll_syms; ++i)
+ {
+ const unsigned char *coll_sym = extra + cset->coll_syms[i];
+ /* Compare the length of input collating element and
+ the length of current collating element. */
+ if (*coll_sym != elem_len)
+ continue;
+ /* Compare each bytes. */
+ for (j = 0; j < *coll_sym; j++)
+ if (pin[j] != coll_sym[1 + j])
+ break;
+ if (j == *coll_sym)
+ {
+ /* Match if every bytes is equal. */
+ match_len = j;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+ if (cset->nranges)
+ {
+ if (elem_len <= char_len)
+ {
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ in_collseq = __collseq_table_lookup (collseqwc, wc);
+ }
+ else
+ in_collseq = find_collation_sequence_value (pin, elem_len);
+ }
+ /* match with range expression? */
+ for (i = 0; i < cset->nranges; ++i)
+ if (cset->range_starts[i] <= in_collseq
+ && in_collseq <= cset->range_ends[i])
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+
+ /* match with equivalence_class? */
+ if (cset->nequiv_classes)
+ {
+ const unsigned char *cp = pin;
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+ idx = findidx (&cp);
+ if (idx > 0)
+ for (i = 0; i < cset->nequiv_classes; ++i)
+ {
+ int32_t equiv_class_idx = cset->equiv_classes[i];
+ size_t weight_len = weights[idx];
+ if (weight_len == weights[equiv_class_idx])
+ {
+ Idx cnt = 0;
+ while (cnt <= weight_len
+ && (weights[equiv_class_idx + 1 + cnt]
+ == weights[idx + 1 + cnt]))
+ ++cnt;
+ if (cnt > weight_len)
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ }
+ }
+ else
+# endif /* _LIBC */
+ {
+ /* match with range expression? */
+#if __GNUC__ >= 2
+ wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
+#else
+ wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+ cmp_buf[2] = wc;
+#endif
+ for (i = 0; i < cset->nranges; ++i)
+ {
+ cmp_buf[0] = cset->range_starts[i];
+ cmp_buf[4] = cset->range_ends[i];
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+ return match_len;
+ else
+ {
+ if (match_len > 0)
+ return 0;
+ else
+ return (elem_len > char_len) ? elem_len : char_len;
+ }
+ }
+ return 0;
+}
+
+# ifdef _LIBC
+static unsigned int
+find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
+{
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules == 0)
+ {
+ if (mbs_len == 1)
+ {
+ /* No valid character. Match it as a single byte character. */
+ const unsigned char *collseq = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ return collseq[mbs[0]];
+ }
+ return UINT_MAX;
+ }
+ else
+ {
+ int32_t idx;
+ const unsigned char *extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ int32_t extrasize = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
+
+ for (idx = 0; idx < extrasize;)
+ {
+ int mbs_cnt;
+ bool found = false;
+ int32_t elem_mbs_len;
+ /* Skip the name of collating element name. */
+ idx = idx + extra[idx] + 1;
+ elem_mbs_len = extra[idx++];
+ if (mbs_len == elem_mbs_len)
+ {
+ for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
+ if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
+ break;
+ if (mbs_cnt == elem_mbs_len)
+ /* Found the entry. */
+ found = true;
+ }
+ /* Skip the byte sequence of the collating element. */
+ idx += elem_mbs_len;
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ /* Skip the wide char sequence of the collating element. */
+ idx = idx + sizeof (uint32_t) * (extra[idx] + 1);
+ /* If we found the entry, return the sequence value. */
+ if (found)
+ return *(uint32_t *) (extra + idx);
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ }
+ return UINT_MAX;
+ }
+}
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+
+/* Check whether the node accepts the byte which is IDX-th
+ byte of the INPUT. */
+
+static bool
+internal_function
+check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
+ Idx idx)
+{
+ unsigned char ch;
+ ch = re_string_byte_at (&mctx->input, idx);
+ switch (node->type)
+ {
+ case CHARACTER:
+ if (node->opr.c != ch)
+ return false;
+ break;
+
+ case SIMPLE_BRACKET:
+ if (!bitset_contain (node->opr.sbcset, ch))
+ return false;
+ break;
+
+#ifdef RE_ENABLE_I18N
+ case OP_UTF8_PERIOD:
+ if (ch >= 0x80)
+ return false;
+ /* FALLTHROUGH */
+#endif
+ case OP_PERIOD:
+ if ((ch == '\n' && !(mctx->dfa->syntax & REG_DOT_NEWLINE))
+ || (ch == '\0' && (mctx->dfa->syntax & REG_DOT_NOT_NULL)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ if (node->constraint)
+ {
+ /* The node has constraints. Check whether the current context
+ satisfies the constraints. */
+ unsigned int context = re_string_context_at (&mctx->input, idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ return false;
+ }
+
+ return true;
+}
+
+/* Extend the buffers, if the buffers have run out. */
+
+static reg_errcode_t
+internal_function
+extend_buffers (re_match_context_t *mctx)
+{
+ reg_errcode_t ret;
+ re_string_t *pstr = &mctx->input;
+
+ /* Double the lengthes of the buffers. */
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ if (mctx->state_log != NULL)
+ {
+ /* And double the length of state_log. */
+ /* XXX We have no indication of the size of this buffer. If this
+ allocation fail we have no indication that the state_log array
+ does not have the right size. */
+ re_dfastate_t **new_array = re_xrealloc (mctx->state_log, re_dfastate_t *,
+ pstr->bufs_len + 1);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->state_log = new_array;
+ }
+
+ /* Then reconstruct the buffers. */
+ if (pstr->icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ }
+ return REG_NOERROR;
+}
+
+
+/* Functions for matching context. */
+
+/* Initialize MCTX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_init (re_match_context_t *mctx, int eflags, Idx n)
+{
+ mctx->eflags = eflags;
+ mctx->match_last = REG_MISSING;
+ if (n > 0)
+ {
+ mctx->bkref_ents = re_xmalloc (struct re_backref_cache_entry, n);
+ mctx->sub_tops = re_xmalloc (re_sub_match_top_t *, n);
+ if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
+ return REG_ESPACE;
+ }
+ /* Already zero-ed by the caller.
+ else
+ mctx->bkref_ents = NULL;
+ mctx->nbkref_ents = 0;
+ mctx->nsub_tops = 0; */
+ mctx->abkref_ents = n;
+ mctx->max_mb_elem_len = 1;
+ mctx->asub_tops = n;
+ return REG_NOERROR;
+}
+
+/* Clean the entries which depend on the current input in MCTX.
+ This function must be invoked when the matcher changes the start index
+ of the input, or changes the input string. */
+
+static void
+internal_function
+match_ctx_clean (re_match_context_t *mctx)
+{
+ Idx st_idx;
+ for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
+ {
+ Idx sl_idx;
+ re_sub_match_top_t *top = mctx->sub_tops[st_idx];
+ for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
+ {
+ re_sub_match_last_t *last = top->lasts[sl_idx];
+ re_free (last->path.array);
+ re_free (last);
+ }
+ re_free (top->lasts);
+ if (top->path)
+ {
+ re_free (top->path->array);
+ re_free (top->path);
+ }
+ free (top);
+ }
+
+ mctx->nsub_tops = 0;
+ mctx->nbkref_ents = 0;
+}
+
+/* Free all the memory associated with MCTX. */
+
+static void
+internal_function
+match_ctx_free (re_match_context_t *mctx)
+{
+ /* First, free all the memory associated with MCTX->SUB_TOPS. */
+ match_ctx_clean (mctx);
+ re_free (mctx->sub_tops);
+ re_free (mctx->bkref_ents);
+}
+
+/* Add a new backreference entry to MCTX.
+ Note that we assume that caller never call this function with duplicate
+ entry, and call with STR_IDX which isn't smaller than any existing entry.
+*/
+
+static reg_errcode_t
+internal_function
+match_ctx_add_entry (re_match_context_t *mctx, Idx node, Idx str_idx,
+ Idx from, Idx to)
+{
+ if (mctx->nbkref_ents >= mctx->abkref_ents)
+ {
+ struct re_backref_cache_entry* new_entry;
+ new_entry = re_x2realloc (mctx->bkref_ents, struct re_backref_cache_entry,
+ &mctx->abkref_ents);
+ if (BE (new_entry == NULL, 0))
+ {
+ re_free (mctx->bkref_ents);
+ return REG_ESPACE;
+ }
+ mctx->bkref_ents = new_entry;
+ memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
+ (sizeof (struct re_backref_cache_entry)
+ * (mctx->abkref_ents - mctx->nbkref_ents)));
+ }
+ if (mctx->nbkref_ents > 0
+ && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
+ mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
+
+ mctx->bkref_ents[mctx->nbkref_ents].node = node;
+ mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
+
+ /* This is a cache that saves negative results of check_dst_limits_calc_pos.
+ If bit N is clear, means that this entry won't epsilon-transition to
+ an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
+ it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
+ such node.
+
+ A backreference does not epsilon-transition unless it is empty, so set
+ to all zeros if FROM != TO. */
+ mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
+ = (from == to ? -1 : 0);
+
+ mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
+ if (mctx->max_mb_elem_len < to - from)
+ mctx->max_mb_elem_len = to - from;
+ return REG_NOERROR;
+}
+
+/* Return the first entry with the same str_idx, or REG_MISSING if none is
+ found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
+
+static Idx
+internal_function
+search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx)
+{
+ Idx left, right, mid, last;
+ last = right = mctx->nbkref_ents;
+ for (left = 0; left < right;)
+ {
+ mid = (left + right) / 2;
+ if (mctx->bkref_ents[mid].str_idx < str_idx)
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
+ return left;
+ else
+ return REG_MISSING;
+}
+
+/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
+ at STR_IDX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_add_subtop (re_match_context_t *mctx, Idx node, Idx str_idx)
+{
+#ifdef DEBUG
+ assert (mctx->sub_tops != NULL);
+ assert (mctx->asub_tops > 0);
+#endif
+ if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
+ {
+ Idx new_asub_tops = mctx->asub_tops;
+ re_sub_match_top_t **new_array = re_x2realloc (mctx->sub_tops,
+ re_sub_match_top_t *,
+ &new_asub_tops);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops = new_array;
+ mctx->asub_tops = new_asub_tops;
+ }
+ mctx->sub_tops[mctx->nsub_tops] = re_calloc (re_sub_match_top_t, 1);
+ if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops[mctx->nsub_tops]->node = node;
+ mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
+ return REG_NOERROR;
+}
+
+/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
+ at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
+
+static re_sub_match_last_t *
+internal_function
+match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx)
+{
+ re_sub_match_last_t *new_entry;
+ if (BE (subtop->nlasts == subtop->alasts, 0))
+ {
+ Idx new_alasts = subtop->alasts;
+ re_sub_match_last_t **new_array = re_x2realloc (subtop->lasts,
+ re_sub_match_last_t *,
+ &new_alasts);
+ if (BE (new_array == NULL, 0))
+ return NULL;
+ subtop->lasts = new_array;
+ subtop->alasts = new_alasts;
+ }
+ new_entry = re_calloc (re_sub_match_last_t, 1);
+ if (BE (new_entry != NULL, 1))
+ {
+ subtop->lasts[subtop->nlasts] = new_entry;
+ new_entry->node = node;
+ new_entry->str_idx = str_idx;
+ ++subtop->nlasts;
+ }
+ return new_entry;
+}
+
+static void
+internal_function
+sift_ctx_init (re_sift_context_t *sctx,
+ re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts,
+ Idx last_node, Idx last_str_idx)
+{
+ sctx->sifted_states = sifted_sts;
+ sctx->limited_states = limited_sts;
+ sctx->last_node = last_node;
+ sctx->last_str_idx = last_str_idx;
+ re_node_set_init_empty (&sctx->limits);
+}
diff --git a/lib/rename.c b/lib/rename.c
new file mode 100644
index 0000000..9c9e7f4
--- /dev/null
+++ b/lib/rename.c
@@ -0,0 +1,58 @@
+/* Work around the bug in some systems whereby rename fails when the source
+ file has a trailing slash. The rename functions of SunOS 4.1.1_U1 and
+ mips-dec-ultrix4.4 have this bug.
+ Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Volker Borchert */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#undef rename
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dirname.h"
+#include "xalloc.h"
+
+/* Rename the file SRC to DST, removing any trailing
+ slashes from SRC. Needed for SunOS 4.1.1_U1. */
+
+int
+rpl_rename (char const *src, char const *dst)
+{
+ char *src_temp;
+ int ret_val;
+ size_t s_len = strlen (src);
+
+ if (s_len && src[s_len - 1] == '/')
+ {
+ src_temp = xstrdup (src);
+ strip_trailing_slashes (src_temp);
+ }
+ else
+ src_temp = (char *) src;
+
+ ret_val = rename (src_temp, dst);
+
+ if (src_temp != src)
+ free (src_temp);
+
+ return ret_val;
+}
diff --git a/lib/rpmatch.c b/lib/rpmatch.c
new file mode 100644
index 0000000..ba8bc4c
--- /dev/null
+++ b/lib/rpmatch.c
@@ -0,0 +1,79 @@
+/* Determine whether string value is affirmation or negative response
+ according to current locale's data.
+ Copyright (C) 1996, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#if ENABLE_NLS
+# include <sys/types.h>
+# include <limits.h>
+# include <regex.h>
+# include "gettext.h"
+# define _(msgid) gettext (msgid)
+
+static int
+try (const char *response, const char *pattern, const int match,
+ const int nomatch, const char **lastp, regex_t *re)
+{
+ if (pattern != *lastp)
+ {
+ /* The pattern has changed. */
+ if (*lastp)
+ {
+ /* Free the old compiled pattern. */
+ regfree (re);
+ *lastp = NULL;
+ }
+ /* Compile the pattern and cache it for future runs. */
+ if (regcomp (re, pattern, REG_EXTENDED) != 0)
+ return -1;
+ *lastp = pattern;
+ }
+
+ /* See if the regular expression matches RESPONSE. */
+ return regexec (re, response, 0, NULL, 0) == 0 ? match : nomatch;
+}
+#endif
+
+
+int
+rpmatch (const char *response)
+{
+#if ENABLE_NLS
+ /* Match against one of the response patterns, compiling the pattern
+ first if necessary. */
+
+ /* We cache the response patterns and compiled regexps here. */
+ static const char *yesexpr, *noexpr;
+ static regex_t yesre, nore;
+ int result;
+
+ return ((result = try (response, _("^[yY]"), 1, 0,
+ &yesexpr, &yesre))
+ ? result
+ : try (response, _("^[nN]"), 0, -1, &noexpr, &nore));
+#else
+ /* Test against "^[yY]" and "^[nN]", hardcoded to avoid requiring regex */
+ return (*response == 'y' || *response == 'Y' ? 1
+ : *response == 'n' || *response == 'N' ? 0 : -1);
+#endif
+}
diff --git a/lib/save-cwd.c b/lib/save-cwd.c
new file mode 100644
index 0000000..7f1b30b
--- /dev/null
+++ b/lib/save-cwd.c
@@ -0,0 +1,115 @@
+/* save-cwd.c -- Save and restore current working directory.
+
+ Copyright (C) 1995, 1997, 1998, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "save-cwd.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+#include <errno.h>
+
+#include "chdir-long.h"
+#include "unistd-safer.h"
+#include "xgetcwd.h"
+
+/* On systems without the fchdir function (WOE), pretend that open
+ always returns -1 so that save_cwd resorts to using xgetcwd.
+ Since chdir_long requires fchdir, use chdir instead. */
+#if !HAVE_FCHDIR
+# undef open
+# define open(File, Flags) (-1)
+# undef fchdir
+# define fchdir(Fd) (abort (), -1)
+# undef chdir_long
+# define chdir_long(Dir) chdir (Dir)
+#endif
+
+/* Record the location of the current working directory in CWD so that
+ the program may change to other directories and later use restore_cwd
+ to return to the recorded location. This function may allocate
+ space using malloc (via xgetcwd) or leave a file descriptor open;
+ use free_cwd to perform the necessary free or close. Upon failure,
+ no memory is allocated, any locally opened file descriptors are
+ closed; return non-zero -- in that case, free_cwd need not be
+ called, but doing so is ok. Otherwise, return zero.
+
+ The `raison d'etre' for this interface is that the working directory
+ is sometimes inaccessible, and getcwd is not robust or as efficient.
+ So, we prefer to use the open/fchdir approach, but fall back on
+ getcwd if necessary.
+
+ Some systems lack fchdir altogether: e.g., OS/2, pre-2001 Cygwin,
+ SCO Xenix. Also, SunOS 4 and Irix 5.3 provide the function, yet it
+ doesn't work for partitions on which auditing is enabled. If
+ you're still using an obsolete system with these problems, please
+ send email to the maintainer of this code. */
+
+int
+save_cwd (struct saved_cwd *cwd)
+{
+ cwd->name = NULL;
+
+ cwd->desc = fd_safer (open (".", O_RDONLY));
+ if (cwd->desc < 0)
+ {
+ cwd->desc = fd_safer (open (".", O_WRONLY));
+ if (cwd->desc < 0)
+ {
+ cwd->name = xgetcwd ();
+ return cwd->name ? 0 : -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Change to recorded location, CWD, in directory hierarchy.
+ Upon failure, return -1 (errno is set by chdir or fchdir).
+ Upon success, return zero. */
+
+int
+restore_cwd (const struct saved_cwd *cwd)
+{
+ if (0 <= cwd->desc)
+ return fchdir (cwd->desc);
+ else
+ return chdir_long (cwd->name);
+}
+
+void
+free_cwd (struct saved_cwd *cwd)
+{
+ if (cwd->desc >= 0)
+ close (cwd->desc);
+ if (cwd->name)
+ free (cwd->name);
+}
diff --git a/lib/save-cwd.h b/lib/save-cwd.h
new file mode 100644
index 0000000..d646b55
--- /dev/null
+++ b/lib/save-cwd.h
@@ -0,0 +1,34 @@
+/* Save and restore current working directory.
+
+ Copyright (C) 1995, 1997, 1998, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#ifndef SAVE_CWD_H
+# define SAVE_CWD_H 1
+
+struct saved_cwd
+ {
+ int desc;
+ char *name;
+ };
+
+int save_cwd (struct saved_cwd *cwd);
+int restore_cwd (const struct saved_cwd *cwd);
+void free_cwd (struct saved_cwd *cwd);
+
+#endif /* SAVE_CWD_H */
diff --git a/lib/setenv.c b/lib/setenv.c
new file mode 100644
index 0000000..33dbeb7
--- /dev/null
+++ b/lib/setenv.c
@@ -0,0 +1,328 @@
+/* Copyright (C) 1992,1995-1999,2000-2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <alloca.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(ev) ((errno) = (ev))
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#if _LIBC || HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !_LIBC
+# include "allocsa.h"
+#endif
+
+#if !_LIBC
+# define __environ environ
+# ifndef HAVE_ENVIRON_DECL
+extern char **environ;
+# endif
+#endif
+
+#if _LIBC
+/* This lock protects against simultaneous modifications of `environ'. */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK __libc_lock_lock (envlock)
+# define UNLOCK __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+/* In the GNU C library we must keep the namespace clean. */
+#ifdef _LIBC
+# define setenv __setenv
+# define clearenv __clearenv
+# define tfind __tfind
+# define tsearch __tsearch
+#endif
+
+/* In the GNU C library implementation we try to be more clever and
+ allow arbitrarily many changes of the environment given that the used
+ values are from a small set. Outside glibc this will eat up all
+ memory after a while. */
+#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
+ && defined __GNUC__)
+# define USE_TSEARCH 1
+# include <search.h>
+typedef int (*compar_fn_t) (const void *, const void *);
+
+/* This is a pointer to the root of the search tree with the known
+ values. */
+static void *known_values;
+
+# define KNOWN_VALUE(Str) \
+ ({ \
+ void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
+ value != NULL ? *(char **) value : NULL; \
+ })
+# define STORE_VALUE(Str) \
+ tsearch (Str, &known_values, (compar_fn_t) strcmp)
+
+#else
+# undef USE_TSEARCH
+
+# define KNOWN_VALUE(Str) NULL
+# define STORE_VALUE(Str) do { } while (0)
+
+#endif
+
+
+/* If this variable is not a null pointer we allocated the current
+ environment. */
+static char **last_environ;
+
+
+/* This function is used by `setenv' and `putenv'. The difference between
+ the two functions is that for the former must create a new string which
+ is then placed in the environment, while the argument of `putenv'
+ must be used directly. This is all complicated by the fact that we try
+ to reuse values once generated for a `setenv' call since we can never
+ free the strings. */
+int
+__add_to_environ (const char *name, const char *value, const char *combined,
+ int replace)
+{
+ register char **ep;
+ register size_t size;
+ const size_t namelen = strlen (name);
+ const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
+
+ LOCK;
+
+ /* We have to get the pointer now that we have the lock and not earlier
+ since another thread might have created a new environment. */
+ ep = __environ;
+
+ size = 0;
+ if (ep != NULL)
+ {
+ for (; *ep != NULL; ++ep)
+ if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
+ break;
+ else
+ ++size;
+ }
+
+ if (ep == NULL || *ep == NULL)
+ {
+ char **new_environ;
+#ifdef USE_TSEARCH
+ char *new_value;
+#endif
+
+ /* We allocated this space; we can extend it. */
+ new_environ =
+ (char **) (last_environ == NULL
+ ? malloc ((size + 2) * sizeof (char *))
+ : realloc (last_environ, (size + 2) * sizeof (char *)));
+ if (new_environ == NULL)
+ {
+ UNLOCK;
+ return -1;
+ }
+
+ /* If the whole entry is given add it. */
+ if (combined != NULL)
+ /* We must not add the string to the search tree since it belongs
+ to the user. */
+ new_environ[size] = (char *) combined;
+ else
+ {
+ /* See whether the value is already known. */
+#ifdef USE_TSEARCH
+# ifdef _LIBC
+ new_value = (char *) alloca (namelen + 1 + vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
+# else
+ new_value = (char *) allocsa (namelen + 1 + vallen);
+ if (new_value == NULL)
+ {
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
+# endif
+
+ new_environ[size] = KNOWN_VALUE (new_value);
+ if (new_environ[size] == NULL)
+#endif
+ {
+ new_environ[size] = (char *) malloc (namelen + 1 + vallen);
+ if (new_environ[size] == NULL)
+ {
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+
+#ifdef USE_TSEARCH
+ memcpy (new_environ[size], new_value, namelen + 1 + vallen);
+#else
+ memcpy (new_environ[size], name, namelen);
+ new_environ[size][namelen] = '=';
+ memcpy (&new_environ[size][namelen + 1], value, vallen);
+#endif
+ /* And save the value now. We cannot do this when we remove
+ the string since then we cannot decide whether it is a
+ user string or not. */
+ STORE_VALUE (new_environ[size]);
+ }
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ }
+
+ if (__environ != last_environ)
+ memcpy ((char *) new_environ, (char *) __environ,
+ size * sizeof (char *));
+
+ new_environ[size + 1] = NULL;
+
+ last_environ = __environ = new_environ;
+ }
+ else if (replace)
+ {
+ char *np;
+
+ /* Use the user string if given. */
+ if (combined != NULL)
+ np = (char *) combined;
+ else
+ {
+#ifdef USE_TSEARCH
+ char *new_value;
+# ifdef _LIBC
+ new_value = alloca (namelen + 1 + vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
+# else
+ new_value = allocsa (namelen + 1 + vallen);
+ if (new_value == NULL)
+ {
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
+# endif
+
+ np = KNOWN_VALUE (new_value);
+ if (np == NULL)
+#endif
+ {
+ np = malloc (namelen + 1 + vallen);
+ if (np == NULL)
+ {
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+
+#ifdef USE_TSEARCH
+ memcpy (np, new_value, namelen + 1 + vallen);
+#else
+ memcpy (np, name, namelen);
+ np[namelen] = '=';
+ memcpy (&np[namelen + 1], value, vallen);
+#endif
+ /* And remember the value. */
+ STORE_VALUE (np);
+ }
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ }
+
+ *ep = np;
+ }
+
+ UNLOCK;
+
+ return 0;
+}
+
+int
+setenv (const char *name, const char *value, int replace)
+{
+ return __add_to_environ (name, value, NULL, replace);
+}
+
+/* The `clearenv' was planned to be added to POSIX.1 but probably
+ never made it. Nevertheless the POSIX.9 standard (POSIX bindings
+ for Fortran 77) requires this function. */
+int
+clearenv (void)
+{
+ LOCK;
+
+ if (__environ == last_environ && __environ != NULL)
+ {
+ /* We allocated this environment so we can free it. */
+ free (__environ);
+ last_environ = NULL;
+ }
+
+ /* Clear the environment pointer removes the whole environment. */
+ __environ = NULL;
+
+ UNLOCK;
+
+ return 0;
+}
+
+#ifdef _LIBC
+static void
+free_mem (void)
+{
+ /* Remove all traces. */
+ clearenv ();
+
+ /* Now remove the search tree. */
+ __tdestroy (known_values, free);
+ known_values = NULL;
+}
+text_set_element (__libc_subfreeres, free_mem);
+
+
+# undef setenv
+# undef clearenv
+weak_alias (__setenv, setenv)
+weak_alias (__clearenv, clearenv)
+#endif
diff --git a/lib/setenv.h b/lib/setenv.h
new file mode 100644
index 0000000..c89e7da
--- /dev/null
+++ b/lib/setenv.h
@@ -0,0 +1,54 @@
+/* Setting environment variables.
+ Copyright (C) 2001-2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#if HAVE_SETENV || HAVE_UNSETENV
+
+/* Get setenv(), unsetenv() declarations. */
+# include <stdlib.h>
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !HAVE_SETENV
+
+/* Set NAME to VALUE in the environment.
+ If REPLACE is nonzero, overwrite an existing value. */
+extern int setenv (const char *name, const char *value, int replace);
+
+#endif
+
+#if HAVE_UNSETENV
+
+# if VOID_UNSETENV
+/* On some systems, unsetenv() returns void.
+ This is the case for FreeBSD 4.8, NetBSD 1.6, OpenBSD 3.4. */
+# define unsetenv(name) ((unsetenv)(name), 0)
+# endif
+
+#else
+
+/* Remove the variable NAME from the environment. */
+extern int unsetenv (const char *name);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib/sighandle.c b/lib/sighandle.c
new file mode 100644
index 0000000..7934461
--- /dev/null
+++ b/lib/sighandle.c
@@ -0,0 +1,416 @@
+/* sighandle.c -- Library routines for manipulating chains of signal handlers
+ Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* Written by Paul Sander, HaL Computer Systems, Inc. <paul@hal.com>
+ Brian Berliner <berliner@Sun.COM> added POSIX support */
+
+/*************************************************************************
+ *
+ * signal.c -- This file contains code that manipulates chains of signal
+ * handlers.
+ *
+ * Facilities are provided to register a signal handler for
+ * any specific signal. When a signal is received, all of the
+ * registered signal handlers are invoked in the reverse order
+ * in which they are registered. Note that the signal handlers
+ * must not themselves make calls to the signal handling
+ * facilities.
+ *
+ *************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "system.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+#if __STDC__
+char *calloc(unsigned nelem, unsigned size);
+char *malloc(unsigned size);
+#else
+char *calloc();
+char *malloc();
+#endif /* __STDC__ */
+#endif /* STDC_HEADERS */
+
+/* Define the highest signal number (usually) */
+#ifndef SIGMAX
+#define SIGMAX 64
+#endif
+
+/* Define linked list of signal handlers structure */
+struct SIG_hlist {
+ RETSIGTYPE (*handler)();
+ struct SIG_hlist *next;
+};
+
+/*
+ * Define array of lists of signal handlers. Note that this depends on
+ * the implementation to initialize each element to a null pointer.
+ */
+
+static struct SIG_hlist **SIG_handlers;
+
+/* Define array of default signal vectors */
+
+#ifdef POSIX_SIGNALS
+static struct sigaction *SIG_defaults;
+#else
+#ifdef BSD_SIGNALS
+static struct sigvec *SIG_defaults;
+#else
+static RETSIGTYPE (**SIG_defaults) (int);
+#endif
+#endif
+
+/* Critical section housekeeping */
+static int SIG_crSectNest = 0; /* Nesting level */
+#ifdef POSIX_SIGNALS
+static sigset_t SIG_crSectMask; /* Signal mask */
+#else
+static int SIG_crSectMask; /* Signal mask */
+#endif
+
+/*
+ * Initialize the signal handler arrays
+ */
+
+static int SIG_init()
+{
+ int i;
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_test;
+#endif
+
+ if (SIG_defaults && SIG_handlers) /* already allocated */
+ return (0);
+
+#ifdef POSIX_SIGNALS
+ (void) sigfillset(&sigset_test);
+ for (i = 1; i < SIGMAX && sigismember(&sigset_test, i) == 1; i++)
+ ;
+ if (i < SIGMAX)
+ i = SIGMAX;
+ i++;
+ if (!SIG_defaults)
+ SIG_defaults = (struct sigaction *)
+ calloc(i, sizeof(struct sigaction));
+ (void) sigemptyset(&SIG_crSectMask);
+#else
+ i = SIGMAX+1;
+#ifdef BSD_SIGNALS
+ if (!SIG_defaults)
+ SIG_defaults = (struct sigvec *)
+ calloc(i, sizeof(struct sigvec));
+#else
+ if (!SIG_defaults)
+ SIG_defaults = ( RETSIGTYPE (**) (int) )
+ calloc( i, sizeof( RETSIGTYPE (**) (int) ) );
+#endif
+ SIG_crSectMask = 0;
+#endif
+ if (!SIG_handlers)
+ SIG_handlers = (struct SIG_hlist **)
+ calloc(i, sizeof(struct SIG_hlist *));
+ return (!SIG_defaults || !SIG_handlers);
+}
+
+
+
+/*
+ * The following begins a critical section.
+ */
+void SIG_beginCrSect (void)
+{
+ if (SIG_init() == 0)
+ {
+ if (SIG_crSectNest == 0)
+ {
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_mask;
+
+ (void) sigfillset(&sigset_mask);
+ (void) sigprocmask(SIG_SETMASK,
+ &sigset_mask, &SIG_crSectMask);
+#else
+#ifdef BSD_SIGNALS
+ SIG_crSectMask = sigblock(~0);
+#else
+ /* TBD */
+#endif
+#endif
+ }
+ SIG_crSectNest++;
+ }
+}
+
+
+
+/*
+ * The following ends a critical section.
+ */
+void SIG_endCrSect (void)
+{
+ if (SIG_init() == 0)
+ {
+ SIG_crSectNest--;
+ if (SIG_crSectNest == 0)
+ {
+#ifdef POSIX_SIGNALS
+ (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL);
+#else
+#ifdef BSD_SIGNALS
+ (void) sigsetmask(SIG_crSectMask);
+#else
+ /* TBD */
+#endif
+#endif
+ }
+ }
+}
+
+
+
+/*
+ * The following invokes each signal handler in the reverse order in which
+ * they were registered.
+ */
+static RETSIGTYPE SIG_handle (int sig)
+{
+ struct SIG_hlist *this;
+
+ /* Dispatch signal handlers */
+ /* This crit section stuff is a CVSism - we know that our interrupt
+ * handlers will always end up exiting and we don't want them to be
+ * interrupted themselves.
+ */
+ SIG_beginCrSect();
+ this = SIG_handlers[sig];
+ while (this != (struct SIG_hlist *) NULL)
+ {
+ (*this->handler)(sig);
+ this = this->next;
+ }
+ SIG_endCrSect();
+
+ return;
+}
+
+/*
+ * The following registers a signal handler. If the handler is already
+ * registered, it is not registered twice, nor is the order in which signal
+ * handlers are invoked changed. If this is the first signal handler
+ * registered for a given signal, the old sigvec structure is saved for
+ * restoration later.
+ */
+
+int SIG_register(int sig, RETSIGTYPE (*fn)())
+{
+ int val;
+ struct SIG_hlist *this;
+#ifdef POSIX_SIGNALS
+ struct sigaction act;
+ sigset_t sigset_mask, sigset_omask;
+#else
+#ifdef BSD_SIGNALS
+ struct sigvec vec;
+ int mask;
+#endif
+#endif
+
+ /* Initialize */
+ if (SIG_init() != 0)
+ return (-1);
+ val = 0;
+
+ /* Block this signal while we look at handler chain */
+#ifdef POSIX_SIGNALS
+ (void) sigemptyset(&sigset_mask);
+ (void) sigaddset(&sigset_mask, sig);
+ (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
+#else
+#ifdef BSD_SIGNALS
+ mask = sigblock(sigmask(sig));
+#endif
+#endif
+
+ /* See if this handler was already registered */
+ this = SIG_handlers[sig];
+ while (this != (struct SIG_hlist *) NULL)
+ {
+ if (this->handler == fn) break;
+ this = this->next;
+ }
+
+ /* Register the new handler only if it is not already registered. */
+ if (this == (struct SIG_hlist *) NULL)
+ {
+
+ /*
+ * If this is the first handler registered for this signal,
+ * set up the signal handler dispatcher
+ */
+
+ if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
+ {
+#ifdef POSIX_SIGNALS
+ act.sa_handler = SIG_handle;
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ val = sigaction(sig, &act, &SIG_defaults[sig]);
+#else
+#ifdef BSD_SIGNALS
+ memset (&vec, 0, sizeof (vec));
+ vec.sv_handler = SIG_handle;
+ val = sigvec(sig, &vec, &SIG_defaults[sig]);
+#else
+ if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == SIG_ERR)
+ val = -1;
+#endif
+#endif
+ }
+
+ /* If not, register it */
+ if ((val == 0) && (this == (struct SIG_hlist *) NULL))
+ {
+ this = (struct SIG_hlist *)
+ malloc(sizeof(struct SIG_hlist));
+ if (this == NULL)
+ {
+ val = -1;
+ }
+ else
+ {
+ this->handler = fn;
+ this->next = SIG_handlers[sig];
+ SIG_handlers[sig] = this;
+ }
+ }
+ }
+
+ /* Unblock the signal */
+#ifdef POSIX_SIGNALS
+ (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
+#else
+#ifdef BSD_SIGNALS
+ (void) sigsetmask(mask);
+#endif
+#endif
+
+ return val;
+}
+
+
+
+/*
+ * The following deregisters a signal handler. If the last signal handler for
+ * a given signal is deregistered, the default sigvec information is restored.
+ */
+
+int SIG_deregister(int sig, RETSIGTYPE (*fn)())
+{
+ int val;
+ struct SIG_hlist *this;
+ struct SIG_hlist *last;
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_mask, sigset_omask;
+#else
+#ifdef BSD_SIGNALS
+ int mask;
+#endif
+#endif
+
+ /* Initialize */
+ if (SIG_init() != 0)
+ return (-1);
+ val = 0;
+ last = (struct SIG_hlist *) NULL;
+
+ /* Block this signal while we look at handler chain */
+#ifdef POSIX_SIGNALS
+ (void) sigemptyset(&sigset_mask);
+ (void) sigaddset(&sigset_mask, sig);
+ (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
+#else
+#ifdef BSD_SIGNALS
+ mask = sigblock(sigmask(sig));
+#endif
+#endif
+
+ /* Search for the signal handler */
+ this = SIG_handlers[sig];
+ while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn))
+ {
+ last = this;
+ this = this->next;
+ }
+
+ /* If it was registered, remove it */
+ if (this != (struct SIG_hlist *) NULL)
+ {
+ if (last == (struct SIG_hlist *) NULL)
+ {
+ SIG_handlers[sig] = this->next;
+ }
+ else
+ {
+ last->next = this->next;
+ }
+ free((char *) this);
+ }
+
+ /* Restore default behavior if there are no registered handlers */
+ if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
+ {
+#ifdef POSIX_SIGNALS
+ val = sigaction(sig, &SIG_defaults[sig],
+ (struct sigaction *) NULL);
+#else
+#ifdef BSD_SIGNALS
+ val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL);
+#else
+ if (signal(sig, SIG_defaults[sig]) == SIG_ERR)
+ val = -1;
+#endif
+#endif
+ }
+
+ /* Unblock the signal */
+#ifdef POSIX_SIGNALS
+ (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
+#else
+#ifdef BSD_SIGNALS
+ (void) sigsetmask(mask);
+#endif
+#endif
+
+ return val;
+}
+
+
+
+/*
+ * Return nonzero if currently in a critical section.
+ * Otherwise return zero.
+ */
+
+int SIG_inCrSect (void)
+{
+ return SIG_crSectNest > 0;
+}
diff --git a/lib/size_max.h b/lib/size_max.h
new file mode 100644
index 0000000..ce2377b
--- /dev/null
+++ b/lib/size_max.h
@@ -0,0 +1,27 @@
+/* size_max.h -- declare SIZE_MAX through system headers
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Written by Simon Josefsson.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef GNULIB_SIZE_MAX_H
+#define GNULIB_SIZE_MAX_H
+
+# include <limits.h>
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+
+#endif /* GNULIB_SIZE_MAX_H */
diff --git a/lib/stat-macros.h b/lib/stat-macros.h
new file mode 100644
index 0000000..0957a22
--- /dev/null
+++ b/lib/stat-macros.h
@@ -0,0 +1,255 @@
+/* stat-related macros
+
+ Copyright (C) 1993, 1994, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert and Jim Meyering. */
+
+#ifndef STAT_MACROS_H
+# define STAT_MACROS_H 1
+
+# if ! defined S_ISREG && ! defined S_IFREG
+# error "you must include <sys/stat.h> before including this file"
+# endif
+
+# ifndef S_IFMT
+# define S_IFMT 0170000
+# endif
+
+# if STAT_MACROS_BROKEN
+# undef S_ISBLK
+# undef S_ISCHR
+# undef S_ISDIR
+# undef S_ISDOOR
+# undef S_ISFIFO
+# undef S_ISLNK
+# undef S_ISNAM
+# undef S_ISMPB
+# undef S_ISMPC
+# undef S_ISNWK
+# undef S_ISREG
+# undef S_ISSOCK
+# endif
+
+
+# ifndef S_ISBLK
+# ifdef S_IFBLK
+# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) 0
+# endif
+# endif
+
+# ifndef S_ISCHR
+# ifdef S_IFCHR
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(m) 0
+# endif
+# endif
+
+# ifndef S_ISDIR
+# ifdef S_IFDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+# define S_ISDIR(m) 0
+# endif
+# endif
+
+# ifndef S_ISDOOR /* Solaris 2.5 and up */
+# ifdef S_IFDOOR
+# define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR)
+# else
+# define S_ISDOOR(m) 0
+# endif
+# endif
+
+# ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) 0
+# endif
+# endif
+
+# ifndef S_ISLNK
+# ifdef S_IFLNK
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(m) 0
+# endif
+# endif
+
+# ifndef S_ISMPB /* V7 */
+# ifdef S_IFMPB
+# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+# else
+# define S_ISMPB(m) 0
+# define S_ISMPC(m) 0
+# endif
+# endif
+
+# ifndef S_ISNAM /* Xenix */
+# ifdef S_IFNAM
+# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM)
+# else
+# define S_ISNAM(m) 0
+# endif
+# endif
+
+# ifndef S_ISNWK /* HP/UX */
+# ifdef S_IFNWK
+# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+# else
+# define S_ISNWK(m) 0
+# endif
+# endif
+
+# ifndef S_ISREG
+# ifdef S_IFREG
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# else
+# define S_ISREG(m) 0
+# endif
+# endif
+
+# ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) 0
+# endif
+# endif
+
+
+# ifndef S_TYPEISMQ
+# define S_TYPEISMQ(p) 0
+# endif
+
+# ifndef S_TYPEISTMO
+# define S_TYPEISTMO(p) 0
+# endif
+
+
+# ifndef S_TYPEISSEM
+# ifdef S_INSEM
+# define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM)
+# else
+# define S_TYPEISSEM(p) 0
+# endif
+# endif
+
+# ifndef S_TYPEISSHM
+# ifdef S_INSHD
+# define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD)
+# else
+# define S_TYPEISSHM(p) 0
+# endif
+# endif
+
+/* contiguous */
+# ifndef S_ISCTG
+# define S_ISCTG(p) 0
+# endif
+
+/* Cray DMF (data migration facility): off line, with data */
+# ifndef S_ISOFD
+# define S_ISOFD(p) 0
+# endif
+
+/* Cray DMF (data migration facility): off line, with no data */
+# ifndef S_ISOFL
+# define S_ISOFL(p) 0
+# endif
+
+/* If any of the following are undefined,
+ define them to their de facto standard values. */
+# if !S_ISUID
+# define S_ISUID 04000
+# endif
+# if !S_ISGID
+# define S_ISGID 02000
+# endif
+
+/* S_ISVTX is a common extension to POSIX. */
+# ifndef S_ISVTX
+# define S_ISVTX 01000
+# endif
+
+# if !S_IRUSR && S_IREAD
+# define S_IRUSR S_IREAD
+# endif
+# if !S_IRUSR
+# define S_IRUSR 00400
+# endif
+# if !S_IRGRP
+# define S_IRGRP (S_IRUSR >> 3)
+# endif
+# if !S_IROTH
+# define S_IROTH (S_IRUSR >> 6)
+# endif
+
+# if !S_IWUSR && S_IWRITE
+# define S_IWUSR S_IWRITE
+# endif
+# if !S_IWUSR
+# define S_IWUSR 00200
+# endif
+# if !S_IWGRP
+# define S_IWGRP (S_IWUSR >> 3)
+# endif
+# if !S_IWOTH
+# define S_IWOTH (S_IWUSR >> 6)
+# endif
+
+# if !S_IXUSR && S_IEXEC
+# define S_IXUSR S_IEXEC
+# endif
+# if !S_IXUSR
+# define S_IXUSR 00100
+# endif
+# if !S_IXGRP
+# define S_IXGRP (S_IXUSR >> 3)
+# endif
+# if !S_IXOTH
+# define S_IXOTH (S_IXUSR >> 6)
+# endif
+
+# if !S_IRWXU
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+# endif
+# if !S_IRWXG
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+# endif
+# if !S_IRWXO
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+# endif
+
+/* S_IXUGO is a common extension to POSIX. */
+# if !S_IXUGO
+# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
+# endif
+
+# ifndef S_IRWXUGO
+# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
+# endif
+
+/* All the mode bits that can be affected by chmod. */
+# define CHMOD_MODE_BITS \
+ (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+
+#endif /* STAT_MACROS_H */
diff --git a/lib/stdbool_.h b/lib/stdbool_.h
new file mode 100644
index 0000000..3177ae0
--- /dev/null
+++ b/lib/stdbool_.h
@@ -0,0 +1,93 @@
+/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+/* ISO C 99 <stdbool.h> for platforms that lack it. */
+
+/* Usage suggestions:
+
+ Programs that use <stdbool.h> should be aware of some limitations
+ and standards compliance issues.
+
+ Standards compliance:
+
+ - <stdbool.h> must be #included before 'bool', 'false', 'true'
+ can be used.
+
+ - You cannot assume that sizeof (bool) == 1.
+
+ - Programs should not undefine the macros bool, true, and false,
+ as C99 lists that as an "obsolescent feature".
+
+ Limitations of this substitute, when used in a C89 environment:
+
+ - <stdbool.h> must be #included before the '_Bool' type can be used.
+
+ - You cannot assume that _Bool is a typedef; it might be a macro.
+
+ - In C99, casts and automatic conversions to '_Bool' or 'bool' are
+ performed in such a way that every nonzero value gets converted
+ to 'true', and zero gets converted to 'false'. This doesn't work
+ with this substitute. With this substitute, only the values 0 and 1
+ give the expected result when converted to _Bool' or 'bool'.
+
+ Also, it is suggested that programs use 'bool' rather than '_Bool';
+ this isn't required, but 'bool' is more common. */
+
+
+/* 7.16. Boolean type and values */
+
+/* BeOS <sys/socket.h> already #defines false 0, true 1. We use the same
+ definitions below, but temporarily we have to #undef them. */
+#ifdef __BEOS__
+# include <OS.h> /* defines bool but not _Bool */
+# undef false
+# undef true
+#endif
+
+/* For the sake of symbolic names in gdb, we define true and false as
+ enum constants, not only as macros.
+ It is tempting to write
+ typedef enum { false = 0, true = 1 } _Bool;
+ so that gdb prints values of type 'bool' symbolically. But if we do
+ this, values of type '_Bool' may promote to 'int' or 'unsigned int'
+ (see ISO C 99 6.7.2.2.(4)); however, '_Bool' must promote to 'int'
+ (see ISO C 99 6.3.1.1.(2)). So we add a negative value to the
+ enum; this ensures that '_Bool' promotes to 'int'. */
+#if !(defined __cplusplus || defined __BEOS__)
+# if !@HAVE__BOOL@
+# if defined __SUNPRO_C && (__SUNPRO_C < 0x550 || __STDC__ == 1)
+ /* Avoid stupid "warning: _Bool is a keyword in ISO C99". */
+# define _Bool signed char
+enum { false = 0, true = 1 };
+# else
+typedef enum { _Bool_must_promote_to_int = -1, false = 0, true = 1 } _Bool;
+# endif
+# endif
+#else
+typedef bool _Bool;
+#endif
+#define bool _Bool
+
+/* The other macros must be usable in preprocessor directives. */
+#define false 0
+#define true 1
+#define __bool_true_false_are_defined 1
+
+#endif /* _STDBOOL_H */
diff --git a/lib/stdint_.h b/lib/stdint_.h
new file mode 100644
index 0000000..ea3619d
--- /dev/null
+++ b/lib/stdint_.h
@@ -0,0 +1,283 @@
+/* Copyright (C) 2001-2002, 2004-2005 Free Software Foundation, Inc.
+ Written by Bruno Haible, Sam Steingold, Peter Burwood.
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+/*
+ * ISO C 99 <stdint.h> for platforms that lack it.
+ * <http://www.opengroup.org/onlinepubs/007904975/basedefs/stdint.h.html>
+ */
+
+/* Get wchar_t, WCHAR_MIN, WCHAR_MAX. */
+#include <stddef.h>
+/* Get CHAR_BIT, LONG_MIN, LONG_MAX, ULONG_MAX. */
+#include <limits.h>
+
+/* Get those types that are already defined in other system include files. */
+#if defined(__FreeBSD__)
+# include <sys/inttypes.h>
+#endif
+#if defined(__sun) && HAVE_SYS_INTTYPES_H
+# include <sys/inttypes.h>
+ /* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and
+ the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX.
+ But note that <sys/int_types.h> contains only the type definitions! */
+# define _STDINT_H_HAVE_SYSTEM_INTTYPES
+#endif
+#if (defined(__hpux) || defined(_AIX)) && HAVE_INTTYPES_H
+# include <inttypes.h>
+ /* HP-UX 10 <inttypes.h> has nearly everything, except UINT_LEAST8_MAX,
+ UINT_FAST8_MAX, PTRDIFF_MIN, PTRDIFF_MAX. */
+ /* AIX 4 <inttypes.h> has nearly everything, except INTPTR_MIN, INTPTR_MAX,
+ UINTPTR_MAX, PTRDIFF_MIN, PTRDIFF_MAX. */
+# define _STDINT_H_HAVE_SYSTEM_INTTYPES
+#endif
+#if !(defined(UNIX_CYGWIN32) && defined(__BIT_TYPES_DEFINED__))
+# define _STDINT_H_NEED_SIGNED_INT_TYPES
+#endif
+
+#if !defined(_STDINT_H_HAVE_SYSTEM_INTTYPES)
+
+/* 7.18.1.1. Exact-width integer types */
+
+#if !defined(__FreeBSD__)
+
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef signed char int8_t;
+#endif
+typedef unsigned char uint8_t;
+
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef short int16_t;
+#endif
+typedef unsigned short uint16_t;
+
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef int int32_t;
+#endif
+typedef unsigned int uint32_t;
+
+#if @HAVE_LONG_64BIT@
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef long int64_t;
+#endif
+typedef unsigned long uint64_t;
+#define _STDINT_H_HAVE_INT64
+#elif @HAVE_LONG_LONG_64BIT@
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef long long int64_t;
+#endif
+typedef unsigned long long uint64_t;
+#define _STDINT_H_HAVE_INT64
+#elif defined(_MSC_VER)
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#define _STDINT_H_HAVE_INT64
+#endif
+
+#endif /* !FreeBSD */
+
+/* 7.18.1.2. Minimum-width integer types */
+
+typedef int8_t int_least8_t;
+typedef uint8_t uint_least8_t;
+typedef int16_t int_least16_t;
+typedef uint16_t uint_least16_t;
+typedef int32_t int_least32_t;
+typedef uint32_t uint_least32_t;
+#ifdef _STDINT_H_HAVE_INT64
+typedef int64_t int_least64_t;
+typedef uint64_t uint_least64_t;
+#endif
+
+/* 7.18.1.3. Fastest minimum-width integer types */
+
+typedef int32_t int_fast8_t;
+typedef uint32_t uint_fast8_t;
+typedef int32_t int_fast16_t;
+typedef uint32_t uint_fast16_t;
+typedef int32_t int_fast32_t;
+typedef uint32_t uint_fast32_t;
+#ifdef _STDINT_H_HAVE_INT64
+typedef int64_t int_fast64_t;
+typedef uint64_t uint_fast64_t;
+#endif
+
+/* 7.18.1.4. Integer types capable of holding object pointers */
+
+#if !defined(__FreeBSD__)
+
+/* On some platforms (like IRIX6 MIPS with -n32) sizeof(void*) < sizeof(long),
+ but this doesn't matter here. */
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+
+#endif /* !FreeBSD */
+
+/* 7.18.1.5. Greatest-width integer types */
+
+#ifdef _STDINT_H_HAVE_INT64
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+#else
+typedef int32_t intmax_t;
+typedef uint32_t uintmax_t;
+#endif
+
+/* 7.18.2. Limits of specified-width integer types */
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+/* 7.18.2.1. Limits of exact-width integer types */
+
+#define INT8_MIN -128
+#define INT8_MAX 127
+#define UINT8_MAX 255U
+#define INT16_MIN -32768
+#define INT16_MAX 32767
+#define UINT16_MAX 65535U
+#define INT32_MIN (~INT32_MAX)
+#define INT32_MAX 2147483647
+#define UINT32_MAX 4294967295U
+#ifdef _STDINT_H_HAVE_INT64
+#define INT64_MIN (~INT64_MAX)
+#if @HAVE_LONG_64BIT@
+#define INT64_MAX 9223372036854775807L
+#define UINT64_MAX 18446744073709551615UL
+#elif @HAVE_LONG_LONG_64BIT@
+#define INT64_MAX 9223372036854775807LL
+#define UINT64_MAX 18446744073709551615ULL
+#elif defined(_MSC_VER)
+#define INT64_MAX 9223372036854775807i64
+#define UINT64_MAX 18446744073709551615ui64
+#endif
+#endif
+
+/* 7.18.2.2. Limits of minimum-width integer types */
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#ifdef _STDINT_H_HAVE_INT64
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+#endif
+
+/* 7.18.2.3. Limits of fastest minimum-width integer types */
+
+#define INT_FAST8_MIN INT32_MIN
+#define INT_FAST8_MAX INT32_MAX
+#define UINT_FAST8_MAX UINT32_MAX
+#define INT_FAST16_MIN INT32_MIN
+#define INT_FAST16_MAX INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#ifdef _STDINT_H_HAVE_INT64
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+#endif
+
+/* 7.18.2.4. Limits of integer types capable of holding object pointers */
+
+#define INTPTR_MIN LONG_MIN
+#define INTPTR_MAX LONG_MAX
+#define UINTPTR_MAX ULONG_MAX
+
+/* 7.18.2.5. Limits of greatest-width integer types */
+
+#ifdef _STDINT_H_HAVE_INT64
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+#else
+#define INTMAX_MIN INT32_MIN
+#define INTMAX_MAX INT32_MAX
+#define UINTMAX_MAX UINT32_MAX
+#endif
+
+/* 7.18.3. Limits of other integer types */
+
+#define PTRDIFF_MIN (~(ptrdiff_t)0 << (sizeof(ptrdiff_t)*CHAR_BIT-1))
+#define PTRDIFF_MAX (~PTRDIFF_MIN)
+
+/* This may be wrong... */
+#define SIG_ATOMIC_MIN 0
+#define SIG_ATOMIC_MAX 127
+
+#define SIZE_MAX (~(size_t)0)
+
+/* wchar_t limits already defined in <stddef.h>. */
+/* wint_t limits already defined in <wchar.h>. */
+
+#endif
+
+/* 7.18.4. Macros for integer constants */
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+
+/* 7.18.4.1. Macros for minimum-width integer constants */
+
+#define INT8_C(x) x
+#define UINT8_C(x) x##U
+#define INT16_C(x) x
+#define UINT16_C(x) x##U
+#define INT32_C(x) x
+#define UINT32_C(x) x##U
+#if @HAVE_LONG_64BIT@
+#define INT64_C(x) x##L
+#define UINT64_C(x) x##UL
+#elif @HAVE_LONG_LONG_64BIT@
+#define INT64_C(x) x##LL
+#define UINT64_C(x) x##ULL
+#elif defined(_MSC_VER)
+#define INT64_C(x) x##i64
+#define UINT64_C(x) x##ui64
+#endif
+
+/* 7.18.4.2. Macros for greatest-width integer constants */
+
+#if @HAVE_LONG_64BIT@
+#define INTMAX_C(x) x##L
+#define UINTMAX_C(x) x##UL
+#elif @HAVE_LONG_LONG_64BIT@
+#define INTMAX_C(x) x##LL
+#define UINTMAX_C(x) x##ULL
+#elif defined(_MSC_VER)
+#define INTMAX_C(x) x##i64
+#define UINTMAX_C(x) x##ui64
+#else
+#define INTMAX_C(x) x
+#define UINTMAX_C(x) x##U
+#endif
+
+#endif
+
+#endif /* !_STDINT_H_HAVE_SYSTEM_INTTYPES */
+
+#endif /* _STDINT_H */
diff --git a/lib/strcase.h b/lib/strcase.h
new file mode 100644
index 0000000..e420798
--- /dev/null
+++ b/lib/strcase.h
@@ -0,0 +1,48 @@
+/* Case-insensitive string comparison functions.
+ Copyright (C) 1995-1996, 2001, 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _STRCASE_H
+#define _STRCASE_H
+
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Compare strings S1 and S2, ignoring case, returning less than, equal to or
+ greater than zero if S1 is lexicographically less than, equal to or greater
+ than S2.
+ Note: This function may, in multibyte locales, return 0 for strings of
+ different lengths! */
+extern int strcasecmp (const char *s1, const char *s2);
+
+/* Compare no more than N characters of strings S1 and S2, ignoring case,
+ returning less than, equal to or greater than zero if S1 is
+ lexicographically less than, equal to or greater than S2.
+ Note: This function can not work correctly in multibyte locales. */
+extern int strncasecmp (const char *s1, const char *s2, size_t n);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _STRCASE_H */
diff --git a/lib/strcasecmp.c b/lib/strcasecmp.c
new file mode 100644
index 0000000..71f2eca
--- /dev/null
+++ b/lib/strcasecmp.c
@@ -0,0 +1,98 @@
+/* Case-insensitive string comparison function.
+ Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2005,
+ based on earlier glibc code.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "strcase.h"
+
+#include <ctype.h>
+
+#if HAVE_MBRTOWC
+# include "mbuiter.h"
+#endif
+
+#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
+
+/* Compare strings S1 and S2, ignoring case, returning less than, equal to or
+ greater than zero if S1 is lexicographically less than, equal to or greater
+ than S2.
+ Note: This function may, in multibyte locales, return 0 for strings of
+ different lengths! */
+int
+strcasecmp (const char *s1, const char *s2)
+{
+ if (s1 == s2)
+ return 0;
+
+ /* Be careful not to look at the entire extent of s1 or s2 until needed.
+ This is useful because when two strings differ, the difference is
+ most often already in the very few first characters. */
+#if HAVE_MBRTOWC
+ if (MB_CUR_MAX > 1)
+ {
+ mbui_iterator_t iter1;
+ mbui_iterator_t iter2;
+
+ mbui_init (iter1, s1);
+ mbui_init (iter2, s2);
+
+ while (mbui_avail (iter1) && mbui_avail (iter2))
+ {
+ int cmp = mb_casecmp (mbui_cur (iter1), mbui_cur (iter2));
+
+ if (cmp != 0)
+ return cmp;
+
+ mbui_advance (iter1);
+ mbui_advance (iter2);
+ }
+ if (mbui_avail (iter1))
+ /* s2 terminated before s1. */
+ return 1;
+ if (mbui_avail (iter2))
+ /* s1 terminated before s2. */
+ return -1;
+ return 0;
+ }
+ else
+#endif
+ {
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+
+ do
+ {
+ c1 = TOLOWER (*p1);
+ c2 = TOLOWER (*p2);
+
+ if (c1 == '\0')
+ break;
+
+ ++p1;
+ ++p2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+ }
+}
diff --git a/lib/strdup.c b/lib/strdup.c
new file mode 100644
index 0000000..d6d0116
--- /dev/null
+++ b/lib/strdup.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 1991, 1996, 1997, 1998, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef _LIBC
+/* Get specification. */
+# include "strdup.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#undef __strdup
+#undef strdup
+
+#ifndef weak_alias
+# define __strdup strdup
+#endif
+
+/* Duplicate S, returning an identical malloc'd string. */
+char *
+__strdup (const char *s)
+{
+ size_t len = strlen (s) + 1;
+ void *new = malloc (len);
+
+ if (new == NULL)
+ return NULL;
+
+ return (char *) memcpy (new, s, len);
+}
+#ifdef libc_hidden_def
+libc_hidden_def (__strdup)
+#endif
+#ifdef weak_alias
+weak_alias (__strdup, strdup)
+#endif
diff --git a/lib/strdup.h b/lib/strdup.h
new file mode 100644
index 0000000..a0d5fb9
--- /dev/null
+++ b/lib/strdup.h
@@ -0,0 +1,29 @@
+/* strdup.h -- duplicate a string
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef STRDUP_H_
+#define STRDUP_H_
+
+/* Get strdup declaration, if available. */
+#include <string.h>
+
+#if defined HAVE_DECL_STRDUP && !HAVE_DECL_STRDUP && !defined strdup
+/* Duplicate S, returning an identical malloc'd string. */
+extern char *strdup (const char *s);
+#endif
+
+#endif /* STRDUP_H_ */
diff --git a/lib/strerror.c b/lib/strerror.c
new file mode 100644
index 0000000..623821d
--- /dev/null
+++ b/lib/strerror.c
@@ -0,0 +1,49 @@
+/* strerror.c --- ANSI C compatible system error routine
+
+ Copyright (C) 1986, 1988, 1989, 1991, 2002, 2003 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <limits.h>
+
+/* Don't include <stdio.h>, since it may or may not declare
+ sys_errlist and its declarations may collide with ours. Just
+ declare the stuff that we need directly. Standard hosted C89
+ implementations define strerror and they don't need this strerror
+ function, so take some liberties with the standard to cater to
+ ancient or limited freestanding implementations. */
+int sprintf (char *, char const *, ...);
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror (int n)
+{
+ static char const fmt[] = "Unknown error (%d)";
+ static char mesg[sizeof fmt + sizeof n * CHAR_BIT / 3];
+
+ if (n < 0 || n >= sys_nerr)
+ {
+ sprintf (mesg, fmt, n);
+ return mesg;
+ }
+ else
+ return sys_errlist[n];
+}
diff --git a/lib/strftime.c b/lib/strftime.c
new file mode 100644
index 0000000..b68b4cf
--- /dev/null
+++ b/lib/strftime.c
@@ -0,0 +1,1375 @@
+/* Copyright (C) 1991-1999, 2000, 2001, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define HAVE_MBLEN 1
+# define HAVE_MBRLEN 1
+# define HAVE_STRUCT_ERA_ENTRY 1
+# define HAVE_TM_GMTOFF 1
+# define HAVE_TM_ZONE 1
+# define HAVE_TZNAME 1
+# define HAVE_TZSET 1
+# define MULTIBYTE_IS_FORMAT_SAFE 1
+# include "../locale/localeinfo.h"
+#endif
+
+#include <ctype.h>
+#include <sys/types.h> /* Some systems define `time_t' here. */
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#if HAVE_TZNAME
+extern char *tzname[];
+#endif
+
+/* Do multibyte processing if multibytes are supported, unless
+ multibyte sequences are safe in formats. Multibyte sequences are
+ safe if they cannot contain byte sequences that look like format
+ conversion specifications. The GNU C Library uses UTF8 multibyte
+ encoding, which is safe for formats, but strftime.c can be used
+ with other C libraries that use unsafe encodings. */
+#define DO_MULTIBYTE (HAVE_MBLEN && HAVE_WCHAR_H && ! MULTIBYTE_IS_FORMAT_SAFE)
+
+#if DO_MULTIBYTE
+# if HAVE_MBRLEN
+# include <wchar.h>
+# else
+ /* Simulate mbrlen with mblen as best we can. */
+# define mbstate_t int
+# define mbrlen(s, n, ps) mblen (s, n)
+# define mbsinit(ps) (*(ps) == 0)
+# endif
+ static const mbstate_t mbstate_zero;
+#endif
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef COMPILE_WIDE
+# include <endian.h>
+# define CHAR_T wchar_t
+# define UCHAR_T unsigned int
+# define L_(Str) L##Str
+# define NLW(Sym) _NL_W##Sym
+
+# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
+# define STRLEN(s) __wcslen (s)
+
+#else
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define L_(Str) Str
+# define NLW(Sym) Sym
+
+# define MEMCPY(d, s, n) memcpy (d, s, n)
+# define STRLEN(s) strlen (s)
+
+# ifdef _LIBC
+# define MEMPCPY(d, s, n) __mempcpy (d, s, n)
+# else
+# ifndef HAVE_MEMPCPY
+# define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
+# endif
+# endif
+#endif
+
+/* Shift A right by B bits portably, by dividing A by 2**B and
+ truncating towards minus infinity. A and B should be free of side
+ effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
+ INT_BITS is the number of useful bits in an int. GNU code can
+ assume that INT_BITS is at least 32.
+
+ ISO C99 says that A >> B is implementation-defined if A < 0. Some
+ implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
+ right in the usual way when A < 0, so SHR falls back on division if
+ ordinary A >> B doesn't seem to be the usual signed shift. */
+#define SHR(a, b) \
+ (-1 >> 1 == -1 \
+ ? (a) >> (b) \
+ : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
+
+/* Bound on length of the string representing an integer type or expression T.
+ Subtract 1 for the sign bit if t is signed; log10 (2.0) < 146/485;
+ add 1 for integer division truncation; add 1 more for a minus sign
+ if needed. */
+#define INT_STRLEN_BOUND(t) \
+ ((sizeof (t) * CHAR_BIT - 1) * 146 / 485 + 2)
+
+#define TM_YEAR_BASE 1900
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+# define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+
+#ifdef _LIBC
+# define tzname __tzname
+# define tzset __tzset
+#endif
+
+#if !HAVE_TM_GMTOFF
+/* Portable standalone applications should supply a "time_r.h" that
+ declares a POSIX-compliant localtime_r, for the benefit of older
+ implementations that lack localtime_r or have a nonstandard one.
+ See the gnulib time_r module for one way to implement this. */
+# include "time_r.h"
+# undef __gmtime_r
+# undef __localtime_r
+# define __gmtime_r gmtime_r
+# define __localtime_r localtime_r
+#endif
+
+
+#ifdef COMPILE_WIDE
+# define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
+# define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
+#else
+# define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
+# define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
+#endif
+
+#define add(n, f) \
+ do \
+ { \
+ int _n = (n); \
+ int _delta = width - _n; \
+ int _incr = _n + (_delta > 0 ? _delta : 0); \
+ if ((size_t) _incr >= maxsize - i) \
+ return 0; \
+ if (p) \
+ { \
+ if (_delta > 0) \
+ { \
+ if (pad == L_('0')) \
+ memset_zero (p, _delta); \
+ else \
+ memset_space (p, _delta); \
+ } \
+ f; \
+ p += _n; \
+ } \
+ i += _incr; \
+ } while (0)
+
+#define cpy(n, s) \
+ add ((n), \
+ if (to_lowcase) \
+ memcpy_lowcase (p, (s), _n LOCALE_ARG); \
+ else if (to_uppcase) \
+ memcpy_uppcase (p, (s), _n LOCALE_ARG); \
+ else \
+ MEMCPY ((void *) p, (void const *) (s), _n))
+
+#ifdef COMPILE_WIDE
+# ifndef USE_IN_EXTENDED_LOCALE_MODEL
+# undef __mbsrtowcs_l
+# define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
+# endif
+# define widen(os, ws, l) \
+ { \
+ mbstate_t __st; \
+ const char *__s = os; \
+ memset (&__st, '\0', sizeof (__st)); \
+ l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \
+ ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t)); \
+ (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \
+ }
+#endif
+
+
+#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
+/* We use this code also for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT
+ macro. */
+# define strftime __strftime_l
+# define wcsftime __wcsftime_l
+# undef _NL_CURRENT
+# define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+# define LOCALE_ARG , loc
+# define LOCALE_PARAM_PROTO , __locale_t loc
+# define HELPER_LOCALE_ARG , current
+#else
+# define LOCALE_PARAM_PROTO
+# define LOCALE_ARG
+# ifdef _LIBC
+# define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
+# else
+# define HELPER_LOCALE_ARG
+# endif
+#endif
+
+#ifdef COMPILE_WIDE
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define TOUPPER(Ch, L) __towupper_l (Ch, L)
+# define TOLOWER(Ch, L) __towlower_l (Ch, L)
+# else
+# define TOUPPER(Ch, L) towupper (Ch)
+# define TOLOWER(Ch, L) towlower (Ch)
+# endif
+#else
+# ifdef _LIBC
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define TOUPPER(Ch, L) __toupper_l (Ch, L)
+# define TOLOWER(Ch, L) __tolower_l (Ch, L)
+# else
+# define TOUPPER(Ch, L) toupper (Ch)
+# define TOLOWER(Ch, L) tolower (Ch)
+# endif
+# else
+# define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
+# define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
+# endif
+#endif
+/* We don't use `isdigit' here since the locale dependent
+ interpretation is not what we want here. We only need to accept
+ the arabic digits in the ASCII range. One day there is perhaps a
+ more reliable way to accept other sets of digits. */
+#define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
+
+static CHAR_T *
+memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
+ size_t len LOCALE_PARAM_PROTO)
+{
+ while (len-- > 0)
+ dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
+ return dest;
+}
+
+static CHAR_T *
+memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
+ size_t len LOCALE_PARAM_PROTO)
+{
+ while (len-- > 0)
+ dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
+ return dest;
+}
+
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds. */
+# define tm_diff ftime_tm_diff
+static int
+tm_diff (const struct tm *a, const struct tm *b)
+{
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations,
+ but it's OK to assume that A and B are close to each other. */
+ int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
+ int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = SHR (a100, 2);
+ int b400 = SHR (b100, 2);
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ int years = a->tm_year - b->tm_year;
+ int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+
+
+/* The number of days from the first day of the first ISO week of this
+ year to the year day YDAY with week day WDAY. ISO weeks start on
+ Monday; the first ISO week has the year's first Thursday. YDAY may
+ be as small as YDAY_MINIMUM. */
+#define ISO_WEEK_START_WDAY 1 /* Monday */
+#define ISO_WEEK1_WDAY 4 /* Thursday */
+#define YDAY_MINIMUM (-366)
+#ifdef __GNUC__
+__inline__
+#endif
+static int
+iso_week_days (int yday, int wday)
+{
+ /* Add enough to the first operand of % to make it nonnegative. */
+ int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
+ return (yday
+ - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
+ + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
+}
+
+
+#if !(defined _NL_CURRENT || HAVE_STRFTIME)
+static CHAR_T const weekday_name[][10] =
+ {
+ L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
+ L_("Thursday"), L_("Friday"), L_("Saturday")
+ };
+static CHAR_T const month_name[][10] =
+ {
+ L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
+ L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
+ L_("November"), L_("December")
+ };
+#endif
+
+
+/* When compiling this file, GNU applications can #define my_strftime
+ to a symbol (typically nstrftime) to get an extended strftime with
+ extra arguments UT and NS. Emacs is a special case for now, but
+ this Emacs-specific code can be removed once Emacs's config.h
+ defines my_strftime. */
+#if defined emacs && !defined my_strftime
+# define my_strftime nstrftime
+#endif
+
+#ifdef my_strftime
+# define extra_args , ut, ns
+# define extra_args_spec , int ut, int ns
+#else
+# ifdef COMPILE_WIDE
+# define my_strftime wcsftime
+# define nl_get_alt_digit _nl_get_walt_digit
+# else
+# define my_strftime strftime
+# define nl_get_alt_digit _nl_get_alt_digit
+# endif
+# define extra_args
+# define extra_args_spec
+/* We don't have this information in general. */
+# define ut 0
+# define ns 0
+#endif
+
+
+/* Write information from TP into S according to the format
+ string FORMAT, writing no more that MAXSIZE characters
+ (including the terminating '\0') and returning number of
+ characters written. If S is NULL, nothing will be written
+ anywhere, so to determine how many characters would be
+ written, use NULL for S and (size_t) -1 for MAXSIZE. */
+size_t
+my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
+ const struct tm *tp extra_args_spec LOCALE_PARAM_PROTO)
+{
+#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
+ struct locale_data *const current = loc->__locales[LC_TIME];
+#endif
+
+ int hour12 = tp->tm_hour;
+#ifdef _NL_CURRENT
+ /* We cannot make the following values variables since we must delay
+ the evaluation of these values until really needed since some
+ expressions might not be valid in every situation. The `struct tm'
+ might be generated by a strptime() call that initialized
+ only a few elements. Dereference the pointers only if the format
+ requires this. Then it is ok to fail if the pointers are invalid. */
+# define a_wkday \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
+# define f_wkday \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
+# define a_month \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
+# define f_month \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
+# define ampm \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
+ ? NLW(PM_STR) : NLW(AM_STR)))
+
+# define aw_len STRLEN (a_wkday)
+# define am_len STRLEN (a_month)
+# define ap_len STRLEN (ampm)
+#else
+# if !HAVE_STRFTIME
+# define f_wkday (weekday_name[tp->tm_wday])
+# define f_month (month_name[tp->tm_mon])
+# define a_wkday f_wkday
+# define a_month f_month
+# define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
+
+ size_t aw_len = 3;
+ size_t am_len = 3;
+ size_t ap_len = 2;
+# endif
+#endif
+ const char *zone;
+ size_t i = 0;
+ CHAR_T *p = s;
+ const CHAR_T *f;
+#if DO_MULTIBYTE && !defined COMPILE_WIDE
+ const char *format_end = NULL;
+#endif
+
+#if ! defined _LIBC && ! HAVE_RUN_TZSET_TEST
+ /* Solaris 2.5.x and 2.6 tzset sometimes modify the storage returned
+ by localtime. On such systems, we must either use the tzset and
+ localtime wrappers to work around the bug (which sets
+ HAVE_RUN_TZSET_TEST) or make a copy of the structure. */
+ struct tm copy = *tp;
+ tp = &copy;
+#endif
+
+ zone = NULL;
+#if HAVE_TM_ZONE
+ /* The POSIX test suite assumes that setting
+ the environment variable TZ to a new value before calling strftime()
+ will influence the result (the %Z format) even if the information in
+ TP is computed with a totally different time zone.
+ This is bogus: though POSIX allows bad behavior like this,
+ POSIX does not require it. Do the right thing instead. */
+ zone = (const char *) tp->tm_zone;
+#endif
+#if HAVE_TZNAME
+ if (ut)
+ {
+ if (! (zone && *zone))
+ zone = "GMT";
+ }
+ else
+ {
+ /* POSIX.1 requires that local time zone information be used as
+ though strftime called tzset. */
+# if HAVE_TZSET
+ tzset ();
+# endif
+ }
+#endif
+
+ if (hour12 > 12)
+ hour12 -= 12;
+ else
+ if (hour12 == 0)
+ hour12 = 12;
+
+ for (f = format; *f != '\0'; ++f)
+ {
+ int pad = 0; /* Padding for number ('-', '_', or 0). */
+ int modifier; /* Field modifier ('E', 'O', or 0). */
+ int digits; /* Max digits for numeric format. */
+ int number_value; /* Numeric value to be printed. */
+ unsigned int u_number_value; /* (unsigned int) number_value. */
+ bool negative_number; /* 1 if the number is negative. */
+ const CHAR_T *subfmt;
+ CHAR_T *bufp;
+ CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
+ ? INT_STRLEN_BOUND (time_t)
+ : INT_STRLEN_BOUND (int))];
+ int width = -1;
+ bool to_lowcase = false;
+ bool to_uppcase = false;
+ bool change_case = false;
+ int format_char;
+
+#if DO_MULTIBYTE && !defined COMPILE_WIDE
+ switch (*f)
+ {
+ case L_('%'):
+ break;
+
+ case L_('\b'): case L_('\t'): case L_('\n'):
+ case L_('\v'): case L_('\f'): case L_('\r'):
+ case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
+ case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
+ case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
+ case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
+ case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
+ case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
+ case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
+ case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
+ case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
+ case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
+ case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
+ case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
+ case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
+ case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
+ case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
+ case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
+ case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
+ case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
+ case L_('~'):
+ /* The C Standard requires these 98 characters (plus '%') to
+ be in the basic execution character set. None of these
+ characters can start a multibyte sequence, so they need
+ not be analyzed further. */
+ add (1, *p = *f);
+ continue;
+
+ default:
+ /* Copy this multibyte sequence until we reach its end, find
+ an error, or come back to the initial shift state. */
+ {
+ mbstate_t mbstate = mbstate_zero;
+ size_t len = 0;
+ size_t fsize;
+
+ if (! format_end)
+ format_end = f + strlen (f) + 1;
+ fsize = format_end - f;
+
+ do
+ {
+ size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
+
+ if (bytes == 0)
+ break;
+
+ if (bytes == (size_t) -2)
+ {
+ len += strlen (f + len);
+ break;
+ }
+
+ if (bytes == (size_t) -1)
+ {
+ len++;
+ break;
+ }
+
+ len += bytes;
+ }
+ while (! mbsinit (&mbstate));
+
+ cpy (len, f);
+ f += len - 1;
+ continue;
+ }
+ }
+
+#else /* ! DO_MULTIBYTE */
+
+ /* Either multibyte encodings are not supported, they are
+ safe for formats, so any non-'%' byte can be copied through,
+ or this is the wide character version. */
+ if (*f != L_('%'))
+ {
+ add (1, *p = *f);
+ continue;
+ }
+
+#endif /* ! DO_MULTIBYTE */
+
+ /* Check for flags that can modify a format. */
+ while (1)
+ {
+ switch (*++f)
+ {
+ /* This influences the number formats. */
+ case L_('_'):
+ case L_('-'):
+ case L_('0'):
+ pad = *f;
+ continue;
+
+ /* This changes textual output. */
+ case L_('^'):
+ to_uppcase = true;
+ continue;
+ case L_('#'):
+ change_case = true;
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ /* As a GNU extension we allow to specify the field width. */
+ if (ISDIGIT (*f))
+ {
+ width = 0;
+ do
+ {
+ if (width > INT_MAX / 10
+ || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
+ /* Avoid overflow. */
+ width = INT_MAX;
+ else
+ {
+ width *= 10;
+ width += *f - L_('0');
+ }
+ ++f;
+ }
+ while (ISDIGIT (*f));
+ }
+
+ /* Check for modifiers. */
+ switch (*f)
+ {
+ case L_('E'):
+ case L_('O'):
+ modifier = *f++;
+ break;
+
+ default:
+ modifier = 0;
+ break;
+ }
+
+ /* Now do the specified format. */
+ format_char = *f;
+ switch (format_char)
+ {
+#define DO_NUMBER(d, v) \
+ digits = d; \
+ number_value = v; goto do_number
+#define DO_SIGNED_NUMBER(d, negative, v) \
+ digits = d; \
+ negative_number = negative; \
+ u_number_value = v; goto do_signed_number
+#define DO_NUMBER_SPACEPAD(d, v) \
+ digits = d; \
+ number_value = v; goto do_number_spacepad
+
+ case L_('%'):
+ if (modifier != 0)
+ goto bad_format;
+ add (1, *p = *f);
+ break;
+
+ case L_('a'):
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = true;
+ to_lowcase = false;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (aw_len, a_wkday);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case 'A':
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = true;
+ to_lowcase = false;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (STRLEN (f_wkday), f_wkday);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('b'):
+ case L_('h'):
+ if (change_case)
+ {
+ to_uppcase = true;
+ to_lowcase = false;
+ }
+ if (modifier != 0)
+ goto bad_format;
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (am_len, a_month);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('B'):
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = true;
+ to_lowcase = false;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (STRLEN (f_month), f_month);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('c'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == 'E'
+ && (*(subfmt =
+ (const CHAR_T *) _NL_CURRENT (LC_TIME,
+ NLW(ERA_D_T_FMT)))
+ != '\0')))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ subfmt = L_("%a %b %e %H:%M:%S %Y");
+# endif
+#endif
+
+ subformat:
+ {
+ CHAR_T *old_start = p;
+ size_t len = my_strftime (NULL, (size_t) -1, subfmt,
+ tp extra_args LOCALE_ARG);
+ add (len, my_strftime (p, maxsize - i, subfmt,
+ tp extra_args LOCALE_ARG));
+
+ if (to_uppcase)
+ while (old_start < p)
+ {
+ *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
+ ++old_start;
+ }
+ }
+ break;
+
+#if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
+ underlying_strftime:
+ {
+ /* The relevant information is available only via the
+ underlying strftime implementation, so use that. */
+ char ufmt[5];
+ char *u = ufmt;
+ char ubuf[1024]; /* enough for any single format in practice */
+ size_t len;
+ /* Make sure we're calling the actual underlying strftime.
+ In some cases, config.h contains something like
+ "#define strftime rpl_strftime". */
+# ifdef strftime
+# undef strftime
+ size_t strftime ();
+# endif
+
+ /* The space helps distinguish strftime failure from empty
+ output. */
+ *u++ = ' ';
+ *u++ = '%';
+ if (modifier != 0)
+ *u++ = modifier;
+ *u++ = format_char;
+ *u = '\0';
+ len = strftime (ubuf, sizeof ubuf, ufmt, tp);
+ if (len != 0)
+ cpy (len - 1, ubuf + 1);
+ }
+ break;
+#endif
+
+ case L_('C'):
+ if (modifier == L_('O'))
+ goto bad_format;
+ if (modifier == L_('E'))
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+# ifdef COMPILE_WIDE
+ size_t len = __wcslen (era->era_wname);
+ cpy (len, era->era_wname);
+# else
+ size_t len = strlen (era->era_name);
+ cpy (len, era->era_name);
+# endif
+ break;
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+
+ {
+ int century = tp->tm_year / 100 + TM_YEAR_BASE / 100;
+ century -= tp->tm_year % 100 < 0 && 0 < century;
+ DO_SIGNED_NUMBER (2, tp->tm_year < - TM_YEAR_BASE, century);
+ }
+
+ case L_('x'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == L_('E')
+ && (*(subfmt =
+ (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
+ != L_('\0'))))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
+ goto subformat;
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ /* Fall through. */
+# endif
+#endif
+ case L_('D'):
+ if (modifier != 0)
+ goto bad_format;
+ subfmt = L_("%m/%d/%y");
+ goto subformat;
+
+ case L_('d'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_mday);
+
+ case L_('e'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER_SPACEPAD (2, tp->tm_mday);
+
+ /* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
+ and then jump to one of these three labels. */
+
+ do_number_spacepad:
+ /* Force `_' flag unless overridden by `0' or `-' flag. */
+ if (pad != L_('0') && pad != L_('-'))
+ pad = L_('_');
+
+ do_number:
+ /* Format NUMBER_VALUE according to the MODIFIER flag. */
+ negative_number = number_value < 0;
+ u_number_value = number_value;
+
+ do_signed_number:
+ /* Format U_NUMBER_VALUE according to the MODIFIER flag.
+ NEGATIVE_NUMBER is nonzero if the original number was
+ negative; in this case it was converted directly to
+ unsigned int (i.e., modulo (UINT_MAX + 1)) without
+ negating it. */
+ if (modifier == L_('O') && !negative_number)
+ {
+#ifdef _NL_CURRENT
+ /* Get the locale specific alternate representation of
+ the number. If none exist NULL is returned. */
+ const CHAR_T *cp = nl_get_alt_digit (u_number_value
+ HELPER_LOCALE_ARG);
+
+ if (cp != NULL)
+ {
+ size_t digitlen = STRLEN (cp);
+ if (digitlen != 0)
+ {
+ cpy (digitlen, cp);
+ break;
+ }
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+
+ bufp = buf + sizeof (buf) / sizeof (buf[0]);
+
+ if (negative_number)
+ u_number_value = - u_number_value;
+
+ do
+ {
+ *--bufp = u_number_value % 10 + L_('0');
+ u_number_value /= 10;
+ }
+ while (u_number_value != 0);
+
+ do_number_sign_and_padding:
+ if (digits < width)
+ digits = width;
+
+ if (negative_number)
+ *--bufp = L_('-');
+
+ if (pad != L_('-'))
+ {
+ int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
+ - bufp);
+
+ if (padding > 0)
+ {
+ if (pad == L_('_'))
+ {
+ if ((size_t) padding >= maxsize - i)
+ return 0;
+
+ if (p)
+ memset_space (p, padding);
+ i += padding;
+ width = width > padding ? width - padding : 0;
+ }
+ else
+ {
+ if ((size_t) digits >= maxsize - i)
+ return 0;
+
+ if (negative_number)
+ {
+ ++bufp;
+
+ if (p)
+ *p++ = L_('-');
+ ++i;
+ }
+
+ if (p)
+ memset_zero (p, padding);
+ i += padding;
+ width = 0;
+ }
+ }
+ }
+
+ cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
+ break;
+
+ case L_('F'):
+ if (modifier != 0)
+ goto bad_format;
+ subfmt = L_("%Y-%m-%d");
+ goto subformat;
+
+ case L_('H'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_hour);
+
+ case L_('I'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, hour12);
+
+ case L_('k'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER_SPACEPAD (2, tp->tm_hour);
+
+ case L_('l'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER_SPACEPAD (2, hour12);
+
+ case L_('j'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_SIGNED_NUMBER (3, tp->tm_yday < -1, tp->tm_yday + 1U);
+
+ case L_('M'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_min);
+
+ case L_('m'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_SIGNED_NUMBER (2, tp->tm_mon < -1, tp->tm_mon + 1U);
+
+#ifndef _LIBC
+ case L_('N'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ number_value = ns;
+ if (width != -1)
+ {
+ /* Take an explicit width less than 9 as a precision. */
+ int j;
+ for (j = width; j < 9; j++)
+ number_value /= 10;
+ }
+
+ DO_NUMBER (9, number_value);
+#endif
+
+ case L_('n'):
+ add (1, *p = L_('\n'));
+ break;
+
+ case L_('P'):
+ to_lowcase = true;
+#if !defined _NL_CURRENT && HAVE_STRFTIME
+ format_char = L_('p');
+#endif
+ /* FALLTHROUGH */
+
+ case L_('p'):
+ if (change_case)
+ {
+ to_uppcase = false;
+ to_lowcase = true;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (ap_len, ampm);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('R'):
+ subfmt = L_("%H:%M");
+ goto subformat;
+
+ case L_('r'):
+#if !defined _NL_CURRENT && HAVE_STRFTIME
+ goto underlying_strftime;
+#else
+# ifdef _NL_CURRENT
+ if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
+ NLW(T_FMT_AMPM)))
+ == L_('\0'))
+# endif
+ subfmt = L_("%I:%M:%S %p");
+ goto subformat;
+#endif
+
+ case L_('S'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_sec);
+
+ case L_('s'): /* GNU extension. */
+ {
+ struct tm ltm;
+ time_t t;
+
+ ltm = *tp;
+ t = mktime (&ltm);
+
+ /* Generate string value for T using time_t arithmetic;
+ this works even if sizeof (long) < sizeof (time_t). */
+
+ bufp = buf + sizeof (buf) / sizeof (buf[0]);
+ negative_number = t < 0;
+
+ do
+ {
+ int d = t % 10;
+ t /= 10;
+ *--bufp = (negative_number ? -d : d) + L_('0');
+ }
+ while (t != 0);
+
+ digits = 1;
+ goto do_number_sign_and_padding;
+ }
+
+ case L_('X'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == L_('E')
+ && (*(subfmt =
+ (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
+ != L_('\0'))))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
+ goto subformat;
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ /* Fall through. */
+# endif
+#endif
+ case L_('T'):
+ subfmt = L_("%H:%M:%S");
+ goto subformat;
+
+ case L_('t'):
+ add (1, *p = L_('\t'));
+ break;
+
+ case L_('u'):
+ DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
+
+ case L_('U'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
+
+ case L_('V'):
+ case L_('g'):
+ case L_('G'):
+ if (modifier == L_('E'))
+ goto bad_format;
+ {
+ /* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
+ is a leap year, except that YEAR and YEAR - 1 both work
+ correctly even when (tp->tm_year + TM_YEAR_BASE) would
+ overflow. */
+ int year = (tp->tm_year
+ + (tp->tm_year < 0
+ ? TM_YEAR_BASE % 400
+ : TM_YEAR_BASE % 400 - 400));
+ int year_adjust = 0;
+ int days = iso_week_days (tp->tm_yday, tp->tm_wday);
+
+ if (days < 0)
+ {
+ /* This ISO week belongs to the previous year. */
+ year_adjust = -1;
+ days = iso_week_days (tp->tm_yday + (365 + __isleap (year - 1)),
+ tp->tm_wday);
+ }
+ else
+ {
+ int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
+ tp->tm_wday);
+ if (0 <= d)
+ {
+ /* This ISO week belongs to the next year. */
+ year_adjust = 1;
+ days = d;
+ }
+ }
+
+ switch (*f)
+ {
+ case L_('g'):
+ {
+ int yy = (tp->tm_year % 100 + year_adjust) % 100;
+ DO_NUMBER (2, (0 <= yy
+ ? yy
+ : tp->tm_year < -TM_YEAR_BASE - year_adjust
+ ? -yy
+ : yy + 100));
+ }
+
+ case L_('G'):
+ DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
+ (tp->tm_year + (unsigned int) TM_YEAR_BASE
+ + year_adjust));
+
+ default:
+ DO_NUMBER (2, days / 7 + 1);
+ }
+ }
+
+ case L_('W'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
+
+ case L_('w'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (1, tp->tm_wday);
+
+ case L_('Y'):
+ if (modifier == 'E')
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+# ifdef COMPILE_WIDE
+ subfmt = era->era_wformat;
+# else
+ subfmt = era->era_format;
+# endif
+ goto subformat;
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+ if (modifier == L_('O'))
+ goto bad_format;
+ else
+ DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE,
+ tp->tm_year + (unsigned int) TM_YEAR_BASE);
+
+ case L_('y'):
+ if (modifier == L_('E'))
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+ int delta = tp->tm_year - era->start_date[0];
+ DO_NUMBER (1, (era->offset
+ + delta * era->absolute_direction));
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+
+ {
+ int yy = tp->tm_year % 100;
+ if (yy < 0)
+ yy = tp->tm_year < - TM_YEAR_BASE ? -yy : yy + 100;
+ DO_NUMBER (2, yy);
+ }
+
+ case L_('Z'):
+ if (change_case)
+ {
+ to_uppcase = false;
+ to_lowcase = true;
+ }
+
+#if HAVE_TZNAME
+ /* The tzset() call might have changed the value. */
+ if (!(zone && *zone) && tp->tm_isdst >= 0)
+ zone = tzname[tp->tm_isdst != 0];
+#endif
+ if (! zone)
+ zone = "";
+
+#ifdef COMPILE_WIDE
+ {
+ /* The zone string is always given in multibyte form. We have
+ to transform it first. */
+ wchar_t *wczone;
+ size_t len;
+ widen (zone, wczone, len);
+ cpy (len, wczone);
+ }
+#else
+ cpy (strlen (zone), zone);
+#endif
+ break;
+
+ case L_('z'):
+ if (tp->tm_isdst < 0)
+ break;
+
+ {
+ int diff;
+#if HAVE_TM_GMTOFF
+ diff = tp->tm_gmtoff;
+#else
+ if (ut)
+ diff = 0;
+ else
+ {
+ struct tm gtm;
+ struct tm ltm;
+ time_t lt;
+
+ ltm = *tp;
+ lt = mktime (&ltm);
+
+ if (lt == (time_t) -1)
+ {
+ /* mktime returns -1 for errors, but -1 is also a
+ valid time_t value. Check whether an error really
+ occurred. */
+ struct tm tm;
+
+ if (! __localtime_r (&lt, &tm)
+ || ((ltm.tm_sec ^ tm.tm_sec)
+ | (ltm.tm_min ^ tm.tm_min)
+ | (ltm.tm_hour ^ tm.tm_hour)
+ | (ltm.tm_mday ^ tm.tm_mday)
+ | (ltm.tm_mon ^ tm.tm_mon)
+ | (ltm.tm_year ^ tm.tm_year)))
+ break;
+ }
+
+ if (! __gmtime_r (&lt, &gtm))
+ break;
+
+ diff = tm_diff (&ltm, &gtm);
+ }
+#endif
+
+ if (diff < 0)
+ {
+ add (1, *p = L_('-'));
+ diff = -diff;
+ }
+ else
+ add (1, *p = L_('+'));
+
+ diff /= 60;
+ DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
+ }
+
+ case L_('\0'): /* GNU extension: % at end of format. */
+ --f;
+ /* Fall through. */
+ default:
+ /* Unknown format; output the format, including the '%',
+ since this is most likely the right thing to do if a
+ multibyte string has been misparsed. */
+ bad_format:
+ {
+ int flen;
+ for (flen = 1; f[1 - flen] != L_('%'); flen++)
+ continue;
+ cpy (flen, &f[1 - flen]);
+ }
+ break;
+ }
+ }
+
+ if (p && maxsize != 0)
+ *p = L_('\0');
+ return i;
+}
+#ifdef _LIBC
+libc_hidden_def (my_strftime)
+#endif
+
+
+#ifdef emacs
+/* For Emacs we have a separate interface which corresponds to the normal
+ strftime function plus the ut argument, but without the ns argument. */
+size_t
+emacs_strftimeu (char *s, size_t maxsize, const char *format,
+ const struct tm *tp, int ut)
+{
+ return my_strftime (s, maxsize, format, tp, ut, 0);
+}
+#endif
diff --git a/lib/strftime.h b/lib/strftime.h
new file mode 100644
index 0000000..16b996e
--- /dev/null
+++ b/lib/strftime.h
@@ -0,0 +1,21 @@
+/* declarations for strftime.c
+
+ Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <time.h>
+
+size_t nstrftime (char *, size_t, char const *, struct tm const *, int, int);
diff --git a/lib/stripslash.c b/lib/stripslash.c
new file mode 100644
index 0000000..9b55da4
--- /dev/null
+++ b/lib/stripslash.c
@@ -0,0 +1,40 @@
+/* stripslash.c -- remove redundant trailing slashes from a file name
+
+ Copyright (C) 1990, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "dirname.h"
+
+/* Remove trailing slashes from FILE.
+ Return true if a trailing slash was removed.
+ This is useful when using file name completion from a shell that
+ adds a "/" after directory names (such as tcsh and bash), because
+ the Unix rename and rmdir system calls return an "Invalid argument" error
+ when given a file that ends in "/" (except for the root directory). */
+
+bool
+strip_trailing_slashes (char *file)
+{
+ char *base = base_name (file);
+ char *base_lim = base + base_len (base);
+ bool had_slash = (*base_lim != '\0');
+ *base_lim = '\0';
+ return had_slash;
+}
diff --git a/lib/strncasecmp.c b/lib/strncasecmp.c
new file mode 100644
index 0000000..72ead01
--- /dev/null
+++ b/lib/strncasecmp.c
@@ -0,0 +1,58 @@
+/* strncasecmp.c -- case insensitive string comparator
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "strcase.h"
+
+#include <ctype.h>
+
+#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
+
+/* Compare no more than N bytes of strings S1 and S2,
+ ignoring case, returning less than, equal to or
+ greater than zero if S1 is lexicographically less
+ than, equal to or greater than S2. */
+
+int
+strncasecmp (const char *s1, const char *s2, size_t n)
+{
+ register const unsigned char *p1 = (const unsigned char *) s1;
+ register const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+
+ if (p1 == p2 || n == 0)
+ return 0;
+
+ do
+ {
+ c1 = TOLOWER (*p1);
+ c2 = TOLOWER (*p2);
+
+ if (--n == 0 || c1 == '\0')
+ break;
+
+ ++p1;
+ ++p2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
diff --git a/lib/strnlen1.c b/lib/strnlen1.c
new file mode 100644
index 0000000..f3338e7
--- /dev/null
+++ b/lib/strnlen1.c
@@ -0,0 +1,39 @@
+/* Find the length of STRING + 1, but scan at most MAXLEN bytes.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "strnlen1.h"
+
+#include <string.h>
+
+/* Find the length of STRING + 1, but scan at most MAXLEN bytes.
+ If no '\0' terminator is found in that many characters, return MAXLEN. */
+/* This is the same as strnlen (string, maxlen - 1) + 1. */
+size_t
+strnlen1 (const char *string, size_t maxlen)
+{
+ const char *end = memchr (string, '\0', maxlen);
+ if (end != NULL)
+ return end - string + 1;
+ else
+ return maxlen;
+}
diff --git a/lib/strnlen1.h b/lib/strnlen1.h
new file mode 100644
index 0000000..4f913ff
--- /dev/null
+++ b/lib/strnlen1.h
@@ -0,0 +1,41 @@
+/* Find the length of STRING + 1, but scan at most MAXLEN bytes.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _STRNLEN1_H
+#define _STRNLEN1_H
+
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Find the length of STRING + 1, but scan at most MAXLEN bytes.
+ If no '\0' terminator is found in that many characters, return MAXLEN. */
+/* This is the same as strnlen (string, maxlen - 1) + 1. */
+extern size_t strnlen1 (const char *string, size_t maxlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _STRNLEN1_H */
diff --git a/lib/strstr.c b/lib/strstr.c
new file mode 100644
index 0000000..e94cef7
--- /dev/null
+++ b/lib/strstr.c
@@ -0,0 +1,128 @@
+/* Searching in a string.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "strstr.h"
+
+#include <stddef.h> /* for NULL */
+
+#if HAVE_MBRTOWC
+# include "mbuiter.h"
+#endif
+
+/* Find the first occurrence of NEEDLE in HAYSTACK. */
+char *
+strstr (const char *haystack, const char *needle)
+{
+ /* Be careful not to look at the entire extent of haystack or needle
+ until needed. This is useful because of these two cases:
+ - haystack may be very long, and a match of needle found early,
+ - needle may be very long, and not even a short initial segment of
+ needle may be found in haystack. */
+#if HAVE_MBRTOWC
+ if (MB_CUR_MAX > 1)
+ {
+ mbui_iterator_t iter_needle;
+
+ mbui_init (iter_needle, needle);
+ if (mbui_avail (iter_needle))
+ {
+ mbui_iterator_t iter_haystack;
+
+ mbui_init (iter_haystack, haystack);
+ for (;; mbui_advance (iter_haystack))
+ {
+ if (!mbui_avail (iter_haystack))
+ /* No match. */
+ return NULL;
+
+ if (mb_equal (mbui_cur (iter_haystack), mbui_cur (iter_needle)))
+ /* The first character matches. */
+ {
+ mbui_iterator_t rhaystack;
+ mbui_iterator_t rneedle;
+
+ memcpy (&rhaystack, &iter_haystack, sizeof (mbui_iterator_t));
+ mbui_advance (rhaystack);
+
+ mbui_init (rneedle, needle);
+ if (!mbui_avail (rneedle))
+ abort ();
+ mbui_advance (rneedle);
+
+ for (;; mbui_advance (rhaystack), mbui_advance (rneedle))
+ {
+ if (!mbui_avail (rneedle))
+ /* Found a match. */
+ return (char *) mbui_cur_ptr (iter_haystack);
+ if (!mbui_avail (rhaystack))
+ /* No match. */
+ return NULL;
+ if (!mb_equal (mbui_cur (rhaystack), mbui_cur (rneedle)))
+ /* Nothing in this round. */
+ break;
+ }
+ }
+ }
+ }
+ else
+ return (char *) haystack;
+ }
+ else
+#endif
+ {
+ if (*needle != '\0')
+ {
+ /* Speed up the following searches of needle by caching its first
+ character. */
+ char b = *needle++;
+
+ for (;; haystack++)
+ {
+ if (*haystack == '\0')
+ /* No match. */
+ return NULL;
+ if (*haystack == b)
+ /* The first character matches. */
+ {
+ const char *rhaystack = haystack + 1;
+ const char *rneedle = needle;
+
+ for (;; rhaystack++, rneedle++)
+ {
+ if (*rneedle == '\0')
+ /* Found a match. */
+ return (char *) haystack;
+ if (*rhaystack == '\0')
+ /* No match. */
+ return NULL;
+ if (*rhaystack != *rneedle)
+ /* Nothing in this round. */
+ break;
+ }
+ }
+ }
+ }
+ else
+ return (char *) haystack;
+ }
+}
diff --git a/lib/strstr.h b/lib/strstr.h
new file mode 100644
index 0000000..a28b140
--- /dev/null
+++ b/lib/strstr.h
@@ -0,0 +1,37 @@
+/* Searching in a string.
+ Copyright (C) 2001-2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+
+/* Include string.h: on glibc systems, it contains a macro definition of
+ strstr() that would collide with our definition if included afterwards. */
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* No known system has a strstr() function that works correctly in
+ multibyte locales. Therefore we use our version always. */
+#undef strstr
+#define strstr rpl_strstr
+
+/* Find the first occurrence of NEEDLE in HAYSTACK. */
+extern char *strstr (const char *haystack, const char *needle);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib/strtol.c b/lib/strtol.c
new file mode 100644
index 0000000..9bfbe3c
--- /dev/null
+++ b/lib/strtol.c
@@ -0,0 +1,447 @@
+/* Convert string representation of a number into an integer value.
+
+ Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2003, 2005
+ Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@gnu.org.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define USE_NUMBER_GROUPING
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_NUMBER_GROUPING
+# include "../locale/localeinfo.h"
+#endif
+
+/* Nonzero if we are defining `strtoul' or `strtoull', operating on
+ unsigned integers. */
+#ifndef UNSIGNED
+# define UNSIGNED 0
+# define INT LONG int
+#else
+# define INT unsigned LONG int
+#endif
+
+/* Determine the name. */
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol __wcstoull_l
+# else
+# define strtol __wcstoul_l
+# endif
+# else
+# ifdef QUAD
+# define strtol __strtoull_l
+# else
+# define strtol __strtoul_l
+# endif
+# endif
+# else
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol __wcstoll_l
+# else
+# define strtol __wcstol_l
+# endif
+# else
+# ifdef QUAD
+# define strtol __strtoll_l
+# else
+# define strtol __strtol_l
+# endif
+# endif
+# endif
+#else
+# if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoull
+# else
+# define strtol wcstoul
+# endif
+# else
+# ifdef QUAD
+# define strtol strtoull
+# else
+# define strtol strtoul
+# endif
+# endif
+# else
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoll
+# else
+# define strtol wcstol
+# endif
+# else
+# ifdef QUAD
+# define strtol strtoll
+# endif
+# endif
+# endif
+#endif
+
+/* If QUAD is defined, we are defining `strtoll' or `strtoull',
+ operating on `long long int's. */
+#ifdef QUAD
+# define LONG long long
+# define STRTOL_LONG_MIN LONG_LONG_MIN
+# define STRTOL_LONG_MAX LONG_LONG_MAX
+# define STRTOL_ULONG_MAX ULONG_LONG_MAX
+
+/* The extra casts in the following macros work around compiler bugs,
+ e.g., in Cray C 5.0.3.0. */
+
+/* True if negative values of the signed integer type T use two's
+ complement, ones' complement, or signed magnitude representation,
+ respectively. Much GNU code assumes two's complement, but some
+ people like to be portable to all possible C hosts. */
+# define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
+# define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
+# define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
+
+/* True if the arithmetic type T is signed. */
+# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+
+/* The maximum and minimum values for the integer type T. These
+ macros have undefined behavior if T is signed and has padding bits.
+ If this is a problem for you, please let us know how to fix it for
+ your host. */
+# define TYPE_MINIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) 0 \
+ : TYPE_SIGNED_MAGNITUDE (t) \
+ ? ~ (t) 0 \
+ : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
+# define TYPE_MAXIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) -1 \
+ : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
+
+# ifndef ULONG_LONG_MAX
+# define ULONG_LONG_MAX TYPE_MAXIMUM (unsigned long long)
+# endif
+# ifndef LONG_LONG_MAX
+# define LONG_LONG_MAX TYPE_MAXIMUM (long long int)
+# endif
+# ifndef LONG_LONG_MIN
+# define LONG_LONG_MIN TYPE_MINIMUM (long long int)
+# endif
+
+# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
+ /* Work around gcc bug with using this constant. */
+ static const unsigned long long int maxquad = ULONG_LONG_MAX;
+# undef STRTOL_ULONG_MAX
+# define STRTOL_ULONG_MAX maxquad
+# endif
+#else
+# define LONG long
+# define STRTOL_LONG_MIN LONG_MIN
+# define STRTOL_LONG_MAX LONG_MAX
+# define STRTOL_ULONG_MAX ULONG_MAX
+#endif
+
+
+/* We use this code also for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT
+ macro. */
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# undef _NL_CURRENT
+# define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+# define LOCALE_PARAM , loc
+# define LOCALE_PARAM_PROTO , __locale_t loc
+#else
+# define LOCALE_PARAM
+# define LOCALE_PARAM_PROTO
+#endif
+
+#if defined _LIBC || defined HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#ifdef USE_WIDE_CHAR
+# include <wctype.h>
+# define L_(Ch) L##Ch
+# define UCHAR_TYPE wint_t
+# define STRING_TYPE wchar_t
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define ISSPACE(Ch) __iswspace_l ((Ch), loc)
+# define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __towupper_l ((Ch), loc)
+# else
+# define ISSPACE(Ch) iswspace (Ch)
+# define ISALPHA(Ch) iswalpha (Ch)
+# define TOUPPER(Ch) towupper (Ch)
+# endif
+#else
+# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+# else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+# endif
+# define L_(Ch) Ch
+# define UCHAR_TYPE unsigned char
+# define STRING_TYPE char
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define ISSPACE(Ch) __isspace_l ((Ch), loc)
+# define ISALPHA(Ch) __isalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __toupper_l ((Ch), loc)
+# else
+# define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch))
+# define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch))
+# define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch))
+# endif
+#endif
+
+#define INTERNAL(X) INTERNAL1(X)
+#define INTERNAL1(X) __##X##_internal
+#define WEAKNAME(X) WEAKNAME1(X)
+
+#ifdef USE_NUMBER_GROUPING
+/* This file defines a function to check for correct grouping. */
+# include "grouping.h"
+#endif
+
+
+
+/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+ If BASE is 0 the base is determined by the presence of a leading
+ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+ If BASE is < 2 or > 36, it is reset to 10.
+ If ENDPTR is not NULL, a pointer to the character after the last
+ one converted is stored in *ENDPTR. */
+
+INT
+INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
+ int base, int group LOCALE_PARAM_PROTO)
+{
+ int negative;
+ register unsigned LONG int cutoff;
+ register unsigned int cutlim;
+ register unsigned LONG int i;
+ register const STRING_TYPE *s;
+ register UCHAR_TYPE c;
+ const STRING_TYPE *save, *end;
+ int overflow;
+
+#ifdef USE_NUMBER_GROUPING
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+ struct locale_data *current = loc->__locales[LC_NUMERIC];
+# endif
+ /* The thousands character of the current locale. */
+ wchar_t thousands = L'\0';
+ /* The numeric grouping specification of the current locale,
+ in the format described in <locale.h>. */
+ const char *grouping;
+
+ if (group)
+ {
+ grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+ if (*grouping <= 0 || *grouping == CHAR_MAX)
+ grouping = NULL;
+ else
+ {
+ /* Figure out the thousands separator character. */
+# if defined _LIBC || defined _HAVE_BTOWC
+ thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP));
+ if (thousands == WEOF)
+ thousands = L'\0';
+# endif
+ if (thousands == L'\0')
+ grouping = NULL;
+ }
+ }
+ else
+ grouping = NULL;
+#endif
+
+ if (base < 0 || base == 1 || base > 36)
+ {
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ save = s = nptr;
+
+ /* Skip white space. */
+ while (ISSPACE (*s))
+ ++s;
+ if (*s == L_('\0'))
+ goto noconv;
+
+ /* Check for a sign. */
+ if (*s == L_('-'))
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == L_('+'))
+ {
+ negative = 0;
+ ++s;
+ }
+ else
+ negative = 0;
+
+ /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
+ if (*s == L_('0'))
+ {
+ if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X'))
+ {
+ s += 2;
+ base = 16;
+ }
+ else if (base == 0)
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+
+#ifdef USE_NUMBER_GROUPING
+ if (group)
+ {
+ /* Find the end of the digit string and check its grouping. */
+ end = s;
+ for (c = *end; c != L_('\0'); c = *++end)
+ if ((wchar_t) c != thousands
+ && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
+ && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
+ break;
+ if (*s == thousands)
+ end = s;
+ else
+ end = correctly_grouped_prefix (s, end, thousands, grouping);
+ }
+ else
+#endif
+ end = NULL;
+
+ cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
+ cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
+
+ overflow = 0;
+ i = 0;
+ for (c = *s; c != L_('\0'); c = *++s)
+ {
+ if (s == end)
+ break;
+ if (c >= L_('0') && c <= L_('9'))
+ c -= L_('0');
+ else if (ISALPHA (c))
+ c = TOUPPER (c) - L_('A') + 10;
+ else
+ break;
+ if ((int) c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ i *= (unsigned LONG int) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (STRING_TYPE *) s;
+
+#if !UNSIGNED
+ /* Check for a value that is within the range of
+ `unsigned LONG int', but outside the range of `LONG int'. */
+ if (overflow == 0
+ && i > (negative
+ ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
+ : (unsigned LONG int) STRTOL_LONG_MAX))
+ overflow = 1;
+#endif
+
+ if (overflow)
+ {
+ __set_errno (ERANGE);
+#if UNSIGNED
+ return STRTOL_ULONG_MAX;
+#else
+ return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
+#endif
+ }
+
+ /* Return the result of the appropriate sign. */
+ return negative ? -i : i;
+
+noconv:
+ /* We must handle a special case here: the base is 0 or 16 and the
+ first two characters are '0' and 'x', but the rest are no
+ hexadecimal digits. This is no error case. We return 0 and
+ ENDPTR points to the `x`. */
+ if (endptr != NULL)
+ {
+ if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
+ && save[-2] == L_('0'))
+ *endptr = (STRING_TYPE *) &save[-1];
+ else
+ /* There was no number to convert. */
+ *endptr = (STRING_TYPE *) nptr;
+ }
+
+ return 0L;
+}
+
+/* External user entry point. */
+
+
+INT
+#ifdef weak_function
+weak_function
+#endif
+strtol (const STRING_TYPE *nptr, STRING_TYPE **endptr,
+ int base LOCALE_PARAM_PROTO)
+{
+ return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
+}
diff --git a/lib/strtoul.c b/lib/strtoul.c
new file mode 100644
index 0000000..79ceed2
--- /dev/null
+++ b/lib/strtoul.c
@@ -0,0 +1,20 @@
+/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#define UNSIGNED 1
+
+#include "strtol.c"
diff --git a/lib/sunos57-select.c b/lib/sunos57-select.c
new file mode 100644
index 0000000..9ee5b6f
--- /dev/null
+++ b/lib/sunos57-select.c
@@ -0,0 +1,225 @@
+/* Work around the bug in Solaris 7 whereby a fd that is opened on
+ /dev/null will cause select/poll to hang when given a NULL timeout.
+
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* written by Mark D. Baushke */
+
+/*
+ * Observed on Solaris 7:
+ * If /dev/null is in the readfds set, it will never be marked as
+ * ready by the OS. In the case of a /dev/null fd being the only fd
+ * in the select set and timeout == NULL, the select will hang.
+ * If /dev/null is in the exceptfds set, it will not be set on
+ * return from select().
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+/* The rpl_select function calls the real select. */
+#undef select
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "minmax.h"
+#include "xtime.h"
+
+static struct stat devnull;
+static int devnull_set = -1;
+int
+rpl_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ int ret = 0;
+
+ /* Argument checking */
+ if (nfds < 1 || nfds > FD_SETSIZE)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Perform the initial stat on /dev/null */
+ if (devnull_set == -1)
+ devnull_set = stat ("/dev/null", &devnull);
+
+ if (devnull_set >= 0)
+ {
+ int fd;
+ int maxfd = -1;
+ fd_set null_rfds, null_wfds;
+ bool altered = false; /* Whether we have altered the caller's args.
+ */
+
+ FD_ZERO (&null_rfds);
+ FD_ZERO (&null_wfds);
+
+ for (fd = 0; fd < nfds; fd++)
+ {
+ /* Check the callers bits for interesting fds */
+ bool isread = (readfds && FD_ISSET (fd, readfds));
+ bool isexcept = (exceptfds && FD_ISSET (fd, exceptfds));
+ bool iswrite = (writefds && FD_ISSET (fd, writefds));
+
+ /* Check interesting fds against /dev/null */
+ if (isread || iswrite || isexcept)
+ {
+ struct stat sb;
+
+ /* Equivalent to /dev/null ? */
+ if (fstat (fd, &sb) >= 0
+ && sb.st_dev == devnull.st_dev
+ && sb.st_ino == devnull.st_ino
+ && sb.st_mode == devnull.st_mode
+ && sb.st_uid == devnull.st_uid
+ && sb.st_gid == devnull.st_gid
+ && sb.st_size == devnull.st_size
+ && sb.st_blocks == devnull.st_blocks
+ && sb.st_blksize == devnull.st_blksize)
+ {
+ /* Save the interesting bits for later use. */
+ if (isread)
+ {
+ FD_SET (fd, &null_rfds);
+ FD_CLR (fd, readfds);
+ altered = true;
+ }
+ if (isexcept)
+ /* Pass exception bits through.
+ *
+ * At the moment, we only know that this bug
+ * exists in Solaris 7 and so this file should
+ * only be compiled on Solaris 7. Since Solaris 7
+ * never returns ready for exceptions on
+ * /dev/null, we probably could assume this too,
+ * but since Solaris 9 is known to always return
+ * ready for exceptions on /dev/null, pass this
+ * through in case any other systems turn out to
+ * do the same. Besides, this will cause the
+ * timeout to be processed as it would have been
+ * otherwise.
+ */
+ maxfd = MAX (maxfd, fd);
+ if (iswrite)
+ {
+ /* We know of no bugs involving selecting /dev/null
+ * writefds, but we also know that /dev/null is always
+ * ready for write. Therefore, since we have already
+ * performed all the necessary processing, avoid calling
+ * the system select for this case.
+ */
+ FD_SET (fd, &null_wfds);
+ FD_CLR (fd, writefds);
+ altered = true;
+ }
+ }
+ else
+ /* A non-/dev/null fd is present. */
+ maxfd = MAX (maxfd, fd);
+ }
+ }
+
+ if (maxfd >= 0)
+ {
+ /* we need to call select, one way or another. */
+ if (altered)
+ {
+ /* We already have some ready bits set, so timeout immediately
+ * if no bits are set.
+ */
+ struct timeval ztime;
+ ztime.tv_sec = 0;
+ ztime.tv_usec = 0;
+ ret = select (maxfd + 1, readfds, writefds, exceptfds, &ztime);
+ if (ret == 0)
+ {
+ /* Timeout. Zero the sets since the system select might
+ * not have.
+ */
+ if (readfds)
+ FD_ZERO (readfds);
+ if (exceptfds)
+ FD_ZERO (exceptfds);
+ if (writefds)
+ FD_ZERO (writefds);
+ }
+ }
+ else
+ /* No /dev/null fds. Call select just as the user specified. */
+ ret = select (maxfd + 1, readfds, writefds, exceptfds, timeout);
+ }
+
+ /*
+ * Borrowed from the Solaris 7 man page for select(3c):
+ *
+ * On successful completion, the objects pointed to by the
+ * readfds, writefds, and exceptfds arguments are modified to
+ * indicate which file descriptors are ready for reading,
+ * ready for writing, or have an error condition pending,
+ * respectively. For each file descriptor less than nfds, the
+ * corresponding bit will be set on successful completion if
+ * it was set on input and the associated condition is true
+ * for that file descriptor.
+ *
+ * On failure, the objects pointed to by the readfds,
+ * writefds, and exceptfds arguments are not modified. If the
+ * timeout interval expires without the specified condition
+ * being true for any of the specified file descriptors, the
+ * objects pointed to by the readfs, writefs, and errorfds
+ * arguments have all bits set to 0.
+ *
+ * On successful completion, select() returns the total number
+ * of bits set in the bit masks. Otherwise, -1 is returned,
+ * and errno is set to indicate the error.
+ */
+
+ /* Fix up the fd sets for any changes we may have made. */
+ if (altered)
+ {
+ /* Tell the caller that nothing is blocking the /dev/null fds */
+ for (fd = 0; fd < nfds; fd++)
+ {
+ /* If ret < 0, then we still need to restore the fd sets. */
+ if (FD_ISSET (fd, &null_rfds))
+ {
+ FD_SET (fd, readfds);
+ if (ret >= 0)
+ ret++;
+ }
+ if (FD_ISSET (fd, &null_wfds))
+ {
+ FD_SET (fd, writefds);
+ if (ret >= 0)
+ ret++;
+ }
+ }
+ }
+ }
+ else
+ ret = select (nfds, readfds, writefds, exceptfds, timeout);
+
+ return ret;
+}
diff --git a/lib/system.h b/lib/system.h
new file mode 100644
index 0000000..8ea4a95
--- /dev/null
+++ b/lib/system.h
@@ -0,0 +1,349 @@
+/* system-dependent definitions for CVS.
+ Copyright (C) 1989-1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/***
+ *** Begin the default set of autoconf includes.
+ ***/
+
+/* Headers assumed for C89 freestanding compilers. See HACKING for more. */
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+/* C89 hosted headers assumed since they were included in UNIX version 7.
+ * See HACKING for more.
+ */
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+
+/* C89 hosted headers we _think_ GCC supplies even on freestanding systems.
+ * If we find any systems which do not have them, a replacement header should
+ * be discussed with the GNULIB folks.
+ *
+ * For more information, please see the `Portability' section of the `HACKING'
+ * file.
+ */
+#include <stdlib.h>
+#include <string.h>
+
+/* We assume this because it has been around forever despite not being a part
+ * of any of the other standards we assume conformance to. So far this hasn't
+ * been a problem.
+ *
+ * For more information, please see the `Portability' section of the `HACKING'
+ * file.
+ */
+#include <sys/types.h>
+
+/* A GNULIB replacement for this C99 header is supplied when it is missing.
+ * See the comments in stdbool_.h for its limitations.
+ */
+#include <stdbool.h>
+
+/* Ditto for these POSIX.2 headers. */
+#include <fnmatch.h>
+#include <getopt.h> /* Has GNU extensions, */
+
+/* We assume <sys/stat.h> because GNULIB does. */
+#include <sys/stat.h>
+
+#if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+#endif /* !STDC_HEADERS && HAVE_MEMORY_H */
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else /* ! HAVE_INTTYPES_H */
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif /* HAVE_STDINT_H */
+#endif /* HAVE_INTTYPES_H */
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+/* End the default set of autoconf includes */
+
+/* Assume these headers. */
+#include <pwd.h>
+
+/* There is a replacement stub for gettext provided by GNULIB when gettext is
+ * not available.
+ */
+#include <gettext.h>
+
+#ifndef DEVNULL
+# define DEVNULL "/dev/null"
+#endif
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#endif
+
+/* The NeXT (without _POSIX_SOURCE, which we don't want) has a utime.h
+ which doesn't define anything. It would be cleaner to have configure
+ check for struct utimbuf, but for now I'm checking NeXT here (so I don't
+ have to debug the configure check across all the machines). */
+#if defined (HAVE_UTIME_H) && !defined (NeXT)
+# include <utime.h>
+#else
+# if defined (HAVE_SYS_UTIME_H)
+# include <sys/utime.h>
+# else
+# ifndef ALTOS
+struct utimbuf
+{
+ long actime;
+ long modtime;
+};
+# endif
+int utime ();
+# endif
+#endif
+
+/* errno.h variations:
+ *
+ * Not all systems set the same error code on a non-existent-file
+ * error. This tries to ask the question somewhat portably.
+ * On systems that don't have ENOTEXIST, this should behave just like
+ * x == ENOENT. "x" is probably errno, of course.
+ */
+#ifdef ENOTEXIST
+# ifdef EOS2ERR
+# define existence_error(x) \
+ (((x) == ENOTEXIST) || ((x) == ENOENT) || ((x) == EOS2ERR))
+# else
+# define existence_error(x) \
+ (((x) == ENOTEXIST) || ((x) == ENOENT))
+# endif
+#else
+# ifdef EVMSERR
+# define existence_error(x) \
+((x) == ENOENT || (x) == EINVAL || (x) == EVMSERR)
+# else
+# define existence_error(x) ((x) == ENOENT)
+# endif
+#endif
+
+/* check for POSIX signals */
+#if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK)
+# define POSIX_SIGNALS
+#endif
+
+/* MINIX 1.6 doesn't properly support sigaction */
+#if defined(_MINIX)
+# undef POSIX_SIGNALS
+#endif
+
+/* If !POSIX, try for BSD.. Reason: 4.4BSD implements these as wrappers */
+#if !defined(POSIX_SIGNALS)
+# if defined(HAVE_SIGVEC) && defined(HAVE_SIGSETMASK) && defined(HAVE_SIGBLOCK)
+# define BSD_SIGNALS
+# endif
+#endif
+
+/* Under OS/2, this must be included _after_ stdio.h; that's why we do
+ it here. */
+#ifdef USE_OWN_TCPIP_H
+# include "tcpip.h"
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# include <sys/file.h>
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+#endif
+
+#ifndef F_OK
+# define F_OK 0
+# define X_OK 1
+# define W_OK 2
+# define R_OK 4
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+/* Convert B 512-byte blocks to kilobytes if K is nonzero,
+ otherwise return it unchanged. */
+#define convert_blocks(b, k) ((k) ? ((b) + 1) / 2 : (b))
+
+/* Under non-UNIX operating systems (MS-DOS, WinNT, MacOS), many filesystem
+ calls take only one argument; permission is handled very differently on
+ those systems than in Unix. So we leave such systems a hook on which they
+ can hang their own definitions. */
+
+#ifndef CVS_ACCESS
+# define CVS_ACCESS access
+#endif
+
+#ifndef CVS_CHDIR
+# define CVS_CHDIR chdir
+#endif
+
+#ifndef CVS_CREAT
+# define CVS_CREAT creat
+#endif
+
+#ifndef CVS_FOPEN
+# define CVS_FOPEN fopen
+#endif
+
+#ifndef CVS_FDOPEN
+# define CVS_FDOPEN fdopen
+#endif
+
+#ifndef CVS_MKDIR
+# define CVS_MKDIR mkdir
+#endif
+
+#ifndef CVS_OPEN
+# define CVS_OPEN open
+#endif
+
+#ifndef CVS_READDIR
+# define CVS_READDIR readdir
+#endif
+
+#ifndef CVS_CLOSEDIR
+# define CVS_CLOSEDIR closedir
+#endif
+
+#ifndef CVS_OPENDIR
+# define CVS_OPENDIR opendir
+#endif
+
+#ifndef CVS_RENAME
+# define CVS_RENAME rename
+#endif
+
+#ifndef CVS_RMDIR
+# define CVS_RMDIR rmdir
+#endif
+
+#ifndef CVS_UNLINK
+# define CVS_UNLINK unlink
+#endif
+
+/* Wildcard matcher. Should be case-insensitive if the system is. */
+#ifndef CVS_FNMATCH
+# define CVS_FNMATCH fnmatch
+#endif
+
+#ifndef HAVE_FSEEKO
+off_t ftello (FILE *);
+int fseeko (FILE *, off_t, int);
+#endif /* HAVE_FSEEKO */
+
+#ifdef FILENAMES_CASE_INSENSITIVE
+
+# if defined (__CYGWIN32__) || defined (WOE32)
+ /* Under Windows, filenames are case-insensitive, and both / and \
+ are path component separators. */
+# define FOLD_FN_CHAR(c) (WNT_filename_classes[(unsigned char) (c)])
+extern unsigned char WNT_filename_classes[];
+# else /* !__CYGWIN32__ && !WOE32 */
+ /* As far as I know, only Macintosh OS X & VMS make it here, but any
+ * platform defining FILENAMES_CASE_INSENSITIVE which isn't WOE32 or
+ * piggy-backing the same could, in theory. Since the OS X fold just folds
+ * A-Z into a-z, I'm just allowing it to be used for any case insensitive
+ * system which we aren't yet making other specific folds or exceptions for.
+ * WOE32 needs its own class since \ and C:\ style absolute paths also need
+ * to be accounted for.
+ */
+# define FOLD_FN_CHAR(c) (OSX_filename_classes[(unsigned char) (c)])
+extern unsigned char OSX_filename_classes[];
+# endif /* __CYGWIN32__ || WOE32 */
+
+/* The following need to be declared for all case insensitive filesystems.
+ * When not FOLD_FN_CHAR is not #defined, a default definition for these
+ * functions is provided later in this header file. */
+
+/* Like strcmp, but with the appropriate tweaks for file names. */
+extern int fncmp (const char *n1, const char *n2);
+
+/* Fold characters in FILENAME to their canonical forms. */
+extern void fnfold (char *FILENAME);
+
+#endif /* FILENAMES_CASE_INSENSITIVE */
+
+
+
+/* Some file systems are case-insensitive. If FOLD_FN_CHAR is
+ #defined, it maps the character C onto its "canonical" form. In a
+ case-insensitive system, it would map all alphanumeric characters
+ to lower case. Under Windows NT, / and \ are both path component
+ separators, so FOLD_FN_CHAR would map them both to /. */
+#ifndef FOLD_FN_CHAR
+# define FOLD_FN_CHAR(c) (c)
+# define fnfold(filename) (filename)
+# define fncmp strcmp
+#endif
+
+/* Different file systems can have different naming patterns which designate
+ * a path as absolute.
+ */
+#ifndef ISABSOLUTE
+# define ISABSOLUTE(s) ISSLASH(s[FILE_SYSTEM_PREFIX_LEN(s)])
+#endif
+
+
+/* On some systems, we have to be careful about writing/reading files
+ in text or binary mode (so in text mode the system can handle CRLF
+ vs. LF, VMS text file conventions, &c). We decide to just always
+ be careful. That way we don't have to worry about whether text and
+ binary differ on this system. We just have to worry about whether
+ the system has O_BINARY and "rb". The latter is easy; all ANSI C
+ libraries have it, SunOS4 has it, and CVS has used it unguarded
+ some places for a while now without complaints (e.g. "rb" in
+ server.c (server_updated), since CVS 1.8). The former is just an
+ #ifdef. */
+
+#define FOPEN_BINARY_READ ("rb")
+#define FOPEN_BINARY_WRITE ("wb")
+#define FOPEN_BINARY_READWRITE ("r+b")
+
+#ifdef O_BINARY
+#define OPEN_BINARY (O_BINARY)
+#else
+#define OPEN_BINARY (0)
+#endif
+
+#ifndef fd_select
+# define fd_select select
+#endif
diff --git a/lib/tempname.c b/lib/tempname.c
new file mode 100644
index 0000000..cae42e1
--- /dev/null
+++ b/lib/tempname.c
@@ -0,0 +1,319 @@
+/* tempname.c - generate the name of a temporary file.
+
+ Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <assert.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#include <stdio.h>
+#ifndef P_tmpdir
+# define P_tmpdir "/tmp"
+#endif
+#ifndef TMP_MAX
+# define TMP_MAX 238328
+#endif
+#ifndef __GT_FILE
+# define __GT_FILE 0
+# define __GT_BIGFILE 1
+# define __GT_DIR 2
+# define __GT_NOCREATE 3
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+
+#if HAVE_SYS_TIME_H || _LIBC
+# include <sys/time.h>
+#endif
+
+#if HAVE_STDINT_H || _LIBC
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#if HAVE_UNISTD_H || _LIBC
+# include <unistd.h>
+#endif
+
+#include <sys/stat.h>
+
+#if _LIBC
+# define struct_stat64 struct stat64
+#else
+# include "stat-macros.h"
+# define struct_stat64 struct stat
+# define __getpid getpid
+# define __gettimeofday gettimeofday
+# define __mkdir mkdir
+# define __open open
+# define __open64 open
+# define __lxstat64(version, file, buf) lstat (file, buf)
+# define __xstat64(version, file, buf) stat (file, buf)
+#endif
+
+#if ! (HAVE___SECURE_GETENV || _LIBC)
+# define __secure_getenv getenv
+#endif
+
+#ifdef _LIBC
+# include <hp-timing.h>
+# if HP_TIMING_AVAIL
+# define RANDOM_BITS(Var) \
+ if (__builtin_expect (value == UINT64_C (0), 0)) \
+ { \
+ /* If this is the first time this function is used initialize \
+ the variable we accumulate the value in to some somewhat \
+ random value. If we'd not do this programs at startup time \
+ might have a reduced set of possible names, at least on slow \
+ machines. */ \
+ struct timeval tv; \
+ __gettimeofday (&tv, NULL); \
+ value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \
+ } \
+ HP_TIMING_NOW (Var)
+# endif
+#endif
+
+/* Use the widest available unsigned type if uint64_t is not
+ available. The algorithm below extracts a number less than 62**6
+ (approximately 2**35.725) from uint64_t, so ancient hosts where
+ uintmax_t is only 32 bits lose about 3.725 bits of randomness,
+ which is better than not having mkstemp at all. */
+#if !defined UINT64_MAX && !defined uint64_t
+# define uint64_t uintmax_t
+#endif
+
+/* Return nonzero if DIR is an existent directory. */
+static int
+direxists (const char *dir)
+{
+ struct_stat64 buf;
+ return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
+}
+
+/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is
+ non-null and exists, uses it; otherwise uses the first of $TMPDIR,
+ P_tmpdir, /tmp that exists. Copies into TMPL a template suitable
+ for use with mk[s]temp. Will fail (-1) if DIR is non-null and
+ doesn't exist, none of the searched dirs exists, or there's not
+ enough space in TMPL. */
+int
+__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
+ int try_tmpdir)
+{
+ const char *d;
+ size_t dlen, plen;
+
+ if (!pfx || !pfx[0])
+ {
+ pfx = "file";
+ plen = 4;
+ }
+ else
+ {
+ plen = strlen (pfx);
+ if (plen > 5)
+ plen = 5;
+ }
+
+ if (try_tmpdir)
+ {
+ d = __secure_getenv ("TMPDIR");
+ if (d != NULL && direxists (d))
+ dir = d;
+ else if (dir != NULL && direxists (dir))
+ /* nothing */ ;
+ else
+ dir = NULL;
+ }
+ if (dir == NULL)
+ {
+ if (direxists (P_tmpdir))
+ dir = P_tmpdir;
+ else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
+ dir = "/tmp";
+ else
+ {
+ __set_errno (ENOENT);
+ return -1;
+ }
+ }
+
+ dlen = strlen (dir);
+ while (dlen > 1 && dir[dlen - 1] == '/')
+ dlen--; /* remove trailing slashes */
+
+ /* check we have room for "${dir}/${pfx}XXXXXX\0" */
+ if (tmpl_len < dlen + 1 + plen + 6 + 1)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
+ return 0;
+}
+
+/* These are the characters used in temporary file names. */
+static const char letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary file name based on TMPL. TMPL must match the
+ rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
+ does not exist at the time of the call to __gen_tempname. TMPL is
+ overwritten with the result.
+
+ KIND may be one of:
+ __GT_NOCREATE: simply verify that the name does not exist
+ at the time of the call.
+ __GT_FILE: create the file using open(O_CREAT|O_EXCL)
+ and return a read-write fd. The file is mode 0600.
+ __GT_BIGFILE: same as __GT_FILE but use open64().
+ __GT_DIR: create a directory, which will be mode 0700.
+
+ We use a clever algorithm to get hard-to-predict names. */
+int
+__gen_tempname (char *tmpl, int kind)
+{
+ int len;
+ char *XXXXXX;
+ static uint64_t value;
+ uint64_t random_time_bits;
+ unsigned int count;
+ int fd = -1;
+ int save_errno = errno;
+ struct_stat64 st;
+
+ /* A lower bound on the number of temporary files to attempt to
+ generate. The maximum total number of temporary file names that
+ can exist for a given template is 62**6. It should never be
+ necessary to try all these combinations. Instead if a reasonable
+ number of names is tried (we define reasonable as 62**3) fail to
+ give the system administrator the chance to remove the problems. */
+ unsigned int attempts_min = 62 * 62 * 62;
+
+ /* The number of times to attempt to generate a temporary file. To
+ conform to POSIX, this must be no smaller than TMP_MAX. */
+ unsigned int attempts = attempts_min < TMP_MAX ? TMP_MAX : attempts_min;
+
+ len = strlen (tmpl);
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* This is where the Xs start. */
+ XXXXXX = &tmpl[len - 6];
+
+ /* Get some more or less random data. */
+#ifdef RANDOM_BITS
+ RANDOM_BITS (random_time_bits);
+#else
+# if HAVE_GETTIMEOFDAY || _LIBC
+ {
+ struct timeval tv;
+ __gettimeofday (&tv, NULL);
+ random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
+ }
+# else
+ random_time_bits = time (NULL);
+# endif
+#endif
+ value += random_time_bits ^ __getpid ();
+
+ for (count = 0; count < attempts; value += 7777, ++count)
+ {
+ uint64_t v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ switch (kind)
+ {
+ case __GT_FILE:
+ fd = __open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ break;
+
+ case __GT_BIGFILE:
+ fd = __open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ break;
+
+ case __GT_DIR:
+ fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+ break;
+
+ case __GT_NOCREATE:
+ /* This case is backward from the other three. __gen_tempname
+ succeeds if __xstat fails because the name does not exist.
+ Note the continue to bypass the common logic at the bottom
+ of the loop. */
+ if (__lxstat64 (_STAT_VER, tmpl, &st) < 0)
+ {
+ if (errno == ENOENT)
+ {
+ __set_errno (save_errno);
+ return 0;
+ }
+ else
+ /* Give up now. */
+ return -1;
+ }
+ continue;
+
+ default:
+ assert (! "invalid KIND in __gen_tempname");
+ }
+
+ if (fd >= 0)
+ {
+ __set_errno (save_errno);
+ return fd;
+ }
+ else if (errno != EEXIST)
+ return -1;
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ __set_errno (EEXIST);
+ return -1;
+}
diff --git a/lib/test-getdate.sh b/lib/test-getdate.sh
new file mode 100755
index 0000000..128def2
--- /dev/null
+++ b/lib/test-getdate.sh
@@ -0,0 +1,340 @@
+#! /bin/sh
+
+# Test that a getdate executable meets its specification.
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+
+###
+### Globals
+###
+LOGFILE=`pwd`/getdate.log
+if test -f "$LOGFILE"; then
+ mv $LOGFILE $LOGFILE~
+fi
+
+
+
+###
+### Functions
+###
+verify ()
+{
+ echo >>getdate-got
+ if cmp getdate-expected getdate-got >getdate.cmp; then
+ echo "PASS: $1" >>$LOGFILE
+ else
+ cat getdate.cmp >>$LOGFILE
+ echo "** expected: " >>$LOGFILE
+ cat getdate-expected >>$LOGFILE
+ echo "** got: " >>$LOGFILE
+ cat getdate-got >>$LOGFILE
+ echo "FAIL: $1" | tee -a $LOGFILE >&2
+ echo "Failed! See $LOGFILE for more!" >&2
+ exit 1
+ fi
+}
+
+
+
+skip ()
+{
+ echo "SKIP: $1"${2+" ($2)"} >>$LOGFILE
+}
+
+
+
+# Prep for future calls to valid_timezone().
+#
+# This should set $UTZ to three spaces, `GMT', `Unrecognized/Unrecognized', or
+# possibly the empty string, depending on what system we are running on. With
+# any luck, this will catch any other existing variations as well. The way it
+# is used later does have the disadvantage of rejecting at least the
+# `Europe/London' timezone for half the year when $UTZ gets set to `GMT', like
+# happens on NetBSD, but, since I haven't come up with any better ideas and
+# since rejecting a timezone just causes a few tests to be skipped, this will
+# have to do for now.
+#
+# UTZ stands for Unrecognized Time Zone.
+UTZ=`TZ=Unrecognized/Unrecognized date +%Z`
+
+# The following function will return true if $1 is a valid timezone. It will
+# return false and set $skipreason, otherwise.
+#
+# Clobbers $NTZ & $skipreason.
+#
+# SUS2 says `date +%Z' will return `no characters' if `no timezone is
+# determinable'. It is, unfortunately, not very specific about what
+# `determinable' means. On GNU/Linux, `date +%Z' returns $TZ when $TZ is not
+# recognized. NetBSD 1.6.1 "determines" that an unrecognizable value in $TZ
+# really means `GMT'. On Cray, the standard is ignored and `date +%Z' returns
+# three spaces when $TZ is not recognized. We test for all three cases, plus
+# the empty string for good measure, though I know of no set of conditions
+# which will actually cause `date +%Z' to return the empty string SUS2
+# specifies.
+#
+# Due to the current nature of this test, this will not work for the
+# three-letter zone codes on some systems. e.g.:
+#
+# test `TZ=EST date +%Z` = "EST"
+#
+# should, quite correctly, evaluate to true on most systems, but:
+#
+# TZ=Asia/Calcutta date +%Z
+#
+# would return `IST' on GNU/Linux, and hopefully any system which understands
+# the `Asia/Calcutta' timezone, and ` ' on Cray. Similarly:
+#
+# TZ=Doesnt_Exist/Doesnt_Exist date +%Z
+#
+# returns `Doesnt_Exist/Doesnt_Exist' on GNU/Linux and ` ' on Cray.
+#
+# Unfortunately, the %z date format string (-HHMM format time zone) supported
+# by the GNU `date' command is not part of any standard I know of and,
+# therefore, is probably not portable.
+#
+valid_timezone ()
+{
+ NTZ=`TZ=$1 date +%Z`
+ if test "$NTZ" = "$UTZ" || test "$NTZ" = "$1"; then
+ skipreason="$1 is not a recognized timezone on this system"
+ return `false`
+ else
+ return `:`
+ fi
+}
+
+
+
+###
+### Tests
+###
+
+# Why are these dates tested?
+#
+# February 29, 2003
+# Is not a leap year - should be invalid.
+#
+# 2004-12-40
+# Make sure get_date does not "roll" date forward to January 9th. Some
+# versions have been known to do this.
+#
+# Dec-5-1972
+# This is my birthday. :)
+#
+# 3/29/1974
+# 1996/05/12 13:57:45
+# Because.
+#
+# 12-05-12
+# This will be my 40th birthday. Ouch. :)
+#
+# 05/12/96
+# Because.
+#
+# third tuesday in March, 2078
+# Wanted this to work.
+#
+# 1969-12-32 2:00:00 UTC
+# 1970-01-01 2:00:00 UTC
+# 1969-12-32 2:00:00 +0400
+# 1970-01-01 2:00:00 +0400
+# 1969-12-32 2:00:00 -0400
+# 1970-01-01 2:00:00 -0400
+# Playing near the UNIX Epoch boundry condition to make sure date rolling
+# is also disabled there.
+#
+# 1996-12-12 1 month
+# Test a relative date.
+
+
+
+# The following tests are currently being skipped for being unportable:
+#
+# Tue Jan 19 03:14:07 2038 +0000
+# For machines with 31-bit time_t, any date past this date will be an
+# invalid date. So, any test date with a value greater than this
+# time is not portable.
+#
+# Feb. 29, 2096 4 years
+# 4 years from this date is _not_ a leap year, so Feb. 29th does not exist.
+#
+# Feb. 29, 2096 8 years
+# 8 years from this date is a leap year, so Feb. 29th does exist,
+# but on many hosts with 32-bit time_t types time, this test will
+# fail. So, this is not a portable test.
+#
+
+TZ=UTC0; export TZ
+
+cat >getdate-expected <<EOF
+Enter date, or blank line to exit.
+ > Bad format - couldn't convert.
+ > Bad format - couldn't convert.
+ > 1972-12-05 00:00:00.000000000
+ > 1974-03-29 00:00:00.000000000
+ > 1996-05-12 13:57:45.000000000
+ > 2012-05-12 00:00:00.000000000
+ > 1996-05-12 00:00:00.000000000
+ > Bad format - couldn't convert.
+ > Bad format - couldn't convert.
+ > 1970-01-01 02:00:00.000000000
+ > Bad format - couldn't convert.
+ > 1969-12-31 22:00:00.000000000
+ > Bad format - couldn't convert.
+ > 1970-01-01 06:00:00.000000000
+ > 1997-01-12 00:00:00.000000000
+ >
+EOF
+
+./getdate >getdate-got <<EOF
+February 29, 2003
+2004-12-40
+Dec-5-1972
+3/29/1974
+1996/05/12 13:57:45
+12-05-12
+05/12/96
+third tuesday in March, 2078
+1969-12-32 2:00:00 UTC
+1970-01-01 2:00:00 UTC
+1969-12-32 2:00:00 +0400
+1970-01-01 2:00:00 +0400
+1969-12-32 2:00:00 -0400
+1970-01-01 2:00:00 -0400
+1996-12-12 1 month
+EOF
+
+verify getdate-1
+
+
+
+# Why are these dates tested?
+#
+# Ian Abbot reported these odd boundry cases. After daylight savings time went
+# into effect, non-daylight time zones would cause
+# "Bad format - couldn't convert." errors, even when the non-daylight zone
+# happened to be a universal one, like GMT.
+
+TZ=Europe/London; export TZ
+if valid_timezone $TZ; then
+ cat >getdate-expected <<EOF
+Enter date, or blank line to exit.
+ > 2005-03-01 00:00:00.000000000
+ > 2005-03-27 00:00:00.000000000
+ > 2005-03-28 01:00:00.000000000
+ > 2005-03-28 01:00:00.000000000
+ > 2005-03-29 01:00:00.000000000
+ > 2005-03-29 01:00:00.000000000
+ > 2005-03-30 01:00:00.000000000
+ > 2005-03-30 01:00:00.000000000
+ > 2005-03-31 01:00:00.000000000
+ > 2005-03-31 01:00:00.000000000
+ > 2005-04-01 01:00:00.000000000
+ > 2005-04-01 01:00:00.000000000
+ > 2005-04-10 01:00:00.000000000
+ > 2005-04-10 01:00:00.000000000
+ > 2005-04-01 00:00:00.000000000
+ >
+EOF
+
+ ./getdate >getdate-got <<EOF
+2005-3-1 GMT
+2005-3-27 GMT
+2005-3-28 GMT
+2005-3-28 UTC0
+2005-3-29 GMT
+2005-3-29 UTC0
+2005-3-30 GMT
+2005-3-30 UTC0
+2005-3-31 GMT
+2005-3-31 UTC0
+2005-4-1 GMT
+2005-4-1 UTC0
+2005-4-10 GMT
+2005-4-10 UTC0
+2005-4-1 BST
+EOF
+
+ verify getdate-2
+else
+ skip getdate-2 "$skipreason"
+fi
+
+
+
+# Many of the following cases were also submitted by Ian Abbott, but the same
+# errors are not exhibited. The original problem had a similar root, but
+# managed to produce errors with GMT, which is considered a "Universal Zone".
+# This was fixed.
+#
+# The deeper problem has to do with "local zone" processing in getdate.y
+# that causes local daylight zones to be excluded when local standard time is
+# in effect and vice versa. This used to cause trouble with GMT in Britian
+# when British Summer Time was in effect, but this was overridden for the
+# "Universal Timezones" (GMT, UTC, & UT), that might double as a local zone in
+# some locales. We still see in these tests the local daylight/standard zone
+# exclusion in EST/EDT. According to Paul Eggert in a message to
+# bug-gnulib@gnu.org on 2005-04-12, this is considered a bug but may not be
+# fixed soon due to its complexity.
+
+TZ=America/New_York; export TZ
+if valid_timezone $TZ; then
+ cat >getdate-expected <<EOF
+Enter date, or blank line to exit.
+ > 2005-03-01 00:00:00.000000000
+ > 2005-02-28 18:00:00.000000000
+ > 2005-04-01 00:00:00.000000000
+ > Bad format - couldn't convert.
+ > 2005-04-30 19:00:00.000000000
+ > 2005-04-30 20:00:00.000000000
+ > 2005-05-01 00:00:00.000000000
+ > 2005-04-30 20:00:00.000000000
+ > Bad format - couldn't convert.
+ > 2005-05-31 19:00:00.000000000
+ > 2005-05-31 20:00:00.000000000
+ > 2005-06-01 00:00:00.000000000
+ > 2005-05-31 20:00:00.000000000
+ >
+EOF
+
+ ./getdate >getdate-got <<EOF
+2005-3-1 EST
+2005-3-1 BST
+2005-4-1 EST
+2005-5-1 EST
+2005-5-1 BST
+2005-5-1 GMT
+2005-5-1 EDT
+2005-5-1 UTC0
+2005-6-1 EST
+2005-6-1 BST
+2005-6-1 GMT
+2005-6-1 EDT
+2005-6-1 UTC0
+EOF
+
+ verify getdate-3
+else
+ skip getdate-3 "$skipreason"
+fi
+
+
+
+rm getdate-expected getdate-got getdate.cmp
+exit 0
diff --git a/lib/time_r.c b/lib/time_r.c
new file mode 100644
index 0000000..245ac92
--- /dev/null
+++ b/lib/time_r.c
@@ -0,0 +1,69 @@
+/* Reentrant time functions like localtime_r.
+
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "time_r.h"
+
+#include <string.h>
+
+static char *
+copy_string_result (char *dest, char const *src)
+{
+ if (! src)
+ return 0;
+ return strcpy (dest, src);
+}
+
+static struct tm *
+copy_tm_result (struct tm *dest, struct tm const *src)
+{
+ if (! src)
+ return 0;
+ *dest = *src;
+ return dest;
+}
+
+
+char *
+asctime_r (struct tm const * restrict tm, char * restrict buf)
+{
+ return copy_string_result (buf, asctime (tm));
+}
+
+char *
+ctime_r (time_t const *t, char *buf)
+{
+ return copy_string_result (buf, ctime (t));
+}
+
+struct tm *
+gmtime_r (time_t const * restrict t, struct tm * restrict tp)
+{
+ return copy_tm_result (tp, gmtime (t));
+}
+
+struct tm *
+localtime_r (time_t const * restrict t, struct tm * restrict tp)
+{
+ return copy_tm_result (tp, localtime (t));
+}
diff --git a/lib/time_r.h b/lib/time_r.h
new file mode 100644
index 0000000..1f2e94a
--- /dev/null
+++ b/lib/time_r.h
@@ -0,0 +1,57 @@
+/* Reentrant time functions like localtime_r.
+
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#ifndef _TIME_R_H
+#define _TIME_R_H
+
+/* Include <time.h> first, since it may declare these functions with
+ signatures that disagree with POSIX, and we don't want to rename
+ those declarations. */
+#include <time.h>
+
+#if !HAVE_TIME_R_POSIX
+# undef asctime_r
+# undef ctime_r
+# undef gmtime_r
+# undef localtime_r
+
+# define asctime_r rpl_asctime_r
+# define ctime_r rpl_ctime_r
+# define gmtime_r rpl_gmtime_r
+# define localtime_r rpl_localtime_r
+
+/* See the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/asctime.html>. */
+char *asctime_r (struct tm const * restrict, char * restrict);
+
+/* See the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/ctime.html>. */
+char *ctime_r (time_t const *, char *);
+
+/* See the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/gmtime.html>. */
+struct tm *gmtime_r (time_t const * restrict, struct tm * restrict);
+
+/* See the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/localtime.html>. */
+struct tm *localtime_r (time_t const * restrict, struct tm * restrict);
+#endif
+
+#endif
diff --git a/lib/timespec.h b/lib/timespec.h
new file mode 100644
index 0000000..8188c20
--- /dev/null
+++ b/lib/timespec.h
@@ -0,0 +1,62 @@
+/* timespec -- System time interface
+
+ Copyright (C) 2000, 2002, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#if ! defined TIMESPEC_H
+# define TIMESPEC_H
+
+# include <sys/types.h>
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+# if ! HAVE_STRUCT_TIMESPEC
+/* Some systems don't define this struct, e.g., AIX 4.1, Ultrix 4.3. */
+struct timespec
+{
+ time_t tv_sec;
+ long tv_nsec;
+};
+# endif
+
+/* Return negative, zero, positive if A < B, A == B, A > B, respectively.
+ Assume the nanosecond components are in range, or close to it. */
+static inline int
+timespec_cmp (struct timespec a, struct timespec b)
+{
+ return (a.tv_sec < b.tv_sec ? -1
+ : a.tv_sec > b.tv_sec ? 1
+ : a.tv_nsec - b.tv_nsec);
+}
+
+# if ! HAVE_DECL_NANOSLEEP
+/* Don't specify a prototype here. Some systems (e.g., OSF) declare
+ nanosleep with a conflicting one (const-less first parameter). */
+int nanosleep ();
+# endif
+
+void gettime (struct timespec *);
+int settime (struct timespec const *);
+
+#endif
diff --git a/lib/unistd--.h b/lib/unistd--.h
new file mode 100644
index 0000000..1fe6ce8
--- /dev/null
+++ b/lib/unistd--.h
@@ -0,0 +1,28 @@
+/* Like unistd.h, but redefine some names to avoid glitches.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#include <unistd.h>
+#include "unistd-safer.h"
+
+#undef dup
+#define dup dup_safer
+
+#undef pipe
+#define pipe pipe_safer
diff --git a/lib/unistd-safer.h b/lib/unistd-safer.h
new file mode 100644
index 0000000..f95999d
--- /dev/null
+++ b/lib/unistd-safer.h
@@ -0,0 +1,23 @@
+/* Invoke unistd-like functions, but avoid some glitches.
+
+ Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+int dup_safer (int);
+int fd_safer (int);
+int pipe_safer (int[2]);
diff --git a/lib/unlocked-io.h b/lib/unlocked-io.h
new file mode 100644
index 0000000..d009303
--- /dev/null
+++ b/lib/unlocked-io.h
@@ -0,0 +1,137 @@
+/* Prefer faster, non-thread-safe stdio functions if available.
+
+ Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#ifndef UNLOCKED_IO_H
+# define UNLOCKED_IO_H 1
+
+/* These are wrappers for functions/macros from the GNU C library, and
+ from other C libraries supporting POSIX's optional thread-safe functions.
+
+ The standard I/O functions are thread-safe. These *_unlocked ones are
+ more efficient but not thread-safe. That they're not thread-safe is
+ fine since all of the applications in this package are single threaded.
+
+ Also, some code that is shared with the GNU C library may invoke
+ the *_unlocked functions directly. On hosts that lack those
+ functions, invoke the non-thread-safe versions instead. */
+
+# include <stdio.h>
+
+# if HAVE_DECL_CLEARERR_UNLOCKED
+# undef clearerr
+# define clearerr(x) clearerr_unlocked (x)
+# else
+# define clearerr_unlocked(x) clearerr (x)
+# endif
+
+# if HAVE_DECL_FEOF_UNLOCKED
+# undef feof
+# define feof(x) feof_unlocked (x)
+# else
+# define feof_unlocked(x) feof (x)
+# endif
+
+# if HAVE_DECL_FERROR_UNLOCKED
+# undef ferror
+# define ferror(x) ferror_unlocked (x)
+# else
+# define ferror_unlocked(x) ferror (x)
+# endif
+
+# if HAVE_DECL_FFLUSH_UNLOCKED
+# undef fflush
+# define fflush(x) fflush_unlocked (x)
+# else
+# define fflush_unlocked(x) fflush (x)
+# endif
+
+# if HAVE_DECL_FGETS_UNLOCKED
+# undef fgets
+# define fgets(x,y,z) fgets_unlocked (x,y,z)
+# else
+# define fgets_unlocked(x,y,z) fgets (x,y,z)
+# endif
+
+# if HAVE_DECL_FPUTC_UNLOCKED
+# undef fputc
+# define fputc(x,y) fputc_unlocked (x,y)
+# else
+# define fputc_unlocked(x,y) fputc (x,y)
+# endif
+
+# if HAVE_DECL_FPUTS_UNLOCKED
+# undef fputs
+# define fputs(x,y) fputs_unlocked (x,y)
+# else
+# define fputs_unlocked(x,y) fputs (x,y)
+# endif
+
+# if HAVE_DECL_FREAD_UNLOCKED
+# undef fread
+# define fread(w,x,y,z) fread_unlocked (w,x,y,z)
+# else
+# define fread_unlocked(w,x,y,z) fread (w,x,y,z)
+# endif
+
+# if HAVE_DECL_FWRITE_UNLOCKED
+# undef fwrite
+# define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z)
+# else
+# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z)
+# endif
+
+# if HAVE_DECL_GETC_UNLOCKED
+# undef getc
+# define getc(x) getc_unlocked (x)
+# else
+# define getc_unlocked(x) getc (x)
+# endif
+
+# if HAVE_DECL_GETCHAR_UNLOCKED
+# undef getchar
+# define getchar() getchar_unlocked ()
+# else
+# define getchar_unlocked() getchar ()
+# endif
+
+# if HAVE_DECL_PUTC_UNLOCKED
+# undef putc
+# define putc(x,y) putc_unlocked (x,y)
+# else
+# define putc_unlocked(x,y) putc (x,y)
+# endif
+
+# if HAVE_DECL_PUTCHAR_UNLOCKED
+# undef putchar
+# define putchar(x) putchar_unlocked (x)
+# else
+# define putchar_unlocked(x) putchar (x)
+# endif
+
+# undef flockfile
+# define flockfile(x) ((void) 0)
+
+# undef ftrylockfile
+# define ftrylockfile(x) 0
+
+# undef funlockfile
+# define funlockfile(x) ((void) 0)
+
+#endif /* UNLOCKED_IO_H */
diff --git a/lib/unsetenv.c b/lib/unsetenv.c
new file mode 100644
index 0000000..4b53fc9
--- /dev/null
+++ b/lib/unsetenv.c
@@ -0,0 +1,99 @@
+/* Copyright (C) 1992,1995-1999,2000-2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#if !_LIBC
+# if !defined errno && !defined HAVE_ERRNO_DECL
+extern int errno;
+# endif
+# define __set_errno(ev) ((errno) = (ev))
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#if _LIBC || HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !_LIBC
+# define __environ environ
+# ifndef HAVE_ENVIRON_DECL
+extern char **environ;
+# endif
+#endif
+
+#if _LIBC
+/* This lock protects against simultaneous modifications of `environ'. */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK __libc_lock_lock (envlock)
+# define UNLOCK __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+/* In the GNU C library we must keep the namespace clean. */
+#ifdef _LIBC
+# define unsetenv __unsetenv
+#endif
+
+
+int
+unsetenv (const char *name)
+{
+ size_t len;
+ char **ep;
+
+ if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ len = strlen (name);
+
+ LOCK;
+
+ ep = __environ;
+ while (*ep != NULL)
+ if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
+ {
+ /* Found it. Remove this pointer by moving later ones back. */
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case NAME appears again. */
+ }
+ else
+ ++ep;
+
+ UNLOCK;
+
+ return 0;
+}
+
+#ifdef _LIBC
+# undef unsetenv
+weak_alias (__unsetenv, unsetenv)
+#endif
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
new file mode 100644
index 0000000..324d62e
--- /dev/null
+++ b/lib/vasnprintf.c
@@ -0,0 +1,901 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 1999, 2002-2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#ifndef IN_LIBINTL
+# include <alloca.h>
+#endif
+
+/* Specification. */
+#if WIDE_CHAR_VERSION
+# include "vasnwprintf.h"
+#else
+# include "vasnprintf.h"
+#endif
+
+#include <stdio.h> /* snprintf(), sprintf() */
+#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
+#include <string.h> /* memcpy(), strlen() */
+#include <errno.h> /* errno */
+#include <limits.h> /* CHAR_BIT, INT_MAX */
+#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
+#if WIDE_CHAR_VERSION
+# include "wprintf-parse.h"
+#else
+# include "printf-parse.h"
+#endif
+
+/* Checked size_t computations. */
+#include "xsize.h"
+
+/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
+#ifndef EOVERFLOW
+# define EOVERFLOW E2BIG
+#endif
+
+#ifdef HAVE_WCHAR_T
+# ifdef HAVE_WCSLEN
+# define local_wcslen wcslen
+# else
+ /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
+ a dependency towards this library, here is a local substitute.
+ Define this substitute only once, even if this file is included
+ twice in the same compilation unit. */
+# ifndef local_wcslen_defined
+# define local_wcslen_defined 1
+static size_t
+local_wcslen (const wchar_t *s)
+{
+ const wchar_t *ptr;
+
+ for (ptr = s; *ptr != (wchar_t) 0; ptr++)
+ ;
+ return ptr - s;
+}
+# endif
+# endif
+#endif
+
+#if WIDE_CHAR_VERSION
+# define VASNPRINTF vasnwprintf
+# define CHAR_T wchar_t
+# define DIRECTIVE wchar_t_directive
+# define DIRECTIVES wchar_t_directives
+# define PRINTF_PARSE wprintf_parse
+# define USE_SNPRINTF 1
+# if HAVE_DECL__SNWPRINTF
+ /* On Windows, the function swprintf() has a different signature than
+ on Unix; we use the _snwprintf() function instead. */
+# define SNPRINTF _snwprintf
+# else
+ /* Unix. */
+# define SNPRINTF swprintf
+# endif
+#else
+# define VASNPRINTF vasnprintf
+# define CHAR_T char
+# define DIRECTIVE char_directive
+# define DIRECTIVES char_directives
+# define PRINTF_PARSE printf_parse
+# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
+# if HAVE_DECL__SNPRINTF
+ /* Windows. */
+# define SNPRINTF _snprintf
+# else
+ /* Unix. */
+# define SNPRINTF snprintf
+# endif
+#endif
+
+CHAR_T *
+VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
+{
+ DIRECTIVES d;
+ arguments a;
+
+ if (PRINTF_PARSE (format, &d, &a) < 0)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+#define CLEANUP() \
+ free (d.dir); \
+ if (a.arg) \
+ free (a.arg);
+
+ if (printf_fetchargs (args, &a) < 0)
+ {
+ CLEANUP ();
+ errno = EINVAL;
+ return NULL;
+ }
+
+ {
+ size_t buf_neededlength;
+ CHAR_T *buf;
+ CHAR_T *buf_malloced;
+ const CHAR_T *cp;
+ size_t i;
+ DIRECTIVE *dp;
+ /* Output string accumulator. */
+ CHAR_T *result;
+ size_t allocated;
+ size_t length;
+
+ /* Allocate a small buffer that will hold a directive passed to
+ sprintf or snprintf. */
+ buf_neededlength =
+ xsum4 (7, d.max_width_length, d.max_precision_length, 6);
+#if HAVE_ALLOCA
+ if (buf_neededlength < 4000 / sizeof (CHAR_T))
+ {
+ buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
+ buf_malloced = NULL;
+ }
+ else
+#endif
+ {
+ size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
+ if (size_overflow_p (buf_memsize))
+ goto out_of_memory_1;
+ buf = (CHAR_T *) malloc (buf_memsize);
+ if (buf == NULL)
+ goto out_of_memory_1;
+ buf_malloced = buf;
+ }
+
+ if (resultbuf != NULL)
+ {
+ result = resultbuf;
+ allocated = *lengthp;
+ }
+ else
+ {
+ result = NULL;
+ allocated = 0;
+ }
+ length = 0;
+ /* Invariants:
+ result is either == resultbuf or == NULL or malloc-allocated.
+ If length > 0, then result != NULL. */
+
+ /* Ensures that allocated >= needed. Aborts through a jump to
+ out_of_memory if needed is SIZE_MAX or otherwise too big. */
+#define ENSURE_ALLOCATION(needed) \
+ if ((needed) > allocated) \
+ { \
+ size_t memory_size; \
+ CHAR_T *memory; \
+ \
+ allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \
+ if ((needed) > allocated) \
+ allocated = (needed); \
+ memory_size = xtimes (allocated, sizeof (CHAR_T)); \
+ if (size_overflow_p (memory_size)) \
+ goto out_of_memory; \
+ if (result == resultbuf || result == NULL) \
+ memory = (CHAR_T *) malloc (memory_size); \
+ else \
+ memory = (CHAR_T *) realloc (result, memory_size); \
+ if (memory == NULL) \
+ goto out_of_memory; \
+ if (result == resultbuf && length > 0) \
+ memcpy (memory, result, length * sizeof (CHAR_T)); \
+ result = memory; \
+ }
+
+ for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
+ {
+ if (cp != dp->dir_start)
+ {
+ size_t n = dp->dir_start - cp;
+ size_t augmented_length = xsum (length, n);
+
+ ENSURE_ALLOCATION (augmented_length);
+ memcpy (result + length, cp, n * sizeof (CHAR_T));
+ length = augmented_length;
+ }
+ if (i == d.count)
+ break;
+
+ /* Execute a single directive. */
+ if (dp->conversion == '%')
+ {
+ size_t augmented_length;
+
+ if (!(dp->arg_index == ARG_NONE))
+ abort ();
+ augmented_length = xsum (length, 1);
+ ENSURE_ALLOCATION (augmented_length);
+ result[length] = '%';
+ length = augmented_length;
+ }
+ else
+ {
+ if (!(dp->arg_index != ARG_NONE))
+ abort ();
+
+ if (dp->conversion == 'n')
+ {
+ switch (a.arg[dp->arg_index].type)
+ {
+ case TYPE_COUNT_SCHAR_POINTER:
+ *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
+ break;
+ case TYPE_COUNT_SHORT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_short_pointer = length;
+ break;
+ case TYPE_COUNT_INT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int_pointer = length;
+ break;
+ case TYPE_COUNT_LONGINT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_COUNT_LONGLONGINT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
+ break;
+#endif
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ arg_type type = a.arg[dp->arg_index].type;
+ CHAR_T *p;
+ unsigned int prefix_count;
+ int prefixes[2];
+#if !USE_SNPRINTF
+ size_t tmp_length;
+ CHAR_T tmpbuf[700];
+ CHAR_T *tmp;
+
+ /* Allocate a temporary buffer of sufficient size for calling
+ sprintf. */
+ {
+ size_t width;
+ size_t precision;
+
+ width = 0;
+ if (dp->width_start != dp->width_end)
+ {
+ if (dp->width_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->width_arg_index].a.a_int;
+ width = (arg < 0 ? (unsigned int) (-arg) : arg);
+ }
+ else
+ {
+ const CHAR_T *digitp = dp->width_start;
+
+ do
+ width = xsum (xtimes (width, 10), *digitp++ - '0');
+ while (digitp != dp->width_end);
+ }
+ }
+
+ precision = 6;
+ if (dp->precision_start != dp->precision_end)
+ {
+ if (dp->precision_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->precision_arg_index].a.a_int;
+ precision = (arg < 0 ? 0 : arg);
+ }
+ else
+ {
+ const CHAR_T *digitp = dp->precision_start + 1;
+
+ precision = 0;
+ while (digitp != dp->precision_end)
+ precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+ }
+ }
+
+ switch (dp->conversion)
+ {
+
+ case 'd': case 'i': case 'u':
+# ifdef HAVE_LONG_LONG
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ break;
+
+ case 'o':
+# ifdef HAVE_LONG_LONG
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ break;
+
+ case 'x': case 'X':
+# ifdef HAVE_LONG_LONG
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading sign or alternate form */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading sign or alternate form */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading sign or alternate form */
+ break;
+
+ case 'f': case 'F':
+# ifdef HAVE_LONG_DOUBLE
+ if (type == TYPE_LONGDOUBLE)
+ tmp_length =
+ (unsigned int) (LDBL_MAX_EXP
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 10; /* sign, decimal point etc. */
+ else
+# endif
+ tmp_length =
+ (unsigned int) (DBL_MAX_EXP
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 10; /* sign, decimal point etc. */
+ tmp_length = xsum (tmp_length, precision);
+ break;
+
+ case 'e': case 'E': case 'g': case 'G':
+ case 'a': case 'A':
+ tmp_length =
+ 12; /* sign, decimal point, exponent etc. */
+ tmp_length = xsum (tmp_length, precision);
+ break;
+
+ case 'c':
+# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
+ if (type == TYPE_WIDE_CHAR)
+ tmp_length = MB_CUR_MAX;
+ else
+# endif
+ tmp_length = 1;
+ break;
+
+ case 's':
+# ifdef HAVE_WCHAR_T
+ if (type == TYPE_WIDE_STRING)
+ {
+ tmp_length =
+ local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
+
+# if !WIDE_CHAR_VERSION
+ tmp_length = xtimes (tmp_length, MB_CUR_MAX);
+# endif
+ }
+ else
+# endif
+ tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
+ break;
+
+ case 'p':
+ tmp_length =
+ (unsigned int) (sizeof (void *) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading 0x */
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (tmp_length < width)
+ tmp_length = width;
+
+ tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+ }
+
+ if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
+ tmp = tmpbuf;
+ else
+ {
+ size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
+
+ if (size_overflow_p (tmp_memsize))
+ /* Overflow, would lead to out of memory. */
+ goto out_of_memory;
+ tmp = (CHAR_T *) malloc (tmp_memsize);
+ if (tmp == NULL)
+ /* Out of memory. */
+ goto out_of_memory;
+ }
+#endif
+
+ /* Construct the format string for calling snprintf or
+ sprintf. */
+ p = buf;
+ *p++ = '%';
+ if (dp->flags & FLAG_GROUP)
+ *p++ = '\'';
+ if (dp->flags & FLAG_LEFT)
+ *p++ = '-';
+ if (dp->flags & FLAG_SHOWSIGN)
+ *p++ = '+';
+ if (dp->flags & FLAG_SPACE)
+ *p++ = ' ';
+ if (dp->flags & FLAG_ALT)
+ *p++ = '#';
+ if (dp->flags & FLAG_ZERO)
+ *p++ = '0';
+ if (dp->width_start != dp->width_end)
+ {
+ size_t n = dp->width_end - dp->width_start;
+ memcpy (p, dp->width_start, n * sizeof (CHAR_T));
+ p += n;
+ }
+ if (dp->precision_start != dp->precision_end)
+ {
+ size_t n = dp->precision_end - dp->precision_start;
+ memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
+ p += n;
+ }
+
+ switch (type)
+ {
+#ifdef HAVE_LONG_LONG
+ case TYPE_LONGLONGINT:
+ case TYPE_ULONGLONGINT:
+ *p++ = 'l';
+ /*FALLTHROUGH*/
+#endif
+ case TYPE_LONGINT:
+ case TYPE_ULONGINT:
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+#endif
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+#endif
+ *p++ = 'l';
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ *p++ = 'L';
+ break;
+#endif
+ default:
+ break;
+ }
+ *p = dp->conversion;
+#if USE_SNPRINTF
+ p[1] = '%';
+ p[2] = 'n';
+ p[3] = '\0';
+#else
+ p[1] = '\0';
+#endif
+
+ /* Construct the arguments for calling snprintf or sprintf. */
+ prefix_count = 0;
+ if (dp->width_arg_index != ARG_NONE)
+ {
+ if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+ abort ();
+ prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
+ }
+ if (dp->precision_arg_index != ARG_NONE)
+ {
+ if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+ abort ();
+ prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
+ }
+
+#if USE_SNPRINTF
+ /* Prepare checking whether snprintf returns the count
+ via %n. */
+ ENSURE_ALLOCATION (xsum (length, 1));
+ result[length] = '\0';
+#endif
+
+ for (;;)
+ {
+ size_t maxlen;
+ int count;
+ int retcount;
+
+ maxlen = allocated - length;
+ count = -1;
+ retcount = 0;
+
+#if USE_SNPRINTF
+# define SNPRINTF_BUF(arg) \
+ switch (prefix_count) \
+ { \
+ case 0: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ arg, &count); \
+ break; \
+ case 1: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ prefixes[0], arg, &count); \
+ break; \
+ case 2: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ prefixes[0], prefixes[1], arg, \
+ &count); \
+ break; \
+ default: \
+ abort (); \
+ }
+#else
+# define SNPRINTF_BUF(arg) \
+ switch (prefix_count) \
+ { \
+ case 0: \
+ count = sprintf (tmp, buf, arg); \
+ break; \
+ case 1: \
+ count = sprintf (tmp, buf, prefixes[0], arg); \
+ break; \
+ case 2: \
+ count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
+ arg); \
+ break; \
+ default: \
+ abort (); \
+ }
+#endif
+
+ switch (type)
+ {
+ case TYPE_SCHAR:
+ {
+ int arg = a.arg[dp->arg_index].a.a_schar;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UCHAR:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_SHORT:
+ {
+ int arg = a.arg[dp->arg_index].a.a_short;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_USHORT:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT:
+ {
+ int arg = a.arg[dp->arg_index].a.a_int;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_uint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_LONGINT:
+ {
+ long int arg = a.arg[dp->arg_index].a.a_longint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_ULONGINT:
+ {
+ unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_LONGLONGINT:
+ {
+ long long int arg = a.arg[dp->arg_index].a.a_longlongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_ULONGLONGINT:
+ {
+ unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_DOUBLE:
+ {
+ double arg = a.arg[dp->arg_index].a.a_double;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ {
+ long double arg = a.arg[dp->arg_index].a.a_longdouble;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_CHAR:
+ {
+ int arg = a.arg[dp->arg_index].a.a_char;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+ {
+ wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_STRING:
+ {
+ const char *arg = a.arg[dp->arg_index].a.a_string;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+ {
+ const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_POINTER:
+ {
+ void *arg = a.arg[dp->arg_index].a.a_pointer;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ default:
+ abort ();
+ }
+
+#if USE_SNPRINTF
+ /* Portability: Not all implementations of snprintf()
+ are ISO C 99 compliant. Determine the number of
+ bytes that snprintf() has produced or would have
+ produced. */
+ if (count >= 0)
+ {
+ /* Verify that snprintf() has NUL-terminated its
+ result. */
+ if (count < maxlen && result[length + count] != '\0')
+ abort ();
+ /* Portability hack. */
+ if (retcount > count)
+ count = retcount;
+ }
+ else
+ {
+ /* snprintf() doesn't understand the '%n'
+ directive. */
+ if (p[1] != '\0')
+ {
+ /* Don't use the '%n' directive; instead, look
+ at the snprintf() return value. */
+ p[1] = '\0';
+ continue;
+ }
+ else
+ {
+ /* Look at the snprintf() return value. */
+ if (retcount < 0)
+ {
+ /* HP-UX 10.20 snprintf() is doubly deficient:
+ It doesn't understand the '%n' directive,
+ *and* it returns -1 (rather than the length
+ that would have been required) when the
+ buffer is too small. */
+ size_t bigger_need =
+ xsum (xtimes (allocated, 2), 12);
+ ENSURE_ALLOCATION (bigger_need);
+ continue;
+ }
+ else
+ count = retcount;
+ }
+ }
+#endif
+
+ /* Attempt to handle failure. */
+ if (count < 0)
+ {
+ if (!(result == resultbuf || result == NULL))
+ free (result);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ CLEANUP ();
+ errno = EINVAL;
+ return NULL;
+ }
+
+#if !USE_SNPRINTF
+ if (count >= tmp_length)
+ /* tmp_length was incorrectly calculated - fix the
+ code above! */
+ abort ();
+#endif
+
+ /* Make room for the result. */
+ if (count >= maxlen)
+ {
+ /* Need at least count bytes. But allocate
+ proportionally, to avoid looping eternally if
+ snprintf() reports a too small count. */
+ size_t n =
+ xmax (xsum (length, count), xtimes (allocated, 2));
+
+ ENSURE_ALLOCATION (n);
+#if USE_SNPRINTF
+ continue;
+#endif
+ }
+
+#if USE_SNPRINTF
+ /* The snprintf() result did fit. */
+#else
+ /* Append the sprintf() result. */
+ memcpy (result + length, tmp, count * sizeof (CHAR_T));
+ if (tmp != tmpbuf)
+ free (tmp);
+#endif
+
+ length += count;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Add the final NUL. */
+ ENSURE_ALLOCATION (xsum (length, 1));
+ result[length] = '\0';
+
+ if (result != resultbuf && length + 1 < allocated)
+ {
+ /* Shrink the allocated memory if possible. */
+ CHAR_T *memory;
+
+ memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
+ if (memory != NULL)
+ result = memory;
+ }
+
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ CLEANUP ();
+ *lengthp = length;
+ if (length > INT_MAX)
+ goto length_overflow;
+ return result;
+
+ length_overflow:
+ /* We could produce such a big string, but its length doesn't fit into
+ an 'int'. POSIX says that snprintf() fails with errno = EOVERFLOW in
+ this case. */
+ if (result != resultbuf)
+ free (result);
+ errno = EOVERFLOW;
+ return NULL;
+
+ out_of_memory:
+ if (!(result == resultbuf || result == NULL))
+ free (result);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ out_of_memory_1:
+ CLEANUP ();
+ errno = ENOMEM;
+ return NULL;
+ }
+}
+
+#undef SNPRINTF
+#undef USE_SNPRINTF
+#undef PRINTF_PARSE
+#undef DIRECTIVES
+#undef DIRECTIVE
+#undef CHAR_T
+#undef VASNPRINTF
diff --git a/lib/vasnprintf.h b/lib/vasnprintf.h
new file mode 100644
index 0000000..894008c
--- /dev/null
+++ b/lib/vasnprintf.h
@@ -0,0 +1,77 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 2002-2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _VASNPRINTF_H
+#define _VASNPRINTF_H
+
+/* Get va_list. */
+#include <stdarg.h>
+
+/* Get size_t. */
+#include <stddef.h>
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+ You can pass a preallocated buffer for the result in RESULTBUF and its
+ size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
+ If successful, return the address of the string (this may be = RESULTBUF
+ if no dynamic memory allocation was necessary) and set *LENGTHP to the
+ number of resulting bytes, excluding the trailing NUL. Upon error, set
+ errno and return NULL.
+
+ When dynamic memory allocation occurs, the preallocated buffer is left
+ alone (with possibly modified contents). This makes it possible to use
+ a statically allocated or stack-allocated buffer, like this:
+
+ char buf[100];
+ size_t len = sizeof (buf);
+ char *output = vasnprintf (buf, &len, format, args);
+ if (output == NULL)
+ ... error handling ...;
+ else
+ {
+ ... use the output string ...;
+ if (output != buf)
+ free (output);
+ }
+ */
+extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
+ __attribute__ ((__format__ (__printf__, 3, 0)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VASNPRINTF_H */
diff --git a/lib/vasprintf.c b/lib/vasprintf.c
new file mode 100644
index 0000000..149c292
--- /dev/null
+++ b/lib/vasprintf.c
@@ -0,0 +1,42 @@
+/* Formatted output to strings.
+ Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "vasprintf.h"
+
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+int
+vasprintf (char **resultp, const char *format, va_list args)
+{
+ size_t length;
+ char *result = vasnprintf (NULL, &length, format, args);
+ if (result == NULL)
+ return -1;
+
+ *resultp = result;
+ /* Return the number of resulting bytes, excluding the trailing NUL.
+ If it wouldn't fit in an 'int', vasnprintf() would have returned NULL
+ and set errno to EOVERFLOW. */
+ return length;
+}
diff --git a/lib/vasprintf.h b/lib/vasprintf.h
new file mode 100644
index 0000000..d02f154
--- /dev/null
+++ b/lib/vasprintf.h
@@ -0,0 +1,63 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 2002-2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _VASPRINTF_H
+#define _VASPRINTF_H
+
+#if HAVE_VASPRINTF
+
+/* Get asprintf(), vasprintf() declarations. */
+#include <stdio.h>
+
+#else
+
+/* Get va_list. */
+#include <stdarg.h>
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+ If the memory allocation succeeds, store the address of the string in
+ *RESULT and return the number of resulting bytes, excluding the trailing
+ NUL. Upon memory allocation error, or some other error, return -1. */
+extern int asprintf (char **result, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+extern int vasprintf (char **result, const char *format, va_list args)
+ __attribute__ ((__format__ (__printf__, 2, 0)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /* _VASPRINTF_H */
diff --git a/lib/wait.h b/lib/wait.h
new file mode 100644
index 0000000..81df938
--- /dev/null
+++ b/lib/wait.h
@@ -0,0 +1,42 @@
+/* wait.h -- POSIX macros for evaluating exit statuses
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/types.h> /* For pid_t. */
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h> /* for rusage */
+#endif
+#include <sys/wait.h>
+#endif
+#ifndef WIFSTOPPED
+#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(w) (((w) & 0xff) == 0)
+#endif
+#ifndef WCOREDUMP /* not POSIX, but common and useful */
+#define WCOREDUMP(w) (((w) & 0x80) != 0)
+#endif
+
+#ifndef WSTOPSIG
+#define WSTOPSIG(w) (((w) >> 8) & 0xff)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(w) ((w) & 0x7f)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
+#endif
diff --git a/lib/waitpid.c b/lib/waitpid.c
new file mode 100644
index 0000000..02d6acb
--- /dev/null
+++ b/lib/waitpid.c
@@ -0,0 +1,80 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "system.h"
+#include "wait.h"
+
+#include <stdio.h>
+
+struct unreaped {
+ pid_t pid;
+ int status;
+};
+static struct unreaped *unreaped;
+static int n;
+
+static struct unreaped *ualloc (oldptr, n)
+ struct unreaped *oldptr;
+ int n;
+{
+ n *= sizeof (struct unreaped);
+ if (n == 0)
+ n = 1;
+ if (oldptr)
+ oldptr = (struct unreaped *) realloc ((char *) oldptr, n);
+ else
+ oldptr = (struct unreaped *) malloc (n);
+ if (oldptr == 0)
+ {
+ fprintf (stderr, "cannot allocate %d bytes\n", n);
+ exit (1);
+ }
+ return oldptr;
+}
+
+pid_t waitpid (pid, status, options)
+ pid_t pid;
+ int *status;
+ int options;
+{
+ int i;
+
+ /* initialize */
+ if (unreaped == 0)
+ {
+ unreaped = ualloc (unreaped, 1);
+ unreaped[0].pid = 0;
+ n = 1;
+ }
+
+ for (i = 0; unreaped[i].pid; i++)
+ if (unreaped[i].pid == pid)
+ {
+ *status = unreaped[i].status;
+ while (unreaped[i].pid)
+ {
+ unreaped[i] = unreaped[i+1];
+ i++;
+ }
+ n--;
+ return pid;
+ }
+
+ while (1)
+ {
+#ifdef HAVE_WAIT3
+ pid_t p = wait3 (status, options, (struct rusage *) 0);
+#else
+ pid_t p = wait (status);
+#endif
+
+ if (p == 0 || p == -1 || p == pid)
+ return p;
+
+ n++;
+ unreaped = ualloc (unreaped, n);
+ unreaped[n-1].pid = p;
+ unreaped[n-1].status = *status;
+ }
+}
diff --git a/lib/xalloc-die.c b/lib/xalloc-die.c
new file mode 100644
index 0000000..ff5ac9e
--- /dev/null
+++ b/lib/xalloc-die.c
@@ -0,0 +1,45 @@
+/* Report a memory allocation failure and exit.
+
+ Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "xalloc.h"
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "exitfail.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+void
+xalloc_die (void)
+{
+ error (exit_failure, 0, "%s", _("memory exhausted"));
+
+ /* The `noreturn' cannot be given to error, since it may return if
+ its first argument is 0. To help compilers understand the
+ xalloc_die does not return, call abort. Also, the abort is a
+ safety feature if exit_failure is 0 (which shouldn't happen). */
+ abort ();
+}
diff --git a/lib/xalloc.h b/lib/xalloc.h
new file mode 100644
index 0000000..f80977e
--- /dev/null
+++ b/lib/xalloc.h
@@ -0,0 +1,79 @@
+/* xalloc.h -- malloc with out-of-memory checking
+
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef XALLOC_H_
+# define XALLOC_H_
+
+# include <stddef.h>
+
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+
+# ifndef __attribute__
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
+# define __attribute__(x)
+# endif
+# endif
+
+# ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+# endif
+
+/* This function is always triggered when memory is exhausted.
+ It must be defined by the application, either explicitly
+ or by using gnulib's xalloc-die module. This is the
+ function to call when one wants the program to die because of a
+ memory allocation failure. */
+extern void xalloc_die (void) ATTRIBUTE_NORETURN;
+
+void *xmalloc (size_t s);
+void *xnmalloc (size_t n, size_t s);
+void *xzalloc (size_t s);
+void *xcalloc (size_t n, size_t s);
+void *xrealloc (void *p, size_t s);
+void *xnrealloc (void *p, size_t n, size_t s);
+void *x2realloc (void *p, size_t *pn);
+void *x2nrealloc (void *p, size_t *pn, size_t s);
+void *xmemdup (void const *p, size_t s);
+char *xstrdup (char const *str);
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+ to size arithmetic overflow. S must be positive and N must be
+ nonnegative. This is a macro, not an inline function, so that it
+ works correctly even when SIZE_MAX < N.
+
+ By gnulib convention, SIZE_MAX represents overflow in size
+ calculations, so the conservative dividend to use here is
+ SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+ However, malloc (SIZE_MAX) fails on all known hosts where
+ sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+ exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+ branch when S is known to be 1. */
+# define xalloc_oversized(n, s) \
+ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+
+# ifdef __cplusplus
+}
+# endif
+
+
+#endif /* !XALLOC_H_ */
diff --git a/lib/xgetcwd.c b/lib/xgetcwd.c
new file mode 100644
index 0000000..0f798da
--- /dev/null
+++ b/lib/xgetcwd.c
@@ -0,0 +1,43 @@
+/* xgetcwd.c -- return current directory with unlimited length
+
+ Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "xgetcwd.h"
+
+#include <errno.h>
+
+#include "getcwd.h"
+#include "xalloc.h"
+
+/* Return the current directory, newly allocated.
+ Upon an out-of-memory error, call xalloc_die.
+ Upon any other type of error, return NULL. */
+
+char *
+xgetcwd (void)
+{
+ char *cwd = getcwd (NULL, 0);
+ if (! cwd && errno == ENOMEM)
+ xalloc_die ();
+ return cwd;
+}
diff --git a/lib/xgetcwd.h b/lib/xgetcwd.h
new file mode 100644
index 0000000..70afe35
--- /dev/null
+++ b/lib/xgetcwd.h
@@ -0,0 +1,18 @@
+/* prototype for xgetcwd
+ Copyright (C) 1995, 2001, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+extern char *xgetcwd (void);
diff --git a/lib/xgethostname.c b/lib/xgethostname.c
new file mode 100644
index 0000000..5b8b9b2
--- /dev/null
+++ b/lib/xgethostname.c
@@ -0,0 +1,84 @@
+/* xgethostname.c -- return current hostname with unlimited length
+
+ Copyright (C) 1992, 1996, 2000, 2001, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "xgethostname.h"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "xalloc.h"
+
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG 0
+#endif
+
+#ifndef INITIAL_HOSTNAME_LENGTH
+# define INITIAL_HOSTNAME_LENGTH 34
+#endif
+
+/* Return the current hostname in malloc'd storage.
+ If malloc fails, exit.
+ Upon any other failure, return NULL and set errno. */
+char *
+xgethostname (void)
+{
+ char *hostname = NULL;
+ size_t size = INITIAL_HOSTNAME_LENGTH;
+
+ while (1)
+ {
+ /* Use SIZE_1 here rather than SIZE to work around the bug in
+ SunOS 5.5's gethostname whereby it NUL-terminates HOSTNAME
+ even when the name is as long as the supplied buffer. */
+ size_t size_1;
+
+ hostname = x2realloc (hostname, &size);
+ size_1 = size - 1;
+ hostname[size_1 - 1] = '\0';
+ errno = 0;
+
+ if (gethostname (hostname, size_1) == 0)
+ {
+ if (! hostname[size_1 - 1])
+ break;
+ }
+ else if (errno != 0 && errno != ENAMETOOLONG && errno != EINVAL
+ /* OSX/Darwin does this when the buffer is not large enough */
+ && errno != ENOMEM)
+ {
+ int saved_errno = errno;
+ free (hostname);
+ errno = saved_errno;
+ return NULL;
+ }
+ }
+
+ return hostname;
+}
diff --git a/lib/xgethostname.h b/lib/xgethostname.h
new file mode 100644
index 0000000..0177a40
--- /dev/null
+++ b/lib/xgethostname.h
@@ -0,0 +1 @@
+char *xgethostname (void);
diff --git a/lib/xmalloc.c b/lib/xmalloc.c
new file mode 100644
index 0000000..687633c
--- /dev/null
+++ b/lib/xmalloc.c
@@ -0,0 +1,241 @@
+/* xmalloc.c -- malloc with out of memory checking
+
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "xalloc.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+/* 1 if calloc is known to be compatible with GNU calloc. This
+ matters if we are not also using the calloc module, which defines
+ HAVE_CALLOC and supports the GNU API even on non-GNU platforms. */
+#if defined HAVE_CALLOC || defined __GLIBC__
+enum { HAVE_GNU_CALLOC = 1 };
+#else
+enum { HAVE_GNU_CALLOC = 0 };
+#endif
+
+/* Allocate an array of N objects, each with S bytes of memory,
+ dynamically, with error checking. S must be nonzero. */
+
+static inline void *
+xnmalloc_inline (size_t n, size_t s)
+{
+ void *p;
+ if (xalloc_oversized (n, s) || (! (p = malloc (n * s)) && n != 0))
+ xalloc_die ();
+ return p;
+}
+
+void *
+xnmalloc (size_t n, size_t s)
+{
+ return xnmalloc_inline (n, s);
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+void *
+xmalloc (size_t n)
+{
+ return xnmalloc_inline (n, 1);
+}
+
+/* Change the size of an allocated block of memory P to an array of N
+ objects each of S bytes, with error checking. S must be nonzero. */
+
+static inline void *
+xnrealloc_inline (void *p, size_t n, size_t s)
+{
+ if (xalloc_oversized (n, s) || (! (p = realloc (p, n * s)) && n != 0))
+ xalloc_die ();
+ return p;
+}
+
+void *
+xnrealloc (void *p, size_t n, size_t s)
+{
+ return xnrealloc_inline (p, n, s);
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking. */
+
+void *
+xrealloc (void *p, size_t n)
+{
+ return xnrealloc_inline (p, n, 1);
+}
+
+
+/* If P is null, allocate a block of at least *PN such objects;
+ otherwise, reallocate P so that it contains more than *PN objects
+ each of S bytes. *PN must be nonzero unless P is null, and S must
+ be nonzero. Set *PN to the new number of objects, and return the
+ pointer to the new block. *PN is never set to zero, and the
+ returned pointer is never null.
+
+ Repeated reallocations are guaranteed to make progress, either by
+ allocating an initial block with a nonzero size, or by allocating a
+ larger block.
+
+ In the following implementation, nonzero sizes are doubled so that
+ repeated reallocations have O(N log N) overall cost rather than
+ O(N**2) cost, but the specification for this function does not
+ guarantee that sizes are doubled.
+
+ Here is an example of use:
+
+ int *p = NULL;
+ size_t used = 0;
+ size_t allocated = 0;
+
+ void
+ append_int (int value)
+ {
+ if (used == allocated)
+ p = x2nrealloc (p, &allocated, sizeof *p);
+ p[used++] = value;
+ }
+
+ This causes x2nrealloc to allocate a block of some nonzero size the
+ first time it is called.
+
+ To have finer-grained control over the initial size, set *PN to a
+ nonzero value before calling this function with P == NULL. For
+ example:
+
+ int *p = NULL;
+ size_t used = 0;
+ size_t allocated = 0;
+ size_t allocated1 = 1000;
+
+ void
+ append_int (int value)
+ {
+ if (used == allocated)
+ {
+ p = x2nrealloc (p, &allocated1, sizeof *p);
+ allocated = allocated1;
+ }
+ p[used++] = value;
+ }
+
+ */
+
+static inline void *
+x2nrealloc_inline (void *p, size_t *pn, size_t s)
+{
+ size_t n = *pn;
+
+ if (! p)
+ {
+ if (! n)
+ {
+ /* The approximate size to use for initial small allocation
+ requests, when the invoking code specifies an old size of
+ zero. 64 bytes is the largest "small" request for the
+ GNU C library malloc. */
+ enum { DEFAULT_MXFAST = 64 };
+
+ n = DEFAULT_MXFAST / s;
+ n += !n;
+ }
+ }
+ else
+ {
+ if (SIZE_MAX / 2 / s < n)
+ xalloc_die ();
+ n *= 2;
+ }
+
+ *pn = n;
+ return xrealloc (p, n * s);
+}
+
+void *
+x2nrealloc (void *p, size_t *pn, size_t s)
+{
+ return x2nrealloc_inline (p, pn, s);
+}
+
+/* If P is null, allocate a block of at least *PN bytes; otherwise,
+ reallocate P so that it contains more than *PN bytes. *PN must be
+ nonzero unless P is null. Set *PN to the new block's size, and
+ return the pointer to the new block. *PN is never set to zero, and
+ the returned pointer is never null. */
+
+void *
+x2realloc (void *p, size_t *pn)
+{
+ return x2nrealloc_inline (p, pn, 1);
+}
+
+/* Allocate S bytes of zeroed memory dynamically, with error checking.
+ There's no need for xnzalloc (N, S), since it would be equivalent
+ to xcalloc (N, S). */
+
+void *
+xzalloc (size_t s)
+{
+ return memset (xmalloc (s), 0, s);
+}
+
+/* Allocate zeroed memory for N elements of S bytes, with error
+ checking. S must be nonzero. */
+
+void *
+xcalloc (size_t n, size_t s)
+{
+ void *p;
+ /* Test for overflow, since some calloc implementations don't have
+ proper overflow checks. But omit overflow and size-zero tests if
+ HAVE_GNU_CALLOC, since GNU calloc catches overflow and never
+ returns NULL if successful. */
+ if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s))
+ || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0)))
+ xalloc_die ();
+ return p;
+}
+
+/* Clone an object P of size S, with error checking. There's no need
+ for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
+ need for an arithmetic overflow check. */
+
+void *
+xmemdup (void const *p, size_t s)
+{
+ return memcpy (xmalloc (s), p, s);
+}
+
+/* Clone STRING. */
+
+char *
+xstrdup (char const *string)
+{
+ return xmemdup (string, strlen (string) + 1);
+}
diff --git a/lib/xreadlink.c b/lib/xreadlink.c
new file mode 100644
index 0000000..f21812d
--- /dev/null
+++ b/lib/xreadlink.c
@@ -0,0 +1,93 @@
+/* xreadlink.c -- readlink wrapper to return the link name in malloc'd storage
+
+ Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering <jim@meyering.net> */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "xreadlink.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+#ifndef SSIZE_MAX
+# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
+#endif
+
+#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX)
+
+#include "xalloc.h"
+
+/* Call readlink to get the symbolic link value of FILE.
+ SIZE is a hint as to how long the link is expected to be;
+ typically it is taken from st_size. It need not be correct.
+ Return a pointer to that NUL-terminated string in malloc'd storage.
+ If readlink fails, return NULL (caller may use errno to diagnose).
+ If malloc fails, or if the link value is longer than SSIZE_MAX :-),
+ give a diagnostic and exit. */
+
+char *
+xreadlink (char const *file, size_t size)
+{
+ /* The initial buffer size for the link value. A power of 2
+ detects arithmetic overflow earlier, but is not required. */
+ size_t buf_size = size < MAXSIZE ? size + 1 : MAXSIZE;
+
+ while (1)
+ {
+ char *buffer = xmalloc (buf_size);
+ ssize_t r = readlink (file, buffer, buf_size);
+ size_t link_length = r;
+
+ /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
+ with errno == ERANGE if the buffer is too small. */
+ if (r < 0 && errno != ERANGE)
+ {
+ int saved_errno = errno;
+ free (buffer);
+ errno = saved_errno;
+ return NULL;
+ }
+
+ if (link_length < buf_size)
+ {
+ buffer[link_length] = 0;
+ return buffer;
+ }
+
+ free (buffer);
+ if (buf_size <= MAXSIZE / 2)
+ buf_size *= 2;
+ else if (buf_size < MAXSIZE)
+ buf_size = MAXSIZE;
+ else
+ xalloc_die ();
+ }
+}
diff --git a/lib/xreadlink.h b/lib/xreadlink.h
new file mode 100644
index 0000000..9fcf836
--- /dev/null
+++ b/lib/xreadlink.h
@@ -0,0 +1,23 @@
+/* readlink wrapper to return the link name in malloc'd storage
+
+ Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Jim Meyering <jim@meyering.net> */
+
+#include <stddef.h>
+char *xreadlink (char const *, size_t);
diff --git a/lib/xselect.h b/lib/xselect.h
new file mode 100644
index 0000000..5605cbd
--- /dev/null
+++ b/lib/xselect.h
@@ -0,0 +1,21 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This file simply performs the include magic necessary for using select */
+
+/* select also requires <sys/types.h>, "xtime.h", and <unistd.h> */
+
+#ifdef HAVE_SYS_BSDTYPES_H
+# include <sys/bsdtypes.h>
+#endif
+
+#if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
diff --git a/lib/xsize.h b/lib/xsize.h
new file mode 100644
index 0000000..341fb16
--- /dev/null
+++ b/lib/xsize.h
@@ -0,0 +1,108 @@
+/* xsize.h -- Checked size_t computations.
+
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _XSIZE_H
+#define _XSIZE_H
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get SIZE_MAX. */
+#include <limits.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+/* The size of memory objects is often computed through expressions of
+ type size_t. Example:
+ void* p = malloc (header_size + n * element_size).
+ These computations can lead to overflow. When this happens, malloc()
+ returns a piece of memory that is way too small, and the program then
+ crashes while attempting to fill the memory.
+ To avoid this, the functions and macros in this file check for overflow.
+ The convention is that SIZE_MAX represents overflow.
+ malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
+ implementation that uses mmap --, it's recommended to use size_overflow_p()
+ or size_in_bounds_p() before invoking malloc().
+ The example thus becomes:
+ size_t size = xsum (header_size, xtimes (n, element_size));
+ void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
+*/
+
+/* Convert an arbitrary value >= 0 to type size_t. */
+#define xcast_size_t(N) \
+ ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
+
+/* Sum of two sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum (size_t size1, size_t size2)
+{
+ size_t sum = size1 + size2;
+ return (sum >= size1 ? sum : SIZE_MAX);
+}
+
+/* Sum of three sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum3 (size_t size1, size_t size2, size_t size3)
+{
+ return xsum (xsum (size1, size2), size3);
+}
+
+/* Sum of four sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
+{
+ return xsum (xsum (xsum (size1, size2), size3), size4);
+}
+
+/* Maximum of two sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xmax (size_t size1, size_t size2)
+{
+ /* No explicit check is needed here, because for any n:
+ max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
+ return (size1 >= size2 ? size1 : size2);
+}
+
+/* Multiplication of a count with an element size, with overflow check.
+ The count must be >= 0 and the element size must be > 0.
+ This is a macro, not an inline function, so that it works correctly even
+ when N is of a wider tupe and N > SIZE_MAX. */
+#define xtimes(N, ELSIZE) \
+ ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
+
+/* Check for overflow. */
+#define size_overflow_p(SIZE) \
+ ((SIZE) == SIZE_MAX)
+/* Check against overflow. */
+#define size_in_bounds_p(SIZE) \
+ ((SIZE) != SIZE_MAX)
+
+#endif /* _XSIZE_H */
diff --git a/lib/xtime.h b/lib/xtime.h
new file mode 100644
index 0000000..f9fd46e
--- /dev/null
+++ b/lib/xtime.h
@@ -0,0 +1,42 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This file simply performs the include magic necessary for using time
+ * functions
+ */
+#ifndef XTIME_HEADER_INCLUDED
+#define XTIME_HEADER_INCLUDED
+
+#ifdef vms
+# include <time.h>
+#else /* vms */
+
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else /* TIME_WITH_SYS_TIME */
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else /* HAVE_SYS_TIME_H */
+# include <time.h>
+# endif /* !HAVE_SYS_TIME_H */
+# endif /* !TIME_WITH_SYS_TIME */
+
+# ifdef timezone
+# undef timezone /* needed for sgi */
+# endif /* timezone */
+
+# if !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE)
+extern long timezone;
+# endif /* !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE) */
+
+#endif /* !vms */
+
+#endif /* !XTIME_HEADER_INCLUDED */
diff --git a/lib/yesno.c b/lib/yesno.c
new file mode 100644
index 0000000..a364a1b
--- /dev/null
+++ b/lib/yesno.c
@@ -0,0 +1,53 @@
+/* yesno.c -- read a yes/no response from stdin
+
+ Copyright (C) 1990, 1998, 2001, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "yesno.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "getline.h"
+
+/* Return true if we read an affirmative line from standard input. */
+
+extern int rpmatch (char const *response);
+
+bool
+yesno (void)
+{
+ char *response = NULL;
+ size_t response_size = 0;
+ ssize_t response_len = getline (&response, &response_size, stdin);
+ bool yes;
+
+ if (response_len <= 0)
+ yes = false;
+ else
+ {
+ response[response_len - 1] = '\0';
+ yes = (0 < rpmatch (response));
+ }
+
+ free (response);
+ return yes;
+}
diff --git a/lib/yesno.h b/lib/yesno.h
new file mode 100644
index 0000000..dfa70bc
--- /dev/null
+++ b/lib/yesno.h
@@ -0,0 +1,26 @@
+/* declare yesno
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef YESNO_H_
+# define YESNO_H_
+
+# include <stdbool.h>
+
+bool yesno (void);
+
+#endif
diff --git a/m4/ChangeLog b/m4/ChangeLog
new file mode 100644
index 0000000..b05f39b
--- /dev/null
+++ b/m4/ChangeLog
@@ -0,0 +1,805 @@
+2005-09-26 Derek Price <derek@ximbiot.com>
+
+ [bug #14639]
+ * acx_with_gssapi.m4: Find the crypto library on FreeBSD 5.x.
+ Patch from Serguei E. Leontiev <lse@CryptoPro.ru>.
+
+2005-09-25 Derek Price <derek@ximbiot.com>
+
+ * lstat.m4: Update from GNULIB.
+
+2005-09-19 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB.
+ * st_mtim.m4: Remove this file.
+ * timespec.m4, gnulib-cache.m4, gnulib-comp.m4: Updated.
+
+2005-09-15 Derek Price <derek@ximbiot.com>
+
+ * strstr.m4: Update from GNULIB.
+
+2005-09-09 Derek Price <derek@ximbiot.com>
+
+ * glob.m4: Update from GNULIB with alpha-quality glibc porting changes.
+
+2005-09-06 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB with alpha-quality patch.
+ * canon-host.m4, gnulib-comp.m4: Updated.
+ * getaddrinfo.m4, sockpfaf.m4: New files.
+
+2005-09-05 Derek Price <derek@ximbiot.com>
+
+ * mbchar.m4 (gl_MBCHAR): Only enable when wchar.h is found.
+ (Patch from Yoann Vandoorselaere <yoann.v@prelude-ids.com>.)
+
+2005-09-04 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB.
+ * glob.m4, gnulib-cache.m4, gnulib-comp.m4: Updated.
+
+ Add canon-host module from GNULIB.
+ * canon-host.m4: New file.
+ * gnulib-cache.m4, gnulib-comp.m4: Updated.
+ * gnulib.m4: Removed.
+
+ Update from GNULIB.
+ * getopt.m4, getpass.m4, lib-link.m4, lib-prefix.m4, minmax.m4,
+ regex.m4, strcase.m4, strstr.m4, unistd-safer.m4, xgetcwd.m4:
+ Updated.
+ * gnulib-cache.m4, gnulib-comp.m4, gnulib-tool.m4, mbchar.m4,
+ mbiter.m4, memchr.m4: New files.
+
+2005-09-03 Larry Jones <lawrence.jones.ugs.com>
+
+ * getlogin_r.m4: Fix cut & paste error.
+
+2005-08-12 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB.
+ * bison.m4, dup2.m4, getcwd-path-max.m4, getcwd.m4, getline.m4,
+ getopt.m4, gnulib.m4, mbrtowc.m4, mkstemp.m4, onceonly_2_57.m4,
+ pagealign_alloc.m4, regex.m4, save-cwd.m4, size_max.m4, strftime.m4,
+ unistd-safer.m4: Updated from GNULIB.
+ * getdelim.m4: New file.
+
+2005-07-15 Derek Price <derek@ximbiot.com>
+
+ * glob.m4: Import new version from GNULIB.
+
+2005-06-15 Derek Price <derek@ximbiot.com>
+
+ * bison.m4 (gl_BISON): Use new build-aux/bison-missing script.
+
+2005-06-10 Derek Price <derek@ximbiot.com>
+
+ Sync with GNULIB.
+ * getcwd-path-max.m4, rename.m4: Update from GNULIB.
+ * path-concat.m4: Rename to...
+ * filenamecat: ...this.
+
+ Test new stat module.
+ * stat.m4: Remove this file.
+ * lstat.m4: Don't check for empty string bug.
+
+2005-05-28 Derek Price <derek@ximbiot.com>
+
+ * glob.m4: s/MISSING_SYS_CDEFS_H/_SYS_CDEFS_H/. Add comment.
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * glob.m4: Don't cater to Solaris here...
+ * extensions.m4: ...do it here instead.
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * getlogin_r.m4: New module from GNULIB.
+
+2005-05-24 Derek Price <derek@ximbiot.com>
+
+ * lstat.m4, stat.m4: Define rpl_stat & rpl_lstat when needed.
+
+2005-05-24 Derek Price <derek@ximbiot.com>
+
+ * glob.m4 (gl_PREREQ_GLOB): Don't look for struct dirent64 or stat64.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * canonicalize.m4, path-concat.m4: Import from GNULIB.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * minmax.m4: New file from GNULIB.
+
+2005-05-19 Derek Price <derek@ximbiot.com>
+
+ * glob.m4 (gl_PREREQ_GLOB): Check for __posix_getpwnam_r for Solaris.
+
+2005-05-19 Derek Price <derek@ximbiot.com>
+
+ * glob.m4 (gl_PREREQ_GLOB): Check for <unistd.h>.
+
+2005-05-18 Derek Price <derek@ximbiot.com>
+
+ * glob.m4 (gl_GLOB): Don't check for <gnu-versions.h> explicitly.
+ (gl_PREREQ_GLOB): Check for <sys/cdefs.h>.
+
+2005-05-17 Derek Price <derek@ximbiot.com>
+
+ * glob.m4 (gl_GLOB): Prefer AC_COMPILE_IFELSE to AC_EGREP_CPP.
+ (Suggested by Paul Eggert <eggert@cs.ucla.edu>.)
+
+2005-05-15 Derek Price <derek@ximbiot.com>
+
+ * glob.m4 (gl_GLOB): Don't call gl_PREREQ_GLOB.
+ (gl_PREREQ_GLOB): Replace search for lots of headers by requiring
+ AC_HEADER_DIRENT. dirent64 is a type, not a function.
+
+2005-05-12 Derek Price <derek@ximbiot.com>
+
+ * d-type.m4: New file from GNULIB.
+ * glob.m4 (gl_GLOB): Remove indirection. Check gnu-versions.h instead
+ of looking for glob_pattern_p(). Use new d-type macro.
+ (gl_PREREQ_GLOB): Reformat to remove blanks line in the generated
+ configure script.
+
+2005-05-11 Derek Price <derek@ximbiot.com>
+
+ * glob.m4: New file.
+ * strdup.m4: New file from GNULIB.
+
+2005-05-10 Derek Price <derek@ximbiot.com>
+
+ * getopt.m4, stat-macros.m4: Update from GNULIB.
+
+2005-05-06 Derek Price <derek@ximbiot.com>
+
+ * getopt.m4: Update from GNULIB. Closes cvshome.org issue #248.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ Update from GNULIB.
+ * clock_time.m4, gnulib.m4, lstat.m4, mkstemp.m4, nanosleep.m4,
+ stat-macros.m4: Updated.
+ * unistd-safer.m4: New file.
+
+2005-05-01 Mark D. Baushke <mdb@cvshome.org>
+
+ * mmap-anon.m4: Update from GNULIB.
+
+2005-04-25 Derek Price <derek@ximbiot.com>
+
+ * getpass.m4, gettext.m4: Update from GNULIB.
+
+2005-03-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * getcwd-path-max.m4: Update from GNULIB.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * chdir-long.m4, closeout.m4, dirname.m4, exitfail.m4,
+ fpending.m4, getcwd.m4, getdate.m4, getline.m4, getpagesize.m4,
+ getpass.m4, gettext.m4, gnulib.m4, lib-link.m4, md5.m4,
+ memrchr.m4, nanosleep.m4, nls.m4, pathmax.m4, po.m4, quotearg.m4,
+ stat-macros.m4, stdint.m4, strftime.m4, timespec.m4,
+ unlocked-io.m4, xalloc.m4, yesno.m4: Update from GNULIB.
+
+2005-03-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * save-cwd.m4: Update from GNULIB.
+
+2005-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * mmap-anon.m4: Update from GNULIB.
+
+2005-03-03 Derek Price <derek@ximbiot.com>
+
+ * mmap-anon.m4, pagealign_alloc.m4: New files from GNULIB.
+
+2005-03-02 Jim Meyering <jim@meyering.net>
+
+ * closeout.m4, fpending.m4, mbrtowc.m4, quotearg.m4: New from gnulib.
+ * gnulib.m4: Regenerated.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ Update installed GNULIB modules.
+ * alloca.m4, allocsa.m4, atexit.m4, bison.m4, clock_time.m4,
+ codeset.m4, dirname.m4, dos.m4, eealloc.m4, eoverflow.m4, exitfail.m4,
+ extensions.m4, fnmatch.m4, getcwd.m4, getdate.m4, gethostname.m4,
+ getline.m4, getndelim2.m4, getnline.m4, getopt.m4, getpagesize.m4,
+ getpass.m4, gettext.m4, gettime.m4, gettimeofday.m4, glibc21.m4,
+ gnulib.m4, iconv.m4, intdiv0.m4, intmax.m4, intmax_t.m4,
+ inttypes-pri.m4, inttypes_h.m4, lcmessage.m4, lib-ld.m4, lib-link.m4,
+ lib-prefix.m4, longdouble.m4, longlong.m4, lstat.m4, mbstate_t.m4,
+ md5.m4, memmove.m4, mkstemp.m4, mktime.m4, nanosleep.m4, nls.m4,
+ pathmax.m4, po.m4, printf-posix.m4, progtest.m4, readlink.m4, regex.m4,
+ restrict.m4, rpmatch.m4, save-cwd.m4, setenv.m4, signed.m4,
+ size_max.m4, ssize_t.m4, st_mtim.m4, stat.m4, stdbool.m4, stdint.m4,
+ stdint_h.m4, strcase.m4, strerror.m4, strerror_r.m4, strftime.m4,
+ time_r.m4, timespec.m4, tm_gmtoff.m4, tzset.m4, uint32_t.m4,
+ uintmax_t.m4, ulonglong.m4, unlocked-io.m4, vasnprintf.m4,
+ vasprintf.m4, wchar_t.m4, wint_t.m4, xalloc.m4, xgetcwd.m4,
+ xreadlink.m4, xsize.m4, yesno.m4: Updated from GNULIB.
+ * chdir-long.m4, d-ino.m4, dup2.m4, error.m4, ftruncate.m4,
+ getcwd-path-max.m4, glibc2.m4, mempcpy.m4, memrchr.m4, mkdir-slash.m4,
+ openat.m4, rename.m4, strstr.m4, strtol.m4, strtoul.m4: New files from
+ GNULIB.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * getopt.m4: Update from GNULIB.
+
+2004-11-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * getopt.m4: Update from GNULIB.
+
+2004-11-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * strftime.m4: Update from GNULIB.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * uint32_t.m4: Update from GNULIB.
+
+2004-11-03 Derek Price <derek@ximbiot.com>
+
+ * bison.m4 (gl_BISON): Update comment to specify the correct Automake
+ version number.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * readlink.m4, xreadlink.m4: New from GNULIB.
+ * uint32_t.m4: Update from GNULIB.
+ * gnulib.m4: Regenerated.
+
+2004-11-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * getpass.m4, setenv.m4: Update from GNULIB.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * allocsa.m4, eealloc.m4, setenv.m4: New files from GNULIB.
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * bison.m4 (gl_BISON): Update comment to eliminate new spaces from
+ generated configure script.
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * bison.m4 (gl_BISON): Update comment to specify an Automake version
+ number, rather than Autoconf.
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * bison.m4 (gl_BISON): Comment reasons for forking form GNULIB.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * rpmatch.m4, yesno.m4: New files from GNULIB.
+
+2004-10-22 Derek Price <derek@ximbiot.com>
+
+ * md5.m4, uint32_t.m4: New files from GNULIB.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * rpmatch.m4, yesno.m4: Back out addition.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * rpmatch.m4, yesno.m4: New files from GNULIB.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * getpagesize.m4: New file from GNULIB.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * realloc.m4: Remove this file.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * malloc.m4: Remove this file.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * sunos57-select.m4: New file. Work around Solaris 7 select()
+ hang.
+
+2004-10-18 Derek Price <derek@ximbiot.com>
+
+ * getopt.m4: Update file from GNULIB.
+
+2004-10-15 Derek Price <derek@ximbiot.com>
+
+ * vasprintf.m4: New file from GNULIB.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * lstat.m4: Update from GNULIB.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * stat.m4: Update from GNULIB.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore, Makefile.am, Makefile.in: Remove.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * getpass.m4: Update from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * strcase.m4: New file from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * ssize_t.m4: Update from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * stdbool.m4: Update from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * getopt.m4: Update from GNULIB.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * mkstemp.m4: Update from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * fnmatch.m4: Update from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * dirname.m4, dos.m4: Updated from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add gnulib.m4.
+ * gnulib.m4: New file.
+ * xalloc.m4: Update from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new and previously missing files.
+ * eoverflow.m4, intmax.m4, printf-posix.m4: New files from GNULIB.
+ * gettext.m4, glibc21.m4, intmax_t.m4, inttypes_h.m4, lib-ld.m4,
+ lib-link.m4, lib-prefix.m4, longlong.m4, po.m4, stdint_h.m4,
+ uintmax_t.m4, ulonglong.m4, vasnprintf.m4: Import most recent versions
+ from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * save-cwd.m4: New file from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * alloca.m4: Import latest version from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * unlocked-io.m4: Import most recent version from GNULIB.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * regex.m4: Import most recent version from GNULIB.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add strftime.m4.
+ * strftime.m4: New file.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add tzset.m4.
+
+2004-05-14 Derek Price <derek@ximbiot.com>
+
+ * gettime.m4: Updated from GNULIB.
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * bison.m4: Declare YACC & YFLAGS as precious vars.
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * bison.m4: Use AM_MISSING_PROG rather than a set/subst combination.
+
+2004-05-02 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add strerror.m4 & strerror_r.m4.
+ * strerror_r.m4: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * unlocked-io.m4: Update to most recent version from GNULIB.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new files.
+ * bison.m4, tm_gmtoff.m4, getdate.m4: New files.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * mktime.m4: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * time_r.m4: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * nanosleep.m4: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new files.
+ * clock_time.m4, gettime.m4: New files.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * gettimeofday.m4: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * st_mtim.m4, timespec.m4: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * extensions.m4: New file.
+ * Makefile.in: Regenerated.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * dos.m4: Update from GNULIB.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ Add dirname module from GNULIB.
+
+ * Makefile.am (EXTRA_DIST): Add new files.
+ * dirname.m4, dos.m4: New files.
+ * Makefile.in: Regenerated.
+
+2004-04-21 Derek Price <derek@ximbiot.com>
+
+ Add stdbool module from GNULIB.
+
+ * Makefile.am (EXTRA_DIST): Add stdbool.m4.
+ * stdbool.m4: New files.
+ * Makefile.in: Regenerated.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ Update to current fnmatch module from GNULIB.
+
+ * Makefile.am (EXTRA_DIST): Add fnmatch.m4 * mbstate_t.m4.
+ * fnmatch.m4, mbstate_t.m4: New files.
+ * Makefile.in: Regenerated.
+
+2004-04-07 Derek Price <derek@ximbiot.com>
+
+ Update regex module from GNULIB.
+
+ * Makefile.am (EXTRA_DIST): Add regex.m4.
+ * regex.m4: New file.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ Import xalloc module from GNULIB, as well as its remaining unimported
+ dependency, the exitfail module.
+
+ * Makefile.am (EXTRA_DIST): Add exitfail.m4 & xalloc.m4.
+ * exitfail.m4, xalloc.m4: New files.
+ * Makefile.in: Regenerated.
+
+2004-02-18 Derek Price <derek@ximbiot.com>
+
+ * xsize.m4: Update to a more recent version which AC_REQUIREs
+ AC_C_INLINE.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add alloca.m4.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import vasnprintf module from GNULIB.
+ * intmax_t.m4, longdouble.m4, longlong.m4, signed.m4, vasnprintf.m4,
+ wchar_t.m4, wint_t.m4: New files.
+ * Makefile.am (EXTRA_DIST): Add new files.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import xsize module from GNULIB for vasnprintf().
+ * size_max.m4, xsize.m4: New files.
+ * Makefile.am (EXTRA_DIST): Add new files.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Import alloca module from GNULIB for vasnprintf().
+ * alloca.m4: New file.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-11-19 Derek Price <derek@ximbiot.com>
+
+ * getline.m4, getndelim2.m4: Import new, synchronized, versions from
+ GNULIB.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * acx_extract_cpp_defn.m4 (ACX_EXTRACT_CPP_DEFN): Remove leading and
+ trailing white space around extracted definitions.
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+2003-10-23 Derek Price <derek@ximbiot.com>
+
+ Avoid including getndelim.o in $(LIBOBJ) twice.
+
+ * getndelim2.m4 (gl_GETNDELIM2): Only allow AC_LIBOBJ(getndelim2) to be
+ called once.
+ * getline.m4 (gl_GETLINE): Use gl_GETNDELIM2 rather than calling
+ AC_LIBOBJ(getndelim2) directly.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ Add the GNULIB restrict module.
+
+ * Makefile.am (EXTRA_DIST): Add restrict.m4.
+ * restrict.m4: New file.
+ * Makefile.in: Regenerated.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add getopt.m4.
+ * getopt.m4: New file from GNULIB.
+ * Makefile.in: Regenerated.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * gettext.m4: Don't check for headers we assume per the notes in
+ HACKING.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ Provide an atexit() function on systems which provide on_exit() but not
+ atexit().
+
+ * Makefile.am (EXTRA_DIST): Add atexit.m4.
+ * atexit.m4: New file.
+ * Makefile.in: Regenerated.
+
+2003-08-11 Derek Price <derek@ximbiot.com>
+
+ * getndelim2: Update from GNULIB to eliminate warning.
+
+2003-07-31 Derek Price <derek@ximbiot.com>
+
+ * getpass.m4: Update from GNULIB.
+
+2003-07-29 Derek Price <derek@ximbiot.com>
+
+ * getpass.m4: New file from GNULIB.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * getline.m4: Sync this file with GNULIB.
+
+2003-07-24 Derek Price <derek@ximbiot.com>
+
+ * gethostname.m4: New file from GNULIB.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * gettext.m4: Assume the existance of <limits.h> & <stddef.h> per C89.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * strerror.m4: New file from GNULIB.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * memmove.m4: New file from GNULIB.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * lstat.m4: Call the *_ONCE functions. This almost syncs us with
+ GNULIB.
+
+2003-07-19 Derek Price <derek@ximbiot.com>
+
+ * getline.m4: Merge more of Bruno Habile's GNULIB changes to this file
+ so our fork is less divergent.
+ * getndelim2.m4: Ditto.
+ * getnline.m4: Ditto.
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * getline.m4 (gl_PREREQ_GETLINE): s/gl_FUNC_GETNDELIM2/gl_GETNDELIM2/.
+ * getnline.m4 (gl_FUNC_GETNLINE): Rename to...
+ (gl_GETNLINE): ...this and s/gl_FUNC_GETNDELIM2/gl_GETNDELIM2/.
+ * getndelim2.m4 (gl_FUNC_GETNDELIM2): Rename to...
+ (gl_GETNDELIM2): ...this.
+ (Merging some of Bruno Habile's changes from GNULIB.)
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * getndelim2.m4: New file.
+ * ssize_t.m4: Ditto.
+
+ * getline.m4: Depend on getndelim2 rather than getnline.
+ * getnline.m4: Depend on getndelim2.
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * getline.m4 (AM_FUNC_GETLINE): Define HAVE_GETDELIM when a working
+ GNU getline() is found.
+ (Thanks again to Steve McIntyre <stevem@cvshome.org> for the report.)
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * pathmax.m4: New file.
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * Makefile.in: Regenerated.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * getline.m4: New file based on GNULIB and resubmitted to GNULIB.
+ * getnline.m4: Ditto.
+
+ * Makefile.am (EXTRA_DIST): Add new files.
+
+ * Makefile.in: Regenerated.
+
+2003-07-15 Derek Price <derek@ximbiot.com>
+
+ * unlocked-io.m4: Use the onceonly_2_57.m4 functions. This syncs us
+ with GNULIB.
+
+2003-06-16 Derek Price <derek@ximbiot.com>
+
+ * acx_with_external_zlib.m4: Fix minor typo that was preventing
+ --with-external-zlib from linking.
+ (Patch from Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>.)
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * onceonly_2_57.m4: New file.
+ * Makefile.am (EXTRA_DIST): Add new file.
+
+ * Makefile.in: Regenerated.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * mkstemp.m4: New file.
+ * Makefile.am (EXTRA_DIST): Add new file.
+
+ * Makefile.in: Regenerated.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * asx_version_compare.c: Check for empty strings in version subparts.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new files and a few forgotten files.
+
+ * codeset.m4: New gettext support macros.
+ * gettext.m4: Ditto.
+ * glibc21.m4: Ditto.
+ * iconv.m4: Ditto.
+ * intdiv0.m4: Ditto.
+ * inttypes-pri.m4: Ditto.
+ * inttypes.m4: Ditto.
+ * inttypes_h.m4: Ditto.
+ * isc-posix.m4: Ditto.
+ * lcmessage.m4: Ditto.
+ * lib-ld.m4: Ditto.
+ * lib-link.m4: Ditto.
+ * lib-prefix.m4: Ditto.
+ * nls.m4: Ditto.
+ * po.m4: Ditto.
+ * progtest.m4: Ditto.
+ * stdint_h.m4: Ditto.
+ * uintmax_t.m4: Ditto.
+ * ulonglong.m4: Ditto.
+
+ * Makefile.in: Regenerated.
+
+2003-05-28 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated with README included in DIST_COMMON.
+
+2003-05-27 Derek Price <derek@ximbiot.com>
+
+ * README: New file explaining the GNULIB origin of many of the m4
+ files.
+
+2003-05-22 Derek Price <derek@ximbiot.com>
+
+ * acx_with_external_zlib.m4: Check version of unused ZLIBs and warn
+ when they are newer than the selected version.
+ * acx_extract_cpp_defn.m4: New file.
+ * asx_version_compare.m4: Ditto.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Autoconf version 1.7.5.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * unlocked-io.m4: New file from GNULIB.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * realloc.m4: New file from GNULIB.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * lstat.m4 (jm_FUNC_LSTAT): Add check for the lstat directory with a
+ trailing slash bug.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * acx_with_external_zlib.m4 (--with-external-zlib): New file with new
+ ACX_WITH_SYSTEM_VLIB function to use the system's installed version of
+ zlib library.
+ (Original patch from Anthon Pang <apang@telus.net>.)
+
+ * Makefile.am (EXTRA_DIST): Add new file.
+ * Makefile.in: Regenerated.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): s/acx_have_gssapi.m4/acx_with_gssapi.m4/.
+
+ * Makefile.in: Regenerated.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: New file.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (EXTRA_DIST): Add stat.m4, lstat.m4, malloc.m4.
+ * malloc.m4: New file from <https://savannah.gnu.org/projects/gnulib>.
+
+ * Makefile.in: Regenerated.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * lstat.m4: New file from
+ <https://savannah.gnu.org/projects/gnulib>.
+ * stat.m4: Ditto.
+
+ * Makefile.in: Regenerated.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: New file.
+ * acx_have_gssapi.m4: Ditto.
+ * cvs_func_printf_ptr.m4: Ditto.
diff --git a/m4/README b/m4/README
new file mode 100644
index 0000000..0cbeab7
--- /dev/null
+++ b/m4/README
@@ -0,0 +1,9 @@
+Many of the macro files in this directory come from the GNULIB project
+<http://savannah.gnu.org/projects/gnulib/>/<mailto:bug-gnulib@gnu.org>, and,
+if they don't, they should.
+
+What this means is that there is often at least one corresponding source file
+in the CVS/lib directory and that bug fixes and enhancements to this code
+should be sent to the GNULIB project and then reimported here after the GNULIB
+developers approve and adopt the change. Changes should not be made locally
+without good reason!
diff --git a/m4/acx_extract_cpp_defn.m4 b/m4/acx_extract_cpp_defn.m4
new file mode 100644
index 0000000..1fc0386
--- /dev/null
+++ b/m4/acx_extract_cpp_defn.m4
@@ -0,0 +1,62 @@
+# Extract data from preprocessor output using sed expresions.
+
+# Copyright (c) 2003
+# Derek R. Price, Ximbiot <http://ximbiot.com>,
+# and the Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# ACX_EXTRACT_CPP_DEFN(VARIABLE, PROGRAM,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Extract single line definitions from preprocessor output. If the
+# output of the C preprocessor on PROGRAM contains a definition for VARIABLE,
+# assign it to shell variable VARIABLE and run ACTION-IF-FOUND. Otherwise run
+# ACTION-IF-NOT-FOUND.
+AC_DEFUN([ACX_EXTRACT_CPP_DEFN],
+[AC_LANG_PREPROC_REQUIRE()dnl
+AC_LANG_CONFTEST([AC_LANG_SOURCE([[$2]])])
+dnl eval is necessary to expand ac_cpp.
+dnl Ultrix and Pyramid sh refuse to redirect output of eval, so use subshell.
+ac_extract_cpp_result=`(eval "$ac_cpp -dM conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD |
+dnl m4 quote the argument to sed to prevent m4 from eating character classes
+dnl
+dnl C89 6.8.3 Specifies that all whitespace separation in macro definitions is
+dnl equivalent, so eat leading and trailing whitespace to account for
+dnl preprocessor quirks (commands 1.2 & 1.3 in the sed script below).
+ sed -n ["/^#define $1 /{
+ s/^#define $1 //;
+ s/^ *//;
+ s/ *\$//;
+ p;}"] 2>&AS_MESSAGE_LOG_FD`
+if test -n "$ac_extract_cpp_result"; then
+ $1=$ac_extract_cpp_result
+m4_ifvaln([$3], [$3])dnl
+m4_ifvaln([$4], [else
+ $4])dnl
+fi
+rm -f conftest*
+])# ACX_EXTRACT_CPP_DEFN
+
+
+
+# ACX_EXTRACT_HEADER_DEFN(VARIABLE, HEADER-FILE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# ---------------------------------------------------------
+AC_DEFUN([ACX_EXTRACT_HEADER_DEFN],
+[ACX_EXTRACT_CPP_DEFN([$1],
+[#include <$2>
+], [$3], [$4])])
diff --git a/m4/acx_with_external_zlib.m4 b/m4/acx_with_external_zlib.m4
new file mode 100644
index 0000000..11a5af3
--- /dev/null
+++ b/m4/acx_with_external_zlib.m4
@@ -0,0 +1,180 @@
+# Allow the builder to specify an external ZLIB rather than the version
+# distributed with CVS.
+
+# Copyright (c) 2003
+# Anthon Pang <apang@telux.net>,
+# Derek R. Price, Ximbiot <http://ximbiot.com>,
+# and the Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# ACX_WITH_EXTERNAL_ZLIB
+# -------------------
+# Determine which ZLIB to use.
+AC_DEFUN([ACX_WITH_EXTERNAL_ZLIB],[
+#
+# Use --with-zlib to build with a zlib other than the version distributed
+# with CVS.
+#
+# defaults to the included snapshot of zlib
+#
+AC_ARG_WITH([external-zlib],
+ AC_HELP_STRING([--with-external-zlib],
+ [Use the specified ZLIB library (defaults to
+ the version distributed with the CVS source)]),
+ [with_external_zlib=$withval],
+ [with_external_zlib=no])
+
+#
+# Try to locate a ZLIB installation if no location was specified, assuming
+# external ZLIB was enabled.
+#
+if test -n "$acx_zlib_cv_external_zlib"; then
+ # Granted, this is a slightly ugly way to print this info, but the
+ # AC_CHECK_HEADER used in the search for a ZLIB installation makes using
+ # AC_CACHE_CHECK worse
+ AC_MSG_CHECKING([for external ZLIB])
+else :; fi
+AC_CACHE_VAL([acx_zlib_cv_external_zlib], [
+ #
+ # --with but no location specified
+ # assume zlib.h locates our install.
+ #
+ acx_zlib_save_CPPFLAGS=$CPPFLAGS
+ for acx_zlib_cv_external_zlib in yes /usr/local no; do
+ if test x$acx_zlib_cv_external_zlib = xno; then
+ break
+ fi
+ if test x$acx_zlib_cv_external_zlib = xyes; then
+ AC_MSG_CHECKING([for external ZLIB])
+ AC_MSG_RESULT([])
+ else
+ CPPFLAGS="$acx_zlib_save_CPPFLAGS -I$acx_zlib_cv_external_zlib/include"
+ AC_MSG_CHECKING([for external ZLIB in $acx_zlib_cv_external_zlib])
+ AC_MSG_RESULT([])
+ fi
+ unset ac_cv_header_zlib_h
+ AC_CHECK_HEADERS([zlib.h])
+ if test "$ac_cv_header_zlib_h" = yes; then
+ break
+ fi
+ done
+ CPPFLAGS=$acx_zlib_save_CPPFLAGS
+AC_MSG_CHECKING([for external ZLIB])
+])dnl
+AC_MSG_RESULT([$acx_zlib_cv_external_zlib])
+
+
+#
+# Output a pretty message naming our selected ZLIB "external" or "package"
+# so that any warnings printed by the version check make more sense.
+#
+AC_MSG_CHECKING([selected ZLIB])
+if test "x$with_external_zlib" = xno; then
+ AC_MSG_RESULT([package])
+else
+ AC_MSG_RESULT([external])
+fi
+
+
+#
+# Verify that the ZLIB we aren't using isn't newer than the one we are.
+#
+if test "x$acx_zlib_cv_external_zlib" != xno; then
+ LOCAL_ZLIB_VERSION=`sed -n '/^#define ZLIB_VERSION ".*"$/{
+ s/^#define ZLIB_VERSION "\(.*\)"$/\1/;
+ p;}' <$srcdir/zlib/zlib.h 2>&AS_MESSAGE_LOG_FD`
+ ACX_EXTRACT_HEADER_DEFN([ZLIB_VERSION], [zlib.h])
+ ZLIB_VERSION=`echo "$ZLIB_VERSION" |sed 's/"//g'`
+ ASX_VERSION_COMPARE([$LOCAL_ZLIB_VERSION], [$ZLIB_VERSION],
+ [if test "x$with_external_zlib" = xno; then
+ AC_MSG_WARN(
+ [Found external ZLIB with a more recent version than the
+ package version ($ZLIB_VERSION > $LOCAL_ZLIB_VERSION). configure with the
+ --with-external-zlib option to select the more recent version.])
+ fi],
+ [],
+ [if test "x$with_external_zlib" != xno; then
+ AC_MSG_WARN(
+ [Package ZLIB is more recent than requested external version
+ ($LOCAL_ZLIB_VERSION > $ZLIB_VERSION). configure with the --without-external-zlib
+ option to select the more recent version.])
+ fi])
+fi
+
+
+# Now set with_external_zlib to our discovered value or the user specified
+# value, as appropriate.
+if test x$with_external_zlib = xyes; then
+ with_external_zlib=$acx_zlib_cv_external_zlib
+fi
+# $with_external_zlib could still be "no"
+
+
+#
+# Set up ZLIB includes for later use.
+#
+if test x$with_external_zlib != xyes \
+ && test x$with_external_zlib != no; then
+ if test -z "$CPPFLAGS"; then
+ CPPFLAGS="-I$with_external_zlib/include"
+ else
+ CPPFLAGS="$CPPFLAGS -I$with_external_zlib/include"
+ fi
+ if test -z "$LDFLAGS"; then
+ LDFLAGS="-L$with_external_zlib/lib"
+ else
+ LDFLAGS="$LDFLAGS -L$with_external_zlib/lib"
+ fi
+fi
+
+ZLIB_CPPFLAGS=
+ZLIB_LIBS=
+ZLIB_SUBDIRS=
+if test x$with_external_zlib = xno; then
+ # We need ZLIB_CPPFLAGS so that later executions of cpp from configure
+ # don't try to interpret $(top_srcdir)
+ ZLIB_CPPFLAGS='-I$(top_srcdir)/zlib'
+ ZLIB_LIBS='$(top_builddir)/zlib/libz.a'
+ # ZLIB_SUBDIRS is only used in the top level Makefiles.
+ ZLIB_SUBDIRS=zlib
+else
+ # We know what to do now, so set up the CPPFLAGS, LDFLAGS, and LIBS for later
+ # use.
+ if test -z "$LIBS"; then
+ LIBS=-lz
+ else
+ LIBS="$LIBS -lz"
+ fi
+
+ #
+ # Verify external installed zlib works
+ #
+ # Ideally, we would also check that the version is newer
+ #
+ AC_MSG_CHECKING([that ZLIB library works])
+ AC_TRY_LINK([#include <zlib.h>],
+ [int i = Z_OK; const char *version = zlibVersion();],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([ZLIB failed to link])])
+fi
+
+dnl Subst for the local case
+AC_SUBST(ZLIB_SUBDIRS)dnl
+AC_SUBST(ZLIB_CPPFLAGS)dnl
+AC_SUBST(ZLIB_LIBS)dnl
+])
diff --git a/m4/acx_with_gssapi.m4 b/m4/acx_with_gssapi.m4
new file mode 100644
index 0000000..1d186b4
--- /dev/null
+++ b/m4/acx_with_gssapi.m4
@@ -0,0 +1,286 @@
+# Determine whether this platform supports GSSAPI.
+
+# Copyright (c) 2001, 2002, 2003
+# Derek R. Price, Ximbiot <http://ximbiot.com>,
+# and the Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# ACX_WITH_GSSAPI
+# -------------------
+# Determine whether this platform supports GSSAPI.
+AC_DEFUN([ACX_WITH_GSSAPI],[
+#
+# Use --with-gssapi[=DIR] to enable GSSAPI support.
+#
+# defaults to enabled with DIR in default list below
+#
+# Search for /SUNHEA/ and read the comments about this default below.
+#
+AC_ARG_WITH(
+ [gssapi],
+ AC_HELP_STRING(
+ [--with-gssapi],
+ [GSSAPI directory (default autoselects)]), ,
+ [with_gssapi=yes])dnl
+
+dnl
+dnl FIXME - cache withval and obliterate later cache values when options change
+dnl
+#
+# Try to locate a GSSAPI installation if no location was specified, assuming
+# GSSAPI was enabled (the default).
+#
+if test -n "$acx_gssapi_cv_gssapi"; then
+ # Granted, this is a slightly ugly way to print this info, but the
+ # AC_CHECK_HEADER used in the search for a GSSAPI installation makes using
+ # AC_CACHE_CHECK worse
+ AC_MSG_CHECKING([for GSSAPI])
+else :; fi
+AC_CACHE_VAL([acx_gssapi_cv_gssapi], [
+if test x$with_gssapi = xyes; then
+ # --with but no location specified
+ # assume a gssapi.h or gssapi/gssapi.h locates our install.
+ #
+ # This isn't always strictly true. For instance Solaris 7's SUNHEA (header)
+ # package installs gssapi.h whether or not the necessary libraries are
+ # installed. I'm still not sure whether to consider this a bug. The long
+ # way around is to not consider GSSPAI installed unless gss_import_name is
+ # found, but that brings up a lot of other hassles, like continuing to let
+ # gcc & ld generate the error messages when the user uses --with-gssapi=dir
+ # as a debugging aid. The short way around is to disable GSSAPI by default,
+ # but I think Sun users have been faced with this for awhile and I haven't
+ # heard many complaints.
+ acx_gssapi_save_CPPFLAGS=$CPPFLAGS
+ for acx_gssapi_cv_gssapi in yes /usr/kerberos /usr/cygnus/kerbnet no; do
+ if test x$acx_gssapi_cv_gssapi = xno; then
+ break
+ fi
+ if test x$acx_gssapi_cv_gssapi = xyes; then
+ AC_MSG_CHECKING([for GSSAPI])
+ AC_MSG_RESULT([])
+ else
+ CPPFLAGS="$acx_gssapi_save_CPPFLAGS -I$acx_gssapi_cv_gssapi/include"
+ AC_MSG_CHECKING([for GSSAPI in $acx_gssapi_cv_gssapi])
+ AC_MSG_RESULT([])
+ fi
+ unset ac_cv_header_gssapi_h
+ unset ac_cv_header_gssapi_gssapi_h
+ unset ac_cv_header_krb5_h
+ AC_CHECK_HEADERS([gssapi.h gssapi/gssapi.h krb5.h])
+ if (test "$ac_cv_header_gssapi_h" = yes ||
+ test "$ac_cv_header_gssapi_gssapi_h" = yes) &&
+ test "$ac_cv_header_krb5_h" = yes; then
+ break
+ fi
+ done
+ CPPFLAGS=$acx_gssapi_save_CPPFLAGS
+else
+ acx_gssapi_cv_gssapi=$with_gssapi
+fi
+AC_MSG_CHECKING([for GSSAPI])
+])dnl
+AC_MSG_RESULT([$acx_gssapi_cv_gssapi])
+
+#
+# Set up GSSAPI includes for later use. We don't bother to check for
+# $acx_gssapi_cv_gssapi=no here since that will be caught later.
+#
+if test x$acx_gssapi_cv_gssapi = xyes; then
+ # no special includes necessary
+ GSSAPI_INCLUDES=""
+else
+ # GSSAPI at $acx_gssapi_cv_gssapi (could be 'no')
+ GSSAPI_INCLUDES=" -I$acx_gssapi_cv_gssapi/include"
+fi
+
+#
+# Get the rest of the information CVS needs to compile with GSSAPI support
+#
+if test x$acx_gssapi_cv_gssapi != xno; then
+ # define HAVE_GSSAPI and set up the includes
+ AC_DEFINE([HAVE_GSSAPI], ,
+[Define if you have GSSAPI with Kerberos version 5 available.])
+ CPPFLAGS=$CPPFLAGS$GSSAPI_INCLUDES
+
+ cvs_client_objects="$cvs_client_objects gssapi-client.o"
+
+ # locate any other headers
+ dnl We don't use HAVE_KRB5_H anywhere, but including it here might make it
+ dnl easier to spot errors by reading configure output
+ AC_CHECK_HEADERS([gssapi.h gssapi/gssapi.h gssapi/gssapi_generic.h krb5.h])
+ # And look through them for GSS_C_NT_HOSTBASED_SERVICE or its alternatives
+ AC_CACHE_CHECK(
+ [for GSS_C_NT_HOSTBASED_SERVICE],
+ [acx_gssapi_cv_gss_c_nt_hostbased_service],
+ [
+ acx_gssapi_cv_gss_c_nt_hostbased_service=no
+ if test "$ac_cv_header_gssapi_h" = "yes"; then
+ AC_EGREP_HEADER(
+ [GSS_C_NT_HOSTBASED_SERVICE], [gssapi.h],
+ [acx_gssapi_cv_gss_c_nt_hostbased_service=yes],
+ [
+ AC_EGREP_HEADER(
+ [gss_nt_service_name], [gssapi.h],
+ [acx_gssapi_cv_gss_c_nt_hostbased_service=gss_nt_service_name])
+ ])
+ fi
+ if test $acx_gssapi_cv_gss_c_nt_hostbased_service = no &&
+ test "$ac_cv_header_gssapi_gssapi_h" = "yes"; then
+ AC_EGREP_HEADER(
+ [GSS_C_NT_HOSTBASED_SERVICE], [gssapi/gssapi.h],
+ [acx_gssapi_cv_gss_c_nt_hostbased_service=yes],
+ [
+ AC_EGREP_HEADER([gss_nt_service_name], [gssapi/gssapi.h],
+ [acx_gssapi_cv_gss_c_nt_hostbased_service=gss_nt_service_name])
+ ])
+ else :; fi
+ if test $acx_gssapi_cv_gss_c_nt_hostbased_service = no &&
+ test "$ac_cv_header_gssapi_gssapi_generic_h" = "yes"; then
+ AC_EGREP_HEADER(
+ [GSS_C_NT_HOSTBASED_SERVICE], [gssapi/gssapi_generic.h],
+ [acx_gssapi_cv_gss_c_nt_hostbased_service=yes],
+ [
+ AC_EGREP_HEADER(
+ [gss_nt_service_name], [gssapi/gssapi_generic.h],
+ [acx_gssapi_cv_gss_c_nt_hostbased_service=gss_nt_service_name])
+ ])
+ else :; fi
+ ])
+ if test $acx_gssapi_cv_gss_c_nt_hostbased_service != yes &&
+ test $acx_gssapi_cv_gss_c_nt_hostbased_service != no; then
+ # don't define for yes since that means it already means something and
+ # don't define for no since we'd rather the compiler catch the error
+ # It's debatable whether we'd prefer that the compiler catch the error
+ # - it seems our estranged developer is more likely to be familiar with
+ # the intricacies of the compiler than with those of autoconf, but by
+ # the same token, maybe we'd rather alert them to the fact that most
+ # of the support they need to fix the problem is installed if they can
+ # simply locate the appropriate symbol.
+ AC_DEFINE_UNQUOTED(
+ [GSS_C_NT_HOSTBASED_SERVICE],
+ [$acx_gssapi_cv_gss_c_nt_hostbased_service],
+[Define to an alternative value if GSS_C_NT_HOSTBASED_SERVICE isn't defined
+in the gssapi.h header file. MIT Kerberos 1.2.1 requires this. Only relevant
+when using GSSAPI.])
+ else :; fi
+
+ # Expect the libs to be installed parallel to the headers
+ #
+ # We could try once with and once without, but I'm not sure it's worth the
+ # trouble.
+ if test x$acx_gssapi_cv_gssapi != xyes; then
+ if test -z "$LIBS"; then
+ LIBS="-L$acx_gssapi_cv_gssapi/lib"
+ else
+ LIBS="-L$acx_gssapi_cv_gssapi/lib $LIBS"
+ fi
+ else :; fi
+
+ dnl What happens if we want to enable, say, krb5 and some other GSSAPI
+ dnl authentication method at the same time?
+ #
+ # Some of the order below is particular due to library dependencies
+ #
+
+ #
+ # des Heimdal K 0.3d, but Heimdal seems to be set up such
+ # that it could have been installed from elsewhere.
+ #
+ AC_SEARCH_LIBS([des_set_odd_parity], [des])
+
+ #
+ # com_err Heimdal K 0.3d
+ #
+ # com_err MIT K5 v1.2.2-beta1
+ #
+ AC_SEARCH_LIBS([com_err], [com_err])
+
+ #
+ # asn1 Heimdal K 0.3d -lcom_err
+ #
+ AC_SEARCH_LIBS([initialize_asn1_error_table_r], [asn1])
+
+ #
+ # resolv required, but not installed by Heimdal K 0.3d
+ #
+ # resolv MIT K5 1.2.2-beta1
+ # Linux 2.2.17
+ #
+ AC_SEARCH_LIBS([__dn_expand], [resolv])
+
+ #
+ # crypto Need by gssapi under FreeBSD 5.4
+ #
+ AC_SEARCH_LIBS([RC4], [crypto])
+
+ #
+ # crypt Needed by roken under FreeBSD 4.6.
+ #
+ AC_SEARCH_LIBS([crypt], [crypt])
+
+ #
+ # roken Heimdal K 0.3d -lresolv
+ # roken FreeBSD 4.6 -lcrypt
+ #
+ AC_SEARCH_LIBS([roken_gethostbyaddr], [roken])
+
+ #
+ # k5crypto MIT K5 v1.2.2-beta1
+ #
+ AC_SEARCH_LIBS([valid_enctype], [k5crypto])
+
+ #
+ # gen ? ? ? Needed on Irix 5.3 with some
+ # Irix 5.3 version of Kerberos. I'm not
+ # sure which since Irix didn't
+ # get any testing this time
+ # around. Original comment:
+ #
+ # This is necessary on Irix 5.3, in order to link against libkrb5 --
+ # there, an_to_ln.o refers to things defined only in -lgen.
+ #
+ AC_SEARCH_LIBS([compile], [gen])
+
+ #
+ # krb5 ? ? ? -lgen -l???
+ # Irix 5.3
+ #
+ # krb5 MIT K5 v1.1.1
+ #
+ # krb5 MIT K5 v1.2.2-beta1 -lcrypto -lcom_err
+ # Linux 2.2.17
+ #
+ # krb5 MIT K5 v1.2.2-beta1 -lcrypto -lcom_err -lresolv
+ #
+ # krb5 Heimdal K 0.3d -lasn1 -lroken -ldes
+ #
+ AC_SEARCH_LIBS([krb5_free_context], [krb5])
+
+ #
+ # gssapi_krb5 Only lib needed with MIT K5 v1.2.1, so find it first in
+ # order to prefer MIT Kerberos. If both MIT & Heimdal
+ # Kerberos are installed and in the path, this will leave
+ # some of the libraries above in LIBS unnecessarily, but
+ # noone would ever do that, right?
+ #
+ # gssapi_krb5 MIT K5 v1.2.2-beta1 -lkrb5
+ #
+ # gssapi Heimdal K 0.3d -lkrb5
+ #
+ AC_SEARCH_LIBS([gss_import_name], [gssapi_krb5 gssapi])
+fi
+])dnl
diff --git a/m4/alloca.m4 b/m4/alloca.m4
new file mode 100644
index 0000000..a9e3f45
--- /dev/null
+++ b/m4/alloca.m4
@@ -0,0 +1,42 @@
+# alloca.m4 serial 5
+dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_ALLOCA],
+[
+ dnl Work around a bug of AC_EGREP_CPP in autoconf-2.57.
+ AC_REQUIRE([AC_PROG_CPP])
+ AC_REQUIRE([AC_PROG_EGREP])
+
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ if test $ac_cv_func_alloca_works = no; then
+ gl_PREREQ_ALLOCA
+ fi
+
+ # Define an additional variable used in the Makefile substitution.
+ if test $ac_cv_working_alloca_h = yes; then
+ AC_EGREP_CPP([Need own alloca], [
+#if defined __GNUC__ || defined _AIX || defined _MSC_VER
+ Need own alloca
+#endif
+ ],
+ [AC_DEFINE(HAVE_ALLOCA, 1,
+ [Define to 1 if you have `alloca' after including <alloca.h>,
+ a header that may be supplied by this distribution.])
+ ALLOCA_H=alloca.h],
+ [ALLOCA_H=])
+ else
+ ALLOCA_H=alloca.h
+ fi
+ AC_SUBST([ALLOCA_H])
+
+ AC_DEFINE(HAVE_ALLOCA_H, 1,
+ [Define HAVE_ALLOCA_H for backward compatibility with older code
+ that includes <alloca.h> only if HAVE_ALLOCA_H is defined.])
+])
+
+# Prerequisites of lib/alloca.c.
+# STACK_DIRECTION is already handled by AC_FUNC_ALLOCA.
+AC_DEFUN([gl_PREREQ_ALLOCA], [:])
diff --git a/m4/allocsa.m4 b/m4/allocsa.m4
new file mode 100644
index 0000000..474862f
--- /dev/null
+++ b/m4/allocsa.m4
@@ -0,0 +1,15 @@
+# allocsa.m4 serial 3
+dnl Copyright (C) 2003-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_ALLOCSA],
+[
+ dnl Use the autoconf tests for alloca(), but not the AC_SUBSTed variables
+ dnl @ALLOCA@ and @LTALLOCA@.
+ AC_REQUIRE([gl_FUNC_ALLOCA])
+ AC_REQUIRE([gl_EEMALLOC])
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+])
diff --git a/m4/asx_version_compare.m4 b/m4/asx_version_compare.m4
new file mode 100644
index 0000000..4f06310
--- /dev/null
+++ b/m4/asx_version_compare.m4
@@ -0,0 +1,65 @@
+# Compare two strings possibly containing shell variables as version strings.
+
+# Copyright (c) 2003
+# Derek R. Price, Ximbiot <http://ximbiot.com>,
+# and the Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# ASX_VERSION_COMPARE(VERSION-1, VERSION-2,
+# [ACTION-IF-LESS], [ACTION-IF-EQUAL], [ACTION-IF-GREATER])
+# -----------------------------------------------------------------------------
+# Compare two strings possibly containing shell variables as version strings.
+AC_DEFUN([ASX_VERSION_COMPARE],
+[if test "x[$1]" = "x[$2]"; then
+ # the strings are equal. run ACTION-IF-EQUAL and bail
+ m4_default([$4], :)
+m4_ifvaln([$3$5], [else
+ # first unletter the versions
+ # this only works for a single trailing letter
+ dnl echo has a double-quoted arg to allow for shell expansion.
+ asx_version_1=`echo "[$1]" |
+ sed 's/\([abcedfghi]\)/.\1/;
+ s/\([jklmnopqrs]\)/.1\1/;
+ s/\([tuvwxyz]\)/.2\1/;
+ y/abcdefghijklmnopqrstuvwxyz/12345678901234567890123456/;'`
+ asx_version_2=`echo "[$2]" |
+ sed 's/\([abcedfghi]\)/.\1/;
+ s/\([jklmnopqrs]\)/.1\1/;
+ s/\([tuvwxyz]\)/.2\1/;
+ y/abcdefghijklmnopqrstuvwxyz/12345678901234567890123456/;'`
+ asx_count=1
+ asx_save_IFS=$IFS
+ IFS=.
+ asx_retval=-1
+ for vsub1 in $asx_version_1; do
+ vsub2=`echo "$asx_version_2" |awk -F. "{print \\\$$asx_count}"`
+ if test -z "$vsub2" || test $vsub1 -gt $vsub2; then
+ asx_retval=1
+ break
+ elif test $vsub1 -lt $vsub2; then
+ break
+ fi
+ asx_count=`expr $asx_count + 1`
+ done
+ IFS=$asx_save_IFS
+ if test $asx_retval -eq -1; then
+ m4_default([$3], :)
+ m4_ifval([$5], [else
+$5])
+ fi])
+fi
+]) # ASX_VERSION_COMPARE
diff --git a/m4/atexit.m4 b/m4/atexit.m4
new file mode 100644
index 0000000..348912f
--- /dev/null
+++ b/m4/atexit.m4
@@ -0,0 +1,18 @@
+# atexit.m4 serial 2
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_ATEXIT],
+[
+ AC_REPLACE_FUNCS(atexit)
+ if test $ac_cv_func_atexit = no; then
+ gl_PREREQ_ATEXIT
+ fi
+])
+
+# Prerequisites of lib/atexit.c.
+AC_DEFUN([gl_PREREQ_ATEXIT], [
+ :
+])
diff --git a/m4/bison.m4 b/m4/bison.m4
new file mode 100644
index 0000000..949c850
--- /dev/null
+++ b/m4/bison.m4
@@ -0,0 +1,31 @@
+#serial 4
+
+# Copyright (C) 2002 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_BISON],
+[dnl
+dnl All this cruft, which tries to fail harmlessly when bison is not present,
+dnl will no longer be necessary after we require an Automake release 1.10 or
+dnl later, as those avoid generating .c files from .y when not in maintainer
+dnl mode. This is currently a fork from the GNULIB version of this file.
+ # expand $ac_aux_dir to an absolute path
+ am_aux_dir=`cd $ac_aux_dir && pwd`
+
+ # getdate.y works with bison only.
+ : ${YACC="\${SHELL} $am_aux_dir/bison-missing --run bison -y"}
+dnl
+dnl Declaring YACC & YFLAGS precious will not be necessary after GNULIB
+dnl requires an Autoconf greater than 2.59c, but it will probably still be
+dnl useful to override the description of YACC in the --help output, re
+dnl getdate.y assuming `bison -y'.
+ AC_ARG_VAR(YACC,
+[The `Yet Another C Compiler' implementation to use. Defaults to `bison -y'.
+Values other than `bison -y' will most likely break on most systems.])dnl
+ AC_ARG_VAR(YFLAGS,
+[YFLAGS contains the list arguments that will be passed by default to Bison.
+This script will default YFLAGS to the empty string to avoid a default value of
+`-d' given by some make applications.])dnl
+])
diff --git a/m4/canon-host.m4 b/m4/canon-host.m4
new file mode 100644
index 0000000..b416104
--- /dev/null
+++ b/m4/canon-host.m4
@@ -0,0 +1,16 @@
+# canon-host.m4 serial 7
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_CANON_HOST],
+[
+ AC_LIBSOURCES([canon-host.c, canon-host.h])
+ AC_LIBOBJ([canon-host])
+ gl_PREREQ_CANON_HOST
+])
+
+AC_DEFUN([gl_PREREQ_CANON_HOST], [
+ AC_REQUIRE([gl_GETADDRINFO])
+])
diff --git a/m4/canonicalize.m4 b/m4/canonicalize.m4
new file mode 100644
index 0000000..42c688a
--- /dev/null
+++ b/m4/canonicalize.m4
@@ -0,0 +1,18 @@
+#serial 8
+
+# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Jim Meyering.
+
+AC_DEFUN([AC_FUNC_CANONICALIZE_FILE_NAME],
+ [
+ AC_LIBSOURCES([canonicalize.c, canonicalize.h])
+ AC_LIBOBJ([canonicalize])
+
+ AC_REQUIRE([AC_HEADER_STDC])
+ AC_CHECK_HEADERS(string.h sys/param.h)
+ AC_CHECK_FUNCS(resolvepath canonicalize_file_name)
+ ])
diff --git a/m4/chdir-long.m4 b/m4/chdir-long.m4
new file mode 100644
index 0000000..9e9e35f
--- /dev/null
+++ b/m4/chdir-long.m4
@@ -0,0 +1,42 @@
+#serial 5
+
+# Use Gnulib's robust chdir function.
+# It can handle arbitrarily long directory names, which means
+# that when it is given the name of an existing directory, it
+# never fails with ENAMETOOLONG.
+# Arrange to compile chdir-long.c only on systems that define PATH_MAX.
+
+dnl Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Written by Jim Meyering.
+
+AC_DEFUN([gl_FUNC_CHDIR_LONG],
+[
+ AC_LIBSOURCES([chdir-long.c, chdir-long.h])
+ AC_CACHE_CHECK([whether this system has a definition of PATH_MAX],
+ gl_have_path_max_definition,
+ [AC_EGREP_CPP([have_path_max_definition],
+ [#include <unistd.h>
+#include <limits.h>
+#ifdef PATH_MAX
+have_path_max_definition
+#endif],
+ gl_have_path_max_definition=yes,
+ gl_have_path_max_definition=no)])
+
+ if test $gl_have_path_max_definition; then
+ AC_LIBOBJ([chdir-long])
+ gl_PREREQ_CHDIR_LONG
+ fi
+])
+
+AC_DEFUN([gl_PREREQ_CHDIR_LONG],
+[
+ AM_STDBOOL_H
+ gl_FUNC_MEMPCPY
+ gl_FUNC_OPENAT
+ gl_FUNC_MEMRCHR
+])
diff --git a/m4/clock_time.m4 b/m4/clock_time.m4
new file mode 100644
index 0000000..0cedfe4
--- /dev/null
+++ b/m4/clock_time.m4
@@ -0,0 +1,26 @@
+# clock_time.m4 serial 6
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Check for clock_gettime and clock_settime, and sets LIB_CLOCK_GETTIME.
+AC_DEFUN([gl_CLOCK_TIME],
+[
+ # dnl Persuade glibc <time.h> to declare these functions.
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
+ # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
+
+ # Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all*
+ # programs in the package would end up linked with that potentially-shared
+ # library, inducing unnecessary run-time overhead.
+ gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS(clock_gettime, [rt posix4],
+ [test "$ac_cv_search_clock_gettime" = "none required" ||
+ LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime])
+ AC_SUBST(LIB_CLOCK_GETTIME)
+ AC_CHECK_FUNCS(clock_gettime clock_settime)
+ LIBS=$gl_saved_libs
+])
diff --git a/m4/closeout.m4 b/m4/closeout.m4
new file mode 100644
index 0000000..8d3ead3
--- /dev/null
+++ b/m4/closeout.m4
@@ -0,0 +1,14 @@
+# closeout.m4 serial 4
+dnl Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_CLOSEOUT],
+[
+ AC_LIBSOURCES([closeout.c, closeout.h])
+ AC_LIBOBJ([closeout])
+
+ dnl Prerequisites of lib/closeout.c.
+ :
+])
diff --git a/m4/codeset.m4 b/m4/codeset.m4
new file mode 100644
index 0000000..a6e67ec
--- /dev/null
+++ b/m4/codeset.m4
@@ -0,0 +1,21 @@
+# codeset.m4 serial AM1 (gettext-0.10.40)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_LANGINFO_CODESET],
+[
+ AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset,
+ [AC_TRY_LINK([#include <langinfo.h>],
+ [char* cs = nl_langinfo(CODESET);],
+ am_cv_langinfo_codeset=yes,
+ am_cv_langinfo_codeset=no)
+ ])
+ if test $am_cv_langinfo_codeset = yes; then
+ AC_DEFINE(HAVE_LANGINFO_CODESET, 1,
+ [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
+ fi
+])
diff --git a/m4/cvs_func_printf_ptr.m4 b/m4/cvs_func_printf_ptr.m4
new file mode 100644
index 0000000..4348e29
--- /dev/null
+++ b/m4/cvs_func_printf_ptr.m4
@@ -0,0 +1,43 @@
+# Determine whether printf supports %p for printing pointers.
+
+# Copyright (c) 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# CVS_FUNC_PRINTF_PTR
+# -------------------
+# Determine whether printf supports %p for printing pointers.
+AC_DEFUN([CVS_FUNC_PRINTF_PTR],
+[AC_CACHE_CHECK(whether printf supports %p,
+ cvs_cv_func_printf_ptr,
+[AC_TRY_RUN([#include <stdio.h>
+/* If printf supports %p, exit 0. */
+int
+main ()
+{
+ void *p1, *p2;
+ char buf[256];
+ p1 = &p1; p2 = &p2;
+ sprintf(buf, "%p", p1);
+ exit(sscanf(buf, "%p", &p2) != 1 || p2 != p1);
+}], cvs_cv_func_printf_ptr=yes, cvs_cv_func_printf_ptr=no)
+rm -f core core.* *.core])
+if test $cvs_cv_func_printf_ptr = yes; then
+ AC_DEFINE(HAVE_PRINTF_PTR, 1,
+ [Define to 1 if the `printf' function supports the %p format
+ for printing pointers.])
+fi
+])# CVS_FUNC_PRINTF_PTR
diff --git a/m4/d-ino.m4 b/m4/d-ino.m4
new file mode 100644
index 0000000..4d2c4db
--- /dev/null
+++ b/m4/d-ino.m4
@@ -0,0 +1,49 @@
+#serial 7
+
+dnl From Jim Meyering.
+dnl
+dnl Check whether struct dirent has a member named d_ino.
+dnl
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004 Free Software
+# Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_CHECK_TYPE_STRUCT_DIRENT_D_INO],
+ [AC_REQUIRE([AC_HEADER_DIRENT])dnl
+ AC_CACHE_CHECK([for d_ino member in directory struct],
+ jm_cv_struct_dirent_d_ino,
+ [AC_TRY_LINK(dnl
+ [
+#include <sys/types.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#else /* not HAVE_DIRENT_H */
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+#endif /* HAVE_DIRENT_H */
+ ],
+ [struct dirent dp; dp.d_ino = 0;],
+
+ jm_cv_struct_dirent_d_ino=yes,
+ jm_cv_struct_dirent_d_ino=no)
+ ]
+ )
+ if test $jm_cv_struct_dirent_d_ino = yes; then
+ AC_DEFINE(D_INO_IN_DIRENT, 1,
+ [Define if there is a member named d_ino in the struct describing
+ directory headers.])
+ fi
+ ]
+)
diff --git a/m4/d-type.m4 b/m4/d-type.m4
new file mode 100644
index 0000000..6f3125c
--- /dev/null
+++ b/m4/d-type.m4
@@ -0,0 +1,49 @@
+#serial 8
+
+dnl From Jim Meyering.
+dnl
+dnl Check whether struct dirent has a member named d_type.
+dnl
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE],
+ [AC_REQUIRE([AC_HEADER_DIRENT])dnl
+ AC_CACHE_CHECK([for d_type member in directory struct],
+ jm_cv_struct_dirent_d_type,
+ [AC_TRY_LINK(dnl
+ [
+#include <sys/types.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#else /* not HAVE_DIRENT_H */
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+#endif /* HAVE_DIRENT_H */
+ ],
+ [struct dirent dp; dp.d_type = 0;],
+
+ jm_cv_struct_dirent_d_type=yes,
+ jm_cv_struct_dirent_d_type=no)
+ ]
+ )
+ if test $jm_cv_struct_dirent_d_type = yes; then
+ AC_DEFINE(HAVE_STRUCT_DIRENT_D_TYPE, 1,
+ [Define if there is a member named d_type in the struct describing
+ directory headers.])
+ fi
+ ]
+)
diff --git a/m4/dirname.m4 b/m4/dirname.m4
new file mode 100644
index 0000000..e36937d
--- /dev/null
+++ b/m4/dirname.m4
@@ -0,0 +1,16 @@
+# dirname.m4 serial 5
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_DIRNAME],
+[
+ AC_LIBSOURCES([dirname.c, dirname.h])
+ AC_LIBOBJ([dirname])
+
+ dnl Prerequisites of lib/dirname.h.
+ AC_REQUIRE([gl_AC_DOS])
+
+ dnl No prerequisites of lib/basename.c, lib/dirname.c, lib/stripslash.c.
+])
diff --git a/m4/dos.m4 b/m4/dos.m4
new file mode 100644
index 0000000..0713cf1
--- /dev/null
+++ b/m4/dos.m4
@@ -0,0 +1,58 @@
+#serial 9
+
+# Define some macros required for proper operation of code in lib/*.c
+# on MSDOS/Windows systems.
+
+# Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# From Jim Meyering.
+
+AC_DEFUN([gl_AC_DOS],
+ [
+ AC_CACHE_CHECK([whether system is Windows or MSDOS], [ac_cv_win_or_dos],
+ [
+ AC_TRY_COMPILE([],
+ [#if !defined _WIN32 && !defined __WIN32__ && !defined __MSDOS__ && !defined __CYGWIN__
+neither MSDOS nor Windows
+#endif],
+ [ac_cv_win_or_dos=yes],
+ [ac_cv_win_or_dos=no])
+ ])
+
+ if test x"$ac_cv_win_or_dos" = xyes; then
+ ac_fs_accepts_drive_letter_prefix=1
+ ac_fs_backslash_is_file_name_separator=1
+ else
+ ac_fs_accepts_drive_letter_prefix=0
+ ac_fs_backslash_is_file_name_separator=0
+ fi
+
+ AH_VERBATIM(FILE_SYSTEM_PREFIX_LEN,
+ [#if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+# define FILE_SYSTEM_PREFIX_LEN(Filename) \
+ ((Filename)[0] && (Filename)[1] == ':' ? 2 : 0)
+#else
+# define FILE_SYSTEM_PREFIX_LEN(Filename) 0
+#endif])
+
+ AC_DEFINE_UNQUOTED([FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX],
+ $ac_fs_accepts_drive_letter_prefix,
+ [Define on systems for which file names may have a so-called
+ `drive letter' prefix, define this to compute the length of that
+ prefix, including the colon.])
+
+ AH_VERBATIM(ISSLASH,
+ [#if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+#else
+# define ISSLASH(C) ((C) == '/')
+#endif])
+
+ AC_DEFINE_UNQUOTED([FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR],
+ $ac_fs_backslash_is_file_name_separator,
+ [Define if the backslash character may also serve as a file name
+ component separator.])
+ ])
diff --git a/m4/dup2.m4 b/m4/dup2.m4
new file mode 100644
index 0000000..31af804
--- /dev/null
+++ b/m4/dup2.m4
@@ -0,0 +1,18 @@
+#serial 3
+dnl Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_DUP2],
+[
+ AC_REPLACE_FUNCS(dup2)
+ if test $ac_cv_func_dup2 = no; then
+ gl_PREREQ_DUP2
+ fi
+])
+
+# Prerequisites of lib/dup2.c.
+AC_DEFUN([gl_PREREQ_DUP2], [
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+])
diff --git a/m4/eealloc.m4 b/m4/eealloc.m4
new file mode 100644
index 0000000..adcfd06
--- /dev/null
+++ b/m4/eealloc.m4
@@ -0,0 +1,32 @@
+# eealloc.m4 serial 1
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_EEALLOC],
+[
+ AC_REQUIRE([gl_EEMALLOC])
+ AC_REQUIRE([gl_EEREALLOC])
+ AC_REQUIRE([AC_C_INLINE])
+])
+
+AC_DEFUN([gl_EEMALLOC],
+[
+ _AC_FUNC_MALLOC_IF(
+ [gl_cv_func_malloc_0_nonnull=1],
+ [gl_cv_func_malloc_0_nonnull=0])
+ AC_DEFINE_UNQUOTED([MALLOC_0_IS_NONNULL], $gl_cv_func_malloc_0_nonnull,
+ [If malloc(0) is != NULL, define this to 1. Otherwise define this
+ to 0.])
+])
+
+AC_DEFUN([gl_EEREALLOC],
+[
+ _AC_FUNC_REALLOC_IF(
+ [gl_cv_func_realloc_0_nonnull=1],
+ [gl_cv_func_realloc_0_nonnull=0])
+ AC_DEFINE_UNQUOTED([REALLOC_0_IS_NONNULL], $gl_cv_func_realloc_0_nonnull,
+ [If realloc(NULL,0) is != NULL, define this to 1. Otherwise define this
+ to 0.])
+])
diff --git a/m4/eoverflow.m4 b/m4/eoverflow.m4
new file mode 100644
index 0000000..8c28ca3
--- /dev/null
+++ b/m4/eoverflow.m4
@@ -0,0 +1,64 @@
+# eoverflow.m4 serial 1
+dnl Copyright (C) 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+# The EOVERFLOW errno value ought to be defined in <errno.h>, according to
+# POSIX. But some systems (like AIX 3) don't define it, and some systems
+# (like OSF/1) define it when _XOPEN_SOURCE_EXTENDED is defined.
+
+# Define EOVERFLOW as a C macro and as a substituted macro in such a way that
+# 1. on all systems, after inclusion of <errno.h>, EOVERFLOW is usable,
+# 2. on systems where EOVERFLOW is defined elsewhere, we use the same numeric
+# value.
+
+AC_DEFUN([gl_EOVERFLOW],
+[
+ AC_REQUIRE([AC_PROG_CC])dnl
+
+ AC_CACHE_CHECK([for EOVERFLOW], ac_cv_decl_EOVERFLOW, [
+ AC_EGREP_CPP(yes,[
+#include <errno.h>
+#ifdef EOVERFLOW
+yes
+#endif
+ ], have_eoverflow=1)
+ if test -n "$have_eoverflow"; then
+ dnl EOVERFLOW exists in <errno.h>. Don't need to define EOVERFLOW ourselves.
+ ac_cv_decl_EOVERFLOW=yes
+ else
+ AC_EGREP_CPP(yes,[
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+#ifdef EOVERFLOW
+yes
+#endif
+ ], have_eoverflow=1)
+ if test -n "$have_eoverflow"; then
+ dnl EOVERFLOW exists but is hidden.
+ dnl Define it to the same value.
+ _AC_COMPUTE_INT([EOVERFLOW], ac_cv_decl_EOVERFLOW, [
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+])
+ else
+ dnl EOVERFLOW isn't defined by the system. Define EOVERFLOW ourselves, but
+ dnl don't define it as EINVAL, because snprintf() callers want to
+ dnl distinguish EINVAL and EOVERFLOW.
+ ac_cv_decl_EOVERFLOW=E2BIG
+ fi
+ fi
+ ])
+ if test "$ac_cv_decl_EOVERFLOW" != yes; then
+ AC_DEFINE_UNQUOTED([EOVERFLOW], [$ac_cv_decl_EOVERFLOW],
+ [Define as good substitute value for EOVERFLOW.])
+ EOVERFLOW="$ac_cv_decl_EOVERFLOW"
+ AC_SUBST(EOVERFLOW)
+ fi
+])
diff --git a/m4/error.m4 b/m4/error.m4
new file mode 100644
index 0000000..b9493fd
--- /dev/null
+++ b/m4/error.m4
@@ -0,0 +1,20 @@
+#serial 11
+
+# Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_ERROR],
+[
+ gl_PREREQ_ERROR
+])
+
+# Prerequisites of lib/error.c.
+AC_DEFUN([gl_PREREQ_ERROR],
+[
+ AC_REQUIRE([AC_FUNC_STRERROR_R])
+ :
+])
diff --git a/m4/exitfail.m4 b/m4/exitfail.m4
new file mode 100644
index 0000000..5523676
--- /dev/null
+++ b/m4/exitfail.m4
@@ -0,0 +1,14 @@
+# exitfail.m4 serial 5
+dnl Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_EXITFAIL],
+[
+ AC_LIBSOURCES([exitfail.c, exitfail.h])
+ AC_LIBOBJ([exitfail])
+
+ dnl No prerequisites of lib/exitfail.c.
+ :
+])
diff --git a/m4/extensions.m4 b/m4/extensions.m4
new file mode 100644
index 0000000..e71845f
--- /dev/null
+++ b/m4/extensions.m4
@@ -0,0 +1,30 @@
+# Enable extensions on systems that normally disable them.
+
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# gl_USE_SYSTEM_EXTENSIONS
+# ------------------------
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+AC_DEFUN([gl_USE_SYSTEM_EXTENSIONS], [
+ AC_BEFORE([$0], [AC_COMPILE_IFELSE])
+ AC_BEFORE([$0], [AC_RUN_IFELSE])
+
+ AC_REQUIRE([AC_GNU_SOURCE])
+ AC_REQUIRE([AC_AIX])
+ AC_REQUIRE([AC_MINIX])
+
+ AH_VERBATIM([__EXTENSIONS__],
+[/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif])
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+])
diff --git a/m4/filenamecat.m4 b/m4/filenamecat.m4
new file mode 100644
index 0000000..c75a57d
--- /dev/null
+++ b/m4/filenamecat.m4
@@ -0,0 +1,14 @@
+# filenamecat.m4 serial 7
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FILE_NAME_CONCAT],
+[
+ AC_LIBSOURCES([filenamecat.c, filenamecat.h])
+ AC_LIBOBJ([filenamecat])
+
+ dnl Prerequisites of lib/filenamecat.c.
+ AC_CHECK_FUNCS_ONCE(mempcpy)
+])
diff --git a/m4/fnmatch.m4 b/m4/fnmatch.m4
new file mode 100644
index 0000000..bca15ad
--- /dev/null
+++ b/m4/fnmatch.m4
@@ -0,0 +1,102 @@
+# Check for fnmatch.
+
+# This is a modified version of autoconf's AC_FUNC_FNMATCH.
+# This file should be simplified after Autoconf 2.57 is required.
+
+# Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AC_FUNC_FNMATCH_IF(STANDARD = GNU | POSIX, CACHE_VAR, IF-TRUE, IF-FALSE)
+# -------------------------------------------------------------------------
+# If a STANDARD compliant fnmatch is found, run IF-TRUE, otherwise
+# IF-FALSE. Use CACHE_VAR.
+AC_DEFUN([_AC_FUNC_FNMATCH_IF],
+[AC_CACHE_CHECK(
+ [for working $1 fnmatch],
+ [$2],
+ [dnl Some versions of Solaris, SCO, and the GNU C Library
+ dnl have a broken or incompatible fnmatch.
+ dnl So we run a test program. If we are cross-compiling, take no chance.
+ dnl Thanks to John Oleynick, François Pinard, and Paul Eggert for this test.
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [
+# include <stdlib.h>
+# include <fnmatch.h>
+# define y(a, b, c) (fnmatch (a, b, c) == 0)
+# define n(a, b, c) (fnmatch (a, b, c) == FNM_NOMATCH)
+ ],
+ [exit
+ (!(y ("a*", "abc", 0)
+ && n ("d*/*1", "d/s/1", FNM_PATHNAME)
+ && y ("a\\\\bc", "abc", 0)
+ && n ("a\\\\bc", "abc", FNM_NOESCAPE)
+ && y ("*x", ".x", 0)
+ && n ("*x", ".x", FNM_PERIOD)
+ && m4_if([$1], [GNU],
+ [y ("xxXX", "xXxX", FNM_CASEFOLD)
+ && y ("a++(x|yy)b", "a+xyyyyxb", FNM_EXTMATCH)
+ && n ("d*/*1", "d/s/1", FNM_FILE_NAME)
+ && y ("*", "x", FNM_FILE_NAME | FNM_LEADING_DIR)
+ && y ("x*", "x/y/z", FNM_FILE_NAME | FNM_LEADING_DIR)
+ && y ("*c*", "c/x", FNM_FILE_NAME | FNM_LEADING_DIR)],
+ 1)));])],
+ [$2=yes],
+ [$2=no],
+ [$2=cross])])
+AS_IF([test $$2 = yes], [$3], [$4])
+])# _AC_FUNC_FNMATCH_IF
+
+
+# _AC_LIBOBJ_FNMATCH
+# ------------------
+# Prepare the replacement of fnmatch.
+AC_DEFUN([_AC_LIBOBJ_FNMATCH],
+[AC_REQUIRE([AC_C_CONST])dnl
+AC_REQUIRE([AC_FUNC_ALLOCA])dnl
+AC_REQUIRE([AC_TYPE_MBSTATE_T])dnl
+AC_CHECK_DECLS([getenv])
+AC_CHECK_FUNCS([btowc mbsrtowcs mempcpy wmemchr wmemcpy wmempcpy])
+AC_CHECK_HEADERS([wchar.h wctype.h])
+AC_LIBOBJ([fnmatch])
+FNMATCH_H=fnmatch.h
+])# _AC_LIBOBJ_FNMATCH
+
+
+AC_DEFUN([gl_FUNC_FNMATCH_POSIX],
+[
+ FNMATCH_H=
+ _AC_FUNC_FNMATCH_IF([POSIX], [ac_cv_func_fnmatch_posix],
+ [rm -f lib/fnmatch.h],
+ [_AC_LIBOBJ_FNMATCH])
+ if test $ac_cv_func_fnmatch_posix != yes; then
+ dnl We must choose a different name for our function, since on ELF systems
+ dnl a broken fnmatch() in libc.so would override our fnmatch() if it is
+ dnl compiled into a shared library.
+ AC_DEFINE([fnmatch], [posix_fnmatch],
+ [Define to a replacement function name for fnmatch().])
+ fi
+ AC_SUBST([FNMATCH_H])
+])
+
+
+AC_DEFUN([gl_FUNC_FNMATCH_GNU],
+[
+ dnl Persuade glibc <fnmatch.h> to declare FNM_CASEFOLD etc.
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ FNMATCH_H=
+ _AC_FUNC_FNMATCH_IF([GNU], [ac_cv_func_fnmatch_gnu],
+ [rm -f lib/fnmatch.h],
+ [_AC_LIBOBJ_FNMATCH])
+ if test $ac_cv_func_fnmatch_gnu != yes; then
+ dnl We must choose a different name for our function, since on ELF systems
+ dnl a broken fnmatch() in libc.so would override our fnmatch() if it is
+ dnl compiled into a shared library.
+ AC_DEFINE([fnmatch], [gnu_fnmatch],
+ [Define to a replacement function name for fnmatch().])
+ fi
+ AC_SUBST([FNMATCH_H])
+])
diff --git a/m4/fpending.m4 b/m4/fpending.m4
new file mode 100644
index 0000000..87398b1
--- /dev/null
+++ b/m4/fpending.m4
@@ -0,0 +1,79 @@
+#serial 6
+
+# Copyright (C) 2000, 2001, 2004, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering
+dnl Using code from emacs, based on suggestions from Paul Eggert
+dnl and Ulrich Drepper.
+
+dnl Find out how to determine the number of pending output bytes on a stream.
+dnl glibc (2.1.93 and newer) and Solaris provide __fpending. On other systems,
+dnl we have to grub around in the FILE struct.
+
+AC_DEFUN([gl_FUNC_FPENDING],
+[
+ AC_LIBSOURCES([__fpending.c, __fpending.h])
+
+ AC_CHECK_HEADERS(stdio_ext.h)
+ AC_REPLACE_FUNCS([__fpending])
+ fp_headers='
+# if HAVE_STDIO_EXT_H
+# include <stdio_ext.h>
+# endif
+'
+ AC_CHECK_DECLS([__fpending], , , $fp_headers)
+ if test $ac_cv_func___fpending = no; then
+ AC_CACHE_CHECK(
+ [how to determine the number of pending output bytes on a stream],
+ ac_cv_sys_pending_output_n_bytes,
+ [
+ for ac_expr in \
+ \
+ '# glibc2' \
+ 'fp->_IO_write_ptr - fp->_IO_write_base' \
+ \
+ '# traditional Unix' \
+ 'fp->_ptr - fp->_base' \
+ \
+ '# BSD' \
+ 'fp->_p - fp->_bf._base' \
+ \
+ '# SCO, Unixware' \
+ 'fp->__ptr - fp->__base' \
+ \
+ '# old glibc?' \
+ 'fp->__bufp - fp->__buffer' \
+ \
+ '# old glibc iostream?' \
+ 'fp->_pptr - fp->_pbase' \
+ \
+ '# VMS' \
+ '(*fp)->_ptr - (*fp)->_base' \
+ \
+ '# e.g., DGUX R4.11; the info is not available' \
+ 1 \
+ ; do
+
+ # Skip each embedded comment.
+ case "$ac_expr" in '#'*) continue;; esac
+
+ AC_TRY_COMPILE(
+ [#include <stdio.h>
+ ],
+ [FILE *fp = stdin; (void) ($ac_expr);],
+ fp_done=yes
+ )
+ test "$fp_done" = yes && break
+ done
+
+ ac_cv_sys_pending_output_n_bytes=$ac_expr
+ ]
+ )
+ AC_DEFINE_UNQUOTED(PENDING_OUTPUT_N_BYTES,
+ $ac_cv_sys_pending_output_n_bytes,
+ [the number of pending output bytes on stream `fp'])
+ fi
+])
diff --git a/m4/ftruncate.m4 b/m4/ftruncate.m4
new file mode 100644
index 0000000..d25c17e
--- /dev/null
+++ b/m4/ftruncate.m4
@@ -0,0 +1,23 @@
+#serial 7
+
+# See if we need to emulate a missing ftruncate function using fcntl or chsize.
+
+# Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_FTRUNCATE],
+[
+ AC_REPLACE_FUNCS(ftruncate)
+ if test $ac_cv_func_ftruncate = no; then
+ gl_PREREQ_FTRUNCATE
+ fi
+])
+
+# Prerequisites of lib/ftruncate.c.
+AC_DEFUN([gl_PREREQ_FTRUNCATE],
+[
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+ AC_CHECK_FUNCS(chsize)
+])
diff --git a/m4/getaddrinfo.m4 b/m4/getaddrinfo.m4
new file mode 100644
index 0000000..4bc9f67
--- /dev/null
+++ b/m4/getaddrinfo.m4
@@ -0,0 +1,19 @@
+# getaddrinfo.m4 serial 3
+dnl Copyright (C) 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_GETADDRINFO],
+[
+ AC_SEARCH_LIBS(getaddrinfo, nsl socket)
+ AC_REPLACE_FUNCS(getaddrinfo gai_strerror)
+ gl_PREREQ_GETADDRINFO
+])
+
+# Prerequisites of lib/getaddrinfo.h and lib/getaddrinfo.c.
+AC_DEFUN([gl_PREREQ_GETADDRINFO], [
+ AC_REQUIRE([gl_C_RESTRICT])
+ AC_REQUIRE([gl_SOCKET_FAMILIES])
+ AC_REQUIRE([AC_C_INLINE])
+])
diff --git a/m4/getcwd-path-max.m4 b/m4/getcwd-path-max.m4
new file mode 100644
index 0000000..5a6c43a
--- /dev/null
+++ b/m4/getcwd-path-max.m4
@@ -0,0 +1,189 @@
+#serial 10
+# Check for several getcwd bugs with long file names.
+# If so, arrange to compile the wrapper function.
+
+# This is necessary for at least GNU libc on linux-2.4.19 and 2.4.20.
+# I've heard that this is due to a Linux kernel bug, and that it has
+# been fixed between 2.4.21-pre3 and 2.4.21-pre4. */
+
+# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# From Jim Meyering
+
+AC_DEFUN([gl_FUNC_GETCWD_PATH_MAX],
+[
+ AC_CHECK_DECLS_ONCE(getcwd)
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ AC_CACHE_CHECK([whether getcwd handles long file names properly],
+ gl_cv_func_getcwd_path_max,
+ [# Arrange for deletion of the temporary directory this test creates.
+ ac_clean_files="$ac_clean_files confdir3"
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifndef AT_FDCWD
+# define AT_FDCWD 0
+#endif
+#ifdef ENAMETOOLONG
+# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
+#else
+# define is_ENAMETOOLONG(x) 0
+#endif
+
+/* Don't get link errors because mkdir is redefined to rpl_mkdir. */
+#undef mkdir
+
+#ifndef S_IRWXU
+# define S_IRWXU 0700
+#endif
+
+/* The length of this name must be 8. */
+#define DIR_NAME "confdir3"
+#define DIR_NAME_LEN 8
+#define DIR_NAME_SIZE (DIR_NAME_LEN + 1)
+
+/* The length of "../". */
+#define DOTDOTSLASH_LEN 3
+
+/* Leftover bytes in the buffer, to work around library or OS bugs. */
+#define BUF_SLOP 20
+
+int
+main (void)
+{
+#ifndef PATH_MAX
+ /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
+ at least not on a local file system. And if we were to start worrying
+ about remote file systems, we'd have to enable the wrapper function
+ all of the time, just to be safe. That's not worth the cost. */
+ exit (0);
+#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \
+ - DIR_NAME_SIZE - BUF_SLOP) \
+ <= PATH_MAX)
+ /* FIXME: Assuming there's a system for which this is true,
+ this should be done in a compile test. */
+ exit (0);
+#else
+ char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
+ + DIR_NAME_SIZE + BUF_SLOP];
+ char *cwd = getcwd (buf, PATH_MAX);
+ size_t initial_cwd_len;
+ size_t cwd_len;
+ int fail = 0;
+ size_t n_chdirs = 0;
+
+ if (cwd == NULL)
+ exit (1);
+
+ cwd_len = initial_cwd_len = strlen (cwd);
+
+ while (1)
+ {
+ size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
+ char *c = NULL;
+
+ cwd_len += DIR_NAME_SIZE;
+ /* If mkdir or chdir fails, it could be that this system cannot create
+ any file with an absolute name longer than PATH_MAX, such as cygwin.
+ If so, leave fail as 0, because the current working directory can't
+ be too long for getcwd if it can't even be created. For other
+ errors, be pessimistic and consider that as a failure, too. */
+ if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
+ {
+ if (! (errno == ERANGE || is_ENAMETOOLONG (errno)))
+ fail = 2;
+ break;
+ }
+
+ if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
+ {
+ c = getcwd (buf, PATH_MAX);
+ if (!c && errno == ENOENT)
+ {
+ fail = 1;
+ break;
+ }
+ if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno)))
+ {
+ fail = 2;
+ break;
+ }
+ }
+
+ if (dotdot_max <= cwd_len - initial_cwd_len)
+ {
+ if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
+ break;
+ c = getcwd (buf, cwd_len + 1);
+ if (!c)
+ {
+ if (! (errno == ERANGE || errno == ENOENT
+ || is_ENAMETOOLONG (errno)))
+ {
+ fail = 2;
+ break;
+ }
+ if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
+ {
+ fail = 1;
+ break;
+ }
+ }
+ }
+
+ if (c && strlen (c) != cwd_len)
+ {
+ fail = 2;
+ break;
+ }
+ ++n_chdirs;
+ }
+
+ /* Leaving behind such a deep directory is not polite.
+ So clean up here, right away, even though the driving
+ shell script would also clean up. */
+ {
+ size_t i;
+
+ /* Unlink first, in case the chdir failed. */
+ unlink (DIR_NAME);
+ for (i = 0; i <= n_chdirs; i++)
+ {
+ if (chdir ("..") < 0)
+ break;
+ rmdir (DIR_NAME);
+ }
+ }
+
+ exit (fail);
+#endif
+}
+ ]])],
+ [gl_cv_func_getcwd_path_max=yes],
+ [case $? in
+ 1) gl_cv_func_getcwd_path_max='no, but it is partly working';;
+ *) gl_cv_func_getcwd_path_max=no;;
+ esac],
+ [gl_cv_func_getcwd_path_max=no])
+ ])
+ case $gl_cv_func_getcwd_path_max in
+ no,*)
+ AC_DEFINE([HAVE_PARTLY_WORKING_GETCWD], 1,
+ [Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
+ setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX
+ is not defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD
+ is defined.]);;
+ esac
+])
diff --git a/m4/getcwd.m4 b/m4/getcwd.m4
new file mode 100644
index 0000000..2e85475
--- /dev/null
+++ b/m4/getcwd.m4
@@ -0,0 +1,67 @@
+# getcwd.m4 - check for working getcwd that is compatible with glibc
+
+# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Paul Eggert.
+
+AC_DEFUN([gl_FUNC_GETCWD_NULL],
+ [
+ AC_LIBSOURCES([getcwd.c, getcwd.h])
+
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+ AC_CACHE_CHECK([whether getcwd (NULL, 0) allocates memory for result],
+ [gl_cv_func_getcwd_null],
+ [AC_TRY_RUN(
+ [
+# include <stdlib.h>
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+# ifndef getcwd
+ char *getcwd ();
+# endif
+ int
+ main ()
+ {
+ if (chdir ("/") != 0)
+ exit (1);
+ else
+ {
+ char *f = getcwd (NULL, 0);
+ exit (! (f && f[0] == '/' && !f[1]));
+ }
+ }],
+ [gl_cv_func_getcwd_null=yes],
+ [gl_cv_func_getcwd_null=no],
+ [gl_cv_func_getcwd_null=no])])
+])
+
+AC_DEFUN([gl_FUNC_GETCWD],
+[
+ AC_REQUIRE([gl_FUNC_GETCWD_NULL])
+
+ case $gl_cv_func_getcwd_null in
+ yes) gl_FUNC_GETCWD_PATH_MAX;;
+ esac
+
+ case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_path_max in
+ yes,yes) ;;
+ *)
+ AC_LIBOBJ([getcwd])
+ AC_DEFINE([__GETCWD_PREFIX], [[rpl_]],
+ [Define to rpl_ if the getcwd replacement function should be used.])
+ gl_PREREQ_GETCWD;;
+ esac
+])
+
+# Prerequisites of lib/getcwd.c.
+AC_DEFUN([gl_PREREQ_GETCWD],
+[
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ AC_REQUIRE([AC_HEADER_DIRENT])
+ AC_REQUIRE([gl_CHECK_TYPE_STRUCT_DIRENT_D_INO])
+ :
+])
diff --git a/m4/getdate.m4 b/m4/getdate.m4
new file mode 100644
index 0000000..5b2f77f
--- /dev/null
+++ b/m4/getdate.m4
@@ -0,0 +1,23 @@
+# getdate.m4 serial 7
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_GETDATE],
+[
+ AC_LIBSOURCES([getdate.h, getdate.y])
+ AC_LIBOBJ([getdate])
+
+ dnl Prerequisites of lib/getdate.h.
+ AC_REQUIRE([AM_STDBOOL_H])
+ AC_REQUIRE([gl_TIMESPEC])
+
+ dnl Prerequisites of lib/getdate.y.
+ AC_REQUIRE([gl_BISON])
+ AC_REQUIRE([AC_HEADER_STDC])
+ AC_CHECK_FUNCS_ONCE(isascii)
+ AC_STRUCT_TIMEZONE
+ AC_REQUIRE([gl_CLOCK_TIME])
+ AC_REQUIRE([gl_TM_GMTOFF])
+])
diff --git a/m4/getdelim.m4 b/m4/getdelim.m4
new file mode 100644
index 0000000..340bb71
--- /dev/null
+++ b/m4/getdelim.m4
@@ -0,0 +1,30 @@
+# getdelim.m4 serial 1
+
+dnl Copyright (C) 2005 Free Software dnl Foundation, Inc.
+dnl
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_PREREQ(2.52)
+
+AC_DEFUN([gl_FUNC_GETDELIM],
+[
+ AC_LIBSOURCES([getdelim.c, getdelim.h])
+
+ dnl Persuade glibc <stdio.h> to declare getdelim().
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ AC_REPLACE_FUNCS(getdelim)
+ AC_CHECK_DECLS_ONCE(getdelim)
+
+ if test $ac_cv_func_getdelim = no; then
+ gl_PREREQ_GETDELIM
+ fi
+])
+
+# Prerequisites of lib/getdelim.c.
+AC_DEFUN([gl_PREREQ_GETDELIM],
+[
+ AC_CHECK_FUNCS([flockfile funlockfile])
+])
diff --git a/m4/gethostname.m4 b/m4/gethostname.m4
new file mode 100644
index 0000000..1e9749d
--- /dev/null
+++ b/m4/gethostname.m4
@@ -0,0 +1,18 @@
+# gethostname.m4 serial 2
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_GETHOSTNAME],
+[
+ AC_REPLACE_FUNCS(gethostname)
+ if test $ac_cv_func_gethostname = no; then
+ gl_PREREQ_GETHOSTNAME
+ fi
+])
+
+# Prerequisites of lib/gethostname.c.
+AC_DEFUN([gl_PREREQ_GETHOSTNAME], [
+ AC_CHECK_FUNCS(uname)
+])
diff --git a/m4/getline.m4 b/m4/getline.m4
new file mode 100644
index 0000000..ff255a3
--- /dev/null
+++ b/m4/getline.m4
@@ -0,0 +1,70 @@
+# getline.m4 serial 13
+
+dnl Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free Software
+dnl Foundation, Inc.
+dnl
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_PREREQ(2.52)
+
+dnl See if there's a working, system-supplied version of the getline function.
+dnl We can't just do AC_REPLACE_FUNCS(getline) because some systems
+dnl have a function by that name in -linet that doesn't have anything
+dnl to do with the function we need.
+AC_DEFUN([gl_FUNC_GETLINE],
+[
+ AC_LIBSOURCES([getline.c, getline.h])
+
+ dnl Persuade glibc <stdio.h> to declare getline().
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ AC_CHECK_DECLS([getline])
+
+ gl_getline_needs_run_time_check=no
+ AC_CHECK_FUNC(getline,
+ dnl Found it in some library. Verify that it works.
+ gl_getline_needs_run_time_check=yes,
+ am_cv_func_working_getline=no)
+ if test $gl_getline_needs_run_time_check = yes; then
+ AC_CACHE_CHECK([for working getline function], am_cv_func_working_getline,
+ [echo fooN |tr -d '\012'|tr N '\012' > conftest.data
+ AC_TRY_RUN([
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+ int main ()
+ { /* Based on a test program from Karl Heuer. */
+ char *line = NULL;
+ size_t siz = 0;
+ int len;
+ FILE *in = fopen ("./conftest.data", "r");
+ if (!in)
+ return 1;
+ len = getline (&line, &siz, in);
+ exit ((len == 4 && line && strcmp (line, "foo\n") == 0) ? 0 : 1);
+ }
+ ], am_cv_func_working_getline=yes dnl The library version works.
+ , am_cv_func_working_getline=no dnl The library version does NOT work.
+ , am_cv_func_working_getline=no dnl We're cross compiling.
+ )])
+ fi
+
+ if test $am_cv_func_working_getline = no; then
+ dnl We must choose a different name for our function, since on ELF systems
+ dnl a broken getline() in libc.so would override our getline() in
+ dnl libgettextlib.so.
+ AC_DEFINE([getline], [gnu_getline],
+ [Define to a replacement function name for getline().])
+ AC_LIBOBJ(getline)
+
+ gl_PREREQ_GETLINE
+ fi
+])
+
+# Prerequisites of lib/getline.c.
+AC_DEFUN([gl_PREREQ_GETLINE],
+[
+ gl_FUNC_GETDELIM
+])
diff --git a/m4/getlogin_r.m4 b/m4/getlogin_r.m4
new file mode 100644
index 0000000..71148bd
--- /dev/null
+++ b/m4/getlogin_r.m4
@@ -0,0 +1,33 @@
+#serial 1
+
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Derek Price
+dnl
+dnl Provide getlogin_r when the system lacks it.
+dnl
+
+AC_DEFUN([gl_GETLOGIN_R_SUBSTITUTE],
+[
+ gl_PREREQ_GETLOGIN_R
+ AC_LIBSOURCE([getlogin_r.h])
+ AC_LIBOBJ([getlogin_r])
+])
+
+AC_DEFUN([gl_GETLOGIN_R],
+[
+ AC_REPLACE_FUNCS([getlogin_r])
+ if test $ac_cv_func_getlogin_r = no; then
+ gl_GETLOGIN_R_SUBSTITUTE
+ fi
+])
+
+AC_DEFUN([gl_PREREQ_GETLOGIN_R],
+[
+ AC_CHECK_HEADERS_ONCE([unistd.h])
+ AC_CHECK_DECLS_ONCE([getlogin getlogin_r])
+])
diff --git a/m4/getndelim2.m4 b/m4/getndelim2.m4
new file mode 100644
index 0000000..404b36d
--- /dev/null
+++ b/m4/getndelim2.m4
@@ -0,0 +1,25 @@
+# getndelim2.m4 serial 4
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_GETNDELIM2],
+[
+ # Avoid multiple inclusions of getndelim2.o into LIBOBJS.
+ # This hack won't be needed after gnulib requires Autoconf 2.58 or later.
+ case " $LIB@&t@OBJS " in
+ *" getndelim2.$ac_objext "* ) ;;
+ *) AC_LIBOBJ(getndelim2);;
+ esac
+
+ gl_PREREQ_GETNDELIM2
+])
+
+# Prerequisites of lib/getndelim2.h and lib/getndelim2.c.
+AC_DEFUN([gl_PREREQ_GETNDELIM2],
+[
+ dnl Prerequisites of lib/getndelim2.h.
+ AC_REQUIRE([gt_TYPE_SSIZE_T])
+ dnl No prerequisites of lib/getndelim2.c.
+])
diff --git a/m4/getnline.m4 b/m4/getnline.m4
new file mode 100644
index 0000000..cdfa0c2
--- /dev/null
+++ b/m4/getnline.m4
@@ -0,0 +1,13 @@
+# getnline.m4 serial 3
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_GETNLINE],
+[
+ dnl Prerequisites of lib/getnline.h.
+ AC_REQUIRE([gt_TYPE_SSIZE_T])
+ dnl Prerequisites of lib/getnline.c.
+ :
+])
diff --git a/m4/getopt.m4 b/m4/getopt.m4
new file mode 100644
index 0000000..6b98782
--- /dev/null
+++ b/m4/getopt.m4
@@ -0,0 +1,80 @@
+# getopt.m4 serial 11
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# The getopt module assume you want GNU getopt, with getopt_long etc,
+# rather than vanilla POSIX getopt. This means your your code should
+# always include <getopt.h> for the getopt prototypes.
+
+AC_DEFUN([gl_GETOPT_SUBSTITUTE],
+[
+ AC_LIBOBJ([getopt])
+ AC_LIBOBJ([getopt1])
+ gl_GETOPT_SUBSTITUTE_HEADER
+ gl_PREREQ_GETOPT
+])
+
+AC_DEFUN([gl_GETOPT_SUBSTITUTE_HEADER],
+[
+ GETOPT_H=getopt.h
+ AC_DEFINE([__GETOPT_PREFIX], [[rpl_]],
+ [Define to rpl_ if the getopt replacement functions and variables
+ should be used.])
+ AC_SUBST([GETOPT_H])
+])
+
+AC_DEFUN([gl_GETOPT_CHECK_HEADERS],
+[
+ if test -z "$GETOPT_H"; then
+ AC_CHECK_HEADERS([getopt.h], [], [GETOPT_H=getopt.h])
+ fi
+
+ if test -z "$GETOPT_H"; then
+ AC_CHECK_FUNCS([getopt_long_only], [], [GETOPT_H=getopt.h])
+ fi
+
+ dnl BSD getopt_long uses an incompatible method to reset option processing,
+ dnl and (as of 2004-10-15) mishandles optional option-arguments.
+ if test -z "$GETOPT_H"; then
+ AC_CHECK_DECL([optreset], [GETOPT_H=getopt.h], [], [#include <getopt.h>])
+ fi
+
+ dnl Solaris 10 getopt doesn't handle `+' as a leading character in an
+ dnl option string (as of 2005-05-05).
+ if test -z "$GETOPT_H"; then
+ AC_CACHE_CHECK([for working GNU getopt function], [gl_cv_func_gnu_getopt],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([#include <getopt.h>],
+ [[
+ char *myargv[3];
+ myargv[0] = "conftest";
+ myargv[1] = "-+";
+ myargv[2] = 0;
+ return getopt (2, myargv, "+a") != '?';
+ ]])],
+ [gl_cv_func_gnu_getopt=yes],
+ [gl_cv_func_gnu_getopt=no],
+ [dnl cross compiling - pessimistically guess based on decls
+ dnl Solaris 10 getopt doesn't handle `+' as a leading character in an
+ dnl option string (as of 2005-05-05).
+ AC_CHECK_DECL([getopt_clip],
+ [gl_cv_func_gnu_getopt=no], [gl_cv_func_gnu_getopt=yes],
+ [#include <getopt.h>])])])
+ if test "$gl_cv_func_gnu_getopt" = "no"; then
+ GETOPT_H=getopt.h
+ fi
+ fi
+])
+
+AC_DEFUN([gl_GETOPT_IFELSE],
+[
+ AC_REQUIRE([gl_GETOPT_CHECK_HEADERS])
+ AS_IF([test -n "$GETOPT_H"], [$1], [$2])
+])
+
+AC_DEFUN([gl_GETOPT], [gl_GETOPT_IFELSE([gl_GETOPT_SUBSTITUTE])])
+
+# Prerequisites of lib/getopt*.
+AC_DEFUN([gl_PREREQ_GETOPT], [:])
diff --git a/m4/getpagesize.m4 b/m4/getpagesize.m4
new file mode 100644
index 0000000..12d6889
--- /dev/null
+++ b/m4/getpagesize.m4
@@ -0,0 +1,15 @@
+# getpagesize.m4 serial 4
+dnl Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_GETPAGESIZE],
+[
+ AC_LIBSOURCES([getpagesize.h])
+
+ dnl Prerequisites of lib/getpagesize.h.
+ AC_CHECK_HEADERS_ONCE(sys/param.h unistd.h)
+ AC_CHECK_HEADERS(OS.h)
+ AC_CHECK_FUNCS(getpagesize)
+])
diff --git a/m4/getpass.m4 b/m4/getpass.m4
new file mode 100644
index 0000000..3d7d33b
--- /dev/null
+++ b/m4/getpass.m4
@@ -0,0 +1,41 @@
+# getpass.m4 serial 6
+dnl Copyright (C) 2002-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Provide a getpass() function if the system doesn't have it.
+AC_DEFUN([gl_FUNC_GETPASS],
+[
+ AC_LIBSOURCES([getpass.c, getpass.h])
+
+ AC_REPLACE_FUNCS(getpass)
+ AC_CHECK_DECLS_ONCE(getpass)
+ if test $ac_cv_func_getpass = no; then
+ gl_PREREQ_GETPASS
+ fi
+])
+
+# Provide the GNU getpass() implementation. It supports passwords of
+# arbitrary length (not just 8 bytes as on HP-UX).
+AC_DEFUN([gl_FUNC_GETPASS_GNU],
+[
+ AC_LIBSOURCES([getpass.c, getpass.h])
+
+ AC_CHECK_DECLS_ONCE(getpass)
+ dnl TODO: Detect when GNU getpass() is already found in glibc.
+ AC_LIBOBJ(getpass)
+ gl_PREREQ_GETPASS
+ dnl We must choose a different name for our function, since on ELF systems
+ dnl an unusable getpass() in libc.so would override our getpass() if it is
+ dnl compiled into a shared library.
+ AC_DEFINE([getpass], [gnu_getpass],
+ [Define to a replacement function name for getpass().])
+])
+
+# Prerequisites of lib/getpass.c.
+AC_DEFUN([gl_PREREQ_GETPASS], [
+ AC_CHECK_HEADERS_ONCE(stdio_ext.h termios.h)
+ AC_CHECK_FUNCS_ONCE(__fsetlocking tcgetattr tcsetattr)
+ AC_CHECK_DECLS_ONCE([fflush_unlocked flockfile fputs_unlocked funlockfile putc_unlocked])
+])
diff --git a/m4/gettext.m4 b/m4/gettext.m4
new file mode 100644
index 0000000..624a807
--- /dev/null
+++ b/m4/gettext.m4
@@ -0,0 +1,549 @@
+# gettext.m4 serial 37 (gettext-0.14.4)
+dnl Copyright (C) 1995-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003.
+
+dnl Macro to add for using GNU gettext.
+
+dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]).
+dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The
+dnl default (if it is not specified or empty) is 'no-libtool'.
+dnl INTLSYMBOL should be 'external' for packages with no intl directory,
+dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory.
+dnl If INTLSYMBOL is 'use-libtool', then a libtool library
+dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static,
+dnl depending on --{enable,disable}-{shared,static} and on the presence of
+dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library
+dnl $(top_builddir)/intl/libintl.a will be created.
+dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext
+dnl implementations (in libc or libintl) without the ngettext() function
+dnl will be ignored. If NEEDSYMBOL is specified and is
+dnl 'need-formatstring-macros', then GNU gettext implementations that don't
+dnl support the ISO C 99 <inttypes.h> formatstring macros will be ignored.
+dnl INTLDIR is used to find the intl libraries. If empty,
+dnl the value `$(top_builddir)/intl/' is used.
+dnl
+dnl The result of the configuration is one of three cases:
+dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled
+dnl and used.
+dnl Catalog format: GNU --> install in $(datadir)
+dnl Catalog extension: .mo after installation, .gmo in source tree
+dnl 2) GNU gettext has been found in the system's C library.
+dnl Catalog format: GNU --> install in $(datadir)
+dnl Catalog extension: .mo after installation, .gmo in source tree
+dnl 3) No internationalization, always use English msgid.
+dnl Catalog format: none
+dnl Catalog extension: none
+dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur.
+dnl The use of .gmo is historical (it was needed to avoid overwriting the
+dnl GNU format catalogs when building on a platform with an X/Open gettext),
+dnl but we keep it in order not to force irrelevant filename changes on the
+dnl maintainers.
+dnl
+AC_DEFUN([AM_GNU_GETTEXT],
+[
+ dnl Argument checking.
+ ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], ,
+ [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT
+])])])])])
+ ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], ,
+ [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT
+])])])])
+ define([gt_included_intl], ifelse([$1], [external], [no], [yes]))
+ define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], []))
+
+ AC_REQUIRE([AM_PO_SUBDIRS])dnl
+ ifelse(gt_included_intl, yes, [
+ AC_REQUIRE([AM_INTL_SUBDIR])dnl
+ ])
+
+ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+
+ dnl Sometimes libintl requires libiconv, so first search for libiconv.
+ dnl Ideally we would do this search only after the
+ dnl if test "$USE_NLS" = "yes"; then
+ dnl if test "$gt_cv_func_gnugettext_libc" != "yes"; then
+ dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT
+ dnl the configure script would need to contain the same shell code
+ dnl again, outside any 'if'. There are two solutions:
+ dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'.
+ dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE.
+ dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not
+ dnl documented, we avoid it.
+ ifelse(gt_included_intl, yes, , [
+ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+ ])
+
+ dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation.
+ gt_INTL_MACOSX
+
+ dnl Set USE_NLS.
+ AM_NLS
+
+ ifelse(gt_included_intl, yes, [
+ BUILD_INCLUDED_LIBINTL=no
+ USE_INCLUDED_LIBINTL=no
+ ])
+ LIBINTL=
+ LTLIBINTL=
+ POSUB=
+
+ dnl If we use NLS figure out what method
+ if test "$USE_NLS" = "yes"; then
+ gt_use_preinstalled_gnugettext=no
+ ifelse(gt_included_intl, yes, [
+ AC_MSG_CHECKING([whether included gettext is requested])
+ AC_ARG_WITH(included-gettext,
+ [ --with-included-gettext use the GNU gettext library included here],
+ nls_cv_force_use_gnu_gettext=$withval,
+ nls_cv_force_use_gnu_gettext=no)
+ AC_MSG_RESULT($nls_cv_force_use_gnu_gettext)
+
+ nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
+ if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
+ ])
+ dnl User does not insist on using GNU NLS library. Figure out what
+ dnl to use. If GNU gettext is available we use this. Else we have
+ dnl to fall back to GNU NLS library.
+
+ dnl Add a version number to the cache macros.
+ define([gt_api_version], ifelse([$2], [need-formatstring-macros], 3, ifelse([$2], [need-ngettext], 2, 1)))
+ define([gt_cv_func_gnugettext_libc], [gt_cv_func_gnugettext]gt_api_version[_libc])
+ define([gt_cv_func_gnugettext_libintl], [gt_cv_func_gnugettext]gt_api_version[_libintl])
+
+ AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc,
+ [AC_TRY_LINK([#include <libintl.h>
+]ifelse([$2], [need-formatstring-macros],
+[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
+#endif
+changequote(,)dnl
+typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
+changequote([,])dnl
+], [])[extern int _nl_msg_cat_cntr;
+extern int *_nl_domain_bindings;],
+ [bindtextdomain ("", "");
+return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_domain_bindings],
+ gt_cv_func_gnugettext_libc=yes,
+ gt_cv_func_gnugettext_libc=no)])
+
+ if test "$gt_cv_func_gnugettext_libc" != "yes"; then
+ dnl Sometimes libintl requires libiconv, so first search for libiconv.
+ ifelse(gt_included_intl, yes, , [
+ AM_ICONV_LINK
+ ])
+ dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL
+ dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv])
+ dnl because that would add "-liconv" to LIBINTL and LTLIBINTL
+ dnl even if libiconv doesn't exist.
+ AC_LIB_LINKFLAGS_BODY([intl])
+ AC_CACHE_CHECK([for GNU gettext in libintl],
+ gt_cv_func_gnugettext_libintl,
+ [gt_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $INCINTL"
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBINTL"
+ dnl Now see whether libintl exists and does not depend on libiconv.
+ AC_TRY_LINK([#include <libintl.h>
+]ifelse([$2], [need-formatstring-macros],
+[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
+#endif
+changequote(,)dnl
+typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
+changequote([,])dnl
+], [])[extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);],
+ [bindtextdomain ("", "");
+return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
+ gt_cv_func_gnugettext_libintl=yes,
+ gt_cv_func_gnugettext_libintl=no)
+ dnl Now see whether libintl exists and depends on libiconv.
+ if test "$gt_cv_func_gnugettext_libintl" != yes && test -n "$LIBICONV"; then
+ LIBS="$LIBS $LIBICONV"
+ AC_TRY_LINK([#include <libintl.h>
+]ifelse([$2], [need-formatstring-macros],
+[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
+#endif
+changequote(,)dnl
+typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
+changequote([,])dnl
+], [])[extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);],
+ [bindtextdomain ("", "");
+return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
+ [LIBINTL="$LIBINTL $LIBICONV"
+ LTLIBINTL="$LTLIBINTL $LTLIBICONV"
+ gt_cv_func_gnugettext_libintl=yes
+ ])
+ fi
+ CPPFLAGS="$gt_save_CPPFLAGS"
+ LIBS="$gt_save_LIBS"])
+ fi
+
+ dnl If an already present or preinstalled GNU gettext() is found,
+ dnl use it. But if this macro is used in GNU gettext, and GNU
+ dnl gettext is already preinstalled in libintl, we update this
+ dnl libintl. (Cf. the install rule in intl/Makefile.in.)
+ if test "$gt_cv_func_gnugettext_libc" = "yes" \
+ || { test "$gt_cv_func_gnugettext_libintl" = "yes" \
+ && test "$PACKAGE" != gettext-runtime \
+ && test "$PACKAGE" != gettext-tools; }; then
+ gt_use_preinstalled_gnugettext=yes
+ else
+ dnl Reset the values set by searching for libintl.
+ LIBINTL=
+ LTLIBINTL=
+ INCINTL=
+ fi
+
+ ifelse(gt_included_intl, yes, [
+ if test "$gt_use_preinstalled_gnugettext" != "yes"; then
+ dnl GNU gettext is not found in the C library.
+ dnl Fall back on included GNU gettext library.
+ nls_cv_use_gnu_gettext=yes
+ fi
+ fi
+
+ if test "$nls_cv_use_gnu_gettext" = "yes"; then
+ dnl Mark actions used to generate GNU NLS library.
+ BUILD_INCLUDED_LIBINTL=yes
+ USE_INCLUDED_LIBINTL=yes
+ LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV"
+ LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV"
+ LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'`
+ fi
+
+ CATOBJEXT=
+ if test "$gt_use_preinstalled_gnugettext" = "yes" \
+ || test "$nls_cv_use_gnu_gettext" = "yes"; then
+ dnl Mark actions to use GNU gettext tools.
+ CATOBJEXT=.gmo
+ fi
+ ])
+
+ if test -n "$INTL_MACOSX_LIBS"; then
+ if test "$gt_use_preinstalled_gnugettext" = "yes" \
+ || test "$nls_cv_use_gnu_gettext" = "yes"; then
+ dnl Some extra flags are needed during linking.
+ LIBINTL="$LIBINTL $INTL_MACOSX_LIBS"
+ LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS"
+ fi
+ fi
+
+ if test "$gt_use_preinstalled_gnugettext" = "yes" \
+ || test "$nls_cv_use_gnu_gettext" = "yes"; then
+ AC_DEFINE(ENABLE_NLS, 1,
+ [Define to 1 if translation of program messages to the user's native language
+ is requested.])
+ else
+ USE_NLS=no
+ fi
+ fi
+
+ AC_MSG_CHECKING([whether to use NLS])
+ AC_MSG_RESULT([$USE_NLS])
+ if test "$USE_NLS" = "yes"; then
+ AC_MSG_CHECKING([where the gettext function comes from])
+ if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+ if test "$gt_cv_func_gnugettext_libintl" = "yes"; then
+ gt_source="external libintl"
+ else
+ gt_source="libc"
+ fi
+ else
+ gt_source="included intl directory"
+ fi
+ AC_MSG_RESULT([$gt_source])
+ fi
+
+ if test "$USE_NLS" = "yes"; then
+
+ if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+ if test "$gt_cv_func_gnugettext_libintl" = "yes"; then
+ AC_MSG_CHECKING([how to link with libintl])
+ AC_MSG_RESULT([$LIBINTL])
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL])
+ fi
+
+ dnl For backward compatibility. Some packages may be using this.
+ AC_DEFINE(HAVE_GETTEXT, 1,
+ [Define if the GNU gettext() function is already present or preinstalled.])
+ AC_DEFINE(HAVE_DCGETTEXT, 1,
+ [Define if the GNU dcgettext() function is already present or preinstalled.])
+ fi
+
+ dnl We need to process the po/ directory.
+ POSUB=po
+ fi
+
+ ifelse(gt_included_intl, yes, [
+ dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL
+ dnl to 'yes' because some of the testsuite requires it.
+ if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then
+ BUILD_INCLUDED_LIBINTL=yes
+ fi
+
+ dnl Make all variables we use known to autoconf.
+ AC_SUBST(BUILD_INCLUDED_LIBINTL)
+ AC_SUBST(USE_INCLUDED_LIBINTL)
+ AC_SUBST(CATOBJEXT)
+
+ dnl For backward compatibility. Some configure.ins may be using this.
+ nls_cv_header_intl=
+ nls_cv_header_libgt=
+
+ dnl For backward compatibility. Some Makefiles may be using this.
+ DATADIRNAME=share
+ AC_SUBST(DATADIRNAME)
+
+ dnl For backward compatibility. Some Makefiles may be using this.
+ INSTOBJEXT=.mo
+ AC_SUBST(INSTOBJEXT)
+
+ dnl For backward compatibility. Some Makefiles may be using this.
+ GENCAT=gencat
+ AC_SUBST(GENCAT)
+
+ dnl For backward compatibility. Some Makefiles may be using this.
+ INTLOBJS=
+ if test "$USE_INCLUDED_LIBINTL" = yes; then
+ INTLOBJS="\$(GETTOBJS)"
+ fi
+ AC_SUBST(INTLOBJS)
+
+ dnl Enable libtool support if the surrounding package wishes it.
+ INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix
+ AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX)
+ ])
+
+ dnl For backward compatibility. Some Makefiles may be using this.
+ INTLLIBS="$LIBINTL"
+ AC_SUBST(INTLLIBS)
+
+ dnl Make all documented variables known to autoconf.
+ AC_SUBST(LIBINTL)
+ AC_SUBST(LTLIBINTL)
+ AC_SUBST(POSUB)
+])
+
+
+dnl Checks for all prerequisites of the intl subdirectory,
+dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS,
+dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL.
+AC_DEFUN([AM_INTL_SUBDIR],
+[
+ AC_REQUIRE([AC_PROG_INSTALL])dnl
+ AC_REQUIRE([AM_MKINSTALLDIRS])dnl
+ AC_REQUIRE([AC_PROG_CC])dnl
+ AC_REQUIRE([AC_CANONICAL_HOST])dnl
+ AC_REQUIRE([gt_GLIBC2])dnl
+ AC_REQUIRE([AC_PROG_RANLIB])dnl
+ AC_REQUIRE([AC_ISC_POSIX])dnl
+ AC_REQUIRE([AC_HEADER_STDC])dnl
+ AC_REQUIRE([AC_C_CONST])dnl
+ AC_REQUIRE([bh_C_SIGNED])dnl
+ AC_REQUIRE([AC_C_INLINE])dnl
+ AC_REQUIRE([AC_TYPE_OFF_T])dnl
+ AC_REQUIRE([AC_TYPE_SIZE_T])dnl
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])dnl
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl
+ AC_REQUIRE([gt_TYPE_WCHAR_T])dnl
+ AC_REQUIRE([gt_TYPE_WINT_T])dnl
+ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+ AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+ AC_REQUIRE([gt_TYPE_INTMAX_T])
+ AC_REQUIRE([gt_PRINTF_POSIX])
+ AC_REQUIRE([AC_FUNC_ALLOCA])dnl
+ AC_REQUIRE([AC_FUNC_MMAP])dnl
+ AC_REQUIRE([gl_GLIBC21])dnl
+ AC_REQUIRE([gt_INTDIV0])dnl
+ AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl
+ AC_REQUIRE([gt_HEADER_INTTYPES_H])dnl
+ AC_REQUIRE([gt_INTTYPES_PRI])dnl
+ AC_REQUIRE([gl_XSIZE])dnl
+ AC_REQUIRE([gt_INTL_MACOSX])dnl
+
+ AC_CHECK_TYPE([ptrdiff_t], ,
+ [AC_DEFINE([ptrdiff_t], [long],
+ [Define as the type of the result of subtracting two pointers, if the system doesn't define it.])
+ ])
+ AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \
+stdlib.h string.h unistd.h sys/param.h])
+ AC_CHECK_FUNCS([asprintf fwprintf getcwd getegid geteuid getgid getuid \
+mempcpy munmap putenv setenv setlocale snprintf stpcpy strcasecmp strdup \
+strtoul tsearch wcslen __argz_count __argz_stringify __argz_next \
+__fsetlocking])
+
+ dnl Use the _snprintf function only if it is declared (because on NetBSD it
+ dnl is defined as a weak alias of snprintf; we prefer to use the latter).
+ gt_CHECK_DECL(_snprintf, [#include <stdio.h>])
+ gt_CHECK_DECL(_snwprintf, [#include <stdio.h>])
+
+ dnl Use the *_unlocked functions only if they are declared.
+ dnl (because some of them were defined without being declared in Solaris
+ dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built
+ dnl on Solaris 2.5.1 to run on Solaris 2.6).
+ dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13.
+ gt_CHECK_DECL(feof_unlocked, [#include <stdio.h>])
+ gt_CHECK_DECL(fgets_unlocked, [#include <stdio.h>])
+ gt_CHECK_DECL(getc_unlocked, [#include <stdio.h>])
+
+ case $gt_cv_func_printf_posix in
+ *yes) HAVE_POSIX_PRINTF=1 ;;
+ *) HAVE_POSIX_PRINTF=0 ;;
+ esac
+ AC_SUBST([HAVE_POSIX_PRINTF])
+ if test "$ac_cv_func_asprintf" = yes; then
+ HAVE_ASPRINTF=1
+ else
+ HAVE_ASPRINTF=0
+ fi
+ AC_SUBST([HAVE_ASPRINTF])
+ if test "$ac_cv_func_snprintf" = yes; then
+ HAVE_SNPRINTF=1
+ else
+ HAVE_SNPRINTF=0
+ fi
+ AC_SUBST([HAVE_SNPRINTF])
+ if test "$ac_cv_func_wprintf" = yes; then
+ HAVE_WPRINTF=1
+ else
+ HAVE_WPRINTF=0
+ fi
+ AC_SUBST([HAVE_WPRINTF])
+
+ AM_ICONV
+ AM_LANGINFO_CODESET
+ if test $ac_cv_header_locale_h = yes; then
+ gt_LC_MESSAGES
+ fi
+
+ if test -n "$INTL_MACOSX_LIBS"; then
+ CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers"
+ fi
+
+ dnl intl/plural.c is generated from intl/plural.y. It requires bison,
+ dnl because plural.y uses bison specific features. It requires at least
+ dnl bison-1.26 because earlier versions generate a plural.c that doesn't
+ dnl compile.
+ dnl bison is only needed for the maintainer (who touches plural.y). But in
+ dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put
+ dnl the rule in general Makefile. Now, some people carelessly touch the
+ dnl files or have a broken "make" program, hence the plural.c rule will
+ dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not
+ dnl present or too old.
+ AC_CHECK_PROGS([INTLBISON], [bison])
+ if test -z "$INTLBISON"; then
+ ac_verc_fail=yes
+ else
+ dnl Found it, now check the version.
+ AC_MSG_CHECKING([version of bison])
+changequote(<<,>>)dnl
+ ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
+ case $ac_prog_version in
+ '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+ 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*)
+changequote([,])dnl
+ ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+ *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+ esac
+ AC_MSG_RESULT([$ac_prog_version])
+ fi
+ if test $ac_verc_fail = yes; then
+ INTLBISON=:
+ fi
+])
+
+
+dnl Checks for special options needed on MacOS X.
+dnl Defines INTL_MACOSX_LIBS.
+AC_DEFUN([gt_INTL_MACOSX],
+[
+ dnl Check for API introduced in MacOS X 10.2.
+ AC_CACHE_CHECK([for CFPreferencesCopyAppValue],
+ gt_cv_func_CFPreferencesCopyAppValue,
+ [gt_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers"
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS -framework CoreFoundation"
+ AC_TRY_LINK([#include <CFPreferences.h>],
+ [CFPreferencesCopyAppValue(NULL, NULL)],
+ [gt_cv_func_CFPreferencesCopyAppValue=yes],
+ [gt_cv_func_CFPreferencesCopyAppValue=no])
+ CPPFLAGS="$gt_save_CPPFLAGS"
+ LIBS="$gt_save_LIBS"])
+ if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then
+ AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1,
+ [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.])
+ fi
+ dnl Check for API introduced in MacOS X 10.3.
+ AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent,
+ [gt_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers"
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS -framework CoreFoundation"
+ AC_TRY_LINK([#include <CFLocale.h>], [CFLocaleCopyCurrent();],
+ [gt_cv_func_CFLocaleCopyCurrent=yes],
+ [gt_cv_func_CFLocaleCopyCurrent=no])
+ CPPFLAGS="$gt_save_CPPFLAGS"
+ LIBS="$gt_save_LIBS"])
+ if test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+ AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1,
+ [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.])
+ fi
+ INTL_MACOSX_LIBS=
+ if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+ INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation"
+ fi
+ AC_SUBST([INTL_MACOSX_LIBS])
+])
+
+
+dnl gt_CHECK_DECL(FUNC, INCLUDES)
+dnl Check whether a function is declared.
+AC_DEFUN([gt_CHECK_DECL],
+[
+ AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1,
+ [AC_TRY_COMPILE([$2], [
+#ifndef $1
+ char *p = (char *) $1;
+#endif
+], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)])
+ if test $ac_cv_have_decl_$1 = yes; then
+ gt_value=1
+ else
+ gt_value=0
+ fi
+ AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value],
+ [Define to 1 if you have the declaration of `$1', and to 0 if you don't.])
+])
+
+
+dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version])
+AC_DEFUN([AM_GNU_GETTEXT_VERSION], [])
diff --git a/m4/gettime.m4 b/m4/gettime.m4
new file mode 100644
index 0000000..0ae4c39
--- /dev/null
+++ b/m4/gettime.m4
@@ -0,0 +1,16 @@
+# gettime.m4 serial 5
+dnl Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_GETTIME],
+[
+ AC_LIBSOURCES([gettime.c])
+ AC_LIBOBJ([gettime])
+
+ dnl Prerequisites of lib/gettime.c.
+ AC_REQUIRE([gl_CLOCK_TIME])
+ AC_REQUIRE([gl_TIMESPEC])
+ AC_CHECK_FUNCS_ONCE(gettimeofday nanotime)
+])
diff --git a/m4/gettimeofday.m4 b/m4/gettimeofday.m4
new file mode 100644
index 0000000..2fdc531
--- /dev/null
+++ b/m4/gettimeofday.m4
@@ -0,0 +1,80 @@
+#serial 7
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering.
+dnl
+dnl See if gettimeofday clobbers the static buffer that localtime uses
+dnl for its return value. The gettimeofday function from Mac OS X 10.0.4
+dnl (i.e., Darwin 1.3.7) has this problem.
+dnl
+dnl If it does, then arrange to use gettimeofday and localtime only via
+dnl the wrapper functions that work around the problem.
+
+AC_DEFUN([AC_FUNC_GETTIMEOFDAY_CLOBBER],
+[
+ AC_REQUIRE([AC_HEADER_TIME])
+ AC_CACHE_CHECK([whether gettimeofday clobbers localtime buffer],
+ jm_cv_func_gettimeofday_clobber,
+ [AC_TRY_RUN([
+#include <stdio.h>
+#include <string.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <stdlib.h>
+
+int
+main ()
+{
+ time_t t = 0;
+ struct tm *lt;
+ struct tm saved_lt;
+ struct timeval tv;
+ lt = localtime (&t);
+ saved_lt = *lt;
+ gettimeofday (&tv, NULL);
+ if (memcmp (lt, &saved_lt, sizeof (struct tm)) != 0)
+ exit (1);
+
+ exit (0);
+}
+ ],
+ jm_cv_func_gettimeofday_clobber=no,
+ jm_cv_func_gettimeofday_clobber=yes,
+ dnl When crosscompiling, assume it is broken.
+ jm_cv_func_gettimeofday_clobber=yes)
+ ])
+ if test $jm_cv_func_gettimeofday_clobber = yes; then
+ gl_GETTIMEOFDAY_REPLACE_LOCALTIME
+
+ AC_DEFINE(gettimeofday, rpl_gettimeofday,
+ [Define to rpl_gettimeofday if the replacement function should be used.])
+ gl_PREREQ_GETTIMEOFDAY
+ fi
+])
+
+AC_DEFUN([gl_GETTIMEOFDAY_REPLACE_LOCALTIME], [
+ AC_LIBOBJ(gettimeofday)
+ AC_DEFINE(gmtime, rpl_gmtime,
+ [Define to rpl_gmtime if the replacement function should be used.])
+ AC_DEFINE(localtime, rpl_localtime,
+ [Define to rpl_localtime if the replacement function should be used.])
+])
+
+# Prerequisites of lib/gettimeofday.c.
+AC_DEFUN([gl_PREREQ_GETTIMEOFDAY], [
+ AC_REQUIRE([AC_HEADER_TIME])
+])
diff --git a/m4/glob.m4 b/m4/glob.m4
new file mode 100644
index 0000000..690318e
--- /dev/null
+++ b/m4/glob.m4
@@ -0,0 +1,80 @@
+# glob.m4 serial 3
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# The glob module assumes you want GNU glob, with glob_pattern_p etc,
+# rather than vanilla POSIX glob. This means your your code should
+# always include <glob.h> for the glob prototypes.
+
+AC_DEFUN([gl_GLOB_SUBSTITUTE],
+[
+ gl_PREREQ_GLOB
+
+ GLOB_H=glob.h
+ AC_LIBSOURCES([glob.c, glob_.h, glob-libc.h])
+ AC_LIBOBJ([glob])
+ AC_SUBST([GLOB_H])
+])
+
+AC_DEFUN([gl_GLOB],
+[ GLOB_H=
+ AC_CHECK_HEADERS([glob.h], [], [GLOB_H=glob.h])
+
+ if test -z "$GLOB_H"; then
+ AC_CACHE_CHECK([for GNU glob interface version 1],
+ [gl_cv_gnu_glob_interface_version_1],
+[ AC_COMPILE_IFELSE(
+[[#include <gnu-versions.h>
+char a[_GNU_GLOB_INTERFACE_VERSION == 1 ? 1 : -1];]],
+ [gl_cv_gnu_glob_interface_version_1=yes],
+ [gl_cv_gnu_glob_interface_version_1=no])])
+
+ if test "$gl_cv_gnu_glob_interface_version_1" = "no"; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ if test -z "$GLOB_H"; then
+ AC_CACHE_CHECK([whether glob lists broken symlinks],
+ [gl_cv_glob_lists_symlinks],
+[ if ln -s conf-doesntexist conf$$-globtest 2>/dev/null; then
+ gl_cv_glob_lists_symlinks=maybe
+ else
+ # If we can't make a symlink, then we cannot test this issue. Be
+ # pessimistic about this.
+ gl_cv_glob_lists_symlinks=no
+ fi
+
+ if test $gl_cv_glob_lists_symlinks = maybe; then
+ AC_RUN_IFELSE(
+AC_LANG_PROGRAM(
+[[#include <stddef.h>
+#include <glob.h>]],
+[[glob_t found;
+if (glob ("conf*-globtest", 0, NULL, &found) == GLOB_NOMATCH) return 1;]]),
+ [gl_cv_glob_lists_symlinks=yes],
+ [gl_cv_glob_lists_symlinks=no], [gl_cv_glob_lists_symlinks=no])
+ fi])
+
+ if test $gl_cv_glob_lists_symlinks = no; then
+ GLOB_H=glob.h
+ fi
+ fi
+
+ rm -f conf$$-globtest
+
+ if test -n "$GLOB_H"; then
+ gl_GLOB_SUBSTITUTE
+ fi
+])
+
+# Prerequisites of lib/glob.*.
+AC_DEFUN([gl_PREREQ_GLOB],
+[ AC_REQUIRE([gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE])dnl
+ AC_REQUIRE([AC_GNU_SOURCE])dnl
+ AC_REQUIRE([AC_HEADER_DIRENT])dnl
+ AC_CHECK_HEADERS_ONCE([sys/cdefs.h unistd.h])dnl
+ AC_CHECK_FUNCS_ONCE([getlogin_r getpwnam_r])dnl
+ :])
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
new file mode 100644
index 0000000..062269c
--- /dev/null
+++ b/m4/gnulib-comp.m4
@@ -0,0 +1,399 @@
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# This file is free software, distributed under the terms of the GNU
+# General Public License. As a special exception to the GNU General
+# Public License, this file may be distributed as part of a program
+# that contains a configuration script generated by Autoconf, under
+# the same distribution terms as the rest of that program.
+#
+# Generated by gnulib-tool.
+#
+# This file represents the compiled summary of the specification in
+# gnulib-cache.m4. It lists the computed macro invocations that need
+# to be invoked from configure.ac.
+# In projects using CVS, this file can be treated like other built files.
+
+
+# This macro should be invoked from ./configure.in, in the section
+# "Checks for programs", right after AC_PROG_CC, and certainly before
+# any checks for libraries, header files, types and library functions.
+AC_DEFUN([gl_EARLY],
+[
+ AC_REQUIRE([AC_GNU_SOURCE])
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+])
+
+# This macro should be invoked from ./configure.in, in the section
+# "Check for header files, types and library functions".
+AC_DEFUN([gl_INIT],
+[
+ gl_FUNC_ALLOCA
+ gl_ALLOCSA
+ gl_FUNC_ATEXIT
+ gl_CANON_HOST
+ AC_FUNC_CANONICALIZE_FILE_NAME
+ gl_FUNC_CHDIR_LONG
+ gl_CLOSEOUT
+ gl_DIRNAME
+ gl_FUNC_DUP2
+ gl_ERROR
+ gl_EXITFAIL
+ dnl gl_USE_SYSTEM_EXTENSIONS must be added quite early to configure.ac.
+ gl_FILE_NAME_CONCAT
+ # No macro. You should also use one of fnmatch-posix or fnmatch-gnu.
+ gl_FUNC_FNMATCH_POSIX
+ gl_FUNC_FPENDING
+ gl_FUNC_FTRUNCATE
+ gl_GETADDRINFO
+ gl_FUNC_GETCWD
+ gl_GETDATE
+ gl_FUNC_GETDELIM
+ gl_FUNC_GETHOSTNAME
+ gl_FUNC_GETLINE
+ gl_GETLOGIN_R
+ gl_GETNDELIM2
+ gl_GETNLINE
+ gl_GETOPT
+ gl_GETPAGESIZE
+ gl_FUNC_GETPASS_GNU
+ dnl you must add AM_GNU_GETTEXT([external]) or similar to configure.ac.
+ gl_GETTIME
+ AC_FUNC_GETTIMEOFDAY_CLOBBER
+ gl_GLOB
+ gl_FUNC_LSTAT
+ AC_FUNC_MALLOC
+ gl_MBCHAR
+ gl_MBITER
+ gl_MD5
+ gl_FUNC_MEMCHR
+ gl_FUNC_MEMMOVE
+ gl_FUNC_MEMPCPY
+ gl_FUNC_MEMRCHR
+ gl_MINMAX
+ gl_FUNC_MKDIR_TRAILING_SLASH
+ gl_FUNC_MKSTEMP
+ gl_FUNC_MKTIME
+ gl_FUNC_NANOSLEEP
+ gl_FUNC_OPENAT
+ gl_PAGEALIGN_ALLOC
+ gl_PATHMAX
+ gl_QUOTEARG
+ gl_FUNC_READLINK
+ AC_FUNC_REALLOC
+ gl_REGEX
+ vb_FUNC_RENAME
+ gl_C_RESTRICT
+ gl_FUNC_RPMATCH
+ gl_SAVE_CWD
+ gt_FUNC_SETENV
+ gl_SIZE_MAX
+ gt_TYPE_SSIZE_T
+ gl_STAT_MACROS
+ AM_STDBOOL_H
+ gl_STDINT_H
+ gl_STRCASE
+ gl_FUNC_STRDUP
+ gl_FUNC_STRERROR
+ gl_FUNC_GNU_STRFTIME
+ gl_FUNC_STRSTR
+ gl_FUNC_STRTOL
+ gl_FUNC_STRTOUL
+ gl_TIME_R
+ gl_TIMESPEC
+ gl_FUNC_TZSET_CLOBBER
+ gl_UNISTD_SAFER
+ gl_FUNC_GLIBC_UNLOCKED_IO
+ gl_FUNC_VASNPRINTF
+ gl_FUNC_VASPRINTF
+ gl_XALLOC
+ gl_XGETCWD
+ gl_XREADLINK
+ gl_XSIZE
+ gl_YESNO
+])
+
+# This macro records the list of files which have been installed by
+# gnulib-tool and may be removed by future gnulib-tool invocations.
+AC_DEFUN([gl_FILE_LIST], [
+ build-aux/config.rpath
+ doc/getdate.texi
+ lib/__fpending.c
+ lib/__fpending.h
+ lib/alloca.c
+ lib/alloca_.h
+ lib/allocsa.c
+ lib/allocsa.h
+ lib/allocsa.valgrind
+ lib/asnprintf.c
+ lib/asprintf.c
+ lib/atexit.c
+ lib/basename.c
+ lib/canon-host.c
+ lib/canon-host.h
+ lib/canonicalize.c
+ lib/canonicalize.h
+ lib/chdir-long.c
+ lib/chdir-long.h
+ lib/closeout.c
+ lib/closeout.h
+ lib/cycle-check.c
+ lib/cycle-check.h
+ lib/dev-ino.h
+ lib/dirname.c
+ lib/dirname.h
+ lib/dup-safer.c
+ lib/dup2.c
+ lib/error.c
+ lib/error.h
+ lib/exit.h
+ lib/exitfail.c
+ lib/exitfail.h
+ lib/fd-safer.c
+ lib/filenamecat.c
+ lib/filenamecat.h
+ lib/fnmatch.c
+ lib/fnmatch_.h
+ lib/fnmatch_loop.c
+ lib/ftruncate.c
+ lib/gai_strerror.c
+ lib/getaddrinfo.c
+ lib/getaddrinfo.h
+ lib/getcwd.c
+ lib/getcwd.h
+ lib/getdate.h
+ lib/getdate.y
+ lib/getdelim.c
+ lib/getdelim.h
+ lib/gethostname.c
+ lib/getline.c
+ lib/getline.h
+ lib/getlogin_r.c
+ lib/getlogin_r.h
+ lib/getndelim2.c
+ lib/getndelim2.h
+ lib/getnline.c
+ lib/getnline.h
+ lib/getopt.c
+ lib/getopt1.c
+ lib/getopt_.h
+ lib/getopt_int.h
+ lib/getpagesize.h
+ lib/getpass.c
+ lib/getpass.h
+ lib/gettext.h
+ lib/gettime.c
+ lib/gettimeofday.c
+ lib/glob-libc.h
+ lib/glob.c
+ lib/glob_.h
+ lib/lstat.c
+ lib/lstat.h
+ lib/malloc.c
+ lib/mbchar.c
+ lib/mbchar.h
+ lib/mbuiter.h
+ lib/md5.c
+ lib/md5.h
+ lib/memchr.c
+ lib/memmove.c
+ lib/mempcpy.c
+ lib/mempcpy.h
+ lib/memrchr.c
+ lib/memrchr.h
+ lib/minmax.h
+ lib/mkdir.c
+ lib/mkstemp.c
+ lib/mktime.c
+ lib/nanosleep.c
+ lib/openat.c
+ lib/openat.h
+ lib/pagealign_alloc.c
+ lib/pagealign_alloc.h
+ lib/pathmax.h
+ lib/pipe-safer.c
+ lib/printf-args.c
+ lib/printf-args.h
+ lib/printf-parse.c
+ lib/printf-parse.h
+ lib/quotearg.c
+ lib/quotearg.h
+ lib/readlink.c
+ lib/realloc.c
+ lib/regcomp.c
+ lib/regex.c
+ lib/regex.h
+ lib/regex_internal.c
+ lib/regex_internal.h
+ lib/regexec.c
+ lib/rename.c
+ lib/rpmatch.c
+ lib/save-cwd.c
+ lib/save-cwd.h
+ lib/setenv.c
+ lib/setenv.h
+ lib/size_max.h
+ lib/stat-macros.h
+ lib/stdbool_.h
+ lib/stdint_.h
+ lib/strcase.h
+ lib/strcasecmp.c
+ lib/strdup.c
+ lib/strdup.h
+ lib/strerror.c
+ lib/strftime.c
+ lib/strftime.h
+ lib/stripslash.c
+ lib/strncasecmp.c
+ lib/strnlen1.c
+ lib/strnlen1.h
+ lib/strstr.c
+ lib/strstr.h
+ lib/strtol.c
+ lib/strtoul.c
+ lib/tempname.c
+ lib/time_r.c
+ lib/time_r.h
+ lib/timespec.h
+ lib/unistd--.h
+ lib/unistd-safer.h
+ lib/unlocked-io.h
+ lib/unsetenv.c
+ lib/vasnprintf.c
+ lib/vasnprintf.h
+ lib/vasprintf.c
+ lib/vasprintf.h
+ lib/xalloc-die.c
+ lib/xalloc.h
+ lib/xgetcwd.c
+ lib/xgetcwd.h
+ lib/xgethostname.c
+ lib/xgethostname.h
+ lib/xmalloc.c
+ lib/xreadlink.c
+ lib/xreadlink.h
+ lib/xsize.h
+ lib/yesno.c
+ lib/yesno.h
+ m4/alloca.m4
+ m4/allocsa.m4
+ m4/atexit.m4
+ m4/bison.m4
+ m4/canon-host.m4
+ m4/canonicalize.m4
+ m4/chdir-long.m4
+ m4/clock_time.m4
+ m4/closeout.m4
+ m4/codeset.m4
+ m4/d-ino.m4
+ m4/d-type.m4
+ m4/dirname.m4
+ m4/dos.m4
+ m4/dup2.m4
+ m4/eealloc.m4
+ m4/eoverflow.m4
+ m4/error.m4
+ m4/exitfail.m4
+ m4/extensions.m4
+ m4/filenamecat.m4
+ m4/fnmatch.m4
+ m4/fpending.m4
+ m4/ftruncate.m4
+ m4/getaddrinfo.m4
+ m4/getcwd-path-max.m4
+ m4/getcwd.m4
+ m4/getdate.m4
+ m4/getdelim.m4
+ m4/gethostname.m4
+ m4/getline.m4
+ m4/getlogin_r.m4
+ m4/getndelim2.m4
+ m4/getnline.m4
+ m4/getopt.m4
+ m4/getpagesize.m4
+ m4/getpass.m4
+ m4/gettext.m4
+ m4/gettime.m4
+ m4/gettimeofday.m4
+ m4/glibc2.m4
+ m4/glibc21.m4
+ m4/glob.m4
+ m4/iconv.m4
+ m4/intdiv0.m4
+ m4/intmax.m4
+ m4/intmax_t.m4
+ m4/inttypes-pri.m4
+ m4/inttypes.m4
+ m4/inttypes_h.m4
+ m4/isc-posix.m4
+ m4/lcmessage.m4
+ m4/lib-ld.m4
+ m4/lib-link.m4
+ m4/lib-prefix.m4
+ m4/longdouble.m4
+ m4/longlong.m4
+ m4/lstat.m4
+ m4/mbchar.m4
+ m4/mbiter.m4
+ m4/mbrtowc.m4
+ m4/mbstate_t.m4
+ m4/md5.m4
+ m4/memchr.m4
+ m4/memmove.m4
+ m4/mempcpy.m4
+ m4/memrchr.m4
+ m4/minmax.m4
+ m4/mkdir-slash.m4
+ m4/mkstemp.m4
+ m4/mktime.m4
+ m4/mmap-anon.m4
+ m4/nanosleep.m4
+ m4/nls.m4
+ m4/onceonly_2_57.m4
+ m4/openat.m4
+ m4/pagealign_alloc.m4
+ m4/pathmax.m4
+ m4/po.m4
+ m4/printf-posix.m4
+ m4/progtest.m4
+ m4/quotearg.m4
+ m4/readlink.m4
+ m4/regex.m4
+ m4/rename.m4
+ m4/restrict.m4
+ m4/rpmatch.m4
+ m4/save-cwd.m4
+ m4/setenv.m4
+ m4/signed.m4
+ m4/size_max.m4
+ m4/sockpfaf.m4
+ m4/ssize_t.m4
+ m4/stat-macros.m4
+ m4/stdbool.m4
+ m4/stdint.m4
+ m4/stdint_h.m4
+ m4/strcase.m4
+ m4/strdup.m4
+ m4/strerror.m4
+ m4/strerror_r.m4
+ m4/strftime.m4
+ m4/strstr.m4
+ m4/strtol.m4
+ m4/strtoul.m4
+ m4/time_r.m4
+ m4/timespec.m4
+ m4/tm_gmtoff.m4
+ m4/tzset.m4
+ m4/uint32_t.m4
+ m4/uintmax_t.m4
+ m4/ulonglong.m4
+ m4/unistd-safer.m4
+ m4/unlocked-io.m4
+ m4/vasnprintf.m4
+ m4/vasprintf.m4
+ m4/wchar_t.m4
+ m4/wint_t.m4
+ m4/xalloc.m4
+ m4/xgetcwd.m4
+ m4/xreadlink.m4
+ m4/xsize.m4
+ m4/yesno.m4
+])
diff --git a/m4/iconv.m4 b/m4/iconv.m4
new file mode 100644
index 0000000..654c415
--- /dev/null
+++ b/m4/iconv.m4
@@ -0,0 +1,101 @@
+# iconv.m4 serial AM4 (gettext-0.11.3)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
+[
+ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+
+ dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([iconv])
+])
+
+AC_DEFUN([AM_ICONV_LINK],
+[
+ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+ dnl those with the standalone portable GNU libiconv installed).
+
+ dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+ dnl accordingly.
+ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+
+ dnl Add $INCICONV to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed libiconv and not disabled its use
+ dnl via --without-libiconv-prefix, he wants to use it. The first
+ dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
+ am_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
+
+ AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
+ am_cv_func_iconv="no, consider installing GNU libiconv"
+ am_cv_lib_iconv=no
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ am_cv_func_iconv=yes)
+ if test "$am_cv_func_iconv" != yes; then
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBICONV"
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ am_cv_lib_iconv=yes
+ am_cv_func_iconv=yes)
+ LIBS="$am_save_LIBS"
+ fi
+ ])
+ if test "$am_cv_func_iconv" = yes; then
+ AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
+ fi
+ if test "$am_cv_lib_iconv" = yes; then
+ AC_MSG_CHECKING([how to link with libiconv])
+ AC_MSG_RESULT([$LIBICONV])
+ else
+ dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV
+ dnl either.
+ CPPFLAGS="$am_save_CPPFLAGS"
+ LIBICONV=
+ LTLIBICONV=
+ fi
+ AC_SUBST(LIBICONV)
+ AC_SUBST(LTLIBICONV)
+])
+
+AC_DEFUN([AM_ICONV],
+[
+ AM_ICONV_LINK
+ if test "$am_cv_func_iconv" = yes; then
+ AC_MSG_CHECKING([for iconv declaration])
+ AC_CACHE_VAL(am_cv_proto_iconv, [
+ AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+ am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+ am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+ AC_MSG_RESULT([$]{ac_t:-
+ }[$]am_cv_proto_iconv)
+ AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
+ [Define as const if the declaration of iconv() needs const.])
+ fi
+])
diff --git a/m4/intmax_t.m4 b/m4/intmax_t.m4
new file mode 100644
index 0000000..44b1652
--- /dev/null
+++ b/m4/intmax_t.m4
@@ -0,0 +1,61 @@
+# intmax_t.m4 serial 4
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+AC_PREREQ(2.13)
+
+# Define intmax_t to 'long' or 'long long'
+# if it is not already defined in <stdint.h> or <inttypes.h>.
+
+AC_DEFUN([gl_AC_TYPE_INTMAX_T],
+[
+ dnl For simplicity, we assume that a header file defines 'intmax_t' if and
+ dnl only if it defines 'uintmax_t'.
+ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+ AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+ if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ test $ac_cv_type_long_long = yes \
+ && ac_type='long long' \
+ || ac_type='long'
+ AC_DEFINE_UNQUOTED(intmax_t, $ac_type,
+ [Define to long or long long if <inttypes.h> and <stdint.h> don't define.])
+ else
+ AC_DEFINE(HAVE_INTMAX_T, 1,
+ [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.])
+ fi
+])
+
+dnl An alternative would be to explicitly test for 'intmax_t'.
+
+AC_DEFUN([gt_AC_TYPE_INTMAX_T],
+[
+ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+ AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+ AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t,
+ [AC_TRY_COMPILE([
+#include <stddef.h>
+#include <stdlib.h>
+#if HAVE_STDINT_H_WITH_UINTMAX
+#include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+#include <inttypes.h>
+#endif
+], [intmax_t x = -1;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)])
+ if test $gt_cv_c_intmax_t = yes; then
+ AC_DEFINE(HAVE_INTMAX_T, 1,
+ [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.])
+ else
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ test $ac_cv_type_long_long = yes \
+ && ac_type='long long' \
+ || ac_type='long'
+ AC_DEFINE_UNQUOTED(intmax_t, $ac_type,
+ [Define to long or long long if <stdint.h> and <inttypes.h> don't define.])
+ fi
+])
diff --git a/m4/inttypes.m4 b/m4/inttypes.m4
new file mode 100644
index 0000000..779bcea
--- /dev/null
+++ b/m4/inttypes.m4
@@ -0,0 +1,25 @@
+# inttypes.m4 serial 1 (gettext-0.11.4)
+dnl Copyright (C) 1997-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_INTTYPES_H if <inttypes.h> exists and doesn't clash with
+# <sys/types.h>.
+
+AC_DEFUN([gt_HEADER_INTTYPES_H],
+[
+ AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h,
+ [
+ AC_TRY_COMPILE(
+ [#include <sys/types.h>
+#include <inttypes.h>],
+ [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no)
+ ])
+ if test $gt_cv_header_inttypes_h = yes; then
+ AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1,
+ [Define if <inttypes.h> exists and doesn't clash with <sys/types.h>.])
+ fi
+])
diff --git a/m4/inttypes_h.m4 b/m4/inttypes_h.m4
new file mode 100644
index 0000000..a5d075d
--- /dev/null
+++ b/m4/inttypes_h.m4
@@ -0,0 +1,26 @@
+# inttypes_h.m4 serial 6
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_INTTYPES_H_WITH_UINTMAX if <inttypes.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_INTTYPES_H],
+[
+ AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h,
+ [AC_TRY_COMPILE(
+ [#include <sys/types.h>
+#include <inttypes.h>],
+ [uintmax_t i = (uintmax_t) -1;],
+ gl_cv_header_inttypes_h=yes,
+ gl_cv_header_inttypes_h=no)])
+ if test $gl_cv_header_inttypes_h = yes; then
+ AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1,
+ [Define if <inttypes.h> exists, doesn't clash with <sys/types.h>,
+ and declares uintmax_t. ])
+ fi
+])
diff --git a/m4/lib-ld.m4 b/m4/lib-ld.m4
new file mode 100644
index 0000000..96c4e2c
--- /dev/null
+++ b/m4/lib-ld.m4
@@ -0,0 +1,110 @@
+# lib-ld.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 1996-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
+dnl with libtool.m4.
+
+dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ acl_cv_prog_gnu_ld=yes ;;
+*)
+ acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by GCC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]* | [A-Za-z]:[\\/]*)]
+ [re_direlt='/[^/][^/]*/\.\./']
+ # Canonicalize the path of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(acl_cv_path_LD,
+[if test -z "$LD"; then
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ acl_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break ;;
+ *)
+ test "$with_gnu_ld" != yes && break ;;
+ esac
+ fi
+ done
+ IFS="$ac_save_ifs"
+else
+ acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_LIB_PROG_LD_GNU
+])
diff --git a/m4/lib-link.m4 b/m4/lib-link.m4
new file mode 100644
index 0000000..244a779
--- /dev/null
+++ b/m4/lib-link.m4
@@ -0,0 +1,554 @@
+# lib-link.m4 serial 7 (gettext-0.15)
+dnl Copyright (C) 2001-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_PREREQ(2.50)
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+ ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+ ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+ ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+ ])
+ LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+ LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+ INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+ dnl results of this search when this library appears as a dependency.
+ HAVE_LIB[]NAME=yes
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+ dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+ dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed lib[]Name and not disabled its use
+ dnl via --without-lib[]Name-prefix, he wants to use it.
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+ AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIB[]NAME"
+ AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+ LIBS="$ac_save_LIBS"
+ ])
+ if test "$ac_cv_lib[]Name" = yes; then
+ HAVE_LIB[]NAME=yes
+ AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+ AC_MSG_CHECKING([how to link with lib[]$1])
+ AC_MSG_RESULT([$LIB[]NAME])
+ else
+ HAVE_LIB[]NAME=no
+ dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+ dnl $INC[]NAME either.
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIB[]NAME=
+ LTLIB[]NAME=
+ fi
+ AC_SUBST([HAVE_LIB]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator,
+dnl hardcode_direct, hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+ dnl Tell automake >= 1.10 to complain if config.rpath is missing.
+ m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+ AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
+ AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
+ AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+ AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+ . ./conftest.sh
+ rm -f ./conftest.sh
+ acl_cv_rpath=done
+ ])
+ wl="$acl_cv_wl"
+ libext="$acl_cv_libext"
+ shlibext="$acl_cv_shlibext"
+ hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ hardcode_direct="$acl_cv_hardcode_direct"
+ hardcode_minus_L="$acl_cv_hardcode_minus_L"
+ dnl Determine whether the user wants rpath handling at all.
+ AC_ARG_ENABLE(rpath,
+ [ --disable-rpath do not hardcode runtime library paths],
+ :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib$1-prefix],
+[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib
+ --without-lib$1-prefix don't search for lib$1 in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/$acl_libdirstem"
+ fi
+ fi
+])
+ dnl Search the library and its dependencies in $additional_libdir and
+ dnl $LDFLAGS. Using breadth-first-seach.
+ LIB[]NAME=
+ LTLIB[]NAME=
+ INC[]NAME=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='$1 $2'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+ dnl or AC_LIB_HAVE_LINKFLAGS call.
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+ else
+ dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+ dnl that this library doesn't exist. So just drop it.
+ :
+ fi
+ else
+ dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+ dnl and the already constructed $LIBNAME/$LTLIBNAME.
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ dnl Found the library.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ dnl Linking with a shared library. We attempt to hardcode its
+ dnl directory into the executable's runpath, unless it's the
+ dnl standard /usr/lib.
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then
+ dnl No hardcoding is needed.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ dnl The hardcoding into $LIBNAME is system dependent.
+ if test "$hardcode_direct" = yes; then
+ dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+ dnl resulting binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ dnl Rely on "-L$found_dir".
+ dnl But don't add it if it's already contained in the LDFLAGS
+ dnl or the already constructed $LIBNAME
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH
+ dnl here, because this doesn't fit in flags passed to the
+ dnl compiler. So give up. No hardcoding. This affects only
+ dnl very old systems.
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ dnl Linking with a static library.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+ else
+ dnl We shouldn't come here, but anyway it's good to have a
+ dnl fallback.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+ fi
+ fi
+ dnl Assume the include files are nearby.
+ additional_includedir=
+ case "$found_dir" in
+ */$acl_libdirstem | */$acl_libdirstem/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ dnl Potentially add $additional_includedir to $INCNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 3. if it's already present in $CPPFLAGS or the already
+ dnl constructed $INCNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INC[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $INCNAME.
+ INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ dnl Look for dependencies.
+ if test -n "$found_la"; then
+ dnl Read the .la file. It defines the variables
+ dnl dlname, library_names, old_library, dependency_libs, current,
+ dnl age, revision, installed, dlopen, dlpreopen, libdir.
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ dnl We use only dependency_libs.
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 3. if it's already present in $LDFLAGS or the already
+ dnl constructed $LIBNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LIBNAME.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LTLIBNAME.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ dnl Handle this in the next round.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ dnl Handle this in the next round. Throw away the .la's
+ dnl directory; it is already contained in a preceding -L
+ dnl option.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ dnl Most likely an immediate library name.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ dnl Didn't find the library; assume it is in the system directories
+ dnl known to the linker and runtime loader. (All the system
+ dnl directories known to the linker should also be known to the
+ dnl runtime loader, otherwise the system is severely misconfigured.)
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ dnl Weird platform: only the last -rpath option counts, the user must
+ dnl pass all path elements in one option. We can arrange that for a
+ dnl single library, but not when more than one $LIBNAMEs are used.
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl.
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ else
+ dnl The -rpath options are cumulative.
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ dnl When using libtool, the option that works for both libraries and
+ dnl executables is -R. The -R options are cumulative.
+ for found_dir in $ltrpathdirs; do
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+ done
+ fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+ for element in [$2]; do
+ haveit=
+ for x in $[$1]; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ [$1]="${[$1]}${[$1]:+ }$element"
+ fi
+ done
+])
diff --git a/m4/lib-prefix.m4 b/m4/lib-prefix.m4
new file mode 100644
index 0000000..a8684e1
--- /dev/null
+++ b/m4/lib-prefix.m4
@@ -0,0 +1,185 @@
+# lib-prefix.m4 serial 5 (gettext-0.15)
+dnl Copyright (C) 2001-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+ AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+ AC_REQUIRE([AC_PROG_CC])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib-prefix],
+[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+ --without-lib-prefix don't search for libraries in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/$acl_libdirstem"
+ fi
+ fi
+])
+ if test $use_additional = yes; then
+ dnl Potentially add $additional_includedir to $CPPFLAGS.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's already present in $CPPFLAGS,
+ dnl 3. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ for x in $CPPFLAGS; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $CPPFLAGS.
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ dnl Potentially add $additional_libdir to $LDFLAGS.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's already present in $LDFLAGS,
+ dnl 3. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+ haveit=
+ for x in $LDFLAGS; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LDFLAGS.
+ LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+ dnl Unfortunately, prefix and exec_prefix get only finally determined
+ dnl at the end of configure.
+ if test "X$prefix" = "XNONE"; then
+ acl_final_prefix="$ac_default_prefix"
+ else
+ acl_final_prefix="$prefix"
+ fi
+ if test "X$exec_prefix" = "XNONE"; then
+ acl_final_exec_prefix='${prefix}'
+ else
+ acl_final_exec_prefix="$exec_prefix"
+ fi
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+ prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ $1
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing
+dnl the basename of the libdir, either "lib" or "lib64".
+AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
+[
+ dnl There is no formal standard regarding lib and lib64. The current
+ dnl practice is that on a system supporting 32-bit and 64-bit instruction
+ dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit
+ dnl libraries go under $prefix/lib. We determine the compiler's default
+ dnl mode by looking at the compiler's library search path. If at least
+ dnl of its elements ends in /lib64 or points to a directory whose absolute
+ dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the
+ dnl default, namely "lib".
+ acl_libdirstem=lib
+ searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+ if test -n "$searchpath"; then
+ acl_save_IFS="${IFS= }"; IFS=":"
+ for searchdir in $searchpath; do
+ if test -d "$searchdir"; then
+ case "$searchdir" in
+ */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
+ *) searchdir=`cd "$searchdir" && pwd`
+ case "$searchdir" in
+ */lib64 ) acl_libdirstem=lib64 ;;
+ esac ;;
+ esac
+ fi
+ done
+ IFS="$acl_save_IFS"
+ fi
+])
diff --git a/m4/longdouble.m4 b/m4/longdouble.m4
new file mode 100644
index 0000000..40cd7ce
--- /dev/null
+++ b/m4/longdouble.m4
@@ -0,0 +1,28 @@
+# longdouble.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether the compiler supports the 'long double' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_LONGDOUBLE],
+[
+ AC_CACHE_CHECK([for long double], gt_cv_c_long_double,
+ [if test "$GCC" = yes; then
+ gt_cv_c_long_double=yes
+ else
+ AC_TRY_COMPILE([
+ /* The Stardent Vistra knows sizeof(long double), but does not support it. */
+ long double foo = 0.0;
+ /* On Ultrix 4.3 cc, long double is 4 and double is 8. */
+ int array [2*(sizeof(long double) >= sizeof(double)) - 1];
+ ], ,
+ gt_cv_c_long_double=yes, gt_cv_c_long_double=no)
+ fi])
+ if test $gt_cv_c_long_double = yes; then
+ AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.])
+ fi
+])
diff --git a/m4/longlong.m4 b/m4/longlong.m4
new file mode 100644
index 0000000..7b399e0
--- /dev/null
+++ b/m4/longlong.m4
@@ -0,0 +1,23 @@
+# longlong.m4 serial 5
+dnl Copyright (C) 1999-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_LONG_LONG if 'long long' works.
+
+AC_DEFUN([gl_AC_TYPE_LONG_LONG],
+[
+ AC_CACHE_CHECK([for long long], ac_cv_type_long_long,
+ [AC_TRY_LINK([long long ll = 1LL; int i = 63;],
+ [long long llmax = (long long) -1;
+ return ll << i | ll >> i | llmax / ll | llmax % ll;],
+ ac_cv_type_long_long=yes,
+ ac_cv_type_long_long=no)])
+ if test $ac_cv_type_long_long = yes; then
+ AC_DEFINE(HAVE_LONG_LONG, 1,
+ [Define if you have the 'long long' type.])
+ fi
+])
diff --git a/m4/lstat.m4 b/m4/lstat.m4
new file mode 100644
index 0000000..20e6fc3
--- /dev/null
+++ b/m4/lstat.m4
@@ -0,0 +1,19 @@
+#serial 14
+
+# Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering.
+
+AC_DEFUN([gl_FUNC_LSTAT],
+[
+ AC_LIBSOURCES([lstat.c, lstat.h])
+
+ AC_REQUIRE([AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK])
+ dnl Note: AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK does AC_LIBOBJ(lstat).
+ :
+])
diff --git a/m4/mbchar.m4 b/m4/mbchar.m4
new file mode 100644
index 0000000..5fced2d
--- /dev/null
+++ b/m4/mbchar.m4
@@ -0,0 +1,21 @@
+# mbchar.m4 serial 1
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl autoconf tests required for use of mbchar.m4
+dnl From Bruno Haible.
+
+AC_DEFUN([gl_MBCHAR],
+[
+ AC_LIBSOURCES([mbchar.c, mbchar.h])
+ AC_CHECK_HEADERS_ONCE(wchar.h wctype.h)
+
+ if test x$ac_cv_header_wchar_h = xyes && test x$ac_cv_header_wctype_h = xyes; then
+ AC_LIBOBJ(mbchar)
+ fi
+
+ AC_REQUIRE([AC_GNU_SOURCE])
+ :
+])
diff --git a/m4/mbiter.m4 b/m4/mbiter.m4
new file mode 100644
index 0000000..3eb92bc
--- /dev/null
+++ b/m4/mbiter.m4
@@ -0,0 +1,14 @@
+# mbiter.m4 serial 1
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl autoconf tests required for use of mbiter.h
+dnl From Bruno Haible.
+
+AC_DEFUN([gl_MBITER],
+[
+ AC_REQUIRE([AC_TYPE_MBSTATE_T])
+ :
+])
diff --git a/m4/mbrtowc.m4 b/m4/mbrtowc.m4
new file mode 100644
index 0000000..a3bd911
--- /dev/null
+++ b/m4/mbrtowc.m4
@@ -0,0 +1,31 @@
+# mbrtowc.m4 serial 8
+dnl Copyright (C) 2001-2002, 2004-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert
+
+dnl This file can be removed, and gl_FUNC_MBRTOWC replaced with
+dnl AC_FUNC_MBRTOWC, when autoconf 2.60 can be assumed everywhere.
+
+AC_DEFUN([gl_FUNC_MBRTOWC],
+[
+ dnl Same as AC_FUNC_MBRTOWC in autoconf-2.60.
+ AC_CACHE_CHECK([whether mbrtowc and mbstate_t are properly declared],
+ gl_cv_func_mbrtowc,
+ [AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <wchar.h>]],
+ [[wchar_t wc;
+ char const s[] = "";
+ size_t n = 1;
+ mbstate_t state;
+ return ! (sizeof state && (mbrtowc) (&wc, s, n, &state));]])],
+ gl_cv_func_mbrtowc=yes,
+ gl_cv_func_mbrtowc=no)])
+ if test $gl_cv_func_mbrtowc = yes; then
+ AC_DEFINE([HAVE_MBRTOWC], 1,
+ [Define to 1 if mbrtowc and mbstate_t are properly declared.])
+ fi
+])
diff --git a/m4/mbstate_t.m4 b/m4/mbstate_t.m4
new file mode 100644
index 0000000..df2a275
--- /dev/null
+++ b/m4/mbstate_t.m4
@@ -0,0 +1,30 @@
+# mbstate_t.m4 serial 9
+dnl Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# From Paul Eggert.
+
+# BeOS 5 has <wchar.h> but does not define mbstate_t,
+# so you can't declare an object of that type.
+# Check for this incompatibility with Standard C.
+
+# AC_TYPE_MBSTATE_T
+# -----------------
+AC_DEFUN([AC_TYPE_MBSTATE_T],
+ [AC_CACHE_CHECK([for mbstate_t], ac_cv_type_mbstate_t,
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [AC_INCLUDES_DEFAULT
+# include <wchar.h>],
+ [mbstate_t x; return sizeof x;])],
+ [ac_cv_type_mbstate_t=yes],
+ [ac_cv_type_mbstate_t=no])])
+ if test $ac_cv_type_mbstate_t = yes; then
+ AC_DEFINE([HAVE_MBSTATE_T], 1,
+ [Define to 1 if <wchar.h> declares mbstate_t.])
+ else
+ AC_DEFINE([mbstate_t], int,
+ [Define to a type if <wchar.h> does not define.])
+ fi])
diff --git a/m4/md5.m4 b/m4/md5.m4
new file mode 100644
index 0000000..729b656
--- /dev/null
+++ b/m4/md5.m4
@@ -0,0 +1,18 @@
+# md5.m4 serial 7
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_MD5],
+[
+ AC_LIBSOURCES([md5.c, md5.h])
+ AC_LIBOBJ([md5])
+
+ dnl Prerequisites of lib/md5.h.
+ AC_REQUIRE([gl_AC_TYPE_UINT32_T])
+
+ dnl Prerequisites of lib/md5.c.
+ AC_REQUIRE([AC_C_BIGENDIAN])
+ :
+])
diff --git a/m4/memchr.m4 b/m4/memchr.m4
new file mode 100644
index 0000000..91b8636
--- /dev/null
+++ b/m4/memchr.m4
@@ -0,0 +1,18 @@
+# memchr.m4 serial 4
+dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MEMCHR],
+[
+ AC_REPLACE_FUNCS(memchr)
+ if test $ac_cv_func_memchr = no; then
+ gl_PREREQ_MEMCHR
+ fi
+])
+
+# Prerequisites of lib/memchr.c.
+AC_DEFUN([gl_PREREQ_MEMCHR], [
+ AC_CHECK_HEADERS(bp-sym.h)
+])
diff --git a/m4/memmove.m4 b/m4/memmove.m4
new file mode 100644
index 0000000..66054e4
--- /dev/null
+++ b/m4/memmove.m4
@@ -0,0 +1,18 @@
+# memmove.m4 serial 2
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MEMMOVE],
+[
+ AC_REPLACE_FUNCS(memmove)
+ if test $ac_cv_func_memmove = no; then
+ gl_PREREQ_MEMMOVE
+ fi
+])
+
+# Prerequisites of lib/memmove.c.
+AC_DEFUN([gl_PREREQ_MEMMOVE], [
+ :
+])
diff --git a/m4/mempcpy.m4 b/m4/mempcpy.m4
new file mode 100644
index 0000000..a96168d
--- /dev/null
+++ b/m4/mempcpy.m4
@@ -0,0 +1,23 @@
+# mempcpy.m4 serial 3
+dnl Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MEMPCPY],
+[
+ AC_LIBSOURCES([mempcpy.c, mempcpy.h])
+
+ dnl Persuade glibc <string.h> to declare mempcpy().
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ AC_REPLACE_FUNCS(mempcpy)
+ if test $ac_cv_func_mempcpy = no; then
+ gl_PREREQ_MEMPCPY
+ fi
+])
+
+# Prerequisites of lib/mempcpy.c.
+AC_DEFUN([gl_PREREQ_MEMPCPY], [
+ :
+])
diff --git a/m4/memrchr.m4 b/m4/memrchr.m4
new file mode 100644
index 0000000..e2406ec
--- /dev/null
+++ b/m4/memrchr.m4
@@ -0,0 +1,23 @@
+# memrchr.m4 serial 4
+dnl Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MEMRCHR],
+[
+ AC_LIBSOURCES([memrchr.c, memrchr.h])
+
+ dnl Persuade glibc <string.h> to declare memrchr().
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ AC_CHECK_DECLS_ONCE([memrchr])
+
+ AC_REPLACE_FUNCS(memrchr)
+ if test $ac_cv_func_memrchr = no; then
+ gl_PREREQ_MEMRCHR
+ fi
+])
+
+# Prerequisites of lib/memrchr.c.
+AC_DEFUN([gl_PREREQ_MEMRCHR], [:])
diff --git a/m4/minmax.m4 b/m4/minmax.m4
new file mode 100644
index 0000000..bbd1ba0
--- /dev/null
+++ b/m4/minmax.m4
@@ -0,0 +1,41 @@
+# minmax.m4 serial 2
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_PREREQ(2.52)
+
+AC_DEFUN([gl_MINMAX],
+[
+ AC_REQUIRE([gl_PREREQ_MINMAX])
+])
+
+# Prerequisites of lib/minmax.h.
+AC_DEFUN([gl_PREREQ_MINMAX],
+[
+ gl_MINMAX_IN_HEADER([limits.h])
+ gl_MINMAX_IN_HEADER([sys/param.h])
+])
+
+dnl gl_MINMAX_IN_HEADER(HEADER)
+dnl The parameter has to be a literal header name; it cannot be macro,
+dnl nor a shell variable. (Because autoheader collects only AC_DEFINE
+dnl invocations with a literal macro name.)
+AC_DEFUN([gl_MINMAX_IN_HEADER],
+[
+ m4_pushdef([header], AS_TR_SH([$1]))
+ m4_pushdef([HEADER], AS_TR_CPP([$1]))
+ AC_CACHE_CHECK([whether <$1> defines MIN and MAX],
+ [gl_cv_minmax_in_]header,
+ [AC_TRY_COMPILE([#include <$1>
+int x = MIN (42, 17);], [],
+ [gl_cv_minmax_in_]header[=yes],
+ [gl_cv_minmax_in_]header[=no])])
+ if test $gl_cv_minmax_in_[]header = yes; then
+ AC_DEFINE([HAVE_MINMAX_IN_]HEADER, 1,
+ [Define to 1 if <$1> defines the MIN and MAX macros.])
+ fi
+ m4_popdef([HEADER])
+ m4_popdef([header])
+])
diff --git a/m4/mkdir-slash.m4 b/m4/mkdir-slash.m4
new file mode 100644
index 0000000..c1e595b
--- /dev/null
+++ b/m4/mkdir-slash.m4
@@ -0,0 +1,44 @@
+#serial 4
+
+# Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# On some systems, mkdir ("foo/", 0700) fails because of the trailing slash.
+# On such systems, arrange to use a wrapper function that removes any
+# trailing slashes.
+AC_DEFUN([gl_FUNC_MKDIR_TRAILING_SLASH],
+[dnl
+ AC_CACHE_CHECK([whether mkdir fails due to a trailing slash],
+ gl_cv_func_mkdir_trailing_slash_bug,
+ [
+ # Arrange for deletion of the temporary directory this test might create.
+ ac_clean_files="$ac_clean_files confdir-slash"
+ AC_TRY_RUN([
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <stdlib.h>
+ int main ()
+ {
+ rmdir ("confdir-slash");
+ exit (mkdir ("confdir-slash/", 0700));
+ }
+ ],
+ gl_cv_func_mkdir_trailing_slash_bug=no,
+ gl_cv_func_mkdir_trailing_slash_bug=yes,
+ gl_cv_func_mkdir_trailing_slash_bug=yes
+ )
+ ]
+ )
+
+ if test $gl_cv_func_mkdir_trailing_slash_bug = yes; then
+ AC_LIBOBJ(mkdir)
+ AC_DEFINE(mkdir, rpl_mkdir,
+ [Define to rpl_mkdir if the replacement function should be used.])
+ gl_PREREQ_MKDIR
+ fi
+])
+
+# Prerequisites of lib/mkdir.c.
+AC_DEFUN([gl_PREREQ_MKDIR], [:])
diff --git a/m4/mkstemp.m4 b/m4/mkstemp.m4
new file mode 100644
index 0000000..fb6cfcd
--- /dev/null
+++ b/m4/mkstemp.m4
@@ -0,0 +1,72 @@
+#serial 11
+
+# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# On some hosts (e.g., HP-UX 10.20, SunOS 4.1.4, Solaris 2.5.1), mkstemp has a
+# silly limit that it can create no more than 26 files from a given template.
+# Other systems lack mkstemp altogether.
+# On OSF1/Tru64 V4.0F, the system-provided mkstemp function can create
+# only 32 files per process.
+# On systems like the above, arrange to use the replacement function.
+AC_DEFUN([gl_FUNC_MKSTEMP],
+[dnl
+ AC_REPLACE_FUNCS(mkstemp)
+ if test $ac_cv_func_mkstemp = no; then
+ gl_cv_func_mkstemp_limitations=yes
+ else
+ AC_CACHE_CHECK([for mkstemp limitations],
+ gl_cv_func_mkstemp_limitations,
+ [
+ mkdir conftest.mkstemp
+ AC_TRY_RUN([
+# include <stdlib.h>
+# include <unistd.h>
+ int main ()
+ {
+ int i;
+ for (i = 0; i < 70; i++)
+ {
+ char template[] = "conftest.mkstemp/coXXXXXX";
+ int fd = mkstemp (template);
+ if (fd == -1)
+ exit (1);
+ close (fd);
+ }
+ exit (0);
+ }
+ ],
+ gl_cv_func_mkstemp_limitations=no,
+ gl_cv_func_mkstemp_limitations=yes,
+ gl_cv_func_mkstemp_limitations=yes
+ )
+ rm -rf conftest.mkstemp
+ ]
+ )
+ fi
+
+ if test $gl_cv_func_mkstemp_limitations = yes; then
+ AC_LIBOBJ(mkstemp)
+ AC_LIBOBJ(tempname)
+ AC_DEFINE(mkstemp, rpl_mkstemp,
+ [Define to rpl_mkstemp if the replacement function should be used.])
+ gl_PREREQ_MKSTEMP
+ gl_PREREQ_TEMPNAME
+ fi
+])
+
+# Prerequisites of lib/mkstemp.c.
+AC_DEFUN([gl_PREREQ_MKSTEMP],
+[
+])
+
+# Prerequisites of lib/tempname.c.
+AC_DEFUN([gl_PREREQ_TEMPNAME],
+[
+ AC_CHECK_HEADERS_ONCE(sys/time.h stdint.h unistd.h)
+ AC_CHECK_FUNCS(__secure_getenv gettimeofday)
+ AC_CHECK_DECLS_ONCE(getenv)
+ AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])
+])
diff --git a/m4/mktime.m4 b/m4/mktime.m4
new file mode 100644
index 0000000..25ca6dc
--- /dev/null
+++ b/m4/mktime.m4
@@ -0,0 +1,200 @@
+# mktime.m4 serial 5
+dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering.
+
+# Redefine AC_FUNC_MKTIME, to fix a bug in Autoconf 2.57 and earlier.
+# This redefinition can be removed once a new version of Autoconf comes out.
+# The redefinition is taken from
+# <http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/autoconf/autoconf/lib/autoconf/functions.m4?rev=1.78>.
+# AC_FUNC_MKTIME
+# --------------
+AC_DEFUN([AC_FUNC_MKTIME],
+[AC_REQUIRE([AC_HEADER_TIME])dnl
+AC_CHECK_HEADERS(stdlib.h sys/time.h unistd.h)
+AC_CHECK_FUNCS(alarm)
+AC_CACHE_CHECK([for working mktime], ac_cv_func_working_mktime,
+[AC_RUN_IFELSE([AC_LANG_SOURCE(
+[[/* Test program from Paul Eggert and Tony Leneis. */
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !HAVE_ALARM
+# define alarm(X) /* empty */
+#endif
+
+/* Work around redefinition to rpl_putenv by other config tests. */
+#undef putenv
+
+static time_t time_t_max;
+static time_t time_t_min;
+
+/* Values we'll use to set the TZ environment variable. */
+static char *tz_strings[] = {
+ (char *) 0, "TZ=GMT0", "TZ=JST-9",
+ "TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00"
+};
+#define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0]))
+
+/* Fail if mktime fails to convert a date in the spring-forward gap.
+ Based on a problem report from Andreas Jaeger. */
+static void
+spring_forward_gap ()
+{
+ /* glibc (up to about 1998-10-07) failed this test. */
+ struct tm tm;
+
+ /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0"
+ instead of "TZ=America/Vancouver" in order to detect the bug even
+ on systems that don't support the Olson extension, or don't have the
+ full zoneinfo tables installed. */
+ putenv ("TZ=PST8PDT,M4.1.0,M10.5.0");
+
+ tm.tm_year = 98;
+ tm.tm_mon = 3;
+ tm.tm_mday = 5;
+ tm.tm_hour = 2;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ tm.tm_isdst = -1;
+ if (mktime (&tm) == (time_t)-1)
+ exit (1);
+}
+
+static void
+mktime_test1 (now)
+ time_t now;
+{
+ struct tm *lt;
+ if ((lt = localtime (&now)) && mktime (lt) != now)
+ exit (1);
+}
+
+static void
+mktime_test (now)
+ time_t now;
+{
+ mktime_test1 (now);
+ mktime_test1 ((time_t) (time_t_max - now));
+ mktime_test1 ((time_t) (time_t_min + now));
+}
+
+static void
+irix_6_4_bug ()
+{
+ /* Based on code from Ariel Faigon. */
+ struct tm tm;
+ tm.tm_year = 96;
+ tm.tm_mon = 3;
+ tm.tm_mday = 0;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ tm.tm_isdst = -1;
+ mktime (&tm);
+ if (tm.tm_mon != 2 || tm.tm_mday != 31)
+ exit (1);
+}
+
+static void
+bigtime_test (j)
+ int j;
+{
+ struct tm tm;
+ time_t now;
+ tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j;
+ now = mktime (&tm);
+ if (now != (time_t) -1)
+ {
+ struct tm *lt = localtime (&now);
+ if (! (lt
+ && lt->tm_year == tm.tm_year
+ && lt->tm_mon == tm.tm_mon
+ && lt->tm_mday == tm.tm_mday
+ && lt->tm_hour == tm.tm_hour
+ && lt->tm_min == tm.tm_min
+ && lt->tm_sec == tm.tm_sec
+ && lt->tm_yday == tm.tm_yday
+ && lt->tm_wday == tm.tm_wday
+ && ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst)
+ == (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst))))
+ exit (1);
+ }
+}
+
+int
+main ()
+{
+ time_t t, delta;
+ int i, j;
+
+ /* This test makes some buggy mktime implementations loop.
+ Give up after 60 seconds; a mktime slower than that
+ isn't worth using anyway. */
+ alarm (60);
+
+ for (time_t_max = 1; 0 < time_t_max; time_t_max *= 2)
+ continue;
+ time_t_max--;
+ if ((time_t) -1 < 0)
+ for (time_t_min = -1; (time_t) (time_t_min * 2) < 0; time_t_min *= 2)
+ continue;
+ delta = time_t_max / 997; /* a suitable prime number */
+ for (i = 0; i < N_STRINGS; i++)
+ {
+ if (tz_strings[i])
+ putenv (tz_strings[i]);
+
+ for (t = 0; t <= time_t_max - delta; t += delta)
+ mktime_test (t);
+ mktime_test ((time_t) 1);
+ mktime_test ((time_t) (60 * 60));
+ mktime_test ((time_t) (60 * 60 * 24));
+
+ for (j = 1; 0 < j; j *= 2)
+ bigtime_test (j);
+ bigtime_test (j - 1);
+ }
+ irix_6_4_bug ();
+ spring_forward_gap ();
+ exit (0);
+}]])],
+ [ac_cv_func_working_mktime=yes],
+ [ac_cv_func_working_mktime=no],
+ [ac_cv_func_working_mktime=no])])
+if test $ac_cv_func_working_mktime = no; then
+ AC_LIBOBJ([mktime])
+fi
+])# AC_FUNC_MKTIME
+
+AC_DEFUN([gl_FUNC_MKTIME],
+[
+ AC_REQUIRE([AC_FUNC_MKTIME])
+ if test $ac_cv_func_working_mktime = no; then
+ AC_DEFINE(mktime, rpl_mktime,
+ [Define to rpl_mktime if the replacement function should be used.])
+ gl_PREREQ_MKTIME
+ fi
+])
+
+# Prerequisites of lib/mktime.c.
+AC_DEFUN([gl_PREREQ_MKTIME], [:])
diff --git a/m4/mmap-anon.m4 b/m4/mmap-anon.m4
new file mode 100644
index 0000000..fd8a537
--- /dev/null
+++ b/m4/mmap-anon.m4
@@ -0,0 +1,48 @@
+# mmap-anon.m4 serial 3
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MMAP_ANON],
+[
+ dnl Work around a bug of AC_EGREP_CPP in autoconf-2.57.
+ AC_REQUIRE([AC_PROG_CPP])
+ AC_REQUIRE([AC_PROG_EGREP])
+
+ dnl Persuade glibc <sys/mman.h> to define MAP_ANONYMOUS.
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ # Check for mmap()
+ AC_FUNC_MMAP
+
+ # Try to allow MAP_ANONYMOUS.
+ gl_have_mmap_anonymous=no
+ if test $ac_cv_func_mmap_fixed_mapped = yes; then
+ AC_MSG_CHECKING([for MAP_ANONYMOUS])
+ AC_EGREP_CPP([I cant identify this map.], [
+#include <sys/mman.h>
+#ifdef MAP_ANONYMOUS
+ I cant identify this map.
+#endif
+],
+ [gl_have_mmap_anonymous=yes])
+ if test $gl_have_mmap_anonymous != yes; then
+ AC_EGREP_CPP([I cant identify this map.], [
+#include <sys/mman.h>
+#ifdef MAP_ANON
+ I cant identify this map.
+#endif
+],
+ [AC_DEFINE(MAP_ANONYMOUS, MAP_ANON,
+ [Define to a substitute value for mmap()'s MAP_ANONYMOUS flag.])
+ gl_have_mmap_anonymous=yes])
+ fi
+ AC_MSG_RESULT($gl_have_mmap_anonymous)
+ if test $gl_have_mmap_anonymous = yes; then
+ AC_DEFINE(HAVE_MAP_ANONYMOUS, 1,
+ [Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including
+ config.h and <sys/mman.h>.])
+ fi
+ fi
+])
diff --git a/m4/nanosleep.m4 b/m4/nanosleep.m4
new file mode 100644
index 0000000..3d64ca9
--- /dev/null
+++ b/m4/nanosleep.m4
@@ -0,0 +1,72 @@
+#serial 13
+
+dnl From Jim Meyering.
+dnl Check for the nanosleep function.
+dnl If not found, use the supplied replacement.
+dnl
+
+# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_NANOSLEEP],
+[
+ AC_LIBSOURCES([nanosleep.c])
+
+ nanosleep_save_libs=$LIBS
+
+ # Solaris 2.5.1 needs -lposix4 to get the nanosleep function.
+ # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
+ AC_SEARCH_LIBS([nanosleep], [rt posix4],
+ [test "$ac_cv_search_nanosleep" = "none required" ||
+ LIB_NANOSLEEP=$ac_cv_search_nanosleep])
+ AC_SUBST([LIB_NANOSLEEP])
+
+ AC_CACHE_CHECK([whether nanosleep works],
+ jm_cv_func_nanosleep_works,
+ [
+ AC_REQUIRE([AC_HEADER_TIME])
+ AC_CHECK_HEADERS_ONCE(sys/time.h)
+ AC_TRY_RUN([
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+ int
+ main ()
+ {
+ struct timespec ts_sleep, ts_remaining;
+ ts_sleep.tv_sec = 0;
+ ts_sleep.tv_nsec = 1;
+ exit (nanosleep (&ts_sleep, &ts_remaining) == 0 ? 0 : 1);
+ }
+ ],
+ jm_cv_func_nanosleep_works=yes,
+ jm_cv_func_nanosleep_works=no,
+ dnl When crosscompiling, assume the worst.
+ jm_cv_func_nanosleep_works=no)
+ ])
+ if test $jm_cv_func_nanosleep_works = no; then
+ AC_LIBOBJ(nanosleep)
+ AC_DEFINE(nanosleep, rpl_nanosleep,
+ [Define to rpl_nanosleep if the replacement function should be used.])
+ gl_PREREQ_NANOSLEEP
+ fi
+
+ LIBS=$nanosleep_save_libs
+])
+
+# Prerequisites of lib/nanosleep.c.
+AC_DEFUN([gl_PREREQ_NANOSLEEP],
+[
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+ AC_CHECK_FUNCS_ONCE(siginterrupt)
+])
diff --git a/m4/nls.m4 b/m4/nls.m4
new file mode 100644
index 0000000..2082c3b
--- /dev/null
+++ b/m4/nls.m4
@@ -0,0 +1,51 @@
+# nls.m4 serial 2 (gettext-0.14.3)
+dnl Copyright (C) 1995-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003.
+
+AC_PREREQ(2.50)
+
+AC_DEFUN([AM_NLS],
+[
+ AC_MSG_CHECKING([whether NLS is requested])
+ dnl Default is enabled NLS
+ AC_ARG_ENABLE(nls,
+ [ --disable-nls do not use Native Language Support],
+ USE_NLS=$enableval, USE_NLS=yes)
+ AC_MSG_RESULT($USE_NLS)
+ AC_SUBST(USE_NLS)
+])
+
+AC_DEFUN([AM_MKINSTALLDIRS],
+[
+ dnl Tell automake >= 1.10 to complain if mkinstalldirs is missing.
+ m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([mkinstalldirs])])
+ dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly
+ dnl find the mkinstalldirs script in another subdir but $(top_srcdir).
+ dnl Try to locate it.
+ MKINSTALLDIRS=
+ if test -n "$ac_aux_dir"; then
+ case "$ac_aux_dir" in
+ /*) MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" ;;
+ *) MKINSTALLDIRS="\$(top_builddir)/$ac_aux_dir/mkinstalldirs" ;;
+ esac
+ fi
+ if test -z "$MKINSTALLDIRS"; then
+ MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+ fi
+ AC_SUBST(MKINSTALLDIRS)
+])
diff --git a/m4/onceonly_2_57.m4 b/m4/onceonly_2_57.m4
new file mode 100644
index 0000000..14d3c0b
--- /dev/null
+++ b/m4/onceonly_2_57.m4
@@ -0,0 +1,86 @@
+# onceonly_2_57.m4 serial 3
+dnl Copyright (C) 2002-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl This file defines some "once only" variants of standard autoconf macros.
+dnl AC_CHECK_HEADERS_ONCE like AC_CHECK_HEADERS
+dnl AC_CHECK_FUNCS_ONCE like AC_CHECK_FUNCS
+dnl AC_CHECK_DECLS_ONCE like AC_CHECK_DECLS
+dnl AC_REQUIRE([AC_HEADER_STDC]) like AC_HEADER_STDC
+dnl The advantage is that the check for each of the headers/functions/decls
+dnl will be put only once into the 'configure' file. It keeps the size of
+dnl the 'configure' file down, and avoids redundant output when 'configure'
+dnl is run.
+dnl The drawback is that the checks cannot be conditionalized. If you write
+dnl if some_condition; then gl_CHECK_HEADERS(stdlib.h); fi
+dnl inside an AC_DEFUNed function, the gl_CHECK_HEADERS macro call expands to
+dnl empty, and the check will be inserted before the body of the AC_DEFUNed
+dnl function.
+
+dnl This is like onceonly.m4, except that it uses diversions to named sections
+dnl DEFAULTS and INIT_PREPARE in order to check all requested headers at once,
+dnl thus reducing the size of 'configure'. Works with autoconf-2.57. The
+dnl size reduction is ca. 9%.
+
+dnl Autoconf version 2.57 or newer is recommended.
+AC_PREREQ(2.57)
+
+# AC_CHECK_HEADERS_ONCE(HEADER1 HEADER2 ...) is a once-only variant of
+# AC_CHECK_HEADERS(HEADER1 HEADER2 ...).
+AC_DEFUN([AC_CHECK_HEADERS_ONCE], [
+ :
+ AC_FOREACH([gl_HEADER_NAME], [$1], [
+ AC_DEFUN([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME,
+ [./-], [___])), [
+ m4_divert_text([INIT_PREPARE],
+ [gl_header_list="$gl_header_list gl_HEADER_NAME"])
+ gl_HEADERS_EXPANSION
+ AH_TEMPLATE(AS_TR_CPP([HAVE_]m4_defn([gl_HEADER_NAME])),
+ [Define to 1 if you have the <]m4_defn([gl_HEADER_NAME])[> header file.])
+ ])
+ AC_REQUIRE([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME,
+ [./-], [___])))
+ ])
+])
+m4_define([gl_HEADERS_EXPANSION], [
+ m4_divert_text([DEFAULTS], [gl_header_list=])
+ AC_CHECK_HEADERS([$gl_header_list])
+ m4_define([gl_HEADERS_EXPANSION], [])
+])
+
+# AC_CHECK_FUNCS_ONCE(FUNC1 FUNC2 ...) is a once-only variant of
+# AC_CHECK_FUNCS(FUNC1 FUNC2 ...).
+AC_DEFUN([AC_CHECK_FUNCS_ONCE], [
+ :
+ AC_FOREACH([gl_FUNC_NAME], [$1], [
+ AC_DEFUN([gl_CHECK_FUNC_]m4_defn([gl_FUNC_NAME]), [
+ m4_divert_text([INIT_PREPARE],
+ [gl_func_list="$gl_func_list gl_FUNC_NAME"])
+ gl_FUNCS_EXPANSION
+ AH_TEMPLATE(AS_TR_CPP([HAVE_]m4_defn([gl_FUNC_NAME])),
+ [Define to 1 if you have the `]m4_defn([gl_FUNC_NAME])[' function.])
+ ])
+ AC_REQUIRE([gl_CHECK_FUNC_]m4_defn([gl_FUNC_NAME]))
+ ])
+])
+m4_define([gl_FUNCS_EXPANSION], [
+ m4_divert_text([DEFAULTS], [gl_func_list=])
+ AC_CHECK_FUNCS([$gl_func_list])
+ m4_define([gl_FUNCS_EXPANSION], [])
+])
+
+# AC_CHECK_DECLS_ONCE(DECL1 DECL2 ...) is a once-only variant of
+# AC_CHECK_DECLS(DECL1, DECL2, ...).
+AC_DEFUN([AC_CHECK_DECLS_ONCE], [
+ :
+ AC_FOREACH([gl_DECL_NAME], [$1], [
+ AC_DEFUN([gl_CHECK_DECL_]m4_defn([gl_DECL_NAME]), [
+ AC_CHECK_DECLS(m4_defn([gl_DECL_NAME]))
+ ])
+ AC_REQUIRE([gl_CHECK_DECL_]m4_defn([gl_DECL_NAME]))
+ ])
+])
diff --git a/m4/openat.m4 b/m4/openat.m4
new file mode 100644
index 0000000..27b0e59
--- /dev/null
+++ b/m4/openat.m4
@@ -0,0 +1,28 @@
+#serial 3
+# See if we need to use our replacement for Solaris' openat function.
+
+dnl Copyright (C) 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Written by Jim Meyering.
+
+AC_DEFUN([gl_FUNC_OPENAT],
+[
+ AC_LIBSOURCES([openat.c, openat.h])
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ AC_REPLACE_FUNCS(openat)
+ case $ac_cv_func_openat in
+ yes) ;;
+ *)
+ AC_DEFINE([__OPENAT_PREFIX], [[rpl_]],
+ [Define to rpl_ if the openat replacement function should be used.])
+ gl_PREREQ_OPENAT;;
+ esac
+])
+
+AC_DEFUN([gl_PREREQ_OPENAT],
+[
+ AC_REQUIRE([gl_SAVE_CWD])
+])
diff --git a/m4/pagealign_alloc.m4 b/m4/pagealign_alloc.m4
new file mode 100644
index 0000000..b8cdfa9
--- /dev/null
+++ b/m4/pagealign_alloc.m4
@@ -0,0 +1,24 @@
+#serial 2
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_PAGEALIGN_ALLOC],
+[
+ dnl Persuade glibc <sys/mman.h> to define MAP_ANONYMOUS.
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ AC_LIBSOURCE([pagealign_alloc.h])
+ AC_LIBOBJ([pagealign_alloc])
+ gl_PREREQ_PAGEALIGN_ALLOC
+])
+
+# Prerequisites of lib/pagealign_alloc.c.
+AC_DEFUN([gl_PREREQ_PAGEALIGN_ALLOC],
+[
+ AC_REQUIRE([gl_FUNC_MMAP_ANON])
+ AC_REQUIRE([gl_GETPAGESIZE])
+ AC_CHECK_FUNCS_ONCE([posix_memalign])
+ AC_CHECK_HEADERS_ONCE([unistd.h])
+])
diff --git a/m4/pathmax.m4 b/m4/pathmax.m4
new file mode 100644
index 0000000..ccf4a77
--- /dev/null
+++ b/m4/pathmax.m4
@@ -0,0 +1,13 @@
+# pathmax.m4 serial 4
+dnl Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_PATHMAX],
+[
+ AC_LIBSOURCES([pathmax.h])
+
+ dnl Prerequisites of lib/pathmax.h.
+ AC_CHECK_HEADERS_ONCE(sys/param.h unistd.h)
+])
diff --git a/m4/po.m4 b/m4/po.m4
new file mode 100644
index 0000000..f2795ee
--- /dev/null
+++ b/m4/po.m4
@@ -0,0 +1,429 @@
+# po.m4 serial 7 (gettext-0.14.3)
+dnl Copyright (C) 1995-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003.
+
+AC_PREREQ(2.50)
+
+dnl Checks for all prerequisites of the po subdirectory.
+AC_DEFUN([AM_PO_SUBDIRS],
+[
+ AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+ AC_REQUIRE([AC_PROG_INSTALL])dnl
+ AC_REQUIRE([AM_MKINSTALLDIRS])dnl
+ AC_REQUIRE([AM_NLS])dnl
+
+ dnl Perform the following tests also if --disable-nls has been given,
+ dnl because they are needed for "make dist" to work.
+
+ dnl Search for GNU msgfmt in the PATH.
+ dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions.
+ dnl The second test excludes FreeBSD msgfmt.
+ AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+ [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
+ (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
+ :)
+ AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+
+ dnl Search for GNU xgettext 0.12 or newer in the PATH.
+ dnl The first test excludes Solaris xgettext and early GNU xgettext versions.
+ dnl The second test excludes FreeBSD xgettext.
+ AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+ [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
+ (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
+ :)
+ dnl Remove leftover from FreeBSD xgettext call.
+ rm -f messages.po
+
+ dnl Search for GNU msgmerge 0.11 or newer in the PATH.
+ AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge,
+ [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :)
+
+ dnl This could go away some day; the PATH_PROG_WITH_TEST already does it.
+ dnl Test whether we really found GNU msgfmt.
+ if test "$GMSGFMT" != ":"; then
+ dnl If it is no GNU msgfmt we define it as : so that the
+ dnl Makefiles still can work.
+ if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 &&
+ (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ : ;
+ else
+ GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'`
+ AC_MSG_RESULT(
+ [found $GMSGFMT program is not GNU msgfmt; ignore it])
+ GMSGFMT=":"
+ fi
+ fi
+
+ dnl This could go away some day; the PATH_PROG_WITH_TEST already does it.
+ dnl Test whether we really found GNU xgettext.
+ if test "$XGETTEXT" != ":"; then
+ dnl If it is no GNU xgettext we define it as : so that the
+ dnl Makefiles still can work.
+ if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 &&
+ (if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ : ;
+ else
+ AC_MSG_RESULT(
+ [found xgettext program is not GNU xgettext; ignore it])
+ XGETTEXT=":"
+ fi
+ dnl Remove leftover from FreeBSD xgettext call.
+ rm -f messages.po
+ fi
+
+ AC_OUTPUT_COMMANDS([
+ for ac_file in $CONFIG_FILES; do
+ # Support "outfile[:infile[:infile...]]"
+ case "$ac_file" in
+ *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ esac
+ # PO directories have a Makefile.in generated from Makefile.in.in.
+ case "$ac_file" in */Makefile.in)
+ # Adjust a relative srcdir.
+ ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+ ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+ ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+ # In autoconf-2.13 it is called $ac_given_srcdir.
+ # In autoconf-2.50 it is called $srcdir.
+ test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+ case "$ac_given_srcdir" in
+ .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+ /*) top_srcdir="$ac_given_srcdir" ;;
+ *) top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+ # Treat a directory as a PO directory if and only if it has a
+ # POTFILES.in file. This allows packages to have multiple PO
+ # directories under different names or in different locations.
+ if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then
+ rm -f "$ac_dir/POTFILES"
+ test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES"
+ cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES"
+ POMAKEFILEDEPS="POTFILES.in"
+ # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend
+ # on $ac_dir but don't depend on user-specified configuration
+ # parameters.
+ if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+ # The LINGUAS file contains the set of available languages.
+ if test -n "$OBSOLETE_ALL_LINGUAS"; then
+ test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+ fi
+ ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+ # Hide the ALL_LINGUAS assigment from automake.
+ eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+ POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+ else
+ # The set of available languages was given in configure.in.
+ eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS'
+ fi
+ # Compute POFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
+ # Compute UPDATEPOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
+ # Compute DUMMYPOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
+ # Compute GMOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
+ case "$ac_given_srcdir" in
+ .) srcdirpre= ;;
+ *) srcdirpre='$(srcdir)/' ;;
+ esac
+ POFILES=
+ UPDATEPOFILES=
+ DUMMYPOFILES=
+ GMOFILES=
+ for lang in $ALL_LINGUAS; do
+ POFILES="$POFILES $srcdirpre$lang.po"
+ UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+ DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+ GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+ done
+ # CATALOGS depends on both $ac_dir and the user's LINGUAS
+ # environment variable.
+ INST_LINGUAS=
+ if test -n "$ALL_LINGUAS"; then
+ for presentlang in $ALL_LINGUAS; do
+ useit=no
+ if test "%UNSET%" != "$LINGUAS"; then
+ desiredlanguages="$LINGUAS"
+ else
+ desiredlanguages="$ALL_LINGUAS"
+ fi
+ for desiredlang in $desiredlanguages; do
+ # Use the presentlang catalog if desiredlang is
+ # a. equal to presentlang, or
+ # b. a variant of presentlang (because in this case,
+ # presentlang can be used as a fallback for messages
+ # which are not translated in the desiredlang catalog).
+ case "$desiredlang" in
+ "$presentlang"*) useit=yes;;
+ esac
+ done
+ if test $useit = yes; then
+ INST_LINGUAS="$INST_LINGUAS $presentlang"
+ fi
+ done
+ fi
+ CATALOGS=
+ if test -n "$INST_LINGUAS"; then
+ for lang in $INST_LINGUAS; do
+ CATALOGS="$CATALOGS $lang.gmo"
+ done
+ fi
+ test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile"
+ sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile"
+ for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do
+ if test -f "$f"; then
+ case "$f" in
+ *.orig | *.bak | *~) ;;
+ *) cat "$f" >> "$ac_dir/Makefile" ;;
+ esac
+ fi
+ done
+ fi
+ ;;
+ esac
+ done],
+ [# Capture the value of obsolete ALL_LINGUAS because we need it to compute
+ # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it
+ # from automake.
+ eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"'
+ # Capture the value of LINGUAS because we need it to compute CATALOGS.
+ LINGUAS="${LINGUAS-%UNSET%}"
+ ])
+])
+
+dnl Postprocesses a Makefile in a directory containing PO files.
+AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE],
+[
+ # When this code is run, in config.status, two variables have already been
+ # set:
+ # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in,
+ # - LINGUAS is the value of the environment variable LINGUAS at configure
+ # time.
+
+changequote(,)dnl
+ # Adjust a relative srcdir.
+ ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+ ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+ ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+ # In autoconf-2.13 it is called $ac_given_srcdir.
+ # In autoconf-2.50 it is called $srcdir.
+ test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+ case "$ac_given_srcdir" in
+ .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+ /*) top_srcdir="$ac_given_srcdir" ;;
+ *) top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ # Find a way to echo strings without interpreting backslash.
+ if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then
+ gt_echo='echo'
+ else
+ if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then
+ gt_echo='printf %s\n'
+ else
+ echo_func () {
+ cat <<EOT
+$*
+EOT
+ }
+ gt_echo='echo_func'
+ fi
+ fi
+
+ # A sed script that extracts the value of VARIABLE from a Makefile.
+ sed_x_variable='
+# Test if the hold space is empty.
+x
+s/P/P/
+x
+ta
+# Yes it was empty. Look if we have the expected variable definition.
+/^[ ]*VARIABLE[ ]*=/{
+ # Seen the first line of the variable definition.
+ s/^[ ]*VARIABLE[ ]*=//
+ ba
+}
+bd
+:a
+# Here we are processing a line from the variable definition.
+# Remove comment, more precisely replace it with a space.
+s/#.*$/ /
+# See if the line ends in a backslash.
+tb
+:b
+s/\\$//
+# Print the line, without the trailing backslash.
+p
+tc
+# There was no trailing backslash. The end of the variable definition is
+# reached. Clear the hold space.
+s/^.*$//
+x
+bd
+:c
+# A trailing backslash means that the variable definition continues in the
+# next line. Put a nonempty string into the hold space to indicate this.
+s/^.*$/P/
+x
+:d
+'
+changequote([,])dnl
+
+ # Set POTFILES to the value of the Makefile variable POTFILES.
+ sed_x_POTFILES="`$gt_echo \"$sed_x_variable\" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'`"
+ POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"`
+ # Compute POTFILES_DEPS as
+ # $(foreach file, $(POTFILES), $(top_srcdir)/$(file))
+ POTFILES_DEPS=
+ for file in $POTFILES; do
+ POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file"
+ done
+ POMAKEFILEDEPS=""
+
+ if test -n "$OBSOLETE_ALL_LINGUAS"; then
+ test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+ fi
+ if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+ # The LINGUAS file contains the set of available languages.
+ ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+ POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+ else
+ # Set ALL_LINGUAS to the value of the Makefile variable LINGUAS.
+ sed_x_LINGUAS="`$gt_echo \"$sed_x_variable\" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'`"
+ ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"`
+ fi
+ # Hide the ALL_LINGUAS assigment from automake.
+ eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+ # Compute POFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
+ # Compute UPDATEPOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
+ # Compute DUMMYPOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
+ # Compute GMOFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
+ # Compute PROPERTIESFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties)
+ # Compute CLASSFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class)
+ # Compute QMFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm)
+ # Compute MSGFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg)
+ # Compute RESOURCESDLLFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll)
+ case "$ac_given_srcdir" in
+ .) srcdirpre= ;;
+ *) srcdirpre='$(srcdir)/' ;;
+ esac
+ POFILES=
+ UPDATEPOFILES=
+ DUMMYPOFILES=
+ GMOFILES=
+ PROPERTIESFILES=
+ CLASSFILES=
+ QMFILES=
+ MSGFILES=
+ RESOURCESDLLFILES=
+ for lang in $ALL_LINGUAS; do
+ POFILES="$POFILES $srcdirpre$lang.po"
+ UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+ DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+ GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+ PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties"
+ CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class"
+ QMFILES="$QMFILES $srcdirpre$lang.qm"
+ frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+ MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg"
+ frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+ RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll"
+ done
+ # CATALOGS depends on both $ac_dir and the user's LINGUAS
+ # environment variable.
+ INST_LINGUAS=
+ if test -n "$ALL_LINGUAS"; then
+ for presentlang in $ALL_LINGUAS; do
+ useit=no
+ if test "%UNSET%" != "$LINGUAS"; then
+ desiredlanguages="$LINGUAS"
+ else
+ desiredlanguages="$ALL_LINGUAS"
+ fi
+ for desiredlang in $desiredlanguages; do
+ # Use the presentlang catalog if desiredlang is
+ # a. equal to presentlang, or
+ # b. a variant of presentlang (because in this case,
+ # presentlang can be used as a fallback for messages
+ # which are not translated in the desiredlang catalog).
+ case "$desiredlang" in
+ "$presentlang"*) useit=yes;;
+ esac
+ done
+ if test $useit = yes; then
+ INST_LINGUAS="$INST_LINGUAS $presentlang"
+ fi
+ done
+ fi
+ CATALOGS=
+ JAVACATALOGS=
+ QTCATALOGS=
+ TCLCATALOGS=
+ CSHARPCATALOGS=
+ if test -n "$INST_LINGUAS"; then
+ for lang in $INST_LINGUAS; do
+ CATALOGS="$CATALOGS $lang.gmo"
+ JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties"
+ QTCATALOGS="$QTCATALOGS $lang.qm"
+ frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+ TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg"
+ frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+ CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll"
+ done
+ fi
+
+ sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$ac_file.tmp"
+ if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then
+ # Add dependencies that cannot be formulated as a simple suffix rule.
+ for lang in $ALL_LINGUAS; do
+ frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+ cat >> "$ac_file.tmp" <<EOF
+$frobbedlang.msg: $lang.po
+ @echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \
+ \$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+ done
+ fi
+ if grep -l '@CSHARPCATALOGS@' "$ac_file" > /dev/null; then
+ # Add dependencies that cannot be formulated as a simple suffix rule.
+ for lang in $ALL_LINGUAS; do
+ frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+ cat >> "$ac_file.tmp" <<EOF
+$frobbedlang/\$(DOMAIN).resources.dll: $lang.po
+ @echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \
+ \$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+ done
+ fi
+ if test -n "$POMAKEFILEDEPS"; then
+ cat >> "$ac_file.tmp" <<EOF
+Makefile: $POMAKEFILEDEPS
+EOF
+ fi
+ mv "$ac_file.tmp" "$ac_file"
+])
diff --git a/m4/progtest.m4 b/m4/progtest.m4
new file mode 100644
index 0000000..a56365c
--- /dev/null
+++ b/m4/progtest.m4
@@ -0,0 +1,92 @@
+# progtest.m4 serial 4 (gettext-0.14.2)
+dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+AC_PREREQ(2.50)
+
+# Search path for a program which passes the given test.
+
+dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+AC_DEFUN([AM_PATH_PROG_WITH_TEST],
+[
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+ ac_executable_p="test -x"
+else
+ ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+ [[\\/]]* | ?:[[\\/]]*)
+ ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in ifelse([$5], , $PATH, [$5]); do
+ IFS="$ac_save_IFS"
+ test -z "$ac_dir" && ac_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+ echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD
+ if [$3]; then
+ ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext"
+ break 2
+ fi
+ fi
+ done
+ done
+ IFS="$ac_save_IFS"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+ ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then
+ AC_MSG_RESULT([$]$1)
+else
+ AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
diff --git a/m4/quotearg.m4 b/m4/quotearg.m4
new file mode 100644
index 0000000..98ae133
--- /dev/null
+++ b/m4/quotearg.m4
@@ -0,0 +1,17 @@
+# quotearg.m4 serial 4
+dnl Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_QUOTEARG],
+[
+ AC_LIBSOURCES([quotearg.c, quotearg.h])
+ AC_LIBOBJ([quotearg])
+
+ dnl Prerequisites of lib/quotearg.c.
+ AC_CHECK_HEADERS_ONCE(wchar.h wctype.h)
+ AC_CHECK_FUNCS_ONCE(iswprint mbsinit)
+ AC_TYPE_MBSTATE_T
+ gl_FUNC_MBRTOWC
+])
diff --git a/m4/readlink.m4 b/m4/readlink.m4
new file mode 100644
index 0000000..b4a7f55
--- /dev/null
+++ b/m4/readlink.m4
@@ -0,0 +1,20 @@
+# readlink.m4 serial 2
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_READLINK],
+[
+ AC_CHECK_FUNCS(readlink)
+ if test $ac_cv_func_readlink = no; then
+ AC_LIBOBJ(readlink)
+ gl_PREREQ_READLINK
+ fi
+])
+
+# Prerequisites of lib/readlink.c.
+AC_DEFUN([gl_PREREQ_READLINK],
+[
+ :
+])
diff --git a/m4/regex.m4 b/m4/regex.m4
new file mode 100644
index 0000000..6addb10
--- /dev/null
+++ b/m4/regex.m4
@@ -0,0 +1,136 @@
+#serial 29
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free
+# Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl Initially derived from code in GNU grep.
+dnl Mostly written by Jim Meyering.
+
+AC_PREREQ([2.50])
+
+AC_DEFUN([gl_REGEX],
+[
+ AC_REQUIRE([AC_SYS_LARGEFILE]) dnl for a sufficently-wide off_t
+ AC_DEFINE([_REGEX_LARGE_OFFSETS], 1,
+ [Define if you want regoff_t to be at least as wide POSIX requires.])
+
+ AC_LIBSOURCES(
+ [regcomp.c, regex.c, regex.h,
+ regex_internal.c, regex_internal.h, regexec.c])
+
+ AC_ARG_WITH([included-regex],
+ [AC_HELP_STRING([--without-included-regex],
+ [don't compile regex; this is the default on
+ systems with recent-enough versions of the GNU C
+ Library (use with caution on other systems)])])
+
+ case $with_included_regex in
+ yes|no) ac_use_included_regex=$with_included_regex
+ ;;
+ '')
+ # If the system regex support is good enough that it passes the the
+ # following run test, then default to *not* using the included regex.c.
+ # If cross compiling, assume the test would fail and use the included
+ # regex.c. The first failing regular expression is from `Spencer ere
+ # test #75' in grep-2.3.
+ AC_CACHE_CHECK([for working re_compile_pattern],
+ [gl_cv_func_re_compile_pattern_broken],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [AC_INCLUDES_DEFAULT
+ #include <regex.h>],
+ [[static struct re_pattern_buffer regex;
+ const char *s;
+ struct re_registers regs;
+ /* Use the POSIX-compliant spelling with leading REG_,
+ rather than the traditional GNU spelling with leading RE_,
+ so that we reject older libc implementations. */
+ re_set_syntax (REG_SYNTAX_POSIX_EGREP);
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("a[:@:>@:]b\n", 9, &regex);
+ /* This should fail with _Invalid character class name_ error. */
+ if (!s)
+ exit (1);
+
+ /* This should succeed, but does not for e.g. glibc-2.1.3. */
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("{1", 2, &regex);
+
+ if (s)
+ exit (1);
+
+ /* The following example is derived from a problem report
+ against gawk from Jorge Stolfi <stolfi@ic.unicamp.br>. */
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("[an\371]*n", 7, &regex);
+ if (s)
+ exit (1);
+
+ /* This should match, but does not for e.g. glibc-2.2.1. */
+ if (re_match (&regex, "an", 2, 0, &regs) != 2)
+ exit (1);
+
+ memset (&regex, 0, sizeof (regex));
+ s = re_compile_pattern ("x", 1, &regex);
+ if (s)
+ exit (1);
+
+ /* The version of regex.c in e.g. GNU libc-2.2.93 did not
+ work with a negative RANGE argument. */
+ if (re_search (&regex, "wxy", 3, 2, -2, &regs) != 1)
+ exit (1);
+
+ /* The version of regex.c in older versions of gnulib
+ ignored REG_IGNORE_CASE (which was then called RE_ICASE).
+ Detect that problem too. */
+ memset (&regex, 0, sizeof (regex));
+ re_set_syntax (REG_SYNTAX_EMACS | REG_IGNORE_CASE);
+ s = re_compile_pattern ("x", 1, &regex);
+ if (s)
+ exit (1);
+
+ if (re_search (&regex, "WXY", 3, 0, 3, &regs) < 0)
+ exit (1);
+
+ /* REG_STARTEND was added to glibc on 2004-01-15.
+ Reject older versions. */
+ if (! REG_STARTEND)
+ exit (1);
+
+ /* Reject hosts whose regoff_t values are too narrow.
+ These include glibc 2.3.5 on hosts with 64-bit off_t
+ and 32-bit int, and Solaris 10 on hosts with 32-bit int
+ and _FILE_OFFSET_BITS=64. */
+ if (sizeof (regoff_t) < sizeof (off_t))
+ exit (1);
+
+ exit (0);]])],
+ [gl_cv_func_re_compile_pattern_broken=no],
+ [gl_cv_func_re_compile_pattern_broken=yes],
+ dnl When crosscompiling, assume it is broken.
+ [gl_cv_func_re_compile_pattern_broken=yes])])
+ ac_use_included_regex=$gl_cv_func_re_compile_pattern_broken
+ ;;
+ *) AC_MSG_ERROR([Invalid value for --with-included-regex: $with_included_regex])
+ ;;
+ esac
+
+ if test $ac_use_included_regex = yes; then
+ AC_LIBOBJ([regex])
+ gl_PREREQ_REGEX
+ fi
+])
+
+# Prerequisites of lib/regex.c and lib/regex_internal.c.
+AC_DEFUN([gl_PREREQ_REGEX],
+[
+ AC_REQUIRE([AC_GNU_SOURCE])
+ AC_REQUIRE([gl_C_RESTRICT])
+ AC_REQUIRE([AM_LANGINFO_CODESET])
+ AC_CHECK_HEADERS_ONCE([locale.h wchar.h wctype.h])
+ AC_CHECK_FUNCS_ONCE([isblank mbrtowc mempcpy wcrtomb wcscoll])
+])
diff --git a/m4/rename.m4 b/m4/rename.m4
new file mode 100644
index 0000000..1c9e0e9
--- /dev/null
+++ b/m4/rename.m4
@@ -0,0 +1,51 @@
+#serial 8
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Volker Borchert.
+dnl Determine whether rename works for source file names with a trailing slash.
+dnl The rename from SunOS 4.1.1_U1 doesn't.
+dnl
+dnl If it doesn't, then define RENAME_TRAILING_SLASH_BUG and arrange
+dnl to compile the wrapper function.
+dnl
+
+AC_DEFUN([vb_FUNC_RENAME],
+[
+ AC_CACHE_CHECK([whether rename is broken],
+ vb_cv_func_rename_trailing_slash_bug,
+ [
+ rm -rf conftest.d1 conftest.d2
+ mkdir conftest.d1 ||
+ AC_MSG_ERROR([cannot create temporary directory])
+ AC_TRY_RUN([
+# include <stdio.h>
+ int
+ main ()
+ {
+ exit (rename ("conftest.d1/", "conftest.d2") ? 1 : 0);
+ }
+ ],
+ vb_cv_func_rename_trailing_slash_bug=no,
+ vb_cv_func_rename_trailing_slash_bug=yes,
+ dnl When crosscompiling, assume rename is broken.
+ vb_cv_func_rename_trailing_slash_bug=yes)
+
+ rm -rf conftest.d1 conftest.d2
+ ])
+ if test $vb_cv_func_rename_trailing_slash_bug = yes; then
+ AC_LIBOBJ(rename)
+ AC_DEFINE(rename, rpl_rename,
+ [Define to rpl_rename if the replacement function should be used.])
+ AC_DEFINE(RENAME_TRAILING_SLASH_BUG, 1,
+ [Define if rename does not work for source file names with a trailing
+ slash, like the one from SunOS 4.1.1_U1.])
+ gl_PREREQ_RENAME
+ fi
+])
+
+# Prerequisites of lib/rename.c.
+AC_DEFUN([gl_PREREQ_RENAME], [:])
diff --git a/m4/restrict.m4 b/m4/restrict.m4
new file mode 100644
index 0000000..1f3bbb9
--- /dev/null
+++ b/m4/restrict.m4
@@ -0,0 +1,38 @@
+#serial 1003
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# This macro can be removed once we can rely on Autoconf 2.57a or later,
+# since we can then use its AC_C_RESTRICT.
+
+# gl_C_RESTRICT
+# --------------
+# Determine whether the C/C++ compiler supports the "restrict" keyword
+# introduced in ANSI C99, or an equivalent. Do nothing if the compiler
+# accepts it. Otherwise, if the compiler supports an equivalent,
+# define "restrict" to be that. Here are some variants:
+# - GCC supports both __restrict and __restrict__
+# - older DEC Alpha C compilers support only __restrict
+# - _Restrict is the only spelling accepted by Sun WorkShop 6 update 2 C
+# Otherwise, define "restrict" to be empty.
+AC_DEFUN([gl_C_RESTRICT],
+[AC_CACHE_CHECK([for C/C++ restrict keyword], gl_cv_c_restrict,
+ [gl_cv_c_restrict=no
+ # Try the official restrict keyword, then gcc's __restrict, and
+ # the less common variants.
+ for ac_kw in restrict __restrict __restrict__ _Restrict; do
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+ [float * $ac_kw x;])],
+ [gl_cv_c_restrict=$ac_kw; break])
+ done
+ ])
+ case $gl_cv_c_restrict in
+ restrict) ;;
+ no) AC_DEFINE(restrict,,
+ [Define to equivalent of C99 restrict keyword, or to nothing if this
+ is not supported. Do not define if restrict is supported directly.]) ;;
+ *) AC_DEFINE_UNQUOTED(restrict, $gl_cv_c_restrict) ;;
+ esac
+])
diff --git a/m4/rpmatch.m4 b/m4/rpmatch.m4
new file mode 100644
index 0000000..4a471ac
--- /dev/null
+++ b/m4/rpmatch.m4
@@ -0,0 +1,16 @@
+# rpmatch.m4 serial 5
+dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_RPMATCH],
+[
+ AC_REPLACE_FUNCS(rpmatch)
+ if test $ac_cv_func_rpmatch = no; then
+ gl_PREREQ_RPMATCH
+ fi
+])
+
+# Prerequisites of lib/rpmatch.c.
+AC_DEFUN([gl_PREREQ_RPMATCH], [:])
diff --git a/m4/save-cwd.m4 b/m4/save-cwd.m4
new file mode 100644
index 0000000..7acdfeb
--- /dev/null
+++ b/m4/save-cwd.m4
@@ -0,0 +1,14 @@
+#serial 6
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_SAVE_CWD],
+[
+ AC_LIBSOURCES([save-cwd.c, save-cwd.h])
+ AC_LIBOBJ([save-cwd])
+ dnl Prerequisites for lib/save-cwd.c.
+ AC_CHECK_FUNCS_ONCE(fchdir)
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+])
diff --git a/m4/setenv.m4 b/m4/setenv.m4
new file mode 100644
index 0000000..4c76be1
--- /dev/null
+++ b/m4/setenv.m4
@@ -0,0 +1,70 @@
+# setenv.m4 serial 5
+dnl Copyright (C) 2001-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gt_FUNC_SETENV],
+[
+ AC_REPLACE_FUNCS(setenv unsetenv)
+ if test $ac_cv_func_setenv = no; then
+ gl_PREREQ_SETENV
+ fi
+ if test $ac_cv_func_unsetenv = no; then
+ gl_PREREQ_UNSETENV
+ else
+ AC_CACHE_CHECK([for unsetenv() return type], gt_cv_func_unsetenv_ret,
+ [AC_TRY_COMPILE([#include <stdlib.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+int unsetenv (const char *name);
+#else
+int unsetenv();
+#endif
+], , gt_cv_func_unsetenv_ret='int', gt_cv_func_unsetenv_ret='void')])
+ if test $gt_cv_func_unsetenv_ret = 'void'; then
+ AC_DEFINE(VOID_UNSETENV, 1, [Define if unsetenv() returns void, not int.])
+ fi
+ fi
+])
+
+# Check if a variable is properly declared.
+# gt_CHECK_VAR_DECL(includes,variable)
+AC_DEFUN([gt_CHECK_VAR_DECL],
+[
+ define([gt_cv_var], [gt_cv_var_]$2[_declaration])
+ AC_MSG_CHECKING([if $2 is properly declared])
+ AC_CACHE_VAL(gt_cv_var, [
+ AC_TRY_COMPILE([$1
+ extern struct { int foo; } $2;],
+ [$2.foo = 1;],
+ gt_cv_var=no,
+ gt_cv_var=yes)])
+ AC_MSG_RESULT($gt_cv_var)
+ if test $gt_cv_var = yes; then
+ AC_DEFINE([HAVE_]translit($2, [a-z], [A-Z])[_DECL], 1,
+ [Define if you have the declaration of $2.])
+ fi
+])
+
+# Prerequisites of lib/setenv.c.
+AC_DEFUN([gl_PREREQ_SETENV],
+[
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+ AC_CHECK_HEADERS(search.h)
+ AC_CHECK_FUNCS(tsearch)
+ gt_CHECK_VAR_DECL([#include <errno.h>], errno)
+ gt_CHECK_VAR_DECL([#include <unistd.h>], environ)
+])
+
+# Prerequisites of lib/unsetenv.c.
+AC_DEFUN([gl_PREREQ_UNSETENV],
+[
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+ gt_CHECK_VAR_DECL([#include <errno.h>], errno)
+ gt_CHECK_VAR_DECL([#include <unistd.h>], environ)
+])
diff --git a/m4/signed.m4 b/m4/signed.m4
new file mode 100644
index 0000000..048f593
--- /dev/null
+++ b/m4/signed.m4
@@ -0,0 +1,17 @@
+# signed.m4 serial 1 (gettext-0.10.40)
+dnl Copyright (C) 2001-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([bh_C_SIGNED],
+[
+ AC_CACHE_CHECK([for signed], bh_cv_c_signed,
+ [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)])
+ if test $bh_cv_c_signed = no; then
+ AC_DEFINE(signed, ,
+ [Define to empty if the C compiler doesn't support this keyword.])
+ fi
+])
diff --git a/m4/size_max.m4 b/m4/size_max.m4
new file mode 100644
index 0000000..0336f3a
--- /dev/null
+++ b/m4/size_max.m4
@@ -0,0 +1,59 @@
+# size_max.m4 serial 3
+dnl Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([gl_SIZE_MAX],
+[
+ AC_CHECK_HEADERS(stdint.h)
+ dnl First test whether the system already has SIZE_MAX.
+ AC_MSG_CHECKING([for SIZE_MAX])
+ result=
+ AC_EGREP_CPP([Found it], [
+#include <limits.h>
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef SIZE_MAX
+Found it
+#endif
+], result=yes)
+ if test -z "$result"; then
+ dnl Define it ourselves. Here we assume that the type 'size_t' is not wider
+ dnl than the type 'unsigned long'.
+ dnl The _AC_COMPUTE_INT macro works up to LONG_MAX, since it uses 'expr',
+ dnl which is guaranteed to work from LONG_MIN to LONG_MAX.
+ _AC_COMPUTE_INT([(size_t)~(size_t)0 / 10], res_hi,
+ [#include <stddef.h>], result=?)
+ _AC_COMPUTE_INT([(size_t)~(size_t)0 % 10], res_lo,
+ [#include <stddef.h>], result=?)
+ _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint,
+ [#include <stddef.h>], result=?)
+ if test "$fits_in_uint" = 1; then
+ dnl Even though SIZE_MAX fits in an unsigned int, it must be of type
+ dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'.
+ AC_TRY_COMPILE([#include <stddef.h>
+ extern size_t foo;
+ extern unsigned long foo;
+ ], [], fits_in_uint=0)
+ fi
+ if test -z "$result"; then
+ if test "$fits_in_uint" = 1; then
+ result="$res_hi$res_lo"U
+ else
+ result="$res_hi$res_lo"UL
+ fi
+ else
+ dnl Shouldn't happen, but who knows...
+ result='((size_t)~(size_t)0)'
+ fi
+ fi
+ AC_MSG_RESULT([$result])
+ if test "$result" != yes; then
+ AC_DEFINE_UNQUOTED([SIZE_MAX], [$result],
+ [Define as the maximum value of type 'size_t', if the system doesn't define it.])
+ fi
+])
diff --git a/m4/sockpfaf.m4 b/m4/sockpfaf.m4
new file mode 100644
index 0000000..b224fae
--- /dev/null
+++ b/m4/sockpfaf.m4
@@ -0,0 +1,39 @@
+# sockpfaf.m4 serial 2
+dnl Copyright (C) 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Test for some common socket protocol families (PF_INET, PF_INET6, ...)
+dnl and some common address families (AF_INET, AF_INET6, ...).
+dnl This test assumes that a system supports an address family if and only if
+dnl it supports the corresponding protocol family.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([gl_SOCKET_FAMILIES],
+[
+ AC_MSG_CHECKING(for IPv4 sockets)
+ AC_CACHE_VAL(gl_cv_socket_ipv4,
+ [AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>],
+[int x = AF_INET; struct in_addr y; struct sockaddr_in z;],
+ gl_cv_socket_ipv4=yes, gl_cv_socket_ipv4=no)])
+ AC_MSG_RESULT($gl_cv_socket_ipv4)
+ if test $gl_cv_socket_ipv4 = yes; then
+ AC_DEFINE(HAVE_IPV4, 1, [Define to 1 if <sys/socket.h> defines AF_INET.])
+ fi
+
+ AC_MSG_CHECKING(for IPv6 sockets)
+ AC_CACHE_VAL(gl_cv_socket_ipv6,
+ [AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>],
+[int x = AF_INET6; struct in6_addr y; struct sockaddr_in6 z;],
+ gl_cv_socket_ipv6=yes, gl_cv_socket_ipv6=no)])
+ AC_MSG_RESULT($gl_cv_socket_ipv6)
+ if test $gl_cv_socket_ipv6 = yes; then
+ AC_DEFINE(HAVE_IPV6, 1, [Define to 1 if <sys/socket.h> defines AF_INET6.])
+ fi
+])
diff --git a/m4/ssize_t.m4 b/m4/ssize_t.m4
new file mode 100644
index 0000000..19b379f
--- /dev/null
+++ b/m4/ssize_t.m4
@@ -0,0 +1,20 @@
+# ssize_t.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether ssize_t is defined.
+
+AC_DEFUN([gt_TYPE_SSIZE_T],
+[
+ AC_CACHE_CHECK([for ssize_t], gt_cv_ssize_t,
+ [AC_TRY_COMPILE([#include <sys/types.h>],
+ [int x = sizeof (ssize_t *) + sizeof (ssize_t);],
+ gt_cv_ssize_t=yes, gt_cv_ssize_t=no)])
+ if test $gt_cv_ssize_t = no; then
+ AC_DEFINE(ssize_t, int,
+ [Define as a signed type of the same size as size_t.])
+ fi
+])
diff --git a/m4/stat-macros.m4 b/m4/stat-macros.m4
new file mode 100644
index 0000000..b01218a
--- /dev/null
+++ b/m4/stat-macros.m4
@@ -0,0 +1,14 @@
+#serial 2
+
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_STAT_MACROS],
+[
+ AC_LIBSOURCES([stat-macros.h])
+
+ AC_REQUIRE([AC_HEADER_STAT])
+])
diff --git a/m4/stdbool.m4 b/m4/stdbool.m4
new file mode 100644
index 0000000..3f6b4bf
--- /dev/null
+++ b/m4/stdbool.m4
@@ -0,0 +1,83 @@
+# Check for stdbool.h that conforms to C99.
+
+dnl Copyright (C) 2002-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Prepare for substituting <stdbool.h> if it is not supported.
+
+AC_DEFUN([AM_STDBOOL_H],
+[
+ AC_REQUIRE([AC_HEADER_STDBOOL])
+
+ # Define two additional variables used in the Makefile substitution.
+
+ if test "$ac_cv_header_stdbool_h" = yes; then
+ STDBOOL_H=''
+ else
+ STDBOOL_H='stdbool.h'
+ fi
+ AC_SUBST([STDBOOL_H])
+
+ if test "$ac_cv_type__Bool" = yes; then
+ HAVE__BOOL=1
+ else
+ HAVE__BOOL=0
+ fi
+ AC_SUBST([HAVE__BOOL])
+])
+
+# This macro is only needed in autoconf <= 2.59. Newer versions of autoconf
+# have this macro built-in.
+
+AC_DEFUN([AC_HEADER_STDBOOL],
+ [AC_CACHE_CHECK([for stdbool.h that conforms to C99],
+ [ac_cv_header_stdbool_h],
+ [AC_TRY_COMPILE(
+ [
+ #include <stdbool.h>
+ #ifndef bool
+ "error: bool is not defined"
+ #endif
+ #ifndef false
+ "error: false is not defined"
+ #endif
+ #if false
+ "error: false is not 0"
+ #endif
+ #ifndef true
+ "error: true is not defined"
+ #endif
+ #if true != 1
+ "error: true is not 1"
+ #endif
+ #ifndef __bool_true_false_are_defined
+ "error: __bool_true_false_are_defined is not defined"
+ #endif
+
+ struct s { _Bool s: 1; _Bool t; } s;
+
+ char a[true == 1 ? 1 : -1];
+ char b[false == 0 ? 1 : -1];
+ char c[__bool_true_false_are_defined == 1 ? 1 : -1];
+ char d[(bool) -0.5 == true ? 1 : -1];
+ bool e = &s;
+ char f[(_Bool) -0.0 == false ? 1 : -1];
+ char g[true];
+ char h[sizeof (_Bool)];
+ char i[sizeof s.t];
+ enum { j = false, k = true, l = false * true, m = true * 256 };
+ _Bool n[m];
+ char o[sizeof n == m * sizeof n[0] ? 1 : -1];
+ ],
+ [
+ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !j + !k + !l
+ + !m + !n + !o);
+ ],
+ [ac_cv_header_stdbool_h=yes],
+ [ac_cv_header_stdbool_h=no])])
+ AC_CHECK_TYPES([_Bool])
+ if test $ac_cv_header_stdbool_h = yes; then
+ AC_DEFINE(HAVE_STDBOOL_H, 1, [Define to 1 if stdbool.h conforms to C99.])
+ fi])
diff --git a/m4/stdint.m4 b/m4/stdint.m4
new file mode 100644
index 0000000..4875752
--- /dev/null
+++ b/m4/stdint.m4
@@ -0,0 +1,58 @@
+# stdint.m4 serial 4
+dnl Copyright (C) 2001-2002, 2004-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <stdint.h> is supported or must be substituted.
+
+AC_DEFUN([gl_STDINT_H],
+[dnl Check for <inttypes.h>.
+AC_REQUIRE([gt_HEADER_INTTYPES_H])
+dnl Check for <sys/inttypes.h>.
+AC_CHECK_HEADERS([sys/inttypes.h])
+
+AC_MSG_CHECKING([for stdint.h])
+AC_CACHE_VAL(gl_cv_header_stdint_h, [
+ AC_TRY_COMPILE([#include <stdint.h>], [],
+ gl_cv_header_stdint_h=yes, gl_cv_header_stdint_h=no)])
+AC_MSG_RESULT([$gl_cv_header_stdint_h])
+if test $gl_cv_header_stdint_h = yes; then
+ AC_DEFINE(HAVE_STDINT_H, 1,
+ [Define if you have a working <stdint.h> header file.])
+ STDINT_H=''
+else
+ STDINT_H='stdint.h'
+
+ dnl Is long == int64_t ?
+ AC_CACHE_CHECK([whether 'long' is 64 bit wide], gl_cv_long_bitsize_64, [
+ AC_TRY_COMPILE([
+#define POW63 ((((((long) 1 << 15) << 15) << 15) << 15) << 3)
+#define POW64 ((((((long) 1 << 15) << 15) << 15) << 15) << 4)
+typedef int array [2 * (POW63 != 0 && POW64 == 0) - 1];
+], , gl_cv_long_bitsize_64=yes, gl_cv_long_bitsize_64=no)])
+ if test $gl_cv_long_bitsize_64 = yes; then
+ HAVE_LONG_64BIT=1
+ else
+ HAVE_LONG_64BIT=0
+ fi
+ AC_SUBST(HAVE_LONG_64BIT)
+
+ dnl Is long long == int64_t ?
+ AC_CACHE_CHECK([whether 'long long' is 64 bit wide], gl_cv_longlong_bitsize_64, [
+ AC_TRY_COMPILE([
+#define POW63 ((((((long long) 1 << 15) << 15) << 15) << 15) << 3)
+#define POW64 ((((((long long) 1 << 15) << 15) << 15) << 15) << 4)
+typedef int array [2 * (POW63 != 0 && POW64 == 0) - 1];
+], , gl_cv_longlong_bitsize_64=yes, gl_cv_longlong_bitsize_64=no)])
+ if test $gl_cv_longlong_bitsize_64 = yes; then
+ HAVE_LONG_LONG_64BIT=1
+ else
+ HAVE_LONG_LONG_64BIT=0
+ fi
+ AC_SUBST(HAVE_LONG_LONG_64BIT)
+
+fi
+AC_SUBST(STDINT_H)
+])
diff --git a/m4/stdint_h.m4 b/m4/stdint_h.m4
new file mode 100644
index 0000000..3355f35
--- /dev/null
+++ b/m4/stdint_h.m4
@@ -0,0 +1,26 @@
+# stdint_h.m4 serial 5
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_STDINT_H_WITH_UINTMAX if <stdint.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_STDINT_H],
+[
+ AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h,
+ [AC_TRY_COMPILE(
+ [#include <sys/types.h>
+#include <stdint.h>],
+ [uintmax_t i = (uintmax_t) -1;],
+ gl_cv_header_stdint_h=yes,
+ gl_cv_header_stdint_h=no)])
+ if test $gl_cv_header_stdint_h = yes; then
+ AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1,
+ [Define if <stdint.h> exists, doesn't clash with <sys/types.h>,
+ and declares uintmax_t. ])
+ fi
+])
diff --git a/m4/strcase.m4 b/m4/strcase.m4
new file mode 100644
index 0000000..8a8ff3a
--- /dev/null
+++ b/m4/strcase.m4
@@ -0,0 +1,38 @@
+# strcase.m4 serial 2
+dnl Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_STRCASE],
+[
+ gl_FUNC_STRCASECMP
+ gl_FUNC_STRNCASECMP
+])
+
+AC_DEFUN([gl_FUNC_STRCASECMP],
+[
+ dnl No known system has a strcasecmp() function that works correctly in
+ dnl multibyte locales. Therefore we use our version always.
+ AC_LIBOBJ(strcasecmp)
+ AC_DEFINE(strcasecmp, rpl_strcasecmp, [Define to rpl_strcasecmp always.])
+ gl_PREREQ_STRCASECMP
+])
+
+AC_DEFUN([gl_FUNC_STRNCASECMP],
+[
+ AC_REPLACE_FUNCS(strncasecmp)
+ if test $ac_cv_func_strncasecmp = no; then
+ gl_PREREQ_STRNCASECMP
+ fi
+])
+
+# Prerequisites of lib/strcasecmp.c.
+AC_DEFUN([gl_PREREQ_STRCASECMP], [
+ gl_FUNC_MBRTOWC
+])
+
+# Prerequisites of lib/strncasecmp.c.
+AC_DEFUN([gl_PREREQ_STRNCASECMP], [
+ :
+])
diff --git a/m4/strdup.m4 b/m4/strdup.m4
new file mode 100644
index 0000000..42325ab
--- /dev/null
+++ b/m4/strdup.m4
@@ -0,0 +1,17 @@
+# strdup.m4 serial 6
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRDUP],
+[
+ AC_LIBSOURCES([strdup.c, strdup.h])
+
+ AC_REPLACE_FUNCS(strdup)
+ AC_CHECK_DECLS_ONCE(strdup)
+ gl_PREREQ_STRDUP
+])
+
+# Prerequisites of lib/strdup.c.
+AC_DEFUN([gl_PREREQ_STRDUP], [:])
diff --git a/m4/strerror.m4 b/m4/strerror.m4
new file mode 100644
index 0000000..32bc7ed
--- /dev/null
+++ b/m4/strerror.m4
@@ -0,0 +1,18 @@
+# strerror.m4 serial 2
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRERROR],
+[
+ AC_REPLACE_FUNCS(strerror)
+ if test $ac_cv_func_strerror = no; then
+ gl_PREREQ_STRERROR
+ fi
+])
+
+# Prerequisites of lib/strerror.c.
+AC_DEFUN([gl_PREREQ_STRERROR], [
+ :
+])
diff --git a/m4/strftime.m4 b/m4/strftime.m4
new file mode 100644
index 0000000..64cdf2b
--- /dev/null
+++ b/m4/strftime.m4
@@ -0,0 +1,38 @@
+#serial 25
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Jim Meyering and Paul Eggert.
+
+AC_DEFUN([gl_FUNC_GNU_STRFTIME],
+[AC_REQUIRE([gl_FUNC_STRFTIME])dnl
+ AC_REQUIRE([AC_C_CONST])dnl
+])
+
+# These are the prerequisite macros for GNU's strftime.c replacement.
+AC_DEFUN([gl_FUNC_STRFTIME],
+[
+ AC_LIBSOURCES([strftime.c, strftime.h])
+ AC_LIBOBJ([strftime])
+
+ # strftime.c uses the underyling system strftime if it exists.
+ AC_REQUIRE([AC_FUNC_STRFTIME])
+
+ # This defines (or not) HAVE_TZNAME and HAVE_TM_ZONE.
+ AC_REQUIRE([AC_STRUCT_TIMEZONE])
+
+ AC_REQUIRE([AC_HEADER_TIME])
+ AC_REQUIRE([AC_TYPE_MBSTATE_T])
+ AC_REQUIRE([gl_TM_GMTOFF])
+
+ AC_CHECK_FUNCS_ONCE(mblen mbrlen mempcpy tzset)
+ AC_CHECK_HEADERS_ONCE(sys/time.h wchar.h)
+
+ AC_DEFINE([my_strftime], [nstrftime],
+ [Define to the name of the strftime replacement function.])
+])
diff --git a/m4/strstr.m4 b/m4/strstr.m4
new file mode 100644
index 0000000..aea809e
--- /dev/null
+++ b/m4/strstr.m4
@@ -0,0 +1,18 @@
+# strstr.m4 serial 4
+dnl Copyright (C) 2002-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRSTR],
+[
+ dnl No known system has a strstr() function that works correctly in
+ dnl multibyte locales. Therefore we use our version always.
+ AC_LIBOBJ(strstr)
+ gl_PREREQ_STRSTR
+])
+
+# Prerequisites of lib/strstr.c.
+AC_DEFUN([gl_PREREQ_STRSTR], [
+ gl_FUNC_MBRTOWC
+])
diff --git a/m4/strtol.m4 b/m4/strtol.m4
new file mode 100644
index 0000000..b9308ed
--- /dev/null
+++ b/m4/strtol.m4
@@ -0,0 +1,19 @@
+# strtol.m4 serial 3
+dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRTOL],
+[
+ AC_REPLACE_FUNCS(strtol)
+ if test $ac_cv_func_strtol = no; then
+ gl_PREREQ_STRTOL
+ fi
+])
+
+# Prerequisites of lib/strtol.c.
+AC_DEFUN([gl_PREREQ_STRTOL], [
+ AC_REQUIRE([AC_HEADER_STDC])
+ AC_CHECK_FUNCS_ONCE(isascii)
+])
diff --git a/m4/strtoul.m4 b/m4/strtoul.m4
new file mode 100644
index 0000000..512cd09
--- /dev/null
+++ b/m4/strtoul.m4
@@ -0,0 +1,18 @@
+# strtoul.m4 serial 2
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRTOUL],
+[
+ AC_REPLACE_FUNCS(strtoul)
+ if test $ac_cv_func_strtoul = no; then
+ gl_PREREQ_STRTOUL
+ fi
+])
+
+# Prerequisites of lib/strtoul.c.
+AC_DEFUN([gl_PREREQ_STRTOUL], [
+ gl_PREREQ_STRTOL
+])
diff --git a/m4/sunos57-select.m4 b/m4/sunos57-select.m4
new file mode 100644
index 0000000..d912dcc
--- /dev/null
+++ b/m4/sunos57-select.m4
@@ -0,0 +1,55 @@
+dnl From Mark D Baushke & Derek Price.
+dnl
+dnl See if select() on a /dev/null fd hangs when timeout is NULL.
+dnl Also check to see that /dev/null is in the readfds set returned.
+dnl
+dnl Observed on Solaris 7:
+dnl If /dev/null is in the readfds set, it will never be marked as
+dnl ready by the OS. In the case of a /dev/null fd being the only fd
+dnl in the select set and timeout == NULL, the select will hang.
+dnl
+dnl If the test fails, then arrange to use select only via a wrapper
+dnl function that works around the problem.
+
+AC_DEFUN([ccvs_FUNC_SELECT],
+[
+ AC_CHECK_HEADERS([fcntl.h])
+ AC_CACHE_CHECK([whether select hangs on /dev/null fd when timeout is NULL],
+ ccvs_cv_func_select_hang,
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/select.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#include <errno.h>]], [[
+ int numfds;
+ fd_set readfds;
+ struct timeval timeout;
+ int fd = open ("/dev/null", O_RDONLY);
+
+ FD_ZERO (&readfds);
+ FD_SET (fd, &readfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1;
+
+ while ((numfds = select (fd + 1, &readfds, NULL, NULL, &timeout)) < 0
+ && errno == EINTR);
+ return (numfds <= 0);
+ ]])],
+ ccvs_cv_func_select_hang=no,
+ ccvs_cv_func_select_hang=yes,
+ dnl When crosscompiling, assume it is broken.
+ ccvs_cv_func_select_hang=yes)
+ ])
+ if test $ccvs_cv_func_select_hang = yes; then
+ ccvs_PREREQ_SELECT
+
+ AC_LIBOBJ(sunos57-select)
+ AC_DEFINE(select, rpl_select,
+ [Define to rpl_select if the replacement function should be used.])
+ fi
+])
+
+AC_DEFUN([ccvs_PREREQ_SELECT], [
+ AC_CHECK_HEADERS(fcntl.h unistd.h)])
diff --git a/m4/time_r.m4 b/m4/time_r.m4
new file mode 100644
index 0000000..42ba66c
--- /dev/null
+++ b/m4/time_r.m4
@@ -0,0 +1,38 @@
+dnl Reentrant time functions like localtime_r.
+
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Written by Paul Eggert.
+
+AC_DEFUN([gl_TIME_R],
+[
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ AC_REQUIRE([gl_C_RESTRICT])
+
+ AC_CACHE_CHECK([whether localtime_r is compatible with its POSIX signature],
+ [gl_cv_time_r_posix],
+ [AC_TRY_COMPILE(
+ [#include <time.h>],
+ [/* We don't need to append 'restrict's to the argument types,
+ even though the POSIX signature has the 'restrict's,
+ since C99 says they can't affect type compatibility. */
+ struct tm * (*ptr) (time_t const *, struct tm *) = localtime_r;],
+ [gl_cv_time_r_posix=yes],
+ [gl_cv_time_r_posix=no])])
+ if test $gl_cv_time_r_posix = yes; then
+ AC_DEFINE([HAVE_TIME_R_POSIX], 1,
+ [Define to 1 if localtime_r, etc. have the type signatures that
+ POSIX requires.])
+ else
+ AC_LIBOBJ([time_r])
+ gl_PREREQ_TIME_R
+ fi
+])
+
+# Prerequisites of lib/time_r.c.
+AC_DEFUN([gl_PREREQ_TIME_R], [
+ :
+])
diff --git a/m4/timespec.m4 b/m4/timespec.m4
new file mode 100644
index 0000000..fddf4b6
--- /dev/null
+++ b/m4/timespec.m4
@@ -0,0 +1,59 @@
+#serial 11
+
+# Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering
+
+AC_DEFUN([gl_TIMESPEC],
+[
+ AC_LIBSOURCES([timespec.h])
+
+ dnl Prerequisites of lib/timespec.h.
+ AC_REQUIRE([AC_C_INLINE])
+ AC_REQUIRE([AC_HEADER_TIME])
+ AC_CHECK_HEADERS_ONCE(sys/time.h)
+ gl_CHECK_TYPE_STRUCT_TIMESPEC
+
+ dnl Persuade glibc <time.h> to declare nanosleep().
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ AC_CHECK_DECLS(nanosleep, , , [#include <time.h>])
+])
+
+dnl Define HAVE_STRUCT_TIMESPEC if `struct timespec' is declared
+dnl in time.h or sys/time.h.
+
+AC_DEFUN([gl_CHECK_TYPE_STRUCT_TIMESPEC],
+[
+ dnl Persuade pedantic Solaris to declare struct timespec.
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+ AC_REQUIRE([AC_HEADER_TIME])
+ AC_CHECK_HEADERS_ONCE(sys/time.h)
+ AC_CACHE_CHECK([for struct timespec], fu_cv_sys_struct_timespec,
+ [AC_TRY_COMPILE(
+ [
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+ ],
+ [static struct timespec x; x.tv_sec = x.tv_nsec;],
+ fu_cv_sys_struct_timespec=yes,
+ fu_cv_sys_struct_timespec=no)
+ ])
+
+ if test $fu_cv_sys_struct_timespec = yes; then
+ AC_DEFINE(HAVE_STRUCT_TIMESPEC, 1,
+ [Define if struct timespec is declared in <time.h>. ])
+ fi
+])
diff --git a/m4/tm_gmtoff.m4 b/m4/tm_gmtoff.m4
new file mode 100644
index 0000000..cb0b3c8
--- /dev/null
+++ b/m4/tm_gmtoff.m4
@@ -0,0 +1,14 @@
+# tm_gmtoff.m4 serial 2
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_TM_GMTOFF],
+[
+ AC_CHECK_MEMBER([struct tm.tm_gmtoff],
+ [AC_DEFINE(HAVE_TM_GMTOFF, 1,
+ [Define if struct tm has the tm_gmtoff member.])],
+ ,
+ [#include <time.h>])
+])
diff --git a/m4/tzset.m4 b/m4/tzset.m4
new file mode 100644
index 0000000..134080c
--- /dev/null
+++ b/m4/tzset.m4
@@ -0,0 +1,68 @@
+#serial 2
+
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# See if we have a working tzset function.
+# If so, arrange to compile the wrapper function.
+# For at least Solaris 2.5.1 and 2.6, this is necessary
+# because tzset can clobber the contents of the buffer
+# used by localtime.
+
+# Written by Paul Eggert and Jim Meyering.
+
+AC_DEFUN([gl_FUNC_TZSET_CLOBBER],
+[
+ AC_REQUIRE([AC_HEADER_TIME])
+ AC_CACHE_CHECK([whether tzset clobbers localtime buffer],
+ gl_cv_func_tzset_clobber,
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#include <stdlib.h>
+
+int
+main ()
+{
+ time_t t1 = 853958121;
+ struct tm *p, s;
+ putenv ("TZ=GMT0");
+ p = localtime (&t1);
+ s = *p;
+ putenv ("TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00");
+ tzset ();
+ exit (p->tm_year != s.tm_year
+ || p->tm_mon != s.tm_mon
+ || p->tm_mday != s.tm_mday
+ || p->tm_hour != s.tm_hour
+ || p->tm_min != s.tm_min
+ || p->tm_sec != s.tm_sec);
+}
+ ]])],
+ [gl_cv_func_tzset_clobber=no],
+ [gl_cv_func_tzset_clobber=yes],
+ [gl_cv_func_tzset_clobber=yes])])
+
+ AC_DEFINE(HAVE_RUN_TZSET_TEST, 1,
+ [Define to 1 if you have run the test for working tzset.])
+
+ if test $gl_cv_func_tzset_clobber = yes; then
+ gl_GETTIMEOFDAY_REPLACE_LOCALTIME
+
+ AC_DEFINE(tzset, rpl_tzset,
+ [Define to rpl_tzset if the wrapper function should be used.])
+ AC_DEFINE(TZSET_CLOBBERS_LOCALTIME_BUFFER, 1,
+ [Define if tzset clobbers localtime's static buffer.])
+ fi
+])
diff --git a/m4/uint32_t.m4 b/m4/uint32_t.m4
new file mode 100644
index 0000000..1fb5e66
--- /dev/null
+++ b/m4/uint32_t.m4
@@ -0,0 +1,53 @@
+# uint32_t.m4 serial 4
+
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Paul Eggert.
+
+AC_DEFUN([gl_AC_TYPE_UINT32_T],
+[
+ AC_CACHE_CHECK([for uint32_t], gl_cv_c_uint32_t,
+ [gl_cv_c_uint32_t=no
+ for ac_type in "uint32_t" "unsigned int" \
+ "unsigned long int" "unsigned short int"; do
+ AC_COMPILE_IFELSE(
+ [AC_LANG_BOOL_COMPILE_TRY(
+ [AC_INCLUDES_DEFAULT],
+ [[($ac_type) -1 == 4294967295U]])],
+ [gl_cv_c_uint32_t=$ac_type])
+ test "$gl_cv_c_uint32_t" != no && break
+ done])
+ case "$gl_cv_c_uint32_t" in
+ no|uint32_t) ;;
+ *)
+ AC_DEFINE(_UINT32_T, 1,
+ [Define for Solaris 2.5.1 so uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was
+ allowed, the #define below would cause a syntax error.])
+ AC_DEFINE_UNQUOTED(uint32_t, $gl_cv_c_uint32_t,
+ [Define to the type of a unsigned integer type of width exactly 32 bits
+ if such a type exists and the standard includes do not define it.])
+ ;;
+ esac
+
+ AC_CACHE_CHECK([for UINT32_MAX], gl_cv_c_uint32_max,
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_BOOL_COMPILE_TRY(
+ [AC_INCLUDES_DEFAULT],
+ [[UINT32_MAX == 4294967295U]])],
+ [gl_cv_c_uint32_max=yes],
+ [gl_cv_c_uint32_max=no])])
+ case $gl_cv_c_uint32_max,$gl_cv_c_uint32_t in
+ yes,*) ;;
+ *,no) ;;
+ *)
+ AC_DEFINE(UINT32_MAX, 4294967295U,
+ [Define to its maximum value if an unsigned integer type of width
+ exactly 32 bits exists and the standard includes do not define
+ UINT32_MAX.])
+ ;;
+ esac
+])
diff --git a/m4/uintmax_t.m4 b/m4/uintmax_t.m4
new file mode 100644
index 0000000..bf83ed7
--- /dev/null
+++ b/m4/uintmax_t.m4
@@ -0,0 +1,30 @@
+# uintmax_t.m4 serial 9
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+AC_PREREQ(2.13)
+
+# Define uintmax_t to 'unsigned long' or 'unsigned long long'
+# if it is not already defined in <stdint.h> or <inttypes.h>.
+
+AC_DEFUN([gl_AC_TYPE_UINTMAX_T],
+[
+ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+ AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+ if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+ AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG])
+ test $ac_cv_type_unsigned_long_long = yes \
+ && ac_type='unsigned long long' \
+ || ac_type='unsigned long'
+ AC_DEFINE_UNQUOTED(uintmax_t, $ac_type,
+ [Define to unsigned long or unsigned long long
+ if <stdint.h> and <inttypes.h> don't define.])
+ else
+ AC_DEFINE(HAVE_UINTMAX_T, 1,
+ [Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>.])
+ fi
+])
diff --git a/m4/ulonglong.m4 b/m4/ulonglong.m4
new file mode 100644
index 0000000..dee10cc
--- /dev/null
+++ b/m4/ulonglong.m4
@@ -0,0 +1,23 @@
+# ulonglong.m4 serial 4
+dnl Copyright (C) 1999-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_UNSIGNED_LONG_LONG if 'unsigned long long' works.
+
+AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG],
+[
+ AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long,
+ [AC_TRY_LINK([unsigned long long ull = 1ULL; int i = 63;],
+ [unsigned long long ullmax = (unsigned long long) -1;
+ return ull << i | ull >> i | ullmax / ull | ullmax % ull;],
+ ac_cv_type_unsigned_long_long=yes,
+ ac_cv_type_unsigned_long_long=no)])
+ if test $ac_cv_type_unsigned_long_long = yes; then
+ AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1,
+ [Define if you have the 'unsigned long long' type.])
+ fi
+])
diff --git a/m4/unistd-safer.m4 b/m4/unistd-safer.m4
new file mode 100644
index 0000000..c819c92
--- /dev/null
+++ b/m4/unistd-safer.m4
@@ -0,0 +1,26 @@
+#serial 6
+dnl Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_UNISTD_SAFER],
+[
+ AC_LIBSOURCES([dup-safer.c, fd-safer.c, pipe-safer.c, unistd-safer.h, unistd--.h])
+ AC_LIBOBJ([dup-safer])
+ AC_LIBOBJ([fd-safer])
+ AC_LIBOBJ([pipe-safer])
+
+ gl_PREREQ_DUP_SAFER
+ gl_PREREQ_FD_SAFER
+])
+
+# Prerequisites of lib/dup-safer.c.
+AC_DEFUN([gl_PREREQ_DUP_SAFER], [
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+])
+
+# Prerequisites of lib/fd-safer.c.
+AC_DEFUN([gl_PREREQ_FD_SAFER], [
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+])
diff --git a/m4/unlocked-io.m4 b/m4/unlocked-io.m4
new file mode 100644
index 0000000..6cbacb0
--- /dev/null
+++ b/m4/unlocked-io.m4
@@ -0,0 +1,36 @@
+# unlocked-io.m4 serial 12
+
+# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering.
+dnl
+dnl See if the glibc *_unlocked I/O macros or functions are available.
+dnl Use only those *_unlocked macros or functions that are declared
+dnl (because some of them were declared in Solaris 2.5.1 but were removed
+dnl in Solaris 2.6, whereas we want binaries built on Solaris 2.5.1 to run
+dnl on Solaris 2.6).
+
+AC_DEFUN([gl_FUNC_GLIBC_UNLOCKED_IO],
+[
+ AC_LIBSOURCES([unlocked-io.h])
+
+ AC_DEFINE([USE_UNLOCKED_IO], 1,
+ [Define to 1 if you want getc etc. to use unlocked I/O if available.
+ Unlocked I/O can improve performance in unithreaded apps,
+ but it is not safe for multithreaded apps.])
+
+ dnl Persuade glibc and Solaris <stdio.h> to declare
+ dnl fgets_unlocked(), fputs_unlocked() etc.
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+ AC_CHECK_DECLS_ONCE(
+ [clearerr_unlocked feof_unlocked ferror_unlocked
+ fflush_unlocked fgets_unlocked fputc_unlocked fputs_unlocked
+ fread_unlocked fwrite_unlocked getc_unlocked
+ getchar_unlocked putc_unlocked putchar_unlocked])
+])
diff --git a/m4/vasnprintf.m4 b/m4/vasnprintf.m4
new file mode 100644
index 0000000..7ff3430
--- /dev/null
+++ b/m4/vasnprintf.m4
@@ -0,0 +1,58 @@
+# vasnprintf.m4 serial 5
+dnl Copyright (C) 2002-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_VASNPRINTF],
+[
+ AC_REQUIRE([gl_EOVERFLOW])
+ AC_REPLACE_FUNCS(vasnprintf)
+ if test $ac_cv_func_vasnprintf = no; then
+ AC_LIBOBJ(printf-args)
+ AC_LIBOBJ(printf-parse)
+ AC_LIBOBJ(asnprintf)
+ gl_PREREQ_PRINTF_ARGS
+ gl_PREREQ_PRINTF_PARSE
+ gl_PREREQ_VASNPRINTF
+ gl_PREREQ_ASNPRINTF
+ fi
+])
+
+# Prequisites of lib/printf-args.h, lib/printf-args.c.
+AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
+[
+ AC_REQUIRE([bh_C_SIGNED])
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+ AC_REQUIRE([gt_TYPE_WCHAR_T])
+ AC_REQUIRE([gt_TYPE_WINT_T])
+])
+
+# Prequisites of lib/printf-parse.h, lib/printf-parse.c.
+AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
+[
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+ AC_REQUIRE([gt_TYPE_WCHAR_T])
+ AC_REQUIRE([gt_TYPE_WINT_T])
+ AC_REQUIRE([AC_TYPE_SIZE_T])
+ AC_CHECK_TYPES(ptrdiff_t)
+ AC_REQUIRE([gt_AC_TYPE_INTMAX_T])
+])
+
+# Prerequisites of lib/vasnprintf.c.
+AC_DEFUN([gl_PREREQ_VASNPRINTF],
+[
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+ AC_REQUIRE([gt_TYPE_WCHAR_T])
+ AC_REQUIRE([gt_TYPE_WINT_T])
+ AC_CHECK_FUNCS(snprintf wcslen)
+])
+
+# Prerequisites of lib/asnprintf.c.
+AC_DEFUN([gl_PREREQ_ASNPRINTF],
+[
+])
diff --git a/m4/vasprintf.m4 b/m4/vasprintf.m4
new file mode 100644
index 0000000..385e92e
--- /dev/null
+++ b/m4/vasprintf.m4
@@ -0,0 +1,25 @@
+# vasprintf.m4 serial 1
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_VASPRINTF],
+[
+ AC_REPLACE_FUNCS(vasprintf)
+ if test $ac_cv_func_vasprintf = no; then
+ AC_LIBOBJ(asprintf)
+ gl_PREREQ_VASPRINTF
+ gl_PREREQ_ASPRINTF
+ fi
+])
+
+# Prerequisites of lib/vasprintf.c.
+AC_DEFUN([gl_PREREQ_VASPRINTF],
+[
+])
+
+# Prerequisites of lib/asprintf.c.
+AC_DEFUN([gl_PREREQ_ASPRINTF],
+[
+])
diff --git a/m4/wchar_t.m4 b/m4/wchar_t.m4
new file mode 100644
index 0000000..cde2129
--- /dev/null
+++ b/m4/wchar_t.m4
@@ -0,0 +1,20 @@
+# wchar_t.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <stddef.h> has the 'wchar_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WCHAR_T],
+[
+ AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t,
+ [AC_TRY_COMPILE([#include <stddef.h>
+ wchar_t foo = (wchar_t)'\0';], ,
+ gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)])
+ if test $gt_cv_c_wchar_t = yes; then
+ AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.])
+ fi
+])
diff --git a/m4/wint_t.m4 b/m4/wint_t.m4
new file mode 100644
index 0000000..b8fff9c
--- /dev/null
+++ b/m4/wint_t.m4
@@ -0,0 +1,20 @@
+# wint_t.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <wchar.h> has the 'wint_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WINT_T],
+[
+ AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t,
+ [AC_TRY_COMPILE([#include <wchar.h>
+ wint_t foo = (wchar_t)'\0';], ,
+ gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)])
+ if test $gt_cv_c_wint_t = yes; then
+ AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.])
+ fi
+])
diff --git a/m4/xalloc.m4 b/m4/xalloc.m4
new file mode 100644
index 0000000..c0847dd
--- /dev/null
+++ b/m4/xalloc.m4
@@ -0,0 +1,25 @@
+# xalloc.m4 serial 12
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XALLOC],
+[
+ AC_LIBSOURCES([xmalloc.c, xalloc.h])
+ AC_LIBOBJ([xmalloc])
+
+ gl_PREREQ_XALLOC
+ gl_PREREQ_XMALLOC
+])
+
+# Prerequisites of lib/xalloc.h.
+AC_DEFUN([gl_PREREQ_XALLOC], [
+ :
+])
+
+# Prerequisites of lib/xmalloc.c.
+AC_DEFUN([gl_PREREQ_XMALLOC], [
+ AC_REQUIRE([AC_C_INLINE])
+ :
+])
diff --git a/m4/xgetcwd.m4 b/m4/xgetcwd.m4
new file mode 100644
index 0000000..7746d45
--- /dev/null
+++ b/m4/xgetcwd.m4
@@ -0,0 +1,13 @@
+# xgetcwd.m4 serial 4
+dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XGETCWD],
+[
+ AC_LIBSOURCES([xgetcwd.c, xgetcwd.h])
+ AC_LIBOBJ([xgetcwd])
+
+ AC_REQUIRE([gl_FUNC_GETCWD])
+])
diff --git a/m4/xreadlink.m4 b/m4/xreadlink.m4
new file mode 100644
index 0000000..f4b25bc
--- /dev/null
+++ b/m4/xreadlink.m4
@@ -0,0 +1,12 @@
+# xreadlink.m4 serial 5
+dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XREADLINK],
+[
+ dnl Prerequisites of lib/xreadlink.c.
+ AC_REQUIRE([gt_TYPE_SSIZE_T])
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+])
diff --git a/m4/xsize.m4 b/m4/xsize.m4
new file mode 100644
index 0000000..85bb721
--- /dev/null
+++ b/m4/xsize.m4
@@ -0,0 +1,13 @@
+# xsize.m4 serial 3
+dnl Copyright (C) 2003-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XSIZE],
+[
+ dnl Prerequisites of lib/xsize.h.
+ AC_REQUIRE([gl_SIZE_MAX])
+ AC_REQUIRE([AC_C_INLINE])
+ AC_CHECK_HEADERS(stdint.h)
+])
diff --git a/m4/yesno.m4 b/m4/yesno.m4
new file mode 100644
index 0000000..6e8078d
--- /dev/null
+++ b/m4/yesno.m4
@@ -0,0 +1,14 @@
+# yesno.m4 serial 4
+dnl Copyright (C) 2002-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_YESNO],
+[
+ AC_LIBSOURCES([yesno.c, yesno.h])
+ AC_LIBOBJ([yesno])
+
+ dnl No prerequisites of lib/yesno.c.
+ :
+])
diff --git a/maint-aux/Makefile.am b/maint-aux/Makefile.am
new file mode 100644
index 0000000..9377b05
--- /dev/null
+++ b/maint-aux/Makefile.am
@@ -0,0 +1,26 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for the maint-aux directory of the GNU Concurrent Versions System.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+## Subdirectories to run make in for the primary targets.
+EXTRA_DIST = \
+ gnulib-filelist.txt \
+ gnulib-modules \
+ gnulib-update \
+ srclist.txt
+
+# for backwards compatibility with the old makefiles
+.PHONY: realclean
+realclean: maintainer-clean
diff --git a/maint-aux/Makefile.in b/maint-aux/Makefile.in
new file mode 100644
index 0000000..52b0a96
--- /dev/null
+++ b/maint-aux/Makefile.in
@@ -0,0 +1,424 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for the maint-aux directory of the GNU Concurrent Versions System.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = maint-aux
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+EXTRA_DIST = \
+ gnulib-filelist.txt \
+ gnulib-modules \
+ gnulib-update \
+ srclist.txt
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu maint-aux/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu maint-aux/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-info-am
+
+
+# for backwards compatibility with the old makefiles
+.PHONY: realclean
+realclean: maintainer-clean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/maint-aux/gnulib-filelist.txt b/maint-aux/gnulib-filelist.txt
new file mode 100644
index 0000000..511ea23
--- /dev/null
+++ b/maint-aux/gnulib-filelist.txt
@@ -0,0 +1,214 @@
+build-aux/config.rpath
+doc/getdate.texi
+lib/allocsa.c
+lib/allocsa.h
+lib/allocsa.valgrind
+lib/asnprintf.c
+lib/asprintf.c
+lib/atexit.c
+lib/basename.c
+lib/canon-host.c
+lib/canon-host.h
+lib/canonicalize.c
+lib/canonicalize.h
+lib/closeout.c
+lib/closeout.h
+lib/dirname.c
+lib/dirname.h
+lib/dup2.c
+lib/error.c
+lib/error.h
+lib/exitfail.c
+lib/exitfail.h
+lib/exit.h
+lib/fnmatch.c
+lib/fnmatch_.h
+lib/fnmatch_loop.c
+lib/ftruncate.c
+lib/getdate.h
+lib/getdate.y
+lib/gethostname.c
+lib/getline.c
+lib/getline.h
+lib/getlogin_r.c
+lib/getlogin_r.h
+lib/getndelim2.c
+lib/getndelim2.h
+lib/getnline.c
+lib/getnline.h
+lib/getopt1.c
+lib/getopt.c
+lib/getopt_.h
+lib/getopt_int.h
+lib/getpagesize.h
+lib/getpass.c
+lib/getpass.h
+lib/gettime.c
+lib/gettimeofday.c
+lib/glob.c
+lib/glob_.h
+lib/glob-libc.h
+lib/lstat.c
+lib/lstat.h
+lib/malloc.c
+lib/md5.c
+lib/md5.h
+lib/memmove.c
+lib/minmax.h
+lib/mkdir.c
+lib/mkstemp.c
+lib/mktime.c
+lib/nanosleep.c
+lib/pagealign_alloc.c
+lib/pagealign_alloc.h
+lib/pathmax.h
+lib/printf-args.c
+lib/printf-args.h
+lib/printf-parse.c
+lib/printf-parse.h
+lib/quotearg.c
+lib/quotearg.h
+lib/readlink.c
+lib/realloc.c
+lib/regcomp.c
+lib/regex.c
+lib/regexec.c
+lib/regex.h
+lib/regex_internal.c
+lib/regex_internal.h
+lib/rename.c
+lib/save-cwd.c
+lib/save-cwd.h
+lib/setenv.c
+lib/setenv.h
+lib/stat-macros.h
+lib/stdbool_.h
+lib/stdint_.h
+lib/strcasecmp.c
+lib/strcase.h
+lib/strdup.c
+lib/strdup.h
+lib/strerror.c
+lib/strftime.c
+lib/strftime.h
+lib/stripslash.c
+lib/strncasecmp.c
+lib/strstr.c
+lib/strstr.h
+lib/strtoul.c
+lib/tempname.c
+lib/time_r.c
+lib/time_r.h
+lib/timespec.h
+lib/unlocked-io.h
+lib/unsetenv.c
+lib/vasnprintf.c
+lib/vasnprintf.h
+lib/vasprintf.c
+lib/vasprintf.h
+lib/xalloc-die.c
+lib/xgethostname.c
+lib/xgethostname.h
+lib/xreadlink.c
+lib/xreadlink.h
+lib/xsize.h
+lib/yesno.c
+lib/yesno.h
+m4/allocsa.m4
+m4/atexit.m4
+m4/bison.m4
+m4/canon-host.m4
+m4/canonicalize.m4
+m4/clock_time.m4
+m4/closeout.m4
+m4/codeset.m4
+m4/dirname.m4
+m4/dos.m4
+m4/d-type.m4
+m4/dup2.m4
+m4/eealloc.m4
+m4/eoverflow.m4
+m4/error.m4
+m4/exitfail.m4
+m4/extensions.m4
+m4/fnmatch.m4
+m4/ftruncate.m4
+m4/getdate.m4
+m4/gethostname.m4
+m4/getline.m4
+m4/getlogin_r.m4
+m4/getndelim2.m4
+m4/getnline.m4
+m4/getopt.m4
+m4/getpagesize.m4
+m4/getpass.m4
+m4/gettext.m4
+m4/gettime.m4
+m4/gettimeofday.m4
+m4/glibc21.m4
+m4/glibc2.m4
+m4/glob.m4
+m4/iconv.m4
+m4/intdiv0.m4
+m4/intmax.m4
+m4/intmax_t.m4
+m4/inttypes_h.m4
+m4/inttypes.m4
+m4/inttypes-pri.m4
+m4/isc-posix.m4
+m4/lcmessage.m4
+m4/longdouble.m4
+m4/longlong.m4
+m4/lstat.m4
+m4/mbrtowc.m4
+m4/mbstate_t.m4
+m4/md5.m4
+m4/memmove.m4
+m4/minmax.m4
+m4/mkdir-slash.m4
+m4/mkstemp.m4
+m4/mktime.m4
+m4/mmap-anon.m4
+m4/nanosleep.m4
+m4/nls.m4
+m4/onceonly_2_57.m4
+m4/pagealign_alloc.m4
+m4/pathmax.m4
+m4/po.m4
+m4/printf-posix.m4
+m4/progtest.m4
+m4/quotearg.m4
+m4/readlink.m4
+m4/regex.m4
+m4/rename.m4
+m4/restrict.m4
+m4/save-cwd.m4
+m4/setenv.m4
+m4/signed.m4
+m4/size_max.m4
+m4/stat-macros.m4
+m4/stdbool.m4
+m4/stdint_h.m4
+m4/stdint.m4
+m4/strcase.m4
+m4/strdup.m4
+m4/strerror.m4
+m4/strerror_r.m4
+m4/strftime.m4
+m4/strstr.m4
+m4/strtoul.m4
+m4/time_r.m4
+m4/timespec.m4
+m4/tm_gmtoff.m4
+m4/tzset.m4
+m4/uint32_t.m4
+m4/uintmax_t.m4
+m4/ulonglong.m4
+m4/unlocked-io.m4
+m4/vasnprintf.m4
+m4/vasprintf.m4
+m4/wchar_t.m4
+m4/wint_t.m4
+m4/xreadlink.m4
+m4/xsize.m4
+m4/yesno.m4
diff --git a/maint-aux/gnulib-modules b/maint-aux/gnulib-modules
new file mode 100644
index 0000000..37402f6
--- /dev/null
+++ b/maint-aux/gnulib-modules
@@ -0,0 +1,66 @@
+gettext
+vasnprintf
+regex
+atexit
+save-cwd
+dirname
+error
+exit
+exitfail
+extensions
+fnmatch-posix
+fnmatch
+mkstemp
+getopt
+stdbool
+getline
+getnline
+getndelim2
+gethostname
+strcase
+getpass-gnu
+gettimeofday
+timespec
+gettime
+unlocked-io
+tzset
+restrict
+time_r
+mktime
+minmax
+memmove
+nanosleep
+lstat
+strerror
+vasprintf
+malloc
+realloc
+strftime
+xsize
+getpagesize
+md5
+stdint
+yesno
+allocsa
+setenv
+getdate
+readlink
+xreadlink
+xgethostname
+mkdir
+rename
+dup2
+strstr
+ftruncate
+strtoul
+pathmax
+xalloc-die
+pagealign_alloc
+closeout
+strdup
+canonicalize
+getlogin_r
+stat-macros
+quotearg
+canon-host
+glob
diff --git a/maint-aux/gnulib-update b/maint-aux/gnulib-update
new file mode 100755
index 0000000..d12d419
--- /dev/null
+++ b/maint-aux/gnulib-update
@@ -0,0 +1,112 @@
+#! /bin/sh
+# Update the local files from GNULIB. Currently assumes that the current
+# GNULIB sources are in a directory parallel with this one.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+if test -f maint-aux/gnulib-modules; then :; else
+ >&2 echo \
+"This script expects to be run from the top level of the CVS source tree."
+ exit 2
+fi
+
+if test -f maint-aux/gnulib-modules; then :; else
+ >&2 echo \
+"Failed to find the modules list (\`maint-aux/gnulib-modules')."
+ exit 2
+fi
+
+# Where to find the GNULIB sources.
+: ${GNULIB="../gnulib"}
+GNULIB_TOOL=$GNULIB/gnulib-tool
+
+# Which modules to update.
+MODULES=`cat maint-aux/gnulib-modules`
+
+# Are the GNULIB sources really where we expect them?
+if test -r $GNULIB && test -d $GNULIB \
+ && test -r $GNULIB_TOOL && test -f $GNULIB_TOOL; then :; else
+ echo GNULIB sources not found. >&2
+ exit 1
+fi
+
+trap \
+'status=$?
+# Restore lib/Makefile.am.
+if test -f lib/Makefile.am.save; then
+ mv lib/Makefile.am.save lib/Makefile.am
+fi
+# Restore m4/error.m4.
+if test -f m4/error.m4.save; then
+ mv m4/error.m4.save m4/error.m4
+fi
+exit $status' EXIT
+
+# Prevent lib/Makefile.am from being overwritten.
+mv lib/Makefile.am lib/Makefile.am.save
+# Prevent m4/error.m4 from being overwritten unless necessary.
+mv m4/error.m4 m4/error.m4.save
+
+# Run the update.
+if $GNULIB_TOOL --import $MODULES >/dev/null; then :; else
+ exit $?
+fi
+
+# Correct this file for our purposes, but try to avoid munging timestamps
+# unless necessary.
+sed '/AC_FUNC_ERROR_AT_LINE/d' <m4/error.m4 >tmp
+if cmp tmp m4/error.m4.save >/dev/null 2>&1; then
+ mv m4/error.m4.save m4/error.m4
+ rm tmp
+else
+ mv tmp m4/error.m4
+ rm m4/error.m4.save
+fi
+
+# Extract the names of the files we imported.
+$GNULIB_TOOL --extract-filelist $MODULES |sort |uniq |sed '/^$/d' \
+ >maint-aux/gnulib-filelist.new
+
+# Warn the user if the filelist has changed.
+if cmp maint-aux/gnulib-filelist.txt maint-aux/gnulib-filelist.new >/dev/null
+then
+ # Avoid munging timestamps when nothing's changed.
+ rm maint-aux/gnulib-filelist.new
+else
+ cat >&2 <<\EOF
+********************************************************************
+The file list has changed. You may need to add or remove files from
+CVS. Use `cvs diff maint-aux/gnulib-filelist.txt' to view changes.
+********************************************************************
+EOF
+ # Save the file list for next time.
+ mv maint-aux/gnulib-filelist.new maint-aux/gnulib-filelist.txt
+fi
+
+
+# Warn the user if changes have been made to the Makefile.am.
+if cmp lib/Makefile.am lib/Makefile.gnulib >/dev/null; then
+ # Avoid munging timestamps when nothing's changed.
+ rm lib/Makefile.am
+else
+ cat >&2 <<\EOF
+********************************************************************
+Makefile.am needs updating. Use `cvs diff lib/Makefile.gnulib' to
+view changes.
+********************************************************************
+EOF
+ # Save the generated lib/Makefile.am for next time.
+ mv lib/Makefile.am lib/Makefile.gnulib
+fi
diff --git a/maint-aux/srclist.txt b/maint-aux/srclist.txt
new file mode 100644
index 0000000..9d24771
--- /dev/null
+++ b/maint-aux/srclist.txt
@@ -0,0 +1,69 @@
+# Files for which we are not the source.
+
+# In the "Local Modifications" fields below, "I" means the source files were
+# imported using the CVS import command and "NI" means CVS import was not used.
+
+GNU ZLib
+Stream compression and decompression libraries.
+License: zlib/README (Public Domain, but do not misrepresent source.)
+Bug Report Email: bug-zlib@gnu.org
+GNU Web Page: http://www.gnu.org/directory/GNU/zlib.html
+Last Web Location: http://www.zlib.net
+Previous Web Location: http://www.gzip.org/zlib
+
+Imported files CVS Local
+ Directory Modifications
+----------------------------------------------- --------------- ---------------
+$GNUZLIB/* zlib build scripts
+ only I
+
+
+
+GNU Diffutils
+License: GPL
+Bug Report Email: bug-gnu-utils@gnu.org
+GNU Web Page: http://www.gnu.org/directory/GNU/diffutils.html
+Project Web Page: http://savannah.gnu.org/projects/diffutils/
+
+Imported files CVS Local
+ Directory Modifications
+----------------------------------------------- --------------- ---------------
+$GNUDIFF/* diff yes NI
+
+
+
+GNULib
+Portable implementations of useful functions found on some platforms but not
+others. We update these files directly from the GNULIB CVS repository.
+Only files which cannot be autoupdated by running the gnulib-update script in
+this directory are tracked here.
+License: GPL
+Bug Report Email: bug-gnulib@gnu.org
+Project Web Page: http://savannah.gnu.org/projects/gnulib
+CVS Repository (via SSH): :ext:anoncvs@savannah.gnu.org/cvsroot/gnulib
+
+Imported files CVS Local
+ Directory Modifications
+----------------------------------------------- --------------- ---------------
+# The following error module is only half-imported to support getdate.y's test
+# hooks when xmalloc, which calls error(), is needed. We cannot completely
+# import the error module since it would conflict with CVS's error() function,
+# which is needed to send errors across the connection to the client.
+# $GNULIB/modules/error
+$GNULIB/lib/error.c lib no NI
+$GNULIB/lib/error.h lib no NI
+$GNULIB/m4/strerror_r.m4 lib no NI
+
+
+
+Windows stat() substitute which works around bass ackwards file time problems
+on Windows.
+License: GPL
+Bug Report Email: ???
+Project Web Page: http://www.codeproject.com/datetime/dstbugs.asp
+
+Imported files CVS Local
+ Directory Modifications
+----------------------------------------------- --------------- ---------------
+JmgStat.c windows-NT yes NI
+JmgStat.h windows-NT yes NI
diff --git a/man/.cvsignore b/man/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/man/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/man/ChangeLog b/man/ChangeLog
new file mode 100644
index 0000000..d4ef485
--- /dev/null
+++ b/man/ChangeLog
@@ -0,0 +1,423 @@
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notices.
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ First pass at closing issue #3 from cvshome.org.
+ * Makefile.am (man_MANS): Remove cvs.1.
+ * cvs.1: Removed.
+ * Makefile.in: Regenerated.
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ Close issue #162.
+ * cvs.1: Remove references to the removed global -l option.
+ (Original patch from Ville Skyttä <scop@cvshome.org>.)
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ Close issue #161.
+ * cvs.1, cvs.5: A couple of spelling fixes.
+ (Patch from Ville Skyttä <scop@cvshome.org>.)
+
+2004-01-30 Derek Price <derek@ximbiot.com>
+
+ Close issue #146.
+ * cvs.1: Reference `cvs --help diff' rather than the rcsdiff man page.
+ Use consistent spelling of `initialization'.
+ (Patch from Ville Skyttä <scop@cvshome.org>.)
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.1 (CVS_RSH): Note that the default "rsh" value may be set by
+ the --with-rsh configure option.
+
+ * Makefile.in: Regenerated.
+
+ * cvs.1 (Environment Variables): Document new CVS_PID variable.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.1 (program): Document new `-R' global option for read-only
+ file-system repository mode.
+ (CVSREADONLYFS): Document new environment variable.
+
+2003-03-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.1 (CVS_LOCAL_BRANCH_NUM): Document new environment variable.
+
+2003-02-26 Larry Jones <lawrence.jones@eds.com>
+
+ * cvs.1: Note using "cvs" in .cvsrc for global options.
+ (Patch from "Mark D. Baushke" <mdb@cvshome.org>).
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * cvs.1(cvs tag): Mention -c option.
+ (Correction from Michael Richardson <mcr@sandelman.ottawa.on.ca>.)
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * cvs.1(cvs commit): It's '-F' now, not '-f'.
+ (Correction from Norikatsu Shigemura <nork@cityfujisawa.ne.jp>.)
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * cvs.1: Claim to be out of date and direct users to the Cederqvist.
+ Replace www.cyclic.com with cvshome.org.
+ * cvs.5: Ditto.
+
+2001-11-27 Larry Jones <larry.jones@sdrc.com>
+
+ * cvsbug.8: Fixed typo.
+ (Correction from Mark D. Baushke <mdb@cvshome.org>.)
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-05-21 Derek Price <dprice@collab.net>
+
+ * cvs.1: Correct a quoting error.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>).
+
+2001-05-18 Derek Price <dprice@collab.net>
+
+ * cvs.1: Add note about 'P' file status from update.
+ (Reported by Jani Averbach <jaa@cc.jyu.fi>).
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+
+2000-09-07 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@
+ from autoconf.
+
+2000-05-03 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.1: Correct CVSEDITOR/VISUAL/EDITOR documentation.
+ Correct KJ's botched patch application.
+
+2000-01-02 John P Cavanaugh <cavanaug@sr.hp.com>
+
+ * cvs.texinfo: document new -C option to update, now that it works
+ both remotely and locally.
+ (Re-applied by Karl Fogel <kfogel@red-bean.com>.)
+
+1999-12-11 Karl Fogel <kfogel@red-bean.com>
+
+ * Revert previous change -- it doesn't work remotely yet.
+
+1999-12-10 John P Cavanaugh <cavanaug@sr.hp.com>
+
+ * cvs.1: document new -C option to update.
+ (Applied by Karl Fogel <kfogel@red-bean.com>.)
+
+1999-11-29 Larry Jones <larry.jones@sdrc.com>
+
+ * cvsbug.8: Change .TH from section 1 to section 8.
+
+1999-11-10 Jim Kingdon <http://developer.redhat.com/>
+
+ * cvs.1: Don't document -H as a command option; it has been a
+ while since that worked.
+
+1999-01-19 Vitaly V Fedrushkov <willy@snowyowl.csu.ac.ru>
+
+ * Makefile.in (INSTALL_DATA): Wrong manpage permissions fixed.
+
+1998-06-28 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.1: Update various items which were out of date. Mostly
+ these related to CVS no longer calling external RCS programs.
+
+Mon Jan 12 11:10:21 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.1: Refer to Cederqvist as Cederqvist not as cvs.texinfo.
+ Describe it in a way which hopefully makes more sense for people
+ who aren't getting the CVS source distribution itself. In "SEE
+ ALSO" section, also mention web pages. Use a period not a comma
+ at the end of the references to other manpages.
+
+ * cvs.1: Remove $Id; we decided to get rid of these some time ago.
+
+Sun Jan 11 13:46:54 1998 Peter Wemm <peter@netplex.com.au>
+
+ * cvs.1: Fix "the the" typo. From Wolfram Schneider
+ <wosch@freebsd.org> via FreeBSD sources.
+
+Wed Feb 12 14:20:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (install): Depend on installdirs.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, cvsbug.8: Remove "675" paragraph;
+ see ../ChangeLog for rationale.
+
+Sat Nov 30 14:49:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.1: Add note at beginning about how cvs.texinfo is more
+ complete than this document. Without some such indication, users
+ have no way of knowing which document to consult.
+
+Tue Oct 1 14:01:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.1: Revert all changes by Greg Woods since CVS 1.8.86. They
+ are for new features which are not appropriate at this stage of
+ the release process.
+
+Mon Sep 30 18:21:05 1996 Greg A. Woods <woods@most.weird.com>
+
+ * cvs.1: document -D, -g, DIFFBIN, and GREPBIN.
+
+Mon Sep 16 23:22:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsbug.8: Remove references to cvsbug.el (or other aspects of
+ emacs interface) and cvsbug.info (or other aspects of texinfo
+ documentation). Neither one has ever existed.
+
+Wed Jul 24 19:01:35 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.1: Document -x.
+
+Fri Sep 13 11:01:59 1996 Greg A. Woods <woods@clapton.seachange.com>
+
+ * cvs.1: add description of -k and -K for rdiff. Mention that
+ import allows '-b 1' to import to the trunk.
+
+Tue May 14 10:23:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.1: Add cvs.texinfo to the SEE ALSO section. Replace an out
+ of date list of default ignore patterns with a reference to
+ cvs.texinfo (if someone wants to undo this change that is OK with
+ me but I did it this way because it isn't clear people would
+ actually keep cvs.1 up to date).
+
+Wed Mar 13 17:06:39 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsinit.8: Removed.
+ * Makefile.in, cvs.1, cvs.5: Remove references to cvsinit.
+
+Tue Feb 13 22:30:54 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * Makefile.in: Remove reference to mkmodules.1
+
+Mon Feb 12 16:30:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.1, cvsinit.8: Remove references to mkmodules, rm, sort
+ * cvs.5: Remove references to mkmodules.
+ * mkmodules.1: Removed.
+
+Tue Jan 30 18:32:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Revise comment regarding install and installdirs.
+
+Tue Nov 14 15:47:44 1995 Greg A. Woods <woods@most.weird.com>
+
+ * cvs.5:
+ - list filenames in alpha sort order
+ - describe the cvswrappers file
+ - describe the taginfo file
+ - fix cvsinit chapter number
+ (This is by no means complete -- it's just stuff I noticed.)
+
+ * cvs.1: put the filenames in alpha sort order
+
+ * cvsinit.8: remove the .pl extension from filenames
+
+Wed Oct 18 11:07:07 1995 Vince Demarco <vdemarco@bou.shl.com>
+
+ * cvs.1 (Flag): Updated the CVSROOT/wrappers stuff. Everyone seems
+ to think this is a NEXT specific thing it isn't.
+
+Tue Oct 17 17:38:27 1995 Warren Jones <wjones@tc.fluke.com>
+
+ * cvs.1: Change \. to \&. at start of line.
+
+Tue Oct 3 13:43:33 1995 Del <del@matra.com.au>
+
+ * cvs.1: Updated man page for all the new features of 1.6
+ (including some that were missed in 1.5 and 1.4.xx). This includes:
+ - -f and -z global options.
+ - tag -F, and -r options.
+ - rtag -F options
+ - CVSROOT/taginfo and CVSROOT/wrappers files (the latter could use a touch
+ up because I don't really understand how wrappers work or why anyone would
+ use them -- I haven't ever played with a NEXT.
+ - export -k option
+ - New environment variables CVS_IGNORE_REMOTE_ROOT, CVS_RSH, CVS_SERVER, and
+ CVSWRAPPERS. I left CVS_CLIENT_LOG, CVS_CLIENT_PORT, and CVS_SERVER_SLEEP
+ undocumented because these appear to be for testing / debugging only.
+ Note that TMPDIR, HOME and PATH are used as well and strictly speaking
+ should be documented.
+ - New files ~/.cvsrc and ~/.cvswrappers
+
+Tue Aug 15 08:13:14 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (MANFILES): include $MAN8FILES too, so they get
+ tarred up in the distribution just like anything else.
+
+Mon Jul 24 19:11:15 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.1: Remove references to -q and -Q command options.
+
+Fri Jul 14 23:30:33 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (prefix): Don't forget to give this a value.
+
+Sun Jul 9 21:22:56 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ Greg Woods' change:
+
+ * cvsbug.8, cvsinit.8: new files.
+
+Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * cvs.1: document 'cvs status [-qQ]'
+ - note reference to cvsinit(8) and cvsbug(8)
+ (from previous local changes)
+
+ * Makefile.in: add support for installing in man8, and new cvsbug
+ and cvsinit pages (from previous local changes)
+
+Sat May 27 08:46:00 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (Makefile): Regenerate only Makefile in current
+ directory when Makefile.in is out of date. Depend on ../config.status.
+
+Fri Apr 28 22:51:31 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (DISTFILES): Updated.
+ (dist-dir): Renamed from dist; changed to work with DISTDIR
+ variable passed from parent.
+
+Fri Jul 15 12:58:14 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * Makefile.in (install): Do not depend upon installdirs.
+
+Sat Dec 18 01:23:13 1993 david d zuhn (zoo@monad.armadillo.com)
+
+ * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead
+
+Mon Jun 14 12:20:33 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com)
+
+ * Makefile.in (install): remove parentdir support
+
+Mon Aug 31 01:42:43 1992 david d [zoo] zuhn (zoo at cirdan.cygnus.com)
+
+ * Makefile.in (install): create $(man1dir) and $(man5dir) before
+ installing the man pages
+
+Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in, configure.in: removed traces of namesubdir,
+ -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced
+ copyrights to '92, changed some from Cygnus to FSF.
+
+Tue Dec 10 04:07:08 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: infodir belongs in datadir.
+
+Tue Dec 10 03:59:10 1991 K. Richard Pixley (rich at cygnus.com)
+
+ * cvs.man: small correction to an explanation of an example.
+
+Thu Dec 5 22:45:59 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: idestdir and ddestdir go away. Added copyrights
+ and shift gpl to v2. Added ChangeLog if it didn't exist. docdir
+ and mandir now keyed off datadir by default.
+
+Wed Nov 27 02:46:20 1991 K. Richard Pixley (rich at sendai)
+
+ * brought Makefile.in's up to standards.text.
+
+ * fresh changelog.
+
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..c2a494d
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,26 @@
+## Process this file with automake to produce Makefile.in
+# Makefile.am for GNU CVS man pages.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+man_MANS = cvs.5 cvsbug.8
+EXTRA_DIST = \
+ .cvsignore \
+ $(man_MANS)
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/man/Makefile.in b/man/Makefile.in
new file mode 100644
index 0000000..76e9a23
--- /dev/null
+++ b/man/Makefile.in
@@ -0,0 +1,526 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for GNU CVS man pages.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = man
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+man5dir = $(mandir)/man5
+am__installdirs = "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(man_MANS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+man_MANS = cvs.5 cvsbug.8
+EXTRA_DIST = \
+ .cvsignore \
+ $(man_MANS)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu man/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu man/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+install-man5: $(man5_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man5dir)" || $(mkdir_p) "$(DESTDIR)$(man5dir)"
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man5 install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-man
+
+uninstall-man: uninstall-man5 uninstall-man8
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-man5 install-man8 install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am uninstall uninstall-am uninstall-info-am \
+ uninstall-man uninstall-man5 uninstall-man8
+
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/man/cvs.5 b/man/cvs.5
new file mode 100644
index 0000000..589f067
--- /dev/null
+++ b/man/cvs.5
@@ -0,0 +1,330 @@
+.TH cvs 5 "12 February 1992"
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.SH NAME
+cvs \- Concurrent Versions System support files
+.SH NOTE
+This documentation may no longer be up to date. Please consult the Cederqvist
+(CVS Manual) as specified in
+.BR cvs ( 1 ).
+
+.SH SYNOPSIS
+.hy 0
+.na
+.TP
+.B $CVSROOT/CVSROOT/commitinfo,v
+.TP
+.B $CVSROOT/CVSROOT/cvsignore,v
+.TP
+.B $CVSROOT/CVSROOT/cvswrappers,v
+.TP
+.B $CVSROOT/CVSROOT/editinfo,v
+.TP
+.B $CVSROOT/CVSROOT/history
+.TP
+.B $CVSROOT/CVSROOT/loginfo,v
+.TP
+.B $CVSROOT/CVSROOT/modules,v
+.TP
+.B $CVSROOT/CVSROOT/rcsinfo,v
+.TP
+.B $CVSROOT/CVSROOT/taginfo,v
+.ad b
+.hy 1
+.SH DESCRIPTION
+.B cvs
+is a system for providing source control to hierarchical collections
+of source directories. Commands and procedures for using \fBcvs\fP
+are described in
+.BR cvs ( 1 ).
+.SP
+.B cvs
+manages \fIsource repositories\fP, the directories containing master
+copies of the revision-controlled files, by copying particular
+revisions of the files to (and modifications back from) developers'
+private \fIworking directories\fP. In terms of file structure, each
+individual source repository is an immediate subdirectory of
+\fB$CVSROOT\fP.
+.SP
+The files described here are supporting files; they do not have to
+exist for \fBcvs\fP to operate, but they allow you to make \fBcvs\fP
+operation more flexible.
+.SP
+You can use the `\|modules\|' file to define symbolic names for
+collections of source maintained with \fBcvs\fP. If there is no
+`\|modules\|' file, developers must specify complete path names
+(absolute, or relative to \fB$CVSROOT\fP) for the files they wish to
+manage with \fBcvs\fP commands.
+.SP
+You can use the `\|commitinfo\|' file to define programs to execute
+whenever `\|\fBcvs commit\fP\|' is about to execute.
+These programs are used for ``pre-commit'' checking to verify that the
+modified, added, and removed files are really ready to be committed.
+Some uses for this check might be to turn off a portion (or all) of the
+source repository from a particular person or group.
+Or, perhaps, to verify that the changed files conform to the site's
+standards for coding practice.
+.SP
+You can use the `\|cvswrappers\|' file to record
+.B cvs
+wrapper commands to be used when checking files into and out of the
+repository. Wrappers allow the file or directory to be processed
+on the way in and out of CVS. The intended uses are many, one
+possible use would be to reformat a C file before the file is checked
+in, so all of the code in the repository looks the same.
+.SP
+You can use the `\|loginfo\|' file to define programs to execute after
+any
+.BR commit ,
+which writes a log entry for changes in the repository.
+These logging programs might be used to append the log message to a file.
+Or send the log message through electronic mail to a group of developers.
+Or, perhaps, post the log message to a particular newsgroup.
+.SP
+You can use the `\|taginfo\|' file to define programs to execute after
+any
+.BR tag or rtag
+operation. These programs might be used to append a message to a file
+listing the new tag name and the programmer who created it, or send mail
+to a group of developers, or, perhaps, post a message to a particular
+newsgroup.
+.SP
+You can use the `\|rcsinfo\|' file to define forms for log messages.
+.SP
+You can use the `\|editinfo\|' file to define a program to execute for
+editing/validating `\|\fBcvs commit\fP\|' log entries.
+This is most useful when used with a `\|rcsinfo\|' forms specification, as
+it can verify that the proper fields of the form have been filled in by the
+user committing the change.
+.SP
+You can use the `\|cvsignore\|' file to specify the default list of
+files to ignore during \fBupdate\fP.
+.SP
+You can use the `\|history\|' file to record the \fBcvs\fP commands
+that affect the repository.
+The creation of this file enables history logging.
+.SH FILES
+.TP
+.B modules
+The `\|modules\|' file records your definitions of names for
+collections of source code. \fBcvs\fP will use these definitions if
+you use \fBcvs\fP to check in a file with the right format to
+`\|\fB$CVSROOT/CVSROOT/modules,v\fP\|'.
+.SP
+The `\|modules\|' file may contain blank lines and comments (lines
+beginning with `\|\fB#\fP\|') as well as module definitions.
+Long lines can be continued on the next line by specifying a backslash
+(``\e'') as the last character on the line.
+.SP
+A \fImodule definition\fP is a single line of the `\|modules\|' file,
+in either of two formats. In both cases, \fImname\fP represents the
+symbolic module name, and the remainder of the line is its definition.
+.SP
+\fImname\fP \fB\-a\fP \fIaliases\fP\|.\|.\|.
+.br
+This represents the simplest way of defining a module \fImname\fP.
+The `\|\fB\-a\fP\|' flags the definition as a simple alias: \fBcvs\fP
+will treat any use of \fImname\fP (as a command argument) as if the list
+of names \fIaliases\fP had been specified instead. \fIaliases\fP may
+contain either other module names or paths. When you use paths in
+\fIaliases\fP, `\|\fBcvs checkout\fP\|' creates all intermediate
+directories in the working directory, just as if the path had been
+specified explicitly in the \fBcvs\fP arguments.
+.SP
+.nf
+\fImname\fP [ \fIoptions\fP ] \fIdir\fP [ \fIfiles\fP\|.\|.\|. ] [ \fB&\fP\fImodule\fP\|.\|.\|. ]
+.fi
+.SP
+In the simplest case, this form of module definition reduces to
+`\|\fImname dir\fP\|'. This defines all the files in directory
+\fIdir\fP as module \fImname\fP. \fIdir\fP is a relative path (from
+\fB$CVSROOT\fP) to a directory of source in one of the source
+repositories. In this case, on \fBcheckout\fP, a single directory
+called \fImname\fP is created as a working directory; no intermediate
+directory levels are used by default, even if \fIdir\fP was a path
+involving several directory levels.
+.SP
+By explicitly specifying \fIfiles\fP in the module definition after
+\fIdir\fP, you can select particular files from directory
+\fIdir\fP. The sample definition for \fBmodules\fP is an example of
+a module defined with a single file from a particular directory. Here
+is another example:
+.SP
+.nf
+.ft B
+m4test unsupported/gnu/m4 foreach.m4 forloop.m4
+.ft P
+.fi
+.SP
+With this definition, executing `\|\fBcvs checkout m4test\fP\|'
+will create a single working directory `\|m4test\|' containing the two
+files listed, which both come from a common directory several levels
+deep in the \fBcvs\fP source repository.
+.SP
+A module definition can refer to other modules by including
+`\|\fB&\fP\fImodule\fP\|' in its definition. \fBcheckout\fP creates
+a subdirectory for each such \fImodule\fP, in your working directory.
+.br
+.I
+New in \fBcvs\fP 1.3;
+avoid this feature if sharing module definitions with older versions
+of \fBcvs\fP.
+.SP
+Finally, you can use one or more of the following \fIoptions\fP in
+module definitions:
+.SP
+\&`\|\fB\-d\fP \fIname\fP\|', to name the working directory something
+other than the module name.
+.br
+.I
+New in \fBcvs\fP 1.3;
+avoid this feature if sharing module definitions with older versions
+of \fBcvs\fP.
+.SP
+\&`\|\fB\-i\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are committed. \fIprog\fP runs with a
+single argument, the full pathname of the affected directory in a
+source repository. The `\|commitinfo\|', `\|loginfo\|', and
+`\|editinfo\|' files provide other ways to call a program on \fBcommit\fP.
+.SP
+`\|\fB\-o\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are checked out. \fIprog\fP runs
+with a single argument, the module name.
+.SP
+`\|\fB\-e\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are exported. \fIprog\fP runs
+with a single argument, the module name.
+.SP
+`\|\fB\-t\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever files in a module are tagged. \fIprog\fP runs with two
+arguments: the module name and the symbolic tag specified to \fBrtag\fP.
+.SP
+`\|\fB\-u\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
+to run whenever `\|\fBcvs update\fP\|' is executed from the top-level
+directory of the checked-out module. \fIprog\fP runs with a
+single argument, the full path to the source repository for this module.
+.TP
+\&\fBcommitinfo\fP, \fBloginfo\fP, \fBrcsinfo\fP, \fBeditinfo\fP
+These files all specify programs to call at different points in the
+`\|\fBcvs commit\fP\|' process. They have a common structure.
+Each line is a pair of fields: a regular expression, separated by
+whitespace from a filename or command-line template.
+Whenever one of the regular expression matches a directory name in the
+repository, the rest of the line is used.
+If the line begins with a \fB#\fP character, the entire line is considered
+a comment and is ignored.
+Whitespace between the fields is also ignored.
+.SP
+For `\|loginfo\|', the rest of the
+line is a command-line template to execute.
+The templates can include not only
+a program name, but whatever list of arguments you wish. If you write
+`\|\fB%s\fP\|' somewhere on the argument list, \fBcvs\fP supplies, at
+that point, the list of files affected by the \fBcommit\fP.
+The first entry in the list is the relative path within the source
+repository where the change is being made.
+The remaining arguments list the files that are being modified, added, or
+removed by this \fBcommit\fP invocation.
+.SP
+For `\|taginfo\|', the rest of the
+line is a command-line template to execute.
+The arguments passed to the command are, in order, the
+.I tagname ,
+.I operation
+(i.e.
+.B add
+for `tag',
+.B mov
+for `tag -F', and
+.B del
+for `tag -d`),
+.I repository ,
+and any remaining are pairs of
+.B "filename revision" .
+A non-zero exit of the filter program will cause the tag to be aborted.
+.SP
+For `\|commitinfo\|', the rest of the line is a command-line template to
+execute.
+The template can include not only a program name, but whatever
+list of arguments you wish.
+The full path to the current source repository is appended to the template,
+followed by the file names of any files involved in the commit (added,
+removed, and modified files).
+.SP
+For `\|rcsinfo\|', the rest of the line is the full path to a file that
+should be loaded into the log message template.
+.SP
+For `\|editinfo\|', the rest of the line is a command-line template to
+execute.
+The template can include not only a program name, but whatever
+list of arguments you wish.
+The full path to the current log message template file is appended to the
+template.
+.SP
+You can use one of two special strings instead of a regular
+expression: `\|\fBALL\fP\|' specifies a command line template that
+must always be executed, and `\|\fBDEFAULT\fP\|' specifies a command
+line template to use if no regular expression is a match.
+.SP
+The `\|commitinfo\|' file contains commands to execute \fIbefore\fP any
+other \fBcommit\fP activity, to allow you to check any conditions that
+must be satisfied before \fBcommit\fP can proceed. The rest of the
+\fBcommit\fP will execute only if all selected commands from this file
+exit with exit status \fB0\fP.
+.SP
+The `\|rcsinfo\|' file allows you to specify \fIlog templates\fP for
+the \fBcommit\fP logging session; you can use this to provide a form
+to edit when filling out the \fBcommit\fP log. The field after the
+regular expression, in this file, contains filenames (of files
+containing the logging forms) rather than command templates.
+.SP
+The `\|editinfo\|' file allows you to execute a script \fIbefore the
+commit starts\fP, but after the log information is recorded. These
+"edit" scripts can verify information recorded in the log file. If
+the edit script exits with a non-zero exit status, the commit is aborted.
+.SP
+The `\|loginfo\|' file contains commands to execute \fIat the end\fP
+of a commit. The text specified as a commit log message is piped
+through the command; typical uses include sending mail, filing an
+article in a newsgroup, or appending to a central file.
+.TP
+\&\fBcvsignore\fP, \fB.cvsignore\fP
+The default list of files (or
+.BR sh ( 1 )
+file name patterns) to ignore during `\|\fBcvs update\fP\|'.
+At startup time, \fBcvs\fP loads the compiled in default list of file name
+patterns (see
+.BR cvs ( 1 )).
+Then the per-repository list included in \fB$CVSROOT/CVSROOT/cvsignore\fP
+is loaded, if it exists.
+Then the per-user list is loaded from `\|$HOME/.cvsignore\|'.
+Finally, as \fBcvs\fP traverses through your directories, it will load any
+per-directory `\|.cvsignore\|' files whenever it finds one.
+These per-directory files are only valid for exactly the directory that
+contains them, not for any sub-directories.
+.TP
+.B history
+Create this file in \fB$CVSROOT/CVSROOT\fP to enable history logging
+(see the description of `\|\fBcvs history\fP\|').
+.SH "SEE ALSO"
+.BR cvs ( 1 ),
+.SH COPYING
+Copyright \(co 1992 Cygnus Support, Brian Berliner, and Jeff Polk
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/man/cvsbug.8 b/man/cvsbug.8
new file mode 100644
index 0000000..f5a96b3
--- /dev/null
+++ b/man/cvsbug.8
@@ -0,0 +1,243 @@
+.\" -*- nroff -*-
+.\" ---------------------------------------------------------------------------
+.\" man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com)
+.\" updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com
+.\"
+.\" This file is part of the Problem Report Management System (GNATS)
+.\" Copyright 1992 Cygnus Support
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public
+.\" License as published by the Free Software Foundation; either
+.\" version 2 of the License, or (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" ---------------------------------------------------------------------------
+.nh
+.TH CVSBUG 8 xVERSIONx "February 1993"
+.SH NAME
+cvsbug \- send problem report (PR) about CVS to a central support site
+.SH SYNOPSIS
+.B cvsbug
+[
+.I site
+]
+[
+.B \-f
+.I problem-report
+]
+[
+.B \-t
+.I mail-address
+]
+.br
+.in +0.8i
+[
+.B \-P
+]
+[
+.B \-L
+]
+[
+.B \-\-request-id
+]
+[
+.B \-v
+]
+.SH DESCRIPTION
+.B cvsbug
+is a tool used to submit
+.I problem reports
+.\" SITE ADMINISTRATORS - change this if you use a local default
+(PRs) to a central support site. In most cases the correct
+.I site
+will be the default. This argument indicates the support site which
+is responsible for the category of problem involved. Some sites may
+use a local address as a default.
+.I site
+values are defined by using the
+.BR aliases (5).
+.LP
+.B cvsbug
+invokes an editor on a problem report template (after trying to fill
+in some fields with reasonable default values). When you exit the
+editor,
+.B cvsbug
+sends the completed form to the
+.I Problem Report Management System
+(\fBGNATS\fR) at a central support site. At the support site, the PR
+is assigned a unique number and is stored in the \fBGNATS\fR database
+according to its category and submitter-id. \fBGNATS\fR automatically
+replies with an acknowledgement, citing the category and the PR
+number.
+.LP
+To ensure that a PR is handled promptly, it should contain your (unique)
+\fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the
+problem area. (Use
+.B `cvsbug -L'
+to see a list of categories.)
+.LP
+The
+.B cvsbug
+template at your site should already be customized with your
+submitter-id (running `\|\fBinstall-sid\fP \fIsubmitter-id\fP\|' to
+accomplish this is part of the installation procedures for
+.BR cvsbug ).
+If this hasn't been done, see your system administrator for your
+submitter-id, or request one from your support site by invoking
+.B `cvsbug \-\-request\-id'.
+If your site does not distinguish between different user sites, or if
+you are not affiliated with the support site, use
+.B `net'
+for this field.
+.LP
+The more precise your problem description and the more complete your
+information, the faster your support team can solve your problems.
+.SH OPTIONS
+.TP
+.BI \-f " problem-report"
+specify a file (\fIproblem-report\fR) which already contains a
+complete problem report.
+.B cvsbug
+sends the contents of the file without invoking the editor. If
+the value for
+.I problem-report
+is
+.BR `\|\-\|' ,
+then
+.B cvsbug
+reads from standard input.
+.TP
+.BI \-t " mail-address"
+Change mail address at the support site for problem reports. The
+default
+.I mail-address
+is the address used for the default
+.IR site .
+Use the
+.I site
+argument rather than this option in nearly all cases.
+.TP
+.B \-P
+print the form specified by the environment variable
+.B PR_FORM
+on standard output. If
+.B PR_FORM
+is not set, print the standard blank PR template. No mail is sent.
+.TP
+.B -L
+print the list of available categories. No mail is sent.
+.TP
+.B \-\-request\-id
+sends mail to the default support site, or
+.I site
+if specified, with a request for your
+.IR submitter-id .
+If you are
+not affiliated with
+.IR site ,
+use a
+.I submitter-id
+of
+.BR net \|'.
+.TP
+.B \-v
+Display the
+.B cvsbug
+version number.
+.LP
+Note: use
+.B cvsbug
+to submit problem reports rather than mailing them directly. Using
+both the template and
+.B cvsbug
+itself will help ensure all necessary information will reach the
+support site.
+.SH ENVIRONMENT
+The environment variable
+.B EDITOR
+specifies the editor to invoke on the template.
+.br
+default:
+.B vi
+.sp
+If the environment variable
+.B PR_FORM
+is set, then its value is used as the file name of the template for
+your problem-report editing session. You can use this to start with a
+partially completed form (for example, a form with the identification
+fields already completed).
+.SH "HOW TO FILL OUT A PROBLEM REPORT"
+Problem reports have to be in a particular form so that a program can
+easily manage them. Please remember the following guidelines:
+.IP \(bu 3m
+describe only
+.B one problem
+with each problem report.
+.IP \(bu 3m
+For follow-up mail, use the same subject line as the one in the automatic
+acknowledgement. It consists of category, PR number and the original synopsis
+line. This allows the support site to relate several mail messages to a
+particular PR and to record them automatically.
+.IP \(bu 3m
+Please try to be as accurate as possible in the subject and/or synopsis line.
+.IP \(bu 3m
+The subject and the synopsis line are not confidential. This is
+because open-bugs lists are compiled from them. Avoid confidential
+information there.
+.LP
+See the GNU
+.B Info
+file
+.B cvsbug.info
+or the document \fIReporting Problems With cvsbug\fR\ for detailed
+information on reporting problems
+.SH "HOW TO SUBMIT TEST CASES, CODE, ETC."
+Submit small code samples with the PR. Contact the support site for
+instructions on submitting larger test cases and problematic source
+code.
+.SH FILES
+.ta \w'/tmp/pbad$$ 'u
+/tmp/p$$ copy of PR used in editing session
+.br
+/tmp/pf$$ copy of empty PR form, for testing purposes
+.br
+/tmp/pbad$$ file for rejected PRs
+.SH INSTALLATION AND CONFIGURATION
+See
+.B INSTALL
+for installation instructions.
+.SH SEE ALSO
+.BR gnats (l),
+.BR query-pr (1),
+.BR edit-pr (1),
+.BR gnats (8),
+.BR queue-pr (8),
+.BR at-pr (8),
+.BR mkcat (8),
+.BR mkdist (8).
+.SH AUTHORS
+Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus
+Support)
+.SH COPYING
+Copyright (c) 1992, 1993 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+
diff --git a/mktemp.sh b/mktemp.sh
new file mode 100644
index 0000000..8bef4d5
--- /dev/null
+++ b/mktemp.sh
@@ -0,0 +1,39 @@
+# mktemp
+
+# Copyright (c) Derek Price, Ximbiot <http://ximbiot.com>, and the
+# Free Software Foundation, Inc. <http://gnu.org>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+
+
+# This Bourne Shell scriptlet is intended as a simple replacement for
+# the BSD mktemp function for systems that do not support mktemp. It
+# currently does not check that the files it is creating did not exist
+# previously and it does not verify that it successfully creates the
+# files it returns the names of.
+mktemp() {
+ if test x"$1" = x-d; then
+ tmp=`echo $2 |sed "s/XXXXXX/$$/"`
+ (umask 077 && exec mkdir $tmp) || return 1
+ else
+ tmp=`echo $1 |sed "s/XXXXXX/$$/"`
+ (umask 077 && touch $tmp) || return 1
+ fi
+ echo $tmp
+ return 0
+}
+
diff --git a/os2/.cvsignore b/os2/.cvsignore
new file mode 100644
index 0000000..fc6daa1
--- /dev/null
+++ b/os2/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+cvs.exe
+icc.in
diff --git a/os2/ChangeLog b/os2/ChangeLog
new file mode 100644
index 0000000..3a2a035
--- /dev/null
+++ b/os2/ChangeLog
@@ -0,0 +1,1012 @@
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * README: Update bug-cvs email.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (open_file): Remove this function.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * config.h: Remove obsolete timeb cruft.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (LIB_SOURCES): Remove stripslash.c.
+ (OS2_OBJECTS): Remove stripslash.obj.
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * stripslash.c: Remove file.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (isabsolute): Remove this function.
+ * config.h (ISABSOLUTE): Define.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * run.c (quote, run_setup): Probably broke this, but not by much.
+ Initially changed the wrong file but left it there in case somebody
+ wanted to finish. Most likely only the run_add_arg function needs
+ to be fiddled with - the quoting has changed.
+
+2003-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (xresolvepath): New function.
+
+2003-08-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (pdf ps): New recursive targets to be ignored for
+ Automake's benefit.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * config.h (PROTOTYPES): Remove definition.
+ * filesubr.c: s/PROTO//.
+ * run.c: Ditto.
+
+2002-05-28 Derek Price <derek@ximbiot.com>
+
+ * config.h: Use standard PROTOTYPES symbol instead of non-standard
+ USE_PROTOTYPES.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2002-03-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Remove unecessary dependence on $(srcdir) to
+ fix the dist target.
+ (distdir): Use new automake generated target (copied from src).
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h (RSH_DFLT): Default to "rsh".
+
+2002-12-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Remove reference to options.h.
+ * options.h: Remove file and move relevant content...
+ * config.h: ...here.
+
+2002-12-06 Derek Price <derek@ximbiot.com>
+
+ * dirent.c: Replace call to realloc with a call to xrealloc and calls
+ to malloc with calls to xmalloc.
+ * popen.c: Ditto.
+ * pwd.c: Ditto.
+ * run.c: Ditto.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove prototype of STDC exit(). Move prototype of
+ getpass()...
+ * config.h: here.
+
+2002-08-24 Larry Jones <lawrence.jones@eds.com>
+
+ * options.h: Remove PATCH_PROGRAM.
+
+2002-08-16 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove RELATIVE_REPOS & move CVS_BADROOT...
+ * config.h: ...here.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in (installcheck): New target.
+
+2001-02-14 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Remove references to rtag.c & rtag.obj.
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Added support for Automake targets
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * options.h: Make RELATIVE_REPOS the default, as in
+ ../src/options.h.in.
+ Remove CVS_DIFFDATE; removed from CVS on 27 Jun 1996.
+
+1998-12-29 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in: Use the getdate.c in ../lib rather than the one
+ here. I don't know whether it compiles with Watcom and/or IBM's
+ compiler, but having a copy of getdate.c in this directory has
+ proven to be unworkable (the version I am removing still had Y2K
+ bugs which were fixed in lib/getdate.c, for example).
+ * getdate.c: Removed.
+
+1998-04-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (link_file): Remove; no longer used.
+
+Tue Feb 17 02:31:15 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * filesubr.c (last_component): return the top-level directory when
+ asked about the top-level directory.
+
+Tue Jan 13 13:17:33 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c: Adjust run_setup for new calling convention.
+
+ * config.h (DIFF): Remove; no longer used.
+ * options.h (DIFF, RCSBIN_DFLT): Remove; no longer used.
+
+Wed Dec 31 10:56:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h, filesubr.c (convert_file): Remove; no longer used
+ (except for BROKEN_READWRITE_CONVERSION which doesn't apply).
+
+Sat Dec 27 16:57:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (HAVE_RCS5): Remove; no longer used.
+
+ * config.h (LINES_CRLF_TERMINATED): Remove; no longer used.
+
+Tue Dec 23 08:28:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Change bug-cvs address from prep.ai.mit.edu to gnu.org
+ per email from Martin Hamilton.
+
+Sun Nov 30 18:03:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (run_args): Remove; nowhere used.
+
+Sat Nov 29 22:21:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove declaration of getwd; see lib/ChangeLog for
+ rationale.
+
+Sun Aug 10 20:42:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * pwd.c, pwd.h: Remove $Header; we decided to get rid of these
+ some time ago.
+
+Wed Jul 30 19:15:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (os2_chdir): If ENODEV is not defined, return ENOENT.
+
+ * README: Talk about srcdir, top_srcdir, and rule to generate
+ "Makefile".
+ * Makefile.in: Add comment about Makefile rule.
+
+Mon Jun 16 13:49:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h, rcmd.h, rcmd.c: Add "copyright" notice.
+
+Sun Jun 8 23:41:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h (HAVE_MKFIFO): Remove; not used anywhere.
+
+Wed Apr 30 12:45:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * icc.compilation-errors: Removed; it was the error messages from
+ trying to compile CVS on OS/2, way out of date.
+
+Wed Mar 12 16:10:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h (HAVE_SETVBUF): Removed; no longer used.
+
+Mon Feb 10 20:01:20 1997 Ullrich von Bassewitz <uz@musoftware.com>
+
+ * filesubr.c: Add an OS/2 specific chdir function that will not
+ only change the path but will also make the drive current that
+ is given in the argument string.
+ config.h: #define the macro CVS_CHDIR to os2_chdir so cvs will
+ use the os2_chdir function instead of chdir.
+
+Mon Feb 10 18:29:04 1997 Ullrich von Bassewitz <uz@musoftware.com>
+
+ * config.h: Define VA_LIST_IS_ARRAY so that vasprintf will work
+ correctly with the watcom compiler.
+
+Sun Feb 9 20:17:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Most of the compiler warnings are gone.
+
+1997-02-09 Jim Kingdon <kingdon@cyclic.com>
+
+ * popen.h: Arguments to popen are const char * not char *.
+
+Wed Jan 29 18:27:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h, config.h (GREP): Remove; no longer used.
+
+Tue Jan 28 18:29:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Remove SIZEOF_INT and SIZEOF_LONG; no longer needed
+ with lib/md5.c changes.
+
+Wed Jan 15 23:56:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * watcom.mak (OS2_OBJECTS): Remove strippath.
+
+ * Makefile.in (DISTFILES): Add os2inc.h and watcom.mak.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c, pwd.c, pwd.h, run.c, stripslash.c:
+ Remove "675" paragraph; see ../ChangeLog for rationale.
+
+Wed Jan 1 22:50:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Reword comment for TMPDIR_DFLT to make it clear that
+ this isn't specific to the pserver server.
+
+Wed Dec 18 10:51:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (CFLAGS): Specify -Gd- not -Gd+. The documentation
+ says this causes a static link, although it hasn't yet been
+ verified whether this option is sufficient to make the binary work
+ on a system without the compiler's DLL.
+
+Fri Dec 6 11:00:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * os2inc.h, watcom.mak: Add GPL notice.
+
+1996-11-24 Ullrich von Bassewitz <uz@wuschel.ibb.schwaben.com>
+
+ Changes for Watcom C:
+ * README: Describe watcom port.
+ * config.h: Include stdio.h and errno.h.
+ * config.h: If EACCES is not defined, define it to EACCESS.
+ * filesubr.c: Use EACCES not EACCESS.
+ * config.h [__WATCOMC__]: Define _setmode and _cwait.
+ Don't define HAVE_DIRENT_H. Don't declare getpid. Don't
+ define NEED_DECOY_PERMISSIONS. Don't define R_OK and friends.
+ * os2inc.h: New file; includes os2.h but protected against
+ multiple inclusion.
+ * config.h: Include os2inc.h before defining sleep.
+ * filesubr.c, getpass.c, popen.c, run.c: Include os2inc.h rather than
+ trying to go through the right contortions to include os2.h
+ ourselves.
+ * popen.c (popen) [__WATCOMC__]: Use _hdopen together with fdopen.
+ (popenRW): Change pid from PID to int.
+ * tcpip.h [__WATCOMC__]: Work around errno value conflict
+ between the TCP/IP header and errno.h.
+ * watcom.mak: New file.
+
+Sat Nov 23 18:36:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Try to clarify status vis-a-vis client vs. local.
+
+Tue Nov 19 17:21:52 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (OS2_SOURCES): Remove strippath.c
+ (OS2_OBJECTS): Remove strippath.obj.
+ * strippath.c: Removed.
+
+Fri Nov 8 14:28:19 1996 Ullrich von Bassewitz <uz@wuschel.ibb.schwaben.com>
+
+ * filesubr.c (expand_wild): Check for ERROR_NO_MORE_FILES from
+ DosFindFirst instead of ERROR_FILE_NOT_FOUND; that is what the
+ function actually returns. Cope with the fact that DosFindFirst
+ and DosFindNext return only the name of the file itself, not any
+ directory names.
+
+Fri Nov 08 11:46:50 1996 Jim Kingdon
+
+ IBM ICC (OS/2) lint:
+ * filesubr.c: Cast from const char * to char * before passing to
+ various system functions.
+ (xchmod): Print error message instead of trying to return ENOENT.
+ (unlink_file): Only call xchmod if the file exists.
+
+ * Makefile.in (CFLAGS): Don't specify -Wpro; there is no way
+ that we could prototype getopt, for example.
+ Don't specify -Wuse. The EDC0805 warning ("Automatic
+ variable line_allocated is set but not referenced.") warns
+ about unavoidable constructs like line_allocated in
+ client.c (send_file_names).
+
+Sat Oct 26 16:21:26 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * config.h (HAVE_TZSET): Add a #definition for this.
+
+Tue Oct 8 12:37:35 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * options.h (HAD_RCS4): Remove; no longer used.
+
+Thu Sep 26 14:15:55 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * filesubr.c (mkdir_if_needed): mkdir only takes one
+ argument on OS/2.
+
+Wed Sep 25 14:31:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (TMPDIR_DFLT): Change from c:\temp to c:\\temp.
+
+Tue Sep 24 14:39:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Add TMPDIR_DFLT.
+
+Mon Aug 26 12:31:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (mkdir_if_needed): Added.
+
+Fri Aug 16 16:05:29 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in (installdirs): new (empty) target
+
+Mon Aug 12 22:59:40 1996 Jim Kingdon (unknown@beezley)
+
+ * filesubr.c (fncmp): Fix typo (n1 -> n2) which had caused the
+ function to always return 0.
+
+ * Makefile.in (COMMON_OBJECTS): Add buffer.obj.
+ (COMMON_SOURCES): Add buffer.c.
+ (zlib_srcdir,ZLIB_OBJECTS): Added.
+ (cvs.exe): Also link with ZLIB_OBJECTS.
+ (OBJECTS): Add ZLIB_OBJECTS.
+ (LIB_OBJECTS): Add valloc.obj.
+ (COMMON_OBJECTS): Add zlib.obj.
+
+Mon Aug 12 16:25:32 1996 Steffen Siebert <siebert@susan.logware.de>
+ and Jim Kingdon (unknown@beezley)
+
+ * Makefile.in (cvs.exe): Use subst so that we link with \
+ and compile with / without needing to mess with SL.
+ * README: Adjust accordingly.
+
+Mon Jul 15 22:32:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Remove EXECUTE_PERMISSION_LOSES; it is no longer used
+ anywhere (superceded by CHMOD_BROKEN).
+
+Fri Jun 7 13:07:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Change INITIALIZE_SOCKET_SUBSYSTEM to
+ SYSTEM_INITIALIZE to reflect change in ../src/main.c.
+
+Tue May 14 13:38:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (cvs_temp_name): New function.
+
+Tue May 7 10:50:13 MET DST 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * filesubr.c (expand_wild): Real implementation (like
+ Windows-NT) for expanding.
+
+Thu Apr 25 09:28:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Add note about LF vs. CRLF in makefile.
+
+Tue Apr 23 20:43:01 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * filesubr.c (get_homedir, expand_wild): New functions.
+
+Wed Feb 28 11:08:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove AUTH_SERVER_SUPPORT; no longer should be
+ defined in options.h.
+
+ * config.h: Remove C_ALLOCA, CRAY_STACKSEG_END, HAVE_ALLOCA,
+ HAVE_ALLOCA_H, and STACK_DIRECTION to reflect alloca removal.
+
+Mon Feb 19 00:35:24 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * Makefile.in: deal with new objects `mkmodules' and `vasprintf'.
+
+ * getpass.c (EchoOn, EchoOff): new funcs.
+ (getpass): use above new funcs to avoid echoing the password to
+ the screen.
+
+Mon Feb 12 16:09:55 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * run.c (run_popen): Changed more Popen() to run_popen()
+
+Mon Feb 12 03:33:27 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * run.c: Changed Popen() to run_popen() for the benefit of
+ case-insensitive linkers (VMS) which confuse Popen() with popen()
+
+Mon Feb 12 03:14:36 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * options.h (PATCH_PROGRAM): "cvspatch" (see comment).
+
+Fri Feb 9 22:10:12 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Remove SYSTEM_COMMENT_TABLE.
+
+Thu Feb 1 15:07:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove RM; no longer used.
+
+ * filesubr.c: Remove rcsid.
+
+Sun Jan 28 12:31:03 1996 Jim Kingdon (kingdon@beezley)
+
+ * filesubr.c (unlink_file): Use xchmod, not chmod, to make the
+ file read-write.
+ (xchmod): Translate / to \ in file name. If file doesn't exist,
+ return ENOENT rather than passing it to attrib (which will print an
+ error message).
+
+Sun Jan 28 01:51:27 1996 Jim Kingdon (kingdon@beezley)
+
+ * config.h: Fix unclosed comment.
+
+Sun Jan 28 00:16:58 1996 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * filesubr.c (xchmod): rewritten for OS/2.
+
+Sat Jan 27 16:18:20 1996 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * config.h (CHMOD_BROKEN): define to 1.
+
+ * filesubr.c (rename_file): rename() returns non-zero error codes,
+ not necessarily negative.
+
+Fri Jan 26 00:52:12 1996 unknown (unknown@beezley)
+
+ * filesubr.c (copy_file): Open the file we are writing, not
+ just the one we are reading, in binary mode.
+
+Thu Jan 18 14:53:58 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (CFLAGS): Don't use +=. This makefile must be
+ portable because it is used on all platforms (e.g. for "make dist").
+
+Thu Jan 11 12:04:42 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * options.h: remove CVS_NOADMIN
+
+Wed Jan 10 15:56:46 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * options.h, config.h: moved NO_SOCKET_TO_FD definition from
+ options.h to config.h, which is where it belongs.
+
+Tue Jan 9 16:43:15 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * run.c (sleep): commented out this definition.
+ * config.h: #define sleep() in terms of DosSleep(), unless sleep()
+ is defined already. Normally it's defined in
+ tcpip/include/utils.h, however on beezley that definition is
+ commented out for some reason.
+ Don't prototype sleep().
+
+Tue Jan 9 16:22:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * .cvsignore: Add cvs.exe and icc.in.
+
+Tue Jan 09 16:43:59 1996 Jim Kingdon (kingdon@beezley.cyclic.com)
+
+ * filesubr.c (link_file): New function (copied from
+ ../windows-NT/filesubr.c)
+
+Fri Jan 5 17:03:09 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * Makefile.in: "lib_dir", not "libdir", to avoid conflict with
+ top-level Makefile.
+
+Mon Jan 1 22:59:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Makefile is not in srcdir.
+
+Sat Dec 23 23:08:43 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * README: adjust for below change.
+
+ * Makefile.in (install-cvs): replaces `install', which must remain
+ a dummy rule so it will work under Unix.
+
+Wed Dec 20 15:18:06 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in: build scramble.obj.
+
+Mon Dec 18 22:49:28 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Reverted all changes between Mon Dec 18 14:54:04 1995 and
+ present, non-inclusive.
+
+Mon Dec 18 21:59:07 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * getpass.c: removed -- getpass() lives in os2/login.c now.
+
+ * cvslogin.c: filled in.
+
+ * login.c: new file.
+
+ * Makefile.in: moved login.c and login.obj from COMMON to OS2
+ section.
+
+Mon Dec 18 19:55:43 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvslogin.c: added long explanatory comment.
+
+Mon Dec 18 18:13:57 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (DISTFILES): include cvslogin.c.
+
+Mon Dec 18 18:07:26 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * README: updated.
+
+ * Makefile.in (cvslogin.exe): new rule.
+ (install): new rule.
+ (install_dir): new var.
+
+ * cvslogin.c: new file.
+
+Mon Dec 18 14:54:04 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * getpass.c (getpass): removed debugging garbage.
+
+ * options.h (NO_SOCKET_TO_FD): fixed comment (Windows 95, not NT,
+ has this problem).
+ (AUTH_CLIENT_SUPPORT): on by default.
+
+ * porttcp.c (SockStrError): fixed typo.
+ (IbmSockSend): `Buffer' arg is const void * again.
+ (IbmSockRecv): `Buffer' arg is const void * again.
+
+ * tcpip.h (send): move send/recv redef section farther down to
+ avoid type conflicts with the real send() and recv().
+ (IbmSockSend, IbmSockRecv): adjust prototype.
+
+Mon Dec 18 12:31:22 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * tcpip.h: reformatted.
+ (send, recv): redefine to IbmSockSend and IbmSockRecv.
+
+ * porttcp.c: reformatted.
+
+Mon Dec 18 04:59:52 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * tcpip.h (send, recv): don't define these to be anything else.
+
+ * porttcp.c (IbmSockSend, IbmSockRecv): make `Buffer' argument
+ char * instead of void *, to evade an over-eager compiler.
+
+Sun Dec 17 21:16:17 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h (NO_SOCKET_TO_FD): define to 1.
+
+Sat Dec 16 21:31:02 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * run.c: mark unimplemented routines more clearly. Hopefully I'll
+ get time to implement them soon.
+
+Fri Dec 15 17:50:17 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * tcpip.h, porttcp.c: new files.
+
+ * makefile.in: added new files (for the "cvs watch" and "cvs edit"
+ commands just checked in by Jim Kingdon).
+
+Thu Dec 14 12:18:20 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * config.h (RSH_NEEDS_BINARY_FLAG): define to 1.
+
+ * run.c (filter_stream_through_program): die, rather than return
+ -1, if spawn failed.
+
+ * options.h (AUTH_CLIENT_SUPPORT): leave unset by default.
+
+Wed Dec 13 21:31:10 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * waitpid.c (waitpid): Don't deal specially with statusp after all.
+ The problem lies elsewhere.
+
+Wed Dec 13 20:58:12 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * waitpid.c (waitpid): oops, make sure there is storage for
+ local_statusp.
+ Don't assign to *statusp if statusp is NULL.
+
+Wed Dec 13 19:52:08 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * waitpid.c (waitpid): be more careful about child's exit status,
+ and about return status of this function.
+
+Wed Dec 13 20:10:50 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * makefile.in (clean): pass /NOE to the linker, to avoid duplicate
+ symbols when linking with setargv.obj.
+
+Wed Dec 13 18:44:47 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (ARGVLIB): new lib, link with this so command-line
+ wildcard expansion works. No, I'm not making this up.
+
+Tue Dec 12 20:43:56 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * getpass.c (getpass): new file and function.
+
+ * options.h: prototype getpass() for OS/2.
+
+ * makefile.in: include new file getpass.c.
+
+Tue Dec 12 19:21:05 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h (RCSBIN_DFLT): expand comment.
+ (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): replace obsolete
+ CVS_AUTH_CLIENT_SUPPORT and CVS_AUTH_SERVER_SUPPORT.
+
+Mon Dec 11 16:03:01 1995 Karl Fogel (kfogel@beezley.cyclic.com)
+
+ * makefile.in: removed various and sundry cruft...
+
+Mon Dec 11 15:57:03 1995 Karl Fogel (kfogel@beezley.cyclic.com)
+
+ * Removed cvs.exe; we don't need to keep the binary in the
+ repository, now that binary file handling has been tested.
+
+Mon Dec 11 15:53:51 1995 Karl Fogel (kfogel@beezley.cyclic.com)
+
+ * rcmd.c (init_sockets): use sock_init(), not SockInit().
+
+Mon Dec 11 12:43:35 1995 Adam Glass <adamg@microsoft.com>
+
+ * config.h: Remove NEED_CALL_SOCKINIT macro in favor of the more
+ generic INITIALIZE_SOCKET_SUBSYSTEM.
+ * rcmd.c: Move old NEED_CALL_SOCKINIT code here and wrap it in a
+ function, i.e init_sockets()
+
+Sat Dec 09 21:16:09 1995 Karl Fogel (kfogel@beezley.cyclic.com)
+
+ * Added cvs.exe, mainly to test binary file handling. Once we
+ know it works, we can remove it.
+
+Sat Dec 09 15:29:16 1995 Karl Fogel (kfogel@beezley.cyclic.com)
+
+ * options.h (DIFF, GREP): don't expect autoconf to help us out.
+
+Sat Dec 09 15:05:41 1995 Karl Fogel (kfogel@beezley.cyclic.com)
+
+ * makefile.in (libdir): Fixed.
+
+ * options.h: define CVS_AUTH_CLIENT_SUPPORT and
+ CVS_AUTH_SERVER_SUPPORT, instead of CVS_LOGIN.
+
+Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com)
+
+ * filesubr.c (isaccessible): Rename from isaccessable.
+
+Mon Dec 4 11:28:10 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in (DISTFILES): prefix all filenames with
+ ${srcdir}${PS}
+ (dist-dir): remove ${srcdir}${PS} (some files already had this
+ prefix, now all have it)
+
+Fri Dec 1 14:29:44 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (srcdir, libdir, cvs_srcdir): use autoconf vars.
+ (dist-dir): use above vars now that they are autoconf-friendly.
+ (clean): same.
+
+Thu Nov 30 18:09:50 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * waitpid.c (waitpid): if _cwait() returns -1, test errno. If
+ ECHILD, then just return pid, else return -1. This is for OS/2,
+ which doesn't have zombie processes, or any other way of
+ remembering a child process after it exits, as far as I can tell.
+
+ * run.c (close_on_exec): don't error, just silently do nothing.
+
+ * Makefile.in: use src/client.c, not os2/client.c.
+
+ * config.h (EXECUTE_PERMISSION_LOSES): define to 1 (see
+ src/client.c for why).
+ (START_RSH_WITH_POPEN_RW): define to 1 (see src/client.c).
+
+Wed Nov 29 16:34:34 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_server): declare pipes[] as int, not FILE *.
+ Kinda nice that it worked anyway, but scary. Ugh.
+
+Wed Nov 22 11:29:11 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * config.h (KFF_DEBUG): expand to nothing; we don't want to print
+ out debugging messages in a production copy.
+
+Tue Nov 21 17:36:16 1995 unknown (unknown@beezley)
+
+ * popen.c: #include <fcntl.h>.
+
+Tue Nov 21 16:18:37 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * popen.h (popenRW): prototype popenRW()... why wasn't I doing
+ this before?
+
+ * client.c (start_server): set tofd and fromfd with popenRW, now
+ that it handles int file descriptors.
+ Log to a file if asked, now that we have
+ filter_stream_through_program().
+
+ * popen.c (popenRW): put int file descriptors into the `pipes'
+ array, not FILE *'s. We'll fdopen in start_server, just like
+ the good old days.
+
+Tue Nov 21 16:34:37 1995 unknown (unknown@beezley)
+
+ * run.c (filter_stream_through_program): defined for OS/2.
+
+ * client.c (start_server): pass a char **argv to popenRW and get a
+ pid in return (instead of a return code).
+
+ * popen.c (popenRW): use a char **argv and spawnvp(), instead of a
+ char *command and DosExecPgm().
+
+Mon Nov 20 23:31:54 1995 unknown (unknown@beezley)
+
+ * filesubr.c (convert_file): pass (S_IREAD | S_IWRITE) to open();
+ we need it if O_CREAT, and it won't hurt if not.
+
+Sun Nov 19 13:43:02 1995 unknown (unknown@beezley)
+
+ * makefile.in (clean): remove obj files in src/ and lib/ dirs too.
+
+Sun Nov 19 12:35:08 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_server): took out old debug statements.
+
+ * dirent.c, dirent.h: took out ^M's.
+
+Sat Nov 18 13:39:06 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_server): took out debug statements.
+
+ * filesubr.c (make_directories): compare errno to EACCESS, not
+ EEXIST, to see if the dir already exists.
+
+ * client.c, filesubr.c: Use new macro `existence_error', instead
+ of comparing errno to ENOENT directly.
+
+ * popen.c (popenRW): fixed misleading comment.
+
+ * client.c:
+ (rsh_pid): no more need for this var; the handle-to-PID library in
+ popen.c manages PID's for us now.
+ (start_rsh_server): removed this func, since we don't use it -- we
+ do use `rsh', but we call it directly from popenRW().
+ (get_responses_and_close): removed cruft that doesn't apply to
+ this port -- i.e., blocks conditional on HAVE_KERBEROS or
+ RSH_NOT_TRANSPARENT.
+ (start_server): Just check return code, instead of recording
+ rsh_pid.
+
+Fri Nov 17 21:13:22 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (call_in_directory): Ask EACCESS even though we're
+ looking for EEXIST. That's just The Way Things Are Done here,
+ apparently. Ick.
+
+ * getdate.c: took out some cruft that the more portable versions
+ need.
+
+ * Makefile.in: use getdate.c from os2/ subdir, not lib/.
+ We don't use startserver.c anymore, so don't build it.
+
+ * client.c (change_mode): never set anything executable, until we
+ understand what that means in OS/2.
+
+ * config.h (NEED_DECOY_PERMISSIONS): define to 1 (& see
+ system.h).
+
+Fri Nov 17 15:02:05 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c: fixed up more error codes.
+
+ * client.c: (send_repository): take into account the cornucopia of
+ error codes so generously offered by OS/2.
+
+Fri Nov 17 14:53:22 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c, client.h: new files, copied from ../src/.
+
+ * config.h (HAVE_POPEN_RW): don't define this anymore, since we'll
+ just be using our own version of client.c.
+
+ * Makefile.in: reflect the fact that os2/client.c is now used
+ instead of src/client.c.
+
+Thu Nov 16 21:47:22 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * startserver.c: removed. We don't need this anymore.
+
+ * config.h (RSH_NOT_TRANSPARENT): undef this. We have a
+ transparent rsh.
+ (HAVE_POPEN_RW): define to 1.
+
+ * popen.c (popenRW): open writing and reading streams in binary
+ mode (i.e., "wb" and "rb").
+
+ * Makefile.in (clean): use `rm' not `del' to remove files.
+
+Wed Nov 15 15:21:53 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * config.h: don't prototype gethostname() here anymore.
+ (USE_OWN_TCPIP_H): define to 1.
+ (NEED_CALL_SOCKINIT): define to 1.
+ (KFF_DEBUG): debugging macro.
+
+Tue Nov 14 12:20:22 1995 Greg A. Woods <woods@most.weird.com>
+
+ * .cvsignore: "Makefile" generated by ../configure
+
+Mon Nov 13 13:21:43 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (PS): note to maintainers about this var.
+
+Mon Nov 13 07:28:04 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * README: updated.
+
+ * rcmd.c: #include <stdio.h>.
+
+ * Makefile.in: Include lib/regex, lib/getdate, strippath.
+ (PS): default to "/", since we always "make dist" on Unix
+ systems.
+ Ahem, "save-cwd" with a hyphen, not an underscore. Oops.
+
+ * strippath.c: new file.
+
+ * popen.c: set DIAGNOSTIC off. Reformat for readability.
+
+ * popen.h: new file.
+
+ * config.h (USE_OWN_POPEN): define to 1.
+
+ * run.c (Popen): make this work now that we have popen().
+
+Mon Nov 13 01:23:27 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in:
+ (cvs.exe): broke up OBJECTS into components to create icc.in in
+ more steps. OBJECTS had gotten so big that it formed too long a
+ command line all by itself. Sheesh.
+ Include stripslash (see below), lib/save_cwd, lib/sighandle,
+ lib/yesno, startserver (see below), rcmd (see below), lib/xgetwd,
+ lib/md5, waitpid (see below), lib/fnmatch, popen (see below).
+
+ * popen.c, rcmd.c, rcmd.h, startserver.c, stripslash.c, waitpid.c:
+ New files.
+
+ * run.c (close_on_exec): new func (skeleton).
+ (sleep): new func (OS/2 doesn't seem to have this).
+
+ * pwd.c (getlogin): Don't call win32getlogin(), obviously.
+
+ * config.h (W_OK, R_OK, X_OK, F_OK): define masks for access().
+ Include <process.h> for getpid().
+
+ * filesubr.c (isaccessable): define. Don't know why I left it out
+ before. For that matter, I don't know how the Windows NT port
+ gets along without it. Hmmm.
+
+Sat Nov 11 15:00:01 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in: Use backslashes in pathnames, so ICC doesn't
+ mistake them for options.
+
+ * run.c (run_setup): cleared away Windows NT stuff, left skeleton
+ functions that just complain and die for now.
+ (run_exec): correctly check return of spawn under OS/2; return
+ child's exit status.
+ (run_args): declare as returning void, in agreement with cvs.h.
+
+Fri Nov 10 14:21:14 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (COMMON_SOURCES, COMMON_OBJECTS): removed filesubr
+ and run, since we have OS/2-specific versions of them now.
+ (DISTFILES): Include Makefile in distribution, since people won't
+ be running configure on their OS/2 systems.
+ (LIB_SOURCES, LIB_OBJECTS): new vars; we'll just build stuff in
+ the lib directory and link it in directly.
+ Made rules for compiling objects and for the full executable.
+ (SHELL): got rid of this var, no need for it here.
+ Use a pattern rule for obj files.
+ Some other minor tweaks for OS/2.
+
+ * threads.c: new file.
+
+Wed Nov 8 11:14:46 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * run.c: include <stdarg.h> and <stdio.h>.
+ Change all VA_START to va_start.
+ Don't ask HAVE_VPRINTF -- this is an OS/2-specific file and we can
+ take things for granted.
+ Started simplifying old NT `HANDLE' code.
+
+ * Makefile.in (OS2_SOURCES): added run.c.
+
+ * run.c: new file, copied from ../windows-NT/run.c. Started
+ making changes for OS/2.
+
+ * test-makefile (all): don't bother to echo $CFLAGS; we can just
+ read the compilation command.
+
+ * filesubr.c (unlink_file): make this work on OS/2.
+ (unlink_file_dir): don't ask if errno == EISDIR. We ain't
+ got EISDIR in OS/2.
+ (deep_remove_dir): use EACCESS to determine if directory
+ nonempty. We ain't got ENOTEMPTY in OS/2.
+ (that_swing): removed references. We ain't got that_swing in
+ OS/2.
+ (rename_file): just use unlink_file(); move to after definition of
+ unlink_file() so we don't have to deal with IBM C/C++'s strange
+ prototyping rituals.
+ (link_file): removed this function -- no one uses it anymore.
+ It still exists in src/filesubr.c, though.
+ (OS2_filename_classes): new table (well, old table, new name).
+ All references changed.
+
+ * config.h (HAVE_SYS_UTIME_H): define to 1.
+
+ * options.h: undef SETXID_SUPPORT, to correspond with Norbert
+ Kiesel's recent change to ../src/options.h.in, etc.
+
+Mon Nov 6 16:29:00 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * test-makefile (CFLAGS): -DHAVE_CONFIG_H -- this turns out to be
+ important for stuff in lib/.
+ Other trivial changes.
+
+ * config.h (HAVE_DIRENT_H): define to 1, now that we have our own
+ dirent.h and dirent.c.
+
+ * Makefile.in (OS2_SOURCES): added filesubr.c; this may not be
+ permanent.
+
+Sun Nov 5 16:17:33 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (OS2_HEADERS, OS2_SOURCES): added dirent.h and
+ dirent.c, respectively.
+
+ * dirent.c, dirent.h: new files.
+
+Sat Oct 28 14:41:38 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (DISTFILES): include `test-makefile'.
+
+ * test-makefile: new file; to be removed when the port is done.
+
+Fri Oct 27 13:03:28 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (OS2_HEADERS, OS2_SOURCES): adjust as necessary for
+ below changes.
+
+ * config.h: oops, don't forget second argument, MODE.
+
+ * mkdir.c (os2_mkdir): new file, new function.
+ Can probably be merged with wnt_mkdir at some point.
+
+ * config.h (ALLOCA_IN_STDLIB): new #define.
+
+ * pwd.h, pwd.c: new files (for now, copied from ../windows-NT
+ directory. We'll modify/merge them as necessary.)
+
+ * config.h: don't use __stdcall in declaration of gethostname().
+
+ * Makefile.in (DISTFILES): include config.h and options.h.
+
+Wed Oct 25 12:52:54 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * config.h: new file; will maintain by hand.
+ Made first pass through to cast it into OS/2-ish condition.
+
+ * Makefile.in: started adding lots of OS/2 gunk.
+ Took out autoconf stuff; just don't want to fool around with that
+ until after it compiles on beezley.
+ (cvs.exe): moved this rule to bottom.
+
+Tue Oct 24 13:51:05 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in: add autoconf variables
+
+ * Makefile.in (dist): use $(srcdir)
+
+Mon Oct 23 17:37:36 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (clean): new rule.
+
+ * init os2 directory. Made dummy Makefile.in, README.
diff --git a/os2/Makefile b/os2/Makefile
new file mode 100644
index 0000000..4288067
--- /dev/null
+++ b/os2/Makefile
@@ -0,0 +1,357 @@
+# Makefile for OS/2. Generated from Makefile.in when CVS is
+# configured for a dist-build. Configure never gets run on OS/2, so
+# we must include the generated Makefile in the distribution. See the
+# `dist-dir' rule.
+
+project: cvs.exe
+# .SUFFIXES .c .obj .exe
+
+# path slash. This was introduced so that it can be set to \
+# instead of / for linking, but now that the cvs.exe rule uses
+# subst to produce \, it should be possible to nuke SL.
+# FIXME - nuke SL
+SL = /
+
+# Directory in which to install executables.
+install_dir = s:${SL}gnu${SL}util
+
+# srcdir is usually "."
+srcdir = .
+
+# top_srcdir is usually ".."
+top_srcdir = ..
+
+
+subdir = os2
+
+lib_dir = ..${SL}lib
+cvs_srcdir = ..${SL}src
+
+zlib_dir = ${top_srcdir}/zlib
+
+# Do we need these?
+# prefix = /usr/local
+# exec_prefix = ${prefix}
+
+# taken straight from the example project
+LIB = s:${SL}ibmcpp${SL}lib;s:${SL}toolkt21${SL}os2lib;
+CINC = -Is:${SL}ibmcpp${SL}include -Is:${SL}toolkt21${SL}c${SL}os2h
+# This says we are building an object file, not a full executable.
+OBJ_CFLAGS = -C+
+CFLAGS = -W3 -Wrea+tru+ -Ti+ -Ss+ -Gd- -Gm+ -G4 -Q+ -Sm ${CINC} \
+ -I${srcdir} -I${lib_dir} -I${cvs_srcdir} -I${zlib_dir} \
+ -DIBM_CPP -DHAVE_CONFIG_H \
+ -DTCPIP_IBM -Is:${SL}ibmtcpip${SL}include
+
+# needed to make command-line wildcard expansion work right. That's
+# right, DOS-descendants handle this from the program, not the shell.
+ARGVLIB = s:${SL}ibmcpp${SL}lib${SL}setargv.obj
+
+# TCP/IP stuff
+TCPIPLIB = s:${SL}ibmtcpip${SL}lib${SL}tcp32dll.lib s:${SL}ibmtcpip${SL}lib${SL}so32dll.lib
+
+
+# headers specific to OS/2
+
+# We list OS2_HEADERS so we know what to include when we make dist-dir
+# here.
+OS2_HEADERS = \
+ tcpip.h \
+ config.h \
+ pwd.h \
+ dirent.h \
+ rcmd.h \
+ popen.h
+
+# headers we use from the common src dir, ..${SL}src
+COMMON_HEADERS = \
+ ${cvs_srcdir}${SL}client.h \
+ ${cvs_srcdir}${SL}cvs.h \
+ ${cvs_srcdir}${SL}rcs.h \
+ ${cvs_srcdir}${SL}hash.h \
+ ${cvs_srcdir}${SL}myndbm.h \
+ ${cvs_srcdir}${SL}patchlevel.h \
+ ${cvs_srcdir}${SL}update.h \
+ ${cvs_srcdir}${SL}server.h \
+ ${cvs_srcdir}${SL}error.h
+
+# sources specific to OS/2
+OS2_SOURCES = \
+ mkdir.c \
+ pwd.c \
+ filesubr.c \
+ dirent.c \
+ run.c \
+ rcmd.c \
+ waitpid.c \
+ popen.c \
+ porttcp.c \
+ getpass.c
+
+# sources we use from the common src dir, ..${SL}src
+# FIXME: Is this used anywhere? I don't think it is.
+COMMON_SOURCES = \
+ ${cvs_srcdir}${SL}add.c \
+ ${cvs_srcdir}${SL}admin.c \
+ ${cvs_srcdir}${SL}buffer.c \
+ ${cvs_srcdir}${SL}checkin.c \
+ ${cvs_srcdir}${SL}checkout.c \
+ ${cvs_srcdir}${SL}classify.c \
+ ${cvs_srcdir}${SL}client.c \
+ ${cvs_srcdir}${SL}commit.c \
+ ${cvs_srcdir}${SL}create_adm.c \
+ ${cvs_srcdir}${SL}cvsrc.c \
+ ${cvs_srcdir}${SL}diff.c \
+ ${cvs_srcdir}${SL}edit.c \
+ ${cvs_srcdir}${SL}entries.c \
+ ${cvs_srcdir}${SL}error.c \
+ ${cvs_srcdir}${SL}expand_path.c \
+ ${cvs_srcdir}${SL}fileattr.c \
+ ${cvs_srcdir}${SL}find_names.c \
+ ${cvs_srcdir}${SL}hash.c \
+ ${cvs_srcdir}${SL}history.c \
+ ${cvs_srcdir}${SL}ignore.c \
+ ${cvs_srcdir}${SL}import.c \
+ ${cvs_srcdir}${SL}lock.c \
+ ${cvs_srcdir}${SL}log.c \
+ ${cvs_srcdir}${SL}login.c \
+ ${cvs_srcdir}${SL}logmsg.c \
+ ${cvs_srcdir}${SL}main.c \
+ ${cvs_srcdir}${SL}mkmodules.c \
+ ${cvs_srcdir}${SL}modules.c \
+ ${cvs_srcdir}${SL}myndbm.c \
+ ${cvs_srcdir}${SL}no_diff.c \
+ ${cvs_srcdir}${SL}parseinfo.c \
+ ${cvs_srcdir}${SL}patch.c \
+ ${cvs_srcdir}${SL}rcs.c \
+ ${cvs_srcdir}${SL}rcscmds.c \
+ ${cvs_srcdir}${SL}recurse.c \
+ ${cvs_srcdir}${SL}release.c \
+ ${cvs_srcdir}${SL}remove.c \
+ ${cvs_srcdir}${SL}repos.c \
+ ${cvs_srcdir}${SL}root.c \
+ ${cvs_srcdir}${SL}scramble.c \
+ ${cvs_srcdir}${SL}server.c \
+ ${cvs_srcdir}${SL}status.c \
+ ${cvs_srcdir}${SL}subr.c \
+ ${cvs_srcdir}${SL}tag.c \
+ ${cvs_srcdir}${SL}update.c \
+ ${cvs_srcdir}${SL}watch.c \
+ ${cvs_srcdir}${SL}wrapper.c \
+ ${cvs_srcdir}${SL}vers_ts.c \
+ ${cvs_srcdir}${SL}version.c
+# end of $COMMON_SOURCES
+
+# sources from ..${SL}lib
+# FIXME: Is this used anywhere? I don't think it is.
+LIB_SOURCES = \
+ ${lib_dir}${SL}getdate.c \
+ ${lib_dir}${SL}getopt.c \
+ ${lib_dir}${SL}getopt1.c \
+ ${lib_dir}${SL}getline.c \
+ ${lib_dir}${SL}getwd.c \
+ ${lib_dir}${SL}savecwd.c \
+ ${lib_dir}${SL}sighandle.c \
+ ${lib_dir}${SL}yesno.c \
+ ${lib_dir}${SL}vasprintf.c \
+ ${lib_dir}${SL}xgetwd.c \
+ ${lib_dir}${SL}md5.c \
+ ${lib_dir}${SL}fnmatch.c \
+ ${lib_dir}${SL}regex.c
+
+# object files from OS/2 sources
+OS2_OBJECTS = \
+ ${srcdir}${SL}mkdir.obj \
+ ${srcdir}${SL}pwd.obj \
+ ${srcdir}${SL}filesubr.obj \
+ ${srcdir}${SL}dirent.obj \
+ ${srcdir}${SL}run.obj \
+ ${srcdir}${SL}rcmd.obj \
+ ${srcdir}${SL}waitpid.obj \
+ ${srcdir}${SL}popen.obj \
+ ${srcdir}${SL}porttcp.obj \
+ ${srcdir}${SL}getpass.obj
+
+# object files from ..${SL}src
+COMMON_OBJECTS = \
+ ${cvs_srcdir}${SL}add.obj \
+ ${cvs_srcdir}${SL}admin.obj \
+ ${cvs_srcdir}${SL}buffer.obj \
+ ${cvs_srcdir}${SL}checkin.obj \
+ ${cvs_srcdir}${SL}checkout.obj \
+ ${cvs_srcdir}${SL}classify.obj \
+ ${cvs_srcdir}${SL}client.obj \
+ ${cvs_srcdir}${SL}commit.obj \
+ ${cvs_srcdir}${SL}create_adm.obj \
+ ${cvs_srcdir}${SL}cvsrc.obj \
+ ${cvs_srcdir}${SL}diff.obj \
+ ${cvs_srcdir}${SL}edit.obj \
+ ${cvs_srcdir}${SL}entries.obj \
+ ${cvs_srcdir}${SL}error.obj \
+ ${cvs_srcdir}${SL}expand_path.obj \
+ ${cvs_srcdir}${SL}fileattr.obj \
+ ${cvs_srcdir}${SL}find_names.obj \
+ ${cvs_srcdir}${SL}hash.obj \
+ ${cvs_srcdir}${SL}history.obj \
+ ${cvs_srcdir}${SL}ignore.obj \
+ ${cvs_srcdir}${SL}import.obj \
+ ${cvs_srcdir}${SL}lock.obj \
+ ${cvs_srcdir}${SL}log.obj \
+ ${cvs_srcdir}${SL}login.obj \
+ ${cvs_srcdir}${SL}logmsg.obj \
+ ${cvs_srcdir}${SL}main.obj \
+ ${cvs_srcdir}${SL}mkmodules.obj \
+ ${cvs_srcdir}${SL}modules.obj \
+ ${cvs_srcdir}${SL}myndbm.obj \
+ ${cvs_srcdir}${SL}no_diff.obj \
+ ${cvs_srcdir}${SL}parseinfo.obj \
+ ${cvs_srcdir}${SL}patch.obj \
+ ${cvs_srcdir}${SL}rcs.obj \
+ ${cvs_srcdir}${SL}rcscmds.obj \
+ ${cvs_srcdir}${SL}recurse.obj \
+ ${cvs_srcdir}${SL}release.obj \
+ ${cvs_srcdir}${SL}remove.obj \
+ ${cvs_srcdir}${SL}repos.obj \
+ ${cvs_srcdir}${SL}root.obj \
+ ${cvs_srcdir}${SL}scramble.obj \
+ ${cvs_srcdir}${SL}server.obj \
+ ${cvs_srcdir}${SL}status.obj \
+ ${cvs_srcdir}${SL}subr.obj \
+ ${cvs_srcdir}${SL}tag.obj \
+ ${cvs_srcdir}${SL}update.obj \
+ ${cvs_srcdir}${SL}watch.obj \
+ ${cvs_srcdir}${SL}wrapper.obj \
+ ${cvs_srcdir}${SL}vers_ts.obj \
+ ${cvs_srcdir}${SL}version.obj \
+ ${cvs_srcdir}/zlib.obj
+# end of $COMMON_OBJECTS
+
+# objects from ..${SL}lib
+LIB_OBJECTS = \
+ ${lib_dir}${SL}getdate.obj \
+ ${lib_dir}${SL}getopt.obj \
+ ${lib_dir}${SL}getopt1.obj \
+ ${lib_dir}${SL}getline.obj \
+ ${lib_dir}${SL}getwd.obj \
+ ${lib_dir}${SL}savecwd.obj \
+ ${lib_dir}${SL}sighandle.obj \
+ ${lib_dir}${SL}yesno.obj \
+ ${lib_dir}${SL}vasprintf.obj \
+ ${lib_dir}${SL}xgetwd.obj \
+ ${lib_dir}${SL}md5.obj \
+ ${lib_dir}${SL}fnmatch.obj \
+ ${lib_dir}${SL}regex.obj \
+ ${lib_dir}/valloc.obj
+
+ZLIB_OBJECTS = ${zlib_dir}/adler32.obj \
+ ${zlib_dir}/compress.obj \
+ ${zlib_dir}/crc32.obj \
+ ${zlib_dir}/uncompr.obj \
+ ${zlib_dir}/deflate.obj \
+ ${zlib_dir}/trees.obj \
+ ${zlib_dir}/zutil.obj \
+ ${zlib_dir}/inflate.obj \
+ ${zlib_dir}/infblock.obj \
+ ${zlib_dir}/inftrees.obj \
+ ${zlib_dir}/infcodes.obj \
+ ${zlib_dir}/infutil.obj \
+ ${zlib_dir}/inffast.obj
+
+SOURCES = ${COMMON_SOURCES} ${LIB_SOURCES} ${OS2_SOURCES}
+HEADERS = ${COMMON_HEADERS} ${OS2_HEADERS}
+OBJECTS = ${COMMON_OBJECTS} ${LIB_OBJECTS} ${OS2_OBJECTS} ${ZLIB_OBJECTS}
+
+DISTFILES = ${OS2_HEADERS} ${OS2_SOURCES} \
+ README ChangeLog \
+ Makefile.in .cvsignore \
+ test-makefile Makefile os2inc.h \
+ watcom.mak
+
+all:
+
+.PHONY: all install uninstall
+all install uninstall:
+
+# Remove targets for Automake
+dvi info pdf ps:
+.PHONY: dvi info pdf ps
+check installcheck:
+.PHONY: check installcheck
+installdirs:
+lint:
+tags TAGS:
+.PHONY: installdirs lint tags TAGS
+
+# distdir added for compatibility with CVS automake.
+top_distdir = ..
+PACKAGE = cvs
+VERSION = 1.12.13
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+.PHONY: distdir
+
+# We don't have a real distclean or anything like that, but at least
+# we can get rid of the obj files and cvs.exe.
+.PHONY: clean distclean realclean mostlyclean maintainer-clean
+clean distclean realclean maintainer-clean mostlyclean:
+ rm -f cvs.exe
+ rm -f ${srcdir}${SL}*.obj
+ rm -f ${lib_dir}${SL}*.obj
+ rm -f ${cvs_srcdir}${SL}*.obj
+
+install-cvs: cvs.exe
+ cp ${srcdir}${SL}cvs.exe ${install_dir}${SL}cvs.exe
+
+%.obj: %.c
+ icc ${OBJ_CFLAGS} ${CFLAGS} /Fo$@ $*.c
+
+# There seems to be no ICC option for specifying library locations, so
+# we must `set' the path in the compilation environment. Urgkle.
+#
+# I'm having some weird problem with "\" vs. "/". If I build
+# with "\" as the path separator in the makefile, the compiler dumps
+# core. Go figure. If I build with "/" as the path separator, the
+# object files compile fine but the linker thinks the "/" is indicating
+# options and gets all confused (though at least it doesn't dump core).
+# So, use subst to compile with "/" and link with "\".
+cvs.exe: ${OBJECTS}
+ echo Creating icc.in...
+ echo -Q+ -Ti+ -Fe$@ -B"/batch" -B"/NOE" > icc.in
+ echo $(subst /,\,$(OS2_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(LIB_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(COMMON_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(ZLIB_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(TCPIPLIB)) >> icc.in
+ echo $(subst /,\,$(ARGVLIB)) >> icc.in
+ echo Creating icc.in... done.
+ set LIB=$(subst /,\,$(LIB)) & icc @icc.in
+
+# cvs.obj: ${OBJECTS} ${SOURCES} ${HEADERS}
+
+# Hmm. This rule wants to exist on unix, so that "make dist" works.
+# And it doesn't want to exist on OS/2, because configure doesn't
+# run on OS/2 and so ../config.status won't exist. For now we just
+# say, in emx/README, that people will need to comment it out.
+Makefile: ../config.status $(srcdir)/Makefile.in
+ cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
diff --git a/os2/Makefile.in b/os2/Makefile.in
new file mode 100644
index 0000000..4f2278b
--- /dev/null
+++ b/os2/Makefile.in
@@ -0,0 +1,357 @@
+# Makefile for OS/2. Generated from Makefile.in when CVS is
+# configured for a dist-build. Configure never gets run on OS/2, so
+# we must include the generated Makefile in the distribution. See the
+# `dist-dir' rule.
+
+project: cvs.exe
+# .SUFFIXES .c .obj .exe
+
+# path slash. This was introduced so that it can be set to \
+# instead of / for linking, but now that the cvs.exe rule uses
+# subst to produce \, it should be possible to nuke SL.
+# FIXME - nuke SL
+SL = /
+
+# Directory in which to install executables.
+install_dir = s:${SL}gnu${SL}util
+
+# srcdir is usually "."
+srcdir = @srcdir@
+
+# top_srcdir is usually ".."
+top_srcdir = @top_srcdir@
+
+VPATH = @srcdir@
+subdir = os2
+
+lib_dir = @top_srcdir@${SL}lib
+cvs_srcdir = @top_srcdir@${SL}src
+
+zlib_dir = ${top_srcdir}/zlib
+
+# Do we need these?
+# prefix = /usr/local
+# exec_prefix = ${prefix}
+
+# taken straight from the example project
+LIB = s:${SL}ibmcpp${SL}lib;s:${SL}toolkt21${SL}os2lib;
+CINC = -Is:${SL}ibmcpp${SL}include -Is:${SL}toolkt21${SL}c${SL}os2h
+# This says we are building an object file, not a full executable.
+OBJ_CFLAGS = -C+
+CFLAGS = -W3 -Wrea+tru+ -Ti+ -Ss+ -Gd- -Gm+ -G4 -Q+ -Sm ${CINC} \
+ -I${srcdir} -I${lib_dir} -I${cvs_srcdir} -I${zlib_dir} \
+ -DIBM_CPP -DHAVE_CONFIG_H \
+ -DTCPIP_IBM -Is:${SL}ibmtcpip${SL}include
+
+# needed to make command-line wildcard expansion work right. That's
+# right, DOS-descendants handle this from the program, not the shell.
+ARGVLIB = s:${SL}ibmcpp${SL}lib${SL}setargv.obj
+
+# TCP/IP stuff
+TCPIPLIB = s:${SL}ibmtcpip${SL}lib${SL}tcp32dll.lib s:${SL}ibmtcpip${SL}lib${SL}so32dll.lib
+
+
+# headers specific to OS/2
+
+# We list OS2_HEADERS so we know what to include when we make dist-dir
+# here.
+OS2_HEADERS = \
+ tcpip.h \
+ config.h \
+ pwd.h \
+ dirent.h \
+ rcmd.h \
+ popen.h
+
+# headers we use from the common src dir, ..${SL}src
+COMMON_HEADERS = \
+ ${cvs_srcdir}${SL}client.h \
+ ${cvs_srcdir}${SL}cvs.h \
+ ${cvs_srcdir}${SL}rcs.h \
+ ${cvs_srcdir}${SL}hash.h \
+ ${cvs_srcdir}${SL}myndbm.h \
+ ${cvs_srcdir}${SL}patchlevel.h \
+ ${cvs_srcdir}${SL}update.h \
+ ${cvs_srcdir}${SL}server.h \
+ ${cvs_srcdir}${SL}error.h
+
+# sources specific to OS/2
+OS2_SOURCES = \
+ mkdir.c \
+ pwd.c \
+ filesubr.c \
+ dirent.c \
+ run.c \
+ rcmd.c \
+ waitpid.c \
+ popen.c \
+ porttcp.c \
+ getpass.c
+
+# sources we use from the common src dir, ..${SL}src
+# FIXME: Is this used anywhere? I don't think it is.
+COMMON_SOURCES = \
+ ${cvs_srcdir}${SL}add.c \
+ ${cvs_srcdir}${SL}admin.c \
+ ${cvs_srcdir}${SL}buffer.c \
+ ${cvs_srcdir}${SL}checkin.c \
+ ${cvs_srcdir}${SL}checkout.c \
+ ${cvs_srcdir}${SL}classify.c \
+ ${cvs_srcdir}${SL}client.c \
+ ${cvs_srcdir}${SL}commit.c \
+ ${cvs_srcdir}${SL}create_adm.c \
+ ${cvs_srcdir}${SL}cvsrc.c \
+ ${cvs_srcdir}${SL}diff.c \
+ ${cvs_srcdir}${SL}edit.c \
+ ${cvs_srcdir}${SL}entries.c \
+ ${cvs_srcdir}${SL}error.c \
+ ${cvs_srcdir}${SL}expand_path.c \
+ ${cvs_srcdir}${SL}fileattr.c \
+ ${cvs_srcdir}${SL}find_names.c \
+ ${cvs_srcdir}${SL}hash.c \
+ ${cvs_srcdir}${SL}history.c \
+ ${cvs_srcdir}${SL}ignore.c \
+ ${cvs_srcdir}${SL}import.c \
+ ${cvs_srcdir}${SL}lock.c \
+ ${cvs_srcdir}${SL}log.c \
+ ${cvs_srcdir}${SL}login.c \
+ ${cvs_srcdir}${SL}logmsg.c \
+ ${cvs_srcdir}${SL}main.c \
+ ${cvs_srcdir}${SL}mkmodules.c \
+ ${cvs_srcdir}${SL}modules.c \
+ ${cvs_srcdir}${SL}myndbm.c \
+ ${cvs_srcdir}${SL}no_diff.c \
+ ${cvs_srcdir}${SL}parseinfo.c \
+ ${cvs_srcdir}${SL}patch.c \
+ ${cvs_srcdir}${SL}rcs.c \
+ ${cvs_srcdir}${SL}rcscmds.c \
+ ${cvs_srcdir}${SL}recurse.c \
+ ${cvs_srcdir}${SL}release.c \
+ ${cvs_srcdir}${SL}remove.c \
+ ${cvs_srcdir}${SL}repos.c \
+ ${cvs_srcdir}${SL}root.c \
+ ${cvs_srcdir}${SL}scramble.c \
+ ${cvs_srcdir}${SL}server.c \
+ ${cvs_srcdir}${SL}status.c \
+ ${cvs_srcdir}${SL}subr.c \
+ ${cvs_srcdir}${SL}tag.c \
+ ${cvs_srcdir}${SL}update.c \
+ ${cvs_srcdir}${SL}watch.c \
+ ${cvs_srcdir}${SL}wrapper.c \
+ ${cvs_srcdir}${SL}vers_ts.c \
+ ${cvs_srcdir}${SL}version.c
+# end of $COMMON_SOURCES
+
+# sources from ..${SL}lib
+# FIXME: Is this used anywhere? I don't think it is.
+LIB_SOURCES = \
+ ${lib_dir}${SL}getdate.c \
+ ${lib_dir}${SL}getopt.c \
+ ${lib_dir}${SL}getopt1.c \
+ ${lib_dir}${SL}getline.c \
+ ${lib_dir}${SL}getwd.c \
+ ${lib_dir}${SL}savecwd.c \
+ ${lib_dir}${SL}sighandle.c \
+ ${lib_dir}${SL}yesno.c \
+ ${lib_dir}${SL}vasprintf.c \
+ ${lib_dir}${SL}xgetwd.c \
+ ${lib_dir}${SL}md5.c \
+ ${lib_dir}${SL}fnmatch.c \
+ ${lib_dir}${SL}regex.c
+
+# object files from OS/2 sources
+OS2_OBJECTS = \
+ ${srcdir}${SL}mkdir.obj \
+ ${srcdir}${SL}pwd.obj \
+ ${srcdir}${SL}filesubr.obj \
+ ${srcdir}${SL}dirent.obj \
+ ${srcdir}${SL}run.obj \
+ ${srcdir}${SL}rcmd.obj \
+ ${srcdir}${SL}waitpid.obj \
+ ${srcdir}${SL}popen.obj \
+ ${srcdir}${SL}porttcp.obj \
+ ${srcdir}${SL}getpass.obj
+
+# object files from ..${SL}src
+COMMON_OBJECTS = \
+ ${cvs_srcdir}${SL}add.obj \
+ ${cvs_srcdir}${SL}admin.obj \
+ ${cvs_srcdir}${SL}buffer.obj \
+ ${cvs_srcdir}${SL}checkin.obj \
+ ${cvs_srcdir}${SL}checkout.obj \
+ ${cvs_srcdir}${SL}classify.obj \
+ ${cvs_srcdir}${SL}client.obj \
+ ${cvs_srcdir}${SL}commit.obj \
+ ${cvs_srcdir}${SL}create_adm.obj \
+ ${cvs_srcdir}${SL}cvsrc.obj \
+ ${cvs_srcdir}${SL}diff.obj \
+ ${cvs_srcdir}${SL}edit.obj \
+ ${cvs_srcdir}${SL}entries.obj \
+ ${cvs_srcdir}${SL}error.obj \
+ ${cvs_srcdir}${SL}expand_path.obj \
+ ${cvs_srcdir}${SL}fileattr.obj \
+ ${cvs_srcdir}${SL}find_names.obj \
+ ${cvs_srcdir}${SL}hash.obj \
+ ${cvs_srcdir}${SL}history.obj \
+ ${cvs_srcdir}${SL}ignore.obj \
+ ${cvs_srcdir}${SL}import.obj \
+ ${cvs_srcdir}${SL}lock.obj \
+ ${cvs_srcdir}${SL}log.obj \
+ ${cvs_srcdir}${SL}login.obj \
+ ${cvs_srcdir}${SL}logmsg.obj \
+ ${cvs_srcdir}${SL}main.obj \
+ ${cvs_srcdir}${SL}mkmodules.obj \
+ ${cvs_srcdir}${SL}modules.obj \
+ ${cvs_srcdir}${SL}myndbm.obj \
+ ${cvs_srcdir}${SL}no_diff.obj \
+ ${cvs_srcdir}${SL}parseinfo.obj \
+ ${cvs_srcdir}${SL}patch.obj \
+ ${cvs_srcdir}${SL}rcs.obj \
+ ${cvs_srcdir}${SL}rcscmds.obj \
+ ${cvs_srcdir}${SL}recurse.obj \
+ ${cvs_srcdir}${SL}release.obj \
+ ${cvs_srcdir}${SL}remove.obj \
+ ${cvs_srcdir}${SL}repos.obj \
+ ${cvs_srcdir}${SL}root.obj \
+ ${cvs_srcdir}${SL}scramble.obj \
+ ${cvs_srcdir}${SL}server.obj \
+ ${cvs_srcdir}${SL}status.obj \
+ ${cvs_srcdir}${SL}subr.obj \
+ ${cvs_srcdir}${SL}tag.obj \
+ ${cvs_srcdir}${SL}update.obj \
+ ${cvs_srcdir}${SL}watch.obj \
+ ${cvs_srcdir}${SL}wrapper.obj \
+ ${cvs_srcdir}${SL}vers_ts.obj \
+ ${cvs_srcdir}${SL}version.obj \
+ ${cvs_srcdir}/zlib.obj
+# end of $COMMON_OBJECTS
+
+# objects from ..${SL}lib
+LIB_OBJECTS = \
+ ${lib_dir}${SL}getdate.obj \
+ ${lib_dir}${SL}getopt.obj \
+ ${lib_dir}${SL}getopt1.obj \
+ ${lib_dir}${SL}getline.obj \
+ ${lib_dir}${SL}getwd.obj \
+ ${lib_dir}${SL}savecwd.obj \
+ ${lib_dir}${SL}sighandle.obj \
+ ${lib_dir}${SL}yesno.obj \
+ ${lib_dir}${SL}vasprintf.obj \
+ ${lib_dir}${SL}xgetwd.obj \
+ ${lib_dir}${SL}md5.obj \
+ ${lib_dir}${SL}fnmatch.obj \
+ ${lib_dir}${SL}regex.obj \
+ ${lib_dir}/valloc.obj
+
+ZLIB_OBJECTS = ${zlib_dir}/adler32.obj \
+ ${zlib_dir}/compress.obj \
+ ${zlib_dir}/crc32.obj \
+ ${zlib_dir}/uncompr.obj \
+ ${zlib_dir}/deflate.obj \
+ ${zlib_dir}/trees.obj \
+ ${zlib_dir}/zutil.obj \
+ ${zlib_dir}/inflate.obj \
+ ${zlib_dir}/infblock.obj \
+ ${zlib_dir}/inftrees.obj \
+ ${zlib_dir}/infcodes.obj \
+ ${zlib_dir}/infutil.obj \
+ ${zlib_dir}/inffast.obj
+
+SOURCES = ${COMMON_SOURCES} ${LIB_SOURCES} ${OS2_SOURCES}
+HEADERS = ${COMMON_HEADERS} ${OS2_HEADERS}
+OBJECTS = ${COMMON_OBJECTS} ${LIB_OBJECTS} ${OS2_OBJECTS} ${ZLIB_OBJECTS}
+
+DISTFILES = ${OS2_HEADERS} ${OS2_SOURCES} \
+ README ChangeLog \
+ Makefile.in .cvsignore \
+ test-makefile Makefile os2inc.h \
+ watcom.mak
+
+all:
+
+.PHONY: all install uninstall
+all install uninstall:
+
+# Remove targets for Automake
+dvi info pdf ps:
+.PHONY: dvi info pdf ps
+check installcheck:
+.PHONY: check installcheck
+installdirs:
+lint:
+tags TAGS:
+.PHONY: installdirs lint tags TAGS
+
+# distdir added for compatibility with CVS automake.
+top_distdir = ..
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+.PHONY: distdir
+
+# We don't have a real distclean or anything like that, but at least
+# we can get rid of the obj files and cvs.exe.
+.PHONY: clean distclean realclean mostlyclean maintainer-clean
+clean distclean realclean maintainer-clean mostlyclean:
+ rm -f cvs.exe
+ rm -f ${srcdir}${SL}*.obj
+ rm -f ${lib_dir}${SL}*.obj
+ rm -f ${cvs_srcdir}${SL}*.obj
+
+install-cvs: cvs.exe
+ cp ${srcdir}${SL}cvs.exe ${install_dir}${SL}cvs.exe
+
+%.obj: %.c
+ icc ${OBJ_CFLAGS} ${CFLAGS} /Fo$@ $*.c
+
+# There seems to be no ICC option for specifying library locations, so
+# we must `set' the path in the compilation environment. Urgkle.
+#
+# I'm having some weird problem with "\" vs. "/". If I build
+# with "\" as the path separator in the makefile, the compiler dumps
+# core. Go figure. If I build with "/" as the path separator, the
+# object files compile fine but the linker thinks the "/" is indicating
+# options and gets all confused (though at least it doesn't dump core).
+# So, use subst to compile with "/" and link with "\".
+cvs.exe: ${OBJECTS}
+ echo Creating icc.in...
+ echo -Q+ -Ti+ -Fe$@ -B"/batch" -B"/NOE" > icc.in
+ echo $(subst /,\,$(OS2_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(LIB_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(COMMON_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(ZLIB_OBJECTS)) >> icc.in
+ echo $(subst /,\,$(TCPIPLIB)) >> icc.in
+ echo $(subst /,\,$(ARGVLIB)) >> icc.in
+ echo Creating icc.in... done.
+ set LIB=$(subst /,\,$(LIB)) & icc @icc.in
+
+# cvs.obj: ${OBJECTS} ${SOURCES} ${HEADERS}
+
+# Hmm. This rule wants to exist on unix, so that "make dist" works.
+# And it doesn't want to exist on OS/2, because configure doesn't
+# run on OS/2 and so ../config.status won't exist. For now we just
+# say, in emx/README, that people will need to comment it out.
+Makefile: ../config.status $(srcdir)/Makefile.in
+ cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
diff --git a/os2/README b/os2/README
new file mode 100644
index 0000000..c7d6906
--- /dev/null
+++ b/os2/README
@@ -0,0 +1,50 @@
+ This port requires IBM C/C++ and the IBM TCPIP library. It
+has probably only been tested with the CVS client. Local CVS might or
+might not work, and the server would definitely not work. You'll need
+to edit the makefile to reflect your system's paths (unless you're our
+customer for this port, in which case the paths are correct because we
+did the port on your machine. :-) ). You also may need to comment out
+the "Makefile" rule in emx/Makefile to avoid a complaint about
+../config.status not existing. You also might need to edit srcdir to
+be "." and top_srcdir to be "..".
+
+ That should be all -- edit the makefile, do "make" and get
+os2\cvs.exe. Assuming you have edited the `install_dir' variable in
+the Makefile, you may type "make install-cvs" to put cvs.exe in the
+right place.
+
+ If the makefile has linefeeds only at the end of lines, make
+(at least the port of GNU make that I have) will interpret it
+differently. This is (IMHO) a bizarre behavior, but you need to
+convert the linefeeds to CRLF pairs (editing the file with an editor
+such as emacs will generally do this).
+
+ There are two compiler warnings in os2/popen.c which we haven't
+figured out the cause of. Other than that there probably aren't a whole
+lot of warnings (but there might be a few).
+Report bugs to <bug-cvs@nongnu.org>.
+
+
+
+Some notes on the watcom port:
+------------------------------
+
+You need the OS/2 TCPIP developers toolkit to translate the sources.
+This is not as bad as it sounds, since the toolkit is on your OS/2
+CD.
+
+To compile the sources, enter
+
+ wmake -f watcom.mak
+
+at the OS/2 prompt.
+
+The executable created by the watcom compiler does *not* need a runtime
+DLL.
+
+
+ Uz (uz@musoftware.com)
+
+Credits:
+
+Original port in 1995 by Karl Fogel <kfogel@cyclic.com>.
diff --git a/os2/config.h b/os2/config.h
new file mode 100644
index 0000000..f5b5cfe
--- /dev/null
+++ b/os2/config.h
@@ -0,0 +1,514 @@
+/* config.h --- configuration file for OS/2
+ Karl Fogel <kfogel@cyclic.com> --- Oct 1995 */
+
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This file lives in the os2/ subdirectory, which is only included
+ * in your header search path if you're working under IBM C++,
+ * and use os2/makefile (with GNU make for OS/2). Thus, this is the
+ * right place to put configuration information for OS/2.
+ */
+
+
+/* We need some system header files here since we evaluate values from
+ * these files below.
+ */
+#include <stdio.h>
+#include <errno.h>
+
+
+
+#ifndef __STDC__
+/* You bet! */
+#define __STDC__ 1
+#endif
+
+/* The IBM compiler uses the (non-standard) error code EACCESS instead of
+ EACCES (note: one 'S'). Define EACCESS to be EACCES and use the standard
+ name in the code. */
+#ifndef EACCES
+#define EACCES EACCESS
+#endif
+
+/* Handle some other name differences between the IBM and the Watcom
+ * compiler.
+ */
+#ifdef __WATCOMC__
+#define _setmode setmode
+#define _cwait cwait
+#endif
+
+/* Some more WATCOM stuff: The watcom compiler defines va_list as an array,
+ * not as a pointer, which will make the vasprintf code break without the
+ * following define:
+ */
+#ifdef __WATCOMC__
+#define VA_LIST_IS_ARRAY
+#endif
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#undef _ALL_SOURCE
+
+/* Define to empty if the keyword does not work. */
+/* Const is working. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* OS/2 doesn't have gid_t. It doesn't even really have group
+ numbers, I think. This will take more thought to get right, but
+ let's get it running first. */
+#define gid_t int
+
+/* Define if you support file names longer than 14 characters. */
+/* We support long file names, but not long corporate acronyms. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* If POSIX.1 requires this, why doesn't WNT have it? */
+/* Maybe POSIX only says that if it is present, it must behave a
+ certain way, but that it can simply be not present too. I
+ dunno. */
+/* Anyway, OS/2 ain't got it. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if utime(file, NULL) sets file's timestamp to the present. */
+/* Documentation says yup; haven't verified experimentally. */
+#define HAVE_UTIME_NULL 1
+
+/* Define if on MINIX. */
+/* Hah. */
+#undef _MINIX
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#define mode_t int
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#define pid_t int
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* This string doesn't appear anywhere in the system header files,
+ so I assume it's irrelevant. */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work. */
+/* Same as for _POSIX_1_SOURCE, above. */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void). */
+/* IBMCPP manual indicates they are void. */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* sys/types.h doesn't define it, but stdio.h does, which cvs.h
+ #includes, so things should be okay. */
+/* #undef size_t */
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* sys/stat.h apparently doesn't even have them; setting this will let
+ ../lib/system.h define them. */
+#define STAT_MACROS_BROKEN 1
+
+/* Define if you have the ANSI C header files. */
+/* We have at least a reasonable facsimile thereof. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+/* We don't have <sys/time.h> at all. Why isn't there a definition
+ for HAVE_SYS_TIME_H anywhere in config.h.in? */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#define uid_t int
+
+/* Define if you have MIT Kerberos version 4 available. */
+/* We don't. */
+#undef HAVE_KERBEROS
+
+/* Define if you want CVS to be able to be a remote repository client. */
+/* That's all we want. */
+#define CLIENT_SUPPORT
+
+/* Define if you want CVS to be able to serve repositories to remote
+ clients. */
+/* No server support yet. Note that you don't have to define
+ CLIENT_SUPPORT or SERVER_SUPPORT to enable the non-remote code;
+ that's always there. */
+#undef SERVER_SUPPORT
+
+/* Define if you have the connect function. */
+/* Not used? */
+/* It appears to be used in client.c now... don't know yet it OS/2 has it. */
+#define HAVE_CONNECT
+
+/* Define if you have the fchdir function. */
+#undef HAVE_FCHDIR
+
+/* Define if you have the fchmod function. */
+#undef HAVE_FCHMOD
+
+/* Define if you have the fsync function. */
+#undef HAVE_FSYNC
+
+/* Define if you have the ftime function. */
+#define HAVE_FTIME 1
+
+/* Define if you have the ftruncate function. */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the krb_get_err_text function. */
+#undef HAVE_KRB_GET_ERR_TEXT
+
+/* Define if you have the putenv function. */
+#define HAVE_PUTENV 1
+
+/* Define if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the sigblock function. */
+#undef HAVE_SIGBLOCK
+
+/* Define if you have the sigprocmask function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define if you have the sigsetmask function. */
+#undef HAVE_SIGSETMASK
+
+/* Define if you have the sigvec function. */
+#undef HAVE_SIGVEC
+
+/* Define if you have the timezone function. */
+/* Hmm, I actually rather think it's an extern long
+ variable; that message was mechanically generated
+ by autoconf. And I don't see any actual uses of
+ this function in the code anyway, hmm. */
+#undef HAVE_TIMEZONE
+
+/* Define if you have the tzset function. */
+#define HAVE_TZSET 1
+
+/* Define if you have the vfork function. */
+#undef HAVE_VFORK
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the <direct.h> header file. */
+#define HAVE_DIRECT_H 1
+
+/* Define if you have the <dirent.h> header file. */
+/* We have our own dirent.h and dirent.c. */
+#ifdef __WATCOMC__
+#undef HAVE_DIRENT_H
+#else
+#define HAVE_DIRENT_H 1
+#endif
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <io.h> header file. */
+/* Low-level Unix I/O routines like open, creat, etc. */
+#define HAVE_IO_H 1
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndbm.h> header file. */
+#undef HAVE_NDBM_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define if you have the inet library (-linet). */
+#undef HAVE_LIBINET
+
+/* Define if you have the nsl library (-lnsl). */
+/* This is not used anywhere in the source code. */
+#undef HAVE_LIBNSL
+
+/* Define if you have the nsl_s library (-lnsl_s). */
+#undef HAVE_LIBNSL_S
+
+/* Define if you have the socket library (-lsocket). */
+/* This isn't ever used either. */
+#undef HAVE_LIBSOCKET
+
+/* Under OS/2, mkdir only takes one argument. */
+#define CVS_MKDIR os2_mkdir
+extern int os2_mkdir (const char *PATH, int MODE);
+
+/* OS/2 needs a special chdir functions that handles drives */
+#define CVS_CHDIR os2_chdir
+extern int os2_chdir (const char *Dir);
+
+/* This function doesn't exist under OS/2; we provide a stub. */
+extern int readlink (char *path, char *buf, int buf_size);
+
+/* This is just a call to GetCurrentProcessID. */
+#ifndef __WATCOMC__
+extern pid_t getpid (void);
+#endif
+
+/* Under OS/2, filenames are case-insensitive, and both / and \
+ are path component separators. */
+#define FOLD_FN_CHAR(c) (OS2_filename_classes[(unsigned char) (c)])
+extern unsigned char OS2_filename_classes[];
+
+/* Is the character C a path name separator? Under OS/2, you can use
+ either / or \. */
+#define ISDIRSEP(c) (FOLD_FN_CHAR(c) == '/')
+
+/* Like strcmp, but with the appropriate tweaks for file names.
+ Under OS/2, filenames are case-insensitive but case-preserving,
+ and both \ and / are path element separators. */
+extern int fncmp (const char *n1, const char *n2);
+
+/* Fold characters in FILENAME to their canonical forms.
+ If FOLD_FN_CHAR is not #defined, the system provides a default
+ definition for this. */
+extern void fnfold (char *FILENAME);
+
+/* This is where old bits go to die under OS/2 as well as WinNT. */
+#define DEVNULL "nul"
+
+/* Make sure that we don't try to perform operations on RCS files on the
+ local machine. I think I neglected to apply some changes from
+ MHI's port in that area of code, or found some issues I didn't want
+ to deal with. */
+#define CLIENT_ONLY
+
+/* We actually do have a transparent rsh, whew. */
+#undef RSH_NOT_TRANSPARENT
+/* But it won't be transparent unless we ask it nicely! */
+#define RSH_NEEDS_BINARY_FLAG 1
+
+/* OS/2 doesn't really have user/group permissions, at least not
+ according to the C library manual pages. So we'll make decoys.
+ (This was partly introduced for an obsolete reason, now taken care
+ of by CHMOD_BROKEN, but I haven't carefully looked at every case
+ (in particular mode_to_string), so it might still be needed).
+ We do not need that for the watcom compiler since watcom already
+ all those permission bits defined. It would probably be better to
+ include the necessary system header files in system.h, and then make
+ each permission define only if it is not already defined.
+*/
+#ifndef __WATCOMC__
+#define NEED_DECOY_PERMISSIONS 1 /* see system.h */
+#endif
+
+
+
+/* For the access() function, for which IBM OS/2 compiler has no pre-defined
+ mnemonic masks. */
+#ifndef __WATCOMC__
+#define R_OK 04
+#define W_OK 02
+#define F_OK 00
+#define X_OK R_OK /* I think this is right for OS/2. */
+#endif
+
+/* For getpid() */
+#include <process.h>
+
+/* So "tcpip.h" gets included in lib/system.h: */
+#define USE_OWN_TCPIP_H 1
+/* The IBM TCP/IP library gets initialized in main(): */
+#define SYSTEM_INITIALIZE(pargc,pargv) init_sockets()
+extern void init_sockets();
+
+/* Under OS/2, we have our own popen() and pclose()... */
+#define USE_OWN_POPEN 1
+/* ... and we use popenRW to start the rsh server. */
+#define START_RSH_WITH_POPEN_RW 1
+
+/*
+ * This tells the client that it must use send()/recv() to talk to the
+ * server if it is connected to the server via a socket. Sigh.
+ * Windows 95 and VMS cannot convert sockets to file descriptors either,
+ * apparently.
+ */
+#define NO_SOCKET_TO_FD 1
+
+/* chmod() doesn't seem to work -- IBM's own example program does not
+ * behave as its documentation claims, in fact! I suspect that
+ * DosSetPathInfo is the way to go, but can't seem to make that work
+ * either. For now, we can deal with some cases by invoking the DOS
+ * "attrib" command via system(). */
+#define CHMOD_BROKEN 1
+
+/* Rule Number 1 of OS/2 Programming: If the function you're looking
+ for doesn't exist, try putting "Dos" in front of it.
+ Do not forget to include the os2 header file if we use DosSleep. */
+#ifndef sleep
+#include "os2inc.h"
+#define sleep(x) DosSleep(((long)(x))*1000L)
+#endif /* sleep */
+
+/* Set to 1 for some debugging messages. */
+#if 0
+#define KFF_DEBUG(call) printf("*** %s:%d: ", __FILE__, __LINE__); \
+ call; fflush(stdout);
+#else
+#define KFF_DEBUG(call)
+#endif
+
+/*
+ * The following configuration options used to be defined in options.h.
+ */
+
+/*
+ * When committing a permanent change, CVS and RCS make a log entry of
+ * who committed the change. If you are committing the change logged in
+ * as "root" (not under "su" or other root-priv giving program), CVS/RCS
+ * cannot determine who is actually making the change.
+ *
+ * As such, by default, CVS disallows changes to be committed by users
+ * logged in as "root". You can disable this option by commenting
+ * out the lines below.
+ *
+ * Under Windows NT, privileges are associated with groups, not users,
+ * so the case in which someone has logged in as root does not occur.
+ * Thus, there is no need for this hack.
+ *
+ * todo: I don't know about OS/2 yet. -kff
+ */
+#undef CVS_BADROOT
+
+/* This prototype is unique to OS2 */
+#ifdef AUTH_CLIENT_SUPPORT
+char *getpass (char *passbuf);
+#endif /* AUTH_CLIENT_SUPPORT */
+
+/*
+ * For portability and heterogeneity reasons, CVS is shipped by default using
+ * my own text-file version of the ndbm database library in the src/myndbm.c
+ * file. If you want better performance and are not concerned about
+ * heterogeneous hosts accessing your modules file, turn this option off.
+ */
+#ifndef MY_NDBM
+#define MY_NDBM
+#endif
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little
+ need to change this (-T is a better mechanism if you need to use a
+ different directory for temporary files). */
+#ifndef TMPDIR_DFLT
+#define TMPDIR_DFLT "c:\\temp"
+#endif
+
+/*
+ * The default editor to use, if one does not specify the "-e" option to cvs,
+ * or does not have an EDITOR environment variable. I set this to just "vi",
+ * and use the shell to find where "vi" actually is. This allows sites with
+ * /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that your PATH
+ * is reasonable).
+ *
+ * The notepad program seems to be Windows NT's bare-bones text editor.
+ */
+#ifndef EDITOR_DFLT
+#define EDITOR_DFLT "notepad"
+#endif
+
+/*
+ * The default umask to use when creating or otherwise setting file or
+ * directory permissions in the repository. Must be a value in the
+ * range of 0 through 0777. For example, a value of 002 allows group
+ * rwx access and world rx access; a value of 007 allows group rwx
+ * access but no world access. This value is overridden by the value
+ * of the CVSUMASK environment variable, which is interpreted as an
+ * octal number.
+ */
+#ifndef UMASK_DFLT
+#define UMASK_DFLT 002
+#endif
+
+/*
+ * The cvs admin command is restricted to the members of the group
+ * CVS_ADMIN_GROUP. If this group does not exist, all users are
+ * allowed to run cvs admin. To disable the cvs admin for all users,
+ * create an empty group CVS_ADMIN_GROUP. To disable access control for
+ * cvs admin, comment out the define below.
+ *
+ * Under Windows NT and OS/2, this must not be used because it tries
+ * to include <grp.h>.
+ */
+#ifdef CVS_ADMIN_GROUP
+/* #define CVS_ADMIN_GROUP "cvsadmin" */
+#endif
+
+/*
+ * When committing or importing files, you must enter a log message.
+ * Normally, you can do this either via the -m flag on the command line or an
+ * editor will be started for you. If you like to use logging templates (the
+ * rcsinfo file within the $CVSROOT/CVSROOT directory), you might want to
+ * force people to use the editor even if they specify a message with -m.
+ * Enabling FORCE_USE_EDITOR will cause the -m message to be appended to the
+ * temp file when the editor is started.
+ */
+#ifndef FORCE_USE_EDITOR
+/* #define FORCE_USE_EDITOR */
+#endif
+
+/*
+ * Under OS/2, we build the authenticated client by default.
+ */
+#define AUTH_CLIENT_SUPPORT 1
+
+/* End of CVS options.h section */
+
+/* FIXME: This is the same definition used for WOE32 in lib/system.h. It
+ * should be consolidated.
+ */
+#define ISABSOLUTE(s) (ISDIRSEP(s[0]) || FOLD_FN_CHAR(s[0]) >= 'a' && FOLD_FN_CHAR(s[0]) <= 'z' && s[1] == ':' && ISDIRSEP(s[2]))
diff --git a/os2/dirent.c b/os2/dirent.c
new file mode 100644
index 0000000..f835cb5
--- /dev/null
+++ b/os2/dirent.c
@@ -0,0 +1,180 @@
+/*
+ * Author: Bob Withers
+ * Copyright (c) 1993, All Rights Reserved
+ *
+ * NOTICE
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * The author makes no representations about the suitability of this
+ * software for any purpose. This software is provided ``as is''
+ * without express or implied warranty.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include "dirent.h"
+
+
+#define DIRENT_INCR 25
+
+
+DIR *opendir(char *filename)
+{
+ auto size_t len;
+ auto DIR *dirp;
+ auto char *p;
+ auto HDIR hdir;
+
+#ifdef OS2_16
+ auto USHORT rc; /* for 16 bit OS/2 */
+ auto FILEFINDBUF ff;
+ auto USHORT cnt;
+#else
+ auto APIRET rc; /* for 32 bit OS/2 */
+ auto FILEFINDBUF3 ff;
+ auto ULONG cnt;
+#endif /* OS2_16 */
+
+ if (NULL == filename || '\0' == filename[0])
+ filename = ".";
+
+ dirp = xmalloc(sizeof(*dirp));
+ if (NULL == dirp)
+ return(NULL);
+
+ len = strlen(filename);
+ dirp->dirname = xmalloc(len + 5);
+ if (NULL == dirp->dirname)
+ {
+ free(dirp);
+ return(NULL);
+ }
+
+ dirp->max_ent = 0;
+ dirp->tot_ent = 0;
+ dirp->cur_ent = 0;
+ dirp->entp = NULL;
+ strcpy(dirp->dirname, filename);
+ for (p = dirp->dirname; *p; ++p)
+ {
+ if ('/' == *p)
+ *p = '\\';
+ }
+
+ if ('\\' != dirp->dirname[len - 1])
+ strcat(dirp->dirname, "\\");
+
+ strcat(dirp->dirname, "*.*");
+
+ hdir = HDIR_SYSTEM;
+ cnt = 1;
+ rc = DosFindFirst(dirp->dirname, &hdir,
+ FILE_NORMAL | FILE_READONLY | FILE_HIDDEN |
+ FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED,
+ &ff, sizeof(ff), &cnt, FIL_STANDARD);
+
+ while (NO_ERROR == rc)
+ {
+ auto struct dirent *entp;
+
+ if (dirp->tot_ent >= dirp->max_ent)
+ {
+ auto struct dirent **p;
+
+ dirp->max_ent += DIRENT_INCR;
+ p = xrealloc(dirp->entp, dirp->max_ent * sizeof(entp));
+ if (NULL == p)
+ {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ dirp->entp = p;
+ }
+
+ entp = xmalloc(sizeof(*entp) + (size_t) ff.cchName);
+ if (NULL == entp)
+ {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ entp->d_ino = 0;
+ entp->d_off = dirp->tot_ent;
+ entp->d_namlen = (unsigned short) ff.cchName;
+ memcpy(entp->d_name, ff.achName, entp->d_namlen);
+ entp->d_name[entp->d_namlen] = '\0';
+ dirp->entp[dirp->tot_ent++] = entp;
+
+ cnt = 1;
+ rc = DosFindNext(hdir, &ff, sizeof(ff), &cnt);
+ }
+
+ DosFindClose(hdir);
+ if (ERROR_NO_MORE_FILES == rc)
+ return(dirp);
+
+ closedir(dirp);
+ return(NULL);
+}
+
+
+struct dirent *readdir(DIR *dirp)
+{
+ if (dirp->cur_ent < 0 || dirp->cur_ent >= dirp->tot_ent)
+ return(NULL);
+
+ return(dirp->entp[dirp->cur_ent++]);
+}
+
+
+long telldir(DIR *dirp)
+{
+ return((long) dirp->cur_ent);
+}
+
+
+void seekdir(DIR *dirp, long loc)
+{
+ dirp->cur_ent = (int) loc;
+ return;
+}
+
+
+void rewinddir(DIR *dirp)
+{
+ dirp->cur_ent = 0;
+ return;
+}
+
+
+void closedir(DIR *dirp)
+{
+ if (dirp)
+ {
+ if (dirp->dirname)
+ free(dirp->dirname);
+
+ if (dirp->entp)
+ {
+ register int i;
+
+ for (i = 0; i < dirp->tot_ent; ++i)
+ free(dirp->entp[i]);
+
+ free(dirp->entp);
+ }
+ }
+
+ return;
+}
diff --git a/os2/dirent.h b/os2/dirent.h
new file mode 100644
index 0000000..bc218b5
--- /dev/null
+++ b/os2/dirent.h
@@ -0,0 +1,50 @@
+/*
+ * Author: Bob Withers
+ * Copyright (c) 1993, All Rights Reserved
+ *
+ * NOTICE
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * The author makes no representations about the suitability of this
+ * software for any purpose. This software is provided ``as is''
+ * without express or implied warranty.
+ */
+
+#ifndef DIRENT_H
+#define DIRENT_H
+
+/* Unix style directory(3C) support for OS/2 V2.x */
+
+struct dirent
+{
+ long d_ino; /* not used in this implementation */
+ long d_off; /* not used in this implementation */
+ unsigned short d_namlen;
+ char d_name[1];
+};
+
+
+struct S_Dir
+{
+ char *dirname;
+ int max_ent;
+ int tot_ent;
+ int cur_ent;
+ struct dirent **entp;
+};
+typedef struct S_Dir DIR;
+
+
+DIR * opendir(char *filename);
+struct dirent * readdir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp, long loc);
+void rewinddir(DIR *dirp);
+void closedir(DIR *dirp);
+
+#endif /* DIRENT_H */
diff --git a/os2/filesubr.c b/os2/filesubr.c
new file mode 100644
index 0000000..e70f4ec
--- /dev/null
+++ b/os2/filesubr.c
@@ -0,0 +1,946 @@
+/* filesubr.c --- subroutines for dealing with files under OS/2
+ Jim Blandy <jimb@cyclic.com> and Karl Fogel <kfogel@cyclic.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* These functions were moved out of subr.c because they need different
+ definitions under operating systems (like, say, Windows NT) with different
+ file system semantics. */
+
+#include <io.h>
+
+#include "os2inc.h"
+#include "cvs.h"
+
+static int deep_remove_dir( const char *path );
+
+/*
+ * Copies "from" to "to".
+ */
+void
+copy_file (from, to)
+ const char *from;
+ const char *to;
+{
+ struct stat sb;
+ struct utimbuf t;
+ int fdin, fdout;
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open %s for copying", from);
+ if (fstat (fdin, &sb) < 0)
+ error (1, errno, "cannot fstat %s", from);
+ if ((fdout = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
+ (int) sb.st_mode & 07777)) < 0)
+ error (1, errno, "cannot create %s for copying", to);
+ if (sb.st_size > 0)
+ {
+ char buf[BUFSIZ];
+ int n;
+
+ for (;;)
+ {
+ n = read (fdin, buf, sizeof(buf));
+ if (n == -1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ error (1, errno, "cannot read file %s for copying", from);
+ }
+ else if (n == 0)
+ break;
+
+ if (write(fdout, buf, n) != n) {
+ error (1, errno, "cannot write file %s for copying", to);
+ }
+ }
+
+#ifdef HAVE_FSYNC
+ if (fsync (fdout))
+ error (1, errno, "cannot fsync file %s after copying", to);
+#endif
+ }
+
+ if (close (fdin) < 0)
+ error (0, errno, "cannot close %s", from);
+ if (close (fdout) < 0)
+ error (1, errno, "cannot close %s", to);
+
+ /* now, set the times for the copied file to match those of the original */
+ memset ((char *) &t, 0, sizeof (t));
+ t.actime = sb.st_atime;
+ t.modtime = sb.st_mtime;
+ (void) utime ((char *)to, &t);
+}
+
+/* FIXME-krp: these functions would benefit from caching the char * &
+ stat buf. */
+
+/*
+ * Returns non-zero if the argument file is a directory, or is a symbolic
+ * link which points to a directory.
+ */
+int
+isdir (file)
+ const char *file;
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return (0);
+ return (S_ISDIR (sb.st_mode));
+}
+
+/*
+ * Returns non-zero if the argument file is a symbolic link.
+ */
+int
+islink (file)
+ const char *file;
+{
+#ifdef S_ISLNK
+ struct stat sb;
+
+ if (lstat (file, &sb) < 0)
+ return (0);
+ return (S_ISLNK (sb.st_mode));
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Returns non-zero if the argument file exists.
+ */
+int
+isfile (file)
+ const char *file;
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return (0);
+ return (1);
+}
+
+/*
+ * Returns non-zero if the argument file is readable.
+ * XXX - must be careful if "cvs" is ever made setuid!
+ */
+int
+isreadable (file)
+ const char *file;
+{
+ return (access (file, R_OK) != -1);
+}
+
+/*
+ * Returns non-zero if the argument file is writable
+ * XXX - muct be careful if "cvs" is ever made setuid!
+ */
+int
+iswritable (file)
+ const char *file;
+{
+ return (access (file, W_OK) != -1);
+}
+
+/*
+ * Returns non-zero if the argument file is accessable according to
+ * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
+ * bits set.
+ */
+int
+isaccessible (file, mode)
+ const char *file;
+ const int mode;
+{
+ return access(file, mode) == 0;
+}
+
+
+
+/*
+ * Make a directory and die if it fails
+ */
+void
+make_directory (name)
+ const char *name;
+{
+ struct stat buf;
+
+ if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode)))
+ error (0, 0, "%s already exists but is not a directory", name);
+ if (!noexec && mkdir ((char *)name) < 0)
+ error (1, errno, "cannot make directory %s", name);
+}
+
+/*
+ * Make a path to the argument directory, printing a message if something
+ * goes wrong.
+ */
+void
+make_directories (name)
+ const char *name;
+{
+ char *cp;
+
+ if (noexec)
+ return;
+
+ if (mkdir ((char *)name) == 0 || errno == EACCES)
+ return;
+ if (! existence_error (errno))
+ {
+ error (0, errno, "cannot make path to %s", name);
+ return;
+ }
+ if ((cp = strrchr (name, '/')) == NULL)
+ return;
+ *cp = '\0';
+ make_directories (name);
+ *cp++ = '/';
+ if (*cp == '\0')
+ return;
+ (void) mkdir ((char *)name);
+}
+
+/* Create directory NAME if it does not already exist; fatal error for
+ other errors. Returns 0 if directory was created; 1 if it already
+ existed. */
+int
+mkdir_if_needed (name)
+ char *name;
+{
+ if (mkdir (name) < 0)
+ {
+ /* Now, let me get this straight. In IBM C/C++
+ under OS/2, the error string for EEXIST is:
+
+ "The file already exists",
+
+ and the error string for EACCES is:
+
+ "The file or directory specified is read-only".
+
+ Nonetheless, mkdir() will set EACCES if the
+ directory *exists*, according both to the
+ documentation and its actual behavior.
+
+ I'm sure that this made sense, to someone,
+ somewhere, sometime. Just not me, here, now. */
+ if (errno != EEXIST
+#ifdef EACCES
+ && errno != EACCES
+#endif
+ )
+ error (1, errno, "cannot make directory %s", name);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Change the mode of a file, either adding write permissions, or removing
+ * all write permissions. Adding write permissions honors the current umask
+ * setting.
+ */
+void
+xchmod (fname, writable)
+ char *fname;
+ int writable;
+{
+ char *attrib_cmd;
+ char *attrib_option;
+ char *whole_cmd;
+ char *p;
+ char *q;
+
+ if (!isfile (fname))
+ {
+ error (0, 0, "cannot change mode of file %s; it does not exist",
+ fname);
+ return;
+ }
+
+ attrib_cmd = "attrib "; /* No, really? */
+
+ if (writable)
+ attrib_option = "-r "; /* make writeable */
+ else
+ attrib_option = "+r "; /* make read-only */
+
+ whole_cmd = xmalloc (strlen (attrib_cmd)
+ + strlen (attrib_option)
+ + strlen (fname)
+ + 1);
+
+ strcpy (whole_cmd, attrib_cmd);
+ strcat (whole_cmd, attrib_option);
+
+ /* Copy fname to the end of whole_cmd, translating / to \.
+ Attrib doesn't take / but many parts of CVS rely
+ on being able to use it. */
+ p = whole_cmd + strlen (whole_cmd);
+ q = fname;
+ while (*q)
+ {
+ if (*q == '/')
+ *p++ = '\\';
+ else
+ *p++ = *q;
+ ++q;
+ }
+ *p = '\0';
+
+ system (whole_cmd);
+ free (whole_cmd);
+}
+
+
+/* Read the value of a symbolic link.
+ Under OS/2, this function always returns EINVAL. */
+int
+readlink (char *path, char *buf, int buf_size)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+/*
+ * unlink a file, if possible.
+ */
+int
+unlink_file (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ /* Win32 unlink is stupid - it fails if the file is read-only.
+ * OS/2 is similarly stupid. It does have a remove() function,
+ * but the documentation does not make clear why remove() is or
+ * isn't preferable to unlink(). I'll use unlink() because the
+ * name is closer to our interface, what the heck. Also, we know
+ * unlink()'s error code when trying to remove a directory.
+ */
+ if (isfile (f))
+ xchmod ((char *)f, 1);
+ return (unlink (f));
+}
+
+/*
+ * Unlink a file or dir, if possible. If it is a directory do a deep
+ * removal of all of the files in the directory. Return -1 on error
+ * (in which case errno is set).
+ */
+int
+unlink_file_dir (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ if (unlink_file (f) != 0)
+ {
+ /* under OS/2, unlink returns EACCES if the path
+ is a directory. */
+ if (errno == EACCES)
+ return deep_remove_dir (f);
+ else
+ /* The file wasn't a directory and some other
+ * error occured
+ */
+ return -1;
+ }
+ /* We were able to remove the file from the disk */
+ return 0;
+}
+
+/* Remove a directory and everything it contains. Returns 0 for
+ * success, -1 for failure (in which case errno is set).
+ */
+
+static int
+deep_remove_dir (path)
+ const char *path;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char buf[PATH_MAX];
+
+ if (rmdir ((char *)path) != 0 && errno == EACCES)
+ {
+ if ((dirp = opendir ((char *)path)) == NULL)
+ /* If unable to open the directory return
+ * an error
+ */
+ return -1;
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0)
+ continue;
+
+ sprintf (buf, "%s/%s", path, dp->d_name);
+
+ if (unlink_file (buf) != 0 )
+ {
+ if (errno == EACCES)
+ {
+ if (deep_remove_dir (buf))
+ {
+ closedir (dirp);
+ return -1;
+ }
+ }
+ else
+ {
+ /* buf isn't a directory, or there are
+ * some sort of permision problems
+ */
+ closedir (dirp);
+ return -1;
+ }
+ }
+ }
+ closedir (dirp);
+ return rmdir ((char *)path);
+ }
+ /* Was able to remove the directory return 0 */
+ return 0;
+}
+
+
+/*
+ * Rename a file and die if it fails
+ */
+void
+rename_file (from, to)
+ const char *from;
+ const char *to;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ unlink_file (to);
+ if (rename (from, to) != 0)
+ error (1, errno, "cannot rename file %s to %s", from, to);
+}
+
+
+/* Read NCHARS bytes from descriptor FD into BUF.
+ Return the number of characters successfully read.
+ The number returned is always NCHARS unless end-of-file or error. */
+static size_t
+block_read (fd, buf, nchars)
+ int fd;
+ char *buf;
+ size_t nchars;
+{
+ char *bp = buf;
+ size_t nread;
+
+ do
+ {
+ nread = read (fd, bp, nchars);
+ if (nread == (size_t)-1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ return (size_t)-1;
+ }
+
+ if (nread == 0)
+ break;
+
+ bp += nread;
+ nchars -= nread;
+ } while (nchars != 0);
+
+ return bp - buf;
+}
+
+
+/*
+ * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
+ */
+int
+xcmp (file1, file2)
+ const char *file1;
+ const char *file2;
+{
+ char *buf1, *buf2;
+ struct stat sb1, sb2;
+ int fd1, fd2;
+ int ret;
+
+ if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file1);
+ if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file2);
+ if (fstat (fd1, &sb1) < 0)
+ error (1, errno, "cannot fstat %s", file1);
+ if (fstat (fd2, &sb2) < 0)
+ error (1, errno, "cannot fstat %s", file2);
+
+ /* A generic file compare routine might compare st_dev & st_ino here
+ to see if the two files being compared are actually the same file.
+ But that won't happen in CVS, so we won't bother. */
+
+ if (sb1.st_size != sb2.st_size)
+ ret = 1;
+ else if (sb1.st_size == 0)
+ ret = 0;
+ else
+ {
+ /* FIXME: compute the optimal buffer size by computing the least
+ common multiple of the files st_blocks field */
+ size_t buf_size = 8 * 1024;
+ size_t read1;
+ size_t read2;
+
+ buf1 = xmalloc (buf_size);
+ buf2 = xmalloc (buf_size);
+
+ do
+ {
+ read1 = block_read (fd1, buf1, buf_size);
+ if (read1 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file1);
+
+ read2 = block_read (fd2, buf2, buf_size);
+ if (read2 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file2);
+
+ /* assert (read1 == read2); */
+
+ ret = memcmp(buf1, buf2, read1);
+ } while (ret == 0 && read1 == buf_size);
+
+ free (buf1);
+ free (buf2);
+ }
+
+ (void) close (fd1);
+ (void) close (fd2);
+ return (ret);
+}
+
+
+/* The equivalence class mapping for filenames.
+ OS/2 filenames are case-insensitive, but case-preserving. Both /
+ and \ are path element separators.
+ Thus, this table maps both upper and lower case to lower case, and
+ both / and \ to /.
+
+ Much thanks to Jim Blandy, who already invented this wheel in the
+ Windows NT port. */
+
+#if 0
+main ()
+{
+ int c;
+
+ for (c = 0; c < 256; c++)
+ {
+ int t;
+
+ if (c == '\\')
+ t = '/';
+ else
+ t = tolower (c);
+
+ if ((c & 0x7) == 0x0)
+ printf (" ");
+ printf ("0x%02x,", t);
+ if ((c & 0x7) == 0x7)
+ putchar ('\n');
+ else if ((c & 0x7) == 0x3)
+ putchar (' ');
+ }
+}
+#endif
+
+
+unsigned char
+OS2_filename_classes[] =
+{
+ 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
+ 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
+ 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
+ 0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
+ 0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
+ 0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
+ 0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
+ 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
+};
+
+/* Like strcmp, but with the appropriate tweaks for file names.
+ Under OS/2, filenames are case-insensitive but case-preserving, and
+ both \ and / are path element separators. */
+int
+fncmp (const char *n1, const char *n2)
+{
+ while (*n1 && *n2
+ && (OS2_filename_classes[(unsigned char) *n1]
+ == OS2_filename_classes[(unsigned char) *n2]))
+ n1++, n2++;
+ return (OS2_filename_classes[(unsigned char) *n1]
+ - OS2_filename_classes[(unsigned char) *n2]);
+}
+
+/* Fold characters in FILENAME to their canonical forms.
+ If FOLD_FN_CHAR is not #defined, the system provides a default
+ definition for this. */
+void
+fnfold (char *filename)
+{
+ while (*filename)
+ {
+ *filename = FOLD_FN_CHAR (*filename);
+ filename++;
+ }
+}
+
+
+/* Generate a unique temporary filename. Returns a pointer to a newly
+ malloc'd string containing the name. Returns successfully or not at
+ all. */
+char *
+cvs_temp_name ()
+{
+ char value[L_tmpnam + 1];
+ char *retval;
+
+ /* FIXME: Does OS/2 have some equivalent to TMPDIR? */
+ retval = tmpnam (value);
+ if (retval == NULL)
+ error (1, errno, "cannot generate temporary filename");
+ return xstrdup (retval);
+}
+
+
+
+/* char *
+ * xresolvepath ( const char *path )
+ *
+ * Like xreadlink(), but resolve all links in a path.
+ *
+ * INPUTS
+ * path The original path.
+ *
+ * RETURNS
+ * The path with any symbolic links expanded.
+ *
+ * ERRORS
+ * This function exits with a fatal error if it fails to read the link for
+ * any reason.
+ */
+char *
+xresolvepath ( path )
+ const char *path;
+{
+ char *hardpath;
+ char *owd;
+
+ /* assert ( isdir ( path ) ); */
+
+ /* FIXME - If HAVE_READLINK is defined, we should probably walk the path
+ * bit by bit calling xreadlink().
+ */
+
+ owd = xgetwd();
+ if ( CVS_CHDIR ( path ) < 0)
+ error ( 1, errno, "cannot chdir to %s", path );
+ if ( ( hardpath = xgetwd() ) == NULL )
+ error (1, errno, "cannot readlink %s", hardpath);
+ if ( CVS_CHDIR ( owd ) < 0)
+ error ( 1, errno, "cannot chdir to %s", owd );
+ free (owd);
+ return hardpath;
+}
+
+/* Return a pointer into PATH's last component. */
+char *
+last_component (char *path)
+{
+ char *scan;
+ char *last = 0;
+
+ for (scan = path; *scan; scan++)
+ if (ISDIRSEP (*scan))
+ last = scan;
+
+ if (last && (last != path))
+ return last + 1;
+ else
+ return path;
+}
+
+
+/* Return the home directory. Returns a pointer to storage
+ managed by this function or its callees (currently getenv). */
+char *
+get_homedir ()
+{
+ return getenv ("HOME");
+}
+
+/* See cvs.h for description. */
+void
+expand_wild (argc, argv, pargc, pargv)
+ int argc;
+ char **argv;
+ int *pargc;
+ char ***pargv;
+{
+ int i;
+ int new_argc;
+ char **new_argv;
+ /* Allocated size of new_argv. We arrange it so there is always room for
+ one more element. */
+ int max_new_argc;
+
+ new_argc = 0;
+ /* Add one so this is never zero. */
+ max_new_argc = argc + 1;
+ new_argv = (char **) xmalloc (max_new_argc * sizeof (char *));
+ for (i = 0; i < argc; ++i)
+ {
+ HDIR FindHandle = 0x0001;
+ FILEFINDBUF3 FindBuffer;
+ ULONG FindCount = 1;
+ APIRET rc; /* Return code */
+#define ALL_FILES (FILE_ARCHIVED|FILE_DIRECTORY|FILE_SYSTEM|FILE_HIDDEN|FILE_READONLY)
+
+ /* DosFindFirst, called with a string like 'dir/file' will return
+ * *only* the file part. So what we have to do here is to save the
+ * directory part, and add it later to the returned filename.
+ */
+
+ /* Path + name */
+ char *PathName = argv [i];
+
+ /* Path only, including slash */
+ char *Path = NULL;
+
+ /* Name without path */
+ char *Name = last_component (PathName);
+
+ if (Name > PathName)
+ {
+ /* We have a path component, save it */
+ Path = xmalloc (Name - PathName + 1);
+ memcpy (Path, PathName, Name - PathName);
+ Path [Name - PathName] = '\0';
+ }
+
+ rc = DosFindFirst(PathName, /* File pattern */
+ &FindHandle, /* Directory search handle */
+ ALL_FILES, /* Search attribute */
+ (PVOID) &FindBuffer, /* Result buffer */
+ sizeof(FindBuffer), /* Result buffer length */
+ &FindCount, /* Number of entries to find */
+ FIL_STANDARD); /* Return level 1 file info */
+
+ if (rc != 0)
+ {
+ if (rc == ERROR_NO_MORE_FILES)
+ {
+ /* No match. The file specified didn't contain a wildcard (in which case
+ we clearly should return it unchanged), or it contained a wildcard which
+ didn't match (in which case it might be better for it to be an error,
+ but we don't try to do that). */
+ new_argv [new_argc++] = xstrdup (argv[i]);
+ if (new_argc == max_new_argc)
+ {
+ max_new_argc *= 2;
+ new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
+ }
+ }
+ else
+ {
+ error (1, rc, "cannot find %s", PathName);
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ /*
+ * Don't match ".", "..", and files starting with '.'
+ * (unless pattern also starts with '.'). This is
+ * (more or less) what standard Unix globbing does.
+ */
+ if ((strcmp(FindBuffer.achName, ".") != 0) &&
+ (strcmp(FindBuffer.achName, "..") != 0) &&
+ ((argv[i][0] == '.') || (FindBuffer.achName[0] != '.')))
+ {
+ /* Be sure to add the path if needed */
+ char *NewArg;
+ if (Path)
+ {
+ unsigned Len =
+ strlen (Path) + strlen (FindBuffer.achName) + 1;
+ NewArg = xmalloc (Len);
+ strcpy (NewArg, Path);
+ strcat (NewArg, FindBuffer.achName);
+ }
+ else
+ {
+ NewArg = xstrdup (FindBuffer.achName);
+ }
+ new_argv [new_argc++] = NewArg;
+ if (new_argc == max_new_argc)
+ {
+ max_new_argc *= 2;
+ new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
+ }
+ }
+
+ rc = DosFindNext (FindHandle,
+ (PVOID) &FindBuffer,
+ sizeof(FindBuffer),
+ &FindCount);
+ if (rc == ERROR_NO_MORE_FILES)
+ break;
+ else if (rc != NO_ERROR)
+ error (1, rc, "cannot find %s", argv[i]);
+ }
+ rc = DosFindClose(FindHandle);
+ if (rc != 0)
+ error (1, rc, "cannot close %s", argv[i]);
+ }
+ if (Path != NULL)
+ free (Path);
+ }
+ *pargc = new_argc;
+ *pargv = new_argv;
+}
+
+/* Change drive and directory to path DIR. */
+
+int
+os2_chdir (const char *Dir)
+{
+ /* If the path includes a drive, change the current drive to the one
+ given. */
+ if (strlen (Dir) >= 2 && Dir [1] == ':')
+ {
+ /* A drive is given in Dir. Extract the drive from the string, then
+ * remove the drive from Dir by incrementing it.
+ */
+ int Drive = Dir [0];
+ Dir += 2;
+
+ /* Check if the given drive is valid, convert to a drive number
+ * (A: == 1, B: == 2, etc.). The compare below assumes ascii, but
+ * that is not a problem with OS/2.
+ */
+ if (Drive >= 'a' && Drive <= 'z')
+ {
+ Drive -= 'a' - 1;
+ }
+ else if (Drive >= 'A' && Drive <= 'Z')
+ {
+ Drive -= 'A' - 1;
+ }
+ else
+ {
+ /* An invalid drive letter. Set errno and return an error */
+ errno = EACCES;
+ return -1;
+ }
+
+ /* We have a valid drive given, so change the drive now */
+ if (DosSetDefaultDisk (Drive) != 0)
+ {
+ /* We had an error. Assume that the drive does not exist */
+#ifdef ENODEV
+ errno = ENODEV;
+#else
+ /* IBM C/C++ Tools 2.01 seems to lack ENODEV. */
+ errno = ENOENT;
+#endif
+ return -1;
+ }
+
+ }
+
+ /* Now we have a path without a drive left. Make it the current dir */
+ return chdir (Dir);
+}
+
+
+
diff --git a/os2/getpass.c b/os2/getpass.c
new file mode 100644
index 0000000..e9ceb22
--- /dev/null
+++ b/os2/getpass.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include "cvs.h"
+#include "os2inc.h"
+
+/* Only define this if you're testing and want to compile this file
+ standalone. */
+/* #define DIAGNOSTIC */
+
+/* Turn off keyboard echo. Does not check error returns. */
+static void
+EchoOff (void)
+{
+ KBDINFO KbdInfo;
+
+ KbdGetStatus (&KbdInfo, 0);
+ KbdInfo.fsMask = (KbdInfo.fsMask & ~KEYBOARD_ECHO_ON) | KEYBOARD_ECHO_OFF;
+ KbdSetStatus (&KbdInfo, 0);
+}
+
+/* Turn on keyboard echo. Does not check error returns. */
+static void
+EchoOn( void )
+{
+ KBDINFO KbdInfo;
+
+ KbdGetStatus (&KbdInfo, 0);
+ KbdInfo.fsMask = (KbdInfo.fsMask & ~KEYBOARD_ECHO_OFF) | KEYBOARD_ECHO_ON;
+ KbdSetStatus (&KbdInfo, 0);
+}
+
+char *
+getpass (char *prompt)
+{
+ static char Buf[80];
+ STRINGINBUF StringInBuf;
+
+ printf ("%s", prompt);
+ fflush (stdout);
+
+ EchoOff ();
+
+ StringInBuf.cb = sizeof (Buf) - 1;
+ StringInBuf.cchIn = 0;
+ KbdStringIn ((PSZ) Buf, &StringInBuf, IO_WAIT, 0);
+ Buf[StringInBuf.cchIn] = '\0';
+
+ EchoOn ();
+
+ return Buf;
+}
+
+
+#ifdef DIAGNOSTIC
+main()
+{
+ char *s;
+ s = getpass ("Input password (no echo): ");
+ printf ("String was \"%s\"\n", s);
+ fflush (stdout);
+}
+#endif /* DIAGNOSTIC */
+
diff --git a/os2/mkdir.c b/os2/mkdir.c
new file mode 100644
index 0000000..2c9df54
--- /dev/null
+++ b/os2/mkdir.c
@@ -0,0 +1,17 @@
+/* mkdir.c --- mkdir for OS/2
+ Karl Fogel <kfogel@cyclic.com> --- October 1995 */
+
+#include <assert.h>
+
+#include "cvs.h"
+
+int
+os2_mkdir (const char *path, int mode)
+{
+ /* This is true for all extant calls to CVS_MKDIR. If
+ someone adds a call that uses something else later,
+ we should tweak this function to handle that. */
+ assert (mode == 0777);
+
+ return mkdir (path);
+}
diff --git a/os2/os2inc.h b/os2/os2inc.h
new file mode 100644
index 0000000..ba348a1
--- /dev/null
+++ b/os2/os2inc.h
@@ -0,0 +1,22 @@
+/* This file is used to make the os/2 header files idempotent.
+ Written 11/96 by Ullrich von Bassewitz (uz@musoftware.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifndef IN_OS2INC_H
+#define IN_OS2INC_H
+
+#define INCL_BASE
+#define INCL_SUB
+#define INCL_KBD
+#include <os2.h>
+
+#endif
diff --git a/os2/popen.c b/os2/popen.c
new file mode 100644
index 0000000..12de183
--- /dev/null
+++ b/os2/popen.c
@@ -0,0 +1,385 @@
+/* popen.c -- popen/pclose for OS/2. */
+
+/* Set to 0 for distribution.
+ Search for "DIAGNOSTIC" in the code to see what it's for. */
+#define DIAGNOSTIC 0
+
+#include <process.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "os2inc.h"
+
+#define LL_VAL ULONG
+#define LL_KEY PID /* also ULONG, really */
+
+#define STDIN 0
+#define STDOUT 1
+#define STDERR 2
+
+/* ********************************************************************* *
+ * *
+ * First, a little linked-list library to help keep track of pipes: *
+ * *
+ * ********************************************************************* */
+
+/* Map integer PID's onto integer termination codes. */
+struct pid_list
+{
+ HFILE pid; /* key */
+ ULONG term_code; /* val */
+ struct pid_list *next; /* duh */
+};
+
+static struct pid_list *pid_ll = (struct pid_list *) NULL;
+
+/* The ll_*() functions all make use of the global var `pid_ll'. */
+
+void
+ll_insert (HFILE key, ULONG val)
+{
+ struct pid_list *new;
+ new = (struct pid_list *) xmalloc (sizeof (*new));
+
+ new->pid = key;
+ new->term_code = val;
+ new->next = pid_ll;
+
+ pid_ll = new;
+}
+
+
+void
+ll_delete (int key)
+{
+ struct pid_list *this, *last;
+
+ this = pid_ll;
+ last = (struct pid_list *) NULL;
+
+ while (this)
+ {
+ if (this->pid == key)
+ {
+ /* Delete this node and leave. */
+ if (last)
+ last->next = this->next;
+ else
+ pid_ll = this->next;
+ free (this);
+ return;
+ }
+
+ /* Else no match, so try the next one. */
+ last = this;
+ this = this->next;
+ }
+}
+
+ULONG
+ll_lookup (HFILE key)
+{
+ struct pid_list *this = pid_ll;
+
+ while (this)
+ {
+ if (this->pid == key)
+ return this->term_code;
+
+ /* Else no match, so try the next one. */
+ this = this->next;
+ }
+
+ /* Zero is special in this context anyway. */
+ return 0;
+}
+
+#if DIAGNOSTIC
+ULONG
+ll_length ()
+{
+ struct pid_list *this = pid_ll;
+ unsigned long int len;
+
+ for (len = 0; this; len++)
+ this = this->next;
+
+ return len;
+}
+
+ULONG
+ll_print ()
+{
+ struct pid_list *this = pid_ll;
+ unsigned long int i;
+
+ for (i = 0; this; i++)
+ {
+ printf ("pid_ll[%d] == (%5d --> %5d)\n",
+ i, this->pid, this->term_code);
+ this = this->next;
+ }
+
+ if (i == 0)
+ printf ("No entries.\n");
+
+ return i;
+}
+#endif /* DIAGNOSTIC */
+
+/* ********************************************************************* *
+ * *
+ * End of linked-list library, beginning of popen/pclose: *
+ * *
+ * ********************************************************************* */
+
+/*
+ * Routine: popen
+ * Returns: FILE pointer to pipe.
+ * Action : Exec program connected via pipe, connect a FILE * to the
+ * pipe and return it.
+ * Params : Command - Program to run
+ * Mode - Mode to open pipe. "r" implies pipe is connected
+ * to the programs stdout, "w" connects to stdin.
+ */
+FILE *
+popen (const char *Command, const char *Mode)
+{
+ HFILE End1, End2, Std, Old1, Old2, Tmp;
+
+ FILE *File;
+
+ char Fail[256],
+ *Args,
+ CmdLine[256],
+ *CmdExe;
+
+ RESULTCODES
+ Result;
+
+ int Rc;
+
+ if (DosCreatePipe (&End1, &End2, 4096))
+ return NULL;
+
+ Std = (*Mode == 'w') ? STDIN : STDOUT ;
+ if (Std == STDIN)
+ {
+ Tmp = End1; End1 = End2; End2 = Tmp;
+ }
+
+ Old1 = -1; /* save stdin or stdout */
+ DosDupHandle (Std, &Old1);
+ DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
+ Tmp = Std; /* redirect stdin or stdout */
+ DosDupHandle (End2, &Tmp);
+
+ if (Std == 1)
+ {
+ Old2 = -1; /* save stderr */
+ DosDupHandle (STDERR, &Old2);
+ DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
+ Tmp = STDERR;
+ DosDupHandle (End2, &Tmp);
+ }
+
+ DosClose (End2);
+ DosSetFHState (End1, OPEN_FLAGS_NOINHERIT);
+
+ if ((CmdExe = getenv ("COMSPEC")) == NULL )
+ CmdExe = "cmd.exe";
+
+ strcpy (CmdLine, CmdExe);
+ Args = CmdLine + strlen (CmdLine) + 1; /* skip zero */
+ strcpy (Args, "/c ");
+ strcat (Args, Command);
+ Args[strlen (Args) + 1] = '\0'; /* two zeroes */
+ Rc = DosExecPgm (Fail, sizeof (Fail), EXEC_ASYNCRESULT,
+ (unsigned char *) CmdLine, 0, &Result,
+ (unsigned char *) CmdExe);
+
+ Tmp = Std; /* restore stdin or stdout */
+ DosDupHandle (Old1, &Tmp);
+ DosClose (Old1);
+
+ if (Std == STDOUT)
+ {
+ Tmp = STDERR; /* restore stderr */
+ DosDupHandle (Old2, &Tmp);
+ DosClose (Old2);
+ }
+
+ if (Rc)
+ {
+ DosClose (End1);
+ return NULL;
+ }
+
+#ifdef __WATCOMC__
+ /* Watcom does not allow mixing operating system handles and
+ * C library handles, so we have to convert.
+ */
+ File = fdopen (_hdopen (End1, *Mode == 'w'? O_WRONLY : O_RDONLY), Mode);
+#else
+ File = fdopen (End1, Mode);
+#endif
+ ll_insert ((LL_KEY) End1, (LL_VAL) Result.codeTerminate);
+
+ return File;
+}
+
+
+/*
+ * Routine: popenRW
+ * Returns: PID of child process
+ * Action : Exec program connected via pipe, connect int fd's to
+ * both the stdin and stdout of the process.
+ * Params : Command - Program to run
+ * Pipes - Array of 2 ints to store the pipe descriptors
+ * Pipe[0] writes to child's stdin,
+ * Pipe[1] reads from child's stdout/stderr
+ */
+int
+popenRW (const char **argv, int *pipes)
+{
+ HFILE Out1, Out2, In1, In2;
+ HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp;
+
+ int pid;
+
+ if (DosCreatePipe (&Out2, &Out1, 4096))
+ return FALSE;
+
+ if (DosCreatePipe (&In1, &In2, 4096))
+ {
+ DosClose (Out1);
+ DosClose (Out2);
+ return FALSE;
+ }
+
+ /* Save std{in,out,err} */
+ DosDupHandle (STDIN, &Old0);
+ DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
+ DosDupHandle (STDOUT, &Old1);
+ DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
+ DosDupHandle (STDERR, &Old2);
+ DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
+
+ /* Redirect std{in,out,err} */
+ Tmp = STDIN;
+ DosDupHandle (In1, &Tmp);
+ Tmp = STDOUT;
+ DosDupHandle (Out1, &Tmp);
+ Tmp = STDERR;
+ DosDupHandle (Out1, &Tmp);
+
+ /* Close file handles not needed in child */
+
+ DosClose (In1);
+ DosClose (Out1);
+ DosSetFHState (In2, OPEN_FLAGS_NOINHERIT);
+ DosSetFHState (Out2, OPEN_FLAGS_NOINHERIT);
+
+ /* Spawn we now our hoary brood. */
+ pid = spawnvp (P_NOWAIT, argv[0], argv);
+
+ /* Restore std{in,out,err} */
+ Tmp = STDIN;
+ DosDupHandle (Old0, &Tmp);
+ DosClose (Old0);
+ Tmp = STDOUT;
+ DosDupHandle (Old1, &Tmp);
+ DosClose (Old1);
+ Tmp = STDERR;
+ DosDupHandle (Old2, &Tmp);
+ DosClose (Old2);
+
+ if(pid < 0)
+ {
+ DosClose (In2);
+ DosClose (Out2);
+ return -1;
+ }
+
+ pipes[0] = In2;
+ _setmode (pipes[0], O_BINARY);
+ pipes[1] = Out2;
+ _setmode (pipes[1], O_BINARY);
+
+ /* Save ID of write-to-child pipe for pclose() */
+ ll_insert ((LL_KEY) In2, (LL_VAL) pid);
+
+ return pid;
+}
+
+
+/*
+ * Routine: pclose
+ * Returns: TRUE on success
+ * Action : Close a pipe opened with popen();
+ * Params : Pipe - pipe to close
+ */
+int
+pclose (FILE *Pipe)
+{
+ RESULTCODES rc;
+ PID pid, pid1;
+ int Handle = fileno (Pipe);
+
+ fclose (Pipe);
+
+ rc.codeTerminate = -1;
+
+ pid1 = (PID) ll_lookup ((LL_KEY) Handle);
+ /* if pid1 is zero, something's seriously wrong */
+ if (pid1 != 0)
+ {
+ DosWaitChild (DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pid1);
+ ll_delete ((LL_KEY) Handle);
+ }
+ return rc.codeTerminate == 0 ? rc.codeResult : -1;
+}
+
+
+#if DIAGNOSTIC
+void
+main ()
+{
+ FILE *fp1, *fp2, *fp3;
+ int c;
+
+ ll_print ();
+ fp1 = popen ("gcc --version", "r");
+ ll_print ();
+ fp2 = popen ("link386 /?", "r");
+ ll_print ();
+ fp3 = popen ("dir", "r");
+ ll_print ();
+
+ while ((c = getc (fp1)) != EOF)
+ printf ("%c", c);
+
+ while ((c = getc (fp2)) != EOF)
+ printf ("%c", c);
+
+ while ((c = getc (fp3)) != EOF)
+ printf ("%c", c);
+
+ pclose (fp1);
+ ll_print ();
+ pclose (fp2);
+ ll_print ();
+ pclose (fp3);
+ ll_print ();
+
+ return;
+}
+
+#endif /* DIAGNOSTIC */
diff --git a/os2/popen.h b/os2/popen.h
new file mode 100644
index 0000000..fec94e0
--- /dev/null
+++ b/os2/popen.h
@@ -0,0 +1,6 @@
+/* We roll our own popen()/pclose() in OS/2.
+ Thanks, Glenn Gribble! */
+
+FILE *popen (const char *cmd, const char *mode);
+int popenRW (char **cmd, int *pipes);
+int pclose (FILE *stream);
diff --git a/os2/porttcp.c b/os2/porttcp.c
new file mode 100644
index 0000000..a64b511
--- /dev/null
+++ b/os2/porttcp.c
@@ -0,0 +1,227 @@
+/****************************************************************
+**
+** PORTTCP.C - Support for portable TCP/IP
+**
+****************************************************************/
+
+#define TCPIP_IBM_NOHIDE
+#include <stdio.h>
+#include "tcpip.h"
+
+/*
+ * Common unknown error buffer
+ */
+static char ErrUnknownBuf[36];
+
+#ifndef SockStrError
+
+/****************************************************************
+ * Routine: SockStrError
+ * Returns: Pointer to static buffer
+ * Action : Convert SOCK_ERRNO into error text
+ ****************************************************************/
+
+const char *
+SockStrError(int SockErrno)
+{
+#if defined (TCPIP_IBM) && defined (IBM_CPP)
+ switch (SockErrno)
+ {
+ case SOCEPERM: return "Not owner";
+ case SOCESRCH: return "No such process";
+ case SOCEINTR: return "Interrupted system call";
+ case SOCENXIO: return "No such device or address";
+ case SOCEBADF: return "Bad file number";
+ case SOCEACCES: return "Permission denied";
+ case SOCEFAULT: return "Bad address";
+ case SOCEINVAL: return "Invalid argument";
+ case SOCEMFILE: return "Too many open files";
+ case SOCEPIPE: return "Broken pipe";
+ case SOCEOS2ERR: return "OS/2 Error";
+ case SOCEWOULDBLOCK: return "Operation would block";
+ case SOCEINPROGRESS: return "Operation now in progress";
+ case SOCEALREADY: return "Operation already in progress";
+ case SOCENOTSOCK: return "Socket operation on non-socket";
+ case SOCEDESTADDRREQ: return "Destination address required";
+ case SOCEMSGSIZE: return "Message too long";
+ case SOCEPROTOTYPE: return "Protocol wrong type for socket";
+ case SOCENOPROTOOPT: return "Protocol not available";
+ case SOCEPROTONOSUPPORT: return "Protocol not supported";
+ case SOCESOCKTNOSUPPORT: return "Socket type not supported";
+ case SOCEOPNOTSUPP: return "Operation not supported on socket";
+ case SOCEPFNOSUPPORT: return "Protocol family not supported";
+ case SOCEAFNOSUPPORT:
+ return "Address family not supported by protocol family";
+ case SOCEADDRINUSE: return "Address already in use";
+ case SOCEADDRNOTAVAIL: return "Can't assign requested address";
+ case SOCENETDOWN: return "Network is down";
+ case SOCENETUNREACH: return "Network is unreachable";
+ case SOCENETRESET: return "Network dropped connection on reset";
+ case SOCECONNABORTED: return "Software caused connection abort";
+ case SOCECONNRESET: return "Connection reset by peer";
+ case SOCENOBUFS: return "No buffer space available";
+ case SOCEISCONN: return "Socket is already connected";
+ case SOCENOTCONN: return "Socket is not connected";
+ case SOCESHUTDOWN: return "Can't send after socket shutdown";
+ case SOCETOOMANYREFS: return "Too many references: can't splice";
+ case SOCETIMEDOUT: return "Connection timed out";
+ case SOCECONNREFUSED: return "Connection refused";
+ case SOCELOOP: return "Too many levels of symbolic links";
+ case SOCENAMETOOLONG: return "File name too long";
+ case SOCEHOSTDOWN: return "Host is down";
+ case SOCEHOSTUNREACH: return "No route to host";
+ case SOCENOTEMPTY: return "Directory not empty";
+
+ default:
+ sprintf( ErrUnknownBuf, "SockStrErrno( %d ) unknown", SockErrno );
+ return ErrUnknownBuf;
+ }
+#else
+#error SockStrError not supported for this OS
+#endif
+}
+
+#endif /* SockStrError */
+
+
+/****************************************************************
+ * Routine: HostStrError
+ * Returns: Pointer to static buffer
+ * Action : Convert HOST_ERRNO into error text
+ ****************************************************************/
+
+const char *
+HostStrError(int HostErrno)
+{
+ switch (HostErrno)
+ {
+ case HOST_NOT_FOUND:
+ return "Host not found";
+ case TRY_AGAIN:
+ return "Host not found (suggest try again)";
+ case NO_RECOVERY:
+ return "Non-recoverable error: FORMERR, REFUSED, NOTIMP";
+ case NO_DATA:
+ return "No Data (valid name, but no record of requested type)";
+
+ default:
+ sprintf( ErrUnknownBuf, "HostStrErrno( %d ) unknown", HostErrno );
+ return ErrUnknownBuf;
+ }
+}
+
+
+#if defined( TCPIP_IBM )
+/****************************************************************
+ * Routine: IbmSockSend
+ * Returns: same as send
+ * Action : Do the right thing for IBM TCP/IP which includes
+ * the following two stupidities:
+ * 1) Never try to send more than 32K
+ * 2) Never pass a buffer that crosses a 64K boundary
+ * If Flags is non-zero, this function only attempts
+ * to deal with condition (1) above.
+ ****************************************************************/
+
+int
+IbmSockSend (int Socket, const void *Buffer, int Len, int Flags)
+{
+ int Sent, ToSend, TotalSent = 0;
+
+ const char *Tmp = Buffer;
+
+ /*
+ * If Flags have been passed in, the 64K boundary optimization
+ * can not be performed. For example, MSG_PEEK would not work
+ * correctly.
+ */
+ if (Flags)
+ return send (Socket, (char *) Buffer, min (0x7FFF, Len), Flags);
+
+ do
+ {
+ /* Never send across a 64K boundary */
+ ToSend = min (Len, (int) (0x10000 - (0xFFFF & (long) Tmp)));
+
+ /* Never send more than 32K */
+ if (ToSend > 0x7FFF)
+ ToSend = 0x7FFF;
+
+ Sent = send (Socket, (char *) Tmp, ToSend, 0);
+ if (Sent < 0)
+ {
+ if ((TotalSent > 0) && (SOCK_ERRNO == EWOULDBLOCK))
+ return TotalSent;
+ if (SOCK_ERRNO == EINTR)
+ continue;
+ return Sent;
+ }
+ if (Sent < ToSend)
+ return TotalSent + Sent;
+
+ Tmp += Sent;
+ TotalSent += Sent;
+ Len -= Sent;
+ } while (Len > 0);
+
+ return TotalSent;
+}
+
+
+
+/****************************************************************
+ * Routine: IbmSockRecv
+ * Returns: same as recv
+ * Action : Do the right thing for IBM TCP/IP which includes
+ * the following two stupidities:
+ * 1) Never try to recv more than 32K
+ * 2) Never pass a buffer that crosses a 64K boundary
+ * If Flags is non-zero, this function only attempts
+ * to deal with condition (1) above.
+ ****************************************************************/
+
+int
+IbmSockRecv (int Socket, const void *Buffer, int Len, int Flags)
+{
+ int Recvd, ToRecv, TotalRecvd = 0;
+
+ char *Tmp = Buffer;
+
+ /* If Flags have been passed in, the 64K boundary optimization
+ probably can not be performed. */
+
+ if (Flags)
+ return recv (Socket, Buffer, min (0x7FFF, Len), Flags);
+
+ do
+ {
+ /* Never send across a 64K boundary */
+ ToRecv = min( Len, (int)( 0x10000 - ( 0xFFFF & (long)Tmp )));
+
+ /* Never send more than 32K */
+ if( ToRecv > 0x7FFF )
+ ToRecv = 0x7FFF;
+
+ Recvd = recv (Socket, Tmp, ToRecv, 0);
+ if (Recvd <= 0)
+ {
+ if ((TotalRecvd > 0)
+ && (Recvd == 0 || (SOCK_ERRNO == EWOULDBLOCK )))
+ return TotalRecvd;
+ if (SOCK_ERRNO == EINTR)
+ continue;
+
+ return Recvd;
+ }
+ if (Recvd < ToRecv)
+ return TotalRecvd + Recvd;
+
+ Tmp += Recvd;
+ TotalRecvd += Recvd;
+ Len -= Recvd;
+ } while (Len > 0);
+
+ return TotalRecvd;
+}
+#endif /* defined( TCPIP_IBM ) */
+
diff --git a/os2/pwd.c b/os2/pwd.c
new file mode 100644
index 0000000..7235f28
--- /dev/null
+++ b/os2/pwd.c
@@ -0,0 +1,198 @@
+/* pwd.c - Try to approximate UN*X's getuser...() functions under MS-DOS.
+ Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This 'implementation' is conjectured from the use of this functions in
+ the RCS and BASH distributions. Of course these functions don't do too
+ much useful things under MS-DOS, but using them avoids many "#ifdef
+ MSDOS" in ported UN*X code ... */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+
+static char *lookup_env (char **);
+
+/* where people might scribble their name into the environment ... */
+
+static char *login_strings[] =
+{
+ "LOGIN", "USER", "MAILNAME", (char *) 0
+};
+
+static char *group_strings[] =
+{
+ "GROUP", (char *) 0
+};
+
+
+static char *anonymous = "anonymous"; /* if all else fails ... */
+
+static char *home_dir = "."; /* we feel (no|every)where at home */
+static char *login_shell = "not cmd.exe!";
+
+static char *login = (char *) 0;/* cache the names here */
+static char *group = (char *) 0;
+
+static struct passwd pw; /* should we return a malloc()'d structure */
+static struct group gr; /* instead of pointers to static structures? */
+
+/* return something like a username in a (butchered!) passwd structure. */
+struct passwd *
+getpwuid (int uid)
+{
+ pw.pw_name = getlogin ();
+ pw.pw_dir = home_dir;
+ pw.pw_shell = login_shell;
+ pw.pw_uid = 0;
+
+ return &pw;
+}
+
+struct passwd *
+getpwnam (char *name)
+{
+ return (struct passwd *) 0;
+}
+
+/* return something like a groupname in a (butchered!) group structure. */
+struct group *
+getgrgid (int uid)
+{
+ gr.gr_name = getgr_name ();
+ gr.gr_gid = 0;
+
+ return &gr;
+}
+
+struct group *
+getgrnam (char *name)
+{
+ return (struct group *) 0;
+}
+
+/* return something like a username. */
+char *
+getlogin ()
+{
+ if (!login) /* have we been called before? */
+ login = lookup_env (login_strings);
+
+ if (!login) /* have we been successful? */
+ login = anonymous;
+
+ return login;
+}
+
+/* return something like a group. */
+char *
+getgr_name ()
+{
+ if (!group) /* have we been called before? */
+ group = lookup_env (group_strings);
+
+ if (!group) /* have we been successful? */
+ group = anonymous;
+
+ return group;
+}
+
+/* return something like a uid. */
+int
+getuid ()
+{
+ return 0; /* every user is a super user ... */
+}
+
+int
+getgid ()
+{
+ return 0;
+}
+
+int
+geteuid ()
+{
+ return 0;
+}
+
+int
+getegid ()
+{
+ return 0;
+}
+
+struct passwd *
+getpwent ()
+{
+ return (struct passwd *) 0;
+}
+
+void
+setpwent ()
+{
+}
+
+void
+endpwent ()
+{
+}
+
+void
+endgrent ()
+{
+}
+
+/* return groups. */
+int
+getgroups (int ngroups, int *groups)
+{
+ *groups = 0;
+ return 1;
+}
+
+/* lookup environment. */
+static char *
+lookup_env (char *table[])
+{
+ char *ptr;
+ char *entry;
+ size_t len;
+
+ while (*table && !(ptr = getenv (*table++))) ; /* scan table */
+
+ if (!ptr)
+ return (char *) 0;
+
+ len = strcspn (ptr, " \n\t\n\r"); /* any WS? */
+ if (!(entry = xmalloc (len + 1)))
+ {
+ fprintf (stderr, "Out of memory.\nStop.");
+ exit (-1);
+ }
+
+ strncpy (entry, ptr, len);
+ entry[len] = '\0';
+
+ return entry;
+
+}
+
+/*
+ * Local Variables:
+ * mode:C
+ * ChangeLog:ChangeLog
+ * compile-command:make
+ * End:
+ */
diff --git a/os2/pwd.h b/os2/pwd.h
new file mode 100644
index 0000000..ad225a1
--- /dev/null
+++ b/os2/pwd.h
@@ -0,0 +1,70 @@
+/* pwd.h - Try to approximate UN*X's getuser...() functions under MS-DOS.
+ Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This 'implementation' is conjectured from the use of this functions in
+ the RCS and BASH distributions. Of course these functions don't do too
+ much useful things under MS-DOS, but using them avoids many "#ifdef
+ MSDOS" in ported UN*X code ... */
+
+#if 0
+/* This is taken care of in Windows-NT/config.h. */
+typedef int uid_t;
+#endif
+
+struct passwd
+{
+ /* ... */
+ /* missing stuff */
+ /* ... */
+ char *pw_name; /* login user id */
+ char *pw_dir; /* home directory */
+ char *pw_shell; /* login shell */
+ int pw_uid;
+};
+
+struct group
+{
+ /* ... */
+ /* missing stuff */
+ /* ... */
+ char *gr_name; /* login user id */
+ int gr_gid;
+};
+
+extern struct passwd *getpwuid (int);
+extern struct passwd *getpwnam (char *);
+extern struct group *getgrgid (int);
+extern struct group *getgrnam (char *);
+extern char *getlogin (void);
+extern char *getgr_name (void);
+extern int getuid (void);
+extern int getgid (void);
+extern int geteuid (void);
+extern int getegid (void);
+
+extern int *groups;
+extern int ngroups;
+extern int getgroups (int, int *);
+
+extern struct passwd *getpwent (void);
+extern void setpwent (void);
+extern void endpwent (void);
+extern void endgrent (void);
+
+/*
+ * Local Variables:
+ * mode:C
+ * ChangeLog:ChangeLog
+ * compile-command:make
+ * End:
+ */
diff --git a/os2/rcmd.c b/os2/rcmd.c
new file mode 100644
index 0000000..2996e49
--- /dev/null
+++ b/os2/rcmd.c
@@ -0,0 +1,76 @@
+/* rcmd.c --- execute a command on a remote host from OS/2
+ Karl Fogel <kfogel@cyclic.com> --- November 1995 */
+
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <io.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <errno.h>
+/* <sys/socket.h> wants `off_t': */
+#include <sys/types.h>
+/* This should get us ibmtcpip\include\sys\socket.h: */
+#include <sys/socket.h>
+#include <assert.h>
+
+#include "rcmd.h"
+
+void
+init_sockets ()
+{
+ int rc;
+
+ rc = sock_init ();
+ if (rc != 0)
+ {
+ fprintf (stderr, "sock_init() failed -- returned %d!\n", rc);
+ exit (1);
+ }
+}
+
+
+static int
+resolve_address (const char **ahost, struct sockaddr_in *sai)
+{
+ fprintf (stderr,
+ "Error: resolve_address() doesn't work.\n");
+ exit (1);
+}
+
+static int
+bind_and_connect (struct sockaddr_in *server_sai)
+{
+ fprintf (stderr,
+ "Error: bind_and_connect() doesn't work.\n");
+ exit (1);
+}
+
+static int
+rcmd_authenticate (int fd, char *locuser, char *remuser, char *command)
+{
+ fprintf (stderr,
+ "Error: rcmd_authenticate() doesn't work.\n");
+ exit (1);
+}
+
+int
+rcmd (const char **ahost,
+ unsigned short inport,
+ char *locuser,
+ char *remuser,
+ char *cmd,
+ int *fd2p)
+{
+ fprintf (stderr,
+ "Error: rcmd() doesn't work.\n");
+ exit (1);
+}
diff --git a/os2/rcmd.h b/os2/rcmd.h
new file mode 100644
index 0000000..2c84d5b
--- /dev/null
+++ b/os2/rcmd.h
@@ -0,0 +1,40 @@
+/* rcmd.h --- interface to executing commands on remote hosts
+ Karl Fogel <kfogel@cyclic.com> --- November 1995 */
+
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* Run the command CMD on the host *AHOST, and return a file descriptor for
+ a bidirectional stream socket connected to the command's standard input
+ and output.
+
+ rcmd looks up *AHOST using gethostbyname, and sets *AHOST to the host's
+ canonical name. If *AHOST is not found, rcmd returns -1.
+
+ rcmd connects to the remote host at TCP port INPORT. This should
+ probably be the "shell" service, port 514.
+
+ LOCUSER is the name of the user on the local machine, and REMUSER is
+ the name of the user on the remote machine; the remote machine uses this,
+ along with the source address of the TCP connection, to authenticate
+ the connection.
+
+ CMD is the command to execute. The remote host will tokenize it any way
+ it damn well pleases. Welcome to Unix.
+
+ FD2P is a feature we don't support, but there's no point in making mindless
+ deviations from the interface. Callers should always pass this argument
+ as zero. */
+extern int rcmd (const char **AHOST,
+ unsigned short INPORT,
+ char *LOCUSER,
+ char *REMUSER,
+ char *CMD,
+ int *fd2p);
diff --git a/os2/run.c b/os2/run.c
new file mode 100644
index 0000000..6a4179b
--- /dev/null
+++ b/os2/run.c
@@ -0,0 +1,611 @@
+/* run.c --- routines for executing subprocesses under OS/2.
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+
+#include "os2inc.h"
+
+#include <process.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <io.h>
+
+#define STDIN 0
+#define STDOUT 1
+#define STDERR 2
+
+static void run_add_arg( const char *s );
+static void run_init_prog( void );
+
+extern char *strtok ();
+
+/*
+ * To exec a program under CVS, first call run_setup() to setup any initial
+ * arguments. The options to run_setup are essentially like printf(). The
+ * arguments will be parsed into whitespace separated words and added to the
+ * global run_argv list.
+ *
+ * Then, optionally call run_arg() for each additional argument that you'd like
+ * to pass to the executed program.
+ *
+ * Finally, call run_exec() to execute the program with the specified
+ * arguments.
+ * The execvp() syscall will be used, so that the PATH is searched correctly.
+ * File redirections can be performed in the call to run_exec().
+ */
+static char **run_argv;
+static int run_argc;
+static int run_argc_allocated;
+
+void
+run_setup (const char *prog)
+{
+ int i;
+ char *run_prog;
+ char *buf, *d, *s;
+ size_t length;
+ size_t doff;
+ char inquotes;
+ int dolastarg;
+
+ /* clean out any malloc'ed values from run_argv */
+ for (i = 0; i < run_argc; i++)
+ {
+ if (run_argv[i])
+ {
+ free (run_argv[i]);
+ run_argv[i] = (char *) 0;
+ }
+ }
+ run_argc = 0;
+
+ run_prog = xstrdup (prog);
+
+ s = run_prog;
+ d = buf = NULL;
+ length = 0;
+ dolastarg = 1;
+ inquotes = '\0';
+ doff = d - buf;
+ expand_string(&buf, &length, doff + 1);
+ d = buf + doff;
+ while (*d = *s++)
+ {
+ switch (*d)
+ {
+ case '\\':
+ if (*s) *d = *s++;
+ d++;
+ break;
+ case '"':
+ case '\'':
+ if (inquotes == *d) inquotes = '\0';
+ else inquotes = *d;
+ break;
+ case ' ':
+ case '\t':
+ if (inquotes) d++;
+ else
+ {
+ *d = '\0';
+ run_add_arg (buf);
+ d = buf;
+ while (isspace(*s)) s++;
+ if (!*s) dolastarg = 0;
+ }
+ break;
+ default:
+ d++;
+ break;
+ }
+ doff = d - buf;
+ expand_string(&buf, &length, doff + 1);
+ d = buf + doff;
+ }
+ if (dolastarg) run_add_arg (buf);
+ /* put each word into run_argv, allocating it as we go */
+ if (buf) free (buf);
+ free (run_prog);
+
+ free (run_prog);
+ if (buf) free (buf);
+}
+
+void
+run_arg (s)
+ const char *s;
+{
+ run_add_arg (s);
+}
+
+/* Return a malloc'd copy of s, with double quotes around it. */
+/* FIXME - this should replace " with \" as it copies. or something.
+ * depends where it's used, I would suppose.
+ */
+static char *
+quote (const char *s)
+{
+ size_t s_len = strlen (s);
+ char *copy = xmalloc (s_len + 3);
+ char *scan = copy;
+
+ *scan++ = '"';
+ strcpy (scan, s);
+ scan += s_len;
+ *scan++ = '"';
+ *scan++ = '\0';
+
+ return copy;
+}
+
+static void
+run_add_arg (s)
+ const char *s;
+{
+ /* allocate more argv entries if we've run out */
+ if (run_argc >= run_argc_allocated)
+ {
+ run_argc_allocated += 50;
+ run_argv = (char **) xrealloc ((char *) run_argv,
+ run_argc_allocated * sizeof (char **));
+ }
+
+ if (s)
+ {
+ run_argv[run_argc] = (run_argc ? quote (s) : xstrdup (s));
+ run_argc++;
+ }
+ else
+ /* not post-incremented on purpose! */
+ run_argv[run_argc] = (char *) 0;
+}
+
+int
+run_exec (stin, stout, sterr, flags)
+ char *stin;
+ char *stout;
+ char *sterr;
+ int flags;
+{
+ int shin, shout, sherr;
+ int sain, saout, saerr; /* saved handles */
+ int mode_out, mode_err;
+ int status = -1;
+ int rerrno = 0;
+ int rval = -1;
+ void (*old_sigint) (int);
+
+ if (trace) /* if in trace mode */
+ {
+ (void) fprintf (stderr, "-> system(");
+ run_print (stderr);
+ (void) fprintf (stderr, ")\n");
+ }
+ if (noexec && (flags & RUN_REALLY) == 0) /* if in noexec mode */
+ return (0);
+
+ /*
+ * start the engine and take off
+ */
+
+ /* make sure that we are null terminated, since we didn't calloc */
+ run_add_arg ((char *) 0);
+
+ /* setup default file descriptor numbers */
+ shin = 0;
+ shout = 1;
+ sherr = 2;
+
+ /* set the file modes for stdout and stderr */
+ mode_out = mode_err = O_WRONLY | O_CREAT;
+ mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
+ mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
+
+ /* open the files as required, shXX are shadows of stdin... */
+ if (stin && (shin = open (stin, O_RDONLY)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for reading (prog %s)",
+ stin, run_argv[0]);
+ goto out0;
+ }
+ if (stout && (shout = open (stout, mode_out, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ stout, run_argv[0]);
+ goto out1;
+ }
+ if (sterr && (flags & RUN_COMBINED) == 0)
+ {
+ if ((sherr = open (sterr, mode_err, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ sterr, run_argv[0]);
+ goto out2;
+ }
+ }
+ /* now save the standard handles */
+ sain = saout = saerr = -1;
+ sain = dup( 0); /* dup stdin */
+ saout = dup( 1); /* dup stdout */
+ saerr = dup( 2); /* dup stderr */
+
+ /* the new handles will be dup'd to the standard handles
+ * for the spawn.
+ */
+
+ if (shin != 0)
+ {
+ (void) dup2 (shin, 0);
+ (void) close (shin);
+ }
+ if (shout != 1)
+ {
+ (void) dup2 (shout, 1);
+ (void) close (shout);
+ }
+ if (flags & RUN_COMBINED)
+ (void) dup2 (1, 2);
+ else if (sherr != 2)
+ {
+ (void) dup2 (sherr, 2);
+ (void) close (sherr);
+ }
+
+ /* Ignore signals while we're running this. */
+ old_sigint = signal (SIGINT, SIG_IGN);
+
+ /* dup'ing is done. try to run it now */
+ rval = spawnvp ( P_WAIT, run_argv[0], run_argv);
+
+ /* Restore signal handling. */
+ signal (SIGINT, old_sigint);
+
+ /* restore the original file handles */
+ if (sain != -1) {
+ (void) dup2( sain, 0); /* re-connect stdin */
+ (void) close( sain);
+ }
+ if (saout != -1) {
+ (void) dup2( saout, 1); /* re-connect stdout */
+ (void) close( saout);
+ }
+ if (saerr != -1) {
+ (void) dup2( saerr, 2); /* re-connect stderr */
+ (void) close( saerr);
+ }
+
+ /* Recognize the return code for a failed subprocess. */
+ if (rval == -1)
+ return 2;
+ else
+ return rval; /* return child's exit status */
+
+ /* error cases */
+ /* cleanup the open file descriptors */
+ out2:
+ if (stout)
+ (void) close (shout);
+ out1:
+ if (stin)
+ (void) close (shin);
+
+ out0:
+ if (rerrno)
+ errno = rerrno;
+ return (status);
+}
+
+
+void
+run_print (fp)
+ FILE *fp;
+{
+ int i;
+
+ for (i = 0; i < run_argc; i++)
+ {
+ (void) fprintf (fp, "'%s'", run_argv[i]);
+ if (i != run_argc - 1)
+ (void) fprintf (fp, " ");
+ }
+}
+
+static char *
+requote (const char *cmd)
+{
+ char *requoted = xmalloc (strlen (cmd) + 1);
+ char *p = requoted;
+
+ strcpy (requoted, cmd);
+ while ((p = strchr (p, '\'')) != NULL)
+ {
+ *p++ = '"';
+ }
+
+ return requoted;
+}
+
+FILE *
+run_popen (cmd, mode)
+ const char *cmd;
+ const char *mode;
+{
+ TRACE( TRACE_FUNCTION, "run_popen(%s,%s)", cmd, mode );
+
+ if (noexec)
+ return (NULL);
+
+ /* If the command string uses single quotes, turn them into
+ double quotes. */
+ {
+ char *requoted = requote (cmd);
+ TRACE( TRACE_DATA, "Executing popen(%s,%s)", requoted, mode );
+ FILE *result = popen (requoted, mode);
+ free (requoted);
+ return result;
+ }
+}
+
+
+/* Running children with pipes connected to them. */
+
+/* Create a pipe. Set READWRITE[0] to its reading end, and
+ READWRITE[1] to its writing end. */
+
+static int
+my_pipe (int *readwrite)
+{
+ fprintf (stderr,
+ "Error: my_pipe() is unimplemented.\n");
+ exit (1);
+}
+
+
+/* Create a child process running COMMAND with IN as its standard input,
+ and OUT as its standard output. Return a handle to the child, or
+ INVALID_HANDLE_VALUE. */
+static int
+start_child (char *command, int in, int out)
+{
+ fprintf (stderr,
+ "Error: start_child() is unimplemented.\n");
+ exit (1);
+}
+
+
+/* Given an array of arguments that one might pass to spawnv,
+ construct a command line that one might pass to CreateProcess.
+ Try to quote things appropriately. */
+static char *
+build_command (char **argv)
+{
+ int len;
+
+ /* Compute the total length the command will have. */
+ {
+ int i;
+
+ len = 0;
+ for (i = 0; argv[i]; i++)
+ {
+ char *p;
+
+ len += 2; /* for the double quotes */
+
+ for (p = argv[i]; *p; p++)
+ {
+ if (*p == '"')
+ len += 2;
+ else
+ len++;
+ }
+ }
+ len++; /* for the space or the '\0' */
+ }
+
+ {
+ char *command = (char *) xmalloc (len);
+ int i;
+ char *p;
+
+ if (! command)
+ {
+ errno = ENOMEM;
+ return command;
+ }
+
+ p = command;
+ /* copy each element of argv to command, putting each command
+ in double quotes, and backslashing any quotes that appear
+ within an argument. */
+ for (i = 0; argv[i]; i++)
+ {
+ char *a;
+ *p++ = '"';
+ for (a = argv[i]; *a; a++)
+ {
+ if (*a == '"')
+ *p++ = '\\', *p++ = '"';
+ else
+ *p++ = *a;
+ }
+ *p++ = '"';
+ *p++ = ' ';
+ }
+ p[-1] = '\0';
+
+ return command;
+ }
+}
+
+
+/* Create an asynchronous child process executing ARGV,
+ with its standard input and output connected to the
+ parent with pipes. Set *TO to the file descriptor on
+ which one writes data for the child; set *FROM to
+ the file descriptor from which one reads data from the child.
+ Return the handle of the child process (this is what
+ _cwait and waitpid expect). */
+int
+piped_child (char **argv, int *to, int *from)
+{
+ fprintf (stderr,
+ "Error: piped_child() is unimplemented.\n");
+ exit (1);
+}
+
+/*
+ * dir = 0 : main proc writes to new proc, which writes to oldfd
+ * dir = 1 : main proc reads from new proc, which reads from oldfd
+ *
+ * If this returns at all, then it was successful and the return value
+ * is a file descriptor; else it errors and exits.
+ */
+int
+filter_stream_through_program (int oldfd, int dir,
+ char **prog, int *pidp)
+{
+ int newfd; /* Gets set to one end of the pipe and returned. */
+ HFILE from, to;
+ HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp;
+
+ if (DosCreatePipe (&from, &to, 4096))
+ return FALSE;
+
+ /* Save std{in,out,err} */
+ DosDupHandle (STDIN, &Old0);
+ DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
+ DosDupHandle (STDOUT, &Old1);
+ DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
+ DosDupHandle (STDERR, &Old2);
+ DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
+
+ /* Redirect std{in,out,err} */
+ if (dir) /* Who goes where? */
+ {
+ Tmp = STDIN;
+ DosDupHandle (oldfd, &Tmp);
+ Tmp = STDOUT;
+ DosDupHandle (to, &Tmp);
+ Tmp = STDERR;
+ DosDupHandle (to, &Tmp);
+
+ newfd = from;
+ _setmode (newfd, O_BINARY);
+
+ DosClose (oldfd);
+ DosClose (to);
+ DosSetFHState (from, OPEN_FLAGS_NOINHERIT);
+ }
+ else
+ {
+ Tmp = STDIN;
+ DosDupHandle (from, &Tmp);
+ Tmp = STDOUT;
+ DosDupHandle (oldfd, &Tmp);
+ Tmp = STDERR;
+ DosDupHandle (oldfd, &Tmp);
+
+ newfd = to;
+ _setmode (newfd, O_BINARY);
+
+ DosClose (oldfd);
+ DosClose (from);
+ DosSetFHState (to, OPEN_FLAGS_NOINHERIT);
+ }
+
+ /* Spawn we now our hoary brood. */
+ *pidp = spawnvp (P_NOWAIT, prog[0], prog);
+
+ /* Restore std{in,out,err} */
+ Tmp = STDIN;
+ DosDupHandle (Old0, &Tmp);
+ DosClose (Old0);
+ Tmp = STDOUT;
+ DosDupHandle (Old1, &Tmp);
+ DosClose (Old1);
+ Tmp = STDERR;
+ DosDupHandle (Old2, &Tmp);
+ DosClose (Old2);
+
+ if(*pidp < 0)
+ {
+ DosClose (from);
+ DosClose (to);
+ error (1, 0, "error spawning %s", prog[0]);
+ }
+
+ return newfd;
+}
+
+
+int
+pipe (int *filedesc)
+{
+ /* todo: actually, we can use DosCreatePipe(). Fix this. */
+ fprintf (stderr,
+ "Error: pipe() should not have been called in client.\n");
+ exit (1);
+}
+
+
+void
+close_on_exec (int fd)
+{
+ /* Just does nothing for now... */
+
+ /* Actually, we probably *can* implement this one. Let's see... */
+ /* Nope. OS/2 has <fcntl.h>, but no fcntl() ! Wow. */
+ /* Well, I'll leave this stuff in for future reference. */
+}
+
+
+/* Actually, we #define sleep() in config.h now. */
+#ifndef sleep
+unsigned int
+sleep (unsigned int seconds)
+{
+ /* I don't want to interfere with alarm signals, so I'm going to do
+ this the nasty way. */
+
+ time_t base;
+ time_t tick;
+ int i;
+
+ /* Init. */
+ time (&base);
+ time (&tick);
+
+ /* Loop until time has passed. */
+ while (difftime (tick, base) < seconds)
+ {
+ /* This might be more civilized than calling time over and over
+ again. */
+ for (i = 0; i < 10000; i++)
+ ;
+ time (&tick);
+ }
+
+ return 0;
+}
+#endif /* sleep */
diff --git a/os2/tcpip.h b/os2/tcpip.h
new file mode 100644
index 0000000..4f3e58f
--- /dev/null
+++ b/os2/tcpip.h
@@ -0,0 +1,131 @@
+/****************************************************************
+ *
+ * TCPIP.H - Portable TCP/IP header file
+ *
+ * TCP/IP on OS/2 is an add-on and thus is not fully integrated
+ * with the operating system. To ensure portability, follow
+ * these rules:
+ *
+ * * Always call SockInit() at the beginning of your program
+ * and check that it returns TRUE.
+ *
+ * * Use SockSend() & SockRecv() instead of read(), write(),
+ * send(), or recv() when working with sockets.
+ *
+ * * Use SockClose() instead of close() with sockets.
+ *
+ * * Use SOCK_ERRNO when using functions that use or return
+ * sockets, such as SockSend() or accept().
+ *
+ * * Use HOST_ERRNO when using gethostbyname() or gethostbyaddr()
+ * functions.
+ *
+ * * As far as I can tell, getservbyname() and related functions
+ * never set any error variable.
+ *
+ * * Use SockStrError() & HostStrError() to convert SOCK_ERRNO
+ * and HOST_ERRNO to error strings.
+ *
+ * * In .MAK files, include $(TCPIP_MAK) & use $(TCPIPLIB)
+ * when linking applications using TCP/IP.
+ *
+ ****************************************************************/
+
+#if !defined( IN_TCPIP_H )
+#define IN_TCPIP_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+
+#if defined( TCPIP_IBM )
+/* Here comes some ugly stuff: The watcom compiler and the IBM TCPIP
+ * toolkit do not work together very well. The return codes for the
+ * socket calls are not integrated into the usual error codes, there
+ * are separate values instead. This results in a crash for two values.
+ * Since these values are not needed for socket access as far as I can
+ * see, I will save those values and redefine them after including
+ * nerrno.h (types.h will include nerrno.h, so this is needed here).
+ */
+# ifdef __WATCOMC__
+ /* First check the numeric values */
+# if ENAMETOOLONG != 35
+# error "ENAMETOOLONG: value unknown"
+# endif
+# if ENOTEMPTY != 39
+# error "ENOTEMPTY: value unknown"
+# endif
+# undef ENAMETOOLONG
+# undef ENOTEMPTY
+# include <nerrno.h>
+# undef ENAMETOOLONG
+# undef ENOTEMPTY
+# define ENAMETOOLONG 35
+# define ENOTEMPTY 39
+# endif
+# include <types.h>
+# if !defined( TCPIP_IBM_NOHIDE )
+# define send IbmSockSend
+# define recv IbmSockRecv
+# endif
+#endif
+
+#if defined( TCPIP_IBM )
+# define BSD_SELECT
+# include <sys/select.h>
+# include <sys/time.h>
+# include <nerrno.h>
+# include <utils.h>
+# if defined( MICROSOFT )
+# define SOCK_ERRNO (tcperrno())
+# else
+# define SOCK_ERRNO (sock_errno())
+# endif
+# define HOST_ERRNO (h_errno)
+# define SockClose(S) soclose(S)
+# define SockInit() (!sock_init())
+# define SockSend IbmSockSend
+# define SockRecv IbmSockRecv
+
+const char *HostStrError(int HostErrno);
+const char *SockStrError(int SockErrno);
+
+int IbmSockSend (int Socket, const void *Buffer, int Len, int Flags);
+int IbmSockRecv (int Socket, const void *Buffer, int Len, int Flags);
+
+#if !defined( h_errno )
+extern int h_errno; /* IBM forgot to declare this in current header files */
+#endif
+
+#elif defined( __unix )
+# if defined( sgi ) /* SGI incorrectly defines FD_ZERO in sys/select.h */
+# include <bstring.h>
+# endif
+# if defined( sunos )
+extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+# else
+# include <sys/select.h>
+# endif
+# include <sys/time.h>
+# include <errno.h>
+# include <arpa/inet.h>
+# define SOCK_ERRNO errno
+# define HOST_ERRNO h_errno
+# define SockClose(S) close(S)
+# define SockInit() TRUE
+# define SockSend send
+# define SockRecv recv
+# define SockStrError(E) strerror(E)
+
+const char *HostStrError( int HostErrno );
+
+#else
+# error Undefined version of TCP/IP specified
+
+#endif
+
+#endif
diff --git a/os2/test-makefile b/os2/test-makefile
new file mode 100644
index 0000000..d6179ee
--- /dev/null
+++ b/os2/test-makefile
@@ -0,0 +1,40 @@
+# I use this for single compilation while porting; once the port is
+# done it can be removed.
+
+THIS_BASENAME = ../src/add
+
+CC = icc
+
+LIB = s:\ibmcpp\lib;s:\toolkt21\os2lib;
+CINC = -Is:/ibmcpp/include -Is:/toolkt21/c/os2h
+CFLAGS = -C+
+CFLAGS += -W3 -Wpro+rea+tru+use+ -Ti+ -Ss+ -Gd+ -Gm+ -G4 -Q+ -Sm ${CINC}
+CFLAGS += -DIBM_CPP -DHAVE_CONFIG_H
+
+# translation of most important CFLAGS -- others are trivial
+# ICC sez -C+ -W3 -Ti+ ${CINC}
+# GCC sez -c -Wall -g ${CINC}
+
+# "-I../os2" below ought to be equivalent to "-I."
+CFLAGS += -I../os2 -I../lib -I../src
+
+# Preprocesses to stdout.
+# CFLAGS += -Pd+
+
+# TCP/IP stuff
+TCPIPLIB = s:\ibmtcpip\lib\tcp32dll.lib s:\ibmtcpip\lib\so32dll.lib porttcp.obj
+
+# We probably don't need these.
+# RPCLIB = s:\ibmtcpip\lib\rpc32dll.lib
+# FTPLIB = s:\ibmtcpip\lib\ftpapi.lib
+
+CFLAGS += -DTCPIP_IBM -Is:\ibmtcpip\include
+
+all: ${THIS_BASENAME}.obj
+# all: ${THIS_BASENAME}.exe
+
+${THIS_BASENAME}.obj: ${THIS_BASENAME}.c
+ ${CC} ${CFLAGS} /Fo${THIS_BASENAME}.obj ${THIS_BASENAME}.c
+
+${THIS_BASENAME}.exe: ${THIS_BASENAME}.c
+ ${CC} ${CFLAGS} /Fe${THIS_BASENAME}.exe ${THIS_BASENAME}.c
diff --git a/os2/waitpid.c b/os2/waitpid.c
new file mode 100644
index 0000000..2b64f5d
--- /dev/null
+++ b/os2/waitpid.c
@@ -0,0 +1,36 @@
+/* waitpid.c --- waiting for process termination, under OS/2
+ Karl Fogel <kfogel@cyclic.com> --- November 1995 */
+
+#include <assert.h>
+#include <stdio.h>
+#include <process.h>
+#include <errno.h>
+
+#include "config.h"
+
+/* Wait for the process PID to exit. Put the return status in *statusp.
+ OPTIONS is not supported yet under OS/2. We hope it's always zero. */
+pid_t waitpid (pid, statusp, options)
+ pid_t pid;
+ int *statusp;
+ int options;
+{
+ pid_t rc;
+
+ /* We don't know how to deal with any options yet. */
+ assert (options == 0);
+
+ rc = _cwait (statusp, pid, WAIT_CHILD);
+
+ if (rc == -1)
+ {
+ if (errno == ECHILD)
+ return pid;
+ else
+ return -1;
+ }
+ else if (rc == pid)
+ return pid;
+ else
+ return -1;
+}
diff --git a/os2/watcom.mak b/os2/watcom.mak
new file mode 100644
index 0000000..1d79c2a
--- /dev/null
+++ b/os2/watcom.mak
@@ -0,0 +1,153 @@
+# Makefile for OS/2 (Watcom-C) for use with the watcom make.
+# Written 11/96 by Ullrich von Bassewitz (uz@musoftware.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# The directory, where the IBM TCP/IP developers toolkit is installed. As far
+# as I remember, c:\mptn is the default location. If it is not, it is still
+# a good choice :-)
+tcpip_dir = c:\mptn
+tcpip_libdir = $(tcpip_dir)\lib
+tcpip_incdir = $(tcpip_dir)\inc
+
+# Directory for source files and objects
+srcdir = .
+top_srcdir = ..
+lib_dir = $(top_srcdir)\lib
+cvs_srcdir = $(top_srcdir)\src
+zlib_dir = $(top_srcdir)\zlib
+
+# Define the stuff used for building the executable
+CC = WCC386
+LD = WLINK
+CFLAGS = -bm -bt=OS2 -I$(srcdir) -I$(lib_dir) -I$(cvs_srcdir) -I$(zlib_dir) &
+ -DIBM_CPP -DHAVE_CONFIG_H -DTCPIP_IBM -d1 -onatx -zp4 -5s -fpi87 -zq &
+ -w2 -ze -I$(tcpip_incdir)
+
+# Tell the make where the C files are located
+.c: $(srcdir);$(lib_dir);$(cvs_srcdir);$(zlib_dir)
+
+# Somewhat modified generic rule for .obj files. Don't put the .obj file into
+# the current directory, use the source directory instead.
+.c.obj: .AUTODEPEND
+ $(CC) $(CFLAGS) -fo=$*.obj $^*
+
+# object files from OS/2 sources
+OS2_OBJECTS = &
+ $(srcdir)\mkdir.obj &
+ $(srcdir)\pwd.obj &
+ $(srcdir)\filesubr.obj &
+ $(srcdir)\run.obj &
+ $(srcdir)\stripslash.obj &
+ $(srcdir)\rcmd.obj &
+ $(srcdir)\waitpid.obj &
+ $(srcdir)\popen.obj &
+ $(srcdir)\porttcp.obj &
+ $(srcdir)\getpass.obj
+
+# object files from ..\src
+COMMON_OBJECTS = &
+ $(cvs_srcdir)\add.obj &
+ $(cvs_srcdir)\admin.obj &
+ $(cvs_srcdir)\buffer.obj &
+ $(cvs_srcdir)\checkin.obj &
+ $(cvs_srcdir)\checkout.obj &
+ $(cvs_srcdir)\classify.obj &
+ $(cvs_srcdir)\client.obj &
+ $(cvs_srcdir)\commit.obj &
+ $(cvs_srcdir)\create_adm.obj &
+ $(cvs_srcdir)\cvsrc.obj &
+ $(cvs_srcdir)\diff.obj &
+ $(cvs_srcdir)\edit.obj &
+ $(cvs_srcdir)\entries.obj &
+ $(cvs_srcdir)\error.obj &
+ $(cvs_srcdir)\expand_path.obj &
+ $(cvs_srcdir)\fileattr.obj &
+ $(cvs_srcdir)\find_names.obj &
+ $(cvs_srcdir)\hash.obj &
+ $(cvs_srcdir)\history.obj &
+ $(cvs_srcdir)\ignore.obj &
+ $(cvs_srcdir)\import.obj &
+ $(cvs_srcdir)\lock.obj &
+ $(cvs_srcdir)\log.obj &
+ $(cvs_srcdir)\login.obj &
+ $(cvs_srcdir)\logmsg.obj &
+ $(cvs_srcdir)\main.obj &
+ $(cvs_srcdir)\mkmodules.obj &
+ $(cvs_srcdir)\modules.obj &
+ $(cvs_srcdir)\myndbm.obj &
+ $(cvs_srcdir)\no_diff.obj &
+ $(cvs_srcdir)\parseinfo.obj &
+ $(cvs_srcdir)\patch.obj &
+ $(cvs_srcdir)\rcs.obj &
+ $(cvs_srcdir)\rcscmds.obj &
+ $(cvs_srcdir)\recurse.obj &
+ $(cvs_srcdir)\release.obj &
+ $(cvs_srcdir)\remove.obj &
+ $(cvs_srcdir)\repos.obj &
+ $(cvs_srcdir)\root.obj &
+ $(cvs_srcdir)\rtag.obj &
+ $(cvs_srcdir)\scramble.obj &
+ $(cvs_srcdir)\server.obj &
+ $(cvs_srcdir)\status.obj &
+ $(cvs_srcdir)\subr.obj &
+ $(cvs_srcdir)\tag.obj &
+ $(cvs_srcdir)\update.obj &
+ $(cvs_srcdir)\watch.obj &
+ $(cvs_srcdir)\wrapper.obj &
+ $(cvs_srcdir)\vers_ts.obj &
+ $(cvs_srcdir)\version.obj &
+ $(cvs_srcdir)\zlib.obj
+# end of $COMMON_OBJECTS
+
+# objects from ..\lib
+LIB_OBJECTS = &
+ $(lib_dir)\getopt.obj &
+ $(lib_dir)\getopt1.obj &
+ $(lib_dir)\getline.obj &
+ $(lib_dir)\getwd.obj &
+ $(lib_dir)\savecwd.obj &
+ $(lib_dir)\sighandle.obj &
+ $(lib_dir)\yesno.obj &
+ $(lib_dir)\vasprintf.obj &
+ $(lib_dir)\xgetwd.obj &
+ $(lib_dir)\md5.obj &
+ $(lib_dir)\fnmatch.obj &
+ $(lib_dir)\regex.obj &
+ $(lib_dir)\getdate.obj &
+ $(lib_dir)\valloc.obj
+
+ZLIB_OBJECTS = &
+ $(zlib_dir)\adler32.obj &
+ $(zlib_dir)\compress.obj &
+ $(zlib_dir)\crc32.obj &
+ $(zlib_dir)\uncompr.obj &
+ $(zlib_dir)\deflate.obj &
+ $(zlib_dir)\trees.obj &
+ $(zlib_dir)\zutil.obj &
+ $(zlib_dir)\inflate.obj &
+ $(zlib_dir)\infblock.obj &
+ $(zlib_dir)\inftrees.obj &
+ $(zlib_dir)\infcodes.obj &
+ $(zlib_dir)\infutil.obj &
+ $(zlib_dir)\inffast.obj
+
+OBJECTS = $(COMMON_OBJECTS) $(LIB_OBJECTS) $(OS2_OBJECTS) $(ZLIB_OBJECTS)
+
+cvs.exe: $(OBJECTS)
+ $(LD) SYSTEM os2v2 DEBUG all NAME cvs.exe OPTION dosseg &
+ OPTION stack=32K FILE $(cvs_srcdir)\*.obj,$(lib_dir)\*.obj, &
+ $(srcdir)\*.obj,$(zlib_dir)\*.obj &
+ LIBRARY $(tcpip_libdir)\tcp32dll.lib, &
+ $(tcpip_libdir)\so32dll.lib
+
+strip: cvs.exe .SYMBOLIC
+ -wstrip cvs.exe
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 0000000..dcdd952
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,13 @@
+*.bb
+*.bbg
+*.da
+.deps
+.pure
+Makefile
+TAGS
+check.log
+check.plog
+cvs
+cvsbug
+mkmodules
+sanity.config.sh
diff --git a/src/ChangeLog b/src/ChangeLog
new file mode 100644
index 0000000..cbfb1ac
--- /dev/null
+++ b/src/ChangeLog
@@ -0,0 +1,14075 @@
+2005-09-30 Larry Jones <lawrence.jones@ugs.com>
+
+ * expand_path.c (expand_path): Fix memory leaks.
+
+2005-09-29 Mark D. Baushke <mdb@gnu.org>
+
+ * main.c (main): Simplify commitid creation.
+
+ * main.c (main): Not all hosts support O_NOCTTY for open.
+ Try to use more random data when time() returns -1.
+
+2005-09-29 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Check for error return from time().
+
+2005-09-29 Paul Eggert <eggert@CS.UCLA.EDU>
+ Derek Price <derek@ximbiot.com>
+
+ * client.c (handle_m, handle_e): Remove incomplete workaround for
+ O_NONBLOCK problem; no longer needed because of the fix below.
+ * cvs.h (piped_child): New bool argument saying whether O_NONBLOCK
+ fix is needed. All uses changed.
+ * rsh-client.c (start_rsh_server): We need the O_NONBLOCK fix,
+ so pass 'true' to piped_child to enable the workaround.
+ * run.c (work_around_openssh_glitch): New function.
+ (piped_child): Use it if the fix is requested. Avoid call call to
+ vfork with undefined behavior.
+
+2005-09-29 Mark D. Baushke <mdb@gnu.org>
+
+ * main.c (main): Rename N as COMMITID_RAW_SIZE.
+ Use base62 encoding for non-urandom case.
+
+2005-09-29 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (fd_buffer_input), client.c (handle_m, handle_e): Use new
+ fd_select in place of select.
+
+ * subr.c: Remove select includes - the sleep functions are now in
+ lib.
+
+2005-09-28 Mark D. Baushke <mdb@gnu.org>
+
+ * main.c (N, RANDOM_BYTES): New constants for base62 conversion.
+ (divide_by): Used in base62 conversion.
+ (convert): Ditto.
+ (main): Set global_session_id using more random data and the
+ current time in base62 if possible, otherwise fallback to the old
+ method.
+
+2005-09-25 Conrad T. Pino <Conrad@Pino.com>
+
+ * rcs.c: Use "#ifdef HAVE_FSYNC" just like every where else.
+
+2005-09-25 Conrad T. Pino <Conrad@Pino.com>
+
+ * buffer.c client.h socket-client.h: Remove HAVE_WINSOCK_H macro &
+ change <winsock.h> to <sys/socket.h> include.
+
+ * server.c: Remove HAVE_WINSOCK_H and <winsock.h> include.
+
+2005-09-25 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (rcs_internal_unlockfile): Fsync files before renaming them.
+ Patch from Rahul Bhargava <rahul@wandisco.com>.
+
+ * cvs.h, filesubr.c, main.c, server.c:
+ s/push_cvs_tmp_dir/push_cvs_temp_dir/.
+
+ * main.c (get_cvs_temp_dir): Use new get_system_temp_dir function.
+ (push_env_temp_dir): Move to...
+ * filesubr.c (push_env_temp_dir): ...here to split from Windows.
+ (get_system_temp_dir): New function.
+ * cvs.h (get_cvs_temp_dir, push_env_temp_dir): Add protos.
+
+ * buffer.c (fd_buffer_input): Fix spelling in header comment block.
+
+2005-09-24 Derek Price <derek@ximbiot.com>
+
+ * socket-client.c: Check HAVE_CONFIG_H, not HAVE_CONFIG.
+
+ * socket-client.c, socket-client.h: Minor cleanup.
+
+ * Makefile.am (cvs_SOURCES): Move socket-client.[ch] to...
+ (EXTRA_cvs_SOURCES): ...here to avoid compiling them.
+ * socket-client.c (init_sockaddr), socket-client.h (init_sockaddr):
+ Move to...
+ * client.c (init_sockaddr), client.c (init_sockaddr): ...here.
+
+ * socket-client.c (socket_buffer_input): Avoid overflow problems.
+
+ * socket-client.c: General cleanup.
+
+2005-09-23 Larry Jones <lawrence.jones@ugs.com>
+
+ * checkout.c (export_usage): Note that -r requires a tag.
+
+2005-09-22 Derek Price <derek@ximbiot.com>
+
+ * classify.c (Classify_File): Correct comment.
+
+2005-09-22 Larry Jones <lawrence.jones@ugs.com>
+
+ * patch.c (patch_usage): Document -k option.
+
+2005-09-22 Derek Price <derek@ximbiot.com>
+
+ * classify.c (Classify_File): If a file had a conflict and the
+ timestamp hasn't changed, it still has a conflict. Add comment about
+ how T_MODIFIED could later turn out to have conflict markers and why
+ it should not be checked in this function.
+ * client.c (send_fileproc): Don't send contents for files known to have
+ conflicts unless this is for `cvs diff'.
+ * commit.c (check_fileproc): T_CONFLICT should be handled like
+ T_MODIFIED, since force could be requested. Simplify logic since
+ T_CONFLICT can now be trusted.
+ * rcs.c (RCS_Checkout): Comment noexec behavior in header block.
+ * server.c (serve_unchanged, serve_is_modified): Handle conflicts.
+ * status.c (status_fileproc): Trust T_CONFLICT to simplify.
+ * subr.c (file_has_conflict): Removed.
+ * subr.h (file_has_conflict): Remove proto.
+ * update.c (update_fileproc): Trust T_CONFLICT.
+ (RegisterMerge): New function factored from...
+ (merge_file, join_file): ...these two functions.
+ * vers_ts.c (time_stamp_server): Handle = conflict timestamps in server
+ entdata.
+ * sanity.sh (files-12): Account for slight behavior improvement.
+ (status, conflicts, mwrap): Account for corrected behavior.
+ (join-readonly-conflict-10): Correct comment.
+ (binfiles-con1b): New test for correct behavior.
+
+ * classify.c (Classify_File): Consolidate redundant conditionals.
+
+2005-09-21 Derek Price <derek@ximbiot.com>
+
+ * entries.c: Remove obsolete comment.
+
+2005-09-20 Derek Price <derek@ximbiot.com>
+
+ * myndbm.c: #include getdelim.h for Windows.
+
+ * main.c: #include setenv.h for Windows.
+
+2005-09-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (modules5-8): Rename...
+ (modules5-8r): ...to this and comment Mac OS X failure.
+ Comment Solaris 9 failure below with a `FIXME?' tag.
+
+ * sanity.sh: Remove previous hack in favor of setting TESTDIR on
+ Solaris (and Mac OS X) until problem is solved correctly.
+
+2005-09-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Use /bin/pwd to verify current dir since Solaris 9 is
+ sometimes resolving symlinked paths.
+
+2005-09-14 Derek Price <derek@ximbiot.com>
+
+ * edit.c (edit_usage, unedit_usage, editors_usage), watch.c
+ (watch_usage, watchers_usage): Add quotes and reword for clarity and
+ consistency.
+
+ * edit.c (edit_usage): Add missing syntax. Reword description for
+ clarity. Mention default behavior.
+
+2005-09-13 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh ($anyusername): Reduce charset to that allowed on Linux.
+
+ * sanity.sh ($anyusername): Make more robust and expand comments.
+ Reported by Mark D. Baushke <mdb@gnu.org>.
+
+ * sanity.sh: Split $username into $username & $username8. Rename
+ $author as $anyusername.
+
+2005-09-12 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (username): Cut $username down to 8 characters when longer,
+ since that is all that appears in output.
+
+2005-09-11 Derek Price <derek@ximbiot.com>
+
+ [bug #14504]
+ * main.c (main): Set server_hostname before it is used by
+ gserver_authenticate_connection.
+ (Report from Serguei E. Leontiev <leo@sai.msu.ru>.)
+
+2005-09-08 Larry Jones <lawrence.jones@ugs.com>
+
+ * server.c (parseServerOptions): getopt() returns int, not char.
+
+2005-09-07 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_parse): Minor reformatting.
+
+ Close <http://savannah.nongnu.org/bugs/?func=detailitem&item_id=14462>.
+ * rcs.c (RCS_parse): Free variable *after* using it for the last time.
+
+2005-09-06 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (tempfile): All CVS temp files start with "cvs".
+
+ * sanity.sh (tempfile): New var.
+ (tempname): Set to $TMPDIR/$tempfile after $TMPDIR is set.
+ (info): s#$TMPDIR/##.
+
+ * rcs.c (RCS_putdtree): Remove unused variable.
+
+2005-09-06 Mark D. Baushke <mdb@gnu.org>
+
+ Close <https://savannah.nongnu.org/bugs/?func=detailitem&item_id=14435>.
+ * rcs.c (RCS_putdtree): Avoid stack overflow which may be
+ possible with excessive recursive calls to RCS_putdtree().
+ (Patch from Serg Masyutin.)
+
+2005-09-06 Derek Price <derek@ximbiot.com>
+
+ Close <http://savannah.nongnu.org/bugs/?func=detailitem&item_id=14448>.
+ * kerberos-client.c (start_kerberos4_server): Pass new root arg to
+ make_bufs_from_fds.
+ (Patch from <Manuel.Guijarro.AT.cern.ch>.)
+
+ * server.c: Reorganize includes slightly and alphabetize sections.
+
+ * server.c: #include canon-host.h.
+ (gserver_authenticate_connection): Print out canon-host errors.
+ * subr.c: #include canon-host.h.
+ (isThisHost): Print out canon-host errors.
+
+ * parseinfo.c (parse_config): Don't check hostname without client
+ or server support.
+
+ * main.c (main): Set cvs_cmd_name before calling parseServerOptions.
+
+2005-09-05 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (Tmpdir): Remove global decl.
+ (get_cvs_tmp_dir, push_env_tmp_dir): New protos.
+ * filesubr.c (cvs_temp_file): Use get_cvs_tmp_dir.
+ * main.c (Tmpdir): Remove global.
+ (tmpdir_cmdline, tmpdir_env): New globals.
+ (get_cvs_tmp_dir, push_env_tmp_dir): New functions.
+ (main): Discard most tmpdir overhead in favor of new globals and
+ functions.
+ * parseinfo.c (parse_config): Parse TmpDir.
+ * sanity.sh (config4): New tests.
+ * server.c (serve_root): Set env TMPDIR after parsing config. Create
+ tmpdir here instead of...
+ (serve_co, server): ...either of thse locations.
+ (server_cleanup): Use new function in favor of obsolete Tmpdir.
+
+ * sanity.sh (config2): Don't overwrite potentially significant config.
+
+ * sanity.sh (info): Use $tempfile instead of reproducing the regex.
+
+ * sanity.sh (info): Accept `.' in temp file names.
+
+ * main (main): Set the actual PID, not a pointer to a string.
+
+2005-09-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (config3): Generalize.
+
+ * main.c (main), server.c (serve_root, switch_to_user): Replace putenv
+ with GNULIB setenv.
+ * sanity.config.sh.in (HAVE_PUTENV): Remove.
+ * sanity.sh (env): Remove reference to $HAVE_PUTENV.
+
+ * sanity.sh (tests): Add config2 & config3.
+
+ * server.c (isSamePath, isThisHost): Move to...
+ * subr.c (isSamePath, isThisHost): ...here.
+ * subr.h (isSamePath, isThisHost): Add protos.
+ * parseinfo.c (parse_config): Handle [rootspec] syntax.
+ * main.c (main): Always set server_hostname.
+ * sanity.sh (config3): New tests for same.
+
+ * server.c (gserver_authenticate_connection): Output hostname in
+ error message.
+
+ * server.c (isThisHost): Fix typo.
+
+ * server.c (isThisHost, gserver_authenticate_connection): Simplify
+ using canon_host().
+
+ * root.c (free_cvsroot_t): Update header comment.
+
+ * root.c (new_cvsroot_t): directory is not client-specific.
+ (free_cvsroot_t): Declare static.
+ * root.h (free_cvsroot_t): Remove proto.
+ * server.c (server_init): Don't free cvsroot_t when finished with it.
+
+2005-09-03 Derek Price <derek@ximbiot.com>
+
+ * root.h (cvsroot_t->isremote): Update comment.
+
+ * history.c (read_hrecs_file): Suppress signed/unsigned char warning.
+
+ * root.h (cvsroot_t->isremote): Declare bool.
+ * root.c (new_cvsroot_t): Initialize isremote to false instead of 0.
+
+ * add.c (add_usage): Standardize usage message somewhat.
+
+2005-09-02 Larry Jones <lawrence.jones@ugs.com>
+
+ * commit.c (checkaddfile): Improve error messages for lock_RCS failure.
+ * release.c (release): Improve error message for pclose failure.
+
+ * root.h (struct cvsroot_s): Always declare isremote to simplify
+ other code. Simplify referencing code.
+ * root.c (new_cvsroot_t): Always initialize isremote.
+ * server.h: Always declare server_active to simplify other code.
+ Simplify referencing code.
+ * server.c: Always define server_active.
+
+2005-09-02 Larry Jones <lawrence.jones@ugs.com>
+
+ * parseinfo.c (parse_config): Variable declarations must precede
+ executable code for pre-C99 compilers. Pass correct line number
+ variable to expand_path.
+
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * recurse.c: Update bug report email address.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (expand_path): Update proto.
+ * expand_path.c (expand_variable): Accept and use cvsroot arg inplace
+ of global.
+ (expand_path): Accept and pass through cvsroot arg.
+ * main.c (main): Prescan args for config path before config options are
+ used. Pass config path on as needed. Update comment.
+ * modules.c (do_module): Update expand_path call.
+ * parseinfo.ci (Parse_Info): Ditto.
+ (allowed_config_prefixes): New global.
+ (parse_config): Accept configPath arg, update expand_path calls, and
+ expand LockDir path.
+ * parseinfo.h (parse_config): Update proto.
+ * root.c (root_allow_add, get_root_allow_config): Accept new configPath
+ arg and pass through to parse_config.
+ * root.h (root_allow_add, get_root_allow_config): Update protos.
+ * server.c (gConfigPath, server_usage): New globals.
+ (parseServerOptions): New function.
+ (server): Use new usage var.
+ (pserver_authenticate_connection): Update get_root_allow_config call.
+ * server.h (parseServerOptions): New proto.
+ * wrapper.c (wrap_add): Update expand_path calls.
+ * sanity.sh (server): New tests for setting config file path.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (close-stdout): Remove archive dir when done.
+
+2005-08-31 Larry Jones <lawrence.jones@ugs.com>
+
+ * import.c (import_descend): Lock repository directory during import.
+
+2005-08-31 Derek Price <derek@ximbiot.com>
+
+ * server.c (isSamePath): Compare args rather than assuming values.
+
+2005-08-29 Derek Price <derek@ximbiot.com>
+
+ Add %{sV} format string to verifymsg script.
+ * logmsg.c (do_verify): Accept change list arg, pass through to...
+ (verifymsg_proc): ...here, to pass through to format_cmdline.
+ * commit.c (commit_fileproc, commit_direntproc), import.c (update):
+ Update all callers of do_verify.
+ * cvs.h (do_verify): Update proto.
+ * sanity.sh (info): Test new verifymsg format strings.
+
+2005-08-09 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Remove debugging echo.
+ (watch6, watch6-0): Clean up properly.
+
+2005-08-03 Jim Hyslop <jhyslop@dreampossible.ca>
+
+ * edit.c, watch.c, watch.h, sanity.sh: fixed problems with watch not
+ setting default attributes, when directory specified.
+
+2005-07-20 Derek Price <derek@ximbiot.com>
+
+ * main.c: s/cvshome.org/nongnu.org.etc.../.
+
+2005-07-12 Derek Price <derek@ximbiot.com>
+
+ * buffer.c, buffer.h, client.h, expand_path.c, history.c, myndbm.h,
+ release.c: Add copyright notices.
+
+2005-07-12 Derek Price <derek@ximbiot.com>
+
+ * client.c: Update fwrite usage to use size & count in the standard
+ order.
+
+2005-07-11 Derek Price <derek@ximbiot.com>
+
+ * buffer.c, buffer.h, client.h, expand_path.c, history.c, myndbm.h,
+ release.c: Update license notices.
+
+2005-06-28 Derek Price <derek@ximbiot.com>
+
+ * server.c (serve_co): Remove obsolete support for Repository request.
+
+2005-06-10 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c, ignore.c, import.c, vers_ts.c: Include "lstat.h".
+
+2005-06-10 Derek Price <derek@ximbiot.com>
+
+ * logmsg.c (logmsg_list_to_args_proc): Add format character for
+ destination tag.
+ (Original patch from Todd Vierling <tv@duh.org>).
+
+ * tag.c (pretag_list_to_args_proc): Likewise.
+ (check_fileproc): Set destination tag name.
+ (tag_delproc): Delete destination tag name.
+ * sanity.sh (info, taginfo): Test new format strings.
+
+2005-06-08 Derek Price <derek@ximbiot.com>
+
+ * parseinfo.c: Restore comparison to NULL in assignment within
+ conditional to placate non-GNU compilers. Eliminate assignments in
+ conditionals where possible by GNU coding standards. Eliminate other
+ comparisons to NULL where possible.
+ (Parse_Info): Make int a true bool.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * client.c (force_gzip): New static global.
+ (handle_force_gzip): New function.
+ (responses): Add `Force-gzip'.
+ (start_server): Turn on encryption and compression before potentially
+ sending other rooted requests. Turn on compression when requested by
+ the user or the server.
+ * main.c (opt_usage): Note that -z<level> *requests* compression
+ <level> from the server.
+ * parseinfo.c (new_config): Initialize MaxCompressionLevel.
+ (parse_config): Parse MinCompressionLevel & MaxCompressionLevel.
+ * parseinfo.h (struct config): Add MinCompressionLevel &
+ MaxCompressionLevel.
+ * server.c (pending_warning_text): New static global.
+ (print_pending_error): Print pending warnings too.
+ (warning_pending): New macro.
+ (alloc_pending_internal): New function with much content...
+ (alloc_pending): ...previously from here.
+ (alloc_pending_warning): New function.
+ (server_root, serve_gzip_contents, gzip_stream): Force gzip_level into
+ configured restrictions.
+ (serve_command_prep): Print pending errors.
+ (requests): Make `Gzip-stream', `gzip-file-contents',
+ `Kerberos-encrypt', `Gssapi-encrypt', & `Gssapi-authenticate' requests
+ rootless to allow them before compression starts.
+ (serve_valid_requests): Send `Force-gzip' response when needed.
+ (server): Abort if a rootless compression request forced compression
+ outside restricted levels.
+ * zlib.c (struct compress_buffer, compress_buffer_initialize): Store
+ compression level.
+ (compress_buffer_output): Reset compression level when global
+ gzip_level has changed.
+ * sanity.sh (config2): New tests for compression restrictions.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * zlib.c (compress_buffer_input): Update comment.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * error.c (error): Correct spelling and grammar in comment.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * modules.c (my_module), wrappers.c (wrap_add): Use new expand_path
+ API.
+
+2005-06-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (expand_path): Rearrange args and use bool for formatsafe flag.
+ * expand_path.c: Globally: Remove init of globals to NULL by C89,
+ reformat to CVS conventions, remove unnecessary comparisons to NULL and
+ 0, & remove unnecessary typecasts.
+ (expand_variable): Remove proto and move function above first use.
+ Make return value const.
+ (expand_path): Don't refer to var when contents are known. Rearrange
+ args per cvs.h changes. Improve header comment block.
+ * parseinfo.c (Parse_Info): Use new expand_path API.
+
+2005-06-02 Derek Price <derek@ximbiot.com>
+
+ * client.c: Don't set NULL for globals by C89. Globally remove
+ comparisons to NULL or replace with !. Similarly remove or replace
+ comparisons of strcmp and strncmp return value to 0. Remove some
+ unneeded braces around single-element blocks.
+ (handle_*): Remove unecessary protos.
+ (handle_notified, notified_a_file): Move up before first use.
+
+2005-06-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (config): Simplify cleanup.
+
+2005-06-02 Derek Price <derek@ximbiot.com>
+
+ * zlib.c (compress_buffer_input): Don't request more bytes from the
+ underlying buffer than asked for.
+ (compress_buffer_shutdown_input): Don't attempt to read EOF from the
+ client during shutdown. It might never be sent.
+ * sanity.sh (abspath2): Test for this.
+
+2005-05-31 Derek Price <derek@ximbiot.com>
+
+ * rcscmds.c (call_diff_argc_allocated): Rename to...
+ (call_diff_arg_allocated): ...to match similar usage in other files.
+
+2005-05-31 Derek Price <derek@ximbiot.com>
+ for Alexander Taler <alex@0--0.org>
+
+ * rcscmds.c: Change type of call_diff_argc_allocated from int to
+ size_t, to match the prototype of run_add_arg_p(). This fixes a
+ bus error in OpenBSD 3.6 sparc64.
+
+2005-05-27 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_arg): Make arg const. Remove unnecessary copy to
+ buffer.
+ (send_option_string): Rename to...
+ (send_options): ...this and accept argc/argv in place of string.
+ * client.h: Update protos to match the changes to client.c.
+ * cvs.h (RCS_exec_rcsdiff, diff_exec): Update protos.
+ (run_add_arg_p, run_arg_free_p): New protos.
+ * diff.c (opts, opts_allocated): Replace with...
+ (diff_argv, diff_argc, diff_arg_allocated): ...these.
+ (add_diff_args): New convenience function.
+ (diff): Use new constructs and APIs.
+ * patch.c (patch_fileproc, RCS_checkin, RCS_delete_revs), rcscmds.c
+ (call_diff_add_arg, call_diff_setup, RCS_merge, RCS_exec_rcsdiff,
+ diff_exec, RCS_output_diff_options), update.c (patch_file): Use new
+ APIs.
+ * run.c (run_add_arg_p, run_arg_free_p): New functions.
+ (run_argc_allocated): Make size_t.
+ (run_setup, run_add_arg): Use new functions.
+ * sanity.sh: Accomodate above changes.
+ (rcslib-diffrgx-3): Slip in test for space splitting.
+
+2005-05-26 Derek Price <derek@ximbiot.com>
+
+ * subr.c (isabsolute), subr.h (isabsolute): Remove this function.
+ * root.c: Likewise, plus some reformatting.
+ * checkout.c, client.c, find_names.c, import.c, modules.c, parseinfo.c,
+ repos.c, root.c, server.c, subr.c: s/isabsolute/ISABSOLUTE/.
+
+2005-05-26 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Move "system.h" include before GNULIB includes. Move some
+ GNULIB includes from "system.h".
+
+2005-05-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * buffer.c, buffer.h: Add & use typedefs for function pointer arguments
+ and struct buffer function pointers. New typedefs are useful in casts.
+ * socket-client.c: Function pointers passed to buf_initialize use size_t
+ not int arguments. buf_initialize warnings are gone from Windows build.
+
+2005-05-24 Derek Price <derek@ximbiot.com>
+
+ * client.c, entries.c, filesubr.c, hardlink.c, ignore.c, import.c,
+ lock.c, logmsg.c, mkmodules.c, rcs.c, rcscmds.c, server.c, subr.c,
+ update.c, vers_ts.c: s/CVS_STAT/stat/ & s/CVS_LSTAT/lstat/.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (xresolvepath): Move to...
+ * subr.c (xcanonicalize_file_name): ...here and rename. Use new
+ GNULIB canonicalize module.
+ * cvs.h (xresolvepath): Move proto...
+ * subr.h (xcanonicalize_file_name): ...here.
+ * checkout.c (safe_location), server.c (isSamePath): Use new function
+ name.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcslib-symlink-10): Accept empty result due to broken glob
+ in glibc 2.3.5.
+
+2005-05-18 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (config-9): Split to local/remote tests to avoid unportable
+ expr characters.
+
+2005-05-17 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Use a predictable umask.
+
+2005-05-13 Derek Price <derek@ximbiot.com>
+
+ * login.c (password_entry_parseline): Placate gcc -Wall.
+
+2005-05-11 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (find_files): New proto.
+ * find_names.c (find_files, strip_rcsext): New functions.
+ (find_rcs): Make arg const. Use new find_files. Improve header
+ comment block.
+ * history.c (histfile): Remove global.
+ (get_history_log_name): New function.
+ (history, history_write): Use new functions.
+ (read_hrecs_file): New function containing most content from...
+ (read_hrecs): ...this function, which now accepts a file list and calls
+ read_hrecs_file once for each file.
+ * parseinfo.c (parse_config): Parse HistoryLogPath & HistorySearchPath.
+ * parseinfo.h (struct config): Add HistoryLogPath & HistorySearchPath.
+ * sanity.sh (basic2-64): Remove obsolete comment.
+ (config): Test new history options.
+ (crerepos): Cleanup.
+
+2005-05-09 Derek Price <derek@ximbiot.com>
+
+ * error.c (error): Avoid unportable calls to vsyslog.
+
+2005-05-09 Derek Price <derek@ximbiot.com>
+
+ * history.c (history_write): Add FIXME.
+
+2005-05-09 Derek Price <derek@ximbiot.com>
+
+ * hash.c (removenode, mergelists): New function.
+ (delnode): Use removenode.
+ * hash.h (mergelists): New proto.
+
+2005-05-04 Derek Price <derek@ximbiot.com>
+
+ * error.c (error): Avoid recursion and syslog the problem.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * tag.c (is_in_val_tags): Remove unnecessary existance checking for the
+ val-tags file and just rely on open() to create it when necessary.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * tag.c (tag_check_valid): Don't verify the_val_args.found when it is
+ not initialized.
+
+2005-05-03 Derek Price <derek@ximbiot.com>
+
+ * add.c: Update comment to include the -k option. This resolves issue
+ #226 on cvshome.org.
+
+2005-05-02 Derek Price <derek@ximbiot.com>
+
+ Remove unnecessary level of indirection.
+ * lock.c (L_HISTORY_LOCK, L_VAL_TAGS_LOCK): Remove macros.
+ (internal_lock, internal_clear_lock): Accept lock as argument.
+ (history_lock, clear_history_lock, val_tags_lock, clear_val_tags_lock):
+ Replace old macro arg with an actual lock pointer.
+
+2005-05-02 Derek Price <derek@ximbiot.com>
+
+ * lock.c (internal_lock, internal_clear_lock): Add protos.
+ (history_lock, val_tags_lock): Return the chartered true/false status.
+
+2005-05-02 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (CVSHISTLCK): Rename macro to...
+ (CVSHISTORYLCK): ...this.
+ (CVSVALTAGSLCK): New macro.
+ (val_tags_lock, clear_val_tags_lock): New functions.
+ * lock.c (global_val_tags_lock): New global.
+ (Lock_Cleanup): Clean up after val-tags lock if necessary.
+ (L_HISTORY_LOCK, L_VAL_TAGS_LOCK): New local macros.
+ (internal_lock, val_tags_lock, clear_val_tags_lock): New functions.
+ (history_lock): Use new internal function.
+ * tag.c (is_in_val_tags, add_to_val_tags): New functions using the
+ write lock for val-tags and factored from...
+ (tag_check_valid): ...this function.
+ * sanity.sh (lockfiles-22): Add val-tags lock test.
+
+2005-04-30 Mark D. Baushke <mdb@cvshome.org>
+
+ * lock.c (global_readlock, global_writelock, global_history_lock):
+ Add missing alternatives for non-LOCK_COMPATIBILITY initialization.
+
+2005-04-28 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (history_lock, clear_history_lock): New protos.
+ * lock.c (struct lock): Add lockdirname.
+ (global_history_lock): New global.
+ (global_read_lock): Initialize.
+ (lock_name): Handle const args.
+ (lock_simple_remove): Factor out code in favor of clear_lock call.
+ (set_lock): Handle variable lockdirname.
+ (lock_filesdoneproc): Set new lockdirname.
+ (history_lock, clear_history_lock): New functions.
+ (clear_lock): Avoid segfault on missing lock.
+ (Lock_Cleanup): Clean up history locks when necessary.
+ * history.c (history_write): Use new lock.
+ * sanity.sh (lockfiles-20): Test new lock.
+
+2005-04-28 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (lockfiles): Port some locking tests over from 1.12.x.
+
+2005-04-28 Derek Price <derek@ximbiot.com>
+
+ * lock.c (clear_lock): Improve comment.
+
+2005-04-28 Derek Price <derek@ximbiot.com>
+
+ * lock.c (struct lock): Store lockdir name.
+ (masterlock): Remove global.
+ (remove_lock_files, clear_lock, set_lock): Update to compensate.
+
+2005-04-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c: Add support for <pam/pam_appl.h> to allow
+ --enable-pam to work on MacOSX 10.2 and newer.
+ (Pach from Moriyoshi Koizumi <moriyoshi@at.wakwak.com>.)
+
+2005-04-25 Derek Price <derek@ximbiot.com>
+
+ * mkmodules.c (mkmodules): Remove `#if 0' and reformat comment.
+
+2005-04-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * expand_path.c (expand_variable): Add SESSIONID and COMMITID
+ internal variables. Both return the unique global session id of
+ the CVS process. Passing this information to administrative
+ triggers seems reasonable. (The same feature exists in CVSNT and
+ the names were chosen to be the same as the CVSNT names.)
+
+ * sanity.sh (info): Add a test for $COMMITID and $SESSIONID.
+
+2005-04-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (rcs4): Fix a typo.
+
+2005-04-20 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcs5): Minor cosmetic change.
+
+2005-04-20 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (tests): Add rcs4.
+ (rcs5): Add comments.
+
+2005-04-20 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (expand_keywords): Avoid buffer overflow.
+ (Original patch from Stewart Brodie <stewart@eh.org>.)
+
+ * sanity.sh (rcs5): New tests for the above.
+
+2005-04-08 Derek Price <derek@ximbiot.com>
+
+ * edit.c (edit_fileproc, unedit_fileproc): s/GMT/-0000/.
+ * rcs.c (RCS_getrevtime): Ditto, & replace a sprintf into a static
+ buffer with an Xasprintf which creates a dynamic one.
+ * sanity.sh: Update tests to compensate.
+ (Original bug report from Ian Abbott <abbotti@mev.co.uk>.)
+
+2005-03-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * checkout.c (checkout_proc): Use Xasprintf/xstrdup instead of
+ xmalloc/strcpy+strcat.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * rcs.c (linevector_add): Use xnrealloc.
+ * server.c (serve_argument): Ditto.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * rcs.c (linevector_copy): Use xtimes in argument.
+
+ * patch.c (patch): Remove dead code.
+
+ * lock.c (set_readlock_name): Use Xasprintf instead of
+ xmalloc/sprintf.
+ (lock_exists, set_promotable_lock, lock_wait): Ditto.
+ (lock_obtained, lock_dir_for_write): Ditto.
+ * log.c (rlog_proc): Ditto.
+
+ * ignore.c (ign_dir_add): Use xnrealloc.
+ * modules.c (save_d): Ditto.
+ * rcs.c (linevector_copy): Ditto.
+
+ * add.c (add): Use xstrdup instead of xmalloc/strcpy.
+ * client.c (client_process_import_file): Ditto.
+ * kerberos4-client.c (start_kerberos4_server): Ditto.
+ * logmsg.c (verifymsg_proc): Ditto.
+ * log.c (log_expand_revlist): Ditto.
+ * patch.c (patch_fileproc): Ditto.
+ * rcs.c (RCS_tag2rev, RCS_nodeisbranch, RCS_getbranch): Ditto.
+ (RCS_getdatebranch, expand_keywords, RCS_addbranch): Ditto.
+ (RCS_checkin): Ditto.
+ * remove.c (remove_fileproc): Ditto.
+
+2005-03-18 Derek Price <derek@ximbiot.com>
+
+ * server.c: Reindent pragmas.
+ (become_proxy): Add parentheses for -Wall.
+
+2005-03-18 Derek Price <derek@ximbiot.com>
+
+ * error.c (error): Simplify using vasnprintf.
+
+2005-03-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * admin.c (postadmin_proc): Cast NULL when it is an argument to
+ stdarg function to ensure it is the correct type.
+ * commit.c (precommit_proc): Ditto.
+ * edit.c (notify_proc): Ditto.
+ * fileattr.c (postwatch_proc): Ditto.
+ * logmsg.c (logfile_write, verifymsg_proc): Ditto.
+ * server.c (prepost_proxy_proc): Ditto.
+ * subr.c (cmdlineescape): Ditto.
+ * tag.c (posttag_proc): Ditto.
+ (Thanks to a report from Derek Price <derek@ximbiot.com>.)
+
+2005-03-17 Derek Price <derek@ximbiot.com>
+
+ * rcs.h (RCSNode): Improve comment.
+ * rcs.c (RCS_head): Ditto, plus gratuitous reformatting.
+
+2005-03-17 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_deltas): Use rcs->print_path.
+
+2005-03-17 Derek Price <derek@ximbiot.com>
+
+ * login.c (password_entry_parseline): Avoid using uninitialized
+ variable.
+ * rcs.c (RCS_deltas): Avoid buffer overflow.
+ (RCS_checkout): Avoid using uninitialized loglen.
+ * patch.c (patch_fileproc): Free original pointer, not one that may
+ have been incremented.
+ (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.)
+
+2005-03-17 Derek Price <derek@ximbiot.com>
+
+ * commit.c (checkaddfile): Avoid dereferencing a NULL pointer in
+ response to a rare error.
+ * admin.c (admin_fileproc), log.c (log_expand_revlist), mkmodules.c
+ (checkout_file), rcs.c (RCS_getdate, RCS_deltas, RCS_findlock_or_tip,
+ RCS_tag2rev): Avoid dereferencing NULL pointer.
+ (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.)
+
+2005-03-17 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_reparsercsfile): Avoid memory leak.
+ (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.)
+
+2005-03-17 Derek Price <derek@ximbiot.com>
+
+ * log.c (log_expand_revlist): Suppress message and not error handling
+ when really_quiet.
+
+2005-03-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * buffer.c (fd_buffer_shutdown): Replace (int *) 0 with NULL.
+ * server.c (do_cvs_command): Ditto.
+
+ * client.c (update_entries): Use xnmalloc.
+
+ * checkin.c (Checkin): Replace (char *) 0 with NULL.
+ * patch.c (patch_fileproc): Ditto.
+ * update.c (update_fileproc): Ditto.
+ * no_diff.c (No_Difference): Ditto.
+ * patch.c (patch_fileproc): Ditto.
+ * rcscmds.c (call_diff_setup, call_diff_add_arg): Ditto.
+
+ * update.c (join_file): Replace (RCSCHECKOUTPROC)0 with NULL.
+ * rcs.c (RCS_checkin, RCS_cmp_file, RCS_delete_revs)
+ (RCS_delete_revs): Ditto.
+ * rcscmds.c (RCS_merge, RCS_exec_rcsdiff): Ditto.
+
+ * annotate.c, checkin.c, classify.c, fileattr.c, find_names.c,
+ hash.c, lock.c, login.c, logmsg.c, main.c, modules.c, myndbm.c,
+ no_diff.c, patch.c, rcs.c, rcscmds.c, remove.c, server.c,
+ status.c, subr.c, tag.c, update.c, vers_ts.c: Avoid casting NULL.
+
+2005-03-17 Derek Price <derek@ximbiot.com>
+
+ * client.c (call_in_directory): Put function call after var decls.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * client.c (call_in_directory), commit.c (commit_filesdoneproc), log.c
+ (log_expand_revlist, log_version), logmsg.c (logfile_write), modules
+ (my_module), no_diff.c (No_Difference), parseinfo.c (Parse_Info), rcs.c
+ (RCS_deltas, RCS_checkin, RCS_addbranch, do_locks, do_symbols),
+ rcscmds.c (RCS_merge), root.c (parse_cvsroot, normalize_cvsroot),
+ update.c (merge_file): Verify assumptions via assertions.
+ (Thanks to (probably) incorrect reports from Alen Zukich
+ <alen.zukich@klocwork.com>.)
+
+2005-03-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * rcs.c (RCS_check_kflag): Use Xasprintf instead of
+ sprintf/xstrdup.
+
+ * mkmodules.c (checkout_file): Use Xasprintf instead of
+ xmalloc/strcpy+strcat.
+ * wrapper.c (wrap_unparse_rcs_options): Ditto.
+ (wrap_rcsoption): Ditto.
+
+ * subr.c (getcaller): Use Xasprintf instead of sprintf/xstrdup.
+
+ * history.c (history): Use Xasprintf instead of xmalloc/sprintf.
+ * lock.c (lock_name, set_lockers_name): Ditto.
+ * main.c (cmd_synonyms, main): Ditto.
+ * mkmodules.c (rename_rcsfile, init): Ditto
+ * modules.c (cat_module): Ditto.
+ * parseinfo.c (Parse_Info): Ditto.
+ * rcscmds.c (diff_exec, RCS_output_diff_options): Ditto.
+ * recurse.c (start_recursion, do_dir_proc): Ditto.
+ * remove.c (remove_fileproc): Ditto.
+ * repos.c (Name_Repository): Ditto.
+ * root.c (Name_Root, Create_Root): Ditto.
+ * status.c (status_fileproc, tag_list_proc): Ditto.
+ * wrapper.c (wrap_setup, wrap_tocvs_process_file): Ditto.
+
+ * hash.c (sortlist): Use xnmalloc.
+ * main.c (cmd_synonyms): Ditto.
+ * server.c (cvs_pam_conv): Ditto.
+
+ * create_adm.c (Create_Admin): Clean up use of Xasprintf/xstrdup.
+ * entries.c (WriteTag, base_walk): Ditto.
+ * modules.c (my_module): Ditto.
+
+ * wrapper.c (wrap_fromcvs_process_file): Use Xasprintf instead of
+ xmalloc/sprintf and clean up control flow.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * history.c (history_write): Remove test that always evaluates to
+ false.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * server.c (become_proxy): Close pipe to primary when pipe from it
+ closes.
+
+2005-03-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (debug-log-nonfatal): Only set CVS_CLIENT_LOG to the
+ old value if it was previously set.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * server.c (create_adm_p, serve_entry), tag.c (rtag_proc): Avoid memory
+ leaks.
+ (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.)
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * logmsg.c (do_verify): Don't check for NULL return from xfopen().
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (debug-log-nonfatal): New test.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (writeproxy-ssh-noredirect): Don't unconditionally create
+ a primary debug log.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (open_file): Move proto...
+ * subr.h (xfopen): ...here and rename.
+ * filesubr.c (open_file): Move function...
+ * subr.c (xfopen): ...here, with additional commenting and minor
+ cosmetic changes.
+ * add.c, checkout.c, client.c, cvsrc.c, edit.c, entries.c, filesubr.c,
+ logmsg.c, mkmodules.c, modules,c, patch.c, root.c, subr.c:
+ s/open_file/xfopen/.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c (setup_logfiles): Failure to open a debug log file
+ should be non-fatal.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * server.c (cvs_outerr): Quote error text in syslog messages.
+
+2005-03-15 Mark D. Baushke <mdb@cvshome.org>
+
+ * history.c (select_hrec): Avoid possible memory leak.
+
+2005-03-15 Derek Price <derek@ximbiot.com>
+
+ * patch.c (patch_proc): Avoid memory leak.
+ (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.)
+
+2005-03-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (receive_partial_file): Use ssize_t to deal with < 0
+ return value from write().
+
+2005-03-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * history.c (save_file): Bug fix from last change.
+
+2005-03-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * update.c (get_linkinfo_proc): Use Xasprintf instead of
+ xmalloc/sprintf. Gratuitous reformatting.
+ (update_ignproc, update_dirent_proc, checkout_file): Ditto.
+ (patch_file, merge_file, join_file): Ditto.
+ * modules.c (open_module): Ditto.
+
+ * modules (my_module): Use Xasprintf instead of xmalloc/sprintf
+ and avoid possibility of trying to free(NULL).
+
+ * subr.c (backup_file): Use Xasprintf instead of xmalloc/sprintf.
+ (cmdlinequote): Use Xasprintf instead of xmalloc/strcat+strlen.
+ * modules.c (my_module): Ditto.
+
+ * client.c (handle_module_expansion): Use xnmalloc, xnrealloc,
+ and xstrdup in place of xmalloc, xrealloc, and xmalloc/strcpy.
+ (start_server): Do not assume gzip_level precision encoding.
+ (send_modified): Do not assume 1024 bytes is sufficient for
+ a temporary filename.
+
+ * modules.c (my_module): Use xnmalloc and xnrealloc. Gratuitous
+ reformatting.
+ * subr.c (line2argv): Ditto.
+
+2005-03-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * modules.c (my_module): Protect against free (NULL) code path.
+
+2005-03-11 Derek Price <derek@ximbiot.com>
+
+ * annotate.c (rannotate_proc), fileattr.c (fileattr_write), rcs.c
+ (RCS_deltas), server.c (check_repository_password), update.c (update):
+ Avoid memory leaks.
+ (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.)
+
+2005-03-10 Derek Price <derek@ximbiot.com>
+
+ * diff.c (diff_fileproc): Remove unnecessary check for NULL.
+
+2005-03-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * commit.c: Gratuitous reformatting.
+ * entries.c: Ditto.
+ * import.c (import, import_descend): Ditto.
+
+ * commit.c (commit): Use xnmalloc. Gratuitous reformatting.
+ * history.c (save_user, save_file, save_module, read_hrecs): Ditto.
+ * ignore.c (ign_add): Ditto.
+
+ * hardlink.c (lookup_file_by_inode): Use Xasprintf instead of
+ xmalloc/sprintf. Gratuitous reformatting.
+ (update_hardlink_info, list_linked_files_on_disk): Ditto.
+ (find_checkedout_proc): Ditto.
+ * history.c (history, history_write, save_file): Ditto.
+ (select_hrec): Ditto.
+ * ignore.c (ign_setup, ignore_files): Ditto.
+ * import.c (process_import_file, import_descend_dir): Ditto.
+
+ * import.c (import_descend_dir): Use Xasprintf instead of
+ xmalloc/strcpy+strcat+strcat.
+
+ * history.c (read_hrecs): Make function argument a const.
+
+2005-03-10 Derek Price <derek@ximbiot.com>
+
+ * fileattr.c (fileattr_read): Only eat a newline when it really is a
+ newline.
+
+2005-03-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * zlib.c: Include "pagealign_alloc.h".
+
+2005-03-09 Derek Price <derek@ximbiot.com>
+
+ * add.c (add, add_directory), buffer.c (allocate_buffer_datas),
+ client.c (update_entries), commit.c (checkaddfile), entries.c
+ (Entries_Open), fileattr.c (fileattr_read), ignore.c (ign_add),
+ import.c (import), main.c (main), parseinfo.c (parse_config), rcs.c
+ (RCS_reparsercsfile, RCS_getbranchpoint, RCS_checkout,
+ RCS_delete_revs, apply_rcs_changes): Avoid memory leaks.
+ (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.)
+
+ * hardlink.c, hardlink.h: Avoid compiling entire contents of these
+ files w/o preserve permissions support.
+
+2005-03-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * history.c (history, save_file): Cleanup the API to match the
+ comments.
+
+2005-03-08 Derek Price <derek@ximbiot.com>
+
+ * rcs.c: Define MAP_FILE & MAP_FAILED when necessary.
+
+2005-03-08 Derek Price <derek@ximbiot.com>
+
+ * zlib.c (compress_buffer_input): Use pagealign_xalloc when allocating
+ buffer datas.
+ (compress_buffer_output, compress_buffer_flush,
+ compress_buffer_shutdown_output): Don't assume that BUFFER_DATA_SIZE is
+ a constant.
+ (Thanks to report from Larry Jones <lawrence.jones@ugs.com>.)
+
+2005-03-08 Larry Jones <lawrence.jones@ugs.com>
+
+ * release.c (release): Remove unneeded code.
+
+2005-03-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * buffer.h (buf_free_data): Compile with proxy disabled.
+ (Thanks to report from Larry Jones <lawrence.jones@ugs.com>.)
+
+2005-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * add.c (add_directory): Xasprintf instead of xmalloc/sprintf+strcat.
+ * admin.c (arg_add): Ditto.
+ (admin_fileproc, postadmin_proc, admin_fileproc): Gratuitous
+ reformatting.
+
+ * client.c (mode_to_string): Use Xasprintf.
+
+ * checkout.c (checkout): Xasprintf instead of xmalloc/sprintf.
+ Gratuitous reformatting.
+ * entries.c (WriteTag): Ditto
+ (subdir_record, base_walk): Ditto.
+ * fileattr.c (fileattr_read, fileattr_set, fileattr_write): Ditto.
+ * filesubr.c (deep_remove_dir, cvs_temp_file): Ditto.
+ (strcat_filename_onto_homedir): Ditto.
+ * find_names.c (Find_Names): Ditto.
+
+ * filesubr.c (expand_wild): Use xnmalloc instead of xmalloc.
+
+2005-03-07 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_free_data): Compile with proxy disabled.
+ (Thanks to report from Larry Jones <lawrence.jones@ugs.com>.)
+
+2005-03-07 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (packetizing_buffer_input, packetizing_buffer_output): Don't
+ assume BUFFER_DATA_SIZE is a constant.
+ (Thanks to report from Larry Jones <lawrence.jones@ugs.com>.)
+
+2005-03-03 Derek Price <derek@ximbiot.com>
+
+ Use new pagealign_alloc() and pagealign_free() functions in
+ lieu of maintaining pointers for reuse. On most systems this should be
+ faster.
+ * buffer.c: Include "pagealign_alloc.h".
+ (free_buffer_data): Remove this global.
+ (allocate_buffer_datas): Remove this function.
+ (buf_free, buf_send_output): Call buf_free_data().
+ (get_buffer_data): Use pagealign_alloc().
+ (buf_free_datas): New function.
+ (buf_send_output, buf_free_data, buf_read_file, buf_read_file_to_eof,
+ buf_read_short_line, buf_read_data, buf_copy_counted): Call
+ buf_free_datas().
+ * buffer.h: Include "getpagesize.h".
+ (BUFFER_DATA_SIZE): Default to getpagesize ();
+ * rcs.c: Lean on m4/mmap-anon.m4 to simplify mmap setup.
+
+2005-03-02 Jim Meyering <jim@meyering.net>
+
+ Detect and report write failure for e.g., cvs up -p FILE > /dev/full
+ * main.c: Include "closeout.h".
+ (main): Arrange to close standard output upon exit.
+ * sanity.sh (close-stdout): New test for this fix.
+
+2005-03-01 Mark D. Baushke <mdb@cvshome.org>
+
+ * checkout.c (emptydir_name): Xasprintf instead of
+ xmalloc/sprintf.
+
+ * add.c (add): Xasprintf instead of xmalloc/sprintf.
+ Gratuitous reformatting.
+ (add_directory, build_entry): Ditto.
+ * annotate.c (rannotate_proc): Ditto.
+ * checkout.c (checkout_proc): Ditto.
+ * client.c (call_in_directory): Ditto.
+ (template, send_dirent_proc): Ditto.
+ (client_process_import_file): Ditto.
+ * commit.c (check_fileproc, precommit_proc): Ditto.
+ (commit_fileproc, finaladd): Ditto.
+ (checkaddfile): Ditto.
+ * create_adm.c (Create_Admin): Ditto.
+ * edit.c (notify_do): Ditto.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * subr.c (get_date): Minor reformatting.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * subr.c (get_date): Replace obsolete timeb cruft in this stub.
+
+2005-02-28 Mark D. Baushke <mdb@cvshome.org>
+
+ * admin.c (arg_add): Use xnmalloc and xnrealloc.
+ (admin): Use xnmalloc. Minor reformatting.
+ Xasprintf instead of xmalloc/strcpy+strcat.
+ * client.c (client_expand_modules): Use xnmalloc.
+ Minor reformatting.
+ * cvsrc.c (read_cvsrc): Use xnmalloc and xnrealloc.
+ Minor reformatting.
+ * history.c (read_hrecs): Use xnrealloc. Minor reformatting.
+ * ignore.c (ign_add): Use xnrealloc. Minor reformatting.
+ * rcscmds.c (call_diff_add_arg): Use xnrealloc.
+ * wrapper.c (wrap_add_entry): Use xnrealloc. Gratuitous
+ reformatting.
+
+2005-02-28 Derek Price <derek@ximbiot.com>
+
+ * edit.c (notify_proc), logmsg.c (logfile_write): Minor reformatting.
+
+2005-02-28 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_root): Trigger a later error message rather than
+ maintaining two copies.
+
+2005-02-27 Mark D. Baushke <mdb@cvshome.org>
+
+ * client.c (connect_to_pserver): Use TRACE_FUNCTION, not 1 in
+ TRACE() calls.
+ (connect_to_pserver,send_modified): Ditto.
+ * create_adm.c (Create_Admin): Ditto.
+ * entries.c (Register, Scratch_Entry, WriteTemplate): Ditto.
+ * filesubr.c (copy_file, xchmod, rename_file): Ditto.
+ * history.c (history_write): Ditto.
+ * kerberos4-client.c (start_kerberos4_server): Ditto.
+ * no_diff.c (No_Difference): Ditto.
+ * parseinfo.c (Parse_Info): Ditto.
+ * rcs.c (RCS_checkout): Ditto.
+ * server.c (server_register): Ditto.
+ * update.c (join_file): Ditto.
+
+ * no_diff.c (No_Difference): Gratuitous reformatting.
+ * kerberos4-client.c (start_kerberos4_server): Ditto.
+
+2005-02-27 Jim Meyering <jim@meyering.net>
+
+ * login.c (password_entry_operation): Exit nonzero when
+ failing to close a just-appended-to .cvspass file.
+
+2005-02-26 Derek Price <derek@ximbiot.com>
+
+ * root.c: Gratuitous reformatting.
+
+2005-02-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * root.c (parse_cvsroot): Handle another Bad CVSROOT.
+ * sanity.sh (parseroot-8r): Test for it.
+ (Problem report from Hiroyuki Ikezoe <poincare@ikezoe.net>.)
+
+2005-02-26 Derek Price <derek@ximbiot.com>
+
+ * server.c: Include netdb.h with server support. Other reformatting.
+
+2005-02-25 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (multiroot2-9a): Correct for new TRACE message.
+
+2005-02-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (tag_check_valid): Declare NAME arg const.
+ * tag.c (tag_check_valid): Ditto, update to account for this.
+ Xasprintf instead of xmalloc/sprintf.
+
+2005-02-25 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_modified): Suppress a -Wall warning.
+
+2005-02-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (global_session_id): New global declaration.
+ * import.c (add_rcs_file), rcs.c (RCS_checkin): Save commitid.
+ * log.c (log_version), status.c (status_fileproc): Output commitid.
+ * main.c (global_session_id): Define new global.
+ (main): Create session ID.
+ * sanity.sh: Update to compensate.
+ (Original patch from Frank Hemer <frank@hemer.org>.)
+
+2005-02-24 Derek Price <derek@ximbiot.com>
+
+ * subr.h (cvs_trace, TRACE*): Move to...
+ * server.h: ...here.
+ * subr.c: Ditto, but to...
+ * server.c: ...here, and print out 'P' instead of 'S' for traces from
+ secondary (proxy) servers.
+
+2005-02-24 Derek Price <derek@ximbiot.com>
+
+ * admin.c (admin): Suppress warning with -Wall and --disable-client.
+ * server.c: Don't declare functions that won't be defined when
+ --disable-server.
+
+2005-02-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (primary-wrapper): Rename CVS_SERVER_LOG for the primary in
+ writeproxy mode to avoid overwriting.
+
+2005-02-24 Derek Price <derek@ximbiot.com>
+
+ * client.c (open_connection_to_server): Fail with an expressive error
+ message when connection is attempted via an unsupported protocol since
+ this is no longer caught in parse_root().
+ * edit.c (edit_fileproc), import.c (import): Don't verify
+ current_parsed_root->isremote without client support.
+ * parseinfo.c (parse_config): Parse PrimaryServer without proxy
+ support. Postpone method verification until the connect phase.
+ * parseinfo.h (struct config): Always include PrimaryServer.
+ * root.c (primary_root_translate, primary_root_inverse_translate):
+ Don't declare vars without PROXY_SUPPORT when they won't be used.
+ (parse_cvsroot): Parse remote connection methods with server support
+ for PrimaryServer/Redirects. Delay method support verification until
+ the connect phase.
+ * root.h (cvsroot_t): Include remote elements with SERVER_SUPPORT.
+ * server.c (isProxyServer): Delay method verification until the connect
+ phase.
+
+2005-02-23 Derek Price <derek@ximbiot.com>
+
+ * tag.c (tag): Handle -r<tag>:<date>.
+ * sanity.sh (tagdate-13.*): New tests.
+
+2005-02-23 Derek Price <derek@ximbiot.com>
+
+ * annotate.c (annotate), ls.c (ls): Handle -r<tag>:<date>.
+
+2005-02-23 Derek Price <derek@ximbiot.com>
+
+ * diff.c: Some reformatting.
+ (diff): Handle -r<tag>:<date>.
+ * sanity.sh (tagdate-13b): New test.
+
+2005-02-23 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (checkout): Use parse_tagdate.
+ * tag.c (tag_check_valid_join): Remove this function.
+ * cvs.h (tag_check_valid_join): Ditto for the proto.
+ (parse_tagdate): New proto.
+ (Make_Date): Make arg const.
+ * main.c (Make_Date): Ditto.
+ (parse_tagdate): New function.
+ * update.c (date_rev1, date_rev2): Rename these globals...
+ (join_date1, join_date2): ...to this.
+ (update): Use parse_tagdate.
+ (do_update): Use new API.
+ * update.h (do_update): Update proto.
+ * sanity.sh: Misc reformatting.
+ (tagdate-12): This test now passes.
+ (tagdate-12b): New test.
+ (multiroot-9a): Handle new TRACE.
+
+2005-02-23 Derek Price <derek@ximbiot.com>
+
+ * rsh-client.c (start_rsh_server): Update comment. Replace
+ malloc/sprintf combo with a call to Xasprintf.
+
+2005-02-22 Derek Price <derek@ximbiot.com>
+
+ * error.c (error): Handle unsigned int format char.
+ * parseinfo.c (parse_error): New function.
+ (parse_config): Keep track of line number and output it in error
+ messages.
+ * rcs.c (RCS_setlocalid): Accept file path and line number for error
+ messages. Add header comment block.
+ * rcs.h (RCS_setlocalid): Update prototype to match.
+ * parseinfo.h (parse_error): Declare new function.
+ * sanity.sh: Accept new --noredirect argument.
+ (checklongoptarg): Accept longoptmode as an argument
+ rather than via an environment variable.
+ (notnoredirect): New function.
+ (newroot): Handle root options.
+ (keywordexpand, config): Skip in noredirect mode. Update for new
+ config error messages.
+ (multiroot): Some reformatting.
+ (writeproxy, writeproxy-noredirect): Skip in noredirect mode.
+ (commit, writeproxy-noredirect): Quote CVSROOT arguments since they
+ might contain semicolons.
+
+2005-02-21 Mark D. Baushke <mdb@cvshome.org>
+
+ * import.c (import): Avoid using assert with side effects it may
+ be configured away using NDEBUG.
+ (Patch from Frank Hemer <frank@hemer.org>.)
+
+2005-02-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * main.c (main): Check the results from xgethostname(). Print a
+ message with the errno and use "localhost" if NULL is returned.
+
+2005-02-20 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (run_arg): Rename to...
+ (run_add_arg): New function.
+ * run.c (run_arg): Remove.
+ (run_add_arg): Remove static declaration.
+ (run_piped): New function.
+ * logmsg.c, modules.c: s/run_arg/run_add_arg/.
+ * release.c (release): Replace use of piped_child with a call
+ to run_piped to avoid quoting issues.
+ * sanity.sh (info-cleanup-0): Expect success.
+
+2005-02-19 Derek Price <derek@ximbiot.com>
+
+ * edit.c (unedit_fileproc, mark_up_to_date): Replace xmallc/strcat
+ sequence with single call to Xasprintf.
+
+2005-02-08 Derek Price <derek@ximbiot.com>
+
+ * rsh-client.c: Some reformatting.
+
+2005-02-04 Derek Price <derek@ximbiot.com>
+
+ * zlib.c (compress_buffer_input): Don't return EOF when there is data
+ pending.
+
+2005-02-01 Derek Price <derek@ximbiot.com>
+
+ * main.c: Update year in copyright notice to match GNU standards.
+ * sanity.sh (version-1): Update to match.
+
+2005-02-01 Larry Jones <lawrence.jones@ugs.com>
+
+ * log.c (log_fileproc, log_expand_revlist): Add support for BASE tag.
+ * sanity.sh (log): New tests for above.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * main.c: Rephrase --version message.
+ * sanity.sh (version-1): Update to match.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am, add.c, admin.c, annotate.c, checkin.c, checkout.c,
+ classify.c, commit.c, create_adm.c, cvs.h, cvsrc.c, diff.c, entries.c,
+ find_names.c, hash.c, hash.h, history.h, import.c, lock.c, log.c,
+ login.c, logmsg.c, main.c, mkmodules.c, modules.c, myndbm.c, no_diff.c,
+ parseinfo.c, patch.c, rcs.c, rcs.h, rcscmds.c, recurse.c, remove.c,
+ repos.c, root.c, root.h, server.h, stack.c, stack.h, status.c, subr.c,
+ tag.c, update.c, vers_ts.c, version.c: Update copyright notices.
+
+2005-01-29 Derek Price <derek@ximbiot.com>
+
+ * log.c (log_usage): Add note about using -S with revision info
+ supression and selection.
+ (Suggestion from Dan Peterson <dbpete@aol.com>.)
+
+2005-01-29 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (writeproxy-ssh-noredirect): Remove some commented out
+ code.
+
+2005-01-25 Larry Jones <lawrence.jones@ugs.com>
+
+ * expand_path.c (expand_path): Rewrite using offsets instead of
+ pointers to simplify and avoid reallocation bugs.
+ (Inspired by Jeremy Bopp <jeremy@motive.com>.)
+
+2005-01-20 Brian Murphy <brian@murphy.dk>
+
+ * server.c fixing the style of the pam function calls and if
+ statements
+
+2005-01-19 Brian Murphy <brian@murphy.dk>
+
+ * server.c (pam_username, pam_password) new global static
+ variables to hold the username and pasword for cvs_pam_conv.
+ (cvs_pam_conv) using pam_username and pam_password.
+ (check_pam_password) set pam_username, pam_password before
+ authentication and clear them when authentication is finished.
+ (server, switch_to_user) Check for pamh being set before using
+ pam functionality, NULL indicating that this user was authenticated
+ using the repository password file.
+
+2004-12-09 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c (buf_count_mem): Compile this for PROXY_SUPPORT.
+ (Report from Brad L. Chisholm <blc@bsdwins.com>.)
+
+2004-12-09 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (modules7): New test group.
+ (Based on a patch from Mark D. Baushke <mdb@cvshome.org>, based on a
+ report from Richard Verhoeven <Richard_Verhoeven@WestLB.de>.)
+
+2004-12-09 Derek Price <derek@ximbiot.com>
+
+ * client.c (start_server): Avoid advertising the Redirect response when
+ the user asked us not to.
+ * root.h (cvsroot_t): Add redirect field.
+ * root.c (new_cvsroot_t): Init redirect field.
+ (parse_cvsroot_t): Parse Redirect method option.
+ * server.c (serve_command_prep): Don't throw proxy_log away when
+ Redirect isn't supported and it might be needed later.
+ * sanity.sh (parseroot): Improve comment, add a few new tests.
+ (writeproxy-ssh): Specify Redirect=yes explicitly.
+ (writeproxy-ssh-noredirect): New test group.
+
+2004-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * main.c (usg): Remove Dr. Pascal Molli's CVS URL from the
+ documentation.
+
+2004-12-08 Derek Price <derek@ximbiot.com>
+
+ * root.c (Name_Root): s/TRACE_FUNCTION/TRACE_FLOW/.
+
+2004-12-08 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_cvsroot): Suppress -Wall warning.
+
+2004-12-08 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_cvsroot): findnode() compares LIST to NULL w/o help.
+
+2004-12-08 Derek Price <derek@ximbiot.com>
+
+ * root.c (Name_root), server.c (serve_referrer): Don't free cvsroot_t.
+ * server.sh (reposmv): Reaccount for multiple potential warnings and
+ comment.
+
+2004-12-07 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_cvsroot): Cache parsed values for efficiency and to
+ avoid printing warnings about non-fatal parsing errors multiple times.
+ * client.c,, login.c, main.c, recurse.c: Don't dispose of parsed roots,
+ parse_cvsroot() has control.
+ * sanity.sh (reposmv): Stop accounting for multiple warnings.
+
+2004-12-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * root.h (cvsroot_t): Add cvs_rsh and cvs_server for bookkeeping
+ purposes.
+ * root.c (new_cvsroot_t, free_cvsroot_t): Add support for case
+ insensitive options CVS_RSH and CVS_SERVER.
+ (parse_cvsroot): Ditto and make all keywords case insensitive.
+ * client.c (connect_to_forked_server): Add support for the new
+ "CVS_SERVER" option to CVSROOT.
+ * rsh-client.c (connect_to_forked_server): Ditto
+ (start_rsh_server): Ditto and add support for the new "CVS_RSH"
+ option to CVSROOT.
+ * sanity.sh (parseroot3): New tests for the new options to
+ CVSROOT.
+
+2004-11-30 Larry Jones <lawrence.jones@ugs.com>
+
+ * mkmodules.c (config_contents): Add LocalKeyword and KeywordExpand,
+ misc. cleanup.
+
+2004-11-30 Derek Price <derek@ximbiot.com>
+
+ * parseinfo.c (readBool): Update quotes in error message for
+ consistency. Move function to...
+ * subr.c (readBool): ...here.
+ (*): Gratuitous reformatting.
+ * cvs.h: Move all subr.c function prototypes to...
+ * subr.h: ...this new file.
+ * Makefile.am (cvs_SOURCES): Add subr.h.
+
+2004-11-30 Derek Price <derek@ximbiot.com>
+
+ * parseinfo.c (readBool): Reorder arguments to error() and improve
+ header comment.
+
+2004-11-30 Derek Price <derek@ximbiot.com>
+
+ * client.c (handle_referrer): New function.
+ (handle_redirect): Handle possibility that CLIENT_REFERRER was set via
+ a response.
+ * server.c (serve_command_prep): Send a normalized Referrer response
+ before a Redirect when the client supports it.
+
+2004-11-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * rcs.c (RCS_setlocalid): Do more configuration validation.
+ Include some gratuitous reformatting.
+ * sanity.sh (keywordexpand): Add tests for new validation code.
+
+2004-11-24 Derek Price <derek@ximbiot.com>
+
+ * server.c (become_proxy): Note assumptions about syncronized primary
+ and secondary versions with `FIXME?' note.
+
+2004-11-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (info): Ignore comments in verifymsg test.
+
+2004-11-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * mkmodules.c (loginfo_contents, verifymsg_contents,
+ commitinfo_contents, taginfo_contents, preproxy_contents,
+ postadmin_contents, postproxy_contents, posttag_contents,
+ postwatch_contents, notify_contents): Add comments regarding the
+ additional format strings that are available. Include some
+ gratuitous reformatting.
+
+2004-11-19 Derek Price <derek@ximbiot.com>
+
+ * subr.c (Xasnprintf): Improve header comment block.
+
+2004-11-19 Derek Price <derek@ximbiot.com>
+
+ * root.c (normalize_cvsroot): Improve header comment block.
+
+2004-11-19 Derek Price <derek@ximbiot.com>
+
+ * server.c: Misc reformatting and comment corrections.
+
+2004-11-19 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (hostname): Redeclare as pointer rather than array.
+ * main.c: Include xgethostname.h. Declare server_hostname.
+ (main): Use xgethostname(). Set server_hostname.
+ * server.c (MAXHOSTNAMELEN): Remove this macro.
+ (isThisHost): Reference global HOSTNAME rather than looking it up.
+ Improve header comment block.
+ (gserver_authenticate_connection): Likewise.
+ (serve_command_prep): Correct comment.
+ (serve_hostname): Don't bother to validate hostname length.
+
+2004-11-19 Derek Price <derek@ximbiot.com>
+
+ * server.c (isThisHost): strcasecmp before consulting the DNS as an
+ optimization.
+
+2004-11-18 Mark D. Baushke <mdb@cvshome.org>
+
+ * checkout.c (checkout_proc): Passing the repository to
+ tag_check_valid seems to stop the assertion failure in recurse.c
+ do_recursion.
+ * sanity.sh (basic2-21a): Removed.
+ (basic2-21c): Fixed.
+
+2004-11-18 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (skip_always, notproxy): New functions.
+ (skip, remoteonly, sshstdio, client): Use new functions.
+
+2004-11-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (basic2-21a): The val-tags file should have
+ at least 'rtagged-by-head y' in it. Test from cvs 1.11.18 that
+ shows fixed result.
+ (basic2-21b, basic2-21c): New tests showing a cvs bug when
+ val-tags is not present.
+ (Report from "John Elgin" <John@JCElgin.com>.)
+
+ * sanity.sh (basicb-21): POSIX 1003.2 specifies 'illegal option'
+ while lots of getopt implementations still use 'invalid option'.
+ Allow either form for this test.
+
+2004-11-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * buffer.c (fd_buffer_block): Deal with BSD and BSDI problems to
+ set block/nonblock on /dev/null.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (distclean-local): Clean check.plog~.
+
+2004-11-11 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: s/cp -r/cp -R/ to meet POSIX specification.
+ (Thanks to report from Paul Eggert <eggert@cs.ucla.edu>.)
+
+2004-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * ms-buffer.c (ms_buffer_input): Avoid UNICOS cc error where
+ 'Both sides of the assignment operator are not compatible.'
+
+ * sanity.sh (importc, rcs, rcs4, tagdate): Use TZ=UTC0 not TZ=UTC
+ to get proper POSIX behavior on MacOS X.
+
+2004-11-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Actually parse -e option like we claim to.
+
+2004-11-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Maintain pass/skip/warn status and output at end.
+ (usage): Note new functionality of -e.
+ (warn): New function.
+ (verify_tmp_empty): Warn instead of failing. Delete turds if warn()
+ doesn't exit.
+
+2004-11-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (verify_tmp_empty): New function.
+ (dotest_internal_*): Call verify_tmp_empty as needed.
+
+2004-11-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (expr_tooltest3): Bugfix. Use $expr rather than $EXPR.
+
+2004-11-08 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (version_test): Echo good version data to the log, even
+ when it went to stderr. Don't echo bad version data.
+
+2004-11-08 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (tool_find): Rewrite. API changed to allow a list of
+ tests to be used against a list of possible command names found on
+ the SEARCHPATH.
+ (version_test): Obtain the version of tools under test if
+ possible.
+ (id_tool_test): Check that 'id -u' and 'id -un' work.
+ (expr_tooltest1): Check for NextStep 3.3 expr bug.
+ (expr_tooltest2): Check for SunOS expr multi-line pattern bug.
+ (expr_create_bar): Create a test file for expr testing.
+ (expr_tooltest3): Use it and test for big multi-line identity
+ matches.
+ (expr_set_ENDANCHOR): Find and set the right value for ENDANCHOR.
+ (expr_set_DOTSTAR): Find and set the right value for DOTSTAR.
+ (expr_tooltest_DOTSTAR): Ensure that DOTSTAR works with big
+ matches.
+ (tr_tooltest1): Verify that tr handles NUL bytes.
+ (ls_tooltest): See if /bin/ls returns true even if wildcard does
+ not match any files.
+ (awk_tooltest1): Verify that awk the BEGIN clause works properly.
+ (awk_tooltest2): Verify that print %c format item works properly.
+
+2004-11-08 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (verify_tmp_empty): New function.
+ (dotest_internal_*): Call verify_tmp_empty as needed.
+
+2004-11-08 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (run_filter): Add function header comment block.
+
+2004-11-07 Larry Jones <lawrence.jones@ugs.com>
+
+ * sanity.sh: Remove trailing / from cp -r commands.
+
+2004-11-04 Derek Price <derek@ximbiot.com>
+
+ * gssapi-client.c (connect_to_gserver): Silence gcc -Wall.
+
+2004-11-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (set_bad_tool): Remove unnecessary quotes.
+
+2004-11-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: s/depends_on_/require/.
+
+2004-11-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (find_tool): Eliminate variable with single reference.
+
+2004-11-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (SEARCHPATH): Unify the PATHs that are to be searched.
+ (Which,find_tool): Use SEARCHPATH.
+ (LS): Use default $SEARCHPATH for Which.
+ (depend_on_rsync): Use default $SEARCHPATH for Which.
+
+2004-11-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (depends_on_rsync): Do not echo rsync information to
+ stdout. Look for rsync in more directories.
+
+2004-11-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (depends_on_rsync): Minor simplifications. Make sure that
+ an rsync that doesn't understand `--version' sends its error message to
+ the log file too.
+
+2004-11-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (set_bad_tool, is_bad_tool): Avoid printing errors
+ about the same tool multiple times.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (depends_on_rsync): Deal with missing rsync.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (depends_on_rsync): Include rsync version information
+ in output.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (depends_on_rsync): More rigorous tests for rsync
+ 2.3.1 problems with --delete --include dir --exclude '*/.
+
+2004-11-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (depends_on_rsync): Verify that `rsync --delete' actually
+ does what it is supposed ot do.
+
+2004-11-03 Derek Price <derek@ximbiot.com>
+
+ * subr.c (Xreadlink): Remove MAXSIZE macro. Minor reformatting.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (xreadlink): Remove and use GNULIB version.
+ (islink): Return ssize_t instead of bool.
+ (copy_file): Use Xreadlink().
+ * cvs.h: Add include "xreadlink.h"
+ (islink): Return ssize_t instead of bool.
+ * import.c (preserve_initial_permissions): Use Xreadlink.
+ * rcs.c (RCS_checkin): Ditto.
+ * update.c (special_file_mismatch): Ditto.
+ * subr.c (get_file): Ditto.
+ (resolve_symlink): Ditto.
+ (Xreadlink): New interface to xreadlink(), never return NULL.
+
+2004-11-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (MAXSIZE): New macro.
+ (xreadlink): Ensure initial buffer size does not exceed MAXSIZE.
+ Avoid cast. If readlink fails with buffer size just under MAXSIZE,
+ try again with MAXSIZE.
+
+2004-11-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (xreadlink): AIX and HP-UX readlink() returns ERANGE
+ when there is not enough room in the buffer.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Remove getdate proto in favor of including getdate.h.
+ * client.c (handle_mod_time), history.c (history), main.c (Make_Date,
+ format_date_alloc), rcs.c (RCS_getrevtime), server.c
+ (serve_checkin_time): Use new get_date API.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcslib): Fix typo in path.
+
+2004-11-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcslib): Test a link to a path longer than 128
+ characters.
+
+2004-10-30 Mark D. Baushke <mdb@cvshome.org>
+
+ * patch.c (patch_cleanup): Add signal argument and use it.
+
+2004-10-30 Mark D. Baushke <mdb@cvshome.org>
+
+ * client.c: Adjust include files to avoid problems with incomplete
+ types under --disable-client.
+ * msg-buffer.c: Deal with --disable-client --disable-server
+ implicitly meaning --disable-proxy.
+ * server.c: Adjust include files to avoid problems with incomplete
+ types under --disable-server.
+
+2004-10-30 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (isThisHost): Deal with possibility of a missing
+ hstrerror() function.
+
+2004-10-29 Derek Price <derek@ximbiot.com>
+
+ * server.c (server_root, move_file_offset, replace_file_offset):
+ Remove dead code.
+
+2004-10-29 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (xreadlink): Make sure allocation is tried once at the
+ maximum buffer size. Protect against overflow.
+
+2004-10-29 Derek Price <derek@ximbiot.com>
+
+ * server.c (isSameHost): Handle gethostname & gethostbyname errors.
+
+2004-10-29 Derek Price <derek@ximbiot.com>
+
+ * server.c (isSameHost): Use strcasecmp to compare host names.
+
+2004-10-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c: Need to #include <netdb.h> for either PROXY_SUPPORT or
+ HAVE_GSSAPI to get gethostbyname() declarations for
+
+2004-10-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (SIZE_MAX, SSIZE_MAX): Use #include "xsize.h" instead.
+ (xreadlink): Use xrealloc instead of xmalloc/free.
+
+2004-10-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (SIZE_MAX, SSIZE_MAX): New constants.
+ (xreadlink): Deal with symlinks longer than 127 bytes.
+ (Problem reported as issue 190 by Gottfried Ganssauge
+ <gotti@cvshome.org>.)
+
+2004-10-29 Derek Price <derek@ximbiot.com>
+
+ * server.c (isSameHost): New fuction.
+ (same_path): Rename to...
+ (isSamePath): ...this.
+ (isProxyServer): Use new functions/names.
+
+2004-10-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (writeproxy): Use DOTSTAR to avoid problems with
+ a missing Gssapi-authenticate in Valid-requests.
+
+2004-10-28 Derek Price <derek@ximbiot.com>
+
+ * server.c (same_path): New function.
+ (isProxyServer): Use new function.
+ * sanity.sh (writeproxy): Test that server resolves symlinks when
+ deciding whether it is a primary server.
+
+2004-10-28 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (isdir, isfile, islink, isdevice, isreadable, iswritable,
+ isaccessible, isabsolute): Return boolean rather than int.
+ * filesubr.c (isdir, isfile, islink, isdevice, isreadable, iswritable,
+ isaccessible), subr.c (isabsolute): Ditto. Some reformatting.
+ * filesubr.c (xresolvepath): Use save_cwd in place of xgetwd. Some
+ reformatting.
+
+2004-10-28 Derek Price <derek@ximbiot.com>
+
+ * client.c (handle_redirect): Detect redirect loops.
+ * sanity.sh (client-20): Test that client detects redirect loops.
+
+2004-10-28 Mark D. Baushke <mdb@cvshome.org>
+
+ * release.c (release): Allow builds of cvs with --disable-server
+ --disable-client both used for local installation configuration.
+ * root.c (Name_Root): Ditto.
+ * update.c (checkout_file): Ditto.
+ * edit.c (edit_fileproc): Ditto.
+ * import.c (import): Ditto.
+ (Problem reported by Jean Olivier Caron <jecar@mlab.t.u-tokyo.ac.jp>.)
+
+2004-10-27 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.h (RCS_FLAGS_USETIME): New flag.
+ * rcs.c (RCS_checkin): Add citime argument.
+ * rcs.h (RCS_checkin): Ditto.
+ * checkin.c (Checkin): Pass new RCS_checkin argument.
+ * commit.c (remove_file, checkaddfile): Ditto.
+ * import.c (add_rev): Ditto.
+
+ * sanity.sh (tagdate): Delete tagdate-19b as an incorrect test.
+
+2004-10-27 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (tagdate): Provide more output.
+
+2004-10-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * commit.c (checkaddfile): Create a dead version for a new file
+ added to a branch. Fixes FIXCVS for tagdate tests.
+ * sanity.sh (tagdate): Update to expect correct results.
+ (death2, branch-after-import, join, ignore-on-branch): Ditto.
+
+2004-10-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (isProxyServer): Fix hostname setup.
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ Call all exit handlers via atexit() & exit(). Signal handlers exit().
+ Eliminates a compiler warning.
+
+ * exithandle.c (cleanup_register): Don't register a signal handler.
+ Register a function to block signals before the exit handler is called.
+ * lock.c (Lock_Cleanup): Remove never_run_again cruft and assoc. cmts.
+ * rcs.c (rcs_cleanup), server.c (server_cleanup): Ditto, plus assume
+ signals are blocked.
+ * main.c (main_cleanup): Declare noreturn attribute.
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * gssapi-client.c (connect_to_gserver): Avoid truncating error messages
+ from the GSSAPI server.
+ (Report from Dan Peterson <dbpete@aol.com>.)
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (import-quirks): Test an even branch number.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * import.c (import): Repair regex for regressions introduced in last
+ commit.
+ * sanity.sh (import-quirks): Test a few branch numbers import shouldn't
+ have a problem with.
+
+2004-10-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (modes3): Quiet rsync messages in proxy mode when
+ permissions are removed. They are expected and not a problem here.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * import.c (import): Anchor and simplify branch verification regex.
+ * sanity.sh (import-quirks): Test another pattern that should fail.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (yesno): Remove prototype.
+ * edit.c, release.c: Include yesno.h. Flush output before calling
+ yesno().
+
+2004-10-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (tagdate): Added some additional tests and FIXCVS
+ comments for dealing properly with a 'cvs add' of a file to
+ a branch that already exists on the mainline.
+ (Problem reported by Renny Barrett <rbarrett@curamsoftware.com>.)
+
+ * sanity.sh (getrlogdate): New shell function.
+ (tagdate-{13,14,16}): Use it to avoid 'sleep 60' by using
+ the exact 1.1.4.1 timestamp for tagdate-14 and tagdate-16.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (depends_on_rsync): Redirect rsync output to /dev/null when
+ just testing.
+
+2004-10-23 Mark D. Baushke <mdb@cvshome.org>
+
+ * socket-client.c (socket_buffer_initialize): Drop obsolete
+ arguments to buf_initialize().
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * client.c (handle_m, handle_e): Winsock is returning
+ SOCK_ERRNO == WSAENOTSOCK for select() problems and not
+ setting errno. Do not bother with printing an error from a
+ select() that is not returning an non-zero errno.
+ (Report from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (proxy): proxycheck depends on rsync, but skip all if
+ no rsync is found rather than generate an error return.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am (proxycheck): New test target.
+ * sanity.sh: Keep one more level of check.log backup.
+ * Makefile.in: Regenerated.
+
+2004-10-22 Derek Price <derek@ximbiot.com>
+
+ * client.c, update.c: Use new MD5 interface.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (find_tool): Search /usr/pkg/bin for NetBSD tools
+ like rsync.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (tagdate): Fix typo.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * subr.c: #include vasnprintf.h to avoid compiler warning.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (error_use_protocol): Move decl here from lib/error.h so that
+ we may use an unforked error.h from GNULIB.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * main.c: #include strftime.h.
+ (format_time_t, gmformat_time_t): Supply missing args to my_strftime.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * buffer.c: Don't maintain last_index & last_count for buffers.
+ * buffer.h (struct buffer): Update struct.
+ (buf_initialize): Update proto.
+ * log-buffer.c, ms-buffer.c, zlib.c: Update all callers.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Fail gracefully in proxy mode when rsync is defective.
+ (depends_on_rsync): New function.
+ (writeproxy, writeproxy-noredirect, writeproxy-ssh): Skip these tests
+ gracefully when rsync is missing.
+
+2004-10-21 Mark D. Baushke <mdb@cvshome.org>
+
+ * add.c (add): Pay attention to cvswrite mode when resurrecting a
+ file that was not yet committed.
+ (Report from Frank Hemer <frank@hemer.org>.)
+ * sanity.sh (resurrection): Add new tests to deal with read-only
+ mode on a cvs add durring a resurrection. Verify that -r is not
+ honored when the resurrected file must be committed to be seen.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * ls.c (ls_fileproc): Deal with files specified on the command line.
+ (ls_delproc): Move to a more accessible location.
+
+2004-10-20 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Avoid unnecessary typecast.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-10-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * add.c (add): Backout last typecasts cleanup.
+
+2004-10-19 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Avoid attempting to resurrect a dead rev 1.1.
+ * sanity.sh (resurrection): Add test for the above.
+ (Report from Dan Peterson <dbpete@aol.com>.)
+
+2004-10-19 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Avoid unnecessary typecasts.
+
+2004-10-19 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Prototype new function.
+ * subr.c (Xasnprintf): New function.
+ * root.c (primary_root_translate, primary_root_inverse_translate):
+ s/asnprintf/Xasnprintf/.
+ * client.c (connect_to_pserver): Store line length for efficiency.
+
+2004-10-19 Derek Price <derek@ximbiot.com>
+
+ * history.c: Remove unecessary typecasts. Some reformatting.
+
+2004-10-18 Derek Price <derek@ximbiot.com>
+
+ * server.c (serve_modified): Eliminate >= 0 check since size_t may not
+ be negative.
+ (Originally reported by Martin Neitzel <neitzel@sco.gaertner.de>.)
+
+2004-10-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (DEVNULL): This is system dependant. Move it to lib/system.h.
+ * client.c (copy_a_file): Consolidate USE_VMS_FILENAMES stuff under a
+ single #ifdef.
+
+2004-10-15 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Don't include vasnprintf.h.
+ (Xasprintf): New prototype.
+ * client.c, edit.c, history.c, import.c, ls.c, main.c, parseinfo.c,
+ recurse.c, release.c, repos.c, root.c, server.c, status.c, subr.c,
+ vers_ts.c: s/asnprintf/Xasprintf/.
+ * root.c: Include vasnprintf.h.
+ (primary_root_translate, primary_root_inverse_translate): Use
+ asnprintf() properly.
+ * subr.c: Include vasprintf.h.
+ (Xasprintf): New function.
+
+2004-10-14 Derek Price <derek@ximbiot.com>
+
+ * import.c (import): Remove an unecessary level of nesting. Simplify
+ xmalloc/sprintf with asnprintf. Remove useless comment.
+
+2004-10-14 Derek Price <derek@ximbiot.com>
+
+ * import.c (import): Verify branch specifications more thoroughly.
+ * sanity.sh (importb): Adapt to new error message.
+ (import-quirks): New test.
+
+2004-10-14 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (server_pause_check, do_cvs_command, server_cleanup):
+ Avoid typecasts.
+
+2004-10-14 Derek Price <derek@ximbiot.com>
+
+ * gssapi-client.c: Use new size_t buffer APIs.
+
+2004-10-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * buffer.h, buffer.c (buf_output, buf_input_data, buf_read_line,
+ buf_read_data, struct packetizing_buffer,
+ packetizing_buffer_initialize) Use size_t instead of int.
+ Silences warnings in buffer.c, server.c, and zlib.c on OpenBSD
+ sparc64 where sizeof(int) is not the same as sizeof(size_t).
+ * client.c (read_line_via, read_line, try_read_from_server,
+ get_server_response, handle_ok, handle_error,
+ handle_valid_requests, handle_checked_in, handle_new_entry,
+ handle_checksum, handle_copy_file, handle_updated, handle_merged,
+ handle_patched, handle_rcs_diff, handle_removed,
+ handle_remove_entry, handle_set_static_directory,
+ handle_clear_static_directory, handle_set_sticky,
+ handle_clear_sticky, handle_clear_template,
+ handle_module_expansion, handle_wrapper_rcs_option, handle_m,
+ handle_e, handle_f, handle_notified): Ditto
+ * client.h (struct response): Ditto.
+ * server.c (receive_partial_file, receive_file, serve_modified,
+ do_cvs_command): Ditto.
+ * zlib.c (compress_buffer_input, compress_buffer_shutdown_input):
+ Ditto.
+ (Patch from Alexander Taler <dissent@cvshome.org>.)
+
+2004-10-08 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_args): Carry through a const to silence gcc -Wall.
+ * hardlink.c (delhardlist): New function.
+ (lookup_file_by_inode): Use new function as delproc since it should
+ work. Carry through a const to silence gcc -Wall.
+ * ms-buffer.c (ms_buffer_initialize): Use a working delproc.
+
+2004-10-08 Derek Price <derek@ximbiot.com>
+
+ * client.c (open_connection_to_server, close_connection_to_server,
+ handle_redirect): Add traces.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs_SOURCES): Add parseinfo.h.
+
+2004-10-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * vers_ts.c (entries_time): Use size_t pointers. sizeof(int)
+ may not be the same as sizeof(size_t) on OpenBSD sparc64.
+ (Patch from Alexander Taler <dissent@cvshome.org>.)
+
+ * wrapper.c (wrap_clean_fmt_str): Make static.
+
+2004-10-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * client.h (struct response): Make name a const.
+ * cvs.h (RETSIGTYPE): Use a full prototype.
+ * hash.h (struct node): Use a full prototype for delproc.
+
+ * client.c (send_arg, send_option_string, option_with_arg): Make
+ args of function const.
+ * client.h (send_arg, send_option_string, option_with_arg): Ditto.
+
+ * checkout.c (checkout): Make valid_options const.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * release.h: Silence gcc -Wall.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Move include of getopt.h to system.h with similar headers.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * login.c: Include getpass.h.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Include strcase.h.
+ (cvs_casecmp): remove proto.
+ * subr.c (cvs_casecmp): Remove function.
+ * parseinfo.c: s/cvs_casecmp/strcasecmp/.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Move getopt.h and regex.h into the GNULIB include section.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * main.c (cmds): Release calls unedit, to it modifies the repository.
+ (struct cmd): Add const and full prototype where needed.
+ * sanity.sh (edit-check): Use modify_repo where needed.
+ (release): No more special case for release in proxy mode.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+ * release.c (release): Simplify login in if statement.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_file_names): Back out broken portion of previous
+ change.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * client.c (call_in_directory): Make args of function arg const.
+ * client.h, client.c, edit.h, edit.c, server.h, zlib.c: Carry change
+ through to called functions and functions passed in as args.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * checkout.c, commit.c, edit.c, rcs.c: Avoid typecasts. Some
+ reformatting.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * client.c: Avoid more typecasts. Some reformatting.
+
+2004-10-06 Mark D. Baushke <mdb@cvshome.org>
+
+ * client.c (send_file_names): Use new save-cwd API.
+ (connect_to_pserver): Use a union to avoid incompatible pointer
+ type warnings.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (Xstrdup): New proto mapped via define to xstrdup.
+ * subr.c (Xstrdup): New function.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * add.c, client.c, history.c, import.c, mkmodules.c, modules.c,
+ recurse.c, release.c, tag.c, update.c: Use new save-cwd API.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * checkout.c, client.c, commit.c, create_adm.c, cvs.h, filesubr.c,
+ hardlink.c, history.c, logmsg.c, main.c, recurse.c, update.c:
+ s/xgetwd/xgetcwd/.
+
+2004-10-04 Derek Price <derek@ximbiot.com>
+
+ * client.c (responses): Add "Edit-file".
+ (handle_edit_file): New function.
+ * commit.c (usage): Add -c option.
+ (check_fileproc): Check for edit when requested.
+ (commit_fileproc): Use new notify_do API.
+ * edit.c (check_edited): New global.
+ (setting_tedit, setting_tunedit, setting_tcommit): s/int/bool/.
+ (ncheck_fileproc): Use new notify_do API.
+ (send_notifications): Remove redundant proto. Remove unnecessary
+ repository lock.
+ (editors_output, find_editors_and_output, edit_file): New functions.
+ edit_file() factored from...
+ (edit_fileproc): ...here. Skip files with existing editors when
+ requested.
+ (usage): Add -c and -f.
+ (edit): Handle new -c and -f options.
+ (notify_do): Accept update_dir as an argument for user messages.
+ (editors_fileproc): Factor most content to find_editors_and_output()
+ and edit_file().
+ * edit.h (notify_do): Proto new API.
+ (editors_output, edit_file): New functions.
+ * rcs.c (RCS_unlock): Use new notify_do() API.
+ * sanity.sh: Update assorted tests to compensate for new output.
+ (edit-check): New tests.
+ * server.c (gupdate_dir): New global.
+ (struct notify_note): Keep track of update_dir.
+ (serve_notify): Use update_dir.
+ (serve_hostname, serve_localdir, serve_edit, server_edit_file): New
+ functions.
+ (server_notify): Use new notify_do() API.
+ (requests): Add Hostname, LocalDir, and edit.
+ * server.h (server_edit_file): New proto.
+ (Note: Original design of new advisory lock behavior came from Noel Yap
+ <yap_noel@yahoo.com>'s original advisory locks patch, originally ported
+ forward and enhanced by Matthew Ogilvie <mmo9317bd@mailcan.com>.)
+
+2004-10-04 Derek Price <derek@ximbiot.com>
+
+ * admin.c (postadmin_proc), edit.c (notify_proc), fileattr.c
+ (postwatch_proc), logmsg.c (logfile_write, verifymsg_proc), server.c
+ (prepost_proxy_proc), tag.c (pretag_proc, posttag_proc): Pass referrer
+ to called scripts when possible.
+ * client.c (handle_redirect): Save the original server.
+ (start_server): Send referrer to the new server if possible.
+ * sever.c (referrer): New global.
+ (serve_referrer): Save referrer.
+ (requests): Add "Referrer" response.
+ * server.h (referrer): Add extern decl.
+ * sanity.sh (ssh-wrapper): Use in remote mode too.
+ (writeproxy-ssh): New tests.
+
+2004-10-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (CVSROOT_DFLT): Undef rather than defining to NULL.
+ * main.c (main): Untangle parsing of CVSROOT, eliminating several
+ variables in the process. Simplify xmalloc/sprintf with asnprintf.
+
+2004-10-04 Derek Price <derek@ximbiot.com>
+
+ * root.c (primary_root_translate, primary_root_inverse_translate,
+ get_local_root_dir, local_cvsroot): Simplify logic without proxy
+ support.
+
+2004-10-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * root.c (primary_root_translate, primary_root_inverse_translate,
+ get_local_root_dir): Protect PrimaryServer with #ifdef
+ PROXY_SUPPORT
+
+2004-10-01 Mark D. Baushke <mdb@cvshome.org>
+
+ * main.c (main): Initialize CVSroot before it is used.
+ (Report and patch by Martin Neitzel <neitzel@sco.gaertner.de>.)
+ * sanity.sh (status): Test it.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (checkout_proc), fileattr.c (fileattr_read), find_names.c
+ (Find_Names), myndbm.c (mydbm_open, mydbm_load_file), parseinfo.c
+ (Parse_Info), rcs.c (RCS_parsercsfile_i, rcsbuf_getkey,
+ rcsbuf_getrevnum, rcsbuf_valword): Root translation functions no longer
+ allocate.
+ * commit.c (commit): Use send_a_repository rather than reimplementing.
+ * main.c (main): Remove --primary-root option.
+ * root.c (primary_root_add): Remove this function.
+ (primary_root_in, primary_root_out): Remove globals.
+ (primary_root_translate, primary_root_inverse_translate): Return const.
+ Don't allocate return value. Rely on parsed root and confg's
+ PrimarServer rather than separately maintained globals.
+ (get_local_root_dir): New function.
+ (local_cvsroot): Translate requests for primary roots when necessary.
+ * root.h (primary_root_add, primary_root_translate,
+ primary_root_inverse_translate): Update protos to match.
+ * sanity.sh (top level, writeproxy): Simplify $proxy setup.
+ (client): Don't execute $proxy. Simplify skips and reindent.
+ (writeproxy-noredirect): Use --allow-root in place of --primary-root.
+ Save and restore $PRIMARY_CVSROOT*.
+ * server.c (serve_root): Rely on local_cvsroot() to do any necessary
+ root translation.
+ (serve_directory): Root translation functions no longer allocate.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * client.c (arg_should_not_be_sent_to_server), create_adm.c
+ (Create_Admin), recurse.c (start_recursion, do_recursion, do_dir_proc),
+ release.c (release), repos.c (Name_Repository, Short_Repository),
+ update.c (update_filesdone_proc):
+ s/original_root/original_parsed_root->MEMBER/.
+ * main.c (set_root_directory): Set original_parsed_root when setting
+ current_parsed_root.
+ (main): s/original_root/original_parsed_root->MEMBER/.
+ * root.c (original_root): Make cvsroot_t and rename to...
+ (original_parsed_root): ...this.
+ * root.h: Update extern decl to match.
+ * server.c (serve_root): Set original_parsed_root.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * server.c (serve_questionable): Use pending errors per API.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * repos.c (Name_Repository): asnprintf, not sprintf.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (ignore-11r): Rename second occurance to...
+ (ignore-11ar): ...this.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (1): Rename to...
+ (init-1): ...this.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * repos.c (Name_Repository): Simplify string construction with
+ asnprintf(). Improve comment. Some reformatting.
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * release.c (release): Simplify string construction with asnprintf().
+
+2004-10-01 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (do_file_proc): Improve header comment. Replace
+ xmalloc()/strcat() combination with asnprintf().
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (config): Handle $SECONDRY_ROOT_DIRNAME output in $proxy
+ mode.
+
+2004-09-29 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh: Workaround MacOS X '/bin/ls' is not returning false
+ when no files are listed. Label some old tests.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Include parseinfo.h.
+ (top_level_admin, UseNewInfoFmtStrings,
+ ImportNewFilesToVendorBranchOnly, PrimaryServer, MaxProxyBufferSize,
+ MaxCommentLeaderLength, UseArchiveCommentLeader, RereadLogAfterVerify,
+ lock_dir, UserAdminOptions): Move extern decls for global config opts
+ to config struct in parseinfo.h.
+ (config): New global.
+ (parse_config): Move proto to...
+ * parseinfo.h: This new file.
+ * parseinfo.c (parse_config): Return struct config.
+ (new_config): New function.
+ * admin.c: Remove global UserAdminOptions.
+ (admin): Don't check config on client.
+ * checkin.c (Checkin), checkout.c (checkout_proc), filesubr.c (xchmod),
+ import.c (import, add_rcs_file, expand_and_copy_contents):
+ Use config instead
+ of globals. Some reformatting.
+ * history.c (logHistory): Move to struct config.
+ (history_write): Use config instead of globals.
+ * lock.c (lock_dir): Move global to struct config.
+ (lock_name): Use config instead of globals.
+ * logmsg.c (RereadLogAfterVerify): Move global to struct config.
+ (do_verify, logfile_write, verifymsg_proc): Prefer config to globals.
+ * main.c (top_level_admin, UseNewInfoFmtStrings, PrimaryServer,
+ MaxProxyBufferSize, MaxCommentLeaderLength, UseArchiveCommentLeader,
+ ImportNewFilesToVendorBranchOnly): Move globals to struct config.
+ (config): New global.
+ (main): Use new parse_config API.
+ * rcs.c (preserve_perms, keywords): Move globals to struct config.
+ (keyword_local): Move to struct rcs_keyword.
+ (new_keywords, free_keywords): New functions.
+ (expand_keywords, RCS_setlocalid, RCS_setincexc): Prefer config to
+ globals.
+ * rcs.h (free_keywords): New proto.
+ (RCS_setincexc, RCS_setlocalid): Accept opaque keywords element.
+ * root.c (delconfig, get_root_allow_config): New functions.
+ * root.h (get_root_allow_config): New proto.
+ * server.c (system_auth): Move global to struct config.
+ (isProxyServer, become_proxy, serve_command_prep): Prefer config to
+ globals.
+ (serve_root): Ditto. Set config.
+ * server.h (system_auth): Move extern decl for global moved to config.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * history.h: Protect against multiple include.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * root.c (root_allow_count, root_allow_vector, root_allow_size):
+ Replace with...
+ (root_allow): ...this single List *.
+ (root_allow_add, root_allow_free, root_allow_ok): Use new List API.
+ Make args const. Return bool rather than int when necessary.
+ * root.h (root_allow_add, root_allow_ok): Update protos to match.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * admin.c (admin): s/int/bool/ as appropriate. Some reformatting.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * history.c (history_write): Use asnprintf(). Some reformatting.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * import.c (killnew): s/int/bool/.
+ (add_rcs_file): Ditto for do_killnew.
+ * rcs.h (add_rcs_file): Change proto to match.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * client.c (start_server): Use bool in place of int.
+
+2004-09-29 Derek Price <derek@ximbiot.com>
+
+ * subr.c (cvs_trace): Correct header comment. Some reformatting.
+
+2004-09-28 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (ssh-wrapper-env): New script to avoid the assumption
+ that the remote end of a $CVS_RSH is running a bourne shell.
+ (ssh-wrapper): Use it.
+
+2004-09-28 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (writeproxy): Remove some setup obsoleted by redirects.
+
+2004-09-27 Derek Price <derek@ximbiot.com>
+
+ Use original_root for client comparisons with CVS/Root since
+ current_parsed_root may be the product of a redirect.
+
+ * client.c (handle_redirect): Don't free current_parsed_root. Validate
+ new roots.
+ (args_should_not_be_sent_to_server):
+ s/current_parsed_root->original/original_root/.
+ * create_adm.c (Create_Admin): Likewise.
+ * cvs.h (current_parsed_root): Move extern decl...
+ * root.h: ...here. Decl original_root extern.
+ * main.c (set_root_directory): Store original_root.
+ (main): s/current_parsed_root->original/original_root/.
+ * recurse.c, release.c, update.c: Likewise.
+ * root.c: Declare original_root.
+
+2004-09-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (parseroot2): Correct two test names. Restore CVSROOT.
+
+2004-09-24 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_cvsroot): Use TRACE_FLOW, not TRACE_FUNCTION since this
+ routine is called repeatedly by the recursion routines.
+ * sanity.sh (multiroot2): Adjust to compensate.
+
+2004-09-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (parseroot2): Use remoteonly.
+
+2004-09-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (tests): Add parseroot2.
+
+2004-09-24 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (do_recursion, do_dir_proc): Make process_this_directory a
+ boolean.
+
+2004-09-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (parseroot2): New test for root parsing consistency.
+ (Original patch from Alexander Taler <dissent@cvshome.org>.)
+
+ * cvs.h (Name_Root, free_cvsroot_t, parse_cvsroot, local_cvsroot,
+ Create_Root, root_allow_add, root_allow_free, root_allow_ok): Move
+ these protos to...
+ * root.h: ...here.
+ * client.c (arg_should_not_be_sent_to_server), recurse.c
+ (start_recusrion, do_recursion): Use new Name_Root API.
+ * main.c (current_root): Remove global.
+ (set_root_directory): Set current_parsed_root directly.
+ (main): Use new Name_Root API. Restore deletion of root directories
+ list.
+ * root.c (Name_Root): Return a parsed cvsroot_t rather than a string.
+
+2004-09-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * buffer.c (buf_append_buffer): Fix typo in comment.
+
+2004-09-23 Mark D. Baushke <mdb@cvshome.org>
+
+ * buffer.c (buf_read_file): Fix typo in comment.
+ (buf_read_file_to_eof): Ditto.
+ * server.c (serve_command_prep): Ditto.
+
+2004-09-23 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (depends_on_ssh, sshstdio): Don't use skip() to skip
+ remote-only tests.
+
+2004-09-23 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (crerepos, sshstdio): Minor modifications to make use of
+ the new depends_on_?sh API.
+
+2004-09-23 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Accept new -e option to interpret non-fatal calls to skip
+ as errors.
+ (skip, depends_on_rsh, depends_on_ssh): New functions.
+
+2004-09-23 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (cvs_output, cvs_output_binary): fflush (stderr)
+ here to avoid problems with 'cvs status 2>&1'.
+ (Report by Frank Hemer <frank@hemer.org>.)
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * buffer.c, buffer.h, log-buffer.c, log-buffer.h, main.c, mkmodules.c,
+ parseinfo.c, server.c: Remove TRUST_OS_FILE_CACHE.
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (fd_set_block): Ignore FreeBSD /dev/null problem.
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (strip_trailing_slashes): Remove proto in favor of including
+ dirname.h from GNULIB.
+ * sever.c (dir_name): Rename to...
+ (gDirname): ...this to avoid conflicts with the GNULIB function.
+
+2004-09-16 Derek Price <derek@ximbiot.com>
+
+ * expand_path.c (expand_path): Silence `gcc -Wall'. Reformat some
+ comments to fit in 80 characters.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (sync-secondary, writeproxy, writeproxy-noredirect): Remove
+ redundant checks for $RSYNC readability.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Only find $RSYNC once.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (writeproxy, writeproxy-noredirect): Find $RSYNC in a
+ portable manner.
+
+2004-09-15 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh: Find $RSYNC in a portable manner.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * parseinfo.c (parse_config): Complete parsing of the remainder of the
+ config file when errors are encountered. Accept and ignore
+ UseNewInfoFmtStrings=yes when !SUPPORT_OLD_INFO_FMT_STRINGS.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_copy_data): Pass args to buf_append_data correctly.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Set $RSYNC in proxy mode.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * main.c: Fix typo in comment.
+
+2004-09-15 Derek Price <derek@ximbiot.com>
+
+ * rcs.c: s/abort/assert/. Reformat function headers. Remove
+ unnecessary typecasts & prototypes.
+
+2004-09-14 Mark D. Baushke <mdb@cvshome.org>
+
+ * parseinfo.c (readBool): Remove dead code.
+
+ * filesubr.c (cvs_casecmp): Move to...
+ * subr.c (cvs_casecmp): ...here.
+ * cvs.h (cvs_casecmp): No longer ifdef under SERVER_SUPPORT
+
+ * parseinfo.c (readBool): Return false when there was no boolean
+ found.
+
+2004-09-14 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (top_level_admin, ImportNewFilesToVendorBranchOnly):
+ s/int/bool/.
+ (MaxCommentLeaderLength, UseArchiveCommentLeader): New vars.
+ * main.c: Ditto, for all four vars above.
+ * mkmodules.c (config_contents): Add default info for
+ MaxCommentLeaderLength & UseArchiveCommentLeader.
+ * parseinfo.c (readBool, readSizeT): New functions.
+ (parse_info): Use new functions. Parse MaxCommentLeaderLength &
+ UseArchiveCommentLeader.
+ * rcs.c (expand_keywords): Limit the size of the comment leader to
+ MaxCommentLeaderLength & fall back to the comment leader specified in
+ the RCS archive when requested.
+ (preserve_perms): s/int/bool/.
+ * rcs.h (preserve_perms), server.c (system_auth), server.h
+ (system_auth): Likewise.
+ * sanity.sh (keywordlog): Add new tests for the above.
+
+2004-09-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * rcs.c (RCS_checkout): Allow noexec to do checkouts when
+ server_active is true.
+ * sanity.sh (join7): Test above change (fixes a FIXCVS).
+
+2004-09-09 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (stuct packetizing_buffer): Use size_t & bool as appropriate
+ in preference to int.
+ (packetizing_buffer_output): s/int/size_t/ as appropriate.
+
+2004-09-09 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (packetizing_buffer_input): s/int/size_t/ as appropriate.
+
+2004-09-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * root.c (primary_root_inverse_translate): No longer inline.
+
+2004-09-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * server.c: Add comment before #if at line 5580 to move it further
+ into the file which seems to work around an apparent buffer managment
+ bug in Microsoft Visual C++ 6.0 compiler.
+
+2004-09-08 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (join7): Fix if-then-else conditional.
+
+ * sanity.sh (join7): Re-order join7-5 and join7-6 tests.
+
+2004-09-08 Conrad T. Pino <Conrad@Pino.com>
+
+ * server.c: Remove extra token in conditional compile line 5580
+ causing error in Windows Visual C++ 6.0 compile.
+
+2004-09-08 Mark D. Baushke <mdb@cvshome.org>
+
+ * buffer.c (fd_buffer_block): Protect fcntl calls when F_GETFL,
+ O_NONBLOCK and F_SETFL are not available.
+ * server.c (move_file_offset): Ditto.
+ (set_nonblock_fd): Ditto.
+
+ * buffer.c (packetizing_buffer_input): Use size_t rather than int.
+ (struct packetizing_buffer): Ditto.
+
+2004-09-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (server_updated): Deal with cvs -n update -jt1 -jt2
+ "protocol error: uncounted data discarded" problem.
+ * sanity.sh (join7): New test for this case.
+
+2004-09-04 Derek Price <derek@ximbiot.com>
+
+ * socket-client.c (socket_client_initialize): Pass new args to
+ buf_initialize.
+
+2004-09-04 Derek Price <derek@ximbiot.com>
+
+ Silence `gcc -Wall'.
+
+ * buffer.c (buf_initialize): Remove unnecessary typecasts by using
+ size_t instead of int or bool as args.
+ * buffer.c, import.c, log-buffer.c, ms-buffer.c, zlib.c: Change all
+ callers.
+ * buffer.h, cvs.h: Update protos.
+ * client.c, ls.c, main.c, rcs.c, root.c, server.c: Remove unused vars,
+ add parens, as requested by `gcc -Wall'.
+
+2004-09-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (writeproxy-noredirect): Between "Set" and
+ "expand-modules" are the optional Kerberos-encrypt, Gssapi-encrypt
+ and Gssapi-authenticate entries. Use ${DOTSTAR} to deal with
+ these optionally configured requests.
+
+2004-09-04 Mark D. Baushke <mdb@cvshome.org>
+
+ * import.c (expand_at_signs): Typecasting for fwrite results.
+ * log-buffer.c (log_buffer_input, log_buffer_output,
+ log_buffer_initialize): Ditto.
+
+ * log-buffer.c (log_buffer_initialize): Protect reference to
+ fatal_errors.
+
+ * parseinfo.c (parse_config): Protect reference to PrimaryServer
+ using #ifdef PROXY_SUPPORT.
+
+ * ls.c (ls_fileproc): Remove unused variables.
+ * subr.c (increment_revnum): Ditto.
+ * vers_ts.c (time_stamp): Ditto.
+
+2004-09-03 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_checkin), commit.c (remove_file): Accept UPDATE_DIR
+ argument and use it to output full relative path on commit.
+ * rcs.h (RCS_checkin): Update prototype.
+ * checkin.c, commit.c, import.c: Change all callers.
+ * sanity.sh: Adjust to compensate.
+
+2004-09-03 Derek Price <derek@ximbiot.com>
+
+ * client.c (call_in_directory): Change passed in function to accept
+ void * to avoid typecasting. Change all functions using this API.
+
+2004-09-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (secondary-wrapper, writeproxy-secondary-wrapper): Improve
+ comments. Use exec to launch server.
+ (writeproxy-noredirect): New tests for writeproxy functionality in
+ conjunction with clients that cannot handle the `Redirect' response.
+
+2004-09-03 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c, rsh-client.c, client.c: Reformat function headers.
+ Remove unnecessary typecasts and prototypes.
+ * client.h: Remove unnecessary extern declarations on protos.
+
+2004-09-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (skip): New function.
+ (sshstdio): Use new function.
+ (writeproxy): Skip test when rsync isn't found.
+
+2004-09-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (serve_directory): C89 compilers do not like mixed
+ declarations and code.
+
+2004-08-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (sync-secondary): 'dirname -b' fails during the
+ spacefiles-5 test on FreeBSD, so use 'dirname -- "\$dir"' for now
+ and look to AS_DIRNAME at some future date.
+
+2004-08-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (ssh-wrapper): Create for $proxy mode too & forward CVS_PID
+ for crerepos.
+
+2004-08-18 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (writeproxy): Use CVS_PID instead of PPID as the
+ former environment variable is set by cvs and the latter is
+ NOT set by all bourne shells.
+
+2004-08-18 Mark D. Baushke <mdb@cvshome.org>
+
+ * log-buffer.c (log_buffer_rewind): Avoid FreeBSD compilation
+ error for dereferencing a void * pointer tmp as well as using it
+ as a buffer pointer under some conditions.
+
+2004-08-17 Derek Price <derek@ximbiot.com>
+
+ * server.c (isProxyServer): Always compile. Cache hostname lookup.
+ (serve_notify): Ignore notifications in conjunction with redirects.
+ (do_cvs_command): Send an error when !PROXY_SUPPORT and a client does
+ not support redirects. Only close proxy logs when they exist.
+ (serve_command_prep): New function.
+ * sanity.sh (secondary-wrapper, writeproxy): Dynamically switch the
+ servers proxy/primary status for testing.
+ (basica): Gratuitous reformatting.
+ (devcom3, config, release): Handle some new proxy/redirect error
+ messages.
+
+2004-08-17 Derek Price <derek@ximbiot.com>
+
+ * main.c (PrimaryServer): Include without PROXY_SUPPORT to support
+ redirects.
+ (main): Handle --primary-root without PROXY_SUPPORT.
+ * mkmodules.c (PrimaryServer), parseinfo.c (parse_config), root.c
+ (primary_root_add, primary_root_translate,
+ primary_root_inverse_translate): Likewise.
+
+2004-08-17 Derek Price <derek@ximbiot.com>
+
+ * client.c: Misc reformatting.
+ (handle_redirect, close_connection_to_server): New functions.
+ (failure_exit,*): s/int/bool/.
+ (responses): Add `Redirect'.
+ (get_server_responses): Handle response_type_redirect.
+ (get_responses_and_close): Use close_connection_to_server().
+ (supported_request): Change API to use bool & const.
+ (start_server): Handle response_type_redirect.
+ * client.h (supported_request): Update proto.
+ (type): Add response_type_redirect.
+ * main.c (lookup_command_attribute): Declare arg const.
+ * cvs.h (lookup_command_attribute): Ditto.
+ * sever.c (requests): Create dummy `Command-prep' request.
+
+2004-08-12 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Don't process --primary-root without PROXY_SUPPORT.
+ * root.c (primary_root_translate, primary_root_inverse_translate):
+ Declare inline.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * ms-buffer.h, ms-buffer.c: Disable contents without PROXY_SUPPORT.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * server.c (isProxyServer): Declare inline.
+ (reprocess_proxy_log): Rename to...
+ (rewind_buf_from_net): ...this and change all callers.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (sync-secondary): Don't bother to log sync activity.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_copy_data), buffer.h (buf_copy_data), log-buffer.c
+ (log_buffer_initialize, log_buffer_input, log_buffer_output,
+ log_buffer_rewind, log_buffer_closelog), log-buffer.h
+ (log_buffer_initialize), main.c (MaxProxyBufferSize), mkmodules.c
+ (config_contents), parseinfo.c (parse_config), server.c (server):
+ Switch eariler support for logs in memory buffers on
+ TRUST_OS_FILE_CACHE.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_free_data, buf_copy_data): Only compile with proxy
+ support.
+ * buffer.h: Ditto for including the protos.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (fd_buffer_input): Bracket misguided attempt at improved
+ I/O efficiency with TRUST_OS_FILE_CACHE pragmas.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.h, main.c, mkmodules.c, parseinfo.c, server.c:
+ s/MaxSecondaryBufferSize/MaxProxyBufferSize/.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * sever.c (secondary_log, secondary_log_out): Rename globals everywhere
+ to...
+ (proxy_log, proxy_log_out): ...these.
+ (isSecondaryServer): Rename function...
+ (isProxyServer): ...to this.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c: #ifdef PROXY_SUPPORT in appropriate places.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * cvs.h, log-buffer.h, main.c, mkmodules.c, parseinfo.c, server.c:
+ s/SECONDARY_SUPPORT/PROXY_SUPPORT/.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * server.c (isSecondaryServer): Declare static.
+ * server.h (isSecondaryServer): Remove proto.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.h (log_buffer_rewind, log_buffer_closelog): Don't define
+ protos without SECONDARY_SUPPORT.
+ * server.c (*): #ifdef correctly for !SECONDARY_SUPPORT.
+ * version.c (version): Remove unused code.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * server.c (server_cleanup): Remove unused variable.
+
+2004-08-10 Derek Price <derek@ximbiot.com>
+
+ * server.c (buf_from_net_save): Remove obsolete variable.
+ (server_cleanup): Don't close BUF_FROM_NET_SAVE.
+
+2004-08-09 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (sync-secondary, *info): Sync only the updated directories
+ rather than the entire repository after a write for a minor efficiency
+ improvement.
+ (info, taginfo): Hack *info to sync all dirs for these tests rather
+ than rewriting the sync-secondary script to handle old-style *info
+ format strings.
+
+2004-08-05 Derek Price <derek@ximbiot.com>
+
+ Beginnings of support for turning off writeproxy support (still broke.)
+ * cvs.h (PrimaryServer, MaxSecondaryBufferSize), main.c (PrimaryServer,
+ MaxSecondaryBufferSize), mkmodules.c (config_contents), parseinfo.c
+ (parse_config): Switch off when writeproxy support disabled.
+ * server.c (replace_file_offset, move_file_offset): Comment out
+ temporarily.
+
+2004-08-05 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (copy_file): Don't fsync. It's slow.
+
+2004-08-05 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_copy_data): New function.
+ * buffer.h: Proto new function.
+ * cvs.h (MaxSecondaryBufferSize): Declare new config global.
+ * log-buffer.c: Allow file-backed memory buffers for "speed".
+ (struct log_buffer): Add new fields.
+ (log_buffer_force_file): New function.
+ (log_buffer_initialize): Initialize new fields.
+ (log_buffer_input, log_buffer_output): Handle logging to memory when
+ asked.
+ (log_buffer_disable): Remove function, moving much functionality...
+ (log_buffer_rewind): ...to this new function and expanding.
+ (log_buffer_closelog): Handle new fields and structs.
+ (log_buffer_get_fd): Remove function.
+ (setup_logfiles): Use new _initialize API.
+ * log-buffer.h: Update protos to match.
+ * main.c (MaxSecondaryBufferSize): Init new config global.
+ * mkmodules.c (config_contents): Add comments 4 MaxSecondaryBufferSize.
+ * parseinfo.c (parse_config): Parse MaxSecondaryBufferSize..
+ * server.c (secondary_log_name, secondary_log_out_name): Remove unused
+ globals.
+ (read_secondary_log): Remove function.
+ (reprocess_secondary_log): Use log_buffer_rewind() instead of the above.
+ (become_proxy): Ditto.
+ (server_cleanup): No need to clean up logfiles any longer.
+ (server): Use new log_buffer_initialize API.
+
+2004-08-04 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_read_data): s/abort/assert/.
+
+2004-08-04 Derek Price <derek@ximbiot.com>
+
+ * server.c (loop_over_inputs): Remove function, moving contents back...
+ (server): ...to here.
+
+2004-08-03 Derek Price <derek@ximbiot.com>
+
+ Checking in IO changes intended to improve speed for posterity since
+ they actually increase CPU usage by about .2% in remote mode and 5% in
+ writeproxy mode.
+ * Makefile.am (cvs_SOURCES): Add ms-buffer.c & ms-buffer.h.
+ * buffer.c (buf_free_data): New function.
+ (buf_read_data): s/abort/assert/.
+ (fd_buffer_input): Try to improve efficiency of blocking read.
+ * buffer.h (buf_free_data): New proto.
+ * server.c (reprocess_secondary_log): Only reopen log and attach to
+ BUF_FROM_NET - don't actually loop over inputs.
+ (become_proxy, serve_co, do_cvs_command): Use new log from above.
+ * ms-buffer.c, ms-buffer.h: New files.
+
+2004-08-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (TIMING): Make this work when not in $remotehost mode.
+ (reserved-13b): Use sorted output.
+
+2004-08-03 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c: Improve comments.
+
+2004-08-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (ssh-wrapper): Export CVSUMASK to remote host.
+ (*): Remove some hacks that were needed because CVSUMASK was not
+ exported to the remote host. Misc cleanup.
+
+2004-07-28 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (pserver-auth-no-dos): ENOMEM on Solaris 7, 8, 9, and
+ AIX 4.3 all use the text "Not enough space" instead of the text
+ "Cannot allocate memory" as is printed on GNU/Linux, NetBSD, and
+ FreeBSD systems.
+
+2004-07-28 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (ssh-wrapper): Export CVS_RSH on remote host.
+
+2004-07-28 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (secondary-wrapper): Not all $TESTSHELL shells
+ are able to set a variable and export it at the same time.
+ Separate the value assignment from the export statement.
+ (writeproxy-secondary-wrapper): Ditto.
+
+2004-07-28 Derek Price <derek@ximbiot.com>
+
+ * server.c (isSecondaryServer): Fix array out of bounds problem.
+ * sanity.sh (ssh-wrapper): Wrap any rsh implementation we are handed to
+ forward variables relevant to testing. Add new $TIMING variable to
+ allow timing of processes on a remote host.
+ (*): Gratuitous reformatting.
+
+2004-07-26 Derek Price <derek@ximbiot.com>
+
+ * server.c (read_secondary_log): Minor comment corrections.
+
+2004-07-23 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (fd_buffer_output): Don't fsync. It is unneeded and slow.
+ * server.c (move_file_offset, replace_file_offset): Ditto.
+ * log-buffer.c (log_buffer_flush_log): Remove function.
+
+2004-07-19 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c (log_buffer_disable): Return log FILE *. Don't close
+ log. Fix header comment.
+ (log_buffer_closelog): New function.
+ * log-buffer.h: Update protos to match.
+ * server.c (read_secondary_log): Rewind file pointer rather than
+ closing and reopening file for speed.
+ (serve_root): Close secondary log rather than just disabling when not
+ running in secondary mode.
+
+2004-07-19 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_flush): Replace abort w/assert.
+ * log-buffer.c (log_buffer_flush_log): New function for syncing a log.
+ (log_buffer_flush, log_buffer_flush): Don't sync log for speed.
+ * log-buffer.h (log_buffer_flush_log): New proto.
+ * sanity.sh: Tidy.
+ (run_filter): Accept file name to filter as argument.
+ (dotest_*): pass new arg to run_filter.
+ * server.c (read_secondary_log): Sync log before reopening.
+
+2004-07-16 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (fd_buffer_input): Back out previous two changes due to
+ incompatibility with current state of write proxies.
+ * log-buffer.c (log_buffer_initialize): Handle new buffers which
+ already have some data in them.
+ (log_buffer_input): Don't fsync here. It is slow.
+ * server.c (serve_root): Disable the secondary output log too.
+ (serve_noop, pserver_authenticate_connection): Misc cleanup.
+ * sanity.sh: Misc gratuitous cleanup.
+
+2004-07-16 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (fd_buffer_input): Don't overwrite the input buffer the
+ second time through the blocking read loop.
+
+2004-07-15 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (fd_buffer_input): Improve efficiency.
+ * sanity.sh (modify_repo): Move timestamp race avoidance to...
+ (sync-secondary): This script.
+ (big): Misc cleanup.
+
+2004-07-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Misc gratuitous cleanup.
+ (modify_repo): Sleep 1 before rsync to avoid timestamp comparison
+ issues.
+
+2004-07-15 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c (log_buffer_output): Remove extremely slow fsync call.
+ (log_buffer_disable): Move to here so log files are sync'd before
+ close.
+ * sanity.sh (run_filter): New function to allow for filtering of cruft
+ output by Rational Quantify or other profilers.
+ (dotest_*): Call new function.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * server.c (prepost_proxy_proc): Add the CVSROOT string for the primary
+ server, as documented.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * tag.c (tag_filesdoneproc): Don't track posttag errors.
+ (cvstag): Move addition of successful tags to val-tags to...
+ (tag_fileproc): ...here and...
+ (rtag_fileproc): ...here. Consolidate returns at single location.
+ (*): Misc reformatting.
+ * sanity.sh (sync-secondary): Include more data in the update-log.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore coverage data generated by GCC.
+
+2004-07-12 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Watch $servercvs and other minor fixes.
+
+2004-07-12 Derek Price <derek@ximbiot.com>
+
+ * server.c: Gratuitous reformatting.
+ * sanity.sh: Misc write proxy accommodations.
+
+2004-07-11 Derek Price <derek@ximbiot.com>
+
+ * log.c (log_fileproc, log_expand_revlist, log_fix_singledate,
+ log_count_print, log_tree, log_abranch, log_version), parseinfo.c
+ (Parse_Info, parse_config), rcs.c (RCS_fully_parse, rcsbuf_getkey,
+ rcsbuf_getrevnum, rcsbuf_valword, RCS_getbranchpoint, RCS_getdate,
+ RCS_getrevtime, RCS_checkout, RCS_findlock_or_tip, RCS_addbranch,
+ RCS_cmp_file, RCS_lock, RCS_unlock, RCS_delete_revs, RCS_deltas,
+ RCS_getdeltatext, RCS_putdtree): Print primary path.
+ * server.c (serve_kopt): Handle secondary log.
+ * sanity.sh: Misc accommodations.
+
+2004-07-11 Derek Price <derek@ximbiot.com>
+
+ * checkin.c (checkout_proc): Correct vi induced typo.
+
+2004-07-11 Derek Price <derek@ximbiot.com>
+
+ * admin.c (postadmin_proc), commit.c (precommit_proc), edit.c
+ (notify_proc), fileattr.c (postwatch_proc), logmsg.c (logfile_write),
+ server.c (prepost_proxy_proc), tag.c (posttag_proc, pretag_proc): Add
+ default %c format string.
+ * client.c, edit.c, lock.c, fileattr.c, mkmodules.c, myndbm.c,
+ parseinfo.c, recurse.c: Misc gratuitous cleanup.
+ * commit.c (commit_filesdoneproc): Move loginfo call to after CVSROOT
+ sync.
+ * checkout.c (checkout_proc), fileattr.c (fileattr_read), myndbm.c
+ (mydbm_open, mydbm_load_file): Print primary path.
+ * server.c (serve_checkin_time): Handle secondary log.
+ (prepost_proxy_proc): Move before first call.
+ (become_proxy): Move before first call.
+ (serve_notify): Become proxy for this request.
+ * sanity.sh: Misc accommodations.
+
+2004-07-10 Derek Price <derek@ximbiot.com>
+
+ * server.c (serve_notify): Handle secondary_log.
+
+2004-07-08 Derek Price <derek@ximbiot.com>
+
+ Intermediate checkin. Adds some new server requests and test fixes.
+ * sanity.sh: Update tests to handle proxies and new hooks.
+ * cvs.h (CVSROOTADM_PREPROXY): Alphebetize & sub correct name.
+ * mkmodules.c (filelist): Alphabetize.
+ * server.c (serve_max_dotdot, serve_static_directory, serve_argumentx):
+ Handle secondary_log.
+ * tag.c (*): Misc gratuitous cleanup.
+
+2004-07-08 Derek Price <derek@ximbiot.com>
+
+ Intermediate checkin. Adds preproxy, & postproxy hooks and some test
+ cruft to test everything.
+
+ * cvs.h (CVSROOTADM_*): Add new hook config files.
+ * log.c (log_fileproc): Print primary path.
+ * mkmodules.c (*_content): Add init content for new files.
+ (filelist): Add new files.
+ * rcs.c (RCS_parsercsfile_i): Set print_path. Misc gratuitous cleanup.
+ (freercsnode): Free print_path.
+ * rcs.h (struct rcsnode): Add print_path.
+ * rcscmds.c (RCS_merge, RCS_exec_rcsdiff): Print primary path.
+ * server.c (isSecondaryServer): No longer static.
+ (serve_sticky, serve_argumentx): Handle secondary logging.
+ (prepost_proxy_proc): New function.
+ (become_proxy): Call pre & post proxy hooks. Handle IO closing better.
+ * server.h (isSecondaryServer): No longer static.
+ * status.c (status_fileproc): Print primary path.
+ * sanity.sh: Accept --proxy argument and run in write proxy mode when
+ seen. Misc fixes to account for other changes. Misc gratuitous
+ cleanup.
+
+2004-07-02 Derek Price <derek@ximbiot.com>
+
+ Woo-hoo! Write proxies work!
+ * client.c (open_connection_to_server): Set up log files...
+ (start_server): ...here.
+ * server.c (secondary_log_out_name, secondary_log_out): New globals.
+ (argument_cound, argument_vector, argument_vector_size): Move before...
+ (reprocess_secondary_log): ...referencing here. Assume secondary_log.
+ (read_secondary_log): Accept buf & name args.
+ (serve_modified, serve_unchanged, serve_is_modified, serve_entry):
+ Handle logging pass.
+ (become_proxy): Use new output-to-client-log. Verify buffers still
+ exist before using.
+ (output_dir): Translate paths to the client on the secondary.
+ (serve_co): Only reprocess the secondary log when one exists.
+ (server_cleanup): Free buf after shutdown. Dispose of client output
+ log.
+ (server): Create client output log.
+ (*): Misc reformatting & detypecasting.
+ * log-buffer.c (log_buffer_output): Handle fatal_errors.
+ (log_buffer_flush): Don't operate on NULL streams.
+ (log_buffer_disable): Reformat so as not to confuse the optimizer.
+ * root.c (primary_root_translate): Remove unused variable and redundant
+ slash.
+ (primary_root_inverse_translate): New function.
+ * root.h: Add new proto.
+ * sanity.sh (writeproxy): Wrap server executables to set args and
+ server variables properly. Fill in some test gaps. Correct `cd' args.
+ Clean up wrappers.
+
+2004-06-30 Derek Price <derek@ximbiot.com>
+
+ * root.h (primary_root_add, primary_root_translate): New protos.
+ * root.c (primary_root_add, primary_root_translate): New functions.
+ * main.c (long_options): Add --primary-root. Handle --primary-root
+ and --allow-root only with SERVER_SUPPORT.
+ (main): Ditto.
+ * server.c (move_file_offset): Set block before fsync. Report
+ ftruncate errors. Force sync after rearranging data.
+ (replace_file_offset): Force sync after replacing data.
+ (serve_directory): Translate roots based on --primary-root arg.
+ (serve_root): Likewise & don't rewrite the log file.
+ (become_proxy): Increment select's N arg because it is required.
+ (do_cvs_command): Use MAX macro appropriately.
+ * sanity.sh (writeproxy): Wrap the secondary server in such a way that
+ it gets the --primary-root option and the primary does not. Move the
+ primary root out of the way for the read operations to prove only the
+ secondary was accessed.
+
+2004-06-30 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c (log_buffer_input, log_buffer_output): Flush logs as
+ soon as they are written to better diagnose hangs.
+
+2004-06-30 Derek Price <derek@ximbiot.com>
+
+ * client.c (connect_to_forked_server): Compile for SERVER_SUPPORT.
+
+2004-06-30 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_append_buffer): Handle NULL from->data.
+
+2004-06-28 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c (log_buffer_flush): Sync all, not just data.
+ * buffer.c (fd_buffer_flush): Ditto. Ignore problems synchronizing
+ unsynchronizable descriptors.
+
+2004-06-28 Derek Price <derek@ximbiot.com>
+
+ Intermediate checkin on the way to enabling the write proxy.
+
+ * server.c (isSecondaryServer): Handle forked primary.
+ (read_secondary_log, move_file_offset, replace_file_offset,
+ become_proxy): New functions.
+ (reprocess_secondary_log): Use new read_secondary_log().
+ (serve_root): Replace `Root' request with new version for primary.
+ (do_cvs_command): Use new become_proxy() function.
+ (*): Gratuitous reformatting.
+ (server): Open new logs and avoid opening pipes to pserver twice.
+ * buffer.c (buf_initialize): Handle new LAST_INDEX & LAST_COUNT
+ initializers.
+ (*): Remove unnecessary typecasts. Gratuitous reformatting. Use
+ assert() rather than if()/abort().
+ (buf_append_buffer, buf_read_data, buf_copy_lines, buf_copy_counted):
+ Track LAST_INDEX & LAST_COUNT.
+ (buf_read_short_line): Track LAST_INDEX & LAST_COUNT.
+ * buffer.h (struct buffer): Add LAST_INDEX & LAST_COUNT.
+ * cvs.h: Include minmax.h.
+ * root.h (enum CVSmethod): Force null_method to 0.
+ * zlib.c: Remove unnecessary typecasts. Gratuitous reformatting. Use
+ assert() rather than if()/abort().
+
+2004-06-23 Derek Price <derek@ximbiot.com>
+
+ Checkout and probably other read-only commands now work.
+
+ * server.c (serve_expand_modules): Discard arguments even when
+ reprocessing.
+ (serve_argument): Always process arguments.
+ (serve_wrapper_sendme_rcs_options): Process in first pass.
+
+2004-06-23 Derek Price <derek@ximbiot.com>
+
+ Operate correctly in non-write proxy mode, delaying processing of most
+ commands until after the `Root' request is received.
+
+ * server.c (buf_from_net_save): New global variable to store the input
+ buffer from the client while the secondary log is being reprocessed.
+ (reprocessing): Global to track whether we are reprocessing.
+ (various redundant prototypes): Removed.
+ (fd_buffer_*): Remove unneeded typecasts.
+ (serve_valid_responses, serve_global_option, serve_set,
+ serve_valid_requests): Avoid processing twice.
+ (command_pid, outbuf_memory_error, input_memory_error): Moved above new
+ references.
+ (server): Factor loop over the client inputs to...
+ (loop_over_inputs): ...this new function.
+ (serve_root): Loop over secondary log of client inputs when we
+ discover we are not the secondary.
+ (*): Add !secondary_log assertions to verify that certain code paths
+ are not yet taken.
+ (do_cvs_command, serve_init): Add switch and pseudo-code comments about
+ what will need to be done on secondary servers.
+ (seve_noop): Print errors & "ok" in the first pass, skip "ok" but
+ restore handling of entries and notification in the second.
+ (serve_co): Note what will need to be done on secondaries.
+ (server_cleanup): Deal with buf_from_net_save when necessary.
+
+2004-06-22 Derek Price <derek@ximbiot.com>
+
+ * server.c (server): Move previously fatal error on failure to open a
+ secondary log to...
+ (serve_root): ...here, and only when we discover we are actually a
+ secondary server.
+ (server): Ensure an interrupt cannot dump core.
+
+2004-06-22 Derek Price <derek@ximbiot.com>
+
+ Enable the writeproxy log and turn it off when we determine we are not
+ running as a secondary server.
+
+ * log-buffer.c: Compile log buffer routines in server mode for write
+ proxy.
+ (struct log_buffer): Add fatal_error member.
+ (log_buffer_initialize, log_buffer_input): Allow for fatal write errors
+ for writeproxy.
+ (log_buffer_disable): Turn off the log when asked.
+ (log_buffer_shutdown): Close log via log_buffer_disable.
+ (log_buffer_input, log_buffer_output, log_buffer_flush): Don't operate
+ on the log when it doesn't exist.
+ (*): Misc gratuitous cleanup.
+ (setup_logfiles): Use new log_buffer_initialize API.
+ * log-buffer.h (log_buffer_initialize, log_buffer_disable): New
+ prototypes.
+ (log_buffer_initialize): Update prototype.
+ * server.c: Include log-buffer.h. Gratuitous reformatting of pragmas.
+ (secondary_log_name, secondary_log): New globals.
+ (server): Set up recording for writeproxy.
+ (serve_root): Turn off recording when we determine that we are not a
+ secondary.
+
+2004-06-21 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (writeproxy): Verify that secondary is updated after a
+ commit. Comment test that verifies that commit took place on primary.
+
+2004-06-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (writeproxy): Test response to a failing rsync.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * server.c (isSecondaryServer): New function.
+ (MAXHOSTNAMELEN): Move to top of file and improve comment.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * parseinfo.c (parse_config): Get my enum references correct.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * parseinfo.c (parse_config): Verify that the ProxyServer connection
+ method is valid.
+
+2004-09-02 Derek Price <derek@ximbiot.com>
+
+ * server.c (do_cvs_command): Pass new args to fd_buffer_initialize().
+ (server): Don't initialize BUF_TO_NET & BUF_FROM_NET when
+ pserver_authenticate already did.
+ (pserver_read_line): New function to access pserver auth dialogue via
+ buffers.
+ (pserver_authenticate_connection): Init buffers to/from net and access
+ via pserver_read_line() and the buffer output functions.
+ (fd_buffer_*): Move to...
+ * buffer.c (fd_buffer_*): ...here. Handle blocking input more
+ efficiently.
+ (buf_initialize): Handle get_fd() argument.
+ (buf_nonio_initialize, packetizing_buffer_initialize): Pass new
+ get_fd() argument.
+ (buf_copy_data, buf_free_data, buf_read_short_line, buf_get_fd,
+ packetizing_buffer_get_fd): New functions.
+ (bufread_line): Wrap buf_read_short_line().
+ (stdio_buffer_*): Remove these functions.
+ (*): Some reformatting of function headers.
+ * buffer.h (struct buffer, buf_initialize): Add get_fd().
+ (buf_read_short_line, buf_get_fd, buf_copy_data, buf_free_data,
+ fd_buffer_initialize): New prototypes.
+ * client.c (get_port_number, get_cvs_port_number,
+ get_proxy_port_number): Compile with SERVER_SUPPORT.
+ (make_bufs_from_fds): Likewise, and accept new ROOT arg and pass on to
+ fd_buffer_initialize().
+ (connect_to_pserver, connect_to_forked_server): Pass ROOT to
+ make_bufs_from_fds().
+ (start_server): Factor much functionality into...
+ (open_connection_to_server): ...this new function.
+ * client.h (make_bufs_from_fds): Update proto.
+ (open_connection_to_server): New proto.
+ * log-buffer.c (log_buffer_initialize): Handle get_gd().
+ (log_buffer_get_fd): New function.
+ * zlib.c (compress_buffer_initialize, compress_buffer_get_fd): Ditto
+ twice.
+ * rsh-client.c (start_rsh_server): Pass ROOT to make_bufs_from_fds().
+ * sanity.sh (pserver): Expect new error messages.
+
+2004-09-01 Derek Price <derek@ximbiot.com>
+
+ * run.c: Remove unneeded typecasts. Reformat function headers. Fix
+ trace.
+
+2004-08-31 Derek Price <derek@ximbiot.com>
+
+ * subr.c (format_cmdline), cvs.h (format_cmdline): Accept bool rather
+ than int.
+ * admin.c, commit.c, edit.c, fileattr.c, logmsg.c, tag.c: Change all
+ callers.
+ * main.c (UseNewInfoFmtStrings), cvs.h (UseNewInfoFmtStrings):
+ s/int/bool/.
+ * parseinfo.c: Change all references.
+
+2004-08-31 Derek Price <derek@ximbiot.com>
+
+ * checkout.c: Reformat function headers. Remove unnecessary typecasts
+ and prototypes. Some other reformatting for legibility.
+
+2004-08-31 Derek Price <derek@ximbiot.com>
+
+ * buffer.c: Gratuitous reformatting of header comments.
+ s/abort/assert/. Remove unnecessary typecasts.
+ * buffer.h: Remove unnecessary "extern" decls. Some reformatting.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (start_recursion): Don't shorten //. to / (use //).
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (start_recursion): Strip trailing CWD indirections on
+ repository.
+ * sanity.sh (rstar-toplevel): Update to account for new behavior.
+ (Report from Dan Peterson <dbpete@aol.com>.)
+
+2004-08-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * recurse.c (do_recursion): Correct test for calling
+ server_pause_check to occur when locktype != CVS_LOCK_WRITE.
+ (Patch suggested by Ian Lance Taylor <ian@wasabisystems.com>
+ in bug#198).
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Update a few tests to account for the recent error message
+ changes.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_valid_rev): Declare arg const.
+ * rcs.h: Likewise.
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (translate_symtag): Prevent infinite loop.
+ * tag.c (tag_check_valid): Check tag syntax before searching for tags.
+ * sanity.sh (tag-space): Some tests for the above.
+ (Report from Dan Peterson <dbpete@aol.com>.)
+
+2004-08-24 Derek Price <derek@ximbiot.com>
+
+ * tag.c (tag_check_valid): Use RCS_valid_rev() rather than duplicating
+ code. Misc error message improvements.
+
+2004-08-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * ignore.c (ignore_directory): Include the terminating NUL
+ character in the directory name comparison to avoid matching
+ substrings of directories by accident.
+ (Report and suggested fix from James E Wilson
+ <wilson@specifixinc.com>.)
+ * sanity.sh (modules4): Add some more tests testing the above
+ change.
+
+2004-08-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (binfiles): Cleanup the 2a temporary directory.
+
+2004-08-20 Derek Price <derek@ximbiot.com>
+
+ Cache tags in val-tags on successful creation to avoid problems with
+ write proxies. Merged from `writeproxy2' branch.
+
+ * tag.c (tag_filesdoneproc): Don't track posttag errors.
+ (cvstag): Move addition of successful tags to val-tags to...
+ (tag_fileproc): ...here and...
+ (rtag_fileproc): ...here. Consolidate returns at single location.
+ (*): Misc reformatting.
+
+ * tag.c (add_val_tag): New function with content factored from...
+ (tag_check_valid): ...here.
+ (cvstag): Call add_val_tag() when needed.
+ * annotate.c, checkout.c, commit.c, diff.c, ls.c, patch.c, recurse.c,
+ tag.c, update.c: Pass new args to tag_check_valid.
+
+ Merge of postadmin, posttag, and postwatch functionality from
+ `writeproxy2' branch.
+
+ * admin.c (postadmin_proc), commit.c (precommit_proc), edit.c
+ (notify_proc), fileattr.c (postwatch_proc), logmsg.c (logfile_write),
+ server.c (prepost_proxy_proc), tag.c (posttag_proc, pretag_proc): Add
+ default %c format string.
+
+ * cvs.h (CVSROOTADM_POSTWATCH): New macro.
+ * fileattr.c (*): Misc cleanup.
+ (postwatch_proc): New function.
+ (fileattr_write): Call watch proc when done writing fileattr.
+ * mkmodules.c (postwatch_contents): New var.
+ (filelist): Add postwatch.
+ * watch.c (addremove_filesdoneproc): Remove function.
+ (watch_addremove): Don't call above function.
+ (*): Misc cleanup.
+ * watch.h: Remove some unnecessary "extern" decls.
+
+ * admin.c (postadmin_proc, admin_filesdoneproc): New functions.
+ (admin): Pass admin_filesdoneproc() to start_recursion().
+ (*): Misc gratuitous cleanup.
+ * cvs.h (CVSROOTADM_*): Alphabetize, add new hook config files.
+ (format_cmdline): Fix proto to match change below.
+ * mkmodules.c (*_content): Add init content for new files. Misc
+ cleanup.
+ (filelist): Add new files.
+ * tag.c (struct pretag_proc_data): Move before first use.
+ (posttag_proc, tag_filesdoneproc): New functions.
+ (rtag_proc): Pass new procs to start_recursion().
+ (*): Misc gratuitous cleanup.
+ * sanity.sh: Misc accommodations.
+
+2004-08-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * log-buffer.c (log_buffer_output): Protect call to fsync()
+ with #ifdef HAVE_FSYNC.
+
+2004-08-18 Mark D. Baushke <mdb@cvshome.org>
+
+ * log-buffer.c (log_buffer_input): Protect call to fsync()
+ with #ifdef HAVE_FSYNC.
+
+2004-08-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (sshstdio): Fix comment typo plus gratuitous
+ reformatting.
+
+ * client.c (handle_m): Workaround to deal with stdio getting put
+ into non-blocking via redirection of stderr and interaction with
+ ssh on some platforms. On those boxes, stdio can put stdout
+ unexpectedly into non-blocking mode which may lead to fwrite() or
+ fflush() failing with EAGAIN, but cvs not checking for the error.
+ (Patch suggested by Frank Hemer <frank@hemer.org>.)
+
+ * client.c (handle_e): Similar fix for stderr.
+ * sanity.sh (sshstdio): New test for non-blocking stdio via ssh.
+
+2004-08-11 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (basicc): Work around a problem in Linux 2.2 & Bash 2.05b
+ which prevents a `cd ..' from a deleted directory from working.
+ (Original patch from Matthew Ogilvie <mmo9317bd@mailcan.com>.)
+
+2004-07-18 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (newb-123j0): Use DOTSTAR at end of response.
+
+2004-07-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * main.c (ImportNewFilesToVendorBranchOnly): New variable.
+ * cvs.h (ImportNewFilesToVendorBranchOnly): Declare new variable.
+ * import.c (import): Respect setting of
+ ImportNewFilesToVendorBranchOnly.
+ * mkmodules.c (config_contents): Document the default
+ ImportNewFilesToVendorBranchOnly=no option in newly generated
+ config files.
+ * parseinfo.c (parse_config): Parse
+ ImportNewFilesToVendorBranchOnly option.
+ * sanity.sh (importX2): New test, to test
+ ImportNewFilesToVendorBranchOnly config file option.
+ (New feature from Chris Demetriou <cgd@broadcom.com>.)
+
+2004-07-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (basic2-14): Use DOTSTAR to be more portable.
+
+ * status.c (status_fileproc): Print datetimes using output_cvs_tagged.
+ * sanity.sh (basic2-14): Allow for an extra blank line at the end.
+
+2004-07-16 Derek Price <derek@ximbiot.com>
+
+ * server.c (pamh): New global static to hold the PAM handle.
+ (server): Close the PAM session so that logging works properly.
+ (switch_to_user): Opens a PAM session and gets credentials from PAM so
+ that PAM modules can change group permissions. Get the username from
+ PAM so that PAM modules can modify the final local username.
+ (cvs_pam_conv): Changed the assertions to allow PAM to output text to
+ the user.
+ (check_system_password): Renamed to...
+ (check_pam_password): ...this. Changed argument type for username so
+ that PAM modules can modify the username under authentication. Setting
+ a terminal so some PAM modules which expect it to be set work, it is
+ set to the pam servicename which defaults to the binary name. Set the
+ username from PAM after authentication if a module has changed it.
+ (check_password): Calls check_pam_password if PAM is enabled otherwiseu
+ calls check_system_password.
+ (Patch from Brian Murphy <brian@murphy.dk>.)
+
+2004-07-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (run_filter): New function to allow for filtering of cruft
+ output by Rational Quantify or other profilers.
+ (dotest_*): Call new function.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore GCC profiling data.
+
+2004-07-12 Derek Price <derek@ximbiot.com>
+
+ * client.c: Misc reformatting.
+
+2004-07-12 Derek Price <derek@ximbiot.com>
+
+ * main.c: fix format_time_t to call localtime
+ (Patch from Bart Robinson <lomew@pobox.com>.)
+
+2004-07-02 Derek Price <derek@ximbiot.com>
+
+ * vers_ts.c: Gratuitous reformatting & detypecasting.
+
+2004-06-30 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c (log_buffer_input, log_buffer_output): Flush logs as
+ soon as they are written to better diagnose hangs.
+
+2004-06-29 Derek R. Price <derek@ximbiot.com>
+
+ * sanity.sh (toplevel-12): Handle new error output.
+
+2004-06-29 Derek R. Price <derek@ximbiot.com>
+
+ * subr.c (xrealloc_and_strcat): Use bool in place of short.
+
+2004-06-29 Derek R. Price <derek@ximbiot.com>
+
+ * client.c: Gratuitous reformatting.
+ (send_repository): Send relative Directory when server reports it is
+ able to handle it.
+ * server.c (serve_directory): Handle relative directories.
+ (output_dir): Send relative directories.
+ (requests): Add `Relative-directory' request.
+
+2004-06-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * import.c (import_usage): Add new -X flag.
+ (import): Handle new -X flag.
+ (process_import_file): Handle new -X flag.
+ (killnew): New static flag variable to indicate use of -X flag.
+ (preserve_initial_permissions): New function, extracted from
+ add_rcs_file().
+ (expand_and_copy_contents): Likewise.
+ (add_rcs_file): New argument, do_killnew, to cause "import -X" flag
+ processing. Implement -X flag, and use newly abstracted functions.
+ * rcs.h (add_rcs_file): Update prototype for do_killnew argument.
+ * commit.c (checkaddfile): Update for add_rcs_file function change.
+ * mkmodules.c (init): Likewise.
+ * client.c (handle_mt): Handle an importmergecmd tag without
+ any conflicts (for 'import -X' support).
+ * sanity.sh (importX): New test.
+ (New feature from Chris Demetriou <cgd@broadcom.com>.)
+
+2004-06-22 Derek Price <derek@ximbiot.com>
+
+ * wrapper.c: Add explicit "void" return type to "wrap_clean_fmt_str"
+ definition.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * server.c (entries, serve_is_modified): Reorder to remove prototypes.
+ (supported_response): Remove prototype.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * commit.c, filesubr.c, history.c, server.c, wrapper.c: Various
+ security fixes.
+ (Original patch from Stefan Essler <s.esser@e-matters.de> & Sebastian
+ Krahmer <krahmer@suse.de>.)
+
+ * cvs.h: Include xsize.h.
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * server.c (serve_entry, serve_is_modified, serve_unchanged): Protect
+ against malformed entries.
+ * sanity.sh (server): Tests for same.
+
+2004-06-07 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * sanity.sh (basica): More tests for string-based revision inc.
+
+2004-06-04 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * subr.c (increment_revnum): Rewrite ala RCS to work directly on
+ the string rather than converting to int to avoid overflow.
+ * sanity.sh (basica): New tests for above, update others to match.
+
+2004-06-04 Derek Price <derek@ximbiot.com>
+
+ Preliminary writeproxy functionality.
+ * main.c: Declare PrimaryServer.
+ * cvs.h: Likewise, but extern.
+ * mkmodules.c: Add PrimaryServer to default CVSROOT/config content.
+ * parseinfo.c: Handle PrimaryServer line.
+ * sanity.sh: (Failing) tests for writeproxy functionality.
+
+2004-05-28 Derek Price <derek@ximbiot.com>
+
+ * main.c (format_time_t, gm_format_time_t): Use my_strftime from
+ GNULIB rather than the system-dependant strftime.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: s/GMT/UTC/ where appropriate.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * server.c (cvs_output_tagged): Move new server code inside a
+ SERVER_SUPPORT block.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (gmformat_time_t, entries_time, unix_time_stamp): New protos.
+ * ls.c (struct long_format_data): New structure.
+ (ls_print): Print datetimes using cvs_output_tagged.
+ (long_format_data_delproc): New function.
+ (ls_fileproc, ls_direntproc): Keep track of long_format_data.
+ * main.c (Make_Date): Use standard quotes.
+ (format_time_t, gmformat_time_t): New functions.
+ (format_date_alloc): Use new functions. Improve comments.
+ * server.c (cvs_output_tagged): Only output in localtime in local mode.
+ * vers_ts.c (entries_time, unix_time_stamp): New functions.
+ (time_stamp): Use new functions.
+ * sanity.sh (ls, branches2): Use $ISO8601DATE where applicable.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ Output `cvs log' times in the local timezone.
+
+ * client.c (handle_mt): Handle the new "date" MT response
+ * server.c (cvs_output_tagged): Likewise
+ * cvs.h: Proto for format_date_alloc
+ * main.c (format_date_alloc, tm_diff): Added.
+ * log.c (log_version): Use MT response to tag date output.
+ (Original patch from Bart Robinson <lomew@pobox.com>.)
+
+ * sanity.sh (importc, rcs, rcs4): Use TZ=GMT for the duration of these
+ tests to obtain consistent times in output.
+ (ISO8601DATE, ISO8601DATE1971, ISO8601DATE2034): Use more precise
+ regex.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * server.c (serve_unchanged, serve_is_modified): Overwrite existing
+ data in timefields. Fixes CAN-2004-0396.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ * lock.c (Lock_Cleanup), rcs.c (rcs_cleanup), server.c
+ (server_cleanup): Clean up inchoherent comment.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ * cvs.h, client.c, history.c, main.c, rcs.c, sanity.sh, server.c:
+ Back out get_date() changes from 2004-04-28.
+
+2004-05-14 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (trailingslashes): During cleanup remove topfile,v to
+ avoid problems in later tests (editor-1).
+
+2004-05-13 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (trailingslashes): Note TODO item #205 in the comment.
+
+2004-05-13 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (trailingslashes): New tests to expose a bug in CVS when
+ paths are specified with trailing slashes. This relates to TODO #205.
+
+2004-05-13 Mark D. Baushke <mdb@cvshome.org>
+
+ * ls.c (ls): Use client_senddate() so the server is able to parse
+ the date/time.
+
+2004-05-12 Derek Price <derek@ximbiot.com>
+
+ * entries.c, subr.c: Gratuitous reformatting.
+
+2004-05-12 Derek Price <derek@ximbiot.com>
+
+ * subr.c (file_has_conflict), vers_ts.c (time_stamp_server): Only
+ special case "=" when it is the only character in a timestamp field.
+ Gratuitous reformatting.
+ * vers_ts.c (time_stamp_server): Check for NULL in a consistent manner.
+ Gratuitous reformatting.
+
+2004-05-12 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (ls): Add some new tests of the ls command with dates
+ specified and show an assertion error when an existing file is
+ specifically requested.
+ (Original patch from Alexander Taler <dissent@cvshome.org>.)
+
+2004-05-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (RCSKEYDATE): New regular expression to match the rcs
+ keyword date format.
+ (keyword,keywordlog): Use it.
+ (RCSDELTADATE): New regular expression to match the internal rcs
+ file format delta.
+ (admin): Use it.
+ (RCSDATE): Deleted.
+ (ISO8601DATE}: A more exact regular expression for cvs log date
+ output than the previous RCSDATE variable.
+ (basica,basic2,branches,branches3,multibranch,import,importb,importc,
+ join,modules,editor,binfiles,log,log2,keyword,multibranch2,admin,
+ reserved,recase,multiroot,trace):
+ Use ${ISO8601DATE} for cvs log output date patterns.
+ (TOUCH1971,ISO8601DATE1971): New variables for test importc.
+ (TOUCH2034,ISO8601DATE2034): Ditto.
+ (importc): Use them. Isolate the touch commands in a sub-shell
+ with TZ=GMT to make the time more predictable.
+ (RAWRCSDATE2000A,RAWRCSDATE1996A,RAWRCSDATE1996B): New date variables.
+ (ISO8601DATE2000A,ISO8601DATE1996A,ISO8601DATE1996B): Regexps to match.
+ (rcs): Use them.
+ (rcs4): Put the touch commands into sub-shells for temporary
+ TZ=GMT use.
+
+2004-05-11 Derek Price <derek@ximbiot.com>
+
+ * checkin.c (Checkin), commit.c (commit_filesdoneproc, remove_file,
+ checkaddfile), rcs.c (RCS_checkin): Remove redundant commit messages.
+ Suppress output when really_quiet.
+ * sanity.sh: Update to match.
+
+2004-05-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (top-level): Rename to...
+ (rstar-toplevel): ...this for clarity.
+
+2004-05-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (dirs2-10ar): Remove unnecessary empty argument.
+
+2004-05-08 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * log.c (log_expand_revlist): Suppress warnings if really_quiet.
+
+2004-05-08 Derek Price <derek@ximbiot.com>
+
+ * server.c: Gratuitous reformatting. Remove unnecessary prototype &
+ unnecessary type cast.
+
+2004-05-07 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (basica): Remove unnecessary empty arguments.
+
+2004-05-07 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (fopen_case): Remove obsolescent prototype.
+
+2004-05-05 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Wait a second and retry if cvs-serv* directories are
+ discovered to avoid race conditions on some systems.
+ (Patch from Pavel Roskin <proski@gnu.org>.)
+
+2004-05-05 Derek Price <derek@ximbiot.com>
+
+ * commit.c: Some gratuitous reformatting.
+
+2004-05-04 Derek Price <derek@ximbiot.com>
+
+ * update.c: Some gratuitous reformatting.
+
+2004-05-04 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Remove obsolete FIXME comment.
+ (*): Some gratuitous reformatting.
+
+2004-05-03 Derek Price <derek@ximbiot.com>
+
+ * src/sanity.sh (branches2-14-ls-4): Change expectations due to new -d
+ flag.
+
+2004-05-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (ls): Add some new tests of ls -d flag.
+ (Original patch from Alexander Taler <dissent@cvshome.org>.)
+
+ * ls.c (ls): Accept -d to show dead files.
+ (ls_proc): Add W_ATTIC to start_recursion flags when user requests dead
+ files.
+ (ls_fileproc): Don't show dead files with -d. Print "dead" in long
+ listings for dead files.
+
+2004-05-02 Derek Price <derek@ximbiot.com>
+
+ * ls.c (ls_dirleaveproc): Return err.
+ (Original patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-05-02 Derek Price <derek@ximbiot.com>
+
+ * ls.c (ls_print): Return 0.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-04-30 Derek Price <derek@ximbiot.com>
+
+ * tag.c (tag_check_valid): Treat a NULL repository the same as an empty
+ one.
+ * sanity.sh (branches2-ls-7): Verify absence of assertion failure.
+
+2004-04-29 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (branches2-rls-1): Reformat comment.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcs2-5): Update to cope with new getdate.y.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs_LIBADD): Use libs for nanosleep & clock_gettime when
+ necessary.
+ * cvs.h: Remove get_date() proto and #include getdate.h.
+ * client.c, history.c, main.c, rcs.c, server.c: Use new form of
+ get_date().
+ * Makefile.in: Regenerated.
+
+2004-04-28 Derek Price <derek@ximbiot.com>
+
+ * lock.c (set_lock), subr.c (sleep_past): Assume we have nanosleep.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * root.c (normalize_cvsroot): Use asnprintf in preference to other
+ indirections.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ Add dirname module from GNULIB.
+
+ * add.c, client.c, commit.c, find_names.c, import.c, lock.c, ls.c,
+ repos.c, server.c, subr.c: s/ISDIRSEP/ISSLASH/.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * commit.c, create_adm.c, entries.c, filesubr.c, hash.c, update.c:
+ Gratuitious reformatting.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * ls.c (ls_direntproc): Remove unneeded assertion.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * ls.c (ls): Set client_prune_dirs in order to delete any directories
+ created by the server.
+ (ls_dirleaveproc): Always delete directories created by
+ ls_direntproc().
+ * sanity.sh (ls): Update to match.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * ls.c: Remove unneeded prototypes. Add `prune' option.
+ (dircount): Remove static global.
+ (set_tag, created_dir, ls_prune_dirs): New static globals.
+ (ls): Handle new prune option.
+ (ls_print_dir): Don't count directories, just remember not to print a
+ blank line in front of the first one. Don't list empty directories
+ when prune is specified.
+ (ls_delproc): New function to dispose of dirlist.
+ (ls_direntproc): Reorganize to assume a directory without a parent must
+ be listed. Create missing directories a la update and checkout so that
+ they may be processed. Use new delproc when creating new list nodes.
+ (ls_dirleave_proc): New function to remove directories created by
+ ls_direntproc.
+ (ls_proc): Call start_recursion() once for each argument so that
+ ls_direntproc() may assume that any directory without a parent in the
+ dirlist must be listed and others must not unless recursing.
+ * sanity.sh (ls): New tests.
+ (Thanks to a report from Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-04-26 Derek Price <derek@ximbiot.com>
+
+ * rsh-client.c (start_rsh_server): Don't rely on GNU argument
+ processing capabilities in the RSH command.
+ (Report from Mark Andrews <Mark_Andrews@isc.org>.)
+
+2004-04-26 Derek Price <derek@ximbiot.com>
+
+ * ls.c (dircount): s/long long/long/ for Windows.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * ls.c (usage): Sync with manual.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs_SOURCES): Add ls.c.
+ * client.c, subr.c: Move #include vasnprintf.h to...
+ * cvs.h: ...here.
+ (ls): Add prototype.
+ * ls.c: New file.
+ * main.c (cmds): Add ls & rls entries.
+ * server.c (serve_ls, serve_rls): New functions.
+ (requests): Add list, ls, rlist, & global-list-quiet.
+ * sanity.sh (branches2): Test new cvs ls & rls commands.
+ * Makefile.in: Regenerated.
+ (Thanks for patches from Alexander Taler <dissent@cvshome.org>
+ and Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (AM_CPPFLAGS): No, really, $(top_builddir)/lib.
+ * Makefile.in: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (AM_CPPFLAGS): Add the builddir/lib directory for
+ generated header files.
+ * Makefile.in: Regenerated.
+
+2004-04-22 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Move include of fnmatch.h into lib/system.h with the other
+ GNULIB headers.
+
+2004-04-22 Derek Price <derek@ximbiot.com>
+
+ * tag.c: Use bool where appropriate. Some gratuitous reformatting.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * ignore.c: Gratuitous reformatting.
+
+2004-04-16 Derek Price <derek@ximbiot.com>
+
+ * tag.c: Gratuitous reformatting.
+
+2004-04-16 Derek Price <derek@ximbiot.com>
+
+ * client.c (connect_to_pserver): Use size_t instead of int as argument
+ to asnprintf. Some gratuitous reformatting.
+ (Report from Mark <cm_mark@yahoo.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * client.c, commit.c, server.c: Gratuitous reformatting.
+
+2004-04-11 Derek Price <derek@ximbiot.com>
+
+ * client.c (call_in_directory): Check paths the server sends us to make
+ sure they are within a sandbox the user requested be updated.
+ (is_valid_client_path, path_list_prefixed): New functions.
+
+2004-04-11 Derek Price <derek@ximbiot.com>
+
+ * modules.c (do_module): Don't allow up-level references in paths to
+ step out of the repository.
+ * sanity.sh (multiroot3): Update tests and add a few more.
+
+2004-04-11 Derek Price <derek@ximbiot.com>
+
+ * client.c (get_proxy_port_number): Use CVS_PROXY_PORT as the default
+ proxy port rather than CVS_AUTH_PORT.
+
+2004-04-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * client.c (get_cvs_port_number): Use CVS_AUTH_PORT as the default
+ for "cvspserver" rather than the CVS_PROXY_PORT.
+ (Fixes parseroot-3r on machines without "cvspserver" in
+ their /etc/services file.)
+
+2004-04-07 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (parseroot): s/oberon/$username/.
+
+2004-04-06 Derek Price <derek@ximbiot.com>
+
+ Import Jim Kingdon's old, old patch which allows CVS to work via a
+ web proxy server.
+ * client.c (*): Some gratuitous restyling.
+ (get_proxy_port_number): New function.
+ (connect_to_pserver): Connect via proxy.
+ * client.h (CVS_PROXY_PORT): Define.
+ * root.c (parse_cvsroot): Parse method options.
+ * sanity.sh (parseroot): Add new tests.
+
+2004-04-06 Derek Price <derek@ximbiot.com>
+
+ * root.h (cvsroot_t): Move username, password, hostname, port inside
+ CLIENT_SUPPORT ifdefs.
+ * buffer.c, gssapi-client.c, root.c, sever.c: Add #ifdefs as necessary
+ so that this will compile without client support and the root.h change.
+ Some gratuitous restyling.
+
+2004-04-06 Derek Price <derek@ximbiot.com>
+
+ * log.c, tag.c: Gratuitous restyling.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (isabsolute): Move...
+ * subr.c: ...here and use new ISABSOLUTE macro.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_file_names): Cast out an unneeded const to avoid a
+ warning.
+
+2004-04-03 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * cvsrc.c: Remove unused declarations.
+ * run.c: Ditto.
+ * server.h (gunzip_and_write): Declare.
+
+ * client.c (send_file_names): Remove unused variables.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (client): Honor $keep.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * log.c, patch.c, rcs.c: Gratuitous restyling.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * import.c (import): Use ISDIRSEP rather than testing paths against `/'
+ directly. Some gratuitos reformatting.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Note the effectiveness of `tail -f check.log' in providing
+ running status.
+
+2004-04-02 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_file_names): Move code which calculates and sends
+ Max-dotdot...
+ (send_max_dotdot): ...to this new function.
+ (send_files): Call send_max_dotdot.
+ * sanity.sh (files-14): Expect .. in paths to work now.
+ (status): Add a few new tests using `..'.
+
+2004-04-01 Derek Price <derek@ximbiot.com>
+
+ * lock.c: Gratuitous restyling.
+
+2004-04-01 Derek Price <derek@ximbiot.com>
+
+ * commit.c, cvs.h, server.c: Gratuitous restyling.
+ * run.c (run_exec): Ditto, plus call cvs_flush{out,err}() instead of
+ flushing stderr & stdout directly.
+
+2004-03-29 Derek Price <derek@ximbiot.com>
+
+ * login.c, server.c: Gratuitous restyling.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_file_names): Initialize string to NULL rather than to
+ a single byte string containing only a null byte.
+ * subr.c (xrealloc_and_strcat): If the destination string is NULL,
+ simply allocate a new string.
+ (Original report from Chris Bohn <cbohn@rrinc.com>.)
+
+2004-03-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (ISODATE): Fix ISO 8601 format comment.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (toplevel): Remove FIXME type comment and unneeded
+ Emtptydir removal.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * update.c: Some minor style cleanup.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * update.c: Some minor style cleanup.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (top-level): Don't match most of the assertion since this
+ string is often system dependent.
+ (Thanks to Larry Jones <lawrence.jones@ugsplm.com>.)
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (top-level): Don't match the assertion's line number.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (top-level): New test to confirm assertion failure.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Only verify argument to -f when -f was passed. Check for
+ $TMPDIR/cvsXXXXXX temp files after each test.
+
+2004-03-22 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Verify that the argument to -f is really a test.
+
+2004-03-20 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * cvs.h: Change command_name to cvs_command_name to avoid conflict
+ on HP-UX (incredibly, it declares a global command_name in prot.h,
+ which is included from shadow.h, which we include in server.c).
+ Change all references.
+
+ * subr.c (previous_rev): Fix == vs = typo.
+
+ * buffer.h: Add prototype for buf_empty.
+
+ * add.c (add): Remove unused variable.
+
+2004-03-20 Derek Price <derek@ximbiot.com>
+
+ * add.c (add, add_directory, build_entry), admin.c (admin_dirproc),
+ checkin.c (Checkin), checkout.c (safe_location, build_dirs_and_chdir),
+ client.c (add_prune_candidate, send_repository, send_a_repository,
+ send_to_server, start_rsh_server, send_arg, send_modified,
+ send_ignproc, send_filesdone_proc, send_dirent_proc,
+ send_dirleave_proc, client_notify), commit.c (check_direntproc,
+ check_filesdoneproc, checkaddfile, commit_direntproc,
+ commit_dirleaveproc, lock_RCS, precommit_proc, find_data,
+ find_dirent_proc, find_ignproc, find_filesdoneproc), create_adm.c
+ (Create_Admin), cvsrc.c (read_cvsrc), diff.c (diff_dirproc,
+ diff_filesdoneproc, diff_dirleaveproc), edit.c (onoff_filesdoneproc,
+ mark_up_to_date, editor_set, notify_proc_args, notify_proc, notify_do,
+ notify_check), entries.c (Scratch_Entry, Register, WriteTag),
+ expand_path.c (expand_variable, expand_path), fileattr.c
+ (fileattr_startdir), filesubr.c (mkdir_if_needed, xchmod,
+ last_component), history.c (history_write), ignore.c (ignore_directory,
+ ignore_files), import.c (get_comment, add_rcs_file, expand_at_signs),xi
+ lock.c (lock_filesdoneproc), log.c (log_dirproc), logmsg.c
+ (logfile_write, rcsinfo_proc, update_logfile_proc, editinfo_proc,
+ verifymsg_proc, do_editor, do_verify, Update_Logfile), main.c (main
+ program_name, program_path, command_name), parseinfo.c (Parse_Info),
+ patch.c (patch_dirproc), rcs.c (RCS_getdatebranch, rcs_lockfilename,
+ RCS_parse, RCS_setattic, RCS_getversion, RCS_gettag, RCS_getbranch,
+ RCS_getdate, RCS_datecmp, RCS_getrevtime, RCS_setexpand,
+ expand_keywords, RCS_checkout, RCS_addbranch, RCS_checkin, RCS_lock,
+ RCS_cmp_file, RCS_deltas, rcs_lockfilename, make_file_label),
+ rcscmds.c (RCS_output_diff_options, call_diff, RCS_merge,
+ RCS_exec_rcsdiff, diff_exec), recurse.c (start_recursion, do_recursion,
+ do_file_proc), remove.c (remove_dirproc), repos.c (Name_Repository,
+ Short_Repository), root.c (Name_Root, Create_Root), run.c
+ (piped_child), server.c (output_dir, server_register,
+ server_checked_in, server_update_entries, server_copy_file,
+ server_set_entstat, server_clear_entstat, server_set_sticky,
+ server_template, cvs_output_tagged), status.c (status_dirproc), subr.c
+ (make_message_rcslegal), tag.c (pretag_proc, tag_dirproc,
+ check_fileproc, check_filesdoneproc, tag_fileproc, val_direntproc),
+ update.c (update_dirent_proc, update_dirleave_proc, update_ignproc,
+ update_filesdone_proc, isemptydir), vers_ts.c (time_stamp_server,
+ time_stamp), watch.c (watch_modify_watchers, addremove_filesdoneproc),
+ zlib.c (read_and_gzip): Make most string args const, mainly in the
+ interest of preserving repository & updatedir but including some
+ collateral damage. Update a few functions to comply with new
+ requirement. Some style fixes.
+ * client.h, cvs.h, edit.h, fileattr.h, rcs.h, server.h, update.h,
+ watch.h: Update prototypes to match.
+
+2004-03-20 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (conflicts2): s/cvs/$testcvs/.
+
+2004-03-20 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Correct longstanding resurrection bugs. Remove FIXME
+ comment to this effect. Set mode and Entries timestamps of resurrected
+ files correctly.
+ * sanity.sh (basica, binfiles, conflicts2, recase, resurrection,
+ update-p): Update tests to compensate. Remove FIXCVS comments.
+
+2004-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (gserver_authenticate_connection): Handle large
+ GSSAPI packets dynamically.
+ (Bug report from Douglas Engert <DEEngert@anl.gov>)
+
+2004-03-19 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (pathname_levels, previous_rev): Remove leading underscore from
+ prototype arguments to avoid potential conflicts with implementations.
+
+2004-03-18 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (pathname_levels): Make string argument const.
+ * subr.c (pathname_levels): Simplify function.
+
+2004-03-17 Derek Price <derek@ximbiot.com>
+
+ * commit.c (precommit_list_to_args_proc), logmsg.c (do_editor), subr.c
+ (format_cmdline), tag.c (pretag_list_to_args_proc):
+ s/atribute/attribute/.
+ (Report from Matthew Doar <matt@trpz.com>.)
+
+2004-03-17 Derek Price <derek@ximbiot.com>
+
+ * subr.c (pathname_levels): Get it right this time.
+
+2004-03-17 Derek Price <derek@ximbiot.com>
+
+ * subr.c (pathname_levels): Remove incorrect assertion and just
+ return 0 when pathname is NULL.
+
+2004-03-17 Derek Price <derek@ximbiot.com>
+
+ * subr.c (pathname_levels): Use ISDIRSEP() instead of strchr('/')
+ and remove FIXME comment to that effect.
+
+2004-03-16 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Update the --version Copyright (c) string to
+ include 2004.
+
+2004-03-15 Mark D. Baushke <mdb@cvshome.org>
+
+ * release.c (release): Add missing xmalloc of update_cmd.
+
+2004-03-15 Derek Price <derek@ximbiot.com>
+
+ * release.c (release): Enable authentication and encryption for a child
+ update process when necessary.
+ (Original patch from Dan Russell <russelld@aol.net> via Hal Mahaffey
+ <HMahaffey@aol.com>.)
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Only call server_updated() when we actual have a new
+ resurrected file for the client.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (previous_rev, write_letter): New prototypes.
+ (struct file_info): Move to before the write_letter prototype.
+ * add.c (add): Allow resurrection of files which used to exist on a
+ branch.
+ * subr.c (previous_rev): New function.
+ * update.c: Consolidate like pragmas.
+ (write_letter): Remove prototype. Remove static declaration.
+ * sanity.sh (resurrection): New tests.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * commit.c (remove_file): Print the actual previous revision instead of
+ a branch number.
+ * sanity.sh: Update to match.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_cmp_file): Print the actual name of the file we failed to
+ open in the error message.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * diff.c (diff_fileproc): Allow diffing of new files against arbitrary
+ revisions instead of assuming that there is no RCS archive file.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Update serveral tests to use $CPROG & $SPROG correctly.
+
+2004-03-14 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Update file resurrection messages for consistency.
+ * sanity.sh: Update to match.
+
+2004-03-13 Derek Price <derek@ximbiot.com>
+
+ * server.c (server_updated): Fix header comment.
+
+2004-03-13 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs_SOURCES): Remove error.h since it is now included in
+ lib.
+ * Makefile.in: Regenerated.
+
+2004-03-09 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * run.c: Move #includes required for cmdline_escape and friends...
+ * subr.c: ...to here.
+
+2004-03-07 Derek Price <derek@ximbiot.com>
+
+ * run.c (struct cmdline_bindings, cmdline_bindings_hash_node_delete,
+ cmdline_escape, cmdline_quote, format_cmdline): Move...
+ * subr.c: ...here so they will compile under Windows.
+
+2004-03-03 Derek Price <derek@ximbiot.com>
+
+ * import.c (import): Check that the module name specified by the user
+ does not contain `CVS' as a directory name.
+ * ignore.c (ign_add): Never cease ignoring "CVS" - it is a reserved
+ name.
+ (Original patch from Dan Peterson <dbpete@aol.com>.)
+
+ * sanity.sh (import-CVS): New tests for the above.
+
+2004-02-29 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * import.c (expand_at_signs): Change type of len to size_t.
+ * subr.c (resolve_symlink): Move declaration of newname inside
+ #ifdef, clean up coding style.
+ * zlib.c (gunzip_and_write): Fix up potential overlow problems.
+ (read_and_gzip): Add explicit casts to placate paranoid compilers.
+
+2004-02-28 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * sanity.sh (join6): New tests for previous fix.
+
+ * update.c (join_file): One more fix to avoid dereferencing NULL.
+ (Reported by Steve McIntyre <steve@einval.com>.)
+ * sanity.sh (join6): New tests for above.
+
+2004-02-25 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * update.c (join_file): Fix optimization to avoid dereferencing NULL.
+ (Reported by Steve McIntyre <steve@einval.com>.)
+
+2004-02-25 Derek Price <derek@ximbiot.com>
+
+ No longer require directories specified to `checkout -d' to exist.
+
+ * checkout.c (safe_location): Only confirm that destination is a safe
+ location for directories that already exist since we can assume that
+ creating directories under such a safe directory is acceptable.
+ (dir_to_build): Remove just_chdir member.
+ (checkout_proc): Add trace. No longer set dir_to_build->just_chdir.
+ Minor reformatting.
+ (build_dirs_and_chdir): Don't create or register directories that are
+ not created.
+ * sanity.sh (*): Update tests to account for new behavior.
+
+2004-02-25 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (buf_empty): New function.
+ * server.c (server): Check for unread data in buffer before closing.
+
+2004-02-25 Derek Price <derek@ximbiot.com>
+
+ * release.c (release): Restore the initial directory before and after
+ calling various sections of code that expect it to prevent corruption
+ of CVS/Entries files on release of a subdir and tell unedit() what to
+ release.
+ * sanity.sh: Add test case for release.c fix.
+ (Original patch from Matthew Ogilvie <mmo9317bd@mailcan.com>.)
+
+ * client.c (last_entries): Move global variable...
+ (call_in_directory): ...here (now a local variable). Remove test that
+ always evaluates to true.
+ (last_dir_name): Remove unused global variable.
+
+2004-02-24 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * filesubr.c (xresolvepath): Fix crash in error case.
+ (Reported by Reinhard Zierke <zierke@informatik.uni-hamburg.de>.)
+
+2004-02-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (crerepos): Fix it so that it ignores the user's
+ .cvsrc file (.cvsrc "checkout -r" used to cause the "rm -r 1"
+ command to print warnings and wait for input).
+ (Original patch from Matthew Ogilvie <mmo9317bd@mailcan.com>.)
+
+ * sanity.sh (reposmv, parseroot, devcom3, binwrap3):
+ s/_SAVED\>/_save/ for consistency.
+
+2004-02-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (taginfo-newfmt-examine-2): Correct expected results.
+
+2004-02-23 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * sanity.sh (taginfo-examine-1): Correct expected results.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ * subr.c (expand_string): Use x2realloc() from GNULIB for core
+ functionality.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ * subr.c (set_nonblock_fd): Move back to...
+ * server.c: ...here.
+ * cvs.h: Remove protos for the above two functions.
+ * buffer.c (stdio_buffer_shutdown): Remove unexessary and possibly
+ dangerous check for unread data on a pipe with a nonblock read.
+
+2004-02-20 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * tag.c (check_fileproc): Remove unused variable.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ * ChangeLog, commit.c, filesubr.c, rcs.c, root.c, sanity.sh, subr.c,
+ update.c: Remove VIM editor commands.
+
+2004-02-20 Derek Price <derek@ximbiot.com>
+
+ Import xalloc module from GNULIB, as well as its remaining unimported
+ dependency, the exitfail module.
+
+ * cvs.h: #include "xalloc.h".
+ * subr.c (xmalloc, xrealloc, xstrdup): Remove these functions.
+
+2004-02-20 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * hash.h (struct node): Change data from char * to void *, change
+ all callers.
+
+ * run.c (cmdlinequote, cmdlineescape): Use prototype in definition
+ to match cvs.h.
+ (format_cmdline): UNIQUE_*_TYPE_* macros imply HAVE_*, so no need
+ to check for both. Remove duplicate code for size_t and ptrdiff_t.
+
+ * tag.c (check_fileproc): Remove spurious invalid cast, clean up
+ coding style.
+
+ * commit.c (precommit_list_proc): Remove vestigial prototype.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * run.c (format_cmdline): Don't accept printf `L' modifier at all when
+ long doubles are not available. Allow UNIQUE_FLOAT_TYPE_LONG_DOUBLE to
+ imply HAVE_LONG_DOUBLE.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * run.c: Remove include of stddef.h - it is already included via
+ lib/system.h.
+
+2004-02-19 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * run.c: Include the appropriate headers for wchar_t and wint_t,
+ create a typedef for convproc and use it (required for va_arg),
+ add explicit comparisons to keep gcc -Wall happy, remove unused
+ variables.
+ (format_cmdline): Fix bugs and portability problems.
+ * tag.c: Remove unused global variable.
+ (pretag_proc): Correct call to format_cmdline: %hhc is not a valid
+ printf format (should just be %c) and NULL must be cast to the correct
+ type in a varargs call.
+ (pretag_list_to_args_proc): Initialize arg to keep gcc -Wall happy,
+ remove unused variable, add auxiliary variable to simplify code,
+ clean up coding style.
+
+ * commit.c (precommit_list_to_args_proc): Initialize arg to keep
+ gcc -Wall happy, remove unused variable, clean up coding style.
+ (precommit_proc): Cast NULL to the correct type in varargs call.
+ * edit.c (notify_proc): Remove unused variables.
+ * expand_path.c (expand_path): Initialize inquotes, add explicit
+ comparison to keep gcc -Wall happy.
+ * logmsg.c: Remove unused global variables and function decl.
+ (do_verify): Add explicit comparison to keep gcc -Wall happy,
+ clean up coding style.
+ (logmsg_list_to_args_proc): Initialize arg to keep gcc -Wall happy,
+ remove unused variable.
+ (logfile_write): Cast NULL to the correct type in varargs call.
+ (verifymsg_proc): Cast NULL to the correct type in varargs call.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * run.c (format_cmdline): Correct some typos and cut/paste errors.
+ Switch on HAVE_WINT_T for Solaris. Switch on HAVE_INTMAX_T for other
+ pre-C99 platforms.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (crerepos): Correct comment.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * logmsg.c (verifymsg_proc), run.c (format_cmdline): Plug memory leak.
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+ * run.c (format_cmdline): Simplify two expressions.
+
+2004-02-19 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * login.c (password_entry_operation): Initialize line.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (tests): Add errmsg3.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (errmsg3): Don't create directories named `tmp' in
+ $TESTDIR to avoid conflicts with the default value of $TMPDIR.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (crerepos): Don't create directories named `tmp' in
+ $TESTDIR to avoid conflicts with the default value of $TMPDIR.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (directory_cmp): Use $TESTDIR for temporary files, like the
+ dotest functions.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: No longer allow user override of $tmp. Set $TMPDIR to a
+ directory under $TESTDIR, as for $HOME, but still allowing for user
+ override. Check for cvs-serv* directories under $TMPDIR rather than
+ $tmp at the end of the script.
+
+2004-02-19 Derek Price <derek@ximbiot.com>
+
+ * run.c (cmdline_quote): Plug memory leak.
+ (format_cmdline): Don't bother with freeing memory before a call to
+ error() which will exit. Plug memory leak.
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-02-18 Derek Price <derek@ximbiot.com>
+
+ * run.c (format_cmdline): Move variable declaration to a position more
+ acceptable to the ANSI C standards.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * commit.c (precommit_proc): Installed new format_cmdline() instead
+ of the old, nonuniform info file interpreter. Support for new user
+ data field in Parse_Info() callbacks. Use cmdlinequote() instead of c.
+ 10 lines of quote processing.
+ * cvs.h (expand_path): Update proto.
+ (UseNewInfoFmtStrings): New global variable to keep track of the config
+ option of the same name.
+ (format_cmdline): Added function prototypes and type definitions to
+ support this new function.
+ * edit.c (notify_proc): Added the formatsafe flag to an
+ expand_path() call. Installed new format_cmdline() instead of the old,
+ nonuniform info file interpreter. Support for new user data field in
+ Parse_Info() callbacks.
+ * expand_path.c (expand_path): Added the formatsafe flag to and some
+ code to double up '%'s in variable subs if formatsafe is set on the
+ presumption that the variables that expand_path() subs into the string
+ are already working paths to files or whatever. It should be quoting
+ too but I haven't done that yet.
+ * logmsg.c (title_proc, logmsg_list_to_args_proc, update_logfile_proc,
+ rcsinfo_proc, editinfo_proc, verifymsg_proc, logfile_write): Installed
+ new format_cmdline() instead of the old, nonuniform info file
+ interpreter. Support for new user data field in Parse_Info()
+ callbacks.
+ * main.c: Added global UseNewInfoFmtStrings variable to keep track
+ of the config file option of the same name (see above).
+ * mkmodules.c (commitinfo_contents, editinfo_contents,
+ taginfo_contents, verifymsg_contents, loginfo_contents: Document new
+ format string features.
+ (config_contents): Added new UseNewInfoFmtStrings option with default
+ of yes.
+ * modules.c (do_module): Added the formatsafe flag to an
+ expand_path call.
+ * parseinfo.c (Parse_Info, parse_config): Added the formatsafe flag
+ to an expand_path() call. Added handling for UseNewInfoFmtStrings
+ option in the config file. Set to no, modifications needed to set to
+ yes are harmless. Set to yes, modifications needed for full
+ compatibility cause deprecation warnings. Eliminating deprecation
+ warnings should allow executable to be compile with
+ --disable-old-info-format-support passed into configure. Added user
+ data field (closure) which is passed through into callproc to
+ Parse_Info().
+ * run.c (format_cmdline): New function to provide uniform handling of
+ *info file scripting hook lines.
+ (cmdline_bindings_hash_node_delete,
+ (cmdlineescape, cmdlinequote): New functions to "quote" and "escape"
+ strings like you would to get them past a command line parser as an
+ argument.
+ (run_setup): Made quote aware
+ * sanity.sh (info, taginfo, config, pserver, lockfiles, reserved):
+ New tests for the new format string functionality as well as the
+ support of backwards compatibility. Had to alter a few of the tests to
+ not care which version of some of the (shared) config files they'd just
+ checked in so that the tests can be run in any order.
+ (taginfo): Add tests for file names with spaces in them.
+ * server.c (template_proc): Support for new user data field in
+ Parse_Info() callbacks.
+ * tag.c (pretag_proc): Installed new format_cmdline() instead of the
+ old, nonuniform info file interpreter. Add support for new user data
+ field in Parse_Info() callbacks.
+ (check_fileproc): Add proper tag_info struct as node data rather than a
+ single revision number in a string and pass tlist properly rather than
+ in a global variable.
+ (check_filesdone_proc): Altered to use non-global tlist.
+ (tag_delproc): Handle new tag_info struct data members.
+ (pretag_list_to_args_proc): Ditto.
+ (pretag_list_proc): Deleted.
+ * wrapper.c (Parse_Info): Added the formatsafe flag to an expand_path()
+ call.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Check for $PWD != $TESTDIR after each set of tests rather
+ than once at the end. Check that there are no cvs-serv* directories in
+ $tmp after each set of remote tests.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Don't check for an empty $TESTDIR - if $TESTDIR was empty
+ then the preceding call to mkdir would have failed anyhow.
+
+2004-02-17 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * log.c (rlog_proc): Fix (harmless) uninitialized variable.
+
+ * sanity.sh (basicc): Add tests pointing out defective handling
+ of the Entries file.
+
+2004-02-17 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (build_dir_and_chdir): Expand header comment.
+
+2004-02-15 Mark D. Baushke <mdb@cvshome.org>
+
+ * annotate.c (rannotate_proc): Plug a memory leak.
+ * log.c (log_fileproc): Ditto.
+ * tag.c (tag_fileproc): Ditto.
+ * update.c (checkout_file): Ditto.
+ * server.c (server_updated): Do not buf_free (filebuf) here.
+
+2004-02-15 Derek Price <derek@ximbiot.com>
+
+ Make error() accessible to the GNULIB functions.
+
+ * error.h: Move into the ../lib directory.
+
+2004-02-13 Derek Price <derek@ximbiot.com>
+
+ * lock.c (Reader_Lock, lock_dir_for_write): Plug memory leaks.
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+2004-02-13 Derek Price <derek@ximbiot.com>
+
+ * lock.c (remove_lock_files): Minor refactoring.
+
+2004-02-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * lock.c (lock_exists): Plug a memory leak.
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ * modules.c: Reformat comment and line to fit in 80 chars.
+
+2004-02-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (do_cvs_command): Plug a memory leak.
+ (Use buf_free() rather than free().)
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (lockfiles): Reformat a comment for 80 characters. Fix a
+ few minor issues that caused tests to fail in remote mode. Clean up
+ after test.
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ * lock.c (unlock_proc): Don't expect an int in closure as it is not
+ condoned in the C standard. For now, just assume zero since this
+ function is currently only called from one location.
+ (remove_locks): Pass NULL for the closure argument to unlock_proc().
+
+2004-02-12 Derek Price <derek@ximbiot.com>
+
+ * lock.c (unlock_proc): Use closure as true/false free_repository
+ free_repository argument to remove_lock_files. Move to a position
+ above remove_locks and delete prototype.
+ (remove_locks): Don't free storage, as specified in our header comment,
+ in order to avoid a seg fault that could otherwise occur after waiting
+ on a lock.
+ * sanity.sh (lockfiles): Add tests for all operation (read, read
+ promotably, or write) and lock combinations.
+ (Original report from Mark <cm_mark@yahoo.com>.)
+
+2004-02-12 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * modules.c (_do_module): Rename to my_module to avoid reserved name.
+ * stack.c (_push, _pop, _unshift, _shift): Rename to do_*.
+
+2004-02-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * commit.c (find_fileproc): Plug a memory leak.
+
+2004-02-12 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * lock.c (_lock_simple_remove): Rename to remove_lock_files to avoid
+ reserved name. Fix typo (free => free_repository).
+ (lock_simple_remove): Delete; use remove_lock_files directly.
+ (lock_simple_remove_and_free): Ditto.
+ (_lock_exists): Rename to lock_exists.
+
+2004-02-11 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * root.c (parse_cvsroot): Set hostname in fork mode for error messages.
+ * buffer.c (stdio_buffer_shutdown): Undo previous change.
+
+2004-02-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * buffer.c (buf_free): Plug a memory leak.
+ * commit.c (checkaddfile): Ditto.
+
+ * server.c (fd_buffer_shutdown): Avoid a double free().
+
+ * parseinfo.c (parse_config): Fix comments.
+
+2004-02-11 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (stdio_buffer_shutdown): Add logic to avoid attempting to
+ print current_parsed_root->hostname when using the fork method.
+
+2004-02-11 Derek Price <derek@ximbiot.com>
+
+ * server.c (do_cvs_command): Simplify stream & pipe closing.
+ (Suggestion from Eric Siegerman <erics@telepres.com>.)
+
+ * cvs.h, subr.c (set_block_fd): Remove this unnecessary function.
+
+2004-02-11 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (checkout_proc): Remove unneeded variable and enclosing
+ block.
+ * modules.c (_do_modules): Minor whitespace change.
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * lock.c (lock_simple_remove): Move core functionality...
+ (_lock_simple_remove): ...here.
+ (lock_simple_remove_and_free): New function.
+ (set_promotable_lock): Use new function to avoid freeing data that will be
+ reused.
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * server.c (do_cvs_command): s/FIXCVS/FIXME/ in comment.
+ (set_block_fd, set_nonblock_fd): Move to...
+ * subr.c: ...here.
+ * cvs.h: Add protos for the above two functions.
+ * buffer.c (stdio_buffer_shutdown): Replace fgetc() which checked for
+ unread data on a pipe with a nonblock read.
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * server.c (do_cvs_command): Have the server child close all the pipes
+ but the flow control pipe and wait on an EOF on the flow control pipe
+ from the parent when done to avoid a race condition that could
+ otherwise generate a SIGPIPE for the parent before the SIGCHILD when
+ the other pipes were so full after a child exited that the parent
+ attempted to write a stop byte to the flow control pipe.
+ (Original report from <jesse_off@stchome.com>.)
+
+2004-02-10 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (stdio_buffer_shutdown): Add a helpful comment.
+
+2004-02-09 Derek Price <derek@ximbiot.com>
+
+ * lock.c (lock_simple_remove): Add comments. Use critical sections to
+ set some variables that might otherwise cause trouble.
+ (struct lock): Correct comment.
+
+2004-02-09 Derek Price <derek@ximbiot.com>
+
+ Attempt to improve readability of code.
+
+ * lock.c (promotable_lock): Rename to...
+ (set_promotable_lock): ...this.
+ (set_promotablelock_proc): Expand header comment.
+ (Promotable_Lock): Rename to...
+ (lock_tree_promotably): ...this.
+
+2004-02-09 Derek Price <derek@ximbiot.com>
+
+ * lock.c (set_writelock_proc): Remove unused prototype.
+ (promotable_lock): Remove unneded whitespace.
+ (Promotable_Lock): Correct comments.
+
+2004-02-09 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (co-d): Update comments and tests to reflect the current
+ state of my side of my discussion with Larry Jones on how these
+ commands should behave.
+
+2004-02-09 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (emptydir): Add two new tests for how modules -d behaves
+ when a directory already exists in the user's workspace.
+ (emptydir): Add --keep functionality.
+
+2004-02-09 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (co-d): New test to prove `co -d' failure case.
+
+2004-02-05 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (recase): Fix typo that creeped in somehow between my last
+ test run and my commit.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * modules.c (do_modules): Move content to and make this function a
+ wrapper for...
+ (_do_modules): ...this new function which can watch for infinite loops
+ in alias modules.
+ * stack.c (_push, _pop, _unshift, _shift, push_string, pop_string,
+ unshift_string, shift_string): New
+ functions.
+ * stack.h (push_string, pop_string, unshift_string, shift_string: New
+ prototypes.
+ * sanity.sh (modules): Add check for nested alias loops.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (recase): Update test names and comments for clarity and
+ consistency.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (recase): Restore some cruft necessary when clients know
+ they are on case insensitive systems.
+
+2004-02-03 Derek Price <derek@ximbiot.com>
+
+ Preserve the case of checked out directories in a path as well as file
+ names for client communication with the server.
+
+ * Makefile.am (cvs_SOURCES): Add stack.c & stack.h.
+ * stack.c, stack.h: New files.
+ * cvs.h: Include stack.h.
+ * client.c (send_file_names): Preserve the case of directories in a
+ path as well as file names for communication with the server.
+
+ * Makefile.in: Regenerated.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (find_fileproc): Update error message for consistency.
+ * sanity.sh (basica): Update to compensate.
+
+2004-02-04 Derek Price <derek@ximbiot.com>
+
+ * classify.c (Classify_File): Update header comment block and reformat
+ prototype for readability in 80 character widths.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (*): Update tests for the new status message from update.c.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (join-rm): New test for issue #104 & #159.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * update.c (join_file): Correct status message for consistency.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ Continue removal from server of handling of case insensitive clients.
+
+ * cvs.h: Remove extern declaration of ign_case.
+ * ignore.c (ign_case): Remove declaration.
+ (ign_name): Remove support for ign_case.
+ * server.c (serve_case): Ditto.
+ (requests): No longer support the "Case" request.
+ * rcs.c (locate_rcs): Remove reference to GLOBAL in function header
+ comment.
+
+2004-02-02 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_file_names): Restore prescribed client handling of the
+ FILENAMES_CASE_INSENSITIVE switch.
+
+2004-01-25 Derek Price <derek@ximbiot.com>
+
+ * server.c (kserver_authenticate_connection): Fix call to
+ switch_to_user().
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2004-01-22 Derek Price <derek@ximbiot.com>
+
+ * modules.c (do_module): Strip trailing slashes before checking for
+ infinite alias loops.
+ * sanity.sh (modules): Tests for response to infinite alias loops.
+
+2004-01-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * logmsg.c (do_verify): Eliminate double-free bug.
+ (Original patch from Gerald Combs.)
+
+2004-01-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * lock.c (lock_name): Deal with potentially NULL string pointers
+ in calls to TRACE.
+ (promotable_lock): Ditto.
+ (set_lock): Ditto.
+ * sanity.sh (trace): Update to latest patterns.
+
+2004-01-07 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * checkout.c (safe_location): Remove unused variable(s).
+ * lock.c (lock_tree_for_write): Ditto.
+ * rcs.c (RCS_checkin): Ditto.
+ * subr.c (compare_revnums): Ditto.
+ * tag.c (tag_check_valid): Ditto.
+ * mkmodules.c (init): Initialize err and return it rather than 0.
+ * server.c (do_cvs_command): Only define and set max_command_fd if
+ we're actually going to use it.
+
+2004-01-06 Mark D. Baushke <mdb@cvshome.org>
+
+ * socket-client.c (socket_buffer_initialize): Fix argument
+ declaration for VMS compiler.
+ (Patch submitted from Michael Lemke
+ <ai26@sternwarte.uni-erlangen.de>.)
+
+2004-01-01 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * zlib.c (read_and_gzip, gunzip_and_write): Fix potential buffer
+ overruns, use names for magic numbers.
+ (Original patch from Jeff Downs <heydowns@borg.com>.)
+
+2003-12-17 Larry Jones <lawrence.jones@ugsplm.com>
+
+ * main.c (main): Don't reference isremote without CLIENT_SUPPORT.
+ (Patch from Jim Salter <jsalterjim@earthlink.net>.)
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * server.c (switch_to_user): SysLog attempts to root from pserver.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * server.c (switch_to_user): Don't allow CVS to run as root in pserver
+ mode.
+ (Original patch from Wichert Akkerman via Bradley M Kuhn
+ <bkuhn@fsf.org>.)
+ * sanity.sh (pserver): Check for bad root error message.
+
+2003-12-17 Larry Jones <lawrence.jones@eds.com>
+
+ * run.c (close_on_exec): fcntl is not documented to return 0 for
+ success (and QNX doesn't), only -1 for error.
+ (Patch from George Refseth <george.refseth@arxi.no>.)
+
+2003-12-10 Larry Jones <lawrence.jones@eds.com>
+
+ * rcs.c: Cleanup HAVE_MMAP code in preparation for falling back to
+ stdio if mmap fails on large files.
+
+2003-12-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * tag.c (tag_check_valid): Fix typo.
+ (Patch from Rob Clevenger <rob@robsite.org>.)
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ Rewrite code to use promotable write locks to avoid locking more than a
+ directory at a time for a full write.
+
+ * cvs.h (lock_tree_for_write): Rename to...
+ (lock_tree_promotably): ...this.
+ (Simple_Lock_Cleanup): New prototype.
+ * lock.c: Remove some unneeded prototypes. Some function
+ reorganization.
+ (struct lock): Make repository const. Add file1 & file2 to
+ track lock names. Keep track of when repository needs to be freed.
+ (promotablelock, global_writelock): New globals.
+ (locked_dir, locked_list): Remove unneeded globals.
+ (lock_name): Take const args.
+ (remove_locks): Update comment. Move readlock cleanup...
+ (Simple_Lock_Cleanup): ...to this new function which also cleans up
+ writelocks.
+ (Lock_Cleanup): No need to clean up after the obsolete locked_dir &
+ locked_list.
+ (lock_simple_remove): Use new lock name cache. Set lock->repository to
+ NULL to show locks are removed. Free repository name when necessary.
+ (Reader_Lock): Copy xrepository argument so we do not need to trust the
+ caller not to dispose of it. Use lock name cache. Factor code to set
+ the global readlock variable...
+ (set_readlock_name): ...to this new function so it can be used by
+ promotable_lock too.
+ (readers_exist): Factor common code and make wrapper for...
+ (_lock_exists): ...this new function.
+ (promotable_exists): Wrapper for _lock_exists().
+ (write_lock): Rename to...
+ (promotable_lock): ...this and tweak for new behavior.
+ (set_writelock_proc): Rename to...
+ (set_promotablelock_proc): ...this and tweak for new functionality.
+ (Write_Lock): Rename to...
+ (Promotable_Lock): ...this and tweak for new functionality.
+ (set_lock): Add trace.
+ (lock_tree_for_write): Rename to...
+ (lock_tree_promotably): ...this and tweak for new functionality.
+ (lock_dir_for_write): Lock only one directory at a time in a promotable
+ lock aware fashion using new interfaces.
+ * admin.c, commit.c, edit.c, watch.c:
+ s/lock_tree_for_write/lock_tree_promotably/.
+ s/CVS_LOCK_NONE/CVS_LOCK_WRITE/ in calls to start_recursion that used
+ to rely on lock_tree_for_write() to obtain their write locks. Remove
+ some unnecessary typecasting.
+ * recurse.c (do_recursion): Use Simple_Lock_Cleanup() rather than
+ Lock_Cleanup to avoid removing promotable locks.
+ * server.c (do_cvs_command): Add traces.
+ (server): Add new way to sleep the parent server process for connecting
+ a debugger.
+ * sanity.sh (lockfiles, multiroot2): Update tests to accomodate minor
+ trace inconsistencies.
+
+2003-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (trace): Remove trace from the set of tests to run.
+ The regexps used take an excessive amount of time and need to
+ be simplified.
+
+2003-12-08 Mark D. Baushke <mdb@cvshome.org>
+
+ * rcs.c (rcsbuf_ftell): Rename to...
+ (rcsbuf_ftello): this.
+ (rcsbuf_cache_open): Use off_t rather than long as the pos
+ argument. Use fseeko rather than fseek and ftello rather than
+ ftell.
+ * rcs.h (struct rcsnode): delta_pos is now an off_t type.
+
+2003-12-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (recase): Add some clarifying comments.
+
+2003-12-03 Larry Jones <lawrence.jones@eds.com>
+
+ * expand_path.c (expand_variable): Expand ${CVSROOT} to just the
+ directory like it's supposed to be.
+ (Reported by Michael S. Tsirkin <cvs1@misha.eml.cc>.)
+
+2003-11-26 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (recase-17sscs): Use ${CVSROOT_DIRNAME} in pattern.
+
+2003-11-26 Derek Price <derek@ximbiot.com>
+
+ Remove server support for case insensitive clients. Includes some
+ merges from 1.11.x.
+
+ * add.c, client.c, cvs.h, rcs.c, subr.c: Remove unnecessary support for
+ case insensitive clients.
+ * sanity.sh (tests): Add recase.
+ (recase): New test of cases that might be expected to cause problems
+ with a heterogeneous mix of case sensitive and case insensitive clients
+ and servers.
+
+2003-11-26 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (modules3-2): Simplify syntax that may have given Cygwin
+ intermittent conniptions.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (binfiles2): Correct yet another Cygwin difficulty.
+
+2003-11-25 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (release): Perform forgotten cleanup.
+
+2003-11-25 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (env): Enable to work with $remotehost.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (trace-19): Separate stdout and stderr to workaround
+ problems on SGI IRIX.
+ (crecrepos): Use 'unset DISPLAY' to avoid problems with ssh
+ X11Forwarding configurations.
+
+2003-11-25 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (pserver, server, server2): Save $servercvs and use the
+ local $testcvs for these tests.
+
+2003-11-25 Derek Price <derek@ximbiot.com>
+
+ * commit.c (commit_fileproc): Reword comment.
+
+2003-11-25 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (devcom3-9ar): Ignore the stderr output since it varies
+ considerably between platforms.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (CVS_RSH): Read config file sooner to pickup RSH_DFLT
+ for use in setting CVS_RSH variable.
+ * sanity.config.sh.in (RSH_DFLT): Use new substitution variable.
+ * Makefile.am (localcheck, remotecheck): Depend on sanity.config.sh.
+ * Makefile.in: Regenerate for new Makefile.am.
+
+ * update.c (join_file): Deal with rev1 == NULL due to rev1 merge tag
+ being missing from the current file.
+ * sanity.sh (join6): New tests for this case.
+ (trace): Renumber test cases.
+
+2003-11-24 Larry Jones <lawrence.jones@eds.com>
+
+ * diff.c (diff_file_nodiff): use_rev1 does *not* imply that diff_rev1
+ is not null, diff_date1 could be set instead (ditto for use_rev2).
+ (Reported by <jnelson-cvsbug@jamponi.net>.)
+
+2003-11-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * client.c (connect_to_forked_server): Avoid passing NULL strings
+ to TRACE. Calling printf("%s",NULL) is not defined and may
+ segfault on some systems.
+ * diff.c (diff_file_nodiff): Ditto.
+ * main.c (main): Ditto.
+ * modules.c (do_module): Ditto.
+ * patch.c (patch_proc): Ditto.
+ * rcs.c (RCS_cmp_file): Ditto.
+ * recurse.c (start_recursion): Ditto.
+ * root.c (parse_cvsroot): Ditto.
+ * server.c (dirswitch, server_pathname_check, dirswitch,
+ serve_directory): Ditto.
+ * tag.c (rtag_proc, check_fileproc, tag_check_valid): Ditto.
+ * sanity.sh (trace): New testcase to test the -t option.
+ (RCSDATE, ISODATE, PFMT): New variables in aid of the trace tests.
+ (dotest_fail_sort): New function in aid of the trace tests.
+ (template): Fix cleanup.
+
+2003-11-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (modes3): Skip modes3-5 entirely under Cygwin since
+ permisions are broken there. This change removes most of the earlier
+ Cygwin differentiation in this test ($cygwin_hack & $cygwin_hack2) in
+ favor of skipping the test entirely.
+
+2003-11-24 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Add `-h <hostname>' option to enable testing across a
+ :ext: connection to another host. Warn when `-h' is specified without
+ $TESTDIR. Leave $TESTDIR intact when it looks absolute since it may
+ contain symlinks. Allow $CVS_SERVER to be overridden via the
+ environment for `-h'. Default $CVS_RSH to `ssh'.
+ (*): Use $CVS_RSH to perform certain commands on the remote host (esp.
+ `ln -s' and `chmod') when `-h' is specified to work around
+ incompatibilities with CygWin & Samba. Add a few other minor
+ workarounds for Cygwin bugs.
+
+ (newroot): New function.
+ (*): Use newroot when appropriate.
+
+2003-11-21 Larry Jones <lawrence.jones@eds.com>
+
+ * hash.c (printnode, printlist): Cast %p arguments to void * as
+ required by the C standard.
+
+2003-11-21 Larry Jones <lawrence.jones@eds.com>
+
+ * recurse.c (start_recursion, do_recursion): Cast %p arguments to
+ void * as required by the C standard.
+
+2003-11-19 Larry Jones <lawrence.jones@eds.com>
+
+ * rcs.c (RCS_getrevtime): Add error checking; cleanup.
+
+2003-11-18 Derek Price <derek@ximbiot.com>
+
+ * socket-client.c (socket_buffer_initialize): Rename poorly named `n'
+ to a slightly more descriptive `sbuf'.
+ (Suggestion from Larry Jones <lawrence.jones@eds.com>.)
+
+2003-11-18 Derek Price <derek@ximbiot.com>
+
+ * socket-client.c (socket_buffer_initialize): Pass in the socket
+ closure we allocate.
+ (Report from Larry Jones <lawrence.jones@eds.com>.)
+
+2003-11-18 Derek Price <derek@ximbiot.com>
+
+ * modules.c (do_module): Reject absolute paths.
+ (Report and suggested fix from Tony Hoyle <tmh@nodomain.org>.)
+
+ * sanity.sh (abspath2): Check for the above.
+ (spacefiles): Remove tests that expect absolute paths to files in the
+ top level repository directory to work.
+ (tests): Add abspath2.
+
+2003-11-18 Derek Price <derek@ximbiot.com>
+
+ * socket-client.c (socket_buffer_initialize): Correct a typo that
+ happened to compile.
+ (Report and suggested fix from Patrick Brown <BrownP@symbol.com>.)
+
+2003-11-13 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_delete_revs): It's `&&', not `and'.
+
+2003-11-13 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Create the empty log to make it easier to tail immediately
+ after the script is started.
+
+2003-11-13 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (exit_help): Correct help to specify `-H' and not `-h' as
+ the help option.
+
+2003-11-13 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_delete_revs): Don't use the WOE32 kludge which refuses to
+ delete revisions from bvinary files on Cygwin. I'm not sure what the
+ kludge was trying to avoid, but commenting it out causes the test suite
+ to pass.
+
+2003-11-12 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Remove a trailing newline from the version string.
+ Replace multiple calls to fputs to a single call reformated to C89
+ specifications. Remove some typecasts unecessary under C89.
+ * sanity.sh (version): Remove trailing newline from the version string.
+
+2003-11-12 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Allocate more space for the string I added characters
+ to.
+ (Report from Mark D. Baushke <mdb@cvshome.org>.)
+
+2003-11-11 Derek Price <derek@ximbiot.com>
+
+ * add.c (add), classify.c (Classify_File), client.c (update_entries),
+ repos.c (Name_Repository): Use consistent quoting in error messages.
+ Misc reformatting.
+ * sanity.sh: Update to match.
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * commit.c (find_fileproc, check_fileproc): Refuse to remove files
+ when the file exists in the sandbox. This used to cause data loss.
+ (Report from Andreas Reifschneider <andyreif@studcs.uni-sb.de>.)
+
+ * sanity.sh (rmadd3): Update to match. Expand comments.
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rmadd3): Test the behavior of commit after the
+ add/replace.
+ (Report from Andreas Reifschneider <andyreif@studcs.uni-sb.de>.)
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rmadd3): Fix another typo.
+
+2003-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * recurse.c (do_dir_proc): Set xframe.repository to NULL after a
+ call to free().
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rmadd3): Fix typo.
+
+2003-11-10 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rmadd3): New tests that confirms that CVS refuses to
+ delete a file it thinks was already removed.
+ (Report and test from Andreas Reifschneider
+ <andyreif@studcs.uni-sb.de>.)
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (server): Test that the global `-l' option is ignored
+ nonfatally.
+
+2003-11-03 Derek Price <derek@ximbiot.com>
+
+ * server.c (serve_global_option): Warn that -l is being ignored rather
+ than exiting fatally due to backwards compatibility complaints from
+ administrators.
+
+2003-11-01 Larry Jones <lawrence.jones@eds.com>
+
+ * filesubr.c (xcmp): Make sure S_ISLNK exists before calling it.
+ (Reported by Paul Edwards <kerravon@nosppaam.w3.to>.)
+
+2003-10-31 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: s/${TESTDIR}/cvsroot/${CVSROOT_DIRNAME}/.
+
+2003-10-28 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (devcom): Renumber tests and use dotest function.
+
+2003-10-28 Derek Price <derek@ximbiot.com>
+
+ * sever.h: Add the standard copyright notice.
+
+2003-10-28 Derek Price <derek@ximbiot.com>
+
+ * lock.c: Remove some suggestions which have already been implemented
+ or which have become obsolete from the header comment.
+
+2003-10-26 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (join6): Fix a few typos in the last test and remove a
+ misplaced test.
+
+2003-10-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (parseroot): Use dokeep function.
+
+ * sanity.sh (parseroot): Perform this test in a subdirectory.
+ It should avoid problems on case-insensitive systems where
+ CVSROOT and cvsroot are the same directory (eg, MacOS X).
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * update.c (join_file): Restore the optimization Mark recently removed,
+ but fix it. Move one other optimization up since it needs to be
+ checked for first. Add bew status messages like merge_file produces
+ when the requested diff has already been applied to the destination.
+ Expand header comment.
+ * sanity.sh (join6): Add tests for the new error messages.
+ (import-113, join-admin-2, diffmerge1): Fix collateral damage.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * update.c (merge_file): Optimize & eliminate code.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (do_recursion): Assert that ignoring the return value of
+ Name_Repository is not a memory leak.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * repos.c (Name_Repository): Replace a FIXME with the improved error
+ message it requested.
+ * sanity.sh (errmsg3): New test for the above.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * patch.c (patch_proc): Avoid memory leak.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+ (patch_proc): Reformat a few long lines for readability.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * vers_ts.c (Version_TS): Move variable declaration inside the only
+ block where it is used and remove uneeded reinitialization.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * server.h: s/^extern// off of function declarations per HACKING.
+ Reformat protos for readability.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * vers_ts.c (Version_TS): Reformat declaration and expand header
+ comment.
+
+2003-10-24 Derek Price <derek@ximbiot.com>
+
+ * update.c (merge_file): Remove code that hasn't been used since CVS
+ used an external RCS (1.9.something).
+
+2003-10-23 Mark D. Baushke <mdb@cvshome.org>
+
+ * update.c (join_file): Do the -jrev1 -jrev2 merge even when
+ the file is already at rev2.
+ * sanity.sh (join6): New testcase for above.
+ (Suggested by Paul Edwards, from somewhere in Australia.)
+ (import): Fix collateral damage.
+
+2003-10-23 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (fail): Refer the user to the `TESTS' and `check.log' files
+ on failure.
+
+2003-10-22 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (start_recursion): Reformat function declaration and
+ expand comments.
+ (Original patch from Terrence Enger <tenger@iSeries-guru.com>.)
+
+2003-10-22 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs_LDADD): Add $(LIBINTL) for gettext.
+ * Makefile.in: Regenerated.
+
+2003-10-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (admin-31): Fix more typos.
+
+2003-10-18 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (admin): Fix a typo.
+
+ * admin.c (admin_fileproc): Restore the ':' character in the
+ -mtag:message admin argument even if the tag does not exist so
+ that other files with the tag will be found. Also, be more
+ paranoid that a symbolic tag actually points to a version that
+ exists.
+ (Reported by Rodolfo Schulz de Lima <rodolfo@rodsoft.org>.)
+ * sanity.sh (admin): Test these changes.
+
+2003-10-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * admin.c (admin_fileproc): Force tag match on admin
+ -mversion:message rather than altering the wrong log message.
+ (Patch from "Rodolfo Schulz de Lima" <rodsoft@uol.com.br>.)
+ * sanity.sh (admin): Test case for it.
+
+2003-10-15 Larry Jones <lawrence.jones@eds.com>
+
+ * commit.c (commit_fileproc, finaladd): Don't call fixaddfile()
+ if the RCS file didn't get created at all.
+ (Reported by David Wood <David.Wood@thestreet.com>.)
+
+2003-10-14 Derek Price <derek@ximbiot.com>
+
+ Port to pedantic POSIX 1003.1-2001 hosts, such as Debian GNU/Linux
+ testing with _POSIX2_VERSION=200112 in the environment.
+
+ * sanity.sh: Use 'sed 1q', not 'head -1'.
+ (Patch from Paul Eggert <eggert@twinsun.com>.)
+
+2003-10-10 Derek Price <derek@ximbiot.com>
+
+ * lock.c (set_lock): Clarify comment.
+
+2003-10-11 Larry Jones <lawrence.jones@eds.com>
+
+ * server.c (server_cleanup): Replace CVS_CHDIR call: some systems
+ won't allow you to delete a directory tree containg your working
+ directory.
+
+2003-10-10 Derek Price <derek@ximbiot.com>
+
+ * server.c (cvs_output, cvs_outerr): Protect calls to syslog()
+ with the usual preprocessor condition: HAVE_SYSLOG_H.
+ (Original patch from Terrence Enger <tenger@iSeries-guru.com>.)
+
+2003-10-09 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: s/^extern// off of function declarations per HACKING.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (cvs_SOURCES): Add history.h.
+ * history.c: Include history.h. Add the `P' record types to more
+ comments. s/ALL_REC_TYPES/ALL_HISTORY_REC_TYPES/.
+ (usage): Reference ALL_HISTORY_REC_TYPES rather than using a separate
+ string literal.
+ (report_hrecs): Handle `P' record type.
+ (ALL_REC_TYPES): Rename and move...
+ * history.h (ALL_HISTORY_REC_TYPES): ...here.
+ * mkmodules.c: Include history.h.
+ (config_contents): Update contents of and references to LogHistory
+ records to use ALL_HISTORY_REC_TYPES.
+ * sanity.sh (basic2-64): Update to include history records of type `P'.
+
+ * Makefile.in: Regenerated.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * update.c (patch_file): Correct spelling and punctuation in comment.
+ Update some lines to fit in 80 characters.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * lock.c (remove_locks): Copy global struct and set status variable to
+ NULL before calling disposal functions that might try to access it
+ during calls to error(1,...).
+
+2003-10-08 Larry Jones <lawrence.jones@eds.com>
+
+ * history.c (history): Don't conflate -e with -x since the client's
+ idea of what -e means may not match the server's.
+ (Reported by Frank Hemer <frank@hemer.org>.)
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * lock.c (Lock_Cleanup), rcs.c (rcs_cleanup), server.c
+ (server_cleanup): Expand comments about the never_run_again variable
+ and its interoperation with critical sections, exit, and interrupts.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * lock.c (remove_locks): Reduce TRACE level since this function is
+ rarely called and we can usually rely on tracing higher level
+ functions.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * lock.c (lock_name, lock_simple_remove),
+ server.c (server_pathname_check, dirswitch): Add TRACE.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * main.c: Reformat header comment to fit in 80 chars.
+
+2003-10-08 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh: Use dotest_fail instead of dotest_status for diff tests
+ since CVS only returns success/fail rather than 0/1/2 like diff does.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ Fix a client/server bug introduced via the data loss fix of 2003-03-17.
+ Basically, the server was reporting ambiguous filename requests when it
+ should have been trusting the user to type the intended case or using
+ the case the client preserved in CVS/Entries before it tried to look
+ anything up in case insensitive mode.
+
+ * rcs.c (locate_rcs): Use the filename exactly as cased before
+ investigating a case insensitive lookup, per the client/server protocol
+ specification. Expand comments.
+ * subr.c (locate_file_in_dir): This function only needs to locate files
+ case insensitively. Expand comments.
+ * cvs.h (locate_file_in_dir): Only prototype when servers which need to
+ handle case insensitivity are being compiled.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (locate_rcs): Declare static. Move to an earlier location in
+ file to avoid prototyping.
+ * rcs.h (locate_rcs): Remove proto.
+
+2003-10-08 Derek Price <derek@ximbiot.com>
+
+ * lock.c (lock_filesdoneproc): Reformat long function prototype.
+
+2003-10-07 Larry Jones <lawrence.jones@eds.com>
+
+ * server.c (server_cleanup): Remove old code that was commented out
+ with //, which isn't valid in C.
+
+2003-10-04 Derek Price <derek@ximbiot.com>
+
+ * exithandle.c: New file.
+ * Makefile.am (cvs_SOURCES): Add exithandle.c.
+ * cvs.h (cleanup_register, signals_register): New prototypes.
+ * lock.c (Lock_Cleanup, remove_locks), rcs.c (rcs_cleanup),
+ server.c (server_cleanup): Avoid calling twice when called from a
+ signal handler and then exit. Avoid being interrupted while globals
+ that the signal handler might touch are in inconsistent states. Expand
+ comments.
+ * rcs.c (rcs_internal_lockfile): Ditto. Use cleanup_register rather
+ than calling atexit() directly.
+ * main.c (main): Consolidate signal stuff into a call to
+ signals_register(). Call cleanup_register to register cleanup
+ functions rather than calling atexit() directly.
+
+ * Makefile.in: Regenerated.
+
+2003-10-04 Derek Price <derek@ximbiot.com>
+
+ * error.c, error.h: Remove error_exit() function.
+ * add.c, client.c, history.c, import.c, main.c, mkmodules.c, modules.c,
+ rcscmds.c, recurse.c, release.c, root.c, server.c, socket-client.c,
+ tag.c, update.c: s/\<error_exit *();$/exit (EXIT_FAILURE);/. Remove
+ related comments.
+
+2003-10-04 Derek Price <derek@ximbiot.com>
+
+ * buffer.c: Reformat a few long function prototypes and lines.
+
+2003-10-04 Derek Price <derek@ximbiot.com>
+
+ * hash.c (dellist): Immediately set input pointers to NULL in case they
+ are references to global variables which might be accessed by interrupt
+ handlers.
+
+2003-10-04 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (rcs_cleanup): Declare static.
+ * rcs.h (rcs_cleanup): Remove prototype.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ Move calls to Lock_Cleanup to the atexit handler.
+
+ * commit.c (commit): Don't call Lock_Cleanup on error exit.
+ * error.c (error_exit): Don't call Lock_Cleanup.
+ * lock.c (Lock_Cleanup): Don't worry about recursive calls now that we
+ are using atexit for calls on exit. Dispose locklist storage after the
+ locks are removed. Expand comments.
+ * main.c (main): Move Lock_Cleanup call into atexit(Lock_Cleanup).
+ * server.c (server_notify): Add TRACE.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (start_recursion): Remove unnecessary typecasts.
+ (do_recursion): Ditto. Add TRACE. Expand comments. Remove unneeded
+ parens.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Dispose of old Tmpdir and Editor when specified
+ multiple times between the command line & the ~/.cvsrc file.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ * lock.c (remove_locks): Eliminate unecessary typecasting.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ Move calls to rcs_cleanup to the atexit handler.
+
+ * error.c (error_exit): Don't call rcs_cleanup.
+ * rcs.c: Initialize global RCS_LOCKFILE to NULL.
+ (rcs_internal_lockfile): Use atexit (rcs_cleanup) rather than
+ setting up signal handlers.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ * modules.c (do_module): Format prototype.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ * server.c (server_cleanup): Skip BUF_TO_NET checks as an optimization
+ when ERROR_USE_PROTOCOL is set.
+
+2003-10-03 Derek Price <derek@ximbiot.com>
+
+ * modules.c (do_module): Use TRACE.
+
+2003-10-02 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Don't free globals that might be needed by the cleanup
+ functions.
+ * server.c (server_cleanup): Only clean up when called in the parent
+ process. Set buffers to NULL before shutting down and freeing in case
+ we are interrupted. Improve comments. Add TRACE.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Use symbolic name for trace level.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * client.c (connect_to_forked_server): Use TRACE macro rather than the
+ old style.
+
+2003-10-01 Derek Price <derek@ximbiot.com>
+
+ * server.c (protocol): Initialize the protocol buffer to NULL so that
+ use before initialization may be detected.
+ (cvs_output, cvs_outerr): Syslog messages when the appropriate buffers
+ are not available.
+ (server_cleanup): Reorganize for a single exit point and to eliminate
+ duplicated code. Set buf_to_net to NULL before calling the buffer
+ shutdown functions in order to force error messages into the syslog.
+ * buffer.c (stdio_buffer_close): Remove FIXME comment re syslog since
+ the calls to error should go through the cvs_outerr function anyhow.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * entries.c (WriteTemplate): TRACE on entrance to a function, not exit.
+ Don't worry about checking noexec without server support since this
+ function will then do nothing.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * update.c (do_update): Reformat function decl. Move and merge
+ comment.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * client.h (buf_output, buf_outerr): Check that our buffers exist
+ before sending them data.
+ (buf_output_binary): Assert that the output buffer is not NULL.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * client.h, rcs.c, rcs.h, server.h: Assume __STDC__ since it is
+ defined as part of the C89 spec.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * commit.c (commit): Optimize function towards a single exit point.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * error.c (error_exit): Remove call to SYSTEM_CLEANUP.
+ * main.c (main): Set up atexit(SYSTEM_CLEANUP) rather than calling it
+ explicitly before exit.
+ * server.c (pserver_authenticate_connection): Don't call SYSTEM_CLEANUP
+ before exiting.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * error.c (exit_error): Remove call to server_cleanup.
+ * main.c (main): Call atexit(server_cleanup). Let server_cleanup turn
+ server_active off.
+ * server.c (server_cleanup): Don't require an argument. Fill out
+ header comment. Unset server_active when done.
+ (server): Don't call server_cleanup - let it be called via the atexit
+ handler.
+ * server.h (server_cleanup): Update proto.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * server.c (buf_output): Don't check that the buffers exist before
+ using them since cvs_outerr does this without problems.
+
+2003-09-30 Derek Price <derek@ximbiot.com>
+
+ * server.c: Remove some unecessary function prototypes.
+
+2003-09-29 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (make_file_label): Make a failure to stat a file a fatal error
+ since it signals that a later read will also fail.
+
+2003-09-29 Derek Price <derek@ximbiot.com>
+
+ * diff.c (diff_fileproc): Optimize the check for labels set by the
+ user.
+
+2003-09-26 Derek Price <derek@ximbiot.com>
+
+ * diff.c (diff): Add a FIXME re spaces in diff arguments.
+
+2003-09-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * rcs.c (make_file_label): Do not return an uninitialized label.
+ (Reported by "Todd C. Miller" <Todd.Miller@courtesan.com>)
+
+2003-09-24 Derek Price <derek@ximbiot.com>
+
+ * lock.c (lock_name): Remove useless prototype.
+
+2003-09-12 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (mkmodules): Correct comments.
+
+2003-09-12 Derek Price <derek@ximbiot.com>
+
+ * mkmodules.c (mkmodules): Do not pass a string which came from the
+ checkoutlist file directly to error as a format string since we don't
+ want to trust any user with access to checkoutlist with creating printf
+ format strings. I already claimed I did this in the NEWS file.
+ (Thanks to Larry Jones for spotting my mistake.)
+ * sanity.sh (mkmodules): Test for the above.
+
+2003-09-12 Derek Price <derek@ximbiot.com>
+
+ * mkmodules.c (checkoutlist_contents): Document the optional portions
+ of this file format more accurately.
+ (mkmodules): Ditto, in comments. Fix bug that always failed to ignore
+ whitespace before error messages.
+ * sanity.sh (mkmodules-temp-file-removal): Rename to...
+ (mkmodules): ...this and add a test of the checkoutlist error message.
+ Add cleanup step to restore checkoutlist.
+
+2003-09-08 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (cvs_temp_file): Replace a chmod 0600, which shouldn't
+ really be necessary and which provided a false sense of security, with
+ an informative comment.
+ (Thanks to Paul Eggert <eggert@cs.ucla.edu> for his educational
+ advice.)
+
+2003-08-29 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Delete reference to CVSADMROOT_EDITINFO.
+ * logmsg.c (editinfo_proc): Delete function and proto.
+ (do_editor): Don't look for editinfo script.
+ * mkmodules.c (editinfo_contents): Delete.
+ * sanity.sh (*): Remove references to editinfo in updates of the
+ CVSROOT module.
+
+2003-08-29 Derek Price <derek@ximbiot.com>
+
+ * remove.c (cvsremove): Update quotes for consistency.
+
+2003-08-27 Larry Jones <lawrence.jones@eds.com>
+
+ * history.c: 'P' is a valid record type and has been for a long time.
+ Add it to the comments, usage message, and, most important,
+ ALL_REC_TYPES so it gets recorded by default.
+ * server.c (do_cvs_command): Set global command_name to the real
+ command name rather than leaving it set to "server".
+ * sanity.sh: Update to match.
+ (Reported by Dmitry Ryzhkov <rdim_outside@softhome.net>.)
+
+2003-08-19 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (cvs_temp_file): Expand comments. Check for glibc version
+ before compiling chmod command. Remove FIXME to this effect.
+
+2003-08-19 Derek Price <derek@ximbiot.com>
+
+ * logmsg.c (do_editor): Use cvs_temp_file rather than cvs_temp_name to
+ create and open the temporary file. Remove FIXME to this effect.
+
+2003-08-19 Derek Price <derek@ximbiot.com>
+
+ * logmsg.c (do_editor): Move editinfo processing to before creation of
+ the temp file so that it may be skipped when no editor is defined.
+ Remove related FIXME. Add comments. Remove some processing of
+ editinfo_editor rendered obsolete when editinfo_editor ceased to be a
+ global.
+
+2003-08-19 Derek Price <derek@ximbiot.com>
+
+ * (*.c): Move some includes to lib/system.h.
+
+2003-08-18 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Use consistent quoting style in user messages.
+ * sanity.sh (*): Ditto.
+
+2003-08-13 Larry Jones <lawrence.jones@eds.com>
+
+ * server.c (server_cleanup): Don't shutdown buf_from_net if it's
+ null.
+ (Reported by Scott Mitchell <scott@fishballoon.org>.)
+
+2003-08-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * lock.c: Do not include xtime.h (already included via system.h).
+ * subr.c: Ditto.
+ (Original patch from Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+ to fix IRIX 5.3 problem.)
+
+2003-08-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (join5): Use $SPROG rather than $PROG.
+
+2003-08-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (join5): Use $PROG consistently and escape a `.'.
+
+2003-08-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (join5): Use `[a-z]*' as opposed to `update'.
+
+2003-07-31 Derek Price <derek@ximbiot.com>
+
+ * rcscmds.c (RCS_merge): Pass `--' before the filename arguments to
+ diff so that filenames starting with `-' can be merged.
+ * sanity.sh (join5): New test for same.
+
+2003-07-31 Derek Price <derek@ximbiot.com>
+
+ * add.c (add_directory): Don't print status information in really_quiet
+ mode.
+
+2003-07-29 Derek Price <derek@ximbiot.com>
+
+ * commit.c (checkaddfile): Simplify the logic here, using assumptions
+ already made later in the function to remove calls to locate_rcs and
+ some conditionals. Use same assumptions to remove some variables.
+
+2003-07-29 Derek Price <derek@ximbiot.com>
+
+ * login.c: Remove GETPASS & HAVE_GETPASSPHRASE cruft in favor of always
+ using the GNULIB getpass since the system getpass was removed from the
+ POSIX.2 specification.
+
+2003-07-28 Derek Price <derek@ximbiot.com>
+
+ * subr.c (strip_trailiing_newlines): Use size_t rather than int to
+ count string length.
+ (Suggestion from Paul Edwards, who provides a broken return email
+ address in Tonga. I believe he is actually from Australia.)
+
+2003-07-28 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (checkout): Remove out-of-date comment about Checkin.prog
+ and Update.prog.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_parsercsfile): Declare rcsfile argument as const.
+ * rcs.h (RCS_parsercsfile): Update prototype to match.
+ * commit.c (fixaddfile): Accept a single path to an rcs file as an
+ argument rather than trying to look it up again when it is not
+ necessary.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * commit.c (finaladd): But don't free variables we no longer allocate.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * checkin.c (Checkin): The rcs argument is unecessary since we know
+ that the parsed RCS data always exists as part of finfo by the time
+ this function gets called.
+ * commit.c (commit_fileproc, finaladd): Use new Checkin() API.
+ * cvs.h (Checkin): Update prototype.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * subr.c (strip_trailing_newlines): Check len b4 str[len] to avoid
+ exceeding the array bounds when the string length == 0.
+ (Report from John Tytgat <JoTy@esko-graphics.com>.)
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * subr.c (strip_trailing_newlines): Generalize this function to watch
+ len so that it cannot walk past the beginning of the string passed in.
+ (Report from John Tytgat <JoTy@esko-graphics.com>.)
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * subr.c (strip_trailing_newlines): Leave the K&R function decl on this
+ branch.
+
+2003-07-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (strip_trailing_newlines): Update prototype.
+ * subr.c (strip_trailing_newlines): Return true when newlines are
+ removed.
+ * server.c (pserver_authenticate_connection): Don't give a DOS attack a
+ chance to authenticate accidentally because I like to be paranoid.
+ * sanity.sh (pserver): New test for same.
+
+2003-07-24 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (check_system_password): Cleanup pam_* return code
+ checking. (Original patch from Brian Murphy <brian@murphy.dk>.)
+
+2003-07-24 Derek Price <derek@ximbiot.com>
+
+ * main.c: But the GNULIB gethostname accepts an int not ssize_t.
+
+2003-07-24 Derek Price <derek@ximbiot.com>
+
+ * main.c: Don't declare gethostname when we already have it to avoid
+ decl conflicts.
+
+2003-07-24 Derek Price <derek@ximbiot.com>
+
+ * server.c (server_directory): Add a TRACE for OS X debugging.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * client.c: Avoid some warning from gcc -Wall.
+ * lock.c: Ditto.
+ * login.c: Ditto.
+ * modules.c: Ditto.
+ * server.c: Ditto.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (isaccessible): Correct some double const warnings from
+ protoize.
+ * login.c (password_entry_parseline): Ditto.
+ * server.c (kserver_authenticate_connection): Remove a multi-line
+ string along with the warning from GCC.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * *.{c,h}: Back out the indent run.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Move some includes into lib/system.h.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * *.{c,h}: Run these through GNU indent as per the NEWS file to fix
+ some of the long function decls which came out of protoize.
+
+2003-07-23 Derek Price <derek@ximbiot.com>
+
+ * *.c: Run these through GCC's protoize to convert the pre-ANSI C
+ function decls to C89 compliance.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Remove support for the PTR macro, since we can assume void *
+ under C89. It also was not being made use of in very many places so
+ even most K&R compilers must have supported it, or nobody was using
+ K&R compilers. We can also assume <stdarg.h> under C89, but move the
+ include...
+ * error.c: ...here, de-macro VA_START, and...
+ * subr.c: ...put a copy here too, as well as de-macroing VA_START.
+ * history.c: s/PTR /void */g;
+ * modules.c: Ditto.
+
+2003-07-22 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Include GNULIB exit.h.
+
+2003-07-20 Derek Price <derek@ximbiot.com>
+
+ * server.c: Add PAM support.
+ (cvs_pam_userinfo): New data type for PAM conversations.
+ (cvs_pam_conv): New function.
+ (check_password): Add PAM support.
+ (Original patch from Brian Murphy <brian@murphy.dk>.)
+
+2003-07-20 Derek Price <derek@ximbiot.com>
+
+ * wrapper.c: Remove mention of obsolete -f and -t wrapper options from
+ a comment.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (release): Add new tests for release with unrecognized
+ recognized directories.
+
+2003-07-18 Derek Price <derek@ximbiot.com>
+
+ * vers_ts (Version_TS): Don't allow command line keyword expansion
+ modes to override binary mode.
+ * sanity.sh (): Tests for the above.
+ (Original patch from Dieter Maurer <dieter@handshake.de>.)
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * add.c: s/PROTO//.
+ * admin.c: Ditto.
+ * annotate.c: Ditto.
+ * buffer.c: Ditto.
+ * buffer.h: Ditto.
+ * checkout.c: Ditto.
+ * classify.c: Ditto.
+ * client.c: Ditto.
+ * client.h: Ditto.
+ * commit.c: Ditto.
+ * cvs.h: Ditto.
+ * diff.c: Ditto.
+ * edit.c: Ditto.
+ * edit.h: Ditto.
+ * entries.c: Ditto.
+ * error.c: Ditto.
+ * error.h: Ditto.
+ * expand_path.c: Ditto.
+ * fileattr.c: Ditto.
+ * fileattr.h: Ditto.
+ * filesubr.c: Ditto.
+ * find_names.c: Ditto.
+ * gssapi-client.c: Ditto.
+ * gssapi-client.h: Ditto.
+ * hardlink.h: Ditto.
+ * hash.c: Ditto.
+ * hash.h: Ditto.
+ * history.c: Ditto.
+ * import.c: Ditto.
+ * kerberos4-client.h: Ditto.
+ * lock.c: Ditto.
+ * log-buffer.c: Ditto.
+ * log-buffer.h: Ditto.
+ * log.c: Ditto.
+ * login.c: Ditto.
+ * logmsg.c: Ditto.
+ * mkmodules.c: Ditto.
+ * modules.c: Ditto.
+ * myndbm.c: Ditto.
+ * myndbm.h: Ditto.
+ * patch.c: Ditto.
+ * rcs.c: Ditto.
+ * rcs.h: Ditto.
+ * rcscmds.c: Ditto.
+ * recurse.c: Ditto.
+ * release.c: Ditto.
+ * remove.c: Ditto.
+ * root.c: Ditto.
+ * rsh-client.h: Ditto.
+ * run.c: Ditto.
+ * server.c: Ditto.
+ * server.h: Ditto.
+ * socket-client.c: Ditto.
+ * socket-client.h: Ditto.
+ * status.c: Ditto.
+ * subr.c: Ditto.
+ * tag.c: Ditto.
+ * update.c: Ditto.
+ * update.h: Ditto.
+ * vers_ts.c: Ditto.
+ * watch.c: Ditto.
+ * watch.h: Ditto.
+ * wrapper.c: Ditto.
+ * zlib.c: Ditto.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Include pathmax.h.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * myndbm.c: Use the GNU getdelim function rather than our package
+ getstr.
+ * server.c: Use the (hopefully) GNULIB and more appropriately named
+ getnline function rather than our getline_safe function.
+
+2003-07-12 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh (diffnl): New tests for diff on files with no newline
+ at end.
+ (Patch from Andrew Moise <chops@demiurgestudios.com>.)
+
+2003-07-11 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.am (cvs_DEPENDENCIES): Include the libraries.
+ * Makefile.in: Regenerated.
+
+ * diff.c (diff_file_nodiff): Fix -Wall complaints.
+ * log.c (rlog_proc): Ditto.
+ * rcs.c (RCS_setlocalid): Ditto.
+ * recurse.c (start_recursion): Handle null repository_in in TRACE.
+
+2003-07-09 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh: Use ${CPROG} instead of ${PROG} so that changes merged
+ from cvs1-11-x-branch without updating won't appear to work.
+
+ * sanity.sh (keywordexpand): Use ${SPROG} instead of ${PROG} as
+ required.
+
+ * add.c (add): Update "re-adding" message to have quotes around
+ the file name like all the other similar messages.
+ * sanity.sh: Update to match.
+
+ * update.c (join_file): Handle locally removed but not yet committed
+ files.
+ (Reported by Larry Lords <LordsLL@ldschurch.org>.)
+ * sanity.sh (join, join4): New tests for above.
+
+2003-06-28 Larry Jones <lawrence.jones@eds.com>
+
+ * commit.c (fixaddfile): Bail out if locate_rcs() fails. Make
+ parameters const.
+
+ * add.c (add): Fix -Wall complaints.
+ * diff.c (diff_file_nodiff): Ditto.
+ * filesubr.c (cvs_casecmp): Ditto.
+ * patch.c (patch_fileproc): Ditto.
+ * rcs.c (RCS_cmp_file): Ditto.
+ * root.c (parse_cvsroot): Ditto.
+ * subr.c (locate_file_in_dir): Ditto.
+ * cvs.h (cvs_casecmp, locate_file_in_dir): Update prototypes.
+
+2003-06-27 Larry Jones <lawrence.jones@eds.com>
+
+ * lock.c (readers_exist): Use LockDir rather than always looking
+ in the repository.
+ (Original patch from Robert Ambalu <Robert.Ambalu@gs.com>.)
+ Remove vestigial lock promotion code.
+
+2003-06-27 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (safe_location): Don't try and print from a NULL pointer.
+ (Report and original patch from Sampo Kellomaki <sampo@symlabs.com>.)
+
+2003-06-26 Larry Jones <lawrence.jones@eds.com>
+
+ * hash.c (sortlist): Avoid crash when list is null.
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * patch.c (patch_fileproc): Output revision number of the original
+ revision in the removed case.
+ (Idea from Paul Edwards <kerravon@w3.to>.)
+
+ * sanity.sh (rdiff-add-remove-nodiff): Rename to...
+ (rdiff-short): ...this. Test for the above changes. Add some tests
+ for when rev2 defaults to the trunk. Expand comments.
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * client.c: Reapply Alexey's changes to client.c from three commits
+ back they were left out of the diff.
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Fix xmalloc's strlen() of wrong variable.
+ * checkout.c (safe_location): leak: reused where_location without free.
+ * log.c (rlog_proc): leak: free where before exit.
+ * logmsg.c (do_verify): leak: free verifymsg_script before exit.
+ (Original patch from Kenneth Lorber <keni@his.com>.)
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * client.c: Remove silly comment.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-06-23 Derek Price <derek@ximbiot.com>
+
+ * kerberos4-client.h, kerberos4-client.c, client.c: Rename
+ start_tcp_server() to start_kerberos4_server().
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-06-20 Derek Price <derek@ximbiot.com>
+
+ * kerberos-client.c, kerberos-client.h, client.c: Split out
+ Kerberos 4 code to separate files.
+
+ * Makefile.am: Mention new files.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-06-16 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Comment an #endif.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (cvs_temp_name): Remove portability cruft obsoleted by the
+ import of GNULIB's mkstemp().
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * subr.c (file_has_conflict): Fix comment.
+ (Patch from Paul Edwards <kerravon@w3.to>.)
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * subr.c (xrealloc): Trivial comment fix.
+ (Patch from Kenneth Lorber <keni@his.com>.)
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * diff.c (diff_fileproc): Fix memory leak.
+ (Patch from Kenneth Lorber <keni@his.com>.)
+
+2003-06-12 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_cvsroot, local_cvsroot): Parse trailing '/'s off the
+ end of cvsroots. Make arguments const.
+ * cvs.h: Update prototypes to match.
+ (Idea from Miles Zarathustra <shiva@aranyaka.org>.)
+
+2003-06-12 Derek Price <derek@ximbiot.com>
+
+ * checkout.c (safe_location): Fix memory leak.
+ (Patch from Kenneth Lorber <keni@his.com>.)
+
+2003-06-11 Larry Jones <lawrence.jones@eds.com>
+
+ * filesubr.c (xresolvepath): Fix memory leak.
+ (Original patch from Kenneth Lorber <keni@his.com>.)
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * commit.c: Change Parse_Info calling convention to include void *
+ suggested in HACKING file and generalize all argument to opt.
+ * cvs.h: update defs for Parse_Info and its callproc.
+ * edit.c: Change Parse_Info calls for new calling convention.
+ * logmsg.c: Ditto.
+ * parseinfo.c: Change Parse_Info for new calling convention.
+ * server.c: Change Parse_Info calls for new calling convention.
+ * tag.c: Ditto.
+ (Original patch from Ken Lorber <keni@his.com>.)
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-06-11 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh: Change warning messages to note that defective tools
+ can result in defective results, both pass and fail. Also change
+ "which" to "that" for errant grammar pedants.
+
+2003-06-10 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (start_recursion): Avoid unneeded allocation.
+
+2003-06-10 Mark D. Baushke <mdb@gnu.org>
+
+ * rcs.c (RCS_setlocalid,RCS_setincexc): New functions to support
+ LocalKeyword and KeywordExpand config keywords.
+
+ * rcs.h (RCS_setlocalid,RCS_setincexc): New prototypes.
+
+ * parseinfo.c (parse_config): Added LocalKeyword
+ and KeywordExpand keywords.
+
+ * sanity.sh (keywordexpand): New CVSROOT/config tests for
+ LocalKeyword and KeywordExpand options.
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_delete_revs): Reference WOE32 rather than WIN32 in
+ accordance with the GNU convention to avoid implying that we consider
+ the Microsoft Windows Operating Environment any sort of "win".
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (cvs_temp_file): Tidy a comment.
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * patch.c (patch_fileproc): Don't assume the content of files is
+ different just because the revision number is different.
+ * sanity.sh (rdiff-add-remove-nodiff): New tests for the above.
+ (Report & original patches from Paul Edwards <kerravon@w3.to>.)
+
+2003-06-04 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (locate_file_in_dir): New proto.
+ (locate_rcs): Move proto...
+ * rcs.h: ...here.
+ * filesubr.c (locate_rcs): Move function...
+ * rcs.c: ...here for Windows.
+ * filesubr.c (locate_file_in_dir): Move function...
+ * subr.c: ...here for Windows.
+
+2003-06-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Add comments re portability of test -x & test -e. Don't
+ bother with quotes in arguments to test when we have laready checked
+ the variables for empty content.
+
+2003-06-02 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Don't use `test -x' since BSD 4.3 doesn't like it. Minor
+ reorganization for clarity. Don't check for $server = false after we
+ set its default. Use </dev/null with calls to $prog --version when we
+ don't know what $prog does for sure.
+
+2003-06-02 Derek Price <derek@ximbiot.com>
+
+ * diff.c (diff_file_nodiff): Don't assume that because two specified
+ revision numbers are different, the contents are different.
+ (Original report & patch from Paul Edwards <kerravon@w3.to>.)
+
+ * diff.c (diff_file_nodiff): Pass through rev1_cache to be filled in
+ by RCS_cmp_file when it needs to check out revision 1 into a file. Add
+ some more informative error messages. Cleanup for efficiency &
+ readability.
+ (diff_fileproc): Pass the cached revision to RCS_exec_diff(). Clean up
+ the error exit code. Remove code killed by the changes to
+ diff_file_nodiff().
+ * rcscmds.c (RCS_exec_rcsdiff): Accept and use new cached revision text
+ if present.
+ * rcs.c (RCS_cmp_file): Accept a second revision number and cache the
+ first revision if it needs to be checked out.
+
+ * checkin.c (Checkin): Use new RCS_cmp_file().
+ * import.c (update_rcs_file): Ditto.
+ * no_diff.c (No_Difference): Ditto.
+
+ * cvs.h (RCS_exec_rcsdiff): New proto to match above changes.
+ * rcs.h (RCS_cmp_file): Ditto.
+
+ * sanity.sh: Minor corrections to handle the above changes.
+
+2003-05-31 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_cvsroot): Refuse :fork: only in client mode, not
+ server.
+ * client.c (connect_to_forked_server): Die without SERVER_SUPPORT when
+ CVSSERVER isn't supplied in the environment.
+ * sanity.sh: Default $servercvs to $testcvs. Add SPROG so that testing
+ a client and server with different names works in order to test the
+ above changes. s/PROG/SPROG/ almost everywhere. Misc corrections to
+ tests when ${PROG} is required not to use [a-z]*. Misc uniqifications
+ of test names. Misc replacement of CVS_SERVER=${testcvs} with
+ CVS_SERVER=${servercvs}. Confirm ${testcvs} & ${servercvs} exist and
+ are executable. Set testcvs_server_support=true if the ${testcvs}
+ executable has server support. Misc comment corrections.
+ (pserver): s/\$\{testcvs\}/${servercvs}/ for invocations of pserver.
+ (server): Ditto for invocations of `cvs server'.
+ (fork): Accept the `was not compiled with server support' error
+ message.
+
+2003-05-29 Derek Price <derek@ximbiot.com>
+
+ * client.c (start_server): Don't send -l to server.
+ * history.c (history_write): Fix comment.
+ * main.c (main): Don't process -l.
+ * server.c (serve_global_option): Ditto.
+ (Suggestion from Rob Lanphier <robla@real.com>.)
+
+2003-05-29 Derek Price <derek@ximbiot.com>
+
+ * log-buffer.c, rsh-client.c, socket-client.c: Allow compilation
+ with --disable-client.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-05-29 Derek Price <derek@ximbiot.com>
+
+ * gssapi-client.h: Move contents of lib/xgssapi.h here.
+ * server.c: xgssapi.h is no more.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-05-28 Derek Price <derek@ximbiot.com>
+
+ * server.c: Use standard PROTOTYPES symbol instead of non-standard
+ USE_PROTOTYPES.
+ * error.h, cvs.h: Use PROTO.h.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-05-23 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh (info-cleanup-verifymsg): Avoid race in output.
+
+ * sanity.sh (template): Fix unintended duplicate DEFAULT lines,
+ duplicate test names.
+
+2003-05-22 Larry Jones <lawrence.jones@eds.com>
+
+ * commit.c (commit): Fix leading zero stripping code to not strip
+ unless there's a following digit.
+
+ * parseinfo.c (Parse_Info): Warn if multiple DEFAULT lines found.
+ * sanity.sh (info): New test for above.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Larry Jones <lawrence.jones@eds.com>
+
+ * parseinfo.c (Parse_Info): Fix stupid memory management error.
+
+ * logmsg.c (do_verify): Treate Parse_Info errors as failure.
+ * parseinfo.c (Parse_Info): Don't call expand_path until executing
+ the command so that errors in unexecuted commands aren't reported.
+ * sanity.sh (info): New tests for above.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * mkmodules.c (config_contents): Add missing newline.
+ (Patch from Kenneth Lorber <keni@his.com>.)
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Macro subsitution for zlib include path and library
+ location
+ * zlib.c: #ifdef inclusion of <zlib.h> versus "zlib.h"
+ (Original patch from Anthon Pang <apang@telus.net>.)
+
+ * Makefile.in: Regenerated
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Move the standard includes into lib/system.h.
+ * subr.c: s/malloc/CVS_MALLOC/;s/realloc/CVS_REALLOC/.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c: s/\bstat\b/CVS_STAT/g;s/\blstat\b/CVS_LSTAT/g
+ * hardlink.c: Ditto.
+ * ignore.c: Ditto.
+ * rcs.c: Ditto.
+ * update.c: Ditto.
+
+2003-05-18 Larry Jones <lawrence.jones@eds.com>
+
+ * checkout.c (safe_location): Remove unused variable.
+ * hash.c (walklist, printnode, printlist): Use %p to print pointers
+ if available, convert to unsigned long if not.
+ * recurse.c (start_recursion, do_recursion): Ditto.
+ * tag.c (rtag_proc, tag_check_valid): Ditto.
+
+2003-05-18 Mark D. Baushke <mdb@gnu.org>
+
+ * Makefile.am (localcheck,remotecheck): Use cvs$(EXEEXT) not cvs.
+ * Makefile.in: Regenerated.
+ * sanity.sh (status-init-7): Use ${PROG} not cvs in tests.
+ (branch-after-import-5): Ditto.
+ (keywordname-update-11): Ditto.
+
+2003-05-18 Larry Jones <lawrence.jones@eds.com>
+
+ * server.h (kserver_authenticate_connection,
+ pserver_authenticate_connection): Add prototypes.
+
+ * client.c (update_entries): Set file's access time to the current
+ time rather than the same as the modification time.
+ * vers_ts.c (Version_TS): Ditto.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * client.c: #ifdef inclusion of gssapi-client.h.
+ * server.c: Ditto.
+ (Reported by Boyd Lynn Gerber <gerberb@zenez.com>.)
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * client.h: Move some of the GSSAPI stuff...
+ * gssapi-client.h: ...to this new file.
+ * client.c (start_server): Use new initialize_gssapi_buffers().
+ (*): Move most of the GSSAPI stuff from here and...
+ * server.c (*): ...here...
+ * gssapi-client.c: ...to this new file.
+ * Makefile.am (EXTRA_cvs_SOURCES, cvs_DEPENDENCIES, cvs_LDADD): Support
+ $(cvs_client_objects).
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * buffer.c: Reindent some compiler directives in order to make nesting
+ clearer.
+
+2003-05-08 Derek Price <derek@ximbiot.com>
+
+ * client.c (log_buffer*): Move...
+ * log-buffer.c (log_buffer*): ...to this new file.
+ * log-buffer.h (setup_logfiles): New file to share prototype.
+ * Makefile.am: Add log-buffer.c & log-buffer.h.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-05-08 Derek Price <derek@ximbiot.com>
+
+ * client.c (init_sockaddr): Move...
+ * socket-client.c (init_sockaddr): ...here.
+ * socket-client.h (init_sockaddr): Prototype.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-05-08 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_to_server): Move most of the functionality to and
+ wrap...
+ (send_to_server_via): ...this new function which accepts the buffer
+ pointer as an argument.
+ (read_line): Ditto, but to...
+ (read_line_via): ...here.
+ (auth_server): Rename lto_server & lfrom_server to s/^l//. Remove
+ ugly code which sets the global versions of these variables
+ temporarily for function calls.
+ s/send_to_server(/send_to_server_via(to_server,/g,
+ s/read_line(/read_line(from_server,/g,
+ Remove emotional FIXME comment to the effect that all this is
+ necessary.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-05-07 Derek Price <derek@ximbiot.com>
+
+ * client.c (from_server, to_server): Rename these global buffer
+ pointers to...
+ (global_from_server, global_to_server): ...this in order to avoid
+ confusion.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-05-07 Derek Price <derek@ximbiot.com>
+
+ * client.c (make_bufs_from_fds, connect_to_forked_server,
+ start_tcp_server): Rename struct buffer ** arguments to s/$/_p/ in an
+ attempt to denote their pointerness more clearly.
+ * rsh-client.c (start_rsh_client): Ditto.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * client.h (make_bufs_from_fds): Sanitize prototype so that the
+ argument name change doesn't clash.
+
+2003-05-07 Derek Price <derek@ximbiot.com>
+
+ * client.h (make_bufs_from_fd): Prototype in order to make available to
+ rsh-client.c.
+ * client.c (start_rsh_server): Moved most of the RSH (:ext:) client
+ stuff to...
+ * rsh-client.h: ...here...
+ * rsh-client.c: ...and here.
+ * Makefile.am (cvs_SOURCES): Add new source files.
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-05-06 Derek Price <derek@ximbiot.com>
+
+ * client.c (socket_buffer_*): Moved most of the socket stuff to...
+ * socket-client.h: ...here...
+ * socket-client.c: ...and here.
+ * Makefile.am (cvs_SOURCES): Add new source files.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-05-05 Derek Price <derek@ximbiot.com>
+
+ * hash.c (findnode): Document behavior of this function when its list
+ argument is NULL and document this behavior. Remove FIXME comment to
+ the effect that this is necessary.
+
+2003-05-01 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Ignore -z when CLIENT_SUPPORT is not defined.
+ (Report from Jim Salter <jsalterjim@earthlink.net>.)
+
+2003-05-01 Derek Price <derek@ximbiot.com>
+
+ * repos.c (Sanitize_Repository_Name): Remove some old comments about
+ the defunct RELATIVE_REPOS macro.
+ * server.c (outside_root): Ditto.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * vers_ts.c (Version_TS): Minor optimization.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Fix a possible, if unlikely, memory out of bounds error.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * commit.c: Free vers in single place
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Get rid of $includeopt, using $CPPFLAGS as intended by
+ the Autoconf folk.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * add.c (add): Fix a possible, if unlikely, memory out of bounds error.
+
+2003-04-28 Derek Price <derek@ximbiot.com>
+
+ * client.c (save_prog): Remove unneeded struct.
+ (checkin_progs, update_progs): Remove these unneeded globals.
+ (handle_set_checkin_prog, handle_set_update_prog, do_deferred_progs):
+ Remove these functions.
+ (send_repository): Remove checkin and update prog support.
+ (responses): Remove Set-checkin-prog and Set-update-prog.
+ (get_responses_and_close): Don't call do_deferred_prog().
+ * commit.c (commit_usage): Remove reference to -n.
+ (commit): Don't set and send run_module_prog via -n. Don't run
+ Checkin.prog or Checkout.prog in local mode.
+ * modules.c (CVSMODULE_OPTS): Remove -i and -u.
+ (do_module): Don't process -i and -u options to set checkin and update
+ progs, respectively.
+ * server.c (server_prog, serve_checkin_prog, server_update_prog):
+ Remove unused functions.
+ (requests): Remove Checkin-prog and Update-prog.
+ * update.c (update_dirleave_proc): Remove update prog functionality.
+
+ * cvs.h (CVSADM_CIPROG, CVSADM_UPROG): Remove unneeded defines.
+ * server.h (server_prog): Remove proto.
+ (progs): Remove enum.
+
+ * sanity.sh (modules5): Remove tests for checkin and update programs.
+
+2003-04-15 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (*): Shrink the yucky case statement using sed's transform
+ functionality.
+ (getlongoptarg): Convert this function to only confirm the arg and move
+ it...
+ (checklongoptarg): ...here.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-04 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh (branches4-15): New test.
+
+ * error.h: Avoid __pure__ for GCC versions < 2.96 & __malloc__ for GCC
+ versions < 3.0.
+
+2003-04-03 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (DISTCLEAN_FILES): Move the contents of this variable...
+ (distclean-local): ...to this target now that Automake supports it.
+
+2003-04-03 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Avoid __pure__ for GCC versions < 2.96 & __malloc__ for GCC
+ versions < 3.0.
+
+2003-04-02 Larry Jones <lawrence.jones@eds.com>
+
+ * update.c (update, update_fileproc, update_filesdone_proc,
+ update_dirent_proc, update_dirleave_proc): Keep track of whether
+ a tag is both a revision tag and a branch tag and warn the user.
+ * sanity.sh (branches4): New tests for above.
+
+2003-04-02 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (do_recursion): Use strstr("/./") rather than strchr('.')
+ to catch only indirections in paths and not directory names with dots
+ in them.
+ (Report from Pavel Roskin <proski@gnu.org>.)
+
+ * sanity.sh (multiroot): Put a dot in the CVSROOT_DIRNAMEs.
+ (dottedroot): New test.
+ (Based on a script from Pavel Roskin <proski@gnu.org>.)
+
+2003-04-01 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (multiroot2-9): Add newly TRACEd parse_cvsroot() to
+ expected output.
+
+2003-03-31 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (freercsnode): Revert an accidental change from the previous
+ commit.
+
+2003-03-31 Derek Price <derek@ximbiot.com>
+
+ * recurse.c (start_recursion): Accept new repository argument so that
+ the working directory may be tracked by do_recursion without using
+ xgetwd(), which returned a value different from the one the user
+ requested when symlinks were in use. Add TRACE. Pass repository_in
+ to do_recursion() as part of the recursion frame.
+ (do_recursion): Default srepository to NULL and only set when we set
+ repository. Keep track of repository using xframe.repository for the
+ r* commands rather than xgetwd(), which used to break when CVSROOT was
+ a symlink to a real root.
+
+ * cvs.h (xreadlink): #ifdef HAVE_READLINK proto.
+ (xresolvepath): New proto.
+ (start_recursion): Add repository to proto.
+ (*): Define some more abstract TRACE levels.
+ * update.h (do_update): Add repository argument to proto.
+
+ * checkout.c (safe_location): Add more complete header comment. Add
+ TRACE. Use new xresolvepath() function. Always return true in
+ client mode since checking our destination path against the CVSROOT
+ path is usually meaningless in client/server mode.
+ (checkout_proc): Pass repository to do_update() for later use with
+ start_recursion().
+ (*): s/<chdir>/CVS_CHDIR/.
+ * filesubr.c (xreadlink): #ifdef HAVE_READLINK this function. Add more
+ complete header comment.
+ (xresolvepath): New function.
+ * hash.c (walklist): Add TRACE.
+ * main.c (main): Don't copy and dispose of CVSRoot_cmdline twice.
+ * patch.c (patch_proc): Add TRACE. Pass repository to
+ tag_check_valid() for r* commands.
+ * root.c (parse_cvsroot): Add TRACE.
+ * tag.c (rtag_proc): Add TRACE.
+ (check_fileproc): Ditto.
+ (tag_check_valid): Ditto.
+ * update.c (do_update): Accept new repository argument for co.
+ (update): Pass NULL repository to do_update().
+
+ * admin.c (*): Use new definition of start_recursion().
+ * annotate.c (*): Ditto.
+ * client.c (*): Ditto.
+ * commit.c (*): Ditto.
+ * diff.c (*): Ditto.
+ * edit.c (*): Ditto.
+ * lock.c (*): Ditto.
+ * log.c (*): Ditto.
+ * patch.c (*): Ditto.
+ * remove.c (*): Ditto.
+ * status.c (*): Ditto.
+ * tag.c (*): Ditto.
+ * update.c (*): Ditto.
+ * watch.c (*): Ditto.
+
+ * sanity.sh: Add new -l option to test symlinked roots.
+ (abspath-3.2): Use [a-z]* rather than "checkout".
+ (check_repository-1): Add server error messages about absolute paths
+ since the client now skips destination validity checks.
+ (check_repository-2): Process client error messages about CVSROOT
+ files being in the way since the client skips destination validity
+ checks since it should be rare that a client is running in
+ client/server mode on the server and CVS has no current way to check if
+ it is runnning on the server.
+
+2003-03-27 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (rdiff2): Add new test case for SEGV problem reported
+ against cvs 1.11.5.
+ (Report from James Cribb)
+
+2003-03-26 Derek Price <derek@ximbiot.com>
+
+ * client.c: Fix, reorganize, and comment ifdefs for AUTH_CLIENT_SUPPORT
+ and HAVE_GSSAPI.
+ * client.h: Ditto. Remove some unecessary server function prototypes.
+
+2003-03-26 Derek Price <derek@ximbiot.com>
+
+ * client.c: Include the net headers for HAVE_GSSAPI.
+ (Report from Jim Salter <jsalterjim@earthlink.net>.)
+
+2003-03-26 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Verify the argument to -z when running without
+ CLIENT_SUPPORT since Eric Siegerman complained about being bit
+ by a run of `cvs -z -n up' which parsed the -n as the argument to
+ -z.
+ * sanity.sh (opterrmsg): New tests for -z argument checking.
+
+2003-03-26 Larry Jones <lawrence.jones@eds.com>
+
+ * main.c (main): Use strtol() instead of atoi() when parsing -z
+ to detect errors.
+ (Reported by Eric Siegerman <erics@telepres.com>.)
+
+2003-03-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Disable GNU attributes as part of PROTO behavior.
+ * error.h: Mirror GNU attribute definitions from cvs.h.
+
+2003-03-25 Derek Price <derek@ximbiot.com>
+
+ * subr.c (cvs_trace): #ifdef use of server_active.
+ (Report from Jim Salter <jsalter@proofpoint.com>.)
+
+ * cvs.h (xmalloc, xrealloc, xstrdup, parse_cvsroot,
+ local_cvsroot, normalize_cvsroot): Use GNU attributes.
+ * error.h (error_exit): Fix PROTO/__attribute__ specification.
+ * root.c (new_cvsroot_t): Add GNU attribute.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-24 Larry Jones <lawrence.jones@eds.com>
+
+ * server.h (server_clear_template): Add declaration.
+ (server_template): Add parameter names to prototype.
+
+2003-03-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (env): Try more than one ps command if the first one
+ fails. This may let the test succeed on more platforms. Also,
+ keep the ps output that was processed for the error report.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh (env): Use 'ps -el' rather than 'ps -l' so that
+ crontab jobs that might be running these tests without a
+ controlling terminal work properly.
+
+ * client.c (start_rsh_server): Use new definition of RSH_DFLT to
+ allow "rsh" to be configured to default to "ssh" or some other
+ local remote transport program.
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Larry Jones <lawrence.jones@eds.com>
+
+ * filesubr.c (mkdir_if_needed): Save errno since isdir() can clobber.
+ (Patch from Brian Poole <raj@cerias.purdue.edu>.)
+ * sanity.sh (abspath-4): Update to match.
+
+ * filesubr.c (locate_rcs): Fix gcc warning.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * add.c (add_directory): Only call WriteTemplate when the server is
+ active.
+ * create_adm.c (Create_Admin): Don't call WriteTemplate here since
+ Create_Admin is only called from the client.
+ * commit.c (commit_dirleaveproc): Don't call WriteTemplate here. I'm
+ a little confused as to why since update_direntproc works for update.c,
+ but I can't come up with a test case that fails when this call is
+ missing. Nor can I come up with a test case that passes when this call
+ is present and the one in commit_filesdoneproc is removed.
+ * sanity.sh (template): Tidy, minimize, and add some extra tests.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * .cvsignore: Added sanity.config.sh, a new auto-generated file.
+
+ * cvs.h (CVS_PID_ENV): New environment variable CVS_PID has the
+ pid of the parent cvs process.
+ * main.c (main): Initialize it.
+ * sanity.sh (env): Test it.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * sanity.config.sh.in: New file.
+ * sanity.sh: Source new config file when available. Accept alternate
+ config file as an argument to a -c option. Accept long options with
+ arguments.
+ (getlongoptarg): New function.
+
+ * Makefile.in: Regenerated.
+
+2003-03-18 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_root): Add some more comments and expand
+ #ifdef CLIENT_SUPPORT pragmas. Rearrange sanity checks slightly.
+
+2003-03-18 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Output -R warning in quiet mode and correct spelling
+ in this warning message.
+ * sanity.sh (commit-readonlyfs-2r4): Correct cascaded spelling mistake
+ in test.
+
+2003-03-17 Derek Price <derek@ximbiot.com>
+
+ * add.c: Correct comment.
+ * client.c: Ditto.
+ * checkin.c (Checkin): Pass work file name to RCS_checkin so that this
+ function works properly in the case insensitive mode.
+ * commit.c (checkaddfile): Fix and factor add logic so that the
+ correct files and directories are created in the case insensitive mode.
+ Reuse code in RCS_parse() below. This avoids a problem that could
+ cause corrupted RCS files to be created on an add from a case
+ insensitive system. Corrupted RCS files could cause later assertion
+ failures for everyone.
+ (locate_rcs): Move this function...
+ * filesubr.c (locate_rcs): ...here and rewrite it.
+ (fopen_case): Remove this function.
+ (locate_file_in_dir): New function.
+ * cvs.h (locate_rcs): Prototype new function.
+ * rcs.c (RCS_parse): Factor out file location into locate_rcs.
+
+2003-03-17 Mark D. Baushke <mdb@cvshome.org>
+
+ * main.c (main): Issue a warning about readonlyfs options unless
+ quiet or really_quiet is set.
+ * lock.c (Writer_Lock): Modify readonlyfs error message text.
+ * sanity.sh (commit-readonlyfs): Adjust test for new messages.
+
+2003-03-17 Larry Jones <lawrence.jones@eds.com>
+
+ * server.c (switch_to_user): Add syslog calls for setgid/setuid
+ failure.
+
+2003-03-16 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.h (CVSREADONLYFS_ENV): New macro to support new environment
+ variable "CVSREADONLYFS" for read-only file-system repository mode.
+ * lock.c (Reader_Lock, Writer_Lock): Add support for new read-only
+ file-system repository mode.
+ * main.c (main, opt_usage): Ditto.
+ * root.c (parse_cvsroot): Ditto.
+ * sanity.sh (commit-readonlyfs): Test new read-only file-system
+ repository mode.
+
+2003-03-14 Mark D. Baushke <mdb@cvshome.org>
+
+ * server.c (template_proc): Fix broken Template protocol code.
+ Must call send buf_send_counted() for Template files to avoid
+ "Protocol error: uncounted data discarded" messages in some
+ circumstances.
+ * sanity.sh (template): Test case to verify fix this fix.
+
+2003-03-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * cvs.h (WriteTemplate): Add missing prototype.
+
+2003-03-07 Mark D Baushke <mdb@cvshome.org>
+
+ * sanity.sh: Fix broken setting of the servercvs variable.
+
+2003-03-07 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (help): Add explanation of CVS-TO-TEST and edit for
+ consistency.
+
+2003-03-07 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (usage): Show users long --help rather than less
+ informative -h.
+
+2003-03-07 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh: Add support for long options.
+ (exit_usage): Move the actual generation of usage text to...
+ (usage): ...this new function and improve the usage message.
+ (exit_help): New function.
+
+2003-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanity.sh: Drop the clientcvs option. Add usage info for
+ the -s servercvs option.
+
+2003-03-07 Larry Jones <lawrence.jones@eds.com>
+
+ * commit.c (check_fileproc): Remove unused variables.
+
+ * patch.c (patch): Pass local to do_module so that -l actually works.
+ (Reported by John Coers <coers@intrinsity.com>.)
+ (patch_fileproc): Fix uninitialized variables.
+ * sanity.sh: Define a DATE pattern for rdiff and use it.
+ (basic2-24a): New test for above.
+
+2003-03-07 Mark D. Baushke <mdb@cvshome.org>
+
+ * entries.c (WriteTemplate): New function to control updates to
+ the CVS/Template file or its removal.
+ * create_adm.c (Create_Admin): Use the new WriteTemplate function.
+ * add.c (add_directory): Add a WriteTemplate() call
+ when a new directory is added to the repository.
+ * commit.c (commit_filesdoneproc): Ensure that the CVS/Template is
+ updated at the end of a commit -- mostly to remove it if it is not
+ relevant.
+ (commit_dirleaveproc): Ensure that the CVS/Template gets updated
+ when the directory is left.
+ * update.c (update_dirent_proc): Update CVS/Template file.
+ * server.c (server_clear_template): New protocol response to
+ remove existing CVS/Template files.
+ * client.c (clear_template): New function to remove or truncate a
+ CVS/Template file.
+ (handle_clear_template): New function. Handle Clear-template
+ protocol response message.
+ (save_prog): Add new Clear-template response line.
+ * sanity.sh (template): Test the CVS/Template creation with
+ the remote protocol. Nothing gets created locally.
+ (multiroot2): Fix for minor changes to trace output.
+ (getopts): Allow tests to be run with specified client and server
+ cvs commands to allow for interoperatbility testing.
+ (check_keep): New shell function for --keep processing.
+
+2003-03-06 Derek Price <derek@ximbiot.com>
+
+ * subr.c (file_has_conflict): New file.
+ * commit.c (check_fileproc): Factor code into new file_has_conflict()
+ function.
+ * update.c (update_fileproc): Ditto.
+ * status.c (status_fileproc): Use new file_has_conflict() function.
+ (Report from Bernd Kuemmerlen <bkuemmer@mevis.de>.)
+
+ * sanity.sh (status): New test for same.
+
+2003-03-06 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh (branches3-4): Set and export CVS_LOCAL_BRANCH_NUM
+ to be sure it really gets into the environment, then unset it
+ when finished (ala CVSWRAPPERS et al).
+
+2003-03-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * sanith.sh (branches3): Localize the setting of
+ the CVS_LOCAL_BRANCH_NUM environment variable.
+
+ * rcs.c (RCS_magicrev): CVS_LOCAL_BRANCH_NUM feature.
+ Port of the FreeBSD hack for setting the next magic branch number
+ to be used. The original patch was written by Peter Wemm
+ <peter@FreeBSD.org> and may be found by visiting the URL:
+ http://www.freebsd.org/cgi/cvsweb.cgi/src/contrib/cvs/src/rcs.c.diff?r1=1.1&r2=1.2
+ Implement a horrible (but simple) hack to allow some control over the
+ branch number that is assigned. This is specifically to support the
+ local commit feature of cvsup. If one sets $CVS_LOCAL_BRANCH_NUM to
+ (say) 1000 then branches the local repository, the revision numbers
+ will look like 1.66.1000.xx. This is almost a dead-set certainty that
+ there will be no conflicts with version numbers.
+ (This needs to be something more than an option to 'cvs tag' or 'cvs
+ rtag' as various parts of cvs "know" how to automatically branch files
+ (eg: cvs add). Trying to remember state is getting "Too Hard (TM)")
+ * sanity.sh (branches3): Test the CVS_LOCAL_BRANCH_NUM feature.
+
+2003-03-04 Derek Price <derek@ximbiot.com>
+
+ * history.c (history_write): Remove unneeded O_CREAT in the call to
+ open() since we abort a few lines earlier if the file doesn't exist.
+ Add a comment to the effect that this is not the optimal method of
+ doing things and needs fixed.
+
+2003-02-28 Derek Price <derek@ximbiot.com>
+
+ * root.c (parse_cvsroot): Set no_password for :gserver: and :kserver:
+ as tokens should already be obtained via external sources.
+ * update.c (update_fileproc): Remove redundant code.
+
+2003-02-28 Larry Jones <lawrence.jones@eds.com>
+
+ * lock.c (set_lock): If possible, try a short wait with no message
+ before calling lock_wait() to optimize master lock contention.
+
+2003-02-26 Larry Jones <lawrence.jones@eds.com>
+
+ * checkout.c (checkout): Send "--" before file names.
+ * sanity.sh (spacefiles): Remote now works just like local.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcs4): Use UTC to work across timezones.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_getdate): Fix a bug that shows up when checking out
+ files by date with the "-D date" command line option. There is
+ code in the original to handle a special case. If the date search
+ finds revision 1.1 it is supposed to check whether revision
+ 1.1.1.1 has the same date stamp, which would indicate that the
+ file was originally brought in with "cvs import". In that case it
+ is supposed to return the vendor branch version 1.1.1.1.
+
+ However, there was a bug in the code. It actually compares the date
+ of revision 1.1 for equality with the date given on the command
+ line -- clearly wrong. This commit fixes the coding bug.
+
+ Note: There is an additional bug which is _not_ fixed in this
+ commit. The date comparison should not be a strict equality test.
+ It should allow a fudge factor of, say, 2-3 seconds. Old versions
+ of CVS created the two revisions with two separate invocations of
+ the RCS "ci" command. We have many old files in the tree in which
+ the dates of revisions 1.1 and 1.1.1.1 differ by 1 second.
+
+ This bug was discovered and fixed for FreeBSD cvs. See v 1.21 of
+ <http://www.freebsd.org/cgi/cvsweb.cgi/src/contrib/cvs/src/rcs.c.diff>
+ for more information.
+
+ * sanity.sh (rcs4): Tests for same.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * logmsg.c (logfile_write): Do not pass a NULL pointer to
+ fprintf() when we have an empty log message.
+ * sanity.sh (editor): Add new tests to verify correct behavior of
+ empty log messages.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>, original report from
+ Piotr KUCHARSKI <chopin@sgh.waw.pl>.)
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (user_admin_options): Rename to...
+ (UserAdminOptions): ...this to match the convention set by
+ of RereadLogAfterVerify.
+ * admin.c (admin): Ditto.
+ * parseinfo.c (parse_config): Ditto.
+
+ * mkmodules.c (config_contents): Update with UserAdminOptions
+ information.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * cvsbug.in: Import use of mktemp function from RedHat 8.0's
+ CVS 1.11.2 RPM. Use new MKTEMP configure variable. Use new
+ SENDMAIL from configure.
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * cvs.h (user_admin_options): New global config option.
+ * admin.c (admin): Handle user_admin_options.
+ * parseinfo.c (parse_config): Handle UserAdminOptions.
+ (Original patch from Dan Peterson <dbpete@aol.com>.)
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * watch.c (watch_usage): Use {} rather than () for literals.
+
+2003-02-21 Larry Jones <lawrence.jones@eds.com>
+
+ * server.c (switch_to_user): Update comment, change error message
+ so it's not an exact duplicate of the one in check_password.
+ (check_repository_password): Add syslog call for password mismatches.
+ (check_password): Add syslog call for password mismatches, rearrange
+ code to simplify and eliminate redundancy.
+ (pserver_authenticate_connection): Remove syslog call, now done by
+ lower-level routines.
+
+2003-02-19 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh (admin-10): Add test for repository files not in
+ working directory.
+
+ * admin.c (admin_fileproc): Fix crash when no rcs file, return
+ failure status for bogus files.
+ * sanity.sh (admin-4a): Test for above.
+ (Original patch submitted by Mark D. Baushke <mdb@cvshome.org>).
+
+2003-02-14 Larry Jones <lawrence.jones@eds.com>
+
+ * log.c (log_expand_revlist): Fix crashes in error cases.
+ (Reported by Bart Santy <Bart.Santy@switch.be>.)
+ * sanity.sh (log): New tests for above.
+
+2003-02-14 Derek Price <derek@ximbiot.com>
+
+ * rcs.h (RCSNode): Add a field for the original path to print with
+ error messages.
+ * rcs.c (RCS_parsercsfile_i): Keep track of the original path for error
+ messages.
+ (freercsnode): Free the origpath.
+
+2003-02-14 Derek Price <derek@ximbiot.com>
+
+ * watch.c (watch_usage): Make the repeatability of -a part of the
+ usage spec.
+
+2003-02-14 Derek Price <derek@ximbiot.com>
+
+ * watch.c (watch_usage): Mention default for -a. Mention multiple
+ invocations of -a. Mention -R as default. Use required () rather than
+ optional [] around watch subcommand list in invocation spec. Use
+ `path' instead of `file'. Put variable <> around `action' and `path'.
+
+2003-02-12 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Update copyright message to 2003.
+
+2003-02-08 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_checkout): Supply the full function name in the TRACE
+ output.
+ * update.c (checkout_file, join_file): Supply tag properly to
+ RCS_checkout more often.
+ (patch_file): Ditto. Fill out comments.
+ * sanity.sh (keyword, keywordname): Some changes to accomodate the fact
+ that the above changes cause patches generated by patch_file to fail
+ occassionally.
+
+2003-02-07 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (*): Don't keep running after a test when --keep has been
+ supplied. That was kind of silly, wasn't it?
+
+2003-02-07 Derek Price <derek@ximbiot.com>
+
+ * rcscmds.c (RCS_merge): Add a FIXME.
+
+2003-02-07 Derek Price <derek@ximbiot.com>
+
+ * commit.c (checkaddfile): Do not lose the vendor branch when
+ adding files to a new branch. Avoids extranious conflicts for
+ future vendor imports. This was found and fixed in FreeBSD cvs.
+ See http://www.freebsd.org/cgi/query-pr.cgi?pr=4033 for details.
+ * sanity.sh (branch-after-import): New test.
+ (Thanks to Mark D Baushke <mdb@cvshome.org> for forwarding the
+ patch and writing the test cases!)
+
+ * sanity.sh (branch-after-import): Misc portablility and standard
+ changes.
+
+2003-02-07 Derek Price <derek@ximbiot.com>
+
+ * add.c: Exercise the pet peeve Karl Fogel, I think, infected me with
+ about using the word invalid rather than illegal and reserving illegal
+ for use when actually discussing laws and governmentally enforced
+ restrictions:
+ s/illegal/invalid/g;s/legality/validity/g;s/legal/valid/g;
+ * admin.c: Ditto.
+ * cvs.h: Ditto.
+ * expand_path.c: Ditto.
+ * log.c: Ditto.
+ * modules.c: Ditto.
+ * rcs.c: Ditto.
+ * rcs.h: Ditto.
+ * repos.c: Ditto.
+ * root.c: Ditto.
+ * sanity.sh: Ditto.
+ * scramble.c: Ditto.
+ * server.c: Ditto.
+ * subr.c: Ditto.
+
+2003-02-06 Derek Price <derek@ximbiot.com>
+
+ * rcs.c (RCS_getdatebranch): Update header comment to reflect the state
+ of the docs and the code's operation.
+
+2003-02-06 Derek Price <derek@ximbiot.com>
+
+ * client.c: Use the complete path to the CVSADM_TEMPLATE file in
+ error messages. Remove related FIXME.
+
+2003-02-04 Derek Price <derek@ximbiot.com>
+
+ * status.c (status_fileproc): Add a FIXME comment.
+
+2003-02-04 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (conflicts2- c. 142d): New test for double add and two
+ attempted commits of files with the same name. Fill out some comments
+ and change one FIXME to a FIXCVS THEN FIXME.
+
+2003-02-03 Derek Price <derek@ximbiot.com>
+
+ * client.c (start_Server): Send multiple trace options when
+ necessary.
+ * server.c (server): Update trace option processing to accept multiple
+ -t arguments.
+ * *: Use new TRACE macro.
+
+2003-02-02 Larry Jones <lawrence.jones@eds.com>
+
+ * error.c: Update to match error.h.
+
+ * cvs.h (cvs_trace): Add attribute for GNU printf format checking.
+ * error.h: Use same check for prototypes as cvs.h. Use PROTO
+ macro rather than #ifdef for error and error_exit.
+
+2003-02-01 Larry Jones <lawrence.jones@eds.com>
+
+ * buffer.c (stdio_buffer_shutdown): Handle EINTR from waitpid.
+ (Patch from Johannes Grødem <johs+n@ifi.uio.no>.)
+
+2003-02-01 Derek Price <derek@ximbiot.com>
+
+ * lock.c: Remove extra line feed on TRACE output.
+
+2003-01-31 Derek Price <derek@ximbiot.com>
+
+ * cvs.h: Move header includes in from...
+ * error.c: ...here. Remove checks for definition of vprintf().
+ Since our error() function was making assumptions about the definition
+ of VA_START, we must not have been compiling on platforms without
+ vprintf for quite awhile and I've heard no complaints.
+ (fperrmsg): Assume vprintf().
+ * subr.c (cvs_trace): Don't assume ANSI C function declarations.
+
+2003-01-31 Derek Price <derek@ximbiot.com>
+
+ * main.c (main): Allow multiple -t options.
+ (opt_usage): Correct usage.
+ * cvs.h (TRACE): New macro.
+ * subr.c (cvs_trace): New function.
+ (Thanks to the team at the CVSNT project.)
+
+ * lock.c (*): Use new TRACE macro.
+
+2003-01-31 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (keywordname): Change a "FIXME" comment to "FIXCVS".
+
+2003-01-30 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (keywordname): New test.
+
+2003-01-23 Larry Jones <lawrence.jones@eds.com>
+
+ * diff.c (diff_fileproc): Restructure code to simplify and eliminate
+ redundant tests.
+
+ * server.c (do_cvs_command): Use WCOREDUMP macro rather than hard
+ coding test for core file.
+
+2003-01-21 Larry Jones <lawrence.jones@eds.com>
+
+ * root.c (method_name): Redefine as a 2D array.
+ * root.h (method_name): Ditto.
+
+2003-01-21 Jim Meyering <jim@meyering.net>
+
+ * add.c (add): Rename local-shadowing `i' to `j'.
+
+ * root.c (method_names): Declare to be a const array of const strings.
+ (Name_Root): Save errno so it doesn't get clobbered
+ by the intervening error call.
+ Use getline's return value, mainly to save a call to strrchr.
+
+2003-01-20 Larry Jones <lawrence.jones@eds.com>
+
+ * myndbm.c (O_ACCMODE): Parenthesize the replacement string so that
+ it parses correctly.
+ (Reported by Andres Bertens <abertens@entelchile.net>.)
+
+2003-01-15 Karl Fogel <kfogel@collab.net>
+
+ * server.c (dirswitch): Don't free dir_name until right before
+ allocating it again. This removes a potential double-free
+ problem, whereby this function could free dir_name and then
+ immediately return due to invalid directory syntax (without ever
+ reassigning dir_name), then reenter and free dir_name again.
+
+ Thanks to Stefan Esser <s.esser@e-matters.de> for the fix.
+
+2003-01-08 Larry Jones <lawrence.jones@eds.com>
+
+ * client.c (update_entries): Only "0" is a special version number;
+ other numbers starting with 0 (like 0.1) are normal version numbers.
+ * commit.c (find_fileproc): Ditto. Also reorganize the code to
+ simplify the conditions.
+ (Reported by Michele Zamparelli <michele.zamparelli@eso.org>.)
+
+2003-01-02 Larry Jones <lawrence.jones@eds.com>
+
+ * rcs.c (getdelta): Use RCSDEAD rather than literal "dead".
+
+2002-12-27 Derek Price <derek@ximbiot.com>
+
+ * admin.c: s/LOCK_(NONE|WRITE|READ)/CVS_$&/g; since the definition of
+ LOCK_WRITE clashes with a definition in objidl.h on Windoze platforms.
+ * annotate.c: Ditto.
+ * client.c: Ditto.
+ * commit.c: Ditto.
+ * cvs.h: Ditto.
+ * diff.c: Ditto.
+ * edit.c: Ditto.
+ * lock.c: Ditto.
+ * log.c: Ditto.
+ * patch.c: Ditto.
+ * recurse.c: Ditto.
+ * remove.c: Ditto.
+ * status.c: Ditto.
+ * tag.c: Ditto.
+ * update.c: Ditto.
+ * watch.c: Ditto.
+ * myndbm.c: Ditto & define O_ACCMODE when it isn't defined, as under
+ Windoze.
+ (Thanks to Stephane Rouleau <s.rouleau@videotron.ca>,
+ Cristopher Seawood <cls@seawood.org>, and
+ Frederico Costa <frederico.costa@tiscali.no> for all their hints,
+ tips, and patches for this problem.)
+
+2002-12-20 Derek Price <derek@ximbiot.com>
+
+ * client.c (send_a_repository): Suppress a warning under Windoze.
+
+2002-12-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Remove reference to options.h.
+ * cvs.h: Ditto.
+ * options.h: Remove this obsolete file.
+ * sanity.sh: Remove comment about external diffs causing tests to fail
+ since CVS hasn't used external diffs in years.
+
+ * Makefile.in: Regenerated.
+
+2002-12-16 Derek Price <derek@ximbiot.com>
+
+ * admin.c: Disable cvsadmin group checking on the client.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2002-12-06 Derek Price <derek@ximbiot.com>
+
+ * buffer.c: Replace calls to malloc with calls to xmalloc and calls to
+ realloc with calls to xrealloc.
+ * parseinfo.c: Ditto.
+ * root.c: Ditto.
+ * server.c: Ditto.
+ * zlib.c: Ditto.
+ * scramble.c: Change some comments to refer to xmalloc rather than
+ malloc.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2002-12-04 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove CVS_ADMIN_GROUP.
+
+2002-12-02 Larry Jones <lawrence.jones@eds.com>
+
+ * commit.c (commit): Strip leading zeros from numeric revision
+ in addition to trailing dots.
+ (Reported by Peter Meszaros <pme@prolan.hu>.)
+
+2002-11-22 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh: Note that the tests run for a long time.
+
+ * checkout.c (safe_location): Use xstrdup, not strdup.
+ (Reported by Terrence Enger <tenger@iSeries-guru.com>.)
+
+2002-11-19 Larry Jones <lawrence.jones@eds.com>
+
+ * log.c (log_expand_revlist): Fix cross-branch correction code.
+
+ * sanity.sh: Set $LANG for systems that ignore $LC_ALL.
+ (rcs2-7): Change date offset from 100 months to 96 months to reduce
+ periodic problems with invalid dates.
+
+2002-11-12 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcslib-symlink): Use rm -f rather than a simple rm when
+ removing links because under some configurations of RH Linux 8.0 the
+ script pauses to ask for removal approval.
+
+2002-11-08 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (importc): Update the use of the touch command to be
+ compliant with POSIX 1003.1-2001, SUS2, and SUS3 now that GNU touch
+ supports this. If this breaks any test platforms we should test
+ the behavior of touch like we do for other tools.
+
+2002-11-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcs2-7): Notate with a wild untested hypothesis.
+
+2002-11-03 Derek Price <derek@ximbiot.com>
+
+ * sanity.sh (rcs2-7): Notate with three more failure dates.
+
+2002-10-25 Derek Price <derek@ximbiot.com>
+
+ * root.c: Change some calls to SYSTEM_CLEANUP() and then exit() to
+ more appropriate calls to error_exit().
+ * server.c: Ditto.
+ * tag.c: Ditto.
+
+2002-10-24 Derek Price <derek@ximbiot.com>
+
+ * buffer.c (stdio_buffer_shutdown): Remove the getc() call used to
+ detect spurious output from clients since getc() would sometimes
+ block and hang indefinately if the client kept the conection open but
+ sent no data. Bug reports state that this hapened frequently with
+ older clients connecting to 1.11.2 servers, especially when
+ compression is enabled.
+ (Original report from Mark D. Baushke <mdb@juniper.net>.
+ Original patch from Ralf S. Engelschall <rse@engelschall.com>
+ via Peter Wemm <peter@freebsd.org>.)
+
+2002-10-05 Larry Jones <lawrence.jones@eds.com>
+
+ * recurse.c (start_recursion, do_recursion): Allow write locking
+ in addition to read locking. Change all callers.
+ * cvs.h: Change prototype to match, add lock types.
+ * tag.c (rtag_proc, rtag_fileproc, tag_fileproc): Have start_recursion
+ use write locks rather than calling lock_dir_for_write to avoid deadly
+ embrace.
+
+2002-10-04 Larry Jones <lawrence.jones@eds.com>
+
+ * client.c (get_responses_and_close, connect_to_pserver): Set
+ to_server and from_server to NULL after freeing.
+ * main.c (main): Clear server_active when finished. Also neaten
+ up the SERVER_SUPPORT ifdef's.
+ * server.c (do_cvs_command): Set protocol_inbuf, stderrbuf, and
+ stdoutbuf to NULL after freeing.
+ (server_cleanup): Free buf_from_net and buf_to_set and set to NULL.
+ Also reset error_use_protocol.
+ (server): Don't SIG_register server_cleanup. main_cleanup (which
+ is already registered) outputs a fatal error which causes it to
+ be called; registering it directly results in it being called twice.
+ (cvs_output): Don't try to use buf_to_net or protocol if they're NULL.
+
+2002-10-03 Larry Jones <lawrence.jones@eds.com>
+
+ * lock.c (readers_exist): Ignore our own read lock, if any, to
+ allow upgrading an existing read lock to a write lock.
+ * tag.c (rtag_proc, rtag_fileproc, tag_fileproc): Rather than
+ locking the entire tree, have start_recursion establish read
+ locks and then upgrade the read lock to a write lock (so only
+ one directory is locked at a time).
+
+2002-09-27 Larry Jones <lawrence.jones@eds.com>
+
+ * add.c (add): Send "--" before file names.
+ * admin.c (admin): Ditto.
+ * annotate.c (annotate): Ditto.
+ * commit.c (commit): Ditto.
+ * diff.c (diff): Ditto.
+ * edit.c (watch_onoff, editors): Ditto.
+ * log.c (cvslog): Ditto.
+ * remove.c (cvsremove): Ditto.
+ * status.c (cvsstatus): Ditto.
+ * tag.c (cvstag): Ditto.
+ * update.c (update): Ditto.
+ * watch.c (watch_addremove, watchers): Ditto.
+
+ * sanity.sh (client-9): Update to match.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove prototype of STDC exit() function. If this breaks
+ a build, this should be detected in configure.in somehow rather than
+ restoring the line to this file.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Move definition of AUTH_CLIENT_SUPPORT into configure.in.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Move definition of FORCE_USE_EDITOR into configure.in.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Move definition of UMASK_DFLT into configure.in.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Larry Jones <lawrence.jones@eds.com>
+
+ * filesubr.c, history.c, import.c, rcs.c, update.c: Use
+ HAVE_STRUCT_STAT_ST_BLKSIZE and HAVE_STRUCT_STAT_ST_RDEV instead of
+ the obsolete HAVE_ST_BLKSIZE and HAVE_ST_RDEV.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Move definition of TMPDIR_DFLT into configure.in.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Move defininition of EDITOR_DFLT into configure.in.
+
+ * Makefile.in: Regenerated.
+
+2002-09-23 Jim Meyering <meyering@lucent.com>
+
+ If `cvs -d REPO commit ...' was used to override CVS/Root,
+ then modified files in the directory from which cvs is invoked
+ would not be committed.
+ * client.c (arg_should_not_be_sent_to_server): The above would happen
+ because this function would throw out a file name when CVS/Root
+ did not match the current server. Fix by allowing the command-line-
+ specified repository to take precedence over the value returned
+ by Name_Root. Patch by Simon Walton <simonw@lucent.com>.
+ * sanity.sh (commit-d): New tests for the above.
+ Patch by Simon Walton <simonw@lucent.com>.
+
+2002-09-20 Derek Price <derek@ximbiot.com>
+
+ * options.h: Move definition of SERVER_FLOWCONTROL, SERVER_HI_WATER,
+ and SERVER_LO_WATER into configure.in.
+
+2002-09-20 Derek Price <derek@ximbiot.com>
+
+ * options.h: Move definition of PATCH_PROGRAM to configure.in.
+
+2002-09-18 Larry Jones <lawrence.jones@eds.com>
+
+ * client.c (call_in_directory): Don't create admin directory when
+ exporting into an existing directory.
+ (Reported by Jens Engel <Jens.Engel@marconi.com>.)
+ * sanity.sh (basic2): New tests for above.
+
+2002-09-16 Jim Meyering <meyering@lucent.com>
+
+ * server.c (do_cvs_command): Move declarations of locals, timeout and
+ timeout_ptr, `up', out of enclosing `#ifdef SERVER_FLOWCONTROL' block.
+ Otherwise, this file would not compile with SERVER_FLOWCONTROL
+ turned off. Patch by Ed Santiago <esm@ascend.com>.
+
+2002-09-15 Larry Jones <lawrence.jones@eds.com>
+
+ * myndbm.c (mydbm_open): Open the file read/write rather than read-
+ only if that's what the user asked for to ensure that the later open
+ for write will succeed.
+ (Patch submitted by Josh Lehan <cvs@krellan.com>.)
+
+2002-08-28 Larry Jones <lawrence.jones@eds.com>
+
+ * logmsg.c (do_editor): Fix bug which prevented reusing log messages.
+ (Reported by Eric Siegerman <erics@telepres.com>.)
+
+2002-08-16 Derek Price <derek@ximbiot.com>
+
+ * create_adm.c (Create_Admin): Assume RELATIVE_REPOS is set.
+ * server.c (outside_root): Add comment.
+ * options.h: Remove RELATIVE_REPOS & CVS_BADROOT.
+ * sanity.sh: Remove a lot of !RELATIVE_REPOS cruft from tests.
+
+2002-08-14 Derek Price <oberon@umich.edu>
+
+ * server.c (server): Dispose of the correct pointer. Tidy comment.
+
+2002-08-13 Derek Price <oberon@umich.edu>
+
+ * client.c (get_cvs_port_number): Fix typo in comment. Add comments.
+ * server.c (server): Fix a FIXME. Remove an errant "const" directive.
+ Remove some redundant memory allocation and error handling code.
+
+2002-08-08 Derek Price <oberon@umich.edu>
+
+ * import.c (import): Surrounded `server_active' with
+ #ifdef SERVER_SUPPORT/#endif.
+ * commit.c (commit_fileproc, commit_direntproc): Likewise.
+ (Patch from John Tytgat <John.Tytgat@aaug.net>.)
+
+2002-07-31 Derek Price <oberon@umich.edu>
+
+ * filesubr.c: Add a line so VIM can determine tab stops and shift widths.
+ * root.c: Ditto.
+ * (parse_cvsroot): Add comments and tidy slightly.
+
+2002-07-31 Derek Price <oberon@umich.edu>
+
+ * sanity.sh: Add another date to the comment about rcs2-7 failing.
+
+2002-07-26 Jim Meyering <meyering@lucent.com>
+
+ * commit.c (find_fileproc): When committing in client mode,
+ arrange to fail if a `cvs add'ed file no longer exists in the
+ working directory.
+ * sanity.sh (commit-add-missing): New test for above.
+
+2002-07-25 Larry Jones <lawrence.jones@eds.com>
+
+ * sanity.sh: Set $TMPDIR if it's not already set and use it rather
+ than /tmp for the expected server temp directory path.
+
+2002-07-09 Larry Jones <lawrence.jones@eds.com>
+
+ * vers_ts.c (time_stamp_server, time_stamp): Eliminate unneeded
+ struct_tm copying.
+
+ * lock.c (lock_wait, lock_obtained): Display time in UTC if possible
+ to reduce confusion in client/server mode.
+ (Original patch from Eduardo Perez Ureta <eperez@it.uc3m.es>.)
+
+2002-06-26 Larry Jones <lawrence.jones@eds.com>
+
+ * tag.c (check_fileproc): When checking up-to-date, T_REMOVE_ENTRY
+ is also a valid status.
+ (Reported by David Everly <David.Everly@wcom.com>.)
+ * sanity.sh (tagc): New tests for above.
+
+2002-06-18 Larry Jones <lawrence.jones@eds.com>
+
+ * update.c (patch_file): Don't patch if diff bigger than file.
+ Don't bother adjusting the permission on the diff output if
+ we're not going to use it.
+
+
+2002-06-18 Derek Price <oberon@umich.edu>
+
+ * server.c: Handle HPUX password expiration fields in the passwd
+ string in case we are set up on a server with NIS passwords served
+ from HPUX.
+ (Original patch from John Cavanaugh <john_cavanaugh@agilent.com>.)
+
+2002-06-17 Larry Jones <lawrence.jones@eds.com>
+ and Jonathan Kamens <jik@kamens.brookline.ma.us>
+
+ * commit.c (commit_fileproc, commit_direntproc): Don't try to call
+ an editor to get the log message if running as a server. Instead,
+ just use an empty log message.
+ * import.c (import): Ditto.
+
+ * import.c (import): In client mode, always send a message to the
+ server, even if it's empty (this parallels a change made by Larry
+ Jones to commit.c on May 7).
+
+2002-05-31 Larry Jones <lawrence.jones@eds.com>
+
+ * rcs.c: Conditionally define MAP_FAILED for old systems that don't
+ have it in <mman.h>.
+ (Reported by jeremy brand <jeremy@earth.care2.com>.)
+
+2002-05-24 Larry Jones <lawrence.jones@eds.com>
+
+ * rcscmds.c (diff_exec): Add a -- before the first file name just
+ in case it looks like an option.
+ (Reported by Zooko <zooko@zooko.com>.)
+
+ * rcscmds.c (diff_execv): Remove -- same as diff_exec. Change
+ only caller.
+ * cvs.h: Ditto.
+
+2002-05-23 Larry Jones <lawrence.jones@eds.com>
+
+ * cvs.h (strcat_filename_onto_homedir): Make arguments const.
+ * filesubr.c (strcat_filename_onto_homedir): Make arguments const,
+ move more code here from callers, change all callers.
+
+2002-05-22 Derek Price <oberon@umich.edu>
+
+ * cvs.h: Add prototype for this...
+ * filesubr.c (strcat_filename_onto_homedir): new function.
+ * login.c (): Use new function.
+
+ * cvsrc.c (read_cvsrc): Use new function due to problems on VMS.
+ * ignore.c (ign_setup): Ditto.
+ * wrapper.c (wrap_setup): Ditto.
+ (Original patch from Karsten Spang <ksp@dannet.dk>.)
+
+2002-05-21 Larry Jones <lawrence.jones@eds.com>
+
+ * rcs.c (rcsbuf_getkey): Correct off-by-one error in ptr assertion
+ and add a similar assertion for ptrend.
+ (Reported by Rebecca Young <raygirl@cvshome.org>.)
+ (rcsbuf_fill): Remove redundant code.
+
+2002-05-20 Derek Price <oberon@umich.edu>
+
+ * buffer.h: New prototype for...
+ * buffer.c (stdio_buffer_get_file): this new function to abstract
+ access to a buffer's file descriptor.
+ * client.c (auth_server): Use the new function.
+ (Original patch from Jonathan Kamens <jik@kamens.brookline.ma.us>.)
+
+2002-05-20 Derek Price <oberon@umich.edu>
+
+ * main.c (main): Add 2002 to the copyright years output with the
+ version string.
+
+2002-05-15 Larry Jones <lawrence.jones@eds.com>
+
+ * log.c (log_parse_list): Fix off-by-one error which caused
+ incorrect handling of 'cvs log -wuser1,user2 foo.c' command.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>,
+ reported by Alex Morozov <morozov@novosoft.ru>.)
+
+2002-05-09 Larry Jones <lawrence.jones@eds.com>
+
+ * login.c (password_entry_operation): Get cvsroot_canonical before
+ trying to read the user's password file so we have it even if the
+ file doesn't exist.
+ (Reported by Sarah Thompson <sthompson@fsl.noaa.gov>.)
+
+2002-05-08 Derek Price <oberon@umich.edu>
+
+ * Makefile.am (cvs_SOURCES): Add options.h explicitly - since we
+ stopped generating it dynamically, Automake stopped noticing it and
+ including it in dists. See TODO item #214 for notes.
+
+2002-05-08 Derek Price <oberon@umich.edu>
+
+ * cvs.h: Use the HAVE_CONFIG_H define.
+
+2002-05-07 Larry Jones <lawrence.jones@eds.com>
+
+ * filesubr.c (isaccessible): Set errno before returning failure
+ in the SETXID_SUPPORT code.
+
+ * logmsg (do_verify): Avoid even more work if there's no verifymsg
+ script to run.
+
+ * logmsg: Use fputs/putc rather than fprintf where appropriate.
+ (do_verify): Run the verifymsg script even if there's no log
+ message. (Reported by Andy Baker <Andy.Baker2@t-mobile.co.uk>.)
+ Don't reread the log message unless a verifymsg script was run.
+
+ * commit.c (commit): Always send -m to the server, even if there's
+ no message.
+
+ * create_adm.c (Create_Admin): Add dotemplate parameter to trace.
+ Remove unreachable code.
+
+2002-05-03 Larry Jones <lawrence.jones@eds.com>
+
+ * server.c (serve_watch_on, serve_watch_off, serve_watch_add,
+ serve_watch_remove): Just pass "watch" as the command name
+ to do_cvs_command to avoid unknown command errors.
+ (Reported by Gary Hennigan <gary@ieee.org>.)
+
+ * rcs.c (RCS_checkin): Fix bad call to error () in buggy
+ PRESERVE_PERMISSIONS code.
+ (rcs_internal_unlockfile): Include current value of errno in error
+ message even though it may well be irrelevant (it's still better
+ than nothing).
+
+2002-05-02 Derek Price <oberon@umich.edu>
+
+ * .cvsignore: Remove lines for files obsoleted by new autotools.
+
+2002-05-02 Derek Price <oberon@umich.edu>
+
+ * stamp-h2.in: Remove this uneeded file.
+
+2002-05-01 Derek Price <oberon@umich.edu>
+
+ * options.h.in: Move to...
+ * options.h: here.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * version.h.in: Remove this file.
+ * version.h: Ditto.
+
+ * Makefile.am: Remove references to version.h.
+ * cvs.h: Use <> rather than "" around the config.h #include. I didn't
+ quite bother to understand why, but autoconf recommends it.
+ * cvsbug.in: Use PACKAGE_BUGREPORT defined by configure for the bug
+ report email address.
+ * version.c (version): Use PACKAGE_STRING defined in config.h instead
+ of the version_string that used to be defined in version.h.
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2002-04-28 Derek Price <oberon@umich.edu>
+
+ * cvs.h: Use `"'s around includes when we mean a local file.
+
+2002-04-28 Derek Price <oberon@umich.edu>
+
+ * cvs.h: #define new names for functions and variables when they
+ might conflict with system definitions (namely on Mac OS X 10.1 with
+ the most recent dev packages - This should be removable after the Mac
+ dev packages are fixed.).
+
+2002-04-26 Larry Jones <larry.jones@sdrc.com>
+
+ * logmsg.c (do_editor): Fix assertion when CLIENT_SUPPORT not defined.
+ (Reported by Matthias Andree <matthias.andree@stud.uni-dortmund.de>.)
+
+2002-04-19 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (log_expand_revlist): First cut at code to allow logging
+ between a revision and *any* ancestor, not just one explicitly on
+ the same branch (e.g., from 1.1 to 4.1.2.3.6.1).
+
+ * subr.c (gca): Simplify and optimize.
+
+2002-04-19 Jim Meyering <meyering@lucent.com>
+ and Ed Santiago <easm@lucent.com>
+
+ * classify.c (Classify_File): Fix it so that `cvs update -p -r...'
+ works, even under some slightly unusual (though perfectly legitimate)
+ circumstances.
+ * sanity.sh (update-p): New tests for this.
+
+2002-04-18 Derek Price <oberon@umich.edu>
+
+ * sanity.sh: Move test for regex metacharacters in username until
+ after we're sure we found the version of expr that we're going to use.
+
+2002-04-18 Larry Jones <larry.jones@sdrc.com>
+
+ * admin.c (admin_fileproc): Allow admin to be used on RCS files with
+ no local version (e.g., removed files) like most other subcommands.
+
+ * wrapper.c (wrap_add): Update URL of -t/-f wrapper discussion.
+
+2002-04-18 Derek Price <oberon@umich.edu>
+
+ * version.h: Regenerated for 1.11.2.1 version update.
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * version.h: Regenerated for 1.11.2.
+
+2002-04-03 Derek Price <oberon@umich.edu>
+
+ * stamp-h2.in: Regenerate with recent version of Autoconf.
+
+2002-04-03 Derek Price <oberon@umich.edu>
+
+ * sanity.sh (TR): Send the stderr of one of the tool setup (tr) tests
+ to /dev/null to avoid spurious output on some operating systems
+ (notably Mac OS X).
+
+2002-03-22 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (rcslib): Correct new tests to use ${testcvs} instead
+ of cvs.
+
+2002-03-21 Derek Price <oberon@umich.edu>
+
+ * vers_ts.c (time_stamp): Return the timestamp for the newer of the
+ link and the link's source when the file is a link.
+ (Patch from RedHat cvs-1.11.1p1-7 SRPM.)
+
+ * sanity.sh (rcslib): Test for same.
+
+2002-03-17 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (cvslog, log_fileproc): Add -S option to suppress head or
+ file name if no revisions selected.
+ * sanity.sh (log): New tests for above.
+
+2002-03-13 Derek Price <oberon@umich.edu>
+
+ * main.c (usg): Correct a spelling mistake in a comment.
+ (Thanks to Matt Kraai <kraai@alumni.cmu.edu>.)
+
+2002-03-09 Larry Jones <larry.jones@sdrc.com>
+
+ * import.c (import): Change the suggested merge message to use
+ rev tags instead of the branch tag with a date.
+ * sanity.sh (import, importb): Change to match.
+
+ * remove.c (remove_fileproc): Disallow removing files with sticky
+ dates for the same reason we already disallow sticky numeric tags.
+ * sanity.sh (sticky): New test for above.
+
+2002-02-27 Larry Jones <larry.jones@sdrc.com>
+
+ * diff.c (diff_fileproc): Treat dead revisions as nonexistent.
+
+2002-02-26 Larry Jones <larry.jones@sdrc.com>
+
+ * diff.c (diff): Remove -V and --paginate options: they aren't valid.
+ (diff_usage): Document all the diff options.
+
+2002-02-13 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_gettag): Do not interpret an empty tag as HEAD (nothing
+ else does and I don't see any documentation that says it should).
+ (translate_symtag): Break out of loop at end of symbols to prevent
+ looping forever when tag is "".
+ (Reported by Alain ENOUT <aln00@udcast.com>
+ via Eric Gillespie <epg@pretzelnet.org>.)
+
+2002-02-11 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (server_cleanup): Set buf_to_net back to blocking mode
+ and flush it (in case there are any error messages pending) before
+ shutting down buf_from_net and again right before shutting it down.
+
+2002-02-08 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (lookup_command_attribute): Throw a fatal error if the
+ command is not found.
+ * server.c (server_tag): Use the correct command name.
+
+2002-01-30 Larry Jones <larry.jones@sdrc.com>
+
+ * error.h (error_exit): Remove unintended prototype.
+
+ * server.c (serve_root): Remove check for impossible condition.
+ (serve_init): Save and restore current_parsed_root.
+
+2002-01-29 Larry Jones <larry.jones@sdrc.com>
+
+ * error.h (error_exit): Declare __noreturn__ to avoid spurious
+ warnings.
+
+ * server.c (serve_root): If the specified root doesn't match the
+ pserver root, return before changing current_parsed_root to prevent
+ subsequent commands from accessing an unchecked root directory.
+ (server_init): Check specified root against the pserver root and
+ complain if they don't match. Also, if there are pending errors,
+ print them and return before changing current_parsed_root to prevent
+ subsequent commands from accessing an unchecked root directory.
+ * sanity.sh (pserver): New tests for above.
+
+2002-01-10 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (log_version_requested): Change :: in revision spec to be
+ exclusive just on the low end (so -r tag1::tag2 gives revisions
+ after tag1 but up to and including tag2), which is much more useful
+ than the previous (exclusive at both ends) behavior.
+ (log_usage): Update to match.
+ * sanity.sh (log): Update to match.
+
+2002-01-02 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (LOG_DAEMON): Define if needed.
+ (Patch from John David Anglin <dave@hiauly1.hia.nrc.ca>.)
+
+ * server.c (pserver_authenticate_connection): Add a specific error
+ message for EOF at protocol start and syslog if available.
+ * sanity.sh (pserver-bufinit): Update to match.
+
+2001-12-10 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (log_usage): Note that -r and -d take lists, not just a
+ single specification.
+ (log_expand_revlist): Don't dereference null pointers when one end
+ of a revision range is a non-existent tag.
+
+2001-12-03 Larry Jones <larry.jones@sdrc.com>
+
+ * annotate.c (annotate, annotate_fileproc): Don't annotate binary
+ files unless new -F option given.
+ * sanity.sh (basica, ann, ann-id, rcs, keywordlog, tagdate): Update
+ to match.
+
+2001-11-30 Larry Jones <larry.jones@sdrc.com>
+
+ * admin.c (admin): Allow unrestricted usage of -q in addition to -k.
+
+2001-10-25 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (log_expand_revlist): Make erroneous or inconsistent revision
+ specs select no revisions rather than all revisions.
+
+2001-10-23 Larry Jones <larry.jones@sdrc.com>
+
+ * import.c (add_rcs_file): Don't put an expand entry into the file
+ for the default expansion mode (kv).
+ * wrapper.c (wrap_send, wrap_unparse_rcs_options): Process entries
+ with default expansion mode since they may be needed to avoid matching
+ a more general entry later.
+ (wrap_add): Set rcsOption to NULL for default (kv).
+ (wrap_add_entry): Use structure assignment to copy entries rather
+ that copying members by hand.
+ * sanity.sh (binwrap3): Revise to test wrapper entries that don't
+ specify any non-default options but just prevent matching later,
+ more general entries.
+
+2001-10-02 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_fully_parse): Add revision number to more error messages.
+
+2001-09-27 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_fully_parse, RCS_getdeltatext): Add the missing revision
+ number to the "mismatch" error message.
+
+ * sanity.sh (multiroot2-9a): Update to match changes to lock.c.
+
+2001-09-26 Larry Jones <larry.jones@sdrc.com>
+
+ * lock.c (Lock_Cleanup, Reader_Lock, write_lock): Add trace messages.
+
+2001-09-24 Derek Price <dprice@collab.net>
+
+ * find_names.c (add_entries_proc): Leave closure specified as such in the
+ function definition for clarity.
+
+ * find_names.c (Find_Names): Use 'closure' feature of walklist()
+ to eliminate the static variable.
+ (add_entries_proc): Expect closure to be the file list.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2001-09-19 Derek Price <dprice@collab.net>
+
+ * rcs.c (rcsbuf_valpolish_internal): Restore one of the
+ "if ( ... ) abort();" sequences since it seems to check the validity of
+ the RCS file rather than for a programming error. Also added a FIXME
+ comment to the effect that we should explain the RCS file error to the
+ user as such if it is such.
+ (Thanks to Larry Jones <scjones@sdrc.com>.)
+
+2001-09-19 Derek Price <dprice@collab.net>
+
+ * rcs.c (rcsbuf_getkey, rcsbuf_valpolish_internal): Replace some code
+ of the form "if ( ... ) abort();" with equivalent calls to assert().
+
+2001-09-17 Derek Price <dprice@collab.net>
+
+ * myndbm.c (mydbm_load_file): Fix buffer overflow error and make error
+ messages more informative.
+ * sanity.sh (modules6): New test.
+ (Original report from Taska <taska@collab.net> and others.)
+
+2001-09-14 Derek Price <dprice@collab.net>
+
+ * logmsg.c (do_verify): Dispose memory when finished with it.
+
+2001-09-07 Larry Jones <larry.jones@sdrc.com>
+
+ * mkmodules.c (notify_contents): In the example, move the %s to
+ the end since many, if not most, versions of mail insist on
+ options coming before addresses.
+
+2001-09-06 Derek Price <dprice@collab.net>
+
+ * login.c (login): Deal with NULL return value from getpass.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+ * stamp-h2.in: Ditto.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * main.c (main): Fix empty CVSROOT message to specify `valid' instead
+ of `legal'.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * server.c (pserver_authenticate_connection): Back out changes from the
+ 30th and...
+ * getline.c (getstr): init the buffer instead.
+
+2001-08-31 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Backed out accidental commit from yesterday.
+
+2001-08-30 Derek Price <dprice@collab.net>
+
+ * server.c (pserver_authenticate_connection): Don't print from the
+ NULL pointer in the error message string in the case where the client
+ didn't send any data.
+ * sanity.sh (pserver): Test for this case.
+ (Report from Mark Welch <mark@collab.net>).
+
+2001-08-24 Derek Price <dprice@collab.net>
+
+ * logmsg.c (do_editor): Add comment and assertion.
+ * import.c (import): Don't call do_editor with a repository argument
+ in client mode.
+ (Report and original patch from darkness <darkness@invado.com>.)
+
+2001-08-24 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (log_expand_revlist): Arrange for nil revision specs to
+ select nothing instead of everything.
+ * sanity.sh (log): New tests for above.
+
+2001-08-24 Derek Price <dprice@collab.net>
+
+ * parseinfo.c (Parse_Info): Change the function name in the trace
+ and add the client/server string.
+
+2001-08-24 Derek Price <dprice@collab.net>
+
+ * Implement RereadLogAfterVerify CVSROOT/config option to control
+ FreeBSD read-write of log messages in the verification script.
+ * logmsg.c: RereadLogAfterVerify defaults to LOGMSG_REREAD_NEVER
+ to preserve the status quo.
+ * parseinfo.c (parse_config): Add parsing for RereadLogAfterVerify
+ option. Possible values are: no | never | yes | always | stat
+ * cvs.h: Add extern for RereadLogAfterVerify and new value macros
+ LOGMSG_REREAD_NEVER, LOGMSG_REREAD_ALWAYS, LOGMSG_REREAD_STAT for
+ its values.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+ * Apply changes from FreeBSD cvs sources to implement a read-write
+ user-defined verification script.
+ * logmsg.c (do_verify): Update do_verify to expect a pointer
+ to the saved message. The log file passed to the verifymsg_script
+ should be re-read after the user-defined verification script has
+ been run. The user-defined verification script is allowed to
+ modify the message. This allows the script to add extra
+ information to the log message or to remove template lines that
+ are not needed.
+ * cvs.h: Update prototype for do_verify prototype to expect a
+ pointer to the saved_message.
+ * commit.c (commit, commit_fileproc, commit_direntproc): Update
+ calls to do_verify as the saved_message arg is now read-write.
+ * import.c (import): Update calls to do_verify as the
+ saved_message arg is now read-write.
+ * sanity.sh (info-v4-[12]): Rename the old info-v4 test to info-v5
+ and add a new info-v4 test case have the verification script
+ modify the log message to test the above changes.
+ (Patch from Mark D. Baushke <mdb@cvshome.org>.)
+
+ * logmsg.c: Change RereadLogAfterVerify default to always.
+ (do_verify): Reformat and make minor fixes to Mark's patch.
+ * mkmodules.c (config_constants): Add comment about
+ RereadLogAfterVerify.
+ * sanity.sh (info-rereadlog): Rename the tests from Mark's patch and
+ reformat them a bit.
+
+2001-08-23 Derek Price <dprice@collab.net>
+
+ * sanity.sh (info): Demonstrate that the verifymsg scripts can
+ sometimes, but not always, retreive information on which directory is
+ being committed to.
+
+2001-08-22 Derek Price <dprice@collab.net>
+
+ * logmsg.c: Back out the last change - the repository which is passed
+ in is actually the directory and changes with each call to do_verify.
+ If a verifymsg script is using `pwd`, this could change the operation.
+ * cvs.h: Ditto.
+ * commit.c: Ditto.
+ * import.c: Ditto.
+
+2001-08-22 Derek Price <dprice@collab.net>
+
+ * logmsg.c (do_editor): Return reused_message.
+ (do_verify): Don't verify the same log message more than once.
+ * cvs.h: Update prototypes for do_verify and do_editor.
+ * commit.c (commit_fileproc, commit_direntproc): Use the new functionality.
+ * import.c (import): Ditto.
+
+2001-08-22 Derek Price <dprice@collab.net>
+
+ * logmsg.c (do_verify): Remove an unecessary "else" clause following an
+ exit and unindent the former contents.
+
+2001-08-22 Derek Price <dprice@collab.net>
+
+ * commit.c (commit): Don't call do_verify in client mode since we know
+ do_verify will just return anyhow.
+
+2001-08-20 Derek Price <dprice@collab.net>
+
+ * Makefile.am (cvs_SOURCES): Add version.c and version.h.
+ (BUILT_SOURCES): Add version.h.
+ (Maintainer Targets): Remove version.h.
+ * version.c: Remove @VERSION@ dependant bits.
+ * version.c.in: Removed.
+ * version.h.in: New file.
+ (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+ * Makefile.am: Various modifications to make Automake, make dist, and
+ windows targets work like they are supposed to.
+ * version.h: New (generated) file.
+
+ * Makefile.in: Regenerated.
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * client.c (socket_buffer_shutdown): Use recv instead of read and
+ return 0 on success.
+ (Patch from "Manfred Klug" <manklu@web.de>.)
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * buffer.c (stdio_buffer_shutdown): Assume the buffer is not a socket
+ when NO_SOCKET_TO_FD is defined.
+ * client.c (make_bufs_from_fds): Add is_sock argument and remove fstat
+ call and reference to S_ISSOCK since these functions aren't available
+ under Windows.
+ (connect_to_forked_server, connect_to_pserver, start_tcp_server,
+ start_server, start_rsh_server): Use new argument.
+ (Patch from "Manfred Klug" <manklu@web.de>.)
+
+ * buffer.c (stdio_buffer_shutdown): Various reformattings, fix bug
+ where rsh pipes weren't being closed.
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * sanity.sh (rmadd, rm-update-message, join-two-branch,
+ ignore-on-branch): Change a few references to `cvs' to `$PROG'.
+
+2001-08-07 Derek Price <dprice@collab.net>
+
+ * build_src.com: Add annotate.c/annotate.obj,verify, correct zlib name.
+ * patch.c: VMS time_t appears to be unsigned. Add a cast when testing
+ for (time_t)-1.
+ * subr.c: #else,#endif for no symlinks should be moved.
+ (Patch from Mike Marciniszyn <Mike.Marciniszyn@sanchez.com>.)
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-08-01 Derek Price <dprice@collab.net>
+
+ * diff.c (diff): Send long option for side-by-side diffs to the server
+ rather than '-y', for backwards compatibility with old servers.
+ (Original patch from Peter Mathiasson <peter@mathiasson.nu>.)
+
+2001-07-19 Larry Jones <larry.jones@sdrc.com>
+
+ * mkmodules.c (cvswrappers_contents): Remove -t/-f since they're
+ disabled in wrapper.c.
+
+ * checkout.c (checkout): Don't complain about checking out into the
+ repository when piping output.
+ (Reported by der Mouse <mouse@Rodents.Montreal.QC.CA>.)
+ * sanity.sh (checkout_repository): New tests for above.
+
+2001-07-10 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (importc-7): Now works correctly in local mode.
+
+ * commit.c (commit_dirleaveproc): We're still in the directory when
+ this is called, so the first argument to Name_Repository needs to
+ be NULL, not dir.
+ * sanity.sh (rmadd): New tests for above.
+
+ * commit.c (commit): Reword error messages for committing as root.
+
+2001-07-08 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_checkout): Correct scanf format to allow for trailing
+ NUL terminator.
+ * update.c (special_file_mismatch): Ditto.
+ (Reported by Pekka Savola <pekkas@netcore.fi>.)
+
+2001-07-05 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c, root.c: Fix -Wall warnings.
+
+ * buffer.c: #include socket header to declare shutdown().
+
+ * rcs.c (rcsbuf_open): Use getpagesize() instead of sysconf() for
+ portability.
+ (RCS_copydeltas, rcsbuf_fill): Fix -Wall warnings.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-07-03 Derek Price <dprice@collab.net>
+
+ * rcs.c (rcsbuf_open): Reduce memory consumption still further by not
+ mmapping the entire file when pos is specified.
+ (rcsbuf_cache_open): Add FIXME comment wrt read-only mmaps and rcsbuf
+ caching.
+
+2001-07-03 Derek Price <dprice@collab.net>
+
+ * rcs.c (rcsbuf_open): Use mmap when possible to reduce memory
+ consumption, especially with large (e.g. binary) files.
+ (rcsbuf_close): Call munmap.
+ (rcsbuf_getkey): Remove the buffer fill code when using mmap.
+ (rcsbuf_getrevnum): Ditto.
+ (rcsbuf_fill): Remove this function when using mmap.
+ (rcsbuf_cache_open): Mostly don't use this function with mmap.
+ (RCS_copydeltas): Don't depend on the file pointer with mmap.
+
+ * stamp-h2.in: Regenerated.
+
+2001-07-03 Derek Price <dprice@collab.net>
+
+ * update.c: Indent compiler directives.
+
+2001-07-02 Larry Jones <larry.jones@sdrc.com>
+
+ * import.c (update_rcs_file): Use -kb instead of -ko when comparing
+ binary files.
+ (Reported by Gyula Faller <gfaller@graphisoft.hu>.)
+
+2001-06-28 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (checkout): Explicitly initialize all the static options
+ so that multiple calls work right. Also fix potential memory leaks.
+ (Reported by Dr. Dieter Maurer <dieter@sz-sb.de>.)
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-06-28 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (checkout): Set history_name for export as well as
+ checkout.
+ (checkout_proc): Use it.
+
+ * checkout.c (safe_location): Add missing argument in error message.
+
+2001-06-26 Larry Jones <larry.jones@sdrc.com>
+
+ * recurse.c (start_recursion): Use strip_trailing_slashes instead
+ of doing it by hand.
+
+ * server.c (pserver_authenticate_connection): Don't clear out
+ descrambled_password until *after* it's (potentially) logged.
+ (Reported by Eric Hanchrow <offby1@blarg.net>.)
+
+2001-06-25 Larry Jones <larry.jones@sdrc.com>
+
+ * recurse.c (start_recursion): Deal with at least some of the cases
+ where trailing slashes cause confusion.
+ (Reported by Malcolm Fernandes <fernande@redback.com>.)
+ * sanity.sh (basica, basicb): Tweak existing tests to check this.
+
+2001-06-22 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (modules5): New tests with -d on command line.
+
+2001-06-21 Larry Jones <larry.jones@sdrc.com>
+
+ * modules.c (do_module): Use run_module_prog and server_active to
+ determine when to call server_prog instead of using server_expanding
+ so that we get the right paths in the replies as long as we take
+ mwhere into account in addition to where.
+ (Reported by Pascal Bourguignon <pjb@informatimago.com>.)
+ * server.c (server_prog): Use protocol pipe instead of buf_to_net.
+ * sanity.sh (modules5): Remove FIXCVS comment and update to match.
+ * server.c, server.h: Remove server_expanding since now unused.
+
+2001-06-21 Larry Jones <larry.jones@sdrc.com>
+ for Stephen Rasku <stephen@tgivan.com>
+
+ * admin.c: Corrected spelling mistakes in help.
+
+2001-06-20 Derek Price <dprice@collab.net>
+
+ * client.c (socket_buffer_shutdown): Fix untested typos.
+ (Reported by "Jerzy Kaczorowski" <jerzyk@wndtabs.com>.)
+
+ * buffer.c (stdio_buffer_shutdown): Put the call to SHUTDOWN_SERVER in
+ the correct place.
+
+2001-06-20 Derek Price <dprice@collab.net>
+
+ * logmsg.c (do_editor): Abort in the case that the file has only
+ comment lines.
+ (Original patch from Mark Valentine <mark@thuvia.demon.co.uk>.)
+
+ * logmsg.c (do_editor): Fix rare memory leak.
+ * sanity.sh (editor): Add tests for aborted log messages.
+
+2001-06-20 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (switch_to_user): Only set $CVS_USER if
+ AUTH_SERVER_SUPPORT is defined.
+ (Reported by Nalin Dahyabhai <nalin@blade.devel.redhat.com>.)
+
+2001-06-13 Derek Price <dprice@collab.net>
+
+ * client.c: Fix incorrect fixed-size buffer usage in
+ connect_to_gserver().
+ (Minor changes to a patch from Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2001-06-11 Derek Price <dprice@collab.net>
+
+ * main.c (main): Always print $CVSROOT when parse_cvsroot fails.
+ * root.c (parse_cvsroot): Tidy error messages and provide more
+ consistent behavior.
+ * sanity.sh (crerepos): Adapt to new error messages.
+ (Suggested by Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2001-06-08 Derek Price <dprice@collab.net>
+
+ * sanity.sh (tagf-28): Use $CVSROOT_DIRNAME.
+
+2001-06-07 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_unlock): Reverse kj's change of 1999-10-18: a bare -u
+ should never break locks, you have to specify a specific revision
+ to do that. Also add an informative message for a bare -u when
+ the user doesn't hold any locks.
+ * commit.c (unlockrcs): Make RCS_unlock quiet, like RCS_lock.
+ * sanity.sh (rmadd-24): Update to match.
+
+ * sanity.sh (crerepos-6a): Set CVS_RSH for ${testcvs}, not for
+ dotest_fail. Allow for "broken pipe" rather than "end of file".
+
+2001-06-07 Derek Price <dprice@collab.net>
+
+ * sanity.sh (tagf): Use $CVSROOT_DIRNAME rather than
+ /tmp/cvs-sanity/cvsroot.
+
+2001-06-06 Derek Price <dprice@collab.net>
+
+ (Reformatting, bug fixes, tests, and comments to a
+ patch from Stephen Cameron <steve.cameron@compaq.com>.)
+
+ * tag.c: (rtag_fileproc, rtag_delete, tag_fileproc)
+ Changed behavior of "cvs tag -F", "cvs tag -d", "cvs rtag -F"
+ and "cvs rtag -d" so that they will not disturb existing
+ branch tags unless a new "-B" option is given.
+ * sanity.sh (tagf-16 - tagf-33): Added tests for new -B option
+ to "cvs tag" and "cvs rtag"
+
+2001-06-06 Derek Price <dprice@collab.net>
+
+ * sanity.sh (crerepos-6a): Set CVS_RSH=false and only for the actual
+ test call at Larry's suggestion. Also, test the error message since
+ it's fixed now.
+
+2001-06-05 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_unlock): Note when breaking someone else's lock.
+ (Reported by MURVAI-BUZOGANY Laszlo
+ <Laszlo.MURVAI-BUZOGANY@gt-systems.hu>.)
+ * sanity.sh (reserved-14): Update to match.
+
+2001-06-05 Derek Price <dprice@collab.net>
+
+ * sanity.sh (crerepos-6a): Set CVS_RSH=/bin/false... this is a local
+ mode only test anyhow.
+ (Thanks to Larry Jones and Morgan Burke <morgan@sitka.triumf.ca>.)
+
+2001-05-31 Derek Price <dprice@collab.net>
+
+ * sanity.sh (rcs2-7): Add today to the list of failure dates for rcs2-7
+ in the hopes that the data will eventually prove useful to someone
+ motivated enough to fix the problem.
+
+2001-05-30 Derek Price <dprice@collab.net>
+
+ * stamp-h2.in: Regenerated.
+
+2001-05-30 Derek Price <dprice@collab.net>
+
+ * *: Various bug fixes and comments for the following
+ patch from Donald Sharp <sharpd@cisco.com>:
+
+ * checkout.c (safe_location): cvs co -d <directory> still had
+ failure modes from the way the -d option works.
+ * sanity.sh: Misc error message resynching.
+
+2001-05-29 Derek Price <dprice@collab.net>
+
+ * Makefile.am (cvs_SOURCES): Add root.h.
+
+ * Makefile.in: Regenerated.
+ * stamp-h2.in: Regenerated.
+
+2001-05-29 Derek Price <dprice@collab.net>
+
+ * checkout.c (safe_location): Correct formatting.
+
+2001-05-29 Derek Price <dprice@collab.net>
+
+ * root.c (parse_cvsroot): Fix a comment.
+
+2001-05-26 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (safe_location): Use old-style definition to keep
+ non-ANSI compilers happy.
+
+ * sanity.sh (check_respository): Use ${CVSROOT_DIRNAME} instead
+ of /tmp/cvs-sanity/cvsroot.
+
+2001-05-25 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (modules5): Add sleep to script to help avoid out of
+ order messages.
+
+ * filesubr.c (mkdir_if_needed): Return 1 if the directory exists
+ reguardless of what errno is set to.
+ (Reported by "Robinson, Greg" <greg.robinson@dsto.defence.gov.au>.)
+
+2001-05-25 Derek Price <dprice@collab.net>
+ for Donald Sharp <sharpd@cisco.com>
+
+ * checkout.c: Modified safe_location() to refuse checkout if
+ the -d option to co specifies inside of the repository.
+ * import.c: New parameter to safe_location needed to be added.
+ * cvs.h: New parameter to safe_location needed to be added.
+ * sanity.sh: Test case to test for failure mode.
+
+2001-05-23 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (checkout_proc): Don't build top_level_admin directory
+ when exporting.
+ (Reported by Tony Byrne <tonyb@directski.com>.)
+
+2001-05-21 Derek Price <dprice@collab.net>
+
+ * client.c: Fix a mispelling in a comment.
+ (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>).
+
+2001-05-05 Larry Jones <larry.jones@sdrc.com>
+
+ * login.c (password_entry_operation): Only warn if unable to open
+ .cvspass for reading: may be initial login and it doesn't exist yet.
+
+2001-05-15 Derek Price <dprice@collab.net>
+
+ * client.c (start_tcp_server): Use the struct sockaddr_in declared in
+ the function.
+ (Reported by Emil Isberg <isberg@dynarc.se>.)
+
+2001-05-05 Larry Jones <larry.jones@sdrc.com>
+
+ * annotate.c (annotate): Pass local to do_module and rannotate_proc
+ so that -l actually works.
+ * log.c (cvslog): Ditto.
+ * patch.c (patch): Ditto; make local local instead of global.
+ (patch_proc): Use local_specified parameter instead of global.
+ * tag.c (cvstag, rtag_proc): Ditto.
+
+2001-05-05 Larry Jones <larry.jones@sdrc.com>
+
+ * client.h: Declare "struct buffer" outside prototype for __STDC__
+ compilers.
+
+2001-05-04 Derek Price <dprice@collab.net>
+
+ * client.c: General refactoring. Removed several global variables in
+ favor of passing locals and/or dynamic evaluation.
+ (recv_line): Removed this function.
+ (make_bufs_from_fds): New function with factored code.
+ (connect_to_forked_server): New prototype. Use new functions.
+ (connect_to_pserver): New prototype. Use new functions.
+ (connect_to_gserver): New prototype. Use new API.
+ (auth_server): Factored this portion of the pserver code so it can be
+ shared. Rewrote to use buffers rather than depending on a socket.
+ (start_rsh_server): New prototype. Use new API.
+ (start_tcp_server): New prototype. Use new API.
+ (start_server): Factor some code. Use new API.
+ * client.h: New prototypes.
+ * cvs.h: Gratuitous reformatting. Use new root.h.
+ * login.c (login): Use new connect_to_pserver API.
+ * root.h: New file. Contains some code that used to be in cvs.h.
+
+2001-05-04 Derek Price <dprice@collab.net>
+
+ * client.c: Gratuitous reformatting.
+ * client.h: Ditto.
+
+2001-05-04 Derek Price <dprice@collab.net>
+
+ * zlib.c (compress_buffer_shutdown_input): Use new buffer shutdown
+ prototype.
+ (compress_buffer_shutdown_output): Ditto.
+ (Thanks to Pavel Roskin <proski@gnu.org>.)
+
+2001-05-03 Derek Price <dprice@collab.net>
+
+ * buffer.c (struct stdio_buffer_closure): New structure to hold a
+ FILE * and the child's PID when necessary.
+ (stdio_buffer_initialize): Change proto to accept PID. Set up new
+ closure. Pass new stdio_buffer_shutdown to buf_initialize.
+ (stdio_buffer_input): Use new closure.
+ (stdio_buffer_output): Ditto.
+ (stdio_buffer_flush): Ditto.
+ (stdio_buffer_shutdown): New function. Teach buffer to close itself.
+ (packetizing_buffer_shutdown): Use new buffer shutdown proto.
+ * buffer.h (struct buffer): New buffer shutdown proto.
+ (stdio_buffer_initialize): New proto.
+ * client.c (log_buffer_shutdown): Use new proto.
+ (socket_buffer_initialize): Pass shutdown func.
+ (socket_buffer_shutdown): New function.
+ * server.c (get_responses_and_close): Remove most of the guts. Rely
+ on the buffer shutdown function from now on.
+ (start_rsh_server): Return child PID.
+
+2001-05-03 Larry Jones <larry.jones@sdrc.com>
+
+ * history.c (history_write): Handle the case where the user's home
+ directory doesn't exist gracefully instead of erroring out.
+ (Reported by David Hoover <dhoover@cadence.com>.)
+
+2001-05-03 Derek Price <dprice@collab.net>
+
+ * cvs.h: s/allocate_and_strcat/xrealloc_and_strcat/ since that is what
+ I wrote in the ChangeLog, oh, so long ago.
+ * diff.c (diff): Ditto.
+ * subr.c (allocate_and_strcat, xrealloc_and_strcat): Ditto.
+
+2001-05-02 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_getdate): Handle the (unusual!) case where we
+ can't find any revisions at all.
+ (Reported by Ryan Grow <rgrow@Dbdoctor.net>.)
+
+2001-04-30 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (multiroot2-9a): Rename (from multiroot2-9) to avoid
+ duplicate names; fix to work without SERVER_SUPPORT defined.
+ (Reported by Pavel Roskin <proski@gnu.org>.)
+
+2001-04-29 Derek Price <dprice@collab.net>
+
+ * Makefile.am (check-local): Make dependent on localcheck and
+ remotecheck and move old check target...
+ (localcheck): here.
+
+ * Makefile.in: Regenerated.
+
+2001-04-27 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (pserver): Add tests for readers and writers.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * sanity.sh (version-2r): Update to handle patch releases in version
+ numbers.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * version.c: Regenerated.
+
+2001-04-27 Derek Price <dprice@collab.net>
+
+ * version.c: Regenerated.
+
+2001-04-27 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (lookup_command_attribute): Lookup specified command, not
+ whatever's in the global command_name.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+ * version.c: Regenerated.
+
+2001-04-22 Larry Jones <larry.jones@sdrc.com>
+
+ * tag.c (tag_check_valid): Make an unwritable val-tags file a
+ warning instead of a fatal error.
+
+2001-04-20 Larry Jones <larry.jones@sdrc.com>
+
+ * annotate.c (annotate_usage): -r and -D are not mutually exclusive.
+ * main.c (cmd_usage): Add missing version subcommand.
+ * update.c (update_usage): Add missing -C option.
+
+ * sanity.sh (death2): New tests for previous change.
+
+ * classify.c (Classify_File): Treat a dead revision like the RCS
+ file doesn't exist.
+ * sanity.sh: Update to match.
+
+2001-04-16 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c, update.c: Fix usage messages: -r and -D are not
+ mutually exclusive.
+ (Suggested by David L. Martin <dlmart2@home.com>.)
+
+ * logmsg.c (do_editor): Don't add a blank line to the message.
+ * sanity.sh (editor-log-file*): Update to match.
+
+ * checkout.c, update.c: Note in usage message that -k is sticky.
+
+ * server.c: (server_cleanup, wait_sig): Remove ancient SunOS kludge.
+ (Suggested by Rob Saccoccio <robs@chelsea.net>.)
+
+2001-04-04 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (dotest, dotest_lit, dotest_fail, dotest_status,
+ dotest_sort): Don't count on $? being set in then or else clauses.
+
+ * ignore.c (ignore_files): Collect unignored files into a list and
+ sort it before calling PROC to avoid order dependencies. Rewrite
+ the while loop to allow normal continues instead of goto.
+
+2001-04-04 Derek Price <dprice@collab.net>
+
+ * sanity.sh (ignore-on-branch-3): Fix in the remote case.
+
+2001-04-03 Larry Jones <larry.jones@sdrc.com>
+
+ * update.c (update_fileproc): Remove unused variable (resurrecting).
+
+2001-04-03 Derek Price <dprice@collab.net>
+ Larry Jones <larry.jones@sdrc.com>
+ reported by Jakob Bøhm <JB@Danware.dk>
+
+ * update.c (update_fileproc): Don't store a file with T_UNKNOWN status
+ in ignlist if present in the sandbox.
+ * sanity.sh (ignore-on-branch): New test.
+ (ignore): Tidy this test.
+
+2001-04-02 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Make sure the test for `id' fails when a nonstandard `id'
+ is used and the user is root. Fix some quoting in error messages.
+ (fork): Take `cvs' out of the PATH.
+ (TODO): Add note about the test suite not working with user names over
+ eight characters in length.
+
+2001-04-02 Derek Price <dprice@collab.net>
+
+ * sanity.sh (fork): New test for CVS_SERVER default.
+ (TODO): Note about eventually removing most of the references to
+ CVS_SERVER.
+
+2001-04-02 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (connect_to_forked_server): Use program_path as the default
+ server instead of "cvs".
+
+2001-04-02 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Use less obfuscated English in my comment about sanity
+ checking sanity.sh.
+
+2001-04-02 Derek Price <dprice@collab.net>
+
+ * sanity.sh (rm-update-message): Create a test directory again but
+ change back to the correct directory upon completion this time.
+
+2001-04-02 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Change last two '[.*]'s to 'test's for
+ consistency and remove...
+ (TODO): the note from the TODO list.
+
+2001-04-02 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Add test for PWD before successful exit.
+
+2001-03-30 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (rm-update-message): Remove duplicate code.
+
+2001-03-30 Derek Price <dprice@collab.net>
+
+ * sanity.sh (rm-update-message): New test for local/client-server
+ warning message discrepency.
+
+2001-03-30 Larry Jones <larry.jones@sdrc.com>
+
+ * annotate.c: Move annotate() here from rcs.c, support rannotate.
+ * Makefile.am, Makefile.in: Add annotate.c.
+ * main.c (cmds[], cmd_usage[]): Add rannotate.
+ * rcs.c: Move declarations of rcs_delta_op and RCS_deltas to...
+ * rcs.h: ... here.
+ * server.c (serve_rannotate): New.
+ (requests[]): Add rannotate.
+ * sanity.sh (ann): New tests for rannotate.
+
+ * log.c (rlog_proc): Remove dead code.
+
+2001-03-30 Derek Price <dprice@collab.net>
+
+ * sanity.sh (join-readonly-conflict): Run more of this through dotest.
+
+2001-03-30 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (log_fileproc): Don't output working file for rlog.
+ * sanity.sh (log): New tests for rlog.
+
+ * cvs.h (mtype): Add MISC type.
+ * log.c (cvslog): Support rlog as well as log.
+ (rlog_proc): New.
+ * main.c (cmds[], cmd_usage[]): Add rlog.
+ (main): Remove old rlog warning message.
+ * server.c (serve_rlog): New.
+ (requests[]): Add rlog.
+
+2001-03-29 Derek Price <dprice@collab.net>
+
+ * sanity.sh: cd to $TESTDIR once after it is normalized. Make TODO
+ on history and symlinks more specific. Tested properly this time.
+
+2001-03-29 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (cmds[], lookup_command_attribute, main): Include the
+ command attributes in the global command table instead of inferring
+ them from the command names. Change the sense of the
+ CVS_CMD_IGNORE_ADMROOT attribute to match its name.
+
+2001-03-29 Derek Price <dprice@collab.net>
+
+ * sanity.sh (*, basic2-64): Remove references to TMPPWD. Fix FIXME
+ at end of script now that $TESTDIR can't be relative.
+
+2001-03-29 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Normalize TESTDIR even when the user set it.
+
+2001-03-29 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (connect_to_pserver, start_tcp_server): Add IP address
+ to connect failed message.
+ (connect_to_forked_server, connect_to_pserver, start_tcp_server): Add
+ trace messages ala start_rsh_server.
+ (start_rsh_server): Include entire command in trace message for
+ START_RSH_WITH_POPEN_RW like ! START_RSH_WITH_POPEN_RW does.
+
+2001-03-29 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Global search & replace ${TESTDIR}/cvsroot with
+ ${CVSROOT_DIRNAME} for consistency.
+
+2001-03-29 Derek Price <dprice@collab.net>
+
+ * sanity.sh (conflicts-12[68].5): Remove sanity hack which has allowed
+ for a CVS bug since May 96/97. Not sure when the bug went bye-bye, but
+ the tests broke when $TESTDIR != $TMPPWD.
+
+2001-03-26 Larry Jones <larry.jones@sdrc.com>
+
+ * classify.c (Classify_File): Don't report a conflict for a removed
+ file when piping. Also simplify the code structure.
+ (Reported by Milos Kleint <milos.kleint@netbeans.com>.)
+ * sanity.sh (rmadd2-14[abc]): New tests for above.
+
+2001-03-24 Noel Cragg <noel@shave.cnet.com>
+
+ * diff.c: mods to allow `-T' and `-y' options to be passed through
+ to the diff library. This wasn't allowed earlier because of a
+ similarly named options that got passed through to the old rcs
+ programs. We've long since stopped sending `-T' to any rcs
+ utility and have never used `-y'. Any users of moldly CVS
+ versions which used to support `-T' have (hopefully) upgraded to
+ one where that option isn't supported. It seems reasonable to
+ enable them again and pass them through. (sanity.sh still works
+ anyways...)
+ (longopts): add short option equivalents for --initial-tab and
+ --side-by-side.
+ (diff): add new short options to getopt string and switch
+ statement.
+
+2001-03-22 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Add check for ${DOTSTAR} with large matches.
+
+2001-03-23 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Do the same as below for $keep.
+
+2001-03-23 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Replace 'remote=(yes|no)' with 'remote=(:|false)' since
+ often 'false' and more often ':' are shell builtins. This makes the
+ succinct, 'if $remote; then' faster than 'if test $remote = yes; then'.
+ Alter tests in the rest of the script to match the new usage. Added
+ a suffix of 'r' to remote test names when it was appropriate and I
+ remembered. Some reformatting.
+
+2001-03-22 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (diffmerge1_yours, diffmerge1_mine): Check for exact
+ output instead of using wildcards to avoid buffer overflows in some
+ versions of expr.
+
+2001-03-21 Derek Price <dprice@collab.net>
+
+ * sanity.sh: cd to '/tmp' again rather than $HOME since HOME was set to
+ a value inside ${TESTDIR} by the script.
+
+2001-03-20 Derek Price <dprice@collab.net>
+
+ * sanity.sh (diffmerge1): Minor formatting and syntax changes.
+
+ for Jacob Burckhardt <bjacob@ca.metsci.com>
+
+ * sanity.sh (diffmerge1): More merging behavior tests. Specifically,
+ test some cases which broke before in Karl Tomlinson's diff fix was
+ checked in today.
+
+2001-03-20 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Don't use unescaped parens in sh outside of quotes.
+
+2001-03-20 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Don't remove ${TESTDIR} when -k (keep) set.
+
+2001-03-20 Derek Price <dprice@collab.net>
+
+ * sanity.sh: Change usage to match the new getopts format and comment.
+
+2001-03-16 Derek Price <dprice@collab.net>
+
+ * sanity.sh (modules2-nestedrename): New test. Verifies behavior of
+ renames nested under an ampersand module.
+ (modules2-ampertag): New test. Verifies an error condition which
+ prevents some ampersand modules from being checked out when a tag
+ is specified.
+
+2001-03-16 Derek Price <dprice@collab.net>
+
+ * sanity.sh (modules2): Additional test for ampersand module behavior
+ with '-d'.
+
+ for Greg Klanderman <greg@itasoftware.com>
+
+ * checkout.c (build_one_dir): Fix typo where clauses of two
+ conditionals were reversed in call to Create_Admin. This caused
+ the CVS/Tag file to be removed in cases where it should have been
+ set, and vice-versa. It only surfaced in rare cases as this code
+ is only invoked when using the -d option to build the path to
+ check out in. Further, the bug would only matter when checking
+ out a module containing ampersand modules within it, via
+ client/server CVS.
+
+2001-03-16 Derek Price <dprice@collab.net>
+
+ * sanity.sh (admin-28-5): Confirm that a missing tag during an
+ 'admin -n' operation is not a fatal error.
+
+2001-03-16 Derek Price <dprice@collab.net>
+
+ * admin.c (admin_data): Remove 'quiet' member.
+ (admin_fileproc): Use global 'really_quiet' rather than
+ admin_data->quiet.
+
+2001-03-16 Derek Price <dprice@collab.net>
+
+ * sanity.sh (admin): Replace hardcoded testdir path with the variable.
+
+2001-03-15 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh (basica, binfiles, head, admin): Adjust for new messages.
+ * admin.c (admin_fileproc): Only print messages when not in
+ really_quiet mode.
+
+ for Stephen Rasku <stephen@tgivan.com>
+
+ * rcs.c (RCS_tag2rev): Make a missing tag a survivable error.
+
+2001-03-15 Larry Jones <larry.jones@sdrc.com>
+
+ * subr.c (sleep_past): Fix various bugs that would result in a
+ negative sleep time if it weren't unsigned; since it is, it would
+ result in a very large sleep time. Ensure that us is always less
+ than 1000000. Don't try to sleep for more 1 sec with usleep.
+ Cast NULL select arguments to correct type just in case.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * subr.c (sleep_past): New function.
+ * client.c (get_responses_and_close): Use new function.
+ * commit.c (commit): Ditto.
+ * update.c (do_update): Ditto.
+ * cvs.h: Prototype new function.
+
+ * stamp-h2.in: Regenerated.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated.
+ * stamp-h2.in: Ditto.
+
+2001-03-14 Larry Jones <larry.jones@sdrc.com>
+
+ * commit.c (check_fileproc): Allow adding on the trunk when there's
+ an existing non-Attic RCS file as long as the head revision is dead.
+ This can happen due to an aborted resurrection.
+ (commit_fileproc): When resurrecting, consider the dead revision
+ along with the other files' revisions.
+ (findmaxrev): Avoid unnecessary work.
+ (checkaddfile): Only warn if file isn't in Attic as expected.
+ (Reported by Ross Burton <r.burton@180sw.com>.)
+ * sanity.sh (basica-r*): New tests for above.
+ (basica-o4): Update to match.
+
+2001-03-09 Larry Jones <larry.jones@sdrc.com>
+
+ * edit.c (edit_fileproc, unedit_fileproc): Some implementations of
+ asctime/ctime apparently use a leading zero on the date instead
+ of the space required by the C Standard. Correct for this so that
+ shared working directories work without hassle.
+ (Reported by David L. Martin <dlmart2@home.com>.)
+ * entries.c (fgetentent): Ditto.
+ * vers_ts.c (time_stamp_server, time_stamp) Ditto.
+
+2001-03-07 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (basica, binfiles2, head, admin): Update to match
+ change to admin.c.
+
+2001-03-06 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (recv_bytes): Handle EOF as in recv_line().
+ (Reported by Pavel Roskin <proski@gnu.org>.)
+
+ * admin.c (admin_fileproc): Change final error message to clarify
+ that CVS refused to modify the RCS file rather than being unable to.
+
+2001-02-28 Jim Meyering <meyering@lucent.com>
+
+ * commit.c (commit_usage): Use `-F logfile' (rather than -F file') in
+ the description of that option, to be consistent with the `-F logfile'
+ in the Usage: line. Use spaces instead of TAB characters, and realign.
+
+2001-03-02 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh (crerepos): Make failed ${CVS_RSH-rsh} attempt print the
+ name of the command it actually used rather than 'rsh'.
+
+2001-02-27 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh (modules2-ampermod-*): Added these tests to make sure the
+ top level directory is created in an ampermodule when '-n' is passed to
+ checkout.
+
+ original bug report from
+ Wolfgang Haefelinger <Wolfgang.Haefelinger@Dresdner-Bank.com>
+
+2001-02-27 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh (version-[12]): replace ' (client/server)' with .* in these
+ two tests so that 'make check' works with whatever client/server
+ options the executable was compiled with.
+
+2001-02-23 Derek Price <derek.price@openavenue.com>
+
+ * main.c (main): Only check a cvsroot_t's isremote member when client
+ support is enabled.
+ * server.c: Include GSSAPI headers with client support as well as
+ server support.
+
+2001-02-21 Larry Jones <larry.jones@sdrc.com>
+
+ * modules.c, cvs.h (do_module): Add build_dirs argument and use it
+ instead of run_module_prog. Change all callers.
+ * tag.c (cvstag): For rtag, don't build directories.
+ * sanity.sh (modules3): Update to match.
+
+2001-02-20 Derek Price <derek.price@openavenue.com>
+
+ * client.c: Use xgssapi.h.
+ * server.c: Ditto.
+
+2001-02-15 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (cvs_SOURCES): Correct error from yesterday.
+ * Makefile.in: Regenerated.
+
+2001-02-14 Derek Price <derek.price@openavenue.com>
+
+ * server.c: Include xselect.h.
+ * update.c (do_update): Use best available sleep function.
+
+2001-02-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (cvs_SOURCES): Alphabetize and split to one/line.
+ (cvs_LDADD): Alphabetize and split to one/line.
+ * Makefile.in: Regenerated.
+
+2001-02-14 Larry Jones <larry.jones@sdrc.com>
+
+ * build_src.com: Remove references to rtag.c & rtag.obj.
+
+2001-02-13 Derek Price <derek.price@openavenue.com>
+
+ * main.c (date_to_tm): New function to convert an RCS date string to a
+ struct tm.
+ (tm_to_internet): New function to convert a struct tm to a date string
+ as specified by RFC822 and amended by RFC 1123.
+ (date_to_internet): Use the above two functions and a struct tm
+ intermediary for conversion.
+ * patch.c (patch_fileproc): Answer somebody's comment and use the new
+ diff_exec API.
+ * rcs.c (RCS_checkin): Use new diff_exec API.
+ (RCS_delete_revs): Use new diff_exec API.
+ (make_file_label): If the file name is DEVNULL, date it the Epoch for
+ compatibility with the POSIX.2 spec and Larry Wall's patch
+ implementation.
+ * rcscmds.c (diff_exec): Accept new label arguments.
+ * sanity.sh (death2): Update some diff tests to accept the new format.
+ * update.c (patch_file): Use new diff_exec API.
+ * diff.c (diff_fileproc): Create header labels appropriate for
+ compatibility with the Larry Wall version of patch.
+ (diff): Rename calls to strcat_and_allocate.
+ (strcat_and_allocate): Rename and move...
+ * subr.c (xrealloc_and_strcat): here.
+ * cvs.h: Update prototypes to match.
+
+2001-02-13 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (cvs_SOURCES): Remove rtag.c.
+
+2001-02-07 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (directory_cmp): Return status rather than setting ISDIFF.
+ (basic2): Rewrite using dotest.
+
+2001-02-06 Larry Jones <larry.jones@sdrc.com>
+
+ * tag.c, rtag.c: Merge with tag.c being the surviving file.
+ * Makefile.in: Update to match.
+ * main.c (cmds): rtag() => cvstag().
+ * server.c (serve_rtag): Ditto, and set command name.
+
+2001-02-06 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+ Shawn Smith <Shawn_Smith@notes.ymp.gov>
+
+ * add.c: Replace opendir, closedir, & readdir calls with CVS_OPENDIR,
+ CVS_CLOSEDIR, & CVS_READDIR in support of changes to handle VMS DEC C
+ 5.7 {open,read,close}dir problems. Check today's entry in the vms
+ subdir for more.
+ * filesubr.c: ditto
+ * find_names.c: ditto
+ * ignore.c: ditto
+ * import.c: ditto
+ * lock.c: ditto
+ * update.c: ditto
+
+2001-02-02 Larry Jones <larry.jones@sdrc.com>
+
+ * error.h: Changed include guard macro from _error_h_ to ERROR_H;
+ names beginning with underscore are reserved.
+ * login.c (password_entry_parseline, password_entry_operation,
+ password_entry_operation_e, password_entry_operation_t): Removed
+ leading underscore(s).
+ (password_entry_parseline): Corrected error messages.
+ (password_entry_operation): Fixed uninitialized variable (password).
+ (login): Removed unused variable (found_password).
+
+ * rtag.c (rtag_proc): Call lock_tree_for_write() before calling
+ start_recursion. This fixes a serious problem where do_recursion
+ was reading and caching RCS files without any locks in place and
+ that information was subsequently being used to rewrite the file
+ causing any intermediate changes to be lost.
+ (rtag_filesdoneproc): Defunct.
+ (Reported by Karl Tomlinson <k.tomlinson@auckland.ac.nz>.)
+ * tag.c (cvstag, tag_filesdoneproc): Ditto.
+ * lock.c (lock_tree_for_write): Add which argument, change all
+ callers to pass W_LOCAL.
+ * rcs.h: Ditto.
+
+2001-01-29 Derek Price <derek.price@openavenue.com>
+
+ * client.c (get_cvs_port_number): change the prototype to accept a
+ const cvsroot_t * as input and add a FIXME comment
+ * cvs.h: new prototypes for get_cvs_port_number & normalize_cvsroot
+ * login.c (_password_entry_operation): consolidate all the ~/.cvspass
+ access into a single new function which reads ~/.cvspass in a backwards
+ compatible manner
+ (logout): use the new _password_entry_operation function
+ (login): ditto
+ (get_cvs_password): ditto
+ * root.c (normalize_cvsroot): move knowledge of default port & username
+ values inside
+
+2001-01-29 Larry Jones <larry.jones@sdrc.com>
+
+ * subr.c (shell_escape): New function.
+ * cvs.h: Declare it.
+ * logmsg.c (logfile_write): Use it to avoid problems with filenames
+ containing "'".
+ (Reported by Gerhard Ahuis <gerhard@ats.xs4all.nl>.)
+
+ * server.c (outbuf_memory_error, pserver_authenticate_connection,
+ kserver_authenticate_connection): If available, use syslog() to
+ record some errors.
+
+2001-01-25 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (do_cvs_command): If there's a partial output line left
+ over and the client doesn't support MT, go ahead and send it in an
+ M response instead of just dropping it.
+ (Reported by Milos Kleint <Milos.Kleint@netbeans.com>.)
+
+ * update.c (update_fileproc): Handle toss_local_changes in the
+ T_NEEDS_MERGE case.
+ (Inspired by Noel L Yap <yap_noel@jpmorgan.com>.)
+ * sanity.sh (clean): New tests for above.
+
+2001-01-23 Derek Price <derek.price@openavenue.com>
+
+ * run.c (run_exec): flush, if used, stderr and stdout before exit
+ * server.c (cvs_flusherr): flush stderr & send a stderr flush command
+ on the protocol pipe
+ (cvs_flushout): like above, for stdout
+ (do_cvs_command): handle flushes properly
+ * sanity.sh (reserved): make the commitinfo script echo errors to
+ stderr rather than stdin
+
+2001-01-18 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (option_revlist, revlist, log_usage, cvslog,
+ log_parse_revlist, log_expand_revlist, log_version_requested): Add
+ support for :: for exclusive ranges.
+ * admin.c (admin_usage): Reorder -o to be parallel to log -r.
+ * sanity.sh (log): New tests for above.
+
+2001-01-18 Derek Price <derek.price@openavenue.com>
+
+ * main.c: Add '2001' to the range of copyright years listed by the
+ --version option
+ * version.c.in (version): check current_parsed_root before its isremote
+ member to avoid a core dump
+ * sanity.sh (version): add a test for the version command
+
+ * version.c: regenerated
+
+2001-01-12 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c, rcs.h (RCS_lock, RCS_unlock): Use RCS_gettag to find the
+ correct revision so that symbolic tags work correctly. (This
+ requires removing the "const" from the rev parameter since it's
+ passed to RCS_gettag which might modify it.)
+ (Reported by irina sturm <irina.sturm@st.com>.)
+
+2001-01-11 Larry Jones <larry.jones@sdrc.com>
+
+ * run.c (close_on_exec): Remove check for FD_CLOEXEC. As far as I
+ can see, it's *never* been defined, which defeats the whole point.
+ If F_SETFD is defined, it's probably safe to use it.
+
+ * server.c (do_cvs_command): Call close_on_exec on the protocol and
+ flow control pipes in the child process so they don't get inherited
+ by any subsidiary processes.
+ (Reported by Tristan Gingold <tgi@netgem.com>.)
+
+ * cvs.h (free_cvsroot_t): Spell correctly (was free_CVSroot_t).
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+
+ * build_src.com: VMS changes
+ * filesubr.c: replace calls to unlink() with CVS_UNLINK() for VMS
+ * rcs.c: ditto
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+
+ * main.c (current_root): explicitly list this as a static global
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+
+ * cvs.h (get_cvs_port_number): change name & prototype from
+ get_port_number
+ * client.c (get_cvs_port_number): new function which returns a port
+ number based on a cvsroot_t rather than requiring all possible sources
+ passed in
+ (connect_to_pserver): use new get_cvs_port_number function
+ (connect_to_server): ditto
+ * login.c (get_password): use new get_cvs_port_number function
+ (login): ditto
+ (logout): ditto
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am ($(srcdir)/version.c): specify $(srcdir) for all subparts
+ of the build since some systems don't allow mv's across partitions
+ * Makefile.in: regenerated
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (version.c): specify $(srcdir) explicitly in target rule
+ so version.c gets built properly for all makes.
+ (version.o): specify $(srcdir)/version.c explicitly so dependency is
+ found and built properly
+ * Makefile.in: regenerated
+
+2001-01-09 Derek Price <derek.price@openavenue.com>
+
+ * version.c: updated timestamp
+
+2001-01-09 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (server): Change to server_temp_dir immediately after
+ creating it so that any stray files that happen to be created go
+ there instead of in the server's initial directory, wherever that
+ may be.
+ * sanity.sh (modules5-15): Update to match.
+
+ * version.c.in: Update to match Derek's change to version.c.
+
+2001-01-09 Derek Price <derek.price@openavenue.com>
+
+ * cvs.h: Remove the various CVSroot_* bits and replace them with a
+ single structure of type cvsroot_t (current_parsed_root)
+
+ * root.c (parse_cvsroot): return pointer to a new cvsroot_t rather than
+ altering global variables
+ (local_cvsroot): return a pointer to a new cvsroot_t rather than
+ setting globals. changed the name of this function from
+ set_local_cvsroot to better explain new functionality
+ (new_cvsroot_t): new initializer function
+ (free_cvsroot_t): new function
+ (others): use current_parsed_root rather than the old CVSroot_* globals
+
+ * add.c: use current_parsed_root rather than the old CVSroot_* globals
+ * admin.c: ditto
+ * checkout.c: ditto
+ * client.c: ditto
+ * commit.c: ditto
+ * create_adm.c: ditto
+ * diff.c: ditto
+ * edit.c: ditto
+ * expand_path.c: ditto
+ * find_names.c: ditto
+ * history.c: ditto
+ * ignore.c: ditto
+ * import.c: ditto
+ * lock.c: ditto
+ * log.c: ditto
+ * login.c: ditto
+ * logmsg.c: ditto
+ * main.c: ditto
+ * mkmodules.c: ditto
+ * modules.c: ditto
+ * parseinfo.c: ditto
+ * patch.c: ditto
+ * rcs.c: ditto
+ * recurse.c: ditto
+ * release.c: ditto
+ * remove.c: ditto
+ * repos.c: ditto
+ * rtag.c: ditto
+ * server.c: ditto
+ * status.c: ditto
+ * tag.c: ditto
+ * update.c: ditto
+ * version.c: ditto
+ * watch.c: ditto
+ * wrapper.c: ditto
+
+2001-01-05 Derek Price <derek.price@openavenue.com>
+
+ * cvs.h (enum CVSmethod): add null_method
+ * root.c (method_names): correlate null_method & "undefined"
+ (parse_cvsroot): make two error cases non fatal
+ * sanity.sh (crerepos-6b): account for new error message, re above
+
+2001-01-05 Derek Price <derek.price@openavenue.com>
+
+ * src/Makefile.am (cvsbug, cvsbug_EXTRA_DIST, EXTRA_DIST): move cvsbug
+ target to configure.in - see ../ChangeLog for more
+ * src/cvsbug.in: Rename from cvsbug.sh
+ * src/cvsbug.sh: Rename to cvsbug.in
+
+2001-01-04 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.am (cvsbug): Explicitly list input file ($< is only
+ valid in inference rules).
+ * Makefile.in: Ditto.
+
+2001-01-04 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh: use getopts rather than getopt for portability reasons
+
+2001-01-03 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (remotecheck): depend on 'all'
+ * Makefile.in: regenerated
+
+2000-12-29 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh: remove explicit "$@" from last checkin and move the 'do'
+ to the line following the 'for'. Apparently this is more portable.
+
+2000-12-29 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh: make "$@" explicit in 'for' statement since Solaris 5.6's
+ implementation of Bourne shell doesn't seem to implement this default
+ behavior.
+
+2000-12-27 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh: add a -f option for continuing from a particular test
+ and shorten --keep to -k so we can use the getopt function.
+
+2000-12-27 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (remotecheck): Make remotecheck dependant on all
+ * Makefile.in: regenerated
+
+2000-12-26 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: update timestamp
+ * stamp-h2.in: ditto
+ * version.c: ditto
+
+2000-12-26 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: new target for version.c
+ (EXTRA_DIST): add version.c.in & version.c so builds work when
+ configure doesn't
+ * Makefile.in: Regenerated
+ * stamp-h2.in: update timestamp
+ * version.c: ditto
+
+2000-12-26 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (INCLUDES): add zlib
+ * Makefile.in: Regenerated
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am (DISTCLEANFILES): added a few files
+ (INCLUDES): commented
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * .cvsignore: Added .deps directory and a new stamp file
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+ * stamp-h2.in: New stamp file created by Automake
+ * version.c.in: use configure to generate version.c
+
+2000-12-16 Derek Price <derek.price@openavenue.com>
+
+ * server.c (server_update): Keep the vers structure up to date after
+ sending a Remove or Remove-entry command to the client
+ * update.c (update): remove call to server_updated() after
+ scratch_file()
+ (scratch_file): in server mode, call server_updated(), otherwise keep
+ the vers structure up to date
+ (join_file): add a trace, save the revision to Register() on a remove
+ before calling server_scratch & server_updated
+ * sanity.sh (join): Add test for a remove/add caused by an update
+ to a new branch and a join in the same step.
+
+2000-12-15 Larry Jones <larry.jones@sdrc.com>
+
+ * error.c (error): Add %ld and %lu.
+
+ * history.c: Change hrec.idx from int to long, reformat NEXT_BAR
+ for readability, add hrec_idx.
+ (fill_hrec): Change initialization to be portable and always set
+ idx so it can be used as a line number in error messages; improve
+ parsing and error checking.
+ (read_hrecs): Initialize hrec_idx, handle embedded NULs, warn about
+ no newline at end of file.
+ (select_hrec): Add basic validity checking.
+
+2000-12-07 Larry Jones <larry.jones@sdrc.com>
+
+ * history.c (history): Allow multiple -m options as documented.
+
+2000-11-29 Derek Price <derek.price@openavenue.com>
+
+ * root.c (parse_cvsroot): back out yesterday's redundant changes
+ * main.c (main): fix CVSROOT trace message to look like other trace
+ messages
+ * sanity.sh (multiroot2-9): expect new trace message
+
+2000-11-28 Derek Price <derek.price@openavenue.com>
+
+ * root.c (parse_cvsroot): add trace on this function
+ * client.c (get_port_number): make trace print look like others
+
+2000-11-16 Derek Price <derek.price@openavenue.com>
+
+ * filesubr.c (cvs_temp_file): back out the previous change in the
+ interests of portability, add an assertion, and fix the header comment
+
+2000-11-16 Derek Price <derek.price@openavenue.com>
+
+ * filesubr.c (cvs_temp_file): refine the exit behavior to notice if
+ the out param was passed in NULL and, if so, avoid setting it and delete
+ the temp file for later
+
+2000-11-16 Derek Price <derek.price@openavenue.com>
+
+ * filesubr.c (cvs_temp_file): fixed a garble or two, added some
+ additional error checking, and added a comment
+
+2000-11-15 Derek Price <derek.price@openavenue.com>
+
+ * filesubr.c (cvs_temp_file): added cvs_temp_file
+ function to use mkstemp rather than one of the other temp file
+ generators as gcc keeps complaining I should.
+ (cvs_temp_name): altered this function to simply wrap cvs_temp_file
+ and deprecated it
+ * cvs.h: added prototype for cvs_temp_file
+ * commit.c (commit): use the new function instead of the old and plug
+ an old (though related) memory leak.
+ * import.c (import): use the new function
+ * login.c (login): Ditto
+ * logmsg.c (do_editor, do_verify): Ditto
+ * patch.c (patch_fileproc): Ditto
+
+2000-11-14 Larry Jones <larry.jones@sdrc.com>
+
+ * update.c, update.h (do_update): Add xdotemplate parameter.
+ Change all callers.
+ (update_dirent_proc): Use dotemplate for Create_Admin, not 1.
+ * checkout.c (checkout_proc): Don't create CVS/Template if
+ exporting.
+ (Reported by Andrey Podkolzin <mdh@zenon.net>.)
+
+2000-11-08 Larry Jones <larry.jones@sdrc.com>
+
+ * admin.c (admin): Use getgroups() to check for membership in
+ CVS_ADMIN_GROUP if it exists. In any event, check the user's
+ primary group in addition to any additional groups.
+ (Reported by Thomas Okken <TOkken@refco.com>.)
+
+2000-11-06 Jim Meyering <meyering@lucent.com>
+
+ Compile with gcc's -Wformat and fix the exposed problems.
+ * root.c (parse_cvsroot) [! HAVE_KERBEROS]: Provide an argument
+ for the %s error format spec.
+ [! HAVE_GSSAPI]: Likewise.
+ (normalize_cvsroot): Put comment delimiters around token after `#endif'.
+
+2000-11-03 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Some versions of sed require a space between -e and
+ the value.
+
+2000-10-27 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (checkout): Don't check for a safe location if just
+ cat'ing the module database.
+ (Reported by Ilya Martynov <m_ilya@agava.com>.)
+ Have -s set cat as well as status; it simplifies the code.
+
+2000-10-26 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (join-admin-2): Check output from all commands instead
+ of (mostly) discarding. (Some of the tests used to produce stray
+ output in remote mode.)
+
+ * sanity.sh (dotest_line_by_line): Handle empty lines in pattern
+ (expr doesn't distingish between successfully matching nothing
+ and failing to match anything).
+
+ * sanity.sh (dotest_internal): Rearrange and use elif to simplify.
+
+2000-10-24 Jim Meyering <meyering@lucent.com>
+
+ Fix a bug, introduced with my fix of 2000-07-10, whereby -kk would
+ sometimes be ignored for some of the files involved in an update.
+
+ * update.c (join_file): Restore the original value of `options'
+ right after calling checkout_file.
+ * sanity.sh (join-admin-2): New test for this.
+
+2000-10-23 Derek Price <derek.price@openavenue.com>
+ James Youngman <jay@gnu.org>
+
+ * sanity.sh: it's /gnu/bin, not /gun/bin. Thanks go to James Youngman
+ <jay@gnu.org> for the bug report and patch.
+
+2000-10-20 Jim Kingdon <http://sourceforge.net/users/kingdon/>
+
+ * server.c (switch_to_user): Set CVS_USER. Patch from Sudish
+ Joseph and popularized by dozens (e.g. mozilla.org, also others).
+
+2000-10-20 Derek Price <derek.price@openavenue.com>
+ KOIE Hidetaka <hide@koie.org>
+
+ * root.c (normalize_cvsroot): plug a memory leak. Thanks to
+ KOIE Hidetaka <hide@koie.org>
+
+2000-10-18 Derek Price <derek.price@openavenue.com>
+
+ * client.c (connect_to_pserver): added a close brace the lack of which
+ was preventing compilation when gssapi was enabled. Removed a
+ redundant check for HAVE_KERBEROS.
+
+2000-10-18 Derek Price <derek.price@openavenue.com>
+
+ * root.c (normalize_cvsroot): removed references to free_port_s and the
+ now useless call to free now that port_s is on the stack. Thanks to
+ Jon Miner.
+
+2000-10-18 Derek Price <derek.price@openavenue.com>
+
+ * root.c (normalize_cvsroot): remove calls to snprintf for
+ compatibility with M$ Windoze.
+
+2000-10-18 Derek Price <derek.price@openavenue.com>
+
+ * sanity.sh (crerepos-6a, crerepos-6a-r): fix a "?" in a regex & pipe
+ the output of a test to /dev/null since we don't know what error
+ messages specific rsh implementations will output.
+
+2000-10-17 Derek Price <derek.price@openavenue.com>
+
+ * cvs.h: added CVSroot_password variable. Provided prototypes for
+ get_port_number & normalize_cvsroot.
+ * client.c (get_port_number): Fixed an ANSI prototype I had included
+ for get_port_number.
+ * login.c (login, logout): Removed two checks for a non-null
+ CVSroot_username since parse_cvsroot now supplies a default in pserver
+ mode. allow for a password in CVSROOT
+ (get_cvs_passsword): return CVSroot_password if it was supplied
+ in the CVSROOT.
+ * root.c (parse_cvsroot): Changed CVSROOT spec from
+ :method:user@host/port:/cvsroot to
+ :method:[[user][:password]@]host[:[port]]/cvsroot
+ Removed the xstrdup function since we'd rather have the error checking
+ from the version in subr.c anyhow. Moved some error messages which
+ looked like they would print the wrong error message after a failed
+ connect_to_gserver call.
+ (normalize_cvsroot): return a normalized CVSROOT for use in the
+ .cvspass file.
+ * sanity.sh (crerepos-6): fix a test which was expecting an old error
+ message.
+
+ * client.c (connect_to_pserver): Moved some error messages which looked like they
+ would print the wrong error message after a failed connect_to_gserver
+ call.
+
+ * login.c (login): Paranoiacly zero a password in memory.
+
+2000-10-12 Derek Price <derek.price@openavenue.com>
+
+ * client.c (auth_server_port_number -> get_port_number, start_pserver,
+ start_tcp_server): use a port specified in CVSROOT instead of the
+ default port. Failing that, use the CVS_CLIENT_PORT environment
+ variable.
+ * cvs.h: Added global CVSroot_port & renamed auth_server_port_number.
+ * root.c (parse_cvsroot): Parse the new CVSROOT format properly.
+ Incidentally reformated some error messages for uniformity and
+ readability.
+ * sanity.sh (crerepos): fix two tests which were now expecting the
+ wrong error message.
+
+2000-10-11 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (pserver_authenticate_connection): Fix stupid mistake
+ in previous change.
+
+2000-10-11 Derek Price <derek.price@openavenue.com>
+
+ * main.c (main): Dispose old CVSroot when parsing a '-d' option if
+ free_CVSroot is set.
+ * root.c (parse_cvsroot): remove references to 'cvsroot_parsed', a
+ static boolean I expect hasn't been used since CVS learned to handle
+ multiple CVSROOTs.
+
+2000-10-10 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (print_error): Make up a message if strerror fails.
+
+ * server.c (pserver_authenticate_connection): Give a real error
+ message for an invalid repository.
+
+2000-10-06 Derek Price <derek.price@openavenue.com>
+
+ * add.c (add): Made quiet mode affect some warning messages as seemed
+ appropriate. Specifically, some of the messages which a user might
+ want to ignore so they don't have to be quite so specific on the
+ command line: files added twice, files already in the repository and
+ check out properly (i.e. but picked up by 'cvs add *'), & files which
+ are readded in place of a dead revision or onto a branch. '-q' will
+ not change the non-zero exit code for the cases where at least one
+ passed in file name was already in the Entries file. There seems to
+ be a precedent in remove.c.
+ * remove.c (cvsremove): switched the "use cvs ci to make these changes
+ permanent message" to only print w/o '-Q' to match the new behavior of
+ add. This seems appropriate as '-Q' is defined to restrict messages
+ to critical errors.
+ * sanity.sh (adderrmsg): Added some tests for the above behavior.
+
+2000-10-05 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (call_in_directory): Create CVSADM directory if it doesn't
+ exist in the directory. This makes client/server work more like
+ standalone when checking out into an existing (non-CVS) directory.
+ * sanity.sh (dirs2, conflicts3, toplevel): Update to match.
+
+2000-10-03 Larry Jones <larry.jones@sdrc.com>
+
+ * filesubr.c (get_homedir): Ignore $HOME when running in server mode.
+
+2000-10-02 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.h: Define (and use) T_PATCH as a valid file classification
+ even when SERVER_SUPPORT isn't defined -- it simplifies the code.
+ * classify.c (Classify_File): Ditto.
+ * commit.c (check_fileproc): Ditto.
+ * status.c (status_fileproc): Ditto.
+ * update.c (update_fileproc): Ditto.
+ * tag.c (check_fileproc): Accept T_PATCH in addition to T_CHECKOUT.
+ * sanity.sh (tagc-10): Update to match.
+
+2000-09-29 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (get_responses_and_close): Reset server_fd to -1 after
+ shutting down.
+ (Reported by Joerg Thoennes <Joerg.Thoennes@data-sciences.de>.)
+
+2000-09-27 Larry Jones <larry.jones@sdrc.com>
+
+ * commit.c (commit): Don't sleep before returning in server mode,
+ just let the client do it.
+ * update.c (do_update): Ditto.
+
+ * sanity.sh (find_tool): Correct method of checking for GNU tools.
+
+ * checkout.c (checkout_proc): Match up user directories with
+ repository directories instead of using Emptydir.
+ * sanity.sh (cvsadm, emptydir): Update to match.
+
+2000-09-19 Larry Jones <larry.jones@sdrc.com>
+
+ * version.c: Push version number to 1.11.0.1.
+
+ * version.c: Version 1.11.
+
+2000-09-07 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@
+ from autoconf.
+
+2000-08-23 Larry Jones <larry.jones@sdrc.com>
+
+ * mkmodules.c (init): Create an empty val-tags file if it doesn't
+ already exist to avoid problems with users not having sufficient
+ permissions to create it later.
+
+2000-09-06 Jim Kingdon <jkingdon@dhcp-net200-89.su.valinux.com>
+
+ * main.c (lookup_command_attribute): Add "release" to commands
+ which can be done by a read-only user.
+
+2000-08-23 Larry Jones <larry.jones@sdrc.com>
+
+ * repos.c (Name_Repository): Use pathname_levels to detect attempts
+ to get above the repository instead of checking for leading ..
+ which isn't reliable.
+ * sanity.sh (multiroot3-12 to multiroot3-15): New tests for above.
+
+2000-08-21 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (expand_keywords): Handle the unusual case of log == NULL.
+ (Reported by Craig Metz <cmetz@inner.net>.)
+
+2000-08-01 Larry Jones <larry.jones@sdrc.com>
+
+ * subr.c (pathname_levels): Fix bug that miscounts adjacent
+ slashes.
+ (Patch submitted by Tanaka Akira <akr@m17n.org>.)
+
+ * loginc.c (login): If available, use getpassphrase instead of
+ getpass to support long passwords on Solaris.
+
+2000-07-28 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (server_noop): Avoid do_cvs_command() overhead.
+ (requests): Make noop RQ_ROOTLESS.
+
+2000-07-27 Noel Cragg <noel@red-bean.com>
+
+ * root.c (parse_cvsroot): change fork method to behave like other
+ remote methods -- let the server check that the repository
+ directory is an absolute pathname.
+
+2000-07-27 Larry Jones <larry.jones@sdrc.com>
+
+ * lock.c (set_lock): Include actual lock directory in error message.
+ * sanity.sh (multiroot3-10): Change to match.
+
+ * sanity.sh (client-3): Allow for a potential "broken pipe".
+
+2000-07-26 Larry Jones <larry.jones@sdrc.com>
+
+ * commit.c (commit_filesdoneproc): Flush stdout before running script.
+ * modules.c (do_module): Ditto.
+ * update.c (update_dirleave_proc): Ditto.
+ * server.c (do_cvs_command): Give input from the protocol pipe
+ precedence over input from stdout/stderr. There's no particularly
+ good justification for this other than helping to avoid out-of-order
+ messages in sanity.sh.
+
+ * admin.c (admin_usage): Add the supported options.
+
+ * sanity.sh (info): Try to avoid out-of-order messages.
+
+ * sanity.sh (info): Fix problems when running twice in a row.
+
+2000-07-17 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (modules5-7, cvsadm-1e, emptydir-2): Allow for a nil
+ commit (can happen if the test is run twice in a row).
+
+2000-07-19 Pavel Roskin <proski@gnu.org>
+ and Larry Jones <larry.jones@sdrc.com>
+
+ * mkmodules.c (config_contents): Add a commented out example for
+ LockDir. Don't suggest PreservePermissions unless it's enabled.
+
+2000-07-17 Larry Jones <larry.jones@sdrc.com>
+
+ * login.c (get_cvs_password): Handle malformed ~/.cvspass more
+ gracefully.
+
+2000-07-12 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (modules5): New tests for module programs.
+
+2000-07-11 Larry Jones <larry.jones@sdrc.com>
+
+ * filesubr.c (copy_file, xcmp): Handle systems (like Plan 9) that
+ don't support mknod() and/or st_rdev.
+ * import.c (add_rcs_file): Ditto.
+ * rcs.c (RCS_checkout, RCS_checkin): Ditto.
+ * update.c (special_file_mismatch): Ditto.
+
+2000-07-10 Larry Jones <larry.jones@sdrc.com>
+
+ * zlib.c (gunzip_and_write): Fix type clashes.
+
+ * main.c (main): Remove unused variables.
+
+2000-07-10 Jim Meyering <meyering@lucent.com>
+
+ When a command like `cvs update -kk -jT1 -jT2' creates a new file
+ (because it had the T2 tag, but not T1), the subsequent commit of
+ that just-added file would effectively set the admin `-kk' option
+ for that file in the repository.
+
+ * update.c (join_file): Rename global-shadowing local `options'
+ to `t_options'.
+ Set file-scoped global `options' to NULL just before
+ check-out.
+ * sanity.sh (join-admin): New test for this.
+
+2000-07-08 Larry Jones <larry.jones@sdrc.com>
+
+ * version.c, cvs.h (version): New function.
+ * main.c (cmds[]): Add version command to invoke it.
+ (main): Also use it in -v.
+ * server.c (serve_version): New function.
+ (requests[]): Add version command to invoke it.
+
+2000-07-06 Karl Fogel <kfogel@red-bean.com>
+
+ * sanity.sh (pserver-14): remove this test for portability
+ reasons (it was only recently added for the 2000-07-04 change).
+
+2000-07-06 Larry Jones <larry.jones@sdrc.com>
+
+ sanity.sh (modules-148): Don't test for specific revisions.
+
+ * main.c (main): Catch SIGABRT to try to clean up after assertion
+ failures. Don't bother SIG_register'ing Lock_Cleanup because
+ main_cleanup calls it indirectly anyway.
+ * patch.c (patch): Catch SIGABRT.
+ * rcs.c (rcs_internal_lockfile): Ditto.
+ * server.c (server): Ditto.
+
+ * fileattr.c (fileattr_write): Don't delete the unrecog_head list
+ when writing...
+ (fileattr_free): Delete it when freeing!
+
+2000-07-05 Larry Jones <larry.jones@sdrc.com>
+
+ * admin.c (admin): Handle -t in client so reading from files works
+ correctly in client/server mode.
+ * sanity.sh (log2): Update to match.
+
+2000-07-04 Karl Fogel <kfogel@red-bean.com>
+
+ * server.c (pserver_authenticate_connection): use new
+ getline_safe() during authentication phase, to avoid a
+ denial-of-service attack in which client sends arbitrary
+ amounts of data with no newlines.
+ (Reported by <jpmg@eng.cam.ac.uk>.)
+
+ * sanity.sh: new test pserver-14 for above.
+
+ * myndbm.c: #include getline.h.
+ (mydbm_load_file): pass new GETLINE_NO_LIMIT flag to getstr().
+
+2000-07-03 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (modules): Rewrite using dotest. Add "modules-"
+ prefix to test names.
+
+2000-06-28 Larry Jones <larry.jones@sdrc.com>
+
+ * error.c (error_exit): Call rcs_cleanup () to release any rcs locks.
+ * rcs.c, rcs.h (rcs_cleanup): Make public, close file before trying
+ to remove (some systems won't remove open files).
+ (RCS_putdtree): Don't worry about cleaning up before call error
+ since it now does it for us.
+ (rcs_internal_lockfile, rcs_internal_unlockfile): Keep track of
+ lock file fd for rcs_cleanup ().
+
+ * client.c (handle_set_checkin_prog, handle_set_update_prog):
+ Just ignore the request when exporting.
+
+2000-06-27 Larry Jones <larry.jones@sdrc.com>
+
+ * create_adm.c, cvs.h (Create_Admin): Add dotemplate argument.
+ Change all callers.
+ * checkout.c (checkout_proc): Don't create CVS/Template if
+ exporting.
+
+2000-06-26 Pavel Roskin <proski@gnu.org>
+ and Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (switch_to_user): Only set CVS_Username if
+ AUTH_SERVER_SUPPORT is defined.
+
+2000-06-23 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (send_dirent_proc): Don't allocate ignlist if you're
+ going to skip the directory (plugs memory leak).
+ (send_dirleave_proc): New function.
+ (send_files): Use it (plugs memory leak).
+ * root.c (root_allow_free): Plug memory leaks.
+ * server.c (serve_directory, serve_notify, check_password,
+ pserver_authenticate_connection): Ditto.
+ * update.c (update): Ditto.
+
+ This completes the memory leak shoot-out -- the Purify'ed version
+ of CVS now runs the entire test suite, both local and remote (except
+ for remote crerepos, which causes Purify to choke) with *no* memory
+ leaks.
+
+ * server.c (pserver_authenticate_connection): Don't free null pointer.
+
+2000-06-21 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (update_entries, get_responses_and_close): Plug memory leaks.
+ * commit.c (find_fileproc, commit): Ditto.
+ * import.c (import): Ditto.
+ * log.c (cvslog): Ditto.
+ * recurse.c (start_recursion): Ditto.
+ * remove.c (cvsremove): Ditto.
+ * server.c (fd_buffer_initialize, server_notify, do_cvs_command): Ditto.
+ (fd_buffer_shutdown): New function.
+
+2000-06-20 Larry Jones <larry.jones@sdrc.com>
+
+ * root.c (parse_cvsroot): Put the terminating NUL byte into the
+ string *before* copying it, not after. :-(
+
+2000-06-19 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (main): Plug memory leaks.
+ * root.c (parse_cvsroot, set_local_cvsroot): Ditto.
+ * server.c (serve_root): Ditto.
+
+2000-06-16 Larry Jones <larry.jones@sdrc.com>
+
+ * fileattr.c (fileattr_read): Plug memory leak.
+ * rcs.c (RCS_whatbranch): Ditto.
+ * update.c (update_dirleave_proc): Ditto.
+
+ * ignore.c (ign_dir_add): Duplicate string so caller can free.
+
+ * modules.c (do_module): Don't write into dbm's memory!
+
+2000-06-15 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (checkout_proc): Fix non-ANSI code in call to
+ findslash(), minor cleanups.
+
+2000-06-14 Larry Jones <larry.jones@sdrc.com>
+
+ * tag.c (val_direntproc): Return R_PROCESS instead of 0.
+
+ * client.c (update_entries): Fix type clash calling gunzip_and_write().
+ * server.c (receive_file): Fix type clash calling gunzip_and_write().
+ (server_updated): Fix type clash calling buf_output().
+ * error.c (error): Make buf char instead of unsigned char to avoid
+ type clashes.
+
+ * modules.c (do_module): Change callback_proc to pass argc by
+ value instead of by reference: callback procs shouldn't be
+ messing with the callers argc/argv, it makes correct memory
+ management impossible. Plug memory leaks.
+ * cvs.h: Change to match.
+ * checkout.c (checkout_proc): Ditto; use a local argv array instead
+ of messing with caller's.
+ * modules.c (callback_proc): Ditto.
+ * patch.c (patch_proc): Ditto; use a local argv array instead
+ of messing with caller's.
+ * rtag.c (rtag_proc): Ditto; use a local argv array instead
+ of messing with caller's.
+ * server.c (expand_proc): Ditto.
+ * subr.c (line2argv): Change initial argv_allocated back to 1.
+
+ * checkout.c (findslash): Fix non-ANSI code.
+
+ * sanity.sh (modes3): Fix test names.
+
+2000-06-13 Larry Jones <larry.jones@sdrc.com>
+
+ * add.c (add): Plug memory leaks.
+ * admin.c (admin_fileproc): Ditto.
+ * checkout.c (build_dirs_and_chdir): Ditto.
+ * edit.c (editors_fileproc): Ditto.
+ * log.c (cvslog, log_parse_revlist, log_parse_date): Ditto.
+ * rcs.c (RCS_addaccess): Ditto.
+ * tag.c (check_fileproc): Ditto.
+ * vers_ts.c (Version_TS): Ditto.
+ * watch.c (watchers_fileproc): Ditto.
+
+2000-06-12 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (rcsbuf_valword): Set rcsbuf->vlen to keep rcsbuf_valcopy()
+ from allocating more memory than needed for @ strings. Don't declare
+ unless PRESERVE_PERMISSIONS_SUPPORT (since not defined).
+
+ * rcs.c (RCS_abandon): New function to abandon changes.
+ * rcs.h: Declare it.
+ * admin.c (admin_fileproc): Use it instead of RCS_reparsercsfile.
+
+ * commit.c (commit_fileproc): Fix memory leaks.
+ * patch.c (patch_fileproc): Ditto.
+ * rcs.c (RCS_nodeisbranch, RCS_copydeltas): Ditto.
+ * tag.c (tag_fileproc): Ditto.
+ * update.c (update): Ditto.
+
+2000-06-09 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_reparsercsfile, RCS_fully_parse, getdelta,
+ RCS_getdeltatext): Handle newphrases with composite values.
+ (rcsbuf_getkey): Don't remove @s in composite values -- it makes
+ it impossible to parse the value! Set special flag to indicate
+ a composite value.
+ (rcsbuf_valcopy, rcsbuf_valpolish_internal): Handle composite values.
+ (putrcsfield): Write composite values.
+ (RCS_checkin): Set node types in other_delta list.
+ * hash.h: Add RCSCMPFLD.
+ * hash.c (nodetypestring): Ditto.
+
+ * rcs.c (getdelta): Never allocate space for value, just return
+ pointer into rcsbuf (fixes memory leaks). Use rcsbuf_getkey to
+ read a key and value and then parse the value if needed rather
+ than trying to read it in bits and pieces with rcsbuf_getid,
+ rcsbuf_getstring, and rcsbuf_getword.
+ (RCS_reparsercsfile): Change callers to compensate.
+ (rcsbuf_valcmp, rcsbuf_valword): New functions.
+ (rcsbuf_getid, rcsbuf_getstring, rcsbuf_getword): Deleted.
+ * sanity.sh (rcs3-1): Now get slightly different error message.
+
+2000-06-08 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (usg): Update CVS home page URL.
+
+ * main.c (main): Provide an actual error message for an unknown
+ command in addition to the usage message.
+
+2000-06-07 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (serve_root, dirswitch, serve_repository,
+ serve_static_directory, serve_sticky, receive_partial_file,
+ receive_file, serve_modified, server_write_entries, serve_notify,
+ serve_checkin_prog, serve_update_prog, server): Don't set
+ pending_error before calling alloc_pending, it makes it fail;
+ use alloc_pending instead of malloc when reasonable; be sure to
+ save errno before calling functions that might change it.
+ (Patch submitted by Dietmar Petras <dietmar.petras@elsa.de>.)
+
+2000-06-03 Larry Jones <larry.jones@sdrc.com>
+
+ * commit.c (checkaddfile): Plug memory leak.
+ * rcs.c (RCS_checkin): Plug memory leaks.
+ * server.c (do_cvs_command): Plug file descriptor leaks.
+ * tag.c (check_fileproc): Plug memory leak.
+
+2000-05-26 Larry Jones <larry.jones@sdrc.com>
+
+ * recurse.c (unroll_files_proc): Plug memory leak.
+
+ * recurse.c (addfile): Fix nonportable pointer cast.
+
+ * rcs.c (rcsbuf_getstring, rcsbuf_getword, getdelta): Plug memory
+ leaks.
+
+2000-05-25 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (checkout, build_one_dir, checkout_proc): Move m_type
+ to file scope and use it instead of continually doing strcmp on
+ command_name.
+ (build_one_dir, checkout_proc): Don't allow export if CVSADM
+ directory already exists.
+
+2000-05-23 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_checkin, RCS_cmp_file): Plug memory leaks. (Patch
+ submitted by Chris G. Demetriou <cgd@sibyte.com>.)
+
+2000-05-20 Ian Lance Taylor <ian@zembu.com>
+
+ * client.c (connect_to_gserver): Handle server error messages
+ reasonably.
+
+2000-05-19 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (requests): Make Global_option RQ_ROOTLESS so it can be
+ used with init.
+
+2000-05-18 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (start_server): Don't do encryption, authentication,
+ compression, or case insensitivity when doing init because init
+ is ROOTLESS and they're not.
+
+ * client.c (connect_to_pserver): Include repository and username in
+ authorization failed message -- if a directory tree crosses multiple
+ repositories, it can be quite difficult for the user to figure out
+ which one is the problem.
+
+2000-05-17 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (main): Use full set of options when looking for -f to
+ avoid misparsing options that take values (previously, -sVAR=foo
+ was incorrectly parsed as though it were -s -V -A -R -= -f -o -o
+ because it didn't know that -s takes a value).
+ * sanity.sh (info-6b): New test for above.
+
+ * sanity.sh (conflicts-status): Fix tests so they work remotely, too.
+
+2000-05-17 Jim Meyering <meyering@lucent.com>
+
+ * sanity.sh (TESTDIR): Fix braino in last change:
+ cd to /tmp before invoking pwd.
+
+ * sanity.sh: Set TESTDIR so that `make check' passes even when /tmp
+ is a symlink.
+ (join-36): Use $TESTDIR rather than hard-coding `/tmp/cvs-sanity'.
+ (conflicts-132): Remove unnecessary `rm aa'.
+
+2000-05-16 Jim Kingdon <kingdon@redhat.com>
+
+ * cvs.h, checkout.c (safe_location): Make extern.
+ * import.c (import): Call it rather than reimplementing
+ (incompletely) the same check.
+
+2000-05-16 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.h, subr.c (file_has_markers): Check for any of the three
+ conflict marker lines, not just one.
+ * sanity.sh (conflicts-status): New tests for above.
+ * sanity.sh: Revise to avoid tripping the above check when merging
+ changes into sanity.sh itself.
+
+2000-05-15 Larry Jones <larry.jones@sdrc.com>
+
+ * update.c (join_file): When registering the result of the merge,
+ make sure that the version number is valid (vers->vn_rcs may be
+ null if the file doesn't exist on the branch yet). (Patch submitted
+ by Robert de Vries <rhdv@rhdv.cistron.nl>.)
+ * update.c (join_file): Correct diagnostics (previous change was not
+ correct -- the file *does* exist in the specified revision, it just
+ doesn't exist in the sandbox).
+ * sanity.sh (import-113, join): New tests and changes for above.
+
+2000-05-04 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Look for a useful id program. Since we're getting
+ the real username for some tests anyway, use it for all the
+ tests instead of a generic regular expression that may or may
+ not match the actual username.
+
+2000-05-04 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c: More error messages.
+
+2000-05-02 Donald Sharp <sharpd@cisco.com>
+ and Larry Jones <larry.jones@sdrc.com>
+
+ * history.c (report_hrecs): Added code to print out year instead of
+ just month/day.
+ * sanity.sh (basic2-64, history): Update to match.
+
+2000-04-19 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (dirswitch): Set pending_error_text in addition to
+ pending_error to aid in problem determination.
+
+2000-03-23 Larry Jones <larry.jones@sdrc.com>
+
+ * mkmodules.c (mkmodules): Return without doing anything if noexec
+ is set to avoid trashing existing files.
+
+2000-03-23 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c: Alphabetize cmds[] and cmd_usage[] and add server
+ commands to cmd_usage[].
+
+2000-03-21 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (client-1): May get "Broken pipe" message from the
+ "server" in addition to the expected output.
+
+2000-03-17 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (switch_to_user): Set CVS_Username if it hasn't already
+ been set elsewhere. (Patch submitted by Gordon Matzigkeit
+ <gord@fig.org>).
+
+2000-03-13 Larry Jones <larry.jones@sdrc.com>
+
+ * parseinfo.c: Add extern to logHistory declaration. (Reported by
+ <John.Tytgat@aaug.net>.)
+ (parse_config): Reformat logHistory code.
+
+2000-03-10 Larry Jones <larry.jones@sdrc.com>
+
+ * add.c (add): Don't try to set cvsroot_len until after checking
+ for help only -- CVSroot_directory isn't set in that case.
+
+2000-03-03 Larry Jones <larry.jones@sdrc.com>
+
+ * mkmodules.c (init): Use mkdir_if_needed to create CVSROOT/Emptydir
+ so we don't fail if run multiple times. (Reported by KOIE Hidetaka
+ <hide@koie.org>.)
+ * sanity.sh (1a): New test for above.
+
+2000-03-02 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c: Use identical #if's in the command table and the code
+ for pserver and kserver to prevent "peculiar" configurations from
+ having really perverse behavior because the command table entries
+ are present but the related code isn't.
+
+2000-03-01 Larry Jones <larry.jones@sdrc.com>
+
+ * import.c (import): Don't allow importing the repository.
+ * sanity.sh (errmsg2-20, errmsg2-21): New tests for above.
+
+2000-03-01 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (main): Update year in copyright message.
+
+2000-03-01 Larry Jones <larry.jones@sdrc.com>
+
+ * logmsg.c (do_editor): Correct previous change.
+
+2000-02-29 Larry Jones <larry.jones@sdrc.com>
+
+ * logmsg.c (do_editor): When reading temp file, check that message
+ buffer is large enough to hold the next line and expand if needed.
+
+2000-02-28 Larry Jones <larry.jones@sdrc.com>
+
+ * commit.c (commit): Use get_file() to read log file correctly
+ and in text mode rather than binary mode.
+
+ * subr.c (get_file): Ignore bufsize if buf is NULL. Include
+ terminating NUL byte when estimating required buffer size.
+
+2000-02-28 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (find_tool): New function to replace duplicated code.
+
+2000-02-25 Larry Jones <larry.jones@sdrc.com>
+
+ * import.c (add_rcs_file): Don't abort just because lstat fails.
+
+2000-02-16 Jim Meyering <meyering@lucent.com>
+
+ Avoid race condition whereby a catchable signal could
+ end up corrupting the repository.
+ * commit.c (checkaddfile): Put a critical section around the code
+ that handles the first commit on the trunk of a file that's already
+ been committed on a branch.
+ * cvs.h (Sig_inCrSect): Declare new function.
+
+2000-02-21 Karl Fogel <kfogel@red-bean.com>
+
+ * main.c (main): still check for repository, but not history file
+ (correction to 2000-02-18 change -- that's what I get for
+ believing the comment rather than the code).
+
+2000-02-21 K.J. Paradise <kj@sourcegear.com>
+
+ * history.c mkmodules.c parseinfo.c: control which actions
+ get logged to the cvs history file via CVSROOT/config file
+ and LogHistory keyword. (John P Cavanaugh <cavanaug@sr.hp.com>)
+
+2000-02-18 Karl Fogel <kfogel@red-bean.com>
+
+ * history.c (history_write): don't die if history file not
+ writable, just warn (unless `really_quiet') and skip out.
+
+ * main.c (main): don't bother checking if history file is
+ writable.
+
+ * server.c (serve_root): same.
+
+2000-02-17 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (perms symlinks symlinks2 hardlinks): Don't run by
+ default since PreservePermissions code is now disabled.
+
+2000-02-17 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (import-113): Revise to match Jim Meyering's fix.
+
+2000-02-16 Larry Jones <larry.jones@sdrc.com>
+
+ * add.c (add): Don't allow adding files or directories to Emptydir.
+ (Patch submitted by Chris Cameron <chris.cameron@ot.co.nz>.)
+ * sanity.sh (emptydir): Revise (emptydir-7 and emptydir-8) for this.
+
+2000-02-16 Jim Meyering <meyering@lucent.com>
+
+ * update.c (join_file): Correct typo in diagnostic:
+ change `file %s is present...' to `file %s is not present...'.
+
+2000-02-10 Larry Jones <larry.jones@sdrc.com>
+
+ * parseinfo.c (Parse_Info): Treat matching lines with bad expansions
+ as errors rather than just ignoring.
+
+2000-02-10 Larry Jones <larry.jones@sdrc.com>
+
+ * edit.c (edit): Check for invalid characters in hostname and CurDir.
+ (Reported by "Andrew S. Townley" <atownley@informix.com>.)
+ * sanity.sh (devcom2): New tests for above.
+
+2000-02-10 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.h: Always #include "server.h" to prevent compile errors when
+ neither CLIENT_SUPPORT nor SERVER_SUPPORT is defined.
+ (Reported by "Crow, Ian" <ian.crow@linklaters.com>.)
+ * log.c (send_one, send_arg_list): Only define when CLIENT_SUPPORT
+ is defined to prevent link errors.
+
+ * server.c (server): Always create a new temporary directory, don't
+ try to reuse an existing one since we might not have correct
+ permissions. Also, include directory name in error messages.
+
+2000-01-29 Jim Kingdon <http://developer.redhat.com/>
+
+ * ignore.c (ignore_files): Correctly set errno to 0 when we go
+ back to the top of the loop. Fixes spurious errors like "cvs
+ update: error reading current directory: No such file or
+ directory".
+
+2000-01-26 Larry Jones <larry.jones@sdrc.com>
+
+ * run.c (run_exec): Conditionalize K.J.'s change so that it only
+ applies when SETXID_SUPPORT is defined since some platforms don't
+ have setegid().
+
+2000-01-26 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Make TESTDIR earlier then use it to check for versions
+ of expr that don't work right with long expressions.
+
+ * sanity.sh (dotest_line_by_line): Have wc read from stdin so it
+ doesn't output the file name and confuse expr. Make the output a
+ bit less verbose and easier to read.
+
+2000-01-24 K.J. Paradise <kj@sourcegear.com>
+
+ * run.c :> prevents a user from creating a privileged shell from the
+ text editor when the SETXID_SUPPORT option is selected. This came from
+ Bob Colle <bcolle@ilx.com>, and is his completely.
+
+2000-01-22 Jim Kingdon <http://developer.redhat.com/>
+
+ * sanity.sh (emptydir): Add a case in which one might hope for a
+ non-Emptydir result, but which result?
+
+2000-01-18 Larry Jones <larry.jones@sdrc.com>
+
+ * main.c (main): Allow -z0 to disable gzip compression.
+
+2000-01-17 Larry Jones <larry.jones@sdrc.com> for
+ K.J. Paradise (kj@sourcegear.com)
+
+ * version.c: Push version number to 1.10.8.1.
+
+ * version.c: Version 1.10.8.
+
+2000-01-17 Larry Jones <larry.jones@sdrc.com>
+
+ * mkmodules.c (init): Create CVSROOT/Emptydir to avoid problems
+ with users not having sufficient permissions to create it later.
+
+2000-01-04 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (get_responses_and_close): Simplify time-stamp race
+ avoidance code.
+ * commit.c (commit): Ditto.
+ * update.c (do_update): Ditto.
+ (Prompted by patch submitted by Pavel Roskin
+ <pavel_roskin@geocities.com>.)
+
+ * hardlink.c: sizeof (char) is 1, by definition.
+ * logmsg.c: Ditto.
+ * rcs.c: Ditto.
+
+2000-01-03 Karl Fogel <kfogel@red-bean.com>
+
+ * filesubr.c, subr.c (backup_file): moved this function from
+ filesubr.c to subr.c, at JimK's suggestion.
+
+2000-01-03 Jim Kingdon <http://developer.redhat.com/>
+
+ * sanity.sh (clean): Test the contents of the .#cleanme.txt.1.1
+ file, not just its existence.
+
+2000-01-03 Karl Fogel <kfogel@red-bean.com>
+
+ * cvs.h, filesubr.c (backup_file): use `const' for suffix too;
+ correct suffix length calculation and appending behavior; discard
+ unnecessary `void' cast. Thanks to Jim Meyering for noticing.
+
+2000-01-03 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (clean): Fix up expected output.
+
+2000-01-02 John P Cavanaugh <cavanaug@sr.hp.com>
+ and Karl Fogel <kfogel@red-bean.com>
+
+ New -C option to update: overwrites local changes with clean
+ copies from the repository. (This is an unreversion of the
+ 1999-12-10 change, further modified to work remotely.)
+
+ * client.h (BACKUP_MODIFIED_FILES): new #define.
+
+ * client.c (struct send_data): new element `backup_modified'.
+ (send_files): set above element if BACKUP_MODIFIED_FILES flag is
+ present.
+
+ * filesubr.c (backup_file): new function.
+
+ * cvs.h: prototype for new function `backup_file'.
+
+ * update.c (toss_local_changes): new file-scoped global.
+ (update): set toss_local_changes if -C flag seen. If
+ client_active, send "-C" to server, and set SEND_NO_CONTENTS and
+ BACKUP_MODIFIED_FILES flags before calling send_files().
+
+ (update_fileproc): if file is modified and toss_local_changes is
+ set, then back the file up and then check out a fresh copy from
+ the repository. Also, fixed indentation and formatting for a
+ particularly bad stretch of code near (but unrelated to) these
+ changes.
+
+ * sanity.sh: new test `clean', for update -C option.
+
+1999-12-29 Jim Kingdon <http://developer.redhat.com/>
+
+ * history.c (read_hrecs): st_blksize is unsigned long, not int.
+ This isn't just cosmetic - getting it wrong will cause coredumps
+ and such on 64 bit machines.
+
+ * import.c (import_descend), ignore.c (ignore_files): Placate gcc
+ -Wall by parenthesizing foo || (bar && baz).
+
+1999-12-24 Larry Jones <larry.jones@sdrc.com>
+
+ * release.c (release): Use fputs to echo lines from update instead
+ of printf to avoid problems with lines containing "%". (Reported
+ by Jean-Luc Simard <Jean-Luc.Simard@matrox.com>.)
+
+ * history.c (read_hrecs): Allocate a single 2-block buffer instead
+ of allocating and freeing a buffer for each block.
+ (fill_hrec): Remove redundant code.
+ (select_hrec): Plug memory leak.
+
+1999-12-22 Larry Jones <larry.jones@sdrc.com>
+
+ * history.c (history): For "modified" or "checkout", sort on
+ file if user specified -l, even if user also specified a date-
+ oriented flag.
+ * sanity.sh (history): Update to match; add new tests.
+
+1999-12-15 Pavel Roskin <pavel_roskin@geocities.com>
+ and Larry Jones <larry.jones@sdrc.com>
+
+ * lock.c (lock_name): fixed assertion failure for the
+ top-level CVS directory when LockDir is used
+ * sanity.sh (lockfiles-9): new test for this case
+
+1999-12-11 Karl Fogel <kfogel@red-bean.com>
+
+ * Revert previous change -- it doesn't work remotely yet.
+
+1999-12-10 John P Cavanaugh <cavanaug@sr.hp.com>
+ and Karl Fogel <kfogel@red-bean.com>
+
+ * update.c: new -C option to update, overwrites local changes with
+ clean copies from the repository.
+ Also, fixed indentation and formatting for a particularly bad
+ stretch of code near these changes in update_fileproc().
+
+ * sanity.sh: test new update -C option.
+
+1999-12-10 Larry Jones <larry.jones@sdrc.com>
+
+ * commit.c (remove_file): Call history_write with update_dir NULL
+ like Checkin() does for add and modify.
+ * sanity.sh (basic2-64): Update to match, add "R" records to expected
+ remote output.
+
+1999-12-09 K.J. Paradise (kj@sourcegear.com)
+
+ * history.c, commit.c, sanity.sh: found (I think) final
+ cause of seg fault in history command. Also, added the "R"
+ history functionality. Fixed basic2-64 so it looks correct for
+ the change.
+
+1999-11-30 K.J. Paradise (kj@sourcegear.com)
+
+ * history.c: fixed seg fault caused by 11-03 changes.
+ off by one in block memory allocations.
+
+1999-11-29 Karl Fogel <kfogel@red-bean.com>
+
+ * login.c (logout): free `tmp_name' when done.
+ Correct a comment.
+
+1999-11-29 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.h, error.c, import.c: Rename fperror to avoid name clash
+ on LynxOS. (Reported by Markus Braun <MarkusBraun@gmx.de>.)
+
+1999-11-23 Larry Jones <larry.jones@sdrc.com>
+
+ * checkout.c (checkout_proc): Split declaration and initialization
+ of rp to placate neurotic compilers that gripe about jumping past
+ an initialization, even when the variable is not subsequently used.
+
+1999-11-19 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (switch_to_user): Correct setgid error messages.
+
+1999-11-19 Karl Fogel <kfogel@red-bean.com>
+
+ * edit.c (unedit_usage, unedit): new struct, use it. Now "cvs
+ unedit" prints an accurate usage message (formerly it printed the
+ message for "cvs edit", even though the two commands do not have
+ identical usages).
+
+1999-11-19 Larry Jones <larry.jones@sdrc.com>
+
+ * history.c: Move -e documentation from Flags to Reports.
+ (history): Add -e to list of report types in error message.
+
+ * history.c (history): Process file arguments before client/server
+ processing so they get sent to the server.
+ * sanity.sh (history): New tests for above. (Also remove comments
+ about variable spacing -- history output is in variable-width
+ columns with exactly one space between.)
+
+1999-11-19 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Reestablish check for running as root (using ``id -u''
+ instead of ``whoami'').
+
+ * sanity.sh(dotest, dotest_lit, dotest_fail, dotest_status,
+ dotest_sort): Eval the command so quoting and pipes work right.
+ (spacefiles, dirs, rcslib, modules, unedit-without-baserev,
+ ignore, rcs, rcs2, history, tagdate, pserver, server, server2)
+ Simplify various tests based on above.
+
+1999-11-19 Karl Fogel <kfogel@red-bean.com>
+
+ * mkmodules.c (init): make history file world-writeable after
+ creating it, since it needs to be writeable for virtually any
+ CVS operation.
+
+1999-11-10 Jim Kingdon <http://developer.redhat.com/>
+
+ * admin.c: Revert change to add -H command option. The help
+ invocation is "cvs -H admin" not "cvs admin -H" (see cvs.texinfo,
+ basicb-21 in sanity.sh; fix to cvs.1)
+
+1999-11-08 Jim Kingdon <http://developer.redhat.com/>
+
+ * log.c (cvslog): If client_active, send options to the server
+ based on our parsed options rather than trying to send the exact
+ strings specified (using canonical forms, like RFC822/1123
+ dates, in the protocol is just cleaner).
+ (send_one, send_arg_list): New functions, helpers for above.
+ * sanity.sh (logopt-6a): New test, for this fix.
+
+1999-11-09 K.J. Paradise <kj@sourcegear.com>
+
+ * admin.c: made the -H option do what it is documented to
+ do. a
+
+1999-11-08 Tom Tromey <tromey@cygnus.com>
+
+ * client.c (connect_to_gserver): Print more error text if gssapi
+ initialization fails. From Assar Westerlund <assar@sics.se>.
+
+1999-11-06 Larry Jones <larry.jones@sdrc.com>
+
+ *sanity.sh(rcs3-5): Remote output can be out-of-order, so need a
+ more general pattern to match the assertion failure.
+
+1999-11-05 K.J. Paradise (kj@sourcegear.com)
+
+ * history.c: Added a trap to verify that if a
+ read(file, buffer,blocksize) returns less than blocksize,
+ that we really are at the end of the file. I can't easily
+ come up with a test case where this code gets touched, so
+ it may cause problems. All sanity tests still pass though.
+
+1999-11-05 Jim Kingdon <http://developer.redhat.com/>
+
+ * sanity.sh (logopt): New test, for Larry's fix.
+ * sanity.sh (log-18a, rcs-15 to rcs-19): New tests, to test -d
+ and -r more thoroughly.
+
+1999-11-05 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (cvslog): Fix -s and -d with spaces on client side.
+ (log_usage): Revert Karl's change once again.
+ sanity.sh(rcs3-5): No longer get different results from local
+ and client/server.
+
+1999-11-04 Karl Fogel <kfogel@red-bean.com>
+
+ * log.c (log_usage): Revert Jim Kingdon's reversion of my change
+ of 1999-11-03. Allowing a space between option and argument
+ results in lossage; here is a reproduction recipe: run this from
+ the top of a remote copy of the cvs source tree
+
+ cvs log -d '>1999-03-01' > log-out.with-space
+
+ and then run this (note there's no space after -d now):
+
+ cvs log -d'>1999-03-01' > log-out.no-space
+
+ The resulting files differ; furthermore, a glance at the output of
+ cvs shows that the first command failed to recurse into
+ subdirectories. Until this misbehavior can be fixed in the source
+ code, the documentation should reflect the true state of affairs:
+ if one simply omits the space, everything works fine.
+
+1999-11-04 Jim Kingdon <http://developer.redhat.com/>
+
+ * log.c (log_usage): Revert Karl's change regarding -d and
+ -s. A space is allowed (see sanity.sh for example).
+
+1999-11-03 K.J. Paradise (kj@sourcegear.com>
+
+ * history.c: cleaned up my prior change a bit, per Larry Jones'
+ comments, and John O'Conner's additional comments about bits of
+ non MS-Visual C++ compliancy of my code.
+
+1999-11-04 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Check that tr that correctly handles NULs; if not, try
+ to find a version that does; if none can be found, warn user.
+ Also fix warnings for defective expr.
+
+1999-11-04 Karl Fogel <kfogel@red-bean.com>
+
+ Changes for empty/random passwords in anon pserver access:
+
+ * server.c (check_repository_password): if password empty, grant
+ access no matter what password is received; this is so anon CVS no
+ longer requires a password but remains backwards-compatible with
+ all those clients out there.
+
+ * client.c (connect_to_pserver): proceed with login even if
+ password not found in .cvspass file -- just use empty string as
+ password. And if such a login fails, print a descriptive error.
+
+ * login.c (get_cvs_password): don't complain if file or password
+ not found. That condition is no longer a showstopper, now that
+ empty passwords are permissible.
+ Cleaned up conditional chaining a bit, too.
+
+ * sanity.sh (pserver-9, pserver-10, pserver-11, pserver-12,
+ pserver-13): new tests, about empty-password pserver access.
+
+1999-11-03 K.J. Paradise (kj@sourcegear.com>
+
+ * history.c: modify parsing routines to parse the history
+ file a block at a time, rather than all at once. This allows
+ people with large history files and small amount of memory
+ to still get some functionality out of the history file.
+
+1999-11-03 Karl Fogel <kfogel@red-bean.com>
+
+ * log.c (log_usage): correct usage message for -d and -s options.
+ Because the space between the option letter and its argument has
+ been eliminated, I capitalized the argument portion to distinguish
+ it from the option letter. This makes it slightly inconsistent
+ with other such usage summaries, but at least it is now both
+ correct and readable.
+
+1999-10-22 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (dotest_sort): Old versions of tr don't understand \t
+ so use a literal tab instead.
+
+1999-10-21 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (dotest_sort): Convert any tabs in the output into spaces
+ before sorting to avoid POSIX.2 sort weirdness.
+ (import-106, importb-2): Change expected output per above.
+
+1999-10-18 K.J. Paradise <kj@sourcegear.com>
+
+ Bug: users 'stan' and 'cartman' both have full read/write access
+ to the cvs repository. 'cartman' does a 'cvs admin -l foo.c'.
+ 'stan' then does a 'cvs admin -u foo.c'. The lock wouldn't be
+ removed, and no warning/error would be given. This is now fixed.
+ * rcs.c:(c.6157) remove caller/user check on the multiple lock
+ detection routines. Sanity.sh runs with no errors after this fix.
+
+1999-10-14 Larry Jones <larry.jones@sdrc.com>
+
+ Make "cvs admin -e" (with no list of users) work:
+ * admin.c (admin): Remove error message.
+ (admin_fileproc): If no args for -e, call RCS_delaccess with NULL user.
+ * rcs.c (RCS_delaccess): Interpret NULL user as request to delete
+ entire access list.
+ * sanity.sh (admin-19a-*): Test.
+
+1999-09-29 Larry Jones <larry.jones@sdrc.com>
+
+ * entries.c (Subdirs_Known): Use entfilename when opening CVSADM_ENTLOG
+ like everywhere else. Although this isn't strictly necessary (since
+ we immediately close it again), it keeps the code consistent and fixes
+ a bug where an open error reported the wrong file name.
+
+1999-09-16 Larry Jones <larry.jones@sdrc.com>
+
+ * log.c (log_parse_revlist): Handle peculiar revision specs like
+ "-r.", "-r:", and "-r," correctly. (Thanks to Pavel Roskin
+ <pavel_roskin@geocities.com> for submitting a patch, this fix is
+ somewhat different.)
+ * sanity.sh (log): New tests for above.
+
+1999-09-15 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (basica-8b1): New test to check fix for bad diff options
+ causing cvs to crash.
+
+1999-09-02 Larry Jones <larry.jones@sdrc.com>
+
+ * modules.c (do_module): Handle case where module definition has
+ options and special options but no directory; fix potential problems
+ running off beginning of string while stripping trailing blanks.
+ * sanity.sh (modules2): New tests for above.
+
+1999-08-26 Larry Jones <larry.jones@sdrc.com>
+
+ * lock.c (lock_name): Remove side-effects from assert() expression
+ since they won't occur if NDEBUG is defined (not that that's a good
+ thing to do). (Reported by KOIE Hidetaka <hide@koie.org>.)
+
+1999-08-25 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Use "${AWK}" instead of "awk" to make it easier for
+ people to use nawk/gawk/etc.; use an explicit "-print" with find
+ since some older version don't assume it; rename tests to avoid
+ duplicate importc-8. (Changes along these lines suggested by
+ Chris Cameron <chris.cameron@ot.co.nz>.)
+
+1999-08-24 Larry Jones <larry.jones@sdrc.com>
+
+ * commit.c (check_fileproc): Don't crash when a file has no
+ repository, just treat it as unknown. (Reported by Stefaan
+ Diericx <stefaan.diericx@argenta.be>.)
+ * sanity.sh (errmsg2): New tests, for this fix.
+
+1999-08-18 Larry Jones <larry.jones@sdrc.com>
+
+ * update.c (special_file_mismatch): Initialize *_hardlinks to
+ avoid trying to free garbage later on. (Reported by Jan
+ Scheffczyk <herta@Xterminator.StudFB.UniBw-Muenchen.de>.)
+
+1999-08-17 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (basicc-11): Older versions of sh don't understand
+ ``if ! test...''. (Patch submitted by David J N Begley
+ <david@avarice.nepean.uws.edu.au>.)
+
+1999-08-17 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c, hardlink.c, hash.c, hash.h, main.c, recurse.c: Change
+ enum constant UNKNOWN to avoid conflicts on HPUX 11.0. (Reported
+ by Laurent Duperval <laurent.duperval@cgi.ca>.)
+
+1999-08-16 Larry Jones <larry.jones@sdrc.com>
+
+ client.c: Eliminate redundant #if. (Patch submitted by Assar
+ Westerlund <assar@sics.se>.)
+
+1999-07-30 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_checkin): Terminate cleanly if RCS_addbranch fails
+ rather than blithely continuing on and crashing.
+ * sanity.sh (basica): New tests, for this fix.
+
+1999-07-29 Larry Jones <larry.jones@sdrc.com>
+
+ * import.c (add_rcs_file): change "cannot lstat" message to include
+ userfile (the actual file causing the problem) instead of user
+ (which may or may not be the same).
+
+1999-07-29 Eric Sink <eric@sourcegear.com>
+
+ * version.c: Push version number to 1.10.7.1.
+
+ * version.c: Version 1.10.7.
+
+1999-07-28 Eric Sink <eric@sourcegear.com>
+
+ * sanity.sh: before running basicc-11, we need to see if
+ the cwd has been deleted (by basicc-8). If so, we
+ recreate it to allow basicc-11 to proceed. This may be
+ something that only happens under the Linux 2.2 kernel.
+
+1999-07-18 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * edit.c (notify_do): chop newline, if any, from the value
+ obtained from CVSROOT/users. Otherwise it just gets passed along
+ in the argument to the notification program (usually mail), which
+ will misinterpret it as signifying the end of the command.
+
+1999-07-19 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_delete_revs): In the WIN32 kludge, be sure that the result
+ of RCS_getexpand is not NULL before trying to use what it points to.
+ (Patch submitted by Timothy L. Taylor <ttaylor@mitre.org>.)
+
+1999-07-16 Tom Tromey <tromey@cygnus.com>
+
+ * admin.c (admin): Allow `-k' options to be used unrestricted.
+
+1999-06-23 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (symlinks2): New test, for symlinks in working
+ directory without PreservePermissions. This test (modulo a few
+ details not relevant to testing whether we are following symlinks)
+ worked remote as of now, or either remote or local for CVS 1.9.
+ * subr.c (get_file): Revert 1998-02-15 change to special-case
+ symlinks. This makes the above test work local too.
+ * rcs.c (RCS_checkin): Move the logic to handle special-case
+ symlinks (and other files other than regular files) here, and make
+ it only happen if PreservePermissions is on.
+
+1999-06-18 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (devcom3-9a): Be less specific about the expected
+ error message (BSD/OS 4.0 has a bug that can cause exec* to fail
+ with EACCES instead of ENOENT).
+
+1999-06-08 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (diff-4, dirs2-10, tagf-13, importc-7, conflicts2-142b8):
+ Use ${PROG} instead of "cvs".
+
+1999-06-05 Jim Kingdon <http://www.cyclic.com>
+
+ * recurse.c (do_recursion, do_dir_proc): Make the SERVER_ACTIVE
+ #ifdef be only around the check for server_active. Modulo a few
+ cosmetic tweaks, same as a patch submitted by Johannes Stezenbach
+ of propack-data.de.
+
+1999-06-01 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh: Add comment about rcs2-7 failures on certain days.
+
+ Make "cvs status -v" on a removed file work:
+ * status.c (cvsstatus): Reindent the client code.
+ (status_fileproc): Don't need a CVS/Entries listing to show the
+ tags.
+ * sanity.sh (rmadd2): New test rmadd2-16 tests the existing
+ behavior with "cvs log"; new test rmadd2-17 tests the new behavior
+ with "cvs status".
+
+ * sanity.sh (basicc): To match no output in dotest, put the empty
+ regexp first. Remove tests which check that first-dir exists,
+ since that isn't true in the case where the OS let us delete it.
+ (dotest_internal): Fix so that things work with two regexps, with
+ an empty one first.
+
+1999-05-28 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (server-4): Replace bogus directory with real one since
+ the server now checks it.
+
+1999-05-27 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (spacefiles): Clean up -c, top, and -b at end.
+ (spacefiles, files): Fix bad references to CVSROOT_DIRNAME.
+
+ Fix two problems pointed out by Olaf Kirch of swb.de/caldera.de:
+ * server.c (outside_root): New function, contains expanded version
+ of code from serve_directory.
+ (serve_directory): Call outside_root.
+ (outside_dir): New function
+ (serve_modified, serve_is_modified, serve_notify,
+ serve_questionable, serve_unchanged): Call outside_dir.
+ * sanity.sh (server2): New tests, for these fixes.
+
+1999-05-26 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.h, subr.c (xmalloc): Return void* not char*, like xrealloc
+ has done for some time.
+ * modules.c (do_module): If we find the module as a directory/file
+ (rather than in the modules file), skip a bunch of processing
+ which was unnecessary and also broken in most of the cases
+ now tested for by the spacefiles sanity.sh test.
+ * sanity.sh (spacefiles): New test, for specifying filenames
+ (containing spaces, or starting with '-', or starting with '/') to
+ "cvs co".
+
+1999-05-25 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (update_entries): Make the old DONT_USE_PATCH code the
+ only code. This means that if people are still on CVS 1.9
+ servers, then CVS will fall back to transferring entire files.
+ This is better than looking for an external "patch" program which
+ causes no end of troubles (especially on Windows, but someone just
+ posted to info-cvs about a problem with the Solaris patch). (This
+ change was run by devel-cvs and feedback was positive).
+
+ * subr.c (xmalloc, xrealloc): The new error.c does not support
+ %lu; use sprintf instead.
+
+1999-05-25 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh (server): Escaped a few more newlines in
+ another awk script. Solaris awk still don't like 'em.
+
+1999-05-25 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ and Jim Kingdon
+
+ * log.c: Remove comment which said "you can delete [this line]"
+ and which stuck around for over 3 years.
+ * sanity.sh (errmsg2 & tagdate): Added tests to prove the
+ current functionality with respect to combining -r and -D.
+
+1999-05-20 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (pserver_authenticate_connection): Previous changes
+ broke verify_and_exit (reported by Robert Fitzsimons, thanks).
+ * sanity.sh (pserver): New tests pserver-7 and pserver-8 for this.
+
+1999-05-18 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh (keyword2): Escaped a newline in an awk script.
+ Apparently Solaris awk don't like 'em.
+
+1999-05-18 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (basicc): Allow the behavior whereby unlink(".")
+ succeeds. Reported by Jeremy Buhler and Pavel Roskin.
+
+1999-05-17 Steve Cameron of Compaq
+
+ * sanity.sh: Modified to no longer use "test -e" for existence
+ test as it has turned out to be not portable enough. Instead use
+ "test -f", "test -d", etc.
+ [SCO Unixware 7 apparently doesn't always support it -kingdon]
+
+1999-05-17 Jim Kingdon <http://www.cyclic.com>
+
+ * version.c: Push version number to 1.10.6.1.
+
+ * version.c: Version 1.10.6.
+
+1999-05-16 Jim Kingdon <http://www.cyclic.com>
+
+ * update.c (patch_file): When we are passing vn_rcs to
+ RCS_checkout, pass vn_tag as well.
+ * sanity.sh (keyword): In test keyword-22, test for the fixed
+ behavior rather than the buggy behavior. Adjust keyword-23. Add
+ test keyword-24, to see whether keyword-23 really worked.
+
+1999-05-12 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (pserver-4, pserver-5): Bogus error messages from
+ non-root initgroups on some 4.4BSD derived systems now show up
+ in different places in the output.
+
+1999-05-12 Jim Kingdon <http://www.cyclic.com>
+
+ * import.c (import): Don't allow the user to supply a repository
+ directory which takes us out of the cvsroot.
+ * sanity.sh (importc): New tests importc-10 to importc-12, for this.
+
+1999-05-11 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (serve_notify): Allocate enough memory to hold the
+ "misformed Notify request" message in pending_error_text.
+
+1999-05-11 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (switch_to_user): Ignore EPERM from initgroups. Fixes
+ pserver-4 in testsuite.
+ (pserver_authenticate_connection): Only print "I LOVE YOU" after
+ switch_to_user has come back successfully.
+
+ * server.c (pserver_authenticate_connection): Call error_exit
+ rather than reinventing the wheel ourselves.
+ (switch_to_user): Check for errors from setuid, setgid, and
+ initgroups. Fix the #ifdef's (the previous code would skip the
+ setuid call if SETXID_SUPPORT).
+
+1999-05-10 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (serve_notify), edit.c (notify_do): Check for
+ and reject characters which will get confused with delimiters.
+ * sanity.sh (server): New tests server-7 through server-15 test
+ for this and for other notify behaviors.
+
+ * rcs.c (RCS_tag2rev): Also look for a physical branch with
+ RCS_getversion.
+ * sanity.sh (tagf): Adjust tagf-12 and following tests to test for
+ the fixed behavior rather than the broken behavior.
+
+1999-05-07 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (server_notify): Also set last_node to NULL.
+ * sanity.sh (server): New tests server-6 and server-7, for this.
+
+1999-05-05 Jim Kingdon <http://www.cyclic.com>
+
+ * rcs.c (rcs_internal_lockfile): Remove unused variable lockfile.
+
+ * add.c (add): Look for directories with the same name in a
+ different case where appropriate (analogous to fopen_case).
+ In client code, add comment about how this doesn't do quite
+ everything.
+
+1999-05-03 Jim Meyering <meyering@ascend.com>
+
+ Remove rcs-style ,file, lock files upon signal.
+ * rcs.c (rcs_lockfile): New file-scoped global.
+ (rcs_cleanup): New function (similar to patch_cleanup).
+ (rcs_internal_lockfile): Register rcs_cleanup the first time this
+ function is called. Rename uses of local `lockfile' to refer to new
+ global, `rcs_lockfile'. Don't free the lock file name string, now
+ that it's global.
+ (rcs_internal_unlockfile): Rename `lockfile', as above, and carefully
+ free and NULL-out the global, rcs_lockfile.
+
+1999-04-30 Jim Kingdon <http://www.cyclic.com>
+
+ * rcs.c (annotate_fileproc): Don't cast NULL in passing it to
+ RCS_deltas. Because there is a prototype in scope the cast is
+ unnecessary (per HACKING's ANSI C or SunOS4 rule), and in fact it
+ was causing failures on UNICOS because it cast to size_t instead
+ of size_t*. (Thanks to Dean Kopesky for reporting this).
+
+1999-04-29 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh: If invoked without any arguments, print a usage
+ message (thanks to Pavel Roskin for a report/patch).
+
+ * run.c (piped_child): Make the error messages more verbose.
+ (close_on_exec): Reindent.
+ * sanity.sh (devcom3): Several errors are possible in devcom3-9a.
+ Adjust for change to piped_child error message.
+
+1999-04-28 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (devcom3): Add some tests of the CVS/Notify file and
+ disconnected "cvs edit".
+
+ * main.c (opt_usage): Remove -b.
+
+1999-04-20 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * rcs.c (RCS_delete_revs): RCS_delete_revs uses an
+ RCS_checkout call to get a new copy of a revision to be
+ used internally after old revisions were deleted and it was
+ performing keyword substitutions. This munged all the
+ the revisions of the file on the branch containing the
+ deleted revisions and its sub-branches, as the original they
+ were being patched from was incorrect. Corrected this by
+ passing in "-ko" as an option to RCS_checkout.
+ * sanity.sh (keywordlog): modified this test to verify the
+ correct behavior of 'cvs admin -o'.
+ [Fixed use of \$ in keywordlog test; added code in RCS_delete_revs
+ to abort on binary file on Windows -kingdon]
+
+1999-04-21 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ and Jim Kingdon
+
+ * tag.c (tag_check_valid): A bug was causing CVS to spin
+ indefinately when -j:<date> was specified. CVS now returns
+ an error.
+ * sanity.sh: Added a test (tagdate-12) to test this.
+
+1999-04-19 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (backuprecover): Clean up the repository at the end.
+
+1999-04-18 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh added a test (backuprecover) to test cvs behavior
+ with a repository that is out of date relative to the
+ developer's workspaces.
+ [Fix --keep code; move test to "Repository Storage" section since
+ it doesn't really exercise the diff/diff3 library. -kingdon]
+
+1999-04-13 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh (diff): Tests to verify correct operation of
+ the --ifdef parameter to cvs diff.
+ [indentation fixed -kingdon].
+
+1999-04-13 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ for Noah Friedman <friedman@splode.com>
+
+ * diff.c (diff): Put "--ifdef=" in opts string, not "-D"; the
+ latter is confused by pserver for a date spec.
+
+1999-04-14 Jim Kingdon <http://www.cyclic.com>
+
+ * fileattr.h: Adjust comments to reflect the official version of
+ the fileattr format now being in cvs.texinfo.
+
+1999-04-05 Jim Kingdon
+
+ * sanity.sh (watch5): Remove nonstandard --keep code. Don't pass
+ -f to rm when cleaning up (that tends to mask bugs). Add watch5
+ to list of tests at start. Add comment explaining why we consider
+ the behavior we test for the right one. Rename a few tests which
+ had been erroneously named watch6* instead of watch5*.
+ * client.c (update_entries): Add comment with brief discussion of
+ whether there is a better way.
+
+1999-04-05 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * client.c (update_entries): Only call mark_up_to_date
+ (which deletes the CVS/Base/<filename> file for watched
+ and edited files) on commit.
+ * sanity.sh: Make sure the CVS/Base/<filename> file for
+ a watched and edited file is not removed on a status or
+ update of a touched/unmodfied file.
+
+1999-03-30 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (get_responses_and_close), commit.c (commit),
+ update.c (do_update): If the sleep(1) call returns prematurely
+ (due to the way wakeup is scheduled or receiving a signal), do
+ it again.
+
+1999-03-26 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (server): Add comment about Gzip-stream vs. RQ_ROOTLESS.
+
+ * sanity.sh (modules3-11b): Adjust exact text of error message to
+ reflect 1999-03-24 change to dirswitch.
+
+1999-03-25 Jim Kingdon <http://www.cyclic.com>
+
+ * admin.c (admin): Make argument to -e optional, to match the
+ documentation.
+ * sanity.sh (admin-19a-2): Test for this.
+
+ * server.c (serve_root): Update comment about checking for missing
+ Root request.
+
+1999-03-24 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (dirswitch): Also check dir here, similar to
+ what server_pathname_check does for other cases.
+ * sanity.sh (files): Adjust files-14 to test for this.
+
+1999-03-24 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ and Jim Kingdon
+
+ * sanity.sh: added a test (files-13) to test .. indirection
+ in a path and another (files-14) to make sure we still fail
+ out when the '..' indirection takes us into the $CVSROOT
+ directory or beyond.
+
+1999-03-24 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c: Change enum constants ADD and DELETE to something less
+ likely to run into conflicts.
+
+1999-03-21 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (tagf): New test, tests for moving a branch tag to a
+ non-branch tag and trying to recover.
+
+1999-03-12 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (branches): Tweak test branches-5 to test the case in
+ which one modifies a file and then branches it.
+
+1999-03-09 John Bley of duke.edu
+
+ * mkmodules.c (filelist): Missed a NULL in this struct (should
+ have 3 members, only had 2).
+
+1999-03-07 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (Index): Rename new test from rm_CVS/Root to rmroot
+ (we don't have a formal rule about funky punctuation in test names
+ but both underscore and a slash is too funky for me :-)).
+ Reindent a few tests which were off.
+
+ * root.c: Remove the sentence which had the improper English;
+ there isn't really a need for that sentence and it isn't
+ particularly accurate any more.
+
+1999-02-27 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh: Added rm_CVS/Root test to test that CVS uses
+ $CVSROOT rather than dumping core when running remotely and
+ the admin file CVS/Root is deleted from the workspace.
+
+ Also, altered a few 'cvs commit' 's in regular expressions to
+ fit the .${PROG} commit. portability syntax.
+
+ * recurse.c: Stopped CVS from dumping core in the case tested
+ above.
+
+ * root.c: Fixed somebody's improper english.
+
+1999-02-25 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (keyword2-12): Use ${QUESTION} instead of ? in the
+ expected result.
+
+1999-02-24 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (keyword2): Restore the original \\\$ instead of $.
+ The latter ends up working due to various kludgy semantics in the
+ shell and regular expressions, but the former is cleaner.
+
+ * sanity.sh (keyword2): Protect keywords against accidental
+ expansion in sanity.sh itself (most occurrences had this, but not
+ all).
+
+1999-02-23 Derek Price <http://www.cyclic.com>
+ and Jim Kingdon.
+
+ * sanity.sh (keyword2): New test, tests for merging with -kk.
+
+1999-02-22 Jim Kingdon <http://www.cyclic.com>
+
+ * version.c: Ease version number to 1.10.5.1.
+
+ * version.c: Version 1.10.5.
+
+1999-02-18 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (files): New test, for a relatively obscure spurious
+ "Up-to-date check failed" in client/server.
+
+ * main.c (lookup_command_attribute): Don't check for "history"
+ twice.
+
+1999-02-17 Jim Kingdon <http://www.cyclic.com>
+ and Hallvard B Furuseth
+
+ * root.c (parse_cvsroot): Rearrange ifdefs to squelch possible
+ warnings about statement not reached.
+
+1999-02-16 Jim Kingdon <http://www.cyclic.com>
+
+ * recurse.c (start_recursion): If we are skipping the current
+ directory (due to it being from the wrong repository), also adjust
+ the arguments we send to the server accordingly (like we already
+ do for the case in which there is no CVS directory).
+ * sanity.sh (multiroot4): New test, for this. All these tests had
+ passed locally, but remote multiroot4-12 tests for this fix.
+ (multiroot): Adjust multiroot-diff-1, multiroot-update-2,
+ multiroot-tag-1, multiroot-status-1, multiroot-update-3, and
+ multiroot-log-1 to reflect the cosmetic change this produces (one
+ less "Diffing ." message).
+ (multiroot2): multiroot2-8 likewise.
+
+1999-02-10 Jim Kingdon <http://www.cyclic.com>
+
+ * tag.c (cvstag): Don't pass SEND_NO_CONTENTS if -c specified.
+ * sanity.sh (tagc): New test, for various tag -c behaviors.
+ Test tagc-6 tests for this fix.
+
+1999-02-09 Jim Kingdon <http://www.cyclic.com>
+
+ * error.c (error): Rewrite to no longer use vasprintf (see
+ ../lib/ChangeLog for rationale). Note the slight change in
+ interface - callers which want %8.8s or similar formats need to
+ call sprintf.
+ * lock.c (lock_wait, lock_obtained): Use sprintf.
+
+1999-02-08 Jim Kingdon <http://www.cyclic.com>
+
+ * rcs.c (RCS_delete_revs): Pass -a to diff_exec.
+ * sanity.sh (binfiles3): New tests binfiles3-9 through
+ binfiles3-13 test for this fix.
+ * sanity.sh (binfiles): New tests binfiles-o4 and binfiles-o5
+ (which don't test this bug, just on general principles).
+
+1999-02-04 Jim Kingdon <http://www.cyclic.com>
+
+ * lock.c (lock_name): Permissions of directories in LockDir
+ shouldn't depend on the umask.
+ * sanity.sh (lockfiles): Set umask and CVSUMASK, to test for this.
+
+1999-02-01 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (keywordlog): New tests keywordlog-22 and
+ keywordlog-23 test keyword expansion and $Log. Adjust other tests
+ so that revisions differ more from each other, so this is a
+ better test.
+
+1999-01-29 Jim Kingdon <http://www.cyclic.com>
+
+ * commit.c (checkaddfile): If options is "", treat it the same as
+ NULL. Centralize this check, and the one for it starting with
+ "-k", at the start of the function.
+
+ * rcs.c, rcs.h (RCS_setexpand): New function.
+ * admin.c (admin_fileproc): Access keyword expansion field via
+ RCS_getexpand and RCS_setexpand, rather than directly.
+ * commit.c (checkaddfile): When resurrecting, set the keyword
+ expansion mode.
+ * sanity.sh (binfiles3): Adjust tests binfiles3-7 and binfiles3-8
+ for the new behavior.
+
+1999-01-27 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (multiroot3): Add new variant of multiroot3-10 test
+ for RELATIVE_REPOS. Move multiroot3-11 test out of the
+ conditionals; it works the same for remote or local,
+ RELATIVE_REPOS or no.
+
+ * options.h.in: Make RELATIVE_REPOS the default, as has been
+ announced as a future direction since 1997-10-11.
+ * sanity.sh (multiroot): Tweak multiroot-update-1a and
+ multiroot-update-1b tests to work with either RELATIVE_REPOS or
+ non-RELATIVE_REPOS.
+
+ * sanity.sh (client-9): Don't assume the time zone.
+
+1999-01-26 Jim Kingdon <http://www.cyclic.com>
+
+ Fix one facet of the "cvs add -kb" re-adding problem (the other
+ known facet is tested for by binfiles3-8).
+ * add.c (add): When re-adding a file, set the keyword expansion
+ as we normally would.
+ * sanity.sh (binfiles3): New test binfiles3-6a tests for this.
+
+1999-01-22 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (rmadd2): New tests, for undoing a commit.
+
+1999-01-21 Eric Mumpower <nocturne@cygnus.com>
+
+ * sanity.sh (reposmv): Actually modify CVSROOT in current
+ environment when calling functions, rather than trying to achieve
+ the same effect with "CVSROOT=foo functionname". (Many common
+ bourne shells, including those in SunOS and Solaris 2.4-2.7,
+ do not properly handle "ENVVAR=foo command" when "command" is
+ a user-defined shell function rather than an actual executable.)
+
+1999-01-15 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (rcs3): Redirect awk's stdin to /dev/null like all the
+ other awk invocations. GNU awk seems not to read stdin in this
+ case, but that behavior is hard to reconcile with the Single Unix
+ Spec and some awks don't do it.
+
+ * sanity.sh (binfiles, binfiles2, binfiles3, server): Use the same
+ tr trick as in rcs3. People don't seem to have been complaining,
+ and this should fix server-4 for HPUX.
+
+1999-01-14 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (recv_line): If the line we are reading contains a
+ character which would sign-extend to EOF, don't treat it as end of
+ file. recv() doesn't report end of file this way and this might
+ fix bugs with 0xff characters.
+
+1999-01-14 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (recv_line): Handle EOF from server.
+
+ * sanity.sh (importc-8, importc-9): Accept anything in the seconds
+ fields of the timestamps since touch doesn't set it reliably.
+ (This isn't great, but it's better than nothing.)
+
+1999-01-14 Jim Kingdon <http://www.cyclic.com>
+
+ * run.c (run_exec): Adjust comment about vfork; this isn't the place
+ to get into a treatise about fork performance vs. vfork
+ performance but it isn't quite as simple as whether one has
+ copy-on-write.
+
+1999-01-13 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (dotest_fail): Handle spurrious output from assert better.
+
+ * sanity.sh (rcs3-4, rcs3-5a): Handle even more variants of the
+ assertion failure message.
+
+1999-01-12 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (mtfr-3): ls behavior varies wildly on nonexistant files,
+ just use echo instead.
+
+1999-01-11 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (mkmodules-temp-file-removal): New test, for this.
+ * mkmodules.c (mkmodules): Remove each `CVSROOT/.#[0-9]*' temporary
+ file that's used to check out files listed in CVSROOT/checkoutlist.
+ Remove extra semicolon at end of line.
+
+1999-01-11 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (rcs3-5a): Allow for multiple lines of output before the
+ assertion failure message.
+
+ * sanity.sh (lockfiles-6, client-8): Work around bug in HP-UX chmod
+ (doesn't allow anything to follow omitted permissions).
+
+1999-01-09 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (set_sticky): Nonfatal error if we can't write it.
+ * sanity.sh (dirs2-8 through dirs2-14): New tests, for this.
+
+ * sanity.sh (rcs3): Write NUL character with tr not awk, in
+ accordance with Single Unix Specification. Hopefully will fix
+ rcs3-7 for HPUX. Will not work on SunOS4, but then again neither
+ did the old syntax.
+
+1999-01-05 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c, update.c: Rename MD5* functions to cvs_MD5* per
+ corresponding change to ../lib/md5.h.
+
+1999-01-03 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (client): Give file1 a predictable mode so that the
+ output in client-9 will not depend on the umask of the user
+ running the tests.
+
+1998-12-29 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (client_senddate): Use date_to_internet rather than
+ using our own "5/26/1997 13:01:40 GMT" date format.
+ * main.c (date_to_internet): Check for errors from sscanf. Always
+ send a four digit year. Send hours, minutes, and seconds as two
+ digits per RFC822.
+ * sanity.sh (client): New tests client-8 and client-9 test for this.
+
+ * sanity.sh (rcs2): New tests rcs2-6 through rcs2-8 test for fix
+ to lib/getdate.y (before the fix, "100 months" or "8 years" would
+ tend to mean the year 1969, thus the tests would give "cvs update:
+ file1 is no longer in the repository").
+
+1998-12-28 Larry Jones <larry.jones@sdrc.com>
+
+ * entries.c (Register): Return if unable to open log file to avoid
+ referencing the invalid file pointer.
+ * sanity.sh (dirs2-7): With above change, no longer fails.
+ * sanity.sh (rcs3-5a): Another assertion failure message.
+ * sanity.sh (pserver-4, pserver-5): Some 4.4BSD derived systems spit
+ out bogus error messages when initgroups is called as non-root.
+
+1998-12-23 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (rcs3, dotest_fail): The assertion failure message varies
+ wildly between different systems and the resulting abort call can
+ even result in spurrious output. Fix the regexp to accept nearly
+ anything containing some kind of assertion failure and ensure that
+ any spurrious output ends up in the output file instead of on the
+ terminal.
+
+1998-12-23 Jim Kingdon <http://www.cyclic.com>
+
+ * admin.c, checkout.c, commit.c, cvsrc.c, expand_path.c,
+ history.c, ignore.c, import.c, log.c, mkmodules.c, modules.c,
+ myndbm.c, parseinfo.c, rcs.c, remove.c, rtag.c, status.c, subr.c,
+ tag.c, wrapper.c: Cast all char's to unsigned char before passing
+ them to ctype.h functions (isalpha, isgraph, isalnum, isspace,
+ isdigit, isprint, isupper). Whether using ctype.h is the right
+ thing at all is unclear to me (having the server depend on locale
+ seems wrong, as we don't necessarily have any good way to set the
+ right locale, if there even is such a concept as 'right' locale in
+ this context), but as long as we use ctype.h we might as use it
+ according to the standards (this affects systems where plain char
+ is signed but users supply characters with the 8th bit set).
+ Thanks to Paul Eggert for suggesting this.
+
+1998-12-22 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (rcs3): Oops, the earlier fix for srcdir only fixed
+ the non-remote case, not the remote case. Fix the other occurrence.
+
+1998-12-22 Jim Kingdon
+
+ * sanity.sh (rcs3): The assertion failure message varies slightly
+ depending on whether CVS was built with srcdir != ".". Fix regexp.
+
+1998-12-21 Jim Kingdon
+
+ * rcs.c (RCS_getdate): Reindent Jim Meyering's change; remove
+ unused variable x_vers.
+
+ * rcs.c: When printing an unexpected character we found in the RCS
+ file, print it in hex rather than as a character (see comment for
+ rationale).
+ * sanity.sh (rcs3): Adjust rcs3-2 and rcs3-7 tests accordingly.
+
+ * sanity.sh (rcs3): New test, for some error handling cases
+ involving parsing RCS files.
+
+1998-12-16 Jim Meyering <meyering@ascend.com>
+
+ * rcs.c (RCS_getdate): Handle the case in which a file is first
+ imported after its initial version has been created.
+ * sanity.sh (import-after-initial): New test for that.
+
+1998-12-17 Jim Kingdon
+
+ * server.c (serve_root): Pserver_Repos only exists if
+ AUTH_SERVER_SUPPORT is defined.
+
+1998-12-12 Jim Kingdon, and Derek R. Price of Stortek.
+
+ * sanity.sh (multiroot): Change + to ${PLUS}.
+
+1998-12-12 Jim Kingdon, and Gary Young of Motorola
+
+ * sanity.sh (admin): In tests admin-13, admin-25, and admin-29,
+ allow 4 digit year in addition to 2 digit year.
+
+1998-12-12 Jim Kingdon
+
+ * sanity.sh (log): New tests log-14a and log-14b test for -rHEAD
+ and for HEAD as (nonexistent) file name.
+
+1998-12-02 Jim Kingdon
+
+ * version.c: Squish version number to 1.10.4.1.
+
+ * version.c: Version 1.10.4.
+
+1998-11-24 Jim Kingdon
+
+ * recurse.c (do_file_proc): Check for errors from RCS_parse.
+ * sanity.sh (rcslib-symlink-7 through rcslib-symlink-10): New
+ tests, test for this.
+
+ * sanity.sh (reposmv-2): Adjust for 22-Nov change to Find_Names.
+
+ * entries.c (Register): If we can't write Entries.Log, make it a
+ nonfatal error.
+ * sanity.sh (dirs2): Test for this fix.
+
+ * sanity.sh (dirs2): Clean up working directory at end of test.
+
+1998-11-23 Jim Kingdon
+
+ * sanity.sh (dirs2): New test, for some more cases involving
+ deleting directories and such.
+
+ * sanity.sh (dirs): Update for yesterday's change in Find_Names
+ error handling. The error in dirs-4 is fairly different now; in
+ dirs-3 and dirs-3a it is the obvious change.
+
+1998-11-22 Jim Kingdon
+
+ * sanity.sh (release): Move the commments listing "cvs release"
+ tests from modules2-6 to here.
+ * release.c (release): Update comment to reflect "? foo" case.
+
+ * find_names.c (Find_Names): If we can't read the repository, make
+ it a nonfatal error. Tell the caller whether this happened.
+ (find_rcs): Add comment regarding this behavior.
+ * recurse.c (do_recursion): If Find_Names gives an error, skip
+ the directory and print a message saying so.
+ * sanity.sh (modes3): New test, for this.
+
+1998-11-18 Jim Kingdon
+
+ * rtag.c (rtag_usage), tag.c (tag_usage): Use "-r rev"
+ consistently.
+
+ * sanity.sh (conflicts3): Tests conflicts3-24 through
+ conflicts3-28 test for another case similar to conflicts3-22.
+
+1998-11-14 Jim Kingdon
+
+ * sanity.sh (diff): New test, for now just tests for the "I know
+ nothing" message.
+
+ * sanity.sh (conflicts2-142b7 through conflicts2-142b11): New
+ tests; resurrecting doesn't work from one level up.
+
+ * sanity.sh (mwrap-7): Remote prints the messages in a different
+ order.
+
+1998-11-13 Jim Kingdon
+
+ * tag.c (check_fileproc): Log tag deletions.
+ * rtag.c (check_fileproc): Likewise.
+ * sanity.sh (taginfo-14 through taginfo-18): New tests, for
+ these behaviors.
+
+1998-11-12 Jim Kingdon
+
+ * sanity.sh (mwrap-7): Update for the noexec fix.
+
+ * server.c (server_copy_file): Add comment about noexec.
+
+ * update.c (checkout_file): Handle noexec case involving revbuf
+ and modes.
+ (update_fileproc): In case T_NEEDS_MERGE, let merge_file take care
+ of noexec, so it can tell the user if there would be conflicts.
+ (merge_file): Print "conflicts found in FILE" message
+ regardless of noexec. Add comment about checking for whether the
+ file already contained the changes, and noexec.
+ * sanity.sh (conflicts-192a): New test, for this.
+
+1998-10-20 Jim Kingdon
+
+ Use the gzip library on the server. Probably doesn't speed things
+ up as currently implemented, but does avoid hassles in terms of
+ finding an external gzip program.
+ * zlib.c, server.h (gunzip_and_write, read_and_gzip): Now returns
+ whether a fatal error occurred, rather than expecting error (1,
+ ...) to work.
+ * client.c (update_entries, send_modified): Change callers.
+ * server.c (receive_file): Rewrite gzip code to use
+ gunzip_and_write rather than filter_through_gunzip.
+ (server_updated): Likewise, use read_and_gzip rather than
+ filter_through_gzip.
+ * client.c, client.h (filter_through_gzip, filter_through_gunzip),
+ run.c, cvs.h (filter_stream_through_program): Removed; no longer used.
+ * sanity.sh (server): New tests server-4 and server-5 test
+ this feature (note that CVS 1.10 also passes these tests; the
+ behavior is supposed to be unchanged).
+
+1998-10-19 Jim Kingdon
+
+ * sanity.sh (multiroot3): New test, tests for a few more
+ multiroot cases.
+
+ * lock.c (lock_name): Set the permissions on each directory we
+ create to that of the parent directory.
+ * sanity.sh (lockfiles): New chmod and tests lockfiles-7a and
+ lockfiles-7b test for this. Adjust lockfiles-5 for new text of
+ error message.
+
+1998-10-15 Jim Kingdon
+
+ * server.c (requests): Set RQ_ROOTLESS for "Set".
+ * sanity.sh (info): Also clean up $HOME/.cvsrc.
+ (server): Test that we can send Set before Root (had been tested
+ by crerepos-6b, but only if you ran the info test first). Tests
+ for this fix.
+
+1998-10-14 Jim Kingdon
+
+ * subr.c (expand_string): Tweak the algorithm so that the size
+ that it allocates is generally a power of two.
+
+1998-10-14 Eivind Eklund and Jim Kingdon
+
+ * commit.c (commit): For the client, don't worry about whether we
+ are root.
+
+1998-10-13 Jim Kingdon
+
+ * server.h (struct request): Change status field to flags and add
+ RQ_ROOTLESS.
+ * client.c (handle_valid_requests, supported_request): Change
+ status to flags.
+ * server.c (requests): Change status to flags. Add RQ_ROOTLESS.
+ * server.c (server): If not RQ_ROOTLESS, and we haven't gotten a
+ Root request, give an error.
+
+1998-10-12 Jim Kingdon
+
+ * version.c: Slide version number to 1.10.3.1.
+
+ * Version 1.10.3.
+
+ * sanity.sh (modules2-17): Update for 9 Oct 1998 change to
+ update_dirent_proc.
+
+1998-10-11 Jim Kingdon
+
+ * commit.c (checkaddfile, commit_fileproc): A numeric value for
+ 'tag' does not mean that we are adding on a branch.
+ * sanity.sh (keywordlog): Adjust this test, to test for this
+ (replaces comment saying we should be doing it).
+ (rmadd): Likewise.
+
+ * sanity.sh (rmadd): New test, tests for various existing
+ behaviors with "cvs ci -r".
+
+1998-10-09 Jim Kingdon
+
+ * update.c (update_dirent_proc): For local CVS, if the directory
+ does not exist in the working directory nor in the repository,
+ just skip it.
+ * sanity.sh (dirs): New tests dirs-3a, dirs-7 and dirs-8 test for
+ this and related behaviors. Note that the new behavior was also
+ the previous behavior for remote; we are only changing it for local.
+
+ * wrapper.c, cvsrc.c, ignore.c: Add comments about ignoring .cvsrc
+ and friends if we can't find a home directory.
+ * expand_path.c (expand_path): If we can't find the home
+ directory, give an error rather than a coredump (or worse).
+ * login.c (construct_cvspass_filename): Don't use errno in error
+ message; get_homedir doesn't set it. Add comment about this
+ message.
+
+1998-10-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (diff): Set variables to NULL at the start, and free
+ memory at the end.
+ * sanity.sh (multiroot2): Add tests for this (before the fix,
+ multiroot2-12 would abort with "no more than two revisions/dates
+ can be specified").
+
+1998-10-06 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (installcheck check): Remove references to RCSBIN;
+ they don't do anything now that RCSBIN is ignored.
+
+ * client.c: Clean up horrible confusion about whether stored_mode
+ or stored_mode_valid (or nothing :-)) indicates whether
+ stored_mode is allocated. Should fix crashes (for example, on NT
+ when the server has renamed multiple files from uppercase to
+ lowercase).
+
+ * sanity.sh (dirs): New tests, tests for some cases involving
+ admins who do surgery on the repository.
+
+1998-10-03 Johannes Stezenbach <johannes.stezenbach@propack-data.de>
+
+ * vers_ts.c (Version_TS): If UTIME_EXPECTS_WRITABLE, if
+ necessary change the file to be writable temporarily to set its
+ modification time.
+
+1998-10-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (handle_error): Add comment about indicating which
+ errors are from the server.
+
+1998-10-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (devcom-180): Allow one digit day.
+
+1998-09-30 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Don't call Name_Root if -d specified.
+ * recurse.c (do_recursion, do_dir_proc): Don't check CVS/Root
+ if -d was specified.
+ * import.c (import): Indentation fix.
+ * sanity.sh (multiroot): Update for this change.
+ (reposmv): New test, tests for this.
+
+1998-09-28 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (multiroot2): New test, tests some nested directory
+ cases.
+
+1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (multiroot): Change a few comments which said modules
+ when they meant directories.
+
+1998-09-25 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (devcom-180): Add 0-9 to the range of characters allowed
+ in hostname regexp.
+
+1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (log2): New test log2-7a tests for one error handling
+ case. Add a comment about another.
+
+1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Change crerepos test back to :ext: (for several
+ reasons; see comments).
+
+1998-09-24 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (rcslib-symlink-5, rcslib-symlink-6): new tests to
+ check the operation of "tag" when there are symlinks in the
+ repository.
+
+ * rcs.c (RCS_checkin): remove old code that resolved the symlink
+ and call resolve_symlink instead.
+ (RCS_rewrite): call resolve_symlink before doing anything else to
+ make sure we're operating on the file and not the symlink.
+
+ * subr.c (resolve_symlink): new routine -- resolves a symbolic
+ link chain to its destination.
+ * cvs.h: add prototype.
+
+ * sanity.sh (basica-6.2, basica-6.3): changed match expressions to
+ reflect new diff output.
+
+ * rcs.c (make_file_label): generate labels for files that include
+ the pathname so that output from "cvs diff" is useable by patch.
+ Looks like I came up with the mods as Andy Piper
+ <andyp@parallax.co.uk>; his patch was on the Cyclic unofficial
+ patches page.
+
+ * sanity.sh: change remote access method from ext to fork. This
+ results in a significant speed improvement when running the
+ testsuite. The ext method on my machine (i586 120MHz Linux 2.0.35
+ with TCP wrappers installed) runs in 450% of the time of the local
+ method while the fork method runs in only 150% of the time of the
+ local method! Yow! Am I SWAPPING yet?!
+ (crerepos-6a, crerepos-6b): change to reflect different error
+ messages for fork method.
+ (modes-15): same.
+
+ * client.c (connect_to_forked_server): new routine.
+ (start_server): call the above when method is fork_method.
+
+ * root.c: add a new method named "fork". This method uses the
+ remote protocol, but does so by forking a "cvs server" process
+ directly rather than doing "rsh host cvs server" (for example).
+ This new method has few advantages for day-to-day use, but has
+ three important benefits for debugging:
+
+ 1) Most secure installations these days don't allow rsh access.
+ With this new method, we can still test the remote protocol on
+ these machines because we don't need to be able to make a local
+ TCP connection.
+
+ 2) Even if installations allow rsh access, they almost always
+ have TCP wrappers to check permissions by IP/hostname. This
+ causes a short delay for every connection. For invocations from
+ the command line, this doesn't matter much, but it adds up to a
+ significant amount of time when running the testsuite.
+
+ 3) On machines that can't (or do not usually) provide rshd
+ access (I'm thinking of WNT/W95 in particular), we can now run
+ tests of the remote protocol using this method. Indeed, we can
+ run remote protocol tests on any machine that has an
+ implementation of piped_child().
+
+ (parse_cvsroot): handle new method.
+ (error_exit, xstrdup, isabsolute): new stub functions to use when
+ compiling root.c with the DEBUG option.
+ (main): fix a few typos.
+ * cvs.h (CVSmethod): add fork_method.
+
+ * server.c (create_adm_p): use Emptydir as the placeholder
+ directory instead of "." to avoid problems with "cvs update -d" et
+ al.
+
+1998-09-22 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (devcom-180): fixed typo in regexp.
+
+ * main.c (main): remove need_to_create_root and related code
+ (including CVS_IGNORE_REMOTE_ROOT environment variable). The
+ current implementation (just removed) of rewriting the contents of
+ the CVS/Root file isn't desirable for a number of reasons:
+
+ 1) Only the top-level CVS/Root directory is updated. If we're
+ really interested in pointing our WD at another CVSROOT, we
+ should have a separate command.
+
+ 2) With the new multiroot mods, we don't ever want to rewrite
+ CVS/Root files in the way the removed code did. Consider:
+
+ cvs -d repository1 co a
+ cd a
+ cvs -d repository2 co b
+ cvs -d repository2 update b
+
+ The update command would rewrite the contents of a/CVS/Root to
+ the incorrect value. Bad. We then wouldn't be talking to the
+ correct repository for files in a.
+
+ 3) The removed code seems to be a quick hack to support working
+ directories checked out from multiple repositories. With the
+ CVS_IGNORE_REMOTE_ROOT variable set, one could perform commands
+ as in example 2, above, without worring about updating CVS/Root
+ files. While in pre-1.10.1 recursive commands wouldn't handle
+ that working directory hierarchy, one could use commands like
+ "cvs foo -l" instead. While not great, this allows you (with a
+ lot of manual interaction) to have a multiroot WD. Since we now
+ have multiroot mods checked in, we don't need this code.
+
+ (lookup_command_attribute): while we don't need the
+ CVS_CMD_USES_WORK_DIR flag anymore (since it only was supporting
+ the need_to_create_root code), I'm leaving it in. It may come in
+ handy at some later date.
+
+1998-09-18 Jim Kingdon <kingdon@pennington.cyclic.com>
+
+ * version.c: Advance version number to 1.10.2.1.
+
+ * Version 1.10.2.
+
+1998-09-13 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c: Refuse to Copy-file to another directory
+ * sanity.sh (client): New test, tests for this.
+
+ * edit.c (editors_fileproc), watch.c (watchers_fileproc): Use
+ cvs_output rather than writing to stdout.
+ * sanity.sh (devcom): Use dotest for tests 178, 180, and 183
+ (tests that we preserve existing behavior on "cvs editors").
+
+ * commit.c (check_fileproc): Don't allow commits in Emptydir.
+ * sanity.sh (emptydir-8): Test for this change in behavior.
+
+ * sanity.sh: Add some compatibility tests to TODO comments at end.
+
+1998-09-10 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * wrapper.c (wrap_add): Remove obsolete comment about -m.
+
+ * server.c (server_updated): Check for error from CVS_UNLINK.
+
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_root): Allocate with malloc, not xmalloc.
+
+ * root.c (set_local_cvsroot): Move memory allocation from here...
+ * server.c (serve_root): ...to here. Fixes error handling.
+
+ * root.c (parse_cvsroot): Don't call check_root_consistent;
+ parse_cvsroot is only used for local and client.
+ * root.c (set_local_cvsroot): Move check_root_consistent
+ functionality from here...
+ * server.c (serve_root): ...to here. Fixes error handling. Also
+ made the error more explicit, while I am at it.
+ * server.c (Pserver_Repos): Now static.
+ * cvs.h: Don't declare it.
+ * root.c (check_root_consistent): Removed; no longer needed.
+ * sanity.sh (pserver): New test, tests for this behavior and some
+ other basic pserver stuff.
+
+ * update.c (merge_file): Use cvs_output for "already contains the
+ differences" message. Found this one when I actually observed the
+ out-of-order bug in Real Life(TM).
+
+1998-09-09 Jim Kingdon
+
+ * find_names.c (find_dirs): Make sure to zero errno before
+ going around the loop again.
+ * find_names.c (find_rcs): Make sure to set save_errno.
+ (thanks to Alexandre Parenteau for reporting both problems).
+
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com> and Michael Pakovic
+
+ * edit.c (notify_do): Only free line if it is not NULL.
+
+1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: dirs_sent_to_server should not be inside
+ AUTH_SERVER_SUPPORT (reported by both Richard Levitte and Murray
+ Bishop, thanks).
+
+ * lock.c, cvs.h: New variable lock_dir.
+ * parseinfo.c (parse_config): New option LockDir.
+ * lock.c (lock_name): New function, abstracts out lock file naming
+ and also supports LockDir.
+ * lock.c (lock_simple_remove, Reader_Lock, write_lock, set_lock):
+ Call it (6 places, to create/remove read/write/master locks).
+ (Lock_Cleanup): Refuse to reenter this function.
+ * sanity.sh (lockfiles): New test, tests for this feature.
+
+1998-09-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (multiroot): Expect ${TESTDIR} in output instead of
+ assuming it is /tmp/cvs-sanity (thanks to Mark D. Baushke of Cisco).
+ Clean up working directory when done (fixes apparent thinko).
+
+ * server.c (create_adm_p): Fix one "return" which didn't return a
+ value.
+ (dirswitch): Check for errors from create_adm_p.
+
+ * sanity.sh: Set LC_ALL rather than just LC_COLLATE.
+
+Wed Sep 2 02:30:22 1998 Jim Kingdon <kingdon@pennington.cyclic.com>
+
+ * version.c: Bump version number to 1.10.1.1.
+
+ * Version 1.10.1.
+
+1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Administrative note regarding Noel's changes to allow one to
+ switch from one CVS root to another in a single command: The
+ ChangeLog entries for the changes which Noel just checked in
+ appear for 1998-09-01, 1998-08-28, 1998-08-25, 1998-08-19, and
+ 1998-08-18, rather than being all together.
+
+ * main.c (set_root_directory): Fix whitespace.
+ (main): Nuke new -m option and just have that message controlled
+ by -t.
+ * server.c (server): Revert the CVS_SERVER_SLEEP code back the way
+ it was in CVS 1.10. Attaching to the parent process is relatively
+ boring (you can just run "cvs server" under a debugger instead),
+ but connecting to the child process is what the old code was for.
+ * recurse.c, server.c: Remove DEBUG_NJC code.
+
+1998-09-01 Noel Cragg <noel@swish.red-bean.com>
+
+ * server.c (do_cvs_command): add another environment variable,
+ CVS_SERVER_SLEEP2, after forking to pause the program so one can
+ attach a debugger.
+
+ * sanity.sh (crerepos): clean up crerepos-18 now that multiroot
+ works in this case.
+ (multiroot): finalize tests for local vs. remote operation.
+
+ * recurse.c (start_recursion): near the beginning, save the list
+ of directories to spoof as command-line arguments, if necessary.
+ Use that list near the end and call send_file_names to send those
+ arguments to the server.
+ (do_argument_proc): removed, since we call send_file_names now.
+
+ * main.c (main): re-initialize dirs_sent_to_server on each pass
+ through the loop for each CVSROOT.
+
+ * cvs.h: add proto for global variable which keeps track of which
+ directories have been sent to the server when in client mode.
+
+ * client.c (is_arg_a_parent_or_listed_dir): new function.
+ (arg_should_not_be_sent_to_server): new function. Tries to decide
+ whether the given argument should be sent to the server, based on
+ the current CVSROOT and the list of directories sent to the
+ server.
+ (send_repository): add the directory name to the list of
+ directories sent to the server.
+ (send_file_names): call arg_should_not_be_sent_to_server.
+
+ * add.c (add): switch the order of send_files and send_file_names
+ to make multiple repository support possible. send_files needs to
+ create a list of directories being requested so that
+ send_file_names can decide which command-line arguments to send to
+ the server for the given current CVSROOT.
+ * admin.c (admin): same.
+ * commit.c (commit): same.
+ * diff.c (diff): same.
+ * edit.c (editors): same.
+ * log.c (cvslog): same.
+ * rcs.c (annotate): same.
+ * remove.c (cvsremove): same.
+ * status.c (cvsstatus): same.
+ * tag.c (cvstag): same.
+ * update.c (update): same.
+ * watch.c (watch_addremove): same.
+ (watchers): same.
+
+1998-08-31 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Remove "debug" function; it was apparently checked
+ in accidentally by Norbert Kiesel's change.
+
+1998-08-31 Norbert Kiesel <nk@iname.com>
+
+ * release.c (release): modify last patch to release so that
+ save_cwd is called only once and restore_cwd is always called when
+ neccessary. Also fixed a tiny memory leak.
+
+ * sanity.sh (release): added some more tests for "cvs release"
+ including a test with two dirs and a "no" for the first one (which
+ fails without the above patch).
+
+1998-08-28 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (crerepos-18): add new comment and change test
+ slightly to support multiroot.
+ (multiroot): add more tests.
+
+ * server.c (create_adm_p): new function.
+ (dirswitch): call create_adm_p. Modify the code to always write a
+ new CVSADM_REP file, since create_adm_p might have put a
+ placeholder there and our value is guaranteed to be correct.
+ (server): move the CVS_SERVER_SLEEP check here so we can debug
+ things at an earlier stage.
+
+ * recurse.c (start_recursion): add large comment about the ideal
+ solution to the "Argument xxx" problem.
+
+ * main.c (main): move position of debugging comment for -m flag.
+
+ * diff.c (diff): clear a static variable.
+
+ * client.c (send_file_names): check to see if we should send this
+ argument to the server based on the contents of the appropriate
+ CVSADM directory. This avoids "nothing known about foo" messages
+ and problems with duplicate modules names in multiple
+ repositories.
+ (send_a_repository): change method of calculating toplevel_repos
+ to support multiple CVSROOTs.
+ (start_server): clear some static variables.
+
+1998-08-28 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (basicc-8, basicc-11): Use `.*' instead of explicit
+ `Operation not permitted'. Solaris2.5.1 gets a different error:
+ `Invalid argument'.
+
+1998-08-26 Eric M. Hopper
+
+ * sanity.sh: Set LC_COLLATE to "C".
+
+1998-08-25 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (multiroot): new set of tests to check the behavior of
+ multiroot.
+
+ * diff.c (diff): set options value to NULL after freeing to reset
+ the state for the next time around.
+
+1998-08-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Fix problems with trying to rename an open file:
+ * rcs.c, rcs.h (RCS_setattic): New function.
+ * commit.c (remove_file, checkaddfile): Call it.
+
+1998-08-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * release.c (release): Use save_cwd and restore_cwd to get back to
+ where we started, rather than hoping that CVS_CHDIR ("..") will do
+ something useful. This removes the need for most of
+ release_delete, so remove that function and inline what is left.
+ * sanity.sh (basicc): Adjust tests for this fix, also some tests
+ with multiple arguments to "cvs release" (in the non-"-d"-case, it
+ would seem like the old code would CVS_CHDIR into directories and not
+ CVS_CHDIR back, but I'm not going to investigate this and it
+ should be a moot point with this fix.).
+
+ * sanity.sh (basicc): Add tests for a serious bug in "cvs release
+ -d .".
+
+ More error handling fixes:
+ * ignore.c (ignore_files): Check for errors from opendir and
+ readdir.
+ * find_names.c (Find_Names): Check for errors from find_rcs.
+ (find_rcs, find_dirs): Comment error handling better; also return
+ an error if we got one from readdir.
+ * filesubr.c (deep_remove_dir): Also check for errors from readdir.
+ * import.c (import_descend): Print message on error from opendir
+ or readdir.
+ * commit.c (remove_file): Check for errors from CVS_MKDIR and
+ CVS_RENAME.
+ (remove_file): No need to remove the file in the temporary
+ directory; server.c now informs time_stamp_server of what is going
+ on via CVS/Entries rather than a file with a kludged up timestamp.
+ * client.c, entries.c, login.c, logmsg.c, mkmodules.c, patch.c,
+ remove.c, update.c: Check for errors from unlink_file.
+ * mkmodules.c (write_dbmfile, rename_dbfile, rename_rcsfile):
+ Check for errors from fclose, CVS_RENAME, and CVS_STAT.
+ * mkmodules.c (checkout_file): Clarify error handling convention.
+ * mkmodules.c (mkmodules): Call checkout_file accordingly.
+ * entries.c (Entries_Open): Check for errors from fclose.
+
+1998-08-21 Ian Lance Taylor <ian@cygnus.com>
+
+ * import.c (import): Output suggested merge command using
+ cvs_output_tagged rather than just cvs_output. Don't put
+ CVSroot_cmdline in the log file.
+ * client.c (importmergecmd): New static struct.
+ (handle_mt): Handle +importmergecmd tag.
+ * sanity.sh (import): Use an explicit -d in importb-2, to test
+ whether it is reported in the suggested merge command.
+
+1998-08-20 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (import): Rewrite tests to use dotest.
+
+1998-08-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add comments about binary files and cvs import.
+
+1998-08-19 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (importc): Use ${username} in one place where I had
+ missed it.
+
+ Make import -d work client/server:
+ * client.c, client.h (client_process_import_file): Take new
+ argument, for whether -d is specified, and send Checkin-time
+ request if it is set.
+ * import.c (import_descend): Pass it.
+ * main.c, cvs.h (date_to_internet): New function.
+ * server.c (server_modtime): Call date_to_internet.
+ * server.c (serve_checkin_time): New function.
+ (requests): Add "Checkin-time" request.
+ (serve_modified): If it was sent, set the timestamp in the
+ temporary directory.
+ * import.c (import): If the client sends a -d option, complain.
+ (import): For the server, always use the timestamps from the temp
+ directory.
+ (import): Don't send a -d option to the server.
+ * sanity.sh (importc): Add tests for import -d.
+
+Wed Aug 19 15:19:13 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (unedit-without-baserev-5): use ${DOTSTAR} instead
+ of .* since we expect to match multiple lines.
+
+1998-08-19 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.h (CVSroot_cmdline): Declare.
+ * root.c (CVSroot_cmdline): Define.
+ * main.c (main): Set CVSroot_cmdline if the -d option is used.
+ * import.c (import): If CVSroot_cmdline is not NULL, then mention
+ an explicit -d option in the suggested merge command line.
+
+Wed Aug 19 00:28:50 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * recurse.c (do_dir_proc): don't muck with CVS/Root directories
+ when running in server mode.
+ (do_recursion): same.
+
+ * main.c (main): add the command-line option `m' to help debug the
+ multiroot environment; it prints out the value of CVSROOT for each
+ iteration through the main loop. Also, changed the main loop so
+ that it gets executed only once when running in server mode (the
+ server will only deal with a single CVSROOT).
+
+ * recurse.c (do_recursion): change default for
+ PROCESS_THIS_DIRECTORY to true; we should always process a
+ directory's contents unless there's an existing CVS/Root file with
+ a different root than the current root to tell us otherwise.
+ (do_dir_proc): same.
+
+Tue Aug 18 14:30:59 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * recurse.c (do_recursion): check the current value of CVS/Root
+ and add it to our list of CVSROOTs if it doesn't exist. Decide
+ whether or not to process files in this directory based based on
+ the value of CURRENT_ROOT.
+ (do_dir_proc): same.
+
+ * main.c: add two new globals -- root_directories and current_root
+ -- which keep track of the values of CVSROOT we've seen and which
+ value of CVSROOT we're currently processing.
+ (main): put the main loop for stepping through cvsroot values
+ here, since we might need to send command-specific arguments for
+ every unique non-local cvsroot. Moved blocks of code around so
+ that one-time initializations happen first (outside the loop) and
+ the other stuff happens inside the loop.
+ (set_root_directory): helper function.
+
+ * cvs.h: add prototypes for root_directories and current_root, two
+ new globals for keeping track of multiple CVSROOT information.
+
+1998-08-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Don't assume that the shell leaves $^ unexpanded in
+ an unquoted here-document (suggested by Bart Schaefer to help when
+ zsh is the shell).
+
+1998-08-17 Ian Lance Taylor <ian@cygnus.com>
+
+ * commit.c (checkaddfile): Don't call fix_rcs_modes.
+ (fix_rcs_modes): Remove.
+
+1998-08-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * create_adm.c (Create_Admin): Don't condition traces on
+ SERVER_SUPPORT; SERVER_SUPPORT shouldn't do (much of) anything
+ independent of server_active.
+
+ * sanity.sh (binfiles3): New test, for yet another binary file
+ bug (sigh). Thanks to Jason Aten for reporting this one.
+
+1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c (call_diff_write_output): Update to reflect new
+ calling convention for the write_output callback.
+
+1998-08-15 Jim Meyering <meyering@ascend.com>
+
+ * update.c (merge_file): Warn about failed unlink when not due
+ to ENOENT.
+
+ * server.h (CLIENT_SERVER_STR): New macro
+ * create_adm.c (Create_Admin): Use it.
+ * entries.c (Scratch_Entry, Register): Use it.
+ * filesubr.c (copy_file, xchmod, rename_file, unlink_file): Use it.
+ * history.c (history_write): Use it.
+ * modules.c (do_module): Use it.
+ * no_diff.c (No_Difference): Use it.
+ * run.c (run_popen): Use it.
+ * server.c (server_register): Use it.
+
+1998-08-14 Jim Meyering <meyering@ascend.com>
+
+ * hardlink.c (lookup_file_by_inode): Use existence_error rather than
+ comparing errno to ENOENT directly.
+
+ * client.c (copy_a_file): Unlink destination before doing copy.
+ * sanity.sh (join-readonly-conflict): New test for this -- it would
+ fail only in client/server mode.
+
+ * sanity.sh (rcsmerge-symlink-4): Don't use `test -L', it's not
+ portable. Instead, match against the output of `ls -l'.
+ (dotest tag8k-16): Simplify tag-construction code and at the same
+ time, avoid using expr's `length' and `substr' operators. Not
+ all versions of expr support those.
+
+1998-08-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Bump version number to 1.10.0.1.
+
+Thu Aug 13 11:15:24 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * version.c: Change version number to 1.10 and name to `Halibut'.
+
+ * sanity.sh (rcslib): new tests to check behavior of symlinks in
+ the repository.
+
+Wed Aug 12 15:39:38 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * main.c (lookup_command_attribute): the `annotate' command
+ shouldn't require access to the repository. Add comment about
+ commands that do not use the working directory.
+
+Mon Aug 10 10:26:38 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * version.c: Change version number to 1.9.30.
+
+Thu Aug 6 17:44:50 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * server.c (serve_rdiff): change the name of the command (for
+ error reporting, etc.) from "patch" to "rdiff."
+ (serve_remove): rename from "cvsremove" to "remove."
+
+ * main.c (lookup_command_attribute): the `rdiff' command shouldn't
+ require write access to the repository.
+
+1998-08-06 David Masterson of kla-tencor.com
+ and Jim Kingdon
+
+ * commit.c (commit_filesdoneproc): Don't call strlen ("CVSROOT")
+ from within the assert statement. Apparently HP's cc compiler on
+ HPUX 10.20 has trouble with that.
+
+1998-08-06 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_checkin): When adding branch, if there is a lock on
+ the branchpoint owned by someone else, leave it alone. This
+ restores CVS 1.9 (RCS 5.7) behavior, fixing a core dump.
+ * sanity.sh (reserved): New tests reserved-16 through reserved-19
+ test for this fix.
+
+1998-08-05 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (unedit-without-baserev): Use ${QUESTION} not "?".
+ This makes it work with GNU expr 1.12 as well as 1.16.
+
+Sun Aug 2 20:27:44 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * mkmodules.c: add comment about TopLevelAdmin for the initial
+ contents of CVSROOT/config.
+
+1998-07-29 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_checkin): Only try to call xreadlink if HAVE_READLINK
+ is defined.
+
+Tue Jul 28 19:33:08 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * version.c: Change version number to 1.9.29.
+
+ * rcs.c (RCS_checkin): add code to follow symbolic links in the
+ repository.
+
+Sun Jul 26 05:14:41 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * This set of changes reverts the code to pre-1.9.2 behavior and
+ does not create CVS directories at top-level (except for the
+ obvious "cvs co ."). Added a new configuration option to switch
+ between 1.9 and 1.9.2 behavior.
+
+ * recurse.c (do_argument_proc): new function.
+ (start_recursion): in the case that we've done a command from
+ top-level but have no CVS directory there, the behavior should be
+ the same as "cvs <cmd> dir1 dir2 dir3...". Make sure that the
+ appropriate "Argument" commands are sent to the server by calling
+ walklist with do_argument_proc.
+
+ * client.c (call_in_directory): only create the top-level CVS
+ directory when we're checking out "." explicitly. The server will
+ force creation of this directory in all other cases.
+
+ * checkout.c (checkout_proc): only generate the top-level
+ directory when the TopLevelAdmin=yes. Also send a message to the
+ client to do the same.
+
+ * parseinfo.c (parse_config): handle TopLevelAdmin option. Set
+ top_level_admin.
+
+ * main.c: add new variable top_level_admin.
+ * cvs.h: add extern definition for above.
+
+ * sanity.sh: since we're reverting to pre 1.9.2 behavior for
+ top-level CVS directories, I needed to make changes to a bunch of
+ tests that made assumptions about said directories.
+ (preamble): make sure to add read and execute access to everything
+ in TMPDIR before removing, since some tests make things read-only.
+ (basicb-1a, basicb-1b, basicb-9a, basicb-9b): use dotest_fail
+ because these tests check for the non-existant top-level CVS
+ directory.
+ (basicc-3, emptydir-6, emptydir-7, crerepos-6): use "rm -rf" so it
+ won't complain when trying to remove the non-existant top-level
+ CVS directory.
+ (106.5): remove imported-f2-orig.tmp.
+ (modules2-10, emptydir-4, abspath-1ba, abspath-1bb): cd into the
+ directory where files exist before using the "add" command so cvs
+ can find CVSROOT in CVS/Root.
+ (cvsadm-2): look at a different CVS/Repository file, since the
+ top-level one doesn't exist.
+ (taginfo-3): create the directory in the repository directly
+ rather than relying on the fact that the top-level CVS directory
+ was created in a previous test.
+ (serverpatch-6): update first-dir explicity, rather than relying
+ on the non-existant top-level CVS/Entries file.
+ (crerepos-18): look at CVS/Repository in a subdirectory rather
+ than in the non-existant top-level CVS directory.
+ (toplevel): add code to set TopLevelAdmin=yes.
+ (toplevel2): new tests -- same as toplevel, but TopLevelAdmin=no.
+
+1998-07-21 Jim Meyering <meyering@ascend.com>
+
+ * rcs.c (RCS_checkout): Hoist frees of rev and value.
+ Warn and return 1 in several cases rather than exiting via
+ `error (1, ...'. The latter could abort a multi-file commit
+ in mid-stream, leaving stale locks in the repository.
+
+1998-07-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * build_src.com (rcscmds.c): Also look for include files in
+ [-.diff], just like Ian's 1998-06-18 change to Makefile.in
+
+1998-07-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * tag.c (pretag_proc), rtag.c (pretag_proc): Don't pass RUN_REALLY
+ to run_exec. This means that taginfo does not get executed if the
+ global -n option is specified. Which makes it like loginfo, -i,
+ -e, -o, -t, -u in modules, editinfo, and verifymsg and unlike
+ commitinfo. The old behavior was pretty bad in the sense that it
+ doesn't provide any way to log only the tags which actually
+ happen.
+ * sanity.sh (taginfo): New tests taginfo-11 to taginfo-13, for this.
+
+1998-07-12 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (ann-id): Write the test so that it tests for the
+ current (buggy) behavior.
+
+ * sanity.sh (taginfo): Also clean up cvsroot/first-dir.
+
+1998-07-12 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (ann-id): New (currently failing) test for bug in how
+ rcs keywords are expanded in the output of `cvs annotate'.
+
+1998-07-12 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (taginfo): Write the TESTDIR into the script rather
+ than having the script look at the environment. This means that
+ it will work if TESTDIR is set by sanity.sh as well as if
+ sanity.sh finds TESTDIR in the environment.
+
+1998-07-11 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * tag.c (check_fileproc): Calculate the revision to be tagged the
+ same way that tag_fileproc does.
+ * sanity.sh (taginfo): New tests, test for this (before this fix,
+ brtag had said 1.1 not 1.1.2.1).
+
+1998-07-10 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (unedit-without-baserev): Also clean up "2" directory.
+
+1998-07-08 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * edit.c (unedit_fileproc): If the Baserev file is missing, don't
+ get the working file from CVS/Base. The previous code could get
+ you version 1.1 of the working file and put 1.2 in CVS/Entries.
+ * sanity.sh (unedit-without-baserev): New tests test for this.
+
+1998-07-02 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (unedit-without-baserev): Move the test itself to be
+ in the same order as in the "tests" variable.
+
+1998-07-02 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcscmds.c: Don't include <stdarg.h> or <vasprintf.h>. Don't
+ declare vasprintf.
+ (call_diff_printf_output): Remove.
+ (call_diff_stdout_callbacks): Don't initialize printf_output
+ field--it has been removed from the interface.
+ (call_diff_file_callbacks): Likewise.
+
+1998-07-01 Jim Meyering <meyering@ascend.com>
+
+ * edit.c (unedit_fileproc): Handle the case in which base_get
+ returns a NULL baserev. That happens when a file being `unedit'ed
+ exists in the CVS/Base directory, but isn't listed in the CVS/Baserev
+ file. The one case I've seen had no Baserev file at all. The symptom
+ (if you're lucky) is a segmentation fault upon unedit. If you use
+ SunOS4.1.4 for which printf prints NULL pointers as `(null)', your
+ unedit command will complete normally, but it will have corrupted
+ your CVS/Entries file and a subsequent update may result in an
+ assertion failure, a core dump, and a stale lock in the repository.
+ * sanity.sh (unedit-without-baserev): New test for this.
+
+1998-07-01 Andy Mortimer of aeat.co.uk
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (server_updated): Use a prototype if we are using them
+ for declarations.
+
+1998-06-29 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (commit-readonly): Protect keyword against expansion
+ in sanity.sh itself. Keep the keyword in the file which we check
+ in (or else this fails to test for the RCS_checkout change).
+
+1998-06-27 Jim Meyering <meyering@ascend.com>
+
+ * rcs.c (RCS_checkout): If opening the local workfile fails due to
+ lack of write access, try to chmod the file and retry the open.
+ Before, a commit could fail part way through merely because the
+ open to rewrite with newly expanded rcs keywords would fail. It's
+ easy to make this happen if you use `cvs -r' or CVSREAD and you
+ apply a patch to one of your read-only source files -- patch
+ preserves the read-only setting for the file and your next commit
+ will fail after committing that file, but before rewriting
+ (checking out) your working copy.
+ * sanity.sh (commit-readonly): New test for this.
+
+1998-06-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (patch_file): Update comments regarding context diffs
+ to reflect diff library.
+
+1998-06-23 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (modules4): Add tests for reversing the order of the
+ "!first-dir/sdir" and "first-dir".
+
+1998-06-23 Jim Kingdon <kingdon@harvey.cyclic.com>
+ and Dave Wolfe@Motorola.
+
+ * sanity.sh (modes2): Touch the file before chmod'ing it.
+
+1998-06-21 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (merge_files): Revert changes of 1998-06-19. Instead,
+ register a merged file with a dummy time stamp. Only set
+ last_register_time if we need to.
+ (join_file): Likewise. Always register a merged file, not just
+ when the merge fails.
+
+1998-06-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * call_diff_write_output, call_diff_printf_output,
+ call_diff_flush_output, call_diff_write_stdout, call_diff_error,
+ call_diff_stdout_callbacks, call_diff_file_callbacks): Re-indent.
+
+1998-06-19 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (merge_file): Make sure the time stamp of the file is
+ different from the time stamp we register in the Entries file.
+ (join_file): Likewise.
+
+1998-06-18 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcscmds.c: Include <stdio.h>. Include either <stdarg.h> or
+ <varargs.h>. Declare vasprintf.
+ (call_diff_write_output): New static function.
+ (call_diff_printf_output): New static function.
+ (call_diff_flush_output): New static function.
+ (call_diff_write_stdout): New static function.
+ (call_diff_error): New static function.
+ (call_diff_stdout_callbacks): New static variable.
+ (call_diff_file_callbacks): New static variable.
+ (call_diff): Don't sleep. Use a callback structure when calling
+ the diff library.
+ (call_diff3): Likewise.
+
+ * rcscmds.c: Include diffrun.h.
+ (call_diff, call_diff3): Pass NULL callback parameter.
+ (diff_run, diff3_run): Don't declare.
+ * Makefile.in (rcscmds.o): New target, to use -I for diff
+ directory.
+ (zlib.o): Depend upon zlib.h.
+
+1998-06-09 Mike Sutton@SAIC
+
+ Make it compile with Sun's bundled K&R C compiler:
+ * rcs.c (count_delta_actions): Change to static to match
+ declaration.
+ * client.c (handle_wrapper_rcs_option): Rename error label to
+ handle_error to avoid clash with function name.
+
+1998-06-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_delete_revs): If we are trying to delete all
+ revisions, give an error rather than assertion failed.
+ * sanity.sh (basicb): New tests basicb-o* test for this.
+
+1998-06-04 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add): Only send "Directory" requests if we need to.
+
+1998-06-02 Assar Westerlund <assar@sics.se>
+
+ * client.c: Check for HAVE_GSS_C_NT_HOSTBASED_SERVICE rather than
+ assuming that GSS_C_NT_HOSTBASED_SERVICE is a macro.
+ * server.c: Likewise.
+
+1998-06-02 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * fileattr.c (fileattr_read): Check for NULL return from strchr.
+ * sanity.sh (devcom3): New test devcom3-10 checks for this.
+
+1998-06-01 Assar Westerlund <assar@sics.se>
+ and Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c: If HAVE_GSSAPI_H, include <gssapi.h>. Only include
+ <gssapi/gssapi.h> if HAVE_GSSAPI_GSSAPI_H. Only include
+ <gssapi/gssapi_generic.h> if HAVE_GSSAPI_GSSAPI_GENERIC_H.
+ (GSS_C_NT_HOSTBASED_SERVICE): Define if not defined.
+ (connect_to_gserver): Use GSS_C_NT_HOSTBASED_SERVICE instead of
+ gss_nt_service_name.
+ * server.c: Same header file changes.
+ (GSS_C_NT_HOSTBASED_SERVICE): Define if not defined.
+ (gserver_authenticate_connection): Use GSS_C_NT_HOSTBASED_SERVICE
+ instead of gss_nt_service_name.
+
+1998-06-01 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (tag8k): Add a test for the 1998-05-02 rcs.c bug fix.
+
+1998-05-26 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (annotate): Call tag_check_valid like the other functions
+ which have a -r option.
+ * sanity.sh (ann): New test ann-14 tests for this.
+
+1998-05-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (importc): New tests importc-5 through importc-8 test
+ for a (fairly obscure) regression from CVS 1.9.
+
+1998-05-23 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (modules2): Add comment listing cvs release tests.
+ (info): New test info-cleanup-0 tests "cvs -n release".
+
+ * rcs.c (rcsbuf_getid): Remove semicolon at end of #undef. I'm
+ kind of surprised that compilers accepted this at all, but
+ removing it squelches a warning for some compilers.
+
+ * version.c: Change version number to 1.9.28.1.
+
+ * Version 1.9.28.
+
+1998-05-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_cmp_file): Check for errors from CVS_FOPEN. This
+ restores the CVS 1.9 behavior (fatal error if we can't open the
+ file), and corrects an apparent oversight in Ian's 13 Apr 1997
+ change.
+ * sanity.sh (modes2): New test, tests for this.
+
+1998-05-22 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (server_updated): Correct test for whether to unlink
+ the file.
+
+1998-05-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * wrapper.c (wrap_add): Disable -t/-f wrappers at least until the
+ serious bug can be fixed.
+
+1998-05-15 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (checkout): Call server_pathname_check on the
+ argument to "cvs co -d".
+ * server.c (server_pathname_check): Add comment about how we could
+ be handling absolute pathnames.
+ * sanity.sh (abspath): Rewrite the tests which run "cvs co -d /foo"
+ for remote, to reflect this.
+
+ * sanity.sh (abspath): Also do the "cannot rename" work-around for
+ abspath-7d.
+
+1998-05-13 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (commit_filesdoneproc): Free admin_dir when done with it.
+
+1998-05-13 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (editor): Change bogus sed command, `s/^/x&/g', to `s/^/x/'.
+ The former exercised a bug in GNU sed-3.01-beta3.
+ (emptydir-8): Add `Rebuilding administrative file database' message,
+ since now it does that.
+ * commit.c (commit_filesdoneproc): Pass only the admin directory
+ pathname to mkmodules.
+ Remove #if 0, now that it's fixed.
+
+ * status.c (cvsstatus): Rename from `status' to avoid shadowing
+ lots of locals and parameters by the same name.
+ * server.c (serve_status): Update caller.
+ * main.c (cmds[]): Update table entry.
+ * cvs.h: Update prototype.
+
+ * commit.c (commit_filesdoneproc): Remove trailing blanks.
+ (commit) [CLIENT_SUPPORT]: Remove unnecessary (and local-shadowing)
+ declaration of `err'.
+ Rename global `tag' to `saved_tag' to avoid overshadowing `tag'
+ parameters of three functions.
+ Rename global `message' to `saved_message' to avoid overshadowing
+ `message' parameter of a function.
+ Rename global `ulist' to `saved_ulist' and move dcl up with others.
+
+1998-05-12 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (commit_filesdoneproc): #if 0 the new code until it can
+ be fixed.
+
+ * commit.c (commit_filesdoneproc): Add comment explaining last
+ change.
+
+1998-05-12 Jim Meyering <meyering@ascend.com>
+
+ * commit.c (commit_filesdoneproc): Call mkmodules not just when
+ committing a file directly under CVSROOT, but also when committing
+ files in subdirectories of CVSROOT.
+
+1998-05-08 Jim Meyering <meyering@ascend.com>
+
+ * filesubr.c (xreadlink): NUL-terminate the symbolic link name.
+ Use a much smaller initial buffer length.
+ Test errno only if readlink fails.
+ Use xstrdup then free the original link name so we don't waste space.
+
+1998-05-02 Jim Meyering <meyering@ascend.com>
+
+ * rcs.c (rcsbuf_getword): Fix off-by-one error that would result in
+ an abort (the first one in rcsbuf_getkey) when operating on on some
+ ,v files with over 8192 bytes of tag and branch info.
+
+1998-05-04 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (ann): New tests ann-12 and ann-13 test for specifying
+ a numeric branch.
+
+1998-05-02 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c: Add comments about getting rid of rcsbuf_getid,
+ rcsbuf_getword, and rcsbuf_getstring.
+
+ * sanity.sh (abspath): Revise the workarounds to deal with exit
+ status.
+
+1998-04-30 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (abspath): Work around the "cannot rename" bug.
+
+1998-04-27 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * classify.c (Classify_File): Add comments about checking whether
+ command name is "update".
+
+1998-04-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.27.1.
+
+ * Version 1.9.27.
+
+1998-04-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ (This diff was run by devel-cvs and everyone seemed to like it).
+ * diff.c (diff_file_nodiff): Make HEAD mean the head of the branch
+ which contains the sticky tag, not the sticky tag itself.
+ * rcs.c, rcs.h (RCS_branch_head): New function.
+ * sanity.sh (head): Update for this changed behavior.
+
+1998-04-19 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Move emptydir tests from basicb to new test emptydir.
+ This is because we now need a module definition to create Emptydir;
+ "co -d" doesn't cut it anymore.
+
+1998-04-17 Petri Virkkula
+
+ * server.c (mkdir_p): Ignore EROFS error (like for EACCES).
+
+1998-04-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (checkout_proc): Don't create directories above the
+ last one specified in "co -d".
+ (build_dirs_and_chdir): Revert Noel's change of 17 Feb 1998.
+ (struct dir_to_build): New field just_chdir.
+ (build_dirs_and_chdir): Test it.
+ * sanity.sh (abspath): New tests abspath-7* test for a bug which
+ we fix, in which CVS would create bogus "D/////" entries in
+ CVS/Entries.
+ (abspath): Revise abspath-3* tests to test for the fact that we no
+ longer create directories above the last one specified in "co -d".
+ I checked that CVS 1.9 gives an error on this, so changing this
+ behavior back should be OK.
+ (cvsadm-2d3): Likewise (also checked CVS 1.9 for this case).
+ (cvsadm-2d3d): Likewise (also checked CVS 1.9 for this case).
+ (cvsadm-2d{4,5,6,7,8}, cvsadm-N2d{3,4,5,6,7,8}): Adjust for new
+ behavior (same case as cvsadm-2d3).
+ (cvsadm-2d{4,5,6,7,8}d, cvsadm-N2d{3,4,5,6,7,8}d): Remove test
+ (same case as cvsadm-2d3d).
+ (cvsadm): For remote, skip most these tests.
+ (abspath): When cleaning up, delete mod1 and mod2 rather than mod1
+ twice (longstanding bug, apparently only becomes visible if you
+ run the tests in a certain order).
+
+1998-04-14 Wilfredo Sanchez <wsanchez@apple.com>
+
+ * rcs.c: variable "lockfile" was being referenced after being
+ free'd. Bad. Moved the free() call down.
+
+1998-04-12 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (rcs): Add test for annotate and the year 2000.
+
+ * server.c (do_cvs_command): If there are partial lines left when
+ the child process is done, send them along.
+ * sanity.sh (rcs, rcs2): Enable all tests for remote; tests for
+ this fix.
+
+1998-04-11 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (client_senddate): Pass SDATEFORM not DATEFORM to
+ sscanf. This fixes a Y2K bug.
+
+ * history.c (history, select_hrec): Change since_date from time_t
+ to RCS format. Use the usual machinery (in particular, Make_Date
+ and client_senddate) so that it will work on VMS too.
+ * main.c, cvs.h (date_from_time_t): New function.
+ * sanity.sh (history): New test, to test that this didn't break
+ anything (also tests client_senddate fix).
+
+1998-04-11 Norbert Kiesel <nk@iname.com>
+
+ * server.c (cvs_output_binary): Shut up "gcc -Wall" by removing
+ unnecessary else if test.
+ * server.c (check_password): Fix uninitialized memory read if
+ shadow passwords are used. Also added some comments.
+ * rcs.c (RCS_checkout): Make sure to call chown with -1 for uid or
+ gid if they should not be changed
+
+1998-04-10 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (rcs2): New test, tests for various Y2K cases.
+ * rcs.c (getdelta): Value for "state" keyword is optional (bug
+ discovered incidentally in writing rcs2 test).
+
+1998-04-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c, cvs.h (link_file): Remove; no longer used.
+
+1998-04-08 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_dir_proc): Restore update_dir rather than a
+ computation which appears to, but does not necessarily, restore it
+ (reported by various people; this fix is from Greg Hudson).
+ * sanity.sh (importc): New test, tests for this fix.
+
+1998-03-27 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_lock): If the revision is already locked, give an
+ error rather than dumping core.
+ * sanity.sh (reserved): New test reserved-13c tests for this.
+
+1998-03-25 Loren J. Rittle
+
+ * import.c (add_rev): Rewrite to use RCS_FLAGS_KEEPFILE option
+ of RCS_checkin() to avoid damage to imported files instead of
+ externally undoing damage after the fact. The side effect is
+ that callers of add_rev() may now incrementally walk the
+ entries of the current directory without seeing gratuitous
+ changes to the directory structure (under at least one file
+ system under at least one OS).
+
+1998-03-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.c (error): Save and restore errno. Should fix test case
+ conflicts3-23 on SCO 5.0.2. Reported by Steve Cameron.
+
+ * sanity.sh (admin): Rename admin-26-o* to admin-26-*; the "o"
+ stands for "cvs admin -o". Add comment about length of tests.
+ Use ${PLUS}.
+
+1998-03-05 Dan Wilder <dan@gasboy.com>
+
+ * Fix problem with cvs admin in which -ntag:branch
+ option associated tag with the branch's head revision.
+ Should have used branch number. Entailed in this fix,
+ the following.
+
+ * Add new functions "RCS_exist_rev", "RCS_exist_tag",
+ "RCS_tag2rev", and "RCS_valid_rev" to rcs.c. RCS_tag2rev
+ is similar to RCS_gettag, but does less interpretation.
+
+ * Plug a small memory leak.
+
+ * Add tests admin-26 through admin-29 to sanity.sh,
+ to test "cvs admin -n".
+
+1998-03-17 Samuel Tardieu <sam@inf.enst.fr>
+
+ * server.c (server_register): protect dereferencing timestamp in
+ the trace message when it is null, to avoid a segmentation fault.
+
+1998-03-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in (MY_NDBM): Rewrite the comment explaining this
+ option. It was not clear to everyone who "my" referred to, for
+ example.
+
+ * hardlink.c (list_linked_files_on_disk): Remove unused variables
+ err and p.
+ (list_linked_files_on_disk): Add comment about memory allocation
+ of return value.
+ * rcs.c (rcsbuf_getword): Shut up gcc -Wall with a "return 0".
+ (RCS_checkin): Remove unused variable fullpath.
+ * sanity.sh (hardlinks): Remove comment about spurious warnings;
+ the warnings are gone.
+
+1998-03-12 Tim Pierce <twp@skepsis.com>
+
+ New functions for parsing and writing hardlink fields.
+ * rcs.c [PRESERVE_PERMISSIONS_SUPPORT] (puthardlink_proc): New
+ function.
+ (putdelta) [PRESERVE_PERMISSIONS_SUPPORT]: Use it.
+ (rcsbuf_getid, rcsbuf_getstring, rcsbuf_getword): New functions.
+ (getdelta): Call them, storing `hardlinks' field in vnode->hardlinks.
+ (RCS_reparsercsfile): When setting rdata->desc, xstrdup value
+ rather than rcsbuf_valcopying it (due to changes in how getdelta
+ handles keys and values in newphrases).
+
+ * sanity.sh (hardlinks): Use uglier filenames. Checking out
+ hardlinked files no longer produces the same spurious diagnostics,
+ so fix that test.
+ (hardlinks-2.3): Renamed from hardlinks-2.2 (duplicate test name).
+
+ New infrastructure for managing hardlink lists internally...
+ * hardlink.c, hardlink.h (list_linked_files_on_disk,
+ compare_linkage_lists, find_checkedout_proc): New functions.
+ * rcs.h (struct rcsversnode) [PRESERVE_PERMISSIONS_SUPPORT]: New
+ member `hardlinks'.
+ * update.c (special_file_mismatch): Get hardlinks from
+ vp->hardlinks instead of from vp->other_delta.
+ * rcs.c (free_rcsvers_contents): Comment about freeing hardlinks
+ member.
+ (RCS_checkout) [PRESERVE_PERMISSIONS_SUPPORT]: Get hardlinks from
+ vers->hardlinks list instead of vers->other_delta.
+
+ ... and removed obsolete code from earlier revs.
+ * hardlink.c, hardlink.h (list_files_linked_to,
+ cache_hardlinks_proc, list_files_proc, set_hardlink_field_proc):
+ Removed.
+ * hardlink.h: Removed `links' member from hardlink_info struct.
+ * commit.c (commit): Remove the call to cache_hardlinks_proc.
+ (check_fileproc) [PRESERVE_PERMISSIONS_SUPPORT]: Removed reference
+ to hlinfo->links.
+ * hardlink.c (update_hardlink_info): Same.
+ * update.c (get_linkinfo_proc): Same.
+
+ * rcs.c (RCS_checkout) [PRESERVE_PERMISSIONS_SUPPORT]: Use
+ vp->hardlinks and find_checkedout_proc to find recently-updated
+ files that may be hardlinked.
+ * update.c (special_file_mismatch): Use List * structures and
+ compare_linkage_lists for rev1_hardlinks and rev2_hardlinks.
+
+1998-03-16 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (check_password): If shadow passwords are supported but no
+ entry is found in the shadow file, check the regular password file.
+
+1998-03-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Rename permissions test to perms since that is what
+ each of its individual tests are named.
+ * sanity.sh (perms symlinks hardlinks): Change CVSROOT to
+ CVSROOT_DIRNAME where appropriate.
+ (perms symlinks hardlinks): Disable/adjust the meat of the tests for
+ remote.
+ (symlinks): Link to ${TESTDIR}/fumble rather than
+ /fumble/mumble/grumble. We shouldn't be making assumptions about
+ what might exist in random directories outside ${TESTDIR}.
+ * hardlink.c (cache_hardlinks_proc): Add comment about trimming
+ whitespace.
+
+1998-03-07 Tim Pierce <twp@skepsis.com>
+
+ * rcs.c (RCS_checkout): Negation bug when checking out symlinks:
+ existence_error should be !existence_error.
+ * sanity.sh (permissions symlinks hardlinks): New tests, for
+ PreservePermissions.
+
+1998-03-04 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.26.1.
+
+ * Version 1.9.26.
+
+ * entries.c, cvs.h (Entries_Open): New argument update_dir; use it
+ in error message.
+ * add.c, checkout.c, client.c, find_names.c, import.c, recurse.c,
+ update.c: Pass it (as NULL except in call_in_directory).
+ * entries.c (Subdirs_Known): Just return if there is no CVSADM
+ directory (as in subdir_record).
+ * sanity.sh (conflicts3): New tests conflicts3-20a and
+ conflicts3-23 test for these fixes.
+
+ * commit.c (commit): Only set up hardlist if preserve_perms.
+
+ * commit.c, import.c, no_diff.c, parseinfo.c, rcs.c, rcscmds.c,
+ update.c: Omit the preserve_perms code if
+ PRESERVE_PERMISSIONS_SUPPORT is not defined. Much of that code
+ won't even compile on non-unix systems.
+
+ * hardlink.c, hardlink.h: Use the 'standard' copyright (as found
+ in server.c).
+ * commit.c, rcs.c: Minor whitespace changes to Tim's submission.
+ * commit.c (check_fileproc), update.c (get_linkinfo_proc): Remove
+ unused variable delta.
+ * hardlink.c (set_hardlink_field_proc), update.c
+ (get_linkinfo_proc): Return a value rather than falling off the
+ end of the function.
+
+1998-03-02 Tim Pierce <twp@skepsis.com>
+
+ * update.c (special_file_mismatch): Compare the hard links of the
+ two revisions.
+
+ * rcs.c (RCS_checkout):
+
+ * hardlink.c, hardlink.h: New files.
+ (hardlink_info): New struct.
+ (hardlist, working_dir): New variables.
+ (list_files_proc, cache_hardlinks_proc, set_hardlink_field_proc,
+ lookup_file_by_inode, update_hardlink_info, list_files_linked_to):
+ New functions.
+
+ * Makefile.in (SOURCES): Add hardlink.c.
+ (OBJECTS): Add hardlink.o.
+ (HEADERS): Add hardlink.h.
+ * commit.c: Include hardlink.h.
+ (commit): Save the working directory before recursing. Walk the
+ hardlink list, calling set_hardlink_field_proc on each node.
+ (check_fileproc): Add each file's link information to hardlist.
+ * rcs.c: Include hardlink.h.
+ (RCS_checkin): Save list of hardlinks in delta node.
+ (RCS_checkout): Look up the file's `hardlinks' delta field, and
+ see if any of the files linked to it have been checked out
+ already. Link to one of those files if so.
+ * update.c: Include hardlink.h.
+ (get_linkinfo_proc): New function.
+ (do_update): Extra recursion to collect hardlink info.
+ (special_file_mismatch): Reparse the RCS file if necessary.
+
+ fsortcmp is now used by several files, so let's make it extern.
+ * hash.c, hash.h (fsortcmp): New function.
+ * find_names.c (fsortcmp): Removed.
+ * lock.c (fsortcmp): Removed.
+
+1998-03-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (conflicts3): New tests conflicts3-14a,
+ conflicts3-14b, and conflicts3-21, conflicts3-22 test that we can
+ skip over a working directory with a CVSADM directory missing.
+
+1998-02-26 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (conflicts3): Tests conflicts3-16 and conflicts3-20
+ test that we include update_dir in messages. Rename test
+ conflicts3-14 to fix typo.
+
+Sun Feb 22 23:14:25 1998 Steve Cameron <steve.cameron@compaq.com>
+ and Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (tag_update_dir): New static variable.
+ (update_dirent_proc): If no tag or date were specified when
+ creating a subdirectory, use the tag and/or date of the parent
+ directory.
+ (update_dirleave_proc): If we set the tag and/or date in
+ update_dirent_proc, reset them when we leave the directory.
+ * sanity.sh (branches2): New set of tests for above patch, and
+ related behaviour.
+
+Sun Feb 22 13:31:51 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * commit.c (lock_RCS): Don't call RCS_rewrite.
+
+ * update.c (patch_file): If the revision is dead, let
+ checkout_file handle it.
+ * sanity.sh (death2): Add test for above patch: add
+ death2-10a, death2-10b, death2-13a, and adjust
+ death2-{2,4,5,11,14,diff-11,diff-12,19}.
+
+ * cvs.h (RCS_FLAGS_KEEPFILE): Define.
+ * rcs.c (RCS_checkin): If RCS_FLAGS_KEEPFILE is set in the flags
+ parameter, don't unlink the working file.
+ * checkin.c (Checkin): Don't copy the file. Instead pass
+ RCS_FLAGS_KEEPFILE to RCS_checkin, and only check the file out
+ again if it has changed.
+
+1998-02-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (rcs_internal_unlockfile, RCS_rewrite): Don't assume errno
+ means anything just because ferror is set.
+
+Sat Feb 21 20:02:24 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * Makefile.in (clean): Change "/bin/rm" to "rm".
+
+ * buffer.c (buf_append_buffer): Correct typo in comment.
+ * rcs.c (RCS_putadmin): Likewise.
+
+Fri Feb 20 17:53:06 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (rcs_internal_unlockfile): Pass errno when calling error
+ because ferror is true.
+
+1998-02-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (abspath): Don't assume that we can't write to /; this
+ is the kind of thing that is sure to break sooner or later
+ (especially on Windows).
+
+ * sanity.sh: Add summary of which modules tests are which (at
+ "modules"). Move cvsadm, abspath, and toplevel next to modules.
+ Add comments to clarify the structure (such as it is).
+
+Fri Feb 20 12:47:14 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * admin.c (admin_fileproc): Better fix for -b.
+
+ * rcs.c (RCS_whatbranch): Back out previous change.
+ (RCS_getversion): Ditto.
+ (RCS_setbranch): Treat an empty revision string like a null pointer.
+
+1998-02-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_whatbranch): Fix indentation.
+
+ * patch.c (patch_fileproc): Check for errors from fclose; check
+ for errors from fopen properly.
+
+Wed Feb 18 16:03:37 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * admin.c (admin_fileproc): Convert -b argument from symbolic name
+ to revision number before storing in the RCS file.
+ * rcs.c (RCS_whatbranch): Allow numeric as well as symbolic revision.
+ (RCS_getversion): Take advantage of above.
+ * sanity.sh (admin): Add/revise/renumber admin-10c, admin-11a,
+ admin-12, and admin-12a to check above.
+
+ * commmit.c (lock_RCS): Minor clean-up.
+
+ * sanity.sh (abspath-6a): Don't depend on the sepcific contents of
+ CVSROOT, it depends on which other tests have been run.
+
+Wed Feb 18 01:56:04 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (putsymbol_proc): Use putc and fputs rather than fprintf.
+ (RCS_putadmin): Don't call RCS_symbols if the symbols have not yet
+ been converted to a list.
+
+ * rcs.c (rcsbuf_cache, rcsbuf_cache_open, rcsbuf_cache_close): New
+ static functions to avoid closing and reopening the RCS file.
+ (cached_rcs, cached_rcsbuf): New static variables.
+ (RCS_parse): Call rcsbuf_cache_close. Don't call fclose.
+ (RCS_parsercsfile): Likewise.
+ (RCS_parsercsfile_i): Call rcsbuf_cache rather than
+ rcsbuf_close. Call fclose on error. Remove comment about
+ inefficiency of opening file twice.
+ (RCS_reparsercsfile): Call rcsbuf_cache_open rather than fopen and
+ rcsbuf_open. Call rcsbuf_cache rather than rcsbuf_close and
+ fclose.
+ (RCS_fully_parse, RCS_checkout, RCS_deltas): Likewise.
+ (RCS_rewrite): Likewise.
+ (RCS_checkin): Call rcsbuf_cache_close.
+
+ * rcs.c (RCS_copydeltas): Fix code which checks for an extra
+ newline in buffered data.
+
+ * rcs.c (rcsbuf_getkey): Save an indirection by using start rather
+ than *valp when trimming trailing whitespace from value.
+
+ * rcs.c (rcsbuf_get_buffered): New static function.
+ (RCS_copydeltas): After we have done all the required special
+ actions, and inserted any new revision, just copy the file bytes
+ directly, rather than interpreting all the data.
+ (count_delta_actions): New static function.
+ * sanity.sh (rcs): Add rcs-6a and rcs-6b to commit a new branch
+ revision, to force CVS to interpret all the data, rather than just
+ copying it. Adjust rcs-5 to add a branch tag. Adjust rcs-8a and
+ rcs-14 for the changes created by rcs-6b.
+
+Tue Feb 17 18:34:01 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (cvsadm, diffmerge2): Remove directories at the end of
+ the test.
+
+ * import.c (expand_at_signs): Rewrite to use memchr and fwrite
+ rather than putc.
+
+ Rewrite RCS file reading routines for speed:
+ * rcs.c (struct rcsbuffer): Define.
+ (rcsbuf_open, rcsbuf_close, rcsbuf_getkey, rcsbuf_getrevnum,
+ rcsbuf_fill, rcsbuf_valcopy, rcsbuf_valpolish,
+ rcsbuf_valpolish_internal, rcsbuf_ftell): New static functions.
+ (getrcskey, getrcsrev, getrevnum): Remove.
+ (many functions): Change to use new rcsbuf functions instead of
+ old getrcskey/getrcsrev/getrevnum functions.
+ (RCS_reparsercsfile): Add rcsbufp parameter. Change all callers.
+ (RCS_deltas): Add rcsbuf parameter. Change all callers.
+ (getdelta): Change fp parameter to rcsbuf parameter. Change all
+ callers.
+ (RCS_getdeltatext): Add rcsbuf parameter. Change all callers.
+ (RCS_copydeltas): Add rcsbufin parameter. Change all callers.
+ * rcs.h (RCS_reparsercsfile): Update declaration.
+ * admin.c (admin_fileproc): Update calls to RCS_reparsercsfile for
+ new parameters.
+
+1998-02-17 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (toplevel): Also clean up second-dir (not a new
+ bug, but triggered by running tests as "toplevel abspath").
+
+ * create_adm.c (Create_Admin): Just print update_dir to tell the
+ user where we are; not the whole xgetwd. Cleaner than
+ Noel's change (which also had problems in errno handling).
+ * sanity.sh (toplevel-12): Update accordingly.
+
+Tue Feb 17 02:32:21 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ [These mods make "checkout" work with "-d /absolute/pathname"
+ once again.]
+
+ * checkout.c (checkout_proc): the -d flag on the command line
+ should override the -d flag in the modules file if the latter is
+ an absolute path. The loop that assembles the list of directories
+ to build has been reorganized slightly to prepare for rewriting
+ with last_component rather than assuming '/' as a path separator.
+ Also added to that loop was some code to handle absolute
+ pathnames.
+ (build_dirs_and_chdir): add a new argument that tells this routine
+ whether or not to check before it creates and populates
+ directories or not.
+
+ * filesubr.c (last_component): return the top-level directory when
+ asked about the top-level directory.
+
+ * sanity.sh (toplevel-12): change test to reflect the new style of
+ this error message.
+
+ * create_adm.c (Create_Admin): include the directory in the error
+ message.
+
+1998-02-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (diff_fileproc), import.c (import, add_rcs_file), rcs.c
+ (RCS_cmp_file): Don't ignore errors from CVS_UNLINK and fclose.
+
+ * patch.c (patch_fileproc): Check for errors from fclose; if we
+ get -1 from getline check for end of file vs. error.
+
+ * rcs.c (RCS_checkout): Comment return value (0/1, not -1).
+ * commit.c, diff.c, mkmodules.c, patch.c, rcs.c, update.c: Update
+ to match this convention. Don't suppress errors based on
+ quiet or really_quiet variables.
+
+ Fix a longstanding bug which also makes stamps-8kw in make
+ remotecheck work again (it stopped working with Ian's 8 Feb 98
+ checkin):
+ * client.c, client.h (change_mode): If new argument respect_umask
+ is set, then honor the umask.
+ * client.c, server.c: Update callers.
+
+ Cleanups to Tim's checkin:
+ * rcs.c (RCS_checkout): Use existence_error not ENOENT.
+ * commit.c (checkaddfile): Remove comment about whether we want to
+ check for errors from fclose; there is no reason not to.
+ * rcs.c (RCS_checkout), update.c (special_file_mismatch): sscanf
+ on %ld requires an unsigned long, not a dev_t.
+ * update.c (special_file_mismatch): Remove unused variable
+ check_devnums.
+ * mkmodules.c (config_contents): Between two settings, use a blank
+ line not a "#" line.
+
+1998-02-15 Tim Pierce <twp@skepsis.com>
+
+ [This is the code as submitted. I'll be checking in my cleanups
+ shortly. This work sponsored by Abbott Labs. -kingdon]
+
+ Support for device special files, symbolic links, user and group
+ ownerships, and file permissions.
+
+ * parseinfo.c: (parse_config): Handle new config variable
+ `PreservePermissions'.
+ * mkmodules.c (config_contents): Add new PreservePermissions var.
+
+ * rcs.c, rcs.h (preserve_perms): New variable.
+ (RCS_checkout, RCS_checkin): Support for newphrases `owner',
+ `group', `permissions', `special', `symlink'.
+ (RCS_checkout): If `workfile' and `sout' are symlinks, remove them
+ before attempting to open them for writing.
+ * import.c (add_rcs_file): Support for newphrases. Do not attempt
+ to read data from special files or symlinks. Error message
+ `cannot fstat' is now `cannot lstat'.
+
+ New metrics for deciding when two files are different:
+
+ * update.c, cvs.h (special_file_mismatch): New function.
+ (merge_file, join_file): Call it.
+ * no_diff.c (No_Difference): Call it.
+
+ * filesubr.c (xcmp): Consider files to be different if they are of
+ different types; if they are symlinks which link to different
+ pathnames; or if they are devices with different device numbers.
+ Error message is now `cannot lstat'.
+ * rcs.c (RCS_cmp_file): Use `xcmp' to compare files, simplifying
+ the special handling for nonregular files.
+
+ * rcscmds.c (diff_exec, diff_execv): If asked to obtain diffs for
+ special files, report no differences.
+
+ Miscellaneous changes to make special file support possible:
+
+ * commit.c (fix_rcs_modes): Don't attempt to `fix' permissions on
+ a symlink.
+
+ * import.c (add_rcs_file): Don't try to close fpuser if it was
+ never opened (e.g. when operating on a symlink).
+
+ * filesubr.c, cvs.h (isdevice, xreadlink): New functions.
+ * filesubr.c (copy_file): Handle special files and symlinks.
+ (xchmod): Do nothing if `preserve_perms' is set.
+
+ * commit.c (checkaddfile): Replace `copy_file (DEVNULL, ...)' with
+ fopen/fclose calls. Copy_file no longer attempts to read data
+ from device files.
+
+ * filesubr.c (islink): Use CVS_LSTAT, not lstat.
+ * vers_ts.c (time_stamp, time_stamp_server): Use CVS_LSTAT, not stat,
+ to get symlinks right.
+ * subr.c (get_file): Same. Don't attempt to read from special
+ files or symlinks.
+
+ * classify.c (Classify_File): Doc fix.
+
+Fri Feb 13 17:07:32 1998 Eric Mumpower <nocturne@cygnus.com>
+ and Ian Lance Taylor <ian@cygnus.com>
+
+ Fix some file system ordering problems found on Irix 6.4:
+ * sanity.sh (basic2): Use dotest_sort for test 56.
+ (importb): Use dotest_sort for tests importb-1 and importb-2.
+ (head): Use dotest_sort for test head-1.
+
+Thu Feb 12 15:15:33 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c (add_rcs_file): If add_logfp is NULL, don't call fperror.
+
+11 Feb 1998 Andy Piper
+
+ * server.c (cvs_output_binary): Use OPEN_BINARY not _O_BINARY.
+
+Mon Feb 9 18:34:39 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Tweaks to Ian's checkin:
+ * update.c (merge_file): Remove comment about sending file to
+ client before the message. It doesn't apply to this code any more
+ (it does apply to checkout_file, but I'm not sure it is important
+ to have such a comment anyway).
+ * buffer.c (buf_default_memory_error, buf_length): Reindent.
+ * server.h: Declare struct buffer before use.
+
+Mon Feb 9 21:05:28 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_fully_parse): Call getrevnum rather than getrcsrev.
+ Don't bother with ungetc.
+
+ * rcs.c (getrcsrev): Rewrite to simply call getrevnum.
+
+Sun Feb 8 15:49:39 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ Don't have the server check out a revision into a file and then
+ immediately read the file; just read into a buffer instead.
+ * update.c: Include buffer.h.
+ (update_fileproc): Let checkout_file call server_updated.
+ (checkout_file): Add merging and update_server parameters. Change
+ all callers. If server_active, don't mess with backup files. If
+ server_active, copy the revision into a buffer rather than a file
+ when possible. If update_server, call server_updated. Fix
+ handling of error status.
+ (checkout_to_buffer): New static function used by checkout_file.
+ (merge_file): Let checkout_file call server_updated.
+ (join_file): Likewise.
+ * server.c (server_updated): Change file_info parameter to mode
+ parameter. Add filebuf parameter. Change all callers. If
+ filebuf is not NULL, don't read the file.
+ * server.h (server_updated): Update declaration.
+ * buffer.c (buf_free): New function.
+ (buf_append_buffer): New function.
+ (buf_length): New function.
+ * buffer.h (buf_free, buf_append_buffer, buf_length): Declare.
+
+ * buffer.c: (buf_initialize): If the memory parameter is NULL, use
+ buf_default_memory_error.
+ (buf_default_memory_error): New static function.
+ * buffer.h (BUFMEMERRPROC): Define typedef.
+ * client.c (buf_memory_error): Remove.
+ (start_server): Pass NULL rather than buf_memory_error as buffer
+ memory error function.
+
+Sat Feb 7 16:27:30 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_parsercsfile_i): Read the expand keyword from the RCS
+ file. We do this because Version_TS calls RCS_getexpand in many
+ common cases, and we don't want to reopen the file just for that.
+ (RCS_reparsercsfile): Skip the expand keyword.
+ (RCS_getexpand): Don't call RCS_reparsercsfile.
+
+ * rcs.c (STREQ): New macro. In all string equality tests in the
+ file, replace strcmp with STREQ.
+
+Fri Feb 6 16:14:49 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (checkout_file): If we've already removed the backup
+ file once, don't try to remove it again.
+
+ * filesubr.c (unlink_file_dir): Call stat rather than isdir, and
+ don't call unlink if the file does not exist.
+
+ * myndbm.c (mydbm_load_file): Rename line_len to line_size. Call
+ getstr rather than getline, to avoid any confusion between \n and
+ \012. Use the line length returned by getstr rather than calling
+ strlen. Remove local variable len.
+
+Fri Feb 6 13:23:46 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_parsercsfile_i): Don't suppress errors on
+ really_quiet.
+ (RCS_parsercsfile_i, RCS_reparsercsfile, RCS_fully_parse,
+ RCS_deltas, getdelta, getrcskey, RCS_getdeltatext):
+ Check for errors. Include errno in error messages. Include
+ filename in error messages. Pass new argument to getrcskey.
+ (getrcskey): New argument NAME, so we can report errors ourself.
+
+Fri Feb 6 12:10:18 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_reparsercsfile): Don't use ftell/fseek; just keep
+ track of whether we've already read a key/value pair. Use sizeof
+ rather than strlen for a constant string. Pass the current key
+ and value to getdelta, and get them back as well.
+ (getdelta): Add keyp and valp parameters. Don't use ftell/fseek;
+ just return the key/value pair to the caller. Don't allocate
+ vnode before we know we need it. Check one getrcskey return
+ value. Use sizeof rather than strlen for a constant string.
+
+ * rcs.c (getrcskey): Correct comment describing return value.
+
+Thu Feb 5 22:51:13 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * subr.c (getcaller): Cache the result, so that we don't keep
+ searching the password file.
+
+Wed Feb 4 23:31:08 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (max_rev): Don't prototype. Interesting that noone
+ complained about this until now.
+
+4 Feb 1998 Jim Kingdon
+
+ * rcs.c (RCS_checkin): When adding a new file, read it
+ with "rb" if binary.
+
+Fri Jan 30 11:32:41 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Also test "first-dir" as the regexp in loginfo in
+ addition to ALL.
+
+ * main.c (main): Update year in copyright notice to 1998.
+
+Thu Jan 29 00:01:05 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.25.
+
+ * Version 1.9.24.
+
+ * sanity.sh (multibranch2): File file2 and tests multibranch2-13
+ through multibranch2-15 test a slightly different case than the
+ rest of multibranch2.
+
+ * mkmodules.c (cvswrappers_contents): Rewrite. The text didn't
+ describe -k and had various other problems.
+
+28 Jan 1998 Karl Fogel and Jim Kingdon
+
+ New feature to let server tell client about wrappers.
+ * client.h (struct response): Add comment about args being
+ '\0' terminated when passed to handle_* functions.
+ * client.c (start_server): send "wrapper-sendme-rcsOptions" to
+ server iff supported.
+ (responses): new response "Wrapper-rcsOption"; allows the server
+ to send certain lines from its cvswrappers file.
+ (handle_wrapper_rcs_option): new func, handles "Wrapper-rcsOption"
+ response from server.
+ * server.c (serve_wrapper_sendme_rcs_options): new func, sends
+ server side CVSROOT/cvswrappers rcs option lines to client.
+ (requests): new request "wrapper-sendme-rcsOptions"; if received,
+ we know we can send "Wrapper-rcsOption..." to the client.
+ * wrapper.c (wrap_unparse_rcs_options): new func; repeated calls
+ step down the wrapper list returning rcs option entries, but
+ repackaged as cvswrappers lines.
+ (wrap_setup): new guard variable `wrap_setup_already_done'; if
+ this function has run already, just return having done nothing.
+ Add comment concerning environment variable.
+ * cvs.h: declare wrap_unparse_rcs_options().
+
+Tue Jan 27 18:27:19 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * rtag.c (rtag_dirproc): Call ignore_directory, and skip the
+ directory if it returns true.
+ * sanity.sh (modules4): New set of tests to test some aspects of
+ excluding directories in the modules file, including the above
+ patch.
+
+Thu Jan 22 10:05:55 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_kopt): Check for length of arg. Based on
+ inspection of the code, plugs a buffer overrun security hole which
+ was introduced Monday.
+
+ * server.c (serve_is_modified): Don't call xmalloc; we aren't
+ allowed to call error() here. Remove duplicate (and potentially
+ confusing) variable 'p'.
+
+ * log.c (log_fileproc): Look for first character of version
+ '0' AND second character '\0', rather than OR. I didn't try to
+ come up with a test case but this looks like a simple thinko
+ (albeit one which would show up in obscure cases if at all).
+
+Tue Jan 20 19:37:53 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (send_dirent_proc): Don't send nonexistent directories
+ unless noexec.
+ * sanity.sh (modules2): New tests modules2-13 through modules2-18
+ test for this fix.
+
+Mon Jan 19 11:17:51 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_kopt): New function.
+ (requests): Add "Kopt" request.
+ (kopt): New variable.
+ (serve_is_modified): Write kopts from there into entries.
+ (serve_modified): Call serve_is_modified so we do the same.
+ Declare serve_modified and serve_is_modified.
+ * vers_ts.c (Version_TS): Set ->options even for a dummy ("D"
+ timestamp) entry.
+ * import.c (process_import_file): Check for -k options.
+ * client.c (client_process_import_file): Send Kopt request.
+ (send_fileproc): Likewise, for "cvs add".
+ * sanity.sh: Enable test binwrap3-sub2-add1 for remote.
+ Add -I .cvswrappers to binwrap3-2a; adjust binwrap3-2d
+ accordingly. Tests for this fix.
+
+Mon Jan 19 08:48:59 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (errmsg1): Append test 168 output to log file.
+
+Sat Jan 17 08:01:51 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (ann-10, ann-11): Don't make assumptions about the
+ number of characters in the username.
+
+Fri Jan 16 15:34:02 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * diff.c (diff_fileproc): Free label1 and label2 when finished.
+
+ * edit.c (editor_set): Don't free edlist until after we're
+ done using it.
+
+ * rcscmds.c (RCS_merge): Free xrev1 and xrev2 when finished.
+
+ * subr.c (make_message_rcslegal): Don't access uninitialized or
+ unallocated memory; only strip trailing blank lines.
+ * sanity.sh (log-3): Enhance to test this fix.
+
+Fri Jan 16 12:41:03 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add keywordlog to list of tests run by default.
+
+ * rcs.c (RCS_deltas): Don't call cvs_output if length is zero;
+ passing zero length to cvs_output does not mean output zero
+ bytes. The 27 Dec 1997 change to no longer '\0'-terminate the
+ ->text field turned this from a time bomb to a user-visible bug.
+ * sanity.sh (ann): New tests, test for this fix and other annotate
+ behaviors.
+
+Thu Jan 15 23:52:00 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * root.c (root_allow_ok): If inetd.conf didn't specify an
+ --allow-root options at all, we know we are in trouble. Give a
+ specific error message.
+
+Thu Jan 15 21:24:59 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (dotest_sort): New variant of dotest which sorts the
+ output, for use when the output depends upon details of the file
+ system, typically when doing an import.
+ (rdiff): Use dotest_sort for rdiff-1.
+ (ignore): Use dotest_sort for 188a, 188b, 189d, 190, and 191.
+
+ * sanity.sh: (TESTSHELL): New variable.
+ (editor, info, reserved): Use TESTSHELL in temporary script.
+
+ * sanity.sh (ignore): Do all tests in subdirectory, to avoid
+ conflict between cvsroot and CVSROOT on Windows.
+ (binwrap3, mwrap, info, config): Likewise.
+
+ * sanity.sh (binfiles2): Correct test name binfile2-7-brmod to
+ binfiles2-7-brmod.
+
+ * release.c (release_delete): If __CYGWIN32__ is defined, don't
+ worry about mismatched inodes. This is a hack, but then I think
+ the test is rather peculiar anyhow.
+
+Thu Jan 15 16:07:36 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (reserved-9): Use ${PROG} instead of "cvs".
+
+Wed Jan 14 15:43:13 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Split ChangeLog into ChangeLog-97 and ChangeLog.
+ * Makefile.in (DISTFILES): Add ChangeLog-97.
+
+13 Jan 1998 Jim Kingdon
+
+ * client.c: Declare handle_mt.
+
+Tue Jan 13 22:21:30 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add comment about how pwd and /bin/pwd often differ
+ in behavior (but are not guaranteed to).
+
+Tue Jan 13 13:49:53 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh: When setting TMPPWD use just pwd, not /bin/pwd.
+
+ * update.c (checkout_file): Don't pass set_time as true to
+ Version_TS if the file is dead.
+ * sanity.sh (modules): Add tests modules-155c6 through
+ modules-155c8 to test for above patch (without the above patch,
+ modules-155c8 will fail when remote).
+
+Tue Jan 13 10:37:02 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (send_modified): Change bufsize and newsize from int
+ to size_t to avoid type clashes in call to read_and_gzip.
+
+Tue Jan 13 10:33:02 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * zlib.c (read_and_gzip): Set finish to 0; it was uninitialized.
+
+Tue Jan 13 10:26:43 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * add.c, rcs.c: Plug memory leaks.
+
+Mon Jan 12 10:45:27 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (mkdir_p): Don't try to create nameless directories
+ (i.e., given "/foo//bar", don't try to create "/foo/",
+ just "/foo" and "/foo//bar") since it isn't necessary and
+ it fails on some systems in unexpected ways.
+
+1998-01-11 enami tsugutomo <enami@but-b.or.jp>
+
+ * rcs.c (linevector_copy): Delete lines before overwriting them.
+
+Sat Jan 10 11:05:40 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsrc.c, entries.c, login.c, logmsg.c, myndbm.c, patch.c,
+ release.c, server.c: Check for errors from getline, CVS_FOPEN,
+ fprintf, CVS_UNLINK and fclose. Note that the new errors are
+ nonfatal. This is because of conservatism more than because
+ it is always the best thing.
+ * login.c (get_cvs_password): Close the file when done with it.
+ * client.c (notified_a_file): If -1 return from getline, check
+ feof rather than assuming errno is set.
+
+Fri Jan 9 14:38:54 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (expand_proc): Also output server_dir in
+ "Module-expansion", not just in output_dir ("Created", &c).
+ * sanity.sh (modules2): New tests modules2-9 through modules2-12
+ test for this.
+
+Thu Jan 8 12:56:55 1998 Yasutoshi Hiroe <hiroe@rgk.ricoh.co.jp>
+
+ * import.c (import): Don't strcat on uninitialized memory. Fixes
+ possible SIGSEGV with zero-length message.
+
+Tue Jan 6 22:56:29 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (crerepos): Fix mistaken variable name which caused us
+ not to clean up at the end of the test.
+
+Mon Dec 22 01:40:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add): Also look for .cvswrappers files.
+ * sanity.sh (binwrap3): New tests binwrap3-2*, binwrap3-sub2-add*
+ test for this.
+
+Tue Jan 6 11:50:38 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (crerepos): New tests crerepos-8 through crerepos-18
+ test behaviors when mixing repositories.
+
+Sun Jan 4 17:40:22 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.23.
+
+ * Version 1.9.22.
+
+
+For older changes see ChangeLog-97.
diff --git a/src/ChangeLog-9194 b/src/ChangeLog-9194
new file mode 100644
index 0000000..eb79efc
--- /dev/null
+++ b/src/ChangeLog-9194
@@ -0,0 +1,524 @@
+Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * subr.c (run_setup, run_args): Check USE_PROTOTYPES if defined
+ instead of __STDC__, just like cvs.h does.
+
+Thu Sep 15 00:14:58 1994 david d `zoo' zuhn <zoo@monad.armadillo.com>
+
+ * main.c: rename nocvsrc to use_cvsrc, don`t read ~/.cvsrc when -H
+ has been seen
+
+Wed Sep 14 21:55:17 1994 david d `zoo' zuhn <zoo@monad.armadillo.com>
+
+ * cvs.h, subr.c: use size_t for xmalloc, xrealloc, and xstrdup
+ parameters
+
+ * cvsrc.c: optimize away two calls of getenv
+
+ * commit.c, subr.c: use mode_t for file mode values (Thanks to jtc@cygnus.com)
+
+ * main.c: update copyrights in -v message
+
+Tue Sep 6 10:29:13 1994 J.T. Conklin (jtc@rtl.cygnus.com)
+
+ * hash.c (hashp): Replace hash function with one from p436 of the
+ Dragon book (via libg++'s hash.cc) which has *much* better
+ behavior.
+
+Wed Aug 17 09:37:44 1994 J.T. Conklin (jtc@cygnus.com)
+
+ * find_names.c (find_dirs): Use 4.4BSD filesystem feature (it
+ contains the file type in the dirent structure) to avoid
+ stat'ing each file.
+
+Tue Aug 16 11:15:12 1994 J.T. Conklin (jtc@cygnus.com)
+
+ * rcs.h (struct rcsnode): add symbols_data field.
+ * rcs.c (RCS_parsercsfile_i): store value of rcs symbols in
+ symbols_data instead of parsing it.
+ (RCS_symbols): New function used for lazy symbols parsing.
+ Build a list out of symbols_data and store it in symbols if it
+ hasn't been done already, and return the list of symbols.
+ (RCS_gettag, RCS_magicrev, RCS_nodeisbranch, RCS_whatbranch):
+ Use RCS_symbols.
+ * status.c: (status_fileproc): Use RCS_symbols.
+
+Thu Jul 14 13:02:51 1994 david d `zoo' zuhn (zoo@monad.armadillo.com)
+
+ * src/diff.c (diff_fileproc): add support for "cvs diff -N" which
+ allows for adding or removing files via patches. (from
+ K. Richard Pixley <rich@cygnus.com>)
+
+Wed Jul 13 10:52:56 1994 J.T. Conklin (jtc@phishhead.cygnus.com)
+
+ * cvs.h: Add macro CVSRFLPAT, a string containing a shell wildcard
+ expression that matches read lock files.
+ * lock.c (readers_exist): Reorganized to use CVSRFLPAT and to not
+ compute the full pathname unless the file matches.
+
+ * rcs.h: Add macro RCSPAT, a string containing a shell wildcard
+ expression that matches RCS files.
+ * find_names.c (find_rcs, find_dirs): Use RCSPAT.
+
+Fri Jul 8 07:02:08 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * entries.c (Register): Pass two arguments to write_ent_proc, in
+ accordance with its declaration.
+
+Thu Jun 30 09:08:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * logmsg.c (do_editor): Fix typo ("c)continue" -> "c)ontinue").
+
+Thu Jun 23 18:28:12 1994 J.T. Conklin (jtc@phishhead.cygnus.com)
+
+ * find_names.c (find_rcs, find_dirs): use fnmatch instead of
+ re_comp/re_exec for wildcard matching.
+ * lock.c (readers_exist): Likewise.
+
+Fri May 20 08:13:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * modules.c (do_module): If something is aliased to itself, print
+ an error message rather than recursing.
+
+Fri May 6 19:25:28 1994 david d zuhn (zoo@monad.armadillo.com)
+
+ * cvsrc.c (read_cvsrc): use open_file for error checking
+
+Sat Feb 26 10:59:37 1994 david d zuhn (zoo@monad.armadillo.com)
+
+ * import.c: use $TMPDIR if available, instead of relying on /tmp
+
+Mon Jan 24 19:10:03 1994 david d zuhn (zoo@monad.armadillo.com)
+
+ * update.c (joining): compare join_rev1 with NULL instead of
+ casting pointer to an int
+
+ * options.h: remove S_IWRITE, S_IWGRP, S_IWOTH macros
+
+ * logmsg.c: #if 0 around gethostbyname prototype
+
+ * hash.c (printnode), find_names.c (add_entries_proc),
+ entries.c (write_ent_proc): correct declaration for function
+ (added void *closure)
+
+ * cvs.h: header include order reorganization: First include the
+ program config headers (config.h, options.h). Then include any
+ system headers (stdio.h, unistd.h). Last, get the program
+ headers and any cvs supplied library support
+
+ * commit.c: use xstrdup instead of strdup
+
+ * cvs.h: redefined USE(var) macro; comment after an #endif
+
+ * all .c files: remove the semicolon from after the USE(var)
+
+Sat Dec 18 00:17:27 1993 david d zuhn (zoo@monad.armadillo.com)
+
+ * cvs.h: include errno.h if available, otherwise declare errno if
+ it's not somehow else defined
+
+ * commit.c (checkaddfile): remove unused file argument from
+ RCS_nodeisbranch call
+
+ * rcs.c (RCS_nodeisbranch): remove file from arguments (was unused)
+
+ * rcs.h (RCS_nodeisbranch): remove file from prototype
+
+ * main.c: don't use rcsid when printing version number (the CVS
+ version number is independent of the repository that it comes
+ from)
+
+ * hash.c (printlist, printnode): use %p to print pointers, not %x
+ (avoids gcc format warnings)
+
+ * cvs.h: define USE if GCC 2, to avoid unused variable warning
+
+ * all .c files: use USE(rcsid)
+
+ * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead
+ (COMMON_OBJECTS): define, and use in several places
+ (OBJECTS): reorder alphabetically
+
+ * hash.c (nodetypestring): handle default return value better
+
+ * modules.c (do_module): remove extra argument to ign_dir_add
+
+ * main.c (main): initialize cvs_update_env to 0 (zero)
+
+ * modules.c (do_module): return error code when ignoring directory
+ (instead of a bare return). error code should be zero here
+
+ * cvs.h: add prototypes for ignore_directory, ign_dir_add
+
+ * ignore.c: add comments about ignore_directory
+
+ * root.c (Name_Root): remove unused variables has_cvsadm and path
+
+ * checkin.c (Checkin): only use -m<message> when message is non-NULL
+
+ * cvsrc.c (read_cvsrc): make sure homeinit is never used while
+ uninitialized (could have happened if getenv("HOME") had failed)
+
+ * cvs.h: include unistd.h if available
+
+Fri Dec 17 23:54:58 1993 david d zuhn (zoo@monad.armadillo.com)
+
+ * all files: now use strchr, strrchr, and memset instead of index,
+ rindex, and bzero respectively
+
+Sat Dec 11 09:50:03 1993 david d zuhn (zoo@monad.armadillo.com)
+
+ * version.c (version_string): bump to +104z
+
+ * Makefile.in: set standard directory variables, CC, and other
+ variables needed to be able to do 'make all' in this directory
+
+ * import.c: implement -k<subst> options, for setting the RCS
+ keyword expansion mode
+
+ * all files: use PROTO() macro for ANSI function prototypes
+ instead of #ifdef __STDC__/#else/#endif around two sets of
+ declarations
+
+Thu Nov 18 19:02:51 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * add.c (add), import.c (import), commit.c (commit): change
+ xmalloc & strcpy to xstrdup.
+
+ * commit.c (remove_file): correct another static buffer problem.
+
+Wed Nov 10 15:01:34 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * recurse.c (start_recursion): directories in repository but not
+ in working directory should be added to dirlist. Fixes "update
+ -d dir" case.
+
+ * version.c (version_string): bump to +103r.
+
+ * commit.c (checkaddfile): mkdir attic only if it does not already
+ exist. comment changes. changed diagnostic about adding on a
+ branch. if a file is added on a branch, remove and replace the
+ internal representation of that rcs file.
+
+Tue Nov 9 18:02:01 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * add.c (add): if a file is being added on a branch, then say so;
+ add quotes around file names in error messages.
+
+Thu Nov 4 16:58:33 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * version.c (version_string): bump to +102r.
+
+ * recurse.c (unroll_files_proc, addfile): new files, forward
+ decls, and prototypes.
+ (recursion_frame): new struct.
+ (start_recursion): rewrite to handle the case of "file1 file2
+ dir1/file3".
+
+ * rcs.c (RCS_parsercsfile): trap and error out on the case where
+ getrcskey tells us it hit an error while reading the file.
+
+ * commit.c (lock_filesdoneproc): add comment about untrapped error
+ condition.
+
+ * hash.c (addnode): comment change.
+
+ * subr.c: add comment about caching.
+
+ * sanity.sh: updated copyright.
+
+Wed Nov 3 14:49:15 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * version.c (version_string): bump to +101r.
+
+ * hash.c (walklist): add a closure for called routines. All
+ callers, callees, and prototypes changed.
+
+ * hash.c (nodetypestring, printnode, printlist): new functions for
+ dumping lists & nodes.
+
+ * tag.c (tag_fileproc): fatal out on failure to set tag.
+
+Tue Nov 2 14:26:38 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * version.c (version_string): bump version to +99.
+
+Mon Nov 1 15:54:51 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ Change buffer allocation for check in messages from static to
+ dynamic.
+ * add.c (add): dynamically allocate message.
+ (build_entry): check (message != NULL) now that message is a
+ pointer.
+ * commit.c (got_message, commit, commit_fileproc,
+ commit_filesdoneproc, commit_direntproc): removed. Replaced by
+ (message != NULL). Dynamically allocate message.
+ * cvs.h: adjust do_editor prototype and forward decl.
+ (MAXMESGLEN): removed.
+ * import.c (import): dynamically allocate message.
+ * logmsg.c (do_editor): change return type to char *. Remove
+ message parameter. Slight optimization to algorythm for
+ removing CVSEDITPREFIX lines. Add comment about fgets lossage.
+
+ * subr.c (xmalloc): change error message to print number of bytes
+ we were attempting to allocate.
+
+Fri Oct 29 14:22:02 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * add.c (add): prevent adding a directory if there exists a dead
+ file of the same name.
+
+ * sanity.sh: update argument to diff from "+ignore-file" to
+ "--exclude=".
+
+ * Makefile.in (TAGS): extend to work from an objdir.
+
+Mon Oct 18 18:45:45 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com)
+
+ * tag.c, rtag.c: change the default actions to make writing over
+ existing tags harder (but not impossible)
+
+Thu Oct 14 18:00:53 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com)
+
+ CVS/Root changes from Mark Baushke (mdb@cisco.com)
+
+ * Makefile.in: added new file called root.c
+
+ * create_adm.c: will create CVS/Root at the same time that the
+ other CVS files are being created
+
+ * cvs.h: new CVSADM_ROOT define plus new function externs
+
+ * main.c: default to using CVS/Root contents for CVSROOT
+ if neither the environment variable or the command line
+ "-d" switch is given. If either are given, perform a
+ sanity check that this directory belongs to that repository.
+
+ * update.c: if CVS/Root does not exist, then create it
+ during an update -- this may be removed if CVS/Root becomes a
+ standard feature
+
+ * root.c: implement new functions to manipulate CVS/Root
+ [this may be integrated with other utility functions in
+ a future revision if CVS/Root becomes a standard feature.]
+
+Wed Sep 29 17:01:40 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com)
+
+ * patch.c (patch_fileproc): output an Index: line for each file
+
+Mon Sep 6 18:40:22 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com)
+
+ * cvs.h: wrap definition of PATH_MAX in #ifndef PATH_MAX/#endif
+
+Tue Aug 9 21:52:10 1994 Mark Eichin (eichin@cygnus.com)
+
+ * commit.c (remove_file): actually allocate space for the
+ filename, not just the directory.
+
+Tue Jul 6 19:05:37 1993 david d `zoo' zuhn (zoo@cygnus.com)
+
+ * diff.c: patches to print an Index: line
+
+Mon Jun 14 12:19:35 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com)
+
+ * Makefile.in: update install target
+
+Tue Jun 1 17:03:05 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * Makefile.in: link cvs against libiberty
+
+Wed May 19 14:10:34 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * ignore.c: add code for keeping lists of directories to ignore.
+
+ * modules.c: new syntax for modules file, !dirname is added to
+ the list of directories to ignore
+
+ * update.c: don't process directories on the ignore list
+
+Tue Apr 6 14:22:48 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * cvs.h: Removed gethostname prototype, since it is unnecessary
+ and does not match prototype in <unistd.h> on HP/UX.
+
+Mon Mar 22 23:25:16 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * Makefile.in: rename installtest to installcheck
+
+Mon Feb 1 12:53:34 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * Makefile.in (check, installtest): set RCSBIN so that we
+ explicitly test the appropriate version of rcs as well.
+
+Fri Jan 29 13:37:35 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * version.c: bump version to +2.
+
+Thu Jan 28 18:11:34 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * import.c (update_rcs_file): if a file was dead, be sure to check
+ in the new version.
+
+ * update.c (checkout_file): if file_is_dead and we *did* have an
+ entry, scratch it.
+
+Tue Jan 26 16:16:48 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * sanity.sh: parcel into pieces for easier truncation when
+ debugging.
+
+ * update.c (checkout_file): print the "no longer pertinent"
+ message only if there was a user file.
+
+Wed Jan 20 17:08:09 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * update.c (checkout_file): remove unused variable s.
+ (join_file): remove unused variables rev & baserev. Fix a typo.
+
+ * commit.c (commit_fileproc): remove unused variable magicbranch.
+
+ * sanity.sh: bring back test 45 even though it fails. Update
+ tests against imported files.
+
+ * add.c (add_directory): move declaration of unused variable.
+
+ * Makefile.in (xxx): when building in this directory, pass CC for
+ the recursion.
+
+Mon Jan 18 13:48:33 1993 K. Richard Pixley (rich@cygnus.com)
+
+ * commit.c (remove_file): fix for files removed in trunk
+ immediately after import.
+
+ * commit.c (remove_file): initialize some variables. Otherwise we
+ end up free'ing some rather inconvenient things.
+
+Wed Jan 13 15:55:36 1993 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * Makefile.in (check, install, installtest): use the sanity test.
+
+ * sanity.el: make into real functions and bind to sun keys.
+
+ * sanity.sh: bring back to working order. Add test for death
+ after import.
+
+Tue Dec 22 17:45:19 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * commit.c (remove_file): when checking in a dead revision to a
+ branch as we are creating the branch, do not lock the underlying
+ revision. Also free some malloc'd memory.
+
+Wed Dec 2 13:09:48 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * RCS-patches: new file.
+
+Fri Nov 27 20:12:48 1992 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ Added support for adding previously removed files, as well as
+ adding and removing files in branches.
+
+ * add.c (build_entry): add new argument, tag, so as to store in
+ Entries the per directory sticky tag under which a file is
+ added. Changed prototype and caller.
+ (build_entry): Do not prevent file additions if the file exists
+ in the Attic.
+ (add): if the file being adding was previously dead, say so, and
+ mark the Entries file with the addition.
+ * checkin.c (Checkin): adding with a tag no longer means to add,
+ then tag. Hence, remove the tagging operation.
+ * classify.c (Classify_File): if the base RCS version is dead,
+ then the file is being added. If a file being added already
+ exists in the attic, and the base RCS version is NOT dead, then
+ we have a conflict.
+ * commit.c (checkaddfile): add the list of srcfiles to calling
+ convention. Change prototype and callers.
+ (remove_file): add message and list of srcfiles to calling
+ convention. Change prototype and callers. When removing a file
+ with a tag, remove the tag only when the tag does not represent
+ a branch. Remove files by committing dead revisions in the
+ appropriate branch. When removing files from the trunk, also
+ move the RCS file into the Attic.
+ (check_fileproc): when adding, and looking for previously
+ existing RCS files, do not look in the Attic.
+ (commit_fileproc): adding files with tags now implies adding the
+ file on a branch with that tag.
+ (checkaddfile): When adding a file on a branch, in addition to
+ creating the rcs file in the Attic, also create a dead, initial
+ revision on the trunk and stub in a magic branch tag.
+ * cvs.h (joining, gca): added prototypes.
+ * rcs.c (RCS_getbranch): now global rather than static.
+ remove prototype and forward decl.
+ (parse_rcs_proc): use RCS_addnode.
+ (RCS_addnode): new function.
+ (RCS_parsercsfile): recognize the new RCS revision
+ newphrase, "dead". Mark the node for the revision.
+ (RCS_gettag): requesting the head of a file in the attic now
+ returns the head of the file in the attic rather than NULL.
+ (RCS_isbranch): use RCS_nodeisbranch.
+ (RCS_nodeisbranch): new function.
+ (RCS_isdead): new function.
+ * rcs.h (RCSDEAD): new macro for new rcs keyword.
+ (struct rcsversnode): new field to flag dead revisions.
+ (RCS_nodeisbranch, RCS_isdead, RCS_addnode): new functions,
+ new prototypes, new externs.
+ (RCS_getbranch): now global, so prototype and extern moved
+ to here.
+ * subr.c (gca): new function.
+ * update.c (join_file): add entries list to calling
+ convention. Caller changed.
+ (update): also search the Attic when joining.
+ (checkout_file): when joining, checkout dead revisions too. If
+ a file has died across an update then say so.
+ (join_file): support joins of dead files against live ones, live
+ files against dead ones, and added files. Change the semantic
+ of a join with only rev specified to mean join specified rev
+ against checked out files via the greatest common ancestor of
+ the specified rev and the base rev of the checked out files.
+ (joining): new function.
+ * vers_ts.c (Version_TS): ALWAYS get the rcs version number.
+
+ * update.c (update): write the 'C' letter for conflicts.
+
+ * cvs.h (ParseTag): remove duplicate extern.
+
+ * add.c (add_directory): do not prompt for interactive
+ verification before adding a directory. Doing so prevents
+ scripted testing.
+
+Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in, configure.in: removed traces of namesubdir,
+ -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced
+ copyrights to '92, changed some from Cygnus to FSF.
+
+Tue Dec 10 01:24:40 1991 K. Richard Pixley (rich at cygnus.com)
+
+ * diff.c: do not pass an empty -r option to rcsdiff.
+
+ * update.c: fix bug where return code from rcsmerge wasn't being
+ handled properly.
+
+ * main.c: "rm" and "delete" now synonyms for "remove".
+
+ * commit.c: abort if editor session fails, but remember to clear
+ locks.
+
+ * Makefile.in: remove conf.h and checkin.configured on clean.
+ infodir belongs in datadir.
+
+Thu Dec 5 22:46:03 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: idestdir and ddestdir go away. Added copyrights
+ and shift gpl to v2. Added ChangeLog if it didn't exist. docdir
+ and mandir now keyed off datadir by default.
+
+Wed Nov 27 02:47:13 1991 K. Richard Pixley (rich at sendai)
+
+ * brought Makefile.in's up to standards.text.
+
+ * fresh changelog.
+
+
+For older changes, there might be some relevant stuff in the bottom of
+the NEWS file, but I'm afraid probably a lot of them are lost in the
+mists of time.
diff --git a/src/ChangeLog-9395 b/src/ChangeLog-9395
new file mode 100644
index 0000000..c2d2111
--- /dev/null
+++ b/src/ChangeLog-9395
@@ -0,0 +1,3731 @@
+Note: this log overlaps in time with ChangeLog-9194. There was a time
+during which changes which had been merged into the official CVS
+(which produced releases such as 1.4A1 and 1.4A2) went into what has
+become ChangeLog-9194, and changes which existed only at Cygnus went
+into this file (ChangeLog-9395). Eventually the Cygnus release became
+Cyclic CVS (as it was then called), which became CVS 1.5, so probably
+all the changes in both (what are now) ChangeLog-9194 and
+ChangeLog-9395 made it into 1.5.
+
+Sun Dec 31 17:33:47 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c (add_rev): Revert portion of 31 Aug 95 change which
+ passes -u to ci instead of using a hard link.
+ * sanity.sh (import): Add test for above-fixed bug.
+
+Sun Dec 31 16:40:41 1995 Peter Chubb <peterc@bookworm.sw.oz.au>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * admin.c (admin_fileproc): Call freevers_ts before returning.
+
+Mon Dec 25 12:20:06 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * logmsg.c (rcsinfo_proc): initialise line and
+ line_chars_allocated so they dont cause malloc problems within
+ getline(). This was causing rcsinfo templates to not work.
+
+Sun Dec 24 01:38:36 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (authenticate_connection): clarify protocol.
+
+ * login.c (login): deprolixify the password prompt.
+
+Sat Dec 23 10:46:41 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * myndbm.h, myndbm.c (dbm_store): New function.
+ * myndbm.h (DBM): Add modified and filename fields.
+ * myndbm.c (dbm_open, dbm_close): Manipulate new fields. dbm_open
+ no longer fails if the file doesn't exist and O_CREAT is set.
+ * cvs.h (CVSROOTADM_VALTAGS): Added.
+ * tag.c, cvs.h (tag_check_valid): New function.
+ * update.c (update), checkout.c (checkout_proc), commit.c (commit),
+ diff.c (diff), patch.c (patch_proc), rtag.c (rtag_proc), tag.c (tag):
+ Call it.
+ * sanity.sh: Test for rejection of invalid tagname.
+
+Fri Dec 22 18:21:39 1995 Karl Fogel <kfogel@csxt.cs.oberlin.edu>
+
+ * client.c (start_server): don't use kerberos if authenticating
+ server was specified.
+
+Fri Dec 22 16:35:57 1995 Karl Fogel <kfogel@csxt.cs.oberlin.edu>
+
+ * login.c (login): deal with new scramble methods.
+ (get_cvs_password): same.
+
+ * server.c (check_repository_password): remove arbitrary limit on
+ line length.
+ (authenticate_connection): use a separate variable for the
+ descrambled password, now that we no longer scramble in place.
+ Set `error_use_protocol' to 1 and just use error() where used to
+ do its job inline.
+
+ * cvs.h (scramble, descramble): adjust prototype.
+
+ * scramble.c (scramble, descramble): return char *.
+
+Fri Dec 22 13:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * release.c (release): If SERVER_SUPPORT is not defined, still
+ set up arg_start_idx.
+
+ * release.c (release): When calling unedit, set argv[1] to
+ NULL (since argc is only 1).
+
+ * edit.c: Pass dosrcs 0 to all calls to start_recursion.
+ None of the fileprocs were using it, so it just slowed things
+ down and caused potentially harmful checks for rcs files.
+
+ * edit.c (send_notifications): In client case, do not readlock.
+
+Thu Dec 21 16:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ Clean up Visual C++ lint:
+ * client.c (read_line): Change input_index and result_size to size_t.
+ (update_entries): Remove unused variables buf2, size_left, size_read.
+ (handle_mode): Prototype.
+ * client.c, client.h (send_to_server, read_from_server): Change
+ len to size_t.
+ * client.c (send_to_server): Change wrtn to size_t.
+ (read_from_server): Change red to size_t.
+ * client.c, myndbm.c, edit.c, fileattr.c: Include getline.h.
+ * checkin.c, commit.c, update.c: Include fileattr.h.
+ * commit.c, update.c: Include edit.h.
+ * edit.c (onoff_filesdoneproc): Prototype.
+ (ncheck_fileproc,edit_fileproc): Change "return" to "return 0".
+ (notify_do): Cast a signed value to unsigned before comparing
+ with unsigned value.
+
+Thu Dec 21 15:24:37 1995 Karl Fogel <kfogel@occs.cs.oberlin.edu>
+
+ * client.c: don't include socket headers twice just because
+ both HAVE_KERBEROS and AUTH_CLIENT_SUPPORT are set.
+ (start_kerberos_server): if fail to connect to kerberos, print out
+ a more specific error message, mainly so pcl-cvs can know what
+ happened and not panic.
+ (start_server): don't assume sprintf() returns len
+ written (only some systems provide this); instead, have
+ send_to_server() calculate the length itself.
+ (send_modified): same.
+ (send_fileproc): same.
+ (send_file_names): same.
+
+Wed Dec 20 14:00:28 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (ignore_files): Move from here...
+ * ignore.c (ignore_files): ...to here. No longer static. Take
+ new argument PROC.
+ * cvs.h (ignore_files): Declare.
+ * client.c (send_filesdoneproc): Split off from
+ update_filesdone_proc. Pass new function send_ignproc to
+ ignore_files (to ask server about ignored file before printing
+ "?").
+ * server.c: Rename outbuf from but_to_net and take it from
+ do_cvs_command to a global. Move initialization accordingly.
+ (serve_questionable): New function.
+ (requests): Add it.
+ * update.c (update_filesdone_proc): Remove client stuff. Pass new
+ function update_ignproc to ignore_files.
+ * cvs.h (joining, do_update): Move declarations from here...
+ * update.h: ...to here.
+ * cvs.h: Include update.h.
+ * update.c, client.c: Don't include update.h
+ * ignore.c, cvs.h: New variable ign_inhibit_server, set on -I !.
+ * import.c (import): Pass -I ! to server if specified.
+ (import_descend): If server, ignore CVS directories even if -I !.
+ * update.c (update), import.c (import): Only call ign_setup before
+ argument processing; don't call it again afterwards in client case.
+ * sanity.sh (ignore): Test above-fixed bugs and other ignore behaviors.
+ (dotest): New function.
+ Move modules checkin from modules test to start, so that other
+ tests can use mkmodules without a warning message.
+
+Wed Dec 20 13:06:17 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (send_to_server): don't check string's length twice.
+
+Wed Dec 20 02:05:19 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (login): took out debugging printf's.
+ (login): Removed unused variable `p'.
+
+Wed Dec 20 00:27:36 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (login): prefix scrambled password with 'A', so we know
+ which version of scrambling was used. This may be useful in the
+ future.
+ (get_cvs_password): skip past the leading 'A'.
+ Scramble $CVS_PASSWORD before returning it.
+
+ * scramble.c: made this work.
+
+Tue Dec 19 17:45:11 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (cvs_password): new static var, init to NULL.
+ (login): scramble() the password before using it.
+ Verify the password with the server.
+ Check CVSroot more carefully to insure that it is
+ "fully-qualified".
+ (get_cvs_password): if cvs_password is not NULL, just return it.
+ Never prompt -- just tell user why failed, then exit.
+ Try CVS_PASSWORD environment variable first.
+ (construct_cvspass_filename): try CVS_PASSFILE environment
+ variable first.
+
+ * client.h (connect_to_pserver): update prototype.
+
+ * client.c (cvsroot_parsed): new static var.
+ (parse_cvsroot): set `cvsroot_parsed' to 1 when done.
+ (connect_to_pserver): return int.
+ Take `verify_only' arg. If it is non-zero, perform password
+ verification with the server and then shut down the connection and
+ return.
+ Call parse_cvsroot() before doing anything.
+
+ * server.c (authenticate_connection): deal with verification
+ requests as well as authorization requests.
+ descramble() the password before hashing it.
+
+ * cvs.h: prototype scramble() and descramble().
+
+ * Makefile.in: build scramble.o.
+
+ * scramble.c: new file, provides trivial encoding but NOT real
+ encryption.
+
+Mon Dec 18 20:57:58 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (login): don't insert extra newlines. They were
+ harmless, but confusing.
+
+Mon Dec 18 15:32:32 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * hash.c, hash.h (findnode_fn): New function.
+ * hash.c (hashp): Tweak hash function so that findnode_fn works.
+ * update.c (ignore_files): Call findnode_fn, not findnode.
+
+Mon Dec 18 09:34:56 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * myndbm.c: Remove arbitrary limit.
+
+ * client.c: Fix comment--Windows 95 requires NO_SOCKET_TO_FD, not
+ Windows NT.
+
+Mon Dec 18 01:06:20 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (server_sock): replaces `server_socket'.
+ (start_kerberos_server): added FIXME comment about how
+ NO_SOCKET_TO_FD is not dealt with in the kerberos case.
+ (connect_to_pserver): deal with NO_SOCKET_TO_FD case.
+ (read_line): deal with NO_SOCKET_TO_FD case.
+ (read_from_server): deal with NO_SOCKET_TO_FD case.
+ (send_to_server): deal with NO_SOCKET_TO_FD case.
+ (get_responses_and_close): deal with NO_SOCKET_TO_FD case.
+
+ * client.c (send_to_server): error check logging.
+ (start_server): error check opening of logfiles.
+ (read_from_server): error check logging.
+ (read_line): use fwrite() to log, & error_check it.
+ Don't log if using socket style, because read_from_server()
+ already logged for us.
+
+Mon Dec 18 00:52:26 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (use_socket_style): new static var, init to 0.
+ (server_socket): new static var.
+ (connect_to_pserver): don't deal with logging here.
+ Caller changed.
+ (start_kerberos_server): don't deal with logging here either.
+ Caller changed.
+
+Mon Dec 18 00:40:46 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (send_modified): don't error-check `to_server';
+ send_to_server() does that now.
+
+Mon Dec 18 00:19:16 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (get_cvs_password): Init `linebuf' to NULL.
+ free() `linebuf' and reset it for each new line.
+ (login): same as above.
+
+ * client.c: Removed all the varargs prototyping gunk.
+ (to_server, from_server): make these static.
+ (from_server_logfile, to_server_logfile): new vars.
+ (start_server): init above two new vars to NULL.
+ (send_to_server): return void.
+ Correct bug in which amount to be written would be too high if the
+ loop ever ran more than once.
+ Log to `to_server_logfile' if it's non-NULL.
+ (read_from_server): new func, does raw reading from server.
+ Logs to `from_server_logfile' if it's non-NULL.
+ (update_entries): just use read_from_server() instead of looping
+ to fread() directly from `from_server'.
+ (read_line): Log to `from_server_logfile' if it's non-NULL.
+
+ * client.h: send_to_server() returns void now.
+ (read_from_server): prototype.
+
+Sun Dec 17 19:38:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (checkout_proc), client.c, lock.c (readers_exist),
+ login.c, modules.c (cat_module, do_module): Remove arbitrary limits.
+
+ * client.c (send_to_server): Fix typo (NULL -> '\0').
+ (get_responses_and_close): Set server_started to 0 instead of
+ setting to_server and from_server to NULL.
+ * client.c: Make to_server and from_server static.
+
+Sun Dec 17 17:59:04 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.h (to_server, from_server): don't declare these anymore.
+ They are now entirely private to client.c (and in fact will go
+ away soon there too).
+
+Sun Dec 17 15:40:58 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.h: update prototype of send_to_server().
+
+ * client.c, watch.c, update.c, tag.c, status.c, rtag.c, remove.c,
+ release.c, patch.c, log.c, import.c, history.c, edit.c, diff.c,
+ commit.c, client.c, checkout.c, admin.c, add.c:
+ Convert all send_to_server() calls that used formatting to send
+ pre-formatted strings instead. And don't error check
+ send_to_server(), because it does its own error checking now.
+
+ * client.c (send_to_server): don't use vasprintf(), just fwrite a
+ certain number of bytes to the server. And do error checking
+ here, so our callers don't have to.
+ (send_arg): use send_to_server() instead of putc()'ing
+ directly to `to_server'.
+
+Sun Dec 17 14:37:52 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h.in (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT):
+ Define to 1 but leave commented out, instead of #undef'ing them.
+ This treats them like everything else in this file.
+
+ * client.c: define server_started, init to 0.
+ (start_server): set server_started to 1.
+
+ * client.h: declare `server_started', extern.
+ AUTH_CLIENT_SUPPORT moved here from cvs.h.
+
+ * cvs.h: moved AUTH_CLIENT_SUPPORT stuff to client.h.
+
+ * edit.c (notify_check): use new var server_started.
+
+Sun Dec 17 00:44:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (get_responses_and_close): Really stop ignoring ECHILD
+ errors. The Nov 30 1995 change claimed to do this, but the code
+ was not actually changed.
+
+ * update.c (ignore_files): Revert H.J. Lu change; it was wrong for
+ directories and sometimes looked at sb.st_mode when it wasn't set.
+ * import.c (import_descend): Revert H.J. Lu change; it was wrong
+ for directories and the extra lstat call was an unnecessary
+ performance hit.
+ * sanity.sh (import): Add test for the second of these two bugs.
+
+Sat Dec 16 17:26:08 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (send_to_server): Remove arbitrary limit. Also remove
+ !HAVE_VPRINTF code; all relevant systems have vprintf these days.
+
+Sat Dec 16 21:35:31 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * checkout.c (checkout): use send_to_server() now.
+
+Sat Dec 16 21:18:16 1995 H.J. Lu (hjl@gnu.ai.mit.edu)
+ (applied by kfogel@cyclic.com)
+
+ * import.c (import_descend): We ignore an entry if it is
+ 1. not a file, nor a link, nor a directory, or
+ 2. a file and on the ignore list.
+
+ * update.c (ignore_files): We ignore any thing which is
+ 1. not a file, or
+ 2. it is a file on the ignore list.
+
+Sat Dec 16 00:14:19 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (send_to_server): corrected comment.
+
+ * client.h: prototype new func send_to_server().
+
+ * add.c, admin.c, client.c, commit.c, diff.c, edit.c, history.c,
+ import.c, log.c, patch.c, release.c, remove.c, rtag.c, status.c,
+ tag.c, update.c, watch.c:
+ Use send_to_server() instead of writing directly to to_server.
+
+ * client.c: conditionally include the right stuff for variable arg
+ lists.
+ (send_to_server): new func.
+
+Fri Dec 15 23:10:22 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * error.c: expanded comments.
+
+ * client.c (connect_to_pserver): verbosify errors.
+ (connect_to_pserver): use send() and recv(), not write() and
+ read(). Sockets are not file descriptors on all systems.
+
+Fri Dec 15 22:36:05 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (connect_to_pserver): oops, removed old debugging
+ printf.
+
+Fri Dec 15 18:21:16 1995 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * client.c (auth_server_port_number): don't call htons();
+ init_sockaddr() does that for us.
+ (init_sockaddr): zero the sockadder_in struct before doing
+ anything with it. IBM TCP/IP docs recommend this, and it can't
+ hurt.
+
+Fri Dec 15 15:21:53 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (connect_to_pserver): new var `port_number', initialize
+ with new func auth_server_port_number() and pass to
+ init_sockaddr().
+ (auth_server_port_number): new func. Right now it just returns
+ `htons (CVS_AUTH_PORT)'. We'll probably add the ability to
+ specify the port at run time soon, anyway, so having this function
+ will make that easier.
+
+Wed Dec 6 18:08:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: Add CVSREP.
+ * find_names.c (find_dirs): Skip CVSREP too.
+ * fileattr.h, fileattr.c: New files, to manipulate file attributes.
+ * hash.c (nodetypestring), hash.h (enum ntype): Add FILEATTR.
+ * hash.c, hash.h (list_isempty): New function.
+ * recurse.c (do_recursion): Call fileattr_startdir before
+ processing files in a directory and fileattr_write and
+ fileattr_free (after files, before recursing).
+ * watch.c, watch.h: New files, to handle notification features.
+ * edit.c, edit.h: New file, to handle new read-only checkout features.
+ * client.c, server.c: Add "Mode" request, to change the mode of a file
+ when it is checked in.
+ * main.c (cmds): Add "watch", "edit", "unedit", "watchers", "editors".
+ * main.c: Split command help from usg into new variable cmd_usage,
+ which.
+ (main): Add --help-commands option to print out cmd_usage.
+ * cvs.h: Declare watch, edit, unedit, watchers, editors.
+ * client.c, client.h: Add client_watch, client_edit, client_unedit,
+ client_watchers, client_editors.
+ * client.c, server.c: Add notification stuff.
+ * update.c (checkout_file, patch_file), checkin.c (Checkin): Check
+ _watched attribute when deciding read-only or read-write.
+ * commit.c (checkaddfile): Call fileattr_newfile to set attributes
+ on newly created files.
+ * release.c (release):
+ * cvs.h: Add CVSADM_NOTIFY and CVSADM_NOTIFYBAK.
+ * recurse.c (do_recursion): Call notify_check.
+ * commit.c (commit_fileproc): Call notify_do after committing file.
+ * client.c (get_responses_and_close): Set to_server and from_server
+ to NULL so that it is possible to tell whether we are speaking to
+ the server.
+ * cvs.h: Add CVSROOTADM_NOTIFY.
+ * mkmodules.c (main): Add CVSROOTADM_NOTIFY to filelist.
+ * Makefile.in (SOURCES,OBJECTS,HEADERS): Add new files mentioned above.
+ * lock.c, cvs.h (lock_tree_for_write, lock_tree_cleanup): New
+ functions, taken from old commit.c writelock code. As part of
+ this, fsortcmp and lock_filesdoneproc go from commit.c to lock.c.
+ So does locklist but it gets renamed to lock_tree_list.
+ * commit.c: Use lock_tree_*.
+
+Fri Dec 15 10:37:00 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * tag.c (tag_usage): Added -r and -D flags to usage string.
+ (tag): Detect when user specifies both -r and -D arguments.
+ Pass -r and -D arguments to server.
+
+Thu Dec 14 11:56:13 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_rsh_server): use RSH_NEEDS_BINARY_FLAG to
+ conditionalize "-b" option to "rsh".
+
+ * run.c (filter_stream_through_program): document return value and
+ error behavior.
+
+ * client.c (filter_through_gunzip): pass the supposedly
+ superfluous "-d" option to gunzip, to avoid stimulating what seems
+ to be an argument-passing bug in spawn() under OS/2 with IBM
+ C/C++. Yucko.
+
+Wed Dec 13 20:08:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in (RCSBIN_DFLT): Recommend specifying -b in
+ inetd.conf for pserver. That is a pretty good solution.
+
+Wed Dec 13 18:29:59 1995 Preston L. Bannister <pbannister@ca.mdis.com>
+ and Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (send_modified): make sure that vers and vers->options
+ are non-NULL before strcmp()'ing them with "-kb".
+ Initialize `bin' near where it is used, not at beginning of
+ function.
+ (update_entries): make sure `options' is non-NULL before
+ strcmp()'ing with "-kb".
+ Initialize `bin' near where it is used, not at beginning of
+ function.
+
+Tue Dec 12 18:56:38 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * options.h.in (RCSBIN_DFLT): document the probable need for this
+ to be set in the authenticating server.
+
+Tue Dec 12 11:56:43 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (expand_proc): If mfile is non-NULL, return it too as
+ part of the expansion.
+ * sanity.sh (modules): Add tests for above-fixed bug.
+
+Mon Dec 11 21:39:07 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * dog.c (flea_bath): Take `suds' arg.
+ All collars changed.
+
+Mon Dec 11 15:58:47 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (login): if client password file doesn't exist, create
+ it, duh.
+
+ * main.c (main): die if CVSroot has access-method but no
+ username.
+
+ * root.c: added some comments.
+
+ * main.c: removed all code pertaining to the "-a" option. We
+ specify access-method in CVSroot now.
+
+ * client.c (parse_cvsroot): new var, `access_method'. If CVSroot
+ is prepended with an access method (i.e.,
+ ":pserver:user@host:/path"), then handle it.
+
+ * login.c (login): use || when checking if CVSroot is "fully
+ qualified".
+ Prepend ":pserver:" before writing to ~/.cvspass.
+ (get_cvs_password): Take no parameters; we'll just use CVSroot to
+ get the password.
+
+Mon Dec 11 12:43:35 1995 adamg <adamg@microsoft.com>
+
+ * error.c, client.c, remove.c, main.c: Add explicit casts for some
+ function pointers to remove warnings under MS VC.
+ * main.c (main): remove use of NEED_CALL_SOCKINIT in favor of the
+ more generic INITIALIZE_SOCKET_SUBSYSTEM. Note that the code assumes
+ that if INITIALIZE_SOCKET_SUBSYSTEM() returns, socket subsystem
+ initialization has been successful.
+
+Sat Dec 9 22:01:41 1995 Dan O'Connor <doconnor@tii.com>
+
+ * commit.c (check_fileproc): pass RUN_REALLY flag to run_exec,
+ because it's okay to examine the file with noexec set.
+
+Sat Dec 9 20:28:01 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (update_entries): new var, `bin, init to 0.
+ Use it in determining whether to convert the file.
+ (send_modified): same as above.
+
+Fri Dec 8 17:47:39 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (downcase_string): removed.
+ (check_repository_password): don't deal with case-insensitivity
+ anymore.
+
+ * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): deleted this. No
+ need for it anymore.
+
+Thu Dec 7 21:08:39 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (check_repository_password): when checking for false
+ prefix-matches, look for ':', not '@'. Duh.
+
+Thu Dec 7 18:44:51 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): replaces
+ CVS_PASSWORDS_CASE_INSENSITIVE; passwords are now insensitive by
+ default. Expanded explanatory comment.
+
+ * login.c (get_cvs_password): Use memset(), not bzero(). I
+ botched this change earlier.
+
+ * server.c (check_repository_password): no need to check
+ xmalloc()'s return value.
+ (check_repository_password): check for false prefix-matches (for
+ example, username is "theo" and linebuf contains user
+ "theocracy").
+
+Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com)
+
+ * filesubr.c (isaccessible): Rename from isaccessable.
+ Update callers.
+ * cvs.h: Update prototype.
+ * main.c (main): Update callers.
+ * server.c (main): Update callers.
+
+Thu Dec 7 12:50:20 1995 Adam Glass <glass@NetBSD.ORG>
+
+ * cvs.h: "isaccessible" is the correct spelling.
+ Also add "const" to second arg to make prototype match
+ declaration.
+
+Thu Dec 7 11:06:51 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c, login.c: memset() instead of bzero().
+
+Thu Dec 7 00:08:53 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (authenticate_connection): document server's side of
+ the Authentication Protocol too.
+
+ * client.c (connect_to_pserver): when printing out "unrecognized
+ response", also print out the offending response.
+
+ * server.c (check_password): take `repository' arg too now.
+ Call check_repository_password() before checking /etc/passwd.
+ (check_repository_password): new func.
+
+ * options.h.in (CVS_PASSWORDS_CASE_INSENSITIVE): new define, unset
+ by default.
+
+Wed Dec 6 18:51:16 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (check_password): If user has a null password, then
+ return 1 if arg is also null.
+ Reverse sense of return value. Caller changed.
+
+Wed Dec 6 14:42:57 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (check_password): new func.
+ (authenticate_connection): call above new func.
+
+ * login.c (login): use construct_cvspass_filename().
+ If CVSroot is not "fully-qualified", then insist the user qualify
+ it before going on.
+ (get_cvs_password): fleshed out. Now reads from ~/.cvspass, or
+ prompts if no appropriate password found.
+ (construct_cvspass_filename): new func.
+
+ * server.c (authenticate_connection): send ACK or NACK to client.
+
+ * client.c (connect_to_pserver): check for ACK vs NACK response
+ from server after sending authorization request.
+
+ * login.c (get_cvs_password): new func.
+
+ * client.c (connect_to_pserver): use new func get_cvs_password().
+ Prototype it at top of file. Hmmm.
+
+Wed Dec 6 13:29:22 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c: same as below (AUTH_SERVER_SUPPORT).
+
+ * main.c: same as below (AUTH_SERVER_SUPPORT where appropriate).
+
+ * login.c: same same as below.
+
+ * cvs.h: same as below.
+
+ * client.c: use AUTH_CLIENT_SUPPORT, not CVS_LOGIN.
+
+ * options.h.in (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): these
+ replace CVS_LOGIN.
+
+Wed Dec 6 00:04:58 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (authenticate_connection): expanded comment.
+
+Tue Dec 5 23:37:39 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (connect_to_pserver): read password from prompt for
+ now.
+
+ * server.c (authenticate_connection): if the password passes
+ muster, then don't abort.
+
+Tue Dec 5 22:46:37 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * subr.c (strip_trailing_newlines): new func.
+
+ * client.c (connect_to_pserver): took out print statements.
+
+ * server.c (authenticate_connection): removed print statments.
+ Use new func strip_trailing_newlines() to purify `repository',
+ `username', and `password'.
+ Run a primitive password check, just for testing.
+
+ * client.c (connect_to_pserver): use CVS_AUTH_PORT.
+ Take tofdp, fromfdp, and log args. Caller changed.
+ (get_responses_and_close): either kerberos and CVS_LOGIN might
+ have one fd for both directions, so adjust #ifdef accordingly.
+
+ * cvs.h (CVS_AUTH_PORT): new define, default to 2401.
+ Prototype strip_trailing_newlines().
+
+Tue Dec 5 16:53:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * server.c (authenticate_connection): new func.
+
+ * client.c (init_sockaddr): func moved here from login.c.
+ (connect_to_pserver): same as above. Take no args, now.
+ Include <sys/socket.h>, <netinet/in.h>, <netdb.h>, if CVS_LOGIN.
+
+ * cvs.h: Declare use_authenticating_server, as extern int.
+ Declare connect_to_pserver().
+
+ * main.c (main): call authenticate_connection(). Removed testing
+ code.
+ Add 'a' to the short-option string in the getopt() call.
+
+ * login.c (connect_to_pserver): moved to client.c.
+
+Tue Dec 5 16:01:42 1995 Peter Chubb <peterc@bookworm.sw.oz.au>
+ (patch applied by Karl Fogel <kfogel@cyclic.com>)
+
+ * update.c (join_file): if vers->vn_user is "0", file has been
+ removed on the current branch, so print an error and return.
+
+Mon Dec 4 14:27:42 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.3.
+
+Mon Dec 4 16:28:25 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * release.c (release): add return (0) as last line
+
+ * cvs.h: declare program_path
+
+ * main.c define program_path
+ (main): set program_path
+
+ * release.c (release): use program_path for update_cmd
+
+Mon Dec 4 11:22:42 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.2.
+
+Sun Dec 3 20:02:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.h (struct rcsnode), rcs.c (freercsnode): Add expand field.
+ * rcs.h (RCSEXPAND): New #define.
+ * rcs.c (RCS_reparsercsfile): Record keyword expansion in expand
+ field of struct rcsnode.
+ * update.c (checkout_file): Set keyword expansion in Entries file
+ from rcs file if there is nowhere else to set it from.
+ * client.c (send_modified, update_entries) [LINES_CRLF_TERMINATED]:
+ If -kb is in effect, don't convert.
+
+ * update.c (update_file_proc), commit.c (check_fileproc),
+ rcscmds.c (RCS_merge): Direct stdout to DEVNULL rather than
+ passing -s option to grep. This avoids trouble with respect to
+ finding a grep which support -s and whether we should use the (GNU
+ grep) -q option if it exists.
+ * options.h.in: Change "@ggrep_path@" to "grep".
+
+Fri Dec 1 11:53:19 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * rcs.c (RCS_gettag): new parameter return_both force return both
+ tags: the symbolic and the numeric one.
+ (RCS_getversion): new parameter return_both is forwarded to
+ RCS_gettag.
+
+ * rtag.c, tag.c, commit.c, patch.c, update.c: pass 0 as additional
+ last parameter to RCS_getversion and RCS_gettag
+
+ * rcs.h (RCS_gettag): new parameter return_both.
+ (RCS_getversion): new parameter return_both.
+
+ * cvs.h (struct vers_ts): add vn_tag slot for symbolic tag name
+
+ * vers_ts.c (Version_TS): call RCS_getversion with 1 for
+ return_both and split output into vn_rcs and vn_tag
+ (freevers_ts): free vn_tag
+
+ * update.c (checkout_file): use vn_tag instead of vn_rcs when
+ calling 'rcs co' to allow rcs expansion of :$Name :
+
+Thu Nov 30 20:44:30 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (get_responses_and_close): undo previous change
+ regarding waitpid(). The problem has been solved by modifying
+ os2/waitpid.c instead of its callers.
+
+Thu Nov 30 16:37:10 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c: All these changes are for OS/2, which will no longer have
+ a separate client.c:
+ (start_kerberos_server): new func, contains code that
+ used to be in start_server().
+ (start_server): moved kerberos code to above function, reorganized
+ the rest. Added authentication clause.
+ (call_in_directory): test errno against EACCESS, if EACCESS is
+ defined (this is for OS/2's oddball mkdir).
+ (change_mode): don't set execute permission on anything if
+ EXECUTE_PERMISSION_LOSES is defined.
+ (get_responses_and_close): if START_RSH_WITH_POPEN_RW, then use
+ pclose() instead of fclose().
+ If waitpid errors with ECHILD, don't die. This is okay.
+ (start_rsh_server): alternate definition if
+ START_RSH_WITH_POPEN_RW.
+
+ * main.c: [all these changes conditional on CVS_LOGIN: ]
+ Don't prototype connect_to_pserver, don't enter it in cmds[]
+ (actually, it was never in there, I don't know why my previous
+ change said it was).
+ (use_authenticating_server): new global var.
+ (main): if "-a", then set above new var to TRUE.
+ (usg): document "-a" option.
+
+Wed Nov 29 12:55:10 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c: Prototype connect_to_pserver(), and enter it in cmds[].
+ (main): test some extremely primitive authentication.
+
+ * login.c: Include <sys/socket.h>
+ (connect_to_pserver): new func.
+ (init_sockaddr): new func.
+
+Mon Nov 20 14:07:41 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (TAGFILES): Separate out from DISTFILES, for C code.
+ (TAGS,tags): Use TAGFILES not DISTFILES.
+
+Sun Nov 19 11:22:43 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_recursion): Don't call server_pause_check if there
+ are writelocks around. Revise comment to reflect fact we are no
+ longer relying on a writelock'd operations being "unable" to
+ generate enough data to pause.
+
+Sun Nov 19 10:04:50 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * server.c, server.h, options.h.in: Implement hooks for doing
+ simple flow control on the server to prevent VM exhaustion on a
+ slow network with a fast server.
+ * recurse.c: Call the flow control check at a convenient location
+ while no locks are active. This is a convenience tradeoff against
+ accurate flow control - if you have a large directory it will all
+ be queued up, bypassing the flow control check until the next
+ directory is processed.
+
+Sat Nov 18 16:22:06 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c, update.c, vers_ts.c, server.c, rcs.c, lock.c,
+ ignore.c, entries.c, diff.c, commit.c, checkin.c:
+ Use new macro `existence_error', instead of comparing errno to
+ ENOENT directly.
+
+Fri Nov 17 14:56:12 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_server): removed alternate version of this func,
+ since os2/client.c will now be used under OS/2.
+
+Thu Nov 16 22:57:12 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (start_server): ifdef HAVE_POPEN_RW, use a different
+ version of start_server(). This is maybe not the cleanest cut to
+ make, but it's better than mucking around with yet more #ifdefs in
+ the middle of the old start_server() function. Once things are
+ up, I may reposition this code.
+
+Wed Nov 15 15:33:37 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): ifdef NEED_CALL_SOCKINIT, then call SockInit().
+ Only OS/2 needs this initialization.
+
+Tue Nov 14 18:54:01 1995 Greg A. Woods <woods@most.weird.com>
+
+ * patch.c:
+ - fix orientation of test for result of getline() call
+ - use fputs() not printf() when just copying file out
+
+ * cvsbug.sh:
+ - add space after #!
+ - new rcs id
+ - allow version to be edited by Makefile.
+
+ * Makefile.in:
+ - make Makefile a dependent of all (this might not be perfect, but
+ it at least gives you a chance to catch up on the second
+ go-around).
+ - filter cvsbug.sh in a manner similar to cvsinit.sh to get the
+ version number set from version.c
+
+Tue Nov 14 13:28:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Call old log file check.plog, not check.olog.
+
+ * sanity.sh: Convert remaining tests from old-style ('***' on fail
+ and nothing on pass), to new-style (FAIL on fail and PASS on pass).
+
+ * sanity.sh: Fix ability to run only some of the tests (always run
+ tests 1-4.75 to set up repository, document better how it works).
+
+ * sanity.sh: Change "completed successfully" to "completed" in
+ message--many tests, but not all, exit if they fail.
+
+Tue Nov 14 15:10:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * sanity.sh: test 63 doesn't work and probably can't
+
+Tue Nov 14 12:22:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * sanity.sh: many minor tweaks:
+ - make the optional arguments almost work
+ - use a function 'directory_cmp' instead of 'diff -r'
+ - fix up a few more tests that weren't working....
+
+Mon Nov 13 07:33:55 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h: ifdef USE_OWN_POPEN, #include "popen.h". Only OS/2 has
+ its own popen()/pclose() right now.
+
+Mon Nov 13 04:06:10 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h: conform to 80 column standard (yes, I'm a pedant).
+
+Sat Nov 11 13:45:13 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * client.c (process_prune_candidates): use unlink_file_dir() to
+ remove the directory, instead of invoking "rm" via run_exec().
+
+Fri Nov 10 14:38:56 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): removed "#define KF_GETOPT_LONG 1", since that
+ change is no longer in testing.
+
+Thu Nov 9 20:32:12 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * release.c (release): Use Popen(), not popen().
+
+Wed Nov 8 10:20:20 1995 Jim Meyering (meyering@comco.com)
+
+ * entries.c (ParseTag): Remove dcl of unused local.
+
+ * patch.c: Include getline.h.
+
+Wed Nov 8 11:57:31 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * options.h.in: add configuration option STEXID_SUPPORT (default
+ is off i.e. old semantics)
+
+ * filesubr.c (isaccessable): new function. Checks access-rights
+ for files like access(), but is getxid-safe. Falls back to
+ access() if SETXID_SUPPORT is not enabled.
+ (isfile): replace stat() by isaccessable(file, F_OK)
+ (isreadable): replace access() by isaccessable()
+ (iswritable): ditto
+ (make_directory): rename local variable buf to sb
+
+ * cvs.h: add prototype for new function isaccessable.
+
+ * server.c (serve_root): replace access() by isaccessable()
+
+ * cvsrc.c (read_cvsrc): replace access() by isreadable()
+
+ * main.c (main): replace access() by isaccessable()
+
+Wed Nov 8 10:22:41 1995 Greg A. Woods <woods@most.weird.com>
+
+ * entries.c (fgetentent): change definition to static to match the
+ declaration at the top of the file
+
+Tue Nov 7 16:59:25 1995 J.T. Conklin <jtc@lestat.cygnus.com>
+
+ * rcs.c (RCS_getbranch, RCS_getdate, RCS_getrevtime, RCS_gettag,
+ RCS_getversion, RCS_head): Use assert() instead of attempting to
+ "do the right thing" with a bogus RCSNode argument.
+
+Mon Nov 6 14:24:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c: Remove ctime define. It is just asking for trouble.
+
+Mon Nov 6 11:58:26 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * vers_ts.c: ifdef ctime, undef it before redefining it. It is a
+ macro on some systems.
+
+ * lock.c: don't prototype ctime() here. (See note below about
+ fgetentent() in entries.c.)
+
+Sun Nov 5 16:06:01 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * entries.c (fgetentent): don't prototype ctime here; we include
+ cvs.h, which includes system.h, which includes <time.h>
+ unconditionally (either as <time.h> or <sys/time.h>). Anyway, IBM
+ C/C++ chokes on mid-function, or even mid-file, prototypes. Sigh.
+
+Thu Nov 2 21:51:04 1995 Dan Wilder <dan@gasboy.com>
+
+ * rtag.c (rtag): Fix typo ("-T" -> "-F").
+
+Tue Oct 31 19:09:11 1995 Dan Wilder <dan@gasboy.com>
+
+ * diff.c (diff_dirproc): just return R_SKIP_ALL if dir not exist.
+ (diff_file_nodiff): don't complain if file doesn't exist, just
+ ignore.
+
+Tue Oct 31 09:25:10 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * sanity.sh: Use absolute pathname for mkmodules.
+
+Sat Oct 28 01:01:41 1995 Jim Meyering (meyering@comco.com)
+
+ * entries.c (ParseTag): Use getline instead of fgets.
+
+Fri Oct 27 13:44:20 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h: do nothing about alloca ifdef ALLOCA_IN_STDLIB. I am
+ rather suspicious of this solution, and will not be surprised to
+ find out that there's a Right Way to handle this situation ("this
+ situation" being that OS/2 simply declares alloca in <stdlib.h>).
+ Suggestions are welcome; see src/cvs.h and lib/system.h to see why
+ I was getting a conflict in the first place.
+
+Wed Oct 25 16:03:20 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * cvs.h (struct entnode): Add user field.
+ * entries.c (fputentent): New function, write entries line.
+ (write_ent_proc): Call fputentent to write entries line.
+ (Entnode_Create): New function, construct new Entnode.
+ (Entnode_Destroy): New function, destruct old Entnode.
+ (AddEntryNode): Changed to take an Entnode argument instead of
+ separate user, version, timestamp, etc. arguments.
+ (fgetentent): Changed to return Entnode.
+ (struct entent, free_entent): Removed.
+
+Wed Oct 25 12:44:32 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * admin.c (admin): Don't rely on ANSI C string concatenation;
+ SunOS 4.1.3 /bin/cc doesn't support it.
+
+Tue Oct 24 22:34:22 1995 Anthony J. Lill <ajlill@ajlc.waterloo.on.ca>
+
+ * import.c (expand_at_signs): Check errno as well as return value
+ from putc. Some systems bogusly return EOF when successfully
+ writing 0xff.
+
+Tue Oct 24 14:32:45 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * admin.c (admin): use getcaller() instead of getpwuid
+
+ * subr.c (getcaller): prefer getlogin() to $USER and $LOGNAME
+ (especially useful for NT where getuid always returns 0)
+
+Tue Oct 24 06:22:08 1995 Jim Meyering (meyering@comco.com)
+
+ * cvsrc.c (read_cvsrc): Use getline instead of fgets.
+ * patch.c (patch_fileproc): Use getline instead of fgets.
+
+ * entries.c (fgetentent): Use getline instead of fgets.
+ Use xmalloc to allocate space for each returned entry.
+ Since LINE is no longer static, save it in struct entent.
+ (struct entent): New member, line.
+ (free_entent): New function.
+ (Entries_Open): Call it after each call to fgetentent.
+
+Tue Oct 24 11:13:15 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.h: Declare valloc again, but this time with the right
+ signature (also changed in libs/valloc.c)
+
+Mon Oct 23 12:17:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c (do_editor): Check for errors from stdio calls.
+
+Mon Oct 23 12:37:06 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: Don't declare valloc. Some systems (e.g. linux) declare
+ it in stdlib.h in a conflicting way.
+
+Mon Oct 23 08:41:25 1995 Jim Meyering (meyering@comco.com)
+
+ * commit.c (commit_filesdoneproc): Use getline instead of fgets.
+
+ * logmsg.c (do_editor): Use getline instead of fgets.
+ (rcsinfo_proc): Likewise.
+
+ * logmsg.c (do_editor): Lose if fclose of temp file output
+ stream fails.
+
+Mon Oct 23 11:59:41 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * cvs.h: add valloc declaration
+
+ * server.h: add server_cleanup prototype
+
+ * server.c: remove server_cleanup prototype
+
+ * mkmodules.c (server_cleanup): fix parameter type
+
+ * server.c: encapsulate wait_sig in #ifdef sun (it's only used in
+ code which is also encapsulated in #ifdef sun)
+
+ * rcscmds.c (RCS_deltag, RCS_lock): add definition of noerr
+ parameter
+
+ * error.c: include cvs.h instead of config.h, add USE(rcsid)
+
+ * error.c (error): fix parameter type
+
+ * update.c (join_file): encapsulate recent changes from garyo
+ within #ifdef SERVER_SUPPORT
+
+Sun Oct 22 13:47:53 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * client.c (update_entries): Fix memory leak; free mode_string and
+ file_timestamp.
+ (send_fileproc): Fix memory leak; call freevers_ts before exiting.
+
+ * module.c (do_module): Partially fix memory leak; added
+ variable so that the address of memory allocated by line2argv
+ is retained, but comment out the call to free_names. Freeing
+ the vector at that point loses because some of the elements
+ may be used later in the function.
+ (cat_module): fix memory leak.
+
+ * recurse.c (start_recursion): Fix memory leak; free return
+ value of Name_Repository after it has been used.
+
+Sat Oct 21 23:24:26 1995 Jim Meyering (meyering@comco.com)
+
+ * client.c (send_modified) [LINES_CRLF_TERMINATED]: Comment text
+ after #endif.
+
+Fri Oct 20 14:41:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add test 87a, to test for bug fixed by garyo in
+ change below.
+
+Fri Oct 20 10:59:58 1995 Gary Oberbrunner <garyo@darkstar.avs.com>
+
+ * update.c (join_file): send file back to client even if no
+ conflicts were detected, by calling Register().
+
+Fri Oct 20 10:46:45 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * lock.c: Add prototype for Check_Owner
+
+Thu Oct 19 16:38:14 1995 Jim Meyering (meyering@comco.com)
+
+ * lock.c (Check_Owner): Declare function `static int'.
+
+Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c (expand_variable): Fix typo ('*'->'(').
+
+Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (commit_filesdoneproc): Check for errors from fopen,
+ fgets, and fclose.
+
+ * rcscmds.c (RCS_merge): Remove comment about rcsmerge -E.
+ Hacking CVS was never a very good solution; the situation is fixed
+ in RCS 5.7, and is documented in ../INSTALL.
+
+Thu Oct 19 15:06:15 1995 Jim Meyering (meyering@comco.com)
+
+ * filesubr.c (xchmod): Parenthesize arithmetic in operand of |
+ to placate gcc -Wall.
+
+ * expand_path.c (expand_path): Parenthesize assignments used as
+ truth values to placate gcc -Wall.
+
+ * commit.c (checkaddfile): Remove dcls of unused variables.
+ * lock.c (unlock): Remove dcl of unused variable.
+
+Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * root.c (Create_Root): If noexec, don't create CVS/Root.
+
+Wed Oct 18 11:19:40 1995 J.T. Conklin <jtc@slave.cygnus.com>
+
+ * lock.c (unlock): Change order of comparison so that Check_Owner
+ is called only if other conditions are true. This performance
+ enhancement was broken when the AFS support was added.
+
+Wed Oct 18 12:51:33 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): check if argv[0] is "pserver" with else-if, not
+ if, since we've already asked if it's "kserver".
+
+Tue Oct 17 18:09:23 1995 Warren Jones <wjones@tc.fluke.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Deal with supplying a relative cvs filename, or
+ with a cvs filename which doesn't have basename "cvs".
+
+Mon Oct 16 15:58:31 1995 Vince Demarco <vdemarco@bou.shl.com>
+
+ * parseinfo.c (Parse_Info): if the Keyword isn't ALL the current
+ version doesn't use the expanded variable, It should.
+
+Mon Oct 16 15:58:31 1995 Gary Oberbrunner <garyo@avs.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (server_register): Don't pass NULL to printf if tag,
+ date, or conflict is NULL.
+
+Thu Oct 12 12:13:42 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): begin to handle "pserver"; support not complete
+ yet, however.
+
+Thu Oct 12 02:52:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * expand_path.c: Don't #include <pwd.h>, since cvs.h already does,
+ and not all systems' <pwd.h>s are protected from multiple inclusion.
+ * login.c: Likewise.
+
+Wed Oct 11 15:23:24 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * login.c (login): handle everything correctly now.
+
+Wed Oct 11 12:02:48 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * rcs.c (RCS_gettag): support RCS keyword Name
+
+Tue Oct 10 19:11:16 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h.in (CVS_LOGIN): discuss, but leave commented out.
+ The "cvs login" command is still under construction; however, the
+ repository was changing so fast that instead of creating a branch
+ and dealing with the attendant hair, I'm just developing on the
+ trunk, making sure that everything is surrounded by "#ifdef
+ CVS_LOGIN ... #endif" so I don't get in anyone's way.
+
+ * login.c: include cvs.h before checking CVS_LOGIN, so it has a
+ chance to get defined before we ask if it's defined.
+ (login): oops, use semi not comma in `for' loop init.
+
+ * Makefile.in (SOURCES, OBJECTS): include login.c, login.o.
+
+ * main.c: added protoype for login().
+ Added "login" entry to cmds[].
+ (usg): added line about "login".
+
+ * login.c: new file.
+
+Tue Oct 10 18:33:47 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * Makefile.in (COMMON_OBJECTS): added error.o.
+ (OBJECTS): took error.o out; it's in COMMON_OBJECTS now.
+
+Tue Oct 10 12:02:37 1995 Thorsten Lockert <tholo@sigmasoft.com>
+
+ * cvsbug.sh: Cater to lame versions of sh (4.4BSD ash) by using
+ ${foo-bar} instead of `if....`.
+
+Tue Oct 10 12:02:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * remove.c (remove_fileproc): If noexec, don't remove file. Check
+ for error when removing file.
+
+Sun Oct 8 12:32:15 1995 Peter Wemm <peter@haywire.DIALix.COM>
+
+ * run.c: detect/use POSIX/BSD style reliable signals for critical
+ section masking etc. Helps prevent stray locks on interruption.
+
+Sat Oct 7 23:26:54 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * admin.c (admin): If group CVS_ADMIN_GROUP exists, allow only
+ users in that group to use "cvs admin".
+ * options.h.in: Default CVS_ADMIN_GROUP to "cvsadmin".
+
+Sat Oct 7 23:05:24 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * add.c, checkout.c, commit.c, cvs.h, filesubr.c, import.c,
+ lock.c, main.c, modules.c, options.h.in: New variable cvsumask
+ which is used to set mode of files in repository (regardless of
+ umask in effect when cvs is run).
+
+Sat Oct 7 22:40:17 1995 Stephen Bailey <sjbailey@sand.npl.washington.edu>
+
+ * lock.c: Include AFSCVS ifdefs to deal with AFS's lack of
+ correspondance between userid's from stat and from geteuid.
+
+Sat Oct 7 22:28:49 1995 Scott Carson <sdc@TracerTech.COM>
+
+ * add.c (add): Pass -ko, not -k -ko, to set keyword expansion options.
+
+ * admin.c (admin): Don't skip first argument when sending to server.
+
+Fri Oct 6 21:45:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Version 1.6.1.
+
+Fri Oct 6 21:31:28 1995 Jeff Johnson <jbj@brewster.jbj.org>
+
+ * cvs.h, admin.c, client.c, commit.c, log.c, modules.c,
+ parseinfo.c, patch.c, recurse.c, rtag.c, status.c, tag.c:
+ Prototype when dealing in pointers to functions.
+
+Fri Oct 6 21:07:22 1995 Mark H. Wilkinson <mhw@minster.york.ac.uk>
+
+ * cvsrc.c (read_cvsrc): fix look up of command names in cvsrc file
+ to use full name from command table rather than possible nickname
+ in argv. Fixes errors with things like `cvs di' when cvsrc has
+ `diff -u5' in it.
+
+Thu Aug 3 01:03:52 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * parseinfo.c (Parse_Info): Add code to call expand_path function
+ instead of using built in code.
+
+ * wrapper.c (wrap_add): Add code to call expand_path function to
+ expand all built in variables.
+
+ * expand_path.c (New file): expand things that look like
+ environmental variables (only expand local CVS environmental
+ variables) and user names like ~/.
+ * cvs.h: Declare expand_path.
+
+ * Makefile.in (SOURCES, OBJECTS): Added expand_path.c,
+ expand_path.o.
+
+Fri Oct 6 14:03:09 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ignore.c (ign_setup): Don't try to look for a file in CVSroot if
+ client. (The recent tightening of the error checking detects this).
+
+ * commit.c (checkaddfile): Don't try to pass options if it is "".
+
+Thu Oct 5 18:04:46 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * sanity.sh: unset CVSREAD, since it causes the script to bomb.
+
+Thu Oct 5 18:29:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * remove.c, add.c, commit.c, cvs.h: Remove CVSEXT_OPT stuff; it
+ has been broken for ages and the options are already stored in the
+ Entries file.
+
+Thu Oct 5 18:20:13 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * commit.c (checkaddfile): New argument options; pass it to RCS.
+ (commit_fileproc): Pass it.
+
+Tue Oct 3 09:26:00 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: upped to 1.6.
+
+Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c: if HAVE_SYS_BSDTYPES_H, include <sys/bsdtypes.h>.
+
+Mon Oct 2 10:34:53 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: Upped version to 1.5.95.
+
+Mon Oct 2 15:16:47 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * tag.c, rtag.c: pass "mov" instead of "add" if tag will be moved
+ (i.e. invoked with -F)
+
+Sun Oct 1 18:36:34 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: upped to 1.5.94.
+
+ * server.c: reverted earlier ISC change (of Sep. 28).
+
+ * version.c: upped to 1.5.93, for Peter Wemm's new SVR4 patch.
+
+Sun Oct 1 14:51:59 1995 Harlan Stenn <Harlan.Stenn@pfcs.com>
+
+ * main.c: don't #include <pwd.h>; cvs.h does that already.
+
+Fri Sep 29 15:21:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * version.c: upped to 1.5.91 for another pre-1.6 release.
+
+Fri Sep 29 14:41:14 1995 <bmeier@rzu.unizh.ch>
+
+ * root.c: start rcsid[] with "CVSid".
+
+Fri Sep 29 13:22:44 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * diff.c (diff): Doc fix.
+
+Fri Sep 29 14:32:36 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * repos.c (Short_Repository): chop superfluous "/".
+
+ * tag.c (pretag_proc): correct user-visible string.
+
+ * rtag.c (pretag_proc): correct user-visible string.
+
+Fri Sep 29 13:45:36 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * cvs.h (USE): if __GNUC__ != 2, expand to a dummy var instead of
+ nothing.
+
+Thu Sep 28 13:37:05 1995 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c: ifdef ISC, include <sys/bsdtypes.h>.
+
+Fri Sep 29 07:54:22 1995 Mike Sutton <mws115@llcoolj.dayton.saic.com>
+
+ * filesubr.c (last_component): Don't use ANSI style declaration.
+
+Wed Sep 27 15:24:00 1995 Del <del@matra.com.au>
+
+ * tag.c, rtag.c: Pass a few extra options to the script
+ named in taginfo (del/add, and revision number).
+
+ * tag.c: Support a -r option (at long last). Also needs
+ a -f option to tag the head if there is no matching -r tag.
+
+Tue Sep 26 11:41:08 1995 Karl Fogel <kfogel@totoro.cyclic.com>
+
+ * version.c: Upped version to 1.5.89 for test release preceding
+ 1.6.
+
+Wed Sep 20 15:32:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ignore.c (ign_add_file): Check for errors from fopen and fclose.
+
+Tue Sep 19 18:02:16 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove sanity.el from this list; the
+ file has been deleted.
+
+Thu Sep 14 14:17:52 1995 Peter Wemm <peter@haywire.dialix.com>
+
+ * import.c: Recover from being unable to open the user file.
+
+ * update.c (join_file): Print a message in the case where the file
+ was added.
+
+ * mkmodules.c: Deal with .db as well as .pag/.dir (for use with
+ BSD 4.4 and real dbm support).
+
+Mon Sep 11 15:44:13 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * release.c (release): Revise comment regarding why and how we
+ skip argv[0].
+
+Mon Sep 11 10:03:59 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * release.c (release): use return value of pclose to determine
+ success of update.
+
+Mon Sep 11 09:56:33 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * release.c (release_delete): Fix comment.
+
+Sun Sep 10 18:48:35 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * release.c (release): made work with client/server.
+ Don't ask if <arg> is mentioned in `modules'.
+
+Fri Sep 8 13:25:55 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: When committing a removal, send stdout to LOGFILE;
+ this is no longer a silent operation.
+
+ * sanity.sh: Remove OUTPUT variable; it is unused.
+
+ * client.c: Add comment regarding deleting temp file.
+ * main.c: Add comment regarding getopt REQUIRE_ORDER.
+
+Thu Sep 7 20:24:46 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * main.c (main): use getopt_long(), accept "--help" and
+ "--version".
+ Don't assume EOF is -1.
+
+Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * cvs.h (unlink_file_dir): Add prototype for this.
+
+Thu Sep 7 14:38:06 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * ALL FILES: add semicolon, as indicated below.
+
+ * cvs.h (USE): don't provide semicolon in the expansion of the USE
+ macro; we'd rather the callers provided it themselves because that
+ way etags doesn't get fooled.
+
+Mon Sep 4 23:30:41 1995 Magnus Hyllander <mhy@os.se>
+
+ * checkout.c: cvs export now takes -k option and does not default
+ to -kv.
+ * checkout.c, cvs.h, modules.c: Modules file now takes -e option
+ for cvs export.
+
+Mon Sep 4 23:30:41 1995 Kirby Koster <koster@sctc.com>
+
+ * commit.c: When committing a removal, print a message saying what
+ we are doing.
+
+Wed Aug 2 10:06:51 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * server.c: fix compiler warnings (on NeXT) (declare functions as
+ static inline instead of just static) functions: get_buffer_date,
+ buf_append_char, and buf_append_data
+
+Mon Sep 4 22:31:28 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (update_entries), import.c (expand_at_signs): Check for
+ errors from fread and putc.
+
+Fri Sep 1 00:03:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Fix TODO item pathname.
+
+ * sanity.el: Removed. It was out of date, didn't do much, and I
+ doubt anyone was using it.
+
+ * no_diff.c (No_Difference): Don't change the modes of the files.
+
+Thu Aug 31 13:14:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version to 1.5.1.
+
+ * client.c (start_rsh_server): Don't pass -d to "cvs server"
+ invocation via rsh (restore change which was lost when NT stuff
+ was merged in).
+ * sanity.sh: Add TODO item suggesting test for bug which this fixes.
+
+Wed Aug 30 12:36:37 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * sanity.sh (basic1): Make sure first-dir is deleted before
+ running this set of tests.
+
+ * subr.c: Extract file twiddling functions to a different file,
+ because we want to use different versions of many of these
+ routines under Windows NT.
+ (copy_file, isdir, islink, isfile, isreadable, iswritable,
+ open_file, make_directory, make_directories, xchmod,
+ rename_file, link_file, unlink_file, xcmp, tmpnam,
+ unlink_file_dir, deep_remove_dir): Moved to...
+ * filesubr.c: ...this file, which is new.
+ * Makefile.in (SOURCES): Mention filesubr.c.
+ (COMMON_OBJECTS): Mention filesubr.o.
+
+ * subr.c: Extract process execution guts to a different file,
+ because we want to replace these routines entirely under
+ Windows NT.
+ (VA_START, va_alist, va_dcl): Move this stuff...
+ (run_add_arg, run_init_prog): and these declarations...
+ (run_prog, run_argv, run_argc, run_argc_allocated): and these
+ variables...
+ (run_setup, run_arg, run_args, run_add_arg, run_init_prog,
+ run_exec, run_print, Popen): and these functions...
+ * run.c: To this file, which is new.
+ * Makefile.in (SOURCES): Mention run.c.
+ (COMMON_OBJECTS): Mention run.o.
+
+ * status.c (status): Call ign_setup, if client_active. Otherwise,
+ we don't end up ignoring CVS directories and such.
+
+ * server.c (mkdir_p, dirswitch): Use CVS_MKDIR instead of mkdir.
+
+ * repos.c (Name_Repository): Use the isabsolute function instead of
+ checking the first character of the path.
+ * root.c (Name_Root): Same.
+
+ * release.c (release): Use fncmp instead of strcmp to compare
+ filenames.
+
+ * rcs.c (RCS_parse, RCS_parsercsfile) [LINES_CRLF_TERMINATED]:
+ Abort, because we have strong reason to believe this code is
+ wrong.
+
+ * patch.c (patch): Register signal handlers iff the signal name is
+ #defined.
+
+ * no_diff.c (No_Difference): Don't try to include server_active in
+ trace message unless SERVER_SUPPORT is #defined.
+
+ * modules.c (do_module): Use CVS_MKDIR instead of mkdir.
+
+ * mkmodules.c (main): Call last_component instead of writing it out.
+
+ * main.c (main): Call last_component instead of writing it out.
+ Break up the long copyright string into several strings; Microsoft
+ Visual C++ can't handle a line that long. Feh.
+ Use fncmp instead of strcmp to compare filenames.
+ Register signal handlers iff the signal name is #defined.
+
+ * lock.c (readers_exist): Don't check return value of closedir.
+ Most of the rest of the code doesn't, and some systems don't
+ provide a return value anyway.
+ (set_lock): Use CVS_MKDIR instead of mkdir.
+
+ * import.c (import): Use the isabsolute function instead of
+ checking the first character of the path.
+ Try to delete the temporary file again after we close it, so it'll
+ get deleted on systems that don't let you delete files that are
+ open.
+ (add_rev): Instead of making a hard link to the working file and
+ checking in the revision with ci -r, use ci -u and restore the
+ permission bits.
+ (comtable): Include lines from SYSTEM_COMMENT_TABLE, if it is
+ #defined.
+ (add_rcs_file) [LINES_CRLF_TERMINATED]: Abort, because we have
+ strong reason to believe this code is wrong.
+ (import_descend_dir): Use CVS_MKDIR instead of mkdir.
+
+ * history.c (read_hrecs): Open the file with OPEN_BINARY.
+
+ * find_names.c (add_entries_proc, fsortcmp): Add prototypes.
+ * entries.c (write_ent_proc): Add prototype.
+ * hash.c (walklist): Add prototype for PROC argument.
+ (sortlist): Add prototype for COMP argument.
+ (printnode): Add a prototype, and make it static.
+
+ * cvs.h (wrap_add_file, wrap_add): Add extern decls for these;
+ they're used in import.c and update.c.
+ * wrapper.c (wrap_add_file, wrap_add): Remove them from here.
+
+ * cvs.h (RUN_NORMAL, RUN_COMBINED, RUN_REALLY, RUN_STDOUT_APPEND,
+ RUN_STDERR_APPEND, RUN_SIGNIGNORE, RUN_TTY, run_arg, run_print,
+ run_setup, run_args, run_exec, Popen, piped_child, close_on_exec,
+ filter_stream_through_program, waitpid): Move all these
+ declarations and definitions to the same section.
+
+ * cvs.h (error_set_cleanup): Fix prototype.
+
+ * cvs.h (isabsolute, last_component): New extern decls.
+
+ * cvs.h (link_file): Function is deleted; remove extern decl.
+
+ * cvs.h (DEATH_STATE, DEATH_SUPPORT): Move #definitions of these
+ above the point where we #include rcs.h, since rcs.h tests them
+ (or DEATH_SUPPORT, at least).
+
+ * cvs.h (DEVNULL): #define this iff it isn't already #defined.
+ config.h may want to override it.
+
+ * cvs.h (SERVER_SUPPORT, CLIENT_SUPPORT): Don't #define these
+ here; let config.h do that. On some systems, we don't have any
+ server support.
+
+ * cvs.h: Don't #include <io.h> or <direct.h>; we take care of
+ those in lib/system.h.
+
+ * commit.c (commit): Open logfile with the OPEN_BINARY flag.
+ (precommit_proc): Use the isabsolute function, instead of
+ comparing the first character with /.
+ (remove_file, checkaddfile): Use CVS_MKDIR instead of mkdir.
+
+ * client.c (send_repository): Use larger line buffers.
+
+ * client.c [LINES_CRLF_TERMINATED] (update_entries): If we've just
+ received a gzipped file, copy it over, converting LF to CRLF,
+ instead of just renaming it into place.
+ [LINES_CRLF_TERMINATED] (send_modified): Convert file to LF format
+ before sending with gzip.
+ (send_modified): Don't be disturbed if we get fewer than
+ sb.st_size characters when we read. The read function may be
+ collapsing CRLF to LF for us.
+
+ * client.c: Add forward declarations for all the cvs command
+ functions we call.
+
+ * client.c: Add forward static declarations for all the
+ handle_mumble functions.
+
+ On some systems, RSH converts LF to CRLF; this screws us up.
+ * client.c (rsh_pid): Declare this iff RSH_NOT_TRANSPARENT is not
+ #defined.
+ (get_responses_and_close): Use SHUTDOWN_SERVER if it is #defined.
+ Only wait for rsh process to exit if RSH_NOT_TRANSPARENT is not
+ #defined.
+ (start_rsh_server): Declare and define only if
+ RSH_NOT_TRANSPARENT is not #defined. Use piped_child, instead of
+ writing all that out.
+ (start_server): Only try to call start_rsh_server if
+ RSH_NOT_TRANSPARENT is not #defined. Use START_SERVER if it is
+ #defined. Convert file descriptors to stdio file pointers using
+ the FOPEN_BINARY_WRITE and FOPEN_BINARY_READ strings.
+
+ * client.h (rsh_pid): Don't declare this; it's never used elsewhere.
+ (supported_request): Add external declaration for this;
+ it's used in checkout.c.
+
+ Move process-running functions to run.c; we need to totally
+ replace these on other systems, like Windows NT.
+ * client.c (close_on_exec, filter_stream_through_program): Moved
+ to run.c.
+ * run.c (close_on_exec, filter_stream_through_program): Here they
+ are.
+
+ * add.c (add_directory): Use CVS_MKDIR instead of straight mkdir.
+ * checkout.c (checkout, build_dirs_and_chdir): Same.
+ (checkout_proc): Use fncmp instead of strcmp.
+ * client.c (call_in_directory): Use CVS_MKDIR instead of straight
+ mkdir.
+
+ * client.c (handle_checksum): Cast return value of strtol.
+
+Wed Aug 30 10:35:46 1995 Stefan Monnier <stefan.monnier@epfl.ch>
+
+ * main.c (main): Allow -d to override CVSROOT_ENV.
+
+Thu Aug 24 18:57:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h, rcscmds.c (RCS_unlock, RCS_deltag, RCS_lock): Add extra
+ parameter for whether to direct stderr to DEVNULL.
+ * checkin.c, tag.c, rtag.c, import.c, commit.c: Pass extra
+ argument. 1 if stderr had been directed to DEVNULL before
+ rcscmds.c was in use, 0 if it was RUN_TTY.
+
+ * cvs.h: Add comment regarding attic.
+
+Tue Aug 22 10:09:29 1995 Alexander Dupuy <dupuy@smarts.com>
+
+ * rcs.c (whitespace): Cast to unsigned char in case char is signed
+ and value is negative.
+
+Tue Aug 22 10:09:29 1995 Kirby Koster <koster@sctc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (join_file): If vers->vn_user is NULL, just return.
+
+Tue Aug 22 10:09:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c, client.c: Add comments about modes and umasks.
+
+Mon Aug 21 12:54:14 1995 Rick Sladkey <jrs@world.std.com>
+
+ * update.c (update_filesdone_proc): If pipeout, don't try to
+ create CVS/Root.
+
+Mon Aug 21 12:54:14 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_rsh_server): Don't pass -d to "cvs server"
+ invocation via rsh.
+
+ * server.c (serve_root): Report errors via pending_error_text.
+ (serve_valid_requests): Check for pending errors.
+
+Sun Aug 20 00:59:46 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Document usage of DIFF in update.c
+ * update.c: Use DIFF -c, not DIFF -u. The small improvement in
+ diff size is not worth the hassle in terms of everyone having to
+ make sure that DIFF is GNU diff (IMHO).
+
+Sat Aug 19 22:05:46 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * recurse.c (start_recursion): Doc fix.
+
+ * server.c (do_cvs_command): Clear error_use_protocol in the
+ child.
+ (server): Set error_use_protocol.
+
+Sun Aug 13 15:33:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (do_cvs_command): Don't select on exceptions.
+
+Fri Aug 4 00:13:47 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (LDFLAGS): Set to @LDFLAGS@.
+ (options.h): Depend on ../config.status and options.h.in.
+ Add rule to build it from dependents.
+
+ * add.c: Include save-cwd.h.
+ (add_directory): Use save_cwd and restore_cwd instead of
+ explicit getwd then chdir.
+ * import.c (import_descend_dir): Likewise.
+ * modules.c (do_module): Likewise.
+
+ * recurse.c (save_cwd, restore_cwd, free_cwd): Remove functions.
+ New versions have been broken out into save-cwd.c.
+ (do_dir_proc): Adapt to handle status code returned by new versions
+ of save_cwd and restore_cwd -- and one fewer argument to restore_cwd.
+ (unroll_files_proc): Likewise.
+
+ * wrapper.c (wrap_name_has): Add default: abort () to switch
+ statement to avoid warning from gcc -Wall.
+ (wrap_matching_entry): Remove dcl of unused TEMP.
+ (wrap_tocvs_process_file): Remove dcl of unused ERR.
+ (wrap_fromcvs_process_file): Likewise.
+
+ * cvs.h: Remove prototype for error. Instead, include error.h.
+ Also, remove trailing white space.
+
+Thu Aug 3 10:12:20 1995 Jim Meyering (meyering@comco.com)
+
+ * import.c (import_descend_dir): Don't print probably-bogus CWD
+ in error messages saying `cannot get working directory'.
+
+Sun Jul 30 20:52:04 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * parseinfo.c (Parse_Info): Revise comments and indentation.
+
+Sun Jul 30 15:30:16 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * history.c: put ifdef SERVER_SUPPORT around tracing code incase
+ the client/server code is not compiled into the program.
+
+Sat Jul 29 16:59:49 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c (deep_remove_dir): Use struct dirent, not struct direct.
+
+Sat Jul 29 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * add.c: Check wrap_name_has.
+
+ * diff.c, checkin.c, import.c: have code call unlink_file_dir in
+ the appropriate places instead of just calling unlink_file.
+
+ * checkin.c: Remove one unlink call.
+
+ * import.c (comtable): Add .m .psw .pswm.
+
+ * import.c (add_rcs_file): Remove tocvsPath before returning.
+
+ * subr.c (unlink_file_dir): Add new function. unlinks the file if
+ it is a file. or will do a recursive delete if the path is
+ actually a directory.
+ (deep_remove_dir): New function, helps unlink_file_dir.
+
+ * mkmodules.c: Added CVSROOTADM_WRAPPER (cvswrappers file) to the
+ checkout file list.
+
+Fri Jul 28 16:27:56 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (safe_location): Use PATH_MAX not MAXPATHLEN.
+
+Fri Jul 28 19:37:03 1995 Paul Eggert <eggert@twinsun.com>
+
+ * log.c (cvslog, log_fileproc): Pass all options (except -l)
+ to rlog as-is, so that users can put spaces in options,
+ can specify multiple -d options, etc.
+ (ac, av): New variables.
+ (log_option_with_arg, options): Remove.
+
+ (log_fileproc): Don't prepend `/' to file name if update_dir is empty.
+
+Tue Jul 25 00:52:26 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (safe_location): Don't use PROTO in function definition.
+
+Mon Jul 24 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * checkout.c (safe_location): fix a compiler warning. (Declare
+ safe_location). Changed code in safe_location to call getwd
+ instead of getcwd. getwd is declared in the ../lib directory and
+ used exclusively thoughout the code. (this helps portability on
+ non POSIX systems).
+
+ * wrapper.c: updated Andrew Athan's email address.
+
+ * main.c: fix an ifdef so the code will compile. syntax error in
+ the ifdef for CVS_NOADMIN.
+
+Mon Jul 24 13:25:00 1995 Del <del@babel.dialix.oz.au>
+
+ * checkout.c: New procedure safe_location.
+ Ensures that you don't check out into the repository
+ itself.
+
+ * tag.c, rtag.c, cvs.h, mkmodules.c: Added a "taginfo" file in
+ CVSROOT to perform pre-tag checks.
+
+ * main.c, options.h.in: Added a compile time option to
+ disable the admin command.
+
+Fri Jul 21 17:07:42 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c, status.c, patch.c, checkout.c, import.c, release.c,
+ rtag.c, tag.c: Now -q and -Q options just print an error message
+ telling you to use global -q and -Q options. The non-global
+ options were a mess because some commands accepted them and some
+ did not, and they were redundant with -q and -Q global options.
+
+ * rcs.c, cvs.h, commit.c, log.c, find_names.c: Remove CVS.dea
+ stuff. It is slower than the alternatives and I don't think
+ anyone ever actually used it.
+
+Fri Jul 21 10:35:10 1995 Vince DeMarco <vdemarco@bou.shl.com>
+
+ * Makefile.in (SOURCES, OBJECTS): Add wrapper.c, wrapper.o.
+ * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c,
+ remove.c, status.c: Call wrap_setup at start of commands.
+ * add.c (add): Check for wrapper, as well as directory, in repository.
+ * checkin.c: Add tocvsPath variable and associated handling.
+ * cvs.h: Add wrapper declarations.
+ * diff.c: Add tocvsPath variable and associated handling.
+ * import.c: Add -W option, CVSDOTWRAPPER handling.
+ (import_descend): check wrap_name_has.
+ (update_rcs_file, add_rev, add_rcs_file): add tocvsPath
+ variable and associated handling.
+ * no_diff.c: Add tocvsPath variable and associated handling.
+ * recurse.c (start_recursion): Check wrap_name_has.
+ * update.c: Copy, don't merge, copy-by-merge files. Attempt to
+ use -j on a copy-by-merge file generates a warning and no further
+ action.
+ * update.c: Add CVSDOTWRAPPER handling.
+ * wrapper.c: Added.
+
+Fri Jul 21 00:20:52 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c: Revert David Lamkin patch, except for the bits about
+ removing temp_filename and the .rej file.
+ * sanity.sh (errmsg1): Test for the underlying bug which Lamkin
+ kludged around.
+ * client.c (call_in_directory): Set short_pathname to include the
+ filename, not just the directory. Improve comments regarding what
+ is passed to FUNC.
+
+Thu Jul 20 17:51:54 1995 David Lamkin <drl@net-tel.co.uk>
+
+ * client.c (short_pathname): Fixes the fetching of the whole file
+ after a patch to bring it up to date has failed:
+ - failed_patches[] now holds short path to file that failed
+ - patch temp files are unlinked where the patch is done
+
+Thu Jul 20 12:37:10 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: Declare error_set_cleanup
+ * main.c: Call it.
+ (error_cleanup): New function.
+
+Thu Jul 20 12:17:16 1995 Mark H. Wilkinson <mhw@minster.york.ac.uk>
+
+ * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c,
+ client.h, commit.c, create_adm.c, cvs.h, diff.c, entries.c,
+ history.c, import.c, log.c, main.c, modules.c, no_diff.c, patch.c,
+ release.c, remove.c, repos.c, rtag.c, server.c, server.h,
+ status.c, subr.c, tag.c, update.c, vers_ts.c, version.c: Put
+ client code inside #ifdef CLIENT_SUPPORT, server code inside
+ #ifdef SERVER_SUPPORT. When reporting version, report whether
+ client and/or server are compiled in.
+
+Wed Jul 19 18:00:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * subr.c (copy_file): Declare local var n to be an int,
+ not a size_t. size_t is unsigned, and the return values
+ of read and write are definitely not unsigned.
+
+ * cvs.h [HAVE_IO_H]: #include <io.h>.
+ [HAVE_DIRECT_H]: #include <direct.h>.
+
+Fri Jul 14 22:28:46 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * server.c (dirswitch, serve_static_directory, serve_sticky,
+ serve_lost, server_write_entries, serve_checkin_prog,
+ serve_update_prog): Include more information in error messages.
+ (Thanks, DJM.)
+
+ * cvsbug.sh: Use /usr/sbin/sendmail, unless it doesn't
+ exist, in which case use /usr/lib/sendmail. (Thanks, DJM.)
+
+ * server.c (server, server_cleanup): Use "/tmp" instead of
+ "/usr/tmp" when the TMPDIR environment variable isn't set. This
+ is what the rest of the code uses.
+
+Thu Jul 13 11:03:17 1995 Jim Meyering (meyering@comco.com)
+
+ * recurse.c (free_cwd): New function.
+ (save_cwd, restore_cwd): Use it instead of simply freeing any
+ string. The function also closes any open file descriptor.
+
+ * import.c (comtable): Now static.
+ (comtable): Put braces around each element of initializer.
+
+ * cvs.h: Add prototype for xgetwd.
+ * recurse.c (save_cwd, restore_cwd): New functions to encapsulate
+ run-time solution to secure-SunOS vs. fchown problem.
+ (do_dir_proc, unroll_files_proc): Use new functions instead of
+ open-coded fchdir/chdir calls with cpp directives.
+
+ * sanity.sh: Change out of TESTDIR before removing it.
+ Some versions of rm fail when asked to delete the current directory.
+
+Wed Jul 12 22:35:04 1995 Jim Meyering (meyering@comco.com)
+
+ * client.c (get_short_pathname): Add const qualifier to parameter dcl.
+ (copy_a_file): Remove set-but-not-used variable, LEN.
+ (handle_clear_static_directory): Likewise: SHORT_PATHNAME.
+ (set_sticky): Likewise: LEN.
+ (handle_set_sticky): Likewise: SHORT_PATHNAME.
+ (handle_clear_sticky): Likewise: SHORT_PATHNAME.
+ (start_rsh_server): Convert perl-style `cond || stmt' to more
+ conventional C-style `if (cond) stmt.' Sheesh.
+ Remove dcl of unused file-static, SEND_CONTENTS.
+
+ * history.c: Remove dcls of set-but-not-used file-statics,
+ HISTSIZE, HISTDATA.
+ (read_hrecs): Don't set them.
+
+ * import.c (add_rev): Remove dcl of set-but-not-used local, RETCODE.
+
+ * repos.c (Name_Repository): Remove dcl of set-but-not-used local,
+ HAS_CVSADM.
+
+ * cvsrc.c (read_cvsrc): Parenthesize assignment used as truth value.
+
+Tue Jul 11 16:49:41 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * hash.h (struct entnode, Entnode): moved from here...
+ * cvs.h: to here.
+
+Wed Jul 12 19:45:24 1995 Dominik Westner (dominik@gowest.ppp.informatik.uni-muenchen.de)
+
+ * client.c (server_user): new var.
+ (parse_cvsroot): set above if repo is "user@host:/dir".
+ (start_rsh_server): if server_user set, then use it.
+
+Wed Jul 12 10:53:36 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * sanity.sh: remove the TESTDIR after done.
+
+ * cvsbug.sh (GNATS_ADDR): now bug-cvs@prep.ai.mit.edu again.
+
+Tue Jul 11 15:53:08 1995 Greg A. Woods <woods@most.weird.com>
+
+ * options.h.in: depend on configure for grep and diff, now that
+ changes to configure.in are applied.
+
+Tue Jul 11 14:32:14 1995 Michael Shields <shields@tembel.org>
+
+ * Makefile.in (LDFLAGS): Pick up from configure.
+
+Tue Jul 11 14:20:00 1995 Loren James Rittle <rittle@supra.comm.mot.com>
+
+ * import.c (add_rev), commit.c (remove_file, ci_new_rev),
+ checkin.c (Checkin), subr.c (make_message_rcslegal), cvs.h:
+ Always perform sanity check and fix-up on messages to be passed
+ directly to RCS via the '-m' switch. RCS 5.7 requires that a
+ non-total-whitespace, non-null message be provided or it will
+ abort with an error. CVS is not setup to handle any returned
+ error from 'ci' gracefully and, thus, the repository entered a
+ trashed state.
+
+ * sanity.sh: Add regression tests for new code and interactions
+ with RCS 5.7.
+
+Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com>
+
+ * .cvsignore: added new backup file
+
+ * options.h.in: our new configure.in finds the right diff and
+ grep paths now....
+
+ * subr.c: quote the string in run_print() for visibility
+ - indent a comment
+ - Jun Hamano's xchmod() patch to prevent writable files
+ (from previous local changes)
+
+ * logmsg.c: fix a NULL pointer de-reference
+ - clean up some string handling code...
+ (from previous local changes)
+
+ * parseinfo.c: add hack to expand $CVSROOT in an *info file.
+ - document "ALL" and "DEFAULT" in opening comment for Parse_Info()
+ - fix the code to match the comments w.r.t. callbacks for "ALL"
+ - add a line of trace output...
+ (from previous local changes)
+
+ * mkmodules.c: add support for comments in CVSROOT/checkoutlist
+ - add CVSroot used by something other .o, ala main.c
+ (from previous local changes)
+
+ * main.c, cvs.h: add support for $VISUAL as log msg editor
+ (from previous local changes)
+
+ * status.c: add support for -q and -Q (from previous local changes)
+
+
+Sun Jul 9 18:44:32 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * log.c: trivial change to test ChangeLog stuff.
+
+Sat Jul 8 20:33:57 1995 Paul Eggert <eggert@twinsun.com>
+
+ * history.c: (history_write): Don't assume that fopen(..., "a")
+ lets one interleave writes to the history file from different processes
+ without interlocking. Use open's O_APPEND option instead.
+ Throw in an lseek to lessen the race bugs on non-Posix hosts.
+ * cvs.h, subr.c (Fopen): Remove.
+
+ * log.c (log_fileproc): Pass working file name to rlog, so that
+ the name is reported correctly.
+
+Fri Jul 7 18:29:37 1995 Michael Hohmuth <hohmuth@inf.tu-dresden.de>
+
+ * client.c, client.h (client_import_setup): New function.
+ (client_import_done, client_process_import_file): Add comments
+ regarding now-redundant code.
+ * import.c (import): Call client_import_setup.
+
+Tue Jul 4 09:21:26 1995 Bernd Leibing <bernd.leibing@rz.uni-ulm.de>
+
+ * rcs.c (RCS_parsercsfile_i): Rename error to l_error; SunOS4 /bin/cc
+ doesn't like a label and function with the same name.
+
+Sun Jul 2 12:51:33 1995 Fred Appelman <Fred.Appelman@cv.ruu.nl>
+
+ * logmsg.c: Rename strlist to str_list to avoid conflict with
+ Unixware 2.01.
+
+Thu Jun 29 17:37:22 1995 Paul Eggert <eggert@twinsun.com>
+
+ * rcs.c (RCS_check_kflag): Allow RCS 5.7's new -kb option.
+
+Wed Jun 28 09:53:14 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (HEADERS): Remove options.h.in.
+ (DISTFILES): Add options.h.in.
+ Depend on options.h in addition to HEADERS.
+
+Tue Jun 27 22:37:28 1995 Vince Demarco <vdemarco@bou.shl.com>
+
+ * subr.c: Don't try to do fancy waitstatus stuff for NeXT,
+ lib/wait.h is sufficient.
+
+Mon Jun 26 15:17:45 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove RCS-patches and convert.sh.
+
+Fri Jun 23 13:38:28 1995 J.T. Conklin (jtc@rtl.cygnus.com)
+
+ * server.c (dirswitch, serve_co): Use CVSADM macro instead of
+ literal "CVS".
+
+Fri Jun 23 00:00:51 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * README-rm-add: Do not talk about patching RCS, that only
+ confuses people.
+ * RCS-patches, convert.sh: Removed (likewise).
+
+Thu Jun 22 10:41:41 1995 James Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c: Change -1 to (size_t)-1 when comparing against a size_t.
+
+Wed Jun 21 16:51:54 1995 nk@ipgate.col.sw-ley.de (Norbert Kiesel)
+
+ * create_adm.c, entries.c, modules.c: Avoid coredumps if
+ timestamps, tags, etc., are NULL.
+
+Tue Jun 20 15:52:53 1995 Jim Meyering (meyering@comco.com)
+
+ * checkout.c (checkout): Remove dcl of unused variable.
+ * client.c (call_in_directory, handle_clear_static_directory,
+ handle_set_sticky, handle_clear_sticky, send_a_repository,
+ send_modified, send_dirent_proc): Remove dcls of unused variables.
+ * server.c (receive_file, serve_modified, server_cleanup):
+ Remove dcls of unused variables.
+ * subr.c (copy_file): Remove dcl of unused variable.
+ * vers_ts.c (time_stamp_server): Remove dcl of unused variable.
+
+Mon Jun 19 13:49:35 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * sanity.sh: Fix commencement message --- the test suite says
+ "Ok." when it's done.
+
+Fri Jun 16 11:23:44 1995 Jim Meyering (meyering@comco.com)
+
+ * entries.c (fgetentent): Parenthesize assignment in if-conditional.
+
+Thu Jun 15 17:33:28 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * server.c (get_buffer_data, buf_append_char, buf_append_data):
+ Don't conditionalize use of "inline". Autoconf takes care of
+ defining it away on systems that don't grok it.
+
+Thu Jun 15 13:43:38 1995 Jim Kingdon (kingdon@cyclic.com)
+
+ * options.h.in (DIFF): Default to "diff" not "diff -a" since diff
+ might not support the -a option.
+
+Wed Jun 14 11:29:42 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * import.c (import_descend): Initialize dirlist to NULL.
+
+ * subr.c (copy_file): Fix infinite loop.
+
+ * server.c (serve_directory): fix a memory leak.
+
+ * checkout.c, commit.c, diff.c, history.c, import.c, log.c,
+ patch.c, release.c, remove.c, rtag.c, status.c, tag.c, update.c:
+ Use send_arg() to send command line arguments to server.
+
+ * commit.c (fsortcmp), find_names (fsortcmp), hash.c (hashp,
+ findnode), hash.h (findnode), rcs.c (RCS_addnode,
+ RCS_check_kflag, RCS_check_tag, RCS_isdead, RCS_parse,
+ RCS_parsercsfile_i), rcs.h (RCS_addnode, RCS_check_kflag,
+ RCS_check_tag, RCS_parse): Added const qualifiers as
+ appropriate.
+ * rcs.h (RCS_isdead): Added prototype.
+
+ * hash.h (walklist, sortlist): correct function prototypes.
+
+ * ignore.c (ign_setup): don't bother checking to see if file
+ exists before calling ign_add_file.
+
+Fri Jun 9 11:24:06 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * all source files (rcsid): Added const qualifer.
+ * ignore.c (ign_default): Added const qualifier.
+ * subr.c (numdots): Added const qualifier to function argument.
+ * cvs.h (numdots): Added const qualifier to prototype argument.
+
+ * client.c (change_mode): Tied consecutive if statements testing
+ the same variable together with else if.
+
+ * import.c (import_descend): Build list of subdirectories when
+ reading directory, and then process the subdirectories in that
+ list. This change avoids I/O overhead of rereading directory
+ and reloading ignore list (.cvsignore) for each subdirectory.
+
+Thu Jun 8 11:54:24 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * import.c (import_descend): Use 4.4BSD d_type field if it is
+ present.
+
+ * lock.c (set_lockers_name): Use %lu in format and cast st_uid
+ field to unsigned long.
+
+ * import.c (import): Use RCS_check_kflag() to check -k options.
+ (keyword_usage, str2expmode, strn2expmode, expand_names):
+ Removed.
+ * rcs.c (RCS_check_kflag): Added keyword_usage array from import.c
+ for more descriptive error messages.
+
+ * subr.c (run_setup, run_args): Changed variable argument
+ processing to work on machines that use <varargs.h>.
+
+ * subr.c (copy_file, xcmp): Changed to read the file(s) by blocks
+ rather than by reading the whole file into a huge buffer. The
+ claim that this was reasonable because source files tend to be
+ small does not hold up in real world situations. CVS is used
+ to manage non-source files, and mallocs of 400K+ buffers (x2
+ for xcmp) can easily fail due to lack of available memory or
+ even memory pool fragmentation.
+ (block_read): New function, taken from GNU cmp and slightly
+ modified.
+
+ * subr.c (xcmp): Added const qualifier to function arguments.
+ * cvs.h (xcmp): Added const qualifer to prototype arguments.
+
+Wed Jun 7 11:28:31 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * cvs.h (Popen): Added prototype.
+ (Fopen, open_file, isreadable, iswritable, isdir, isfile,
+ islink, make_directory, make_directories, rename_file,
+ link_file, unlink_file, copy_file): Added const qualifer to
+ prototype arguments.
+ * subr.c (Fopen, Popen, open_file, isreadable, iswritable, isdir,
+ isfile, islink, make_directory, make_directories, rename_file,
+ link_file, unlink_file, copy_file): Added const qualifier to
+ function arguments.
+
+ * logmsg.c (logfile_write), recurse.c (do_recursion, addfile):
+ Don't cast void functions to a void expression. There is at
+ least one compiler (MPW) that balks at this.
+
+ * rcs.c (keysize, valsize): Change type to size_t.
+
+ * add.c (add_directory): Don't cast umask() argument to int.
+
+ * import.c (add_rcs_file): Changed type of mode to mode_t.
+
+ * rcscmds.c (RCS_merge): New function.
+ * cvs.h (RCS_merge): Declare.
+ * update.c (merge_file, join_file): Call RCS_merge instead of
+ invoking rcsmerge directly.
+
+ * cvs.h: Include <stdlib.h> if HAVE_STDC_HEADERS, otherwise
+ declared getenv().
+ * cvsrc.c, ignore.c, main.c: Removed getenv() declaration.
+
+ * client.c (mode_to_string): Changed to take mode_t instead of
+ struct statb argument. Simplified implementation, no longer
+ overallocates storage for returned mode string.
+ * client.h (mode_to_string): Updated declaration.
+ * server.c (server_updated): Updated for new calling conventions,
+ pass st_mode instead of pointer to struct statb.
+
+ * cvs.h (CONST): Removed definition, use of const qualifier is
+ determined by autoconf.
+ * history.c, modules.c, parseinfo.c: Use const instead of CONST.
+
+ * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c,
+ main.c, mkmodules.c, patch.c, recurse.c, remove.c, rtag.c,
+ server.c, status.c, subr.c, tag.c, update.c: Changed function
+ arguments "char *argv[]" to "char **argv" to silence lint
+ warnings about performing arithmetic on arrays.
+
+Tue Jun 6 18:57:21 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * version.c: Fix up version string, to say that this is Cyclic
+ CVS.
+
+Tue Jun 6 15:26:16 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * subr.c (run_setup, run_args, run_add_arg, xstrdup): Add const
+ qualifier to format argument.
+ * cvs.h (run_setup, run_args, xstrdup): Likewise.
+
+ * Makefile.in (SOURCES): Added rcscmds.c.
+ (OBJECTS): Added rcscmds.o.
+
+ * rcscmds.c: New file, with new functions RCS_settag, RCS_deltag,
+ RCS_setbranch, RCS_lock, RCS_unlock.
+ * checkin.c, commit.c, import.c, rtag.c, tag.c: Call above
+ functions instead of exec'ing rcs commands.
+ * cvs.h: Declare new functions.
+
+Mon May 29 21:40:54 1995 J.T. Conklin (jtc@rtl.cygnus.com)
+
+ * recurse.c (start_recursion, do_recursion): Set entries to NULL
+ after calling Entries_Close().
+
+Sat May 27 08:08:18 1995 Jim Meyering (meyering@comco.com)
+
+ * Makefile.in (check): Export RCSBIN only if there exists an
+ `rcs' executable in ../../rcs/src. Before, tests would fail when
+ the directory existed but contained no executables.
+ (distclean): Remove options.h, now that it's generated.
+ (Makefile): Regenerate only *this* file when Makefile.in is
+ out of date. Depend on ../config.status.
+
+Fri May 26 14:34:28 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * entries.c (Entries_Open): Added missing fclose().
+ (Entries_Close): Don't write Entries unless Entries.Log exists.
+
+ * entries.c (Entries_Open): Renamed from ParseEntries; changed to
+ process Entries Log files left over from previous crashes or
+ aborted runs.
+ (Entries_Close): New function, write out Entries file if
+ neccessary and erase Log file.
+ (Register): Append changed records to Log file instead of
+ re-writing file.
+ (fgetentent): New function, parse one Entry record from a file.
+ (AddEntryNode): It's no longer an error for two records with the
+ same name to be added to the list. New records replace older
+ ones.
+ * cvs.h (Entries_Open, Entries_Close): Add prototypes.
+ (CVSADM_ENTLOG): New constant, name of Entries Log file.
+ * add.c, checkout.c, client.c, find_names.c, recurse.c: Use
+ Entries_Open()/Entries_Close() instead of ParseEntries()/dellist().
+
+ * add.c, admin.c, checkout.c, client.c, commit.c, diff.c,
+ history.c, import.c, log.c, patch.c, release.c, remove.c,
+ rtag.c, server.c, status.c, tag.c, update.c: Changed
+ conditionals so that return value of *printf is tested less than
+ 0 instead of equal to EOF.
+
+Thu May 25 08:30:12 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * subr.c (xmalloc): Never try to malloc zero bytes; if the user
+ asks for zero bytes, malloc one instead.
+
+Wed May 24 12:44:25 1995 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * subr.c (xmalloc): Don't complain about NULL if zero bytes were
+ requested.
+
+Tue May 16 21:49:05 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * subr.c (xmalloc): Never try to malloc zero bytes; if the user
+ asks for zero bytes, malloc one instead.
+
+Mon May 15 14:35:11 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * lock.c (L_LOCK_OWNED): Removed.
+
+ * add.c, checkout.c, client.c, create_adm.c, cvs.h, entries.c,
+ find_names.c modules.c, recurse.c, release.c, repos.c, update.c:
+ removed CVS 1.2 compatibility/upgrade code.
+
+Mon May 8 11:25:07 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * lock.c (write_lock): Missed one instance where rmdir(tmp) should
+ have been changed to clear_lock().
+
+Wed May 3 11:08:32 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * create_adm.c, entries.c, import.c, root.c: Changed conditionals
+ so that return value of *printf is tested less than 0 instead of
+ equal to EOF --- That's all Standard C requires.
+
+Wed May 3 18:03:37 1995 Samuel Tardieu <tardieu@emma.enst.fr>
+
+ * rcs.h: removed #ifdef CVS_PRIVATE and #endif because cvs didn't
+ compile anymore.
+
+Mon May 1 13:58:53 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * rcs.c, rcs.h: Implemented lazy parsing of rcs files.
+ RCS_parsercsfile_i modified to read only the first two records
+ of rcs files, a new function RCS_reparsercsfile is called only
+ when additional information (tags, revision numbers, dates,
+ etc.) is required.
+
+Mon May 1 12:20:02 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Makefile.in (INCLUDES): Include -I. for options.h.
+
+Fri Apr 28 16:16:33 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (SOURCES, HEADERS, DISTFILES): Updated.
+ (dist-dir): Renamed from dist; changed to work with DISTDIR
+ variable passed from parent.
+
+ We don't want to include a file the user has to edit in the
+ distribution.
+ * options.h: No longer distributed.
+ * options.h.in: Distribute this instead.
+ * ../INSTALL, ../README: Installation instructions updated.
+
+ * client.c (start_rsh_server): Send the remote command to rsh as a
+ single string.
+
+Fri Apr 28 00:29:49 1995 Noel Cragg <noel@vo.com>
+
+ * commit.c: Added initializer for FORCE_CI
+
+ * sanity.sh: Fix tests added 25 Apr -- they were expecting the
+ server to make noise, but the CVS_SERVER variable had been
+ accidentally set with the `-Q' flag. Ran all tests -- both
+ locally and remotely -- to verify that the change didn't break
+ anything.
+
+Thu Apr 27 12:41:52 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * Makefile.in: Revise comment regarding check vs. remotecheck.
+
+Thu Apr 27 12:52:28 1995 Bryan O'Sullivan <bos@cyclic.com>
+
+ * client.c (start_rsh_server): If the CVS_RSH environment variable
+ is set, use its contents as the name of the program to invoke
+ instead of `rsh'.
+
+Thu Apr 27 12:18:38 1995 Noel Cragg <noel@vo.com>
+
+ * checkout.c (checkout): To fix new bug created by Apr 23 change,
+ re-enabled "expand-module" functionality, because it has the side
+ effect of setting the checkin/update programs for a directory. To
+ solve the local/remote checkout problem that prompted this change
+ in the first place, I performed the next change.
+ * server.c (expand_proc): Now returns expansions for aliases only.
+
+Wed Apr 26 12:07:42 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * rcs.c (getrcskey): Rewritten to process runs of whitespace chars
+ and rcs @ strings instead of using state variables "white" and
+ "funky".
+
+Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * lock.c (unlock): Only call stat if we need to.
+
+Wed Apr 26 10:48:44 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (new_entries_line): Don't prototype.
+
+Tue Apr 25 22:19:16 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * sanity.sh: Add new tests to catch bugs in Apr 23 change.
+
+Tue Apr 25 17:10:55 1995 Roland McGrath <roland@baalperazim.frob.com>
+
+ * create_adm.c (Create_Admin): Use getwd instead of getcwd.
+
+Sun Apr 23 20:58:32 1995 Noel Cragg <noel@vo.com>
+
+ * checkout.c (checkout): Disabled "expand-module" functionality on
+ remote checkout, since it makes modules behave like aliases (see
+ longer note there). This change necessitated the change below.
+ Also merged the like parts of a conditional.
+
+ * client.c (call_in_directory): Changed the algorithm that created
+ nested and directories and the "CVS" administration directories
+ therein. The algoithm wrongly assumed that the name of the
+ directory that that was to be created and the repository name were
+ the same, which breaks modules.
+
+ * create_adm.c (Create_Admin), module.c (do_module), server.c
+ (server_register), subr.c, entries.c: Added fprintfs for trace-mode
+ debugging.
+
+ * client.c (client_send_expansions): Argument to function didn't
+ have a type -- added one.
+
+ * server.c (new_entries_line): Arguments to this function are
+ never used -- reoved them and fixed callers.
+
+Sat Apr 22 11:17:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * rcs.c (RCS_parse): If we can't open the file, give an error
+ message (except for ENOENT in case callers rely on that).
+
+Wed Apr 19 08:52:37 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_repository): Check for CVSADM_ENTSTAT in `dir', not
+ in `.'.
+
+ * sanity.sh: Add TODO list. Revise some comments. Add tests of
+ one working directory adding a file and other updating it.
+
+Sat Apr 8 14:52:55 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * Makefile.in (CFLAGS): Let configure set the default for CFLAGS.
+ Under GCC, we want -g -O.
+
+Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * root.c (Name_Root): merge identical adjacent conditionals.
+
+ * create_admin.c (Create_Admin): Rearranged check for CVSADM and
+ OCVSADM directories so that CVSADM pathname is only built once.
+
+ * update.c (update_dirleave_proc): Removed code to remove CVS
+ administration directory if command_name == "export" and to
+ create CVS/Root file if it is not present. Identical code
+ in update_filesdone_proc() will perform these same actions.
+ Also removed code that read and verfied CVS/Root. This is
+ expensive, and if it is necessary should happen in the
+ general recursion processor rather than in the update
+ callbacks.
+
+ * lock.c (masterlock): New variable, pathname of master lockdir.
+ (set_lock): removed lockdir argument, now constructs it itself
+ and stores it in masterlock.
+ (clear_lock): new function, removes master lockdir.
+ (Reader_Lock, write_lock): call clear_lock instead of removing
+ master lockdir.
+ (Reader_Lock, write_lock): #ifdef'd out CVSTFL code.
+
+ * main.c (main): register Lock_Cleanup signal handler.
+ * lock.c (Reader_Lock, write_lock): no longer register
+ Lock_Cleanup.
+
+ * main.c (main): initialize new array hostname.
+ * lock.c (Reader_Lock, write_lock): Use global hostname array.
+ * logmsg.c (logfile_write): Likewise.
+
+ * recurse.c (do_dir_proc, unroll_files_proc): Use open()/fchdir()
+ instead of getwd()/chdir() on systems that support the fchdir()
+ system call.
+
+Fri Apr 7 06:57:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c: Include the word "server" in error message for memory
+ exhausted, so the user knows which machine ran out of memory.
+
+ * sanity.sh: For remote, set CVS_SERVER to test the right server,
+ rather than a random one from the PATH.
+
+ * commit.c [DEATH_STATE]: Pass -f to `ci'.
+
+Thu Apr 6 13:05:15 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * commit.c (checkaddfile): If we didn't manage to fopen the file,
+ don't try to fclose it.
+
+ * client.c (handle_m, handle_e): Use fwrite, rather than a loop of
+ putc's. Sometimes these streams are unbuffered.
+
+Tue Apr 4 11:33:56 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * (DISTFILES): Include cvsbug.sh, ChangeLog, NOTES, RCS-patches,
+ README-rm-add, ChangeLog.fsf, sanity.sh, sanity.el, and
+ .cvsignore.
+
+Mon Mar 27 08:58:42 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * rcs.c (RCS_parsercsfile_i): Accept `dead' state regardless of
+ DEATH_STATE define. Revise comments regarding DEATH_STATE versus
+ CVSDEA versus the scheme which uses a patched RCS.
+ * README-rm-add, RCS-patches: Explain what versions of CVS need
+ RCS patches.
+
+Sat Mar 25 18:51:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * server.c (server_cleanup): Only do the abysmal kludge of waiting
+ for command and draining the pipe #ifdef sun. The code makes
+ assumptions not valid on all systems, and is only there to
+ workaround a SunOS bug.
+
+Wed Mar 22 21:55:56 1995 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (mkdir_p): Call stat only if we get the EACCES. Faster
+ and more elegant.
+
+Tue Jan 31 20:59:19 1995 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * server.c: Try to avoid starting the "rm -rf" at cleanup time
+ until after subprocesses have finished.
+ (command_fds_to_drain, max_command_fd): New variables.
+ (do_cvs_command): Set them.
+ (command_pid_is_dead): New variable.
+ (wait_sig): New function.
+ (server_cleanup): If command_pid is nonzero, wait for it to die,
+ draining output from it in the meantime. If nonzero SIG was
+ passed, send a signal to the subprocess, to encourage it to die
+ soon.
+
+ * main.c (usage): Argument is now `const char *const *'.
+ * cvs.h (usage): Changed prototype.
+ (USE): Make new variable `const'.
+ * add.c (add_usage), admin.c (admin_usage), checkout.c
+ (checkout_usage, export_usage, checkout), commit.c (commit_usage),
+ diff.c (diff_usage), history.c (history_usg), import.c
+ (import_usage, keyword_usage), log.c (log_usage), main.c (usg),
+ patch.c (patch_usage), release.c (release_usage), remove.c
+ (remove_usage), rtag.c (rtag_usage), server.c (server), status.c
+ (status_usage), tag.c (tag_usage), update.c (update_usage): Usage
+ messages are now const arrays of pointers to const char.
+
+ * import.c (comtable): Now const.
+ * main.c (rcsid): Now static.
+ (cmd): Now const.
+ (main): Local variable CM now points to const.
+ * server.c (outbuf_memory_error): Local var MSG now const.
+
+ * client.c (client_commit_usage): Deleted.
+
+Sat Dec 31 15:51:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * logmsg.c (do_editor): Allocate enough space for trailing '\0'.
+
+Fri Mar 3 11:59:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * cvsbug.sh: Call it "Cyclic CVS" now, not "Remote CVS". Call it
+ version C1.4A, not 1.4A2-remote. Send bugs to cyclic-cvs, not
+ remote-cvs.
+
+ * classify.c (Classify_File): Put check for dead file inside
+ "#ifdef DEATH_SUPPORT".
+
+Thu Feb 23 23:03:43 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * update.c (join_file): Don't pass the -E option to rcsmerge here,
+ either (see Jan 22 change).
+
+Mon Feb 13 13:28:46 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * cvsbug.sh: Send bug reports to remote-cvs@cyclic.com, rather
+ than to the ordinary CVS bug address. This does mean we'll have
+ to wade through GNATS-style bug reports, sigh.
+
+Wed Feb 8 06:42:27 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * server.c: Don't include <sys/stat.h>; system.h already does, and
+ 4.3BSD can't take it twice.
+
+ * subr.c [! HAVE_VPRINTF] (run_setup, run_args): Don't use va_dcl
+ in declaration. Declare the a1..a8 args which are used in the
+ sprintf call.
+ * cvs.h [! HAVE_VPRINTF] (run_setup, run_args): Don't prototype
+ args, to avoid conflicting with the function definitions
+ themselves.
+
+Tue Feb 7 20:10:00 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * client.c (update_entries): Pass the patch subprocess the switch
+ "-b ~", not "-b~"; the latter form seems not to work with patch
+ version 2.0 and earlier --- it takes the next argv element as the
+ backup suffix, and thus doesn't notice that the patch file's name
+ has been specified, thus doesn't find the patch, thus... *aargh*
+
+Fri Feb 3 20:28:21 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * log.c (log_option_with_arg): New function.
+ (cvslog): Use it and send_arg to handle the rlog options that take
+ arguments. The code used to use send_option_string for
+ everything, which assumes that "-d1995/01/02" is equivalent to
+ "-d -1 -9 -9 -5 ...".
+
+Tue Jan 31 15:02:01 1995 Jim Blandy <jimb@floss.life.uiuc.edu>
+
+ * server.c: #include <sys/stat.h> for the new stat call in mkdir_p.
+ (mkdir_p): Don't try to create the intermediate directory if it
+ exists already. Some systems return EEXIST, but others return
+ EACCES, which we can't otherwise distinguish from a real access
+ problem.
+
+Sun Jan 22 15:25:45 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
+
+ * update.c (merge_file): My rcsmerge doesn't accept a -E option,
+ and it doesn't look too important, so don't pass it.
+
+Fri Jan 20 14:24:58 1995 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * client.c (do_deferred_progs): Don't try to chdir to toplevel_wd
+ if it has not been set.
+ (process_prune_candidates): Likewise.
+
+Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (client_commit): Move guts of function from here...
+ * commit.c (commit): ...to here.
+
+Mon Nov 28 15:14:36 1994 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * server.c (buf_input_data, buf_send_output): Start cpp directives
+ in column 1, otherwise Sun 4 pcc complains.
+
+Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (add_prune_candidate): Don't try to prune ".".
+
+Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c, client.c: More formatting cleanups.
+
+ * client.h, client.c: New variable client_prune_dirs.
+ * update.c (update), checkout.c (checkout): Set it.
+ * client.c (add_prune_candidate, process_prune_candidates): New
+ functions.
+ (send_repository, call_in_directory, get_responses_and_close):
+ Call them.
+
+Wed Nov 23 01:17:32 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * server.c (do_cvs_command): Don't select on STDOUT_FILENO unless
+ we have something to write.
+
+Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * remove.c (remove_fileproc): Only call server_checked_in if we
+ actually are changing the entries file.
+
+ * server.c (server_write_entries): New function.
+ (dirswitch, do_cvs_command): Call it.
+ (serve_entry, serve_updated): Just update in-memory data
+ structures, don't mess with CVS/Entries file.
+
+Mon Nov 21 10:15:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (server_checked_in): Set scratched_file to NULL after
+ using it.
+
+ * checkin.c (Checkin): If the file was changed by the checkin,
+ call server_updated not server_checked_in.
+
+Sun Nov 20 08:01:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_repository): Move check for update_dir NULL to
+ before where we check last_update_dir. Check for "" here too.
+
+ * client.c (send_repository): Use new argument dir.
+
+ * client.c: Pass new argument dir to send_repository and
+ send_a_repository.
+
+ * server.c, server.h (server_prog): New function.
+ * modules.c (do_modules): Call it if server_expanding.
+ * client.c: Support Set-checkin-prog and Set-update-prog responses.
+ * server.c, client.c: Add Checkin-prog and Update-prog requests.
+
+Fri Nov 18 14:04:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (get_short_pathname, is_cvsroot_level,
+ call_in_directory): Base whether this is new-style or
+ old-style based on whether we actually used the Directory request,
+ not based on whether the pathname is absolute. Rename
+ directory_supported to use_directory.
+ * server.c: Rename use_relative_pathnames to use_dir_and_repos.
+ * client.c (send_a_repository): If update_dir is absolute, don't
+ use it to try to reconstruct how far we have recursed.
+
+ * server.c, server.h, client.c, client.h, vers_ts.c, update.h:
+ More cosmetic changes (identation, PARAMS vs. PROTO, eliminate
+ alloca, etc.) to remote CVS to make it more like the rest of CVS.
+
+ * server.c: Make server_temp_dir just the dir name, not the name
+ with "%s" at the end.
+ * server.c, client.c: Add "Max-dotdot" request, and use it to make
+ extra directories in server_temp_dir if needed.
+
+Thu Nov 17 09:03:28 1994 Jim Kingdon <kingdon@cygnus.com>
+
+ * client.c: Fix two cases where NULL was used and 0 was meant.
+
+Mon Nov 14 08:48:41 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (serve_unchanged): Set noexec to 0 when calling Register.
+
+ * update.c (merge_file): Don't call xcmp if noexec.
+
+Fri Nov 11 13:58:22 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (call_in_directory): Deal with it if reposdirname is
+ not a subdirectory of toplevel_repos.
+
+Mon Nov 7 09:12:01 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * patch.c: If file is removed and we don't have a tag or date,
+ just print "current release".
+
+ * classify.c (Classify_File): Treat dead files appropriately.
+
+Fri Nov 4 07:33:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * main.c (main) [SERVER_SUPPORT]: Move call to getwd past where we
+ know whether we are the server or not. Set CurDir to "<remote>"
+ if we are the server.
+
+ * client.c: Remove #if 0'd function option_with_arg.
+ Remove #if 0'd code pertaining to the old way of logging the
+ session.
+
+ * client.c (start_rsh_server): Don't invoke the server with the
+ -d option.
+ * server.c (serve_root): Test root for validity, just like main.c
+ does for non-remote CVS.
+ * main.c (main): If `cvs server' happens with a colon in the
+ CVSroot, just handle it normally; don't make it an error.
+
+Wed Nov 2 11:09:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_dirent_proc): If dir does not exist, just return
+ R_SKIP_ALL.
+
+ * server.c, client.c: Add Directory request and support for
+ local relative pathnames (along with the repository absolute
+ pathnames).
+ * update.c, add.c, checkout.c, checkin.c, cvs.h, create_adm.c,
+ commit.c, modules.c, server.c, server.h, remove.c, client.h:
+ Pass update_dir to server_* functions. Include update_dir in
+ more error messages.
+
+Fri Oct 28 08:54:00 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c: Reformat to bring closer to cvs standards for brace
+ position, comment formatting, etc.
+
+ * sanity.sh: Remove wrong "last mod" line. Convert more tests to
+ put PASS or FAIL in log file. Change it so arguments to the
+ script specify which tests to run.
+
+ * client.c, client.h, server.c, checkout.c: Expand modules in
+ separate step from the checkout itself.
+
+Sat Oct 22 20:33:35 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * update.c (join_file): When checking for null return from
+ RCS_getversion, still do return even if quiet flag is set.
+
+Thu Oct 13 07:36:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_files): Call send_repository even if
+ toplevel_repos was NULL.
+
+ * server.c (server_updated): If joining, don't remove file.
+
+ * update.c (join_file): If server and file is unmodified, check it
+ out before joining. After joining, call server_updated. New
+ argument repository.
+
+ * server.c, server.h (server_copy_file): New function.
+ * update.c (update_file_proc, join_file): Call it.
+ * client.c (copy_file, handle_copy_file): New functions.
+ * client.c (responses): Add "Copy-file".
+
+ * client.c, client.h: Make toplevel_wd, failed_patches and
+ failed_patches_count extern.
+ * client.c (client_update): Move guts of function from here...
+ * update.c (update): ...to here.
+
+ * client.c, checkout.c: Likewise for checkout.
+
+ * client.c (is_cvsroot_level): New function.
+ (handle_set_sticky, handle_clear_sticky,
+ handle_clear_static_directory): Call it, instead of checking
+ short_pathname for a slash.
+
+ * client.c, client.h (client_process_import_file,
+ client_import_done): New functions.
+ * import.c (import, import_descend): Use them.
+ * import.c (import_descend): If server, don't mention ignored CVS
+ directories.
+ * import.c (import_descend_dir): If client, don't print warm
+ fuzzies, or make directories in repository. If server, print warm
+ fuzzies to stdout not stderr.
+ * client.c (send_modified): New function, broken out from
+ send_fileproc.
+ (send_fileproc): Call it.
+
+ * client.c (handle_clear_sticky, handle_set_sticky,
+ handle_clear_static_directory, handle_set_static_directory): If
+ command is export, just return.
+ (call_in_directory, update_entries): If command is export, don't
+ create CVS directories, CVS/Entries files, etc.
+ * update.c (update_filesdone_proc): Don't remove CVS directories if
+ client_active.
+
+ * client.c (send_a_repository): Instead of insisting that
+ repository end with update_dir, just strip as many pathname
+ components from the end as there are in update_dir.
+
+ * Makefile.in (remotecheck): New target, pass -r to sanity.sh.
+ * sanity.sh: Accept -r argument which means to test remote cvs.
+
+ * tag.c (tag), rtag.c (rtag), patch.c (patch), import.c (import),
+ admin.c (admin), release.c (release): If client_active, connect to
+ the server and send the right requests.
+ * main.c (cmds): Add these commands.
+ (main): Remove code which would strip hostname off cvsroot and try
+ the command locally. There are no longer any commands which are
+ not supported.
+ * client.c, client.h (client_rdiff, client_tag, client_rtag,
+ client_import, client_admin, client_export, client_history,
+ client_release): New functions.
+ * server.c (serve_rdiff, serve_tag, serve_rtag, serve_import,
+ serve_admin, serve_export, serve_history, serve_release): New
+ functions.
+ (requests): List them.
+ * server.c: Declare cvs commands (add, admin, etc.).
+ * cvs.h, server.h: Don't declare any of them here.
+ * main.c: Restore declarations of cvs commands which were
+ previously removed.
+
+ * cvs.h: New define DEATH_STATE, commented out for now.
+ * rcs.c (RCS_parsercsfile_i), commit.c (remove_file, checkaddfile)
+ [DEATH_STATE]: Use RCS state to record a dead file.
+
+Mon Oct 3 09:44:54 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * status.c (status_fileproc): Now that ts_rcs is just one time,
+ don't try to print the second time from it. (Same as raeburn 20
+ Aug change, it accidentally got lost in 1.4 Alpha-1 merge).
+
+ * cvs.h (CVSDEA): Added (but commented out for now).
+ * rcs.c (RCS_parsercsfile_i) [CVSDEA]: Also look in CVSDEA to see if
+ something is dead.
+ * commit.c (ci_new_rev, mark_file) [CVSDEA]: New functions.
+ (remove_file, checkaddfile) [CVSDEA]: Use them instead of ci -K.
+ * find_names.c (find_dirs) [CVSDEA]: Don't match CVSDEA directories.
+ * update.c (checkout_file): Check RCS_isdead rather than relying
+ on co to not create the file.
+
+ * sanity.sh: Direct output to logfile, not /dev/null.
+
+ * subr.c (run_exec): Print error message if we are unable to exec.
+
+ * commit.c (remove_file): Call Scratch_Entry when removing tag
+ from file. The DEATH_SUPPORT ifdef was erroneous.
+
+Sun Oct 2 20:33:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * commit.c (checkaddfile): Instead of calling isdir before
+ attempting to create the directory, just ignore EEXIST errors from
+ mkdir. (This removes some DEATH_SUPPORT ifdefs which actually had
+ nothing to do with death support).
+
+Thu Sep 29 09:23:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * diff.c (diff): Search attic too if we have a second tag/date.
+ (diff_fileproc): If we have a second tag/date, don't do all the
+ checking regarding the user file.
+
+Mon Sep 26 12:02:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * checkin.c (Checkin): Check for error from unlink_file.
+
+Mon Sep 26 08:51:10 1994 Anthony J. Lill (ajlill@ajlc.waterloo.on.ca)
+
+ * rcs.c (getrcskey): Allocate space for terminating '\0' if
+ necessary.
+
+Sat Sep 24 09:07:37 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * commit.c (commit_fileproc): Set got_message = 1 when calling
+ do_editor (accidentally omitted from last change).
+
+Fri Sep 23 11:59:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Revert buggy parts of Rich's change of 1 Nov 1993 (keeping the
+ dynamic buffer allocation, which was the point of that change).
+ * logmsg.c (do_editor): Reinstate message arg, but make it char
+ **messagep instead of char *message. Change occurances of message
+ to *messagep. Char return type from char * back to void.
+ * cvs.h: Change do_editor declaration.
+ * commit.c: Reinstate got_message variable
+ (commit_filesdoneproc, commit_fileproc, commit_direntproc): Use it.
+ * import.c (import), commit.c (commit_fileproc,
+ commit_direntproc): Pass &message to do_editor; don't expect it to
+ return a value.
+ * client.c (client_commit): Likewise.
+ * import.c (import): Deal with it if message is NULL.
+
+Wed Sep 21 09:43:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (server_updated): If the file doesn't exist, skip it.
+
+ * diff.c, client.h, client.c: Rename diff_client_senddate to
+ client_senddate and move from diff.c to client.c.
+ * client.c (client_update, client_checkout): Use it.
+
+Sat Sep 17 08:36:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * checkout.c (checkout_proc): Don't pass NULL to Register for
+ version. (should fix "cvs co -r <nonexistent-tag> <file>"
+ coredump on Solaris).
+
+Fri Sep 16 08:38:02 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * diff.c (diff_fileproc): Set top_rev from vn_user, not vn_rcs.
+ Rename it to user_file_rev because it need not be the head of any
+ branch.
+ (diff_file_nodiff): After checking user_file_rev, if we have both
+ use_rev1 and use_rev2, compare them instead of going on to code
+ which assumes use_rev2 == NULL.
+
+Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * status.c (status): Return a value in client_active case.
+
+Thu Sep 15 15:02:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * server.c (serve_modified): Create the file even if the size is
+ zero.
+
+Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * lock.c (readers_exist): Clear errno each time around the loop,
+ not just the first time.
+
+ * client.c (start_server): Don't send Global_option -q twice.
+
+ * no_diff.c (No_Difference): Check for error from unlink.
+
+ * no_diff.c, cvs.h (No_Difference): New args repository,
+ update_dir. Call server_update_entries if needed. Use update_dir
+ in error message.
+ * classify.c (Classify_File): Pass new args to No_Difference.
+
+ * server.c (server_update_entries, server_checked_in,
+ server_updated): Don't do anything if noexec.
+
+ * client.c (send_fileproc): Rather than guessing how big the gzip
+ output may be, just realloc the buffer as needed.
+
+Tue Sep 13 13:22:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * lock.c: Check for errors from unlink, readdir, and closedir.
+
+ * classify.c (Classify_File): Pass repository and update_dir to
+ sticky_ck.
+ (sticky_ck): New args repository and update_dir.
+ * server.c, server.h (server_update_entries): New function.
+ * classify.c (sticky_ck): Call it.
+ * client.c: New response "New-entry".
+ * client.c (send_fileproc): Send tag/date from vers->entdata, not
+ from vers itself.
+
+Mon Sep 12 07:07:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c: Clean up formatting ("= (errno)" -> "= errno").
+
+ * cvs.h: Declare strerror.
+
+ * client.c: Add code to deal with Set-sticky and Clear-sticky
+ responses, and Sticky request.
+ * server.c: Add code to deal with Sticky request.
+ * server.c, server.h (server_set_sticky): New function.
+ * create_adm.c (Create_Admin), update.c (update, update_dirent_proc),
+ commit.c (commit_dirleaveproc): Call it.
+ * client.c, client.h (send_files): Add parameter aflag.
+ * add.c (add), diff.c (diff), log.c (cvslog), remove.c (cvsremove),
+ status.c (status),
+ client.c (client_commit, client_update, client_checkout): Pass it.
+ * client.c (client_update): Add -A flag.
+
+Fri Sep 9 07:05:35 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * entries.c (WriteTag): Check for error from unlink_file.
+
+ * server.c (server_updated): Initialize size to 0. Previously if
+ the file was zero length, the variable size got used without being
+ set.
+
+Thu Sep 8 14:23:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (serve_repository): Check for error from fopen on
+ CVSADM_ENT.
+
+ * update.c (update, update_dirent_proc): Check for errors when
+ removing Entries.Static.
+
+ * client.c: Add code to deal with Set-static-directory and
+ Clear-static-directory responses, and Static-directory request.
+ * server.c, server.h (server_clear_entstat, server_set_entstat):
+ New functions.
+ * update.c, checkout.c, modules.c: Call them.
+ * server.c: Add code to deal with Static-directory request.
+
+ * server.c, client.c: Use strchr and strrchr instead of index and
+ rindex.
+
+ * server.c (serve_unchanged, serve_lost): Change comments which
+ referred to changing timestamp; we don't always change the
+ timestamp in those cases anymore.
+
+Wed Sep 7 10:58:12 1994 J.T. Conklin (jtc@rtl.cygnus.com)
+
+ * cvsrc.c (read_cvsrc): Don't call getenv() three times when one
+ time will do.
+
+ * subr.c (xmalloc, xrealloc): Change type of bytes argument from
+ int to size_t and remove the test that checks if it is less than
+ zero.
+ * cvs.h (xmalloc, xrealloc): Update prototype.
+
+Thu Sep 1 12:22:20 1994 Jim Kingdon (kingdon@cygnus.com)
+
+ * update.c (merge_file, join_file): Pass -E to rcsmerge.
+ (merge_file): If rcsmerge doesn't change the file, say so.
+
+ * recurse.c, cvs.h (start_recursion): New argument wd_is_repos.
+ * recurse.c (start_recursion): Use it instead of checking whether
+ command_name is rtag to find out if we are cd'd to the repository.
+ * client.c, update.c, commit.c, status.c, diff.c, log.c, admin.c,
+ remove.c, tag.c: Pass 0 for wd_is_repos.
+ * rtag.c, patch.c: Pass 1 for wd_is_repos.
+
+ * classify.c, cvs.h (Classify_File): New argument pipeout.
+ * classify.c (Classify_File): If pipeout, don't complain if the
+ file is already there.
+ * update.c, commit.c, status.c: Change callers.
+
+ * mkmodules.c (main): Don't print "reminders" if commitinfo,
+ loginfo, rcsinfo, or editinfo files are missing.
+
+Mon Aug 22 23:22:59 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * server.c (strerror): Static definition replaced by extern
+ declaration.
+
+Sun Aug 21 07:16:27 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com)
+
+ * client.c (update_entries): Run "patch" with input from
+ /dev/null, so if it's the wrong version, it fails quickly rather
+ than waiting for EOF from terminal before failing.
+
+Sat Aug 20 04:16:33 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * server.c (serve_unchanged): Instead of creating a file with a
+ zero timestamp, rewrite the entries file to have "=" in the
+ timestamp field.
+ * vers_ts.c (mark_lost, mark_unchanged): New macros.
+ (time_stamp_server): Use them, for clarity. Interpret "="
+ timestamp as an unchanged file. A zero-timestamp file should
+ never be encountered now in use_unchanged mode.
+
+ * client.c (start_server): If CVS_CLIENT_PORT indicates a
+ non-positive port number, skip straight to rsh connection.
+
+ * status.c (status_fileproc): Fix ts_rcs reference when printing
+ version info, to correspond to new Entries file format. Don't
+ print it at all if server_active, because it won't have any useful
+ data.
+
+Thu Aug 18 14:38:21 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * cvs.h (status): Declare.
+ * client.c (client_status): New function.
+
+ * client.h (client_status): Declare.
+ * main.c (cmds): Include it.
+ * server.c (serve_status): New function.
+ (requests): Add it.
+ * status.c (status): Do the remote thing if client_active.
+
+ * client.c (supported_request): New function.
+ (start_server): Use it.
+
+ * server.c (receive_partial_file): New function, broken out from
+ serve_modified. Operate with fixed-size local buffer, instead of
+ growing stack frame by entire file size.
+ (receive_file): New function, broken out from serve_modified.
+ (serve_modified): Call it.
+ (server): Print out name of unrecognized request.
+
+ More generic stream-filtering support:
+ * client.c (close_on_exec, filter_stream_through_program): New
+ functions.
+ (server_fd): New variable.
+ (get_responses_and_close): Direct non-rsh connection is now
+ indicated by server_fd being non-negative. File descriptors for
+ to_server and from_server may now be different in case "tee"
+ filtering is being done. Wait for rsh_pid specifically.
+ (start_server): Use filter_stream_through_program for "tee"
+ filter, and enable it for direct Kerberos-authenticated
+ connections. Use dup to create new file descriptors for server
+ connection if logging is enabled.
+ (start_rsh_server): Disable code that deals with logging.
+
+ Per-file compression support:
+ * cvs.h (gzip_level): Declare.
+ * main.c (usg): Describe new -z argument.
+ (main): Recognize it and set gzip_level.
+ * client.c (filter_through_gzip, filter_through_gunzip): New
+ functions to handle compression.
+ (update_entries): If size starts with "z", uncompress
+ (start_server): If gzip_level is non-zero and server supports it,
+ issue gzip-file-contents request.
+ (send_fileproc): Optionally compress file contents. Use a
+ slightly larger buffer, anticipating the worst case.
+ * server.c (gzip_level): Define here.
+ (receive_file): Uncompress file contents if needed.
+ (serve_modified): Recognize "z" in file size and pass receive_file
+ appropriate flag.
+ (buf_read_file_to_eof, buf_chain_length): New functions.
+ (server_updated): Call them when sending a compressed file.
+ (serve_gzip_contents): New function; set gzip_level.
+ (requests): Added gzip-file-contents request.
+
+Wed Aug 17 09:37:44 1994 J.T. Conklin (jtc@cygnus.com)
+
+ * find_names.c (find_dirs): Use 4.4BSD filesystem feature (it
+ contains the file type in the dirent structure) to avoid
+ stat'ing each file.
+
+ * commit.c (remove_file,checkaddfile): Change type of umask
+ variables from int to mode_t.
+ * subr.c (): Likewise.
+
+Tue Aug 16 19:56:34 1994 Mark Eichin (eichin@cygnus.com)
+
+ * diff.c (diff_fileproc): Don't use diff_rev* because they're
+ invariant across calls -- add new variable top_rev.
+ (diff_file_nodiff): After checking possible use_rev* values, if
+ top_rev is set drop it in as well (if we don't already have two
+ versions) and then clear it for next time around.
+
+Wed Aug 10 20:50:47 1994 Mark Eichin (eichin@cygnus.com)
+
+ * diff.c (diff_fileproc): if ts_user and ts_rcs match, then the
+ file is at the top of the tree -- so we might not even have a
+ copy. Put the revision into diff_rev1 or diff_rev2.
+
+Wed Aug 10 14:55:38 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * server.c (do_cvs_command): Use waitpid.
+
+ * subr.c (run_exec): Always use waitpid.
+
+ * Makefile.in (CC, LIBS): Define here, in case "make" is run in
+ this directory instead of top level.
+
+Wed Aug 10 13:57:06 1994 Mark Eichin (eichin@cygnus.com)
+
+ * client.c (krb_get_err_text): use HAVE_KRB_GET_ERR_TEXT to
+ determine if we need to use the array or the function.
+ * main.c: ditto.
+
+Tue Aug 9 16:43:30 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * entries.c (ParseEntries): If timestamp is in old format, rebuild
+ it in the new format. Fudge an unmatchable entry that won't
+ trigger this code next time around, if the file is modified.
+
+ * vers_ts.c (time_stamp): Only put st_mtime field into timestamp,
+ and use GMT time for it. With st_ctime or in local time, copying
+ trees between machines in different time zones makes all the files
+ look modified.
+ (time_stamp_server): Likewise.
+
+Tue Aug 9 19:40:51 1994 Mark Eichin (eichin@cygnus.com)
+
+ * main.c (main): use krb_get_err_text function instead of
+ krb_err_txt array.
+
+Thu Aug 4 15:37:50 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * main.c (main): When invoked as kserver, set LOGNAME and USER
+ environment variables to the remote user name.
+
+Thu Aug 4 07:44:37 1994 Mark Eichin (eichin@cygnus.com)
+
+ * client.c: (handle_valid_requests): if we get an option that has
+ rq_enableme set, then send that option. If it is UseUnchanged, set
+ use_unchanged so that the rest of the client knows about
+ it. (Could become a more general method for dealing with protocol
+ upgrades.)
+ (send_fileproc): if use_unchanged didn't get set, send an
+ old-style "Lost" request, otherwise send an "Unchanged" request.
+ * server.c (serve_unchanged): new function, same as serve_lost,
+ but used in the opposite case.
+ (requests): add new UseUnchanged and Unchanged requests, and make
+ "Lost" optional (there isn't a good way to interlock these.)
+ * server.h (request.status): rq_enableme, new value for detecting
+ compatibility changes.
+ * vers_ts.c (time_stamp_server): swap meaning of zero timestamp if
+ use_unchanged is set.
+
+Tue Jul 26 10:19:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * sanity.sh: Separate CVSROOT_FILENAME, which must be the filename
+ of the root, from CVSROOT, which can include a hostname for
+ testing remote CVS. (but the tests aren't yet prepared to deal
+ with the bugs in remote CVS).
+
+ * import.c (update_rcs_file): Change temporary file name in TMPDIR
+ from FILE_HOLDER to cvs-imp<process-id>.
+
+ * sanity.sh: Add ">/dev/null" and "2>/dev/null" many places to
+ suppress spurious output. Comment out tests which don't work (cvs
+ add on top-level directory, cvs diff when non-committed adds or
+ removes have been made, cvs release, test 53 (already commented as
+ broken), retagging without deleting old tag, test 63). Now 'make
+ check' runs without any failures.
+
+Fri Jul 15 12:58:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * Makefile.in (install): Do not depend upon installdirs.
+
+Thu Jul 14 15:49:42 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c, server.c: Don't try to handle alloca here; it's
+ handled by cvs.h.
+
+Tue Jul 12 13:32:40 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (update_entries): Reset stored_checksum_valid if we
+ quit early because of a patch failure.
+
+Fri Jul 8 11:13:05 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (responses): Mark "Remove-entry" as optional.
+
+Thu Jul 7 14:07:58 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * server.c (server_updated): Add new checksum argument. If it is
+ not NULL, and the client supports the "Checksum" response, send
+ it.
+ * server.h (server_updated): Update prototype.
+ * update.c: Include md5.h.
+ (update_file_proc): Pass new arguments to patch_file and
+ server_updated.
+ (patch_file): Add new checksum argument. Set it to the MD5
+ checksum of the version of the file being checked out.
+ (merge_file): Pass new argument to server_updated.
+ * client.c: Include md5.h.
+ (stored_checksum_valid, stored_checksum): New static variables.
+ (handle_checksum): New static function.
+ (update_entries): If a checksum was received, check it against the
+ MD5 checksum of the final file.
+ (responses): Add "Checksum".
+ (start_server): Clear stored_checksum_valid.
+ * commit.c (commit_fileproc): Pass new argument to server_updated.
+
+ * client.h (struct response): Move definition in from client.c,
+ add status field.
+ (responses): Declare.
+ * client.c (struct response): Remove definition; moved to
+ client.h.
+ (responses): Make non-static. Initialize status field.
+ * server.c (serve_valid_responses): Check and record valid
+ responses, just as in handle_valid_requests in client.c.
+
+ * diff.c (diff_client_senddate): New function.
+ (diff): Use it to send -D arguments to server.
+
+Wed Jul 6 12:52:37 1994 J.T. Conklin (jtc@phishhead.cygnus.com)
+
+ * rcs.c (RCS_parsercsfile_i): New function, parse RCS file
+ referenced by file ptr argument.
+ (RCS_parsercsfile): Open file and pass its file ptr to above function.
+ (RCS_parse): Likewise.
+
+Wed Jul 6 01:25:38 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * client.c (update_entries): Print message indicating that an
+ unpatchable file will be refetched.
+ (client_update): Print message when refetching unpatchable files.
+
+Fri Jul 1 07:16:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * client.c (send_dirent_proc): Don't call send_a_repository if
+ repository is "".
+
+Fri Jul 1 13:58:11 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (last_dirname, last_repos): Move out of function.
+ (failed_patches, failed_patches_count): New static variables.
+ (update_entries): If patch program fails, save short_pathname in
+ failed_patches array, only exit program if retcode is -1, and
+ return out of the function rather than update the Entries line.
+ (start_server): Clear toplevel_repos, last_dirname, last_repos.
+ (client_update): If failed_patches is not NULL after doing first
+ update, do another update, but remove all the failed files first.
+
+Thu Jun 30 09:08:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (requests): Add request "Global_option".
+ (serve_global_option): New function, to handle it.
+ * client.c (start_server): Deal with global options. Check for
+ errors from fprintf.
+
+ * client.c (send_fileproc): Split out code which sends repository
+ into new function send_a_repository. Also, deal with update_dir
+ being ".".
+ (send_dirent_proc): Call send_a_repository.
+ * add.c (add): If client_active, do special processing for
+ directories.
+ (add_directory): If server_active, don't try to create CVSADM
+ directory.
+
+Thu Jun 30 11:58:52 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (update_entries): If patch succeeds, remove the backup
+ file.
+ * server.c (server_updated): Add new argument file_info. If it is
+ not NULL, use it rather than sb to get the file mode.
+ * server.h (server_updated): Update prototype for new argument.
+ * update.c (update_file_proc): Pass new arguments to patch_file
+ and server_updated.
+ (patch_file): Add new argument file_info. Don't use -p to check
+ out new version, check it out into file and rename that to file2.
+ If result is not readable, assume file is dead and set docheckout.
+ Call xchmod on file2. Close the patch file after checking for a
+ binary diff. Set file_info to the results of stat on file2.
+ (merge_file): Pass new argument to server_updated.
+ * commit.c (commit_fileproc): Pass new argument to server_updated.
+
+Wed Jun 29 13:00:41 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (krb_realmofhost): Declare, since it's not the current
+ <krb.h>.
+ (start_server): Save the name returned by gethostbyname. Call
+ krb_realmofhost to get the realm. Pass the resulting realm to
+ krb_sendauth. Pass the saved real name to krb_sendauth, rather
+ than server_host.
+
+ * update.c (update_file_proc): Pass &docheckout to patch_file. If
+ it is set to 1, fall through to T_CHECKOUT case.
+ (patch_file): Add docheckout argument. Set it to 1 if we can't
+ make a patch. Check out the files and run diff rather than
+ rcsdiff. If either file does not end in a newline, we can't make
+ a patch. If the patch starts with the string "Binary", assume
+ one or the other is a binary file, and that we can't make a patch.
+
+Tue Jun 28 11:57:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com)
+
+ * client.c (update_entries): If the patch file is empty, don't run
+ patch program; avoids error message.
+
+ * classify.c (Classify_File): Return T_CHECKOUT, not T_PATCH, if
+ the file is in the Attic.
+
+ * cvs.h (enum classify_type): Add T_PATCH.
+ * config.h (PATCH_PROGRAM): Define.
+ * classify.c (Classify_File): If user file exists and is not
+ modified, and using the same -k options, return T_PATCH instead of
+ T_CHECKOUT.
+ * update.c (patches): New static variable.
+ (update): Add u to gnu_getopt argument. Handle it.
+ (update_file_proc): Handle T_PATCH.
+ (patch_file): New static function.
+ * server.h (enum server_updated_arg4): Add SERVER_PATCHED.
+ * server.c (server_updated): Handle SERVER_PATCHED by sending
+ "Patched" command.
+ (serve_ignore): New static function.
+ (requests): Add "update-patches".
+ (client_update): If the server supports "update-patches", send -u.
+ * client.c (struct update_entries_data): Change contents field
+ from int to an unnamed enum.
+ (update_entries): Correponding change. If contents is
+ UPDATE_ENTRIES_PATCH, pass the input to the patch program.
+ (handle_checked_in): Initialize contents to enum value, not int.
+ (handle_updated, handle_merged): Likewise.
+ (handle_patched): New static function.
+ (responses): Add "Patched".
+ * commit.c (check_fileproc): Handle T_PATCH.
+ * status.c (status_fileproc): Likewise.
+
+ * client.c (start_server): If CVS_CLIENT_PORT is set in the
+ environment, connect to that port, rather than looking up "cvs" in
+ /etc/services. For debugging.
+
+Tue Jun 21 12:48:16 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
+
+ * update.c (joining): Return result of comparing pointer with
+ NULL, not result of casting (truncating, on Alpha) pointer to int.
+
+ * main.c (main) [HAVE_KERBEROS]: Impose a umask if starting as
+ Kerberos server, so temp directories won't be world-writeable.
+
+ * update.c (update_filesdone_proc) [CVSADM_ROOT]: If environment
+ variable CVS_IGNORE_REMOTE_ROOT is set and repository is remote,
+ don't create CVS/Root file.
+ * main.c (main): If env var CVS_IGNORE_REMOTE_ROOT is set, don't
+ check CVS/Root.
+
+Fri Jun 10 18:48:32 1994 Mark Eichin (eichin@cygnus.com)
+
+ * server.c (O_NDELAY): use POSIX O_NONBLOCK by default, unless it
+ isn't available (in which case substitute O_NDELAY.)
+
+Thu Jun 9 19:17:44 1994 Mark Eichin (eichin@cygnus.com)
+
+ * server.c (server_cleanup): chdir out of server_temp_dir before
+ deleting it (so that it works on non-BSD systems.) Code for choice
+ of directory cloned from server().
+
+Fri May 27 18:16:01 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * client.c (update_entries): Add return type of void.
+ (get_responses_and_close): If using Kerberos and from_server and
+ to_server are using the same file descriptor, use shutdown, not
+ fclose. Close from_server.
+ (start_server): New function; most of old version renamed to
+ start_rsh_server.
+ (start_rsh_server): Mostly renamed from old start_server.
+ (send_fileproc): Use %lu and cast sb.st_size in fprintf call.
+ (send_files): Remove unused variables repos and i.
+ (option_no_arg): Comment out; unused.
+ * main.c (main): Initialize cvs_update_env to 0. If command is
+ "kserver", authenticate and change command to "server". If
+ command is "server", don't call Name_Root, don't check access to
+ history file, and don't assume that CVSroot is not NULL.
+ * server.c (my_memmove): Removed.
+ (strerror): Change check from STRERROR_MISSING to HAVE_STRERROR.
+ (serve_root): Likewise for putenv.
+ (serve_modified): Initialize buf to NULL.
+ (struct output_buffer, buf_try_send): Remove old buffering code.
+ (struct buffer, struct buffer_data, BUFFER_DATA_SIZE,
+ allocate_buffer_datas, get_buffer_data, buf_empty_p,
+ buf_append_char, buf_append_data, buf_read_file, buf_input_data,
+ buf_copy_lines): New buffering code.
+ (buf_output, buf_output0, buf_send_output, set_nonblock,
+ set_block, buf_send_counted, buf_copy_counted): Rewrite for new
+ buffering code.
+ (protocol, protocol_memory_error, outbuf_memory_error,
+ do_cvs_command, server_updated): Rewrite for new buffering code.
+ (input_memory_error): New function.
+ (server): Put Rcsbin at start of PATH in environment.
+ * Makefile.in: Add @includeopt@ to DEFS.
+
+Fri May 20 08:13:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * cvs.h, classify.c (Classify_File): New argument update_dir.
+ Include it in user messages.
+ * commit.c (check_fileproc), status.c (status_fileproc), update.c
+ (update_file_proc): Pass update_dir to Classify_File.
+ * commit.c (check_fileproc), update.c (checkout_file):
+ Include update_dir in user messages.
+ * commit.c (check_fileproc) update.c (update_file_proc): Re-word
+ "unknown status" message.
+
+ * server.c (server_checked_in): Deal with the case where
+ scratched_file is set rather than entries_line.
+
+ * entries.c (Register): Write file even if server_active.
+ * add.c (add): Add comment about how we depend on above behavior.
+
+Tue May 17 08:16:42 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * mkmodules.c: Add dummy server_active and server_cleanup, to go
+ with the dummy Lock_Cleanup already there.
+
+ * server.c (server_cleanup): No longer static.
+
+Sat May 7 10:17:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Deal with add and remove:
+ * commit.c (checkaddfile): If CVSEXT_OPT or CVSEXT_LOG file does
+ not exist, just silently keep going.
+ (remove_file): If server_active, remove file before creating
+ temporary file with that name.
+ * server.c (serve_remove, serve_add): New functions.
+ (requests): Add them.
+ * server.c (server_register): If options is NULL, it means there
+ are no options.
+ * server.c, server.h (server_scratch_entry_only): New function.
+ New variable kill_scratched_file.
+ (server_scratch, server_updated): Deal with kill_scratched_file.
+ * commit.c (commit_fileproc): If server_active, call
+ server_scratch_entry_only and server_updated.
+ * add.c (add): Add client_active code.
+ (add): If server_active, call server_checked_in for each file added.
+ * remove.c (remove): Add client_active code.
+ (remove_fileproc): If server_active, call server_checked_in.
+ * main.c (cmds), client.c, client.h: New functions client_add and
+ client_remove.
+ * Move declarations of add, cvsremove, diff, and cvslog from
+ main.c to cvs.h.
+ * client.c (call_in_directory): Update comment regarding Root and
+ Repository files.
+ (send_fileproc): Only send Entries line if Version_TS really finds
+ an entry. If it doesn't find one, send Modified.
+ (update_entries): If version is empty or starts with 0 or -,
+ create a dummy timestamp.
+
+Thu May 5 19:02:51 1994 Per Bothner (bothner@kalessin.cygnus.com)
+
+ * recurse/c (start_recursion): If we're doing rtag, and thus
+ have cd'd to the reporsitory, add ,v to a file name before stat'ing.
+
+Wed Apr 20 15:01:45 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * client.c (client_commit): Call ign_setup.
+ (client_update, client_checkout): Likewise.
+ * diff.c (diff): If client, call ign_setup.
+ * log.c (cvslog): Likewise.
+ * update.h (ignlist): Change definition to declaration to avoid
+ depending upon common semantics (not required by ANSI C, and not
+ the default on Irix 5).
+ * update.c (ignlist): Define.
+
+Tue Apr 19 00:02:54 1994 John Gilmore (gnu@cygnus.com)
+
+ Add support for remote `cvs log'; clean up `cvs diff' a bit.
+
+ * client.c (send_arg): Make external.
+ (send_option_string): New function.
+ (client_diff_usage): Remove, unused.
+ (client_diff): Just call diff, not do_diff.
+ (client_log): Add.
+ * client.h (client_log, send_arg, send_option_string): Declare.
+ * cvs.h (cvslog): Declare.
+ * diff.c (do_diff): Fold back into diff(), distinguish by checking
+ client_active.
+ (diff): Remove `-*' arg parsing crud; use send_option_string.
+ * log.c (cvslog): If a client, start the server, pass options
+ and files, and handle server responses.
+ * main.c (cmds): Add client_log.
+ (main): Remove obnoxious message every time CVS/Root is used.
+ Now CVS will be quiet about it -- unless there is a conflict
+ between $CVSROOT or -d value versus CVS/Root.
+ * server.c (serve_log): Add.
+ (requests): Add "log".
+
+Mon Apr 18 22:07:53 1994 John Gilmore (gnu@cygnus.com)
+
+ Add support for remote `cvs diff'.
+
+ * diff.c (diff): Break guts out into new fn do_diff.
+ Add code to handle starting server, writing args,
+ sending files, and retrieving responses.
+ (includes): Use PARAMS for static function declarations.
+ * client.c (to_server, from_server, rsh_pid,
+ get_responses_and_close, start_server, send_files,
+ option_with_arg): Make external.
+ (send_file_names): New function.
+ (client_diff): New function.
+ * client.h (client_diff, to_server, from_server,
+ rsh_pid, option_with_arg, get_responses_and_close, start_server,
+ send_file_names, send_files): Declare.
+ * cvs.h (diff): Declare.
+ * main.c (cmds): Add client_diff to command table.
+ * server.c (serve_diff): New function.
+ (requests): Add serve_diff.
+ (server): Bug fix: avoid free()ing incremented cmd pointer.
+ * update.h (update_filesdone_proc): Declare with PARAMS.
+
+Sat Apr 16 04:20:09 1994 John Gilmore (gnu@cygnus.com)
+
+ * root.c (Name_root): Fix tyop (CVSroot when root meant).
+
+Sat Apr 16 03:49:36 1994 John Gilmore (gnu@cygnus.com)
+
+ Clean up remote `cvs update' to properly handle ignored
+ files (and files that CVS can't identify), and to create
+ CVS/Root entries on the client side, not the server side.
+
+ * client.c (send_fileproc): Handle the ignore list.
+ (send_dirent_proc): New function for handling ignores.
+ (send_files): Use update_filesdone_proc and send_dirent_proc
+ while recursing through the local filesystem.
+ * update.h: New file.
+ * update.c: Move a few things into update.h so that client.c
+ can use them.
+
+Fri Mar 11 13:13:20 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * server.c: If O_NDELAY is not defined, but O_NONBLOCK is, define
+ O_NDELAY to O_NONBLOCK.
+
+Wed Mar 9 21:08:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Fix some spurious remote CVS errors caused by the CVS/Root patches:
+ * update.c (update_filesdone_proc): If server_active, don't try to
+ create CVS/Root.
+ * root.c (Name_Root): Make error messages which happen if root is
+ not an absolute pathname or if it doesn't exist a bit clearer.
+ Skip them if root contains a colon.
+
+Mon Nov 1 15:54:51 1993 K. Richard Pixley (rich@sendai.cygnus.com)
+
+ * client.c (client_commit): dynamically allocate message.
+
+Tue Jun 1 17:03:05 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * server.h: remove alloca cruft
+
+ * server.c: replace with better alloca cruft
+
+Mon May 24 11:25:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * entries.c (Scratch_Entry): Update our local Entries file even if
+ server_active.
+
+ * server.c (server_scratch, server_register): If both Register
+ and Scratch_Entry happen, use whichever one happened later.
+ If neither happen, silently continue.
+
+ * client.c (client_checkout): Initialize tag and date (eichin and
+ I independently discovered this bug at the same time).
+
+Wed May 19 10:11:51 1993 Mark Eichin (eichin@cygnus.com)
+
+ * client.c (update_entries): handle short reads over the net
+ (SVR4 fread is known to be broken, specifically for short
+ reads off of streams.)
+
+Tue May 18 15:53:44 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * server.c (do_cvs_command): Fix fencepost error in setting
+ num_to_check.
+
+ * server.c (do_cvs_command): If terminated with a core dump, print
+ message and set dont_delete_temp.
+ (server_cleanup): If dont_delete_temp, don't delete it.
+
+ * client.c (get_server_responses): Don't change cmd since we
+ are going to "free (cmd)".
+
+ * server.c: Rename memmove to my_memmove pending a real fix.
+
+ * server.c (do_cvs_command): Set num_to_check to largest descriptor
+ we try to use, rather than using (non-portable) getdtablesize.
+
+Wed May 12 15:31:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ Add CVS client feature:
+ * client.{c,h}: New files.
+ * cvs.h: Include client.h.
+ * main.c: If CVSROOT has a colon, use client commands instead.
+ * vers_ts.c (Version_TS): If repository arg is NULL, don't worry
+ about the repository.
+ * logmsg.c (do_editor): If repository or changes is NULL, just don't
+ use those features.
+ * create_adm.c (Create_Admin), callers: Move the test for whether
+ the repository exists from here to callers.
+ * repos.c (Name_Repository): Don't test whether the repository exists
+ if client_active set (might be better to move test to callers).
+
+ Add CVS server feature:
+ * server.{c,h}: New files.
+ * cvs.h: Include server.h.
+ * checkin.c (Checkin): Call server_checked_in.
+ * update.c (update_file_proc, merge_files): Call server_updated.
+ * entries.c (Register): Call server_register.
+ (Scratch_Entry): Call server_scratch.
+ * main.c: Add server to cmds.
+ * vers_ts.c (Version_TS): If server_active, call new function
+ time_stamp_server to set ts_user.
+
+
+For older changes, there might be some relevant stuff in the bottom of
+the NEWS file, but I'm afraid probably a lot of them are lost in the
+mists of time.
diff --git a/src/ChangeLog-96 b/src/ChangeLog-96
new file mode 100644
index 0000000..6c3a2a1
--- /dev/null
+++ b/src/ChangeLog-96
@@ -0,0 +1,4434 @@
+Mon Dec 30 15:43:48 1996 Abe Feldman <feldman@harvey.cyclic.com>
+
+ * checkout.c (build_dirs_and_chdir): Reproduced block containing
+ Create_Admin, placing it before Subdir_Register.
+ * sanity.sh (basicb): Added tests 1a and 9a to test above changes
+ to the checkout command.
+
+Mon Dec 30 13:29:14 1996 uz@wuschel.ibb.schwaben.com (Ullrich von Bassewitz)
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h (CVSEDITPREFIXLEN): New define.
+ * logmsg.c (do_editor): Use CVSEDITPREFIXLEN when deciding whether
+ to strip off CVSEDITPREFIX and when telling the user what we will
+ strip off.
+
+Sun Dec 22 22:06:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c (do_verify): If noexec, skip the verification *without*
+ printing a message. Use cvs_output not printf. Skip verification
+ for client_active.
+
+Wed Dec 18 12:27:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * repos.c (Name_Repository): Add comment regarding wording of
+ "*PANIC*" error message.
+
+1996-12-18 Jim Kingdon
+
+ * client.c (call_in_directory): If the directory we are about
+ to create is the same as CVSADM as seen by fncmp (for example,
+ it is "cvs" and filenames are case-insensitive), then give a
+ fatal error.
+
+Tue Dec 17 13:14:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Add comments about SETXID security holes.
+
+ * logmsg.c (do_verify): Reindent comments. Check errno if return
+ code from run_exec is -1, not if it is 1.
+ * sanity.sh (info): Move tests info-4 and info-8 to end and rename
+ them. Add verifymsg tests. Instead of forcibly removing loginfo,
+ remove it nicely (test info-11).
+
+Tue Dec 17 12:45:32 1996 Abe Feldman <feldman@cyclic.com>
+
+ * commit.c, import.c: Call do_verify as well as do_editor.
+ * cvs.h (CVSROOTADM_VERIFYMSG): Define.
+ * logmsg.c, cvs.h (do_verify, verifymsg_proc): New functions.
+ (verifymsg_script): New variable.
+ * mkmodules.c (filelist): Add CVSROOTADM_VERIFYMSG.
+
+Mon Dec 16 13:24:47 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * lock.c (remove_locks): New static function, copied from part of
+ Lock_Cleanup.
+ (Lock_Cleanup): Call remove_locks.
+ (Writer_Lock): Call remove_locks rather than Lock_Cleanup when
+ waiting for a lock.
+
+Thu Dec 12 10:36:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * login.c (get_cvs_password): If CVS_PASSWORD is set, print a
+ warning (and then proceed to ignore it). It was a documented
+ feature, so we should point people who were using it to the
+ replacement.
+
+Mon Dec 9 12:35:43 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (server_updated): Change comment to only worry about
+ umask in the rsh case.
+ (server): Create the temporary directory, and change the mode to
+ S_IRWXU.
+ (switch_to_user): Set the umask to 0, not 077.
+
+Mon Dec 9 10:58:28 1996 Jim Blandy <jimb@floss.cyclic.com>
+
+ * login.c (get_cvs_password): Remove code to check for value of
+ CVS_PASSWORD. Keeping cleartext passwords in environment
+ variables is a really bad idea on Unix, since anyone can print
+ out a processes' environment using 'ps' (on BSD variants
+ anyway). Update help message.
+
+Fri Dec 6 15:59:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: When matching "use .cvs commit. to remove this file
+ permanently" messages, change "cvs" to "${PROG}".
+ (rdiff, binfiles): Likewise.
+ This fixes testing a program named something other than "cvs", e.g.
+ $ cp cvs cvs-test
+ $ /bin/sh <srcdir>/sanity.sh `pwd`/cvs-test
+
+1996-12-02 Jim Kingdon
+
+ * client.c: In comment saying that socket buffers don't
+ implement the blocking routine, say they are blocking.
+ * buffer.h (struct buffer): In description of input function,
+ describe blocking, non-blocking, and NEED more fully. Say
+ what happens if we read a nonzero amount less than NEED and
+ then get end of file.
+ * client.c (socket_buffer_input): If NEED == 0, still call
+ recv (once). Handle the case where recv returns 0.
+
+Sat Nov 30 15:10:07 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c, cvs.h (file_has_markers): New function.
+ * rcs.h (RCS_MERGE_PAT): Now a fixed string not a regexp.
+ * options.h.in (GREP): Removed; no longer used.
+ * update.c (update_fileproc), commit.c (check_fileproc): Call
+ file_has_markers rather than GREP.
+ * rcscmds.c (RCS_merge): Just give a fatal error in the case where
+ we had been calling GREP. I suspect noone is using this code
+ any more.
+ * sanity.sh (conflicts): Rewrite tests 131, 132, and 133 to use
+ dotest; tests that the above changes didn't break anything.
+
+Fri Nov 29 09:06:41 1996 fnf@ninemoons.com (Fred Fish)
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (safe_location): Only call readlink if HAVE_READLINK.
+
+ * run.c (piped_child, filter_stream_through_program): If
+ HAVE_VFORK, call vfork not fork.
+ * run.c (run_exec): Add comment about why we use vfork.
+
+Mon Nov 25 12:48:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * release.c (release): Don't return after processing the first
+ argument; that kind of defeats the purpose of having a loop, eh?
+ For client, close the connection after we've processed them all.
+ * sanity.sh: Remove workaround for modules2-8 test; tests for
+ above fix. Adjust modules2-6 test to answer both questions.
+
+ * login.c: Reindent (all of get_cvs_password, a handful of lines
+ elsewhere).
+
+ Cleanups to release, mostly cosmetic:
+ * release.c (release_server): New function; breaks out server code
+ from the release function.
+ * release.c: Move delete_flag inside the release function.
+ * release.c (release): Reindent. Rewrite comments about how the
+ implementation could be improved. Don't declare variables as
+ "register". Include errno in error message. Don't cast result of
+ printf to void. Remove unused variable srepos.
+ * release.c: Remove comments at top of file about what it does.
+ They were not particularly coherent and they were also out of date
+ (I think). Likewise for comment in release function about "if we
+ are in a repository".
+ * release.c: Change "module" to "directory" in a few messages
+ since that is what is meant.
+ * sanity.sh: In tests ignore-195 and ignore-193, change expected
+ message accordingly.
+
+Sun Nov 24 11:30:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Clarify a few items in the todo list.
+
+ * log.c (log_parse_date): Use the "end" of the epoch not "next
+ week" as the time which means "no end time".
+ * sanity.sh (rcs): New test, tests dates and importing RCS files.
+
+1996-11-19 Jim Kingdon
+
+ Visual C++ lint:
+ * hash.c: Declare qsort_comp.
+ * update.c: Declare isremoved.
+
+1996-11-19 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * root.c, repos.c, modules.c, create_adm.c: Change all calls to
+ strip_path to strip_trailing_slashes. Basically strip_path is
+ just an unneeded complication (we should keep the pathname the way
+ the user specifies it, and the system can worry about things like
+ consecutive /'s if it wants to). Stripping trailing slashes is
+ potentially dubious for the same reason, but it is a somewhat
+ different case which I won't try to tackle now.
+ * cvs.h (strip_path): Remove declaration.
+
+Tue Nov 19 15:18:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ There are a lot of details to this change, but the concept is
+ relatively simple: make it so that for every CVSLCK lock that we
+ might take out, there is a flag which is set iff we have created
+ the CVSLCK directory.
+ * lock.c (struct lock): New structure.
+ * lock.c: Remove static variables repository and cleanup_lckdir.
+ They are replaced by global_readlock.repository and
+ global_readlock.have_lckdir, respectively (except insofar as the
+ rest of these changes change the concept of cleanup_lckdir).
+ New static variable global_readlock.
+ (Reader_Lock, Lock_Cleanup): Use global_readlock in place of
+ repository.
+ (lock_simple_remove, set_lock, clear_lock, write_lock): Take a
+ struct lock * instead of just a repository. Set/clear
+ lock->have_lckdir instead of cleanup_lckdir.
+ (set_writelock_proc, unlock_proc): Pass ->data, not ->key, to
+ write_lock or lock_simple_remove.
+ (lock_filesdoneproc,lock_dir_for_write): Allocate a struct lock,
+ put it in the ->data field, and fill in its fields.
+ (lock_simple_remove): Use lock->have_lckdir as the sole test for
+ whether the CVSLCK directory needs to be removed. Add
+ comments about why readlock and writelock variables don't tell us
+ for sure whether locks exist.
+ (lock_simple_remove, clear_lock): Use SIG_beginCrSect and
+ SIG_endCrSect to ensure that ->have_lckdir is set to 0 iff the
+ CVSLCK directory was really removed.
+ (lock_simple_remove): Check for errors removing CVSLCK directory.
+ (lock_simple_remove, Check_Owner, set_lock): Remove all code which
+ checks userids (including all of Check_Owner and all the AFCVS
+ code). It was bogus if several CVS processes with the same userid
+ were running (common if several users share a userid; a common
+ practice with remote CVS), and with the rest of the changes here
+ should not be needed.
+
+1996-11-16 Paul Eggert <eggert@twinsun.com>
+
+ * rcs.c (RCS_deltas): Fix unintended trigraphs.
+
+Fri Nov 15 13:06:03 1996 Tom Hageman <tom@basil.icce.rug.nl>
+
+ * diff.c (diff_fileproc): In printing error messages, use the
+ correct filename for which the error occurred.
+
+Sun Nov 10 21:13:38 1996 Paul Sanders <p.sanders@dial.pipex.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c: Use all the right cruft which goes along with
+ including sys/time.h.
+
+ * server.c: Include a "copyright" notice.
+
+ * server.c: If HAVE_WINSOCK_H, include winsock.h.
+
+ * server.c (server): Only set a handler for SIGHUP if it is
+ defined. Likewise for all the other signals.
+
+ * server.c (do_cvs_command): Use DEVNULL not /dev/null.
+
+Fri Nov 08 12:14:20 1996 Jim Kingdon
+
+ IBM ICC (OS/2) lint:
+ * add.c (add): Only declare begin_added_files if
+ SERVER_SUPPORT.
+ * client.c (init_sockaddr): Change port argument from
+ unsigned short to unsigned int. Change hostname
+ argument from const char * to char *.
+
+Sun Nov 3 18:24:28 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * sanity.sh (info): add new tests that check behavior of format
+ string substitution in loginfo file.
+
+Sat Nov 2 09:39:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (do_deferred_progs): Don't access memory once it is
+ freed (we already did it right for checkin_progs; do the same
+ thing for update_progs).
+
+ * update.c, client.c, classify.c, client.h, diff.c, commit.c,
+ create_adm.c: Nuke more PATH_MAX.
+
+Fri Nov 1 18:22:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.h: Define PROTO if it is not defined.
+
+Wed Oct 30 08:53:20 1996 jalving@ibm.net
+
+ * patch.c (patch_fileproc): Set line1 and line2 to NULL up-front
+ (before the first "goto out") so we don't try to free them.
+
+Wed Oct 30 08:53:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (remove_file, commit_filesdoneproc), run.c (run_print,
+ run_exec), modules.c (open_module, cat_module, do_module), update.c
+ (update_dirleave_proc), tag.c (tag_fileproc): Call cvs_out* rather
+ than stdio.
+ * server.c (serve_expand_modules): Remove comment about do_module
+ writing to stdout/stderr; above changes should fix this.
+
+Tue Oct 29 17:23:59 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * status.c (tag_list_proc): When printing the tag name, don't
+ truncate it to 25 characters.
+
+Tue Oct 29 12:49:07 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c, checkin.c, checkout.c, filesubr.c: Nuke arbitrary limit
+ of PATH_MAX. Many more such limits surely remain.
+
+ * fileattr.c (fileattr_set): Set attrs_modified *after* we might
+ call fileattr_read, because fileattr_read clears it.
+ * sanity.sh (devcom2): New tests, test for above fix and other
+ behaviors I discovered in the process of looking into it.
+
+Mon Oct 28 08:55:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ The following changes are to ensure that SYSTEM_CLEANUP is always
+ called.
+ * error.c, cvs.h, main.c: Remove error_set_cleanup and related
+ machinery. It was for a time when error.c was intended to be
+ shared with other programs, but that is no longer true.
+ * error.c, error.h (error_exit): New function; like error_cleanup
+ from main.c but also calls SYSTEM_CLEANUP and exit (EXIT_FAILURE).
+ * error.c (error, fperror): Call error_exit instead of doing it
+ ourself.
+ * server.c (server, serve_valid_responses, switch_to_user,
+ check_password, pserver_authenticate_connection,
+ kserver_authenticate_connection): Call SYSTEM_CLEANUP before exit.
+ * add.c, client.c, import.c, main.c, mkmodules.c, modules.c,
+ recurse.c, server.c, tag.c, update.c: Call error_exit ()
+ instead of exit (EXIT_FAILURE).
+
+Sun Oct 27 08:34:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (conflicts): New test 128.5 tests "cvs co -p" in an empty
+ directory (like 126.5), but when the file has nonempty contents.
+ * rcs.c (RCS_checkout): If writing to stdout, use cvs_output
+ rather than fwrite.
+ * update.c (checkout_file): Call cvs_stderr not fprintf.
+ These changes should fix some out-of-order bugs which show up in
+ situations like conflicts-126.5 and conflicts-128.5.
+
+ * mkmodules.c (checkout_file): Call RCS_checkout rather than
+ run_exec on RCS_CO.
+
+Sat Oct 26 18:29:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (rdiff): cd out of testimport directory and remove it
+ when done.
+
+ * sanity.sh (info): Adjust tests to reflect fact that loginfo was
+ created by cvs init.
+
+ * sanity.sh (ignore): Change test 187a1 to allow any number of
+ files in CVSROOT, not just modules.
+
+ * sanity.sh (modules): In tests 148a0 and 148a1, don't expect a
+ module which defines CVSROOT to itself, since we don't define one
+ any more. Also change test to rewrite modules rather than append
+ to it (in case any previous tests are changed to do something with
+ modules). Change test 155b to allow any number of files in
+ CVSROOT, not just modules.
+
+ * add.c (add_directory): Set rev_old and rev_new fields of struct
+ logfile_info to NULL (prevents us from trying to free them later).
+ * commit.c (find_fileproc), import.c (import): Likewise.
+
+ * sanity.sh (crerepos): New tests, to test alternate ways of
+ creating a repository and related matters.
+ * sanity.sh: Remove tests 1 through 3 and related cruft; replace
+ them with a new test 1 which merely tests "cvs init". By doing
+ the obscure stuff in crerepos we avoid having to do all this stuff
+ any time we run any single test.
+
+Sat Oct 26 16:19:48 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * main.c (main): If HAVE_TZSET is #defined, call tzset. This is
+ harmless on all systems I know of, and required on some.
+
+Fri Oct 25 13:20:44 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * diff.c (diff_file_nodiff): When setting use_rev1, only return
+ DIFF_SAME if empty_file is DIFF_DIFFERENT and ts_user is not
+ NULL. Don't get confused by a vn_user field of "0" or one
+ starting with '-'.
+ * sanity.sh (death2): Add new death2-diff-{1,2,7,8} tests for
+ above patch. Renumber existing death2-diff tests to make room.
+
+Fri Oct 25 12:38:29 1996 Jim Wilson <wilson@cygnus.com>
+
+ * sanity.sh (death2): In tests death2-diff-{2,4,6,8,10}, allow "_"
+ in temp file names. The system (tmpnam or whatever) generates
+ these names so they vary from system to system.
+
+Fri Oct 25 07:52:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c (logfile_write): Give an error for several cases which
+ should not be legal. Adjust comments accordingly.
+ * mkmodules.c (loginfo_contents): Make description of loginfo much
+ more concise. This should be a reminder, not full documentation.
+
+Tue Oct 22 10:37:37 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * commit.c (update_delproc): free structure members rev_old and
+ rev_new if they have been allocated.
+
+ * mkmodules.c: change loginfo_contents to include a description of
+ the new format string.
+
+ * logmsg.c (logfile_write): change syntax of format string.
+
+Sat Oct 19 16:09:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ For reference, this takes CVS's text segment from 348348 bytes to
+ 347420 bytes.
+ * server.c (requests): Change Directory to rq_essential
+ per change in doc/cvsclient.texi.
+ * client.c: Remove use_directory and all code which executed if
+ it wasn't set. This includes the get_short_pathname function.
+ * server.c: Likewise, for use_dir_and_repos.
+ (serve_repository): Give a fatal error.
+ * server.c (requests): Remove Lost. Change Unchanged to rq_essential.
+ (serve_lost): Removed.
+ * server.c, server.h, client.c, vers_ts.c: Remove use_unchanged,
+ code to set it, and all code which executed if it wasn't set.
+
+Sat Oct 19 12:44:08 1996 J. Richard Sladkey <jrs@world.std.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * hash.c (sortlist, new function qsort_comp): Rewrite to use qsort
+ instead of insert sort. Changes algorithm from n^2 to n log n
+ (assuming qsort is implemented with quicksort or similar).
+
+Sat Oct 19 12:44:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basic2): In test basic2-64, use -x and specify types
+ which exclude E; the test is not built to deal with E (or any
+ other new types).
+
+Sat Oct 19 12:00:00 1996 Mark Mitchell <mmitchell@usa.net>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (isemptydir, new function isremoved): Avoid pruning
+ directories that contain files marked for removal but not
+ comitted.
+ * update.c, update.h (isemptydir): Now extern, not static.
+ * update.c (isemptydir): New parameter might_not_exist handles
+ difference in functionality from old client_isemptydir. Bring
+ over the improved error checking from client_isemptydir.
+ * client.c (client_isemptydir): Removed; isemptydir now suffices.
+ * update.c (update_dirleave_proc), client.c
+ (process_prune_candidates): Update callers.
+ * sanity.sh (deep): Add tests deep-rm* for above fix.
+
+Fri Oct 18 15:53:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (devcom): Add tests devcom-some* to test watching just
+ a single file.
+
+ * root.c (Name_Root): Use isabsolute to test whether a pathname is
+ absolute instead of checking for the first character being '/'.
+ (Reported by Antoine P. Brusseau <brusseau@jprc.com>).
+
+ * commit.c (checkaddfile): Free rev only if it is non-NULL (thanks
+ to cwong@world.std.com (Christopher Wong) for diagnosing this; the
+ death2-15 test in sanity.sh hits it).
+
+Thu Oct 17 15:21:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Reenable rdiff tests. Delete rdiff-9 test to reflect
+ the fact that the change to add a -K option has not been
+ incorporated. Adjust rdiff-8 test to reflect the fact that the
+ change to change the default keyword expansion for the first
+ revision has not been incorporated.
+ * patch.c (patch_fileproc): Pass the symbolic revision to
+ RCS_checkout so that Name can be expanded correctly. Reinstates
+ one of the 30 Sep 96 changes and fixes a bug which the sanity.sh
+ rdiff test tests for.
+
+ Reinstate change from 30 Sep 96:
+ * patch.c (patch): CLIENT_SUPPORT: send '-f' if NOT force_tag_match
+
+ * client.c (process_prune_candidates): Do not ignore errors from
+ unlink_file_dir.
+
+ * filesubr.c (deep_remove_dir): If rmdir returns an error other
+ than ENOTEMPTY or EEXIST, return -1 not 0. Add workaround for AIX
+ header bug.
+
+Tue Apr 30 08:21:27 1996 Mike Sutton <mike_sutton@dayton.saic.com>
+
+ * checkout.c, history.c: added logging/reporting of cvs export
+ command
+
+Wed Oct 16 10:16:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Remove tests 4, 4.5, and 4.75; this functionality is
+ already tested by 45, 45.5 and other tests.
+ (ignore): New tests ignore-192, ignore-193, ignore-194, and
+ ignore-195 test output from "cvs release".
+ (modules2): New tests modules2-6, modules2-7, and modules2-8 test
+ ability of cvs release to handle multiple arguments. Since it
+ currently doesn't, the tests are kludged.
+
+ * server.c, cvs.h (cvs_flushout): New function.
+ * recurse.c (do_file_proc): Call it.
+ * server.c (cvs_outerr): Call fflush (stdout) in non-server case.
+ * main.c (main): Don't call setvbuf. The code was incorrectly
+ checking for "patch" (it really is "rdiff"); the concern about
+ slowing down large amounts of output is not specific to rdiff
+ (it applies to "log" for example); and the above changes should
+ meet the need.
+
+Tue Oct 15 10:22:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ This is intended to facilitate some future cleanups to the
+ locking, but by itself it is a simple, conversative rearrangement:
+ * tag.c (locked_dir, locked_list): Move from here...
+ * lock.c: ...to here.
+ * lock.c (Lock_Cleanup): If locked_dir is set clean it up too.
+ * tag.c (tag_unlockdir): Removed; with the above change
+ Lock_Cleanup suffices.
+ * tag.c (tag_lockdir): Move from here...
+ * lock.c (lock_dir_for_write): ...to here.
+ * tag.c (tag_fileproc), rtag.c (rtag_fileproc): Update callers.
+ Move comments concerning why we are locking what we are from
+ tag_lockdir to here.
+ * tag.c (tag_filesdoneproc), rtag.c (rtag_filesdoneproc):
+ Update callers.
+ * lock.c (Writer_Lock): Made static.
+ * cvs.h: Update declarations.
+ * server.c (server_notify): Call lock_dir_for_write rather than
+ calling Writer_Lock ourselves.
+
+ This is intended to facilitate some future cleanups to the
+ locking, but by itself it is a simple, conversative rearrangement:
+ * lock.c (Lock_Cleanup): Also dellist (lock_tree_list).
+ * lock.c, cvs.h (lock_tree_cleanup): Removed; with the above change
+ Lock_Cleanup suffices.
+ * commit.c, edit.c, watch.c: Change callers.
+
+Sat Oct 12 21:41:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (deep): Add comment about whether the deep-4b behavior
+ is considered desirable.
+
+Sat Oct 12 20:36:36 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (client_send_expansions): Add build_dirs parameter.
+ Change all callers.
+ (send_dirent_proc): Get build_dirs from callerdat; if it is
+ zero, don't send a nonexistent directory to the server.
+ (send_files): Add build_dirs parameter. Change all callers.
+ * client.h (send_files): Update prototype.
+ (send_files_contents): Remove prototype for nonexistent function.
+ (client_send_expansions): Update prototype.
+ * sanity.sh (deep): Add deep-4b test for above patch.
+
+Fri Oct 11 14:07:12 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ gcc -Wall lint:
+ * logmsg.c (title_proc): Remove unused variables title and comma.
+
+ * sanity.sh (modules2): Don't be picky about whether we are
+ checking in 1.3 or 1.2 of modules; it depends on whether we are
+ running all the tests or just some.
+
+Thu Oct 10 14:52:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c, server.h (server_dir): New variable.
+ (output_dir): If it is set, send it before the directory name.
+ * modules.c (do_module): Set it, in the case of & modules, and
+ restore it when done.
+ * sanity.sh (modules): Don't clean up first-dir before starting;
+ tests now clean up for themselves at the end.
+ (modules2): New tests, for above fix.
+
+Wed Oct 9 15:52:34 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * sanity.sh: Barf immediately if run as root.
+
+ * rcs.c (RCS_getrevtime): When giving a date to get_date, use the full
+ year, not the year - 1900, so that dates after 1999 are parsed
+ correctly. (Change thanks to Paul Eggert.)
+
+Wed Oct 9 10:59:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Clean up gcc -Wmissing-prototypes lint:
+ * cvs.h (admin, add, checkout, commit, diff, history, import,
+ cvslog, login, patch, release, cvsremove, rtag, status, tag):
+ Declare.
+ * server.c, main.c: Don't declare them here. Don't declare update
+ either (which is already declared in cvs.h).
+ * tag.c, cvs.h, main.c, server.c: Rename tag to cvstag to avoid
+ name conflicts.
+ * client.c (init_sockaddr, auth_server_port_number), entries.c
+ (Entnode_Create, Entnode_Destroy), hash.c (nodetypestring),
+ login.c (construct_cvspass_filename), server.c
+ (supported_response), wrapper.c (wrap_matching_entry): Make static;
+ prototype.
+ * hash.c (printlist): Prototype.
+ * myndbm.c (mydbm_load_file): Change declaration to prototype.
+
+Tue Oct 8 22:35:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (log2): Re-add these tests; they were deleted for 1.9
+ (because they were thought to be destabilizing and/or due to
+ confusion/accident), but they can be put back now.
+
+ * sanity.sh (death2): In tests death2-diff-{2,4,6,8,10}, allow "-"
+ or "%" in temp file names. The system (tmpnam or whatever)
+ generates these names so they vary from system to system.
+
+Tue Oct 8 12:37:09 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * options.h.in (HAD_RCS4): Remove; no longer used.
+
+Sun Oct 6 15:58:11 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * The following changes address problem #56 in the GNATS database
+ on harvey.cyclic.com:
+
+ * logmsg.c (str_list_format): new global -- contains the format
+ for items to be placed in str_list.
+ (Update_Logfile): move code that creates the "title" string...
+ (logfile_write): ...to here. Pull apart the filter program and
+ look for a format string, extracting it if there is one.
+ (title_proc): write a given filename/value based on the format
+ string.
+
+ * commit.c (classify_file_internal): new routine, old code (needed
+ to use the code in more than one place). Determines the status
+ and version information about a file.
+ (check_fileproc): use classify_file_internal. Fill in the rev_old
+ field for the struct logfile_info.
+ (commit_fileproc): Fill in the rev_new field.
+
+ * cvs.h (struct logfile_info): add two new fields -- rev_old and
+ rev_new -- that keep track of revision numbers across commits.
+
+Fri Sep 27 15:21:47 1996 Peter Wemm <peter@spinner.dialix.com>
+
+ * logmsg.c (do_editor): Do not use editinfo if running on the client.
+
+Fri Oct 4 15:11:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (server_cleanup): Temporarily clear noexec when calling
+ unlink_file_dir. This is so we clean up the temp directory even
+ when the -n global option is specified.
+
+Wed Oct 2 10:47:33 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * client.c (send_repository): initialize some variables before
+ first usage
+
+Tue Oct 1 13:01:24 1996 Jim Blandy <jimb@floss.cyclic.com>
+
+ Revert some of Greg's changes; they're welcome later, but we're
+ trying to keep CVS stable for pre-release testing at the moment.
+ * checkin.c, commit.c, cvs.h, diff.c, import.c, main.c, no_diff.c,
+ options.h.in, patch.c, rcs.c, rcs.h, rcscmds.c, sanity.sh, update.c:
+ Revert changes of Sep 29 and 30.
+
+Tue Oct 1 13:17:31 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Make sure the server temporary directory is removed even if
+ Max-dotdot is used.
+ * server.c (orig_server_temp_dir): New static variable.
+ (serve_max_dotdot): Don't free server_temp_dir if it is the same
+ as orig_server_temp_dir.
+ (do_cvs_command): Use orig_server_temp_dir in error message.
+ (server_cleanup): Remove orig_server_temp_dir.
+ (server): Set orig_server_temp_dir. Remove incorrect indentation
+ of error message.
+
+ * import.c (update_rcs_file): Restore new argument to
+ RCS_checkout, removed in last patch.
+
+Tue Oct 1 00:32:55 1996 Jim Blandy <jimb@floss.cyclic.com>
+
+ * import.c: Revert Greg Woods' changes of Sep 30. We may want
+ them later, but not before 1.9.
+
+Mon Sep 30 23:31:01 1996 Jim Blandy <jimb@floss.cyclic.com>
+
+ * log.c (log_fileproc): Now that we might actually find a "desc"
+ node in rcsfile->other, thanks to Ian's change below, we had
+ better deal correctly if we find a null pointer in it.
+
+Mon Sep 30 13:55:03 1996 Greg A. Woods <woods@most.weird.com>
+
+ * main.c (main): don't set need_to_create_root for "cvs init"
+ either, just in case it's run from within a valid working
+ directory.
+
+ * sanity.sh (testcvs): oops, forgot to comment out test version I
+ was using...
+
+ * diff.c (diff_fileproc): use Diffbin instead of DIFF (3).
+ * patch.c (patch_fileproc): use Diffbin instead of DIFF.
+ * commit.c (check_fileproc): use Grepbin instead of GREP.
+ * rcscmds.c (RCS_merge): use Grepbin instead of GREP.
+ * update.c (patch_file): use Diffbin instead of DIFF.
+ (update_fileproc): use Grepbin instead of GREP.
+ * cvs.h (Diffbin): new declaration.
+ (Grepbin): new declaration.
+ (DIFFBIN_ENV): new manifest to name DIFFBIN environ var.
+ (GREPBIN_ENV): new manifest to name GREPBIN environ var.
+ * option.h.in (DIFFBIN_DFLT): renamed from DIFF.
+ (GREPBIN_DFLT): renamed from GREP.
+ * main.c (main): new variables diffbin_update_env and
+ grepbin_update_inv, ala rcsbin_update_env.
+ (main): new options -D diffbin and -g grepbin
+ (usg): describe new options -D diffbin and -g grepbin.
+ (Diffbin): new global variable for DIFF path.
+ (Grepfbin): new global variable for GREP path.
+
+ * options.h.in (RCSBIN_DFLT): mention this needs to be set if
+ your PATH isn't set properly by rshd.
+
+ * sanity.sh (rdiff): re-do Jim's change, but with the original
+ keywords I had intended (should be a bit more like real life), and
+ Jim's better RCS date and user matching form.
+ [I guess that's what I get for checking things in at 3am! ;-)]
+
+Mon Sep 30 17:00:20 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_reparsercsfile): Store desc field value in main RCS
+ node data, not in version specific data.
+ * sanity.sh: Enable log2 test (for local CVS only).
+
+Mon Sep 30 13:01:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (log2): New test, tests cvs add -m. Not yet enabled
+ in "tests" because CVS currently flunks this test.
+
+ * sanity.sh (rdiff, basic2): Allow "cvs server" as well as "cvs
+ checkout" and friends in messages. In testing output of cvs
+ status, don't require a tab which isn't there for remote. Skip
+ test rdiff-9 for remote. In test basic2-64, add missing slash in
+ the pattern which gets used for remote.
+
+ * sanity.sh (rdiff): Fix strings we were matching against which
+ got keyword-expanded in checking in sanity.sh.
+
+Mon Sep 30 03:21:37 1996 Greg A. Woods <woods@most.weird.com>
+
+ * sanity.sh: change all regexpr literal '.' to '\.'
+ (basic2): why are tests 34 & 42 commented out (because
+ of 'diff -u'?)?
+ add tests 56[abc], 57a, and 58a to test import to the main
+ branch (i.e. branch '1').
+ (rdiff): new test section for rdiff -K, etc.
+ (dotest): remove dotest.ex? before running a new test.
+ (dotest_fail): remove dotest.ex? before running a new test.
+ (dotest_internal): write expected output to dotest.exp, or if $4
+ also used, to dotest.ex1 and dotest.ex2.
+ (patch): renamed this test to 'serverpatch'.
+ (dotest_lit): rename dotest.res to dotest.exp ala dotest().
+ remove dotest.ex? before running a new test.
+ (DOTSTAR): mention the bug exists up to 1.12
+ (ENDANCHOR): mention the bug exists up to 1.12
+ (dotest_all_in_one): new function for debugging.
+ (dotest_line_by_line): new function for debugging.
+ (dotest_internal_debug): new function for debugging.
+ (dotest_internal): stop emulating the ancient tests and don't spew
+ the dotest.tmp contents onto $LOGFILE -- it's just too much
+ meaningless noise. Only do this if the test fails. Many tests
+ don't use dotest() yet, so this isn't quite so helpful as it might
+ otherwise be.
+ (TODO): mention CVS/* files, especially CVS/Root.
+
+ * main.c (main): add a commented out piece of code to suggest that
+ there should be a function lookup_command_attribute() that could
+ tell us various things about internal commands, such as whether
+ they use CVS/Root, or if they're repository-only, or if they need
+ a working directory, etc....
+ (main): don't set need_to_create_root if command doesn't use a
+ local working directory.
+
+ * patch.c (patch): CLIENT_SUPPORT: send '-f' if NOT force_tag_match
+
+ * error.c (fperror): protect declaration for un-defined __STDC__
+
+ * import.c (import): permit imports to a branch with zero dots,
+ i.e. the trunk.
+ (update_rcs_file): don't detect conflicts if importing to the
+ trunk.
+ (import): add hint that we should allow a module name, instead of
+ just a pathname relative to $CVSROOT.
+ (add_rcs_file): if importing to trunk, do it with ci(1).
+
+ * import.c: XXX the following are all #if 0'ed out until a full
+ implementation can be designed....
+ (cbranch): new variable to support conflict detection on another
+ branch set by -c.
+ (import): truncate -b and -c optarg if to fit in static storage.
+ (import_usage): describe -c
+
+ * rcscmds.c (RCS_checkout): add new argument 'rcsver'. If rcsver
+ is set, turn on 'keywords' to force call to RCS_exec_checkout.
+ * rcs.c (RCS_exec_checkout): add new argument 'rcsver'. Pass
+ 'rcsver' to "co" with run_arg().
+ * cvs.h: (RCS_checkout): add new argument 'rcsver' to prototype.
+ (RCS_exec_checkout): add new argument 'rcsver' to prototype.
+ * commit.c (remove_file): supply new argument to RCS_checkout.
+ * checkin.c (Checkin): supply new argument to RCS_checkout.
+ * diff.c (diff_fileproc): supply new argument to RCS_checkout.
+ (diff_file_nodiff): supply new argument to RCS_checkout.
+ * no_diff.c (No_Difference): supply new argument to RCS_checkout.
+ * update.c (checkout_file): supply new argument to RCS_checkout.
+ (patch_file): supply new argument to RCS_checkout.
+ (join_file): supply new argument to RCS_checkout.
+
+ * patch.c: (o_options): new variable for -K
+ (rcsver): new variable for -V.
+ (patch): add -K flag which sets o_options, change -V to set
+ rcsver, send o_options and rcsver if in client mode.
+ (patch_fileproc): use RCS_checkout instead of RCS_fast_checkout in
+ order to ensure $Name is expanded, use o_options if set, or
+ options if set, or by default "-ko" when getting "old" file.
+
+Sun Sep 29 16:43:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c: Replace comment at top of file concerning RCS library
+ with a reworded version based on discussion between me, Ian, Paul
+ Eggert, and JimB.
+
+Sun Sep 29 13:09:45 1996 Noel Cragg <noel@kiva.rain.org>
+
+ * main.c (main): don't create/update CVS/Root when doing the "cvs
+ login" command. Consider: if the user executes "cvs login" with
+ the working directory inside an already checked out module, we'd
+ incorrectly change the CVS/Root file to reflect the CVSROOT of the
+ "cvs login" command.
+
+ * login.c (login): if we're re-logging into a server for which a
+ .cvspass entry already exists, copy the temporary file to its home
+ location rather than renaming. Renaming doesn't work between
+ filesystems. After copying, unlink the temporary file.
+
+Fri Sep 27 05:24:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c: Add comment about --brief option.
+
+ * README-rm-add: Removed; the information which was here is now in
+ cvs.texinfo.
+ * Makefile.in (DISTFILES): Remove README-rm-add.
+
+Wed Sep 25 10:00:00 1996 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in (cvsbug): Add dependency on version.c.
+
+Wed Sep 25 09:01:48 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (get_homedir), update.c (update): Reindent.
+
+Wed Sep 25 04:44:54 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * version.c (version_string): Bump to 1.8.86.
+
+Wed Sep 25 05:17:50 1996 Jim Blandy <jimb@floss.cyclic.com>
+
+ * update.c (update): Don't neglect to pass the -kmumble options
+ to the server.
+ * sanity.sh (binfiles-sticky): New tests for above.
+
+ * cvsrc.c (read_cvsrc): Deal correctly with lines that specify a
+ command, but no options; don't corrupt argv.
+
+ * sanity.sh: When testing rsh, use the program specified by
+ the CVS_RSH environment variable, if it's set. Move test to top
+ of file, so it runs before all other tests (it's really a
+ meta-test).
+
+ * filesubr.c (get_homedir): Use getpwuid to find the home
+ directory, if the HOME environment variable isn't set.
+ * ignore.c (ign_add_file): Call get_homedir to find the user's
+ home directory; this is more portable than calling getpwuid.
+
+Tue Sep 24 09:08:17 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * log.c (log_tree): When walking through branches, follow the
+ ->prev field rather than following ->next which insures that the
+ loop only executes once and we only see the last branch.
+ * sanity.sh (multibranch): Test "cvs log" too; tests for above fix.
+
+Mon Sep 23 09:55:22 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * options.h.in: Fixed some typos in the comments and reindented
+ them.
+
+Sat Sep 21 02:33:26 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * sanity.sh: If we're testing remote CVS, make sure rsh itself is
+ working before running any tests. It's confusing when basica-1
+ fails just because you don't have the local host in your .rhosts
+ file.
+
+ * version.c (version_string): Bump to 1.8.85.
+
+Thu Sep 19 09:15:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Define SERVER_FLOWCONTROL, SERVER_HI_WATER,
+ SERVER_LO_WATER. Several large sites (FreeBSD, Cygnus) have been
+ pounding on this code without problems, and it doesn't seem to
+ have any significant downsides.
+
+Tue Sep 17 01:13:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * status.c (status_fileproc): Instead of a default case, set sstat
+ before the switch. This way gcc -Wall can detect a missed case.
+ Add explicit T_TITLE case.
+
+Tue Sep 17 00:09:44 1996 Assar Westerlund <assar@pdc.kth.se>
+
+ * login.c (login): Print usage if argc < 0.
+
+Tue Sep 17 00:09:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * lock.c: In comment, mention one more function of readlocks
+ (fileattr not updated atomically). Note similarity between
+ solutions #2 and #5.
+
+ * checkout.c (safe_location): Do not reject a location merely
+ because it textually starts with hardpath; insist that it be
+ hardpath or a subdirectory thereof.
+
+Mon Sep 16 11:46:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (server_cleanup): Add comment about ignoring errors
+ from unlink_file_dir.
+
+Mon Sep 16 10:31:48 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * main.c: Add support for -T <tmpdir> command line option. This
+ is needed for servers started via inetd.
+ (usg): Added line for -T. Improved -z documentation.
+ (main): Read default for tmpdir from the environment. Test for 'T'
+ in getopt loop. Use '/tmp' as ultimative fallback. Update
+ environment if possible.
+
+ * cvs.h (TMPDIR_ENV): Added for -T <tmpdir> command line option.
+
+ * options.h.in: Add TMPDIR_DFLT
+
+ * import.c (update_rcs_file): Use global variable Tmpdir instead
+ of reading the environment.
+
+ * server.c (server_cleanup): Use global variable Tmpdir instead of
+ reading the environment. Also, replace system("rm -rf") with
+ unlink_file_dir.
+ (server): Use global variable Tmpdir instead of reading the
+ environment.
+
+Thu Sep 12 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * main.c (main): If ARGV0_NOT_PROGRAM_NAME, then just set
+ program_name to "cvs" rather than argv[0].
+
+Thu Sep 12 12:06:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (update_entries): If we can't write the file, don't
+ make it a fatal error.
+
+Wed Sep 11 12:46:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_server): Move START_SERVER_RETURNS_SOCKET code
+ so that it is only run for server_method. It is wrong for
+ pserver_method (in which connect_to_pserver sets server_sock).
+
+ * login.c (construct_cvspass_filename): If NO_SLASH_AFTER_HOME,
+ don't put a '/' between $HOME and .cvspass. Reindent function.
+ * build_src.com: Add zlib.c, login.c, and scramble.c.
+
+ * rcs.c (RCS_deltas): When looking for our branch in ->branches,
+ check the branch number.
+ * sanity.sh (multibranch): New tests test for above fix.
+
+ * commit.c (precommit_list_proc): Fix typo in last change
+ (->status to ->type).
+
+Tue Sep 10 23:05:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add build_src.com.
+ * build_src.com: Add buffer.c, buffer.obj, and zlib.olb.
+
+Tue Sep 10 20:35:23 1996 Juergen Renz <renz@conware.de>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (precommit_list_proc): Update to reflect Jul 22 change
+ in which p->data was changed from a Ctype to a struct
+ logfile_info *. This means that commitinfo scripts again get
+ passed the file list like they should.
+
+Tue Sep 10 20:35:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (auth_server_port_number): Change name of service from
+ "cvs" to "cvspserver". The latter is what the manual has always
+ recommended, and it is also officially registered with IANA.
+
+Tue Sep 10 11:12:42 1996 Mark A. Solinski <markso@mcs.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (socket_buffer_output): Change ifdef VMS to ifdef
+ SEND_NEVER_PARTIAL.
+ (start_server): Change ifdef VMS to ifdef START_SERVER_RETURNS_SOCKET.
+
+Tue Sep 10 17:15:21 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * client.c (auth_server_port_number): Look up "cvs" in the
+ services database, and use the value it returns; fall back to
+ CVS_AUTH_PORT if no entry is present.
+ (connect_to_pserver): Use the correct port number in any error
+ messages.
+
+Tue Sep 10 11:12:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (newb): New test newb-123j0 tests for another "cvs
+ status" case.
+
+Sun Sep 8 15:20:37 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_checkout): Clarify handling of options parameter.
+
+ * rcs.c (RCS_checkout): Free buffer allocated by RCS_deltas.
+
+Sat Sep 7 21:28:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (struct cmd): Add comment concerning recognizing unique
+ abbreviations.
+
+Fri Sep 6 22:31:52 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_checkout): Fix indentation.
+
+Fri Sep 6 11:48:08 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_checkout): Replace tag parameter with rev and nametag
+ parameters. Change all callers.
+ * rcs.h (RCS_checkout): Update declaration.
+
+ * rcs.c (RCS_getversion): Replace return_both parameter with
+ simple_tag. Change all callers.
+ (RCS_gettag): Likewise.
+ * rcs.h (RCS_getversion, RCS_gettag): Update declarations.
+ * vers_ts.c (Version_TS): Simplify vn_tag initialization using new
+ simple_tag rather than old return_both.
+ * cvs.h (struct vers_ts): Clarify vn_tag comment a bit.
+
+ * main.c (usg): Only mention -x if ENCRYPTION is defined.
+ (main): Mention ENCRYPTION define in comment for -x.
+ * client.h (krb_encrypt_buffer_initialize): Only declare if
+ ENCRYPTION is defined.
+ * client.c (start_server): Only encrypt if ENCRYPTION is defined.
+ * server.c (serve_kerberos_encrypt): Only define if ENCRYPTION is
+ defined.
+ (requests): Only include Kerberos-encrypt is ENCRYPTION is
+ defined.
+ (krb_encrypt_*): Only define if ENCRYPTION is defined.
+
+Thu Sep 5 17:32:39 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh: When testing remote, use :ext: instead of :server: to
+ match change made earlier today.
+
+Thu Sep 5 13:57:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_tcp_server): Don't allow :kserver: to mean
+ "direct tcp" (root.c already takes care of this, but I want to
+ make it clear what is intended, and not intended, here).
+ (start_server): Handle ext_method (external rsh program) and
+ server_method (internal rsh client) separately.
+ * client.c: Take rsh_pid and start_rsh_server out of
+ RSH_NOT_TRANSPARENT ifdefs. It is useful for things like SSH on NT.
+ * cvs.h (CVSmethod), root.c (method_names): Add ext_method.
+ * root.c (parse_cvsroot): Recognize "ext" access method.
+ If access method is not specified and CVSROOT contains a colon,
+ use either ext_method or server_method depending on
+ RSH_NOT_TRANSPARENT.
+
+Thu Sep 5 00:09:49 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_checkout): Remove flags parameter, which was not
+ serving any useful purpose. Change all callers.
+ * rcscmds.c (RCS_exec_checkout): Likewise.
+
+ * rcscmds.c (RCS_exec_checkout): Rename from RCS_checkout. Change
+ all callers.
+ * rcs.c (RCS_checkout): Rename from RCS_fast_checkout. Change all
+ callers.
+
+Wed Sep 4 14:42:28 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_fast_checkout): If tracing, output a message. If
+ noexec, and workfile is not NULL, just return immediately. Assert
+ that sout is RUN_TTY or workfile is NULL, rather than using it as
+ a conditional. Replace found variable with two variables--gothead
+ and keywords--reflecting what it actually means.
+
+ * rcs.c (RCS_fast_checkout): Don't handle the case of workfile set
+ to "".
+ * rcscmds.c (RCS_checkout): Likewise.
+ * checkin.c (Checkin): Pass explicit file name, not "", to
+ RCS_fast_checkout.
+ * update.c (join_file): Likewise.
+ * commit.c (remove_file): Pass explicit file name to
+ RCS_fast_checkout and RCS_checkin.
+
+ * rcs.c (RCS_reparsercsfile): Always continue after seeing
+ RCSSYMBOLS, even if the value is NULL. Clear the NODELTA flag
+ after setting delta_pos.
+ (free_rcsnode_contents): New static function.
+ (freercsnode): Call free_rcsnode_contents.
+ (RCS_fast_checkout): If NODELTA is set, reparse the RCS file.
+ (RCS_settag): New function. Change all callers to old function.
+ (RCS_deltag, RCS_setbranch): Likewise.
+ (RCS_lock, RCS_unlock): Likewise.
+ (RCS_deltas): If NODELTA is set, reparse the RCS file.
+ * rcs.h (NODELTA): Define.
+ (RCS_settag, RCS_deltag, RCS_setbranch): Declare.
+ (RCS_lock, RCS_unlock): Declare.
+ * rcscmds.c (RCS_exec_settag): Rename from RCS_settag. Don't
+ check tag against BASE or HEAD (now done in new RCS_settag).
+ (RCS_exec_deltag): Rename from RCS_deltag.
+ (RCS_exec_setbranch): Rename from RCS_setbranch.
+ (RCS_exec_lock): Rename from RCS_lock.
+ (RCS_exec_unlock): Rename from RCS_unlock.
+ * cvs.h: Update declarations of renamed functions.
+ * checkin.c (Checkin): Remove rcscopy variable (no longer needed
+ because of change in RCS_unlock call).
+ * commit.c: Include <assert.h>.
+ (remove_file): Update RCSNode path if the file is renamed.
+ (unblockrcs): Change rcs parameter to RCSNode. Change all
+ callers.
+ (fixbranch): Likewise.
+ (lock_RCS): Likewise. Don't call RCS_parsercsfile.
+ (checkaddfile): Update RCSNode path if the file is renamed. After
+ creating a new file, call RCS_parse. When stubbing a branch, use
+ the passed in RCSNode if there is one, rather than calling
+ RCS_Parse. Don't call RCS_Parse again after calling RCS_settag.
+ Free head and magicrev even if RCS_settag fails.
+ * import.c (add_rev): Change rcs parameter to RCSNode. Change all
+ callers.
+ (add_tag): Likewise.
+
+ * rcs.c (RCS_fast_checkout): Amend last patch: if workfile is
+ NULL, but sout is not NULL, use sout in error message.
+
+Wed Sep 4 13:35:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Increment version number to 1.8.8.
+
+ * Version 1.8.7.
+
+Wed Sep 4 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * client.c (send_file_names): Look for the name to send in
+ Entries even if the file doesn't exist; we should send the
+ name as it appears in Entries in the "rm foo; cvs update FOO"
+ case.
+
+Tue Sep 3 20:50:11 1996 William A. Hoffman <hoffman@albirio.crd.ge.com>
+
+ * rcs.c (RCS_fast_checkout): If workfile is NULL, don't try to
+ include it in error message.
+
+Mon Aug 26 12:27:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * mkmodules.c (mkdir_if_needed): Move from here ...
+ * filesubr.c, cvs.h (mkdir_if_needed): ... to here. Have it
+ return a value saying whether the directory was created.
+ * client.c (call_in_directory), edit.c (edit_fileproc): Call it.
+
+Fri Aug 23 19:19:44 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * checkin.c (Checkin): Copy rcs parameter in case it is freed when
+ finfo->rcs is freed.
+
+Fri Aug 23 14:55:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * remove.c (remove_fileproc): Revert change of 23 Aug to print
+ getwd and finfo->file in message. The latter is redundant with
+ fullname and the former is redundant with fullname and the working
+ directory when CVS was invoked. The implementation was also
+ lacking as the getwd call could overflow the buffer.
+
+Fri Aug 23 18:40:35 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * remove.c (cvsremove): fix remove -f for client/server
+
+Fri Aug 23 11:28:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * wrapper.c, cvs.h: Remove conflictHook field of WrapperEntry,
+ WRAP_CONFLICT in WrapMergeHas, and 'c' option in wrap_add; they
+ are never used.
+
+Fri Aug 23 11:41:46 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * server.c (switch_to_user): use #ifdef SETXID_SUPPORT instead of
+ #if SETXID_SUPPORT
+
+Thu Aug 22 14:18:43 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * checkin.c (Checkin): Remove local variable xfinfo. Reparse the
+ RCS file after the checkin. Call RCS_fast_checkout rather than
+ RCS_checkout.
+
+ * cvs.h (RCS_FLAGS_LOCK): Don't define.
+ (RCS_FLAGS_*): Adjust values to fill in hole left by removal of
+ RCS_FLAGS_LOCK.
+ * rcs.c (RCS_fast_checkout): Don't check for RCS_FLAGS_LOCK.
+ * rcscmds.c (RCS_checkout): Likewise.
+ * commit.c (commit_fileproc): Remove rcs local variable. If
+ status is T_MODIFIED, require that finfo->rcs be set, call
+ Lock_RCS directly, and don't call locate_rcs. If adding to a tag,
+ require that finfo->rcs be set, and don't call locate_rcs.
+ (remove_file): Remove rcs local variable. Require that finfo->rcs
+ be set. Don't call locate_rcs. Don't pass RCS_FLAGS_LOCK to
+ RCS_checkout; use RCS_lock instead. Call RCS_fast_checkout rather
+ than RCS_checkout.
+ (unlockrcs): Use a single rcs parameter rather than two parameters
+ for file and repository. Change all callers. Don't call
+ locate_rcs.
+ (fixbranch): Likewise.
+ (lockrcsfile): Remove; no more callers.
+
+Tue Aug 20 10:13:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * buffer.c, rcs.c: Don't use inline. It wasn't being used in a
+ loop or any such place where it would matter for performance, and
+ it was a (minor) portability hassle.
+
+ * server.c (server): Change "Dummy argument 0" to "cvs server" and
+ add comment explaining why.
+
+ * rcs.c (linevector_add): Add comment regarding changing \n to \0.
+
+Tue Aug 20 09:19:19 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * checkout.c (checkout_proc): Call RCS_parse to get the default
+ options from the RCS file.
+
+ * sanity.sh (binfiles): Add tests 5.5b0 and 5.5b1 for the above fix
+
+Mon Aug 19 18:13:32 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (linevector_init): Make inline. Set lines_alloced to 0,
+ not 10. Set vector to NULL.
+ (linevector_add): Remove assertion that lines_alloced is greater
+ than zero. Initialize lines_alloced if necessary.
+ (linevector_copy): Initialize lines_alloced if necessary.
+ (linevector_free): Only free vector if it is not NULL.
+ (RCS_deltas): Always call linevector_init and linevector_free on
+ curlines, headlines, and trunklines.
+ (RCS_fast_checkout): Remove #if 0 around code that calls
+ RCS_deltas.
+
+Fri Aug 16 17:52:54 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (linevector_add): Handle zero length correctly.
+ (RCS_deltas): In RCS_FETCH case, the data is in headlines, not
+ curlines.
+ (RCS_fast_checkout): Update comment about RCS_deltas: the
+ testsuite now passes.
+
+ * rcs.c (RCS_fully_parse): Use the length of the value, rather
+ than assuming that there are no embedded zero bytes.
+ (struct line): Add len field.
+ (linevector_add): Add len parameter. Change all callers. Use
+ len, rather than assuming that there are no embedded zero bytes.
+ Set the len field in new lines.
+ (RCS_deltas): Use the length of the value, rather than assuming
+ that there are no embedded zero bytes. Use the line length when
+ outputting it and when copying it.
+ (RCS_fast_checkout): Update comment about RCS_deltas to remove
+ note about supporting zero bytes correctly.
+
+Thu Aug 15 23:38:48 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c, import.c: Revise comments regarding the fact that we
+ call start_server before do_editor.
+
+Thu Aug 15 11:30:55 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c: Include <sys/socket.h> if AUTH_SERVER_SUPPORT.
+ (pserver_authenticate_connection): Set SO_KEEPALIVE on
+ STDIN_FILENO.
+ (kserver_authenticate_connection): Likewise.
+
+Thu Aug 15 10:26:41 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * server.c (switch_to_user): Fix previous patch to compile it for
+ both HAVE_KERBEROS and AUTH_SERVER_SUPPORT
+
+Wed Aug 14 14:02:00 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * server.c (check_password): if available use getspnam instead of
+ getpwnam when reading system passwords. This allows cvs pserver
+ to run on systems with shadow passwords.
+ (switch_to_user): new static function. Contains the extracted
+ common tail of kserver_authenticate_connection and
+ pserver_authenticate_connection. If compiled with SETXID_SUPPORT,
+ honor the setgid bit if it is set.
+ (check_repository_password): turn into a static function
+ (check_password): ditto
+ (pserver_authenticate_connection): little code cleanup
+
+Wed Aug 14 01:07:10 1996 Greg A. Woods <woods@most.weird.com>
+
+ * history.c (history): apply fix posted by Steven Meyer
+ <steve@blacksmith.com> to info-cvs to correct handling of '-D'
+ argument. Message-Id: <9608122335.AA01385@nijel.blacksmith.com>
+
+Tue Aug 13 13:42:36 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * log.c (cvslog): Remove comment about calling rlog.
+ * rcs.c (translate_symtag): Correct typo in comment (l ist ->
+ list).
+ * server.c (server_write_entries): Add omitted word (lists) in
+ comment.
+
+Tue Aug 13 14:01:49 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * wrapper.c (wrap_rcsoption): fix memory access error
+
+ * rcs.c (RCS_fast_checkout): fix memory access error (triggered
+ by an empty option string)
+
+Mon Aug 12 17:45:15 1996 Jim Kingdon (unknown@beezley)
+
+ * buffer.c, zlib.c: If EIO is not defined, try to define it.
+
+Mon Aug 12 10:33:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c (comtable): Add comment concerning applicability with
+ RCS 5.7.
+
+ * server.c (server): If TMPDIR is not an absolute pathname, give
+ an error.
+
+Mon Aug 12 10:34:43 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * main.c: add synonym "ann" for "annotate" again
+
+Sun Aug 11 17:54:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.h (RCS_RLOG): Removed; no longer used.
+
+Fri Aug 9 20:16:20 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (dirswitch): Open the Entries file with mode "a" rather
+ than "w+".
+ (server_write_entries): Open the Entries file with mode "a" rather
+ than "w".
+ * sanity.sh (modules): Add topfiles module and 155cN tests for
+ above patch.
+
+Fri Aug 9 12:11:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (cmd): Add comment regarding synonyms.
+
+Thu Aug 8 14:40:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c: Remove synonyms for "cvs annotate". Synonyms create
+ user confusion.
+
+Thu Aug 8 10:24:04 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * main.c: Revert (undocumented) change to rename the cvs history
+ alias "his" to "hist"
+
+Wed Aug 7 18:26:25 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (cvs_output): Change str parameter to const char *.
+ Correct loop to print from p, not str.
+ (cvs_outerr): Likewise.
+ * cvs.h (cvs_output, cvs_outerr): Update declarations.
+
+ * server.c (receive_partial_file): Read and discard remaining file
+ data on a write error.
+ (serve_modified): Discard data while size > 0, not >=.
+
+Wed Aug 7 15:11:40 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * main.c (cmds): Add some aliases for "annotate".
+ (usg): Improve usage message text
+ (cmd_synonyms): New function to print the command synonym list
+ (main): Add new option --help-synonyms
+
+Wed Aug 7 00:07:31 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Keep track of subdirectories in the Entries file.
+ * cvs.h (enum ent_type): Define.
+ (struct entnode): Add type field.
+ (struct stickydirtag): Add subdirs field.
+ (Subdirs_Known, Subdir_Register, Subdir_Deregister): Declare.
+ (ignore_files): Update declaration for new parameter.
+ (FILESDONEPROC): Add entries parameter.
+ (DIRENTPROC, DIRLEAVEPROC): Likewise.
+ * entries.c (Entnode_Create): Add type parameter. Change all
+ callers.
+ (write_ent_proc): If closure is not NULL, treat it as a pointer to
+ an int, and set it to 1 if a node is seen which is not ENT_FILE.
+ (write_entries): If subdirectory information is known, but no
+ subdirectories were written, write an unadorned D to the file.
+ (Scratch_Entry): Write an R command to Entries.Log. Don't rewrite
+ the Entries file.
+ (Register): Set entfilename. Write an A command rather than an
+ unadorned entries line.
+ (fgetentent): Add cmd and sawdir parameters. Change all callers.
+ If CMD is not NULL, expect and return a single character command.
+ Handle an initial D by setting the type to ENT_SUBDIR.
+ (fputentent): Output an initial D for an ENT_SUBDIR entry.
+ (Entries_Open): Handle removal commands in Entries.Log. Record
+ whether subdirectory information is known in the list private
+ data.
+ (Subdirs_Known): New function.
+ (subdir_record): New static function.
+ (Subdir_Register, Subdir_Deregister): New functions.
+ * find_names.c (add_entries_proc): Skip entries that are not
+ ENT_FILE.
+ (add_subdir_proc): New static function.
+ (register_subdir_proc): New static function.
+ (Find_Directories): If the Entries file has subdirectory
+ information, get the directories out of it. Otherwise, call
+ find_dirs, and add the information to the Entries file.
+ * recurse.c (struct frame_and_entries): Define.
+ (do_recursion): Don't call Entries_Close until after processing
+ dirlist. Pass entries to filesdoneproc. Pass a frame_and_entries
+ structure to do_dir_proc via walklist.
+ (do_dir_proc): Expect a frame_and_entries structure in closure,
+ not a recursion_frame. Pass entries to direntproc and
+ dirleaveproc.
+ * ignore.c (ignore_files): Add entries parameter. Change all
+ callers. If we have subdirectory information, check for
+ directories in entries.
+ * add.c (add): If client_active, call Subdir_Register on each new
+ directory.
+ (add_directory): Add entries parameter. Change caller. Call
+ Subdir_Register.
+ * checkout.c (build_dirs_and_chdir): Call Subdir_Register.
+ * client.c (call_in_directory): Call Subdir_Register for newly
+ created directories. Call Subdirs_Known or Find_Directories after
+ calling Entries_Open.
+ (process_prune_candidates): Call Subdir_Deregister.
+ * commit.c (findmaxrev): Skip entries that are not ENT_FILE.
+ * server.c (dirswitch): Call Subdir_Register.
+ * update.c (update_dirent_proc): Call Subdir_Register.
+ (update_dirleave_proc): Call Subdir_Deregister.
+ * Several files: Change direntproc, dirleaveproc, and
+ filesdoneproc routines to expect an entries argument.
+
+ * rcs.c (translate_symtag): New static function.
+ (RCS_gettag): Use translate_symtag rather than RCS_symbols.
+ (RCS_nodeisbranch, RCS_whatbranch): Likewise.
+
+Tue Aug 6 15:36:09 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Finish the conversion of cvs log so that it never invokes rlog.
+ * log.c (struct log_data): Remove dorlog field. Add nameonly,
+ header, long_header, statelist, and authorlist fields.
+ (log_usage): Remove rlog-options. Add -R, -h, -t, -b, -s, -w.
+ (cvslog): Don't clear opterr. Handle -h, -R, -s, -t, -w. If an
+ unrecognized option is seen, call usage.
+ (log_parse_list): New static function.
+ (log_fileproc): Remove code that called rlog. Check nameonly,
+ header, and long_header fields in log_data.
+ (log_version_requested): Check statelist and authorlist.
+
+ * log.c (struct datelist): Define.
+ (struct log_data): Add datelist and singledatelist fields.
+ (log_usage): Add -d.
+ (cvslog): Handle -d.
+ (log_parse_date): New static function.
+ (log_fileproc): Do special single date handling.
+ (log_version_requested): Check datelist and singledatelist.
+ (log_fix_singledate): New static function.
+
+Mon Aug 5 23:48:16 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * log.c (struct option_revlist): Define.
+ (struct revlist): Define.
+ (struct log_data): Add default_branch and revlist fields.
+ (struct log_data_and_rcs): Define.
+ (log_usage): Add -N and -r.
+ (cvslog): Handle -N and -r.
+ (log_parse_revlist): New static function.
+ (log_fileproc): Call log_expand_revlist and log_free_revlist.
+ Pass log_data_and_rcs structure to log_count_print via walklist.
+ (log_expand_revlist, log_free_revlist): New static functions.
+ (log_version_requested): New static function.
+ (log_count_print): New static function.
+ (log_tree): Add log_data and revlist parameter. Change all
+ callers.
+ (log_abranch): Likewise.
+ (log_version): Likewise. Call log_version_requested.
+ (version_compare): New static function.
+ * sanity.sh (log): New tests for -r, -b, and -N options to log.
+
+Sun Aug 4 11:19:30 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Handle simple cases of cvs log without invoking rlog.
+ * log.c (struct log_data): Define.
+ (cvslog): Use getopt to parse options. Set up a log_data
+ structure, and pass it to start_recursion.
+ (log_fileproc): Get arguments form callerdat rather than static
+ variables. In simple cases, print the log information directly,
+ rather than invoking rlog.
+ (log_symbol, log_count, log_tree): New static functions.
+ (log_abranch, log_version, log_branch): New static functions.
+ * rcs.h (struct rcsnode): Add other field.
+ (struct rcsversnode): Add other field.
+ (RCS_fully_parse): Declare.
+ * rcs.c (getrcsrev): Move declaration to start of file.
+ (RCS_reparsercsfile): Add all parameter. Change all callers.
+ (RCS_fully_parse): New function.
+ (freercsnode): Free other list.
+ (rcsvers_delproc): Free other list.
+ * hash.h (enum ntype): Add RCSFIELD.
+ * hash.c (nodetypestring): Handle RCSFIELD.
+
+Sat Aug 3 19:39:54 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * log.c (cvslog): Correct position of CLIENT_SUPPORT #endif.
+
+Thu Jul 25 12:06:45 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (join_file): If merging a branch, and the branch
+ revision does not exist, just return without doing anything.
+ * sanity.sh (join): Add cases file7 and file8 to test above
+ patch.
+
+ * server.c (cvsencrypt): Rename from encrypt, to avoid conflict
+ with NetBSD unistd.h. Rename all uses.
+
+ * server.c (krb_encrypt_buffer_output): Fix typo in comment (reply
+ -> replay).
+
+Thu Jul 25 10:37:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (krb_encrypt_buffer_output): Fix typo in comment
+ (krb_recv_auth -> krb_recvauth).
+
+Wed Jul 24 09:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * lock.c (set_lock): Adjust comment regarding why we call stat.
+
+Wed Jul 24 15:06:08 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Add encryption support over a Kerberos connection.
+ * main.c (usg): Mention -x if CLIENT_SUPPORT.
+ (main): Handle -x.
+ * client.h (encrypt): Declare.
+ (krb_encrypt_buffer_initialize): Declare.
+ * client.c (kblock, sched): New static variables if
+ HAVE_KERBEROS.
+ (start_tcp_server): Remove sched local variable. Copy
+ cred.session into kblock.
+ (start_server): Turn on encryption if requested.
+ * server.c (kblock, sched): New static variables if
+ HAVE_KERBEROS.
+ (serve_kerberos_encrypt): New static function.
+ (requests): Add "Kerberos-encrypt" if HAVE_KERBEROS.
+ (kserver_authenticate_connection): Remove sched local variable.
+ Copy auth.session into kblock.
+ (encrypt): New global variable.
+ (struct krb_encrypt_buffer): Define.
+ (krb_encrypt_buffer_initialize): New function.
+ (krb_encrypt_buffer_input): New static function.
+ (krb_encrypt_buffer_output): New static function.
+ (krb_encrypt_buffer_flush): New static function.
+ (krb_encrypt_buffer_block): New static function.
+ (krb_encrypt_buffer_shutdown): New static function.
+
+Wed Jul 24 09:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_recursion): Add comment about calling
+ Name_Repository in !(which & W_LOCAL) case.
+
+ * expand_path.c (expand_variable): Fix typo (varaible -> variable).
+
+Tue Jul 23 15:05:01 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (update_fileproc): In T_REMOVE_ENTRY case, only call
+ server_scratch_entry_only if ts_user is NULL.
+ * sanity.sh (death2): Add death2-20 test for above patch.
+
+ * diff.c (diff_fileproc): If a file is not in the working
+ directory, check that the tag is present before warning that no
+ comparison is possible.
+ * sanity.sh (death2): Add death2-diff-9 and death2-diff-10 tests
+ for above patch.
+
+Tue Jul 23 12:05:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * tag.c (tag_check_valid): Fix indentation.
+
+ * client.c (handle_e): Flush stdout before writing to stderr.
+ (handle_m): Flush stderr before writing to stdout.
+
+Fri Jul 19 16:02:11 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * client.c: Added NO_CLIENT_GZIP_PROCESS to deal with the MacOS
+ client where Gzip-stream is supported, but "gzip-file-contents" is
+ not.
+
+Fri Jul 19 16:02:11 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * repos.c: Fixed recent patch which added plain fopen rather than
+ CVS_FOPEN
+
+Mon Jul 22 22:25:53 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * logmsg.c (tag): New static variable.
+ (setup_tmpfile): Don't print the prefix before calling fmt_proc.
+ Free tag if it is set.
+ (find_type): Get type from logfile_info struct.
+ (fmt_proc): Likewise. Print tag information. Handle all prefix
+ printing.
+ (revision): Remove static variable.
+ (Update_Logfile): Remove xrevision parameter. Change all
+ callers.
+ (title_proc): Get type from logfile_info struct.
+ (logfile_write): Remove revision parameter. Change all callers.
+ * cvs.h (struct logfile_info): Define.
+ (Update_Logfile): Update prototype.
+ * commit.c (find_fileproc): Set logfile_info information.
+ (check_fileproc): Likewise.
+ (commit_filesdoneproc): Don't call ParseTag.
+ (update_delproc): Free logfile_info information.
+ * add.c (add_directory): Set logfile_info information.
+ * import.c (import): Likewise.
+
+ * tag.c (tag_check_valid): The special BASE and HEAD tags are
+ always valid.
+ * sanity.sh (basica): Add basica-6.3 test for above patch.
+
+Mon Jul 22 14:41:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (merge_file): Pass 0 not NULL to checkout_file (20 Jul
+ 96 change changed other calls to checkout_file but missed this one).
+
+Sat Jul 20 00:21:54 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (join_file): Check whether the target of the merge is
+ the same as the working file revision before checking whether the
+ file was added during the merge.
+
+ * update.c (scratch_file): Remove existing parameters, and add a
+ single parameter of type struct file_info. Change all callers.
+ Warn if unlink_file fails.
+ (checkout_file): Remove resurrecting_out parameter. Add adding
+ parameter. Change all callers. Remove joining code.
+ (join_file): Remove resurrecting parameter. Rewrite to handle
+ joining dead or added revisions.
+ * classify.c (Classify_File): If there is no user file, and the
+ RCS file is dead, return T_UPTODATE rather than T_CHECKOUT.
+ * checkout.c (checkout_proc): Set W_ATTIC if there is a join tag.
+ * sanity.sh (join): New set of tests for above patches.
+ (death): Adjust tests 86, 89, 89a, 92.1c, 95 for above patches.
+ (import): Adjust test 113 for above patches.
+
+Thu Jul 18 19:24:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * lock.c: Add comment explaining what locks are for. Also discuss
+ various changes to locking which get proposed from time to time.
+
+ * sanity.sh (death2): Change a number of test names from death-*
+ to death2-*.
+
+ * wrapper.c (wrap_setup): Don't look in repository if client_active.
+ * wrapper.c, cvs.h (wrap_send): New function.
+ * update.c (update), import.c (import): Call it.
+ * sanity.sh (binwrap): Do binwrap tests for remote as well as
+ local; tests for above fixes.
+
+ * wrapper.c: Add a few FIXME comments.
+
+Thu Jul 18 18:43:50 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (patch): Fix names of a couple of tests to say patch
+ rather than death2.
+
+Thu Jul 18 16:19:21 1996 Bill Bumgarner <bbum@friday.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add), import.c (add_rcs_file): Check for options from
+ wrappers and use them if specified.
+ * cvs.h (WrapMergeHas): Add WRAP_RCSOPTION.
+ * wrapper.c (WrapperEntry): Add rcsOption field.
+ (wrap_add): Allow a single character argument to an option.
+ (wrap_add): Handle -k option.
+ (wrap_add_entry): Handle rcsOption field.
+ (wrap_name_has): Handle WRAP_RCSOPTION.
+ * wrapper.c, cvs.h (wrap_rcsoption): New function.
+ * add.c, import.c, wrapper.c: Minor beautification (mostly
+ removing trailing spaces).
+ * sanity.sh (binwrap): New tests test for this feature.
+
+Wed Jul 17 10:14:20 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * checkout.c (checkout): Remove extraneous else accidentally
+ inserted in last checkin.
+
+Tue Jul 16 11:37:41 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (import): Use quoting to avoid expansion of RCS ID
+ strings.
+
+ * sanity.sh (import): Use dotest to examine the output of test
+ 113, and the actual contents of the file in test 116.
+
+ * update.c (join_file): Always skip rcsmerge if the two revisions
+ are the same (the old code always did the rcsmerge when two -j
+ options were specified).
+
+ * checkout.c (history_name): New static variable.
+ (checkout): Permit both tag and date to be specified. Set
+ history_name.
+ (checkout_proc): Use history_name when calling history_write.
+ * rcs.c (RCS_getversion): If both tag and date are set, use
+ RCS_whatbranch to get the branch revision number of a symbolic
+ tag.
+ (RCS_getdatebranch): If the branch revision itself is early
+ enough, then use it if the first branch is not early enough. Add
+ comment for invalid RCS file. Don't bother to check for NULL
+ before calling xstrdup, since xstrdup checks anyhow.
+
+ * client.h (file_gzip_level): Declare.
+ * client.c (file_gzip_level): Define.
+ (start_server): Don't set gzip_level to zero after sending
+ Gzip-stream command. Set file_gzip_level after sending
+ gzip-file-contents command.
+ (send_modified): Use file_gzip_level rather than gzip_level.
+ * server.c (server_updated): Likewise.
+ (serve_gzip_contents): Likewise.
+
+ * sanity.sh (patch): New tests. Test remote CVS handling of
+ unpatchable files.
+
+ * sanity.sh (death2): Accept a '.' in the temporary file name
+ printed by diff.
+
+ * rcscmds.c (RCS_checkin): Remove noerr parameter. Change all
+ callers.
+ * cvs.h (RCS_checkin): Update declaration.
+ * commit.c (remove_file): Pass RCS_FLAGS_QUIET to RCS_checkin.
+
+ * history.c (history): Cast sizeof to int to use correct type in
+ error printf string.
+ (report_hrecs): Cast strlen result to int to use correct type in
+ printf string.
+
+ * server.c (cvs_flusherr): Correct typo in comment.
+
+ * rcs.c (getrcskey): Hoist three constant strcmp calls out of the
+ value reading loop.
+
+ * fileattr.c (fileattr_get): Change parameter types from char * to
+ const char *.
+ (fileattr_get0, fileattr_modify, fileattr_set): Likewise.
+ (fileattr_newfile): Likewise.
+ * fileattr.h (fileattr_get): Update declaration.
+ (fileattr_get0, fileattr_modify, fileattr_set): Likewise.
+ (fileattr_newfile): Likewise.
+
+Thu May 16 11:12:18 1996 Mark P. Immel <immel@radix.net>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.h, client.c, checkout.c (client_send_expansions):
+ Pass an additional parameter indicating where the checkout is
+ to occur, to avoid passing the wrong information to send_files().
+ * sanity.sh (basicb): New test basicb-cod-1 tests for above fix.
+
+Mon Jul 15 18:26:56 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * recurse.c (do_recursion): Require a repository before calling
+ Find_Names.
+ * repos.c (Name_Repository): Remove sanity checks which spend time
+ examining the filesystem.
+
+Mon Jul 15 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * client.c (send_file_names): Send file names as they appear
+ in CVS/Entries, rather than as specified (in cases where they
+ might differ in case).
+ (send_fileproc): Use file name from CVS/Entries (vers->entdata->user)
+ rather than file name as specified (finfo->file) when available.
+
+Sun Jul 14 15:39:44 1996 Mark Eichin <eichin@cygnus.com>
+ and Ian Lance Taylor <ian@cygnus.com>
+
+ Improve diff -N handling of nonexistent tags and removed files.
+ * diff.c (enum diff_file): New definition for whole file, moving
+ unnamed enum out of diff_fileproc, renaming DIFF_NEITHER to
+ DIFF_DIFFERENT, and adding DIFF_SAME.
+ (diff): Look through the repository even if only one revision is
+ given.
+ (diff_fileproc): Change empty_file to be enum diff_file. If there
+ is no user revision, but there is a repository file, treat it as a
+ removed file. Pass empty_file to diff_file_nodiff, and set it
+ from the return value.
+ (diff_file_nodiff): Change return type to enum diff_file. Replace
+ just_set_rev parameter with enum diff_file empty_file parameter.
+ Change handling of a missing tag to return an enum diff_file value
+ if empty_files is set, rather than reporting an error. Free tmp
+ if xcmp returns 0.
+ * sanity.sh (death2): Add tests for above patches.
+
+Sat Jul 13 19:11:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (annotate): In sending options to server, reverse sense of
+ test so that we send -f iff -f was specified, rather than iff -f was
+ not specified.
+
+Fri Jul 12 20:23:54 1996 Greg A. Woods <woods@most.weird.com>
+
+ * zlib.c (compress_buffer_input): add a couple of casts for
+ uses of z_stream's next_in and next_out
+
+Fri Jul 12 18:55:26 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * zlib.c: New file.
+ * client.c (log_buffer_block): Call set_block and set_nonblock,
+ rather than lb->buf->block.
+ (log_buffer_shutdown): New static function.
+ (get_responses_and_close): Call buf_shutdown on to_server and
+ from_server.
+ (start_server): If "Gzip-stream" is supported, use it rather than
+ "gzip-file-contents".
+ * server.c (print_error): Call buf_flush rather than
+ buf_send_output.
+ (print_pending_error, serve_valid_responses): Likewise.
+ (serve_expand_modules, serve_valid_requests): Likewise.
+ (do_cvs_command): Call buf_flush rather than buf_send_output
+ before the fork, and in the parent after the child has completed.
+ In the child, set buf_to_net and buf_from_net to NULL.
+ (serve_gzip_stream): New static function.
+ (requests): Add "Gzip-stream".
+ (server_cleanup): Don't do anything with buf_to_net if it is
+ NULL. Call buf_flush rather than buf_send_output. Call
+ buf_shutdown on buf_to_net and buf_from_net. Call error for an
+ malloc failure rather than buf_output to buf_to_net.
+ * buffer.h (struct buffer): Add shutdown field.
+ (buf_initialize): Update declaration for new shutdown parameter.
+ (compress_buffer_initialize): Declare.
+ (buf_shutdown): Declare.
+ * buffer.c (buf_initialize): Add shutdown parameter. Change all
+ callers.
+ (buf_shutdown): New function.
+ * Makefile.in (SOURCES): Add zlib.c
+ (OBJECTS): Add zlib.o.
+ ($(PROGS)): Depend upon ../zlib/libz.a.
+ (cvs): Link against ../zlib/libz.a.
+ (zlib.o): New target.
+
+Fri Jul 12 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * client.c (log_buffer_input, log_buffer_output): Use size_t
+ to avoid Visual C++ signed/unsigned warnings.
+
+Thu Jul 11 22:01:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (handle_f): Reindent.
+
+ * client.c (mode_to_string, handle_m, handle_e,
+ auth_server_port_number, get_responses_and_close), server.c
+ (pserver_authenticate_connection, serve_modified,
+ serve_enable_unchanged, wait_sig, server_cleanup): Reindent.
+ * server.c: Remove #if 0'd block of code above
+ check_repository_password; it was yanked out of some unknown
+ context and didn't seem to be very useful.
+
+Thu Jul 11 20:10:21 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (do_cvs_command): Pass new special parameter to
+ buf_copy_counted. If it gets set to -1, send an 'F' response if
+ the client supports it, and call cvs_flusherr.
+ (cvs_flusherr): New function.
+ * cvs.h (cvs_flusherr): Declare.
+ * client.c (handle_f): New static function.
+ (responses): Add "F".
+ * buffer.c (buf_send_special_count): New function.
+ (buf_copy_counted): Add special parameter. Handle negative counts
+ specially.
+ * buffer.h (buf_send_sepcial_count): Declare.
+ (buf_copy_counted): Update declaration.
+ * lock.c (lock_wait, lock_obtained): Call cvs_flusherr.
+
+ Change the client to use the buffer data structure.
+ * client.c: Include "buffer.h".
+ (to_server): Change to be struct buffer *.
+ (to_server_fp): New static variable.
+ (from_server): Change to be struct buffer *.
+ (from_server_fp): New static variable.
+ (from_server_logfile, to_server_logfile): Remove.
+ (buf_memory_error): New static function.
+ (struct log_buffer): Define.
+ (log_buffer_initialize, log_buffer_input): New static functions.
+ (log_buffer_output, log_buffer_flush): New static functions.
+ (log_buffer_block): New static function.
+ (struct socket_buffer): Define if NO_SOCKET_TO_FD.
+ (socket_buffer_initialize): New static function if
+ NO_SOCKET_TO_FD.
+ (socket_buffer_input, socket_buffer_output): Likewise.
+ (socket_buffer_flush): Likewise.
+ (read_line): Rewrite to use buf_read_line. Remove eof_ok
+ parameter (it was always passed as 0); change all callers.
+ (send_to_server): Rewrite to use buf_output.
+ (try_read_from_server): Rewrite to use buf_read_data.
+ (get_responses_and_close): Use from_server_fp and to_server_fp for
+ the streams. Check buf_empty_p when checking for dying gasps.
+ (start_server): Don't set from_server_logfile and
+ to_server_logfile; instead, call log_buffer_initialize. If
+ NO_SOCKET_TO_FD and use_socket_style, call
+ socket_buffer_initialize; otherwise, call
+ stdio_buffer_initialize.
+ * buffer.c: Compile if CLIENT_SUPPORT is defined.
+ (buf_flush): Fix comment to describe return value.
+ (buf_read_line): Add lenp parameter. Change all callers. Look
+ for a line terminated by \012 rather than \n.
+ * buffer.h: Compile if CLIENT_SUPPORT is defined.
+ (buf_read_line): Update declaration.
+
+ * server.c (server): Initialize buf_to_net, buf_from_net,
+ saved_output, and saved_outerr before setting error_use_protocol.
+ (pserver_authenticate_connection): Don't set error_use_protocol.
+ Errors before the authentication is complete aren't handled
+ cleanly anyhow. Change error call after authentication to use
+ printf.
+
+Thu Jul 11 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * client.c (start_server): Open logfiles in binary, not text, mode.
+
+Wed Jul 10 19:24:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (print_pending_error, print_error): Remove comments
+ about deadlocks; they don't apply here. Add comments saying
+ that these functions must only be called when it is OK to
+ send output (which is why the deadlock concern doesn't apply). The
+ comments remain for server_cleanup and serve_valid_responses,
+ where they are an example of the "print a message and exit"
+ behavior which is noted in cvsclient.texi and which also exists
+ places like kserver_authenticate_connection.
+
+Wed Jul 10 18:24:46 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (print_error): Add comment warning about potential
+ deadlock.
+ (print_pending_error, serve_valid_responses): Likewise.
+ (server_cleanup): Likewise.
+ (serve_directory): Don't call buf_send_output.
+ (serve_modified, serve_notify, server, cvs_outerr): Likewise.
+ (serve_expand_modules): Call buf_send_output.
+ (serve_valid_requests): Likewise.
+
+Wed Jul 10 15:51:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Print a warning for rlog command.
+
+Wed Jul 10 15:00:55 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Abstract the buffer data structure away from the underlying
+ communication medium.
+ * buffer.h (struct buffer): Remove fd and output fields. Add
+ input, output, flush, block, and closure fields.
+ (buf_initialize, buf_nonio_initialize): Declare.
+ (stdio_buffer_initialize, buf_flush): Declare.
+ (buf_read_line, buf_read_data): Declare.
+ * buffer.c: Include <assert.h>. Don't include <fcntl.h>.
+ (O_NONBLOCK, blocking_error): Don't define.
+ (buf_initialize, buf_nonio_initialize): New functions.
+ (buf_send_output): Use output function, rather than write.
+ (buf_flush): New function.
+ (set_nonblock, set_block): Use block function, rather than calling
+ fcntl.
+ (buf_send_counted): Don't check output.
+ (buf_input_data): Call input function, rather than read.
+ (buf_read_line, buf_read_data): New functions.
+ (buf_copy_lines, buf_copy_counted): Don't check output.
+ (stdio_buffer_initialize): New function.
+ (stdio_buffer_input, stdio_buffer_output): New static functions.
+ (stdio_bufer_flush): New static function.
+ * server.c: Include "getline.h".
+ (buf_to_net): Change to be a pointer. Change all uses.
+ (protocol, saved_output, saved_outerr): Likewise.
+ (buf_from_net): New static variable.
+ (no_mem_error, NO_MEM_ERROR, read_line): Remove.
+ (struct fd_buffer): Define.
+ (fd_buffer_initialize, fd_buffer_input): New static functions.
+ (fd_buffer_output, fd_buffer_flush): New static functions.
+ (fd_buffer_block): New static function.
+ (serve_directory): Call buf_read_line rather than read_line.
+ (serve_notify, server): Likewise.
+ (receive_partial_file): Call buf_read_data rather than fread.
+ (serve_modified): Call buf_read_line rather than read_line. Call
+ buf_read_data rather than fread.
+ (do_cvs_command): Initialize buffers with fd_buffer_initialize.
+ Change stdoutbuf, stderrbuf, and protocol_inbuf to be pointers.
+ (server): Initialize buffers using fd_buffer_initialize,
+ stdio_buffer_initialize, and buf_nonio_initialize.
+ (check_repository_password): Call getline rather than read_line.
+
+Wed Jul 10 15:51:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (find_fileproc): Add comments describing a few cases
+ that we aren't handling.
+
+Tue Jul 9 04:33:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_deltas): New function, created from guts of old
+ annotate_fileproc.
+ (annotate_fileproc): Call RCS_deltas.
+ (RCS_fast_checkout): Call it (commented out for now; see comment
+ for reasons).
+
+ * cvs.h, recurse.c (start_recursion): Add callerdat argument.
+ * cvs.h: Add callerdat argument to recursion processor callbacks.
+ * recurse.c: add it to struct recursion_frame and pass it to all
+ the callbacks.
+ * admin.c, client.c, commit.c, diff.c, edit.c, lock.c, log.c,
+ patch.c, rcs.c, remove.c, rtag.c, status.c, tag.c, update.c,
+ watch.c: Update all the functions used as callbacks. Update calls
+ to start_recursion.
+ * commit.c (find_filesdoneproc, find_fileproc, find_dirent_proc,
+ commit), tag.c (val_fileproc, tag_check_valid): Use callerdat
+ instead of a static variable.
+
+ * recurse.c (do_recursion): Make static and move declaration to here...
+ * cvs.h: ...from here.
+ * recurse.c (do_recursion): Replace plethora of arguments with
+ single struct recursion_frame *. Change callers.
+ * recurse.c: New structure frame_and_file. Use it and existing
+ struct recursion_frame structures to pass info to do_file_proc and
+ do_dir_proc. Remove globals fileproc, filesdoneproc, direntproc,
+ dirleaveproc, which, flags, aflag, readlock, and dosrcs.
+
+Tue Jul 9 11:13:29 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * modules.c (do_module): Call cvs_outerr rather than fprintf.
+
+Mon Jul 8 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * rcs.c (RCS_fast_checkout): If -kb is not in use, open the
+ working file in text, not binary, mode.
+
+Sun Jul 7 10:36:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c (RCS_settag): Add comment regarding moving check for
+ reserved tag names to RCS_check_tag.
+
+ * rcscmds.c: Add comment regarding librarifying RCS and related
+ issues. This is a lightly edited version of a message I sent to
+ the CVS developers and didn't get flamed for, so it would appear
+ to be relatively uncontroversial.
+
+ * rcs.c (annotate): Remove comment suggesting -r option and
+ related functionality; it is done.
+
+Fri Jul 5 17:19:57 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (last_entries): Make file static, rather than function
+ static within call_in_directory.
+ (get_responses_and_close): If last_entries is not NULL, pass it to
+ Entries_Close.
+
+ * server.c (server_pause_check): Check for errors when reading
+ from flowcontrol_pipe.
+
+ * client.c (call_in_directory): If dir_name is ".", call
+ Create_Admin if there is no CVS directory.
+ (send_dirent_proc): If there is no CVS subdirectory, pretend that
+ the directory does not exist (i.e., don't try to send any files in
+ the directory).
+ * server.c (dirswitch): If dir is "." in the top level repository,
+ add "/." after the Repository entry.
+ * sanity.sh (modules): Add test 155b for above patches.
+
+Thu Jul 4 15:57:34 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (buf_to_net): Move definition near top of file.
+ (read_line): Call buf_send_output rather than fflush.
+ (print_error): Output information to buf_to_net buffer rather than
+ stdout.
+ (print_pending_error, serve_valid_responses): Likewise.
+ (server_notify, do_cvs_command, server_co): Likewise.
+ (expand_proc, serve_expand_modules, server_prog): Likewise.
+ (serve_valid_requests, server_cleanup, server): Likewise.
+ (server_notify): Don't call fflush on stdout.
+ (do_cvs_command): Flush saved_output and saved_outerr to
+ buf_to_net before fork. Flush buf_to_net before fork. In child,
+ just initialize memory_error field of saved_output and
+ saved_outerr.
+ (server_cleanup): Flush buf_to_net.
+ (server): Initialize saved_output and saved_outerr.
+ (cvs_output): Add support for error_use_protocol case.
+ (cvs_outerr): Likewise.
+ * error.c (error): In HAVE_VPRINTF case, just call cvs_outerr.
+
+ * buffer.c: New file; buffer support functions taken from
+ server.c.
+ * buffer.h: New file; declarations for buffer.c.
+ * server.c: Move buffer support functions into buffer.c and
+ buffer.h. Include "buffer.h".
+ * Makefile.in (SOURCES): Add buffer.c.
+ (OBJECTS): Add buffer.o.
+ (HEADERS): Add buffer.h.
+
+Thu Jul 4 00:12:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Increment version number to 1.8.6.
+
+Wed Jul 3 22:31:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Version 1.8.5.
+
+Wed Jul 3 21:51:23 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (blocking_error): Define macro.
+ (buf_send_output, buf_input_data): Use blocking_error rather than
+ #ifdef EWOULDBLOCK.
+
+Tue Jul 2 20:38:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add): Change message which said "version 1.2 of foo.c
+ will be resurrected"; the message was confusing because it made
+ people think that the old contents of the file would come back
+ instead of the contents in the working directory.
+
+Mon Jul 1 01:38:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * find_names.c (find_dirs): Add comment explaining why we bother
+ with the entries stuff.
+
+Sat Jun 29 20:23:50 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * find_names.c (Find_Directories): Add entries parameter, and pass
+ it to find_dirs.
+ (find_dirs): Add entries parameter, and skip all files it names.
+ * cvs.h (Find_Directories): Update declaration.
+ * recurse.c (start_recursion): Pass NULL to Find_Directories.
+ (do_recursion): Pass entries to Find_Directories.
+
+ * client.c (send_modified): Add trace output.
+
+ * diff.c (diff_fileproc): Always call diff_file_nodiff. Handle
+ dead versions correctly. Handle diffs between a specified
+ revision to a dead file correctly.
+ (diff_file_nodiff): Add just_set_rev parameter. Change caller.
+ * patch.c (patch_fileproc): Check for dead versions.
+ * sanity.sh (death2): Add tests for above patches.
+
+Fri Jun 28 20:30:48 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ For reference, this takes CVS's text segment from 271136 bytes to
+ 270352 bytes, a saving of 784. Not as good as I had hoped (oh well,
+ the source *seems* simpler at least).
+ * checkin.c (Checkin), commit.c (finaladd, remove_file), update.c
+ (join_file, checkout_file, patch_file), no_diff.c
+ (No_Differences), server.c (server_updated), classify.c
+ (Classify_File), vers_ts.c (Version_TS), diff.c (diff_file_nodiff):
+ Use a single struct file_info * argument instead of a bunch of
+ separate arguments for each of its fields. Remove local fullname
+ emulations. Use fullname in error messages where file had
+ erroneously been used.
+ * cvs.h: Update declarations of above functions and move them to
+ after the struct file_info declaration.
+ * server.h: Update declarations.
+ * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c,
+ commit.c, diff.c, history.c, import.c, update.c, status.c,
+ remove.c, rtag.c, tag.c: Change callers.
+
+ * diff.c (diff): Remove -q and -Q command options. This somehow
+ slipped through the cracks of the general removal of -q and -Q
+ command options on Jul 21 1995. Note that there is no need to
+ accept and ignore these options in server mode, like there is for
+ some of the commands, because the client has never sent -q and -Q
+ command options for "cvs diff".
+
+Fri Jun 28 16:50:18 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * add.c (add): Pass force_tag_match as 1 when calling Version_TS.
+ * sanity.sh (death2): Add test for above patch. Also add
+ commented out test for adding a file on a nonbranch tag, which CVS
+ currently, mistakenly, permits.
+
+Thu Jun 27 23:20:49 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (longopts): New static array.
+ (diff): Handle long options and new short options in diff 2.7.
+ Fix arbitrary limit associated with the tmp variable.
+ * client.c (send_option_string): Parse options as space separated,
+ rather than requiring all options to be single characters.
+ * diff.c, options.h.in: Remove CVS_DIFFDATE; the need for it is gone
+ now that we have --ifdef (the new behavior is the behavior which
+ was the default, which is that -D specifies a date).
+
+Wed Jun 26 22:36:29 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * commit.c (check_fileproc): If there is a tag, permit adding a
+ file even if the RCS file already exists.
+ (checkaddfile): If there is a tag, use the file in the regular
+ repository, rather than the Attic, if it exists.
+ * sanity.sh (death2): New set of tests for above patch.
+
+Tue Jun 25 23:34:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (checkout_file): Add comments about two cases which
+ seem fishy.
+
+ * sanity.sh (basic2, death): Add comments encouraging people to
+ stop making these sections bigger and more complex. I'm not (yet
+ at least) trying to figure out the ideal size for a section (my
+ current best estimate is 10-20 tests), but surely these
+ two sections are pushing the limit, whatever it is.
+
+Tue Jun 25 19:52:02 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (checkout_file): Rewrite handling of dead files when
+ joining. Avoid space leaks. Avoid unnecessary file
+ resurrections.
+ (join_file): Add checks to skip merging a dead revision onto a
+ dead revision, and to skip merging a common ancestor onto a dead
+ revision. Move check for non-existent working file after new
+ checks.
+ * sanity.sh (death): Use dotest for tests 86 and 95, and add test
+ death-file2-1, to test above changes.
+
+Mon Jun 24 11:27:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (merge_file): Replace file, repository, entries, and
+ update_dir arguments with finfo argument. Use fullname field
+ instead of locally emulating it.
+ (update_fileproc): Update caller.
+ (merge_file): If -kb is in effect, call it a conflict, leave
+ the two versions in the file and the backup file, and tell the
+ user to deal with it. The previous behavior was that the merge
+ would fail and then there was no way to do a checkin even once you
+ resolved the conflict (short of kludges like moving the file
+ aside, updating, and then moving it back).
+ * sanity.sh (binfiles): New tests binfiles-con* test for above
+ behavior. Adjust remaining tests to reflect changes in revision
+ numbers.
+
+Mon Jun 17 15:11:09 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (import): Remove sleep. Requiring it was a bug, and
+ it is fixed in the current sources.
+
+Mon Jun 17 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (TMPPWD): Set to real name of /tmp directory.
+ (basic2-64, conflicts-126.5): Use ${TMPPWD}.
+
+Mon Jun 17 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcscmds.c (RCS_checkout): Remove noerr parameter. Change all
+ callers.
+ * rcs.c (RCS_fast_checkout): Likewise.
+
+Mon Jun 17 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Cleaner implementation of tag locking code added Jun 13 1996:
+ * cvs.h (tag_lockdir, tag_unlockdir): Declare.
+ * rtag.c (locked_dir, locked_list): Remove.
+ (rtag_fileproc): Don't lock here; just call tag_lockdir.
+ (rtag_filesdoneproc): Don't unlock here; just call tag_unlockdir.
+ * tag.c (locked_dir, locked_list): Move farther down in file.
+ (tag_fileproc): Don't lock here; just call tag_lockdir.
+ (tag_filesdoneproc): Don't unlock here; just call tag_unlockdir.
+ (tag_lockdir, tag_unlockdir): New functions.
+
+Wed Jun 15 07:52:22 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * client.c (send_modified, update_entries): Fixed bug which didn't
+ handle binary file transfers in BROKEN_READWRITE_CONVERSION.
+
+Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (checkout_file): Call server_scratch_entry_only when a
+ non-pertinent file is found that does not exist.
+ * sanity.sh (newb): Add test case for above patch.
+
+Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (update_fileproc): Call server_scratch_entry_only when
+ handling T_REMOVE_ENTRY on the server.
+ * sanity.sh (conflicts2): Remove special case for remote server
+ bug fixed by above patch.
+
+Thu Jun 13 21:16:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basica-9): Update to reflect change to "sufficient
+ access" message.
+
+Thu Jun 13 20:13:55 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c, cvs.h (start_recursion): Remove wd_is_repos argument;
+ add comment about meaning of which argument. Use !(which &
+ W_LOCAL) instead of wd_is_repos.
+ * admin.c, client.c, commit.c, diff.c, edit.c, lock.c, log.c,
+ patch.c, rcs.c, remove.c, rtag.c, status.c, tag.c, update.c,
+ watch.c: Change callers. This is a semantic change in only two
+ cases: (1) tag_check_valid, where repository was not "", and (2)
+ the pipeout case in checkout_proc. In both of those cases the
+ previous setting of wd_is_repos did not reflect whether we
+ actually were cd'd into the repository.
+ * recurse.c (start_recursion): Only check for the CVS subdirectory
+ if which & W_LOCAL.
+ * sanity.sh (devcom): Add test case fixed by above patch.
+
+Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * ignore.c (ignore_files): Skip based on the file name before
+ calling lstat.
+
+ * client.c (last_register_time): New static variable.
+ (update_entries): Set last_register_time when calling Register.
+ (get_responses_and_close): If the current time is the same as
+ last_register_time, sleep for a section to avoid timestamp races.
+
+Thu Jun 13 17:24:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (supported_request): Reindent.
+
+Thu Jun 13 1996 Mark H. Wilkinson <mhw@minster.york.ac.uk>
+
+ * options.h.in, mkmodules.c: Corrections to allow compilation of
+ non-client-server version.
+
+Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * tag.c (tag_check_valid_join): New function.
+ * cvs.h (tag_check_valid_join): Declare.
+ * checkout.c (join_tags_validated): New static variable.
+ (checkout_proc): Check validity of join tags.
+ * update.c (update): Likewise.
+
+ * tag.c (tag_check_valid): Correct sizeof CVSROOTADM_HISTORY to
+ use CVSROOTADM_VALTAGS.
+
+ * lock.c (Writer_Lock): If we called lock_wait to wait for a lock,
+ then call lock_obtained when we get it.
+ (set_lock): Likewise.
+ (lock_obtained): New static function.
+
+Thu Jun 13 13:55:38 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): If we can't read cvs root, don't say "you don't
+ have sufficient access"; just print the message from errno. It
+ might be "No such file or directory" or something else for which
+ "you don't have sufficient access" doesn't make any sense.
+
+Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * commit.c (remove_file): Pass noerr as 0 to RCS_checkout.
+
+Thu Jun 13 12:55:56 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * patch.c: Initialize rev1_validated and rev2_validated to 0, not 1.
+
+Thu Jun 13 12:55:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rtag.c (locked_dir): Revise comments regarding locking; the rtag
+ and tag situations are different (changing from readlocking one
+ directory at a time to writelocking one directory at a time does
+ not do everything we might want, but it does fix simultaneous tags
+ and it doesn't make anything worse).
+
+Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Prevent simultaneous tag operations from interfering with each
+ other.
+ * rtag.c (rtag_proc): Pass rtag_filesdoneproc to start_recursion,
+ and pass readlock as 0.
+ (locked_dir, locked_list): New static variables.
+ (rtag_fileproc): Write lock the repository if it is not already
+ locked.
+ (rtag_filesdoneproc): New static function to unlock the
+ repository.
+ * tag.c (tag): Pass tag_filesdoneproc to start_recursion, and pass
+ readlock as 0.
+ (locked_dir, locked_list): New static variables.
+ (tag_fileproc): Write lock the repository if it is not already
+ locked.
+ (tag_filesdoneproc): New static function.
+
+Thu Jun 13 11:42:25 1996 Mike Sutton <mws115@llcoolj.dayton.saic.com>
+
+ * sanity.sh: Allow digits in usernames.
+
+Wed Jun 12 16:23:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (send_modified, update_entries): Reindent and add
+ comments to BROKEN_READWRITE_CONVERSION code.
+
+Wed Jun 12 16:23:03 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * client.c (send_modified, update_entries): Add
+ BROKEN_READWRITE_CONVERSION code.
+
+Mon Jun 10 20:03:16 1996 J.T. Conklin <jtc@cygnus.com>
+
+ * rcs.c (RCS_gettag): No longer set p to NULL if rcs is also NULL.
+ rcs will never be null, thanks to the assertion at top of function.
+
+Mon Jun 10 16:28:14 1996 Ian Lance Taylor <ian@cygnus.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Ignore CVS/Root file when doing an import.
+
+Fri Jun 7 18:20:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * status.c (status_fileproc, tag_list_proc): Use cvs_output rather
+ than writing to stdout directly.
+
+Wed Jun 5 13:54:57 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (force_tag_match, tag, date): New static variables.
+ (annotate_fileproc): Redo the loop to look for the version
+ specified by tag/date/force_tag_match, and handle branches
+ correctly.
+ (annotate_usage): Mention -f, -r, and -D.
+ (annotate): Handle -f, -r, and -D.
+
+Tue Jun 4 13:38:17 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (annotate_fileproc): Skip unrelated branch deltas.
+
+Fri Jun 7 13:04:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Change INITIALIZE_SOCKET_SUBSYSTEM to
+ SYSTEM_INITIALIZE and pass it pointers to argc and argv. Rename
+ CLEANUP_SOCKET_SUBSYSTEM to SYSTEM_CLEANUP.
+
+Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * import.c (add_rcs_file): make buf char[] not unsigned char[]
+
+Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * main.c (main): Add CLEANUP_SOCKET_SUBSYSTEM hook at end. Revise
+ comments regarding INITIALIZE_SOCKET_SUBSYSTEM.
+
+Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * main.c (main): Don't mess with signals if DONT_USE_SIGNALS is
+ defined.
+
+Thu Jun 6 15:32:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * modules.c (cat_module): Always format for 80 columns rather than
+ trying to determine how wide the screen is. The code we had for
+ the latter didn't cover all cases, was a portability headache, and
+ didn't work client/server.
+
+Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * error.c: Don't declare strerror if it is #defined.
+
+Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * cvs.h: If ENUMS_CAN_BE_TROUBLE, typedef Dtype to int not an enum.
+
+Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * update.c (update): If DONT_USE_PATCH, don't request patches.
+ Also call supported_request rather than reimplementing it.
+
+Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com>
+
+ * client.c (read_line): Changed an occurence of '\n' to '\012'.
+
+Wed Jun 5 17:18:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add_directory): Don't create the directory if noexec.
+ * sanity.sh (basica): New tests basica-1a10, basica-1a11 test for
+ above fix.
+ * sanity.sh (basicb): New tests basicb-2a10, basicb-2a11,
+ basicb-3a1 test for analogous situation with files rather than
+ directories.
+
+Tue Jun 4 13:38:17 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh: When doing a remote check, use :server: in CVSROOT.
+
+Wed Jun 5 13:32:40 1996 Larry Jones <larry.jones@sdrc.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * ignore.c: Set ign_hold to -1 when not holding instead of 0 so
+ that holding an empty list works correctly.
+ * sanity.sh (ignore): New tests 190 & 191 for above fix.
+
+Wed Jun 5 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ Visual C++ lint:
+ * client.c (update_entries): Copy the size to an unsigned variable
+ before comparing it with unsigned variables.
+ (handle_created, handle_update_existing): Prototype.
+
+Tue Jun 4 10:02:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (responses): Add Created and Update-existing responses.
+ * server.c (server_updated): If they are supported, use them
+ instead of Updated.
+ * client.c (struct update_entries_data): Add existp field.
+ (handle_checked_in, handle_updated, handle_new_entry,
+ handle_merged, handle_patched): Set it.
+ (handle_update_existing, handle_created): New functions,
+ for new responses.
+ (update_entries): Based on existp, check for
+ existence/nonexistence of file.
+ (try_read_from_server): Expand comment.
+ * server.c, server.h (server_updated): New argument vers.
+ * checkin.c (Checkin), commit.c (commit_fileproc), update.c
+ (update_fileproc, merge_file, join_file): Pass it.
+ * cvs.h: Move include of server.h after Vers_TS declaration.
+ * sanity.sh (conflicts2): New tests conflicts2-142d* test for
+ above fix.
+
+ * sanity.sh (ignore): Fix typo in comment.
+
+ * tag.c (tag_check_valid): Add comment clarifying when val-tags
+ entries are created.
+
+Mon Jun 3 07:26:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Increment version number to 1.8.4.
+
+Mon Jun 3 02:20:30 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * version.c: version 1.8.3.
+
+Thu May 30 10:07:24 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (cmds): Fix typo ("bdif" -> "dif") which was accidentally
+ introduced 24 May 96.
+
+ * main.c (main_cleanup): Add comment stating default case will
+ never be reached.
+
+Wed May 29 21:43:43 1996 noel <noel@BOAT_ANCHOR>
+
+ * main.c (main_cleanup): check to see if SIGHUP, SIGINT, SIGQUIT,
+ SIGPIPE, and SIGTERM are defined before using them. Also add a
+ default case to print out those errors numerically which are not
+ found.
+
+Wed May 29 18:43:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c (expand_path): Document LINE == 0 and allocation
+ of return value.
+ * modules.c (do_module): Pass 0, not -1, to indicate line number
+ not known. Free value returned from expand_path. Deal with NULL
+ return from expand_path.
+
+Wed May 29 15:56:47 1996 Greg A. Woods <woods@most.weird.com>
+
+ * modules.c (do_module): call expand_path() on the program name
+ specfied by one of '-o', '-t', or '-e' in the modules file before
+ passing it to run_setup(). This makes it possible to use $CVSROOT
+ (or indeed ~user or any other user-specified variable) to specify
+ pathnames for programs not installed in the normal execution path.
+
+Sun May 26 21:57:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_server): Don't include %s in error message;
+ there is no argument to go with it. Do include "internal error"
+ in error message since that might not be clear to the user otherwise.
+
+Sun May 26 11:58:13 1996 Greg A. Woods <woods@most.weird.com>
+
+ * root.c (set_local_cvsroot): enforce a wee bit of portability
+ (parse_cvsroot): same....
+ (DEBUG main): same, plus style guidelines
+ (DEBUG error): deleted -- not necessary here (use fprintf instead)
+
+ * mkmodules.c (modules_contents): updated notes about what must be
+ done if you change any of the options for a module.
+ (loginfo_contents): fixed grammar, re-pargraphed, and added 'echo
+ %s;' to the example.
+ (editinfo_contents): minor grammar fix.
+
+Sun May 26 17:51:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (Version_TS): Remove case where we get options from
+ sdtp->options. Whatever case that was intended to handle is
+ probably lost in the mists of time, but sdtp->options isn't set
+ anywhere, and I think that has been true for a long time.
+ * cvs.h (struct stickydirtag): remove options field.
+ * entries.c (freesdt): Don't free ->options.
+ * sanity.sh (binfiles): New tests binfiles-13a* test for above fix.
+
+ * tag.c (check_fileproc): Use fullname not file in error message.
+ Say "locally modified" not "up-to-date"; the file need not match
+ the head revision it only need match some revision.
+
+Sun May 26 16:57:02 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * tag.c: added support for new option -c to make sure all tagged
+ files are up-to-date
+ (tag): check for option and set check_uptodate
+ (check_fileproc): check status of file if check_uptodate is set
+
+Sat May 25 15:22:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Revert change to look for a -H command option;
+ command option parsing should be up to each subcommand and the -H
+ global option works fine.
+
+Mon May 23 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (process_prune_candidates): Set prune_candidates to
+ NULL at the end of the function.
+
+Mon May 23 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * checkout.c (checkout): In code to handle multiple arguments,
+ pass preload_update_dir, not where, to Create_Admin.
+ (checkout_proc): Pass preload_update_dir, not where, to
+ Create_Admin.
+
+Thu May 23 19:14:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (server_set_sticky): Assert that update_dir != NULL.
+ * sanity.sh (basicb): New test; tests for Ian's fix to checkout.c
+ above.
+
+Thu May 23 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * patch.c (patch_fileproc): Don't ignore a file just because it is
+ in the Attic directory.
+
+Thu May 23 10:40:24 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (death): New tests death-{72a,76a0,76a1} test for bug
+ fixed by Ian's patch_fileproc change above.
+
+ * sanity.sh (death): Remove "temporary hack" in test 89.
+
+ * rcs.c (RCS_fast_checkout): If error closing file, and workfile
+ is NULL, use sout in error message instead of workfile.
+
+Thu May 23 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_fast_checkout): Do a fast checkout in the case where
+ workfile is NULL and sout is a file name.
+
+Wed May 22 19:06:23 1996 Mark Immel <immel@centerline.com>
+
+ * update.c (checkout_file): New arg resurrecting_out, to provide
+ resurrecting flag to caller.
+ (join_file): New arg resurrecting. Register with "0" if we are
+ the server and are resurrecting.
+ (update_fileproc): Pass the flag from checkout_file to join_file.
+
+Wed May 22 19:06:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (death): Test for above fix, in test 89 and new test 89a.
+
+Tue May 21 09:49:04 1996 Greg A. Woods <woods@most.weird.com>
+
+ * update.c (update_usage): oops -- fix my spelling typo.
+
+Mon May 20 10:53:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (find_fileproc): Call freevers_ts.
+
+ * commit.c (find_*): Keep an ignlist, like update.c and client.c do.
+ * commit.c (commit): Process the files from the ignlists, once we
+ are connected to the server.
+ * sanity.sh (ignore): New tests 189e and 189f test for new
+ commit.c behavior (and client.c behavior, which is unchanged).
+ * sanity.sh (conflicts): Remove dir1 and sdir in parts of the test
+ where we aren't prepared for "? dir1" and similar output.
+
+Mon May 20 13:23:36 1996 Greg A. Woods <woods@most.weird.com>
+
+ * main.c (cmd_usage): minor corrections to descriptions of status,
+ rtag, tag, and rdiff. Sort alphabetically by command name.
+
+Mon May 20 10:36:07 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (call_in_directory): Move the call to Entries_Close
+ before the call to chdir, since Entries_Close examines files in
+ the current directory.
+
+Fri May 17 12:13:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_tcp_server, start_server, start_rsh_server,
+ read_line, filter_through_gzip, filter_through_gunzip,
+ call_in_directory): Reindent as needed.
+
+ * main.c (main): Add missing #endif. Use indentation to indicate
+ nesting.
+
+Thu May 16 17:15:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (cmd_usage): Add "init" command.
+
+Thu May 16 16:45:51 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * client.c (start_tcp_server): Error message modified to tell the
+ user to use ":server:" instead of setting CVS_CLIENT_PORT to a
+ negative number.
+
+ * main.c (main): Add #ifdefs for turning off buffering of
+ stdio/stderr, so we don't get it by default.
+
+Thu May 16 01:29:47 1996 noel <noel@BOAT_ANCHOR>
+
+ * commit.c (commit_filesdoneproc): Print the repository and root
+ directories as part of the error message.
+
+ * main.c (main): Don't buffer stdout or stderr. It's inefficient,
+ but it then produces the right output for sanity.sh.
+
+Thu May 16 09:44:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * fileattr.c (fileattr_set): In the case where we are about to
+ call delproc, don't free ->data; delproc does that.
+ * sanity.sh (devcom): New tests devcom-b* test for this fix.
+
+ * sanity.sh (conflicts): Remove redundant clean up from previous
+ tests at the beginning of the test. Use dotest a few more places.
+ (conflicts2): New test, tests for Ian's fix to Classify_File.
+
+ * client.c (remove_entry_and_file): Add comment about
+ existence_error's.
+
+Sat May 16 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * update.c (update_dirleave_proc): Don't try to chdir .. and check
+ for an empty directory if there is a slash in the directory name.
+
+Thu May 16 09:02:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (deep): New tests deep-4a* test for Ian's fix to
+ update_dirleave_proc.
+
+Sat May 16 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * main.c (main_cleanup): Report signal name before dying.
+
+Wed May 15 23:47:59 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * main.c (usg): revert usage strings for `-H' flag change.
+
+Sat May 15 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * server.c (serve_static_directory): Return immediately if there
+ is a pending error.
+ (serve_sticky): Likewise.
+ (serve_modified): Read the file data even if there is a pending
+ error.
+
+Wed May 15 14:26:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): If -d and CVS/Root both specified, after writing
+ the value from -d into CVS/Root, use the value from -d, not the
+ old value from CVS/Root. Don't write CVS/Root with value from -d
+ until we have verified that it works.
+ * sanity.sh: Reenable test basica-9 and adjust for new behavior.
+
+Tue May 14 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * logmsg.c (do_editor): If user aborts the commit, still remove the
+ temporary file.
+
+Tue May 14 11:45:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c, cvs.h (cvs_temp_name): New function. Move L_tmpnam
+ define from cvs.h to filesubr.c.
+ * client.c, diff.c, import.c, login.c, logmsg.c, no_diff.c,
+ patch.c, wrapper.c: Call cvs_temp_name not tmpnam.
+ * login.c (login): Reindent function.
+
+Tue May 14 10:56:56 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_fast_checkout): If workfile is NULL, don't call chmod.
+
+Mon May 13 10:52:10 1996 Greg A. Woods <woods@most.weird.com>
+
+ * checkout.c (export_usage): note which options cause a sticky
+ version to be set, and which option avoids this.
+ * update.c (update_usage): likewise
+
+Sat May 11 18:57:07 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Comment out test basica-9 until I get around to
+ actually fixing it (the -d vs. CVS/Root change broke it).
+
+Fri May 10 09:39:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): -d now overrides CVS/Root.
+
+Thu May 9 19:45:24 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c: Remove comment listing commands at beginning. It was
+ out of date and redundant with the help.
+
+Thu May 9 09:33:55 1996 Greg A. Woods <woods@most.weird.com>
+
+ * main.c: add 'init' to opening comment listing commands
+
+ * mkmodules.c (init): fix to recognize argc==-1 as hint to call
+ usage() [should make "cvs init -H" work as expected]
+
+Wed May 8 15:02:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Set EXPR in the case that the expr in the path is the
+ one that we want.
+
+Wed May 8 14:06:24 1996 Greg A. Woods <woods@most.weird.com>
+
+ * sanity.sh (test): - convert all '[' to test ala GCD
+
+Wed May 8 13:46:56 1996 Greg A. Woods <woods@most.weird.com>
+
+ * sanity.sh (expr): - make a valiant attempt to find GNU expr
+ - Patch from Larry Jones:
+ sanity test deep-4 failed with "expr: arg list too long"
+ sanity test 56 failed because the stderr and stdout output was not
+ interleaved as expected.
+ sanity test modules-155a4 failed with "ls: illegal option -- 1"
+
+ * main.c (main): - Patch from Larry Jones for SysV setvbuf
+
+Tue May 7 16:41:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Increment version number to 1.8.2 to work around fact
+ that CVS 1.8 (confusingly) calls itself 1.8.1 not 1.8.
+
+Tue May 7 10:44:20 MET DST 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * rcs.c (rcsvers_delproc): fix memory leak by freeing author
+ field.
+
+Mon May 6 10:40:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (conflicts): New test conflicts-126.5 tests for bug
+ which Ian fixed May 5 in update.c
+
+Mon May 6 06:00:10 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.8.1
+
+Sun May 5 21:39:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (Version_TS): If sdtp is NULL, go ahead and check
+ RCS_getexpand for options. Fixes binaries and non-unix clients.
+ * sanity.sh: Fix binfiles-5.5 to test for the correct behavior
+ rather than the buggy behavior which existed when the binfiles-5.5
+ test was written.
+ (binfiles-14c,binfiles-14f): Likewise.
+
+Sun May 5 17:38:21 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ Integrated changes submitted by Ian Taylor <ian@cygnus.com>
+
+ * update.c (update_dirent_proc): cvs co -p doesn't print
+ anything when run from an empty directory.
+
+ * import.c (import_descend_dir): Check for a file in the
+ repository which will be checked out to the same name as the
+ directory.
+
+Sat May 4 12:33:02 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Extract the head revision directly from the RCS file when
+ possible, rather than execing co.
+ * rcs.c (RCS_reparsercsfile): Set delta_pos field.
+ (getrcskey): Add lenp parameter. Change all callers.
+ (RCS_fast_checkout): New function.
+ (annotate_fileproc): If PARTIAL is not set, just fseek to
+ delta_pos.
+ * rcs.h (struct rcsnode): Add delta_pos field.
+ (RCS_fast_checkout): Declare.
+ * diff.c (diff_file_nodiff): Call RCS_fast_checkout rather than
+ RCS_checkout.
+ * import.c (update_rcs_file): Likewise.
+ * no_diff.c (No_Difference): Likewise.
+ * patch.c (patch_fileproc): Likewise.
+ * update.c (checkout_file): Likewise.
+ (patch_file): Likewise.
+ (join_file): Likewise.
+
+Sat May 4 12:33:02 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * classify.c (Classify_File): Don't report a conflict for a
+ pending remove if somebody else has already removed the file.
+
+Thu May 2 13:34:37 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.7.88
+
+Thu May 2 01:40:55 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * server.c (HAVE_INITGROUPS): Use initgroups() only if
+ located by configure, in the event a system has crypt(), but
+ no initgroups()
+
+Wed May 01 21:08:21 1996 noel <noel@BOAT_ANCHOR>
+
+ * client.c (filter_through_gunzip): use "gzip -d" instead of
+ "gunzip," since there's no good reason (on NT at least) to have an
+ extra copy of gzip.exe copied to gunzip.exe (Arrrrgh! No symbolic
+ links!).
+
+ * mkmodules.c (init): check to see that we have the correct number
+ of arguments or print out the usage message (used to be argc > 1,
+ should be argc != 1, because help forces argc == -1 as a special
+ case).
+
+Wed May 1 18:05:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basica): When testing rejection of reserved tag name,
+ use BASE instead of RESERVED.
+
+Wed May 1 15:15:11 1996 Tom Jarmolowski <tjj@booklink.com>
+
+ * rcs.c (linevector_delete): Only copy up to vec->nlines - nlines,
+ not to vec->nlines.
+
+Wed May 1 15:43:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c (RCS_settag): Instead of reserving all tag names
+ containing only uppercase letters, reserve only BASE and HEAD.
+ * sanity.sh (mflag): Revert 26 Mar change; use all-uppercase tag
+ name again.
+
+Wed May 1 15:15:11 1996 Tom Jarmolowski <tjj@booklink.com>
+
+ * rcs.c (linevector_add): Move increment of i out of larger
+ statement, to avoid assumptions about evaluation order.
+
+Tue Apr 30 15:46:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.7.87.
+
+ * server.c (check_password): Don't use ANSI string concatenation.
+ Reindent function.
+
+Mon Apr 29 10:48:38 1996 Noel Cragg <noel@gargle>
+
+ * root.c (parse_cvsroot): removed "rsh" as an alias to "server" in
+ the method section.
+
+ * main.c (main): new variable help so we can support the `cvs -H
+ cmd' convention. Reverts change of 26 Apr 96 which removed this
+ feature.
+
+Sun Apr 28 14:57:38 1996 Noel Cragg <noel@gargle>
+
+ * main.c (main): update error message if parse_cvsroot fails.
+ * server.c (serve_root): same.
+ (serve_init): same.
+
+ * client.c (start_tcp_server): get rid of the "fall through"
+ stuff, now that we have access methods.
+ (start_server): switch off the access method to choose routine
+ that starts the server.
+ (start_tcp_server): tofd wasn't getting set to -1 early enough,
+ because a call to error for bind or gethostbyname might fail and
+ the subsequent error check to see if the connection had been made
+ would fail.
+
+ * root.c: new variable method_names for error reporting purposes.
+
+Sun Apr 28 17:22:15 1996 Noel Cragg <noel@occs.cs.oberlin.edu>
+
+ * server.c: moved kerberos #includes from main.c for the
+ kserver_authenticate_connection routine.
+
+Fri Apr 26 07:59:44 1996 Noel Cragg <noel@gargle>
+
+ * server.c (serve_init): use the new return value from
+ parse_cvsroot.
+ (serve_root): same.
+ * main.c (main): same.
+
+ * root.c (parse_cvsroot): fix indentation, add a return value
+ which tells whether the command succeeded or failed.
+
+ * main.c (main): move the setting of the UMASK environment
+ variable inside the stuff that gets done if the user is NOT asking
+ for help, so we don't signal any errors prematurely (don't want to
+ give an error because we can't parse an environment variable
+ correctly if the user asks for help). Similar mods for the code
+ that tries to get the working directory.
+
+ Also make CVSADM_Root a local variable instead of a global, since
+ its scope is only about 20 lines here!
+
+ * server.c (kserver_authenticate_connection): moved code from
+ main.c to clean up MAIN. Makes sense, since we already have a
+ pserver_authenticate_connection.
+ (pserver_authenticate_connection): rename from
+ authenticate_connection.
+
+ * main.c (main): reorganized the routine to eliminate variables
+ help, help_commands, and version_flag. Now the routine is much
+ clearer, since we don't have to be checking to see if these
+ variables are set. One behavior that was a bug/feature which is
+ now gone is an invocation like "cvs -H rtag" -- previously this
+ would give usage for rtag, but now gives usage for cvs itself.
+ The first behavior didn't make sense, especially since we say in
+ the docs that command-line flags are position-specific. *Reverted
+ Above*
+
+Thu Apr 25 20:05:10 1996 Noel Cragg <noel@gargle>
+
+ * main.c (main): make sure we have a valid command name before we
+ do anything else (moved the thing that looks for a command in CMDS
+ to right after the GETOPT loop). Added `kserver' and `pserver' to
+ the table so they will be recognized; set their functions to
+ SERVER so that help will be given when asked for.
+
+ * expand_path.c (expand_variable): return CVSroot_original rather
+ than CVSroot_directory.
+
+ * main.c (main): save CVSroot in the env rather than
+ CVSroot_original, since we might not have called PARSE_CVSROOT
+ (this can happen if we use the -H option to a command).
+
+ * root.c (parse_cvsroot): the parsing method was bogus for
+ guessing when we had hostnames vs. directories specified. Any
+ ambiguity should be removed by having the user specify the access
+ method. If the access method isn't specified, choose
+ server_method if the string contains a colon or local_method
+ otherwise.
+
+ * Changed CVSroot_remote back to client_active since the code
+ reads better.
+
+Wed Apr 24 17:27:53 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * vers_ts.c (Version_TS): xmalloc enough space (1 more
+ byte). Thanks to purify!
+
+Mon Apr 22 00:38:08 1996 Noel Cragg <noel@gargle>
+
+ * create_adm.c (Create_Admin): pass CVSroot_original instead of
+ CVSroot_directory (oops!).
+ * update.c (update_filesdone_proc): same.
+
+ * server.c (serve_root): modify to use parse_cvsroot rather than
+ goofing around with other variables. Will need to fix
+ parse_cvsroot to have a return value so we can return an error and
+ quit gracefully if in server mode.
+ (serve_init): same.
+
+ * main.c: modify command table to remove client_* routines, since
+ they no longer exist.
+ (main): don't try to switch off non-existent field in command
+ table! ;-)
+
+ * client.h (client_*): removed prototypes for now non-existent
+ functions.
+
+ * client.c: remove proto for get_cvs_password, since it is now in
+ cvs.h. Modify routines to use new globals that describe CVSROOT
+ rather than client_active, server_host, server_user, and
+ server_cvsroot.
+ (parse_cvsroot): removed function, since a more generic version
+ now lives in root.c.
+ (connect_to_pserver): remove call to parse_cvsroot, since main.c
+ has already done it for us.
+ (client_*): removed all of these routines, since they only call
+ parse_cvsroot and then their respective operation functions.
+ Since main.c has already called parse_cvsroot, we shouldn't bother
+ with the extra function call, since client-server diffs are
+ already handled in the core routines themselves.
+
+ * main.c: remove CVSroot as a global variable. Remove
+ use_authenticating_server variable since we have a new
+ `CVSroot_method' variable instead.
+ (main): add `CVSroot' as a local variable. Call parse_cvsroot
+ after we're sure we have the right setting for `CVSroot.'
+
+ * login.c (login): update to use new global variables. Instead of
+ old behavior which let the user type in user@host when prompted,
+ it makes them do it in CVSROOT proper. The routine still lets the
+ user type the password, however.
+ (get_cvs_password): make sure that CVSROOT is fully qualified
+ before trying to find the entry in the .cvspass file.
+ * cvs.h: add prototype for get_cvs_password.
+
+ * add.c: use new globals that describe CVSROOT.
+ * admin.c: same.
+ * checkout.c: same.
+ * commit.c: same.
+ * create_adm.c: same.
+ * diff.c: same.
+ * edit.c: same.
+ * expand_path.c: same.
+ * history.c: same.
+ * ignore.c: same.
+ * import.c: same.
+ * log.c: same.
+ * mkmodules.c: same.
+ * modules.c: same.
+ * parseinfo.c: same.
+ * patch.c: same.
+ * rcs.c: same.
+ * recurse.c: same.
+ * release.c: same.
+ * remove.c: same.
+ * repos.c: same.
+ * rtag.c: same.
+ * status.c: same.
+ * tag.c: same.
+ * update.c: same.
+ * watch.c: same.
+ * wrapper.c: same.
+
+ * root.c (Name_Root): remove error message that reports missing
+ CVSROOT, since new code in main.c will catch it and also print out
+ an error.
+ (parse_cvsroot): new function -- takes a CVSROOT string and breaks
+ it up into its component parts -- method, hostname, username, and
+ repository directory. Sets new global variables that describe the
+ repository location more precisely: CVSroot_original,
+ CVSroot_remote, CVSroot_method, CVSroot_username,
+ CVSroot_hostname, CVSroot_directory for use by all other
+ functions. Checks for obvious errors in format of string.
+ (main): a short routine to test parse_cvsroot from the command
+ line.
+ * cvs.h: add prototype for parse_cvsroot and extern definitions
+ for new globals.
+
+ * cvs.h: removed CVSroot variable, since we don't want other
+ routines using the raw CVSROOT (also helped to find all of the
+ refs to the variable!).
+
+Fri Apr 19 11:22:35 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.7.86
+
+Thu Apr 18 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * client.c (try_read_from_server): Compare return value from fwrite
+ with a size_t not an int (Visual C++ lint).
+
+Wed Apr 17 11:56:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (try_read_from_server): New function.
+ (read_from_server): Use it.
+ (read_counted_file): New function.
+ * client.c, server.c: Add Template response.
+ * cvs.h (CVSADM_TEMPLATE): Added.
+ * logmsg.c (do_editor): If repository is NULL, use CVSADM_TEMPLATE
+ file in place of rcsinfo.
+ * server.c, server.h (server_template): New function.
+ * create_adm.c (Create_Admin): Call it.
+
+Tue Apr 16 13:56:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * repos.c (Name_Repository): Fix comments.
+ * create_adm.c (Create_Admin): Fix indentation.
+
+Wed Apr 10 16:46:54 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Include relevant information here rather than
+ citing (former) FAQ.
+
+ * ChangeLog-9395: Fix typo in introductory paragraph.
+
+Wed Apr 10 14:55:10 1996 code by Mike Spengler mks@msc.edu
+ comments by Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (unlink_file_dir,deep_remove_dir): Don't call unlink
+ on something which might be a directory; check using isdir instead.
+
+Wed Apr 10 14:55:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (build_dirs_and_chdir): Pass path, not cp, to
+ Create_Admin. The former is the correct update dir.
+ * sanity.sh (modules): New tests modules-155* test, for above fix.
+
+Mon Apr 8 13:53:27 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * rcs.c (annotate_fileproc): If the file is not under CVS control,
+ return instead of dumping a core. Don't bug on files with an empty
+ first revision.
+
+Fri Mar 29 16:08:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (annotate_fileproc): If last line of add-chunk is not
+ newline terminated, end the loop when we find that out.
+
+Fri Mar 29 16:59:34 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * rcs.c (annotate_fileproc): allow last line of add-chunk not to
+ be newline terminated
+
+Thu Mar 28 10:56:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Add more diff tests:
+ * sanity.sh (basic2): Use dotest for test 61.
+ (basica): Add test basica-6.2.
+ (branches): Add tests branches-14.4 and branches-14.5.
+ (basic1): Remove tests 19, 20, 25, and 26. The only thing this
+ might miss out on is diff's interaction with added and removed
+ files, but those tests didn't test that very well anyway.
+
+ * rcs.c (RCS_getrevtime): Add comment regarding years after 1999.
+
+ * rcs.c: Add "cvs annotate" command and related code.
+ (getrcskey): Move special handling of RCSDESC from here to
+ callers. Handle those keys (desc, log, text) which do not
+ end in a semicolon.
+ * rcs.h (RCSVers): Add author field.
+ * rcs.c (RCS_reparsercsfile): Set it.
+ * cvs.h (annotate), main.c (cmd_usage, cmds), client.h client.c
+ (client_annotate), server.c (serve_annotate, requests): Usual
+ machinery to add a new command.
+ * sanity.sh (basica): Test cvs annotate.
+
+ * sanity.sh (branches): More tests, of things like adding files on
+ the trunk after a branch has been made.
+
+Tue Mar 26 09:48:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c: Don't declare free and xmalloc; cvs.h already
+ takes care of that.
+
+ * sanity.sh (mflag): Don't use tag name reserved to CVS.
+
+ NT local changes plus miscellaneous things noticed in the process:
+ * import.c (add_rcs_file): Use binary mode to write RCS file. Use
+ \012 where linefeed is intended. Copy data a small block at a
+ time, until we hit EOF, rather than trying to read the whole file
+ into memory at once.
+ * client.c (send_modified): Add comments regarding st_size.
+ * commit.c (commit): Add comments regarding binary mode and read().
+ * logmsg.c (do_editor): Add comments regarding st_size.
+ * server.c (server_updated): Use binary mode to read file we are
+ sending.
+
+ * rcscmds.c (RCS_settag): Complain if user tries to add a tag name
+ reserved to CVS.
+ * sanity.sh (basica): Test for this behavior.
+
+ * sanity.sh (binfiles): New tests test ability to change keyword
+ expansion.
+
+Mon Mar 25 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvs.h, filesubr.c (expand_wild): New function.
+ * recurse.c (start_recursion): Call expand_wild at beginning and
+ free its results at the end.
+ * cvs.h, subr.c (xrealloc): Make argument and return value void *.
+ * client.h, client.c (send_file_names): Add flags argument. If
+ SEND_EXPAND_WILD flag is passed, call expand_wild at beginning and
+ free its results at the end.
+ * admin.c, add.c, log.c, tag.c, status.c, edit.c, watch.c,
+ update.c, commit.c, remove.c, client.c, diff.c: Update callers.
+
+Fri Mar 22 10:09:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.c (error, fperror): Exit with status EXIT_FAILURE rather
+ than STATUS. We had been neglecting to check for 256, and the
+ value of providing a count of errors is probably minimal anyway.
+ * add.c, modules.c, mkmodules.c, tag.c, server.c, main.c,
+ import.c, client.c, scramble.c, recurse.c: Exit with status
+ EXIT_FAILURE rather than 1. On VMS, 1 is success, not failure.
+ * main.c (main): Return EXIT_FAILURE or 0. The value of providing
+ a count of errors is minimal.
+
+ * client.c (init_sockaddr): Exit with status 1 rather than
+ EXIT_FAILURE. The latter apparently doesn't exist on SunOS4.
+ Reindent function.
+
+Mon Mar 18 14:28:00 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h, ignore.c: New variable ign_case.
+ * ignore.c (ign_name): If it is set, match in a case-insensitive
+ fashion.
+ * server.c (serve_case): New function.
+ (requests): Add Case request.
+ * client.c (start_server): If FILENAMES_CASE_INSENSITIVE is
+ defined, send Case request.
+
+Sat Mar 16 08:20:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ For reference, this change takes cvs's text segment from 315392
+ bytes to 311296 bytes (one 4096 byte page).
+ * cvs.h (struct file_info): Add fullname field.
+ * recurse.c (do_file_proc): Set it.
+ * commit.c (find_fileproc), client.c (send_fileproc), commit.c
+ (check_fileproc), diff.c (diff_fileproc), edit.c
+ (unedit_fileproc), patch.c (patch_fileproc), remove.c
+ (remove_fileproc), rtag.c (rtag_fileproc), tag.c (tag_fileproc),
+ update.c (update_fileproc), watch.c (watchers_fileproc): Use it
+ instead of computing it each time.
+ * diff.c (diff_fileproc), remove.c (remove_fileproc): Use fullname
+ where we had been (bogusly) omitting the directory from user
+ messages.
+ * edit.c (unedit_fileproc, edit_fileproc): If we cannot close
+ CVSADM_NOTIFY, mention CVSADM_NOTIFY rather than finfo->file in
+ error message.
+ * rtag.c (rtag_fileproc), tag.c (tag_fileproc): Reindent.
+
+Fri Mar 15 15:12:11 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * server.h: fix prototype of server_pause_check (was
+ server_check_pause)
+
+Thu Mar 14 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * vers_ts.c (Version_TS), entries.c (Scratch_Entry, AddEntryNode):
+ Change findnode to findnode_fn.
+
+ * main.c: Depending on HAVE_WINSOCK_H, include winsock.h or
+ declare gethostname.
+ * cvs.h: Don't declare it here.
+
+Thu Mar 14 07:06:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (find_fileproc): If vn_user is NULL and ts_user is not,
+ print an error rather than silently succeeding.
+ * sanity.sh (basica-notadded): New test, for above fix.
+ (dotest_internal): New function.
+ (dotest,dotest_fail): Call it instead of duplicating code between
+ these two functions.
+
+ * sanity.sh: Skip tests binfiles-9 through binfiles-13 for remote.
+
+ * options.h.in: Adjust comment to reflect kfogel change.
+
+Thu Mar 14 01:38:30 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * options.h.in (AUTH_CLIENT_SUPPORT): turn on by default.
+
+Wed Mar 13 09:25:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (Version_TS): Don't try to override options from rcs
+ file if there isn't an rcs file (e.g. called from send_fileproc).
+ This fixes a bug detected by test 59 in "make remotecheck".
+
+ * rcs.c (RCS_reparsercsfile, RCS_getexpand): Assert that argument
+ is not NULL.
+
+ Fix a gcc -Wall warning:
+ * rcs.c, rcs.h (RCS_getexpand): New function.
+ * vers_ts.c (Version_TS): Call it.
+ * rcs.c (RCS_reparsercsfile): Make static.
+
+ Add a "cvs init" command. This is needed because cvsinit.sh
+ invoked mkmodules which doesn't exist any more.
+ * mkmodules.c: Break filelist out of mkmodules function, rename
+ struct _checkout_file to struct admin_file (for namespace
+ correctness), and add contents field.
+ (init,mkdir_if_needed): New functions.
+ * cvs.h (init): Declare.
+ * main.c (cmds): Add init.
+ (main): If command is init, don't require cvsroot to exist.
+ * client.c, client.h (client_init, send_init_command): New functions.
+ * client.c (start_server): Don't send Root request if command is init.
+ * server.c (serve_init): New function.
+ (requests): Add "init".
+
+Wed Mar 13 09:51:03 MET 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * vers_ts.c (Version_TS): set options to default option if the
+ file if no -k option but -A was given. This avoids the (wrong)
+ update message for binary files which are up-to-date when
+ running 'cvs -A'.
+
+ * update.c (checkout_file): remove test of -k option stored in the
+ file itself because it was moved to vers_ts.c
+
+ * sanity.sh: added tests for the above fix.
+
+Tue Mar 12 13:47:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * hash.c (findnode): Adjust comment regarding errors.
+
+ * hash.c (findnode, findnode_fn): Assert that key != NULL. This
+ way the check still happens even if the function is later
+ rewritten to not start out by calling hashp.
+
+Mon Mar 11 10:21:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: If expr accepts multi-line patterns but is too
+ liberal in matching them, print a warning but keep going.
+
+ * sanity.sh: Add QUESTION variable, analogous to PLUS. Use it
+ instead of \? to match a question mark.
+
+ * cvs.h (CVSMODULE_OPTS, CVSMODULE_SPEC): Move from here...
+ * modules.c: ...to here. They are only used here and the code to
+ handle the syntax of modules files should not be scattered all over.
+ * modules.c (CVSMODULE_OPTS): Add "+" as first character.
+ * sanity.sh (modules): New tests 148a0 and 148a1 test for
+ above-fixed bug.
+
+Mon Mar 11 13:11:04 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * modules.c (cat_module): set optind to 0 to force getopt() to
+ reinitialize its internal nextchar
+
+Mon Mar 11 00:09:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * hash.c (findnode, findnode_fn): Revert changes of 7-8 Mar 1996.
+ The correct style is to assert() that key != NULL (see HACKING),
+ which is already done in the hashp function.
+ * fileattr.c (fileattr_delproc): Likewise, assert() that
+ node->data != NULL rather than trying to deal with it being NULL.
+
+Fri Mar 8 01:31:04 1996 Greg A. Woods <woods@most.weird.com>
+
+ * hash.c (findnode_fn): one more place to avoid calling hashp()
+ with a NULL key
+
+Thu Mar 7 17:30:01 1996 Greg A. Woods <woods@most.weird.com>
+
+ * hash.c (findnode): also return NULL if key is not set
+ [[ reported by Chris_Eich@optilink.optilink.dsccc.com, and
+ supposedly in a PR that should be marked "fixed"..... ]]
+
+ * fileattr.c (fileattr_set): set node->data to NULL after freeing
+ it to prevent subsequent accesses
+ (fileattr_delproc): don't free node->data if it's NULL, and set it
+ to NULL after freeing
+ [[ reported by Chris_Eich@optilink.optilink.dsccc.com, and
+ supposedly in a PR that should be marked "fixed"..... ]]
+
+Fri Mar 1 14:56:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basica): New test basica-4a tests for bug fixed by
+ sam@inf.enst.fr on 1 Mar 96.
+
+Fri Mar 1 18:10:49 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * tag.c (check_fileproc): Check for file existence before trying
+ to tag it.
+
+Fri Mar 1 07:51:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (update_entries): If command is export, set options to
+ NULL.
+
+Thu Feb 29 16:54:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * lock.c (write_lock, Reader_Lock): Remove
+ BOGUS_UNLESS_PROVEN_OTHERWISE code. It was pretty bogus, and has
+ been ifdeffed out for a long time.
+ * cvs.h (CVSTFL): Removed; no longer used.
+
+ * cvsrc.c, cvs.h (read_cvsrc): Pass in command name rather than
+ using global variable command_name.
+ * main.c (command_name): Initialize to "", not "cvs" so that error
+ messages don't say "cvs cvs". Update calls to read_cvsrc to pass
+ in command_name or "cvs" as appropriate.
+ * sanity.sh (basica): New test basica-9 tests for above-fixed bug.
+
+ * lock.c: Rename unlock to lock_simple_remove to avoid conflict
+ with builtin function on QNX.
+
+Thu Feb 29 17:02:22 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * fileattr.c (fileattr_get): Removed NULL pointer dereference
+ which occurred in the absence of default attribute.
+
+Thu Feb 29 07:36:57 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * rcs.c (RCS_isbranch, RCS_whatbranch): Remove no longer used file
+ argument, swap order of remaining two arguments to be like other
+ RCS_* functions.
+ (RCS_nodeisbranch): swap order of arguments to be like other RCS_*
+ functions.
+ * rcs.h (RCS_isbranch, RCS_whatbranch, RCS_nodeisbranch): Update
+ prototypes for above changes.
+ * commit.c, rtag.c, status.c, tag.c: Update for above calling
+ convention changes.
+
+Thu Feb 29 08:39:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_server): Revert changes which claimed to fall
+ back to a different way of connecting. Add comments explaining
+ why. (I don't think the changes did what they claimed, anyway).
+ Use indentation rather than comments to line up #if, #else, and
+ #endif.
+
+ * patch.c (patch, patch_fileproc): Revert change to add optional
+ arguments to -c and -u. Optional arguments are evil and in
+ violation of the POSIX argument syntax guidelines. The correct
+ way to do this is -C and -U. Also change DIFF back to "diff" in
+ output (see comments).
+
+ gcc -Wall lint:
+ * client.c (copy_a_file): Declare p inside the #ifdef in which is
+ it used.
+ * commit.c (remove_file): Remove unused variable p.
+ * commit.c (checkaddfile): Remove unused variables p.
+ * rcs.c (RCS_isbranch): Remove unused variable p.
+ * rcs.c: Remove unused declarations and definitions of
+ parse_rcs_proc, rcsnode_delproc, rcslist, and repository.
+ * rtag.c (rtag_fileproc): Remove unused variable p.
+ * patch.c (patch_fileproc): Remove unused variable p.
+ * tag.c (val_fileproc): Remove unused variable node.
+ * client.c, import.c, lock.c, server.c: Cast pid_t to long before
+ passing it to %ld.
+
+ * cvs.h: Don't prototype gethostname; merely declare it (on linux,
+ second argument is size_t not int).
+
+Thu Feb 29 10:29:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de>
+
+ * sanity.sh: added "cat > /dev/null" to loginfo entry to avoid the
+ SIGPIPE signal
+
+Thu Feb 29 10:28:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de>
+
+ * patch.c: added new variable diff_opt
+ (patch): allow optional parameter to -c and -u option, send it to
+ server
+ (patch_fileproc): cleaned up the code which prints the current
+ filename. For "-s" option, print the pathname relative to CVSROOT
+ instead of just the filename.
+
+ * filesubr.c (xchmod): added cast to shut up gcc
+
+ * cvs.h: added prototype for gethostname
+
+Thu Feb 29 10:27:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de>
+
+ * lock.c (write_lock), (Reader_Lock), import.c (update_rcs_file),
+ client.c (update_entries), (send_modified), server.c (server),
+ (receive_file), (server_updated): use %ld for printing pid_t
+ variables
+
+Thu Feb 29 02:22:12 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * run.c (run_exec): Added VMS return status support.
+
+Thu Feb 29 01:07:43 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * client.c (send_to_server): wrtn wasn't being declared under
+ VMS for some reason.
+
+Wed Feb 28 23:27:04 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * client.c: Changed #ifdef VMS && NO_SOCKET_TO_FD to
+ #if defined(VMS) && defined(NO_SOCKET_TO_FD)
+
+Wed Feb 28 22:28:43 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * build_src.com: Added DCL command procedure to build
+ and link CVS client for VMS.
+
+Wed Feb 28 22:07:20 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * client.c: VMS CVS client specific changes.
+
+ Added USE_DIRECT_TCP to allow CVS_PORT to be used to specify
+ a TCP connection port (no Kerberos). Changed
+ start_kerberos_server() to start_tcp_server().
+
+ In copy_a_file(): transform a backup file to have a
+ VMS-friendly name.
+
+ Added HAVE_CONFIG_H to include "config.h".
+
+ start_server() will starts the first successful of any
+ mutually exclusive methods of starting the CVS server
+ which might be enabled.
+
+ Initialized use_socket_style and server_sock for VMS in
+ start_server().
+
+Wed Feb 28 21:49:48 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * find_names.c, recurse.c, cvs.h: Changed Find_Dirs() to
+ Find_Directories().
+ * cvs.h: Added VMS filenames enabled through USE_VMS_FILENAMES
+ VMS POSIX will require to use the regular CVS filenames
+ while VMS is #define'd.
+
+Wed Feb 28 21:26:22 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * ignore.c: Added the patterns *.olb *.exe _$* *$ to default
+ ignore list for VMS.
+
+Wed Feb 28 13:32:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c (do_editor): Fix indentation.
+
+Wed Feb 28 12:56:49 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * logmsg.c (do_editor): If no editor is defined, exit and print
+ a message.
+
+Wed Feb 28 10:40:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (time_stamp, time_stamp_server): Reindent and revise
+ comments.
+
+Tue Feb 27 23:57:55 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * vers_ts.c: gmtime() returns NULL on some systems (VMS)
+ revert to local time via ctime() if GMT is not avaiable.
+
+Tue Feb 27 13:07:45 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ The changes listed below cause cvs to parse each rcs file (and
+ free the associated rcsnode after the file has been processed)
+ sequentially. cvs used to parse all files in a directory, an
+ approach that does not scale to huge repositories with lots
+ of revisions/branches/tags/etc.
+
+ * cvs.h (struct file_info): Removed srcfiles field. Added rcs
+ (node) field.
+ * recurse.c (do_recursion): Removed code that pre-parsed all
+ rcs files in the directory.
+ (do_file_proc): Parse current rcs file.
+ * rcs.c (RCS_parsefiles, parse_rcs_proc, RCS_addnode): Removed.
+ (RCS_isbranch, RCS_whatbranch): Changed srcfiles argument to
+ rcs (node).
+ * rcs.h (RCS_parsefiles, RCS_addnode): Removed prototypes.
+ (RCS_isbranch, RCS_whatbranch): Updated prototypes.
+ * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c,
+ commit.c, diff.c, history.c, import.c, log.c, patch.c, remove.c,
+ rtag.c, status.c, tag.c, update.c, vers_ts: Updated for above
+ calling convention / data structure changes.
+
+Mon Feb 26 16:07:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.7.3.
+
+ * Version 1.7.2.
+
+Mon Feb 26 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * recurse.c (start_recursion): Use last_component rather than
+ checking for '/' directly.
+ (do_dir_proc): Likewise.
+
+ Visual C++ lint:
+ * client.c (send_to_server): Change wrtn to size_t.
+ (connect_to_pserver): Put tofd and fromfd declarations inside
+ #ifndef NO_SOCKET_TO_FD.
+ * scramble.c (shifts): Change from array of char to array of
+ unsigned char.
+
+Mon Feb 26 13:31:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (check_repository_password): Remove unused variables
+ linelen, ch.
+
+ * client.c (send_file_names): Translate ISDIRSEP characters to '/'.
+
+Sat Feb 24 21:25:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (safe_location): Re-indent one line.
+
+Sat Feb 24 10:50:42 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * checkout.c (safe_location): put assignment to hardpath[x] in an
+ `else'-clause, so we don't do it when x == -1.
+
+Sat Feb 24 01:40:28 1996 Marcus Daniels <marcus@sayre.sysc.pdx.edu>
+ via Karl Fogel <kfogel@floss.red-bean.com>
+
+ * server.c (check_repository_password): Return by reference an
+ optional username, the `host_user', from the passwd file. The
+ host_user will be the user-id under which the cvs repository is
+ run.
+ (check_repository_password): Use `read_line' instead of fgets to
+ allow for passwords larger than 32 characters, as well as the
+ optional host user argument.
+ (check_password): Modify to use host_user.
+ (authenticate_connection): Modify to use host_user.
+
+Sat Feb 24 01:05:21 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * scramble.c (descramble): just shift descrambled string to get
+ rid of tag char, instead of allocating a whole new copy.
+ (scramble): cast return value of xmalloc to avoid unsightly
+ compiler warnings.
+
+ * options.h.in (RCSBIN_DFLT): don't refer to AUTH_SERVER_SUPPORT
+ in comment anymore, now that it's not defined in this file.
+
+Fri Feb 23 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * client.c: Ifdef HAVE_WINSOCK_H, include winsock.h
+ instead of sys/socket.h and friends.
+ * login.c: Don't include sys/socket.h and friends.
+ * login.c (login): Only fclose fp in the case where it was
+ successfully fopen'd.
+ * login.c: Declare getpass.
+ * filesubr.c, cvs.h (get_homedir): New function.
+ * cvsrc.c, expand_path.c, history.c, login.c: Call it instead
+ of getenv ("HOME").
+
+Fri Feb 23 09:23:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (connect_to_pserver): Remove unused variable host.
+ * login.c: Include getline.h.
+ (login): Remove unused variables i and username.
+ (get_cvs_password): Move free of linebuf to where it actually will
+ be called. Add a "return NULL" at the end of the function to shut
+ up gcc -Wall.
+
+ * options.h.in: Remove AUTH_SERVER_SUPPORT.
+ * client.h (authenticate_connection): Declare.
+ * scramble.c (scramble): Cast char to unsigned char before using
+ it to look up in table (char might be signed).
+ * server.c [AUTH_SERVER_SUPPORT]: Include grp.h
+ (authenticate_connection): Remove unused variables len and
+ server_user.
+
+ * sanity.sh (basica): Add comments regarding creating a top-level
+ directory.
+ (basic1): Don't try to remove first-dir and
+ ${CVSROOT_DIRNAME}/first-dir at start of test; tests are now
+ responsible for cleaning up at the end.
+ (PLUS,DOTSTAR,ENDANCHOR): Add comments regarding fixed GNU expr.
+
+Thu Feb 22 22:34:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: Remove alloca cruft.
+
+Wed Feb 21 07:30:16 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * modules.c (do_module): call free_cwd before exiting.
+
+ * recurse.c: Removed entries global variable.
+ (do_recursion): Declare entries. Moved call to Entries_Close so
+ entries list is closed on all code paths.
+ (start_recursion): Removed call to Entries_Close, entries list has
+ been moved to do_recursion only.
+
+Tue Feb 20 22:10:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (update_dirent_proc): If dir lacks a CVS subdirectory,
+ don't recurse into it.
+ * sanity.sh (conflicts): Test for above-fixed bug.
+
+ * update.c (merge_file): Use write_letter not printf.
+
+Tue Feb 20 12:34:07 EST 1996: Gary Oberbrunner <garyo@avs.com>
+ and Jim Kingdon <kingdon@cyclic.com>
+
+ * history.c (history_write): Change username to char * and call
+ getcaller() to set it. Setting username accidentally got deleted
+ 8 Feb 96.
+ * sanity.sh: Revise test 64 to test for above-fixed bug.
+ * sanity.sh (PLUS): New variable, work around yet another GNU expr
+ bug.
+
+Tue Feb 20 14:07:50 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Merge test rtags into test basic2. They never were
+ capable of running separately of each other.
+
+ * sanity.sh (deep): New test, to test ability to operate in deeply
+ nested directories (more quickly than basic2 test did).
+ (basic2,rtags): Remove directories dir3 and dir4. Remove file8,
+ file10, file12, file9, file11, file13, file15, file16, file17.
+ These additional files slowed down the tests considerably without
+ significantly increasing coverage.
+
+ * sanity.sh (PROG): New variable. Use it instead of "cvs"
+ to match the name cvs prints out for itself.
+
+Mon Feb 19 09:00:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ This fixes a bug whereby old default attributes would get
+ clobbered instead of added to on "cvs watch add".
+ * hash.c (findnode): Don't check for key == NULL; let the
+ assertion in hashp take care of it.
+ * fileattr.h, fileattr.c (fileattr_get): If filename is NULL,
+ return default attributes.
+
+ * client.c (send_repository): Fix indentation.
+
+Mon Feb 19 01:10:01 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * login.c (login): print out full repos so user knows which server
+ she's logging into.
+
+ * client.c (send_repository): die if `repos' is NULL. This is a
+ lame solution; see comments in code.
+
+Thu Feb 15 15:04:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.c (error): Free entire and mess when done with them.
+
+ * sanity.sh (info): Correct syntax of .cvsrc file.
+
+ * cvs.h, expand_path.c, edit.c, parseinfo.c, wrapper.c:
+ expand_path now takes arguments containing file and line for error
+ message, and it prints the error message itself.
+ * sanity.sh (info-6a): Test printing of error message.
+
+ * expand_path.c (expand_variable): Add USER internal variable.
+ * sanity.sh (info): Test USER and CVSROOT internal variables too.
+
+Wed Feb 14 19:11:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (usg): Add -s option.
+
+Tue Feb 13 20:26:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ gcc -Wall lint:
+ * mkmodules.c (mkmodules_usage): Remove declaration of
+ non-existent function.
+ * cvs.h (mkmodules): Declare.
+
+Mon Feb 12 12:20:04 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * mkmodules.c: Rename main to mkmodules and remove various pieces
+ of scaffolding which it used to emulate non-existent parts of CVS.
+ Change calling convention to just take a char * not argc,argv.
+ Save and restore working directory.
+ * commit.c (commit_filesdoneproc): Call it if checking files into
+ CVSROOT.
+ * Makefile.in (SOURCES): Add mkmodules.c.
+ (OBJECTS): Add mkmodules.o.
+ (MSOURCES,MOBJECTS): Removed.
+ (COMMON_OBJECTS): Removed; move former contents into OBJECTS.
+ Update other rules accordingly.
+ * sanity.sh: Adjust to reflect nonexistence of mkmodules.
+
+ These changes introduce functions cvs_output and cvs_outerr;
+ eventually all server output will go through them rather than
+ stdio directly.
+ * server.c (saved_output, saved_outerr): New variables.
+ (do_cvs_command): Initialize them.
+ (buf_output): Don't require that buf->output be set; saved_* use
+ this to shove some data in a buffer which buf_copy_lines will
+ later want to get data from.
+ * server.c, cvs.h (cvs_output, cvs_outerr): New functions.
+ * mkmodules.c (cvs_outerr): New function, so error() works.
+ * error.c: Reindent. Don't declare program_name and command_name;
+ cvs.h declares them.
+ (error): Use vasprintf and cvs_outerr (or fputs in the
+ error_use_protocol case) rather than stdio directly.
+ * import.c (import_descend_dir): Remove kludge which had prevented
+ messages from error() from being out of order with respect to
+ messages from printf; cvs_output and cvs_outerr are a cleaner
+ solution to the problem.
+ (add_log, import): Use cvs_output not printf.
+ * update.c (write_letter): Use cvs_output not printf.
+ (checkout_file): Use write_letter not printf.
+ * sanity.sh: Use dotest for test 56 (test that output is actually
+ correct). In theory should test that the import.c bug is fixed,
+ but I was unable to reproduce the bug (it is timing dependent).
+
+Mon Feb 12 16:07:45 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * commit.c: define last_register_time
+ (commit): make sure cvs doesn't exit in the same second it wrote
+ the last timestamp
+ (commit_fileproc): set last_register_time
+ (finaladd): set last_register_time
+
+ * run.c, cvs.h: Changed more Popen() to run_popen()
+
+Mon Feb 12 03:06:50 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * release.c, rtag.c, tag.c: changed 'delete' to 'delete_flag'
+ to avoid symbol collision with DEC C RTL function delete()
+
+Mon Feb 12 03:01:48 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * mkmodules.c: changed 'void Lock_Cleanup()' to 'void static
+ Lock_Cleanup() to avoid conflict with more substantial
+ Lock_Cleanup() in lock.c
+
+Mon Feb 12 02:50:19 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * edit.c, logmsg.c, release.c, run.c: Changed Popen() to
+ run_popen(). VMS' linker is not case sensitive and considered
+ popen() and Popen() to be identical symbols.
+
+Sun Feb 11 10:51:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main) [!CLIENT_SUPPORT]: Silently ignore gzip level
+ rather than printing usage message.
+
+ * cvs.h, expand_path.c (variable_list): New variable.
+ (variable_set): New function.
+ * hash.h (enum ntype), hash.c (nodetypestring): Add VARIABLE.
+ * expand_path.c (expand_path, expand_variable): Reindent.
+ (expand_variable): Use user variables not environment variables
+ for ${=VAR} syntax. The environment variables didn't work
+ client/server.
+ * main.c (main): Process new -s global option.
+ * client.c (send_variable_proc): New function.
+ (start_server): Call it, to send user variables.
+ * server.c (serve_set): New function.
+ (requests): Add Set request.
+ * sanity.sh: Revise info test to use user variables rather than
+ environment variables.
+
+Sat Feb 10 16:55:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ By itself this is only a small cleanup, but in the long run it
+ will be way cool (for reference, it takes CVS's text segment from
+ 290816 bytes to 294912, which I expect will be made up by future
+ changes which this enables):
+ * cvs.h (struct file_info): Added.
+ (FILEPROC): Replace 5 args with single struct file_info *.
+ * recurse.c (do_file_proc): Adjust args to fileproc; passed in
+ instead of from globals.
+ (do_recursion): Call do_file_proc accordingly. Remove srcfiles
+ global variable.
+ * update.c (update_fileproc): Renamed from update_file_proc.
+ * admin.c, client.c, commit.c, diff.c, edit.c, log.c, patch.c,
+ remove.c, rtag.c, status.c, tag.c, update.c, watch.c: Update
+ fileprocs to new calling convention.
+
+Fri Feb 9 15:30:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c (expand_variable): Accept a variable name starting
+ with '=' as a way to specify an environment variable.
+ * sanity.sh (info): New tests, for above behavior.
+
+ * Makefile.in (clean): Also remove check.log check.plog.
+
+ * import.c (comtable): Remove SYSTEM_COMMENT_TABLE; the table
+ should *not* depend on what kind of machine the server happens to
+ be. Add "mak", "rc", "dlg", "frm", and "bas" types which were
+ formerly included via SYSTEM_COMMENT_TABLE.
+
+ * cvs.h, rcs.h, add.c, checkin.c, classify.c, commit.c, diff.c,
+ import.c, patch.c, rcs.c, update.c, vers_ts.c: Remove
+ DEATH_SUPPORT ifdefs. They were introduced to facilitate merging
+ between Cygnus and Berliner variants of CVS, not because it was
+ intended to subset CVS this way. And they clutter up the code
+ quite a bit.
+ * cvs.h, create_adm.c, main.c, update.c: Likewise, remove
+ CVSADM_ROOT ifdefs (it is still a #define, of course). I believe
+ they had a more-or-less similar motivation.
+
+ * sanity.sh: Move setting of HOME from ignore test to the start of
+ the tests so it applies to all tests.
+ (CVS): Remove -f; the above change takes care of it.
+
+ * rcs.h (RCS_MERGE): Removed; unused.
+
+ * commit.c (checkaddfile): Fix memory leak.
+
+ * admin.c, commit.c, diff.c, log.c, mkmodules.c: Pass -x,v/ to RCS
+ commands.
+
+ * rcscmds.c, cvs.h (RCS_checkin): New function.
+ * checkin.c, commit.c, import.c: Call it, rather than run_*.
+ * cvs.h, commit.c: Remove DEATH_STATE define; the behavior
+ which used to be the default (DEATH_STATE) is now the only one.
+ Failing to define DEATH_STATE has been commented as obsolete at
+ least since CVS 1.5. We still can read repositories created with
+ such a CVS, however.
+ * rcs.h, rcs.c: Adjust comments regarding DEATH_STATE.
+ * subr.c (make_message_rcslegal): Add comment, describing
+ allocation of returned value.
+
+Fri Feb 9 09:53:44 MET 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * sanity.sh: use "${testcvs}" instead of "cvs" in devcom tests
+
+ * hash.c: fix "dereferencing a NULL pointer" bug triggered with
+ "cvs watch add"
+ (findnode): return NULL if key == NULL
+ (hashp): assert (key != NULL)
+
+Fri Feb 9 00:46:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_reparsercsfile): Remove unused variable date.
+
+ * myndbm.c (mydbm_load_file): Fix typo ('015' -> '\015').
+
+Thu Feb 8 13:00:00 1996 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * rcs.c (RCS_parse, RCS_parsercsfile, RCS_reparsercsfile),
+ fileattr.c (fileattr_read), myndbm.c (myndbm_open):
+ Use FOPEN_BINARY_READ.
+ * fileattr.c (fileattr_write), myndbm.c (myndbm_close):
+ Use FOPEN_BINARY_WRITE.
+ * history.c (history_write, read_hrecs): Specify OPEN_BINARY.
+ * rcs.c: Remove calls to abort.
+ * myndbm.c (myndbm_load_file): Ignore CRs from ends of lines
+ if present.
+ * myndbm.c, fileattr.c: While I am at it, change \n to \012
+ a few places where LF is intended.
+ * history.c (history_write): Use getenv ("HOME"), not getpwnam,
+ to find home directory. If it isn't set, just keep going; don't
+ print a message.
+ * rcscmds.c, cvs.h (RCS_checkout): New function.
+ * update.c, checkin.c, commit.c, diff.c, import.c, no_diff.c,
+ patch.c: Call it instead of run_*.
+ * patch.c (patch_fileproc): Clean up inconsistent handling of
+ noexec flag.
+ * rcscmds.c (RCS_*): Pass -x,v/ to RCS commands; elsewhere in
+ CVS it is assumed that ,v is a suffix.
+
+Fri Feb 2 14:07:32 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * rcs.h (struct rcsnode): Remove dates field (list of rcsversnodes
+ indexed by date). CVS maintained this list for each RCS file even
+ though it was never used. This resulted in higher then necessary
+ memory requirements (and run time too). Even if revision info was
+ needed, CVS' List data structure is inappropriate because can't
+ handle duplicate keys. The above was discovered by tracking down
+ a memory leak.
+ * rcs.c (RCS_reparsercsfile): Don't build dates list.
+ (freercsnode): Don't delete dates list.
+ (rcsvers_delproc): Free date field.
+ (null_delproc): Removed.
+
+Thu Feb 1 12:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * remove.c (cvsremove): Don't tell user the name of the program
+ which they use to remove files; we don't have any way of knowing
+ that, and besides which they might use a GUI or emacs 'dired' anyway.
+ * update.c (update_filesdone_proc, update_dirleave_proc): Call
+ unlink_file_dir instead of rm -rf.
+ * options.h.in: Remove RM; no longer used.
+
+ * sanity.sh: New tests devcom-a* test "cvs watch add",
+ "cvs watch remove", and "cvs watchers".
+
+ * sanity.sh: New test 171a0 tests for watch.c bug just fixed by kfogel.
+
+ * Most .c files: Remove rcsids.
+ * cvs.h: Remove USE macro.
+
+Thu Feb 1 13:07:15 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * tag.c, rtag.c: Update various comments to reflect function name
+ changes.
+
+Thu Feb 1 14:14:31 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * recurse.c (do_recursion): comment #endif.
+
+ * edit.c (notify_check): surround with #ifdef CLIENT_SUPPORT; else
+ CVS won't compile if CLIENT_SUPPORT is undefined.
+
+ * edit.h (notify_check): surround declaration with #ifdef
+ CLIENT_SUPPORT.
+
+ * watch.c (watch): if argc <= 1, then just give usage (previously
+ was "argc == -1").
+
+Thu Feb 1 12:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README-rm-add: Remove information which is now in cvs.texinfo.
+
+ * sanity.sh: Remove basic0 tests. Move a few to new tests
+ basica-1a* (but there is no need to test that *every* command
+ gracefully does nothing on an empty directory; exhaustive testing
+ is impractical and the generic recursion processor handles this
+ anyway).
+
+ * sanity.sh: New tests 69a* test use of update -p to restore old
+ version of dead file.
+
+Wed Jan 31 18:32:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ChangeLog-9395: Remove duplicate entries from 1996 which
+ accidentally got into this file.
+
+ * client.c (read_line, read_from_server): Change "premature end of
+ file from server" message to "end of file from server (consult
+ above messages if any)" because 99% of the time it means rsh has
+ printed an error message and exited.
+
+Wed Jan 31 15:09:51 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * edit.c (ncheck_fileproc): Fix memory leak; free line before
+ returning.
+
+Tue Jan 30 18:06:12 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_recursion): Add comment about the fact that we
+ don't have locks in place at certain points.
+
+Tue Jan 30 09:43:34 1996 Vince Demarco <vdemarco@bou.shl.com>
+
+ * edit.c (notify_proc): have notify_proc call expand_path with
+ the name of the filter program. The user may have used a
+ cvs environmental variable. (Popen will expand it, but it may not
+ use the correct value)
+
+Tue Jan 30 09:43:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ChangeLog: take the pre-1996 changes and put them in a new file
+ ChangeLog-9395.
+ * ChangeLog-9194: Renamed from ChangeLog.fsf.
+ * ChangeLog-9194, ChangeLog-9395, ChangeLog: Add additional text
+ explaining the difference between all these logs and pointing to
+ older logs.
+ * Makefile.in (DISTFILES): Add ChangeLog-9194 and ChangeLog-9395;
+ remove ChangeLog.fsf.
+
+ * modules.c (do_module): Don't fall through from 'l' to 'o' case
+ of option processing switch statement.
+
+Tue Jan 30 06:50:19 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * client.c (send_repository): Fix memory leak; free adm_name
+ before returning.
+ * diff.c (diff_file_nodiff): Fix memory leak; free xvers before
+ returning.
+ * rtag.c (rtag_fileproc): Fix memory leak; if branch_mode is set,
+ free rev before returning.
+ * status.c (status_fileproc, tag_list_proc): Fix memory leak; free
+ return value of RCS_whatbranch.
+ * tag.c (tag_fileproc): Fix memory leak; free vers before
+ returning.
+ (val_fileproc): Fix memory leak; free return value of RCS_gettag.
+ * watch.c (watch_modify_watchers): Fix memory leak; free mynewattr
+ before returning.
+
+Tue Jan 30 09:43:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * lock.c (readers_exist): If stat gave an error, print an error
+ message saying it was from stat, rather than from "reading
+ directory". Skip the message completely if it was an
+ existence_error.
+
+ * sanity.sh (branches): New tests (branches off of branches, etc.).
+
+Tue Jan 30 11:55:34 MET 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * main.c (main): Add change to run getopt_long twice again.
+
+Mon Jan 29 15:59:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ gcc -Wall lint:
+ * client.c: Include edit.h
+
+Sun Jan 28 09:45:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * edit.c, edit.h (mark_up_to_date): New function, to remove file
+ in CVS/Base.
+ * client.c (update_entries): Call it if file is up to date.
+ * checkin.c (Checkin): Call it in non-server (local) case.
+ * sanity.sh: New test 182.5, tests for above-fixed bug.
+
+Sun Jan 28 01:07:22 1996 Jim Kingdon (kingdon@beezley)
+
+ * client.c (change_mode): Separate out CHMOD_BROKEN code to parse
+ mode_string, rather than going through a mode_t. Cleaner than
+ the previous CHMOD_BROKEN code (which also had a typo of && not &).
+
+Sat Jan 27 23:29:46 1996 Jim Kingdon (kingdon@beezley)
+
+ * edit.c (edit_fileproc): Check for EACCESS as well as EEXIST.
+
+Sat Jan 27 16:26:30 1996 Karl Fogel (kfogel@floss.cyclic.com)
+
+ * client.c (notified_a_file): use rename_file() instead of
+ rename() (but temporarily set `noexec' to 0 so it runs
+ unconditionally).
+ (change_mode): deal with CHMOD_BROKEN.
+
+Fri Jan 26 00:14:00 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * server.c: renamed `dirname' to `dir_name', to avoid conflicts
+ with system headers.
+
+ * client.c: renamed `dirname' and `last_dirname' to `dir_name' and
+ last_dir_name' (see above). Not strictly necessary, but
+ consistency is nice -- as long as you do it all the time.
+
+Thu Jan 25 00:41:59 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * options.h.in (AUTH_SERVER_SUPPORT, AUTH_CLIENT_SUPPORT): change
+ comment now that no longer under construction.
+
+Wed Jan 24 15:25:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.7.1.
+
+ * Version 1.7.
+
+Sat Jan 20 00:05:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.87.
+
+Mon Jan 15 18:14:55 1996 Gary Oberbrunner <garyo@avs.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * tag.c (val_direntproc): New function to ignore
+ nonexistent dirs when recursing to check tag validity.
+ (tag_check_valid): Pass it to start_recursion.
+ * sanity.sh (death): New tests 65a0-65a6 cause test 74 to test for
+ above-fixed bug.
+
+Mon Jan 15 12:55:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c: Revert change to run getopt_long twice. This can go in
+ after 1.7.
+
+Mon Jan 15 13:03:28 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * filesubr.c (deep_remove_dir): added test of EEXIST for nonempty
+ directory (Posix states that both ENOTEMPTY (BSD) and EEXIST
+ (SYSV) are valid)
+
+ * main.c (main): run getopt_long twice to allow command-line
+ suppression of reading the cvsrc file
+
+Fri Jan 12 10:02:43 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.86.
+
+Thu Jan 11 23:28:05 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * fileattr.h (fileattr_startdir): Add comment about REPOS == NULL.
+ * fileattr.c (fileattr_read, fileattr_write): Assert that
+ fileattr_stored_repos != NULL.
+ (fileattr_free): If fileattr_stored_repos is NULL, don't free it.
+
+Thu Jan 11 18:03:21 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * scramble.c (descramble): deal with DIAGNOSTIC better.
+
+Thu Jan 11 12:04:42 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * main.c: remove CVS_NOADMIN.
+
+ * options.h.in: remove CVS_NOADMIN
+
+Thu Jan 11 10:28:44 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * scramble.c (descramble): make sure the string returned is safe
+ to free().
+
+Wed Jan 10 01:11:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_notify): Cast return value from malloc.
+
+ * edit.c (notify_do): Use struct assignment, not struct
+ initialization (which SunOS4 /bin/cc doesn't have).
+
+Tue Jan 9 09:41:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.85.
+
+ We use version numbers instead of patchlevels. But there was some
+ confusing patchlevel stuff lying around. Nuke it:
+ * Makefile.in (HEADERS): Remove patchlevel.h
+ * patchlevel.h: Removed.
+ * main.c: Don't include patchlevel.h.
+ (main): Don't print patch level.
+
+ * server.c (check_repository_password): Check for errors from
+ system calls; reindent function.
+
+Tue Jan 9 23:15:30 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * expand_path.c: fix comments (explain expand_path()'s behavior
+ correctly).
+
+Tue Jan 9 09:41:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * edit.c (notify_proc): After copying in string following %s,
+ don't clobber it. Instead set up q to end of string.
+
+ * watch.c (watch_modify_watchers), edit.c (editor_set): Fix sense
+ of test in trying to decide whether attributes are changed.
+
+ * cvs.h (CVSROOTADM_USERS): New macro.
+ * edit.c (notify_do): Look up notifyee in CVSROOTADM_USERS if it
+ exists.
+
+Tue Jan 9 21:39:45 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * expand_path.c: don't redundantly #include things that cvs.h
+ already #includes (i.e., stdio.h, ctype.h, string[s].h).
+
+Tue Jan 9 09:41:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ignore.c (ign_default): Add *.obj.
+
+ * server.c: Put /* */ around #endif comment.
+
+Mon Jan 8 20:37:17 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * client.c (connect_to_pserver): check return value of recv().
+
+Mon Jan 8 11:37:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (connect_to_pserver): Check for error from connect;
+ reindent function.
+
+ * sanity.sh (4.75): Use dotest, so we get a PASS if test passes.
+
+ * sanity.sh (dotest): New argument OUTPUT2.
+ (188a): Use it instead of \|.
+
+ * sanity.sh (import): Avoid using string $ followed by Id followed
+ by $ in sanity.sh source, in case sanity.sh itself is under CVS.
+ I hate keyword expansion.
+
+ * sanity.sh: If expr cannot handle multiline expressions, fail and
+ tell the user to get one which can.
+
+ * release.c (release_delete): Remove unused variable retcode.
+
+Fri Jan 5 13:30:00 1996 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * release.c (release_delete): Call unlink_file_dir rather
+ than "rm -rf".
+
+Thu Jan 4 09:58:30 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (find_fileproc): Print "nothing known about foo" and
+ return 1 if the file doesn't exist and isn't in CVS/Entries.
+ (commit): If the recursion over find_fileproc returns an error,
+ print "correct above errors first!" just like local CVS.
+ * sanity.sh (basica): Test for above-fixed bug.
+
+ * release.c (release): If we are the client, only unedit if the
+ server supports it.
+
+ * sanity.sh: Remove STARTANCHOR stuff; expr patterns are
+ automatically anchored to the start. ENDANCHOR remains.
+
+ * commit.c (commit): Don't start the server until we have
+ determined that there is something to commit.
+
+Thu Jan 4 09:48:33 1996 Ben Laurie <ben@gonzo.ben.algroup.co.uk>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_server): dup the file descriptor before
+ fdopening it.
+
+Wed Jan 3 18:25:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Remove tests 5, 5.5, and 5.75. All that stuff is
+ tested elsewhere.
+
+ * ignore.c (ign_default): Change CVS* to CVS CVS.adm. CVS* is too
+ broad, especially in a case-insensitive filesystem.
+
+ * Makefile.in (cvsbug): version.c is in srcdir.
+
+Wed Jan 3 17:30:45 1996 Phi-Long Tran <ptran@autodesk.com>
+
+ * modules.c (do_module): Honor error_use_protocol in printing trace.
+ * server.c (server_register): Move check for options NULL to above
+ printing of the trace.
+
+Wed Jan 3 01:19:53 1996 Mark Immel <immel@centerline.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (checkout_file): Do not resurrect file on join if it
+ doesn't contain the revisions we are joining. Probably not a
+ perfect test, but should be an improvement.
+ * sanity.sh (death): New death-file4-* tests, for bug fixed above.
+
+Wed Jan 3 01:19:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c, admin.c, checkout.c, client.c, commit.c, diff.c, edit.c,
+ history.c, import.c, log.c, patch.c, release.c, remove.c, rtag.c,
+ status.c, tag.c, update.c, watch.c: In calling send_to_server,
+ pass \012 not \n. On the Mac \n is CR, not LF, and we want to
+ send LF. I didn't try to deal with whether files in CVSADM should
+ contain CR or LF--in fact there is some code in client.c which
+ reads \n from CVSADM files and passes it to send_to_server; it
+ needs to be cleaned up one way or the other.
+
+ * entries.c (Entries_Open): Don't try to close fpin twice.
+
+ * client.c (update_entries): Fix typo ("strlen (filename + 10)"
+ -> "strlen (filename) + 10").
+
+ * commit.c (checkaddfile): Remove arbitrary limit.
+
+Tue Jan 2 11:25:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (commit): Only pass files which were modified, added,
+ or removed to send_file_names. This has as a side effect a
+ semantic change--the up-to-date check is now skipped for other
+ files--but probably a good one, or at least not a bad one.
+ * sanity.sh (basica): New test; tests for bug fixed above.
+ * sanity.sh (187a3): Adjust for new 'cvs commit' output. Set up
+ DOTSTAR to match arbitrary text (another GNU expr bug/misfeature,
+ sigh).
+
+ * sanity.sh: Test that the commit in test 43 actually worked.
+ Merge tests basic2 and basic3 and make them independent of basic1.
+ (pass,fail): Don't insert spurious space.
+ (45.5): Fix typo in directory name.
+
+Tue Jan 2 13:00:00 1996 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ Visual C++ lint:
+ * myndbm.c: Prototype write_item.
+
+Tue Jan 2 11:25:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ gcc -Wall lint:
+ * client.c (client_expand_modules): Pass error message not "" to error.
+ * client.c (supported_request), server.c (supported_response):
+ Return a value (gcc -Wall can't know that error doesn't return).
+ * commit.c (copy_ulist): Return a value.
+ * history.c (fill_hrec): Don't make assumptions about whether
+ time_t is "int" or "long" or what.
+ * cvs.h: Declare link_file.
+ * server.c: Include fileattr.h.
+ * server.c (server_notify): Remove unused variable val.
+ * tag.c (val_fileproc): Remove unused variable foundtag.
+
+Mon Jan 1 09:49:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.6.5.
+
+ * Version 1.6.4.
+
+ * filesubr.c (link_file): Add comment about link vs. copy semantics.
+
+ * cvs.h (struct vers_ts): Fix comments.
+ * commit.c (commit): Before we ask for a log message, figure out
+ what is modified and what is not and pass the information to
+ do_editor.
+ (copy_ulist,find_fileproc): New helper functions for above code.
+
+ * client.c (read_line): When writing to from_server_logfile, write
+ the \n too.
+
+ * client.c (send_files): No longer call send_file_names.
+ * client.h: Update comment.
+ * add.c, admin.c, commit.c, diff.c, edit.c, log.c, remove.c,
+ status.c, tag.c, update.c, watch.c: Call send_file_names before
+ send_files.
+ * client.c: New variables module_argc, module_argv.
+ (client_expand_modules): Set them, to arguments.
+ (client_send_expansions): Use them instead of modules_vector to
+ send arguments.
+ * sanity.sh (modules): Add test of modules -d flag.
+
+
+For older changes see ChangeLog-9395.
diff --git a/src/ChangeLog-97 b/src/ChangeLog-97
new file mode 100644
index 0000000..ce7180b
--- /dev/null
+++ b/src/ChangeLog-97
@@ -0,0 +1,3249 @@
+1997-12-30 enami tsugutomo <enami@but-b.or.jp>
+
+ * rcs.c (RCS_checkin): Use gmtime() instead of localtime()
+ (restores behavior from RCS 5.x which was broken with RCS library
+ -kingdon).
+
+Mon Dec 29 12:53:00 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * modules.c (do_module): Check for a request for a file within a
+ module which is not a directory.
+ * sanity.sh (modules): Add test 149b1 for above patch.
+
+ * client.c (start_tcp_server): Remove useless assignment, left
+ behind by Dec 15 patch.
+
+Sat Dec 27 17:41:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c, options.h.in, history.c, import.c, main.c, rcs.c,
+ update.c: Remove !HAVE_RCS5 code. It had bit-rotted a while ago,
+ and more to the point is obsolete with the RCS library.
+
+27 Dec 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * zlib.c, server.h (gunzip_and_write): New function.
+ * client.c (update_entries): Call it instead of a gunzip subprocess.
+ * zlib.c, server.h (read_and_gzip): New function.
+ * client.c (send_modified): Call it instead of a gzip subprocess.
+
+Sat Dec 27 13:07:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Decrease RCS_deltas memory usage to what we need (approximately
+ the size of the file we are patching plus the size of the largest
+ patch). Previously memory usage had been approximately the size
+ of the RCS file because we never freed lines until the end.
+ * rcs.c (linevector_free, linevector_copy, linevector_add,
+ linevector_delete):
+ Instead of having all the lines and struct line's in the alloc_*
+ space, have each line and its struct line in its own malloc'd
+ space. Use a refcount to deal with curlines vs. headlines
+ vs. trunklines in RCS_deltas.
+ (struct allocblock, blocks, block_alloc, block_free): Remove; no
+ longer used.
+ (apply_rcs_changes, RCS_deltas): Don't copy lines into allocated
+ space; linevector_add now does that for us.
+ (rcs_change_text, RCS_deltas): Don't call block_free.
+
+Tue Dec 23 08:28:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsbug.sh: Change bug-cvs address from prep.ai.mit.edu to gnu.org
+ per email from Martin Hamilton.
+
+Sun Dec 21 21:49:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_checkin): Disable keyword expansion when generating
+ the change text.
+ * sanity.sh: Move tests keyword-24 through keyword-27 into
+ new section keywordlog and expand greatly. Note that CVS 1.9.18
+ passes the new tests both local and remote but the current
+ version failed them both local and remote before this fix.
+
+Sat Dec 20 19:56:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_delete_revs): Clean up temporary files even if noexec.
+ Without this fix, basica-o5a in sanity.sh would leave files around.
+
+Thu Dec 18 13:05:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c: Fix typo in declaration (evecvp -> execvp) (credit to
+ Erik Walthinsen for reporting this). Only declare it if not
+ HAVE_UNISTD_H. Move declaration to before the first use.
+
+Tue Dec 16 12:59:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c: Collapse two identical declarations for join_file.
+
+Mon Dec 15 16:01:49 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (start_tcp_server): Remove calls to htons and add one
+ call to ntohs (init_sockaddr calls htons on the port argument).
+
+Mon Dec 15 00:07:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (failure_exit): New variable.
+ (get_server_responses): If it is set, then return
+ failure.
+ (updated_seen, updated_fname): New variables.
+ (update_entries): Use updated_fname if set. In the "move away
+ foo.c; it is in the way" case print "C" not "U", and set
+ failure_exit.
+ (handle_mt): If we get +updated tagged text, stash it away in
+ updated_fname rather than printing it immediately.
+ (handle_mt, get_server_responses): If we stashed a filename and
+ didn't get around to printing it, go ahead and print it.
+ * sanity.sh (conflicts2-142d2): Adjust to test for fix. Remote is
+ now like local was in terms of exit status and "C aa.c" message.
+
+Sun Dec 14 00:27:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Implement tagged text feature:
+ * update.c (write_letter): Take a single finfo argument rather
+ than file and update_dir. While we are at it change it to return
+ void (since the returned value always had been 0).
+ * update.c: Update callers.
+ * server.c, cvs.h (cvs_output_tagged): New function.
+ * client.c (responses): Add "MT" response.
+ (handle_mt): New function.
+ * update.c (write_letter): Output via cvs_output_tagged.
+
+Sun Dec 14 14:13:05 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * recurse.c (do_dir_proc): Only check for CVS/Repository if
+ W_LOCAL.
+ * sanity.sh (devcom-t2, devcom-t3): New tests for above patch.
+
+Sun Dec 14 00:27:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * root.c (parse_cvsroot): Initialize check_hostname (fixes thinko
+ in GSSAPI changes).
+
+Sat Dec 13 13:15:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c: Use indentation to indicate nesting of #ifdef's.
+
+ * client.c (connect_to_gserver): Reindent (in one place).
+
+Fri Dec 12 17:38:15 1997 Chris Provenzano <proven@cygnus.com>
+ and Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.h (CVSmethod): Add gserver_method.
+ * root.c (method_names): Add gserver.
+ (parse_cvsroot): Handle :gserver:.
+ * client.h (cvsauthenticate): Declare.
+ (cvs_gssapi_encrypt): Declare if HAVE_GSSAPI and ENCRYPTION.
+ (cvs_gssapi_wrap_buffer_initialize): Declare if HAVE_GSSAPI.
+ (connect_to_pserver): Update declaration.
+ (pserver_authenticate_connection): Declare when HAVE_GSSAPI and
+ SERVER_SUPPORT is defined in addition to other case.
+ * client.c: If HAVE_GSSAPI, include GSSAPI header files.
+ (gcontext): New static variable if HAVE_GSSAPI.
+ (connect_to_pserver): Add do_gssapi parameter. Change all
+ callers. Move rejection handling to bottom of function.
+ (recv_bytes): New static function if HAVE_GSSAPI.
+ (connect_to_gserver): Likewise.
+ (start_server): Handle gserver_method. Handle GSSAPI encryption
+ and authentication.
+ * server.c: Include <sys/socket.h> if HAVE_GSSAPI, in addition to
+ existing cases. If HAVE_GSSAPI, include GSSAPI header files.
+ Include <grp.h> even if AUTH_SERVER_SUPPORT is not defined.
+ (gcontext, cvs_gssapi_wrapping): New static variables if
+ HAVE_GSSAPI.
+ (cvs_gssapi_encrypt): New global variable if HAVE_GSSAPI and
+ ENCRYPTION.
+ (serve_gssapi_encrypt): New static function if HAVE_GSSAPI and
+ ENCRYPTION.
+ (serve_gssapi_authenticate): New static function if HAVE_GSSAPI.
+ (requests): Add Gssapi-encrypt if HAVE_GSSAPI and ENCRYPTION. Add
+ Gssapi-authenticate if HAVE_GSSAPI.
+ (switch_to_user): Compile if HAVE_GSSAPI, in addition to existing
+ cases.
+ (pserver_authenticate_connection): Likewise. Ifdef out part of
+ the code for AUTH_SERVER_SUPPORT. Handle a GSSAPI request.
+ (gserver_authenticate_connection): New static function if
+ HAVE_GSSAPI.
+ (cvsauthenticate): New global variable.
+ (struct cvs_gssapi_wrap_data): Define if HAVE_GSSAPI.
+ (cvs_gssapi_wrap_buffer_initialize): New function if HAVE_GSSAPI.
+ (cvs_gssapi_wrap_input): New static function if HAVE_GSSAPI.
+ (cvs_gssapi_wrap_output): Likewise.
+ * main.c (opt_usage): Mention -a.
+ (main): Handle -a. Handle pserver if HAVE_GSSAPI, in addition to
+ existing cases.
+ * login.c (login): Pass new argument to connect_to_pserver.
+
+Fri Dec 12 15:33:19 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * buffer.c (PACKET_SLOP): Define.
+ (packetizing_buffer_initialize): Use PACKET_SLOP when allocating
+ holdbuf.
+ (packetizing_buffer_input): Allow up to PACKET_SLOP bytes in
+ stackoutbuf.
+ (packetizing_buffer_output): Use just BUFFER_DATA_SIZE + 2 for
+ inbuf. Allow PACKET_SLOP + 4 extra bytes in stack_outbuf.
+ Correct >= to > in test of incoming number of bytes. Use
+ PACKET_SLOP in other tests.
+
+Fri Dec 12 10:27:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_tcp_server): Revise comment to reflect
+ SOCK_STRERROR and SOCK_ERRNO now being in use.
+
+Thu Dec 11 15:32:31 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (init_sockaddr): Compile if HAVE_KERBEROS, as well as
+ if AUTH_CLIENT_SUPPORT. Return a pointer to a struct hostent.
+ (start_tcp_server): Clean up. Use init_sockaddr. Use
+ SOCK_STRERROR and SOCK_ERRNO. Don't bind the socket.
+
+ Generalize buffering code used by Kerberos encryption routines
+ into a generic packetizing buffer. The new code in buffer.c is a
+ modified version of the code removed from server.c.
+ * buffer.c (struct packetizing_buffer): Define.
+ (packetizing_buffer_initialize): New function.
+ (packetizing_buffer_input): New static function.
+ (packetizing_buffer_output): New static function.
+ (packetizing_buffer_flush): New static function.
+ (packetizing_buffer_block): New static function.
+ (packetizing_buffer_shutdown): New static function.
+ * buffer.h (packetizing_buffer_initialize): Declare.
+ * server.c (struct krb_encrypt_data): Rename from
+ krb_encrypt_buffer, and remove all fields not related to
+ encryption.
+ (krb_encrypt_buffer_initialize): Just call
+ packetizing_buffer_initialize.
+ (krb_encrypt_input): New static function.
+ (krb_encrypt_output): New static function.
+ (krb_encrypt_buffer_input): Remove.
+ (krb_encrypt_buffer_output): Remove.
+ (krb_encrypt_buffer_flush): Remove.
+ (krb_encrypt_buffer_block): Remove.
+ (krb_encrypt_buffer_shutdown): Remove.
+
+Wed Dec 10 15:39:44 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * buffer.c (stdio_buffer_initialize): Correct formatting.
+
+Sun Dec 7 09:37:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb-0d0): New test, for checkout on existing
+ directory.
+
+Sat Dec 6 00:25:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (binwrap3): Clean up repository too. Clean up working
+ directory with "rm -r" not "rm -rf".
+
+Thu Dec 4 17:11:18 1997 Larry Jones <larry.jones@sdrc.com>
+
+ * subr.c (check_numeric): Don't reference argv[1] when argc is 1
+ (should be argv[0]).
+
+ * sanity.sh: Fix lines that look like conflict markers but aren't
+ to prevent problems checking in.
+ (binwrap3): Remove local CVSROOT when done so that later
+ tests that expect to create it don't fail.
+
+Thu Dec 4 18:19:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: Remove mempcpy definition. I think the polite way to
+ describe my feelings about mempcpy is something like "we don't
+ have agreement that it is a good idea".
+ * rcs.c (truncate_revnum): Don't call it.
+ * sanity.sh: Run multibranch2 test by default.
+ (multibranch2): Use ${TESTDIR} a few places.
+ (multibranch2-9): Accept "P file1" as well as "U file1".
+
+ * sanity.sh: Don't add 1997 to the copyright notice. Add GPL
+ terms. Add discussion of copyright issues.
+ * rcs.c (truncate_revnum, truncate_revnum_in_place,
+ compare_truncated_revnums): Reindent.
+
+1997-12-04 Jim Meyering <meyering@na-net.ornl.gov>
+
+ * subr.c (xstrdup): Use memcpy rather than strcpy.
+ (compare_revnums): Declare parameters to be `const'.
+ Remove unnecessary uses of xstrdup and corresponding frees.
+ (increment_revnum): Declare parameter to be `const'.
+ Use memcpy rather than strcpy.
+ (gca): Declare parameters to be `const'.
+ (check_numeric): Declare REV parameter to be `const'.
+ (file_has_markers): Declare parameter to be `const'.
+ (get_file): Declare `char*' parameters to be `const'.
+ * run.c (run_exec): Declare `char*' parameters to be `const'.
+ * cvs.h (mempcpy) [! HAVE_MEMPCPY]: Define it.
+ Add `const' to types in several prototypes.
+
+ * rcs.c (truncate_revnum): New function.
+ (truncate_revnum_in_place): New function.
+ (compare_truncated_revnums): New function.
+ (max_rev): New function.
+ (RCS_addbranch): Make BRANCH parameter `const'.
+ Use the above functions rather than open-coding them.
+ When BRANCH is a revision number, insert it *in order*
+ in the sorted list of branch numbers, not at the end.
+ Add assertion that insertion succeeds.
+ * sanity.sh (multibranch2): Test for this.
+ (Copyright): Add 1997.
+
+Dec 1997 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * wrapper.c (wrap_name_has): loop as far as wrap_count +
+ wrap_temp_count, not wrap_count + wrap_saved_count, otherwise
+ some wrappers get skipped.
+ (wrap_matching_entry): same.
+ * sanity.sh (binwrap3): new test, for import with
+ CVSROOT/cvswrappers and .cvswrappers specifying -k 'b' options.
+
+1997-11-30 Jim Meyering <meyering@na-net.ornl.gov>
+
+ * client.c (send_a_repository): Strip trailing slashes from the name
+ of the update directory. Otherwise, running `cvs update dir/' provokes
+ this failure `protocol error: illegal directory syntax in dir/' when
+ running in client/server mode.
+
+ * hash.c (insert_before): New function derived from addnode.
+ (addnode): Simply return insert_before.
+ (addnode_at_front): Simply return insert_before.
+ * hash.h (insert_before): Add prototype.
+
+ * server.c (dirswitch): Compute `strlen(dir)' once and save it,
+ rather than computing it four times. Also do s/illegal/invalid/ to
+ this diagnostic: "E protocol error: illegal directory syntax in %s".
+
+Sun Nov 30 18:03:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * admin.c: Fix comment (no longer a front-end to "rcs").
+
+ * error.c, error.h (rcserror): Remove.
+ * admin.c, rcs.c: Call error instead of rcserror. This changes
+ the format of these messages from "rcs: <path>: error" to "cvs
+ <command>: <path>: error". The former format wasn't quite what
+ RCS printed anyway (because RCS would sometimes print "ci", "co",
+ &c, not "rcs"), and preserving RCS's exact output probably is not
+ a good idea anyway (because it will make people think that the
+ error was caused by an external program). In two cases, I tidied
+ up the message in a more drastic fashion ("cannot stat" in
+ RCS_checkin and "could not diff" in RCS_delete_revs).
+
+ * sanity.sh (basica-o2b, binfiles2-o1, admin-18, admin-22-o10,
+ admin-22-o17): Look for "cvs <command>" not "rcs".
+
+ * run.c, cvs.h (run_setup): Replace varargs nonsense with a single
+ argument which gets parsed as the result of the vasprintf
+ used to.
+ * client.c, commit.c, logmsg.c, modules.c, rtag.c, tag.c, update.c,
+ wrapper.c: Update callers, either to do the sprintf themself or to
+ just call run_arg if it will do the job.
+ * rcscmds.c: Likewise for call_diff_setup and callers.
+
+ * run.c, cvs.h (run_args): Remove; nowhere used.
+
+Sat Nov 29 22:15:06 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Remove declaration of getwd; see lib/ChangeLog for
+ rationale.
+
+1997-11-29 Jim Meyering <meyering@na-net.ornl.gov>
+
+ * update.c (checkout_file): Initialize `backup'.
+
+ * diff.c (diff_fileproc): Initialize `tmp' and `fname'.
+
+ * modules.c (do_module): Initialize `server_dir_to_restore'.
+ (do_module): Initialize `value' in an else clause.
+
+ * rcs.c (RCS_checkin): Initialize `commitpt'.
+ (RCS_delete_revs): Initialize `revp'.
+ (RCS_copydeltas): Always initialize `insertbefore'.
+
+ * run.c (run_print): Define `outfn' even in error case.
+
+Mon Nov 24 17:28:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_findlock_or_tip): Prototype.
+ (RCS_checkin): Fix call to pass correct number of arguments.
+
+Sun Nov 23 10:34:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_dir_proc): Move check for CVS/Repository and
+ CVS/Entries to before where we call the direntproc.
+ * client.c (send_dirent_proc): Remove code to check for
+ CVS/Repository, now that recurse.c does it.
+ * sanity.sh (conflicts3-18 through conflicts3-19): New tests, for this.
+
+Sat Nov 22 10:54:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_dir_proc): Check that CVS/Repository and
+ CVS/Entries exist.
+ * sanity.sh (conflicts3-14 through conflicts3-17): New tests, for this.
+
+ * client.c (send_fileproc): Send options field from
+ vers->entdata->options not vers->options.
+ * cvs.h (struct entnode): Add comment (options and timestamp must
+ not be NULL).
+ * sanity.sh (binfiles-9 through binfiles-13, binfiles-sticky5,
+ keyword-17): Remove kludges for remote; tests for fix.
+
+ * update.c (update_fileproc): Fix comment; direct checkout is
+ still faster than patches for local but not for quite the
+ same reasons.
+
+ * add.c (add): Pass SEND_NO_CONTENTS to send_files.
+
+Wed Nov 19 18:25:03 1997 Mike Glendinning <mikeg@sequent.com>
+
+ * update.c (patch_file_write): Missing cast provided.
+
+Wed Nov 19 15:57:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_deltas): Solve trigraph problem (once and for all, I
+ hope) with 3 calls to cvs_output.
+
+Wed Nov 19 01:52:57 1997 Andy Piper <andyp@parallax.co.uk>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * classify.c (Classify_File), cvs.h (struct vers_ts), vers_ts.c
+ (Version_TS): Clarify NULL versus "" for options in comments.
+ * vers_ts.c (Version_TS): Treat "" the same way as NULL in options
+ and vers_ts->options.
+ * sanity.sh: New tests binfiles-sticky5 through binfiles-17 test
+ for this.
+
+1997-11-16 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * client.c (update_entries): parse server-sent entries line even
+ in the case of "cvs export", because we need to know if -kb option
+ is set.
+ Init `options' to NULL like anything else.
+
+Tue Nov 18 09:20:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.21.
+
+ * Version 1.9.20.
+
+Mon Nov 17 14:35:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (server_updated): If scratched_file and noexec are set,
+ clean up so we don't get a "duplicate Scratch_Entry" warning
+ later.
+ * sanity.sh: New tests conflicts3-10 to conflicts3-13, for this.
+
+ * sanity.sh (conflicts3): Don't allow "file1 was lost" messages
+ here; I don't think CVS actually produced them, and they don't
+ belong.
+
+Sun Nov 16 23:19:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Accept either "U file1" or "P file1".
+
+Fri Nov 14 12:32:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c: Add comment about cleaning up ,foo, file on ^C.
+
+Fri Nov 14 11:56:29 1997 Andy Piper <andyp@parallax.co.uk>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (unlink_file_dir): Don't print trace message in the
+ server.
+
+Fri Nov 14 11:28:55 1997 Jim Meyering and Jim Kingdon
+
+ * rcs.c (RCS_getdatebranch): If the branch we are looking for
+ doesn't exist, return a revision which matches the date, not
+ just NULL.
+ * sanity.sh (tagdate): New test, for this.
+
+Thu Nov 13 10:11:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb-21): Fix comment which described a behavior
+ which no longer exists.
+
+Wed Nov 12 16:24:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Clean up infrastructure made unnecessary by RCS library:
+ * rcscmds.c (diff_exec, diff_execv): Use literal "diff" not DIFF.
+ * options.h.in (DIFF), rcs.h (RCS, RCS_CI, RCS_DIFF,
+ RCS_RCSMERGE): Removed; no longer used.
+ * commit.c (commit), patch.c (patch_fileproc),
+ rcscmds.c (RCS_exec_rcsdiff), start of rcscmds.c: Update comments
+ to reflect librarification of RCS.
+ * options.h.in (RCSBIN_DFLT): Removed.
+ * main.c, cvs.h (Rcsbin, free_Rcsbin): Removed.
+ * main.c (main): Don't check RCSBIN environment variable. -b
+ global option is now a noop.
+ * cvs.h (RCSBIN_ENV): Removed.
+ * expand_path.c (expand_variable): $RCSBIN is now an error.
+ * mkmodules.c (config_contents): Remove RCSBIN.
+ * parseinfo.c (parse_config): RCSBIN now a noop.
+ * server.c (server): Don't put Rcsbin in PATH.
+
+Mon, 10 Nov 1997 Jim Kingdon
+
+ * rcs.c (RCS_checkin): Actually, when we get a change text
+ for a text file using get_file, we want text mode, although
+ the reasons are kind of subtle (see comment).
+
+ * rcs.c (RCS_checkin): Pass correct mode to get_file for
+ binary files.
+
+ * rcscmds.c: Declare vasprintf.
+
+Mon Nov 10 11:11:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ This fixes problems with windows-NT/run.c improperly quoting, and
+ is cleaner anyway.
+ * rcscmds.c (call_diff_setup, call_diff_arg, call_diff_add_arg,
+ call_diff_argv, call_diff_argc, call_diff_argc_allocated): New
+ functions/variables, lightly adapted from src/run.c.
+ * cvs.h, run.c (call_diff, call_diff3): Move from here...
+ * rcscmds.c: ...to here.
+
+Sun, 9 Nov 1997 Jim Kingdon
+
+ * rcs.c (rcs_internal_unlockfile): Call rename_file not rename.
+ This makes it work on NT again.
+
+Sun Nov 9 16:54:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (diffmerge2): Protect keywords against unwanted
+ expansion. They got clobbered and the testcase stopped working
+ when I checked it in.
+
+Fri Nov 7 13:23:38 1997 Karl Fogel <kfogel@floss.red-bean.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (diffmerge1, diffmerge2): new tests, for bugs, or
+ potential bugs, in ../diff/analyze.c which were fixed by Paul
+ Eggert's patch.
+
+Sun Nov 9 10:28:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_settag): Reindent.
+
+ * rcs.c (rcs_internal_lockfile): Fix typo (thow -> throw).
+
+Sat Nov 8 15:58:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (cvsadm): Remove most of the tests which tested
+ CVS/Root. This takes the run time for the cvsadm tests from
+ about 5 minutes 15 seconds to about 4 minutes 10 seconds with no
+ significant loss in coverage.
+
+ * rcs.c (rcs_internal_lockfile): Check for errors from system
+ calls. If open() gives an error, don't muck with stat and errno
+ (I don't know what the RCS code that this comes from was trying to
+ do, but it clearly isn't accomplishing anything here).
+ (RCS_rewrite, RCS_delete_revs): Check for errors from system calls.
+
+Sat Nov 1 14:21:29 1997 Michael L.H. Brouwer <michael@thi.nl>
+
+ * rcs.c (RCS_checkin): Change type of bufsize from int to size_t.
+ (RCS_delete_revs): Change type of bufsize and len from int to size_t.
+ (RCS_getdeltatext): Change type of textlen from int to size_t.
+ * rcs.h (struct deltatext): Change len from int to size_t to keep
+ the compiler happy on systems where size_t is unsigned int.
+ [This goes well beyond keeping the compiler happy; if sizeof
+ (size_t) != sizeof (int), the old code was quite broken -kingdon]
+
+Sat Nov 1 14:21:29 1997 Michael L.H. Brouwer <michael@thi.nl>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_checkin): When checking if we were holding the lock
+ use delta->author instead of user since the latter might have been
+ clobbered by a call to getcaller. This resulted in the failure of
+ test basica-7.
+ [I don't completely follow the scenario where it gets clobbered,
+ it but sounds vaguely plausible and the replacement seems
+ cleaner, precisely because it avoids allocation issues -kingdon]
+
+Wed Nov 5 20:16:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkin.c, checkout.c, commit.c, cvs.h, import.c, login.c,
+ main.c, update.c: Change FALSE to 0 and TRUE to 1 and replace
+ monstrosities like "cvswrite == TRUE" with just "cvswrite". FALSE
+ and TRUE sometimes conflicted with system headers (NextStep3.3?),
+ but more to the point, good old 1 and 0 are fine and were used by
+ most of CVS already.
+
+Tue Nov 4 12:19:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_checkin, RCS_lock, RCS_unlock): Rename local variable
+ quiet to checkin_quiet or some such, to avoid confusion with
+ global variable quiet.
+
+ * lock.c: Update comment to refer to add_rcs_file rather than "rcs
+ -i".
+
+ * rcs.h (struct rcsnode): Add comments for all fields.
+ * rcs.c (RCS_delete_revs): Refuse to delete revisions which have
+ symbolic names. Fix fencepost bug which caused us to sometimes
+ check one more revision than we should for locks, branches, and
+ this.
+ (findtag): New function, to help above code.
+
+ * admin.c (admin): Take out writelocks not readlocks. This has
+ been a bug "forever", but may become more noticeable with
+ rcs_internal_lockfile relying on the writelocks.
+
+Mon Nov 3 10:17:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_rewrite): Don't write the file if noexec.
+ * sanity.sh (basica, branches): Test for this.
+
+Sat Nov 1 10:01:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.h (struct deltatext): Comment text and log fields.
+
+ * admin.c (admin_fileproc): Call RCS_reparsercsfile not
+ RCS_fully_parse. Don't muck with ->other field in RCSVers (it
+ doesn't need to be set).
+ * rcs.h, rcs.c (RCS_reparsercsfile): No longer static. No point
+ in having this static when RCS_rewrite and RCS_fully_parse are not.
+ * rcs.c (getdelta): Remove obsolete comment about not storing the
+ newphrases from the deltas, since we now do.
+
+Sat Nov 1 10:01:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+ and Paul Eggert
+
+ * rcs.c (rcs_internal_lockfile): Clarify the comments about O_EXCL
+ and such matters.
+
+Sat Nov 1 10:01:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_delete_revs): Pass force_tag_match to RCS_settag.
+ * sanity.sh (basica-o2a, basica-o2b): Test for this.
+
+1997-11-01 Peter Brandstrom <d91-pbr@nada.kth.se>
+
+ * sanity.sh: Use ${username} more places.
+
+Sat Nov 1 00:14:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (rcs_internal_lockfile): Add comments about what we are
+ trying to accomplish here (versus what RCS tries to accomplish).
+
+ * rcs.c (RCS_parsercsfile_i): Clarify/expand comment about
+ the purpose of having both this and RCS_reparsercsfile.
+ (RCS_rewrite): Add comment about how this works.
+
+ * admin.c (admin_fileproc): Add comment about call to
+ RCS_fully_parse not RCS_reparsercsfile.
+ * rcs.h: Comment on what delta_pos field of struct rcsnode is.
+
+Fri Oct 31 16:38:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+ and Abe Feldman
+
+ * client.c (update_entries): If UTIME_EXPECTS_WRITABLE, if
+ necessary change the file to be writable temporarily to set its
+ modification time.
+
+Thu Oct 30 17:42:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * admin.c (admin): Deal with new :: syntax for ranges.
+ * rcs.c, rcs.h (RCS_delete_revs): New arg inclusive (set for the old
+ behavior, clear to enable new code).
+ * admin.c (admin_fileproc): Set it if :, clear it if ::.
+ * sanity.sh (basica, head, branches, log): Add tests for this feature.
+
+ * admin.c (admin_fileproc): Clean up the error message which
+ happens if one of the RCS_* functions returns an error status; it
+ is confusing to say that "rcs" failed now that this is implemented
+ internally.
+ * sanity.sh (admin): Update accordingly.
+
+Wed Oct 29 07:07:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (admin-22-o24): New test, tests that admin -o
+ correctly munged the deltatexts on a branch too.
+
+ * rcs.c (RCS_delete_revs): If we are deleting an entire branch,
+ delete the node in ->branches rather than setting the ->key to the
+ bogus value NULL.
+ * rcs.c (RCS_delete_revs): If "rev1" equals "branchpoint", then set
+ "before" to the revision on the trunk that we branch from.
+ * rcs.c (RCS_delete_revs): Don't set rev2 to revp->version (the
+ code is missing an xstrdup, but it doesn't matter because rev2
+ isn't used after this point).
+ * sanity.sh (binfiles2-o2 to binfiles2-o4): New tests, for this.
+
+Tue Oct 28 19:30:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_delete_revs): Restore code which passes rev2 to
+ RCS_getbranchpoint if rev1 is NULL; it still makes sense for the
+ non-trunk case. Fixes admin-22-o22 in testsuite.
+
+ * sanity.sh (admin-18): Adjust to reflect "rcs failed" no longer
+ being suppressed by global -q option.
+
+ * rcs.c (RCS_delete_revs): If rev1 == NULL and rev2 is on the
+ trunk, handle it the same way we do everything else--by swapping
+ the two. This replaces the code which tried to kludge what we
+ passed to RCS_getbranchpoint (which didn't work).
+ * sanity.sh (binfiles2-o1 to binfiles2-o4): New tests, for this fix.
+ * admin.c (admin_fileproc): Don't have -q global option suppress
+ "rcs failed" message.
+
+1997-10-28 Jim Kingdon
+
+ * log.c (printlock_proc), rcs.c (putlock_proc): Prototype.
+ * rcs.c (rcs_internal_lockfile): Only try to call fchmod if
+ HAVE_FCHMOD is defined.
+
+Tue Oct 28 10:27:03 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_deltas): Don't use \? in string if __STDC__ is not
+ defined.
+
+ * rcs.c (make_file_label): Remove extraneous `+'.
+
+Mon Oct 27 14:40:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * status.c (status): Don't pass SEND_NO_CONTENTS to send_files.
+
+Sat Oct 25 00:33:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_delete_revs): Use : not - for range in error message.
+
+ * rcs.h: Add comment about '\0' in RCS fields.
+
+ * rcs.c (getdelta): Add comment about branches and next field
+ being mandatory.
+
+ * rcs.c (RCS_reparsercsfile, RCS_deltas), sanity.sh (reserved):
+ Reindent sections which were misindented as a result of recent
+ changes.
+
+Fri Oct 24 10:22:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_findlock_or_tip): Don't worry about file ownership
+ and nonstrict locking when returning the default branch or head.
+ The most conspicuous problem with the old code is that in the
+ error case it would examine rstat.st_uid when it had not been
+ set. For a discussion of more fundamental reasons, see comment.
+
+ * admin.c (admin_fileproc): In handling -A, don't handle relative
+ pathnames differently from absolute pathnames. See comment for
+ rationale. If problem opening the file, give a nice error not a
+ coredump.
+ * sanity.sh (admin-19a-admin, admin-19a-log, admin-19a-fix):
+ New tests, test for traditional "cvs admin -A" behavior with
+ relative pathnames.
+ * sanity.sh (admin-19a-nonexist): Test for the core dump fix.
+ * sanity.sh (admin-22-o1): Look for ${PROG} not cvs.
+
+ * sanity.sh (reserved-16): Remove commitinfo change with "cvs
+ commit" not "cvs admin -o". In addition to commit being The Right
+ Thing on general principles, cvs admin -o doesn't work because it
+ doesn't rebuild the administrative file database.
+
+ * update.c (patch_file): If the first revision does not exist in
+ the RCS file, fall back to sending entire file. Fixes
+ admin-22-o15 in make remotecheck.
+
+1997-10-23 enami tsugutomo <enami@but-b.or.jp>
+
+ * rcs.c (RCS_checkin): Unlink temporary files stored in variable
+ `tmpfile' and `changefile'.
+
+Wed Oct 22 12:16:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (rcs_lockfilename): Allocate enough memory for terminating
+ '\0'.
+
+ * admin.c (admin_fileproc): Don't support '-' for ranges in "cvs
+ admin -o".
+ (admin): Adjust comment.
+
+ * rcs.h (RCSVers): New field other_delta.
+ * rcs.c (free_rcsvers_contents): Also free other_delta.
+ (getdelta): Read newphrases from deltas into other_delta field.
+ (putdelta): Write those newphrases.
+ * sanity.sh (rcs-8a): New test, for this fix.
+ * admin.c (admin_fileproc): If "-b" without argument, then set
+ branch to NULL, not "" (uncovered by rcs-8a test).
+ * rcs.c (putrcsfield_proc): Add comment about how we (mis)handle
+ values in newphrases.
+
+ * sanity.sh (reserved): Instead of looking for rcslock.pl in CVS
+ distribution, just use our own equivalent.
+
+ * rcs.c (RCS_rewrite): Call ferror before fclose to avoid "Invalid
+ argument" warnings.
+
+Mon Oct 20 00:30:16 1997 Tim Pierce <twp@twp.tezcat.com>
+
+ [I removed a ChangeLog entry for a change to sanity.sh (editor),
+ because the actual change was not made. With this change, CVS no
+ longer runs RCS. I'll be checking in my cleanups shortly. -kingdon]
+
+ Librarify `ci'.
+ * rcscmds.c, cvs.h (RCS_checkin): Removed.
+ * rcs.c, rcs.h (RCS_checkin, RCS_getbranchpoint, RCS_addbranch,
+ RCS_findlock_or_tip): New functions. RCS_checkin completely
+ rewritten to eliminate RCS 5.7; change `rcs' parameter from string
+ to RCSNode, so we can update RCSNode without re-reading from
+ disk.
+ * checkin.c (Checkin): Updated RCS_checkin caller, moved RCS_parse
+ call to before RCS_checkin.
+ * import.c (add_rev): Updated caller.
+ * commit.c (remove_file): Updated caller.
+ (checkaddfile): Updated caller. Parse `rcsfile' after
+ calling add_rcs_file. Free `rcsfile' instead of asserting it to
+ be NULL.
+
+ Librarify `rcs'.
+ * rcscmds.c, cvs.h (RCS_exec_settag, RCS_exec_deltag,
+ RCS_exec_setbranch, RCS_exec_lock, RCS_exec_unlock): Removed.
+
+ * rcs.c (RCS_settag): Rewritten to eliminate RCS 5.7.
+ * commit.c (checkaddfile): Call RCS_rewrite after calling RCS_settag.
+ * import.c (add_tags): Same.
+ * rtag.c (rtag_fileproc): Same.
+ * tag.c (tag_fileproc): Same.
+
+ * rcs.c (RCS_deltag): Rewritten to eliminate RCS 5.7. Remove
+ `quiet' parameter, since this function no longer prints any output.
+ * commit.c (remove_file): Update caller. Also call RCS_rewrite
+ after RCS_deltag.
+ * rtag.c (rtag_delete): Same.
+ * tag.c (tag_fileproc): Same.
+
+ * rcs.c (RCS_setbranch): Rewritten to eliminate RCS 5.7.
+ * commit.c (remove_file): Call RCS_rewrite after calling RCS_setbranch.
+ (fixbranch): Same.
+ (lock_RCS): Same.
+
+ * rcs.c (RCS_lock): Rewritten to eliminate RCS 5.7. Change third
+ arg to mean `quiet' and not `noerr', permitting admin_fileproc to
+ run RCS_lock verbosely.
+ * commit.c (lock_RCS): Update callers; call
+ RCS_rewrite after RCS_lock.
+ (remove_file): Same. Call RCS_lock quietly.
+ * import.c (add_rev): Same. Do not print `fork failed' error
+ message, since we're no longer forking.
+
+ * rcs.c (RCS_unlock): Rewritten to eliminate RCS 5.7. Change
+ `noerr' arg to mean `quiet', permitting admin_fileproc to run
+ RCS_unlock verbosely. Use notify_do when breaking another user's
+ lock. Include "edit.h" for notify_do prototype.
+ * checkin.c (Checkin): Update caller; use RCS_rewrite after RCS_unlock.
+ * commit.c (unlockrcs): Same.
+ * import.c (add_rev): Same.
+
+ * rcs.c, rcs.h (RCS_getlocks, RCS_addaccess, RCS_delaccess,
+ RCS_getaccess, RCS_delete_revs): New functions.
+ (expand_keywords, RCS_lock, RCS_unlock): Use RCS_getlocks.
+ * log.c (log_fileproc, log_version): Call RCS_getlocks. Don't add
+ bogus ";locker" nodes to RCSVers nodes -- walk lock list with
+ printlock_proc.
+ (printlock_proc): New function.
+
+ * admin.c (admin_fileproc): Largely rewritten: call internal RCS
+ library functions instead of forking RCS processes.
+ (admin, admin_fileproc): Obsolete -V option.
+ (struct admin_data): Remove `version' member.
+ * sanity.sh (admin-24): Remove -V test case.
+
+ New functions for reading and writing RCS files.
+ * rcs.h (struct deltatext, Deltatext): New types.
+ (struct rcsversnode): New members `text' and `outdated'.
+ (struct rcsnode): New members `access', `locks', `strict_locks',
+ `comment', and `desc'.
+ * rcs.c (RCS_reparsercsfile, expand_keywords): Use new RCSNode members.
+ (free_rcsnode_contents): Free them.
+ * log.c (log_fileproc): Use new RCSNode members instead of ->other.
+
+ * rcs.c (getdelta, RCS_getdeltatext, freedeltatext, do_locks,
+ RCS_putadmin, RCS_putdtree, RCS_putdesc, putdelta,
+ putrcsfield_proc, putsymbol_proc, RCS_copydeltas, putdeltatext,
+ RCS_rewrite, getrevnum, rcs_internal_lockfile,
+ rcs_internal_unlockfile, rcs_lockfilename): New functions.
+
+ (RCS_reparsercsfile): Use getdelta, making sure fp is positioned
+ correctly before calling it. Skip `head' and `branch' nodes: we
+ have already parsed them, and they were being added incorrectly to
+ rcs->other. Do not signal error if the RCS file has an empty
+ delta tree; this made it impossible for RCS_checkin to perform an
+ initial checkin. Remove `all' parameter; always store all RCS
+ fields.
+ (RCS_fully_parse, RCS_gettag, RCS_getbranch, RCS_getdate,
+ RCS_getdatebranch, RCS_getrevtime, RCS_symbols, translate_symtag,
+ RCS_isdead, RCS_getexpand, RCS_checkout, annotate_fileproc):
+ Update all callers to remove `all' parameter.
+
+ (getrcskey): Do not append trailing whitespace to a value. This
+ corrupted some log fields and wrecked some sanity.sh test cases.
+
+ (free_rcsvers_contents): New function.
+ (rcsvers_delproc): Call it.
+
+ * rcs.h (NODELTA): Removed symbol; now obsolete (since RCSNodes
+ do not go stale).
+ * import.c (add_rev): Removed NODELTA reference.
+ * rcs.c (RCS_reparsercsfile, RCS_checkout, RCS_settag, RCS_deltag,
+ RCS_setbranch, RCS_lock, RCS_unlock, RCS_deltas): Removed NODELTA
+ references.
+
+ Miscellaneous changes to support RCS librarification and fix some bugs.
+ * subr.c, cvs.h (line2argv): Add `sepchars' argument.
+ * modules.c (cat_module, admin_fileproc): Update all callers.
+
+ * subr.c, cvs.h (compare_revnums, increment_revnum): New functions.
+ (make_message_rcslegal): Strip whitespace from end of
+ lines and end of string, a la `cleanlogmsg' in RCS 5.7.
+ (get_file): Terminate buf with \0, extending it if
+ necessary. Read from stdin if `name' arg is NULL.
+ * admin.c (admin_fileproc): Call get_file to read -t arg from stdin.
+
+ * error.c, error.h (rcserror): New function, used everywhere.
+
+ * hash.c, hash.h (addnode_at_front): New function.
+ * rcs.c (RCS_settag, RCS_lock): Call it.
+
+ * import.c, cvs.h (expand_at_signs): Make extern.
+ * rcs.c (putrcsfield_proc, RCS_putadmin, RCS_putdesc,
+ putdeltatext): Call it.
+
+ * rcs.c (make_file_label): Use last_component to get file's basename.
+
+ * sanity.sh (srcdir): New variable.
+ (rcs-7): Remove newphrase warning, no longer produced by CVS.
+ (rcs-8): Permit random whitespace around newphrase fields.
+ (admin-22): New test cases for -o options: admin-22-o{1..23}.
+ (reserved): New test cases for rcslock.pl: reserved-{8..16}.
+
+Tue Oct 21 16:48:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * tag.c (tag_check_valid): Add comment about locking or lack
+ thereof.
+
+1997-10-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.19.
+
+1997-10-19 Jim Kingdon
+
+ * Version 1.9.18.
+
+Wed Oct 15 15:21:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (username): Add '-' to characters allowed in user name.
+
+ * rcscmds.c (diff_exec): Remove item about external diff
+ programs. It doesn't really belong here now that diff is
+ librarified and TODO #191 now mentions this.
+
+ * checkout.c (checkout_proc): Add comment about assuming '/' is
+ the only path separator.
+ * options.h.in: Fix thinko (CVS/Repository -> CVS/Root).
+
+Mon Oct 13 22:46:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (commit): Add comment about CVS_BADROOT and command
+ other than "commit".
+
+1997-10-11 Noel Cragg <noel@swish.red-bean.com>
+
+ * options.h.in: RELATIVE_REPOS has been checked for bitrot -- it
+ now works again. Change the comment before the #define to say
+ that we'll be switching to it soon.
+
+ * sanity.sh (basicb-1, basicb-1a): update dotest strings to match
+ no matter if we're running with RELATIVE_REPOS defined or not.
+ (basicb-9b, basicb-9c): same.
+
+ * sanity.sh (basicb-9b, basicb-9c): modified tests, since the
+ checkout.c fix changes the way this test module is checked out.
+ (basicb-9d, basicb-9e, basicb-9f): new tests, same.
+ (basicb-18): modify test, same.
+ (cvsadm): new set of exhaustive tests to check the contents of
+ CVS/Root and CVS/Repository files under various conditions. As a
+ side effect, it tests the behavior of the "-d" flags (command line
+ and modules file).
+ (modules3-7e through modules3-7h): removed, since these tests were
+ a small subset of what is tested in the new cvsadm section.
+ (modules-1b, modules-1c): same.
+ (modules-2b, modules-2c): same.
+ (modules-3b, modules-3c, modules-3e, modules-3f): same.
+
+ * create_adm.c (Create_Admin): be a bit more verbose when using
+ trace mode.
+
+ * checkout.c (checkout_proc): rewrote the code that sets the where
+ variable and the code that matches directory names with repository
+ directories. This fixes a long-standing bug in CVS. (It used to
+ be the case that "cvs co -d foo <mod1> <mod2>" would not properly,
+ where <mod1> and <mod2> where defined in the modules file. While
+ the first module would be checked out correctly, the second would
+ be checked out under the name of the directory to which the module
+ referred rather than the module name!). This fix also allows us
+ to check out things into directories that are more than one deep
+ (e.g. "cvs -d foo/bar/baz co blah" will now work).
+ (checkout): remove code that performed a CHDIR if the
+ number of arguments specified was greater than one, since it's no
+ longer necessary. Also remove the code that prevented us from
+ doing "cvs co -d <dir1>/<dir2>" without <dir1> existing, since
+ checkout_proc handles things correctly now.
+
+ * cvs.h: fix typo.
+
+ * rtag.c (rtag): reformat so that we don't run over 80 characters
+ per line.
+ (rtag_dirproc): same.
+
+ * sanity.sh: change all old test cases to use pass and fail
+ functions rather than doing some combination of echo and exit
+ themselves.
+
+ * commit.c (commit_direntproc): remove the "warm fuzzy" -- this
+ code never gets called when running in client/server mode, and we
+ should have CVS' output match as much as possible between the two
+ modes. Moreover, there is no analogous place to put this same
+ message when we're running in c/s mode.
+ (find_direntproc): print the same "fuzzy" as in check_direntproc
+ so that local and c/s mode have the same messages.
+ * sanity.sh (187a3): update test case to reflect the above.
+
+Thu Oct 9 10:57:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * parseinfo.c (parse_config): Add comment about compatibility
+ issues with adding keywords.
+
+Wed Oct 8 16:40:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (do_dir_proc), commit.c (check_direntproc,
+ commit_direntproc, find_dirent_proc): If this
+ directory doesn't exist, skip it.
+ * diff.c (diff_dirproc): Reindent.
+ * sanity.sh (deep-4b0a, deep-4b0b): Check for this fix.
+
+Thu Sep 26 16:30:00 1997 Larry Jones <larry.jones@sdrc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (checkout_file): Don't set timestamp in noexec mode.
+ * vers_ts.c (Version_TS): Add comment about ignoring errors from
+ utime.
+ * sanity.sh (conflicts3): New tests, for this fix.
+
+Fri Oct 3 09:47:04 1997 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (168): use PROG instead of CVSBASE, since they are
+ equal.
+ (importb-2): refer to PROG instead of "cvs" in error message.
+
+ * add.c (add): use PROGRAM_NAME in the error message rather than
+ "cvs".
+ * classify.c (Classify_File): same.
+ * commit.c (find_fileproc): same.
+ * sanity.sh: change all add notification messages to refer to PROG
+ rather than "cvs". Fixed nasty quoting in several places at the
+ same time, replacing older "'command'" forms with newer
+ ".command." for simplicity.
+
+Sat Sep 27 01:37:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (rcslib-merge-8): Accept "P file1" as well as "U file1".
+
+Fri Sep 26 22:24:10 1997 Noel Cragg <noel@swish.red-bean.com>
+
+ * create_adm.c (Create_Admin): assign our duplicate pointer `cp'
+ after the xrealloc of `reposcopy' because the latter might have
+ changed addresses.
+
+Fri Sep 26 14:25:59 1997 Tim Pierce <twp@twp.tezcat.com>
+
+ * run.c (call_diff): Don't reset optind; this is done by diff_run now.
+
+ Librarify rcsmerge/diff3.
+ * rcscmds.c, cvs.h (RCS_merge): Rewritten from scratch: check out
+ selected files and diff3 them. Take new `rcs' and `workfile'
+ arguments, so we can resolve symbolic tags and manipulate the
+ working file.
+ * update.c (merge_file, join_file): Update RCS_merge calls.
+ * run.c, cvs.h (call_diff3): New function.
+
+ * sanity.sh (rcslib): New tests, rcslib-merge-{1..13}.
+
+Fri Sep 26 22:59:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * create_adm.c (Create_Admin): Fix thinko in Noel's change: keep
+ track of the originally allocated "cp" and free it, rather than
+ calling free on a pointer which may point halfway into the allocation.
+ * repos.c (Sanitize_Repository_Name): Per HACKING, assert that
+ repository != NULL, rather than just silently returning if NULL.
+ Reindent a line.
+
+Fri Sep 26 15:40:00 1997 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (modules): add tests modules-[123]* that make sure the
+ administrative files get rebuilt in various cases.
+
+ * add.c (combine_dir): removed function, since we no longer need
+ to worry about stripping the "." path element out. Changed the
+ two callers to simply concatenate their two arguments.
+
+ * recurse.c (do_dir_proc): don't bother trying to strip off "." in
+ the repository name since the below changes fix that behavior --
+ simply concatenate the repository and directory names together.
+
+ * checkout.c (checkout_proc): sanitize the repository name after
+ constructing it (we may create "/path/to/repos/.", but we don't
+ want that to be passed around). Remove the code that tacks on
+ "/." when constructing top_repository, since the below changes fix
+ that behavior. Added comments to the part of this function that
+ builds administrative files.
+
+ * sanity.sh (basicb): now that the below weirdness is fixed, the
+ extra "." path element in test basicb-0c doesn't appear when a
+ top-level file is checked out. Remove it from the expect string.
+
+ * create_adm.c (Create_Admin): now that the repository name isn't
+ floating around with "." as the last path element, make creation
+ of the top-level administrative files a special case -- save the
+ repository name as "/path/to/repos/." Why? I considered not
+ including the "." but didn't know how it would affect the remote
+ protocol when RELATIVE_REPOS was defined (do we have a way of
+ sending "" via the protocol?). After I make sure that the
+ RELATIVE_REPOS patches still work, I'll check the "" possibility
+ so we don't have to have a this special case.
+
+ * repos.c (Sanitize_Repository_Name): new function that removes
+ (if present) the trailing slash and "." component from the
+ repository name. Many routines break if we don't guarantee this.
+ See the comment before the function for complete information.
+ (Name_Repository): call Sanitize_Repository_Name before returning
+ the value.
+ * cvs.h: add prototype for Sanitize_Repository_Name.
+
+Fri Sep 26 14:19:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h (CVS_CMD_USES_WORK_DIR): Fix comment (the sense of the
+ flag is not reversed from what it would seem; when I thought so it
+ was because I was misreading the lookup_command_attribute code).
+
+Thu Sep 25 23:14:47 1997 Noel Cragg <noel@swish.red-bean.com>
+
+ * parseinfo.c (Parse_Info): fix typo in the trace message.
+
+Thu Sep 25 14:22:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * build_src.com: Also link with diff.olb.
+
+ * main.c (Make_Date): If gmtime returns NULL, try localtime.
+
+Wed Sep 24 19:18:40 1997 Noel Cragg <noel@swish.red-bean.com>
+
+ * checkout.c (checkout): fix typo in comment.
+
+Wed Sep 24 08:31:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (patch_file): Revise comments about diff -a now that
+ diff is librarified.
+
+Sun Sep 21 21:28:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (call_diff): Sleep for a second, in hopes of helping with
+ out of order bugs.
+
+Sat Sep 20 07:19:18 1997 Tim Pierce <twp@twp.tezcat.com>
+
+ Integrate diff library into CVS.
+ * run.c, cvs.h (call_diff): New function.
+ * rcscmds.c (diff_exec, diff_execv): Get diffs from call_diff
+ instead of running diff as a subprocess.
+ * Makefile.in (cvs): Add ../diff/libdiff.a.
+
+ * diff.c (longopts, diff): Use 131 for --ifdef, fixing Jim's thinko
+ (using 147 for both --side-by-side and --ifdef).
+
+ * sanity.sh (rcslib): Added tests rcslib-diffrgx-*, to test
+ handling of regex diff options.
+
+1997-09-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ (Note that this requires that DIFF support -L. I'll be checking
+ in a fix to that in a moment, but I wanted separate checkins in
+ case that helps with clarity).
+ Tweaks to rcsdiff librarification:
+ * sanity.sh (rcslib): Change "cvs" to "${PROG}" and subcommand
+ names (e.g. "add") to "[a-z]*". Former should deal with ${testcvs}
+ being "cvs.old" or something; latter fixes make remotecheck.
+ * rcs.c (make_file_label): Take into account strlen (rev) when
+ allocating space. Removes a FIXME and probably fixes a buffer
+ overrun security hole.
+ * rcscmds.c (RCS_exec_rcsdiff): Remove #if 0'd code to call
+ rcsdiff. Tim says he has compared the new code with rcsdiff code
+ and is confident that the behavior is preserved, so we need to
+ nuke the comment which says this has not been done. #if 0 isn't
+ really a very good way to document the way it used to work anyway;
+ the old code is still in CVS.
+ * diff.c: Add comment about rcsdiff options that we don't support,
+ which Tim had sent in email. Remove -T and -y, as the
+ previous meaning had been very confused.
+
+1997-09-21 Tim Pierce <twp@xochi.tezcat.com>
+
+ Librarify rcsdiff.
+
+ * diff.c (have_rev1_label, have_rev2_label): New variables.
+ (diff): Generate file labels with make_file_label if necessary;
+ pass labels, revisions and working file name to RCS_exec_rcsdiff.
+ * rcscmds.c, cvs.h (RCS_exec_rcsdiff): Completely revised function
+ to eliminate rcsdiff dependency, based on patch from JimK.
+ (diff_execv): New function, to exec diff with explicit -L args.
+ * rcs.c, rcs.h (make_file_label): New function.
+ (RCS_output_diff_options): New function.
+ * sanity.sh (rcslib): New test.
+
+Fri Sep 19 15:08:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_nodeisbranch): Assert that RCS is non-NULL.
+ * commit.c (remove_file), rcs.c (RCS_getversion), rtag.c
+ (rtag_fileproc), status.c (status_fileproc, tag_list_proc), tag.c
+ (tag_fileproc): Call RCS_nodeisbranch not RCS_isbranch
+ in contexts where we know the RCS argument is non-NULL.
+
+ * commit.c (find_fileproc): Pass tag not NULL to Version_TS for
+ the tag.
+ * vers_ts.c (Version_TS): Improve (somewhat) the introductory
+ comment.
+ * sanity.sh (editor): New test editor-9 tests for above fix.
+ Renumber/tweak surrounding tests to fit.
+
+ * log.c (log_version): If p->data is NULL, it is an empty log
+ message.
+ * sanity.sh (rcs-14): New test, tests for above fix (previously
+ this was a coredump).
+
+Thu Sep 18 08:45:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (rcs-7): Fix stupid ${TESTDIR} omission.
+
+Wed Sep 17 16:27:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (rcs): New tests rcs-5 through rcs-13 test for
+ getdate.y fix (rcs-12 and rcs-13 both failed with the buggy
+ getdate.y).
+
+Tue Sep 16 00:07:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (editor): Clean up first-dir at end of test.
+
+ * sanity.sh (editor): New tests test do_editor.
+
+ * commit.c (commit): For the client, if we got the log message
+ from do_editor and there was an error, don't toss the message.
+
+Mon Sep 15 14:27:54 1997 martin.sjoelin@ubs.com
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (RCS_checkout): fwrite in bite-size pieces, not the whole
+ file in one fwrite.
+
+Sun Sep 14 12:23:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (check_fileproc): If the file has "conflict
+ indicators", spit a warning and proceed with the checkin.
+ * sanity.sh (conflicts): Adjust tests conflicts-132,
+ conflicts-status-3, conflicts-133, and conflicts-status-4
+ for new behavior.
+
+Fri Sep 12 11:12:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c, admin.c, checkin.c, checkout.c, classify.c, commit.c,
+ create_adm.c, cvsrc.c, diff.c, entries.c, find_names.c, hash.c,
+ import.c, lock.c, log.c, logmsg.c, main.c, modules.c, myndbm.c,
+ no_diff.c, parseinfo.c, patch.c, rcs.c, rcscmds.c, recurse.c,
+ remove.c, repos.c, root.c, rtag.c, status.c, subr.c, tag.c,
+ update.c, vers_ts.c, hash.h, rcs.h, options.h.in: Change "CVS 1.4
+ kit" to "CVS source distribution".
+
+ * sanity.sh: Comment out call to "whoami".
+
+Thu Sep 11 10:09:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (classify_file_internal): Add comment about saving
+ quiet vs. saving really_quiet.
+
+ * sanity.sh (newb-123j0): Use two regexps instead of assuming that
+ expr has "\(", "\|", and "\)". If we want to require the latter,
+ we should check for it up front, rather than let people get
+ halfway through and wonder why the test failed.
+
+Tue Sep 9 19:22:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c (expand_path): If GETPWNAM_MISSING is defined,
+ just give an error instead of calling getpwnam.
+
+ * subr.c (getcaller): If SYSTEM_GETCALLER is defined, call it
+ instead of all the getlogin/getpwuid/etc.
+ * wrapper.c (wrap_setup): Call get_homedir not getpwuid.
+
+Mon Sep 8 17:54:14 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicc): Change ls -1 to echo *; according to
+ larry.jones@sdrc.com, ls -1 isn't portable.
+
+Sun Sep 7 07:45:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basic2): In test basic2-64, match usernames with
+ ${username}.
+
+ * root.c: Reindent a few things.
+ * root.c, cvs.h (same_directories): Remove. Never used,
+ portability hassle.
+
+ * add.c (add_directory): When checking for CVSADM, call fncmp not
+ strcmp. I actually suspect this code doesn't do much these days,
+ but fncmp clearly will make more sense than strcmp.
+
+ * rtag.c (rtag_usage), tag.c (tag_usage): Reword to hopefully be
+ clearer that -r takes either numeric or symbolic revision.
+
+ * ignore.c (ign_dir_add, ignore_directory): Reindent. Tweaks to
+ comments.
+
+ * update.c (checkout_file): Only ignore existence_error from
+ unlink_file_dir, not all errors.
+
+ * checkout.c (safe_location): Check for errors from xgetwd.
+ * create_adm.c (Create_Admin): Remove call to xgetwd; it is just
+ debugging code anyway and it wasn't checking for errors.
+
+ * sanity.sh: Add comment about default value for TESTDIR.
+
+ * server.c (serve_log): Change "cvslog" to "log". This
+ (accidental, I presume) error had made it impossible for anonymous
+ users to run "cvs log".
+
+ * classify.c (sticky_ck): Change to take an finfo argument rather
+ than several arguments taken from there. Cleans up the way the
+ calling convention had depended on SERVER_SUPPORT.
+ (Classify_File): Change callers.
+
+ * version.c: Change version number to 1.9.17.
+
+ * Version 1.9.16.
+
+ * recurse.c (do_dir_proc): In combining repository and dir, omit
+ trailing "/." from repository.
+ * sanity.sh (modules3): Adjust test modules3-4 so we test for
+ this fix (this is not just cosmetic; the bug prevented the
+ "Rebuilding administrative file database" from happening).
+ modules2 already tests the "co CVSROOT/modules" usage.
+
+ * checkout.c (checkout_proc): When building top-level CVSADM
+ directory, continue the process of walking up the repository one
+ more level, rather than putting in the same repository as for the
+ first-level directory.
+ * sanity.sh: Adjust tests basicb-1b, basicb-9b, modules3-7f,
+ toplevel-9, and toplevel-11 to test for this fix.
+
+ (For reference, this takes CVS's text segment from 344460 to
+ 344140 bytes. I know, this may seem unimportant, but it is so
+ unusual for programs to shrink and I think it is so cool when they
+ do without losing functionality/clarity/etc).
+ * checkout.c, cvs.h (emptydir_name): New function.
+ * checkout.c (checkout, checkout_proc), modules.c (do_module):
+ Call it instead of duplicating the code to do that.
+
+ * sanity.sh (basicc): Clean up first-dir at end of test.
+
+Sat Sep 6 09:48:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (join): Fix cut and paste error in join-28
+ (/home/kingdon/... -> ${TESTDIR}).
+
+ * recurse.c (start_recursion): If there is no CVSADM and no
+ subdirectories, give an error.
+ * sanity.sh (basicc): New tests, test for this fix.
+
+ * sanity.sh (join): New tests join-25 through join-29 test merging
+ from one branch to a different branch.
+
+ * release.c: In comment about CVSROOTADM_IGNORE, also mention
+ comment just added to entries.c.
+ * entries.c: Expand this comment, especially the part about
+ CVS/Template.
+
+ Keep track of what revisions CVS/Base correspond to:
+ * cvs.h (CVSADM_BASEREV, CVSADM_BASEREVTMP): Added.
+ * entries.c, cvs.h (base_register, base_deregister, base_get,
+ base_walk): New functions.
+ * edit.c (edit_fileproc): Call base_register when setting up CVS/Base.
+ (unedit_fileproc): When taking a file out of CVS/Base, put its
+ revision back into entries, and base_deregister it.
+ * sanity.sh (watch4): New tests watch4-10 through watch4-18 test
+ for above fix.
+
+Fri Sep 5 09:14:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c: Only declare start_rsh_server if we are going to
+ define it (!NO_EXT_METHOD).
+
+ * subr.c, cvs.h (check_numeric): New function.
+ * admin.c (admin): Call it.
+ * sanity.sh (admin): New tests admin-10a and admin-10b test for fix.
+
+Thu Sep 4 15:55:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (binwrap2): New tests, test for the ability to specify
+ all files are binary except certain patterns.
+
+ * sanity.sh (modules3): New tests modules3-16 and modules3-17 test
+ for another behavior involving '/' in a module name.
+
+Sun Aug 31 12:03:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add): Remove checks for '/' in pathnames.
+ (add): Move code which handles entries and repository inside loop,
+ since these now might be different for each argument. Add code to
+ set finfo.update_dir, finfo.file, and finfo.fullname appropriately
+ even if pathname contains '/'. Replace user variable with
+ finfo.file or finfo.fullname, depending on which is meant. chdir
+ into update_dir for each argument. Likewise for the client code
+ which creates directories.
+ (add_directory): Replace arguments with a single finfo argument.
+ Replace dir with finfo->fullname as needed.
+ (add): Update call to add_directory.
+ * client.c, client.h (send_a_repository): No longer static.
+ * sanity.sh (errmsg2): Adjust tests to test for '/' in pathname.
+
+ * sanity.sh (errmsg2): New tests errmsg2-13 through errmsg2-16
+ test the status quo with respect to '/' in cvs add argument.
+
+Sat Aug 30 17:37:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (run_popen): Add comment on return value.
+ * release.c (release): Check for NULL return from popen.
+
+Fri Aug 29 17:49:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (get_server_responses): Add comment about "ok^M".
+
+Thu Aug 28 13:35:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * edit.c (edit_fileproc): If file doesn't exist, give an error.
+ * sanity.sh (devcom2): Tests devcom2-12 through devcom2-17 test
+ for above fix.
+
+Tue Aug 26 16:42:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c (xmalloc): Reword error message to clarify that memory,
+ not disk space or some other resource, is in question.
+
+Tue Aug 26 01:04:48 1997 Steve Ralston <sralston@ppdpost.ks.symbios.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add_directory): In allocating message, also allocate
+ enough for tag and date related text.
+
+Tue Aug 26 01:04:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (update_dirent_proc): Use update_dir not dir in "new
+ directory" message.
+ * find_names.c (find_dirs): Skip CVSNULLREPOS.
+ (Find_Directories): Add comment about find_dirs skipping CVSATTIC
+ and CVSLCK in working directories.
+ * sanity.sh (basicb): New tests basicb-edir-* test for find_dirs
+ fix. Change other tests to test that Emptydir is not special in
+ non-CVSNULLREPOS contexts.
+
+Sun Aug 17 14:44:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c (add_rcs_file): Add comment about -k overriding wrappers.
+
+Sat Aug 16 18:09:05 1997 Martin Sjoelin <martin.sjoelin@ubs.ch>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c (add_rcs_file): Before opening the input file
+ when importing, if options is binary, open the file in
+ binary mode.
+
+1997-08-16 enami tsugutomo <enami@ba2.so-net.or.jp>
+
+ * sanity.sh (mcopy): Unset CVSWRAPPERS last of all.
+
+Fri Aug 15 11:11:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add_directory): Copy default file attributes from the
+ parent directory to the directory we are creating.
+ * fileattr.h, fileattr.c (fileattr_getall, fileattr_setall):
+ New functions, in support of above.
+ * fileattr.c (fileattr_free): Add comment about fileattr_write
+ maybe not clearing attrs_modified.
+ * sanity.sh (watch4): New test, tests for above fix.
+
+Thu Aug 14 11:08:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (merge_file, join_file): If wrap_merge_is_copy, treat
+ files as nonmergeable (as we had been treating binary files).
+ (join_file, update_fileproc): Remove previous wrap_merge_is_copy
+ cruft.
+ * sanity.sh (mcopy): New tests, test for above fix.
+ (binfiles2): New tests binfiles2-9a-* correct an oversight.
+ (binfiles, binfiles2): Adjust to reflect wording change from
+ "binary file" to "nonmergeable file".
+ (mwrap): Adjust tests mwrap-8 through mwrap-10 for new behavior.
+
+ * main.c (main): Reword copyright notices to include the latest
+ year, to refer to "other authors" in addition to the ones listed,
+ and to be more concisely formatted.
+
+Wed Aug 13 13:50:00 1997 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: Replace hard-coded directory with ${TESTDIR}, add
+ join3 to default tests
+
+Wed Aug 13 11:42:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c: Adjust comment to reflect progress on removing RCS
+ execs outside this file.
+
+Mon Aug 11 10:14:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (Version_TS): If vers_ts->vn_rcs == NULL, skip setting
+ modification time in server case as well as local case.
+ * server.c (server_modtime): Add assertion to clarify that caller
+ must assure that vers_ts->vn_rcs != NULL.
+ * sanity.sh (join3): Add file "file2" to test for above fix.
+
+ * modules.c (save_d): When parsing -s option, don't assume that
+ we will hit a space before we hit the '\0'.
+ (struct sortrec): Document allocation policies (status quo except
+ status field is now malloc'd).
+ (cat_module): No longer need to set the '\0' at the end of the
+ status field back to ' ', as it no longer shares storage with the
+ rest field.
+ * sanity.sh (modules): Add "statusmod" to test for above fix.
+
+Sun Aug 10 12:18:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Remove TODO item about more keyword expansion tests.
+ The keyword test and others cover it pretty well, and such an item
+ isn't useful unless it is specific.
+
+ * sanity.sh (importb): New tests test "cvs import -b".
+
+ * mkmodules.c: Update comment with more reasons why having
+ CVSROOT/passwd be a regular administrative file would be a Bad
+ Idea.
+
+ * server.c (switch_to_user): Add comment about checking for errors
+ from setuid and friends.
+
+Wed Aug 6 13:48:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Add comment about errors writing CVS/Root in
+ need_to_create_root code.
+
+Tue Aug 5 22:05:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * entries.c (write_entries): If trouble writing Entries.Backup,
+ make it a warning not an error.
+
+Wed Jul 30 08:42:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * parseinfo.c (parse_config): If AUTH_SERVER_SUPPORT is not
+ defined, don't set system_auth.
+
+ * version.c: Change version number to 1.9.15.
+
+ * Version 1.9.14.
+
+ * create_adm.c, cvs.h (Create_Admin): If new argument WARN is set,
+ then make creating the CVS directory itself a warning not a fatal
+ error. New return value indicates whether we did this.
+ * checkout.c (build_one_dir), client.c (call_in_directory):
+ Pass WARN as one.
+ * add.c, client.c, checkout.c, modules.c, update.c: Pass WARN as
+ zero for all other Create_Admin callers.
+ * sanity.sh (toplevel): New test toplevel-12 tests for this fix.
+ * filesubr.c (mkdir_if_needed): Also check EACCES/isdir. Needed
+ to make toplevel-12 test work.
+
+ * sanity.sh (toplevel): New test toplevel-11 and friends test for
+ another variation of the toplevel-9 bug.
+
+Tue Jul 29 12:11:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * login.c (construct_cvspass_filename): Revert this change. The
+ main reason is procedural; Karl is not a current CVS developer.
+ The other thing is that the new text doesn't say anything about
+ HOMEDRIVE and HOMEPATH.
+
+Tue Jul 29 11:36:22 1997 Karl Fogel <kfogel@harvey.cyclic.com>
+
+ * login.c (construct_cvspass_filename): error message informs user
+ she may need to set HOME environment variable by hand.
+
+Sun Jul 27 15:36:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * admin.c (admin): Remove comment "XXX send -ko too with i = 0".
+ It turns out to be a description of a bugfix which was applied on
+ 8 Oct 1995, and never should have been in a comment in the first
+ place.
+
+ * admin.c (admin, admin_fileproc): Parse options ourself rather
+ than blindly passing them to RCS.
+ Accordingly, add struct admin_data and function arg_add, and delete
+ global variables ac and av.
+ * sanity.sh (admin): Change admin-3 test to reflect cvs admin -i
+ now being an error.
+ (basicb): Change basicb-21 test to relect the improved error
+ message here.
+
+Sat Jul 26 11:34:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (join3): New tests, test a new branch topology and
+ greatest common ancestor.
+
+Fri Jul 25 09:51:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_directory): Repository must start with
+ CVSroot_directory rather than some random pathname.
+
+ * remove.c (remove_fileproc): If there is a numeric sticky tag,
+ don't allow the remove.
+ * commit.c (check_fileproc): Add comment about this case.
+ * sanity.sh (sticky): New tests sticky-15 through sticky-23
+ test for this behavior and the analogous behavior with
+ non-branch sticky tags (which is unchanged).
+
+ * client.c (update_entries): Clear the stored mode, modtime, and
+ checksum even on an error.
+ * sanity.sh (contents2-142d*): Also test cvs status. Also test
+ the case in which the contents of the file are unchanged. Also
+ test running diff to see the conflict, and resolving the conflict.
+ Without the fix above, the new contents2-142d2 test would get a
+ "duplicate Mod-time" warning.
+
+Thu Jul 24 13:29:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (pserver_authenticate_connection): Call parse_config
+ here too.
+ * parseinfo.c (parse_config): If we are called several times, the
+ times beyond the first do nothing.
+ * cvs.h, parseinfo.c (parse_config): New argument cvsroot.
+ * server.c, main.c: Update callers.
+ * server.c, server.h (system_auth): New variable.
+ * parseinfo.c (parse_config): Parse new keyword SystemAuth.
+ * mkmodules.c (config_contents): Add comments for SystemAuth.
+ * server.c (check_password): If !system_auth, then skip the check
+ for a system username/password.
+
+ * main.c (main): No fatal error if parse_config returned an error.
+ * server.c (serve_root): Likewise.
+ * error.c (error): Add comment about calling from the server.
+ * parseinfo.c, cvs.h (parse_config): Remove NOERR crock.
+ Closer reading of server.c makes it seem like calling error
+ here is OK after all.
+ * sanity.sh (config): New test, tests for above fix.
+
+ * server.c (serve_root): Fix typo ("doign" -> "doing").
+
+Wed Jul 23 13:55:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (Version_TS): If entdata is for a directory, don't set
+ vn_user and friends.
+ * server.c (dirswitch): Add comment about why Subdir_Register is
+ sometimes a noop here.
+ * cvs.h (struct vers_ts): Fix comments about NULL vs. "" in vn_user.
+ * sanity.sh (errmsg2): New tests errmsg2-10 through errmsg2-12 test
+ for above fix.
+ * add.c (add_directory): Call cvs_output not printf. This fixes
+ an out-of-order bug which was showing up in the testcase.
+
+21 Jul 1997 Jim Kingdon
+
+ * subr.c (get_file): Put st_size into an unsigned variable to
+ avoid signed/unsigned warnings.
+
+Mon Jul 21 00:19:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.13.
+
+ * Version 1.9.12.
+
+ * sanity.sh (toplevel, head): Delete our files from the repository
+ when done with them.
+
+Sun Jul 20 15:53:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (admin, reserved): New tests, test most cvs admin
+ behaviors.
+ (log2): New tests log2-5 through log2-10 test setting the
+ description via cvs admin.
+
+Thu Jul 17 12:39:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (socket_buffer_input, socket_buffer_output): Add
+ comment regarding size of of buffer we pass to send and recv.
+
+Sat Jul 12 15:21:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c, rcs.h (add_rcs_file): New argument key_opt replaces
+ access to global variable keyword_opt. New arguments desctext and
+ desclen allow one to set the description. If add_vhead is NULL,
+ then omit a revision, like rcs -i.
+ * import.c (process_import_file), mkmodules.c (init): Change
+ callers.
+ * subr.c, cvs.h (get_file): New function, adapted from code in
+ update_entries.
+ * client.c (update_entries): Call it.
+ * commit.c (checkaddfile): Create new RCS files with add_rcs_file
+ rather than rcs -i.
+
+Fri Jul 11 12:14:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (join_file): Handle binary files ourself rather than
+ passing them to RCS_merge (which sort of tries to handle binary
+ files, but does so badly).
+ * sanity.sh (binfile2): New "brmod", "brmod-trmod", and
+ "brmod-wdmod" tests test for this fix.
+
+ * add.c (add): Exit status is now nonzero if any of the arguments
+ failed (already was mostly true, make it true for the new sanity
+ check). Move check for '/' (now ISDIRSEP) up to sanity check, so
+ the client does it too.
+ * sanity.sh (errmsg2): Test for this fix.
+
+Thu Jul 10 00:02:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add): Check for CVSADM, ".", and "..", and skip any
+ attempt to add them.
+ * sanity.sh (errmsg2): New tests, tests for above fix.
+
+ * main.c (main): In text printed upon --version, also refer
+ people to --help.
+
+ * rcscmds.c (RCS_exec_rcsdiff): Add comment about timezones.
+
+ * server.c, cvs.h (cvs_output_binary): New function.
+ * rcs.c (RCS_checkout): For a binary file, call cvs_output_binary
+ rather than cvs_output.
+ * client.c (handle_mbinary): New function.
+ (responses): Add "Mbinary".
+
+Tue Jul 8 12:18:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (get_homedir): Add comment about root vs. user
+ directory in pserver server.
+
+Mon Jul 7 14:39:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (big): Also test Rcs-diff case.
+
+ * client.c (update_entries): Reindent a line.
+
+ * sanity.sh (death2): Add comment about Sun diff. Thanks to
+ Warren Jones <wjones@TC.FLUKE.COM> for reporting this.
+
+ * client.c (update_entries): If DONT_USE_PATCH, then just treat a
+ Patched response as an indication to try again with complete files.
+ * update.c (update): Remove DONT_USE_PATCH ifdefs, since a CVS
+ with DONT_USE_PATCH defined can still handle Rcs-diff.
+ * sanity.sh (serverpatch): Add comment about this coming up in
+ real life if the user modifies the file while CVS is running.
+
+ * client.c (start_server): Add comment about logfiles if there are
+ several connections to the server.
+ (log_buffer_shutdown): Close the logfile after shutting down the
+ underlying buffer. This way at least we get the last set of
+ logfiles rather than a bizarre mishmash.
+
+1997-07-06 enami tsugutomo <enami@but-b.or.jp>
+
+ * logmsg.c (do_verify): Unlink temporary file before call error().
+ Remove unneeded `return' statement. Fix comment.
+
+Sun Jul 6 13:36:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (diff_fileproc): Change message from "during rcsdiff of"
+ to "while diffing". For a while now, that message might be
+ printed after a call to DIFF instead of rcsdiff.
+
+ * diff.c (diff_fileproc): Call cvs_output not printf. Remove
+ calls to fflush (should be handled now by call to cvs_outflush in
+ recurse.c).
+ * patch.c (patch_fileproc): Likewise.
+
+ * rcscmds.c, cvs.h (diff_exec): New function.
+ * diff.c (diff_fileproc), patch.c (patch_fileproc),
+ update.c (patch_file): Call it.
+
+ * rcscmds.c: Adjust comments concerning diff library to point to
+ new, expanded comments at diff_exec. Remove comments concerning
+ patch library; Rcs-diff should be adequate.
+
+ * client.c (update_entries): Add comment about GNU patch usage (-b
+ option and so on).
+
+Sat Jul 5 04:13:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c, cvs.h (RCS_exec_rcsdiff): New function.
+ * diff.c (diff_fileproc): Call it.
+
+Thu Jul 3 09:50:07 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Add comment about how long we should keep the
+ deprecated "cvs rlog" alias.
+
+ * server.c (cvs_output): Add comment about whether to fflush.
+
+Wed Jul 2 18:57:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (join2): New tests join2-19 and friends test for a
+ case that we can't readily get right (see comments).
+
+Tue Jul 1 09:52:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (cmd_usage): Say "specify" --help rather than the vague
+ "use".
+ (opt_usage, cmd_synonyms): Mention --help here too.
+ * add.c, admin.c, checkout.c, commit.c, diff.c, edit.c, import.c,
+ log.c, login.c, mkmodules.c, patch.c, rcs.c, release.c, remove.c,
+ rtag.c, status.c, tag.c, update.c, watch.c: Likewise, for all the
+ other help messages.
+
+ * sanity.sh (join2): New tests.
+
+ * repos.c (Name_Repository): Check for errors from fclose.
+
+Fri Jun 27 10:27:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * scramble.c, login.c: Reindent.
+
+ * client.c (connect_to_pserver): Check for errors from send().
+ If socket() fails, include SOCK_STRERROR (SOCK_ERRNO) in message.
+
+Wed Jun 25 11:21:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c: New option --help-options, with much of the text
+ from --help. Fix a few capitalization and punctuation problems.
+ Rewrite text for --help to be an intro to all the --help-*
+ options.
+
+ * sanity.sh (head): New tests, concerning meaning of HEAD.
+
+Tue Jun 24 10:14:18 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (recv_line): New function.
+ (connect_to_pserver): Call it, and rewrite accordingly. Also
+ accept new "E" and "error" responses. Change \n to \012.
+ * server.c (pserver_authenticate_connection): Adjust comment
+ accordingly, concerning sending I HATE YOU not "error".
+
+Sun, 22 Jun 1997 Jim Kingdon
+
+ * main.c (main): Move setting of server_active inside #ifdef
+ SERVER_SUPPORT; otherwise the variable doesn't exist.
+ * main.c (main): Call return after exit to shut up warning.
+
+Fri Jun 20 22:56:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (connect_to_pserver): On "I HATE YOU", give
+ "authorization failed" fatal error regardless of verify_only.
+ * login.c (login): Don't print that "incorrect password" message;
+ it now is possible with an --allow-root failure as well as an
+ incorrect password. cvsclient.texi doesn't really specify what I
+ HATE YOU means in any detail, and it seems a little silly for
+ login to give different messages than the other commands.
+ * client.c, client.h (connect_to_pserver): Return type now void.
+
+Thu Jun 19 12:16:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_root): Give error on duplicate Root request.
+ Call parse_config.
+ * parseinfo.c, cvs.h (parse_config): New function.
+ * cvs.h (CVSROOTADM_CONFIG): Added.
+ * main.c (main): Set server_active here...
+ * server.c (server): ...not here. That seems cleaner than
+ strcmp's between command_name and "server" in main.c.
+ * main.c (main): Call parse_config.
+ * main.c, cvs.h (free_Rcsbin): Make global.
+ * mkmodules.c (filelist): Add CVSROOTADM_CONFIG.
+
+Wed Jun 18 11:24:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.11.
+
+ * Version 1.9.10.
+
+Tue Jun 17 22:48:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Add --allow-root=ROOT argument; call
+ root_allow_add for each time it is specified. Call
+ root_allow_free before exiting.
+ * root.c, cvs.h (root_allow_add, root_allow_free, root_allow_ok):
+ New function.
+ * server.c (pserver_authenticate_connection): If root_allow_ok
+ doesn't like the CVSROOT directory, don't allow access.
+
+Tue Jun 17 14:30:14 1997 Jim Kingdon (unknown@beezley)
+
+ * client.c: Add "copyright" notice. If NO_EXT_METHOD, omit
+ start_rsh_method.
+ * client.c (update_entries): Cast argument to MD5Update from
+ char * to unsigned char *.
+
+Mon Jun 16 16:46:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (piped_child, filter_stream_through_program):
+ If USE_SETMODE_BINARY, then put the pipes into binary mode.
+ * find_names.c, ignore.c, lock.c, wrapper.c: Change fnmatch to
+ CVS_FNMATCH.
+ * client.c (start_server): If NO_EXT_METHOD, then give a fatal
+ error on any use of :ext:.
+
+Sun Jun 15 22:30:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (toplevel): Match U CVSROOT/* lines with DOTSTAR in
+ test toplevel-9.
+
+Thu Jun 12 10:27:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (toplevel): Remove Emptydir before starting.
+
+ * sanity.sh: Change "rm -rf" to "rm -r" when deleting working
+ directories (except a few watches cases). Helps detect cases
+ where the testsuite has cd'd to somewhere other than where we
+ think it has.
+ (basic2): Remove "rm -r first-dir" between tests 49 and 50. The
+ directory was already deleted in test 45.5.
+ (rcs): Add "cd .." at end of tests.
+ (stamps): No longer cd to TESTDIR; shouldn't be necessary with
+ fix to "rcs" test.
+
+Wed Jun 11 22:28:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb): Also remove CVSROOT/Emptydir at end of
+ test. Otherwise it affects the toplevel-9 test for remote.
+
+Tue Jun 10 14:03:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (toplevel): Change "update" and "checkout" to "[a-z]*"
+ as these read "server" instead for "make remotecheck". Change
+ expect strings for toplevel-9 to accept the behavior of remote CVS
+ (see comments for more discussion).
+
+ * sanity.sh: New tests stamps-9 through stamps-11 test timestamp
+ behavior on cvs update.
+
+Mon Jun 9 22:42:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Remove "#! /bin/zsh" line at end. I assume it was
+ added accidentally.
+
+Tue Jun 10 03:08:46 1997 Norbert Kiesel <nk@psycho.de>
+
+ * sanity.sh: new tests "toplevel" for the new toplevel CVS
+ directory creation (including one test which shows an error in
+ this area).
+
+Sun Jun 8 20:52:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (getrcsrev): Before printing error, check whether it was
+ feof or ferror.
+
+ * rcs.h, import.c (add_rcs_file): No longer static. New arguments
+ add_vbranch, add_vhead, and add_logfp replace access to static
+ variables vbranch, vhead, and logfp.
+ * mkmodules.c: Call it instead of RCS_CI.
+ * import.c (process_import_file): Adjust call to add_rcs_file.
+
+Tue Jun 3 10:18:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb): Match "." with "\." not ".".
+
+Tue Jun 3 13:02:37 1997 Norbert Kiesel <nk@cosa.de>
+
+ * checkout.c (checkout): Removed restriction of not sending -k in
+ remote export (I think this was introduced while the -k handling
+ was still broken in remote mode). Give better error texts
+ regarding -c and -s options. Use error() instead of usage() for
+ reporting errors in all places. Reindented some lines. Free
+ xmalloc'd space of options.
+
+Thu May 29 16:32:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c (RCS_checkin), mkmodules.c (init): Pass -w option to
+ "ci", specifying getcaller ().
+ * server.h, server.c (CVS_Username): Now extern.
+ * subr.c (getcaller): Return CVS_Username if it is set.
+
+Wed May 28 22:31:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (update_fileproc): If wrap_merge_is_copy and we would
+ like to do a merge, give a fatal error. See comment for why.
+ * sanity.sh (mwrap): New tests, tests for above fix.
+
+Tue May 27 21:59:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (stamps): cd to ${TESTDIR} before starting.
+
+Mon May 26 15:31:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (handle_mod_time): New function.
+ (responses): Add "Mod-time".
+ (stored_modtime_valid, stored_modtime): New variables.
+ (update_entries): If it is set, change the file's modtime.
+ * server.c, server.h (server_modtime): New function.
+ * vers_ts.c (Version_TS): Call it.
+ * patch.c (patch_fileproc): Add comment about why we don't.
+ * sanity.sh (stamps): Added, tests for above fix.
+
+Fri May 16 13:14:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c (free_names): Update documentation to reflect fact that
+ free_names is now called to free vectors allocated by expand_wild
+ as well as by line2argv.
+
+ * main.c (main): Use "xstrdup (foo)" not "xstrdup(foo)" as
+ specified in HACKING.
+
+Fri May 16 15:10:37 1997 Norbert Kiesel <nk@cosa.de>
+
+ * modules.c (do_module): initialize optind to 0. use local copies
+ of optarg's (because they might me freed within free_names).
+
+Thu May 15 11:50:15 1997 Norbert Kiesel <nk@cosa.de>
+
+ * main.c (main): initialize optind to 0. use local copies of
+ optarg's (because they might me freed within read_cvsrc).
+
+ * cvsrc.c (read_cvsrc): free old argv after constructing a new
+ one. This fixes a memory leak.
+
+ * recurse.c (start_recursion): use free_names() instead of
+ reimplementing it
+
+ * rcs.c (RCS_deltas): free branchversion (memory leak).
+
+ * parseinfo.c (Parse_Info): free some vars (3 memory leaks).
+
+ * logmsg.c (logfile_write): free str_list_format (memory leak).
+
+ * watch.c (watch_addremove), (watchers), update.c (update), tag.c
+ (cvstag), status.c (status), rtag.c (rtag), remove.c (cvsremove),
+ release.c (release), patch.c (patch), log.c (cvslog), import.c
+ (import), history.c (history), edit.c (watch_onoff), (edit),
+ (unedit), (editors), diff.c (diff), commit.c (commit), checkout.c
+ (checkout), add.c (add): initialize optind to 0
+
+ * diff.c (diff_fileproc): cosmetic change (whitespace added).
+
+ * checkout.c (checkout): move local variable definition into the
+ block where the variable is used.
+
+ * client.c (update_entries): initialize some local variables to shut up
+ gcc -O -Wall.
+
+ * buffer.c (buf_read_line): initialize a local variable to shut up
+ gcc -O -Wall.
+
+
+Wed May 14 16:29:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * admin.c (admin): When sending options to server, don't try to
+ send av[ac]. It may contain one of the names that we'll send in
+ send_file_names (which caused tests like keyword-6 to work,
+ sort of accidentally), or it may contain NULL (which would tend to
+ cause a coredump).
+ * sanity.sh (basicb): New test basicb-21 tests for above fix.
+
+Mon May 12 16:22:00 1997 Larry Jones <larry.jones@sdrc.com>
+
+ * add.c (add): Free message and repository in client code.
+ * checkout.c (checkout): Don't free repository unless allocated.
+ * client.c (start_rsh_server): Free command.
+
+Sun May 11 11:43:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c: Remove all references to USE_DIRECT_TCP; see
+ ../ChangeLog for rationale.
+
+Fri May 9 22:19:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Add comment explaining why we call exit. Pass 0
+ not EXIT_SUCCESS, because lib/system.h has portability cruft for
+ EXIT_FAILURE but not EXIT_SUCCESS.
+
+Fri May 9 17:25:00 1997 Larry Jones <larry.jones@sdrc.com>
+
+ Fix miscellaneous memory allocation problems:
+ * add.c (add): Free repository.
+ * client.c (notified_a_file): Free getline buffer.
+ * edit.c (notify_check): Free getline buffer.
+ * hash.c (dellist): Free header node when not caching.
+ * login.c (login): Don't continually free & allocate getline
+ buffer, use xstrdup instead of xmalloc/strcpy, free getline
+ buffer before returning.
+ * main.c (main): Call exit instead of returning so tools like
+ Purify won't consider permanently allocated memory as leaks.
+ * mkmodules.c (mkmodules): Free getline buffer.
+ * modules.c (cat_module): Call close_module.
+ * rcs.c (rcsvers_delproc): Free state.
+ * recurse.c (start_recursion): Free files_by_dir.
+ (unroll_files_proc): NULL out p->data after using it to set
+ filelist to avoid multiple frees.
+ * server.c (check_command_legal_p): Don't continually free &
+ allocate getline buffer, free getline buffer before returning.
+ (check_repository_password): Ditto, use xstrdup instead of
+ xmalloc/strcpy.
+ * wrapper.c (wrap_add_file): Free getline buffer.
+
+Thu May 8 14:21:00 1997 Larry Jones <larry.jones@sdrc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (checkout_proc): Free finfo.rcs (memory leak).
+
+8 May 1997 Larry Jones <larry.jones@sdrc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * hash.c: Add #ifdef's to disable caching. This makes it easier
+ to track down memory allocation problems.
+
+Thu May 8 11:40:39 1997 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh: In setting "tests" use a number of statements rather
+ than one very long line.
+
+Thu May 8 11:40:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsbug.sh: Remove $Id; we decided to get rid of these some time
+ ago.
+
+Thu May 8 11:34:02 1997 Larry Jones <larry.jones@sdrc.com>
+
+ * cvsbug.sh: Put separate statements on separate lines, so it
+ works if awk is AT&T nawk.
+
+Tue May 6 16:56:00 1997 Larry Jones <larry.jones@sdrc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsrc.c (read_cvsrc): Fix various memory allocation problems:
+ rearrange code to avoid leaks, use xrealloc instead of xmalloc/
+ copy/free, make sure there's room for the remaining args before
+ appending them.
+
+Tue May 6 14:20:00 1997 Larry Jones <larry.jones@sdrc.com>
+
+ * edit.c (watch_onoff, edit, unedit, editors): Add -R like
+ other things with -l.
+ * watch.c (watch_addremove, watchers): Ditto.
+
+Mon May 5 18:10:37 1997 larry.jones@sdrc.com
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Change all /tmp/cvs-sanity to TESTDIR. If TESTDIR
+ environment variable is set, use it instead of /tmp/cvs-sanity.
+ * sanity.sh: Make TMPPWD the pwd equivalent of TESTDIR, not of /tmp.
+
+4 May 1997 Larry jones <larry.jones@sdrc.com>
+ and Jim Kingdon
+
+ * checkout.c, diff.c, patch.c, rcs.c: Update usage messages.
+ * rcs.c (annotate): Add -R like other things with -l.
+
+Sat May 3 14:57:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basic1): Rewrite test (use dotest, unroll the loops
+ which IMHO makes the test a zillion times more understandable, and
+ only do the variant which tests for 4 files at a time--we test one
+ file at a time lots of places).
+
+2 May 1997 Ziv Gigus <ziv@rest.home.net>
+ and Jim Kingdon
+
+ * client.c, client.h (client_process_import_file): New argument
+ all_files_binary means treat all files as binary.
+ * import.c (import_descend): Pass it if -kb is specified.
+ * client.c (client_process_import_file): In the
+ non-all_files_binary case, call wrap_rcsoption to determine
+ whether the file is binary.
+
+Thu May 1 13:44:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (binfiles2): New tests, for update -j and binary files.
+
+Wed Apr 30 11:18:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (start_recursion): Also free reposfile.
+ Don't look in repository if client_active (latter bug reported by Paul
+ Sanders <p.sanders@dial.pipex.com>).
+
+Mon Apr 28 22:36:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (diff_file_nodiff): Remove SERVER_SUPPORT ifdefs. They
+ were not based on server_active, which doesn't really make any
+ sense (it meant that compiling --disable-server could affect the
+ behavior of the non-client/server CVS). This affected the output
+ in tests death2-diff-11 and death2-diff-12 in the testsuite.
+ * sanity.sh (newb-123j0): Also accept "Needs Checkout", for a
+ --disable-server CVS.
+
+ * main.c (cmd_usage): Change "run diffs" to "show differences";
+ the former is jargon.
+ * edit.c (edit_usage): Fix typo ("." -> ",").
+ * edit.c (editors_usage), watch.c (watchers_usage): Mention -l.
+ * checkout.c (export_usage): Say what -P does.
+ * history.c (history_usg): Add comment about message wording.
+
+Mon Apr 28 14:47:45 1997 Norbert Kiesel <nk@cosa.de>
+
+ * checkin.c (Checkin): use filename without path when calling
+ wrapper (bug found by Michal Schmitz <ms@cosa.de>).
+
+Fri Apr 25 13:28:55 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (update_entries): In UPDATE_ENTRIES_RCS_DIFF case,
+ write to a temporary file and then rename it.
+
+Thu Apr 24 11:35:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c, cvs.h (pathname_levels): New function, from a piece of
+ send_file_names.
+ * client.c (send_file_names): Call pathname_levels in place of the
+ code which was moved there.
+ * server.c, server.h (server_pathname_check): New function.
+ * recurse.c (start_recursion): Call it.
+ * sanity.sh (modules3): New test modules3-11b tests for above fix.
+
+ * filesubr.c: Do not define L_tmpnam. It is in ANSI and SunOS4,
+ so I don't think there will be a problem with it being missing.
+ Defining it too small can cause memory corruption.
+ (cvs_temp_name): Do not use L_tmpnam in the mktemp code; this
+ could cause a buffer overflow if the -T global option was in use.
+
+Thu Apr 24 13:21:15 1997 Norbert Kiesel <nk@cosa.de>
+
+ * filesubr.c (cvs_temp_name): Use tempnam if available, else
+ mktemp, else tmpnam. See the comment for rationale.
+
+ * sanity.sh: use "tar cf - ." instead of "tar cf - *" for
+ directory copies.
+
+Wed Apr 23 23:41:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_update_prog): If in readonly mode, give an error.
+
+Wed Apr 23 19:07:41 1997 Norbert Kiesel <nk@cosa.de>
+
+ * subr.c (line2argv): Allocate at least 4 slots for argv.
+
+ * checkout.c (checkout_proc): Add a comment which says why the
+ above change was necessary to avoid writing to unallocated memory.
+
+Wed Apr 23 11:20:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * entries.c (ParseTag): Always set *NONBRANCHP.
+
+21 Apr 1997 Jim Kingdon
+
+ * client.c (update_entries), rcs.c (expand_keywords): Rewrite
+ test to avoid signed/unsigned warning.
+
+Mon Apr 21 09:02:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (patch_file): Add comment about whether auto-detecting
+ features of the DIFF program is a good idea.
+
+Mon Apr 21 00:03:34 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ Don't require the patch program:
+ * client.c (struct update_entries_data): Add
+ UPDATE_ENTRIES_RCS_DIFF to contents enum.
+ (update_entries): Handle UPDATE_ENTRIES_RCS_DIFF.
+ (handle_rcs_diff): New static function.
+ (responses): Add "Rcs-diff".
+ * server.c (server_updated): Handle SERVER_RCS_DIFF.
+ (server_use_rcs_diff): New function.
+ * server.h (enum server_updated_arg4): Add SERVER_RCS_DIFF.
+ (server_use_rcs_diff): Declare.
+ * update.c (rcs_diff_patches): New static variable.
+ (update): Set rcs_diff_patches.
+ (update_fileproc): If rcs_diff_patches, pass SERVER_RCS_DIFF
+ rather than SERVER_PATCHED to server_updated.
+ (patch_file): Correct initial comment to say diff rather than
+ rcsdiff. If rcs_diff_options, pass -n to diff rather than -c.
+ * rcs.c (rcs_change_text): New function.
+ * rcs.h (rcs_change_text): Declare.
+
+Mon Apr 21 00:08:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (diff_fileproc): Add comment concerning updating the
+ client timestamp.
+
+Sun Apr 20 23:20:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (commit): Add comment regarding SEND_FORCE rationale.
+
+Sat Apr 19 17:10:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (dirswitch): If directory ends in '/', complain.
+
+Fri Apr 18 18:09:57 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (apply_rcs_changes): New static function, broken out of
+ RCS_deltas.
+ (RCS_deltas): Call it.
+ (linevector_add): Change return type to int. Return an indication
+ of an error for an invalid add, rather than calling error.
+
+Fri Apr 18 11:24:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.9.
+
+ * version.c: Version 1.9.8.
+
+ * commit.c (struct find_data): Add field force.
+ (find_fileproc, commit): Use it instead of force_ci to decide
+ whether to send files to server.
+ (commit): Set it if either -f or -r is specified.
+ * sanity.sh (basica): Add tests basica-8a0, basica-8a1, and
+ basica-8a2; tests for above fix.
+
+Wed Apr 16 11:50:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * zlib.c: Remove paragraph with Free Software Foundation address.
+ See 2 Jan 1997 entry in ../ChangeLog for rationale.
+
+Tue Apr 15 00:36:23 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (patch_file_write): Always assign to final_nl, so that
+ it ends up reflecting whether the data from the last call had a
+ newline, not whether the data from any of the calls ended in a
+ newline. Doesn't matter with the current RCS_checkout
+ implementation, but it will if RCS_checkout is changed to pass
+ less than the entire file.
+
+ * rcs.c (RCS_cmp_file): Change NULL to RUN_TTY in passing sout to
+ RCS_checkout, for clarity.
+
+ * import.c (update_rcs_file): Remove unused variable ierrno.
+
+ * add.c, checkout.c, commit.c, diff.c, edit.c, import.c,
+ history.c, log.c, main.c, patch.c, release.c, remove.c, rtag.c,
+ status.c, tag.c, update.c, watch.c: Pass "+" to all calls to
+ getopt. This ensures that we maintain existing behavior even with
+ glibc2.
+
+ * filesubr.c (fopen_case): Don't set *PATHP if we return an
+ error. Since the 9 Apr 1997 change, the behavior has been to
+ sometimes set it and sometimes not.
+ * rcs.c (RCS_parse): Adjust callers to not free it. Without this
+ change, they could call free() on an uninitialized variable.
+
+ * checkout.c (checkout): Add comment about export -k.
+
+ * root.c (check_root_consistent): Add comment about wording of
+ message.
+
+Mon Apr 14 11:51:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (call_in_directory): If rdirp reaches the end of
+ reposdirname, then just set it to NULL. If server does not create
+ directories one at a time, give a warning.
+ * sanity.sh (modules3): Enable tests modules3-8 through
+ modules3-11 for remote; tests for above fix.
+
+ * client.c (call_in_directory): Don't set short_pathname to
+ pathname for a while; just use pathname itself (cleans up a relic
+ of the old "Repository" (not "Directory") code). Add comment
+ explaining short_pathname.
+
+Sun Apr 13 18:07:50 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * rcs.c (RCS_checkout): Add pfn and callerdat parameters. Change
+ all callers. Move setting of expand after retrieval of file
+ data.
+ (struct cmp_file_data): Define.
+ (RCS_cmp_file): New function.
+ (cmp_file_buffer): New static function.
+ * rcs.h (RCSCHECKOUTPROC): Define type.
+ (RCS_checkout): Update declaration.
+ (RCS_cmp_file): Define.
+ * diff.c (diff_file_nodiff): Call RCS_cmp_file rather than
+ RCS_checkout and xcmp.
+ * import.c (update_rcs_file): Likewise.
+ * no_diff.c (No_Difference): Likewise.
+ * update.c (struct patch_file_data): Define.
+ (patch_file): Just return if noexec, or if binary file. Pass
+ patch_file_write to RCS_checkout. Don't check for newlines or
+ compute checksums here. Stat RCS file to set modes.
+ (patch_file_write): New static function.
+
+ * update.c (patch_file): Checkout directly to file2, rather than
+ to finfo->file followed by rename. Remove check for whether
+ result of checkout is readable; that was for an old, obsolete,
+ form of death support.
+
+Sun Apr 13 13:16:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (build_one_dir): New function.
+ (struct dir_to_build): New structure.
+ (build_dirs_and_chir): Rewritten to accept a linked list of struct
+ dir_to_build rather than the silly string processing we had been
+ doing before.
+ (checkout_proc): Rewrite code that calls build_dirs_and_chdir
+ accordingly.
+ * sanity.sh: Enable tests modules3-10 and modules3-11 for local CVS;
+ tests for above fix.
+
+ * rcs.h (RCS_CO): Removed; no longer used.
+
+Sun Apr 13 00:04:34 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ Expand RCS keywords internally; never call co:
+ * rcs.h (struct rcsversnode): Add state field.
+ * rcs.c (kflags): Move out of RCS_check_kflag, and make file
+ static.
+ (enum kflag): Define.
+ (RCS_reparsercsfile): Always save lock information. Save state in
+ new state field, rather than other field.
+ (struct rcs_keyword): Define.
+ (keywords): New static variable.
+ (enum keyword): Define.
+ (printable_date, escape_keyword_value): New static functions.
+ (expand_keywords): New static function.
+ (RCS_checkout): Call expand_keywords. Don't call
+ RCS_exec_checkout.
+ (RCS_deltas): Add log and loglen parameters. Change all callers.
+ * log.c (log_version_requested): Use new state field.
+ (log_version): Likewise.
+ * cvs.h (RCS_exec_checkout): Don't declare.
+ * rcscmds.c (RCS_exec_checkout): Remove.
+
+Sat Apr 12 17:32:59 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (modules3): Remove second-dir at end of tests.
+ (sticky): Correct removal of directories at end of tests.
+
+ * sanity.sh (keyword): New tests for RCS keyword expansion.
+
+Sat Apr 12 16:47:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb): New tests basicb-1b, basicb-1c, basicb-9b,
+ basic-9c test current build_dirs_and_chdir behavior.
+
+Fri Apr 11 23:54:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (modules3): New tests modules3-7* test for ability to
+ supply a path in -d in modules. Similar to modules3-8 through
+ modules3-11 except because the nesting is different, these ones
+ work.
+
+Thu Apr 10 00:14:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (modules3): New tests modules3-12 through modules3-15
+ test use of a module name which contains a slash.
+
+ * sanity.sh (basicb): New tests basicb-14 to basicb-20 test use of
+ co -d with two or more arguments.
+
+ * rcscmds.c: Refer to doc/RCSFILES in comment.
+
+Wed Apr 9 09:49:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb): New tests basicb-11 through basicb-13 test
+ ability to specify several directory levels in co -d (commented
+ out).
+
+ * filesubr.c (fopen_case): If CVS_OPENDIR gives an
+ existence_error, return it to the caller instead of giving a fatal
+ error.
+
+ * client.c (update_entries): Fix typo in call to error (1 -> errno).
+
+Tue Apr 8 23:02:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.h, error.c: Test for #ifdef __STDC__, not #if __STDC__.
+ This is consistent with other parts of CVS; it means that the
+ declaration for fperror will match the definition even if __STDC__
+ is defined to 0 as the SunPro 4.0 compiler does. Reported by
+ Richard Smith <rjsmith@cisco.com>.
+
+2 Apr 1997 Jim Kingdon
+
+ * entries.c (ParseTag): Add "break;" after "default:" to avoid
+ error from Visual C++.
+
+Wed Apr 2 12:06:44 1997 Vince Del Vecchio <vdelvecc@spd.analog.com>
+ and Jim Kingdon
+
+ * client.c: In reporting errors from socket calls, use
+ SOCK_STRERROR and SOCK_ERRNO since strerror(errno) doesn't work
+ for Win32.
+
+Tue Apr 8 10:45:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (modules3): Add tests modules3-8 to modules3-11, to
+ test for ability to supply a path to -d in modules. Mostly
+ commented out as CVS is buggy in this area.
+
+Mon Apr 7 12:41:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add): Add comment about SEND_NO_CONTENTS.
+
+Sun Apr 6 21:46:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (update): Add comment about noexec and SEND_NO_CONTENTS.
+
+Sun Apr 6 17:34:08 1997 Robert Bihlmeyer <robbe@orcus.priv.at>
+
+ * Pass +f not f to getopt_long to prevent options from being
+ permuted with glibc 2.0.1.
+
+Sun Mar 30 00:07:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h (struct vers_ts): Adjust comment regarding ts_user.
+ * server.c (serve_is_modified): New function. Set entries to show
+ that the file is modified but we don't know the contents.
+ * server.c (requests): Add "Is-modified" request.
+ * vers_ts.c (time_stamp_server): If the timestamp in entdata is
+ "M" or "D", just copy that over into ts_user.
+ * vers_ts.c (Version_TS): If timestamp is "D", use the entries
+ line for the sole purpose of passing it to time_stamp_server.
+ * no_diff.c (No_Difference): If ts_user is "M", conclude the files
+ are different.
+ * client.h, client.c (send_files): Replace arguments build_dirs
+ and force with argument flags. Add flag SEND_NO_CONTENTS and add
+ to struct send_data.
+ (send_fileproc): If no_contents, then send Is-modified instead of
+ Modified.
+ * add.c, admin.c, client.c, commit.c, diff.c, edit.c, log.c,
+ rcs.c, remove.c, status.c, tag.c, update.c, watch.c: Change all
+ send_files callers.
+
+Fri Mar 28 22:32:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (requests): Change "Repository" to rq_optional. I'm
+ not sure whether I overlooked this when I removed support for
+ Repository, or whether I was thinking that servers would need to
+ support it anyway, for CVS 1.5 to 1.9 clients, but making it
+ optional doesn't prevent the server from supporting it and it
+ seems silly for the client to complain about absence of a request
+ that it never will use.
+
+Fri Mar 28 10:06:59 1997 Steven Miller <Miller@wingra.com>
+
+ * entries.c (Subdirs_Known): Don't create Entries.Log if noexec.
+
+Thu Mar 27 18:14:12 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (death2): Remove commented out test death2-21. It
+ would now pass, but it duplicates the new test sticky-11.
+
+Thu Mar 27 10:21:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (dotest_internal): Write test output to logfile even
+ if test succeeds. This was the behavior prior to 30 Sep 1996.
+ See the comment for rationale.
+
+Tue Mar 25 13:26:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h, entries.c (WriteTag): Add arguments nonbranch,
+ update_dir, and repository. Move the server_set_sticky call from
+ callers to here.
+ * cvs.h, create_adm.c (Create_Admin): New argument nonbranch.
+ * cvs.h, entries.c (ParseTag): Add argument nonbranchp.
+ * cvs.h (struct stickydirtag): Add field nonbranch.
+ * entries.c (Entries_Open): Set it.
+ * cvs.h (Vers_TS): Add field nonbranch.
+ * vers_ts.c (Version_TS): Copy it from struct stickydirtag.
+ * server.c, server.h (server_set_sticky): Add argument nonbranch.
+ * add.c, client.c, checkout.c, modules.c, update.c, create_adm.c,
+ commit.c: Update callers.
+ * add.c (add): If nonbranch, don't add the file on that "branch".
+ * commit.c (write_dirnonbranch): New variable.
+ (commit_fileproc, commit): Set it.
+ (commit_dirleaveproc): Pass it to WriteTag.
+ * update.c (rewrite_tag, nonbranch): New variables.
+ (update, update_dirent_proc, update_fileproc): Set them.
+ (update_filesdoneproc): If rewrite_tag, call WriteTag.
+ * sanity.sh (sticky): New tests, test for above fix.
+
+ * version.c: Change version number to 1.9.7.
+
+ * version.c: Version 1.9.6.
+
+Mon Mar 24 13:02:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * entries.c (ParseTag): Add comment about unrecognized characters
+ in CVS/Tag file.
+
+ * classify.c (Classify_File): Add comment about how specifying a
+ tag (bogusly?) suppresses certain messages.
+
+Fri Mar 21 13:37:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.h (struct rcsnode): Add comment about case of PATH.
+ * rcs.c (RCS_parse): If ign_case, then try opening the file with
+ fopen_case.
+ * ignore.c (ign_case): Adjust comment.
+ * cvs.h, filesubr.c (cvs_casecmp, fopen_case): New functions.
+
+20 Mar 1997 Jim Kingdon
+
+ * client.c (send_repository): When sending Directory request,
+ send any ISDIRSEP character as '/'. Fixes
+ "cvs log foo\bar\baz.c" on NT & friends.
+
+ * client.c (send_file_names): Don't try to read Entries file if
+ CVSADM directory does not exist. Fixes fairly serious regression
+ (warning on all fresh checkouts) introduced by 1997-01-08 change.
+
+Tue Mar 18 13:03:33 1997 Jim Meyering <meyering@totoro.cyclic.com>
+
+ * sanity.sh (RCSINIT): Define to be empty and export, to hide any
+ existing value that might cause spurious failures.
+
+ * Makefile.in: (install): Depend on installdirs.
+ Remove `CYGNUS LOCAL' comment saying not to.
+
+Tue Mar 18 09:36:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * recurse.c (struct recursion_frame): Reindent.
+ (do_dir_proc): Print message if we try to recurse into a CVSADM
+ directory.
+ * sanity.sh (basicb): New test basicb-4a tests for above fix.
+
+Sun Mar 16 10:18:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (death2): Replace regexp matching temporary file name
+ with new variable ${tempname}. For most of the tests this is a
+ cosmetic change, but death2-diff-6 had been missing _ which caused
+ it to fail on Solaris (at least sometimes).
+
+ * sanity.sh (modes): Don't use export -n; it doesn't seem
+ to be sufficiently portable.
+
+ * version.c: Change version number to 1.9.5.
+
+ * version.c: Version 1.9.4.
+
+ * rcscmds.c (RCS_checkin): Preserve the mode of the rcsfile.
+ RCS_CI usually, but not always, does this for us.
+ * commit.c (fix_rcs_modes): Replace algorithm with a more
+ CVSUMASK-friendly one.
+ * sanity.sh (modes): Update tests modes-5, modes-7, modes-10, and
+ modes-15 so they test that CVSUMASK is honored.
+
+Sun Mar 16 10:18:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (modes): New tests modes-7a and modes-7b test behavior
+ if one manually changes the modes in the repository.
+
+ * server.c (server): Revise code which checks for errors creating
+ temporary directory. This won't solve the intermittent
+ can't create temporary directory
+ Unknown error -1
+ but it will mean (a) the right message based on errno gets
+ printed, instead of "unknown error -1", and (b) the message says
+ that it happened in chmod instead of mkdir_p.
+
+Sat Mar 15 16:47:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (modes): New tests. Note that (for now) these are
+ just testing how CVS already behaves; I want to record that before
+ I move on to changing CVS's behavior with modes of RCS files.
+
+13 Mar 1997 Jim Kingdon
+
+ * subr.c (line2argv): Change argv_allocated from size_t to int.
+
+Wed Mar 12 22:16:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add_directory): If repository has an extraneous "."
+ directory at the end, strip it off. This fixes a bug which was
+ introduced when strip_path was nuked (this fix is much more
+ limited in scope than strip_path was; I _think_ that is a good
+ thing).
+ (add): Likewise, for client.
+ (combine_dir): New function, helps with above.
+ * sanity.sh (modules3): Reenable tests for this behavior.
+ (basica-0b, basicb-0e): Adjust test to reflect "foo/bar" instead
+ of "foo/./bar" in message. As with the rest of this, I believe
+ this is just restoring the behavior prior to the strip_path nuking
+ (I tried it with CVS 1.9).
+
+Sun Mar 9 10:06:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * root.c (parse_cvsroot), server.c (serve_root, serve_init):
+ If CVSroot_directory is not an absolute pathname, give a fatal error.
+ * sanity.sh (crerepos): New tests crerepos-6* test for above fixes.
+
+Sat Mar 8 22:06:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ This cleans up the last known code which can overflow its buffers
+ (except the Mac client). I've skimmed through much of CVS looking
+ for other such places; but I didn't read everything. If I missed
+ any please report it to bug-cvs.
+ * logmsg.c (logfile_write, title_proc): Realloc str_list as
+ needed; don't assume MAXLISTLEN is enough.
+ * cvs.h (MAXLISTLEN, MAXFILEPERDIR): Removed; no longer used.
+ * add.c, myndbm.c, parseinfo.c, update.c: Nuke MAXLINELEN limit.
+ * parseinfo.c, update.c, mkmodules.c: Check for errors reading file.
+ * cvs.h (MAXLINELEN): Removed; no longer used.
+ * logmsg (MAXHOSTNAMELEN): Removed; not used.
+ * main.c (cmd_synonyms): Allocate based on fullname, nick1, and
+ nick2, just in case someone makes those big enough so that 100
+ bytes is not enough.
+ (Make_Date): Use MAXDATELEN rather than our own fixed size.
+ * mkmodules.c (mkmodules): Nuke arbitrary limit on line length.
+ * rcs.c (ALLOCINCR): Remove; not used.
+ (RCS_check_kflag): Add comment concerning karg size.
+ * run.c: Allocate run_prog to the needed size, rather than
+ allocating a fixed size buffer.
+
+Fri Mar 7 22:39:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c (logfile_write): Allocate prog to needed length rather
+ than assuming MAXPROGLEN is enough.
+ * cvs.h (MAXPROGLEN): Removed; no longer used.
+ * subr.c (MIN_INCR): Update comment to reflect MAXPROGLEN's demise.
+
+ * subr.c (free_names): Fix comment: this function is not used to
+ free memory allocated by Find_Names (at least it hasn't for a long
+ time).
+ * subr.c, cvs.h (line2argv): Change calling convention so that we
+ allocate argv array rather than the caller. The previous one had
+ no way of checking whether we overflowed the passed-in buffer.
+ * subr.c (free_names): Free the argv array too.
+ * modules.c (do_module, cat_module): Update callers.
+
+Thu Mar 6 12:44:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c: Allocate vhead and vbranch dynamically; removes
+ arbitrary limit.
+ * history.c: Likewise (since_rev, since_tag, backto, rec_types).
+ * ignore.c: Likewise (line). Also check for errors from getline
+ and add 'copyright' notice to top of file.
+ * wrapper.c (wrap_add_file): Likewise (line). Also check for
+ errors from various calls and add 'copyright' notice to top of file.
+
+Tue Mar 4 17:39:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (update_entries): Add comment about "move away <file>"
+ message.
+
+Mon Mar 3 21:51:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb): Clean up topfile,v at end of test. Fixes
+ failure in modules-155b.
+
+Sun Mar 2 18:11:09 1997 Dan Wilder <dan@gasboy.com>
+ and Jim Kingdon
+
+ * admin.c (admin): Arrange to perform recursion if "cvs admin"
+ is passed only options.
+
+Sun Mar 2 18:11:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basicb): New tests basicb-0* test for files at top
+ level.
+
+ * error.c (error): Add newline to "out of memory" message. I think
+ that its omission probably could cause the message to be lost in
+ the bowels of server.c and never passed to the user.
+
+ * client.c (start_rsh_server): Add comment about "remsh" vs. "rsh".
+
+ * cvs.h: Move copyright notice to top of file.
+
+Sun Mar 2 13:44:36 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh: Use -n when testing whether rsh works.
+
+ * server.c (serve_root): Free path.
+
+Sun Mar 2 13:12:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ The following are things that I noticed in the process of trying
+ to track down:
+ can't create temporary directory
+ Unknown error -1
+ FAIL: test 28
+ from nightly testing. I'm not sure that either item explains that
+ message however.
+ * server.c (server): Allocate pending_error_text;
+ print_pending_error will try to free it so
+ pending_error_text = "foo"
+ won't work.
+ (mkdir_p): Don't assume that isdir will leave errno unmolested.
+
+Thu Feb 27 15:29:58 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * remove.c (cvsremove): When forcing removal in client mode, use
+ start_recursion rather than calling CVS_UNLINK on each argument.
+ (remove_force_fileproc): New static function.
+ * sanity.sh (deep): Add tests deep-rm7 through deep-rm10 for above
+ patch.
+
+ * sanity.sh (death): Enable death-76a0 and death-76a1 tests for
+ remote, since they now work.
+
+Wed Feb 26 16:13:26 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (add_prune_candidate): Skip adding this directory if
+ it is the same as the first directory already on the list.
+
+Mon Feb 24 21:36:43 1997 Noel Cragg <noel@gargle.rain.org>
+
+ * main.c (lookup_command_attribute): Add the "init" command to the
+ list of commands that don't use the current working directory.
+
+Sun Feb 23 09:54:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (devcom3): Clean up at end of test.
+
+ * sanity.sh (basicb): Add commented out test basicb-8a0, for
+ whether CVS can print an error on bad numeric revision to diff.
+ Commented out until we get around to fixing CVS.
+ * diff.c (diff_file_nodiff): Add comment about this case.
+
+ * fileattr.c (fileattr_read): If a filename is duplicated,
+ continue to ignore subsequent lines but free the node so that we
+ don't leak memory.
+ * sanity.sh (devcom3): New tests devcom3-8 and devcom3-9 test for
+ behavior on duplicated filenames.
+
+ * fileattr.h: Add comment about unrecognized ENT-TYPE and order of
+ lines in fileattr file.
+ * fileattr.c (struct unrecog, unrecog_head): New variables, to
+ record unrecognized lines.
+ (fileattr_startdir): Assert that unrecog_head == NULL.
+ (fileattr_read): Record unrecognized lines in unrecog_head linked
+ list rather than ignoring them.
+ (fileattr_write): Also write out unrecognized lines, if any.
+ * sanity.sh (devcom3): New tests, test for above fix.
+
+ * fileattr.h (fileattr_modify): Fix example in comment.
+
+Sat Feb 22 08:30:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add variable username.
+ (basica rdiff multibranch log log2): Use it instead of our own
+ (inconsistent) ways of matching an author name.
+
+ * filesubr.c, root.c, rtag.c, server.c, subr.c, update.c,
+ wrapper.c: Nuke PATH_MAX.
+ * cvs.h, wrapper.c (wrap_fromcvs_process_file): Now returns void
+ (return value had been unused).
+ * cvs.h: Adjust comment to reflect the fact that PATH_MAX is
+ gone, at least from src/*.c (except safe_location, as noted).
+
+22 Feb 1997 patch by Tom Hageman <tom@basil.icce.rug.nl> (4 Jun 1996)
+ updated and commented by Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * update.c (checkout_file): Call unlink_file_dir on backup, not
+ unlink_file.
+
+Fri Feb 21 16:40:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove NOTES.
+
+ * NOTES: Removed. bcopy->memcpy is done. "static buffers" I
+ assume refers to what is covered by reentrancy text in HACKING.
+ Obstack idea moved to comment in hash.c (at nodecache). Checking
+ system calls for error returns largely done, and isn't a very
+ helpful suggestion unless you know where the bogus calls are
+ anyway. Sizing limits--we're in the progress of removing them
+ (assuming it meant things like PATH_MAX and earlier, already
+ nuked, limits). Removed various items about changes which were
+ done a long time ago (I realize that the ChangeLog's probably
+ aren't reliable that far back, but I'm not convinced anyone cares
+ anymore). CONFIRM_DIRECTORY_ADDS: I assume this is a
+ reference to the #if 0'd code in add_directory which asks for
+ confirmation--a better way of making it harder to accidentally add
+ directories would be to have to add and commit directories like
+ for files. I don't know what FORCE_MESSAGE_ON_ADD meant.
+
+ * rcs.c (RCS_getrevtime): Fix documentation (in particular, the
+ size of the array that DATE must point to, but many other things
+ too).
+ * patch.c, recurse.c, release.c, remove.c, repos.c: Nuke PATH_MAX.
+ (patch_fileproc): Use MAXDATELEN not hardcoded 50.
+
+Sun Feb 16 12:00:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (client_process_import_file): New variable fullname;
+ pass it to send_modified. This finishes the job of untangling the
+ old short_pathname variable into update_dir vs. fullname.
+
+ * client.c (client_process_import_file): Nuke first_time. If
+ toplevel_repos were ever NULL here, the code would dump core in
+ strncmp a few lines down. And client_import_setup ensures
+ toplevel_repos is not NULL.
+
+Sun Feb 16 08:16:48 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * client.c (client_process_import_file): Rename short_pathname to
+ update_dir (to reflect its function) and make sure that it doesn't
+ point to uninitialized memory if repository and toplevel_repos
+ contain the same string.
+
+Sun Feb 16 08:16:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_rsh_server): Nuke comment about weirdnesses with
+ pre-1.5 versions of CVS and .bashrc/.cshrc. The remote protocol
+ is interoperable only back to 1.5, and people who need to know are
+ unlikely to see this comment anyway.
+
+Sun Dec 15 13:12:30 1996 Michael Douglass <mikedoug@texas.net>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (cmds): Added an entry for new logout command.
+ (cmd_usage): Added an entry for new logout command.
+ (lookup_command_attribute): Added 'logout' to list of commands
+ that set need_to_crate_root to 1.
+ * login.c, cvs.h (logout): New command for removing entries from
+ the .cvspass file.
+ (logout_usage): Usage information on the logout command.
+
+Wed Feb 12 11:19:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (struct send_data): Fix indentation.
+
+Wed Feb 12 08:48:04 1997 Greg A. Woods <woods@most.weird.com>
+
+ * mkmodules.c (loginfo_contents): add missing comma in
+ initializer statement (caused syntax error on SunOS-4).
+
+Tue Feb 11 21:14:28 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * commit.c (find_fileproc): If force_ci is set, set the status to
+ T_MODIFIED even if the file hasn't changed.
+ (commit): Pass force_ci to send_files as new force argument.
+ * client.c (struct send_data): Define.
+ (send_fileproc): The callerdat parameter now points to a send_data
+ struct. If force is set, always call send_modified.
+ (send_dirent_proc): The callerdat parameter now points to a
+ send_data struct.
+ (send_files): Add force parameter. Change all callers. Set up a
+ send_data struct and pass it to start_recursion as callerdat.
+ * client.h (send_files): Update declaration.
+ * sanity.sh (basica): Add a simple test for the above patch.
+
+Sun Feb 9 12:58:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * tag.c (cvstag), rtag.c (rtag): Pass -f to server if specified in
+ the client. I haven't tried to come up with a test case because
+ the fix seems obvious.
+
+ * import.c (add_rcs_file): Change size of altdate1 and altdate2 to
+ MAXDATELEN.
+ * cvs.h (MAXDATELEN): Fix comments; describe what this is for.
+
+ * diff.c (diff_usage): Document --ifdef and try to briefly say
+ what "rcsdiff-options" means.
+
+ * update.c (update): If update had a nonzero status and we haven't
+ yet tried to fetch unpatchable files, go ahead and try it again.
+ The previous behavior was to quit, which meant that updates would
+ keep failing until you hacked around the problem. Patch and bug
+ report by Ian; comment, ChangeLog entry, and willingness to take
+ the flak if checking it is premature by Jim.
+
+ * server.c (alloc_pending): New function.
+ * server.c: Call it. Fixes places where we had neglected to
+ check for NULL return from malloc.
+
+ * sanity.sh (binwrap): Add test binwrap-0, tests for import.c fix
+ below.
+
+Sun, 9 Feb 1997 (submitted 19 Jul 1996) John Polstra <jdp@polstra.com>
+
+ * import.c (import): Give error if the same tag is specified more
+ than once. The previous behavior was to write an RCS file which
+ had the same tag listed twice, once pointing to each revision,
+ which is not legal.
+
+Sun Feb 9 12:37:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkin.c (Checkin): Use cvs_output to print message (should
+ make out of order bugs no worse, as it merely substitues a
+ protocol_pipe vs. stderr_pipe race instead of a stdout_pipe
+ vs. stderr_pipe race). Add comment about stdout vs. stderr.
+
+Fri Feb 7 08:29:52 1997 Josef Nelissen <josef.nelissen@munich.ixos.de>
+
+ * server.c (check_command_legal_p): Don't use ANSI-style definition.
+
+Thu Feb 6 10:55:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * patch.c (patch): Give a fatal error for -V option (see comment
+ for rationale).
+
+ * diff.c (diff): Also send "options" to server. Pretty much the
+ patch submitted independently by josef.nelissen@munich.ixos.de and
+ Ronald Khoo <ronald@demon.net>.
+
+Wed Feb 5 18:57:14 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * modules.c (do_module): Fix typo in 30 Jan 97 PATH_MAX nuking
+ (free -> free_cwd). Testsuite test 151 gets credit for catching
+ this one.
+
+Mon Feb 3 16:14:54 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * main.c (lookup_command_attribute): Don't use an ANSI prototype
+ when defining the function.
+
+Fri Jan 31 12:49:02 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * modules.c (do_module): Actually goto found if is_found is set
+ (fixes thinko in PATH_MAX nuking of 30 Jan 97).
+
+Fri Jan 31 12:49:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add modules3 and big to list of tests to run
+ by default; they were omitted by accident.
+
+Thu Jan 30 11:46:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c, main.c, mkmodules.c, modules.c, parseinfo.c, patch.c:
+ Nuke more PATH_MAX.
+
+ * server.c (server_updated): After we send Created or
+ Update-existing for a file, mark it as unchanged, in case we
+ process it again.
+ * sanity.sh (modules3): New tests, test for above fix.
+
+ * logmsg.c (do_verify): Error return from fopen is NULL, not -1.
+ Pass errno to error().
+
+ * login.c [_CRAY]: Don't declare getpass.
+
+Mon Jan 27 17:25:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * import.c (process_import_file): Fix freeing of rcs (Don't free
+ it before we are done using it, and don't free it twice).
+
+ * modules.c (cat_module): Allocate line right before we use
+ it. The previous code was wrong because the length of the
+ s_h->rest changes between the time we allocate line and the time we
+ sprintf s_h->rest into it.
+
+Sun Jan 26 21:58:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c (expand_path): Revise to call expand_string as
+ needed. Nuke PATH_MAX.
+ * find_names.c (find_dirs): Likewise.
+ * import.c, lock.c: Nuke more PATH_MAX.
+
+ * server.c (mkdir_p): Set retval to 0 at start of function.
+ Previously it had been uninitialized for some cases. Thanks are
+ due to nightly testing for catching this one.
+
+Sat Jan 25 21:34:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * subr.c, cvs.h (expand_string): New function.
+ * rcs.c (getrcskey, getrcsrev): Call it. This greatly reduces the
+ number of calls to realloc if there is a very large file in the
+ RCS file. Credit goes to Mike Heath <mike@pswtech.com> for
+ pointing out the problem and the basic solution (MIN_INCR,
+ MAX_INCR); I adapted it into the separate function expand_string.
+ * sanity.sh (big): New test helps insure this hasn't broken
+ anything obvious.
+
+Wed Jan 22 10:06:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * status.c (status_fileproc): Change message which is printed for
+ T_MODIFIED and ts_conflict set, so that it doesn't say "unresolved
+ confict". This message occurs whether the conflict is resolved or
+ not.
+ * sanity.sh (conflicts): Add tests conflicts-status-* to test
+ output of "cvs status" in the context of conflicts. Tests for
+ above fix.
+
+ * rtag.c (rtag): Send -n if run_module_prog is NOT true.
+
+Thu Jan 16 00:06:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Change version number to 1.9.3.
+
+ * version.c: Version 1.9.2.
+
+Wed Jan 15 09:14:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (call_in_directory): Take code that creates CVSADM at
+ top level, move it before the CVS_CHDIR (dir_name) call, and do it
+ regardless of whether dir_name is ".". Pass "." not dir_name to
+ Create_Admin (when the code was written they were always the
+ same). Don't add reposdirname to the repository we pass to
+ Create_Admin (when the code was written, I think reposdirname
+ probably would always be "."). Don't create CVSADM if
+ reposdirname_absolute.
+ * sanity.sh (basicb): Enable tests basicb-1a and basicb-9a for
+ remote; tests for above fix.
+ (basic1): Do entire test within a "1" directory to deal with
+ creation of CVS directories at top level. Support --keep.
+ (conflicts): In test conflicts-136, only update first-dir.
+ (basica): Uncomment the part that tests "cvs co -l .". That tests
+ the existing functionality which I might have (but hopefully did not)
+ perturbed with the call_in_directory changes.
+
+Mon Jan 13 11:04:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (check_command_legal_p): Do not call error (1, ...)
+ here; that will always cause a protocol violation by shutting down
+ the connection prematurely. Remove croak_on_illegal arg.
+ (do_cvs_command): Move call to check_command_legal_p until after
+ the call to print_pending_error. Print the error message ourself.
+
+ * mkmodules.c (filelist): Add readers and writers. Add comment
+ about why passwd is not included. Add comment about meaning of
+ NULL contents field.
+
+Fri Jan 10 13:23:09 1997 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * release.c (release): Initialize delete_flag before reading it
+ (found by running purify)
+
+ * logmsg.c (do_verify): Fix reading unallocated memory (found by
+ running purify)
+
+Thu Jan 9 16:32:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (build_dirs_and_chdir): Partially revert 3 Jan
+ change--move call to Subdir_Register back above the CVS_CHDIR call
+ (we need to register in the old, not the new, directory). Instead
+ of calling CVS_MKDIR and ignoring errors, call mkdir_if_needed;
+ this is an effort to catch errors there rather than catching them
+ in the CVS_CHDIR. This makes test 27-add-add in sanity.sh work
+ again.
+
+ * find_names.c (Find_Directories): Remove code inside
+ #ifdef ATTIC_DIR_SUPPORT and replace it with a comment explaining
+ why we don't look in the attic. ATTIC_DIR_SUPPORT was never defined.
+
+ * find_names.c (find_dirs): Add comment about tmp being unset.
+
+ * commit.c (checkaddfile): Report errors with errno and specific
+ error messages.
+
+ * rcs.c, commit.c, create_adm.c, entries.c, find_names.c,
+ ignore.c, history.c: Nuke PATH_MAX arbitrary limits.
+
+Wed Jan 8 23:07:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * add.c (add): Reindent a portion which needed it.
+
+1997-01-08 Jim Kingdon
+
+ * client.c (send_file_names): When looking name up in Entries,
+ call Entries_Open and Entries_Close. This has two effects:
+ (1) we look at Entries.Log, and (2) we don't skip 'D' entries,
+ both of which are needed to make us get the right (command
+ line) name for a directory we are adding.
+
+Wed Jan 8 14:50:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, cvs.h, hash.h, myndbm.h, rcs.h: Remove CVSid; we
+ decided to get rid of these some time ago.
+
+Tue Jan 7 12:56:10 1997 Karl Fogel <kfogel@ynu38.ynu.edu.cn>
+
+ * root.c (check_root_consistent): new func, compares below new
+ global var with CVSroot_directory, assuming both set.
+ (set_local_cvsroot): use above new func for security check.
+ (parse_cvsroot): same.
+ But do all of above only #ifdef AUTH_SERVER_SUPPORT.
+
+ * server.c: (Pserver_Repos): new global var, init to NULL.
+ (pserver_authenticate_connection): set above new global.
+ (check_repository_password): be a good scout and use
+ CVSROOTADM and CVSROOTADM_PASSWD, now that they are the standard.
+ Make sure all of above is in #ifdef AUTH_SERVER_SUPPORT.
+ (check_command_legal_p): wrap most of body in #ifdef
+ AUTH_SERVER_SUPPORT.
+ Everywhere: wrap all references to CVS_Username in #ifdef
+ AUTH_SERVER_SUPPORT.
+
+ * cvs.h (Pserver_Repos): new var, used in consistency [security]
+ check. Defined only #ifdef AUTH_SERVER_SUPPORT.
+ (CVSROOTADM_PASSWD): new #define, trying to get with the program.
+
+Fri Jan 3 18:10:39 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * checkout.c (build_dirs_and_chdir): Move call to Subdir_Register
+ until after we know that the directory exists.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in, cvsbug.sh, edit.c, edit.h, error.c, error.h,
+ fileattr.c, fileattr.h, filesubr.c, run.c, update.h, watch.c,
+ watch.h: Remove "675" paragraph; see ../ChangeLog for rationale.
+
+Thu Jan 2 12:27:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (info): New test info-cleanup-verifymsg gets rid of
+ verifymsg when we are done with it.
+
+ * sanity.sh (basicb): Skip tests basicb-1a and basicb-9a for remote.
+ * sanity.sh (modules-155a4): It is OK if a CVS directory exists.
+ * sanity.sh (ignore): Do everything inside a "1" directory. The
+ change to create CVS directories at top-level causes messages such as
+ "? home" otherwise. In test 191, specify -I CVS so that new CVS
+ directory is ignored.
+ * sanity.sh (crerepos): Manually remove CVS directory which had not
+ existed before.
+
+Thu Jan 2 09:06:20 1997 Karl Fogel <kfogel@ynu38.ynu.edu.cn>
+
+ * server.c: Changes for pserver read-only repository access:
+ (check_command_legal_p): new func. Right now, just checks if
+ repository modification is permitted, and that only if pserver is
+ active.
+ (do_cvs_command): take new parameter `cmd_name', a string. All
+ callers changed. Pass it on to new func check_command_legal_p()
+ before executing the command.
+ (CVS_Username): new global, init to NULL. Used by
+ check_command_legal_p(), set in check_password().
+ (check_password): set above new global CVS_Username; reorganized a
+ bit to facilitate this.
+ (check_repository_password): give *host_user_ptr permanent
+ storage iff success.
+
+ * main.c: Changes for pserver read-only repository access:
+ (lookup_command_attribute): new func.
+ (main): use new func lookup_command_attribute() to establish if
+ CVS_CMD_IGNORE_ADMROOT and CVS_CMD_USES_WORK_DIR.
+
+ * cvs.h: Changes for pserver read-only repository access:
+ (CVSROOTADM_READERS, CVSROOTADM_WRITERS): new #defines.
+ Prototype lookup_command_attribute().
+ (CVS_CMD_IGNORE_ADMROOT, CVS_CMD_USES_WORK_DIR,
+ CVS_CMD_MODIFIES_REPOSITORY): new #defines for
+ lookup_command_attribute() and its callers.
+
+Wed Jan 1 19:50:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Reword comment for TMPDIR_DFLT to make it clear
+ that this isn't specific to the pserver server.
+
+ * modules.c (do_module): Give an error message if one tries to
+ specify -a together with another option.
+ * sanity.sh (modules2): New tests modules2-a* test for above fix.
+
+ * sanity.sh (devcom): Add tests devcom-a-nonexist and
+ devcom-t-nonexist for "cvs watchers" on nonexistent argument.
+
+1997-01-01 Fred Fish <fnf@ninemoons.com>
+
+ * run.c (piped_child, filter_stream_through_program): Actually
+ install these HAVE_VFORK patches that got missed.
+ (There was a log entry for these changes for 29 Nov 1996 but it
+ seems I accidentally forgot to actually check them in -kingdon).
+
+Wed Jan 1 18:32:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Add ChangeLog-96.
+ * ChangeLog-96: New file, contains former contents of ChangeLog.
+ * ChangeLog: Now just contains 1997 changes.
+
+
+For older changes see ChangeLog-96.
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..160fa2d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,152 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for GNU CVS program.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+SHELL = /bin/sh
+
+AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib \
+ -I$(top_srcdir)/diff $(ZLIB_CPPFLAGS)
+
+bin_PROGRAMS = cvs
+bin_SCRIPTS = cvsbug
+
+# The cvs executable
+cvs_SOURCES = \
+ add.c \
+ admin.c \
+ annotate.c \
+ buffer.c \
+ checkin.c \
+ checkout.c \
+ classify.c \
+ client.c \
+ commit.c \
+ create_adm.c \
+ cvsrc.c \
+ diff.c \
+ edit.c \
+ entries.c \
+ error.c \
+ exithandle.c \
+ expand_path.c \
+ fileattr.c \
+ filesubr.c \
+ find_names.c \
+ hardlink.c \
+ hash.c \
+ history.c \
+ ignore.c \
+ import.c \
+ lock.c \
+ log.c \
+ log-buffer.c log-buffer.h \
+ login.c \
+ logmsg.c \
+ ls.c \
+ main.c \
+ mkmodules.c \
+ modules.c \
+ ms-buffer.c ms-buffer.h \
+ myndbm.c \
+ no_diff.c \
+ parseinfo.c parseinfo.h \
+ patch.c \
+ rcs.c \
+ rcscmds.c \
+ recurse.c \
+ release.c \
+ remove.c \
+ repos.c \
+ root.c \
+ rsh-client.c rsh-client.h \
+ run.c \
+ scramble.c \
+ server.c \
+ stack.c stack.h \
+ status.c \
+ subr.c subr.h \
+ tag.c \
+ update.c \
+ version.c \
+ vers_ts.c \
+ watch.c \
+ wrapper.c \
+ zlib.c \
+ buffer.h \
+ client.h \
+ cvs.h \
+ edit.h \
+ fileattr.h \
+ hardlink.h \
+ hash.h \
+ history.h \
+ myndbm.h \
+ rcs.h \
+ root.h \
+ server.h \
+ update.h \
+ watch.h
+
+EXTRA_cvs_SOURCES = gssapi-client.c gssapi-client.h \
+ kerberos4-client.c kerberos4-client.h \
+ socket-client.c socket-client.h
+
+cvs_DEPENDENCIES = $(cvs_client_objects) \
+ ../diff/libdiff.a \
+ ../lib/libcvs.a \
+ $(ZLIB_LIBS)
+cvs_LDADD = $(cvs_client_objects) \
+ ../diff/libdiff.a \
+ ../lib/libcvs.a \
+ $(ZLIB_LIBS) \
+ $(LIB_CLOCK_GETTIME) \
+ $(LIB_NANOSLEEP) \
+ $(LIBINTL)
+
+# General
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog-9194 \
+ ChangeLog-9395 \
+ ChangeLog-96 \
+ ChangeLog-97 \
+ build_src.com \
+ sanity.sh
+
+check-local: localcheck remotecheck proxycheck
+
+.PHONY: localcheck
+localcheck: sanity.config.sh
+ $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs$(EXEEXT)
+
+.PHONY: remotecheck
+remotecheck: all sanity.config.sh
+ $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs$(EXEEXT)
+
+.PHONY: proxycheck
+proxycheck: all sanity.config.sh
+ $(SHELL) $(srcdir)/sanity.sh -p `pwd`/cvs$(EXEEXT)
+
+# Our distclean targets
+distclean-local:
+ rm -f check.log check.plog check.plog~
+
+## MAINTAINER Targets
+
+# for backwards compatibility with the old makefiles
+.PHONY: realclean
+realclean: maintainer-clean
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..c7de4c7
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,776 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for GNU CVS program.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = cvs$(EXEEXT)
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/cvsbug.in $(srcdir)/sanity.config.sh.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = cvsbug sanity.config.sh
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am_cvs_OBJECTS = add.$(OBJEXT) admin.$(OBJEXT) annotate.$(OBJEXT) \
+ buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \
+ classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \
+ create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \
+ edit.$(OBJEXT) entries.$(OBJEXT) error.$(OBJEXT) \
+ exithandle.$(OBJEXT) expand_path.$(OBJEXT) fileattr.$(OBJEXT) \
+ filesubr.$(OBJEXT) find_names.$(OBJEXT) hardlink.$(OBJEXT) \
+ hash.$(OBJEXT) history.$(OBJEXT) ignore.$(OBJEXT) \
+ import.$(OBJEXT) lock.$(OBJEXT) log.$(OBJEXT) \
+ log-buffer.$(OBJEXT) login.$(OBJEXT) logmsg.$(OBJEXT) \
+ ls.$(OBJEXT) main.$(OBJEXT) mkmodules.$(OBJEXT) \
+ modules.$(OBJEXT) ms-buffer.$(OBJEXT) myndbm.$(OBJEXT) \
+ no_diff.$(OBJEXT) parseinfo.$(OBJEXT) patch.$(OBJEXT) \
+ rcs.$(OBJEXT) rcscmds.$(OBJEXT) recurse.$(OBJEXT) \
+ release.$(OBJEXT) remove.$(OBJEXT) repos.$(OBJEXT) \
+ root.$(OBJEXT) rsh-client.$(OBJEXT) run.$(OBJEXT) \
+ scramble.$(OBJEXT) server.$(OBJEXT) stack.$(OBJEXT) \
+ status.$(OBJEXT) subr.$(OBJEXT) tag.$(OBJEXT) update.$(OBJEXT) \
+ version.$(OBJEXT) vers_ts.$(OBJEXT) watch.$(OBJEXT) \
+ wrapper.$(OBJEXT) zlib.$(OBJEXT)
+cvs_OBJECTS = $(am_cvs_OBJECTS)
+am__DEPENDENCIES_1 =
+binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(bin_SCRIPTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(cvs_SOURCES) $(EXTRA_cvs_SOURCES)
+DIST_SOURCES = $(cvs_SOURCES) $(EXTRA_cvs_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = /bin/sh
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib \
+ -I$(top_srcdir)/diff $(ZLIB_CPPFLAGS)
+
+bin_SCRIPTS = cvsbug
+
+# The cvs executable
+cvs_SOURCES = \
+ add.c \
+ admin.c \
+ annotate.c \
+ buffer.c \
+ checkin.c \
+ checkout.c \
+ classify.c \
+ client.c \
+ commit.c \
+ create_adm.c \
+ cvsrc.c \
+ diff.c \
+ edit.c \
+ entries.c \
+ error.c \
+ exithandle.c \
+ expand_path.c \
+ fileattr.c \
+ filesubr.c \
+ find_names.c \
+ hardlink.c \
+ hash.c \
+ history.c \
+ ignore.c \
+ import.c \
+ lock.c \
+ log.c \
+ log-buffer.c log-buffer.h \
+ login.c \
+ logmsg.c \
+ ls.c \
+ main.c \
+ mkmodules.c \
+ modules.c \
+ ms-buffer.c ms-buffer.h \
+ myndbm.c \
+ no_diff.c \
+ parseinfo.c parseinfo.h \
+ patch.c \
+ rcs.c \
+ rcscmds.c \
+ recurse.c \
+ release.c \
+ remove.c \
+ repos.c \
+ root.c \
+ rsh-client.c rsh-client.h \
+ run.c \
+ scramble.c \
+ server.c \
+ stack.c stack.h \
+ status.c \
+ subr.c subr.h \
+ tag.c \
+ update.c \
+ version.c \
+ vers_ts.c \
+ watch.c \
+ wrapper.c \
+ zlib.c \
+ buffer.h \
+ client.h \
+ cvs.h \
+ edit.h \
+ fileattr.h \
+ hardlink.h \
+ hash.h \
+ history.h \
+ myndbm.h \
+ rcs.h \
+ root.h \
+ server.h \
+ update.h \
+ watch.h
+
+EXTRA_cvs_SOURCES = gssapi-client.c gssapi-client.h \
+ kerberos4-client.c kerberos4-client.h \
+ socket-client.c socket-client.h
+
+cvs_DEPENDENCIES = $(cvs_client_objects) \
+ ../diff/libdiff.a \
+ ../lib/libcvs.a \
+ $(ZLIB_LIBS)
+
+cvs_LDADD = $(cvs_client_objects) \
+ ../diff/libdiff.a \
+ ../lib/libcvs.a \
+ $(ZLIB_LIBS) \
+ $(LIB_CLOCK_GETTIME) \
+ $(LIB_NANOSLEEP) \
+ $(LIBINTL)
+
+
+# General
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog-9194 \
+ ChangeLog-9395 \
+ ChangeLog-96 \
+ ChangeLog-97 \
+ build_src.com \
+ sanity.sh
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+cvsbug: $(top_builddir)/config.status $(srcdir)/cvsbug.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sanity.config.sh: $(top_builddir)/config.status $(srcdir)/sanity.config.sh.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+cvs$(EXEEXT): $(cvs_OBJECTS) $(cvs_DEPENDENCIES)
+ @rm -f cvs$(EXEEXT)
+ $(LINK) $(cvs_LDFLAGS) $(cvs_OBJECTS) $(cvs_LDADD) $(LIBS)
+install-binSCRIPTS: $(bin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-binSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/admin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/annotate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checkin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checkout.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/classify.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/create_adm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvsrc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/entries.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exithandle.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expand_path.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileattr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filesubr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/find_names.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssapi-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hardlink.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/history.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ignore.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/import.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kerberos4-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/login.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logmsg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ls.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkmodules.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modules.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ms-buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/myndbm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/no_diff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parseinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/patch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcscmds.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recurse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/release.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remove.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repos.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/root.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsh-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scramble.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stack.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vers_ts.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapper.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zlib.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+all-am: Makefile $(PROGRAMS) $(SCRIPTS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-local distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS install-binSCRIPTS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
+ uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \
+ clean-binPROGRAMS clean-generic ctags distclean \
+ distclean-compile distclean-generic distclean-local \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-binSCRIPTS \
+ install-data install-data-am install-exec install-exec-am \
+ install-info install-info-am install-man install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS \
+ uninstall-info-am
+
+
+check-local: localcheck remotecheck proxycheck
+
+.PHONY: localcheck
+localcheck: sanity.config.sh
+ $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs$(EXEEXT)
+
+.PHONY: remotecheck
+remotecheck: all sanity.config.sh
+ $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs$(EXEEXT)
+
+.PHONY: proxycheck
+proxycheck: all sanity.config.sh
+ $(SHELL) $(srcdir)/sanity.sh -p `pwd`/cvs$(EXEEXT)
+
+# Our distclean targets
+distclean-local:
+ rm -f check.log check.plog check.plog~
+
+# for backwards compatibility with the old makefiles
+.PHONY: realclean
+realclean: maintainer-clean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/add.c b/src/add.c
new file mode 100644
index 0000000..02404b5
--- /dev/null
+++ b/src/add.c
@@ -0,0 +1,923 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Add
+ *
+ * Adds a file or directory to the RCS source repository. For a file,
+ * the entry is marked as "needing to be added" in the user's own CVS
+ * directory, and really added to the repository when it is committed.
+ * For a directory, it is added at the appropriate place in the source
+ * repository and a CVS directory is generated within the directory.
+ *
+ * `cvs add' supports `-k <mode>' and `-m <description>' options.
+ * Some may wish to supply other standard "rcs" options here, but I've
+ * found that this causes more trouble than anything else.
+ *
+ * The user files or directories must already exist. For a directory, it must
+ * not already have a CVS file in it.
+ *
+ * An "add" on a file that has been "remove"d but not committed will cause the
+ * file to be resurrected.
+ */
+
+#include <assert.h>
+#include "cvs.h"
+#include "save-cwd.h"
+#include "fileattr.h"
+
+static int add_directory (struct file_info *finfo);
+static int build_entry (const char *repository, const char *user,
+ const char *options, const char *message,
+ List * entries, const char *tag);
+
+static const char *const add_usage[] =
+{
+ "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
+ "\t-k rcs-kflag\tUse \"rcs-kflag\" to add the file with the specified\n",
+ "\t\t\tkflag.\n",
+ "\t-m message\tUse \"message\" for the creation log.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+add (int argc, char **argv)
+{
+ char *message = NULL;
+ int i;
+ char *repository;
+ int c;
+ int err = 0;
+ int added_files = 0;
+ char *options = NULL;
+ List *entries;
+ Vers_TS *vers;
+ struct saved_cwd cwd;
+ /* Nonzero if we found a slash, and are thus adding files in a
+ subdirectory. */
+ int found_slash = 0;
+ size_t cvsroot_len;
+
+ if (argc == 1 || argc == -1)
+ usage (add_usage);
+
+ wrap_setup ();
+
+ /* parse args */
+ optind = 0;
+ while ((c = getopt (argc, argv, "+k:m:")) != -1)
+ {
+ switch (c)
+ {
+ case 'k':
+ if (options) free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+
+ case 'm':
+ if (message) free (message);
+ message = xstrdup (optarg);
+ break;
+ case '?':
+ default:
+ usage (add_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc <= 0)
+ usage (add_usage);
+
+ cvsroot_len = strlen (current_parsed_root->directory);
+
+ /* First some sanity checks. I know that the CVS case is (sort of)
+ also handled by add_directory, but we need to check here so the
+ client won't get all confused in send_file_names. */
+ for (i = 0; i < argc; i++)
+ {
+ int skip_file = 0;
+
+ /* If it were up to me I'd probably make this a fatal error.
+ But some people are really fond of their "cvs add *", and
+ don't seem to object to the warnings.
+ Whatever. */
+ strip_trailing_slashes (argv[i]);
+ if (strcmp (argv[i], ".") == 0
+ || strcmp (argv[i], "..") == 0
+ || fncmp (argv[i], CVSADM) == 0)
+ {
+ if (!quiet)
+ error (0, 0, "cannot add special file `%s'; skipping", argv[i]);
+ skip_file = 1;
+ }
+ else
+ {
+ char *p;
+ p = argv[i];
+ while (*p != '\0')
+ {
+ if (ISSLASH (*p))
+ {
+ found_slash = 1;
+ break;
+ }
+ ++p;
+ }
+ }
+
+ if (skip_file)
+ {
+ int j;
+
+ /* FIXME: We don't do anything about free'ing argv[i]. But
+ the problem is that it is only sometimes allocated (see
+ cvsrc.c). */
+
+ for (j = i; j < argc - 1; ++j)
+ argv[j] = argv[j + 1];
+ --argc;
+ /* Check the new argv[i] again. */
+ --i;
+ ++err;
+ }
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ int j;
+
+ if (argc == 0)
+ /* We snipped out all the arguments in the above sanity
+ check. We can just forget the whole thing (and we
+ better, because if we fired up the server and passed it
+ nothing, it would spit back a usage message). */
+ return err;
+
+ start_server ();
+ ign_setup ();
+ if (options)
+ {
+ send_arg (options);
+ free (options);
+ }
+ option_with_arg ("-m", message);
+ send_arg ("--");
+
+ /* If !found_slash, refrain from sending "Directory", for
+ CVS 1.9 compatibility. If we only tried to deal with servers
+ which are at least CVS 1.9.26 or so, we wouldn't have to
+ special-case this. */
+ if (found_slash)
+ {
+ repository = Name_Repository (NULL, NULL);
+ send_a_repository ("", repository, "");
+ free (repository);
+ }
+
+ for (j = 0; j < argc; ++j)
+ {
+ /* FIXME: Does this erroneously call Create_Admin in error
+ conditions which are only detected once the server gets its
+ hands on things? */
+ if (isdir (argv[j]))
+ {
+ char *tag;
+ char *date;
+ int nonbranch;
+ char *rcsdir;
+ char *p;
+ char *update_dir;
+ /* This is some mungeable storage into which we can point
+ with p and/or update_dir. */
+ char *filedir;
+
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+
+ filedir = xstrdup (argv[j]);
+ /* Deliberately discard the const below since we know we just
+ * allocated filedir and can do what we like with it.
+ */
+ p = (char *)last_component (filedir);
+ if (p == filedir)
+ {
+ update_dir = "";
+ }
+ else
+ {
+ p[-1] = '\0';
+ update_dir = filedir;
+ if (CVS_CHDIR (update_dir) < 0)
+ error (1, errno,
+ "could not chdir to `%s'", update_dir);
+ }
+
+ /* find the repository associated with our current dir */
+ repository = Name_Repository (NULL, update_dir);
+
+ /* don't add stuff to Emptydir */
+ if (strncmp (repository, current_parsed_root->directory, cvsroot_len) == 0
+ && ISSLASH (repository[cvsroot_len])
+ && strncmp (repository + cvsroot_len + 1,
+ CVSROOTADM,
+ sizeof CVSROOTADM - 1) == 0
+ && ISSLASH (repository[cvsroot_len + sizeof CVSROOTADM])
+ && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
+ CVSNULLREPOS) == 0)
+ error (1, 0, "cannot add to `%s'", repository);
+
+ /* before we do anything else, see if we have any
+ per-directory tags */
+ ParseTag (&tag, &date, &nonbranch);
+
+ rcsdir = Xasprintf ("%s/%s", repository, p);
+
+ Create_Admin (p, argv[j], rcsdir, tag, date,
+ nonbranch, 0, 1);
+
+ if (found_slash)
+ send_a_repository ("", repository, update_dir);
+
+ if (restore_cwd (&cwd))
+ error (1, errno,
+ "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+
+ if (tag)
+ free (tag);
+ if (date)
+ free (date);
+ free (rcsdir);
+
+ if (p == filedir)
+ Subdir_Register (NULL, NULL, argv[j]);
+ else
+ {
+ Subdir_Register (NULL, update_dir, p);
+ }
+ free (repository);
+ free (filedir);
+ }
+ }
+ send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("add\012", 0);
+ if (message)
+ free (message);
+ return err + get_responses_and_close ();
+ }
+#endif
+
+ /* walk the arg list adding files/dirs */
+ for (i = 0; i < argc; i++)
+ {
+ int begin_err = err;
+#ifdef SERVER_SUPPORT
+ int begin_added_files = added_files;
+#endif
+ struct file_info finfo;
+ char *filename, *p;
+
+ memset (&finfo, 0, sizeof finfo);
+
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+
+ finfo.fullname = xstrdup (argv[i]);
+ filename = xstrdup (argv[i]);
+ /* We know we can discard the const below since we just allocated
+ * filename and can do as we like with it.
+ */
+ p = (char *)last_component (filename);
+ if (p == filename)
+ {
+ finfo.update_dir = "";
+ finfo.file = p;
+ }
+ else
+ {
+ p[-1] = '\0';
+ finfo.update_dir = filename;
+ finfo.file = p;
+ if (CVS_CHDIR (finfo.update_dir) < 0)
+ error (1, errno, "could not chdir to `%s'", finfo.update_dir);
+ }
+
+ /* Add wrappers for this directory. They exist only until
+ the next call to wrap_add_file. */
+ wrap_add_file (CVSDOTWRAPPER, 1);
+
+ finfo.rcs = NULL;
+
+ /* Find the repository associated with our current dir. */
+ repository = Name_Repository (NULL, finfo.update_dir);
+
+ /* don't add stuff to Emptydir */
+ if (strncmp (repository, current_parsed_root->directory,
+ cvsroot_len) == 0
+ && ISSLASH (repository[cvsroot_len])
+ && strncmp (repository + cvsroot_len + 1,
+ CVSROOTADM,
+ sizeof CVSROOTADM - 1) == 0
+ && ISSLASH (repository[cvsroot_len + sizeof CVSROOTADM])
+ && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
+ CVSNULLREPOS) == 0)
+ error (1, 0, "cannot add to `%s'", repository);
+
+ entries = Entries_Open (0, NULL);
+
+ finfo.repository = repository;
+ finfo.entries = entries;
+
+ /* We pass force_tag_match as 1. If the directory has a
+ sticky branch tag, and there is already an RCS file which
+ does not have that tag, then the head revision is
+ meaningless to us. */
+ vers = Version_TS (&finfo, options, NULL, NULL, 1, 0);
+ if (vers->vn_user == NULL)
+ {
+ /* No entry available, ts_rcs is invalid */
+ if (vers->vn_rcs == NULL)
+ {
+ /* There is no RCS file either */
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file either */
+ error (0, 0, "nothing known about `%s'", finfo.fullname);
+ err++;
+ }
+ else if (!isdir (finfo.file)
+ || wrap_name_has (finfo.file, WRAP_TOCVS))
+ {
+ /*
+ * See if a directory exists in the repository with
+ * the same name. If so, blow this request off.
+ */
+ char *dname = Xasprintf ("%s/%s", repository, finfo.file);
+ if (isdir (dname))
+ {
+ error (0, 0,
+ "cannot add file `%s' since the directory",
+ finfo.fullname);
+ error (0, 0, "`%s' already exists in the repository",
+ dname);
+ error (1, 0, "invalid filename overlap");
+ }
+ free (dname);
+
+ if (vers->options == NULL || *vers->options == '\0')
+ {
+ /* No options specified on command line (or in
+ rcs file if it existed, e.g. the file exists
+ on another branch). Check for a value from
+ the wrapper stuff. */
+ if (wrap_name_has (finfo.file, WRAP_RCSOPTION))
+ {
+ if (vers->options)
+ free (vers->options);
+ vers->options = wrap_rcsoption (finfo.file, 1);
+ }
+ }
+
+ if (vers->nonbranch)
+ {
+ error (0, 0,
+ "cannot add file on non-branch tag `%s'",
+ vers->tag);
+ ++err;
+ }
+ else
+ {
+ /* There is a user file, so build the entry for it */
+ if (build_entry (repository, finfo.file, vers->options,
+ message, entries, vers->tag) != 0)
+ err++;
+ else
+ {
+ added_files++;
+ if (!quiet)
+ {
+ if (vers->tag)
+ error (0, 0, "scheduling %s `%s' for"
+ " addition on branch `%s'",
+ (wrap_name_has (finfo.file,
+ WRAP_TOCVS)
+ ? "wrapper"
+ : "file"),
+ finfo.fullname, vers->tag);
+ else
+ error (0, 0,
+ "scheduling %s `%s' for addition",
+ (wrap_name_has (finfo.file,
+ WRAP_TOCVS)
+ ? "wrapper"
+ : "file"),
+ finfo.fullname);
+ }
+ }
+ }
+ }
+ }
+ else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
+ {
+ if (isdir (finfo.file)
+ && !wrap_name_has (finfo.file, WRAP_TOCVS))
+ {
+ error (0, 0,
+ "the directory `%s' cannot be added because a file"
+ " of the", finfo.fullname);
+ error (1, 0, "same name already exists in the repository.");
+ }
+ else
+ {
+ if (vers->nonbranch)
+ {
+ error (0, 0,
+ "cannot add file on non-branch tag `%s'",
+ vers->tag);
+ ++err;
+ }
+ else
+ {
+ char *timestamp = NULL;
+ if (vers->ts_user == NULL)
+ {
+ /* If this file does not exist locally, assume that
+ * the last version on the branch is being
+ * resurrected.
+ *
+ * Compute previous revision. We assume that it
+ * exists and that it is not a revision on the
+ * trunk of the form X.1 (1.1, 2.1, 3.1, ...). We
+ * also assume that it is not dead, which seems
+ * fair since we know vers->vn_rcs is dead
+ * and we shouldn't see two dead revisions in a
+ * row.
+ */
+ char *prev = previous_rev (vers->srcfile,
+ vers->vn_rcs);
+ int status;
+ if (prev == NULL)
+ {
+ /* There is no previous revision. Either:
+ *
+ * * Revision 1.1 was dead, as when a file was
+ * inititially added on a branch,
+ *
+ * or
+ *
+ * * All previous revisions have been deleted.
+ * For instance, via `admin -o'.
+ */
+ if (!really_quiet)
+ error (0, 0,
+"File `%s' has no previous revision to resurrect.",
+ finfo.fullname);
+ free (prev);
+ goto skip_this_file;
+ }
+ if (!quiet)
+ error (0, 0,
+"Resurrecting file `%s' from revision %s.",
+ finfo.fullname, prev);
+ status = RCS_checkout (vers->srcfile, finfo.file,
+ prev, vers->tag,
+ vers->options, RUN_TTY,
+ NULL, NULL);
+ xchmod (finfo.file, 1);
+ if (status != 0)
+ {
+ error (0, 0, "Failed to resurrect revision %s",
+ prev);
+ err++;
+ }
+ else
+ {
+ /* I don't actually set vers->ts_user here
+ * because it would confuse server_update().
+ */
+ timestamp = time_stamp (finfo.file);
+ if (!really_quiet)
+ write_letter (&finfo, 'U');
+ }
+ free (prev);
+ }
+ if (!quiet)
+ {
+ char *bbuf;
+ if (vers->tag)
+ {
+ bbuf = Xasprintf (" on branch `%s'",
+ vers->tag);
+ }
+ else
+ bbuf = "";
+ error (0, 0,
+"Re-adding file `%s'%s after dead revision %s.",
+ finfo.fullname, bbuf, vers->vn_rcs);
+ if (vers->tag)
+ free (bbuf);
+ }
+ Register (entries, finfo.file, "0",
+ timestamp ? timestamp : vers->ts_user,
+ vers->options, vers->tag, vers->date, NULL);
+ if (timestamp) free (timestamp);
+#ifdef SERVER_SUPPORT
+ if (server_active && vers->ts_user == NULL)
+ {
+ /* If we resurrected the file from the archive, we
+ * need to tell the client about it.
+ */
+ server_updated (&finfo, vers,
+ SERVER_UPDATED,
+ (mode_t) -1, NULL, NULL);
+ /* This is kinda hacky or, at least, it renders the
+ * name "begin_added_files" obsolete, but we want
+ * the added_files to be counted without triggering
+ * the check that causes server_checked_in() to be
+ * called below since we have already called
+ * server_updated() to complete the resurrection.
+ */
+ ++begin_added_files;
+ }
+#endif
+ ++added_files;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * There is an RCS file already, so somebody else must've
+ * added it
+ */
+ error (0, 0, "`%s' added independently by second party",
+ finfo.fullname);
+ err++;
+ }
+ }
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ {
+
+ /*
+ * An entry for a new-born file, ts_rcs is dummy, but that is
+ * inappropriate here
+ */
+ if (!quiet)
+ error (0, 0, "`%s' has already been entered", finfo.fullname);
+ err++;
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ /* An entry for a removed file, ts_rcs is invalid */
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file (as it should be) */
+ if (vers->vn_rcs == NULL)
+ {
+
+ /*
+ * There is no RCS file, so somebody else must've removed
+ * it from under us
+ */
+ error (0, 0,
+ "cannot resurrect `%s'; RCS file removed by"
+ " second party", finfo.fullname);
+ err++;
+ }
+ else
+ {
+ int status;
+ /*
+ * There is an RCS file, so remove the "-" from the
+ * version number and restore the file
+ */
+ char *tmp = xstrdup (vers->vn_user + 1);
+ (void) strcpy (vers->vn_user, tmp);
+ free (tmp);
+ status = RCS_checkout (vers->srcfile, finfo.file,
+ vers->vn_user, vers->tag,
+ vers->options, RUN_TTY,
+ NULL, NULL);
+ xchmod (finfo.file, cvswrite);
+ if (status != 0)
+ {
+ error (0, 0, "Failed to resurrect revision %s.",
+ vers->vn_user);
+ err++;
+ tmp = NULL;
+ }
+ else
+ {
+ /* I don't actually set vers->ts_user here because it
+ * would confuse server_update().
+ */
+ tmp = time_stamp (finfo.file);
+ write_letter (&finfo, 'U');
+ if (!quiet)
+ error (0, 0, "`%s', version %s, resurrected",
+ finfo.fullname, vers->vn_user);
+ }
+ Register (entries, finfo.file, vers->vn_user,
+ tmp, vers->options,
+ vers->tag, vers->date, NULL);
+ if (tmp) free (tmp);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* If we resurrected the file from the archive, we
+ * need to tell the client about it.
+ */
+ server_updated (&finfo, vers,
+ SERVER_UPDATED,
+ (mode_t) -1, NULL, NULL);
+ }
+ /* We don't increment added_files here because this isn't
+ * a change that needs to be committed.
+ */
+#endif
+ }
+ }
+ else
+ {
+ /* The user file shouldn't be there */
+ error (0, 0, "\
+`%s' should be removed and is still there (or is back again)", finfo.fullname);
+ err++;
+ }
+ }
+ else
+ {
+ /* A normal entry, ts_rcs is valid, so it must already be there */
+ if (!quiet)
+ error (0, 0, "`%s' already exists, with version number %s",
+ finfo.fullname,
+ vers->vn_user);
+ err++;
+ }
+ freevers_ts (&vers);
+
+ /* passed all the checks. Go ahead and add it if its a directory */
+ if (begin_err == err
+ && isdir (finfo.file)
+ && !wrap_name_has (finfo.file, WRAP_TOCVS))
+ {
+ err += add_directory (&finfo);
+ }
+ else
+ {
+#ifdef SERVER_SUPPORT
+ if (server_active && begin_added_files != added_files)
+ server_checked_in (finfo.file, finfo.update_dir, repository);
+#endif
+ }
+
+skip_this_file:
+ free (repository);
+ Entries_Close (entries);
+
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+
+ /* It's okay to discard the const to free this - we allocated this
+ * above. The const is for everybody else.
+ */
+ free ((char *) finfo.fullname);
+ free (filename);
+ }
+ if (added_files && !really_quiet)
+ error (0, 0, "use `%s commit' to add %s permanently",
+ program_name,
+ (added_files == 1) ? "this file" : "these files");
+
+ if (message)
+ free (message);
+ if (options)
+ free (options);
+
+ return err;
+}
+
+
+
+/*
+ * The specified user file is really a directory. So, let's make sure that
+ * it is created in the RCS source repository, and that the user's directory
+ * is updated to include a CVS directory.
+ *
+ * Returns 1 on failure, 0 on success.
+ */
+static int
+add_directory (struct file_info *finfo)
+{
+ const char *repository = finfo->repository;
+ List *entries = finfo->entries;
+ const char *dir = finfo->file;
+
+ char *rcsdir = NULL;
+ struct saved_cwd cwd;
+ char *message = NULL;
+ char *tag, *date;
+ int nonbranch;
+ char *attrs;
+
+ if (strchr (dir, '/') != NULL)
+ {
+ /* "Can't happen". */
+ error (0, 0,
+ "directory %s not added; must be a direct sub-directory", dir);
+ return 1;
+ }
+ if (fncmp (dir, CVSADM) == 0)
+ {
+ error (0, 0, "cannot add a `%s' directory", CVSADM);
+ return 1;
+ }
+
+ /* before we do anything else, see if we have any per-directory tags */
+ ParseTag (&tag, &date, &nonbranch);
+
+ /* Remember the default attributes from this directory, so we can apply
+ them to the new directory. */
+ fileattr_startdir (repository);
+ attrs = fileattr_getall (NULL);
+ fileattr_free ();
+
+ /* now, remember where we were, so we can get back */
+ if (save_cwd (&cwd))
+ {
+ error (0, errno, "Failed to save current directory.");
+ return 1;
+ }
+ if (CVS_CHDIR (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", finfo->fullname);
+ return 1;
+ }
+ if (!server_active && isfile (CVSADM))
+ {
+ error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM);
+ goto out;
+ }
+
+ rcsdir = Xasprintf ("%s/%s", repository, dir);
+ if (isfile (rcsdir) && !isdir (rcsdir))
+ {
+ error (0, 0, "%s is not a directory; %s not added", rcsdir,
+ finfo->fullname);
+ goto out;
+ }
+
+ /* setup the log message */
+ message = Xasprintf ("Directory %s added to the repository\n%s%s%s%s%s%s",
+ rcsdir,
+ tag ? "--> Using per-directory sticky tag `" : "",
+ tag ? tag : "", tag ? "'\n" : "",
+ date ? "--> Using per-directory sticky date `" : "",
+ date ? date : "", date ? "'\n" : "");
+
+ if (!isdir (rcsdir))
+ {
+ mode_t omask;
+ Node *p;
+ List *ulist;
+ struct logfile_info *li;
+
+ /* There used to be some code here which would prompt for
+ whether to add the directory. The details of that code had
+ bitrotted, but more to the point it can't work
+ client/server, doesn't ask in the right way for GUIs, etc.
+ A better way of making it harder to accidentally add
+ directories would be to have to add and commit directories
+ like for files. The code was #if 0'd at least since CVS 1.5. */
+
+ if (!noexec)
+ {
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (rcsdir, 0777) < 0)
+ {
+ error (0, errno, "cannot mkdir %s", rcsdir);
+ (void) umask (omask);
+ goto out;
+ }
+ (void) umask (omask);
+ }
+
+ /* Now set the default file attributes to the ones we inherited
+ from the parent directory. */
+ fileattr_startdir (rcsdir);
+ fileattr_setall (NULL, attrs);
+ fileattr_write ();
+ fileattr_free ();
+ if (attrs != NULL)
+ free (attrs);
+
+ /*
+ * Set up an update list with a single title node for Update_Logfile
+ */
+ ulist = getlist ();
+ p = getnode ();
+ p->type = UPDATE;
+ p->delproc = update_delproc;
+ p->key = xstrdup ("- New directory");
+ li = xmalloc (sizeof (struct logfile_info));
+ li->type = T_TITLE;
+ li->tag = xstrdup (tag);
+ li->rev_old = li->rev_new = NULL;
+ p->data = li;
+ (void) addnode (ulist, p);
+ Update_Logfile (rcsdir, message, NULL, ulist);
+ dellist (&ulist);
+ }
+
+ if (server_active)
+ WriteTemplate (finfo->fullname, 1, rcsdir);
+ else
+ Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1);
+
+ if (tag)
+ free (tag);
+ if (date)
+ free (date);
+
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+
+ Subdir_Register (entries, NULL, dir);
+
+ if (!really_quiet)
+ cvs_output (message, 0);
+
+ free (rcsdir);
+ free (message);
+
+ return 0;
+
+out:
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+ if (message) free (message);
+ if (rcsdir != NULL)
+ free (rcsdir);
+ return 0;
+}
+
+
+
+/*
+ * Builds an entry for a new file and sets up "CVS/file",[pt] by
+ * interrogating the user. Returns non-zero on error.
+ */
+static int
+build_entry (const char *repository, const char *user, const char *options,
+ const char *message, List *entries, const char *tag)
+{
+ char *fname;
+ char *line;
+ FILE *fp;
+
+ if (noexec)
+ return 0;
+
+ /*
+ * The requested log is read directly from the user and stored in the
+ * file user,t. If the "message" argument is set, use it as the
+ * initial creation log (which typically describes the file).
+ */
+ fname = Xasprintf ("%s/%s%s", CVSADM, user, CVSEXT_LOG);
+ fp = xfopen (fname, "w+");
+ if (message && fputs (message, fp) == EOF)
+ error (1, errno, "cannot write to %s", fname);
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", fname);
+ free (fname);
+
+ /*
+ * Create the entry now, since this allows the user to interrupt us above
+ * without needing to clean anything up (well, we could clean up the
+ * ,t file, but who cares).
+ */
+ line = Xasprintf ("Initial %s", user);
+ Register (entries, user, "0", line, options, tag, NULL, NULL);
+ free (line);
+ return 0;
+}
diff --git a/src/admin.c b/src/admin.c
new file mode 100644
index 0000000..3558493
--- /dev/null
+++ b/src/admin.c
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Administration ("cvs admin")
+ *
+ */
+
+#include "cvs.h"
+#ifdef CVS_ADMIN_GROUP
+#include <grp.h>
+#endif
+
+static Dtype admin_dirproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int admin_fileproc (void *callerdat, struct file_info *finfo);
+
+static const char *const admin_usage[] =
+{
+ "Usage: %s %s [options] files...\n",
+ "\t-a users Append (comma-separated) user names to access list.\n",
+ "\t-A file Append another file's access list.\n",
+ "\t-b[rev] Set default branch (highest branch on trunk if omitted).\n",
+ "\t-c string Set comment leader.\n",
+ "\t-e[users] Remove (comma-separated) user names from access list\n",
+ "\t (all names if omitted).\n",
+ "\t-I Run interactively.\n",
+ "\t-k subst Set keyword substitution mode:\n",
+ "\t kv (Default) Substitute keyword and value.\n",
+ "\t kvl Substitute keyword, value, and locker (if any).\n",
+ "\t k Substitute keyword only.\n",
+ "\t o Preserve original string.\n",
+ "\t b Like o, but mark file as binary.\n",
+ "\t v Substitute value only.\n",
+ "\t-l[rev] Lock revision (latest revision on branch,\n",
+ "\t latest revision on trunk if omitted).\n",
+ "\t-L Set strict locking.\n",
+ "\t-m rev:msg Replace revision's log message.\n",
+ "\t-n tag[:[rev]] Tag branch or revision. If :rev is omitted,\n",
+ "\t delete the tag; if rev is omitted, tag the latest\n",
+ "\t revision on the default branch.\n",
+ "\t-N tag[:[rev]] Same as -n except override existing tag.\n",
+ "\t-o range Delete (outdate) specified range of revisions:\n",
+ "\t rev1:rev2 Between rev1 and rev2, including rev1 and rev2.\n",
+ "\t rev1::rev2 Between rev1 and rev2, excluding rev1 and rev2.\n",
+ "\t rev: rev and following revisions on the same branch.\n",
+ "\t rev:: After rev on the same branch.\n",
+ "\t :rev rev and previous revisions on the same branch.\n",
+ "\t ::rev Before rev on the same branch.\n",
+ "\t rev Just rev.\n",
+ "\t-q Run quietly.\n",
+ "\t-s state[:rev] Set revision state (latest revision on branch,\n",
+ "\t latest revision on trunk if omitted).\n",
+ "\t-t[file] Get descriptive text from file (stdin if omitted).\n",
+ "\t-t-string Set descriptive text.\n",
+ "\t-u[rev] Unlock the revision (latest revision on branch,\n",
+ "\t latest revision on trunk if omitted).\n",
+ "\t-U Unset strict locking.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+/* This structure is used to pass information through start_recursion. */
+struct admin_data
+{
+ /* Set default branch (-b). It is "-b" followed by the value
+ given, or NULL if not specified, or merely "-b" if -b is
+ specified without a value. */
+ char *branch;
+
+ /* Set comment leader (-c). It is "-c" followed by the value
+ given, or NULL if not specified. The comment leader is
+ relevant only for old versions of RCS, but we let people set it
+ anyway. */
+ char *comment;
+
+ /* Set strict locking (-L). */
+ int set_strict;
+
+ /* Set nonstrict locking (-U). */
+ int set_nonstrict;
+
+ /* Delete revisions (-o). It is "-o" followed by the value specified. */
+ char *delete_revs;
+
+ /* Keyword substitution mode (-k), e.g. "-kb". */
+ char *kflag;
+
+ /* Description (-t). */
+ char *desc;
+
+ /* Interactive (-I). Problematic with client/server. */
+ int interactive;
+
+ /* This is the cheesy part. It is a vector with the options which
+ we don't deal with above (e.g. "-afoo" "-abar,baz"). In the future
+ this presumably will be replaced by other variables which break
+ out the data in a more convenient fashion. AV as well as each of
+ the strings it points to is malloc'd. */
+ int ac;
+ char **av;
+ int av_alloc;
+};
+
+/* Add an argument. OPT is the option letter, e.g. 'a'. ARG is the
+ argument to that option, or NULL if omitted (whether NULL can actually
+ happen depends on whether the option was specified as optional to
+ getopt). */
+static void
+arg_add (struct admin_data *dat, int opt, char *arg)
+{
+ char *newelt = Xasprintf ("-%c%s", opt, arg ? arg : "");
+
+ if (dat->av_alloc == 0)
+ {
+ dat->av_alloc = 1;
+ dat->av = xnmalloc (dat->av_alloc, sizeof (*dat->av));
+ }
+ else if (dat->ac >= dat->av_alloc)
+ {
+ dat->av_alloc *= 2;
+ dat->av = xnrealloc (dat->av, dat->av_alloc, sizeof (*dat->av));
+ }
+ dat->av[dat->ac++] = newelt;
+}
+
+
+
+/*
+ * callback proc to run a script when admin finishes.
+ */
+static int
+postadmin_proc (const char *repository, const char *filter, void *closure)
+{
+ char *cmdline;
+ const char *srepos = Short_Repository (repository);
+
+ TRACE (TRACE_FUNCTION, "postadmin_proc (%s, %s)", repository, filter);
+
+ /* %c = cvs_cmd_name
+ * %R = referrer
+ * %p = shortrepos
+ * %r = repository
+ */
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ false, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s", current_parsed_root->directory,
+ (char *) NULL);
+
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ error (0, 0, "postadmin proc resolved to the empty string!");
+ return 1;
+ }
+
+ run_setup (cmdline);
+
+ free (cmdline);
+
+ /* FIXME - read the comment in verifymsg_proc() about why we use abs()
+ * below() and shouldn't.
+ */
+ return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_NORMAL | RUN_SIGIGNORE));
+}
+
+
+
+/*
+ * Call any postadmin procs.
+ */
+static int
+admin_filesdoneproc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ TRACE (TRACE_FUNCTION, "admin_filesdoneproc (%d, %s, %s)", err, repository,
+ update_dir);
+ Parse_Info (CVSROOTADM_POSTADMIN, repository, postadmin_proc, PIOPT_ALL,
+ NULL);
+
+ return err;
+}
+
+
+
+int
+admin (int argc, char **argv)
+{
+ int err;
+#ifdef CVS_ADMIN_GROUP
+ struct group *grp;
+ struct group *getgrnam (const char *);
+#endif
+ struct admin_data admin_data;
+ int c;
+ int i;
+ bool only_allowed_options;
+
+ if (argc <= 1)
+ usage (admin_usage);
+
+ wrap_setup ();
+
+ memset (&admin_data, 0, sizeof admin_data);
+
+ /* TODO: get rid of `-' switch notation in admin_data. For
+ example, admin_data->branch should be not `-bfoo' but simply `foo'. */
+
+ optind = 0;
+ only_allowed_options = true;
+ while ((c = getopt (argc, argv,
+ "+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1)
+ {
+ if (
+# ifdef CLIENT_SUPPORT
+ !current_parsed_root->isremote &&
+# endif /* CLIENT_SUPPORT */
+ c != 'q' && !strchr (config->UserAdminOptions, c)
+ )
+ only_allowed_options = false;
+
+ switch (c)
+ {
+ case 'i':
+ /* This has always been documented as useless in cvs.texinfo
+ and it really is--admin_fileproc silently does nothing
+ if vers->vn_user is NULL. */
+ error (0, 0, "the -i option to admin is not supported");
+ error (0, 0, "run add or import to create an RCS file");
+ goto usage_error;
+
+ case 'b':
+ if (admin_data.branch != NULL)
+ {
+ error (0, 0, "duplicate 'b' option");
+ goto usage_error;
+ }
+ if (optarg == NULL)
+ admin_data.branch = xstrdup ("-b");
+ else
+ admin_data.branch = Xasprintf ("-b%s", optarg);
+ break;
+
+ case 'c':
+ if (admin_data.comment != NULL)
+ {
+ error (0, 0, "duplicate 'c' option");
+ goto usage_error;
+ }
+ admin_data.comment = Xasprintf ("-c%s", optarg);
+ break;
+
+ case 'a':
+ arg_add (&admin_data, 'a', optarg);
+ break;
+
+ case 'A':
+ /* In the client/server case, this is cheesy because
+ we just pass along the name of the RCS file, which
+ then will want to exist on the server. This is
+ accidental; having the client specify a pathname on
+ the server is not a design feature of the protocol. */
+ arg_add (&admin_data, 'A', optarg);
+ break;
+
+ case 'e':
+ arg_add (&admin_data, 'e', optarg);
+ break;
+
+ case 'l':
+ /* Note that multiple -l options are valid. */
+ arg_add (&admin_data, 'l', optarg);
+ break;
+
+ case 'u':
+ /* Note that multiple -u options are valid. */
+ arg_add (&admin_data, 'u', optarg);
+ break;
+
+ case 'L':
+ /* Probably could also complain if -L is specified multiple
+ times, although RCS doesn't and I suppose it is reasonable
+ just to have it mean the same as a single -L. */
+ if (admin_data.set_nonstrict)
+ {
+ error (0, 0, "-U and -L are incompatible");
+ goto usage_error;
+ }
+ admin_data.set_strict = 1;
+ break;
+
+ case 'U':
+ /* Probably could also complain if -U is specified multiple
+ times, although RCS doesn't and I suppose it is reasonable
+ just to have it mean the same as a single -U. */
+ if (admin_data.set_strict)
+ {
+ error (0, 0, "-U and -L are incompatible");
+ goto usage_error;
+ }
+ admin_data.set_nonstrict = 1;
+ break;
+
+ case 'n':
+ /* Mostly similar to cvs tag. Could also be parsing
+ the syntax of optarg, although for now we just pass
+ it to rcs as-is. Note that multiple -n options are
+ valid. */
+ arg_add (&admin_data, 'n', optarg);
+ break;
+
+ case 'N':
+ /* Mostly similar to cvs tag. Could also be parsing
+ the syntax of optarg, although for now we just pass
+ it to rcs as-is. Note that multiple -N options are
+ valid. */
+ arg_add (&admin_data, 'N', optarg);
+ break;
+
+ case 'm':
+ /* Change log message. Could also be parsing the syntax
+ of optarg, although for now we just pass it to rcs
+ as-is. Note that multiple -m options are valid. */
+ arg_add (&admin_data, 'm', optarg);
+ break;
+
+ case 'o':
+ /* Delete revisions. Probably should also be parsing the
+ syntax of optarg, so that the client can give errors
+ rather than making the server take care of that.
+ Other than that I'm not sure whether it matters much
+ whether we parse it here or in admin_fileproc.
+
+ Note that multiple -o options are invalid, in RCS
+ as well as here. */
+
+ if (admin_data.delete_revs != NULL)
+ {
+ error (0, 0, "duplicate '-o' option");
+ goto usage_error;
+ }
+ admin_data.delete_revs = Xasprintf ("-o%s", optarg);
+ break;
+
+ case 's':
+ /* Note that multiple -s options are valid. */
+ arg_add (&admin_data, 's', optarg);
+ break;
+
+ case 't':
+ if (admin_data.desc != NULL)
+ {
+ error (0, 0, "duplicate 't' option");
+ goto usage_error;
+ }
+ if (optarg != NULL && optarg[0] == '-')
+ admin_data.desc = xstrdup (optarg + 1);
+ else
+ {
+ size_t bufsize = 0;
+ size_t len;
+
+ get_file (optarg, optarg, "r", &admin_data.desc,
+ &bufsize, &len);
+ }
+ break;
+
+ case 'I':
+ /* At least in RCS this can be specified several times,
+ with the same meaning as being specified once. */
+ admin_data.interactive = 1;
+ break;
+
+ case 'q':
+ /* Silently set the global really_quiet flag. This keeps admin in
+ * sync with the RCS man page and allows us to silently support
+ * older servers when necessary.
+ *
+ * Some logic says we might want to output a deprecation warning
+ * here, but I'm opting not to in order to stay quietly in sync
+ * with the RCS man page.
+ */
+ really_quiet = 1;
+ break;
+
+ case 'x':
+ error (0, 0, "the -x option has never done anything useful");
+ error (0, 0, "RCS files in CVS always end in ,v");
+ goto usage_error;
+
+ case 'V':
+ /* No longer supported. */
+ error (0, 0, "the `-V' option is obsolete");
+ break;
+
+ case 'k':
+ if (admin_data.kflag != NULL)
+ {
+ error (0, 0, "duplicate '-k' option");
+ goto usage_error;
+ }
+ admin_data.kflag = RCS_check_kflag (optarg);
+ break;
+ default:
+ case '?':
+ /* getopt will have printed an error message. */
+
+ usage_error:
+ /* Don't use cvs_cmd_name; it might be "server". */
+ error (1, 0, "specify %s -H admin for usage information",
+ program_name);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CVS_ADMIN_GROUP
+ /* The use of `cvs admin -k' is unrestricted. However, any other
+ option is restricted if the group CVS_ADMIN_GROUP exists on the
+ server. */
+ /* This is only "secure" on the server, since the user could edit the
+ * RCS file on a local host, but some people like this kind of
+ * check anyhow. The alternative would be to check only when
+ * (server_active) rather than when not on the client.
+ */
+ if (!current_parsed_root->isremote && !only_allowed_options &&
+ (grp = getgrnam(CVS_ADMIN_GROUP)) != NULL)
+ {
+#ifdef HAVE_GETGROUPS
+ gid_t *grps;
+ int n;
+
+ /* get number of auxiliary groups */
+ n = getgroups (0, NULL);
+ if (n < 0)
+ error (1, errno, "unable to get number of auxiliary groups");
+ grps = xnmalloc (n + 1, sizeof *grps);
+ n = getgroups (n, grps);
+ if (n < 0)
+ error (1, errno, "unable to get list of auxiliary groups");
+ grps[n] = getgid ();
+ for (i = 0; i <= n; i++)
+ if (grps[i] == grp->gr_gid) break;
+ free (grps);
+ if (i > n)
+ error (1, 0, "usage is restricted to members of the group %s",
+ CVS_ADMIN_GROUP);
+#else
+ char *me = getcaller ();
+ char **grnam;
+
+ for (grnam = grp->gr_mem; *grnam; grnam++)
+ if (strcmp (*grnam, me) == 0) break;
+ if (!*grnam && getgid () != grp->gr_gid)
+ error (1, 0, "usage is restricted to members of the group %s",
+ CVS_ADMIN_GROUP);
+#endif
+ }
+#endif /* defined CVS_ADMIN_GROUP */
+
+ for (i = 0; i < admin_data.ac; ++i)
+ {
+ assert (admin_data.av[i][0] == '-');
+ switch (admin_data.av[i][1])
+ {
+ case 'm':
+ case 'l':
+ case 'u':
+ check_numeric (&admin_data.av[i][2], argc, argv);
+ break;
+ default:
+ break;
+ }
+ }
+ if (admin_data.branch != NULL)
+ check_numeric (admin_data.branch + 2, argc, argv);
+ if (admin_data.delete_revs != NULL)
+ {
+ char *p;
+
+ check_numeric (admin_data.delete_revs + 2, argc, argv);
+ p = strchr (admin_data.delete_revs + 2, ':');
+ if (p != NULL && isdigit ((unsigned char) p[1]))
+ check_numeric (p + 1, argc, argv);
+ else if (p != NULL && p[1] == ':' && isdigit ((unsigned char) p[2]))
+ check_numeric (p + 2, argc, argv);
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ /* Note that option_with_arg does not work for us, because some
+ of the options must be sent without a space between the option
+ and its argument. */
+ if (admin_data.interactive)
+ error (1, 0, "-I option not useful with client/server");
+ if (admin_data.branch != NULL)
+ send_arg (admin_data.branch);
+ if (admin_data.comment != NULL)
+ send_arg (admin_data.comment);
+ if (admin_data.set_strict)
+ send_arg ("-L");
+ if (admin_data.set_nonstrict)
+ send_arg ("-U");
+ if (admin_data.delete_revs != NULL)
+ send_arg (admin_data.delete_revs);
+ if (admin_data.desc != NULL)
+ {
+ char *p = admin_data.desc;
+ send_to_server ("Argument -t-", 0);
+ while (*p)
+ {
+ if (*p == '\n')
+ {
+ send_to_server ("\012Argumentx ", 0);
+ ++p;
+ }
+ else
+ {
+ char *q = strchr (p, '\n');
+ if (q == NULL) q = p + strlen (p);
+ send_to_server (p, q - p);
+ p = q;
+ }
+ }
+ send_to_server ("\012", 1);
+ }
+ /* Send this for all really_quiets since we know that it will be silently
+ * ignored when unneeded. This supports old servers.
+ */
+ if (really_quiet)
+ send_arg ("-q");
+ if (admin_data.kflag != NULL)
+ send_arg (admin_data.kflag);
+
+ for (i = 0; i < admin_data.ac; ++i)
+ send_arg (admin_data.av[i]);
+
+ send_arg ("--");
+ send_files (argc, argv, 0, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("admin\012", 0);
+ err = get_responses_and_close ();
+ goto return_it;
+ }
+#endif /* CLIENT_SUPPORT */
+
+ lock_tree_promotably (argc, argv, 0, W_LOCAL, 0);
+
+ err = start_recursion
+ (admin_fileproc, admin_filesdoneproc, admin_dirproc,
+ NULL, &admin_data,
+ argc, argv, 0,
+ W_LOCAL, 0, CVS_LOCK_WRITE, NULL, 1, NULL);
+
+ Lock_Cleanup ();
+
+/* This just suppresses a warning from -Wall. */
+#ifdef CLIENT_SUPPORT
+ return_it:
+#endif /* CLIENT_SUPPORT */
+ if (admin_data.branch != NULL)
+ free (admin_data.branch);
+ if (admin_data.comment != NULL)
+ free (admin_data.comment);
+ if (admin_data.delete_revs != NULL)
+ free (admin_data.delete_revs);
+ if (admin_data.kflag != NULL)
+ free (admin_data.kflag);
+ if (admin_data.desc != NULL)
+ free (admin_data.desc);
+ for (i = 0; i < admin_data.ac; ++i)
+ free (admin_data.av[i]);
+ if (admin_data.av != NULL)
+ free (admin_data.av);
+
+ return err;
+}
+
+
+
+/*
+ * Called to run "rcs" on a particular file.
+ */
+/* ARGSUSED */
+static int
+admin_fileproc (void *callerdat, struct file_info *finfo)
+{
+ struct admin_data *admin_data = (struct admin_data *) callerdat;
+ Vers_TS *vers;
+ char *version;
+ int i;
+ int status = 0;
+ RCSNode *rcs, *rcs2;
+
+ vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
+
+ version = vers->vn_user;
+ if (version != NULL && strcmp (version, "0") == 0)
+ {
+ error (0, 0, "cannot admin newly added file `%s'", finfo->file);
+ status = 1;
+ goto exitfunc;
+ }
+
+ rcs = vers->srcfile;
+ if (rcs == NULL)
+ {
+ if (!really_quiet)
+ error (0, 0, "nothing known about %s", finfo->file);
+ status = 1;
+ goto exitfunc;
+ }
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (!really_quiet)
+ {
+ cvs_output ("RCS file: ", 0);
+ cvs_output (rcs->path, 0);
+ cvs_output ("\n", 1);
+ }
+
+ if (admin_data->branch != NULL)
+ {
+ char *branch = &admin_data->branch[2];
+ if (*branch != '\0' && ! isdigit ((unsigned char) *branch))
+ {
+ branch = RCS_whatbranch (rcs, admin_data->branch + 2);
+ if (branch == NULL)
+ {
+ error (0, 0, "%s: Symbolic name %s is undefined.",
+ rcs->path, admin_data->branch + 2);
+ status = 1;
+ }
+ }
+ if (status == 0)
+ RCS_setbranch (rcs, branch);
+ if (branch != NULL && branch != &admin_data->branch[2])
+ free (branch);
+ }
+ if (admin_data->comment != NULL)
+ {
+ if (rcs->comment != NULL)
+ free (rcs->comment);
+ rcs->comment = xstrdup (admin_data->comment + 2);
+ }
+ if (admin_data->set_strict)
+ rcs->strict_locks = 1;
+ if (admin_data->set_nonstrict)
+ rcs->strict_locks = 0;
+ if (admin_data->delete_revs != NULL)
+ {
+ char *s, *t, *rev1, *rev2;
+ /* Set for :, clear for ::. */
+ int inclusive;
+ char *t2;
+
+ s = admin_data->delete_revs + 2;
+ inclusive = 1;
+ t = strchr (s, ':');
+ if (t != NULL)
+ {
+ if (t[1] == ':')
+ {
+ inclusive = 0;
+ t2 = t + 2;
+ }
+ else
+ t2 = t + 1;
+ }
+
+ /* Note that we don't support '-' for ranges. RCS considers it
+ obsolete and it is problematic with tags containing '-'. "cvs log"
+ has made the same decision. */
+
+ if (t == NULL)
+ {
+ /* -orev */
+ rev1 = xstrdup (s);
+ rev2 = xstrdup (s);
+ }
+ else if (t == s)
+ {
+ /* -o:rev2 */
+ rev1 = NULL;
+ rev2 = xstrdup (t2);
+ }
+ else
+ {
+ *t = '\0';
+ rev1 = xstrdup (s);
+ *t = ':'; /* probably unnecessary */
+ if (*t2 == '\0')
+ /* -orev1: */
+ rev2 = NULL;
+ else
+ /* -orev1:rev2 */
+ rev2 = xstrdup (t2);
+ }
+
+ if (rev1 == NULL && rev2 == NULL)
+ {
+ /* RCS segfaults if `-o:' is given */
+ error (0, 0, "no valid revisions specified in `%s' option",
+ admin_data->delete_revs);
+ status = 1;
+ }
+ else
+ {
+ status |= RCS_delete_revs (rcs, rev1, rev2, inclusive);
+ if (rev1)
+ free (rev1);
+ if (rev2)
+ free (rev2);
+ }
+ }
+ if (admin_data->desc != NULL)
+ {
+ free (rcs->desc);
+ rcs->desc = xstrdup (admin_data->desc);
+ }
+ if (admin_data->kflag != NULL)
+ {
+ char *kflag = admin_data->kflag + 2;
+ char *oldexpand = RCS_getexpand (rcs);
+ if (oldexpand == NULL || strcmp (oldexpand, kflag) != 0)
+ RCS_setexpand (rcs, kflag);
+ }
+
+ /* Handle miscellaneous options. TODO: decide whether any or all
+ of these should have their own fields in the admin_data
+ structure. */
+ for (i = 0; i < admin_data->ac; ++i)
+ {
+ char *arg;
+ char *p, *rev, *revnum, *tag, *msg;
+ char **users;
+ int argc, u;
+ Node *n;
+ RCSVers *delta;
+
+ arg = admin_data->av[i];
+ switch (arg[1])
+ {
+ case 'a': /* fall through */
+ case 'e':
+ line2argv (&argc, &users, arg + 2, " ,\t\n");
+ if (arg[1] == 'a')
+ for (u = 0; u < argc; ++u)
+ RCS_addaccess (rcs, users[u]);
+ else if (argc == 0)
+ RCS_delaccess (rcs, NULL);
+ else
+ for (u = 0; u < argc; ++u)
+ RCS_delaccess (rcs, users[u]);
+ free_names (&argc, users);
+ break;
+ case 'A':
+
+ /* See admin-19a-admin and friends in sanity.sh for
+ relative pathnames. It makes sense to think in
+ terms of a syntax which give pathnames relative to
+ the repository or repository corresponding to the
+ current directory or some such (and perhaps don't
+ include ,v), but trying to worry about such things
+ is a little pointless unless you first worry about
+ whether "cvs admin -A" as a whole makes any sense
+ (currently probably not, as access lists don't
+ affect the behavior of CVS). */
+
+ rcs2 = RCS_parsercsfile (arg + 2);
+ if (rcs2 == NULL)
+ error (1, 0, "cannot continue");
+
+ p = xstrdup (RCS_getaccess (rcs2));
+ line2argv (&argc, &users, p, " \t\n");
+ free (p);
+ freercsnode (&rcs2);
+
+ for (u = 0; u < argc; ++u)
+ RCS_addaccess (rcs, users[u]);
+ free_names (&argc, users);
+ break;
+ case 'n': /* fall through */
+ case 'N':
+ if (arg[2] == '\0')
+ {
+ cvs_outerr ("missing symbolic name after ", 0);
+ cvs_outerr (arg, 0);
+ cvs_outerr ("\n", 1);
+ break;
+ }
+ p = strchr (arg, ':');
+ if (p == NULL)
+ {
+ if (RCS_deltag (rcs, arg + 2) != 0)
+ {
+ error (0, 0, "%s: Symbolic name %s is undefined.",
+ rcs->path,
+ arg + 2);
+ status = 1;
+ continue;
+ }
+ break;
+ }
+ *p = '\0';
+ tag = xstrdup (arg + 2);
+ *p++ = ':';
+
+ /* Option `n' signals an error if this tag is already bound. */
+ if (arg[1] == 'n')
+ {
+ n = findnode (RCS_symbols (rcs), tag);
+ if (n != NULL)
+ {
+ error (0, 0,
+ "%s: symbolic name %s already bound to %s",
+ rcs->path,
+ tag, (char *)n->data);
+ status = 1;
+ free (tag);
+ continue;
+ }
+ }
+
+ /* Attempt to perform the requested tagging. */
+
+ if ((*p == 0 && (rev = RCS_head (rcs)))
+ || (rev = RCS_tag2rev (rcs, p))) /* tag2rev may exit */
+ {
+ RCS_check_tag (tag); /* exit if not a valid tag */
+ RCS_settag (rcs, tag, rev);
+ free (rev);
+ }
+ else
+ {
+ if (!really_quiet)
+ error (0, 0,
+ "%s: Symbolic name or revision %s is undefined.",
+ rcs->path, p);
+ status = 1;
+ }
+ free (tag);
+ break;
+ case 's':
+ p = strchr (arg, ':');
+ if (p == NULL)
+ {
+ tag = xstrdup (arg + 2);
+ rev = RCS_head (rcs);
+ if (!rev)
+ {
+ error (0, 0, "No head revision in archive file `%s'.",
+ rcs->path);
+ status = 1;
+ continue;
+ }
+ }
+ else
+ {
+ *p = '\0';
+ tag = xstrdup (arg + 2);
+ *p++ = ':';
+ rev = xstrdup (p);
+ }
+ revnum = RCS_gettag (rcs, rev, 0, NULL);
+ if (revnum != NULL)
+ {
+ n = findnode (rcs->versions, revnum);
+ free (revnum);
+ }
+ else
+ n = NULL;
+ if (n == NULL)
+ {
+ error (0, 0,
+ "%s: can't set state of nonexisting revision %s",
+ rcs->path,
+ rev);
+ free (rev);
+ status = 1;
+ continue;
+ }
+ free (rev);
+ delta = n->data;
+ free (delta->state);
+ delta->state = tag;
+ break;
+
+ case 'm':
+ p = strchr (arg, ':');
+ if (p == NULL)
+ {
+ error (0, 0, "%s: -m option lacks revision number",
+ rcs->path);
+ status = 1;
+ continue;
+ }
+ *p = '\0'; /* temporarily make arg+2 its own string */
+ rev = RCS_gettag (rcs, arg + 2, 1, NULL); /* Force tag match */
+ if (rev == NULL)
+ {
+ error (0, 0, "%s: no such revision %s", rcs->path, arg+2);
+ status = 1;
+ *p = ':'; /* restore the full text of the -m argument */
+ continue;
+ }
+ msg = p+1;
+
+ n = findnode (rcs->versions, rev);
+ /* tags may exist against non-existing versions */
+ if (n == NULL)
+ {
+ error (0, 0, "%s: no such revision %s: %s",
+ rcs->path, arg+2, rev);
+ status = 1;
+ *p = ':'; /* restore the full text of the -m argument */
+ free (rev);
+ continue;
+ }
+ *p = ':'; /* restore the full text of the -m argument */
+ free (rev);
+
+ delta = n->data;
+ if (delta->text == NULL)
+ {
+ delta->text = xmalloc (sizeof (Deltatext));
+ memset (delta->text, 0, sizeof (Deltatext));
+ }
+ delta->text->version = xstrdup (delta->version);
+ delta->text->log = make_message_rcsvalid (msg);
+ break;
+
+ case 'l':
+ status |= RCS_lock (rcs, arg[2] ? arg + 2 : NULL, 0);
+ break;
+ case 'u':
+ status |= RCS_unlock (rcs, arg[2] ? arg + 2 : NULL, 0);
+ break;
+ default: assert(0); /* can't happen */
+ }
+ }
+
+ if (status == 0)
+ {
+ RCS_rewrite (rcs, NULL, NULL);
+ if (!really_quiet)
+ cvs_output ("done\n", 5);
+ }
+ else
+ {
+ /* Note that this message should only occur after another
+ message has given a more specific error. The point of this
+ additional message is to make it clear that the previous problems
+ caused CVS to forget about the idea of modifying the RCS file. */
+ if (!really_quiet)
+ error (0, 0, "RCS file for `%s' not modified.", finfo->file);
+ RCS_abandon (rcs);
+ }
+
+ exitfunc:
+ freevers_ts (&vers);
+ return status;
+}
+
+
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+admin_dirproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+ if (!quiet)
+ error (0, 0, "Administrating %s", update_dir);
+ return R_PROCESS;
+}
diff --git a/src/annotate.c b/src/annotate.c
new file mode 100644
index 0000000..962e9b5
--- /dev/null
+++ b/src/annotate.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Show last revision where each line modified
+ *
+ * Prints the specified files with each line annotated with the revision
+ * number where it was last modified. With no argument, annotates all
+ * all the files in the directory (recursive by default).
+ */
+
+#include "cvs.h"
+
+/* Options from the command line. */
+
+static int force_tag_match = 1;
+static int force_binary = 0;
+static char *tag = NULL;
+static int tag_validated;
+static char *date = NULL;
+
+static int is_rannotate;
+
+static int annotate_fileproc (void *callerdat, struct file_info *);
+static int rannotate_proc (int argc, char **argv, char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local, char *mname, char *msg);
+
+static const char *const annotate_usage[] =
+{
+ "Usage: %s %s [-lRfF] [-r rev] [-D date] [files...]\n",
+ "\t-l\tLocal directory only, no recursion.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-f\tUse head revision if tag/date not found.\n",
+ "\t-F\tAnnotate binary files.\n",
+ "\t-r rev\tAnnotate file as of specified revision/tag.\n",
+ "\t-D date\tAnnotate file as of specified date.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+/* Command to show the revision, date, and author where each line of a
+ file was modified. */
+
+int
+annotate (int argc, char **argv)
+{
+ int local = 0;
+ int err = 0;
+ int c;
+
+ is_rannotate = (strcmp(cvs_cmd_name, "rannotate") == 0);
+
+ if (argc == -1)
+ usage (annotate_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lr:D:fFR")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'r':
+ parse_tagdate (&tag, &date, optarg);
+ break;
+ case 'D':
+ if (date) free (date);
+ date = Make_Date (optarg);
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'F':
+ force_binary = 1;
+ break;
+ case '?':
+ default:
+ usage (annotate_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+
+ if (is_rannotate && !supported_request ("rannotate"))
+ error (1, 0, "server does not support rannotate");
+
+ ign_setup ();
+
+ if (local)
+ send_arg ("-l");
+ if (!force_tag_match)
+ send_arg ("-f");
+ if (force_binary)
+ send_arg ("-F");
+ option_with_arg ("-r", tag);
+ if (date)
+ client_senddate (date);
+ send_arg ("--");
+ if (is_rannotate)
+ {
+ int i;
+ for (i = 0; i < argc; i++)
+ send_arg (argv[i]);
+ send_to_server ("rannotate\012", 0);
+ }
+ else
+ {
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("annotate\012", 0);
+ }
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ if (is_rannotate)
+ {
+ DBM *db;
+ int i;
+ db = open_module ();
+ for (i = 0; i < argc; i++)
+ {
+ err += do_module (db, argv[i], MISC, "Annotating", rannotate_proc,
+ NULL, 0, local, 0, 0, NULL);
+ }
+ close_module (db);
+ }
+ else
+ {
+ err = rannotate_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0,
+ local, NULL, NULL);
+ }
+
+ return err;
+}
+
+
+static int
+rannotate_proc (int argc, char **argv, char *xwhere, char *mwhere,
+ char *mfile, int shorten, int local, char *mname, char *msg)
+{
+ /* Begin section which is identical to patch_proc--should this
+ be abstracted out somehow? */
+ char *myargv[2];
+ int err = 0;
+ int which;
+ char *repository;
+ char *where;
+
+ if (is_rannotate)
+ {
+ repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
+ (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
+ where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ + 1);
+ (void) strcpy (where, argv[0]);
+
+ /* if mfile isn't null, we need to set up to do only part of the module */
+ if (mfile != NULL)
+ {
+ char *cp;
+ char *path;
+
+ /* if the portion of the module is a path, put the dir part on repos */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = '\0';
+ (void) strcat (repository, "/");
+ (void) strcat (repository, mfile);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+ /* take care of the rest */
+ path = Xasprintf ("%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* directory means repository gets the dir tacked on */
+ (void) strcpy (repository, path);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ }
+ else
+ {
+ myargv[0] = argv[0];
+ myargv[1] = mfile;
+ argc = 2;
+ argv = myargv;
+ }
+ free (path);
+ }
+
+ /* cd to the starting repository */
+ if (CVS_CHDIR (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ free (repository);
+ free (where);
+ return 1;
+ }
+ /* End section which is identical to patch_proc. */
+
+ if (force_tag_match && tag != NULL)
+ which = W_REPOS | W_ATTIC;
+ else
+ which = W_REPOS;
+ }
+ else
+ {
+ where = NULL;
+ which = W_LOCAL;
+ repository = "";
+ }
+
+ if (tag != NULL && !tag_validated)
+ {
+ tag_check_valid (tag, argc - 1, argv + 1, local, 0, repository, false);
+ tag_validated = 1;
+ }
+
+ err = start_recursion (annotate_fileproc, NULL, NULL, NULL, NULL,
+ argc - 1, argv + 1, local, which, 0, CVS_LOCK_READ,
+ where, 1, repository);
+ if (which & W_REPOS)
+ free (repository);
+ if (where != NULL)
+ free (where);
+ return err;
+}
+
+
+static int
+annotate_fileproc (void *callerdat, struct file_info *finfo)
+{
+ char *expand, *version;
+
+ if (finfo->rcs == NULL)
+ return 1;
+
+ if (finfo->rcs->flags & PARTIAL)
+ RCS_reparsercsfile (finfo->rcs, NULL, NULL);
+
+ expand = RCS_getexpand (finfo->rcs);
+ version = RCS_getversion (finfo->rcs, tag, date, force_tag_match, NULL);
+
+ if (version == NULL)
+ return 0;
+
+ /* Distinguish output for various files if we are processing
+ several files. */
+ cvs_outerr ("\nAnnotations for ", 0);
+ cvs_outerr (finfo->fullname, 0);
+ cvs_outerr ("\n***************\n", 0);
+
+ if (!force_binary && expand && expand[0] == 'b')
+ {
+ cvs_outerr ("Skipping binary file -- -F not specified.\n", 0);
+ }
+ else
+ {
+ RCS_deltas (finfo->rcs, NULL, NULL,
+ version, RCS_ANNOTATE, NULL, NULL, NULL, NULL);
+ }
+ free (version);
+ return 0;
+}
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..365d91c
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,2187 @@
+/*
+ * Copyright (C) 1996-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Code for the buffer data structure. */
+
+#include "cvs.h"
+#include "buffer.h"
+#include "pagealign_alloc.h"
+
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+
+# include <sys/socket.h>
+
+/* OS/2 doesn't have EIO. FIXME: this whole notion of turning
+ a different error into EIO strikes me as pretty dubious. */
+# if !defined( EIO )
+# define EIO EBADPOS
+# endif
+
+/* Local functions. */
+static void buf_default_memory_error (struct buffer *);
+static struct buffer_data *get_buffer_data (void);
+
+
+
+/* Initialize a buffer structure. */
+struct buffer *
+buf_initialize (type_buf_input input,
+ type_buf_output output,
+ type_buf_flush flush,
+ type_buf_block block,
+ type_buf_get_fd get_fd,
+ type_buf_shutdown shutdown,
+ type_buf_memory_error memory_error,
+ void *closure)
+{
+ struct buffer *buf;
+
+ buf = xmalloc (sizeof (struct buffer));
+ buf->data = NULL;
+ buf->last = NULL;
+ buf->nonblocking = false;
+ buf->input = input;
+ buf->output = output;
+ buf->flush = flush;
+ buf->block = block;
+ buf->get_fd = get_fd;
+ buf->shutdown = shutdown;
+ buf->memory_error = memory_error ? memory_error : buf_default_memory_error;
+ buf->closure = closure;
+ return buf;
+}
+
+
+
+/* Free a buffer structure. */
+void
+buf_free (struct buffer *buf)
+{
+ if (buf->closure != NULL)
+ {
+ free (buf->closure);
+ buf->closure = NULL;
+ }
+ buf_free_data (buf);
+ free (buf);
+}
+
+
+
+/* Initialize a buffer structure which is not to be used for I/O. */
+struct buffer *
+buf_nonio_initialize( void (*memory) (struct buffer *) )
+{
+ return buf_initialize (NULL, NULL, NULL, NULL, NULL, NULL, memory, NULL);
+}
+
+
+
+/* Default memory error handler. */
+static void
+buf_default_memory_error (struct buffer *buf)
+{
+ error (1, 0, "out of memory");
+}
+
+
+
+/* Allocate more buffer_data structures. */
+/* Get a new buffer_data structure. */
+static struct buffer_data *
+get_buffer_data (void)
+{
+ struct buffer_data *ret;
+
+ ret = xmalloc (sizeof (struct buffer_data));
+ ret->text = pagealign_xalloc (BUFFER_DATA_SIZE);
+
+ return ret;
+}
+
+
+
+/* See whether a buffer and its file descriptor is empty. */
+int
+buf_empty (buf)
+ struct buffer *buf;
+{
+ /* Try and read any data on the file descriptor first.
+ * We already know the descriptor is non-blocking.
+ */
+ buf_input_data (buf, NULL);
+ return buf_empty_p (buf);
+}
+
+
+
+/* See whether a buffer is empty. */
+int
+buf_empty_p (struct buffer *buf)
+{
+ struct buffer_data *data;
+
+ for (data = buf->data; data != NULL; data = data->next)
+ if (data->size > 0)
+ return 0;
+ return 1;
+}
+
+
+
+# if defined (SERVER_FLOWCONTROL) || defined (PROXY_SUPPORT)
+/*
+ * Count how much data is stored in the buffer..
+ * Note that each buffer is a xmalloc'ed chunk BUFFER_DATA_SIZE.
+ */
+int
+buf_count_mem (struct buffer *buf)
+{
+ struct buffer_data *data;
+ int mem = 0;
+
+ for (data = buf->data; data != NULL; data = data->next)
+ mem += BUFFER_DATA_SIZE;
+
+ return mem;
+}
+# endif /* SERVER_FLOWCONTROL || PROXY_SUPPORT */
+
+
+
+/* Add data DATA of length LEN to BUF. */
+void
+buf_output (struct buffer *buf, const char *data, size_t len)
+{
+ if (buf->data != NULL
+ && (((buf->last->text + BUFFER_DATA_SIZE)
+ - (buf->last->bufp + buf->last->size))
+ >= len))
+ {
+ memcpy (buf->last->bufp + buf->last->size, data, len);
+ buf->last->size += len;
+ return;
+ }
+
+ while (1)
+ {
+ struct buffer_data *newdata;
+
+ newdata = get_buffer_data ();
+ if (newdata == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return;
+ }
+
+ if (buf->data == NULL)
+ buf->data = newdata;
+ else
+ buf->last->next = newdata;
+ newdata->next = NULL;
+ buf->last = newdata;
+
+ newdata->bufp = newdata->text;
+
+ if (len <= BUFFER_DATA_SIZE)
+ {
+ newdata->size = len;
+ memcpy (newdata->text, data, len);
+ return;
+ }
+
+ newdata->size = BUFFER_DATA_SIZE;
+ memcpy (newdata->text, data, BUFFER_DATA_SIZE);
+
+ data += BUFFER_DATA_SIZE;
+ len -= BUFFER_DATA_SIZE;
+ }
+
+ /*NOTREACHED*/
+}
+
+
+
+/* Add a '\0' terminated string to BUF. */
+void
+buf_output0 (struct buffer *buf, const char *string)
+{
+ buf_output (buf, string, strlen (string));
+}
+
+
+
+/* Add a single character to BUF. */
+void
+buf_append_char (struct buffer *buf, int ch)
+{
+ if (buf->data != NULL
+ && (buf->last->text + BUFFER_DATA_SIZE
+ != buf->last->bufp + buf->last->size))
+ {
+ *(buf->last->bufp + buf->last->size) = ch;
+ ++buf->last->size;
+ }
+ else
+ {
+ char b;
+
+ b = ch;
+ buf_output (buf, &b, 1);
+ }
+}
+
+
+
+/* Free struct buffer_data's from the list starting with FIRST and ending at
+ * LAST, inclusive.
+ */
+static inline void
+buf_free_datas (struct buffer_data *first, struct buffer_data *last)
+{
+ struct buffer_data *b, *n, *p;
+ b = first;
+ do
+ {
+ p = b;
+ n = b->next;
+ pagealign_free (b->text);
+ free (b);
+ b = n;
+ } while (p != last);
+}
+
+
+
+/*
+ * Send all the output we've been saving up. Returns 0 for success or
+ * errno code. If the buffer has been set to be nonblocking, this
+ * will just write until the write would block.
+ */
+int
+buf_send_output (struct buffer *buf)
+{
+ assert (buf->output != NULL);
+
+ while (buf->data != NULL)
+ {
+ struct buffer_data *data;
+
+ data = buf->data;
+
+ if (data->size > 0)
+ {
+ int status;
+ size_t nbytes;
+
+ status = (*buf->output) (buf->closure, data->bufp, data->size,
+ &nbytes);
+ if (status != 0)
+ {
+ /* Some sort of error. Discard the data, and return. */
+ buf_free_data (buf);
+ return status;
+ }
+
+ if (nbytes != data->size)
+ {
+ /* Not all the data was written out. This is only
+ permitted in nonblocking mode. Adjust the buffer,
+ and return. */
+
+ assert (buf->nonblocking);
+
+ data->size -= nbytes;
+ data->bufp += nbytes;
+
+ return 0;
+ }
+ }
+
+ buf->data = data->next;
+ buf_free_datas (data, data);
+ }
+
+ buf->last = NULL;
+
+ return 0;
+}
+
+
+
+/*
+ * Flush any data queued up in the buffer. If BLOCK is nonzero, then
+ * if the buffer is in nonblocking mode, put it into blocking mode for
+ * the duration of the flush. This returns 0 on success, or an error
+ * code.
+ */
+int
+buf_flush (struct buffer *buf, bool block)
+{
+ int nonblocking;
+ int status;
+
+ assert (buf->flush != NULL);
+
+ nonblocking = buf->nonblocking;
+ if (nonblocking && block)
+ {
+ status = set_block (buf);
+ if (status != 0)
+ return status;
+ }
+
+ status = buf_send_output (buf);
+ if (status == 0)
+ status = (*buf->flush) (buf->closure);
+
+ if (nonblocking && block)
+ {
+ int blockstat;
+
+ blockstat = set_nonblock (buf);
+ if (status == 0)
+ status = blockstat;
+ }
+
+ return status;
+}
+
+
+
+/*
+ * Set buffer BUF to nonblocking I/O. Returns 0 for success or errno
+ * code.
+ */
+int
+set_nonblock (struct buffer *buf)
+{
+ int status;
+
+ if (buf->nonblocking)
+ return 0;
+ assert (buf->block != NULL);
+ status = (*buf->block) (buf->closure, 0);
+ if (status != 0)
+ return status;
+ buf->nonblocking = true;
+ return 0;
+}
+
+
+
+/*
+ * Set buffer BUF to blocking I/O. Returns 0 for success or errno
+ * code.
+ */
+int
+set_block (struct buffer *buf)
+{
+ int status;
+
+ if (! buf->nonblocking)
+ return 0;
+ assert (buf->block != NULL);
+ status = (*buf->block) (buf->closure, 1);
+ if (status != 0)
+ return status;
+ buf->nonblocking = false;
+ return 0;
+}
+
+
+
+/*
+ * Send a character count and some output. Returns errno code or 0 for
+ * success.
+ *
+ * Sending the count in binary is OK since this is only used on a pipe
+ * within the same system.
+ */
+int
+buf_send_counted (struct buffer *buf)
+{
+ int size;
+ struct buffer_data *data;
+
+ size = 0;
+ for (data = buf->data; data != NULL; data = data->next)
+ size += data->size;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return ENOMEM;
+ }
+
+ data->next = buf->data;
+ buf->data = data;
+ if (buf->last == NULL)
+ buf->last = data;
+
+ data->bufp = data->text;
+ data->size = sizeof (int);
+
+ *((int *) data->text) = size;
+
+ return buf_send_output (buf);
+}
+
+
+
+/*
+ * Send a special count. COUNT should be negative. It will be
+ * handled specially by buf_copy_counted. This function returns 0 or
+ * an errno code.
+ *
+ * Sending the count in binary is OK since this is only used on a pipe
+ * within the same system.
+ */
+int
+buf_send_special_count (struct buffer *buf, int count)
+{
+ struct buffer_data *data;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return ENOMEM;
+ }
+
+ data->next = buf->data;
+ buf->data = data;
+ if (buf->last == NULL)
+ buf->last = data;
+
+ data->bufp = data->text;
+ data->size = sizeof (int);
+
+ *((int *) data->text) = count;
+
+ return buf_send_output (buf);
+}
+
+
+
+/* Append a list of buffer_data structures to an buffer. */
+void
+buf_append_data (struct buffer *buf, struct buffer_data *data,
+ struct buffer_data *last)
+{
+ if (data != NULL)
+ {
+ if (buf->data == NULL)
+ buf->data = data;
+ else
+ buf->last->next = data;
+ buf->last = last;
+ }
+}
+
+
+
+# ifdef PROXY_SUPPORT
+/* Copy data structures and append them to a buffer.
+ *
+ * ERRORS
+ * Failure to allocate memory here is fatal.
+ */
+void
+buf_copy_data (struct buffer *buf, struct buffer_data *data,
+ struct buffer_data *last)
+{
+ struct buffer_data *first, *new, *cur, *prev;
+
+ assert (buf);
+ assert (data);
+
+ prev = first = NULL;
+ cur = data;
+ while (1)
+ {
+ new = get_buffer_data ();
+ if (!new) error (1, errno, "Failed to allocate buffer data.");
+
+ if (!first) first = new;
+ memcpy (new->text, cur->bufp, cur->size);
+ new->bufp = new->text;
+ new->size = cur->size;
+ new->next = NULL;
+ if (prev) prev->next = new;
+ if (cur == last) break;
+ prev = new;
+ cur = cur->next;
+ }
+
+ buf_append_data (buf, first, new);
+}
+# endif /* PROXY_SUPPORT */
+
+
+
+/* Dispose of any remaining data in the buffer. */
+void
+buf_free_data (struct buffer *buffer)
+{
+ if (buf_empty_p (buffer)) return;
+ buf_free_datas (buffer->data, buffer->last);
+ buffer->data = buffer->last = NULL;
+}
+
+
+
+/* Append the data in one buffer to another. This removes the data
+ * from the source buffer.
+ */
+void
+buf_append_buffer (struct buffer *to, struct buffer *from)
+{
+ struct buffer_data *n;
+
+ /* Copy the data pointer to the new buf. */
+ buf_append_data (to, from->data, from->last);
+
+ n = from->data;
+ while (n)
+ {
+ if (n == from->last) break;
+ n = n->next;
+ }
+
+ /* Remove from the original location. */
+ from->data = NULL;
+ from->last = NULL;
+}
+
+
+
+/*
+ * Copy the contents of file F into buffer_data structures. We can't
+ * copy directly into an buffer, because we want to handle failure and
+ * success differently. Returns 0 on success, or -2 if out of
+ * memory, or a status code on error. Since the caller happens to
+ * know the size of the file, it is passed in as SIZE. On success,
+ * this function sets *RETP and *LASTP, which may be passed to
+ * buf_append_data.
+ */
+int
+buf_read_file (FILE *f, long int size, struct buffer_data **retp,
+ struct buffer_data **lastp)
+{
+ int status;
+
+ *retp = NULL;
+ *lastp = NULL;
+
+ while (size > 0)
+ {
+ struct buffer_data *data;
+ int get;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ status = -2;
+ goto error_return;
+ }
+
+ if (*retp == NULL)
+ *retp = data;
+ else
+ (*lastp)->next = data;
+ data->next = NULL;
+ *lastp = data;
+
+ data->bufp = data->text;
+ data->size = 0;
+
+ if (size > BUFFER_DATA_SIZE)
+ get = BUFFER_DATA_SIZE;
+ else
+ get = size;
+
+ errno = EIO;
+ if (fread (data->text, get, 1, f) != 1)
+ {
+ status = errno;
+ goto error_return;
+ }
+
+ data->size += get;
+ size -= get;
+ }
+
+ return 0;
+
+ error_return:
+ if (*retp != NULL)
+ buf_free_datas (*retp, (*lastp)->next);
+ return status;
+}
+
+
+
+/*
+ * Copy the contents of file F into buffer_data structures. We can't
+ * copy directly into an buffer, because we want to handle failure and
+ * success differently. Returns 0 on success, or -2 if out of
+ * memory, or a status code on error. On success, this function sets
+ * *RETP and *LASTP, which may be passed to buf_append_data.
+ */
+int
+buf_read_file_to_eof (FILE *f, struct buffer_data **retp,
+ struct buffer_data **lastp)
+{
+ int status;
+
+ *retp = NULL;
+ *lastp = NULL;
+
+ while (!feof (f))
+ {
+ struct buffer_data *data;
+ int get, nread;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ status = -2;
+ goto error_return;
+ }
+
+ if (*retp == NULL)
+ *retp = data;
+ else
+ (*lastp)->next = data;
+ data->next = NULL;
+ *lastp = data;
+
+ data->bufp = data->text;
+ data->size = 0;
+
+ get = BUFFER_DATA_SIZE;
+
+ errno = EIO;
+ nread = fread (data->text, 1, get, f);
+ if (nread == 0 && !feof (f))
+ {
+ status = errno;
+ goto error_return;
+ }
+
+ data->size = nread;
+ }
+
+ return 0;
+
+ error_return:
+ if (*retp != NULL)
+ buf_free_datas (*retp, (*lastp)->next);
+ return status;
+}
+
+
+
+/* Return the number of bytes in a chain of buffer_data structures. */
+int
+buf_chain_length (struct buffer_data *buf)
+{
+ int size = 0;
+ while (buf)
+ {
+ size += buf->size;
+ buf = buf->next;
+ }
+ return size;
+}
+
+
+
+/* Return the number of bytes in a buffer. */
+int
+buf_length (struct buffer *buf)
+{
+ return buf_chain_length (buf->data);
+}
+
+
+
+/*
+ * Read an arbitrary amount of data into an input buffer. The buffer
+ * will be in nonblocking mode, and we just grab what we can. Return
+ * 0 on success, or -1 on end of file, or -2 if out of memory, or an
+ * error code. If COUNTP is not NULL, *COUNTP is set to the number of
+ * bytes read.
+ */
+int
+buf_input_data (struct buffer *buf, size_t *countp)
+{
+ assert (buf->input != NULL);
+
+ if (countp != NULL)
+ *countp = 0;
+
+ while (1)
+ {
+ int status;
+ size_t get, nbytes;
+
+ if (buf->data == NULL
+ || (buf->last->bufp + buf->last->size
+ == buf->last->text + BUFFER_DATA_SIZE))
+ {
+ struct buffer_data *data;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return -2;
+ }
+
+ if (buf->data == NULL)
+ buf->data = data;
+ else
+ buf->last->next = data;
+ data->next = NULL;
+ buf->last = data;
+
+ data->bufp = data->text;
+ data->size = 0;
+ }
+
+ get = ((buf->last->text + BUFFER_DATA_SIZE)
+ - (buf->last->bufp + buf->last->size));
+
+ status = (*buf->input) (buf->closure,
+ buf->last->bufp + buf->last->size,
+ 0, get, &nbytes);
+ if (status != 0)
+ return status;
+
+ buf->last->size += nbytes;
+ if (countp != NULL)
+ *countp += nbytes;
+
+ if (nbytes < get)
+ {
+ /* If we did not fill the buffer, then presumably we read
+ all the available data. */
+ return 0;
+ }
+ }
+
+ /*NOTREACHED*/
+}
+
+
+
+/*
+ * Read a line (characters up to a \012) from an input buffer. (We
+ * use \012 rather than \n for the benefit of non Unix clients for
+ * which \n means something else). This returns 0 on success, or -1
+ * on end of file, or -2 if out of memory, or an error code. If it
+ * succeeds, it sets *LINE to an allocated buffer holding the contents
+ * of the line. The trailing \012 is not included in the buffer. If
+ * LENP is not NULL, then *LENP is set to the number of bytes read;
+ * strlen may not work, because there may be embedded null bytes.
+ */
+int
+buf_read_line (struct buffer *buf, char **line, size_t *lenp)
+{
+ return buf_read_short_line (buf, line, lenp, SIZE_MAX);
+}
+
+
+
+/* Like buf_read_line, but return -2 if no newline is found in MAX characters.
+ */
+int
+buf_read_short_line (struct buffer *buf, char **line, size_t *lenp,
+ size_t max)
+{
+ assert (buf->input != NULL);
+
+ *line = NULL;
+
+ while (1)
+ {
+ size_t len, finallen, predicted_len;
+ struct buffer_data *data;
+ char *nl;
+
+ /* See if there is a newline in BUF. */
+ len = 0;
+ for (data = buf->data; data != NULL; data = data->next)
+ {
+ nl = memchr (data->bufp, '\012', data->size);
+ if (nl != NULL)
+ {
+ finallen = nl - data->bufp;
+ if (xsum (len, finallen) >= max) return -2;
+ len += finallen;
+ break;
+ }
+ else if (xsum (len, data->size) >= max) return -2;
+ len += data->size;
+ }
+
+ /* If we found a newline, copy the line into a memory buffer,
+ and remove it from BUF. */
+ if (data != NULL)
+ {
+ char *p;
+ struct buffer_data *nldata;
+
+ p = xmalloc (len + 1);
+ if (p == NULL)
+ return -2;
+ *line = p;
+
+ nldata = data;
+ data = buf->data;
+ while (data != nldata)
+ {
+ struct buffer_data *next;
+
+ memcpy (p, data->bufp, data->size);
+ p += data->size;
+ next = data->next;
+ buf_free_datas (data, data);
+ data = next;
+ }
+
+ memcpy (p, data->bufp, finallen);
+ p[finallen] = '\0';
+
+ data->size -= finallen + 1;
+ data->bufp = nl + 1;
+ buf->data = data;
+
+ if (lenp != NULL)
+ *lenp = len;
+
+ return 0;
+ }
+
+ /* Read more data until we get a newline or MAX characters. */
+ predicted_len = 0;
+ while (1)
+ {
+ int status;
+ size_t size, nbytes;
+ char *mem;
+
+ if (buf->data == NULL
+ || (buf->last->bufp + buf->last->size
+ == buf->last->text + BUFFER_DATA_SIZE))
+ {
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return -2;
+ }
+
+ if (buf->data == NULL)
+ buf->data = data;
+ else
+ buf->last->next = data;
+ data->next = NULL;
+ buf->last = data;
+
+ data->bufp = data->text;
+ data->size = 0;
+ }
+
+ mem = buf->last->bufp + buf->last->size;
+ size = (buf->last->text + BUFFER_DATA_SIZE) - mem;
+
+ /* We need to read at least 1 byte. We can handle up to
+ SIZE bytes. This will only be efficient if the
+ underlying communication stream does its own buffering,
+ or is clever about getting more than 1 byte at a time. */
+ status = (*buf->input) (buf->closure, mem, 1, size, &nbytes);
+ if (status != 0)
+ return status;
+
+ predicted_len += nbytes;
+ buf->last->size += nbytes;
+
+ /* Optimize slightly to avoid an unnecessary call to memchr. */
+ if (nbytes == 1)
+ {
+ if (*mem == '\012')
+ break;
+ }
+ else
+ {
+ if (memchr (mem, '\012', nbytes) != NULL)
+ break;
+ }
+ if (xsum (len, predicted_len) >= max) return -2;
+ }
+ }
+}
+
+
+
+/*
+ * Extract data from the input buffer BUF. This will read up to WANT
+ * bytes from the buffer. It will set *RETDATA to point at the bytes,
+ * and set *GOT to the number of bytes to be found there. Any buffer
+ * call which uses BUF may change the contents of the buffer at *DATA,
+ * so the data should be fully processed before any further calls are
+ * made. This returns 0 on success, or -1 on end of file, or -2 if
+ * out of memory, or an error code.
+ */
+int
+buf_read_data (struct buffer *buf, size_t want, char **retdata, size_t *got)
+{
+ assert (buf->input != NULL);
+
+ while (buf->data != NULL && buf->data->size == 0)
+ {
+ struct buffer_data *next;
+
+ next = buf->data->next;
+ buf_free_datas (buf->data, buf->data);
+ buf->data = next;
+ if (next == NULL)
+ buf->last = NULL;
+ }
+
+ if (buf->data == NULL)
+ {
+ struct buffer_data *data;
+ int status;
+ size_t get, nbytes;
+
+ data = get_buffer_data ();
+ if (data == NULL)
+ {
+ (*buf->memory_error) (buf);
+ return -2;
+ }
+
+ buf->data = data;
+ buf->last = data;
+ data->next = NULL;
+ data->bufp = data->text;
+ data->size = 0;
+
+ if (want < BUFFER_DATA_SIZE)
+ get = want;
+ else
+ get = BUFFER_DATA_SIZE;
+ status = (*buf->input) (buf->closure, data->bufp, get,
+ BUFFER_DATA_SIZE, &nbytes);
+ if (status != 0)
+ return status;
+
+ data->size = nbytes;
+ }
+
+ *retdata = buf->data->bufp;
+ if (want < buf->data->size)
+ {
+ *got = want;
+ buf->data->size -= want;
+ buf->data->bufp += want;
+ }
+ else
+ {
+ *got = buf->data->size;
+ buf->data->size = 0;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Copy lines from an input buffer to an output buffer.
+ * This copies all complete lines (characters up to a
+ * newline) from INBUF to OUTBUF. Each line in OUTBUF is preceded by the
+ * character COMMAND and a space.
+ */
+void
+buf_copy_lines (struct buffer *outbuf, struct buffer *inbuf, int command)
+{
+ while (1)
+ {
+ struct buffer_data *data;
+ struct buffer_data *nldata;
+ char *nl;
+ int len;
+
+ /* See if there is a newline in INBUF. */
+ nldata = NULL;
+ nl = NULL;
+ for (data = inbuf->data; data != NULL; data = data->next)
+ {
+ nl = memchr (data->bufp, '\n', data->size);
+ if (nl != NULL)
+ {
+ nldata = data;
+ break;
+ }
+ }
+
+ if (nldata == NULL)
+ {
+ /* There are no more lines in INBUF. */
+ return;
+ }
+
+ /* Put in the command. */
+ buf_append_char (outbuf, command);
+ buf_append_char (outbuf, ' ');
+
+ if (inbuf->data != nldata)
+ {
+ /*
+ * Simply move over all the buffers up to the one containing
+ * the newline.
+ */
+ for (data = inbuf->data; data->next != nldata; data = data->next);
+ data->next = NULL;
+ buf_append_data (outbuf, inbuf->data, data);
+ inbuf->data = nldata;
+ }
+
+ /*
+ * If the newline is at the very end of the buffer, just move
+ * the buffer onto OUTBUF. Otherwise we must copy the data.
+ */
+ len = nl + 1 - nldata->bufp;
+ if (len == nldata->size)
+ {
+ inbuf->data = nldata->next;
+ if (inbuf->data == NULL)
+ inbuf->last = NULL;
+
+ nldata->next = NULL;
+ buf_append_data (outbuf, nldata, nldata);
+ }
+ else
+ {
+ buf_output (outbuf, nldata->bufp, len);
+ nldata->bufp += len;
+ nldata->size -= len;
+ }
+ }
+}
+
+
+
+/*
+ * Copy counted data from one buffer to another. The count is an
+ * integer, host size, host byte order (it is only used across a
+ * pipe). If there is enough data, it should be moved over. If there
+ * is not enough data, it should remain on the original buffer. A
+ * negative count is a special case. if one is seen, *SPECIAL is set
+ * to the (negative) count value and no additional data is gathered
+ * from the buffer; normally *SPECIAL is set to 0. This function
+ * returns the number of bytes it needs to see in order to actually
+ * copy something over.
+ */
+int
+buf_copy_counted (struct buffer *outbuf, struct buffer *inbuf, int *special)
+{
+ *special = 0;
+
+ while (1)
+ {
+ struct buffer_data *data;
+ int need;
+ union
+ {
+ char intbuf[sizeof (int)];
+ int i;
+ } u;
+ char *intp;
+ int count;
+ struct buffer_data *start;
+ int startoff;
+ struct buffer_data *stop;
+ int stopwant;
+
+ /* See if we have enough bytes to figure out the count. */
+ need = sizeof (int);
+ intp = u.intbuf;
+ for (data = inbuf->data; data != NULL; data = data->next)
+ {
+ if (data->size >= need)
+ {
+ memcpy (intp, data->bufp, need);
+ break;
+ }
+ memcpy (intp, data->bufp, data->size);
+ intp += data->size;
+ need -= data->size;
+ }
+ if (data == NULL)
+ {
+ /* We don't have enough bytes to form an integer. */
+ return need;
+ }
+
+ count = u.i;
+ start = data;
+ startoff = need;
+
+ if (count < 0)
+ {
+ /* A negative COUNT is a special case meaning that we
+ don't need any further information. */
+ stop = start;
+ stopwant = 0;
+ }
+ else
+ {
+ /*
+ * We have an integer in COUNT. We have gotten all the
+ * data from INBUF in all buffers before START, and we
+ * have gotten STARTOFF bytes from START. See if we have
+ * enough bytes remaining in INBUF.
+ */
+ need = count - (start->size - startoff);
+ if (need <= 0)
+ {
+ stop = start;
+ stopwant = count;
+ }
+ else
+ {
+ for (data = start->next; data != NULL; data = data->next)
+ {
+ if (need <= data->size)
+ break;
+ need -= data->size;
+ }
+ if (data == NULL)
+ {
+ /* We don't have enough bytes. */
+ return need;
+ }
+ stop = data;
+ stopwant = need;
+ }
+ }
+
+ /*
+ * We have enough bytes. Free any buffers in INBUF before
+ * START, and remove STARTOFF bytes from START, so that we can
+ * forget about STARTOFF.
+ */
+ start->bufp += startoff;
+ start->size -= startoff;
+
+ if (start->size == 0)
+ start = start->next;
+
+ if (stop->size == stopwant)
+ {
+ stop = stop->next;
+ stopwant = 0;
+ }
+
+ while (inbuf->data != start)
+ {
+ data = inbuf->data;
+ inbuf->data = data->next;
+ buf_free_datas (data, data);
+ }
+
+ /* If COUNT is negative, set *SPECIAL and get out now. */
+ if (count < 0)
+ {
+ *special = count;
+ return 0;
+ }
+
+ /*
+ * We want to copy over the bytes from START through STOP. We
+ * only want STOPWANT bytes from STOP.
+ */
+
+ if (start != stop)
+ {
+ /* Attach the buffers from START through STOP to OUTBUF. */
+ for (data = start; data->next != stop; data = data->next);
+ inbuf->data = stop;
+ data->next = NULL;
+ buf_append_data (outbuf, start, data);
+ }
+
+ if (stopwant > 0)
+ {
+ buf_output (outbuf, stop->bufp, stopwant);
+ stop->bufp += stopwant;
+ stop->size -= stopwant;
+ }
+ }
+
+ /*NOTREACHED*/
+}
+
+
+
+int
+buf_get_fd (struct buffer *buf)
+{
+ if (buf->get_fd)
+ return (*buf->get_fd) (buf->closure);
+ return -1;
+}
+
+
+
+/* Shut down a buffer. This returns 0 on success, or an errno code. */
+int
+buf_shutdown (struct buffer *buf)
+{
+ if (buf->shutdown) return (*buf->shutdown) (buf);
+ return 0;
+}
+
+
+
+/* Certain types of communication input and output data in packets,
+ where each packet is translated in some fashion. The packetizing
+ buffer type supports that, given a buffer which handles lower level
+ I/O and a routine to translate the data in a packet.
+
+ This code uses two bytes for the size of a packet, so packets are
+ restricted to 65536 bytes in total.
+
+ The translation functions should just translate; they may not
+ significantly increase or decrease the amount of data. The actual
+ size of the initial data is part of the translated data. The
+ output translation routine may add up to PACKET_SLOP additional
+ bytes, and the input translation routine should shrink the data
+ correspondingly. */
+
+# define PACKET_SLOP (100)
+
+/* This structure is the closure field of a packetizing buffer. */
+
+struct packetizing_buffer
+{
+ /* The underlying buffer. */
+ struct buffer *buf;
+ /* The input translation function. Exactly one of inpfn and outfn
+ will be NULL. The input translation function should
+ untranslate the data in INPUT, storing the result in OUTPUT.
+ SIZE is the amount of data in INPUT, and is also the size of
+ OUTPUT. This should return 0 on success, or an errno code. */
+ int (*inpfn) (void *fnclosure, const char *input, char *output,
+ size_t size);
+ /* The output translation function. This should translate the
+ data in INPUT, storing the result in OUTPUT. The first two
+ bytes in INPUT will be the size of the data, and so will SIZE.
+ This should set *TRANSLATED to the amount of translated data in
+ OUTPUT. OUTPUT is large enough to hold SIZE + PACKET_SLOP
+ bytes. This should return 0 on success, or an errno code. */
+ int (*outfn) (void *fnclosure, const char *input, char *output,
+ size_t size, size_t *translated);
+ /* A closure for the translation function. */
+ void *fnclosure;
+ /* For an input buffer, we may have to buffer up data here. */
+ /* This is non-zero if the buffered data has been translated.
+ Otherwise, the buffered data has not been translated, and starts
+ with the two byte packet size. */
+ bool translated;
+ /* The amount of buffered data. */
+ size_t holdsize;
+ /* The buffer allocated to hold the data. */
+ char *holdbuf;
+ /* The size of holdbuf. */
+ size_t holdbufsize;
+ /* If translated is set, we need another data pointer to track
+ where we are in holdbuf. If translated is clear, then this
+ pointer is not used. */
+ char *holddata;
+};
+
+
+
+static int packetizing_buffer_input (void *, char *, size_t, size_t, size_t *);
+static int packetizing_buffer_output (void *, const char *, size_t, size_t *);
+static int packetizing_buffer_flush (void *);
+static int packetizing_buffer_block (void *, bool);
+static int packetizing_buffer_get_fd (void *);
+static int packetizing_buffer_shutdown (struct buffer *);
+
+
+
+/* Create a packetizing buffer. */
+struct buffer *
+packetizing_buffer_initialize (struct buffer *buf,
+ int (*inpfn) (void *, const char *, char *,
+ size_t),
+ int (*outfn) (void *, const char *, char *,
+ size_t, size_t *),
+ void *fnclosure,
+ void (*memory) (struct buffer *))
+{
+ struct packetizing_buffer *pb;
+
+ pb = xmalloc (sizeof *pb);
+ memset (pb, 0, sizeof *pb);
+
+ pb->buf = buf;
+ pb->inpfn = inpfn;
+ pb->outfn = outfn;
+ pb->fnclosure = fnclosure;
+
+ if (inpfn != NULL)
+ {
+ /* Add PACKET_SLOP to handle larger translated packets, and
+ add 2 for the count. This buffer is increased if
+ necessary. */
+ pb->holdbufsize = BUFFER_DATA_SIZE + PACKET_SLOP + 2;
+ pb->holdbuf = xmalloc (pb->holdbufsize);
+ }
+
+ return buf_initialize (inpfn != NULL ? packetizing_buffer_input : NULL,
+ inpfn != NULL ? NULL : packetizing_buffer_output,
+ inpfn != NULL ? NULL : packetizing_buffer_flush,
+ packetizing_buffer_block,
+ packetizing_buffer_get_fd,
+ packetizing_buffer_shutdown,
+ memory,
+ pb);
+}
+
+
+
+/* Input data from a packetizing buffer. */
+static int
+packetizing_buffer_input (void *closure, char *data, size_t need, size_t size,
+ size_t *got)
+{
+ struct packetizing_buffer *pb = closure;
+
+ *got = 0;
+
+ if (pb->holdsize > 0 && pb->translated)
+ {
+ size_t copy;
+
+ copy = pb->holdsize;
+
+ if (copy > size)
+ {
+ memcpy (data, pb->holddata, size);
+ pb->holdsize -= size;
+ pb->holddata += size;
+ *got = size;
+ return 0;
+ }
+
+ memcpy (data, pb->holddata, copy);
+ pb->holdsize = 0;
+ pb->translated = false;
+
+ data += copy;
+ need -= copy;
+ size -= copy;
+ *got = copy;
+ }
+
+ while (need > 0 || *got == 0)
+ {
+ int status;
+ size_t get, nread, count, tcount;
+ char *bytes;
+ static char *stackoutbuf = NULL;
+ char *inbuf, *outbuf;
+
+ if (!stackoutbuf)
+ stackoutbuf = xmalloc (BUFFER_DATA_SIZE + PACKET_SLOP);
+
+ /* If we don't already have the two byte count, get it. */
+ if (pb->holdsize < 2)
+ {
+ get = 2 - pb->holdsize;
+ status = buf_read_data (pb->buf, get, &bytes, &nread);
+ if (status != 0)
+ {
+ /* buf_read_data can return -2, but a buffer input
+ function is only supposed to return -1, 0, or an
+ error code. */
+ if (status == -2)
+ status = ENOMEM;
+ return status;
+ }
+
+ if (nread == 0)
+ {
+ /* The buffer is in nonblocking mode, and we didn't
+ manage to read anything. */
+ return 0;
+ }
+
+ if (get == 1)
+ pb->holdbuf[1] = bytes[0];
+ else
+ {
+ pb->holdbuf[0] = bytes[0];
+ if (nread < 2)
+ {
+ /* We only got one byte, but we needed two. Stash
+ the byte we got, and try again. */
+ pb->holdsize = 1;
+ continue;
+ }
+ pb->holdbuf[1] = bytes[1];
+ }
+ pb->holdsize = 2;
+ }
+
+ /* Read the packet. */
+
+ count = (((pb->holdbuf[0] & 0xff) << 8)
+ + (pb->holdbuf[1] & 0xff));
+
+ if (count + 2 > pb->holdbufsize)
+ {
+ char *n;
+
+ /* We didn't allocate enough space in the initialize
+ function. */
+
+ n = xrealloc (pb->holdbuf, count + 2);
+ if (n == NULL)
+ {
+ (*pb->buf->memory_error) (pb->buf);
+ return ENOMEM;
+ }
+ pb->holdbuf = n;
+ pb->holdbufsize = count + 2;
+ }
+
+ get = count - (pb->holdsize - 2);
+
+ status = buf_read_data (pb->buf, get, &bytes, &nread);
+ if (status != 0)
+ {
+ /* buf_read_data can return -2, but a buffer input
+ function is only supposed to return -1, 0, or an error
+ code. */
+ if (status == -2)
+ status = ENOMEM;
+ return status;
+ }
+
+ if (nread == 0)
+ {
+ /* We did not get any data. Presumably the buffer is in
+ nonblocking mode. */
+ return 0;
+ }
+
+ if (nread < get)
+ {
+ /* We did not get all the data we need to fill the packet.
+ buf_read_data does not promise to return all the bytes
+ requested, so we must try again. */
+ memcpy (pb->holdbuf + pb->holdsize, bytes, nread);
+ pb->holdsize += nread;
+ continue;
+ }
+
+ /* We have a complete untranslated packet of COUNT bytes. */
+
+ if (pb->holdsize == 2)
+ {
+ /* We just read the entire packet (the 2 bytes in
+ PB->HOLDBUF are the size). Save a memcpy by
+ translating directly from BYTES. */
+ inbuf = bytes;
+ }
+ else
+ {
+ /* We already had a partial packet in PB->HOLDBUF. We
+ need to copy the new data over to make the input
+ contiguous. */
+ memcpy (pb->holdbuf + pb->holdsize, bytes, nread);
+ inbuf = pb->holdbuf + 2;
+ }
+
+ if (count <= BUFFER_DATA_SIZE + PACKET_SLOP)
+ outbuf = stackoutbuf;
+ else
+ {
+ outbuf = xmalloc (count);
+ if (outbuf == NULL)
+ {
+ (*pb->buf->memory_error) (pb->buf);
+ return ENOMEM;
+ }
+ }
+
+ status = (*pb->inpfn) (pb->fnclosure, inbuf, outbuf, count);
+ if (status != 0)
+ return status;
+
+ /* The first two bytes in the translated buffer are the real
+ length of the translated data. */
+ tcount = ((outbuf[0] & 0xff) << 8) + (outbuf[1] & 0xff);
+
+ if (tcount > count)
+ error (1, 0, "Input translation failure");
+
+ if (tcount > size)
+ {
+ /* We have more data than the caller has provided space
+ for. We need to save some of it for the next call. */
+
+ memcpy (data, outbuf + 2, size);
+ *got += size;
+
+ pb->holdsize = tcount - size;
+ memcpy (pb->holdbuf, outbuf + 2 + size, tcount - size);
+ pb->holddata = pb->holdbuf;
+ pb->translated = true;
+
+ if (outbuf != stackoutbuf)
+ free (outbuf);
+
+ return 0;
+ }
+
+ memcpy (data, outbuf + 2, tcount);
+
+ if (outbuf != stackoutbuf)
+ free (outbuf);
+
+ pb->holdsize = 0;
+
+ data += tcount;
+ need -= tcount;
+ size -= tcount;
+ *got += tcount;
+ }
+
+ return 0;
+}
+
+
+
+/* Output data to a packetizing buffer. */
+static int
+packetizing_buffer_output (void *closure, const char *data, size_t have,
+ size_t *wrote)
+{
+ struct packetizing_buffer *pb = closure;
+ static char *inbuf = NULL; /* These two buffers are static so that they
+ * depend on the size of BUFFER_DATA_SIZE yet
+ * still only be allocated once per run.
+ */
+ static char *stack_outbuf = NULL;
+ struct buffer_data *outdata = NULL; /* Initialize to silence -Wall. Dumb.
+ */
+ char *outbuf;
+ size_t size, translated;
+ int status;
+
+ /* It would be easy to xmalloc a buffer, but I don't think this
+ case can ever arise. */
+ assert (have <= BUFFER_DATA_SIZE);
+
+ if (!inbuf)
+ {
+ inbuf = xmalloc (BUFFER_DATA_SIZE + 2);
+ stack_outbuf = xmalloc (BUFFER_DATA_SIZE + PACKET_SLOP + 4);
+ }
+
+ inbuf[0] = (have >> 8) & 0xff;
+ inbuf[1] = have & 0xff;
+ memcpy (inbuf + 2, data, have);
+
+ size = have + 2;
+
+ /* The output function is permitted to add up to PACKET_SLOP
+ bytes, and we need 2 bytes for the size of the translated data.
+ If we can guarantee that the result will fit in a buffer_data,
+ we translate directly into one to avoid a memcpy in buf_output. */
+ if (size + PACKET_SLOP + 2 > BUFFER_DATA_SIZE)
+ outbuf = stack_outbuf;
+ else
+ {
+ outdata = get_buffer_data ();
+ if (outdata == NULL)
+ {
+ (*pb->buf->memory_error) (pb->buf);
+ return ENOMEM;
+ }
+
+ outdata->next = NULL;
+ outdata->bufp = outdata->text;
+
+ outbuf = outdata->text;
+ }
+
+ status = (*pb->outfn) (pb->fnclosure, inbuf, outbuf + 2, size,
+ &translated);
+ if (status != 0)
+ return status;
+
+ /* The output function is permitted to add up to PACKET_SLOP
+ bytes. */
+ assert (translated <= size + PACKET_SLOP);
+
+ outbuf[0] = (translated >> 8) & 0xff;
+ outbuf[1] = translated & 0xff;
+
+ if (outbuf == stack_outbuf)
+ buf_output (pb->buf, outbuf, translated + 2);
+ else
+ {
+ outdata->size = translated + 2;
+ buf_append_data (pb->buf, outdata, outdata);
+ }
+
+ *wrote = have;
+
+ /* We will only be here because buf_send_output was called on the
+ packetizing buffer. That means that we should now call
+ buf_send_output on the underlying buffer. */
+ return buf_send_output (pb->buf);
+}
+
+
+
+/* Flush data to a packetizing buffer. */
+static int
+packetizing_buffer_flush (void *closure)
+{
+ struct packetizing_buffer *pb = closure;
+
+ /* Flush the underlying buffer. Note that if the original call to
+ buf_flush passed 1 for the BLOCK argument, then the buffer will
+ already have been set into blocking mode, so we should always
+ pass 0 here. */
+ return buf_flush (pb->buf, 0);
+}
+
+
+
+/* The block routine for a packetizing buffer. */
+static int
+packetizing_buffer_block (void *closure, bool block)
+{
+ struct packetizing_buffer *pb = closure;
+
+ if (block)
+ return set_block (pb->buf);
+ else
+ return set_nonblock (pb->buf);
+}
+
+
+
+/* Return the file descriptor underlying any child buffers. */
+static int
+packetizing_buffer_get_fd (void *closure)
+{
+ struct packetizing_buffer *cb = closure;
+ return buf_get_fd (cb->buf);
+}
+
+
+
+/* Shut down a packetizing buffer. */
+static int
+packetizing_buffer_shutdown (struct buffer *buf)
+{
+ struct packetizing_buffer *pb = buf->closure;
+
+ return buf_shutdown (pb->buf);
+}
+
+
+
+/* All server communication goes through buffer structures. Most of
+ the buffers are built on top of a file descriptor. This structure
+ is used as the closure field in a buffer. */
+
+struct fd_buffer
+{
+ /* The file descriptor. */
+ int fd;
+ /* Nonzero if the file descriptor is in blocking mode. */
+ int blocking;
+ /* The child process id when fd is a pipe. */
+ pid_t child_pid;
+ /* The connection info, when fd is a pipe to a server. */
+ cvsroot_t *root;
+};
+
+static int fd_buffer_input (void *, char *, size_t, size_t, size_t *);
+static int fd_buffer_output (void *, const char *, size_t, size_t *);
+static int fd_buffer_flush (void *);
+static int fd_buffer_block (void *, bool);
+static int fd_buffer_get_fd (void *);
+static int fd_buffer_shutdown (struct buffer *);
+
+/* Initialize a buffer built on a file descriptor. FD is the file
+ descriptor. INPUT is nonzero if this is for input, zero if this is
+ for output. MEMORY is the function to call when a memory error
+ occurs. */
+
+struct buffer *
+fd_buffer_initialize (int fd, pid_t child_pid, cvsroot_t *root, bool input,
+ void (*memory) (struct buffer *))
+{
+ struct fd_buffer *n;
+
+ n = xmalloc (sizeof *n);
+ n->fd = fd;
+ n->child_pid = child_pid;
+ n->root = root;
+ fd_buffer_block (n, true);
+ return buf_initialize (input ? fd_buffer_input : NULL,
+ input ? NULL : fd_buffer_output,
+ input ? NULL : fd_buffer_flush,
+ fd_buffer_block, fd_buffer_get_fd,
+ fd_buffer_shutdown,
+ memory,
+ n);
+}
+
+
+
+/* The buffer input function for a buffer built on a file descriptor.
+ *
+ * In non-blocking mode, this function will read as many bytes as it can in a
+ * single try, up to SIZE bytes, and return.
+ *
+ * In blocking mode with NEED > 0, this function will read as many bytes as it
+ * can but will not return until it has read at least NEED bytes.
+ *
+ * In blocking mode with NEED == 0, this function will block until it can read
+ * either at least one byte or EOF, then read as many bytes as are available
+ * and return. At the very least, compress_buffer_shutdown depends on this
+ * behavior to read EOF and can loop indefinitely without it.
+ *
+ * ASSUMPTIONS
+ * NEED <= SIZE.
+ *
+ * INPUTS
+ * closure Our FD_BUFFER struct.
+ * data The start of our input buffer.
+ * need How many bytes our caller needs.
+ * size How many bytes are available in DATA.
+ * got Where to store the number of bytes read.
+ *
+ * OUTPUTS
+ * data Filled with bytes read.
+ * *got Number of bytes actually read into DATA.
+ *
+ * RETURNS
+ * errno On error.
+ * -1 On EOF.
+ * 0 Otherwise.
+ *
+ * ERRORS
+ * This function can return an error if fd_buffer_block(), or the system
+ * read() or select() calls do.
+ */
+static int
+fd_buffer_input (void *closure, char *data, size_t need, size_t size,
+ size_t *got)
+{
+ struct fd_buffer *fb = closure;
+ int nbytes;
+
+ assert (need <= size);
+
+ *got = 0;
+
+ if (fb->blocking)
+ {
+ int status;
+ fd_set readfds;
+
+ /* Set non-block. */
+ status = fd_buffer_block (fb, false);
+ if (status != 0) return status;
+
+ FD_ZERO (&readfds);
+ FD_SET (fb->fd, &readfds);
+ do
+ {
+ int numfds;
+
+ do {
+ /* This used to select on exceptions too, but as far
+ as I know there was never any reason to do that and
+ SCO doesn't let you select on exceptions on pipes. */
+ numfds = fd_select (fb->fd + 1, &readfds, NULL, NULL, NULL);
+ if (numfds < 0 && errno != EINTR)
+ {
+ status = errno;
+ goto block_done;
+ }
+ } while (numfds < 0);
+
+ nbytes = read (fb->fd, data + *got, size - *got);
+
+ if (nbytes == 0)
+ {
+ /* End of file. This assumes that we are using POSIX or BSD
+ style nonblocking I/O. On System V we will get a zero
+ return if there is no data, even when not at EOF. */
+ if (*got)
+ {
+ /* We already read some data, so return no error, counting
+ * on the fact that we will read EOF again next time.
+ */
+ status = 0;
+ break;
+ }
+ else
+ {
+ /* Return EOF. */
+ status = -1;
+ break;
+ }
+ }
+
+ if (nbytes < 0)
+ {
+ /* Some error occurred. */
+ if (!blocking_error (errno))
+ {
+ status = errno;
+ break;
+ }
+ /* else Everything's fine, we just didn't get any data. */
+ }
+
+ *got += nbytes;
+ } while (*got < need);
+
+block_done:
+ if (status == 0 || status == -1)
+ {
+ int newstatus;
+
+ /* OK or EOF - Reset block. */
+ newstatus = fd_buffer_block (fb, true);
+ if (newstatus) status = newstatus;
+ }
+ return status;
+ }
+
+ /* The above will always return. Handle non-blocking read. */
+ nbytes = read (fb->fd, data, size);
+
+ if (nbytes > 0)
+ {
+ *got = nbytes;
+ return 0;
+ }
+
+ if (nbytes == 0)
+ /* End of file. This assumes that we are using POSIX or BSD
+ style nonblocking I/O. On System V we will get a zero
+ return if there is no data, even when not at EOF. */
+ return -1;
+
+ /* Some error occurred. */
+ if (blocking_error (errno))
+ /* Everything's fine, we just didn't get any data. */
+ return 0;
+
+ return errno;
+}
+
+
+
+/* The buffer output function for a buffer built on a file descriptor. */
+
+static int
+fd_buffer_output (void *closure, const char *data, size_t have, size_t *wrote)
+{
+ struct fd_buffer *fd = closure;
+
+ *wrote = 0;
+
+ while (have > 0)
+ {
+ int nbytes;
+
+ nbytes = write (fd->fd, data, have);
+
+ if (nbytes <= 0)
+ {
+ if (! fd->blocking
+ && (nbytes == 0 || blocking_error (errno)))
+ {
+ /* A nonblocking write failed to write any data. Just
+ return. */
+ return 0;
+ }
+
+ /* Some sort of error occurred. */
+
+ if (nbytes == 0)
+ return EIO;
+
+ return errno;
+ }
+
+ *wrote += nbytes;
+ data += nbytes;
+ have -= nbytes;
+ }
+
+ return 0;
+}
+
+
+
+/* The buffer flush function for a buffer built on a file descriptor. */
+static int
+fd_buffer_flush (void *closure)
+{
+ /* We don't need to do anything here. Our fd doesn't have its own buffer
+ * and syncing won't do anything but slow us down.
+ *
+ * struct fd_buffer *fb = closure;
+ *
+ * if (fsync (fb->fd) < 0 && errno != EROFS && errno != EINVAL)
+ * return errno;
+ */
+ return 0;
+}
+
+
+
+static struct stat devnull;
+static int devnull_set = -1;
+
+/* The buffer block function for a buffer built on a file descriptor. */
+static int
+fd_buffer_block (void *closure, bool block)
+{
+ struct fd_buffer *fb = closure;
+# if defined (F_GETFL) && defined (O_NONBLOCK) && defined (F_SETFL)
+ int flags;
+
+ flags = fcntl (fb->fd, F_GETFL, 0);
+ if (flags < 0)
+ return errno;
+
+ if (block)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
+
+ if (fcntl (fb->fd, F_SETFL, flags) < 0)
+ {
+ /*
+ * BSD returns ENODEV when we try to set block/nonblock on /dev/null.
+ * BSDI returns ENOTTY when we try to set block/nonblock on /dev/null.
+ */
+ struct stat sb;
+ int save_errno = errno;
+ bool isdevnull = false;
+
+ if (devnull_set == -1)
+ devnull_set = stat ("/dev/null", &devnull);
+
+ if (devnull_set >= 0)
+ /* Equivalent to /dev/null ? */
+ isdevnull = (fstat (fb->fd, &sb) >= 0
+ && sb.st_dev == devnull.st_dev
+ && sb.st_ino == devnull.st_ino
+ && sb.st_mode == devnull.st_mode
+ && sb.st_uid == devnull.st_uid
+ && sb.st_gid == devnull.st_gid
+ && sb.st_size == devnull.st_size
+ && sb.st_blocks == devnull.st_blocks
+ && sb.st_blksize == devnull.st_blksize);
+ if (isdevnull)
+ errno = 0;
+ else
+ {
+ errno = save_errno;
+ return errno;
+ }
+ }
+# endif /* F_GETFL && O_NONBLOCK && F_SETFL */
+
+ fb->blocking = block;
+
+ return 0;
+}
+
+
+
+static int
+fd_buffer_get_fd (void *closure)
+{
+ struct fd_buffer *fb = closure;
+ return fb->fd;
+}
+
+
+
+/* The buffer shutdown function for a buffer built on a file descriptor.
+ *
+ * This function disposes of memory allocated for this buffer.
+ */
+static int
+fd_buffer_shutdown (struct buffer *buf)
+{
+ struct fd_buffer *fb = buf->closure;
+ struct stat s;
+ bool closefd, statted;
+
+ /* Must be an open pipe, socket, or file. What could go wrong? */
+ if (fstat (fb->fd, &s) == -1) statted = false;
+ else statted = true;
+ /* Don't bother to try closing the FD if we couldn't stat it. This
+ * probably won't work.
+ *
+ * (buf_shutdown() on some of the server/child communication pipes is
+ * getting EBADF on both the fstat and the close. I'm not sure why -
+ * perhaps they were alredy closed somehow?
+ */
+ closefd = statted;
+
+ /* Flush the buffer if possible. */
+ if (buf->flush)
+ {
+ buf_flush (buf, 1);
+ buf->flush = NULL;
+ }
+
+ if (buf->input)
+ {
+ /* There used to be a check here for unread data in the buffer of
+ * the pipe, but it was deemed unnecessary and possibly dangerous. In
+ * some sense it could be second-guessing the caller who requested it
+ * closed, as well.
+ */
+
+/* FIXME:
+ *
+ * This mess of #ifdefs is hard to read. There must be some relation between
+ * the macros being checked which at least deserves comments - if
+ * SHUTDOWN_SERVER, NO_SOCKET_TO_FD, & START_RSH_WITH_POPEN_RW were completely
+ * independant, then the next few lines could easily refuse to compile.
+ *
+ * The note below about START_RSH_WITH_POPEN_RW never being set when
+ * SHUTDOWN_SERVER is defined means that this code would always break on
+ * systems with SHUTDOWN_SERVER defined and thus the comment must now be
+ * incorrect or the code was broken since the comment was written.
+ */
+# ifdef SHUTDOWN_SERVER
+ if (fb->root && fb->root->method != server_method)
+# endif
+# ifndef NO_SOCKET_TO_FD
+ {
+ /* shutdown() sockets */
+ if (statted && S_ISSOCK (s.st_mode))
+ shutdown (fb->fd, 0);
+ }
+# endif /* NO_SOCKET_TO_FD */
+# ifdef START_RSH_WITH_POPEN_RW
+/* Can't be set with SHUTDOWN_SERVER defined */
+ /* FIXME: This is now certainly broken since pclose is defined by ANSI
+ * C to accept a FILE * argument. The switch will need to happen at a
+ * higher abstraction level to switch between initializing stdio & fd
+ * buffers on systems that need this (or maybe an fd buffer that keeps
+ * track of the FILE * could be used - I think flushing the stream
+ * before beginning exclusive access via the FD is OK.
+ */
+ else if (fb->root && pclose (fb->fd) == EOF)
+ {
+ error (1, errno, "closing connection to %s",
+ fb->root->hostname);
+ closefd = false;
+ }
+# endif /* START_RSH_WITH_POPEN_RW */
+
+ buf->input = NULL;
+ }
+ else if (buf->output)
+ {
+# ifdef SHUTDOWN_SERVER
+ /* FIXME: Should have a SHUTDOWN_SERVER_INPUT &
+ * SHUTDOWN_SERVER_OUTPUT
+ */
+ if (fb->root && fb->root->method == server_method)
+ SHUTDOWN_SERVER (fb->fd);
+ else
+# endif
+# ifndef NO_SOCKET_TO_FD
+ /* shutdown() sockets */
+ if (statted && S_ISSOCK (s.st_mode))
+ shutdown (fb->fd, 1);
+# else
+ {
+ /* I'm not sure I like this empty block, but the alternative
+ * is another nested NO_SOCKET_TO_FD switch as above.
+ */
+ }
+# endif /* NO_SOCKET_TO_FD */
+
+ buf->output = NULL;
+ }
+
+ if (statted && closefd && close (fb->fd) == -1)
+ {
+ if (server_active)
+ {
+ /* Syslog this? */
+ }
+# ifdef CLIENT_SUPPORT
+ else if (fb->root)
+ error (1, errno, "closing down connection to %s",
+ fb->root->hostname);
+ /* EXITS */
+# endif /* CLIENT_SUPPORT */
+
+ error (0, errno, "closing down buffer");
+ }
+
+ /* If we were talking to a process, make sure it exited */
+ if (fb->child_pid)
+ {
+ int w;
+
+ do
+ w = waitpid (fb->child_pid, NULL, 0);
+ while (w == -1 && errno == EINTR);
+ if (w == -1)
+ error (1, errno, "waiting for process %d", fb->child_pid);
+ }
+
+ free (buf->closure);
+ buf->closure = NULL;
+
+ return 0;
+}
+#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
diff --git a/src/buffer.h b/src/buffer.h
new file mode 100644
index 0000000..b5affa4
--- /dev/null
+++ b/src/buffer.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 1996-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Declarations concerning the buffer data structure. */
+
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+
+# include "getpagesize.h"
+
+/*
+ * We must read data from a child process and send it across the
+ * network. We do not want to block on writing to the network, so we
+ * store the data from the child process in memory. A BUFFER
+ * structure holds the status of one communication, and uses a linked
+ * list of buffer_data structures to hold data.
+ */
+
+struct buffer;
+
+typedef int (*type_buf_input) (void *, char *, size_t, size_t, size_t *);
+typedef int (*type_buf_output) (void *, const char *, size_t, size_t *);
+typedef int (*type_buf_flush) (void *);
+typedef int (*type_buf_block) (void *, bool);
+typedef int (*type_buf_get_fd) (void *);
+typedef int (*type_buf_shutdown) (struct buffer *);
+typedef void (*type_buf_memory_error) (struct buffer *);
+
+struct buffer
+{
+ /* Data. */
+ struct buffer_data *data;
+
+ /* Last buffer on data chain. */
+ struct buffer_data *last;
+
+ /* Nonzero if the buffer is in nonblocking mode. */
+ bool nonblocking;
+
+ /* Functions must be provided to transfer data in and out of the
+ buffer. Either the input or output field must be set, but not
+ both. */
+
+ /* Read data into the buffer DATA. There is room for up to SIZE
+ bytes. In blocking mode, wait until some input, at least NEED
+ bytes, is available (NEED may be 0 but that is the same as NEED
+ == 1). In non-blocking mode return immediately no matter how
+ much input is available; NEED is ignored. Return 0 on success,
+ or -1 on end of file, or an errno code. Set the number of
+ bytes read in *GOT.
+
+ If there are a nonzero number of bytes available, less than NEED,
+ followed by end of file, just read those bytes and return 0. */
+ type_buf_input input;
+
+ /* Write data. This should write up to HAVE bytes from DATA.
+ This should return 0 on success, or an errno code. It should
+ set the number of bytes written in *WROTE. */
+ type_buf_output output;
+
+ /* Flush any data which may be buffered up after previous calls to
+ OUTPUT. This should return 0 on success, or an errno code. */
+ type_buf_flush flush;
+
+ /* Change the blocking mode of the underlying communication
+ stream. If BLOCK is non-zero, it should be placed into
+ blocking mode. Otherwise, it should be placed into
+ non-blocking mode. This should return 0 on success, or an
+ errno code. */
+ type_buf_block block;
+
+ /* Return the file descriptor underlying this buffer, if any, or -1
+ * otherwise.
+ */
+ type_buf_get_fd get_fd;
+
+ /* Shut down the communication stream. This does not mean that it
+ should be closed. It merely means that no more data will be
+ read or written, and that any final processing that is
+ appropriate should be done at this point. This may be NULL.
+ It should return 0 on success, or an errno code. This entry
+ point exists for the compression code. */
+ type_buf_shutdown shutdown;
+
+ /* This field is passed to the INPUT, OUTPUT, and BLOCK functions. */
+ void *closure;
+
+ /* Function to call if we can't allocate memory. */
+ type_buf_memory_error memory_error;
+};
+
+/* Data is stored in lists of these structures. */
+
+struct buffer_data
+{
+ /* Next buffer in linked list. */
+ struct buffer_data *next;
+
+ /*
+ * A pointer into the data area pointed to by the text field. This
+ * is where to find data that has not yet been written out.
+ */
+ char *bufp;
+
+ /* The number of data bytes found at BUFP. */
+ size_t size;
+
+ /*
+ * Actual buffer. This never changes after the structure is
+ * allocated. The buffer is BUFFER_DATA_SIZE bytes.
+ */
+ char *text;
+};
+
+/* The size we allocate for each buffer_data structure. */
+#define BUFFER_DATA_SIZE getpagesize ()
+
+/* The type of a function passed as a memory error handler. */
+typedef void (*BUFMEMERRPROC) (struct buffer *);
+
+struct buffer *buf_initialize (type_buf_input,
+ type_buf_output,
+ type_buf_flush,
+ type_buf_block,
+ type_buf_get_fd,
+ type_buf_shutdown,
+ type_buf_memory_error,
+ void *);
+void buf_free (struct buffer *);
+struct buffer *buf_nonio_initialize (void (*) (struct buffer *));
+struct buffer *compress_buffer_initialize (struct buffer *, int, int,
+ void (*) (struct buffer *));
+struct buffer *packetizing_buffer_initialize
+ (struct buffer *, int (*) (void *, const char *, char *, size_t),
+ int (*) (void *, const char *, char *, size_t, size_t *), void *,
+ void (*) (struct buffer *));
+int buf_empty (struct buffer *);
+int buf_empty_p (struct buffer *);
+void buf_output (struct buffer *, const char *, size_t);
+void buf_output0 (struct buffer *, const char *);
+void buf_append_char (struct buffer *, int);
+int buf_send_output (struct buffer *);
+int buf_flush (struct buffer *, bool);
+int set_nonblock (struct buffer *);
+int set_block (struct buffer *);
+int buf_send_counted (struct buffer *);
+int buf_send_special_count (struct buffer *, int);
+void buf_append_data (struct buffer *, struct buffer_data *,
+ struct buffer_data *);
+void buf_append_buffer (struct buffer *, struct buffer *);
+int buf_read_file (FILE *, long, struct buffer_data **, struct buffer_data **);
+int buf_read_file_to_eof (FILE *, struct buffer_data **,
+ struct buffer_data **);
+int buf_input_data (struct buffer *, size_t *);
+int buf_read_line (struct buffer *, char **, size_t *);
+int buf_read_short_line (struct buffer *buf, char **line, size_t *lenp,
+ size_t max);
+int buf_read_data (struct buffer *, size_t, char **, size_t *);
+void buf_copy_lines (struct buffer *, struct buffer *, int);
+int buf_copy_counted (struct buffer *, struct buffer *, int *);
+int buf_chain_length (struct buffer_data *);
+int buf_length (struct buffer *);
+int buf_get_fd (struct buffer *);
+int buf_shutdown (struct buffer *);
+#ifdef PROXY_SUPPORT
+void buf_copy_data (struct buffer *buf, struct buffer_data *data,
+ struct buffer_data *last);
+#endif /* PROXY_SUPPORT */
+void buf_free_data (struct buffer *);
+
+#ifdef SERVER_FLOWCONTROL
+int buf_count_mem (struct buffer *);
+#endif /* SERVER_FLOWCONTROL */
+
+struct buffer *
+fd_buffer_initialize (int fd, pid_t child_pid, cvsroot_t *root, bool input,
+ void (*memory) (struct buffer *));
+
+/* EWOULDBLOCK is not defined by POSIX, but some BSD systems will
+ return it, rather than EAGAIN, for nonblocking writes. */
+# ifdef EWOULDBLOCK
+# define blocking_error(err) ((err) == EWOULDBLOCK || (err) == EAGAIN)
+# else
+# define blocking_error(err) ((err) == EAGAIN)
+# endif
+#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
diff --git a/src/build_src.com b/src/build_src.com
new file mode 100755
index 0000000..8b8358c
--- /dev/null
+++ b/src/build_src.com
@@ -0,0 +1,71 @@
+$ set verify
+$ CC :== CC/NOOPT/DEB/STANDARD=VAXC/DEFINE=HAVE_CONFIG_H-
+/INCLUDE_DIR=([-],[-.VMS],[-.LIB])/PREFIX=ALL
+$ CC add.c
+$ CC admin.c
+$ CC annotate.c
+$ CC buffer.c
+$ CC checkin.c
+$ CC checkout.c
+$ CC classify.c
+$ CC client.c
+$ CC commit.c
+$ CC create_adm.c
+$ CC cvsrc.c
+$ CC diff.c
+$ CC edit.c
+$ CC entries.c
+$ CC error.c
+$ CC expand_path.c
+$ CC fileattr.c
+$ CC find_names.c
+$ CC hash.c
+$ CC history.c
+$ CC ignore.c
+$ CC import.c
+$ CC lock.c
+$ CC log.c
+$ CC login.c
+$ CC logmsg.c
+$ CC main.c
+$ CC mkmodules.c
+$ CC modules.c
+$ CC myndbm.c
+$ CC no_diff.c
+$ CC parseinfo.c
+$ CC patch.c
+$ CC rcs.c
+$ CC/INCLUDE_DIR=([-],[-.VMS],[-.LIB],[-.diff]) rcscmds.c
+$ CC recurse.c
+$ CC release.c
+$ CC remove.c
+$ CC repos.c
+$ CC root.c
+$ CC run.c
+$ CC scramble.c
+$ CC server.c
+$ CC stack.c
+$ CC status.c
+$ CC subr.c
+$ CC tag.c
+$ CC update.c
+$ CC version.c
+$ CC vers_ts.c
+$ CC watch.c
+$ CC wrapper.c
+$ CC/INCLUDE_DIR=([-],[-.VMS],[-.LIB],[-.zlib]) zlib.c
+$ LIBRARY/CREATE cvslib.olb add.obj,admin.obj,annotate.obj,buffer.obj,checkin.obj,-
+checkout.obj,-
+classify.obj,client.obj,commit.obj,create_adm.obj,cvsrc.obj,-
+diff.obj,edit.obj,entries.obj,error.obj,expand_path.obj,fileattr.obj,-
+find_names.obj,hash.obj,history.obj,ignore.obj,import.obj,-
+lock.obj,log.obj,login.obj,logmsg.obj,mkmodules.obj,modules.obj,myndbm.obj,-
+no_diff.obj,-
+parseinfo.obj,patch.obj,rcs.obj,rcscmds.obj,recurse.obj,release.obj,-
+remove.obj,repos.obj,root.obj,run.obj,scramble.obj,server.obj,-
+stack.obj,status.obj,-
+subr.obj,tag.obj,update.obj,version.obj,vers_ts.obj,watch.obj,wrapper.obj,-
+zlib.obj
+$ link/nodeb/exe=cvs.exe main.obj,cvslib.olb/lib,[-.vms]openvmslib.olb/lib,-
+ [-.zlib]libz.olb/lib,[-.diff]diff.olb/lib,[-.lib]gnulib.olb/lib
+$ set noverify
diff --git a/src/checkin.c b/src/checkin.c
new file mode 100644
index 0000000..33793e4
--- /dev/null
+++ b/src/checkin.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Check In
+ *
+ * Does a very careful checkin of the file "user", and tries not to spoil its
+ * modification time (to avoid needless recompilations). When RCS ID keywords
+ * get expanded on checkout, however, the modification time is updated and
+ * there is no good way to get around this.
+ *
+ * Returns non-zero on error.
+ */
+
+#include "cvs.h"
+#include "fileattr.h"
+#include "edit.h"
+
+int
+Checkin (int type, struct file_info *finfo, char *rev, char *tag,
+ char *options, char *message)
+{
+ Vers_TS *vers;
+ int set_time;
+ char *tocvsPath = NULL;
+
+ tocvsPath = wrap_tocvs_process_file (finfo->file);
+ if (!noexec)
+ {
+ if (tocvsPath)
+ {
+ if (unlink_file_dir (finfo->file) < 0)
+ if (! existence_error (errno))
+ error (1, errno, "cannot remove %s", finfo->fullname);
+ rename_file (tocvsPath, finfo->file);
+ }
+ }
+
+ /* There use to be a check for finfo->rcs == NULL here and then a
+ * call to RCS_parse when necessary, but Checkin() isn't called
+ * if the RCS file hasn't already been parsed in one of the
+ * check functions.
+ */
+ assert (finfo->rcs != NULL);
+
+ switch (RCS_checkin (finfo->rcs, finfo->update_dir, finfo->file, message,
+ rev, 0, RCS_FLAGS_KEEPFILE))
+ {
+ case 0: /* everything normal */
+
+ /* The checkin succeeded. If checking the file out again
+ would not cause any changes, we are done. Otherwise,
+ we need to check out the file, which will change the
+ modification time of the file.
+
+ The only way checking out the file could cause any
+ changes is if the file contains RCS keywords. So we if
+ we are not expanding RCS keywords, we are done. */
+
+ if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
+ options[0] = '\0';
+
+ /* FIXME: If PreservePermissions is on, RCS_cmp_file is
+ going to call RCS_checkout into a temporary file
+ anyhow. In that case, it would be more efficient to
+ call RCS_checkout here, compare the resulting files
+ using xcmp, and rename if necessary. I think this
+ should be fixed in RCS_cmp_file. */
+ if ((1
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ !config->preserve_perms
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+ && options
+ && (!strcmp (options, "-ko") || !strcmp (options, "-kb")))
+ || !RCS_cmp_file (finfo->rcs, rev, NULL, NULL,
+ options, finfo->file))
+ {
+ /* The existing file is correct. We don't have to do
+ anything. */
+ set_time = 0;
+ }
+ else
+ {
+ /* The existing file is incorrect. We need to check
+ out the correct file contents. */
+ if (RCS_checkout (finfo->rcs, finfo->file, rev, NULL,
+ options, RUN_TTY, NULL, NULL) != 0)
+ error (1, 0, "failed when checking out new copy of %s",
+ finfo->fullname);
+ xchmod (finfo->file, 1);
+ set_time = 1;
+ }
+
+ wrap_fromcvs_process_file (finfo->file);
+
+ /*
+ * If we want read-only files, muck the permissions here, before
+ * getting the file time-stamp.
+ */
+ if (!cvswrite || fileattr_get (finfo->file, "_watched"))
+ xchmod (finfo->file, 0);
+
+ /* Re-register with the new data. */
+ vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time);
+ if (strcmp (vers->options, "-V4") == 0)
+ vers->options[0] = '\0';
+ Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_user,
+ vers->options, vers->tag, vers->date, NULL);
+ history_write (type, NULL, vers->vn_rcs,
+ finfo->file, finfo->repository);
+
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ break;
+
+ case -1: /* fork failed */
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ if (!noexec)
+ error (1, errno, "could not check in %s -- fork failed",
+ finfo->fullname);
+ return (1);
+
+ default: /* ci failed */
+
+ /* The checkin failed, for some unknown reason, so we
+ print an error, and return an error. We assume that
+ the original file has not been touched. */
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ if (!noexec)
+ error (0, 0, "could not check in %s", finfo->fullname);
+ return (1);
+ }
+
+ /*
+ * When checking in a specific revision, we may have locked the wrong
+ * branch, so to be sure, we do an extra unlock here before
+ * returning.
+ */
+ if (rev)
+ {
+ (void) RCS_unlock (finfo->rcs, NULL, 1);
+ RCS_rewrite (finfo->rcs, NULL, NULL);
+ }
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ if (set_time)
+ /* Need to update the checked out file on the client side. */
+ server_updated (finfo, vers, SERVER_UPDATED,
+ (mode_t) -1, NULL, NULL);
+ else
+ server_checked_in (finfo->file, finfo->update_dir,
+ finfo->repository);
+ }
+ else
+#endif
+ mark_up_to_date (finfo->file);
+
+ freevers_ts (&vers);
+ return 0;
+}
diff --git a/src/checkout.c b/src/checkout.c
new file mode 100644
index 0000000..bba93ca
--- /dev/null
+++ b/src/checkout.c
@@ -0,0 +1,1260 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Create Version
+ *
+ * "checkout" creates a "version" of an RCS repository. This version is owned
+ * totally by the user and is actually an independent copy, to be dealt with
+ * as seen fit. Once "checkout" has been called in a given directory, it
+ * never needs to be called again. The user can keep up-to-date by calling
+ * "update" when he feels like it; this will supply him with a merge of his
+ * own modifications and the changes made in the RCS original. See "update"
+ * for details.
+ *
+ * "checkout" can be given a list of directories or files to be updated and in
+ * the case of a directory, will recursivley create any sub-directories that
+ * exist in the repository.
+ *
+ * When the user is satisfied with his own modifications, the present version
+ * can be committed by "commit"; this keeps the present version in tact,
+ * usually.
+ *
+ * The call is cvs checkout [options] <module-name>...
+ *
+ * "checkout" creates a directory ./CVS, in which it keeps its administration,
+ * in two files, Repository and Entries. The first contains the name of the
+ * repository. The second contains one line for each registered file,
+ * consisting of the version number it derives from, its time stamp at
+ * derivation time and its name. Both files are normal files and can be
+ * edited by the user, if necessary (when the repository is moved, e.g.)
+ */
+
+#include "cvs.h"
+
+static char *findslash (char *start, char *p);
+static int checkout_proc (int argc, char **argv, char *where,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *omodule,
+ char *msg);
+
+static const char *const checkout_usage[] =
+{
+ "Usage:\n %s %s [-ANPRcflnps] [-r rev] [-D date] [-d dir]\n",
+ " [-j rev1] [-j rev2] [-k kopt] modules...\n",
+ "\t-A\tReset any sticky tags/date/kopts.\n",
+ "\t-N\tDon't shorten module paths if -d specified.\n",
+ "\t-P\tPrune empty directories.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-c\t\"cat\" the module database.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-n\tDo not run module program (if any).\n",
+ "\t-p\tCheck out files to standard output (avoids stickiness).\n",
+ "\t-s\tLike -c, but include module status.\n",
+ "\t-r rev\tCheck out revision or tag. (implies -P) (is sticky)\n",
+ "\t-D date\tCheck out revisions as of date. (implies -P) (is sticky)\n",
+ "\t-d dir\tCheck out into dir instead of module name.\n",
+ "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n",
+ "\t-j rev\tMerge in changes made between current revision and rev.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+static const char *const export_usage[] =
+{
+ "Usage: %s %s [-NRfln] [-r tag] [-D date] [-d dir] [-k kopt] module...\n",
+ "\t-N\tDon't shorten module paths if -d specified.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-R\tProcess directories recursively (default).\n",
+ "\t-n\tDo not run module program (if any).\n",
+ "\t-r tag\tExport tagged revisions.\n",
+ "\t-D date\tExport revisions as of date.\n",
+ "\t-d dir\tExport into dir instead of module name.\n",
+ "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+static int checkout_prune_dirs;
+static int force_tag_match;
+static int pipeout;
+static int aflag;
+static char *options;
+static char *tag;
+static bool tag_validated;
+static char *date;
+static char *join_rev1, *join_date1;
+static char *join_rev2, *join_date2;
+static bool join_tags_validated;
+static char *preload_update_dir;
+static char *history_name;
+static enum mtype m_type;
+
+int
+checkout (int argc, char **argv)
+{
+ int i;
+ int c;
+ DBM *db;
+ int cat = 0, err = 0, status = 0;
+ int run_module_prog = 1;
+ int local = 0;
+ int shorten = -1;
+ char *where = NULL;
+ const char *valid_options;
+ const char *const *valid_usage;
+ char *join_orig1, *join_orig2;
+
+ /* initialize static options */
+ force_tag_match = 1;
+ if (options)
+ {
+ free (options);
+ options = NULL;
+ }
+ tag = date = join_rev1 = join_date1 = join_rev2 = join_date2 =
+ join_orig1 = join_orig2 = preload_update_dir = NULL;
+ history_name = NULL;
+ tag_validated = join_tags_validated = false;
+
+
+ /*
+ * A smaller subset of options are allowed for the export command, which
+ * is essentially like checkout, except that it hard-codes certain
+ * options to be default (like -kv) and takes care to remove the CVS
+ * directory when it has done its duty
+ */
+ if (strcmp (cvs_cmd_name, "export") == 0)
+ {
+ m_type = EXPORT;
+ valid_options = "+Nnk:d:flRQqr:D:";
+ valid_usage = export_usage;
+ }
+ else
+ {
+ m_type = CHECKOUT;
+ valid_options = "+ANnk:d:flRpQqcsr:D:j:P";
+ valid_usage = checkout_usage;
+ }
+
+ if (argc == -1)
+ usage (valid_usage);
+
+ ign_setup ();
+ wrap_setup ();
+
+ optind = 0;
+ while ((c = getopt (argc, argv, valid_options)) != -1)
+ {
+ switch (c)
+ {
+ case 'A':
+ aflag = 1;
+ break;
+ case 'N':
+ shorten = 0;
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'n':
+ run_module_prog = 0;
+ break;
+ case 'Q':
+ case 'q':
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ cvs_cmd_name);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'P':
+ checkout_prune_dirs = 1;
+ break;
+ case 'p':
+ pipeout = 1;
+ run_module_prog = 0; /* don't run module prog when piping */
+ noexec = 1; /* so no locks will be created */
+ break;
+ case 'c':
+ cat = 1;
+ break;
+ case 'd':
+ where = optarg;
+ if (shorten == -1)
+ shorten = 1;
+ break;
+ case 's':
+ cat = status = 1;
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'r':
+ parse_tagdate (&tag, &date, optarg);
+ checkout_prune_dirs = 1;
+ break;
+ case 'D':
+ if (date) free (date);
+ date = Make_Date (optarg);
+ checkout_prune_dirs = 1;
+ break;
+ case 'j':
+ if (join_rev2 || join_date2)
+ error (1, 0, "only two -j options can be specified");
+ if (join_rev1 || join_date1)
+ {
+ if (join_orig2) free (join_orig2);
+ join_orig2 = xstrdup (optarg);
+ parse_tagdate (&join_rev2, &join_date2, optarg);
+ }
+ else
+ {
+ if (join_orig1) free (join_orig1);
+ join_orig1 = xstrdup (optarg);
+ parse_tagdate (&join_rev1, &join_date1, optarg);
+ }
+ break;
+ case '?':
+ default:
+ usage (valid_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (shorten == -1)
+ shorten = 0;
+
+ if (cat && argc != 0)
+ error (1, 0, "-c and -s must not get any arguments");
+
+ if (!cat && argc == 0)
+ error (1, 0, "must specify at least one module or directory");
+
+ if (where && pipeout)
+ error (1, 0, "-d and -p are mutually exclusive");
+
+ if (m_type == EXPORT)
+ {
+ if (!tag && !date)
+ error (1, 0, "must specify a tag or date");
+
+ if (tag && isdigit (tag[0]))
+ error (1, 0, "tag `%s' must be a symbolic tag", tag);
+ }
+
+#ifdef SERVER_SUPPORT
+ if (server_active && where != NULL)
+ {
+ server_pathname_check (where);
+ }
+#endif
+
+ if (!cat && !pipeout && !safe_location (where))
+ {
+ error (1, 0, "Cannot check out files into the repository itself");
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ int expand_modules;
+
+ start_server ();
+
+ ign_setup ();
+
+ expand_modules = (!cat && !pipeout
+ && supported_request ("expand-modules"));
+
+ if (expand_modules)
+ {
+ /* This is done here because we need to read responses
+ from the server before we send the command checkout or
+ export files. */
+
+ client_expand_modules (argc, argv, local);
+ }
+
+ if (!run_module_prog)
+ send_arg ("-n");
+ if (local)
+ send_arg ("-l");
+ if (pipeout)
+ send_arg ("-p");
+ if (!force_tag_match)
+ send_arg ("-f");
+ if (aflag)
+ send_arg ("-A");
+ if (!shorten)
+ send_arg ("-N");
+ if (checkout_prune_dirs && m_type == CHECKOUT)
+ send_arg ("-P");
+ client_prune_dirs = checkout_prune_dirs;
+ if (cat && !status)
+ send_arg ("-c");
+ if (where != NULL)
+ option_with_arg ("-d", where);
+ if (status)
+ send_arg ("-s");
+ if (options != NULL && options[0] != '\0')
+ send_arg (options);
+ option_with_arg ("-r", tag);
+ if (date)
+ client_senddate (date);
+ if (join_orig1)
+ option_with_arg ("-j", join_orig1);
+ if (join_orig2)
+ option_with_arg ("-j", join_orig2);
+ send_arg ("--");
+
+ if (expand_modules)
+ {
+ client_send_expansions (local, where, 1);
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ client_nonexpanded_setup ();
+ }
+
+ send_to_server (m_type == EXPORT ? "export\012" : "co\012", 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ if (cat)
+ {
+ cat_module (status);
+ if (options)
+ {
+ free (options);
+ options = NULL;
+ }
+ return 0;
+ }
+ db = open_module ();
+
+
+ /* If we've specified something like "cvs co foo/bar baz/quux"
+ don't try to shorten names. There are a few cases in which we
+ could shorten (e.g. "cvs co foo/bar foo/baz"), but we don't
+ handle those yet. Better to have an extra directory created
+ than the thing checked out under the wrong directory name. */
+
+ if (argc > 1)
+ shorten = 0;
+
+
+ /* If we will be calling history_write, work out the name to pass
+ it. */
+ if (!pipeout)
+ {
+ if (!date)
+ history_name = tag;
+ else if (!tag)
+ history_name = date;
+ else
+ history_name = Xasprintf ("%s:%s", tag, date);
+ }
+
+
+ for (i = 0; i < argc; i++)
+ err += do_module (db, argv[i], m_type, "Updating", checkout_proc,
+ where, shorten, local, run_module_prog, !pipeout,
+ NULL);
+ close_module (db);
+ if (options)
+ {
+ free (options);
+ options = NULL;
+ }
+ if (history_name != tag && history_name != date && history_name != NULL)
+ free (history_name);
+ return err;
+}
+
+
+
+/* FIXME: This is and emptydir_name are in checkout.c for historical
+ reasons, probably want to move them. */
+
+/* int
+ * safe_location ( char *where )
+ *
+ * Return true if where is a safe destination for a checkout.
+ *
+ * INPUTS
+ * where The requested destination directory.
+ *
+ * GLOBALS
+ * current_parsed_root->directory
+ * current_parsed_root->isremote
+ * Used to locate our CVSROOT.
+ *
+ * RETURNS
+ * true If we are running in client mode or if where is not located
+ * within the CVSROOT.
+ * false Otherwise.
+ *
+ * ERRORS
+ * Exits with a fatal error message when various events occur, such as not
+ * being able to resolve a path or failing ot chdir to a path.
+ */
+int
+safe_location (char *where)
+{
+ char *current;
+ char *hardpath;
+ size_t hardpath_len;
+ int retval;
+
+ TRACE (TRACE_FUNCTION, "safe_location( where=%s )",
+ where ? where : "(null)");
+
+ /* Don't compare remote CVSROOTs to our destination directory. */
+ if (current_parsed_root->isremote) return 1;
+
+ /* set current - even if where is set we'll need to cd back... */
+ current = xgetcwd ();
+ if (current == NULL)
+ error (1, errno, "could not get working directory");
+
+ hardpath = xcanonicalize_file_name (current_parsed_root->directory);
+
+ /* if where is set, set current to as much of where as exists,
+ * or fail.
+ */
+ if (where != NULL)
+ {
+ char *where_this_pass = xstrdup (where);
+ while (1)
+ {
+ if (CVS_CHDIR (where_this_pass) != -1)
+ {
+ /* where */
+ free (where_this_pass);
+ where_this_pass = xgetcwd ();
+ if (where_this_pass == NULL)
+ error (1, errno, "could not get working directory");
+
+ if (CVS_CHDIR (current) == -1)
+ error (1, errno,
+ "could not restore directory to `%s'", current);
+
+ free (current);
+ current = where_this_pass;
+ break;
+ }
+ else if (errno == ENOENT)
+ {
+ /* where_this_pass - last_component (where_this_pass) */
+ char *parent;
+
+ /* It's okay to cast out the const below since we know we
+ * allocated where_this_pass and have control of it.
+ */
+ if ((parent = (char *)last_component (where_this_pass))
+ != where_this_pass)
+ {
+ /* strip the last_component */
+ parent[-1] = '\0';
+ /* continue */
+ }
+ else
+ {
+ /* ERRNO == ENOENT
+ * && last_component (where_this_pass) == where_this_pass
+ * means we've tried all the parent diretories and not one
+ * exists, so there is no need to test any portion of where
+ * - it is all being created.
+ */
+ free (where_this_pass);
+ break;
+ }
+ }
+ else
+ /* we don't know how to handle other errors, so fail */
+ error (1, errno, "\
+could not change directory to requested checkout directory `%s'",
+ where_this_pass);
+ } /* while (1) */
+ } /* where != NULL */
+
+ hardpath_len = strlen (hardpath);
+ if (strlen (current) >= hardpath_len
+ && strncmp (current, hardpath, hardpath_len) == 0)
+ {
+ if (/* Current is a subdirectory of hardpath. */
+ current[hardpath_len] == '/'
+
+ /* Current is hardpath itself. */
+ || current[hardpath_len] == '\0')
+ retval = 0;
+ else
+ /* It isn't a problem. For example, current is
+ "/foo/cvsroot-bar" and hardpath is "/foo/cvsroot". */
+ retval = 1;
+ }
+ else
+ retval = 1;
+ free (current);
+ free (hardpath);
+ return retval;
+}
+
+
+
+struct dir_to_build
+{
+ /* What to put in CVS/Repository. */
+ char *repository;
+ /* The path to the directory. */
+ char *dirpath;
+
+ struct dir_to_build *next;
+};
+
+
+
+static int build_dirs_and_chdir (struct dir_to_build *list,
+ int sticky);
+
+static void
+build_one_dir (char *repository, char *dirpath, int sticky)
+{
+ FILE *fp;
+
+ if (isfile (CVSADM))
+ {
+ if (m_type == EXPORT)
+ error (1, 0, "cannot export into a working directory");
+ }
+ else if (m_type == CHECKOUT)
+ {
+ /* I suspect that this check could be omitted. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+
+ if (Create_Admin (".", dirpath, repository,
+ sticky ? tag : NULL,
+ sticky ? date : NULL,
+
+ /* FIXME? This is a guess. If it is important
+ for nonbranch to be set correctly here I
+ think we need to write it one way now and
+ then rewrite it later via WriteTag, once
+ we've had a chance to call RCS_nodeisbranch
+ on each file. */
+ 0, 1, 1))
+ return;
+
+ if (!noexec)
+ {
+ fp = xfopen (CVSADM_ENTSTAT, "w+");
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (dirpath, repository);
+#endif
+ }
+ }
+}
+
+
+
+/*
+ * process_module calls us back here so we do the actual checkout stuff
+ */
+/* ARGSUSED */
+static int
+checkout_proc (int argc, char **argv, char *where_orig, char *mwhere,
+ char *mfile, int shorten, int local_specified, char *omodule,
+ char *msg)
+{
+ char *myargv[2];
+ int err = 0;
+ int which;
+ char *cp;
+ char *repository;
+ char *oldupdate = NULL;
+ char *where;
+
+ TRACE (TRACE_FUNCTION, "checkout_proc (%s, %s, %s, %d, %d, %s, %s)\n",
+ where_orig ? where_orig : "(null)",
+ mwhere ? mwhere : "(null)",
+ mfile ? mfile : "(null)",
+ shorten, local_specified,
+ omodule ? omodule : "(null)",
+ msg ? msg : "(null)"
+ );
+
+ /*
+ * OK, so we're doing the checkout! Our args are as follows:
+ * argc,argv contain either dir or dir followed by a list of files
+ * where contains where to put it (if supplied by checkout)
+ * mwhere contains the module name or -d from module file
+ * mfile says do only that part of the module
+ * shorten = 1 says shorten as much as possible
+ * omodule is the original arg to do_module()
+ */
+
+ /* Set up the repository (maybe) for the bottom directory.
+ Allocate more space than we need so we don't need to keep
+ reallocating this string. */
+ repository = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile))
+ + 10);
+ (void) sprintf (repository, "%s/%s",
+ current_parsed_root->directory, argv[0]);
+ Sanitize_Repository_Name (repository);
+
+
+ /* save the original value of preload_update_dir */
+ if (preload_update_dir != NULL)
+ oldupdate = xstrdup (preload_update_dir);
+
+
+ /* Allocate space and set up the where variable. We allocate more
+ space than necessary here so that we don't have to keep
+ reallocaing it later on. */
+
+ where = xmalloc (strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile))
+ + (mwhere == NULL ? 0 : strlen (mwhere))
+ + (where_orig == NULL ? 0 : strlen (where_orig))
+ + 10);
+
+ /* Yes, this could be written in a less verbose way, but in this
+ form it is quite easy to read.
+
+ FIXME? The following code that sets should probably be moved
+ to do_module in modules.c, since there is similar code in
+ patch.c and rtag.c. */
+
+ if (shorten)
+ {
+ if (where_orig != NULL)
+ {
+ /* If the user has specified a directory with `-d' on the
+ command line, use it preferentially, even over the `-d'
+ flag in the modules file. */
+
+ (void) strcpy (where, where_orig);
+ }
+ else if (mwhere != NULL)
+ {
+ /* Second preference is the value of mwhere, which is from
+ the `-d' flag in the modules file. */
+
+ (void) strcpy (where, mwhere);
+ }
+ else
+ {
+ /* Third preference is the directory specified in argv[0]
+ which is this module'e directory in the repository. */
+
+ (void) strcpy (where, argv[0]);
+ }
+ }
+ else
+ {
+ /* Use the same preferences here, bug don't shorten -- that
+ is, tack on where_orig if it exists. */
+
+ *where = '\0';
+
+ if (where_orig != NULL)
+ {
+ (void) strcat (where, where_orig);
+ (void) strcat (where, "/");
+ }
+
+ /* If the -d flag in the modules file specified an absolute
+ directory, let the user override it with the command-line
+ -d option. */
+
+ if (mwhere && !ISABSOLUTE (mwhere))
+ (void) strcat (where, mwhere);
+ else
+ (void) strcat (where, argv[0]);
+ }
+ strip_trailing_slashes (where); /* necessary? */
+
+
+ /* At this point, the user may have asked for a single file or
+ directory from within a module. In that case, we should modify
+ where, repository, and argv as appropriate. */
+
+ if (mfile != NULL)
+ {
+ /* The mfile variable can have one or more path elements. If
+ it has multiple elements, we want to tack those onto both
+ repository and where. The last element may refer to either
+ a file or directory. Here's what to do:
+
+ it refers to a directory
+ -> simply tack it on to where and repository
+ it refers to a file
+ -> munge argv to contain `basename mfile` */
+
+ char *cp;
+ char *path;
+
+
+ /* Paranoia check. */
+
+ if (mfile[strlen (mfile) - 1] == '/')
+ {
+ error (0, 0, "checkout_proc: trailing slash on mfile (%s)!",
+ mfile);
+ }
+
+
+ /* Does mfile have multiple path elements? */
+
+ cp = strrchr (mfile, '/');
+ if (cp != NULL)
+ {
+ *cp = '\0';
+ (void) strcat (repository, "/");
+ (void) strcat (repository, mfile);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+
+ /* Now mfile is a single path element. */
+
+ path = Xasprintf ("%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* It's a directory, so tack it on to repository and
+ where, as we did above. */
+
+ (void) strcat (repository, "/");
+ (void) strcat (repository, mfile);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ }
+ else
+ {
+ /* It's a file, which means we have to screw around with
+ argv. */
+ myargv[0] = argv[0];
+ myargv[1] = mfile;
+ argc = 2;
+ argv = myargv;
+ }
+ free (path);
+ }
+
+ if (preload_update_dir != NULL)
+ {
+ preload_update_dir =
+ xrealloc (preload_update_dir,
+ strlen (preload_update_dir) + strlen (where) + 5);
+ strcat (preload_update_dir, "/");
+ strcat (preload_update_dir, where);
+ }
+ else
+ preload_update_dir = xstrdup (where);
+
+ /*
+ * At this point, where is the directory we want to build, repository is
+ * the repository for the lowest level of the path.
+ *
+ * We need to tell build_dirs not only the path we want it to
+ * build, but also the repositories we want it to populate the
+ * path with. To accomplish this, we walk the path backwards, one
+ * pathname component at a time, constucting a linked list of
+ * struct dir_to_build.
+ */
+
+ /*
+ * If we are sending everything to stdout, we can skip a whole bunch of
+ * work from here
+ */
+ if (!pipeout)
+ {
+ struct dir_to_build *head;
+ char *reposcopy;
+
+ if (strncmp (repository, current_parsed_root->directory,
+ strlen (current_parsed_root->directory)) != 0)
+ error (1, 0, "\
+internal error: %s doesn't start with %s in checkout_proc",
+ repository, current_parsed_root->directory);
+
+ /* We always create at least one directory, which corresponds to
+ the entire strings for WHERE and REPOSITORY. */
+ head = xmalloc (sizeof (struct dir_to_build));
+ /* Special marker to indicate that we don't want build_dirs_and_chdir
+ to create the CVSADM directory for us. */
+ head->repository = NULL;
+ head->dirpath = xstrdup (where);
+ head->next = NULL;
+
+ /* Make a copy of the repository name to play with. */
+ reposcopy = xstrdup (repository);
+
+ /* FIXME: this should be written in terms of last_component
+ instead of hardcoding '/'. This presumably affects OS/2,
+ NT, &c, if the user specifies '\'. Likewise for the call
+ to findslash. */
+ cp = where + strlen (where);
+ while (cp > where)
+ {
+ struct dir_to_build *new;
+
+ cp = findslash (where, cp - 1);
+ if (cp == NULL)
+ break; /* we're done */
+
+ new = xmalloc (sizeof (struct dir_to_build));
+ new->dirpath = xmalloc (strlen (where));
+
+ /* If the user specified an absolute path for where, the
+ last path element we create should be the top-level
+ directory. */
+
+ if (cp > where)
+ {
+ strncpy (new->dirpath, where, cp - where);
+ new->dirpath[cp - where] = '\0';
+ }
+ else
+ {
+ /* where should always be at least one character long. */
+ assert (where[0] != '\0');
+ strcpy (new->dirpath, "/");
+ }
+ new->next = head;
+ head = new;
+
+ /* Now figure out what repository directory to generate.
+ The most complete case would be something like this:
+
+ The modules file contains
+ foo -d bar/baz quux
+
+ The command issued was:
+ cvs co -d what/ever -N foo
+
+ The results in the CVS/Repository files should be:
+ . -> (don't touch CVS/Repository)
+ (I think this case might be buggy currently)
+ what -> (don't touch CVS/Repository)
+ ever -> . (same as "cd what/ever; cvs co -N foo")
+ bar -> Emptydir (generated dir -- not in repos)
+ baz -> quux (finally!) */
+
+ if (strcmp (reposcopy, current_parsed_root->directory) == 0)
+ {
+ /* We can't walk up past CVSROOT. Instead, the
+ repository should be Emptydir. */
+ new->repository = emptydir_name ();
+ }
+ else
+ {
+ /* It's a directory in the repository! */
+
+ char *rp;
+
+ /* We'll always be below CVSROOT, but check for
+ paranoia's sake. */
+ rp = strrchr (reposcopy, '/');
+ if (rp == NULL)
+ error (1, 0,
+ "internal error: %s doesn't contain a slash",
+ reposcopy);
+
+ *rp = '\0';
+
+ if (strcmp (reposcopy, current_parsed_root->directory) == 0)
+ {
+ /* Special case -- the repository name needs
+ to be "/path/to/repos/." (the trailing dot
+ is important). We might be able to get rid
+ of this after the we check out the other
+ code that handles repository names. */
+ new-> repository = Xasprintf ("%s/.", reposcopy);
+ }
+ else
+ new->repository = xstrdup (reposcopy);
+ }
+ }
+
+ /* clean up */
+ free (reposcopy);
+
+ /* The top-level CVSADM directory should always be
+ current_parsed_root->directory. Create it, but only if WHERE is
+ relative. If WHERE is absolute, our current directory
+ may not have a thing to do with where the sources are
+ being checked out. If it does, build_dirs_and_chdir
+ will take care of creating adm files here. */
+ /* FIXME: checking where_is_absolute is a horrid kludge;
+ I suspect we probably can just skip the call to
+ build_one_dir whenever the -d command option was specified
+ to checkout. */
+
+ if (!ISABSOLUTE (where) && config->top_level_admin
+ && m_type == CHECKOUT)
+ {
+ /* It may be argued that we shouldn't set any sticky
+ bits for the top-level repository. FIXME? */
+ build_one_dir (current_parsed_root->directory, ".", argc <= 1);
+
+#ifdef SERVER_SUPPORT
+ /* We _always_ want to have a top-level admin
+ directory. If we're running in client/server mode,
+ send a "Clear-static-directory" command to make
+ sure it is created on the client side. (See 5.10
+ in cvsclient.dvi to convince yourself that this is
+ OK.) If this is a duplicate command being sent, it
+ will be ignored on the client side. */
+
+ if (server_active)
+ server_clear_entstat (".", current_parsed_root->directory);
+#endif
+ }
+
+
+ /* Build dirs on the path if necessary and leave us in the
+ bottom directory (where if where was specified) doesn't
+ contain a CVS subdir yet, but all the others contain
+ CVS and Entries.Static files */
+
+ if (build_dirs_and_chdir (head, argc <= 1) != 0)
+ {
+ error (0, 0, "ignoring module %s", omodule);
+ err = 1;
+ goto out;
+ }
+
+ /* set up the repository (or make sure the old one matches) */
+ if (!isfile (CVSADM))
+ {
+ FILE *fp;
+
+ if (!noexec && argc > 1)
+ {
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+
+ Create_Admin (".", preload_update_dir, repository,
+ NULL, NULL, 0, 0, m_type == CHECKOUT);
+ fp = xfopen (CVSADM_ENTSTAT, "w+");
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (where, repository);
+#endif
+ }
+ else
+ {
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+
+ Create_Admin (".", preload_update_dir, repository, tag, date,
+
+ /* FIXME? This is a guess. If it is important
+ for nonbranch to be set correctly here I
+ think we need to write it one way now and
+ then rewrite it later via WriteTag, once
+ we've had a chance to call RCS_nodeisbranch
+ on each file. */
+ 0, 0, m_type == CHECKOUT);
+ }
+ }
+ else
+ {
+ char *repos;
+
+ if (m_type == EXPORT)
+ error (1, 0, "cannot export into working directory");
+
+ /* get the contents of the previously existing repository */
+ repos = Name_Repository (NULL, preload_update_dir);
+ if (fncmp (repository, repos) != 0)
+ {
+ char *prepos = xstrdup (primary_root_inverse_translate (repos));
+ char *prepository =
+ xstrdup (primary_root_inverse_translate (repository));
+ error (0, 0, "existing repository %s does not match %s",
+ prepos, prepository);
+ error (0, 0, "ignoring module %s", omodule);
+ free (repos);
+ free (prepos);
+ free (prepository);
+ err = 1;
+ goto out;
+ }
+ free (repos);
+ }
+ }
+
+ /*
+ * If we are going to be updating to stdout, we need to cd to the
+ * repository directory so the recursion processor can use the current
+ * directory as the place to find repository information
+ */
+ if (pipeout)
+ {
+ if (CVS_CHDIR (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ err = 1;
+ goto out;
+ }
+ which = W_REPOS;
+ if (tag && !tag_validated)
+ {
+ tag_check_valid (tag, argc - 1, argv + 1, 0, aflag,
+ repository, false);
+ tag_validated = true;
+ }
+ }
+ else
+ {
+ which = W_LOCAL | W_REPOS;
+ if (tag && !tag_validated)
+ {
+ tag_check_valid (tag, argc - 1, argv + 1, 0, aflag,
+ repository, false);
+ tag_validated = true;
+ }
+ }
+
+ if (tag || date || join_rev1 || join_date2)
+ which |= W_ATTIC;
+
+ if (!join_tags_validated)
+ {
+ if (join_rev1)
+ tag_check_valid (join_rev1, argc - 1, argv + 1, 0, aflag,
+ repository, false);
+ if (join_rev2)
+ tag_check_valid (join_rev2, argc - 1, argv + 1, 0, aflag,
+ repository, false);
+ join_tags_validated = true;
+ }
+
+ /*
+ * if we are going to be recursive (building dirs), go ahead and call the
+ * update recursion processor. We will be recursive unless either local
+ * only was specified, or we were passed arguments
+ */
+ if (!(local_specified || argc > 1))
+ {
+ if (!pipeout)
+ history_write (m_type == CHECKOUT ? 'O' : 'E', preload_update_dir,
+ history_name, where, repository);
+ err += do_update (0, NULL, options, tag, date,
+ force_tag_match, false /* !local */ ,
+ true /* update -d */ , aflag, checkout_prune_dirs,
+ pipeout, which, join_rev1, join_date1,
+ join_rev2, join_date2,
+ preload_update_dir, m_type == CHECKOUT,
+ repository);
+ goto out;
+ }
+
+ if (!pipeout)
+ {
+ int i;
+ List *entries;
+
+ /* we are only doing files, so register them */
+ entries = Entries_Open (0, NULL);
+ for (i = 1; i < argc; i++)
+ {
+ char *line;
+ Vers_TS *vers;
+ struct file_info finfo;
+
+ memset (&finfo, 0, sizeof finfo);
+ finfo.file = argv[i];
+ /* Shouldn't be used, so set to arbitrary value. */
+ finfo.update_dir = NULL;
+ finfo.fullname = argv[i];
+ finfo.repository = repository;
+ finfo.entries = entries;
+ /* The rcs slot is needed to get the options from the RCS
+ file */
+ finfo.rcs = RCS_parse (finfo.file, repository);
+
+ vers = Version_TS (&finfo, options, tag, date,
+ force_tag_match, 0);
+ if (vers->ts_user == NULL)
+ {
+ line = Xasprintf ("Initial %s", finfo.file);
+ Register (entries, finfo.file,
+ vers->vn_rcs ? vers->vn_rcs : "0",
+ line, vers->options, vers->tag,
+ vers->date, NULL);
+ free (line);
+ }
+ freevers_ts (&vers);
+ freercsnode (&finfo.rcs);
+ }
+
+ Entries_Close (entries);
+ }
+
+ /* Don't log "export", just regular "checkouts" */
+ if (m_type == CHECKOUT && !pipeout)
+ history_write ('O', preload_update_dir, history_name, where,
+ repository);
+
+ /* go ahead and call update now that everything is set */
+ err += do_update (argc - 1, argv + 1, options, tag, date,
+ force_tag_match, local_specified, true /* update -d */,
+ aflag, checkout_prune_dirs, pipeout, which, join_rev1,
+ join_date1, join_rev2, join_date2, preload_update_dir,
+ m_type == CHECKOUT, repository);
+out:
+ free (preload_update_dir);
+ preload_update_dir = oldupdate;
+ free (where);
+ free (repository);
+ return err;
+}
+
+
+
+static char *
+findslash (char *start, char *p)
+{
+ for (;;)
+ {
+ if (*p == '/') return p;
+ if (p == start) break;
+ --p;
+ }
+ return NULL;
+}
+
+
+
+/* Return a newly malloc'd string containing a pathname for CVSNULLREPOS,
+ and make sure that it exists. If there is an error creating the
+ directory, give a fatal error. Otherwise, the directory is guaranteed
+ to exist when we return. */
+char *
+emptydir_name (void)
+{
+ char *repository;
+
+ repository = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSNULLREPOS);
+ if (!isfile (repository))
+ {
+ mode_t omask;
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (repository, 0777) < 0)
+ error (1, errno, "cannot create %s", repository);
+ (void) umask (omask);
+ }
+ return repository;
+}
+
+
+
+/* Build all the dirs along the path to DIRS with CVS subdirs with appropriate
+ * repositories. If DIRS->repository is NULL or the directory already exists,
+ * do not create a CVSADM directory for that subdirectory; just CVS_CHDIR into
+ * it. Frees all storage used by DIRS.
+ *
+ * ASSUMPTIONS
+ * 1. Parent directories will be listed in DIRS before their children.
+ * 2. At most a single directory will need to be changed at one time. In
+ * other words, if we are in /a/b/c, and our final destination is
+ * /a/b/c/d/e/f, then we will build d, then d/e, then d/e/f.
+ *
+ * INPUTS
+ * dirs Simple list composed of dir_to_build structures, listing
+ * information about directories to build.
+ * sticky Passed to build_one_dir to tell it whether there are any sticky
+ * tags or dates to be concerned with.
+ *
+ * RETURNS
+ * 1 on error, 0 otherwise.
+ *
+ * ERRORS
+ * The only nonfatal error this function may return is if the CHDIR fails.
+ */
+static int
+build_dirs_and_chdir (struct dir_to_build *dirs, int sticky)
+{
+ int retval = 0;
+ struct dir_to_build *nextdir;
+
+ while (dirs != NULL)
+ {
+ const char *dir = last_component (dirs->dirpath);
+ int made_dir = 0;
+
+ made_dir = !mkdir_if_needed (dir);
+ if (made_dir) Subdir_Register (NULL, NULL, dir);
+
+ if (CVS_CHDIR (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", dir);
+ retval = 1;
+ goto out;
+ }
+ if (dirs->repository != NULL)
+ {
+ if (made_dir)
+ build_one_dir (dirs->repository, dirs->dirpath, sticky);
+ free (dirs->repository);
+ }
+ nextdir = dirs->next;
+ free (dirs->dirpath);
+ free (dirs);
+ dirs = nextdir;
+ }
+
+ out:
+ while (dirs != NULL)
+ {
+ if (dirs->repository != NULL)
+ free (dirs->repository);
+ nextdir = dirs->next;
+ free (dirs->dirpath);
+ free (dirs);
+ dirs = nextdir;
+ }
+ return retval;
+}
diff --git a/src/classify.c b/src/classify.c
new file mode 100644
index 0000000..320cf4f
--- /dev/null
+++ b/src/classify.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ */
+
+#include "cvs.h"
+
+static void sticky_ck (struct file_info *finfo, int aflag,
+ Vers_TS * vers);
+
+/*
+ * Classify the state of a file.
+ *
+ * INPUTS
+ * finfo Information about the file to be classified.
+ * tag
+ * date
+ * options Keyword expansion options. Can be either NULL or "" to
+ * indicate none are specified here.
+ * force_tag_match
+ * aflag
+ * versp
+ * pipeout Did the user pass the "pipeout" flag to request that
+ * all output go to STDOUT rather than to a file or files?
+ *
+ * RETURNS
+ * A Ctype (defined as an enum) describing the state of the file relative to
+ * the repository. See the definition of Ctype for more.
+ */
+Ctype
+Classify_File (struct file_info *finfo, char *tag, char *date, char *options,
+ int force_tag_match, int aflag, Vers_TS **versp, int pipeout)
+{
+ Vers_TS *vers;
+ Ctype ret;
+
+ /* get all kinds of good data about the file */
+ vers = Version_TS (finfo, options, tag, date,
+ force_tag_match, 0);
+
+ if (vers->vn_user == NULL)
+ {
+ /* No entry available, ts_rcs is invalid */
+ if (vers->vn_rcs == NULL)
+ {
+ /* there is no RCS file either */
+ if (vers->ts_user == NULL)
+ {
+ /* there is no user file */
+ /* FIXME: Why do we skip this message if vers->tag or
+ vers->date is set? It causes "cvs update -r tag98 foo"
+ to silently do nothing, which is seriously confusing
+ behavior. "cvs update foo" gives this message, which
+ is what I would expect. */
+ if (!force_tag_match || !(vers->tag || vers->date))
+ if (!really_quiet)
+ error (0, 0, "nothing known about `%s'",
+ finfo->fullname);
+ ret = T_UNKNOWN;
+ }
+ else
+ {
+ /* there is a user file */
+ /* FIXME: Why do we skip this message if vers->tag or
+ vers->date is set? It causes "cvs update -r tag98 foo"
+ to silently do nothing, which is seriously confusing
+ behavior. "cvs update foo" gives this message, which
+ is what I would expect. */
+ if (!force_tag_match || !(vers->tag || vers->date))
+ if (!really_quiet)
+ error (0, 0, "use `%s add' to create an entry for `%s'",
+ program_name, finfo->fullname);
+ ret = T_UNKNOWN;
+ }
+ }
+ else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
+ {
+ /* there is an RCS file, but it's dead */
+ if (vers->ts_user == NULL)
+ ret = T_UPTODATE;
+ else
+ {
+ error (0, 0, "use `%s add' to create an entry for `%s'",
+ program_name, finfo->fullname);
+ ret = T_UNKNOWN;
+ }
+ }
+ else if (!pipeout && vers->ts_user && No_Difference (finfo, vers))
+ {
+ /* the files were different so it is a conflict */
+ if (!really_quiet)
+ error (0, 0, "move away `%s'; it is in the way",
+ finfo->fullname);
+ ret = T_CONFLICT;
+ }
+ else
+ /* no user file or no difference, just checkout */
+ ret = T_CHECKOUT;
+ }
+ else if (strcmp (vers->vn_user, "0") == 0)
+ {
+ /* An entry for a new-born file; ts_rcs is dummy */
+
+ if (vers->ts_user == NULL)
+ {
+ if (pipeout)
+ {
+ ret = T_CHECKOUT;
+ }
+ else
+ {
+ /*
+ * There is no user file, but there should be one; remove the
+ * entry
+ */
+ if (!really_quiet)
+ error (0, 0, "warning: new-born `%s' has disappeared",
+ finfo->fullname);
+ ret = T_REMOVE_ENTRY;
+ }
+ }
+ else if (vers->vn_rcs == NULL ||
+ RCS_isdead (vers->srcfile, vers->vn_rcs))
+ /* No RCS file or RCS file revision is dead */
+ ret = T_ADDED;
+ else
+ {
+ if (pipeout)
+ {
+ ret = T_CHECKOUT;
+ }
+ else
+ {
+ if (vers->srcfile->flags & INATTIC
+ && vers->srcfile->flags & VALID)
+ {
+ /* This file has been added on some branch other than
+ the one we are looking at. In the branch we are
+ looking at, the file was already valid. */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: `%s' has been added, but already exists",
+ finfo->fullname);
+ }
+ else
+ {
+ /*
+ * There is an RCS file, so someone else must have checked
+ * one in behind our back; conflict
+ */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: `%s' created independently by"
+ " second party",
+ finfo->fullname);
+ }
+ ret = T_CONFLICT;
+ }
+ }
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ /* An entry for a removed file, ts_rcs is invalid */
+
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file (as it should be) */
+
+ if (vers->vn_rcs == NULL
+ || RCS_isdead (vers->srcfile, vers->vn_rcs))
+ {
+
+ /*
+ * There is no RCS file; this is all-right, but it has been
+ * removed independently by a second party; remove the entry
+ */
+ ret = T_REMOVE_ENTRY;
+ }
+ else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
+ /*
+ * The RCS file is the same version as the user file was, and
+ * that's OK; remove it
+ */
+ ret = T_REMOVED;
+ else if (pipeout)
+ /*
+ * The RCS file doesn't match the user's file, but it doesn't
+ * matter in this case
+ */
+ ret = T_NEEDS_MERGE;
+ else
+ {
+
+ /*
+ * The RCS file is a newer version than the removed user file
+ * and this is definitely not OK; make it a conflict.
+ */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: removed `%s' was modified by"
+ " second party",
+ finfo->fullname);
+ ret = T_CONFLICT;
+ }
+ }
+ else
+ {
+ /* The user file shouldn't be there */
+ if (!really_quiet)
+ error (0, 0, "`%s' should be removed and is still there",
+ finfo->fullname);
+ ret = T_REMOVED;
+ }
+ }
+ else
+ {
+ /* A normal entry, TS_Rcs is valid */
+ if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
+ {
+ /* There is no RCS file */
+
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file, so just remove the entry */
+ if (!really_quiet)
+ error (0, 0, "warning: `%s' is not (any longer) pertinent",
+ finfo->fullname);
+ ret = T_REMOVE_ENTRY;
+ }
+ else if (strcmp (vers->ts_user, vers->ts_rcs)
+ && No_Difference (finfo, vers))
+ {
+ /* they are different -> conflict */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: `%s' is modified but no longer in the"
+ " repository",
+ finfo->fullname);
+ ret = T_CONFLICT;
+ }
+ else
+ {
+
+ /*
+ * The user file is still unmodified, so just remove it from
+ * the entry list
+ */
+ if (!really_quiet)
+ error (0, 0, "`%s' is no longer in the repository",
+ finfo->fullname);
+ ret = T_REMOVE_ENTRY;
+ }
+ }
+ else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
+ {
+ /* The RCS file is the same version as the user file */
+
+ if (vers->ts_user == NULL)
+ {
+
+ /*
+ * There is no user file, so note that it was lost and
+ * extract a new version
+ */
+ /* Comparing the cvs_cmd_name against "update", in
+ addition to being an ugly way to operate, means
+ that this message does not get printed by the
+ server. That might be considered just a straight
+ bug, although there is one subtlety: that case also
+ gets hit when a patch fails and the client fetches
+ a file. I'm not sure there is currently any way
+ for the server to distinguish those two cases. */
+ if (strcmp (cvs_cmd_name, "update") == 0)
+ if (!really_quiet)
+ error (0, 0, "warning: `%s' was lost", finfo->fullname);
+ ret = T_CHECKOUT;
+ }
+ else if (!strcmp (vers->ts_user,
+ vers->ts_conflict
+ ? vers->ts_conflict : vers->ts_rcs))
+ {
+
+ /*
+ * The user file is still unmodified, so nothing special at
+ * all to do -- no lists updated, unless the sticky -k option
+ * has changed. If the sticky tag has changed, we just need
+ * to re-register the entry
+ */
+ /* TODO: decide whether we need to check file permissions
+ for a mismatch, and return T_CONFLICT if so. */
+ if (vers->entdata->options &&
+ strcmp (vers->entdata->options, vers->options) != 0)
+ ret = T_CHECKOUT;
+ else if (vers->ts_conflict)
+ ret = T_CONFLICT;
+ else
+ {
+ sticky_ck (finfo, aflag, vers);
+ ret = T_UPTODATE;
+ }
+ }
+ else if (No_Difference (finfo, vers))
+ {
+
+ /*
+ * they really are different; modified if we aren't
+ * changing any sticky -k options, else needs merge
+ */
+#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
+ if (strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options) == 0)
+ ret = T_MODIFIED;
+ else
+ ret = T_NEEDS_MERGE;
+#else
+ /* Files with conflict markers and new timestamps fall through
+ * here, but they need to. T_CONFLICT is an error in
+ * commit_fileproc, whereas T_MODIFIED with conflict markers
+ * is caught but only warned about. Similarly, update_fileproc
+ * currently reregisters a file that was conflicted but lost
+ * its markers.
+ */
+ ret = T_MODIFIED;
+ sticky_ck (finfo, aflag, vers);
+#endif
+ }
+ else if (strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options) != 0)
+ {
+ /* file has not changed; check out if -k changed */
+ ret = T_CHECKOUT;
+ }
+ else
+ {
+
+ /*
+ * else -> note that No_Difference will Register the
+ * file already for us, using the new tag/date. This
+ * is the desired behaviour
+ */
+ ret = T_UPTODATE;
+ }
+ }
+ else
+ {
+ /* The RCS file is a newer version than the user file */
+
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file, so just get it */
+
+ /* See comment at other "update" compare, for more
+ thoughts on this comparison. */
+ if (strcmp (cvs_cmd_name, "update") == 0)
+ if (!really_quiet)
+ error (0, 0, "warning: `%s' was lost", finfo->fullname);
+ ret = T_CHECKOUT;
+ }
+ else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
+ {
+
+ /*
+ * The user file is still unmodified, so just get it as well
+ */
+ if (strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options) != 0
+ || (vers->srcfile != NULL
+ && (vers->srcfile->flags & INATTIC) != 0))
+ ret = T_CHECKOUT;
+ else
+ ret = T_PATCH;
+ }
+ else if (No_Difference (finfo, vers))
+ /* really modified, needs to merge */
+ ret = T_NEEDS_MERGE;
+ else if ((strcmp (vers->entdata->options ?
+ vers->entdata->options : "", vers->options)
+ != 0)
+ || (vers->srcfile != NULL
+ && (vers->srcfile->flags & INATTIC) != 0))
+ /* not really modified, check it out */
+ ret = T_CHECKOUT;
+ else
+ ret = T_PATCH;
+ }
+ }
+
+ /* free up the vers struct, or just return it */
+ if (versp != NULL)
+ *versp = vers;
+ else
+ freevers_ts (&vers);
+
+ /* return the status of the file */
+ return (ret);
+}
+
+static void
+sticky_ck (struct file_info *finfo, int aflag, Vers_TS *vers)
+{
+ if (aflag || vers->tag || vers->date)
+ {
+ char *enttag = vers->entdata->tag;
+ char *entdate = vers->entdata->date;
+
+ if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
+ ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
+ (entdate && vers->date && strcmp (entdate, vers->date)) ||
+ ((entdate && !vers->date) || (!entdate && vers->date)))
+ {
+ Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
+ vers->options, vers->tag, vers->date, vers->ts_conflict);
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* We need to update the entries line on the client side.
+ It is possible we will later update it again via
+ server_updated or some such, but that is OK. */
+ server_update_entries
+ (finfo->file, finfo->update_dir, finfo->repository,
+ strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
+ SERVER_UPDATED : SERVER_MERGED);
+ }
+#endif
+ }
+ }
+}
diff --git a/src/client.c b/src/client.c
new file mode 100644
index 0000000..751406b
--- /dev/null
+++ b/src/client.c
@@ -0,0 +1,5180 @@
+/* CVS client-related stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "cvs.h"
+#include "getline.h"
+#include "edit.h"
+#include "buffer.h"
+#include "save-cwd.h"
+
+#ifdef CLIENT_SUPPORT
+
+# include "log-buffer.h"
+# include "md5.h"
+
+#include "socket-client.h"
+#include "rsh-client.h"
+
+# ifdef HAVE_GSSAPI
+# include "gssapi-client.h"
+# endif
+
+# ifdef HAVE_KERBEROS
+# include "kerberos4-client.h"
+# endif
+
+
+
+/* Keep track of any paths we are sending for Max-dotdot so that we can verify
+ * that uplevel paths coming back form the server are valid.
+ *
+ * FIXME: The correct way to do this is probably provide some sort of virtual
+ * path map on the client side. This would be generic enough to be applied to
+ * absolute paths supplied by the user too.
+ */
+static List *uppaths;
+
+
+
+static void add_prune_candidate (const char *);
+
+/* All the commands. */
+int add (int argc, char **argv);
+int admin (int argc, char **argv);
+int checkout (int argc, char **argv);
+int commit (int argc, char **argv);
+int diff (int argc, char **argv);
+int history (int argc, char **argv);
+int import (int argc, char **argv);
+int cvslog (int argc, char **argv);
+int patch (int argc, char **argv);
+int release (int argc, char **argv);
+int cvsremove (int argc, char **argv);
+int rtag (int argc, char **argv);
+int status (int argc, char **argv);
+int tag (int argc, char **argv);
+int update (int argc, char **argv);
+
+static size_t try_read_from_server (char *, size_t);
+
+static void auth_server (cvsroot_t *, struct buffer *, struct buffer *,
+ int, int, struct hostent *);
+
+
+
+/* This is the referrer who referred us to a primary, or write server, using
+ * the "Redirect" request.
+ */
+static cvsroot_t *client_referrer;
+
+/* We need to keep track of the list of directories we've sent to the
+ server. This list, along with the current CVSROOT, will help us
+ decide which command-line arguments to send. */
+List *dirs_sent_to_server;
+static int
+is_arg_a_parent_or_listed_dir (Node *n, void *d)
+{
+ char *directory = n->key; /* name of the dir sent to server */
+ char *this_argv_elem = d; /* this argv element */
+
+ /* Say we should send this argument if the argument matches the
+ beginning of a directory name sent to the server. This way,
+ the server will know to start at the top of that directory
+ hierarchy and descend. */
+
+ if (!strncmp (directory, this_argv_elem, strlen (this_argv_elem)))
+ return 1;
+
+ return 0;
+}
+
+
+
+/* Return nonzero if this argument should not be sent to the
+ server. */
+static int
+arg_should_not_be_sent_to_server (char *arg)
+{
+ /* Decide if we should send this directory name to the server. We
+ should always send argv[i] if:
+
+ 1) the list of directories sent to the server is empty (as it
+ will be for checkout, etc.).
+
+ 2) the argument is "."
+
+ 3) the argument is a file in the cwd and the cwd is checked out
+ from the current root
+
+ 4) the argument lies within one of the paths in
+ dirs_sent_to_server.
+
+ */
+
+ if (list_isempty (dirs_sent_to_server))
+ return 0; /* always send it */
+
+ if (!strcmp (arg, "."))
+ return 0; /* always send it */
+
+ /* We should send arg if it is one of the directories sent to the
+ server or the parent of one; this tells the server to descend
+ the hierarchy starting at this level. */
+ if (isdir (arg))
+ {
+ if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, arg))
+ return 0;
+
+ /* If arg wasn't a parent, we don't know anything about it (we
+ would have seen something related to it during the
+ send_files phase). Don't send it. */
+ return 1;
+ }
+
+ /* Try to decide whether we should send arg to the server by
+ checking the contents of the corresponding CVSADM directory. */
+ {
+ char *t, *root_string;
+ cvsroot_t *this_root = NULL;
+
+ /* Calculate "dirname arg" */
+ for (t = arg + strlen (arg) - 1; t >= arg; t--)
+ {
+ if (ISSLASH (*t))
+ break;
+ }
+
+ /* Now we're either poiting to the beginning of the
+ string, or we found a path separator. */
+ if (t >= arg)
+ {
+ /* Found a path separator. */
+ char c = *t;
+ *t = '\0';
+
+ /* First, check to see if we sent this directory to the
+ server, because it takes less time than actually
+ opening the stuff in the CVSADM directory. */
+ if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir,
+ arg))
+ {
+ *t = c; /* make sure to un-truncate the arg */
+ return 0;
+ }
+
+ /* Since we didn't find it in the list, check the CVSADM
+ files on disk. */
+ this_root = Name_Root (arg, NULL);
+ root_string = this_root->original;
+ *t = c;
+ }
+ else
+ {
+ /* We're at the beginning of the string. Look at the
+ CVSADM files in cwd. */
+ if (CVSroot_cmdline)
+ root_string = CVSroot_cmdline;
+ else
+ {
+ this_root = Name_Root (NULL, NULL);
+ root_string = this_root->original;
+ }
+ }
+
+ /* Now check the value for root. */
+ if (root_string && current_parsed_root
+ && strcmp (root_string, original_parsed_root->original))
+ {
+ /* Don't send this, since the CVSROOTs don't match. */
+ return 1;
+ }
+ }
+
+ /* OK, let's send it. */
+ return 0;
+}
+#endif /* CLIENT_SUPPORT */
+
+
+
+#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
+
+/* Shared with server. */
+
+/*
+ * Return a malloc'd, '\0'-terminated string
+ * corresponding to the mode in SB.
+ */
+char *
+mode_to_string (mode_t mode)
+{
+ char u[4], g[4], o[4];
+ int i;
+
+ i = 0;
+ if (mode & S_IRUSR) u[i++] = 'r';
+ if (mode & S_IWUSR) u[i++] = 'w';
+ if (mode & S_IXUSR) u[i++] = 'x';
+ u[i] = '\0';
+
+ i = 0;
+ if (mode & S_IRGRP) g[i++] = 'r';
+ if (mode & S_IWGRP) g[i++] = 'w';
+ if (mode & S_IXGRP) g[i++] = 'x';
+ g[i] = '\0';
+
+ i = 0;
+ if (mode & S_IROTH) o[i++] = 'r';
+ if (mode & S_IWOTH) o[i++] = 'w';
+ if (mode & S_IXOTH) o[i++] = 'x';
+ o[i] = '\0';
+
+ return Xasprintf ("u=%s,g=%s,o=%s", u, g, o);
+}
+
+
+
+/*
+ * Change mode of FILENAME to MODE_STRING.
+ * Returns 0 for success or errno code.
+ * If RESPECT_UMASK is set, then honor the umask.
+ */
+int
+change_mode (const char *filename, const char *mode_string, int respect_umask)
+{
+#ifdef CHMOD_BROKEN
+ char *p;
+ int writeable = 0;
+
+ /* We can only distinguish between
+ 1) readable
+ 2) writeable
+ 3) Picasso's "Blue Period"
+ We handle the first two. */
+ p = mode_string;
+ while (*p != '\0')
+ {
+ if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=')
+ {
+ char *q = p + 2;
+ while (*q != ',' && *q != '\0')
+ {
+ if (*q == 'w')
+ writeable = 1;
+ ++q;
+ }
+ }
+ /* Skip to the next field. */
+ while (*p != ',' && *p != '\0')
+ ++p;
+ if (*p == ',')
+ ++p;
+ }
+
+ /* xchmod honors the umask for us. In the !respect_umask case, we
+ don't try to cope with it (probably to handle that well, the server
+ needs to deal with modes in data structures, rather than via the
+ modes in temporary files). */
+ xchmod (filename, writeable);
+ return 0;
+
+#else /* ! CHMOD_BROKEN */
+
+ const char *p;
+ mode_t mode = 0;
+ mode_t oumask;
+
+ p = mode_string;
+ while (*p != '\0')
+ {
+ if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=')
+ {
+ int can_read = 0, can_write = 0, can_execute = 0;
+ const char *q = p + 2;
+ while (*q != ',' && *q != '\0')
+ {
+ if (*q == 'r')
+ can_read = 1;
+ else if (*q == 'w')
+ can_write = 1;
+ else if (*q == 'x')
+ can_execute = 1;
+ ++q;
+ }
+ if (p[0] == 'u')
+ {
+ if (can_read)
+ mode |= S_IRUSR;
+ if (can_write)
+ mode |= S_IWUSR;
+ if (can_execute)
+ mode |= S_IXUSR;
+ }
+ else if (p[0] == 'g')
+ {
+ if (can_read)
+ mode |= S_IRGRP;
+ if (can_write)
+ mode |= S_IWGRP;
+ if (can_execute)
+ mode |= S_IXGRP;
+ }
+ else if (p[0] == 'o')
+ {
+ if (can_read)
+ mode |= S_IROTH;
+ if (can_write)
+ mode |= S_IWOTH;
+ if (can_execute)
+ mode |= S_IXOTH;
+ }
+ }
+ /* Skip to the next field. */
+ while (*p != ',' && *p != '\0')
+ ++p;
+ if (*p == ',')
+ ++p;
+ }
+
+ if (respect_umask)
+ {
+ oumask = umask (0);
+ (void) umask (oumask);
+ mode &= ~oumask;
+ }
+
+ if (chmod (filename, mode) < 0)
+ return errno;
+ return 0;
+#endif /* ! CHMOD_BROKEN */
+}
+#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
+
+
+
+#ifdef CLIENT_SUPPORT
+int client_prune_dirs;
+
+static List *ignlist = NULL;
+
+/* Buffer to write to the server. */
+static struct buffer *global_to_server;
+
+/* Buffer used to read from the server. */
+static struct buffer *global_from_server;
+
+
+
+/*
+ * Read a line from the server. Result does not include the terminating \n.
+ *
+ * Space for the result is malloc'd and should be freed by the caller.
+ *
+ * Returns number of bytes read.
+ */
+static size_t
+read_line_via (struct buffer *via_from_buffer, struct buffer *via_to_buffer,
+ char **resultp)
+{
+ int status;
+ char *result;
+ size_t len;
+
+ status = buf_flush (via_to_buffer, 1);
+ if (status != 0)
+ error (1, status, "writing to server");
+
+ status = buf_read_line (via_from_buffer, &result, &len);
+ if (status != 0)
+ {
+ if (status == -1)
+ error (1, 0,
+ "end of file from server (consult above messages if any)");
+ else if (status == -2)
+ error (1, 0, "out of memory");
+ else
+ error (1, status, "reading from server");
+ }
+
+ if (resultp)
+ *resultp = result;
+ else
+ free (result);
+
+ return len;
+}
+
+
+
+static size_t
+read_line (char **resultp)
+{
+ return read_line_via (global_from_server, global_to_server, resultp);
+}
+#endif /* CLIENT_SUPPORT */
+
+
+
+#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
+/*
+ * Zero if compression isn't supported or requested; non-zero to indicate
+ * a compression level to request from gzip.
+ */
+int gzip_level;
+
+/*
+ * Level of compression to use when running gzip on a single file.
+ */
+int file_gzip_level;
+
+#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
+
+#ifdef CLIENT_SUPPORT
+
+/* Whether the server asked us to force compression. */
+static bool force_gzip;
+
+/*
+ * The Repository for the top level of this command (not necessarily
+ * the CVSROOT, just the current directory at the time we do it).
+ */
+static char *toplevel_repos;
+
+/* Working directory when we first started. Note: we could speed things
+ up on some systems by using savecwd.h here instead of just always
+ storing a name. */
+char *toplevel_wd;
+
+
+
+static void
+handle_ok (char *args, size_t len)
+{
+ return;
+}
+
+
+
+static void
+handle_error (char *args, size_t len)
+{
+ int something_printed;
+
+ /*
+ * First there is a symbolic error code followed by a space, which
+ * we ignore.
+ */
+ char *p = strchr (args, ' ');
+ if (!p)
+ {
+ error (0, 0, "invalid data from cvs server");
+ return;
+ }
+ ++p;
+
+ /* Next we print the text of the message from the server. We
+ probably should be prefixing it with "server error" or some
+ such, because if it is something like "Out of memory", the
+ current behavior doesn't say which machine is out of
+ memory. */
+
+ len -= p - args;
+ something_printed = 0;
+ for (; len > 0; --len)
+ {
+ something_printed = 1;
+ putc (*p++, stderr);
+ }
+ if (something_printed)
+ putc ('\n', stderr);
+}
+
+
+
+static void
+handle_valid_requests (char *args, size_t len)
+{
+ char *p = args;
+ char *q;
+ struct request *rq;
+ do
+ {
+ q = strchr (p, ' ');
+ if (q)
+ *q++ = '\0';
+ for (rq = requests; rq->name; ++rq)
+ {
+ if (!strcmp (rq->name, p))
+ break;
+ }
+ if (!rq->name)
+ /*
+ * It is a request we have never heard of (and thus never
+ * will want to use). So don't worry about it.
+ */
+ ;
+ else
+ {
+ if (rq->flags & RQ_ENABLEME)
+ {
+ /*
+ * Server wants to know if we have this, to enable the
+ * feature.
+ */
+ send_to_server (rq->name, 0);
+ send_to_server ("\012", 0);
+ }
+ else
+ rq->flags |= RQ_SUPPORTED;
+ }
+ p = q;
+ } while (q);
+ for (rq = requests; rq->name; ++rq)
+ {
+ if ((rq->flags & RQ_SUPPORTED)
+ || (rq->flags & RQ_ENABLEME))
+ continue;
+ if (rq->flags & RQ_ESSENTIAL)
+ error (1, 0, "request `%s' not supported by server", rq->name);
+ }
+}
+
+static void
+handle_force_gzip (char *args, size_t len)
+{
+ force_gzip = true;
+}
+
+
+
+/* Has the server told us its name since the last redirect?
+ */
+static bool referred_since_last_redirect = false;
+static bool free_client_referrer = false;
+
+
+
+static void
+handle_referrer (char *args, size_t len)
+{
+ TRACE (TRACE_FUNCTION, "handle_referrer (%s)", args);
+ client_referrer = parse_cvsroot (args);
+ referred_since_last_redirect = true;
+ free_client_referrer = true;
+}
+
+
+
+/* Redirect our connection to a different server and start over.
+ *
+ * GLOBALS
+ * current_parsed_root The CVSROOT being accessed.
+ * client_referrer Used to track the server which referred us to a
+ * new server. Can be supplied by the referring
+ * server.
+ * free_client_referrer Used to track whether the client_referrer needs
+ * to be freed before changing it.
+ * referred_since_last_redirect
+ * Tracks whether the currect server told us how
+ * to refer to it.
+ *
+ * OUTPUTS
+ * current_parsed_root Updated to point to the new CVSROOT.
+ * referred_since_last_redirect
+ * Always cleared.
+ * client_referrer Set automatically to current_parsed_root if
+ * the current server did not give us a name to
+ * refer to it by.
+ * free_client_referrer Reset when necessary.
+ */
+static void
+handle_redirect (char *args, size_t len)
+{
+ static List *redirects = NULL;
+
+ TRACE (TRACE_FUNCTION, "handle_redirect (%s)", args);
+
+ if (redirects && findnode (redirects, args))
+ error (1, 0, "`Redirect' loop detected. Server misconfiguration?");
+ else
+ {
+ if (!redirects) redirects = getlist();
+ push_string (redirects, args);
+ }
+
+ if (referred_since_last_redirect)
+ referred_since_last_redirect = false;
+ else
+ {
+ if (free_client_referrer) free (client_referrer);
+ client_referrer = current_parsed_root;
+ free_client_referrer = false;
+ }
+
+ current_parsed_root = parse_cvsroot (args);
+
+ /* We deliberately do not set ORIGINAL_PARSED_ROOT here.
+ * ORIGINAL_PARSED_ROOT is used by the client to determine the current root
+ * being processed for the purpose of looking it up in lists and such, even
+ * after a redirect.
+ *
+ * FIXME
+ * CURRENT_PARSED_ROOT should not be reset by this function. Redirects
+ * should be "added" to it. The REDIRECTS list should also be replaced
+ * by this new CURRENT_PARSED_ROOT element. This way, if, for instance,
+ * a multi-root workspace had two secondaries pointing to the same
+ * primary, then the client would not report a looping error.
+ *
+ * There is also a potential memory leak above and storing new roots as
+ * part of the original could help avoid it fairly elegantly.
+ */
+ if (!current_parsed_root)
+ error (1, 0, "Server requested redirect to invalid root: `%s'",
+ args);
+}
+
+
+
+/*
+ * This is a proc for walklist(). It inverts the error return premise of
+ * walklist.
+ *
+ * RETURNS
+ * True If this path is prefixed by one of the paths in walklist and
+ * does not step above the prefix path.
+ * False Otherwise.
+ */
+static
+int path_list_prefixed (Node *p, void *closure)
+{
+ const char *questionable = closure;
+ const char *prefix = p->key;
+ if (strncmp (prefix, questionable, strlen (prefix))) return 0;
+ questionable += strlen (prefix);
+ while (ISSLASH (*questionable)) questionable++;
+ if (*questionable == '\0') return 1;
+ return pathname_levels (questionable);
+}
+
+
+
+/*
+ * Need to validate the client pathname. Disallowed paths include:
+ *
+ * 1. Absolute paths.
+ * 2. Pathnames that do not reference a specifically requested update
+ * directory.
+ *
+ * In case 2, we actually only check that the directory is under the uppermost
+ * directories mentioned on the command line.
+ *
+ * RETURNS
+ * True If the path is valid.
+ * False Otherwise.
+ */
+static
+int is_valid_client_path (const char *pathname)
+{
+ /* 1. Absolute paths. */
+ if (ISABSOLUTE (pathname)) return 0;
+ /* 2. No up-references in path. */
+ if (pathname_levels (pathname) == 0) return 1;
+ /* 2. No Max-dotdot paths registered. */
+ if (!uppaths) return 0;
+
+ return walklist (uppaths, path_list_prefixed, (void *)pathname);
+}
+
+
+
+/*
+ * Do all the processing for PATHNAME, where pathname consists of the
+ * repository and the filename. The parameters we pass to FUNC are:
+ * DATA is just the DATA parameter which was passed to
+ * call_in_directory; ENT_LIST is a pointer to an entries list (which
+ * we manage the storage for); SHORT_PATHNAME is the pathname of the
+ * file relative to the (overall) directory in which the command is
+ * taking place; and FILENAME is the filename portion only of
+ * SHORT_PATHNAME. When we call FUNC, the curent directory points to
+ * the directory portion of SHORT_PATHNAME. */
+static void
+call_in_directory (const char *pathname,
+ void (*func) (void *, List *, const char *, const char *),
+ void *data)
+{
+ /* This variable holds the result of Entries_Open. */
+ List *last_entries = NULL;
+ char *dir_name;
+ char *filename;
+ /* This is what we get when we hook up the directory (working directory
+ name) from PATHNAME with the filename from REPOSNAME. For example:
+ pathname: ccvs/src/
+ reposname: /u/src/master/ccvs/foo/ChangeLog
+ short_pathname: ccvs/src/ChangeLog
+ */
+ char *short_pathname;
+ char *p;
+
+ /*
+ * Do the whole descent in parallel for the repositories, so we
+ * know what to put in CVS/Repository files. I'm not sure the
+ * full hair is necessary since the server does a similar
+ * computation; I suspect that we only end up creating one
+ * directory at a time anyway.
+ *
+ * Also note that we must *only* worry about this stuff when we
+ * are creating directories; `cvs co foo/bar; cd foo/bar; cvs co
+ * CVSROOT; cvs update' is legitimate, but in this case
+ * foo/bar/CVSROOT/CVS/Repository is not a subdirectory of
+ * foo/bar/CVS/Repository.
+ */
+ char *reposname;
+ char *short_repos;
+ char *reposdirname;
+ char *rdirp;
+ int reposdirname_absolute;
+ int newdir = 0;
+
+ assert (pathname);
+
+ reposname = NULL;
+ read_line (&reposname);
+ assert (reposname);
+
+ reposdirname_absolute = 0;
+ if (strncmp (reposname, toplevel_repos, strlen (toplevel_repos)))
+ {
+ reposdirname_absolute = 1;
+ short_repos = reposname;
+ }
+ else
+ {
+ short_repos = reposname + strlen (toplevel_repos) + 1;
+ if (short_repos[-1] != '/')
+ {
+ reposdirname_absolute = 1;
+ short_repos = reposname;
+ }
+ }
+
+ /* Now that we have SHORT_REPOS, we can calculate the path to the file we
+ * are being requested to operate on.
+ */
+ filename = strrchr (short_repos, '/');
+ if (!filename)
+ filename = short_repos;
+ else
+ ++filename;
+
+ short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5);
+ strcpy (short_pathname, pathname);
+ strcat (short_pathname, filename);
+
+ /* Now that we know the path to the file we were requested to operate on,
+ * we can verify that it is valid.
+ *
+ * For security reasons, if SHORT_PATHNAME is absolute or attempts to
+ * ascend outside of the current sanbbox, we abort. The server should not
+ * send us anything but relative paths which remain inside the sandbox
+ * here. Anything less means a trojan CVS server could create and edit
+ * arbitrary files on the client.
+ */
+ if (!is_valid_client_path (short_pathname))
+ {
+ error (0, 0,
+ "Server attempted to update a file via an invalid pathname:");
+ error (1, 0, "`%s'.", short_pathname);
+ }
+
+ reposdirname = xstrdup (short_repos);
+ p = strrchr (reposdirname, '/');
+ if (!p)
+ {
+ reposdirname = xrealloc (reposdirname, 2);
+ reposdirname[0] = '.'; reposdirname[1] = '\0';
+ }
+ else
+ *p = '\0';
+
+ dir_name = xstrdup (pathname);
+ p = strrchr (dir_name, '/');
+ if (!p)
+ {
+ dir_name = xrealloc (dir_name, 2);
+ dir_name[0] = '.'; dir_name[1] = '\0';
+ }
+ else
+ *p = '\0';
+ if (client_prune_dirs)
+ add_prune_candidate (dir_name);
+
+ if (!toplevel_wd)
+ {
+ toplevel_wd = xgetcwd ();
+ if (!toplevel_wd)
+ error (1, errno, "could not get working directory");
+ }
+
+ if (CVS_CHDIR (toplevel_wd) < 0)
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+
+ /* Create the CVS directory at the top level if needed. The
+ isdir seems like an unneeded system call, but it *does*
+ need to be called both if the CVS_CHDIR below succeeds
+ (e.g. "cvs co .") or if it fails (e.g. basicb-1a in
+ testsuite). We only need to do this for the "." case,
+ since the server takes care of forcing this directory to be
+ created in all other cases. If we don't create CVSADM
+ here, the call to Entries_Open below will fail. FIXME:
+ perhaps this means that we should change our algorithm
+ below that calls Create_Admin instead of having this code
+ here? */
+ if (/* I think the reposdirname_absolute case has to do with
+ things like "cvs update /foo/bar". In any event, the
+ code below which tries to put toplevel_repos into
+ CVS/Repository is almost surely unsuited to
+ the reposdirname_absolute case. */
+ !reposdirname_absolute
+ && !strcmp (dir_name, ".")
+ && ! isdir (CVSADM))
+ {
+ char *repo;
+ char *r;
+
+ newdir = 1;
+
+ /* If toplevel_repos doesn't have at least one character, then the
+ * reference to r[-1] below could be out of bounds.
+ */
+ assert (*toplevel_repos);
+
+ repo = xmalloc (strlen (toplevel_repos)
+ + 10);
+ strcpy (repo, toplevel_repos);
+ r = repo + strlen (repo);
+ if (r[-1] != '.' || r[-2] != '/')
+ strcpy (r, "/.");
+
+ Create_Admin (".", ".", repo, NULL, NULL, 0, 1, 1);
+
+ free (repo);
+ }
+
+ if (CVS_CHDIR (dir_name) < 0)
+ {
+ char *dir;
+ char *dirp;
+
+ if (! existence_error (errno))
+ error (1, errno, "could not chdir to %s", dir_name);
+
+ /* Directory does not exist, we need to create it. */
+ newdir = 1;
+
+ /* Provided we are willing to assume that directories get
+ created one at a time, we could simplify this a lot.
+ Do note that one aspect still would need to walk the
+ dir_name path: the checking for "fncmp (dir, CVSADM)". */
+
+ dir = xmalloc (strlen (dir_name) + 1);
+ dirp = dir_name;
+ rdirp = reposdirname;
+
+ /* This algorithm makes nested directories one at a time
+ and create CVS administration files in them. For
+ example, we're checking out foo/bar/baz from the
+ repository:
+
+ 1) create foo, point CVS/Repository to <root>/foo
+ 2) .. foo/bar .. <root>/foo/bar
+ 3) .. foo/bar/baz .. <root>/foo/bar/baz
+
+ As you can see, we're just stepping along DIR_NAME (with
+ DIRP) and REPOSDIRNAME (with RDIRP) respectively.
+
+ We need to be careful when we are checking out a
+ module, however, since DIR_NAME and REPOSDIRNAME are not
+ going to be the same. Since modules will not have any
+ slashes in their names, we should watch the output of
+ STRCHR to decide whether or not we should use STRCHR on
+ the RDIRP. That is, if we're down to a module name,
+ don't keep picking apart the repository directory name. */
+
+ do
+ {
+ dirp = strchr (dirp, '/');
+ if (dirp)
+ {
+ strncpy (dir, dir_name, dirp - dir_name);
+ dir[dirp - dir_name] = '\0';
+ /* Skip the slash. */
+ ++dirp;
+ if (!rdirp)
+ /* This just means that the repository string has
+ fewer components than the dir_name string. But
+ that is OK (e.g. see modules3-8 in testsuite). */
+ ;
+ else
+ rdirp = strchr (rdirp, '/');
+ }
+ else
+ {
+ /* If there are no more slashes in the dir name,
+ we're down to the most nested directory -OR- to
+ the name of a module. In the first case, we
+ should be down to a DIRP that has no slashes,
+ so it won't help/hurt to do another STRCHR call
+ on DIRP. It will definitely hurt, however, if
+ we're down to a module name, since a module
+ name can point to a nested directory (that is,
+ DIRP will still have slashes in it. Therefore,
+ we should set it to NULL so the routine below
+ copies the contents of REMOTEDIRNAME onto the
+ root repository directory (does this if rdirp
+ is set to NULL, because we used to do an extra
+ STRCHR call here). */
+
+ rdirp = NULL;
+ strcpy (dir, dir_name);
+ }
+
+ if (fncmp (dir, CVSADM) == 0)
+ {
+ error (0, 0, "cannot create a directory named %s", dir);
+ error (0, 0, "because CVS uses \"%s\" for its own uses",
+ CVSADM);
+ error (1, 0, "rename the directory and try again");
+ }
+
+ if (mkdir_if_needed (dir))
+ {
+ /* It already existed, fine. Just keep going. */
+ }
+ else if (!strcmp (cvs_cmd_name, "export"))
+ /* Don't create CVSADM directories if this is export. */
+ ;
+ else
+ {
+ /*
+ * Put repository in CVS/Repository. For historical
+ * (pre-CVS/Root) reasons, this is an absolute pathname,
+ * but what really matters is the part of it which is
+ * relative to cvsroot.
+ */
+ char *repo;
+ char *r, *b;
+
+ repo = xmalloc (strlen (reposdirname)
+ + strlen (toplevel_repos)
+ + 80);
+ if (reposdirname_absolute)
+ r = repo;
+ else
+ {
+ strcpy (repo, toplevel_repos);
+ strcat (repo, "/");
+ r = repo + strlen (repo);
+ }
+
+ if (rdirp)
+ {
+ /* See comment near start of function; the only
+ way that the server can put the right thing
+ in each CVS/Repository file is to create the
+ directories one at a time. I think that the
+ CVS server has been doing this all along. */
+ error (0, 0, "\
+warning: server is not creating directories one at a time");
+ strncpy (r, reposdirname, rdirp - reposdirname);
+ r[rdirp - reposdirname] = '\0';
+ }
+ else
+ strcpy (r, reposdirname);
+
+ Create_Admin (dir, dir, repo, NULL, NULL, 0, 0, 1);
+ free (repo);
+
+ b = strrchr (dir, '/');
+ if (!b)
+ Subdir_Register (NULL, NULL, dir);
+ else
+ {
+ *b = '\0';
+ Subdir_Register (NULL, dir, b + 1);
+ *b = '/';
+ }
+ }
+
+ if (rdirp)
+ {
+ /* Skip the slash. */
+ ++rdirp;
+ }
+
+ } while (dirp);
+ free (dir);
+ /* Now it better work. */
+ if (CVS_CHDIR (dir_name) < 0)
+ error (1, errno, "could not chdir to %s", dir_name);
+ }
+ else if (!strcmp (cvs_cmd_name, "export"))
+ /* Don't create CVSADM directories if this is export. */
+ ;
+ else if (!isdir (CVSADM))
+ {
+ /*
+ * Put repository in CVS/Repository. For historical
+ * (pre-CVS/Root) reasons, this is an absolute pathname,
+ * but what really matters is the part of it which is
+ * relative to cvsroot.
+ */
+ char *repo;
+
+ if (reposdirname_absolute)
+ repo = reposdirname;
+ else
+ repo = Xasprintf ("%s/%s", toplevel_repos, reposdirname);
+
+ Create_Admin (".", ".", repo, NULL, NULL, 0, 1, 1);
+ if (repo != reposdirname)
+ free (repo);
+ }
+
+ if (strcmp (cvs_cmd_name, "export"))
+ {
+ last_entries = Entries_Open (0, dir_name);
+
+ /* If this is a newly created directory, we will record
+ all subdirectory information, so call Subdirs_Known in
+ case there are no subdirectories. If this is not a
+ newly created directory, it may be an old working
+ directory from before we recorded subdirectory
+ information in the Entries file. We force a search for
+ all subdirectories now, to make sure our subdirectory
+ information is up to date. If the Entries file does
+ record subdirectory information, then this call only
+ does list manipulation. */
+ if (newdir)
+ Subdirs_Known (last_entries);
+ else
+ {
+ List *dirlist;
+
+ dirlist = Find_Directories (NULL, W_LOCAL, last_entries);
+ dellist (&dirlist);
+ }
+ }
+ free (reposdirname);
+ (*func) (data, last_entries, short_pathname, filename);
+ if (last_entries)
+ Entries_Close (last_entries);
+ free (dir_name);
+ free (short_pathname);
+ free (reposname);
+}
+
+
+
+static void
+copy_a_file (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ char *newname;
+
+ read_line (&newname);
+
+#ifdef USE_VMS_FILENAMES
+ {
+ /* Mogrify the filename so VMS is happy with it. */
+ char *p;
+ for(p = newname; *p; p++)
+ if(*p == '.' || *p == '#') *p = '_';
+ }
+#endif
+ /* cvsclient.texi has said for a long time that newname must be in the
+ same directory. Wouldn't want a malicious or buggy server overwriting
+ ~/.profile, /etc/passwd, or anything like that. */
+ if (last_component (newname) != newname)
+ error (1, 0, "protocol error: Copy-file tried to specify directory");
+
+ if (unlink_file (newname) && !existence_error (errno))
+ error (0, errno, "unable to remove %s", newname);
+ copy_file (filename, newname);
+ free (newname);
+}
+
+
+
+static void
+handle_copy_file (char *args, size_t len)
+{
+ call_in_directory (args, copy_a_file, NULL);
+}
+
+
+
+/* Read from the server the count for the length of a file, then read
+ the contents of that file and write them to FILENAME. FULLNAME is
+ the name of the file for use in error messages. FIXME-someday:
+ extend this to deal with compressed files and make update_entries
+ use it. On error, gives a fatal error. */
+static void
+read_counted_file (char *filename, char *fullname)
+{
+ char *size_string;
+ size_t size;
+ char *buf;
+
+ /* Pointers in buf to the place to put data which will be read,
+ and the data which needs to be written, respectively. */
+ char *pread;
+ char *pwrite;
+ /* Number of bytes left to read and number of bytes in buf waiting to
+ be written, respectively. */
+ size_t nread;
+ size_t nwrite;
+
+ FILE *fp;
+
+ read_line (&size_string);
+ if (size_string[0] == 'z')
+ error (1, 0, "\
+protocol error: compressed files not supported for that operation");
+ /* FIXME: should be doing more error checking, probably. Like using
+ strtoul and making sure we used up the whole line. */
+ size = atoi (size_string);
+ free (size_string);
+
+ /* A more sophisticated implementation would use only a limited amount
+ of buffer space (8K perhaps), and read that much at a time. We allocate
+ a buffer for the whole file only to make it easy to keep track what
+ needs to be read and written. */
+ buf = xmalloc (size);
+
+ /* FIXME-someday: caller should pass in a flag saying whether it
+ is binary or not. I haven't carefully looked into whether
+ CVS/Template files should use local text file conventions or
+ not. */
+ fp = CVS_FOPEN (filename, "wb");
+ if (!fp)
+ error (1, errno, "cannot write %s", fullname);
+ nread = size;
+ nwrite = 0;
+ pread = buf;
+ pwrite = buf;
+ while (nread > 0 || nwrite > 0)
+ {
+ size_t n;
+
+ if (nread > 0)
+ {
+ n = try_read_from_server (pread, nread);
+ nread -= n;
+ pread += n;
+ nwrite += n;
+ }
+
+ if (nwrite > 0)
+ {
+ n = fwrite (pwrite, sizeof *pwrite, nwrite, fp);
+ if (ferror (fp))
+ error (1, errno, "cannot write %s", fullname);
+ nwrite -= n;
+ pwrite += n;
+ }
+ }
+ free (buf);
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", fullname);
+}
+
+
+
+/* OK, we want to swallow the "U foo.c" response and then output it only
+ if we can update the file. In the future we probably want some more
+ systematic approach to parsing tagged text, but for now we keep it
+ ad hoc. "Why," I hear you cry, "do we not just look at the
+ Update-existing and Created responses?" That is an excellent question,
+ and the answer is roughly conservatism/laziness--I haven't read through
+ update.c enough to figure out the exact correspondence or lack thereof
+ between those responses and a "U foo.c" line (note that Merged, from
+ join_file, can be either "C foo" or "U foo" depending on the context). */
+/* Nonzero if we have seen +updated and not -updated. */
+static int updated_seen;
+/* Filename from an "fname" tagged response within +updated/-updated. */
+static char *updated_fname;
+
+/* This struct is used to hold data when reading the +importmergecmd
+ and -importmergecmd tags. We put the variables in a struct only
+ for namespace issues. FIXME: As noted above, we need to develop a
+ more systematic approach. */
+static struct
+{
+ /* Nonzero if we have seen +importmergecmd and not -importmergecmd. */
+ int seen;
+ /* Number of conflicts, from a "conflicts" tagged response. */
+ int conflicts;
+ /* First merge tag, from a "mergetag1" tagged response. */
+ char *mergetag1;
+ /* Second merge tag, from a "mergetag2" tagged response. */
+ char *mergetag2;
+ /* Repository, from a "repository" tagged response. */
+ char *repository;
+} importmergecmd;
+
+/* Nonzero if we should arrange to return with a failure exit status. */
+static bool failure_exit;
+
+
+/*
+ * The time stamp of the last file we registered.
+ */
+static time_t last_register_time;
+
+
+
+/*
+ * The Checksum response gives the checksum for the file transferred
+ * over by the next Updated, Merged or Patch response. We just store
+ * it here, and then check it in update_entries.
+ */
+static int stored_checksum_valid;
+static unsigned char stored_checksum[16];
+static void
+handle_checksum (char *args, size_t len)
+{
+ char *s;
+ char buf[3];
+ int i;
+
+ if (stored_checksum_valid)
+ error (1, 0, "Checksum received before last one was used");
+
+ s = args;
+ buf[2] = '\0';
+ for (i = 0; i < 16; i++)
+ {
+ char *bufend;
+
+ buf[0] = *s++;
+ buf[1] = *s++;
+ stored_checksum[i] = (char) strtol (buf, &bufend, 16);
+ if (bufend != buf + 2)
+ break;
+ }
+
+ if (i < 16 || *s != '\0')
+ error (1, 0, "Invalid Checksum response: `%s'", args);
+
+ stored_checksum_valid = 1;
+}
+
+
+
+/* Mode that we got in a "Mode" response (malloc'd), or NULL if none. */
+static char *stored_mode;
+static void
+handle_mode (char *args, size_t len)
+{
+ if (stored_mode)
+ error (1, 0, "protocol error: duplicate Mode");
+ stored_mode = xstrdup (args);
+}
+
+
+
+/* Nonzero if time was specified in Mod-time. */
+static int stored_modtime_valid;
+/* Time specified in Mod-time. */
+static time_t stored_modtime;
+static void
+handle_mod_time (char *args, size_t len)
+{
+ struct timespec newtime;
+ if (stored_modtime_valid)
+ error (0, 0, "protocol error: duplicate Mod-time");
+ if (get_date (&newtime, args, NULL))
+ {
+ /* Truncate nanoseconds. */
+ stored_modtime = newtime.tv_sec;
+ stored_modtime_valid = 1;
+ }
+ else
+ error (0, 0, "protocol error: cannot parse date %s", args);
+}
+
+
+
+/*
+ * If we receive a patch, but the patch program fails to apply it, we
+ * want to request the original file. We keep a list of files whose
+ * patches have failed.
+ */
+
+char **failed_patches;
+int failed_patches_count;
+
+struct update_entries_data
+{
+ enum {
+ /*
+ * We are just getting an Entries line; the local file is
+ * correct.
+ */
+ UPDATE_ENTRIES_CHECKIN,
+ /* We are getting the file contents as well. */
+ UPDATE_ENTRIES_UPDATE,
+ /*
+ * We are getting a patch against the existing local file, not
+ * an entire new file.
+ */
+ UPDATE_ENTRIES_PATCH,
+ /*
+ * We are getting an RCS change text (diff -n output) against
+ * the existing local file, not an entire new file.
+ */
+ UPDATE_ENTRIES_RCS_DIFF
+ } contents;
+
+ enum {
+ /* We are replacing an existing file. */
+ UPDATE_ENTRIES_EXISTING,
+ /* We are creating a new file. */
+ UPDATE_ENTRIES_NEW,
+ /* We don't know whether it is existing or new. */
+ UPDATE_ENTRIES_EXISTING_OR_NEW
+ } existp;
+
+ /*
+ * String to put in the timestamp field or NULL to use the timestamp
+ * of the file.
+ */
+ char *timestamp;
+};
+
+
+
+/* Update the Entries line for this file. */
+static void
+update_entries (void *data_arg, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ char *entries_line;
+ struct update_entries_data *data = data_arg;
+
+ char *cp;
+ char *user;
+ char *vn;
+ /* Timestamp field. Always empty according to the protocol. */
+ char *ts;
+ char *options = NULL;
+ char *tag = NULL;
+ char *date = NULL;
+ char *tag_or_date;
+ char *scratch_entries = NULL;
+ int bin;
+
+#ifdef UTIME_EXPECTS_WRITABLE
+ int change_it_back = 0;
+#endif
+
+ read_line (&entries_line);
+
+ /*
+ * Parse the entries line.
+ */
+ scratch_entries = xstrdup (entries_line);
+
+ if (scratch_entries[0] != '/')
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ user = scratch_entries + 1;
+ if (!(cp = strchr (user, '/')))
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+ vn = cp;
+ if (!(cp = strchr (vn, '/')))
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+
+ ts = cp;
+ if (!(cp = strchr (ts, '/')))
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+ options = cp;
+ if (!(cp = strchr (options, '/')))
+ error (1, 0, "bad entries line `%s' from server", entries_line);
+ *cp++ = '\0';
+ tag_or_date = cp;
+
+ /* If a slash ends the tag_or_date, ignore everything after it. */
+ cp = strchr (tag_or_date, '/');
+ if (cp)
+ *cp = '\0';
+ if (*tag_or_date == 'T')
+ tag = tag_or_date + 1;
+ else if (*tag_or_date == 'D')
+ date = tag_or_date + 1;
+
+ /* Done parsing the entries line. */
+
+ if (data->contents == UPDATE_ENTRIES_UPDATE
+ || data->contents == UPDATE_ENTRIES_PATCH
+ || data->contents == UPDATE_ENTRIES_RCS_DIFF)
+ {
+ char *size_string;
+ char *mode_string;
+ int size;
+ char *buf;
+ char *temp_filename;
+ int use_gzip;
+ int patch_failed;
+
+ read_line (&mode_string);
+
+ read_line (&size_string);
+ if (size_string[0] == 'z')
+ {
+ use_gzip = 1;
+ size = atoi (size_string+1);
+ }
+ else
+ {
+ use_gzip = 0;
+ size = atoi (size_string);
+ }
+ free (size_string);
+
+ /* Note that checking this separately from writing the file is
+ a race condition: if the existence or lack thereof of the
+ file changes between now and the actual calls which
+ operate on it, we lose. However (a) there are so many
+ cases, I'm reluctant to try to fix them all, (b) in some
+ cases the system might not even have a system call which
+ does the right thing, and (c) it isn't clear this needs to
+ work. */
+ if (data->existp == UPDATE_ENTRIES_EXISTING
+ && !isfile (filename))
+ /* Emit a warning and update the file anyway. */
+ error (0, 0, "warning: %s unexpectedly disappeared",
+ short_pathname);
+
+ if (data->existp == UPDATE_ENTRIES_NEW
+ && isfile (filename))
+ {
+ /* Emit a warning and refuse to update the file; we don't want
+ to clobber a user's file. */
+ size_t nread;
+ size_t toread;
+
+ /* size should be unsigned, but until we get around to fixing
+ that, work around it. */
+ size_t usize;
+
+ char buf[8192];
+
+ /* This error might be confusing; it isn't really clear to
+ the user what to do about it. Keep in mind that it has
+ several causes: (1) something/someone creates the file
+ during the time that CVS is running, (2) the repository
+ has two files whose names clash for the client because
+ of case-insensitivity or similar causes, See 3 for
+ additional notes. (3) a special case of this is that a
+ file gets renamed for example from a.c to A.C. A
+ "cvs update" on a case-insensitive client will get this
+ error. In this case and in case 2, the filename
+ (short_pathname) printed in the error message will likely _not_
+ have the same case as seen by the user in a directory listing.
+ (4) the client has a file which the server doesn't know
+ about (e.g. "? foo" file), and that name clashes with a file
+ the server does know about, (5) classify.c will print the same
+ message for other reasons.
+
+ I hope the above paragraph makes it clear that making this
+ clearer is not a one-line fix. */
+ error (0, 0, "move away `%s'; it is in the way", short_pathname);
+ if (updated_fname)
+ {
+ cvs_output ("C ", 0);
+ cvs_output (updated_fname, 0);
+ cvs_output ("\n", 1);
+ }
+ failure_exit = true;
+
+ discard_file_and_return:
+ /* Now read and discard the file contents. */
+ usize = size;
+ nread = 0;
+ while (nread < usize)
+ {
+ toread = usize - nread;
+ if (toread > sizeof buf)
+ toread = sizeof buf;
+
+ nread += try_read_from_server (buf, toread);
+ if (nread == usize)
+ break;
+ }
+
+ free (mode_string);
+ free (scratch_entries);
+ free (entries_line);
+
+ /* The Mode, Mod-time, and Checksum responses should not carry
+ over to a subsequent Created (or whatever) response, even
+ in the error case. */
+ if (stored_mode)
+ {
+ free (stored_mode);
+ stored_mode = NULL;
+ }
+ stored_modtime_valid = 0;
+ stored_checksum_valid = 0;
+
+ if (updated_fname)
+ {
+ free (updated_fname);
+ updated_fname = NULL;
+ }
+ return;
+ }
+
+ temp_filename = xmalloc (strlen (filename) + 80);
+#ifdef USE_VMS_FILENAMES
+ /* A VMS rename of "blah.dat" to "foo" to implies a
+ destination of "foo.dat" which is unfortinate for CVS */
+ sprintf (temp_filename, "%s_new_", filename);
+#else
+#ifdef _POSIX_NO_TRUNC
+ sprintf (temp_filename, ".new.%.9s", filename);
+#else /* _POSIX_NO_TRUNC */
+ sprintf (temp_filename, ".new.%s", filename);
+#endif /* _POSIX_NO_TRUNC */
+#endif /* USE_VMS_FILENAMES */
+
+ buf = xmalloc (size);
+
+ /* Some systems, like OS/2 and Windows NT, end lines with CRLF
+ instead of just LF. Format translation is done in the C
+ library I/O funtions. Here we tell them whether or not to
+ convert -- if this file is marked "binary" with the RCS -kb
+ flag, then we don't want to convert, else we do (because
+ CVS assumes text files by default). */
+
+ if (options)
+ bin = !strcmp (options, "-kb");
+ else
+ bin = 0;
+
+ if (data->contents == UPDATE_ENTRIES_RCS_DIFF)
+ {
+ /* This is an RCS change text. We just hold the change
+ text in memory. */
+
+ if (use_gzip)
+ error (1, 0,
+ "server error: gzip invalid with RCS change text");
+
+ read_from_server (buf, size);
+ }
+ else
+ {
+ int fd;
+
+ fd = CVS_OPEN (temp_filename,
+ (O_WRONLY | O_CREAT | O_TRUNC
+ | (bin ? OPEN_BINARY : 0)),
+ 0777);
+
+ if (fd < 0)
+ {
+ /* I can see a case for making this a fatal error; for
+ a condition like disk full or network unreachable
+ (for a file server), carrying on and giving an
+ error on each file seems unnecessary. But if it is
+ a permission problem, or some such, then it is
+ entirely possible that future files will not have
+ the same problem. */
+ error (0, errno, "cannot write %s", short_pathname);
+ free (temp_filename);
+ free (buf);
+ goto discard_file_and_return;
+ }
+
+ if (size > 0)
+ {
+ read_from_server (buf, size);
+
+ if (use_gzip)
+ {
+ if (gunzip_and_write (fd, short_pathname,
+ (unsigned char *) buf, size))
+ error (1, 0, "aborting due to compression error");
+ }
+ else if (write (fd, buf, size) != size)
+ error (1, errno, "writing %s", short_pathname);
+ }
+
+ if (close (fd) < 0)
+ error (1, errno, "writing %s", short_pathname);
+ }
+
+ /* This is after we have read the file from the net (a change
+ from previous versions, where the server would send us
+ "M U foo.c" before Update-existing or whatever), but before
+ we finish writing the file (arguably a bug). The timing
+ affects a user who wants status info about how far we have
+ gotten, and also affects whether "U foo.c" appears in addition
+ to various error messages. */
+ if (updated_fname)
+ {
+ cvs_output ("U ", 0);
+ cvs_output (updated_fname, 0);
+ cvs_output ("\n", 1);
+ free (updated_fname);
+ updated_fname = 0;
+ }
+
+ patch_failed = 0;
+
+ if (data->contents == UPDATE_ENTRIES_UPDATE)
+ {
+ rename_file (temp_filename, filename);
+ }
+ else if (data->contents == UPDATE_ENTRIES_PATCH)
+ {
+ /* You might think we could just leave Patched out of
+ Valid-responses and not get this response. However, if
+ memory serves, the CVS 1.9 server bases this on -u
+ (update-patches), and there is no way for us to send -u
+ or not based on whether the server supports "Rcs-diff".
+
+ Fall back to transmitting entire files. */
+ patch_failed = 1;
+ }
+ else
+ {
+ char *filebuf;
+ size_t filebufsize;
+ size_t nread;
+ char *patchedbuf;
+ size_t patchedlen;
+
+ /* Handle UPDATE_ENTRIES_RCS_DIFF. */
+
+ if (!isfile (filename))
+ error (1, 0, "patch original file %s does not exist",
+ short_pathname);
+ filebuf = NULL;
+ filebufsize = 0;
+ nread = 0;
+
+ get_file (filename, short_pathname, bin ? FOPEN_BINARY_READ : "r",
+ &filebuf, &filebufsize, &nread);
+ /* At this point the contents of the existing file are in
+ FILEBUF, and the length of the contents is in NREAD.
+ The contents of the patch from the network are in BUF,
+ and the length of the patch is in SIZE. */
+
+ if (! rcs_change_text (short_pathname, filebuf, nread, buf, size,
+ &patchedbuf, &patchedlen))
+ patch_failed = 1;
+ else
+ {
+ if (stored_checksum_valid)
+ {
+ unsigned char checksum[16];
+
+ /* We have a checksum. Check it before writing
+ the file out, so that we don't have to read it
+ back in again. */
+ md5_buffer (patchedbuf, patchedlen, checksum);
+ if (memcmp (checksum, stored_checksum, 16) != 0)
+ {
+ error (0, 0,
+"checksum failure after patch to %s; will refetch",
+ short_pathname);
+
+ patch_failed = 1;
+ }
+
+ stored_checksum_valid = 0;
+ }
+
+ if (! patch_failed)
+ {
+ FILE *e;
+
+ e = xfopen (temp_filename,
+ bin ? FOPEN_BINARY_WRITE : "w");
+ if (fwrite (patchedbuf, sizeof *patchedbuf, patchedlen, e)
+ != patchedlen)
+ error (1, errno, "cannot write %s", temp_filename);
+ if (fclose (e) == EOF)
+ error (1, errno, "cannot close %s", temp_filename);
+ rename_file (temp_filename, filename);
+ }
+
+ free (patchedbuf);
+ }
+
+ free (filebuf);
+ }
+
+ free (temp_filename);
+
+ if (stored_checksum_valid && ! patch_failed)
+ {
+ FILE *e;
+ struct md5_ctx context;
+ unsigned char buf[8192];
+ unsigned len;
+ unsigned char checksum[16];
+
+ /*
+ * Compute the MD5 checksum. This will normally only be
+ * used when receiving a patch, so we always compute it
+ * here on the final file, rather than on the received
+ * data.
+ *
+ * Note that if the file is a text file, we should read it
+ * here using text mode, so its lines will be terminated the same
+ * way they were transmitted.
+ */
+ e = CVS_FOPEN (filename, "r");
+ if (!e)
+ error (1, errno, "could not open %s", short_pathname);
+
+ md5_init_ctx (&context);
+ while ((len = fread (buf, 1, sizeof buf, e)) != 0)
+ md5_process_bytes (buf, len, &context);
+ if (ferror (e))
+ error (1, errno, "could not read %s", short_pathname);
+ md5_finish_ctx (&context, checksum);
+
+ fclose (e);
+
+ stored_checksum_valid = 0;
+
+ if (memcmp (checksum, stored_checksum, 16) != 0)
+ {
+ if (data->contents != UPDATE_ENTRIES_PATCH)
+ error (1, 0, "checksum failure on %s",
+ short_pathname);
+
+ error (0, 0,
+ "checksum failure after patch to %s; will refetch",
+ short_pathname);
+
+ patch_failed = 1;
+ }
+ }
+
+ if (patch_failed)
+ {
+ /* Save this file to retrieve later. */
+ failed_patches = xnrealloc (failed_patches,
+ failed_patches_count + 1,
+ sizeof (char *));
+ failed_patches[failed_patches_count] = xstrdup (short_pathname);
+ ++failed_patches_count;
+
+ stored_checksum_valid = 0;
+
+ free (mode_string);
+ free (buf);
+ free (scratch_entries);
+ free (entries_line);
+
+ return;
+ }
+
+ {
+ int status = change_mode (filename, mode_string, 1);
+ if (status != 0)
+ error (0, status, "cannot change mode of %s", short_pathname);
+ }
+
+ free (mode_string);
+ free (buf);
+ }
+
+ if (stored_mode)
+ {
+ change_mode (filename, stored_mode, 1);
+ free (stored_mode);
+ stored_mode = NULL;
+ }
+
+ if (stored_modtime_valid)
+ {
+ struct utimbuf t;
+
+ memset (&t, 0, sizeof (t));
+ t.modtime = stored_modtime;
+ (void) time (&t.actime);
+
+#ifdef UTIME_EXPECTS_WRITABLE
+ if (!iswritable (filename))
+ {
+ xchmod (filename, 1);
+ change_it_back = 1;
+ }
+#endif /* UTIME_EXPECTS_WRITABLE */
+
+ if (utime (filename, &t) < 0)
+ error (0, errno, "cannot set time on %s", filename);
+
+#ifdef UTIME_EXPECTS_WRITABLE
+ if (change_it_back)
+ {
+ xchmod (filename, 0);
+ change_it_back = 0;
+ }
+#endif /* UTIME_EXPECTS_WRITABLE */
+
+ stored_modtime_valid = 0;
+ }
+
+ /*
+ * Process the entries line. Do this after we've written the file,
+ * since we need the timestamp.
+ */
+ if (strcmp (cvs_cmd_name, "export"))
+ {
+ char *local_timestamp;
+ char *file_timestamp;
+
+ (void) time (&last_register_time);
+
+ local_timestamp = data->timestamp;
+ if (!local_timestamp || ts[0] == '+')
+ file_timestamp = time_stamp (filename);
+ else
+ file_timestamp = NULL;
+
+ /*
+ * These special version numbers signify that it is not up to
+ * date. Create a dummy timestamp which will never compare
+ * equal to the timestamp of the file.
+ */
+ if (vn[0] == '\0' || !strcmp (vn, "0") || vn[0] == '-')
+ local_timestamp = "dummy timestamp";
+ else if (!local_timestamp)
+ {
+ local_timestamp = file_timestamp;
+
+ /* Checking for cvs_cmd_name of "commit" doesn't seem like
+ the cleanest way to handle this, but it seem to roughly
+ parallel what the :local: code which calls
+ mark_up_to_date ends up amounting to. Some day, should
+ think more about what the Checked-in response means
+ vis-a-vis both Entries and Base and clarify
+ cvsclient.texi accordingly. */
+
+ if (!strcmp (cvs_cmd_name, "commit"))
+ mark_up_to_date (filename);
+ }
+
+ Register (ent_list, filename, vn, local_timestamp,
+ options, tag, date, ts[0] == '+' ? file_timestamp : NULL);
+
+ if (file_timestamp)
+ free (file_timestamp);
+
+ }
+ free (scratch_entries);
+ free (entries_line);
+}
+
+
+
+static void
+handle_checked_in (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_CHECKIN;
+ dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_new_entry (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_CHECKIN;
+ dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+ dat.timestamp = "dummy timestamp from new-entry";
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_updated (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_UPDATE;
+ dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_created (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_UPDATE;
+ dat.existp = UPDATE_ENTRIES_NEW;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_update_existing (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_UPDATE;
+ dat.existp = UPDATE_ENTRIES_EXISTING;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_merged (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_UPDATE;
+ /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */
+ dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+ dat.timestamp = "Result of merge";
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_patched (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_PATCH;
+ /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */
+ dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_rcs_diff (char *args, size_t len)
+{
+ struct update_entries_data dat;
+ dat.contents = UPDATE_ENTRIES_RCS_DIFF;
+ /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */
+ dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+ dat.timestamp = NULL;
+ call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+remove_entry (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ Scratch_Entry (ent_list, filename);
+}
+
+
+
+static void
+handle_remove_entry (char *args, size_t len)
+{
+ call_in_directory (args, remove_entry, NULL);
+}
+
+
+
+static void
+remove_entry_and_file (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ Scratch_Entry (ent_list, filename);
+ /* Note that we don't ignore existence_error's here. The server
+ should be sending Remove-entry rather than Removed in cases
+ where the file does not exist. And if the user removes the
+ file halfway through a cvs command, we should be printing an
+ error. */
+ if (unlink_file (filename) < 0)
+ error (0, errno, "unable to remove %s", short_pathname);
+}
+
+
+
+static void
+handle_removed (char *args, size_t len)
+{
+ call_in_directory (args, remove_entry_and_file, NULL);
+}
+
+
+
+/* Is this the top level (directory containing CVSROOT)? */
+static int
+is_cvsroot_level (char *pathname)
+{
+ if (strcmp (toplevel_repos, current_parsed_root->directory))
+ return 0;
+
+ return !strchr (pathname, '/');
+}
+
+
+
+static void
+set_static (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ FILE *fp;
+ fp = xfopen (CVSADM_ENTSTAT, "w+");
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
+}
+
+
+
+static void
+handle_set_static_directory (char *args, size_t len)
+{
+ if (!strcmp (cvs_cmd_name, "export"))
+ {
+ /* Swallow the repository. */
+ read_line (NULL);
+ return;
+ }
+ call_in_directory (args, set_static, NULL);
+}
+
+
+
+static void
+clear_static (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
+}
+
+
+
+static void
+handle_clear_static_directory (char *pathname, size_t len)
+{
+ if (!strcmp (cvs_cmd_name, "export"))
+ {
+ /* Swallow the repository. */
+ read_line (NULL);
+ return;
+ }
+
+ if (is_cvsroot_level (pathname))
+ {
+ /*
+ * Top level (directory containing CVSROOT). This seems to normally
+ * lack a CVS directory, so don't try to create files in it.
+ */
+ return;
+ }
+ call_in_directory (pathname, clear_static, NULL);
+}
+
+
+
+static void
+set_sticky (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ char *tagspec;
+ FILE *f;
+
+ read_line (&tagspec);
+
+ /* FIXME-update-dir: error messages should include the directory. */
+ f = CVS_FOPEN (CVSADM_TAG, "w+");
+ if (!f)
+ {
+ /* Making this non-fatal is a bit of a kludge (see dirs2
+ in testsuite). A better solution would be to avoid having
+ the server tell us about a directory we shouldn't be doing
+ anything with anyway (e.g. by handling directory
+ addition/removal better). */
+ error (0, errno, "cannot open %s", CVSADM_TAG);
+ free (tagspec);
+ return;
+ }
+ if (fprintf (f, "%s\n", tagspec) < 0)
+ error (1, errno, "writing %s", CVSADM_TAG);
+ if (fclose (f) == EOF)
+ error (1, errno, "closing %s", CVSADM_TAG);
+ free (tagspec);
+}
+
+
+
+static void
+handle_set_sticky (char *pathname, size_t len)
+{
+ if (!strcmp (cvs_cmd_name, "export"))
+ {
+ /* Swallow the repository. */
+ read_line (NULL);
+ /* Swallow the tag line. */
+ read_line (NULL);
+ return;
+ }
+ if (is_cvsroot_level (pathname))
+ {
+ /*
+ * Top level (directory containing CVSROOT). This seems to normally
+ * lack a CVS directory, so don't try to create files in it.
+ */
+
+ /* Swallow the repository. */
+ read_line (NULL);
+ /* Swallow the tag line. */
+ read_line (NULL);
+ return;
+ }
+
+ call_in_directory (pathname, set_sticky, NULL);
+}
+
+
+
+static void
+clear_sticky (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove %s", CVSADM_TAG);
+}
+
+
+
+static void
+handle_clear_sticky (char *pathname, size_t len)
+{
+ if (!strcmp (cvs_cmd_name, "export"))
+ {
+ /* Swallow the repository. */
+ read_line (NULL);
+ return;
+ }
+
+ if (is_cvsroot_level (pathname))
+ {
+ /*
+ * Top level (directory containing CVSROOT). This seems to normally
+ * lack a CVS directory, so don't try to create files in it.
+ */
+ return;
+ }
+
+ call_in_directory (pathname, clear_sticky, NULL);
+}
+
+
+
+/* Handle the client-side support for a successful edit.
+ */
+static void
+handle_edit_file (char *pathname, size_t len)
+{
+ call_in_directory (pathname, edit_file, NULL);
+}
+
+
+
+static void
+template (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ char *buf = Xasprintf ("%s/%s", short_pathname, CVSADM_TEMPLATE);
+ read_counted_file (CVSADM_TEMPLATE, buf);
+ free (buf);
+}
+
+
+
+static void
+handle_template (char *pathname, size_t len)
+{
+ call_in_directory (pathname, template, NULL);
+}
+
+
+
+static void
+clear_template (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ if (unlink_file (CVSADM_TEMPLATE) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove %s", CVSADM_TEMPLATE);
+}
+
+
+
+static void
+handle_clear_template (char *pathname, size_t len)
+{
+ call_in_directory (pathname, clear_template, NULL);
+}
+
+
+
+struct save_dir {
+ char *dir;
+ struct save_dir *next;
+};
+
+struct save_dir *prune_candidates;
+
+static void
+add_prune_candidate (const char *dir)
+{
+ struct save_dir *p;
+
+ if ((dir[0] == '.' && dir[1] == '\0')
+ || (prune_candidates && !strcmp (dir, prune_candidates->dir)))
+ return;
+ p = xmalloc (sizeof (struct save_dir));
+ p->dir = xstrdup (dir);
+ p->next = prune_candidates;
+ prune_candidates = p;
+}
+
+
+
+static void
+process_prune_candidates (void)
+{
+ struct save_dir *p;
+ struct save_dir *q;
+
+ if (toplevel_wd)
+ {
+ if (CVS_CHDIR (toplevel_wd) < 0)
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+ }
+ for (p = prune_candidates; p; )
+ {
+ if (isemptydir (p->dir, 1))
+ {
+ char *b;
+
+ if (unlink_file_dir (p->dir) < 0)
+ error (0, errno, "cannot remove %s", p->dir);
+ b = strrchr (p->dir, '/');
+ if (!b)
+ Subdir_Deregister (NULL, NULL, p->dir);
+ else
+ {
+ *b = '\0';
+ Subdir_Deregister (NULL, p->dir, b + 1);
+ }
+ }
+ free (p->dir);
+ q = p->next;
+ free (p);
+ p = q;
+ }
+ prune_candidates = NULL;
+}
+
+
+
+/* Send a Repository line. */
+static char *last_repos;
+static char *last_update_dir;
+static void
+send_repository (const char *dir, const char *repos, const char *update_dir)
+{
+ char *adm_name;
+
+ /* FIXME: this is probably not the best place to check; I wish I
+ * knew where in here's callers to really trap this bug. To
+ * reproduce the bug, just do this:
+ *
+ * mkdir junk
+ * cd junk
+ * cvs -d some_repos update foo
+ *
+ * Poof, CVS seg faults and dies! It's because it's trying to
+ * send a NULL string to the server but dies in send_to_server.
+ * That string was supposed to be the repository, but it doesn't
+ * get set because there's no CVSADM dir, and somehow it's not
+ * getting set from the -d argument either... ?
+ */
+ if (!repos)
+ {
+ /* Lame error. I want a real fix but can't stay up to track
+ this down right now. */
+ error (1, 0, "no repository");
+ }
+
+ if (!update_dir || update_dir[0] == '\0')
+ update_dir = ".";
+
+ if (last_repos && !strcmp (repos, last_repos)
+ && last_update_dir && !strcmp (update_dir, last_update_dir))
+ /* We've already sent it. */
+ return;
+
+ if (client_prune_dirs)
+ add_prune_candidate (update_dir);
+
+ /* Add a directory name to the list of those sent to the
+ server. */
+ if (update_dir && *update_dir != '\0' && strcmp (update_dir, ".")
+ && !findnode (dirs_sent_to_server, update_dir))
+ {
+ Node *n;
+ n = getnode ();
+ n->type = NT_UNKNOWN;
+ n->key = xstrdup (update_dir);
+ n->data = NULL;
+
+ if (addnode (dirs_sent_to_server, n))
+ error (1, 0, "cannot add directory %s to list", n->key);
+ }
+
+ /* 80 is large enough for any of CVSADM_*. */
+ adm_name = xmalloc (strlen (dir) + 80);
+
+ send_to_server ("Directory ", 0);
+ {
+ /* Send the directory name. I know that this
+ sort of duplicates code elsewhere, but each
+ case seems slightly different... */
+ char buf[1];
+ const char *p = update_dir;
+ while (*p != '\0')
+ {
+ assert (*p != '\012');
+ if (ISSLASH (*p))
+ {
+ buf[0] = '/';
+ send_to_server (buf, 1);
+ }
+ else
+ {
+ buf[0] = *p;
+ send_to_server (buf, 1);
+ }
+ ++p;
+ }
+ }
+ send_to_server ("\012", 1);
+ if (supported_request ("Relative-directory"))
+ {
+ const char *short_repos = Short_Repository (repos);
+ send_to_server (short_repos, 0);
+ }
+ else
+ send_to_server (repos, 0);
+ send_to_server ("\012", 1);
+
+ if (supported_request ("Static-directory"))
+ {
+ adm_name[0] = '\0';
+ if (dir[0] != '\0')
+ {
+ strcat (adm_name, dir);
+ strcat (adm_name, "/");
+ }
+ strcat (adm_name, CVSADM_ENTSTAT);
+ if (isreadable (adm_name))
+ {
+ send_to_server ("Static-directory\012", 0);
+ }
+ }
+ if (supported_request ("Sticky"))
+ {
+ FILE *f;
+ if (dir[0] == '\0')
+ strcpy (adm_name, CVSADM_TAG);
+ else
+ sprintf (adm_name, "%s/%s", dir, CVSADM_TAG);
+
+ f = CVS_FOPEN (adm_name, "r");
+ if (!f)
+ {
+ if (! existence_error (errno))
+ error (1, errno, "reading %s", adm_name);
+ }
+ else
+ {
+ char line[80];
+ char *nl = NULL;
+ send_to_server ("Sticky ", 0);
+ while (fgets (line, sizeof (line), f))
+ {
+ send_to_server (line, 0);
+ nl = strchr (line, '\n');
+ if (nl)
+ break;
+ }
+ if (!nl)
+ send_to_server ("\012", 1);
+ if (fclose (f) == EOF)
+ error (0, errno, "closing %s", adm_name);
+ }
+ }
+ free (adm_name);
+ if (last_repos) free (last_repos);
+ if (last_update_dir) free (last_update_dir);
+ last_repos = xstrdup (repos);
+ last_update_dir = xstrdup (update_dir);
+}
+
+
+
+/* Send a Repository line and set toplevel_repos. */
+void
+send_a_repository (const char *dir, const char *repository,
+ const char *update_dir_in)
+{
+ char *update_dir = xstrdup (update_dir_in);
+
+ if (!toplevel_repos && repository)
+ {
+ if (update_dir[0] == '\0'
+ || (update_dir[0] == '.' && update_dir[1] == '\0'))
+ toplevel_repos = xstrdup (repository);
+ else
+ {
+ /*
+ * Get the repository from a CVS/Repository file if update_dir
+ * is absolute. This is not correct in general, because
+ * the CVS/Repository file might not be the top-level one.
+ * This is for cases like "cvs update /foo/bar" (I'm not
+ * sure it matters what toplevel_repos we get, but it does
+ * matter that we don't hit the "internal error" code below).
+ */
+ if (update_dir[0] == '/')
+ toplevel_repos = Name_Repository (update_dir, update_dir);
+ else
+ {
+ /*
+ * Guess the repository of that directory by looking at a
+ * subdirectory and removing as many pathname components
+ * as are in update_dir. I think that will always (or at
+ * least almost always) be 1.
+ *
+ * So this deals with directories which have been
+ * renamed, though it doesn't necessarily deal with
+ * directories which have been put inside other
+ * directories (and cvs invoked on the containing
+ * directory). I'm not sure the latter case needs to
+ * work.
+ *
+ * 21 Aug 1998: Well, Mr. Above-Comment-Writer, it
+ * does need to work after all. When we are using the
+ * client in a multi-cvsroot environment, it will be
+ * fairly common that we have the above case (e.g.,
+ * cwd checked out from one repository but
+ * subdirectory checked out from another). We can't
+ * assume that by walking up a directory in our wd we
+ * necessarily walk up a directory in the repository.
+ */
+ /*
+ * This gets toplevel_repos wrong for "cvs update ../foo"
+ * but I'm not sure toplevel_repos matters in that case.
+ */
+
+ int repository_len, update_dir_len;
+
+ strip_trailing_slashes (update_dir);
+
+ repository_len = strlen (repository);
+ update_dir_len = strlen (update_dir);
+
+ /* Try to remove the path components in UPDATE_DIR
+ from REPOSITORY. If the path elements don't exist
+ in REPOSITORY, or the removal of those path
+ elements mean that we "step above"
+ current_parsed_root->directory, set toplevel_repos to
+ current_parsed_root->directory. */
+ if (repository_len > update_dir_len
+ && !strcmp (repository + repository_len - update_dir_len,
+ update_dir)
+ /* TOPLEVEL_REPOS shouldn't be above current_parsed_root->directory */
+ && ((size_t)(repository_len - update_dir_len)
+ > strlen (current_parsed_root->directory)))
+ {
+ /* The repository name contains UPDATE_DIR. Set
+ toplevel_repos to the repository name without
+ UPDATE_DIR. */
+
+ toplevel_repos = xmalloc (repository_len - update_dir_len);
+ /* Note that we don't copy the trailing '/'. */
+ strncpy (toplevel_repos, repository,
+ repository_len - update_dir_len - 1);
+ toplevel_repos[repository_len - update_dir_len - 1] = '\0';
+ }
+ else
+ {
+ toplevel_repos = xstrdup (current_parsed_root->directory);
+ }
+ }
+ }
+ }
+
+ send_repository (dir, repository, update_dir);
+ free (update_dir);
+}
+
+
+
+static void
+notified_a_file (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ FILE *fp;
+ FILE *newf;
+ size_t line_len = 8192;
+ char *line = xmalloc (line_len);
+ char *cp;
+ int nread;
+ int nwritten;
+ char *p;
+
+ fp = xfopen (CVSADM_NOTIFY, "r");
+ if (getline (&line, &line_len, fp) < 0)
+ {
+ if (feof (fp))
+ error (0, 0, "cannot read %s: end of file", CVSADM_NOTIFY);
+ else
+ error (0, errno, "cannot read %s", CVSADM_NOTIFY);
+ goto error_exit;
+ }
+ cp = strchr (line, '\t');
+ if (!cp)
+ {
+ error (0, 0, "malformed %s file", CVSADM_NOTIFY);
+ goto error_exit;
+ }
+ *cp = '\0';
+ if (strcmp (filename, line + 1))
+ error (0, 0, "protocol error: notified %s, expected %s", filename,
+ line + 1);
+
+ if (getline (&line, &line_len, fp) < 0)
+ {
+ if (feof (fp))
+ {
+ free (line);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
+ if ( CVS_UNLINK (CVSADM_NOTIFY) < 0)
+ error (0, errno, "cannot remove %s", CVSADM_NOTIFY);
+ return;
+ }
+ else
+ {
+ error (0, errno, "cannot read %s", CVSADM_NOTIFY);
+ goto error_exit;
+ }
+ }
+ newf = xfopen (CVSADM_NOTIFYTMP, "w");
+ if (fputs (line, newf) < 0)
+ {
+ error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP);
+ goto error2;
+ }
+ while ((nread = fread (line, 1, line_len, fp)) > 0)
+ {
+ p = line;
+ while ((nwritten = fwrite (p, sizeof *p, nread, newf)) > 0)
+ {
+ nread -= nwritten;
+ p += nwritten;
+ }
+ if (ferror (newf))
+ {
+ error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP);
+ goto error2;
+ }
+ }
+ if (ferror (fp))
+ {
+ error (0, errno, "cannot read %s", CVSADM_NOTIFY);
+ goto error2;
+ }
+ if (fclose (newf) < 0)
+ {
+ error (0, errno, "cannot close %s", CVSADM_NOTIFYTMP);
+ goto error_exit;
+ }
+ free (line);
+ if (fclose (fp) < 0)
+ {
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
+ return;
+ }
+
+ {
+ /* In this case, we want rename_file() to ignore noexec. */
+ int saved_noexec = noexec;
+ noexec = 0;
+ rename_file (CVSADM_NOTIFYTMP, CVSADM_NOTIFY);
+ noexec = saved_noexec;
+ }
+
+ return;
+ error2:
+ (void)fclose (newf);
+ error_exit:
+ free (line);
+ (void)fclose (fp);
+}
+
+
+
+static void
+handle_notified (char *args, size_t len)
+{
+ call_in_directory (args, notified_a_file, NULL);
+}
+
+
+
+/* The "expanded" modules. */
+static int modules_count;
+static int modules_allocated;
+static char **modules_vector;
+
+static void
+handle_module_expansion (char *args, size_t len)
+{
+ if (!modules_vector)
+ {
+ modules_allocated = 1; /* Small for testing */
+ modules_vector = xnmalloc (modules_allocated,
+ sizeof (modules_vector[0]));
+ }
+ else if (modules_count >= modules_allocated)
+ {
+ modules_allocated *= 2;
+ modules_vector = xnrealloc (modules_vector,
+ modules_allocated,
+ sizeof (modules_vector[0]));
+ }
+ modules_vector[modules_count] = xstrdup (args);
+ ++modules_count;
+}
+
+
+
+/* Original, not "expanded" modules. */
+static int module_argc;
+static char **module_argv;
+
+void
+client_expand_modules (int argc, char **argv, int local)
+{
+ int errs;
+ int i;
+
+ module_argc = argc;
+ module_argv = xnmalloc (argc + 1, sizeof (module_argv[0]));
+ for (i = 0; i < argc; ++i)
+ module_argv[i] = xstrdup (argv[i]);
+ module_argv[argc] = NULL;
+
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ send_a_repository ("", current_parsed_root->directory, "");
+
+ send_to_server ("expand-modules\012", 0);
+
+ errs = get_server_responses ();
+
+ if (last_repos) free (last_repos);
+ last_repos = NULL;
+
+ if (last_update_dir) free (last_update_dir);
+ last_update_dir = NULL;
+
+ if (errs)
+ error (errs, 0, "cannot expand modules");
+}
+
+
+
+void
+client_send_expansions (int local, char *where, int build_dirs)
+{
+ int i;
+ char *argv[1];
+
+ /* Send the original module names. The "expanded" module name might
+ not be suitable as an argument to a co request (e.g. it might be
+ the result of a -d argument in the modules file). It might be
+ cleaner if we genuinely expanded module names, all the way to a
+ local directory and repository, but that isn't the way it works
+ now. */
+ send_file_names (module_argc, module_argv, 0);
+
+ for (i = 0; i < modules_count; ++i)
+ {
+ argv[0] = where ? where : modules_vector[i];
+ if (isfile (argv[0]))
+ send_files (1, argv, local, 0, build_dirs ? SEND_BUILD_DIRS : 0);
+ }
+ send_a_repository ("", current_parsed_root->directory, "");
+}
+
+
+
+void
+client_nonexpanded_setup (void)
+{
+ send_a_repository ("", current_parsed_root->directory, "");
+}
+
+
+
+/* Receive a cvswrappers line from the server; it must be a line
+ containing an RCS option (e.g., "*.exe -k 'b'").
+
+ Note that this doesn't try to handle -t/-f options (which are a
+ whole separate issue which noone has thought much about, as far
+ as I know).
+
+ We need to know the keyword expansion mode so we know whether to
+ read the file in text or binary mode. */
+static void
+handle_wrapper_rcs_option (char *args, size_t len)
+{
+ char *p;
+
+ /* Enforce the notes in cvsclient.texi about how the response is not
+ as free-form as it looks. */
+ p = strchr (args, ' ');
+ if (!p)
+ goto handle_error;
+ if (*++p != '-'
+ || *++p != 'k'
+ || *++p != ' '
+ || *++p != '\'')
+ goto handle_error;
+ if (!strchr (p, '\''))
+ goto handle_error;
+
+ /* Add server-side cvswrappers line to our wrapper list. */
+ wrap_add (args, 0);
+ return;
+ handle_error:
+ error (0, errno, "protocol error: ignoring invalid wrappers %s", args);
+}
+
+
+
+
+static void
+handle_m (char *args, size_t len)
+{
+ /* In the case where stdout and stderr point to the same place,
+ fflushing stderr will make output happen in the correct order.
+ Often stderr will be line-buffered and this won't be needed,
+ but not always (is that true? I think the comment is probably
+ based on being confused between default buffering between
+ stdout and stderr. But I'm not sure). */
+ fflush (stderr);
+ fwrite (args, sizeof *args, len, stdout);
+ putc ('\n', stdout);
+}
+
+
+
+static void
+handle_mbinary (char *args, size_t len)
+{
+ char *size_string;
+ size_t size;
+ size_t totalread;
+ size_t nread;
+ size_t toread;
+ char buf[8192];
+
+ /* See comment at handle_m about (non)flush of stderr. */
+
+ /* Get the size. */
+ read_line (&size_string);
+ size = atoi (size_string);
+ free (size_string);
+
+ /* OK, now get all the data. The algorithm here is that we read
+ as much as the network wants to give us in
+ try_read_from_server, and then we output it all, and then
+ repeat, until we get all the data. */
+ totalread = 0;
+ while (totalread < size)
+ {
+ toread = size - totalread;
+ if (toread > sizeof buf)
+ toread = sizeof buf;
+
+ nread = try_read_from_server (buf, toread);
+ cvs_output_binary (buf, nread);
+ totalread += nread;
+ }
+}
+
+
+
+static void
+handle_e (char *args, size_t len)
+{
+ /* In the case where stdout and stderr point to the same place,
+ fflushing stdout will make output happen in the correct order. */
+ fflush (stdout);
+ fwrite (args, sizeof *args, len, stderr);
+ putc ('\n', stderr);
+}
+
+
+
+/*ARGSUSED*/
+static void
+handle_f (char *args, size_t len)
+{
+ fflush (stderr);
+}
+
+
+
+static void
+handle_mt (char *args, size_t len)
+{
+ char *p;
+ char *tag = args;
+ char *text;
+
+ /* See comment at handle_m for more details. */
+ fflush (stderr);
+
+ p = strchr (args, ' ');
+ if (!p)
+ text = NULL;
+ else
+ {
+ *p++ = '\0';
+ text = p;
+ }
+
+ switch (tag[0])
+ {
+ case '+':
+ if (!strcmp (tag, "+updated"))
+ updated_seen = 1;
+ else if (!strcmp (tag, "+importmergecmd"))
+ importmergecmd.seen = 1;
+ break;
+ case '-':
+ if (!strcmp (tag, "-updated"))
+ updated_seen = 0;
+ else if (!strcmp (tag, "-importmergecmd"))
+ {
+ char buf[80];
+
+ /* Now that we have gathered the information, we can
+ output the suggested merge command. */
+
+ if (importmergecmd.conflicts == 0
+ || !importmergecmd.mergetag1
+ || !importmergecmd.mergetag2
+ || !importmergecmd.repository)
+ {
+ error (0, 0,
+ "invalid server: incomplete importmergecmd tags");
+ break;
+ }
+
+ if (importmergecmd.conflicts == -1)
+ sprintf (buf, "\nNo conflicts created by this import.\n");
+ else
+ sprintf (buf, "\n%d conflicts created by this import.\n",
+ importmergecmd.conflicts);
+ cvs_output (buf, 0);
+ cvs_output ("Use the following command to help the merge:\n\n",
+ 0);
+ cvs_output ("\t", 1);
+ cvs_output (program_name, 0);
+ if (CVSroot_cmdline)
+ {
+ cvs_output (" -d ", 0);
+ cvs_output (CVSroot_cmdline, 0);
+ }
+ cvs_output (" checkout -j", 0);
+ cvs_output (importmergecmd.mergetag1, 0);
+ cvs_output (" -j", 0);
+ cvs_output (importmergecmd.mergetag2, 0);
+ cvs_output (" ", 1);
+ cvs_output (importmergecmd.repository, 0);
+ cvs_output ("\n\n", 0);
+
+ /* Clear the static variables so that everything is
+ ready for any subsequent importmergecmd tag. */
+ importmergecmd.conflicts = 0;
+ free (importmergecmd.mergetag1);
+ importmergecmd.mergetag1 = NULL;
+ free (importmergecmd.mergetag2);
+ importmergecmd.mergetag2 = NULL;
+ free (importmergecmd.repository);
+ importmergecmd.repository = NULL;
+
+ importmergecmd.seen = 0;
+ }
+ break;
+ default:
+ if (updated_seen)
+ {
+ if (!strcmp (tag, "fname"))
+ {
+ if (updated_fname)
+ {
+ /* Output the previous message now. This can happen
+ if there was no Update-existing or other such
+ response, due to the -n global option. */
+ cvs_output ("U ", 0);
+ cvs_output (updated_fname, 0);
+ cvs_output ("\n", 1);
+ free (updated_fname);
+ }
+ updated_fname = xstrdup (text);
+ }
+ /* Swallow all other tags. Either they are extraneous
+ or they reflect future extensions that we can
+ safely ignore. */
+ }
+ else if (importmergecmd.seen)
+ {
+ if (!strcmp (tag, "conflicts"))
+ {
+ if (!strcmp (text, "No"))
+ importmergecmd.conflicts = -1;
+ else
+ importmergecmd.conflicts = atoi (text);
+ }
+ else if (!strcmp (tag, "mergetag1"))
+ importmergecmd.mergetag1 = xstrdup (text);
+ else if (!strcmp (tag, "mergetag2"))
+ importmergecmd.mergetag2 = xstrdup (text);
+ else if (!strcmp (tag, "repository"))
+ importmergecmd.repository = xstrdup (text);
+ /* Swallow all other tags. Either they are text for
+ which we are going to print our own version when we
+ see -importmergecmd, or they are future extensions
+ we can safely ignore. */
+ }
+ else if (!strcmp (tag, "newline"))
+ printf ("\n");
+ else if (!strcmp (tag, "date"))
+ {
+ char *date = format_date_alloc (text);
+ printf ("%s", date);
+ free (date);
+ }
+ else if (text)
+ printf ("%s", text);
+ }
+}
+
+
+
+#endif /* CLIENT_SUPPORT */
+#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
+
+/* This table must be writeable if the server code is included. */
+struct response responses[] =
+{
+#ifdef CLIENT_SUPPORT
+#define RSP_LINE(n, f, t, s) {n, f, t, s}
+#else /* ! CLIENT_SUPPORT */
+#define RSP_LINE(n, f, t, s) {n, s}
+#endif /* CLIENT_SUPPORT */
+
+ RSP_LINE("ok", handle_ok, response_type_ok, rs_essential),
+ RSP_LINE("error", handle_error, response_type_error, rs_essential),
+ RSP_LINE("Valid-requests", handle_valid_requests, response_type_normal,
+ rs_essential),
+ RSP_LINE("Force-gzip", handle_force_gzip, response_type_normal,
+ rs_optional),
+ RSP_LINE("Referrer", handle_referrer, response_type_normal, rs_optional),
+ RSP_LINE("Redirect", handle_redirect, response_type_redirect, rs_optional),
+ RSP_LINE("Checked-in", handle_checked_in, response_type_normal,
+ rs_essential),
+ RSP_LINE("New-entry", handle_new_entry, response_type_normal, rs_optional),
+ RSP_LINE("Checksum", handle_checksum, response_type_normal, rs_optional),
+ RSP_LINE("Copy-file", handle_copy_file, response_type_normal, rs_optional),
+ RSP_LINE("Updated", handle_updated, response_type_normal, rs_essential),
+ RSP_LINE("Created", handle_created, response_type_normal, rs_optional),
+ RSP_LINE("Update-existing", handle_update_existing, response_type_normal,
+ rs_optional),
+ RSP_LINE("Merged", handle_merged, response_type_normal, rs_essential),
+ RSP_LINE("Patched", handle_patched, response_type_normal, rs_optional),
+ RSP_LINE("Rcs-diff", handle_rcs_diff, response_type_normal, rs_optional),
+ RSP_LINE("Mode", handle_mode, response_type_normal, rs_optional),
+ RSP_LINE("Mod-time", handle_mod_time, response_type_normal, rs_optional),
+ RSP_LINE("Removed", handle_removed, response_type_normal, rs_essential),
+ RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal,
+ rs_optional),
+ RSP_LINE("Set-static-directory", handle_set_static_directory,
+ response_type_normal,
+ rs_optional),
+ RSP_LINE("Clear-static-directory", handle_clear_static_directory,
+ response_type_normal,
+ rs_optional),
+ RSP_LINE("Set-sticky", handle_set_sticky, response_type_normal,
+ rs_optional),
+ RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal,
+ rs_optional),
+ RSP_LINE("Edit-file", handle_edit_file, response_type_normal,
+ rs_optional),
+ RSP_LINE("Template", handle_template, response_type_normal,
+ rs_optional),
+ RSP_LINE("Clear-template", handle_clear_template, response_type_normal,
+ rs_optional),
+ RSP_LINE("Notified", handle_notified, response_type_normal, rs_optional),
+ RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal,
+ rs_optional),
+ RSP_LINE("Wrapper-rcsOption", handle_wrapper_rcs_option,
+ response_type_normal,
+ rs_optional),
+ RSP_LINE("M", handle_m, response_type_normal, rs_essential),
+ RSP_LINE("Mbinary", handle_mbinary, response_type_normal, rs_optional),
+ RSP_LINE("E", handle_e, response_type_normal, rs_essential),
+ RSP_LINE("F", handle_f, response_type_normal, rs_optional),
+ RSP_LINE("MT", handle_mt, response_type_normal, rs_optional),
+ /* Possibly should be response_type_error. */
+ RSP_LINE(NULL, NULL, response_type_normal, rs_essential)
+
+#undef RSP_LINE
+};
+
+#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
+#ifdef CLIENT_SUPPORT
+
+
+
+/*
+ * If LEN is 0, then send_to_server_via() computes string's length itself.
+ *
+ * Therefore, pass the real length when transmitting data that might
+ * contain 0's.
+ */
+void
+send_to_server_via (struct buffer *via_buffer, const char *str, size_t len)
+{
+ static int nbytes;
+
+ if (len == 0)
+ len = strlen (str);
+
+ buf_output (via_buffer, str, len);
+
+ /* There is no reason not to send data to the server, so do it
+ whenever we've accumulated enough information in the buffer to
+ make it worth sending. */
+ nbytes += len;
+ if (nbytes >= 2 * BUFFER_DATA_SIZE)
+ {
+ int status;
+
+ status = buf_send_output (via_buffer);
+ if (status != 0)
+ error (1, status, "error writing to server");
+ nbytes = 0;
+ }
+}
+
+
+
+void
+send_to_server (const char *str, size_t len)
+{
+ send_to_server_via (global_to_server, str, len);
+}
+
+
+
+/* Read up to LEN bytes from the server. Returns actual number of
+ bytes read, which will always be at least one; blocks if there is
+ no data available at all. Gives a fatal error on EOF or error. */
+static size_t
+try_read_from_server( char *buf, size_t len )
+{
+ int status;
+ size_t nread;
+ char *data;
+
+ status = buf_read_data (global_from_server, len, &data, &nread);
+ if (status != 0)
+ {
+ if (status == -1)
+ error (1, 0,
+ "end of file from server (consult above messages if any)");
+ else if (status == -2)
+ error (1, 0, "out of memory");
+ else
+ error (1, status, "reading from server");
+ }
+
+ memcpy (buf, data, nread);
+
+ return nread;
+}
+
+
+
+/*
+ * Read LEN bytes from the server or die trying.
+ */
+void
+read_from_server (char *buf, size_t len)
+{
+ size_t red = 0;
+ while (red < len)
+ {
+ red += try_read_from_server (buf + red, len - red);
+ if (red == len)
+ break;
+ }
+}
+
+
+
+/* Get some server responses and process them.
+ *
+ * RETURNS
+ * 0 Success
+ * 1 Error
+ * 2 Redirect
+ */
+int
+get_server_responses (void)
+{
+ struct response *rs;
+ do
+ {
+ char *cmd;
+ size_t len;
+
+ len = read_line (&cmd);
+ for (rs = responses; rs->name; ++rs)
+ if (!strncmp (cmd, rs->name, strlen (rs->name)))
+ {
+ size_t cmdlen = strlen (rs->name);
+ if (cmd[cmdlen] == '\0')
+ ;
+ else if (cmd[cmdlen] == ' ')
+ ++cmdlen;
+ else
+ /*
+ * The first len characters match, but it's a different
+ * response. e.g. the response is "oklahoma" but we
+ * matched "ok".
+ */
+ continue;
+ (*rs->func) (cmd + cmdlen, len - cmdlen);
+ break;
+ }
+ if (!rs->name)
+ /* It's OK to print just to the first '\0'. */
+ /* We might want to handle control characters and the like
+ in some other way other than just sending them to stdout.
+ One common reason for this error is if people use :ext:
+ with a version of rsh which is doing CRLF translation or
+ something, and so the client gets "ok^M" instead of "ok".
+ Right now that will tend to print part of this error
+ message over the other part of it. It seems like we could
+ do better (either in general, by quoting or omitting all
+ control characters, and/or specifically, by detecting the CRLF
+ case and printing a specific error message). */
+ error (0, 0,
+ "warning: unrecognized response `%s' from cvs server",
+ cmd);
+ free (cmd);
+ } while (rs->type == response_type_normal);
+
+ if (updated_fname)
+ {
+ /* Output the previous message now. This can happen
+ if there was no Update-existing or other such
+ response, due to the -n global option. */
+ cvs_output ("U ", 0);
+ cvs_output (updated_fname, 0);
+ cvs_output ("\n", 1);
+ free (updated_fname);
+ updated_fname = NULL;
+ }
+
+ if (rs->type == response_type_redirect) return 2;
+ if (rs->type == response_type_error) return 1;
+ if (failure_exit) return 1;
+ return 0;
+}
+
+
+
+static inline void
+close_connection_to_server (struct buffer **to, struct buffer **from)
+{
+ int status;
+
+ /* First we shut down GLOBAL_TO_SERVER. That tells the server that its
+ * input is finished. It then shuts down the buffer it is sending to us,
+ * at which point our shut down of GLOBAL_FROM_SERVER will complete.
+ */
+
+ TRACE (TRACE_FUNCTION, "close_connection_to_server ()");
+
+ status = buf_shutdown (*to);
+ if (status != 0)
+ error (0, status, "shutting down buffer to server");
+ buf_free (*to);
+ *to = NULL;
+
+ status = buf_shutdown (*from);
+ if (status != 0)
+ error (0, status, "shutting down buffer from server");
+ buf_free (*from);
+ *from = NULL;
+}
+
+
+
+/* Get the responses and then close the connection. */
+
+/*
+ * Flag var; we'll set it in start_server() and not one of its
+ * callees, such as start_rsh_server(). This means that there might
+ * be a small window between the starting of the server and the
+ * setting of this var, but all the code in that window shouldn't care
+ * because it's busy checking return values to see if the server got
+ * started successfully anyway.
+ */
+int server_started = 0;
+
+int
+get_responses_and_close (void)
+{
+ int errs = get_server_responses ();
+
+ /* The following is necessary when working with multiple cvsroots, at least
+ * with commit. It used to be buried nicely in do_deferred_progs() before
+ * that function was removed. I suspect it wouldn't be necessary if
+ * call_in_directory() saved its working directory via save_cwd() before
+ * changing its directory and restored the saved working directory via
+ * restore_cwd() before exiting. Of course, calling CVS_CHDIR only once,
+ * here, may be more efficient.
+ */
+ if (toplevel_wd)
+ {
+ if (CVS_CHDIR (toplevel_wd) < 0)
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+ }
+
+ if (client_prune_dirs)
+ process_prune_candidates ();
+
+ close_connection_to_server (&global_to_server, &global_from_server);
+ server_started = 0;
+
+ /* see if we need to sleep before returning to avoid time-stamp races */
+ if (last_register_time)
+ sleep_past (last_register_time);
+
+ return errs;
+}
+
+
+
+bool
+supported_request (const char *name)
+{
+ struct request *rq;
+
+ for (rq = requests; rq->name; rq++)
+ if (!strcmp (rq->name, name))
+ return (rq->flags & RQ_SUPPORTED) != 0;
+ error (1, 0, "internal error: testing support for unknown request?");
+ /* NOTREACHED */
+ return 0;
+}
+
+
+
+#if defined (AUTH_CLIENT_SUPPORT) || defined (SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI)
+
+
+/* Generic function to do port number lookup tasks.
+ *
+ * In order of precedence, will return:
+ * getenv (envname), if defined
+ * getservbyname (portname), if defined
+ * defaultport
+ */
+static int
+get_port_number (const char *envname, const char *portname, int defaultport)
+{
+ struct servent *s;
+ char *port_s;
+
+ if (envname && (port_s = getenv (envname)))
+ {
+ int port = atoi (port_s);
+ if (port <= 0)
+ {
+ error (0, 0, "%s must be a positive integer! If you", envname);
+ error (0, 0, "are trying to force a connection via rsh, please");
+ error (0, 0, "put \":server:\" at the beginning of your CVSROOT");
+ error (1, 0, "variable.");
+ }
+ return port;
+ }
+ else if (portname && (s = getservbyname (portname, "tcp")))
+ return ntohs (s->s_port);
+ else
+ return defaultport;
+}
+
+
+
+/* get the port number for a client to connect to based on the port
+ * and method of a cvsroot_t.
+ *
+ * we do this here instead of in parse_cvsroot so that we can keep network
+ * code confined to a localized area and also to delay the lookup until the
+ * last possible moment so it remains possible to run cvs client commands that
+ * skip opening connections to the server (i.e. skip network operations
+ * entirely)
+ *
+ * and yes, I know none of the commands do that now, but here's to planning
+ * for the future, eh? cheers.
+ */
+int
+get_cvs_port_number (const cvsroot_t *root)
+{
+
+ if (root->port) return root->port;
+
+ switch (root->method)
+ {
+# ifdef HAVE_GSSAPI
+ case gserver_method:
+# endif /* HAVE_GSSAPI */
+# ifdef AUTH_CLIENT_SUPPORT
+ case pserver_method:
+# endif /* AUTH_CLIENT_SUPPORT */
+# if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI)
+ return get_port_number ("CVS_CLIENT_PORT", "cvspserver",
+ CVS_AUTH_PORT);
+# endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */
+# ifdef HAVE_KERBEROS
+ case kserver_method:
+ return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT);
+# endif /* HAVE_KERBEROS */
+ default:
+ error(1, EINVAL,
+"internal error: get_cvs_port_number called for invalid connection method (%s)",
+ method_names[root->method]);
+ break;
+ }
+ /* NOTREACHED */
+ return -1;
+}
+
+
+
+/* get the port number for a client to connect to based on the proxy port
+ * of a cvsroot_t.
+ */
+static int
+get_proxy_port_number (const cvsroot_t *root)
+{
+
+ if (root->proxy_port) return root->proxy_port;
+
+ return get_port_number ("CVS_PROXY_PORT", NULL, CVS_PROXY_PORT);
+}
+
+
+
+void
+make_bufs_from_fds(int tofd, int fromfd, int child_pid, cvsroot_t *root,
+ struct buffer **to_server_p,
+ struct buffer **from_server_p, int is_sock)
+{
+# ifdef NO_SOCKET_TO_FD
+ if (is_sock)
+ {
+ assert (tofd == fromfd);
+ *to_server_p = socket_buffer_initialize (tofd, 0, NULL);
+ *from_server_p = socket_buffer_initialize (tofd, 1, NULL);
+ }
+ else
+# endif /* NO_SOCKET_TO_FD */
+ {
+ /* todo: some OS's don't need these calls... */
+ close_on_exec (tofd);
+ close_on_exec (fromfd);
+
+ /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
+ fdopening the same file descriptor twice, so dup it if it is the
+ same. */
+ if (tofd == fromfd)
+ {
+ fromfd = dup (tofd);
+ if (fromfd < 0)
+ error (1, errno, "cannot dup net connection");
+ }
+
+ /* These will use binary mode on systems which have it. */
+ /*
+ * Also, we know that from_server is shut down second, so we pass
+ * child_pid in there. In theory, it should be stored in both
+ * buffers with a ref count...
+ */
+ *to_server_p = fd_buffer_initialize (tofd, 0, root, false, NULL);
+ *from_server_p = fd_buffer_initialize (fromfd, child_pid, root,
+ true, NULL);
+ }
+}
+#endif /* defined (AUTH_CLIENT_SUPPORT) || defined (SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined(HAVE_GSSAPI) */
+
+
+
+#if defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI)
+/* Connect to the authenticating server.
+
+ If VERIFY_ONLY is non-zero, then just verify that the password is
+ correct and then shutdown the connection.
+
+ If VERIFY_ONLY is 0, then really connect to the server.
+
+ If DO_GSSAPI is non-zero, then we use GSSAPI authentication rather
+ than the pserver password authentication.
+
+ If we fail to connect or if access is denied, then die with fatal
+ error. */
+void
+connect_to_pserver (cvsroot_t *root, struct buffer **to_server_p,
+ struct buffer **from_server_p, int verify_only,
+ int do_gssapi)
+{
+ int sock;
+ int port_number,
+ proxy_port_number = 0; /* Initialize to silence -Wall. Dumb. */
+ union sai {
+ struct sockaddr_in addr_in;
+ struct sockaddr addr;
+ } client_sai;
+ struct hostent *hostinfo;
+ struct buffer *to_server, *from_server;
+
+ sock = socket (AF_INET, SOCK_STREAM, 0);
+ if (sock == -1)
+ error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
+ port_number = get_cvs_port_number (root);
+
+ /* if we have a proxy connect to that instead */
+ if (root->proxy_hostname)
+ {
+ proxy_port_number = get_proxy_port_number (root);
+ hostinfo = init_sockaddr (&client_sai.addr_in, root->proxy_hostname,
+ proxy_port_number);
+ TRACE (TRACE_FUNCTION, "Connecting to %s:%d via proxy %s(%s):%d.",
+ root->hostname, port_number, root->proxy_hostname,
+ inet_ntoa (client_sai.addr_in.sin_addr), proxy_port_number);
+ }
+ else
+ {
+ hostinfo = init_sockaddr (&client_sai.addr_in, root->hostname,
+ port_number);
+ TRACE (TRACE_FUNCTION, "Connecting to %s(%s):%d.",
+ root->hostname,
+ inet_ntoa (client_sai.addr_in.sin_addr), port_number);
+ }
+
+ if (connect (sock, &client_sai.addr, sizeof (client_sai))
+ < 0)
+ error (1, 0, "connect to %s(%s):%d failed: %s",
+ root->proxy_hostname ? root->proxy_hostname : root->hostname,
+ inet_ntoa (client_sai.addr_in.sin_addr),
+ root->proxy_hostname ? proxy_port_number : port_number,
+ SOCK_STRERROR (SOCK_ERRNO));
+
+ make_bufs_from_fds (sock, sock, 0, root, &to_server, &from_server, 1);
+
+ /* if we have proxy then connect to the proxy first */
+ if (root->proxy_hostname)
+ {
+#define CONNECT_STRING "CONNECT %s:%d HTTP/1.0\r\n\r\n"
+ /* Send a "CONNECT" command to proxy: */
+ char* read_buf;
+ int codenum;
+ size_t count;
+ /* 4 characters for port covered by the length of %s & %d */
+ char* write_buf = Xasnprintf (NULL, &count, CONNECT_STRING,
+ root->hostname, port_number);
+ send_to_server_via (to_server, write_buf, count);
+
+ /* Wait for HTTP status code, bail out if you don't get back a 2xx
+ * code.
+ */
+ read_line_via (from_server, to_server, &read_buf);
+ sscanf (read_buf, "%s %d", write_buf, &codenum);
+
+ if ((codenum / 100) != 2)
+ error (1, 0, "proxy server %s:%d does not support http tunnelling",
+ root->proxy_hostname, proxy_port_number);
+ free (read_buf);
+ free (write_buf);
+
+ /* Skip through remaining part of MIME header, recv_line
+ consumes the trailing \n */
+ while (read_line_via (from_server, to_server, &read_buf) > 0)
+ {
+ if (read_buf[0] == '\r' || read_buf[0] == 0)
+ {
+ free (read_buf);
+ break;
+ }
+ free (read_buf);
+ }
+ }
+
+ auth_server (root, to_server, from_server, verify_only, do_gssapi,
+ hostinfo);
+
+ if (verify_only)
+ {
+ int status;
+
+ status = buf_shutdown (to_server);
+ if (status != 0)
+ error (0, status, "shutting down buffer to server");
+ buf_free (to_server);
+ to_server = NULL;
+
+ status = buf_shutdown (from_server);
+ if (status != 0)
+ error (0, status, "shutting down buffer from server");
+ buf_free (from_server);
+ from_server = NULL;
+
+ /* Don't need to set server_started = 0 since we don't set it to 1
+ * until returning from this call.
+ */
+ }
+ else
+ {
+ *to_server_p = to_server;
+ *from_server_p = from_server;
+ }
+
+ return;
+}
+
+
+
+static void
+auth_server (cvsroot_t *root, struct buffer *to_server,
+ struct buffer *from_server, int verify_only, int do_gssapi,
+ struct hostent *hostinfo)
+{
+ char *username = NULL; /* the username we use to connect */
+ char no_passwd = 0; /* gets set if no password found */
+
+ /* Run the authorization mini-protocol before anything else. */
+ if (do_gssapi)
+ {
+# ifdef HAVE_GSSAPI
+ int fd = buf_get_fd (to_server);
+ struct stat s;
+
+ if ((fd < 0) || (fstat (fd, &s) < 0) || !S_ISSOCK(s.st_mode))
+ {
+ error (1, 0,
+ "gserver currently only enabled for socket connections");
+ }
+
+ if (! connect_to_gserver (root, fd, hostinfo))
+ {
+ error (1, 0,
+ "authorization failed: server %s rejected access to %s",
+ root->hostname, root->directory);
+ }
+# else /* ! HAVE_GSSAPI */
+ error (1, 0,
+"INTERNAL ERROR: This client does not support GSSAPI authentication");
+# endif /* HAVE_GSSAPI */
+ }
+ else /* ! do_gssapi */
+ {
+# ifdef AUTH_CLIENT_SUPPORT
+ char *begin = NULL;
+ char *password = NULL;
+ char *end = NULL;
+
+ if (verify_only)
+ {
+ begin = "BEGIN VERIFICATION REQUEST";
+ end = "END VERIFICATION REQUEST";
+ }
+ else
+ {
+ begin = "BEGIN AUTH REQUEST";
+ end = "END AUTH REQUEST";
+ }
+
+ /* Get the password, probably from ~/.cvspass. */
+ password = get_cvs_password ();
+ username = root->username ? root->username : getcaller();
+
+ /* Send the empty string by default. This is so anonymous CVS
+ access doesn't require client to have done "cvs login". */
+ if (!password)
+ {
+ no_passwd = 1;
+ password = scramble ("");
+ }
+
+ /* Announce that we're starting the authorization protocol. */
+ send_to_server_via(to_server, begin, 0);
+ send_to_server_via(to_server, "\012", 1);
+
+ /* Send the data the server needs. */
+ send_to_server_via(to_server, root->directory, 0);
+ send_to_server_via(to_server, "\012", 1);
+ send_to_server_via(to_server, username, 0);
+ send_to_server_via(to_server, "\012", 1);
+ send_to_server_via(to_server, password, 0);
+ send_to_server_via(to_server, "\012", 1);
+
+ /* Announce that we're ending the authorization protocol. */
+ send_to_server_via(to_server, end, 0);
+ send_to_server_via(to_server, "\012", 1);
+
+ /* Paranoia. */
+ memset (password, 0, strlen (password));
+# else /* ! AUTH_CLIENT_SUPPORT */
+ error (1, 0, "INTERNAL ERROR: This client does not support pserver authentication");
+# endif /* AUTH_CLIENT_SUPPORT */
+ } /* if (do_gssapi) */
+
+ {
+ char *read_buf;
+
+ /* Loop, getting responses from the server. */
+ while (1)
+ {
+ read_line_via (from_server, to_server, &read_buf);
+
+ if (!strcmp (read_buf, "I HATE YOU"))
+ {
+ /* Authorization not granted.
+ *
+ * This is a little confusing since we can reach this while
+ * loop in GSSAPI mode, but if GSSAPI authentication failed,
+ * we already jumped to the rejected label (there is no case
+ * where the connect_to_gserver function can return 1 and we
+ * will not receive "I LOVE YOU" from the server, barring
+ * broken connections and garbled messages, of course). The
+ * GSSAPI case is also the case where username can be NULL
+ * since username is initialized in the !gssapi section.
+ *
+ * i.e. This is a pserver specific error message and should be
+ * since GSSAPI doesn't use username.
+ */
+ error (0, 0,
+"authorization failed: server %s rejected access to %s for user %s",
+ root->hostname, root->directory,
+ username ? username : "(null)");
+
+ /* Output a special error message if authentication was attempted
+ with no password -- the user should be made aware that they may
+ have missed a step. */
+ if (no_passwd)
+ {
+ error (0, 0,
+"used empty password; try \"cvs login\" with a real password");
+ }
+ exit (EXIT_FAILURE);
+ }
+ else if (!strncmp (read_buf, "E ", 2))
+ {
+ fprintf (stderr, "%s\n", read_buf + 2);
+
+ /* Continue with the authentication protocol. */
+ }
+ else if (!strncmp (read_buf, "error ", 6))
+ {
+ char *p;
+
+ /* First skip the code. */
+ p = read_buf + 6;
+ while (*p != ' ' && *p != '\0')
+ ++p;
+
+ /* Skip the space that follows the code. */
+ if (*p == ' ')
+ ++p;
+
+ /* Now output the text. */
+ fprintf (stderr, "%s\n", p);
+ exit (EXIT_FAILURE);
+ }
+ else if (!strcmp (read_buf, "I LOVE YOU"))
+ {
+ free (read_buf);
+ break;
+ }
+ else
+ {
+ error (1, 0,
+ "unrecognized auth response from %s: %s",
+ root->hostname, read_buf);
+ }
+ free (read_buf);
+ }
+ }
+}
+#endif /* defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI) */
+
+
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+/*
+ * Connect to a forked server process.
+ */
+static void
+connect_to_forked_server (cvsroot_t *root, struct buffer **to_server_p,
+ struct buffer **from_server_p)
+{
+ int tofd, fromfd;
+ int child_pid;
+
+ /* This is pretty simple. All we need to do is choose the correct
+ cvs binary and call piped_child. */
+
+ char *command[3];
+
+ command[0] = (root->cvs_server
+ ? root->cvs_server : getenv ("CVS_SERVER"));
+ if (!command[0])
+# ifdef SERVER_SUPPORT
+ /* FIXME:
+ * I'm casting out the const below because I know that piped_child, the
+ * only function we pass COMMAND to, accepts COMMAND as a
+ * (char *const *) and won't alter it, and we don't alter it in this
+ * function. This is yucky, there should be a way to declare COMMAND
+ * such that this casting isn't needed, but I don't know how. If I
+ * declare it as (const char *command[]), the compiler complains about
+ * an incompatible arg 1 being passed to piped_child and if I declare
+ * it as (char *const command[3]), then the compiler complains when I
+ * assign values to command[i].
+ */
+ command[0] = (char *)program_path;
+# else /* SERVER_SUPPORT */
+ {
+ error( 0, 0, "You must set the CVS_SERVER environment variable when" );
+ error( 0, 0, "using the :fork: access method." );
+ error( 1, 0, "This CVS was not compiled with server support." );
+ }
+# endif /* SERVER_SUPPORT */
+
+ command[1] = "server";
+ command[2] = NULL;
+
+ TRACE (TRACE_FUNCTION, "Forking server: %s %s",
+ command[0] ? command[0] : "(null)", command[1]);
+
+ child_pid = piped_child (command, &tofd, &fromfd, false);
+ if (child_pid < 0)
+ error (1, 0, "could not fork server process");
+
+ make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p,
+ from_server_p, 0);
+}
+#endif /* CLIENT_SUPPORT || SERVER_SUPPORT */
+
+
+
+static int
+send_variable_proc (Node *node, void *closure)
+{
+ send_to_server ("Set ", 0);
+ send_to_server (node->key, 0);
+ send_to_server ("=", 1);
+ send_to_server (node->data, 0);
+ send_to_server ("\012", 1);
+ return 0;
+}
+
+
+
+/* Open up the connection to the server and perform any necessary
+ * authentication.
+ */
+void
+open_connection_to_server (cvsroot_t *root, struct buffer **to_server_p,
+ struct buffer **from_server_p)
+{
+ /* Note that generally speaking we do *not* fall back to a different
+ way of connecting if the first one does not work. This is slow
+ (*really* slow on a 14.4kbps link); the clean way to have a CVS
+ which supports several ways of connecting is with access methods. */
+
+ TRACE (TRACE_FUNCTION, "open_connection_to_server (%s)", root->original);
+
+ switch (root->method)
+ {
+ case pserver_method:
+#ifdef AUTH_CLIENT_SUPPORT
+ /* Toss the return value. It will die with an error message if
+ * anything goes wrong anyway.
+ */
+ connect_to_pserver (root, to_server_p, from_server_p, 0, 0);
+#else /* AUTH_CLIENT_SUPPORT */
+ error (0, 0, "CVSROOT is set for a pserver access method but your");
+ error (1, 0, "CVS executable doesn't support it.");
+#endif /* AUTH_CLIENT_SUPPORT */
+ break;
+
+ case kserver_method:
+#if HAVE_KERBEROS
+ start_kerberos4_server (root, to_server_p,
+ from_server_p);
+#else /* !HAVE_KERBEROS */
+ error (0, 0,
+ "CVSROOT is set for a kerberos access method but your");
+ error (1, 0, "CVS executable doesn't support it.");
+#endif /* HAVE_KERBEROS */
+ break;
+
+ case gserver_method:
+#ifdef HAVE_GSSAPI
+ /* GSSAPI authentication is handled by the pserver. */
+ connect_to_pserver (root, to_server_p, from_server_p, 0, 1);
+#else /* !HAVE_GSSAPI */
+ error (0, 0, "CVSROOT is set for a GSSAPI access method but your");
+ error (1, 0, "CVS executable doesn't support it.");
+#endif /* HAVE_GSSAPI */
+ break;
+
+ case ext_method:
+#ifdef NO_EXT_METHOD
+ error (0, 0, ":ext: method not supported by this port of CVS");
+ error (1, 0, "try :server: instead");
+#else /* ! NO_EXT_METHOD */
+ start_rsh_server (root, to_server_p,
+ from_server_p);
+#endif /* NO_EXT_METHOD */
+ break;
+
+ case server_method:
+#ifdef START_SERVER
+ {
+ int tofd, fromfd;
+ START_SERVER (&tofd, &fromfd, getcaller (),
+ root->username,
+ root->hostname,
+ root->directory);
+# ifdef START_SERVER_RETURNS_SOCKET
+ make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p,
+ from_server_p, 1);
+# else /* ! START_SERVER_RETURNS_SOCKET */
+ make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p,
+ from_server_p, 0);
+# endif /* START_SERVER_RETURNS_SOCKET */
+ }
+#else /* ! START_SERVER */
+ /* FIXME: It should be possible to implement this portably,
+ like pserver, which would get rid of the duplicated code
+ in {vms,windows-NT,...}/startserver.c. */
+ error (1, 0,
+"the :server: access method is not supported by this port of CVS");
+#endif /* START_SERVER */
+ break;
+
+ case fork_method:
+ connect_to_forked_server (root, to_server_p, from_server_p);
+ break;
+
+ default:
+ error (1, 0,
+ "(start_server internal error): unknown access method");
+ break;
+ }
+
+ /* "Hi, I'm Darlene and I'll be your server tonight..." */
+ server_started = 1;
+}
+
+
+
+/* Contact the server. */
+void
+start_server (void)
+{
+ bool rootless;
+ int status;
+ bool have_global;
+
+ do
+ {
+ /* Clear our static variables for this invocation. */
+ if (toplevel_repos)
+ free (toplevel_repos);
+ toplevel_repos = NULL;
+
+ open_connection_to_server (current_parsed_root, &global_to_server,
+ &global_from_server);
+ setup_logfiles ("CVS_CLIENT_LOG", &global_to_server,
+ &global_from_server);
+
+ /* Clear static variables. */
+ if (toplevel_repos)
+ {
+ free (toplevel_repos);
+ toplevel_repos = NULL;
+ }
+ if (last_repos)
+ {
+ free (last_repos);
+ last_repos = NULL;
+ }
+ if (last_update_dir)
+ {
+ free (last_update_dir);
+ last_update_dir = NULL;
+ }
+ stored_checksum_valid = 0;
+ if (stored_mode)
+ {
+ free (stored_mode);
+ stored_mode = NULL;
+ }
+
+ rootless = !strcmp (cvs_cmd_name, "init");
+ if (!rootless)
+ {
+ send_to_server ("Root ", 0);
+ send_to_server (current_parsed_root->directory, 0);
+ send_to_server ("\012", 1);
+ }
+
+ {
+ struct response *rs;
+ bool suppress_redirect = !current_parsed_root->redirect;
+
+ send_to_server ("Valid-responses", 0);
+
+ for (rs = responses; rs->name; ++rs)
+ {
+ if (suppress_redirect && !strcmp (rs->name, "Redirect"))
+ continue;
+
+ send_to_server (" ", 0);
+ send_to_server (rs->name, 0);
+ }
+ send_to_server ("\012", 1);
+ }
+ send_to_server ("valid-requests\012", 0);
+
+ if (get_server_responses ())
+ exit (EXIT_FAILURE);
+
+ have_global = supported_request ("Global_option");
+
+ /* Encryption needs to come before compression. Good encryption can
+ * render compression useless in the other direction.
+ */
+ if (cvsencrypt && !rootless)
+ {
+#ifdef ENCRYPTION
+ /* Turn on encryption before turning on compression. We do
+ * not want to try to compress the encrypted stream. Instead,
+ * we want to encrypt the compressed stream. If we can't turn
+ * on encryption, bomb out; don't let the user think the data
+ * is being encrypted when it is not.
+ */
+# ifdef HAVE_KERBEROS
+ if (current_parsed_root->method == kserver_method)
+ {
+ if (!supported_request ("Kerberos-encrypt"))
+ error (1, 0, "This server does not support encryption");
+ send_to_server ("Kerberos-encrypt\012", 0);
+ initialize_kerberos4_encryption_buffers (&global_to_server,
+ &global_from_server);
+ }
+ else
+# endif /* HAVE_KERBEROS */
+# ifdef HAVE_GSSAPI
+ if (current_parsed_root->method == gserver_method)
+ {
+ if (!supported_request ("Gssapi-encrypt"))
+ error (1, 0, "This server does not support encryption");
+ send_to_server ("Gssapi-encrypt\012", 0);
+ initialize_gssapi_buffers (&global_to_server,
+ &global_from_server);
+ cvs_gssapi_encrypt = 1;
+ }
+ else
+# endif /* HAVE_GSSAPI */
+ error (1, 0,
+"Encryption is only supported when using GSSAPI or Kerberos");
+#else /* ! ENCRYPTION */
+ error (1, 0, "This client does not support encryption");
+#endif /* ! ENCRYPTION */
+ }
+
+ /* Send this before compression to enable supression of the
+ * "Forcing compression level Z" messages.
+ */
+ if (quiet)
+ {
+ if (have_global)
+ {
+ send_to_server ("Global_option -q\012", 0);
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -q option.");
+ }
+ if (really_quiet)
+ {
+ if (have_global)
+ {
+ send_to_server ("Global_option -Q\012", 0);
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -Q option.");
+ }
+
+ /* Compression needs to come before any of the rooted requests to
+ * work with compression limits.
+ */
+ if (!rootless && (gzip_level || force_gzip))
+ {
+ if (supported_request ("Gzip-stream"))
+ {
+ char *gzip_level_buf = Xasprintf ("%d", gzip_level);
+ send_to_server ("Gzip-stream ", 0);
+ send_to_server (gzip_level_buf, 0);
+ free (gzip_level_buf);
+ send_to_server ("\012", 1);
+
+ /* All further communication with the server will be
+ compressed. */
+
+ global_to_server =
+ compress_buffer_initialize (global_to_server, 0,
+ gzip_level, NULL);
+ global_from_server =
+ compress_buffer_initialize (global_from_server, 1,
+ gzip_level, NULL);
+ }
+#ifndef NO_CLIENT_GZIP_PROCESS
+ else if (supported_request ("gzip-file-contents"))
+ {
+ char *gzip_level_buf = Xasprintf ("%d", gzip_level);
+ send_to_server ("gzip-file-contents ", 0);
+ send_to_server (gzip_level_buf, 0);
+ free (gzip_level_buf);
+ send_to_server ("\012", 1);
+
+ file_gzip_level = gzip_level;
+ }
+#endif
+ else
+ {
+ fprintf (stderr, "server doesn't support gzip-file-contents\n");
+ /* Setting gzip_level to 0 prevents us from giving the
+ error twice if update has to contact the server again
+ to fetch unpatchable files. */
+ gzip_level = 0;
+ }
+ }
+
+ if (client_referrer && supported_request ("Referrer"))
+ {
+ send_to_server ("Referrer ", 0);
+ send_to_server (client_referrer->original, 0);
+ send_to_server ("\012", 0);
+ }
+
+ /* FIXME: I think we should still be sending this for init. */
+ if (!rootless && supported_request ("Command-prep"))
+ {
+ send_to_server ("Command-prep ", 0);
+ send_to_server (cvs_cmd_name, 0);
+ send_to_server ("\012", 0);
+ status = get_server_responses ();
+ if (status == 1) exit (EXIT_FAILURE);
+ if (status == 2) close_connection_to_server (&global_to_server,
+ &global_from_server);
+ }
+ else status = 0;
+ } while (status == 2);
+
+
+ /*
+ * Now handle global options.
+ *
+ * -H, -f, -d, -e should be handled OK locally.
+ *
+ * -b we ignore (treating it as a server installation issue).
+ * FIXME: should be an error message.
+ *
+ * -v we print local version info; FIXME: Add a protocol request to get
+ * the version from the server so we can print that too.
+ *
+ * -l -t -r -w -q -n and -Q need to go to the server.
+ */
+ if (noexec)
+ {
+ if (have_global)
+ {
+ send_to_server ("Global_option -n\012", 0);
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -n option.");
+ }
+ if (!cvswrite)
+ {
+ if (have_global)
+ {
+ send_to_server ("Global_option -r\012", 0);
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -r option.");
+ }
+ if (trace)
+ {
+ if (have_global)
+ {
+ int count = trace;
+ while (count--) send_to_server ("Global_option -t\012", 0);
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -t option.");
+ }
+
+ /* Find out about server-side cvswrappers. An extra network
+ turnaround for cvs import seems to be unavoidable, unless we
+ want to add some kind of client-side place to configure which
+ filenames imply binary. For cvs add, we could avoid the
+ problem by keeping a copy of the wrappers in CVSADM (the main
+ reason to bother would be so we could make add work without
+ contacting the server, I suspect). */
+
+ if (!strcmp (cvs_cmd_name, "import") || !strcmp (cvs_cmd_name, "add"))
+ {
+ if (supported_request ("wrapper-sendme-rcsOptions"))
+ {
+ int err;
+ send_to_server ("wrapper-sendme-rcsOptions\012", 0);
+ err = get_server_responses ();
+ if (err != 0)
+ error (err, 0, "error reading from server");
+ }
+ }
+
+ if (cvsauthenticate && ! cvsencrypt && !rootless)
+ {
+ /* Turn on authentication after turning on compression, so
+ that we can compress the authentication information. We
+ assume that encrypted data is always authenticated--the
+ ability to decrypt the data stream is itself a form of
+ authentication. */
+#ifdef HAVE_GSSAPI
+ if (current_parsed_root->method == gserver_method)
+ {
+ if (! supported_request ("Gssapi-authenticate"))
+ error (1, 0,
+ "This server does not support stream authentication");
+ send_to_server ("Gssapi-authenticate\012", 0);
+ initialize_gssapi_buffers(&global_to_server, &global_from_server);
+
+ }
+ else
+ error (1, 0, "Stream authentication is only supported when using GSSAPI");
+#else /* ! HAVE_GSSAPI */
+ error (1, 0, "This client does not support stream authentication");
+#endif /* ! HAVE_GSSAPI */
+ }
+
+ /* If "Set" is not supported, just silently fail to send the variables.
+ Users with an old server should get a useful error message when it
+ fails to recognize the ${=foo} syntax. This way if someone uses
+ several servers, some of which are new and some old, they can still
+ set user variables in their .cvsrc without trouble. */
+ if (supported_request ("Set"))
+ walklist (variable_list, send_variable_proc, NULL);
+}
+
+
+
+/* Send an argument STRING. */
+void
+send_arg (const char *string)
+{
+ const char *p = string;
+
+ send_to_server ("Argument ", 0);
+
+ while (*p)
+ {
+ if (*p == '\n')
+ send_to_server ("\012Argumentx ", 0);
+ else
+ send_to_server (p, 1);
+ ++p;
+ }
+ send_to_server ("\012", 1);
+}
+
+
+
+/* VERS->OPTIONS specifies whether the file is binary or not. NOTE: BEFORE
+ using any other fields of the struct vers, we would need to fix
+ client_process_import_file to set them up. */
+static void
+send_modified (const char *file, const char *short_pathname, Vers_TS *vers)
+{
+ /* File was modified, send it. */
+ struct stat sb;
+ int fd;
+ unsigned char *buf;
+ char *mode_string;
+ size_t bufsize;
+ int bin;
+
+ TRACE (TRACE_FUNCTION, "Sending file `%s' to server", file);
+
+ /* Don't think we can assume fstat exists. */
+ if (stat (file, &sb) < 0)
+ error (1, errno, "reading %s", short_pathname);
+
+ mode_string = mode_to_string (sb.st_mode);
+
+ /* Beware: on systems using CRLF line termination conventions,
+ the read and write functions will convert CRLF to LF, so the
+ number of characters read is not the same as sb.st_size. Text
+ files should always be transmitted using the LF convention, so
+ we don't want to disable this conversion. */
+ bufsize = sb.st_size;
+ buf = xmalloc (bufsize);
+
+ /* Is the file marked as containing binary data by the "-kb" flag?
+ If so, make sure to open it in binary mode: */
+
+ if (vers && vers->options)
+ bin = !strcmp (vers->options, "-kb");
+ else
+ bin = 0;
+
+#ifdef BROKEN_READWRITE_CONVERSION
+ if (!bin)
+ {
+ /* If only stdio, not open/write/etc., do text/binary
+ conversion, use convert_file which can compensate
+ (FIXME: we could just use stdio instead which would
+ avoid the whole problem). */
+ char *tfile = Xasprintf ("%s.CVSBFCTMP", file);
+ convert_file (file, O_RDONLY,
+ tfile, O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY);
+ fd = CVS_OPEN (tfile, O_RDONLY | OPEN_BINARY);
+ if (fd < 0)
+ error (1, errno, "reading %s", short_pathname);
+ free (tfile);
+ }
+ else
+ fd = CVS_OPEN (file, O_RDONLY | OPEN_BINARY);
+#else
+ fd = CVS_OPEN (file, O_RDONLY | (bin ? OPEN_BINARY : 0));
+#endif
+
+ if (fd < 0)
+ error (1, errno, "reading %s", short_pathname);
+
+ if (file_gzip_level && sb.st_size > 100)
+ {
+ size_t newsize = 0;
+
+ if (read_and_gzip (fd, short_pathname, &buf,
+ &bufsize, &newsize,
+ file_gzip_level))
+ error (1, 0, "aborting due to compression error");
+
+ if (close (fd) < 0)
+ error (0, errno, "warning: can't close %s", short_pathname);
+
+ {
+ char tmp[80];
+
+ send_to_server ("Modified ", 0);
+ send_to_server (file, 0);
+ send_to_server ("\012", 1);
+ send_to_server (mode_string, 0);
+ send_to_server ("\012z", 2);
+ sprintf (tmp, "%lu\n", (unsigned long) newsize);
+ send_to_server (tmp, 0);
+
+ send_to_server (buf, newsize);
+ }
+ }
+ else
+ {
+ int newsize;
+
+ {
+ unsigned char *bufp = buf;
+ int len;
+
+ /* FIXME: This is gross. It assumes that we might read
+ less than st_size bytes (true on NT), but not more.
+ Instead of this we should just be reading a block of
+ data (e.g. 8192 bytes), writing it to the network, and
+ so on until EOF. */
+ while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0)
+ bufp += len;
+
+ if (len < 0)
+ error (1, errno, "reading %s", short_pathname);
+
+ newsize = bufp - buf;
+ }
+ if (close (fd) < 0)
+ error (0, errno, "warning: can't close %s", short_pathname);
+
+ {
+ char tmp[80];
+
+ send_to_server ("Modified ", 0);
+ send_to_server (file, 0);
+ send_to_server ("\012", 1);
+ send_to_server (mode_string, 0);
+ send_to_server ("\012", 1);
+ sprintf (tmp, "%lu\012", (unsigned long) newsize);
+ send_to_server (tmp, 0);
+ }
+#ifdef BROKEN_READWRITE_CONVERSION
+ if (!bin)
+ {
+ char *tfile = Xasprintf ("%s.CVSBFCTMP", file);
+ if (CVS_UNLINK (tfile) < 0)
+ error (0, errno, "warning: can't remove temp file %s", tfile);
+ free (tfile);
+ }
+#endif
+
+ /*
+ * Note that this only ends with a newline if the file ended with
+ * one.
+ */
+ if (newsize > 0)
+ send_to_server (buf, newsize);
+ }
+ free (buf);
+ free (mode_string);
+}
+
+
+
+/* The address of an instance of this structure is passed to
+ send_fileproc, send_filesdoneproc, and send_direntproc, as the
+ callerdat parameter. */
+struct send_data
+{
+ /* Each of the following flags are zero for clear or nonzero for set. */
+ int build_dirs;
+ int force;
+ int no_contents;
+ int backup_modified;
+};
+
+/* Deal with one file. */
+static int
+send_fileproc (void *callerdat, struct file_info *finfo)
+{
+ struct send_data *args = callerdat;
+ Vers_TS *vers;
+ struct file_info xfinfo;
+ /* File name to actually use. Might differ in case from
+ finfo->file. */
+ const char *filename;
+
+ send_a_repository ("", finfo->repository, finfo->update_dir);
+
+ xfinfo = *finfo;
+ xfinfo.repository = NULL;
+ xfinfo.rcs = NULL;
+ vers = Version_TS (&xfinfo, NULL, NULL, NULL, 0, 0);
+
+ if (vers->entdata)
+ filename = vers->entdata->user;
+ else
+ filename = finfo->file;
+
+ if (vers->vn_user)
+ {
+ /* The Entries request. */
+ send_to_server ("Entry /", 0);
+ send_to_server (filename, 0);
+ send_to_server ("/", 0);
+ send_to_server (vers->vn_user, 0);
+ send_to_server ("/", 0);
+ if (vers->ts_conflict)
+ {
+ if (vers->ts_user && !strcmp (vers->ts_conflict, vers->ts_user))
+ send_to_server ("+=", 0);
+ else
+ send_to_server ("+modified", 0);
+ }
+ send_to_server ("/", 0);
+ send_to_server (vers->entdata ? vers->entdata->options : vers->options,
+ 0);
+ send_to_server ("/", 0);
+ if (vers->entdata && vers->entdata->tag)
+ {
+ send_to_server ("T", 0);
+ send_to_server (vers->entdata->tag, 0);
+ }
+ else if (vers->entdata && vers->entdata->date)
+ {
+ send_to_server ("D", 0);
+ send_to_server (vers->entdata->date, 0);
+ }
+ send_to_server ("\012", 1);
+ }
+ else
+ {
+ /* It seems a little silly to re-read this on each file, but
+ send_dirent_proc doesn't get called if filenames are specified
+ explicitly on the command line. */
+ wrap_add_file (CVSDOTWRAPPER, 1);
+
+ if (wrap_name_has (filename, WRAP_RCSOPTION))
+ {
+ /* No "Entry", but the wrappers did give us a kopt so we better
+ send it with "Kopt". As far as I know this only happens
+ for "cvs add". Question: is there any reason why checking
+ for options from wrappers isn't done in Version_TS?
+
+ Note: it might have been better to just remember all the
+ kopts on the client side, rather than send them to the server,
+ and have it send us back the same kopts. But that seemed like
+ a bigger change than I had in mind making now. */
+
+ if (supported_request ("Kopt"))
+ {
+ char *opt;
+
+ send_to_server ("Kopt ", 0);
+ opt = wrap_rcsoption (filename, 1);
+ send_to_server (opt, 0);
+ send_to_server ("\012", 1);
+ free (opt);
+ }
+ else
+ error (0, 0, "\
+warning: ignoring -k options due to server limitations");
+ }
+ }
+
+ if (!vers->ts_user)
+ {
+ /*
+ * Do we want to print "file was lost" like normal CVS?
+ * Would it always be appropriate?
+ */
+ /* File no longer exists. Don't do anything, missing files
+ just happen. */
+ }
+ else if (!vers->ts_rcs || args->force
+ || strcmp (vers->ts_conflict
+ ? vers->ts_conflict : vers->ts_rcs, vers->ts_user)
+ || (vers->ts_conflict && !strcmp (cvs_cmd_name, "diff")))
+ {
+ if (args->no_contents
+ && supported_request ("Is-modified"))
+ {
+ send_to_server ("Is-modified ", 0);
+ send_to_server (filename, 0);
+ send_to_server ("\012", 1);
+ }
+ else
+ send_modified (filename, finfo->fullname, vers);
+
+ if (args->backup_modified)
+ {
+ char *bakname;
+ bakname = backup_file (filename, vers->vn_user);
+ /* This behavior is sufficiently unexpected to
+ justify overinformativeness, I think. */
+ if (! really_quiet)
+ printf ("(Locally modified %s moved to %s)\n",
+ filename, bakname);
+ free (bakname);
+ }
+ }
+ else
+ {
+ send_to_server ("Unchanged ", 0);
+ send_to_server (filename, 0);
+ send_to_server ("\012", 1);
+ }
+
+ /* if this directory has an ignore list, add this file to it */
+ if (ignlist)
+ {
+ Node *p;
+
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (finfo->file);
+ (void) addnode (ignlist, p);
+ }
+
+ freevers_ts (&vers);
+ return 0;
+}
+
+
+
+static void
+send_ignproc (const char *file, const char *dir)
+{
+ if (ign_inhibit_server || !supported_request ("Questionable"))
+ {
+ if (dir[0] != '\0')
+ (void) printf ("? %s/%s\n", dir, file);
+ else
+ (void) printf ("? %s\n", file);
+ }
+ else
+ {
+ send_to_server ("Questionable ", 0);
+ send_to_server (file, 0);
+ send_to_server ("\012", 1);
+ }
+}
+
+
+
+static int
+send_filesdoneproc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ /* if this directory has an ignore list, process it then free it */
+ if (ignlist)
+ {
+ ignore_files (ignlist, entries, update_dir, send_ignproc);
+ dellist (&ignlist);
+ }
+
+ return err;
+}
+
+
+
+/*
+ * send_dirent_proc () is called back by the recursion processor before a
+ * sub-directory is processed for update.
+ * A return code of 0 indicates the directory should be
+ * processed by the recursion code. A return of non-zero indicates the
+ * recursion code should skip this directory.
+ *
+ */
+static Dtype
+send_dirent_proc (void *callerdat, const char *dir, const char *repository,
+ const char *update_dir, List *entries)
+{
+ struct send_data *args = callerdat;
+ int dir_exists;
+ char *cvsadm_name;
+
+ if (ignore_directory (update_dir))
+ {
+ /* print the warm fuzzy message */
+ if (!quiet)
+ error (0, 0, "Ignoring %s", update_dir);
+ return R_SKIP_ALL;
+ }
+
+ /*
+ * If the directory does not exist yet (e.g. "cvs update -d foo"),
+ * no need to send any files from it. If the directory does not
+ * have a CVS directory, then we pretend that it does not exist.
+ * Otherwise, we will fail when trying to open the Entries file.
+ * This case will happen when checking out a module defined as
+ * ``-a .''.
+ */
+ cvsadm_name = Xasprintf ("%s/%s", dir, CVSADM);
+ dir_exists = isdir (cvsadm_name);
+ free (cvsadm_name);
+
+ /*
+ * If there is an empty directory (e.g. we are doing `cvs add' on a
+ * newly-created directory), the server still needs to know about it.
+ */
+
+ if (dir_exists)
+ {
+ /*
+ * Get the repository from a CVS/Repository file whenever possible.
+ * The repository variable is wrong if the names in the local
+ * directory don't match the names in the repository.
+ */
+ char *repos = Name_Repository (dir, update_dir);
+ send_a_repository (dir, repos, update_dir);
+ free (repos);
+
+ /* initialize the ignore list for this directory */
+ ignlist = getlist ();
+ }
+ else
+ {
+ /* It doesn't make sense to send a non-existent directory,
+ because there is no way to get the correct value for
+ the repository (I suppose maybe via the expand-modules
+ request). In the case where the "obvious" choice for
+ repository is correct, the server can figure out whether
+ to recreate the directory; in the case where it is wrong
+ (that is, does not match what modules give us), we might as
+ well just fail to recreate it.
+
+ Checking for noexec is a kludge for "cvs -n add dir". */
+ /* Don't send a non-existent directory unless we are building
+ new directories (build_dirs is true). Otherwise, CVS may
+ see a D line in an Entries file, and recreate a directory
+ which the user removed by hand. */
+ if (args->build_dirs && noexec)
+ send_a_repository (dir, repository, update_dir);
+ }
+
+ return dir_exists ? R_PROCESS : R_SKIP_ALL;
+}
+
+
+
+/*
+ * send_dirleave_proc () is called back by the recursion code upon leaving
+ * a directory. All it does is delete the ignore list if it hasn't already
+ * been done (by send_filesdone_proc).
+ */
+/* ARGSUSED */
+static int
+send_dirleave_proc (void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries )
+{
+
+ /* Delete the ignore list if it hasn't already been done. */
+ if (ignlist)
+ dellist (&ignlist);
+ return err;
+}
+
+
+
+/*
+ * Send each option in an array to the server, one by one.
+ * argv might be "--foo=bar", "-C", "5", "-y".
+ */
+
+void
+send_options (int argc, char * const *argv)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ send_arg (argv[i]);
+}
+
+
+
+/* Send the names of all the argument files to the server. */
+void
+send_file_names (int argc, char **argv, unsigned int flags)
+{
+ int i;
+
+ /* The fact that we do this here as well as start_recursion is a bit
+ of a performance hit. Perhaps worth cleaning up someday. */
+ if (flags & SEND_EXPAND_WILD)
+ expand_wild (argc, argv, &argc, &argv);
+
+ for (i = 0; i < argc; ++i)
+ {
+ char buf[1];
+ char *p;
+#ifdef FILENAMES_CASE_INSENSITIVE
+ char *line = NULL;
+#endif /* FILENAMES_CASE_INSENSITIVE */
+
+ if (arg_should_not_be_sent_to_server (argv[i]))
+ continue;
+
+#ifdef FILENAMES_CASE_INSENSITIVE
+ /* We want to send the path as it appears in the
+ CVS/Entries files. We put this inside an ifdef
+ to avoid doing all these system calls in
+ cases where fncmp is just strcmp anyway. */
+ /* The isdir (CVSADM) check could more gracefully be replaced
+ with a way of having Entries_Open report back the
+ error to us and letting us ignore existence_error.
+ Or some such. */
+ {
+ List *stack;
+ size_t line_len = 0;
+ char *q, *r;
+ struct saved_cwd sdir;
+
+ /* Split the argument onto the stack. */
+ stack = getlist();
+ r = xstrdup (argv[i]);
+ /* It's okay to discard the const from the last_component return
+ * below since we know we passed in an arg that was not const.
+ */
+ while ((q = (char *)last_component (r)) != r)
+ {
+ push (stack, xstrdup (q));
+ *--q = '\0';
+ }
+ push (stack, r);
+
+ /* Normalize the path into outstr. */
+ save_cwd (&sdir);
+ while (q = pop (stack))
+ {
+ Node *node = NULL;
+ if (isdir (CVSADM))
+ {
+ List *entries;
+
+ /* Note that if we are adding a directory,
+ the following will read the entry
+ that we just wrote there, that is, we
+ will get the case specified on the
+ command line, not the case of the
+ directory in the filesystem. This
+ is correct behavior. */
+ entries = Entries_Open (0, NULL);
+ node = findnode_fn (entries, q);
+ if (node)
+ {
+ /* Add the slash unless this is our first element. */
+ if (line_len)
+ xrealloc_and_strcat (&line, &line_len, "/");
+ xrealloc_and_strcat (&line, &line_len, node->key);
+ delnode (node);
+ }
+ Entries_Close (entries);
+ }
+
+ /* If node is still NULL then we either didn't find CVSADM or
+ * we didn't find an entry there.
+ */
+ if (!node)
+ {
+ /* Add the slash unless this is our first element. */
+ if (line_len)
+ xrealloc_and_strcat (&line, &line_len, "/");
+ xrealloc_and_strcat (&line, &line_len, q);
+ break;
+ }
+
+ /* And descend the tree. */
+ if (isdir (q))
+ CVS_CHDIR (q);
+ free (q);
+ }
+ restore_cwd (&sdir);
+ free_cwd (&sdir);
+
+ /* Now put everything we didn't find entries for back on. */
+ while (q = pop (stack))
+ {
+ if (line_len)
+ xrealloc_and_strcat (&line, &line_len, "/");
+ xrealloc_and_strcat (&line, &line_len, q);
+ free (q);
+ }
+
+ p = line;
+
+ dellist (&stack);
+ }
+#else /* !FILENAMES_CASE_INSENSITIVE */
+ p = argv[i];
+#endif /* FILENAMES_CASE_INSENSITIVE */
+
+ send_to_server ("Argument ", 0);
+
+ while (*p)
+ {
+ if (*p == '\n')
+ {
+ send_to_server ("\012Argumentx ", 0);
+ }
+ else if (ISSLASH (*p))
+ {
+ buf[0] = '/';
+ send_to_server (buf, 1);
+ }
+ else
+ {
+ buf[0] = *p;
+ send_to_server (buf, 1);
+ }
+ ++p;
+ }
+ send_to_server ("\012", 1);
+#ifdef FILENAMES_CASE_INSENSITIVE
+ free (line);
+#endif /* FILENAMES_CASE_INSENSITIVE */
+ }
+
+ if (flags & SEND_EXPAND_WILD)
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ free (argv[i]);
+ free (argv);
+ }
+}
+
+
+
+/* Calculate and send max-dotdot to the server */
+static void
+send_max_dotdot (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ int level = 0;
+ int max_level = 0;
+
+ /* Send Max-dotdot if needed. */
+ for (i = 0; i < argc; ++i)
+ {
+ level = pathname_levels (argv[i]);
+ if (level > 0)
+ {
+ if (!uppaths) uppaths = getlist();
+ push_string (uppaths, xstrdup (argv[i]));
+ }
+ if (level > max_level)
+ max_level = level;
+ }
+
+ if (max_level > 0)
+ {
+ if (supported_request ("Max-dotdot"))
+ {
+ char buf[10];
+ sprintf (buf, "%d", max_level);
+
+ send_to_server ("Max-dotdot ", 0);
+ send_to_server (buf, 0);
+ send_to_server ("\012", 1);
+ }
+ else
+ {
+ error (1, 0,
+"backreference in path (`..') not supported by old (pre-Max-dotdot) servers");
+ }
+ }
+}
+
+
+
+/* Send Repository, Modified and Entry. argc and argv contain only
+ the files to operate on (or empty for everything), not options.
+ local is nonzero if we should not recurse (-l option). flags &
+ SEND_BUILD_DIRS is nonzero if nonexistent directories should be
+ sent. flags & SEND_FORCE is nonzero if we should send unmodified
+ files to the server as though they were modified. flags &
+ SEND_NO_CONTENTS means that this command only needs to know
+ _whether_ a file is modified, not the contents. Also sends Argument
+ lines for argc and argv, so should be called after options are sent. */
+void
+send_files (int argc, char **argv, int local, int aflag, unsigned int flags)
+{
+ struct send_data args;
+ int err;
+
+ send_max_dotdot (argc, argv);
+
+ /*
+ * aflag controls whether the tag/date is copied into the vers_ts.
+ * But we don't actually use it, so I don't think it matters what we pass
+ * for aflag here.
+ */
+ args.build_dirs = flags & SEND_BUILD_DIRS;
+ args.force = flags & SEND_FORCE;
+ args.no_contents = flags & SEND_NO_CONTENTS;
+ args.backup_modified = flags & BACKUP_MODIFIED_FILES;
+ err = start_recursion
+ (send_fileproc, send_filesdoneproc, send_dirent_proc,
+ send_dirleave_proc, &args, argc, argv, local, W_LOCAL, aflag,
+ CVS_LOCK_NONE, NULL, 0, NULL);
+ if (err)
+ exit (EXIT_FAILURE);
+ if (!toplevel_repos)
+ /*
+ * This happens if we are not processing any files,
+ * or for checkouts in directories without any existing stuff
+ * checked out. The following assignment is correct for the
+ * latter case; I don't think toplevel_repos matters for the
+ * former.
+ */
+ toplevel_repos = xstrdup (current_parsed_root->directory);
+ send_repository ("", toplevel_repos, ".");
+}
+
+
+
+void
+client_import_setup (char *repository)
+{
+ if (!toplevel_repos) /* should always be true */
+ send_a_repository ("", repository, "");
+}
+
+
+
+/*
+ * Process the argument import file.
+ */
+int
+client_process_import_file (char *message, char *vfile, char *vtag, int targc,
+ char *targv[], char *repository,
+ int all_files_binary,
+ int modtime /* Nonzero for "import -d". */ )
+{
+ char *update_dir;
+ char *fullname;
+ Vers_TS vers;
+
+ assert (toplevel_repos);
+
+ if (strncmp (repository, toplevel_repos, strlen (toplevel_repos)))
+ error (1, 0,
+ "internal error: pathname `%s' doesn't specify file in `%s'",
+ repository, toplevel_repos);
+
+ if (!strcmp (repository, toplevel_repos))
+ {
+ update_dir = "";
+ fullname = xstrdup (vfile);
+ }
+ else
+ {
+ update_dir = repository + strlen (toplevel_repos) + 1;
+
+ fullname = Xasprintf ("%s/%s", update_dir, vfile);
+ }
+
+ send_a_repository ("", repository, update_dir);
+ if (all_files_binary)
+ vers.options = xstrdup ("-kb");
+ else
+ vers.options = wrap_rcsoption (vfile, 1);
+
+ if (vers.options)
+ {
+ if (supported_request ("Kopt"))
+ {
+ send_to_server ("Kopt ", 0);
+ send_to_server (vers.options, 0);
+ send_to_server ("\012", 1);
+ }
+ else
+ error (0, 0,
+ "warning: ignoring -k options due to server limitations");
+ }
+ if (modtime)
+ {
+ if (supported_request ("Checkin-time"))
+ {
+ struct stat sb;
+ char *rcsdate;
+ char netdate[MAXDATELEN];
+
+ if (stat (vfile, &sb) < 0)
+ error (1, errno, "cannot stat %s", fullname);
+ rcsdate = date_from_time_t (sb.st_mtime);
+ date_to_internet (netdate, rcsdate);
+ free (rcsdate);
+
+ send_to_server ("Checkin-time ", 0);
+ send_to_server (netdate, 0);
+ send_to_server ("\012", 1);
+ }
+ else
+ error (0, 0,
+ "warning: ignoring -d option due to server limitations");
+ }
+ send_modified (vfile, fullname, &vers);
+ if (vers.options)
+ free (vers.options);
+ free (fullname);
+ return 0;
+}
+
+
+
+void
+client_import_done (void)
+{
+ if (!toplevel_repos)
+ /*
+ * This happens if we are not processing any files,
+ * or for checkouts in directories without any existing stuff
+ * checked out. The following assignment is correct for the
+ * latter case; I don't think toplevel_repos matters for the
+ * former.
+ */
+ /* FIXME: "can't happen" now that we call client_import_setup
+ at the beginning. */
+ toplevel_repos = xstrdup (current_parsed_root->directory);
+ send_repository ("", toplevel_repos, ".");
+}
+
+
+
+void
+client_notify (const char *repository, const char *update_dir,
+ const char *filename, int notif_type, const char *val)
+{
+ char buf[2];
+
+ send_a_repository ("", repository, update_dir);
+ send_to_server ("Notify ", 0);
+ send_to_server (filename, 0);
+ send_to_server ("\012", 1);
+ buf[0] = notif_type;
+ buf[1] = '\0';
+ send_to_server (buf, 1);
+ send_to_server ("\t", 1);
+ send_to_server (val, 0);
+}
+
+
+
+/*
+ * Send an option with an argument, dealing correctly with newlines in
+ * the argument. If ARG is NULL, forget the whole thing.
+ */
+void
+option_with_arg (const char *option, const char *arg)
+{
+ if (!arg)
+ return;
+
+ send_to_server ("Argument ", 0);
+ send_to_server (option, 0);
+ send_to_server ("\012", 1);
+
+ send_arg (arg);
+}
+
+
+
+/* Send a date to the server. The input DATE is in RCS format.
+ The time will be GMT.
+
+ We then convert that to the format required in the protocol
+ (including the "-D" option) and send it. According to
+ cvsclient.texi, RFC 822/1123 format is preferred. */
+void
+client_senddate (const char *date)
+{
+ char buf[MAXDATELEN];
+
+ date_to_internet (buf, date);
+ option_with_arg ("-D", buf);
+}
+
+
+
+void
+send_init_command (void)
+{
+ /* This is here because we need the current_parsed_root->directory variable. */
+ send_to_server ("init ", 0);
+ send_to_server (current_parsed_root->directory, 0);
+ send_to_server ("\012", 0);
+}
+
+
+
+#if defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS || defined HAVE_GSSAPI
+
+struct hostent *
+init_sockaddr (struct sockaddr_in *name, char *hostname, unsigned int port)
+{
+ struct hostent *hostinfo;
+ unsigned short shortport = port;
+
+ memset (name, 0, sizeof (*name));
+ name->sin_family = AF_INET;
+ name->sin_port = htons (shortport);
+ hostinfo = gethostbyname (hostname);
+ if (!hostinfo)
+ {
+ fprintf (stderr, "Unknown host %s.\n", hostname);
+ exit (EXIT_FAILURE);
+ }
+ name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
+ return hostinfo;
+}
+
+#endif /* defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS
+ * || defined HAVE_GSSAPI
+ */
+
+#endif /* CLIENT_SUPPORT */
diff --git a/src/client.h b/src/client.h
new file mode 100644
index 0000000..add35c1
--- /dev/null
+++ b/src/client.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Interface between the client and the rest of CVS. */
+
+/* Stuff shared with the server. */
+char *mode_to_string (mode_t);
+int change_mode (const char *, const char *, int);
+
+extern int gzip_level;
+extern int file_gzip_level;
+
+struct buffer;
+
+void make_bufs_from_fds (int, int, int, cvsroot_t *,
+ struct buffer **, struct buffer **, int);
+
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+
+/* Whether the connection should be encrypted. */
+extern int cvsencrypt;
+
+/* Whether the connection should use per-packet authentication. */
+extern int cvsauthenticate;
+
+# ifdef ENCRYPTION
+
+# ifdef HAVE_KERBEROS
+
+/* We can't declare the arguments without including krb.h, and I don't
+ want to do that in every file. */
+extern struct buffer *krb_encrypt_buffer_initialize ();
+
+# endif /* HAVE_KERBEROS */
+
+# endif /* ENCRYPTION */
+
+#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+
+#ifdef CLIENT_SUPPORT
+/*
+ * Flag variable for seeing whether the server has been started yet.
+ * As of this writing, only edit.c:notify_check() uses it.
+ */
+extern int server_started;
+
+/* Is the -P option to checkout or update specified? */
+extern int client_prune_dirs;
+
+# ifdef AUTH_CLIENT_SUPPORT
+extern int use_authenticating_server;
+# endif /* AUTH_CLIENT_SUPPORT */
+# if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI)
+void connect_to_pserver (cvsroot_t *, struct buffer **, struct buffer **,
+ int, int );
+# ifndef CVS_AUTH_PORT
+# define CVS_AUTH_PORT 2401
+# endif /* CVS_AUTH_PORT */
+# ifndef CVS_PROXY_PORT
+# define CVS_PROXY_PORT 8080
+# endif /* CVS_AUTH_PORT */
+# endif /* (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */
+
+# if HAVE_KERBEROS
+# ifndef CVS_PORT
+# define CVS_PORT 1999
+# endif
+# endif /* HAVE_KERBEROS */
+
+/* Talking to the server. */
+void send_to_server (const char *str, size_t len);
+void read_from_server (char *buf, size_t len);
+
+/* Internal functions that handle client communication to server, etc. */
+bool supported_request (const char *);
+void option_with_arg (const char *option, const char *arg);
+
+/* Get the responses and then close the connection. */
+int get_responses_and_close (void);
+
+int get_server_responses (void);
+
+/* Start up the connection to the server on the other end. */
+void
+open_connection_to_server (cvsroot_t *root, struct buffer **to_server_p,
+ struct buffer **from_server_p);
+void
+start_server (void);
+
+/* Send the names of all the argument files to the server. */
+void
+send_file_names (int argc, char **argv, unsigned int flags);
+
+/* Flags for send_file_names. */
+/* Expand wild cards? */
+# define SEND_EXPAND_WILD 1
+
+/*
+ * Send Repository, Modified and Entry. argc and argv contain only
+ * the files to operate on (or empty for everything), not options.
+ * local is nonzero if we should not recurse (-l option).
+ */
+void
+send_files (int argc, char **argv, int local, int aflag,
+ unsigned int flags);
+
+/* Flags for send_files. */
+# define SEND_BUILD_DIRS 1
+# define SEND_FORCE 2
+# define SEND_NO_CONTENTS 4
+# define BACKUP_MODIFIED_FILES 8
+
+/* Send an argument to the remote server. */
+void
+send_arg (const char *string);
+
+/* Send a string of single-char options to the remote server, one by one. */
+void
+send_options (int argc, char * const *argv);
+
+void send_a_repository (const char *, const char *, const char *);
+
+#endif /* CLIENT_SUPPORT */
+
+/*
+ * This structure is used to catalog the responses the client is
+ * prepared to see from the server.
+ */
+
+struct response
+{
+ /* Name of the response. */
+ const char *name;
+
+#ifdef CLIENT_SUPPORT
+ /*
+ * Function to carry out the response. ARGS is the text of the
+ * command after name and, if present, a single space, have been
+ * stripped off. The function can scribble into ARGS if it wants.
+ * Note that although LEN is given, ARGS is also guaranteed to be
+ * '\0' terminated.
+ */
+ void (*func) (char *args, size_t len);
+
+ /*
+ * ok and error are special; they indicate we are at the end of the
+ * responses, and error indicates we should exit with nonzero
+ * exitstatus.
+ */
+ enum {response_type_normal, response_type_ok, response_type_error,
+ response_type_redirect} type;
+#endif
+
+ /* Used by the server to indicate whether response is supported by
+ the client, as set by the Valid-responses request. */
+ enum {
+ /*
+ * Failure to implement this response can imply a fatal
+ * error. This should be set only for responses which were in the
+ * original version of the protocol; it should not be set for new
+ * responses.
+ */
+ rs_essential,
+
+ /* Some clients might not understand this response. */
+ rs_optional,
+
+ /*
+ * Set by the server to one of the following based on what this
+ * client actually supports.
+ */
+ rs_supported,
+ rs_not_supported
+ } status;
+};
+
+/* Table of responses ending in an entry with a NULL name. */
+
+extern struct response responses[];
+
+#ifdef CLIENT_SUPPORT
+
+void client_senddate (const char *date);
+void client_expand_modules (int argc, char **argv, int local);
+void client_send_expansions (int local, char *where, int build_dirs);
+void client_nonexpanded_setup (void);
+
+void send_init_command (void);
+
+extern char **failed_patches;
+extern int failed_patches_count;
+extern char *toplevel_wd;
+void client_import_setup (char *repository);
+int client_process_import_file
+ (char *message, char *vfile, char *vtag, int targc, char *targv[],
+ char *repository, int all_files_binary, int modtime);
+void client_import_done (void);
+void client_notify (const char *, const char *, const char *, int,
+ const char *);
+
+#if defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS || defined HAVE_GSSAPI
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+struct hostent *init_sockaddr (struct sockaddr_in *, char *, unsigned int);
+#endif
+
+#endif /* CLIENT_SUPPORT */
diff --git a/src/commit.c b/src/commit.c
new file mode 100644
index 0000000..c37c39b
--- /dev/null
+++ b/src/commit.c
@@ -0,0 +1,2469 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Commit Files
+ *
+ * "commit" commits the present version to the RCS repository, AFTER
+ * having done a test on conflicts.
+ *
+ * The call is: cvs commit [options] files...
+ *
+ */
+
+#include "cvs.h"
+#include "getline.h"
+#include "edit.h"
+#include "fileattr.h"
+#include "hardlink.h"
+
+static Dtype check_direntproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int check_fileproc (void *callerdat, struct file_info *finfo);
+static int check_filesdoneproc (void *callerdat, int err, const char *repos,
+ const char *update_dir, List *entries);
+static int checkaddfile (const char *file, const char *repository,
+ const char *tag, const char *options,
+ RCSNode **rcsnode);
+static Dtype commit_direntproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int commit_dirleaveproc (void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries);
+static int commit_fileproc (void *callerdat, struct file_info *finfo);
+static int commit_filesdoneproc (void *callerdat, int err,
+ const char *repository,
+ const char *update_dir, List *entries);
+static int finaladd (struct file_info *finfo, char *revision, char *tag,
+ char *options);
+static int findmaxrev (Node * p, void *closure);
+static int lock_RCS (const char *user, RCSNode *rcs, const char *rev,
+ const char *repository);
+static int precommit_list_to_args_proc (Node * p, void *closure);
+static int precommit_proc (const char *repository, const char *filter,
+ void *closure);
+static int remove_file (struct file_info *finfo, char *tag,
+ char *message);
+static void fixaddfile (const char *rcs);
+static void fixbranch (RCSNode *, char *branch);
+static void unlockrcs (RCSNode *rcs);
+static void ci_delproc (Node *p);
+static void masterlist_delproc (Node *p);
+
+struct commit_info
+{
+ Ctype status; /* as returned from Classify_File() */
+ char *rev; /* a numeric rev, if we know it */
+ char *tag; /* any sticky tag, or -r option */
+ char *options; /* Any sticky -k option */
+};
+struct master_lists
+{
+ List *ulist; /* list for Update_Logfile */
+ List *cilist; /* list with commit_info structs */
+};
+
+static int check_valid_edit = 0;
+static int force_ci = 0;
+static int got_message;
+static int aflag;
+static char *saved_tag;
+static char *write_dirtag;
+static int write_dirnonbranch;
+static char *logfile;
+static List *mulist;
+static char *saved_message;
+static time_t last_register_time;
+
+static const char *const commit_usage[] =
+{
+ "Usage: %s %s [-cRlf] [-m msg | -F logfile] [-r rev] files...\n",
+ " -c Check for valid edits before committing.\n",
+ " -R Process directories recursively.\n",
+ " -l Local directory only (not recursive).\n",
+ " -f Force the file to be committed; disables recursion.\n",
+ " -F logfile Read the log message from file.\n",
+ " -m msg Log message.\n",
+ " -r rev Commit to this branch or trunk revision.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+#ifdef CLIENT_SUPPORT
+/* Identify a file which needs "? foo" or a Questionable request. */
+struct question
+{
+ /* The two fields for the Directory request. */
+ char *dir;
+ char *repos;
+
+ /* The file name. */
+ char *file;
+
+ struct question *next;
+};
+
+struct find_data
+{
+ List *ulist;
+ int argc;
+ char **argv;
+
+ /* This is used from dirent to filesdone time, for each directory,
+ to make a list of files we have already seen. */
+ List *ignlist;
+
+ /* Linked list of files which need "? foo" or a Questionable request. */
+ struct question *questionables;
+
+ /* Only good within functions called from the filesdoneproc. Stores
+ the repository (pointer into storage managed by the recursion
+ processor. */
+ const char *repository;
+
+ /* Non-zero if we should force the commit. This is enabled by
+ either -f or -r options, unlike force_ci which is just -f. */
+ int force;
+};
+
+
+
+static Dtype
+find_dirent_proc (void *callerdat, const char *dir, const char *repository,
+ const char *update_dir, List *entries)
+{
+ struct find_data *find_data = callerdat;
+
+ /* This check seems to slowly be creeping throughout CVS (update
+ and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess
+ is that it (or some variant thereof) should go in all the
+ dirent procs. Unless someone has some better idea... */
+ if (!isdir (dir))
+ return R_SKIP_ALL;
+
+ /* initialize the ignore list for this directory */
+ find_data->ignlist = getlist ();
+
+ /* Print the same warm fuzzy as in check_direntproc, since that
+ code will never be run during client/server operation and we
+ want the messages to match. */
+ if (!quiet)
+ error (0, 0, "Examining %s", update_dir);
+
+ return R_PROCESS;
+}
+
+
+
+/* Here as a static until we get around to fixing ignore_files to pass
+ it along as an argument. */
+static struct find_data *find_data_static;
+
+
+
+static void
+find_ignproc (const char *file, const char *dir)
+{
+ struct question *p;
+
+ p = xmalloc (sizeof (struct question));
+ p->dir = xstrdup (dir);
+ p->repos = xstrdup (find_data_static->repository);
+ p->file = xstrdup (file);
+ p->next = find_data_static->questionables;
+ find_data_static->questionables = p;
+}
+
+
+
+static int
+find_filesdoneproc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ struct find_data *find_data = callerdat;
+ find_data->repository = repository;
+
+ /* if this directory has an ignore list, process it then free it */
+ if (find_data->ignlist)
+ {
+ find_data_static = find_data;
+ ignore_files (find_data->ignlist, entries, update_dir, find_ignproc);
+ dellist (&find_data->ignlist);
+ }
+
+ find_data->repository = NULL;
+
+ return err;
+}
+
+
+
+/* Machinery to find out what is modified, added, and removed. It is
+ possible this should be broken out into a new client_classify function;
+ merging it with classify_file is almost sure to be a mess, though,
+ because classify_file has all kinds of repository processing. */
+static int
+find_fileproc (void *callerdat, struct file_info *finfo)
+{
+ Vers_TS *vers;
+ enum classify_type status;
+ Node *node;
+ struct find_data *args = callerdat;
+ struct logfile_info *data;
+ struct file_info xfinfo;
+
+ /* if this directory has an ignore list, add this file to it */
+ if (args->ignlist)
+ {
+ Node *p;
+
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (finfo->file);
+ if (addnode (args->ignlist, p) != 0)
+ freenode (p);
+ }
+
+ xfinfo = *finfo;
+ xfinfo.repository = NULL;
+ xfinfo.rcs = NULL;
+
+ vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0);
+ if (vers->vn_user == NULL)
+ {
+ if (vers->ts_user == NULL)
+ error (0, 0, "nothing known about `%s'", finfo->fullname);
+ else
+ error (0, 0, "use `%s add' to create an entry for `%s'",
+ program_name, finfo->fullname);
+ freevers_ts (&vers);
+ return 1;
+ }
+ if (vers->vn_user[0] == '-')
+ {
+ if (vers->ts_user != NULL)
+ {
+ error (0, 0,
+ "`%s' should be removed and is still there (or is back"
+ " again)", finfo->fullname);
+ freevers_ts (&vers);
+ return 1;
+ }
+ /* else */
+ status = T_REMOVED;
+ }
+ else if (strcmp (vers->vn_user, "0") == 0)
+ {
+ if (vers->ts_user == NULL)
+ {
+ /* This happens when one has `cvs add'ed a file, but it no
+ longer exists in the working directory at commit time.
+ FIXME: What classify_file does in this case is print
+ "new-born %s has disappeared" and removes the entry.
+ We probably should do the same. */
+ if (!really_quiet)
+ error (0, 0, "warning: new-born %s has disappeared",
+ finfo->fullname);
+ status = T_REMOVE_ENTRY;
+ }
+ else
+ status = T_ADDED;
+ }
+ else if (vers->ts_user == NULL)
+ {
+ /* FIXME: What classify_file does in this case is print
+ "%s was lost". We probably should do the same. */
+ freevers_ts (&vers);
+ return 0;
+ }
+ else if (vers->ts_rcs != NULL
+ && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0))
+ /* If we are forcing commits, pretend that the file is
+ modified. */
+ status = T_MODIFIED;
+ else
+ {
+ /* This covers unmodified files, as well as a variety of other
+ cases. FIXME: we probably should be printing a message and
+ returning 1 for many of those cases (but I'm not sure
+ exactly which ones). */
+ freevers_ts (&vers);
+ return 0;
+ }
+
+ node = getnode ();
+ node->key = xstrdup (finfo->fullname);
+
+ data = xmalloc (sizeof (struct logfile_info));
+ data->type = status;
+ data->tag = xstrdup (vers->tag);
+ data->rev_old = data->rev_new = NULL;
+
+ node->type = UPDATE;
+ node->delproc = update_delproc;
+ node->data = data;
+ (void)addnode (args->ulist, node);
+
+ ++args->argc;
+
+ freevers_ts (&vers);
+ return 0;
+}
+
+
+
+static int
+copy_ulist (Node *node, void *data)
+{
+ struct find_data *args = data;
+ args->argv[args->argc++] = node->key;
+ return 0;
+}
+#endif /* CLIENT_SUPPORT */
+
+
+
+#ifdef SERVER_SUPPORT
+# define COMMIT_OPTIONS "+cnlRm:fF:r:"
+#else /* !SERVER_SUPPORT */
+# define COMMIT_OPTIONS "+clRm:fF:r:"
+#endif /* SERVER_SUPPORT */
+int
+commit (int argc, char **argv)
+{
+ int c;
+ int err = 0;
+ int local = 0;
+
+ if (argc == -1)
+ usage (commit_usage);
+
+#ifdef CVS_BADROOT
+ /*
+ * For log purposes, do not allow "root" to commit files. If you look
+ * like root, but are really logged in as a non-root user, it's OK.
+ */
+ /* FIXME: Shouldn't this check be much more closely related to the
+ readonly user stuff (CVSROOT/readers, &c). That is, why should
+ root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
+ /* Who we are on the client side doesn't affect logging. */
+ if (geteuid () == (uid_t) 0 && !current_parsed_root->isremote)
+ {
+ struct passwd *pw;
+
+ if ((pw = getpwnam (getcaller ())) == NULL)
+ error (1, 0,
+ "your apparent username (%s) is unknown to this system",
+ getcaller ());
+ if (pw->pw_uid == (uid_t) 0)
+ error (1, 0, "'root' is not allowed to commit files");
+ }
+#endif /* CVS_BADROOT */
+
+ optind = 0;
+ while ((c = getopt (argc, argv, COMMIT_OPTIONS)) != -1)
+ {
+ switch (c)
+ {
+ case 'c':
+ check_valid_edit = 1;
+ break;
+#ifdef SERVER_SUPPORT
+ case 'n':
+ /* Silently ignore -n for compatibility with old
+ * clients.
+ */
+ break;
+#endif /* SERVER_SUPPORT */
+ case 'm':
+#ifdef FORCE_USE_EDITOR
+ use_editor = 1;
+#else
+ use_editor = 0;
+#endif
+ if (saved_message)
+ {
+ free (saved_message);
+ saved_message = NULL;
+ }
+
+ saved_message = xstrdup (optarg);
+ break;
+ case 'r':
+ if (saved_tag)
+ free (saved_tag);
+ saved_tag = xstrdup (optarg);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'f':
+ force_ci = 1;
+ check_valid_edit = 0;
+ local = 1; /* also disable recursion */
+ break;
+ case 'F':
+#ifdef FORCE_USE_EDITOR
+ use_editor = 1;
+#else
+ use_editor = 0;
+#endif
+ logfile = optarg;
+ break;
+ case '?':
+ default:
+ usage (commit_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* numeric specified revision means we ignore sticky tags... */
+ if (saved_tag && isdigit ((unsigned char) *saved_tag))
+ {
+ char *p = saved_tag + strlen (saved_tag);
+ aflag = 1;
+ /* strip trailing dots and leading zeros */
+ while (*--p == '.') ;
+ p[1] = '\0';
+ while (saved_tag[0] == '0' && isdigit ((unsigned char) saved_tag[1]))
+ ++saved_tag;
+ }
+
+ /* some checks related to the "-F logfile" option */
+ if (logfile)
+ {
+ size_t size = 0, len;
+
+ if (saved_message)
+ error (1, 0, "cannot specify both a message and a log file");
+
+ get_file (logfile, logfile, "r", &saved_message, &size, &len);
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ struct find_data find_args;
+
+ ign_setup ();
+
+ find_args.ulist = getlist ();
+ find_args.argc = 0;
+ find_args.questionables = NULL;
+ find_args.ignlist = NULL;
+ find_args.repository = NULL;
+
+ /* It is possible that only a numeric tag should set this.
+ I haven't really thought about it much.
+ Anyway, I suspect that setting it unnecessarily only causes
+ a little unneeded network traffic. */
+ find_args.force = force_ci || saved_tag != NULL;
+
+ err = start_recursion
+ (find_fileproc, find_filesdoneproc, find_dirent_proc, NULL,
+ &find_args, argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE,
+ NULL, 0, NULL );
+ if (err)
+ error (1, 0, "correct above errors first!");
+
+ if (find_args.argc == 0)
+ {
+ /* Nothing to commit. Exit now without contacting the
+ server (note that this means that we won't print "?
+ foo" for files which merit it, because we don't know
+ what is in the CVSROOT/cvsignore file). */
+ dellist (&find_args.ulist);
+ return 0;
+ }
+
+ /* Now we keep track of which files we actually are going to
+ operate on, and only work with those files in the future.
+ This saves time--we don't want to search the file system
+ of the working directory twice. */
+ if (size_overflow_p (xtimes (find_args.argc, sizeof (char **))))
+ {
+ find_args.argc = 0;
+ return 0;
+ }
+ find_args.argv = xnmalloc (find_args.argc, sizeof (char **));
+ find_args.argc = 0;
+ walklist (find_args.ulist, copy_ulist, &find_args);
+
+ /* Do this before calling do_editor; don't ask for a log
+ message if we can't talk to the server. But do it after we
+ have made the checks that we can locally (to more quickly
+ catch syntax errors, the case where no files are modified,
+ added or removed, etc.).
+
+ On the other hand, calling start_server before do_editor
+ means that we chew up server resources the whole time that
+ the user has the editor open (hours or days if the user
+ forgets about it), which seems dubious. */
+ start_server ();
+
+ /*
+ * We do this once, not once for each directory as in normal CVS.
+ * The protocol is designed this way. This is a feature.
+ */
+ if (use_editor)
+ do_editor (".", &saved_message, NULL, find_args.ulist);
+
+ /* We always send some sort of message, even if empty. */
+ option_with_arg ("-m", saved_message ? saved_message : "");
+
+ /* OK, now process all the questionable files we have been saving
+ up. */
+ {
+ struct question *p;
+ struct question *q;
+
+ p = find_args.questionables;
+ while (p != NULL)
+ {
+ if (ign_inhibit_server || !supported_request ("Questionable"))
+ {
+ cvs_output ("? ", 2);
+ if (p->dir[0] != '\0')
+ {
+ cvs_output (p->dir, 0);
+ cvs_output ("/", 1);
+ }
+ cvs_output (p->file, 0);
+ cvs_output ("\n", 1);
+ }
+ else
+ {
+ /* This used to send the Directory line of its own accord,
+ * but skipped some of the other processing like checking
+ * for whether the server would accept "Relative-directory"
+ * requests. Relying on send_a_repository() to do this
+ * picks up these checks but also:
+ *
+ * 1. Causes the "Directory" request to be sent only once
+ * per directory.
+ * 2. Causes the global TOPLEVEL_REPOS to be set.
+ * 3. Causes "Static-directory" and "Sticky" requests
+ * to sometimes be sent.
+ *
+ * (1) is almost certainly a plus. (2) & (3) may or may
+ * not be useful sometimes, and will ocassionally cause a
+ * little extra network traffic. The additional network
+ * traffic is probably already saved several times over and
+ * certainly cancelled out via the multiple "Directory"
+ * request suppression of (1).
+ */
+ send_a_repository (p->dir, p->repos, p->dir);
+
+ send_to_server ("Questionable ", 0);
+ send_to_server (p->file, 0);
+ send_to_server ("\012", 1);
+ }
+ free (p->dir);
+ free (p->repos);
+ free (p->file);
+ q = p->next;
+ free (p);
+ p = q;
+ }
+ }
+
+ if (local)
+ send_arg ("-l");
+ if (check_valid_edit)
+ send_arg ("-c");
+ if (force_ci)
+ send_arg ("-f");
+ option_with_arg ("-r", saved_tag);
+ send_arg ("--");
+
+ /* FIXME: This whole find_args.force/SEND_FORCE business is a
+ kludge. It would seem to be a server bug that we have to
+ say that files are modified when they are not. This makes
+ "cvs commit -r 2" across a whole bunch of files a very slow
+ operation (and it isn't documented in cvsclient.texi). I
+ haven't looked at the server code carefully enough to be
+ _sure_ why this is needed, but if it is because the "ci"
+ program, which we used to call, wanted the file to exist,
+ then it would be relatively simple to fix in the server. */
+ send_files (find_args.argc, find_args.argv, local, 0,
+ find_args.force ? SEND_FORCE : 0);
+
+ /* Sending only the names of the files which were modified, added,
+ or removed means that the server will only do an up-to-date
+ check on those files. This is different from local CVS and
+ previous versions of client/server CVS, but it probably is a Good
+ Thing, or at least Not Such A Bad Thing. */
+ send_file_names (find_args.argc, find_args.argv, 0);
+ free (find_args.argv);
+ dellist (&find_args.ulist);
+
+ send_to_server ("ci\012", 0);
+ err = get_responses_and_close ();
+ if (err != 0 && use_editor && saved_message != NULL)
+ {
+ /* If there was an error, don't nuke the user's carefully
+ constructed prose. This is something of a kludge; a better
+ solution is probably more along the lines of #150 in TODO
+ (doing a second up-to-date check before accepting the
+ log message has also been suggested, but that seems kind of
+ iffy because the real up-to-date check could still fail,
+ another error could occur, &c. Also, a second check would
+ slow things down). */
+
+ char *fname;
+ FILE *fp;
+
+ fp = cvs_temp_file (&fname);
+ if (fp == NULL)
+ error (1, 0, "cannot create temporary file %s", fname);
+ if (fwrite (saved_message, 1, strlen (saved_message), fp)
+ != strlen (saved_message))
+ error (1, errno, "cannot write temporary file %s", fname);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close temporary file %s", fname);
+ error (0, 0, "saving log message in %s", fname);
+ free (fname);
+ }
+ return err;
+ }
+#endif
+
+ if (saved_tag != NULL)
+ tag_check_valid (saved_tag, argc, argv, local, aflag, "", false);
+
+ /* XXX - this is not the perfect check for this */
+ if (argc <= 0)
+ write_dirtag = saved_tag;
+
+ wrap_setup ();
+
+ lock_tree_promotably (argc, argv, local, W_LOCAL, aflag);
+
+ /*
+ * Set up the master update list and hard link list
+ */
+ mulist = getlist ();
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms)
+ {
+ hardlist = getlist ();
+
+ /*
+ * We need to save the working directory so that
+ * check_fileproc can construct a full pathname for each file.
+ */
+ working_dir = xgetcwd ();
+ }
+#endif
+
+ /*
+ * Run the recursion processor to verify the files are all up-to-date
+ */
+ err = start_recursion (check_fileproc, check_filesdoneproc,
+ check_direntproc, NULL, NULL, argc, argv, local,
+ W_LOCAL, aflag, CVS_LOCK_NONE, NULL, 1, NULL);
+ if (err)
+ error (1, 0, "correct above errors first!");
+
+ /*
+ * Run the recursion processor to commit the files
+ */
+ write_dirnonbranch = 0;
+ if (noexec == 0)
+ err = start_recursion (commit_fileproc, commit_filesdoneproc,
+ commit_direntproc, commit_dirleaveproc, NULL,
+ argc, argv, local, W_LOCAL, aflag,
+ CVS_LOCK_WRITE, NULL, 1, NULL);
+
+ /*
+ * Unlock all the dirs and clean up
+ */
+ Lock_Cleanup ();
+ dellist (&mulist);
+
+ /* see if we need to sleep before returning to avoid time-stamp races */
+ if (!server_active && last_register_time)
+ {
+ sleep_past (last_register_time);
+ }
+
+ return err;
+}
+
+
+
+/* This routine determines the status of a given file and retrieves
+ the version information that is associated with that file. */
+
+static
+Ctype
+classify_file_internal (struct file_info *finfo, Vers_TS **vers)
+{
+ int save_noexec, save_quiet, save_really_quiet;
+ Ctype status;
+
+ /* FIXME: Do we need to save quiet as well as really_quiet? Last
+ time I glanced at Classify_File I only saw it looking at really_quiet
+ not quiet. */
+ save_noexec = noexec;
+ save_quiet = quiet;
+ save_really_quiet = really_quiet;
+ noexec = quiet = really_quiet = 1;
+
+ /* handle specified numeric revision specially */
+ if (saved_tag && isdigit ((unsigned char) *saved_tag))
+ {
+ /* If the tag is for the trunk, make sure we're at the head */
+ if (numdots (saved_tag) < 2)
+ {
+ status = Classify_File (finfo, NULL, NULL,
+ NULL, 1, aflag, vers, 0);
+ if (status == T_UPTODATE || status == T_MODIFIED ||
+ status == T_ADDED)
+ {
+ Ctype xstatus;
+
+ freevers_ts (vers);
+ xstatus = Classify_File (finfo, saved_tag, NULL,
+ NULL, 1, aflag, vers, 0);
+ if (xstatus == T_REMOVE_ENTRY)
+ status = T_MODIFIED;
+ else if (status == T_MODIFIED && xstatus == T_CONFLICT)
+ status = T_MODIFIED;
+ else
+ status = xstatus;
+ }
+ }
+ else
+ {
+ char *xtag, *cp;
+
+ /*
+ * The revision is off the main trunk; make sure we're
+ * up-to-date with the head of the specified branch.
+ */
+ xtag = xstrdup (saved_tag);
+ if ((numdots (xtag) & 1) != 0)
+ {
+ cp = strrchr (xtag, '.');
+ *cp = '\0';
+ }
+ status = Classify_File (finfo, xtag, NULL,
+ NULL, 1, aflag, vers, 0);
+ if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
+ && (cp = strrchr (xtag, '.')) != NULL)
+ {
+ /* pluck one more dot off the revision */
+ *cp = '\0';
+ freevers_ts (vers);
+ status = Classify_File (finfo, xtag, NULL,
+ NULL, 1, aflag, vers, 0);
+ if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
+ status = T_MODIFIED;
+ }
+ /* now, muck with vers to make the tag correct */
+ free ((*vers)->tag);
+ (*vers)->tag = xstrdup (saved_tag);
+ free (xtag);
+ }
+ }
+ else
+ status = Classify_File (finfo, saved_tag, NULL, NULL, 1, 0, vers, 0);
+ noexec = save_noexec;
+ quiet = save_quiet;
+ really_quiet = save_really_quiet;
+
+ return status;
+}
+
+
+
+/*
+ * Check to see if a file is ok to commit and make sure all files are
+ * up-to-date
+ */
+/* ARGSUSED */
+static int
+check_fileproc (void *callerdat, struct file_info *finfo)
+{
+ Ctype status;
+ const char *xdir;
+ Node *p;
+ List *ulist, *cilist;
+ Vers_TS *vers;
+ struct commit_info *ci;
+ struct logfile_info *li;
+ int retval = 1;
+
+ size_t cvsroot_len = strlen (current_parsed_root->directory);
+
+ if (!finfo->repository)
+ {
+ error (0, 0, "nothing known about `%s'", finfo->fullname);
+ return 1;
+ }
+
+ if (strncmp (finfo->repository, current_parsed_root->directory,
+ cvsroot_len) == 0
+ && ISSLASH (finfo->repository[cvsroot_len])
+ && strncmp (finfo->repository + cvsroot_len + 1,
+ CVSROOTADM,
+ sizeof (CVSROOTADM) - 1) == 0
+ && ISSLASH (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
+ && strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
+ CVSNULLREPOS) == 0
+ )
+ error (1, 0, "cannot check in to %s", finfo->repository);
+
+ status = classify_file_internal (finfo, &vers);
+
+ /*
+ * If the force-commit option is enabled, and the file in question
+ * appears to be up-to-date, just make it look modified so that
+ * it will be committed.
+ */
+ if (force_ci && status == T_UPTODATE)
+ status = T_MODIFIED;
+
+ switch (status)
+ {
+ case T_CHECKOUT:
+ case T_PATCH:
+ case T_NEEDS_MERGE:
+ case T_REMOVE_ENTRY:
+ error (0, 0, "Up-to-date check failed for `%s'", finfo->fullname);
+ goto out;
+ case T_CONFLICT:
+ case T_MODIFIED:
+ case T_ADDED:
+ case T_REMOVED:
+ {
+ char *editor;
+
+ /*
+ * some quick sanity checks; if no numeric -r option specified:
+ * - can't have a sticky date
+ * - can't have a sticky tag that is not a branch
+ * Also,
+ * - if status is T_REMOVED, file must not exist and its entry
+ * can't have a numeric sticky tag.
+ * - if status is T_ADDED, rcs file must not exist unless on
+ * a branch or head is dead
+ * - if status is T_ADDED, can't have a non-trunk numeric rev
+ * - if status is T_MODIFIED and a Conflict marker exists, don't
+ * allow the commit if timestamp is identical or if we find
+ * an RCS_MERGE_PAT in the file.
+ */
+ if (!saved_tag || !isdigit ((unsigned char) *saved_tag))
+ {
+ if (vers->date)
+ {
+ error (0, 0,
+ "cannot commit with sticky date for file `%s'",
+ finfo->fullname);
+ goto out;
+ }
+ if (status == T_MODIFIED && vers->tag &&
+ !RCS_isbranch (finfo->rcs, vers->tag))
+ {
+ error (0, 0,
+ "sticky tag `%s' for file `%s' is not a branch",
+ vers->tag, finfo->fullname);
+ goto out;
+ }
+ }
+ if (status == T_CONFLICT && !force_ci)
+ {
+ error (0, 0,
+ "file `%s' had a conflict and has not been modified",
+ finfo->fullname);
+ goto out;
+ }
+ if (status == T_MODIFIED && !force_ci && file_has_markers (finfo))
+ {
+ /* Make this a warning, not an error, because we have
+ no way of knowing whether the "conflict indicators"
+ are really from a conflict or whether they are part
+ of the document itself (cvs.texinfo and sanity.sh in
+ CVS itself, for example, tend to want to have strings
+ like ">>>>>>>" at the start of a line). Making people
+ kludge this the way they need to kludge keyword
+ expansion seems undesirable. And it is worse than
+ keyword expansion, because there is no -ko
+ analogue. */
+ error (0, 0,
+ "\
+warning: file `%s' seems to still contain conflict indicators",
+ finfo->fullname);
+ }
+
+ if (status == T_REMOVED)
+ {
+ if (vers->ts_user != NULL)
+ {
+ error (0, 0,
+ "`%s' should be removed and is still there (or is"
+ " back again)", finfo->fullname);
+ goto out;
+ }
+
+ if (vers->tag && isdigit ((unsigned char) *vers->tag))
+ {
+ /* Remove also tries to forbid this, but we should check
+ here. I'm only _sure_ about somewhat obscure cases
+ (hacking the Entries file, using an old version of
+ CVS for the remove and a new one for the commit), but
+ there might be other cases. */
+ error (0, 0,
+ "cannot remove file `%s' which has a numeric sticky"
+ " tag of `%s'", finfo->fullname, vers->tag);
+ freevers_ts (&vers);
+ goto out;
+ }
+ }
+ if (status == T_ADDED)
+ {
+ if (vers->tag == NULL)
+ {
+ if (finfo->rcs != NULL &&
+ !RCS_isdead (finfo->rcs, finfo->rcs->head))
+ {
+ error (0, 0,
+ "cannot add file `%s' when RCS file `%s' already exists",
+ finfo->fullname, finfo->rcs->path);
+ goto out;
+ }
+ }
+ else if (isdigit ((unsigned char) *vers->tag) &&
+ numdots (vers->tag) > 1)
+ {
+ error (0, 0,
+ "cannot add file `%s' with revision `%s'; must be on trunk",
+ finfo->fullname, vers->tag);
+ goto out;
+ }
+ }
+
+ /* done with consistency checks; now, to get on with the commit */
+ if (finfo->update_dir[0] == '\0')
+ xdir = ".";
+ else
+ xdir = finfo->update_dir;
+ if ((p = findnode (mulist, xdir)) != NULL)
+ {
+ ulist = ((struct master_lists *) p->data)->ulist;
+ cilist = ((struct master_lists *) p->data)->cilist;
+ }
+ else
+ {
+ struct master_lists *ml;
+
+ ml = xmalloc (sizeof (struct master_lists));
+ ulist = ml->ulist = getlist ();
+ cilist = ml->cilist = getlist ();
+
+ p = getnode ();
+ p->key = xstrdup (xdir);
+ p->type = UPDATE;
+ p->data = ml;
+ p->delproc = masterlist_delproc;
+ (void) addnode (mulist, p);
+ }
+
+ /* first do ulist, then cilist */
+ p = getnode ();
+ p->key = xstrdup (finfo->file);
+ p->type = UPDATE;
+ p->delproc = update_delproc;
+ li = xmalloc (sizeof (struct logfile_info));
+ li->type = status;
+
+ if (check_valid_edit)
+ {
+ char *editors = NULL;
+
+ editor = NULL;
+ editors = fileattr_get0 (finfo->file, "_editors");
+ if (editors != NULL)
+ {
+ char *caller = getcaller ();
+ char *p = NULL;
+ char *p0 = NULL;
+
+ p = editors;
+ p0 = p;
+ while (*p != '\0')
+ {
+ p = strchr (p, '>');
+ if (p == NULL)
+ {
+ break;
+ }
+ *p = '\0';
+ if (strcmp (caller, p0) == 0)
+ {
+ break;
+ }
+ p = strchr (p + 1, ',');
+ if (p == NULL)
+ {
+ break;
+ }
+ ++p;
+ p0 = p;
+ }
+
+ if (strcmp (caller, p0) == 0)
+ {
+ editor = caller;
+ }
+
+ free (editors);
+ }
+ }
+
+ if (check_valid_edit && editor == NULL)
+ {
+ error (0, 0, "Valid edit does not exist for %s",
+ finfo->fullname);
+ freevers_ts (&vers);
+ return 1;
+ }
+
+ li->tag = xstrdup (vers->tag);
+ li->rev_old = xstrdup (vers->vn_rcs);
+ li->rev_new = NULL;
+ p->data = li;
+ (void) addnode (ulist, p);
+
+ p = getnode ();
+ p->key = xstrdup (finfo->file);
+ p->type = UPDATE;
+ p->delproc = ci_delproc;
+ ci = xmalloc (sizeof (struct commit_info));
+ ci->status = status;
+ if (vers->tag)
+ if (isdigit ((unsigned char) *vers->tag))
+ ci->rev = xstrdup (vers->tag);
+ else
+ ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
+ else
+ ci->rev = NULL;
+ ci->tag = xstrdup (vers->tag);
+ ci->options = xstrdup (vers->options);
+ p->data = ci;
+ (void) addnode (cilist, p);
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms)
+ {
+ /* Add this file to hardlist, indexed on its inode. When
+ we are done, we can find out what files are hardlinked
+ to a given file by looking up its inode in hardlist. */
+ char *fullpath;
+ Node *linkp;
+ struct hardlink_info *hlinfo;
+
+ /* Get the full pathname of the current file. */
+ fullpath = Xasprintf ("%s/%s", working_dir, finfo->fullname);
+
+ /* To permit following links in subdirectories, files
+ are keyed on finfo->fullname, not on finfo->name. */
+ linkp = lookup_file_by_inode (fullpath);
+
+ /* If linkp is NULL, the file doesn't exist... maybe
+ we're doing a remove operation? */
+ if (linkp != NULL)
+ {
+ /* Create a new hardlink_info node, which will record
+ the current file's status and the links listed in its
+ `hardlinks' delta field. We will append this
+ hardlink_info node to the appropriate hardlist entry. */
+ hlinfo = xmalloc (sizeof (struct hardlink_info));
+ hlinfo->status = status;
+ linkp->data = hlinfo;
+ }
+ }
+#endif
+
+ break;
+ }
+
+ case T_UNKNOWN:
+ error (0, 0, "nothing known about `%s'", finfo->fullname);
+ goto out;
+ case T_UPTODATE:
+ break;
+ default:
+ error (0, 0, "CVS internal error: unknown status %d", status);
+ break;
+ }
+
+ retval = 0;
+
+ out:
+
+ freevers_ts (&vers);
+ return retval;
+}
+
+
+
+/*
+ * By default, return the code that tells do_recursion to examine all
+ * directories
+ */
+/* ARGSUSED */
+static Dtype
+check_direntproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+ if (!isdir (dir))
+ return R_SKIP_ALL;
+
+ if (!quiet)
+ error (0, 0, "Examining %s", update_dir);
+
+ return R_PROCESS;
+}
+
+
+
+/*
+ * Walklist proc to generate an arg list from the line in commitinfo
+ */
+static int
+precommit_list_to_args_proc (p, closure)
+ Node *p;
+ void *closure;
+{
+ struct format_cmdline_walklist_closure *c = closure;
+ struct logfile_info *li;
+ char *arg = NULL;
+ const char *f;
+ char *d;
+ size_t doff;
+
+ if (p->data == NULL) return 1;
+
+ f = c->format;
+ d = *c->d;
+ /* foreach requested attribute */
+ while (*f)
+ {
+ switch (*f++)
+ {
+ case 's':
+ li = p->data;
+ if (li->type == T_ADDED
+ || li->type == T_MODIFIED
+ || li->type == T_REMOVED)
+ {
+ arg = p->key;
+ }
+ break;
+ default:
+ error (1, 0,
+ "Unknown format character or not a list attribute: %c",
+ f[-1]);
+ /* NOTREACHED */
+ break;
+ }
+ /* copy the attribute into an argument */
+ if (c->quotes)
+ {
+ arg = cmdlineescape (c->quotes, arg);
+ }
+ else
+ {
+ arg = cmdlinequote ('"', arg);
+ }
+ doff = d - *c->buf;
+ expand_string (c->buf, c->length, doff + strlen (arg));
+ d = *c->buf + doff;
+ strncpy (d, arg, strlen (arg));
+ d += strlen (arg);
+ free (arg);
+
+ /* and always put the extra space on. we'll have to back up a char
+ * when we're done, but that seems most efficient
+ */
+ doff = d - *c->buf;
+ expand_string (c->buf, c->length, doff + 1);
+ d = *c->buf + doff;
+ *d++ = ' ';
+ }
+ /* correct our original pointer into the buff */
+ *c->d = d;
+ return 0;
+}
+
+
+
+/*
+ * Callback proc for pre-commit checking
+ */
+static int
+precommit_proc (const char *repository, const char *filter, void *closure)
+{
+ char *newfilter = NULL;
+ char *cmdline;
+ const char *srepos = Short_Repository (repository);
+ List *ulist = closure;
+
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (!strchr (filter, '%'))
+ {
+ error (0, 0,
+ "warning: commitinfo line contains no format strings:\n"
+ " \"%s\"\n"
+ "Appending defaults (\" %%r/%%p %%s\"), but please be aware that this usage is\n"
+ "deprecated.", filter);
+ newfilter = Xasprintf ("%s %%r/%%p %%s", filter);
+ filter = newfilter;
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ false, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s", current_parsed_root->directory,
+ "s", ",", ulist, precommit_list_to_args_proc,
+ (void *) NULL,
+ (char *) NULL);
+
+ if (newfilter) free (newfilter);
+
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ error (0, 0, "precommit proc resolved to the empty string!");
+ return 1;
+ }
+
+ run_setup (cmdline);
+ free (cmdline);
+
+ return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL | RUN_REALLY);
+}
+
+
+
+/*
+ * Run the pre-commit checks for the dir
+ */
+/* ARGSUSED */
+static int
+check_filesdoneproc (void *callerdat, int err, const char *repos,
+ const char *update_dir, List *entries)
+{
+ int n;
+ Node *p;
+ List *saved_ulist;
+
+ /* find the update list for this dir */
+ p = findnode (mulist, update_dir);
+ if (p != NULL)
+ saved_ulist = ((struct master_lists *) p->data)->ulist;
+ else
+ saved_ulist = NULL;
+
+ /* skip the checks if there's nothing to do */
+ if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list)
+ return err;
+
+ /* run any pre-commit checks */
+ n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, PIOPT_ALL,
+ saved_ulist);
+ if (n > 0)
+ {
+ error (0, 0, "Pre-commit check failed");
+ err += n;
+ }
+
+ return err;
+}
+
+
+
+/*
+ * Do the work of committing a file
+ */
+static int maxrev;
+static char *sbranch;
+
+/* ARGSUSED */
+static int
+commit_fileproc (void *callerdat, struct file_info *finfo)
+{
+ Node *p;
+ int err = 0;
+ List *ulist, *cilist;
+ struct commit_info *ci;
+
+ /* Keep track of whether write_dirtag is a branch tag.
+ Note that if it is a branch tag in some files and a nonbranch tag
+ in others, treat it as a nonbranch tag. It is possible that case
+ should elicit a warning or an error. */
+ if (write_dirtag != NULL
+ && finfo->rcs != NULL)
+ {
+ char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL);
+ if (rev != NULL
+ && !RCS_nodeisbranch (finfo->rcs, write_dirtag))
+ write_dirnonbranch = 1;
+ if (rev != NULL)
+ free (rev);
+ }
+
+ if (finfo->update_dir[0] == '\0')
+ p = findnode (mulist, ".");
+ else
+ p = findnode (mulist, finfo->update_dir);
+
+ /*
+ * if p is null, there were file type command line args which were
+ * all up-to-date so nothing really needs to be done
+ */
+ if (p == NULL)
+ return 0;
+ ulist = ((struct master_lists *) p->data)->ulist;
+ cilist = ((struct master_lists *) p->data)->cilist;
+
+ /*
+ * At this point, we should have the commit message unless we were called
+ * with files as args from the command line. In that latter case, we
+ * need to get the commit message ourselves
+ */
+ if (!got_message)
+ {
+ got_message = 1;
+ if (!server_active && use_editor)
+ do_editor (finfo->update_dir, &saved_message,
+ finfo->repository, ulist);
+ do_verify (&saved_message, finfo->repository, ulist);
+ }
+
+ p = findnode (cilist, finfo->file);
+ if (p == NULL)
+ return 0;
+
+ ci = p->data;
+ if (ci->status == T_MODIFIED)
+ {
+ if (finfo->rcs == NULL)
+ error (1, 0, "internal error: no parsed RCS file");
+ if (lock_RCS (finfo->file, finfo->rcs, ci->rev,
+ finfo->repository) != 0)
+ {
+ unlockrcs (finfo->rcs);
+ err = 1;
+ goto out;
+ }
+ }
+ else if (ci->status == T_ADDED)
+ {
+ if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
+ &finfo->rcs) != 0)
+ {
+ if (finfo->rcs != NULL)
+ fixaddfile (finfo->rcs->path);
+ err = 1;
+ goto out;
+ }
+
+ /* adding files with a tag, now means adding them on a branch.
+ Since the branch test was done in check_fileproc for
+ modified files, we need to stub it in again here. */
+
+ if (ci->tag
+
+ /* If numeric, it is on the trunk; check_fileproc enforced
+ this. */
+ && !isdigit ((unsigned char) ci->tag[0]))
+ {
+ if (finfo->rcs == NULL)
+ error (1, 0, "internal error: no parsed RCS file");
+ if (ci->rev)
+ free (ci->rev);
+ ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
+ err = Checkin ('A', finfo, ci->rev,
+ ci->tag, ci->options, saved_message);
+ if (err != 0)
+ {
+ unlockrcs (finfo->rcs);
+ fixbranch (finfo->rcs, sbranch);
+ }
+
+ (void) time (&last_register_time);
+
+ ci->status = T_UPTODATE;
+ }
+ }
+
+ /*
+ * Add the file for real
+ */
+ if (ci->status == T_ADDED)
+ {
+ char *xrev = NULL;
+
+ if (ci->rev == NULL)
+ {
+ /* find the max major rev number in this directory */
+ maxrev = 0;
+ (void) walklist (finfo->entries, findmaxrev, NULL);
+ if (finfo->rcs->head)
+ {
+ /* resurrecting: include dead revision */
+ int thisrev = atoi (finfo->rcs->head);
+ if (thisrev > maxrev)
+ maxrev = thisrev;
+ }
+ if (maxrev == 0)
+ maxrev = 1;
+ xrev = Xasprintf ("%d", maxrev);
+ }
+
+ /* XXX - an added file with symbolic -r should add tag as well */
+ err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options);
+ if (xrev)
+ free (xrev);
+ }
+ else if (ci->status == T_MODIFIED)
+ {
+ err = Checkin ('M', finfo, ci->rev, ci->tag,
+ ci->options, saved_message);
+
+ (void) time (&last_register_time);
+
+ if (err != 0)
+ {
+ unlockrcs (finfo->rcs);
+ fixbranch (finfo->rcs, sbranch);
+ }
+ }
+ else if (ci->status == T_REMOVED)
+ {
+ err = remove_file (finfo, ci->tag, saved_message);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ server_scratch_entry_only ();
+ server_updated (finfo,
+ NULL,
+
+ /* Doesn't matter, it won't get checked. */
+ SERVER_UPDATED,
+
+ (mode_t) -1,
+ NULL,
+ NULL);
+ }
+#endif
+ }
+
+ /* Clearly this is right for T_MODIFIED. I haven't thought so much
+ about T_ADDED or T_REMOVED. */
+ notify_do ('C', finfo->file, finfo->update_dir, getcaller (), NULL, NULL,
+ finfo->repository);
+
+out:
+ if (err != 0)
+ {
+ /* on failure, remove the file from ulist */
+ p = findnode (ulist, finfo->file);
+ if (p)
+ delnode (p);
+ }
+ else
+ {
+ /* On success, retrieve the new version number of the file and
+ copy it into the log information (see logmsg.c
+ (logfile_write) for more details). We should only update
+ the version number for files that have been added or
+ modified but not removed since classify_file_internal
+ will return the version number of a file even after it has
+ been removed from the archive, which is not the behavior we
+ want for our commitlog messages; we want the old version
+ number and then "NONE." */
+
+ if (ci->status != T_REMOVED)
+ {
+ p = findnode (ulist, finfo->file);
+ if (p)
+ {
+ Vers_TS *vers;
+ struct logfile_info *li;
+
+ (void) classify_file_internal (finfo, &vers);
+ li = p->data;
+ li->rev_new = xstrdup (vers->vn_rcs);
+ freevers_ts (&vers);
+ }
+ }
+ }
+ if (SIG_inCrSect ())
+ SIG_endCrSect ();
+
+ return err;
+}
+
+
+
+/*
+ * Log the commit and clean up the update list
+ */
+/* ARGSUSED */
+static int
+commit_filesdoneproc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ Node *p;
+ List *ulist;
+
+ assert (repository);
+
+ p = findnode (mulist, update_dir);
+ if (p == NULL)
+ return err;
+
+ ulist = ((struct master_lists *) p->data)->ulist;
+
+ got_message = 0;
+
+ /* Build the administrative files if necessary. */
+ {
+ const char *p;
+
+ if (strncmp (current_parsed_root->directory, repository,
+ strlen (current_parsed_root->directory)) != 0)
+ error (0, 0,
+ "internal error: repository (%s) doesn't begin with root (%s)",
+ repository, current_parsed_root->directory);
+ p = repository + strlen (current_parsed_root->directory);
+ if (*p == '/')
+ ++p;
+ if (strcmp ("CVSROOT", p) == 0
+ /* Check for subdirectories because people may want to create
+ subdirectories and list files therein in checkoutlist. */
+ || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0
+ )
+ {
+ /* "Database" might a little bit grandiose and/or vague,
+ but "checked-out copies of administrative files, unless
+ in the case of modules and you are using ndbm in which
+ case modules.{pag,dir,db}" is verbose and excessively
+ focused on how the database is implemented. */
+
+ /* mkmodules requires the absolute name of the CVSROOT directory.
+ Remove anything after the `CVSROOT' component -- this is
+ necessary when committing in a subdirectory of CVSROOT. */
+ char *admin_dir = xstrdup (repository);
+ int cvsrootlen = strlen ("CVSROOT");
+ assert (admin_dir[p - repository + cvsrootlen] == '\0'
+ || admin_dir[p - repository + cvsrootlen] == '/');
+ admin_dir[p - repository + cvsrootlen] = '\0';
+
+ if (!really_quiet)
+ {
+ cvs_output (program_name, 0);
+ cvs_output (" ", 1);
+ cvs_output (cvs_cmd_name, 0);
+ cvs_output (": Rebuilding administrative file database\n", 0);
+ }
+ mkmodules (admin_dir);
+ free (admin_dir);
+ WriteTemplate (".", 1, repository);
+ }
+ }
+
+ /* FIXME: This used to be above the block above. The advantage of being
+ * here is that it is not called until after all possible writes from this
+ * process are complete. The disadvantage is that a fatal error during
+ * update of CVSROOT can prevent the loginfo script from being called.
+ *
+ * A more general solution I have been considering is calling a generic
+ * "postwrite" hook from the remove write lock routine.
+ */
+ Update_Logfile (repository, saved_message, NULL, ulist);
+
+ return err;
+}
+
+
+
+/*
+ * Get the log message for a dir
+ */
+/* ARGSUSED */
+static Dtype
+commit_direntproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+ Node *p;
+ List *ulist;
+ char *real_repos;
+
+ if (!isdir (dir))
+ return R_SKIP_ALL;
+
+ /* find the update list for this dir */
+ p = findnode (mulist, update_dir);
+ if (p != NULL)
+ ulist = ((struct master_lists *) p->data)->ulist;
+ else
+ ulist = NULL;
+
+ /* skip the files as an optimization */
+ if (ulist == NULL || ulist->list->next == ulist->list)
+ return R_SKIP_FILES;
+
+ /* get commit message */
+ got_message = 1;
+ real_repos = Name_Repository (dir, update_dir);
+ if (!server_active && use_editor)
+ do_editor (update_dir, &saved_message, real_repos, ulist);
+ do_verify (&saved_message, real_repos, ulist);
+ free (real_repos);
+ return R_PROCESS;
+}
+
+
+
+/*
+ * Process the post-commit proc if necessary
+ */
+/* ARGSUSED */
+static int
+commit_dirleaveproc (void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries)
+{
+ /* update the per-directory tag info */
+ /* FIXME? Why? The "commit examples" node of cvs.texinfo briefly
+ mentions commit -r being sticky, but apparently in the context of
+ this being a confusing feature! */
+ if (err == 0 && write_dirtag != NULL)
+ {
+ char *repos = Name_Repository (NULL, update_dir);
+ WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
+ update_dir, repos);
+ free (repos);
+ }
+
+ return err;
+}
+
+
+
+/*
+ * find the maximum major rev number in an entries file
+ */
+static int
+findmaxrev (Node *p, void *closure)
+{
+ int thisrev;
+ Entnode *entdata = p->data;
+
+ if (entdata->type != ENT_FILE)
+ return 0;
+ thisrev = atoi (entdata->version);
+ if (thisrev > maxrev)
+ maxrev = thisrev;
+ return 0;
+}
+
+/*
+ * Actually remove a file by moving it to the attic
+ * XXX - if removing a ,v file that is a relative symbolic link to
+ * another ,v file, we probably should add a ".." component to the
+ * link to keep it relative after we move it into the attic.
+
+ Return value is 0 on success, or >0 on error (in which case we have
+ printed an error message). */
+static int
+remove_file (struct file_info *finfo, char *tag, char *message)
+{
+ int retcode;
+
+ int branch;
+ int lockflag;
+ char *corev;
+ char *rev;
+ char *prev_rev;
+ char *old_path;
+
+ corev = NULL;
+ rev = NULL;
+ prev_rev = NULL;
+
+ retcode = 0;
+
+ if (finfo->rcs == NULL)
+ error (1, 0, "internal error: no parsed RCS file");
+
+ branch = 0;
+ if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
+ {
+ /* a symbolic tag is specified; just remove the tag from the file */
+ if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to remove tag `%s' from `%s'", tag,
+ finfo->fullname);
+ return 1;
+ }
+ RCS_rewrite (finfo->rcs, NULL, NULL);
+ Scratch_Entry (finfo->entries, finfo->file);
+ return 0;
+ }
+
+ /* we are removing the file from either the head or a branch */
+ /* commit a new, dead revision. */
+
+ rev = NULL;
+ lockflag = 1;
+ if (branch)
+ {
+ char *branchname;
+
+ rev = RCS_whatbranch (finfo->rcs, tag);
+ if (rev == NULL)
+ {
+ error (0, 0, "cannot find branch \"%s\".", tag);
+ return 1;
+ }
+
+ branchname = RCS_getbranch (finfo->rcs, rev, 1);
+ if (branchname == NULL)
+ {
+ /* no revision exists on this branch. use the previous
+ revision but do not lock. */
+ corev = RCS_gettag (finfo->rcs, tag, 1, NULL);
+ prev_rev = xstrdup (corev);
+ lockflag = 0;
+ } else
+ {
+ corev = xstrdup (rev);
+ prev_rev = xstrdup (branchname);
+ free (branchname);
+ }
+
+ } else /* Not a branch */
+ {
+ /* Get current head revision of file. */
+ prev_rev = RCS_head (finfo->rcs);
+ }
+
+ /* if removing without a tag or a branch, then make sure the default
+ branch is the trunk. */
+ if (!tag && !branch)
+ {
+ if (RCS_setbranch (finfo->rcs, NULL) != 0)
+ {
+ error (0, 0, "cannot change branch to default for %s",
+ finfo->fullname);
+ return 1;
+ }
+ RCS_rewrite (finfo->rcs, NULL, NULL);
+ }
+
+ /* check something out. Generally this is the head. If we have a
+ particular rev, then name it. */
+ retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
+ NULL, NULL, RUN_TTY, NULL, NULL);
+ if (retcode != 0)
+ {
+ error (0, 0,
+ "failed to check out `%s'", finfo->fullname);
+ return 1;
+ }
+
+ /* Except when we are creating a branch, lock the revision so that
+ we can check in the new revision. */
+ if (lockflag)
+ {
+ if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
+ RCS_rewrite (finfo->rcs, NULL, NULL);
+ }
+
+ if (corev != NULL)
+ free (corev);
+
+ retcode = RCS_checkin (finfo->rcs, NULL, finfo->file, message,
+ rev, 0, RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
+ if (retcode != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to commit dead revision for `%s'", finfo->fullname);
+ return 1;
+ }
+ /* At this point, the file has been committed as removed. We should
+ probably tell the history file about it */
+ history_write ('R', NULL, finfo->rcs->head, finfo->file, finfo->repository);
+
+ if (rev != NULL)
+ free (rev);
+
+ old_path = xstrdup (finfo->rcs->path);
+ if (!branch)
+ RCS_setattic (finfo->rcs, 1);
+
+ /* Print message that file was removed. */
+ if (!really_quiet)
+ {
+ cvs_output (old_path, 0);
+ cvs_output (" <-- ", 0);
+ if (finfo->update_dir && strlen (finfo->update_dir))
+ {
+ cvs_output (finfo->update_dir, 0);
+ cvs_output ("/", 1);
+ }
+ cvs_output (finfo->file, 0);
+ cvs_output ("\nnew revision: delete; previous revision: ", 0);
+ cvs_output (prev_rev, 0);
+ cvs_output ("\n", 0);
+ }
+
+ free (prev_rev);
+
+ free (old_path);
+
+ Scratch_Entry (finfo->entries, finfo->file);
+ return 0;
+}
+
+
+
+/*
+ * Do the actual checkin for added files
+ */
+static int
+finaladd (struct file_info *finfo, char *rev, char *tag, char *options)
+{
+ int ret;
+
+ ret = Checkin ('A', finfo, rev, tag, options, saved_message);
+ if (ret == 0)
+ {
+ char *tmp = Xasprintf ("%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
+ if (unlink_file (tmp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmp);
+ free (tmp);
+ }
+ else if (finfo->rcs != NULL)
+ fixaddfile (finfo->rcs->path);
+
+ (void) time (&last_register_time);
+
+ return ret;
+}
+
+
+
+/*
+ * Unlock an rcs file
+ */
+static void
+unlockrcs (RCSNode *rcs)
+{
+ int retcode;
+
+ if ((retcode = RCS_unlock (rcs, NULL, 1)) != 0)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not unlock %s", rcs->path);
+ else
+ RCS_rewrite (rcs, NULL, NULL);
+}
+
+
+
+/*
+ * remove a partially added file. if we can parse it, leave it alone.
+ *
+ * FIXME: Every caller that calls this function can access finfo->rcs (the
+ * parsed RCSNode data), so we should be able to detect that the file needs
+ * to be removed without reparsing the file as we do below.
+ */
+static void
+fixaddfile (const char *rcs)
+{
+ RCSNode *rcsfile;
+ int save_really_quiet;
+
+ save_really_quiet = really_quiet;
+ really_quiet = 1;
+ if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
+ {
+ if (unlink_file (rcs) < 0)
+ error (0, errno, "cannot remove %s", rcs);
+ }
+ else
+ freercsnode (&rcsfile);
+ really_quiet = save_really_quiet;
+}
+
+
+
+/*
+ * put the branch back on an rcs file
+ */
+static void
+fixbranch (RCSNode *rcs, char *branch)
+{
+ int retcode;
+
+ if (branch != NULL)
+ {
+ if ((retcode = RCS_setbranch (rcs, branch)) != 0)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "cannot restore branch to %s for %s", branch, rcs->path);
+ RCS_rewrite (rcs, NULL, NULL);
+ }
+}
+
+
+
+/*
+ * do the initial part of a file add for the named file. if adding
+ * with a tag, put the file in the Attic and point the symbolic tag
+ * at the committed revision.
+ *
+ * INPUTS
+ * file The name of the file in the workspace.
+ * repository The repository directory to expect to find FILE,v in.
+ * tag The name or rev num of the branch being added to, if any.
+ * options Any RCS keyword expansion options specified by the user.
+ * rcsnode A pointer to the pre-parsed RCSNode for this file, if the file
+ * exists in the repository. If this is NULL, assume the file
+ * does not yet exist.
+ *
+ * RETURNS
+ * 0 on success.
+ * 1 on errors, after printing any appropriate error messages.
+ *
+ * ERRORS
+ * This function will return an error when any of the following functions do:
+ * add_rcs_file
+ * RCS_setattic
+ * lock_RCS
+ * RCS_checkin
+ * RCS_parse (called to verify the newly created archive file)
+ * RCS_settag
+ */
+
+static int
+checkaddfile (const char *file, const char *repository, const char *tag,
+ const char *options, RCSNode **rcsnode)
+{
+ RCSNode *rcs;
+ char *fname;
+ int newfile = 0; /* Set to 1 if we created a new RCS archive. */
+ int retval = 1;
+ int adding_on_branch;
+
+ assert (rcsnode != NULL);
+
+ /* Callers expect to be able to use either "" or NULL to mean the
+ default keyword expansion. */
+ if (options != NULL && options[0] == '\0')
+ options = NULL;
+ if (options != NULL)
+ assert (options[0] == '-' && options[1] == 'k');
+
+ /* If numeric, it is on the trunk; check_fileproc enforced
+ this. */
+ adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
+
+ if (*rcsnode == NULL)
+ {
+ char *rcsname;
+ char *desc = NULL;
+ size_t descalloc = 0;
+ size_t desclen = 0;
+ const char *opt;
+
+ if (adding_on_branch)
+ {
+ mode_t omask;
+ rcsname = xmalloc (strlen (repository)
+ + sizeof (CVSATTIC)
+ + strlen (file)
+ + sizeof (RCSEXT)
+ + 3);
+ (void) sprintf (rcsname, "%s/%s", repository, CVSATTIC);
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (rcsname, 0777) != 0 && errno != EEXIST)
+ error (1, errno, "cannot make directory `%s'", rcsname);
+ (void) umask (omask);
+ (void) sprintf (rcsname,
+ "%s/%s/%s%s",
+ repository,
+ CVSATTIC,
+ file,
+ RCSEXT);
+ }
+ else
+ rcsname = Xasprintf ("%s/%s%s", repository, file, RCSEXT);
+
+ /* this is the first time we have ever seen this file; create
+ an RCS file. */
+ fname = Xasprintf ("%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ /* If the file does not exist, no big deal. In particular, the
+ server does not (yet at least) create CVSEXT_LOG files. */
+ if (isfile (fname))
+ /* FIXME: Should be including update_dir in the appropriate
+ place here. */
+ get_file (fname, fname, "r", &desc, &descalloc, &desclen);
+ free (fname);
+
+ /* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
+ end of the log message if the message is nonempty.
+ Do it. RCS also deletes certain whitespace, in cleanlogmsg,
+ which we don't try to do here. */
+ if (desclen > 0)
+ {
+ expand_string (&desc, &descalloc, desclen + 1);
+ desc[desclen++] = '\012';
+ }
+
+ /* Set RCS keyword expansion options. */
+ if (options != NULL)
+ opt = options + 2;
+ else
+ opt = NULL;
+
+ if (add_rcs_file (NULL, rcsname, file, NULL, opt,
+ NULL, NULL, 0, NULL,
+ desc, desclen, NULL, 0) != 0)
+ {
+ if (rcsname != NULL)
+ free (rcsname);
+ goto out;
+ }
+ rcs = RCS_parsercsfile (rcsname);
+ newfile = 1;
+ if (rcsname != NULL)
+ free (rcsname);
+ if (desc != NULL)
+ free (desc);
+ *rcsnode = rcs;
+ }
+ else
+ {
+ /* file has existed in the past. Prepare to resurrect. */
+ char *rev;
+ char *oldexpand;
+
+ rcs = *rcsnode;
+
+ oldexpand = RCS_getexpand (rcs);
+ if ((oldexpand != NULL
+ && options != NULL
+ && strcmp (options + 2, oldexpand) != 0)
+ || (oldexpand == NULL && options != NULL))
+ {
+ /* We tell the user about this, because it means that the
+ old revisions will no longer retrieve the way that they
+ used to. */
+ error (0, 0, "changing keyword expansion mode to %s", options);
+ RCS_setexpand (rcs, options + 2);
+ }
+
+ if (!adding_on_branch)
+ {
+ /* We are adding on the trunk, so move the file out of the
+ Attic. */
+ if (!(rcs->flags & INATTIC))
+ {
+ error (0, 0, "warning: expected %s to be in Attic",
+ rcs->path);
+ }
+
+ /* Begin a critical section around the code that spans the
+ first commit on the trunk of a file that's already been
+ committed on a branch. */
+ SIG_beginCrSect ();
+
+ if (RCS_setattic (rcs, 0))
+ {
+ goto out;
+ }
+ }
+
+ rev = RCS_getversion (rcs, tag, NULL, 1, NULL);
+ /* and lock it */
+ if (lock_RCS (file, rcs, rev, repository))
+ {
+ error (0, 0, "cannot lock revision %s in `%s'.",
+ rev ? rev : tag ? tag : "HEAD", rcs->path);
+ if (rev != NULL)
+ free (rev);
+ goto out;
+ }
+
+ if (rev != NULL)
+ free (rev);
+ }
+
+ /* when adding a file for the first time, and using a tag, we need
+ to create a dead revision on the trunk. */
+ if (adding_on_branch)
+ {
+ if (newfile)
+ {
+ char *tmp;
+ FILE *fp;
+ int retcode;
+
+ /* move the new file out of the way. */
+ fname = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, file);
+ rename_file (file, fname);
+
+ /* Create empty FILE. Can't use copy_file with a DEVNULL
+ argument -- copy_file now ignores device files. */
+ fp = fopen (file, "w");
+ if (fp == NULL)
+ error (1, errno, "cannot open %s for writing", file);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", file);
+
+ tmp = Xasprintf ("file %s was initially added on branch %s.",
+ file, tag);
+ /* commit a dead revision. */
+ retcode = RCS_checkin (rcs, NULL, NULL, tmp, NULL, 0,
+ RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
+ free (tmp);
+ if (retcode != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not create initial dead revision %s", rcs->path);
+ free (fname);
+ goto out;
+ }
+
+ /* put the new file back where it was */
+ rename_file (fname, file);
+ free (fname);
+
+ /* double-check that the file was written correctly */
+ freercsnode (&rcs);
+ rcs = RCS_parse (file, repository);
+ if (rcs == NULL)
+ {
+ error (0, 0, "could not read %s", rcs->path);
+ goto out;
+ }
+ *rcsnode = rcs;
+
+ /* and lock it once again. */
+ if (lock_RCS (file, rcs, NULL, repository))
+ {
+ error (0, 0, "cannot lock initial revision in `%s'.",
+ rcs->path);
+ goto out;
+ }
+ }
+
+ /* when adding with a tag, we need to stub a branch, if it
+ doesn't already exist. */
+ if (!RCS_nodeisbranch (rcs, tag))
+ {
+ /* branch does not exist. Stub it. */
+ char *head;
+ char *magicrev;
+ int retcode;
+ time_t headtime = -1;
+ char *revnum, *tmp;
+ FILE *fp;
+ time_t t = -1;
+ struct tm *ct;
+
+ fixbranch (rcs, sbranch);
+
+ head = RCS_getversion (rcs, NULL, NULL, 0, NULL);
+ if (!head)
+ error (1, 0, "No head revision in archive file `%s'.",
+ rcs->print_path);
+ magicrev = RCS_magicrev (rcs, head);
+
+ /* If this is not a new branch, then we will want a dead
+ version created before this one. */
+ if (!newfile)
+ headtime = RCS_getrevtime (rcs, head, 0, 0);
+
+ retcode = RCS_settag (rcs, tag, magicrev);
+ RCS_rewrite (rcs, NULL, NULL);
+
+ free (head);
+ free (magicrev);
+
+ if (retcode != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not stub branch %s for %s", tag, rcs->path);
+ goto out;
+ }
+ /* We need to add a dead version here to avoid -rtag -Dtime
+ checkout problems between when the head version was
+ created and now. */
+ if (!newfile && headtime != -1)
+ {
+ /* move the new file out of the way. */
+ fname = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, file);
+ rename_file (file, fname);
+
+ /* Create empty FILE. Can't use copy_file with a DEVNULL
+ argument -- copy_file now ignores device files. */
+ fp = fopen (file, "w");
+ if (fp == NULL)
+ error (1, errno, "cannot open %s for writing", file);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", file);
+
+ /* As we will be hacking the delta date, put the time
+ this was added into the log message. */
+ t = time (NULL);
+ ct = gmtime (&t);
+ tmp = Xasprintf ("file %s was added on branch %s on %d-%02d-%02d %02d:%02d:%02d +0000",
+ file, tag,
+ ct->tm_year + (ct->tm_year < 100 ? 0 : 1900),
+ ct->tm_mon + 1, ct->tm_mday,
+ ct->tm_hour, ct->tm_min, ct->tm_sec);
+
+ /* commit a dead revision. */
+ revnum = RCS_whatbranch (rcs, tag);
+ retcode = RCS_checkin (rcs, NULL, NULL, tmp, revnum, headtime,
+ RCS_FLAGS_DEAD |
+ RCS_FLAGS_QUIET |
+ RCS_FLAGS_USETIME);
+ free (revnum);
+ free (tmp);
+
+ if (retcode != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not created dead stub %s for %s", tag,
+ rcs->path);
+ goto out;
+ }
+
+ /* put the new file back where it was */
+ rename_file (fname, file);
+ free (fname);
+
+ /* double-check that the file was written correctly */
+ freercsnode (&rcs);
+ rcs = RCS_parse (file, repository);
+ if (rcs == NULL)
+ {
+ error (0, 0, "could not read %s", rcs->path);
+ goto out;
+ }
+ *rcsnode = rcs;
+ }
+ }
+ else
+ {
+ /* lock the branch. (stubbed branches need not be locked.) */
+ if (lock_RCS (file, rcs, NULL, repository))
+ {
+ error (0, 0, "cannot lock head revision in `%s'.", rcs->path);
+ goto out;
+ }
+ }
+
+ if (*rcsnode != rcs)
+ {
+ freercsnode (rcsnode);
+ *rcsnode = rcs;
+ }
+ }
+
+ fileattr_newfile (file);
+
+ /* At this point, we used to set the file mode of the RCS file
+ based on the mode of the file in the working directory. If we
+ are creating the RCS file for the first time, add_rcs_file does
+ this already. If we are re-adding the file, then perhaps it is
+ consistent to preserve the old file mode, just as we preserve
+ the old keyword expansion mode.
+
+ If we decide that we should change the modes, then we can't do
+ it here anyhow. At this point, the RCS file may be owned by
+ somebody else, so a chmod will fail. We need to instead do the
+ chmod after rewriting it.
+
+ FIXME: In general, I think the file mode (and the keyword
+ expansion mode) should be associated with a particular revision
+ of the file, so that it is possible to have different revisions
+ of a file have different modes. */
+
+ retval = 0;
+
+ out:
+ if (retval != 0 && SIG_inCrSect ())
+ SIG_endCrSect ();
+ return retval;
+}
+
+
+
+/*
+ * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it
+ * couldn't. If the RCS file currently has a branch as the head, we must
+ * move the head back to the trunk before locking the file, and be sure to
+ * put the branch back as the head if there are any errors.
+ */
+static int
+lock_RCS (const char *user, RCSNode *rcs, const char *rev,
+ const char *repository)
+{
+ char *branch = NULL;
+ int err = 0;
+
+ /*
+ * For a specified, numeric revision of the form "1" or "1.1", (or when
+ * no revision is specified ""), definitely move the branch to the trunk
+ * before locking the RCS file.
+ *
+ * The assumption is that if there is more than one revision on the trunk,
+ * the head points to the trunk, not a branch... and as such, it's not
+ * necessary to move the head in this case.
+ */
+ if (rev == NULL
+ || (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
+ {
+ branch = xstrdup (rcs->branch);
+ if (branch != NULL)
+ {
+ if (RCS_setbranch (rcs, NULL) != 0)
+ {
+ error (0, 0, "cannot change branch to default for %s",
+ rcs->path);
+ if (branch)
+ free (branch);
+ return 1;
+ }
+ }
+ err = RCS_lock (rcs, NULL, 1);
+ }
+ else
+ {
+ RCS_lock (rcs, rev, 1);
+ }
+
+ /* We used to call RCS_rewrite here, and that might seem
+ appropriate in order to write out the locked revision
+ information. However, such a call would actually serve no
+ purpose. CVS locks will prevent any interference from other
+ CVS processes. The comment above rcs_internal_lockfile
+ explains that it is already unsafe to use RCS and CVS
+ simultaneously. It follows that writing out the locked
+ revision information here would add no additional security.
+
+ If we ever do care about it, the proper fix is to create the
+ RCS lock file before calling this function, and maintain it
+ until the checkin is complete.
+
+ The call to RCS_lock is still required at present, since in
+ some cases RCS_checkin will determine which revision to check
+ in by looking for a lock. FIXME: This is rather roundabout,
+ and a more straightforward approach would probably be easier to
+ understand. */
+
+ if (err == 0)
+ {
+ if (sbranch != NULL)
+ free (sbranch);
+ sbranch = branch;
+ return 0;
+ }
+
+ /* try to restore the branch if we can on error */
+ if (branch != NULL)
+ fixbranch (rcs, branch);
+
+ if (branch)
+ free (branch);
+ return 1;
+}
+
+
+
+/*
+ * free an UPDATE node's data
+ */
+void
+update_delproc (Node *p)
+{
+ struct logfile_info *li = p->data;
+
+ if (li->tag)
+ free (li->tag);
+ if (li->rev_old)
+ free (li->rev_old);
+ if (li->rev_new)
+ free (li->rev_new);
+ free (li);
+}
+
+/*
+ * Free the commit_info structure in p.
+ */
+static void
+ci_delproc (Node *p)
+{
+ struct commit_info *ci = p->data;
+
+ if (ci->rev)
+ free (ci->rev);
+ if (ci->tag)
+ free (ci->tag);
+ if (ci->options)
+ free (ci->options);
+ free (ci);
+}
+
+/*
+ * Free the commit_info structure in p.
+ */
+static void
+masterlist_delproc (Node *p)
+{
+ struct master_lists *ml = p->data;
+
+ dellist (&ml->ulist);
+ dellist (&ml->cilist);
+ free (ml);
+}
diff --git a/src/create_adm.c b/src/create_adm.c
new file mode 100644
index 0000000..538c47b
--- /dev/null
+++ b/src/create_adm.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Create Administration.
+ *
+ * Creates a CVS administration directory based on the argument repository; the
+ * "Entries" file is prefilled from the "initrecord" argument.
+ */
+
+#include "cvs.h"
+
+
+
+/* update_dir includes dir as its last component.
+
+ Return value is 0 for success, or 1 if we printed a warning message.
+ Note that many errors are still fatal; particularly for unlikely errors
+ a fatal error is probably better than a warning which might be missed
+ or after which CVS might do something non-useful. If WARN is zero, then
+ don't print warnings; all errors are fatal then. */
+
+int
+Create_Admin (const char *dir, const char *update_dir, const char *repository,
+ const char *tag, const char *date, int nonbranch, int warn,
+ int dotemplate)
+{
+ FILE *fout;
+ char *cp;
+ char *reposcopy;
+ char *tmp;
+
+ TRACE (TRACE_FUNCTION, "Create_Admin (%s, %s, %s, %s, %s, %d, %d, %d)",
+ dir, update_dir, repository, tag ? tag : "",
+ date ? date : "", nonbranch, warn, dotemplate);
+
+ if (noexec)
+ return 0;
+
+ tmp = Xasprintf ("%s/%s", dir, CVSADM);
+ if (isfile (tmp))
+ error (1, 0, "there is a version in %s already", update_dir);
+
+ if (CVS_MKDIR (tmp, 0777) < 0)
+ {
+ free (tmp);
+ tmp = NULL;
+
+ /* We want to print out the entire update_dir, since a lot of
+ our code calls this function with dir == "." or dir ==
+ NULL. I hope that gives enough information in cases like
+ absolute pathnames; printing out xgetcwd() or something would
+ be way too verbose in the common cases. */
+
+ if (warn)
+ {
+ /* The reason that this is a warning, rather than silently
+ just skipping creating the directory, is that we don't want
+ CVS's behavior to vary subtly based on factors (like directory
+ permissions) which are not made clear to the user. With
+ the warning at least we let them know what is going on. */
+ error (0, errno, "warning: cannot make directory %s in %s",
+ CVSADM, update_dir);
+ return 1;
+ }
+ else
+ error (1, errno, "cannot make directory %s in %s",
+ CVSADM, update_dir);
+ }
+ else
+ {
+ free (tmp);
+ tmp = NULL;
+ }
+
+ /* record the current cvs root for later use */
+
+ Create_Root (dir, original_parsed_root->original);
+ if (dir != NULL)
+ tmp = Xasprintf ("%s/%s", dir, CVSADM_REP);
+ else
+ tmp = xstrdup (CVSADM_REP);
+ fout = CVS_FOPEN (tmp, "w+");
+ if (fout == NULL)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot open %s", tmp);
+ else
+ error (1, errno, "cannot open %s/%s", update_dir, CVSADM_REP);
+ }
+ reposcopy = xstrdup (repository);
+ Sanitize_Repository_Name (reposcopy);
+
+ /* The top level of the repository is a special case -- we need to
+ write it with an extra dot at the end. This trailing `.' stuff
+ rubs me the wrong way -- on the other hand, I don't want to
+ spend the time making sure all of the code can handle it if we
+ don't do it. */
+
+ if (strcmp (reposcopy, current_parsed_root->directory) == 0)
+ {
+ reposcopy = xrealloc (reposcopy, strlen (reposcopy) + 3);
+ strcat (reposcopy, "/.");
+ }
+
+ cp = reposcopy;
+
+ /*
+ * If the Repository file is to hold a relative path, try to strip off
+ * the leading CVSroot argument.
+ */
+ {
+ char *path = Xasprintf ("%s/", current_parsed_root->directory);
+ if (strncmp (cp, path, strlen (path)) == 0)
+ cp += strlen (path);
+ free (path);
+ }
+
+ if (fprintf (fout, "%s\n", cp) < 0)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "write to %s failed", tmp);
+ else
+ error (1, errno, "write to %s/%s failed", update_dir, CVSADM_REP);
+ }
+ if (fclose (fout) == EOF)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot close %s", tmp);
+ else
+ error (1, errno, "cannot close %s/%s", update_dir, CVSADM_REP);
+ }
+
+ /* now, do the Entries file */
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
+ else
+ (void) strcpy (tmp, CVSADM_ENT);
+ fout = CVS_FOPEN (tmp, "w+");
+ if (fout == NULL)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot open %s", tmp);
+ else
+ error (1, errno, "cannot open %s/%s", update_dir, CVSADM_ENT);
+ }
+ if (fclose (fout) == EOF)
+ {
+ if (update_dir[0] == '\0')
+ error (1, errno, "cannot close %s", tmp);
+ else
+ error (1, errno, "cannot close %s/%s", update_dir, CVSADM_ENT);
+ }
+
+ /* Create a new CVS/Tag file */
+ WriteTag (dir, tag, date, nonbranch, update_dir, repository);
+
+ TRACE (TRACE_FUNCTION, "Create_Admin");
+
+ free (reposcopy);
+ free (tmp);
+ return 0;
+}
diff --git a/src/cvs.h b/src/cvs.h
new file mode 100644
index 0000000..ce7d370
--- /dev/null
+++ b/src/cvs.h
@@ -0,0 +1,923 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS kit.
+ */
+
+/*
+ * basic information used in all source files
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h> /* this is stuff found via autoconf */
+#endif /* CONFIG_H */
+
+/* Add GNU attribute suppport. */
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# else
+# if __GNUC__ == 2 && __GNUC_MINOR__ < 96
+# define __pure__ /* empty */
+# endif
+# if __GNUC__ < 3
+# define __malloc__ /* empty */
+# endif
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __const__ const
+# define __format__ format
+# define __noreturn__ noreturn
+# define __printf__ printf
+# endif
+#endif /* __attribute__ */
+
+/* Some GNULIB headers require that we include system headers first. */
+#include "system.h"
+
+/* begin GNULIB headers */
+#include "dirname.h"
+#include "exit.h"
+#include "getdate.h"
+#include "minmax.h"
+#include "regex.h"
+#include "strcase.h"
+#include "stat-macros.h"
+#include "timespec.h"
+#include "unlocked-io.h"
+#include "xalloc.h"
+#include "xgetcwd.h"
+#include "xreadlink.h"
+#include "xsize.h"
+/* end GNULIB headers */
+
+#if ! STDC_HEADERS
+char *getenv();
+#endif /* ! STDC_HEADERS */
+
+/* Under OS/2, <stdio.h> doesn't define popen()/pclose(). */
+#ifdef USE_OWN_POPEN
+#include "popen.h"
+#endif
+
+#ifdef SERVER_SUPPORT
+/* If the system doesn't provide strerror, it won't be declared in
+ string.h. */
+char *strerror (int);
+#endif
+
+#include "hash.h"
+#include "stack.h"
+
+#include "root.h"
+
+#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
+# include "client.h"
+#endif
+
+#ifdef MY_NDBM
+#include "myndbm.h"
+#else
+#include <ndbm.h>
+#endif /* MY_NDBM */
+
+#include "wait.h"
+
+#include "rcs.h"
+
+
+
+/* Note that the _ONLY_ reason for PATH_MAX is if various system calls (getwd,
+ * getcwd, readlink) require/want us to use it. All other parts of CVS
+ * allocate pathname buffers dynamically, and we want to keep it that way.
+ */
+#include "pathmax.h"
+
+
+
+/* Definitions for the CVS Administrative directory and the files it contains.
+ Here as #define's to make changing the names a simple task. */
+
+#ifdef USE_VMS_FILENAMES
+#define CVSADM "CVS"
+#define CVSADM_ENT "CVS/Entries."
+#define CVSADM_ENTBAK "CVS/Entries.Backup"
+#define CVSADM_ENTLOG "CVS/Entries.Log"
+#define CVSADM_ENTSTAT "CVS/Entries.Static"
+#define CVSADM_REP "CVS/Repository."
+#define CVSADM_ROOT "CVS/Root."
+#define CVSADM_TAG "CVS/Tag."
+#define CVSADM_NOTIFY "CVS/Notify."
+#define CVSADM_NOTIFYTMP "CVS/Notify.tmp"
+#define CVSADM_BASE "CVS/Base"
+#define CVSADM_BASEREV "CVS/Baserev."
+#define CVSADM_BASEREVTMP "CVS/Baserev.tmp"
+#define CVSADM_TEMPLATE "CVS/Template."
+#else /* USE_VMS_FILENAMES */
+#define CVSADM "CVS"
+#define CVSADM_ENT "CVS/Entries"
+#define CVSADM_ENTBAK "CVS/Entries.Backup"
+#define CVSADM_ENTLOG "CVS/Entries.Log"
+#define CVSADM_ENTSTAT "CVS/Entries.Static"
+#define CVSADM_REP "CVS/Repository"
+#define CVSADM_ROOT "CVS/Root"
+#define CVSADM_TAG "CVS/Tag"
+#define CVSADM_NOTIFY "CVS/Notify"
+#define CVSADM_NOTIFYTMP "CVS/Notify.tmp"
+/* A directory in which we store base versions of files we currently are
+ editing with "cvs edit". */
+#define CVSADM_BASE "CVS/Base"
+#define CVSADM_BASEREV "CVS/Baserev"
+#define CVSADM_BASEREVTMP "CVS/Baserev.tmp"
+/* File which contains the template for use in log messages. */
+#define CVSADM_TEMPLATE "CVS/Template"
+#endif /* USE_VMS_FILENAMES */
+
+/* This is the special directory which we use to store various extra
+ per-directory information in the repository. It must be the same as
+ CVSADM to avoid creating a new reserved directory name which users cannot
+ use, but is a separate #define because if anyone changes it (which I don't
+ recommend), one needs to deal with old, unconverted, repositories.
+
+ See fileattr.h for details about file attributes, the only thing stored
+ in CVSREP currently. */
+#define CVSREP "CVS"
+
+/*
+ * Definitions for the CVSROOT Administrative directory and the files it
+ * contains. This directory is created as a sub-directory of the $CVSROOT
+ * environment variable, and holds global administration information for the
+ * entire source repository beginning at $CVSROOT.
+ */
+#define CVSROOTADM "CVSROOT"
+#define CVSROOTADM_CHECKOUTLIST "checkoutlist"
+#define CVSROOTADM_COMMITINFO "commitinfo"
+#define CVSROOTADM_CONFIG "config"
+#define CVSROOTADM_HISTORY "history"
+#define CVSROOTADM_IGNORE "cvsignore"
+#define CVSROOTADM_LOGINFO "loginfo"
+#define CVSROOTADM_MODULES "modules"
+#define CVSROOTADM_NOTIFY "notify"
+#define CVSROOTADM_PASSWD "passwd"
+#define CVSROOTADM_POSTADMIN "postadmin"
+#define CVSROOTADM_POSTPROXY "postproxy"
+#define CVSROOTADM_POSTTAG "posttag"
+#define CVSROOTADM_POSTWATCH "postwatch"
+#define CVSROOTADM_PREPROXY "preproxy"
+#define CVSROOTADM_RCSINFO "rcsinfo"
+#define CVSROOTADM_READERS "readers"
+#define CVSROOTADM_TAGINFO "taginfo"
+#define CVSROOTADM_USERS "users"
+#define CVSROOTADM_VALTAGS "val-tags"
+#define CVSROOTADM_VERIFYMSG "verifymsg"
+#define CVSROOTADM_WRAPPER "cvswrappers"
+#define CVSROOTADM_WRITERS "writers"
+
+#define CVSNULLREPOS "Emptydir" /* an empty directory */
+
+/* Other CVS file names */
+
+/* Files go in the attic if the head main branch revision is dead,
+ otherwise they go in the regular repository directories. The whole
+ concept of having an attic is sort of a relic from before death
+ support but on the other hand, it probably does help the speed of
+ some operations (such as main branch checkouts and updates). */
+#define CVSATTIC "Attic"
+
+#define CVSLCK "#cvs.lock"
+#define CVSHISTORYLCK "#cvs.history.lock"
+#define CVSVALTAGSLCK "#cvs.val-tags.lock"
+#define CVSRFL "#cvs.rfl"
+#define CVSPFL "#cvs.pfl"
+#define CVSWFL "#cvs.wfl"
+#define CVSPFLPAT "#cvs.pfl.*" /* wildcard expr to match plocks */
+#define CVSRFLPAT "#cvs.rfl.*" /* wildcard expr to match read locks */
+#define CVSEXT_LOG ",t"
+#define CVSPREFIX ",,"
+#define CVSDOTIGNORE ".cvsignore"
+#define CVSDOTWRAPPER ".cvswrappers"
+
+/* Command attributes -- see function lookup_command_attribute(). */
+#define CVS_CMD_IGNORE_ADMROOT 1
+
+/* Set if CVS needs to create a CVS/Root file upon completion of this
+ command. The name may be slightly confusing, because the flag
+ isn't really as general purpose as it seems (it is not set for cvs
+ release). */
+
+#define CVS_CMD_USES_WORK_DIR 2
+
+#define CVS_CMD_MODIFIES_REPOSITORY 4
+
+/* miscellaneous CVS defines */
+
+/* This is the string which is at the start of the non-log-message lines
+ that we put up for the user when they edit the log message. */
+#define CVSEDITPREFIX "CVS: "
+/* Number of characters in CVSEDITPREFIX to compare when deciding to strip
+ off those lines. We don't check for the space, to accomodate users who
+ have editors which strip trailing spaces. */
+#define CVSEDITPREFIXLEN 4
+
+#define CVSLCKAGE (60*60) /* 1-hour old lock files cleaned up */
+#define CVSLCKSLEEP 30 /* wait 30 seconds before retrying */
+#define CVSBRANCH "1.1.1" /* RCS branch used for vendor srcs */
+
+#ifdef USE_VMS_FILENAMES
+# define BAKPREFIX "_$"
+#else /* USE_VMS_FILENAMES */
+# define BAKPREFIX ".#" /* when rcsmerge'ing */
+#endif /* USE_VMS_FILENAMES */
+
+/*
+ * Special tags. -rHEAD refers to the head of an RCS file, regardless of any
+ * sticky tags. -rBASE refers to the current revision the user has checked
+ * out This mimics the behaviour of RCS.
+ */
+#define TAG_HEAD "HEAD"
+#define TAG_BASE "BASE"
+
+/* Environment variable used by CVS */
+#define CVSREAD_ENV "CVSREAD" /* make files read-only */
+#define CVSREAD_DFLT 0 /* writable files by default */
+
+#define CVSREADONLYFS_ENV "CVSREADONLYFS" /* repository is read-only */
+
+#define TMPDIR_ENV "TMPDIR" /* Temporary directory */
+#define CVS_PID_ENV "CVS_PID" /* pid of running cvs */
+
+#define EDITOR1_ENV "CVSEDITOR" /* which editor to use */
+#define EDITOR2_ENV "VISUAL" /* which editor to use */
+#define EDITOR3_ENV "EDITOR" /* which editor to use */
+
+#define CVSROOT_ENV "CVSROOT" /* source directory root */
+/* Define CVSROOT_DFLT to a fallback value for CVSROOT.
+ *
+#undef CVSROOT_DFL
+ */
+
+#define IGNORE_ENV "CVSIGNORE" /* More files to ignore */
+#define WRAPPER_ENV "CVSWRAPPERS" /* name of the wrapper file */
+
+#define CVSUMASK_ENV "CVSUMASK" /* Effective umask for repository */
+
+/*
+ * If the beginning of the Repository matches the following string, strip it
+ * so that the output to the logfile does not contain a full pathname.
+ *
+ * If the CVSROOT environment variable is set, it overrides this define.
+ */
+#define REPOS_STRIP "/master/"
+
+/* Large enough to hold DATEFORM. Not an arbitrary limit as long as
+ it is used for that purpose, and not to hold a string from the
+ command line, the client, etc. */
+#define MAXDATELEN 50
+
+/* The type of an entnode. */
+enum ent_type
+{
+ ENT_FILE, ENT_SUBDIR
+};
+
+/* structure of a entry record */
+struct entnode
+{
+ enum ent_type type;
+ char *user;
+ char *version;
+
+ /* Timestamp, or "" if none (never NULL). */
+ char *timestamp;
+
+ /* Keyword expansion options, or "" if none (never NULL). */
+ char *options;
+
+ char *tag;
+ char *date;
+ char *conflict;
+};
+typedef struct entnode Entnode;
+
+/* The type of request that is being done in do_module() */
+enum mtype
+{
+ CHECKOUT, TAG, PATCH, EXPORT, MISC
+};
+
+/*
+ * structure used for list-private storage by Entries_Open() and
+ * Version_TS() and Find_Directories().
+ */
+struct stickydirtag
+{
+ /* These fields pass sticky tag information from Entries_Open() to
+ Version_TS(). */
+ int aflag;
+ char *tag;
+ char *date;
+ int nonbranch;
+
+ /* This field is set by Entries_Open() if there was subdirectory
+ information; Find_Directories() uses it to see whether it needs
+ to scan the directory itself. */
+ int subdirs;
+};
+
+/* Flags for find_{names,dirs} routines */
+#define W_LOCAL 0x01 /* look for files locally */
+#define W_REPOS 0x02 /* look for files in the repository */
+#define W_ATTIC 0x04 /* look for files in the attic */
+
+/* Flags for return values of direnter procs for the recursion processor */
+enum direnter_type
+{
+ R_PROCESS = 1, /* process files and maybe dirs */
+ R_SKIP_FILES, /* don't process files in this dir */
+ R_SKIP_DIRS, /* don't process sub-dirs */
+ R_SKIP_ALL /* don't process files or dirs */
+};
+#ifdef ENUMS_CAN_BE_TROUBLE
+typedef int Dtype;
+#else
+typedef enum direnter_type Dtype;
+#endif
+
+/* Recursion processor lock types */
+#define CVS_LOCK_NONE 0
+#define CVS_LOCK_READ 1
+#define CVS_LOCK_WRITE 2
+
+/* Option flags for Parse_Info() */
+#define PIOPT_ALL 1 /* accept "all" keyword */
+
+extern const char *program_name, *program_path, *cvs_cmd_name;
+extern char *Editor;
+extern int cvsadmin_root;
+extern char *CurDir;
+extern int really_quiet, quiet;
+extern int use_editor;
+extern int cvswrite;
+extern mode_t cvsumask;
+
+/* Temp dir abstraction. */
+/* From main.c. */
+const char *get_cvs_tmp_dir (void);
+/* From filesubr.c. */
+const char *get_system_temp_dir (void);
+void push_env_temp_dir (void);
+
+
+/* This global variable holds the global -d option. It is NULL if -d
+ was not used, which means that we must get the CVSroot information
+ from the CVSROOT environment variable or from a CVS/Root file. */
+extern char *CVSroot_cmdline;
+
+/* This variable keeps track of all of the CVSROOT directories that
+ * have been seen by the client.
+ */
+extern List *root_directories;
+
+char *emptydir_name (void);
+int safe_location (char *);
+
+extern int trace; /* Show all commands */
+extern int noexec; /* Don't modify disk anywhere */
+extern int readonlyfs; /* fail on all write locks; succeed all read locks */
+extern int logoff; /* Don't write history entry */
+
+
+
+#define LOGMSG_REREAD_NEVER 0 /* do_verify - never reread message */
+#define LOGMSG_REREAD_ALWAYS 1 /* do_verify - always reread message */
+#define LOGMSG_REREAD_STAT 2 /* do_verify - reread message if changed */
+
+/* This header needs the LOGMSG_* defns above. */
+#include "parseinfo.h"
+
+/* This structure holds the global configuration data. */
+extern struct config *config;
+
+#ifdef CLIENT_SUPPORT
+extern List *dirs_sent_to_server; /* used to decide which "Argument
+ xxx" commands to send to each
+ server in multiroot mode. */
+#endif
+
+extern char *hostname;
+
+/* Externs that are included directly in the CVS sources */
+
+int RCS_merge (RCSNode *, const char *, const char *, const char *,
+ const char *, const char *);
+/* Flags used by RCS_* functions. See the description of the individual
+ functions for which flags mean what for each function. */
+#define RCS_FLAGS_FORCE 1
+#define RCS_FLAGS_DEAD 2
+#define RCS_FLAGS_QUIET 4
+#define RCS_FLAGS_MODTIME 8
+#define RCS_FLAGS_KEEPFILE 16
+#define RCS_FLAGS_USETIME 32
+
+int RCS_exec_rcsdiff (RCSNode *rcsfile, int diff_argc,
+ char * const *diff_argv, const char *options,
+ const char *rev1, const char *rev1_cache,
+ const char *rev2,
+ const char *label1, const char *label2,
+ const char *workfile);
+int diff_exec (const char *file1, const char *file2,
+ const char *label1, const char *label2,
+ int iargc, char * const *iargv, const char *out);
+
+
+#include "error.h"
+
+/* If non-zero, error will use the CVS protocol to report error
+ * messages. This will only be set in the CVS server parent process;
+ * most other code is run via do_cvs_command, which forks off a child
+ * process and packages up its stderr in the protocol.
+ *
+ * This needs to be here rather than in error.h in order to use an unforked
+ * error.h from GNULIB.
+ */
+extern int error_use_protocol;
+
+
+DBM *open_module (void);
+List *Find_Directories (char *repository, int which, List *entries);
+void Entries_Close (List *entries);
+List *Entries_Open (int aflag, char *update_dir);
+void Subdirs_Known (List *entries);
+void Subdir_Register (List *, const char *, const char *);
+void Subdir_Deregister (List *, const char *, const char *);
+
+void parse_tagdate (char **tag, char **date, const char *input);
+char *Make_Date (const char *rawdate);
+char *date_from_time_t (time_t);
+void date_to_internet (char *, const char *);
+void date_to_tm (struct tm *, const char *);
+void tm_to_internet (char *, const struct tm *);
+char *gmformat_time_t (time_t unixtime);
+char *format_date_alloc (char *text);
+
+char *Name_Repository (const char *dir, const char *update_dir);
+const char *Short_Repository (const char *repository);
+void Sanitize_Repository_Name (char *repository);
+
+char *entries_time (time_t unixtime);
+time_t unix_time_stamp (const char *file);
+char *time_stamp (const char *file);
+
+typedef int (*CALLPROC) (const char *repository, const char *value,
+ void *closure);
+int Parse_Info (const char *infofile, const char *repository,
+ CALLPROC callproc, int opt, void *closure);
+
+typedef RETSIGTYPE (*SIGCLEANUPPROC) (int);
+int SIG_register (int sig, SIGCLEANUPPROC sigcleanup);
+bool isdir (const char *file);
+bool isfile (const char *file);
+ssize_t islink (const char *file);
+bool isdevice (const char *file);
+bool isreadable (const char *file);
+bool iswritable (const char *file);
+bool isaccessible (const char *file, const int mode);
+const char *last_component (const char *path);
+char *get_homedir (void);
+char *strcat_filename_onto_homedir (const char *, const char *);
+char *cvs_temp_name (void);
+FILE *cvs_temp_file (char **filename);
+
+int ls (int argc, char *argv[]);
+int unlink_file (const char *f);
+int unlink_file_dir (const char *f);
+
+/* This is the structure that the recursion processor passes to the
+ fileproc to tell it about a particular file. */
+struct file_info
+{
+ /* Name of the file, without any directory component. */
+ const char *file;
+
+ /* Name of the directory we are in, relative to the directory in
+ which this command was issued. We have cd'd to this directory
+ (either in the working directory or in the repository, depending
+ on which sort of recursion we are doing). If we are in the directory
+ in which the command was issued, this is "". */
+ const char *update_dir;
+
+ /* update_dir and file put together, with a slash between them as
+ necessary. This is the proper way to refer to the file in user
+ messages. */
+ const char *fullname;
+
+ /* Name of the directory corresponding to the repository which contains
+ this file. */
+ const char *repository;
+
+ /* The pre-parsed entries for this directory. */
+ List *entries;
+
+ RCSNode *rcs;
+};
+
+/* This needs to be included after the struct file_info definition since some
+ * of the functions subr.h defines refer to struct file_info.
+ */
+#include "subr.h"
+
+int update (int argc, char *argv[]);
+/* The only place this is currently used outside of update.c is add.c.
+ * Restricting its use to update.c seems to be in the best interest of
+ * modularity, but I can't think of a good way to get an update of a
+ * resurrected file done and print the fact otherwise.
+ */
+void write_letter (struct file_info *finfo, int letter);
+int xcmp (const char *file1, const char *file2);
+void *valloc (size_t bytes);
+
+int Create_Admin (const char *dir, const char *update_dir,
+ const char *repository, const char *tag, const char *date,
+ int nonbranch, int warn, int dotemplate);
+int expand_at_signs (const char *, size_t, FILE *);
+
+/* Locking subsystem (implemented in lock.c). */
+
+int Reader_Lock (char *xrepository);
+void Simple_Lock_Cleanup (void);
+void Lock_Cleanup (void);
+
+/* Writelock an entire subtree, well the part specified by ARGC, ARGV, LOCAL,
+ and AFLAG, anyway. */
+void lock_tree_promotably (int argc, char **argv, int local, int which,
+ int aflag);
+
+/* See lock.c for description. */
+void lock_dir_for_write (const char *);
+
+/* Get a write lock for the history file. */
+int history_lock (const char *);
+void clear_history_lock (void);
+
+/* Get a write lock for the val-tags file. */
+int val_tags_lock (const char *);
+void clear_val_tags_lock (void);
+
+void Scratch_Entry (List * list, const char *fname);
+void ParseTag (char **tagp, char **datep, int *nonbranchp);
+void WriteTag (const char *dir, const char *tag, const char *date,
+ int nonbranch, const char *update_dir, const char *repository);
+void WriteTemplate (const char *update_dir, int dotemplate,
+ const char *repository);
+void cat_module (int status);
+void check_entries (char *dir);
+void close_module (DBM * db);
+void copy_file (const char *from, const char *to);
+void fperrmsg (FILE * fp, int status, int errnum, char *message,...);
+
+int ign_name (char *name);
+void ign_add (char *ign, int hold);
+void ign_add_file (char *file, int hold);
+void ign_setup (void);
+void ign_dir_add (char *name);
+int ignore_directory (const char *name);
+typedef void (*Ignore_proc) (const char *, const char *);
+void ignore_files (List *, List *, const char *, Ignore_proc);
+extern int ign_inhibit_server;
+
+#include "update.h"
+
+void make_directories (const char *name);
+void make_directory (const char *name);
+int mkdir_if_needed (const char *name);
+void rename_file (const char *from, const char *to);
+/* Expand wildcards in each element of (ARGC,ARGV). This is according to the
+ files which exist in the current directory, and accordingly to OS-specific
+ conventions regarding wildcard syntax. It might be desirable to change the
+ former in the future (e.g. "cvs status *.h" including files which don't exist
+ in the working directory). The result is placed in *PARGC and *PARGV;
+ the *PARGV array itself and all the strings it contains are newly
+ malloc'd. It is OK to call it with PARGC == &ARGC or PARGV == &ARGV. */
+void expand_wild (int argc, char **argv,
+ int *pargc, char ***pargv);
+
+/* exithandle.c */
+void signals_register (RETSIGTYPE (*handler)(int));
+void cleanup_register (void (*handler) (void));
+
+void update_delproc (Node * p);
+void usage (const char *const *cpp);
+void xchmod (const char *fname, int writable);
+List *Find_Names (char *repository, int which, int aflag,
+ List ** optentries);
+void Register (List * list, const char *fname, const char *vn, const char *ts,
+ const char *options, const char *tag, const char *date,
+ const char *ts_conflict);
+void Update_Logfile (const char *repository, const char *xmessage,
+ FILE *xlogfp, List *xchanges);
+void do_editor (const char *dir, char **messagep,
+ const char *repository, List *changes);
+
+void do_verify (char **messagep, const char *repository, List *changes);
+
+typedef int (*CALLBACKPROC) (int argc, char *argv[], char *where,
+ char *mwhere, char *mfile, int shorten, int local_specified,
+ char *omodule, char *msg);
+
+
+typedef int (*FILEPROC) (void *callerdat, struct file_info *finfo);
+typedef int (*FILESDONEPROC) (void *callerdat, int err,
+ const char *repository, const char *update_dir,
+ List *entries);
+typedef Dtype (*DIRENTPROC) (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+typedef int (*DIRLEAVEPROC) (void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries);
+
+int mkmodules (char *dir);
+int init (int argc, char **argv);
+
+int do_module (DBM * db, char *mname, enum mtype m_type, char *msg,
+ CALLBACKPROC callback_proc, char *where, int shorten,
+ int local_specified, int run_module_prog, int build_dirs,
+ char *extra_arg);
+void history_write (int type, const char *update_dir, const char *revs,
+ const char *name, const char *repository);
+int start_recursion (FILEPROC fileproc, FILESDONEPROC filesdoneproc,
+ DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc,
+ void *callerdat,
+ int argc, char *argv[], int local, int which,
+ int aflag, int locktype, char *update_preload,
+ int dosrcs, char *repository);
+void SIG_beginCrSect (void);
+void SIG_endCrSect (void);
+int SIG_inCrSect (void);
+void read_cvsrc (int *argc, char ***argv, const char *cmdname);
+
+/* flags for run_exec(), the fast system() for CVS */
+#define RUN_NORMAL 0x0000 /* no special behaviour */
+#define RUN_COMBINED 0x0001 /* stdout is duped to stderr */
+#define RUN_REALLY 0x0002 /* do the exec, even if noexec is on */
+#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */
+#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */
+#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */
+#define RUN_TTY (char *)0 /* for the benefit of lint */
+
+void run_add_arg_p (int *, size_t *, char ***, const char *s);
+void run_arg_free_p (int, char **);
+void run_add_arg (const char *s);
+void run_print (FILE * fp);
+void run_setup (const char *prog);
+int run_exec (const char *stin, const char *stout, const char *sterr,
+ int flags);
+int run_piped (int *, int *);
+
+/* other similar-minded stuff from run.c. */
+FILE *run_popen (const char *, const char *);
+int piped_child (char *const *, int *, int *, bool);
+void close_on_exec (int);
+
+pid_t waitpid (pid_t, int *, int);
+
+/*
+ * a struct vers_ts contains all the information about a file including the
+ * user and rcs file names, and the version checked out and the head.
+ *
+ * this is usually obtained from a call to Version_TS which takes a
+ * tag argument for the RCS file if desired
+ */
+struct vers_ts
+{
+ /* rcs version user file derives from, from CVS/Entries.
+ It can have the following special values:
+
+ NULL = file is not mentioned in Entries (this is also used for a
+ directory).
+ "" = INVALID! The comment used to say that it meant "no user file"
+ but as far as I know CVS didn't actually use it that way.
+ Note that according to cvs.texinfo, "" is not valid in the
+ Entries file.
+ 0 = user file is new
+ -vers = user file to be removed. */
+ char *vn_user;
+
+ /* Numeric revision number corresponding to ->vn_tag (->vn_tag
+ will often be symbolic). */
+ char *vn_rcs;
+ /* If ->tag is a simple tag in the RCS file--a tag which really
+ exists which is not a magic revision--and if ->date is NULL,
+ then this is a copy of ->tag. Otherwise, it is a copy of
+ ->vn_rcs. */
+ char *vn_tag;
+
+ /* This is the timestamp from stating the file in the working directory.
+ It is NULL if there is no file in the working directory. It is
+ "Is-modified" if we know the file is modified but don't have its
+ contents. */
+ char *ts_user;
+ /* Timestamp from CVS/Entries. For the server, ts_user and ts_rcs
+ are computed in a slightly different way, but the fact remains that
+ if they are equal the file in the working directory is unmodified
+ and if they differ it is modified. */
+ char *ts_rcs;
+
+ /* Options from CVS/Entries (keyword expansion), malloc'd. If none,
+ then it is an empty string (never NULL). */
+ char *options;
+
+ /* If non-NULL, there was a conflict (or merely a merge? See merge_file)
+ and the time stamp in this field is the time stamp of the working
+ directory file which was created with the conflict markers in it.
+ This is from CVS/Entries. */
+ char *ts_conflict;
+
+ /* Tag specified on the command line, or if none, tag stored in
+ CVS/Entries. */
+ char *tag;
+ /* Date specified on the command line, or if none, date stored in
+ CVS/Entries. */
+ char *date;
+ /* If this is 1, then tag is not a branch tag. If this is 0, then
+ tag may or may not be a branch tag. */
+ int nonbranch;
+
+ /* Pointer to entries file node */
+ Entnode *entdata;
+
+ /* Pointer to parsed src file info */
+ RCSNode *srcfile;
+};
+typedef struct vers_ts Vers_TS;
+
+Vers_TS *Version_TS (struct file_info *finfo, char *options, char *tag,
+ char *date, int force_tag_match,
+ int set_time);
+void freevers_ts (Vers_TS ** versp);
+
+/* Miscellaneous CVS infrastructure which layers on top of the recursion
+ processor (for example, needs struct file_info). */
+
+int Checkin (int type, struct file_info *finfo, char *rev,
+ char *tag, char *options, char *message);
+int No_Difference (struct file_info *finfo, Vers_TS *vers);
+/* TODO: can the finfo argument to special_file_mismatch be changed? -twp */
+int special_file_mismatch (struct file_info *finfo,
+ char *rev1, char *rev2);
+
+/* CVSADM_BASEREV stuff, from entries.c. */
+char *base_get (struct file_info *);
+void base_register (struct file_info *, char *);
+void base_deregister (struct file_info *);
+
+/*
+ * defines for Classify_File() to determine the current state of a file.
+ * These are also used as types in the data field for the list we make for
+ * Update_Logfile in commit, import, and add.
+ */
+enum classify_type
+{
+ T_UNKNOWN = 1, /* no old-style analog existed */
+ T_CONFLICT, /* C (conflict) list */
+ T_NEEDS_MERGE, /* G (needs merging) list */
+ T_MODIFIED, /* M (needs checked in) list */
+ T_CHECKOUT, /* O (needs checkout) list */
+ T_ADDED, /* A (added file) list */
+ T_REMOVED, /* R (removed file) list */
+ T_REMOVE_ENTRY, /* W (removed entry) list */
+ T_UPTODATE, /* File is up-to-date */
+ T_PATCH, /* P Like C, but can patch */
+ T_TITLE /* title for node type */
+};
+typedef enum classify_type Ctype;
+
+Ctype Classify_File (struct file_info *finfo, char *tag, char *date, char *options,
+ int force_tag_match, int aflag, Vers_TS **versp, int pipeout);
+
+/*
+ * structure used for list nodes passed to Update_Logfile() and
+ * do_editor().
+ */
+struct logfile_info
+{
+ enum classify_type type;
+ char *tag;
+ char *rev_old; /* rev number before a commit/modify,
+ NULL for add or import */
+ char *rev_new; /* rev number after a commit/modify,
+ add, or import, NULL for remove */
+};
+
+/* Wrappers. */
+
+typedef enum { WRAP_MERGE, WRAP_COPY } WrapMergeMethod;
+typedef enum {
+ /* -t and -f wrapper options. Treating directories as single files. */
+ WRAP_TOCVS,
+ WRAP_FROMCVS,
+ /* -k wrapper option. Default keyword expansion options. */
+ WRAP_RCSOPTION
+} WrapMergeHas;
+
+void wrap_setup (void);
+int wrap_name_has (const char *name,WrapMergeHas has);
+char *wrap_rcsoption (const char *fileName, int asFlag);
+char *wrap_tocvs_process_file (const char *fileName);
+int wrap_merge_is_copy (const char *fileName);
+void wrap_fromcvs_process_file (const char *fileName);
+void wrap_add_file (const char *file,int temp);
+void wrap_add (char *line,int temp);
+void wrap_send (void);
+#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
+void wrap_unparse_rcs_options (char **, int);
+#endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
+
+/* Pathname expansion */
+char *expand_path (const char *name, const char *cvsroot, bool formatsafe,
+ const char *file, int line);
+
+/* User variables. */
+extern List *variable_list;
+
+void variable_set (char *nameval);
+
+int watch (int argc, char **argv);
+int edit (int argc, char **argv);
+int unedit (int argc, char **argv);
+int editors (int argc, char **argv);
+int watchers (int argc, char **argv);
+int annotate (int argc, char **argv);
+int add (int argc, char **argv);
+int admin (int argc, char **argv);
+int checkout (int argc, char **argv);
+int commit (int argc, char **argv);
+int diff (int argc, char **argv);
+int history (int argc, char **argv);
+int import (int argc, char **argv);
+int cvslog (int argc, char **argv);
+#ifdef AUTH_CLIENT_SUPPORT
+/* Some systems (namely Mac OS X) have conflicting definitions for these
+ * functions. Avoid them.
+ */
+#ifdef HAVE_LOGIN
+# define login cvs_login
+#endif /* HAVE_LOGIN */
+#ifdef HAVE_LOGOUT
+# define logout cvs_logout
+#endif /* HAVE_LOGOUT */
+int login (int argc, char **argv);
+int logout (int argc, char **argv);
+#endif /* AUTH_CLIENT_SUPPORT */
+int patch (int argc, char **argv);
+int release (int argc, char **argv);
+int cvsremove (int argc, char **argv);
+int rtag (int argc, char **argv);
+int cvsstatus (int argc, char **argv);
+int cvstag (int argc, char **argv);
+int version (int argc, char **argv);
+
+unsigned long int lookup_command_attribute (const char *);
+
+#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT)
+char *scramble (char *str);
+char *descramble (char *str);
+#endif /* AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT */
+
+#ifdef AUTH_CLIENT_SUPPORT
+char *get_cvs_password (void);
+/* get_cvs_port_number() is not pure since the /etc/services file could change
+ * between calls. */
+int get_cvs_port_number (const cvsroot_t *root);
+/* normalize_cvsroot() is not pure since it calls get_cvs_port_number. */
+char *normalize_cvsroot (const cvsroot_t *root)
+ __attribute__ ((__malloc__));
+#endif /* AUTH_CLIENT_SUPPORT */
+
+void tag_check_valid (const char *, int, char **, int, int, char *, bool);
+
+#include "server.h"
+
+/* From server.c and documented there. */
+void cvs_output (const char *, size_t);
+void cvs_output_binary (char *, size_t);
+void cvs_outerr (const char *, size_t);
+void cvs_flusherr (void);
+void cvs_flushout (void);
+void cvs_output_tagged (const char *, const char *);
+
+extern const char *global_session_id;
+
+/* From find_names.c. */
+List *find_files (const char *dir, const char *pat);
diff --git a/src/cvsbug.in b/src/cvsbug.in
new file mode 100755
index 0000000..efc156d
--- /dev/null
+++ b/src/cvsbug.in
@@ -0,0 +1,527 @@
+#! /bin/sh
+# Submit a problem report to a GNATS site.
+# Copyright (C) 1993 Free Software Foundation, Inc.
+# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
+# version written by Heinz G. Seidl (hgs@ide.com).
+#
+# This file is part of GNU GNATS.
+# Modified by Berliner for CVS.
+#
+# GNU GNATS is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU GNATS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# The version of this send-pr.
+VERSION=3.2
+
+# The submitter-id for your site.
+SUBMITTER=net
+
+## # Where the GNATS directory lives, if at all.
+## [ -z "$GNATS_ROOT" ] &&
+## GNATS_ROOT=/usr/local/lib/gnats/gnats-db
+
+# The default mail address for PR submissions.
+GNATS_ADDR=@PACKAGE_BUGREPORT@
+
+## # Where the gnats category tree lives.
+## DATADIR=/usr/local/lib
+
+## # If we've been moved around, try using GCC_EXEC_PREFIX.
+## [ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=${GCC_EXEC_PREFIX}..
+
+# The default release for this host.
+DEFAULT_RELEASE="@VERSION@"
+
+# The default organization.
+DEFAULT_ORGANIZATION="net"
+
+## # The default site to look for.
+## GNATS_SITE=unknown
+
+## # Newer config information?
+## [ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config
+
+# Hack mktemp on systems that don't have it.
+@MKTEMP_SH_FUNCTION@
+MKTEMP="@MKTEMP@"
+
+# What mailer to use. This must come after the config file, since it is
+# host-dependent.
+SENDMAIL="@SENDMAIL@"
+MAIL_AGENT="$SENDMAIL -oi -t"
+MAILER=`echo $MAIL_AGENT | sed -e 's, .*,,'`
+if [ ! -f "$MAILER" ] ; then
+ echo "$COMMAND: Cannot find mail program \"$MAILER\"."
+ echo "$COMMAND: Please fix the MAIL_AGENT entry in the $COMMAND file."
+ exit 1
+fi
+
+if test "`echo -n foo`" = foo ; then
+ ECHON=bsd
+elif test "`echo 'foo\c'`" = foo ; then
+ ECHON=sysv
+else
+ ECHON=none
+fi
+
+if [ $ECHON = bsd ] ; then
+ ECHON1="echo -n"
+ ECHON2=
+elif [ $ECHON = sysv ] ; then
+ ECHON1=echo
+ ECHON2='\c'
+else
+ ECHON1=echo
+ ECHON2=
+fi
+
+#
+
+[ -z "$TMPDIR" ] && TMPDIR=/tmp
+
+TEMP="`$MKTEMP $TMPDIR/p.XXXXXX`"
+BAD="`$MKTEMP $TMPDIR/pbad.XXXXXX`"
+REF="`$MKTEMP $TMPDIR/pf.XXXXXX`"
+
+if [ -z "$LOGNAME" -a -n "$USER" ]; then
+ LOGNAME=$USER
+fi
+
+FROM="$LOGNAME"
+REPLY_TO="$LOGNAME"
+
+# Find out the name of the originator of this PR.
+if [ -n "$NAME" ]; then
+ ORIGINATOR="$NAME"
+elif [ -f $HOME/.fullname ]; then
+ ORIGINATOR="`sed -e '1q' $HOME/.fullname`"
+elif [ -f /bin/domainname ]; then
+ if [ "`/bin/domainname`" != "" -a -f /usr/bin/ypcat ]; then
+ # Must use temp file due to incompatibilities in quoting behavior
+ # and to protect shell metacharacters in the expansion of $LOGNAME
+ /usr/bin/ypcat passwd 2>/dev/null | cat - /etc/passwd | grep "^$LOGNAME:" |
+ cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
+ ORIGINATOR="`cat $TEMP`"
+ rm -f $TEMP
+ fi
+fi
+
+if [ "$ORIGINATOR" = "" ]; then
+ grep "^$LOGNAME:" /etc/passwd | cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
+ ORIGINATOR="`cat $TEMP`"
+ rm -f $TEMP
+fi
+
+if [ -n "$ORGANIZATION" ]; then
+ if [ -f "$ORGANIZATION" ]; then
+ ORGANIZATION="`cat $ORGANIZATION`"
+ fi
+else
+ if [ -n "$DEFAULT_ORGANIZATION" ]; then
+ ORGANIZATION="$DEFAULT_ORGANIZATION"
+ elif [ -f $HOME/.organization ]; then
+ ORGANIZATION="`cat $HOME/.organization`"
+ elif [ -f $HOME/.signature ]; then
+ ORGANIZATION="`cat $HOME/.signature`"
+ fi
+fi
+
+# If they don't have a preferred editor set, then use
+if [ -z "$VISUAL" ]; then
+ if [ -z "$EDITOR" ]; then
+ EDIT=vi
+ else
+ EDIT="$EDITOR"
+ fi
+else
+ EDIT="$VISUAL"
+fi
+
+# Find out some information.
+SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \
+ ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""`
+ARCH=`[ -f /bin/arch ] && /bin/arch`
+MACHINE=`[ -f /bin/machine ] && /bin/machine`
+
+COMMAND=`echo $0 | sed -e 's,.*/,,'`
+## USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id]
+USAGE="Usage: $COMMAND [-PVL]
+[--version]"
+REMOVE=
+BATCH=
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -r) ;; # Ignore for backward compat.
+## -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+## shift ; GNATS_ADDR="$1"
+## EXPLICIT_GNATS_ADDR=true
+## ;;
+## -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+## shift ; IN_FILE="$1"
+## if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then
+## echo "$COMMAND: cannot read $IN_FILE"
+## exit 1
+## fi
+## ;;
+ -b | --batch) BATCH=true ;;
+ -p | -P | --print) PRINT=true ;;
+ -L | --list) FORMAT=norm ;;
+ -l | -CL | --lisp) FORMAT=lisp ;;
+## --request-id) REQUEST_ID=true ;;
+ -h | --help) echo "$USAGE"; exit 0 ;;
+ -V | --version) echo "$VERSION"; exit 0 ;;
+ -*) echo "$USAGE" ; exit 1 ;;
+ *) echo "$USAGE" ; exit 1
+## if [ -z "$USER_GNATS_SITE" ]; then
+## if [ ! -r "$DATADIR/gnats/$1" ]; then
+## echo "$COMMAND: the GNATS site $1 does not have a categories list."
+## exit 1
+## else
+## # The site name is the alias they'll have to have created.
+## USER_GNATS_SITE=$1
+## fi
+## else
+## echo "$USAGE" ; exit 1
+## fi
+ ;;
+ esac
+ shift
+done
+
+if [ -n "$USER_GNATS_SITE" ]; then
+ GNATS_SITE=$USER_GNATS_SITE
+ GNATS_ADDR=$USER_GNATS_SITE-gnats
+fi
+
+if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then
+ cat << '__EOF__'
+It seems that send-pr is not installed with your unique submitter-id.
+You need to run
+
+ install-sid YOUR-SID
+
+where YOUR-SID is the identification code you received with `send-pr'.
+`send-pr' will automatically insert this value into the template field
+`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net'
+for this value. If you do not know your id, run `send-pr --request-id' to
+get one from your support site.
+__EOF__
+ exit 1
+fi
+
+## if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then
+## CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort`
+## else
+## echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list."
+## exit 1
+## fi
+CATEGORIES="contrib cvs doc pcl-cvs portability"
+
+if [ -z "$CATEGORIES" ]; then
+ echo "$COMMAND: the categories list for $GNATS_SITE was empty!"
+ exit 1
+fi
+
+case "$FORMAT" in
+ lisp) echo "$CATEGORIES" | \
+ awk 'BEGIN {printf "( "}
+ {printf "(\"%s\") ",$0}
+ END {printf ")\n"}'
+ exit 0
+ ;;
+ norm) l=`echo "$CATEGORIES" | \
+ awk 'BEGIN {max = 0; }
+ { if (length($0) > max) { max = length($0); } }
+ END {print max + 1;}'`
+ c=`expr 70 / $l`
+ if [ $c -eq 0 ]; then c=1; fi
+ echo "$CATEGORIES" | \
+ awk 'BEGIN {print "Known categories:"; i = 0 }
+ { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } }
+ END { print ""; }'
+ exit 0
+ ;;
+esac
+
+ORIGINATOR_C='<name of the PR author (one line)>'
+ORGANIZATION_C='<organization of PR author (multiple lines)>'
+CONFIDENTIAL_C='<[ yes | no ] (one line)>'
+SYNOPSIS_C='<synopsis of the problem (one line)>'
+SEVERITY_C='<[ non-critical | serious | critical ] (one line)>'
+PRIORITY_C='<[ low | medium | high ] (one line)>'
+CATEGORY_C='<name of the product (one line)>'
+CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>'
+RELEASE_C='<release number or tag (one line)>'
+ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>'
+DESCRIPTION_C='<precise description of the problem (multiple lines)>'
+HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>'
+FIX_C='<how to correct or work around the problem, if known (multiple lines)>'
+
+# Catch some signals. ($xs kludge needed by Sun /bin/sh)
+xs=0
+trap 'rm -f $REF $TEMP; exit $xs' 0
+trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15
+
+# If they told us to use a specific file, then do so.
+if [ -n "$IN_FILE" ]; then
+ if [ "$IN_FILE" = "-" ]; then
+ # The PR is coming from the standard input.
+ if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+ sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP
+ else
+ cat > $TEMP
+ fi
+ else
+ # Use the file they named.
+ if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+ sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP
+ else
+ cat $IN_FILE > $TEMP
+ fi
+ fi
+else
+
+ if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+ # If their PR_FORM points to a bogus entry, then bail.
+ if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then
+ echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM"
+ sleep 1
+ PRINT_INTERN=bad_prform
+ fi
+ fi
+
+ if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+ cp $PR_FORM $TEMP ||
+ ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit )
+ else
+ for file in $TEMP $REF ; do
+ cat > $file << '__EOF__'
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as
+SEND-PR: will all comments (text enclosed in `<' and `>').
+SEND-PR:
+SEND-PR: Choose from the following categories:
+SEND-PR:
+__EOF__
+
+ # Format the categories so they fit onto lines.
+ l=`echo "$CATEGORIES" | \
+ awk 'BEGIN {max = 0; }
+ { if (length($0) > max) { max = length($0); } }
+ END {print max + 1;}'`
+ c=`expr 61 / $l`
+ if [ $c -eq 0 ]; then c=1; fi
+ echo "$CATEGORIES" | \
+ awk 'BEGIN {printf "SEND-PR: "; i = 0 }
+ { printf ("%-'$l'.'$l's", $0);
+ if ((++i % '$c') == 0) { printf "\nSEND-PR: " } }
+ END { printf "\nSEND-PR:\n"; }' >> $file
+
+ cat >> $file << __EOF__
+To: $GNATS_ADDR
+Subject:
+From: $FROM
+Reply-To: $REPLY_TO
+X-send-pr-version: $VERSION
+
+
+>Submitter-Id: $SUBMITTER
+>Originator: $ORIGINATOR
+>Organization:
+${ORGANIZATION-$ORGANIZATION_C}
+>Confidential: $CONFIDENTIAL_C
+>Synopsis: $SYNOPSIS_C
+>Severity: $SEVERITY_C
+>Priority: $PRIORITY_C
+>Category: $CATEGORY_C
+>Class: $CLASS_C
+>Release: ${DEFAULT_RELEASE-$RELEASE_C}
+>Environment:
+ $ENVIRONMENT_C
+`[ -n "$SYSTEM" ] && echo System: $SYSTEM`
+`[ -n "$ARCH" ] && echo Architecture: $ARCH`
+`[ -n "$MACHINE" ] && echo Machine: $MACHINE`
+>Description:
+ $DESCRIPTION_C
+>How-To-Repeat:
+ $HOW_TO_REPEAT_C
+>Fix:
+ $FIX_C
+__EOF__
+ done
+ fi
+
+ if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then
+ cat $TEMP
+ xs=0; exit
+ fi
+
+ chmod u+w $TEMP
+ if [ -z "$REQUEST_ID" ]; then
+ eval $EDIT $TEMP
+ else
+ ed -s $TEMP << '__EOF__'
+/^Subject/s/^Subject:.*/Subject: request for a customer id/
+/^>Category/s/^>Category:.*/>Category: send-pr/
+w
+q
+__EOF__
+ fi
+
+ if cmp -s $REF $TEMP ; then
+ echo "$COMMAND: problem report not filled out, therefore not sent"
+ xs=1; exit
+ fi
+fi
+
+#
+# Check the enumeration fields
+
+# This is a "sed-subroutine" with one keyword parameter
+# (with workaround for Sun sed bug)
+#
+SED_CMD='
+/$PATTERN/{
+s|||
+s|<.*>||
+s|^[ ]*||
+s|[ ]*$||
+p
+q
+}'
+
+
+while [ -z "$REQUEST_ID" ]; do
+ CNT=0
+
+ # 1) Confidential
+ #
+ PATTERN=">Confidential:"
+ CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$CONFIDENTIAL" in
+ ""|yes|no) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;;
+ esac
+ #
+ # 2) Severity
+ #
+ PATTERN=">Severity:"
+ SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$SEVERITY" in
+ ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'."
+ esac
+ #
+ # 3) Priority
+ #
+ PATTERN=">Priority:"
+ PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$PRIORITY" in
+ ""|low|medium|high) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'."
+ esac
+ #
+ # 4) Category
+ #
+ PATTERN=">Category:"
+ CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ FOUND=
+ for C in $CATEGORIES
+ do
+ if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi
+ done
+ if [ -n "$FOUND" ]; then
+ CNT=`expr $CNT + 1`
+ else
+ if [ -z "$CATEGORY" ]; then
+ echo "$COMMAND: you must include a Category: field in your report."
+ else
+ echo "$COMMAND: \`$CATEGORY' is not a known category."
+ fi
+ fi
+ #
+ # 5) Class
+ #
+ PATTERN=">Class:"
+ CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$CLASS" in
+ ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'."
+ esac
+
+ [ $CNT -lt 5 -a -z "$BATCH" ] &&
+ echo "Errors were found with the problem report."
+
+ while true; do
+ if [ -z "$BATCH" ]; then
+ $ECHON1 "a)bort, e)dit or s)end? $ECHON2"
+ read input
+ else
+ if [ $CNT -eq 5 ]; then
+ input=s
+ else
+ input=a
+ fi
+ fi
+ case "$input" in
+ a*)
+ if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $TEMP $BAD
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ xs=1; exit
+ ;;
+ e*)
+ eval $EDIT $TEMP
+ continue 2
+ ;;
+ s*)
+ break 2
+ ;;
+ esac
+ done
+done
+#
+# Remove comments and send the problem report
+# (we have to use patterns, where the comment contains regex chars)
+#
+# /^>Originator:/s;$ORIGINATOR;;
+sed -e "
+/^SEND-PR:/d
+/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;;
+/^>Confidential:/s;<.*>;;
+/^>Synopsis:/s;$SYNOPSIS_C;;
+/^>Severity:/s;<.*>;;
+/^>Priority:/s;<.*>;;
+/^>Category:/s;$CATEGORY_C;;
+/^>Class:/s;<.*>;;
+/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;;
+/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;;
+/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;;
+/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;;
+/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;;
+" $TEMP > $REF
+
+if $MAIL_AGENT < $REF; then
+ echo "$COMMAND: problem report sent"
+ xs=0; exit
+else
+ echo "$COMMAND: mysterious mail failure."
+ if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $REF $BAD
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ xs=1; exit
+fi
diff --git a/src/cvsrc.c b/src/cvsrc.c
new file mode 100644
index 0000000..bb90fb8
--- /dev/null
+++ b/src/cvsrc.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1993 david d zuhn
+ *
+ * Written by david d `zoo' zuhn while at Cygnus Support
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ */
+
+
+#include "cvs.h"
+#include "getline.h"
+
+/* this file is to be found in the user's home directory */
+
+#ifndef CVSRC_FILENAME
+#define CVSRC_FILENAME ".cvsrc"
+#endif
+char cvsrc[] = CVSRC_FILENAME;
+
+#define GROW 10
+
+/* Read cvsrc, processing options matching CMDNAME ("cvs" for global
+ options, and update *ARGC and *ARGV accordingly. */
+
+void
+read_cvsrc (int *argc, char ***argv, const char *cmdname)
+{
+ char *homedir;
+ char *homeinit;
+ FILE *cvsrcfile;
+
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+
+ char *optstart;
+
+ int command_len;
+ int found = 0;
+
+ int i;
+
+ int new_argc;
+ int max_new_argv;
+ char **new_argv;
+
+ /* old_argc and old_argv hold the values returned from the
+ previous invocation of read_cvsrc and are used to free the
+ allocated memory. The first invocation of read_cvsrc gets argv
+ from the system, this memory must not be free'd. */
+ static int old_argc = 0;
+ static char **old_argv = NULL;
+
+ /* don't do anything if argc is -1, since that implies "help" mode */
+ if (*argc == -1)
+ return;
+
+ /* determine filename for ~/.cvsrc */
+
+ homedir = get_homedir ();
+ /* If we can't find a home directory, ignore ~/.cvsrc. This may
+ make tracking down problems a bit of a pain, but on the other
+ hand it might be obnoxious to complain when CVS will function
+ just fine without .cvsrc (and many users won't even know what
+ .cvsrc is). */
+ if (!homedir)
+ return;
+
+ homeinit = strcat_filename_onto_homedir (homedir, cvsrc);
+
+ /* if it can't be read, there's no point to continuing */
+
+ if (!isreadable (homeinit))
+ {
+ free (homeinit);
+ return;
+ }
+
+ /* now scan the file until we find the line for the command in question */
+
+ line = NULL;
+ line_chars_allocated = 0;
+ command_len = strlen (cmdname);
+ cvsrcfile = xfopen (homeinit, "r");
+ while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile))
+ >= 0)
+ {
+ /* skip over comment lines */
+ if (line[0] == '#')
+ continue;
+
+ /* stop if we match the current command */
+ if (!strncmp (line, cmdname, command_len)
+ && isspace ((unsigned char) *(line + command_len)))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (line_length < 0 && !feof (cvsrcfile))
+ error (0, errno, "cannot read %s", homeinit);
+
+ fclose (cvsrcfile);
+
+ /* setup the new options list */
+
+ new_argc = 1;
+ max_new_argv = (*argc) + GROW;
+ new_argv = xnmalloc (max_new_argv, sizeof (char *));
+ new_argv[0] = xstrdup ((*argv)[0]);
+
+ if (found)
+ {
+ /* skip over command in the options line */
+ for (optstart = strtok (line + command_len, "\t \n");
+ optstart;
+ optstart = strtok (NULL, "\t \n"))
+ {
+ new_argv [new_argc++] = xstrdup (optstart);
+
+ if (new_argc >= max_new_argv)
+ {
+ max_new_argv += GROW;
+ new_argv = xnrealloc (new_argv, max_new_argv, sizeof (char *));
+ }
+ }
+ }
+
+ if (line != NULL)
+ free (line);
+
+ /* now copy the remaining arguments */
+
+ if (new_argc + *argc > max_new_argv)
+ {
+ max_new_argv = new_argc + *argc;
+ new_argv = xnrealloc (new_argv, max_new_argv, sizeof (char *));
+ }
+ for (i = 1; i < *argc; i++)
+ new_argv [new_argc++] = xstrdup ((*argv)[i]);
+
+ if (old_argv != NULL)
+ {
+ /* Free the memory which was allocated in the previous
+ read_cvsrc call. */
+ free_names (&old_argc, old_argv);
+ }
+
+ old_argc = *argc = new_argc;
+ old_argv = *argv = new_argv;
+
+ free (homeinit);
+ return;
+}
diff --git a/src/diff.c b/src/diff.c
new file mode 100644
index 0000000..84fc103
--- /dev/null
+++ b/src/diff.c
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Difference
+ *
+ * Run diff against versions in the repository. Options that are specified are
+ * passed on directly to "rcsdiff".
+ *
+ * Without any file arguments, runs diff against all the currently modified
+ * files.
+ */
+
+#include "cvs.h"
+
+enum diff_file
+{
+ DIFF_ERROR,
+ DIFF_ADDED,
+ DIFF_REMOVED,
+ DIFF_DIFFERENT,
+ DIFF_SAME
+};
+
+static Dtype diff_dirproc (void *callerdat, const char *dir,
+ const char *pos_repos, const char *update_dir,
+ List *entries);
+static int diff_filesdoneproc (void *callerdat, int err,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int diff_dirleaveproc (void *callerdat, const char *dir,
+ int err, const char *update_dir,
+ List *entries);
+static enum diff_file diff_file_nodiff (struct file_info *finfo, Vers_TS *vers,
+ enum diff_file, char **rev1_cache );
+static int diff_fileproc (void *callerdat, struct file_info *finfo);
+static void diff_mark_errors (int err);
+
+
+/* Global variables. Would be cleaner if we just put this stuff in a
+ struct like log.c does. */
+
+/* Command line tags, from -r option. Points into argv. */
+static char *diff_rev1, *diff_rev2;
+/* Command line dates, from -D option. Malloc'd. */
+static char *diff_date1, *diff_date2;
+static char *use_rev1, *use_rev2;
+static int have_rev1_label, have_rev2_label;
+
+/* Revision of the user file, if it is unchanged from something in the
+ repository and we want to use that fact. */
+static char *user_file_rev;
+
+static char *options;
+static char **diff_argv;
+static int diff_argc;
+static size_t diff_arg_allocated;
+static int diff_errors;
+static int empty_files;
+
+static const char *const diff_usage[] =
+{
+ "Usage: %s %s [-lR] [-k kopt] [format_options]\n",
+ " [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-k kopt\tSpecify keyword expansion mode.\n",
+ "\t-D d1\tDiff revision for date against working file.\n",
+ "\t-D d2\tDiff rev1/date1 against date2.\n",
+ "\t-r rev1\tDiff revision for rev1 against working file.\n",
+ "\t-r rev2\tDiff rev1/date1 against rev2.\n",
+ "\nformat_options:\n",
+ " -i --ignore-case Consider upper- and lower-case to be the same.\n",
+ " -w --ignore-all-space Ignore all white space.\n",
+ " -b --ignore-space-change Ignore changes in the amount of white space.\n",
+ " -B --ignore-blank-lines Ignore changes whose lines are all blank.\n",
+ " -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n",
+ " --binary Read and write data in binary mode.\n",
+ " -a --text Treat all files as text.\n\n",
+ " -c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.\n",
+ " -u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.\n",
+ " -NUM Use NUM context lines.\n",
+ " -L LABEL --label LABEL Use LABEL instead of file name.\n",
+ " -p --show-c-function Show which C function each change is in.\n",
+ " -F RE --show-function-line=RE Show the most recent line matching RE.\n",
+ " --brief Output only whether files differ.\n",
+ " -e --ed Output an ed script.\n",
+ " -f --forward-ed Output something like an ed script in forward order.\n",
+ " -n --rcs Output an RCS format diff.\n",
+ " -y --side-by-side Output in two columns.\n",
+ " -W NUM --width=NUM Output at most NUM (default 130) characters per line.\n",
+ " --left-column Output only the left column of common lines.\n",
+ " --suppress-common-lines Do not output common lines.\n",
+ " --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.\n",
+ " --GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.\n",
+ " --line-format=LFMT Similar, but format all input lines with LFMT.\n",
+ " --LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.\n",
+ " LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.\n",
+ " GFMT may contain:\n",
+ " %%< lines from FILE1\n",
+ " %%> lines from FILE2\n",
+ " %%= lines common to FILE1 and FILE2\n",
+ " %%[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER\n",
+ " LETTERs are as follows for new group, lower case for old group:\n",
+ " F first line number\n",
+ " L last line number\n",
+ " N number of lines = L-F+1\n",
+ " E F-1\n",
+ " M L+1\n",
+ " LFMT may contain:\n",
+ " %%L contents of line\n",
+ " %%l contents of line, excluding any trailing newline\n",
+ " %%[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number\n",
+ " Either GFMT or LFMT may contain:\n",
+ " %%%% %%\n",
+ " %%c'C' the single character C\n",
+ " %%c'\\OOO' the character with octal code OOO\n\n",
+ " -t --expand-tabs Expand tabs to spaces in output.\n",
+ " -T --initial-tab Make tabs line up by prepending a tab.\n\n",
+ " -N --new-file Treat absent files as empty.\n",
+ " -s --report-identical-files Report when two files are the same.\n",
+ " --horizon-lines=NUM Keep NUM lines of the common prefix and suffix.\n",
+ " -d --minimal Try hard to find a smaller set of changes.\n",
+ " -H --speed-large-files Assume large files and many scattered small changes.\n",
+ "\n(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+/* I copied this array directly out of diff.c in diffutils 2.7, after
+ removing the following entries, none of which seem relevant to use
+ with CVS:
+ --help
+ --version (-v)
+ --recursive (-r)
+ --unidirectional-new-file (-P)
+ --starting-file (-S)
+ --exclude (-x)
+ --exclude-from (-X)
+ --sdiff-merge-assist
+ --paginate (-l) (doesn't work with library callbacks)
+
+ I changed the options which take optional arguments (--context and
+ --unified) to return a number rather than a letter, so that the
+ optional argument could be handled more easily. I changed the
+ --brief and --ifdef options to return numbers, since -q and -D mean
+ something else to cvs diff.
+
+ The numbers 129- that appear in the fourth element of some entries
+ tell the big switch in `diff' how to process those options. -- Ian
+
+ The following options, which diff lists as "An alias, no longer
+ recommended" have been removed: --file-label --entire-new-file
+ --ascii --print. */
+
+static struct option const longopts[] =
+{
+ {"ignore-blank-lines", 0, 0, 'B'},
+ {"context", 2, 0, 143},
+ {"ifdef", 1, 0, 131},
+ {"show-function-line", 1, 0, 'F'},
+ {"speed-large-files", 0, 0, 'H'},
+ {"ignore-matching-lines", 1, 0, 'I'},
+ {"label", 1, 0, 'L'},
+ {"new-file", 0, 0, 'N'},
+ {"initial-tab", 0, 0, 'T'},
+ {"width", 1, 0, 'W'},
+ {"text", 0, 0, 'a'},
+ {"ignore-space-change", 0, 0, 'b'},
+ {"minimal", 0, 0, 'd'},
+ {"ed", 0, 0, 'e'},
+ {"forward-ed", 0, 0, 'f'},
+ {"ignore-case", 0, 0, 'i'},
+ {"rcs", 0, 0, 'n'},
+ {"show-c-function", 0, 0, 'p'},
+
+ /* This is a potentially very useful option, except the output is so
+ silly. It would be much better for it to look like "cvs rdiff -s"
+ which displays all the same info, minus quite a few lines of
+ extraneous garbage. */
+ {"brief", 0, 0, 145},
+
+ {"report-identical-files", 0, 0, 's'},
+ {"expand-tabs", 0, 0, 't'},
+ {"ignore-all-space", 0, 0, 'w'},
+ {"side-by-side", 0, 0, 'y'},
+ {"unified", 2, 0, 146},
+ {"left-column", 0, 0, 129},
+ {"suppress-common-lines", 0, 0, 130},
+ {"old-line-format", 1, 0, 132},
+ {"new-line-format", 1, 0, 133},
+ {"unchanged-line-format", 1, 0, 134},
+ {"line-format", 1, 0, 135},
+ {"old-group-format", 1, 0, 136},
+ {"new-group-format", 1, 0, 137},
+ {"unchanged-group-format", 1, 0, 138},
+ {"changed-group-format", 1, 0, 139},
+ {"horizon-lines", 1, 0, 140},
+ {"binary", 0, 0, 142},
+ {0, 0, 0, 0}
+};
+
+
+
+/* Add one of OPT or LONGOPT, and ARGUMENT, when present, to global DIFF_ARGV.
+ *
+ * INPUTS
+ * opt A character option representation.
+ * longopt A long option name.
+ * argument Optional option argument.
+ *
+ * GLOBALS
+ * diff_argc The number of arguments in DIFF_ARGV.
+ * diff_argv Array of argument strings.
+ * diff_arg_allocated Allocated length of DIFF_ARGV.
+ *
+ * NOTES
+ * Behavior when both OPT & LONGOPT are provided is undefined.
+ *
+ * RETURNS
+ * Nothing.
+ */
+static void
+add_diff_args (char opt, const char *longopt, const char *argument)
+{
+ char *tmp;
+
+ /* Add opt or longopt to diff_arv. */
+ assert (opt || (longopt && *longopt));
+ assert (!(opt && (longopt && *longopt)));
+ if (opt) tmp = Xasprintf ("-%c", opt);
+ else tmp = Xasprintf ("--%s", longopt);
+ run_add_arg_p (&diff_argc, &diff_arg_allocated, &diff_argv, tmp);
+ free (tmp);
+
+ /* When present, add ARGUMENT to DIFF_ARGV. */
+ if (argument)
+ run_add_arg_p (&diff_argc, &diff_arg_allocated, &diff_argv, argument);
+}
+
+
+
+/* CVS 1.9 and similar versions seemed to have pretty weird handling
+ of -y and -T. In the cases where it called rcsdiff,
+ they would have the meanings mentioned below. In the cases where it
+ called diff, they would have the meanings mentioned in "longopts".
+ Noone seems to have missed them, so I think the right thing to do is
+ just to remove the options altogether (which I have done).
+
+ In the case of -z and -q, "cvs diff" did not accept them even back
+ when we called rcsdiff (at least, it hasn't accepted them
+ recently).
+
+ In comparing rcsdiff to the new CVS implementation, I noticed that
+ the following rcsdiff flags are not handled by CVS diff:
+
+ -y: perform diff even when the requested revisions are the
+ same revision number
+ -q: run quietly
+ -T: preserve modification time on the RCS file
+ -z: specify timezone for use in file labels
+
+ I think these are not really relevant. -y is undocumented even in
+ RCS 5.7, and seems like a minor change at best. According to RCS
+ documentation, -T only applies when a RCS file has been modified
+ because of lock changes; doesn't CVS sidestep RCS's entire lock
+ structure? -z seems to be unsupported by CVS diff, and has a
+ different meaning as a global option anyway. (Adding it could be
+ a feature, but if it is left out for now, it should not break
+ anything.) For the purposes of producing output, CVS diff appears
+ mostly to ignore -q. Maybe this should be fixed, but I think it's
+ a larger issue than the changes included here. */
+
+int
+diff (int argc, char **argv)
+{
+ int c, err = 0;
+ int local = 0;
+ int which;
+ int option_index;
+ char *diff_orig1, *diff_orig2;
+
+ if (argc == -1)
+ usage (diff_usage);
+
+ have_rev1_label = have_rev2_label = 0;
+
+ /*
+ * Note that we catch all the valid arguments here, so that we can
+ * intercept the -r arguments for doing revision diffs; and -l/-R for a
+ * non-recursive/recursive diff.
+ */
+
+ /* Clean out our global variables (multiroot can call us multiple
+ times and the server can too, if the client sends several
+ diff commands). */
+ run_arg_free_p (diff_argc, diff_argv);
+ diff_argc = 0;
+
+ diff_orig1 = NULL;
+ diff_orig2 = NULL;
+ diff_rev1 = NULL;
+ diff_rev2 = NULL;
+ diff_date1 = NULL;
+ diff_date2 = NULL;
+
+ optind = 0;
+ /* FIXME: This should really be allocating an argv to be passed to diff
+ * later rather than strcatting onto the opts variable. We have some
+ * handling routines that can already handle most of the argc/argv
+ * maintenance for us and currently, if anyone were to attempt to pass a
+ * quoted string in here, it would be split on spaces and tabs on its way
+ * to diff.
+ */
+ while ((c = getopt_long (argc, argv,
+ "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:W:k:r:",
+ longopts, &option_index)) != -1)
+ {
+ switch (c)
+ {
+ case 'y':
+ add_diff_args (0, "side-by-side", NULL);
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'h': case 'i': case 'n': case 'p': case 's': case 't':
+ case 'u': case 'w':
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ case 'B': case 'H': case 'T':
+ add_diff_args (c, NULL, NULL);
+ break;
+ case 'L':
+ if (have_rev1_label++)
+ if (have_rev2_label++)
+ {
+ error (0, 0, "extra -L arguments ignored");
+ break;
+ }
+ /* Fall through. */
+ case 'C': case 'F': case 'I': case 'U': case 'W':
+ add_diff_args (c, NULL, optarg);
+ break;
+ case 129: case 130: case 131: case 132: case 133: case 134:
+ case 135: case 136: case 137: case 138: case 139: case 140:
+ case 141: case 142: case 143: case 145: case 146:
+ add_diff_args (0, longopts[option_index].name,
+ longopts[option_index].has_arg ? optarg : NULL);
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'r':
+ if (diff_rev2 || diff_date2)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (diff_rev1 || diff_date1)
+ {
+ diff_orig2 = xstrdup (optarg);
+ parse_tagdate (&diff_rev2, &diff_date2, optarg);
+ }
+ else
+ {
+ diff_orig1 = xstrdup (optarg);
+ parse_tagdate (&diff_rev1, &diff_date1, optarg);
+ }
+ break;
+ case 'D':
+ if (diff_rev2 || diff_date2)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (diff_rev1 || diff_date1)
+ diff_date2 = Make_Date (optarg);
+ else
+ diff_date1 = Make_Date (optarg);
+ break;
+ case 'N':
+ empty_files = 1;
+ break;
+ case '?':
+ default:
+ usage (diff_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* make sure options is non-null */
+ if (!options)
+ options = xstrdup ("");
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote) {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg("-l");
+ if (empty_files)
+ send_arg("-N");
+ send_options (diff_argc, diff_argv);
+ if (options[0] != '\0')
+ send_arg (options);
+ if (diff_orig1)
+ option_with_arg ("-r", diff_orig1);
+ else if (diff_date1)
+ client_senddate (diff_date1);
+ if (diff_orig2)
+ option_with_arg ("-r", diff_orig2);
+ else if (diff_date2)
+ client_senddate (diff_date2);
+ send_arg ("--");
+
+ /* Send the current files unless diffing two revs from the archive */
+ if (!diff_rev2 && !diff_date2)
+ send_files (argc, argv, local, 0, 0);
+ else
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+
+ send_to_server ("diff\012", 0);
+ err = get_responses_and_close ();
+ free (options);
+ options = NULL;
+ return err;
+ }
+#endif
+
+ if (diff_rev1 != NULL)
+ tag_check_valid (diff_rev1, argc, argv, local, 0, "", false);
+ if (diff_rev2 != NULL)
+ tag_check_valid (diff_rev2, argc, argv, local, 0, "", false);
+
+ which = W_LOCAL;
+ if (diff_rev1 || diff_date1)
+ which |= W_REPOS | W_ATTIC;
+
+ wrap_setup ();
+
+ /* start the recursion processor */
+ err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc,
+ diff_dirleaveproc, NULL, argc, argv, local,
+ which, 0, CVS_LOCK_READ, NULL, 1, NULL);
+
+ /* clean up */
+ free (options);
+ options = NULL;
+
+ if (diff_date1 != NULL)
+ free (diff_date1);
+ if (diff_date2 != NULL)
+ free (diff_date2);
+
+ return err;
+}
+
+
+
+/*
+ * Do a file diff
+ */
+/* ARGSUSED */
+static int
+diff_fileproc (void *callerdat, struct file_info *finfo)
+{
+ int status, err = 2; /* 2 == trouble, like rcsdiff */
+ Vers_TS *vers;
+ enum diff_file empty_file = DIFF_DIFFERENT;
+ char *tmp = NULL;
+ char *tocvsPath = NULL;
+ char *fname = NULL;
+ char *label1;
+ char *label2;
+ char *rev1_cache = NULL;
+
+ user_file_rev = 0;
+ vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0);
+
+ if (diff_rev2 || diff_date2)
+ {
+ /* Skip all the following checks regarding the user file; we're
+ not using it. */
+ }
+ else if (vers->vn_user == NULL)
+ {
+ /* The file does not exist in the working directory. */
+ if ((diff_rev1 || diff_date1)
+ && vers->srcfile != NULL)
+ {
+ /* The file does exist in the repository. */
+ if (empty_files)
+ empty_file = DIFF_REMOVED;
+ else
+ {
+ int exists;
+
+ exists = 0;
+ /* special handling for TAG_HEAD */
+ if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
+ {
+ char *head =
+ (vers->vn_rcs == NULL
+ ? NULL
+ : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+ exists = head != NULL && !RCS_isdead (vers->srcfile, head);
+ if (head != NULL)
+ free (head);
+ }
+ else
+ {
+ Vers_TS *xvers;
+
+ xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
+ 1, 0);
+ exists = xvers->vn_rcs && !RCS_isdead (xvers->srcfile,
+ xvers->vn_rcs);
+ freevers_ts (&xvers);
+ }
+ if (exists)
+ error (0, 0,
+ "%s no longer exists, no comparison available",
+ finfo->fullname);
+ goto out;
+ }
+ }
+ else
+ {
+ error (0, 0, "I know nothing about %s", finfo->fullname);
+ goto out;
+ }
+ }
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ {
+ /* The file was added locally. */
+ int exists = 0;
+
+ if (vers->srcfile != NULL)
+ {
+ /* The file does exist in the repository. */
+
+ if (diff_rev1 || diff_date1)
+ {
+ /* special handling for TAG_HEAD */
+ if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
+ {
+ char *head =
+ (vers->vn_rcs == NULL
+ ? NULL
+ : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+ exists = head && !RCS_isdead (vers->srcfile, head);
+ if (head != NULL)
+ free (head);
+ }
+ else
+ {
+ Vers_TS *xvers;
+
+ xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
+ 1, 0);
+ exists = xvers->vn_rcs
+ && !RCS_isdead (xvers->srcfile, xvers->vn_rcs);
+ freevers_ts (&xvers);
+ }
+ }
+ else
+ {
+ /* The file was added locally, but an RCS archive exists. Our
+ * base revision must be dead.
+ */
+ /* No need to set, exists = 0, here. That's the default. */
+ }
+ }
+ if (!exists)
+ {
+ /* If we got here, then either the RCS archive does not exist or
+ * the relevant revision is dead.
+ */
+ if (empty_files)
+ empty_file = DIFF_ADDED;
+ else
+ {
+ error (0, 0, "%s is a new entry, no comparison available",
+ finfo->fullname);
+ goto out;
+ }
+ }
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ if (empty_files)
+ empty_file = DIFF_REMOVED;
+ else
+ {
+ error (0, 0, "%s was removed, no comparison available",
+ finfo->fullname);
+ goto out;
+ }
+ }
+ else
+ {
+ if (!vers->vn_rcs && !vers->srcfile)
+ {
+ error (0, 0, "cannot find revision control file for %s",
+ finfo->fullname);
+ goto out;
+ }
+ else
+ {
+ if (vers->ts_user == NULL)
+ {
+ error (0, 0, "cannot find %s", finfo->fullname);
+ goto out;
+ }
+ else if (!strcmp (vers->ts_user, vers->ts_rcs))
+ {
+ /* The user file matches some revision in the repository
+ Diff against the repository (for remote CVS, we might not
+ have a copy of the user file around). */
+ user_file_rev = vers->vn_user;
+ }
+ }
+ }
+
+ empty_file = diff_file_nodiff (finfo, vers, empty_file, &rev1_cache);
+ if (empty_file == DIFF_SAME)
+ {
+ /* In the server case, would be nice to send a "Checked-in"
+ response, so that the client can rewrite its timestamp.
+ server_checked_in by itself isn't the right thing (it
+ needs a server_register), but I'm not sure what is.
+ It isn't clear to me how "cvs status" handles this (that
+ is, for a client which sends Modified not Is-modified to
+ "cvs status"), but it does. */
+ err = 0;
+ goto out;
+ }
+ else if (empty_file == DIFF_ERROR)
+ goto out;
+
+ /* Output an "Index:" line for patch to use */
+ cvs_output ("Index: ", 0);
+ cvs_output (finfo->fullname, 0);
+ cvs_output ("\n", 1);
+
+ tocvsPath = wrap_tocvs_process_file (finfo->file);
+ if (tocvsPath)
+ {
+ /* Backup the current version of the file to CVS/,,filename */
+ fname = Xasprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
+ if (unlink_file_dir (fname) < 0)
+ if (!existence_error (errno))
+ error (1, errno, "cannot remove %s", fname);
+ rename_file (finfo->file, fname);
+ /* Copy the wrapped file to the current directory then go to work */
+ copy_file (tocvsPath, finfo->file);
+ }
+
+ /* Set up file labels appropriate for compatibility with the Larry Wall
+ * implementation of patch if the user didn't specify. This is irrelevant
+ * according to the POSIX.2 specification.
+ */
+ label1 = NULL;
+ label2 = NULL;
+ /* The user cannot set the rev2 label without first setting the rev1
+ * label.
+ */
+ if (!have_rev2_label)
+ {
+ if (empty_file == DIFF_REMOVED)
+ label2 = make_file_label (DEVNULL, NULL, NULL);
+ else
+ label2 = make_file_label (finfo->fullname, use_rev2,
+ vers->srcfile);
+ if (!have_rev1_label)
+ {
+ if (empty_file == DIFF_ADDED)
+ label1 = make_file_label (DEVNULL, NULL, NULL);
+ else
+ label1 = make_file_label (finfo->fullname, use_rev1,
+ vers->srcfile);
+ }
+ }
+
+ if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED)
+ {
+ /* This is fullname, not file, possibly despite the POSIX.2
+ * specification, because that's the way all the Larry Wall
+ * implementations of patch (are there other implementations?) want
+ * things and the POSIX.2 spec appears to leave room for this.
+ */
+ cvs_output ("\
+===================================================================\n\
+RCS file: ", 0);
+ cvs_output (finfo->fullname, 0);
+ cvs_output ("\n", 1);
+
+ cvs_output ("diff -N ", 0);
+ cvs_output (finfo->fullname, 0);
+ cvs_output ("\n", 1);
+
+ if (empty_file == DIFF_ADDED)
+ {
+ if (use_rev2 == NULL)
+ status = diff_exec (DEVNULL, finfo->file, label1, label2,
+ diff_argc, diff_argv, RUN_TTY);
+ else
+ {
+ int retcode;
+
+ tmp = cvs_temp_name ();
+ retcode = RCS_checkout (vers->srcfile, NULL, use_rev2, NULL,
+ *options ? options : vers->options,
+ tmp, NULL, NULL);
+ if (retcode != 0)
+ goto out;
+
+ status = diff_exec (DEVNULL, tmp, label1, label2,
+ diff_argc, diff_argv, RUN_TTY);
+ }
+ }
+ else
+ {
+ int retcode;
+
+ tmp = cvs_temp_name ();
+ retcode = RCS_checkout (vers->srcfile, NULL, use_rev1, NULL,
+ *options ? options : vers->options,
+ tmp, NULL, NULL);
+ if (retcode != 0)
+ goto out;
+
+ status = diff_exec (tmp, DEVNULL, label1, label2,
+ diff_argc, diff_argv, RUN_TTY);
+ }
+ }
+ else
+ {
+ status = RCS_exec_rcsdiff (vers->srcfile, diff_argc, diff_argv,
+ *options ? options : vers->options,
+ use_rev1, rev1_cache, use_rev2,
+ label1, label2, finfo->file);
+
+ }
+
+ if (label1) free (label1);
+ if (label2) free (label2);
+
+ switch (status)
+ {
+ case -1: /* fork failed */
+ error (1, errno, "fork failed while diffing %s",
+ vers->srcfile->path);
+ case 0: /* everything ok */
+ err = 0;
+ break;
+ default: /* other error */
+ err = status;
+ break;
+ }
+
+out:
+ if( tocvsPath != NULL )
+ {
+ if (unlink_file_dir (finfo->file) < 0)
+ if (! existence_error (errno))
+ error (1, errno, "cannot remove %s", finfo->file);
+
+ rename_file (fname, finfo->file);
+ if (unlink_file (tocvsPath) < 0)
+ error (1, errno, "cannot remove %s", tocvsPath);
+ free (fname);
+ }
+
+ /* Call CVS_UNLINK() rather than unlink_file() below to avoid the check
+ * for noexec.
+ */
+ if (tmp != NULL)
+ {
+ if (CVS_UNLINK (tmp) < 0)
+ error (0, errno, "cannot remove %s", tmp);
+ free (tmp);
+ }
+ if (rev1_cache != NULL)
+ {
+ if (CVS_UNLINK (rev1_cache) < 0)
+ error (0, errno, "cannot remove %s", rev1_cache);
+ free (rev1_cache);
+ }
+
+ freevers_ts (&vers);
+ diff_mark_errors (err);
+ return err;
+}
+
+
+
+/*
+ * Remember the exit status for each file.
+ */
+static void
+diff_mark_errors (int err)
+{
+ if (err > diff_errors)
+ diff_errors = err;
+}
+
+
+
+/*
+ * Print a warm fuzzy message when we enter a dir
+ *
+ * Don't try to diff directories that don't exist! -- DW
+ */
+/* ARGSUSED */
+static Dtype
+diff_dirproc (void *callerdat, const char *dir, const char *pos_repos,
+ const char *update_dir, List *entries)
+{
+ /* XXX - check for dirs we don't want to process??? */
+
+ /* YES ... for instance dirs that don't exist!!! -- DW */
+ if (!isdir (dir))
+ return R_SKIP_ALL;
+
+ if (!quiet)
+ error (0, 0, "Diffing %s", update_dir);
+ return R_PROCESS;
+}
+
+
+
+/*
+ * Concoct the proper exit status - done with files
+ */
+/* ARGSUSED */
+static int
+diff_filesdoneproc (void *callerdat, int err, const char *repos,
+ const char *update_dir, List *entries)
+{
+ return diff_errors;
+}
+
+
+
+/*
+ * Concoct the proper exit status - leaving directories
+ */
+/* ARGSUSED */
+static int
+diff_dirleaveproc (void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries)
+{
+ return diff_errors;
+}
+
+
+
+/*
+ * verify that a file is different
+ *
+ * INPUTS
+ * finfo
+ * vers
+ * empty_file
+ *
+ * OUTPUTS
+ * rev1_cache Cache the contents of rev1 if we look it up.
+ */
+static enum diff_file
+diff_file_nodiff (struct file_info *finfo, Vers_TS *vers,
+ enum diff_file empty_file, char **rev1_cache)
+{
+ Vers_TS *xvers;
+ int retcode;
+
+ TRACE (TRACE_FUNCTION, "diff_file_nodiff (%s, %d)",
+ finfo->fullname ? finfo->fullname : "(null)", empty_file);
+
+ /* free up any old use_rev* variables and reset 'em */
+ if (use_rev1)
+ free (use_rev1);
+ if (use_rev2)
+ free (use_rev2);
+ use_rev1 = use_rev2 = NULL;
+
+ if (diff_rev1 || diff_date1)
+ {
+ /* special handling for TAG_HEAD */
+ if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
+ {
+ if (vers->vn_rcs != NULL && vers->srcfile != NULL)
+ use_rev1 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
+ }
+ else
+ {
+ xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
+ if (xvers->vn_rcs != NULL)
+ use_rev1 = xstrdup (xvers->vn_rcs);
+ freevers_ts (&xvers);
+ }
+ }
+ if (diff_rev2 || diff_date2)
+ {
+ /* special handling for TAG_HEAD */
+ if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
+ {
+ if (vers->vn_rcs && vers->srcfile)
+ use_rev2 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
+ }
+ else
+ {
+ xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
+ if (xvers->vn_rcs != NULL)
+ use_rev2 = xstrdup (xvers->vn_rcs);
+ freevers_ts (&xvers);
+ }
+
+ if (use_rev1 == NULL || RCS_isdead (vers->srcfile, use_rev1))
+ {
+ /* The first revision does not exist. If EMPTY_FILES is
+ true, treat this as an added file. Otherwise, warn
+ about the missing tag. */
+ if (use_rev2 == NULL || RCS_isdead (vers->srcfile, use_rev2))
+ /* At least in the case where DIFF_REV1 and DIFF_REV2
+ * are both numeric (and non-existant (NULL), as opposed to
+ * dead?), we should be returning some kind of error (see
+ * basicb-8a0 in testsuite). The symbolic case may be more
+ * complicated.
+ */
+ return DIFF_SAME;
+ if (empty_files)
+ return DIFF_ADDED;
+ if (use_rev1 != NULL)
+ {
+ if (diff_rev1)
+ {
+ error (0, 0,
+ "Tag %s refers to a dead (removed) revision in file `%s'.",
+ diff_rev1, finfo->fullname);
+ }
+ else
+ {
+ error (0, 0,
+ "Date %s refers to a dead (removed) revision in file `%s'.",
+ diff_date1, finfo->fullname);
+ }
+ error (0, 0,
+ "No comparison available. Pass `-N' to `%s diff'?",
+ program_name);
+ }
+ else if (diff_rev1)
+ error (0, 0, "tag %s is not in file %s", diff_rev1,
+ finfo->fullname);
+ else
+ error (0, 0, "no revision for date %s in file %s",
+ diff_date1, finfo->fullname);
+ return DIFF_ERROR;
+ }
+
+ assert( use_rev1 != NULL );
+ if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) )
+ {
+ /* The second revision does not exist. If EMPTY_FILES is
+ true, treat this as a removed file. Otherwise warn
+ about the missing tag. */
+ if (empty_files)
+ return DIFF_REMOVED;
+ if( use_rev2 != NULL )
+ {
+ if (diff_rev2)
+ {
+ error( 0, 0,
+ "Tag %s refers to a dead (removed) revision in file `%s'.",
+ diff_rev2, finfo->fullname );
+ }
+ else
+ {
+ error( 0, 0,
+ "Date %s refers to a dead (removed) revision in file `%s'.",
+ diff_date2, finfo->fullname );
+ }
+ error( 0, 0,
+ "No comparison available. Pass `-N' to `%s diff'?",
+ program_name );
+ }
+ else if (diff_rev2)
+ error (0, 0, "tag %s is not in file %s", diff_rev2,
+ finfo->fullname);
+ else
+ error (0, 0, "no revision for date %s in file %s",
+ diff_date2, finfo->fullname);
+ return DIFF_ERROR;
+ }
+ /* Now, see if we really need to do the diff. We can't assume that the
+ * files are different when the revs are.
+ */
+ assert( use_rev2 != NULL );
+ if( strcmp (use_rev1, use_rev2) == 0 )
+ return DIFF_SAME;
+ /* else fall through and do the diff */
+ }
+
+ /* If we had a r1/d1 & r2/d2, then at this point we must have a C3P0...
+ * err... ok, then both rev1 & rev2 must have resolved to an existing,
+ * live version due to if statement we just closed.
+ */
+ assert (!(diff_rev2 || diff_date2) || (use_rev1 && use_rev2));
+
+ if ((diff_rev1 || diff_date1) &&
+ (use_rev1 == NULL || RCS_isdead (vers->srcfile, use_rev1)))
+ {
+ /* The first revision does not exist, and no second revision
+ was given. */
+ if (empty_files)
+ {
+ if (empty_file == DIFF_REMOVED)
+ return DIFF_SAME;
+ if( user_file_rev && use_rev2 == NULL )
+ use_rev2 = xstrdup( user_file_rev );
+ return DIFF_ADDED;
+ }
+ if( use_rev1 != NULL )
+ {
+ if (diff_rev1)
+ {
+ error( 0, 0,
+ "Tag %s refers to a dead (removed) revision in file `%s'.",
+ diff_rev1, finfo->fullname );
+ }
+ else
+ {
+ error( 0, 0,
+ "Date %s refers to a dead (removed) revision in file `%s'.",
+ diff_date1, finfo->fullname );
+ }
+ error( 0, 0,
+ "No comparison available. Pass `-N' to `%s diff'?",
+ program_name );
+ }
+ else if ( diff_rev1 )
+ error( 0, 0, "tag %s is not in file %s", diff_rev1,
+ finfo->fullname );
+ else
+ error( 0, 0, "no revision for date %s in file %s",
+ diff_date1, finfo->fullname );
+ return DIFF_ERROR;
+ }
+
+ assert( !diff_rev1 || use_rev1 );
+
+ if (user_file_rev)
+ {
+ /* drop user_file_rev into first unused use_rev */
+ if (!use_rev1)
+ use_rev1 = xstrdup (user_file_rev);
+ else if (!use_rev2)
+ use_rev2 = xstrdup (user_file_rev);
+ /* and if not, it wasn't needed anyhow */
+ user_file_rev = NULL;
+ }
+
+ /* Now, see if we really need to do the diff. We can't assume that the
+ * files are different when the revs are.
+ */
+ if( use_rev1 && use_rev2)
+ {
+ if (strcmp (use_rev1, use_rev2) == 0)
+ return DIFF_SAME;
+ /* Fall through and do the diff. */
+ }
+ /* Don't want to do the timestamp check with both use_rev1 & use_rev2 set.
+ * The timestamp check is just for the default case of diffing the
+ * workspace file against its base revision.
+ */
+ else if( use_rev1 == NULL
+ || ( vers->vn_user != NULL
+ && strcmp( use_rev1, vers->vn_user ) == 0 ) )
+ {
+ if (empty_file == DIFF_DIFFERENT
+ && vers->ts_user != NULL
+ && strcmp (vers->ts_rcs, vers->ts_user) == 0
+ && (!(*options) || strcmp (options, vers->options) == 0))
+ {
+ return DIFF_SAME;
+ }
+ if (use_rev1 == NULL
+ && (vers->vn_user[0] != '0' || vers->vn_user[1] != '\0'))
+ {
+ if (vers->vn_user[0] == '-')
+ use_rev1 = xstrdup (vers->vn_user + 1);
+ else
+ use_rev1 = xstrdup (vers->vn_user);
+ }
+ }
+
+ /* If we already know that the file is being added or removed,
+ then we don't want to do an actual file comparison here. */
+ if (empty_file != DIFF_DIFFERENT)
+ return empty_file;
+
+ /*
+ * Run a quick cmp to see if we should bother with a full diff.
+ */
+
+ retcode = RCS_cmp_file( vers->srcfile, use_rev1, rev1_cache,
+ use_rev2, *options ? options : vers->options,
+ finfo->file );
+
+ return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT;
+}
diff --git a/src/edit.c b/src/edit.c
new file mode 100644
index 0000000..9702872
--- /dev/null
+++ b/src/edit.c
@@ -0,0 +1,1233 @@
+/* Implementation for "cvs edit", "cvs watch on", and related commands
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+#include "getline.h"
+#include "yesno.h"
+#include "watch.h"
+#include "edit.h"
+#include "fileattr.h"
+
+static int watch_onoff (int, char **);
+
+static bool check_edited = false;
+static int setting_default;
+static int turning_on;
+
+static bool setting_tedit;
+static bool setting_tunedit;
+static bool setting_tcommit;
+
+
+
+static int
+onoff_fileproc (void *callerdat, struct file_info *finfo)
+{
+ fileattr_get0 (finfo->file, "_watched");
+ fileattr_set (finfo->file, "_watched", turning_on ? "" : NULL);
+ return 0;
+}
+
+
+
+static int
+onoff_filesdoneproc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ if (setting_default)
+ {
+ fileattr_get0 (NULL, "_watched");
+ fileattr_set (NULL, "_watched", turning_on ? "" : NULL);
+ }
+ return err;
+}
+
+
+
+static int
+watch_onoff (int argc, char **argv)
+{
+ int c;
+ int local = 0;
+ int err;
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lR")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (watch_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg ("-l");
+ send_arg ("--");
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server (turning_on ? "watch-on\012" : "watch-off\012", 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ setting_default = (argc <= 0);
+
+ lock_tree_promotably (argc, argv, local, W_LOCAL, 0);
+
+ err = start_recursion (onoff_fileproc, onoff_filesdoneproc, NULL, NULL,
+ NULL, argc, argv, local, W_LOCAL, 0, CVS_LOCK_WRITE,
+ NULL, 0, NULL);
+
+ Lock_Cleanup ();
+ return err;
+}
+
+int
+watch_on (int argc, char **argv)
+{
+ turning_on = 1;
+ return watch_onoff (argc, argv);
+}
+
+int
+watch_off (int argc, char **argv)
+{
+ turning_on = 0;
+ return watch_onoff (argc, argv);
+}
+
+
+
+static int
+dummy_fileproc (void *callerdat, struct file_info *finfo)
+{
+ /* This is a pretty hideous hack, but the gist of it is that recurse.c
+ won't call notify_check unless there is a fileproc, so we can't just
+ pass NULL for fileproc. */
+ return 0;
+}
+
+
+
+/* Check for and process notifications. Local only. I think that doing
+ this as a fileproc is the only way to catch all the
+ cases (e.g. foo/bar.c), even though that means checking over and over
+ for the same CVSADM_NOTIFY file which we removed the first time we
+ processed the directory. */
+static int
+ncheck_fileproc (void *callerdat, struct file_info *finfo)
+{
+ int notif_type;
+ char *filename;
+ char *val;
+ char *cp;
+ char *watches;
+
+ FILE *fp;
+ char *line = NULL;
+ size_t line_len = 0;
+
+ /* We send notifications even if noexec. I'm not sure which behavior
+ is most sensible. */
+
+ fp = CVS_FOPEN (CVSADM_NOTIFY, "r");
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", CVSADM_NOTIFY);
+ return 0;
+ }
+
+ while (getline (&line, &line_len, fp) > 0)
+ {
+ notif_type = line[0];
+ if (notif_type == '\0')
+ continue;
+ filename = line + 1;
+ cp = strchr (filename, '\t');
+ if (cp == NULL)
+ continue;
+ *cp++ = '\0';
+ val = cp;
+ cp = strchr (val, '\t');
+ if (cp == NULL)
+ continue;
+ *cp++ = '+';
+ cp = strchr (cp, '\t');
+ if (cp == NULL)
+ continue;
+ *cp++ = '+';
+ cp = strchr (cp, '\t');
+ if (cp == NULL)
+ continue;
+ *cp++ = '\0';
+ watches = cp;
+ cp = strchr (cp, '\n');
+ if (cp == NULL)
+ continue;
+ *cp = '\0';
+
+ notify_do (notif_type, filename, finfo->update_dir, getcaller (), val,
+ watches, finfo->repository);
+ }
+ free (line);
+
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", CVSADM_NOTIFY);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
+
+ if ( CVS_UNLINK (CVSADM_NOTIFY) < 0)
+ error (0, errno, "cannot remove %s", CVSADM_NOTIFY);
+
+ return 0;
+}
+
+
+
+/* Look through the CVSADM_NOTIFY file and process each item there
+ accordingly. */
+static int
+send_notifications (int argc, char **argv, int local)
+{
+ int err = 0;
+
+#ifdef CLIENT_SUPPORT
+ /* OK, we've done everything which needs to happen on the client side.
+ Now we can try to contact the server; if we fail, then the
+ notifications stay in CVSADM_NOTIFY to be sent next time. */
+ if (current_parsed_root->isremote)
+ {
+ if (strcmp (cvs_cmd_name, "release") != 0)
+ {
+ start_server ();
+ ign_setup ();
+ }
+
+ err += start_recursion (dummy_fileproc, NULL, NULL, NULL, NULL, argc,
+ argv, local, W_LOCAL, 0, 0, NULL, 0, NULL);
+
+ send_to_server ("noop\012", 0);
+ if (strcmp (cvs_cmd_name, "release") == 0)
+ err += get_server_responses ();
+ else
+ err += get_responses_and_close ();
+ }
+ else
+#endif
+ {
+ /* Local. */
+
+ err += start_recursion (ncheck_fileproc, NULL, NULL, NULL, NULL, argc,
+ argv, local, W_LOCAL, 0, CVS_LOCK_WRITE, NULL,
+ 0, NULL);
+ Lock_Cleanup ();
+ }
+ return err;
+}
+
+
+
+void editors_output (const char *fullname, const char *p)
+{
+ cvs_output (fullname, 0);
+
+ while (1)
+ {
+ cvs_output ("\t", 1);
+ while (*p != '>' && *p != '\0')
+ cvs_output (p++, 1);
+ if (*p == '\0')
+ {
+ /* Only happens if attribute is misformed. */
+ cvs_output ("\n", 1);
+ break;
+ }
+ ++p;
+ cvs_output ("\t", 1);
+ while (1)
+ {
+ while (*p != '+' && *p != ',' && *p != '\0')
+ cvs_output (p++, 1);
+ if (*p == '\0')
+ {
+ cvs_output ("\n", 1);
+ return;
+ }
+ if (*p == ',')
+ {
+ ++p;
+ break;
+ }
+ ++p;
+ cvs_output ("\t", 1);
+ }
+ cvs_output ("\n", 1);
+ }
+}
+
+
+
+static int find_editors_and_output (struct file_info *finfo)
+{
+ char *them;
+
+ them = fileattr_get0 (finfo->file, "_editors");
+ if (them == NULL)
+ return 0;
+
+ editors_output (finfo->fullname, them);
+
+ return 0;
+}
+
+
+
+/* Handle the client-side details of editing a file.
+ *
+ * These args could be const but this needs to fit the call_in_directory API.
+ */
+void
+edit_file (void *data, List *ent_list, const char *short_pathname,
+ const char *filename)
+{
+ Node *node;
+ struct file_info finfo;
+ char *basefilename;
+
+ xchmod (filename, 1);
+
+ mkdir_if_needed (CVSADM_BASE);
+ basefilename = Xasprintf ("%s/%s", CVSADM_BASE, filename);
+ copy_file (filename, basefilename);
+ free (basefilename);
+
+ node = findnode_fn (ent_list, filename);
+ if (node != NULL)
+ {
+ finfo.file = filename;
+ finfo.fullname = short_pathname;
+ finfo.update_dir = dir_name (short_pathname);
+ base_register (&finfo, ((Entnode *) node->data)->version);
+ free ((char *)finfo.update_dir);
+ }
+}
+
+
+
+static int
+edit_fileproc (void *callerdat, struct file_info *finfo)
+{
+ FILE *fp;
+ time_t now;
+ char *ascnow;
+ Vers_TS *vers;
+
+#if defined (CLIENT_SUPPORT)
+ assert (!(current_parsed_root->isremote && check_edited));
+#else /* !CLIENT_SUPPORT */
+ assert (!check_edited);
+#endif /* CLIENT_SUPPORT */
+
+ if (noexec)
+ return 0;
+
+ vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0);
+
+ if (!vers->vn_user)
+ {
+ error (0, 0, "no such file %s; ignored", finfo->fullname);
+ return 1;
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (!current_parsed_root->isremote)
+#endif /* CLIENT_SUPPORT */
+ {
+ char *editors = fileattr_get0 (finfo->file, "_editors");
+ if (editors)
+ {
+ if (check_edited)
+ {
+ /* In the !CHECK_EDIT case, this message is printed by
+ * server_notify.
+ */
+ if (!quiet)
+ editors_output (finfo->fullname, editors);
+ /* Now warn the user if we skip the file, then return. */
+ if (!really_quiet)
+ error (0, 0, "Skipping file `%s' due to existing editors.",
+ finfo->fullname);
+ return 1;
+ }
+ free (editors);
+ }
+ }
+
+ fp = xfopen (CVSADM_NOTIFY, "a");
+
+ (void) time (&now);
+ ascnow = asctime (gmtime (&now));
+ ascnow[24] = '\0';
+ /* Fix non-standard format. */
+ if (ascnow[8] == '0') ascnow[8] = ' ';
+ fprintf (fp, "E%s\t%s -0000\t%s\t%s\t", finfo->file,
+ ascnow, hostname, CurDir);
+ if (setting_tedit)
+ fprintf (fp, "E");
+ if (setting_tunedit)
+ fprintf (fp, "U");
+ if (setting_tcommit)
+ fprintf (fp, "C");
+ fprintf (fp, "\n");
+
+ if (fclose (fp) < 0)
+ {
+ if (finfo->update_dir[0] == '\0')
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
+ else
+ error (0, errno, "cannot close %s/%s", finfo->update_dir,
+ CVSADM_NOTIFY);
+ }
+
+ /* Now stash the file away in CVSADM so that unedit can revert even if
+ it can't communicate with the server. We stash away a writable
+ copy so that if the user removes the working file, then restores it
+ with "cvs update" (which clears _editors but does not update
+ CVSADM_BASE), then a future "cvs edit" can still win. */
+ /* Could save a system call by only calling mkdir_if_needed if
+ trying to create the output file fails. But copy_file isn't
+ set up to facilitate that. */
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_edit_file (finfo);
+ else
+#endif /* SERVER_SUPPORT */
+ edit_file (NULL, finfo->entries, finfo->fullname, finfo->file);
+
+ return 0;
+}
+
+static const char *const edit_usage[] =
+{
+ "Usage: %s %s [-lRcf] [-a <action>]... [<file>]...\n",
+ "-l\tLocal directory only, not recursive.\n",
+ "-R\tProcess directories recursively (default).\n",
+ "-a\tSpecify action to register for temporary watch, one of:\n",
+ " \t`edit', `unedit', `commit', `all', `none' (defaults to `all').\n",
+ "-c\tCheck for <file>s edited by others and abort if found.\n",
+ "-f\tAllow edit if <file>s are edited by others (default).\n",
+ "(Specify the --help global option for a list of other help options.)\n",
+ NULL
+};
+
+int
+edit (int argc, char **argv)
+{
+ int local = 0;
+ int c;
+ int err = 0;
+ bool a_omitted, a_all, a_none;
+
+ if (argc == -1)
+ usage (edit_usage);
+
+ a_omitted = true;
+ a_all = false;
+ a_none = false;
+ setting_tedit = false;
+ setting_tunedit = false;
+ setting_tcommit = false;
+ optind = 0;
+ while ((c = getopt (argc, argv, "+cflRa:")) != -1)
+ {
+ switch (c)
+ {
+ case 'c':
+ check_edited = true;
+ break;
+ case 'f':
+ check_edited = false;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'a':
+ a_omitted = false;
+ if (strcmp (optarg, "edit") == 0)
+ setting_tedit = true;
+ else if (strcmp (optarg, "unedit") == 0)
+ setting_tunedit = true;
+ else if (strcmp (optarg, "commit") == 0)
+ setting_tcommit = true;
+ else if (strcmp (optarg, "all") == 0)
+ {
+ a_all = true;
+ a_none = false;
+ setting_tedit = true;
+ setting_tunedit = true;
+ setting_tcommit = true;
+ }
+ else if (strcmp (optarg, "none") == 0)
+ {
+ a_none = true;
+ a_all = false;
+ setting_tedit = false;
+ setting_tunedit = false;
+ setting_tcommit = false;
+ }
+ else
+ usage (edit_usage);
+ break;
+ case '?':
+ default:
+ usage (edit_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (strpbrk (hostname, "+,>;=\t\n") != NULL)
+ error (1, 0,
+ "host name (%s) contains an invalid character (+,>;=\\t\\n)",
+ hostname);
+ if (strpbrk (CurDir, "+,>;=\t\n") != NULL)
+ error (1, 0,
+"current directory (%s) contains an invalid character (+,>;=\\t\\n)",
+ CurDir);
+
+#ifdef CLIENT_SUPPORT
+ if (check_edited && current_parsed_root->isremote)
+ {
+ /* When CHECK_EDITED, we might as well contact the server and let it do
+ * the work since we don't want an edit unless we know it is safe.
+ *
+ * When !CHECK_EDITED, we set up notifications and then attempt to
+ * contact the server in order to allow disconnected edits.
+ */
+ start_server();
+
+ if (!supported_request ("edit"))
+ error (1, 0, "Server does not support enforced advisory locks.");
+
+ ign_setup();
+
+ send_to_server ("Hostname ", 0);
+ send_to_server (hostname, 0);
+ send_to_server ("\012", 1);
+ send_to_server ("LocalDir ", 0);
+ send_to_server (CurDir, 0);
+ send_to_server ("\012", 1);
+
+ if (local)
+ send_arg ("-l");
+ send_arg ("-c");
+ if (!a_omitted)
+ {
+ if (a_all)
+ option_with_arg ("-a", "all");
+ else if (a_none)
+ option_with_arg ("-a", "none");
+ else
+ {
+ if (setting_tedit)
+ option_with_arg ("-a", "edit");
+ if (setting_tunedit)
+ option_with_arg ("-a", "unedit");
+ if (setting_tcommit)
+ option_with_arg ("-a", "commit");
+ }
+ }
+ send_arg ("--");
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("edit\012", 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ /* Now, either SERVER_ACTIVE, local mode, or !CHECK_EDITED. */
+
+ if (a_omitted)
+ {
+ setting_tedit = true;
+ setting_tunedit = true;
+ setting_tcommit = true;
+ }
+
+ TRACE (TRACE_DATA, "edit(): EUC: %d%d%d edit-check: %d",
+ setting_tedit, setting_tunedit, setting_tcommit, check_edited);
+
+ err = start_recursion (edit_fileproc, NULL, NULL, NULL, NULL, argc, argv,
+ local, W_LOCAL, 0, 0, NULL, 0, NULL);
+
+ err += send_notifications (argc, argv, local);
+
+ return err;
+}
+
+static int unedit_fileproc (void *callerdat, struct file_info *finfo);
+
+static int
+unedit_fileproc (void *callerdat, struct file_info *finfo)
+{
+ FILE *fp;
+ time_t now;
+ char *ascnow;
+ char *basefilename = NULL;
+
+ if (noexec)
+ return 0;
+
+ basefilename = Xasprintf ("%s/%s", CVSADM_BASE, finfo->file);
+ if (!isfile (basefilename))
+ {
+ /* This file apparently was never cvs edit'd (e.g. we are uneditting
+ a directory where only some of the files were cvs edit'd. */
+ free (basefilename);
+ return 0;
+ }
+
+ if (xcmp (finfo->file, basefilename) != 0)
+ {
+ printf ("%s has been modified; revert changes? ", finfo->fullname);
+ fflush (stderr);
+ fflush (stdout);
+ if (!yesno ())
+ {
+ /* "no". */
+ free (basefilename);
+ return 0;
+ }
+ }
+ rename_file (basefilename, finfo->file);
+ free (basefilename);
+
+ fp = xfopen (CVSADM_NOTIFY, "a");
+
+ (void) time (&now);
+ ascnow = asctime (gmtime (&now));
+ ascnow[24] = '\0';
+ /* Fix non-standard format. */
+ if (ascnow[8] == '0') ascnow[8] = ' ';
+ fprintf (fp, "U%s\t%s -0000\t%s\t%s\t\n", finfo->file,
+ ascnow, hostname, CurDir);
+
+ if (fclose (fp) < 0)
+ {
+ if (finfo->update_dir[0] == '\0')
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
+ else
+ error (0, errno, "cannot close %s/%s", finfo->update_dir,
+ CVSADM_NOTIFY);
+ }
+
+ /* Now update the revision number in CVS/Entries from CVS/Baserev.
+ The basic idea here is that we are reverting to the revision
+ that the user edited. If we wanted "cvs update" to update
+ CVS/Base as we go along (so that an unedit could revert to the
+ current repository revision), we would need:
+
+ update (or all send_files?) (client) needs to send revision in
+ new Entry-base request. update (server/local) needs to check
+ revision against repository and send new Update-base response
+ (like Update-existing in that the file already exists. While
+ we are at it, might try to clean up the syntax by having the
+ mode only in a "Mode" response, not in the Update-base itself). */
+ {
+ char *baserev;
+ Node *node;
+ Entnode *entdata;
+
+ baserev = base_get (finfo);
+ node = findnode_fn (finfo->entries, finfo->file);
+ /* The case where node is NULL probably should be an error or
+ something, but I don't want to think about it too hard right
+ now. */
+ if (node != NULL)
+ {
+ entdata = node->data;
+ if (baserev == NULL)
+ {
+ /* This can only happen if the CVS/Baserev file got
+ corrupted. We suspect it might be possible if the
+ user interrupts CVS, although I haven't verified
+ that. */
+ error (0, 0, "%s not mentioned in %s", finfo->fullname,
+ CVSADM_BASEREV);
+
+ /* Since we don't know what revision the file derives from,
+ keeping it around would be asking for trouble. */
+ if (unlink_file (finfo->file) < 0)
+ error (0, errno, "cannot remove %s", finfo->fullname);
+
+ /* This is cheesy, in a sense; why shouldn't we do the
+ update for the user? However, doing that would require
+ contacting the server, so maybe this is OK. */
+ error (0, 0, "run update to complete the unedit");
+ return 0;
+ }
+ Register (finfo->entries, finfo->file, baserev, entdata->timestamp,
+ entdata->options, entdata->tag, entdata->date,
+ entdata->conflict);
+ }
+ free (baserev);
+ base_deregister (finfo);
+ }
+
+ xchmod (finfo->file, 0);
+ return 0;
+}
+
+static const char *const unedit_usage[] =
+{
+ "Usage: %s %s [-lR] [<file>]...\n",
+ "-l\tLocal directory only, not recursive.\n",
+ "-R\tProcess directories recursively (default).\n",
+ "(Specify the --help global option for a list of other help options.)\n",
+ NULL
+};
+
+int
+unedit (int argc, char **argv)
+{
+ int local = 0;
+ int c;
+ int err;
+
+ if (argc == -1)
+ usage (unedit_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lR")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (unedit_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* No need to readlock since we aren't doing anything to the
+ repository. */
+ err = start_recursion (unedit_fileproc, NULL, NULL, NULL, NULL, argc, argv,
+ local, W_LOCAL, 0, 0, NULL, 0, NULL);
+
+ err += send_notifications (argc, argv, local);
+
+ return err;
+}
+
+
+
+void
+mark_up_to_date (const char *file)
+{
+ char *base;
+
+ /* The file is up to date, so we better get rid of an out of
+ date file in CVSADM_BASE. */
+ base = Xasprintf ("%s/%s", CVSADM_BASE, file);
+ if (unlink_file (base) < 0 && ! existence_error (errno))
+ error (0, errno, "cannot remove %s", file);
+ free (base);
+}
+
+
+
+void
+editor_set (const char *filename, const char *editor, const char *val)
+{
+ char *edlist;
+ char *newlist;
+
+ edlist = fileattr_get0 (filename, "_editors");
+ newlist = fileattr_modify (edlist, editor, val, '>', ',');
+ /* If the attributes is unchanged, don't rewrite the attribute file. */
+ if (!((edlist == NULL && newlist == NULL)
+ || (edlist != NULL
+ && newlist != NULL
+ && strcmp (edlist, newlist) == 0)))
+ fileattr_set (filename, "_editors", newlist);
+ if (edlist != NULL)
+ free (edlist);
+ if (newlist != NULL)
+ free (newlist);
+}
+
+struct notify_proc_args {
+ /* What kind of notification, "edit", "tedit", etc. */
+ const char *type;
+ /* User who is running the command which causes notification. */
+ const char *who;
+ /* User to be notified. */
+ const char *notifyee;
+ /* File. */
+ const char *file;
+};
+
+
+
+static int
+notify_proc (const char *repository, const char *filter, void *closure)
+{
+ char *cmdline;
+ FILE *pipefp;
+ const char *srepos = Short_Repository (repository);
+ struct notify_proc_args *args = closure;
+
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ false, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s", current_parsed_root->directory,
+ "s", "s", args->notifyee,
+ (char *) NULL);
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ error (0, 0, "pretag proc resolved to the empty string!");
+ return 1;
+ }
+
+ pipefp = run_popen (cmdline, "w");
+ if (pipefp == NULL)
+ {
+ error (0, errno, "cannot write entry to notify filter: %s", cmdline);
+ free (cmdline);
+ return 1;
+ }
+
+ fprintf (pipefp, "%s %s\n---\n", srepos, args->file);
+ fprintf (pipefp, "Triggered %s watch on %s\n", args->type, repository);
+ fprintf (pipefp, "By %s\n", args->who);
+
+ /* Lots more potentially useful information we could add here; see
+ logfile_write for inspiration. */
+
+ free (cmdline);
+ return pclose (pipefp);
+}
+
+
+
+/* FIXME: this function should have a way to report whether there was
+ an error so that server.c can know whether to report Notified back
+ to the client. */
+void
+notify_do (int type, const char *filename, const char *update_dir,
+ const char *who, const char *val, const char *watches,
+ const char *repository)
+{
+ static struct addremove_args blank;
+ struct addremove_args args;
+ char *watchers;
+ char *p;
+ char *endp;
+ char *nextp;
+
+ /* Print out information on current editors if we were called during an
+ * edit.
+ */
+ if (type == 'E' && !check_edited && !quiet)
+ {
+ char *editors = fileattr_get0 (filename, "_editors");
+ if (editors)
+ {
+ /* In the CHECK_EDIT case, this message is printed by
+ * edit_check. It needs to be done here too since files
+ * which are found to be edited when CHECK_EDIT are not
+ * added to the notify list.
+ */
+ const char *tmp;
+ if (update_dir && *update_dir)
+ tmp = Xasprintf ("%s/%s", update_dir, filename);
+ else
+ tmp = filename;
+
+ editors_output (tmp, editors);
+
+ if (update_dir && *update_dir) free ((char *)tmp);
+ free (editors);
+ }
+ }
+
+ /* Initialize fields to 0, NULL, or 0.0. */
+ args = blank;
+ switch (type)
+ {
+ case 'E':
+ if (strpbrk (val, ",>;=\n") != NULL)
+ {
+ error (0, 0, "invalid character in editor value");
+ return;
+ }
+ editor_set (filename, who, val);
+ break;
+ case 'U':
+ case 'C':
+ editor_set (filename, who, NULL);
+ break;
+ default:
+ return;
+ }
+
+ watchers = fileattr_get0 (filename, "_watchers");
+ p = watchers;
+ while (p != NULL)
+ {
+ char *q;
+ char *endq;
+ char *nextq;
+ char *notif;
+
+ endp = strchr (p, '>');
+ if (endp == NULL)
+ break;
+ nextp = strchr (p, ',');
+
+ if ((size_t)(endp - p) == strlen (who) && strncmp (who, p, endp - p) == 0)
+ {
+ /* Don't notify user of their own changes. Would perhaps
+ be better to check whether it is the same working
+ directory, not the same user, but that is hairy. */
+ p = nextp == NULL ? nextp : nextp + 1;
+ continue;
+ }
+
+ /* Now we point q at a string which looks like
+ "edit+unedit+commit,"... and walk down it. */
+ q = endp + 1;
+ notif = NULL;
+ while (q != NULL)
+ {
+ endq = strchr (q, '+');
+ if (endq == NULL || (nextp != NULL && endq > nextp))
+ {
+ if (nextp == NULL)
+ endq = q + strlen (q);
+ else
+ endq = nextp;
+ nextq = NULL;
+ }
+ else
+ nextq = endq + 1;
+
+ /* If there is a temporary and a regular watch, send a single
+ notification, for the regular watch. */
+ if (type == 'E' && endq - q == 4 && strncmp ("edit", q, 4) == 0)
+ {
+ notif = "edit";
+ }
+ else if (type == 'U'
+ && endq - q == 6 && strncmp ("unedit", q, 6) == 0)
+ {
+ notif = "unedit";
+ }
+ else if (type == 'C'
+ && endq - q == 6 && strncmp ("commit", q, 6) == 0)
+ {
+ notif = "commit";
+ }
+ else if (type == 'E'
+ && endq - q == 5 && strncmp ("tedit", q, 5) == 0)
+ {
+ if (notif == NULL)
+ notif = "temporary edit";
+ }
+ else if (type == 'U'
+ && endq - q == 7 && strncmp ("tunedit", q, 7) == 0)
+ {
+ if (notif == NULL)
+ notif = "temporary unedit";
+ }
+ else if (type == 'C'
+ && endq - q == 7 && strncmp ("tcommit", q, 7) == 0)
+ {
+ if (notif == NULL)
+ notif = "temporary commit";
+ }
+ q = nextq;
+ }
+ if (nextp != NULL)
+ ++nextp;
+
+ if (notif != NULL)
+ {
+ struct notify_proc_args args;
+ size_t len = endp - p;
+ FILE *fp;
+ char *usersname;
+ char *line = NULL;
+ size_t line_len = 0;
+
+ args.notifyee = NULL;
+ usersname = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_USERS);
+ fp = CVS_FOPEN (usersname, "r");
+ if (fp == NULL && !existence_error (errno))
+ error (0, errno, "cannot read %s", usersname);
+ if (fp != NULL)
+ {
+ while (getline (&line, &line_len, fp) >= 0)
+ {
+ if (strncmp (line, p, len) == 0
+ && line[len] == ':')
+ {
+ char *cp;
+ args.notifyee = xstrdup (line + len + 1);
+
+ /* There may or may not be more
+ colon-separated fields added to this in the
+ future; in any case, we ignore them right
+ now, and if there are none we make sure to
+ chop off the final newline, if any. */
+ cp = strpbrk (args.notifyee, ":\n");
+
+ if (cp != NULL)
+ *cp = '\0';
+ break;
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", usersname);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", usersname);
+ }
+ free (usersname);
+ if (line != NULL)
+ free (line);
+
+ if (args.notifyee == NULL)
+ {
+ char *tmp;
+ tmp = xmalloc (endp - p + 1);
+ strncpy (tmp, p, endp - p);
+ tmp[endp - p] = '\0';
+ args.notifyee = tmp;
+ }
+
+ args.type = notif;
+ args.who = who;
+ args.file = filename;
+
+ (void) Parse_Info (CVSROOTADM_NOTIFY, repository, notify_proc,
+ PIOPT_ALL, &args);
+ /* It's okay to cast out the const for the free() below since we
+ * just allocated this a few lines above. The const was for
+ * everybody else.
+ */
+ free ((char *)args.notifyee);
+ }
+
+ p = nextp;
+ }
+ if (watchers != NULL)
+ free (watchers);
+
+ switch (type)
+ {
+ case 'E':
+ if (*watches == 'E')
+ {
+ args.add_tedit = 1;
+ ++watches;
+ }
+ if (*watches == 'U')
+ {
+ args.add_tunedit = 1;
+ ++watches;
+ }
+ if (*watches == 'C')
+ {
+ args.add_tcommit = 1;
+ }
+ watch_modify_watchers (filename, &args);
+ break;
+ case 'U':
+ case 'C':
+ args.remove_temp = 1;
+ watch_modify_watchers (filename, &args);
+ break;
+ }
+}
+
+
+
+#ifdef CLIENT_SUPPORT
+/* Check and send notifications. This is only for the client. */
+void
+notify_check (const char *repository, const char *update_dir)
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t line_len = 0;
+
+ if (!server_started)
+ /* We are in the midst of a command which is not to talk to
+ the server (e.g. the first phase of a cvs edit). Just chill
+ out, we'll catch the notifications on the flip side. */
+ return;
+
+ /* We send notifications even if noexec. I'm not sure which behavior
+ is most sensible. */
+
+ fp = CVS_FOPEN (CVSADM_NOTIFY, "r");
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", CVSADM_NOTIFY);
+ return;
+ }
+ while (getline (&line, &line_len, fp) > 0)
+ {
+ int notif_type;
+ char *filename;
+ char *val;
+ char *cp;
+
+ notif_type = line[0];
+ if (notif_type == '\0')
+ continue;
+ filename = line + 1;
+ cp = strchr (filename, '\t');
+ if (cp == NULL)
+ continue;
+ *cp++ = '\0';
+ val = cp;
+
+ client_notify (repository, update_dir, filename, notif_type, val);
+ }
+ if (line)
+ free (line);
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", CVSADM_NOTIFY);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
+
+ /* Leave the CVSADM_NOTIFY file there, until the server tells us it
+ has dealt with it. */
+}
+#endif /* CLIENT_SUPPORT */
+
+
+static const char *const editors_usage[] =
+{
+ "Usage: %s %s [-lR] [<file>]...\n",
+ "-l\tProcess this directory only (not recursive).\n",
+ "-R\tProcess directories recursively (default).\n",
+ "(Specify the --help global option for a list of other help options.)\n",
+ NULL
+};
+
+
+
+static int
+editors_fileproc (void *callerdat, struct file_info *finfo)
+{
+ return find_editors_and_output (finfo);
+}
+
+
+
+int
+editors (int argc, char **argv)
+{
+ int local = 0;
+ int c;
+
+ if (argc == -1)
+ usage (editors_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lR")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (editors_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+ ign_setup ();
+
+ if (local)
+ send_arg ("-l");
+ send_arg ("--");
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("editors\012", 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ return start_recursion (editors_fileproc, NULL, NULL, NULL, NULL,
+ argc, argv, local, W_LOCAL, 0, CVS_LOCK_READ, NULL,
+ 0, NULL);
+}
diff --git a/src/edit.h b/src/edit.h
new file mode 100644
index 0000000..48caf59
--- /dev/null
+++ b/src/edit.h
@@ -0,0 +1,45 @@
+/* Interface to "cvs edit", "cvs watch on", and related features
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+extern int watch_on (int argc, char **argv);
+extern int watch_off (int argc, char **argv);
+
+#ifdef CLIENT_SUPPORT
+/* Check to see if any notifications are sitting around in need of being
+ sent. These are the notifications stored in CVSADM_NOTIFY (edit,unedit);
+ commit calls notify_do directly. */
+extern void notify_check (const char *repository, const char *update_dir);
+#endif /* CLIENT_SUPPORT */
+
+/* Issue a notification for file FILENAME. TYPE is 'E' for edit, 'U'
+ for unedit, and 'C' for commit. WHO is the user currently running.
+ For TYPE 'E', VAL is the time+host+directory data which goes in
+ _editors, and WATCHES is zero or more of E,U,C, in that order, to specify
+ what kinds of temporary watches to set. */
+extern void notify_do (int type, const char *filename, const char *upadte_dir,
+ const char *who, const char *val, const char *watches,
+ const char *repository);
+
+/* Set attributes to reflect the fact that EDITOR is editing FILENAME.
+ VAL is time+host+directory, or NULL if we are to say that EDITOR is
+ *not* editing FILENAME. */
+extern void editor_set (const char *filename, const char *editor,
+ const char *val);
+
+/* Take note of the fact that FILE is up to date (this munges CVS/Base;
+ processing of CVS/Entries is done separately). */
+extern void mark_up_to_date (const char *file);
+
+void editors_output (const char *fullname, const char *them);
+
+void edit_file (void *data, List *ent_list, const char *short_pathname,
+ const char *filename);
diff --git a/src/entries.c b/src/entries.c
new file mode 100644
index 0000000..0512380
--- /dev/null
+++ b/src/entries.c
@@ -0,0 +1,1133 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Entries file to Files file
+ *
+ * Creates the file Files containing the names that comprise the project, from
+ * the Entries file.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+static Node *AddEntryNode (List * list, Entnode *entnode);
+
+static Entnode *fgetentent (FILE *, char *, int *);
+static int fputentent (FILE *, Entnode *);
+
+static Entnode *subdir_record (int, const char *, const char *);
+
+static FILE *entfile;
+static char *entfilename; /* for error messages */
+
+
+
+/*
+ * Construct an Entnode
+ */
+static Entnode *
+Entnode_Create (enum ent_type type, const char *user, const char *vn,
+ const char *ts, const char *options, const char *tag,
+ const char *date, const char *ts_conflict)
+{
+ Entnode *ent;
+
+ /* Note that timestamp and options must be non-NULL */
+ ent = xmalloc (sizeof (Entnode));
+ ent->type = type;
+ ent->user = xstrdup (user);
+ ent->version = xstrdup (vn);
+ ent->timestamp = xstrdup (ts ? ts : "");
+ ent->options = xstrdup (options ? options : "");
+ ent->tag = xstrdup (tag);
+ ent->date = xstrdup (date);
+ ent->conflict = xstrdup (ts_conflict);
+
+ return ent;
+}
+
+/*
+ * Destruct an Entnode
+ */
+static void Entnode_Destroy (Entnode *);
+
+static void
+Entnode_Destroy (Entnode *ent)
+{
+ free (ent->user);
+ free (ent->version);
+ free (ent->timestamp);
+ free (ent->options);
+ if (ent->tag)
+ free (ent->tag);
+ if (ent->date)
+ free (ent->date);
+ if (ent->conflict)
+ free (ent->conflict);
+ free (ent);
+}
+
+/*
+ * Write out the line associated with a node of an entries file
+ */
+static int write_ent_proc (Node *, void *);
+static int
+write_ent_proc (Node *node, void *closure)
+{
+ Entnode *entnode = node->data;
+
+ if (closure != NULL && entnode->type != ENT_FILE)
+ *(int *) closure = 1;
+
+ if (fputentent (entfile, entnode))
+ error (1, errno, "cannot write %s", entfilename);
+
+ return 0;
+}
+
+/*
+ * write out the current entries file given a list, making a backup copy
+ * first of course
+ */
+static void
+write_entries (List *list)
+{
+ int sawdir;
+
+ sawdir = 0;
+
+ /* open the new one and walk the list writing entries */
+ entfilename = CVSADM_ENTBAK;
+ entfile = CVS_FOPEN (entfilename, "w+");
+ if (entfile == NULL)
+ {
+ /* Make this a warning, not an error. For example, one user might
+ have checked out a working directory which, for whatever reason,
+ contains an Entries.Log file. A second user, without write access
+ to that working directory, might want to do a "cvs log". The
+ problem rewriting Entries shouldn't affect the ability of "cvs log"
+ to work, although the warning is probably a good idea so that
+ whether Entries gets rewritten is not an inexplicable process. */
+ /* FIXME: should be including update_dir in message. */
+ error (0, errno, "cannot rewrite %s", entfilename);
+
+ /* Now just return. We leave the Entries.Log file around. As far
+ as I know, there is never any data lying around in 'list' that
+ is not in Entries.Log at this time (if there is an error writing
+ Entries.Log that is a separate problem). */
+ return;
+ }
+
+ (void) walklist (list, write_ent_proc, (void *) &sawdir);
+ if (! sawdir)
+ {
+ struct stickydirtag *sdtp;
+
+ /* We didn't write out any directories. Check the list
+ private data to see whether subdirectory information is
+ known. If it is, we need to write out an empty D line. */
+ sdtp = list->list->data;
+ if (sdtp == NULL || sdtp->subdirs)
+ if (fprintf (entfile, "D\n") < 0)
+ error (1, errno, "cannot write %s", entfilename);
+ }
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+
+ /* now, atomically (on systems that support it) rename it */
+ rename_file (entfilename, CVSADM_ENT);
+
+ /* now, remove the log file */
+ if (unlink_file (CVSADM_ENTLOG) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", CVSADM_ENTLOG);
+}
+
+
+
+/*
+ * Removes the argument file from the Entries file if necessary.
+ */
+void
+Scratch_Entry (List *list, const char *fname)
+{
+ Node *node;
+
+ TRACE (TRACE_FUNCTION, "Scratch_Entry(%s)", fname);
+
+ /* hashlookup to see if it is there */
+ if ((node = findnode_fn (list, fname)) != NULL)
+ {
+ if (!noexec)
+ {
+ entfilename = CVSADM_ENTLOG;
+ entfile = xfopen (entfilename, "a");
+
+ if (fprintf (entfile, "R ") < 0)
+ error (1, errno, "cannot write %s", entfilename);
+
+ write_ent_proc (node, NULL);
+
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+ }
+
+ delnode (node); /* delete the node */
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_scratch (fname);
+#endif
+ }
+}
+
+
+
+/*
+ * Enters the given file name/version/time-stamp into the Entries file,
+ * removing the old entry first, if necessary.
+ */
+void
+Register (List *list, const char *fname, const char *vn, const char *ts,
+ const char *options, const char *tag, const char *date,
+ const char *ts_conflict)
+{
+ Entnode *entnode;
+ Node *node;
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ server_register (fname, vn, ts, options, tag, date, ts_conflict);
+ }
+#endif
+
+ TRACE (TRACE_FUNCTION, "Register(%s, %s, %s%s%s, %s, %s %s)",
+ fname, vn, ts ? ts : "",
+ ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
+ options, tag ? tag : "", date ? date : "");
+
+ entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date,
+ ts_conflict);
+ node = AddEntryNode (list, entnode);
+
+ if (!noexec)
+ {
+ entfilename = CVSADM_ENTLOG;
+ entfile = CVS_FOPEN (entfilename, "a");
+
+ if (entfile == NULL)
+ {
+ /* Warning, not error, as in write_entries. */
+ /* FIXME-update-dir: should be including update_dir in message. */
+ error (0, errno, "cannot open %s", entfilename);
+ return;
+ }
+
+ if (fprintf (entfile, "A ") < 0)
+ error (1, errno, "cannot write %s", entfilename);
+
+ write_ent_proc (node, NULL);
+
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+ }
+}
+
+/*
+ * Node delete procedure for list-private sticky dir tag/date info
+ */
+static void
+freesdt (Node *p)
+{
+ struct stickydirtag *sdtp = p->data;
+
+ if (sdtp->tag)
+ free (sdtp->tag);
+ if (sdtp->date)
+ free (sdtp->date);
+ free ((char *) sdtp);
+}
+
+/* Return the next real Entries line. On end of file, returns NULL.
+ On error, prints an error message and returns NULL. */
+
+static Entnode *
+fgetentent (FILE *fpin, char *cmd, int *sawdir)
+{
+ Entnode *ent;
+ char *line;
+ size_t line_chars_allocated;
+ register char *cp;
+ enum ent_type type;
+ char *l, *user, *vn, *ts, *options;
+ char *tag_or_date, *tag, *date, *ts_conflict;
+ int line_length;
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ ent = NULL;
+ while ((line_length = getline (&line, &line_chars_allocated, fpin)) > 0)
+ {
+ l = line;
+
+ /* If CMD is not NULL, we are reading an Entries.Log file.
+ Each line in the Entries.Log file starts with a single
+ character command followed by a space. For backward
+ compatibility, the absence of a space indicates an add
+ command. */
+ if (cmd != NULL)
+ {
+ if (l[1] != ' ')
+ *cmd = 'A';
+ else
+ {
+ *cmd = l[0];
+ l += 2;
+ }
+ }
+
+ type = ENT_FILE;
+
+ if (l[0] == 'D')
+ {
+ type = ENT_SUBDIR;
+ *sawdir = 1;
+ ++l;
+ /* An empty D line is permitted; it is a signal that this
+ Entries file lists all known subdirectories. */
+ }
+
+ if (l[0] != '/')
+ continue;
+
+ user = l + 1;
+ if ((cp = strchr (user, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ vn = cp;
+ if ((cp = strchr (vn, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ ts = cp;
+ if ((cp = strchr (ts, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ options = cp;
+ if ((cp = strchr (options, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ tag_or_date = cp;
+ if ((cp = strchr (tag_or_date, '\n')) == NULL)
+ continue;
+ *cp = '\0';
+ tag = NULL;
+ date = NULL;
+ if (*tag_or_date == 'T')
+ tag = tag_or_date + 1;
+ else if (*tag_or_date == 'D')
+ date = tag_or_date + 1;
+
+ if ((ts_conflict = strchr (ts, '+')))
+ *ts_conflict++ = '\0';
+
+ /*
+ * XXX - Convert timestamp from old format to new format.
+ *
+ * If the timestamp doesn't match the file's current
+ * mtime, we'd have to generate a string that doesn't
+ * match anyways, so cheat and base it on the existing
+ * string; it doesn't have to match the same mod time.
+ *
+ * For an unmodified file, write the correct timestamp.
+ */
+ {
+ struct stat sb;
+ if (strlen (ts) > 30 && stat (user, &sb) == 0)
+ {
+ char *c = ctime (&sb.st_mtime);
+ /* Fix non-standard format. */
+ if (c[8] == '0') c[8] = ' ';
+
+ if (!strncmp (ts + 25, c, 24))
+ ts = time_stamp (user);
+ else
+ {
+ ts += 24;
+ ts[0] = '*';
+ }
+ }
+ }
+
+ ent = Entnode_Create (type, user, vn, ts, options, tag, date,
+ ts_conflict);
+ break;
+ }
+
+ if (line_length < 0 && !feof (fpin))
+ error (0, errno, "cannot read entries file");
+
+ free (line);
+ return ent;
+}
+
+static int
+fputentent (FILE *fp, Entnode *p)
+{
+ switch (p->type)
+ {
+ case ENT_FILE:
+ break;
+ case ENT_SUBDIR:
+ if (fprintf (fp, "D") < 0)
+ return 1;
+ break;
+ }
+
+ if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
+ return 1;
+ if (p->conflict)
+ {
+ if (fprintf (fp, "+%s", p->conflict) < 0)
+ return 1;
+ }
+ if (fprintf (fp, "/%s/", p->options) < 0)
+ return 1;
+
+ if (p->tag)
+ {
+ if (fprintf (fp, "T%s\n", p->tag) < 0)
+ return 1;
+ }
+ else if (p->date)
+ {
+ if (fprintf (fp, "D%s\n", p->date) < 0)
+ return 1;
+ }
+ else
+ {
+ if (fprintf (fp, "\n") < 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Read the entries file into a list, hashing on the file name.
+
+ UPDATE_DIR is the name of the current directory, for use in error
+ messages, or NULL if not known (that is, noone has gotten around
+ to updating the caller to pass in the information). */
+List *
+Entries_Open (int aflag, char *update_dir)
+{
+ List *entries;
+ struct stickydirtag *sdtp = NULL;
+ Entnode *ent;
+ char *dirtag, *dirdate;
+ int dirnonbranch;
+ int do_rewrite = 0;
+ FILE *fpin;
+ int sawdir;
+
+ /* get a fresh list... */
+ entries = getlist ();
+
+ /*
+ * Parse the CVS/Tag file, to get any default tag/date settings. Use
+ * list-private storage to tuck them away for Version_TS().
+ */
+ ParseTag (&dirtag, &dirdate, &dirnonbranch);
+ if (aflag || dirtag || dirdate)
+ {
+ sdtp = xmalloc (sizeof (*sdtp));
+ memset (sdtp, 0, sizeof (*sdtp));
+ sdtp->aflag = aflag;
+ sdtp->tag = xstrdup (dirtag);
+ sdtp->date = xstrdup (dirdate);
+ sdtp->nonbranch = dirnonbranch;
+
+ /* feed it into the list-private area */
+ entries->list->data = sdtp;
+ entries->list->delproc = freesdt;
+ }
+
+ sawdir = 0;
+
+ fpin = CVS_FOPEN (CVSADM_ENT, "r");
+ if (fpin == NULL)
+ {
+ if (update_dir != NULL)
+ error (0, 0, "in directory %s:", update_dir);
+ error (0, errno, "cannot open %s for reading", CVSADM_ENT);
+ }
+ else
+ {
+ while ((ent = fgetentent (fpin, NULL, &sawdir)) != NULL)
+ {
+ (void) AddEntryNode (entries, ent);
+ }
+
+ if (fclose (fpin) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_ENT);
+ }
+
+ fpin = CVS_FOPEN (CVSADM_ENTLOG, "r");
+ if (fpin != NULL)
+ {
+ char cmd;
+ Node *node;
+
+ while ((ent = fgetentent (fpin, &cmd, &sawdir)) != NULL)
+ {
+ switch (cmd)
+ {
+ case 'A':
+ (void) AddEntryNode (entries, ent);
+ break;
+ case 'R':
+ node = findnode_fn (entries, ent->user);
+ if (node != NULL)
+ delnode (node);
+ Entnode_Destroy (ent);
+ break;
+ default:
+ /* Ignore unrecognized commands. */
+ Entnode_Destroy (ent);
+ break;
+ }
+ }
+ do_rewrite = 1;
+ if (fclose (fpin) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_ENTLOG);
+ }
+
+ /* Update the list private data to indicate whether subdirectory
+ information is known. Nonexistent list private data is taken
+ to mean that it is known. */
+ if (sdtp != NULL)
+ sdtp->subdirs = sawdir;
+ else if (! sawdir)
+ {
+ sdtp = xmalloc (sizeof (*sdtp));
+ memset (sdtp, 0, sizeof (*sdtp));
+ sdtp->subdirs = 0;
+ entries->list->data = sdtp;
+ entries->list->delproc = freesdt;
+ }
+
+ if (do_rewrite && !noexec)
+ write_entries (entries);
+
+ /* clean up and return */
+ if (dirtag)
+ free (dirtag);
+ if (dirdate)
+ free (dirdate);
+ return entries;
+}
+
+void
+Entries_Close (List *list)
+{
+ if (list)
+ {
+ if (!noexec)
+ {
+ if (isfile (CVSADM_ENTLOG))
+ write_entries (list);
+ }
+ dellist (&list);
+ }
+}
+
+
+/*
+ * Free up the memory associated with the data section of an ENTRIES type
+ * node
+ */
+static void
+Entries_delproc (Node *node)
+{
+ Entnode *p = node->data;
+
+ Entnode_Destroy (p);
+}
+
+/*
+ * Get an Entries file list node, initialize it, and add it to the specified
+ * list
+ */
+static Node *
+AddEntryNode (List *list, Entnode *entdata)
+{
+ Node *p;
+
+ /* was it already there? */
+ if ((p = findnode_fn (list, entdata->user)) != NULL)
+ {
+ /* take it out */
+ delnode (p);
+ }
+
+ /* get a node and fill in the regular stuff */
+ p = getnode ();
+ p->type = ENTRIES;
+ p->delproc = Entries_delproc;
+
+ /* this one gets a key of the name for hashing */
+ /* FIXME This results in duplicated data --- the hash package shouldn't
+ assume that the key is dynamically allocated. The user's free proc
+ should be responsible for freeing the key. */
+ p->key = xstrdup (entdata->user);
+ p->data = entdata;
+
+ /* put the node into the list */
+ addnode (list, p);
+ return p;
+}
+
+
+
+/*
+ * Write out the CVS/Template file.
+ */
+void
+WriteTemplate (const char *update_dir, int xdotemplate, const char *repository)
+{
+#ifdef SERVER_SUPPORT
+ TRACE (TRACE_FUNCTION, "Write_Template (%s, %s)", update_dir, repository);
+
+ if (noexec)
+ return;
+
+ if (server_active && xdotemplate)
+ {
+ /* Clear the CVS/Template if supported to allow for the case
+ * where the rcsinfo file no longer has an entry for this
+ * directory.
+ */
+ server_clear_template (update_dir, repository);
+ server_template (update_dir, repository);
+ }
+#endif
+
+ return;
+}
+
+
+
+/*
+ * Write out/Clear the CVS/Tag file.
+ */
+void
+WriteTag (const char *dir, const char *tag, const char *date, int nonbranch,
+ const char *update_dir, const char *repository)
+{
+ FILE *fout;
+ char *tmp;
+
+ if (noexec)
+ return;
+
+ if (dir != NULL)
+ tmp = Xasprintf ("%s/%s", dir, CVSADM_TAG);
+ else
+ tmp = xstrdup (CVSADM_TAG);
+
+
+ if (tag || date)
+ {
+ fout = xfopen (tmp, "w+");
+ if (tag)
+ {
+ if (nonbranch)
+ {
+ if (fprintf (fout, "N%s\n", tag) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ else
+ {
+ if (fprintf (fout, "T%s\n", tag) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ }
+ else
+ {
+ if (fprintf (fout, "D%s\n", date) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ if (fclose (fout) == EOF)
+ error (1, errno, "cannot close %s", tmp);
+ }
+ else
+ if (unlink_file (tmp) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove %s", tmp);
+ free (tmp);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_sticky (update_dir, repository, tag, date, nonbranch);
+#endif
+}
+
+/* Parse the CVS/Tag file for the current directory.
+
+ If it contains a date, sets *DATEP to the date in a newly malloc'd
+ string, *TAGP to NULL, and *NONBRANCHP to an unspecified value.
+
+ If it contains a branch tag, sets *TAGP to the tag in a newly
+ malloc'd string, *NONBRANCHP to 0, and *DATEP to NULL.
+
+ If it contains a nonbranch tag, sets *TAGP to the tag in a newly
+ malloc'd string, *NONBRANCHP to 1, and *DATEP to NULL.
+
+ If it does not exist, or contains something unrecognized by this
+ version of CVS, set *DATEP and *TAGP to NULL and *NONBRANCHP to
+ an unspecified value.
+
+ If there is an error, print an error message, set *DATEP and *TAGP
+ to NULL, and return. */
+void
+ParseTag (char **tagp, char **datep, int *nonbranchp)
+{
+ FILE *fp;
+
+ if (tagp)
+ *tagp = NULL;
+ if (datep)
+ *datep = NULL;
+ /* Always store a value here, even in the 'D' case where the value
+ is unspecified. Shuts up tools which check for references to
+ uninitialized memory. */
+ if (nonbranchp != NULL)
+ *nonbranchp = 0;
+ fp = CVS_FOPEN (CVSADM_TAG, "r");
+ if (fp)
+ {
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0)
+ {
+ /* Remove any trailing newline. */
+ if (line[line_length - 1] == '\n')
+ line[--line_length] = '\0';
+ switch (*line)
+ {
+ case 'T':
+ if (tagp != NULL)
+ *tagp = xstrdup (line + 1);
+ break;
+ case 'D':
+ if (datep != NULL)
+ *datep = xstrdup (line + 1);
+ break;
+ case 'N':
+ if (tagp != NULL)
+ *tagp = xstrdup (line + 1);
+ if (nonbranchp != NULL)
+ *nonbranchp = 1;
+ break;
+ default:
+ /* Silently ignore it; it may have been
+ written by a future version of CVS which extends the
+ syntax. */
+ break;
+ }
+ }
+
+ if (line_length < 0)
+ {
+ /* FIXME-update-dir: should include update_dir in messages. */
+ if (feof (fp))
+ error (0, 0, "cannot read %s: end of file", CVSADM_TAG);
+ else
+ error (0, errno, "cannot read %s", CVSADM_TAG);
+ }
+
+ if (fclose (fp) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_TAG);
+
+ free (line);
+ }
+ else if (!existence_error (errno))
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot open %s", CVSADM_TAG);
+}
+
+/*
+ * This is called if all subdirectory information is known, but there
+ * aren't any subdirectories. It records that fact in the list
+ * private data.
+ */
+
+void
+Subdirs_Known (List *entries)
+{
+ struct stickydirtag *sdtp = entries->list->data;
+
+ /* If there is no list private data, that means that the
+ subdirectory information is known. */
+ if (sdtp != NULL && ! sdtp->subdirs)
+ {
+ FILE *fp;
+
+ sdtp->subdirs = 1;
+ if (!noexec)
+ {
+ /* Create Entries.Log so that Entries_Close will do something. */
+ entfilename = CVSADM_ENTLOG;
+ fp = CVS_FOPEN (entfilename, "a");
+ if (fp == NULL)
+ {
+ int save_errno = errno;
+
+ /* As in subdir_record, just silently skip the whole thing
+ if there is no CVSADM directory. */
+ if (! isdir (CVSADM))
+ return;
+ error (1, save_errno, "cannot open %s", entfilename);
+ }
+ else
+ {
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", entfilename);
+ }
+ }
+ }
+}
+
+/* Record subdirectory information. */
+
+static Entnode *
+subdir_record (int cmd, const char *parent, const char *dir)
+{
+ Entnode *entnode;
+
+ /* None of the information associated with a directory is
+ currently meaningful. */
+ entnode = Entnode_Create (ENT_SUBDIR, dir, "", "", "",
+ NULL, NULL, NULL);
+
+ if (!noexec)
+ {
+ if (parent == NULL)
+ entfilename = CVSADM_ENTLOG;
+ else
+ entfilename = Xasprintf ("%s/%s", parent, CVSADM_ENTLOG);
+
+ entfile = CVS_FOPEN (entfilename, "a");
+ if (entfile == NULL)
+ {
+ int save_errno = errno;
+
+ /* It is not an error if there is no CVS administration
+ directory. Permitting this case simplifies some
+ calling code. */
+
+ if (parent == NULL)
+ {
+ if (! isdir (CVSADM))
+ return entnode;
+ }
+ else
+ {
+ free (entfilename);
+ entfilename = Xasprintf ("%s/%s", parent, CVSADM);
+ if (! isdir (entfilename))
+ {
+ free (entfilename);
+ entfilename = NULL;
+ return entnode;
+ }
+ }
+
+ error (1, save_errno, "cannot open %s", entfilename);
+ }
+
+ if (fprintf (entfile, "%c ", cmd) < 0)
+ error (1, errno, "cannot write %s", entfilename);
+
+ if (fputentent (entfile, entnode) != 0)
+ error (1, errno, "cannot write %s", entfilename);
+
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+
+ if (parent != NULL)
+ {
+ free (entfilename);
+ entfilename = NULL;
+ }
+ }
+
+ return entnode;
+}
+
+/*
+ * Record the addition of a new subdirectory DIR in PARENT. PARENT
+ * may be NULL, which means the current directory. ENTRIES is the
+ * current entries list; it may be NULL, which means that it need not
+ * be updated.
+ */
+
+void
+Subdir_Register (List *entries, const char *parent, const char *dir)
+{
+ Entnode *entnode;
+
+ /* Ignore attempts to register ".". These can happen in the
+ server code. */
+ if (dir[0] == '.' && dir[1] == '\0')
+ return;
+
+ entnode = subdir_record ('A', parent, dir);
+
+ if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
+ (void) AddEntryNode (entries, entnode);
+ else
+ Entnode_Destroy (entnode);
+}
+
+
+
+/*
+ * Record the removal of a subdirectory. The arguments are the same
+ * as for Subdir_Register.
+ */
+
+void
+Subdir_Deregister (List *entries, const char *parent, const char *dir)
+{
+ Entnode *entnode;
+
+ entnode = subdir_record ('R', parent, dir);
+ Entnode_Destroy (entnode);
+
+ if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
+ {
+ Node *p;
+
+ p = findnode_fn (entries, dir);
+ if (p != NULL)
+ delnode (p);
+ }
+}
+
+
+
+/* OK, the following base_* code tracks the revisions of the files in
+ CVS/Base. We do this in a file CVS/Baserev. Separate from
+ CVS/Entries because it needs to go in separate data structures
+ anyway (the name in Entries must be unique), so this seemed
+ cleaner. The business of rewriting the whole file in
+ base_deregister and base_register is the kind of thing we used to
+ do for Entries and which turned out to be slow, which is why there
+ is now the Entries.Log machinery. So maybe from that point of
+ view it is a mistake to do this separately from Entries, I dunno. */
+
+enum base_walk
+{
+ /* Set the revision for FILE to *REV. */
+ BASE_REGISTER,
+ /* Get the revision for FILE and put it in a newly malloc'd string
+ in *REV, or put NULL if not mentioned. */
+ BASE_GET,
+ /* Remove FILE. */
+ BASE_DEREGISTER
+};
+
+static void base_walk (enum base_walk, struct file_info *, char **);
+
+/* Read through the lines in CVS/Baserev, taking the actions as documented
+ for CODE. */
+
+static void
+base_walk (enum base_walk code, struct file_info *finfo, char **rev)
+{
+ FILE *fp;
+ char *line;
+ size_t line_allocated;
+ FILE *newf;
+ char *baserev_fullname;
+ char *baserevtmp_fullname;
+
+ line = NULL;
+ line_allocated = 0;
+ newf = NULL;
+
+ /* First compute the fullnames for the error messages. This
+ computation probably should be broken out into a separate function,
+ as recurse.c does it too and places like Entries_Open should be
+ doing it. */
+ if (finfo->update_dir[0] != '\0')
+ {
+ baserev_fullname = Xasprintf ("%s/%s", finfo->update_dir,
+ CVSADM_BASEREV);
+ baserevtmp_fullname = Xasprintf ("%s/%s", finfo->update_dir,
+ CVSADM_BASEREVTMP);
+ }
+ else
+ {
+ baserev_fullname = xstrdup (CVSADM_BASEREV);
+ baserevtmp_fullname = xstrdup (CVSADM_BASEREVTMP);
+ }
+
+ fp = CVS_FOPEN (CVSADM_BASEREV, "r");
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ {
+ error (0, errno, "cannot open %s for reading", baserev_fullname);
+ goto out;
+ }
+ }
+
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ newf = CVS_FOPEN (CVSADM_BASEREVTMP, "w");
+ if (newf == NULL)
+ {
+ error (0, errno, "cannot open %s for writing",
+ baserevtmp_fullname);
+ goto out;
+ }
+ break;
+ case BASE_GET:
+ *rev = NULL;
+ break;
+ }
+
+ if (fp != NULL)
+ {
+ while (getline (&line, &line_allocated, fp) >= 0)
+ {
+ char *linefile;
+ char *p;
+ char *linerev;
+
+ if (line[0] != 'B')
+ /* Ignore, for future expansion. */
+ continue;
+
+ linefile = line + 1;
+ p = strchr (linefile, '/');
+ if (p == NULL)
+ /* Syntax error, ignore. */
+ continue;
+ linerev = p + 1;
+ p = strchr (linerev, '/');
+ if (p == NULL)
+ continue;
+
+ linerev[-1] = '\0';
+ if (fncmp (linefile, finfo->file) == 0)
+ {
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ /* Don't copy over the old entry, we don't want it. */
+ break;
+ case BASE_GET:
+ *p = '\0';
+ *rev = xstrdup (linerev);
+ *p = '/';
+ goto got_it;
+ }
+ }
+ else
+ {
+ linerev[-1] = '/';
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ if (fprintf (newf, "%s\n", line) < 0)
+ error (0, errno, "error writing %s",
+ baserevtmp_fullname);
+ break;
+ case BASE_GET:
+ break;
+ }
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", baserev_fullname);
+ }
+ got_it:
+
+ if (code == BASE_REGISTER)
+ {
+ if (fprintf (newf, "B%s/%s/\n", finfo->file, *rev) < 0)
+ error (0, errno, "error writing %s",
+ baserevtmp_fullname);
+ }
+
+ out:
+
+ if (line != NULL)
+ free (line);
+
+ if (fp != NULL)
+ {
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", baserev_fullname);
+ }
+ if (newf != NULL)
+ {
+ if (fclose (newf) < 0)
+ error (0, errno, "cannot close %s", baserevtmp_fullname);
+ rename_file (CVSADM_BASEREVTMP, CVSADM_BASEREV);
+ }
+
+ free (baserev_fullname);
+ free (baserevtmp_fullname);
+}
+
+/* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev,
+ or NULL if not listed. */
+
+char *
+base_get (struct file_info *finfo)
+{
+ char *rev;
+ base_walk (BASE_GET, finfo, &rev);
+ return rev;
+}
+
+/* Set the revision for FILE to REV. */
+
+void
+base_register (struct file_info *finfo, char *rev)
+{
+ base_walk (BASE_REGISTER, finfo, &rev);
+}
+
+/* Remove FILE. */
+
+void
+base_deregister (struct file_info *finfo)
+{
+ base_walk (BASE_DEREGISTER, finfo, NULL);
+}
diff --git a/src/error.c b/src/error.c
new file mode 100644
index 0000000..7f355bc
--- /dev/null
+++ b/src/error.c
@@ -0,0 +1,267 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990-1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* David MacKenzie */
+/* Brian Berliner added support for CVS */
+
+#include "cvs.h"
+#include "vasnprintf.h"
+
+/* Out of memory errors which could not be forwarded to the client are sent to
+ * the syslog when it is available.
+ */
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+# ifndef LOG_DAEMON /* for ancient syslogs */
+# define LOG_DAEMON 0
+# endif
+#endif /* HAVE_SYSLOG_H */
+
+
+
+/* If non-zero, error will use the CVS protocol to stdout to report error
+ * messages. This will only be set in the CVS server parent process.
+ *
+ * Most other code is run via do_cvs_command, which forks off a child
+ * process and packages up its stderr in the protocol.
+ */
+int error_use_protocol;
+
+#ifndef strerror
+extern char *strerror (int);
+#endif
+
+
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ * format string with optional args, like:
+ *
+ * PROGRAM_NAME CVS_CMD_NAME: MESSAGE: ERRNUM
+ *
+ * or, when STATUS is non-zero:
+ *
+ * PROGRAM_NAME [CVS_CMD_NAME aborted]: MESSAGE: ERRNUM
+ *
+ * CVS_CMD_NAME & ERRMSG may or may not appear in the output (the `:' before
+ * ERRMSG will disappear as well when ERRNUM is not present). ERRMSG
+ * represents the system dependent message returned by strerror (ERRNUM), when
+ * ERRNUM is non-zero.
+ *
+ * Exit with status EXIT_FAILURE if STATUS is nonzero.
+ *
+ * If this function fails to get any memory it might request, it attempts to
+ * log a "memory exhausted" message to the syslog, when syslog is available,
+ * without any further attempts to allocate memory, before exiting. See NOTES
+ * below for more information on this functions memory allocation.
+ *
+ * INPUTS
+ * status When non-zero, exit with EXIT_FAILURE rather than returning.
+ * errnum When non-zero, interpret as global ERRNO for the purpose of
+ * generating additional error text.
+ * message A printf style format string.
+ * ... Variable number of args, as printf.
+ *
+ * GLOBALS
+ * program_name The name of this executable, for the output message.
+ * cvs_cmd_name Output in the error message, when it exists.
+ * errno Accessed simply to save and restore it before
+ * returning.
+ *
+ * NOTES
+ * This function goes to fairly great lengths to avoid allocating memory so
+ * that it can relay out-of-memory error messages to the client. Any error
+ * messages which fit in under 256 characters (after expanding MESSAGE with
+ * ARGS but before adding any ERRNUM text) should not require memory
+ * allocation before they are sent on to cvs_outerr(). Unfortunately,
+ * cvs_outerr() and the buffer functions it uses to send messages to the
+ * client still don't make this same sort of effort, so in local mode
+ * out-of-memory errors will probably get printed properly to stderr but if a
+ * memory outage happens on the server, the admin will need to consult the
+ * syslog to find out what went wrong.
+ *
+ * I think this is largely cleaned up to the point where it does the right
+ * thing for the server, whether the normal server_active (child process)
+ * case or the error_use_protocol (parent process) case. The one exception
+ * is that STATUS nonzero for error_use_protocol probably doesn't work yet;
+ * in that case still need to use the pending_error machinery in server.c.
+ *
+ * error() does not molest errno; some code (e.g. Entries_Open) depends
+ * on being able to say something like:
+ *
+ * error (0, 0, "foo");
+ * error (0, errno, "bar");
+ *
+ * RETURNS
+ * Sometimes. ;)
+ */
+void
+error (int status, int errnum, const char *message, ...)
+{
+ va_list args;
+ int save_errno = errno;
+
+ /* Various buffers we attempt to use to generate the error message. */
+ char statbuf[256];
+ char *buf;
+ size_t length;
+ char statbuf2[384];
+ char *buf2;
+ char statcmdbuf[32];
+ char *cmdbuf;
+ char *emptybuf = "";
+
+ static const char *last_message = NULL;
+ static int last_status;
+ static int last_errnum;
+
+ /* Initialize these to avoid a lot of special case error handling. */
+ buf = statbuf;
+ buf2 = statbuf2;
+ cmdbuf = emptybuf;
+
+ /* Expand the message the user passed us. */
+ length = sizeof (statbuf);
+ va_start (args, message);
+ buf = vasnprintf (statbuf, &length, message, args);
+ va_end (args);
+ if (!buf) goto memerror;
+
+ /* Expand the cvs commmand name to <cmd> or [<cmd> aborted].
+ *
+ * I could squeeze this into the buf2 printf below, but this makes the code
+ * easier to read and I don't think error messages are printed often enough
+ * to make this a major performance hit. I think the memory cost is about
+ * 40 bytes.
+ */
+ if (cvs_cmd_name)
+ {
+ length = sizeof (statcmdbuf);
+ cmdbuf = asnprintf (statcmdbuf, &length, " %s%s%s",
+ status ? "[" : "",
+ cvs_cmd_name,
+ status ? " aborted]" : "");
+ /* Else cmdbuf still = emptybuf. */
+ if (!cmdbuf) goto memerror;
+ }
+ /* Else cmdbuf still = emptybuf. */
+
+ /* Now put it all together. */
+ length = sizeof (statbuf2);
+ buf2 = asnprintf (statbuf2, &length, "%s%s: %s%s%s\n",
+ program_name, cmdbuf, buf,
+ errnum ? ": " : "", errnum ? strerror (errnum) : "");
+ if (!buf2) goto memerror;
+
+ /* Send the final message to the client or log it.
+ *
+ * Set this recursion block first since this is the only function called
+ * here which can cause error() to be called a second time.
+ */
+ if (last_message) goto recursion_error;
+ last_message = buf2;
+ last_status = status;
+ last_errnum = errnum;
+ cvs_outerr (buf2, length);
+
+ /* Reset our recursion lock. This needs to be done before the call to
+ * exit() to allow the exit handlers to make calls to error().
+ */
+ last_message = NULL;
+
+ /* Done, if we're exiting. */
+ if (status)
+ exit (EXIT_FAILURE);
+
+ /* Free anything we may have allocated. */
+ if (buf != statbuf) free (buf);
+ if (buf2 != statbuf2) free (buf2);
+ if (cmdbuf != statcmdbuf && cmdbuf != emptybuf) free (cmdbuf);
+
+ /* Restore errno per our charter. */
+ errno = save_errno;
+
+ /* Done. */
+ return;
+
+memerror:
+ /* Make one last attempt to log the problem in the syslog since that
+ * should not require new memory, then abort.
+ *
+ * No second attempt is made to send the information to the client - if we
+ * got here then that already failed once and this prevents us from
+ * entering an infinite loop.
+ *
+ * FIXME
+ * If the buffer routines can be altered in such a way that a single,
+ * short, statically allocated message could be sent without needing to
+ * allocate new memory, then it would still be safe to call cvs_outerr
+ * with the message here.
+ */
+#if HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_EMERG, "Memory exhausted. Aborting.");
+#endif /* HAVE_SYSLOG_H */
+
+ goto sidestep_done;
+
+recursion_error:
+#if HAVE_SYSLOG_H
+ /* Syslog the problem since recursion probably means that we encountered an
+ * error while attempting to send the last error message to the client.
+ */
+
+ syslog (LOG_DAEMON | LOG_EMERG,
+ "error (%d, %d) called recursively. Original message was:",
+ last_status, last_errnum);
+ syslog (LOG_DAEMON | LOG_EMERG, "%s", last_message);
+
+
+ syslog (LOG_DAEMON | LOG_EMERG,
+ "error (%d, %d) called recursively. Second message was:",
+ status, errnum);
+ syslog (LOG_DAEMON | LOG_EMERG, "%s", buf2);
+
+ syslog (LOG_DAEMON | LOG_EMERG, "Aborting.");
+#endif /* HAVE_SYSLOG_H */
+
+sidestep_done:
+ /* Reset our recursion lock. This needs to be done before the call to
+ * exit() to allow the exit handlers to make calls to error().
+ */
+ last_message = NULL;
+
+ exit (EXIT_FAILURE);
+}
+
+
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args to the file specified by FP.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status EXIT_FAILURE if STATUS is nonzero. */
+/* VARARGS */
+void
+fperrmsg (FILE *fp, int status, int errnum, char *message, ...)
+{
+ va_list args;
+
+ fprintf (fp, "%s: ", program_name);
+ va_start (args, message);
+ vfprintf (fp, message, args);
+ va_end (args);
+ if (errnum)
+ fprintf (fp, ": %s", strerror (errnum));
+ putc ('\n', fp);
+ fflush (fp);
+ if (status)
+ exit (EXIT_FAILURE);
+}
diff --git a/src/exithandle.c b/src/exithandle.c
new file mode 100644
index 0000000..ecb85db
--- /dev/null
+++ b/src/exithandle.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003, Derek Price and Ximbiot <http://ximbiot.com>
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS source
+ * distribution.
+ *
+ * This is a convenience wrapper for some of the functions in lib/sighandle.c.
+ */
+
+#include "cvs.h"
+
+/*
+ * Register a handler for all signals.
+ */
+void
+signals_register (RETSIGTYPE (*handler)(int))
+{
+#ifndef DONT_USE_SIGNALS
+#ifdef SIGABRT
+ (void) SIG_register (SIGABRT, handler);
+#endif
+#ifdef SIGHUP
+ (void) SIG_register (SIGHUP, handler);
+#endif
+#ifdef SIGINT
+ (void) SIG_register (SIGINT, handler);
+#endif
+#ifdef SIGQUIT
+ (void) SIG_register (SIGQUIT, handler);
+#endif
+#ifdef SIGPIPE
+ (void) SIG_register (SIGPIPE, handler);
+#endif
+#ifdef SIGTERM
+ (void) SIG_register (SIGTERM, handler);
+#endif
+#endif /* !DONT_USE_SIGNALS */
+}
+
+
+
+/*
+ * Register a handler for all signals and exit.
+ */
+void
+cleanup_register (void (*handler) (void))
+{
+ atexit (handler);
+
+ /* Always calling this function before any other exit handlers guarantees
+ * that signals will be blocked by the time the other exit handlers are
+ * called.
+ *
+ * SIG_beginCrSect will be called once for each handler registered via
+ * cleanup_register, but there is no unregister routine for atexit() and
+ * this seems like minimal overhead.
+ *
+ * There is no reason to unblock signals again when the exit handlers are
+ * done since the program will be exiting anyhow.
+ */
+ atexit (SIG_beginCrSect);
+}
diff --git a/src/expand_path.c b/src/expand_path.c
new file mode 100644
index 0000000..a25e84f
--- /dev/null
+++ b/src/expand_path.c
@@ -0,0 +1,382 @@
+/* expand_path.c -- expand environmental variables in passed in string
+ *
+ * Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * The main routine is expand_path(), it is the routine that handles
+ * the '~' character in four forms:
+ * ~name
+ * ~name/
+ * ~/
+ * ~
+ * and handles environment variables contained within the pathname
+ * which are defined by:
+ * ${var_name} (var_name is the name of the environ variable)
+ * $var_name (var_name ends w/ non-alphanumeric char other than '_')
+ */
+
+#include "cvs.h"
+#include <sys/types.h>
+
+/* User variables. */
+
+List *variable_list;
+
+static void variable_delproc (Node *);
+
+static void
+variable_delproc (Node *node)
+{
+ free (node->data);
+}
+
+/* Currently used by -s option; we might want a way to set user
+ variables in a file in the $CVSROOT/CVSROOT directory too. */
+
+void
+variable_set (char *nameval)
+{
+ char *p;
+ char *name;
+ Node *node;
+
+ p = nameval;
+ while (isalnum ((unsigned char) *p) || *p == '_')
+ ++p;
+ if (*p != '=')
+ error (1, 0, "invalid character in user variable name in %s", nameval);
+ if (p == nameval)
+ error (1, 0, "empty user variable name in %s", nameval);
+ name = xmalloc (p - nameval + 1);
+ strncpy (name, nameval, p - nameval);
+ name[p - nameval] = '\0';
+ /* Make p point to the value. */
+ ++p;
+ if (strchr (p, '\012'))
+ error (1, 0, "linefeed in user variable value in %s", nameval);
+
+ if (!variable_list)
+ variable_list = getlist ();
+
+ node = findnode (variable_list, name);
+ if (!node)
+ {
+ node = getnode ();
+ node->type = VARIABLE;
+ node->delproc = variable_delproc;
+ node->key = name;
+ node->data = xstrdup (p);
+ (void) addnode (variable_list, node);
+ }
+ else
+ {
+ /* Replace the old value. For example, this means that -s
+ options on the command line override ones from .cvsrc. */
+ free (node->data);
+ node->data = xstrdup (p);
+ free (name);
+ }
+}
+
+
+
+/* Expand variable NAME into its contents, per the rules above.
+ *
+ * CVSROOT is used to expanding $CVSROOT.
+ *
+ * RETURNS
+ * A pointer to the requested variable contents or NULL when the requested
+ * variable is not found.
+ *
+ * ERRORS
+ * None, though this function may generate warning messages when NAME is not
+ * found.
+ */
+static const char *
+expand_variable (const char *name, const char *cvsroot,
+ const char *file, int line)
+{
+ if (!strcmp (name, CVSROOT_ENV))
+ return cvsroot;
+ else if (!strcmp (name, "RCSBIN"))
+ {
+ error (0, 0, "RCSBIN internal variable is no longer supported");
+ return NULL;
+ }
+ else if (!strcmp (name, EDITOR1_ENV))
+ return Editor;
+ else if (!strcmp (name, EDITOR2_ENV))
+ return Editor;
+ else if (!strcmp (name, EDITOR3_ENV))
+ return Editor;
+ else if (!strcmp (name, "USER"))
+ return getcaller ();
+ else if (!strcmp (name, "SESSIONID")
+ || !strcmp (name, "COMMITID"))
+ return global_session_id;
+ else if (isalpha (name[0]))
+ {
+ /* These names are reserved for future versions of CVS,
+ so that is why it is an error. */
+ if (line)
+ error (0, 0, "%s:%d: no such internal variable $%s",
+ file, line, name);
+ else
+ error (0, 0, "%s: no such internal variable $%s",
+ file, name);
+ return NULL;
+ }
+ else if (name[0] == '=')
+ {
+ Node *node;
+ /* Crazy syntax for a user variable. But we want
+ *something* that lets the user name a user variable
+ anything he wants, without interference from
+ (existing or future) internal variables. */
+ node = findnode (variable_list, name + 1);
+ if (!node)
+ {
+ if (line)
+ error (0, 0, "%s:%d: no such user variable ${%s}",
+ file, line, name);
+ else
+ error (0, 0, "%s: no such user variable ${%s}",
+ file, name);
+ return NULL;
+ }
+ return node->data;
+ }
+ else
+ {
+ /* It is an unrecognized character. We return an error to
+ reserve these for future versions of CVS; it is plausible
+ that various crazy syntaxes might be invented for inserting
+ information about revisions, branches, etc. */
+ if (line)
+ error (0, 0, "%s:%d: unrecognized variable syntax %s",
+ file, line, name);
+ else
+ error (0, 0, "%s: unrecognized variable syntax %s",
+ file, name);
+ return NULL;
+ }
+}
+
+
+
+/* This routine will expand the pathname to account for ~ and $
+ * characters as described above. Returns a pointer to a newly
+ * malloc'd string. If an error occurs, an error message is printed
+ * via error() and NULL is returned. FILE and LINE are the filename
+ * and linenumber to include in the error message. FILE must point
+ * to something; LINE can be zero to indicate the line number is not
+ * known.
+ *
+ * When FORMATSAFE is set, percent signs (`%') in variable contents are doubled
+ * to prevent later expansion by format_cmdline.
+ *
+ * CVSROOT is used to expanding $CVSROOT.
+ */
+char *
+expand_path (const char *name, const char *cvsroot, bool formatsafe,
+ const char *file, int line)
+{
+ size_t s, d, p;
+ const char *e;
+
+ char *mybuf = NULL;
+ size_t mybuf_size = 0;
+ char *buf = NULL;
+ size_t buf_size = 0;
+
+ char inquotes = '\0';
+
+ char *result;
+
+ /* Sorry this routine is so ugly; it is a head-on collision
+ between the `traditional' unix *d++ style and the need to
+ dynamically allocate. It would be much cleaner (and probably
+ faster, not that this is a bottleneck for CVS) with more use of
+ strcpy & friends, but I haven't taken the effort to rewrite it
+ thusly. */
+
+ /* First copy from NAME to MYBUF, expanding $<foo> as we go. */
+ s = d = 0;
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ while ((mybuf[d++] = name[s]) != '\0')
+ {
+ if (name[s] == '\\')
+ {
+ /* The next character is a literal. Leave the \ in the string
+ * since it will be needed again when the string is split into
+ * arguments.
+ */
+ /* if we have a \ as the last character of the string, just leave
+ * it there - this is where we would set the escape flag to tell
+ * our parent we want another line if we cared.
+ */
+ if (name[++s])
+ {
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ mybuf[d++] = name[s++];
+ }
+ }
+ /* skip $ variable processing for text inside single quotes */
+ else if (inquotes == '\'')
+ {
+ if (name[s++] == '\'')
+ {
+ inquotes = '\0';
+ }
+ }
+ else if (name[s] == '\'')
+ {
+ s++;
+ inquotes = '\'';
+ }
+ else if (name[s] == '"')
+ {
+ s++;
+ if (inquotes) inquotes = '\0';
+ else inquotes = '"';
+ }
+ else if (name[s++] == '$')
+ {
+ int flag = (name[s] == '{');
+ p = d;
+
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ for (; (mybuf[d++] = name[s]); s++)
+ {
+ if (flag
+ ? name[s] =='}'
+ : !isalnum (name[s]) && name[s] != '_')
+ break;
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ }
+ mybuf[--d] = '\0';
+ e = expand_variable (&mybuf[p+flag], cvsroot, file, line);
+
+ if (e)
+ {
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ for (d = p - 1; (mybuf[d++] = *e++); )
+ {
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ if (mybuf[d-1] == '"')
+ {
+ /* escape the double quotes if we're between a matched
+ * pair of double quotes so that this sub will be
+ * passed inside as or as part of a single argument
+ * during the argument split later.
+ */
+ if (inquotes)
+ {
+ mybuf[d-1] = '\\';
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ mybuf[d++] = '"';
+ }
+ }
+ else if (formatsafe && mybuf[d-1] == '%')
+ {
+ /* escape '%' to get past printf style format strings
+ * later (in make_cmdline).
+ */
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ mybuf[d] = '%';
+ d++;
+ }
+ }
+ --d;
+ if (flag && name[s])
+ s++;
+ }
+ else
+ /* expand_variable has already printed an error message. */
+ goto error_exit;
+ }
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ }
+ expand_string (&mybuf, &mybuf_size, d + 1);
+ mybuf[d] = '\0';
+
+ /* Then copy from MYBUF to BUF, expanding ~. */
+ s = d = 0;
+ /* If you don't want ~username ~/ to be expanded simply remove
+ * This entire if statement including the else portion
+ */
+ if (mybuf[s] == '~')
+ {
+ p = d;
+ while (mybuf[++s] != '/' && mybuf[s] != '\0')
+ {
+ expand_string (&buf, &buf_size, p + 1);
+ buf[p++] = name[s];
+ }
+ expand_string (&buf, &buf_size, p + 1);
+ buf[p] = '\0';
+
+ if (p == d)
+ e = get_homedir ();
+ else
+ {
+#ifdef GETPWNAM_MISSING
+ if (line)
+ error (0, 0,
+ "%s:%d:tilde expansion not supported on this system",
+ file, line);
+ else
+ error (0, 0, "%s:tilde expansion not supported on this system",
+ file);
+ goto error_exit;
+#else
+ struct passwd *ps;
+ ps = getpwnam (buf + d);
+ if (ps == NULL)
+ {
+ if (line)
+ error (0, 0, "%s:%d: no such user %s",
+ file, line, buf + d);
+ else
+ error (0, 0, "%s: no such user %s", file, buf + d);
+ goto error_exit;
+ }
+ e = ps->pw_dir;
+#endif
+ }
+ if (!e)
+ error (1, 0, "cannot find home directory");
+
+ p = strlen (e);
+ expand_string (&buf, &buf_size, d + p);
+ memcpy (buf + d, e, p);
+ d += p;
+ }
+ /* Kill up to here */
+ p = strlen (mybuf + s) + 1;
+ expand_string (&buf, &buf_size, d + p);
+ memcpy (buf + d, mybuf + s, p);
+
+ /* OK, buf contains the value we want to return. Clean up and return
+ it. */
+ free (mybuf);
+ /* Save a little memory with xstrdup; buf will tend to allocate
+ more than it needs to. */
+ result = xstrdup (buf);
+ free (buf);
+ return result;
+
+ error_exit:
+ if (mybuf) free (mybuf);
+ if (buf) free (buf);
+ return NULL;
+}
diff --git a/src/fileattr.c b/src/fileattr.c
new file mode 100644
index 0000000..26794bb
--- /dev/null
+++ b/src/fileattr.c
@@ -0,0 +1,695 @@
+/* Implementation for file attribute munging features.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+#include "getline.h"
+#include "fileattr.h"
+
+static void fileattr_read (void);
+static int writeattr_proc (Node *, void *);
+
+/* Where to look for CVSREP_FILEATTR. */
+static char *fileattr_stored_repos;
+
+/* The in-memory attributes. */
+static List *attrlist;
+static char *fileattr_default_attrs;
+/* We have already tried to read attributes and failed in this directory
+ (for example, there is no CVSREP_FILEATTR file). */
+static int attr_read_attempted;
+
+/* Have the in-memory attributes been modified since we read them? */
+static int attrs_modified;
+
+/* More in-memory attributes: linked list of unrecognized
+ fileattr lines. We pass these on unchanged. */
+struct unrecog {
+ char *line;
+ struct unrecog *next;
+};
+static struct unrecog *unrecog_head;
+
+
+
+/* Note that if noone calls fileattr_get, this is very cheap. No stat(),
+ no open(), no nothing. */
+void
+fileattr_startdir (const char *repos)
+{
+ assert (fileattr_stored_repos == NULL);
+ fileattr_stored_repos = xstrdup (repos);
+ assert (attrlist == NULL);
+ attr_read_attempted = 0;
+ assert (unrecog_head == NULL);
+}
+
+
+
+static void
+fileattr_delproc (Node *node)
+{
+ assert (node->data != NULL);
+ free (node->data);
+ node->data = NULL;
+}
+
+/* Read all the attributes for the current directory into memory. */
+static void
+fileattr_read (void)
+{
+ char *fname;
+ FILE *fp;
+ char *line = NULL;
+ size_t line_len = 0;
+
+ /* If there are no attributes, don't waste time repeatedly looking
+ for the CVSREP_FILEATTR file. */
+ if (attr_read_attempted)
+ return;
+
+ /* If NULL was passed to fileattr_startdir, then it isn't kosher to look
+ at attributes. */
+ assert (fileattr_stored_repos != NULL);
+
+ fname = Xasprintf ("%s/%s", fileattr_stored_repos, CVSREP_FILEATTR);
+
+ attr_read_attempted = 1;
+ fp = CVS_FOPEN (fname, FOPEN_BINARY_READ);
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot read %s", fname);
+ free (fname);
+ return;
+ }
+ attrlist = getlist ();
+ while (1) {
+ int nread;
+ nread = getline (&line, &line_len, fp);
+ if (nread < 0)
+ break;
+ /* Remove trailing newline.
+ * It is okay to reference line[nread - 1] here, since getline must
+ * always return 1 character or EOF, but we need to verify that the
+ * character we eat is the newline, since getline can return a line
+ * w/o a newline just before returning EOF.
+ */
+ if (line[nread - 1] == '\n') line[nread - 1] = '\0';
+ if (line[0] == 'F')
+ {
+ char *p;
+ Node *newnode;
+
+ p = strchr (line, '\t');
+ if (p == NULL)
+ error (1, 0,
+ "file attribute database corruption: tab missing in %s",
+ primary_root_inverse_translate (fname));
+ *p++ = '\0';
+ newnode = getnode ();
+ newnode->type = FILEATTR;
+ newnode->delproc = fileattr_delproc;
+ newnode->key = xstrdup (line + 1);
+ newnode->data = xstrdup (p);
+ if (addnode (attrlist, newnode) != 0)
+ /* If the same filename appears twice in the file, discard
+ any line other than the first for that filename. This
+ is the way that CVS has behaved since file attributes
+ were first introduced. */
+ freenode (newnode);
+ }
+ else if (line[0] == 'D')
+ {
+ char *p;
+ /* Currently nothing to skip here, but for future expansion,
+ ignore anything located here. */
+ p = strchr (line, '\t');
+ if (p == NULL)
+ error (1, 0,
+ "file attribute database corruption: tab missing in %s",
+ fname);
+ ++p;
+ if (fileattr_default_attrs) free (fileattr_default_attrs);
+ fileattr_default_attrs = xstrdup (p);
+ }
+ else
+ {
+ /* Unrecognized type, we want to just preserve the line without
+ changing it, for future expansion. */
+ struct unrecog *new;
+
+ new = xmalloc (sizeof (struct unrecog));
+ new->line = xstrdup (line);
+ new->next = unrecog_head;
+ unrecog_head = new;
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", fname);
+ if (line != NULL)
+ free (line);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", fname);
+ attrs_modified = 0;
+ free (fname);
+}
+
+
+
+char *
+fileattr_get (const char *filename, const char *attrname)
+{
+ Node *node;
+ size_t attrname_len = strlen (attrname);
+ char *p;
+
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ /* Either nothing has any attributes, or fileattr_read already printed
+ an error message. */
+ return NULL;
+
+ if (filename == NULL)
+ p = fileattr_default_attrs;
+ else
+ {
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ /* A file not mentioned has no attributes. */
+ return NULL;
+ p = node->data;
+ }
+ while (p)
+ {
+ if (strncmp (attrname, p, attrname_len) == 0
+ && p[attrname_len] == '=')
+ {
+ /* Found it. */
+ return p + attrname_len + 1;
+ }
+ p = strchr (p, ';');
+ if (p == NULL)
+ break;
+ ++p;
+ }
+ /* The file doesn't have this attribute. */
+ return NULL;
+}
+
+
+
+char *
+fileattr_get0 (const char *filename, const char *attrname)
+{
+ char *cp;
+ char *cpend;
+ char *retval;
+
+ cp = fileattr_get (filename, attrname);
+ if (cp == NULL)
+ return NULL;
+ cpend = strchr (cp, ';');
+ if (cpend == NULL)
+ cpend = cp + strlen (cp);
+ retval = xmalloc (cpend - cp + 1);
+ strncpy (retval, cp, cpend - cp);
+ retval[cpend - cp] = '\0';
+ return retval;
+}
+
+
+
+char *
+fileattr_modify (char *list, const char *attrname, const char *attrval, int namevalsep, int entsep)
+{
+ char *retval;
+ char *rp;
+ size_t attrname_len = strlen (attrname);
+
+ /* Portion of list before the attribute to be replaced. */
+ char *pre;
+ char *preend;
+ /* Portion of list after the attribute to be replaced. */
+ char *post;
+
+ char *p;
+ char *p2;
+
+ p = list;
+ pre = list;
+ preend = NULL;
+ /* post is NULL unless set otherwise. */
+ post = NULL;
+ p2 = NULL;
+ if (list != NULL)
+ {
+ while (1) {
+ p2 = strchr (p, entsep);
+ if (p2 == NULL)
+ {
+ p2 = p + strlen (p);
+ if (preend == NULL)
+ preend = p2;
+ }
+ else
+ ++p2;
+ if (strncmp (attrname, p, attrname_len) == 0
+ && p[attrname_len] == namevalsep)
+ {
+ /* Found it. */
+ preend = p;
+ if (preend > list)
+ /* Don't include the preceding entsep. */
+ --preend;
+
+ post = p2;
+ }
+ if (p2[0] == '\0')
+ break;
+ p = p2;
+ }
+ }
+ if (post == NULL)
+ post = p2;
+
+ if (preend == pre && attrval == NULL && post == p2)
+ return NULL;
+
+ retval = xmalloc ((preend - pre)
+ + 1
+ + (attrval == NULL ? 0 : (attrname_len + 1
+ + strlen (attrval)))
+ + 1
+ + (p2 - post)
+ + 1);
+ if (preend != pre)
+ {
+ strncpy (retval, pre, preend - pre);
+ rp = retval + (preend - pre);
+ if (attrval != NULL)
+ *rp++ = entsep;
+ *rp = '\0';
+ }
+ else
+ retval[0] = '\0';
+ if (attrval != NULL)
+ {
+ strcat (retval, attrname);
+ rp = retval + strlen (retval);
+ *rp++ = namevalsep;
+ strcpy (rp, attrval);
+ }
+ if (post != p2)
+ {
+ rp = retval + strlen (retval);
+ if (preend != pre || attrval != NULL)
+ *rp++ = entsep;
+ strncpy (rp, post, p2 - post);
+ rp += p2 - post;
+ *rp = '\0';
+ }
+ return retval;
+}
+
+void
+fileattr_set (const char *filename, const char *attrname, const char *attrval)
+{
+ Node *node;
+ char *p;
+
+ if (filename == NULL)
+ {
+ p = fileattr_modify (fileattr_default_attrs, attrname, attrval,
+ '=', ';');
+ if (fileattr_default_attrs != NULL)
+ free (fileattr_default_attrs);
+ fileattr_default_attrs = p;
+ attrs_modified = 1;
+ return;
+ }
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ {
+ /* Not sure this is a graceful way to handle things
+ in the case where fileattr_read was unable to read the file. */
+ /* No attributes existed previously. */
+ attrlist = getlist ();
+ }
+
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ {
+ if (attrval == NULL)
+ /* Attempt to remove an attribute which wasn't there. */
+ return;
+
+ /* First attribute for this file. */
+ node = getnode ();
+ node->type = FILEATTR;
+ node->delproc = fileattr_delproc;
+ node->key = xstrdup (filename);
+ node->data = Xasprintf ("%s=%s", attrname, attrval);
+ addnode (attrlist, node);
+ }
+
+ p = fileattr_modify (node->data, attrname, attrval, '=', ';');
+ if (p == NULL)
+ delnode (node);
+ else
+ {
+ free (node->data);
+ node->data = p;
+ }
+
+ attrs_modified = 1;
+}
+
+
+
+char *
+fileattr_getall (const char *filename)
+{
+ Node *node;
+ char *p;
+
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ /* Either nothing has any attributes, or fileattr_read already printed
+ an error message. */
+ return NULL;
+
+ if (filename == NULL)
+ p = fileattr_default_attrs;
+ else
+ {
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ /* A file not mentioned has no attributes. */
+ return NULL;
+ p = node->data;
+ }
+ return xstrdup (p);
+}
+
+
+
+void
+fileattr_setall (const char *filename, const char *attrs)
+{
+ Node *node;
+
+ if (filename == NULL)
+ {
+ if (fileattr_default_attrs != NULL)
+ free (fileattr_default_attrs);
+ fileattr_default_attrs = xstrdup (attrs);
+ attrs_modified = 1;
+ return;
+ }
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ {
+ /* Not sure this is a graceful way to handle things
+ in the case where fileattr_read was unable to read the file. */
+ /* No attributes existed previously. */
+ attrlist = getlist ();
+ }
+
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ {
+ /* The file had no attributes. Add them if we have any to add. */
+ if (attrs != NULL)
+ {
+ node = getnode ();
+ node->type = FILEATTR;
+ node->delproc = fileattr_delproc;
+ node->key = xstrdup (filename);
+ node->data = xstrdup (attrs);
+ addnode (attrlist, node);
+ }
+ }
+ else
+ {
+ if (attrs == NULL)
+ delnode (node);
+ else
+ {
+ free (node->data);
+ node->data = xstrdup (attrs);
+ }
+ }
+
+ attrs_modified = 1;
+}
+
+
+
+void
+fileattr_newfile (const char *filename)
+{
+ Node *node;
+
+ if (attrlist == NULL)
+ fileattr_read ();
+
+ if (fileattr_default_attrs == NULL)
+ return;
+
+ if (attrlist == NULL)
+ {
+ /* Not sure this is a graceful way to handle things
+ in the case where fileattr_read was unable to read the file. */
+ /* No attributes existed previously. */
+ attrlist = getlist ();
+ }
+
+ node = getnode ();
+ node->type = FILEATTR;
+ node->delproc = fileattr_delproc;
+ node->key = xstrdup (filename);
+ node->data = xstrdup (fileattr_default_attrs);
+ addnode (attrlist, node);
+ attrs_modified = 1;
+}
+
+
+
+static int
+writeattr_proc (Node *node, void *data)
+{
+ FILE *fp = (FILE *)data;
+ fputs ("F", fp);
+ fputs (node->key, fp);
+ fputs ("\t", fp);
+ fputs (node->data, fp);
+ fputs ("\012", fp);
+ return 0;
+}
+
+
+
+/*
+ * callback proc to run a script when fileattrs are updated.
+ */
+static int
+postwatch_proc (const char *repository, const char *filter, void *closure)
+{
+ char *cmdline;
+ const char *srepos = Short_Repository (repository);
+
+ TRACE (TRACE_FUNCTION, "postwatch_proc (%s, %s)", repository, filter);
+
+ /* %c = command name
+ * %p = shortrepos
+ * %r = repository
+ */
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ false, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s", current_parsed_root->directory,
+ (char *) NULL);
+
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ error (0, 0, "postwatch proc resolved to the empty string!");
+ return 1;
+ }
+
+ run_setup (cmdline);
+
+ free (cmdline);
+
+ /* FIXME - read the comment in verifymsg_proc() about why we use abs()
+ * below() and shouldn't.
+ */
+ return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_NORMAL | RUN_SIGIGNORE));
+}
+
+
+
+void
+fileattr_write (void)
+{
+ FILE *fp;
+ char *fname;
+ mode_t omask;
+ struct unrecog *p;
+
+ if (!attrs_modified)
+ return;
+
+ if (noexec)
+ return;
+
+ /* If NULL was passed to fileattr_startdir, then it isn't kosher to set
+ attributes. */
+ assert (fileattr_stored_repos != NULL);
+
+ fname = Xasprintf ("%s/%s", fileattr_stored_repos, CVSREP_FILEATTR);
+
+ if (list_isempty (attrlist)
+ && fileattr_default_attrs == NULL
+ && unrecog_head == NULL)
+ {
+ /* There are no attributes. */
+ if (unlink_file (fname) < 0)
+ {
+ if (!existence_error (errno))
+ {
+ error (0, errno, "cannot remove %s", fname);
+ }
+ }
+
+ /* Now remove CVSREP directory, if empty. The main reason we bother
+ is that CVS 1.6 and earlier will choke if a CVSREP directory
+ exists, so provide the user a graceful way to remove it. */
+ strcpy (fname, fileattr_stored_repos);
+ strcat (fname, "/");
+ strcat (fname, CVSREP);
+ if (CVS_RMDIR (fname) < 0)
+ {
+ if (errno != ENOTEMPTY
+
+ /* Don't know why we would be here if there is no CVSREP
+ directory, but it seemed to be happening anyway, so
+ check for it. */
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", fname);
+ }
+
+ free (fname);
+ return;
+ }
+
+ omask = umask (cvsumask);
+ fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
+ if (fp == NULL)
+ {
+ if (existence_error (errno))
+ {
+ /* Maybe the CVSREP directory doesn't exist. Try creating it. */
+ char *repname;
+
+ repname = Xasprintf ("%s/%s", fileattr_stored_repos, CVSREP);
+
+ if (CVS_MKDIR (repname, 0777) < 0 && errno != EEXIST)
+ {
+ error (0, errno, "cannot make directory %s", repname);
+ (void) umask (omask);
+ free (fname);
+ free (repname);
+ return;
+ }
+ free (repname);
+
+ fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
+ }
+ if (fp == NULL)
+ {
+ error (0, errno, "cannot write %s", fname);
+ (void) umask (omask);
+ free (fname);
+ return;
+ }
+ }
+ (void) umask (omask);
+
+ /* First write the "F" attributes. */
+ walklist (attrlist, writeattr_proc, fp);
+
+ /* Then the "D" attribute. */
+ if (fileattr_default_attrs != NULL)
+ {
+ fputs ("D\t", fp);
+ fputs (fileattr_default_attrs, fp);
+ fputs ("\012", fp);
+ }
+
+ /* Then any other attributes. */
+ for (p = unrecog_head; p != NULL; p = p->next)
+ {
+ fputs (p->line, fp);
+ fputs ("\012", fp);
+ }
+
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", fname);
+ attrs_modified = 0;
+ free (fname);
+
+ Parse_Info (CVSROOTADM_POSTWATCH, fileattr_stored_repos, postwatch_proc,
+ PIOPT_ALL, NULL);
+}
+
+
+
+void
+fileattr_free (void)
+{
+ /* Note that attrs_modified will ordinarily be zero, but there are
+ a few cases in which fileattr_write will fail to zero it (if
+ noexec is set, or error conditions). This probably is the way
+ it should be. */
+ dellist (&attrlist);
+ if (fileattr_stored_repos != NULL)
+ free (fileattr_stored_repos);
+ fileattr_stored_repos = NULL;
+ if (fileattr_default_attrs != NULL)
+ free (fileattr_default_attrs);
+ fileattr_default_attrs = NULL;
+ while (unrecog_head)
+ {
+ struct unrecog *p = unrecog_head;
+ unrecog_head = p->next;
+ free (p->line);
+ free (p);
+ }
+}
diff --git a/src/fileattr.h b/src/fileattr.h
new file mode 100644
index 0000000..4ce8233
--- /dev/null
+++ b/src/fileattr.h
@@ -0,0 +1,136 @@
+/* Declarations for file attribute munging features.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifndef FILEATTR_H
+
+/* File containing per-file attributes. The format of this file is in
+ cvs.texinfo but here is a quick summary. The file contains a
+ series of entries:
+
+ ENT-TYPE FILENAME <tab> ATTRNAME = ATTRVAL
+ {; ATTRNAME = ATTRVAL} <linefeed>
+
+ ENT-TYPE is 'F' for a file.
+
+ ENT-TYPE is 'D', and FILENAME empty, for default attributes.
+
+ Other ENT-TYPE are reserved for future expansion.
+
+ Note that the order of the line is not significant; CVS is free to
+ rearrange them at its convenience.
+
+ FIXME: this implementation doesn't handle '\0' in any of the
+ fields. We are encouraged to fix this (by cvs.texinfo).
+
+ By convention, ATTRNAME starting with '_' is for an attribute given
+ special meaning by CVS; other ATTRNAMEs are for user-defined attributes
+ (or will be, once we add commands to manipulate user-defined attributes).
+
+ Builtin attributes:
+
+ _watched: Present means the file is watched and should be checked out
+ read-only.
+
+ _watchers: Users with watches for this file. Value is
+ WATCHER > TYPE { , WATCHER > TYPE }
+ where WATCHER is a username, and TYPE is edit,unedit,commit separated by
+ + (or nothing if none; there is no "none" or "all" keyword).
+
+ _editors: Users editing this file. Value is
+ EDITOR > VAL { , EDITOR > VAL }
+ where EDITOR is a username, and VAL is TIME+HOSTNAME+PATHNAME, where
+ TIME is when the "cvs edit" command happened,
+ and HOSTNAME and PATHNAME are for the working directory. */
+
+#define CVSREP_FILEATTR "CVS/fileattr"
+
+/* Prepare for a new directory with repository REPOS. If REPOS is NULL,
+ then prepare for a "non-directory"; the caller can call fileattr_write
+ and fileattr_free, but must not call fileattr_get or fileattr_set. */
+extern void fileattr_startdir (const char *repos);
+
+/* Get the attribute ATTRNAME for file FILENAME. The return value
+ points into memory managed by the fileattr_* routines, should not
+ be altered by the caller, and is only good until the next call to
+ fileattr_clear or fileattr_set. It points to the value, terminated
+ by '\0' or ';'. Return NULL if said file lacks said attribute.
+ If FILENAME is NULL, return default attributes (attributes for
+ files created in the future). */
+extern char *fileattr_get (const char *filename, const char *attrname);
+
+/* Like fileattr_get, but return a pointer to a newly malloc'd string
+ terminated by '\0' (or NULL if said file lacks said attribute). */
+extern char *fileattr_get0 (const char *filename,
+ const char *attrname);
+
+/* This is just a string manipulation function; it does not manipulate
+ file attributes as such.
+
+ LIST is in the format
+
+ ATTRNAME NAMEVALSEP ATTRVAL {ENTSEP ATTRNAME NAMEVALSEP ATTRVAL}
+
+ And we want to put in an attribute with name NAME and value VAL,
+ replacing the already-present attribute with name NAME if there is
+ one. Or if VAL is NULL remove attribute NAME. Return a new
+ malloc'd list; don't muck with the one passed in. If we are removing
+ the last attribute return NULL. LIST can be NULL to mean that we
+ started out without any attributes.
+
+ Examples:
+
+ fileattr_modify ("abc=def", "xxx", "val", '=', ';')) => "abc=def;xxx=val"
+ fileattr_modify ("abc=def", "abc", "val", '=', ';')) => "abc=val"
+ fileattr_modify ("abc=v1;def=v2", "abc", "val", '=', ';'))
+ => "abc=val;def=v2"
+ fileattr_modify ("abc=v1;def=v2", "def", "val", '=', ';'))
+ => "abc=v1;def=val"
+ fileattr_modify ("abc=v1;def=v2", "xxx", "val", '=', ';'))
+ => "abc=v1;def=v2;xxx=val"
+ fileattr_modify ("abc=v1;def=v2;ghi=v3", "def", "val", '=', ';'))
+ => "abc=v1;def=val;ghi=v3"
+*/
+
+extern char *fileattr_modify (char *list, const char *attrname,
+ const char *attrval, int namevalsep,
+ int entsep);
+
+/* Set attribute ATTRNAME for file FILENAME to ATTRVAL. If ATTRVAL is NULL,
+ the attribute is removed. Changes are not written to disk until the
+ next call to fileattr_write. If FILENAME is NULL, set attributes for
+ files created in the future. If ATTRVAL is NULL, remove that attribute. */
+extern void fileattr_set (const char *filename, const char *attrname,
+ const char *attrval);
+
+/* Get all the attributes for file FILENAME. They are returned as malloc'd
+ data in an unspecified format which is guaranteed only to be good for
+ passing to fileattr_setall, or NULL if no attributes. If FILENAME is
+ NULL, get default attributes. */
+extern char *fileattr_getall (const char *filename);
+
+/* Set the attributes for file FILENAME to ATTRS, overwriting all previous
+ attributes for that file. ATTRS was obtained from a previous call to
+ fileattr_getall (malloc'd data or NULL). */
+extern void fileattr_setall (const char *filename, const char *attrs);
+
+/* Set the attributes for file FILENAME in whatever manner is appropriate
+ for a newly created file. */
+extern void fileattr_newfile (const char *filename);
+
+/* Write out all modified attributes. */
+extern void fileattr_write (void);
+
+/* Free all memory allocated by fileattr_*. */
+extern void fileattr_free (void);
+
+#define FILEATTR_H 1
+#endif /* fileattr.h */
diff --git a/src/filesubr.c b/src/filesubr.c
new file mode 100644
index 0000000..64e9f4b
--- /dev/null
+++ b/src/filesubr.c
@@ -0,0 +1,878 @@
+/* filesubr.c --- subroutines for dealing with files
+ Jim Blandy <jimb@cyclic.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* These functions were moved out of subr.c because they need different
+ definitions under operating systems (like, say, Windows NT) with different
+ file system semantics. */
+
+#include "cvs.h"
+#include "lstat.h"
+#include "save-cwd.h"
+#include "xsize.h"
+
+static int deep_remove_dir (const char *path);
+
+/*
+ * Copies "from" to "to".
+ */
+void
+copy_file (const char *from, const char *to)
+{
+ struct stat sb;
+ struct utimbuf t;
+ int fdin, fdout;
+ ssize_t rsize;
+
+ TRACE (TRACE_FUNCTION, "copy(%s,%s)", from, to);
+
+ if (noexec)
+ return;
+
+ /* If the file to be copied is a link or a device, then just create
+ the new link or device appropriately. */
+ if ((rsize = islink (from)) > 0)
+ {
+ char *source = Xreadlink (from, rsize);
+ symlink (source, to);
+ free (source);
+ return;
+ }
+
+ if (isdevice (from))
+ {
+#if defined(HAVE_MKNOD) && defined(HAVE_STRUCT_STAT_ST_RDEV)
+ if (stat (from, &sb) < 0)
+ error (1, errno, "cannot stat %s", from);
+ mknod (to, sb.st_mode, sb.st_rdev);
+#else
+ error (1, 0, "cannot copy device files on this system (%s)", from);
+#endif
+ }
+ else
+ {
+ /* Not a link or a device... probably a regular file. */
+ if ((fdin = open (from, O_RDONLY)) < 0)
+ error (1, errno, "cannot open %s for copying", from);
+ if (fstat (fdin, &sb) < 0)
+ error (1, errno, "cannot fstat %s", from);
+ if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
+ error (1, errno, "cannot create %s for copying", to);
+ if (sb.st_size > 0)
+ {
+ char buf[BUFSIZ];
+ int n;
+
+ for (;;)
+ {
+ n = read (fdin, buf, sizeof(buf));
+ if (n == -1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ error (1, errno, "cannot read file %s for copying", from);
+ }
+ else if (n == 0)
+ break;
+
+ if (write(fdout, buf, n) != n) {
+ error (1, errno, "cannot write file %s for copying", to);
+ }
+ }
+ }
+
+ if (close (fdin) < 0)
+ error (0, errno, "cannot close %s", from);
+ if (close (fdout) < 0)
+ error (1, errno, "cannot close %s", to);
+ }
+
+ /* preserve last access & modification times */
+ memset ((char *) &t, 0, sizeof (t));
+ t.actime = sb.st_atime;
+ t.modtime = sb.st_mtime;
+ (void) utime (to, &t);
+}
+
+
+
+/* FIXME-krp: these functions would benefit from caching the char * &
+ stat buf. */
+
+/*
+ * Returns true if the argument file is a directory, or is a symbolic
+ * link which points to a directory.
+ */
+bool
+isdir (const char *file)
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return false;
+ return S_ISDIR (sb.st_mode);
+}
+
+
+
+/*
+ * Returns 0 if the argument file is not a symbolic link.
+ * Returns size of the link if it is a symbolic link.
+ */
+ssize_t
+islink (const char *file)
+{
+ ssize_t retsize = 0;
+#ifdef S_ISLNK
+ struct stat sb;
+
+ if ((lstat (file, &sb) >= 0) && S_ISLNK (sb.st_mode))
+ retsize = sb.st_size;
+#endif
+ return retsize;
+}
+
+
+
+/*
+ * Returns true if the argument file is a block or
+ * character special device.
+ */
+bool
+isdevice (const char *file)
+{
+ struct stat sb;
+
+ if (lstat (file, &sb) < 0)
+ return false;
+#ifdef S_ISBLK
+ if (S_ISBLK (sb.st_mode))
+ return true;
+#endif
+#ifdef S_ISCHR
+ if (S_ISCHR (sb.st_mode))
+ return true;
+#endif
+ return false;
+}
+
+
+
+/*
+ * Returns true if the argument file exists.
+ */
+bool
+isfile (const char *file)
+{
+ return isaccessible (file, F_OK);
+}
+
+
+
+/*
+ * Returns non-zero if the argument file is readable.
+ */
+bool
+isreadable (const char *file)
+{
+ return isaccessible (file, R_OK);
+}
+
+
+
+/*
+ * Returns non-zero if the argument file is writable.
+ */
+bool
+iswritable (const char *file)
+{
+ return isaccessible (file, W_OK);
+}
+
+
+
+/*
+ * Returns true if the argument file is accessable according to
+ * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
+ * bits set.
+ */
+bool
+isaccessible (const char *file, const int mode)
+{
+#ifdef SETXID_SUPPORT
+ struct stat sb;
+ int umask = 0;
+ int gmask = 0;
+ int omask = 0;
+ int uid, mask;
+
+ if (stat (file, &sb)== -1)
+ return false;
+ if (mode == F_OK)
+ return true;
+
+ uid = geteuid();
+ if (uid == 0) /* superuser */
+ {
+ if (!(mode & X_OK) || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
+ return true;
+
+ errno = EACCES;
+ return false;
+ }
+
+ if (mode & R_OK)
+ {
+ umask |= S_IRUSR;
+ gmask |= S_IRGRP;
+ omask |= S_IROTH;
+ }
+ if (mode & W_OK)
+ {
+ umask |= S_IWUSR;
+ gmask |= S_IWGRP;
+ omask |= S_IWOTH;
+ }
+ if (mode & X_OK)
+ {
+ umask |= S_IXUSR;
+ gmask |= S_IXGRP;
+ omask |= S_IXOTH;
+ }
+
+ mask = sb.st_uid == uid ? umask : sb.st_gid == getegid() ? gmask : omask;
+ if ((sb.st_mode & mask) == mask)
+ return true;
+ errno = EACCES;
+ return false;
+#else /* !SETXID_SUPPORT */
+ return access (file, mode) == 0;
+#endif /* SETXID_SUPPORT */
+}
+
+
+
+/*
+ * Make a directory and die if it fails
+ */
+void
+make_directory (const char *name)
+{
+ struct stat sb;
+
+ if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
+ error (0, 0, "%s already exists but is not a directory", name);
+ if (!noexec && mkdir (name, 0777) < 0)
+ error (1, errno, "cannot make directory %s", name);
+}
+
+/*
+ * Make a path to the argument directory, printing a message if something
+ * goes wrong.
+ */
+void
+make_directories (const char *name)
+{
+ char *cp;
+
+ if (noexec)
+ return;
+
+ if (mkdir (name, 0777) == 0 || errno == EEXIST)
+ return;
+ if (! existence_error (errno))
+ {
+ error (0, errno, "cannot make path to %s", name);
+ return;
+ }
+ if ((cp = strrchr (name, '/')) == NULL)
+ return;
+ *cp = '\0';
+ make_directories (name);
+ *cp++ = '/';
+ if (*cp == '\0')
+ return;
+ (void) mkdir (name, 0777);
+}
+
+/* Create directory NAME if it does not already exist; fatal error for
+ other errors. Returns 0 if directory was created; 1 if it already
+ existed. */
+int
+mkdir_if_needed (const char *name)
+{
+ if (mkdir (name, 0777) < 0)
+ {
+ int save_errno = errno;
+ if (save_errno != EEXIST && !isdir (name))
+ error (1, save_errno, "cannot make directory %s", name);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Change the mode of a file, either adding write permissions, or removing
+ * all write permissions. Either change honors the current umask setting.
+ *
+ * Don't do anything if PreservePermissions is set to `yes'. This may
+ * have unexpected consequences for some uses of xchmod.
+ */
+void
+xchmod (const char *fname, int writable)
+{
+ struct stat sb;
+ mode_t mode, oumask;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (config->preserve_perms)
+ return;
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+
+ if (stat (fname, &sb) < 0)
+ {
+ if (!noexec)
+ error (0, errno, "cannot stat %s", fname);
+ return;
+ }
+ oumask = umask (0);
+ (void) umask (oumask);
+ if (writable)
+ {
+ mode = sb.st_mode | (~oumask
+ & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
+ | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
+ | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
+ }
+ else
+ {
+ mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
+ }
+
+ TRACE (TRACE_FUNCTION, "chmod(%s,%o)", fname, (unsigned int) mode);
+
+ if (noexec)
+ return;
+
+ if (chmod (fname, mode) < 0)
+ error (0, errno, "cannot change mode of file %s", fname);
+}
+
+/*
+ * Rename a file and die if it fails
+ */
+void
+rename_file (const char *from, const char *to)
+{
+ TRACE (TRACE_FUNCTION, "rename(%s,%s)", from, to);
+
+ if (noexec)
+ return;
+
+ if (rename (from, to) < 0)
+ error (1, errno, "cannot rename file %s to %s", from, to);
+}
+
+/*
+ * unlink a file, if possible.
+ */
+int
+unlink_file (const char *f)
+{
+ TRACE (TRACE_FUNCTION, "unlink_file(%s)", f);
+
+ if (noexec)
+ return (0);
+
+ return (CVS_UNLINK (f));
+}
+
+
+
+/*
+ * Unlink a file or dir, if possible. If it is a directory do a deep
+ * removal of all of the files in the directory. Return -1 on error
+ * (in which case errno is set).
+ */
+int
+unlink_file_dir (const char *f)
+{
+ struct stat sb;
+
+ /* This is called by the server parent process in contexts where
+ it is not OK to send output (e.g. after we sent "ok" to the
+ client). */
+ if (!server_active)
+ TRACE (TRACE_FUNCTION, "unlink_file_dir(%s)", f);
+
+ if (noexec)
+ return 0;
+
+ /* For at least some unices, if root tries to unlink() a directory,
+ instead of doing something rational like returning EISDIR,
+ the system will gleefully go ahead and corrupt the filesystem.
+ So we first call stat() to see if it is OK to call unlink(). This
+ doesn't quite work--if someone creates a directory between the
+ call to stat() and the call to unlink(), we'll still corrupt
+ the filesystem. Where is the Unix Haters Handbook when you need
+ it? */
+ if (stat (f, &sb) < 0)
+ {
+ if (existence_error (errno))
+ {
+ /* The file or directory doesn't exist anyhow. */
+ return -1;
+ }
+ }
+ else if (S_ISDIR (sb.st_mode))
+ return deep_remove_dir (f);
+
+ return CVS_UNLINK (f);
+}
+
+
+
+/* Remove a directory and everything it contains. Returns 0 for
+ * success, -1 for failure (in which case errno is set).
+ */
+
+static int
+deep_remove_dir (const char *path)
+{
+ DIR *dirp;
+ struct dirent *dp;
+
+ if (rmdir (path) != 0)
+ {
+ if (errno == ENOTEMPTY
+ || errno == EEXIST
+ /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug
+ (it defines ENOTEMPTY and EEXIST to 17 but actually
+ returns 87). */
+ || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
+ {
+ if ((dirp = CVS_OPENDIR (path)) == NULL)
+ /* If unable to open the directory return
+ * an error
+ */
+ return -1;
+
+ errno = 0;
+ while ((dp = CVS_READDIR (dirp)) != NULL)
+ {
+ char *buf;
+
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0)
+ continue;
+
+ buf = Xasprintf ("%s/%s", path, dp->d_name);
+
+ /* See comment in unlink_file_dir explanation of why we use
+ isdir instead of just calling unlink and checking the
+ status. */
+ if (isdir (buf))
+ {
+ if (deep_remove_dir (buf))
+ {
+ CVS_CLOSEDIR (dirp);
+ free (buf);
+ return -1;
+ }
+ }
+ else
+ {
+ if (CVS_UNLINK (buf) != 0)
+ {
+ CVS_CLOSEDIR (dirp);
+ free (buf);
+ return -1;
+ }
+ }
+ free (buf);
+
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ int save_errno = errno;
+ CVS_CLOSEDIR (dirp);
+ errno = save_errno;
+ return -1;
+ }
+ CVS_CLOSEDIR (dirp);
+ return rmdir (path);
+ }
+ else
+ return -1;
+ }
+
+ /* Was able to remove the directory return 0 */
+ return 0;
+}
+
+
+
+/* Read NCHARS bytes from descriptor FD into BUF.
+ Return the number of characters successfully read.
+ The number returned is always NCHARS unless end-of-file or error. */
+static size_t
+block_read (int fd, char *buf, size_t nchars)
+{
+ char *bp = buf;
+ size_t nread;
+
+ do
+ {
+ nread = read (fd, bp, nchars);
+ if (nread == (size_t)-1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ return (size_t)-1;
+ }
+
+ if (nread == 0)
+ break;
+
+ bp += nread;
+ nchars -= nread;
+ } while (nchars != 0);
+
+ return bp - buf;
+}
+
+
+/*
+ * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
+ * If FILE1 and FILE2 are special files, compare their salient characteristics
+ * (i.e. major/minor device numbers, links, etc.
+ */
+int
+xcmp (const char *file1, const char *file2)
+{
+ char *buf1, *buf2;
+ struct stat sb1, sb2;
+ int fd1, fd2;
+ int ret;
+
+ if (lstat (file1, &sb1) < 0)
+ error (1, errno, "cannot lstat %s", file1);
+ if (lstat (file2, &sb2) < 0)
+ error (1, errno, "cannot lstat %s", file2);
+
+ /* If FILE1 and FILE2 are not the same file type, they are unequal. */
+ if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT))
+ return 1;
+
+ /* If FILE1 and FILE2 are symlinks, they are equal if they point to
+ the same thing. */
+#ifdef S_ISLNK
+ if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode))
+ {
+ int result;
+ buf1 = Xreadlink (file1, sb1.st_size);
+ buf2 = Xreadlink (file2, sb2.st_size);
+ result = (strcmp (buf1, buf2) == 0);
+ free (buf1);
+ free (buf2);
+ return result;
+ }
+#endif
+
+ /* If FILE1 and FILE2 are devices, they are equal if their device
+ numbers match. */
+ if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode))
+ {
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+ if (sb1.st_rdev == sb2.st_rdev)
+ return 0;
+ else
+ return 1;
+#else
+ error (1, 0, "cannot compare device files on this system (%s and %s)",
+ file1, file2);
+#endif
+ }
+
+ if ((fd1 = open (file1, O_RDONLY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file1);
+ if ((fd2 = open (file2, O_RDONLY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file2);
+
+ /* A generic file compare routine might compare st_dev & st_ino here
+ to see if the two files being compared are actually the same file.
+ But that won't happen in CVS, so we won't bother. */
+
+ if (sb1.st_size != sb2.st_size)
+ ret = 1;
+ else if (sb1.st_size == 0)
+ ret = 0;
+ else
+ {
+ /* FIXME: compute the optimal buffer size by computing the least
+ common multiple of the files st_blocks field */
+ size_t buf_size = 8 * 1024;
+ size_t read1;
+ size_t read2;
+
+ buf1 = xmalloc (buf_size);
+ buf2 = xmalloc (buf_size);
+
+ do
+ {
+ read1 = block_read (fd1, buf1, buf_size);
+ if (read1 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file1);
+
+ read2 = block_read (fd2, buf2, buf_size);
+ if (read2 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file2);
+
+ /* assert (read1 == read2); */
+
+ ret = memcmp(buf1, buf2, read1);
+ } while (ret == 0 && read1 == buf_size);
+
+ free (buf1);
+ free (buf2);
+ }
+
+ (void) close (fd1);
+ (void) close (fd2);
+ return (ret);
+}
+
+/* Generate a unique temporary filename. Returns a pointer to a newly
+ * malloc'd string containing the name. Returns successfully or not at
+ * all.
+ *
+ * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!!
+ *
+ * and yes, I know about the way the rcs commands use temp files. I think
+ * they should be converted too but I don't have time to look into it right
+ * now.
+ */
+char *
+cvs_temp_name (void)
+{
+ char *fn;
+ FILE *fp;
+
+ fp = cvs_temp_file (&fn);
+ if (fp == NULL)
+ error (1, errno, "Failed to create temporary file");
+ if (fclose (fp) == EOF)
+ error (0, errno, "Failed to close temporary file %s", fn);
+ return fn;
+}
+
+/* Generate a unique temporary filename and return an open file stream
+ * to the truncated file by that name
+ *
+ * INPUTS
+ * filename where to place the pointer to the newly allocated file
+ * name string
+ *
+ * OUTPUTS
+ * filename dereferenced, will point to the newly allocated file
+ * name string. This value is undefined if the function
+ * returns an error.
+ *
+ * RETURNS
+ * An open file pointer to a read/write mode empty temporary file with the
+ * unique file name or NULL on failure.
+ *
+ * ERRORS
+ * On error, errno will be set to some value either by CVS_FOPEN or
+ * whatever system function is called to generate the temporary file name.
+ * The value of filename is undefined on error.
+ */
+FILE *
+cvs_temp_file (char **filename)
+{
+ char *fn;
+ FILE *fp;
+ int fd;
+
+ /* FIXME - I'd like to be returning NULL here in noexec mode, but I think
+ * some of the rcs & diff functions which rely on a temp file run in
+ * noexec mode too.
+ */
+
+ assert (filename != NULL);
+
+ fn = Xasprintf ("%s/%s", get_cvs_tmp_dir (), "cvsXXXXXX");
+ fd = mkstemp (fn);
+
+ /* a NULL return will be interpreted by callers as an error and
+ * errno should still be set
+ */
+ if (fd == -1)
+ fp = NULL;
+ else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL)
+ {
+ /* Attempt to close and unlink the file since mkstemp returned
+ * sucessfully and we believe it's been created and opened.
+ */
+ int save_errno = errno;
+ if (close (fd))
+ error (0, errno, "Failed to close temporary file %s", fn);
+ if (CVS_UNLINK (fn))
+ error (0, errno, "Failed to unlink temporary file %s", fn);
+ errno = save_errno;
+ }
+
+ if (fp == NULL)
+ free (fn);
+
+ /* mkstemp is defined to open mode 0600 using glibc 2.0.7+. There used
+ * to be a complicated #ifdef checking the library versions here and then
+ * a chmod 0600 on the temp file for versions of glibc less than 2.1. This
+ * is rather a special case, leaves a race condition open regardless, and
+ * one could hope that sysadmins have read the relevant security
+ * announcements and upgraded by now to a version with a fix committed in
+ * January of 1999.
+ *
+ * If it is decided at some point that old, buggy versions of glibc should
+ * still be catered to, a umask of 0600 should be set before file creation
+ * instead then reset after file creation since this would avoid the race
+ * condition that the chmod left open to exploitation.
+ */
+
+ *filename = fn;
+ return fp;
+}
+
+
+
+/* Return a pointer into PATH's last component. */
+const char *
+last_component (const char *path)
+{
+ const char *last = strrchr (path, '/');
+
+ if (last && (last != path))
+ return last + 1;
+ else
+ return path;
+}
+
+
+
+/* Return the home directory. Returns a pointer to storage
+ managed by this function or its callees (currently getenv).
+ This function will return the same thing every time it is
+ called. Returns NULL if there is no home directory.
+
+ Note that for a pserver server, this may return root's home
+ directory. What typically happens is that upon being started from
+ inetd, before switching users, the code in cvsrc.c calls
+ get_homedir which remembers root's home directory in the static
+ variable. Then the switch happens and get_homedir might return a
+ directory that we don't even have read or execute permissions for
+ (which is bad, when various parts of CVS try to read there). One
+ fix would be to make the value returned by get_homedir only good
+ until the next call (which would free the old value). Another fix
+ would be to just always malloc our answer, and let the caller free
+ it (that is best, because some day we may need to be reentrant).
+
+ The workaround is to put -f in inetd.conf which means that
+ get_homedir won't get called until after the switch in user ID.
+
+ The whole concept of a "home directory" on the server is pretty
+ iffy, although I suppose some people probably are relying on it for
+ .cvsrc and such, in the cases where it works. */
+char *
+get_homedir (void)
+{
+ static char *home = NULL;
+ char *env;
+ struct passwd *pw;
+
+ if (home != NULL)
+ return home;
+
+ if (!server_active && (env = getenv ("HOME")) != NULL)
+ home = env;
+ else if ((pw = (struct passwd *) getpwuid (getuid ()))
+ && pw->pw_dir)
+ home = xstrdup (pw->pw_dir);
+ else
+ return 0;
+
+ return home;
+}
+
+/* Compose a path to a file in the home directory. This is necessary because
+ * of different behavior on UNIX and VMS. See the notes in vms/filesubr.c.
+ *
+ * A more clean solution would be something more along the lines of a
+ * "join a directory to a filename" kind of thing which was not specific to
+ * the homedir. This should aid portability between UNIX, Mac, Windows, VMS,
+ * and possibly others. This is already handled by Perl - it might be
+ * interesting to see how much of the code was written in C since Perl is under
+ * the GPL and the Artistic license - we might be able to use it.
+ */
+char *
+strcat_filename_onto_homedir (const char *dir, const char *file)
+{
+ char *path = Xasprintf ("%s/%s", dir, file);
+ return path;
+}
+
+/* See cvs.h for description. On unix this does nothing, because the
+ shell expands the wildcards. */
+void
+expand_wild (int argc, char **argv, int *pargc, char ***pargv)
+{
+ int i;
+ if (size_overflow_p (xtimes (argc, sizeof (char *)))) {
+ *pargc = 0;
+ *pargv = NULL;
+ error (0, 0, "expand_wild: too many arguments");
+ return;
+ }
+ *pargc = argc;
+ *pargv = xnmalloc (argc, sizeof (char *));
+ for (i = 0; i < argc; ++i)
+ (*pargv)[i] = xstrdup (argv[i]);
+}
+
+
+
+static char *tmpdir_env;
+
+/* Return path to temp directory.
+ */
+const char *
+get_system_temp_dir (void)
+{
+ if (!tmpdir_env) tmpdir_env = getenv (TMPDIR_ENV);
+ return tmpdir_env;
+}
+
+
+
+void
+push_env_temp_dir (void)
+{
+ const char *tmpdir = get_cvs_tmp_dir ();
+ if (tmpdir_env && strcmp (tmpdir_env, tmpdir))
+ setenv (TMPDIR_ENV, tmpdir, 1);
+}
diff --git a/src/find_names.c b/src/find_names.c
new file mode 100644
index 0000000..22e25fd
--- /dev/null
+++ b/src/find_names.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Find Names
+ *
+ * Finds all the pertinent file names, both from the administration and from the
+ * repository
+ *
+ * Find Dirs
+ *
+ * Finds all pertinent sub-directories of the checked out instantiation and the
+ * repository (and optionally the attic)
+ */
+
+#include "cvs.h"
+#include <glob.h>
+#include <assert.h>
+
+static int find_dirs (char *dir, List * list, int checkadm,
+ List *entries);
+static int find_rcs (const char *dir, List * list);
+static int add_subdir_proc (Node *, void *);
+static int register_subdir_proc (Node *, void *);
+
+/*
+ * add the key from entry on entries list to the files list
+ */
+static int add_entries_proc (Node *, void *);
+static int
+add_entries_proc (Node *node, void *closure)
+{
+ Node *fnode;
+ List *filelist = closure;
+ Entnode *entnode = node->data;
+
+ if (entnode->type != ENT_FILE)
+ return (0);
+
+ fnode = getnode ();
+ fnode->type = FILES;
+ fnode->key = xstrdup (node->key);
+ if (addnode (filelist, fnode) != 0)
+ freenode (fnode);
+ return (0);
+}
+
+/* Find files in the repository and/or working directory. On error,
+ may either print a nonfatal error and return NULL, or just give
+ a fatal error. On success, return non-NULL (even if it is an empty
+ list). */
+
+List *
+Find_Names (char *repository, int which, int aflag, List **optentries)
+{
+ List *entries;
+ List *files;
+
+ /* make a list for the files */
+ files = getlist ();
+
+ /* look at entries (if necessary) */
+ if (which & W_LOCAL)
+ {
+ /* parse the entries file (if it exists) */
+ entries = Entries_Open (aflag, NULL);
+ if (entries != NULL)
+ {
+ /* walk the entries file adding elements to the files list */
+ (void) walklist (entries, add_entries_proc, files);
+
+ /* if our caller wanted the entries list, return it; else free it */
+ if (optentries != NULL)
+ *optentries = entries;
+ else
+ Entries_Close (entries);
+ }
+ }
+
+ if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
+ {
+ /* search the repository */
+ if (find_rcs (repository, files) != 0)
+ {
+ error (0, errno, "cannot open directory %s",
+ primary_root_inverse_translate (repository));
+ goto error_exit;
+ }
+
+ /* search the attic too */
+ if (which & W_ATTIC)
+ {
+ char *dir = Xasprintf ("%s/%s", repository, CVSATTIC);
+ if (find_rcs (dir, files) != 0
+ && !existence_error (errno))
+ /* For now keep this a fatal error, seems less useful
+ for access control than the case above. */
+ error (1, errno, "cannot open directory %s",
+ primary_root_inverse_translate (dir));
+ free (dir);
+ }
+ }
+
+ /* sort the list into alphabetical order and return it */
+ sortlist (files, fsortcmp);
+ return files;
+ error_exit:
+ dellist (&files);
+ return NULL;
+}
+
+/*
+ * Add an entry from the subdirs list to the directories list. This
+ * is called via walklist.
+ */
+
+static int
+add_subdir_proc (Node *p, void *closure)
+{
+ List *dirlist = closure;
+ Entnode *entnode = p->data;
+ Node *dnode;
+
+ if (entnode->type != ENT_SUBDIR)
+ return 0;
+
+ dnode = getnode ();
+ dnode->type = DIRS;
+ dnode->key = xstrdup (entnode->user);
+ if (addnode (dirlist, dnode) != 0)
+ freenode (dnode);
+ return 0;
+}
+
+/*
+ * Register a subdirectory. This is called via walklist.
+ */
+
+/*ARGSUSED*/
+static int
+register_subdir_proc (Node *p, void *closure)
+{
+ List *entries = (List *) closure;
+
+ Subdir_Register (entries, NULL, p->key);
+ return 0;
+}
+
+/*
+ * create a list of directories to traverse from the current directory
+ */
+List *
+Find_Directories (char *repository, int which, List *entries)
+{
+ List *dirlist;
+
+ /* make a list for the directories */
+ dirlist = getlist ();
+
+ /* find the local ones */
+ if (which & W_LOCAL)
+ {
+ List *tmpentries;
+ struct stickydirtag *sdtp;
+
+ /* Look through the Entries file. */
+
+ if (entries != NULL)
+ tmpentries = entries;
+ else if (isfile (CVSADM_ENT))
+ tmpentries = Entries_Open (0, NULL);
+ else
+ tmpentries = NULL;
+
+ if (tmpentries != NULL)
+ sdtp = tmpentries->list->data;
+
+ /* If we do have an entries list, then if sdtp is NULL, or if
+ sdtp->subdirs is nonzero, all subdirectory information is
+ recorded in the entries list. */
+ if (tmpentries != NULL && (sdtp == NULL || sdtp->subdirs))
+ walklist (tmpentries, add_subdir_proc, (void *) dirlist);
+ else
+ {
+ /* This is an old working directory, in which subdirectory
+ information is not recorded in the Entries file. Find
+ the subdirectories the hard way, and, if possible, add
+ it to the Entries file for next time. */
+
+ /* FIXME-maybe: find_dirs is bogus for this usage because
+ it skips CVSATTIC and CVSLCK directories--those names
+ should be special only in the repository. However, in
+ the interests of not perturbing this code, we probably
+ should leave well enough alone unless we want to write
+ a sanity.sh test case (which would operate by manually
+ hacking on the CVS/Entries file). */
+
+ if (find_dirs (".", dirlist, 1, tmpentries) != 0)
+ error (1, errno, "cannot open current directory");
+ if (tmpentries != NULL)
+ {
+ if (! list_isempty (dirlist))
+ walklist (dirlist, register_subdir_proc,
+ (void *) tmpentries);
+ else
+ Subdirs_Known (tmpentries);
+ }
+ }
+
+ if (entries == NULL && tmpentries != NULL)
+ Entries_Close (tmpentries);
+ }
+
+ /* look for sub-dirs in the repository */
+ if ((which & W_REPOS) && repository)
+ {
+ /* search the repository */
+ if (find_dirs (repository, dirlist, 0, entries) != 0)
+ error (1, errno, "cannot open directory %s", repository);
+
+ /* We don't need to look in the attic because directories
+ never go in the attic. In the future, there hopefully will
+ be a better mechanism for detecting whether a directory in
+ the repository is alive or dead; it may or may not involve
+ moving directories to the attic. */
+ }
+
+ /* sort the list into alphabetical order and return it */
+ sortlist (dirlist, fsortcmp);
+ return (dirlist);
+}
+
+
+
+/* Finds all the files matching PAT. If DIR is NULL, PAT will be interpreted
+ * as either absolute or relative to the PWD and read errors, e.g. failure to
+ * open a directory, will be ignored. If DIR is not NULL, PAT is
+ * always interpreted as relative to DIR. Adds all matching files and
+ * directories to a new List. Returns the new List for success and NULL in
+ * case of error, in which case ERRNO will also be set.
+ *
+ * NOTES
+ * When DIR is NULL, this is really just a thinly veiled wrapper for glob().
+ *
+ * Much of the cruft in this function could be avoided if DIR was eliminated.
+ *
+ * INPUTS
+ * dir The directory to match relative to.
+ * pat The pattern to match against, via glob().
+ *
+ * GLOBALS
+ * errno Set on error.
+ * really_quiet Used to decide whether to print warnings.
+ *
+ * RETURNS
+ * A pointer to a List of matching file and directory names, on success.
+ * NULL, on error.
+ *
+ * ERRORS
+ * Error returns can be caused if glob() returns an error. ERRNO will be
+ * set. When !REALLY_QUIET and the failure was not a read error, a warning
+ * message will be printed via error (0, errno, ...).
+ */
+List *
+find_files (const char *dir, const char *pat)
+{
+ List *retval;
+ glob_t glist;
+ int err, i;
+ char *catpat = NULL;
+ bool dirslash = false;
+
+ if (dir && *dir)
+ {
+ size_t catpatlen = 0;
+ const char *p;
+ if (glob_pattern_p (dir, false))
+ {
+ /* Escape special characters in DIR. */
+ size_t len = 0;
+ p = dir;
+ while (*p)
+ {
+ switch (*p)
+ {
+ case '\\':
+ case '*':
+ case '[':
+ case ']':
+ case '?':
+ expand_string (&catpat, &catpatlen, len + 1);
+ catpat[len++] = '\\';
+ default:
+ expand_string (&catpat, &catpatlen, len + 1);
+ catpat[len++] = *p++;
+ break;
+ }
+ }
+ catpat[len] = '\0';
+ }
+ else
+ {
+ xrealloc_and_strcat (&catpat, &catpatlen, dir);
+ p = dir + strlen (dir);
+ }
+
+ dirslash = *p - 1 == '/';
+ if (!dirslash)
+ xrealloc_and_strcat (&catpat, &catpatlen, "/");
+
+ xrealloc_and_strcat (&catpat, &catpatlen, pat);
+ pat = catpat;
+ }
+
+ err = glob (pat, GLOB_PERIOD | (dir ? GLOB_ERR : 0), NULL, &glist);
+ if (err && err != GLOB_NOMATCH)
+ {
+ if (err == GLOB_ABORTED)
+ /* Let our caller handle the problem. */
+ return NULL;
+ if (err == GLOB_NOSPACE) errno = ENOMEM;
+ if (!really_quiet)
+ error (0, errno, "glob failed");
+ if (catpat) free (catpat);
+ return NULL;
+ }
+
+ /* Copy what glob() returned into a List for our caller. */
+ retval = getlist ();
+ for (i = 0; i < glist.gl_pathc; i++)
+ {
+ Node *p;
+ const char *tmp;
+
+ /* Ignore `.' && `..'. */
+ tmp = last_component (glist.gl_pathv[i]);
+ if (!strcmp (tmp, ".") || !strcmp (tmp, ".."))
+ continue;
+
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (glist.gl_pathv[i]
+ + (dir ? strlen (dir) + !dirslash : 0));
+ if (addnode (retval, p)) freenode (p);
+ }
+
+ if (catpat) free (catpat);
+ globfree (&glist);
+ return retval;
+}
+
+
+
+/* walklist() proc which strips a trailing RCSEXT from node keys.
+ */
+static int
+strip_rcsext (Node *p, void *closure)
+{
+ char *s = p->key + strlen (p->key) - strlen (RCSEXT);
+ assert (!strcmp (s, RCSEXT));
+ *s = '\0'; /* strip the ,v */
+ return 0;
+}
+
+
+
+/*
+ * Finds all the ,v files in the directory DIR, and adds them to the LIST.
+ * Returns 0 for success and non-zero if DIR cannot be opened, in which case
+ * ERRNO is set to indicate the error. In the error case, LIST is left in some
+ * reasonable state (unchanged, or containing the files which were found before
+ * the error occurred).
+ *
+ * INPUTS
+ * dir The directory to open for read.
+ *
+ * OUTPUTS
+ * list Where to store matching file entries.
+ *
+ * GLOBALS
+ * errno Set on error.
+ *
+ * RETURNS
+ * 0, for success.
+ * <> 0, on error.
+ */
+static int
+find_rcs (dir, list)
+ const char *dir;
+ List *list;
+{
+ List *newlist;
+ if (!(newlist = find_files (dir, RCSPAT)))
+ return 1;
+ walklist (newlist, strip_rcsext, NULL);
+ mergelists (list, &newlist);
+ return 0;
+}
+
+
+
+/*
+ * Finds all the subdirectories of the argument dir and adds them to
+ * the specified list. Sub-directories without a CVS administration
+ * directory are optionally ignored. If ENTRIES is not NULL, all
+ * files on the list are ignored. Returns 0 for success or 1 on
+ * error, in which case errno is set to indicate the error.
+ */
+static int
+find_dirs (char *dir, List *list, int checkadm, List *entries)
+{
+ Node *p;
+ char *tmp = NULL;
+ size_t tmp_size = 0;
+ struct dirent *dp;
+ DIR *dirp;
+ int skip_emptydir = 0;
+
+ /* First figure out whether we need to skip directories named
+ Emptydir. Except in the CVSNULLREPOS case, Emptydir is just
+ a normal directory name. */
+ if (ISABSOLUTE (dir)
+ && strncmp (dir, current_parsed_root->directory, strlen (current_parsed_root->directory)) == 0
+ && ISSLASH (dir[strlen (current_parsed_root->directory)])
+ && strcmp (dir + strlen (current_parsed_root->directory) + 1, CVSROOTADM) == 0)
+ skip_emptydir = 1;
+
+ /* set up to read the dir */
+ if ((dirp = CVS_OPENDIR (dir)) == NULL)
+ return (1);
+
+ /* read the dir, grabbing sub-dirs */
+ errno = 0;
+ while ((dp = CVS_READDIR (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0 ||
+ strcmp (dp->d_name, CVSATTIC) == 0 ||
+ strcmp (dp->d_name, CVSLCK) == 0 ||
+ strcmp (dp->d_name, CVSREP) == 0)
+ goto do_it_again;
+
+ /* findnode() is going to be significantly faster than stat()
+ because it involves no system calls. That is why we bother
+ with the entries argument, and why we check this first. */
+ if (entries != NULL && findnode (entries, dp->d_name) != NULL)
+ goto do_it_again;
+
+ if (skip_emptydir
+ && strcmp (dp->d_name, CVSNULLREPOS) == 0)
+ goto do_it_again;
+
+#ifdef DT_DIR
+ if (dp->d_type != DT_DIR)
+ {
+ if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
+ goto do_it_again;
+#endif
+ /* don't bother stating ,v files */
+ if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
+ goto do_it_again;
+
+ expand_string (&tmp,
+ &tmp_size,
+ strlen (dir) + strlen (dp->d_name) + 10);
+ sprintf (tmp, "%s/%s", dir, dp->d_name);
+ if (!isdir (tmp))
+ goto do_it_again;
+
+#ifdef DT_DIR
+ }
+#endif
+
+ /* check for administration directories (if needed) */
+ if (checkadm)
+ {
+ /* blow off symbolic links to dirs in local dir */
+#ifdef DT_DIR
+ if (dp->d_type != DT_DIR)
+ {
+ /* we're either unknown or a symlink at this point */
+ if (dp->d_type == DT_LNK)
+ goto do_it_again;
+#endif
+ /* Note that we only get here if we already set tmp
+ above. */
+ if (islink (tmp))
+ goto do_it_again;
+#ifdef DT_DIR
+ }
+#endif
+
+ /* check for new style */
+ expand_string (&tmp,
+ &tmp_size,
+ (strlen (dir) + strlen (dp->d_name)
+ + sizeof (CVSADM) + 10));
+ (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
+ if (!isdir (tmp))
+ goto do_it_again;
+ }
+
+ /* put it in the list */
+ p = getnode ();
+ p->type = DIRS;
+ p->key = xstrdup (dp->d_name);
+ if (addnode (list, p) != 0)
+ freenode (p);
+
+ do_it_again:
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ int save_errno = errno;
+ (void) CVS_CLOSEDIR (dirp);
+ errno = save_errno;
+ return 1;
+ }
+ (void) CVS_CLOSEDIR (dirp);
+ if (tmp != NULL)
+ free (tmp);
+ return (0);
+}
diff --git a/src/gssapi-client.c b/src/gssapi-client.c
new file mode 100644
index 0000000..b49206b
--- /dev/null
+++ b/src/gssapi-client.c
@@ -0,0 +1,316 @@
+/* CVS GSSAPI client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include "cvs.h"
+#include "buffer.h"
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+# include "gssapi-client.h"
+
+/* This is needed for GSSAPI encryption. */
+gss_ctx_id_t gcontext;
+#endif /* CLIENT_SUPPORT || SERVER_SUPPORT */
+
+#ifdef CLIENT_SUPPORT
+# include "socket-client.h"
+
+# ifdef ENCRYPTION
+/* Whether to encrypt GSSAPI communication. We use a global variable
+ like this because we use the same buffer type (gssapi_wrap) to
+ handle both authentication and encryption, and we don't want
+ multiple instances of that buffer in the communication stream. */
+int cvs_gssapi_encrypt;
+# endif /* ENCRYPTION */
+
+
+/* Receive a given number of bytes. */
+
+static void
+recv_bytes (int sock, char *buf, int need)
+{
+ while (need > 0)
+ {
+ int got;
+
+ got = recv (sock, buf, need, 0);
+ if (got <= 0)
+ error (1, 0, "recv() from server %s: %s",
+ current_parsed_root->hostname,
+ got == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO));
+
+ buf += got;
+ need -= got;
+ }
+}
+
+
+
+/* Connect to the server using GSSAPI authentication. */
+
+/* FIXME
+ *
+ * This really needs to be rewritten to use a buffer and not a socket.
+ * This would enable gserver to work with the SSL code I'm about to commit
+ * since the SSL connection is going to look like a FIFO and not a socket.
+ *
+ * I think, basically, it will need to use buf_output and buf_read directly
+ * since I don't think there is a read_bytes function - only read_line.
+ *
+ * recv_bytes could then be removed too.
+ *
+ * Besides, I added some cruft to reenable the socket which shouldn't be
+ * there. This would also enable its removal.
+ */
+#define BUFSIZE 1024
+int
+connect_to_gserver (cvsroot_t *root, int sock, struct hostent *hostinfo)
+{
+ char *str;
+ char buf[BUFSIZE];
+ gss_buffer_desc *tok_in_ptr, tok_in, tok_out;
+ OM_uint32 stat_min, stat_maj;
+ gss_name_t server_name;
+
+ str = "BEGIN GSSAPI REQUEST\012";
+
+ if (send (sock, str, strlen (str), 0) < 0)
+ error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+
+ if (strlen (hostinfo->h_name) > BUFSIZE - 5)
+ error (1, 0, "Internal error: hostname exceeds length of buffer");
+ sprintf (buf, "cvs@%s", hostinfo->h_name);
+ tok_in.length = strlen (buf);
+ tok_in.value = buf;
+ gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE,
+ &server_name);
+
+ tok_in_ptr = GSS_C_NO_BUFFER;
+ gcontext = GSS_C_NO_CONTEXT;
+
+ do
+ {
+ stat_maj = gss_init_sec_context (&stat_min, GSS_C_NO_CREDENTIAL,
+ &gcontext, server_name,
+ GSS_C_NULL_OID,
+ (GSS_C_MUTUAL_FLAG
+ | GSS_C_REPLAY_FLAG),
+ 0, NULL, tok_in_ptr, NULL, &tok_out,
+ NULL, NULL);
+ if (stat_maj != GSS_S_COMPLETE && stat_maj != GSS_S_CONTINUE_NEEDED)
+ {
+ OM_uint32 message_context;
+ OM_uint32 new_stat_min;
+
+ message_context = 0;
+ gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE,
+ GSS_C_NULL_OID, &message_context, &tok_out);
+ error (0, 0, "GSSAPI authentication failed: %s",
+ (const char *) tok_out.value);
+
+ message_context = 0;
+ gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &message_context, &tok_out);
+ error (1, 0, "GSSAPI authentication failed: %s",
+ (const char *) tok_out.value);
+ }
+
+ if (tok_out.length == 0)
+ {
+ tok_in.length = 0;
+ }
+ else
+ {
+ char cbuf[2];
+ int need;
+
+ cbuf[0] = (tok_out.length >> 8) & 0xff;
+ cbuf[1] = tok_out.length & 0xff;
+ if (send (sock, cbuf, 2, 0) < 0)
+ error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+ if (send (sock, tok_out.value, tok_out.length, 0) < 0)
+ error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+
+ recv_bytes (sock, cbuf, 2);
+ need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff);
+
+ if (need > sizeof buf)
+ {
+ ssize_t got;
+ size_t total;
+
+ /* This usually means that the server sent us an error
+ message. Read it byte by byte and print it out.
+ FIXME: This is a terrible error handling strategy.
+ However, even if we fix the server, we will still
+ want to do this to work with older servers. */
+ buf[0] = cbuf[0];
+ buf[1] = cbuf[1];
+ total = 2;
+ while ((got = recv (sock, buf + total, sizeof buf - total, 0)))
+ {
+ if (got < 0)
+ error (1, 0, "recv() from server %s: %s",
+ root->hostname, SOCK_STRERROR (SOCK_ERRNO));
+ total += got;
+ if (strrchr (buf + total - got, '\n'))
+ break;
+ }
+ buf[total] = '\0';
+ if (buf[total - 1] == '\n')
+ buf[total - 1] = '\0';
+ error (1, 0, "error from server %s: %s", root->hostname,
+ buf);
+ }
+
+ recv_bytes (sock, buf, need);
+ tok_in.length = need;
+ }
+
+ tok_in.value = buf;
+ tok_in_ptr = &tok_in;
+ }
+ while (stat_maj == GSS_S_CONTINUE_NEEDED);
+
+ return 1;
+}
+#endif /* CLIENT_SUPPORT */
+
+
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+/* A buffer interface using GSSAPI. It is built on top of a
+ packetizing buffer. */
+
+/* This structure is the closure field of the GSSAPI translation
+ routines. */
+
+struct cvs_gssapi_wrap_data
+{
+ /* The GSSAPI context. */
+ gss_ctx_id_t gcontext;
+};
+
+
+
+/* Unwrap data using GSSAPI. */
+static int
+cvs_gssapi_wrap_input (void *fnclosure, const char *input, char *output,
+ size_t size)
+{
+ struct cvs_gssapi_wrap_data *gd = fnclosure;
+ gss_buffer_desc inbuf, outbuf;
+ OM_uint32 stat_min;
+ int conf;
+
+ inbuf.value = (void *)input;
+ inbuf.length = size;
+
+ if (gss_unwrap (&stat_min, gd->gcontext, &inbuf, &outbuf, &conf, NULL)
+ != GSS_S_COMPLETE)
+ {
+ error (1, 0, "gss_unwrap failed");
+ }
+
+ if (outbuf.length > size)
+ abort ();
+
+ memcpy (output, outbuf.value, outbuf.length);
+
+ /* The real packet size is stored in the data, so we don't need to
+ remember outbuf.length. */
+
+ gss_release_buffer (&stat_min, &outbuf);
+
+ return 0;
+}
+
+
+
+/* Wrap data using GSSAPI. */
+static int
+cvs_gssapi_wrap_output (void *fnclosure, const char *input, char *output,
+ size_t size, size_t *translated)
+{
+ struct cvs_gssapi_wrap_data *gd = fnclosure;
+ gss_buffer_desc inbuf, outbuf;
+ OM_uint32 stat_min;
+ int conf_req, conf;
+
+ inbuf.value = (void *)input;
+ inbuf.length = size;
+
+#ifdef ENCRYPTION
+ conf_req = cvs_gssapi_encrypt;
+#else
+ conf_req = 0;
+#endif
+
+ if (gss_wrap (&stat_min, gd->gcontext, conf_req, GSS_C_QOP_DEFAULT,
+ &inbuf, &conf, &outbuf) != GSS_S_COMPLETE)
+ error (1, 0, "gss_wrap failed");
+
+ /* The packetizing buffer only permits us to add 100 bytes.
+ FIXME: I don't know what, if anything, is guaranteed by GSSAPI.
+ This may need to be increased for a different GSSAPI
+ implementation, or we may need a different algorithm. */
+ if (outbuf.length > size + 100)
+ abort ();
+
+ memcpy (output, outbuf.value, outbuf.length);
+
+ *translated = outbuf.length;
+
+ gss_release_buffer (&stat_min, &outbuf);
+
+ return 0;
+}
+
+
+
+/* Create a GSSAPI wrapping buffer. We use a packetizing buffer with
+ GSSAPI wrapping routines. */
+struct buffer *
+cvs_gssapi_wrap_buffer_initialize (struct buffer *buf, int input,
+ gss_ctx_id_t gcontext,
+ void (*memory) ( struct buffer * ))
+{
+ struct cvs_gssapi_wrap_data *gd;
+
+ gd = xmalloc (sizeof *gd);
+ gd->gcontext = gcontext;
+
+ return packetizing_buffer_initialize (buf,
+ input ? cvs_gssapi_wrap_input
+ : NULL,
+ input ? NULL
+ : cvs_gssapi_wrap_output,
+ gd, memory);
+}
+
+
+
+void
+initialize_gssapi_buffers (struct buffer **to_server_p,
+ struct buffer **from_server_p)
+{
+ *to_server_p = cvs_gssapi_wrap_buffer_initialize (*to_server_p, 0,
+ gcontext, NULL);
+
+ *from_server_p = cvs_gssapi_wrap_buffer_initialize (*from_server_p, 1,
+ gcontext, NULL);
+}
+#endif /* CLIENT_SUPPORT || SERVER_SUPPORT */
diff --git a/src/gssapi-client.h b/src/gssapi-client.h
new file mode 100644
index 0000000..99c1838
--- /dev/null
+++ b/src/gssapi-client.h
@@ -0,0 +1,61 @@
+/* CVS GSSAPI client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+
+#ifndef GSSAPI_CLIENT_H__
+#define GSSAPI_CLIENT_H__
+
+#ifdef HAVE_GSSAPI
+
+/* Here goes the generic include magic necessary for using
+ * cross platform gssapi which configure doesn't perform itself.
+ */
+
+/* Can't include both of these headers at the same time with Solaris 7 &
+ * Heimdal Kerberos 0.3. If some system ends up requiring both, a configure
+ * test like TIME_AND_SYS_TIME will probably be necessary.
+ */
+#ifdef HAVE_GSSAPI_H
+# include <gssapi.h>
+#else
+/* Assume existance of this header so that the user will get an informative
+ * message if HAVE_GSSAPI somehow gets defined with both headers missing.
+ */
+# include <gssapi/gssapi.h>
+#endif
+#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
+/* MIT Kerberos 5 v1.2.1 */
+# include <gssapi/gssapi_generic.h>
+#endif
+
+#include "socket-client.h"
+
+/* Set this to turn on GSSAPI encryption. */
+extern int cvs_gssapi_encrypt;
+
+extern gss_ctx_id_t gcontext;
+
+/* We can't declare the arguments without including gssapi.h, and I
+ don't want to do that in every file. */
+struct buffer* cvs_gssapi_wrap_buffer_initialize( struct buffer *buf,
+ int input,
+ gss_ctx_id_t gcontext,
+ void (*memory) (struct buffer *) );
+
+int connect_to_gserver (cvsroot_t *, int, struct hostent *);
+
+extern void initialize_gssapi_buffers (struct buffer **to_server_p,
+ struct buffer **from_server_p);
+
+#endif /* HAVE_GSSAPI */
+
+#endif
diff --git a/src/hardlink.c b/src/hardlink.c
new file mode 100644
index 0000000..04af09f
--- /dev/null
+++ b/src/hardlink.c
@@ -0,0 +1,304 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* Collect and manage hardlink info associated with a particular file. */
+
+#include "cvs.h"
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+# include "hardlink.h"
+
+/* The structure currently used to manage hardlink info is a list.
+ Therefore, most of the functions which manipulate hardlink data
+ are walklist procedures. This is not a very efficient implementation;
+ if someone decides to use a real hash table (for instance), then
+ much of this code can be rewritten to be a little less arcane.
+
+ Each element of `hardlist' represents an inode. It is keyed on the
+ inode number, and points to a list of files. This is to make it
+ easy to find out what files are linked to a given file FOO: find
+ FOO's inode, look it up in hardlist, and retrieve the list of files
+ associated with that inode.
+
+ Each file node, in turn, is represented by a `hardlink_info' struct,
+ which includes `status' and `links' fields. The `status' field should
+ be used by a procedure like commit_fileproc or update_fileproc to
+ record each file's status; that way, after all file links have been
+ recorded, CVS can check the linkage of files which are in doubt
+ (i.e. T_NEEDS_MERGE files).
+
+ TODO: a diagram of an example hardlist would help here. */
+
+/* TODO: change this to something with a marginal degree of
+ efficiency, like maybe a hash table. Yeah. */
+
+
+
+static void
+delhardlist (Node *p)
+{
+ if (p->data)
+ dellist ((List **)&p->data);
+}
+
+
+
+List *hardlist; /* Record hardlink information for working files */
+char *working_dir; /* The top-level working directory, used for
+ constructing full pathnames. */
+
+/* Return a pointer to FILEPATH's node in the hardlist. This means
+ looking up its inode, retrieving the list of files linked to that
+ inode, and then looking up FILE in that list. If the file doesn't
+ seem to exist, return NULL. */
+Node *
+lookup_file_by_inode (const char *filepath)
+{
+ char *inodestr;
+ const char *file;
+ struct stat sb;
+ Node *hp, *p;
+
+ /* Get file's basename, so that we can stat it. */
+ file = strrchr (filepath, '/');
+ if (file)
+ ++file;
+ else
+ file = filepath;
+
+ if (stat (file, &sb) < 0)
+ {
+ if (existence_error (errno))
+ {
+ /* The file doesn't exist; we may be doing an update on a
+ file that's been removed. A nonexistent file has no
+ link information, so return without changing hardlist. */
+ free (inodestr);
+ return NULL;
+ }
+ error (1, errno, "cannot stat %s", file);
+ }
+
+ /* inodestr contains the hexadecimal representation of an
+ inode. */
+ inodestr = Xasprintf ("%lx", (unsigned long) sb.st_ino);
+
+ /* Find out if this inode is already in the hardlist, adding
+ a new entry to the list if not. */
+ hp = findnode (hardlist, inodestr);
+ if (hp == NULL)
+ {
+ hp = getnode ();
+ hp->type = NT_UNKNOWN;
+ hp->key = inodestr;
+ hp->data = getlist ();
+ hp->delproc = delhardlist;
+ (void) addnode (hardlist, hp);
+ }
+ else
+ {
+ free (inodestr);
+ }
+
+ p = findnode (hp->data, filepath);
+ if (p == NULL)
+ {
+ p = getnode ();
+ p->type = NT_UNKNOWN;
+ p->key = xstrdup (filepath);
+ p->data = NULL;
+ (void) addnode (hp->data, p);
+ }
+
+ return p;
+}
+
+/* After a file has been checked out, add a node for it to the hardlist
+ (if necessary) and mark it as checked out. */
+void
+update_hardlink_info (const char *file)
+{
+ char *path;
+ Node *n;
+ struct hardlink_info *hlinfo;
+
+ if (file[0] == '/')
+ {
+ path = xstrdup (file);
+ }
+ else
+ {
+ /* file is a relative pathname; assume it's from the current
+ working directory. */
+ char *dir = xgetcwd ();
+ path = Xasprintf ("%s/%s", dir, file);
+ free (dir);
+ }
+
+ n = lookup_file_by_inode (path);
+ if (n == NULL)
+ {
+ /* Something is *really* wrong if the file doesn't exist here;
+ update_hardlink_info should be called only when a file has
+ just been checked out to a working directory. */
+ error (1, 0, "lost hardlink info for %s", file);
+ }
+
+ if (n->data == NULL)
+ n->data = xmalloc (sizeof (struct hardlink_info));
+ hlinfo = n->data;
+ hlinfo->status = T_UPTODATE;
+ hlinfo->checked_out = 1;
+}
+
+/* Return a List with all the files known to be linked to FILE in
+ the working directory. Used by special_file_mismatch, to determine
+ whether it is safe to merge two files.
+
+ FIXME: What is the memory allocation for the return value? We seem
+ to sometimes allocate a new list (getlist() call below) and sometimes
+ return an existing list (where we return n->data). */
+List *
+list_linked_files_on_disk (char *file)
+{
+ char *inodestr, *path;
+ struct stat sb;
+ Node *n;
+
+ /* If hardlist is NULL, we have not been doing an operation that
+ would permit us to know anything about the file's hardlinks
+ (cvs update, cvs commit, etc). Return an empty list. */
+ if (hardlist == NULL)
+ return getlist ();
+
+ /* Get the full pathname of file (assuming the working directory) */
+ if (file[0] == '/')
+ path = xstrdup (file);
+ else
+ {
+ char *dir = xgetcwd ();
+ path = Xasprintf ("%s/%s", dir, file);
+ free (dir);
+ }
+
+ /* We do an extra lookup_file here just to make sure that there
+ is a node for `path' in the hardlist. If that were not so,
+ comparing the working directory linkage against the repository
+ linkage for a file would always fail. */
+ (void) lookup_file_by_inode (path);
+
+ if (stat (path, &sb) < 0)
+ error (1, errno, "cannot stat %s", file);
+ /* inodestr contains the hexadecimal representation of an
+ inode. */
+ inodestr = Xasprintf ("%lx", (unsigned long) sb.st_ino);
+
+ /* Make sure the files linked to this inode are sorted. */
+ n = findnode (hardlist, inodestr);
+ sortlist (n->data, fsortcmp);
+
+ free (inodestr);
+ return n->data;
+}
+
+/* Compare the files in the `key' fields of two lists, returning 1 if
+ the lists are equivalent and 0 otherwise.
+
+ Only the basenames of each file are compared. This is an awful hack
+ that exists because list_linked_files_on_disk returns full paths
+ and the `hardlinks' structure of a RCSVers node contains only
+ basenames. That in turn is a result of the awful hack that only
+ basenames are stored in the RCS file. If anyone ever solves the
+ problem of correctly managing cross-directory hardlinks, this
+ function (along with most functions in this file) must be fixed. */
+
+int
+compare_linkage_lists (List *links1, List *links2)
+{
+ Node *n1, *n2;
+ char *p1, *p2;
+
+ sortlist (links1, fsortcmp);
+ sortlist (links2, fsortcmp);
+
+ n1 = links1->list->next;
+ n2 = links2->list->next;
+
+ while (n1 != links1->list && n2 != links2->list)
+ {
+ /* Get the basenames of both files. */
+ p1 = strrchr (n1->key, '/');
+ if (p1 == NULL)
+ p1 = n1->key;
+ else
+ ++p1;
+
+ p2 = strrchr (n2->key, '/');
+ if (p2 == NULL)
+ p2 = n2->key;
+ else
+ ++p2;
+
+ /* Compare the files' basenames. */
+ if (strcmp (p1, p2) != 0)
+ return 0;
+
+ n1 = n1->next;
+ n2 = n2->next;
+ }
+
+ /* At this point we should be at the end of both lists; if not,
+ one file has more links than the other, and return 1. */
+ return (n1 == links1->list && n2 == links2->list);
+}
+
+/* Find a checked-out file in a list of filenames. Used by RCS_checkout
+ when checking out a new hardlinked file, to decide whether this file
+ can be linked to any others that already exist. The return value
+ is not currently used. */
+
+int
+find_checkedout_proc (Node *node, void *data)
+{
+ Node **uptodate = data;
+ Node *link;
+ char *dir = xgetcwd ();
+ char *path;
+ struct hardlink_info *hlinfo;
+
+ /* If we have already found a file, don't do anything. */
+ if (*uptodate != NULL)
+ return 0;
+
+ /* Look at this file in the hardlist and see whether the checked_out
+ field is 1, meaning that it has been checked out during this CVS run. */
+ path = Xasprintf ("%s/%s", dir, node->key);
+ link = lookup_file_by_inode (path);
+ free (path);
+ free (dir);
+
+ if (link == NULL)
+ {
+ /* We haven't seen this file -- maybe it hasn't been checked
+ out yet at all. */
+ return 0;
+ }
+
+ hlinfo = link->data;
+ if (hlinfo->checked_out)
+ {
+ /* This file has been checked out recently, so it's safe to
+ link to it. */
+ *uptodate = link;
+ }
+
+ return 0;
+}
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
diff --git a/src/hardlink.h b/src/hardlink.h
new file mode 100644
index 0000000..7e2b384
--- /dev/null
+++ b/src/hardlink.h
@@ -0,0 +1,35 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* Data type definitions and declarations for hardlink management. */
+
+/* This file should be #included in CVS source files after cvs.h
+ since it relies on types and macros defined there. */
+
+/* The `checked_out' member of a hardlink_info struct is used only
+ when files are being checked out or updated. It is used only when
+ hardlinked files are being checked out. */
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+struct hardlink_info
+{
+ Ctype status; /* as returned from Classify_File() */
+ int checked_out; /* has this file been checked out lately? */
+};
+
+extern List *hardlist;
+extern char *working_dir;
+
+Node *lookup_file_by_inode (const char *);
+void update_hardlink_info (const char *);
+List *list_linked_files_on_disk (char *);
+int compare_linkage_lists (List *, List *);
+int find_checkedout_proc (Node *, void *);
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
diff --git a/src/hash.c b/src/hash.c
new file mode 100644
index 0000000..e87b40d
--- /dev/null
+++ b/src/hash.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Polk's hash list manager. So cool.
+ */
+
+#include "cvs.h"
+
+/* Global caches. The idea is that we maintain a linked list of "free"d
+ nodes or lists, and get new items from there. It has been suggested
+ to use an obstack instead, but off the top of my head, I'm not sure
+ that would gain enough to be worth worrying about. */
+static List *listcache = NULL;
+static Node *nodecache = NULL;
+
+static void freenode_mem (Node * p);
+
+/* hash function */
+static int
+hashp (const char *key)
+{
+ unsigned int h = 0;
+ unsigned int g;
+
+ assert(key != NULL);
+
+ while (*key != 0)
+ {
+ unsigned int c = *key++;
+ /* The FOLD_FN_CHAR is so that findnode_fn works. */
+ h = (h << 4) + FOLD_FN_CHAR (c);
+ if ((g = h & 0xf0000000) != 0)
+ h = (h ^ (g >> 24)) ^ g;
+ }
+
+ return h % HASHSIZE;
+}
+
+
+
+/*
+ * create a new list (or get an old one from the cache)
+ */
+List *
+getlist (void)
+{
+ int i;
+ List *list;
+ Node *node;
+
+ if (listcache != NULL)
+ {
+ /* get a list from the cache and clear it */
+ list = listcache;
+ listcache = listcache->next;
+ list->next = NULL;
+ for (i = 0; i < HASHSIZE; i++)
+ list->hasharray[i] = NULL;
+ }
+ else
+ {
+ /* make a new list from scratch */
+ list = xmalloc (sizeof (List));
+ memset (list, 0, sizeof (List));
+ node = getnode ();
+ list->list = node;
+ node->type = HEADER;
+ node->next = node->prev = node;
+ }
+ return list;
+}
+
+
+
+/*
+ * Free up a list. For accessing globals which might be accessed via interrupt
+ * handlers, it can be assumed that the first action of this function will be
+ * to set the *listp to NULL.
+ */
+void
+dellist (List **listp)
+{
+ int i;
+ Node *p;
+ List *tmp;
+
+ if (*listp == NULL)
+ return;
+
+ tmp = *listp;
+ *listp = NULL;
+
+ p = tmp->list;
+
+ /* free each node in the list (except header) */
+ while (p->next != p)
+ delnode (p->next);
+
+ /* free any list-private data, without freeing the actual header */
+ freenode_mem (p);
+
+ /* free up the header nodes for hash lists (if any) */
+ for (i = 0; i < HASHSIZE; i++)
+ {
+ if ((p = tmp->hasharray[i]) != NULL)
+ {
+ /* put the nodes into the cache */
+#ifndef NOCACHE
+ p->type = NT_UNKNOWN;
+ p->next = nodecache;
+ nodecache = p;
+#else
+ /* If NOCACHE is defined we turn off the cache. This can make
+ it easier to tools to determine where items were allocated
+ and freed, for tracking down memory leaks and the like. */
+ free (p);
+#endif
+ }
+ }
+
+ /* put it on the cache */
+#ifndef NOCACHE
+ tmp->next = listcache;
+ listcache = tmp;
+#else
+ free (tmp->list);
+ free (tmp);
+#endif
+}
+
+
+
+/*
+ * remove a node from it's list (maybe hash list too)
+ */
+void
+removenode (Node *p)
+{
+ if (!p) return;
+
+ /* take it out of the list */
+ p->next->prev = p->prev;
+ p->prev->next = p->next;
+
+ /* if it was hashed, remove it from there too */
+ if (p->hashnext)
+ {
+ p->hashnext->hashprev = p->hashprev;
+ p->hashprev->hashnext = p->hashnext;
+ }
+}
+
+
+
+void
+mergelists (List *dest, List **src)
+{
+ Node *head, *p, *n;
+
+ head = (*src)->list;
+ for (p = head->next; p != head; p = n)
+ {
+ n = p->next;
+ removenode (p);
+ addnode (dest, p);
+ }
+ dellist (src);
+}
+
+
+
+/*
+ * get a new list node
+ */
+Node *
+getnode (void)
+{
+ Node *p;
+
+ if (nodecache != NULL)
+ {
+ /* get one from the cache */
+ p = nodecache;
+ nodecache = p->next;
+ }
+ else
+ {
+ /* make a new one */
+ p = xmalloc (sizeof (Node));
+ }
+
+ /* always make it clean */
+ memset (p, 0, sizeof (Node));
+ p->type = NT_UNKNOWN;
+
+ return p;
+}
+
+
+
+/*
+ * remove a node from it's list (maybe hash list too) and free it
+ */
+void
+delnode (Node *p)
+{
+ if (!p) return;
+ /* remove it */
+ removenode (p);
+ /* free up the storage */
+ freenode (p);
+}
+
+
+
+/*
+ * free up the storage associated with a node
+ */
+static void
+freenode_mem (Node *p)
+{
+ if (p->delproc != NULL)
+ p->delproc (p); /* call the specified delproc */
+ else
+ {
+ if (p->data != NULL) /* otherwise free() it if necessary */
+ free (p->data);
+ }
+ if (p->key != NULL) /* free the key if necessary */
+ free (p->key);
+
+ /* to be safe, re-initialize these */
+ p->key = p->data = NULL;
+ p->delproc = NULL;
+}
+
+
+
+/*
+ * free up the storage associated with a node and recycle it
+ */
+void
+freenode (Node *p)
+{
+ /* first free the memory */
+ freenode_mem (p);
+
+ /* then put it in the cache */
+#ifndef NOCACHE
+ p->type = NT_UNKNOWN;
+ p->next = nodecache;
+ nodecache = p;
+#else
+ free (p);
+#endif
+}
+
+
+
+/*
+ * Link item P into list LIST before item MARKER. If P->KEY is non-NULL and
+ * that key is already in the hash table, return -1 without modifying any
+ * parameter.
+ *
+ * return 0 on success
+ */
+int
+insert_before (List *list, Node *marker, Node *p)
+{
+ if (p->key != NULL) /* hash it too? */
+ {
+ int hashval;
+ Node *q;
+
+ hashval = hashp (p->key);
+ if (list->hasharray[hashval] == NULL) /* make a header for list? */
+ {
+ q = getnode ();
+ q->type = HEADER;
+ list->hasharray[hashval] = q->hashnext = q->hashprev = q;
+ }
+
+ /* put it into the hash list if it's not already there */
+ for (q = list->hasharray[hashval]->hashnext;
+ q != list->hasharray[hashval]; q = q->hashnext)
+ {
+ if (strcmp (p->key, q->key) == 0)
+ return -1;
+ }
+ q = list->hasharray[hashval];
+ p->hashprev = q->hashprev;
+ p->hashnext = q;
+ p->hashprev->hashnext = p;
+ q->hashprev = p;
+ }
+
+ p->next = marker;
+ p->prev = marker->prev;
+ marker->prev->next = p;
+ marker->prev = p;
+
+ return 0;
+}
+
+
+
+/*
+ * insert item p at end of list "list" (maybe hash it too) if hashing and it
+ * already exists, return -1 and don't actually put it in the list
+ *
+ * return 0 on success
+ */
+int
+addnode (List *list, Node *p)
+{
+ return insert_before (list, list->list, p);
+}
+
+
+
+/*
+ * Like addnode, but insert p at the front of `list'. This bogosity is
+ * necessary to preserve last-to-first output order for some RCS functions.
+ */
+int
+addnode_at_front (List *list, Node *p)
+{
+ return insert_before (list, list->list->next, p);
+}
+
+
+
+/* Look up an entry in hash list table and return a pointer to the
+ * node. Return NULL if not found or if list is NULL. Abort with a fatal
+ * error for errors.
+ */
+Node *
+findnode (List *list, const char *key)
+{
+ Node *head, *p;
+
+ if ((list == NULL))
+ return NULL;
+
+ assert (key != NULL);
+
+ head = list->hasharray[hashp (key)];
+ if (head == NULL)
+ /* Not found. */
+ return NULL;
+
+ for (p = head->hashnext; p != head; p = p->hashnext)
+ if (strcmp (p->key, key) == 0)
+ return p;
+ return NULL;
+}
+
+
+
+/*
+ * Like findnode, but for a filename.
+ */
+Node *
+findnode_fn (List *list, const char *key)
+{
+ Node *head, *p;
+
+ /* This probably should be "assert (list != NULL)" (or if not we
+ should document the current behavior), but only if we check all
+ the callers to see if any are relying on this behavior. */
+ if (list == NULL)
+ return NULL;
+
+ assert (key != NULL);
+
+ head = list->hasharray[hashp (key)];
+ if (head == NULL)
+ return NULL;
+
+ for (p = head->hashnext; p != head; p = p->hashnext)
+ if (fncmp (p->key, key) == 0)
+ return p;
+ return NULL;
+}
+
+
+
+/*
+ * walk a list with a specific proc
+ */
+int
+walklist (List *list, int (*proc) (Node *, void *), void *closure)
+{
+ Node *head, *p;
+ int err = 0;
+
+#ifdef HAVE_PRINTF_PTR
+ TRACE (TRACE_FLOW, "walklist ( list=%p, proc=%p, closure=%p )",
+ (void *)list, (void *)proc, (void *)closure);
+#else
+ TRACE (TRACE_FLOW, "walklist ( list=%lx, proc=%lx, closure=%lx )",
+ (unsigned long)list,(unsigned long) proc,
+ (unsigned long)closure);
+#endif
+
+ if (list == NULL)
+ return 0;
+
+ head = list->list;
+ for (p = head->next; p != head; p = p->next)
+ err += proc (p, closure);
+ return err;
+}
+
+
+
+int
+list_isempty (List *list)
+{
+ return list == NULL || list->list->next == list->list;
+}
+
+
+
+static int (*client_comp) (const Node *, const Node *);
+
+static int
+qsort_comp (const void *elem1, const void *elem2)
+{
+ Node **node1 = (Node **) elem1;
+ Node **node2 = (Node **) elem2;
+ return client_comp (*node1, *node2);
+}
+
+
+
+/*
+ * sort the elements of a list (in place)
+ */
+void
+sortlist (List *list, int (*comp) (const Node *, const Node *))
+{
+ Node *head, *remain, *p, **array;
+ int i, n;
+
+ if (list == NULL)
+ return;
+
+ /* save the old first element of the list */
+ head = list->list;
+ remain = head->next;
+
+ /* count the number of nodes in the list */
+ n = 0;
+ for (p = remain; p != head; p = p->next)
+ n++;
+
+ /* allocate an array of nodes and populate it */
+ array = xnmalloc (n, sizeof (Node *));
+ i = 0;
+ for (p = remain; p != head; p = p->next)
+ array[i++] = p;
+
+ /* sort the array of nodes */
+ client_comp = comp;
+ qsort (array, n, sizeof(Node *), qsort_comp);
+
+ /* rebuild the list from beginning to end */
+ head->next = head->prev = head;
+ for (i = 0; i < n; i++)
+ {
+ p = array[i];
+ p->next = head;
+ p->prev = head->prev;
+ p->prev->next = p;
+ head->prev = p;
+ }
+
+ /* release the array of nodes */
+ free (array);
+}
+
+
+
+/*
+ * compare two files list node (for sort)
+ */
+int
+fsortcmp (const Node *p, const Node *q)
+{
+ return strcmp (p->key, q->key);
+}
+
+
+
+/* Debugging functions. Quite useful to call from within gdb. */
+
+
+static char *
+nodetypestring (Ntype type)
+{
+ switch (type) {
+ case NT_UNKNOWN: return "UNKNOWN";
+ case HEADER: return "HEADER";
+ case ENTRIES: return "ENTRIES";
+ case FILES: return "FILES";
+ case LIST: return "LIST";
+ case RCSNODE: return "RCSNODE";
+ case RCSVERS: return "RCSVERS";
+ case DIRS: return "DIRS";
+ case UPDATE: return "UPDATE";
+ case LOCK: return "LOCK";
+ case NDBMNODE: return "NDBMNODE";
+ case FILEATTR: return "FILEATTR";
+ case VARIABLE: return "VARIABLE";
+ case RCSFIELD: return "RCSFIELD";
+ case RCSCMPFLD: return "RCSCMPFLD";
+ }
+
+ return "<trash>";
+}
+
+
+
+static int
+printnode (Node *node, void *closure)
+{
+ if (node == NULL)
+ {
+ (void) printf("NULL node.\n");
+ return 0;
+ }
+
+#ifdef HAVE_PRINTF_PTR
+ (void) printf("Node at %p: type = %s, key = %p = \"%s\", data = %p, next = %p, prev = %p\n",
+ (void *) node, nodetypestring(node->type),
+ (void *) node->key, node->key, node->data,
+ (void *) node->next, (void *) node->prev);
+#else
+ (void) printf("Node at 0x%lx: type = %s, key = 0x%lx = \"%s\", data = 0x%lx, next = 0x%lx, prev = 0x%lx\n",
+ (unsigned long) node, nodetypestring(node->type),
+ (unsigned long) node->key, node->key, (unsigned long) node->data,
+ (unsigned long) node->next, (unsigned long) node->prev);
+#endif
+
+ return 0;
+}
+
+
+
+/* This is global, not static, so that its name is unique and to avoid
+ compiler warnings about it not being used. But it is not used by CVS;
+ it exists so one can call it from a debugger. */
+
+void
+printlist (List *list)
+{
+ if (list == NULL)
+ {
+ (void) printf("NULL list.\n");
+ return;
+ }
+
+#ifdef HAVE_PRINTF_PTR
+ (void) printf("List at %p: list = %p, HASHSIZE = %d, next = %p\n",
+ (void *) list, (void *) list->list, HASHSIZE, (void *) list->next);
+#else
+ (void) printf("List at 0x%lx: list = 0x%lx, HASHSIZE = %d, next = 0x%lx\n",
+ (unsigned long) list, (unsigned long) list->list, HASHSIZE,
+ (unsigned long) list->next);
+#endif
+
+ (void) walklist(list, printnode, NULL);
+
+ return;
+}
diff --git a/src/hash.h b/src/hash.h
new file mode 100644
index 0000000..a595a22
--- /dev/null
+++ b/src/hash.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ */
+
+/*
+ * The number of buckets for the hash table contained in each list. This
+ * should probably be prime.
+ */
+#define HASHSIZE 151
+
+/*
+ * Types of nodes
+ */
+enum ntype
+{
+ NT_UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE,
+ RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE, FILEATTR,
+ VARIABLE, RCSFIELD, RCSCMPFLD
+};
+typedef enum ntype Ntype;
+
+struct node
+{
+ Ntype type;
+ struct node *next;
+ struct node *prev;
+ struct node *hashnext;
+ struct node *hashprev;
+ char *key;
+ void *data;
+ void (*delproc) (struct node *);
+};
+typedef struct node Node;
+
+struct list
+{
+ Node *list;
+ Node *hasharray[HASHSIZE];
+ struct list *next;
+};
+typedef struct list List;
+
+List *getlist (void);
+Node *findnode (List *list, const char *key);
+Node *findnode_fn (List *list, const char *key);
+Node *getnode (void);
+int insert_before (List *list, Node *marker, Node *p);
+int addnode (List *list, Node *p);
+int addnode_at_front (List *list, Node *p);
+int walklist (List *list, int (*)(Node *n, void *closure), void *closure);
+int list_isempty (List *list);
+void removenode (Node *p);
+void mergelists (List *dest, List **src);
+void dellist (List **listp);
+void delnode (Node *p);
+void freenode (Node *p);
+void sortlist (List *list, int (*)(const Node *, const Node *));
+int fsortcmp (const Node *p, const Node *q);
diff --git a/src/history.c b/src/history.c
new file mode 100644
index 0000000..4f5f9ec
--- /dev/null
+++ b/src/history.c
@@ -0,0 +1,1686 @@
+/*
+ * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* **************** History of Users and Module ****************
+ *
+ * LOGGING: Append record to "${CVSROOT}/CVSROOTADM/CVSROOTADM_HISTORY".
+ *
+ * On For each Tag, Add, Checkout, Commit, Update or Release command,
+ * one line of text is written to a History log.
+ *
+ * X date | user | CurDir | special | rev(s) | argument '\n'
+ *
+ * where: [The spaces in the example line above are not in the history file.]
+ *
+ * X is a single character showing the type of event:
+ * T "Tag" cmd.
+ * O "Checkout" cmd.
+ * E "Export" cmd.
+ * F "Release" cmd.
+ * W "Update" cmd - No User file, Remove from Entries file.
+ * U "Update" cmd - File was checked out over User file.
+ * P "Update" cmd - User file was patched.
+ * G "Update" cmd - File was merged successfully.
+ * C "Update" cmd - File was merged and shows overlaps.
+ * M "Commit" cmd - "Modified" file.
+ * A "Commit" cmd - "Added" file.
+ * R "Commit" cmd - "Removed" file.
+ *
+ * date is a fixed length 8-char hex representation of a Unix time_t.
+ * [Starting here, variable fields are delimited by '|' chars.]
+ *
+ * user is the username of the person who typed the command.
+ *
+ * CurDir The directory where the action occurred. This should be the
+ * absolute path of the directory which is at the same level as
+ * the "Repository" field (for W,U,P,G,C & M,A,R).
+ *
+ * Repository For record types [W,U,P,G,C,M,A,R] this field holds the
+ * repository read from the administrative data where the
+ * command was typed.
+ * T "A" --> New Tag, "D" --> Delete Tag
+ * Otherwise it is the Tag or Date to modify.
+ * O,F,E A "" (null field)
+ *
+ * rev(s) Revision number or tag.
+ * T The Tag to apply.
+ * O,E The Tag or Date, if specified, else "" (null field).
+ * F "" (null field)
+ * W The Tag or Date, if specified, else "" (null field).
+ * U,P The Revision checked out over the User file.
+ * G,C The Revision(s) involved in merge.
+ * M,A,R RCS Revision affected.
+ *
+ * argument The module (for [TOEF]) or file (for [WUPGCMAR]) affected.
+ *
+ *
+ *** Report categories: "User" and "Since" modifiers apply to all reports.
+ * [For "sort" ordering see the "sort_order" routine.]
+ *
+ * Extract list of record types
+ *
+ * -e, -x [TOEFWUPGCMAR]
+ *
+ * Extracted records are simply printed, No analysis is performed.
+ * All "field" modifiers apply. -e chooses all types.
+ *
+ * Checked 'O'ut modules
+ *
+ * -o, -w
+ * Checked out modules. 'F' and 'O' records are examined and if
+ * the last record for a repository/file is an 'O', a line is
+ * printed. "-w" forces the "working dir" to be used in the
+ * comparison instead of the repository.
+ *
+ * Committed (Modified) files
+ *
+ * -c, -l, -w
+ * All 'M'odified, 'A'dded and 'R'emoved records are examined.
+ * "Field" modifiers apply. -l forces a sort by file within user
+ * and shows only the last modifier. -w works as in Checkout.
+ *
+ * Warning: Be careful with what you infer from the output of
+ * "cvs hi -c -l". It means the last time *you*
+ * changed the file, not the list of files for which
+ * you were the last changer!!!
+ *
+ * Module history for named modules.
+ * -m module, -l
+ *
+ * This is special. If one or more modules are specified, the
+ * module names are remembered and the files making up the
+ * modules are remembered. Only records matching exactly those
+ * files and repositories are shown. Sorting by "module", then
+ * filename, is implied. If -l ("last modified") is specified,
+ * then "update" records (types WUPCG), tag and release records
+ * are ignored and the last (by date) "modified" record.
+ *
+ * TAG history
+ *
+ * -T All Tag records are displayed.
+ *
+ *** Modifiers.
+ *
+ * Since ... [All records contain a timestamp, so any report
+ * category can be limited by date.]
+ *
+ * -D date - The "date" is parsed into a Unix "time_t" and
+ * records with an earlier time stamp are ignored.
+ * -r rev/tag - A "rev" begins with a digit. A "tag" does not. If
+ * you use this option, every file is searched for the
+ * indicated rev/tag.
+ * -t tag - The "tag" is searched for in the history file and no
+ * record is displayed before the tag is found. An
+ * error is printed if the tag is never found.
+ * -b string - Records are printed only back to the last reference
+ * to the string in the "module", "file" or
+ * "repository" fields.
+ *
+ * Field Selections [Simple comparisons on existing fields. All field
+ * selections are repeatable.]
+ *
+ * -a - All users.
+ * -u user - If no user is given and '-a' is not given, only
+ * records for the user typing the command are shown.
+ * ==> If -a or -u is not specified, just use "self".
+ *
+ * -f filematch - Only records in which the "file" field contains the
+ * string "filematch" are considered.
+ *
+ * -p repository - Only records in which the "repository" string is a
+ * prefix of the "repos" field are considered.
+ *
+ * -n modulename - Only records which contain "modulename" in the
+ * "module" field are considered.
+ *
+ *
+ * EXAMPLES: ("cvs history", "cvs his" or "cvs hi")
+ *
+ *** Checked out files for username. (default self, e.g. "dgg")
+ * cvs hi [equivalent to: "cvs hi -o -u dgg"]
+ * cvs hi -u user [equivalent to: "cvs hi -o -u user"]
+ * cvs hi -o [equivalent to: "cvs hi -o -u dgg"]
+ *
+ *** Committed (modified) files from the beginning of the file.
+ * cvs hi -c [-u user]
+ *
+ *** Committed (modified) files since Midnight, January 1, 1990:
+ * cvs hi -c -D 'Jan 1 1990' [-u user]
+ *
+ *** Committed (modified) files since tag "TAG" was stored in the history file:
+ * cvs hi -c -t TAG [-u user]
+ *
+ *** Committed (modified) files since tag "TAG" was placed on the files:
+ * cvs hi -c -r TAG [-u user]
+ *
+ *** Who last committed file/repository X?
+ * cvs hi -c -l -[fp] X
+ *
+ *** Modified files since tag/date/file/repos?
+ * cvs hi -c {-r TAG | -D Date | -b string}
+ *
+ *** Tag history
+ * cvs hi -T
+ *
+ *** History of file/repository/module X.
+ * cvs hi -[fpn] X
+ *
+ *** History of user "user".
+ * cvs hi -e -u user
+ *
+ *** Dump (eXtract) specified record types
+ * cvs hi -x [TOEFWUPGCMAR]
+ *
+ *
+ * FUTURE: J[Join], I[Import] (Not currently implemented.)
+ *
+ */
+
+#include "cvs.h"
+#include "history.h"
+#include "save-cwd.h"
+
+static struct hrec
+{
+ char *type; /* Type of record (In history record) */
+ char *user; /* Username (In history record) */
+ char *dir; /* "Compressed" Working dir (In history record) */
+ char *repos; /* (Tag is special.) Repository (In history record) */
+ char *rev; /* Revision affected (In history record) */
+ char *file; /* Filename (In history record) */
+ char *end; /* Ptr into repository to copy at end of workdir */
+ char *mod; /* The module within which the file is contained */
+ time_t date; /* Calculated from date stored in record */
+ long idx; /* Index of record, for "stable" sort. */
+} *hrec_head;
+static long hrec_idx;
+
+
+static void fill_hrec (char *line, struct hrec * hr);
+static int accept_hrec (struct hrec * hr, struct hrec * lr);
+static int select_hrec (struct hrec * hr);
+static int sort_order (const void *l, const void *r);
+static int within (char *find, char *string);
+static void expand_modules (void);
+static void read_hrecs (List *flist);
+static void report_hrecs (void);
+static void save_file (char *dir, char *name, char *module);
+static void save_module (char *module);
+static void save_user (char *name);
+
+#define USER_INCREMENT 2
+#define FILE_INCREMENT 128
+#define MODULE_INCREMENT 5
+#define HREC_INCREMENT 128
+
+static short report_count;
+
+static short extract;
+static short extract_all;
+static short v_checkout;
+static short modified;
+static short tag_report;
+static short module_report;
+static short working;
+static short last_entry;
+static short all_users;
+
+static short user_sort;
+static short repos_sort;
+static short file_sort;
+static short module_sort;
+
+static short tz_local;
+static time_t tz_seconds_east_of_GMT;
+static char *tz_name = "+0000";
+
+/* -r, -t, or -b options, malloc'd. These are "" if the option in
+ question is not specified or is overridden by another option. The
+ main reason for using "" rather than NULL is historical. Together
+ with since_date, these are a mutually exclusive set; one overrides the
+ others. */
+static char *since_rev;
+static char *since_tag;
+static char *backto;
+/* -D option, or 0 if not specified. RCS format. */
+static char * since_date;
+
+static struct hrec *last_since_tag;
+static struct hrec *last_backto;
+
+/* Record types to look for, malloc'd. Probably could be statically
+ allocated, but only if we wanted to check for duplicates more than
+ we do. */
+static char *rec_types;
+
+static int hrec_count;
+static int hrec_max;
+
+static char **user_list; /* Ptr to array of ptrs to user names */
+static int user_max; /* Number of elements allocated */
+static int user_count; /* Number of elements used */
+
+static struct file_list_str
+{
+ char *l_file;
+ char *l_module;
+} *file_list; /* Ptr to array file name structs */
+static int file_max; /* Number of elements allocated */
+static int file_count; /* Number of elements used */
+
+static char **mod_list; /* Ptr to array of ptrs to module names */
+static int mod_max; /* Number of elements allocated */
+static int mod_count; /* Number of elements used */
+
+/* This is pretty unclear. First of all, separating "flags" vs.
+ "options" (I think the distinction is that "options" take arguments)
+ is nonstandard, and not something we do elsewhere in CVS. Second of
+ all, what does "reports" mean? I think it means that you can only
+ supply one of those options, but "reports" hardly has that meaning in
+ a self-explanatory way. */
+static const char *const history_usg[] =
+{
+ "Usage: %s %s [-report] [-flags] [-options args] [files...]\n\n",
+ " Reports:\n",
+ " -T Produce report on all TAGs\n",
+ " -c Committed (Modified) files\n",
+ " -o Checked out modules\n",
+ " -m <module> Look for specified module (repeatable)\n",
+ " -x [" ALL_HISTORY_REC_TYPES "] Extract by record type\n",
+ " -e Everything (same as -x, but all record types)\n",
+ " Flags:\n",
+ " -a All users (Default is self)\n",
+ " -l Last modified (committed or modified report)\n",
+ " -w Working directory must match\n",
+ " Options:\n",
+ " -D <date> Since date (Many formats)\n",
+ " -b <str> Back to record with str in module/file/repos field\n",
+ " -f <file> Specified file (same as command line) (repeatable)\n",
+ " -n <modulename> In module (repeatable)\n",
+ " -p <repos> In repository (repeatable)\n",
+ " -r <rev/tag> Since rev or tag (looks inside RCS files!)\n",
+ " -t <tag> Since tag record placed in history file (by anyone).\n",
+ " -u <user> For user name (repeatable)\n",
+ " -z <tz> Output for time zone <tz> (e.g. -z -0700)\n",
+ NULL};
+
+/* Sort routine for qsort:
+ - If a user is selected at all, sort it first. User-within-file is useless.
+ - If a module was selected explicitly, sort next on module.
+ - Then sort by file. "File" is "repository/file" unless "working" is set,
+ then it is "workdir/file". (Revision order should always track date.)
+ - Always sort timestamp last.
+*/
+static int
+sort_order (const void *l, const void *r)
+{
+ int i;
+ const struct hrec *left = l;
+ const struct hrec *right = r;
+
+ if (user_sort) /* If Sort by username, compare users */
+ {
+ if ((i = strcmp (left->user, right->user)) != 0)
+ return i;
+ }
+ if (module_sort) /* If sort by modules, compare module names */
+ {
+ if (left->mod && right->mod)
+ if ((i = strcmp (left->mod, right->mod)) != 0)
+ return i;
+ }
+ if (repos_sort) /* If sort by repository, compare them. */
+ {
+ if ((i = strcmp (left->repos, right->repos)) != 0)
+ return i;
+ }
+ if (file_sort) /* If sort by filename, compare files, NOT dirs. */
+ {
+ if ((i = strcmp (left->file, right->file)) != 0)
+ return i;
+
+ if (working)
+ {
+ if ((i = strcmp (left->dir, right->dir)) != 0)
+ return i;
+
+ if ((i = strcmp (left->end, right->end)) != 0)
+ return i;
+ }
+ }
+
+ /*
+ * By default, sort by date, time
+ * XXX: This fails after 2030 when date slides into sign bit
+ */
+ if ((i = ((long) (left->date) - (long) (right->date))) != 0)
+ return i;
+
+ /* For matching dates, keep the sort stable by using record index */
+ return left->idx - right->idx;
+}
+
+
+
+/* Get the name of the history log, either from CVSROOT/config, or via the
+ * hard-coded default.
+ */
+static const char *
+get_history_log_name (time_t now)
+{
+ char *log_name;
+
+ if (config->HistoryLogPath)
+ {
+ /* ~, $VARs, and were expanded via expand_path() when CVSROOT/config
+ * was parsed.
+ */
+ log_name = xmalloc (PATH_MAX);
+ if (!now) now = time (NULL);
+ if (!strftime (log_name, PATH_MAX, config->HistoryLogPath,
+ localtime (&now)))
+ {
+ error (0, 0, "Invalid date format in HistoryLogPath.");
+ free (config->HistoryLogPath);
+ config->HistoryLogPath = NULL;
+ }
+ }
+
+ if (!config->HistoryLogPath)
+ {
+ /* Use the default. */
+ log_name = xmalloc (strlen (current_parsed_root->directory)
+ + sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_HISTORY) + 3);
+ sprintf (log_name, "%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_HISTORY);
+ }
+
+ return log_name;
+}
+
+
+
+int
+history (int argc, char **argv)
+{
+ int i, c;
+ const char *fname = NULL;
+ List *flist;
+
+ if (argc == -1)
+ usage (history_usg);
+
+ since_rev = xstrdup ("");
+ since_tag = xstrdup ("");
+ backto = xstrdup ("");
+ rec_types = xstrdup ("");
+ optind = 0;
+ while ((c = getopt (argc, argv, "+Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1)
+ {
+ switch (c)
+ {
+ case 'T': /* Tag list */
+ report_count++;
+ tag_report++;
+ break;
+ case 'a': /* For all usernames */
+ all_users++;
+ break;
+ case 'c':
+ report_count++;
+ modified = 1;
+ break;
+ case 'e':
+ report_count++;
+ extract_all++;
+ free (rec_types);
+ rec_types = xstrdup (ALL_HISTORY_REC_TYPES);
+ break;
+ case 'l': /* Find Last file record */
+ last_entry = 1;
+ break;
+ case 'o':
+ report_count++;
+ v_checkout = 1;
+ break;
+ case 'w': /* Match Working Dir (CurDir) fields */
+ working = 1;
+ break;
+ case 'X': /* Undocumented debugging flag */
+#ifdef DEBUG
+ fname = optarg;
+#endif
+ break;
+
+ case 'D': /* Since specified date */
+ if (*since_rev || *since_tag || *backto)
+ {
+ error (0, 0, "date overriding rev/tag/backto");
+ *since_rev = *since_tag = *backto = '\0';
+ }
+ since_date = Make_Date (optarg);
+ break;
+ case 'b': /* Since specified file/Repos */
+ if (since_date || *since_rev || *since_tag)
+ {
+ error (0, 0, "backto overriding date/rev/tag");
+ *since_rev = *since_tag = '\0';
+ if (since_date != NULL)
+ free (since_date);
+ since_date = NULL;
+ }
+ free (backto);
+ backto = xstrdup (optarg);
+ break;
+ case 'f': /* For specified file */
+ save_file (NULL, optarg, NULL);
+ break;
+ case 'm': /* Full module report */
+ if (!module_report++) report_count++;
+ /* fall through */
+ case 'n': /* Look for specified module */
+ save_module (optarg);
+ break;
+ case 'p': /* For specified directory */
+ save_file (optarg, NULL, NULL);
+ break;
+ case 'r': /* Since specified Tag/Rev */
+ if (since_date || *since_tag || *backto)
+ {
+ error (0, 0, "rev overriding date/tag/backto");
+ *since_tag = *backto = '\0';
+ if (since_date != NULL)
+ free (since_date);
+ since_date = NULL;
+ }
+ free (since_rev);
+ since_rev = xstrdup (optarg);
+ break;
+ case 't': /* Since specified Tag/Rev */
+ if (since_date || *since_rev || *backto)
+ {
+ error (0, 0, "tag overriding date/marker/file/repos");
+ *since_rev = *backto = '\0';
+ if (since_date != NULL)
+ free (since_date);
+ since_date = NULL;
+ }
+ free (since_tag);
+ since_tag = xstrdup (optarg);
+ break;
+ case 'u': /* For specified username */
+ save_user (optarg);
+ break;
+ case 'x':
+ report_count++;
+ extract++;
+ {
+ char *cp;
+
+ for (cp = optarg; *cp; cp++)
+ if (!strchr (ALL_HISTORY_REC_TYPES, *cp))
+ error (1, 0, "%c is not a valid report type", *cp);
+ }
+ free (rec_types);
+ rec_types = xstrdup (optarg);
+ break;
+ case 'z':
+ tz_local =
+ (optarg[0] == 'l' || optarg[0] == 'L')
+ && (optarg[1] == 't' || optarg[1] == 'T')
+ && !optarg[2];
+ if (tz_local)
+ tz_name = optarg;
+ else
+ {
+ /*
+ * Convert a known time with the given timezone to time_t.
+ * Use the epoch + 23 hours, so timezones east of GMT work.
+ */
+ struct timespec t;
+ char *buf = Xasprintf ("1/1/1970 23:00 %s", optarg);
+ if (get_date (&t, buf, NULL))
+ {
+ /*
+ * Convert to seconds east of GMT, removing the
+ * 23-hour offset mentioned above.
+ */
+ tz_seconds_east_of_GMT = (time_t)23 * 60 * 60
+ - t.tv_sec;
+ tz_name = optarg;
+ }
+ else
+ error (0, 0, "%s is not a known time zone", optarg);
+ free (buf);
+ }
+ break;
+ case '?':
+ default:
+ usage (history_usg);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ for (i = 0; i < argc; i++)
+ save_file (NULL, argv[i], NULL);
+
+
+ /* ================ Now analyze the arguments a bit */
+ if (!report_count)
+ v_checkout++;
+ else if (report_count > 1)
+ error (1, 0, "Only one report type allowed from: \"-Tcomxe\".");
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ struct file_list_str *f1;
+ char **mod;
+
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (tag_report)
+ send_arg ("-T");
+ if (all_users)
+ send_arg ("-a");
+ if (modified)
+ send_arg ("-c");
+ if (last_entry)
+ send_arg ("-l");
+ if (v_checkout)
+ send_arg ("-o");
+ if (working)
+ send_arg ("-w");
+ if (fname)
+ option_with_arg ("-X", fname);
+ if (since_date)
+ client_senddate (since_date);
+ if (backto[0] != '\0')
+ option_with_arg ("-b", backto);
+ for (f1 = file_list; f1 < &file_list[file_count]; ++f1)
+ {
+ if (f1->l_file[0] == '*')
+ option_with_arg ("-p", f1->l_file + 1);
+ else
+ option_with_arg ("-f", f1->l_file);
+ }
+ if (module_report)
+ send_arg ("-m");
+ for (mod = mod_list; mod < &mod_list[mod_count]; ++mod)
+ option_with_arg ("-n", *mod);
+ if (*since_rev)
+ option_with_arg ("-r", since_rev);
+ if (*since_tag)
+ option_with_arg ("-t", since_tag);
+ for (mod = user_list; mod < &user_list[user_count]; ++mod)
+ option_with_arg ("-u", *mod);
+ if (extract_all)
+ send_arg ("-e");
+ if (extract)
+ option_with_arg ("-x", rec_types);
+ option_with_arg ("-z", tz_name);
+
+ send_to_server ("history\012", 0);
+ return get_responses_and_close ();
+ }
+#endif
+
+ if (all_users)
+ save_user ("");
+
+ if (mod_list)
+ expand_modules ();
+
+ if (tag_report)
+ {
+ if (!strchr (rec_types, 'T'))
+ {
+ rec_types = xrealloc (rec_types, strlen (rec_types) + 5);
+ (void) strcat (rec_types, "T");
+ }
+ }
+ else if (extract || extract_all)
+ {
+ if (user_list)
+ user_sort++;
+ }
+ else if (modified)
+ {
+ free (rec_types);
+ rec_types = xstrdup ("MAR");
+ /*
+ * If the user has not specified a date oriented flag ("Since"), sort
+ * by Repository/file before date. Default is "just" date.
+ */
+ if (last_entry
+ || (!since_date && !*since_rev && !*since_tag && !*backto))
+ {
+ repos_sort++;
+ file_sort++;
+ /*
+ * If we are not looking for last_modified and the user specified
+ * one or more users to look at, sort by user before filename.
+ */
+ if (!last_entry && user_list)
+ user_sort++;
+ }
+ }
+ else if (module_report)
+ {
+ free (rec_types);
+ rec_types = xstrdup (last_entry ? "OMAR" : ALL_HISTORY_REC_TYPES);
+ module_sort++;
+ repos_sort++;
+ file_sort++;
+ working = 0; /* User's workdir doesn't count here */
+ }
+ else
+ /* Must be "checkout" or default */
+ {
+ free (rec_types);
+ rec_types = xstrdup ("OF");
+ /* See comments in "modified" above */
+ if (!last_entry && user_list)
+ user_sort++;
+ if (last_entry
+ || (!since_date && !*since_rev && !*since_tag && !*backto))
+ file_sort++;
+ }
+
+ /* If no users were specified, use self (-a saves a universal ("") user) */
+ if (!user_list)
+ save_user (getcaller ());
+
+ /* If we're looking back to a Tag value, must consider "Tag" records */
+ if (*since_tag && !strchr (rec_types, 'T'))
+ {
+ rec_types = xrealloc (rec_types, strlen (rec_types) + 5);
+ (void) strcat (rec_types, "T");
+ }
+
+ if (fname)
+ {
+ Node *p;
+
+ flist = getlist ();
+ p = getnode ();
+ p->type = FILES;
+ p->key = Xasprintf ("%s/%s/%s",
+ current_parsed_root->directory, CVSROOTADM, fname);
+ addnode (flist, p);
+ }
+ else
+ {
+ char *pat;
+
+ if (config->HistorySearchPath)
+ pat = config->HistorySearchPath;
+ else
+ pat = Xasprintf ("%s/%s/%s",
+ current_parsed_root->directory, CVSROOTADM,
+ CVSROOTADM_HISTORY);
+
+ flist = find_files (NULL, pat);
+ if (pat != config->HistorySearchPath) free (pat);
+ }
+
+ read_hrecs (flist);
+ if (hrec_count > 0)
+ qsort (hrec_head, hrec_count, sizeof (struct hrec), sort_order);
+ report_hrecs ();
+ if (since_date != NULL)
+ free (since_date);
+ free (since_rev);
+ free (since_tag);
+ free (backto);
+ free (rec_types);
+
+ return 0;
+}
+
+
+
+/* An empty LogHistory string in CVSROOT/config will turn logging off.
+ */
+void
+history_write (int type, const char *update_dir, const char *revs,
+ const char *name, const char *repository)
+{
+ const char *fname;
+ char *workdir;
+ char *username = getcaller ();
+ int fd;
+ char *line;
+ char *slash = "", *cp;
+ const char *cp2, *repos;
+ int i;
+ static char *tilde = "";
+ static char *PrCurDir = NULL;
+ time_t now;
+
+ if (logoff) /* History is turned off by noexec or
+ * readonlyfs.
+ */
+ return;
+ if (!strchr (config->logHistory, type))
+ return;
+
+ if (noexec)
+ goto out;
+
+ repos = Short_Repository (repository);
+
+ if (!PrCurDir)
+ {
+ char *pwdir;
+
+ pwdir = get_homedir ();
+ PrCurDir = CurDir;
+ if (pwdir != NULL)
+ {
+ /* Assumes neither CurDir nor pwdir ends in '/' */
+ i = strlen (pwdir);
+ if (!strncmp (CurDir, pwdir, i))
+ {
+ PrCurDir += i; /* Point to '/' separator */
+ tilde = "~";
+ }
+ else
+ {
+ /* Try harder to find a "homedir" */
+ struct saved_cwd cwd;
+ char *homedir;
+
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+
+ if (CVS_CHDIR (pwdir) < 0 || (homedir = xgetcwd ()) == NULL)
+ homedir = pwdir;
+
+ if (restore_cwd (&cwd))
+ error (1, errno,
+ "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+
+ i = strlen (homedir);
+ if (!strncmp (CurDir, homedir, i))
+ {
+ PrCurDir += i; /* Point to '/' separator */
+ tilde = "~";
+ }
+
+ if (homedir != pwdir)
+ free (homedir);
+ }
+ }
+ }
+
+ if (type == 'T')
+ {
+ repos = update_dir;
+ update_dir = "";
+ }
+ else if (update_dir && *update_dir)
+ slash = "/";
+ else
+ update_dir = "";
+
+ workdir = Xasprintf ("%s%s%s%s", tilde, PrCurDir, slash, update_dir);
+
+ /*
+ * "workdir" is the directory where the file "name" is. ("^~" == $HOME)
+ * "repos" is the Repository, relative to $CVSROOT where the RCS file is.
+ *
+ * "$workdir/$name" is the working file name.
+ * "$CVSROOT/$repos/$name,v" is the RCS file in the Repository.
+ *
+ * First, note that the history format was intended to save space, not
+ * to be human readable.
+ *
+ * The working file directory ("workdir") and the Repository ("repos")
+ * usually end with the same one or more directory elements. To avoid
+ * duplication (and save space), the "workdir" field ends with
+ * an integer offset into the "repos" field. This offset indicates the
+ * beginning of the "tail" of "repos", after which all characters are
+ * duplicates.
+ *
+ * In other words, if the "workdir" field has a '*' (a very stupid thing
+ * to put in a filename) in it, then every thing following the last '*'
+ * is a hex offset into "repos" of the first character from "repos" to
+ * append to "workdir" to finish the pathname.
+ *
+ * It might be easier to look at an example:
+ *
+ * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo
+ *
+ * Indicates that the workdir is really "~/work/cvs/examples", saving
+ * 10 characters, where "~/work*d" would save 6 characters and mean that
+ * the workdir is really "~/work/examples". It will mean more on
+ * directories like: usr/local/gnu/emacs/dist-19.17/lisp/term
+ *
+ * "workdir" is always an absolute pathname (~/xxx is an absolute path)
+ * "repos" is always a relative pathname. So we can assume that we will
+ * never run into the top of "workdir" -- there will always be a '/' or
+ * a '~' at the head of "workdir" that is not matched by anything in
+ * "repos". On the other hand, we *can* run off the top of "repos".
+ *
+ * Only "compress" if we save characters.
+ */
+
+ cp = workdir + strlen (workdir) - 1;
+ cp2 = repos + strlen (repos) - 1;
+ for (i = 0; cp2 >= repos && cp > workdir && *cp == *cp2--; cp--)
+ i++;
+
+ if (i > 2)
+ {
+ i = strlen (repos) - i;
+ (void) sprintf ((cp + 1), "*%x", i);
+ }
+
+ if (!revs)
+ revs = "";
+ now = time (NULL);
+ line = Xasprintf ("%c%08lx|%s|%s|%s|%s|%s\n", type, (long) now,
+ username, workdir, repos, revs, name);
+
+ fname = get_history_log_name (now);
+
+ if (!history_lock (current_parsed_root->directory))
+ /* history_lock() will already have printed an error on failure. */
+ goto out;
+
+ fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666);
+ if (fd < 0)
+ {
+ if (!really_quiet)
+ error (0, errno,
+ "warning: cannot open history file `%s' for write", fname);
+ goto out;
+ }
+
+ TRACE (TRACE_FUNCTION, "open (`%s', a)", fname);
+
+ /* Lessen some race conditions on non-Posix-compliant hosts.
+ *
+ * FIXME: I'm guessing the following was necessary for NFS when multiple
+ * simultaneous writes to the same file are possible, since NFS does not
+ * natively support append mode and it must be emulated via lseek(). Now
+ * that the history file is locked for write, the following lseek() may be
+ * unnecessary.
+ */
+ if (lseek (fd, (off_t) 0, SEEK_END) == -1)
+ error (1, errno, "cannot seek to end of history file: %s", fname);
+
+ if (write (fd, line, strlen (line)) < 0)
+ error (1, errno, "cannot write to history file: %s", fname);
+ free (line);
+ if (close (fd) != 0)
+ error (1, errno, "cannot close history file: %s", fname);
+ free (workdir);
+ out:
+ clear_history_lock ();
+}
+
+
+
+/*
+ * save_user() adds a user name to the user list to select. Zero-length
+ * username ("") matches any user.
+ */
+static void
+save_user (char *name)
+{
+ if (user_count == user_max)
+ {
+ user_max = xsum (user_max, USER_INCREMENT);
+ if (size_overflow_p (xtimes (user_max, sizeof (char *))))
+ {
+ error (0, 0, "save_user: too many users");
+ return;
+ }
+ user_list = xnrealloc (user_list, user_max, sizeof (char *));
+ }
+ user_list[user_count++] = xstrdup (name);
+}
+
+/*
+ * save_file() adds file name and associated module to the file list to select.
+ *
+ * If "dir" is null, store a file name as is.
+ * If "name" is null, store a directory name with a '*' on the front.
+ * Else, store concatenated "dir/name".
+ *
+ * Later, in the "select" stage:
+ * - if it starts with '*', it is prefix-matched against the repository.
+ * - if it has a '/' in it, it is matched against the repository/file.
+ * - else it is matched against the file name.
+ */
+static void
+save_file (char *dir, char *name, char *module)
+{
+ struct file_list_str *fl;
+
+ if (file_count == file_max)
+ {
+ file_max = xsum (file_max, FILE_INCREMENT);
+ if (size_overflow_p (xtimes (file_max, sizeof (*fl))))
+ {
+ error (0, 0, "save_file: too many files");
+ return;
+ }
+ file_list = xnrealloc (file_list, file_max, sizeof (*fl));
+ }
+ fl = &file_list[file_count++];
+ fl->l_module = module;
+
+ if (dir && *dir)
+ {
+ if (name && *name)
+ fl->l_file = Xasprintf ("%s/%s", dir, name);
+ else
+ fl->l_file = Xasprintf ("*%s", dir);
+ }
+ else
+ {
+ if (name && *name)
+ fl->l_file = xstrdup (name);
+ else
+ error (0, 0, "save_file: null dir and file name");
+ }
+}
+
+static void
+save_module (char *module)
+{
+ if (mod_count == mod_max)
+ {
+ mod_max = xsum (mod_max, MODULE_INCREMENT);
+ if (size_overflow_p (xtimes (mod_max, sizeof (char *))))
+ {
+ error (0, 0, "save_module: too many modules");
+ return;
+ }
+ mod_list = xnrealloc (mod_list, mod_max, sizeof (char *));
+ }
+ mod_list[mod_count++] = xstrdup (module);
+}
+
+static void
+expand_modules (void)
+{
+}
+
+/* fill_hrec
+ *
+ * Take a ptr to 7-part history line, ending with a newline, for example:
+ *
+ * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo
+ *
+ * Split it into 7 parts and drop the parts into a "struct hrec".
+ * Return a pointer to the character following the newline.
+ *
+ */
+
+#define NEXT_BAR(here) do { \
+ while (isspace (*line)) line++; \
+ hr->here = line; \
+ while ((c = *line++) && c != '|') ; \
+ if (!c) return; line[-1] = '\0'; \
+ } while (0)
+
+static void
+fill_hrec (char *line, struct hrec *hr)
+{
+ char *cp;
+ int c;
+
+ hr->type = hr->user = hr->dir = hr->repos = hr->rev = hr->file =
+ hr->end = hr->mod = NULL;
+ hr->date = -1;
+ hr->idx = ++hrec_idx;
+
+ while (isspace ((unsigned char) *line))
+ line++;
+
+ hr->type = line++;
+ hr->date = strtoul (line, &cp, 16);
+ if (cp == line || *cp != '|')
+ return;
+ line = cp + 1;
+ NEXT_BAR (user);
+ NEXT_BAR (dir);
+ if ((cp = strrchr (hr->dir, '*')) != NULL)
+ {
+ *cp++ = '\0';
+ hr->end = line + strtoul (cp, NULL, 16);
+ }
+ else
+ hr->end = line - 1; /* A handy pointer to '\0' */
+ NEXT_BAR (repos);
+ NEXT_BAR (rev);
+ if (strchr ("FOET", *(hr->type)))
+ hr->mod = line;
+
+ NEXT_BAR (file);
+}
+
+
+#ifndef STAT_BLOCKSIZE
+#if HAVE_STRUCT_STAT_ST_BLKSIZE
+#define STAT_BLOCKSIZE(s) (s).st_blksize
+#else
+#define STAT_BLOCKSIZE(s) (4 * 1024)
+#endif
+#endif
+
+
+/* read_hrecs_file's job is to read a history file and fill in new "hrec"
+ * (history record) array elements with the ones we need to print.
+ *
+ * Logic:
+ * - Read a block from the file.
+ * - Walk through the block parsing line into hr records.
+ * - if the hr isn't used, free its strings, if it is, bump the hrec counter
+ * - at the end of a block, copy the end of the current block to the start
+ * of space for the next block, then read in the next block. If we get less
+ * than the whole block, we're done.
+ */
+static int
+read_hrecs_file (Node *p, void *closure)
+{
+ char *cpstart, *cpend, *cp, *nl;
+ char *hrline;
+ int i;
+ int fd;
+ struct stat st_buf;
+ const char *fname = p->key;
+
+ if ((fd = CVS_OPEN (fname, O_RDONLY | OPEN_BINARY)) < 0)
+ {
+ error (0, errno, "cannot open history file `%s'", fname);
+ return 0;
+ }
+
+ if (fstat (fd, &st_buf) < 0)
+ {
+ error (0, errno, "can't stat history file `%s'", fname);
+ return 0;
+ }
+
+ if (!(st_buf.st_size))
+ {
+ error (0, 0, "history file `%s' is empty", fname);
+ return 0;
+ }
+
+ cpstart = xnmalloc (2, STAT_BLOCKSIZE (st_buf));
+ cpstart[0] = '\0';
+ cp = cpend = cpstart;
+
+ for (;;)
+ {
+ for (nl = cp; nl < cpend && *nl != '\n'; nl++)
+ if (!isprint (*nl)) *nl = ' ';
+
+ if (nl >= cpend)
+ {
+ if (nl - cp >= STAT_BLOCKSIZE (st_buf))
+ {
+ error(1, 0, "history line %ld too long (> %lu)", hrec_idx + 1,
+ (unsigned long) STAT_BLOCKSIZE(st_buf));
+ }
+ if (nl > cp)
+ memmove (cpstart, cp, nl - cp);
+ nl = cpstart + (nl - cp);
+ cp = cpstart;
+ i = read (fd, nl, STAT_BLOCKSIZE(st_buf));
+ if (i > 0)
+ {
+ cpend = nl + i;
+ *cpend = '\0';
+ continue;
+ }
+ if (i < 0)
+ {
+ error (0, errno, "error reading history file `%s'", fname);
+ return 0;
+ }
+ if (nl == cp) break;
+ error (0, 0, "warning: no newline at end of history file `%s'",
+ fname);
+ }
+ *nl = '\0';
+
+ if (hrec_count == hrec_max)
+ {
+ struct hrec *old_head = hrec_head;
+
+ hrec_max += HREC_INCREMENT;
+ hrec_head = xnrealloc (hrec_head, hrec_max, sizeof (struct hrec));
+ if (last_since_tag)
+ last_since_tag = hrec_head + (last_since_tag - old_head);
+ if (last_backto)
+ last_backto = hrec_head + (last_backto - old_head);
+ }
+
+ /* fill_hrec dates from when history read the entire
+ history file in one chunk, and then records were pulled out
+ by pointing to the various parts of this big chunk. This is
+ why there are ugly hacks here: I don't want to completely
+ re-write the whole history stuff right now. */
+
+ hrline = xstrdup (cp);
+ fill_hrec (hrline, &hrec_head[hrec_count]);
+ if (select_hrec (&hrec_head[hrec_count]))
+ hrec_count++;
+ else
+ free (hrline);
+
+ cp = nl + 1;
+ }
+ free (cpstart);
+ close (fd);
+ return 1;
+}
+
+
+
+/* Read the history records in from a list of history files. */
+static void
+read_hrecs (List *flist)
+{
+ int files_read;
+
+ /* The global history records are already initialized to 0 according to
+ * ANSI C.
+ */
+ hrec_max = HREC_INCREMENT;
+ hrec_head = xmalloc (hrec_max * sizeof (struct hrec));
+ hrec_idx = 0;
+
+ files_read = walklist (flist, read_hrecs_file, NULL);
+ if (!files_read)
+ error (1, 0, "No history files read.");
+
+ /* Special selection problem: If "since_tag" is set, we have saved every
+ * record from the 1st occurrence of "since_tag", when we want to save
+ * records since the *last* occurrence of "since_tag". So what we have
+ * to do is bump hrec_head forward and reduce hrec_count accordingly.
+ */
+ if (last_since_tag)
+ {
+ hrec_count -= (last_since_tag - hrec_head);
+ hrec_head = last_since_tag;
+ }
+
+ /* Much the same thing is necessary for the "backto" option. */
+ if (last_backto)
+ {
+ hrec_count -= (last_backto - hrec_head);
+ hrec_head = last_backto;
+ }
+}
+
+
+
+/* Utility program for determining whether "find" is inside "string" */
+static int
+within (char *find, char *string)
+{
+ int c, len;
+
+ if (!find || !string)
+ return 0;
+
+ c = *find++;
+ len = strlen (find);
+
+ while (*string)
+ {
+ if (!(string = strchr (string, c)))
+ return 0;
+ string++;
+ if (!strncmp (find, string, len))
+ return 1;
+ }
+ return 0;
+}
+
+/* The purpose of "select_hrec" is to apply the selection criteria based on
+ * the command arguments and defaults and return a flag indicating whether
+ * this record should be remembered for printing.
+ */
+static int
+select_hrec (struct hrec *hr)
+{
+ char **cpp, *cp, *cp2;
+ struct file_list_str *fl;
+ int count;
+
+ /* basic validity checking */
+ if (!hr->type || !hr->user || !hr->dir || !hr->repos || !hr->rev ||
+ !hr->file || !hr->end)
+ {
+ error (0, 0, "warning: history line %ld invalid", hr->idx);
+ return 0;
+ }
+
+ /* "Since" checking: The argument parser guarantees that only one of the
+ * following four choices is set:
+ *
+ * 1. If "since_date" is set, it contains the date specified on the
+ * command line. hr->date fields earlier than "since_date" are ignored.
+ * 2. If "since_rev" is set, it contains either an RCS "dotted" revision
+ * number (which is of limited use) or a symbolic TAG. Each RCS file
+ * is examined and the date on the specified revision (or the revision
+ * corresponding to the TAG) in the RCS file (CVSROOT/repos/file) is
+ * compared against hr->date as in 1. above.
+ * 3. If "since_tag" is set, matching tag records are saved. The field
+ * "last_since_tag" is set to the last one of these. Since we don't
+ * know where the last one will be, all records are saved from the
+ * first occurrence of the TAG. Later, at the end of "select_hrec"
+ * records before the last occurrence of "since_tag" are skipped.
+ * 4. If "backto" is set, all records with a module name or file name
+ * matching "backto" are saved. In addition, all records with a
+ * repository field with a *prefix* matching "backto" are saved.
+ * The field "last_backto" is set to the last one of these. As in
+ * 3. above, "select_hrec" adjusts to include the last one later on.
+ */
+ if (since_date)
+ {
+ char *ourdate = date_from_time_t (hr->date);
+ count = RCS_datecmp (ourdate, since_date);
+ free (ourdate);
+ if (count < 0)
+ return 0;
+ }
+ else if (*since_rev)
+ {
+ Vers_TS *vers;
+ time_t t;
+ struct file_info finfo;
+
+ memset (&finfo, 0, sizeof finfo);
+ finfo.file = hr->file;
+ /* Not used, so don't worry about it. */
+ finfo.update_dir = NULL;
+ finfo.fullname = finfo.file;
+ finfo.repository = hr->repos;
+ finfo.entries = NULL;
+ finfo.rcs = NULL;
+
+ vers = Version_TS (&finfo, NULL, since_rev, NULL, 1, 0);
+ if (vers->vn_rcs)
+ {
+ if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, NULL, 0))
+ != (time_t) 0)
+ {
+ if (hr->date < t)
+ {
+ freevers_ts (&vers);
+ return 0;
+ }
+ }
+ }
+ freevers_ts (&vers);
+ }
+ else if (*since_tag)
+ {
+ if (*(hr->type) == 'T')
+ {
+ /*
+ * A 'T'ag record, the "rev" field holds the tag to be set,
+ * while the "repos" field holds "D"elete, "A"dd or a rev.
+ */
+ if (within (since_tag, hr->rev))
+ {
+ last_since_tag = hr;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ if (!last_since_tag)
+ return 0;
+ }
+ else if (*backto)
+ {
+ if (within (backto, hr->file) || within (backto, hr->mod) ||
+ within (backto, hr->repos))
+ last_backto = hr;
+ else
+ return 0;
+ }
+
+ /* User checking:
+ *
+ * Run down "user_list", match username ("" matches anything)
+ * If "" is not there and actual username is not there, return failure.
+ */
+ if (user_list && hr->user)
+ {
+ for (cpp = user_list, count = user_count; count; cpp++, count--)
+ {
+ if (!**cpp)
+ break; /* null user == accept */
+ if (!strcmp (hr->user, *cpp)) /* found listed user */
+ break;
+ }
+ if (!count)
+ return 0; /* Not this user */
+ }
+
+ /* Record type checking:
+ *
+ * 1. If Record type is not in rec_types field, skip it.
+ * 2. If mod_list is null, keep everything. Otherwise keep only modules
+ * on mod_list.
+ * 3. If neither a 'T', 'F' nor 'O' record, run through "file_list". If
+ * file_list is null, keep everything. Otherwise, keep only files on
+ * file_list, matched appropriately.
+ */
+ if (!strchr (rec_types, *(hr->type)))
+ return 0;
+ if (!strchr ("TFOE", *(hr->type))) /* Don't bother with "file" if "TFOE" */
+ {
+ if (file_list) /* If file_list is null, accept all */
+ {
+ for (fl = file_list, count = file_count; count; fl++, count--)
+ {
+ /* 1. If file_list entry starts with '*', skip the '*' and
+ * compare it against the repository in the hrec.
+ * 2. If file_list entry has a '/' in it, compare it against
+ * the concatenation of the repository and file from hrec.
+ * 3. Else compare the file_list entry against the hrec file.
+ */
+ char *cmpfile = NULL;
+
+ if (*(cp = fl->l_file) == '*')
+ {
+ cp++;
+ /* if argument to -p is a prefix of repository */
+ if (!strncmp (cp, hr->repos, strlen (cp)))
+ {
+ hr->mod = fl->l_module;
+ break;
+ }
+ }
+ else
+ {
+ if (strchr (cp, '/'))
+ {
+ cmpfile = Xasprintf ("%s/%s", hr->repos, hr->file);
+ cp2 = cmpfile;
+ }
+ else
+ {
+ cp2 = hr->file;
+ }
+
+ /* if requested file is found within {repos}/file fields */
+ if (within (cp, cp2))
+ {
+ hr->mod = fl->l_module;
+ if (cmpfile != NULL)
+ free (cmpfile);
+ break;
+ }
+ if (cmpfile != NULL)
+ free (cmpfile);
+ }
+ }
+ if (!count)
+ return 0; /* String specified and no match */
+ }
+ }
+ if (mod_list)
+ {
+ for (cpp = mod_list, count = mod_count; count; cpp++, count--)
+ {
+ if (hr->mod && !strcmp (hr->mod, *cpp)) /* found module */
+ break;
+ }
+ if (!count)
+ return 0; /* Module specified & this record is not one of them. */
+ }
+
+ return 1; /* Select this record unless rejected above. */
+}
+
+/* The "sort_order" routine (when handed to qsort) has arranged for the
+ * hrecs files to be in the right order for the report.
+ *
+ * Most of the "selections" are done in the select_hrec routine, but some
+ * selections are more easily done after the qsort by "accept_hrec".
+ */
+static void
+report_hrecs (void)
+{
+ struct hrec *hr, *lr;
+ struct tm *tm;
+ int i, count, ty;
+ char *cp;
+ int user_len, file_len, rev_len, mod_len, repos_len;
+
+ if (*since_tag && !last_since_tag)
+ {
+ (void) printf ("No tag found: %s\n", since_tag);
+ return;
+ }
+ else if (*backto && !last_backto)
+ {
+ (void) printf ("No module, file or repository with: %s\n", backto);
+ return;
+ }
+ else if (hrec_count < 1)
+ {
+ (void) printf ("No records selected.\n");
+ return;
+ }
+
+ user_len = file_len = rev_len = mod_len = repos_len = 0;
+
+ /* Run through lists and find maximum field widths */
+ hr = lr = hrec_head;
+ hr++;
+ for (count = hrec_count; count--; lr = hr, hr++)
+ {
+ char *repos;
+
+ if (!count)
+ hr = NULL;
+ if (!accept_hrec (lr, hr))
+ continue;
+
+ ty = *(lr->type);
+ repos = xstrdup (lr->repos);
+ if ((cp = strrchr (repos, '/')) != NULL)
+ {
+ if (lr->mod && !strcmp (++cp, lr->mod))
+ {
+ (void) strcpy (cp, "*");
+ }
+ }
+ if ((i = strlen (lr->user)) > user_len)
+ user_len = i;
+ if ((i = strlen (lr->file)) > file_len)
+ file_len = i;
+ if (ty != 'T' && (i = strlen (repos)) > repos_len)
+ repos_len = i;
+ if (ty != 'T' && (i = strlen (lr->rev)) > rev_len)
+ rev_len = i;
+ if (lr->mod && (i = strlen (lr->mod)) > mod_len)
+ mod_len = i;
+ free (repos);
+ }
+
+ /* Walk through hrec array setting "lr" (Last Record) to each element.
+ * "hr" points to the record following "lr" -- It is NULL in the last
+ * pass.
+ *
+ * There are two sections in the loop below:
+ * 1. Based on the report type (e.g. extract, checkout, tag, etc.),
+ * decide whether the record should be printed.
+ * 2. Based on the record type, format and print the data.
+ */
+ for (lr = hrec_head, hr = (lr + 1); hrec_count--; lr = hr, hr++)
+ {
+ char *workdir;
+ char *repos;
+
+ if (!hrec_count)
+ hr = NULL;
+ if (!accept_hrec (lr, hr))
+ continue;
+
+ ty = *(lr->type);
+ if (!tz_local)
+ {
+ time_t t = lr->date + tz_seconds_east_of_GMT;
+ tm = gmtime (&t);
+ }
+ else
+ tm = localtime (&(lr->date));
+
+ (void) printf ("%c %04d-%02d-%02d %02d:%02d %s %-*s", ty,
+ tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
+ tm->tm_min, tz_name, user_len, lr->user);
+
+ workdir = xmalloc (strlen (lr->dir) + strlen (lr->end) + 10);
+ (void) sprintf (workdir, "%s%s", lr->dir, lr->end);
+ if ((cp = strrchr (workdir, '/')) != NULL)
+ {
+ if (lr->mod && !strcmp (++cp, lr->mod))
+ {
+ (void) strcpy (cp, "*");
+ }
+ }
+ repos = xmalloc (strlen (lr->repos) + 10);
+ (void) strcpy (repos, lr->repos);
+ if ((cp = strrchr (repos, '/')) != NULL)
+ {
+ if (lr->mod && !strcmp (++cp, lr->mod))
+ {
+ (void) strcpy (cp, "*");
+ }
+ }
+
+ switch (ty)
+ {
+ case 'T':
+ /* 'T'ag records: repository is a "tag type", rev is the tag */
+ (void) printf (" %-*s [%s:%s]", mod_len, lr->mod, lr->rev,
+ repos);
+ if (working)
+ (void) printf (" {%s}", workdir);
+ break;
+ case 'F':
+ case 'E':
+ case 'O':
+ if (lr->rev && *(lr->rev))
+ (void) printf (" [%s]", lr->rev);
+ (void) printf (" %-*s =%s%-*s %s", repos_len, repos, lr->mod,
+ mod_len + 1 - (int) strlen (lr->mod),
+ "=", workdir);
+ break;
+ case 'W':
+ case 'U':
+ case 'P':
+ case 'C':
+ case 'G':
+ case 'M':
+ case 'A':
+ case 'R':
+ (void) printf (" %-*s %-*s %-*s =%s= %s", rev_len, lr->rev,
+ file_len, lr->file, repos_len, repos,
+ lr->mod ? lr->mod : "", workdir);
+ break;
+ default:
+ (void) printf ("Hey! What is this junk? RecType[0x%2.2x]", ty);
+ break;
+ }
+ (void) putchar ('\n');
+ free (workdir);
+ free (repos);
+ }
+}
+
+static int
+accept_hrec (struct hrec *lr, struct hrec *hr)
+{
+ int ty;
+
+ ty = *(lr->type);
+
+ if (last_since_tag && ty == 'T')
+ return 1;
+
+ if (v_checkout)
+ {
+ if (ty != 'O')
+ return 0; /* Only interested in 'O' records */
+
+ /* We want to identify all the states that cause the next record
+ * ("hr") to be different from the current one ("lr") and only
+ * print a line at the allowed boundaries.
+ */
+
+ if (!hr || /* The last record */
+ strcmp (hr->user, lr->user) || /* User has changed */
+ strcmp (hr->mod, lr->mod) ||/* Module has changed */
+ (working && /* If must match "workdir" */
+ (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */
+ strcmp (hr->end, lr->end)))) /* the 2nd parts differ */
+
+ return 1;
+ }
+ else if (modified)
+ {
+ if (!last_entry || /* Don't want only last rec */
+ !hr || /* Last entry is a "last entry" */
+ strcmp (hr->repos, lr->repos) || /* Repository has changed */
+ strcmp (hr->file, lr->file))/* File has changed */
+ return 1;
+
+ if (working)
+ { /* If must match "workdir" */
+ if (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */
+ strcmp (hr->end, lr->end)) /* the 2nd parts differ */
+ return 1;
+ }
+ }
+ else if (module_report)
+ {
+ if (!last_entry || /* Don't want only last rec */
+ !hr || /* Last entry is a "last entry" */
+ strcmp (hr->mod, lr->mod) ||/* Module has changed */
+ strcmp (hr->repos, lr->repos) || /* Repository has changed */
+ strcmp (hr->file, lr->file))/* File has changed */
+ return 1;
+ }
+ else
+ {
+ /* "extract" and "tag_report" always print selected records. */
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/history.h b/src/history.h
new file mode 100644
index 0000000..8b2ba13
--- /dev/null
+++ b/src/history.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2003-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 2003-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS source
+ * distribution.
+ *
+ * This is the header file for definitions and functions shared by history.c
+ * with other portions of CVS.
+ */
+
+#ifndef HISTORY_H
+# define HISTORY_H
+#define ALL_HISTORY_REC_TYPES "TOEFWUPCGMAR"
+#endif /* HISTORY_H */
diff --git a/src/ignore.c b/src/ignore.c
new file mode 100644
index 0000000..756066d
--- /dev/null
+++ b/src/ignore.c
@@ -0,0 +1,486 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/*
+ * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
+ */
+
+#include "cvs.h"
+#include "getline.h"
+#include "lstat.h"
+
+/*
+ * Ignore file section.
+ *
+ * "!" may be included any time to reset the list (i.e. ignore nothing);
+ * "*" may be specified to ignore everything. It stays as the first
+ * element forever, unless a "!" clears it out.
+ */
+
+static char **ign_list; /* List of files to ignore in update
+ * and import */
+static char **s_ign_list = NULL;
+static int ign_count; /* Number of active entries */
+static int s_ign_count = 0;
+static int ign_size; /* This many slots available (plus
+ * one for a NULL) */
+static int ign_hold = -1; /* Index where first "temporary" item
+ * is held */
+
+const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
+ .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
+ *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
+
+#define IGN_GROW 16 /* grow the list by 16 elements at a
+ * time */
+
+/* Nonzero if we have encountered an -I ! directive, which means one should
+ no longer ask the server about what is in CVSROOTADM_IGNORE. */
+int ign_inhibit_server;
+
+
+
+/*
+ * To the "ignore list", add the hard-coded default ignored wildcards above,
+ * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
+ * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
+ * variable.
+ */
+void
+ign_setup (void)
+{
+ char *home_dir;
+ char *tmp;
+
+ ign_inhibit_server = 0;
+
+ /* Start with default list and special case */
+ tmp = xstrdup (ign_default);
+ ign_add (tmp, 0);
+ free (tmp);
+
+ /* The client handles another way, by (after it does its own ignore file
+ processing, and only if !ign_inhibit_server), letting the server
+ know about the files and letting it decide whether to ignore
+ them based on CVSROOOTADM_IGNORE. */
+ if (!current_parsed_root->isremote)
+ {
+ char *file = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_IGNORE);
+ /* Then add entries found in repository, if it exists */
+ ign_add_file (file, 0);
+ free (file);
+ }
+
+ /* Then add entries found in home dir, (if user has one) and file exists */
+ home_dir = get_homedir ();
+ /* If we can't find a home directory, ignore ~/.cvsignore. This may
+ make tracking down problems a bit of a pain, but on the other
+ hand it might be obnoxious to complain when CVS will function
+ just fine without .cvsignore (and many users won't even know what
+ .cvsignore is). */
+ if (home_dir)
+ {
+ char *file = strcat_filename_onto_homedir (home_dir, CVSDOTIGNORE);
+ ign_add_file (file, 0);
+ free (file);
+ }
+
+ /* Then add entries found in CVSIGNORE environment variable. */
+ ign_add (getenv (IGNORE_ENV), 0);
+
+ /* Later, add ignore entries found in -I arguments */
+}
+
+
+
+/*
+ * Open a file and read lines, feeding each line to a line parser. Arrange
+ * for keeping a temporary list of wildcards at the end, if the "hold"
+ * argument is set.
+ */
+void
+ign_add_file (char *file, int hold)
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t line_allocated = 0;
+
+ /* restore the saved list (if any) */
+ if (s_ign_list != NULL)
+ {
+ int i;
+
+ for (i = 0; i < s_ign_count; i++)
+ ign_list[i] = s_ign_list[i];
+ ign_count = s_ign_count;
+ ign_list[ign_count] = NULL;
+
+ s_ign_count = 0;
+ free (s_ign_list);
+ s_ign_list = NULL;
+ }
+
+ /* is this a temporary ignore file? */
+ if (hold)
+ {
+ /* re-set if we had already done a temporary file */
+ if (ign_hold >= 0)
+ {
+ int i;
+
+ for (i = ign_hold; i < ign_count; i++)
+ free (ign_list[i]);
+ ign_count = ign_hold;
+ ign_list[ign_count] = NULL;
+ }
+ else
+ {
+ ign_hold = ign_count;
+ }
+ }
+
+ /* load the file */
+ fp = CVS_FOPEN (file, "r");
+ if (fp == NULL)
+ {
+ if (! existence_error (errno))
+ error (0, errno, "cannot open %s", file);
+ return;
+ }
+ while (getline (&line, &line_allocated, fp) >= 0)
+ ign_add (line, hold);
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", file);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", file);
+ free (line);
+}
+
+
+
+/* Parse a line of space-separated wildcards and add them to the list. */
+void
+ign_add (char *ign, int hold)
+{
+ if (!ign || !*ign)
+ return;
+
+ for (; *ign; ign++)
+ {
+ char *mark;
+ char save;
+
+ /* ignore whitespace before the token */
+ if (isspace ((unsigned char) *ign))
+ continue;
+
+ /* If we have used up all the space, add some more. Do this before
+ processing `!', since an "empty" list still contains the `CVS'
+ entry. */
+ if (ign_count >= ign_size)
+ {
+ ign_size += IGN_GROW;
+ ign_list = xnrealloc (ign_list, ign_size + 1, sizeof (char *));
+ }
+
+ /*
+ * if we find a single character !, we must re-set the ignore list
+ * (saving it if necessary). We also catch * as a special case in a
+ * global ignore file as an optimization
+ */
+ if ((!*(ign+1) || isspace ((unsigned char) *(ign+1)))
+ && (*ign == '!' || *ign == '*'))
+ {
+ if (!hold)
+ {
+ /* permanently reset the ignore list */
+ int i;
+
+ for (i = 0; i < ign_count; i++)
+ free (ign_list[i]);
+ ign_count = 1;
+ /* Always ignore the "CVS" directory. */
+ ign_list[0] = xstrdup ("CVS");
+ ign_list[1] = NULL;
+
+ /* if we are doing a '!', continue; otherwise add the '*' */
+ if (*ign == '!')
+ {
+ ign_inhibit_server = 1;
+ continue;
+ }
+ }
+ else if (*ign == '!')
+ {
+ /* temporarily reset the ignore list */
+ int i;
+
+ if (ign_hold >= 0)
+ {
+ for (i = ign_hold; i < ign_count; i++)
+ free (ign_list[i]);
+ ign_hold = -1;
+ }
+ if (s_ign_list)
+ {
+ /* Don't save the ignore list twice - if there are two
+ * bangs in a local .cvsignore file then we don't want to
+ * save the new list the first bang created.
+ *
+ * We still need to free the "new" ignore list.
+ */
+ for (i = 0; i < ign_count; i++)
+ free (ign_list[i]);
+ }
+ else
+ {
+ /* Save the ignore list for later. */
+ s_ign_list = xnmalloc (ign_count, sizeof (char *));
+ for (i = 0; i < ign_count; i++)
+ s_ign_list[i] = ign_list[i];
+ s_ign_count = ign_count;
+ }
+ ign_count = 1;
+ /* Always ignore the "CVS" directory. */
+ ign_list[0] = xstrdup ("CVS");
+ ign_list[1] = NULL;
+ continue;
+ }
+ }
+
+ /* find the end of this token */
+ for (mark = ign; *mark && !isspace ((unsigned char) *mark); mark++)
+ /* do nothing */ ;
+
+ save = *mark;
+ *mark = '\0';
+
+ ign_list[ign_count++] = xstrdup (ign);
+ ign_list[ign_count] = NULL;
+
+ *mark = save;
+ if (save)
+ ign = mark;
+ else
+ ign = mark - 1;
+ }
+}
+
+
+
+/* Return true if the given filename should be ignored by update or import,
+ * else return false.
+ */
+int
+ign_name (char *name)
+{
+ char **cpp = ign_list;
+
+ if (cpp == NULL)
+ return 0;
+
+ while (*cpp)
+ if (CVS_FNMATCH (*cpp++, name, 0) == 0)
+ return 1;
+
+ return 0;
+}
+
+
+
+/* FIXME: This list of dirs to ignore stuff seems not to be used.
+ Really? send_dirent_proc and update_dirent_proc both call
+ ignore_directory and do_module calls ign_dir_add. No doubt could
+ use some documentation/testsuite work. */
+
+static char **dir_ign_list = NULL;
+static int dir_ign_max = 0;
+static int dir_ign_current = 0;
+
+/* Add a directory to list of dirs to ignore. */
+void
+ign_dir_add (char *name)
+{
+ /* Make sure we've got the space for the entry. */
+ if (dir_ign_current <= dir_ign_max)
+ {
+ dir_ign_max += IGN_GROW;
+ dir_ign_list = xnrealloc (dir_ign_list,
+ dir_ign_max + 1, sizeof (char *));
+ }
+
+ dir_ign_list[dir_ign_current++] = xstrdup (name);
+}
+
+
+/* Return nonzero if NAME is part of the list of directories to ignore. */
+
+int
+ignore_directory (const char *name)
+{
+ int i;
+
+ if (!dir_ign_list)
+ return 0;
+
+ i = dir_ign_current;
+ while (i--)
+ {
+ if (strncmp (name, dir_ign_list[i], strlen (dir_ign_list[i])+1) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Process the current directory, looking for files not in ILIST and
+ * not on the global ignore list for this directory. If we find one,
+ * call PROC passing it the name of the file and the update dir.
+ * ENTRIES is the entries list, which is used to identify known
+ * directories. ENTRIES may be NULL, in which case we assume that any
+ * directory with a CVS administration directory is known.
+ */
+void
+ignore_files (List *ilist, List *entries, const char *update_dir,
+ Ignore_proc proc)
+{
+ int subdirs;
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat sb;
+ char *file;
+ const char *xdir;
+ List *files;
+ Node *p;
+
+ /* Set SUBDIRS if we have subdirectory information in ENTRIES. */
+ if (entries == NULL)
+ subdirs = 0;
+ else
+ {
+ struct stickydirtag *sdtp = entries->list->data;
+
+ subdirs = sdtp == NULL || sdtp->subdirs;
+ }
+
+ /* we get called with update_dir set to "." sometimes... strip it */
+ if (strcmp (update_dir, ".") == 0)
+ xdir = "";
+ else
+ xdir = update_dir;
+
+ dirp = CVS_OPENDIR (".");
+ if (dirp == NULL)
+ {
+ error (0, errno, "cannot open current directory");
+ return;
+ }
+
+ ign_add_file (CVSDOTIGNORE, 1);
+ wrap_add_file (CVSDOTWRAPPER, 1);
+
+ /* Make a list for the files. */
+ files = getlist ();
+
+ while (errno = 0, (dp = CVS_READDIR (dirp)) != NULL)
+ {
+ file = dp->d_name;
+ if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
+ continue;
+ if (findnode_fn (ilist, file) != NULL)
+ continue;
+ if (subdirs)
+ {
+ Node *node;
+
+ node = findnode_fn (entries, file);
+ if (node != NULL
+ && ((Entnode *) node->data)->type == ENT_SUBDIR)
+ {
+ char *p;
+ int dir;
+
+ /* For consistency with past behaviour, we only ignore
+ this directory if there is a CVS subdirectory.
+ This will normally be the case, but the user may
+ have messed up the working directory somehow. */
+ p = Xasprintf ("%s/%s", file, CVSADM);
+ dir = isdir (p);
+ free (p);
+ if (dir)
+ continue;
+ }
+ }
+
+ /* We could be ignoring FIFOs and other files which are neither
+ regular files nor directories here. */
+ if (ign_name (file))
+ continue;
+
+ if (
+#ifdef DT_DIR
+ dp->d_type != DT_UNKNOWN ||
+#endif
+ lstat (file, &sb) != -1)
+ {
+
+ if (
+#ifdef DT_DIR
+ dp->d_type == DT_DIR
+ || (dp->d_type == DT_UNKNOWN && S_ISDIR (sb.st_mode))
+#else
+ S_ISDIR (sb.st_mode)
+#endif
+ )
+ {
+ if (!subdirs)
+ {
+ char *temp = Xasprintf ("%s/%s", file, CVSADM);
+ if (isdir (temp))
+ {
+ free (temp);
+ continue;
+ }
+ free (temp);
+ }
+ }
+#ifdef S_ISLNK
+ else if (
+#ifdef DT_DIR
+ dp->d_type == DT_LNK
+ || (dp->d_type == DT_UNKNOWN && S_ISLNK (sb.st_mode))
+#else
+ S_ISLNK (sb.st_mode)
+#endif
+ )
+ {
+ continue;
+ }
+#endif
+ }
+
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (file);
+ (void) addnode (files, p);
+ }
+ if (errno != 0)
+ error (0, errno, "error reading current directory");
+ (void) CVS_CLOSEDIR (dirp);
+
+ sortlist (files, fsortcmp);
+ for (p = files->list->next; p != files->list; p = p->next)
+ (*proc) (p->key, xdir);
+ dellist (&files);
+}
diff --git a/src/import.c b/src/import.c
new file mode 100644
index 0000000..0ced5ee
--- /dev/null
+++ b/src/import.c
@@ -0,0 +1,1778 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * "import" checks in the vendor release located in the current directory into
+ * the CVS source repository. The CVS vendor branch support is utilized.
+ *
+ * At least three arguments are expected to follow the options:
+ * repository Where the source belongs relative to the CVSROOT
+ * VendorTag Vendor's major tag
+ * VendorReleTag Tag for this particular release
+ *
+ * Additional arguments specify more Vendor Release Tags.
+ */
+
+#include "cvs.h"
+#include "lstat.h"
+#include "save-cwd.h"
+
+static char *get_comment (const char *user);
+static int add_rev (char *message, RCSNode *rcs, char *vfile,
+ char *vers);
+static int add_tags (RCSNode *rcs, char *vfile, char *vtag, int targc,
+ char *targv[]);
+static int import_descend (char *message, char *vtag, int targc, char *targv[]);
+static int import_descend_dir (char *message, char *dir, char *vtag,
+ int targc, char *targv[]);
+static int process_import_file (char *message, char *vfile, char *vtag,
+ int targc, char *targv[]);
+static int update_rcs_file (char *message, char *vfile, char *vtag, int targc,
+ char *targv[], int inattic);
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+static int preserve_initial_permissions (FILE *fprcs, const char *userfile,
+ mode_t file_type, struct stat *sbp);
+#endif
+static int expand_and_copy_contents (FILE *fprcs, mode_t file_type,
+ const char *user, FILE *fpuser);
+static void add_log (int ch, char *fname);
+
+static int repos_len;
+static char *vhead;
+static char *vbranch;
+static FILE *logfp;
+static char *repository;
+static int conflicts;
+static int use_file_modtime;
+static char *keyword_opt = NULL;
+static bool killnew;
+
+static const char *const import_usage[] =
+{
+ "Usage: %s %s [-dX] [-k subst] [-I ign] [-m msg] [-b branch]\n",
+ " [-W spec] repository vendor-tag release-tags...\n",
+ "\t-d\tUse the file's modification time as the time of import.\n",
+ "\t-X\tWhen importing new files, mark their trunk revisions as dead.\n",
+ "\t-k sub\tSet default RCS keyword substitution mode.\n",
+ "\t-I ign\tMore files to ignore (! to reset).\n",
+ "\t-b bra\tVendor branch id.\n",
+ "\t-m msg\tLog message.\n",
+ "\t-W spec\tWrappers specification line.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+import (int argc, char **argv)
+{
+ char *message = NULL;
+ char *tmpfile;
+ char *cp;
+ int i, c, msglen, err;
+ List *ulist;
+ Node *p;
+ struct logfile_info *li;
+
+ if (argc == -1)
+ usage (import_usage);
+
+ /* Force -X behaviour or not based on the CVS repository
+ CVSROOT/config setting. */
+#ifdef CLIENT_SUPPORT
+ killnew = !current_parsed_root->isremote
+ && config->ImportNewFilesToVendorBranchOnly;
+#else /* !CLIENT_SUPPORT */
+ killnew = config->ImportNewFilesToVendorBranchOnly;
+#endif /* CLIENT_SUPPORT */
+
+
+ ign_setup ();
+ wrap_setup ();
+
+ vbranch = xstrdup (CVSBRANCH);
+ optind = 0;
+ while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:X")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ cvs_cmd_name);
+ break;
+ case 'd':
+ if (server_active)
+ {
+ /* CVS 1.10 and older clients will send this, but it
+ doesn't do any good. So tell the user we can't
+ cope, rather than silently losing. */
+ error (0, 0,
+ "warning: not setting the time of import from the file");
+ error (0, 0, "due to client limitations");
+ }
+ use_file_modtime = 1;
+ break;
+ case 'b':
+ free (vbranch);
+ vbranch = xstrdup (optarg);
+ break;
+ case 'm':
+#ifdef FORCE_USE_EDITOR
+ use_editor = 1;
+#else
+ use_editor = 0;
+#endif
+ if (message) free (message);
+ message = xstrdup (optarg);
+ break;
+ case 'I':
+ ign_add (optarg, 0);
+ break;
+ case 'k':
+ /* RCS_check_kflag returns strings of the form -kxx. We
+ only use it for validation, so we can free the value
+ as soon as it is returned. */
+ free (RCS_check_kflag (optarg));
+ keyword_opt = optarg;
+ break;
+ case 'W':
+ wrap_add (optarg, 0);
+ break;
+ case 'X':
+ killnew = true;
+ break;
+ case '?':
+ default:
+ usage (import_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 3)
+ usage (import_usage);
+
+ /* This is for handling the Checkin-time request. It might seem a
+ bit odd to enable the use_file_modtime code even in the case
+ where Checkin-time was not sent for a particular file. The
+ effect is that we use the time of upload, rather than the time
+ when we call RCS_checkin. Since those times are both during
+ CVS's run, that seems OK, and it is easier to implement than
+ putting the "was Checkin-time sent" flag in CVS/Entries or some
+ such place. */
+
+ if (server_active)
+ use_file_modtime = 1;
+
+ /* Don't allow "CVS" as any directory in module path.
+ *
+ * Could abstract this to valid_module_path, but I don't think we'll need
+ * to call it from anywhere else.
+ */
+ if ((cp = strstr (argv[0], "CVS")) && /* path contains "CVS" AND ... */
+ ((cp == argv[0]) || ISSLASH (*(cp-1))) && /* /^CVS/ OR m#/CVS# AND ... */
+ ((*(cp+3) == '\0') || ISSLASH (*(cp+3))) /* /CVS$/ OR m#CVS/# */
+ )
+ {
+ error (0, 0,
+ "The word `CVS' is reserved by CVS and may not be used");
+ error (1, 0, "as a directory in a path or as a file name.");
+ }
+
+ for (i = 1; i < argc; i++) /* check the tags for validity */
+ {
+ int j;
+
+ RCS_check_tag (argv[i]);
+ for (j = 1; j < i; j++)
+ if (strcmp (argv[j], argv[i]) == 0)
+ error (1, 0, "tag `%s' was specified more than once", argv[i]);
+ }
+
+ if (ISABSOLUTE (argv[0]) || pathname_levels (argv[0]) > 0)
+ /* It is somewhere between a security hole and "unexpected" to
+ let the client start mucking around outside the cvsroot
+ (wouldn't get the right CVSROOT configuration, &c). */
+ error (1, 0, "directory %s not relative within the repository",
+ argv[0]);
+
+ if (current_parsed_root == NULL)
+ {
+ error (0, 0, "missing CVSROOT environment variable\n");
+ error (1, 0, "Set it or specify the '-d' option to %s.",
+ program_name);
+ }
+ repository = Xasprintf ("%s/%s", current_parsed_root->directory, argv[0]);
+ repos_len = strlen (current_parsed_root->directory);
+
+ /*
+ * Consistency checks on the specified vendor branch. It must be
+ * composed of only numbers and dots ('.'). Also, for now we only
+ * support branching to a single level, so the specified vendor branch
+ * must only have two dots in it (like "1.1.1").
+ */
+ {
+ regex_t pat;
+ int ret = regcomp (&pat, "^[1-9][0-9]*\\.[1-9][0-9]*\\.[1-9][0-9]*$",
+ REG_EXTENDED);
+ assert (!ret);
+ if (regexec (&pat, vbranch, 0, NULL, 0))
+ {
+ error (1, 0,
+"Only numeric branch specifications with two dots are\n"
+"supported by import, not `%s'. For example: `1.1.1'.",
+ vbranch);
+ }
+ regfree (&pat);
+ }
+
+ /* Set vhead to the branch's parent. */
+ vhead = xstrdup (vbranch);
+ cp = strrchr (vhead, '.');
+ *cp = '\0';
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ /* For rationale behind calling start_server before do_editor, see
+ commit.c */
+ start_server ();
+ }
+#endif
+
+ if (!server_active && use_editor)
+ {
+ do_editor (NULL, &message,
+ current_parsed_root->isremote ? NULL : repository,
+ NULL);
+ }
+ msglen = message == NULL ? 0 : strlen (message);
+ if (msglen == 0 || message[msglen - 1] != '\n')
+ {
+ char *nm = xmalloc (msglen + 2);
+ *nm = '\0';
+ if (message != NULL)
+ {
+ (void) strcpy (nm, message);
+ free (message);
+ }
+ (void) strcat (nm + msglen, "\n");
+ message = nm;
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ int err;
+
+ if (vbranch[0] != '\0')
+ option_with_arg ("-b", vbranch);
+ option_with_arg ("-m", message ? message : "");
+ if (keyword_opt != NULL)
+ option_with_arg ("-k", keyword_opt);
+ if (killnew)
+ send_arg ("-X");
+ /* The only ignore processing which takes place on the server side
+ is the CVSROOT/cvsignore file. But if the user specified -I !,
+ the documented behavior is to not process said file. */
+ if (ign_inhibit_server)
+ {
+ send_arg ("-I");
+ send_arg ("!");
+ }
+ wrap_send ();
+
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ }
+
+ logfp = stdin;
+ client_import_setup (repository);
+ err = import_descend (message, argv[1], argc - 2, argv + 2);
+ client_import_done ();
+ if (message)
+ free (message);
+ free (repository);
+ free (vbranch);
+ free (vhead);
+ send_to_server ("import\012", 0);
+ err += get_responses_and_close ();
+ return err;
+ }
+#endif
+
+ if (!safe_location (NULL))
+ {
+ error (1, 0, "attempt to import the repository");
+ }
+
+ ulist = getlist ();
+ p = getnode ();
+ p->type = UPDATE;
+ p->delproc = update_delproc;
+ p->key = xstrdup ("- Imported sources");
+ li = xmalloc (sizeof (struct logfile_info));
+ li->type = T_TITLE;
+ li->tag = xstrdup (vbranch);
+ li->rev_old = li->rev_new = NULL;
+ p->data = li;
+ (void) addnode (ulist, p);
+ do_verify (&message, repository, ulist);
+
+ /*
+ * Make all newly created directories writable. Should really use a more
+ * sophisticated security mechanism here.
+ */
+ (void) umask (cvsumask);
+ make_directories (repository);
+
+ /* Create the logfile that will be logged upon completion */
+ if ((logfp = cvs_temp_file (&tmpfile)) == NULL)
+ error (1, errno, "cannot create temporary file `%s'", tmpfile);
+ /* On systems where we can unlink an open file, do so, so it will go
+ away no matter how we exit. FIXME-maybe: Should be checking for
+ errors but I'm not sure which error(s) we get if we are on a system
+ where one can't unlink open files. */
+ (void) CVS_UNLINK (tmpfile);
+ (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
+ (void) fprintf (logfp, "Release Tags:\t");
+ for (i = 2; i < argc; i++)
+ (void) fprintf (logfp, "%s\n\t\t", argv[i]);
+ (void) fprintf (logfp, "\n");
+
+ /* Just Do It. */
+ err = import_descend (message, argv[1], argc - 2, argv + 2);
+ if (conflicts || killnew)
+ {
+ if (!really_quiet)
+ {
+ char buf[20];
+
+ cvs_output_tagged ("+importmergecmd", NULL);
+ cvs_output_tagged ("newline", NULL);
+ if (conflicts)
+ sprintf (buf, "%d", conflicts);
+ else
+ strcpy (buf, "No");
+ cvs_output_tagged ("conflicts", buf);
+ cvs_output_tagged ("text", " conflicts created by this import.");
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("text",
+ "Use the following command to help the merge:");
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("text", "\t");
+ cvs_output_tagged ("text", program_name);
+ if (CVSroot_cmdline != NULL)
+ {
+ cvs_output_tagged ("text", " -d ");
+ cvs_output_tagged ("text", CVSroot_cmdline);
+ }
+ cvs_output_tagged ("text", " checkout -j");
+ cvs_output_tagged ("mergetag1", "<prev_rel_tag>");
+ cvs_output_tagged ("text", " -j");
+ cvs_output_tagged ("mergetag2", argv[2]);
+ cvs_output_tagged ("text", " ");
+ cvs_output_tagged ("repository", argv[0]);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("-importmergecmd", NULL);
+ }
+
+ /* FIXME: I'm not sure whether we need to put this information
+ into the loginfo. If we do, then note that it does not
+ report any required -d option. There is no particularly
+ clean way to tell the server about the -d option used by
+ the client. */
+ if (conflicts)
+ (void) fprintf (logfp, "\n%d", conflicts);
+ else
+ (void) fprintf (logfp, "\nNo");
+ (void) fprintf (logfp, " conflicts created by this import.\n");
+ (void) fprintf (logfp,
+ "Use the following command to help the merge:\n\n");
+ (void) fprintf (logfp, "\t%s checkout ", program_name);
+ (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
+ argv[1], argv[1], argv[0]);
+ }
+ else
+ {
+ if (!really_quiet)
+ cvs_output ("\nNo conflicts created by this import\n\n", 0);
+ (void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
+ }
+
+ /*
+ * Write out the logfile and clean up.
+ */
+ Update_Logfile (repository, message, logfp, ulist);
+ dellist (&ulist);
+ if (fclose (logfp) < 0)
+ error (0, errno, "error closing %s", tmpfile);
+
+ /* Make sure the temporary file goes away, even on systems that don't let
+ you delete a file that's in use. */
+ if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile);
+ free (tmpfile);
+
+ if (message)
+ free (message);
+ free (repository);
+ free (vbranch);
+ free (vhead);
+
+ return err;
+}
+
+/* Process all the files in ".", then descend into other directories.
+ Returns 0 for success, or >0 on error (in which case a message
+ will have been printed). */
+static int
+import_descend (char *message, char *vtag, int targc, char **targv)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int err = 0;
+ List *dirlist = NULL;
+
+ /* first, load up any per-directory ignore lists */
+ ign_add_file (CVSDOTIGNORE, 1);
+ wrap_add_file (CVSDOTWRAPPER, 1);
+
+ if (!current_parsed_root->isremote)
+ lock_dir_for_write (repository);
+
+ if ((dirp = CVS_OPENDIR (".")) == NULL)
+ {
+ error (0, errno, "cannot open directory");
+ err++;
+ }
+ else
+ {
+ errno = 0;
+ while ((dp = CVS_READDIR (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
+ goto one_more_time_boys;
+
+ /* CVS directories are created in the temp directory by
+ server.c because it doesn't special-case import. So
+ don't print a message about them, regardless of -I!. */
+ if (server_active && strcmp (dp->d_name, CVSADM) == 0)
+ goto one_more_time_boys;
+
+ if (ign_name (dp->d_name))
+ {
+ add_log ('I', dp->d_name);
+ goto one_more_time_boys;
+ }
+
+ if (
+#ifdef DT_DIR
+ (dp->d_type == DT_DIR
+ || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
+#else
+ isdir (dp->d_name)
+#endif
+ && !wrap_name_has (dp->d_name, WRAP_TOCVS)
+ )
+ {
+ Node *n;
+
+ if (dirlist == NULL)
+ dirlist = getlist ();
+
+ n = getnode ();
+ n->key = xstrdup (dp->d_name);
+ addnode (dirlist, n);
+ }
+ else if (
+#ifdef DT_DIR
+ dp->d_type == DT_LNK
+ || (dp->d_type == DT_UNKNOWN && islink (dp->d_name))
+#else
+ islink (dp->d_name)
+#endif
+ )
+ {
+ add_log ('L', dp->d_name);
+ err++;
+ }
+ else
+ {
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ err += client_process_import_file (message, dp->d_name,
+ vtag, targc, targv,
+ repository,
+ keyword_opt != NULL &&
+ keyword_opt[0] == 'b',
+ use_file_modtime);
+ else
+#endif
+ err += process_import_file (message, dp->d_name,
+ vtag, targc, targv);
+ }
+ one_more_time_boys:
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ error (0, errno, "cannot read directory");
+ ++err;
+ }
+ (void) CVS_CLOSEDIR (dirp);
+ }
+
+ if (!current_parsed_root->isremote)
+ Simple_Lock_Cleanup ();
+
+ if (dirlist != NULL)
+ {
+ Node *head, *p;
+
+ head = dirlist->list;
+ for (p = head->next; p != head; p = p->next)
+ {
+ err += import_descend_dir (message, p->key, vtag, targc, targv);
+ }
+
+ dellist (&dirlist);
+ }
+
+ return err;
+}
+
+/*
+ * Process the argument import file.
+ */
+static int
+process_import_file (char *message, char *vfile, char *vtag, int targc,
+ char **targv)
+{
+ char *rcs;
+ int inattic = 0;
+
+ rcs = Xasprintf ("%s/%s%s", repository, vfile, RCSEXT);
+ if (!isfile (rcs))
+ {
+ char *attic_name;
+
+ attic_name = xmalloc (strlen (repository) + strlen (vfile) +
+ sizeof (CVSATTIC) + sizeof (RCSEXT) + 10);
+ (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
+ vfile, RCSEXT);
+ if (!isfile (attic_name))
+ {
+ int retval;
+ char *free_opt = NULL;
+ char *our_opt = keyword_opt;
+
+ /* If marking newly-imported files as dead, they must be
+ created in the attic! */
+ if (!killnew)
+ free (attic_name);
+ else
+ {
+ free (rcs);
+ rcs = attic_name;
+
+ /* Attempt to make the Attic directory, in case it
+ does not exist. */
+ (void) sprintf (rcs, "%s/%s", repository, CVSATTIC);
+ if (CVS_MKDIR (rcs, 0777 ) != 0 && errno != EEXIST)
+ error (1, errno, "cannot make directory `%s'", rcs);
+
+ /* Note that the above clobbered the path name, so we
+ recreate it here. */
+ (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC,
+ vfile, RCSEXT);
+ }
+
+ /*
+ * A new import source file; it doesn't exist as a ,v within the
+ * repository nor in the Attic -- create it anew.
+ */
+ add_log ('N', vfile);
+
+#ifdef SERVER_SUPPORT
+ /* The most reliable information on whether the file is binary
+ is what the client told us. That is because if the client had
+ the wrong idea about binaryness, it corrupted the file, so
+ we might as well believe the client. */
+ if (server_active)
+ {
+ Node *node;
+ List *entries;
+
+ /* Reading all the entries for each file is fairly silly, and
+ probably slow. But I am too lazy at the moment to do
+ anything else. */
+ entries = Entries_Open (0, NULL);
+ node = findnode_fn (entries, vfile);
+ if (node != NULL)
+ {
+ Entnode *entdata = node->data;
+
+ if (entdata->type == ENT_FILE)
+ {
+ assert (entdata->options[0] == '-'
+ && entdata->options[1] == 'k');
+ our_opt = xstrdup (entdata->options + 2);
+ free_opt = our_opt;
+ }
+ }
+ Entries_Close (entries);
+ }
+#endif
+
+ retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
+ vbranch, vtag, targc, targv,
+ NULL, 0, logfp, killnew);
+ if (free_opt != NULL)
+ free (free_opt);
+ free (rcs);
+ return retval;
+ }
+ free (attic_name);
+ inattic = 1;
+ }
+
+ free (rcs);
+ /*
+ * an rcs file exists. have to do things the official, slow, way.
+ */
+ return update_rcs_file (message, vfile, vtag, targc, targv, inattic);
+}
+
+/*
+ * The RCS file exists; update it by adding the new import file to the
+ * (possibly already existing) vendor branch.
+ */
+static int
+update_rcs_file (char *message, char *vfile, char *vtag, int targc,
+ char **targv, int inattic)
+{
+ Vers_TS *vers;
+ int letter;
+ char *tocvsPath;
+ char *expand;
+ struct file_info finfo;
+
+ memset (&finfo, 0, sizeof finfo);
+ finfo.file = vfile;
+ /* Not used, so don't worry about it. */
+ finfo.update_dir = NULL;
+ finfo.fullname = finfo.file;
+ finfo.repository = repository;
+ finfo.entries = NULL;
+ finfo.rcs = NULL;
+ vers = Version_TS (&finfo, NULL, vbranch, NULL, 1, 0);
+ if (vers->vn_rcs != NULL
+ && !RCS_isdead (vers->srcfile, vers->vn_rcs))
+ {
+ int different;
+
+ /*
+ * The rcs file does have a revision on the vendor branch. Compare
+ * this revision with the import file; if they match exactly, there
+ * is no need to install the new import file as a new revision to the
+ * branch. Just tag the revision with the new import tags.
+ *
+ * This is to try to cut down the number of "C" conflict messages for
+ * locally modified import source files.
+ */
+ tocvsPath = wrap_tocvs_process_file (vfile);
+ /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is
+ not NULL? */
+ expand = (vers->srcfile->expand != NULL
+ && vers->srcfile->expand[0] == 'b') ? "-kb" : "-ko";
+ different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, NULL,
+ NULL, expand, vfile);
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ if (!different)
+ {
+ int retval = 0;
+
+ /*
+ * The two files are identical. Just update the tags, print the
+ * "U", signifying that the file has changed, but needs no
+ * attention, and we're done.
+ */
+ if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
+ retval = 1;
+ add_log ('U', vfile);
+ freevers_ts (&vers);
+ return retval;
+ }
+ }
+
+ /* We may have failed to parse the RCS file; check just in case */
+ if (vers->srcfile == NULL ||
+ add_rev (message, vers->srcfile, vfile, vers->vn_rcs) ||
+ add_tags (vers->srcfile, vfile, vtag, targc, targv))
+ {
+ freevers_ts (&vers);
+ return 1;
+ }
+
+ if (vers->srcfile->branch == NULL || inattic ||
+ strcmp (vers->srcfile->branch, vbranch) != 0)
+ {
+ conflicts++;
+ letter = 'C';
+ }
+ else
+ letter = 'U';
+ add_log (letter, vfile);
+
+ freevers_ts (&vers);
+ return 0;
+}
+
+/*
+ * Add the revision to the vendor branch
+ */
+static int
+add_rev (char *message, RCSNode *rcs, char *vfile, char *vers)
+{
+ int locked, status, ierrno;
+ char *tocvsPath;
+
+ if (noexec)
+ return 0;
+
+ locked = 0;
+ if (vers != NULL)
+ {
+ /* Before RCS_lock existed, we were directing stdout, as well as
+ stderr, from the RCS command, to DEVNULL. I wouldn't guess that
+ was necessary, but I don't know for sure. */
+ /* Earlier versions of this function printed a `fork failed' error
+ when RCS_lock returned an error code. That's not appropriate
+ now that RCS_lock is librarified, but should the error text be
+ preserved? */
+ if (RCS_lock (rcs, vbranch, 1) != 0)
+ return 1;
+ locked = 1;
+ RCS_rewrite (rcs, NULL, NULL);
+ }
+ tocvsPath = wrap_tocvs_process_file (vfile);
+
+ status = RCS_checkin (rcs, NULL, tocvsPath == NULL ? vfile : tocvsPath,
+ message, vbranch, 0,
+ (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
+ | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
+ ierrno = errno;
+
+ if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ if (status)
+ {
+ if (!noexec)
+ {
+ fperrmsg (logfp, 0, status == -1 ? ierrno : 0,
+ "ERROR: Check-in of %s failed", rcs->path);
+ error (0, status == -1 ? ierrno : 0,
+ "ERROR: Check-in of %s failed", rcs->path);
+ }
+ if (locked)
+ {
+ (void) RCS_unlock (rcs, vbranch, 0);
+ RCS_rewrite (rcs, NULL, NULL);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Add the vendor branch tag and all the specified import release tags to the
+ * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
+ * vendor release tags go on the newly added leaf of the branch (1.1.1.1,
+ * 1.1.1.2, ...).
+ */
+static int
+add_tags (RCSNode *rcs, char *vfile, char *vtag, int targc, char **targv)
+{
+ int i, ierrno;
+ Vers_TS *vers;
+ int retcode = 0;
+ struct file_info finfo;
+
+ if (noexec)
+ return 0;
+
+ if ((retcode = RCS_settag (rcs, vtag, vbranch)) != 0)
+ {
+ ierrno = errno;
+ fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
+ "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
+ error (0, retcode == -1 ? ierrno : 0,
+ "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
+ return 1;
+ }
+ RCS_rewrite (rcs, NULL, NULL);
+
+ memset (&finfo, 0, sizeof finfo);
+ finfo.file = vfile;
+ /* Not used, so don't worry about it. */
+ finfo.update_dir = NULL;
+ finfo.fullname = finfo.file;
+ finfo.repository = repository;
+ finfo.entries = NULL;
+ finfo.rcs = NULL;
+ vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0);
+ for (i = 0; i < targc; i++)
+ {
+ if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0)
+ RCS_rewrite (rcs, NULL, NULL);
+ else
+ {
+ ierrno = errno;
+ fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
+ "WARNING: Couldn't add tag %s to %s", targv[i],
+ rcs->path);
+ error (0, retcode == -1 ? ierrno : 0,
+ "WARNING: Couldn't add tag %s to %s", targv[i],
+ rcs->path);
+ }
+ }
+ freevers_ts (&vers);
+ return 0;
+}
+
+/*
+ * Stolen from rcs/src/rcsfnms.c, and adapted/extended.
+ */
+struct compair
+{
+ char *suffix, *comlead;
+};
+
+static const struct compair comtable[] =
+{
+
+/*
+ * comtable pairs each filename suffix with a comment leader. The comment
+ * leader is placed before each line generated by the $Log keyword. This
+ * table is used to guess the proper comment leader from the working file's
+ * suffix during initial ci (see InitAdmin()). Comment leaders are needed for
+ * languages without multiline comments; for others they are optional.
+ *
+ * I believe that the comment leader is unused if you are using RCS 5.7, which
+ * decides what leader to use based on the text surrounding the $Log keyword
+ * rather than a specified comment leader.
+ */
+ {"a", "-- "}, /* Ada */
+ {"ada", "-- "},
+ {"adb", "-- "},
+ {"asm", ";; "}, /* assembler (MS-DOS) */
+ {"ads", "-- "}, /* Ada */
+ {"bas", "' "}, /* Visual Basic code */
+ {"bat", ":: "}, /* batch (MS-DOS) */
+ {"body", "-- "}, /* Ada */
+ {"c", " * "}, /* C */
+ {"c++", "// "}, /* C++ in all its infinite guises */
+ {"cc", "// "},
+ {"cpp", "// "},
+ {"cxx", "// "},
+ {"m", "// "}, /* Objective-C */
+ {"cl", ";;; "}, /* Common Lisp */
+ {"cmd", ":: "}, /* command (OS/2) */
+ {"cmf", "c "}, /* CM Fortran */
+ {"cs", " * "}, /* C* */
+ {"csh", "# "}, /* shell */
+ {"dlg", " * "}, /* MS Windows dialog file */
+ {"e", "# "}, /* efl */
+ {"epsf", "% "}, /* encapsulated postscript */
+ {"epsi", "% "}, /* encapsulated postscript */
+ {"el", "; "}, /* Emacs Lisp */
+ {"f", "c "}, /* Fortran */
+ {"for", "c "},
+ {"frm", "' "}, /* Visual Basic form */
+ {"h", " * "}, /* C-header */
+ {"hh", "// "}, /* C++ header */
+ {"hpp", "// "},
+ {"hxx", "// "},
+ {"in", "# "}, /* for Makefile.in */
+ {"l", " * "}, /* lex (conflict between lex and
+ * franzlisp) */
+ {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11,
+ * VMS, etc) */
+ {"mak", "# "}, /* makefile, e.g. Visual C++ */
+ {"me", ".\\\" "}, /* me-macros t/nroff */
+ {"ml", "; "}, /* mocklisp */
+ {"mm", ".\\\" "}, /* mm-macros t/nroff */
+ {"ms", ".\\\" "}, /* ms-macros t/nroff */
+ {"man", ".\\\" "}, /* man-macros t/nroff */
+ {"1", ".\\\" "}, /* feeble attempt at man pages... */
+ {"2", ".\\\" "},
+ {"3", ".\\\" "},
+ {"4", ".\\\" "},
+ {"5", ".\\\" "},
+ {"6", ".\\\" "},
+ {"7", ".\\\" "},
+ {"8", ".\\\" "},
+ {"9", ".\\\" "},
+ {"p", " * "}, /* pascal */
+ {"pas", " * "},
+ {"pl", "# "}, /* perl (conflict with Prolog) */
+ {"ps", "% "}, /* postscript */
+ {"psw", "% "}, /* postscript wrap */
+ {"pswm", "% "}, /* postscript wrap */
+ {"r", "# "}, /* ratfor */
+ {"rc", " * "}, /* Microsoft Windows resource file */
+ {"red", "% "}, /* psl/rlisp */
+#ifdef sparc
+ {"s", "! "}, /* assembler */
+#endif
+#ifdef mc68000
+ {"s", "| "}, /* assembler */
+#endif
+#ifdef pdp11
+ {"s", "/ "}, /* assembler */
+#endif
+#ifdef vax
+ {"s", "# "}, /* assembler */
+#endif
+#ifdef __ksr__
+ {"s", "# "}, /* assembler */
+ {"S", "# "}, /* Macro assembler */
+#endif
+ {"sh", "# "}, /* shell */
+ {"sl", "% "}, /* psl */
+ {"spec", "-- "}, /* Ada */
+ {"tex", "% "}, /* tex */
+ {"y", " * "}, /* yacc */
+ {"ye", " * "}, /* yacc-efl */
+ {"yr", " * "}, /* yacc-ratfor */
+ {"", "# "}, /* default for empty suffix */
+ {NULL, "# "} /* default for unknown suffix; */
+/* must always be last */
+};
+
+
+
+static char *
+get_comment (const char *user)
+{
+ char *cp, *suffix;
+ char *suffix_path;
+ int i;
+ char *retval;
+
+ suffix_path = xmalloc (strlen (user) + 5);
+ cp = strrchr (user, '.');
+ if (cp != NULL)
+ {
+ cp++;
+
+ /*
+ * Convert to lower-case, since we are not concerned about the
+ * case-ness of the suffix.
+ */
+ (void) strcpy (suffix_path, cp);
+ for (cp = suffix_path; *cp; cp++)
+ if (isupper ((unsigned char) *cp))
+ *cp = tolower (*cp);
+ suffix = suffix_path;
+ }
+ else
+ suffix = ""; /* will use the default */
+ for (i = 0;; i++)
+ {
+ if (comtable[i].suffix == NULL)
+ {
+ /* Default. Note we'll always hit this case before we
+ ever return NULL. */
+ retval = comtable[i].comlead;
+ break;
+ }
+ if (strcmp (suffix, comtable[i].suffix) == 0)
+ {
+ retval = comtable[i].comlead;
+ break;
+ }
+ }
+ free (suffix_path);
+ return retval;
+}
+
+/* Create a new RCS file from scratch.
+ *
+ * This probably should be moved to rcs.c now that it is called from
+ * places outside import.c.
+ *
+ * INPUTS
+ * message Log message for the addition. Not used if add_vhead == NULL.
+ * rcs Filename of the RCS file to create. Note that if 'do_killnew'
+ * is set, this file should be in the Attic directory, and the
+ * Attic directory must already exist.
+ * user Filename of the file to serve as the contents of the initial
+ * revision. Even if add_vhead is NULL, we use this to determine
+ * the modes to give the new RCS file.
+ * add_vhead Revision number of head that we are adding. Normally 1.1 but
+ * could be another revision as long as ADD_VBRANCH is a branch
+ * from it. If NULL, then just add an empty file without any
+ * revisions (similar to the one created by "rcs -i").
+ * key_opt Keyword expansion mode, e.g., "b" for binary. NULL means the
+ * default behavior.
+ * add_vbranch
+ * Vendor branch to import to, or NULL if none. If non-NULL, then
+ * vtag should also be non-NULL.
+ * vtag
+ * targc Number of elements in TARGV.
+ * targv The list of tags to attached to this imported revision.
+ * desctext If non-NULL, description for the file. If NULL, the
+ * description will be empty.
+ * desclen The number of bytes in desctext.
+ * add_logfp Write errors to here as well as via error (), or NULL if we
+ * should use only error ().
+ * do_killnew Mark newly-imported files as being dead on the trunk, i.e.,
+ * as being imported only to the vendor branch.
+ *
+ * RETURNS
+ * Return value is 0 for success, or nonzero for failure (in which
+ * case an error message will have already been printed).
+ */
+int
+add_rcs_file (const char *message, const char *rcs, const char *user,
+ const char *add_vhead, const char *key_opt,
+ const char *add_vbranch, const char *vtag, int targc,
+ char **targv, const char *desctext, size_t desclen,
+ FILE *add_logfp, bool do_killnew)
+{
+ FILE *fprcs, *fpuser;
+ struct stat sb;
+ struct tm *ftm;
+ time_t now;
+ char altdate1[MAXDATELEN];
+ char *author;
+ int i, ierrno, err = 0;
+ mode_t mode;
+ char *tocvsPath;
+ const char *userfile;
+ char *free_opt = NULL;
+ mode_t file_type;
+ char *dead_revision = NULL;
+
+ if (noexec)
+ return 0;
+
+ if (do_killnew)
+ {
+ char *last_place;
+ int last_number;
+
+ /* If we are marking the newly imported file as dead, we must
+ have a head revision. */
+ if (add_vhead == NULL)
+ error (1, 0, "killing new file attempted when no head revision is being added");
+
+ /* One extra byte for NUL, plus one for carry generated by adding
+ one to the last number in the add_vhead revision. */
+ dead_revision = xmalloc (strlen (add_vhead) + 2);
+ strcpy (dead_revision, add_vhead);
+
+ /* Find the loacation of the last number, which we will increment
+ and overwrite. Note that this handles single numbers (w/o
+ dots), which is probably unnecessary. */
+ if ((last_place = strrchr (dead_revision, '.')) != NULL)
+ last_place++;
+ else
+ last_place = dead_revision;
+ last_number = atoi (last_place);
+ if (++last_number <= 0)
+ error (1, 0, "invalid revision number %s", add_vhead);
+ sprintf (last_place, "%d", last_number);
+ }
+
+ /* Note that as the code stands now, the -k option overrides any
+ settings in wrappers (whether CVSROOT/cvswrappers, -W, or
+ whatever). Some have suggested this should be the other way
+ around. As far as I know the documentation doesn't say one way
+ or the other. Before making a change of this sort, should think
+ about what is best, document it (in cvs.texinfo and NEWS), &c. */
+
+ if (key_opt == NULL)
+ {
+ if (wrap_name_has (user, WRAP_RCSOPTION))
+ {
+ key_opt = free_opt = wrap_rcsoption (user, 0);
+ }
+ }
+
+ tocvsPath = wrap_tocvs_process_file (user);
+ userfile = (tocvsPath == NULL ? user : tocvsPath);
+
+ /* Opening in text mode is probably never the right thing for the
+ server (because the protocol encodes text files in a fashion
+ which does not depend on what the client or server OS is, as
+ documented in cvsclient.texi), but as long as the server just
+ runs on unix it is a moot point. */
+
+ /* If PreservePermissions is set, then make sure that the file
+ is a plain file before trying to open it. Longstanding (although
+ often unpopular) CVS behavior has been to follow symlinks, so we
+ maintain that behavior if PreservePermissions is not on.
+
+ NOTE: this error message used to be `cannot fstat', but is now
+ `cannot lstat'. I don't see a way around this, since we must
+ stat the file before opening it. -twp */
+
+ if (lstat (userfile, &sb) < 0)
+ {
+ /* not fatal, continue import */
+ if (add_logfp != NULL)
+ fperrmsg (add_logfp, 0, errno,
+ "ERROR: cannot lstat file %s", userfile);
+ error (0, errno, "cannot lstat file %s", userfile);
+ goto read_error;
+ }
+ file_type = sb.st_mode & S_IFMT;
+
+ fpuser = NULL;
+ if (
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ !config->preserve_perms ||
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+ file_type == S_IFREG)
+ {
+ fpuser = CVS_FOPEN (userfile,
+ ((key_opt != NULL && strcmp (key_opt, "b") == 0)
+ ? "rb"
+ : "r")
+ );
+ if (fpuser == NULL)
+ {
+ /* not fatal, continue import */
+ if (add_logfp != NULL)
+ fperrmsg (add_logfp, 0, errno,
+ "ERROR: cannot read file %s", userfile);
+ error (0, errno, "ERROR: cannot read file %s", userfile);
+ goto read_error;
+ }
+ }
+
+ fprcs = CVS_FOPEN (rcs, "w+b");
+ if (fprcs == NULL)
+ {
+ ierrno = errno;
+ goto write_error_noclose;
+ }
+
+ /*
+ * putadmin()
+ */
+ if (add_vhead != NULL)
+ {
+ if (fprintf (fprcs, "head %s;\012",
+ do_killnew ? dead_revision : add_vhead) < 0)
+ goto write_error;
+ }
+ else
+ {
+ if (fprintf (fprcs, "head ;\012") < 0)
+ goto write_error;
+ }
+
+ /* This sets the default branch. If using the 'do_killnew' functionality,
+ where imports don't show up until merged, no default branch should
+ be set. */
+ if (add_vbranch != NULL && ! do_killnew)
+ {
+ if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, "access ;\012") < 0 ||
+ fprintf (fprcs, "symbols ") < 0)
+ {
+ goto write_error;
+ }
+
+ for (i = targc - 1; i >= 0; i--)
+ {
+ /* RCS writes the symbols backwards */
+ assert (add_vbranch != NULL);
+ if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0)
+ goto write_error;
+ }
+
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, ";\012") < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "locks ; strict;\012") < 0 ||
+ /* XXX - make sure @@ processing works in the RCS file */
+ fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0)
+ {
+ goto write_error;
+ }
+
+ if (key_opt != NULL && strcmp (key_opt, "kv") != 0)
+ {
+ if (fprintf (fprcs, "expand @%s@;\012", key_opt) < 0)
+ {
+ goto write_error;
+ }
+ }
+
+ if (fprintf (fprcs, "\012") < 0)
+ goto write_error;
+
+ /* Write the revision(s), with the date and author and so on
+ (that is "delta" rather than "deltatext" from rcsfile(5)). */
+
+ if (use_file_modtime)
+ now = sb.st_mtime;
+ else
+ (void) time (&now);
+ ftm = gmtime (&now);
+ (void) sprintf (altdate1, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+ author = getcaller ();
+
+ if (do_killnew)
+ {
+ if (fprintf (fprcs, "\012%s\012", dead_revision) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state %s;\012",
+ altdate1, author, RCSDEAD) < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "branches;\012") < 0)
+ goto write_error;
+ if (fprintf (fprcs, "next %s;\012", add_vhead) < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "commitid %s;\012", global_session_id) < 0)
+ goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Store initial permissions if necessary. */
+ if (config->preserve_perms)
+ {
+ if (preserve_initial_permissions (fprcs, userfile,
+ file_type, sbp))
+ goto write_error;
+ }
+#endif
+ }
+
+ if (add_vhead != NULL)
+ {
+ if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\012",
+ altdate1, author) < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "branches") < 0)
+ goto write_error;
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, ";\012") < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "next ;\012") < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "commitid %s;\012", global_session_id) < 0)
+ goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Store initial permissions if necessary. */
+ if (config->preserve_perms)
+ {
+ if (preserve_initial_permissions (fprcs, userfile,
+ file_type, sbp))
+ goto write_error;
+ }
+#endif
+
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\012",
+ altdate1, author) < 0 ||
+ fprintf (fprcs, "branches ;\012") < 0 ||
+ fprintf (fprcs, "next ;\012") < 0 ||
+ fprintf (fprcs, "commitid %s;\012", global_session_id) < 0)
+ goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Store initial permissions if necessary. */
+ if (config->preserve_perms)
+ {
+ if (preserve_initial_permissions (fprcs, userfile,
+ file_type, sbp))
+ goto write_error;
+ }
+#endif
+
+ if (fprintf (fprcs, "\012") < 0)
+ goto write_error;
+ }
+ }
+
+ /* Now write the description (possibly empty). */
+ if (fprintf (fprcs, "\012desc\012") < 0 ||
+ fprintf (fprcs, "@") < 0)
+ goto write_error;
+ if (desctext != NULL)
+ {
+ /* The use of off_t not size_t for the second argument is very
+ strange, since we are dealing with something which definitely
+ fits in memory. */
+ if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, "@\012\012\012") < 0)
+ goto write_error;
+
+ /* Now write the log messages and contents for the revision(s) (that
+ is, "deltatext" rather than "delta" from rcsfile(5)). */
+
+ if (do_killnew)
+ {
+ if (fprintf (fprcs, "\012%s\012", dead_revision) < 0 ||
+ fprintf (fprcs, "log\012@") < 0)
+ goto write_error;
+ if (fprintf (fprcs, "Revision %s was added on the vendor branch.\012",
+ add_vhead) < 0)
+ goto write_error;
+ if (fprintf (fprcs, "@\012") < 0 ||
+ fprintf (fprcs, "text\012@") < 0)
+ {
+ goto write_error;
+ }
+
+ /* Now copy over the contents of the file, expanding at signs. */
+ if (expand_and_copy_contents (fprcs, file_type, user, fpuser))
+ goto write_error;
+
+ if (fprintf (fprcs, "@\012\012") < 0)
+ goto write_error;
+ }
+
+ if (add_vhead != NULL)
+ {
+ if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
+ fprintf (fprcs, "log\012@") < 0)
+ goto write_error;
+ if (add_vbranch != NULL)
+ {
+ /* We are going to put the log message in the revision on the
+ branch. So putting it here too seems kind of redundant, I
+ guess (and that is what CVS has always done, anyway). */
+ if (fprintf (fprcs, "Initial revision\012") < 0)
+ goto write_error;
+ }
+ else
+ {
+ if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, "@\012") < 0 ||
+ fprintf (fprcs, "text\012@") < 0)
+ {
+ goto write_error;
+ }
+
+ /* Now copy over the contents of the file, expanding at signs.
+ * If config->preserve_perms is set, do this only for regular files.
+ */
+ if (!do_killnew)
+ {
+ /* Now copy over the contents of the file, expanding at signs,
+ if not done as part of do_killnew handling above. */
+ if (expand_and_copy_contents (fprcs, file_type, user, fpuser))
+ goto write_error;
+ }
+
+ if (fprintf (fprcs, "@\012\012") < 0)
+ goto write_error;
+
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
+ fprintf (fprcs, "log\012@") < 0 ||
+ expand_at_signs (message,
+ (off_t) strlen (message), fprcs) < 0 ||
+ fprintf (fprcs, "@\012text\012") < 0 ||
+ fprintf (fprcs, "@@\012") < 0)
+ goto write_error;
+ }
+ }
+
+ if (fclose (fprcs) == EOF)
+ {
+ ierrno = errno;
+ goto write_error_noclose;
+ }
+ /* Close fpuser only if we opened it to begin with. */
+ if (fpuser != NULL)
+ {
+ if (fclose (fpuser) < 0)
+ error (0, errno, "cannot close %s", user);
+ }
+
+ /*
+ * Fix the modes on the RCS files. The user modes of the original
+ * user file are propagated to the group and other modes as allowed
+ * by the repository umask, except that all write permissions are
+ * turned off.
+ */
+ mode = (sb.st_mode |
+ (sb.st_mode & S_IRWXU) >> 3 |
+ (sb.st_mode & S_IRWXU) >> 6) &
+ ~cvsumask &
+ ~(S_IWRITE | S_IWGRP | S_IWOTH);
+ if (chmod (rcs, mode) < 0)
+ {
+ ierrno = errno;
+ if (add_logfp != NULL)
+ fperrmsg (add_logfp, 0, ierrno,
+ "WARNING: cannot change mode of file %s", rcs);
+ error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
+ err++;
+ }
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+ if (free_opt != NULL)
+ free (free_opt);
+ return err;
+
+write_error:
+ ierrno = errno;
+ if (fclose (fprcs) < 0)
+ error (0, errno, "cannot close %s", rcs);
+write_error_noclose:
+ if (fclose (fpuser) < 0)
+ error (0, errno, "cannot close %s", user);
+ if (add_logfp != NULL)
+ fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
+ error (0, ierrno, "ERROR: cannot write file %s", rcs);
+ if (ierrno == ENOSPC)
+ {
+ if (CVS_UNLINK (rcs) < 0)
+ error (0, errno, "cannot remove %s", rcs);
+ if (add_logfp != NULL)
+ fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting");
+ error (1, 0, "ERROR: out of space - aborting");
+ }
+read_error:
+ if (tocvsPath)
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
+
+ if (free_opt != NULL)
+ free (free_opt);
+
+ return err + 1;
+}
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+/* Write file permissions and symlink information for a file being
+ * added into its RCS file.
+ *
+ * INPUTS
+ * fprcs FILE pointer for the (newly-created) RCS file. Permisisons
+ * and symlink information should be written here.
+ * userfile Filename of the file being added. (Used to read symbolic
+ * link contents, for symlinks.)
+ * file_type File type of userfile, extracted from sbp->st_mode.
+ * sbp 'stat' information for userfile.
+ *
+ * RETURNS
+ * Return value is 0 for success, or nonzero for failure (in which case
+ * no error message has yet been printed).
+ */
+static int
+preserve_initial_permissions (fprcs, userfile, file_type, sbp)
+ FILE *fprcs;
+ const char *userfile;
+ mode_t file_type;
+ struct stat *sbp;
+{
+ if (file_type == S_IFLNK)
+ {
+ char *link = Xreadlink (userfile, sbp->st_size);
+ if (fprintf (fprcs, "symlink\t@") < 0 ||
+ expand_at_signs (link, strlen (link), fprcs) < 0 ||
+ fprintf (fprcs, "@;\012") < 0)
+ goto write_error;
+ free (link);
+ }
+ else
+ {
+ if (fprintf (fprcs, "owner\t%u;\012", sbp->st_uid) < 0)
+ goto write_error;
+ if (fprintf (fprcs, "group\t%u;\012", sbp->st_gid) < 0)
+ goto write_error;
+ if (fprintf (fprcs, "permissions\t%o;\012",
+ sbp->st_mode & 07777) < 0)
+ goto write_error;
+ switch (file_type)
+ {
+ case S_IFREG: break;
+ case S_IFCHR:
+ case S_IFBLK:
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+ if (fprintf (fprcs, "special\t%s %lu;\012",
+ (file_type == S_IFCHR
+ ? "character"
+ : "block"),
+ (unsigned long) sbp->st_rdev) < 0)
+ goto write_error;
+#else
+ error (0, 0,
+"can't import %s: unable to import device files on this system",
+userfile);
+#endif
+ break;
+ default:
+ error (0, 0,
+ "can't import %s: unknown kind of special file",
+ userfile);
+ }
+ }
+ return 0;
+
+write_error:
+ return 1;
+}
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+
+/* Copy file contents into an RCS file, expanding at signs.
+ *
+ * If config->preserve_perms is set, nothing is copied if the source is not
+ * a regular file.
+ *
+ * INPUTS
+ * fprcs FILE pointer for the (newly-created) RCS file. The expanded
+ * contents should be written here.
+ * file_type File type of the data source. No data is copied if
+ * preserve_permissions is set and the source is not a
+ * regular file.
+ * user Filename of the data source (used to print error messages).
+ * fpuser FILE pointer for the data source, whose data is being
+ * copied into the RCS file.
+ *
+ * RETURNS
+ * Return value is 0 for success, or nonzero for failure (in which case
+ * no error message has yet been printed).
+ */
+static int
+expand_and_copy_contents (fprcs, file_type, user, fpuser)
+ FILE *fprcs, *fpuser;
+ mode_t file_type;
+ const char *user;
+{
+ if (
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ !config->preserve_perms ||
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+ file_type == S_IFREG)
+ {
+ char buf[8192];
+ unsigned int len;
+
+ while (1)
+ {
+ len = fread (buf, 1, sizeof buf, fpuser);
+ if (len == 0)
+ {
+ if (ferror (fpuser))
+ error (1, errno, "cannot read file %s for copying",
+ user);
+ break;
+ }
+ if (expand_at_signs (buf, len, fprcs) < 0)
+ goto write_error;
+ }
+ }
+ return 0;
+
+write_error:
+ return 1;
+}
+
+/*
+ * Write SIZE bytes at BUF to FP, expanding @ signs into double @
+ * signs. If an error occurs, return a negative value and set errno
+ * to indicate the error. If not, return a nonnegative value.
+ */
+int
+expand_at_signs (const char *buf, size_t size, FILE *fp)
+{
+ register const char *cp, *next;
+
+ cp = buf;
+ while ((next = memchr (cp, '@', size)) != NULL)
+ {
+ size_t len = ++next - cp;
+ if (fwrite (cp, 1, len, fp) != len)
+ return EOF;
+ if (putc ('@', fp) == EOF)
+ return EOF;
+ cp = next;
+ size -= len;
+ }
+
+ if (fwrite (cp, 1, size, fp) != size)
+ return EOF;
+
+ return 1;
+}
+
+/*
+ * Write an update message to (potentially) the screen and the log file.
+ */
+static void
+add_log (int ch, char *fname)
+{
+ if (!really_quiet) /* write to terminal */
+ {
+ char buf[2];
+ buf[0] = ch;
+ buf[1] = ' ';
+ cvs_output (buf, 2);
+ if (repos_len)
+ {
+ cvs_output (repository + repos_len + 1, 0);
+ cvs_output ("/", 1);
+ }
+ else if (repository[0] != '\0')
+ {
+ cvs_output (repository, 0);
+ cvs_output ("/", 1);
+ }
+ cvs_output (fname, 0);
+ cvs_output ("\n", 1);
+ }
+
+ if (repos_len) /* write to logfile */
+ (void) fprintf (logfp, "%c %s/%s\n", ch,
+ repository + repos_len + 1, fname);
+ else if (repository[0])
+ (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
+ else
+ (void) fprintf (logfp, "%c %s\n", ch, fname);
+}
+
+/*
+ * This is the recursive function that walks the argument directory looking
+ * for sub-directories that have CVS administration files in them and updates
+ * them recursively.
+ *
+ * Note that we do not follow symbolic links here, which is a feature!
+ */
+static int
+import_descend_dir (char *message, char *dir, char *vtag, int targc,
+ char **targv)
+{
+ struct saved_cwd cwd;
+ char *cp;
+ int ierrno, err;
+ char *rcs = NULL;
+
+ if (islink (dir))
+ return 0;
+ if (save_cwd (&cwd))
+ {
+ fperrmsg (logfp, 0, errno, "Failed to save current directory.");
+ return 1;
+ }
+
+ /* Concatenate DIR to the end of REPOSITORY. */
+ if (repository[0] == '\0')
+ {
+ char *new = xstrdup (dir);
+ free (repository);
+ repository = new;
+ }
+ else
+ {
+ char *new = Xasprintf ("%s/%s", repository, dir);
+ free (repository);
+ repository = new;
+ }
+
+ if (!quiet && !current_parsed_root->isremote)
+ error (0, 0, "Importing %s", repository);
+
+ if (CVS_CHDIR (dir) < 0)
+ {
+ ierrno = errno;
+ fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
+ error (0, ierrno, "ERROR: cannot chdir to %s", repository);
+ err = 1;
+ goto out;
+ }
+ if (!current_parsed_root->isremote && !isdir (repository))
+ {
+ rcs = Xasprintf ("%s%s", repository, RCSEXT);
+ if (isfile (repository) || isfile (rcs))
+ {
+ fperrmsg (logfp, 0, 0,
+ "ERROR: %s is a file, should be a directory!",
+ repository);
+ error (0, 0, "ERROR: %s is a file, should be a directory!",
+ repository);
+ err = 1;
+ goto out;
+ }
+ if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
+ {
+ ierrno = errno;
+ fperrmsg (logfp, 0, ierrno,
+ "ERROR: cannot mkdir %s -- not added", repository);
+ error (0, ierrno,
+ "ERROR: cannot mkdir %s -- not added", repository);
+ err = 1;
+ goto out;
+ }
+ }
+ err = import_descend (message, vtag, targc, targv);
+ out:
+ if (rcs != NULL)
+ free (rcs);
+ if ((cp = strrchr (repository, '/')) != NULL)
+ *cp = '\0';
+ else
+ repository[0] = '\0';
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+ return err;
+}
diff --git a/src/kerberos4-client.c b/src/kerberos4-client.c
new file mode 100644
index 0000000..168d791
--- /dev/null
+++ b/src/kerberos4-client.c
@@ -0,0 +1,110 @@
+/* CVS Kerberos4 client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <config.h>
+
+#include "cvs.h"
+
+#include "buffer.h"
+#include "socket-client.h"
+
+# include <krb.h>
+
+extern char *krb_realmofhost ();
+# ifndef HAVE_KRB_GET_ERR_TEXT
+# define krb_get_err_text(status) krb_err_txt[status]
+# endif /* HAVE_KRB_GET_ERR_TEXT */
+
+/* Information we need if we are going to use Kerberos encryption. */
+static C_Block kblock;
+static Key_schedule sched;
+
+
+/* This function has not been changed to deal with NO_SOCKET_TO_FD
+ (i.e., systems on which sockets cannot be converted to file
+ descriptors). The first person to try building a kerberos client
+ on such a system (OS/2, Windows 95, and maybe others) will have to
+ take care of this. */
+void
+start_kerberos4_server (cvsroot_t *root, struct buffer **to_server_p,
+ struct buffer **from_server_p)
+{
+ int s;
+ int port;
+ struct hostent *hp;
+ struct sockaddr_in sin;
+ char *hname;
+
+ s = socket (AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
+
+ port = get_cvs_port_number (root);
+
+ hp = init_sockaddr (&sin, root->hostname, port);
+
+ hname = xstrdup (hp->h_name);
+
+ TRACE (TRACE_FUNCTION, "Connecting to %s(%s):%d",
+ root->hostname,
+ inet_ntoa (sin.sin_addr),
+ port);
+
+ if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
+ error (1, 0, "connect to %s(%s):%d failed: %s",
+ root->hostname,
+ inet_ntoa (sin.sin_addr),
+ port, SOCK_STRERROR (SOCK_ERRNO));
+
+ {
+ const char *realm;
+ struct sockaddr_in laddr;
+ int laddrlen;
+ KTEXT_ST ticket;
+ MSG_DAT msg_data;
+ CREDENTIALS cred;
+ int status;
+
+ realm = krb_realmofhost (hname);
+
+ laddrlen = sizeof (laddr);
+ if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0)
+ error (1, 0, "getsockname failed: %s", SOCK_STRERROR (SOCK_ERRNO));
+
+ /* We don't care about the checksum, and pass it as zero. */
+ status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd",
+ hname, realm, (unsigned long) 0, &msg_data,
+ &cred, sched, &laddr, &sin, "KCVSV1.0");
+ if (status != KSUCCESS)
+ error (1, 0, "kerberos authentication failed: %s",
+ krb_get_err_text (status));
+ memcpy (kblock, cred.session, sizeof (C_Block));
+ }
+
+ close_on_exec (s);
+
+ free (hname);
+
+ /* Give caller the values it wants. */
+ make_bufs_from_fds (s, s, 0, root, to_server_p, from_server_p, 1);
+}
+
+void
+initialize_kerberos4_encryption_buffers( struct buffer **to_server_p,
+ struct buffer **from_server_p )
+{
+ *to_server_p = krb_encrypt_buffer_initialize (*to_server_p, 0, sched,
+ kblock, NULL);
+ *from_server_p = krb_encrypt_buffer_initialize (*from_server_p, 1,
+ sched, kblock, NULL);
+}
+
diff --git a/src/kerberos4-client.h b/src/kerberos4-client.h
new file mode 100644
index 0000000..b9ab70d
--- /dev/null
+++ b/src/kerberos4-client.h
@@ -0,0 +1,25 @@
+/* CVS Kerberos4 client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+
+#ifndef KERBEROS4_CLIENT_H__
+#define KERBEROS4_CLIENT_H__
+
+extern void start_kerberos4_server (cvsroot_t *root,
+ struct buffer **to_server_p,
+ struct buffer **from_server_p);
+
+extern void initialize_kerberos4_encryption_buffers (struct buffer **to_server_p,
+ struct buffer **from_server_p);
+
+#endif
+
diff --git a/src/lock.c b/src/lock.c
new file mode 100644
index 0000000..bada280
--- /dev/null
+++ b/src/lock.c
@@ -0,0 +1,1373 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Set Lock
+ *
+ * Lock file support for CVS.
+ */
+
+/* The node Concurrency in doc/cvs.texinfo has a brief introduction to
+ how CVS locks function, and some of the user-visible consequences of
+ their existence. Here is a summary of why they exist (and therefore,
+ the consequences of hacking CVS to read a repository without creating
+ locks):
+
+ There are two uses. One is the ability to prevent there from being
+ two writers at the same time. This is necessary for any number of
+ reasons (fileattr code, probably others). Commit needs to lock the
+ whole tree so that nothing happens between the up-to-date check and
+ the actual checkin.
+
+ The second use is the ability to ensure that there is not a writer
+ and a reader at the same time (several readers are allowed). Reasons
+ for this are:
+
+ * Readlocks ensure that once CVS has found a collection of rcs
+ files using Find_Names, the files will still exist when it reads
+ them (they may have moved in or out of the attic).
+
+ * Readlocks provide some modicum of consistency, although this is
+ kind of limited--see the node Concurrency in cvs.texinfo.
+
+ * Readlocks ensure that the RCS file does not change between
+ RCS_parse and RCS_reparsercsfile time. This one strikes me as
+ important, although I haven't thought up what bad scenarios might
+ be.
+
+ * Readlocks ensure that we won't find the file in the state in
+ which it is in between the calls to add_rcs_file and RCS_checkin in
+ commit.c (when a file is being added). This state is a state in
+ which the RCS file parsing routines in rcs.c cannot parse the file.
+
+ * Readlocks ensure that a reader won't try to look at a
+ half-written fileattr file (fileattr is not updated atomically).
+
+ (see also the description of anonymous read-only access in
+ "Password authentication security" node in doc/cvs.texinfo).
+
+ While I'm here, I'll try to summarize a few random suggestions
+ which periodically get made about how locks might be different:
+
+ 1. Check for EROFS. Maybe useful, although in the presence of NFS
+ EROFS does *not* mean that the file system is unchanging.
+
+ 2. Provide an option to disable locks for operations which only
+ read (see above for some of the consequences).
+
+ 3. Have a server internally do the locking. Probably a good
+ long-term solution, and many people have been working hard on code
+ changes which would eventually make it possible to have a server
+ which can handle various connections in one process, but there is
+ much, much work still to be done before this is feasible. */
+
+#include "cvs.h"
+
+
+
+struct lock {
+ /* This is the directory in which we may have a lock named by the
+ readlock variable, a lock named by the writelock variable, and/or
+ a lock named CVSLCK. The storage is not allocated along with the
+ struct lock; it is allocated by the Reader_Lock caller or in the
+ case of promotablelocks, it is just a pointer to the storage allocated
+ for the ->key field. */
+ const char *repository;
+
+ /* The name of the lock files. */
+ char *file1;
+#ifdef LOCK_COMPATIBILITY
+ char *file2;
+#endif /* LOCK_COMPATIBILITY */
+
+ /* The name of the master lock dir. Usually CVSLCK. */
+ const char *lockdirname;
+
+ /* The full path to the lock dir, if we are currently holding it.
+ *
+ * This will be LOCKDIRNAME catted onto REPOSITORY. We waste a little
+ * space by storing it, but save a later malloc/free.
+ */
+ char *lockdir;
+
+ /* Note there is no way of knowing whether the readlock and writelock
+ exist. The code which sets the locks doesn't use SIG_beginCrSect
+ to set a flag like we do for CVSLCK. */
+ bool free_repository;
+};
+
+static void remove_locks (void);
+static int set_lock (struct lock *lock, int will_wait);
+static void clear_lock (struct lock *lock);
+static void set_lockers_name (struct stat *statp);
+
+/* Malloc'd array containing the username of the whoever has the lock.
+ Will always be non-NULL in the cases where it is needed. */
+static char *lockers_name;
+/* Malloc'd array specifying name of a readlock within a directory.
+ Or NULL if none. */
+static char *readlock;
+/* Malloc'd array specifying name of a writelock within a directory.
+ Or NULL if none. */
+static char *writelock;
+/* Malloc'd array specifying name of a promotablelock within a directory.
+ Or NULL if none. */
+static char *promotablelock;
+static List *locklist;
+
+#define L_OK 0 /* success */
+#define L_ERROR 1 /* error condition */
+#define L_LOCKED 2 /* lock owned by someone else */
+
+/* This is the (single) readlock which is set by Reader_Lock. The
+ repository field is NULL if there is no such lock. */
+#ifdef LOCK_COMPATIBILITY
+static struct lock global_readlock = {NULL, NULL, NULL, CVSLCK, NULL, false};
+static struct lock global_writelock = {NULL, NULL, NULL, CVSLCK, NULL, false};
+
+static struct lock global_history_lock = {NULL, NULL, NULL, CVSHISTORYLCK,
+ NULL, false};
+static struct lock global_val_tags_lock = {NULL, NULL, NULL, CVSVALTAGSLCK,
+ NULL, false};
+#else
+static struct lock global_readlock = {NULL, NULL, CVSLCK, NULL, false};
+static struct lock global_writelock = {NULL, NULL, CVSLCK, NULL, false};
+
+static struct lock global_history_lock = {NULL, NULL, CVSHISTORYLCK, NULL,
+ false};
+static struct lock global_val_tags_lock = {NULL, NULL, CVSVALTAGSLCK, NULL,
+ false};
+#endif /* LOCK_COMPATIBILITY */
+
+/* List of locks set by lock_tree_for_write. This is redundant
+ with locklist, sort of. */
+static List *lock_tree_list;
+
+
+
+/* Return a newly malloc'd string containing the name of the lock for the
+ repository REPOSITORY and the lock file name within that directory
+ NAME. Also create the directories in which to put the lock file
+ if needed (if we need to, could save system call(s) by doing
+ that only if the actual operation fails. But for now we'll keep
+ things simple). */
+static char *
+lock_name (const char *repository, const char *name)
+{
+ char *retval;
+ const char *p;
+ char *q;
+ const char *short_repos;
+ mode_t save_umask = 0000;
+ int saved_umask = 0;
+
+ TRACE (TRACE_FLOW, "lock_name (%s, %s)",
+ repository ? repository : "(null)", name ? name : "(null)");
+
+ if (!config->lock_dir)
+ {
+ /* This is the easy case. Because the lock files go directly
+ in the repository, no need to create directories or anything. */
+ assert (name != NULL);
+ assert (repository != NULL);
+ retval = Xasprintf ("%s/%s", repository, name);
+ }
+ else
+ {
+ struct stat sb;
+ mode_t new_mode = 0;
+
+ /* The interesting part of the repository is the part relative
+ to CVSROOT. */
+ assert (current_parsed_root != NULL);
+ assert (current_parsed_root->directory != NULL);
+ assert (strncmp (repository, current_parsed_root->directory,
+ strlen (current_parsed_root->directory)) == 0);
+ short_repos = repository + strlen (current_parsed_root->directory) + 1;
+
+ if (strcmp (repository, current_parsed_root->directory) == 0)
+ short_repos = ".";
+ else
+ assert (short_repos[-1] == '/');
+
+ retval = xmalloc (strlen (config->lock_dir)
+ + strlen (short_repos)
+ + strlen (name)
+ + 10);
+ strcpy (retval, config->lock_dir);
+ q = retval + strlen (retval);
+ *q++ = '/';
+
+ strcpy (q, short_repos);
+
+ /* In the common case, where the directory already exists, let's
+ keep it to one system call. */
+ if (stat (retval, &sb) < 0)
+ {
+ /* If we need to be creating more than one directory, we'll
+ get the existence_error here. */
+ if (!existence_error (errno))
+ error (1, errno, "cannot stat directory %s", retval);
+ }
+ else
+ {
+ if (S_ISDIR (sb.st_mode))
+ goto created;
+ else
+ error (1, 0, "%s is not a directory", retval);
+ }
+
+ /* Now add the directories one at a time, so we can create
+ them if needed.
+
+ The idea behind the new_mode stuff is that the directory we
+ end up creating will inherit permissions from its parent
+ directory (we re-set new_mode with each EEXIST). CVSUMASK
+ isn't right, because typically the reason for LockDir is to
+ use a different set of permissions. We probably want to
+ inherit group ownership also (but we don't try to deal with
+ that, some systems do it for us either always or when g+s is on).
+
+ We don't try to do anything about the permissions on the lock
+ files themselves. The permissions don't really matter so much
+ because the locks will generally be removed by the process
+ which created them. */
+
+ if (stat (config->lock_dir, &sb) < 0)
+ error (1, errno, "cannot stat %s", config->lock_dir);
+ new_mode = sb.st_mode;
+ save_umask = umask (0000);
+ saved_umask = 1;
+
+ p = short_repos;
+ while (1)
+ {
+ while (!ISSLASH (*p) && *p != '\0')
+ ++p;
+ if (ISSLASH (*p))
+ {
+ strncpy (q, short_repos, p - short_repos);
+ q[p - short_repos] = '\0';
+ if (!ISSLASH (q[p - short_repos - 1])
+ && CVS_MKDIR (retval, new_mode) < 0)
+ {
+ int saved_errno = errno;
+ if (saved_errno != EEXIST)
+ error (1, errno, "cannot make directory %s", retval);
+ else
+ {
+ if (stat (retval, &sb) < 0)
+ error (1, errno, "cannot stat %s", retval);
+ new_mode = sb.st_mode;
+ }
+ }
+ ++p;
+ }
+ else
+ {
+ strcpy (q, short_repos);
+ if (CVS_MKDIR (retval, new_mode) < 0
+ && errno != EEXIST)
+ error (1, errno, "cannot make directory %s", retval);
+ goto created;
+ }
+ }
+ created:;
+
+ strcat (retval, "/");
+ strcat (retval, name);
+
+ if (saved_umask)
+ {
+ assert (umask (save_umask) == 0000);
+ saved_umask = 0;
+ }
+ }
+ return retval;
+}
+
+
+
+/* Remove the lock files. For interrupt purposes, it can be assumed that the
+ * first thing this function does is set lock->repository to NULL.
+ *
+ * INPUTS
+ * lock The lock to remove.
+ * free True if this lock directory will not be reused (free
+ * lock->repository if necessary).
+ */
+static void
+remove_lock_files (struct lock *lock, bool free_repository)
+{
+ TRACE (TRACE_FLOW, "remove_lock_files (%s)", lock->repository);
+
+ /* If lock->file is set, the lock *might* have been created, but since
+ * Reader_Lock & lock_dir_for_write don't use SIG_beginCrSect the way that
+ * set_lock does, we don't know that. That is why we need to check for
+ * existence_error here.
+ */
+ if (lock->file1)
+ {
+ char *tmp = lock->file1;
+ lock->file1 = NULL;
+ if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", tmp);
+ free (tmp);
+ }
+#ifdef LOCK_COMPATIBILITY
+ if (lock->file2)
+ {
+ char *tmp = lock->file2;
+ lock->file2 = NULL;
+ if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", tmp);
+ free (tmp);
+ }
+#endif /* LOCK_COMPATIBILITY */
+
+ clear_lock (lock);
+
+ /* And free the repository string. We don't really have to set the
+ * repository string to NULL first since there is no harm in running any of
+ * the above code twice.
+ *
+ * Use SIG_beginCrSect since otherwise we might be interrupted between
+ * checking whether free_repository is set and freeing stuff.
+ */
+ if (free_repository)
+ {
+ SIG_beginCrSect ();
+ if (lock->free_repository)
+ {
+ free ((char *)lock->repository);
+ lock->free_repository = false;
+ }
+ lock->repository = NULL;
+ SIG_endCrSect ();
+ }
+}
+
+
+
+/*
+ * Clean up outstanding read and write locks and free their storage.
+ */
+void
+Simple_Lock_Cleanup (void)
+{
+ TRACE (TRACE_FUNCTION, "Simple_Lock_Cleanup()");
+
+ /* Avoid interrupts while accessing globals the interrupt handlers might
+ * make use of.
+ */
+ SIG_beginCrSect();
+
+ /* clean up simple read locks (if any) */
+ if (global_readlock.repository != NULL)
+ remove_lock_files (&global_readlock, true);
+ /* See note in Lock_Cleanup() below. */
+ SIG_endCrSect();
+
+ SIG_beginCrSect();
+
+ /* clean up simple write locks (if any) */
+ if (global_writelock.repository != NULL)
+ remove_lock_files (&global_writelock, true);
+ /* See note in Lock_Cleanup() below. */
+ SIG_endCrSect();
+
+ SIG_beginCrSect();
+
+ /* clean up simple write locks (if any) */
+ if (global_history_lock.repository)
+ remove_lock_files (&global_history_lock, true);
+ SIG_endCrSect();
+
+ SIG_beginCrSect();
+
+ if (global_val_tags_lock.repository)
+ remove_lock_files (&global_val_tags_lock, true);
+ /* See note in Lock_Cleanup() below. */
+ SIG_endCrSect();
+}
+
+
+
+/*
+ * Clean up all outstanding locks and free their storage.
+ *
+ * NOTES
+ * This function needs to be reentrant since a call to exit() can cause a
+ * call to this function, which can then be interrupted by a signal, which
+ * can cause a second call to this function.
+ *
+ * RETURNS
+ * Nothing.
+ */
+void
+Lock_Cleanup (void)
+{
+ TRACE (TRACE_FUNCTION, "Lock_Cleanup()");
+
+ /* FIXME: Do not perform buffered I/O from an interrupt handler like
+ * this (via error). However, I'm leaving the error-calling code there
+ * in the hope that on the rare occasion the error call is actually made
+ * (e.g., a fluky I/O error or permissions problem prevents the deletion
+ * of a just-created file) reentrancy won't be an issue.
+ */
+
+ remove_locks ();
+
+ /* Avoid being interrupted during calls which set globals to NULL. This
+ * avoids having interrupt handlers attempt to use these global variables
+ * in inconsistent states.
+ *
+ * This isn't always necessary, because sometimes we are called via exit()
+ * or the interrupt handler, in which case signals will already be blocked,
+ * but sometimes we might be called from elsewhere.
+ */
+ SIG_beginCrSect();
+ dellist (&lock_tree_list);
+ /* Unblocking allows any signal to be processed as soon as possible. This
+ * isn't really necessary, but since we know signals can cause us to be
+ * called, why not avoid having blocks of code run twice.
+ */
+ SIG_endCrSect();
+}
+
+
+
+/*
+ * walklist proc for removing a list of locks
+ */
+static int
+unlock_proc (Node *p, void *closure)
+{
+ remove_lock_files (p->data, false);
+ return 0;
+}
+
+
+
+/*
+ * Remove locks without discarding the lock information.
+ */
+static void
+remove_locks (void)
+{
+ TRACE (TRACE_FLOW, "remove_locks()");
+
+ Simple_Lock_Cleanup ();
+
+ /* clean up promotable locks (if any) */
+ SIG_beginCrSect();
+ if (locklist != NULL)
+ {
+ /* Use a tmp var since any of these functions could call exit, causing
+ * us to be called a second time.
+ */
+ List *tmp = locklist;
+ locklist = NULL;
+ walklist (tmp, unlock_proc, NULL);
+ }
+ SIG_endCrSect();
+}
+
+
+
+/*
+ * Set the global readlock variable if it isn't already.
+ */
+static void
+set_readlock_name (void)
+{
+ if (readlock == NULL)
+ {
+ readlock = Xasprintf (
+#ifdef HAVE_LONG_FILE_NAMES
+ "%s.%s.%ld", CVSRFL, hostname,
+#else
+ "%s.%ld", CVSRFL,
+#endif
+ (long) getpid ());
+ }
+}
+
+
+
+/*
+ * Create a lock file for readers
+ */
+int
+Reader_Lock (char *xrepository)
+{
+ int err = 0;
+ FILE *fp;
+
+ TRACE (TRACE_FUNCTION, "Reader_Lock(%s)", xrepository);
+
+ if (noexec || readonlyfs)
+ return 0;
+
+ /* we only do one directory at a time for read locks! */
+ if (global_readlock.repository != NULL)
+ {
+ error (0, 0, "Reader_Lock called while read locks set - Help!");
+ return 1;
+ }
+
+ set_readlock_name ();
+
+ /* remember what we're locking (for Lock_Cleanup) */
+ global_readlock.repository = xstrdup (xrepository);
+ global_readlock.free_repository = true;
+
+ /* get the lock dir for our own */
+ if (set_lock (&global_readlock, 1) != L_OK)
+ {
+ error (0, 0, "failed to obtain dir lock in repository `%s'",
+ xrepository);
+ if (readlock != NULL)
+ free (readlock);
+ readlock = NULL;
+ /* We don't set global_readlock.repository to NULL. I think this
+ only works because recurse.c will give a fatal error if we return
+ a nonzero value. */
+ return 1;
+ }
+
+ /* write a read-lock */
+ global_readlock.file1 = lock_name (xrepository, readlock);
+ if ((fp = CVS_FOPEN (global_readlock.file1, "w+")) == NULL
+ || fclose (fp) == EOF)
+ {
+ error (0, errno, "cannot create read lock in repository `%s'",
+ xrepository);
+ err = 1;
+ }
+
+ /* free the lock dir */
+ clear_lock (&global_readlock);
+
+ return err;
+}
+
+
+
+/*
+ * lock_exists() returns 0 if there is no lock file matching FILEPAT in
+ * the repository but not IGNORE; else 1 is returned, to indicate that the
+ * caller should sleep a while and try again.
+ *
+ * INPUTS
+ * repository The repository directory to search for locks.
+ * filepat The file name pattern to search for.
+ * ignore The name of a single file which can be ignored.
+ *
+ * GLOBALS
+ * lockdir The lock dir external to the repository, if any.
+ *
+ * RETURNS
+ * 0 No lock matching FILEPAT and not IGNORE exists.
+ * 1 Otherwise and on error.
+ *
+ * ERRORS
+ * In the case where errors are encountered reading the directory, a warning
+ * message is printed, 1 is is returned and ERRNO is left set.
+ */
+static int
+lock_exists (const char *repository, const char *filepat, const char *ignore)
+{
+ char *lockdir;
+ char *line;
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat sb;
+ int ret;
+#ifdef CVS_FUDGELOCKS
+ time_t now;
+ (void)time (&now);
+#endif
+
+ TRACE (TRACE_FLOW, "lock_exists (%s, %s, %s)",
+ repository, filepat, ignore ? ignore : "(null)");
+
+ lockdir = lock_name (repository, "");
+ lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */
+
+ do {
+ if ((dirp = CVS_OPENDIR (lockdir)) == NULL)
+ error (1, 0, "cannot open directory %s", lockdir);
+
+ ret = 0;
+ errno = 0;
+ while ((dp = CVS_READDIR (dirp)) != NULL)
+ {
+ if (CVS_FNMATCH (filepat, dp->d_name, 0) == 0)
+ {
+ /* FIXME: the basename conversion below should be replaced with
+ * a call to the GNULIB basename function once it is imported.
+ */
+ /* ignore our plock, if any */
+ if (ignore && !fncmp (ignore, dp->d_name))
+ continue;
+
+ line = Xasprintf ("%s/%s", lockdir, dp->d_name);
+ if (stat (line, &sb) != -1)
+ {
+#ifdef CVS_FUDGELOCKS
+ /*
+ * If the create time of the file is more than CVSLCKAGE
+ * seconds ago, try to clean-up the lock file, and if
+ * successful, re-open the directory and try again.
+ */
+ if (now >= (sb.st_ctime + CVSLCKAGE) &&
+ CVS_UNLINK (line) != -1)
+ {
+ free (line);
+ ret = -1;
+ break;
+ }
+#endif
+ set_lockers_name (&sb);
+ }
+ else
+ {
+ /* If the file doesn't exist, it just means that it
+ * disappeared between the time we did the readdir and the
+ * time we did the stat.
+ */
+ if (!existence_error (errno))
+ error (0, errno, "cannot stat %s", line);
+ }
+ errno = 0;
+ free (line);
+ ret = 1;
+ break;
+ }
+ errno = 0;
+ }
+ if (errno != 0)
+ error (0, errno, "error reading directory %s", repository);
+
+ CVS_CLOSEDIR (dirp);
+ } while (ret < 0);
+
+ if (lockdir != NULL)
+ free (lockdir);
+ return ret;
+}
+
+
+
+/*
+ * readers_exist() returns 0 if there are no reader lock files remaining in
+ * the repository; else 1 is returned, to indicate that the caller should
+ * sleep a while and try again.
+ *
+ * See lock_exists() for argument detail.
+ */
+static int
+readers_exist (const char *repository)
+{
+ TRACE (TRACE_FLOW, "readers_exist (%s)", repository);
+
+ /* It is only safe to ignore a readlock set by our process if it was set as
+ * a safety measure to prevent older CVS processes from ignoring our
+ * promotable locks. The code to ignore these readlocks can be removed
+ * once it is deemed unlikely that anyone will be using CVS servers earlier
+ * than version 1.12.4.
+ */
+ return lock_exists (repository, CVSRFLPAT,
+#ifdef LOCK_COMPATIBILITY
+ findnode (locklist, repository) ? readlock :
+#endif /* LOCK_COMPATIBILITY */
+ NULL);
+}
+
+
+
+/*
+ * promotable_exists() returns 0 if there is no promotable lock file in
+ * the repository; else 1 is returned, to indicate that the caller should
+ * sleep a while and try again.
+ *
+ * See lock_exists() for argument detail.
+ */
+static int
+promotable_exists (const char *repository)
+{
+ TRACE (TRACE_FLOW, "promotable_exists (%s)", repository);
+ return lock_exists (repository, CVSPFLPAT, promotablelock);
+}
+
+
+
+/*
+ * Lock a list of directories for writing
+ */
+static char *lock_error_repos;
+static int lock_error;
+
+
+
+/*
+ * Create a lock file for potential writers returns L_OK if lock set ok,
+ * L_LOCKED if lock held by someone else or L_ERROR if an error occurred.
+ */
+static int
+set_promotable_lock (struct lock *lock)
+{
+ int status;
+ FILE *fp;
+
+ TRACE (TRACE_FUNCTION, "set_promotable_lock(%s)",
+ lock->repository ? lock->repository : "(null)");
+
+ if (promotablelock == NULL)
+ {
+ promotablelock = Xasprintf (
+#ifdef HAVE_LONG_FILE_NAMES
+ "%s.%s.%ld", CVSPFL, hostname,
+#else
+ "%s.%ld", CVSPFL,
+#endif
+ (long) getpid());
+ }
+
+ /* make sure the lock dir is ours (not necessarily unique to us!) */
+ status = set_lock (lock, 0);
+ if (status == L_OK)
+ {
+ /* we now own a promotable lock - make sure there are no others */
+ if (promotable_exists (lock->repository))
+ {
+ /* clean up the lock dir */
+ clear_lock (lock);
+
+ /* indicate we failed due to read locks instead of error */
+ return L_LOCKED;
+ }
+
+ /* write the promotable-lock file */
+ lock->file1 = lock_name (lock->repository, promotablelock);
+ if ((fp = CVS_FOPEN (lock->file1, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ int xerrno = errno;
+
+ if (CVS_UNLINK (lock->file1) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", lock->file1);
+
+ /* free the lock dir */
+ clear_lock (lock);
+
+ /* return the error */
+ error (0, xerrno,
+ "cannot create promotable lock in repository `%s'",
+ lock->repository);
+ return L_ERROR;
+ }
+
+#ifdef LOCK_COMPATIBILITY
+ /* write the read-lock file. We only do this so that older versions of
+ * CVS will not think it is okay to create a write lock. When it is
+ * decided that versions of CVS earlier than 1.12.4 are not likely to
+ * be used, this code can be removed.
+ */
+ set_readlock_name ();
+ lock->file2 = lock_name (lock->repository, readlock);
+ if ((fp = CVS_FOPEN (lock->file2, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ int xerrno = errno;
+
+ if ( CVS_UNLINK (lock->file2) < 0 && ! existence_error (errno))
+ error (0, errno, "failed to remove lock %s", lock->file2);
+
+ /* free the lock dir */
+ clear_lock (lock);
+
+ /* Remove the promotable lock. */
+ lock->file2 = NULL;
+ remove_lock_files (lock, false);
+
+ /* return the error */
+ error (0, xerrno,
+ "cannot create read lock in repository `%s'",
+ lock->repository);
+ return L_ERROR;
+ }
+#endif /* LOCK_COMPATIBILITY */
+
+ clear_lock (lock);
+
+ return L_OK;
+ }
+ else
+ return status;
+}
+
+
+
+/*
+ * walklist proc for setting write locks. Mostly just a wrapper for the
+ * set_promotable_lock function, which has a prettier API, but no other good
+ * reason for existing separately.
+ *
+ * INPUTS
+ * p The current node, as determined by walklist().
+ * closure Not used.
+ *
+ * GLOBAL INPUTS
+ * lock_error Any previous error encountered while attempting to get
+ * a lock.
+ *
+ * GLOBAL OUTPUTS
+ * lock_error Set if we encounter an error attempting to get axi
+ * promotable lock.
+ * lock_error_repos Set so that if we set lock_error later functions will
+ * be able to report where the other process's lock was
+ * encountered.
+ *
+ * RETURNS
+ * 0 for no error.
+ */
+static int
+set_promotablelock_proc (Node *p, void *closure)
+{
+ /* if some lock was not OK, just skip this one */
+ if (lock_error != L_OK)
+ return 0;
+
+ /* apply the write lock */
+ lock_error_repos = p->key;
+ lock_error = set_promotable_lock ((struct lock *)p->data);
+ return 0;
+}
+
+
+
+/*
+ * Print out a message that the lock is still held, then sleep a while.
+ */
+static void
+lock_wait (const char *repos)
+{
+ time_t now;
+ char *msg;
+ struct tm *tm_p;
+
+ (void) time (&now);
+ tm_p = gmtime (&now);
+ msg = Xasprintf ("[%8.8s] waiting for %s's lock in %s",
+ (tm_p ? asctime (tm_p) : ctime (&now)) + 11,
+ lockers_name, repos);
+ error (0, 0, "%s", msg);
+ /* Call cvs_flusherr to ensure that the user sees this message as
+ soon as possible. */
+ cvs_flusherr ();
+ free (msg);
+ (void)sleep (CVSLCKSLEEP);
+}
+
+
+
+/*
+ * Print out a message when we obtain a lock.
+ */
+static void
+lock_obtained (const char *repos)
+{
+ time_t now;
+ char *msg;
+ struct tm *tm_p;
+
+ (void) time (&now);
+ tm_p = gmtime (&now);
+ msg = Xasprintf ("[%8.8s] obtained lock in %s",
+ (tm_p ? asctime (tm_p) : ctime (&now)) + 11, repos);
+ error (0, 0, "%s", msg);
+ /* Call cvs_flusherr to ensure that the user sees this message as
+ soon as possible. */
+ cvs_flusherr ();
+ free (msg);
+}
+
+
+
+static int
+lock_list_promotably (List *list)
+{
+ char *wait_repos;
+
+ TRACE (TRACE_FLOW, "lock_list_promotably ()");
+
+ if (noexec)
+ return 0;
+
+ if (readonlyfs) {
+ error (0, 0,
+ "promotable lock failed.\n\
+WARNING: Read-only repository access mode selected via `cvs -R'.\n\
+Attempting to write to a read-only filesystem is not allowed.");
+ return 1;
+ }
+
+ /* We only know how to do one list at a time */
+ if (locklist != NULL)
+ {
+ error (0, 0,
+ "lock_list_promotably called while promotable locks set - Help!");
+ return 1;
+ }
+
+ wait_repos = NULL;
+ for (;;)
+ {
+ /* try to lock everything on the list */
+ lock_error = L_OK; /* init for set_promotablelock_proc */
+ lock_error_repos = NULL; /* init for set_promotablelock_proc */
+ locklist = list; /* init for Lock_Cleanup */
+ if (lockers_name != NULL)
+ free (lockers_name);
+ lockers_name = xstrdup ("unknown");
+
+ (void) walklist (list, set_promotablelock_proc, NULL);
+
+ switch (lock_error)
+ {
+ case L_ERROR: /* Real Error */
+ if (wait_repos != NULL)
+ free (wait_repos);
+ Lock_Cleanup (); /* clean up any locks we set */
+ error (0, 0, "lock failed - giving up");
+ return 1;
+
+ case L_LOCKED: /* Someone already had a lock */
+ remove_locks (); /* clean up any locks we set */
+ lock_wait (lock_error_repos); /* sleep a while and try again */
+ wait_repos = xstrdup (lock_error_repos);
+ continue;
+
+ case L_OK: /* we got the locks set */
+ if (wait_repos != NULL)
+ {
+ lock_obtained (wait_repos);
+ free (wait_repos);
+ }
+ return 0;
+
+ default:
+ if (wait_repos != NULL)
+ free (wait_repos);
+ error (0, 0, "unknown lock status %d in lock_list_promotably",
+ lock_error);
+ return 1;
+ }
+ }
+}
+
+
+
+/*
+ * Set the static variable lockers_name appropriately, based on the stat
+ * structure passed in.
+ */
+static void
+set_lockers_name (struct stat *statp)
+{
+ struct passwd *pw;
+
+ if (lockers_name != NULL)
+ free (lockers_name);
+ pw = (struct passwd *) getpwuid (statp->st_uid);
+ if (pw != NULL)
+ lockers_name = xstrdup (pw->pw_name);
+ else
+ lockers_name = Xasprintf ("uid%lu", (unsigned long) statp->st_uid);
+}
+
+
+
+/*
+ * Persistently tries to make the directory "lckdir", which serves as a
+ * lock.
+ *
+ * #ifdef CVS_FUDGELOCKS
+ * If the create time on the directory is greater than CVSLCKAGE
+ * seconds old, just try to remove the directory.
+ * #endif
+ *
+ */
+static int
+set_lock (struct lock *lock, int will_wait)
+{
+ int waited;
+ long us;
+ struct stat sb;
+ mode_t omask;
+ char *masterlock;
+ int status;
+#ifdef CVS_FUDGELOCKS
+ time_t now;
+#endif
+
+ TRACE (TRACE_FLOW, "set_lock (%s, %d)",
+ lock->repository ? lock->repository : "(null)", will_wait);
+
+ masterlock = lock_name (lock->repository, lock->lockdirname);
+
+ /*
+ * Note that it is up to the callers of set_lock() to arrange for signal
+ * handlers that do the appropriate things, like remove the lock
+ * directory before they exit.
+ */
+ waited = 0;
+ us = 1;
+ for (;;)
+ {
+ status = -1;
+ omask = umask (cvsumask);
+ SIG_beginCrSect ();
+ if (CVS_MKDIR (masterlock, 0777) == 0)
+ {
+ lock->lockdir = masterlock;
+ SIG_endCrSect ();
+ status = L_OK;
+ if (waited)
+ lock_obtained (lock->repository);
+ goto after_sig_unblock;
+ }
+ SIG_endCrSect ();
+ after_sig_unblock:
+ (void) umask (omask);
+ if (status != -1)
+ goto done;
+
+ if (errno != EEXIST)
+ {
+ error (0, errno,
+ "failed to create lock directory for `%s' (%s)",
+ lock->repository, masterlock);
+ status = L_ERROR;
+ goto done;
+ }
+
+ /* Find out who owns the lock. If the lock directory is
+ non-existent, re-try the loop since someone probably just
+ removed it (thus releasing the lock). */
+ if (stat (masterlock, &sb) < 0)
+ {
+ if (existence_error (errno))
+ continue;
+
+ error (0, errno, "couldn't stat lock directory `%s'", masterlock);
+ status = L_ERROR;
+ goto done;
+ }
+
+#ifdef CVS_FUDGELOCKS
+ /*
+ * If the create time of the directory is more than CVSLCKAGE seconds
+ * ago, try to clean-up the lock directory, and if successful, just
+ * quietly retry to make it.
+ */
+ (void) time (&now);
+ if (now >= (sb.st_ctime + CVSLCKAGE))
+ {
+ if (CVS_RMDIR (masterlock) >= 0)
+ continue;
+ }
+#endif
+
+ /* set the lockers name */
+ set_lockers_name (&sb);
+
+ /* if he wasn't willing to wait, return an error */
+ if (!will_wait)
+ {
+ status = L_LOCKED;
+ goto done;
+ }
+
+ /* if possible, try a very short sleep without a message */
+ if (!waited && us < 1000)
+ {
+ us += us;
+ {
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = us * 1000;
+ (void)nanosleep (&ts, NULL);
+ continue;
+ }
+ }
+
+ lock_wait (lock->repository);
+ waited = 1;
+ }
+
+done:
+ if (!lock->lockdir)
+ free (masterlock);
+ return status;
+}
+
+
+
+/*
+ * Clear master lock.
+ *
+ * INPUTS
+ * lock The lock information.
+ *
+ * OUTPUTS
+ * Sets LOCK->lockdir to NULL after removing the directory it names and
+ * freeing the storage.
+ *
+ * ASSUMPTIONS
+ * If we own the master lock directory, its name is stored in LOCK->lockdir.
+ * We may free LOCK->lockdir.
+ */
+static void
+clear_lock (struct lock *lock)
+{
+ SIG_beginCrSect ();
+ if (lock->lockdir)
+ {
+ if (CVS_RMDIR (lock->lockdir) < 0)
+ error (0, errno, "failed to remove lock dir `%s'", lock->lockdir);
+ free (lock->lockdir);
+ lock->lockdir = NULL;
+ }
+ SIG_endCrSect ();
+}
+
+
+
+/*
+ * Create a list of repositories to lock
+ */
+/* ARGSUSED */
+static int
+lock_filesdoneproc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ Node *p;
+
+ p = getnode ();
+ p->type = LOCK;
+ p->key = xstrdup (repository);
+ p->data = xmalloc (sizeof (struct lock));
+ ((struct lock *)p->data)->repository = p->key;
+ ((struct lock *)p->data)->file1 = NULL;
+#ifdef LOCK_COMPATIBILITY
+ ((struct lock *)p->data)->file2 = NULL;
+#endif /* LOCK_COMPATIBILITY */
+ ((struct lock *)p->data)->lockdirname = CVSLCK;
+ ((struct lock *)p->data)->lockdir = NULL;
+ ((struct lock *)p->data)->free_repository = false;
+
+ /* FIXME-KRP: this error condition should not simply be passed by. */
+ if (p->key == NULL || addnode (lock_tree_list, p) != 0)
+ freenode (p);
+ return err;
+}
+
+
+
+void
+lock_tree_promotably (int argc, char **argv, int local, int which, int aflag)
+{
+ TRACE (TRACE_FUNCTION, "lock_tree_promotably (%d, argv, %d, %d, %d)",
+ argc, local, which, aflag);
+
+ /*
+ * Run the recursion processor to find all the dirs to lock and lock all
+ * the dirs
+ */
+ lock_tree_list = getlist ();
+ start_recursion
+ (NULL, lock_filesdoneproc,
+ NULL, NULL, NULL, argc,
+ argv, local, which, aflag, CVS_LOCK_NONE,
+ NULL, 0, NULL );
+ sortlist (lock_tree_list, fsortcmp);
+ if (lock_list_promotably (lock_tree_list) != 0)
+ error (1, 0, "lock failed - giving up");
+}
+
+
+
+/* Lock a single directory in REPOSITORY. It is OK to call this if
+ * a lock has been set with lock_dir_for_write; the new lock will replace
+ * the old one. If REPOSITORY is NULL, don't do anything.
+ *
+ * We do not clear the dir lock after writing the lock file name since write
+ * locks are exclusive to all other locks.
+ */
+void
+lock_dir_for_write (const char *repository)
+{
+ int waiting = 0;
+
+ TRACE (TRACE_FLOW, "lock_dir_for_write (%s)", repository);
+
+ if (repository != NULL
+ && (global_writelock.repository == NULL
+ || !strcmp (global_writelock.repository, repository)))
+ {
+ if (writelock == NULL)
+ {
+ writelock = Xasprintf (
+#ifdef HAVE_LONG_FILE_NAMES
+ "%s.%s.%ld", CVSWFL, hostname,
+#else
+ "%s.%ld", CVSWFL,
+#endif
+ (long) getpid());
+ }
+
+ if (global_writelock.repository != NULL)
+ remove_lock_files (&global_writelock, true);
+
+ global_writelock.repository = xstrdup (repository);
+ global_writelock.free_repository = true;
+
+ for (;;)
+ {
+ FILE *fp;
+
+ if (set_lock (&global_writelock, 1) != L_OK)
+ error (1, 0, "failed to obtain write lock in repository `%s'",
+ repository);
+
+ /* check if readers exist */
+ if (readers_exist (repository)
+ || promotable_exists (repository))
+ {
+ clear_lock (&global_writelock);
+ lock_wait (repository); /* sleep a while and try again */
+ waiting = 1;
+ continue;
+ }
+
+ if (waiting)
+ lock_obtained (repository);
+
+ /* write the write-lock file */
+ global_writelock.file1 = lock_name (global_writelock.repository,
+ writelock);
+ if ((fp = CVS_FOPEN (global_writelock.file1, "w+")) == NULL
+ || fclose (fp) == EOF)
+ {
+ int xerrno = errno;
+
+ if (CVS_UNLINK (global_writelock.file1) < 0
+ && !existence_error (errno))
+ {
+ error (0, errno, "failed to remove write lock %s",
+ global_writelock.file1);
+ }
+
+ /* free the lock dir */
+ clear_lock (&global_writelock);
+
+ /* return the error */
+ error (1, xerrno,
+ "cannot create write lock in repository `%s'",
+ global_writelock.repository);
+ }
+
+ /* If we upgraded from a promotable lock, remove it. */
+ if (locklist)
+ {
+ Node *p = findnode (locklist, repository);
+ if (p)
+ {
+ remove_lock_files (p->data, true);
+ delnode (p);
+ }
+ }
+
+ break;
+ }
+ }
+}
+
+
+
+/* This is the internal implementation behind history_lock & val_tags_lock. It
+ * gets a write lock for the history or val-tags file.
+ *
+ * RETURNS
+ * true, on success
+ * false, on error
+ */
+static inline int
+internal_lock (struct lock *lock, const char *xrepository)
+{
+ /* remember what we're locking (for Lock_Cleanup) */
+ assert (!lock->repository);
+ lock->repository = Xasprintf ("%s/%s", xrepository, CVSROOTADM);
+ lock->free_repository = true;
+
+ /* get the lock dir for our own */
+ if (set_lock (lock, 1) != L_OK)
+ {
+ if (!really_quiet)
+ error (0, 0, "failed to obtain history lock in repository `%s'",
+ xrepository);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+/* Lock the CVSROOT/history file for write.
+ */
+int
+history_lock (const char *xrepository)
+{
+ return internal_lock (&global_history_lock, xrepository);
+}
+
+
+
+/* Remove the CVSROOT/history lock, if it exists.
+ */
+void
+clear_history_lock ()
+{
+ remove_lock_files (&global_history_lock, true);
+}
+
+
+
+/* Lock the CVSROOT/val-tags file for write.
+ */
+int
+val_tags_lock (const char *xrepository)
+{
+ return internal_lock (&global_val_tags_lock, xrepository);
+}
+
+
+
+/* Remove the CVSROOT/val-tags lock, if it exists.
+ */
+void
+clear_val_tags_lock ()
+{
+ remove_lock_files (&global_val_tags_lock, true);
+}
diff --git a/src/log-buffer.c b/src/log-buffer.c
new file mode 100644
index 0000000..c7cb6a9
--- /dev/null
+++ b/src/log-buffer.c
@@ -0,0 +1,529 @@
+/* CVS client logging buffer.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "cvs.h"
+#include "buffer.h"
+
+#if defined CLIENT_SUPPORT || defined SERVER_SUPPORT
+
+/* We want to be able to log data sent between us and the server. We
+ do it using log buffers. Each log buffer has another buffer which
+ handles the actual I/O, and a file to log information to.
+
+ This structure is the closure field of a log buffer. */
+
+struct log_buffer
+{
+ /* The underlying buffer. */
+ struct buffer *buf;
+ /* The file to log information to. */
+ FILE *log;
+
+#ifdef PROXY_SUPPORT
+ /* Whether errors writing to the log file should be fatal or not. */
+ bool fatal_errors;
+
+ /* The name of the file backing this buffer so that it may be deleted on
+ * buffer shutdown.
+ */
+ char *back_fn;
+
+ /* Set once logging is permanently disabled for a buffer. */
+ bool disabled;
+
+ /* The memory buffer (cache) backing this log. */
+ struct buffer *back_buf;
+
+ /* The maximum number of bytes to store in memory before beginning logging
+ * to a file.
+ */
+ size_t max;
+
+ /* Once we start logging to a file we do not want to stop unless asked. */
+ bool tofile;
+#endif /* PROXY_SUPPORT */
+};
+
+
+
+#ifdef PROXY_SUPPORT
+/* Force the existance of lb->log.
+ *
+ * INPUTS
+ * lb The log buffer.
+ *
+ * OUTPUTS
+ * lb->log The new FILE *.
+ * lb->back_fn The name of the new log, for later disposal.
+ *
+ * ASSUMPTIONS
+ * lb->log is NULL or, at least, does not require freeing.
+ * lb->back_fn is NULL or, at least, does not require freeing..
+ *
+ * RETURNS
+ * Nothing.
+ *
+ * ERRORS
+ * Errors creating the log file will output a message via error(). Whether
+ * the error is fatal or not is dependent on lb->fatal_errors.
+ */
+static inline void
+log_buffer_force_file (struct log_buffer *lb)
+{
+ lb->log = cvs_temp_file (&lb->back_fn);
+ if (!lb->log)
+ error (lb->fatal_errors, errno, "failed to open log file.");
+}
+#endif /* PROXY_SUPPORT */
+
+
+
+/* Create a log buffer.
+ *
+ * INPUTS
+ * buf A pointer to the buffer structure to log input from.
+ * fp A file name to log data to. May be NULL.
+#ifdef PROXY_SUPPORT
+ * fatal_errors Whether errors writing to a log file should be
+ * considered fatal.
+#else
+ * fatal_errors unused
+#endif
+ * input Whether we will log data for an input or output
+ * buffer.
+#ifdef PROXY_SUPPORT
+ * max The maximum size of our memory cache.
+#else
+ * max unused
+#endif
+ * memory The function to call when memory allocation errors are
+ * encountered.
+ *
+ * RETURNS
+ * A pointer to a new buffer structure.
+ */
+static int log_buffer_input (void *, char *, size_t, size_t, size_t *);
+static int log_buffer_output (void *, const char *, size_t, size_t *);
+static int log_buffer_flush (void *);
+static int log_buffer_block (void *, bool);
+static int log_buffer_get_fd (void *);
+static int log_buffer_shutdown (struct buffer *);
+struct buffer *
+log_buffer_initialize (struct buffer *buf, FILE *fp,
+# ifdef PROXY_SUPPORT
+ bool fatal_errors,
+ size_t max,
+# endif /* PROXY_SUPPORT */
+ bool input,
+ void (*memory) (struct buffer *))
+{
+ struct log_buffer *lb = xmalloc (sizeof *lb);
+ struct buffer *retbuf;
+
+ lb->buf = buf;
+ lb->log = fp;
+#ifdef PROXY_SUPPORT
+ lb->back_fn = NULL;
+ lb->fatal_errors = fatal_errors;
+ lb->disabled = false;
+ assert (size_in_bounds_p (max));
+ lb->max = max;
+ lb->tofile = false;
+ lb->back_buf = buf_nonio_initialize (memory);
+#endif /* PROXY_SUPPORT */
+ retbuf = buf_initialize (input ? log_buffer_input : NULL,
+ input ? NULL : log_buffer_output,
+ input ? NULL : log_buffer_flush,
+ log_buffer_block, log_buffer_get_fd,
+ log_buffer_shutdown, memory, lb);
+
+ if (!buf_empty_p (buf))
+ {
+ /* If our buffer already had data, copy it & log it if necessary. This
+ * can happen, for instance, with a pserver, where we deliberately do
+ * not instantiate the log buffer until after authentication so that
+ * auth data does not get logged (the pserver data will not be logged
+ * in this case, but any data which was left unused in the buffer by
+ * the auth code will be logged and put in our new buffer).
+ */
+ struct buffer_data *data;
+#ifdef PROXY_SUPPORT
+ size_t total = 0;
+#endif /* PROXY_SUPPORT */
+
+ for (data = buf->data; data != NULL; data = data->next)
+ {
+#ifdef PROXY_SUPPORT
+ if (!lb->tofile)
+ {
+ total = xsum (data->size, total);
+ if (total >= max)
+ lb->tofile = true;
+ }
+
+ if (lb->tofile)
+ {
+ if (!lb->log) log_buffer_force_file (lb);
+ if (lb->log)
+ {
+#endif /* PROXY_SUPPORT */
+ if (fwrite (data->bufp, 1, data->size, lb->log)
+ != (size_t) data->size)
+ error (
+#ifdef PROXY_SUPPORT
+ fatal_errors,
+#else /* !PROXY_SUPPORT */
+ false,
+#endif /* PROXY_SUPPORT */
+ errno, "writing to log file");
+ fflush (lb->log);
+#ifdef PROXY_SUPPORT
+ }
+ }
+ else
+ /* Log to memory buffer. */
+ buf_copy_data (lb->back_buf, data, data);
+#endif /* PROXY_SUPPORT */
+ }
+ buf_append_buffer (retbuf, buf);
+ }
+ return retbuf;
+}
+
+
+
+/* The input function for a log buffer. */
+static int
+log_buffer_input (void *closure, char *data, size_t need, size_t size,
+ size_t *got)
+{
+ struct log_buffer *lb = closure;
+ int status;
+
+ assert (lb->buf->input);
+
+ status = (*lb->buf->input) (lb->buf->closure, data, need, size, got);
+ if (status != 0)
+ return status;
+
+ if (
+#ifdef PROXY_SUPPORT
+ !lb->disabled &&
+#endif /* PROXY_SUPPORT */
+ *got > 0)
+ {
+#ifdef PROXY_SUPPORT
+ if (!lb->tofile
+ && xsum (*got, buf_count_mem (lb->back_buf)) >= lb->max)
+ lb->tofile = true;
+
+ if (lb->tofile)
+ {
+ if (!lb->log) log_buffer_force_file (lb);
+ if (lb->log)
+ {
+#endif /* PROXY_SUPPORT */
+ if (fwrite (data, 1, *got, lb->log) != *got)
+ error (
+#ifdef PROXY_SUPPORT
+ lb->fatal_errors,
+#else /* !PROXY_SUPPORT */
+ false,
+#endif /* PROXY_SUPPORT */
+ errno, "writing to log file");
+ fflush (lb->log);
+#ifdef PROXY_SUPPORT
+ }
+ }
+ else
+ /* Log to memory buffer. */
+ buf_output (lb->back_buf, data, *got);
+#endif /* PROXY_SUPPORT */
+ }
+
+ return 0;
+}
+
+
+
+/* The output function for a log buffer. */
+static int
+log_buffer_output (void *closure, const char *data, size_t have, size_t *wrote)
+{
+ struct log_buffer *lb = closure;
+ int status;
+
+ assert (lb->buf->output);
+
+ status = (*lb->buf->output) (lb->buf->closure, data, have, wrote);
+ if (status != 0)
+ return status;
+
+ if (
+#ifdef PROXY_SUPPORT
+ !lb->disabled &&
+#endif /* PROXY_SUPPORT */
+ *wrote > 0)
+ {
+#ifdef PROXY_SUPPORT
+ if (!lb->tofile
+ && xsum (*wrote, buf_count_mem (lb->back_buf)) >= lb->max)
+ lb->tofile = true;
+
+ if (lb->tofile)
+ {
+ if (!lb->log) log_buffer_force_file (lb);
+ if (lb->log)
+ {
+#endif /* PROXY_SUPPORT */
+ if (fwrite (data, 1, *wrote, lb->log) != *wrote)
+ error (
+#ifdef PROXY_SUPPORT
+ lb->fatal_errors,
+#else /* !PROXY_SUPPORT */
+ false,
+#endif /* PROXY_SUPPORT */
+ errno, "writing to log file");
+ fflush (lb->log);
+#ifdef PROXY_SUPPORT
+ }
+ }
+ else
+ /* Log to memory buffer. */
+ buf_output (lb->back_buf, data, *wrote);
+#endif /* PROXY_SUPPORT */
+ }
+
+ return 0;
+}
+
+
+
+/* The flush function for a log buffer. */
+static int
+log_buffer_flush (void *closure)
+{
+ struct log_buffer *lb = closure;
+
+ assert (lb->buf->flush);
+
+ /* We don't really have to flush the log file here, but doing it
+ * will let tail -f on the log file show what is sent to the
+ * network as it is sent.
+ */
+ if (lb->log && (fflush (lb->log)))
+ error (0, errno, "flushing log file");
+
+ return (*lb->buf->flush) (lb->buf->closure);
+}
+
+
+
+/* The block function for a log buffer. */
+static int
+log_buffer_block (void *closure, bool block)
+{
+ struct log_buffer *lb = closure;
+
+ if (block)
+ return set_block (lb->buf);
+ else
+ return set_nonblock (lb->buf);
+}
+
+
+
+#ifdef PROXY_SUPPORT
+/* Disable logging without shutting down the next buffer in the chain.
+ */
+struct buffer *
+log_buffer_rewind (struct buffer *buf)
+{
+ struct log_buffer *lb = buf->closure;
+ struct buffer *retbuf;
+ int fd;
+
+ lb->disabled = true;
+
+ if (lb->log)
+ {
+ FILE *tmp = lb->log;
+ lb->log = NULL;
+
+ /* flush & rewind the file. */
+ if (fflush (tmp) < 0)
+ error (0, errno, "flushing log file");
+ rewind (tmp);
+
+ /* Get a descriptor for the log and close the FILE *. */
+ fd = dup (fileno (tmp));
+ if (fclose (tmp) < 0)
+ error (0, errno, "closing log file");
+ }
+ else
+ fd = open (DEVNULL, O_RDONLY);
+
+ /* Catch dup/open errors. */
+ if (fd < 0)
+ {
+ error (lb->fatal_errors, errno, "failed to rewind log buf.");
+ return NULL;
+ }
+
+ /* Create a new fd buffer around the log. */
+ retbuf = fd_buffer_initialize (fd, 0, NULL, true, buf->memory_error);
+
+ {
+ struct buffer *tmp;
+ /* Insert the data which wasn't written to a file. */
+ buf_append_buffer (retbuf, lb->back_buf);
+ tmp = lb->back_buf;
+ lb->back_buf = NULL;
+ buf_free (tmp);
+ }
+
+ return retbuf;
+}
+#endif /* PROXY_SUPPORT */
+
+
+
+/* Disable logging and close the log without shutting down the next buffer in
+ * the chain.
+ */
+#ifndef PROXY_SUPPORT
+static
+#endif /* !PROXY_SUPPORT */
+void
+log_buffer_closelog (struct buffer *buf)
+{
+ struct log_buffer *lb = buf->closure;
+ void *tmp;
+
+#ifdef PROXY_SUPPORT
+ lb->disabled = true;
+#endif /* PROXY_SUPPORT */
+
+ /* Close the log. */
+ if (lb->log)
+ {
+ tmp = lb->log;
+ lb->log = NULL;
+ if (fclose (tmp) < 0)
+ error (0, errno, "closing log file");
+ }
+
+#ifdef PROXY_SUPPORT
+ /* Delete the log if we know its name. */
+ if (lb->back_fn)
+ {
+ tmp = lb->back_fn;
+ lb->back_fn = NULL;
+ if (CVS_UNLINK (tmp))
+ error (0, errno, "Failed to delete log file.");
+ free (tmp);
+ }
+
+ if (lb->back_buf)
+ {
+ tmp = lb->back_buf;
+ lb->back_buf = NULL;
+ buf_free (tmp);
+ }
+#endif /* PROXY_SUPPORT */
+}
+
+
+
+/* Return the file descriptor underlying any child buffers. */
+static int
+log_buffer_get_fd (void *closure)
+{
+ struct log_buffer *lb = closure;
+ return buf_get_fd (lb->buf);
+}
+
+
+
+/* The shutdown function for a log buffer. */
+static int
+log_buffer_shutdown (struct buffer *buf)
+{
+ struct log_buffer *lb = buf->closure;
+
+ log_buffer_closelog (buf);
+ return buf_shutdown (lb->buf);
+}
+
+
+
+void
+setup_logfiles (char *var, struct buffer **to_server_p,
+ struct buffer **from_server_p)
+{
+ char *log = getenv (var);
+
+ /* Set up logfiles, if any.
+ *
+ * We do this _after_ authentication on purpose. Wouldn't really like to
+ * worry about logging passwords...
+ */
+ if (log)
+ {
+ int len = strlen (log);
+ char *buf = xmalloc (len + 5);
+ char *p;
+ FILE *fp;
+
+ strcpy (buf, log);
+ p = buf + len;
+
+ /* Open logfiles in binary mode so that they reflect
+ exactly what was transmitted and received (that is
+ more important than that they be maximally
+ convenient to view). */
+ /* Note that if we create several connections in a single CVS client
+ (currently used by update.c), then the last set of logfiles will
+ overwrite the others. There is currently no way around this. */
+ strcpy (p, ".in");
+ fp = fopen (buf, "wb");
+ if (!fp)
+ error (0, errno, "opening to-server logfile %s", buf);
+ else
+ *to_server_p = log_buffer_initialize (*to_server_p, fp,
+# ifdef PROXY_SUPPORT
+ false,
+ 0,
+# endif /* PROXY_SUPPORT */
+ false, NULL);
+
+ strcpy (p, ".out");
+ fp = fopen (buf, "wb");
+ if (!fp)
+ error (0, errno, "opening from-server logfile %s", buf);
+ else
+ *from_server_p = log_buffer_initialize (*from_server_p, fp,
+# ifdef PROXY_SUPPORT
+ false,
+ 0,
+# endif /* PROXY_SUPPORT */
+ true, NULL);
+
+ free (buf);
+ }
+}
+
+#endif /* CLIENT_SUPPORT || SERVER_SUPPORT */
diff --git a/src/log-buffer.h b/src/log-buffer.h
new file mode 100644
index 0000000..f876d09
--- /dev/null
+++ b/src/log-buffer.h
@@ -0,0 +1,34 @@
+/* CVS client logging buffer.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+
+#ifndef LOG_BUFFER_H__
+#define LOG_BUFFER_H__
+
+void setup_logfiles (char *var, struct buffer** to_server_p,
+ struct buffer** from_server_p);
+
+struct buffer *
+log_buffer_initialize (struct buffer *buf, FILE *fp,
+# ifdef PROXY_SUPPORT
+ bool fatal_errors,
+ size_t max,
+# endif /* PROXY_SUPPORT */
+ bool input,
+ void (*memory) (struct buffer *));
+
+# ifdef PROXY_SUPPORT
+struct buffer *log_buffer_rewind (struct buffer *buf);
+void log_buffer_closelog (struct buffer *buf);
+# endif /* PROXY_SUPPORT */
+
+#endif /* LOG_BUFFER_H__ */
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..ed138df
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,1782 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Print Log Information
+ *
+ * Prints the RCS "log" (rlog) information for the specified files. With no
+ * argument, prints the log information for all the files in the directory
+ * (recursive by default).
+ */
+
+#include "cvs.h"
+#include <assert.h>
+
+/* This structure holds information parsed from the -r option. */
+
+struct option_revlist
+{
+ /* The next -r option. */
+ struct option_revlist *next;
+ /* The first revision to print. This is NULL if the range is
+ :rev, or if no revision is given. */
+ char *first;
+ /* The last revision to print. This is NULL if the range is rev:,
+ or if no revision is given. If there is no colon, first and
+ last are the same. */
+ char *last;
+ /* Nonzero if there was a trailing `.', which means to print only
+ the head revision of a branch. */
+ int branchhead;
+ /* Nonzero if first and last are inclusive. */
+ int inclusive;
+};
+
+/* This structure holds information derived from option_revlist given
+ a particular RCS file. */
+
+struct revlist
+{
+ /* The next pair. */
+ struct revlist *next;
+ /* The first numeric revision to print. */
+ char *first;
+ /* The last numeric revision to print. */
+ char *last;
+ /* The number of fields in these revisions (one more than
+ numdots). */
+ int fields;
+ /* Whether first & last are to be included or excluded. */
+ int inclusive;
+};
+
+/* This structure holds information parsed from the -d option. */
+
+struct datelist
+{
+ /* The next date. */
+ struct datelist *next;
+ /* The starting date. */
+ char *start;
+ /* The ending date. */
+ char *end;
+ /* Nonzero if the range is inclusive rather than exclusive. */
+ int inclusive;
+};
+
+/* This structure is used to pass information through start_recursion. */
+struct log_data
+{
+ /* Nonzero if the -R option was given, meaning that only the name
+ of the RCS file should be printed. */
+ int nameonly;
+ /* Nonzero if the -h option was given, meaning that only header
+ information should be printed. */
+ int header;
+ /* Nonzero if the -t option was given, meaning that only the
+ header and the descriptive text should be printed. */
+ int long_header;
+ /* Nonzero if the -N option was seen, meaning that tag information
+ should not be printed. */
+ int notags;
+ /* Nonzero if the -b option was seen, meaning that only revisions
+ on the default branch should be printed. */
+ int default_branch;
+ /* Nonzero if the -S option was seen, meaning that the header/name
+ should be suppressed if no revisions are selected. */
+ int sup_header;
+ /* If not NULL, the value given for the -r option, which lists
+ sets of revisions to be printed. */
+ struct option_revlist *revlist;
+ /* If not NULL, the date pairs given for the -d option, which
+ select date ranges to print. */
+ struct datelist *datelist;
+ /* If not NULL, the single dates given for the -d option, which
+ select specific revisions to print based on a date. */
+ struct datelist *singledatelist;
+ /* If not NULL, the list of states given for the -s option, which
+ only prints revisions of given states. */
+ List *statelist;
+ /* If not NULL, the list of login names given for the -w option,
+ which only prints revisions checked in by given users. */
+ List *authorlist;
+};
+
+/* This structure is used to pass information through walklist. */
+struct log_data_and_rcs
+{
+ struct log_data *log_data;
+ struct revlist *revlist;
+ RCSNode *rcs;
+};
+
+static int rlog_proc (int argc, char **argv, char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *mname, char *msg);
+static Dtype log_dirproc (void *callerdat, const char *dir,
+ const char *repository, const char *update_dir,
+ List *entries);
+static int log_fileproc (void *callerdat, struct file_info *finfo);
+static struct option_revlist *log_parse_revlist (const char *);
+static void log_parse_date (struct log_data *, const char *);
+static void log_parse_list (List **, const char *);
+static struct revlist *log_expand_revlist (RCSNode *, char *,
+ struct option_revlist *, int);
+static void log_free_revlist (struct revlist *);
+static int log_version_requested (struct log_data *, struct revlist *,
+ RCSNode *, RCSVers *);
+static int log_symbol (Node *, void *);
+static int log_count (Node *, void *);
+static int log_fix_singledate (Node *, void *);
+static int log_count_print (Node *, void *);
+static void log_tree (struct log_data *, struct revlist *,
+ RCSNode *, const char *);
+static void log_abranch (struct log_data *, struct revlist *,
+ RCSNode *, const char *);
+static void log_version (struct log_data *, struct revlist *,
+ RCSNode *, RCSVers *, int);
+static int log_branch (Node *, void *);
+static int version_compare (const char *, const char *, int);
+
+static struct log_data log_data;
+static int is_rlog;
+
+static const char *const log_usage[] =
+{
+ "Usage: %s %s [-lRhtNb] [-r[revisions]] [-d dates] [-s states]\n",
+ " [-w[logins]] [files...]\n",
+ "\t-l\tLocal directory only, no recursion.\n",
+ "\t-b\tOnly list revisions on the default branch.\n",
+ "\t-h\tOnly print header.\n",
+ "\t-R\tOnly print name of RCS file.\n",
+ "\t-t\tOnly print header and descriptive text.\n",
+ "\t-N\tDo not list tags.\n",
+ "\t-S\tDo not print name/header if no revisions selected. -d, -r,\n",
+ "\t\t-s, & -w have little effect in conjunction with -b, -h, -R, and\n",
+ "\t\t-t without this option.\n",
+ "\t-r[revisions]\tA comma-separated list of revisions to print:\n",
+ "\t rev1:rev2 Between rev1 and rev2, including rev1 and rev2.\n",
+ "\t rev1::rev2 Between rev1 and rev2, excluding rev1.\n",
+ "\t rev: rev and following revisions on the same branch.\n",
+ "\t rev:: After rev on the same branch.\n",
+ "\t :rev rev and previous revisions on the same branch.\n",
+ "\t ::rev rev and previous revisions on the same branch.\n",
+ "\t rev Just rev.\n",
+ "\t branch All revisions on the branch.\n",
+ "\t branch. The last revision on the branch.\n",
+ "\t-d dates\tA semicolon-separated list of dates\n",
+ "\t \t(D1<D2 for range, D for latest before).\n",
+ "\t-s states\tOnly list revisions with specified states.\n",
+ "\t-w[logins]\tOnly list revisions checked in by specified logins.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+#ifdef CLIENT_SUPPORT
+
+
+
+/* Helper function for send_arg_list. */
+static int
+send_one (Node *node, void *closure)
+{
+ char *option = closure;
+
+ send_to_server ("Argument ", 0);
+ send_to_server (option, 0);
+ if (strcmp (node->key, "@@MYSELF") == 0)
+ /* It is a bare -w option. Note that we must send it as
+ -w rather than messing with getcaller() or something (which on
+ the client will return garbage). */
+ ;
+ else
+ send_to_server (node->key, 0);
+ send_to_server ("\012", 0);
+ return 0;
+}
+
+
+
+/* For each element in ARG, send an argument consisting of OPTION
+ concatenated with that element. */
+static void
+send_arg_list (char *option, List *arg)
+{
+ if (arg == NULL)
+ return;
+ walklist (arg, send_one, option);
+}
+
+#endif
+
+
+
+int
+cvslog (int argc, char **argv)
+{
+ int c;
+ int err = 0;
+ int local = 0;
+ struct option_revlist **prl;
+
+ is_rlog = (strcmp (cvs_cmd_name, "rlog") == 0);
+
+ if (argc == -1)
+ usage (log_usage);
+
+ memset (&log_data, 0, sizeof log_data);
+ prl = &log_data.revlist;
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+bd:hlNSRr::s:tw::")) != -1)
+ {
+ switch (c)
+ {
+ case 'b':
+ log_data.default_branch = 1;
+ break;
+ case 'd':
+ log_parse_date (&log_data, optarg);
+ break;
+ case 'h':
+ log_data.header = 1;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'N':
+ log_data.notags = 1;
+ break;
+ case 'S':
+ log_data.sup_header = 1;
+ break;
+ case 'R':
+ log_data.nameonly = 1;
+ break;
+ case 'r':
+ *prl = log_parse_revlist (optarg);
+ prl = &(*prl)->next;
+ break;
+ case 's':
+ log_parse_list (&log_data.statelist, optarg);
+ break;
+ case 't':
+ log_data.long_header = 1;
+ break;
+ case 'w':
+ if (optarg != NULL)
+ log_parse_list (&log_data.authorlist, optarg);
+ else
+ log_parse_list (&log_data.authorlist, "@@MYSELF");
+ break;
+ case '?':
+ default:
+ usage (log_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ struct datelist *p;
+ struct option_revlist *rp;
+ char datetmp[MAXDATELEN];
+
+ /* We're the local client. Fire up the remote server. */
+ start_server ();
+
+ if (is_rlog && !supported_request ("rlog"))
+ error (1, 0, "server does not support rlog");
+
+ ign_setup ();
+
+ if (log_data.default_branch)
+ send_arg ("-b");
+
+ while (log_data.datelist != NULL)
+ {
+ p = log_data.datelist;
+ log_data.datelist = p->next;
+ send_to_server ("Argument -d\012", 0);
+ send_to_server ("Argument ", 0);
+ date_to_internet (datetmp, p->start);
+ send_to_server (datetmp, 0);
+ if (p->inclusive)
+ send_to_server ("<=", 0);
+ else
+ send_to_server ("<", 0);
+ date_to_internet (datetmp, p->end);
+ send_to_server (datetmp, 0);
+ send_to_server ("\012", 0);
+ if (p->start)
+ free (p->start);
+ if (p->end)
+ free (p->end);
+ free (p);
+ }
+ while (log_data.singledatelist != NULL)
+ {
+ p = log_data.singledatelist;
+ log_data.singledatelist = p->next;
+ send_to_server ("Argument -d\012", 0);
+ send_to_server ("Argument ", 0);
+ date_to_internet (datetmp, p->end);
+ send_to_server (datetmp, 0);
+ send_to_server ("\012", 0);
+ if (p->end)
+ free (p->end);
+ free (p);
+ }
+
+ if (log_data.header)
+ send_arg ("-h");
+ if (local)
+ send_arg("-l");
+ if (log_data.notags)
+ send_arg("-N");
+ if (log_data.sup_header)
+ send_arg("-S");
+ if (log_data.nameonly)
+ send_arg("-R");
+ if (log_data.long_header)
+ send_arg("-t");
+
+ while (log_data.revlist != NULL)
+ {
+ rp = log_data.revlist;
+ log_data.revlist = rp->next;
+ send_to_server ("Argument -r", 0);
+ if (rp->branchhead)
+ {
+ if (rp->first != NULL)
+ send_to_server (rp->first, 0);
+ send_to_server (".", 1);
+ }
+ else
+ {
+ if (rp->first != NULL)
+ send_to_server (rp->first, 0);
+ send_to_server (":", 1);
+ if (!rp->inclusive)
+ send_to_server (":", 1);
+ if (rp->last != NULL)
+ send_to_server (rp->last, 0);
+ }
+ send_to_server ("\012", 0);
+ if (rp->first)
+ free (rp->first);
+ if (rp->last)
+ free (rp->last);
+ free (rp);
+ }
+ send_arg_list ("-s", log_data.statelist);
+ dellist (&log_data.statelist);
+ send_arg_list ("-w", log_data.authorlist);
+ dellist (&log_data.authorlist);
+ send_arg ("--");
+
+ if (is_rlog)
+ {
+ int i;
+ for (i = 0; i < argc; i++)
+ send_arg (argv[i]);
+ send_to_server ("rlog\012", 0);
+ }
+ else
+ {
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("log\012", 0);
+ }
+ err = get_responses_and_close ();
+ return err;
+ }
+#endif
+
+ /* OK, now that we know we are local/server, we can resolve @@MYSELF
+ into our user name. */
+ if (findnode (log_data.authorlist, "@@MYSELF") != NULL)
+ log_parse_list (&log_data.authorlist, getcaller ());
+
+ if (is_rlog)
+ {
+ DBM *db;
+ int i;
+ db = open_module ();
+ for (i = 0; i < argc; i++)
+ {
+ err += do_module (db, argv[i], MISC, "Logging", rlog_proc,
+ NULL, 0, local, 0, 0, NULL);
+ }
+ close_module (db);
+ }
+ else
+ {
+ err = rlog_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL,
+ NULL);
+ }
+
+ while (log_data.revlist)
+ {
+ struct option_revlist *rl = log_data.revlist->next;
+ if (log_data.revlist->first)
+ free (log_data.revlist->first);
+ if (log_data.revlist->last)
+ free (log_data.revlist->last);
+ free (log_data.revlist);
+ log_data.revlist = rl;
+ }
+ while (log_data.datelist)
+ {
+ struct datelist *nd = log_data.datelist->next;
+ if (log_data.datelist->start)
+ free (log_data.datelist->start);
+ if (log_data.datelist->end)
+ free (log_data.datelist->end);
+ free (log_data.datelist);
+ log_data.datelist = nd;
+ }
+ while (log_data.singledatelist)
+ {
+ struct datelist *nd = log_data.singledatelist->next;
+ if (log_data.singledatelist->start)
+ free (log_data.singledatelist->start);
+ if (log_data.singledatelist->end)
+ free (log_data.singledatelist->end);
+ free (log_data.singledatelist);
+ log_data.singledatelist = nd;
+ }
+ dellist (&log_data.statelist);
+ dellist (&log_data.authorlist);
+
+ return err;
+}
+
+
+
+static int
+rlog_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile,
+ int shorten, int local, char *mname, char *msg)
+{
+ /* Begin section which is identical to patch_proc--should this
+ be abstracted out somehow? */
+ char *myargv[2];
+ int err = 0;
+ int which;
+ char *repository = NULL;
+ char *where;
+
+ if (is_rlog)
+ {
+ repository = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
+ (void)sprintf (repository, "%s/%s",
+ current_parsed_root->directory, argv[0]);
+ where = xmalloc (strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ + 1);
+ (void)strcpy (where, argv[0]);
+
+ /* If mfile isn't null, we need to set up to do only part of theu
+ * module.
+ */
+ if (mfile != NULL)
+ {
+ char *cp;
+ char *path;
+
+ /* If the portion of the module is a path, put the dir part on
+ * repos.
+ */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = '\0';
+ (void)strcat (repository, "/");
+ (void)strcat (repository, mfile);
+ (void)strcat (where, "/");
+ (void)strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+ /* take care of the rest */
+ path = Xasprintf ("%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* directory means repository gets the dir tacked on */
+ (void)strcpy (repository, path);
+ (void)strcat (where, "/");
+ (void)strcat (where, mfile);
+ }
+ else
+ {
+ myargv[0] = argv[0];
+ myargv[1] = mfile;
+ argc = 2;
+ argv = myargv;
+ }
+ free (path);
+ }
+
+ /* cd to the starting repository */
+ if (CVS_CHDIR (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ free (repository);
+ free (where);
+ return 1;
+ }
+ /* End section which is identical to patch_proc. */
+
+ which = W_REPOS | W_ATTIC;
+ }
+ else
+ {
+ repository = NULL;
+ where = NULL;
+ which = W_LOCAL | W_REPOS | W_ATTIC;
+ }
+
+ err = start_recursion (log_fileproc, NULL, log_dirproc,
+ NULL, &log_data,
+ argc - 1, argv + 1, local, which, 0, CVS_LOCK_READ,
+ where, 1, repository);
+
+ if (!(which & W_LOCAL)) free (repository);
+ if (where) free (where);
+
+ return err;
+}
+
+
+
+/*
+ * Parse a revision list specification.
+ */
+static struct option_revlist *
+log_parse_revlist (const char *argstring)
+{
+ char *orig_copy, *copy;
+ struct option_revlist *ret, **pr;
+
+ /* Unfortunately, rlog accepts -r without an argument to mean that
+ latest revision on the default branch, so we must support that
+ for compatibility. */
+ if (argstring == NULL)
+ argstring = "";
+
+ ret = NULL;
+ pr = &ret;
+
+ /* Copy the argument into memory so that we can change it. We
+ don't want to change the argument because, at least as of this
+ writing, we will use it if we send the arguments to the server. */
+ orig_copy = copy = xstrdup (argstring);
+ while (copy != NULL)
+ {
+ char *comma;
+ struct option_revlist *r;
+
+ comma = strchr (copy, ',');
+ if (comma != NULL)
+ *comma++ = '\0';
+
+ r = xmalloc (sizeof *r);
+ r->next = NULL;
+ r->first = copy;
+ r->branchhead = 0;
+ r->last = strchr (copy, ':');
+ if (r->last != NULL)
+ {
+ *r->last++ = '\0';
+ r->inclusive = (*r->last != ':');
+ if (!r->inclusive)
+ r->last++;
+ }
+ else
+ {
+ r->last = r->first;
+ r->inclusive = 1;
+ if (r->first[0] != '\0' && r->first[strlen (r->first) - 1] == '.')
+ {
+ r->branchhead = 1;
+ r->first[strlen (r->first) - 1] = '\0';
+ }
+ }
+
+ if (*r->first == '\0')
+ r->first = NULL;
+ if (*r->last == '\0')
+ r->last = NULL;
+
+ if (r->first != NULL)
+ r->first = xstrdup (r->first);
+ if (r->last != NULL)
+ r->last = xstrdup (r->last);
+
+ *pr = r;
+ pr = &r->next;
+
+ copy = comma;
+ }
+
+ free (orig_copy);
+ return ret;
+}
+
+
+
+/*
+ * Parse a date specification.
+ */
+static void
+log_parse_date (struct log_data *log_data, const char *argstring)
+{
+ char *orig_copy, *copy;
+
+ /* Copy the argument into memory so that we can change it. We
+ don't want to change the argument because, at least as of this
+ writing, we will use it if we send the arguments to the server. */
+ orig_copy = copy = xstrdup (argstring);
+ while (copy != NULL)
+ {
+ struct datelist *nd, **pd;
+ char *cpend, *cp, *ds, *de;
+
+ nd = xmalloc (sizeof *nd);
+
+ cpend = strchr (copy, ';');
+ if (cpend != NULL)
+ *cpend++ = '\0';
+
+ pd = &log_data->datelist;
+ nd->inclusive = 0;
+
+ if ((cp = strchr (copy, '>')) != NULL)
+ {
+ *cp++ = '\0';
+ if (*cp == '=')
+ {
+ ++cp;
+ nd->inclusive = 1;
+ }
+ ds = cp;
+ de = copy;
+ }
+ else if ((cp = strchr (copy, '<')) != NULL)
+ {
+ *cp++ = '\0';
+ if (*cp == '=')
+ {
+ ++cp;
+ nd->inclusive = 1;
+ }
+ ds = copy;
+ de = cp;
+ }
+ else
+ {
+ ds = NULL;
+ de = copy;
+ pd = &log_data->singledatelist;
+ }
+
+ if (ds == NULL)
+ nd->start = NULL;
+ else if (*ds != '\0')
+ nd->start = Make_Date (ds);
+ else
+ {
+ /* 1970 was the beginning of time, as far as get_date and
+ Make_Date are concerned. FIXME: That is true only if time_t
+ is a POSIX-style time and there is nothing in ANSI that
+ mandates that. It would be cleaner to set a flag saying
+ whether or not there is a start date. */
+ nd->start = Make_Date ("1/1/1970 UTC");
+ }
+
+ if (*de != '\0')
+ nd->end = Make_Date (de);
+ else
+ {
+ /* We want to set the end date to some time sufficiently far
+ in the future to pick up all revisions that have been
+ created since the specified date and the time `cvs log'
+ completes. FIXME: The date in question only makes sense
+ if time_t is a POSIX-style time and it is 32 bits
+ and signed. We should instead be setting a flag saying
+ whether or not there is an end date. Note that using
+ something like "next week" would break the testsuite (and,
+ perhaps less importantly, loses if the clock is set grossly
+ wrong). */
+ nd->end = Make_Date ("2038-01-01");
+ }
+
+ nd->next = *pd;
+ *pd = nd;
+
+ copy = cpend;
+ }
+
+ free (orig_copy);
+}
+
+
+
+/*
+ * Parse a comma separated list of items, and add each one to *PLIST.
+ */
+static void
+log_parse_list (List **plist, const char *argstring)
+{
+ while (1)
+ {
+ Node *p;
+ char *cp;
+
+ p = getnode ();
+
+ cp = strchr (argstring, ',');
+ if (cp == NULL)
+ p->key = xstrdup (argstring);
+ else
+ {
+ size_t len;
+
+ len = cp - argstring;
+ p->key = xmalloc (len + 1);
+ strncpy (p->key, argstring, len);
+ p->key[len] = '\0';
+ }
+
+ if (*plist == NULL)
+ *plist = getlist ();
+ if (addnode (*plist, p) != 0)
+ freenode (p);
+
+ if (cp == NULL)
+ break;
+
+ argstring = cp + 1;
+ }
+}
+
+
+
+static int
+printlock_proc (Node *lock, void *foo)
+{
+ cvs_output ("\n\t", 2);
+ cvs_output (lock->data, 0);
+ cvs_output (": ", 2);
+ cvs_output (lock->key, 0);
+ return 0;
+}
+
+
+
+/*
+ * Do an rlog on a file
+ */
+static int
+log_fileproc (void *callerdat, struct file_info *finfo)
+{
+ struct log_data *log_data = callerdat;
+ Node *p;
+ char *baserev;
+ int selrev = -1;
+ RCSNode *rcsfile;
+ char buf[50];
+ struct revlist *revlist = NULL;
+ struct log_data_and_rcs log_data_and_rcs;
+
+ rcsfile = finfo->rcs;
+ p = findnode (finfo->entries, finfo->file);
+ if (p != NULL)
+ {
+ Entnode *e = p->data;
+ baserev = e->version;
+ if (baserev[0] == '-') ++baserev;
+ }
+ else
+ baserev = NULL;
+
+ if (rcsfile == NULL)
+ {
+ /* no rcs file. What *do* we know about this file? */
+ if (baserev != NULL)
+ {
+ if (baserev[0] == '0' && baserev[1] == '\0')
+ {
+ if (!really_quiet)
+ error (0, 0, "%s has been added, but not committed",
+ finfo->file);
+ return 0;
+ }
+ }
+
+ if (!really_quiet)
+ error (0, 0, "nothing known about %s", finfo->file);
+
+ return 1;
+ }
+
+ if (log_data->sup_header || !log_data->nameonly)
+ {
+
+ /* We will need all the information in the RCS file. */
+ RCS_fully_parse (rcsfile);
+
+ /* Turn any symbolic revisions in the revision list into numeric
+ revisions. */
+ revlist = log_expand_revlist (rcsfile, baserev, log_data->revlist,
+ log_data->default_branch);
+ if (log_data->sup_header
+ || (!log_data->header && !log_data->long_header))
+ {
+ log_data_and_rcs.log_data = log_data;
+ log_data_and_rcs.revlist = revlist;
+ log_data_and_rcs.rcs = rcsfile;
+
+ /* If any single dates were specified, we need to identify the
+ revisions they select. Each one selects the single
+ revision, which is otherwise selected, of that date or
+ earlier. The log_fix_singledate routine will fill in the
+ start date for each specific revision. */
+ if (log_data->singledatelist != NULL)
+ walklist (rcsfile->versions, log_fix_singledate,
+ &log_data_and_rcs);
+
+ selrev = walklist (rcsfile->versions, log_count_print,
+ &log_data_and_rcs);
+ if (log_data->sup_header && selrev == 0)
+ {
+ log_free_revlist (revlist);
+ return 0;
+ }
+ }
+
+ }
+
+ if (log_data->nameonly)
+ {
+ cvs_output (rcsfile->print_path, 0);
+ cvs_output ("\n", 1);
+ log_free_revlist (revlist);
+ return 0;
+ }
+
+ /* The output here is intended to be exactly compatible with the
+ output of rlog. I'm not sure whether this code should be here
+ or in rcs.c; I put it here because it is specific to the log
+ function, even though it uses information gathered by the
+ functions in rcs.c. */
+
+ cvs_output ("\n", 1);
+
+ cvs_output ("RCS file: ", 0);
+ cvs_output (rcsfile->print_path, 0);
+
+ if (!is_rlog)
+ {
+ cvs_output ("\nWorking file: ", 0);
+ if (finfo->update_dir[0] != '\0')
+ {
+ cvs_output (finfo->update_dir, 0);
+ cvs_output ("/", 0);
+ }
+ cvs_output (finfo->file, 0);
+ }
+
+ cvs_output ("\nhead:", 0);
+ if (rcsfile->head != NULL)
+ {
+ cvs_output (" ", 1);
+ cvs_output (rcsfile->head, 0);
+ }
+
+ cvs_output ("\nbranch:", 0);
+ if (rcsfile->branch != NULL)
+ {
+ cvs_output (" ", 1);
+ cvs_output (rcsfile->branch, 0);
+ }
+
+ cvs_output ("\nlocks:", 0);
+ if (rcsfile->strict_locks)
+ cvs_output (" strict", 0);
+ walklist (RCS_getlocks (rcsfile), printlock_proc, NULL);
+
+ cvs_output ("\naccess list:", 0);
+ if (rcsfile->access != NULL)
+ {
+ const char *cp;
+
+ cp = rcsfile->access;
+ while (*cp != '\0')
+ {
+ const char *cp2;
+
+ cvs_output ("\n\t", 2);
+ cp2 = cp;
+ while (!isspace ((unsigned char)*cp2) && *cp2 != '\0')
+ ++cp2;
+ cvs_output (cp, cp2 - cp);
+ cp = cp2;
+ while (isspace ((unsigned char)*cp) && *cp != '\0')
+ ++cp;
+ }
+ }
+
+ if (!log_data->notags)
+ {
+ List *syms;
+
+ cvs_output ("\nsymbolic names:", 0);
+ syms = RCS_symbols (rcsfile);
+ walklist (syms, log_symbol, NULL);
+ }
+
+ cvs_output ("\nkeyword substitution: ", 0);
+ if (rcsfile->expand == NULL)
+ cvs_output ("kv", 2);
+ else
+ cvs_output (rcsfile->expand, 0);
+
+ cvs_output ("\ntotal revisions: ", 0);
+ sprintf (buf, "%d", walklist (rcsfile->versions, log_count, NULL));
+ cvs_output (buf, 0);
+
+ if (selrev >= 0)
+ {
+ cvs_output (";\tselected revisions: ", 0);
+ sprintf (buf, "%d", selrev);
+ cvs_output (buf, 0);
+ }
+
+ cvs_output ("\n", 1);
+
+ if (!log_data->header || log_data->long_header)
+ {
+ cvs_output ("description:\n", 0);
+ if (rcsfile->desc != NULL)
+ cvs_output (rcsfile->desc, 0);
+ }
+
+ if (!log_data->header && ! log_data->long_header && rcsfile->head != NULL)
+ {
+ p = findnode (rcsfile->versions, rcsfile->head);
+ if (p == NULL)
+ error (1, 0, "can not find head revision in `%s'",
+ finfo->fullname);
+ while (p != NULL)
+ {
+ RCSVers *vers = p->data;
+
+ log_version (log_data, revlist, rcsfile, vers, 1);
+ if (vers->next == NULL)
+ p = NULL;
+ else
+ {
+ p = findnode (rcsfile->versions, vers->next);
+ if (p == NULL)
+ error (1, 0, "can not find next revision `%s' in `%s'",
+ vers->next, finfo->fullname);
+ }
+ }
+
+ log_tree (log_data, revlist, rcsfile, rcsfile->head);
+ }
+
+ cvs_output("\
+=============================================================================\n",
+ 0);
+
+ /* Free up the new revlist and restore the old one. */
+ log_free_revlist (revlist);
+
+ /* If singledatelist is not NULL, free up the start dates we added
+ to it. */
+ if (log_data->singledatelist != NULL)
+ {
+ struct datelist *d;
+
+ for (d = log_data->singledatelist; d != NULL; d = d->next)
+ {
+ if (d->start != NULL)
+ free (d->start);
+ d->start = NULL;
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Fix up a revision list in order to compare it against versions.
+ * Expand any symbolic revisions.
+ */
+static struct revlist *
+log_expand_revlist (RCSNode *rcs, char *baserev,
+ struct option_revlist *revlist, int default_branch)
+{
+ struct option_revlist *r;
+ struct revlist *ret, **pr;
+
+ ret = NULL;
+ pr = &ret;
+ for (r = revlist; r != NULL; r = r->next)
+ {
+ struct revlist *nr;
+
+ nr = xmalloc (sizeof *nr);
+ nr->inclusive = r->inclusive;
+
+ if (r->first == NULL && r->last == NULL)
+ {
+ /* If both first and last are NULL, it means that we want
+ just the head of the default branch, which is RCS_head. */
+ nr->first = RCS_head (rcs);
+ if (!nr->first)
+ {
+ if (!really_quiet)
+ error (0, 0, "No head revision in archive `%s'.",
+ rcs->path);
+ nr->last = NULL;
+ nr->fields = 0;
+ }
+ else
+ {
+ nr->last = xstrdup (nr->first);
+ nr->fields = numdots (nr->first) + 1;
+ }
+ }
+ else if (r->branchhead)
+ {
+ char *branch;
+
+ /* Print just the head of the branch. */
+ if (isdigit ((unsigned char) r->first[0]))
+ nr->first = RCS_getbranch (rcs, r->first, 1);
+ else
+ {
+ branch = RCS_whatbranch (rcs, r->first);
+ if (branch == NULL)
+ nr->first = NULL;
+ else
+ {
+ nr->first = RCS_getbranch (rcs, branch, 1);
+ free (branch);
+ }
+ }
+ if (!nr->first)
+ {
+ if (!really_quiet)
+ error (0, 0, "warning: no branch `%s' in `%s'",
+ r->first, rcs->print_path);
+ nr->last = NULL;
+ nr->fields = 0;
+ }
+ else
+ {
+ nr->last = xstrdup (nr->first);
+ nr->fields = numdots (nr->first) + 1;
+ }
+ }
+ else
+ {
+ if (r->first == NULL || isdigit ((unsigned char) r->first[0]))
+ nr->first = xstrdup (r->first);
+ else
+ {
+ if (baserev && strcmp (r->first, TAG_BASE) == 0)
+ nr->first = xstrdup (baserev);
+ else if (RCS_nodeisbranch (rcs, r->first))
+ nr->first = RCS_whatbranch (rcs, r->first);
+ else
+ nr->first = RCS_gettag (rcs, r->first, 1, NULL);
+ if (nr->first == NULL && !really_quiet)
+ {
+ error (0, 0, "warning: no revision `%s' in `%s'",
+ r->first, rcs->print_path);
+ }
+ }
+
+ if (r->last == r->first || (r->last != NULL && r->first != NULL &&
+ strcmp (r->last, r->first) == 0))
+ nr->last = xstrdup (nr->first);
+ else if (r->last == NULL || isdigit ((unsigned char) r->last[0]))
+ nr->last = xstrdup (r->last);
+ else
+ {
+ if (baserev && strcmp (r->last, TAG_BASE) == 0)
+ nr->last = xstrdup (baserev);
+ else if (RCS_nodeisbranch (rcs, r->last))
+ nr->last = RCS_whatbranch (rcs, r->last);
+ else
+ nr->last = RCS_gettag (rcs, r->last, 1, NULL);
+ if (nr->last == NULL && !really_quiet)
+ {
+ error (0, 0, "warning: no revision `%s' in `%s'",
+ r->last, rcs->print_path);
+ }
+ }
+
+ /* Process the revision numbers the same way that rlog
+ does. This code is a bit cryptic for my tastes, but
+ keeping the same implementation as rlog ensures a
+ certain degree of compatibility. */
+ if (r->first == NULL && nr->last != NULL)
+ {
+ nr->fields = numdots (nr->last) + 1;
+ if (nr->fields < 2)
+ nr->first = xstrdup (".0");
+ else
+ {
+ char *cp;
+
+ nr->first = xstrdup (nr->last);
+ cp = strrchr (nr->first, '.');
+ assert (cp);
+ strcpy (cp + 1, "0");
+ }
+ }
+ else if (r->last == NULL && nr->first != NULL)
+ {
+ nr->fields = numdots (nr->first) + 1;
+ nr->last = xstrdup (nr->first);
+ if (nr->fields < 2)
+ nr->last[0] = '\0';
+ else
+ {
+ char *cp;
+
+ cp = strrchr (nr->last, '.');
+ assert (cp);
+ *cp = '\0';
+ }
+ }
+ else if (nr->first == NULL || nr->last == NULL)
+ nr->fields = 0;
+ else if (strcmp (nr->first, nr->last) == 0)
+ nr->fields = numdots (nr->last) + 1;
+ else
+ {
+ int ord;
+ int dots1 = numdots (nr->first);
+ int dots2 = numdots (nr->last);
+ if (dots1 > dots2 || (dots1 == dots2 &&
+ version_compare (nr->first, nr->last, dots1 + 1) > 0))
+ {
+ char *tmp = nr->first;
+ nr->first = nr->last;
+ nr->last = tmp;
+ nr->fields = dots2 + 1;
+ dots2 = dots1;
+ dots1 = nr->fields - 1;
+ }
+ else
+ nr->fields = dots1 + 1;
+ dots1 += (nr->fields & 1);
+ ord = version_compare (nr->first, nr->last, dots1);
+ if (ord > 0 || (nr->fields > 2 && ord < 0))
+ {
+ error (0, 0,
+ "invalid branch or revision pair %s:%s in `%s'",
+ r->first, r->last, rcs->print_path);
+ free (nr->first);
+ nr->first = NULL;
+ free (nr->last);
+ nr->last = NULL;
+ nr->fields = 0;
+ }
+ else
+ {
+ if (nr->fields <= dots2 && (nr->fields & 1))
+ {
+ char *p = Xasprintf ("%s.0", nr->first);
+ free (nr->first);
+ nr->first = p;
+ ++nr->fields;
+ }
+ while (nr->fields <= dots2)
+ {
+ char *p;
+ int i;
+
+ nr->next = NULL;
+ *pr = nr;
+ nr = xmalloc (sizeof *nr);
+ nr->inclusive = 1;
+ nr->first = xstrdup ((*pr)->last);
+ nr->last = xstrdup ((*pr)->last);
+ nr->fields = (*pr)->fields;
+ p = (*pr)->last;
+ for (i = 0; i < nr->fields; i++)
+ p = strchr (p, '.') + 1;
+ p[-1] = '\0';
+ p = strchr (nr->first + (p - (*pr)->last), '.');
+ if (p != NULL)
+ {
+ *++p = '0';
+ *++p = '\0';
+ nr->fields += 2;
+ }
+ else
+ ++nr->fields;
+ pr = &(*pr)->next;
+ }
+ }
+ }
+ }
+
+ nr->next = NULL;
+ *pr = nr;
+ pr = &nr->next;
+ }
+
+ /* If the default branch was requested, add a revlist entry for
+ it. This is how rlog handles this option. */
+ if (default_branch
+ && (rcs->head != NULL || rcs->branch != NULL))
+ {
+ struct revlist *nr;
+
+ nr = xmalloc (sizeof *nr);
+ if (rcs->branch != NULL)
+ nr->first = xstrdup (rcs->branch);
+ else
+ {
+ char *cp;
+
+ nr->first = xstrdup (rcs->head);
+ assert (nr->first);
+ cp = strrchr (nr->first, '.');
+ assert (cp);
+ *cp = '\0';
+ }
+ nr->last = xstrdup (nr->first);
+ nr->fields = numdots (nr->first) + 1;
+ nr->inclusive = 1;
+
+ nr->next = NULL;
+ *pr = nr;
+ }
+
+ return ret;
+}
+
+
+
+/*
+ * Free a revlist created by log_expand_revlist.
+ */
+static void
+log_free_revlist (struct revlist *revlist)
+{
+ struct revlist *r;
+
+ r = revlist;
+ while (r != NULL)
+ {
+ struct revlist *next;
+
+ if (r->first != NULL)
+ free (r->first);
+ if (r->last != NULL)
+ free (r->last);
+ next = r->next;
+ free (r);
+ r = next;
+ }
+}
+
+
+
+/*
+ * Return nonzero if a revision should be printed, based on the
+ * options provided.
+ */
+static int
+log_version_requested (struct log_data *log_data, struct revlist *revlist,
+ RCSNode *rcs, RCSVers *vnode)
+{
+ /* Handle the list of states from the -s option. */
+ if (log_data->statelist != NULL
+ && findnode (log_data->statelist, vnode->state) == NULL)
+ {
+ return 0;
+ }
+
+ /* Handle the list of authors from the -w option. */
+ if (log_data->authorlist != NULL)
+ {
+ if (vnode->author != NULL
+ && findnode (log_data->authorlist, vnode->author) == NULL)
+ {
+ return 0;
+ }
+ }
+
+ /* rlog considers all the -d options together when it decides
+ whether to print a revision, so we must be compatible. */
+ if (log_data->datelist != NULL || log_data->singledatelist != NULL)
+ {
+ struct datelist *d;
+
+ for (d = log_data->datelist; d != NULL; d = d->next)
+ {
+ int cmp;
+
+ cmp = RCS_datecmp (vnode->date, d->start);
+ if (cmp > 0 || (cmp == 0 && d->inclusive))
+ {
+ cmp = RCS_datecmp (vnode->date, d->end);
+ if (cmp < 0 || (cmp == 0 && d->inclusive))
+ break;
+ }
+ }
+
+ if (d == NULL)
+ {
+ /* Look through the list of specific dates. We want to
+ select the revision with the exact date found in the
+ start field. The commit code ensures that it is
+ impossible to check in multiple revisions of a single
+ file in a single second, so checking the date this way
+ should never select more than one revision. */
+ for (d = log_data->singledatelist; d != NULL; d = d->next)
+ {
+ if (d->start != NULL
+ && RCS_datecmp (vnode->date, d->start) == 0)
+ {
+ break;
+ }
+ }
+
+ if (d == NULL)
+ return 0;
+ }
+ }
+
+ /* If the -r or -b options were used, REVLIST will be non NULL,
+ and we print the union of the specified revisions. */
+ if (revlist != NULL)
+ {
+ char *v;
+ int vfields;
+ struct revlist *r;
+
+ /* This code is taken from rlog. */
+ v = vnode->version;
+ vfields = numdots (v) + 1;
+ for (r = revlist; r != NULL; r = r->next)
+ {
+ if (vfields == r->fields + (r->fields & 1) &&
+ (r->inclusive ? version_compare (v, r->first, r->fields) >= 0 :
+ version_compare (v, r->first, r->fields) > 0)
+ && version_compare (v, r->last, r->fields) <= 0)
+ {
+ return 1;
+ }
+ }
+
+ /* If we get here, then the -b and/or the -r option was used,
+ but did not match this revision, so we reject it. */
+
+ return 0;
+ }
+
+ /* By default, we print all revisions. */
+ return 1;
+}
+
+
+
+/*
+ * Output a single symbol. This is called via walklist.
+ */
+/*ARGSUSED*/
+static int
+log_symbol (Node *p, void *closure)
+{
+ cvs_output ("\n\t", 2);
+ cvs_output (p->key, 0);
+ cvs_output (": ", 2);
+ cvs_output (p->data, 0);
+ return 0;
+}
+
+
+
+/*
+ * Count the number of entries on a list. This is called via walklist.
+ */
+/*ARGSUSED*/
+static int
+log_count (Node *p, void *closure)
+{
+ return 1;
+}
+
+
+
+/*
+ * Sort out a single date specification by narrowing down the date
+ * until we find the specific selected revision.
+ */
+static int
+log_fix_singledate (Node *p, void *closure)
+{
+ struct log_data_and_rcs *data = closure;
+ Node *pv;
+ RCSVers *vnode;
+ struct datelist *holdsingle, *holddate;
+ int requested;
+
+ pv = findnode (data->rcs->versions, p->key);
+ if (pv == NULL)
+ error (1, 0, "missing version `%s' in RCS file `%s'",
+ p->key, data->rcs->print_path);
+ vnode = pv->data;
+
+ /* We are only interested if this revision passes any other tests.
+ Temporarily clear log_data->singledatelist to avoid confusing
+ log_version_requested. We also clear log_data->datelist,
+ because rlog considers all the -d options together. We don't
+ want to reject a revision because it does not match a date pair
+ if we are going to select it on the basis of the singledate. */
+ holdsingle = data->log_data->singledatelist;
+ data->log_data->singledatelist = NULL;
+ holddate = data->log_data->datelist;
+ data->log_data->datelist = NULL;
+ requested = log_version_requested (data->log_data, data->revlist,
+ data->rcs, vnode);
+ data->log_data->singledatelist = holdsingle;
+ data->log_data->datelist = holddate;
+
+ if (requested)
+ {
+ struct datelist *d;
+
+ /* For each single date, if this revision is before the
+ specified date, but is closer than the previously selected
+ revision, select it instead. */
+ for (d = data->log_data->singledatelist; d != NULL; d = d->next)
+ {
+ if (RCS_datecmp (vnode->date, d->end) <= 0
+ && (d->start == NULL
+ || RCS_datecmp (vnode->date, d->start) > 0))
+ {
+ if (d->start != NULL)
+ free (d->start);
+ d->start = xstrdup (vnode->date);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Count the number of revisions we are going to print.
+ */
+static int
+log_count_print (Node *p, void *closure)
+{
+ struct log_data_and_rcs *data = closure;
+ Node *pv;
+
+ pv = findnode (data->rcs->versions, p->key);
+ if (pv == NULL)
+ error (1, 0, "missing version `%s' in RCS file `%s'",
+ p->key, data->rcs->print_path);
+ if (log_version_requested (data->log_data, data->revlist, data->rcs,
+ pv->data))
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/*
+ * Print the list of changes, not including the trunk, in reverse
+ * order for each branch.
+ */
+static void
+log_tree (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs,
+ const char *ver)
+{
+ Node *p;
+ RCSVers *vnode;
+
+ p = findnode (rcs->versions, ver);
+ if (p == NULL)
+ error (1, 0, "missing version `%s' in RCS file `%s'",
+ ver, rcs->print_path);
+ vnode = p->data;
+ if (vnode->next != NULL)
+ log_tree (log_data, revlist, rcs, vnode->next);
+ if (vnode->branches != NULL)
+ {
+ Node *head, *branch;
+
+ /* We need to do the branches in reverse order. This breaks
+ the List abstraction, but so does most of the branch
+ manipulation in rcs.c. */
+ head = vnode->branches->list;
+ for (branch = head->prev; branch != head; branch = branch->prev)
+ {
+ log_abranch (log_data, revlist, rcs, branch->key);
+ log_tree (log_data, revlist, rcs, branch->key);
+ }
+ }
+}
+
+
+
+/*
+ * Log the changes for a branch, in reverse order.
+ */
+static void
+log_abranch (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs,
+ const char *ver)
+{
+ Node *p;
+ RCSVers *vnode;
+
+ p = findnode (rcs->versions, ver);
+ if (p == NULL)
+ error (1, 0, "missing version `%s' in RCS file `%s'",
+ ver, rcs->print_path);
+ vnode = p->data;
+ if (vnode->next != NULL)
+ log_abranch (log_data, revlist, rcs, vnode->next);
+ log_version (log_data, revlist, rcs, vnode, 0);
+}
+
+
+
+/*
+ * Print the log output for a single version.
+ */
+static void
+log_version (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs,
+ RCSVers *ver, int trunk)
+{
+ Node *p;
+ int year, mon, mday, hour, min, sec;
+ char buf[100];
+ Node *padd, *pdel;
+
+ if (! log_version_requested (log_data, revlist, rcs, ver))
+ return;
+
+ cvs_output ("----------------------------\nrevision ", 0);
+ cvs_output (ver->version, 0);
+
+ p = findnode (RCS_getlocks (rcs), ver->version);
+ if (p != NULL)
+ {
+ cvs_output ("\tlocked by: ", 0);
+ cvs_output (p->data, 0);
+ cvs_output (";", 1);
+ }
+ cvs_output ("\n", 1);
+
+ cvs_output_tagged ("text", "date: ");
+ (void)sscanf (ver->date, SDATEFORM, &year, &mon, &mday, &hour, &min,
+ &sec);
+ if (year < 1900)
+ year += 1900;
+ sprintf (buf, "%04d-%02d-%02d %02d:%02d:%02d +0000", year, mon, mday,
+ hour, min, sec);
+ cvs_output_tagged ("date", buf);
+
+ cvs_output_tagged ("text", "; author: ");
+ cvs_output_tagged ("text", ver->author);
+
+ cvs_output_tagged ("text", "; state: ");
+ cvs_output_tagged ("text", ver->state);
+ cvs_output_tagged ("text", ";");
+
+ if (! trunk)
+ {
+ padd = findnode (ver->other, ";add");
+ pdel = findnode (ver->other, ";delete");
+ }
+ else if (ver->next == NULL)
+ {
+ padd = NULL;
+ pdel = NULL;
+ }
+ else
+ {
+ Node *nextp;
+ RCSVers *nextver;
+
+ nextp = findnode (rcs->versions, ver->next);
+ if (nextp == NULL)
+ error (1, 0, "missing version `%s' in `%s'", ver->next,
+ rcs->print_path);
+ nextver = nextp->data;
+ pdel = findnode (nextver->other, ";add");
+ padd = findnode (nextver->other, ";delete");
+ }
+
+ if (padd != NULL)
+ {
+ assert (pdel);
+ cvs_output_tagged ("text", " lines: +");
+ cvs_output_tagged ("text", padd->data);
+ cvs_output_tagged ("text", " -");
+ cvs_output_tagged ("text", pdel->data);
+ cvs_output_tagged ("text", ";");
+ }
+
+ p = findnode(ver->other_delta,"commitid");
+ if(p && p->data)
+ {
+ cvs_output_tagged ("text", " commitid: ");
+ cvs_output_tagged ("text", p->data);
+ cvs_output_tagged ("text", ";");
+ }
+
+ cvs_output_tagged ("newline", NULL);
+
+ if (ver->branches != NULL)
+ {
+ cvs_output ("branches:", 0);
+ walklist (ver->branches, log_branch, NULL);
+ cvs_output ("\n", 1);
+ }
+
+ p = findnode (ver->other, "log");
+ /* The p->date == NULL case is the normal one for an empty log
+ message (rcs-14 in sanity.sh). I don't think the case where
+ p->data is "" can happen (getrcskey in rcs.c checks for an
+ empty string and set the value to NULL in that case). My guess
+ would be the p == NULL case would mean an RCS file which was
+ missing the "log" keyword (which is invalid according to
+ rcsfile.5). */
+ if (p == NULL || p->data == NULL || *(char *)p->data == '\0')
+ cvs_output ("*** empty log message ***\n", 0);
+ else
+ {
+ /* FIXME: Technically, the log message could contain a null
+ byte. */
+ cvs_output (p->data, 0);
+ if (((char *)p->data)[strlen (p->data) - 1] != '\n')
+ cvs_output ("\n", 1);
+ }
+}
+
+
+
+/*
+ * Output a branch version. This is called via walklist.
+ */
+/*ARGSUSED*/
+static int
+log_branch (Node *p, void *closure)
+{
+ cvs_output (" ", 2);
+ if ((numdots (p->key) & 1) == 0)
+ cvs_output (p->key, 0);
+ else
+ {
+ char *f, *cp;
+
+ f = xstrdup (p->key);
+ cp = strrchr (f, '.');
+ *cp = '\0';
+ cvs_output (f, 0);
+ free (f);
+ }
+ cvs_output (";", 1);
+ return 0;
+}
+
+
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+log_dirproc (void *callerdat, const char *dir, const char *repository,
+ const char *update_dir, List *entries)
+{
+ if (!isdir (dir))
+ return R_SKIP_ALL;
+
+ if (!quiet)
+ error (0, 0, "Logging %s", update_dir);
+ return R_PROCESS;
+}
+
+
+
+/*
+ * Compare versions. This is taken from RCS compartial.
+ */
+static int
+version_compare (const char *v1, const char *v2, int len)
+{
+ while (1)
+ {
+ int d1, d2, r;
+
+ if (*v1 == '\0')
+ return 1;
+ if (*v2 == '\0')
+ return -1;
+
+ while (*v1 == '0')
+ ++v1;
+ for (d1 = 0; isdigit ((unsigned char) v1[d1]); ++d1)
+ ;
+
+ while (*v2 == '0')
+ ++v2;
+ for (d2 = 0; isdigit ((unsigned char) v2[d2]); ++d2)
+ ;
+
+ if (d1 != d2)
+ return d1 < d2 ? -1 : 1;
+
+ r = memcmp (v1, v2, d1);
+ if (r != 0)
+ return r;
+
+ --len;
+ if (len == 0)
+ return 0;
+
+ v1 += d1;
+ v2 += d1;
+
+ if (*v1 == '.')
+ ++v1;
+ if (*v2 == '.')
+ ++v2;
+ }
+}
diff --git a/src/login.c b/src/login.c
new file mode 100644
index 0000000..cdd103d
--- /dev/null
+++ b/src/login.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with CVS.
+ *
+ * Allow user to log in for an authenticating server.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+/* There seems to be very little agreement on which system header
+ getpass is declared in. With a lot of fancy autoconfiscation,
+ we could perhaps detect this, but for now we'll just rely on
+ _CRAY, since Cray is perhaps the only system on which our own
+ declaration won't work (some Crays declare the 2#$@% thing as
+ varadic, believe it or not). On Cray, getpass will be declared
+ in either stdlib.h or unistd.h. */
+#include "getpass.h"
+
+#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */
+
+
+#ifndef CVS_PASSWORD_FILE
+#define CVS_PASSWORD_FILE ".cvspass"
+#endif
+
+/* If non-NULL, get_cvs_password() will just return this. */
+static char *cvs_password = NULL;
+
+static char *construct_cvspass_filename (void);
+
+/* The return value will need to be freed. */
+static char *
+construct_cvspass_filename (void)
+{
+ char *homedir;
+ char *passfile;
+
+ /* Environment should override file. */
+ if ((passfile = getenv ("CVS_PASSFILE")) != NULL)
+ return xstrdup (passfile);
+
+ /* Construct absolute pathname to user's password file. */
+ /* todo: does this work under OS/2 ? */
+ homedir = get_homedir ();
+ if (! homedir)
+ {
+ /* FIXME? This message confuses a lot of users, at least
+ on Win95 (which doesn't set HOMEDRIVE and HOMEPATH like
+ NT does). I suppose the answer for Win95 is to store the
+ passwords in the registry or something (??). And .cvsrc
+ and such too? Wonder what WinCVS does (about .cvsrc, the
+ right thing for a GUI is to just store the password in
+ memory only)... */
+ error (1, 0, "could not find out home directory");
+ return NULL;
+ }
+
+ passfile = strcat_filename_onto_homedir (homedir, CVS_PASSWORD_FILE);
+
+ /* Safety first and last, Scouts. */
+ if (isfile (passfile))
+ /* xchmod() is too polite. */
+ chmod (passfile, 0600);
+
+ return passfile;
+}
+
+
+
+/*
+ * static char *
+ * password_entry_parseline (
+ * const char *cvsroot_canonical,
+ * const unsigned char warn,
+ * const int linenumber,
+ * char *linebuf
+ * );
+ *
+ * Internal function used by password_entry_operation. Parse a single line
+ * from a ~/.cvsroot password file and return a pointer to the password if the
+ * line refers to the same cvsroot as cvsroot_canonical
+ *
+ * INPUTS
+ * cvsroot_canonical the root we are looking for
+ * warn Boolean: print warnings for invalid lines?
+ * linenumber the line number for error messages
+ * linebuf the current line
+ *
+ * RETURNS
+ * NULL if the line doesn't match
+ * char *password as a pointer into linebuf
+ *
+ * NOTES
+ * This function temporarily alters linebuf, so it isn't thread safe when
+ * called on the same linebuf
+ */
+static char *
+password_entry_parseline (const char *cvsroot_canonical,
+ const unsigned char warn, const int linenumber,
+ char *linebuf)
+{
+ char *password = NULL;
+ char *p;
+
+ /* look for '^/' */
+ if (*linebuf == '/')
+ {
+ /* Yes: slurp '^/\d+\D' and parse the rest of the line according to
+ * version number
+ */
+ char *q;
+ unsigned long int entry_version = 0 /* Placate -Wall. */;
+
+ if (isspace(*(linebuf + 1)))
+ /* special case since strtoul ignores leading white space */
+ q = linebuf + 1;
+ else
+ entry_version = strtoul (linebuf + 1, &q, 10);
+
+ if (q != linebuf + 1)
+ /* assume a delimiting seperator */
+ q++;
+ /* else, no valid digits found by strtoul */
+
+ switch (entry_version)
+ {
+ case 1:
+ /* this means the same normalize_cvsroot we are using was
+ * used to create this entry. strcmp is good enough for
+ * us.
+ */
+ p = strchr (q, ' ');
+ if (p == NULL)
+ {
+ if (warn && !really_quiet)
+ error (0, 0, "warning: skipping invalid entry in password file at line %d",
+ linenumber);
+ }
+ else
+ {
+ *p = '\0';
+ if (strcmp (cvsroot_canonical, q) == 0)
+ password = p + 1;
+ *p = ' ';
+ }
+ break;
+ case ULONG_MAX:
+ if (warn && !really_quiet)
+ {
+ error (0, errno, "warning: unable to convert version number in password file at line %d",
+ linenumber);
+ error (0, 0, "skipping entry");
+ }
+ break;
+ case 0:
+ if (warn && !really_quiet)
+ error (0, 0, "warning: skipping entry with invalid version string in password file at line %d",
+ linenumber);
+ break;
+ default:
+ if (warn && !really_quiet)
+ error (0, 0, "warning: skipping entry with unknown version (%lu) in password file at line %d",
+ entry_version, linenumber);
+ break;
+ }
+ }
+ else
+ {
+ /* No: assume:
+ *
+ * ^cvsroot Aencoded_password$
+ *
+ * as header comment specifies and parse accordingly
+ */
+ cvsroot_t *tmp_root;
+ char *tmp_root_canonical;
+
+ p = strchr (linebuf, ' ');
+ if (p == NULL)
+ {
+ if (warn && !really_quiet)
+ error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber);
+ return NULL;;
+ }
+
+ *p = '\0';
+ if ((tmp_root = parse_cvsroot (linebuf)) == NULL)
+ {
+ if (warn && !really_quiet)
+ error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber);
+ *p = ' ';
+ return NULL;
+ }
+ *p = ' ';
+ tmp_root_canonical = normalize_cvsroot (tmp_root);
+ if (strcmp (cvsroot_canonical, tmp_root_canonical) == 0)
+ password = p + 1;
+
+ free (tmp_root_canonical);
+ }
+
+ return password;
+}
+
+
+
+/*
+ * static char *
+ * password_entry_operation (
+ * password_entry_operation_t operation,
+ * cvsroot_t *root,
+ * char *newpassword
+ * );
+ *
+ * Search the password file and depending on the value of operation:
+ *
+ * Mode Action
+ * password_entry_lookup Return the password
+ * password_entry_delete Delete the entry from the file, if it
+ * exists.
+ * password_entry_add Replace the line with the new one, else
+ * append it.
+ *
+ * Because the user might be accessing multiple repositories, with
+ * different passwords for each one, the format of ~/.cvspass is:
+ *
+ * [user@]host:[port]/path Aencoded_password
+ * [user@]host:[port]/path Aencoded_password
+ * ...
+ *
+ * New entries are always of the form:
+ *
+ * /1 user@host:port/path Aencoded_password
+ *
+ * but the old format is supported for backwards compatibility.
+ * The entry version string wasn't strictly necessary, but it avoids the
+ * overhead of parsing some entries since we know it is already in canonical
+ * form and allows room for expansion later, say, if we want to allow spaces
+ * and/or other characters to be escaped in the string. Also, the new entries
+ * would have been ignored by old versions of CVS anyhow since those versions
+ * didn't know how to parse a port number.
+ *
+ * The "A" before "encoded_password" is a literal capital A. It's a
+ * version number indicating which form of scrambling we're doing on
+ * the password -- someday we might provide something more secure than
+ * the trivial encoding we do now, and when that day comes, it would
+ * be nice to remain backward-compatible.
+ *
+ * Like .netrc, the file's permissions are the only thing preventing
+ * it from being read by others. Unlike .netrc, we will not be
+ * fascist about it, at most issuing a warning, and never refusing to
+ * work.
+ *
+ * INPUTS
+ * operation operation to perform
+ * root cvsroot_t to look up
+ * newpassword prescrambled new password, for password_entry_add_mode
+ *
+ * RETURNS
+ * -1 if password_entry_lookup_mode not specified
+ * NULL on failed lookup
+ * pointer to a copy of the password string otherwise, which the caller is
+ * responsible for disposing of
+ */
+
+typedef enum password_entry_operation_e {
+ password_entry_lookup,
+ password_entry_delete,
+ password_entry_add
+} password_entry_operation_t;
+
+static char *
+password_entry_operation (password_entry_operation_t operation, cvsroot_t *root, char *newpassword)
+{
+ char *passfile;
+ FILE *fp;
+ char *cvsroot_canonical = NULL;
+ char *password = NULL;
+ int line_length;
+ long line = -1;
+ char *linebuf = NULL;
+ size_t linebuf_len;
+ char *p;
+ int save_errno = 0;
+
+ if (root->method != pserver_method)
+ {
+ error (0, 0, "\
+internal error: can only call password_entry_operation with pserver method");
+ error (1, 0, "CVSROOT: %s", root->original);
+ }
+
+ cvsroot_canonical = normalize_cvsroot (root);
+
+ /* Yes, the method below reads the user's password file twice when we have
+ * to delete an entry. It's inefficient, but we're not talking about a gig of
+ * data here.
+ */
+
+ passfile = construct_cvspass_filename ();
+ fp = CVS_FOPEN (passfile, "r");
+ if (fp == NULL)
+ {
+ error (0, errno, "warning: failed to open %s for reading", passfile);
+ goto process;
+ }
+
+ /* Check each line to see if we have this entry already. */
+ line = 0L;
+ while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ line++;
+ password = password_entry_parseline (cvsroot_canonical, 1, line,
+ linebuf);
+ if (password != NULL)
+ /* this is it! break out and deal with linebuf */
+ break;
+ }
+ if (line_length < 0 && !feof (fp))
+ {
+ error (0, errno, "cannot read %s", passfile);
+ goto error_exit;
+ }
+ if (fclose (fp) < 0)
+ /* not fatal, unless it cascades */
+ error (0, errno, "cannot close %s", passfile);
+ fp = NULL;
+
+ /* Utter, total, raving paranoia, I know. */
+ chmod (passfile, 0600);
+
+ /* a copy to return or keep around so we can reuse linebuf */
+ if (password != NULL)
+ {
+ /* chomp the EOL */
+ p = strchr (password, '\n');
+ if (p != NULL)
+ *p = '\0';
+ password = xstrdup (password);
+ }
+
+process:
+
+ /* might as well return now */
+ if (operation == password_entry_lookup)
+ goto out;
+
+ /* same here */
+ if (operation == password_entry_delete && password == NULL)
+ {
+ error (0, 0, "Entry not found.");
+ goto out;
+ }
+
+ /* okay, file errors can simply be fatal from now on since we don't do
+ * anything else if we're in lookup mode
+ */
+
+ /* copy the file with the entry deleted unless we're in add
+ * mode and the line we found contains the same password we're supposed to
+ * add
+ */
+ if (!noexec && password != NULL && (operation == password_entry_delete
+ || (operation == password_entry_add
+ && strcmp (password, newpassword))))
+ {
+ long found_at = line;
+ char *tmp_name;
+ FILE *tmp_fp;
+
+ /* open the original file again */
+ fp = CVS_FOPEN (passfile, "r");
+ if (fp == NULL)
+ error (1, errno, "failed to open %s for reading", passfile);
+
+ /* create and open a temp file */
+ if ((tmp_fp = cvs_temp_file (&tmp_name)) == NULL)
+ error (1, errno, "unable to open temp file %s", tmp_name);
+
+ line = 0L;
+ while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ line++;
+ if (line < found_at
+ || (line != found_at
+ && !password_entry_parseline (cvsroot_canonical, 0, line,
+ linebuf)))
+ {
+ if (fprintf (tmp_fp, "%s", linebuf) == EOF)
+ {
+ /* try and clean up anyhow */
+ error (0, errno, "fatal error: cannot write %s", tmp_name);
+ if (fclose (tmp_fp) == EOF)
+ error (0, errno, "cannot close %s", tmp_name);
+ /* call CVS_UNLINK instead of unlink_file since the file
+ * got created in noexec mode
+ */
+ if (CVS_UNLINK (tmp_name) < 0)
+ error (0, errno, "cannot remove %s", tmp_name);
+ /* but quit so we don't remove all the entries from a
+ * user's password file accidentally
+ */
+ error (1, 0, "exiting");
+ }
+ }
+ }
+ if (line_length < 0 && !feof (fp))
+ {
+ error (0, errno, "cannot read %s", passfile);
+ goto error_exit;
+ }
+ if (fclose (fp) < 0)
+ /* not fatal, unless it cascades */
+ error (0, errno, "cannot close %s", passfile);
+ if (fclose (tmp_fp) < 0)
+ /* not fatal, unless it cascades */
+ /* FIXME - does copy_file return correct results if the file wasn't
+ * closed? should this be fatal?
+ */
+ error (0, errno, "cannot close %s", tmp_name);
+
+ /* FIXME: rename_file would make more sense (e.g. almost
+ * always faster).
+ *
+ * I don't think so, unless we change the way rename_file works to
+ * attempt a cp/rm sequence when rename fails since rename doesn't
+ * work across file systems and it isn't uncommon to have /tmp
+ * on its own partition.
+ *
+ * For that matter, it's probably not uncommon to have a home
+ * directory on an NFS mount.
+ */
+ copy_file (tmp_name, passfile);
+ if (CVS_UNLINK (tmp_name) < 0)
+ error (0, errno, "cannot remove %s", tmp_name);
+ free (tmp_name);
+ }
+
+ /* in add mode, if we didn't find an entry or found an entry with a
+ * different password, append the new line
+ */
+ if (!noexec && operation == password_entry_add
+ && (password == NULL || strcmp (password, newpassword)))
+ {
+ if ((fp = CVS_FOPEN (passfile, "a")) == NULL)
+ error (1, errno, "could not open %s for writing", passfile);
+
+ if (fprintf (fp, "/1 %s %s\n", cvsroot_canonical, newpassword) == EOF)
+ error (1, errno, "cannot write %s", passfile);
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", passfile);
+ }
+
+ /* Utter, total, raving paranoia, I know. */
+ chmod (passfile, 0600);
+
+ if (password)
+ {
+ free (password);
+ password = NULL;
+ }
+ if (linebuf)
+ free (linebuf);
+
+out:
+ free (cvsroot_canonical);
+ free (passfile);
+ return password;
+
+error_exit:
+ /* just exit when we're not in lookup mode */
+ if (operation != password_entry_lookup)
+ error (1, 0, "fatal error: exiting");
+ /* clean up and exit in lookup mode so we can try a login with a NULL
+ * password anyhow in case that's what we would have found
+ */
+ save_errno = errno;
+ if (fp != NULL)
+ {
+ /* Utter, total, raving paranoia, I know. */
+ chmod (passfile, 0600);
+ if(fclose (fp) < 0)
+ error (0, errno, "cannot close %s", passfile);
+ }
+ if (linebuf)
+ free (linebuf);
+ if (cvsroot_canonical)
+ free (cvsroot_canonical);
+ free (passfile);
+ errno = save_errno;
+ return NULL;
+}
+
+
+
+/* Prompt for a password, and store it in the file "CVS/.cvspass".
+ */
+
+static const char *const login_usage[] =
+{
+ "Usage: %s %s\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+login (int argc, char **argv)
+{
+ char *typed_password;
+ char *cvsroot_canonical;
+
+ if (argc < 0)
+ usage (login_usage);
+
+ if (current_parsed_root->method != pserver_method)
+ {
+ error (0, 0, "can only use `login' command with the 'pserver' method");
+ error (1, 0, "CVSROOT: %s", current_parsed_root->original);
+ }
+
+ cvsroot_canonical = normalize_cvsroot(current_parsed_root);
+ printf ("Logging in to %s\n", cvsroot_canonical);
+ fflush (stdout);
+
+ if (current_parsed_root->password)
+ {
+ typed_password = scramble (current_parsed_root->password);
+ }
+ else
+ {
+ char *tmp;
+ tmp = getpass ("CVS password: ");
+ /* Must deal with a NULL return value here. I haven't managed to
+ * disconnect the CVS process from the tty and force a NULL return
+ * in sanity.sh, but the Linux version of getpass is documented
+ * to return NULL when it can't open /dev/tty...
+ */
+ if (!tmp) error (1, errno, "login: Failed to read password.");
+ typed_password = scramble (tmp);
+ memset (tmp, 0, strlen (tmp));
+ }
+
+ /* Force get_cvs_password() to use this one (when the client
+ * confirms the new password with the server), instead of
+ * consulting the file. We make a new copy because cvs_password
+ * will get zeroed by connect_to_server(). */
+ cvs_password = xstrdup (typed_password);
+
+ connect_to_pserver (current_parsed_root, NULL, NULL, 1, 0);
+
+ password_entry_operation (password_entry_add, current_parsed_root,
+ typed_password);
+
+ memset (typed_password, 0, strlen (typed_password));
+ free (typed_password);
+
+ free (cvs_password);
+ free (cvsroot_canonical);
+ cvs_password = NULL;
+
+ return 0;
+}
+
+
+
+/* Returns the _scrambled_ password. The server must descramble
+ before hashing and comparing. If password file not found, or
+ password not found in the file, just return NULL. */
+char *
+get_cvs_password (void)
+{
+ if (current_parsed_root->password)
+ return scramble (current_parsed_root->password);
+
+ /* If someone (i.e., login()) is calling connect_to_pserver() out of
+ context, then assume they have supplied the correct, scrambled
+ password. */
+ if (cvs_password)
+ return cvs_password;
+
+ if (getenv ("CVS_PASSWORD") != NULL)
+ {
+ /* In previous versions of CVS one could specify a password in
+ * CVS_PASSWORD. This is a bad idea, because in BSD variants
+ * of unix anyone can see the environment variable with 'ps'.
+ * But for users who were using that feature we want to at
+ * least let them know what is going on. After printing this
+ * warning, we should fall through to the regular error where
+ * we tell them to run "cvs login" (unless they already ran
+ * it, of course).
+ */
+ error (0, 0, "CVS_PASSWORD is no longer supported; ignored");
+ }
+
+ if (current_parsed_root->method != pserver_method)
+ {
+ error (0, 0, "can only call get_cvs_password with pserver method");
+ error (1, 0, "CVSROOT: %s", current_parsed_root->original);
+ }
+
+ return password_entry_operation (password_entry_lookup,
+ current_parsed_root, NULL);
+}
+
+
+
+static const char *const logout_usage[] =
+{
+ "Usage: %s %s\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+/* Remove any entry for the CVSRoot repository found in .cvspass. */
+int
+logout (int argc, char **argv)
+{
+ char *cvsroot_canonical;
+
+ if (argc < 0)
+ usage (logout_usage);
+
+ if (current_parsed_root->method != pserver_method)
+ {
+ error (0, 0, "can only use pserver method with `logout' command");
+ error (1, 0, "CVSROOT: %s", current_parsed_root->original);
+ }
+
+ /* Hmm. Do we want a variant of this command which deletes _all_
+ the entries from the current .cvspass? Might be easier to
+ remember than "rm ~/.cvspass" but then again if people are
+ mucking with HOME (common in Win95 as the system doesn't set
+ it), then this variant of "cvs logout" might give a false sense
+ of security, in that it wouldn't delete entries from any
+ .cvspass files but the current one. */
+
+ if (!quiet)
+ {
+ cvsroot_canonical = normalize_cvsroot(current_parsed_root);
+ printf ("Logging out of %s\n", cvsroot_canonical);
+ fflush (stdout);
+ free (cvsroot_canonical);
+ }
+
+ password_entry_operation (password_entry_delete, current_parsed_root, NULL);
+
+ return 0;
+}
+
+#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */
diff --git a/src/logmsg.c b/src/logmsg.c
new file mode 100644
index 0000000..b61b7ef
--- /dev/null
+++ b/src/logmsg.c
@@ -0,0 +1,977 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ */
+
+
+#include "cvs.h"
+#include "getline.h"
+
+static int find_type (Node * p, void *closure);
+static int fmt_proc (Node * p, void *closure);
+static int logfile_write (const char *repository, const char *filter,
+ const char *message, FILE * logfp, List * changes);
+static int logmsg_list_to_args_proc (Node *p, void *closure);
+static int rcsinfo_proc (const char *repository, const char *template,
+ void *closure );
+static int update_logfile_proc (const char *repository, const char *filter,
+ void *closure);
+static void setup_tmpfile (FILE * xfp, char *xprefix, List * changes);
+static int verifymsg_proc (const char *repository, const char *script,
+ void *closure );
+
+static FILE *fp;
+static Ctype type;
+
+struct verifymsg_proc_data
+{
+ /* The name of the temp file storing the log message to be verified. This
+ * is initially NULL and verifymsg_proc() writes message into it so that it
+ * can be shared when multiple verifymsg scripts exist. do_verify() is
+ * responsible for rereading the message from the file when
+ * RereadLogAfterVerify is in effect and the file has changed.
+ */
+ char *fname;
+ /* The initial message text to be verified.
+ */
+ char *message;
+ /* The initial stats of the temp file so we can tell that the temp file has
+ * been changed when RereadLogAfterVerify is STAT.
+ */
+ struct stat pre_stbuf;
+ /* The list of files being changed, with new and old version numbers.
+ */
+ List *changes;
+};
+
+/*
+ * Puts a standard header on the output which is either being prepared for an
+ * editor session, or being sent to a logfile program. The modified, added,
+ * and removed files are included (if any) and formatted to look pretty. */
+static char *prefix;
+static int col;
+static char *tag;
+static void
+setup_tmpfile (FILE *xfp, char *xprefix, List *changes)
+{
+ /* set up statics */
+ fp = xfp;
+ prefix = xprefix;
+
+ type = T_MODIFIED;
+ if (walklist (changes, find_type, NULL) != 0)
+ {
+ (void) fprintf (fp, "%sModified Files:\n", prefix);
+ col = 0;
+ (void) walklist (changes, fmt_proc, NULL);
+ (void) fprintf (fp, "\n");
+ if (tag != NULL)
+ {
+ free (tag);
+ tag = NULL;
+ }
+ }
+ type = T_ADDED;
+ if (walklist (changes, find_type, NULL) != 0)
+ {
+ (void) fprintf (fp, "%sAdded Files:\n", prefix);
+ col = 0;
+ (void) walklist (changes, fmt_proc, NULL);
+ (void) fprintf (fp, "\n");
+ if (tag != NULL)
+ {
+ free (tag);
+ tag = NULL;
+ }
+ }
+ type = T_REMOVED;
+ if (walklist (changes, find_type, NULL) != 0)
+ {
+ (void) fprintf (fp, "%sRemoved Files:\n", prefix);
+ col = 0;
+ (void) walklist (changes, fmt_proc, NULL);
+ (void) fprintf (fp, "\n");
+ if (tag != NULL)
+ {
+ free (tag);
+ tag = NULL;
+ }
+ }
+}
+
+/*
+ * Looks for nodes of a specified type and returns 1 if found
+ */
+static int
+find_type (Node *p, void *closure)
+{
+ struct logfile_info *li = p->data;
+
+ if (li->type == type)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * Breaks the files list into reasonable sized lines to avoid line wrap...
+ * all in the name of pretty output. It only works on nodes whose types
+ * match the one we're looking for
+ */
+static int
+fmt_proc (Node *p, void *closure)
+{
+ struct logfile_info *li;
+
+ li = p->data;
+ if (li->type == type)
+ {
+ if (li->tag == NULL
+ ? tag != NULL
+ : tag == NULL || strcmp (tag, li->tag) != 0)
+ {
+ if (col > 0)
+ (void) fprintf (fp, "\n");
+ (void) fputs (prefix, fp);
+ col = strlen (prefix);
+ while (col < 6)
+ {
+ (void) fprintf (fp, " ");
+ ++col;
+ }
+
+ if (li->tag == NULL)
+ (void) fprintf (fp, "No tag");
+ else
+ (void) fprintf (fp, "Tag: %s", li->tag);
+
+ if (tag != NULL)
+ free (tag);
+ tag = xstrdup (li->tag);
+
+ /* Force a new line. */
+ col = 70;
+ }
+
+ if (col == 0)
+ {
+ (void) fprintf (fp, "%s\t", prefix);
+ col = 8;
+ }
+ else if (col > 8 && (col + (int) strlen (p->key)) > 70)
+ {
+ (void) fprintf (fp, "\n%s\t", prefix);
+ col = 8;
+ }
+ (void) fprintf (fp, "%s ", p->key);
+ col += strlen (p->key) + 1;
+ }
+ return (0);
+}
+
+/*
+ * Builds a temporary file using setup_tmpfile() and invokes the user's
+ * editor on the file. The header garbage in the resultant file is then
+ * stripped and the log message is stored in the "message" argument.
+ *
+ * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it
+ * is NULL, use the CVSADM_TEMPLATE file instead. REPOSITORY should be
+ * NULL when running in client mode.
+ *
+ * GLOBALS
+ * Editor Set to a default value by configure and overridable using the
+ * -e option to the CVS executable.
+ */
+void
+do_editor (const char *dir, char **messagep, const char *repository,
+ List *changes)
+{
+ static int reuse_log_message = 0;
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+ char *fname;
+ struct stat pre_stbuf, post_stbuf;
+ int retcode = 0;
+
+ assert (!current_parsed_root->isremote != !repository);
+
+ if (noexec || reuse_log_message)
+ return;
+
+ /* Abort before creation of the temp file if no editor is defined. */
+ if (strcmp (Editor, "") == 0)
+ error(1, 0, "no editor defined, must use -e or -m");
+
+ again:
+ /* Create a temporary file. */
+ if( ( fp = cvs_temp_file( &fname ) ) == NULL )
+ error( 1, errno, "cannot create temporary file" );
+
+ if (*messagep)
+ {
+ (void) fputs (*messagep, fp);
+
+ if ((*messagep)[0] == '\0' ||
+ (*messagep)[strlen (*messagep) - 1] != '\n')
+ (void) fprintf (fp, "\n");
+ }
+
+ if (repository != NULL)
+ /* tack templates on if necessary */
+ (void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc,
+ PIOPT_ALL, NULL);
+ else
+ {
+ FILE *tfp;
+ char buf[1024];
+ size_t n;
+ size_t nwrite;
+
+ /* Why "b"? */
+ tfp = CVS_FOPEN (CVSADM_TEMPLATE, "rb");
+ if (tfp == NULL)
+ {
+ if (!existence_error (errno))
+ error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
+ }
+ else
+ {
+ while (!feof (tfp))
+ {
+ char *p = buf;
+ n = fread (buf, 1, sizeof buf, tfp);
+ nwrite = n;
+ while (nwrite > 0)
+ {
+ n = fwrite (p, 1, nwrite, fp);
+ nwrite -= n;
+ p += n;
+ }
+ if (ferror (tfp))
+ error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
+ }
+ if (fclose (tfp) < 0)
+ error (0, errno, "cannot close %s", CVSADM_TEMPLATE);
+ }
+ }
+
+ (void) fprintf (fp,
+ "%s----------------------------------------------------------------------\n",
+ CVSEDITPREFIX);
+ (void) fprintf (fp,
+ "%sEnter Log. Lines beginning with `%.*s' are removed automatically\n%s\n",
+ CVSEDITPREFIX, CVSEDITPREFIXLEN, CVSEDITPREFIX,
+ CVSEDITPREFIX);
+ if (dir != NULL && *dir)
+ (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX,
+ dir, CVSEDITPREFIX);
+ if (changes != NULL)
+ setup_tmpfile (fp, CVSEDITPREFIX, changes);
+ (void) fprintf (fp,
+ "%s----------------------------------------------------------------------\n",
+ CVSEDITPREFIX);
+
+ /* finish off the temp file */
+ if (fclose (fp) == EOF)
+ error (1, errno, "%s", fname);
+ if (stat (fname, &pre_stbuf) == -1)
+ pre_stbuf.st_mtime = 0;
+
+ /* run the editor */
+ run_setup (Editor);
+ run_add_arg (fname);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_NORMAL | RUN_SIGIGNORE)) != 0)
+ error (0, retcode == -1 ? errno : 0, "warning: editor session failed");
+
+ /* put the entire message back into the *messagep variable */
+
+ fp = xfopen (fname, "r");
+
+ if (*messagep)
+ free (*messagep);
+
+ if (stat (fname, &post_stbuf) != 0)
+ error (1, errno, "cannot find size of temp file %s", fname);
+
+ if (post_stbuf.st_size == 0)
+ *messagep = NULL;
+ else
+ {
+ /* On NT, we might read less than st_size bytes, but we won't
+ read more. So this works. */
+ *messagep = (char *) xmalloc (post_stbuf.st_size + 1);
+ (*messagep)[0] = '\0';
+ }
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ if (*messagep)
+ {
+ size_t message_len = post_stbuf.st_size + 1;
+ size_t offset = 0;
+ while (1)
+ {
+ line_length = getline (&line, &line_chars_allocated, fp);
+ if (line_length == -1)
+ {
+ if (ferror (fp))
+ error (0, errno, "warning: cannot read %s", fname);
+ break;
+ }
+ if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
+ continue;
+ if (offset + line_length >= message_len)
+ expand_string (messagep, &message_len,
+ offset + line_length + 1);
+ (void) strcpy (*messagep + offset, line);
+ offset += line_length;
+ }
+ }
+ if (fclose (fp) < 0)
+ error (0, errno, "warning: cannot close %s", fname);
+
+ /* canonicalize emply messages */
+ if (*messagep != NULL &&
+ (**messagep == '\0' || strcmp (*messagep, "\n") == 0))
+ {
+ free (*messagep);
+ *messagep = NULL;
+ }
+
+ if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL)
+ {
+ for (;;)
+ {
+ (void) printf ("\nLog message unchanged or not specified\n");
+ (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n");
+ (void) printf ("Action: (continue) ");
+ (void) fflush (stdout);
+ line_length = getline (&line, &line_chars_allocated, stdin);
+ if (line_length < 0)
+ {
+ error (0, errno, "cannot read from stdin");
+ if (unlink_file (fname) < 0)
+ error (0, errno,
+ "warning: cannot remove temp file %s", fname);
+ error (1, 0, "aborting");
+ }
+ else if (line_length == 0
+ || *line == '\n' || *line == 'c' || *line == 'C')
+ break;
+ if (*line == 'a' || *line == 'A')
+ {
+ if (unlink_file (fname) < 0)
+ error (0, errno, "warning: cannot remove temp file %s", fname);
+ error (1, 0, "aborted by user");
+ }
+ if (*line == 'e' || *line == 'E')
+ goto again;
+ if (*line == '!')
+ {
+ reuse_log_message = 1;
+ break;
+ }
+ (void) printf ("Unknown input\n");
+ }
+ }
+ if (line)
+ free (line);
+ if (unlink_file (fname) < 0)
+ error (0, errno, "warning: cannot remove temp file %s", fname);
+ free (fname);
+}
+
+/* Runs the user-defined verification script as part of the commit or import
+ process. This verification is meant to be run whether or not the user
+ included the -m attribute. unlike the do_editor function, this is
+ independant of the running of an editor for getting a message.
+ */
+void
+do_verify (char **messagep, const char *repository, List *changes)
+{
+ int err;
+ struct verifymsg_proc_data data;
+ struct stat post_stbuf;
+
+ if (current_parsed_root->isremote)
+ /* The verification will happen on the server. */
+ return;
+
+ /* FIXME? Do we really want to skip this on noexec? What do we do
+ for the other administrative files? */
+ /* EXPLAIN: Why do we check for repository == NULL here? */
+ if (noexec || repository == NULL)
+ return;
+
+ /* Get the name of the verification script to run */
+
+ data.message = *messagep;
+ data.fname = NULL;
+ data.changes = changes;
+ if ((err = Parse_Info (CVSROOTADM_VERIFYMSG, repository,
+ verifymsg_proc, 0, &data)) != 0)
+ {
+ int saved_errno = errno;
+ /* Since following error() exits, delete the temp file now. */
+ if (data.fname != NULL && unlink_file( data.fname ) < 0)
+ error (0, errno, "cannot remove %s", data.fname);
+ free (data.fname);
+
+ errno = saved_errno;
+ error (1, err == -1 ? errno : 0, "Message verification failed");
+ }
+
+ /* Return if no temp file was created. That means that we didn't call any
+ * verifymsg scripts.
+ */
+ if (data.fname == NULL)
+ return;
+
+ /* Get the mod time and size of the possibly new log message
+ * in always and stat modes.
+ */
+ if (config->RereadLogAfterVerify == LOGMSG_REREAD_ALWAYS ||
+ config->RereadLogAfterVerify == LOGMSG_REREAD_STAT)
+ {
+ if(stat (data.fname, &post_stbuf) != 0)
+ error (1, errno, "cannot find size of temp file %s", data.fname);
+ }
+
+ /* And reread the log message in `always' mode or in `stat' mode when it's
+ * changed.
+ */
+ if (config->RereadLogAfterVerify == LOGMSG_REREAD_ALWAYS ||
+ (config->RereadLogAfterVerify == LOGMSG_REREAD_STAT &&
+ (data.pre_stbuf.st_mtime != post_stbuf.st_mtime ||
+ data.pre_stbuf.st_size != post_stbuf.st_size)))
+ {
+ /* put the entire message back into the *messagep variable */
+
+ if (*messagep) free (*messagep);
+
+ if (post_stbuf.st_size == 0)
+ *messagep = NULL;
+ else
+ {
+ char *line = NULL;
+ int line_length;
+ size_t line_chars_allocated = 0;
+ char *p;
+ FILE *fp;
+
+ fp = xfopen (data.fname, "r");
+
+ /* On NT, we might read less than st_size bytes,
+ but we won't read more. So this works. */
+ p = *messagep = (char *) xmalloc (post_stbuf.st_size + 1);
+ *messagep[0] = '\0';
+
+ for (;;)
+ {
+ line_length = getline( &line,
+ &line_chars_allocated,
+ fp);
+ if (line_length == -1)
+ {
+ if (ferror (fp))
+ /* Fail in this case because otherwise we will have no
+ * log message
+ */
+ error (1, errno, "cannot read %s", data.fname);
+ break;
+ }
+ if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
+ continue;
+ (void) strcpy (p, line);
+ p += line_length;
+ }
+ if (line) free (line);
+ if (fclose (fp) < 0)
+ error (0, errno, "warning: cannot close %s", data.fname);
+ }
+ }
+ /* Delete the temp file */
+ if (unlink_file (data.fname) < 0)
+ error (0, errno, "cannot remove `%s'", data.fname);
+ free (data.fname);
+}
+
+
+
+/*
+ * callback proc for Parse_Info for rcsinfo templates this routine basically
+ * copies the matching template onto the end of the tempfile we are setting
+ * up
+ */
+/* ARGSUSED */
+static int
+rcsinfo_proc (const char *repository, const char *template, void *closure)
+{
+ static char *last_template;
+ FILE *tfp;
+
+ /* nothing to do if the last one included is the same as this one */
+ if (last_template && strcmp (last_template, template) == 0)
+ return (0);
+ if (last_template)
+ free (last_template);
+ last_template = xstrdup (template);
+
+ if ((tfp = CVS_FOPEN (template, "r")) != NULL)
+ {
+ char *line = NULL;
+ size_t line_chars_allocated = 0;
+
+ while (getline (&line, &line_chars_allocated, tfp) >= 0)
+ (void) fputs (line, fp);
+ if (ferror (tfp))
+ error (0, errno, "warning: cannot read %s", template);
+ if (fclose (tfp) < 0)
+ error (0, errno, "warning: cannot close %s", template);
+ if (line)
+ free (line);
+ return (0);
+ }
+ else
+ {
+ error (0, errno, "Couldn't open rcsinfo template file %s", template);
+ return (1);
+ }
+}
+
+/*
+ * Uses setup_tmpfile() to pass the updated message on directly to any
+ * logfile programs that have a regular expression match for the checked in
+ * directory in the source repository. The log information is fed into the
+ * specified program as standard input.
+ */
+struct ulp_data {
+ FILE *logfp;
+ const char *message;
+ List *changes;
+};
+
+
+
+void
+Update_Logfile (const char *repository, const char *xmessage, FILE *xlogfp,
+ List *xchanges)
+{
+ struct ulp_data ud;
+
+ /* nothing to do if the list is empty */
+ if (xchanges == NULL || xchanges->list->next == xchanges->list)
+ return;
+
+ /* set up vars for update_logfile_proc */
+ ud.message = xmessage;
+ ud.logfp = xlogfp;
+ ud.changes = xchanges;
+
+ /* call Parse_Info to do the actual logfile updates */
+ (void) Parse_Info (CVSROOTADM_LOGINFO, repository, update_logfile_proc,
+ PIOPT_ALL, &ud);
+}
+
+
+
+/*
+ * callback proc to actually do the logfile write from Update_Logfile
+ */
+static int
+update_logfile_proc (const char *repository, const char *filter, void *closure)
+{
+ struct ulp_data *udp = closure;
+ TRACE (TRACE_FUNCTION, "update_logfile_proc(%s,%s)", repository, filter);
+ return logfile_write (repository, filter, udp->message, udp->logfp,
+ udp->changes);
+}
+
+
+
+/* static int
+ * logmsg_list_to_args_proc( Node *p, void *closure )
+ * This function is intended to be passed into walklist() with a list of tags
+ * (nodes in the same format as pretag_list_proc() accepts - p->key = tagname
+ * and p->data = a revision.
+ *
+ * closure will be a struct format_cmdline_walklist_closure
+ * where closure is undefined.
+ */
+static int
+logmsg_list_to_args_proc (Node *p, void *closure)
+{
+ struct format_cmdline_walklist_closure *c = closure;
+ struct logfile_info *li;
+ char *arg = NULL;
+ const char *f;
+ char *d;
+ size_t doff;
+
+ if (p->data == NULL) return 1;
+
+ f = c->format;
+ d = *c->d;
+ /* foreach requested attribute */
+ while (*f)
+ {
+ switch (*f++)
+ {
+ case 's':
+ arg = p->key;
+ break;
+ case 'T':
+ li = p->data;
+ arg = li->tag ? li->tag : "";
+ break;
+ case 'V':
+ li = p->data;
+ arg = li->rev_old ? li->rev_old : "NONE";
+ break;
+ case 'v':
+ li = p->data;
+ arg = li->rev_new ? li->rev_new : "NONE";
+ break;
+ default:
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (c->onearg)
+ {
+ /* The old deafult was to print the empty string for
+ * unknown args.
+ */
+ arg = "\0";
+ }
+ else
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ error (1, 0,
+ "Unknown format character or not a list attribute: %c", f[-1]);
+ /* NOTREACHED */
+ break;
+ }
+ /* copy the attribute into an argument */
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (c->onearg)
+ {
+ if (c->firstpass)
+ {
+ c->firstpass = 0;
+ doff = d - *c->buf;
+ expand_string (c->buf, c->length,
+ doff + strlen (c->srepos) + 1);
+ d = *c->buf + doff;
+ strncpy (d, c->srepos, strlen (c->srepos));
+ d += strlen (c->srepos);
+ *d++ = ' ';
+ }
+ }
+ else /* c->onearg */
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ {
+ if (c->quotes)
+ {
+ arg = cmdlineescape (c->quotes, arg);
+ }
+ else
+ {
+ arg = cmdlinequote ('"', arg);
+ }
+ } /* !c->onearg */
+ doff = d - *c->buf;
+ expand_string (c->buf, c->length, doff + strlen (arg));
+ d = *c->buf + doff;
+ strncpy (d, arg, strlen (arg));
+ d += strlen (arg);
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (!c->onearg)
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ free (arg);
+
+ /* Always put the extra space on. we'll have to back up a char
+ * when we're done, but that seems most efficient.
+ */
+ doff = d - *c->buf;
+ expand_string (c->buf, c->length, doff + 1);
+ d = *c->buf + doff;
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (c->onearg && *f) *d++ = ',';
+ else
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ *d++ = ' ';
+ }
+ /* correct our original pointer into the buff */
+ *c->d = d;
+ return 0;
+}
+
+
+
+/*
+ * Writes some stuff to the logfile "filter" and returns the status of the
+ * filter program.
+ */
+static int
+logfile_write (const char *repository, const char *filter, const char *message,
+ FILE *logfp, List *changes)
+{
+ char *cmdline;
+ FILE *pipefp;
+ char *cp;
+ int c;
+ int pipestatus;
+ const char *srepos = Short_Repository (repository);
+
+ assert (repository);
+
+ /* The user may specify a format string as part of the filter.
+ Originally, `%s' was the only valid string. The string that
+ was substituted for it was:
+
+ <repository-name> <file1> <file2> <file3> ...
+
+ Each file was either a new directory/import (T_TITLE), or a
+ added (T_ADDED), modified (T_MODIFIED), or removed (T_REMOVED)
+ file.
+
+ It is desirable to preserve that behavior so lots of commitlog
+ scripts won't die when they get this new code. At the same
+ time, we'd like to pass other information about the files (like
+ version numbers, statuses, or checkin times).
+
+ The solution is to allow a format string that allows us to
+ specify those other pieces of information. The format string
+ will be composed of `%' followed by a single format character,
+ or followed by a set of format characters surrounded by `{' and
+ `}' as separators. The format characters are:
+
+ s = file name
+ V = old version number (pre-checkin)
+ v = new version number (post-checkin)
+
+ For example, valid format strings are:
+
+ %{}
+ %s
+ %{s}
+ %{sVv}
+
+ There's no reason that more items couldn't be added (like
+ modification date or file status [added, modified, updated,
+ etc.]) -- the code modifications would be minimal (logmsg.c
+ (title_proc) and commit.c (check_fileproc)).
+
+ The output will be a string of tokens separated by spaces. For
+ backwards compatibility, the the first token will be the
+ repository name. The rest of the tokens will be
+ comma-delimited lists of the information requested in the
+ format string. For example, if `/u/src/master' is the
+ repository, `%{sVv}' is the format string, and three files
+ (ChangeLog, Makefile, foo.c) were modified, the output might
+ be:
+
+ /u/src/master ChangeLog,1.1,1.2 Makefile,1.3,1.4 foo.c,1.12,1.13
+
+ Why this duplicates the old behavior when the format string is
+ `%s' is left as an exercise for the reader. */
+
+ /* %c = cvs_cmd_name
+ * %p = shortrepos
+ * %r = repository
+ * %{sVv} = file name, old revision (precommit), new revision (postcommit)
+ */
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ !config->UseNewInfoFmtStrings, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s", current_parsed_root->directory,
+ "sVv", ",", changes,
+ logmsg_list_to_args_proc, (void *) NULL,
+ (char *) NULL);
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ error (0, 0, "logmsg proc resolved to the empty string!");
+ return 1;
+ }
+
+ if ((pipefp = run_popen (cmdline, "w")) == NULL)
+ {
+ if (!noexec)
+ error (0, 0, "cannot write entry to log filter: %s", cmdline);
+ free (cmdline);
+ return 1;
+ }
+ (void) fprintf (pipefp, "Update of %s\n", repository);
+ (void) fprintf (pipefp, "In directory %s:", hostname);
+ cp = xgetcwd ();
+ if (cp == NULL)
+ fprintf (pipefp, "<cannot get working directory: %s>\n\n",
+ strerror (errno));
+ else
+ {
+ fprintf (pipefp, "%s\n\n", cp);
+ free (cp);
+ }
+
+ setup_tmpfile (pipefp, "", changes);
+ (void) fprintf (pipefp, "Log Message:\n%s\n", (message) ? message : "");
+ if (logfp)
+ {
+ (void) fprintf (pipefp, "Status:\n");
+ rewind (logfp);
+ while ((c = getc (logfp)) != EOF)
+ (void) putc (c, pipefp);
+ }
+ free (cmdline);
+ pipestatus = pclose (pipefp);
+ return ((pipestatus == -1) || (pipestatus == 127)) ? 1 : 0;
+}
+
+
+
+/* This routine is called by Parse_Info. It runs the
+ * message verification script.
+ */
+static int
+verifymsg_proc (const char *repository, const char *script, void *closure)
+{
+ char *verifymsg_script;
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ char *newscript = NULL;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ struct verifymsg_proc_data *vpd = closure;
+ const char *srepos = Short_Repository (repository);
+
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (!strchr (script, '%'))
+ {
+ error (0, 0,
+ "warning: verifymsg line doesn't contain any format strings:\n"
+ " \"%s\"\n"
+ "Appending default format string (\" %%l\"), but be aware that this usage is\n"
+ "deprecated.", script);
+ script = newscript = Xasprintf ("%s %%l", script);
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+ /* If we don't already have one, open a temporary file, write the message
+ * to the temp file, and close the file.
+ *
+ * We do this here so that we only create the file when there is a
+ * verifymsg script specified and we only create it once when there is
+ * more than one verifymsg script specified.
+ */
+ if (vpd->fname == NULL)
+ {
+ FILE *fp;
+ if ((fp = cvs_temp_file (&(vpd->fname))) == NULL)
+ error (1, errno, "cannot create temporary file %s", vpd->fname);
+
+ if (vpd->message != NULL)
+ fputs (vpd->message, fp);
+ if (vpd->message == NULL ||
+ (vpd->message)[0] == '\0' ||
+ (vpd->message)[strlen (vpd->message) - 1] != '\n')
+ putc ('\n', fp);
+ if (fclose (fp) == EOF)
+ error (1, errno, "%s", vpd->fname);
+
+ if (config->RereadLogAfterVerify == LOGMSG_REREAD_STAT)
+ {
+ /* Remember the status of the temp file for later */
+ if (stat (vpd->fname, &(vpd->pre_stbuf)) != 0)
+ error (1, errno, "cannot stat temp file %s", vpd->fname);
+
+ /*
+ * See if we need to sleep before running the verification
+ * script to avoid time-stamp races.
+ */
+ sleep_past (vpd->pre_stbuf.st_mtime);
+ }
+ } /* if (vpd->fname == NULL) */
+
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ verifymsg_script = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ false, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ script,
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer
+ ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s",
+ current_parsed_root->directory,
+ "l", "s", vpd->fname,
+ "sV", ",", vpd->changes,
+ logmsg_list_to_args_proc, (void *) NULL,
+ (char *) NULL);
+
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (newscript) free (newscript);
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+ if (!verifymsg_script || !strlen (verifymsg_script))
+ {
+ if (verifymsg_script) free (verifymsg_script);
+ verifymsg_script = NULL;
+ error (0, 0, "verifymsg proc resolved to the empty string!");
+ return 1;
+ }
+
+ run_setup (verifymsg_script);
+
+ free (verifymsg_script);
+
+ /* FIXME - because run_exec can return negative values and Parse_Info adds
+ * the values of each call to this function to get a total error, we are
+ * calling abs on the value of run_exec to ensure two errors do not sum to
+ * zero.
+ *
+ * The only REALLY obnoxious thing about this, I guess, is that a -1 return
+ * code from run_exec can mean we failed to call the process for some
+ * reason and should care about errno or that the process we called
+ * returned -1 and the value of errno is undefined. In other words,
+ * run_exec should probably be rewritten to have two return codes. one
+ * which is its own exit status and one which is the child process's. So
+ * there. :P
+ *
+ * Once run_exec is returning two error codes, we should probably be
+ * failing here with an error message including errno when we get the
+ * return code which means we care about errno, in case you missed that
+ * little tidbit.
+ *
+ * I do happen to know we just fail for a non-zero value anyway and I
+ * believe the docs actually state that if the verifymsg_proc returns a
+ * "non-zero" value we will fail.
+ */
+ return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_NORMAL | RUN_SIGIGNORE));
+}
diff --git a/src/ls.c b/src/ls.c
new file mode 100644
index 0000000..0184bdd
--- /dev/null
+++ b/src/ls.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ * Copyright (c) 2001, Tony Hoyle
+ * Copyright (c) 2004, Derek R. Price & Ximbiot <http://ximbiot.com>
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Query CVS/Entries from server
+ */
+
+#include "cvs.h"
+#include <stdbool.h>
+
+static int ls_proc (int argc, char **argv, char *xwhere, char *mwhere,
+ char *mfile, int shorten, int local, char *mname,
+ char *msg);
+
+static const char *const ls_usage[] =
+{
+ "Usage: %s %s [-e | -l] [-RP] [-r rev] [-D date] [path...]\n",
+ "\t-d\tShow dead revisions (with tag when specified).\n",
+ "\t-e\tDisplay in CVS/Entries format.\n",
+ "\t-l\tDisplay all details.\n",
+ "\t-P\tPrune empty directories.\n",
+ "\t-R\tList recursively.\n",
+ "\t-r rev\tShow files with revision or tag.\n",
+ "\t-D date\tShow files from date.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+static bool entries_format;
+static bool long_format;
+static char *show_tag;
+static char *show_date;
+static bool set_tag;
+static char *created_dir;
+static bool tag_validated;
+static bool recurse;
+static bool ls_prune_dirs;
+static char *regexp_match;
+static bool is_rls;
+static bool show_dead_revs;
+
+
+
+int
+ls (int argc, char **argv)
+{
+ int c;
+ int err = 0;
+
+ is_rls = strcmp (cvs_cmd_name, "rls") == 0;
+
+ if (argc == -1)
+ usage (ls_usage);
+
+ entries_format = false;
+ long_format = false;
+ show_tag = NULL;
+ show_date = NULL;
+ tag_validated = false;
+ recurse = false;
+ ls_prune_dirs = false;
+ show_dead_revs = false;
+
+ optind = 0;
+
+ while ((c = getopt (argc, argv,
+#ifdef SERVER_SUPPORT
+ server_active ? "qdelr:D:PR" :
+#endif /* SERVER_SUPPORT */
+ "delr:D:RP"
+ )) != -1)
+ {
+ switch (c)
+ {
+#ifdef SERVER_SUPPORT
+ case 'q':
+ if (server_active)
+ {
+ error (0, 0,
+"`%s ls -q' is deprecated. Please use the global `-q' option instead.",
+ program_name);
+ quiet = true;
+ }
+ else
+ usage (ls_usage);
+ break;
+#endif /* SERVER_SUPPORT */
+ case 'd':
+ show_dead_revs = true;
+ break;
+ case 'e':
+ entries_format = true;
+ break;
+ case 'l':
+ long_format = true;
+ break;
+ case 'r':
+ parse_tagdate (&show_tag, &show_date, optarg);
+ break;
+ case 'D':
+ if (show_date) free (show_date);
+ show_date = Make_Date (optarg);
+ break;
+ case 'P':
+ ls_prune_dirs = true;
+ break;
+ case 'R':
+ recurse = true;
+ break;
+ case '?':
+ default:
+ usage (ls_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (entries_format && long_format)
+ {
+ error (0, 0, "`-e' & `-l' are mutually exclusive.");
+ usage (ls_usage);
+ }
+
+ wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ /* We're the local client. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (is_rls ? !(supported_request ("rlist") || supported_request ("ls"))
+ : !supported_request ("list"))
+ error (1, 0, "server does not support %s", cvs_cmd_name);
+
+ if (quiet && !supported_request ("global-list-quiet"))
+ send_arg ("-q");
+ if (entries_format)
+ send_arg ("-e");
+ if (long_format)
+ send_arg ("-l");
+ if (ls_prune_dirs)
+ send_arg ("-P");
+ if (recurse)
+ send_arg ("-R");
+ if (show_dead_revs)
+ send_arg ("-d");
+ if (show_tag)
+ option_with_arg ("-r", show_tag);
+ if (show_date)
+ client_senddate (show_date);
+
+ send_arg ("--");
+
+ if (is_rls)
+ {
+ int i;
+ for (i = 0; i < argc; i++)
+ send_arg (argv[i]);
+ if (supported_request ("rlist"))
+ send_to_server ("rlist\012", 0);
+ else
+ /* For backwards compatibility with CVSNT... */
+ send_to_server ("ls\012", 0);
+ }
+ else
+ {
+ /* Setting this means, I think, that any empty directories created
+ * by the server will be deleted by the client. Since any dirs
+ * created at all by ls should remain empty, this should cause any
+ * dirs created by the server for the ls command to be deleted.
+ */
+ client_prune_dirs = 1;
+
+ /* I explicitly decide not to send contents here. We *could* let
+ * the user pull status information with this command, but why
+ * don't they just use update or status?
+ */
+ send_files (argc, argv, !recurse, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("list\012", 0);
+ }
+
+ err = get_responses_and_close ();
+ return err;
+ }
+#endif
+
+ if (is_rls)
+ {
+ DBM *db;
+ int i;
+ db = open_module ();
+ if (argc)
+ {
+ for (i = 0; i < argc; i++)
+ {
+ char *mod = xstrdup (argv[i]);
+ char *p;
+
+ for (p=strchr (mod,'\\'); p; p=strchr (p,'\\'))
+ *p='/';
+
+ p = strrchr (mod,'/');
+ if (p && (strchr (p,'?') || strchr (p,'*')))
+ {
+ *p='\0';
+ regexp_match = p+1;
+ }
+ else
+ regexp_match = NULL;
+
+ /* Frontends like to do 'ls -q /', so we support it explicitly.
+ */
+ if (!strcmp (mod,"/"))
+ {
+ *mod='\0';
+ }
+
+ err += do_module (db, mod, MISC, "Listing",
+ ls_proc, NULL, 0, 0, 0, 0, NULL);
+
+ free (mod);
+ }
+ }
+ else
+ {
+ /* should be ".", but do_recursion()
+ fails this: assert ( strstr ( repository, "/./" ) == NULL ); */
+ char *topmod = xstrdup ("");
+ err += do_module (db, topmod, MISC, "Listing",
+ ls_proc, NULL, 0, 0, 0, 0, NULL);
+ free (topmod);
+ }
+ close_module (db);
+ }
+ else
+ ls_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, 0, NULL, NULL);
+
+ return err;
+}
+
+
+
+struct long_format_data
+{
+ char *header;
+ char *time;
+ char *footer;
+};
+
+static int
+ls_print (Node *p, void *closure)
+{
+ if (long_format)
+ {
+ struct long_format_data *data = p->data;
+ cvs_output_tagged ("text", data->header);
+ if (data->time)
+ cvs_output_tagged ("date", data->time);
+ if (data->footer)
+ cvs_output_tagged ("text", data->footer);
+ cvs_output_tagged ("newline", NULL);
+ }
+ else
+ cvs_output (p->data, 0);
+ return 0;
+}
+
+
+
+static int
+ls_print_dir (Node *p, void *closure)
+{
+ static bool printed = false;
+
+ if (recurse && !(ls_prune_dirs && list_isempty (p->data)))
+ {
+ /* Keep track of whether we've printed. If we have, then put a blank
+ * line before directory headers, to separate the header from the
+ * listing of the previous directory.
+ */
+ if (printed)
+ cvs_output ("\n", 1);
+ else
+ printed = true;
+
+ if (!strcmp (p->key, ""))
+ cvs_output (".", 1);
+ else
+ cvs_output (p->key, 0);
+ cvs_output (":\n", 2);
+ }
+ walklist (p->data, ls_print, NULL);
+ return 0;
+}
+
+
+
+/*
+ * Delproc for a node containing a struct long_format_data as data.
+ */
+static void
+long_format_data_delproc (Node *n)
+{
+ struct long_format_data *data = (struct long_format_data *)n->data;
+ if (data->header) free (data->header);
+ if (data->time) free (data->time);
+ if (data->footer) free (data->footer);
+ free (data);
+}
+
+
+
+/* A delproc for a List Node containing a List *. */
+static void
+ls_delproc (Node *p)
+{
+ dellist ((List **)&p->data);
+}
+
+
+
+/*
+ * Add a file to our list of data to print for a directory.
+ */
+/* ARGSUSED */
+static int
+ls_fileproc (void *callerdat, struct file_info *finfo)
+{
+ Vers_TS *vers;
+ char *regex_err;
+ Node *p, *n;
+ bool isdead;
+ const char *filename;
+
+ if (regexp_match)
+ {
+#ifdef FILENAMES_CASE_INSENSITIVE
+ re_set_syntax (REG_ICASE|RE_SYNTAX_EGREP);
+#else
+ re_set_syntax (RE_SYNTAX_EGREP);
+#endif
+ if ((regex_err = re_comp (regexp_match)) != NULL)
+ {
+ error (1, 0, "bad regular expression passed to 'ls': %s",
+ regex_err);
+ }
+ if (re_exec (finfo->file) == 0)
+ return 0; /* no match */
+ }
+
+ vers = Version_TS (finfo, NULL, show_tag, show_date, 1, 0);
+ /* Skip dead revisions unless specifically requested to do otherwise.
+ * We also bother to check for long_format so we can print the state.
+ */
+ if (vers->vn_rcs && (!show_dead_revs || long_format))
+ isdead = RCS_isdead (finfo->rcs, vers->vn_rcs);
+ else
+ isdead = false;
+ if (!vers->vn_rcs || (!show_dead_revs && isdead))
+ {
+ freevers_ts (&vers);
+ return 0;
+ }
+
+ p = findnode (callerdat, finfo->update_dir);
+ if (!p)
+ {
+ /* This only occurs when a complete path to a file is specified on the
+ * command line. Put the file in the root list.
+ */
+ filename = finfo->fullname;
+
+ /* Add update_dir node. */
+ p = findnode (callerdat, ".");
+ if (!p)
+ {
+ p = getnode ();
+ p->key = xstrdup (".");
+ p->data = getlist ();
+ p->delproc = ls_delproc;
+ addnode (callerdat, p);
+ }
+ }
+ else
+ filename = finfo->file;
+
+ n = getnode();
+ if (entries_format)
+ {
+ char *outdate = entries_time (RCS_getrevtime (finfo->rcs, vers->vn_rcs,
+ 0, 0));
+ n->data = Xasprintf ("/%s/%s/%s/%s/%s%s\n",
+ filename, vers->vn_rcs,
+ outdate, vers->options,
+ show_tag ? "T" : "", show_tag ? show_tag : "");
+ free (outdate);
+ }
+ else if (long_format)
+ {
+ struct long_format_data *out =
+ xmalloc (sizeof (struct long_format_data));
+ out->header = Xasprintf ("%-5.5s",
+ vers->options[0] != '\0' ? vers->options
+ : "----");
+ /* FIXME: Do we want to mimc the real `ls' command's date format? */
+ out->time = gmformat_time_t (RCS_getrevtime (finfo->rcs, vers->vn_rcs,
+ 0, 0));
+ out->footer = Xasprintf (" %-9.9s%s %s%s", vers->vn_rcs,
+ strlen (vers->vn_rcs) > 9 ? "+" : " ",
+ show_dead_revs ? (isdead ? "dead " : " ")
+ : "",
+ filename);
+ n->data = out;
+ n->delproc = long_format_data_delproc;
+ }
+ else
+ n->data = Xasprintf ("%s\n", filename);
+
+ addnode (p->data, n);
+
+ freevers_ts (&vers);
+ return 0;
+}
+
+
+
+/*
+ * Add this directory to the list of data to be printed for a directory and
+ * decide whether to tell the recursion processor whether to continue
+ * recursing or not.
+ */
+static Dtype
+ls_direntproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+ Dtype retval;
+ Node *p;
+
+ /* Due to the way we called start_recursion() from ls_proc() with a single
+ * argument at a time, we can assume that if we don't yet have a parent
+ * directory in DIRS then this directory should be processed.
+ */
+
+ if (strcmp (dir, "."))
+ {
+ /* Search for our parent directory. */
+ char *parent;
+ parent = xmalloc (strlen (update_dir) - strlen (dir) + 1);
+ strncpy (parent, update_dir, strlen (update_dir) - strlen (dir));
+ parent[strlen (update_dir) - strlen (dir)] = '\0';
+ strip_trailing_slashes (parent);
+ p = findnode (callerdat, parent);
+ }
+ else
+ p = NULL;
+
+ if (p)
+ {
+ /* Push this dir onto our parent directory's listing. */
+ Node *n = getnode();
+
+ if (entries_format)
+ n->data = Xasprintf ("D/%s////\n", dir);
+ else if (long_format)
+ {
+ struct long_format_data *out =
+ xmalloc (sizeof (struct long_format_data));
+ out->header = xstrdup ("d--- ");
+ out->time = gmformat_time_t (unix_time_stamp (repos));
+ out->footer = Xasprintf ("%12s%s%s", "",
+ show_dead_revs ? " " : "", dir);
+ n->data = out;
+ n->delproc = long_format_data_delproc;
+ }
+ else
+ n->data = Xasprintf ("%s\n", dir);
+
+ addnode (p->data, n);
+ }
+
+ if (!p || recurse)
+ {
+ /* Create a new list for this directory. */
+ p = getnode ();
+ p->key = xstrdup (strcmp (update_dir, ".") ? update_dir : "");
+ p->data = getlist ();
+ p->delproc = ls_delproc;
+ addnode (callerdat, p);
+
+ /* Create a local directory and mark it as needing deletion. This is
+ * the behavior the recursion processor relies upon, a la update &
+ * checkout.
+ */
+ if (!isdir (dir))
+ {
+ int nonbranch;
+ if (show_tag == NULL && show_date == NULL)
+ {
+ ParseTag (&show_tag, &show_date, &nonbranch);
+ set_tag = true;
+ }
+
+ if (!created_dir)
+ created_dir = xstrdup (update_dir);
+
+ make_directory (dir);
+ Create_Admin (dir, update_dir, repos, show_tag, show_date,
+ nonbranch, 0, 0);
+ Subdir_Register (entries, NULL, dir);
+ }
+
+ /* Tell do_recursion to keep going. */
+ retval = R_PROCESS;
+ }
+ else
+ retval = R_SKIP_ALL;
+
+ return retval;
+}
+
+
+
+/* Clean up tags, dates, and dirs if we created this directory.
+ */
+static int
+ls_dirleaveproc (void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries)
+{
+ if (created_dir && !strcmp (created_dir, update_dir))
+ {
+ if (set_tag)
+ {
+ if (show_tag) free (show_tag);
+ if (show_date) free (show_date);
+ show_tag = show_date = NULL;
+ set_tag = false;
+ }
+
+ (void)CVS_CHDIR ("..");
+ if (unlink_file_dir (dir))
+ error (0, errno, "Failed to remove directory `%s'",
+ created_dir);
+ Subdir_Deregister (entries, NULL, dir);
+
+ free (created_dir);
+ created_dir = NULL;
+ }
+ return err;
+}
+
+
+
+static int
+ls_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile,
+ int shorten, int local, char *mname, char *msg)
+{
+ char *repository;
+ int err = 0;
+ int which;
+ char *where;
+ int i;
+
+ if (is_rls)
+ {
+ char *myargv[2];
+
+ if (!quiet)
+ error (0, 0, "Listing module: `%s'",
+ strcmp (mname, "") ? mname : ".");
+
+ repository = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ + 2);
+ (void)sprintf (repository, "%s/%s", current_parsed_root->directory,
+ argv[0]);
+ where = xmalloc (strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ + 1);
+ (void)strcpy (where, argv[0]);
+
+ /* If mfile isn't null, we need to set up to do only part of the
+ * module.
+ */
+ if (mfile != NULL)
+ {
+ char *cp;
+ char *path;
+
+ /* If the portion of the module is a path, put the dir part on
+ * repos.
+ */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = '\0';
+ (void)strcat (repository, "/");
+ (void)strcat (repository, mfile);
+ (void)strcat (where, "/");
+ (void)strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+ /* take care of the rest */
+ path = Xasprintf ("%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* directory means repository gets the dir tacked on */
+ (void)strcpy (repository, path);
+ (void)strcat (where, "/");
+ (void)strcat (where, mfile);
+ }
+ else
+ {
+ myargv[1] = mfile;
+ argc = 2;
+ argv = myargv;
+ }
+ free (path);
+ }
+
+ /* cd to the starting repository */
+ if (CVS_CHDIR (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ free (repository);
+ free (where);
+ return 1;
+ }
+
+ which = W_REPOS;
+ }
+ else /* !is_rls */
+ {
+ repository = NULL;
+ where = NULL;
+ which = W_LOCAL | W_REPOS;
+ }
+
+ if (show_tag || show_date || show_dead_revs)
+ which |= W_ATTIC;
+
+ if (show_tag != NULL && !tag_validated)
+ {
+ tag_check_valid (show_tag, argc - 1, argv + 1, local, 0, repository,
+ false);
+ tag_validated = true;
+ }
+
+ /* Loop on argc so that we are guaranteed that any directory passed to
+ * ls_direntproc should be processed if its parent is not yet in DIRS.
+ */
+ if (argc == 1)
+ {
+ List *dirs = getlist ();
+ err = start_recursion (ls_fileproc, NULL, ls_direntproc,
+ ls_dirleaveproc, dirs, 0, NULL, local, which, 0,
+ CVS_LOCK_READ, where, 1, repository);
+ walklist (dirs, ls_print_dir, NULL);
+ dellist (&dirs);
+ }
+ else
+ {
+ for (i = 1; i < argc; i++)
+ {
+ List *dirs = getlist ();
+ err = start_recursion (ls_fileproc, NULL, ls_direntproc,
+ NULL, dirs, 1, argv + i, local, which, 0,
+ CVS_LOCK_READ, where, 1, repository);
+ walklist (dirs, ls_print_dir, NULL);
+ dellist (&dirs);
+ }
+ }
+
+ if (!(which & W_LOCAL)) free (repository);
+ if (where) free (where);
+
+ return err;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..45208fa
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,1466 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS source distribution.
+ *
+ * This is the main C driver for the CVS system.
+ *
+ * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
+ * the shell-script CVS system that this is based on.
+ *
+ */
+
+#include "cvs.h"
+
+#include "closeout.h"
+#include "setenv.h"
+#include "strftime.h"
+#include "xgethostname.h"
+
+const char *program_name;
+const char *program_path;
+const char *cvs_cmd_name;
+
+const char *global_session_id; /* Random session ID */
+
+char *hostname;
+/* FIXME: Perhaps this should be renamed original_hostname or the like? */
+char *server_hostname;
+
+int use_editor = 1;
+int use_cvsrc = 1;
+int cvswrite = !CVSREAD_DFLT;
+int really_quiet = 0;
+int quiet = 0;
+int trace = 0;
+int noexec = 0;
+int readonlyfs = 0;
+int logoff = 0;
+
+
+
+/***
+ ***
+ *** CVSROOT/config options
+ ***
+ ***/
+struct config *config;
+
+
+
+mode_t cvsumask = UMASK_DFLT;
+
+char *CurDir;
+
+/*
+ * Defaults, for the environment variables that are not set
+ */
+char *Editor = EDITOR_DFLT;
+
+
+
+/* Temp dir stuff. */
+
+/* Temp dir, if set by the user. */
+static char *tmpdir_cmdline;
+
+
+
+/* Returns in order of precedence:
+ *
+ * 1. Temp dir as set via the command line.
+ * 2. Temp dir as set in CVSROOT/config.
+ * 3. Temp dir as set in $TMPDIR env var.
+ * 4. Contents of TMPDIR_DFLT preprocessor macro.
+ *
+ * ERRORS
+ * It is a fatal error if this function would otherwise return NULL or an
+ * empty string.
+ */
+const char *
+get_cvs_tmp_dir (void)
+{
+ const char *retval;
+ if (tmpdir_cmdline) retval = tmpdir_cmdline;
+ else if (config && config->TmpDir) retval = config->TmpDir;
+ else retval = get_system_temp_dir ();
+ if (!retval) retval = TMPDIR_DFLT;
+
+ if (!retval || !*retval) error (1, 0, "No temp dir specified.");
+
+ return retval;
+}
+
+
+
+/* When our working directory contains subdirectories with different
+ values in CVS/Root files, we maintain a list of them. */
+List *root_directories = NULL;
+
+static const struct cmd
+{
+ const char *fullname; /* Full name of the function (e.g. "commit") */
+
+ /* Synonyms for the command, nick1 and nick2. We supply them
+ mostly for two reasons: (1) CVS has always supported them, and
+ we need to maintain compatibility, (2) if there is a need for a
+ version which is shorter than the fullname, for ease in typing.
+ Synonyms have the disadvantage that people will see "new" and
+ then have to think about it, or look it up, to realize that is
+ the operation they know as "add". Also, this means that one
+ cannot create a command "cvs new" with a different meaning. So
+ new synonyms are probably best used sparingly, and where used
+ should be abbreviations of the fullname (preferably consisting
+ of the first 2 or 3 or so letters).
+
+ One thing that some systems do is to recognize any unique
+ abbreviation, for example "annotat" "annota", etc., for
+ "annotate". The problem with this is that scripts and user
+ habits will expect a certain abbreviation to be unique, and in
+ a future release of CVS it may not be. So it is better to
+ accept only an explicit list of abbreviations and plan on
+ supporting them in the future as well as now. */
+
+ const char *nick1;
+ const char *nick2;
+
+ int (*func) (int, char **); /* Function takes (argc, argv) arguments. */
+ unsigned long attr; /* Attributes. */
+} cmds[] =
+
+{
+ { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "annotate", "ann", NULL, annotate, CVS_CMD_USES_WORK_DIR },
+ { "checkout", "co", "get", checkout, 0 },
+ { "commit", "ci", "com", commit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "diff", "di", "dif", diff, CVS_CMD_USES_WORK_DIR },
+ { "edit", NULL, NULL, edit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "editors", NULL, NULL, editors, CVS_CMD_USES_WORK_DIR },
+ { "export", "exp", "ex", checkout, CVS_CMD_USES_WORK_DIR },
+ { "history", "hi", "his", history, CVS_CMD_USES_WORK_DIR },
+ { "import", "im", "imp", import, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR | CVS_CMD_IGNORE_ADMROOT},
+ { "init", NULL, NULL, init, CVS_CMD_MODIFIES_REPOSITORY },
+#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
+ { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
+#endif
+ { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR },
+#ifdef AUTH_CLIENT_SUPPORT
+ { "login", "logon", "lgn", login, 0 },
+ { "logout", NULL, NULL, logout, 0 },
+#endif /* AUTH_CLIENT_SUPPORT */
+ { "ls", "dir", "list", ls, 0 },
+#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
+ { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
+#endif
+ { "rannotate","rann", "ra", annotate, 0 },
+ { "rdiff", "patch", "pa", patch, 0 },
+ { "release", "re", "rel", release, CVS_CMD_MODIFIES_REPOSITORY },
+ { "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "rlog", "rl", NULL, cvslog, 0 },
+ { "rls", "rdir", "rlist", ls, 0 },
+ { "rtag", "rt", "rfreeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY },
+#ifdef SERVER_SUPPORT
+ { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+#endif
+ { "status", "st", "stat", cvsstatus, CVS_CMD_USES_WORK_DIR },
+ { "tag", "ta", "freeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "unedit", NULL, NULL, unedit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "update", "up", "upd", update, CVS_CMD_USES_WORK_DIR },
+ { "version", "ve", "ver", version, 0 },
+ { "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+ { "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR },
+ { NULL, NULL, NULL, NULL, 0 },
+};
+
+static const char *const usg[] =
+{
+ /* CVS usage messages never have followed the GNU convention of
+ putting metavariables in uppercase. I don't know whether that
+ is a good convention or not, but if it changes it would have to
+ change in all the usage messages. For now, they consistently
+ use lowercase, as far as I know. Punctuation is pretty funky,
+ though. Sometimes they use none, as here. Sometimes they use
+ single quotes (not the TeX-ish `' stuff), as in --help-options.
+ Sometimes they use double quotes, as in cvs -H add.
+
+ Most (not all) of the usage messages seem to have periods at
+ the end of each line. I haven't tried to duplicate this style
+ in --help as it is a rather different format from the rest. */
+
+ "Usage: %s [cvs-options] command [command-options-and-arguments]\n",
+ " where cvs-options are -q, -n, etc.\n",
+ " (specify --help-options for a list of options)\n",
+ " where command is add, admin, etc.\n",
+ " (specify --help-commands for a list of commands\n",
+ " or --help-synonyms for a list of command synonyms)\n",
+ " where command-options-and-arguments depend on the specific command\n",
+ " (specify -H followed by a command name for command-specific help)\n",
+ " Specify --help to receive this message\n",
+ "\n",
+
+ /* Some people think that a bug-reporting address should go here. IMHO,
+ the web sites are better because anything else is very likely to go
+ obsolete in the years between a release and when someone might be
+ reading this help. Besides, we could never adequately discuss
+ bug reporting in a concise enough way to put in a help message. */
+
+ /* I was going to put this at the top, but usage() wants the %s to
+ be in the first line. */
+ "The Concurrent Versions System (CVS) is a tool for version control.\n",
+ /* I really don't think I want to try to define "version control"
+ in one line. I'm not sure one can get more concise than the
+ paragraph in ../cvs.spec without assuming the reader knows what
+ version control means. */
+
+ "For CVS updates and additional information, see\n",
+ " the CVS home page at http://www.nongnu.org/cvs/ or\n",
+ " the CVSNT home page at http://www.cvsnt.org/\n",
+ NULL,
+};
+
+static const char *const cmd_usage[] =
+{
+ "CVS commands are:\n",
+ " add Add a new file/directory to the repository\n",
+ " admin Administration front end for rcs\n",
+ " annotate Show last revision where each line was modified\n",
+ " checkout Checkout sources for editing\n",
+ " commit Check files into the repository\n",
+ " diff Show differences between revisions\n",
+ " edit Get ready to edit a watched file\n",
+ " editors See who is editing a watched file\n",
+ " export Export sources from CVS, similar to checkout\n",
+ " history Show repository access history\n",
+ " import Import sources into CVS, using vendor branches\n",
+ " init Create a CVS repository if it doesn't exist\n",
+#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
+ " kserver Kerberos server mode\n",
+#endif
+ " log Print out history information for files\n",
+#ifdef AUTH_CLIENT_SUPPORT
+ " login Prompt for password for authenticating server\n",
+ " logout Removes entry in .cvspass for remote repository\n",
+#endif /* AUTH_CLIENT_SUPPORT */
+ " ls List files available from CVS\n",
+#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
+ " pserver Password server mode\n",
+#endif
+ " rannotate Show last revision where each line of module was modified\n",
+ " rdiff Create 'patch' format diffs between releases\n",
+ " release Indicate that a Module is no longer in use\n",
+ " remove Remove an entry from the repository\n",
+ " rlog Print out history information for a module\n",
+ " rls List files in a module\n",
+ " rtag Add a symbolic tag to a module\n",
+#ifdef SERVER_SUPPORT
+ " server Server mode\n",
+#endif
+ " status Display status information on checked out files\n",
+ " tag Add a symbolic tag to checked out version of files\n",
+ " unedit Undo an edit command\n",
+ " update Bring work tree in sync with repository\n",
+ " version Show current CVS version(s)\n",
+ " watch Set watches\n",
+ " watchers See who is watching a file\n",
+ "(Specify the --help option for a list of other help options)\n",
+ NULL,
+};
+
+static const char *const opt_usage[] =
+{
+ /* Omit -b because it is just for compatibility. */
+ "CVS global options (specified before the command name) are:\n",
+ " -H Displays usage information for command.\n",
+ " -Q Cause CVS to be really quiet.\n",
+ " -q Cause CVS to be somewhat quiet.\n",
+ " -r Make checked-out files read-only.\n",
+ " -w Make checked-out files read-write (default).\n",
+ " -n Do not execute anything that will change the disk.\n",
+ " -t Show trace of program execution (repeat for more\n",
+ " verbosity) -- try with -n.\n",
+ " -R Assume repository is read-only, such as CDROM\n",
+ " -v CVS version and copyright.\n",
+ " -T tmpdir Use 'tmpdir' for temporary files.\n",
+ " -e editor Use 'editor' for editing log information.\n",
+ " -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n",
+ " -f Do not use the ~/.cvsrc file.\n",
+#ifdef CLIENT_SUPPORT
+ " -z # Request compression level '#' for net traffic.\n",
+#ifdef ENCRYPTION
+ " -x Encrypt all net traffic.\n",
+#endif
+ " -a Authenticate all net traffic.\n",
+#endif
+ " -s VAR=VAL Set CVS user variable.\n",
+ "(Specify the --help option for a list of other help options)\n",
+ NULL
+};
+
+
+static int
+set_root_directory (Node *p, void *ignored)
+{
+ if (current_parsed_root == NULL && p->data != NULL)
+ {
+ current_parsed_root = p->data;
+ original_parsed_root = current_parsed_root;
+ return 1;
+ }
+ return 0;
+}
+
+
+static const char * const*
+cmd_synonyms (void)
+{
+ char ** synonyms;
+ char ** line;
+ const struct cmd *c = &cmds[0];
+ /* Three more for title, "specify --help" line, and NULL. */
+ int numcmds = 3;
+
+ while (c->fullname != NULL)
+ {
+ numcmds++;
+ c++;
+ }
+
+ synonyms = xnmalloc (numcmds, sizeof(char *));
+ line = synonyms;
+ *line++ = "CVS command synonyms are:\n";
+ for (c = &cmds[0]; c->fullname != NULL; c++)
+ {
+ if (c->nick1 || c->nick2)
+ {
+ *line = Xasprintf (" %-12s %s %s\n", c->fullname,
+ c->nick1 ? c->nick1 : "",
+ c->nick2 ? c->nick2 : "");
+ line++;
+ }
+ }
+ *line++ = "(Specify the --help option for a list of other help options)\n";
+ *line = NULL;
+
+ return (const char * const*) synonyms; /* will never be freed */
+}
+
+
+
+unsigned long int
+lookup_command_attribute (const char *cmd_name)
+{
+ const struct cmd *cm;
+
+ for (cm = cmds; cm->fullname; cm++)
+ {
+ if (strcmp (cmd_name, cm->fullname) == 0)
+ break;
+ }
+ if (!cm->fullname)
+ error (1, 0, "unknown command: %s", cmd_name);
+ return cm->attr;
+}
+
+
+
+/*
+ * Exit with an error code and an informative message about the signal
+ * received. This function, by virtue of causing an actual call to exit(),
+ * causes all the atexit() handlers to be called.
+ *
+ * INPUTS
+ * sig The signal recieved.
+ *
+ * ERRORS
+ * The cleanup routines registered via atexit() and the error function
+ * itself can potentially change the exit status. They shouldn't do this
+ * unless they encounter problems doing their own jobs.
+ *
+ * RETURNS
+ * Nothing. This function will always exit. It should exit with an exit
+ * status of 1, but might not, as noted in the ERRORS section above.
+ */
+#ifndef DONT_USE_SIGNALS
+static RETSIGTYPE main_cleanup (int) __attribute__ ((__noreturn__));
+#endif /* DONT_USE_SIGNALS */
+static RETSIGTYPE
+main_cleanup (int sig)
+{
+#ifndef DONT_USE_SIGNALS
+ const char *name;
+ char temp[10];
+
+ switch (sig)
+ {
+#ifdef SIGABRT
+ case SIGABRT:
+ name = "abort";
+ break;
+#endif
+#ifdef SIGHUP
+ case SIGHUP:
+ name = "hangup";
+ break;
+#endif
+#ifdef SIGINT
+ case SIGINT:
+ name = "interrupt";
+ break;
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT:
+ name = "quit";
+ break;
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE:
+ name = "broken pipe";
+ break;
+#endif
+#ifdef SIGTERM
+ case SIGTERM:
+ name = "termination";
+ break;
+#endif
+ default:
+ /* This case should never be reached, because we list above all
+ the signals for which we actually establish a signal handler. */
+ sprintf (temp, "%d", sig);
+ name = temp;
+ break;
+ }
+
+ /* This always exits, which will cause our exit handlers to be called. */
+ error (1, 0, "received %s signal", name);
+ /* but make the exit explicit to silence warnings when gcc processes the
+ * noreturn attribute.
+ */
+ exit (EXIT_FAILURE);
+#endif /* !DONT_USE_SIGNALS */
+}
+
+
+
+/* From server.c.
+ *
+ * When !defined ALLOW_CONFIG_OVERRIDE, this will never have any value but
+ * NULL.
+ */
+extern char *gConfigPath;
+
+
+
+
+enum {RANDOM_BYTES = 8};
+enum {COMMITID_RAW_SIZE = (sizeof(time_t) + RANDOM_BYTES)};
+
+static char const alphabet[62] =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+/* Divide BUF by D, returning the remainder. Replace BUF by the
+ quotient. BUF[0] is the most significant part of BUF.
+ D must not exceed UINT_MAX >> CHAR_BIT. */
+static unsigned int
+divide_by (unsigned char buf[COMMITID_RAW_SIZE], unsigned int d)
+{
+ unsigned int carry = 0;
+ int i;
+ for (i = 0; i < COMMITID_RAW_SIZE; i++)
+ {
+ unsigned int byte = buf[i];
+ unsigned int dividend = (carry << CHAR_BIT) + byte;
+ buf[i] = dividend / d;
+ carry = dividend % d;
+ }
+ return carry;
+}
+
+static void
+convert (char const input[COMMITID_RAW_SIZE], char *output)
+{
+ static char const zero[COMMITID_RAW_SIZE] = { 0, };
+ unsigned char buf[COMMITID_RAW_SIZE];
+ size_t o = 0;
+ memcpy (buf, input, COMMITID_RAW_SIZE);
+ while (memcmp (buf, zero, COMMITID_RAW_SIZE) != 0)
+ output[o++] = alphabet[divide_by (buf, sizeof alphabet)];
+ if (! o)
+ output[o++] = '0';
+ output[o] = '\0';
+}
+
+
+int
+main (int argc, char **argv)
+{
+ cvsroot_t *CVSroot_parsed = NULL;
+ bool cvsroot_update_env = true;
+ char *cp, *end;
+ const struct cmd *cm;
+ int c, err = 0;
+ int free_Editor = 0;
+
+ int help = 0; /* Has the user asked for help? This
+ lets us support the `cvs -H cmd'
+ convention to give help for cmd. */
+ static const char short_options[] = "+QqrwtnRvb:T:e:d:Hfz:s:xa";
+ static struct option long_options[] =
+ {
+ {"help", 0, NULL, 'H'},
+ {"version", 0, NULL, 'v'},
+ {"help-commands", 0, NULL, 1},
+ {"help-synonyms", 0, NULL, 2},
+ {"help-options", 0, NULL, 4},
+#ifdef SERVER_SUPPORT
+ {"allow-root", required_argument, NULL, 3},
+#endif /* SERVER_SUPPORT */
+ {0, 0, 0, 0}
+ };
+ /* `getopt_long' stores the option index here, but right now we
+ don't use it. */
+ int option_index = 0;
+
+#ifdef SYSTEM_INITIALIZE
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_INITIALIZE (&argc, &argv);
+#endif
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ cleanup_register (SYSTEM_CLEANUP);
+#endif
+
+#ifdef HAVE_TZSET
+ /* On systems that have tzset (which is almost all the ones I know
+ of), it's a good idea to call it. */
+ tzset ();
+#endif
+
+ /*
+ * Just save the last component of the path for error messages
+ */
+ program_path = xstrdup (argv[0]);
+#ifdef ARGV0_NOT_PROGRAM_NAME
+ /* On some systems, e.g. VMS, argv[0] is not the name of the command
+ which the user types to invoke the program. */
+ program_name = "cvs";
+#else
+ program_name = last_component (argv[0]);
+#endif
+
+ /*
+ * Query the environment variables up-front, so that
+ * they can be overridden by command line arguments
+ */
+ if ((cp = getenv (EDITOR1_ENV)) != NULL)
+ Editor = cp;
+ else if ((cp = getenv (EDITOR2_ENV)) != NULL)
+ Editor = cp;
+ else if ((cp = getenv (EDITOR3_ENV)) != NULL)
+ Editor = cp;
+ if (getenv (CVSREAD_ENV) != NULL)
+ cvswrite = 0;
+ if (getenv (CVSREADONLYFS_ENV) != NULL) {
+ readonlyfs = 1;
+ logoff = 1;
+ }
+
+ /* Set this to 0 to force getopt initialization. getopt() sets
+ this to 1 internally. */
+ optind = 0;
+
+ /* We have to parse the options twice because else there is no
+ chance to avoid reading the global options from ".cvsrc". Set
+ opterr to 0 for avoiding error messages about invalid options.
+ */
+ opterr = 0;
+
+ while ((c = getopt_long
+ (argc, argv, short_options, long_options, &option_index))
+ != EOF)
+ {
+ if (c == 'f')
+ use_cvsrc = 0;
+ }
+
+#ifdef SERVER_SUPPORT
+ /* Don't try and read a .cvsrc file if we are a server. */
+ if (optind < argc
+ && (false
+# if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
+ || !strcmp (argv[optind], "pserver")
+# endif
+# ifdef HAVE_KERBEROS
+ || !strcmp (argv[optind], "kserver")
+# endif /* HAVE_KERBEROS */
+ || !strcmp (argv[optind], "server")))
+ {
+ /* Avoid any .cvsrc file. */
+ use_cvsrc = 0;
+ /* Pre-parse the server options to get the config path. */
+ cvs_cmd_name = argv[optind];
+ parseServerOptions (argc - optind, argv + optind);
+ }
+#endif /* SERVER_SUPPORT */
+
+ /*
+ * Scan cvsrc file for global options.
+ */
+ if (use_cvsrc)
+ read_cvsrc (&argc, &argv, "cvs");
+
+ optind = 0;
+ opterr = 1;
+
+ while ((c = getopt_long
+ (argc, argv, short_options, long_options, &option_index))
+ != EOF)
+ {
+ switch (c)
+ {
+ case 1:
+ /* --help-commands */
+ usage (cmd_usage);
+ break;
+ case 2:
+ /* --help-synonyms */
+ usage (cmd_synonyms());
+ break;
+ case 4:
+ /* --help-options */
+ usage (opt_usage);
+ break;
+#ifdef SERVER_SUPPORT
+ case 3:
+ /* --allow-root */
+ root_allow_add (optarg, gConfigPath);
+ break;
+#endif /* SERVER_SUPPORT */
+ case 'Q':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ cvswrite = 0;
+ break;
+ case 'w':
+ cvswrite = 1;
+ break;
+ case 't':
+ trace++;
+ break;
+ case 'R':
+ readonlyfs = -1;
+ logoff = 1;
+ break;
+ case 'n':
+ noexec = 1;
+ logoff = 1;
+ break;
+ case 'v':
+ (void) fputs ("\n", stdout);
+ version (0, NULL);
+ (void) fputs ("\n", stdout);
+ (void) fputs ("\
+Copyright (C) 2005 Free Software Foundation, Inc.\n\
+\n\
+Senior active maintainers include Larry Jones, Derek R. Price,\n\
+and Mark D. Baushke. Please see the AUTHORS and README files from the CVS\n\
+distribution kit for a complete list of contributors and copyrights.\n",
+ stdout);
+ (void) fputs ("\n", stdout);
+ (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
+ (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
+ (void) fputs ("\n", stdout);
+
+ (void) fputs ("Specify the --help option for further information about CVS\n", stdout);
+
+ exit (0);
+ break;
+ case 'b':
+ /* This option used to specify the directory for RCS
+ executables. But since we don't run them any more,
+ this is a noop. Silently ignore it so that .cvsrc
+ and scripts and inetd.conf and such can work with
+ either new or old CVS. */
+ break;
+ case 'T':
+ if (tmpdir_cmdline) free (tmpdir_cmdline);
+ tmpdir_cmdline = xstrdup (optarg);
+ break;
+ case 'e':
+ if (free_Editor) free (Editor);
+ Editor = xstrdup (optarg);
+ free_Editor = 1;
+ break;
+ case 'd':
+ if (CVSroot_cmdline != NULL)
+ free (CVSroot_cmdline);
+ CVSroot_cmdline = xstrdup (optarg);
+ break;
+ case 'H':
+ help = 1;
+ break;
+ case 'f':
+ use_cvsrc = 0; /* unnecessary, since we've done it above */
+ break;
+ case 'z':
+#ifdef CLIENT_SUPPORT
+ gzip_level = strtol (optarg, &end, 10);
+ if (*end != '\0' || gzip_level < 0 || gzip_level > 9)
+ error (1, 0,
+ "gzip compression level must be between 0 and 9");
+#endif /* CLIENT_SUPPORT */
+ /* If no CLIENT_SUPPORT, we just silently ignore the gzip
+ * level, so that users can have it in their .cvsrc and not
+ * cause any trouble.
+ *
+ * We still parse the argument to -z for correctness since
+ * one user complained of being bitten by a run of
+ * `cvs -z -n up' which read -n as the argument to -z without
+ * complaining. */
+ break;
+ case 's':
+ variable_set (optarg);
+ break;
+ case 'x':
+#ifdef CLIENT_SUPPORT
+ cvsencrypt = 1;
+#endif /* CLIENT_SUPPORT */
+ /* If no CLIENT_SUPPORT, ignore -x, so that users can
+ have it in their .cvsrc and not cause any trouble.
+ If no ENCRYPTION, we still accept -x, but issue an
+ error if we are being run as a client. */
+ break;
+ case 'a':
+#ifdef CLIENT_SUPPORT
+ cvsauthenticate = 1;
+#endif
+ /* If no CLIENT_SUPPORT, ignore -a, so that users can
+ have it in their .cvsrc and not cause any trouble.
+ We will issue an error later if stream
+ authentication is not supported. */
+ break;
+ case '?':
+ default:
+ usage (usg);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage (usg);
+
+ if (readonlyfs && !really_quiet) {
+ error (0, 0,
+ "WARNING: Read-only repository access mode selected via `cvs -R'.\n\
+Using this option to access a repository which some users write to may\n\
+cause intermittent sandbox corruption.");
+ }
+
+ /* Calculate the cvs global session ID */
+
+ {
+ char buf[COMMITID_RAW_SIZE] = { 0, };
+ char out[COMMITID_RAW_SIZE * 2];
+ ssize_t len = 0;
+ time_t rightnow = time (NULL);
+ char *startrand = buf + sizeof (time_t);
+ unsigned char *p = (unsigned char *) startrand;
+ size_t randbytes = RANDOM_BYTES;
+ int flags = O_RDONLY;
+ int fd;
+#ifdef O_NOCTTY
+ flags |= O_NOCTTY;
+#endif
+ if (rightnow != (time_t)-1)
+ while (rightnow > 0) {
+ *--p = rightnow % (UCHAR_MAX + 1);
+ rightnow /= UCHAR_MAX + 1;
+ }
+ else {
+ /* try to use more random data */
+ randbytes = COMMITID_RAW_SIZE;
+ startrand = buf;
+ }
+ fd = open ("/dev/urandom", flags);
+ if (fd >= 0) {
+ len = read (fd, startrand, randbytes);
+ close (fd);
+ }
+ if (len <= 0) {
+ /* no random data was available so use pid */
+ long int pid = (long int)getpid ();
+ p = (unsigned char *) (startrand + sizeof (pid));
+ while (pid > 0) {
+ *--p = pid % (UCHAR_MAX + 1);
+ pid /= UCHAR_MAX + 1;
+ }
+ }
+ convert(buf, out);
+ global_session_id = strdup (out);
+ }
+
+
+ TRACE (TRACE_FUNCTION, "main: Session ID is %s", global_session_id);
+
+ /* Look up the command name. */
+
+ cvs_cmd_name = argv[0];
+ for (cm = cmds; cm->fullname; cm++)
+ {
+ if (cm->nick1 && !strcmp (cvs_cmd_name, cm->nick1))
+ break;
+ if (cm->nick2 && !strcmp (cvs_cmd_name, cm->nick2))
+ break;
+ if (!strcmp (cvs_cmd_name, cm->fullname))
+ break;
+ }
+
+ if (!cm->fullname)
+ {
+ fprintf (stderr, "Unknown command: `%s'\n\n", cvs_cmd_name);
+ usage (cmd_usage);
+ }
+ else
+ cvs_cmd_name = cm->fullname; /* Global pointer for later use */
+
+ if (help)
+ {
+ argc = -1; /* some functions only check for this */
+ err = (*(cm->func)) (argc, argv);
+ }
+ else
+ {
+ /* The user didn't ask for help, so go ahead and authenticate,
+ set up CVSROOT, and the rest of it. */
+
+ short int lock_cleanup_setup = 0;
+
+ /* The UMASK environment variable isn't handled with the
+ others above, since we don't want to signal errors if the
+ user has asked for help. This won't work if somebody adds
+ a command-line flag to set the umask, since we'll have to
+ parse it before we get here. */
+
+ if ((cp = getenv (CVSUMASK_ENV)) != NULL)
+ {
+ /* FIXME: Should be accepting symbolic as well as numeric mask. */
+ cvsumask = strtol (cp, &end, 8) & 0777;
+ if (*end != '\0')
+ error (1, errno, "invalid umask value in %s (%s)",
+ CVSUMASK_ENV, cp);
+ }
+
+ /* HOSTNAME & SERVER_HOSTNAME need to be set before they are
+ * potentially used in gserver_authenticate_connection() (called from
+ * pserver_authenticate_connection, below).
+ */
+ hostname = xgethostname ();
+ if (!hostname)
+ {
+ error (0, errno,
+ "xgethostname () returned NULL, using \"localhost\"");
+ hostname = xstrdup ("localhost");
+ }
+
+ /* Keep track of this separately since the client can change
+ * HOSTNAME on the server.
+ */
+ server_hostname = xstrdup (hostname);
+
+#ifdef SERVER_SUPPORT
+
+# ifdef HAVE_KERBEROS
+ /* If we are invoked with a single argument "kserver", then we are
+ running as Kerberos server as root. Do the authentication as
+ the very first thing, to minimize the amount of time we are
+ running as root. */
+ if (strcmp (cvs_cmd_name, "kserver") == 0)
+ {
+ kserver_authenticate_connection ();
+
+ /* Pretend we were invoked as a plain server. */
+ cvs_cmd_name = "server";
+ }
+# endif /* HAVE_KERBEROS */
+
+# if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
+ if (strcmp (cvs_cmd_name, "pserver") == 0)
+ {
+ /* The reason that --allow-root is not a command option
+ is mainly that it seems easier to make it a global option. */
+
+ /* Gets username and password from client, authenticates, then
+ switches to run as that user and sends an ACK back to the
+ client. */
+ pserver_authenticate_connection ();
+
+ /* Pretend we were invoked as a plain server. */
+ cvs_cmd_name = "server";
+ }
+# endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
+#endif /* SERVER_SUPPORT */
+
+ server_active = strcmp (cvs_cmd_name, "server") == 0;
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* This is only used for writing into the history file. For
+ remote connections, it might be nice to have hostname
+ and/or remote path, on the other hand I'm not sure whether
+ it is worth the trouble. */
+ CurDir = xstrdup ("<remote>");
+ cleanup_register (server_cleanup);
+ }
+ else
+#endif
+ {
+ cleanup_register (close_stdout);
+ CurDir = xgetcwd ();
+ if (CurDir == NULL)
+ error (1, errno, "cannot get working directory");
+ }
+
+ {
+ char *val;
+ /* XXX pid < 10^32 */
+ val = Xasprintf ("%ld", (long) getpid ());
+ setenv (CVS_PID_ENV, val, 1);
+ free (val);
+ }
+
+ /* make sure we clean up on error */
+ signals_register (main_cleanup);
+
+#ifdef KLUDGE_FOR_WNT_TESTSUITE
+ /* Probably the need for this will go away at some point once
+ we call fflush enough places (e.g. fflush (stdout) in
+ cvs_outerr). */
+ (void) setvbuf (stdout, NULL, _IONBF, 0);
+ (void) setvbuf (stderr, NULL, _IONBF, 0);
+#endif /* KLUDGE_FOR_WNT_TESTSUITE */
+
+ if (use_cvsrc)
+ read_cvsrc (&argc, &argv, cvs_cmd_name);
+
+ /* Fiddling with CVSROOT doesn't make sense if we're running
+ * in server mode, since the client will send the repository
+ * directory after the connection is made.
+ */
+ if (!server_active)
+ {
+ /* First check if a root was set via the command line. */
+ if (CVSroot_cmdline)
+ {
+ if (!(CVSroot_parsed = parse_cvsroot (CVSroot_cmdline)))
+ error (1, 0, "Bad CVSROOT: `%s'.", CVSroot_cmdline);
+ }
+
+ /* See if we are able to find a 'better' value for CVSroot
+ * in the CVSADM_ROOT directory.
+ *
+ * "cvs import" shouldn't check CVS/Root; in general it
+ * ignores CVS directories and CVS/Root is likely to
+ * specify a different repository than the one we are
+ * importing to, but if this is not import and no root was
+ * specified on the command line, set the root from the
+ * CVS/Root file.
+ */
+ if (!CVSroot_parsed
+ && !(cm->attr & CVS_CMD_IGNORE_ADMROOT)
+ )
+ CVSroot_parsed = Name_Root (NULL, NULL);
+
+ /* Now, if there is no root on the command line and we didn't find
+ * one in a file, set it via the $CVSROOT env var.
+ */
+ if (!CVSroot_parsed)
+ {
+ char *tmp = getenv (CVSROOT_ENV);
+ if (tmp)
+ {
+ if (!(CVSroot_parsed = parse_cvsroot (tmp)))
+ error (1, 0, "Bad CVSROOT: `%s'.", tmp);
+ cvsroot_update_env = false;
+ }
+ }
+
+#ifdef CVSROOT_DFLT
+ if (!CVSroot_parsed)
+ {
+ if (!(CVSroot_parsed = parse_cvsroot (CVSROOT_DFLT)))
+ error (1, 0, "Bad CVSROOT: `%s'.", CVSROOT_DFLT);
+ }
+#endif /* CVSROOT_DFLT */
+
+ /* Now we've reconciled CVSROOT from the command line, the
+ CVS/Root file, and the environment variable. Do the
+ last sanity checks on the variable. */
+ if (!CVSroot_parsed)
+ {
+ error (0, 0,
+ "No CVSROOT specified! Please use the `-d' option");
+ error (1, 0,
+ "or set the %s environment variable.", CVSROOT_ENV);
+ }
+ }
+
+ /* Here begins the big loop over unique cvsroot values. We
+ need to call do_recursion once for each unique value found
+ in CVS/Root. Prime the list with the current value. */
+
+ /* Create the list. */
+ assert (root_directories == NULL);
+ root_directories = getlist ();
+
+ /* Prime it. */
+ if (CVSroot_parsed)
+ {
+ Node *n;
+ n = getnode ();
+ n->type = NT_UNKNOWN;
+ n->key = xstrdup (CVSroot_parsed->original);
+ n->data = CVSroot_parsed;
+
+ if (addnode (root_directories, n))
+ error (1, 0, "cannot add initial CVSROOT %s", n->key);
+ }
+
+ assert (current_parsed_root == NULL);
+
+ /* If we're running the server, we want to execute this main
+ loop once and only once (we won't be serving multiple roots
+ from this connection, so there's no need to do it more than
+ once). To get out of the loop, we perform a "break" at the
+ end of things. */
+
+ while (server_active ||
+ walklist (root_directories, set_root_directory, NULL))
+ {
+ /* Fiddling with CVSROOT doesn't make sense if we're running
+ in server mode, since the client will send the repository
+ directory after the connection is made. */
+
+ if (!server_active)
+ {
+ /* Now we're 100% sure that we have a valid CVSROOT
+ variable. Parse it to see if we're supposed to do
+ remote accesses or use a special access method. */
+
+ TRACE (TRACE_FUNCTION,
+ "main loop with CVSROOT=%s",
+ current_parsed_root ? current_parsed_root->directory
+ : "(null)");
+
+ /*
+ * Check to see if the repository exists.
+ */
+ if (!current_parsed_root->isremote)
+ {
+ char *path;
+ int save_errno;
+
+ path = Xasprintf ("%s/%s", current_parsed_root->directory,
+ CVSROOTADM);
+ if (!isaccessible (path, R_OK | X_OK))
+ {
+ save_errno = errno;
+ /* If this is "cvs init", the root need not exist yet.
+ */
+ if (strcmp (cvs_cmd_name, "init"))
+ error (1, save_errno, "%s", path);
+ }
+ free (path);
+ }
+
+ /* Update the CVSROOT environment variable. */
+ if (cvsroot_update_env)
+ setenv (CVSROOT_ENV, current_parsed_root->original, 1);
+ }
+
+ /* Parse the CVSROOT/config file, but only for local. For the
+ server, we parse it after we know $CVSROOT. For the
+ client, it doesn't get parsed at all, obviously. The
+ presence of the parse_config call here is not meant to
+ predetermine whether CVSROOT/config overrides things from
+ read_cvsrc and other such places or vice versa. That sort
+ of thing probably needs more thought. */
+ if (!server_active && !current_parsed_root->isremote)
+ {
+ /* If there was an error parsing the config file, parse_config
+ already printed an error. We keep going. Why? Because
+ if we didn't, then there would be no way to check in a new
+ CVSROOT/config file to fix the broken one! */
+ if (config) free_config (config);
+ config = parse_config (current_parsed_root->directory, NULL);
+
+ /* Can set TMPDIR in the environment if necessary now, since
+ * if it was set in config, we now know it.
+ */
+ push_env_temp_dir ();
+ }
+
+#ifdef CLIENT_SUPPORT
+ /* Need to check for current_parsed_root != NULL here since
+ * we could still be in server mode before the server function
+ * gets called below and sets the root
+ */
+ if (current_parsed_root != NULL && current_parsed_root->isremote)
+ {
+ /* Create a new list for directory names that we've
+ sent to the server. */
+ if (dirs_sent_to_server != NULL)
+ dellist (&dirs_sent_to_server);
+ dirs_sent_to_server = getlist ();
+ }
+#endif
+
+ if (
+#ifdef SERVER_SUPPORT
+ /* Don't worry about lock_cleanup_setup when the server is
+ * active since we can only go through this loop once in that
+ * case anyhow.
+ */
+ server_active ||
+#endif
+ (
+#ifdef CLIENT_SUPPORT
+ !current_parsed_root->isremote &&
+#endif
+ !lock_cleanup_setup))
+ {
+ /* Set up to clean up any locks we might create on exit. */
+ cleanup_register (Lock_Cleanup);
+ lock_cleanup_setup = 1;
+ }
+
+ /* Call our worker function. */
+ err = (*(cm->func)) (argc, argv);
+
+ /* Mark this root directory as done. When the server is
+ active, our list will be empty -- don't try and
+ remove it from the list. */
+
+ if (!server_active)
+ {
+ Node *n = findnode (root_directories,
+ original_parsed_root->original);
+ assert (n != NULL);
+ assert (n->data != NULL);
+ n->data = NULL;
+ current_parsed_root = NULL;
+ }
+
+ if (server_active)
+ break;
+ } /* end of loop for cvsroot values */
+
+ dellist (&root_directories);
+ } /* end of stuff that gets done if the user DOESN'T ask for help */
+
+ root_allow_free ();
+
+ /* This is exit rather than return because apparently that keeps
+ some tools which check for memory leaks happier. */
+ exit (err ? EXIT_FAILURE : 0);
+ /* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy. */
+ return 0;
+}
+
+
+
+char *
+Make_Date (const char *rawdate)
+{
+ struct timespec t;
+
+ if (!get_date (&t, rawdate, NULL))
+ error (1, 0, "Can't parse date/time: `%s'", rawdate);
+
+ /* Truncate nanoseconds. */
+ return date_from_time_t (t.tv_sec);
+}
+
+
+
+/* Parse a string of the form TAG[:DATE], where TAG could be the empty string.
+ *
+ * INPUTS
+ * input The string to be parsed.
+ *
+ * OUTPUTS
+ * tag The tag found, if any. If TAG is the empty string, then leave
+ * this value unchanged.
+ * date The date found, if any. If DATE is the empty string or is
+ * missing, leave this value unchanged.
+ *
+ * NOTES
+ * If either TAG or DATE is replaced for output, the previous value is freed.
+ *
+ * ERRORS
+ * If either TAG or DATE cannot be parsed, then this function will exit with
+ * a fatal error message.
+ *
+ * RETURNS
+ * Nothing.
+ */
+void
+parse_tagdate (char **tag, char **date, const char *input)
+{
+ char *p;
+
+ TRACE (TRACE_FUNCTION, "parse_tagdate (%s, %s, %s)",
+ *tag ? *tag : "(null)", *date ? *date : "(null)",
+ input);
+
+ if ((p = strchr (input, ':')))
+ {
+ /* Parse the tag. */
+ if (p - input)
+ {
+ /* The tag has > 0 length. */
+ if (*tag) free (*tag);
+ *tag = xmalloc (p - input + 1);
+ strncpy (*tag, input, p - input);
+ (*tag)[p - input] = '\0';
+ }
+
+ /* Parse the date. */
+ if (*++p)
+ {
+ if (*date) free (*date);
+ *date = Make_Date (p);
+ }
+ }
+ else if (strlen (input))
+ {
+ /* The tag has > 0 length. */
+ if (*tag) free (*tag);
+ *tag = xstrdup (input);
+ }
+
+ TRACE (TRACE_DATA, "parse_tagdate: got tag = `%s', date = `%s'",
+ *tag ? *tag : "(null)", *date ? *date : "(null)");
+}
+
+
+
+/* Convert a time_t to an RCS format date. This is mainly for the
+ use of "cvs history", because the CVSROOT/history file contains
+ time_t format dates; most parts of CVS will want to avoid using
+ time_t's directly, and instead use RCS_datecmp, Make_Date, &c.
+ Assuming that the time_t is in GMT (as it generally should be),
+ then the result will be in GMT too.
+
+ Returns a newly malloc'd string. */
+
+char *
+date_from_time_t (time_t unixtime)
+{
+ struct tm *ftm;
+ char date[MAXDATELEN];
+ char *ret;
+
+ ftm = gmtime (&unixtime);
+ if (ftm == NULL)
+ /* This is a system, like VMS, where the system clock is in local
+ time. Hopefully using localtime here matches the "zero timezone"
+ hack I added to get_date (get_date of course being the relevant
+ issue for Make_Date, and for history.c too I think). */
+ ftm = localtime (&unixtime);
+
+ (void) sprintf (date, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+ ret = xstrdup (date);
+ return ret;
+}
+
+
+
+/* Convert a date to RFC822/1123 format. This is used in contexts like
+ dates to send in the protocol; it should not vary based on locale or
+ other such conventions for users. We should have another routine which
+ does that kind of thing.
+
+ The SOURCE date is in our internal RCS format. DEST should point to
+ storage managed by the caller, at least MAXDATELEN characters. */
+void
+date_to_internet (char *dest, const char *source)
+{
+ struct tm date;
+
+ date_to_tm (&date, source);
+ tm_to_internet (dest, &date);
+}
+
+
+
+void
+date_to_tm (struct tm *dest, const char *source)
+{
+ if (sscanf (source, SDATEFORM,
+ &dest->tm_year, &dest->tm_mon, &dest->tm_mday,
+ &dest->tm_hour, &dest->tm_min, &dest->tm_sec)
+ != 6)
+ /* Is there a better way to handle errors here? I made this
+ non-fatal in case we are called from the code which can't
+ deal with fatal errors. */
+ error (0, 0, "internal error: bad date %s", source);
+
+ if (dest->tm_year > 100)
+ dest->tm_year -= 1900;
+
+ dest->tm_mon -= 1;
+}
+
+
+
+/* Convert a date to RFC822/1123 format. This is used in contexts like
+ dates to send in the protocol; it should not vary based on locale or
+ other such conventions for users. We should have another routine which
+ does that kind of thing.
+
+ The SOURCE date is a pointer to a struct tm. DEST should point to
+ storage managed by the caller, at least MAXDATELEN characters. */
+void
+tm_to_internet (char *dest, const struct tm *source)
+{
+ /* Just to reiterate, these strings are from RFC822 and do not vary
+ according to locale. */
+ static const char *const month_names[] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday,
+ source->tm_mon < 0 || source->tm_mon > 11
+ ? "???" : month_names[source->tm_mon],
+ source->tm_year + 1900, source->tm_hour, source->tm_min,
+ source->tm_sec);
+}
+
+
+
+/*
+ * Format a date for the current locale.
+ *
+ * INPUT
+ * UNIXTIME The UNIX seconds since the epoch.
+ *
+ * RETURNS
+ * If my_strftime() encounters an error, this function can return NULL.
+ *
+ * Otherwise, returns a date string in ISO8601 format, e.g.:
+ *
+ * 2004-04-29 13:24:22 -0700
+ *
+ * It is the responsibility of the caller to return of this string.
+ */
+static char *
+format_time_t (time_t unixtime)
+{
+ static char buf[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")];
+ /* Convert to a time in the local time zone. */
+ struct tm ltm = *(localtime (&unixtime));
+
+ if (!my_strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S %z", &ltm, 0, 0))
+ return NULL;
+
+ return xstrdup (buf);
+}
+
+
+
+/* Like format_time_t(), but return time in UTC.
+ */
+char *
+gmformat_time_t (time_t unixtime)
+{
+ static char buf[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")];
+ /* Convert to a time in the local time zone. */
+ struct tm ltm = *(gmtime (&unixtime));
+
+ if (!my_strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S %z", &ltm, 0, 0))
+ return NULL;
+
+ return xstrdup (buf);
+}
+
+
+
+/* Format a date in the local timezone using format_time_t() given a date from
+ * an arbitrary timezone in a string.
+ *
+ * INPUT
+ * DATESTR A string that looks like anything get_date() can parse, e.g.:
+ *
+ * 2004-04-29 20:24:22
+ *
+ * ERRORS
+ * As get_date() & format_time_t(). Prints a warning if either provide
+ * error return values. See RETURNS.
+ *
+ * RETURNS
+ * A freshly allocated string that is a copy of the input string if either
+ * get_date() or format_time_t() encounter an error and as format_time_t()
+ * otherwise.
+ */
+char *
+format_date_alloc (char *datestr)
+{
+ struct timespec t;
+ char *buf;
+
+ TRACE (TRACE_FUNCTION, "format_date (%s)", datestr);
+
+ /* Convert the date string to seconds since the epoch. */
+ if (!get_date (&t, datestr, NULL))
+ {
+ error (0, 0, "Can't parse date/time: `%s'.", datestr);
+ goto as_is;
+ }
+
+ /* Get the time into a string, truncating any nanoseconds returned by
+ * getdate.
+ */
+ if ((buf = format_time_t (t.tv_sec)) == NULL)
+ {
+ error (0, 0, "Unable to reformat date `%s'.", datestr);
+ goto as_is;
+ }
+
+ return buf;
+
+ as_is:
+ return xstrdup (datestr);
+}
+
+
+
+void
+usage (register const char *const *cpp)
+{
+ (void) fprintf (stderr, *cpp++, program_name, cvs_cmd_name);
+ for (; *cpp; cpp++)
+ (void) fprintf (stderr, *cpp);
+ exit (EXIT_FAILURE);
+}
+
+/* vim:tabstop=8:shiftwidth=4
+ */
diff --git a/src/mkmodules.c b/src/mkmodules.c
new file mode 100644
index 0000000..e881e1e
--- /dev/null
+++ b/src/mkmodules.c
@@ -0,0 +1,1284 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS kit. */
+
+#include "cvs.h"
+#include "getline.h"
+#include "history.h"
+#include "save-cwd.h"
+
+#ifndef DBLKSIZ
+#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */
+#endif
+
+static int checkout_file (char *file, char *temp);
+static char *make_tempfile (void);
+static void rename_rcsfile (char *temp, char *real);
+
+#ifndef MY_NDBM
+static void rename_dbmfile (char *temp);
+static void write_dbmfile (char *temp);
+#endif /* !MY_NDBM */
+
+/* Structure which describes an administrative file. */
+struct admin_file {
+ /* Name of the file, within the CVSROOT directory. */
+ char *filename;
+
+ /* This is a one line description of what the file is for. It is not
+ currently used, although one wonders whether it should be, somehow.
+ If NULL, then don't process this file in mkmodules (FIXME?: a bit of
+ a kludge; probably should replace this with a flags field). */
+ char *errormsg;
+
+ /* Contents which the file should have in a new repository. To avoid
+ problems with brain-dead compilers which choke on long string constants,
+ this is a pointer to an array of char * terminated by NULL--each of
+ the strings is concatenated.
+
+ If this field is NULL, the file is not created in a new
+ repository, but it can be added with "cvs add" (just as if one
+ had created the repository with a version of CVS which didn't
+ know about the file) and the checked-out copy will be updated
+ without having to add it to checkoutlist. */
+ const char * const *contents;
+};
+
+static const char *const loginfo_contents[] = {
+ "# The \"loginfo\" file controls where \"cvs commit\" log information is\n",
+ "# sent. The first entry on a line is a regular expression which must\n",
+ "# match the directory that the change is being made to, relative to the\n",
+ "# $CVSROOT. If a match is found, then the remainder of the line is a\n",
+ "# filter program that should expect log information on its standard input.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name ALL appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or DEFAULT.\n",
+ "#\n",
+ "# If any format strings are present in the filter, they will be replaced\n",
+ "# as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "# %{sVv} = attribute list = file name, old version number (pre-checkin),\n",
+ "# new version number (post-checkin). When either old or new revision\n",
+ "# is unknown, doesn't exist, or isn't applicable, the string \"NONE\"\n",
+ "# will be placed on the command line instead.\n",
+ "#\n",
+ "# Note that %{sVv} is a list operator and not all elements are necessary.\n",
+ "# Thus %{sv} is a legal format string, but will only be replaced with\n",
+ "# file name and new revision.\n",
+ "# It also generates multiple arguments for each file being operated upon.\n",
+ "# That is, if two files, file1 & file2, are being commited from 1.1 to\n",
+ "# version 1.1.2.1 and from 1.1.2.2 to 1.1.2.3, respectively, %{sVv} will\n",
+ "# generate the following six arguments in this order:\n",
+ "# file1, 1.1, 1.1.2.1, file2, 1.1.2.2, 1.1.2.3.\n",
+ "#\n",
+ "# For example:\n",
+ "#DEFAULT (echo \"\"; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
+ "# or\n",
+ "#DEFAULT (echo \"\"; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
+ NULL
+};
+
+static const char *const rcsinfo_contents[] = {
+ "# The \"rcsinfo\" file is used to control templates with which the editor\n",
+ "# is invoked on commit and import.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being made to, relative to the\n",
+ "# $CVSROOT. For the first match that is found, then the remainder of the\n",
+ "# line is the name of the file that contains the template.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+
+
+static const char *const verifymsg_contents[] = {
+ "# The \"verifymsg\" file is used to allow verification of logging\n",
+ "# information. It works best when a template (as specified in the\n",
+ "# rcsinfo file) is provided for the logging procedure. Given a\n",
+ "# template with locations for, a bug-id number, a list of people who\n",
+ "# reviewed the code before it can be checked in, and an external\n",
+ "# process to catalog the differences that were code reviewed, the\n",
+ "# following test can be applied to the code:\n",
+ "#\n",
+ "# Making sure that the entered bug-id number is correct.\n",
+ "# Validating that the code that was reviewed is indeed the code being\n",
+ "# checked in (using the bug-id number or a seperate review\n",
+ "# number to identify this particular code set.).\n",
+ "#\n",
+ "# If any of the above test failed, then the commit would be aborted.\n",
+ "#\n",
+ "# Format strings present in the filter will be replaced as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "# %l = name of log file to be verified.\n",
+ "#\n",
+ "# If no format strings are present in the filter, a default \" %l\" will\n",
+ "# be appended to the filter, but this usage is deprecated.\n",
+ "#\n",
+ "# Actions such as mailing a copy of the report to each reviewer are\n",
+ "# better handled by an entry in the loginfo file.\n",
+ "#\n",
+ "# One thing that should be noted is the the ALL keyword is not\n",
+ "# supported. There can be only one entry that matches a given\n",
+ "# repository.\n",
+ NULL
+};
+
+static const char *const commitinfo_contents[] = {
+ "# The \"commitinfo\" file is used to control pre-commit checks.\n",
+ "# The filter on the right is invoked with the repository and a list \n",
+ "# of files to check. A non-zero exit of the filter program will \n",
+ "# cause the commit to be aborted.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# Format strings present in the filter will be replaced as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "# %{s} = file name, file name, ...\n",
+ "#\n",
+ "# If no format strings are present in the filter string, a default of\n",
+ "# \" %r %s\" will be appended to the filter string, but this usage is\n",
+ "# deprecated.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const taginfo_contents[] = {
+ "# The \"taginfo\" file is used to control pre-tag checks.\n",
+ "# The filter on the right is invoked with the following arguments\n",
+ "# if no format strings are present:\n",
+ "#\n",
+ "# $1 -- tagname\n",
+ "# $2 -- operation \"add\" for tag, \"mov\" for tag -F, and \"del\" for tag -d\n",
+ "# $3 -- tagtype \"?\" on delete, \"T\" for branch, \"N\" for static\n",
+ "# $4 -- repository\n",
+ "# $5-> file revision [file revision ...]\n",
+ "#\n",
+ "# If any format strings are present in the filter, they will be replaced\n",
+ "# as follows:\n",
+ "# %b = branch mode = \"?\" (delete ops - unknown) | \"T\" (branch)\n",
+ "# | \"N\" (not branch)\n",
+ "# %o = operation = \"add\" | \"mov\" | \"del\"\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "# %t = tagname\n",
+ "# %{sVv} = attribute list = file name, old version tag will be deleted\n",
+ "# from, new version tag will be added to (or deleted from, but\n",
+ "# this feature is deprecated. When either old or new revision is\n",
+ "# unknown, doesn't exist, or isn't applicable, the string \"NONE\"\n",
+ "# will be placed on the command line.\n",
+ "#\n",
+ "# Note that %{sVv} is a list operator and not all elements are necessary.\n",
+ "# Thus %{sV} is a legal format string, but will only be replaced with file\n",
+ "# name and old revision. it also generates multiple arguments for each file\n",
+ "# being operated upon. i.e. if two files, file1 & file2, are having a tag\n",
+ "# moved from version 1.1 to version 1.1.2.9, %{sVv} will generate the\n",
+ "# following six arguments in this order:\n",
+ "# file1, 1.1, 1.1.2.9, file2, 1.1, 1.1.2.9.\n",
+ "#\n",
+ "# A non-zero exit of the filter program will cause the tag to be aborted.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const preproxy_contents[] = {
+ "# The \"preproxy\" file is called form the secondary server as soon as\n",
+ "# the secondary server determines that it will be proxying a write\n",
+ "# command to a primary server and immediately before it opens a\n",
+ "# connection to the primary server. This script might, for example, be\n",
+ "# used to launch a dial up or VPN connection to the primary server's\n",
+ "# network.\n",
+ "#\n",
+ "# If any format strings are present in the filter, they will be replaced\n",
+ "# as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository (currently always \".\")\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const postadmin_contents[] = {
+ "# The \"postadmin\" file is called after the \"admin\" command finishes\n",
+ "# processing a directory.\n",
+ "#\n",
+ "# If any format strings are present in the filter, they will be replaced\n",
+ "# as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const postproxy_contents[] = {
+ "# The \"postproxy\" file is called from a secondary server as soon as\n",
+ "# the secondary server closes its connection to the primary server.\n",
+ "# This script might, for example, be used to shut down a dial up\n",
+ "# or VPN connection to the primary server's network.\n",
+ "#\n",
+ "# If any format strings are present in the filter, they will be replaced\n",
+ "# as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository (currently always \".\")\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const posttag_contents[] = {
+ "# The \"posttag\" file is called after the \"tag\" command finishes\n",
+ "# processing a directory.\n",
+ "#\n",
+ "# If any format strings are present in the filter, they will be replaced\n",
+ "# as follows:\n",
+ "# %b = branch mode = \"?\" (delete ops - unknown) | \"T\" (branch)\n",
+ "# | \"N\" (not branch)\n",
+ "# %o = operation = \"add\" | \"mov\" | \"del\"\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "# %t = tagname\n",
+ "# %{sVv} = attribute list = file name, old version tag will be deleted\n",
+ "# from, new version tag will be added to (or deleted from, but\n",
+ "# this feature is deprecated. When either old or new revision is\n",
+ "# unknown, doesn't exist, or isn't applicable, the string \"NONE\"\n",
+ "# will be placed on the command line.\n",
+ "#\n",
+ "# Note that %{sVv} is a list operator and not all elements are necessary.\n",
+ "# Thus %{sV} is a legal format string, but will only be replaced with file\n",
+ "# name and old revision. it also generates multiple arguments for each file\n",
+ "# being operated upon. i.e. if two files, file1 & file2, are having a tag\n",
+ "# moved from version 1.1 to version 1.1.2.9, %{sVv} will generate the\n",
+ "# following six arguments in this order:\n",
+ "# file1, 1.1, 1.1.2.9, file2, 1.1, 1.1.2.9.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const postwatch_contents[] = {
+ "# The \"postwatch\" file is called after any command finishes writing new\n",
+ "# file attibute (watch/edit) information in a directory.\n",
+ "#\n",
+ "# If any format strings are present in the filter, they will be replaced\n",
+ "# as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const checkoutlist_contents[] = {
+ "# The \"checkoutlist\" file is used to support additional version controlled\n",
+ "# administrative files in $CVSROOT/CVSROOT, such as template files.\n",
+ "#\n",
+ "# The first entry on a line is a filename which will be checked out from\n",
+ "# the corresponding RCS file in the $CVSROOT/CVSROOT directory.\n",
+ "# The remainder of the line is an error message to use if the file cannot\n",
+ "# be checked out.\n",
+ "#\n",
+ "# File format:\n",
+ "#\n",
+ "# [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>\n",
+ "#\n",
+ "# comment lines begin with '#'\n",
+ NULL
+};
+
+static const char *const cvswrappers_contents[] = {
+ "# This file affects handling of files based on their names.\n",
+ "#\n",
+#if 0 /* see comments in wrap_add in wrapper.c */
+ "# The -t/-f options allow one to treat directories of files\n",
+ "# as a single file, or to transform a file in other ways on\n",
+ "# its way in and out of CVS.\n",
+ "#\n",
+#endif
+ "# The -m option specifies whether CVS attempts to merge files.\n",
+ "#\n",
+ "# The -k option specifies keyword expansion (e.g. -kb for binary).\n",
+ "#\n",
+ "# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)\n",
+ "#\n",
+ "# wildcard [option value][option value]...\n",
+ "#\n",
+ "# where option is one of\n",
+ "# -f from cvs filter value: path to filter\n",
+ "# -t to cvs filter value: path to filter\n",
+ "# -m update methodology value: MERGE or COPY\n",
+ "# -k expansion mode value: b, o, kkv, &c\n",
+ "#\n",
+ "# and value is a single-quote delimited value.\n",
+ "# For example:\n",
+ "#*.gif -k 'b'\n",
+ NULL
+};
+
+static const char *const notify_contents[] = {
+ "# The \"notify\" file controls where notifications from watches set by\n",
+ "# \"cvs watch add\" or \"cvs edit\" are sent. The first entry on a line is\n",
+ "# a regular expression which is tested against the directory that the\n",
+ "# change is being made to, relative to the $CVSROOT. If it matches,\n",
+ "# then the remainder of the line is a filter program that should contain\n",
+ "# one occurrence of %s for the user to notify, and information on its\n",
+ "# standard input.\n",
+ "#\n",
+ "# \"ALL\" or \"DEFAULT\" can be used in place of the regular expression.\n",
+ "#\n",
+ "# format strings are replaceed as follows:\n",
+ "# %c = canonical name of the command being executed\n",
+#ifdef PROXY_SUPPORT
+ "# %R = the name of the referrer, if any, otherwise the value NONE\n",
+#endif
+ "# %p = path relative to repository\n",
+ "# %r = repository (path portion of $CVSROOT)\n",
+ "# %s = user to notify\n",
+ "#\n",
+ "# For example:\n",
+ "#ALL (echo Committed to %r/%p; cat) |mail %s -s \"CVS notification\"\n",
+ NULL
+};
+
+static const char *const modules_contents[] = {
+ "# Three different line formats are valid:\n",
+ "# key -a aliases...\n",
+ "# key [options] directory\n",
+ "# key [options] directory files...\n",
+ "#\n",
+ "# Where \"options\" are composed of:\n",
+ "# -i prog Run \"prog\" on \"cvs commit\" from top-level of module.\n",
+ "# -o prog Run \"prog\" on \"cvs checkout\" of module.\n",
+ "# -e prog Run \"prog\" on \"cvs export\" of module.\n",
+ "# -t prog Run \"prog\" on \"cvs rtag\" of module.\n",
+ "# -u prog Run \"prog\" on \"cvs update\" of module.\n",
+ "# -d dir Place module in directory \"dir\" instead of module name.\n",
+ "# -l Top-level directory only -- do not recurse.\n",
+ "#\n",
+ "# NOTE: If you change any of the \"Run\" options above, you'll have to\n",
+ "# release and re-checkout any working directories of these modules.\n",
+ "#\n",
+ "# And \"directory\" is a path to a directory relative to $CVSROOT.\n",
+ "#\n",
+ "# The \"-a\" option specifies an alias. An alias is interpreted as if\n",
+ "# everything on the right of the \"-a\" had been typed on the command line.\n",
+ "#\n",
+ "# You can encode a module within a module by using the special '&'\n",
+ "# character to interpose another module into the current module. This\n",
+ "# can be useful for creating a module that consists of many directories\n",
+ "# spread out over the entire source repository.\n",
+ NULL
+};
+
+static const char *const config_contents[] = {
+ "# Set `SystemAuth' to `no' if pserver shouldn't check system users/passwords.\n",
+ "#SystemAuth=no\n",
+ "\n",
+ "# Set `LocalKeyword' to specify a local alias for a standard keyword.\n",
+ "#LocalKeyword=MYCVS=CVSHeader\n",
+ "\n",
+ "# Set `KeywordExpand' to `i' followed by a list of keywords to expand or\n",
+ "# `e' followed by a list of keywords to not expand.\n"
+ "#KeywordExpand=iMYCVS,Name,Date\n",
+ "#KeywordExpand=eCVSHeader\n",
+ "\n",
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ "# Set `PreservePermissions' to `yes' to save file status information\n",
+ "# in the repository.\n",
+ "#PreservePermissions=no\n",
+ "\n",
+#endif
+ "# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top\n",
+ "# level of the new working directory when using the `cvs checkout'\n",
+ "# command.\n",
+ "#TopLevelAdmin=no\n",
+ "\n",
+ "# Put CVS lock files in this directory rather than directly in the repository.\n",
+ "#LockDir=/var/lock/cvs\n",
+ "\n",
+ "# Set `LogHistory' to `all' or `" ALL_HISTORY_REC_TYPES "' to log all transactions to the\n",
+ "# history file, or a subset as needed (ie `TMAR' logs all write operations)\n",
+ "#LogHistory=" ALL_HISTORY_REC_TYPES "\n",
+ "\n",
+ "# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg\n",
+ "# script to change the log message. Set it to `stat' to force CVS to verify\n",
+ "# that the file has changed before reading it (this can take up to an extra\n",
+ "# second per directory being committed, so it is not recommended for large\n",
+ "# repositories. Set it to `never' (the previous CVS behavior) to prevent\n",
+ "# verifymsg scripts from changing the log message.\n",
+ "#RereadLogAfterVerify=always\n",
+ "\n",
+ "# Set `UserAdminOptions' to the list of `cvs admin' commands (options)\n",
+ "# that users not in the `cvsadmin' group are allowed to run. This\n",
+ "# defaults to `k', or only allowing the changing of the default\n",
+ "# keyword expansion mode for files for users not in the `cvsadmin' group.\n",
+ "# This value is ignored if the `cvsadmin' group does not exist.\n",
+ "#\n",
+ "# The following string would enable all `cvs admin' commands for all\n",
+ "# users:\n",
+ "#UserAdminOptions=aAbceIklLmnNostuU\n",
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ "\n",
+ "# Set `UseNewInfoFmtStrings' to `no' if you must support a legacy system by\n",
+ "# enabling the deprecated old style info file command line format strings.\n",
+ "# Be warned that these strings could be disabled in any new version of CVS.\n",
+ "UseNewInfoFmtStrings=yes\n",
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ "\n",
+ "# Set `ImportNewFilesToVendorBranchOnly' to `yes' if you wish to force\n",
+ "# every `cvs import' command to behave as if the `-X' flag was\n",
+ "# specified.\n",
+ "#ImportNewFilesToVendorBranchOnly=no\n",
+#ifdef PROXY_SUPPORT
+ "\n",
+ "# Set `PrimaryServer' to the CVSROOT to the primary, or write, server when\n",
+ "# establishing one or more read-only mirrors which serve as proxies for\n",
+ "# the write server in write mode or redirect the client to the primary for\n",
+ "# write requests.\n",
+ "#\n",
+ "# For example:\n",
+ "#\n",
+ "# PrimaryServer=:fork:localhost/cvsroot\n",
+ "\n",
+ "# Set `MaxProxyBufferSize' to the the maximum allowable secondary\n",
+ "# buffer memory cache size before the buffer begins being stored to disk, in\n",
+ "# bytes. Must be a positive integer but may end in `k', `M', `G', or `T' (for\n",
+ "# kiilo, mega, giga, & tera, respectively). If an otherwise valid number you\n",
+ "# specify is greater than the SIZE_MAX defined by your system's C compiler,\n",
+ "# then it will be resolved to SIZE_MAX without a warning. Defaults to 8M (8\n",
+ "# megabytes).\n",
+ "#\n",
+ "# High values for MaxProxyBufferSize may speed up a secondary server\n",
+ "# with old hardware and a lot of available memory but can actually slow a\n",
+ "# modern system down slightly.\n",
+ "#\n",
+ "# For example:\n",
+ "#\n",
+ "# MaxProxyBufferSize=1G\n",
+#endif /* PROXY_SUPPORT */
+ "\n",
+ "# Set `MaxCommentLeaderLength' to the maximum length permitted for the\n",
+ "# automagically determined comment leader used when expanding the Log\n",
+ "# keyword, in bytes. CVS's behavior when the automagically determined\n",
+ "# comment leader exceeds this length is dependant on the value of\n",
+ "# `UseArchiveCommentLeader' set in this file. `unlimited' is a valid\n",
+ "# setting for this value. Defaults to 20 bytes.\n",
+ "#\n",
+ "# For example:\n",
+ "#\n",
+ "# MaxCommentLeaderLength=20\n",
+ "\n",
+ "# Set `UseArchiveCommentLeader' to `yes' to cause CVS to fall back on\n",
+ "# the comment leader set in the RCS archive file, if any, when the\n",
+ "# automagically determined comment leader exceeds `MaxCommentLeaderLength'\n",
+ "# bytes. If `UseArchiveCommentLeader' is not set and a comment leader\n",
+ "# greater than `MaxCommentLeaderLength' is calculated, the Log keyword\n",
+ "# being examined will not be expanded. Defaults to `no'.\n",
+ "#\n",
+ "# For example:\n",
+ "#\n",
+ "# UseArchiveCommentLeader=no\n",
+ NULL
+};
+
+static const struct admin_file filelist[] = {
+ {CVSROOTADM_CHECKOUTLIST,
+ "a %s file can specify extra CVSROOT files to auto-checkout",
+ checkoutlist_contents},
+ {CVSROOTADM_COMMITINFO,
+ "a %s file can be used to configure 'cvs commit' checking",
+ commitinfo_contents},
+ {CVSROOTADM_IGNORE,
+ "a %s file can be used to specify files to ignore",
+ NULL},
+ {CVSROOTADM_LOGINFO,
+ "no logging of 'cvs commit' messages is done without a %s file",
+ &loginfo_contents[0]},
+ {CVSROOTADM_MODULES,
+ /* modules is special-cased in mkmodules. */
+ NULL,
+ modules_contents},
+ {CVSROOTADM_NOTIFY,
+ "a %s file can be used to specify where notifications go",
+ notify_contents},
+ {CVSROOTADM_POSTADMIN,
+ "a %s file can be used to configure 'cvs admin' logging",
+ postadmin_contents},
+ {CVSROOTADM_POSTPROXY,
+ "a %s file can be used to close or log connections to a primary server",
+ postproxy_contents},
+ {CVSROOTADM_POSTTAG,
+ "a %s file can be used to configure 'cvs tag' logging",
+ posttag_contents},
+ {CVSROOTADM_POSTWATCH,
+ "a %s file can be used to configure 'cvs watch' logging",
+ postwatch_contents},
+ {CVSROOTADM_PREPROXY,
+ "a %s file can be used to open or log connections to a primary server",
+ preproxy_contents},
+ {CVSROOTADM_RCSINFO,
+ "a %s file can be used to configure 'cvs commit' templates",
+ rcsinfo_contents},
+ {CVSROOTADM_READERS,
+ "a %s file specifies read-only users",
+ NULL},
+ {CVSROOTADM_TAGINFO,
+ "a %s file can be used to configure 'cvs tag' checking",
+ taginfo_contents},
+ {CVSROOTADM_VERIFYMSG,
+ "a %s file can be used to validate log messages",
+ verifymsg_contents},
+ {CVSROOTADM_WRAPPER,
+ "a %s file can be used to specify files to treat as wrappers",
+ cvswrappers_contents},
+ {CVSROOTADM_WRITERS,
+ "a %s file specifies read/write users",
+ NULL},
+
+ /* Some have suggested listing CVSROOTADM_PASSWD here too. This
+ would mean that CVS commands which operate on the
+ CVSROOTADM_PASSWD file would transmit hashed passwords over the
+ net. This might seem to be no big deal, as pserver normally
+ transmits cleartext passwords, but the difference is that
+ CVSROOTADM_PASSWD contains *all* passwords, not just the ones
+ currently being used. For example, it could be too easy to
+ accidentally give someone readonly access to CVSROOTADM_PASSWD
+ (e.g. via anonymous CVS or cvsweb), and then if there are any
+ guessable passwords for read/write access (usually there will be)
+ they get read/write access.
+
+ Another worry is the implications of storing old passwords--if
+ someone used a password in the past they might be using it
+ elsewhere, using a similar password, etc, and so saving old
+ passwords, even hashed, is probably not a good idea. */
+
+ {CVSROOTADM_CONFIG,
+ "a %s file configures various behaviors",
+ config_contents},
+ {NULL, NULL, NULL}
+};
+
+/* Rebuild the checked out administrative files in directory DIR. */
+int
+mkmodules (char *dir)
+{
+ struct saved_cwd cwd;
+ char *temp;
+ char *cp, *last, *fname;
+#ifdef MY_NDBM
+ DBM *db;
+#endif
+ FILE *fp;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ const struct admin_file *fileptr;
+
+ if (noexec)
+ return 0;
+
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+
+ if (CVS_CHDIR (dir) < 0)
+ error (1, errno, "cannot chdir to %s", dir);
+
+ /*
+ * First, do the work necessary to update the "modules" database.
+ */
+ temp = make_tempfile ();
+ switch (checkout_file (CVSROOTADM_MODULES, temp))
+ {
+
+ case 0: /* everything ok */
+#ifdef MY_NDBM
+ /* open it, to generate any duplicate errors */
+ if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL)
+ dbm_close (db);
+#else
+ write_dbmfile (temp);
+ rename_dbmfile (temp);
+#endif
+ rename_rcsfile (temp, CVSROOTADM_MODULES);
+ break;
+
+ default:
+ error (0, 0,
+ "'cvs checkout' is less functional without a %s file",
+ CVSROOTADM_MODULES);
+ break;
+ } /* switch on checkout_file() */
+
+ if (unlink_file (temp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", temp);
+ free (temp);
+
+ /* Checkout the files that need it in CVSROOT dir */
+ for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) {
+ if (fileptr->errormsg == NULL)
+ continue;
+ temp = make_tempfile ();
+ if (checkout_file (fileptr->filename, temp) == 0)
+ rename_rcsfile (temp, fileptr->filename);
+ /* else
+ * If there was some problem other than the file not existing,
+ * checkout_file already printed a real error message. If the
+ * file does not exist, it is harmless--it probably just means
+ * that the repository was created with an old version of CVS
+ * which didn't have so many files in CVSROOT.
+ */
+
+ if (unlink_file (temp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", temp);
+ free (temp);
+ }
+
+ fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r");
+ if (fp)
+ {
+ /*
+ * File format:
+ * [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>
+ *
+ * comment lines begin with '#'
+ */
+ while (getline (&line, &line_allocated, fp) >= 0)
+ {
+ /* skip lines starting with # */
+ if (line[0] == '#')
+ continue;
+
+ if ((last = strrchr (line, '\n')) != NULL)
+ *last = '\0'; /* strip the newline */
+
+ /* Skip leading white space. */
+ for (fname = line;
+ *fname && isspace ((unsigned char) *fname);
+ fname++)
+ ;
+
+ /* Find end of filename. */
+ for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++)
+ ;
+ *cp = '\0';
+
+ temp = make_tempfile ();
+ if (checkout_file (fname, temp) == 0)
+ {
+ rename_rcsfile (temp, fname);
+ }
+ else
+ {
+ /* Skip leading white space before the error message. */
+ for (cp++;
+ cp < last && *cp && isspace ((unsigned char) *cp);
+ cp++)
+ ;
+ if (cp < last && *cp)
+ error (0, 0, "%s", cp);
+ }
+ if (unlink_file (temp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", temp);
+ free (temp);
+ }
+ if (line)
+ free (line);
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", CVSROOTADM_CHECKOUTLIST);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", CVSROOTADM_CHECKOUTLIST);
+ }
+ else
+ {
+ /* Error from CVS_FOPEN. */
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", CVSROOTADM_CHECKOUTLIST);
+ }
+
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+
+ return 0;
+}
+
+
+
+/*
+ * Yeah, I know, there are NFS race conditions here.
+ */
+static char *
+make_tempfile (void)
+{
+ static int seed = 0;
+ int fd;
+ char *temp;
+
+ if (seed == 0)
+ seed = getpid ();
+ temp = xmalloc (sizeof (BAKPREFIX) + 40);
+ while (1)
+ {
+ (void) sprintf (temp, "%s%d", BAKPREFIX, seed++);
+ if ((fd = CVS_OPEN (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
+ break;
+ if (errno != EEXIST)
+ error (1, errno, "cannot create temporary file %s", temp);
+ }
+ if (close(fd) < 0)
+ error(1, errno, "cannot close temporary file %s", temp);
+ return temp;
+}
+
+
+
+/* Get a file. If the file does not exist, return 1 silently. If
+ there is an error, print a message and return 1 (FIXME: probably
+ not a very clean convention). On success, return 0. */
+static int
+checkout_file (char *file, char *temp)
+{
+ char *rcs;
+ RCSNode *rcsnode;
+ int retcode = 0;
+
+ if (noexec)
+ return 0;
+
+ rcs = Xasprintf ("%s%s", file, RCSEXT);
+ if (!isfile (rcs))
+ {
+ free (rcs);
+ return 1;
+ }
+
+ rcsnode = RCS_parsercsfile (rcs);
+ if (!rcsnode)
+ {
+ /* Probably not necessary (?); RCS_parsercsfile already printed a
+ message. */
+ error (0, 0, "Failed to parse `%s'.", rcs);
+ free (rcs);
+ return 1;
+ }
+
+ retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp, NULL, NULL);
+ if (retcode != 0)
+ {
+ /* Probably not necessary (?); RCS_checkout already printed a
+ message. */
+ error (0, 0, "failed to check out %s file",
+ file);
+ }
+ freercsnode (&rcsnode);
+ free (rcs);
+ return retcode;
+}
+
+
+
+#ifndef MY_NDBM
+
+static void
+write_dbmfile( char *temp )
+{
+ char line[DBLKSIZ], value[DBLKSIZ];
+ FILE *fp;
+ DBM *db;
+ char *cp, *vp;
+ datum key, val;
+ int len, cont, err = 0;
+
+ fp = xfopen (temp, "r");
+ if ((db = dbm_open (temp, O_RDWR | O_CREAT | O_TRUNC, 0666)) == NULL)
+ error (1, errno, "cannot open dbm file %s for creation", temp);
+ for (cont = 0; fgets (line, sizeof (line), fp) != NULL;)
+ {
+ if ((cp = strrchr (line, '\n')) != NULL)
+ *cp = '\0'; /* strip the newline */
+
+ /*
+ * Add the line to the value, at the end if this is a continuation
+ * line; otherwise at the beginning, but only after any trailing
+ * backslash is removed.
+ */
+ vp = value;
+ if (cont)
+ vp += strlen (value);
+
+ /*
+ * See if the line we read is a continuation line, and strip the
+ * backslash if so.
+ */
+ len = strlen (line);
+ if (len > 0)
+ cp = &line[len - 1];
+ else
+ cp = line;
+ if (*cp == '\\')
+ {
+ cont = 1;
+ *cp = '\0';
+ }
+ else
+ {
+ cont = 0;
+ }
+ (void) strcpy (vp, line);
+ if (value[0] == '#')
+ continue; /* comment line */
+ vp = value;
+ while (*vp && isspace ((unsigned char) *vp))
+ vp++;
+ if (*vp == '\0')
+ continue; /* empty line */
+
+ /*
+ * If this was not a continuation line, add the entry to the database
+ */
+ if (!cont)
+ {
+ key.dptr = vp;
+ while (*vp && !isspace ((unsigned char) *vp))
+ vp++;
+ key.dsize = vp - key.dptr;
+ *vp++ = '\0'; /* NULL terminate the key */
+ while (*vp && isspace ((unsigned char) *vp))
+ vp++; /* skip whitespace to value */
+ if (*vp == '\0')
+ {
+ error (0, 0, "warning: NULL value for key `%s'", key.dptr);
+ continue;
+ }
+ val.dptr = vp;
+ val.dsize = strlen (vp);
+ if (dbm_store (db, key, val, DBM_INSERT) == 1)
+ {
+ error (0, 0, "duplicate key found for `%s'", key.dptr);
+ err++;
+ }
+ }
+ }
+ dbm_close (db);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", temp);
+ if (err)
+ {
+ /* I think that the size of the buffer needed here is
+ just determined by sizeof (CVSROOTADM_MODULES), the
+ filenames created by make_tempfile, and other things that won't
+ overflow. */
+ char dotdir[50], dotpag[50], dotdb[50];
+
+ (void) sprintf (dotdir, "%s.dir", temp);
+ (void) sprintf (dotpag, "%s.pag", temp);
+ (void) sprintf (dotdb, "%s.db", temp);
+ if (unlink_file (dotdir) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", dotdir);
+ if (unlink_file (dotpag) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", dotpag);
+ if (unlink_file (dotdb) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", dotdb);
+ error (1, 0, "DBM creation failed; correct above errors");
+ }
+}
+
+static void
+rename_dbmfile( char *temp )
+{
+ /* I think that the size of the buffer needed here is
+ just determined by sizeof (CVSROOTADM_MODULES), the
+ filenames created by make_tempfile, and other things that won't
+ overflow. */
+ char newdir[50], newpag[50], newdb[50];
+ char dotdir[50], dotpag[50], dotdb[50];
+ char bakdir[50], bakpag[50], bakdb[50];
+
+ int dir1_errno = 0, pag1_errno = 0, db1_errno = 0;
+ int dir2_errno = 0, pag2_errno = 0, db2_errno = 0;
+ int dir3_errno = 0, pag3_errno = 0, db3_errno = 0;
+
+ (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES);
+ (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES);
+ (void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES);
+ (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (bakdb, "%s%s.db", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (newdir, "%s.dir", temp);
+ (void) sprintf (newpag, "%s.pag", temp);
+ (void) sprintf (newdb, "%s.db", temp);
+
+ (void) chmod (newdir, 0666);
+ (void) chmod (newpag, 0666);
+ (void) chmod (newdb, 0666);
+
+ /* don't mess with me */
+ SIG_beginCrSect ();
+
+ /* rm .#modules.dir .#modules.pag */
+ if (unlink_file (bakdir) < 0)
+ dir1_errno = errno;
+ if (unlink_file (bakpag) < 0)
+ pag1_errno = errno;
+ if (unlink_file (bakdb) < 0)
+ db1_errno = errno;
+
+ /* mv modules.dir .#modules.dir */
+ if (CVS_RENAME (dotdir, bakdir) < 0)
+ dir2_errno = errno;
+ /* mv modules.pag .#modules.pag */
+ if (CVS_RENAME (dotpag, bakpag) < 0)
+ pag2_errno = errno;
+ /* mv modules.db .#modules.db */
+ if (CVS_RENAME (dotdb, bakdb) < 0)
+ db2_errno = errno;
+
+ /* mv "temp".dir modules.dir */
+ if (CVS_RENAME (newdir, dotdir) < 0)
+ dir3_errno = errno;
+ /* mv "temp".pag modules.pag */
+ if (CVS_RENAME (newpag, dotpag) < 0)
+ pag3_errno = errno;
+ /* mv "temp".db modules.db */
+ if (CVS_RENAME (newdb, dotdb) < 0)
+ db3_errno = errno;
+
+ /* OK -- make my day */
+ SIG_endCrSect ();
+
+ /* I didn't want to call error() when we had signals blocked
+ (unnecessary?), but do it now. */
+ if (dir1_errno && !existence_error (dir1_errno))
+ error (0, dir1_errno, "cannot remove %s", bakdir);
+ if (pag1_errno && !existence_error (pag1_errno))
+ error (0, pag1_errno, "cannot remove %s", bakpag);
+ if (db1_errno && !existence_error (db1_errno))
+ error (0, db1_errno, "cannot remove %s", bakdb);
+
+ if (dir2_errno && !existence_error (dir2_errno))
+ error (0, dir2_errno, "cannot remove %s", bakdir);
+ if (pag2_errno && !existence_error (pag2_errno))
+ error (0, pag2_errno, "cannot remove %s", bakpag);
+ if (db2_errno && !existence_error (db2_errno))
+ error (0, db2_errno, "cannot remove %s", bakdb);
+
+ if (dir3_errno && !existence_error (dir3_errno))
+ error (0, dir3_errno, "cannot remove %s", bakdir);
+ if (pag3_errno && !existence_error (pag3_errno))
+ error (0, pag3_errno, "cannot remove %s", bakpag);
+ if (db3_errno && !existence_error (db3_errno))
+ error (0, db3_errno, "cannot remove %s", bakdb);
+}
+
+#endif /* !MY_NDBM */
+
+static void
+rename_rcsfile (char *temp, char *real)
+{
+ char *bak;
+ struct stat statbuf;
+ char *rcs;
+
+ /* Set "x" bits if set in original. */
+ rcs = Xasprintf ("%s%s", real, RCSEXT);
+ statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */
+ if (stat (rcs, &statbuf) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot stat %s", rcs);
+ free (rcs);
+
+ if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0)
+ error (0, errno, "warning: cannot chmod %s", temp);
+ bak = Xasprintf ("%s%s", BAKPREFIX, real);
+
+ /* rm .#loginfo */
+ if (unlink_file (bak) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", bak);
+
+ /* mv loginfo .#loginfo */
+ if (CVS_RENAME (real, bak) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot rename %s to %s", real, bak);
+
+ /* mv "temp" loginfo */
+ if (CVS_RENAME (temp, real) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot rename %s to %s", temp, real);
+
+ free (bak);
+}
+
+const char *const init_usage[] = {
+ "Usage: %s %s\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+init (int argc, char **argv)
+{
+ /* Name of CVSROOT directory. */
+ char *adm;
+ /* Name of this administrative file. */
+ char *info;
+ /* Name of ,v file for this administrative file. */
+ char *info_v;
+ /* Exit status. */
+ int err = 0;
+
+ const struct admin_file *fileptr;
+
+ umask (cvsumask);
+
+ if (argc == -1 || argc > 1)
+ usage (init_usage);
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+
+ ign_setup ();
+ send_init_command ();
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ /* Note: we do *not* create parent directories as needed like the
+ old cvsinit.sh script did. Few utilities do that, and a
+ non-existent parent directory is as likely to be a typo as something
+ which needs to be created. */
+ mkdir_if_needed (current_parsed_root->directory);
+
+ adm = Xasprintf ("%s/%s", current_parsed_root->directory, CVSROOTADM);
+ mkdir_if_needed (adm);
+
+ /* This is needed because we pass "fileptr->filename" not "info"
+ to add_rcs_file below. I think this would be easy to change,
+ thus nuking the need for CVS_CHDIR here, but I haven't looked
+ closely (e.g. see wrappers calls within add_rcs_file). */
+ if ( CVS_CHDIR (adm) < 0)
+ error (1, errno, "cannot change to directory %s", adm);
+
+ /* Make Emptydir so it's there if we need it */
+ mkdir_if_needed (CVSNULLREPOS);
+
+ /* 80 is long enough for all the administrative file names, plus
+ "/" and so on. */
+ info = xmalloc (strlen (adm) + 80);
+ info_v = xmalloc (strlen (adm) + 80);
+ for (fileptr = filelist; fileptr && fileptr->filename; ++fileptr)
+ {
+ if (fileptr->contents == NULL)
+ continue;
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, fileptr->filename);
+ strcpy (info_v, info);
+ strcat (info_v, RCSEXT);
+ if (isfile (info_v))
+ /* We will check out this file in the mkmodules step.
+ Nothing else is required. */
+ ;
+ else
+ {
+ int retcode;
+
+ if (!isfile (info))
+ {
+ FILE *fp;
+ const char * const *p;
+
+ fp = xfopen (info, "w");
+ for (p = fileptr->contents; *p != NULL; ++p)
+ if (fputs (*p, fp) < 0)
+ error (1, errno, "cannot write %s", info);
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+ }
+ /* The message used to say " of " and fileptr->filename after
+ "initial checkin" but I fail to see the point as we know what
+ file it is from the name. */
+ retcode = add_rcs_file ("initial checkin", info_v,
+ fileptr->filename, "1.1", NULL,
+
+ /* No vendor branch. */
+ NULL, NULL, 0, NULL,
+
+ NULL, 0, NULL, 0);
+ if (retcode != 0)
+ /* add_rcs_file already printed an error message. */
+ err = 1;
+ }
+ }
+
+ /* Turn on history logging by default. The user can remove the file
+ to disable it. */
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, CVSROOTADM_HISTORY);
+ if (!isfile (info))
+ {
+ FILE *fp;
+
+ fp = xfopen (info, "w");
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+
+ /* Make the new history file world-writeable, since every CVS
+ user will need to be able to write to it. We use chmod()
+ because xchmod() is too shy. */
+ chmod (info, 0666);
+ }
+
+ /* Make an empty val-tags file to prevent problems creating it later. */
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, CVSROOTADM_VALTAGS);
+ if (!isfile (info))
+ {
+ FILE *fp;
+
+ fp = xfopen (info, "w");
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+
+ /* Make the new val-tags file world-writeable, since every CVS
+ user will need to be able to write to it. We use chmod()
+ because xchmod() is too shy. */
+ chmod (info, 0666);
+ }
+
+ free (info);
+ free (info_v);
+
+ mkmodules (adm);
+
+ free (adm);
+ return err;
+}
diff --git a/src/modules.c b/src/modules.c
new file mode 100644
index 0000000..2975298
--- /dev/null
+++ b/src/modules.c
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS source
+ * distribution.
+ *
+ * Modules
+ *
+ * Functions for accessing the modules file.
+ *
+ * The modules file supports basically three formats of lines:
+ * key [options] directory files... [ -x directory [files] ] ...
+ * key [options] directory [ -x directory [files] ] ...
+ * key -a aliases...
+ *
+ * The -a option allows an aliasing step in the parsing of the modules
+ * file. The "aliases" listed on a line following the -a are
+ * processed one-by-one, as if they were specified as arguments on the
+ * command line.
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+
+
+/* Defines related to the syntax of the modules file. */
+
+/* Options in modules file. Note that it is OK to use GNU getopt features;
+ we already are arranging to make sure we are using the getopt distributed
+ with CVS. */
+#define CVSMODULE_OPTS "+ad:lo:e:s:t:"
+
+/* Special delimiter. */
+#define CVSMODULE_SPEC '&'
+
+struct sortrec
+{
+ /* Name of the module, malloc'd. */
+ char *modname;
+ /* If Status variable is set, this is either def_status or the malloc'd
+ name of the status. If Status is not set, the field is left
+ uninitialized. */
+ char *status;
+ /* Pointer to a malloc'd array which contains (1) the raw contents
+ of the options and arguments, excluding comments, (2) a '\0',
+ and (3) the storage for the "comment" field. */
+ char *rest;
+ char *comment;
+};
+
+static int sort_order (const void *l, const void *r);
+static void save_d (char *k, int ks, char *d, int ds);
+
+
+/*
+ * Open the modules file, and die if the CVSROOT environment variable
+ * was not set. If the modules file does not exist, that's fine, and
+ * a warning message is displayed and a NULL is returned.
+ */
+DBM *
+open_module (void)
+{
+ char *mfile;
+ DBM *retval;
+
+ if (current_parsed_root == NULL)
+ {
+ error (0, 0, "must set the CVSROOT environment variable");
+ error (1, 0, "or specify the '-d' global option");
+ }
+ mfile = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_MODULES);
+ retval = dbm_open (mfile, O_RDONLY, 0666);
+ free (mfile);
+ return retval;
+}
+
+/*
+ * Close the modules file, if the open succeeded, that is
+ */
+void
+close_module (DBM *db)
+{
+ if (db != NULL)
+ dbm_close (db);
+}
+
+
+
+/*
+ * This is the recursive function that processes a module name.
+ * It calls back the passed routine for each directory of a module
+ * It runs the post checkout or post tag proc from the modules file
+ */
+int
+my_module (DBM *db, char *mname, enum mtype m_type, char *msg,
+ CALLBACKPROC callback_proc, char *where, int shorten,
+ int local_specified, int run_module_prog, int build_dirs,
+ char *extra_arg, List *stack)
+{
+ char *checkout_prog = NULL;
+ char *export_prog = NULL;
+ char *tag_prog = NULL;
+ struct saved_cwd cwd;
+ int cwd_saved = 0;
+ char *line;
+ int modargc;
+ int xmodargc;
+ char **modargv = NULL;
+ char **xmodargv = NULL;
+ /* Found entry from modules file, including options and such. */
+ char *value = NULL;
+ char *mwhere = NULL;
+ char *mfile = NULL;
+ char *spec_opt = NULL;
+ char *xvalue = NULL;
+ int alias = 0;
+ datum key, val;
+ char *cp;
+ int c, err = 0;
+ int nonalias_opt = 0;
+
+#ifdef SERVER_SUPPORT
+ int restore_server_dir = 0;
+ char *server_dir_to_restore = NULL;
+#endif
+
+ TRACE (TRACE_FUNCTION, "my_module (%s, %s, %s, %s)",
+ mname ? mname : "(null)", msg ? msg : "(null)",
+ where ? where : "NULL", extra_arg ? extra_arg : "NULL");
+
+ /* Don't process absolute directories. Anything else could be a security
+ * problem. Before this check was put in place:
+ *
+ * $ cvs -d:fork:/cvsroot co /foo
+ * cvs server: warning: cannot make directory CVS in /: Permission denied
+ * cvs [server aborted]: cannot make directory /foo: Permission denied
+ * $
+ */
+ if (ISABSOLUTE (mname))
+ error (1, 0, "Absolute module reference invalid: `%s'", mname);
+
+ /* Similarly for directories that attempt to step above the root of the
+ * repository.
+ */
+ if (pathname_levels (mname) > 0)
+ error (1, 0, "up-level in module reference (`..') invalid: `%s'.",
+ mname);
+
+ /* if this is a directory to ignore, add it to that list */
+ if (mname[0] == '!' && mname[1] != '\0')
+ {
+ ign_dir_add (mname+1);
+ goto do_module_return;
+ }
+
+ /* strip extra stuff from the module name */
+ strip_trailing_slashes (mname);
+
+ /*
+ * Look up the module using the following scheme:
+ * 1) look for mname as a module name
+ * 2) look for mname as a directory
+ * 3) look for mname as a file
+ * 4) take mname up to the first slash and look it up as a module name
+ * (this is for checking out only part of a module)
+ */
+
+ /* look it up as a module name */
+ key.dptr = mname;
+ key.dsize = strlen (key.dptr);
+ if (db != NULL)
+ val = dbm_fetch (db, key);
+ else
+ val.dptr = NULL;
+ if (val.dptr != NULL)
+ {
+ /* copy and null terminate the value */
+ value = xmalloc (val.dsize + 1);
+ memcpy (value, val.dptr, val.dsize);
+ value[val.dsize] = '\0';
+
+ /* If the line ends in a comment, strip it off */
+ if ((cp = strchr (value, '#')) != NULL)
+ *cp = '\0';
+ else
+ cp = value + val.dsize;
+
+ /* Always strip trailing spaces */
+ while (cp > value && isspace ((unsigned char) *--cp))
+ *cp = '\0';
+
+ mwhere = xstrdup (mname);
+ goto found;
+ }
+ else
+ {
+ char *file;
+ char *attic_file;
+ char *acp;
+ int is_found = 0;
+
+ /* check to see if mname is a directory or file */
+ file = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (mname) + sizeof(RCSEXT) + 2);
+ (void) sprintf (file, "%s/%s", current_parsed_root->directory, mname);
+ attic_file = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (mname)
+ + sizeof (CVSATTIC) + sizeof (RCSEXT) + 3);
+ if ((acp = strrchr (mname, '/')) != NULL)
+ {
+ *acp = '\0';
+ (void) sprintf (attic_file, "%s/%s/%s/%s%s", current_parsed_root->directory,
+ mname, CVSATTIC, acp + 1, RCSEXT);
+ *acp = '/';
+ }
+ else
+ (void) sprintf (attic_file, "%s/%s/%s%s",
+ current_parsed_root->directory,
+ CVSATTIC, mname, RCSEXT);
+
+ if (isdir (file))
+ {
+ modargv = xmalloc (sizeof (*modargv));
+ modargv[0] = xstrdup (mname);
+ modargc = 1;
+ is_found = 1;
+ }
+ else
+ {
+ (void) strcat (file, RCSEXT);
+ if (isfile (file) || isfile (attic_file))
+ {
+ /* if mname was a file, we have to split it into "dir file" */
+ if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
+ {
+ modargv = xnmalloc (2, sizeof (*modargv));
+ modargv[0] = xmalloc (strlen (mname) + 2);
+ strncpy (modargv[0], mname, cp - mname);
+ modargv[0][cp - mname] = '\0';
+ modargv[1] = xstrdup (cp + 1);
+ modargc = 2;
+ }
+ else
+ {
+ /*
+ * the only '/' at the beginning or no '/' at all
+ * means the file we are interested in is in CVSROOT
+ * itself so the directory should be '.'
+ */
+ if (cp == mname)
+ {
+ /* drop the leading / if specified */
+ modargv = xnmalloc (2, sizeof (*modargv));
+ modargv[0] = xstrdup (".");
+ modargv[1] = xstrdup (mname + 1);
+ modargc = 2;
+ }
+ else
+ {
+ /* otherwise just copy it */
+ modargv = xnmalloc (2, sizeof (*modargv));
+ modargv[0] = xstrdup (".");
+ modargv[1] = xstrdup (mname);
+ modargc = 2;
+ }
+ }
+ is_found = 1;
+ }
+ }
+ free (attic_file);
+ free (file);
+
+ if (is_found)
+ {
+ assert (value == NULL);
+
+ /* OK, we have now set up modargv with the actual
+ file/directory we want to work on. We duplicate a
+ small amount of code here because the vast majority of
+ the code after the "found" label does not pertain to
+ the case where we found a file/directory rather than
+ finding an entry in the modules file. */
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+ cwd_saved = 1;
+
+ err += callback_proc (modargc, modargv, where, mwhere, mfile,
+ shorten,
+ local_specified, mname, msg);
+
+ free_names (&modargc, modargv);
+
+ /* cd back to where we started. */
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+ cwd_saved = 0;
+
+ goto do_module_return;
+ }
+ }
+
+ /* look up everything to the first / as a module */
+ if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL)
+ {
+ /* Make the slash the new end of the string temporarily */
+ *cp = '\0';
+ key.dptr = mname;
+ key.dsize = strlen (key.dptr);
+
+ /* do the lookup */
+ if (db != NULL)
+ val = dbm_fetch (db, key);
+ else
+ val.dptr = NULL;
+
+ /* if we found it, clean up the value and life is good */
+ if (val.dptr != NULL)
+ {
+ char *cp2;
+
+ /* copy and null terminate the value */
+ value = xmalloc (val.dsize + 1);
+ memcpy (value, val.dptr, val.dsize);
+ value[val.dsize] = '\0';
+
+ /* If the line ends in a comment, strip it off */
+ if ((cp2 = strchr (value, '#')) != NULL)
+ *cp2 = '\0';
+ else
+ cp2 = value + val.dsize;
+
+ /* Always strip trailing spaces */
+ while (cp2 > value && isspace ((unsigned char) *--cp2))
+ *cp2 = '\0';
+
+ /* mwhere gets just the module name */
+ mwhere = xstrdup (mname);
+ mfile = cp + 1;
+ assert (strlen (mfile));
+
+ /* put the / back in mname */
+ *cp = '/';
+
+ goto found;
+ }
+
+ /* put the / back in mname */
+ *cp = '/';
+ }
+
+ /* if we got here, we couldn't find it using our search, so give up */
+ error (0, 0, "cannot find module `%s' - ignored", mname);
+ err++;
+ goto do_module_return;
+
+
+ /*
+ * At this point, we found what we were looking for in one
+ * of the many different forms.
+ */
+ found:
+
+ /* remember where we start */
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+ cwd_saved = 1;
+
+ assert (value != NULL);
+
+ /* search the value for the special delimiter and save for later */
+ if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
+ {
+ *cp = '\0'; /* null out the special char */
+ spec_opt = cp + 1; /* save the options for later */
+
+ /* strip whitespace if necessary */
+ while (cp > value && isspace ((unsigned char) *--cp))
+ *cp = '\0';
+ }
+
+ /* don't do special options only part of a module was specified */
+ if (mfile != NULL)
+ spec_opt = NULL;
+
+ /*
+ * value now contains one of the following:
+ * 1) dir
+ * 2) dir file
+ * 3) the value from modules without any special args
+ * [ args ] dir [file] [file] ...
+ * or -a module [ module ] ...
+ */
+
+ /* Put the value on a line with XXX prepended for getopt to eat */
+ line = Xasprintf ("XXX %s", value);
+
+ /* turn the line into an argv[] array */
+ line2argv (&xmodargc, &xmodargv, line, " \t");
+ free (line);
+ modargc = xmodargc;
+ modargv = xmodargv;
+
+ /* parse the args */
+ optind = 0;
+ while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
+ {
+ switch (c)
+ {
+ case 'a':
+ alias = 1;
+ break;
+ case 'd':
+ if (mwhere)
+ free (mwhere);
+ mwhere = xstrdup (optarg);
+ nonalias_opt = 1;
+ break;
+ case 'l':
+ local_specified = 1;
+ nonalias_opt = 1;
+ break;
+ case 'o':
+ if (checkout_prog)
+ free (checkout_prog);
+ checkout_prog = xstrdup (optarg);
+ nonalias_opt = 1;
+ break;
+ case 'e':
+ if (export_prog)
+ free (export_prog);
+ export_prog = xstrdup (optarg);
+ nonalias_opt = 1;
+ break;
+ case 't':
+ if (tag_prog)
+ free (tag_prog);
+ tag_prog = xstrdup (optarg);
+ nonalias_opt = 1;
+ break;
+ case '?':
+ error (0, 0,
+ "modules file has invalid option for key %s value %s",
+ key.dptr, value);
+ err++;
+ goto do_module_return;
+ }
+ }
+ modargc -= optind;
+ modargv += optind;
+ if (modargc == 0 && spec_opt == NULL)
+ {
+ error (0, 0, "modules file missing directory for module %s", mname);
+ ++err;
+ goto do_module_return;
+ }
+
+ if (alias && nonalias_opt)
+ {
+ /* The documentation has never said it is valid to specify
+ -a along with another option. And I believe that in the past
+ CVS has ignored the options other than -a, more or less, in this
+ situation. */
+ error (0, 0, "\
+-a cannot be specified in the modules file along with other options");
+ ++err;
+ goto do_module_return;
+ }
+
+ /* if this was an alias, call ourselves recursively for each module */
+ if (alias)
+ {
+ int i;
+
+ for (i = 0; i < modargc; i++)
+ {
+ /*
+ * Recursion check: if an alias module calls itself or a module
+ * which causes the first to be called again, print an error
+ * message and stop recursing.
+ *
+ * Algorithm:
+ *
+ * 1. Check that MNAME isn't in the stack.
+ * 2. Push MNAME onto the stack.
+ * 3. Call do_module().
+ * 4. Pop MNAME from the stack.
+ */
+ if (stack && findnode (stack, mname))
+ error (0, 0,
+ "module `%s' in modules file contains infinite loop",
+ mname);
+ else
+ {
+ if (!stack) stack = getlist();
+ push_string (stack, mname);
+ err += my_module (db, modargv[i], m_type, msg, callback_proc,
+ where, shorten, local_specified,
+ run_module_prog, build_dirs, extra_arg,
+ stack);
+ pop_string (stack);
+ if (isempty (stack)) dellist (&stack);
+ }
+ }
+ goto do_module_return;
+ }
+
+ if (mfile != NULL && modargc > 1)
+ {
+ error (0, 0, "\
+module `%s' is a request for a file in a module which is not a directory",
+ mname);
+ ++err;
+ goto do_module_return;
+ }
+
+ /* otherwise, process this module */
+ if (modargc > 0)
+ {
+ err += callback_proc (modargc, modargv, where, mwhere, mfile, shorten,
+ local_specified, mname, msg);
+ }
+ else
+ {
+ /*
+ * we had nothing but special options, so we must
+ * make the appropriate directory and cd to it
+ */
+ char *dir;
+
+ if (!build_dirs)
+ goto do_special;
+
+ dir = where ? where : (mwhere ? mwhere : mname);
+ /* XXX - think about making null repositories at each dir here
+ instead of just at the bottom */
+ make_directories (dir);
+ if (CVS_CHDIR (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", dir);
+ spec_opt = NULL;
+ err++;
+ goto do_special;
+ }
+ if (!isfile (CVSADM))
+ {
+ char *nullrepos;
+
+ nullrepos = emptydir_name ();
+
+ Create_Admin (".", dir, nullrepos, NULL, NULL, 0, 0, 1);
+ if (!noexec)
+ {
+ FILE *fp;
+
+ fp = xfopen (CVSADM_ENTSTAT, "w+");
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (dir, nullrepos);
+#endif
+ }
+ free (nullrepos);
+ }
+ }
+
+ /* if there were special include args, process them now */
+
+ do_special:
+
+ free_names (&xmodargc, xmodargv);
+ xmodargv = NULL;
+
+ /* blow off special options if -l was specified */
+ if (local_specified)
+ spec_opt = NULL;
+
+#ifdef SERVER_SUPPORT
+ /* We want to check out into the directory named by the module.
+ So we set a global variable which tells the server to glom that
+ directory name onto the front. A cleaner approach would be some
+ way of passing it down to the recursive call, through the
+ callback_proc, to start_recursion, and then into the update_dir in
+ the struct file_info. That way the "Updating foo" message could
+ print the actual directory we are checking out into.
+
+ For local CVS, this is handled by the chdir call above
+ (directly or via the callback_proc). */
+ if (server_active && spec_opt != NULL)
+ {
+ char *change_to;
+
+ change_to = where ? where : (mwhere ? mwhere : mname);
+ server_dir_to_restore = server_dir;
+ restore_server_dir = 1;
+ if (server_dir_to_restore != NULL)
+ server_dir = Xasprintf ("%s/%s", server_dir_to_restore, change_to);
+ else
+ server_dir = xstrdup (change_to);
+ }
+#endif
+
+ while (spec_opt != NULL)
+ {
+ char *next_opt;
+
+ cp = strchr (spec_opt, CVSMODULE_SPEC);
+ if (cp != NULL)
+ {
+ /* save the beginning of the next arg */
+ next_opt = cp + 1;
+
+ /* strip whitespace off the end */
+ do
+ *cp = '\0';
+ while (cp > spec_opt && isspace ((unsigned char) *--cp));
+ }
+ else
+ next_opt = NULL;
+
+ /* strip whitespace from front */
+ while (isspace ((unsigned char) *spec_opt))
+ spec_opt++;
+
+ if (*spec_opt == '\0')
+ error (0, 0, "Mal-formed %c option for module %s - ignored",
+ CVSMODULE_SPEC, mname);
+ else
+ err += my_module (db, spec_opt, m_type, msg, callback_proc,
+ NULL, 0, local_specified, run_module_prog,
+ build_dirs, extra_arg, stack);
+ spec_opt = next_opt;
+ }
+
+#ifdef SERVER_SUPPORT
+ if (server_active && restore_server_dir)
+ {
+ free (server_dir);
+ server_dir = server_dir_to_restore;
+ }
+#endif
+
+ /* cd back to where we started */
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+ cwd_saved = 0;
+
+ /* run checkout or tag prog if appropriate */
+ if (err == 0 && run_module_prog)
+ {
+ if ((m_type == TAG && tag_prog != NULL) ||
+ (m_type == CHECKOUT && checkout_prog != NULL) ||
+ (m_type == EXPORT && export_prog != NULL))
+ {
+ /*
+ * If a relative pathname is specified as the checkout, tag
+ * or export proc, try to tack on the current "where" value.
+ * if we can't find a matching program, just punt and use
+ * whatever is specified in the modules file.
+ */
+ char *real_prog = NULL;
+ char *prog = (m_type == TAG ? tag_prog :
+ (m_type == CHECKOUT ? checkout_prog : export_prog));
+ char *real_where = (where != NULL ? where : mwhere);
+ char *expanded_path;
+
+ if ((*prog != '/') && (*prog != '.'))
+ {
+ real_prog = Xasprintf ("%s/%s", real_where, prog);
+ if (isfile (real_prog))
+ prog = real_prog;
+ }
+
+ /* XXX can we determine the line number for this entry??? */
+ expanded_path = expand_path (prog, current_parsed_root->directory,
+ false, "modules", 0);
+ if (expanded_path != NULL)
+ {
+ run_setup (expanded_path);
+ run_add_arg (real_where);
+
+ if (extra_arg)
+ run_add_arg (extra_arg);
+
+ if (!quiet)
+ {
+ cvs_output (program_name, 0);
+ cvs_output (" ", 1);
+ cvs_output (cvs_cmd_name, 0);
+ cvs_output (": Executing '", 0);
+ run_print (stdout);
+ cvs_output ("'\n", 0);
+ cvs_flushout ();
+ }
+ err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ free (expanded_path);
+ }
+ if (real_prog) free (real_prog);
+ }
+ }
+
+ do_module_return:
+ /* clean up */
+ if (xmodargv != NULL)
+ free_names (&xmodargc, xmodargv);
+ if (mwhere)
+ free (mwhere);
+ if (checkout_prog)
+ free (checkout_prog);
+ if (export_prog)
+ free (export_prog);
+ if (tag_prog)
+ free (tag_prog);
+ if (cwd_saved)
+ free_cwd (&cwd);
+ if (value != NULL)
+ free (value);
+
+ if (xvalue != NULL)
+ free (xvalue);
+ return (err);
+}
+
+
+
+/* External face of do_module so that we can have an internal version which
+ * accepts a stack argument to track alias recursion.
+ */
+int
+do_module (DBM *db, char *mname, enum mtype m_type, char *msg,
+ CALLBACKPROC callback_proc, char *where, int shorten,
+ int local_specified, int run_module_prog, int build_dirs,
+ char *extra_arg)
+{
+ return my_module (db, mname, m_type, msg, callback_proc, where, shorten,
+ local_specified, run_module_prog, build_dirs, extra_arg,
+ NULL);
+}
+
+
+
+/* - Read all the records from the modules database into an array.
+ - Sort the array depending on what format is desired.
+ - Print the array in the format desired.
+
+ Currently, there are only two "desires":
+
+ 1. Sort by module name and format the whole entry including switches,
+ files and the comment field: (Including aliases)
+
+ modulename -s switches, one per line, even if
+ it has many switches.
+ Directories and files involved, formatted
+ to cover multiple lines if necessary.
+ # Comment, also formatted to cover multiple
+ # lines if necessary.
+
+ 2. Sort by status field string and print: (*not* including aliases)
+
+ modulename STATUS Directories and files involved, formatted
+ to cover multiple lines if necessary.
+ # Comment, also formatted to cover multiple
+ # lines if necessary.
+*/
+
+static struct sortrec *s_head;
+
+static int s_max = 0; /* Number of elements allocated */
+static int s_count = 0; /* Number of elements used */
+
+static int Status; /* Nonzero if the user is
+ interested in status
+ information as well as
+ module name */
+static char def_status[] = "NONE";
+
+/* Sort routine for qsort:
+ - If we want the "Status" field to be sorted, check it first.
+ - Then compare the "module name" fields. Since they are unique, we don't
+ have to look further.
+*/
+static int
+sort_order (const void *l, const void *r)
+{
+ int i;
+ const struct sortrec *left = (const struct sortrec *) l;
+ const struct sortrec *right = (const struct sortrec *) r;
+
+ if (Status)
+ {
+ /* If Sort by status field, compare them. */
+ if ((i = strcmp (left->status, right->status)) != 0)
+ return (i);
+ }
+ return (strcmp (left->modname, right->modname));
+}
+
+static void
+save_d (char *k, int ks, char *d, int ds)
+{
+ char *cp, *cp2;
+ struct sortrec *s_rec;
+
+ if (Status && *d == '-' && *(d + 1) == 'a')
+ return; /* We want "cvs co -s" and it is an alias! */
+
+ if (s_count == s_max)
+ {
+ s_max += 64;
+ s_head = xnrealloc (s_head, s_max, sizeof (*s_head));
+ }
+ s_rec = &s_head[s_count];
+ s_rec->modname = cp = xmalloc (ks + 1);
+ (void) strncpy (cp, k, ks);
+ *(cp + ks) = '\0';
+
+ s_rec->rest = cp2 = xmalloc (ds + 1);
+ cp = d;
+ *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
+
+ while (isspace ((unsigned char) *cp))
+ cp++;
+ /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
+ while (*cp)
+ {
+ if (isspace ((unsigned char) *cp))
+ {
+ *cp2++ = ' ';
+ while (isspace ((unsigned char) *cp))
+ cp++;
+ }
+ else
+ *cp2++ = *cp++;
+ }
+ *cp2 = '\0';
+
+ /* Look for the "-s statusvalue" text */
+ if (Status)
+ {
+ s_rec->status = def_status;
+
+ for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2)
+ {
+ if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
+ {
+ char *status_start;
+
+ cp2 += 3;
+ status_start = cp2;
+ while (*cp2 != ' ' && *cp2 != '\0')
+ cp2++;
+ s_rec->status = xmalloc (cp2 - status_start + 1);
+ strncpy (s_rec->status, status_start, cp2 - status_start);
+ s_rec->status[cp2 - status_start] = '\0';
+ cp = cp2;
+ break;
+ }
+ }
+ }
+ else
+ cp = s_rec->rest;
+
+ /* Find comment field, clean up on all three sides & compress blanks */
+ if ((cp2 = cp = strchr (cp, '#')) != NULL)
+ {
+ if (*--cp2 == ' ')
+ *cp2 = '\0';
+ if (*++cp == ' ')
+ cp++;
+ s_rec->comment = cp;
+ }
+ else
+ s_rec->comment = "";
+
+ s_count++;
+}
+
+/* Print out the module database as we know it. If STATUS is
+ non-zero, print out status information for each module. */
+
+void
+cat_module (int status)
+{
+ DBM *db;
+ datum key, val;
+ int i, c, wid, argc, cols = 80, indent, fill;
+ int moduleargc;
+ struct sortrec *s_h;
+ char *cp, *cp2, **argv;
+ char **moduleargv;
+
+ Status = status;
+
+ /* Read the whole modules file into allocated records */
+ if (!(db = open_module ()))
+ error (1, 0, "failed to open the modules file");
+
+ for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db))
+ {
+ val = dbm_fetch (db, key);
+ if (val.dptr != NULL)
+ save_d (key.dptr, key.dsize, val.dptr, val.dsize);
+ }
+
+ close_module (db);
+
+ /* Sort the list as requested */
+ qsort ((void *) s_head, s_count, sizeof (struct sortrec), sort_order);
+
+ /*
+ * Run through the sorted array and format the entries
+ * indent = space for modulename + space for status field
+ */
+ indent = 12 + (status * 12);
+ fill = cols - (indent + 2);
+ for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
+ {
+ char *line;
+
+ /* Print module name (and status, if wanted) */
+ line = Xasprintf ("%-12s", s_h->modname);
+ cvs_output (line, 0);
+ free (line);
+ if (status)
+ {
+ line = Xasprintf (" %-11s", s_h->status);
+ cvs_output (line, 0);
+ free (line);
+ }
+
+ /* Parse module file entry as command line and print options */
+ line = Xasprintf ("%s %s", s_h->modname, s_h->rest);
+ line2argv (&moduleargc, &moduleargv, line, " \t");
+ free (line);
+ argc = moduleargc;
+ argv = moduleargv;
+
+ optind = 0;
+ wid = 0;
+ while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
+ {
+ if (!status)
+ {
+ if (c == 'a' || c == 'l')
+ {
+ char buf[5];
+
+ sprintf (buf, " -%c", c);
+ cvs_output (buf, 0);
+ wid += 3; /* Could just set it to 3 */
+ }
+ else
+ {
+ char buf[10];
+
+ if (strlen (optarg) + 4 + wid > (unsigned) fill)
+ {
+ int j;
+
+ cvs_output ("\n", 1);
+ for (j = 0; j < indent; ++j)
+ cvs_output (" ", 1);
+ wid = 0;
+ }
+ sprintf (buf, " -%c ", c);
+ cvs_output (buf, 0);
+ cvs_output (optarg, 0);
+ wid += strlen (optarg) + 4;
+ }
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Format and Print all the files and directories */
+ for (; argc--; argv++)
+ {
+ if (strlen (*argv) + wid > (unsigned) fill)
+ {
+ int j;
+
+ cvs_output ("\n", 1);
+ for (j = 0; j < indent; ++j)
+ cvs_output (" ", 1);
+ wid = 0;
+ }
+ cvs_output (" ", 1);
+ cvs_output (*argv, 0);
+ wid += strlen (*argv) + 1;
+ }
+ cvs_output ("\n", 1);
+
+ /* Format the comment field -- save_d (), compressed spaces */
+ for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
+ {
+ int j;
+
+ for (j = 0; j < indent; ++j)
+ cvs_output (" ", 1);
+ cvs_output (" # ", 0);
+ if (strlen (cp2) < (unsigned) (fill - 2))
+ {
+ cvs_output (cp2, 0);
+ cvs_output ("\n", 1);
+ break;
+ }
+ cp += fill - 2;
+ while (*cp != ' ' && cp > cp2)
+ cp--;
+ if (cp == cp2)
+ {
+ cvs_output (cp2, 0);
+ cvs_output ("\n", 1);
+ break;
+ }
+
+ *cp++ = '\0';
+ cvs_output (cp2, 0);
+ cvs_output ("\n", 1);
+ }
+
+ free_names(&moduleargc, moduleargv);
+ /* FIXME-leak: here is where we would free s_h->modname, s_h->rest,
+ and if applicable, s_h->status. Not exactly a memory leak,
+ in the sense that we are about to exit(), but may be worth
+ noting if we ever do a multithreaded server or something of
+ the sort. */
+ }
+ /* FIXME-leak: as above, here is where we would free s_head. */
+}
diff --git a/src/ms-buffer.c b/src/ms-buffer.c
new file mode 100644
index 0000000..5bf49f5
--- /dev/null
+++ b/src/ms-buffer.c
@@ -0,0 +1,163 @@
+/* CVS client logging buffer.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "cvs.h"
+#include "buffer.h"
+#include "ms-buffer.h"
+
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+#ifdef PROXY_SUPPORT
+
+/* This structure is the closure field of a multi-source buffer. */
+struct ms_buffer
+{
+ /* Our buffer struct. */
+ struct buffer *buf;
+
+ /* The underlying buffers. */
+ struct buffer *cur;
+ List *bufs;
+
+ /* Whether we are in blocking mode or not. */
+ bool block;
+};
+
+
+
+/* The block function for a multi-source buffer. */
+static int
+ms_buffer_block (void *closure, bool block)
+{
+ struct ms_buffer *mb = closure;
+
+ mb->block = block;
+ if (block)
+ return set_block (mb->cur);
+ else
+ return set_nonblock (mb->cur);
+}
+
+
+
+/* The input function for a log buffer. */
+static int
+ms_buffer_input (void *closure, char *data, size_t need, size_t size,
+ size_t *got)
+{
+ struct ms_buffer *mb = closure;
+ int status;
+
+ assert (mb->cur->input);
+ status = (*mb->cur->input) (mb->cur->closure, data, need, size, got);
+ if (status == -1)
+ {
+ Node *p;
+ /* EOF. Set up the next buffer in line but return success and no
+ * data since our caller may have selected on the target to find
+ * ready data before calling us.
+ *
+ * If there are no more buffers, return EOF.
+ */
+ if (list_isempty (mb->bufs)) return -1;
+ buf_shutdown (mb->cur);
+ buf_free (mb->cur);
+ p = mb->bufs->list->next;
+ mb->cur = p->data;
+ p->delproc = NULL;
+ p->data = NULL;
+ delnode (p);
+ if (!buf_empty_p (mb->cur)) buf_append_buffer (mb->buf, mb->cur);
+ ms_buffer_block (closure, mb->block);
+ *got = 0;
+ status = 0;
+ }
+
+ return status;
+}
+
+
+
+/* Return the file descriptor underlying any child buffers. */
+static int
+ms_buffer_get_fd (void *closure)
+{
+ struct ms_buffer *mb = closure;
+ return buf_get_fd (mb->cur);
+}
+
+
+
+/* The shutdown function for a multi-source buffer. */
+static int
+ms_buffer_shutdown (struct buffer *buf)
+{
+ struct ms_buffer *mb = buf->closure;
+ Node *p;
+ int err = 0;
+
+ assert (mb->cur);
+ err += buf_shutdown (mb->cur);
+ buf_free (mb->cur);
+ for (p = mb->bufs->list->next; p != mb->bufs->list; p = p->next)
+ {
+ assert (p);
+ err += buf_shutdown (p->data);
+ }
+
+ dellist (&mb->bufs);
+ return err;
+}
+
+
+
+static void
+delbuflist (Node *p)
+{
+ if (p->data)
+ buf_free (p->data);
+}
+
+
+
+/* Create a multi-source buffer. This could easily be generalized to support
+ * any number of source buffers, but for now only two are necessary.
+ */
+struct buffer *
+ms_buffer_initialize (void (*memory) (struct buffer *),
+ struct buffer *buf, struct buffer *buf2/*, ...*/)
+{
+ struct ms_buffer *mb = xmalloc (sizeof *mb);
+ struct buffer *retbuf;
+ Node *p;
+
+ mb->block = false;
+ mb->cur = buf;
+ set_nonblock (buf);
+ mb->bufs = getlist ();
+ p = getnode ();
+ p->data = buf2;
+ p->delproc = delbuflist;
+ addnode (mb->bufs, p);
+ retbuf = buf_initialize (ms_buffer_input, NULL, NULL,
+ ms_buffer_block, ms_buffer_get_fd,
+ ms_buffer_shutdown, memory, mb);
+ if (!buf_empty_p (buf)) buf_append_buffer (retbuf, buf);
+ mb->buf = retbuf;
+
+ return retbuf;
+}
+#endif /* PROXY_SUPPORT */
+#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
diff --git a/src/ms-buffer.h b/src/ms-buffer.h
new file mode 100644
index 0000000..085fcc9
--- /dev/null
+++ b/src/ms-buffer.h
@@ -0,0 +1,22 @@
+/* CVS client logging buffer.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+
+#ifndef MS_BUFFER_H__
+# define MS_BUFFER_H__
+# ifdef PROXY_SUPPORT
+
+struct buffer *
+ms_buffer_initialize (void (*memory) (struct buffer *),
+ struct buffer *buf, struct buffer *buf2);
+# endif /* PROXY_SUPPORT */
+#endif /* MS_BUFFER_H__ */
diff --git a/src/myndbm.c b/src/myndbm.c
new file mode 100644
index 0000000..d7ef885
--- /dev/null
+++ b/src/myndbm.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * A simple ndbm-emulator for CVS. It parses a text file of the format:
+ *
+ * key value
+ *
+ * at dbm_open time, and loads the entire file into memory. As such, it is
+ * probably only good for fairly small modules files. Ours is about 30K in
+ * size, and this code works fine.
+ */
+
+#include "cvs.h"
+
+#include "getdelim.h"
+#include "getline.h"
+
+#ifdef MY_NDBM
+# ifndef O_ACCMODE
+# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+# endif /* defined O_ACCMODE */
+
+static void mydbm_load_file (FILE *, List *, char *);
+
+/* Returns NULL on error in which case errno has been set to indicate
+ the error. Can also call error() itself. */
+/* ARGSUSED */
+DBM *
+mydbm_open (char *file, int flags, int mode)
+{
+ FILE *fp;
+ DBM *db;
+
+ fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY
+ ? FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
+ if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
+ return NULL;
+
+ db = xmalloc (sizeof (*db));
+ db->dbm_list = getlist ();
+ db->modified = 0;
+ db->name = xstrdup (file);
+
+ if (fp != NULL)
+ {
+ mydbm_load_file (fp, db->dbm_list, file);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s",
+ primary_root_inverse_translate (file));
+ }
+ return db;
+}
+
+
+
+static int
+write_item (Node *node, void *data)
+{
+ FILE *fp = data;
+ fputs (node->key, fp);
+ fputs (" ", fp);
+ fputs (node->data, fp);
+ fputs ("\012", fp);
+ return 0;
+}
+
+
+
+void
+mydbm_close (DBM *db)
+{
+ if (db->modified)
+ {
+ FILE *fp;
+ fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE);
+ if (fp == NULL)
+ error (1, errno, "cannot write %s", db->name);
+ walklist (db->dbm_list, write_item, fp);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", db->name);
+ }
+ free (db->name);
+ dellist (&db->dbm_list);
+ free (db);
+}
+
+
+
+datum
+mydbm_fetch (DBM *db, datum key)
+{
+ Node *p;
+ char *s;
+ datum val;
+
+ /* make sure it's null-terminated */
+ s = xmalloc (key.dsize + 1);
+ (void) strncpy (s, key.dptr, key.dsize);
+ s[key.dsize] = '\0';
+
+ p = findnode (db->dbm_list, s);
+ if (p)
+ {
+ val.dptr = p->data;
+ val.dsize = strlen (p->data);
+ }
+ else
+ {
+ val.dptr = NULL;
+ val.dsize = 0;
+ }
+ free (s);
+ return val;
+}
+
+
+
+datum
+mydbm_firstkey (DBM *db)
+{
+ Node *head, *p;
+ datum key;
+
+ head = db->dbm_list->list;
+ p = head->next;
+ if (p != head)
+ {
+ key.dptr = p->key;
+ key.dsize = strlen (p->key);
+ }
+ else
+ {
+ key.dptr = NULL;
+ key.dsize = 0;
+ }
+ db->dbm_next = p->next;
+ return key;
+}
+
+
+
+datum
+mydbm_nextkey (DBM *db)
+{
+ Node *head, *p;
+ datum key;
+
+ head = db->dbm_list->list;
+ p = db->dbm_next;
+ if (p != head)
+ {
+ key.dptr = p->key;
+ key.dsize = strlen (p->key);
+ }
+ else
+ {
+ key.dptr = NULL;
+ key.dsize = 0;
+ }
+ db->dbm_next = p->next;
+ return key;
+}
+
+
+
+/* Note: only updates the in-memory copy, which is written out at
+ mydbm_close time. Note: Also differs from DBM in that on duplication,
+ it gives a warning, rather than either DBM_INSERT or DBM_REPLACE
+ behavior. */
+int
+mydbm_store (DBM *db, datum key, datum value, int flags)
+{
+ Node *node;
+
+ node = getnode ();
+ node->type = NDBMNODE;
+
+ node->key = xmalloc (key.dsize + 1);
+ *node->key = '\0';
+ strncat (node->key, key.dptr, key.dsize);
+
+ node->data = xmalloc (value.dsize + 1);
+ *(char *)node->data = '\0';
+ strncat (node->data, value.dptr, value.dsize);
+
+ db->modified = 1;
+ if (addnode (db->dbm_list, node) == -1)
+ {
+ error (0, 0, "attempt to insert duplicate key `%s'", node->key);
+ freenode (node);
+ return 0;
+ }
+ return 0;
+}
+
+
+
+/* Load a DBM file.
+ *
+ * INPUTS
+ * filename Used in error messages.
+ */
+static void
+mydbm_load_file (FILE *fp, List *list, char *filename)
+{
+ char *line = NULL;
+ size_t line_size;
+ char *value;
+ size_t value_allocated;
+ char *cp, *vp;
+ int cont;
+ int line_length;
+ int line_num;
+
+ value_allocated = 1;
+ value = xmalloc (value_allocated);
+
+ cont = 0;
+ line_num=0;
+ while ((line_length = getdelim (&line, &line_size, '\012', fp)) >= 0)
+ {
+ line_num++;
+ if (line_length > 0 && line[line_length - 1] == '\012')
+ {
+ /* Strip the newline. */
+ --line_length;
+ line[line_length] = '\0';
+ }
+ if (line_length > 0 && line[line_length - 1] == '\015')
+ {
+ /* If the file (e.g. modules) was written on an NT box, it will
+ contain CRLF at the ends of lines. Strip them (we can't do
+ this by opening the file in text mode because we might be
+ running on unix). */
+ --line_length;
+ line[line_length] = '\0';
+ }
+
+ /*
+ * Add the line to the value, at the end if this is a continuation
+ * line; otherwise at the beginning, but only after any trailing
+ * backslash is removed.
+ */
+ if (!cont)
+ value[0] = '\0';
+
+ /*
+ * See if the line we read is a continuation line, and strip the
+ * backslash if so.
+ */
+ if (line_length > 0)
+ cp = &line[line_length - 1];
+ else
+ cp = line;
+ if (*cp == '\\')
+ {
+ cont = 1;
+ *cp = '\0';
+ --line_length;
+ }
+ else
+ {
+ cont = 0;
+ }
+ expand_string (&value,
+ &value_allocated,
+ strlen (value) + line_length + 5);
+ strcat (value, line);
+
+ if (value[0] == '#')
+ continue; /* comment line */
+ vp = value;
+ while (*vp && isspace ((unsigned char) *vp))
+ vp++;
+ if (*vp == '\0')
+ continue; /* empty line */
+
+ /*
+ * If this was not a continuation line, add the entry to the database
+ */
+ if (!cont)
+ {
+ Node *p = getnode ();
+ char *kp;
+
+ kp = vp;
+ while (*vp && !isspace ((unsigned char) *vp))
+ vp++;
+ if (*vp)
+ *vp++ = '\0'; /* NULL terminate the key */
+ p->type = NDBMNODE;
+ p->key = xstrdup (kp);
+ while (*vp && isspace ((unsigned char) *vp))
+ vp++; /* skip whitespace to value */
+ if (*vp == '\0')
+ {
+ if (!really_quiet)
+ error (0, 0,
+ "warning: NULL value for key `%s' at line %d of `%s'",
+ p->key, line_num,
+ primary_root_inverse_translate (filename));
+ freenode (p);
+ continue;
+ }
+ p->data = xstrdup (vp);
+ if (addnode (list, p) == -1)
+ {
+ if (!really_quiet)
+ error (0, 0,
+ "duplicate key found for `%s' at line %d of `%s'",
+ p->key, line_num,
+ primary_root_inverse_translate (filename));
+ freenode (p);
+ }
+ }
+ }
+ if (line_length < 0 && !feof (fp))
+ error (0, errno, "cannot read file `%s' in mydbm_load_file",
+ primary_root_inverse_translate (filename));
+
+ free (line);
+ free (value);
+}
+
+#endif /* MY_NDBM */
diff --git a/src/myndbm.h b/src/myndbm.h
new file mode 100644
index 0000000..a3d807c
--- /dev/null
+++ b/src/myndbm.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef MY_NDBM
+
+#define DBLKSIZ 4096
+
+typedef struct
+{
+ List *dbm_list; /* cached database */
+ Node *dbm_next; /* next key to return for nextkey() */
+
+ /* Name of the file to write to if modified is set. malloc'd. */
+ char *name;
+
+ /* Nonzero if the database has been modified and dbm_close needs to
+ write it out to disk. */
+ int modified;
+} DBM;
+
+typedef struct
+{
+ char *dptr;
+ int dsize;
+} datum;
+
+/*
+ * So as not to conflict with other dbm_open, etc., routines that may
+ * be included by someone's libc, all of my emulation routines are prefixed
+ * by "my" and we define the "standard" ones to be "my" ones here.
+ */
+#define dbm_open mydbm_open
+#define dbm_close mydbm_close
+#define dbm_fetch mydbm_fetch
+#define dbm_firstkey mydbm_firstkey
+#define dbm_nextkey mydbm_nextkey
+#define dbm_store mydbm_store
+#define DBM_INSERT 0
+#define DBM_REPLACE 1
+
+DBM *mydbm_open (char *file, int flags, int mode);
+void mydbm_close (DBM * db);
+datum mydbm_fetch (DBM * db, datum key);
+datum mydbm_firstkey (DBM * db);
+datum mydbm_nextkey (DBM * db);
+extern int mydbm_store (DBM *, datum, datum, int);
+
+#endif /* MY_NDBM */
diff --git a/src/no_diff.c b/src/no_diff.c
new file mode 100644
index 0000000..9e6cfa7
--- /dev/null
+++ b/src/no_diff.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * No Difference
+ *
+ * The user file looks modified judging from its time stamp; however it needn't
+ * be. No_Difference() finds out whether it is or not. If it is not, it
+ * updates the administration.
+ *
+ * returns 0 if no differences are found and non-zero otherwise
+ */
+
+#include "cvs.h"
+#include <assert.h>
+
+int
+No_Difference (struct file_info *finfo, Vers_TS *vers)
+{
+ Node *p;
+ int ret;
+ char *ts, *options;
+ int retcode = 0;
+ char *tocvsPath;
+
+ /* If ts_user is "Is-modified", we can only conclude the files are
+ different (since we don't have the file's contents). */
+ if (vers->ts_user != NULL
+ && strcmp (vers->ts_user, "Is-modified") == 0)
+ return -1;
+
+ if (!vers->srcfile || !vers->srcfile->path)
+ return (-1); /* different since we couldn't tell */
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* If special files are in use, then any mismatch of file metadata
+ information also means that the files should be considered different. */
+ if (preserve_perms && special_file_mismatch (finfo, vers->vn_user, NULL))
+ return 1;
+#endif
+
+ if (vers->entdata && vers->entdata->options)
+ options = xstrdup (vers->entdata->options);
+ else
+ options = xstrdup ("");
+
+ tocvsPath = wrap_tocvs_process_file (finfo->file);
+ retcode = RCS_cmp_file (vers->srcfile, vers->vn_user, NULL, NULL, options,
+ tocvsPath == NULL ? finfo->file : tocvsPath);
+ if (retcode == 0)
+ {
+ /* no difference was found, so fix the entries file */
+ ts = time_stamp (finfo->file);
+ Register (finfo->entries, finfo->file,
+ vers->vn_user ? vers->vn_user : vers->vn_rcs, ts,
+ options, vers->tag, vers->date, NULL);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* We need to update the entries line on the client side. */
+ server_update_entries (finfo->file, finfo->update_dir,
+ finfo->repository, SERVER_UPDATED);
+ }
+#endif
+ free (ts);
+
+ /* update the entdata pointer in the vers_ts structure */
+ p = findnode (finfo->entries, finfo->file);
+ assert (p);
+ vers->entdata = p->data;
+
+ ret = 0;
+ }
+ else
+ ret = 1; /* files were really different */
+
+ if (tocvsPath)
+ {
+ /* Need to call unlink myself because the noexec variable
+ * has been set to 1. */
+ TRACE (TRACE_FUNCTION, "unlink (%s)", tocvsPath);
+ if ( CVS_UNLINK (tocvsPath) < 0)
+ error (0, errno, "could not remove %s", tocvsPath);
+ }
+
+ free (options);
+ return ret;
+}
diff --git a/src/parseinfo.c b/src/parseinfo.c
new file mode 100644
index 0000000..51e6873
--- /dev/null
+++ b/src/parseinfo.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+#include "history.h"
+
+/*
+ * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
+ * the first line in the file that matches the REPOSITORY, or if ALL != 0, any
+ * lines matching "ALL", or if no lines match, the last line matching
+ * "DEFAULT".
+ *
+ * Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure.
+ */
+int
+Parse_Info (const char *infofile, const char *repository, CALLPROC callproc,
+ int opt, void *closure)
+{
+ int err = 0;
+ FILE *fp_info;
+ char *infopath;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ char *default_value = NULL;
+ int default_line = 0;
+ char *expanded_value;
+ bool callback_done;
+ int line_number;
+ char *cp, *exp, *value;
+ const char *srepos;
+ const char *regex_err;
+
+ assert (repository);
+
+ if (!current_parsed_root)
+ {
+ /* XXX - should be error maybe? */
+ error (0, 0, "CVSROOT variable not set");
+ return 1;
+ }
+
+ /* find the info file and open it */
+ infopath = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, infofile);
+ fp_info = CVS_FOPEN (infopath, "r");
+ if (!fp_info)
+ {
+ /* If no file, don't do anything special. */
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", infopath);
+ free (infopath);
+ return 0;
+ }
+
+ /* strip off the CVSROOT if repository was absolute */
+ srepos = Short_Repository (repository);
+
+ TRACE (TRACE_FUNCTION, "Parse_Info (%s, %s, %s)",
+ infopath, srepos, (opt & PIOPT_ALL) ? "ALL" : "not ALL");
+
+ /* search the info file for lines that match */
+ callback_done = false;
+ line_number = 0;
+ while (getline (&line, &line_allocated, fp_info) >= 0)
+ {
+ line_number++;
+
+ /* skip lines starting with # */
+ if (line[0] == '#')
+ continue;
+
+ /* skip whitespace at beginning of line */
+ for (cp = line; *cp && isspace ((unsigned char) *cp); cp++)
+ ;
+
+ /* if *cp is null, the whole line was blank */
+ if (*cp == '\0')
+ continue;
+
+ /* the regular expression is everything up to the first space */
+ for (exp = cp; *cp && !isspace ((unsigned char) *cp); cp++)
+ ;
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ /* skip whitespace up to the start of the matching value */
+ while (*cp && isspace ((unsigned char) *cp))
+ cp++;
+
+ /* no value to match with the regular expression is an error */
+ if (*cp == '\0')
+ {
+ error (0, 0, "syntax error at line %d file %s; ignored",
+ line_number, infopath);
+ continue;
+ }
+ value = cp;
+
+ /* strip the newline off the end of the value */
+ cp = strrchr (value, '\n');
+ if (cp) *cp = '\0';
+
+ /*
+ * At this point, exp points to the regular expression, and value
+ * points to the value to call the callback routine with. Evaluate
+ * the regular expression against srepos and callback with the value
+ * if it matches.
+ */
+
+ /* save the default value so we have it later if we need it */
+ if (strcmp (exp, "DEFAULT") == 0)
+ {
+ if (default_value)
+ {
+ error (0, 0, "Multiple `DEFAULT' lines (%d and %d) in %s file",
+ default_line, line_number, infofile);
+ free (default_value);
+ }
+ default_value = xstrdup (value);
+ default_line = line_number;
+ continue;
+ }
+
+ /*
+ * For a regular expression of "ALL", do the callback always We may
+ * execute lots of ALL callbacks in addition to *one* regular matching
+ * callback or default
+ */
+ if (strcmp (exp, "ALL") == 0)
+ {
+ if (!(opt & PIOPT_ALL))
+ error (0, 0, "Keyword `ALL' is ignored at line %d in %s file",
+ line_number, infofile);
+ else if ((expanded_value =
+ expand_path (value, current_parsed_root->directory,
+ true, infofile, line_number)))
+ {
+ err += callproc (repository, expanded_value, closure);
+ free (expanded_value);
+ }
+ else
+ err++;
+ continue;
+ }
+
+ if (callback_done)
+ /* only first matching, plus "ALL"'s */
+ continue;
+
+ /* see if the repository matched this regular expression */
+ regex_err = re_comp (exp);
+ if (regex_err)
+ {
+ error (0, 0, "bad regular expression at line %d file %s: %s",
+ line_number, infofile, regex_err);
+ continue;
+ }
+ if (re_exec (srepos) == 0)
+ continue; /* no match */
+
+ /* it did, so do the callback and note that we did one */
+ expanded_value = expand_path (value, current_parsed_root->directory,
+ true, infofile, line_number);
+ if (expanded_value)
+ {
+ err += callproc (repository, expanded_value, closure);
+ free (expanded_value);
+ }
+ else
+ err++;
+ callback_done = true;
+ }
+ if (ferror (fp_info))
+ error (0, errno, "cannot read %s", infopath);
+ if (fclose (fp_info) < 0)
+ error (0, errno, "cannot close %s", infopath);
+
+ /* if we fell through and didn't callback at all, do the default */
+ if (!callback_done && default_value)
+ {
+ expanded_value = expand_path (default_value,
+ current_parsed_root->directory,
+ true, infofile, line_number);
+ if (expanded_value)
+ {
+ err += callproc (repository, expanded_value, closure);
+ free (expanded_value);
+ }
+ else
+ err++;
+ }
+
+ /* free up space if necessary */
+ if (default_value) free (default_value);
+ free (infopath);
+ if (line) free (line);
+
+ return err;
+}
+
+
+
+/* Print a warning and return false if P doesn't look like a string specifying
+ * something that can be converted into a size_t.
+ *
+ * Sets *VAL to the parsed value when it is found to be valid. *VAL will not
+ * be altered when false is returned.
+ */
+static bool
+readSizeT (const char *infopath, const char *option, const char *p,
+ size_t *val)
+{
+ const char *q;
+ size_t num, factor = 1;
+
+ if (!strcasecmp ("unlimited", p))
+ {
+ *val = SIZE_MAX;
+ return true;
+ }
+
+ /* Record the factor character (kilo, mega, giga, tera). */
+ if (!isdigit (p[strlen(p) - 1]))
+ {
+ switch (p[strlen(p) - 1])
+ {
+ case 'T':
+ factor = xtimes (factor, 1024);
+ case 'G':
+ factor = xtimes (factor, 1024);
+ case 'M':
+ factor = xtimes (factor, 1024);
+ case 'k':
+ factor = xtimes (factor, 1024);
+ break;
+ default:
+ error (0, 0,
+ "%s: Unknown %s factor: `%c'",
+ infopath, option, p[strlen(p)]);
+ return false;
+ }
+ TRACE (TRACE_DATA, "readSizeT(): Found factor %u for %s",
+ factor, option);
+ }
+
+ /* Verify that *q is a number. */
+ q = p;
+ while (q < p + strlen(p) - 1 /* Checked last character above. */)
+ {
+ if (!isdigit(*q))
+ {
+ error (0, 0,
+"%s: %s must be a postitive integer, not '%s'",
+ infopath, option, p);
+ return false;
+ }
+ q++;
+ }
+
+ /* Compute final value. */
+ num = strtoul (p, NULL, 10);
+ if (num == ULONG_MAX || num > SIZE_MAX)
+ /* Don't return an error, just max out. */
+ num = SIZE_MAX;
+
+ TRACE (TRACE_DATA, "readSizeT(): read number %u for %s", num, option);
+ *val = xtimes (strtoul (p, NULL, 10), factor);
+ TRACE (TRACE_DATA, "readSizeT(): returnning %u for %s", *val, option);
+ return true;
+}
+
+
+
+/* Allocate and initialize a new config struct. */
+static inline struct config *
+new_config (void)
+{
+ struct config *new = xcalloc (1, sizeof (struct config));
+
+ TRACE (TRACE_FLOW, "new_config ()");
+
+ new->logHistory = xstrdup (ALL_HISTORY_REC_TYPES);
+ new->RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS;
+ new->UserAdminOptions = xstrdup ("k");
+ new->MaxCommentLeaderLength = 20;
+#ifdef SERVER_SUPPORT
+ new->MaxCompressionLevel = 9;
+#endif /* SERVER_SUPPORT */
+#ifdef PROXY_SUPPORT
+ new->MaxProxyBufferSize = (size_t)(8 * 1024 * 1024); /* 8 megabytes,
+ * by default.
+ */
+#endif /* PROXY_SUPPORT */
+#ifdef AUTH_SERVER_SUPPORT
+ new->system_auth = true;
+#endif /* AUTH_SERVER_SUPPORT */
+
+ return new;
+}
+
+
+
+void
+free_config (struct config *data)
+{
+ if (data->keywords) free_keywords (data->keywords);
+ free (data);
+}
+
+
+
+/* Return true if this function has already been called for line LN of file
+ * INFOPATH.
+ */
+bool
+parse_error (const char *infopath, unsigned int ln)
+{
+ static List *errors = NULL;
+ char *nodename = NULL;
+
+ if (!errors)
+ errors = getlist();
+
+ nodename = Xasprintf ("%s/%u", infopath, ln);
+ if (findnode (errors, nodename))
+ {
+ free (nodename);
+ return true;
+ }
+
+ push_string (errors, nodename);
+ return false;
+}
+
+
+
+#ifdef ALLOW_CONFIG_OVERRIDE
+const char * const allowed_config_prefixes[] = { ALLOW_CONFIG_OVERRIDE };
+#endif /* ALLOW_CONFIG_OVERRIDE */
+
+
+
+/* Parse the CVS config file. The syntax right now is a bit ad hoc
+ * but tries to draw on the best or more common features of the other
+ * *info files and various unix (or non-unix) config file syntaxes.
+ * Lines starting with # are comments. Settings are lines of the form
+ * KEYWORD=VALUE. There is currently no way to have a multi-line
+ * VALUE (would be nice if there was, probably).
+ *
+ * CVSROOT is the $CVSROOT directory
+ * (current_parsed_root->directory might not be set yet, so this
+ * function takes the cvsroot as a function argument).
+ *
+ * RETURNS
+ * Always returns a fully initialized config struct, which on error may
+ * contain only the defaults.
+ *
+ * ERRORS
+ * Calls error(0, ...) on errors in addition to the return value.
+ *
+ * xmalloc() failures are fatal, per usual.
+ */
+struct config *
+parse_config (const char *cvsroot, const char *path)
+{
+ const char *infopath;
+ char *freeinfopath = NULL;
+ FILE *fp_info;
+ char *line = NULL;
+ unsigned int ln; /* Input file line counter. */
+ char *buf = NULL;
+ size_t buf_allocated = 0;
+ size_t len;
+ char *p;
+ struct config *retval;
+ /* PROCESSING Whether config keys are currently being processed for
+ * this root.
+ * PROCESSED Whether any keys have been processed for this root.
+ * This is initialized to true so that any initial keys
+ * may be processed as global defaults.
+ */
+ bool processing = true;
+ bool processed = true;
+
+ TRACE (TRACE_FUNCTION, "parse_config (%s)", cvsroot);
+
+#ifdef ALLOW_CONFIG_OVERRIDE
+ if (path)
+ {
+ const char * const *prefix;
+ char *npath = xcanonicalize_file_name (path);
+ bool approved = false;
+ for (prefix = allowed_config_prefixes; *prefix != NULL; prefix++)
+ {
+ char *nprefix;
+
+ if (!isreadable (*prefix)) continue;
+ nprefix = xcanonicalize_file_name (*prefix);
+ if (!strncmp (nprefix, npath, strlen (nprefix))
+ && (((*prefix)[strlen (*prefix)] != '/'
+ && strlen (npath) == strlen (nprefix))
+ || ((*prefix)[strlen (*prefix)] == '/'
+ && npath[strlen (nprefix)] == '/')))
+ approved = true;
+ free (nprefix);
+ if (approved) break;
+ }
+ if (!approved)
+ error (1, 0, "Invalid path to config file specified: `%s'",
+ path);
+ infopath = path;
+ free (npath);
+ }
+ else
+#endif
+ infopath = freeinfopath =
+ Xasprintf ("%s/%s/%s", cvsroot, CVSROOTADM, CVSROOTADM_CONFIG);
+
+ retval = new_config ();
+
+ fp_info = CVS_FOPEN (infopath, "r");
+ if (!fp_info)
+ {
+ /* If no file, don't do anything special. */
+ if (!existence_error (errno))
+ {
+ /* Just a warning message; doesn't affect return
+ value, currently at least. */
+ error (0, errno, "cannot open %s", infopath);
+ }
+ if (freeinfopath) free (freeinfopath);
+ return retval;
+ }
+
+ ln = 0; /* Have not read any lines yet. */
+ while (getline (&buf, &buf_allocated, fp_info) >= 0)
+ {
+ ln++; /* Keep track of input file line number for error messages. */
+
+ line = buf;
+
+ /* Skip leading white space. */
+ while (isspace (*line)) line++;
+
+ /* Skip comments. */
+ if (line[0] == '#')
+ continue;
+
+ /* Is there any kind of written standard for the syntax of this
+ sort of config file? Anywhere in POSIX for example (I guess
+ makefiles are sort of close)? Red Hat Linux has a bunch of
+ these too (with some GUI tools which edit them)...
+
+ Along the same lines, we might want a table of keywords,
+ with various types (boolean, string, &c), as a mechanism
+ for making sure the syntax is consistent. Any good examples
+ to follow there (Apache?)? */
+
+ /* Strip the trailing newline. There will be one unless we
+ read a partial line without a newline, and then got end of
+ file (or error?). */
+
+ len = strlen (line) - 1;
+ if (line[len] == '\n')
+ line[len--] = '\0';
+
+ /* Skip blank lines. */
+ if (line[0] == '\0')
+ continue;
+
+ TRACE (TRACE_DATA, "parse_info() examining line: `%s'", line);
+
+ /* Check for a root specification. */
+ if (line[0] == '[' && line[len] == ']')
+ {
+ cvsroot_t *tmproot;
+
+ line++[len] = '\0';
+ tmproot = parse_cvsroot (line);
+
+ /* Ignoring method. */
+ if (!tmproot
+#if defined CLIENT_SUPPORT || defined SERVER_SUPPORT
+ || (tmproot->method != local_method
+ && (!tmproot->hostname || !isThisHost (tmproot->hostname)))
+#endif /* CLIENT_SUPPORT || SERVER_SUPPORT */
+ || !isSamePath (tmproot->directory, cvsroot))
+ {
+ if (processed) processing = false;
+ }
+ else
+ {
+ TRACE (TRACE_FLOW, "Matched root section`%s'", line);
+ processing = true;
+ processed = false;
+ }
+
+ continue;
+ }
+
+ /* There is data on this line. */
+
+ /* Even if the data is bad or ignored, consider data processed for
+ * this root.
+ */
+ processed = true;
+
+ if (!processing)
+ /* ...but it is for a different root. */
+ continue;
+
+ /* The first '=' separates keyword from value. */
+ p = strchr (line, '=');
+ if (!p)
+ {
+ if (!parse_error (infopath, ln))
+ error (0, 0,
+"%s [%d]: syntax error: missing `=' between keyword and value",
+ infopath, ln);
+ continue;
+ }
+
+ *p++ = '\0';
+
+ if (strcmp (line, "RCSBIN") == 0)
+ {
+ /* This option used to specify the directory for RCS
+ executables. But since we don't run them any more,
+ this is a noop. Silently ignore it so that a
+ repository can work with either new or old CVS. */
+ ;
+ }
+ else if (strcmp (line, "SystemAuth") == 0)
+#ifdef AUTH_SERVER_SUPPORT
+ readBool (infopath, "SystemAuth", p, &retval->system_auth);
+#else
+ {
+ /* Still parse the syntax but ignore the option. That way the same
+ * config file can be used for local and server.
+ */
+ bool dummy;
+ readBool (infopath, "SystemAuth", p, &dummy);
+ }
+#endif
+ else if (strcmp (line, "LocalKeyword") == 0)
+ RCS_setlocalid (infopath, ln, &retval->keywords, p);
+ else if (strcmp (line, "KeywordExpand") == 0)
+ RCS_setincexc (&retval->keywords, p);
+ else if (strcmp (line, "PreservePermissions") == 0)
+ {
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ readBool (infopath, "PreservePermissions", p,
+ &retval->preserve_perms);
+#else
+ if (!parse_error (infopath, ln))
+ error (0, 0, "\
+%s [%u]: warning: this CVS does not support PreservePermissions",
+ infopath, ln);
+#endif
+ }
+ else if (strcmp (line, "TopLevelAdmin") == 0)
+ readBool (infopath, "TopLevelAdmin", p, &retval->top_level_admin);
+ else if (strcmp (line, "LockDir") == 0)
+ {
+ if (retval->lock_dir)
+ free (retval->lock_dir);
+ retval->lock_dir = expand_path (p, cvsroot, false, infopath, ln);
+ /* Could try some validity checking, like whether we can
+ opendir it or something, but I don't see any particular
+ reason to do that now rather than waiting until lock.c. */
+ }
+ else if (strcmp (line, "HistoryLogPath") == 0)
+ {
+ if (retval->HistoryLogPath) free (retval->HistoryLogPath);
+
+ /* Expand ~ & $VARs. */
+ retval->HistoryLogPath = expand_path (p, cvsroot, false,
+ infopath, ln);
+
+ if (retval->HistoryLogPath && !ISABSOLUTE (retval->HistoryLogPath))
+ {
+ error (0, 0, "%s [%u]: HistoryLogPath must be absolute.",
+ infopath, ln);
+ free (retval->HistoryLogPath);
+ retval->HistoryLogPath = NULL;
+ }
+ }
+ else if (strcmp (line, "HistorySearchPath") == 0)
+ {
+ if (retval->HistorySearchPath) free (retval->HistorySearchPath);
+ retval->HistorySearchPath = expand_path (p, cvsroot, false,
+ infopath, ln);
+
+ if (retval->HistorySearchPath
+ && !ISABSOLUTE (retval->HistorySearchPath))
+ {
+ error (0, 0, "%s [%u]: HistorySearchPath must be absolute.",
+ infopath, ln);
+ free (retval->HistorySearchPath);
+ retval->HistorySearchPath = NULL;
+ }
+ }
+ else if (strcmp (line, "LogHistory") == 0)
+ {
+ if (strcmp (p, "all") != 0)
+ {
+ static bool gotone = false;
+ if (gotone)
+ error (0, 0, "\
+%s [%u]: warning: duplicate LogHistory entry found.",
+ infopath, ln);
+ else
+ gotone = true;
+ free (retval->logHistory);
+ retval->logHistory = xstrdup (p);
+ }
+ }
+ else if (strcmp (line, "RereadLogAfterVerify") == 0)
+ {
+ if (!strcasecmp (p, "never"))
+ retval->RereadLogAfterVerify = LOGMSG_REREAD_NEVER;
+ else if (!strcasecmp (p, "always"))
+ retval->RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS;
+ else if (!strcasecmp (p, "stat"))
+ retval->RereadLogAfterVerify = LOGMSG_REREAD_STAT;
+ else
+ {
+ bool tmp;
+ if (readBool (infopath, "RereadLogAfterVerify", p, &tmp))
+ {
+ if (tmp)
+ retval->RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS;
+ else
+ retval->RereadLogAfterVerify = LOGMSG_REREAD_NEVER;
+ }
+ }
+ }
+ else if (strcmp (line, "TmpDir") == 0)
+ {
+ if (retval->TmpDir) free (retval->TmpDir);
+ retval->TmpDir = expand_path (p, cvsroot, false, infopath, ln);
+ /* Could try some validity checking, like whether we can
+ * opendir it or something, but I don't see any particular
+ * reason to do that now rather than when the first function
+ * tries to create a temp file.
+ */
+ }
+ else if (strcmp (line, "UserAdminOptions") == 0)
+ retval->UserAdminOptions = xstrdup (p);
+ else if (strcmp (line, "UseNewInfoFmtStrings") == 0)
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ readBool (infopath, "UseNewInfoFmtStrings", p,
+ &retval->UseNewInfoFmtStrings);
+#else /* !SUPPORT_OLD_INFO_FMT_STRINGS */
+ {
+ bool dummy;
+ if (readBool (infopath, "UseNewInfoFmtStrings", p, &dummy)
+ && !dummy)
+ error (1, 0,
+"%s [%u]: Old style info format strings not supported by this executable.",
+ infopath, ln);
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ else if (strcmp (line, "ImportNewFilesToVendorBranchOnly") == 0)
+ readBool (infopath, "ImportNewFilesToVendorBranchOnly", p,
+ &retval->ImportNewFilesToVendorBranchOnly);
+ else if (strcmp (line, "PrimaryServer") == 0)
+ retval->PrimaryServer = parse_cvsroot (p);
+#ifdef PROXY_SUPPORT
+ else if (!strcmp (line, "MaxProxyBufferSize"))
+ readSizeT (infopath, "MaxProxyBufferSize", p,
+ &retval->MaxProxyBufferSize);
+#endif /* PROXY_SUPPORT */
+ else if (!strcmp (line, "MaxCommentLeaderLength"))
+ readSizeT (infopath, "MaxCommentLeaderLength", p,
+ &retval->MaxCommentLeaderLength);
+ else if (!strcmp (line, "UseArchiveCommentLeader"))
+ readBool (infopath, "UseArchiveCommentLeader", p,
+ &retval->UseArchiveCommentLeader);
+#ifdef SERVER_SUPPORT
+ else if (!strcmp (line, "MinCompressionLevel"))
+ readSizeT (infopath, "MinCompressionLevel", p,
+ &retval->MinCompressionLevel);
+ else if (!strcmp (line, "MaxCompressionLevel"))
+ readSizeT (infopath, "MaxCompressionLevel", p,
+ &retval->MaxCompressionLevel);
+#endif /* SERVER_SUPPORT */
+ else
+ /* We may be dealing with a keyword which was added in a
+ subsequent version of CVS. In that case it is a good idea
+ to complain, as (1) the keyword might enable a behavior like
+ alternate locking behavior, in which it is dangerous and hard
+ to detect if some CVS's have it one way and others have it
+ the other way, (2) in general, having us not do what the user
+ had in mind when they put in the keyword violates the
+ principle of least surprise. Note that one corollary is
+ adding new keywords to your CVSROOT/config file is not
+ particularly recommended unless you are planning on using
+ the new features. */
+ if (!parse_error (infopath, ln))
+ error (0, 0, "%s [%u]: unrecognized keyword `%s'",
+ infopath, ln, line);
+ }
+ if (ferror (fp_info))
+ error (0, errno, "cannot read %s", infopath);
+ if (fclose (fp_info) < 0)
+ error (0, errno, "cannot close %s", infopath);
+ if (freeinfopath) free (freeinfopath);
+ if (buf) free (buf);
+
+ return retval;
+}
diff --git a/src/parseinfo.h b/src/parseinfo.h
new file mode 100644
index 0000000..136ef5e
--- /dev/null
+++ b/src/parseinfo.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2004 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and the Free Software Foundation
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS source
+ * distribution.
+ *
+ * This is the header file for definitions and functions shared by parseinfo.c
+ * with other portions of CVS.
+ */
+#ifndef PARSEINFO_H
+# define PARSEINFO_H
+
+struct config
+{
+ void *keywords;
+ bool top_level_admin;
+ char *lock_dir;
+ char *logHistory;
+ char *HistoryLogPath;
+ char *HistorySearchPath;
+ char *TmpDir;
+
+ /* Should the logmsg be re-read during the do_verify phase?
+ * RereadLogAfterVerify=no|stat|yes
+ * LOGMSG_REREAD_NEVER - never re-read the logmsg
+ * LOGMSG_REREAD_STAT - re-read the logmsg only if it has changed
+ * LOGMSG_REREAD_ALWAYS - always re-read the logmsg
+ */
+ int RereadLogAfterVerify;
+
+ char *UserAdminOptions;
+
+ /* Control default behavior of 'cvs import' (-X option on or off) in
+ * CVSROOT/config. Defaults to off, for backward compatibility.
+ */
+ bool ImportNewFilesToVendorBranchOnly;
+
+ size_t MaxCommentLeaderLength;
+ bool UseArchiveCommentLeader;
+
+#ifdef AUTH_SERVER_SUPPORT
+ /* Should we check for system usernames/passwords? */
+ bool system_auth;
+#endif /* AUTH_SERVER_SUPPORT */
+
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ bool UseNewInfoFmtStrings;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ cvsroot_t *PrimaryServer;
+#ifdef PROXY_SUPPORT
+ size_t MaxProxyBufferSize;
+#endif /* PROXY_SUPPORT */
+#ifdef SERVER_SUPPORT
+ size_t MinCompressionLevel;
+ size_t MaxCompressionLevel;
+#endif /* SERVER_SUPPORT */
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ bool preserve_perms;
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+};
+
+bool parse_error (const char *, unsigned int);
+struct config *parse_config (const char *, const char *);
+void free_config (struct config *data);
+#endif /* !PARSEINFO_H */
diff --git a/src/patch.c b/src/patch.c
new file mode 100644
index 0000000..a2f43f7
--- /dev/null
+++ b/src/patch.c
@@ -0,0 +1,846 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Patch
+ *
+ * Create a Larry Wall format "patch" file between a previous release and the
+ * current head of a module, or between two releases. Can specify the
+ * release as either a date or a revision number.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+static RETSIGTYPE patch_cleanup (int);
+static Dtype patch_dirproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int patch_fileproc (void *callerdat, struct file_info *finfo);
+static int patch_proc (int argc, char **argv, char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *mname, char *msg);
+
+static int force_tag_match = 1;
+static int patch_short = 0;
+static int toptwo_diffs = 0;
+static char *options = NULL;
+static char *rev1 = NULL;
+static int rev1_validated = 0;
+static char *rev2 = NULL;
+static int rev2_validated = 0;
+static char *date1 = NULL;
+static char *date2 = NULL;
+static char *tmpfile1 = NULL;
+static char *tmpfile2 = NULL;
+static char *tmpfile3 = NULL;
+static int unidiff = 0;
+
+static const char *const patch_usage[] =
+{
+ "Usage: %s %s [-flR] [-c|-u] [-s|-t] [-V %%d] [-k kopt]\n",
+ " -r rev|-D date [-r rev2 | -D date2] modules...\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-c\tContext diffs (default)\n",
+ "\t-u\tUnidiff format.\n",
+ "\t-s\tShort patch - one liner per file.\n",
+ "\t-t\tTop two diffs - last change made to the file.\n",
+ "\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n",
+ "\t-k kopt\tSpecify keyword expansion mode.\n",
+ "\t-D date\tDate.\n",
+ "\t-r rev\tRevision - symbolic or numeric.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+
+
+int
+patch (int argc, char **argv)
+{
+ register int i;
+ int local = 0;
+ int c;
+ int err = 0;
+ DBM *db;
+
+ if (argc == -1)
+ usage (patch_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+V:k:cuftsQqlRD:r:")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ cvs_cmd_name);
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 't':
+ toptwo_diffs = 1;
+ break;
+ case 's':
+ patch_short = 1;
+ break;
+ case 'D':
+ if (rev2 != NULL || date2 != NULL)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (rev1 != NULL || date1 != NULL)
+ date2 = Make_Date (optarg);
+ else
+ date1 = Make_Date (optarg);
+ break;
+ case 'r':
+ if (rev2 != NULL || date2 != NULL)
+ error (1, 0,
+ "no more than two revisions/dates can be specified");
+ if (rev1 != NULL || date1 != NULL)
+ rev2 = optarg;
+ else
+ rev1 = optarg;
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'V':
+ /* This option is pretty seriously broken:
+ 1. It is not clear what it does (does it change keyword
+ expansion behavior? If so, how? Or does it have
+ something to do with what version of RCS we are using?
+ Or the format we write RCS files in?).
+ 2. Because both it and -k use the options variable,
+ specifying both -V and -k doesn't work.
+ 3. At least as of CVS 1.9, it doesn't work (failed
+ assertion in RCS_checkout where it asserts that options
+ starts with -k). Few people seem to be complaining.
+ In the future (perhaps the near future), I have in mind
+ removing it entirely, and updating NEWS and cvs.texinfo,
+ but in case it is a good idea to give people more time
+ to complain if they would miss it, I'll just add this
+ quick and dirty error message for now. */
+ error (1, 0,
+ "the -V option is obsolete and should not be used");
+ break;
+ case 'u':
+ unidiff = 1; /* Unidiff */
+ break;
+ case 'c': /* Context diff */
+ unidiff = 0;
+ break;
+ case '?':
+ default:
+ usage (patch_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Sanity checks */
+ if (argc < 1)
+ usage (patch_usage);
+
+ if (toptwo_diffs && patch_short)
+ error (1, 0, "-t and -s options are mutually exclusive");
+ if (toptwo_diffs && (date1 != NULL || date2 != NULL ||
+ rev1 != NULL || rev2 != NULL))
+ error (1, 0, "must not specify revisions/dates with -t option!");
+
+ if (!toptwo_diffs && (date1 == NULL && date2 == NULL &&
+ rev1 == NULL && rev2 == NULL))
+ error (1, 0, "must specify at least one revision/date!");
+ if (date1 != NULL && date2 != NULL)
+ if (RCS_datecmp (date1, date2) >= 0)
+ error (1, 0, "second date must come after first date!");
+
+ /* if options is NULL, make it a NULL string */
+ if (options == NULL)
+ options = xstrdup ("");
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (local)
+ send_arg("-l");
+ if (!force_tag_match)
+ send_arg("-f");
+ if (toptwo_diffs)
+ send_arg("-t");
+ if (patch_short)
+ send_arg("-s");
+ if (unidiff)
+ send_arg("-u");
+
+ if (rev1)
+ option_with_arg ("-r", rev1);
+ if (date1)
+ client_senddate (date1);
+ if (rev2)
+ option_with_arg ("-r", rev2);
+ if (date2)
+ client_senddate (date2);
+ if (options[0] != '\0')
+ send_arg (options);
+
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ }
+
+ send_to_server ("rdiff\012", 0);
+ return get_responses_and_close ();
+ }
+#endif
+
+ /* clean up if we get a signal */
+#ifdef SIGABRT
+ (void)SIG_register (SIGABRT, patch_cleanup);
+#endif
+#ifdef SIGHUP
+ (void)SIG_register (SIGHUP, patch_cleanup);
+#endif
+#ifdef SIGINT
+ (void)SIG_register (SIGINT, patch_cleanup);
+#endif
+#ifdef SIGQUIT
+ (void)SIG_register (SIGQUIT, patch_cleanup);
+#endif
+#ifdef SIGPIPE
+ (void)SIG_register (SIGPIPE, patch_cleanup);
+#endif
+#ifdef SIGTERM
+ (void)SIG_register (SIGTERM, patch_cleanup);
+#endif
+
+ db = open_module ();
+ for (i = 0; i < argc; i++)
+ err += do_module (db, argv[i], PATCH, "Patching", patch_proc,
+ NULL, 0, local, 0, 0, NULL);
+ close_module (db);
+ free (options);
+ patch_cleanup (0);
+ return err;
+}
+
+
+
+/*
+ * callback proc for doing the real work of patching
+ */
+/* ARGSUSED */
+static int
+patch_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile,
+ int shorten, int local_specified, char *mname, char *msg)
+{
+ char *myargv[2];
+ int err = 0;
+ int which;
+ char *repository;
+ char *where;
+
+ TRACE ( TRACE_FUNCTION, "patch_proc ( %s, %s, %s, %d, %d, %s, %s )",
+ xwhere ? xwhere : "(null)",
+ mwhere ? mwhere : "(null)",
+ mfile ? mfile : "(null)",
+ shorten, local_specified,
+ mname ? mname : "(null)",
+ msg ? msg : "(null)" );
+
+ repository = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
+ (void)sprintf (repository, "%s/%s",
+ current_parsed_root->directory, argv[0]);
+ where = xmalloc (strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ + 1);
+ (void)strcpy (where, argv[0]);
+
+ /* if mfile isn't null, we need to set up to do only part of the module */
+ if (mfile != NULL)
+ {
+ char *cp;
+ char *path;
+
+ /* if the portion of the module is a path, put the dir part on repos */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = '\0';
+ (void)strcat (repository, "/");
+ (void)strcat (repository, mfile);
+ (void)strcat (where, "/");
+ (void)strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+ /* take care of the rest */
+ path = xmalloc (strlen (repository) + strlen (mfile) + 2);
+ (void)sprintf (path, "%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* directory means repository gets the dir tacked on */
+ (void)strcpy (repository, path);
+ (void)strcat (where, "/");
+ (void)strcat (where, mfile);
+ }
+ else
+ {
+ myargv[0] = argv[0];
+ myargv[1] = mfile;
+ argc = 2;
+ argv = myargv;
+ }
+ free (path);
+ }
+
+ /* cd to the starting repository */
+ if (CVS_CHDIR (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ free (repository);
+ free (where);
+ return 1;
+ }
+
+ if (force_tag_match)
+ which = W_REPOS | W_ATTIC;
+ else
+ which = W_REPOS;
+
+ if (rev1 != NULL && !rev1_validated)
+ {
+ tag_check_valid (rev1, argc - 1, argv + 1, local_specified, 0,
+ repository, false);
+ rev1_validated = 1;
+ }
+ if (rev2 != NULL && !rev2_validated)
+ {
+ tag_check_valid (rev2, argc - 1, argv + 1, local_specified, 0,
+ repository, false);
+ rev2_validated = 1;
+ }
+
+ /* start the recursion processor */
+ err = start_recursion (patch_fileproc, NULL, patch_dirproc, NULL, NULL,
+ argc - 1, argv + 1, local_specified,
+ which, 0, CVS_LOCK_READ, where, 1, repository );
+ free (repository);
+ free (where);
+
+ return err;
+}
+
+
+
+/*
+ * Called to examine a particular RCS file, as appropriate with the options
+ * that were set above.
+ */
+/* ARGSUSED */
+static int
+patch_fileproc (void *callerdat, struct file_info *finfo)
+{
+ struct utimbuf t;
+ char *vers_tag, *vers_head;
+ char *rcs = NULL;
+ char *rcs_orig = NULL;
+ RCSNode *rcsfile;
+ FILE *fp1, *fp2, *fp3;
+ int ret = 0;
+ int isattic = 0;
+ int retcode = 0;
+ char *file1;
+ char *file2;
+ char *strippath;
+ char *line1, *line2;
+ size_t line1_chars_allocated;
+ size_t line2_chars_allocated;
+ char *cp1, *cp2;
+ FILE *fp;
+ int line_length;
+ int dargc = 0;
+ size_t darg_allocated = 0;
+ char **dargv = NULL;
+
+ line1 = NULL;
+ line1_chars_allocated = 0;
+ line2 = NULL;
+ line2_chars_allocated = 0;
+ vers_tag = vers_head = NULL;
+
+ /* find the parsed rcs file */
+ if ((rcsfile = finfo->rcs) == NULL)
+ {
+ ret = 1;
+ goto out2;
+ }
+ if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
+ isattic = 1;
+
+ rcs_orig = rcs = Xasprintf ("%s%s", finfo->file, RCSEXT);
+
+ /* if vers_head is NULL, may have been removed from the release */
+ if (isattic && rev2 == NULL && date2 == NULL)
+ vers_head = NULL;
+ else
+ {
+ vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match,
+ NULL);
+ if (vers_head != NULL && RCS_isdead (rcsfile, vers_head))
+ {
+ free (vers_head);
+ vers_head = NULL;
+ }
+ }
+
+ if (toptwo_diffs)
+ {
+ if (vers_head == NULL)
+ {
+ ret = 1;
+ goto out2;
+ }
+
+ if (!date1)
+ date1 = xmalloc (MAXDATELEN);
+ *date1 = '\0';
+ if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == (time_t)-1)
+ {
+ if (!really_quiet)
+ error (0, 0, "cannot find date in rcs file %s revision %s",
+ rcs, vers_head);
+ ret = 1;
+ goto out2;
+ }
+ }
+ vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match, NULL);
+ if (vers_tag != NULL && RCS_isdead (rcsfile, vers_tag))
+ {
+ free (vers_tag);
+ vers_tag = NULL;
+ }
+
+ if ((vers_tag == NULL && vers_head == NULL) ||
+ (vers_tag != NULL && vers_head != NULL &&
+ strcmp (vers_head, vers_tag) == 0))
+ {
+ /* Nothing known about specified revs or
+ * not changed between releases.
+ */
+ ret = 0;
+ goto out2;
+ }
+
+ if (patch_short && (vers_tag == NULL || vers_head == NULL))
+ {
+ /* For adds & removes with a short patch requested, we can print our
+ * error message now and get out.
+ */
+ cvs_output ("File ", 0);
+ cvs_output (finfo->fullname, 0);
+ if (vers_tag == NULL)
+ {
+ cvs_output (" is new; ", 0);
+ cvs_output (rev2 ? rev2 : date2 ? date2 : "current", 0);
+ cvs_output (" revision ", 0);
+ cvs_output (vers_head, 0);
+ cvs_output ("\n", 1);
+ }
+ else
+ {
+ cvs_output (" is removed; ", 0);
+ cvs_output (rev1 ? rev1 : date1, 0);
+ cvs_output (" revision ", 0);
+ cvs_output (vers_tag, 0);
+ cvs_output ("\n", 1);
+ }
+ ret = 0;
+ goto out2;
+ }
+
+ /* Create 3 empty files. I'm not really sure there is any advantage
+ * to doing so now rather than just waiting until later.
+ *
+ * There is - cvs_temp_file opens the file so that it can guarantee that
+ * we have exclusive write access to the file. Unfortunately we spoil that
+ * by closing it and reopening it again. Of course any better solution
+ * requires that the RCS functions accept open file pointers rather than
+ * simple file names.
+ */
+ if ((fp1 = cvs_temp_file (&tmpfile1)) == NULL)
+ {
+ error (0, errno, "cannot create temporary file %s", tmpfile1);
+ ret = 1;
+ goto out;
+ }
+ else
+ if (fclose (fp1) < 0)
+ error (0, errno, "warning: cannot close %s", tmpfile1);
+ if ((fp2 = cvs_temp_file (&tmpfile2)) == NULL)
+ {
+ error (0, errno, "cannot create temporary file %s", tmpfile2);
+ ret = 1;
+ goto out;
+ }
+ else
+ if (fclose (fp2) < 0)
+ error (0, errno, "warning: cannot close %s", tmpfile2);
+ if ((fp3 = cvs_temp_file (&tmpfile3)) == NULL)
+ {
+ error (0, errno, "cannot create temporary file %s", tmpfile3);
+ ret = 1;
+ goto out;
+ }
+ else
+ if (fclose (fp3) < 0)
+ error (0, errno, "warning: cannot close %s", tmpfile3);
+
+ if (vers_tag != NULL)
+ {
+ retcode = RCS_checkout (rcsfile, NULL, vers_tag, rev1, options,
+ tmpfile1, NULL, NULL);
+ if (retcode != 0)
+ {
+ error (0, 0,
+ "cannot check out revision %s of %s", vers_tag, rcs);
+ ret = 1;
+ goto out;
+ }
+ memset ((char *) &t, 0, sizeof (t));
+ if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag,
+ NULL, 0)) != -1)
+ /* I believe this timestamp only affects the dates in our diffs,
+ and therefore should be on the server, not the client. */
+ (void)utime (tmpfile1, &t);
+ }
+ else if (toptwo_diffs)
+ {
+ ret = 1;
+ goto out;
+ }
+ if (vers_head != NULL)
+ {
+ retcode = RCS_checkout (rcsfile, NULL, vers_head, rev2, options,
+ tmpfile2, NULL, NULL);
+ if (retcode != 0)
+ {
+ error (0, 0,
+ "cannot check out revision %s of %s", vers_head, rcs);
+ ret = 1;
+ goto out;
+ }
+ if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head,
+ NULL, 0)) != -1)
+ /* I believe this timestamp only affects the dates in our diffs,
+ and therefore should be on the server, not the client. */
+ (void)utime (tmpfile2, &t);
+ }
+
+ if (unidiff) run_add_arg_p (&dargc, &darg_allocated, &dargv, "-u");
+ else run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c");
+ switch (diff_exec (tmpfile1, tmpfile2, NULL, NULL, dargc, dargv,
+ tmpfile3))
+ {
+ case -1: /* fork/wait failure */
+ error (1, errno, "fork for diff failed on %s", rcs);
+ break;
+ case 0: /* nothing to do */
+ break;
+ case 1:
+ /*
+ * The two revisions are really different, so read the first two
+ * lines of the diff output file, and munge them to include more
+ * reasonable file names that "patch" will understand, unless the
+ * user wanted a short patch. In that case, just output the short
+ * message.
+ */
+ if (patch_short)
+ {
+ cvs_output ("File ", 0);
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" changed from revision ", 0);
+ cvs_output (vers_tag, 0);
+ cvs_output (" to ", 0);
+ cvs_output (vers_head, 0);
+ cvs_output ("\n", 1);
+ ret = 0;
+ goto out;
+ }
+
+ /* Output an "Index:" line for patch to use */
+ cvs_output ("Index: ", 0);
+ cvs_output (finfo->fullname, 0);
+ cvs_output ("\n", 1);
+
+ /* Now the munging. */
+ fp = xfopen (tmpfile3, "r");
+ if (getline (&line1, &line1_chars_allocated, fp) < 0 ||
+ getline (&line2, &line2_chars_allocated, fp) < 0)
+ {
+ if (feof (fp))
+ error (0, 0, "\
+failed to read diff file header %s for %s: end of file", tmpfile3, rcs);
+ else
+ error (0, errno,
+ "failed to read diff file header %s for %s",
+ tmpfile3, rcs);
+ ret = 1;
+ if (fclose (fp) < 0)
+ error (0, errno, "error closing %s", tmpfile3);
+ goto out;
+ }
+ if (!unidiff)
+ {
+ if (strncmp (line1, "*** ", 4) != 0 ||
+ strncmp (line2, "--- ", 4) != 0 ||
+ (cp1 = strchr (line1, '\t')) == NULL ||
+ (cp2 = strchr (line2, '\t')) == NULL)
+ {
+ error (0, 0, "invalid diff header for %s", rcs);
+ ret = 1;
+ if (fclose (fp) < 0)
+ error (0, errno, "error closing %s", tmpfile3);
+ goto out;
+ }
+ }
+ else
+ {
+ if (strncmp (line1, "--- ", 4) != 0 ||
+ strncmp (line2, "+++ ", 4) != 0 ||
+ (cp1 = strchr (line1, '\t')) == NULL ||
+ (cp2 = strchr (line2, '\t')) == NULL)
+ {
+ error (0, 0, "invalid unidiff header for %s", rcs);
+ ret = 1;
+ if (fclose (fp) < 0)
+ error (0, errno, "error closing %s", tmpfile3);
+ goto out;
+ }
+ }
+ assert (current_parsed_root != NULL);
+ assert (current_parsed_root->directory != NULL);
+
+ strippath = Xasprintf ("%s/", current_parsed_root->directory);
+
+ if (strncmp (rcs, strippath, strlen (strippath)) == 0)
+ rcs += strlen (strippath);
+ free (strippath);
+ if (vers_tag != NULL)
+ file1 = Xasprintf ("%s:%s", finfo->fullname, vers_tag);
+ else
+ file1 = xstrdup (DEVNULL);
+
+ file2 = Xasprintf ("%s:%s", finfo->fullname,
+ vers_head ? vers_head : "removed");
+
+ /* Note that the string "diff" is specified by POSIX (for -c)
+ and is part of the diff output format, not the name of a
+ program. */
+ if (unidiff)
+ {
+ cvs_output ("diff -u ", 0);
+ cvs_output (file1, 0);
+ cvs_output (" ", 1);
+ cvs_output (file2, 0);
+ cvs_output ("\n", 1);
+
+ cvs_output ("--- ", 0);
+ cvs_output (file1, 0);
+ cvs_output (cp1, 0);
+ cvs_output ("+++ ", 0);
+ }
+ else
+ {
+ cvs_output ("diff -c ", 0);
+ cvs_output (file1, 0);
+ cvs_output (" ", 1);
+ cvs_output (file2, 0);
+ cvs_output ("\n", 1);
+
+ cvs_output ("*** ", 0);
+ cvs_output (file1, 0);
+ cvs_output (cp1, 0);
+ cvs_output ("--- ", 0);
+ }
+
+ cvs_output (finfo->fullname, 0);
+ cvs_output (cp2, 0);
+
+ /* spew the rest of the diff out */
+ while ((line_length
+ = getline (&line1, &line1_chars_allocated, fp))
+ >= 0)
+ cvs_output (line1, 0);
+ if (line_length < 0 && !feof (fp))
+ error (0, errno, "cannot read %s", tmpfile3);
+
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", tmpfile3);
+ free (file1);
+ free (file2);
+ break;
+ default:
+ error (0, 0, "diff failed for %s", finfo->fullname);
+ }
+ out:
+ if (line1)
+ free (line1);
+ if (line2)
+ free (line2);
+ if (CVS_UNLINK (tmpfile1) < 0)
+ error (0, errno, "cannot unlink %s", tmpfile1);
+ if (CVS_UNLINK (tmpfile2) < 0)
+ error (0, errno, "cannot unlink %s", tmpfile2);
+ if (CVS_UNLINK (tmpfile3) < 0)
+ error (0, errno, "cannot unlink %s", tmpfile3);
+ free (tmpfile1);
+ free (tmpfile2);
+ free (tmpfile3);
+ tmpfile1 = tmpfile2 = tmpfile3 = NULL;
+ if (darg_allocated)
+ {
+ run_arg_free_p (dargc, dargv);
+ free (dargv);
+ }
+
+ out2:
+ if (vers_tag != NULL)
+ free (vers_tag);
+ if (vers_head != NULL)
+ free (vers_head);
+ if (rcs_orig)
+ free (rcs_orig);
+ return ret;
+}
+
+
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+patch_dirproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+ if (!quiet)
+ error (0, 0, "Diffing %s", update_dir);
+ return R_PROCESS;
+}
+
+
+
+/*
+ * Clean up temporary files
+ */
+static RETSIGTYPE
+patch_cleanup (int sig)
+{
+ /* Note that the checks for existence_error are because we are
+ called from a signal handler, without SIG_begincrsect, so
+ we don't know whether the files got created. */
+
+ if (tmpfile1 != NULL)
+ {
+ if (unlink_file (tmpfile1) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile1);
+ free (tmpfile1);
+ }
+ if (tmpfile2 != NULL)
+ {
+ if (unlink_file (tmpfile2) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile2);
+ free (tmpfile2);
+ }
+ if (tmpfile3 != NULL)
+ {
+ if (unlink_file (tmpfile3) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile3);
+ free (tmpfile3);
+ }
+ tmpfile1 = tmpfile2 = tmpfile3 = NULL;
+
+ if (sig != 0)
+ {
+ const char *name;
+ char temp[10];
+
+ switch (sig)
+ {
+#ifdef SIGABRT
+ case SIGABRT:
+ name = "abort";
+ break;
+#endif
+#ifdef SIGHUP
+ case SIGHUP:
+ name = "hangup";
+ break;
+#endif
+#ifdef SIGINT
+ case SIGINT:
+ name = "interrupt";
+ break;
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT:
+ name = "quit";
+ break;
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE:
+ name = "broken pipe";
+ break;
+#endif
+#ifdef SIGTERM
+ case SIGTERM:
+ name = "termination";
+ break;
+#endif
+ default:
+ /* This case should never be reached, because we list
+ above all the signals for which we actually establish a
+ signal handler. */
+ sprintf (temp, "%d", sig);
+ name = temp;
+ break;
+ }
+ error (0, 0, "received %s signal", name);
+ }
+}
diff --git a/src/rcs.c b/src/rcs.c
new file mode 100644
index 0000000..8a26046
--- /dev/null
+++ b/src/rcs.c
@@ -0,0 +1,8878 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * The routines contained in this file do all the rcs file parsing and
+ * manipulation
+ */
+
+#include "cvs.h"
+#include "edit.h"
+#include "hardlink.h"
+
+/* These need to be source after cvs.h or HAVE_MMAP won't be set... */
+#ifdef HAVE_MMAP
+# include "getpagesize.h"
+# include <sys/mman.h>
+
+/* Define MAP_FILE when it isn't otherwise. */
+# ifndef MAP_FILE
+# define MAP_FILE 0
+# endif
+/* Define MAP_FAILED for old systems which neglect to. */
+# ifndef MAP_FAILED
+# define MAP_FAILED ((void *)-1)
+# endif
+#endif
+
+/* The RCS -k options, and a set of enums that must match the array.
+ These come first so that we can use enum kflag in function
+ prototypes. */
+static const char *const kflags[] =
+ {"kv", "kvl", "k", "v", "o", "b", NULL};
+enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
+
+/* A structure we use to buffer the contents of an RCS file. The
+ various fields are only referenced directly by the rcsbuf_*
+ functions. We declare the struct here so that we can allocate it
+ on the stack, rather than in memory. */
+
+struct rcsbuffer
+{
+ /* Points to the current position in the buffer. */
+ char *ptr;
+ /* Points just after the last valid character in the buffer. */
+ char *ptrend;
+ /* The file. */
+ FILE *fp;
+ /* The name of the file, used for error messages. */
+ const char *filename;
+ /* The starting file position of the data in the buffer. */
+ unsigned long pos;
+ /* The length of the value. */
+ size_t vlen;
+ /* Whether the value contains an '@' string. If so, we can not
+ compress whitespace characters. */
+ int at_string;
+ /* The number of embedded '@' characters in an '@' string. If
+ this is non-zero, we must search the string for pairs of '@'
+ and convert them to a single '@'. */
+ int embedded_at;
+};
+
+static RCSNode *RCS_parsercsfile_i (FILE * fp, const char *rcsfile);
+static char *RCS_getdatebranch (RCSNode * rcs, const char *date,
+ const char *branch);
+static void rcsbuf_open (struct rcsbuffer *, FILE *fp,
+ const char *filename, unsigned long pos);
+static void rcsbuf_close (struct rcsbuffer *);
+static int rcsbuf_getkey (struct rcsbuffer *, char **keyp, char **valp);
+static int rcsbuf_getrevnum (struct rcsbuffer *, char **revp);
+static char *rcsbuf_fill (struct rcsbuffer *, char *ptr, char **keyp,
+ char **valp);
+static int rcsbuf_valcmp (struct rcsbuffer *);
+static char *rcsbuf_valcopy (struct rcsbuffer *, char *val, int polish,
+ size_t *lenp);
+static void rcsbuf_valpolish (struct rcsbuffer *, char *val, int polish,
+ size_t *lenp);
+static void rcsbuf_valpolish_internal (struct rcsbuffer *, char *to,
+ const char *from, size_t *lenp);
+static off_t rcsbuf_ftello (struct rcsbuffer *);
+static void rcsbuf_get_buffered (struct rcsbuffer *, char **datap,
+ size_t *lenp);
+static void rcsbuf_cache (RCSNode *, struct rcsbuffer *);
+static void rcsbuf_cache_close (void);
+static void rcsbuf_cache_open (RCSNode *, off_t, FILE **, struct rcsbuffer *);
+static int checkmagic_proc (Node *p, void *closure);
+static void do_branches (List * list, char *val);
+static void do_symbols (List * list, char *val);
+static void do_locks (List * list, char *val);
+static void free_rcsnode_contents (RCSNode *);
+static void free_rcsvers_contents (RCSVers *);
+static void rcsvers_delproc (Node * p);
+static char *translate_symtag (RCSNode *, const char *);
+static char *RCS_addbranch (RCSNode *, const char *);
+static char *truncate_revnum_in_place (char *);
+static char *truncate_revnum (const char *);
+static char *printable_date (const char *);
+static char *escape_keyword_value (const char *, int *);
+static void expand_keywords (RCSNode *, RCSVers *, const char *,
+ const char *, size_t, enum kflag, char *,
+ size_t, char **, size_t *);
+static void cmp_file_buffer (void *, const char *, size_t);
+
+/* Routines for reading, parsing and writing RCS files. */
+static RCSVers *getdelta (struct rcsbuffer *, char *, char **, char **);
+static Deltatext *RCS_getdeltatext (RCSNode *, FILE *, struct rcsbuffer *);
+static void freedeltatext (Deltatext *);
+
+static void RCS_putadmin (RCSNode *, FILE *);
+static void RCS_putdtree (RCSNode *, char *, FILE *);
+static void RCS_putdesc (RCSNode *, FILE *);
+static void putdelta (RCSVers *, FILE *);
+static int putrcsfield_proc (Node *, void *);
+static int putsymbol_proc (Node *, void *);
+static void RCS_copydeltas (RCSNode *, FILE *, struct rcsbuffer *, FILE *,
+ Deltatext *, char *);
+static int count_delta_actions (Node *, void *);
+static void putdeltatext (FILE *, Deltatext *);
+
+static FILE *rcs_internal_lockfile (char *);
+static void rcs_internal_unlockfile (FILE *, char *);
+static char *rcs_lockfilename (const char *);
+
+/* The RCS file reading functions are called a lot, and they do some
+ string comparisons. This macro speeds things up a bit by skipping
+ the function call when the first characters are different. It
+ evaluates its arguments multiple times. */
+#define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
+
+static char * getfullCVSname (char *, char **);
+
+/*
+ * We don't want to use isspace() from the C library because:
+ *
+ * 1. The definition of "whitespace" in RCS files includes ASCII
+ * backspace, but the C locale doesn't.
+ * 2. isspace is an very expensive function call in some implementations
+ * due to the addition of wide character support.
+ */
+static const char spacetab[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
+};
+
+#define whitespace(c) (spacetab[(unsigned char)c] != 0)
+
+static char *rcs_lockfile = NULL;
+static int rcs_lockfd = -1;
+
+
+
+/*
+ * char *
+ * locate_rcs ( const char* file, const char *repository , int *inattic )
+ *
+ * Find an RCS file in the repository, case insensitively when the cased name
+ * doesn't exist, we are running as the server, and a client has asked us to
+ * ignore case.
+ *
+ * Most parts of CVS will want to rely instead on RCS_parse which calls this
+ * function and is called by recurse.c which then puts the result in useful
+ * places like the rcs field of struct file_info.
+ *
+ * INPUTS
+ *
+ * repository the repository (including the directory)
+ * file the filename within that directory (without RCSEXT).
+ * inattic NULL or a pointer to the output boolean
+ *
+ * OUTPUTS
+ *
+ * inattic If this input was non-null, the destination will be
+ * set to true if the file was found in the attic or
+ * false if not. If no RCS file is found, this value
+ * is undefined.
+ *
+ * RETURNS
+ *
+ * a newly-malloc'd array containing the absolute pathname of the RCS
+ * file that was found or NULL when none was found.
+ *
+ * ERRORS
+ *
+ * errno can be set by the return value of the final call to
+ * locate_file_in_dir(). This should resolve to the system's existence error
+ * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
+ * the Attic was found but no matching files were found in the Attic or its
+ * parent.
+ */
+static char *
+locate_rcs (const char *repository, const char *file, int *inattic)
+{
+ char *retval;
+
+ /* First, try to find the file as cased. */
+ retval = xmalloc (strlen (repository)
+ + sizeof (CVSATTIC)
+ + strlen (file)
+ + sizeof (RCSEXT)
+ + 3);
+ sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
+ if (isreadable (retval))
+ {
+ if (inattic)
+ *inattic = 0;
+ return retval;
+ }
+ sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
+ if (isreadable (retval))
+ {
+ if (inattic)
+ *inattic = 1;
+ return retval;
+ }
+ free (retval);
+
+ return NULL;
+}
+
+
+
+/* A few generic thoughts on error handling, in particular the
+ printing of unexpected characters that we find in the RCS file
+ (that is, why we use '\x%x' rather than %c or some such).
+
+ * Avoiding %c means we don't have to worry about what is printable
+ and other such stuff. In error handling, often better to keep it
+ simple.
+
+ * Hex rather than decimal or octal because character set standards
+ tend to use hex.
+
+ * Saying "character 0x%x" might make it sound like we are printing
+ a file offset. So we use '\x%x'.
+
+ * Would be nice to print the offset within the file, but I can
+ imagine various portability hassles (in particular, whether
+ unsigned long is always big enough to hold file offsets). */
+
+/* Parse an rcsfile given a user file name and a repository. If there is
+ an error, we print an error message and return NULL. If the file
+ does not exist, we return NULL without printing anything (I'm not
+ sure this allows the caller to do anything reasonable, but it is
+ the current behavior). */
+RCSNode *
+RCS_parse (const char *file, const char *repos)
+{
+ RCSNode *rcs;
+ FILE *fp;
+ RCSNode *retval = NULL;
+ char *rcsfile;
+ int inattic;
+
+ /* We're creating a new RCSNode, so there is no hope of finding it
+ in the cache. */
+ rcsbuf_cache_close ();
+
+ if (!(rcsfile = locate_rcs (repos, file, &inattic)))
+ {
+ /* Handle the error cases */
+ }
+ else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)))
+ {
+ rcs = RCS_parsercsfile_i (fp, rcsfile);
+ if (rcs)
+ {
+ rcs->flags |= VALID;
+ if (inattic)
+ rcs->flags |= INATTIC;
+ }
+
+ free (rcsfile);
+ retval = rcs;
+ }
+ else if (!existence_error (errno))
+ {
+ error (0, errno, "cannot open `%s'", rcsfile);
+ free (rcsfile);
+ }
+
+ return retval;
+}
+
+
+
+/*
+ * Parse a specific rcsfile.
+ */
+RCSNode *
+RCS_parsercsfile (const char *rcsfile)
+{
+ FILE *fp;
+ RCSNode *rcs;
+
+ /* We're creating a new RCSNode, so there is no hope of finding it
+ in the cache. */
+ rcsbuf_cache_close ();
+
+ /* open the rcsfile */
+ if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
+ {
+ error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
+ return NULL;
+ }
+
+ rcs = RCS_parsercsfile_i (fp, rcsfile);
+
+ return rcs;
+}
+
+
+
+/*
+ */
+static RCSNode *
+RCS_parsercsfile_i (FILE *fp, const char *rcsfile)
+{
+ RCSNode *rdata;
+ struct rcsbuffer rcsbuf;
+ char *key, *value;
+
+ /* make a node */
+ rdata = xmalloc (sizeof (RCSNode));
+ memset (rdata, 0, sizeof (RCSNode));
+ rdata->refcount = 1;
+ rdata->path = xstrdup (rcsfile);
+ rdata->print_path = xstrdup (primary_root_inverse_translate (rcsfile));
+
+ /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
+
+ Most cvs operations on the main branch don't need any more
+ information. Those that do call RCS_reparsercsfile to parse
+ the rest of the header and the deltas. */
+
+ rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
+
+ if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ goto l_error;
+ if (STREQ (key, RCSDESC))
+ goto l_error;
+
+ if (STREQ (RCSHEAD, key) && value != NULL)
+ rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
+
+ if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ goto l_error;
+ if (STREQ (key, RCSDESC))
+ goto l_error;
+
+ if (STREQ (RCSBRANCH, key) && value != NULL)
+ {
+ char *cp;
+
+ rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
+ if ((numdots (rdata->branch) & 1) != 0)
+ {
+ /* turn it into a branch if it's a revision */
+ cp = strrchr (rdata->branch, '.');
+ *cp = '\0';
+ }
+ }
+
+ /* Look ahead for expand, stopping when we see desc or a revision
+ number. */
+ while (1)
+ {
+ char *cp;
+
+ if (STREQ (RCSEXPAND, key))
+ {
+ rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
+ break;
+ }
+
+ for (cp = key;
+ (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
+ cp++)
+ /* do nothing */ ;
+ if (*cp == '\0')
+ break;
+
+ if (STREQ (RCSDESC, key))
+ break;
+
+ if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ break;
+ }
+
+ rdata->flags |= PARTIAL;
+
+ rcsbuf_cache (rdata, &rcsbuf);
+
+ return rdata;
+
+l_error:
+ error (0, 0, "`%s' does not appear to be a valid rcs file",
+ rcsfile);
+ rcsbuf_close (&rcsbuf);
+ freercsnode (&rdata);
+ fclose (fp);
+ return NULL;
+}
+
+
+
+/* Do the real work of parsing an RCS file.
+
+ On error, die with a fatal error; if it returns at all it was successful.
+
+ If PFP is NULL, close the file when done. Otherwise, leave it open
+ and store the FILE * in *PFP. */
+void
+RCS_reparsercsfile (RCSNode *rdata, FILE **pfp, struct rcsbuffer *rcsbufp)
+{
+ FILE *fp;
+ char *rcsfile;
+ struct rcsbuffer rcsbuf;
+ Node *q, *kv;
+ RCSVers *vnode;
+ int gotkey;
+ char *cp;
+ char *key, *value;
+
+ assert (rdata != NULL);
+ rcsfile = rdata->path;
+
+ rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
+
+ /* make a node */
+ /* This probably shouldn't be done until later: if a file has an
+ empty revision tree (which is permissible), rdata->versions
+ should be NULL. -twp */
+ rdata->versions = getlist ();
+
+ /*
+ * process all the special header information, break out when we get to
+ * the first revision delta
+ */
+ gotkey = 0;
+ for (;;)
+ {
+ /* get the next key/value pair */
+ if (!gotkey)
+ {
+ if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ {
+ error (1, 0, "`%s' does not appear to be a valid rcs file",
+ rcsfile);
+ }
+ }
+
+ gotkey = 0;
+
+ /* Skip head, branch and expand tags; we already have them. */
+ if (STREQ (key, RCSHEAD)
+ || STREQ (key, RCSBRANCH)
+ || STREQ (key, RCSEXPAND))
+ {
+ continue;
+ }
+
+ if (STREQ (key, "access"))
+ {
+ if (value != NULL)
+ {
+ /* We pass the POLISH parameter as 1 because
+ RCS_addaccess expects nothing but spaces. FIXME:
+ It would be easy and more efficient to change
+ RCS_addaccess. */
+ if (rdata->access)
+ {
+ error (0, 0,
+ "Duplicate `access' keyword found in RCS file.");
+ free (rdata->access);
+ }
+ rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1, NULL);
+ }
+ continue;
+ }
+
+ /* We always save lock information, so that we can handle
+ -kkvl correctly when checking out a file. */
+ if (STREQ (key, "locks"))
+ {
+ if (value != NULL)
+ {
+ if (rdata->locks_data)
+ {
+ error (0, 0,
+ "Duplicate `locks' keyword found in RCS file.");
+ free (rdata->locks_data);
+ }
+ rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
+ }
+ if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ {
+ error (1, 0, "premature end of file reading %s", rcsfile);
+ }
+ if (STREQ (key, "strict") && value == NULL)
+ {
+ rdata->strict_locks = 1;
+ }
+ else
+ gotkey = 1;
+ continue;
+ }
+
+ if (STREQ (RCSSYMBOLS, key))
+ {
+ if (value != NULL)
+ {
+ if (rdata->symbols_data)
+ {
+ error (0, 0,
+ "Duplicate `%s' keyword found in RCS file.",
+ RCSSYMBOLS);
+ free (rdata->symbols_data);
+ }
+ rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
+ }
+ continue;
+ }
+
+ /*
+ * check key for '.''s and digits (probably a rev) if it is a
+ * revision or `desc', we are done with the headers and are down to the
+ * revision deltas, so we break out of the loop
+ */
+ for (cp = key;
+ (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ cp++)
+ /* do nothing */ ;
+ /* Note that when comparing with RCSDATE, we are not massaging
+ VALUE from the string found in the RCS file. This is OK
+ since we know exactly what to expect. */
+ if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
+ break;
+
+ if (STREQ (key, RCSDESC))
+ break;
+
+ if (STREQ (key, "comment"))
+ {
+ if (rdata->comment)
+ {
+ error (0, 0,
+ "warning: duplicate key `%s' in RCS file `%s'",
+ key, rcsfile);
+ free (rdata->comment);
+ }
+ rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
+ continue;
+ }
+ if (rdata->other == NULL)
+ rdata->other = getlist ();
+ kv = getnode ();
+ kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
+ kv->key = xstrdup (key);
+ kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, NULL);
+ if (addnode (rdata->other, kv) != 0)
+ {
+ error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
+ key, rcsfile);
+ freenode (kv);
+ }
+
+ /* if we haven't grabbed it yet, we didn't want it */
+ }
+
+ /* We got out of the loop, so we have the first part of the first
+ revision delta in KEY (the revision) and VALUE (the date key
+ and its value). This is what getdelta expects to receive. */
+
+ while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
+ {
+ /* get the node */
+ q = getnode ();
+ q->type = RCSVERS;
+ q->delproc = rcsvers_delproc;
+ q->data = vnode;
+ q->key = vnode->version;
+
+ /* add the nodes to the list */
+ if (addnode (rdata->versions, q) != 0)
+ {
+#if 0
+ purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
+ q->key, rcsfile);
+ freenode (q);
+#endif
+ }
+ }
+
+ /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
+
+ if (STREQ (key, RCSDESC))
+ {
+ if (rdata->desc != NULL)
+ {
+ error (0, 0,
+ "warning: duplicate key `%s' in RCS file `%s'",
+ key, rcsfile);
+ free (rdata->desc);
+ }
+ rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, NULL);
+ }
+
+ rdata->delta_pos = rcsbuf_ftello (&rcsbuf);
+
+ if (pfp == NULL)
+ rcsbuf_cache (rdata, &rcsbuf);
+ else
+ {
+ *pfp = fp;
+ *rcsbufp = rcsbuf;
+ }
+ rdata->flags &= ~PARTIAL;
+}
+
+
+
+/* Move RCS into or out of the Attic, depending on TOATTIC. If the
+ file is already in the desired place, return without doing
+ anything. At some point may want to think about how this relates
+ to RCS_rewrite but that is a bit hairy (if one wants renames to be
+ atomic, or that kind of thing). If there is an error, print a message
+ and return 1. On success, return 0. */
+int
+RCS_setattic (RCSNode *rcs, int toattic)
+{
+ char *newpath;
+ const char *p;
+ char *q;
+
+ /* Some systems aren't going to let us rename an open file. */
+ rcsbuf_cache_close ();
+
+ /* Could make the pathname computations in this file, and probably
+ in other parts of rcs.c too, easier if the REPOS and FILE
+ arguments to RCS_parse got stashed in the RCSNode. */
+
+ if (toattic)
+ {
+ mode_t omask;
+
+ if (rcs->flags & INATTIC)
+ return 0;
+
+ /* Example: rcs->path is "/foo/bar/baz,v". */
+ newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
+ p = last_component (rcs->path);
+ strncpy (newpath, rcs->path, p - rcs->path);
+ strcpy (newpath + (p - rcs->path), CVSATTIC);
+
+ /* Create the Attic directory if it doesn't exist. */
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
+ error (0, errno, "cannot make directory %s", newpath);
+ (void) umask (omask);
+
+ strcat (newpath, "/");
+ strcat (newpath, p);
+
+ if (CVS_RENAME (rcs->path, newpath) < 0)
+ {
+ int save_errno = errno;
+
+ /* The checks for isreadable look awfully fishy, but
+ I'm going to leave them here for now until I
+ can think harder about whether they take care of
+ some cases which should be handled somehow. */
+
+ if (isreadable (rcs->path) || !isreadable (newpath))
+ {
+ error (0, save_errno, "cannot rename %s to %s",
+ rcs->path, newpath);
+ free (newpath);
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ if (!(rcs->flags & INATTIC))
+ return 0;
+
+ newpath = xmalloc (strlen (rcs->path));
+
+ /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
+ p = last_component (rcs->path);
+ strncpy (newpath, rcs->path, p - rcs->path - 1);
+ newpath[p - rcs->path - 1] = '\0';
+ q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
+ assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
+ strcpy (q, p);
+
+ if (CVS_RENAME (rcs->path, newpath) < 0)
+ {
+ error (0, errno, "failed to move `%s' out of the attic",
+ rcs->path);
+ free (newpath);
+ return 1;
+ }
+ }
+
+ free (rcs->path);
+ rcs->path = newpath;
+
+ return 0;
+}
+
+
+
+/*
+ * Fully parse the RCS file. Store all keyword/value pairs, fetch the
+ * log messages for each revision, and fetch add and delete counts for
+ * each revision (we could fetch the entire text for each revision,
+ * but the only caller, log_fileproc, doesn't need that information,
+ * so we don't waste the memory required to store it). The add and
+ * delete counts are stored on the OTHER field of the RCSVERSNODE
+ * structure, under the names ";add" and ";delete", so that we don't
+ * waste the memory space of extra fields in RCSVERSNODE for code
+ * which doesn't need this information.
+ */
+void
+RCS_fully_parse (RCSNode *rcs)
+{
+ FILE *fp;
+ struct rcsbuffer rcsbuf;
+
+ RCS_reparsercsfile (rcs, &fp, &rcsbuf);
+
+ while (1)
+ {
+ char *key, *value;
+ Node *vers;
+ RCSVers *vnode;
+
+ /* Rather than try to keep track of how much information we
+ have read, just read to the end of the file. */
+ if (!rcsbuf_getrevnum (&rcsbuf, &key))
+ break;
+
+ vers = findnode (rcs->versions, key);
+ if (vers == NULL)
+ error (1, 0,
+ "mismatch in rcs file %s between deltas and deltatexts (%s)",
+ rcs->print_path, key);
+
+ vnode = vers->data;
+
+ while (rcsbuf_getkey (&rcsbuf, &key, &value))
+ {
+ if (!STREQ (key, "text"))
+ {
+ Node *kv;
+
+ if (vnode->other == NULL)
+ vnode->other = getlist ();
+ kv = getnode ();
+ kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
+ kv->key = xstrdup (key);
+ kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
+ NULL);
+ if (addnode (vnode->other, kv) != 0)
+ {
+ error (0, 0,
+ "\
+warning: duplicate key `%s' in version `%s' of RCS file `%s'",
+ key, vnode->version, rcs->print_path);
+ freenode (kv);
+ }
+
+ continue;
+ }
+
+ if (!STREQ (vnode->version, rcs->head))
+ {
+ unsigned long add, del;
+ char buf[50];
+ Node *kv;
+
+ /* This is a change text. Store the add and delete
+ counts. */
+ add = 0;
+ del = 0;
+ if (value != NULL)
+ {
+ size_t vallen;
+ const char *cp;
+
+ rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
+ cp = value;
+ while (cp < value + vallen)
+ {
+ char op;
+ unsigned long count;
+
+ op = *cp++;
+ if (op != 'a' && op != 'd')
+ error (1, 0, "\
+unrecognized operation '\\x%x' in %s",
+ op, rcs->print_path);
+ (void) strtoul (cp, (char **) &cp, 10);
+ if (*cp++ != ' ')
+ error (1, 0, "space expected in %s revision %s",
+ rcs->print_path, vnode->version);
+ count = strtoul (cp, (char **) &cp, 10);
+ if (*cp++ != '\012')
+ error (1, 0, "linefeed expected in %s revision %s",
+ rcs->print_path, vnode->version);
+
+ if (op == 'd')
+ del += count;
+ else
+ {
+ add += count;
+ while (count != 0)
+ {
+ if (*cp == '\012')
+ --count;
+ else if (cp == value + vallen)
+ {
+ if (count != 1)
+ error (1, 0, "\
+premature end of value in %s revision %s",
+ rcs->print_path, vnode->version);
+ else
+ break;
+ }
+ ++cp;
+ }
+ }
+ }
+ }
+
+ sprintf (buf, "%lu", add);
+ kv = getnode ();
+ kv->type = RCSFIELD;
+ kv->key = xstrdup (";add");
+ kv->data = xstrdup (buf);
+ if (addnode (vnode->other, kv) != 0)
+ {
+ error (0, 0,
+ "\
+warning: duplicate key `%s' in version `%s' of RCS file `%s'",
+ key, vnode->version, rcs->print_path);
+ freenode (kv);
+ }
+
+ sprintf (buf, "%lu", del);
+ kv = getnode ();
+ kv->type = RCSFIELD;
+ kv->key = xstrdup (";delete");
+ kv->data = xstrdup (buf);
+ if (addnode (vnode->other, kv) != 0)
+ {
+ error (0, 0,
+ "\
+warning: duplicate key `%s' in version `%s' of RCS file `%s'",
+ key, vnode->version, rcs->print_path);
+ freenode (kv);
+ }
+ }
+
+ /* We have found the "text" key which ends the data for
+ this revision. Break out of the loop and go on to the
+ next revision. */
+ break;
+ }
+ }
+
+ rcsbuf_cache (rcs, &rcsbuf);
+}
+
+
+
+/*
+ * freercsnode - free up the info for an RCSNode
+ */
+void
+freercsnode (RCSNode **rnodep)
+{
+ if (rnodep == NULL || *rnodep == NULL)
+ return;
+
+ ((*rnodep)->refcount)--;
+ if ((*rnodep)->refcount != 0)
+ {
+ *rnodep = NULL;
+ return;
+ }
+ free ((*rnodep)->path);
+ free ((*rnodep)->print_path);
+ if ((*rnodep)->head != NULL)
+ free ((*rnodep)->head);
+ if ((*rnodep)->branch != NULL)
+ free ((*rnodep)->branch);
+ free_rcsnode_contents (*rnodep);
+ free (*rnodep);
+ *rnodep = NULL;
+}
+
+
+
+/*
+ * free_rcsnode_contents - free up the contents of an RCSNode without
+ * freeing the node itself, or the file name, or the head, or the
+ * path. This returns the RCSNode to the state it is in immediately
+ * after a call to RCS_parse.
+ */
+static void
+free_rcsnode_contents (RCSNode *rnode)
+{
+ dellist (&rnode->versions);
+ if (rnode->symbols != NULL)
+ dellist (&rnode->symbols);
+ if (rnode->symbols_data != NULL)
+ free (rnode->symbols_data);
+ if (rnode->expand != NULL)
+ free (rnode->expand);
+ if (rnode->other != NULL)
+ dellist (&rnode->other);
+ if (rnode->access != NULL)
+ free (rnode->access);
+ if (rnode->locks_data != NULL)
+ free (rnode->locks_data);
+ if (rnode->locks != NULL)
+ dellist (&rnode->locks);
+ if (rnode->comment != NULL)
+ free (rnode->comment);
+ if (rnode->desc != NULL)
+ free (rnode->desc);
+}
+
+
+
+/* free_rcsvers_contents -- free up the contents of an RCSVers node,
+ but also free the pointer to the node itself. */
+/* Note: The `hardlinks' list is *not* freed, since it is merely a
+ pointer into the `hardlist' structure (defined in hardlink.c), and
+ that structure is freed elsewhere in the program. */
+static void
+free_rcsvers_contents (RCSVers *rnode)
+{
+ if (rnode->branches != NULL)
+ dellist (&rnode->branches);
+ if (rnode->date != NULL)
+ free (rnode->date);
+ if (rnode->next != NULL)
+ free (rnode->next);
+ if (rnode->author != NULL)
+ free (rnode->author);
+ if (rnode->state != NULL)
+ free (rnode->state);
+ if (rnode->other != NULL)
+ dellist (&rnode->other);
+ if (rnode->other_delta != NULL)
+ dellist (&rnode->other_delta);
+ if (rnode->text != NULL)
+ freedeltatext (rnode->text);
+ free (rnode);
+}
+
+
+
+/*
+ * rcsvers_delproc - free up an RCSVers type node
+ */
+static void
+rcsvers_delproc (Node *p)
+{
+ free_rcsvers_contents (p->data);
+}
+
+
+
+/* These functions retrieve keys and values from an RCS file using a
+ buffer. We use this somewhat complex approach because it turns out
+ that for many common operations, CVS spends most of its time
+ reading keys, so it's worth doing some fairly hairy optimization. */
+
+/* The number of bytes we try to read each time we need more data. */
+
+#define RCSBUF_BUFSIZE (8192)
+
+/* The buffer we use to store data. This grows as needed. */
+
+static char *rcsbuf_buffer = NULL;
+static size_t rcsbuf_buffer_size = 0;
+
+/* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
+
+static int rcsbuf_inuse;
+
+/* Set up to start gathering keys and values from an RCS file. This
+ initializes RCSBUF. */
+
+static void
+rcsbuf_open (struct rcsbuffer *rcsbuf, FILE *fp, const char *filename,
+ long unsigned int pos)
+{
+ if (rcsbuf_inuse)
+ error (1, 0, "rcsbuf_open: internal error");
+ rcsbuf_inuse = 1;
+
+#ifdef HAVE_MMAP
+ {
+ /* When we have mmap, it is much more efficient to let the system do the
+ * buffering and caching for us
+ */
+ struct stat fs;
+ size_t mmap_off = 0;
+
+ if ( fstat (fileno(fp), &fs) < 0 )
+ error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
+
+ if (pos)
+ {
+ size_t ps = getpagesize ();
+ mmap_off = ( pos / ps ) * ps;
+ }
+
+ /* Map private here since this particular buffer is read only */
+ rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fileno(fp), mmap_off );
+ if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
+ error ( 1, errno, "Could not map memory to RCS archive %s", filename );
+
+ rcsbuf_buffer_size = fs.st_size - mmap_off;
+ rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
+ rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
+ rcsbuf->pos = mmap_off;
+ }
+#else /* !HAVE_MMAP */
+ if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
+ expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
+
+ rcsbuf->ptr = rcsbuf_buffer;
+ rcsbuf->ptrend = rcsbuf_buffer;
+ rcsbuf->pos = pos;
+#endif /* HAVE_MMAP */
+ rcsbuf->fp = fp;
+ rcsbuf->filename = filename;
+ rcsbuf->vlen = 0;
+ rcsbuf->at_string = 0;
+ rcsbuf->embedded_at = 0;
+}
+
+
+
+/* Stop gathering keys from an RCS file. */
+static void
+rcsbuf_close (struct rcsbuffer *rcsbuf)
+{
+ if (! rcsbuf_inuse)
+ error (1, 0, "rcsbuf_close: internal error");
+#ifdef HAVE_MMAP
+ munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
+#endif
+ rcsbuf_inuse = 0;
+}
+
+
+
+/* Read a key/value pair from an RCS file. This sets *KEYP to point
+ to the key, and *VALUEP to point to the value. A missing or empty
+ value is indicated by setting *VALUEP to NULL.
+
+ This function returns 1 on success, or 0 on EOF. If there is an
+ error reading the file, or an EOF in an unexpected location, it
+ gives a fatal error.
+
+ This sets *KEYP and *VALUEP to point to storage managed by
+ rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
+ RCS format: it may contain embedded whitespace and embedded '@'
+ characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
+ appropriate massaging. */
+
+/* Note that the extreme hair in rcsbuf_getkey is because profiling
+ statistics show that it was worth it. */
+static int
+rcsbuf_getkey (struct rcsbuffer *rcsbuf, char **keyp, char **valp)
+{
+ register const char * const my_spacetab = spacetab;
+ register char *ptr, *ptrend;
+ char c;
+
+#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
+
+ rcsbuf->vlen = 0;
+ rcsbuf->at_string = 0;
+ rcsbuf->embedded_at = 0;
+
+ ptr = rcsbuf->ptr;
+ ptrend = rcsbuf->ptrend;
+
+ /* Sanity check. */
+ assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
+ assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
+
+#ifndef HAVE_MMAP
+ /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
+ buffer, move back to the start of the buffer. This keeps the
+ buffer from growing indefinitely. */
+ if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
+ {
+ int len;
+
+ len = ptrend - ptr;
+
+ /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
+ at a time, so we can't have more bytes than that past PTR. */
+ assert (len <= RCSBUF_BUFSIZE);
+
+ /* Update the POS field, which holds the file offset of the
+ first byte in the RCSBUF_BUFFER buffer. */
+ rcsbuf->pos += ptr - rcsbuf_buffer;
+
+ memcpy (rcsbuf_buffer, ptr, len);
+ ptr = rcsbuf_buffer;
+ ptrend = ptr + len;
+ rcsbuf->ptrend = ptrend;
+ }
+#endif /* HAVE_MMAP */
+
+ /* Skip leading whitespace. */
+
+ while (1)
+ {
+ if (ptr >= ptrend)
+ {
+ ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL);
+ if (ptr == NULL)
+ return 0;
+ ptrend = rcsbuf->ptrend;
+ }
+
+ c = *ptr;
+ if (! my_whitespace (c))
+ break;
+
+ ++ptr;
+ }
+
+ /* We've found the start of the key. */
+
+ *keyp = ptr;
+
+ if (c != ';')
+ {
+ while (1)
+ {
+ ++ptr;
+ if (ptr >= ptrend)
+ {
+ ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL);
+ if (ptr == NULL)
+ error (1, 0, "EOF in key in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ ptrend = rcsbuf->ptrend;
+ }
+ c = *ptr;
+ if (c == ';' || my_whitespace (c))
+ break;
+ }
+ }
+
+ /* Here *KEYP points to the key in the buffer, C is the character
+ we found at the of the key, and PTR points to the location in
+ the buffer where we found C. We must set *PTR to \0 in order
+ to terminate the key. If the key ended with ';', then there is
+ no value. */
+
+ *ptr = '\0';
+ ++ptr;
+
+ if (c == ';')
+ {
+ *valp = NULL;
+ rcsbuf->ptr = ptr;
+ return 1;
+ }
+
+ /* C must be whitespace. Skip whitespace between the key and the
+ value. If we find ';' now, there is no value. */
+
+ while (1)
+ {
+ if (ptr >= ptrend)
+ {
+ ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL);
+ if (ptr == NULL)
+ error (1, 0, "EOF while looking for value in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ ptrend = rcsbuf->ptrend;
+ }
+ c = *ptr;
+ if (c == ';')
+ {
+ *valp = NULL;
+ rcsbuf->ptr = ptr + 1;
+ return 1;
+ }
+ if (! my_whitespace (c))
+ break;
+ ++ptr;
+ }
+
+ /* Now PTR points to the start of the value, and C is the first
+ character of the value. */
+
+ if (c != '@')
+ *valp = ptr;
+ else
+ {
+ char *pat;
+ size_t vlen;
+
+ /* Optimize the common case of a value composed of a single
+ '@' string. */
+
+ rcsbuf->at_string = 1;
+
+ ++ptr;
+
+ *valp = ptr;
+
+ while (1)
+ {
+ while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
+ {
+ /* Note that we pass PTREND as the PTR value to
+ rcsbuf_fill, so that we will wind up setting PTR to
+ the location corresponding to the old PTREND, so
+ that we don't search the same bytes again. */
+ ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
+ if (ptr == NULL)
+ error (1, 0,
+ "EOF while looking for end of string in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ ptrend = rcsbuf->ptrend;
+ }
+
+ /* Handle the special case of an '@' right at the end of
+ the known bytes. */
+ if (pat + 1 >= ptrend)
+ {
+ /* Note that we pass PAT, not PTR, here. */
+ pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
+ if (pat == NULL)
+ {
+ /* EOF here is OK; it just means that the last
+ character of the file was an '@' terminating a
+ value for a key type which does not require a
+ trailing ';'. */
+ pat = rcsbuf->ptrend - 1;
+
+ }
+ ptrend = rcsbuf->ptrend;
+
+ /* Note that the value of PTR is bogus here. This is
+ OK, because we don't use it. */
+ }
+
+ if (pat + 1 >= ptrend || pat[1] != '@')
+ break;
+
+ /* We found an '@' pair in the string. Keep looking. */
+ ++rcsbuf->embedded_at;
+ ptr = pat + 2;
+ }
+
+ /* Here PAT points to the final '@' in the string. */
+
+ *pat = '\0';
+
+ vlen = pat - *valp;
+ if (vlen == 0)
+ *valp = NULL;
+ rcsbuf->vlen = vlen;
+
+ ptr = pat + 1;
+ }
+
+ /* Certain keywords only have a '@' string. If there is no '@'
+ string, then the old getrcskey function assumed that they had
+ no value, and we do the same. */
+
+ {
+ char *k;
+
+ k = *keyp;
+ if (STREQ (k, RCSDESC)
+ || STREQ (k, "text")
+ || STREQ (k, "log"))
+ {
+ if (c != '@')
+ *valp = NULL;
+ rcsbuf->ptr = ptr;
+ return 1;
+ }
+ }
+
+ /* If we've already gathered a '@' string, try to skip whitespace
+ and find a ';'. */
+ if (c == '@')
+ {
+ while (1)
+ {
+ char n;
+
+ if (ptr >= ptrend)
+ {
+ ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
+ if (ptr == NULL)
+ error (1, 0, "EOF in value in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ ptrend = rcsbuf->ptrend;
+ }
+ n = *ptr;
+ if (n == ';')
+ {
+ /* We're done. We already set everything up for this
+ case above. */
+ rcsbuf->ptr = ptr + 1;
+ return 1;
+ }
+ if (! my_whitespace (n))
+ break;
+ ++ptr;
+ }
+
+ /* The value extends past the '@' string. We need to undo the
+ '@' stripping done in the default case above. This
+ case never happens in a plain RCS file, but it can happen
+ if user defined phrases are used. */
+ ((*valp)--)[rcsbuf->vlen++] = '@';
+ }
+
+ /* Here we have a value which is not a simple '@' string. We need
+ to gather up everything until the next ';', including any '@'
+ strings. *VALP points to the start of the value. If
+ RCSBUF->VLEN is not zero, then we have already read an '@'
+ string, and PTR points to the data following the '@' string.
+ Otherwise, PTR points to the start of the value. */
+
+ while (1)
+ {
+ char *start, *psemi, *pat;
+
+ /* Find the ';' which must end the value. */
+ start = ptr;
+ while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
+ {
+ int slen;
+
+ /* Note that we pass PTREND as the PTR value to
+ rcsbuf_fill, so that we will wind up setting PTR to the
+ location corresponding to the old PTREND, so that we
+ don't search the same bytes again. */
+ slen = start - *valp;
+ ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
+ if (ptr == NULL)
+ error (1, 0, "EOF in value in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ start = *valp + slen;
+ ptrend = rcsbuf->ptrend;
+ }
+
+ /* See if there are any '@' strings in the value. */
+ pat = memchr (start, '@', psemi - start);
+
+ if (pat == NULL)
+ {
+ size_t vlen;
+
+ /* We're done with the value. Trim any trailing
+ whitespace. */
+
+ rcsbuf->ptr = psemi + 1;
+
+ start = *valp;
+ while (psemi > start && my_whitespace (psemi[-1]))
+ --psemi;
+ *psemi = '\0';
+
+ vlen = psemi - start;
+ if (vlen == 0)
+ *valp = NULL;
+ rcsbuf->vlen = vlen;
+
+ return 1;
+ }
+
+ /* We found an '@' string in the value. We set RCSBUF->AT_STRING
+ and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
+ compress whitespace correctly for this type of value.
+ Since this type of value never arises in a normal RCS file,
+ this should not be a big deal. It means that if anybody
+ adds a phrase which can have both an '@' string and regular
+ text, they will have to handle whitespace compression
+ themselves. */
+
+ rcsbuf->at_string = 1;
+ rcsbuf->embedded_at = -1;
+
+ ptr = pat + 1;
+
+ while (1)
+ {
+ while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
+ {
+ /* Note that we pass PTREND as the PTR value to
+ rcsbuff_fill, so that we will wind up setting PTR
+ to the location corresponding to the old PTREND, so
+ that we don't search the same bytes again. */
+ ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
+ if (ptr == NULL)
+ error (1, 0,
+ "EOF while looking for end of string in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ ptrend = rcsbuf->ptrend;
+ }
+
+ /* Handle the special case of an '@' right at the end of
+ the known bytes. */
+ if (pat + 1 >= ptrend)
+ {
+ ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
+ if (ptr == NULL)
+ error (1, 0, "EOF in value in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ ptrend = rcsbuf->ptrend;
+ }
+
+ if (pat[1] != '@')
+ break;
+
+ /* We found an '@' pair in the string. Keep looking. */
+ ptr = pat + 2;
+ }
+
+ /* Here PAT points to the final '@' in the string. */
+ ptr = pat + 1;
+ }
+
+#undef my_whitespace
+}
+
+
+
+/* Read an RCS revision number from an RCS file. This sets *REVP to
+ point to the revision number; it will point to space that is
+ managed by the rcsbuf functions, and is only good until the next
+ call to rcsbuf_getkey or rcsbuf_getrevnum.
+
+ This function returns 1 on success, or 0 on EOF. If there is an
+ error reading the file, or an EOF in an unexpected location, it
+ gives a fatal error. */
+static int
+rcsbuf_getrevnum (struct rcsbuffer *rcsbuf, char **revp)
+{
+ char *ptr, *ptrend;
+ char c;
+
+ ptr = rcsbuf->ptr;
+ ptrend = rcsbuf->ptrend;
+
+ *revp = NULL;
+
+ /* Skip leading whitespace. */
+
+ while (1)
+ {
+ if (ptr >= ptrend)
+ {
+ ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL);
+ if (ptr == NULL)
+ return 0;
+ ptrend = rcsbuf->ptrend;
+ }
+
+ c = *ptr;
+ if (! whitespace (c))
+ break;
+
+ ++ptr;
+ }
+
+ if (! isdigit ((unsigned char) c) && c != '.')
+ error (1, 0,
+ "\
+unexpected '\\x%x' reading revision number in RCS file %s",
+ c, primary_root_inverse_translate (rcsbuf->filename));
+
+ *revp = ptr;
+
+ do
+ {
+ ++ptr;
+ if (ptr >= ptrend)
+ {
+ ptr = rcsbuf_fill (rcsbuf, ptr, revp, NULL);
+ if (ptr == NULL)
+ error (1, 0,
+ "unexpected EOF reading revision number in RCS file %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+ ptrend = rcsbuf->ptrend;
+ }
+
+ c = *ptr;
+ }
+ while (isdigit ((unsigned char) c) || c == '.');
+
+ if (! whitespace (c))
+ error (1, 0, "\
+unexpected '\\x%x' reading revision number in RCS file %s",
+ c, primary_root_inverse_translate (rcsbuf->filename));
+
+ *ptr = '\0';
+
+ rcsbuf->ptr = ptr + 1;
+
+ return 1;
+}
+
+
+
+/* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
+ updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
+ then *KEYP points into the buffer, and must be adjusted if the
+ buffer is changed. Likewise for VALP. Returns the new value of
+ PTR, or NULL on error. */
+static char *
+rcsbuf_fill (struct rcsbuffer *rcsbuf, char *ptr, char **keyp, char **valp)
+{
+#ifdef HAVE_MMAP
+ return NULL;
+#else /* HAVE_MMAP */
+ int got;
+
+ if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
+ {
+ int poff, peoff, koff, voff;
+
+ poff = ptr - rcsbuf_buffer;
+ peoff = rcsbuf->ptrend - rcsbuf_buffer;
+ koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
+ voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
+
+ expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
+ rcsbuf_buffer_size + RCSBUF_BUFSIZE);
+
+ ptr = rcsbuf_buffer + poff;
+ rcsbuf->ptrend = rcsbuf_buffer + peoff;
+ if (keyp != NULL)
+ *keyp = rcsbuf_buffer + koff;
+ if (valp != NULL)
+ *valp = rcsbuf_buffer + voff;
+ }
+
+ got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
+ if (got == 0)
+ {
+ if (ferror (rcsbuf->fp))
+ error (1, errno, "cannot read %s", rcsbuf->filename);
+ return NULL;
+ }
+
+ rcsbuf->ptrend += got;
+
+ return ptr;
+#endif /* HAVE_MMAP */
+}
+
+
+
+/* Test whether the last value returned by rcsbuf_getkey is a composite
+ value or not. */
+static int
+rcsbuf_valcmp (struct rcsbuffer *rcsbuf)
+{
+ return rcsbuf->at_string && rcsbuf->embedded_at < 0;
+}
+
+
+
+/* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
+ returning the memory buffer. Polish the value like
+ rcsbuf_valpolish, q.v. */
+static char *
+rcsbuf_valcopy (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp)
+{
+ size_t vlen;
+ int embedded_at;
+ char *ret;
+
+ if (val == NULL)
+ {
+ if (lenp != NULL)
+ *lenp = 0;
+ return NULL;
+ }
+
+ vlen = rcsbuf->vlen;
+ embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
+
+ ret = xmalloc (vlen - embedded_at + 1);
+
+ if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
+ {
+ /* No special action to take. */
+ memcpy (ret, val, vlen + 1);
+ if (lenp != NULL)
+ *lenp = vlen;
+ return ret;
+ }
+
+ rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
+ return ret;
+}
+
+
+
+/* Polish the value VAL returned by rcsbuf_getkey. The POLISH
+ parameter is non-zero if multiple embedded whitespace characters
+ should be compressed into a single whitespace character. Note that
+ leading and trailing whitespace was already removed by
+ rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
+ compressed into a single '@' character regardless of the value of
+ POLISH. If LENP is not NULL, set *LENP to the length of the value. */
+static void
+rcsbuf_valpolish (struct rcsbuffer *rcsbuf, char *val, int polish,
+ size_t *lenp)
+{
+ if (val == NULL)
+ {
+ if (lenp != NULL)
+ *lenp= 0;
+ return;
+ }
+
+ if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
+ {
+ /* No special action to take. */
+ if (lenp != NULL)
+ *lenp = rcsbuf->vlen;
+ return;
+ }
+
+ rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
+}
+
+
+
+/* Internal polishing routine, called from rcsbuf_valcopy and
+ rcsbuf_valpolish. */
+static void
+rcsbuf_valpolish_internal (struct rcsbuffer *rcsbuf, char *to,
+ const char *from, size_t *lenp)
+{
+ size_t len;
+
+ len = rcsbuf->vlen;
+
+ if (! rcsbuf->at_string)
+ {
+ char *orig_to;
+ size_t clen;
+
+ orig_to = to;
+
+ for (clen = len; clen > 0; ++from, --clen)
+ {
+ char c;
+
+ c = *from;
+ if (whitespace (c))
+ {
+ /* Note that we know that clen can not drop to zero
+ while we have whitespace, because we know there is
+ no trailing whitespace. */
+ while (whitespace (from[1]))
+ {
+ ++from;
+ --clen;
+ }
+ c = ' ';
+ }
+ *to++ = c;
+ }
+
+ *to = '\0';
+
+ if (lenp != NULL)
+ *lenp = to - orig_to;
+ }
+ else
+ {
+ const char *orig_from;
+ char *orig_to;
+ int embedded_at;
+ size_t clen;
+
+ orig_from = from;
+ orig_to = to;
+
+ embedded_at = rcsbuf->embedded_at;
+ assert (embedded_at > 0);
+
+ if (lenp != NULL)
+ *lenp = len - embedded_at;
+
+ for (clen = len; clen > 0; ++from, --clen)
+ {
+ char c;
+
+ c = *from;
+ *to++ = c;
+ if (c == '@')
+ {
+ ++from;
+
+ /* Sanity check.
+ *
+ * FIXME: I restored this to an abort from an assert based on
+ * advice from Larry Jones that asserts should not be used to
+ * confirm the validity of an RCS file... This leaves two
+ * issues here: 1) I am uncertain that the fact that we will
+ * only find double '@'s hasn't already been confirmed; and:
+ * 2) If this is the proper place to spot the error in the RCS
+ * file, then we should print a much clearer error here for the
+ * user!!!!!!!
+ *
+ * - DRP
+ */
+ if (*from != '@' || clen == 0)
+ abort ();
+
+ --clen;
+
+ --embedded_at;
+ if (embedded_at == 0)
+ {
+ /* We've found all the embedded '@' characters.
+ We can just memcpy the rest of the buffer after
+ this '@' character. */
+ if (orig_to != orig_from)
+ memcpy (to, from + 1, clen - 1);
+ else
+ memmove (to, from + 1, clen - 1);
+ from += clen;
+ to += clen - 1;
+ break;
+ }
+ }
+ }
+
+ /* Sanity check. */
+ assert (from == orig_from + len
+ && to == orig_to + (len - rcsbuf->embedded_at));
+
+ *to = '\0';
+ }
+}
+
+
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+
+/* Copy the next word from the value VALP returned by rcsbuf_getkey into a
+ memory buffer, updating VALP and returning the memory buffer. Return
+ NULL when there are no more words. */
+
+static char *
+rcsbuf_valword (struct rcsbuffer *rcsbuf, char **valp)
+{
+ register const char * const my_spacetab = spacetab;
+ register char *ptr, *pat;
+ char c;
+
+# define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
+
+ if (*valp == NULL)
+ return NULL;
+
+ for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
+ if (*ptr == '\0')
+ {
+ assert (ptr - *valp == rcsbuf->vlen);
+ *valp = NULL;
+ rcsbuf->vlen = 0;
+ return NULL;
+ }
+
+ /* PTR now points to the start of a value. Find out whether it is
+ a num, an id, a string or a colon. */
+ c = *ptr;
+ if (c == ':')
+ {
+ rcsbuf->vlen -= ++ptr - *valp;
+ *valp = ptr;
+ return xstrdup (":");
+ }
+
+ if (c == '@')
+ {
+ int embedded_at = 0;
+ size_t vlen;
+
+ pat = ++ptr;
+ while ((pat = strchr (pat, '@')) != NULL)
+ {
+ if (pat[1] != '@')
+ break;
+ ++embedded_at;
+ pat += 2;
+ }
+
+ /* Here PAT points to the final '@' in the string. */
+ *pat++ = '\0';
+ assert (rcsbuf->at_string);
+ vlen = rcsbuf->vlen - (pat - *valp);
+ rcsbuf->vlen = pat - ptr - 1;
+ rcsbuf->embedded_at = embedded_at;
+ ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, NULL);
+ *valp = pat;
+ rcsbuf->vlen = vlen;
+ if (strchr (pat, '@') == NULL)
+ rcsbuf->at_string = 0;
+ else
+ rcsbuf->embedded_at = -1;
+ return ptr;
+ }
+
+ /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
+ or an id. Make sure it is not another special character. */
+ if (c == '$' || c == '.' || c == ',')
+ error (1, 0, "invalid special character in RCS field in %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+
+ pat = ptr;
+ while (1)
+ {
+ /* Legitimate ID characters are digits, dots and any `graphic
+ printing character that is not a special.' This test ought
+ to do the trick. */
+ c = *++pat;
+ if (!isprint ((unsigned char) c) ||
+ c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
+ break;
+ }
+
+ /* PAT points to the last non-id character in this word, and C is
+ the character in its memory cell. Check to make sure that it
+ is a legitimate word delimiter -- whitespace or end. */
+ if (c != '\0' && !my_whitespace (c))
+ error (1, 0, "invalid special character in RCS field in %s",
+ primary_root_inverse_translate (rcsbuf->filename));
+
+ *pat = '\0';
+ rcsbuf->vlen -= pat - *valp;
+ *valp = pat;
+ return xstrdup (ptr);
+
+# undef my_whitespace
+}
+
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+
+
+
+/* Return the current position of an rcsbuf. */
+static off_t
+rcsbuf_ftello (struct rcsbuffer *rcsbuf)
+{
+ return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
+}
+
+
+
+/* Return a pointer to any data buffered for RCSBUF, along with the
+ length. */
+static void
+rcsbuf_get_buffered (struct rcsbuffer *rcsbuf, char **datap, size_t *lenp)
+{
+ *datap = rcsbuf->ptr;
+ *lenp = rcsbuf->ptrend - rcsbuf->ptr;
+}
+
+
+
+/* CVS optimizes by quickly reading some header information from a
+ file. If it decides it needs to do more with the file, it reopens
+ it. We speed that up here by maintaining a cache of a single open
+ file, to save the time it takes to reopen the file in the common
+ case. */
+static RCSNode *cached_rcs;
+static struct rcsbuffer cached_rcsbuf;
+
+/* Cache RCS and RCSBUF. This takes responsibility for closing
+ RCSBUF->FP. */
+static void
+rcsbuf_cache (RCSNode *rcs, struct rcsbuffer *rcsbuf)
+{
+ if (cached_rcs != NULL)
+ rcsbuf_cache_close ();
+ cached_rcs = rcs;
+ ++rcs->refcount;
+ cached_rcsbuf = *rcsbuf;
+}
+
+
+
+/* If there is anything in the cache, close it. */
+static void
+rcsbuf_cache_close (void)
+{
+ if (cached_rcs != NULL)
+ {
+ rcsbuf_close (&cached_rcsbuf);
+ if (fclose (cached_rcsbuf.fp) != 0)
+ error (0, errno, "cannot close %s", cached_rcsbuf.filename);
+ freercsnode (&cached_rcs);
+ cached_rcs = NULL;
+ }
+}
+
+
+
+/* Open an rcsbuffer for RCS, getting it from the cache if possible.
+ Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
+ be put at position POS. */
+static void
+rcsbuf_cache_open (RCSNode *rcs, off_t pos, FILE **pfp,
+ struct rcsbuffer *prcsbuf)
+{
+#ifndef HAVE_MMAP
+ if (cached_rcs == rcs)
+ {
+ if (rcsbuf_ftello (&cached_rcsbuf) != pos)
+ {
+ if (fseeko (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
+ error (1, 0, "cannot fseeko RCS file %s",
+ cached_rcsbuf.filename);
+ cached_rcsbuf.ptr = rcsbuf_buffer;
+ cached_rcsbuf.ptrend = rcsbuf_buffer;
+ cached_rcsbuf.pos = pos;
+ }
+ *pfp = cached_rcsbuf.fp;
+
+ /* When RCS_parse opens a file using fopen_case, it frees the
+ filename which we cached in CACHED_RCSBUF and stores a new
+ file name in RCS->PATH. We avoid problems here by always
+ copying the filename over. FIXME: This is hackish. */
+ cached_rcsbuf.filename = rcs->path;
+
+ *prcsbuf = cached_rcsbuf;
+
+ cached_rcs = NULL;
+
+ /* Removing RCS from the cache removes a reference to it. */
+ --rcs->refcount;
+ if (rcs->refcount <= 0)
+ error (1, 0, "rcsbuf_cache_open: internal error");
+ }
+ else
+ {
+#endif /* ifndef HAVE_MMAP */
+ /* FIXME: If these routines can be rewritten to not write to the
+ * rcs file buffer, there would be a considerably larger memory savings
+ * from using mmap since the shared file would never need be copied to
+ * process memory.
+ *
+ * If this happens, cached mmapped buffers would be usable, but don't
+ * forget to make sure rcs->pos < pos here...
+ */
+ if (cached_rcs != NULL)
+ rcsbuf_cache_close ();
+
+ *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
+ if (*pfp == NULL)
+ error (1, 0, "unable to reopen `%s'", rcs->path);
+#ifndef HAVE_MMAP
+ if (pos != 0)
+ {
+ if (fseeko (*pfp, pos, SEEK_SET) != 0)
+ error (1, 0, "cannot fseeko RCS file %s", rcs->path);
+ }
+#endif /* ifndef HAVE_MMAP */
+ rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
+#ifndef HAVE_MMAP
+ }
+#endif /* ifndef HAVE_MMAP */
+}
+
+
+
+/*
+ * process the symbols list of the rcs file
+ */
+static void
+do_symbols (List *list, char *val)
+{
+ Node *p;
+ char *cp = val;
+ char *tag, *rev;
+
+ assert (cp);
+
+ for (;;)
+ {
+ /* skip leading whitespace */
+ while (whitespace (*cp))
+ cp++;
+
+ /* if we got to the end, we are done */
+ if (*cp == '\0')
+ break;
+
+ /* split it up into tag and rev */
+ tag = cp;
+ cp = strchr (cp, ':');
+ *cp++ = '\0';
+ rev = cp;
+ while (!whitespace (*cp) && *cp != '\0')
+ cp++;
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ /* make a new node and add it to the list */
+ p = getnode ();
+ p->key = xstrdup (tag);
+ p->data = xstrdup (rev);
+ (void) addnode (list, p);
+ }
+}
+
+
+
+/*
+ * process the locks list of the rcs file
+ * Like do_symbols, but hash entries are keyed backwards: i.e.
+ * an entry like `user:rev' is keyed on REV rather than on USER.
+ */
+static void
+do_locks (List *list, char *val)
+{
+ Node *p;
+ char *cp = val;
+ char *user, *rev;
+
+ assert (cp);
+
+ for (;;)
+ {
+ /* skip leading whitespace */
+ while (whitespace (*cp))
+ cp++;
+
+ /* if we got to the end, we are done */
+ if (*cp == '\0')
+ break;
+
+ /* split it up into user and rev */
+ user = cp;
+ cp = strchr (cp, ':');
+ *cp++ = '\0';
+ rev = cp;
+ while (!whitespace (*cp) && *cp != '\0')
+ cp++;
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ /* make a new node and add it to the list */
+ p = getnode ();
+ p->key = xstrdup (rev);
+ p->data = xstrdup (user);
+ (void) addnode (list, p);
+ }
+}
+
+
+
+/*
+ * process the branches list of a revision delta
+ */
+static void
+do_branches (List *list, char *val)
+{
+ Node *p;
+ char *cp = val;
+ char *branch;
+
+ for (;;)
+ {
+ /* skip leading whitespace */
+ while (whitespace (*cp))
+ cp++;
+
+ /* if we got to the end, we are done */
+ if (*cp == '\0')
+ break;
+
+ /* find the end of this branch */
+ branch = cp;
+ while (!whitespace (*cp) && *cp != '\0')
+ cp++;
+ if (*cp != '\0')
+ *cp++ = '\0';
+
+ /* make a new node and add it to the list */
+ p = getnode ();
+ p->key = xstrdup (branch);
+ (void) addnode (list, p);
+ }
+}
+
+
+
+/*
+ * Version Number
+ *
+ * Returns the requested version number of the RCS file, satisfying tags and/or
+ * dates, and walking branches, if necessary.
+ *
+ * The result is returned; null-string if error.
+ */
+char *
+RCS_getversion (RCSNode *rcs, const char *tag, const char *date,
+ int force_tag_match, int *simple_tag)
+{
+ if (simple_tag != NULL)
+ *simple_tag = 0;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (tag && date)
+ {
+ char *branch, *rev;
+
+ if (! RCS_nodeisbranch (rcs, tag))
+ {
+ /* We can't get a particular date if the tag is not a
+ branch. */
+ return NULL;
+ }
+
+ /* Work out the branch. */
+ if (! isdigit ((unsigned char) tag[0]))
+ branch = RCS_whatbranch (rcs, tag);
+ else
+ branch = xstrdup (tag);
+
+ /* Fetch the revision of branch as of date. */
+ rev = RCS_getdatebranch (rcs, date, branch);
+ free (branch);
+ return rev;
+ }
+ else if (tag)
+ return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
+ else if (date)
+ return RCS_getdate (rcs, date, force_tag_match);
+ else
+ return RCS_head (rcs);
+
+}
+
+
+
+/*
+ * Get existing revision number corresponding to tag or revision.
+ * Similar to RCS_gettag but less interpretation imposed.
+ * For example:
+ * -- If tag designates a magic branch, RCS_tag2rev
+ * returns the magic branch number.
+ * -- If tag is a branch tag, returns the branch number, not
+ * the revision of the head of the branch.
+ * If tag or revision is not valid or does not exist in file,
+ * return NULL.
+ */
+char *
+RCS_tag2rev (RCSNode *rcs, char *tag)
+{
+ char *rev, *pa, *pb;
+ int i;
+
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* If a valid revision, try to look it up */
+ if ( RCS_valid_rev (tag) )
+ {
+ /* Make a copy so we can scribble on it */
+ rev = xstrdup (tag);
+
+ /* If revision exists, return the copy */
+ if (RCS_exist_rev (rcs, tag))
+ return rev;
+
+ /* Nope, none such. If tag is not a branch we're done. */
+ i = numdots (rev);
+ if ((i & 1) == 1 )
+ {
+ pa = strrchr (rev, '.');
+ if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
+ {
+ free (rev);
+ error (1, 0, "revision `%s' does not exist", tag);
+ }
+ }
+
+ /* Try for a real (that is, exists in the RCS deltas) branch
+ (RCS_exist_rev just checks for real revisions and revisions
+ which have tags pointing to them). */
+ pa = RCS_getbranch (rcs, rev, 1);
+ if (pa != NULL)
+ {
+ free (pa);
+ return rev;
+ }
+
+ /* Tag is branch, but does not exist, try corresponding
+ * magic branch tag.
+ *
+ * FIXME: assumes all magic branches are of
+ * form "n.n.n ... .0.n". I'll fix if somebody can
+ * send me a method to get a magic branch tag with
+ * the 0 in some other position -- <dan@gasboy.com>
+ */
+ pa = strrchr (rev, '.');
+ if (!pa)
+ /* This might happen, for instance, if an RCS file only contained
+ * revisions 2.x and higher, and REV == "1".
+ */
+ error (1, 0, "revision `%s' does not exist", tag);
+
+ *pa++ = 0;
+ pb = Xasprintf ("%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
+ free (rev);
+ rev = pb;
+ if (RCS_exist_rev (rcs, rev))
+ return rev;
+ error (1, 0, "revision `%s' does not exist", tag);
+ }
+
+
+ RCS_check_tag (tag); /* exit if not a valid tag */
+
+ /* If tag is "HEAD", special case to get head RCS revision */
+ if (tag && STREQ (tag, TAG_HEAD))
+ return RCS_head (rcs);
+
+ /* If valid tag let translate_symtag say yea or nay. */
+ rev = translate_symtag (rcs, tag);
+
+ if (rev)
+ return rev;
+
+ /* Trust the caller to print warnings. */
+ return NULL;
+}
+
+
+
+/*
+ * Find the revision for a specific tag.
+ * If force_tag_match is set, return NULL if an exact match is not
+ * possible otherwise return RCS_head (). We are careful to look for
+ * and handle "magic" revisions specially.
+ *
+ * If the matched tag is a branch tag, find the head of the branch.
+ *
+ * Returns pointer to newly malloc'd string, or NULL.
+ */
+char *
+RCS_gettag (RCSNode *rcs, const char *symtag, int force_tag_match,
+ int *simple_tag)
+{
+ char *tag;
+
+ if (simple_tag != NULL)
+ *simple_tag = 0;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ /* XXX this is probably not necessary, --jtc */
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* If symtag is "HEAD", special case to get head RCS revision */
+ if (symtag && STREQ (symtag, TAG_HEAD))
+#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
+ if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
+ return NULL; /* head request for removed file */
+ else
+#endif
+ return RCS_head (rcs);
+
+ if (!isdigit ((unsigned char) symtag[0]))
+ {
+ char *version;
+
+ /* If we got a symbolic tag, resolve it to a numeric */
+ version = translate_symtag (rcs, symtag);
+ if (version != NULL)
+ {
+ int dots;
+ char *magic, *branch, *cp;
+
+ tag = version;
+
+ /*
+ * If this is a magic revision, we turn it into either its
+ * physical branch equivalent (if one exists) or into
+ * its base revision, which we assume exists.
+ */
+ dots = numdots (tag);
+ if (dots > 2 && (dots & 1) != 0)
+ {
+ branch = strrchr (tag, '.');
+ cp = branch++ - 1;
+ while (*cp != '.')
+ cp--;
+
+ /* see if we have .magic-branch. (".0.") */
+ magic = xmalloc (strlen (tag) + 1);
+ (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
+ if (strncmp (magic, cp, strlen (magic)) == 0)
+ {
+ /* it's magic. See if the branch exists */
+ *cp = '\0'; /* turn it into a revision */
+ (void) sprintf (magic, "%s.%s", tag, branch);
+ branch = RCS_getbranch (rcs, magic, 1);
+ free (magic);
+ if (branch != NULL)
+ {
+ free (tag);
+ return branch;
+ }
+ return tag;
+ }
+ free (magic);
+ }
+ }
+ else
+ {
+ /* The tag wasn't there, so return the head or NULL */
+ if (force_tag_match)
+ return NULL;
+ else
+ return RCS_head (rcs);
+ }
+ }
+ else
+ tag = xstrdup (symtag);
+
+ /* tag is always allocated and numeric now. */
+
+ /*
+ * numeric tag processing:
+ * 1) revision number - just return it
+ * 2) branch number - find head of branch
+ */
+
+ /* strip trailing dots */
+ while (tag[strlen (tag) - 1] == '.')
+ tag[strlen (tag) - 1] = '\0';
+
+ if ((numdots (tag) & 1) == 0)
+ {
+ char *branch;
+
+ /* we have a branch tag, so we need to walk the branch */
+ branch = RCS_getbranch (rcs, tag, force_tag_match);
+ free (tag);
+ return branch;
+ }
+ else
+ {
+ Node *p;
+
+ /* we have a revision tag, so make sure it exists */
+ p = findnode (rcs->versions, tag);
+ if (p != NULL)
+ {
+ /* We have found a numeric revision for the revision tag.
+ To support expanding the RCS keyword Name, if
+ SIMPLE_TAG is not NULL, tell the the caller that this
+ is a simple tag which co will recognize. FIXME: Are
+ there other cases in which we should set this? In
+ particular, what if we expand RCS keywords internally
+ without calling co? */
+ if (simple_tag != NULL)
+ *simple_tag = 1;
+ return tag;
+ }
+ else
+ {
+ /* The revision wasn't there, so return the head or NULL */
+ free (tag);
+ if (force_tag_match)
+ return NULL;
+ else
+ return RCS_head (rcs);
+ }
+ }
+}
+
+
+
+/*
+ * Return a "magic" revision as a virtual branch off of REV for the RCS file.
+ * A "magic" revision is one which is unique in the RCS file. By unique, I
+ * mean we return a revision which:
+ * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
+ * - has a revision component which is not an existing branch off REV
+ * - has a revision component which is not an existing magic revision
+ * - is an even-numbered revision, to avoid conflicts with vendor branches
+ * The first point is what makes it "magic".
+ *
+ * As an example, if we pass in 1.37 as REV, we will look for an existing
+ * branch called 1.37.2. If it did not exist, we would look for an
+ * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
+ * didn't exist, then we know that the 1.37.2 branch can be reserved by
+ * creating a symbolic tag with 1.37.0.2 as the numeric part.
+ *
+ * This allows us to fork development with very little overhead -- just a
+ * symbolic tag is used in the RCS file. When a commit is done, a physical
+ * branch is dynamically created to hold the new revision.
+ *
+ * Note: We assume that REV is an RCS revision and not a branch number.
+ */
+static char *check_rev;
+char *
+RCS_magicrev (RCSNode *rcs, char *rev)
+{
+ int rev_num;
+ char *xrev, *test_branch, *local_branch_num;
+
+ xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
+ check_rev = xrev;
+
+ local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
+ if (local_branch_num)
+ {
+ rev_num = atoi(local_branch_num);
+ if (rev_num < 2)
+ rev_num = 2;
+ else
+ rev_num &= ~1;
+ }
+ else
+ rev_num = 2;
+
+ /* only look at even numbered branches */
+ for ( ; ; rev_num += 2)
+ {
+ /* see if the physical branch exists */
+ (void) sprintf (xrev, "%s.%d", rev, rev_num);
+ test_branch = RCS_getbranch (rcs, xrev, 1);
+ if (test_branch != NULL) /* it did, so keep looking */
+ {
+ free (test_branch);
+ continue;
+ }
+
+ /* now, create a "magic" revision */
+ (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
+
+ /* walk the symbols list to see if a magic one already exists */
+ if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
+ continue;
+
+ /* we found a free magic branch. Claim it as ours */
+ return xrev;
+ }
+}
+
+
+
+/*
+ * walklist proc to look for a match in the symbols list.
+ * Returns 0 if the symbol does not match, 1 if it does.
+ */
+static int
+checkmagic_proc (Node *p, void *closure)
+{
+ if (STREQ (check_rev, p->data))
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/*
+ * Given an RCSNode, returns non-zero if the specified revision number
+ * or symbolic tag resolves to a "branch" within the rcs file.
+ *
+ * FIXME: this is the same as RCS_nodeisbranch except for the special
+ * case for handling a null rcsnode.
+ */
+int
+RCS_isbranch (RCSNode *rcs, const char *rev)
+{
+ /* numeric revisions are easy -- even number of dots is a branch */
+ if (isdigit ((unsigned char) *rev))
+ return (numdots (rev) & 1) == 0;
+
+ /* assume a revision if you can't find the RCS info */
+ if (rcs == NULL)
+ return 0;
+
+ /* now, look for a match in the symbols list */
+ return RCS_nodeisbranch (rcs, rev);
+}
+
+
+
+/*
+ * Given an RCSNode, returns non-zero if the specified revision number
+ * or symbolic tag resolves to a "branch" within the rcs file. We do
+ * take into account any magic branches as well.
+ */
+int
+RCS_nodeisbranch (RCSNode *rcs, const char *rev)
+{
+ int dots;
+ char *version;
+
+ assert (rcs != NULL);
+
+ /* numeric revisions are easy -- even number of dots is a branch */
+ if (isdigit ((unsigned char) *rev))
+ return (numdots (rev) & 1) == 0;
+
+ version = translate_symtag (rcs, rev);
+ if (version == NULL)
+ return 0;
+ dots = numdots (version);
+ if ((dots & 1) == 0)
+ {
+ free (version);
+ return 1;
+ }
+
+ /* got a symbolic tag match, but it's not a branch; see if it's magic */
+ if (dots > 2)
+ {
+ char *magic;
+ char *branch = strrchr (version, '.');
+ char *cp = branch - 1;
+ while (*cp != '.')
+ cp--;
+
+ /* see if we have .magic-branch. (".0.") */
+ magic = Xasprintf (".%d.", RCS_MAGIC_BRANCH);
+ if (strncmp (magic, cp, strlen (magic)) == 0)
+ {
+ free (magic);
+ free (version);
+ return 1;
+ }
+ free (magic);
+ }
+ free (version);
+ return 0;
+}
+
+
+
+/*
+ * Returns a pointer to malloc'ed memory which contains the branch
+ * for the specified *symbolic* tag. Magic branches are handled correctly.
+ */
+char *
+RCS_whatbranch (RCSNode *rcs, const char *rev)
+{
+ char *version;
+ int dots;
+
+ /* assume no branch if you can't find the RCS info */
+ if (rcs == NULL)
+ return NULL;
+
+ /* now, look for a match in the symbols list */
+ version = translate_symtag (rcs, rev);
+ if (version == NULL)
+ return NULL;
+ dots = numdots (version);
+ if ((dots & 1) == 0)
+ return version;
+
+ /* got a symbolic tag match, but it's not a branch; see if it's magic */
+ if (dots > 2)
+ {
+ char *magic;
+ char *branch = strrchr (version, '.');
+ char *cp = branch++ - 1;
+ while (*cp != '.')
+ cp--;
+
+ /* see if we have .magic-branch. (".0.") */
+ magic = xmalloc (strlen (version) + 1);
+ (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
+ if (strncmp (magic, cp, strlen (magic)) == 0)
+ {
+ /* yep. it's magic. now, construct the real branch */
+ *cp = '\0'; /* turn it into a revision */
+ (void) sprintf (magic, "%s.%s", version, branch);
+ free (version);
+ return magic;
+ }
+ free (magic);
+ }
+ free (version);
+ return NULL;
+}
+
+
+
+/*
+ * Get the head of the specified branch. If the branch does not exist,
+ * return NULL or RCS_head depending on force_tag_match.
+ * Returns NULL or a newly malloc'd string.
+ */
+char *
+RCS_getbranch (RCSNode *rcs, const char *tag, int force_tag_match)
+{
+ Node *p, *head;
+ RCSVers *vn;
+ char *xtag;
+ char *nextvers;
+ char *cp;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* find out if the tag contains a dot, or is on the trunk */
+ cp = strrchr (tag, '.');
+
+ /* trunk processing is the special case */
+ if (cp == NULL)
+ {
+ xtag = Xasprintf ("%s.", tag);
+ for (cp = rcs->head; cp != NULL;)
+ {
+ if (strncmp (xtag, cp, strlen (xtag)) == 0)
+ break;
+ p = findnode (rcs->versions, cp);
+ if (p == NULL)
+ {
+ free (xtag);
+ if (force_tag_match)
+ return NULL;
+ else
+ return RCS_head (rcs);
+ }
+ vn = p->data;
+ cp = vn->next;
+ }
+ free (xtag);
+ if (cp == NULL)
+ {
+ if (force_tag_match)
+ return NULL;
+ else
+ return RCS_head (rcs);
+ }
+ return xstrdup (cp);
+ }
+
+ /* if it had a `.', terminate the string so we have the base revision */
+ *cp = '\0';
+
+ /* look up the revision this branch is based on */
+ p = findnode (rcs->versions, tag);
+
+ /* put the . back so we have the branch again */
+ *cp = '.';
+
+ if (p == NULL)
+ {
+ /* if the base revision didn't exist, return head or NULL */
+ if (force_tag_match)
+ return NULL;
+ else
+ return RCS_head (rcs);
+ }
+
+ /* find the first element of the branch we are looking for */
+ vn = p->data;
+ if (vn->branches == NULL)
+ return NULL;
+ xtag = Xasprintf ("%s.", tag);
+ head = vn->branches->list;
+ for (p = head->next; p != head; p = p->next)
+ if (strncmp (p->key, xtag, strlen (xtag)) == 0)
+ break;
+ free (xtag);
+
+ if (p == head)
+ {
+ /* we didn't find a match so return head or NULL */
+ if (force_tag_match)
+ return NULL;
+ else
+ return RCS_head (rcs);
+ }
+
+ /* now walk the next pointers of the branch */
+ nextvers = p->key;
+ do
+ {
+ p = findnode (rcs->versions, nextvers);
+ if (p == NULL)
+ {
+ /* a link in the chain is missing - return head or NULL */
+ if (force_tag_match)
+ return NULL;
+ else
+ return RCS_head (rcs);
+ }
+ vn = p->data;
+ nextvers = vn->next;
+ } while (nextvers != NULL);
+
+ /* we have the version in our hand, so go for it */
+ return xstrdup (vn->version);
+}
+
+
+
+/* Returns the head of the branch which REV is on. REV can be a
+ branch tag or non-branch tag; symbolic or numeric.
+
+ Returns a newly malloc'd string. Returns NULL if a symbolic name
+ isn't found. */
+char *
+RCS_branch_head (RCSNode *rcs, char *rev)
+{
+ char *num;
+ char *br;
+ char *retval;
+
+ assert (rcs != NULL);
+
+ if (RCS_nodeisbranch (rcs, rev))
+ return RCS_getbranch (rcs, rev, 1);
+
+ if (isdigit ((unsigned char) *rev))
+ num = xstrdup (rev);
+ else
+ {
+ num = translate_symtag (rcs, rev);
+ if (num == NULL)
+ return NULL;
+ }
+ br = truncate_revnum (num);
+ retval = RCS_getbranch (rcs, br, 1);
+ free (br);
+ free (num);
+ return retval;
+}
+
+
+
+/* Get the branch point for a particular branch, that is the first
+ revision on that branch. For example, RCS_getbranchpoint (rcs,
+ "1.3.2") will normally return "1.3.2.1". TARGET may be either a
+ branch number or a revision number; if a revnum, find the
+ branchpoint of the branch to which TARGET belongs.
+
+ Return RCS_head if TARGET is on the trunk or if the root node could
+ not be found (this is sort of backwards from our behavior on a branch;
+ the rationale is that the return value is a revision from which you
+ can start walking the next fields and end up at TARGET).
+ Return NULL on error. */
+static char *
+RCS_getbranchpoint (RCSNode *rcs, char *target)
+{
+ char *branch, *bp;
+ Node *vp;
+ RCSVers *rev;
+ int dots, isrevnum, brlen;
+
+ dots = numdots (target);
+ isrevnum = dots & 1;
+
+ if (dots == 1)
+ /* TARGET is a trunk revision; return rcs->head. */
+ return RCS_head (rcs);
+
+ /* Get the revision number of the node at which TARGET's branch is
+ rooted. If TARGET is a branch number, lop off the last field;
+ if it's a revision number, lop off the last *two* fields. */
+ branch = xstrdup (target);
+ bp = strrchr (branch, '.');
+ if (bp == NULL)
+ error (1, 0, "%s: confused revision number %s",
+ rcs->print_path, target);
+ if (isrevnum)
+ while (*--bp != '.')
+ ;
+ *bp = '\0';
+
+ vp = findnode (rcs->versions, branch);
+ if (vp == NULL)
+ {
+ error (0, 0, "%s: can't find branch point %s", rcs->print_path, target);
+ free (branch);
+ return NULL;
+ }
+ rev = vp->data;
+
+ *bp++ = '.';
+ while (*bp && *bp != '.')
+ ++bp;
+ brlen = bp - branch;
+
+ vp = rev->branches->list->next;
+ while (vp != rev->branches->list)
+ {
+ /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
+ maybe a full revision number, e.g. `1.1.3.6'. We have
+ found our branch point if the first BRANCHLEN characters
+ of the revision number match, *and* if the following
+ character is a dot. */
+ if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
+ break;
+ vp = vp->next;
+ }
+
+ free (branch);
+ if (vp == rev->branches->list)
+ {
+ error (0, 0, "%s: can't find branch point %s", rcs->print_path, target);
+ return NULL;
+ }
+ else
+ return xstrdup (vp->key);
+}
+
+
+
+/*
+ * Get the head of the RCS file. If branch is set, this is the head of the
+ * branch, otherwise the real head.
+ *
+ * INPUTS
+ * rcs The parsed rcs node information.
+ *
+ * RETURNS
+ * NULL when rcs->branch exists and cannot be found.
+ * A newly malloc'd string, otherwise.
+ */
+char *
+RCS_head (RCSNode *rcs)
+{
+ /* make sure we have something to look at... */
+ assert (rcs);
+
+ /*
+ * NOTE: we call getbranch with force_tag_match set to avoid any
+ * possibility of recursion
+ */
+ if (rcs->branch)
+ return RCS_getbranch (rcs, rcs->branch, 1);
+ else
+ return xstrdup (rcs->head);
+}
+
+
+
+/*
+ * Get the most recent revision, based on the supplied date, but use some
+ * funky stuff and follow the vendor branch maybe
+ */
+char *
+RCS_getdate (RCSNode *rcs, const char *date, int force_tag_match)
+{
+ char *cur_rev = NULL;
+ char *retval = NULL;
+ Node *p;
+ RCSVers *vers = NULL;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* if the head is on a branch, try the branch first */
+ if (rcs->branch != NULL)
+ {
+ retval = RCS_getdatebranch (rcs, date, rcs->branch);
+ if (retval != NULL)
+ return retval;
+ }
+
+ /* otherwise if we have a trunk, try it */
+ if (rcs->head)
+ {
+ p = findnode (rcs->versions, rcs->head);
+ if (p == NULL)
+ {
+ error (0, 0, "%s: head revision %s doesn't exist", rcs->print_path,
+ rcs->head);
+ }
+ while (p != NULL)
+ {
+ /* if the date of this one is before date, take it */
+ vers = p->data;
+ if (RCS_datecmp (vers->date, date) <= 0)
+ {
+ cur_rev = vers->version;
+ break;
+ }
+
+ /* if there is a next version, find the node */
+ if (vers->next != NULL)
+ p = findnode (rcs->versions, vers->next);
+ else
+ p = NULL;
+ }
+ }
+ else
+ error (0, 0, "%s: no head revision", rcs->print_path);
+
+ /*
+ * at this point, either we have the revision we want, or we have the
+ * first revision on the trunk (1.1?) in our hands, or we've come up
+ * completely empty
+ */
+
+ /* if we found what we're looking for, and it's not 1.1 return it */
+ if (cur_rev != NULL)
+ {
+ if (! STREQ (cur_rev, "1.1"))
+ return xstrdup (cur_rev);
+
+ /* This is 1.1; if the date of 1.1 is not the same as that for the
+ 1.1.1.1 version, then return 1.1. This happens when the first
+ version of a file is created by a regular cvs add and commit,
+ and there is a subsequent cvs import of the same file. */
+ p = findnode (rcs->versions, "1.1.1.1");
+ if (p)
+ {
+ char *date_1_1 = vers->date;
+
+ vers = p->data;
+ if (RCS_datecmp (vers->date, date_1_1) != 0)
+ return xstrdup ("1.1");
+ }
+ }
+
+ /* look on the vendor branch */
+ retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
+
+ /*
+ * if we found a match, return it; otherwise, we return the first
+ * revision on the trunk or NULL depending on force_tag_match and the
+ * date of the first rev
+ */
+ if (retval != NULL)
+ return retval;
+
+ if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0))
+ return xstrdup (vers->version);
+ else
+ return NULL;
+}
+
+
+
+/*
+ * Look up the last element on a branch that was put in before or on
+ * the specified date and time (return the rev or NULL)
+ */
+static char *
+RCS_getdatebranch (RCSNode *rcs, const char *date, const char *branch)
+{
+ char *cur_rev = NULL;
+ char *cp;
+ char *xbranch, *xrev;
+ Node *p;
+ RCSVers *vers;
+
+ /* look up the first revision on the branch */
+ xrev = xstrdup (branch);
+ cp = strrchr (xrev, '.');
+ if (cp == NULL)
+ {
+ free (xrev);
+ return NULL;
+ }
+ *cp = '\0'; /* turn it into a revision */
+
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ p = findnode (rcs->versions, xrev);
+ free (xrev);
+ if (p == NULL)
+ return NULL;
+ vers = p->data;
+
+ /* Tentatively use this revision, if it is early enough. */
+ if (RCS_datecmp (vers->date, date) <= 0)
+ cur_rev = vers->version;
+
+ /* If no branches list, return now. This is what happens if the branch
+ is a (magic) branch with no revisions yet. */
+ if (vers->branches == NULL)
+ return xstrdup (cur_rev);
+
+ /* walk the branches list looking for the branch number */
+ xbranch = Xasprintf ("%s.", branch);
+ for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
+ if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
+ break;
+ free (xbranch);
+ if (p == vers->branches->list)
+ {
+ /* This is what happens if the branch is a (magic) branch with
+ no revisions yet. Similar to the case where vers->branches ==
+ NULL, except here there was a another branch off the same
+ branchpoint. */
+ return xstrdup (cur_rev);
+ }
+
+ p = findnode (rcs->versions, p->key);
+
+ /* walk the next pointers until you find the end, or the date is too late */
+ while (p != NULL)
+ {
+ vers = p->data;
+ if (RCS_datecmp (vers->date, date) <= 0)
+ cur_rev = vers->version;
+ else
+ break;
+
+ /* if there is a next version, find the node */
+ if (vers->next != NULL)
+ p = findnode (rcs->versions, vers->next);
+ else
+ p = NULL;
+ }
+
+ /* Return whatever we found, which may be NULL. */
+ return xstrdup (cur_rev);
+}
+
+
+
+/*
+ * Compare two dates in RCS format. Beware the change in format on January 1,
+ * 2000, when years go from 2-digit to full format.
+ */
+int
+RCS_datecmp (const char *date1, const char *date2)
+{
+ int length_diff = strlen (date1) - strlen (date2);
+
+ return length_diff ? length_diff : strcmp (date1, date2);
+}
+
+
+
+/* Look up revision REV in RCS and return the date specified for the
+ revision minus FUDGE seconds (FUDGE will generally be one, so that the
+ logically previous revision will be found later, or zero, if we want
+ the exact date).
+
+ The return value is the date being returned as a time_t, or (time_t)-1
+ on error (previously was documented as zero on error; I haven't checked
+ the callers to make sure that they really check for (time_t)-1, but
+ the latter is what this function really returns). If DATE is non-NULL,
+ then it must point to MAXDATELEN characters, and we store the same
+ return value there in DATEFORM format. */
+time_t
+RCS_getrevtime (RCSNode *rcs, const char *rev, char *date, int fudge)
+{
+ char *tdate;
+ struct tm xtm, *ftm;
+ struct timespec revdate;
+ Node *p;
+ RCSVers *vers;
+
+ /* make sure we have something to look at... */
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* look up the revision */
+ p = findnode (rcs->versions, rev);
+ if (p == NULL)
+ return -1;
+ vers = p->data;
+
+ /* split up the date */
+ if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon,
+ &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
+ error (1, 0, "%s: invalid date for revision %s (%s)", rcs->print_path,
+ rev, vers->date);
+
+ /* If the year is from 1900 to 1999, RCS files contain only two
+ digits, and sscanf gives us a year from 0-99. If the year is
+ 2000+, RCS files contain all four digits and we subtract 1900,
+ because the tm_year field should contain years since 1900. */
+
+ if (xtm.tm_year >= 100 && xtm.tm_year < 2000)
+ error (0, 0, "%s: non-standard date format for revision %s (%s)",
+ rcs->print_path, rev, vers->date);
+ if (xtm.tm_year >= 1900)
+ xtm.tm_year -= 1900;
+
+ /* put the date in a form getdate can grok */
+ tdate = Xasprintf ("%d-%d-%d %d:%d:%d -0000",
+ xtm.tm_year + 1900, xtm.tm_mon, xtm.tm_mday,
+ xtm.tm_hour, xtm.tm_min, xtm.tm_sec);
+
+ /* Turn it into seconds since the epoch.
+ *
+ * We use a struct timespec since that is what getdate requires, then
+ * truncate the nanoseconds.
+ */
+ if (!get_date (&revdate, tdate, NULL))
+ {
+ free (tdate);
+ return (time_t)-1;
+ }
+ free (tdate);
+
+ revdate.tv_sec -= fudge; /* remove "fudge" seconds */
+ if (date)
+ {
+ /* Put an appropriate string into `date', if we were given one. */
+ ftm = gmtime (&revdate.tv_sec);
+ (void) sprintf (date, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+ }
+
+ return revdate.tv_sec;
+}
+
+
+
+List *
+RCS_getlocks (RCSNode *rcs)
+{
+ assert(rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (rcs->locks_data) {
+ rcs->locks = getlist ();
+ do_locks (rcs->locks, rcs->locks_data);
+ free(rcs->locks_data);
+ rcs->locks_data = NULL;
+ }
+
+ return rcs->locks;
+}
+
+
+
+List *
+RCS_symbols(RCSNode *rcs)
+{
+ assert(rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (rcs->symbols_data) {
+ rcs->symbols = getlist ();
+ do_symbols (rcs->symbols, rcs->symbols_data);
+ free(rcs->symbols_data);
+ rcs->symbols_data = NULL;
+ }
+
+ return rcs->symbols;
+}
+
+
+
+/*
+ * Return the version associated with a particular symbolic tag.
+ * Returns NULL or a newly malloc'd string.
+ */
+static char *
+translate_symtag (RCSNode *rcs, const char *tag)
+{
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (rcs->symbols != NULL)
+ {
+ Node *p;
+
+ /* The symbols have already been converted into a list. */
+ p = findnode (rcs->symbols, tag);
+ if (p == NULL)
+ return NULL;
+
+ return xstrdup (p->data);
+ }
+
+ if (rcs->symbols_data != NULL)
+ {
+ size_t len;
+ char *cp, *last;
+
+ /* Look through the RCS symbols information. This is like
+ do_symbols, but we don't add the information to a list. In
+ most cases, we will only be called once for this file, so
+ generating the list is unnecessary overhead. */
+
+ len = strlen (tag);
+ cp = rcs->symbols_data;
+ /* Keeping track of LAST below isn't strictly necessary, now that tags
+ * should be parsed for validity before they are accepted, but tags
+ * with spaces used to cause the code below to loop indefintely, so
+ * I have corrected for that. Now, in the event that I missed
+ * something, the server cannot be hung. -DRP
+ */
+ last = NULL;
+ while ((cp = strchr (cp, tag[0])) != NULL)
+ {
+ if (cp == last) break;
+ if ((cp == rcs->symbols_data || whitespace (cp[-1]))
+ && strncmp (cp, tag, len) == 0
+ && cp[len] == ':')
+ {
+ char *v, *r;
+
+ /* We found the tag. Return the version number. */
+
+ cp += len + 1;
+ v = cp;
+ while (! whitespace (*cp) && *cp != '\0')
+ ++cp;
+ r = xmalloc (cp - v + 1);
+ strncpy (r, v, cp - v);
+ r[cp - v] = '\0';
+ return r;
+ }
+
+ while (! whitespace (*cp) && *cp != '\0')
+ ++cp;
+ if (*cp == '\0')
+ break;
+ last = cp;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+/*
+ * The argument ARG is the getopt remainder of the -k option specified on the
+ * command line. This function returns malloc'ed space that can be used
+ * directly in calls to RCS V5, with the -k flag munged correctly.
+ */
+char *
+RCS_check_kflag (const char *arg)
+{
+ static const char *const keyword_usage[] =
+ {
+ "%s %s: invalid RCS keyword expansion mode\n",
+ "Valid expansion modes include:\n",
+ " -kkv\tGenerate keywords using the default form.\n",
+ " -kkvl\tLike -kkv, except locker's name inserted.\n",
+ " -kk\tGenerate only keyword names in keyword strings.\n",
+ " -kv\tGenerate only keyword values in keyword strings.\n",
+ " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
+ " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL,
+ };
+ char const *const *cpp = NULL;
+
+ if (arg)
+ {
+ for (cpp = kflags; *cpp != NULL; cpp++)
+ {
+ if (STREQ (arg, *cpp))
+ break;
+ }
+ }
+
+ if (arg == NULL || *cpp == NULL)
+ {
+ usage (keyword_usage);
+ }
+
+ return Xasprintf ("-k%s", *cpp);
+}
+
+
+
+/*
+ * Do some consistency checks on the symbolic tag... These should equate
+ * pretty close to what RCS checks, though I don't know for certain.
+ */
+void
+RCS_check_tag (const char *tag)
+{
+ char *invalid = "$,.:;@"; /* invalid RCS tag characters */
+ const char *cp;
+
+ /*
+ * The first character must be an alphabetic letter. The remaining
+ * characters cannot be non-visible graphic characters, and must not be
+ * in the set of "invalid" RCS identifier characters.
+ */
+ if (isalpha ((unsigned char) *tag))
+ {
+ for (cp = tag; *cp; cp++)
+ {
+ if (!isgraph ((unsigned char) *cp))
+ error (1, 0, "tag `%s' has non-visible graphic characters",
+ tag);
+ if (strchr (invalid, *cp))
+ error (1, 0, "tag `%s' must not contain the characters `%s'",
+ tag, invalid);
+ }
+ }
+ else
+ error (1, 0, "tag `%s' must start with a letter", tag);
+}
+
+
+
+/*
+ * TRUE if argument has valid syntax for an RCS revision or
+ * branch number. All characters must be digits or dots, first
+ * and last characters must be digits, and no two consecutive
+ * characters may be dots.
+ *
+ * Intended for classifying things, so this function doesn't
+ * call error.
+ */
+int
+RCS_valid_rev (const char *rev)
+{
+ char last, c;
+ last = *rev++;
+ if (!isdigit ((unsigned char) last))
+ return 0;
+ while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
+ {
+ if (c == '.')
+ {
+ if (last == '.')
+ return 0;
+ continue;
+ }
+ last = c;
+ if (!isdigit ((unsigned char) c))
+ return 0;
+ }
+ if (!isdigit ((unsigned char) last))
+ return 0;
+ return 1;
+}
+
+
+
+/*
+ * Return true if RCS revision with TAG is a dead revision.
+ */
+int
+RCS_isdead (RCSNode *rcs, const char *tag)
+{
+ Node *p;
+ RCSVers *version;
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ p = findnode (rcs->versions, tag);
+ if (p == NULL)
+ return 0;
+
+ version = p->data;
+ return version->dead;
+}
+
+
+
+/* Return the RCS keyword expansion mode. For example "b" for binary.
+ Returns a pointer into storage which is allocated and freed along with
+ the rest of the RCS information; the caller should not modify this
+ storage. Returns NULL if the RCS file does not specify a keyword
+ expansion mode; for all other errors, die with a fatal error. */
+char *
+RCS_getexpand (RCSNode *rcs)
+{
+ /* Since RCS_parsercsfile_i now reads expand, don't need to worry
+ about RCS_reparsercsfile. */
+ assert (rcs != NULL);
+ return rcs->expand;
+}
+
+
+
+/* Set keyword expansion mode to EXPAND. For example "b" for binary. */
+void
+RCS_setexpand (RCSNode *rcs, const char *expand)
+{
+ /* Since RCS_parsercsfile_i now reads expand, don't need to worry
+ about RCS_reparsercsfile. */
+ assert (rcs != NULL);
+ if (rcs->expand != NULL)
+ free (rcs->expand);
+ rcs->expand = xstrdup (expand);
+}
+
+
+
+/* RCS keywords, and a matching enum. */
+enum keyword
+{
+ KEYWORD_AUTHOR = 0,
+ KEYWORD_DATE,
+ KEYWORD_CVSHEADER,
+ KEYWORD_HEADER,
+ KEYWORD_ID,
+ KEYWORD_LOCKER,
+ KEYWORD_LOG,
+ KEYWORD_NAME,
+ KEYWORD_RCSFILE,
+ KEYWORD_REVISION,
+ KEYWORD_SOURCE,
+ KEYWORD_STATE,
+ KEYWORD_LOCALID
+};
+struct rcs_keyword
+{
+ const char *string;
+ size_t len;
+ enum keyword expandto;
+ bool expandit;
+};
+
+
+
+static inline struct rcs_keyword *
+new_keywords (void)
+{
+ struct rcs_keyword *new;
+ new = xcalloc (KEYWORD_LOCALID + 2, sizeof (struct rcs_keyword));
+
+#define KEYWORD_INIT(k, i, s) \
+ k[i].string = s; \
+ k[i].len = sizeof s - 1; \
+ k[i].expandto = i; \
+ k[i].expandit = true
+
+ KEYWORD_INIT (new, KEYWORD_AUTHOR, "Author");
+ KEYWORD_INIT (new, KEYWORD_DATE, "Date");
+ KEYWORD_INIT (new, KEYWORD_CVSHEADER, "CVSHeader");
+ KEYWORD_INIT (new, KEYWORD_HEADER, "Header");
+ KEYWORD_INIT (new, KEYWORD_ID, "Id");
+ KEYWORD_INIT (new, KEYWORD_LOCKER, "Locker");
+ KEYWORD_INIT (new, KEYWORD_LOG, "Log");
+ KEYWORD_INIT (new, KEYWORD_NAME, "Name");
+ KEYWORD_INIT (new, KEYWORD_RCSFILE, "RCSfile");
+ KEYWORD_INIT (new, KEYWORD_REVISION, "Revision");
+ KEYWORD_INIT (new, KEYWORD_SOURCE, "Source");
+ KEYWORD_INIT (new, KEYWORD_STATE, "State");
+
+ return new;
+}
+
+
+
+void
+free_keywords (void *keywords)
+{
+ free (keywords);
+}
+
+
+
+/* Convert an RCS date string into a readable string. This is like
+ the RCS date2str function. */
+static char *
+printable_date (const char *rcs_date)
+{
+ int year, mon, mday, hour, min, sec;
+ char buf[100];
+
+ (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
+ &sec);
+ if (year < 1900)
+ year += 1900;
+ sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
+ hour, min, sec);
+ return xstrdup (buf);
+}
+
+
+
+/* Escape the characters in a string so that it can be included in an
+ RCS value. */
+static char *
+escape_keyword_value (const char *value, int *free_value)
+{
+ char *ret, *t;
+ const char *s;
+
+ for (s = value; *s != '\0'; s++)
+ {
+ char c;
+
+ c = *s;
+ if (c == '\t'
+ || c == '\n'
+ || c == '\\'
+ || c == ' '
+ || c == '$')
+ {
+ break;
+ }
+ }
+
+ if (*s == '\0')
+ {
+ *free_value = 0;
+ return (char *) value;
+ }
+
+ ret = xmalloc (strlen (value) * 4 + 1);
+ *free_value = 1;
+
+ for (s = value, t = ret; *s != '\0'; s++, t++)
+ {
+ switch (*s)
+ {
+ default:
+ *t = *s;
+ break;
+ case '\t':
+ *t++ = '\\';
+ *t = 't';
+ break;
+ case '\n':
+ *t++ = '\\';
+ *t = 'n';
+ break;
+ case '\\':
+ *t++ = '\\';
+ *t = '\\';
+ break;
+ case ' ':
+ *t++ = '\\';
+ *t++ = '0';
+ *t++ = '4';
+ *t = '0';
+ break;
+ case '$':
+ *t++ = '\\';
+ *t++ = '0';
+ *t++ = '4';
+ *t = '4';
+ break;
+ }
+ }
+
+ *t = '\0';
+
+ return ret;
+}
+
+
+
+/* Expand RCS keywords in the memory buffer BUF of length LEN. This
+ applies to file RCS and version VERS. If NAME is not NULL, and is
+ not a numeric revision, then it is the symbolic tag used for the
+ checkout. EXPAND indicates how to expand the keywords. This
+ function sets *RETBUF and *RETLEN to the new buffer and length.
+ This function may modify the buffer BUF. If BUF != *RETBUF, then
+ RETBUF is a newly allocated buffer. */
+static void
+expand_keywords (RCSNode *rcs, RCSVers *ver, const char *name, const char *log,
+ size_t loglen, enum kflag expand, char *buf, size_t len,
+ char **retbuf, size_t *retlen)
+{
+ struct expand_buffer
+ {
+ struct expand_buffer *next;
+ char *data;
+ size_t len;
+ int free_data;
+ } *ebufs = NULL;
+ struct expand_buffer *ebuf_last = NULL;
+ size_t ebuf_len = 0;
+ char *locker;
+ char *srch, *srch_next;
+ size_t srch_len;
+ const struct rcs_keyword *keywords;
+
+ if (!config /* For `cvs init', config may not be set. */
+ ||expand == KFLAG_O || expand == KFLAG_B)
+ {
+ *retbuf = buf;
+ *retlen = len;
+ return;
+ }
+
+ if (!config->keywords) config->keywords = new_keywords ();
+ keywords = config->keywords;
+
+ /* If we are using -kkvl, dig out the locker information if any. */
+ locker = NULL;
+ if (expand == KFLAG_KVL)
+ {
+ Node *lock;
+ lock = findnode (RCS_getlocks(rcs), ver->version);
+ if (lock != NULL)
+ locker = xstrdup (lock->data);
+ }
+
+ /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
+ srch = buf;
+ srch_len = len;
+ while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
+ {
+ char *s, *send;
+ size_t slen;
+ const struct rcs_keyword *keyword;
+ char *value;
+ int free_value;
+ char *sub;
+ size_t sublen;
+
+ srch_len -= (srch_next + 1) - srch;
+ srch = srch_next + 1;
+
+ /* Look for the first non alphabetic character after the '$'. */
+ send = srch + srch_len;
+ for (s = srch; s < send; s++)
+ if (! isalpha ((unsigned char) *s))
+ break;
+
+ /* If the first non alphabetic character is not '$' or ':',
+ then this is not an RCS keyword. */
+ if (s == send || (*s != '$' && *s != ':'))
+ continue;
+
+ /* See if this is one of the keywords. */
+ slen = s - srch;
+ for (keyword = keywords; keyword->string != NULL; keyword++)
+ {
+ if (keyword->expandit
+ && keyword->len == slen
+ && strncmp (keyword->string, srch, slen) == 0)
+ {
+ break;
+ }
+ }
+ if (keyword->string == NULL)
+ continue;
+
+ /* If the keyword ends with a ':', then the old value consists
+ of the characters up to the next '$'. If there is no '$'
+ before the end of the line, though, then this wasn't an RCS
+ keyword after all. */
+ if (*s == ':')
+ {
+ for (; s < send; s++)
+ if (*s == '$' || *s == '\n')
+ break;
+ if (s == send || *s != '$')
+ continue;
+ }
+
+ /* At this point we must replace the string from SRCH to S
+ with the expansion of the keyword KW. */
+
+ /* Get the value to use. */
+ free_value = 0;
+ if (expand == KFLAG_K)
+ value = NULL;
+ else
+ {
+ switch (keyword->expandto)
+ {
+ default:
+ assert (!"unreached");
+
+ case KEYWORD_AUTHOR:
+ value = ver->author;
+ break;
+
+ case KEYWORD_DATE:
+ value = printable_date (ver->date);
+ free_value = 1;
+ break;
+
+ case KEYWORD_CVSHEADER:
+ case KEYWORD_HEADER:
+ case KEYWORD_ID:
+ case KEYWORD_LOCALID:
+ {
+ const char *path;
+ int free_path;
+ char *date;
+ char *old_path;
+
+ old_path = NULL;
+ if (keyword->expandto == KEYWORD_HEADER)
+ path = rcs->print_path;
+ else if (keyword->expandto == KEYWORD_CVSHEADER)
+ path = getfullCVSname (rcs->print_path, &old_path);
+ else
+ path = last_component (rcs->print_path);
+ path = escape_keyword_value (path, &free_path);
+ date = printable_date (ver->date);
+ value = Xasprintf ("%s %s %s %s %s%s%s",
+ path, ver->version, date, ver->author,
+ ver->state,
+ locker != NULL ? " " : "",
+ locker != NULL ? locker : "");
+ if (free_path)
+ /* If free_path is set then we know we allocated path
+ * and we can discard the const.
+ */
+ free ((char *)path);
+ if (old_path)
+ free (old_path);
+ free (date);
+ free_value = 1;
+ }
+ break;
+
+ case KEYWORD_LOCKER:
+ value = locker;
+ break;
+
+ case KEYWORD_LOG:
+ case KEYWORD_RCSFILE:
+ value = escape_keyword_value (last_component (rcs->print_path),
+ &free_value);
+ break;
+
+ case KEYWORD_NAME:
+ if (name != NULL && ! isdigit ((unsigned char) *name))
+ value = (char *) name;
+ else
+ value = NULL;
+ break;
+
+ case KEYWORD_REVISION:
+ value = ver->version;
+ break;
+
+ case KEYWORD_SOURCE:
+ value = escape_keyword_value (rcs->print_path, &free_value);
+ break;
+
+ case KEYWORD_STATE:
+ value = ver->state;
+ break;
+ }
+ }
+
+ sub = xmalloc (keyword->len
+ + (value == NULL ? 0 : strlen (value))
+ + 10);
+ if (expand == KFLAG_V)
+ {
+ /* Decrement SRCH and increment S to remove the $
+ characters. */
+ --srch;
+ ++srch_len;
+ ++s;
+ sublen = 0;
+ }
+ else
+ {
+ strcpy (sub, keyword->string);
+ sublen = strlen (keyword->string);
+ if (expand != KFLAG_K)
+ {
+ sub[sublen] = ':';
+ sub[sublen + 1] = ' ';
+ sublen += 2;
+ }
+ }
+ if (value != NULL)
+ {
+ strcpy (sub + sublen, value);
+ sublen += strlen (value);
+ }
+ if (expand != KFLAG_V && expand != KFLAG_K)
+ {
+ sub[sublen] = ' ';
+ ++sublen;
+ sub[sublen] = '\0';
+ }
+
+ if (free_value)
+ free (value);
+
+ /* The Log keyword requires special handling. This behaviour
+ is taken from RCS 5.7. The special log message is what RCS
+ uses for ci -k. */
+ if (keyword->expandto == KEYWORD_LOG
+ && (sizeof "checked in with -k by " <= loglen
+ || log == NULL
+ || strncmp (log, "checked in with -k by ",
+ sizeof "checked in with -k by " - 1) != 0))
+ {
+ char *start;
+ char *leader;
+ size_t leader_len, leader_sp_len;
+ const char *logend;
+ const char *snl;
+ int cnl;
+ char *date;
+ const char *sl;
+
+ /* We are going to insert the trailing $ ourselves, before
+ the log message, so we must remove it from S, if we
+ haven't done so already. */
+ if (expand != KFLAG_V)
+ ++s;
+
+ /* CVS never has empty log messages, but old RCS files might. */
+ if (log == NULL)
+ log = "";
+
+ /* Find the start of the line. */
+ start = srch;
+ leader_len = 0;
+ while (start > buf && start[-1] != '\n'
+ && leader_len <= xsum (config->MaxCommentLeaderLength,
+ expand != KFLAG_V ? 1 : 0))
+ {
+ --start;
+ ++leader_len;
+ }
+
+ if (expand != KFLAG_V)
+ /* When automagically determined and !KFLAG_V, we wish to avoid
+ * including the leading `$' of the Log keyword in our leader.
+ */
+ --leader_len;
+
+ /* If the automagically determined leader exceeds the limit set in
+ * CVSROOT/config, try to use a fallback.
+ */
+ if (leader_len > config->MaxCommentLeaderLength)
+ {
+ if (config->UseArchiveCommentLeader && rcs->comment)
+ {
+ leader = xstrdup (rcs->comment);
+ leader_len = strlen (rcs->comment);
+ }
+ else
+ {
+ error (0, 0,
+"Skipping `$" "Log$' keyword due to excessive comment leader.");
+ continue;
+ }
+ }
+ else /* leader_len <= config->MaxCommentLeaderLength */
+ {
+ /* Copy the start of the line to use as a comment leader. */
+ leader = xmalloc (leader_len);
+ memcpy (leader, start, leader_len);
+ }
+
+ leader_sp_len = leader_len;
+ while (leader_sp_len > 0 && isspace (leader[leader_sp_len - 1]))
+ --leader_sp_len;
+
+ /* RCS does some checking for an old style of Log here,
+ but we don't bother. RCS issues a warning if it
+ changes anything. */
+
+ /* Count the number of newlines in the log message so that
+ we know how many copies of the leader we will need. */
+ cnl = 0;
+ logend = log + loglen;
+ for (snl = log; snl < logend; snl++)
+ if (*snl == '\n')
+ ++cnl;
+
+ /* If the log message did not end in a newline, increment
+ * the newline count so we have space for the extra leader.
+ * Failure to do so results in a buffer overrun.
+ */
+ if (loglen && snl[-1] != '\n')
+ ++cnl;
+
+ date = printable_date (ver->date);
+ sub = xrealloc (sub,
+ (sublen
+ + sizeof "Revision"
+ + strlen (ver->version)
+ + strlen (date)
+ + strlen (ver->author)
+ + loglen
+ /* Use CNL + 2 below: One leader for each log
+ * line, plus the Revision/Author/Date line,
+ * plus a trailing blank line.
+ */
+ + (cnl + 2) * leader_len
+ + 20));
+ if (expand != KFLAG_V)
+ {
+ sub[sublen] = '$';
+ ++sublen;
+ }
+ sub[sublen] = '\n';
+ ++sublen;
+ memcpy (sub + sublen, leader, leader_len);
+ sublen += leader_len;
+ sprintf (sub + sublen, "Revision %s %s %s\n",
+ ver->version, date, ver->author);
+ sublen += strlen (sub + sublen);
+ free (date);
+
+ sl = log;
+ while (sl < logend)
+ {
+ if (*sl == '\n')
+ {
+ memcpy (sub + sublen, leader, leader_sp_len);
+ sublen += leader_sp_len;
+ sub[sublen] = '\n';
+ ++sublen;
+ ++sl;
+ }
+ else
+ {
+ const char *slnl;
+
+ memcpy (sub + sublen, leader, leader_len);
+ sublen += leader_len;
+ for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
+ ;
+ if (slnl < logend)
+ ++slnl;
+ memcpy (sub + sublen, sl, slnl - sl);
+ sublen += slnl - sl;
+ if (slnl == logend && slnl[-1] != '\n')
+ {
+ /* There was no EOL at the end of the log message. Add
+ * one.
+ */
+ sub[sublen] = '\n';
+ ++sublen;
+ }
+ sl = slnl;
+ }
+ }
+
+ memcpy (sub + sublen, leader, leader_sp_len);
+ sublen += leader_sp_len;
+
+ free (leader);
+ }
+
+ /* Now SUB contains a string which is to replace the string
+ from SRCH to S. SUBLEN is the length of SUB. */
+
+ if (srch + sublen == s)
+ {
+ memcpy (srch, sub, sublen);
+ free (sub);
+ }
+ else
+ {
+ struct expand_buffer *ebuf;
+
+ /* We need to change the size of the buffer. We build a
+ list of expand_buffer structures. Each expand_buffer
+ structure represents a portion of the final output. We
+ concatenate them back into a single buffer when we are
+ done. This minimizes the number of potentially large
+ buffer copies we must do. */
+
+ if (ebufs == NULL)
+ {
+ ebufs = xmalloc (sizeof *ebuf);
+ ebufs->next = NULL;
+ ebufs->data = buf;
+ ebufs->free_data = 0;
+ ebuf_len = srch - buf;
+ ebufs->len = ebuf_len;
+ ebuf_last = ebufs;
+ }
+ else
+ {
+ assert (srch >= ebuf_last->data);
+ assert (srch <= ebuf_last->data + ebuf_last->len);
+ ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
+ ebuf_last->len = srch - ebuf_last->data;
+ }
+
+ ebuf = xmalloc (sizeof *ebuf);
+ ebuf->data = sub;
+ ebuf->len = sublen;
+ ebuf->free_data = 1;
+ ebuf->next = NULL;
+ ebuf_last->next = ebuf;
+ ebuf_last = ebuf;
+ ebuf_len += sublen;
+
+ ebuf = xmalloc (sizeof *ebuf);
+ ebuf->data = s;
+ ebuf->len = srch_len - (s - srch);
+ ebuf->free_data = 0;
+ ebuf->next = NULL;
+ ebuf_last->next = ebuf;
+ ebuf_last = ebuf;
+ ebuf_len += srch_len - (s - srch);
+ }
+
+ srch_len -= (s - srch);
+ srch = s;
+ }
+
+ if (locker != NULL)
+ free (locker);
+
+ if (ebufs == NULL)
+ {
+ *retbuf = buf;
+ *retlen = len;
+ }
+ else
+ {
+ char *ret;
+
+ ret = xmalloc (ebuf_len);
+ *retbuf = ret;
+ *retlen = ebuf_len;
+ while (ebufs != NULL)
+ {
+ struct expand_buffer *next;
+
+ memcpy (ret, ebufs->data, ebufs->len);
+ ret += ebufs->len;
+ if (ebufs->free_data)
+ free (ebufs->data);
+ next = ebufs->next;
+ free (ebufs);
+ ebufs = next;
+ }
+ }
+}
+
+
+
+/* Check out a revision from an RCS file.
+
+ If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
+ or more times with the contents of the file. CALLERDAT is passed,
+ uninterpreted, to PFN. (The current code will always call PFN
+ exactly once for a non empty file; however, the current code
+ assumes that it can hold the entire file contents in memory, which
+ is not a good assumption, and might change in the future).
+
+ Otherwise, if WORKFILE is not NULL, check out the revision to
+ WORKFILE. However, if WORKFILE is not NULL, and noexec is set,
+ then don't do anything.
+
+ Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If
+ SOUT is RUN_TTY, then write the contents of the revision to
+ standard output. When using SOUT, the output is generally a
+ temporary file; don't bother to get the file modes correct. When
+ NOEXEC is set, WORKFILEs are not written but SOUTs are.
+
+ REV is the numeric revision to check out. It may be NULL, which
+ means to check out the head of the default branch.
+
+ If NAMETAG is not NULL, and is not a numeric revision, then it is
+ the tag that should be used when expanding the RCS Name keyword.
+
+ OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
+ options. It may be NULL to use the default expansion mode of the
+ file, typically "-kkv".
+
+ On an error which prevented checking out the file, either print a
+ nonfatal error and return 1, or give a fatal error. On success,
+ return 0. */
+
+/* This function mimics the behavior of `rcs co' almost exactly. The
+ chief difference is in its support for preserving file ownership,
+ permissions, and special files across checkin and checkout -- see
+ comments in RCS_checkin for some issues about this. -twp */
+int
+RCS_checkout (RCSNode *rcs, const char *workfile, const char *rev,
+ const char *nametag, const char *options, const char *sout,
+ RCSCHECKOUTPROC pfn, void *callerdat)
+{
+ int free_rev = 0;
+ enum kflag expand;
+ FILE *fp,
+ *ofp = NULL; /* Initialize since -Wall doesn't understand that
+ * error (1, ...) does not return.
+ */
+ struct stat sb;
+ struct rcsbuffer rcsbuf;
+ char *key;
+ char *value;
+ size_t len;
+ int free_value = 0;
+ char *log = NULL;
+ size_t loglen = 0;
+ Node *vp = NULL;
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ uid_t rcs_owner = (uid_t) -1;
+ gid_t rcs_group = (gid_t) -1;
+ mode_t rcs_mode;
+ int change_rcs_owner_or_group = 0;
+ int change_rcs_mode = 0;
+ int special_file = 0;
+ unsigned long devnum_long;
+ dev_t devnum = 0;
+#endif
+
+ TRACE (TRACE_FUNCTION, "RCS_checkout (%s, %s, %s, %s, %s)",
+ rcs->path,
+ rev != NULL ? rev : "",
+ nametag != NULL ? nametag : "",
+ options != NULL ? options : "",
+ (pfn != NULL ? "(function)"
+ : (workfile != NULL ? workfile
+ : (sout != RUN_TTY ? sout
+ : "(stdout)"))));
+
+ assert (rev == NULL || isdigit ((unsigned char) *rev));
+
+ if (noexec && !server_active && workfile != NULL)
+ return 0;
+
+ assert (sout == RUN_TTY || workfile == NULL);
+ assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
+
+ /* Some callers, such as Checkin or remove_file, will pass us a
+ branch. */
+ if (rev != NULL && (numdots (rev) & 1) == 0)
+ {
+ rev = RCS_getbranch (rcs, rev, 1);
+ if (rev == NULL)
+ error (1, 0, "internal error: bad branch tag in checkout");
+ free_rev = 1;
+ }
+
+ if (rev == NULL || STREQ (rev, rcs->head))
+ {
+ int gothead;
+
+ /* We want the head revision. Try to read it directly. */
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, &fp, &rcsbuf);
+ else
+ rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
+
+ gothead = 0;
+ if (! rcsbuf_getrevnum (&rcsbuf, &key))
+ error (1, 0, "unexpected EOF reading %s", rcs->print_path);
+ while (rcsbuf_getkey (&rcsbuf, &key, &value))
+ {
+ if (STREQ (key, "log"))
+ {
+ if (log)
+ {
+ error (0, 0,
+"Duplicate log keyword found for head revision in RCS file.");
+ free (log);
+ }
+ log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
+ }
+ else if (STREQ (key, "text"))
+ {
+ gothead = 1;
+ break;
+ }
+ }
+
+ if (! gothead)
+ {
+ error (0, 0, "internal error: cannot find head text");
+ if (free_rev)
+ /* It's okay to discard the const when free_rev is set, because
+ * we know we allocated it in this function.
+ */
+ free ((char *)rev);
+ return 1;
+ }
+
+ rcsbuf_valpolish (&rcsbuf, value, 0, &len);
+
+ if (fstat (fileno (fp), &sb) < 0)
+ error (1, errno, "cannot fstat %s", rcs->path);
+
+ rcsbuf_cache (rcs, &rcsbuf);
+ }
+ else
+ {
+ struct rcsbuffer *rcsbufp;
+
+ /* It isn't the head revision of the trunk. We'll need to
+ walk through the deltas. */
+
+ fp = NULL;
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, &fp, &rcsbuf);
+
+ if (fp == NULL)
+ {
+ /* If RCS_deltas didn't close the file, we could use fstat
+ here too. Probably should change it thusly.... */
+ if (stat (rcs->path, &sb) < 0)
+ error (1, errno, "cannot stat %s", rcs->path);
+ rcsbufp = NULL;
+ }
+ else
+ {
+ if (fstat (fileno (fp), &sb) < 0)
+ error (1, errno, "cannot fstat %s", rcs->path);
+ rcsbufp = &rcsbuf;
+ }
+
+ RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
+ &log, &loglen);
+ free_value = 1;
+ }
+
+ /* If OPTIONS is NULL or the empty string, then the old code would
+ invoke the RCS co program with no -k option, which means that
+ co would use the string we have stored in rcs->expand. */
+ if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
+ expand = KFLAG_KV;
+ else
+ {
+ const char *ouroptions;
+ const char * const *cpp;
+
+ if (options != NULL && options[0] != '\0')
+ {
+ assert (options[0] == '-' && options[1] == 'k');
+ ouroptions = options + 2;
+ }
+ else
+ ouroptions = rcs->expand;
+
+ for (cpp = kflags; *cpp != NULL; cpp++)
+ if (STREQ (*cpp, ouroptions))
+ break;
+
+ if (*cpp != NULL)
+ expand = (enum kflag) (cpp - kflags);
+ else
+ {
+ error (0, 0,
+ "internal error: unsupported substitution string -k%s",
+ ouroptions);
+ expand = KFLAG_KV;
+ }
+ }
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Handle special files and permissions, if that is desired. */
+ if (preserve_perms)
+ {
+ RCSVers *vers;
+ Node *info;
+
+ vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
+ if (vp == NULL)
+ error (1, 0, "internal error: no revision information for %s",
+ rev == NULL ? rcs->head : rev);
+ vers = vp->data;
+
+ /* First we look for symlinks, which are simplest to handle. */
+ info = findnode (vers->other_delta, "symlink");
+ if (info != NULL)
+ {
+ char *dest;
+
+ if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
+ error (1, 0, "symbolic link %s:%s cannot be piped",
+ rcs->path, vers->version);
+ if (workfile == NULL)
+ dest = sout;
+ else
+ dest = workfile;
+
+ /* Remove `dest', just in case. It's okay to get ENOENT here,
+ since we just want the file not to be there. (TODO: decide
+ whether it should be considered an error for `dest' to exist
+ at this point. If so, the unlink call should be removed and
+ `symlink' should signal the error. -twp) */
+ if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
+ error (1, errno, "cannot remove %s", dest);
+ if (symlink (info->data, dest) < 0)
+ error (1, errno, "cannot create symbolic link from %s to %s",
+ dest, (char *)info->data);
+ if (free_value)
+ free (value);
+ if (free_rev)
+ /* It's okay to discard the const when free_rev is set, because
+ * we know we allocated it in this function.
+ */
+ free ((char *)rev);
+ return 0;
+ }
+
+ /* Next, we look at this file's hardlinks field, and see whether
+ it is linked to any other file that has been checked out.
+ If so, we don't do anything else -- just link it to that file.
+
+ If we are checking out a file to a pipe or temporary storage,
+ none of this should matter. Hence the `workfile != NULL'
+ wrapper around the whole thing. -twp */
+
+ if (workfile != NULL)
+ {
+ List *links = vers->hardlinks;
+ if (links != NULL)
+ {
+ Node *uptodate_link;
+
+ /* For each file in the hardlinks field, check to see
+ if it exists, and if so, if it has been checked out
+ this iteration. When walklist returns, uptodate_link
+ should point to a hardlist node representing a file
+ in `links' which has recently been checked out, or
+ NULL if no file in `links' has yet been checked out. */
+
+ uptodate_link = NULL;
+ (void) walklist (links, find_checkedout_proc, &uptodate_link);
+ dellist (&links);
+
+ /* If we've found a file that `workfile' is supposed to be
+ linked to, and it has been checked out since CVS was
+ invoked, then simply link workfile to that file and return.
+
+ If one of these conditions is not met, then
+ workfile is the first one in its hardlink group to
+ be checked out, and we must continue with a full
+ checkout. */
+
+ if (uptodate_link != NULL)
+ {
+ struct hardlink_info *hlinfo = uptodate_link->data;
+
+ if (link (uptodate_link->key, workfile) < 0)
+ error (1, errno, "cannot link %s to %s",
+ workfile, uptodate_link->key);
+ hlinfo->checked_out = 1; /* probably unnecessary */
+ if (free_value)
+ free (value);
+ if (free_rev)
+ /* It's okay to discard the const when free_rev is set,
+ * because we know we allocated it in this function.
+ */
+ free ((char *)rev);
+ return 0;
+ }
+ }
+ }
+
+ info = findnode (vers->other_delta, "owner");
+ if (info != NULL)
+ {
+ change_rcs_owner_or_group = 1;
+ rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
+ }
+ info = findnode (vers->other_delta, "group");
+ if (info != NULL)
+ {
+ change_rcs_owner_or_group = 1;
+ rcs_group = (gid_t) strtoul (info->data, NULL, 10);
+ }
+ info = findnode (vers->other_delta, "permissions");
+ if (info != NULL)
+ {
+ change_rcs_mode = 1;
+ rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
+ }
+ info = findnode (vers->other_delta, "special");
+ if (info != NULL)
+ {
+ /* If the size of `devtype' changes, fix the sscanf call also */
+ char devtype[16];
+
+ if (sscanf (info->data, "%15s %lu",
+ devtype, &devnum_long) < 2)
+ error (1, 0, "%s:%s has bad `special' newphrase %s",
+ workfile, vers->version, (char *)info->data);
+ devnum = devnum_long;
+ if (STREQ (devtype, "character"))
+ special_file = S_IFCHR;
+ else if (STREQ (devtype, "block"))
+ special_file = S_IFBLK;
+ else
+ error (0, 0, "%s is a special file of unsupported type `%s'",
+ workfile, (char *)info->data);
+ }
+ }
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+
+ if (expand != KFLAG_O && expand != KFLAG_B)
+ {
+ char *newvalue;
+
+ /* Don't fetch the delta node again if we already have it. */
+ if (vp == NULL)
+ {
+ vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
+ if (vp == NULL)
+ error (1, 0, "internal error: no revision information for %s",
+ rev == NULL ? rcs->head : rev);
+ }
+
+ expand_keywords (rcs, vp->data, nametag, log, loglen,
+ expand, value, len, &newvalue, &len);
+
+ if (newvalue != value)
+ {
+ if (free_value)
+ free (value);
+ value = newvalue;
+ free_value = 1;
+ }
+ }
+
+ if (free_rev)
+ /* It's okay to discard the const when free_rev is set, because
+ * we know we allocated it in this function.
+ */
+ free ((char *)rev);
+
+ if (log != NULL)
+ {
+ free (log);
+ log = NULL;
+ }
+
+ if (pfn != NULL)
+ {
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (special_file)
+ error (1, 0, "special file %s cannot be piped to anything",
+ rcs->path);
+#endif
+ /* The PFN interface is very simple to implement right now, as
+ we always have the entire file in memory. */
+ if (len != 0)
+ pfn (callerdat, value, len);
+ }
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ else if (special_file)
+ {
+# ifdef HAVE_MKNOD
+ char *dest;
+
+ /* Can send either to WORKFILE or to SOUT, as long as SOUT is
+ not RUN_TTY. */
+ dest = workfile;
+ if (dest == NULL)
+ {
+ if (sout == RUN_TTY)
+ error (1, 0, "special file %s cannot be written to stdout",
+ rcs->path);
+ dest = sout;
+ }
+
+ /* Unlink `dest', just in case. It's okay if this provokes a
+ ENOENT error. */
+ if (CVS_UNLINK (dest) < 0 && existence_error (errno))
+ error (1, errno, "cannot remove %s", dest);
+ if (mknod (dest, special_file, devnum) < 0)
+ error (1, errno, "could not create special file %s",
+ dest);
+# else
+ error (1, 0,
+"cannot create %s: unable to create special files on this system",
+workfile);
+# endif
+ }
+#endif
+ else
+ {
+ /* Not a special file: write to WORKFILE or SOUT. */
+ if (workfile == NULL)
+ {
+ if (sout == RUN_TTY)
+ ofp = stdout;
+ else
+ {
+ /* Symbolic links should be removed before replacement, so that
+ `fopen' doesn't follow the link and open the wrong file. */
+ if (islink (sout))
+ if (unlink_file (sout) < 0)
+ error (1, errno, "cannot remove %s", sout);
+ ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
+ if (ofp == NULL)
+ error (1, errno, "cannot open %s", sout);
+ }
+ }
+ else
+ {
+ /* Output is supposed to go to WORKFILE, so we should open that
+ file. Symbolic links should be removed first (see above). */
+ if (islink (workfile))
+ if (unlink_file (workfile) < 0)
+ error (1, errno, "cannot remove %s", workfile);
+
+ ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
+
+ /* If the open failed because the existing workfile was not
+ writable, try to chmod the file and retry the open. */
+ if (ofp == NULL && errno == EACCES
+ && isfile (workfile) && !iswritable (workfile))
+ {
+ xchmod (workfile, 1);
+ ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
+ }
+
+ if (ofp == NULL)
+ {
+ error (0, errno, "cannot open %s", workfile);
+ if (free_value)
+ free (value);
+ return 1;
+ }
+ }
+
+ if (workfile == NULL && sout == RUN_TTY)
+ {
+ if (expand == KFLAG_B)
+ cvs_output_binary (value, len);
+ else
+ {
+ /* cvs_output requires the caller to check for zero
+ length. */
+ if (len > 0)
+ cvs_output (value, len);
+ }
+ }
+ else
+ {
+ /* NT 4.0 is said to have trouble writing 2099999 bytes
+ (for example) in a single fwrite. So break it down
+ (there is no need to be writing that much at once
+ anyway; it is possible that LARGEST_FWRITE should be
+ somewhat larger for good performance, but for testing I
+ want to start with a small value until/unless a bigger
+ one proves useful). */
+#define LARGEST_FWRITE 8192
+ size_t nleft = len;
+ size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
+ char *p = value;
+
+ while (nleft > 0)
+ {
+ if (fwrite (p, 1, nstep, ofp) != nstep)
+ {
+ error (0, errno, "cannot write %s",
+ (workfile != NULL
+ ? workfile
+ : (sout != RUN_TTY ? sout : "stdout")));
+ if (free_value)
+ free (value);
+ return 1;
+ }
+ p += nstep;
+ nleft -= nstep;
+ if (nleft < nstep)
+ nstep = nleft;
+ }
+ }
+ }
+
+ if (free_value)
+ free (value);
+
+ if (workfile != NULL)
+ {
+ int ret;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (!special_file && fclose (ofp) < 0)
+ {
+ error (0, errno, "cannot close %s", workfile);
+ return 1;
+ }
+
+ if (change_rcs_owner_or_group)
+ {
+ if (chown (workfile, rcs_owner, rcs_group) < 0)
+ error (0, errno, "could not change owner or group of %s",
+ workfile);
+ }
+
+ ret = chmod (workfile,
+ change_rcs_mode
+ ? rcs_mode
+ : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
+#else
+ if (fclose (ofp) < 0)
+ {
+ error (0, errno, "cannot close %s", workfile);
+ return 1;
+ }
+
+ ret = chmod (workfile,
+ sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
+#endif
+ if (ret < 0)
+ {
+ error (0, errno, "cannot change mode of file %s",
+ workfile);
+ }
+ }
+ else if (sout != RUN_TTY)
+ {
+ if (
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ !special_file &&
+#endif
+ fclose (ofp) < 0)
+ {
+ error (0, errno, "cannot close %s", sout);
+ return 1;
+ }
+ }
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* If we are in the business of preserving hardlinks, then
+ mark this file as having been checked out. */
+ if (preserve_perms && workfile != NULL)
+ update_hardlink_info (workfile);
+#endif
+
+ return 0;
+}
+
+
+
+/* Find the delta currently locked by the user. From the `ci' man page:
+
+ "If rev is omitted, ci tries to derive the new revision
+ number from the caller's last lock. If the caller has
+ locked the tip revision of a branch, the new revision is
+ appended to that branch. The new revision number is
+ obtained by incrementing the tip revision number. If the
+ caller locked a non-tip revision, a new branch is started
+ at that revision by incrementing the highest branch number
+ at that revision. The default initial branch and level
+ numbers are 1.
+
+ If rev is omitted and the caller has no lock, but owns the
+ file and locking is not set to strict, then the revision
+ is appended to the default branch (normally the trunk; see
+ the -b option of rcs(1))."
+
+ RCS_findlock_or_tip finds the unique revision locked by the caller
+ and returns its delta node. If the caller has not locked any
+ revisions (and is permitted to commit to an unlocked delta, as
+ described above), return the tip of the default branch. */
+static RCSVers *
+RCS_findlock_or_tip (RCSNode *rcs)
+{
+ char *user = getcaller();
+ Node *lock, *p;
+ List *locklist;
+
+ /* Find unique delta locked by caller. This code is very similar
+ to the code in RCS_unlock -- perhaps it could be abstracted
+ into a RCS_findlock function. */
+ locklist = RCS_getlocks (rcs);
+ lock = NULL;
+ for (p = locklist->list->next; p != locklist->list; p = p->next)
+ {
+ if (STREQ (p->data, user))
+ {
+ if (lock != NULL)
+ {
+ error (0, 0, "\
+%s: multiple revisions locked by %s; please specify one", rcs->print_path, user);
+ return NULL;
+ }
+ lock = p;
+ }
+ }
+
+ if (lock != NULL)
+ {
+ /* Found an old lock, but check that the revision still exists. */
+ p = findnode (rcs->versions, lock->key);
+ if (p == NULL)
+ {
+ error (0, 0, "%s: can't unlock nonexistent revision %s",
+ rcs->print_path,
+ lock->key);
+ return NULL;
+ }
+ return p->data;
+ }
+
+ /* No existing lock. The RCS rule is that this is an error unless
+ locking is nonstrict AND the file is owned by the current
+ user. Trying to determine the latter is a portability nightmare
+ in the face of NT, VMS, AFS, and other systems with non-unix-like
+ ideas of users and owners. In the case of CVS, we should never get
+ here (as long as the traditional behavior of making sure to call
+ RCS_lock persists). Anyway, we skip the RCS error checks
+ and just return the default branch or head. The reasoning is that
+ those error checks are to make users lock before a checkin, and we do
+ that in other ways if at all anyway (e.g. rcslock.pl). */
+
+ p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
+ if (!p)
+ {
+ error (0, 0, "RCS file `%s' does not contain its default revision.",
+ rcs->path);
+ return NULL;
+ }
+
+ return p->data;
+}
+
+
+
+/* Revision number string, R, must contain a `.'.
+ Return a newly-malloc'd copy of the prefix of R up
+ to but not including the final `.'. */
+static char *
+truncate_revnum (const char *r)
+{
+ size_t len;
+ char *new_r;
+ char *dot = strrchr (r, '.');
+
+ assert (dot);
+ len = dot - r;
+ new_r = xmalloc (len + 1);
+ memcpy (new_r, r, len);
+ *(new_r + len) = '\0';
+ return new_r;
+}
+
+
+
+/* Revision number string, R, must contain a `.'.
+ R must be writable. Replace the rightmost `.' in R with
+ the NUL byte and return a pointer to that NUL byte. */
+static char *
+truncate_revnum_in_place (char *r)
+{
+ char *dot = strrchr (r, '.');
+ assert (dot);
+ *dot = '\0';
+ return dot;
+}
+
+
+
+/* Revision number strings, R and S, must each contain a `.'.
+ R and S must be writable and must have the same number of dots.
+ Truncate R and S for the comparison, then restored them to their
+ original state.
+ Return the result (see compare_revnums) of comparing R and S
+ ignoring differences in any component after the rightmost `.'. */
+static int
+compare_truncated_revnums (char *r, char *s)
+{
+ char *r_dot = truncate_revnum_in_place (r);
+ char *s_dot = truncate_revnum_in_place (s);
+ int cmp;
+
+ assert (numdots (r) == numdots (s));
+
+ cmp = compare_revnums (r, s);
+
+ *r_dot = '.';
+ *s_dot = '.';
+
+ return cmp;
+}
+
+
+
+/* Return a malloc'd copy of the string representing the highest branch
+ number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL.
+ FIXME: isn't the max rev always the last one?
+ If so, we don't even need a loop. */
+static char *
+max_rev (const RCSVers *branchnode)
+{
+ Node *head;
+ Node *bp;
+ char *max;
+
+ if (branchnode->branches == NULL)
+ {
+ return NULL;
+ }
+
+ max = NULL;
+ head = branchnode->branches->list;
+ for (bp = head->next; bp != head; bp = bp->next)
+ {
+ if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
+ {
+ max = bp->key;
+ }
+ }
+ assert (max);
+
+ return truncate_revnum (max);
+}
+
+
+
+/* Create BRANCH in RCS's delta tree. BRANCH may be either a branch
+ number or a revision number. In the former case, create the branch
+ with the specified number; in the latter case, create a new branch
+ rooted at node BRANCH with a higher branch number than any others.
+ Return the number of the tip node on the new branch. */
+static char *
+RCS_addbranch (RCSNode *rcs, const char *branch)
+{
+ char *branchpoint, *newrevnum;
+ Node *nodep, *bp;
+ Node *marker;
+ RCSVers *branchnode;
+
+ assert (branch);
+
+ /* Append to end by default. */
+ marker = NULL;
+
+ branchpoint = xstrdup (branch);
+ if ((numdots (branchpoint) & 1) == 0)
+ {
+ truncate_revnum_in_place (branchpoint);
+ }
+
+ /* Find the branch rooted at BRANCHPOINT. */
+ nodep = findnode (rcs->versions, branchpoint);
+ if (nodep == NULL)
+ {
+ error (0, 0, "%s: can't find branch point %s", rcs->print_path, branchpoint);
+ free (branchpoint);
+ return NULL;
+ }
+ free (branchpoint);
+ branchnode = nodep->data;
+
+ /* If BRANCH was a full branch number, make sure it is higher than MAX. */
+ if ((numdots (branch) & 1) == 1)
+ {
+ if (branchnode->branches == NULL)
+ {
+ /* We have to create the first branch on this node, which means
+ appending ".2" to the revision number. */
+ newrevnum = Xasprintf ("%s.2", branch);
+ }
+ else
+ {
+ char *max = max_rev (branchnode);
+ assert (max);
+ newrevnum = increment_revnum (max);
+ free (max);
+ }
+ }
+ else
+ {
+ newrevnum = xstrdup (branch);
+
+ if (branchnode->branches != NULL)
+ {
+ Node *head;
+ Node *bp;
+
+ /* Find the position of this new branch in the sorted list
+ of branches. */
+ head = branchnode->branches->list;
+ for (bp = head->next; bp != head; bp = bp->next)
+ {
+ char *dot;
+ int found_pos;
+
+ /* The existing list must be sorted on increasing revnum. */
+ assert (bp->next == head
+ || compare_truncated_revnums (bp->key,
+ bp->next->key) < 0);
+ dot = truncate_revnum_in_place (bp->key);
+ found_pos = (compare_revnums (branch, bp->key) < 0);
+ *dot = '.';
+
+ if (found_pos)
+ {
+ break;
+ }
+ }
+ marker = bp;
+ }
+ }
+
+ newrevnum = xrealloc (newrevnum, strlen (newrevnum) + 3);
+ strcat (newrevnum, ".1");
+
+ /* Add this new revision number to BRANCHPOINT's branches list. */
+ if (branchnode->branches == NULL)
+ branchnode->branches = getlist();
+ bp = getnode();
+ bp->key = xstrdup (newrevnum);
+
+ /* Append to the end of the list by default, that is, just before
+ the header node, `list'. */
+ if (marker == NULL)
+ marker = branchnode->branches->list;
+
+ {
+ int fail;
+ fail = insert_before (branchnode->branches, marker, bp);
+ assert (!fail);
+ }
+
+ return newrevnum;
+}
+
+
+
+/* Check in to RCSFILE with revision REV (which must be greater than
+ the largest revision) and message MESSAGE (which is checked for
+ validity). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
+ If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
+ RCS_FLAGS_MODTIME, use the working file's modification time for the
+ checkin time. WORKFILE is the working file to check in from, or
+ NULL to use the usual RCS rules for deriving it from the RCSFILE.
+ If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
+ unlinking the working file is standard RCS behavior, but is rarely
+ appropriate for CVS.
+
+ UPDATE_DIR is used to print the path for the file. This argument is
+ unnecessary when FLAGS & RCS_FLAGS_QUIET since the path won't be printed
+ anyhow.
+
+ This function should almost exactly mimic the behavior of `rcs ci'. The
+ principal point of difference is the support here for preserving file
+ ownership and permissions in the delta nodes. This is not a clean
+ solution -- precisely because it diverges from RCS's behavior -- but
+ it doesn't seem feasible to do this anywhere else in the code. [-twp]
+
+ Return value is -1 for error (and errno is set to indicate the
+ error), positive for error (and an error message has been printed),
+ or zero for success. */
+int
+RCS_checkin (RCSNode *rcs, const char *update_dir, const char *workfile_in,
+ const char *message, const char *rev, time_t citime, int flags)
+{
+ RCSVers *delta, *commitpt;
+ Deltatext *dtext;
+ Node *nodep;
+ char *tmpfile, *changefile;
+ int dargc = 0;
+ size_t darg_allocated = 0;
+ char **dargv = NULL;
+ size_t bufsize;
+ int status, checkin_quiet;
+ struct tm *ftm;
+ time_t modtime;
+ int adding_branch = 0;
+ char *workfile = xstrdup (workfile_in);
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ struct stat sb;
+#endif
+ Node *np;
+
+ commitpt = NULL;
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* Get basename of working file. Is there a library function to
+ do this? I couldn't find one. -twp */
+ if (workfile == NULL)
+ {
+ char *p;
+ int extlen = strlen (RCSEXT);
+ assert (rcs->path);
+ workfile = xstrdup (last_component (rcs->path));
+ p = workfile + (strlen (workfile) - extlen);
+ assert (strncmp (p, RCSEXT, extlen) == 0);
+ *p = '\0';
+ }
+
+ /* If the filename is a symbolic link, follow it and replace it
+ with the destination of the link. We need to do this before
+ calling rcs_internal_lockfile, or else we won't put the lock in
+ the right place. */
+ resolve_symlink (&(rcs->path));
+
+ checkin_quiet = flags & RCS_FLAGS_QUIET;
+ if (!(checkin_quiet || really_quiet))
+ {
+ cvs_output (rcs->path, 0);
+ cvs_output (" <-- ", 7);
+ if (update_dir && strlen (update_dir))
+ {
+ cvs_output (update_dir, 0);
+ cvs_output ("/", 1);
+ }
+ cvs_output (workfile, 0);
+ cvs_output ("\n", 1);
+ }
+
+ /* Create new delta node. */
+ delta = xmalloc (sizeof (RCSVers));
+ memset (delta, 0, sizeof (RCSVers));
+ delta->author = xstrdup (getcaller ());
+ if (flags & RCS_FLAGS_MODTIME)
+ {
+ struct stat ws;
+ if (stat (workfile, &ws) < 0)
+ {
+ error (1, errno, "cannot stat %s", workfile);
+ }
+ modtime = ws.st_mtime;
+ }
+ else if (flags & RCS_FLAGS_USETIME)
+ modtime = citime;
+ else
+ (void) time (&modtime);
+ ftm = gmtime (&modtime);
+ delta->date = Xasprintf (DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+ if (flags & RCS_FLAGS_DEAD)
+ {
+ delta->state = xstrdup (RCSDEAD);
+ delta->dead = 1;
+ }
+ else
+ delta->state = xstrdup ("Exp");
+
+ delta->other_delta = getlist();
+
+ /* save the commit ID */
+ np = getnode();
+ np->type = RCSFIELD;
+ np->key = xstrdup ("commitid");
+ np->data = xstrdup(global_session_id);
+ addnode (delta->other_delta, np);
+
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* If permissions should be preserved on this project, then
+ save the permission info. */
+ if (preserve_perms)
+ {
+ Node *np;
+ char buf[64]; /* static buffer should be safe: see usage. -twp */
+
+ delta->other_delta = getlist();
+
+ if (lstat (workfile, &sb) < 0)
+ error (1, errno, "cannot lstat %s", workfile);
+
+ if (S_ISLNK (sb.st_mode))
+ {
+ np = getnode();
+ np->type = RCSFIELD;
+ np->key = xstrdup ("symlink");
+ np->data = Xreadlink (workfile, sb.st_size);
+ addnode (delta->other_delta, np);
+ }
+ else
+ {
+ (void) sprintf (buf, "%u", sb.st_uid);
+ np = getnode();
+ np->type = RCSFIELD;
+ np->key = xstrdup ("owner");
+ np->data = xstrdup (buf);
+ addnode (delta->other_delta, np);
+
+ (void) sprintf (buf, "%u", sb.st_gid);
+ np = getnode();
+ np->type = RCSFIELD;
+ np->key = xstrdup ("group");
+ np->data = xstrdup (buf);
+ addnode (delta->other_delta, np);
+
+ (void) sprintf (buf, "%o", sb.st_mode & 07777);
+ np = getnode();
+ np->type = RCSFIELD;
+ np->key = xstrdup ("permissions");
+ np->data = xstrdup (buf);
+ addnode (delta->other_delta, np);
+
+ /* Save device number. */
+ switch (sb.st_mode & S_IFMT)
+ {
+ case S_IFREG: break;
+ case S_IFCHR:
+ case S_IFBLK:
+# ifdef HAVE_STRUCT_STAT_ST_RDEV
+ np = getnode();
+ np->type = RCSFIELD;
+ np->key = xstrdup ("special");
+ sprintf (buf, "%s %lu",
+ ((sb.st_mode & S_IFMT) == S_IFCHR
+ ? "character" : "block"),
+ (unsigned long) sb.st_rdev);
+ np->data = xstrdup (buf);
+ addnode (delta->other_delta, np);
+# else
+ error (0, 0,
+"can't preserve %s: unable to save device files on this system",
+workfile);
+# endif
+ break;
+
+ default:
+ error (0, 0, "special file %s has unknown type", workfile);
+ }
+
+ /* Save hardlinks. */
+ delta->hardlinks = list_linked_files_on_disk (workfile);
+ }
+ }
+#endif
+
+ /* Create a new deltatext node. */
+ dtext = xmalloc (sizeof (Deltatext));
+ memset (dtext, 0, sizeof (Deltatext));
+
+ dtext->log = make_message_rcsvalid (message);
+
+ /* If the delta tree is empty, then there's nothing to link the
+ new delta into. So make a new delta tree, snarf the working
+ file contents, and just write the new RCS file. */
+ if (rcs->head == NULL)
+ {
+ char *newrev;
+ FILE *fout;
+
+ /* Figure out what the first revision number should be. */
+ if (rev == NULL || *rev == '\0')
+ newrev = xstrdup ("1.1");
+ else if (numdots (rev) == 0)
+ {
+ newrev = Xasprintf ("%s.1", rev);
+ }
+ else
+ newrev = xstrdup (rev);
+
+ /* Don't need to xstrdup NEWREV because it's already dynamic, and
+ not used for anything else. (Don't need to free it, either.) */
+ rcs->head = newrev;
+ delta->version = xstrdup (newrev);
+ nodep = getnode();
+ nodep->type = RCSVERS;
+ nodep->delproc = rcsvers_delproc;
+ nodep->data = delta;
+ nodep->key = delta->version;
+ (void) addnode (rcs->versions, nodep);
+
+ dtext->version = xstrdup (newrev);
+ bufsize = 0;
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms && !S_ISREG (sb.st_mode))
+ /* Pretend file is empty. */
+ bufsize = 0;
+ else
+#endif
+ get_file (workfile, workfile,
+ rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
+ &dtext->text, &bufsize, &dtext->len);
+
+ if (!(checkin_quiet || really_quiet))
+ {
+ cvs_output ("initial revision: ", 0);
+ cvs_output (rcs->head, 0);
+ cvs_output ("\n", 1);
+ }
+
+ /* We are probably about to invalidate any cached file. */
+ rcsbuf_cache_close ();
+
+ fout = rcs_internal_lockfile (rcs->path);
+ RCS_putadmin (rcs, fout);
+ RCS_putdtree (rcs, rcs->head, fout);
+ RCS_putdesc (rcs, fout);
+ rcs->delta_pos = ftello (fout);
+ if (rcs->delta_pos == -1)
+ error (1, errno, "cannot ftello for %s", rcs->path);
+ putdeltatext (fout, dtext);
+ rcs_internal_unlockfile (fout, rcs->path);
+
+ if ((flags & RCS_FLAGS_KEEPFILE) == 0)
+ {
+ if (unlink_file (workfile) < 0)
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (0, errno, "cannot remove %s", workfile);
+ }
+
+ status = 0;
+ goto checkin_done;
+ }
+
+ /* Derive a new revision number. From the `ci' man page:
+
+ "If rev is a revision number, it must be higher than the
+ latest one on the branch to which rev belongs, or must
+ start a new branch.
+
+ If rev is a branch rather than a revision number, the new
+ revision is appended to that branch. The level number is
+ obtained by incrementing the tip revision number of that
+ branch. If rev indicates a non-existing branch, that
+ branch is created with the initial revision numbered
+ rev.1."
+
+ RCS_findlock_or_tip handles the case where REV is omitted.
+ RCS 5.7 also permits REV to be "$" or to begin with a dot, but
+ we do not address those cases -- every routine that calls
+ RCS_checkin passes it a numeric revision. */
+
+ if (rev == NULL || *rev == '\0')
+ {
+ /* Figure out where the commit point is by looking for locks.
+ If the commit point is at the tip of a branch (or is the
+ head of the delta tree), then increment its revision number
+ to obtain the new revnum. Otherwise, start a new
+ branch. */
+ commitpt = RCS_findlock_or_tip (rcs);
+ if (commitpt == NULL)
+ {
+ status = 1;
+ goto checkin_done;
+ }
+ else if (commitpt->next == NULL
+ || STREQ (commitpt->version, rcs->head))
+ delta->version = increment_revnum (commitpt->version);
+ else
+ delta->version = RCS_addbranch (rcs, commitpt->version);
+ }
+ else
+ {
+ /* REV is either a revision number or a branch number. Find the
+ tip of the target branch. */
+ char *branch, *tip, *newrev, *p;
+ int dots, isrevnum;
+
+ assert (isdigit ((unsigned char) *rev));
+
+ newrev = xstrdup (rev);
+ dots = numdots (newrev);
+ isrevnum = dots & 1;
+
+ branch = xstrdup (rev);
+ if (isrevnum)
+ {
+ p = strrchr (branch, '.');
+ *p = '\0';
+ }
+
+ /* Find the tip of the target branch. If we got a one- or two-digit
+ revision number, this will be the head of the tree. Exception:
+ if rev is a single-field revision equal to the branch number of
+ the trunk (usually "1") then we want to treat it like an ordinary
+ branch revision. */
+ if (dots == 0)
+ {
+ tip = xstrdup (rcs->head);
+ if (atoi (tip) != atoi (branch))
+ {
+ newrev = xrealloc (newrev, strlen (newrev) + 3);
+ strcat (newrev, ".1");
+ dots = isrevnum = 1;
+ }
+ }
+ else if (dots == 1)
+ tip = xstrdup (rcs->head);
+ else
+ tip = RCS_getbranch (rcs, branch, 1);
+
+ /* If the branch does not exist, and we were supplied an exact
+ revision number, signal an error. Otherwise, if we were
+ given only a branch number, create it and set COMMITPT to
+ the branch point. */
+ if (tip == NULL)
+ {
+ if (isrevnum)
+ {
+ error (0, 0, "%s: can't find branch point %s",
+ rcs->print_path, branch);
+ free (branch);
+ free (newrev);
+ status = 1;
+ goto checkin_done;
+ }
+ delta->version = RCS_addbranch (rcs, branch);
+ if (!delta->version)
+ {
+ free (branch);
+ free (newrev);
+ status = 1;
+ goto checkin_done;
+ }
+ adding_branch = 1;
+ p = strrchr (branch, '.');
+ *p = '\0';
+ tip = xstrdup (branch);
+ }
+ else
+ {
+ if (isrevnum)
+ {
+ /* NEWREV must be higher than TIP. */
+ if (compare_revnums (tip, newrev) >= 0)
+ {
+ error (0, 0,
+ "%s: revision %s too low; must be higher than %s",
+ rcs->print_path,
+ newrev, tip);
+ free (branch);
+ free (newrev);
+ free (tip);
+ status = 1;
+ goto checkin_done;
+ }
+ delta->version = xstrdup (newrev);
+ }
+ else
+ /* Just increment the tip number to get the new revision. */
+ delta->version = increment_revnum (tip);
+ }
+
+ nodep = findnode (rcs->versions, tip);
+ commitpt = nodep->data;
+
+ free (branch);
+ free (newrev);
+ free (tip);
+ }
+
+ assert (delta->version != NULL);
+
+ /* If COMMITPT is locked by us, break the lock. If it's locked
+ by someone else, signal an error. */
+ nodep = findnode (RCS_getlocks (rcs), commitpt->version);
+ if (nodep != NULL)
+ {
+ if (! STREQ (nodep->data, delta->author))
+ {
+ /* If we are adding a branch, then leave the old lock around.
+ That is sensible in the sense that when adding a branch,
+ we don't need to use the lock to tell us where to check
+ in. It is fishy in the sense that if it is our own lock,
+ we break it. However, this is the RCS 5.7 behavior (at
+ the end of addbranch in ci.c in RCS 5.7, it calls
+ removelock only if it is our own lock, not someone
+ else's). */
+
+ if (!adding_branch)
+ {
+ error (0, 0, "%s: revision %s locked by %s",
+ rcs->print_path,
+ nodep->key, (char *)nodep->data);
+ status = 1;
+ goto checkin_done;
+ }
+ }
+ else
+ delnode (nodep);
+ }
+
+ dtext->version = xstrdup (delta->version);
+
+ /* Obtain the change text for the new delta. If DELTA is to be the
+ new head of the tree, then its change text should be the contents
+ of the working file, and LEAFNODE's change text should be a diff.
+ Else, DELTA's change text should be a diff between LEAFNODE and
+ the working file. */
+
+ tmpfile = cvs_temp_name();
+ status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
+ ((rcs->expand != NULL
+ && STREQ (rcs->expand, "b"))
+ ? "-kb"
+ : "-ko"),
+ tmpfile,
+ NULL, NULL);
+ if (status != 0)
+ error (1, 0,
+ "could not check out revision %s of `%s'",
+ commitpt->version, rcs->print_path);
+
+ bufsize = 0;
+ changefile = cvs_temp_name();
+
+ /* Diff options should include --binary if the RCS file has -kb set
+ in its `expand' field. */
+ run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
+ run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
+ if (rcs->expand != NULL && STREQ (rcs->expand, "b"))
+ run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary");
+
+ if (STREQ (commitpt->version, rcs->head) &&
+ numdots (delta->version) == 1)
+ {
+ /* If this revision is being inserted on the trunk, the change text
+ for the new delta should be the contents of the working file ... */
+ bufsize = 0;
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms && !S_ISREG (sb.st_mode))
+ /* Pretend file is empty. */
+ ;
+ else
+#endif
+ get_file (workfile, workfile,
+ rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
+ &dtext->text, &bufsize, &dtext->len);
+
+ /* ... and the change text for the old delta should be a diff. */
+ commitpt->text = xmalloc (sizeof (Deltatext));
+ memset (commitpt->text, 0, sizeof (Deltatext));
+
+ bufsize = 0;
+ switch (diff_exec (workfile, tmpfile, NULL, NULL,
+ dargc, dargv, changefile))
+ {
+ case 0:
+ case 1:
+ break;
+ case -1:
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (1, errno, "error diffing %s", workfile);
+ break;
+ default:
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (1, 0, "error diffing %s", workfile);
+ break;
+ }
+
+ /* OK, the text file case here is really dumb. Logically
+ speaking we want diff to read the files in text mode,
+ convert them to the canonical form found in RCS files
+ (which, we hope at least, is independent of OS--always
+ bare linefeeds), and then work with change texts in that
+ format. However, diff_exec both generates change
+ texts and produces output for user purposes (e.g. patch.c),
+ and there is no way to distinguish between the two cases.
+ So we actually implement the text file case by writing the
+ change text as a text file, then reading it as a text file.
+ This should cause no harm, but doesn't strike me as
+ immensely clean. */
+ get_file (changefile, changefile,
+ rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
+ &commitpt->text->text, &bufsize, &commitpt->text->len);
+
+ /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
+ was empty and that there are no differences between revisions.
+ In that event, we want to force RCS_rewrite to write an empty
+ string for COMMITPT's change text. Leaving the change text
+ field set NULL won't work, since that means "preserve the original
+ change text for this delta." */
+ if (commitpt->text->text == NULL)
+ {
+ commitpt->text->text = xstrdup ("");
+ commitpt->text->len = 0;
+ }
+ }
+ else
+ {
+ /* This file is not being inserted at the head, but on a side
+ branch somewhere. Make a diff from the previous revision
+ to the working file. */
+ switch (diff_exec (tmpfile, workfile, NULL, NULL,
+ dargc, dargv, changefile))
+ {
+ case 0:
+ case 1:
+ break;
+ case -1:
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (1, errno, "error diffing %s", workfile);
+ break;
+ default:
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (1, 0, "error diffing %s", workfile);
+ break;
+ }
+ /* See the comment above, at the other get_file invocation,
+ regarding binary vs. text. */
+ get_file (changefile, changefile,
+ rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
+ &dtext->text, &bufsize,
+ &dtext->len);
+ if (dtext->text == NULL)
+ {
+ dtext->text = xstrdup ("");
+ dtext->len = 0;
+ }
+ }
+
+ run_arg_free_p (dargc, dargv);
+ free (dargv);
+
+ /* Update DELTA linkage. It is important not to do this before
+ the very end of RCS_checkin; if an error arises that forces
+ us to abort checking in, we must not have malformed deltas
+ partially linked into the tree.
+
+ If DELTA and COMMITPT are on different branches, do nothing --
+ DELTA is linked to the tree through COMMITPT->BRANCHES, and we
+ don't want to change `next' pointers.
+
+ Otherwise, if the nodes are both on the trunk, link DELTA to
+ COMMITPT; otherwise, link COMMITPT to DELTA. */
+
+ if (numdots (commitpt->version) == numdots (delta->version))
+ {
+ if (STREQ (commitpt->version, rcs->head))
+ {
+ delta->next = rcs->head;
+ rcs->head = xstrdup (delta->version);
+ }
+ else
+ commitpt->next = xstrdup (delta->version);
+ }
+
+ /* Add DELTA to RCS->VERSIONS. */
+ if (rcs->versions == NULL)
+ rcs->versions = getlist();
+ nodep = getnode();
+ nodep->type = RCSVERS;
+ nodep->delproc = rcsvers_delproc;
+ nodep->data = delta;
+ nodep->key = delta->version;
+ (void) addnode (rcs->versions, nodep);
+
+ /* Write the new RCS file, inserting the new delta at COMMITPT. */
+ if (!(checkin_quiet || really_quiet))
+ {
+ cvs_output ("new revision: ", 14);
+ cvs_output (delta->version, 0);
+ cvs_output ("; previous revision: ", 21);
+ cvs_output (commitpt->version, 0);
+ cvs_output ("\n", 1);
+ }
+
+ RCS_rewrite (rcs, dtext, commitpt->version);
+
+ if ((flags & RCS_FLAGS_KEEPFILE) == 0)
+ {
+ if (unlink_file (workfile) < 0)
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (1, errno, "cannot remove %s", workfile);
+ }
+ if (unlink_file (tmpfile) < 0)
+ error (0, errno, "cannot remove %s", tmpfile);
+ free (tmpfile);
+ if (unlink_file (changefile) < 0)
+ error (0, errno, "cannot remove %s", changefile);
+ free (changefile);
+
+ checkin_done:
+ free (workfile);
+
+ if (commitpt != NULL && commitpt->text != NULL)
+ {
+ freedeltatext (commitpt->text);
+ commitpt->text = NULL;
+ }
+
+ freedeltatext (dtext);
+ if (status != 0)
+ {
+ /* If delta has not been added to a List, then freeing the Node key
+ * won't free delta->version.
+ */
+ if (delta->version) free (delta->version);
+ free_rcsvers_contents (delta);
+ }
+
+ return status;
+}
+
+
+
+/* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
+struct cmp_file_data
+{
+ const char *filename;
+ FILE *fp;
+ int different;
+};
+
+/* Compare the contents of revision REV1 of RCS file RCS with the
+ contents of REV2 if given, otherwise, compare with the contents of
+ the file FILENAME. OPTIONS is a string for the keyword
+ expansion options. Return 0 if the contents of the revision are
+ the same as the contents of the file, 1 if they are different. */
+int
+RCS_cmp_file (RCSNode *rcs, const char *rev1, char **rev1_cache,
+ const char *rev2, const char *options, const char *filename)
+{
+ int binary;
+
+ TRACE (TRACE_FUNCTION, "RCS_cmp_file( %s, %s, %s, %s, %s )",
+ rcs->path ? rcs->path : "(null)",
+ rev1 ? rev1 : "(null)", rev2 ? rev2 : "(null)",
+ options ? options : "(null)", filename ? filename : "(null)");
+
+ if (options != NULL && options[0] != '\0')
+ binary = STREQ (options, "-kb");
+ else
+ {
+ char *expand;
+
+ expand = RCS_getexpand (rcs);
+ if (expand != NULL && STREQ (expand, "b"))
+ binary = 1;
+ else
+ binary = 0;
+ }
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* If CVS is to deal properly with special files (when
+ PreservePermissions is on), the best way is to check out the
+ revision to a temporary file and call `xcmp' on the two disk
+ files. xcmp needs to handle non-regular files properly anyway,
+ so calling it simplifies RCS_cmp_file. We *could* just yank
+ the delta node out of the version tree and look for device
+ numbers, but writing to disk and calling xcmp is a better
+ abstraction (therefore probably more robust). -twp */
+
+ if (preserve_perms)
+ {
+ char *tmp;
+ int retcode;
+
+ tmp = cvs_temp_name();
+ retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
+ if (retcode != 0)
+ return 1;
+
+ retcode = xcmp (tmp, filename);
+ if (CVS_UNLINK (tmp) < 0)
+ error (0, errno, "cannot remove %s", tmp);
+ free (tmp);
+ return retcode;
+ }
+ else
+#endif
+ {
+ FILE *fp;
+ struct cmp_file_data data;
+ const char *use_file1;
+ char *tmpfile = NULL;
+
+ if (rev2 != NULL)
+ {
+ /* Open & cache rev1 */
+ tmpfile = cvs_temp_name();
+ if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
+ NULL, NULL))
+ error (1, errno,
+ "cannot check out revision %s of %s",
+ rev1, rcs->print_path);
+ use_file1 = tmpfile;
+ if (rev1_cache != NULL)
+ *rev1_cache = tmpfile;
+ }
+ else
+ use_file1 = filename;
+
+ fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r");
+ if (fp == NULL)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (1, errno, "cannot open file %s for comparing", use_file1);
+
+ data.filename = use_file1;
+ data.fp = fp;
+ data.different = 0;
+
+ if (RCS_checkout (rcs, NULL, rev2 ? rev2 : rev1, NULL, options,
+ RUN_TTY, cmp_file_buffer, &data ))
+ error (1, errno,
+ "cannot check out revision %s of %s",
+ rev2 ? rev2 : rev1, rcs->print_path);
+
+ /* If we have not yet found a difference, make sure that we are at
+ the end of the file. */
+ if (!data.different)
+ {
+ if (getc (fp) != EOF)
+ data.different = 1;
+ }
+
+ fclose (fp);
+ if (rev1_cache == NULL && tmpfile)
+ {
+ if (CVS_UNLINK (tmpfile ) < 0)
+ error (0, errno, "cannot remove %s", tmpfile);
+ free (tmpfile);
+ }
+
+ return data.different;
+ }
+}
+
+
+
+/* This is a subroutine of RCS_cmp_file. It is passed to
+ RCS_checkout. */
+#define CMP_BUF_SIZE (8 * 1024)
+
+static void
+cmp_file_buffer (void *callerdat, const char *buffer, size_t len)
+{
+ struct cmp_file_data *data = callerdat;
+ char *filebuf;
+
+ /* If we've already found a difference, we don't need to check
+ further. */
+ if (data->different)
+ return;
+
+ filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
+
+ while (len > 0)
+ {
+ size_t checklen;
+
+ checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
+ if (fread (filebuf, 1, checklen, data->fp) != checklen)
+ {
+ if (ferror (data->fp))
+ error (1, errno, "cannot read file %s for comparing",
+ data->filename);
+ data->different = 1;
+ free (filebuf);
+ return;
+ }
+
+ if (memcmp (filebuf, buffer, checklen) != 0)
+ {
+ data->different = 1;
+ free (filebuf);
+ return;
+ }
+
+ buffer += checklen;
+ len -= checklen;
+ }
+
+ free (filebuf);
+}
+
+
+
+/* For RCS file RCS, make symbolic tag TAG point to revision REV.
+ This validates that TAG is OK for a user to use. Return value is
+ -1 for error (and errno is set to indicate the error), positive for
+ error (and an error message has been printed), or zero for success. */
+int
+RCS_settag (RCSNode *rcs, const char *tag, const char *rev)
+{
+ List *symbols;
+ Node *node;
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* FIXME: This check should be moved to RCS_check_tag. There is no
+ reason for it to be here. */
+ if (STREQ (tag, TAG_BASE)
+ || STREQ (tag, TAG_HEAD))
+ {
+ /* Print the name of the tag might be considered redundant
+ with the caller, which also prints it. Perhaps this helps
+ clarify why the tag name is considered reserved, I don't
+ know. */
+ error (0, 0, "Attempt to add reserved tag name %s", tag);
+ return 1;
+ }
+
+ /* A revision number of NULL means use the head or default branch.
+ If rev is not NULL, it may be a symbolic tag or branch number;
+ expand it to the correct numeric revision or branch head. */
+ if (rev == NULL)
+ rev = rcs->branch ? rcs->branch : rcs->head;
+
+ /* At this point rcs->symbol_data may not have been parsed.
+ Calling RCS_symbols will force it to be parsed into a list
+ which we can easily manipulate. */
+ symbols = RCS_symbols (rcs);
+ if (symbols == NULL)
+ {
+ symbols = getlist ();
+ rcs->symbols = symbols;
+ }
+ node = findnode (symbols, tag);
+ if (node != NULL)
+ {
+ free (node->data);
+ node->data = xstrdup (rev);
+ }
+ else
+ {
+ node = getnode ();
+ node->key = xstrdup (tag);
+ node->data = xstrdup (rev);
+ (void)addnode_at_front (symbols, node);
+ }
+
+ return 0;
+}
+
+
+
+/* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if
+ the tag was found (and removed), or 1 if it was not present. (In
+ either case, the tag will no longer be in RCS->SYMBOLS.) */
+int
+RCS_deltag (RCSNode *rcs, const char *tag)
+{
+ List *symbols;
+ Node *node;
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ symbols = RCS_symbols (rcs);
+ if (symbols == NULL)
+ return 1;
+
+ node = findnode (symbols, tag);
+ if (node == NULL)
+ return 1;
+
+ delnode (node);
+
+ return 0;
+}
+
+
+
+/* Set the default branch of RCS to REV. */
+int
+RCS_setbranch (RCSNode *rcs, const char *rev)
+{
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (rev && ! *rev)
+ rev = NULL;
+
+ if (rev == NULL && rcs->branch == NULL)
+ return 0;
+ if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
+ return 0;
+
+ if (rcs->branch != NULL)
+ free (rcs->branch);
+ rcs->branch = xstrdup (rev);
+
+ return 0;
+}
+
+
+
+/* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
+ Most of the callers only call us because RCS_checkin still tends to
+ like a lock (a relic of old behavior inherited from the RCS ci
+ program). If we clean this up, only "cvs admin -l" will still need
+ to call RCS_lock. */
+
+/* FIXME-twp: if a lock owned by someone else is broken, should this
+ send mail to the lock owner? Prompt user? It seems like such an
+ obscure situation for CVS as almost not worth worrying much
+ about. */
+int
+RCS_lock (RCSNode *rcs, const char *rev, int lock_quiet)
+{
+ List *locks;
+ Node *p;
+ char *user;
+ char *xrev = NULL;
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ locks = RCS_getlocks (rcs);
+ if (locks == NULL)
+ locks = rcs->locks = getlist();
+ user = getcaller();
+
+ /* A revision number of NULL means lock the head or default branch. */
+ if (rev == NULL)
+ xrev = RCS_head (rcs);
+ else
+ xrev = RCS_gettag (rcs, rev, 1, NULL);
+
+ /* Make sure that the desired revision exists. Technically,
+ we can update the locks list without even checking this,
+ but RCS 5.7 did this. And it can't hurt. */
+ if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
+ {
+ if (!lock_quiet)
+ error (0, 0, "%s: revision %s absent", rcs->print_path, rev);
+ free (xrev);
+ return 1;
+ }
+
+ /* Is this rev already locked? */
+ p = findnode (locks, xrev);
+ if (p != NULL)
+ {
+ if (STREQ (p->data, user))
+ {
+ /* We already own the lock on this revision, so do nothing. */
+ free (xrev);
+ return 0;
+ }
+
+#if 0
+ /* Well, first of all, "rev" below should be "xrev" to avoid
+ core dumps. But more importantly, should we really be
+ breaking the lock unconditionally? What CVS 1.9 does (via
+ RCS) is to prompt "Revision 1.1 is already locked by fred.
+ Do you want to break the lock? [ny](n): ". Well, we don't
+ want to interact with the user (certainly not at the
+ server/protocol level, and probably not in the command-line
+ client), but isn't it more sensible to give an error and
+ let the user run "cvs admin -u" if they want to break the
+ lock? */
+
+ /* Break the lock. */
+ if (!lock_quiet)
+ {
+ cvs_output (rev, 0);
+ cvs_output (" unlocked\n", 0);
+ }
+ delnode (p);
+#else
+ error (1, 0, "Revision %s is already locked by %s",
+ xrev, (char *)p->data);
+#endif
+ }
+
+ /* Create a new lock. */
+ p = getnode();
+ p->key = xrev; /* already xstrdupped */
+ p->data = xstrdup (getcaller());
+ (void)addnode_at_front (locks, p);
+
+ if (!lock_quiet)
+ {
+ cvs_output (xrev, 0);
+ cvs_output (" locked\n", 0);
+ }
+
+ return 0;
+}
+
+
+
+/* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME:
+ Like RCS_lock, this can become a no-op if we do the checkin
+ ourselves.
+
+ If REV is not null and is locked by someone else, break their
+ lock and notify them. It is an open issue whether RCS_unlock
+ queries the user about whether or not to break the lock. */
+int
+RCS_unlock (RCSNode *rcs, char *rev, int unlock_quiet)
+{
+ Node *lock;
+ List *locks;
+ char *user;
+ char *xrev = NULL;
+
+ user = getcaller();
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ /* If rev is NULL, unlock the revision held by the caller; if more
+ than one, make the user specify the revision explicitly. This
+ differs from RCS which unlocks the latest revision (first in
+ rcs->locks) held by the caller. */
+ if (rev == NULL)
+ {
+ Node *p;
+
+ /* No-ops: attempts to unlock an empty tree or an unlocked file. */
+ if (rcs->head == NULL)
+ {
+ if (!unlock_quiet)
+ cvs_outerr ("can't unlock an empty tree\n", 0);
+ return 0;
+ }
+
+ locks = RCS_getlocks (rcs);
+ if (locks == NULL)
+ {
+ if (!unlock_quiet)
+ cvs_outerr ("No locks are set.\n", 0);
+ return 0;
+ }
+
+ lock = NULL;
+ for (p = locks->list->next; p != locks->list; p = p->next)
+ {
+ if (STREQ (p->data, user))
+ {
+ if (lock != NULL)
+ {
+ if (!unlock_quiet)
+ error (0, 0, "\
+%s: multiple revisions locked by %s; please specify one", rcs->print_path, user);
+ return 1;
+ }
+ lock = p;
+ }
+ }
+ if (lock == NULL)
+ {
+ if (!unlock_quiet)
+ error (0, 0, "No locks are set for %s.\n", user);
+ return 0; /* no lock found, ergo nothing to do */
+ }
+ xrev = xstrdup (lock->key);
+ }
+ else
+ {
+ xrev = RCS_gettag (rcs, rev, 1, NULL);
+ if (xrev == NULL)
+ {
+ error (0, 0, "%s: revision %s absent", rcs->print_path, rev);
+ return 1;
+ }
+ }
+
+ lock = findnode (RCS_getlocks (rcs), xrev);
+ if (lock == NULL)
+ {
+ /* This revision isn't locked. */
+ free (xrev);
+ return 0;
+ }
+
+ if (! STREQ (lock->data, user))
+ {
+ /* If the revision is locked by someone else, notify
+ them. Note that this shouldn't ever happen if RCS_unlock
+ is called with a NULL revision, since that means "whatever
+ revision is currently locked by the caller." */
+ char *repos, *workfile;
+ if (!unlock_quiet)
+ error (0, 0, "\
+%s: revision %s locked by %s; breaking lock", rcs->print_path, xrev,
+ (char *)lock->data);
+ repos = xstrdup (rcs->path);
+ workfile = strrchr (repos, '/');
+ *workfile++ = '\0';
+ notify_do ('C', workfile, NULL, user, NULL, NULL, repos);
+ free (repos);
+ }
+
+ delnode (lock);
+ if (!unlock_quiet)
+ {
+ cvs_output (xrev, 0);
+ cvs_output (" unlocked\n", 0);
+ }
+
+ free (xrev);
+ return 0;
+}
+
+
+
+/* Add USER to the access list of RCS. Do nothing if already present.
+ FIXME-twp: check syntax of USER to make sure it's a valid id. */
+
+void
+RCS_addaccess (RCSNode *rcs, char *user)
+{
+ char *access, *a;
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (rcs->access == NULL)
+ rcs->access = xstrdup (user);
+ else
+ {
+ access = xstrdup (rcs->access);
+ for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
+ {
+ if (STREQ (a, user))
+ {
+ free (access);
+ return;
+ }
+ }
+ free (access);
+ rcs->access = xrealloc (rcs->access,
+ strlen (rcs->access) + strlen (user) + 2);
+ strcat (rcs->access, " ");
+ strcat (rcs->access, user);
+ }
+}
+
+
+
+/* Remove USER from the access list of RCS. */
+void
+RCS_delaccess (RCSNode *rcs, char *user)
+{
+ char *p, *s;
+ int ulen;
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (rcs->access == NULL)
+ return;
+
+ if (user == NULL)
+ {
+ free (rcs->access);
+ rcs->access = NULL;
+ return;
+ }
+
+ p = rcs->access;
+ ulen = strlen (user);
+ while (p != NULL)
+ {
+ if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
+ break;
+ p = strchr (p, ' ');
+ if (p != NULL)
+ ++p;
+ }
+
+ if (p == NULL)
+ return;
+
+ s = p + ulen;
+ while (*s != '\0')
+ *p++ = *s++;
+ *p = '\0';
+}
+
+
+
+char *
+RCS_getaccess (RCSNode *rcs)
+{
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ return rcs->access;
+}
+
+
+
+/* Return a nonzero value if the revision specified by ARG is found. */
+static int
+findtag (Node *node, void *arg)
+{
+ char *rev = arg;
+
+ if (STREQ (node->data, rev))
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/* Delete revisions between REV1 and REV2. The changes between the two
+ revisions must be collapsed, and the result stored in the revision
+ immediately preceding the lower one. Return 0 for successful completion,
+ 1 otherwise.
+
+ Solution: check out the revision preceding REV1 and the revision
+ following REV2. Use call_diff to find aggregate diffs between
+ these two revisions, and replace the delta text for the latter one
+ with the new aggregate diff. Alternatively, we could write a
+ function that takes two change texts and combines them to produce a
+ new change text, without checking out any revs or calling diff. It
+ would be hairy, but so, so cool.
+
+ If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
+ delete that revision as well (cvs admin -o tag1:tag2). If clear,
+ delete up to but not including that revision (cvs admin -o tag1::tag2).
+ This does not affect TAG1 or TAG2 being NULL; the meaning of the start
+ point in ::tag2 and :tag2 is the same and likewise for end points. */
+int
+RCS_delete_revs (RCSNode *rcs, char *tag1, char *tag2, int inclusive)
+{
+ char *next;
+ Node *nodep;
+ RCSVers *revp = NULL;
+ RCSVers *beforep;
+ int status, found;
+ int save_noexec;
+
+ char *branchpoint = NULL;
+ char *rev1 = NULL;
+ char *rev2 = NULL;
+ int rev1_inclusive = inclusive;
+ int rev2_inclusive = inclusive;
+ char *before = NULL;
+ char *after = NULL;
+ char *beforefile = NULL;
+ char *afterfile = NULL;
+ char *outfile = NULL;
+
+ if (tag1 == NULL && tag2 == NULL)
+ return 0;
+
+ /* Assume error status until everything is finished. */
+ status = 1;
+
+ /* Make sure both revisions exist. */
+ if (tag1 != NULL)
+ {
+ rev1 = RCS_gettag (rcs, tag1, 1, NULL);
+ if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
+ {
+ error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag1);
+ goto delrev_done;
+ }
+ }
+ if (tag2 != NULL)
+ {
+ rev2 = RCS_gettag (rcs, tag2, 1, NULL);
+ if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
+ {
+ error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag2);
+ goto delrev_done;
+ }
+ }
+
+ /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
+ RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch
+ instead.) We need to check this special case early, in order
+ to make sure that rev1 and rev2 get ordered correctly. */
+ if (rev2 == NULL && numdots (rev1) == 1)
+ {
+ rev2 = xstrdup (rcs->head);
+ rev2_inclusive = 1;
+ }
+
+ if (rev2 == NULL)
+ rev2_inclusive = 1;
+
+ if (rev1 != NULL && rev2 != NULL)
+ {
+ /* A range consisting of a branch number means the latest revision
+ on that branch. */
+ if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
+ {
+ char *tmp = RCS_getbranch (rcs, rev1, 0);
+ free (rev1);
+ free (rev2);
+ rev1 = rev2 = tmp;
+ }
+ else
+ {
+ /* Make sure REV1 and REV2 are ordered correctly (in the
+ same order as the next field). For revisions on the
+ trunk, REV1 should be higher than REV2; for branches,
+ REV1 should be lower. */
+ /* Shouldn't we just be giving an error in the case where
+ the user specifies the revisions in the wrong order
+ (that is, always swap on the trunk, never swap on a
+ branch, in the non-error cases)? It is not at all
+ clear to me that users who specify -o 1.4:1.2 really
+ meant to type -o 1.2:1.4, and the out of order usage
+ has never been documented, either by cvs.texinfo or
+ rcs(1). */
+ char *temp;
+ int temp_inclusive;
+ if (numdots (rev1) == 1)
+ {
+ if (compare_revnums (rev1, rev2) <= 0)
+ {
+ temp = rev2;
+ rev2 = rev1;
+ rev1 = temp;
+
+ temp_inclusive = rev2_inclusive;
+ rev2_inclusive = rev1_inclusive;
+ rev1_inclusive = temp_inclusive;
+ }
+ }
+ else if (compare_revnums (rev1, rev2) > 0)
+ {
+ temp = rev2;
+ rev2 = rev1;
+ rev1 = temp;
+
+ temp_inclusive = rev2_inclusive;
+ rev2_inclusive = rev1_inclusive;
+ rev1_inclusive = temp_inclusive;
+ }
+ }
+ }
+
+ /* Basically the same thing; make sure that the ordering is what we
+ need. */
+ if (rev1 == NULL)
+ {
+ assert (rev2 != NULL);
+ if (numdots (rev2) == 1)
+ {
+ /* Swap rev1 and rev2. */
+ int temp_inclusive;
+
+ rev1 = rev2;
+ rev2 = NULL;
+
+ temp_inclusive = rev2_inclusive;
+ rev2_inclusive = rev1_inclusive;
+ rev1_inclusive = temp_inclusive;
+ }
+ }
+
+ /* Put the revision number preceding the first one to delete into
+ BEFORE (where "preceding" means according to the next field).
+ If the first revision to delete is the first revision on its
+ branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
+ at which the branch is rooted. If the first revision to delete
+ is the head revision of the trunk, set BEFORE to NULL.
+
+ Note that because BEFORE may not be on the same branch as REV1,
+ it is not very handy for navigating the revision tree. It's
+ most useful just for checking out the revision preceding REV1. */
+ before = NULL;
+ branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
+ if (rev1 == NULL)
+ {
+ rev1 = xstrdup (branchpoint);
+ if (numdots (branchpoint) > 1)
+ {
+ char *bp;
+ bp = strrchr (branchpoint, '.');
+ while (*--bp != '.')
+ ;
+ *bp = '\0';
+ /* Note that this is exclusive, always, because the inclusive
+ flag doesn't affect the meaning when rev1 == NULL. */
+ before = xstrdup (branchpoint);
+ *bp = '.';
+ }
+ }
+ else if (! STREQ (rev1, branchpoint))
+ {
+ /* Walk deltas from BRANCHPOINT on, looking for REV1. */
+ nodep = findnode (rcs->versions, branchpoint);
+ revp = nodep->data;
+ while (revp->next != NULL && ! STREQ (revp->next, rev1))
+ {
+ revp = nodep->data;
+ nodep = findnode (rcs->versions, revp->next);
+ }
+ if (revp->next == NULL)
+ {
+ error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, rev1);
+ goto delrev_done;
+ }
+ if (rev1_inclusive)
+ before = xstrdup (revp->version);
+ else
+ {
+ before = rev1;
+ nodep = findnode (rcs->versions, before);
+ rev1 = xstrdup (((RCSVers *)nodep->data)->next);
+ }
+ }
+ else if (!rev1_inclusive)
+ {
+ before = rev1;
+ nodep = findnode (rcs->versions, before);
+ rev1 = xstrdup (((RCSVers *)nodep->data)->next);
+ }
+ else if (numdots (branchpoint) > 1)
+ {
+ /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
+ Set before to "1.3". */
+ char *bp;
+ bp = strrchr (branchpoint, '.');
+ while (*--bp != '.')
+ ;
+ *bp = '\0';
+ before = xstrdup (branchpoint);
+ *bp = '.';
+ }
+
+ /* If any revision between REV1 and REV2 is locked or is a branch point,
+ we can't delete that revision and must abort. */
+ after = NULL;
+ next = rev1;
+ found = 0;
+ while (!found && next != NULL)
+ {
+ nodep = findnode (rcs->versions, next);
+ revp = nodep->data;
+
+ if (rev2 != NULL)
+ found = STREQ (revp->version, rev2);
+ next = revp->next;
+
+ if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
+ {
+ if (findnode (RCS_getlocks (rcs), revp->version))
+ {
+ error (0, 0, "%s: can't remove locked revision %s",
+ rcs->print_path,
+ revp->version);
+ goto delrev_done;
+ }
+ if (revp->branches != NULL)
+ {
+ error (0, 0, "%s: can't remove branch point %s",
+ rcs->print_path,
+ revp->version);
+ goto delrev_done;
+ }
+
+ /* Doing this only for the :: syntax is for compatibility.
+ See cvs.texinfo for somewhat more discussion. */
+ if (!inclusive
+ && walklist (RCS_symbols (rcs), findtag, revp->version))
+ {
+ /* We don't print which file this happens to on the theory
+ that the caller will print the name of the file in a
+ more useful fashion (fullname not rcs->path). */
+ error (0, 0, "cannot remove revision %s because it has tags",
+ revp->version);
+ goto delrev_done;
+ }
+
+ /* It's misleading to print the `deleting revision' output
+ here, since we may not actually delete these revisions.
+ But that's how RCS does it. Bleah. Someday this should be
+ moved to the point where the revs are actually marked for
+ deletion. -twp */
+ cvs_output ("deleting revision ", 0);
+ cvs_output (revp->version, 0);
+ cvs_output ("\n", 1);
+ }
+ }
+
+ if (rev2 == NULL)
+ ;
+ else if (found)
+ {
+ if (rev2_inclusive)
+ after = xstrdup (next);
+ else
+ after = xstrdup (revp->version);
+ }
+ else if (!inclusive)
+ {
+ /* In the case of an empty range, for example 1.2::1.2 or
+ 1.2::1.3, we want to just do nothing. */
+ status = 0;
+ goto delrev_done;
+ }
+ else
+ {
+ /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
+ Are those cases really impossible? */
+ assert (tag1 != NULL);
+ assert (tag2 != NULL);
+
+ error (0, 0, "%s: invalid revision range %s:%s", rcs->print_path,
+ tag1, tag2);
+ goto delrev_done;
+ }
+
+ if (after == NULL && before == NULL)
+ {
+ /* The user is trying to delete all revisions. While an
+ RCS file without revisions makes sense to RCS (e.g. the
+ state after "rcs -i"), CVS has never been able to cope with
+ it. So at least for now we just make this an error.
+
+ We don't include rcs->path in the message since "cvs admin"
+ already printed "RCS file:" and the name. */
+ error (1, 0, "attempt to delete all revisions");
+ }
+
+ /* The conditionals at this point get really hairy. Here is the
+ general idea:
+
+ IF before != NULL and after == NULL
+ THEN don't check out any revisions, just delete them
+ IF before == NULL and after != NULL
+ THEN only check out after's revision, and use it for the new deltatext
+ ELSE
+ check out both revisions and diff -n them. This could use
+ RCS_exec_rcsdiff with some changes, like being able
+ to suppress diagnostic messages and to direct output. */
+
+ if (after != NULL)
+ {
+ char *diffbuf;
+ size_t bufsize, len;
+
+#if defined (WOE32) && !defined (__CYGWIN32__)
+ /* FIXME: This is an awful kludge, but at least until I have
+ time to work on it a little more and test it, I'd rather
+ give a fatal error than corrupt the file. I think that we
+ need to use "-kb" and "--binary" and "rb" to get_file
+ (probably can do it always, not just for binary files, if
+ we are consistent between the RCS_checkout and the diff). */
+ {
+ char *expand = RCS_getexpand (rcs);
+ if (expand != NULL && STREQ (expand, "b"))
+ error (1, 0,
+ "admin -o not implemented yet for binary on this system");
+ }
+#endif /* WOE32 */
+
+ afterfile = cvs_temp_name();
+ status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
+ NULL, NULL);
+ if (status > 0)
+ goto delrev_done;
+
+ if (before == NULL)
+ {
+ /* We are deleting revisions from the head of the tree,
+ so must create a new head. */
+ diffbuf = NULL;
+ bufsize = 0;
+ get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
+
+ save_noexec = noexec;
+ noexec = 0;
+ if (unlink_file (afterfile) < 0)
+ error (0, errno, "cannot remove %s", afterfile);
+ noexec = save_noexec;
+
+ free (afterfile);
+ afterfile = NULL;
+
+ free (rcs->head);
+ rcs->head = xstrdup (after);
+ }
+ else
+ {
+ int dargc = 0;
+ size_t darg_allocated = 0;
+ char **dargv = NULL;
+
+ beforefile = cvs_temp_name();
+ status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
+ NULL, NULL);
+ if (status > 0)
+ goto delrev_done;
+
+ outfile = cvs_temp_name();
+ run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
+ run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
+ status = diff_exec (beforefile, afterfile, NULL, NULL,
+ dargc, dargv, outfile);
+ run_arg_free_p (dargc, dargv);
+ free (dargv);
+
+ if (status == 2)
+ {
+ /* Not sure we need this message; will diff_exec already
+ have printed an error? */
+ error (0, 0, "%s: could not diff", rcs->print_path);
+ status = 1;
+ goto delrev_done;
+ }
+
+ diffbuf = NULL;
+ bufsize = 0;
+ get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
+ }
+
+ /* Save the new change text in after's delta node. */
+ nodep = findnode (rcs->versions, after);
+ revp = nodep->data;
+
+ assert (revp->text == NULL);
+
+ revp->text = xmalloc (sizeof (Deltatext));
+ memset (revp->text, 0, sizeof (Deltatext));
+ revp->text->version = xstrdup (revp->version);
+ revp->text->text = diffbuf;
+ revp->text->len = len;
+
+ /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
+ there are no differences between the two revisions. In that
+ case, we want to force RCS_copydeltas to write an empty string
+ for the new change text (leaving the text field set NULL
+ means "preserve the original change text for this delta," so
+ we don't want that). */
+ if (revp->text->text == NULL)
+ revp->text->text = xstrdup ("");
+ }
+
+ /* Walk through the revisions (again) to mark each one as
+ outdated. (FIXME: would it be safe to use the `dead' field for
+ this? Doubtful.) */
+ for (next = rev1;
+ next != NULL && (after == NULL || ! STREQ (next, after));
+ next = revp->next)
+ {
+ nodep = findnode (rcs->versions, next);
+ revp = nodep->data;
+ revp->outdated = 1;
+ }
+
+ /* Update delta links. If BEFORE == NULL, we're changing the
+ head of the tree and don't need to update any `next' links. */
+ if (before != NULL)
+ {
+ /* If REV1 is the first node on its branch, then BEFORE is its
+ root node (on the trunk) and we have to update its branches
+ list. Otherwise, BEFORE is on the same branch as AFTER, and
+ we can just change BEFORE's `next' field to point to AFTER.
+ (This should be safe: since findnode manages its lists via
+ the `hashnext' and `hashprev' fields, rather than `next' and
+ `prev', mucking with `next' and `prev' should not corrupt the
+ delta tree's internal structure. Much. -twp) */
+
+ if (rev1 == NULL)
+ /* beforep's ->next field already should be equal to after,
+ which I think is always NULL in this case. */
+ ;
+ else if (STREQ (rev1, branchpoint))
+ {
+ nodep = findnode (rcs->versions, before);
+ revp = nodep->data;
+ nodep = revp->branches->list->next;
+ while (nodep != revp->branches->list &&
+ ! STREQ (nodep->key, rev1))
+ nodep = nodep->next;
+ assert (nodep != revp->branches->list);
+ if (after == NULL)
+ delnode (nodep);
+ else
+ {
+ free (nodep->key);
+ nodep->key = xstrdup (after);
+ }
+ }
+ else
+ {
+ nodep = findnode (rcs->versions, before);
+ beforep = nodep->data;
+ free (beforep->next);
+ beforep->next = xstrdup (after);
+ }
+ }
+
+ status = 0;
+
+ delrev_done:
+ if (rev1 != NULL)
+ free (rev1);
+ if (rev2 && rev2 != rev1)
+ free (rev2);
+ if (branchpoint != NULL)
+ free (branchpoint);
+ if (before != NULL)
+ free (before);
+ if (after != NULL)
+ free (after);
+
+ save_noexec = noexec;
+ noexec = 0;
+ if (beforefile != NULL)
+ {
+ if (unlink_file (beforefile) < 0)
+ error (0, errno, "cannot remove %s", beforefile);
+ free (beforefile);
+ }
+ if (afterfile != NULL)
+ {
+ if (unlink_file (afterfile) < 0)
+ error (0, errno, "cannot remove %s", afterfile);
+ free (afterfile);
+ }
+ if (outfile != NULL)
+ {
+ if (unlink_file (outfile) < 0)
+ error (0, errno, "cannot remove %s", outfile);
+ free (outfile);
+ }
+ noexec = save_noexec;
+
+ return status;
+}
+
+
+
+/*
+ * TRUE if there exists a symbolic tag "tag" in file.
+ */
+int
+RCS_exist_tag (RCSNode *rcs, char *tag)
+{
+
+ assert (rcs != NULL);
+
+ if (findnode (RCS_symbols (rcs), tag))
+ return 1;
+ return 0;
+
+}
+
+
+
+/*
+ * TRUE if RCS revision number "rev" exists.
+ * This includes magic branch revisions, not found in rcs->versions,
+ * but only in rcs->symbols, requiring a list walk to find them.
+ * Take advantage of list walk callback function already used by
+ * RCS_delete_revs, above.
+ */
+int
+RCS_exist_rev (RCSNode *rcs, char *rev)
+{
+
+ assert (rcs != NULL);
+
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL, NULL);
+
+ if (findnode(rcs->versions, rev) != 0)
+ return 1;
+
+ if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
+ return 1;
+
+ return 0;
+
+}
+
+
+
+
+/* RCS_deltas and friends. Processing of the deltas in RCS files. */
+struct line
+{
+ /* Text of this line. Part of the same malloc'd block as the struct
+ line itself (we probably should use the "struct hack" (char text[1])
+ and save ourselves sizeof (char *) bytes). Does not include \n;
+ instead has_newline indicates the presence or absence of \n. */
+ char *text;
+ /* Length of this line, not counting \n if has_newline is true. */
+ size_t len;
+ /* Version in which it was introduced. */
+ RCSVers *vers;
+ /* Nonzero if this line ends with \n. This will always be true
+ except possibly for the last line. */
+ int has_newline;
+ /* Number of pointers to this struct line. */
+ int refcount;
+};
+
+struct linevector
+{
+ /* How many lines in use for this linevector? */
+ unsigned int nlines;
+ /* How many lines allocated for this linevector? */
+ unsigned int lines_alloced;
+ /* Pointer to array containing a pointer to each line. */
+ struct line **vector;
+};
+
+
+
+/* Initialize *VEC to be a linevector with no lines. */
+static void
+linevector_init (struct linevector *vec)
+{
+ vec->lines_alloced = 0;
+ vec->nlines = 0;
+ vec->vector = NULL;
+}
+
+
+
+/* Given some text TEXT, add each of its lines to VEC before line POS
+ (where line 0 is the first line). The last line in TEXT may or may
+ not be \n terminated.
+ Set the version for each of the new lines to VERS. This
+ function returns non-zero for success. It returns zero if the line
+ number is out of range.
+
+ Each of the lines in TEXT are copied to space which is managed with
+ the linevector (and freed by linevector_free). So the caller doesn't
+ need to keep TEXT around after the call to this function. */
+static int
+linevector_add (struct linevector *vec, const char *text, size_t len,
+ RCSVers *vers, unsigned int pos)
+{
+ const char *textend;
+ unsigned int i;
+ unsigned int nnew;
+ const char *p;
+ const char *nextline_text;
+ size_t nextline_len;
+ int nextline_newline;
+ struct line *q;
+
+ if (len == 0)
+ return 1;
+
+ textend = text + len;
+
+ /* Count the number of lines we will need to add. */
+ nnew = 1;
+ for (p = text; p < textend; ++p)
+ if (*p == '\n' && p + 1 < textend)
+ ++nnew;
+
+ /* Expand VEC->VECTOR if needed. */
+ if (vec->nlines + nnew >= vec->lines_alloced)
+ {
+ if (vec->lines_alloced == 0)
+ vec->lines_alloced = 10;
+ while (vec->nlines + nnew >= vec->lines_alloced)
+ vec->lines_alloced *= 2;
+ vec->vector = xnrealloc (vec->vector,
+ vec->lines_alloced, sizeof (*vec->vector));
+ }
+
+ /* Make room for the new lines in VEC->VECTOR. */
+ for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
+ vec->vector[i] = vec->vector[i - nnew];
+
+ if (pos > vec->nlines)
+ return 0;
+
+ /* Actually add the lines, to VEC->VECTOR. */
+ i = pos;
+ nextline_text = text;
+ nextline_newline = 0;
+ for (p = text; p < textend; ++p)
+ if (*p == '\n')
+ {
+ nextline_newline = 1;
+ if (p + 1 == textend)
+ /* If there are no characters beyond the last newline, we
+ don't consider it another line. */
+ break;
+ nextline_len = p - nextline_text;
+ q = xmalloc (sizeof (struct line) + nextline_len);
+ q->vers = vers;
+ q->text = (char *)q + sizeof (struct line);
+ q->len = nextline_len;
+ q->has_newline = nextline_newline;
+ q->refcount = 1;
+ memcpy (q->text, nextline_text, nextline_len);
+ vec->vector[i++] = q;
+
+ nextline_text = (char *)p + 1;
+ nextline_newline = 0;
+ }
+ nextline_len = p - nextline_text;
+ q = xmalloc (sizeof (struct line) + nextline_len);
+ q->vers = vers;
+ q->text = (char *)q + sizeof (struct line);
+ q->len = nextline_len;
+ q->has_newline = nextline_newline;
+ q->refcount = 1;
+ memcpy (q->text, nextline_text, nextline_len);
+ vec->vector[i] = q;
+
+ vec->nlines += nnew;
+
+ return 1;
+}
+
+
+
+/* Remove NLINES lines from VEC at position POS (where line 0 is the
+ first line). */
+static void
+linevector_delete (struct linevector *vec, unsigned int pos,
+ unsigned int nlines)
+{
+ unsigned int i;
+ unsigned int last;
+
+ last = vec->nlines - nlines;
+ for (i = pos; i < pos + nlines; ++i)
+ {
+ if (--vec->vector[i]->refcount == 0)
+ free (vec->vector[i]);
+ }
+ for (i = pos; i < last; ++i)
+ vec->vector[i] = vec->vector[i + nlines];
+ vec->nlines -= nlines;
+}
+
+
+
+/* Copy FROM to TO, copying the vectors but not the lines pointed to. */
+static void
+linevector_copy (struct linevector *to, struct linevector *from)
+{
+ unsigned int ln;
+
+ for (ln = 0; ln < to->nlines; ++ln)
+ {
+ if (--to->vector[ln]->refcount == 0)
+ free (to->vector[ln]);
+ }
+ if (from->nlines > to->lines_alloced)
+ {
+ if (to->lines_alloced == 0)
+ to->lines_alloced = 10;
+ while (from->nlines > to->lines_alloced)
+ to->lines_alloced *= 2;
+ to->vector = xnrealloc (to->vector,
+ to->lines_alloced,
+ sizeof (*to->vector));
+ }
+ memcpy (to->vector, from->vector,
+ xtimes (from->nlines, sizeof (*to->vector)));
+ to->nlines = from->nlines;
+ for (ln = 0; ln < to->nlines; ++ln)
+ ++to->vector[ln]->refcount;
+}
+
+
+
+/* Free storage associated with linevector. */
+static void
+linevector_free (struct linevector *vec)
+{
+ unsigned int ln;
+
+ if (vec->vector != NULL)
+ {
+ for (ln = 0; ln < vec->nlines; ++ln)
+ if (--vec->vector[ln]->refcount == 0)
+ free (vec->vector[ln]);
+
+ free (vec->vector);
+ }
+}
+
+
+
+/* Given a textual string giving the month (1-12), terminated with any
+ character not recognized by atoi, return the 3 character name to
+ print it with. I do not think it is a good idea to change these
+ strings based on the locale; they are standard abbreviations (for
+ example in rfc822 mail messages) which should be widely understood.
+ Returns a pointer into static readonly storage. */
+static const char *
+month_printname (const char *month)
+{
+ static const char *const months[] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ int mnum;
+
+ mnum = atoi (month);
+ if (mnum < 1 || mnum > 12)
+ return "???";
+ return months[mnum - 1];
+}
+
+
+
+/* Apply changes to the line vector LINES. DIFFBUF is a buffer of
+ length DIFFLEN holding the change text from an RCS file (the output
+ of diff -n). NAME is used in error messages. The VERS field of
+ any line added is set to ADDVERS. The VERS field of any line
+ deleted is set to DELVERS, unless DELVERS is NULL, in which case
+ the VERS field of deleted lines is unchanged. The function returns
+ non-zero if the change text is applied successfully. It returns
+ zero if the change text does not appear to apply to LINES (e.g., a
+ line number is invalid). If the change text is improperly
+ formatted (e.g., it is not the output of diff -n), the function
+ calls error with a status of 1, causing the program to exit. */
+static int
+apply_rcs_changes (struct linevector *lines, const char *diffbuf,
+ size_t difflen, const char *name, RCSVers *addvers,
+ RCSVers *delvers)
+{
+ const char *p;
+ const char *q;
+ int op;
+ /* The RCS format throws us for a loop in that the deltafrags (if
+ we define a deltafrag as an add or a delete) need to be applied
+ in reverse order. So we stick them into a linked list. */
+ struct deltafrag {
+ enum {FRAG_ADD, FRAG_DELETE} type;
+ unsigned long pos;
+ unsigned long nlines;
+ const char *new_lines;
+ size_t len;
+ struct deltafrag *next;
+ };
+ struct deltafrag *dfhead;
+ struct deltafrag *df;
+ int err;
+
+ dfhead = NULL;
+ for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
+ {
+ op = *p++;
+ if (op != 'a' && op != 'd')
+ /* Can't just skip over the deltafrag, because the value
+ of op determines the syntax. */
+ error (1, 0, "unrecognized operation '\\x%x' in %s",
+ op, name);
+ df = xmalloc (sizeof (struct deltafrag));
+ df->next = dfhead;
+ dfhead = df;
+ df->pos = strtoul (p, (char **) &q, 10);
+
+ if (p == q)
+ error (1, 0, "number expected in %s", name);
+ p = q;
+ if (*p++ != ' ')
+ error (1, 0, "space expected in %s", name);
+ df->nlines = strtoul (p, (char **) &q, 10);
+ if (p == q)
+ error (1, 0, "number expected in %s", name);
+ p = q;
+ if (*p++ != '\012')
+ error (1, 0, "linefeed expected in %s", name);
+
+ if (op == 'a')
+ {
+ unsigned int i;
+
+ df->type = FRAG_ADD;
+ i = df->nlines;
+ /* The text we want is the number of lines specified, or
+ until the end of the value, whichever comes first (it
+ will be the former except in the case where we are
+ adding a line which does not end in newline). */
+ for (q = p; i != 0; ++q)
+ if (*q == '\n')
+ --i;
+ else if (q == diffbuf + difflen)
+ {
+ if (i != 1)
+ error (1, 0, "premature end of change in %s", name);
+ else
+ break;
+ }
+
+ /* Stash away a pointer to the text we are adding. */
+ df->new_lines = p;
+ df->len = q - p;
+
+ p = q;
+ }
+ else
+ {
+ /* Correct for the fact that line numbers in RCS files
+ start with 1. */
+ --df->pos;
+
+ assert (op == 'd');
+ df->type = FRAG_DELETE;
+ }
+ }
+
+ err = 0;
+ for (df = dfhead; df != NULL;)
+ {
+ unsigned int ln;
+
+ /* Once an error is encountered, just free the rest of the list and
+ * return.
+ */
+ if (!err)
+ switch (df->type)
+ {
+ case FRAG_ADD:
+ if (! linevector_add (lines, df->new_lines, df->len, addvers,
+ df->pos))
+ err = 1;
+ break;
+ case FRAG_DELETE:
+ if (df->pos > lines->nlines
+ || df->pos + df->nlines > lines->nlines)
+ return 0;
+ if (delvers != NULL)
+ for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
+ lines->vector[ln]->vers = delvers;
+ linevector_delete (lines, df->pos, df->nlines);
+ break;
+ }
+
+ df = df->next;
+ free (dfhead);
+ dfhead = df;
+ }
+
+ return !err;
+}
+
+
+
+/* Apply an RCS change text to a buffer. The function name starts
+ with rcs rather than RCS because this does not take an RCSNode
+ argument. NAME is used in error messages. TEXTBUF is the text
+ buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are
+ the change buffer and size. The new buffer is returned in *RETBUF
+ and *RETLEN. The new buffer is allocated by xmalloc.
+
+ Return 1 for success. On failure, call error and return 0. */
+int
+rcs_change_text (const char *name, char *textbuf, size_t textlen,
+ const char *diffbuf, size_t difflen, char **retbuf,
+ size_t *retlen)
+{
+ struct linevector lines;
+ int ret;
+
+ *retbuf = NULL;
+ *retlen = 0;
+
+ linevector_init (&lines);
+
+ if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
+ error (1, 0, "cannot initialize line vector");
+
+ if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
+ {
+ error (0, 0, "invalid change text in %s", name);
+ ret = 0;
+ }
+ else
+ {
+ char *p;
+ size_t n;
+ unsigned int ln;
+
+ n = 0;
+ for (ln = 0; ln < lines.nlines; ++ln)
+ /* 1 for \n */
+ n += lines.vector[ln]->len + 1;
+
+ p = xmalloc (n);
+ *retbuf = p;
+
+ for (ln = 0; ln < lines.nlines; ++ln)
+ {
+ memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
+ p += lines.vector[ln]->len;
+ if (lines.vector[ln]->has_newline)
+ *p++ = '\n';
+ }
+
+ *retlen = p - *retbuf;
+ assert (*retlen <= n);
+
+ ret = 1;
+ }
+
+ linevector_free (&lines);
+
+ return ret;
+}
+
+
+
+/* Walk the deltas in RCS to get to revision VERSION.
+
+ If OP is RCS_ANNOTATE, then write annotations using cvs_output.
+
+ If OP is RCS_FETCH, then put the contents of VERSION into a
+ newly-malloc'd array and put a pointer to it in *TEXT. Each line
+ is \n terminated; the caller is responsible for converting text
+ files if desired. The total length is put in *LEN.
+
+ If FP is non-NULL, it should be a file descriptor open to the file
+ RCS with file position pointing to the deltas. We close the file
+ when we are done.
+
+ If LOG is non-NULL, then *LOG is set to the log message of VERSION,
+ and *LOGLEN is set to the length of the log message.
+
+ On error, give a fatal error. */
+void
+RCS_deltas (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf,
+ const char *version, enum rcs_delta_op op, char **text,
+ size_t *len, char **log, size_t *loglen)
+{
+ struct rcsbuffer rcsbuf_local;
+ char *branchversion;
+ char *cpversion;
+ char *key;
+ char *value;
+ size_t vallen;
+ RCSVers *vers;
+ RCSVers *prev_vers;
+ RCSVers *trunk_vers;
+ char *next;
+ int ishead, isnext, isversion, onbranch;
+ Node *node;
+ struct linevector headlines;
+ struct linevector curlines;
+ struct linevector trunklines;
+ int foundhead;
+
+ assert (version);
+
+ if (fp == NULL)
+ {
+ rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
+ rcsbuf = &rcsbuf_local;
+ }
+
+ if (log) *log = NULL;
+
+ ishead = 1;
+ vers = NULL;
+ prev_vers = NULL;
+ trunk_vers = NULL;
+ next = NULL;
+ onbranch = 0;
+ foundhead = 0;
+
+ linevector_init (&curlines);
+ linevector_init (&headlines);
+ linevector_init (&trunklines);
+
+ /* We set BRANCHVERSION to the version we are currently looking
+ for. Initially, this is the version on the trunk from which
+ VERSION branches off. If VERSION is not a branch, then
+ BRANCHVERSION is just VERSION. */
+ branchversion = xstrdup (version);
+ cpversion = strchr (branchversion, '.');
+ if (cpversion != NULL)
+ cpversion = strchr (cpversion + 1, '.');
+ if (cpversion != NULL)
+ *cpversion = '\0';
+
+ do {
+ if (! rcsbuf_getrevnum (rcsbuf, &key))
+ error (1, 0, "unexpected EOF reading RCS file %s", rcs->print_path);
+
+ if (next != NULL && ! STREQ (next, key))
+ {
+ /* This is not the next version we need. It is a branch
+ version which we want to ignore. */
+ isnext = 0;
+ isversion = 0;
+ }
+ else
+ {
+ isnext = 1;
+
+ /* look up the revision */
+ node = findnode (rcs->versions, key);
+ if (node == NULL)
+ error (1, 0,
+ "mismatch in rcs file %s between deltas and deltatexts (%s)",
+ rcs->print_path, key);
+
+ /* Stash the previous version. */
+ prev_vers = vers;
+
+ vers = node->data;
+ next = vers->next;
+
+ /* Compare key and trunkversion now, because key points to
+ storage controlled by rcsbuf_getkey. */
+ if (STREQ (branchversion, key))
+ isversion = 1;
+ else
+ isversion = 0;
+ }
+
+ while (1)
+ {
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ error (1, 0, "%s does not appear to be a valid rcs file",
+ rcs->print_path);
+
+ if (log != NULL
+ && isversion
+ && STREQ (key, "log")
+ && STREQ (branchversion, version))
+ {
+ if (*log != NULL)
+ {
+ error (0, 0, "Duplicate `log' keyword in RCS file (`%s').",
+ rcs->print_path);
+ free (*log);
+ }
+ *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
+ }
+
+ if (STREQ (key, "text"))
+ {
+ rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
+ if (ishead)
+ {
+ if (! linevector_add (&curlines, value, vallen, NULL, 0))
+ error (1, 0, "invalid rcs file %s", rcs->print_path);
+
+ ishead = 0;
+ }
+ else if (isnext)
+ {
+ if (! apply_rcs_changes (&curlines, value, vallen,
+ rcs->path,
+ onbranch ? vers : NULL,
+ onbranch ? NULL : prev_vers))
+ error (1, 0, "invalid change text in %s", rcs->print_path);
+ }
+ break;
+ }
+ }
+
+ if (isversion)
+ {
+ /* This is either the version we want, or it is the
+ branchpoint to the version we want. */
+ if (STREQ (branchversion, version))
+ {
+ /* This is the version we want. */
+ linevector_copy (&headlines, &curlines);
+ foundhead = 1;
+ if (onbranch)
+ {
+ /* We have found this version by tracking up a
+ branch. Restore back to the lines we saved
+ when we left the trunk, and continue tracking
+ down the trunk. */
+ onbranch = 0;
+ vers = trunk_vers;
+ next = vers->next;
+ linevector_copy (&curlines, &trunklines);
+ }
+ }
+ else
+ {
+ Node *p;
+
+ /* We need to look up the branch. */
+ onbranch = 1;
+
+ if (numdots (branchversion) < 2)
+ {
+ unsigned int ln;
+
+ /* We are leaving the trunk; save the current
+ lines so that we can restore them when we
+ continue tracking down the trunk. */
+ trunk_vers = vers;
+ linevector_copy (&trunklines, &curlines);
+
+ /* Reset the version information we have
+ accumulated so far. It only applies to the
+ changes from the head to this version. */
+ for (ln = 0; ln < curlines.nlines; ++ln)
+ curlines.vector[ln]->vers = NULL;
+ }
+
+ /* The next version we want is the entry on
+ VERS->branches which matches this branch. For
+ example, suppose VERSION is 1.21.4.3 and
+ BRANCHVERSION was 1.21. Then we look for an entry
+ starting with "1.21.4" and we'll put it (probably
+ 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by
+ two dots (in this example, to 1.21.4.3). */
+
+ if (vers->branches == NULL)
+ error (1, 0, "missing expected branches in %s",
+ rcs->print_path);
+ if (!cpversion)
+ error (1, 0, "Invalid revision number in `%s'.",
+ rcs->print_path);
+ *cpversion = '.';
+ ++cpversion;
+ cpversion = strchr (cpversion, '.');
+ if (cpversion == NULL)
+ error (1, 0, "version number confusion in %s",
+ rcs->print_path);
+ for (p = vers->branches->list->next;
+ p != vers->branches->list;
+ p = p->next)
+ if (strncmp (p->key, branchversion,
+ cpversion - branchversion) == 0)
+ break;
+ if (p == vers->branches->list)
+ error (1, 0, "missing expected branch in %s",
+ rcs->print_path);
+
+ next = p->key;
+
+ cpversion = strchr (cpversion + 1, '.');
+ if (cpversion != NULL)
+ *cpversion = '\0';
+ }
+ }
+ if (op == RCS_FETCH && foundhead)
+ break;
+ } while (next != NULL);
+
+ free (branchversion);
+
+ rcsbuf_cache (rcs, rcsbuf);
+
+ if (! foundhead)
+ error (1, 0, "could not find desired version %s in %s",
+ version, rcs->print_path);
+
+ /* Now print out or return the data we have just computed. */
+ switch (op)
+ {
+ case RCS_ANNOTATE:
+ {
+ unsigned int ln;
+
+ for (ln = 0; ln < headlines.nlines; ++ln)
+ {
+ char *buf;
+ /* Period which separates year from month in date. */
+ char *ym;
+ /* Period which separates month from day in date. */
+ char *md;
+ RCSVers *prvers;
+
+ prvers = headlines.vector[ln]->vers;
+ if (prvers == NULL)
+ prvers = vers;
+
+ buf = xmalloc (strlen (prvers->version) + 24);
+ sprintf (buf, "%-12s (%-8.8s ",
+ prvers->version,
+ prvers->author);
+ cvs_output (buf, 0);
+ free (buf);
+
+ /* Now output the date. */
+ ym = strchr (prvers->date, '.');
+ if (ym == NULL)
+ {
+ cvs_output ("??", 0);
+ cvs_output ("-???", 0);
+ cvs_output ("-??", 0);
+ }
+ else
+ {
+ md = strchr (ym + 1, '.');
+ if (md == NULL)
+ cvs_output ("??", 0);
+ else
+ cvs_output (md + 1, 2);
+
+ cvs_output ("-", 1);
+ cvs_output (month_printname (ym + 1), 0);
+ cvs_output ("-", 1);
+ /* Only output the last two digits of the year. Our output
+ lines are long enough as it is without printing the
+ century. */
+ cvs_output (ym - 2, 2);
+ }
+ cvs_output ("): ", 0);
+ if (headlines.vector[ln]->len != 0)
+ cvs_output (headlines.vector[ln]->text,
+ headlines.vector[ln]->len);
+ cvs_output ("\n", 1);
+ }
+ }
+ break;
+ case RCS_FETCH:
+ {
+ char *p;
+ size_t n;
+ unsigned int ln;
+
+ assert (text != NULL);
+ assert (len != NULL);
+
+ n = 0;
+ for (ln = 0; ln < headlines.nlines; ++ln)
+ /* 1 for \n */
+ n += headlines.vector[ln]->len + 1;
+ p = xmalloc (n);
+ *text = p;
+ for (ln = 0; ln < headlines.nlines; ++ln)
+ {
+ memcpy (p, headlines.vector[ln]->text,
+ headlines.vector[ln]->len);
+ p += headlines.vector[ln]->len;
+ if (headlines.vector[ln]->has_newline)
+ *p++ = '\n';
+ }
+ *len = p - *text;
+ assert (*len <= n);
+ }
+ break;
+ }
+
+ linevector_free (&curlines);
+ linevector_free (&headlines);
+ linevector_free (&trunklines);
+
+ return;
+}
+
+
+
+/* Read the information for a single delta from the RCS buffer RCSBUF,
+ whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
+ first key/value pair to read, as set by rcsbuf_getkey. Return NULL
+ if there are no more deltas. Store the key/value pair which
+ terminated the read in *KEYP and *VALP. */
+static RCSVers *
+getdelta (struct rcsbuffer *rcsbuf, char *rcsfile, char **keyp, char **valp)
+{
+ RCSVers *vnode;
+ char *key, *value, *cp;
+ Node *kv;
+
+ /* Get revision number if it wasn't passed in. This uses
+ rcsbuf_getkey because it doesn't croak when encountering
+ unexpected input. As a result, we have to play unholy games
+ with `key' and `value'. */
+ if (*keyp != NULL)
+ {
+ key = *keyp;
+ value = *valp;
+ }
+ else
+ {
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ error (1, 0, "%s: unexpected EOF", rcsfile);
+ }
+
+ /* Make sure that it is a revision number and not a cabbage
+ or something. */
+ for (cp = key;
+ (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ cp++)
+ /* do nothing */ ;
+ /* Note that when comparing with RCSDATE, we are not massaging
+ VALUE from the string found in the RCS file. This is OK since
+ we know exactly what to expect. */
+ if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
+ {
+ *keyp = key;
+ *valp = value;
+ return NULL;
+ }
+
+ vnode = xmalloc (sizeof (RCSVers));
+ memset (vnode, 0, sizeof (RCSVers));
+
+ vnode->version = xstrdup (key);
+
+ /* Grab the value of the date from value. Note that we are not
+ massaging VALUE from the string found in the RCS file. */
+ cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
+ while (whitespace (*cp)) /* take space off front of value */
+ cp++;
+
+ vnode->date = xstrdup (cp);
+
+ /* Get author field. */
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ {
+ error (1, 0, "unexpected end of file reading %s", rcsfile);
+ }
+ if (! STREQ (key, "author"))
+ error (1, 0, "\
+unable to parse %s; `author' not in the expected place", rcsfile);
+ vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
+
+ /* Get state field. */
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ {
+ error (1, 0, "unexpected end of file reading %s", rcsfile);
+ }
+ if (! STREQ (key, "state"))
+ error (1, 0, "\
+unable to parse %s; `state' not in the expected place", rcsfile);
+ vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
+ /* The value is optional, according to rcsfile(5). */
+ if (value != NULL && STREQ (value, RCSDEAD))
+ {
+ vnode->dead = 1;
+ }
+
+ /* Note that "branches" and "next" are in fact mandatory, according
+ to doc/RCSFILES. */
+
+ /* fill in the branch list (if any branches exist) */
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ {
+ error (1, 0, "unexpected end of file reading %s", rcsfile);
+ }
+ if (STREQ (key, RCSDESC))
+ {
+ *keyp = key;
+ *valp = value;
+ /* Probably could/should be a fatal error. */
+ error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
+ return vnode;
+ }
+ if (value != NULL)
+ {
+ vnode->branches = getlist ();
+ /* Note that we are not massaging VALUE from the string found
+ in the RCS file. */
+ do_branches (vnode->branches, value);
+ }
+
+ /* fill in the next field if there is a next revision */
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ {
+ error (1, 0, "unexpected end of file reading %s", rcsfile);
+ }
+ if (STREQ (key, RCSDESC))
+ {
+ *keyp = key;
+ *valp = value;
+ /* Probably could/should be a fatal error. */
+ error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
+ return vnode;
+ }
+ if (value != NULL)
+ vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
+
+ /*
+ * XXX - this is where we put the symbolic link stuff???
+ * (into newphrases in the deltas).
+ */
+ while (1)
+ {
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ error (1, 0, "unexpected end of file reading %s", rcsfile);
+
+ /* The `desc' keyword is the end of the deltas. */
+ if (strcmp (key, RCSDESC) == 0)
+ break;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+
+ /* The `hardlinks' value is a group of words, which must
+ be parsed separately and added as a list to vnode->hardlinks. */
+ if (strcmp (key, "hardlinks") == 0)
+ {
+ char *word;
+
+ vnode->hardlinks = getlist();
+ while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
+ {
+ Node *n = getnode();
+ n->key = word;
+ addnode (vnode->hardlinks, n);
+ }
+ continue;
+ }
+#endif
+
+ /* Enable use of repositories created by certain obsolete
+ versions of CVS. This code should remain indefinately;
+ there is no procedure for converting old repositories, and
+ checking for it is harmless. */
+ if (STREQ (key, RCSDEAD))
+ {
+ vnode->dead = 1;
+ if (vnode->state != NULL)
+ free (vnode->state);
+ vnode->state = xstrdup (RCSDEAD);
+ continue;
+ }
+ /* if we have a new revision number, we're done with this delta */
+ for (cp = key;
+ (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ cp++)
+ /* do nothing */ ;
+ /* Note that when comparing with RCSDATE, we are not massaging
+ VALUE from the string found in the RCS file. This is OK
+ since we know exactly what to expect. */
+ if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
+ break;
+
+ /* At this point, key and value represent a user-defined field
+ in the delta node. */
+ if (vnode->other_delta == NULL)
+ vnode->other_delta = getlist ();
+ kv = getnode ();
+ kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
+ kv->key = xstrdup (key);
+ kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, NULL);
+ if (addnode (vnode->other_delta, kv) != 0)
+ {
+ /* Complaining about duplicate keys in newphrases seems
+ questionable, in that we don't know what they mean and
+ doc/RCSFILES has no prohibition on several newphrases
+ with the same key. But we can't store more than one as
+ long as we store them in a List *. */
+ error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
+ key, rcsfile);
+ freenode (kv);
+ }
+ }
+
+ /* Return the key which caused us to fail back to the caller. */
+ *keyp = key;
+ *valp = value;
+
+ return vnode;
+}
+
+
+
+static void
+freedeltatext (Deltatext *d)
+{
+ if (d->version != NULL)
+ free (d->version);
+ if (d->log != NULL)
+ free (d->log);
+ if (d->text != NULL)
+ free (d->text);
+ if (d->other != NULL)
+ dellist (&d->other);
+ free (d);
+}
+
+static Deltatext *
+RCS_getdeltatext (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf)
+{
+ char *num;
+ char *key, *value;
+ Node *p;
+ Deltatext *d;
+
+ /* Get the revision number. */
+ if (! rcsbuf_getrevnum (rcsbuf, &num))
+ {
+ /* If num == NULL, it means we reached EOF naturally. That's
+ fine. */
+ if (num == NULL)
+ return NULL;
+ else
+ error (1, 0, "%s: unexpected EOF", rcs->print_path);
+ }
+
+ p = findnode (rcs->versions, num);
+ if (p == NULL)
+ error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)",
+ rcs->print_path, num);
+
+ d = xmalloc (sizeof (Deltatext));
+ d->version = xstrdup (num);
+
+ /* Get the log message. */
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num);
+ if (! STREQ (key, "log"))
+ error (1, 0, "%s, delta %s: expected `log', got `%s'",
+ rcs->print_path, num, key);
+ d->log = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
+
+ /* Get random newphrases. */
+ d->other = getlist();
+ while (1)
+ {
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num);
+
+ if (STREQ (key, "text"))
+ break;
+
+ p = getnode();
+ p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
+ p->key = xstrdup (key);
+ p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, NULL);
+ if (addnode (d->other, p) < 0)
+ {
+ error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
+ rcs->print_path, num, key);
+ }
+ }
+
+ /* Get the change text. We already know that this key is `text'. */
+ d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
+
+ return d;
+}
+
+
+
+/* RCS output functions, for writing RCS format files from RCSNode
+ structures.
+
+ For most of this work, RCS 5.7 uses an `aprintf' function which aborts
+ program upon error. Instead, these functions check the output status
+ of the stream right before closing it, and aborts if an error condition
+ is found. The RCS solution is probably the better one: it produces
+ more overhead, but will produce a clearer diagnostic in the case of
+ catastrophic error. In either case, however, the repository will probably
+ not get corrupted. */
+static int
+putsymbol_proc (Node *symnode, void *fparg)
+{
+ FILE *fp = fparg;
+
+ /* A fiddly optimization: this code used to just call fprintf, but
+ in an old repository with hundreds of tags this can get called
+ hundreds of thousands of times when doing a cvs tag. Since
+ tagging is a relatively common operation, and using putc and
+ fputs is just as comprehensible, the change is worthwhile. */
+ putc ('\n', fp);
+ putc ('\t', fp);
+ fputs (symnode->key, fp);
+ putc (':', fp);
+ fputs (symnode->data, fp);
+ return 0;
+}
+
+
+
+/* putlock_proc is like putsymbol_proc, but key and data are reversed. */
+static int
+putlock_proc (Node *symnode, void *fp)
+{
+ return fprintf (fp, "\n\t%s:%s", (char *)symnode->data, symnode->key);
+}
+
+
+
+static int
+putrcsfield_proc (Node *node, void *vfp)
+{
+ FILE *fp = vfp;
+
+ /* Some magic keys used internally by CVS start with `;'. Skip them. */
+ if (node->key[0] == ';')
+ return 0;
+
+ fprintf (fp, "\n%s\t", node->key);
+ if (node->data != NULL)
+ {
+ /* If the field's value contains evil characters,
+ it must be stringified. */
+ /* FIXME: This does not quite get it right. "7jk8f" is not a valid
+ value for a value in a newpharse, according to doc/RCSFILES,
+ because digits are not valid in an "id". We might do OK by
+ always writing strings (enclosed in @@). Would be nice to
+ explicitly mention this one way or another in doc/RCSFILES.
+ A case where we are wrong in a much more clear-cut way is that
+ we let through non-graphic characters such as whitespace and
+ control characters. */
+
+ if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
+ fputs (node->data, fp);
+ else
+ {
+ putc ('@', fp);
+ expand_at_signs (node->data, (off_t) strlen (node->data), fp);
+ putc ('@', fp);
+ }
+ }
+
+ /* desc, log and text fields should not be terminated with semicolon;
+ all other fields should be. */
+ if (! STREQ (node->key, "desc") &&
+ ! STREQ (node->key, "log") &&
+ ! STREQ (node->key, "text"))
+ {
+ putc (';', fp);
+ }
+ return 0;
+}
+
+
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+
+/* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain
+ a full pathname, but currently only basenames are stored in the RCS
+ node. Assume that the filename includes nasty characters and
+ @-escape it. */
+
+static int
+puthardlink_proc (node, vfp)
+ Node *node;
+ void *vfp;
+{
+ FILE *fp = vfp;
+ char *basename = strrchr (node->key, '/');
+
+ if (basename == NULL)
+ basename = node->key;
+ else
+ ++basename;
+
+ putc ('\t', fp);
+ putc ('@', fp);
+ (void) expand_at_signs (basename, strlen (basename), fp);
+ putc ('@', fp);
+
+ return 0;
+}
+
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+
+
+
+/* Output the admin node for RCS into stream FP. */
+static void
+RCS_putadmin (RCSNode *rcs, FILE *fp)
+{
+ fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
+ if (rcs->branch)
+ fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
+
+ fputs ("access", fp);
+ if (rcs->access)
+ {
+ char *p, *s;
+ s = xstrdup (rcs->access);
+ for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
+ fprintf (fp, "\n\t%s", p);
+ free (s);
+ }
+ fputs (";\n", fp);
+
+ fputs (RCSSYMBOLS, fp);
+ /* If we haven't had to convert the symbols to a list yet, don't
+ force a conversion now; just write out the string. */
+ if (rcs->symbols == NULL && rcs->symbols_data != NULL)
+ {
+ fputs ("\n\t", fp);
+ fputs (rcs->symbols_data, fp);
+ }
+ else
+ walklist (RCS_symbols (rcs), putsymbol_proc, fp);
+ fputs (";\n", fp);
+
+ fputs ("locks", fp);
+ if (rcs->locks_data)
+ fprintf (fp, "\t%s", rcs->locks_data);
+ else if (rcs->locks)
+ walklist (rcs->locks, putlock_proc, fp);
+ if (rcs->strict_locks)
+ fprintf (fp, "; strict");
+ fputs (";\n", fp);
+
+ if (rcs->comment)
+ {
+ fprintf (fp, "comment\t@");
+ expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
+ fputs ("@;\n", fp);
+ }
+ if (rcs->expand && ! STREQ (rcs->expand, "kv"))
+ fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
+
+ walklist (rcs->other, putrcsfield_proc, fp);
+
+ putc ('\n', fp);
+}
+
+
+
+static void
+putdelta (RCSVers *vers, FILE *fp)
+{
+ Node *bp, *start;
+
+ /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
+ if (vers == NULL || vers->outdated)
+ return;
+
+ fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
+ vers->version,
+ RCSDATE, vers->date,
+ "author", vers->author,
+ "state", vers->state ? vers->state : "");
+
+ if (vers->branches != NULL)
+ {
+ start = vers->branches->list;
+ for (bp = start->next; bp != start; bp = bp->next)
+ fprintf (fp, "\n\t%s", bp->key);
+ }
+
+ fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
+
+ walklist (vers->other_delta, putrcsfield_proc, fp);
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (vers->hardlinks)
+ {
+ fprintf (fp, "\nhardlinks");
+ walklist (vers->hardlinks, puthardlink_proc, fp);
+ putc (';', fp);
+ }
+#endif
+ putc ('\n', fp);
+}
+
+
+
+static void
+RCS_putdtree (RCSNode *rcs, char *rev, FILE *fp)
+{
+ RCSVers *versp;
+ Node *p, *branch;
+
+ /* Previously, this function used a recursive implementation, but
+ if the trunk has a huge number of revisions and the program
+ stack is not big, a stack overflow could occur, so this
+ nonrecursive version was developed to be more safe. */
+ Node *branchlist, *onebranch;
+ List *branches;
+ List *onebranchlist;
+
+ if (rev == NULL)
+ return;
+
+ branches = getlist();
+
+ for (; rev != NULL;)
+ {
+ /* Find the delta node for this revision. */
+ p = findnode (rcs->versions, rev);
+ if (p == NULL)
+ {
+ error (1, 0,
+ "error parsing repository file %s, file may be corrupt.",
+ rcs->path);
+ }
+
+ versp = p->data;
+
+ /* Print the delta node and go for its `next' node. This
+ prints the trunk. If there are any branches printed on this
+ revision, mark we have some. */
+ putdelta (versp, fp);
+ /* Store branch information into branch list so to write its
+ trunk afterwards */
+ if (versp->branches != NULL)
+ {
+ branch = getnode();
+ branch->data = versp->branches;
+
+ addnode(branches, branch);
+ }
+
+ rev = versp->next;
+ }
+
+ /* If there are any branches printed on this revision,
+ print those trunks as well. */
+ branchlist = branches->list;
+ for (branch = branchlist->next;
+ branch != branchlist;
+ branch = branch->next)
+ {
+ onebranchlist = (List *)(branch->data);
+ onebranch = onebranchlist->list;
+ for (p = onebranch->next; p != onebranch; p = p->next)
+ RCS_putdtree (rcs, p->key, fp);
+
+ branch->data = NULL; /* so to prevent its freeing on dellist */
+ }
+
+ dellist(&branches);
+}
+
+
+
+static void
+RCS_putdesc (RCSNode *rcs, FILE *fp)
+{
+ fprintf (fp, "\n\n%s\n@", RCSDESC);
+ if (rcs->desc != NULL)
+ {
+ off_t len = (off_t) strlen (rcs->desc);
+ if (len > 0)
+ {
+ expand_at_signs (rcs->desc, len, fp);
+ if (rcs->desc[len-1] != '\n')
+ putc ('\n', fp);
+ }
+ }
+ fputs ("@\n", fp);
+}
+
+
+
+static void
+putdeltatext (FILE *fp, Deltatext *d)
+{
+ fprintf (fp, "\n\n%s\nlog\n@", d->version);
+ if (d->log != NULL)
+ {
+ int loglen = strlen (d->log);
+ expand_at_signs (d->log, (off_t) loglen, fp);
+ if (d->log[loglen-1] != '\n')
+ putc ('\n', fp);
+ }
+ putc ('@', fp);
+
+ walklist (d->other, putrcsfield_proc, fp);
+
+ fputs ("\ntext\n@", fp);
+ if (d->text != NULL)
+ expand_at_signs (d->text, (off_t) d->len, fp);
+ fputs ("@\n", fp);
+}
+
+
+
+/* TODO: the whole mechanism for updating deltas is kludgey... more
+ sensible would be to supply all the necessary info in a `newdeltatext'
+ field for RCSVers nodes. -twp */
+
+/* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it
+ is a new delta text node, and should be added to the tree at the
+ node whose revision number is INSERTPT. (Note that trunk nodes are
+ written in decreasing order, and branch nodes are written in
+ increasing order.) */
+static void
+RCS_copydeltas (RCSNode *rcs, FILE *fin, struct rcsbuffer *rcsbufin,
+ FILE *fout, Deltatext *newdtext, char *insertpt)
+{
+ int actions;
+ RCSVers *dadmin;
+ Node *np;
+ int insertbefore, found;
+ char *bufrest;
+ int nls;
+ size_t buflen;
+#ifndef HAVE_MMAP
+ char buf[8192];
+ int got;
+#endif
+
+ /* Count the number of versions for which we have to do some
+ special operation. */
+ actions = walklist (rcs->versions, count_delta_actions, NULL);
+
+ /* Make a note of whether NEWDTEXT should be inserted
+ before or after its INSERTPT. */
+ insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
+
+ while (actions != 0 || newdtext != NULL)
+ {
+ Deltatext *dtext;
+
+ dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
+
+ /* We shouldn't hit EOF here, because that would imply that
+ some action was not taken, or that we could not insert
+ NEWDTEXT. */
+ if (dtext == NULL)
+ error (1, 0, "internal error: EOF too early in RCS_copydeltas");
+
+ found = (insertpt != NULL && STREQ (dtext->version, insertpt));
+ if (found && insertbefore)
+ {
+ putdeltatext (fout, newdtext);
+ newdtext = NULL;
+ insertpt = NULL;
+ }
+
+ np = findnode (rcs->versions, dtext->version);
+ dadmin = np->data;
+
+ /* If this revision has been outdated, just skip it. */
+ if (dadmin->outdated)
+ {
+ freedeltatext (dtext);
+ --actions;
+ continue;
+ }
+
+ /* Update the change text for this delta. New change text
+ data may come from cvs admin -m, cvs admin -o, or cvs ci. */
+ if (dadmin->text != NULL)
+ {
+ if (dadmin->text->log != NULL || dadmin->text->text != NULL)
+ --actions;
+ if (dadmin->text->log != NULL)
+ {
+ free (dtext->log);
+ dtext->log = dadmin->text->log;
+ dadmin->text->log = NULL;
+ }
+ if (dadmin->text->text != NULL)
+ {
+ free (dtext->text);
+ dtext->text = dadmin->text->text;
+ dtext->len = dadmin->text->len;
+ dadmin->text->text = NULL;
+ }
+ }
+ putdeltatext (fout, dtext);
+ freedeltatext (dtext);
+
+ if (found && !insertbefore)
+ {
+ putdeltatext (fout, newdtext);
+ newdtext = NULL;
+ insertpt = NULL;
+ }
+ }
+
+ /* Copy the rest of the file directly, without bothering to
+ interpret it. The caller will handle error checking by calling
+ ferror.
+
+ We just wrote a newline to the file, either in putdeltatext or
+ in the caller. However, we may not have read the corresponding
+ newline from the file, because rcsbuf_getkey returns as soon as
+ it finds the end of the '@' string for the desc or text key.
+ Therefore, we may read three newlines when we should really
+ only write two, and we check for that case here. This is not
+ an semantically important issue; we only do it to make our RCS
+ files look traditional. */
+
+ nls = 3;
+
+ rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
+ if (buflen > 0)
+ {
+ if (bufrest[0] != '\n'
+ || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
+ {
+ nls = 0;
+ }
+ else
+ {
+ if (buflen < 3)
+ nls -= buflen;
+ else
+ {
+ ++bufrest;
+ --buflen;
+ nls = 0;
+ }
+ }
+
+ fwrite (bufrest, 1, buflen, fout);
+ }
+#ifndef HAVE_MMAP
+ /* This bit isn't necessary when using mmap since the entire file
+ * will already be available via the RCS buffer. Besides, the
+ * mmap code doesn't always keep the file pointer up to date, so
+ * this adds some data twice.
+ */
+ while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
+ {
+ if (nls > 0
+ && got >= nls
+ && buf[0] == '\n'
+ && strncmp (buf, "\n\n\n", nls) == 0)
+ {
+ fwrite (buf + 1, 1, got - 1, fout);
+ }
+ else
+ {
+ fwrite (buf, 1, got, fout);
+ }
+
+ nls = 0;
+ }
+#endif /* HAVE_MMAP */
+}
+
+
+
+/* A helper procedure for RCS_copydeltas. This is called via walklist
+ to count the number of RCS revisions for which some special action
+ is required. */
+static int
+count_delta_actions (Node *np, void *ignore)
+{
+ RCSVers *dadmin = np->data;
+
+ if (dadmin->outdated)
+ return 1;
+
+ if (dadmin->text != NULL
+ && (dadmin->text->log != NULL || dadmin->text->text != NULL))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Clean up temporary files.
+ *
+ * NOTES
+ * This function needs to be reentrant since a call to exit() can cause a
+ * call to this function, which can then be interrupted by a signal, which
+ * can cause a second call to this function.
+ *
+ * RETURNS
+ * Nothing.
+ */
+static void
+rcs_cleanup (void)
+{
+ TRACE (TRACE_FUNCTION, "rcs_cleanup()");
+
+ /* FIXME: Do not perform buffered I/O from an interrupt handler like
+ * this (via error). However, I'm leaving the error-calling code there
+ * in the hope that on the rare occasion the error call is actually made
+ * (e.g., a fluky I/O error or permissions problem prevents the deletion
+ * of a just-created file) reentrancy won't be an issue.
+ */
+
+ /* We don't want to be interrupted during calls which set globals to NULL,
+ * but we know that by the time we reach this function, interrupts have
+ * already been blocked.
+ */
+ if (rcs_lockfile != NULL)
+ {
+ /* Use a tmp var since any of these functions could call exit, causing
+ * us to be called a second time.
+ */
+ char *tmp = rcs_lockfile;
+ rcs_lockfile = NULL;
+ if (rcs_lockfd >= 0)
+ {
+ if (close (rcs_lockfd) != 0)
+ error (0, errno, "error closing lock file %s", tmp);
+ rcs_lockfd = -1;
+ }
+
+ /* Note that the checks for existence_error are because we can be
+ * called from a signal handler, so we don't know whether the
+ * files got created.
+ */
+ if (unlink_file (tmp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmp);
+ }
+}
+
+
+
+/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
+ locking on the specified RCSFILE: for a file called `foo,v', open
+ for writing a file called `,foo,'.
+
+ Note that we what do here is quite different from what RCS does.
+ RCS creates the ,foo, file before it reads the RCS file (if it
+ knows that it will be writing later), so that it actually serves as
+ a lock. We don't; instead we rely on CVS writelocks. This means
+ that if someone is running RCS on the file at the same time they
+ are running CVS on it, they might lose (we read the file,
+ then RCS writes it, then we write it, clobbering the
+ changes made by RCS). I believe the current sentiment about this
+ is "well, don't do that".
+
+ A concern has been expressed about whether adopting the RCS
+ strategy would slow us down. I don't think so, since we need to
+ write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
+ something).
+
+ These do not perform quite the same function as the RCS -l option
+ for locking files: they are intended to prevent competing RCS
+ processes from stomping all over each other's laundry. Hence,
+ they are `internal' locking functions.
+
+ If there is an error, give a fatal error; if we return we always
+ return a non-NULL value. */
+static FILE *
+rcs_internal_lockfile (char *rcsfile)
+{
+ struct stat rstat;
+ FILE *fp;
+ static int first_call = 1;
+
+ if (first_call)
+ {
+ first_call = 0;
+ /* Clean up if we get a signal or exit. */
+ cleanup_register (rcs_cleanup);
+ }
+
+ /* Get the lock file name: `,file,' for RCS file `file,v'. */
+ assert (rcs_lockfile == NULL);
+ assert (rcs_lockfd < 0);
+ rcs_lockfile = rcs_lockfilename (rcsfile);
+
+ /* Use the existing RCS file mode, or read-only if this is a new
+ file. (Really, this is a lie -- if this is a new file,
+ RCS_checkin uses the permissions from the working copy. For
+ actually creating the file, we use 0444 as a safe default mode.) */
+ if (stat (rcsfile, &rstat) < 0)
+ {
+ if (existence_error (errno))
+ rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
+ else
+ error (1, errno, "cannot stat %s", rcsfile);
+ }
+
+ /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT
+ guarantees an exclusive open. According to the RCS source, with
+ NFS v2 we must also throw in O_TRUNC and use an open mask that makes
+ the file unwriteable. For extensive justification, see the comments for
+ rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless
+ in the CVS case; see comment at the start of this file concerning
+ general ,foo, file strategy.
+
+ There is some sentiment that with NFSv3 and such, that one can
+ rely on O_EXCL these days. This might be true for unix (I
+ don't really know), but I am still pretty skeptical in the case
+ of the non-unix systems. */
+ rcs_lockfd = open (rcs_lockfile,
+ OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
+ S_IRUSR | S_IRGRP | S_IROTH);
+
+ if (rcs_lockfd < 0)
+ {
+ error (1, errno, "could not open lock file `%s'", rcs_lockfile);
+ }
+
+ /* Force the file permissions, and return a stream object. */
+ /* Because we change the modes later, we don't worry about
+ this in the non-HAVE_FCHMOD case. */
+#ifdef HAVE_FCHMOD
+ if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
+ error (1, errno, "cannot change mode for %s", rcs_lockfile);
+#endif
+ fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
+ if (fp == NULL)
+ error (1, errno, "cannot fdopen %s", rcs_lockfile);
+
+ return fp;
+}
+
+
+
+static void
+rcs_internal_unlockfile (FILE *fp, char *rcsfile)
+{
+ assert (rcs_lockfile != NULL);
+ assert (rcs_lockfd >= 0);
+
+ /* Abort if we could not write everything successfully to LOCKFILE.
+ This is not a great error-handling mechanism, but should prevent
+ corrupting the repository. */
+
+ if (ferror (fp))
+ /* Using errno here may well be misleanding since the most recent
+ call that set errno may not have anything whatsoever to do with
+ the error that set the flag, but it's better than nothing. The
+ real solution is to check each call to fprintf rather than waiting
+ until the end like this. */
+ error (1, errno, "error writing to lock file %s", rcs_lockfile);
+
+ /* Flush and sync the file, or the user may be told the commit completed,
+ * while a server crash/power failure could still cause the data to be
+ * lost.
+ *
+ * Invoking rename(",<file>," , "<file>,v") on Linux and almost all UNIXs
+ * only flushes the inode for the target file to disk, it does not
+ * guarantee flush of the kernel buffers allocated for the ,<file>,.
+ * Depending upon the load on the machine, the Linux kernel's flush daemon
+ * process may not flush for a while. In the meantime the CVS transaction
+ * could have been declared committed to the end CVS user (CVS process has
+ * returned the final "OK"). If the machine crashes prior to syncing the
+ * changes to disk, the committed transaction can be lost.
+ */
+ if (fflush (fp) != 0)
+ error (1, errno, "error flushing file `%s' to kernel buffers",
+ rcs_lockfile);
+#ifdef HAVE_FSYNC
+ if (fsync (rcs_lockfd) < 0)
+ error (1, errno, "error fsyncing file `%s'", rcs_lockfile);
+#endif
+
+ if (fclose (fp) == EOF)
+ error (1, errno, "error closing lock file %s", rcs_lockfile);
+ rcs_lockfd = -1;
+
+ rename_file (rcs_lockfile, rcsfile);
+
+ {
+ /* Use a temporary to make sure there's no interval
+ (after rcs_lockfile has been freed but before it's set to NULL)
+ during which the signal handler's use of rcs_lockfile would
+ reference freed memory. */
+ char *tmp = rcs_lockfile;
+ rcs_lockfile = NULL;
+ free (tmp);
+ }
+}
+
+
+
+static char *
+rcs_lockfilename (const char *rcsfile)
+{
+ char *lockfile, *lockp;
+ const char *rcsbase, *rcsp, *rcsend;
+ int rcslen;
+
+ /* Create the lockfile name. */
+ rcslen = strlen (rcsfile);
+ lockfile = xmalloc (rcslen + 10);
+ rcsbase = last_component (rcsfile);
+ rcsend = rcsfile + rcslen - sizeof(RCSEXT);
+ for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
+ *lockp++ = *rcsp;
+ *lockp++ = ',';
+ while (rcsp <= rcsend)
+ *lockp++ = *rcsp++;
+ *lockp++ = ',';
+ *lockp = '\0';
+
+ return lockfile;
+}
+
+
+
+/* Rewrite an RCS file. The basic idea here is that the caller should
+ first call RCS_reparsercsfile, then munge the data structures as
+ desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */
+void
+RCS_rewrite (RCSNode *rcs, Deltatext *newdtext, char *insertpt)
+{
+ FILE *fin, *fout;
+ struct rcsbuffer rcsbufin;
+
+ if (noexec)
+ return;
+
+ /* Make sure we're operating on an actual file and not a symlink. */
+ resolve_symlink (&(rcs->path));
+
+ fout = rcs_internal_lockfile (rcs->path);
+
+ RCS_putadmin (rcs, fout);
+ RCS_putdtree (rcs, rcs->head, fout);
+ RCS_putdesc (rcs, fout);
+
+ /* Open the original RCS file and seek to the first delta text. */
+ rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
+
+ /* Update delta_pos to the current position in the output file.
+ Do NOT move these statements: they must be done after fin has
+ been positioned at the old delta_pos, but before any delta
+ texts have been written to fout.
+ */
+ rcs->delta_pos = ftello (fout);
+ if (rcs->delta_pos == -1)
+ error (1, errno, "cannot ftello in RCS file %s", rcs->path);
+
+ RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
+
+ /* We don't want to call rcsbuf_cache here, since we're about to
+ delete the file. */
+ rcsbuf_close (&rcsbufin);
+ if (ferror (fin))
+ /* The only case in which using errno here would be meaningful
+ is if we happen to have left errno unmolested since the call
+ which produced the error (e.g. fread). That is pretty
+ fragile even if it happens to sometimes be true. The real
+ solution is to make sure that all the code which reads
+ from fin checks for errors itself (some does, some doesn't). */
+ error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
+ if (fclose (fin) < 0)
+ error (0, errno, "warning: closing RCS file `%s'", rcs->path);
+
+ rcs_internal_unlockfile (fout, rcs->path);
+}
+
+
+
+/* Abandon changes to an RCS file. */
+void
+RCS_abandon (RCSNode *rcs)
+{
+ free_rcsnode_contents (rcs);
+ rcs->symbols_data = NULL;
+ rcs->expand = NULL;
+ rcs->access = NULL;
+ rcs->locks_data = NULL;
+ rcs->comment = NULL;
+ rcs->desc = NULL;
+ rcs->flags |= PARTIAL;
+}
+
+
+
+/*
+ * For a given file with full pathname PATH and revision number REV,
+ * produce a file label suitable for passing to diff. The default
+ * file label as used by RCS 5.7 looks like this:
+ *
+ * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
+ *
+ * The date and time used are the revision's last checkin date and time.
+ * If REV is NULL, use the working copy's mtime instead.
+ *
+ * /dev/null is not statted but assumed to have been created on the Epoch.
+ * At least using the POSIX.2 definition of patch, this should cause creation
+ * of files on platforms such as Windoze where the null IO device isn't named
+ * /dev/null to be parsed by patch properly.
+ */
+char *
+make_file_label (const char *path, const char *rev, RCSNode *rcs)
+{
+ char datebuf[MAXDATELEN + 1];
+ char *label;
+
+ if (rev)
+ {
+ char date[MAXDATELEN + 1];
+ /* revs cannot be attached to /dev/null ... duh. */
+ assert (strcmp(DEVNULL, path));
+ RCS_getrevtime (rcs, rev, datebuf, 0);
+ (void) date_to_internet (date, datebuf);
+ label = Xasprintf ("-L%s\t%s\t%s", path, date, rev);
+ }
+ else
+ {
+ struct stat sb;
+ struct tm *wm;
+
+ if (strcmp(DEVNULL, path))
+ {
+ const char *file = last_component (path);
+ if (stat (file, &sb) < 0)
+ /* Assume that if the stat fails,then the later read for the
+ * diff will too.
+ */
+ error (1, errno, "could not get info for `%s'", path);
+ wm = gmtime (&sb.st_mtime);
+ }
+ else
+ {
+ time_t t = 0;
+ wm = gmtime(&t);
+ }
+
+ (void) tm_to_internet (datebuf, wm);
+ label = Xasprintf ("-L%s\t%s", path, datebuf);
+ }
+ return label;
+}
+
+
+
+/*
+ * Set up a local/custom RCS keyword for expansion.
+ *
+ * INPUTS
+ * infopath Path to file being parsed, for error messages.
+ * ln Line number of INFOPATH being processed, for error
+ * messages.
+ * keywords_in
+ * arg
+ *
+ * OUTPUTS
+ * keywords_in
+ */
+void
+RCS_setlocalid (const char *infopath, unsigned int ln,
+ void **keywords_in, const char *arg)
+{
+ char *copy, *next, *key, *s;
+ struct rcs_keyword *keywords;
+ enum keyword save_expandto;
+
+ if (!*keywords_in)
+ *keywords_in = new_keywords ();
+ keywords = *keywords_in;
+
+ copy = xstrdup (arg);
+ next = copy;
+ key = strtok (next, "=");
+
+ /*
+ * Validate key
+ */
+ for (s = key; *s != '\0'; s++)
+ {
+ if (! isalpha ((unsigned char) *s))
+ {
+ if (!parse_error (infopath, ln))
+ error (0, 0,
+"%s [%u]: LocalKeyword ignored: Bad character `%c' in key `%s'",
+ primary_root_inverse_translate (infopath),
+ ln, *s, key);
+ free (copy);
+ return;
+ }
+ }
+
+ save_expandto = keywords[KEYWORD_LOCALID].expandto;
+
+ /* options? */
+ while ((key = strtok (NULL, ",")) != NULL) {
+ if (!strcmp(key, keywords[KEYWORD_ID].string))
+ keywords[KEYWORD_LOCALID].expandto = KEYWORD_ID;
+ else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
+ keywords[KEYWORD_LOCALID].expandto = KEYWORD_HEADER;
+ else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
+ keywords[KEYWORD_LOCALID].expandto = KEYWORD_CVSHEADER;
+ else
+ {
+ keywords[KEYWORD_LOCALID].expandto = save_expandto;
+ if (!parse_error (infopath, ln))
+ error (0, 0,
+"%s [%u]: LocalKeyword ignored: Unknown LocalId mode: `%s'",
+ primary_root_inverse_translate (infopath),
+ ln, key);
+ free (copy);
+ return;
+ }
+ }
+
+ keywords[KEYWORD_LOCALID].string = xstrdup (next);
+ keywords[KEYWORD_LOCALID].len = strlen (next);
+ keywords[KEYWORD_LOCALID].expandit = 1;
+
+ free (copy);
+}
+
+
+
+void
+RCS_setincexc (void **keywords_in, const char *arg)
+{
+ char *key;
+ char *copy, *next;
+ bool include = false;
+ struct rcs_keyword *keyword;
+ struct rcs_keyword *keywords;
+
+ if (!*keywords_in)
+ *keywords_in = new_keywords ();
+ keywords = *keywords_in;
+
+ copy = xstrdup(arg);
+ next = copy;
+ switch (*next++) {
+ case 'e':
+ include = false;
+ break;
+ case 'i':
+ include = true;
+ break;
+ default:
+ free(copy);
+ return;
+ }
+
+ if (include)
+ for (keyword = keywords; keyword->string != NULL; keyword++)
+ {
+ keyword->expandit = false;
+ }
+
+ key = strtok(next, ",");
+ while (key) {
+ for (keyword = keywords; keyword->string != NULL; keyword++) {
+ if (strcmp (keyword->string, key) == 0)
+ keyword->expandit = include;
+ }
+ key = strtok(NULL, ",");
+ }
+ free(copy);
+ return;
+}
+
+
+
+#define ATTIC "/" CVSATTIC
+static char *
+getfullCVSname(char *CVSname, char **pathstore)
+{
+ if (current_parsed_root->directory) {
+ int rootlen;
+ char *c = NULL;
+ int alen = sizeof(ATTIC) - 1;
+
+ *pathstore = xstrdup(CVSname);
+ if ((c = strrchr(*pathstore, '/')) != NULL) {
+ if (c - *pathstore >= alen) {
+ if (!strncmp(c - alen, ATTIC, alen)) {
+ while (*c != '\0') {
+ *(c - alen) = *c;
+ c++;
+ }
+ *(c - alen) = '\0';
+ }
+ }
+ }
+
+ rootlen = strlen(current_parsed_root->directory);
+ if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
+ (*pathstore)[rootlen] == '/')
+ CVSname = (*pathstore + rootlen + 1);
+ else
+ CVSname = (*pathstore);
+ }
+ return CVSname;
+}
diff --git a/src/rcs.h b/src/rcs.h
new file mode 100644
index 0000000..2b82ed1
--- /dev/null
+++ b/src/rcs.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * RCS source control definitions needed by rcs.c and friends
+ */
+
+/* Strings which indicate a conflict if they occur at the start of a line. */
+#define RCS_MERGE_PAT_1 "<<<<<<< "
+#define RCS_MERGE_PAT_2 "=======\n"
+#define RCS_MERGE_PAT_3 ">>>>>>> "
+
+#define RCSEXT ",v"
+#define RCSPAT "*,v"
+#define RCSHEAD "head"
+#define RCSBRANCH "branch"
+#define RCSSYMBOLS "symbols"
+#define RCSDATE "date"
+#define RCSDESC "desc"
+#define RCSEXPAND "expand"
+
+/* Used by the version of death support which resulted from old
+ versions of CVS (e.g. 1.5 if you define DEATH_SUPPORT and not
+ DEATH_STATE). Only a hacked up RCS (used by those old versions of
+ CVS) will put this into RCS files. Considered obsolete. */
+#define RCSDEAD "dead"
+
+#define DATEFORM "%02d.%02d.%02d.%02d.%02d.%02d"
+#define SDATEFORM "%d.%d.%d.%d.%d.%d"
+
+/*
+ * Opaque structure definitions used by RCS specific lookup routines
+ */
+#define VALID 0x1 /* flags field contains valid data */
+#define INATTIC 0x2 /* RCS file is located in the Attic */
+#define PARTIAL 0x4 /* RCS file not completly parsed */
+
+/* All the "char *" fields in RCSNode, Deltatext, and RCSVers are
+ '\0'-terminated (except "text" in Deltatext). This means that we
+ can't deal with fields containing '\0', which is a limitation that
+ RCS does not have. Would be nice to fix this some day. */
+
+struct rcsnode
+{
+ /* Reference count for this structure. Used to deal with the
+ fact that there might be a pointer from the Vers_TS or might
+ not. Callers who increment this field are responsible for
+ calling freercsnode when they are done with their reference. */
+ int refcount;
+
+ /* Flags (INATTIC, PARTIAL, &c), see above. */
+ int flags;
+
+ /* File name of the RCS file. This is not necessarily the name
+ as specified by the user, but it is a name which can be passed to
+ system calls and a name which is OK to print in error messages
+ (the various names might differ in case). */
+ char *path;
+
+ /* Use when printing paths. */
+ char *print_path;
+
+ /* Value for head keyword from RCS header, or NULL if empty. HEAD may only
+ * be empty in a valid RCS file when the file has no revisions, a state
+ * that should not be able to occur with CVS.
+ */
+ char *head;
+
+ /* Value for branch keyword from RCS header, or NULL if omitted. */
+ char *branch;
+
+ /* Raw data on symbolic revisions. The first time that RCS_symbols is
+ called, we parse these into ->symbols, and free ->symbols_data. */
+ char *symbols_data;
+
+ /* Value for expand keyword from RCS header, or NULL if omitted. */
+ char *expand;
+
+ /* List of nodes, the key of which is the symbolic name and the data
+ of which is the numeric revision that it corresponds to (malloc'd). */
+ List *symbols;
+
+ /* List of nodes (type RCSVERS), the key of which the numeric revision
+ number, and the data of which is an RCSVers * for the revision. */
+ List *versions;
+
+ /* Value for access keyword from RCS header, or NULL if empty.
+ FIXME: RCS_delaccess would also seem to use "" for empty. We
+ should pick one or the other. */
+ char *access;
+
+ /* Raw data on locked revisions. The first time that RCS_getlocks is
+ called, we parse these into ->locks, and free ->locks_data. */
+ char *locks_data;
+
+ /* List of nodes, the key of which is the numeric revision and the
+ data of which is the user that it corresponds to (malloc'd). */
+ List *locks;
+
+ /* Set for the strict keyword from the RCS header. */
+ int strict_locks;
+
+ /* Value for the comment keyword from RCS header (comment leader), or
+ NULL if omitted. */
+ char *comment;
+
+ /* Value for the desc field in the RCS file, or NULL if empty. */
+ char *desc;
+
+ /* File offset of the first deltatext node, so we can seek there. */
+ off_t delta_pos;
+
+ /* Newphrases from the RCS header. List of nodes, the key of which
+ is the "id" which introduces the newphrase, and the value of which
+ is the value from the newphrase. */
+ List *other;
+};
+
+typedef struct rcsnode RCSNode;
+
+struct deltatext {
+ char *version;
+
+ /* Log message, or NULL if we do not intend to change the log message
+ (that is, RCS_copydeltas should just use the log message from the
+ file). */
+ char *log;
+
+ /* Change text, or NULL if we do not intend to change the change text
+ (that is, RCS_copydeltas should just use the change text from the
+ file). Note that it is perfectly valid to have log be NULL and
+ text non-NULL, or vice-versa. */
+ char *text;
+ size_t len;
+
+ /* Newphrase fields from deltatext nodes. FIXME: duplicates the
+ other field in the rcsversnode, I think. */
+ List *other;
+};
+typedef struct deltatext Deltatext;
+
+struct rcsversnode
+{
+ /* Duplicate of the key by which this structure is indexed. */
+ char *version;
+
+ char *date;
+ char *author;
+ char *state;
+ char *next;
+ int dead;
+ int outdated;
+ Deltatext *text;
+ List *branches;
+ /* Newphrase fields from deltatext nodes. Also contains ";add" and
+ ";delete" magic fields (see rcs.c, log.c). I think this is
+ only used by log.c (where it looks up "log"). Duplicates the
+ other field in struct deltatext, I think. */
+ List *other;
+ /* Newphrase fields from delta nodes. */
+ List *other_delta;
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Hard link information for each revision. */
+ List *hardlinks;
+#endif
+};
+typedef struct rcsversnode RCSVers;
+
+/*
+ * CVS reserves all even-numbered branches for its own use. "magic" branches
+ * (see rcs.c) are contained as virtual revision numbers (within symbolic
+ * tags only) off the RCS_MAGIC_BRANCH, which is 0. CVS also reserves the
+ * ".1" branch for vendor revisions. So, if you do your own branching, you
+ * should limit your use to odd branch numbers starting at 3.
+ */
+#define RCS_MAGIC_BRANCH 0
+
+/* The type of a function passed to RCS_checkout. */
+typedef void (*RCSCHECKOUTPROC) (void *, const char *, size_t);
+
+struct rcsbuffer;
+
+/* What RCS_deltas is supposed to do. */
+enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH};
+
+/*
+ * exported interfaces
+ */
+RCSNode *RCS_parse (const char *file, const char *repos);
+RCSNode *RCS_parsercsfile (const char *rcsfile);
+void RCS_fully_parse (RCSNode *);
+void RCS_reparsercsfile (RCSNode *, FILE **, struct rcsbuffer *);
+extern int RCS_setattic (RCSNode *, int);
+
+char *RCS_check_kflag (const char *arg);
+char *RCS_getdate (RCSNode * rcs, const char *date, int force_tag_match);
+char *RCS_gettag (RCSNode * rcs, const char *symtag, int force_tag_match,
+ int *simple_tag);
+int RCS_exist_rev (RCSNode *rcs, char *rev);
+int RCS_exist_tag (RCSNode *rcs, char *tag);
+char *RCS_tag2rev (RCSNode *rcs, char *tag);
+char *RCS_getversion (RCSNode *rcs, const char *tag, const char *date,
+ int force_tag_match, int *simple_tag);
+char *RCS_magicrev (RCSNode *rcs, char *rev);
+int RCS_isbranch (RCSNode *rcs, const char *rev);
+int RCS_nodeisbranch (RCSNode *rcs, const char *tag);
+char *RCS_whatbranch (RCSNode *rcs, const char *tag);
+char *RCS_head (RCSNode * rcs);
+int RCS_datecmp (const char *date1, const char *date2);
+time_t RCS_getrevtime (RCSNode * rcs, const char *rev, char *date, int fudge);
+List *RCS_symbols (RCSNode *rcs);
+void RCS_check_tag (const char *tag);
+int RCS_valid_rev (const char *rev);
+List *RCS_getlocks (RCSNode *rcs);
+void freercsnode (RCSNode ** rnodep);
+char *RCS_getbranch (RCSNode *rcs, const char *tag, int force_tag_match);
+char *RCS_branch_head (RCSNode *rcs, char *rev);
+
+int RCS_isdead (RCSNode *, const char *);
+char *RCS_getexpand (RCSNode *);
+void RCS_setexpand (RCSNode *, const char *);
+int RCS_checkout (RCSNode *, const char *, const char *, const char *,
+ const char *, const char *, RCSCHECKOUTPROC, void *);
+int RCS_checkin (RCSNode *rcs, const char *update_dir, const char *workfile,
+ const char *message, const char *rev, time_t citime,
+ int flags);
+int RCS_cmp_file (RCSNode *, const char *, char **, const char *, const char *,
+ const char * );
+int RCS_settag (RCSNode *, const char *, const char *);
+int RCS_deltag (RCSNode *, const char *);
+int RCS_setbranch (RCSNode *, const char *);
+int RCS_lock (RCSNode *, const char *, int);
+int RCS_unlock (RCSNode *, char *, int);
+int RCS_delete_revs (RCSNode *, char *, char *, int);
+void RCS_addaccess (RCSNode *, char *);
+void RCS_delaccess (RCSNode *, char *);
+char *RCS_getaccess (RCSNode *);
+void RCS_rewrite (RCSNode *, Deltatext *, char *);
+void RCS_abandon (RCSNode *);
+int rcs_change_text (const char *, char *, size_t, const char *,
+ size_t, char **, size_t *);
+void RCS_deltas (RCSNode *, FILE *, struct rcsbuffer *, const char *,
+ enum rcs_delta_op, char **, size_t *,
+ char **, size_t *);
+void RCS_setincexc (void **, const char *arg);
+void RCS_setlocalid (const char *, unsigned int, void **, const char *arg);
+char *make_file_label (const char *, const char *, RCSNode *);
+
+extern bool preserve_perms;
+
+/* From import.c. */
+extern int add_rcs_file (const char *, const char *, const char *,
+ const char *, const char *, const char *,
+ const char *, int, char **, const char *, size_t,
+ FILE *, bool);
+void free_keywords (void *keywords);
diff --git a/src/rcscmds.c b/src/rcscmds.c
new file mode 100644
index 0000000..3c2afb7
--- /dev/null
+++ b/src/rcscmds.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * The functions in this file provide an interface for performing
+ * operations directly on RCS files.
+ */
+
+#include "cvs.h"
+#include <stdio.h>
+#include "diffrun.h"
+#include "quotearg.h"
+
+/* This file, rcs.h, and rcs.c, together sometimes known as the "RCS
+ library", are intended to define our interface to RCS files.
+
+ Whether there will also be a version of RCS which uses this
+ library, or whether the library will be packaged for uses beyond
+ CVS or RCS (many people would like such a thing) is an open
+ question. Some considerations:
+
+ 1. An RCS library for CVS must have the capabilities of the
+ existing CVS code which accesses RCS files. In particular, simple
+ approaches will often be slow.
+
+ 2. An RCS library should not use code from the current RCS
+ (5.7 and its ancestors). The code has many problems. Too few
+ comments, too many layers of abstraction, too many global variables
+ (the correct number for a library is zero), too much intricately
+ interwoven functionality, and too many clever hacks. Paul Eggert,
+ the current RCS maintainer, agrees.
+
+ 3. More work needs to be done in terms of separating out the RCS
+ library from the rest of CVS (for example, cvs_output should be
+ replaced by a callback, and the declarations should be centralized
+ into rcs.h, and probably other such cleanups).
+
+ 4. To be useful for RCS and perhaps for other uses, the library
+ may need features beyond those needed by CVS.
+
+ 5. Any changes to the RCS file format *must* be compatible. Many,
+ many tools (not just CVS and RCS) can at least import this format.
+ RCS and CVS must preserve the current ability to import/export it
+ (preferably improved--magic branches are currently a roadblock).
+ See doc/RCSFILES in the CVS distribution for documentation of this
+ file format.
+
+ On a related note, see the comments at diff_exec, later in this file,
+ for more on the diff library. */
+
+static void RCS_output_diff_options (int, char * const *, const char *,
+ const char *, const char *);
+
+
+/* Stuff to deal with passing arguments the way libdiff.a wants to deal
+ with them. This is a crufty interface; there is no good reason for it
+ to resemble a command line rather than something closer to "struct
+ log_data" in log.c. */
+
+/* First call call_diff_setup to setup any initial arguments. The
+ argument will be parsed into whitespace separated words and added
+ to the global call_diff_argv list.
+
+ Then, optionally, call call_diff_add_arg for each additional argument
+ that you'd like to pass to the diff library.
+
+ Finally, call call_diff or call_diff3 to produce the diffs. */
+
+static char **call_diff_argv;
+static int call_diff_argc;
+static size_t call_diff_arg_allocated;
+
+static int call_diff (const char *out);
+static int call_diff3 (char *out);
+
+static void call_diff_write_output (const char *, size_t);
+static void call_diff_flush_output (void);
+static void call_diff_write_stdout (const char *);
+static void call_diff_error (const char *, const char *, const char *);
+
+
+
+/* VARARGS */
+static void
+call_diff_add_arg (const char *s)
+{
+ TRACE (TRACE_DATA, "call_diff_add_arg (%s)", s);
+ run_add_arg_p (&call_diff_argc, &call_diff_arg_allocated, &call_diff_argv,
+ s);
+}
+
+
+
+static void
+call_diff_setup (const char *prog, int argc, char * const *argv)
+{
+ int i;
+
+ /* clean out any malloc'ed values from call_diff_argv */
+ run_arg_free_p (call_diff_argc, call_diff_argv);
+ call_diff_argc = 0;
+
+ /* put each word into call_diff_argv, allocating it as we go */
+ call_diff_add_arg (prog);
+ for (i = 0; i < argc; i++)
+ call_diff_add_arg (argv[i]);
+}
+
+
+
+/* Callback function for the diff library to write data to the output
+ file. This is used when we are producing output to stdout. */
+
+static void
+call_diff_write_output (const char *text, size_t len)
+{
+ if (len > 0)
+ cvs_output (text, len);
+}
+
+/* Call back function for the diff library to flush the output file.
+ This is used when we are producing output to stdout. */
+
+static void
+call_diff_flush_output (void)
+{
+ cvs_flushout ();
+}
+
+/* Call back function for the diff library to write to stdout. */
+
+static void
+call_diff_write_stdout (const char *text)
+{
+ cvs_output (text, 0);
+}
+
+/* Call back function for the diff library to write to stderr. */
+
+static void
+call_diff_error (const char *format, const char *a1, const char *a2)
+{
+ /* FIXME: Should we somehow indicate that this error is coming from
+ the diff library? */
+ error (0, 0, format, a1, a2);
+}
+
+/* This set of callback functions is used if we are sending the diff
+ to stdout. */
+
+static struct diff_callbacks call_diff_stdout_callbacks =
+{
+ call_diff_write_output,
+ call_diff_flush_output,
+ call_diff_write_stdout,
+ call_diff_error
+};
+
+/* This set of callback functions is used if we are sending the diff
+ to a file. */
+
+static struct diff_callbacks call_diff_file_callbacks =
+{
+ NULL,
+ NULL,
+ call_diff_write_stdout,
+ call_diff_error
+};
+
+
+
+static int
+call_diff (const char *out)
+{
+ call_diff_add_arg (NULL);
+
+ if (out == RUN_TTY)
+ return diff_run( call_diff_argc, call_diff_argv, NULL,
+ &call_diff_stdout_callbacks );
+ else
+ return diff_run( call_diff_argc, call_diff_argv, out,
+ &call_diff_file_callbacks );
+}
+
+
+
+static int
+call_diff3 (char *out)
+{
+ if (out == RUN_TTY)
+ return diff3_run (call_diff_argc, call_diff_argv, NULL,
+ &call_diff_stdout_callbacks);
+ else
+ return diff3_run (call_diff_argc, call_diff_argv, out,
+ &call_diff_file_callbacks);
+}
+
+
+
+/* Merge revisions REV1 and REV2. */
+
+int
+RCS_merge (RCSNode *rcs, const char *path, const char *workfile,
+ const char *options, const char *rev1, const char *rev2)
+{
+ char *xrev1, *xrev2;
+ char *tmp1, *tmp2;
+ char *diffout = NULL;
+ int retval;
+
+ if (options != NULL && options[0] != '\0')
+ assert (options[0] == '-' && options[1] == 'k');
+
+ cvs_output ("RCS file: ", 0);
+ cvs_output (rcs->print_path, 0);
+ cvs_output ("\n", 1);
+
+ /* Calculate numeric revision numbers from rev1 and rev2 (may be
+ symbolic).
+ FIXME - No they can't. Both calls to RCS_merge are passing in
+ numeric revisions. */
+ xrev1 = RCS_gettag (rcs, rev1, 0, NULL);
+ xrev2 = RCS_gettag (rcs, rev2, 0, NULL);
+ assert (xrev1 && xrev2);
+
+ /* Check out chosen revisions. The error message when RCS_checkout
+ fails is not very informative -- it is taken verbatim from RCS 5.7,
+ and relies on RCS_checkout saying something intelligent upon failure. */
+ cvs_output ("retrieving revision ", 0);
+ cvs_output (xrev1, 0);
+ cvs_output ("\n", 1);
+
+ tmp1 = cvs_temp_name();
+ if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL))
+ {
+ cvs_outerr ("rcsmerge: co failed\n", 0);
+ exit (EXIT_FAILURE);
+ }
+
+ cvs_output ("retrieving revision ", 0);
+ cvs_output (xrev2, 0);
+ cvs_output ("\n", 1);
+
+ tmp2 = cvs_temp_name();
+ if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL))
+ {
+ cvs_outerr ("rcsmerge: co failed\n", 0);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Merge changes. */
+ cvs_output ("Merging differences between ", 0);
+ cvs_output (xrev1, 0);
+ cvs_output (" and ", 0);
+ cvs_output (xrev2, 0);
+ cvs_output (" into ", 0);
+ cvs_output (workfile, 0);
+ cvs_output ("\n", 1);
+
+ /* Remember that the first word in the `call_diff_setup' string is used now
+ only for diagnostic messages -- CVS no longer forks to run diff3. */
+ diffout = cvs_temp_name();
+ call_diff_setup ("diff3", 0, NULL);
+ call_diff_add_arg ("-E");
+ call_diff_add_arg ("-am");
+
+ call_diff_add_arg ("-L");
+ call_diff_add_arg (workfile);
+ call_diff_add_arg ("-L");
+ call_diff_add_arg (xrev1);
+ call_diff_add_arg ("-L");
+ call_diff_add_arg (xrev2);
+
+ call_diff_add_arg ("--");
+ call_diff_add_arg (workfile);
+ call_diff_add_arg (tmp1);
+ call_diff_add_arg (tmp2);
+
+ retval = call_diff3 (diffout);
+
+ if (retval == 1)
+ cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
+ else if (retval == 2)
+ exit (EXIT_FAILURE);
+
+ if (diffout)
+ copy_file (diffout, workfile);
+
+ /* Clean up. */
+ {
+ int save_noexec = noexec;
+ noexec = 0;
+ if (unlink_file (tmp1) < 0)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot remove temp file %s", tmp1);
+ }
+ free (tmp1);
+ if (unlink_file (tmp2) < 0)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot remove temp file %s", tmp2);
+ }
+ free (tmp2);
+ if (diffout)
+ {
+ if (unlink_file (diffout) < 0)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot remove temp file %s", diffout);
+ }
+ free (diffout);
+ }
+ free (xrev1);
+ free (xrev2);
+ noexec = save_noexec;
+ }
+
+ return retval;
+}
+
+/* Diff revisions and/or files. OPTS controls the format of the diff
+ (it contains options such as "-w -c", &c), or "" for the default.
+ OPTIONS controls keyword expansion, as a string starting with "-k",
+ or "" to use the default. REV1 is the first revision to compare
+ against; it must be non-NULL. If REV2 is non-NULL, compare REV1
+ and REV2; if REV2 is NULL compare REV1 with the file in the working
+ directory, whose name is WORKFILE. LABEL1 and LABEL2 are default
+ file labels, and (if non-NULL) should be added as -L options
+ to diff. Output goes to stdout.
+
+ Return value is 0 for success, -1 for a failure which set errno,
+ or positive for a failure which printed a message on stderr.
+
+ This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
+
+ An issue is what timezone is used for the dates which appear in the
+ diff output. rcsdiff uses the -z flag, which is not presently
+ processed by CVS diff, but I'm not sure exactly how hard to worry
+ about this--any such features are undocumented in the context of
+ CVS, and I'm not sure how important to users. */
+int
+RCS_exec_rcsdiff (RCSNode *rcsfile, int diff_argc,
+ char * const *diff_argv, const char *options,
+ const char *rev1, const char *rev1_cache, const char *rev2,
+ const char *label1, const char *label2, const char *workfile)
+{
+ char *tmpfile1 = NULL;
+ char *tmpfile2 = NULL;
+ const char *use_file1, *use_file2;
+ int status, retval;
+
+
+ cvs_output ("\
+===================================================================\n\
+RCS file: ", 0);
+ cvs_output (rcsfile->print_path, 0);
+ cvs_output ("\n", 1);
+
+ /* Historically, `cvs diff' has expanded the $Name keyword to the
+ empty string when checking out revisions. This is an accident,
+ but no one has considered the issue thoroughly enough to determine
+ what the best behavior is. Passing NULL for the `nametag' argument
+ preserves the existing behavior. */
+
+ cvs_output ("retrieving revision ", 0);
+ cvs_output (rev1, 0);
+ cvs_output ("\n", 1);
+
+ if (rev1_cache != NULL)
+ use_file1 = rev1_cache;
+ else
+ {
+ tmpfile1 = cvs_temp_name();
+ status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
+ NULL, NULL);
+ if (status > 0)
+ {
+ retval = status;
+ goto error_return;
+ }
+ else if (status < 0)
+ {
+ error( 0, errno,
+ "cannot check out revision %s of %s", rev1, rcsfile->path );
+ retval = 1;
+ goto error_return;
+ }
+ use_file1 = tmpfile1;
+ }
+
+ if (rev2 == NULL)
+ {
+ assert (workfile != NULL);
+ use_file2 = workfile;
+ }
+ else
+ {
+ tmpfile2 = cvs_temp_name ();
+ cvs_output ("retrieving revision ", 0);
+ cvs_output (rev2, 0);
+ cvs_output ("\n", 1);
+ status = RCS_checkout (rcsfile, NULL, rev2, NULL, options,
+ tmpfile2, NULL, NULL);
+ if (status > 0)
+ {
+ retval = status;
+ goto error_return;
+ }
+ else if (status < 0)
+ {
+ error (0, errno,
+ "cannot check out revision %s of %s", rev2, rcsfile->path);
+ return 1;
+ }
+ use_file2 = tmpfile2;
+ }
+
+ RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile);
+ status = diff_exec (use_file1, use_file2, label1, label2,
+ diff_argc, diff_argv, RUN_TTY);
+ if (status >= 0)
+ {
+ retval = status;
+ goto error_return;
+ }
+ else if (status < 0)
+ {
+ error (0, errno,
+ "cannot diff %s and %s", use_file1, use_file2);
+ retval = 1;
+ goto error_return;
+ }
+
+ error_return:
+ {
+ /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
+ * for noexec.
+ */
+ if( tmpfile1 != NULL )
+ {
+ if( CVS_UNLINK( tmpfile1 ) < 0 )
+ {
+ if( !existence_error( errno ) )
+ error( 0, errno, "cannot remove temp file %s", tmpfile1 );
+ }
+ free( tmpfile1 );
+ }
+ if( tmpfile2 != NULL )
+ {
+ if( CVS_UNLINK( tmpfile2 ) < 0 )
+ {
+ if( !existence_error( errno ) )
+ error( 0, errno, "cannot remove temp file %s", tmpfile2 );
+ }
+ free (tmpfile2);
+ }
+ }
+
+ return retval;
+}
+
+
+
+/* Show differences between two files. This is the start of a diff library.
+
+ Some issues:
+
+ * Should option parsing be part of the library or the caller? The
+ former allows the library to add options without changing the callers,
+ but it causes various problems. One is that something like --brief really
+ wants special handling in CVS, and probably the caller should retain
+ some flexibility in this area. Another is online help (the library could
+ have some feature for providing help, but how does that interact with
+ the help provided by the caller directly?). Another is that as things
+ stand currently, there is no separate namespace for diff options versus
+ "cvs diff" options like -l (that is, if the library adds an option which
+ conflicts with a CVS option, it is trouble).
+
+ * This isn't required for a first-cut diff library, but if there
+ would be a way for the caller to specify the timestamps that appear
+ in the diffs (rather than the library getting them from the files),
+ that would clean up the kludgy utime() calls in patch.c.
+
+ Show differences between FILE1 and FILE2. Either one can be
+ DEVNULL to indicate a nonexistent file (same as an empty file
+ currently, I suspect, but that may be an issue in and of itself).
+ OPTIONS is a list of diff options, or "" if none. At a minimum,
+ CVS expects that -c (update.c, patch.c) and -n (update.c) will be
+ supported. Other options, like -u, --speed-large-files, &c, will
+ be specified if the user specified them.
+
+ OUT is a filename to send the diffs to, or RUN_TTY to send them to
+ stdout. Error messages go to stderr. Return value is 0 for
+ success, -1 for a failure which set errno, 1 for success (and some
+ differences were found), or >1 for a failure which printed a
+ message on stderr. */
+
+int
+diff_exec (const char *file1, const char *file2, const char *label1,
+ const char *label2, int dargc, char * const *dargv,
+ const char *out)
+{
+ TRACE (TRACE_FUNCTION, "diff_exec (%s, %s, %s, %s, %s)",
+ file1, file2, label1, label2, out);
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* If either file1 or file2 are special files, pretend they are
+ /dev/null. Reason: suppose a file that represents a block
+ special device in one revision becomes a regular file. CVS
+ must find the `difference' between these files, but a special
+ file contains no data useful for calculating this metric. The
+ safe thing to do is to treat the special file as an empty file,
+ thus recording the regular file's full contents. Doing so will
+ create extremely large deltas at the point of transition
+ between device files and regular files, but this is probably
+ very rare anyway.
+
+ There may be ways around this, but I think they are fraught
+ with danger. -twp */
+
+ if (preserve_perms &&
+ strcmp (file1, DEVNULL) != 0 &&
+ strcmp (file2, DEVNULL) != 0)
+ {
+ struct stat sb1, sb2;
+
+ if (lstat (file1, &sb1) < 0)
+ error (1, errno, "cannot get file information for %s", file1);
+ if (lstat (file2, &sb2) < 0)
+ error (1, errno, "cannot get file information for %s", file2);
+
+ if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
+ file1 = DEVNULL;
+ if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
+ file2 = DEVNULL;
+ }
+#endif
+
+ /* The first arg to call_diff_setup is used only for error reporting. */
+ call_diff_setup ("diff", dargc, dargv);
+ if (label1)
+ call_diff_add_arg (label1);
+ if (label2)
+ call_diff_add_arg (label2);
+ call_diff_add_arg ("--");
+ call_diff_add_arg (file1);
+ call_diff_add_arg (file2);
+
+ return call_diff (out);
+}
+
+/* Print the options passed to DIFF, in the format used by rcsdiff.
+ The rcsdiff code that produces this output is extremely hairy, and
+ it is not clear how rcsdiff decides which options to print and
+ which not to print. The code below reproduces every rcsdiff run
+ that I have seen. */
+
+static void
+RCS_output_diff_options (int diff_argc, char * const *diff_argv,
+ const char *rev1, const char *rev2,
+ const char *workfile)
+{
+ int i;
+
+ cvs_output ("diff", 0);
+ for (i = 0; i < diff_argc; i++)
+ {
+ cvs_output (" ", 1);
+ cvs_output (quotearg_style (shell_quoting_style, diff_argv[i]), 0);
+ }
+ cvs_output (" -r", 3);
+ cvs_output (rev1, 0);
+
+ if (rev2)
+ {
+ cvs_output (" -r", 3);
+ cvs_output (rev2, 0);
+ }
+ else
+ {
+ assert (workfile != NULL);
+ cvs_output (" ", 1);
+ cvs_output (workfile, 0);
+ }
+ cvs_output ("\n", 1);
+}
diff --git a/src/recurse.c b/src/recurse.c
new file mode 100644
index 0000000..ef80138
--- /dev/null
+++ b/src/recurse.c
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * General recursion handler
+ *
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+#include "fileattr.h"
+#include "edit.h"
+
+static int do_dir_proc (Node * p, void *closure);
+static int do_file_proc (Node * p, void *closure);
+static void addlist (List ** listp, char *key);
+static int unroll_files_proc (Node *p, void *closure);
+static void addfile (List **listp, char *dir, char *file);
+
+static char *update_dir;
+static char *repository = NULL;
+static List *filelist = NULL; /* holds list of files on which to operate */
+static List *dirlist = NULL; /* holds list of directories on which to operate */
+
+struct recursion_frame {
+ FILEPROC fileproc;
+ FILESDONEPROC filesdoneproc;
+ DIRENTPROC direntproc;
+ DIRLEAVEPROC dirleaveproc;
+ void *callerdat;
+ Dtype flags;
+ int which;
+ int aflag;
+ int locktype;
+ int dosrcs;
+ char *repository; /* Keep track of repository for rtag */
+};
+
+static int do_recursion (struct recursion_frame *frame);
+
+/* I am half tempted to shove a struct file_info * into the struct
+ recursion_frame (but then we would need to modify or create a
+ recursion_frame for each file), or shove a struct recursion_frame *
+ into the struct file_info (more tempting, although it isn't completely
+ clear that the struct file_info should contain info about recursion
+ processor internals). So instead use this struct. */
+
+struct frame_and_file {
+ struct recursion_frame *frame;
+ struct file_info *finfo;
+};
+
+/* Similarly, we need to pass the entries list to do_dir_proc. */
+
+struct frame_and_entries {
+ struct recursion_frame *frame;
+ List *entries;
+};
+
+
+/* Start a recursive command.
+ *
+ * INPUT
+ *
+ * fileproc
+ * Function called with each file as an argument.
+ *
+ * filesdoneproc
+ * Function called after all the files in a directory have been processed,
+ * before subdirectories have been processed.
+ *
+ * direntproc
+ * Function called immediately upon entering a directory, before processing
+ * any files or subdirectories.
+ *
+ * dirleaveproc
+ * Function called upon finishing a directory, immediately before leaving
+ * it and returning control to the function processing the parent
+ * directory.
+ *
+ * callerdat
+ * This void * is passed to the functions above.
+ *
+ * argc, argv
+ * The files on which to operate, interpreted as command line arguments.
+ * In the special case of no arguments, defaults to operating on the
+ * current directory (`.').
+ *
+ * local
+ *
+ * which
+ * specifies the kind of recursion. There are several cases:
+ *
+ * 1. W_LOCAL is not set but W_REPOS or W_ATTIC is. The current
+ * directory when we are called must be the repository and
+ * recursion proceeds according to what exists in the repository.
+ *
+ * 2a. W_LOCAL is set but W_REPOS and W_ATTIC are not. The
+ * current directory when we are called must be the working
+ * directory. Recursion proceeds according to what exists in the
+ * working directory, never (I think) consulting any part of the
+ * repository which does not correspond to the working directory
+ * ("correspond" == Name_Repository).
+ *
+ * 2b. W_LOCAL is set and so is W_REPOS or W_ATTIC. This is the
+ * weird one. The current directory when we are called must be
+ * the working directory. We recurse through working directories,
+ * but we recurse into a directory if it is exists in the working
+ * directory *or* it exists in the repository. If a directory
+ * does not exist in the working directory, the direntproc must
+ * either tell us to skip it (R_SKIP_ALL), or must create it (I
+ * think those are the only two cases).
+ *
+ * aflag
+ * locktype
+ * update_preload
+ * dosrcs
+ *
+ * repository_in
+ * keeps track of the repository string. This is only for the remote mode,
+ * specifically, r* commands (rtag, rdiff, co, ...) where xgetcwd() was used
+ * to locate the repository. Things would break when xgetcwd() was used
+ * with a symlinked repository because xgetcwd() would return the true path
+ * and in some cases this would cause the path to be printed as other than
+ * the user specified in error messages and in other cases some of CVS's
+ * security assertions would fail.
+ *
+ * GLOBALS
+ * ???
+ *
+ * OUTPUT
+ *
+ * callerdat can be modified by the FILEPROC, FILESDONEPROC, DIRENTPROC, and
+ * DIRLEAVEPROC.
+ *
+ * RETURNS
+ * A count of errors counted by walking the argument list with
+ * unroll_files_proc() and do_recursion().
+ *
+ * ERRORS
+ * Fatal errors occur:
+ * 1. when there were no arguments and the current directory
+ * does not contain CVS metadata.
+ * 2. when all but the last path element from an argument from ARGV cannot
+ * be found to be a local directory.
+ */
+int
+start_recursion (FILEPROC fileproc, FILESDONEPROC filesdoneproc,
+ DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc,
+ void *callerdat, int argc, char **argv, int local,
+ int which, int aflag, int locktype,
+ char *update_preload, int dosrcs, char *repository_in)
+{
+ int i, err = 0;
+#ifdef CLIENT_SUPPORT
+ List *args_to_send_when_finished = NULL;
+#endif
+ List *files_by_dir = NULL;
+ struct recursion_frame frame;
+
+#ifdef HAVE_PRINTF_PTR
+ TRACE ( TRACE_FLOW,
+ "start_recursion ( fileproc=%p, filesdoneproc=%p,\n"
+ " direntproc=%p, dirleavproc=%p,\n"
+ " callerdat=%p, argc=%d, argv=%p,\n"
+ " local=%d, which=%d, aflag=%d,\n"
+ " locktype=%d, update_preload=%s\n"
+ " dosrcs=%d, repository_in=%s )",
+ (void *) fileproc, (void *) filesdoneproc,
+ (void *) direntproc, (void *) dirleaveproc,
+ (void *) callerdat, argc, (void *) argv,
+ local, which, aflag, locktype,
+ update_preload ? update_preload : "(null)", dosrcs,
+ repository_in ? repository_in : "(null)");
+#else
+ TRACE ( TRACE_FLOW,
+ "start_recursion ( fileproc=%lx, filesdoneproc=%lx,\n"
+ " direntproc=%lx, dirleavproc=%lx,\n"
+ " callerdat=%lx, argc=%d, argv=%lx,\n"
+ " local=%d, which=%d, aflag=%d,\n"
+ " locktype=%d, update_preload=%s\n"
+ " dosrcs=%d, repository_in=%s )",
+ (unsigned long) fileproc, (unsigned long) filesdoneproc,
+ (unsigned long) direntproc, (unsigned long) dirleaveproc,
+ (unsigned long) callerdat, argc, (unsigned long) argv,
+ local, which, aflag, locktype,
+ update_preload ? update_preload : "(null)", dosrcs,
+ repository_in ? repository_in : "(null)");
+#endif
+
+ frame.fileproc = fileproc;
+ frame.filesdoneproc = filesdoneproc;
+ frame.direntproc = direntproc;
+ frame.dirleaveproc = dirleaveproc;
+ frame.callerdat = callerdat;
+ frame.flags = local ? R_SKIP_DIRS : R_PROCESS;
+ frame.which = which;
+ frame.aflag = aflag;
+ frame.locktype = locktype;
+ frame.dosrcs = dosrcs;
+
+ /* If our repository_in has a trailing "/.", remove it before storing it
+ * for do_recursion().
+ *
+ * FIXME: This is somewhat of a hack in the sense that many of our callers
+ * painstakingly compute and add the trailing '.' we now remove.
+ */
+ while (repository_in && strlen (repository_in) >= 2
+ && repository_in[strlen (repository_in) - 2] == '/'
+ && repository_in[strlen (repository_in) - 1] == '.')
+ {
+ /* Beware the case where the string is exactly "/." or "//.".
+ * Paths with a leading "//" are special on some early UNIXes.
+ */
+ if (strlen (repository_in) == 2 || strlen (repository_in) == 3)
+ repository_in[strlen (repository_in) - 1] = '\0';
+ else
+ repository_in[strlen (repository_in) - 2] = '\0';
+ }
+ frame.repository = repository_in;
+
+ expand_wild (argc, argv, &argc, &argv);
+
+ if (update_preload == NULL)
+ update_dir = xstrdup ("");
+ else
+ update_dir = xstrdup (update_preload);
+
+ /* clean up from any previous calls to start_recursion */
+ if (repository)
+ {
+ free (repository);
+ repository = NULL;
+ }
+ if (filelist)
+ dellist (&filelist); /* FIXME-krp: no longer correct. */
+ if (dirlist)
+ dellist (&dirlist);
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ for (i = 0; i < argc; ++i)
+ server_pathname_check (argv[i]);
+ }
+#endif
+
+ if (argc == 0)
+ {
+ int just_subdirs = (which & W_LOCAL) && !isdir (CVSADM);
+
+#ifdef CLIENT_SUPPORT
+ if (!just_subdirs
+ && CVSroot_cmdline == NULL
+ && current_parsed_root->isremote)
+ {
+ cvsroot_t *root = Name_Root (NULL, update_dir);
+ if (root)
+ {
+ if (strcmp (root->original, original_parsed_root->original))
+ /* We're skipping this directory because it is for
+ * a different root. Therefore, we just want to
+ * do the subdirectories only. Processing files would
+ * cause a working directory from one repository to be
+ * processed against a different repository, which could
+ * cause all kinds of spurious conflicts and such.
+ *
+ * Question: what about the case of "cvs update foo"
+ * where we process foo/bar and not foo itself? That
+ * seems to be handled somewhere (else) but why should
+ * it be a separate case? Needs investigation... */
+ just_subdirs = 1;
+ }
+ }
+#endif
+
+ /*
+ * There were no arguments, so we'll probably just recurse. The
+ * exception to the rule is when we are called from a directory
+ * without any CVS administration files. That has always meant to
+ * process each of the sub-directories, so we pretend like we were
+ * called with the list of sub-dirs of the current dir as args
+ */
+ if (just_subdirs)
+ {
+ dirlist = Find_Directories (NULL, W_LOCAL, NULL);
+ /* If there are no sub-directories, there is a certain logic in
+ favor of doing nothing, but in fact probably the user is just
+ confused about what directory they are in, or whether they
+ cvs add'd a new directory. In the case of at least one
+ sub-directory, at least when we recurse into them we
+ notice (hopefully) whether they are under CVS control. */
+ if (list_isempty (dirlist))
+ {
+ if (update_dir[0] == '\0')
+ error (0, 0, "in directory .:");
+ else
+ error (0, 0, "in directory %s:", update_dir);
+ error (1, 0,
+ "there is no version here; run '%s checkout' first",
+ program_name);
+ }
+#ifdef CLIENT_SUPPORT
+ else if (current_parsed_root->isremote && server_started)
+ {
+ /* In the the case "cvs update foo bar baz", a call to
+ send_file_names in update.c will have sent the
+ appropriate "Argument" commands to the server. In
+ this case, that won't have happened, so we need to
+ do it here. While this example uses "update", this
+ generalizes to other commands. */
+
+ /* This is the same call to Find_Directories as above.
+ FIXME: perhaps it would be better to write a
+ function that duplicates a list. */
+ args_to_send_when_finished = Find_Directories (NULL,
+ W_LOCAL,
+ NULL);
+ }
+#endif
+ }
+ else
+ addlist (&dirlist, ".");
+
+ goto do_the_work;
+ }
+
+
+ /*
+ * There were arguments, so we have to handle them by hand. To do
+ * that, we set up the filelist and dirlist with the arguments and
+ * call do_recursion. do_recursion recognizes the fact that the
+ * lists are non-null when it starts and doesn't update them.
+ *
+ * explicitly named directories are stored in dirlist.
+ * explicitly named files are stored in filelist.
+ * other possibility is named entities whicha are not currently in
+ * the working directory.
+ */
+
+ for (i = 0; i < argc; i++)
+ {
+ /* if this argument is a directory, then add it to the list of
+ directories. */
+
+ if (!wrap_name_has (argv[i], WRAP_TOCVS) && isdir (argv[i]))
+ {
+ strip_trailing_slashes (argv[i]);
+ addlist (&dirlist, argv[i]);
+ }
+ else
+ {
+ /* otherwise, split argument into directory and component names. */
+ char *dir;
+ char *comp;
+ char *file_to_try;
+
+ /* Now break out argv[i] into directory part (DIR) and file part
+ * (COMP). DIR and COMP will each point to a newly malloc'd
+ * string.
+ */
+ dir = xstrdup (argv[i]);
+ /* It's okay to cast out last_component's const below since we know
+ * we just allocated dir here and have control of it.
+ */
+ comp = (char *)last_component (dir);
+ if (comp == dir)
+ {
+ /* no dir component. What we have is an implied "./" */
+ dir = xstrdup(".");
+ }
+ else
+ {
+ comp[-1] = '\0';
+ comp = xstrdup (comp);
+ }
+
+ /* if this argument exists as a file in the current
+ working directory tree, then add it to the files list. */
+
+ if (!(which & W_LOCAL))
+ {
+ /* If doing rtag, we've done a chdir to the repository. */
+ file_to_try = Xasprintf ("%s%s", argv[i], RCSEXT);
+ }
+ else
+ file_to_try = xstrdup (argv[i]);
+
+ if (isfile (file_to_try))
+ addfile (&files_by_dir, dir, comp);
+ else if (isdir (dir))
+ {
+ if ((which & W_LOCAL) && isdir (CVSADM) &&
+ !current_parsed_root->isremote)
+ {
+ /* otherwise, look for it in the repository. */
+ char *tmp_update_dir;
+ char *repos;
+ char *reposfile;
+
+ tmp_update_dir = xmalloc (strlen (update_dir)
+ + strlen (dir)
+ + 5);
+ strcpy (tmp_update_dir, update_dir);
+
+ if (*tmp_update_dir != '\0')
+ strcat (tmp_update_dir, "/");
+
+ strcat (tmp_update_dir, dir);
+
+ /* look for it in the repository. */
+ repos = Name_Repository (dir, tmp_update_dir);
+ reposfile = Xasprintf ("%s/%s", repos, comp);
+ free (repos);
+
+ if (!wrap_name_has (comp, WRAP_TOCVS) && isdir (reposfile))
+ addlist (&dirlist, argv[i]);
+ else
+ addfile (&files_by_dir, dir, comp);
+
+ free (tmp_update_dir);
+ free (reposfile);
+ }
+ else
+ addfile (&files_by_dir, dir, comp);
+ }
+ else
+ error (1, 0, "no such directory `%s'", dir);
+
+ free (file_to_try);
+ free (dir);
+ free (comp);
+ }
+ }
+
+ /* At this point we have looped over all named arguments and built
+ a coupla lists. Now we unroll the lists, setting up and
+ calling do_recursion. */
+
+ err += walklist (files_by_dir, unroll_files_proc, (void *) &frame);
+ dellist(&files_by_dir);
+
+ /* then do_recursion on the dirlist. */
+ if (dirlist != NULL)
+ {
+ do_the_work:
+ err += do_recursion (&frame);
+ }
+
+ /* Free the data which expand_wild allocated. */
+ free_names (&argc, argv);
+
+ free (update_dir);
+ update_dir = NULL;
+
+#ifdef CLIENT_SUPPORT
+ if (args_to_send_when_finished != NULL)
+ {
+ /* FIXME (njc): in the multiroot case, we don't want to send
+ argument commands for those top-level directories which do
+ not contain any subdirectories which have files checked out
+ from current_parsed_root. If we do, and two repositories
+ have a module with the same name, nasty things could happen.
+
+ This is hard. Perhaps we should send the Argument commands
+ later in this procedure, after we've had a chance to notice
+ which directores we're using (after do_recursion has been
+ called once). This means a _lot_ of rewriting, however.
+
+ What we need to do for that to happen is descend the tree
+ and construct a list of directories which are checked out
+ from current_cvsroot. Now, we eliminate from the list all
+ of those directories which are immediate subdirectories of
+ another directory in the list. To say that the opposite
+ way, we keep the directories which are not immediate
+ subdirectories of any other in the list. Here's a picture:
+
+ a
+ / \
+ B C
+ / \
+ D e
+ / \
+ F G
+ / \
+ H I
+
+ The node in capitals are those directories which are
+ checked out from current_cvsroot. We want the list to
+ contain B, C, F, and G. D, H, and I are not included,
+ because their parents are also checked out from
+ current_cvsroot.
+
+ The algorithm should be:
+
+ 1) construct a tree of all directory names where each
+ element contains a directory name and a flag which notes if
+ that directory is checked out from current_cvsroot
+
+ a0
+ / \
+ B1 C1
+ / \
+ D1 e0
+ / \
+ F1 G1
+ / \
+ H1 I1
+
+ 2) Recursively descend the tree. For each node, recurse
+ before processing the node. If the flag is zero, do
+ nothing. If the flag is 1, check the node's parent. If
+ the parent's flag is one, change the current entry's flag
+ to zero.
+
+ a0
+ / \
+ B1 C1
+ / \
+ D0 e0
+ / \
+ F1 G1
+ / \
+ H0 I0
+
+ 3) Walk the tree and spit out "Argument" commands to tell
+ the server which directories to munge.
+
+ Yuck. It's not clear this is worth spending time on, since
+ we might want to disable cvs commands entirely from
+ directories that do not have CVSADM files...
+
+ Anyways, the solution as it stands has modified server.c
+ (dirswitch) to create admin files [via server.c
+ (create_adm_p)] in all path elements for a client's
+ "Directory xxx" command, which forces the server to descend
+ and serve the files there. client.c (send_file_names) has
+ also been modified to send only those arguments which are
+ appropriate to current_parsed_root.
+
+ */
+
+ /* Construct a fake argc/argv pair. */
+
+ int our_argc = 0, i;
+ char **our_argv = NULL;
+
+ if (! list_isempty (args_to_send_when_finished))
+ {
+ Node *head, *p;
+
+ head = args_to_send_when_finished->list;
+
+ /* count the number of nodes */
+ i = 0;
+ for (p = head->next; p != head; p = p->next)
+ i++;
+ our_argc = i;
+
+ /* create the argument vector */
+ our_argv = xmalloc (sizeof (char *) * our_argc);
+
+ /* populate it */
+ i = 0;
+ for (p = head->next; p != head; p = p->next)
+ our_argv[i++] = xstrdup (p->key);
+ }
+
+ /* We don't want to expand widcards, since we've just created
+ a list of directories directly from the filesystem. */
+ send_file_names (our_argc, our_argv, 0);
+
+ /* Free our argc/argv. */
+ if (our_argv != NULL)
+ {
+ for (i = 0; i < our_argc; i++)
+ free (our_argv[i]);
+ free (our_argv);
+ }
+
+ dellist (&args_to_send_when_finished);
+ }
+#endif
+
+ return err;
+}
+
+
+
+/*
+ * Implement the recursive policies on the local directory. This may be
+ * called directly, or may be called by start_recursion.
+ */
+static int
+do_recursion (struct recursion_frame *frame)
+{
+ int err = 0;
+ int dodoneproc = 1;
+ char *srepository = NULL;
+ List *entries = NULL;
+ int locktype;
+ bool process_this_directory = true;
+
+#ifdef HAVE_PRINT_PTR
+ TRACE (TRACE_FLOW, "do_recursion ( frame=%p )", (void *) frame);
+#else
+ TRACE (TRACE_FLOW, "do_recursion ( frame=%lx )", (unsigned long) frame);
+#endif
+
+ /* do nothing if told */
+ if (frame->flags == R_SKIP_ALL)
+ return 0;
+
+ locktype = noexec ? CVS_LOCK_NONE : frame->locktype;
+
+ /* The fact that locks are not active here is what makes us fail to have
+ the
+
+ If someone commits some changes in one cvs command,
+ then an update by someone else will either get all the
+ changes, or none of them.
+
+ property (see node Concurrency in cvs.texinfo).
+
+ The most straightforward fix would just to readlock the whole
+ tree before starting an update, but that means that if a commit
+ gets blocked on a big update, it might need to wait a *long*
+ time.
+
+ A more adequate fix would be a two-pass design for update,
+ checkout, etc. The first pass would go through the repository,
+ with the whole tree readlocked, noting what versions of each
+ file we want to get. The second pass would release all locks
+ (except perhaps short-term locks on one file at a
+ time--although I think RCS already deals with this) and
+ actually get the files, specifying the particular versions it wants.
+
+ This could be sped up by separating out the data needed for the
+ first pass into a separate file(s)--for example a file
+ attribute for each file whose value contains the head revision
+ for each branch. The structure should be designed so that
+ commit can relatively quickly update the information for a
+ single file or a handful of files (file attributes, as
+ implemented in Jan 96, are probably acceptable; improvements
+ would be possible such as branch attributes which are in
+ separate files for each branch). */
+
+#if defined(SERVER_SUPPORT) && defined(SERVER_FLOWCONTROL)
+ /*
+ * Now would be a good time to check to see if we need to stop
+ * generating data, to give the buffers a chance to drain to the
+ * remote client. We should not have locks active at this point,
+ * but if there are writelocks around, we cannot pause here. */
+ if (server_active && locktype != CVS_LOCK_WRITE)
+ server_pause_check();
+#endif
+
+ /* Check the value in CVSADM_ROOT and see if it's in the list. If
+ not, add it to our lists of CVS/Root directories and do not
+ process the files in this directory. Otherwise, continue as
+ usual. THIS_ROOT might be NULL if we're doing an initial
+ checkout -- check before using it. The default should be that
+ we process a directory's contents and only skip those contents
+ if a CVS/Root file exists.
+
+ If we're running the server, we want to process all
+ directories, since we're guaranteed to have only one CVSROOT --
+ our own. */
+
+ /* If -d was specified, it should override CVS/Root.
+
+ In the single-repository case, it is long-standing CVS behavior
+ and makes sense - the user might want another access method,
+ another server (which mounts the same repository), &c.
+
+ In the multiple-repository case, -d overrides all CVS/Root
+ files. That is the only plausible generalization I can
+ think of. */
+ if (CVSroot_cmdline == NULL && !server_active)
+ {
+ cvsroot_t *this_root = Name_Root (NULL, update_dir);
+ if (this_root != NULL)
+ {
+ if (findnode (root_directories, this_root->original))
+ {
+ process_this_directory =
+ !strcmp (original_parsed_root->original,
+ this_root->original);
+ }
+ else
+ {
+ /* Add it to our list. */
+
+ Node *n = getnode ();
+ n->type = NT_UNKNOWN;
+ n->key = xstrdup (this_root->original);
+ n->data = this_root;
+
+ if (addnode (root_directories, n))
+ error (1, 0, "cannot add new CVSROOT %s",
+ this_root->original);
+
+ process_this_directory = false;
+ }
+ }
+ }
+
+ /*
+ * Fill in repository with the current repository
+ */
+ if (frame->which & W_LOCAL)
+ {
+ if (isdir (CVSADM))
+ {
+ repository = Name_Repository (NULL, update_dir);
+ srepository = repository; /* remember what to free */
+ }
+ else
+ repository = NULL;
+ }
+ else
+ {
+ repository = frame->repository;
+ assert (repository != NULL);
+ assert (strstr (repository, "/./") == NULL);
+ }
+
+ fileattr_startdir (repository);
+
+ /*
+ * The filesdoneproc needs to be called for each directory where files
+ * processed, or each directory that is processed by a call where no
+ * directories were passed in. In fact, the only time we don't want to
+ * call back the filesdoneproc is when we are processing directories that
+ * were passed in on the command line (or in the special case of `.' when
+ * we were called with no args
+ */
+ if (dirlist != NULL && filelist == NULL)
+ dodoneproc = 0;
+
+ /*
+ * If filelist or dirlist is already set, we don't look again. Otherwise,
+ * find the files and directories
+ */
+ if (filelist == NULL && dirlist == NULL)
+ {
+ /* both lists were NULL, so start from scratch */
+ if (frame->fileproc != NULL && frame->flags != R_SKIP_FILES)
+ {
+ int lwhich = frame->which;
+
+ /* be sure to look in the attic if we have sticky tags/date */
+ if ((lwhich & W_ATTIC) == 0)
+ if (isreadable (CVSADM_TAG))
+ lwhich |= W_ATTIC;
+
+ /* In the !(which & W_LOCAL) case, we filled in repository
+ earlier in the function. In the (which & W_LOCAL) case,
+ the Find_Names function is going to look through the
+ Entries file. If we do not have a repository, that
+ does not make sense, so we insist upon having a
+ repository at this point. Name_Repository will give a
+ reasonable error message. */
+ if (repository == NULL)
+ {
+ Name_Repository (NULL, update_dir);
+ assert (!"Not reached. Please report this problem to <"
+ PACKAGE_BUGREPORT ">");
+ }
+ /* find the files and fill in entries if appropriate */
+ if (process_this_directory)
+ {
+ filelist = Find_Names (repository, lwhich, frame->aflag,
+ &entries);
+ if (filelist == NULL)
+ {
+ error (0, 0, "skipping directory %s", update_dir);
+ /* Note that Find_Directories and the filesdoneproc
+ in particular would do bad things ("? foo.c" in
+ the case of some filesdoneproc's). */
+ goto skip_directory;
+ }
+ }
+ }
+
+ /* find sub-directories if we will recurse */
+ if (frame->flags != R_SKIP_DIRS)
+ dirlist = Find_Directories (
+ process_this_directory ? repository : NULL,
+ frame->which, entries);
+ }
+ else
+ {
+ /* something was passed on the command line */
+ if (filelist != NULL && frame->fileproc != NULL)
+ {
+ /* we will process files, so pre-parse entries */
+ if (frame->which & W_LOCAL)
+ entries = Entries_Open (frame->aflag, NULL);
+ }
+ }
+
+ /* process the files (if any) */
+ if (process_this_directory && filelist != NULL && frame->fileproc)
+ {
+ struct file_info finfo_struct;
+ struct frame_and_file frfile;
+
+ /* Lock the repository, if necessary. */
+ if (repository)
+ {
+ if (locktype == CVS_LOCK_READ)
+ {
+ if (Reader_Lock (repository) != 0)
+ error (1, 0, "read lock failed - giving up");
+ }
+ else if (locktype == CVS_LOCK_WRITE)
+ lock_dir_for_write (repository);
+ }
+
+#ifdef CLIENT_SUPPORT
+ /* For the server, we handle notifications in a completely different
+ place (server_notify). For local, we can't do them here--we don't
+ have writelocks in place, and there is no way to get writelocks
+ here. */
+ if (current_parsed_root->isremote)
+ notify_check (repository, update_dir);
+#endif /* CLIENT_SUPPORT */
+
+ finfo_struct.repository = repository;
+ finfo_struct.update_dir = update_dir;
+ finfo_struct.entries = entries;
+ /* do_file_proc will fill in finfo_struct.file. */
+
+ frfile.finfo = &finfo_struct;
+ frfile.frame = frame;
+
+ /* process the files */
+ err += walklist (filelist, do_file_proc, &frfile);
+
+ /* unlock it */
+ if (/* We only lock the repository above when repository is set */
+ repository
+ /* and when asked for a read or write lock. */
+ && locktype != CVS_LOCK_NONE)
+ Simple_Lock_Cleanup ();
+
+ /* clean up */
+ dellist (&filelist);
+ }
+
+ /* call-back files done proc (if any) */
+ if (process_this_directory && dodoneproc && frame->filesdoneproc != NULL)
+ err = frame->filesdoneproc (frame->callerdat, err, repository,
+ update_dir[0] ? update_dir : ".",
+ entries);
+
+ skip_directory:
+ fileattr_write ();
+ fileattr_free ();
+
+ /* process the directories (if necessary) */
+ if (dirlist != NULL)
+ {
+ struct frame_and_entries frent;
+
+ frent.frame = frame;
+ frent.entries = entries;
+ err += walklist (dirlist, do_dir_proc, &frent);
+ }
+#if 0
+ else if (frame->dirleaveproc != NULL)
+ err += frame->dirleaveproc (frame->callerdat, ".", err, ".");
+#endif
+ dellist (&dirlist);
+
+ if (entries)
+ {
+ Entries_Close (entries);
+ entries = NULL;
+ }
+
+ /* free the saved copy of the pointer if necessary */
+ if (srepository)
+ free (srepository);
+ repository = NULL;
+
+#ifdef HAVE_PRINT_PTR
+ TRACE (TRACE_FLOW, "Leaving do_recursion (frame=%p)", (void *)frame);
+#else
+ TRACE (TRACE_FLOW, "Leaving do_recursion (frame=%lx)",
+ (unsigned long)frame);
+#endif
+
+ return err;
+}
+
+
+
+/*
+ * Process each of the files in the list with the callback proc
+ *
+ * NOTES
+ * Fills in FINFO->fullname, and sometimes FINFO->rcs before
+ * calling the callback proc (FRFILE->frame->fileproc), but frees them
+ * before return.
+ *
+ * OUTPUTS
+ * Fills in FINFO->file.
+ *
+ * RETURNS
+ * 0 if we were supposed to find an RCS file but couldn't.
+ * Otherwise, returns the error code returned by the callback function.
+ */
+static int
+do_file_proc (Node *p, void *closure)
+{
+ struct frame_and_file *frfile = closure;
+ struct file_info *finfo = frfile->finfo;
+ int ret;
+ char *tmp;
+
+ finfo->file = p->key;
+ if (finfo->update_dir[0] != '\0')
+ tmp = Xasprintf ("%s/%s", finfo->update_dir, finfo->file);
+ else
+ tmp = xstrdup (finfo->file);
+
+ if (frfile->frame->dosrcs && repository)
+ {
+ finfo->rcs = RCS_parse (finfo->file, repository);
+
+ /* OK, without W_LOCAL the error handling becomes relatively
+ simple. The file names came from readdir() on the
+ repository and so we know any ENOENT is an error
+ (e.g. symlink pointing to nothing). Now, the logic could
+ be simpler - since we got the name from readdir, we could
+ just be calling RCS_parsercsfile. */
+ if (finfo->rcs == NULL
+ && !(frfile->frame->which & W_LOCAL))
+ {
+ error (0, 0, "could not read RCS file for %s", tmp);
+ free (tmp);
+ cvs_flushout ();
+ return 0;
+ }
+ }
+ else
+ finfo->rcs = NULL;
+ finfo->fullname = tmp;
+ ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo);
+
+ freercsnode (&finfo->rcs);
+ free (tmp);
+
+ /* Allow the user to monitor progress with tail -f. Doing this once
+ per file should be no big deal, but we don't want the performance
+ hit of flushing on every line like previous versions of CVS. */
+ cvs_flushout ();
+
+ return ret;
+}
+
+
+
+/*
+ * Process each of the directories in the list (recursing as we go)
+ */
+static int
+do_dir_proc (Node *p, void *closure)
+{
+ struct frame_and_entries *frent = (struct frame_and_entries *) closure;
+ struct recursion_frame *frame = frent->frame;
+ struct recursion_frame xframe;
+ char *dir = p->key;
+ char *newrepos;
+ List *sdirlist;
+ char *srepository;
+ Dtype dir_return = R_PROCESS;
+ int stripped_dot = 0;
+ int err = 0;
+ struct saved_cwd cwd;
+ char *saved_update_dir;
+ bool process_this_directory = true;
+
+ if (fncmp (dir, CVSADM) == 0)
+ {
+ /* This seems to most often happen when users (beginning users,
+ generally), try "cvs ci *" or something similar. On that
+ theory, it is possible that we should just silently skip the
+ CVSADM directories, but on the other hand, using a wildcard
+ like this isn't necessarily a practice to encourage (it operates
+ only on files which exist in the working directory, unlike
+ regular CVS recursion). */
+
+ /* FIXME-reentrancy: printed_cvs_msg should be in a "command
+ struct" or some such, so that it gets cleared for each new
+ command (this is possible using the remote protocol and a
+ custom-written client). The struct recursion_frame is not
+ far back enough though, some commands (commit at least)
+ will call start_recursion several times. An alternate solution
+ would be to take this whole check and move it to a new function
+ validate_arguments or some such that all the commands call
+ and which snips the offending directory from the argc,argv
+ vector. */
+ static int printed_cvs_msg = 0;
+ if (!printed_cvs_msg)
+ {
+ error (0, 0, "warning: directory %s specified in argument",
+ dir);
+ error (0, 0, "\
+but CVS uses %s for its own purposes; skipping %s directory",
+ CVSADM, dir);
+ printed_cvs_msg = 1;
+ }
+ return 0;
+ }
+
+ saved_update_dir = update_dir;
+ update_dir = xmalloc (strlen (saved_update_dir)
+ + strlen (dir)
+ + 5);
+ strcpy (update_dir, saved_update_dir);
+
+ /* set up update_dir - skip dots if not at start */
+ if (strcmp (dir, ".") != 0)
+ {
+ if (update_dir[0] != '\0')
+ {
+ (void) strcat (update_dir, "/");
+ (void) strcat (update_dir, dir);
+ }
+ else
+ (void) strcpy (update_dir, dir);
+
+ /*
+ * Here we need a plausible repository name for the sub-directory. We
+ * create one by concatenating the new directory name onto the
+ * previous repository name. The only case where the name should be
+ * used is in the case where we are creating a new sub-directory for
+ * update -d and in that case the generated name will be correct.
+ */
+ if (repository == NULL)
+ newrepos = xstrdup ("");
+ else
+ newrepos = Xasprintf ("%s/%s", repository, dir);
+ }
+ else
+ {
+ if (update_dir[0] == '\0')
+ (void) strcpy (update_dir, dir);
+
+ if (repository == NULL)
+ newrepos = xstrdup ("");
+ else
+ newrepos = xstrdup (repository);
+ }
+
+ /* Check to see that the CVSADM directory, if it exists, seems to be
+ well-formed. It can be missing files if the user hit ^C in the
+ middle of a previous run. We want to (a) make this a nonfatal
+ error, and (b) make sure we print which directory has the
+ problem.
+
+ Do this before the direntproc, so that (1) the direntproc
+ doesn't have to guess/deduce whether we will skip the directory
+ (e.g. send_dirent_proc and whether to send the directory), and
+ (2) so that the warm fuzzy doesn't get printed if we skip the
+ directory. */
+ if (frame->which & W_LOCAL)
+ {
+ char *cvsadmdir;
+
+ cvsadmdir = xmalloc (strlen (dir)
+ + sizeof (CVSADM_REP)
+ + sizeof (CVSADM_ENT)
+ + 80);
+
+ strcpy (cvsadmdir, dir);
+ strcat (cvsadmdir, "/");
+ strcat (cvsadmdir, CVSADM);
+ if (isdir (cvsadmdir))
+ {
+ strcpy (cvsadmdir, dir);
+ strcat (cvsadmdir, "/");
+ strcat (cvsadmdir, CVSADM_REP);
+ if (!isfile (cvsadmdir))
+ {
+ /* Some commands like update may have printed "? foo" but
+ if we were planning to recurse, and don't on account of
+ CVS/Repository, we want to say why. */
+ error (0, 0, "ignoring %s (%s missing)", update_dir,
+ CVSADM_REP);
+ dir_return = R_SKIP_ALL;
+ }
+
+ /* Likewise for CVS/Entries. */
+ if (dir_return != R_SKIP_ALL)
+ {
+ strcpy (cvsadmdir, dir);
+ strcat (cvsadmdir, "/");
+ strcat (cvsadmdir, CVSADM_ENT);
+ if (!isfile (cvsadmdir))
+ {
+ /* Some commands like update may have printed "? foo" but
+ if we were planning to recurse, and don't on account of
+ CVS/Repository, we want to say why. */
+ error (0, 0, "ignoring %s (%s missing)", update_dir,
+ CVSADM_ENT);
+ dir_return = R_SKIP_ALL;
+ }
+ }
+ }
+ free (cvsadmdir);
+ }
+
+ /* Only process this directory if the root matches. This nearly
+ duplicates code in do_recursion. */
+
+ /* If -d was specified, it should override CVS/Root.
+
+ In the single-repository case, it is long-standing CVS behavior
+ and makes sense - the user might want another access method,
+ another server (which mounts the same repository), &c.
+
+ In the multiple-repository case, -d overrides all CVS/Root
+ files. That is the only plausible generalization I can
+ think of. */
+ if (CVSroot_cmdline == NULL && !server_active)
+ {
+ cvsroot_t *this_root = Name_Root (dir, update_dir);
+ if (this_root != NULL)
+ {
+ if (findnode (root_directories, this_root->original))
+ {
+ process_this_directory =
+ !strcmp (original_parsed_root->original,
+ this_root->original);
+ }
+ else
+ {
+ /* Add it to our list. */
+
+ Node *n = getnode ();
+ n->type = NT_UNKNOWN;
+ n->key = xstrdup (this_root->original);
+ n->data = this_root;
+
+ if (addnode (root_directories, n))
+ error (1, 0, "cannot add new CVSROOT %s",
+ this_root->original);
+
+ process_this_directory = false;
+ }
+ }
+ }
+
+ /* call-back dir entry proc (if any) */
+ if (dir_return == R_SKIP_ALL)
+ ;
+ else if (frame->direntproc != NULL)
+ {
+ /* If we're doing the actual processing, call direntproc.
+ Otherwise, assume that we need to process this directory
+ and recurse. FIXME. */
+
+ if (process_this_directory)
+ dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
+ update_dir, frent->entries);
+ else
+ dir_return = R_PROCESS;
+ }
+ else
+ {
+ /* Generic behavior. I don't see a reason to make the caller specify
+ a direntproc just to get this. */
+ if ((frame->which & W_LOCAL) && !isdir (dir))
+ dir_return = R_SKIP_ALL;
+ }
+
+ free (newrepos);
+
+ /* only process the dir if the return code was 0 */
+ if (dir_return != R_SKIP_ALL)
+ {
+ /* save our current directory and static vars */
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+ sdirlist = dirlist;
+ srepository = repository;
+ dirlist = NULL;
+
+ /* cd to the sub-directory */
+ if (CVS_CHDIR (dir) < 0)
+ error (1, errno, "could not chdir to %s", dir);
+
+ /* honor the global SKIP_DIRS (a.k.a. local) */
+ if (frame->flags == R_SKIP_DIRS)
+ dir_return = R_SKIP_DIRS;
+
+ /* remember if the `.' will be stripped for subsequent dirs */
+ if (strcmp (update_dir, ".") == 0)
+ {
+ update_dir[0] = '\0';
+ stripped_dot = 1;
+ }
+
+ /* make the recursive call */
+ xframe = *frame;
+ xframe.flags = dir_return;
+ /* Keep track of repository, really just for r* commands (rtag, rdiff,
+ * co, ...) to tag_check_valid, since all the other commands use
+ * CVS/Repository to figure it out per directory.
+ */
+ if (repository)
+ {
+ if (strcmp (dir, ".") == 0)
+ xframe.repository = xstrdup (repository);
+ else
+ xframe.repository = Xasprintf ("%s/%s", repository, dir);
+ }
+ else
+ xframe.repository = NULL;
+ err += do_recursion (&xframe);
+ if (xframe.repository)
+ {
+ free (xframe.repository);
+ xframe.repository = NULL;
+ }
+
+ /* put the `.' back if necessary */
+ if (stripped_dot)
+ (void) strcpy (update_dir, ".");
+
+ /* call-back dir leave proc (if any) */
+ if (process_this_directory && frame->dirleaveproc != NULL)
+ err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir,
+ frent->entries);
+
+ /* get back to where we started and restore state vars */
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+ dirlist = sdirlist;
+ repository = srepository;
+ }
+
+ free (update_dir);
+ update_dir = saved_update_dir;
+
+ return err;
+}
+
+/*
+ * Add a node to a list allocating the list if necessary.
+ */
+static void
+addlist (List **listp, char *key)
+{
+ Node *p;
+
+ if (*listp == NULL)
+ *listp = getlist ();
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (key);
+ if (addnode (*listp, p) != 0)
+ freenode (p);
+}
+
+static void
+addfile (List **listp, char *dir, char *file)
+{
+ Node *n;
+ List *fl;
+
+ /* add this dir. */
+ addlist (listp, dir);
+
+ n = findnode (*listp, dir);
+ if (n == NULL)
+ {
+ error (1, 0, "can't find recently added dir node `%s' in start_recursion.",
+ dir);
+ }
+
+ n->type = DIRS;
+ fl = n->data;
+ addlist (&fl, file);
+ n->data = fl;
+ return;
+}
+
+static int
+unroll_files_proc (Node *p, void *closure)
+{
+ Node *n;
+ struct recursion_frame *frame = (struct recursion_frame *) closure;
+ int err = 0;
+ List *save_dirlist;
+ char *save_update_dir = NULL;
+ struct saved_cwd cwd;
+
+ /* if this dir was also an explicitly named argument, then skip
+ it. We'll catch it later when we do dirs. */
+ n = findnode (dirlist, p->key);
+ if (n != NULL)
+ return (0);
+
+ /* otherwise, call dorecusion for this list of files. */
+ filelist = p->data;
+ p->data = NULL;
+ save_dirlist = dirlist;
+ dirlist = NULL;
+
+ if (strcmp(p->key, ".") != 0)
+ {
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+ if ( CVS_CHDIR (p->key) < 0)
+ error (1, errno, "could not chdir to %s", p->key);
+
+ save_update_dir = update_dir;
+ update_dir = xmalloc (strlen (save_update_dir)
+ + strlen (p->key)
+ + 5);
+ strcpy (update_dir, save_update_dir);
+
+ if (*update_dir != '\0')
+ (void) strcat (update_dir, "/");
+
+ (void) strcat (update_dir, p->key);
+ }
+
+ err += do_recursion (frame);
+
+ if (save_update_dir != NULL)
+ {
+ free (update_dir);
+ update_dir = save_update_dir;
+
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+ }
+
+ dirlist = save_dirlist;
+ if (filelist)
+ dellist (&filelist);
+ return(err);
+}
+/* vim:tabstop=8:shiftwidth=4
+ */
diff --git a/src/release.c b/src/release.c
new file mode 100644
index 0000000..4400d6c
--- /dev/null
+++ b/src/release.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Release: "cancel" a checkout in the history log.
+ *
+ * - Enter a line in the history log indicating the "release". - If asked to,
+ * delete the local working directory.
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+#include "getline.h"
+#include "yesno.h"
+
+static const char *const release_usage[] =
+{
+ "Usage: %s %s [-d] directories...\n",
+ "\t-d\tDelete the given directory.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+#ifdef SERVER_SUPPORT
+static int release_server (int argc, char **argv);
+
+/* This is the server side of cvs release. */
+static int
+release_server (int argc, char **argv)
+{
+ int i;
+
+ /* Note that we skip argv[0]. */
+ for (i = 1; i < argc; ++i)
+ history_write ('F', argv[i], "", argv[i], "");
+ return 0;
+}
+
+#endif /* SERVER_SUPPORT */
+
+/* Construct an update command. Be sure to add authentication and
+* encryption if we are using them currently, else our child process may
+* not be able to communicate with the server.
+*/
+static FILE *
+setup_update_command (pid_t *child_pid)
+{
+ int tofd, fromfd;
+
+ run_setup (program_path);
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ /* Be sure to add authentication and encryption if we are using them
+ * currently, else our child process may not be able to communicate with
+ * the server.
+ */
+ if (cvsauthenticate) run_add_arg ("-a");
+ if (cvsencrypt) run_add_arg ("-x");
+#endif
+
+ /* Don't really change anything. */
+ run_add_arg ("-n");
+
+ /* Don't need full verbosity. */
+ run_add_arg ("-q");
+
+ /* Propogate our CVSROOT. */
+ run_add_arg ("-d");
+ run_add_arg (original_parsed_root->original);
+
+ run_add_arg ("update");
+ *child_pid = run_piped (&tofd, &fromfd);
+ if (*child_pid < 0)
+ error (1, 0, "could not fork server process");
+
+ close (tofd);
+
+ return fdopen (fromfd, "r");
+}
+
+
+
+static int
+close_update_command (FILE *fp, pid_t child_pid)
+{
+ int status;
+ pid_t w;
+
+ do
+ w = waitpid (child_pid, &status, 0);
+ while (w == -1 && errno == EINTR);
+ if (w == -1)
+ error (1, errno, "waiting for process %d", child_pid);
+
+ return status;
+}
+
+
+
+/* There are various things to improve about this implementation:
+
+ 1. Using run_popen to run "cvs update" could be replaced by a
+ fairly simple start_recursion/classify_file loop--a win for
+ portability, performance, and cleanliness. In particular, there is
+ no particularly good way to find the right "cvs".
+
+ 2. The fact that "cvs update" contacts the server slows things down;
+ it undermines the case for using "cvs release" rather than "rm -rf".
+ However, for correctly printing "? foo" and correctly handling
+ CVSROOTADM_IGNORE, we currently need to contact the server. (One
+ idea for how to fix this is to stash a copy of CVSROOTADM_IGNORE in
+ the working directories; see comment at base_* in entries.c for a
+ few thoughts on that).
+
+ 3. Would be nice to take processing things on the client side one step
+ further, and making it like edit/unedit in terms of working well if
+ disconnected from the network, and then sending a delayed
+ notification.
+
+ 4. Having separate network turnarounds for the "Notify" request
+ which we do as part of unedit, and for the "release" itself, is slow
+ and unnecessary. */
+
+int
+release (int argc, char **argv)
+{
+ FILE *fp;
+ int i, c;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ char *thisarg;
+ int arg_start_idx;
+ int err = 0;
+ short delete_flag = 0;
+ struct saved_cwd cwd;
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ return release_server (argc, argv);
+#endif
+
+ /* Everything from here on is client or local. */
+ if (argc == -1)
+ usage (release_usage);
+ optind = 0;
+ while ((c = getopt (argc, argv, "+Qdq")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ cvs_cmd_name);
+ break;
+ case 'd':
+ delete_flag++;
+ break;
+ case '?':
+ default:
+ usage (release_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* We're going to run "cvs -n -q update" and check its output; if
+ * the output is sufficiently unalarming, then we release with no
+ * questions asked. Else we prompt, then maybe release.
+ * (Well, actually we ask no matter what. Our notion of "sufficiently
+ * unalarming" doesn't take into account "? foo.c" files, so it is
+ * up to the user to take note of them, at least currently
+ * (ignore-193 in testsuite)).
+ */
+
+#ifdef CLIENT_SUPPORT
+ /* Start the server; we'll close it after looping. */
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+ ign_setup ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ /* Remember the directory where "cvs release" was invoked because
+ all args are relative to this directory and we chdir around.
+ */
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+
+ arg_start_idx = 0;
+
+ for (i = arg_start_idx; i < argc; i++)
+ {
+ thisarg = argv[i];
+
+ if (isdir (thisarg))
+ {
+ if (CVS_CHDIR (thisarg) < 0)
+ {
+ if (!really_quiet)
+ error (0, errno, "can't chdir to: %s", thisarg);
+ continue;
+ }
+ if (!isdir (CVSADM))
+ {
+ if (!really_quiet)
+ error (0, 0, "no repository directory: %s", thisarg);
+ if (restore_cwd (&cwd))
+ error (1, errno,
+ "Failed to restore current directory, `%s'.",
+ cwd.name);
+ continue;
+ }
+ }
+ else
+ {
+ if (!really_quiet)
+ error (0, 0, "no such directory: %s", thisarg);
+ continue;
+ }
+
+ if (!really_quiet)
+ {
+ int line_length, status;
+ pid_t child_pid;
+
+ /* The "release" command piggybacks on "update", which
+ does the real work of finding out if anything is not
+ up-to-date with the repository. Then "release" prompts
+ the user, telling her how many files have been
+ modified, and asking if she still wants to do the
+ release. */
+ fp = setup_update_command (&child_pid);
+ if (fp == NULL)
+ {
+ error (0, 0, "cannot run command:");
+ run_print (stderr);
+ error (1, 0, "Exiting due to fatal error referenced above.");
+ }
+
+ c = 0;
+
+ while ((line_length = getline (&line, &line_allocated, fp)) >= 0)
+ {
+ if (strchr ("MARCZ", *line))
+ c++;
+ (void) fputs (line, stdout);
+ }
+ if (line_length < 0 && !feof (fp))
+ error (0, errno, "cannot read from subprocess");
+
+ /* If the update exited with an error, then we just want to
+ complain and go on to the next arg. Especially, we do
+ not want to delete the local copy, since it's obviously
+ not what the user thinks it is. */
+ status = close_update_command (fp, child_pid);
+ if (status != 0)
+ {
+ error (0, 0, "unable to release `%s' (%d)", thisarg, status);
+ if (restore_cwd (&cwd))
+ error (1, errno,
+ "Failed to restore current directory, `%s'.",
+ cwd.name);
+ continue;
+ }
+
+ printf ("You have [%d] altered files in this repository.\n",
+ c);
+
+ if (!noexec)
+ {
+ printf ("Are you sure you want to release %sdirectory `%s': ",
+ delete_flag ? "(and delete) " : "", thisarg);
+ fflush (stderr);
+ fflush (stdout);
+ if (!yesno ()) /* "No" */
+ {
+ (void) fprintf (stderr,
+ "** `%s' aborted by user choice.\n",
+ cvs_cmd_name);
+ if (restore_cwd (&cwd))
+ error (1, errno,
+ "Failed to restore current directory, `%s'.",
+ cwd.name);
+ continue;
+ }
+ }
+ else
+ {
+ if (restore_cwd (&cwd))
+ error (1, errno,
+ "Failed to restore current directory, `%s'.",
+ cwd.name);
+ continue;
+ }
+ }
+
+ /* Note: client.c doesn't like to have other code
+ changing the current directory on it. So a fair amount
+ of effort is needed to make sure it doesn't get confused
+ about the directory and (for example) overwrite
+ CVS/Entries file in the wrong directory. See release-17
+ through release-23. */
+
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+
+#ifdef CLIENT_SUPPORT
+ if (!current_parsed_root->isremote
+ || (supported_request ("noop") && supported_request ("Notify")))
+#endif
+ {
+ int argc = 2;
+ char *argv[3];
+ argv[0] = "dummy";
+ argv[1] = thisarg;
+ argv[2] = NULL;
+ err += unedit (argc, argv);
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ send_to_server ("Argument ", 0);
+ send_to_server (thisarg, 0);
+ send_to_server ("\012", 1);
+ send_to_server ("release\012", 0);
+ }
+ else
+#endif /* CLIENT_SUPPORT */
+ {
+ history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
+ }
+
+ if (delete_flag)
+ {
+ /* FIXME? Shouldn't this just delete the CVS-controlled
+ files and, perhaps, the files that would normally be
+ ignored and leave everything else? */
+
+ if (unlink_file_dir (thisarg) < 0)
+ error (0, errno, "deletion of directory %s failed", thisarg);
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ /* FIXME:
+ * Is there a good reason why get_server_responses() isn't
+ * responsible for restoring its initial directory itself when
+ * finished?
+ */
+ err += get_server_responses ();
+
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ }
+#endif /* CLIENT_SUPPORT */
+ }
+
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ /* Unfortunately, client.c doesn't offer a way to close
+ the connection without waiting for responses. The extra
+ network turnaround here is quite unnecessary other than
+ that.... */
+ send_to_server ("noop\012", 0);
+ err += get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ if (line != NULL)
+ free (line);
+ return err;
+}
diff --git a/src/remove.c b/src/remove.c
new file mode 100644
index 0000000..2afe362
--- /dev/null
+++ b/src/remove.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Remove a File
+ *
+ * Removes entries from the present version. The entries will be removed from
+ * the RCS repository upon the next "commit".
+ *
+ * "remove" accepts no options, only file names that are to be removed. The
+ * file must not exist in the current directory for "remove" to work
+ * correctly.
+ */
+
+#include "cvs.h"
+
+#ifdef CLIENT_SUPPORT
+static int remove_force_fileproc (void *callerdat,
+ struct file_info *finfo);
+#endif
+static int remove_fileproc (void *callerdat, struct file_info *finfo);
+static Dtype remove_dirproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+
+static int force;
+static int local;
+static int removed_files;
+static int existing_files;
+
+static const char *const remove_usage[] =
+{
+ "Usage: %s %s [-flR] [files...]\n",
+ "\t-f\tDelete the file before removing it.\n",
+ "\t-l\tProcess this directory only (not recursive).\n",
+ "\t-R\tProcess directories recursively.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+cvsremove (int argc, char **argv)
+{
+ int c, err;
+
+ if (argc == -1)
+ usage (remove_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+flR")) != -1)
+ {
+ switch (c)
+ {
+ case 'f':
+ force = 1;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (remove_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote) {
+ /* Call expand_wild so that the local removal of files will
+ work. It's ok to do it always because we have to send the
+ file names expanded anyway. */
+ expand_wild (argc, argv, &argc, &argv);
+
+ if (force)
+ {
+ if (!noexec)
+ {
+ start_recursion (remove_force_fileproc, NULL, NULL, NULL,
+ NULL, argc, argv, local, W_LOCAL,
+ 0, CVS_LOCK_NONE, NULL, 0, NULL);
+ }
+ /* else FIXME should probably act as if the file doesn't exist
+ in doing the following checks. */
+ }
+
+ start_server ();
+ ign_setup ();
+ if (local)
+ send_arg("-l");
+ send_arg ("--");
+ /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */
+ send_files (argc, argv, local, 0, 0);
+ send_file_names (argc, argv, 0);
+ free_names (&argc, argv);
+ send_to_server ("remove\012", 0);
+ return get_responses_and_close ();
+ }
+#endif
+
+ /* start the recursion processor */
+ err = start_recursion (remove_fileproc, NULL, remove_dirproc, NULL,
+ NULL, argc, argv, local, W_LOCAL, 0,
+ CVS_LOCK_READ, NULL, 1, NULL);
+
+ if (removed_files && !really_quiet)
+ error (0, 0, "use `%s commit' to remove %s permanently", program_name,
+ (removed_files == 1) ? "this file" : "these files");
+
+ if (existing_files)
+ error (0, 0,
+ ((existing_files == 1) ?
+ "%d file exists; remove it first" :
+ "%d files exist; remove them first"),
+ existing_files);
+
+ return (err);
+}
+
+#ifdef CLIENT_SUPPORT
+
+/*
+ * This is called via start_recursion if we are running as the client
+ * and the -f option was used. We just physically remove the file.
+ */
+
+/*ARGSUSED*/
+static int
+remove_force_fileproc (void *callerdat, struct file_info *finfo)
+{
+ if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
+ error (0, errno, "unable to remove %s", finfo->fullname);
+ return 0;
+}
+
+#endif
+
+/*
+ * remove the file, only if it has already been physically removed
+ */
+/* ARGSUSED */
+static int
+remove_fileproc (void *callerdat, struct file_info *finfo)
+{
+ Vers_TS *vers;
+
+ if (force)
+ {
+ if (!noexec)
+ {
+ if ( CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
+ {
+ error (0, errno, "unable to remove %s", finfo->fullname);
+ }
+ }
+ /* else FIXME should probably act as if the file doesn't exist
+ in doing the following checks. */
+ }
+
+ vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
+
+ if (vers->ts_user != NULL)
+ {
+ existing_files++;
+ if (!quiet)
+ error (0, 0, "file `%s' still in working directory",
+ finfo->fullname);
+ }
+ else if (vers->vn_user == NULL)
+ {
+ if (!quiet)
+ error (0, 0, "nothing known about `%s'", finfo->fullname);
+ }
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ {
+ char *fname;
+
+ /*
+ * It's a file that has been added, but not commited yet. So,
+ * remove the ,t file for it and scratch it from the
+ * entries file. */
+ Scratch_Entry (finfo->entries, finfo->file);
+ fname = Xasprintf ("%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
+ if (unlink_file (fname) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", CVSEXT_LOG);
+ if (!quiet)
+ error (0, 0, "removed `%s'", finfo->fullname);
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
+#endif
+ free (fname);
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ if (!quiet)
+ error (0, 0, "file `%s' already scheduled for removal",
+ finfo->fullname);
+ }
+ else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag))
+ {
+ /* Commit will just give an error, and so there seems to be
+ little reason to allow the remove. I mean, conflicts that
+ arise out of parallel development are one thing, but conflicts
+ that arise from sticky tags are quite another.
+
+ I would have thought that non-branch sticky tags should be the
+ same but at least now, removing a file with a non-branch sticky
+ tag means to delete the tag from the file. I'm not sure that
+ is a good behavior, but until it is changed, we need to allow
+ it. */
+ error (0, 0, "\
+cannot remove file `%s' which has a numeric sticky tag of `%s'",
+ finfo->fullname, vers->tag);
+ }
+ else if (vers->date != NULL)
+ {
+ /* Commit will just give an error, and so there seems to be
+ little reason to allow the remove. */
+ error (0, 0, "\
+cannot remove file `%s' which has a sticky date of `%s'",
+ finfo->fullname, vers->date);
+ }
+ else
+ {
+ char *fname;
+
+ /* Re-register it with a negative version number. */
+ fname = Xasprintf ("-%s", vers->vn_user);
+ Register (finfo->entries, finfo->file, fname, vers->ts_rcs,
+ vers->options, vers->tag, vers->date, vers->ts_conflict);
+ if (!quiet)
+ error (0, 0, "scheduling `%s' for removal", finfo->fullname);
+ removed_files++;
+
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
+#endif
+ free (fname);
+ }
+
+ freevers_ts (&vers);
+ return (0);
+}
+
+
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+remove_dirproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+ if (!quiet)
+ error (0, 0, "Removing %s", update_dir);
+ return (R_PROCESS);
+}
diff --git a/src/repos.c b/src/repos.c
new file mode 100644
index 0000000..3990424
--- /dev/null
+++ b/src/repos.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+
+
+/* Determine the name of the RCS repository for directory DIR in the
+ current working directory, or for the current working directory
+ itself if DIR is NULL. Returns the name in a newly-malloc'd
+ string. On error, gives a fatal error and does not return.
+ UPDATE_DIR is the path from where cvs was invoked (for use in error
+ messages), and should contain DIR as its last component.
+ UPDATE_DIR can be NULL to signify the directory in which cvs was
+ invoked. */
+
+char *
+Name_Repository (const char *dir, const char *update_dir)
+{
+ FILE *fpin;
+ const char *xupdate_dir;
+ char *repos = NULL;
+ size_t repos_allocated = 0;
+ char *tmp;
+ char *cp;
+
+ if (update_dir && *update_dir)
+ xupdate_dir = update_dir;
+ else
+ xupdate_dir = ".";
+
+ if (dir != NULL)
+ tmp = Xasprintf ("%s/%s", dir, CVSADM_REP);
+ else
+ tmp = xstrdup (CVSADM_REP);
+
+ /*
+ * The assumption here is that the repository is always contained in the
+ * first line of the "Repository" file.
+ */
+ fpin = CVS_FOPEN (tmp, "r");
+
+ if (fpin == NULL)
+ {
+ int save_errno = errno;
+ char *cvsadm;
+
+ if (dir != NULL)
+ cvsadm = Xasprintf ("%s/%s", dir, CVSADM);
+ else
+ cvsadm = xstrdup (CVSADM);
+
+ if (!isdir (cvsadm))
+ {
+ error (0, 0, "in directory `%s':", xupdate_dir);
+ error (1, 0, "there is no version here; do `%s checkout' first",
+ program_name);
+ }
+ free (cvsadm);
+
+ if (existence_error (save_errno))
+ {
+ /* This occurs at least in the case where the user manually
+ * creates a directory named CVS.
+ */
+ error (0, 0, "in directory `%s':", xupdate_dir);
+ error (0, 0, "CVS directory found without administrative files.");
+ error (0, 0, "Use CVS to create the CVS directory, or rename the");
+ error (0, 0, "directory if it is intended to store something");
+ error (0, 0, "besides CVS administrative files.");
+ error (1, 0, "*PANIC* administration files missing!");
+ }
+
+ error (1, save_errno, "cannot open `%s'", tmp);
+ }
+
+ if (getline (&repos, &repos_allocated, fpin) < 0)
+ {
+ /* FIXME: should be checking for end of file separately. */
+ error (0, 0, "in directory `%s':", xupdate_dir);
+ error (1, errno, "cannot read `%s'", CVSADM_REP);
+ }
+ if (fclose (fpin) < 0)
+ error (0, errno, "cannot close `%s'", tmp);
+ free (tmp);
+
+ if ((cp = strrchr (repos, '\n')) != NULL)
+ *cp = '\0'; /* strip the newline */
+
+ /* If this is a relative repository pathname, turn it into an absolute
+ * one by tacking on the current root. There is no need to grab it from
+ * the CVS/Root file via the Name_Root() function because by the time
+ * this function is called, we the contents of CVS/Root have already been
+ * compared to original_root and found to match.
+ */
+ if (!ISABSOLUTE (repos))
+ {
+ char *newrepos;
+
+ if (current_parsed_root == NULL)
+ {
+ error (0, 0, "in directory `%s:", xupdate_dir);
+ error (0, 0, "must set the CVSROOT environment variable\n");
+ error (0, 0, "or specify the '-d' option to `%s'.", program_name);
+ error (1, 0, "invalid repository setting");
+ }
+ if (pathname_levels (repos) > 0)
+ {
+ error (0, 0, "in directory `%s':", xupdate_dir);
+ error (0, 0, "`..'-relative repositories are not supported.");
+ error (1, 0, "invalid source repository");
+ }
+ newrepos = Xasprintf ("%s/%s", original_parsed_root->directory, repos);
+ free (repos);
+ repos = newrepos;
+ }
+
+ Sanitize_Repository_Name (repos);
+
+ return repos;
+}
+
+
+
+/*
+ * Return a pointer to the repository name relative to CVSROOT from a
+ * possibly fully qualified repository
+ */
+const char *
+Short_Repository (const char *repository)
+{
+ if (repository == NULL)
+ return NULL;
+
+ /* If repository matches CVSroot at the beginning, strip off CVSroot */
+ /* And skip leading '/' in rep, in case CVSroot ended with '/'. */
+ if (strncmp (original_parsed_root->directory, repository,
+ strlen (original_parsed_root->directory)) == 0)
+ {
+ const char *rep = repository + strlen (original_parsed_root->directory);
+ return (*rep == '/') ? rep+1 : rep;
+ }
+ else
+ return repository;
+}
+
+
+
+/* Sanitize the repository name (in place) by removing trailing
+ * slashes and a trailing "." if present. It should be safe for
+ * callers to use strcat and friends to create repository names.
+ * Without this check, names like "/path/to/repos/./foo" and
+ * "/path/to/repos//foo" would be created. For example, one
+ * significant case is the CVSROOT-detection code in commit.c. It
+ * decides whether or not it needs to rebuild the administrative file
+ * database by doing a string compare. If we've done a `cvs co .' to
+ * get the CVSROOT files, "/path/to/repos/./CVSROOT" and
+ * "/path/to/repos/CVSROOT" are the arguments that are compared!
+ *
+ * This function ends up being called from the same places as
+ * strip_path, though what it does is much more conservative. Many
+ * comments about this operation (which was scattered around in
+ * several places in the source code) ran thus:
+ *
+ * ``repository ends with "/."; omit it. This sort of thing used
+ * to be taken care of by strip_path. Now we try to be more
+ * selective. I suspect that it would be even better to push it
+ * back further someday, so that the trailing "/." doesn't get into
+ * repository in the first place, but we haven't taken things that
+ * far yet.'' --Jim Kingdon (recurse.c, 07-Sep-97)
+ */
+
+void
+Sanitize_Repository_Name (char *repository)
+{
+ size_t len;
+
+ assert (repository != NULL);
+
+ strip_trailing_slashes (repository);
+
+ len = strlen (repository);
+ if (len >= 2
+ && repository[len - 1] == '.'
+ && ISSLASH (repository[len - 2]))
+ {
+ repository[len - 2] = '\0';
+ }
+}
diff --git a/src/root.c b/src/root.c
new file mode 100644
index 0000000..34a957c
--- /dev/null
+++ b/src/root.c
@@ -0,0 +1,1054 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Poritons Copyright (c) 1992, Mark D. Baushke
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Name of Root
+ *
+ * Determine the path to the CVSROOT and set "Root" accordingly.
+ */
+
+#include "cvs.h"
+#include <assert.h>
+#include "getline.h"
+
+/* Printable names for things in the current_parsed_root->method enum variable.
+ Watch out if the enum is changed in cvs.h! */
+
+const char method_names[][16] = {
+ "undefined", "local", "server (rsh)", "pserver",
+ "kserver", "gserver", "ext", "fork"
+};
+
+#ifndef DEBUG
+
+cvsroot_t *
+Name_Root (const char *dir, const char *update_dir)
+{
+ FILE *fpin;
+ cvsroot_t *ret;
+ const char *xupdate_dir;
+ char *root = NULL;
+ size_t root_allocated = 0;
+ char *tmp;
+ char *cvsadm;
+ char *cp;
+ int len;
+
+ TRACE (TRACE_FLOW, "Name_Root (%s, %s)",
+ dir ? dir : "(null)",
+ update_dir ? update_dir : "(null)");
+
+ if (update_dir && *update_dir)
+ xupdate_dir = update_dir;
+ else
+ xupdate_dir = ".";
+
+ if (dir != NULL)
+ {
+ cvsadm = Xasprintf ("%s/%s", dir, CVSADM);
+ tmp = Xasprintf ("%s/%s", dir, CVSADM_ROOT);
+ }
+ else
+ {
+ cvsadm = xstrdup (CVSADM);
+ tmp = xstrdup (CVSADM_ROOT);
+ }
+
+ /*
+ * Do not bother looking for a readable file if there is no cvsadm
+ * directory present.
+ *
+ * It is possible that not all repositories will have a CVS/Root
+ * file. This is ok, but the user will need to specify -d
+ * /path/name or have the environment variable CVSROOT set in
+ * order to continue. */
+ if ((!isdir (cvsadm)) || (!isreadable (tmp)))
+ {
+ ret = NULL;
+ goto out;
+ }
+
+ /*
+ * The assumption here is that the CVS Root is always contained in the
+ * first line of the "Root" file.
+ */
+ fpin = xfopen (tmp, "r");
+
+ if ((len = getline (&root, &root_allocated, fpin)) < 0)
+ {
+ int saved_errno = errno;
+ /* FIXME: should be checking for end of file separately; errno
+ is not set in that case. */
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, saved_errno, "cannot read %s", CVSADM_ROOT);
+ error (0, 0, "please correct this problem");
+ ret = NULL;
+ goto out;
+ }
+ fclose (fpin);
+ cp = root + len - 1;
+ if (*cp == '\n')
+ *cp = '\0'; /* strip the newline */
+
+ /*
+ * root now contains a candidate for CVSroot. It must be an
+ * absolute pathname or specify a remote server.
+ */
+
+ ret = parse_cvsroot (root);
+ if (ret == NULL)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, 0,
+ "ignoring %s because it does not contain a valid root.",
+ CVSADM_ROOT);
+ goto out;
+ }
+
+ if (!ret->isremote && !isdir (ret->directory))
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (0, 0,
+ "ignoring %s because it specifies a non-existent repository %s",
+ CVSADM_ROOT, root);
+ ret = NULL;
+ goto out;
+ }
+
+
+ out:
+ free (cvsadm);
+ free (tmp);
+ if (root != NULL)
+ free (root);
+ return ret;
+}
+
+
+
+/*
+ * Write the CVS/Root file so that the environment variable CVSROOT
+ * and/or the -d option to cvs will be validated or not necessary for
+ * future work.
+ */
+void
+Create_Root (const char *dir, const char *rootdir)
+{
+ FILE *fout;
+ char *tmp;
+
+ if (noexec)
+ return;
+
+ /* record the current cvs root */
+
+ if (rootdir != NULL)
+ {
+ if (dir != NULL)
+ tmp = Xasprintf ("%s/%s", dir, CVSADM_ROOT);
+ else
+ tmp = xstrdup (CVSADM_ROOT);
+
+ fout = xfopen (tmp, "w+");
+ if (fprintf (fout, "%s\n", rootdir) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ if (fclose (fout) == EOF)
+ error (1, errno, "cannot close %s", tmp);
+ free (tmp);
+ }
+}
+
+#endif /* ! DEBUG */
+
+
+
+/* Translate an absolute repository string for a primary server and return it.
+ *
+ * INPUTS
+ * root_in The root to be translated.
+ *
+ * RETURNS
+ * A translated string this function owns, or a pointer to the original
+ * string passed in if no translation was necessary.
+ *
+ * If the returned string is the translated one, it may be overwritten
+ * by the next call to this function.
+ */
+const char *
+primary_root_translate (const char *root_in)
+{
+#ifdef PROXY_SUPPORT
+ char *translated;
+ static char *previous = NULL;
+ static size_t len;
+
+ /* This can happen, for instance, during `cvs init'. */
+ if (!config) return root_in;
+
+ if (config->PrimaryServer
+ && !strncmp (root_in, config->PrimaryServer->directory,
+ strlen (config->PrimaryServer->directory))
+ && (ISSLASH (root_in[strlen (config->PrimaryServer->directory)])
+ || root_in[strlen (config->PrimaryServer->directory)] == '\0')
+ )
+ {
+ translated =
+ Xasnprintf (previous, &len,
+ "%s%s", current_parsed_root->directory,
+ root_in + strlen (config->PrimaryServer->directory));
+ if (previous && previous != translated)
+ free (previous);
+ return previous = translated;
+ }
+#endif
+
+ /* There is no primary root configured or it didn't match. */
+ return root_in;
+}
+
+
+
+/* Translate a primary root in reverse for PATHNAMEs in responses.
+ *
+ * INPUTS
+ * root_in The root to be translated.
+ *
+ * RETURNS
+ * A translated string this function owns, or a pointer to the original
+ * string passed in if no translation was necessary.
+ *
+ * If the returned string is the translated one, it may be overwritten
+ * by the next call to this function.
+ */
+const char *
+primary_root_inverse_translate (const char *root_in)
+{
+#ifdef PROXY_SUPPORT
+ char *translated;
+ static char *previous = NULL;
+ static size_t len;
+
+ /* This can happen, for instance, during `cvs init'. */
+ if (!config) return root_in;
+
+ if (config->PrimaryServer
+ && !strncmp (root_in, current_parsed_root->directory,
+ strlen (current_parsed_root->directory))
+ && (ISSLASH (root_in[strlen (current_parsed_root->directory)])
+ || root_in[strlen (current_parsed_root->directory)] == '\0')
+ )
+ {
+ translated =
+ Xasnprintf (previous, &len,
+ "%s%s", config->PrimaryServer->directory,
+ root_in + strlen (current_parsed_root->directory));
+ if (previous && previous != translated)
+ free (previous);
+ return previous = translated;
+ }
+#endif
+
+ /* There is no primary root configured or it didn't match. */
+ return root_in;
+}
+
+
+
+/* The root_allow_* stuff maintains a list of valid CVSROOT
+ directories. Then we can check against them when a remote user
+ hands us a CVSROOT directory. */
+static List *root_allow;
+
+static void
+delconfig (Node *n)
+{
+ if (n->data) free_config (n->data);
+}
+
+
+
+void
+root_allow_add (const char *arg, const char *configPath)
+{
+ Node *n;
+
+ if (!root_allow) root_allow = getlist();
+ n = getnode();
+ n->key = xstrdup (arg);
+ n->data = parse_config (arg, configPath);
+ n->delproc = delconfig;
+ addnode (root_allow, n);
+}
+
+void
+root_allow_free (void)
+{
+ dellist (&root_allow);
+}
+
+bool
+root_allow_ok (const char *arg)
+{
+ if (!root_allow)
+ {
+ /* Probably someone upgraded from CVS before 1.9.10 to 1.9.10
+ or later without reading the documentation about
+ --allow-root. Printing an error here doesn't disclose any
+ particularly useful information to an attacker because a
+ CVS server configured in this way won't let *anyone* in. */
+
+ /* Note that we are called from a context where we can spit
+ back "error" rather than waiting for the next request which
+ expects responses. */
+ printf ("\
+error 0 Server configuration missing --allow-root in inetd.conf\n");
+ exit (EXIT_FAILURE);
+ }
+
+ if (findnode (root_allow, arg))
+ return true;
+ return false;
+}
+
+
+
+/* Get a config we stored in response to root_allow.
+ *
+ * RETURNS
+ * The config associated with ARG.
+ */
+struct config *
+get_root_allow_config (const char *arg, const char *configPath)
+{
+ Node *n;
+
+ TRACE (TRACE_FUNCTION, "get_root_allow_config (%s)", arg);
+
+ if (root_allow)
+ n = findnode (root_allow, arg);
+ else
+ n = NULL;
+
+ if (n) return n->data;
+ return parse_config (arg, configPath);
+}
+
+
+
+/* This global variable holds the global -d option. It is NULL if -d
+ was not used, which means that we must get the CVSroot information
+ from the CVSROOT environment variable or from a CVS/Root file. */
+char *CVSroot_cmdline;
+
+
+
+/* FIXME - Deglobalize this. */
+cvsroot_t *current_parsed_root = NULL;
+/* Used to save the original root being processed so that we can still find it
+ * in lists and the like after a `Redirect' response. Also set to mirror
+ * current_parsed_root in server mode so that code which runs on both the
+ * client and server but which wants to use original data on the client can
+ * just always reference the original_parsed_root.
+ */
+const cvsroot_t *original_parsed_root;
+
+
+/* allocate and initialize a cvsroot_t
+ *
+ * We must initialize the strings to NULL so we know later what we should
+ * free
+ *
+ * Some of the other zeroes remain meaningful as, "never set, use default",
+ * or the like
+ */
+/* Functions which allocate memory are not pure. */
+static cvsroot_t *new_cvsroot_t(void)
+ __attribute__( (__malloc__) );
+static cvsroot_t *
+new_cvsroot_t (void)
+{
+ cvsroot_t *newroot;
+
+ /* gotta store it somewhere */
+ newroot = xmalloc(sizeof(cvsroot_t));
+
+ newroot->original = NULL;
+ newroot->directory = NULL;
+ newroot->method = null_method;
+ newroot->isremote = false;
+#ifdef CLIENT_SUPPORT
+ newroot->username = NULL;
+ newroot->password = NULL;
+ newroot->hostname = NULL;
+ newroot->cvs_rsh = NULL;
+ newroot->cvs_server = NULL;
+ newroot->port = 0;
+ newroot->proxy_hostname = NULL;
+ newroot->proxy_port = 0;
+ newroot->redirect = true; /* Advertise Redirect support */
+#endif /* CLIENT_SUPPORT */
+
+ return newroot;
+}
+
+
+
+/* Dispose of a cvsroot_t and its component parts.
+ *
+ * NOTE
+ * It is dangerous for most code to call this function since parse_cvsroot
+ * maintains a cache of parsed roots.
+ */
+static void
+free_cvsroot_t (cvsroot_t *root)
+{
+ assert (root);
+ if (root->original != NULL)
+ free (root->original);
+ if (root->directory != NULL)
+ free (root->directory);
+#ifdef CLIENT_SUPPORT
+ if (root->username != NULL)
+ free (root->username);
+ if (root->password != NULL)
+ {
+ /* I like to be paranoid */
+ memset (root->password, 0, strlen (root->password));
+ free (root->password);
+ }
+ if (root->hostname != NULL)
+ free (root->hostname);
+ if (root->cvs_rsh != NULL)
+ free (root->cvs_rsh);
+ if (root->cvs_server != NULL)
+ free (root->cvs_server);
+ if (root->proxy_hostname != NULL)
+ free (root->proxy_hostname);
+#endif /* CLIENT_SUPPORT */
+ free (root);
+}
+
+
+
+/*
+ * Parse a CVSROOT string to allocate and return a new cvsroot_t structure.
+ * Valid specifications are:
+ *
+ * :(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path
+ * [:(ext|server):][[user]@]host[:]/path
+ * [:local:[e:]]/path
+ * :fork:/path
+ *
+ * INPUTS
+ * root_in C String containing the CVSROOT to be parsed.
+ *
+ * RETURNS
+ * A pointer to a newly allocated cvsroot_t structure upon success and
+ * NULL upon failure. The caller should never dispose of this structure,
+ * as it is stored in a cache, but the caller may rely on it not to
+ * change.
+ *
+ * NOTES
+ * This would have been a lot easier to write in Perl.
+ *
+ * Would it make sense to reimplement the root and config file parsing
+ * gunk in Lex/Yacc?
+ *
+ * SEE ALSO
+ * free_cvsroot_t()
+ */
+cvsroot_t *
+parse_cvsroot (const char *root_in)
+{
+ cvsroot_t *newroot; /* the new root to be returned */
+ char *cvsroot_save; /* what we allocated so we can dispose
+ * it when finished */
+ char *cvsroot_copy, *p; /* temporary pointers for parsing */
+#if defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ char *q; /* temporary pointer for parsing */
+ char *firstslash; /* save where the path spec starts
+ * while we parse
+ * [[user][:password]@]host[:[port]]
+ */
+ int check_hostname, no_port, no_password, no_proxy;
+#endif /* defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+ static List *cache = NULL;
+ Node *node;
+
+ assert (root_in != NULL);
+
+ /* This message is TRACE_FLOW since this function is called repeatedly by
+ * the recursion routines.
+ */
+ TRACE (TRACE_FLOW, "parse_cvsroot (%s)", root_in);
+
+ if ((node = findnode (cache, root_in)))
+ return node->data;
+
+ assert (root_in);
+
+ /* allocate some space */
+ newroot = new_cvsroot_t();
+
+ /* save the original string */
+ newroot->original = xstrdup (root_in);
+
+ /* and another copy we can munge while parsing */
+ cvsroot_save = cvsroot_copy = xstrdup (root_in);
+
+ if (*cvsroot_copy == ':')
+ {
+ char *method = ++cvsroot_copy;
+
+ /* Access method specified, as in
+ * "cvs -d :(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path",
+ * "cvs -d [:(ext|server):][[user]@]host[:]/path",
+ * "cvs -d :local:e:\path",
+ * "cvs -d :fork:/path".
+ * We need to get past that part of CVSroot before parsing the
+ * rest of it.
+ */
+
+ if (! (p = strchr (method, ':')))
+ {
+ error (0, 0, "No closing `:' on method in CVSROOT.");
+ goto error_exit;
+ }
+ *p = '\0';
+ cvsroot_copy = ++p;
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ /* Look for method options, for instance, proxy, proxyport.
+ * Calling strtok again is saved until after parsing the method.
+ */
+ method = strtok (method, ";");
+ if (!method)
+ /* Could just exit now, but this keeps the error message in sync.
+ */
+ method = "";
+#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+
+ /* Now we have an access method -- see if it's valid. */
+
+ if (!strcasecmp (method, "local"))
+ newroot->method = local_method;
+ else if (!strcasecmp (method, "pserver"))
+ newroot->method = pserver_method;
+ else if (!strcasecmp (method, "kserver"))
+ newroot->method = kserver_method;
+ else if (!strcasecmp (method, "gserver"))
+ newroot->method = gserver_method;
+ else if (!strcasecmp (method, "server"))
+ newroot->method = server_method;
+ else if (!strcasecmp (method, "ext"))
+ newroot->method = ext_method;
+ else if (!strcasecmp (method, "fork"))
+ newroot->method = fork_method;
+ else
+ {
+ error (0, 0, "Unknown method (`%s') in CVSROOT.", method);
+ goto error_exit;
+ }
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ /* Parse the method options, for instance, proxy, proxyport */
+ while ((p = strtok (NULL, ";")))
+ {
+ char *q = strchr (p, '=');
+ if (q == NULL)
+ {
+ error (0, 0, "Option (`%s') has no argument in CVSROOT.",
+ p);
+ goto error_exit;
+ }
+
+ *q++ = '\0';
+ TRACE (TRACE_DATA, "CVSROOT option=`%s' value=`%s'", p, q);
+ if (!strcasecmp (p, "proxy"))
+ {
+ newroot->proxy_hostname = xstrdup (q);
+ }
+ else if (!strcasecmp (p, "proxyport"))
+ {
+ char *r = q;
+ if (*r == '-') r++;
+ while (*r)
+ {
+ if (!isdigit(*r++))
+ {
+ error (0, 0,
+"CVSROOT may only specify a positive, non-zero, integer proxy port (not `%s').",
+ q);
+ goto error_exit;
+ }
+ }
+ if ((newroot->proxy_port = atoi (q)) <= 0)
+ error (0, 0,
+"CVSROOT may only specify a positive, non-zero, integer proxy port (not `%s').",
+ q);
+ }
+ else if (!strcasecmp (p, "CVS_RSH"))
+ {
+ /* override CVS_RSH environment variable */
+ if (newroot->method == ext_method)
+ newroot->cvs_rsh = xstrdup (q);
+ }
+ else if (!strcasecmp (p, "CVS_SERVER"))
+ {
+ /* override CVS_SERVER environment variable */
+ if (newroot->method == ext_method
+ || newroot->method == fork_method)
+ newroot->cvs_server = xstrdup (q);
+ }
+ else if (!strcasecmp (p, "Redirect"))
+ readBool ("CVSROOT", "Redirect", q, &newroot->redirect);
+ else
+ {
+ error (0, 0, "Unknown option (`%s') in CVSROOT.", p);
+ goto error_exit;
+ }
+ }
+#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+ }
+ else
+ {
+ /* If the method isn't specified, assume EXT_METHOD if the string looks
+ like a relative path and LOCAL_METHOD otherwise. */
+
+ newroot->method = ((*cvsroot_copy != '/' && strchr (cvsroot_copy, '/'))
+ ? ext_method
+ : local_method);
+ }
+
+ /*
+ * There are a few sanity checks we can do now, only knowing the
+ * method of this root.
+ */
+
+ newroot->isremote = (newroot->method != local_method);
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ if (readonlyfs && newroot->isremote)
+ error (1, 0,
+"Read-only repository feature unavailable with remote roots (cvsroot = %s)",
+ cvsroot_copy);
+
+ if ((newroot->method != local_method)
+ && (newroot->method != fork_method)
+ )
+ {
+ /* split the string into [[user][:password]@]host[:[port]] & /path
+ *
+ * this will allow some characters such as '@' & ':' to remain unquoted
+ * in the path portion of the spec
+ */
+ if ((p = strchr (cvsroot_copy, '/')) == NULL)
+ {
+ error (0, 0, "CVSROOT requires a path spec:");
+ error (0, 0,
+":(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path");
+ error (0, 0, "[:(ext|server):][[user]@]host[:]/path");
+ goto error_exit;
+ }
+ firstslash = p; /* == NULL if '/' not in string */
+ *p = '\0';
+
+ /* Check to see if there is a username[:password] in the string. */
+ if ((p = strchr (cvsroot_copy, '@')) != NULL)
+ {
+ *p = '\0';
+ /* check for a password */
+ if ((q = strchr (cvsroot_copy, ':')) != NULL)
+ {
+ *q = '\0';
+ newroot->password = xstrdup (++q);
+ /* Don't check for *newroot->password == '\0' since
+ * a user could conceivably wish to specify a blank password
+ *
+ * (newroot->password == NULL means to use the
+ * password from .cvspass)
+ */
+ }
+
+ /* copy the username */
+ if (*cvsroot_copy != '\0')
+ /* a blank username is impossible, so leave it NULL in that
+ * case so we know to use the default username
+ */
+ newroot->username = xstrdup (cvsroot_copy);
+
+ cvsroot_copy = ++p;
+ }
+
+ /* now deal with host[:[port]] */
+
+ /* the port */
+ if ((p = strchr (cvsroot_copy, ':')) != NULL)
+ {
+ *p++ = '\0';
+ if (strlen(p))
+ {
+ q = p;
+ if (*q == '-') q++;
+ while (*q)
+ {
+ if (!isdigit(*q++))
+ {
+ error (0, 0,
+"CVSROOT may only specify a positive, non-zero, integer port (not `%s').",
+ p);
+ error (0, 0,
+ "Perhaps you entered a relative pathname?");
+ goto error_exit;
+ }
+ }
+ if ((newroot->port = atoi (p)) <= 0)
+ {
+ error (0, 0,
+"CVSROOT may only specify a positive, non-zero, integer port (not `%s').",
+ p);
+ error (0, 0, "Perhaps you entered a relative pathname?");
+ goto error_exit;
+ }
+ }
+ }
+
+ /* copy host */
+ if (*cvsroot_copy != '\0')
+ /* blank hostnames are invalid, but for now leave the field NULL
+ * and catch the error during the sanity checks later
+ */
+ newroot->hostname = xstrdup (cvsroot_copy);
+
+ /* restore the '/' */
+ cvsroot_copy = firstslash;
+ *cvsroot_copy = '/';
+ }
+#endif /* defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+
+ /*
+ * Parse the path for all methods.
+ */
+ /* Here & local_cvsroot() should be the only places this needs to be
+ * called on a CVSROOT now. cvsroot->original is saved for error messages
+ * and, otherwise, we want no trailing slashes.
+ */
+ Sanitize_Repository_Name (cvsroot_copy);
+ newroot->directory = xstrdup (cvsroot_copy);
+
+ /*
+ * Do various sanity checks.
+ */
+
+#if defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ if (newroot->username && ! newroot->hostname)
+ {
+ error (0, 0, "Missing hostname in CVSROOT.");
+ goto error_exit;
+ }
+
+ /* We won't have attempted to parse these without CLIENT_SUPPORT or
+ * SERVER_SUPPORT.
+ */
+ check_hostname = 0;
+ no_password = 1;
+ no_proxy = 1;
+ no_port = 0;
+#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+ switch (newroot->method)
+ {
+ case local_method:
+#if defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ if (newroot->username || newroot->hostname)
+ {
+ error (0, 0, "Can't specify hostname and username in CVSROOT");
+ error (0, 0, "when using local access method.");
+ goto error_exit;
+ }
+#endif /* defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+ /* cvs.texinfo has always told people that CVSROOT must be an
+ absolute pathname. Furthermore, attempts to use a relative
+ pathname produced various errors (I couldn't get it to work),
+ so there would seem to be little risk in making this a fatal
+ error. */
+ if (!ISABSOLUTE (newroot->directory))
+ {
+ error (0, 0, "CVSROOT must be an absolute pathname (not `%s')",
+ newroot->directory);
+ error (0, 0, "when using local access method.");
+ goto error_exit;
+ }
+#if defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ /* We don't need to check for these in :local: mode, really, since
+ * we shouldn't be able to hit the code above which parses them, but
+ * I'm leaving them here in lieu of assertions.
+ */
+ no_port = 1;
+ /* no_password already set */
+#endif /* defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+ break;
+#if defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ case fork_method:
+ /* We want :fork: to behave the same as other remote access
+ methods. Therefore, don't check to see that the repository
+ name is absolute -- let the server do it. */
+ if (newroot->username || newroot->hostname)
+ {
+ error (0, 0, "Can't specify hostname and username in CVSROOT");
+ error (0, 0, "when using fork access method.");
+ goto error_exit;
+ }
+ newroot->hostname = xstrdup("server"); /* for error messages */
+ if (!ISABSOLUTE (newroot->directory))
+ {
+ error (0, 0, "CVSROOT must be an absolute pathname (not `%s')",
+ newroot->directory);
+ error (0, 0, "when using fork access method.");
+ goto error_exit;
+ }
+ no_port = 1;
+ /* no_password already set */
+ break;
+ case kserver_method:
+ check_hostname = 1;
+ /* no_password already set */
+ break;
+ case gserver_method:
+ check_hostname = 1;
+ no_proxy = 0;
+ /* no_password already set */
+ break;
+ case server_method:
+ case ext_method:
+ no_port = 1;
+ /* no_password already set */
+ check_hostname = 1;
+ break;
+ case pserver_method:
+ no_password = 0;
+ no_proxy = 0;
+ check_hostname = 1;
+ break;
+#endif /* defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+ default:
+ error (1, 0, "Invalid method found in parse_cvsroot");
+ }
+
+#if defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ if (no_password && newroot->password)
+ {
+ error (0, 0, "CVSROOT password specification is only valid for");
+ error (0, 0, "pserver connection method.");
+ goto error_exit;
+ }
+ if (no_proxy && (newroot->proxy_hostname || newroot->proxy_port))
+ {
+ error (0, 0,
+"CVSROOT proxy specification is only valid for gserver and");
+ error (0, 0, "pserver connection methods.");
+ goto error_exit;
+ }
+
+ if (!newroot->proxy_hostname && newroot->proxy_port)
+ {
+ error (0, 0, "Proxy port specified in CVSROOT without proxy host.");
+ goto error_exit;
+ }
+
+ if (check_hostname && !newroot->hostname)
+ {
+ error (0, 0, "Didn't specify hostname in CVSROOT.");
+ goto error_exit;
+ }
+
+ if (no_port && newroot->port)
+ {
+ error (0, 0,
+"CVSROOT port specification is only valid for gserver, kserver,");
+ error (0, 0, "and pserver connection methods.");
+ goto error_exit;
+ }
+#endif /* defined(CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+
+ if (*newroot->directory == '\0')
+ {
+ error (0, 0, "Missing directory in CVSROOT.");
+ goto error_exit;
+ }
+
+ /* Hooray! We finally parsed it! */
+ free (cvsroot_save);
+
+ if (!cache) cache = getlist();
+ node = getnode();
+ node->key = xstrdup (newroot->original);
+ node->data = newroot;
+ addnode (cache, node);
+ return newroot;
+
+error_exit:
+ free (cvsroot_save);
+ free_cvsroot_t (newroot);
+ return NULL;
+}
+
+
+
+#ifdef AUTH_CLIENT_SUPPORT
+/* Use root->username, root->hostname, root->port, and root->directory
+ * to create a normalized CVSROOT fit for the .cvspass file
+ *
+ * username defaults to the result of getcaller()
+ * port defaults to the result of get_cvs_port_number()
+ *
+ * FIXME - we could cache the canonicalized version of a root inside the
+ * cvsroot_t, but we'd have to un'const the input here and stop expecting the
+ * caller to be responsible for our return value
+ *
+ * ASSUMPTIONS
+ * ROOT->method == pserver_method
+ */
+char *
+normalize_cvsroot (const cvsroot_t *root)
+{
+ char *cvsroot_canonical;
+ char *p, *hostname;
+
+ assert (root && root->hostname && root->directory);
+
+ /* use a lower case hostname since we know hostnames are case insensitive */
+ /* Some logic says we should be tacking our domain name on too if it isn't
+ * there already, but for now this works. Reverse->Forward lookups are
+ * almost certainly too much since that would make CVS immune to some of
+ * the DNS trickery that makes life easier for sysadmins when they want to
+ * move a repository or the like
+ */
+ p = hostname = xstrdup (root->hostname);
+ while (*p)
+ {
+ *p = tolower (*p);
+ p++;
+ }
+
+ cvsroot_canonical = Xasprintf (":pserver:%s@%s:%d%s",
+ root->username ? root->username
+ : getcaller(),
+ hostname, get_cvs_port_number (root),
+ root->directory);
+
+ free (hostname);
+ return cvsroot_canonical;
+}
+#endif /* AUTH_CLIENT_SUPPORT */
+
+
+
+#ifdef PROXY_SUPPORT
+/* A walklist() function to walk the root_allow list looking for a PrimaryServer
+ * configuration with a directory matching the requested directory.
+ *
+ * If found, replace it.
+ */
+static bool get_local_root_dir_done;
+static int
+get_local_root_dir (Node *p, void *root_in)
+{
+ struct config *c = p->data;
+ char **r = root_in;
+
+ if (get_local_root_dir_done)
+ return 0;
+
+ if (c->PrimaryServer && !strcmp (*r, c->PrimaryServer->directory))
+ {
+ free (*r);
+ *r = xstrdup (p->key);
+ get_local_root_dir_done = true;
+ }
+ return 0;
+}
+#endif /* PROXY_SUPPORT */
+
+
+
+/* allocate and return a cvsroot_t structure set up as if we're using the local
+ * repository DIR. */
+cvsroot_t *
+local_cvsroot (const char *dir)
+{
+ cvsroot_t *newroot = new_cvsroot_t();
+
+ newroot->original = xstrdup(dir);
+ newroot->method = local_method;
+ newroot->directory = xstrdup(dir);
+ /* Here and parse_cvsroot() should be the only places this needs to be
+ * called on a CVSROOT now. cvsroot->original is saved for error messages
+ * and, otherwise, we want no trailing slashes.
+ */
+ Sanitize_Repository_Name (newroot->directory);
+
+#ifdef PROXY_SUPPORT
+ /* Translate the directory to a local one in the case that we are
+ * configured as a secondary. If root_allow has not been initialized,
+ * nothing happens.
+ */
+ get_local_root_dir_done = false;
+ walklist (root_allow, get_local_root_dir, &newroot->directory);
+#endif /* PROXY_SUPPORT */
+
+ return newroot;
+}
+
+
+
+#ifdef DEBUG
+/* This is for testing the parsing function. Use
+
+ gcc -I. -I.. -I../lib -DDEBUG root.c -o root
+
+ to compile. */
+
+#include <stdio.h>
+
+char *program_name = "testing";
+char *cvs_cmd_name = "parse_cvsroot"; /* XXX is this used??? */
+
+void
+main (int argc, char *argv[])
+{
+ program_name = argv[0];
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage: %s <CVSROOT>\n", program_name);
+ exit (2);
+ }
+
+ if ((current_parsed_root = parse_cvsroot (argv[1])) == NULL)
+ {
+ fprintf (stderr, "%s: Parsing failed.\n", program_name);
+ exit (1);
+ }
+ printf ("CVSroot: %s\n", argv[1]);
+ printf ("current_parsed_root->method: %s\n",
+ method_names[current_parsed_root->method]);
+ printf ("current_parsed_root->username: %s\n",
+ current_parsed_root->username
+ ? current_parsed_root->username : "NULL");
+ printf ("current_parsed_root->hostname: %s\n",
+ current_parsed_root->hostname
+ ? current_parsed_root->hostname : "NULL");
+ printf ("current_parsed_root->directory: %s\n",
+ current_parsed_root->directory);
+
+ exit (0);
+ /* NOTREACHED */
+}
+#endif
diff --git a/src/root.h b/src/root.h
new file mode 100644
index 0000000..012ff04
--- /dev/null
+++ b/src/root.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS kit.
+ */
+
+/* CVSroot data structures */
+
+/* Access method specified in CVSroot. */
+typedef enum {
+ null_method = 0,
+ local_method,
+ server_method,
+ pserver_method,
+ kserver_method,
+ gserver_method,
+ ext_method,
+ fork_method
+} CVSmethod;
+extern const char method_names[][16]; /* change this in root.c if you change
+ the enum above */
+
+typedef struct cvsroot_s {
+ char *original; /* The complete source CVSroot string. */
+ CVSmethod method; /* One of the enum values above. */
+ char *directory; /* The directory name. */
+ bool isremote; /* True if we are doing remote access. */
+/* The following is required for servers now to allow Redirects to be sent
+ * for remote roots when client support is disabled.
+ */
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+ char *username; /* The username or NULL if method == local. */
+ char *password; /* The password or NULL if method == local. */
+ char *hostname; /* The hostname or NULL if method == local. */
+ char *cvs_rsh; /* The $CVS_RSH or NULL if method != ext. */
+ char *cvs_server; /* The $CVS_SERVER or NULL if
+ * method != ext and method != fork. */
+ int port; /* The port or zero if method == local. */
+ char *proxy_hostname; /* The hostname of the proxy server, or NULL
+ * when method == local or no proxy will be
+ * used.
+ */
+ int proxy_port; /* The port of the proxy or zero, as above. */
+ bool redirect; /* False if we are to disable redirects. */
+#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+} cvsroot_t;
+
+extern cvsroot_t *current_parsed_root;
+extern const cvsroot_t *original_parsed_root;
+
+cvsroot_t *Name_Root (const char *dir, const char *update_dir);
+cvsroot_t *parse_cvsroot (const char *root)
+ __attribute__ ((__malloc__));
+cvsroot_t *local_cvsroot (const char *dir)
+ __attribute__ ((__malloc__));
+void Create_Root (const char *dir, const char *rootdir);
+void root_allow_add (const char *, const char *configPath);
+void root_allow_free (void);
+bool root_allow_ok (const char *);
+struct config *get_root_allow_config (const char *arg, const char *configPath);
+const char *primary_root_translate (const char *root_in);
+const char *primary_root_inverse_translate (const char *root_in);
diff --git a/src/rsh-client.c b/src/rsh-client.c
new file mode 100644
index 0000000..512bdad
--- /dev/null
+++ b/src/rsh-client.c
@@ -0,0 +1,202 @@
+/* CVS rsh client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <config.h>
+
+#include "cvs.h"
+#include "buffer.h"
+
+#ifdef CLIENT_SUPPORT
+
+#include "rsh-client.h"
+
+#ifndef NO_EXT_METHOD
+
+/* Contact the server by starting it with rsh. */
+
+/* Right now, we have two different definitions for this function,
+ depending on whether we start the rsh server using popenRW or not.
+ This isn't ideal, and the best thing would probably be to change
+ the OS/2 port to be more like the regular Unix client (i.e., by
+ implementing piped_child)... but I'm doing something else at the
+ moment, and wish to make only one change at a time. -Karl */
+
+# ifdef START_RSH_WITH_POPEN_RW
+
+
+
+/* This is actually a crock -- it's OS/2-specific, for no one else
+ uses it. If I get time, I want to make piped_child and all the
+ other stuff in os2/run.c work right. In the meantime, this gets us
+ up and running, and that's most important. */
+void
+start_rsh_server (cvsroot_t *root, struct buffer **to_server_p,
+ struct buffer **from_server_p)
+{
+ int pipes[2];
+ int child_pid;
+
+ /* If you're working through firewalls, you can set the
+ CVS_RSH environment variable to a script which uses rsh to
+ invoke another rsh on a proxy machine. */
+ char *cvs_rsh = (root->cvs_rsh != NULL
+ ? root->cvs_rsh : getenv ("CVS_RSH"));
+ char *cvs_server = (root->cvs_server != NULL
+ ? root->cvs_server : getenv ("CVS_SERVER"));
+ int i = 0;
+ /* This needs to fit "rsh", "-b", "-l", "USER", "host",
+ "cmd (w/ args)", and NULL. We leave some room to grow. */
+ char *rsh_argv[10];
+
+ if (!cvs_rsh)
+ /* People sometimes suggest or assume that this should default
+ to "remsh" on systems like HPUX in which that is the
+ system-supplied name for the rsh program. However, that
+ causes various problems (keep in mind that systems such as
+ HPUX might have non-system-supplied versions of "rsh", like
+ a Kerberized one, which one might want to use). If we
+ based the name on what is found in the PATH of the person
+ who runs configure, that would make it harder to
+ consistently produce the same result in the face of
+ different people producing binary distributions. If we
+ based it on "remsh" always being the default for HPUX
+ (e.g. based on uname), that might be slightly better but
+ would require us to keep track of what the defaults are for
+ each system type, and probably would cope poorly if the
+ existence of remsh or rsh varies from OS version to OS
+ version. Therefore, it seems best to have the default
+ remain "rsh", and tell HPUX users to specify remsh, for
+ example in CVS_RSH or other such mechanisms to be devised,
+ if that is what they want (the manual already tells them
+ that). */
+ cvs_rsh = RSH_DFLT;
+ if (!cvs_server)
+ cvs_server = "cvs";
+
+ /* The command line starts out with rsh. */
+ rsh_argv[i++] = cvs_rsh;
+
+# ifdef RSH_NEEDS_BINARY_FLAG
+ /* "-b" for binary, under OS/2. */
+ rsh_argv[i++] = "-b";
+# endif /* RSH_NEEDS_BINARY_FLAG */
+
+ /* Then we strcat more things on the end one by one. */
+ if (root->username != NULL)
+ {
+ rsh_argv[i++] = "-l";
+ rsh_argv[i++] = root->username;
+ }
+
+ rsh_argv[i++] = root->hostname;
+ rsh_argv[i++] = cvs_server;
+ rsh_argv[i++] = "server";
+
+ /* Mark the end of the arg list. */
+ rsh_argv[i] = NULL;
+
+ if (trace)
+ {
+ fprintf (stderr, " -> Starting server: ");
+ for (i = 0; rsh_argv[i]; i++)
+ fprintf (stderr, "%s ", rsh_argv[i]);
+ putc ('\n', stderr);
+ }
+
+ /* Do the deed. */
+ child_pid = popenRW (rsh_argv, pipes);
+ if (child_pid < 0)
+ error (1, errno, "cannot start server via rsh");
+
+ /* Give caller the file descriptors in a form it can deal with. */
+ make_bufs_from_fds (pipes[0], pipes[1], child_pid, to_server_p,
+ from_server_p, 0);
+}
+
+# else /* ! START_RSH_WITH_POPEN_RW */
+
+void
+start_rsh_server (cvsroot_t *root, struct buffer **to_server_p,
+ struct buffer **from_server_p)
+{
+ /* If you're working through firewalls, you can set the
+ CVS_RSH environment variable to a script which uses rsh to
+ invoke another rsh on a proxy machine. */
+ char *cvs_rsh = (root->cvs_rsh != NULL
+ ? root->cvs_rsh : getenv ("CVS_RSH"));
+ char *cvs_server = (root->cvs_server != NULL
+ ? root->cvs_server : getenv ("CVS_SERVER"));
+ char *command;
+ int tofd, fromfd;
+ int child_pid;
+
+ if (!cvs_rsh)
+ cvs_rsh = RSH_DFLT;
+ if (!cvs_server)
+ cvs_server = "cvs";
+
+ /* Pass the command to rsh as a single string. This shouldn't
+ * affect most rsh servers at all, and will pacify some buggy
+ * versions of rsh that grab switches out of the middle of the
+ * command (they're calling the GNU getopt routines incorrectly).
+ *
+ * If you are running a very old (Nov 3, 1994, before 1.5)
+ * version of the server, you need to make sure that your .bashrc
+ * on the server machine does not set CVSROOT to something
+ * containing a colon (or better yet, upgrade the server).
+ */
+ command = Xasprintf ("%s server", cvs_server);
+
+ {
+ char *argv[10];
+ char **p = argv;
+
+ *p++ = cvs_rsh;
+
+ /* If the login names differ between client and server
+ * pass it on to rsh.
+ */
+ if (root->username != NULL)
+ {
+ *p++ = "-l";
+ *p++ = root->username;
+ }
+
+ *p++ = root->hostname;
+ *p++ = command;
+ *p++ = NULL;
+
+ if (trace)
+ {
+ int i;
+
+ fprintf (stderr, " -> Starting server: ");
+ for (i = 0; argv[i]; i++)
+ fprintf (stderr, "%s ", argv[i]);
+ putc ('\n', stderr);
+ }
+ child_pid = piped_child (argv, &tofd, &fromfd, true);
+
+ if (child_pid < 0)
+ error (1, errno, "cannot start server via rsh");
+ }
+ free (command);
+
+ make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p,
+ from_server_p, 0);
+}
+
+# endif /* START_RSH_WITH_POPEN_RW */
+
+#endif /* NO_EXT_METHOD */
+
+#endif /* CLIENT_SUPPORT */
diff --git a/src/rsh-client.h b/src/rsh-client.h
new file mode 100644
index 0000000..01d102b
--- /dev/null
+++ b/src/rsh-client.h
@@ -0,0 +1,19 @@
+/* CVS rsh client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+
+#ifndef RSH_CLIENT_H__
+#define RSH_CLIENT_H__
+
+void start_rsh_server (cvsroot_t *, struct buffer **, struct buffer **);
+
+#endif
diff --git a/src/run.c b/src/run.c
new file mode 100644
index 0000000..a97a7e4
--- /dev/null
+++ b/src/run.c
@@ -0,0 +1,608 @@
+/* run.c --- routines for executing subprocesses.
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+
+#ifndef HAVE_UNISTD_H
+extern int execvp (char *file, char **argv);
+#endif
+
+
+
+/*
+ * To exec a program under CVS, first call run_setup() to setup initial
+ * arguments. The argument to run_setup will be parsed into whitespace
+ * separated words and added to the global run_argv list.
+ *
+ * Then, optionally call run_add_arg() for each additional argument that you'd
+ * like to pass to the executed program.
+ *
+ * Finally, call run_exec() to execute the program with the specified arguments.
+ * The execvp() syscall will be used, so that the PATH is searched correctly.
+ * File redirections can be performed in the call to run_exec().
+ */
+static char **run_argv;
+static int run_argc;
+static size_t run_arg_allocated;
+
+
+
+void
+run_arg_free_p (int argc, char **argv)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ free (argv[i]);
+}
+
+
+
+/* VARARGS */
+void
+run_setup (const char *prog)
+{
+ char *run_prog;
+ char *buf, *d, *s;
+ size_t length;
+ size_t doff;
+ char inquotes;
+ int dolastarg;
+
+ /* clean out any malloc'ed values from run_argv */
+ run_arg_free_p (run_argc, run_argv);
+ run_argc = 0;
+
+ run_prog = xstrdup (prog);
+
+ s = run_prog;
+ d = buf = NULL;
+ length = 0;
+ dolastarg = 1;
+ inquotes = '\0';
+ doff = d - buf;
+ expand_string(&buf, &length, doff + 1);
+ d = buf + doff;
+ while ((*d = *s++) != '\0')
+ {
+ switch (*d)
+ {
+ case '\\':
+ if (*s) *d = *s++;
+ d++;
+ break;
+ case '"':
+ case '\'':
+ if (inquotes == *d) inquotes = '\0';
+ else inquotes = *d;
+ break;
+ case ' ':
+ case '\t':
+ if (inquotes) d++;
+ else
+ {
+ *d = '\0';
+ run_add_arg (buf);
+ d = buf;
+ while (isspace(*s)) s++;
+ if (!*s) dolastarg = 0;
+ }
+ break;
+ default:
+ d++;
+ break;
+ }
+ doff = d - buf;
+ expand_string(&buf, &length, doff + 1);
+ d = buf + doff;
+ }
+ if (dolastarg) run_add_arg (buf);
+ /* put each word into run_argv, allocating it as we go */
+ if (buf) free (buf);
+ free (run_prog);
+}
+
+
+
+void
+run_add_arg_p (int *iargc, size_t *iarg_allocated, char ***iargv,
+ const char *s)
+{
+ /* allocate more argv entries if we've run out */
+ if (*iargc >= *iarg_allocated)
+ {
+ *iarg_allocated += 50;
+ *iargv = xnrealloc (*iargv, *iarg_allocated, sizeof (char **));
+ }
+
+ if (s)
+ (*iargv)[(*iargc)++] = xstrdup (s);
+ else
+ (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */
+}
+
+
+
+void
+run_add_arg (const char *s)
+{
+ run_add_arg_p (&run_argc, &run_arg_allocated, &run_argv, s);
+}
+
+
+
+int
+run_exec (const char *stin, const char *stout, const char *sterr, int flags)
+{
+ int shin, shout, sherr;
+ int mode_out, mode_err;
+ int status;
+ int rc = -1;
+ int rerrno = 0;
+ int pid, w;
+
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_mask, sigset_omask;
+ struct sigaction act, iact, qact;
+
+#else
+#ifdef BSD_SIGNALS
+ int mask;
+ struct sigvec vec, ivec, qvec;
+
+#else
+ RETSIGTYPE (*istat) (), (*qstat) ();
+#endif
+#endif
+
+ if (trace)
+ {
+ cvs_outerr (
+#ifdef SERVER_SUPPORT
+ server_active ? "S" :
+#endif
+ " ", 1);
+ cvs_outerr (" -> system (", 0);
+ run_print (stderr);
+ cvs_outerr (")\n", 0);
+ }
+ if (noexec && (flags & RUN_REALLY) == 0)
+ return 0;
+
+ /* make sure that we are null terminated, since we didn't calloc */
+ run_add_arg (NULL);
+
+ /* setup default file descriptor numbers */
+ shin = 0;
+ shout = 1;
+ sherr = 2;
+
+ /* set the file modes for stdout and stderr */
+ mode_out = mode_err = O_WRONLY | O_CREAT;
+ mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
+ mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
+
+ if (stin && (shin = open (stin, O_RDONLY)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for reading (prog %s)",
+ stin, run_argv[0]);
+ goto out0;
+ }
+ if (stout && (shout = open (stout, mode_out, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ stout, run_argv[0]);
+ goto out1;
+ }
+ if (sterr && (flags & RUN_COMBINED) == 0)
+ {
+ if ((sherr = open (sterr, mode_err, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ sterr, run_argv[0]);
+ goto out2;
+ }
+ }
+
+ /* Make sure we don't flush this twice, once in the subprocess. */
+ cvs_flushout();
+ cvs_flusherr();
+
+ /* The output files, if any, are now created. Do the fork and dups.
+
+ We use vfork not so much for a performance boost (the
+ performance boost, if any, is modest on most modern unices),
+ but for the sake of systems without a memory management unit,
+ which find it difficult or impossible to implement fork at all
+ (e.g. Amiga). The other solution is spawn (see
+ windows-NT/run.c). */
+
+#ifdef HAVE_VFORK
+ pid = vfork ();
+#else
+ pid = fork ();
+#endif
+ if (pid == 0)
+ {
+ if (shin != 0)
+ {
+ (void) dup2 (shin, 0);
+ (void) close (shin);
+ }
+ if (shout != 1)
+ {
+ (void) dup2 (shout, 1);
+ (void) close (shout);
+ }
+ if (flags & RUN_COMBINED)
+ (void) dup2 (1, 2);
+ else if (sherr != 2)
+ {
+ (void) dup2 (sherr, 2);
+ (void) close (sherr);
+ }
+
+#ifdef SETXID_SUPPORT
+ /*
+ ** This prevents a user from creating a privileged shell
+ ** from the text editor when the SETXID_SUPPORT option is selected.
+ */
+ if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
+ {
+ error (0, errno, "cannot set egid to gid");
+ _exit (127);
+ }
+#endif
+
+ /* dup'ing is done. try to run it now */
+ (void) execvp (run_argv[0], run_argv);
+ error (0, errno, "cannot exec %s", run_argv[0]);
+ _exit (127);
+ }
+ else if (pid == -1)
+ {
+ rerrno = errno;
+ goto out;
+ }
+
+ /* the parent. Ignore some signals for now */
+#ifdef POSIX_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ act.sa_handler = SIG_IGN;
+ (void) sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ (void) sigaction (SIGINT, &act, &iact);
+ (void) sigaction (SIGQUIT, &act, &qact);
+ }
+ else
+ {
+ (void) sigemptyset (&sigset_mask);
+ (void) sigaddset (&sigset_mask, SIGINT);
+ (void) sigaddset (&sigset_mask, SIGQUIT);
+ (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
+ }
+#else
+#ifdef BSD_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ memset (&vec, 0, sizeof vec);
+ vec.sv_handler = SIG_IGN;
+ (void) sigvec (SIGINT, &vec, &ivec);
+ (void) sigvec (SIGQUIT, &vec, &qvec);
+ }
+ else
+ mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
+#else
+ istat = signal (SIGINT, SIG_IGN);
+ qstat = signal (SIGQUIT, SIG_IGN);
+#endif
+#endif
+
+ /* wait for our process to die and munge return status */
+#ifdef POSIX_SIGNALS
+ while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+ ;
+#else
+ while ((w = wait (&status)) != pid)
+ {
+ if (w == -1 && errno != EINTR)
+ break;
+ }
+#endif
+
+ if (w == -1)
+ {
+ rc = -1;
+ rerrno = errno;
+ }
+#ifndef VMS /* status is return status */
+ else if (WIFEXITED (status))
+ rc = WEXITSTATUS (status);
+ else if (WIFSIGNALED (status))
+ {
+ if (WTERMSIG (status) == SIGPIPE)
+ error (1, 0, "broken pipe");
+ rc = 2;
+ }
+ else
+ rc = 1;
+#else /* VMS */
+ rc = WEXITSTATUS (status);
+#endif /* VMS */
+
+ /* restore the signals */
+#ifdef POSIX_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ (void) sigaction (SIGINT, &iact, NULL);
+ (void) sigaction (SIGQUIT, &qact, NULL);
+ }
+ else
+ (void) sigprocmask (SIG_SETMASK, &sigset_omask, NULL);
+#else
+#ifdef BSD_SIGNALS
+ if (flags & RUN_SIGIGNORE)
+ {
+ (void) sigvec (SIGINT, &ivec, NULL);
+ (void) sigvec (SIGQUIT, &qvec, NULL);
+ }
+ else
+ (void) sigsetmask (mask);
+#else
+ (void) signal (SIGINT, istat);
+ (void) signal (SIGQUIT, qstat);
+#endif
+#endif
+
+ /* cleanup the open file descriptors */
+ out:
+ if (sterr)
+ (void) close (sherr);
+ else
+ /* ensure things are received by the parent in the correct order
+ * relative to the protocol pipe
+ */
+ cvs_flusherr();
+ out2:
+ if (stout)
+ (void) close (shout);
+ else
+ /* ensure things are received by the parent in the correct order
+ * relative to the protocol pipe
+ */
+ cvs_flushout();
+ out1:
+ if (stin)
+ (void) close (shin);
+
+ out0:
+ if (rerrno)
+ errno = rerrno;
+ return rc;
+}
+
+
+
+void
+run_print (FILE *fp)
+{
+ int i;
+ void (*outfn) (const char *, size_t);
+
+ if (fp == stderr)
+ outfn = cvs_outerr;
+ else if (fp == stdout)
+ outfn = cvs_output;
+ else
+ {
+ error (1, 0, "internal error: bad argument to run_print");
+ /* Solely to placate gcc -Wall.
+ FIXME: it'd be better to use a function named `fatal' that
+ is known never to return. Then kludges wouldn't be necessary. */
+ outfn = NULL;
+ }
+
+ for (i = 0; i < run_argc; i++)
+ {
+ (*outfn) ("'", 1);
+ (*outfn) (run_argv[i], 0);
+ (*outfn) ("'", 1);
+ if (i != run_argc - 1)
+ (*outfn) (" ", 1);
+ }
+}
+
+
+
+/* Return value is NULL for error, or if noexec was set. If there was an
+ error, return NULL and I'm not sure whether errno was set (the Red Hat
+ Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec
+ case complicates this even aside from popen behavior). */
+FILE *
+run_popen (const char *cmd, const char *mode)
+{
+ TRACE (TRACE_FUNCTION, "run_popen (%s,%s)", cmd, mode);
+ if (noexec)
+ return NULL;
+
+ return popen (cmd, mode);
+}
+
+
+
+/* Work around an OpenSSH problem: it can put its standard file
+ descriptors into nonblocking mode, which will mess us up if we
+ share file descriptions with it. The simplest workaround is
+ to create an intervening process between OpenSSH and the
+ actual stderr. */
+
+static void
+work_around_openssh_glitch (void)
+{
+ pid_t pid;
+ int stderr_pipe[2];
+ struct stat sb;
+
+ /* Do nothing unless stderr is a file that is affected by
+ nonblocking mode. */
+ if (!(fstat (STDERR_FILENO, &sb) == 0
+ && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode)
+ || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode))))
+ return;
+
+ if (pipe (stderr_pipe) < 0)
+ error (1, errno, "cannot create pipe");
+ pid = fork ();
+ if (pid < 0)
+ error (1, errno, "cannot fork");
+ if (pid != 0)
+ {
+ /* Still in child of original process. Act like "cat -u". */
+ char buf[1 << 13];
+ ssize_t inbytes;
+ pid_t w;
+ int status;
+
+ if (close (stderr_pipe[1]) < 0)
+ error (1, errno, "cannot close pipe");
+
+ while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0)
+ {
+ size_t outbytes = 0;
+
+ if (inbytes < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ error (1, errno, "reading from pipe");
+ }
+
+ do
+ {
+ ssize_t w = write (STDERR_FILENO,
+ buf + outbytes, inbytes - outbytes);
+ if (w < 0)
+ {
+ if (errno == EINTR)
+ w = 0;
+ if (w < 0)
+ _exit (1);
+ }
+ outbytes += w;
+ }
+ while (inbytes != outbytes);
+ }
+
+ /* Done processing output from grandchild. Propagate
+ its exit status back to the parent. */
+ while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+ continue;
+ if (w < 0)
+ error (1, errno, "waiting for child");
+ if (!WIFEXITED (status))
+ {
+ if (WIFSIGNALED (status))
+ raise (WTERMSIG (status));
+ error (1, errno, "child did not exit cleanly");
+ }
+ _exit (WEXITSTATUS (status));
+ }
+
+ /* Grandchild of original process. */
+ if (close (stderr_pipe[0]) < 0)
+ error (1, errno, "cannot close pipe");
+
+ if (stderr_pipe[1] != STDERR_FILENO)
+ {
+ if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
+ error (1, errno, "cannot dup2 pipe");
+ if (close (stderr_pipe[1]) < 0)
+ error (1, errno, "cannot close pipe");
+ }
+}
+
+
+
+int
+piped_child (char *const *command, int *tofdp, int *fromfdp, bool fix_stderr)
+{
+ int pid;
+ int to_child_pipe[2];
+ int from_child_pipe[2];
+
+ if (pipe (to_child_pipe) < 0)
+ error (1, errno, "cannot create pipe");
+ if (pipe (from_child_pipe) < 0)
+ error (1, errno, "cannot create pipe");
+
+#ifdef USE_SETMODE_BINARY
+ setmode (to_child_pipe[0], O_BINARY);
+ setmode (to_child_pipe[1], O_BINARY);
+ setmode (from_child_pipe[0], O_BINARY);
+ setmode (from_child_pipe[1], O_BINARY);
+#endif
+
+ pid = fork ();
+ if (pid < 0)
+ error (1, errno, "cannot fork");
+ if (pid == 0)
+ {
+ if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
+ error (1, errno, "cannot dup2 pipe");
+ if (close (to_child_pipe[1]) < 0)
+ error (1, errno, "cannot close pipe");
+ if (close (from_child_pipe[0]) < 0)
+ error (1, errno, "cannot close pipe");
+ if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
+ error (1, errno, "cannot dup2 pipe");
+
+ if (fix_stderr)
+ work_around_openssh_glitch ();
+
+ /* Okay to cast out const below - execvp don't return nohow. */
+ execvp ((char *)command[0], (char **)command);
+ error (1, errno, "cannot exec %s", command[0]);
+ }
+ if (close (to_child_pipe[0]) < 0)
+ error (1, errno, "cannot close pipe");
+ if (close (from_child_pipe[1]) < 0)
+ error (1, errno, "cannot close pipe");
+
+ *tofdp = to_child_pipe[1];
+ *fromfdp = from_child_pipe[0];
+ return pid;
+}
+
+
+
+int
+run_piped (int *tofdp, int *fromfdp)
+{
+ run_add_arg (NULL);
+ return piped_child (run_argv, tofdp, fromfdp, false);
+}
+
+
+
+void
+close_on_exec (int fd)
+{
+#ifdef F_SETFD
+ if (fcntl (fd, F_SETFD, 1) == -1)
+ error (1, errno, "can't set close-on-exec flag on %d", fd);
+#endif
+}
diff --git a/src/sanity.config.sh.in b/src/sanity.config.sh.in
new file mode 100644
index 0000000..7775124
--- /dev/null
+++ b/src/sanity.config.sh.in
@@ -0,0 +1 @@
+RSH_DFLT=@RSH_DFLT@
diff --git a/src/sanity.sh b/src/sanity.sh
new file mode 100755
index 0000000..6d068ad
--- /dev/null
+++ b/src/sanity.sh
@@ -0,0 +1,35660 @@
+#! /bin/sh
+:
+# sanity.sh -- a growing testsuite for cvs.
+#
+# The copyright notice said: "Copyright (C) 1992, 1993 Cygnus Support"
+# I'm not adding new copyright notices for new years as our recent
+# practice has been to include copying terms without copyright notices.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# Original Author: K. Richard Pixley
+
+# usage:
+usage ()
+{
+ echo "Usage: `basename $0` --help"
+ echo "Usage: `basename $0` [--eklr] [-c CONFIG-FILE] [-f FROM-TEST] \\"
+ echo " [-h HOSTNAME] [-s CVS-FOR-CVS-SERVER] CVS-TO-TEST \\"
+ echo " [TESTS-TO-RUN...]"
+}
+
+exit_usage ()
+{
+ usage 1>&2
+ exit 2
+}
+
+exit_help ()
+{
+ usage
+ echo
+ echo "-H|--help display this text"
+ echo "-c CONFIG-FILE"
+ echo "--config=CONFIG_FILE"
+ echo " use an alternate test suite config file (defaults to"
+ echo " \`sanity.config.sh' in the same directory as"
+ echo " CVS-TO-TEST is found in)"
+ echo "-e|--skipfail Treat tests that would otherwise be nonfatally skipped"
+ echo " for reasons like missing tools as failures, exiting"
+ echo " with an error message. Also treat warnings as"
+ echo " failures."
+ echo "-f FROM-TEST"
+ echo "--from-test=FROM-TEST"
+ echo " run TESTS-TO-RUN, skipping all tests in the list before"
+ echo " FROM-TEST"
+ echo "-h HOSTNAME"
+ echo "--hostname HOSTNAME"
+ echo " Use :ext:HOSTNAME to run remote tests rather than"
+ echo " :fork:. Implies --remote and assumes that \$TESTDIR"
+ echo " resolves to the same directory on both the client and"
+ echo " the server."
+ echo "-k|--keep try to keep directories created by individual tests"
+ echo " around, exiting after the first test which supports"
+ echo " --keep"
+ echo "-l|--link-root"
+ echo " test CVS using a symlink to a real CVSROOT"
+ echo "-n|--noredirect"
+ echo " test a secondary/primary CVS server (writeproxy)"
+ echo " configuration with the Redirect response disabled"
+ echo " (implies --proxy)."
+ echo "-p|--proxy test a secondary/primary CVS server (writeproxy)"
+ echo " configuration (implies --remote)."
+ echo "-r|--remote test client/server, as opposed to local, CVS"
+ echo "-s CVS-FOR-CVS-SERVER"
+ echo "--server=CVS-FOR-CVS-SERVER"
+ echo " use CVS-FOR-CVS-SERVER as the path to the CVS SERVER"
+ echo " executable to be tested (defaults to CVS-TO-TEST and"
+ echo " implies --remote)"
+ echo
+ echo "CVS-TO-TEST the path to the CVS executable to be tested; used as"
+ echo " the path to the CVS client when CVS-FOR-CVS-SERVER is"
+ echo " specified"
+ echo "TESTS-TO-RUN the names of the tests to run (defaults to all tests)"
+ exit 2
+}
+
+checklongoptarg()
+{
+ if test "x$1" != xoptional && test -z "$OPTARG"; then
+ echo "option \`--$LONGOPT' requires an argument" >&2
+ exit_usage
+ fi
+}
+
+# See TODO list at end of file.
+
+# required to make this script work properly.
+unset CVSREAD
+
+# We want to invoke a predictable set of i18n behaviors, not whatever
+# the user running this script might have set.
+# In particular:
+# 'sort' and tabs and spaces (LC_COLLATE).
+# Messages from getopt (LC_MESSAGES) (in the future, CVS itself might
+# also alter its messages based on LC_MESSAGES).
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+
+# And a few tests want a predictable umask.
+umask 0002
+
+#
+# Initialize the test counts.
+#
+passed=0
+skipped=0
+warnings=0
+
+
+
+#
+# read our options
+#
+unset configfile
+unset fromtest
+unset remotehost
+unset rootoptions
+keep=false
+linkroot=false
+noredirect=false
+proxy=false
+remote=false
+servercvs=false
+skipfail=false
+while getopts Hc:ef:h:klnprs:-: option ; do
+ # convert the long opts to short opts
+ if test x$option = x-; then
+ # remove any argument
+ if echo "$OPTARG" |grep = >/dev/null; then
+ LONGOPT=`echo "$OPTARG" |sed 's/=.*$//'`
+ OPTARG=`echo "$OPTARG" |sed -e 's/^.*=//'`
+ else
+ LONGOPT=$OPTARG
+ OPTARG=
+ fi
+ # Convert LONGOPT to lower case
+ LONGOPT=`echo "$LONGOPT" |sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+ case "$LONGOPT" in
+ c|co|con|conf|confi|config)
+ option=c
+ checklongoptarg
+ ;;
+ f|fr|fro|from|from-|from-t|from-te|from-tes|from-test)
+ option=f
+ checklongoptarg
+ ;;
+ h)
+ echo "\`--h' is ambiguous. Could mean \`--help' or \`--hostname'" >&2
+ exit_usage
+ ;;
+ he|hel|help)
+ option=H
+ OPTARG=
+ ;;
+ ho|hos|host|hostn|hostna|hostnam|hostname)
+ option=h
+ checklongoptarg
+ ;;
+ k|ke|kee|keep)
+ option=k
+ OPTARG=
+ ;;
+ l|li|lin|link|link-|link-r]|link-ro|link-roo|link-root)
+ option=l
+ OPTARG=
+ ;;
+ n|no|nor|nore|nored|noredi|noredir|noredire|noredirec|noredirect)
+ option=n
+ OPTARG=
+ ;;
+ p|pr|pro|prox|proxy)
+ option=p
+ OPTARG=
+ ;;
+ r|re|rem|remo|remot|remote)
+ option=r
+ OPTARG=
+ ;;
+ s)
+ echo "\`--s' is ambiguous. Could mean \`--server' or \`--skipfail'" >&2
+ exit_usage
+ ;;
+ se|ser|serv|serve|server)
+ option=s
+ checklongoptarg
+ ;;
+ sk|ski|skip|skipf|skipfa|skipfai|skipfail)
+ option=e
+ OPTARG=
+ ;;
+ *)
+ option=\?
+ OPTARG=
+ esac
+ fi
+ case "$option" in
+ c)
+ configfile="$OPTARG"
+ ;;
+ e)
+ skipfail=:
+ ;;
+ f)
+ fromtest="$OPTARG"
+ ;;
+ h)
+ # Set a remotehost to run the remote tests on via :ext:
+ # Implies `-r' and assumes that $TESTDIR resolves to the same
+ # directory on the client and the server.
+ remotehost="$OPTARG"
+ remote=:
+ ;;
+ H)
+ exit_help
+ ;;
+ k)
+ # The -k (keep) option will eventually cause all the tests to
+ # leave around the contents of the /tmp directory; right now only
+ # some implement it. Not originally intended to be useful with
+ # more than one test, but this should work if each test uses a
+ # uniquely named dir (use the name of the test).
+ keep=:
+ ;;
+ l)
+ linkroot=:
+ ;;
+ n)
+ proxy=:
+ noredirect=:
+ remote=:
+ ;;
+ p)
+ proxy=:
+ remote=:
+ ;;
+ r)
+ remote=:
+ ;;
+ s)
+ servercvs="$OPTARG"
+ remote=:
+ ;;
+ \?)
+ exit_usage
+ ;;
+ esac
+done
+
+# boot the arguments we used above
+while test $OPTIND -gt 1 ; do
+ shift
+ OPTIND=`expr $OPTIND - 1`
+done
+
+# Use full path for CVS executable, so that CVS_SERVER gets set properly
+# for remote.
+case $1 in
+"")
+ exit_usage
+ ;;
+/*)
+ testcvs=$1
+ ;;
+*)
+ testcvs=`pwd`/$1
+ ;;
+esac
+shift
+
+# Verify that $testcvs looks like CVS.
+# we can't use test -x since BSD 4.3 doesn't support it.
+if test ! -f $testcvs || test ! -r $testcvs; then
+ echo "No such file or file not readable: $testcvs" >&2
+ exit 1
+fi
+if $testcvs --version </dev/null 2>/dev/null |
+ grep '^Concurrent Versions System' >/dev/null 2>&1; then :; else
+ echo "Not a CVS executable: $testcvs" >&2
+ exit 1
+fi
+
+# If $remotehost is set, warn if $TESTDIR isn't since we are pretty sure
+# that its default value of `/tmp/cvs-sanity' will not resolve to the same
+# directory on two different machines.
+if test -n "$remotehost" && test -z "$TESTDIR"; then
+ echo "WARNING: CVS server hostname is set and \$TESTDIR is not. If" >&2
+ echo "$remotehost is not the local machine, then it is unlikely that" >&2
+ echo "the default value assigned to \$TESTDIR will resolve to the same" >&2
+ echo "directory on both this client and the CVS server." >&2
+fi
+
+# Read our config file if we can find it.
+#
+# The config file should always be located in the same directory as the CVS
+# executable, unless we are testing an executable outside of the build
+# directory. In this case, we echo a warning and attempt to assume the most
+# portable configuration.
+if test -z "$configfile"; then
+ configfile=`dirname $testcvs`/sanity.config.sh
+fi
+if test -r "$configfile"; then
+ . "$configfile"
+else
+ echo "WARNING: Failed to locate test suite config file" >&2
+ echo " \`$configfile'." >&2
+fi
+
+
+
+# Set a default value for $CVS_RSH. The sanity.config.sh file will
+# have the configured value in the RSH_DFLT variable.
+#
+: ${CVS_RSH=${RSH_DFLT:-ssh}}; export CVS_RSH
+
+if test -n "$remotehost"; then
+ # Verify that $CVS_RSH $remotehost works.
+ result=`$CVS_RSH $remotehost 'echo test'`
+ if test $? != 0 || test "x$result" != "xtest"; then
+ echo "\`$CVS_RSH $remotehost' failed." >&2
+ exit 1
+ fi
+fi
+
+case "$servercvs" in
+"")
+ exit_usage
+ ;;
+false)
+ ;;
+/*)
+ ;;
+*)
+ servercvs=`pwd`/$servercvs
+ ;;
+esac
+
+if test false != $servercvs; then
+ # Allow command line to override $CVS_SERVER
+ CVS_SERVER=$servercvs
+else
+ # default $CVS_SERVER to ${testcvs}
+ : ${CVS_SERVER=$testcvs}
+ # With the previous command, effectively defaults $servercvs to $CVS_SERVER,
+ # then $testcvs
+ servercvs=$CVS_SERVER
+fi
+export CVS_SERVER
+servercvs_orig=$servercvs
+
+# Fail in client/server mode if our ${servercvs} does not contain server
+# support.
+if $remote; then
+ if test -n "$remotehost"; then
+ if $CVS_RSH $remotehost "test ! -f ${servercvs} || test ! -r ${servercvs}"
+ then
+ echo "No such file or file not readable: $remotehost:${testcvs}" >&2
+ exit 1
+ fi
+ if $CVS_RSH $remotehost "${servercvs} --version </dev/null 2>/dev/null |
+ grep '^Concurrent Versions System' >/dev/null 2>&1"; then :; else
+ echo "Not a CVS executable: $remotehost:${servercvs}" >&2
+ exit 1
+ fi
+ if $CVS_RSH $remotehost "${servercvs} --version </dev/null |
+ grep '^Concurrent.*(.*server)$' >/dev/null 2>&1"; then :; else
+ echo "CVS executable \`$remotehost:${servercvs}' does not contain server support." >&2
+ exit 1
+ fi
+ else
+ if test ! -f ${servercvs} || test ! -r ${servercvs}; then
+ echo "No such file or file not readable: ${testcvs}" >&2
+ exit 1
+ fi
+ if ${servercvs} --version </dev/null 2>/dev/null |
+ grep '^Concurrent Versions System' >/dev/null 2>&1; then :; else
+ echo "Not a CVS executable: ${servercvs}" >&2
+ exit 1
+ fi
+ if ${servercvs} --version </dev/null |
+ grep '^Concurrent.*(.*server)$' >/dev/null 2>&1; then :; else
+ echo "CVS executable \`${servercvs}' does not contain server support." >&2
+ exit 1
+ fi
+ fi
+fi
+
+# Fail in client/server mode if our ${testcvs} does not contain client
+# support.
+if $remote; then
+ if ${testcvs} --version </dev/null |
+ grep '^Concurrent.*(client.*)$' >/dev/null 2>&1; then :; else
+ echo "CVS executable \`${testcvs}' does not contain client support." >&2
+ exit 1
+ fi
+fi
+
+# For the "fork" tests.
+if ${testcvs} --version </dev/null |
+ grep '^Concurrent.*(.*server)$' >/dev/null 2>&1
+then
+ testcvs_server_support=:
+else
+ testcvs_server_support=false
+fi
+
+
+
+dokeep()
+{
+ if ${keep}; then
+ echo "Keeping ${TESTDIR} for test case \`${what}' and exiting due to --keep"
+ exit 0
+ fi
+}
+
+
+
+###
+### GUTS
+###
+
+# "debugger"
+#set -x
+
+echo 'This test should produce no other output than this message, and a final "OK".'
+echo '(Note that the test can take an hour or more to run and periodically stops'
+echo 'for as long as one minute. Do not assume there is a problem just because'
+echo 'nothing seems to happen for a long time. If you cannot live without'
+echo "running status, try the command: \`tail -f check.log' from another window.)"
+
+# Regexp to match what the CVS client will call itself in output that it prints.
+# FIXME: we don't properly quote this--if the name contains . we'll
+# just spuriously match a few things; if the name contains other regexp
+# special characters we are probably in big trouble.
+CPROG=`basename ${testcvs} |sed 's/\.exe$//'`
+# And the regexp for the CVS server when we have one. In local mode, this
+# defaults to $CPROG since $servercvs already did.
+# FIXCVS: There are a few places in error messages where CVS suggests a command
+# and outputs $SPROG as the suggested executable. This could hopefully use
+# MT (tagged text - see doc/cvs-client.texi) to request that the client print
+# its own name.
+SPROG=`basename ${servercvs} |sed 's/\.exe$//'`
+
+
+# Match the hostname
+hostname="[-_.a-zA-Z0-9]*"
+
+# Regexp to match a commitid
+commitid="[a-zA-Z0-9]*"
+
+# Regexp to match the name of a temporary file (from cvs_temp_name).
+# This appears in certain diff output.
+tempfile="cvs[-a-zA-Z0-9.%_]*"
+# $tempname set after $TMPDIR, below.
+
+# Regexp to match a date in RFC822 format (as amended by RFC1123).
+RFCDATE="[a-zA-Z0-9 ][a-zA-Z0-9 ]* [0-9:][0-9:]* -0000"
+RFCDATE_EPOCH="1 Jan 1970 00:00:00 -0000"
+
+# Special times used in touch -t commands and the regular expresions
+# to match them. Now that the tests set TZ=UTC0, it
+# should be easier to be more exact in their regexp.
+TOUCH1971="197107040343"
+# This date regexp was 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]
+ISO8601DATE1971="1971-07-04 03:43:[0-9][0-9] [+-]0000"
+
+TOUCH2034="203412251801"
+# This date regexp was 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]
+ISO8601DATE2034="2034-12-25 18:01:[0-9][0-9] [+-]0000"
+
+# Used in admin tests for exporting RCS files.
+# The RAWRCSDATE..... format is for internal ,v files and
+# the ISO8601DATE..... format is to allow for a regular expression in
+# 'cvs log' output patterns. The tests that use this set of specific
+# ${ISO8601DATE.....} variables also force TZ=UTC0 for the test.
+RAWRCSDATE2000A="2000.11.24.15.58.37"
+RAWRCSDATE1996A="96.11.24.15.57.41"
+RAWRCSDATE1996B="96.11.24.15.56.05"
+ISO8601DATE2000A="2000-11-24 15:58:37 [+-]0000"
+ISO8601DATE1996A="1996-11-24 15:57:41 [+-]0000"
+ISO8601DATE1996B="1996-11-24 15:56:05 [+-]0000"
+
+# Regexp to match the date in cvs log command output
+# This format has been enhanced in the future to accept either
+# old-style cvs log output dates or new-style ISO8601 timezone
+# information similar to the ISODATE format. The RCSKEYDATE is
+# similar, but uses '/' instead of '-' to sepearate year/month/day
+# and does not include the optional timezone offset.
+ISO8601DATE="[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9] [-+][0-1][0-9][0-6][0-9]"
+
+# Regexp to match the dates found in rcs keyword strings
+RCSKEYDATE="[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]"
+
+# Regexp to match the date in the delta section of rcs format files.
+# Dates in very old RCS files may not have included the century.
+RCSDELTADATE="[0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]"
+
+# Regexp to match a date in standard Unix format as used by rdiff
+# FIXCVS: There's no reason for rdiff to use a different date format
+# than diff does
+DATE="[a-zA-Z]* [a-zA-Z]* [ 1-3][0-9] [0-9:]* [0-9]*"
+# ISO 8601 format "yyyy-mm-dd hh:mm -0000"
+ISODATE="[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9] [+-][0-9][0-9][0-9][0-9]"
+# %p format is not well defined (nil) and hex digits are common. Using
+# ..* is a bad idea as the tests take a very long time to run due to
+# the complexity of the expressions. If you run into any other characters
+# that are used in a %p format, add them here.
+PFMT="[0-9a-zA-Z()][0-9a-zA-Z()]*"
+
+# Which directories should Which and find_tool search for executables?
+SEARCHPATH=$PATH:/usr/local/bin:/usr/contrib/bin:/usr/contrib:/usr/gnu/bin:/local/bin:/local/gnu/bin:/gnu/bin:/sw/bin:/usr/pkg/bin
+
+# Do not assume that `type -p cmd` is portable
+# Usage: Which [-a] [-x|-f|-r] prog [$SEARCHPATH:/with/directories:/to/search]
+Which() {
+ # Optional first argument for file type, defaults to -x.
+ # Second argument is the file or directory to be found.
+ # Third argument is the PATH to search.
+ # By default, print only the first file that matches,
+ # -a will cause all matches to be printed.
+ notevery=:
+ if [ "x$1" = "x-a" ]; then notevery=false; shift; fi
+ case "$1" in
+ -*) t=$1; shift ;;
+ *) t=-x ;;
+ esac
+ case "$1" in
+ # FIXME: Someday this may need to be fixed
+ # to deal better with C:\some\path\to\ssh values...
+ /*) test $t $1 && echo $1 ;;
+ *) for d in `IFS=:; echo ${2-$SEARCHPATH}`
+ do
+ test $t $d/$1 && { echo $d/$1; if $notevery; then break; fi; }
+ done
+ ;;
+ esac
+}
+
+
+# On cygwin32, we may not have /bin/sh.
+if test -r /bin/sh; then
+ TESTSHELL="/bin/sh"
+else
+ TESTSHELL=`Which -f sh`
+ if test ! -r "$TESTSHELL"; then
+ TESTSHELL="/bin/sh"
+ fi
+fi
+
+# FIXME: try things (what things? checkins?) without -m.
+#
+# Some of these tests are written to expect -Q. But testing with
+# -Q is kind of bogus, it is not the way users actually use CVS (usually).
+# So new tests probably should invoke ${testcvs} directly, rather than ${CVS}.
+# and then they've obviously got to do something with the output....
+#
+CVS="${testcvs} -Q"
+
+LOGFILE=`pwd`/check.log
+
+# Save the previous log in case the person running the tests decides
+# they want to look at it. The extension ".plog" is chosen for consistency
+# with dejagnu.
+test -f check.plog && mv check.plog check.plog~
+test -f check.log && mv check.log check.plog
+
+# Create the log file so check.log can be tailed almost immediately after
+# this script is started. Otherwise it can take up to a minute or two before
+# the log file gets created when $remotehost is specified on some systems,
+# which makes for a lot of failed `tail -f' attempts.
+touch check.log
+
+# Workaround any X11Forwarding by ssh. Otherwise this text:
+# Warning: No xauth data; using fake authentication data for X11 forwarding.
+# has been known to end up in the test results below
+# causing the test to fail.
+[ -n "$DISPLAY" ] && unset DISPLAY
+
+# The default value of /tmp/cvs-sanity for TESTDIR is dubious,
+# because it loses if two people/scripts try to run the tests
+# at the same time. Some possible solutions:
+# 1. Use /tmp/cvs-test$$. One disadvantage is that the old
+# cvs-test* directories would pile up, because they wouldn't
+# necessarily get removed.
+# 2. Have everyone/everything running the testsuite set
+# TESTDIR to some appropriate directory.
+# 3. Have the default value of TESTDIR be some variation of
+# `pwd`/cvs-sanity. The biggest problem here is that we have
+# been fairly careful to test that CVS prints in messages the
+# actual pathnames that we pass to it, rather than a different
+# pathname for the same directory, as may come out of `pwd`.
+# So this would be lost if everything was `pwd`-based. I suppose
+# if we wanted to get baroque we could start making symlinks
+# to ensure the two are different.
+if test -n "$remotehost"; then
+ # We need to set $tmp on the server since $TMPDIR is compared against
+ # messages generated by the server.
+ tmp=`$CVS_RSH $remotehost 'cd /tmp; /bin/pwd || pwd' 2>/dev/null`
+ if test $? != 0; then
+ echo "$CVS_RSH $remotehost failed." >&2
+ exit 1
+ fi
+else
+ tmp=`(cd /tmp; /bin/pwd || pwd) 2>/dev/null`
+fi
+
+# Now:
+# 1) Set TESTDIR if it's not set already
+# 2) Remove any old test remnants
+# 3) Create $TESTDIR
+# 4) Normalize TESTDIR with `cd && (/bin/pwd || pwd)`
+# (This will match CVS output later)
+: ${TESTDIR=$tmp/cvs-sanity}
+# clean any old remnants (we need the chmod because some tests make
+# directories read-only)
+if test -d $TESTDIR; then
+ chmod -R a+wx $TESTDIR
+ rm -rf $TESTDIR
+fi
+# These exits are important. The first time I tried this, if the `mkdir && cd`
+# failed then the build directory would get blown away. Some people probably
+# wouldn't appreciate that.
+mkdir $TESTDIR || exit 1
+cd $TESTDIR || exit 1
+# Ensure $TESTDIR is absolute
+if echo "$TESTDIR" |grep '^[^/]'; then
+ # Don't resolve this unless we have to. This keeps symlinks intact. This
+ # is important at least when testing using -h $remotehost, because the same
+ # value for $TESTDIR must resolve to the same directory on the client and
+ # the server and we likely used Samba, and possibly symlinks, to do this.
+ TESTDIR=`(/bin/pwd || pwd) 2>/dev/null`
+fi
+
+if test -z "$TESTDIR" || echo "$TESTDIR" |grep '^[^/]'; then
+ echo "Unable to resolve TESTDIR to an absolute directory." >&2
+ exit 1
+fi
+cd $TESTDIR
+
+
+
+: ${TIMING=false}
+if $remote; then
+ # Now override our CVS_RSH in order to forward variables which affect the
+ # test suite through. This always needs to be done when $remotehost is
+ # set, needs to be done in $proxy mode for the crerepos tests, and needs to
+ # be done in $remote mode for the writeproxy-ssh tests.
+ if $TIMING; then
+ time="/usr/bin/time -ao'$TESTDIR/time.out'"
+ else
+ time=
+ fi
+ cat >$TESTDIR/ssh-wrapper-env <<EOF
+#! $TESTSHELL
+while [ \$# -gt 0 ]
+do
+ case "\$1" in
+ *=*)
+ eval "\$1"
+ var=\`echo "\$1" | sed 's/^\\(.*\\)=.*\$/\\1/'\`
+ export \$var
+ ;;
+ *) break;;
+ esac
+ shift
+done
+exec \${1+"\$@"}
+EOF
+ chmod a+x $TESTDIR/ssh-wrapper-env
+ cat >$TESTDIR/ssh-wrapper <<EOF
+#! $TESTSHELL
+hostname=\$1
+shift
+exec \
+$CVS_RSH \
+ \$hostname \
+ $TESTDIR/ssh-wrapper-env \
+ "CVS_SERVER='\$CVS_SERVER'" \
+ "CVS_SERVER_SLEEP='\$CVS_SERVER_SLEEP'" \
+ "CVS_PARENT_SERVER_SLEEP='\$CVS_PARENT_SERVER_SLEEP'" \
+ "CVS_SERVER_LOG='\$CVS_SERVER_LOG'" \
+ "CVS_SECONDARY_LOG='\$CVS_SECONDARY_LOG'" \
+ "TMPDIR='\$TMPDIR'" \
+ "CVS_RSH='$TESTDIR/ssh-wrapper'" \
+ "CVSUMASK='\$CVSUMASK'" \
+ "CVS_PID='\$CVS_PID'" \
+ $time \
+ \${1+"\$@"}
+EOF
+ chmod a+x $TESTDIR/ssh-wrapper
+ CVS_RSH=$TESTDIR/ssh-wrapper
+fi # $remotehost
+
+
+
+# Now set $TMPDIR if the user hasn't overridden it.
+#
+# We use a $TMPDIR under $TESTDIR by default so that two tests may be run at
+# the same time without bumping heads without requiring the user to specify
+# more than $TESTDIR. See the test for leftover cvs-serv* directories near the
+# end of this script at the end of "The big loop".
+: ${TMPDIR=$TESTDIR/tmp}
+export TMPDIR
+if test -d $TMPDIR; then :; else
+ mkdir $TMPDIR
+fi
+
+
+# Regexp to match the the full path to a temporary file (from cvs_temp_name).
+# This appears in certain diff output.
+tempname=$TMPDIR/$tempfile
+
+# Make sure various tools work the way we expect, or try to find
+# versions that do.
+: ${AWK=awk}
+: ${EXPR=expr}
+: ${ID=id}
+: ${TR=tr}
+
+# Keep track of tools that are found, but do NOT work as we hope
+# in order to avoid them in future
+badtools=
+set_bad_tool ()
+{
+ badtools=$badtools:$1
+}
+is_bad_tool ()
+{
+ case ":$badtools:" in *:$1:*) return 0 ;; *) return 1 ; esac
+}
+
+version_test ()
+{
+ vercmd=$1
+ verbad=:
+ if RES=`$vercmd --version </dev/null 2>&1`; then
+ if test "X$RES" != "X--version" && test "X$RES" != "X" ; then
+ echo "$RES"
+ verbad=false
+ fi
+ fi
+ if $verbad; then
+ echo "The command \`$vercmd' does not support the --version option."
+ fi
+ # It does not really matter that --version is not supported
+ return 0
+}
+
+# Try to find a tool that satisfies all of the tests.
+# Usage: list:of:colon:separated:alternatives test1 test2 test3 test4...
+# Example: find_tool awk:gawk:nawk awk_tooltest1 awk_tooltest2
+find_tool ()
+{
+ default_TOOL=$1
+ echo find_tool: ${1+"$@"} >>$LOGFILE
+ cmds="`IFS=:; echo $1`"; shift; tooltests="${1+$@}"
+ if test -z "$tooltests"; then tooltests=version_test; fi
+ clist=; for cmd in $cmds; do clist="$clist `Which -a $cmd`"; done
+ # Make sure the default tool is just the first real command name
+ for default_TOOL in $clist `IFS=:; echo $default_TOOL`; do break; done
+ TOOL=""
+ for trytool in $clist ; do
+ pass=:
+ for tooltest in $tooltests; do
+ result=`eval $tooltest $trytool`
+ rc=$?
+ echo "Running $tooltest $trytool" >>$LOGFILE
+ if test -n "$result"; then
+ echo "$result" >>$LOGFILE
+ fi
+ if test "$rc" = "0"; then
+ echo "PASS: $tooltest $trytool" >>$LOGFILE
+ elif test "$rc" = "77"; then
+ echo "MARGINAL: $tooltest $trytool; rc=$rc" >>$LOGFILE
+ TOOL=$trytool
+ pass=false
+ else
+ set_bad_tool $trytool
+ echo "FAIL: $tooltest $trytool; rc=$rc" >>$LOGFILE
+ pass=false
+ fi
+ done
+ if $pass; then
+ echo $trytool
+ return 0
+ fi
+ done
+ if test -n "$TOOL"; then
+ echo "Notice: The default version of \`$default_TOOL' is defective." >>$LOGFILE
+ echo "using \`$TOOL' and hoping for the best." >>$LOGFILE
+ echo "Notice: The default version of \`$default_TOOL' is defective." >&2
+ echo "using \`$TOOL' and hoping for the best." >&2
+ echo $TOOL
+ else
+ echo $default_TOOL
+ fi
+}
+
+id_tool_test ()
+{
+ id=$1
+ if $id -u >/dev/null 2>&1 && $id -un >/dev/null 2>&1; then
+ return 0
+ else
+ echo "Running these tests requires an \`id' program that understands the"
+ echo "-u and -n flags. Make sure that such an id (GNU, or many but not"
+ echo "all vendor-supplied versions) is in your path."
+ return 1
+ fi
+}
+
+ID=`find_tool id version_test id_tool_test`
+echo "Using ID=$ID" >>$LOGFILE
+
+# You can't run CVS as root; print a nice error message here instead
+# of somewhere later, after making a mess.
+for pass in false :; do
+ case "`$ID -u 2>/dev/null`" in
+ "0")
+ echo "Test suite does not work correctly when run as root" >&2
+ exit 1
+ ;;
+
+ *)
+ break
+ ;;
+ esac
+done
+
+# Cause NextStep 3.3 users to lose in a more graceful fashion.
+expr_tooltest1 ()
+{
+expr=$1
+if $expr 'abc
+def' : 'abc
+def' >/dev/null; then
+ # good, it works
+ return 0
+else
+ echo 'Running these tests requires an "expr" program that can handle'
+ echo 'multi-line patterns. Make sure that such an expr (GNU, or many but'
+ echo 'not all vendor-supplied versions) is in your path.'
+ return 1
+fi
+}
+
+# Warn SunOS, SysVr3.2, etc., users that they may be partially losing
+# if we can't find a GNU expr to ease their troubles...
+expr_tooltest2 ()
+{
+expr=$1
+if $expr 'a
+b' : 'a
+c' >/dev/null; then
+ echo 'Warning: you are using a version of expr that does not correctly'
+ echo 'match multi-line patterns. Some tests may spuriously pass or fail.'
+ echo 'You may wish to make sure GNU expr is in your path.'
+ return 1
+else
+ return 0
+fi
+}
+
+expr_create_bar ()
+{
+echo 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' >${TESTDIR}/foo
+cat ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo >${TESTDIR}/bar
+cat ${TESTDIR}/bar ${TESTDIR}/bar ${TESTDIR}/bar ${TESTDIR}/bar >${TESTDIR}/foo
+cat ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo >${TESTDIR}/bar
+rm -f ${TESTDIR}/foo
+}
+
+expr_tooltest3 ()
+{
+expr=$1
+# More SunOS lossage...
+test ! -f ${TESTDIR}/bar && expr_create_bar
+if $expr "`cat ${TESTDIR}/bar`" : "`cat ${TESTDIR}/bar`" >/dev/null; then
+ : good, it works
+else
+ echo 'Warning: you are using a version of expr that does not correctly'
+ echo 'match large patterns. Some tests may spuriously pass or fail.'
+ echo 'You may wish to make sure GNU expr is in your path.'
+ return 1
+fi
+if $expr "`cat ${TESTDIR}/bar`x" : "`cat ${TESTDIR}/bar`y" >/dev/null; then
+ echo 'Warning: you are using a version of expr that does not correctly'
+ echo 'match large patterns. Some tests may spuriously pass or fail.'
+ echo 'You may wish to make sure GNU expr is in your path.'
+ return 1
+fi
+# good, it works
+return 0
+}
+
+# That we should have to do this is total bogosity, but GNU expr
+# version 1.9.4-1.12 uses the emacs definition of "$" instead of the unix
+# (e.g. SunOS 4.1.3 expr) one. Rumor has it this will be fixed in the
+# next release of GNU expr after 1.12 (but we still have to cater to the old
+# ones for some time because they are in many linux distributions).
+ENDANCHOR="$"
+expr_set_ENDANCHOR ()
+{
+expr=$1
+ENDANCHOR="$"
+if $expr 'abc
+def' : 'abc$' >/dev/null; then
+ ENDANCHOR='\'\'
+ echo "Notice: An ENDANCHOR of dollar does not work."
+ echo "Using a workaround for GNU expr versions 1.9.4 thru 1.12"
+fi
+return 0
+}
+
+# Work around another GNU expr (version 1.10-1.12) bug/incompatibility.
+# "." doesn't appear to match a newline (it does with SunOS 4.1.3 expr).
+# Note that the workaround is not a complete equivalent of .* because
+# the first parenthesized expression in the regexp must match something
+# in order for expr to return a successful exit status.
+# Rumor has it this will be fixed in the
+# next release of GNU expr after 1.12 (but we still have to cater to the old
+# ones for some time because they are in many linux distributions).
+DOTSTAR='.*'
+expr_set_DOTSTAR ()
+{
+expr=$1
+DOTSTAR='.*'
+if $expr 'abc
+def' : "a${DOTSTAR}f" >/dev/null; then
+ : good, it works
+else
+ DOTSTAR='\(.\|
+\)*'
+ echo "Notice: DOTSTAR changed from sane \`.*' value to \`$DOTSTAR\`"
+ echo "to workaround GNU expr version 1.10 thru 1.12 bug where \`.'"
+ echo "does not match a newline."
+fi
+return 0
+}
+
+# Now that we have DOTSTAR, make sure it works with big matches
+expr_tooltest_DOTSTAR ()
+{
+expr=$1
+test ! -f ${TESTDIR}/bar && expr_create_bar
+if $expr "`cat ${TESTDIR}/bar`" : "${DOTSTAR}xyzABC${DOTSTAR}$" >/dev/null; then
+ # good, it works
+ return 0
+else
+ echo 'Warning: you are using a version of expr that does not correctly'
+ echo 'match large patterns. Some tests may spuriously pass or fail.'
+ echo 'You may wish to make sure GNU expr is in your path.'
+ return 77
+fi
+}
+
+EXPR=`find_tool ${EXPR}:gexpr \
+ version_test expr_tooltest1 expr_tooltest2 expr_tooltest3 \
+expr_set_ENDANCHOR expr_set_DOTSTAR expr_tooltest_DOTSTAR`
+
+# Set the ENDANCHOR and DOTSTAR for the chosen expr version.
+expr_set_ENDANCHOR ${EXPR} >/dev/null
+expr_tooltest_DOTSTAR ${EXPR} >/dev/null
+
+echo "Using EXPR=$EXPR" >>$LOGFILE
+echo "Using ENDANCHOR=$ENDANCHOR" >>$LOGFILE
+echo "Using DOTSTAR=$DOTSTAR" >>$LOGFILE
+
+# Cleanup
+rm -f ${TESTDIR}/bar
+
+# Work around yet another GNU expr (version 1.10) bug/incompatibility.
+# "+" is a special character, yet for unix expr (e.g. SunOS 4.1.3)
+# it is not. I doubt that POSIX allows us to use \+ and assume it means
+# (non-special) +, so here is another workaround
+# Rumor has it this will be fixed in the
+# next release of GNU expr after 1.12 (but we still have to cater to the old
+# ones for some time because they are in many linux distributions).
+PLUS='+'
+if $EXPR 'a +b' : "a ${PLUS}b" >/dev/null; then
+ : good, it works
+else
+ PLUS='\+'
+fi
+
+# Likewise, for ?
+QUESTION='?'
+if $EXPR 'a?b' : "a${QUESTION}b" >/dev/null; then
+ : good, it works
+else
+ QUESTION='\?'
+fi
+
+# Now test the username to make sure it contains only valid characters
+username=`$ID -un`
+if $EXPR "${username}" : "${username}" >/dev/null; then
+ : good, it works
+else
+ echo "Test suite does not work correctly when run by a username" >&2
+ echo "containing regular expression meta-characters." >&2
+ exit 1
+fi
+
+# Only 8 characters of $username appear in some output.
+if test `echo $username |wc -c` -gt 8; then
+ username8=`echo $username |sed 's/^\(........\).*/\1/'`
+else
+ username8=$username
+fi
+
+# Rarely, we need to match any username, not just the name of the user
+# running this test. This variable usually shouldn't be used. $username
+# contains the name of the user actually running this test.
+#
+# I believe this only ever actually gets compared to usernames created by this
+# test. It used to be compared to the username of the user running this test,
+# but this hasn't been true for a long time. Regardless, I tried to get the
+# allowed character set right, based on a list in a private email from Mark
+# Baushke, basically the allowed names from Linux systems (plus `.', which is
+# only allowed on Gentoo Linux as of 2005-09-13).
+anyusername="[_a-zA-Z0-9][-_.$a-zA-Z0-9]*"
+
+# now make sure that tr works on NULs
+tr_tooltest1 ()
+{
+tr=$1
+if $EXPR `echo "123" | $tr '2' '\0'` : "123" >/dev/null 2>&1; then
+ echo 'Warning: you are using a version of tr which does not correctly'
+ echo 'handle NUL bytes. Some tests may spuriously pass or fail.'
+ echo 'You may wish to make sure GNU tr is in your path.'
+ return 77
+fi
+# good, it works
+return 0
+}
+
+TR=`find_tool ${TR}:gtr version_test tr_tooltest1`
+echo "Using TR=$TR" >>$LOGFILE
+
+# MacOS X (10.2.8) has a /bin/ls that does not work correctly in that
+# it will return true even if the wildcard argument does not match any
+# files.
+ls_tooltest ()
+{
+ls=$1
+# Force cleanup
+if test -d $TESTDIR/ls-test; then
+ chmod -R a+wx $TESTDIR/ls-test
+ rm -rf $TESTDIR/ls-test
+fi
+if $ls $TESTDIR/ls-test >/dev/null 2>&1; then
+ echo "Notice: \`$ls' is defective."
+ echo 'This is a version of ls which does not correctly'
+ echo 'return false for files that do not exist. Some tests may'
+ echo 'spuriously pass or fail.'
+ echo 'You may wish to put a an ls from GNU coreutils into your path.'
+ return 77
+else
+ return 0
+fi
+}
+LS=`find_tool ls:gls version_test ls_tooltest`
+echo "Using LS=$LS" >>$LOGFILE
+
+# Awk testing
+
+awk_tooltest1 ()
+{
+awk=$1
+$awk 'BEGIN {printf("one\ntwo\nthree\nfour\nfive\nsix")}' </dev/null >abc
+if $EXPR "`cat abc`" : \
+'one
+two
+three
+four
+five
+six'; then
+ rm abc
+ return 0
+else
+ rm abc
+ echo "Notice: awk BEGIN clause or printf is not be working properly."
+ return 1
+fi
+}
+
+# Format item %c check
+awk_tooltest2 ()
+{
+awk=$1
+$awk 'BEGIN { printf "%c%c%c", 2, 3, 4 }' </dev/null \
+ | ${TR} '\002\003\004' '123' >abc
+if $EXPR "`cat abc`" : "123" ; then
+ : good, found it
+else
+ echo "Notice: awk format %c string may not be working properly."
+ rm abc
+ return 77
+fi
+rm abc
+return 0
+}
+
+AWK=`find_tool gawk:nawk:awk version_test awk_tooltest1 awk_tooltest2`
+echo "Using AWK=$AWK" >>$LOGFILE
+
+
+###
+### Functions used by tests.
+###
+
+# Execute a command on the repository, syncing when done if necessary.
+#
+# Syntax is as `eval'.
+modify_repo ()
+{
+ eval "$*"
+ if $proxy; then
+ # And now resync the secondary.
+ $TESTDIR/sync-secondary "repo modification" modify_repo ALL "$@"
+ fi
+}
+
+# Restore changes to CVSROOT admin files.
+restore_adm ()
+{
+ modify_repo rm -rf $CVSROOT_DIRNAME/CVSROOT
+ modify_repo cp -Rp $TESTDIR/CVSROOT.save $CVSROOT_DIRNAME/CVSROOT
+}
+
+# Test that $RSYNC supports the options we need or try to find a
+# replacement. If $RSYNC works or we replace it, and return 0.
+# Otherwise, set $skipreason and return 77.
+require_rsync ()
+{
+ rsyncworks=false
+ # rsync is NOT a GNU tool, so do NOT use find_tool for name munging.
+ for rsync in ${RSYNC} `Which -a rsync`;
+ do
+
+ if is_bad_tool `Which $rsync` ; then continue ; fi
+ # Make some data to test rsync on.
+ mkdir $TESTDIR/rsync-test
+ mkdir $TESTDIR/rsync-test/Attic && touch $TESTDIR/rsync-test/Attic/6
+ mkdir $TESTDIR/rsync-test/otherdir && touch $TESTDIR/rsync-test/otherdir/7
+ for file in 1 2 3 4 5; do
+ touch $TESTDIR/rsync-test/$file
+ done
+
+ if test -f "$rsync" && test -r "$rsync" \
+ && $rsync -rglop --delete $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy \
+ >/dev/null 2>&1 \
+ && $rsync -rglop --delete --include Attic --exclude '*/' \
+ $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy2 \
+ >/dev/null 2>&1 \
+ && test -f $TESTDIR/rsync-test/5 \
+ && mv $TESTDIR/rsync-test/5 $TESTDIR/rsync-test/Attic/5 \
+ && test -f $TESTDIR/rsync-test-copy/Attic/6 \
+ && $rsync -rglop --delete $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy \
+ >/dev/null 2>&1 \
+ && $rsync -rglop --delete --include Attic --exclude '*/' \
+ $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy2 \
+ >/dev/null 2>&1 \
+ && test ! -f $TESTDIR/rsync-test-copy/5 \
+ && test ! -f $TESTDIR/rsync-test-copy2/5 \
+ && test -f $TESTDIR/rsync-test-copy2/Attic/5 \
+ && test ! -f $TESTDIR/rsync-test-copy2/otherdir/7
+ then
+ # good, it works
+ rsyncworks=:
+ RSYNC=$rsync
+ else
+ # Only use Which because of ${RSYNC} in the for loop.
+ set_bad_tool `Which $rsync`
+ fi
+
+ rm -rf $TESTDIR/rsync-test $TESTDIR/rsync-test-copy \
+ $TESTDIR/rsync-test-copy2
+
+ if $rsyncworks; then
+ return 0
+ else
+ (echo $rsync failed to work properly;\
+ echo "$rsync --version"; $rsync --version) >>$LOGFILE 2>&1
+ fi
+ done
+
+ unset RSYNC
+ skipreason="unusable or no rsync found"
+ return 77
+}
+
+# Test that $1 works as a remote shell. If so, set $host, $CVS_RSH, &
+# $save_CVS_RSH to match and return 0. Otherwise, set $skipreason and return
+# 77.
+require_rsh ()
+{
+ host=${remotehost-"`hostname`"}
+ result=`$1 $host 'echo test'`
+ rc=$?
+ if test $? != 0 || test "x$result" != "xtest"; then
+ skipreason="\`$1 $host' failed rc=$rc result=$result"
+ return 77
+ fi
+
+ save_CVS_RSH=$CVS_RSH
+ CVS_RSH=$1; export CVS_RSH
+ return 0
+}
+
+# Find a usable SSH. When a usable ssh is found, set $host, $CVS_RSH, and
+# $save_CVS_RSH and return 0. Otherwise, set $skipreason and return 77.
+require_ssh ()
+{
+ case "$CVS_RSH" in
+ *ssh*|*putty*)
+ tryssh=`Which $CVS_RSH`
+ if [ ! -n "$tryssh" ]; then
+ skipreason="Unable to find CVS_RSH=$CVS_RSH executable"
+ return 77
+ elif [ ! -x "$tryssh" ]; then
+ skipreason="Unable to execute $tryssh program"
+ return 77
+ fi
+ ;;
+ *)
+ # Look in the user's PATH for "ssh"
+ tryssh=`Which ssh`
+ if test ! -r "$tryssh"; then
+ skipreason="Unable to find ssh program"
+ return 77
+ fi
+ ;;
+ esac
+
+ require_rsh "$tryssh"
+ return $?
+}
+
+pass ()
+{
+ echo "PASS: $1" >>${LOGFILE}
+ passed=`expr $passed + 1`
+}
+
+# Like skip(), but don't fail when $skipfail is set.
+skip_always ()
+{
+ echo "SKIP: $1${2+ ($2)}" >>$LOGFILE
+ skipped=`expr $skipped + 1`
+}
+
+skip ()
+{
+ if $skipfail; then
+ # exits
+ fail "$1${2+ ($2)}"
+ fi
+
+ skip_always ${1+"$@"}
+}
+
+# Convenience function for skipping tests run only in remote mode.
+remoteonly ()
+{
+ skip_always $1 "only tested in remote mode"
+}
+
+# Convenience function for skipping tests not run in proxy mode.
+notproxy ()
+{
+ skip_always $1 "not tested in proxy mode"
+}
+
+# Convenience function for skipping tests not run in proxy mode.
+notnoredirect ()
+{
+ skip_always $1 "not tested in proxy-noredirect mode"
+}
+
+warn ()
+{
+ if $skipfail; then
+ fail "$1${2+ ($2)}"
+ else
+ echo "WARNING: $1${2+ ($2)}" >>$LOGFILE
+ fi
+ warnings=`expr $warnings + 1`
+}
+
+fail ()
+{
+ echo "FAIL: $1" | tee -a ${LOGFILE}
+ echo "*** Please see the \`TESTS' and \`check.log' files for more information." >&2
+ # This way the tester can go and see what remnants were left
+ exit 1
+}
+
+verify_tmp_empty ()
+{
+ # Test our temp directory for cvs-serv* directories and cvsXXXXXX temp
+ # files. We would like to not leave any behind.
+ if $remote && $LS $TMPDIR/cvs-serv* >/dev/null 2>&1; then
+ # A true value means ls found files/directories with these names.
+ # Give the server some time to finish, then retry.
+ sleep 1
+ if $LS $TMPDIR/cvs-serv* >/dev/null 2>&1; then
+ warn "$1" "Found cvs-serv* directories in $TMPDIR."
+ # The above will exit if $skipfail
+ rm -rf $TMPDIR/cvs-serv*
+ fi
+ fi
+ if $LS $TMPDIR/cvs?????? >/dev/null 2>&1; then
+ # A true value means ls found files/directories with these names.
+ warn "$1" "Found cvsXXXXXX temp files in $TMPDIR."
+ # The above will exit if $skipfail
+ rm -f ls $TMPDIR/cvs??????
+ fi
+}
+
+# See dotest and dotest_fail for explanation (this is the parts
+# of the implementation common to the two).
+dotest_internal ()
+{
+ if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : "$3${ENDANCHOR}" >/dev/null; then
+ # Why, I hear you ask, do we write this to the logfile
+ # even when the test passes? The reason is that the test
+ # may give us the regexp which we were supposed to match,
+ # but sometimes it may be useful to look at the exact
+ # text which was output. For example, suppose one wants
+ # to grep for a particular warning, and make _sure_ that
+ # CVS never hits it (even in cases where the tests might
+ # match it with .*). Or suppose one wants to see the exact
+ # date format output in a certain case (where the test will
+ # surely use a somewhat non-specific pattern).
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ pass "$1"
+ verify_tmp_empty "$1"
+ # expr can't distinguish between "zero characters matched" and "no match",
+ # so special-case it.
+ elif test -z "$3" && test ! -s ${TESTDIR}/dotest.tmp; then
+ pass "$1"
+ verify_tmp_empty "$1"
+ elif test x"$4" != x; then
+ if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : "$4${ENDANCHOR}" >/dev/null; then
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ pass "$1"
+ verify_tmp_empty "$1"
+ else
+ echo "** expected: " >>${LOGFILE}
+ echo "$3" >>${LOGFILE}
+ echo "$3" > ${TESTDIR}/dotest.ex1
+ echo "** or: " >>${LOGFILE}
+ echo "$4" >>${LOGFILE}
+ echo "$4" > ${TESTDIR}/dotest.ex2
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ fail "$1"
+ fi
+ else
+ echo "** expected: " >>${LOGFILE}
+ echo "$3" >>${LOGFILE}
+ echo "$3" > ${TESTDIR}/dotest.exp
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ fail "$1"
+ fi
+}
+
+dotest_all_in_one ()
+{
+ if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : \
+ "`cat ${TESTDIR}/dotest.exp`" >/dev/null; then
+ return 0
+ fi
+ return 1
+}
+
+# WARNING: this won't work with REs that match newlines....
+#
+dotest_line_by_line ()
+{
+ line=1
+ while [ $line -le `wc -l <${TESTDIR}/dotest.tmp` ] ; do
+ if $EXPR "`sed -n ${line}p ${TESTDIR}/dotest.tmp`" : \
+ "`sed -n ${line}p ${TESTDIR}/dotest.exp`" >/dev/null; then
+ :
+ elif test -z "`sed -n ${line}p ${TESTDIR}/dotest.tmp`" &&
+ test -z "`sed -n ${line}p ${TESTDIR}/dotest.exp`"; then
+ :
+ else
+ echo "Line $line:" >> ${LOGFILE}
+ echo "**** expected: " >>${LOGFILE}
+ sed -n ${line}p ${TESTDIR}/dotest.exp >>${LOGFILE}
+ echo "**** got: " >>${LOGFILE}
+ sed -n ${line}p ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ unset line
+ return 1
+ fi
+ line=`expr $line + 1`
+ done
+ unset line
+ return 0
+}
+
+# If you are having trouble telling which line of a multi-line
+# expression is not being matched, replace calls to dotest_internal()
+# with calls to this function:
+#
+dotest_internal_debug ()
+{
+ if test -z "$3"; then
+ if test -s ${TESTDIR}/dotest.tmp; then
+ echo "** expected: " >>${LOGFILE}
+ echo "$3" >>${LOGFILE}
+ echo "$3" > ${TESTDIR}/dotest.exp
+ rm -f ${TESTDIR}/dotest.ex2
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ fail "$1"
+ else
+ pass "$1"
+ verify_tmp_empty "$1"
+ fi
+ else
+ echo "$3" > ${TESTDIR}/dotest.exp
+ if dotest_line_by_line "$1" "$2"; then
+ pass "$1"
+ verify_tmp_empty "$1"
+ else
+ if test x"$4" != x; then
+ mv ${TESTDIR}/dotest.exp ${TESTDIR}/dotest.ex1
+ echo "$4" > ${TESTDIR}/dotest.exp
+ if dotest_line_by_line "$1" "$2"; then
+ pass "$1"
+ verify_tmp_empty "$1"
+ else
+ mv ${TESTDIR}/dotest.exp ${TESTDIR}/dotest.ex2
+ echo "** expected: " >>${LOGFILE}
+ echo "$3" >>${LOGFILE}
+ echo "** or: " >>${LOGFILE}
+ echo "$4" >>${LOGFILE}
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ fail "$1"
+ fi
+ else
+ echo "** expected: " >>${LOGFILE}
+ echo "$3" >>${LOGFILE}
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ fail "$1"
+ fi
+ fi
+ fi
+}
+
+# This function allows the test output to be filtered before being verified.
+# The dotest_* functions all call this function, which runs the command
+# in the env var $TEST_FILTER on its argument if $TEST_FILTER is set. If
+# $TEST_FILTER is not set, this function does nothing.
+#
+# I found this primarily useful when running the test suite on a CVS
+# executable linked with memory and function profilers which can generate
+# spurious output.
+run_filter ()
+{
+ if test -n "$TEST_FILTER"; then
+ # Make sure there is an EOL
+ echo >>$1
+ sed '${/^$/d}' <$1 >$1.filter1
+ # Run the filter
+ eval "$TEST_FILTER" <$1.filter1 >$1.filter2
+ diff -u $1 $1.filter2 \
+ >$1.diff
+ mv $1.filter2 $1
+ rm $1.filter1
+ fi
+}
+
+# Usage:
+# dotest TESTNAME COMMAND OUTPUT [OUTPUT2]
+# TESTNAME is the name used in the log to identify the test.
+# COMMAND is the command to run; for the test to pass, it exits with
+# exitstatus zero.
+# OUTPUT is a regexp which is compared against the output (stdout and
+# stderr combined) from the test. It is anchored to the start and end
+# of the output, so should start or end with ".*" if that is what is desired.
+# Trailing newlines are stripped from the command's actual output before
+# matching against OUTPUT.
+# If OUTPUT2 is specified and the output matches it, then it is also
+# a pass (partial workaround for the fact that some versions of expr
+# lack \|).
+dotest ()
+{
+ rm -f $TESTDIR/dotest.ex? 2>&1
+ eval "$2" >$TESTDIR/dotest.tmp 2>&1
+ status=$?
+ run_filter $TESTDIR/dotest.tmp
+ if test "$status" != 0; then
+ cat $TESTDIR/dotest.tmp >>$LOGFILE
+ echo "exit status was $status" >>${LOGFILE}
+ fail "$1"
+ fi
+ dotest_internal "$@"
+}
+
+# Like dotest except only 2 args and result must exactly match stdin
+dotest_lit ()
+{
+ rm -f $TESTDIR/dotest.ex? 2>&1
+ eval "$2" >$TESTDIR/dotest.tmp 2>&1
+ status=$?
+ run_filter $TESTDIR/dotest.tmp
+ if test "$status" != 0; then
+ cat $TESTDIR/dotest.tmp >>$LOGFILE
+ echo "exit status was $status" >>$LOGFILE
+ fail "$1"
+ fi
+ cat >$TESTDIR/dotest.exp
+ if cmp $TESTDIR/dotest.exp $TESTDIR/dotest.tmp >/dev/null 2>&1; then
+ pass "$1"
+ verify_tmp_empty "$1"
+ else
+ echo "** expected: " >>$LOGFILE
+ cat $TESTDIR/dotest.exp >>$LOGFILE
+ echo "** got: " >>$LOGFILE
+ cat $TESTDIR/dotest.tmp >>$LOGFILE
+ fail "$1"
+ fi
+}
+
+# Like dotest except exitstatus should be nonzero.
+dotest_fail ()
+{
+ rm -f $TESTDIR/dotest.ex? 2>&1
+ eval "$2" >$TESTDIR/dotest.tmp 2>&1
+ status=$?
+ run_filter $TESTDIR/dotest.tmp
+ if test "$status" = 0; then
+ cat $TESTDIR/dotest.tmp >>$LOGFILE
+ echo "exit status was $status" >>$LOGFILE
+ fail "$1"
+ fi
+ dotest_internal "$@"
+}
+
+# Like dotest except output is sorted.
+dotest_sort ()
+{
+ rm -f $TESTDIR/dotest.ex? 2>&1
+ eval "$2" >$TESTDIR/dotest.tmp1 2>&1
+ status=$?
+ run_filter $TESTDIR/dotest.tmp1
+ if test "$status" != 0; then
+ cat $TESTDIR/dotest.tmp1 >>$LOGFILE
+ echo "exit status was $status" >>$LOGFILE
+ fail "$1"
+ fi
+ $TR ' ' ' ' < $TESTDIR/dotest.tmp1 | sort > $TESTDIR/dotest.tmp
+ dotest_internal "$@"
+}
+
+# Like dotest_fail except output is sorted.
+dotest_fail_sort ()
+{
+ rm -f $TESTDIR/dotest.ex? 2>&1
+ eval "$2" >$TESTDIR/dotest.tmp1 2>&1
+ status=$?
+ run_filter $TESTDIR/dotest.tmp1
+ if test "$status" = 0; then
+ cat $TESTDIR/dotest.tmp1 >>$LOGFILE
+ echo "exit status was $status" >>$LOGFILE
+ fail "$1"
+ fi
+ $TR ' ' ' ' < $TESTDIR/dotest.tmp1 | sort > $TESTDIR/dotest.tmp
+ dotest_internal "$@"
+}
+
+# A function for fetching the timestamp of a revison of a file
+getrlogdate () {
+ ${testcvs} -n rlog -N ${1+"$@"} |
+ while read token value; do
+ case "$token" in
+ date:)
+ echo $value | sed "s,;.*,,"
+ break;
+ ;;
+ esac
+ done
+}
+
+# Avoid picking up any stray .cvsrc, etc., from the user running the tests
+mkdir home
+HOME=$TESTDIR/home; export HOME
+
+# Make sure this variable is not defined to anything that would
+# change the format of rcs dates. Otherwise people using e.g.,
+# RCSINIT=-zLT get lots of spurious failures.
+RCSINIT=; export RCSINIT
+
+# Remaining arguments are the names of tests to run.
+#
+# The testsuite is broken up into (hopefully manageably-sized)
+# independently runnable tests, so that one can quickly get a result
+# from a cvs or testsuite change, and to facilitate understanding the
+# tests.
+
+if test x"$*" = x; then
+ # Basic/miscellaneous functionality
+ tests="version basica basicb basicc basic1 deep basic2 ls"
+ tests="$tests parseroot parseroot2 parseroot3 files spacefiles"
+ tests="${tests} commit-readonly commit-add-missing"
+ tests="${tests} status"
+ # Branching, tagging, removing, adding, multiple directories
+ tests="${tests} rdiff rdiff-short"
+ tests="${tests} rdiff2 diff diffnl death death2"
+ tests="${tests} rm-update-message rmadd rmadd2 rmadd3 resurrection"
+ tests="${tests} dirs dirs2 branches branches2 branches3"
+ tests="${tests} branches4 tagc tagf tag-space"
+ tests="${tests} rcslib multibranch import importb importc importX"
+ tests="$tests importX2 import-CVS import-quirks"
+ tests="${tests} update-p import-after-initial branch-after-import"
+ tests="${tests} join join2 join3 join4 join5 join6 join7"
+ tests="${tests} join-readonly-conflict join-admin join-admin-2"
+ tests="${tests} join-rm"
+ tests="${tests} new newb conflicts conflicts2 conflicts3"
+ tests="${tests} clean"
+ tests="${tests} keywordexpand"
+ # Checking out various places (modules, checkout -d, &c)
+ tests="${tests} modules modules2 modules3 modules4 modules5 modules6"
+ tests="${tests} modules7 mkmodules co-d"
+ tests="${tests} cvsadm emptydir abspath abspath2 toplevel toplevel2"
+ tests="${tests} rstar-toplevel trailingslashes checkout_repository"
+ # Log messages, error messages.
+ tests="${tests} mflag editor env errmsg1 errmsg2 adderrmsg opterrmsg"
+ tests="${tests} errmsg3"
+ tests="${tests} close-stdout"
+ tests="$tests debug-log-nonfatal"
+ # Watches, binary files, history browsing, &c.
+ tests="${tests} devcom devcom2 devcom3 watch4 watch5 watch6-0 watch6"
+ tests="${tests} edit-check"
+ tests="${tests} unedit-without-baserev"
+ tests="${tests} ignore ignore-on-branch binfiles binfiles2 binfiles3"
+ tests="${tests} mcopy binwrap binwrap2"
+ tests="${tests} binwrap3 mwrap info taginfo posttag"
+ tests="$tests config config2 config3 config4"
+ tests="${tests} serverpatch log log2 logopt ann ann-id"
+ # Repository Storage (RCS file format, CVS lock files, creating
+ # a repository without "cvs init", &c).
+ tests="${tests} crerepos rcs rcs2 rcs3 rcs4 rcs5"
+ tests="$tests lockfiles backuprecover"
+ tests="${tests} sshstdio"
+ # More history browsing, &c.
+ tests="${tests} history"
+ tests="${tests} big modes modes2 modes3 stamps"
+ # PreservePermissions stuff: permissions, symlinks et al.
+ # tests="${tests} perms symlinks symlinks2 hardlinks"
+ # More tag and branch tests, keywords.
+ tests="${tests} sticky keyword keywordlog keywordname keyword2"
+ tests="${tests} head tagdate multibranch2 tag8k"
+ # "cvs admin", reserved checkouts.
+ tests="${tests} admin reserved"
+ # Nuts and bolts of diffing/merging (diff library, &c)
+ tests="${tests} diffmerge1 diffmerge2"
+ # Release of multiple directories
+ tests="${tests} release"
+ tests="${tests} recase"
+ # Multiple root directories and low-level protocol tests.
+ tests="${tests} multiroot multiroot2 multiroot3 multiroot4"
+ tests="${tests} rmroot reposmv pserver server server2 client"
+ tests="${tests} dottedroot fork commit-d template"
+ tests="${tests} writeproxy writeproxy-noredirect writeproxy-ssh"
+ tests="${tests} writeproxy-ssh-noredirect"
+else
+ tests="$*"
+fi
+
+# Now check the -f argument for validity.
+if test -n "$fromtest"; then
+ # Don't allow spaces - they are our delimiters in tests
+ count=0
+ for sub in $fromtest; do
+ count=`expr $count + 1`
+ done
+ if test $count != 1; then
+ echo "No such test \`$fromtest'." >&2
+ exit 2
+ fi
+ # make sure it is in $tests
+ case " $tests " in
+ *" $fromtest "*)
+ ;;
+ *)
+ echo "No such test \`$fromtest'." >&2
+ exit 2
+ ;;
+ esac
+fi
+
+
+
+# a simple function to compare directory contents
+#
+# Returns: 0 for same, 1 for different
+#
+directory_cmp ()
+{
+ OLDPWD=`pwd`
+ DIR_1=$1
+ DIR_2=$2
+
+ cd $DIR_1
+ find . -print | fgrep -v /CVS | sort > $TESTDIR/dc$$d1
+
+ # go back where we were to avoid symlink hell...
+ cd $OLDPWD
+ cd $DIR_2
+ find . -print | fgrep -v /CVS | sort > $TESTDIR/dc$$d2
+
+ if diff $TESTDIR/dc$$d1 $TESTDIR/dc$$d2 >/dev/null 2>&1
+ then
+ :
+ else
+ return 1
+ fi
+ cd $OLDPWD
+ while read a
+ do
+ if test -f $DIR_1/"$a" ; then
+ cmp -s $DIR_1/"$a" $DIR_2/"$a"
+ if test $? -ne 0 ; then
+ return 1
+ fi
+ fi
+ done < $TESTDIR/dc$$d1
+ rm -f $TESTDIR/dc$$*
+ return 0
+}
+
+
+
+#
+# The following 4 functions are used by the diffmerge1 test case. They set up,
+# respectively, the four versions of the files necessary:
+#
+# 1. Ancestor revisions.
+# 2. "Your" changes.
+# 3. "My" changes.
+# 4. Expected merge result.
+#
+
+# Create ancestor revisions for diffmerge1
+diffmerge_create_older_files() {
+ # This test case was supplied by Noah Friedman:
+ cat >testcase01 <<EOF
+// Button.java
+
+package random.application;
+
+import random.util.*;
+
+public class Button
+{
+ /* Instantiates a Button with origin (0, 0) and zero width and height.
+ * You must call an initializer method to properly initialize the Button.
+ */
+ public Button ()
+ {
+ super ();
+
+ _titleColor = Color.black;
+ _disabledTitleColor = Color.gray;
+ _titleFont = Font.defaultFont ();
+ }
+
+ /* Convenience constructor for instantiating a Button with
+ * bounds x, y, width, and height. Equivalent to
+ * foo = new Button ();
+ * foo.init (x, y, width, height);
+ */
+ public Button (int x, int y, int width, int height)
+ {
+ this ();
+ init (x, y, width, height);
+ }
+}
+EOF
+
+ # This test case was supplied by Jacob Burckhardt:
+ cat >testcase02 <<EOF
+a
+a
+a
+a
+a
+EOF
+
+ # This test case was supplied by Karl Tomlinson who also wrote the
+ # patch which lets CVS correctly handle this and several other cases:
+ cat >testcase03 <<EOF
+x
+s
+a
+b
+s
+y
+EOF
+
+ # This test case was supplied by Karl Tomlinson:
+ cat >testcase04 <<EOF
+s
+x
+m
+m
+x
+s
+v
+s
+x
+m
+m
+x
+s
+EOF
+
+ # This test case was supplied by Karl Tomlinson:
+ cat >testcase05 <<EOF
+s
+x
+m
+m
+x
+x
+x
+x
+x
+x
+x
+x
+x
+x
+s
+s
+s
+s
+s
+s
+s
+s
+s
+s
+v
+EOF
+
+ # This test case was supplied by Jacob Burckhardt:
+ cat >testcase06 <<EOF
+g
+
+
+
+
+
+
+
+
+
+
+
+i
+EOF
+
+ # This test is supposed to verify that the horizon lines are the same
+ # for both 2-way diffs, but unfortunately, it does not fail with the
+ # old version of cvs. However, Karl Tomlinson still thought it would
+ # be good to test it anyway:
+ cat >testcase07 <<EOF
+h
+f
+
+
+
+
+
+
+
+
+
+g
+r
+
+
+
+i
+
+
+
+
+
+
+
+
+
+
+i
+EOF
+
+ # This test case was supplied by Jacob Burckhardt:
+ cat >testcase08 <<EOF
+Both changes move this line to the end of the file.
+
+no
+changes
+here
+
+First change will delete this line.
+
+First change will also delete this line.
+
+ no
+ changes
+ here
+
+Second change will change it here.
+
+ no
+ changes
+ here
+EOF
+
+ # This test case was supplied by Jacob Burckhardt. Note that I do not
+ # think cvs has ever failed with this case, but I include it anyway,
+ # since I think it is a hard case. It is hard because Peter Miller's
+ # fmerge utility fails on it:
+ cat >testcase09 <<EOF
+m
+a
+{
+}
+b
+{
+}
+EOF
+
+ # This test case was supplied by Martin Dorey and simplified by Jacob
+ # Burckhardt:
+ cat >testcase10 <<EOF
+
+ petRpY ( MtatRk );
+ fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );
+
+ MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
+ OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );
+
+ Bloke_GttpfIRte_MtpeaL ( &acI );
+MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
+{
+ fV ( Y < 16 )
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ Y * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+ elke
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+
+}
+
+
+/****************************************************************************
+* *
+* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) *
+* *
+****************************************************************************/
+
+MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
+{
+MTGTXM MtatRk = Zy;
+
+ MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );
+
+ petRpY ( MtatRk );
+
+}
+ HfkQipfte ( waYdle, /* waYdle */
+ waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */
+ (coYkt RfYt8*) nRVVep, /* nRVVep */
+ 0, /* MRrepVlRoRk KfxoYfkL */
+ beYgtz /* nEtek to Apfte */
+ );
+
+ petRpY ( Zy );
+}
+EOF
+}
+
+# Create "your" revisions for diffmerge1
+diffmerge_create_your_files() {
+ # remove the Button() method
+ cat >testcase01 <<\EOF
+// Button.java
+
+package random.application;
+
+import random.util.*;
+
+public class Button
+{
+ /* Instantiates a Button with origin (0, 0) and zero width and height.
+ * You must call an initializer method to properly initialize the Button.
+ */
+ public Button ()
+ {
+ super ();
+
+ _titleColor = Color.black;
+ _disabledTitleColor = Color.gray;
+ _titleFont = Font.defaultFont ();
+ }
+}
+EOF
+
+ cat >testcase02 <<\EOF
+y
+a
+a
+a
+a
+EOF
+
+ cat >testcase03 <<\EOF
+x
+s
+a
+b
+s
+b
+s
+y
+EOF
+
+ cat >testcase04 <<\EOF
+s
+m
+s
+v
+s
+m
+s
+EOF
+
+ cat >testcase05 <<\EOF
+v
+s
+m
+s
+s
+s
+s
+s
+s
+s
+s
+s
+s
+v
+EOF
+
+ # Test case 6 and test case 7 both use the same input files, but they
+ # order the input files differently. In one case, a certain file is
+ # used as the older file, but in the other test case, that same file
+ # is used as the file which has changes. I could have put echo
+ # commands here, but since the echo lines would be the same as those
+ # in the previous function, I decided to save space and avoid repeating
+ # several lines of code. Instead, I merely swap the files:
+ mv testcase07 tmp
+ mv testcase06 testcase07
+ mv tmp testcase06
+
+ # Make the date newer so that cvs thinks that the files are changed:
+ touch testcase06 testcase07
+
+ cat >testcase08 <<\EOF
+no
+changes
+here
+
+First change has now added this in.
+
+ no
+ changes
+ here
+
+Second change will change it here.
+
+ no
+ changes
+ here
+
+Both changes move this line to the end of the file.
+EOF
+
+ cat >testcase09 <<\EOF
+
+m
+a
+{
+}
+b
+{
+}
+c
+{
+}
+EOF
+
+ cat >testcase10 <<\EOF
+
+ fV ( BzQkV_URYYfYg ) (*jfle_Uecopdk)[0].jfle_Uecopd_KRLIep = ZpfgfYal_jUK;
+
+ petRpY ( MtatRk );
+ fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );
+
+ fV ( jfle_Uecopd_KRLIep < 16 )
+ {
+ MtatRk = Uead_Ktz_qjT_jfle_Uecopd ( jfle_Uecopd_KRLIep, (uofd*)nRVVep );
+ }
+ elke
+ {
+ MtatRk = ZreY_GttpfIRte_MtpeaL ( qjT_jfle_Uecopdk, qjT_jfle_Uecopd_BoRYt, HGTG_TvFD, KXbb, KXbb, &acI );
+ fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );
+
+ MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
+ OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );
+
+ Bloke_GttpfIRte_MtpeaL ( &acI );
+MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
+{
+MTGTXM MtatRk = Zy;
+
+ fV ( Y < 16 )
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ Y * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+ elke
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+
+ petRpY ( MtatRk );
+
+}
+
+
+/****************************************************************************
+* *
+* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) *
+* *
+****************************************************************************/
+
+MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
+{
+MTGTXM MtatRk = Zy;
+
+ MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );
+
+ petRpY ( MtatRk );
+
+}
+ HfkQipfte ( waYdle, /* waYdle */
+ waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */
+ (coYkt RfYt8*) nRVVep, /* nRVVep */
+ 0, /* MRrepVlRoRk KfxoYfkL */
+ beYgtz /* nEtek to Apfte */
+ );
+
+ petRpY ( Zy );
+}
+
+EOF
+}
+
+# Create "my" revisions for diffmerge1
+diffmerge_create_my_files() {
+ # My working copy still has the Button() method, but I
+ # comment out some code at the top of the class.
+ cat >testcase01 <<\EOF
+// Button.java
+
+package random.application;
+
+import random.util.*;
+
+public class Button
+{
+ /* Instantiates a Button with origin (0, 0) and zero width and height.
+ * You must call an initializer method to properly initialize the Button.
+ */
+ public Button ()
+ {
+ super ();
+
+ // _titleColor = Color.black;
+ // _disabledTitleColor = Color.gray;
+ // _titleFont = Font.defaultFont ();
+ }
+
+ /* Convenience constructor for instantiating a Button with
+ * bounds x, y, width, and height. Equivalent to
+ * foo = new Button ();
+ * foo.init (x, y, width, height);
+ */
+ public Button (int x, int y, int width, int height)
+ {
+ this ();
+ init (x, y, width, height);
+ }
+}
+EOF
+
+ cat >testcase02 <<\EOF
+a
+a
+a
+a
+m
+EOF
+
+ cat >testcase03 <<\EOF
+x
+s
+c
+s
+b
+s
+y
+EOF
+
+ cat >testcase04 <<\EOF
+v
+s
+x
+m
+m
+x
+s
+v
+s
+x
+m
+m
+x
+s
+v
+EOF
+
+ # Note that in test case 5, there are no changes in the "mine"
+ # section, which explains why there is no command here which writes to
+ # file testcase05.
+
+ # no changes for testcase06
+
+ # The two branches make the same changes:
+ cp ../yours/testcase07 .
+
+ cat >testcase08 <<\EOF
+no
+changes
+here
+
+First change will delete this line.
+
+First change will also delete this line.
+
+ no
+ changes
+ here
+
+Second change has now changed it here.
+
+ no
+ changes
+ here
+
+Both changes move this line to the end of the file.
+EOF
+
+ cat >testcase09 <<\EOF
+m
+a
+{
+}
+b
+{
+}
+c
+{
+}
+EOF
+
+ cat >testcase10 <<\EOF
+
+ petRpY ( MtatRk );
+ fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );
+
+ MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
+ OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );
+
+ Bloke_GttpfIRte_MtpeaL ( &acI );
+MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
+{
+ fV ( Y < 16 )
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ Y * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+ elke
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+
+}
+
+
+/****************************************************************************
+* *
+* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) *
+* *
+****************************************************************************/
+
+MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
+{
+MTGTXM MtatRk = Zy;
+
+ MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );
+
+ petRpY ( MtatRk );
+
+}
+ HfkQipfte ( waYdle, /* waYdle */
+ waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */
+ (coYkt RfYt8*) nRVVep, /* nRVVep */
+ beYgtz /* nEtek to Apfte */
+ );
+
+ petRpY ( Zy );
+}
+
+EOF
+}
+
+# Create expected results of merge for diffmerge1
+diffmerge_create_expected_files() {
+ cat >testcase01 <<\EOF
+// Button.java
+
+package random.application;
+
+import random.util.*;
+
+public class Button
+{
+ /* Instantiates a Button with origin (0, 0) and zero width and height.
+ * You must call an initializer method to properly initialize the Button.
+ */
+ public Button ()
+ {
+ super ();
+
+ // _titleColor = Color.black;
+ // _disabledTitleColor = Color.gray;
+ // _titleFont = Font.defaultFont ();
+ }
+}
+EOF
+
+ cat >testcase02 <<\EOF
+y
+a
+a
+a
+m
+EOF
+
+ cat >testcase03 <<\EOF
+x
+s
+c
+s
+b
+s
+b
+s
+y
+EOF
+
+ cat >testcase04 <<\EOF
+v
+s
+m
+s
+v
+s
+m
+s
+v
+EOF
+
+ # Since there are no changes in the "mine" section, just take exactly
+ # the version in the "yours" section:
+ cp ../yours/testcase05 .
+
+ cp ../yours/testcase06 .
+
+ # Since the two branches make the same changes, the result should be
+ # the same as both branches. Here, I happen to pick yours to copy from,
+ # but I could have also picked mine, since the source of the copy is
+ # the same in either case. However, the mine has already been
+ # altered by the update command, so don't use it. Instead, use the
+ # yours section which has not had an update on it and so is unchanged:
+ cp ../yours/testcase07 .
+
+ cat >testcase08 <<\EOF
+no
+changes
+here
+
+First change has now added this in.
+
+ no
+ changes
+ here
+
+Second change has now changed it here.
+
+ no
+ changes
+ here
+
+Both changes move this line to the end of the file.
+EOF
+
+ cat >testcase09 <<\EOF
+
+m
+a
+{
+}
+b
+{
+}
+c
+{
+}
+EOF
+
+ cat >testcase10 <<\EOF
+
+ fV ( BzQkV_URYYfYg ) (*jfle_Uecopdk)[0].jfle_Uecopd_KRLIep = ZpfgfYal_jUK;
+
+ petRpY ( MtatRk );
+ fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );
+
+ fV ( jfle_Uecopd_KRLIep < 16 )
+ {
+ MtatRk = Uead_Ktz_qjT_jfle_Uecopd ( jfle_Uecopd_KRLIep, (uofd*)nRVVep );
+ }
+ elke
+ {
+ MtatRk = ZreY_GttpfIRte_MtpeaL ( qjT_jfle_Uecopdk, qjT_jfle_Uecopd_BoRYt, HGTG_TvFD, KXbb, KXbb, &acI );
+ fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );
+
+ MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
+ OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );
+
+ Bloke_GttpfIRte_MtpeaL ( &acI );
+MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
+{
+MTGTXM MtatRk = Zy;
+
+ fV ( Y < 16 )
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ Y * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+ elke
+ {
+ petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
+ ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
+ jfle_Uecopd_MfJe_fY_Mectopk,
+ nRVVep ) );
+ }
+
+ petRpY ( MtatRk );
+
+}
+
+
+/****************************************************************************
+* *
+* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) *
+* *
+****************************************************************************/
+
+MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
+{
+MTGTXM MtatRk = Zy;
+
+ MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );
+
+ petRpY ( MtatRk );
+
+}
+ HfkQipfte ( waYdle, /* waYdle */
+ waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */
+ (coYkt RfYt8*) nRVVep, /* nRVVep */
+ beYgtz /* nEtek to Apfte */
+ );
+
+ petRpY ( Zy );
+}
+
+EOF
+}
+
+
+
+# Echo a new CVSROOT based on $1, $remote, and $remotehost
+newroot() {
+ if $remote; then
+ if test -n "$remotehost"; then
+ echo :ext$rootoptions:$remotehost$1
+ else
+ echo :fork$rootoptions:$1
+ fi
+ else
+ echo $1
+ fi
+}
+
+
+
+# Set up CVSROOT (the crerepos tests will test operating without CVSROOT set).
+#
+# Currently we test :fork: and :ext: (see crerepos test). There is a
+# known difference between the two in modes-15 (see comments there).
+#
+# :ext: can be tested against a remote machine if:
+#
+# 1. $remotehost is set using the `-h' option to this script.
+# 2. ${CVS_RSH=rsh} $remotehost works.
+# 3. The path to $TESTDIR is the same on both machines (symlinks are okay)
+# 4. The path to $testcvs is the same on both machines (symlinks are okay)
+# or $CVS_SERVER is overridden in this script's environment to point to
+# a working CVS exectuable on the remote machine.
+#
+# Testing :pserver: would be hard (inetd issues). (How about using tcpserver
+# and some high port number? DRP)
+
+if $linkroot; then
+ mkdir ${TESTDIR}/realcvsroot
+ ln -s realcvsroot ${TESTDIR}/cvsroot
+fi
+CVSROOT_DIRNAME=${TESTDIR}/cvsroot
+CVSROOT=`newroot $CVSROOT_DIRNAME`; export CVSROOT
+
+
+
+###
+### Initialize the repository
+###
+dotest init-1 "$testcvs init"
+
+# Now hide the primary root behind a secondary if requested.
+if $proxy; then
+ # Save the primary root.
+ PRIMARY_CVSROOT=$CVSROOT
+ PRIMARY_CVSROOT_DIRNAME=$CVSROOT_DIRNAME
+ # Where the secondary root will be
+ SECONDARY_CVSROOT_DIRNAME=$TESTDIR/secondary_cvsroot
+ if $noredirect; then
+ rootoptions=";Redirect=no"
+ SECONDARY_CVSROOT=`newroot $PRIMARY_CVSROOT_DIRNAME`
+ else
+ SECONDARY_CVSROOT=`newroot $SECONDARY_CVSROOT_DIRNAME`
+ fi
+ # Now set the global CVSROOT to use the secondary.
+ CVSROOT=$SECONDARY_CVSROOT; export CVSROOT
+
+ require_rsync
+ if test $? -eq 77; then
+ echo "Unable to test in proxy mode: $skipreason" >&2
+ skip all "missing or broken rsync command."
+ exit 0
+ fi
+
+ if $noredirect; then
+ # Wrap the CVS server to allow --primary-root to be set by the
+ # secondary.
+ cat <<EOF >$TESTDIR/secondary-wrapper
+#! $TESTSHELL
+CVS_SERVER=$TESTDIR/primary-wrapper
+export CVS_SERVER
+
+# No need to check the PID of the last client since we are testing with
+# Redirect disabled.
+proot_arg="--allow-root=$SECONDARY_CVSROOT_DIRNAME"
+exec $CVS_SERVER \$proot_arg "\$@"
+EOF
+ cat <<EOF >$TESTDIR/primary-wrapper
+#! $TESTSHELL
+if test -n "$CVS_SERVER_LOG"; then
+ CVS_SERVER_LOG=`dirname "$CVS_SERVER_LOG"`/cvsprimarylog
+ export CVS_SERVER_LOG
+fi
+exec $CVS_SERVER "\$@"
+EOF
+
+ CVS_SERVER_secondary=$TESTDIR/secondary-wrapper
+ CVS_SERVER=$CVS_SERVER_secondary
+
+ chmod a+x $TESTDIR/secondary-wrapper \
+ $TESTDIR/primary-wrapper
+ fi
+
+ # Script to sync the secondary root.
+ cat >$TESTDIR/sync-secondary <<EOF
+#! $TESTSHELL
+# date >>$TESTDIR/update-log
+
+ps=\$1
+cmd=\$2
+dir=\$3
+shift
+shift
+shift
+
+# echo "updating from \$ps for command \\\`\$cmd' in dir \\\`\$dir'" \${1+"\$@"} \\
+# >>$TESTDIR/update-log
+
+# If multiple CVS executables could attempt to access the repository, we would
+# Need to lock for this sync and sleep
+case "\$dir" in
+ ALL)
+ # This is a hack to allow a few of the tests to play with the
+ # UseNewInfoFmtStrings key in CVSROOT/config. It's inefficient, but there
+ # aren't many tests than need it and the alternative is an awful lot of
+ # special casing.
+ $RSYNC -rglop --delete --exclude '#cvs.*' \\
+ $PRIMARY_CVSROOT_DIRNAME/ \\
+ $SECONDARY_CVSROOT_DIRNAME
+ ;;
+
+ *)
+ # For the majority of the tests we will only sync the directories that
+ # were written to.
+ case "\$cmd" in
+ add|import)
+ # For \`add', we need a recursive update due to quirks in rsync syntax,
+ # but it shouldn't affect efficiency since any new dir should be empty.
+ #
+ # For \`import', a recursive update is necessary since subdirs may have
+ # been added underneath the root dir we were passed.
+ $RSYNC -rglop \\
+ $PRIMARY_CVSROOT_DIRNAME/"\$dir" \\
+ $SECONDARY_CVSROOT_DIRNAME/\`dirname -- "\$dir"\`
+ ;;
+
+ tag)
+ # \`tag' may have changed CVSROOT/val-tags too.
+ $RSYNC -glop \\
+ $PRIMARY_CVSROOT_DIRNAME/CVSROOT/val-tags \\
+ $SECONDARY_CVSROOT_DIRNAME/CVSROOT
+ # Otherwise it is identical to other write commands.
+ $RSYNC -rglop --delete \\
+ --include Attic --include CVS \
+ --exclude '#cvs.*' --exclude '*/' \\
+ $PRIMARY_CVSROOT_DIRNAME/"\$dir"/ \\
+ $SECONDARY_CVSROOT_DIRNAME/"\$dir"
+ ;;
+
+ *)
+ # By default, sync just what changed.
+ $RSYNC -rglop --delete \\
+ --include Attic --include CVS \
+ --exclude '#cvs.*' --exclude '*/' \\
+ $PRIMARY_CVSROOT_DIRNAME/"\$dir"/ \\
+ $SECONDARY_CVSROOT_DIRNAME/"\$dir"
+ ;;
+ esac # \$cmd
+
+ # And keep the history file up to date for all commands.
+ $RSYNC -glop \\
+ $PRIMARY_CVSROOT_DIRNAME/CVSROOT/history \\
+ $SECONDARY_CVSROOT_DIRNAME/CVSROOT
+ ;; # \$dir = *
+esac # \$dir
+
+# Avoid timestamp comparison issues with rsync.
+sleep 1
+EOF
+ chmod a+x $TESTDIR/sync-secondary
+
+ # And now init the secondary.
+ $TESTDIR/sync-secondary "- no, before - create secondary root" \
+ sanity-setup ALL
+
+ # Initialize the primary repository
+ mkdir proxy-init; cd proxy-init
+ dotest proxy-init-1 "$testcvs -Qd$PRIMARY_CVSROOT co CVSROOT"
+ cd CVSROOT
+ cat >>config <<EOF
+PrimaryServer=$PRIMARY_CVSROOT
+EOF
+ cat >>loginfo <<EOF
+ALL $TESTDIR/sync-secondary loginfo %c %p %{sVv}
+EOF
+ cat >>postadmin <<EOF
+ALL $TESTDIR/sync-secondary postadmin %c %p
+EOF
+ cat >>posttag <<EOF
+ALL $TESTDIR/sync-secondary posttag %c %p %o %b %t %{sVv}
+EOF
+ cat >>postwatch <<EOF
+ALL $TESTDIR/sync-secondary postwatch %c %p
+EOF
+ dotest proxy-init-2 \
+"$testcvs -Q ci -mconfigure-writeproxy"
+
+ # Save these files for later reference
+ cp config $TESTDIR/config-clean
+ cp loginfo $TESTDIR/loginfo-clean
+ cp postadmin $TESTDIR/postadmin-clean
+ cp posttag $TESTDIR/posttag-clean
+ cp postwatch $TESTDIR/postwatch-clean
+
+ # done in here
+ cd ../..
+ rm -rf proxy-init
+else # !$proxy
+ # Set this even when not testing $proxy to match messages, like $SPROG.
+ SECONDARY_CVSROOT_DIRNAME=$CVSROOT_DIRNAME
+fi # $proxy
+
+# Save a copy of the initial repository so that it may be restored after the
+# tests that alter it.
+cp -Rp $CVSROOT_DIRNAME/CVSROOT $TESTDIR/CVSROOT.save
+
+
+###
+### The tests
+###
+dotest init-2 "$testcvs init"
+
+
+
+###
+### The big loop
+###
+for what in $tests; do
+ if test -n "$fromtest" ; then
+ if test $fromtest = $what ; then
+ unset fromtest
+ else
+ continue
+ fi
+ fi
+ case $what in
+
+ version)
+ # We've had cases where the version command started dumping core,
+ # so we might as well test it
+ dotest version-1 "${testcvs} --version" \
+'
+Concurrent Versions System (CVS) [0-9.]*.*
+
+Copyright (C) [0-9]* Free Software Foundation, Inc.
+
+Senior active maintainers include Larry Jones, Derek R. Price,
+and Mark D. Baushke. Please see the AUTHORS and README files from the CVS
+distribution kit for a complete list of contributors and copyrights.
+
+CVS may be copied only under the terms of the GNU General Public License,
+a copy of which can be found with the CVS distribution kit.
+
+Specify the --help option for further information about CVS'
+
+# Maybe someday...
+# if $proxy; then
+# dotest version-2r "${testcvs} version" \
+#'Client: Concurrent Versions System (CVS) [0-9p.]* (client.*)
+#Server: Concurrent Versions System (CVS) [0-9p.]* (.*server)
+#Secondary Server: Concurrent Versions System (CVS) [0-9p.]* (.*server)'
+ if $remote; then
+ dotest version-2r "${testcvs} version" \
+'Client: Concurrent Versions System (CVS) [0-9p.]* (client.*)
+Server: Concurrent Versions System (CVS) [0-9p.]* (.*server)'
+ else
+ dotest version-2 "${testcvs} version" \
+'Concurrent Versions System (CVS) [0-9.]*.*'
+ fi
+ ;;
+
+
+
+ basica)
+ # Similar in spirit to some of the basic1, and basic2
+ # tests, but hopefully a lot faster. Also tests operating on
+ # files two directories down *without* operating on the parent dirs.
+
+ # Tests basica-0a and basica-0b provide the equivalent of the:
+ # mkdir ${CVSROOT_DIRNAME}/first-dir
+ # used by many of the tests. It is "more official" in the sense
+ # that is does everything through CVS; the reason most of the
+ # tests don't use it is mostly historical.
+ mkdir 1; cd 1
+ dotest basica-0a "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest basica-0b "$testcvs add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd ..
+ rm -r 1
+
+ dotest basica-1 "$testcvs -q co first-dir" ''
+ cd first-dir
+
+ # Test a few operations, to ensure they gracefully do
+ # nothing in an empty directory.
+ dotest basica-1a0 "$testcvs -q update"
+ dotest basica-1a1 "$testcvs -q diff -c"
+ dotest basica-1a2 "$testcvs -q status"
+ dotest basica-1a3 "$testcvs -q update ."
+ dotest basica-1a4 "$testcvs -q update ./"
+
+ mkdir sdir
+ # Remote CVS gives the "cannot open CVS/Entries" error, which is
+ # clearly a bug, but not a simple one to fix.
+ dotest basica-1a10 "$testcvs -n add sdir" \
+"Directory $CVSROOT_DIRNAME/first-dir/sdir added to the repository" \
+"$SPROG add: cannot open CVS/Entries for reading: No such file or directory
+Directory $CVSROOT_DIRNAME/first-dir/sdir added to the repository"
+ dotest_fail basica-1a11 \
+ "test -d $CVSROOT_DIRNAME/first-dir/sdir"
+ dotest basica-2 "$testcvs add sdir" \
+"Directory $CVSROOT_DIRNAME/first-dir/sdir added to the repository"
+ cd sdir
+ mkdir ssdir
+ dotest basica-3 "$testcvs add ssdir" \
+"Directory $CVSROOT_DIRNAME/first-dir/sdir/ssdir added to the repository"
+ cd ssdir
+ echo ssfile >ssfile
+
+ # Trying to commit it without a "cvs add" should be an error.
+ # The "use `cvs add' to create an entry" message is the one
+ # that I consider to be more correct, but local cvs prints the
+ # "nothing known" message and noone has gotten around to fixing it.
+ dotest_fail basica-notadded "${testcvs} -q ci ssfile" \
+"${CPROG} commit: use .${CPROG} add. to create an entry for \`ssfile'
+${CPROG}"' \[commit aborted\]: correct above errors first!' \
+"${CPROG}"' commit: nothing known about `ssfile'\''
+'"${CPROG}"' \[commit aborted\]: correct above errors first!'
+
+ dotest basica-4 "${testcvs} add ssfile" \
+"${SPROG}"' add: scheduling file `ssfile'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest_fail basica-4a "${testcvs} tag tag0 ssfile" \
+"${SPROG} tag: nothing known about ssfile
+${SPROG} "'\[tag aborted\]: correct the above errors first!'
+ cd ../..
+ dotest basica-5 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- sdir/ssdir/ssfile
+initial revision: 1\.1"
+ dotest_fail basica-5a \
+ "${testcvs} -q tag BASE sdir/ssdir/ssfile" \
+"${SPROG} tag: Attempt to add reserved tag name BASE
+${SPROG} \[tag aborted\]: failed to set tag BASE to revision 1\.1 in ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v"
+ dotest basica-5b "${testcvs} -q tag NOT_RESERVED" \
+'T sdir/ssdir/ssfile'
+
+ dotest basica-6 "${testcvs} -q update" ''
+ echo "ssfile line 2" >>sdir/ssdir/ssfile
+ dotest_fail basica-6.2 "${testcvs} -q diff -c" \
+"Index: sdir/ssdir/ssfile
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+retrieving revision 1\.1
+diff -c -r1\.1 ssfile
+\*\*\* sdir/ssdir/ssfile ${RFCDATE} 1\.1
+--- sdir/ssdir/ssfile ${RFCDATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+--- 1,2 ----
+ ssfile
+${PLUS} ssfile line 2"
+ dotest_fail basica-6.3 "${testcvs} -q diff -c -rBASE" \
+"Index: sdir/ssdir/ssfile
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+retrieving revision 1\.1
+diff -c -r1\.1 ssfile
+\*\*\* sdir/ssdir/ssfile ${RFCDATE} 1\.1
+--- sdir/ssdir/ssfile ${RFCDATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+--- 1,2 ----
+ ssfile
+${PLUS} ssfile line 2"
+ dotest_fail basica-6.4 "${testcvs} -q diff -c -rBASE -C3isacrowd" \
+"Index: sdir/ssdir/ssfile
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+retrieving revision 1\.1
+diff -c -C 3isacrowd -r1\.1 ssfile
+${SPROG} diff: invalid context length argument"
+ dotest basica-7 "${testcvs} -q ci -m modify-it" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- sdir/ssdir/ssfile
+new revision: 1\.2; previous revision: 1\.1"
+ dotest_fail basica-nonexist "${testcvs} -q ci nonexist" \
+"${CPROG}"' commit: nothing known about `nonexist'\''
+'"${CPROG}"' \[commit aborted\]: correct above errors first!'
+ dotest basica-8 "${testcvs} -q update ." ''
+
+ # Test the -f option to ci
+ cd sdir/ssdir
+ dotest basica-8a0 "${testcvs} -q ci -m not-modified ssfile" ''
+ dotest basica-8a "${testcvs} -q ci -f -m force-it" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 1\.3; previous revision: 1\.2"
+ dotest basica-8a1 "${testcvs} -q ci -m bump-it -r 2.0" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 2\.0; previous revision: 1\.3"
+ dotest basica-8a1a "${testcvs} -q ci -m bump-it -r 2.9" \
+"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 2\.9; previous revision: 2\.0"
+ # Test string-based revion number increment rollover
+ dotest basica-8a1b "${testcvs} -q ci -m bump-it -f -r 2" \
+"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 2\.10; previous revision: 2\.9"
+ dotest basica-8a1c "${testcvs} -q ci -m bump-it -r 2.99" \
+"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 2\.99; previous revision: 2\.10"
+ # Test string-based revion number increment rollover
+ dotest basica-8a1d "${testcvs} -q ci -m bump-it -f -r 2" \
+"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 2\.100; previous revision: 2\.99"
+ dotest basica-8a1e "${testcvs} -q ci -m bump-it -r 2.1099" \
+"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 2\.1099; previous revision: 2\.100"
+ # Test string-based revion number increment rollover
+ dotest basica-8a1f "${testcvs} -q ci -m bump-it -f -r 2" \
+"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 2\.1100; previous revision: 2\.1099"
+ # -f should not be necessary, but it should be harmless.
+ # Also test the "-r 3" (rather than "-r 3.0") usage.
+ dotest basica-8a2 "${testcvs} -q ci -m bump-it -f -r 3" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 3\.1; previous revision: 2\.1100"
+
+ # Test using -r to create a branch
+ dotest_fail basica-8a3 "${testcvs} -q ci -m bogus -r 3.0.0" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+$SPROG commit: $CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v: can't find branch point 3\.0
+$SPROG commit: could not check in ssfile"
+ dotest basica-8a4 "${testcvs} -q ci -m valid -r 3.1.2" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 3\.1\.2\.1; previous revision: 3\.1"
+ # now get rid of the sticky tag and go back to the trunk
+ dotest basica-8a5 "${testcvs} -q up -A ./" "[UP] ssfile"
+
+ cd ../..
+ dotest basica-8b "${testcvs} -q diff -r1.2 -r1.3"
+
+ dotest basica-8b1 "${testcvs} -q diff -r1.2 -r1.3 -C 3isacrowd"
+
+ # The .* here will normally be "No such file or directory",
+ # but if memory serves some systems (AIX?) have a different message.
+: dotest_fail basica-9 \
+ "${testcvs} -q -d ${TESTDIR}/nonexist update" \
+"${SPROG}: cannot access cvs root ${TESTDIR}/nonexist: .*"
+ dotest_fail basica-9a \
+ "${testcvs} -q -d ${TESTDIR}/nonexist update" \
+"${CPROG} \[update aborted\]: ${TESTDIR}/nonexist/CVSROOT: .*"
+
+ dotest basica-10 "${testcvs} annotate" \
+'
+Annotations for sdir/ssdir/ssfile
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 .'"$username8"' *[0-9a-zA-Z-]*.: ssfile
+1\.2 .'"$username8"' *[0-9a-zA-Z-]*.: ssfile line 2'
+
+ # Test resurrecting with strange revision numbers
+ cd sdir/ssdir
+ dotest basica-r1 "${testcvs} rm -f ssfile" \
+"${SPROG} remove: scheduling .ssfile. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest basica-r2 "${testcvs} -q ci -m remove" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: delete; previous revision: 3\.1"
+ dotest basica-r3 "${testcvs} -q up -p -r 3.1 ./ssfile >ssfile" ""
+ dotest basica-r4 "${testcvs} add ssfile" \
+"${SPROG} add: Re-adding file .ssfile. after dead revision 3\.2\.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest basica-r5 "${testcvs} -q ci -m resurrect" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v <-- ssfile
+new revision: 3\.3; previous revision: 3\.2"
+ cd ../..
+
+ # As long as we have a file with a few revisions, test
+ # a few "cvs admin -o" invocations.
+ cd sdir/ssdir
+ dotest_fail basica-o1 "${testcvs} admin -o 1.2::1.2" \
+"${CPROG} admin: while processing more than one file:
+${CPROG} \[admin aborted\]: attempt to specify a numeric revision"
+ dotest basica-o2 "${testcvs} admin -o 1.2::1.2 ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+done"
+ dotest basica-o2a "${testcvs} admin -o 1.1::NOT_RESERVED ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+done"
+ dotest_fail basica-o2b "${testcvs} admin -o 1.1::NOT_EXIST ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v: Revision NOT_EXIST doesn't exist.
+${SPROG} admin: RCS file for .ssfile. not modified\."
+ dotest basica-o3 "${testcvs} admin -o 1.2::1.3 ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+done"
+ dotest basica-o4 "${testcvs} admin -o 3.1:: ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+deleting revision 3\.3
+deleting revision 3\.2
+done"
+ dotest basica-o5 "${testcvs} admin -o ::1.1 ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+done"
+ dotest basica-o5a "${testcvs} -n admin -o 1.2::3.1 ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+deleting revision 2\.1100
+deleting revision 2\.1099
+deleting revision 2\.100
+deleting revision 2\.99
+deleting revision 2\.10
+deleting revision 2\.9
+deleting revision 2\.0
+deleting revision 1\.3
+done"
+ dotest basica-o6 "${testcvs} admin -o 1.2::3.1 ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+deleting revision 2\.1100
+deleting revision 2\.1099
+deleting revision 2\.100
+deleting revision 2\.99
+deleting revision 2\.10
+deleting revision 2\.9
+deleting revision 2\.0
+deleting revision 1\.3
+done"
+ dotest basica-o6a "${testcvs} admin -o 3.1.2: ssfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+deleting revision 3\.1\.2\.1
+done"
+ dotest basica-o7 "${testcvs} log -N ssfile" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
+Working file: ssfile
+head: 3\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 3\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+bump-it
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify-it
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+add-it
+============================================================================="
+ dotest basica-o8 "${testcvs} -q update -p -r 1.1 ./ssfile" "ssfile"
+ cd ../..
+
+ cd ..
+
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r first-dir
+ ;;
+
+
+
+ basicb)
+ # More basic tests, including non-branch tags and co -d.
+ mkdir 1; cd 1
+ dotest basicb-0a "${testcvs} -q co -l ." ''
+ touch topfile
+ dotest basicb-0b "${testcvs} add topfile" \
+"${SPROG} add: scheduling file .topfile. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest basicb-0c "${testcvs} -q ci -m add-it topfile" \
+"$CVSROOT_DIRNAME/topfile,v <-- topfile
+initial revision: 1\.1"
+ cd ..
+ rm -r 1
+ mkdir 2; cd 2
+ dotest basicb-0d "${testcvs} -q co -l ." "U topfile"
+ # Now test the ability to run checkout on an existing working
+ # directory without having it lose its mind. I don't know
+ # whether this is tested elsewhere in sanity.sh. A more elaborate
+ # test might also have modified files, make sure it works if
+ # the modules file was modified to add new directories to the
+ # module, and such.
+ dotest basicb-0d0 "${testcvs} -q co -l ." ""
+ mkdir first-dir
+ dotest basicb-0e "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd ..
+ rm -r 2
+
+ dotest basicb-1 "${testcvs} -q co first-dir" ''
+
+ # The top-level CVS directory is not created by default.
+ # I'm leaving basicb-1a and basicb-1b untouched, mostly, in
+ # case we decide that the default should be reversed...
+
+ dotest_fail basicb-1a "test -d CVS" ''
+
+ dotest basicb-1c "cat first-dir/CVS/Repository" "first-dir"
+
+ cd first-dir
+ # Note that the name Emptydir is chosen to test that CVS just
+ # treats it like any other directory name. It should be
+ # special only when it is directly in $CVSROOT/CVSROOT.
+ mkdir Emptydir sdir2
+ dotest basicb-2 "${testcvs} add Emptydir sdir2" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/Emptydir added to the repository
+Directory ${CVSROOT_DIRNAME}/first-dir/sdir2 added to the repository"
+ cd Emptydir
+ echo sfile1 starts >sfile1
+ dotest basicb-2a10 "${testcvs} -n add sfile1" \
+"${SPROG} add: scheduling file .sfile1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest basicb-2a11 "${testcvs} status sfile1" \
+"${SPROG} status: use \`${SPROG} add' to create an entry for \`sfile1'
+===================================================================
+File: sfile1 Status: Unknown
+
+ Working revision: No entry for sfile1
+ Repository revision: No revision control file"
+ dotest basicb-3 "${testcvs} add sfile1" \
+"${SPROG} add: scheduling file .sfile1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest basicb-3a1 "${testcvs} status sfile1" \
+"===================================================================
+File: sfile1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ cd ../sdir2
+ echo sfile2 starts >sfile2
+ dotest basicb-4 "${testcvs} add sfile2" \
+"${SPROG} add: scheduling file .sfile2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest basicb-4a "${testcvs} -q ci CVS" \
+"${CPROG} commit: warning: directory CVS specified in argument
+${CPROG} commit: but CVS uses CVS for its own purposes; skipping CVS directory"
+ cd ..
+ dotest basicb-5 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/Emptydir/sfile1,v <-- Emptydir/sfile1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/sdir2/sfile2,v <-- sdir2/sfile2
+initial revision: 1\.1"
+ echo sfile1 develops >Emptydir/sfile1
+ dotest basicb-6 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/Emptydir/sfile1,v <-- Emptydir/sfile1
+new revision: 1\.2; previous revision: 1\.1"
+ dotest basicb-7 "${testcvs} -q tag release-1" 'T Emptydir/sfile1
+T sdir2/sfile2'
+ echo not in time for release-1 >sdir2/sfile2
+ dotest basicb-8 "${testcvs} -q ci -m modify-2" \
+"$CVSROOT_DIRNAME/first-dir/sdir2/sfile2,v <-- sdir2/sfile2
+new revision: 1\.2; previous revision: 1\.1"
+ # See if CVS can correctly notice when an invalid numeric
+ # revision is specified.
+ # Commented out until we get around to fixing CVS
+: dotest basicb-8a0 "${testcvs} diff -r 1.5 -r 1.7 sfile2" 'error msg'
+ cd ..
+
+ # Test that we recurse into the correct directory when checking
+ # for existing files, even if co -d is in use.
+ touch first-dir/extra
+ dotest basicb-cod-1 "${testcvs} -q co -d first-dir1 first-dir" \
+'U first-dir1/Emptydir/sfile1
+U first-dir1/sdir2/sfile2'
+ rm -r first-dir1
+
+ rm -r first-dir
+
+ # FIXME? basicb-9 used to check things out like this:
+ # U newdir/Emptydir/sfile1
+ # U newdir/sdir2/sfile2
+ # but that's difficult to do. The whole "shorten" thing
+ # is pretty bogus, because it will break on things
+ # like "cvs co foo/bar baz/quux". Unless there's some
+ # pretty detailed expansion and analysis of the command-line
+ # arguments, we shouldn't do "shorten" stuff at all.
+
+ dotest basicb-9 \
+"${testcvs} -q co -d newdir -r release-1 first-dir/Emptydir first-dir/sdir2" \
+'U newdir/first-dir/Emptydir/sfile1
+U newdir/first-dir/sdir2/sfile2'
+
+ # basicb-9a and basicb-9b: see note about basicb-1a
+
+ dotest_fail basicb-9a "test -d CVS" ''
+
+ dotest basicb-9c "cat newdir/CVS/Repository" "\."
+ dotest basicb-9d "cat newdir/first-dir/CVS/Repository" \
+"${CVSROOT_DIRNAME}/first-dir" \
+"first-dir"
+ dotest basicb-9e "cat newdir/first-dir/Emptydir/CVS/Repository" \
+"${CVSROOT_DIRNAME}/first-dir/Emptydir" \
+"first-dir/Emptydir"
+ dotest basicb-9f "cat newdir/first-dir/sdir2/CVS/Repository" \
+"${CVSROOT_DIRNAME}/first-dir/sdir2" \
+"first-dir/sdir2"
+
+ dotest basicb-10 "cat newdir/first-dir/Emptydir/sfile1 newdir/first-dir/sdir2/sfile2" \
+"sfile1 develops
+sfile2 starts"
+
+ rm -r newdir
+
+ # Hmm, this might be a case for CVSNULLREPOS, but CVS doesn't
+ # seem to deal with it...
+ if false; then
+ dotest basicb-11 "${testcvs} -q co -d sub1/sub2 first-dir" \
+"U sub1/sub2/Emptydir/sfile1
+U sub1/sub2/sdir2/sfile2"
+ cd sub1
+ dotest basicb-12 "${testcvs} -q update ./." ''
+ touch xx
+ dotest basicb-13 "${testcvs} add xx" fixme
+ cd ..
+ rm -r sub1
+ # to test: sub1/sub2/sub3
+ fi # end of tests commented out.
+
+ # Create a second directory.
+ mkdir 1
+ cd 1
+ dotest basicb-14 "${testcvs} -q co -l ." 'U topfile'
+ mkdir second-dir
+ dotest basicb-15 "${testcvs} add second-dir" \
+"Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
+ cd second-dir
+ touch aa
+ dotest basicb-16 "${testcvs} add aa" \
+"${SPROG} add: scheduling file .aa. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest basicb-17 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/second-dir/aa,v <-- aa
+initial revision: 1\.1"
+ cd ..
+
+ # Try to remove all revisions in a file.
+ dotest_fail basicb-o1 "${testcvs} admin -o1.1 topfile" \
+"RCS file: ${CVSROOT_DIRNAME}/topfile,v
+deleting revision 1\.1
+${SPROG} \[admin aborted\]: attempt to delete all revisions"
+ dotest basicb-o2 "${testcvs} -q update -d first-dir" \
+"U first-dir/Emptydir/sfile1
+U first-dir/sdir2/sfile2"
+ dotest_fail basicb-o3 \
+"${testcvs} admin -o1.1:1.2 first-dir/sdir2/sfile2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir2/sfile2,v
+deleting revision 1\.2
+deleting revision 1\.1
+${SPROG} \[admin aborted\]: attempt to delete all revisions"
+ cd ..
+ rm -r 1
+
+ mkdir 1; cd 1
+ # Note that -H is an invalid option.
+ # I suspect that the choice between "illegal" and "invalid"
+ # depends on the user's environment variables, the phase
+ # of the moon (weirdness with optind), and who knows what else.
+ # I've been seeing "illegal"...
+ # And I switched it to "invalid". -DRP
+ # POSIX 1003.2 specifies the format should be 'illegal option'
+ # many other folks are still using the older 'invalid option'
+ # lib/getopt.c will use POSIX when __posixly_correct
+ # otherwise the other, so accept both of them. -- mdb
+ dotest_fail basicb-21 "${testcvs} -q admin -H" \
+"admin: invalid option -- H
+${CPROG} \[admin aborted\]: specify ${CPROG} -H admin for usage information" \
+"admin: illegal option -- H
+${CPROG} \[admin aborted\]: specify ${CPROG} -H admin for usage information"
+ cd ..
+ rmdir 1
+
+ if $keep; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir
+ modify_repo rm -f $CVSROOT_DIRNAME/topfile,v
+ ;;
+
+
+
+ basicc)
+ # More tests of basic/miscellaneous functionality.
+ mkdir 1; cd 1
+ dotest_fail basicc-1 "$testcvs diff" \
+"$CPROG diff: in directory \.:
+$CPROG \[diff aborted\]: there is no version here; run .$CPROG checkout. first"
+ dotest basicc-2 "$testcvs -q co -l ."
+ mkdir first-dir second-dir
+ dotest basicc-3 "${testcvs} add first-dir second-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository
+Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
+ # Old versions of CVS often didn't create this top-level CVS
+ # directory in the first place. I think that maybe the only
+ # way to get it to work currently is to let CVS create it,
+ # and then blow it away (don't complain if it does not
+ # exist). But that is perfectly valid; people who are used
+ # to the old behavior especially may be interested.
+ # FIXME: this test is intended for the TopLevelAdmin=yes case;
+ # should adjust/move it accordingly.
+ rm -rf CVS
+ dotest basicc-4 "echo *" "first-dir second-dir"
+ dotest basicc-5 "${testcvs} update" \
+"${SPROG} update: Updating first-dir
+${SPROG} update: Updating second-dir" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating first-dir
+${SPROG} update: Updating second-dir"
+
+ cd first-dir
+ dotest basicc-6 "${testcvs} release -d" ""
+ dotest basicc-7 "test -d ../first-dir" ""
+ # The Linux 2.2 kernel lets you delete ".". That's OK either way,
+ # the point is that CVS must not mess with anything *outside* "."
+ # the way that CVS 1.10 and older tried to.
+ dotest basicc-8 "${testcvs} -Q release -d ." \
+"" "${CPROG} release: deletion of directory \. failed: .*"
+ dotest basicc-9 "test -d ../second-dir" ""
+ # For CVS to make a syntactic check for "." wouldn't suffice.
+ # On Linux 2.2 systems, the cwd may be gone, so we recreate it
+ # to allow basicc-11 to actually happen
+ if test ! -d ../first-dir; then
+ # Apparently `cd ..' doesn't work with Linux 2.2 & Bash 2.05b.
+ cd $TESTDIR/1
+ mkdir ./first-dir
+ cd ./first-dir
+ fi
+ dotest basicc-11 "${testcvs} -Q release -d ./." \
+"" "${CPROG} release: deletion of directory \./\. failed: .*"
+ dotest basicc-11a "test -d ../second-dir" ""
+
+ cd ../..
+
+ mkdir 2; cd 2
+ dotest basicc-12 "${testcvs} -Q co ." ""
+ # actual entries can be in either Entries or Entries.log, do
+ # an update to get them consolidated into Entries
+ dotest basicc-12a "${testcvs} -Q up" ""
+ dotest basicc-12b "cat CVS/Entries" \
+"D/CVSROOT////
+D/first-dir////
+D/second-dir////"
+ dotest basicc-13 "echo *" "CVS CVSROOT first-dir second-dir"
+ dotest basicc-14 "${testcvs} -Q release first-dir second-dir" ""
+ # a normal release shouldn't affect the Entries file
+ dotest basicc-14b "cat CVS/Entries" \
+"D/CVSROOT////
+D/first-dir////
+D/second-dir////"
+ # FIXCVS: but release -d probably should
+ dotest basicc-15 "${testcvs} -Q release -d first-dir second-dir" ""
+ dotest basicc-16 "echo *" "CVS CVSROOT"
+ dotest basicc-17 "cat CVS/Entries" \
+"D/CVSROOT////
+D/first-dir////
+D/second-dir////"
+ # FIXCVS: if not, update should notice the missing directories
+ # and update Entries accordingly
+ dotest basicc-18 "${testcvs} -Q up" ""
+ dotest basicc-19 "cat CVS/Entries" \
+"D/CVSROOT////
+D/first-dir////
+D/second-dir////"
+
+ cd ..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ basic1)
+ # first dive - add a files, first singly, then in a group.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir basic1; cd basic1
+ # check out an empty directory
+ dotest basic1-1 "${testcvs} -q co first-dir" ''
+
+ cd first-dir
+ echo file2 >file2
+ echo file3 >file3
+ echo file4 >file4
+ echo file5 >file5
+
+ dotest basic1-14-add-add "${testcvs} add file2 file3 file4 file5" \
+"${SPROG} add: scheduling file \`file2' for addition
+${SPROG} add: scheduling file \`file3' for addition
+${SPROG} add: scheduling file \`file4' for addition
+${SPROG} add: scheduling file \`file5' for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest basic1-15-add-add \
+"${testcvs} -q update file2 file3 file4 file5" \
+"A file2
+A file3
+A file4
+A file5"
+ dotest basic1-16-add-add "${testcvs} -q update" \
+"A file2
+A file3
+A file4
+A file5"
+ dotest basic1-17-add-add "${testcvs} -q status" \
+"===================================================================
+File: file2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file4 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file5 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest basic1-18-add-add "${testcvs} -q log" \
+"${SPROG} log: file2 has been added, but not committed
+${SPROG} log: file3 has been added, but not committed
+${SPROG} log: file4 has been added, but not committed
+${SPROG} log: file5 has been added, but not committed"
+ cd ..
+ dotest basic1-21-add-add "${testcvs} -q update" \
+"A first-dir/file2
+A first-dir/file3
+A first-dir/file4
+A first-dir/file5"
+ # FIXCVS? Shouldn't this read first-dir/file2 instead of file2?
+ dotest basic1-22-add-add "${testcvs} log first-dir" \
+"${SPROG} log: Logging first-dir
+${SPROG} log: file2 has been added, but not committed
+${SPROG} log: file3 has been added, but not committed
+${SPROG} log: file4 has been added, but not committed
+${SPROG} log: file5 has been added, but not committed"
+ dotest basic1-23-add-add "${testcvs} status first-dir" \
+"${SPROG} status: Examining first-dir
+===================================================================
+File: file2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file4 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file5 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest basic1-24-add-add "${testcvs} update first-dir" \
+"${SPROG} update: Updating first-dir
+A first-dir/file2
+A first-dir/file3
+A first-dir/file4
+A first-dir/file5"
+ dotest basic1-27-add-add "${testcvs} co first-dir" \
+"${SPROG} checkout: Updating first-dir
+A first-dir/file2
+A first-dir/file3
+A first-dir/file4
+A first-dir/file5"
+ cd first-dir
+ dotest basic1-14-add-ci \
+"$testcvs commit -m test file2 file3 file4 file5" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+initial revision: 1\.1"
+ dotest basic1-15-add-ci \
+"${testcvs} -q update file2 file3 file4 file5" ''
+ dotest basic1-16-add-ci "${testcvs} -q update" ''
+ dotest basic1-17-add-ci "${testcvs} -q status" \
+"===================================================================
+File: file2 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file4 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file4,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file5 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file5,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ # The "log" tests and friends probably already test the output
+ # from log quite adequately.
+ # Note: using dotest fails here. It seems to be related
+ # to the output being sufficiently large (Red Hat 4.1).
+ # dotest basic1-18-add-ci "${testcvs} log" "${DOTSTAR}"
+ if ${testcvs} -q log >>${LOGFILE}; then
+ pass basic1-18-add-ci
+ else
+ pass basic1-18-add-ci
+ fi
+ cd ..
+ dotest basic1-21-add-ci "${testcvs} -q update" ''
+ # See test basic1-18-add-ci for explanation of non-use of dotest.
+ if ${testcvs} -q log first-dir >>${LOGFILE}; then
+ pass basic1-22-add-ci
+ else
+ pass basic1-22-add-ci
+ fi
+ # At least for the moment I am going to consider 17-add-ci
+ # an adequate test of the output here.
+ # See test basic1-18-add-ci for explanation of non-use of dotest.
+ if ${testcvs} -q status first-dir >>${LOGFILE}; then
+ pass basic1-23-add-ci
+ else
+ pass basic1-23-add-ci
+ fi
+ dotest basic1-24-add-ci "${testcvs} -q update first-dir" ''
+ dotest basic1-27-add-ci "${testcvs} -q co first-dir" ''
+
+ cd first-dir
+ rm file2 file3 file4 file5
+ dotest basic1-14-rm-rm "${testcvs} rm file2 file3 file4 file5" \
+"${SPROG} remove: scheduling .file2. for removal
+${SPROG} remove: scheduling .file3. for removal
+${SPROG} remove: scheduling .file4. for removal
+${SPROG} remove: scheduling .file5. for removal
+${SPROG} remove: use .${SPROG} commit. to remove these files permanently"
+ # 15-rm-rm was commented out. Why?
+ dotest basic1-15-rm-rm \
+"${testcvs} -q update file2 file3 file4 file5" \
+"R file2
+R file3
+R file4
+R file5"
+ dotest basic1-16-rm-rm "${testcvs} -q update" \
+"R file2
+R file3
+R file4
+R file5"
+ dotest basic1-17-rm-rm "${testcvs} -q status" \
+"===================================================================
+File: no file file2 Status: Locally Removed
+
+ Working revision: -1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: no file file3 Status: Locally Removed
+
+ Working revision: -1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: no file file4 Status: Locally Removed
+
+ Working revision: -1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file4,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: no file file5 Status: Locally Removed
+
+ Working revision: -1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file5,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ # Would be nice to test that real logs appear (with dead state
+ # and all), either here or someplace like log2 tests.
+ if ${testcvs} -q log >>${LOGFILE}; then
+ pass basic1-18-rm-rm
+ else
+ fail basic1-18-rm-rm
+ fi
+ cd ..
+ dotest basic1-21-rm-rm "${testcvs} -q update" \
+"R first-dir/file2
+R first-dir/file3
+R first-dir/file4
+R first-dir/file5"
+ if ${testcvs} -q log first-dir >>${LOGFILE}; then
+ pass basic1-22-rm-rm
+ else
+ fail basic1-22-rm-rm
+ fi
+ if ${testcvs} -q status first-dir >>${LOGFILE}; then
+ pass basic1-23-rm-rm
+ else
+ fail basic1-23-rm-rm
+ fi
+ dotest basic1-24-rm-rm "${testcvs} -q update first-dir" \
+"R first-dir/file2
+R first-dir/file3
+R first-dir/file4
+R first-dir/file5"
+ dotest basic1-27-rm-rm "${testcvs} -q co first-dir" \
+"R first-dir/file2
+R first-dir/file3
+R first-dir/file4
+R first-dir/file5"
+ cd first-dir
+ dotest basic1-14-rm-ci "${testcvs} -q commit -m test" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+new revision: delete; previous revision: 1\.1"
+ dotest basic1-15-rm-ci \
+"${testcvs} -q update file2 file3 file4 file5" ''
+ dotest basic1-16-rm-ci "${testcvs} -q update" ''
+ dotest basic1-17-rm-ci "${testcvs} -q status" ''
+ # Would be nice to test that real logs appear (with dead state
+ # and all), either here or someplace like log2 tests.
+ if ${testcvs} -q log >>${LOGFILE}; then
+ pass basic1-18-rm-ci
+ else
+ fail basic1-18-rm-ci
+ fi
+ cd ..
+ dotest basic1-21-rm-ci "${testcvs} -q update" ''
+ if ${testcvs} -q log first-dir >>${LOGFILE}; then
+ pass basic1-22-rm-ci
+ else
+ fail basic1-22-rm-ci
+ fi
+ if ${testcvs} -q status first-dir >>${LOGFILE}; then
+ pass basic1-23-rm-ci
+ else
+ fail basic1-23-rm-ci
+ fi
+ dotest basic1-24-rm-ci "${testcvs} -q update first-dir" ''
+ dotest basic1-27-rm-ci "${testcvs} -q co first-dir" ''
+ cd first-dir
+ # All the files are removed, so nothing gets tagged.
+ dotest basic1-28 "${testcvs} -q tag first-dive" ''
+ cd ..
+ cd ..
+
+ if $keep; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ rm -r basic1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ deep)
+ # Test the ability to operate on directories nested rather deeply.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest deep-1 "${testcvs} -q co first-dir" ''
+ cd first-dir
+ for i in dir1 dir2 dir3 dir4 dir5 dir6 dir7 dir8; do
+ mkdir $i
+ dotest deep-2-$i "${testcvs} add $i" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir1[/dir0-9]* added to the repository"
+ cd $i
+ echo file1 >file1
+ dotest deep-3-$i "${testcvs} add file1" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ done
+ cd ../../../../../../../../..
+ dotest_lit deep-4 "$testcvs -q ci -m add-them first-dir" <<HERE
+$CVSROOT_DIRNAME/first-dir/dir1/file1,v <-- first-dir/dir1/file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/file1,v <-- first-dir/dir1/dir2/file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/file1,v <-- first-dir/dir1/dir2/dir3/file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/file1,v <-- first-dir/dir1/dir2/dir3/dir4/file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/file1,v <-- first-dir/dir1/dir2/dir3/dir4/dir5/file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1,v <-- first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1,v <-- first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1,v <-- first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1
+initial revision: 1.1
+HERE
+
+ cd first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8
+ rm file1
+ dotest deep-4a0 "$testcvs rm file1" \
+"$SPROG remove: scheduling .file1. for removal
+$SPROG remove: use .$SPROG commit. to remove this file permanently"
+ dotest deep-4a1 "$testcvs -q ci -m rm-it" \
+"$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1,v <-- file1
+new revision: delete; previous revision: 1\.1"
+ cd ../../..
+ dotest deep-4a2 "${testcvs} -q update -P dir6/dir7" ''
+ # Should be using "test -e", but it's not portable enough -
+ # Solaris 2.5 does not have it.
+ dotest_fail deep-4a3 "test -d dir6/dir7/dir8" ''
+
+ # Test that if we remove the working directory, CVS does not
+ # recreate it. (I realize that this behavior is what the
+ # users expect, but in the longer run we might want to
+ # re-think it. The corresponding behavior for a file is that
+ # CVS *will* recreate it, and we might want to make it so
+ # that "cvs release -d" is the way to delete the directory
+ # and have it stay gone -kingdon, Oct1996).
+ rm -r dir6
+ dotest deep-4b0a "${testcvs} -q diff"
+ dotest deep-4b0b "${testcvs} -q ci"
+ dotest deep-4b1 "${testcvs} -q update"
+ dotest deep-4b2 "${testcvs} -q update -d -P" \
+'U dir6/file1
+U dir6/dir7/file1'
+
+ # Test what happens if one uses -P when there are files removed
+ # but not committed.
+ cd dir6/dir7
+ dotest deep-rm1 "${testcvs} rm -f file1" \
+"${SPROG} remove: scheduling .file1. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ cd ..
+ dotest deep-rm2 "${testcvs} -q update -d -P" 'R dir7/file1'
+ dotest deep-rm3 "test -d dir7" ''
+ dotest deep-rm4 "$testcvs -q ci -m rm-it" \
+"$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1,v <-- dir7/file1
+new revision: delete; previous revision: 1\.1"
+ dotest deep-rm5 "${testcvs} -q update -d -P" ''
+ dotest_fail deep-rm6 "test -d dir7" ''
+
+ # Test rm -f -R.
+ cd ../..
+ dotest deep-rm7 "${testcvs} rm -f -R dir5" \
+"${SPROG} remove: Removing dir5
+${SPROG} remove: scheduling .dir5/file1. for removal
+${SPROG} remove: Removing dir5/dir6
+${SPROG} remove: scheduling .dir5/dir6/file1. for removal
+${SPROG} remove: use .${SPROG} commit. to remove these files permanently"
+ dotest deep-rm8 "${testcvs} -q ci -m rm-it" \
+"$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/file1,v <-- dir5/file1
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1,v <-- dir5/dir6/file1
+new revision: delete; previous revision: 1\.1"
+ dotest deep-rm9 "${testcvs} -q update -d -P" ''
+ dotest_fail deep-rm10 "test -d dir5"
+
+ cd ../../../../..
+
+ if echo "yes" | $testcvs release -d first-dir >>$LOGFILE 2>&1; then
+ pass deep-5
+ else
+ fail deep-5
+ fi
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ basic2)
+ # Test rtag, import, history, various miscellaneous operations
+
+ # NOTE: this section has reached the size and
+ # complexity where it is getting to be a good idea to
+ # add new tests to a new section rather than
+ # continuing to piggyback them onto the tests here.
+
+ # First empty the history file
+ modify_repo rm -rf $CVSROOT_DIRNAME/CVSROOT/history
+ modify_repo touch $CVSROOT_DIRNAME/CVSROOT/history
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest basic2-1 "$testcvs -q co first-dir"
+ for i in first-dir dir1 dir2 ; do
+ if test ! -d $i ; then
+ mkdir $i
+ dotest basic2-2-$i "${testcvs} add $i" \
+"Directory ${CVSROOT_DIRNAME}/.*/$i added to the repository"
+ fi
+
+ cd $i
+
+ for j in file6 file7; do
+ echo $j > $j
+ done
+
+ dotest basic2-3-$i "${testcvs} add file6 file7" \
+"${SPROG} add: scheduling file .file6. for addition
+${SPROG} add: scheduling file .file7. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+
+ done
+ cd ../../..
+ dotest basic2-4 "${testcvs} update first-dir" \
+"${SPROG} update: Updating first-dir
+A first-dir/file6
+A first-dir/file7
+${SPROG} update: Updating first-dir/dir1
+A first-dir/dir1/file6
+A first-dir/dir1/file7
+${SPROG} update: Updating first-dir/dir1/dir2
+A first-dir/dir1/dir2/file6
+A first-dir/dir1/dir2/file7"
+
+ # fixme: doesn't work right for added files.
+ dotest basic2-5 "${testcvs} log first-dir" \
+"${SPROG} log: Logging first-dir
+${SPROG} log: file6 has been added, but not committed
+${SPROG} log: file7 has been added, but not committed
+${SPROG} log: Logging first-dir/dir1
+${SPROG} log: file6 has been added, but not committed
+${SPROG} log: file7 has been added, but not committed
+${SPROG} log: Logging first-dir/dir1/dir2
+${SPROG} log: file6 has been added, but not committed
+${SPROG} log: file7 has been added, but not committed"
+
+ dotest basic2-6 "${testcvs} status first-dir" \
+"${SPROG} status: Examining first-dir
+===================================================================
+File: file6 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file7 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+${SPROG} status: Examining first-dir/dir1
+===================================================================
+File: file6 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file7 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+${SPROG} status: Examining first-dir/dir1/dir2
+===================================================================
+File: file6 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file7 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+# XXX why is this commented out???
+# if ${CVS} diff -u first-dir >> ${LOGFILE} || test $? = 1 ; then
+# pass 34
+# else
+# fail 34
+# fi
+
+ dotest basic2-8 "${testcvs} -q ci -m 'second dive' first-dir" \
+"$CVSROOT_DIRNAME/first-dir/file6,v <-- first-dir/file6
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file7,v <-- first-dir/file7
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir1/file6,v <-- first-dir/dir1/file6
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir1/file7,v <-- first-dir/dir1/file7
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/file6,v <-- first-dir/dir1/dir2/file6
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir1/dir2/file7,v <-- first-dir/dir1/dir2/file7
+initial revision: 1\.1"
+
+ dotest basic2-9 "${testcvs} tag second-dive first-dir" \
+"${SPROG} tag: Tagging first-dir
+T first-dir/file6
+T first-dir/file7
+${SPROG} tag: Tagging first-dir/dir1
+T first-dir/dir1/file6
+T first-dir/dir1/file7
+${SPROG} tag: Tagging first-dir/dir1/dir2
+T first-dir/dir1/dir2/file6
+T first-dir/dir1/dir2/file7"
+
+ # third dive - in bunch o' directories, add bunch o' files,
+ # delete some, change some.
+
+ for i in first-dir dir1 dir2 ; do
+ cd $i
+
+ # modify a file
+ echo file6 >>file6
+
+ # delete a file
+ rm file7
+
+ dotest basic2-10-$i "${testcvs} rm file7" \
+"${SPROG} remove: scheduling .file7. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+
+ # and add a new file
+ echo file14 >file14
+
+ dotest basic2-11-$i "${testcvs} add file14" \
+"${SPROG} add: scheduling file .file14. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ done
+
+ cd ../../..
+ dotest basic2-12 "${testcvs} update first-dir" \
+"${SPROG} update: Updating first-dir
+A first-dir/file14
+M first-dir/file6
+R first-dir/file7
+${SPROG} update: Updating first-dir/dir1
+A first-dir/dir1/file14
+M first-dir/dir1/file6
+R first-dir/dir1/file7
+${SPROG} update: Updating first-dir/dir1/dir2
+A first-dir/dir1/dir2/file14
+M first-dir/dir1/dir2/file6
+R first-dir/dir1/dir2/file7"
+
+ # FIXME: doesn't work right for added files
+ dotest basic2-13 "${testcvs} log first-dir" \
+"${SPROG} log: Logging first-dir
+${SPROG} log: file14 has been added, but not committed
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file6,v
+Working file: first-dir/file6
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ second-dive: 1\.1
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+second dive
+=============================================================================
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v
+Working file: first-dir/file7
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ second-dive: 1\.1
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+second dive
+=============================================================================
+${SPROG} log: Logging first-dir/dir1
+${SPROG} log: file14 has been added, but not committed
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file6,v
+Working file: first-dir/dir1/file6
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ second-dive: 1\.1
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+second dive
+=============================================================================
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file7,v
+Working file: first-dir/dir1/file7
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ second-dive: 1\.1
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+second dive
+=============================================================================
+${SPROG} log: Logging first-dir/dir1/dir2
+${SPROG} log: file14 has been added, but not committed
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v
+Working file: first-dir/dir1/dir2/file6
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ second-dive: 1\.1
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+second dive
+=============================================================================
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v
+Working file: first-dir/dir1/dir2/file7
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ second-dive: 1\.1
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+second dive
+============================================================================="
+
+ dotest basic2-14 "${testcvs} status first-dir" \
+"${SPROG} status: Examining first-dir
+===================================================================
+File: file14 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file6 Status: Locally Modified
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file6,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: no file file7 Status: Locally Removed
+
+ Working revision: -1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file7,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+${SPROG} status: Examining first-dir/dir1
+===================================================================
+File: file14 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file6 Status: Locally Modified
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/file6,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: no file file7 Status: Locally Removed
+
+ Working revision: -1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/file7,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+${SPROG} status: Examining first-dir/dir1/dir2
+===================================================================
+File: file14 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file6 Status: Locally Modified
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: no file file7 Status: Locally Removed
+
+ Working revision: -1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)${DOTSTAR}"
+
+# XXX why is this commented out?
+# if ${CVS} diff -u first-dir >> ${LOGFILE} || test $? = 1 ; then
+# pass 42
+# else
+# fail 42
+# fi
+
+ dotest basic2-16 "${testcvs} ci -m 'third dive' first-dir" \
+"${CPROG} commit: Examining first-dir
+${CPROG} commit: Examining first-dir/dir1
+${CPROG} commit: Examining first-dir/dir1/dir2
+${CVSROOT_DIRNAME}/first-dir/file14,v <-- first-dir/file14
+initial revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/file6,v <-- first-dir/file6
+new revision: 1\.2; previous revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/file7,v <-- first-dir/file7
+new revision: delete; previous revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/dir1/file14,v <-- first-dir/dir1/file14
+initial revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/dir1/file6,v <-- first-dir/dir1/file6
+new revision: 1\.2; previous revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/dir1/file7,v <-- first-dir/dir1/file7
+new revision: delete; previous revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file14,v <-- first-dir/dir1/dir2/file14
+initial revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v <-- first-dir/dir1/dir2/file6
+new revision: 1\.2; previous revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v <-- first-dir/dir1/dir2/file7
+new revision: delete; previous revision: 1\.1"
+ dotest basic2-17 "${testcvs} -q update first-dir" ''
+
+ dotest basic2-18 "${testcvs} tag third-dive first-dir" \
+"${SPROG} tag: Tagging first-dir
+T first-dir/file14
+T first-dir/file6
+${SPROG} tag: Tagging first-dir/dir1
+T first-dir/dir1/file14
+T first-dir/dir1/file6
+${SPROG} tag: Tagging first-dir/dir1/dir2
+T first-dir/dir1/dir2/file14
+T first-dir/dir1/dir2/file6"
+
+ dotest basic2-19 "echo yes | ${testcvs} release -d first-dir" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .first-dir.: "
+
+ # end of third dive
+ dotest_fail basic2-20 "test -d first-dir" ""
+
+ # now try some rtags
+
+ # rtag HEADS
+ dotest basic2-21 "${testcvs} rtag rtagged-by-head first-dir" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: Tagging first-dir/dir1
+${SPROG} rtag: Tagging first-dir/dir1/dir2"
+
+ dotest basic2-21b "${testcvs} co -p -r rtagged-by-head first-dir/file6" \
+"===================================================================
+Checking out first-dir/file6
+RCS: $CVSROOT_DIRNAME/first-dir/file6,v
+VERS: 1\.2
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+file6
+file6"
+ # see what happens when val-tags is removed
+ modify_repo mv $CVSROOT_DIRNAME/CVSROOT/val-tags \
+ $CVSROOT_DIRNAME/CVSROOT/val-tags.save
+ # The output for this used to be something like:
+ # "${SPROG} checkout: cannot open CVS/Entries for reading: No such file or directory
+ # ${SPROG} \[checkout aborted\]: no such tag \`rtagged-by-head'"
+
+ dotest basic2-21c \
+"${testcvs} co -p -r rtagged-by-head first-dir/file6" \
+"===================================================================
+Checking out first-dir/file6
+RCS: $CVSROOT_DIRNAME/first-dir/file6,v
+VERS: 1\.2
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+file6
+file6"
+ modify_repo mv $CVSROOT_DIRNAME/CVSROOT/val-tags.save \
+ $CVSROOT_DIRNAME/CVSROOT/val-tags
+
+ # tag by tag
+ dotest basic2-22 "${testcvs} rtag -r rtagged-by-head rtagged-by-tag first-dir" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: Tagging first-dir/dir1
+${SPROG} rtag: Tagging first-dir/dir1/dir2"
+
+ # tag by revision
+ dotest basic2-23 "${testcvs} rtag -r1.1 rtagged-by-revision first-dir" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: Tagging first-dir/dir1
+${SPROG} rtag: Tagging first-dir/dir1/dir2"
+
+ # rdiff by revision
+ dotest basic2-24 "${testcvs} rdiff -r1.1 -rrtagged-by-head first-dir" \
+"${SPROG} rdiff: Diffing first-dir
+Index: first-dir/file6
+diff -c first-dir/file6:1\.1 first-dir/file6:1\.2
+\*\*\* first-dir/file6:1\.1 ${DATE}
+--- first-dir/file6 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+--- 1,2 ----
+ file6
+${PLUS} file6
+Index: first-dir/file7
+diff -c first-dir/file7:1\.1 first-dir/file7:removed
+\*\*\* first-dir/file7:1.1 ${DATE}
+--- first-dir/file7 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- file7
+--- 0 ----
+${SPROG} rdiff: Diffing first-dir/dir1
+Index: first-dir/dir1/file6
+diff -c first-dir/dir1/file6:1\.1 first-dir/dir1/file6:1\.2
+\*\*\* first-dir/dir1/file6:1\.1 ${DATE}
+--- first-dir/dir1/file6 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+--- 1,2 ----
+ file6
+${PLUS} file6
+Index: first-dir/dir1/file7
+diff -c first-dir/dir1/file7:1\.1 first-dir/dir1/file7:removed
+\*\*\* first-dir/dir1/file7:1\.1 ${DATE}
+--- first-dir/dir1/file7 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- file7
+--- 0 ----
+${SPROG} rdiff: Diffing first-dir/dir1/dir2
+Index: first-dir/dir1/dir2/file6
+diff -c first-dir/dir1/dir2/file6:1\.1 first-dir/dir1/dir2/file6:1\.2
+\*\*\* first-dir/dir1/dir2/file6:1\.1 ${DATE}
+--- first-dir/dir1/dir2/file6 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+--- 1,2 ----
+ file6
+${PLUS} file6
+Index: first-dir/dir1/dir2/file7
+diff -c first-dir/dir1/dir2/file7:1\.1 first-dir/dir1/dir2/file7:removed
+\*\*\* first-dir/dir1/dir2/file7:1\.1 ${DATE}
+--- first-dir/dir1/dir2/file7 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- file7
+--- 0 ----"
+ dotest basic2-24a "${testcvs} rdiff -l -r1.1 -rrtagged-by-head first-dir" \
+"${SPROG} rdiff: Diffing first-dir
+Index: first-dir/file6
+diff -c first-dir/file6:1\.1 first-dir/file6:1\.2
+\*\*\* first-dir/file6:1\.1 ${DATE}
+--- first-dir/file6 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+--- 1,2 ----
+ file6
+${PLUS} file6
+Index: first-dir/file7
+diff -c first-dir/file7:1\.1 first-dir/file7:removed
+\*\*\* first-dir/file7:1.1 ${DATE}
+--- first-dir/file7 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- file7
+--- 0 ----"
+ # now export by rtagged-by-head and rtagged-by-tag and compare.
+ dotest basic2-25 "${testcvs} export -r rtagged-by-head -d 1dir first-dir" \
+"${SPROG} export: Updating 1dir
+U 1dir/file14
+U 1dir/file6
+${SPROG} export: Updating 1dir/dir1
+U 1dir/dir1/file14
+U 1dir/dir1/file6
+${SPROG} export: Updating 1dir/dir1/dir2
+U 1dir/dir1/dir2/file14
+U 1dir/dir1/dir2/file6"
+ dotest_fail basic2-25a "test -d 1dir/CVS"
+ dotest_fail basic2-25b "test -d 1dir/dir1/CVS"
+ dotest_fail basic2-25c "test -d 1dir/dir1/dir2/CVS"
+
+ dotest basic2-26 "${testcvs} export -r rtagged-by-tag first-dir" \
+"${SPROG} export: Updating first-dir
+U first-dir/file14
+U first-dir/file6
+${SPROG} export: Updating first-dir/dir1
+U first-dir/dir1/file14
+U first-dir/dir1/file6
+${SPROG} export: Updating first-dir/dir1/dir2
+U first-dir/dir1/dir2/file14
+U first-dir/dir1/dir2/file6"
+ dotest_fail basic2-26a "test -d first-dir/CVS"
+ dotest_fail basic2-26b "test -d first-dir/dir1/CVS"
+ dotest_fail basic2-26c "test -d first-dir/dir1/dir2/CVS"
+
+ dotest basic2-27 "directory_cmp 1dir first-dir"
+ rm -r 1dir first-dir
+
+ # checkout by revision vs export by rtagged-by-revision and compare.
+ mkdir export-dir
+ dotest basic2-28 "${testcvs} export -rrtagged-by-revision -d export-dir first-dir" \
+"${SPROG} export: Updating export-dir
+U export-dir/file14
+U export-dir/file6
+U export-dir/file7
+${SPROG} export: Updating export-dir/dir1
+U export-dir/dir1/file14
+U export-dir/dir1/file6
+U export-dir/dir1/file7
+${SPROG} export: Updating export-dir/dir1/dir2
+U export-dir/dir1/dir2/file14
+U export-dir/dir1/dir2/file6
+U export-dir/dir1/dir2/file7"
+ dotest_fail basic2-28a "test -d export-dir/CVS"
+ dotest_fail basic2-28b "test -d export-dir/dir1/CVS"
+ dotest_fail basic2-28c "test -d export-dir/dir1/dir2/CVS"
+
+ dotest basic2-29 "${testcvs} co -r1.1 first-dir" \
+"${SPROG} checkout: Updating first-dir
+U first-dir/file14
+U first-dir/file6
+U first-dir/file7
+${SPROG} checkout: Updating first-dir/dir1
+U first-dir/dir1/file14
+U first-dir/dir1/file6
+U first-dir/dir1/file7
+${SPROG} checkout: Updating first-dir/dir1/dir2
+U first-dir/dir1/dir2/file14
+U first-dir/dir1/dir2/file6
+U first-dir/dir1/dir2/file7"
+
+ # directory copies are done in an oblique way in order to avoid a bug in sun's tmp filesystem.
+ mkdir first-dir.cpy ; (cd first-dir ; tar cf - . | (cd ../first-dir.cpy ; tar xf -))
+
+ dotest basic2-30 "directory_cmp first-dir export-dir"
+
+ # interrupt, while we've got a clean 1.1 here, let's import it
+ # into a couple of other modules.
+ cd export-dir
+ dotest_sort basic2-31 \
+"$testcvs import -m first-import second-dir first-immigration immigration1 immigration1_0" \
+"
+
+N second-dir/dir1/dir2/file14
+N second-dir/dir1/dir2/file6
+N second-dir/dir1/dir2/file7
+N second-dir/dir1/file14
+N second-dir/dir1/file6
+N second-dir/dir1/file7
+N second-dir/file14
+N second-dir/file6
+N second-dir/file7
+No conflicts created by this import
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/dir1
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/dir1/dir2"
+ cd ..
+
+ dotest basic2-32 "${testcvs} export -r HEAD second-dir" \
+"${SPROG} export: Updating second-dir
+U second-dir/file14
+U second-dir/file6
+U second-dir/file7
+${SPROG} export: Updating second-dir/dir1
+U second-dir/dir1/file14
+U second-dir/dir1/file6
+U second-dir/dir1/file7
+${SPROG} export: Updating second-dir/dir1/dir2
+U second-dir/dir1/dir2/file14
+U second-dir/dir1/dir2/file6
+U second-dir/dir1/dir2/file7"
+
+ dotest basic2-33 "directory_cmp first-dir second-dir"
+
+ rm -r second-dir
+
+ rm -r export-dir first-dir
+ mkdir first-dir
+ (cd first-dir.cpy ; tar cf - . | (cd ../first-dir ; tar xf -))
+
+ # update the top, cancelling sticky tags, retag, update other copy, compare.
+ cd first-dir
+ dotest basic2-34 "${testcvs} update -A -l *file*" \
+"[UP] file6
+${SPROG} update: \`file7' is no longer in the repository"
+
+ # If we don't delete the tag first, cvs won't retag it.
+ # This would appear to be a feature.
+ dotest basic2-35 "${testcvs} tag -l -d rtagged-by-revision" \
+"${SPROG} tag: Untagging \.
+D file14
+D file6"
+ dotest basic2-36 "${testcvs} tag -l rtagged-by-revision" \
+"${SPROG} tag: Tagging \.
+T file14
+T file6"
+
+ cd ..
+ mv first-dir 1dir
+ mv first-dir.cpy first-dir
+ cd first-dir
+
+ dotest basic2-37 "${testcvs} -q diff -u" ''
+
+ dotest basic2-38 "${testcvs} update" \
+"${SPROG} update: Updating .
+${SPROG} update: Updating dir1
+${SPROG} update: Updating dir1/dir2"
+
+ cd ..
+
+ #### FIXME: is this expected to work??? Need to investigate
+ #### and fix or remove the test.
+# dotest basic2-39 "directory_cmp 1dir first-dir"
+
+ rm -r 1dir first-dir
+
+ # Test the cvs history command.
+ #
+ # Just skip these in write proxy mode for now. We should only
+ # see write commands and maybe the last few reads in the
+ # secondary history file the way we currently sync, but I'm not
+ # going to try and test this yet.
+ if $proxy; then :; else
+
+ # The reason that there are two patterns rather than using
+ # \(${TESTDIR}\|<remote>\) is that we are trying to
+ # make this portable. Perhaps at some point we should
+ # ditch that notion and require GNU expr (or dejagnu or....)
+ # since it seems to be so painful.
+
+ dotest basic2-64 "${testcvs} his -x TOFWUPCGMAR -a" \
+"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= ${TESTDIR}/\*
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == ${TESTDIR}
+M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TESTDIR}
+R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == ${TESTDIR}
+M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == ${TESTDIR}
+R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1 == ${TESTDIR}
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == ${TESTDIR}
+M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == ${TESTDIR}
+R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1/dir2 == ${TESTDIR}
+F [0-9-]* [0-9:]* ${PLUS}0000 ${username} =first-dir= ${TESTDIR}/\*
+T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\]
+T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\]
+T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\]
+O [0-9-]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-dir= ${TESTDIR}/\*
+U [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TESTDIR}/first-dir
+W [0-9-]* [0-9:]* ${PLUS}0000 ${username} file7 first-dir == ${TESTDIR}/first-dir" \
+"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= <remote>/\*
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == <remote>
+M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == <remote>
+R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == <remote>
+M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == <remote>
+R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1 == <remote>
+A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == <remote>
+M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == <remote>
+R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1/dir2 == <remote>
+F [0-9-]* [0-9:]* ${PLUS}0000 ${username} =first-dir= <remote>/\*
+T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\]
+T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\]
+T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\]
+O [0-9-]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-dir= <remote>/\*
+P [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == <remote>
+W [0-9-]* [0-9:]* ${PLUS}0000 ${username} file7 first-dir == <remote>"
+ fi
+
+ dokeep
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ ls)
+ # Test the ls & rls commands. There are some tests of
+ # Interaction of ls, rls, and branches in branches2.
+ mkdir ls; cd ls
+ dotest ls-init-1 "$testcvs -Q co -dtop ."
+ cd top
+ dotest ls-1 "$testcvs ls CVSROOT" \
+"checkoutlist
+commitinfo
+config
+cvswrappers
+loginfo
+modules
+notify
+postadmin
+postproxy
+posttag
+postwatch
+preproxy
+rcsinfo
+taginfo
+verifymsg"
+ dotest ls-2 "$testcvs ls -R" \
+"\.:
+CVSROOT
+
+CVSROOT:
+checkoutlist
+commitinfo
+config
+cvswrappers
+loginfo
+modules
+notify
+postadmin
+postproxy
+posttag
+postwatch
+preproxy
+rcsinfo
+taginfo
+verifymsg"
+ # This used to cause a fatal error.
+ modify_repo mkdir $CVSROOT_DIRNAME/notcheckedout
+ dotest ls-3 "$testcvs ls -RP" \
+"\.:
+CVSROOT
+notcheckedout
+
+CVSROOT:
+checkoutlist
+commitinfo
+config
+cvswrappers
+loginfo
+modules
+notify
+postadmin
+postproxy
+posttag
+postwatch
+preproxy
+rcsinfo
+taginfo
+verifymsg"
+
+ # Make sure the previous command did not create the notcheckedout
+ # directory.
+ dotest_fail ls-4 "test -d notcheckedout"
+
+ dotest ls-5 "$testcvs ls -R" \
+"\.:
+CVSROOT
+notcheckedout
+
+CVSROOT:
+checkoutlist
+commitinfo
+config
+cvswrappers
+loginfo
+modules
+notify
+postadmin
+postproxy
+posttag
+postwatch
+preproxy
+rcsinfo
+taginfo
+verifymsg
+
+notcheckedout:"
+ dotest_fail ls-6 "test -d notcheckedout"
+
+ # Several test for ls -d, which shows dead revisions
+
+ # Set up the dead files
+ mkdir cemetery
+ dotest ls-d-init-1 "$testcvs -Q add cemetery"
+ cd cemetery
+ touch dead living
+ dotest ls-d-init-2 "$testcvs -Q add dead living"
+ dotest ls-d-init-3 "$testcvs -Q ci -mm dead living"
+ dotest ls-d-init-4 "$testcvs -Q tag -b branch"
+ dotest ls-d-init-5 "$testcvs -Q up -A"
+ rm dead
+ dotest ls-d-init-6 "$testcvs -Q rm dead"
+ dotest ls-d-init-7 "$testcvs -Q ci -mm dead"
+ dotest ls-d-init-8 "$testcvs -Q up -r branch"
+ rm dead
+ dotest ls-d-init-9 "$testcvs -Q rm dead"
+ dotest ls-d-init-10 "$testcvs -Q ci -mm dead"
+
+ # Possible output
+ output_living="living"
+ output_dead="dead
+living"
+
+ # The basic test is to make sure that dead revisions are shown if and
+ # only if -d is speficified (and that live revisions are always
+ # shown). The following test cases cover all combinations of these
+ # factors:
+ #
+ # + Working directory is on branch or trunk
+ # + ls or rls
+ # + implicit branch, explicit trunk, or explicit branch
+ # + -d present or absent
+
+ # Working directory on trunk
+ $testcvs -Q up -A
+
+ ## ls
+ dotest ls-d-1 "$testcvs ls" "$output_living"
+ dotest ls-d-2 "$testcvs ls -d" "$output_dead"
+
+ dotest ls-d-3 "$testcvs ls -rHEAD" "$output_living"
+ dotest ls-d-4 "$testcvs ls -drHEAD" "$output_dead"
+
+ dotest ls-d-5 "$testcvs ls -rbranch" "$output_living"
+ dotest ls-d-6 "$testcvs ls -drbranch" "$output_dead"
+
+ ## rls
+ dotest ls-d-7 "$testcvs rls cemetery" \
+"$SPROG rls: Listing module: \`cemetery'
+$output_living"
+ dotest ls-d-8 "$testcvs rls -d cemetery" \
+"$SPROG rls: Listing module: \`cemetery'
+$output_dead"
+
+ dotest ls-d-9 "$testcvs -q rls -rHEAD cemetery" "$output_living"
+ dotest ls-d-10 "$testcvs -q rls -drHEAD cemetery" "$output_dead"
+
+ dotest ls-d-11 "$testcvs -q rls -rbranch cemetery" "$output_living"
+ dotest ls-d-12 "$testcvs -q rls -drbranch cemetery" "$output_dead"
+
+ # Working directory on branch
+ $testcvs -Q up -r branch
+
+ ## ls
+ dotest ls-d-13 "$testcvs ls" "$output_living"
+ dotest ls-d-14 "$testcvs ls -d" "$output_dead"
+
+ dotest ls-d-15 "$testcvs ls -r HEAD" "$output_living"
+ dotest ls-d-16 "$testcvs ls -d -r HEAD" "$output_dead"
+
+ dotest ls-d-17 "$testcvs ls -r branch" "$output_living"
+ dotest ls-d-18 "$testcvs ls -d -r branch" "$output_dead"
+
+ ## rls
+ dotest ls-d-19 "$testcvs -q rls cemetery" "$output_living"
+ dotest ls-d-20 "$testcvs -q rls -d cemetery" "$output_dead"
+
+ dotest ls-d-21 "$testcvs -q rls -rHEAD cemetery" "$output_living"
+ dotest ls-d-22 "$testcvs -q rls -drHEAD cemetery" "$output_dead"
+
+ dotest ls-d-23 "$testcvs -q rls -rbranch cemetery" "$output_living"
+ dotest ls-d-24 "$testcvs -q rls -drbranch cemetery" "$output_dead"
+
+ # Some tests to cover specifying a file name as an option
+ # Combinations of factors:
+ #
+ # + file in CVS/Entries or not
+ # + current directory or subdirectory
+ # + file dead or not
+
+ # Switch back to the trunk
+ $testcvs -Q up -A
+
+ ## file in CVS/Entries
+ dotest ls-filename-1 "$testcvs ls dead"
+
+ # ls'ing a file that already exists once caused an assertion failure.
+ dotest ls-filename-2 "$testcvs ls living" "living"
+
+ cd ..
+ dotest ls-filename-3 "$testcvs ls cemetery/dead"
+
+ # ls'ing a file that already exists once caused an assertion failure.
+ dotest ls-filename-4 "$testcvs ls cemetery/living" "cemetery/living"
+ cd cemetery
+
+ ## file not in CVS/Entries
+ echo D > CVS/Entries
+
+ dotest ls-filename-5 "$testcvs ls dead"
+
+ # ls'ing a file that already exists once caused an assertion failure.
+ dotest ls-filename-6 "$testcvs ls living" "living"
+
+ cd ..
+ dotest ls-filename-7 "$testcvs ls cemetery/dead"
+
+ # ls'ing a file that already exists once caused an assertion failure.
+ dotest ls-filename-8 "$testcvs ls cemetery/living" "cemetery/living"
+
+ cd cemetery
+
+ # Test the -D date option to cvs ls
+
+ # try and list a file before it's created, during an old revision, in
+ # a period when it was dead and in the future
+ time_prebirth=`date '+%Y-%m-%d %H:%M:%S'` ; sleep 1
+ touch dated
+ dotest ls-D-init-1 "$testcvs -Q add dated"
+ dotest ls-D-init-2 "$testcvs -Q ci -mm dated"
+ time_newborn=`date '+%Y-%m-%d %H:%M:%S'` ; sleep 1
+ echo mm >> dated
+ dotest ls-D-init-2 "$testcvs -Q ci -mm dated"
+ time_predeath=`date '+%Y-%m-%d %H:%M:%S'` ; sleep 1
+ rm dated
+ dotest ls-D-init-3 "$testcvs -Q rm dated"
+ dotest ls-D-init-4 "$testcvs -Q ci -mm dated"
+ time_postdeath=`date '+%Y-%m-%d %H:%M:%S'`
+
+ dotest ls-D-1 "$testcvs ls -D '$time_prebirth' -e dated"
+
+ # ls'ing a file that already exists once caused an assertion failure.
+ dotest ls-D-2 "$testcvs ls -D '$time_newborn' -e dated" \
+"/dated/1\.1/.*"
+
+ # ls'ing a file that already exists once caused an assertion failure.
+ dotest ls-D-3 "$testcvs ls -D '$time_predeath' -e dated" \
+"/dated/1.2/.*"
+
+ dotest ls-D-4 "$testcvs ls -D '$time_postdeath' -e dated"
+
+ dokeep
+ cd ../../..
+ rm -r ls
+ modify_repo rm -rf $CVSROOT_DIRNAME/notcheckedout \
+ $CVSROOT_DIRNAME/cemetery
+ unset output_living output_dead
+ ;;
+
+
+
+ parseroot)
+ mkdir 1; cd 1
+ # Test odd cases involving CVSROOT. At the moment, that means we
+ # are testing roots with '/'s on the end, which CVS should parse off.
+ CVSROOT_save=${CVSROOT}
+ CVSROOT="${CVSROOT}/////"
+ dotest parseroot-1 "${testcvs} -q co CVSROOT/modules" \
+"U CVSROOT/modules"
+ dotest parseroot-2 "${testcvs} -q ci -fmnull-change CVSROOT/modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- CVSROOT/modules
+new revision: 1\.2; previous revision: 1\.1
+$SPROG commit: Rebuilding administrative file database"
+
+ if $remote; then
+ # I only test these when testing remote in case CVS was compiled
+ # without client support.
+
+ # logout does not try to contact the server.
+ CVSROOT=":pserver;proxy=localhost;proxyport=8080:localhost/dev/null"
+ dotest parseroot-3r "$testcvs -d'$CVSROOT' logout" \
+"Logging out of :pserver:$username@localhost:2401/dev/null
+$CPROG logout: warning: failed to open $HOME/\.cvspass for reading: No such file or directory
+$CPROG logout: Entry not found."
+ CVSROOT=":pserver;proxyport=8080:localhost/dev/null"
+ dotest_fail parseroot-4r "$testcvs -d'$CVSROOT' logout" \
+"$CPROG logout: Proxy port specified in CVSROOT without proxy host\.
+$CPROG \[logout aborted\]: Bad CVSROOT: \`:pserver;proxyport=8080:localhost/dev/null'\."
+ CVSROOT=":pserver;optionnoarg:localhost/dev/null"
+ dotest_fail parseroot-5r "$testcvs -d'$CVSROOT' logout" \
+"$CPROG logout: Option (\`optionnoarg') has no argument in CVSROOT\.
+$CPROG \[logout aborted\]: Bad CVSROOT: \`:pserver;optionnoarg:localhost/dev/null'\."
+ CVSROOT=":pserver;notanoption=anything:localhost/dev/null"
+ dotest_fail parseroot-6r "$testcvs -d'$CVSROOT' logout" \
+"$CPROG logout: Unknown option (\`notanoption') in CVSROOT\.
+$CPROG \[logout aborted\]: Bad CVSROOT: \`:pserver;notanoption=anything:localhost/dev/null'\."
+ CVSROOT=":local;proxy=localhost:/dev/null"
+ dotest_fail parseroot-7r "$testcvs -d'$CVSROOT' logout" \
+"$CPROG logout: CVSROOT proxy specification is only valid for gserver and
+$CPROG logout: pserver connection methods\.
+$CPROG \[logout aborted\]: Bad CVSROOT: \`:local;proxy=localhost:/dev/null'\."
+ CVSROOT="::pserver@anonymous@test.org:/cvs"
+ dotest_fail parseroot-8r "$testcvs -d'$CVSROOT' co test" \
+"$CPROG checkout: Unknown method (\`') in CVSROOT\.
+$CPROG \[checkout aborted\]: Bad CVSROOT: \`$CVSROOT'\."
+ fi
+
+ dokeep
+
+ # Clean up
+ CVSROOT=$CVSROOT_save
+ cd ..
+ rm -r 1
+ ;;
+
+
+
+ files)
+ # Test of how we specify files on the command line
+ # (recurse.c and that sort of thing). Vaguely similar to
+ # tests like basic* and deep. See modules and such tests
+ # for what happens when we throw in modules and co -d, &c.
+
+ # This particular test is fairly carefully crafted, to spot
+ # one particular issue with remote.
+ mkdir 1; cd 1
+ dotest files-1 "${testcvs} -q co -l ." ""
+ mkdir first-dir
+ dotest files-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch tfile
+ dotest files-3 "${testcvs} add tfile" \
+"${SPROG} add: scheduling file .tfile. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest files-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/tfile,v <-- tfile
+initial revision: 1\.1"
+ dotest files-5 "${testcvs} -q tag -b C" "T tfile"
+ dotest files-6 "${testcvs} -q update -r C" ""
+ mkdir dir
+ dotest files-7 "${testcvs} add dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir added to the repository
+--> Using per-directory sticky tag .C'"
+ cd dir
+ touch .file
+ dotest files-7b "${testcvs} add .file" \
+"${SPROG} add: scheduling file .\.file' for addition on branch .C.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ mkdir sdir
+ dotest files-7c "${testcvs} add sdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir/sdir added to the repository
+--> Using per-directory sticky tag .C'"
+ cd sdir
+ mkdir ssdir
+ dotest files-8 "${testcvs} add ssdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir added to the repository
+--> Using per-directory sticky tag .C'"
+ cd ssdir
+ touch .file
+ dotest files-9 "${testcvs} add .file" \
+"${SPROG} add: scheduling file .\.file' for addition on branch .C.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cd ../..
+ dotest files-10 "${testcvs} -q ci -m test" \
+"$CVSROOT_DIRNAME/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- sdir/ssdir/\.file
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ dotest files-11 \
+"${testcvs} commit -m test -f ./.file ./sdir/ssdir/.file" \
+"${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
+${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \./sdir/ssdir/\.file
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+ if $remote; then
+ # FIXCVS:
+ # This is a bug, looks like that toplevel_repos cruft in
+ # client.c is coming back to haunt us.
+ # May want to think about the whole issue, toplevel_repos
+ # has always been crufty and trying to patch it up again
+ # might be a mistake.
+ dotest files-12r \
+"$testcvs commit -f -m test ./sdir/ssdir/.file ./.file" \
+"$CVSROOT_DIRNAME/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \./sdir/ssdir/\.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2"
+
+ # Sync up the version numbers so that the rest of the
+ # tests don't need to expect different numbers based
+ # local or remote.
+ dotest files-12rworkaround \
+"$testcvs commit -f -m test .file" \
+"$CVSROOT_DIRNAME/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2"
+ else
+ dotest files-12 \
+"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \
+"${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \./sdir/ssdir/\.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2
+${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2"
+ fi
+ dotest files-13 \
+"${testcvs} commit -fmtest ./sdir/../sdir/ssdir/..///ssdir/.file" \
+"${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \./sdir/\.\./sdir/ssdir/\.\.///ssdir/\.file
+new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3"
+ dotest files-14 \
+"${testcvs} commit -fmtest ../../first-dir/dir/.file" \
+"${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.\./\.\./first-dir/dir/\.file
+new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3"
+
+ dokeep
+ cd ../../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ spacefiles)
+ # More filename tests, in particular spaces in file names.
+ # (it might be better to just change a few of the names in
+ # basica or some other test instead, always good to keep the
+ # testsuite concise).
+
+ mkdir 1; cd 1
+ dotest spacefiles-1 "${testcvs} -q co -l ." ""
+ touch ./-c
+ dotest spacefiles-2 "${testcvs} add -- -c" \
+"${SPROG} add: scheduling file .-c. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest spacefiles-3 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/-c,v <-- -c
+initial revision: 1\.1"
+ mkdir 'first dir'
+ dotest spacefiles-4 "${testcvs} add 'first dir'" \
+"Directory ${CVSROOT_DIRNAME}/first dir added to the repository"
+ mkdir ./-b
+ dotest spacefiles-5 "${testcvs} add -- -b" \
+"Directory ${CVSROOT_DIRNAME}/-b added to the repository"
+ cd 'first dir'
+ touch 'a file'
+ dotest spacefiles-6 "${testcvs} add 'a file'" \
+"${SPROG} add: scheduling file .a file. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest spacefiles-7 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first dir/a file,v <-- a file
+initial revision: 1\.1"
+ dotest spacefiles-8 "${testcvs} -q tag new-tag" "T a file"
+ cd ../..
+
+ mkdir 2; cd 2
+ dotest spacefiles-10 "${testcvs} co -- -b" \
+"${SPROG} checkout: Updating -b"
+ dotest spacefiles-11 "${testcvs} -q co -- -c" "U \./-c"
+ rm ./-c
+ dotest spacefiles-13 "${testcvs} -q co 'first dir'" \
+"U first dir/a file"
+ cd ..
+
+ mkdir 3; cd 3
+ dotest spacefiles-14 "${testcvs} -q co 'first dir/a file'" \
+"U first dir/a file"
+ cd ..
+
+ rm -r 1 2 3
+ modify_repo rm -rf "'$CVSROOT_DIRNAME/first dir'" \
+ $CVSROOT_DIRNAME/-b $CVSROOT_DIRNAME/-c,v
+ ;;
+
+
+
+ commit-readonly)
+ mkdir 1; cd 1
+ module=x
+
+ : > junk
+ dotest commit-readonly-1 "$testcvs -Q import -m . $module X Y" ''
+ dotest commit-readonly-2 "$testcvs -Q co $module" ''
+ cd $module
+
+ file=m
+
+ # Include an rcs keyword to be expanded.
+ echo '$Id''$' > $file
+
+ dotest commit-readonly-3 "$testcvs add $file" \
+"$SPROG add: scheduling file .$file. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest commit-readonly-4 "$testcvs -Q ci -m . $file"
+
+ echo line2 >> $file
+ # Make the file read-only.
+ chmod a-w $file
+
+ dotest commit-readonly-5 "$testcvs -Q ci -m . $file"
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/"$module"
+ ;;
+
+
+
+ status)
+ # This tests for a bug in the status command which failed to
+ # notice resolved conflicts.
+ mkdir status; cd status
+ dotest status-init-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest status-init-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo a line >tfile
+ dotest status-init-3 "${testcvs} add tfile" \
+"${SPROG} add: scheduling file .tfile. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest status-init-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/tfile,v <-- tfile
+initial revision: 1\.1"
+ cd ..
+ dotest status-init-5 "${testcvs} -q co -dsecond-dir first-dir" \
+"U second-dir/tfile"
+ cd second-dir
+ echo some junk >>tfile
+ dotest status-init-6 "${testcvs} -q ci -maline" \
+"$CVSROOT_DIRNAME/first-dir/tfile,v <-- tfile
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../first-dir
+ echo force a conflict >>tfile
+ dotest status-init-7 "${testcvs} -q up" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/tfile,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into tfile
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in tfile
+C tfile"
+
+ # Now note our status
+ dotest status-1 "${testcvs} status tfile" \
+"===================================================================
+File: tfile Status: Unresolved Conflict
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # touch the file, leaving conflict markers in place
+ # and note our status
+ touch tfile
+ dotest status-2 "${testcvs} status tfile" \
+"===================================================================
+File: tfile Status: File had conflicts on merge
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # resolve the conflict
+ echo resolution >tfile
+ dotest status-3 "${testcvs} status tfile" \
+"===================================================================
+File: tfile Status: Locally Modified
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # Check that there are no problems just using CVS/Root too.
+ save_CVSROOT=$CVSROOT
+ unset CVSROOT
+ dotest status-3a "${testcvs} status tfile" \
+"===================================================================
+File: tfile Status: Locally Modified
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ CVSROOT=$save_CVSROOT
+ export CVSROOT
+
+ # FIXCVS:
+ # Update is supposed to re-Register() the file when it
+ # finds resolved conflicts:
+ dotest status-4 "grep 'Result of merge' CVS/Entries" \
+"/tfile/1\.2/Result of merge${PLUS}[a-zA-Z0-9 :]*//"
+
+ cd ..
+ mkdir fourth-dir
+ dotest status-init-8 "$testcvs add fourth-dir" \
+"Directory $CVSROOT_DIRNAME/fourth-dir added to the repository"
+ cd fourth-dir
+ echo yet another line >t3file
+ dotest status-init-9 "$testcvs add t3file" \
+"$SPROG add: scheduling file .t3file. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest status-init-10 "$testcvs -q ci -m add" \
+"$CVSROOT_DIRNAME/fourth-dir/t3file,v <-- t3file
+initial revision: 1\.1"
+ cd ../first-dir
+ mkdir third-dir
+ dotest status-init-11 "$testcvs add third-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir/third-dir added to the repository"
+ cd third-dir
+ echo another line >t2file
+ dotest status-init-12 "$testcvs add t2file" \
+"$SPROG add: scheduling file .t2file. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest status-init-13 "$testcvs -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/third-dir/t2file,v <-- t2file
+initial revision: 1\.1"
+ dotest status-5 "$testcvs status ../tfile" \
+"===================================================================
+File: tfile Status: Locally Modified
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/tfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest status-6 "$testcvs status ../../fourth-dir/t3file" \
+"===================================================================
+File: t3file Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/fourth-dir/t3file,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ dokeep
+ cd ../../..
+ rm -rf status
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/fourth-dir
+ ;;
+
+
+
+ commit-readonlyfs)
+ mkdir 1; cd 1
+ module=x
+ : > junk
+ dotest commit-readonlyfs-1 "${testcvs} -Q import -m . $module X Y" ''
+ if $remote; then
+ dotest_fail commit-readonlyfs-2r1 "${testcvs} -Q -R co $module" \
+"${CPROG} \[checkout aborted\]: Read-only repository feature unavailable with remote roots (cvsroot = ${CVSROOT_DIRNAME})"
+ dotest commit-readonlyfs-2r2 "${testcvs} -Q co $module" ''
+ else
+ dotest commit-readonlyfs-2 "${testcvs} -Q -R co $module" ''
+ rm -rf $module
+ dotest commit-readonlyfs-2r3 "${testcvs} -q -R co $module" \
+"U $module/junk"
+ rm -rf $module
+ dotest commit-readonlyfs-2r4 "${testcvs} -R co $module" \
+"${SPROG}: WARNING: Read-only repository access mode selected via \`cvs -R'\.
+Using this option to access a repository which some users write to may
+cause intermittent sandbox corruption\.
+${SPROG} checkout: Updating $module
+U $module/junk"
+ fi
+ cd $module
+ echo test > junk
+ if $remote; then
+ dotest_fail commit-readonlyfs-3r "${testcvs} -Q -R ci -m. junk" \
+"${SPROG} \[commit aborted\]: Read-only repository feature unavailable with remote roots (cvsroot = ${CVSROOT_DIRNAME})"
+ else
+ dotest_fail commit-readonlyfs-3 "${testcvs} -Q -R ci -m. junk" \
+"${SPROG} commit: write lock failed\.
+WARNING: Read-only repository access mode selected via \`cvs -R'\.
+Attempting to write to a read-only filesystem is not allowed\.
+${SPROG} \[commit aborted\]: lock failed - giving up"
+ fi
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/"$module"
+ ;;
+
+
+
+ rdiff)
+ # Test rdiff
+ # XXX for now this is just the most essential test...
+ cd ${TESTDIR}
+
+ mkdir testimport
+ cd testimport
+ echo '$''Id$' > foo
+ echo '$''Name$' >> foo
+ echo '$''Id$' > bar
+ echo '$''Name$' >> bar
+ dotest_sort rdiff-1 \
+ "${testcvs} import -I ! -m test-import-with-keyword trdiff TRDIFF T1" \
+'
+
+N trdiff/bar
+N trdiff/foo
+No conflicts created by this import'
+ dotest rdiff-2 \
+ "${testcvs} co -ko trdiff" \
+"${SPROG} checkout: Updating trdiff
+U trdiff/bar
+U trdiff/foo"
+ cd trdiff
+ echo something >> foo
+ dotest rdiff-3 \
+ "${testcvs} ci -m added-something foo" \
+"${CVSROOT_DIRNAME}/trdiff/foo,v <-- foo
+new revision: 1\.2; previous revision: 1\.1"
+ echo '#ident "@(#)trdiff:$''Name$:$''Id$"' > new
+ echo "new file" >> new
+ dotest rdiff-4 \
+ "${testcvs} add -m new-file-description new" \
+"${SPROG} add: scheduling file \`new' for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest rdiff-5 \
+ "${testcvs} commit -m added-new-file new" \
+"${CVSROOT_DIRNAME}/trdiff/new,v <-- new
+initial revision: 1\.1"
+ dotest rdiff-6 \
+ "${testcvs} tag local-v0" \
+"${SPROG} tag: Tagging .
+T bar
+T foo
+T new"
+ dotest rdiff-7 \
+ "${testcvs} status -v foo" \
+"===================================================================
+File: foo Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/trdiff/foo,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -ko
+
+ Existing Tags:
+ local-v0 (revision: 1\.2)
+ T1 (revision: 1\.1\.1\.1)
+ TRDIFF (branch: 1\.1\.1)"
+
+ cd ..
+ rm -r trdiff
+
+ dotest rdiff-8 \
+ "${testcvs} rdiff -r T1 -r local-v0 trdiff" \
+"${SPROG}"' rdiff: Diffing trdiff
+Index: trdiff/foo
+diff -c trdiff/foo:1\.1\.1\.1 trdiff/foo:1\.2
+\*\*\* trdiff/foo:1\.1\.1\.1 '"${DATE}"'
+--- trdiff/foo '"${DATE}"'
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1,2 \*\*\*\*
+! \$''Id: foo,v 1\.1\.1\.1 [0-9/]* [0-9:]* '"${username}"' Exp \$
+! \$''Name: T1 \$
+--- 1,3 ----
+! \$''Id: foo,v 1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$
+! \$''Name: local-v0 \$
+! something
+Index: trdiff/new
+diff -c /dev/null trdiff/new:1\.1
+\*\*\* /dev/null '"${DATE}"'
+--- trdiff/new '"${DATE}"'
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1,2 ----
+'"${PLUS}"' #ident "@(#)trdiff:\$''Name: local-v0 \$:\$''Id: new,v 1\.1 [0-9/]* [0-9:]* '"${username}"' Exp \$"
+'"${PLUS}"' new file'
+
+ dokeep
+ cd ..
+ rm -r testimport
+ modify_repo rm -rf $CVSROOT_DIRNAME/trdiff
+ ;;
+
+
+
+ rdiff-short)
+ # Test that the short patch behaves as expected
+ # 1) Added file.
+ # 2) Removed file.
+ # 3) Different revision number with no difference.
+ # 4) Different revision number with changes.
+ # 5) Against trunk.
+ # 6) Same revision number (no difference).
+ mkdir rdiff-short; cd rdiff-short
+ mkdir abc
+ dotest rdiff-short-init-1 \
+"${testcvs} -q import -I ! -m initial-import abc vendor initial" \
+'
+No conflicts created by this import'
+
+ dotest rdiff-short-init-2 "${testcvs} -q get abc" ''
+ cd abc
+ echo "abc" >file1.txt
+ dotest rdiff-short-init-3 "${testcvs} add file1.txt" \
+"${SPROG} add: scheduling file .file1\.txt' for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ dotest rdiff-short-init-4 \
+"${testcvs} commit -madd-file1 file1.txt" \
+"${CVSROOT_DIRNAME}/abc/file1\.txt,v <-- file1\.txt
+initial revision: 1\.1"
+ echo def >>file1.txt
+ dotest rdiff-short-init-5 \
+"${testcvs} commit -mchange-file1 file1.txt" \
+"${CVSROOT_DIRNAME}/abc/file1\.txt,v <-- file1\.txt
+new revision: 1\.2; previous revision: 1\.1"
+ echo "abc" >file1.txt
+ dotest rdiff-short-init-6 \
+"${testcvs} commit -mrestore-file1-rev1 file1.txt" \
+"${CVSROOT_DIRNAME}/abc/file1\.txt,v <-- file1\.txt
+new revision: 1\.3; previous revision: 1\.2"
+ dotest rdiff-short-init-7 \
+"${testcvs} tag -r 1.1 tag1 file1.txt" \
+"T file1\.txt"
+ dotest rdiff-short-init-8 \
+"${testcvs} tag -r 1.2 tag2 file1.txt" \
+"T file1\.txt"
+ dotest rdiff-short-init-9 \
+"${testcvs} tag -r 1.3 tag3 file1.txt" \
+"T file1\.txt"
+ echo "abc" >file2.txt
+ dotest rdiff-short-init-10 \
+"${testcvs} add file2.txt" \
+"${SPROG} add: scheduling file .file2\.txt' for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ dotest rdiff-add-remove-nodiff-init-11 \
+"${testcvs} commit -madd-file2 file2.txt" \
+"${CVSROOT_DIRNAME}/abc/file2\.txt,v <-- file2\.txt
+initial revision: 1\.1"
+ dotest rdiff-short-init-12 \
+"${testcvs} tag -r 1.1 tag4 file2.txt" \
+"T file2\.txt"
+ dotest rdiff-short-init-13 \
+"${testcvs} tag -r 1.1 tag5 file2.txt" \
+"T file2\.txt"
+ cd ../..
+ rm -fr rdiff-short
+
+ # 3) Different revision number with no difference.
+ dotest rdiff-short-no-real-change \
+"${testcvs} -q rdiff -s -r tag1 -r tag3 abc"
+
+ # 4) Different revision number with changes.
+ dotest rdiff-short-real-change \
+"${testcvs} -q rdiff -s -r tag1 -r tag2 abc" \
+'File abc/file1.txt changed from revision 1\.1 to 1\.2'
+
+ # 1) Added file.
+ # 2) Removed file.
+ dotest_sort rdiff-short-remove-add \
+"${testcvs} -q rdiff -s -r tag2 -r tag4 abc" \
+'File abc/file1\.txt is removed; tag2 revision 1\.2
+File abc/file2\.txt is new; tag4 revision 1\.1'
+
+ # 6) Same revision number (no difference).
+ dotest rdiff-short-no-change \
+"${testcvs} -q rdiff -s -r tag4 -r tag5 abc"
+
+ # 5) Against trunk.
+ # Check that the messages change when we diff against the trunk
+ # rather than a tag or date.
+ dotest rdiff-short-against-trunk-1 \
+"${testcvs} -q rdiff -s -rtag4 abc" \
+"File abc/file1\.txt is new; current revision 1\.3"
+
+ dotest rdiff-short-against-trunk-2 \
+"${testcvs} -q rdiff -s -rtag2 abc" \
+"File abc/file1\.txt changed from revision 1\.2 to 1\.3
+File abc/file2\.txt is new; current revision 1\.1"
+
+ modify_repo rm -rf $CVSROOT_DIRNAME/abc
+ ;;
+
+
+
+ rdiff2)
+ # Test for the segv problem reported by James Cribb
+ # Somewhere to work
+ mkdir rdiff2; cd rdiff2
+ # Create a module "m" with files "foo" and "d/bar"
+ mkdir m; cd m
+ echo foo >foo
+ mkdir d
+ echo bar >d/bar
+ dotest_sort rdiff2-1 \
+"${testcvs} -q import -I ! -m initial-import m vendor initial" \
+'
+
+N m/d/bar
+N m/foo
+No conflicts created by this import'
+
+ cd ..
+ rm -r m
+
+ # Remove "foo"
+ dotest rdiff2-2 "${testcvs} get m" \
+"${SPROG} checkout: Updating m
+U m/foo
+${SPROG} checkout: Updating m/d
+U m/d/bar"
+ cd m
+ dotest rdiff2-3 "${testcvs} rm -f foo" \
+"${SPROG} remove: scheduling .foo. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+
+ dotest rdiff2-4 "${testcvs} commit -m Removed foo" \
+"${CVSROOT_DIRNAME}/m/foo,v <-- foo
+new revision: delete; previous revision: 1\.1\.1\.1"
+
+ # Modify "d/bar"
+ echo foo >d/bar
+ dotest rdiff2-5 "${testcvs} commit -m Changed d/bar" \
+"${CVSROOT_DIRNAME}/m/d/bar,v <-- d/bar
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Crash before showing d/bar diffs
+ dotest_fail rdiff2-6 "${testcvs} rdiff -t m" \
+"${SPROG} rdiff: Diffing m
+${SPROG} rdiff: Diffing m/d
+Index: m/d/bar
+diff -c m/d/bar:1\.1\.1\.1 m/d/bar:1\.2
+\*\*\* m/d/bar:1\.1\.1\.1 ${DATE}
+--- m/d/bar ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+! bar
+--- 1 ----
+! foo"
+
+ dokeep
+ cd ../..
+ rm -rf rdiff2
+ modify_repo rm -rf $CVSROOT_DIRNAME/m
+ ;;
+
+
+
+ diff)
+ # Various tests specific to the "cvs diff" command.
+ # Related tests:
+ # death2: -N
+ # rcslib: cvs diff and $Name.
+ # rdiff: cvs rdiff.
+ # diffmerge*: nuts and bolts (stuff within diff library)
+ mkdir 1; cd 1
+ dotest diff-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest diff-2 "$testcvs add first-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+ cd first-dir
+
+ # diff is anomalous. Most CVS commands print the "nothing
+ # known" message (or worse yet, no message in some cases) but
+ # diff says "I know nothing". Shrug.
+ dotest_fail diff-3 "${testcvs} diff xyzpdq" \
+"${SPROG} diff: I know nothing about xyzpdq"
+ touch abc
+ dotest diff-4 "${testcvs} add abc" \
+"${SPROG} add: scheduling file .abc. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest diff-5 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/abc,v <-- abc
+initial revision: 1\.1"
+ echo "extern int gethostname ();" >abc
+ dotest diff-6 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/abc,v <-- abc
+new revision: 1\.2; previous revision: 1\.1"
+ echo "#include <winsock.h>" >abc
+ # check the behavior of the --ifdef=MACRO option
+ dotest_fail diff-7 "${testcvs} -q diff --ifdef=HAVE_WINSOCK_H" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.2
+diff --ifdef HAVE_WINSOCK_H -r1\.2 abc
+#ifndef HAVE_WINSOCK_H
+extern int gethostname ();
+#else /\* HAVE_WINSOCK_H \*/
+#include <winsock\.h>
+#endif /\* HAVE_WINSOCK_H \*/"
+
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r 1
+ ;;
+
+
+
+ diffnl)
+ # Test handling of 'cvs diff' of files without newlines
+ mkdir 1; cd 1
+ dotest diffnl-000 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest diffnl-001 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nfive\nsix")}' </dev/null >abc
+ dotest diffnl-002 "${testcvs} add abc" \
+"${SPROG} add: scheduling file .abc. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest diffnl-003 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/abc,v <-- abc
+initial revision: 1\.1"
+
+ # change to line near EOF
+ ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nsix")}' </dev/null >abc
+ dotest_fail diffnl-100 "${testcvs} diff abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.1
+diff -r1\.1 abc
+5d4
+< five"
+ dotest_fail diffnl-101 "${testcvs} diff -u abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.1
+diff -u -r1\.1 abc
+--- abc ${RFCDATE} 1\.1
++++ abc ${RFCDATE}
+@@ -2,5 +2,4 @@
+ two
+ three
+ four
+-five
+ six
+\\\\ No newline at end of file"
+ dotest diffnl-102 "${testcvs} -q ci -mtest abc" \
+"$CVSROOT_DIRNAME/first-dir/abc,v <-- abc
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Change to last line
+ ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null >abc
+ dotest_fail diffnl-200 "${testcvs} diff abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.2
+diff -r1\.2 abc
+5c5
+< six
+\\\\ No newline at end of file
+---
+> seven
+\\\\ No newline at end of file"
+ dotest_fail diffnl-201 "${testcvs} diff -u abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.2
+diff -u -r1\.2 abc
+--- abc ${RFCDATE} 1\.2
++++ abc ${RFCDATE}
+@@ -2,4 +2,4 @@
+ two
+ three
+ four
+-six
+\\\\ No newline at end of file
++seven
+\\\\ No newline at end of file"
+ dotest diffnl-202 "${testcvs} ci -mtest abc" \
+"${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc
+new revision: 1\.3; previous revision: 1\.2"
+
+ # Addition of newline
+ echo "one
+two
+three
+four
+seven" > abc
+ dotest_fail diffnl-300 "${testcvs} diff abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.3
+diff -r1\.3 abc
+5c5
+< seven
+\\\\ No newline at end of file
+---
+> seven"
+ dotest_fail diffnl-301 "${testcvs} diff -u abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.3
+diff -u -r1\.3 abc
+--- abc ${RFCDATE} 1\.3
++++ abc ${RFCDATE}
+@@ -2,4 +2,4 @@
+ two
+ three
+ four
+-seven
+\\\\ No newline at end of file
++seven"
+ dotest diffnl-302 "${testcvs} ci -mtest abc" \
+"${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc
+new revision: 1\.4; previous revision: 1\.3"
+
+ # Removal of newline
+ ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null >abc
+ dotest_fail diffnl-400 "${testcvs} diff abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.4
+diff -r1\.4 abc
+5c5
+< seven
+---
+> seven
+\\\\ No newline at end of file"
+ dotest_fail diffnl-401 "${testcvs} diff -u abc" \
+"Index: abc
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
+retrieving revision 1\.4
+diff -u -r1\.4 abc
+--- abc ${RFCDATE} 1\.4
++++ abc ${RFCDATE}
+@@ -2,4 +2,4 @@
+ two
+ three
+ four
+-seven
++seven
+\\\\ No newline at end of file"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ death)
+ # next dive. test death support.
+
+ # NOTE: this section has reached the size and
+ # complexity where it is getting to be a good idea to
+ # add new death support tests to a new section rather
+ # than continuing to piggyback them onto the tests here.
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest death-init-1 "$testcvs -Q co first-dir"
+
+ cd first-dir
+
+ # Create a directory with only dead files, to make sure CVS
+ # doesn't get confused by it.
+ mkdir subdir
+ dotest 65a0 "${testcvs} add subdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"
+ cd subdir
+ echo file in subdir >sfile
+ dotest 65a1 "${testcvs} add sfile" \
+"${SPROG}"' add: scheduling file `sfile'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest 65a2 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/subdir/sfile,v <-- sfile
+initial revision: 1\.1"
+ rm sfile
+ dotest 65a3 "${testcvs} rm sfile" \
+"${SPROG}"' remove: scheduling `sfile'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
+ dotest 65a4 "${testcvs} -q ci -m remove-it" \
+"$CVSROOT_DIRNAME/first-dir/subdir/sfile,v <-- sfile
+new revision: delete; previous revision: 1\.1"
+ cd ..
+ dotest 65a5 "${testcvs} -q update -P" ''
+ dotest_fail 65a6 "test -d subdir" ''
+
+ # add a file.
+ touch file1
+ if ${CVS} add file1 2>> ${LOGFILE}; then
+ pass 66
+ else
+ fail 66
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ pass 67
+ else
+ fail 67
+ fi
+
+ # remove
+ rm file1
+ if ${CVS} rm file1 2>> ${LOGFILE}; then
+ pass 68
+ else
+ fail 68
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE} ; then
+ pass 69
+ else
+ fail 69
+ fi
+
+ dotest_fail 69a0 "test -f file1" ''
+ # get the old contents of file1 back
+ if ${testcvs} update -p -r 1.1 file1 >file1 2>>${LOGFILE}; then
+ pass 69a1
+ else
+ fail 69a1
+ fi
+ dotest 69a2 "cat file1" ''
+
+ # create second file
+ touch file2
+ if ${CVS} add file1 file2 2>> ${LOGFILE}; then
+ pass 70
+ else
+ fail 70
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ pass 71
+ else
+ fail 71
+ fi
+
+ # log
+ if ${CVS} log file1 >> ${LOGFILE}; then
+ pass 72
+ else
+ fail 72
+ fi
+
+ # file4 will be dead at the time of branching and stay dead.
+ echo file4 > file4
+ dotest death-file4-add "${testcvs} add file4" \
+"${SPROG}"' add: scheduling file `file4'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest death-file4-ciadd "${testcvs} -q ci -m add file4" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+initial revision: 1\.1"
+ rm file4
+ dotest death-file4-rm "${testcvs} remove file4" \
+"${SPROG}"' remove: scheduling `file4'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
+ dotest death-file4-cirm "${testcvs} -q ci -m remove file4" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: delete; previous revision: 1\.1"
+
+ # Tag the branchpoint.
+ dotest death-72a "${testcvs} -q tag bp_branch1" 'T file1
+T file2'
+
+ # branch1
+ if ${CVS} tag -b branch1 ; then
+ pass 73
+ else
+ fail 73
+ fi
+
+ # and move to the branch.
+ if ${CVS} update -r branch1 ; then
+ pass 74
+ else
+ fail 74
+ fi
+
+ dotest_fail death-file4-3 "test -f file4" ''
+
+ # add a file in the branch
+ echo line1 from branch1 >> file3
+ if ${CVS} add file3 2>> ${LOGFILE}; then
+ pass 75
+ else
+ fail 75
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ pass 76
+ else
+ fail 76
+ fi
+
+ dotest death-76a0 \
+"${testcvs} -q rdiff -r bp_branch1 -r branch1 first-dir" \
+"Index: first-dir/file3
+diff -c /dev/null first-dir/file3:1\.1\.2\.1
+\*\*\* /dev/null ${DATE}
+--- first-dir/file3 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1 ----
+${PLUS} line1 from branch1"
+ dotest death-76a1 \
+"${testcvs} -q rdiff -r branch1 -r bp_branch1 first-dir" \
+"Index: first-dir/file3
+diff -c first-dir/file3:1\.1\.2\.1 first-dir/file3:removed
+\*\*\* first-dir/file3:1\.1\.2\.1 ${DATE}
+--- first-dir/file3 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- line1 from branch1
+--- 0 ----"
+
+ # remove
+ rm file3
+ if ${CVS} rm file3 2>> ${LOGFILE}; then
+ pass 77
+ else
+ fail 77
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE} ; then
+ pass 78
+ else
+ fail 78
+ fi
+
+ # add again
+ echo line1 from branch1 >> file3
+ if ${CVS} add file3 2>> ${LOGFILE}; then
+ pass 79
+ else
+ fail 79
+ fi
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ pass 80
+ else
+ fail 80
+ fi
+
+ # change the first file
+ echo line2 from branch1 >> file1
+
+ # commit
+ if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then
+ pass 81
+ else
+ fail 81
+ fi
+
+ # remove the second
+ rm file2
+ if ${CVS} rm file2 2>> ${LOGFILE}; then
+ pass 82
+ else
+ fail 82
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE}; then
+ pass 83
+ else
+ fail 83
+ fi
+
+ # back to the trunk.
+ if ${CVS} update -A 2>> ${LOGFILE}; then
+ pass 84
+ else
+ fail 84
+ fi
+
+ dotest_fail death-file4-4 "test -f file4" ''
+
+ if test -f file3 ; then
+ fail 85
+ else
+ pass 85
+ fi
+
+ # join
+ dotest death-86 "$testcvs -q update -j branch1" \
+"RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
+retrieving revision 1\.3
+retrieving revision 1\.3\.2\.1
+Merging differences between 1\.3 and 1\.3\.2\.1 into file1
+${SPROG} update: scheduling \`file2' for removal
+U file3"
+
+ dotest_fail death-file4-5 "test -f file4" ''
+
+ if test -f file3 ; then
+ pass 87
+ else
+ fail 87
+ fi
+
+ # Make sure that we joined the correct change to file1
+ if echo line2 from branch1 | cmp - file1 >/dev/null; then
+ pass 87a
+ else
+ fail 87a
+ fi
+
+ # update
+ if ${CVS} update ; then
+ pass 88
+ else
+ fail 88
+ fi
+
+ # commit
+ dotest 89 "${testcvs} -q ci -m test" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+new revision: 1\.2; previous revision: 1\.1"
+ cd ..
+ mkdir 2
+ cd 2
+ dotest 89a "${testcvs} -q co first-dir" 'U first-dir/file1
+U first-dir/file3'
+ cd ..
+ rm -r 2
+ cd first-dir
+
+ # remove first file.
+ rm file1
+ if ${CVS} rm file1 2>> ${LOGFILE}; then
+ pass 90
+ else
+ fail 90
+ fi
+
+ # commit
+ if ${CVS} ci -m test >>${LOGFILE}; then
+ pass 91
+ else
+ fail 91
+ fi
+
+ if test -f file1 ; then
+ fail 92
+ else
+ pass 92
+ fi
+
+ # typo; try to get to the branch and fail
+ dotest_fail 92.1a "$testcvs update -r brnach1" \
+ "$SPROG \[update aborted\]: no such tag \`brnach1'"
+ # Make sure we are still on the trunk
+ if test -f file1 ; then
+ fail 92.1b
+ else
+ pass 92.1b
+ fi
+ if test -f file3 ; then
+ pass 92.1c
+ else
+ fail 92.1c
+ fi
+
+ # back to branch1
+ if ${CVS} update -r branch1 2>> ${LOGFILE}; then
+ pass 93
+ else
+ fail 93
+ fi
+
+ dotest_fail death-file4-6 "test -f file4" ''
+
+ if test -f file1 ; then
+ pass 94
+ else
+ fail 94
+ fi
+
+ # and join
+ dotest 95 "${testcvs} -q update -j HEAD" \
+"${SPROG}"' update: file file1 has been modified, but has been removed in revision HEAD
+'"${SPROG}"' update: file file3 exists, but has been added in revision HEAD'
+
+ dotest_fail death-file4-7 "test -f file4" ''
+
+ # file2 should not have been recreated. It was
+ # deleted on the branch, and has not been modified on
+ # the trunk. That means that there have been no
+ # changes between the greatest common ancestor (the
+ # trunk version) and HEAD.
+ dotest_fail death-file2-1 "test -f file2" ''
+
+ dokeep
+ cd ..
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ death2)
+ # More tests of death support.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest death2-1 "$testcvs -q co first-dir"
+
+ cd first-dir
+
+ # Add two files on the trunk.
+ echo "first revision" > file1
+ echo "file4 first revision" > file4
+ dotest death2-2 "${testcvs} add file1 file4" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: scheduling file `file4'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+
+ dotest death2-3 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+initial revision: 1\.1"
+
+ # Make a branch and a non-branch tag.
+ dotest death2-4 "${testcvs} -q tag -b branch" \
+'T file1
+T file4'
+ dotest death2-5 "${testcvs} -q tag tag" \
+'T file1
+T file4'
+
+ # Switch over to the branch.
+ dotest death2-6 "${testcvs} -q update -r branch" ''
+
+ # Delete the file on the branch.
+ rm file1
+ dotest death2-7 "${testcvs} rm file1" \
+"${SPROG} remove: scheduling .file1. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+
+ # Test diff of the removed file before it is committed.
+ dotest_fail death2-diff-1 "${testcvs} -q diff file1" \
+"${SPROG} diff: file1 was removed, no comparison available"
+
+ dotest_fail death2-diff-2 "${testcvs} -q diff -N -c file1" \
+"Index: file1
+===================================================================
+RCS file: file1
+diff -N file1
+\*\*\* file1 ${RFCDATE} [0-9.]*
+--- /dev/null ${RFCDATE_EPOCH}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- first revision
+--- 0 ----"
+
+ dotest death2-8 "${testcvs} -q ci -m removed" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1"
+
+ # Test diff of a dead file.
+ dotest_fail death2-diff-3 \
+"${testcvs} -q diff -r1.1 -rbranch -c file1" \
+"${SPROG} diff: Tag branch refers to a dead (removed) revision in file .file1.\.
+${SPROG} diff: No comparison available\. Pass .-N. to .${SPROG} diff.${QUESTION}"
+ # and in reverse
+ dotest_fail death2-diff-3a \
+"${testcvs} -q diff -rbranch -r1.1 -c file1" \
+"${SPROG} diff: Tag branch refers to a dead (removed) revision in file .file1.\.
+${SPROG} diff: No comparison available\. Pass .-N. to .${SPROG} diff.${QUESTION}"
+
+ dotest_fail death2-diff-4 \
+"${testcvs} -q diff -r1.1 -rbranch -N -c file1" \
+"Index: file1
+===================================================================
+RCS file: file1
+diff -N file1
+\*\*\* file1 ${RFCDATE} [0-9.]*
+--- /dev/null ${RFCDATE_EPOCH}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- first revision
+--- 0 ----"
+ # and in reverse
+ dotest_fail death2-diff-4a \
+"${testcvs} -q diff -rbranch -r1.1 -N -c file1" \
+"Index: file1
+===================================================================
+RCS file: file1
+diff -N file1
+\*\*\* /dev/null ${RFCDATE_EPOCH}
+--- file1 ${RFCDATE} [0-9.]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1 ----
++ first revision"
+
+
+ dotest_fail death2-diff-5 "${testcvs} -q diff -rtag -c ." \
+"${SPROG} diff: file1 no longer exists, no comparison available"
+
+ dotest_fail death2-diff-6 "${testcvs} -q diff -rtag -N -c ." \
+"Index: file1
+===================================================================
+RCS file: file1
+diff -N file1
+\*\*\* file1 [-a-zA-Z0-9: ]* [0-9.]*
+--- /dev/null ${RFCDATE_EPOCH}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- first revision
+--- 0 ----"
+
+ # Test rdiff of a dead file.
+ dotest death2-rdiff-1 \
+"${testcvs} -q rtag -rbranch rdiff-tag first-dir" ''
+
+ dotest death2-rdiff-2 "${testcvs} -q rdiff -rtag -rbranch first-dir" \
+"Index: first-dir/file1
+diff -c first-dir/file1:1\.1 first-dir/file1:removed
+\*\*\* first-dir/file1:1\.1 [a-zA-Z0-9: ]*
+--- first-dir/file1 [a-zA-Z0-9: ]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- first revision
+--- 0 ----"
+
+ # Readd the file to the branch.
+ echo "second revision" > file1
+ dotest death2-9 "${testcvs} add file1" \
+"${SPROG} add: Re-adding file \`file1' on branch \`branch' after dead revision 1\.1\.2\.1\.
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+
+ # Test diff of the added file before it is committed.
+ dotest_fail death2-diff-7 "${testcvs} -q diff file1" \
+"${SPROG} diff: file1 is a new entry, no comparison available"
+
+ dotest_fail death2-diff-8 "${testcvs} -q diff -N -c file1" \
+"Index: file1
+===================================================================
+RCS file: file1
+diff -N file1
+\*\*\* /dev/null ${RFCDATE_EPOCH}
+--- file1 ${RFCDATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1 ----
+${PLUS} second revision"
+
+ dotest death2-10 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+
+ # Delete file4 from the branch
+ dotest death2-10a "${testcvs} rm -f file4" \
+"${SPROG} remove: scheduling .file4. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest death2-10b "${testcvs} -q ci -m removed" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: delete; previous revision: 1\.1"
+
+ # Back to the trunk.
+ dotest death2-11 "${testcvs} -q update -A" \
+"[UP] file1
+U file4"
+
+ # Add another file on the trunk.
+ echo "first revision" > file2
+ dotest death2-12 "${testcvs} add file2" \
+"${SPROG}"' add: scheduling file `file2'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest death2-13 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+
+ # Modify file4 on the trunk.
+ echo "new file4 revision" > file4
+ dotest death2-13a "${testcvs} -q commit -m mod" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Back to the branch.
+ # The ``no longer in the repository'' message doesn't really
+ # look right to me, but that's what CVS currently prints for
+ # this case.
+ dotest death2-14 "${testcvs} -q update -r branch" \
+"[UP] file1
+${SPROG} update: \`file2' is no longer in the repository
+${SPROG} update: \`file4' is no longer in the repository"
+
+ # Add a file on the branch with the same name.
+ echo "branch revision" > file2
+ dotest death2-15 "${testcvs} add file2" \
+"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest death2-16 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+
+ # Add a new file on the branch.
+ echo "first revision" > file3
+ dotest death2-17 "${testcvs} add file3" \
+"${SPROG}"' add: scheduling file `file3'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest death2-18 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/Attic/file3,v <-- file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # Test diff of a nonexistent tag
+ dotest_fail death2-diff-9 "$testcvs -q diff -rtag -c file3" \
+"$SPROG diff: tag tag is not in file file3"
+
+ dotest_fail death2-diff-10 "${testcvs} -q diff -rtag -N -c file3" \
+"Index: file3
+===================================================================
+RCS file: file3
+diff -N file3
+\*\*\* /dev/null ${RFCDATE_EPOCH}
+--- file3 ${RFCDATE} [0-9.]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1 ----
+${PLUS} first revision"
+
+ dotest_fail death2-diff-11 "${testcvs} -q diff -rtag -c ." \
+"Index: file1
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.2
+diff -c -r1\.1 -r1\.1\.2\.2
+\*\*\* file1 ${RFCDATE} [0-9.]*
+--- file1 ${RFCDATE} [0-9.]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+! first revision
+--- 1 ----
+! second revision
+${SPROG} diff: tag tag is not in file file2
+${SPROG} diff: tag tag is not in file file3
+${SPROG} diff: file4 no longer exists, no comparison available"
+
+ dotest_fail death2-diff-12 "${testcvs} -q diff -rtag -c -N ." \
+"Index: file1
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.2
+diff -c -r1\.1 -r1\.1\.2\.2
+\*\*\* file1 ${RFCDATE} [0-9.]*
+--- file1 ${RFCDATE} [0-9.]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+! first revision
+--- 1 ----
+! second revision
+Index: file2
+===================================================================
+RCS file: file2
+diff -N file2
+\*\*\* /dev/null ${RFCDATE_EPOCH}
+--- file2 ${RFCDATE} [0-9.]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1 ----
+${PLUS} branch revision
+Index: file3
+===================================================================
+RCS file: file3
+diff -N file3
+\*\*\* /dev/null ${RFCDATE_EPOCH}
+--- file3 ${RFCDATE} [0-9.]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1 ----
+${PLUS} first revision
+Index: file4
+===================================================================
+RCS file: file4
+diff -N file4
+\*\*\* file4 ${RFCDATE} [0-9.]*
+--- /dev/null ${RFCDATE_EPOCH}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+- file4 first revision
+--- 0 ----"
+
+ # Switch to the nonbranch tag.
+ dotest death2-19 "${testcvs} -q update -r tag" \
+"[UP] file1
+${SPROG} update: \`file2' is no longer in the repository
+${SPROG} update: \`file3' is no longer in the repository
+U file4"
+
+ dotest_fail death2-20 "test -f file2"
+
+ # Make sure diff only reports appropriate files.
+ dotest_fail death2-diff-13 "${testcvs} -q diff -r rdiff-tag" \
+"${SPROG} diff: Tag rdiff-tag refers to a dead (removed) revision in file .file1.\.
+${SPROG} diff: No comparison available\. Pass .-N. to .${SPROG} diff.${QUESTION}"
+
+ dotest_fail death2-diff-14 "${testcvs} -q diff -r rdiff-tag -c -N" \
+"Index: file1
+===================================================================
+RCS file: file1
+diff -N file1
+\*\*\* /dev/null ${RFCDATE_EPOCH}
+--- file1 ${RFCDATE} [0-9.]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 0 \*\*\*\*
+--- 1 ----
+${PLUS} first revision"
+
+ # now back to the trunk
+ dotest death2-21 "${testcvs} -q update -A" \
+"U file2
+[UP] file4"
+
+ # test merging with a dead file
+ dotest death2-22 "${testcvs} -q co first-dir" \
+"U first-dir/file1
+U first-dir/file2
+U first-dir/file4"
+
+ cd first-dir
+ dotest death2-23 "${testcvs} rm -f file4" \
+"${SPROG} remove: scheduling .file4. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest death2-24 "${testcvs} -q ci -m removed file4" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: delete; previous revision: 1\.2"
+ cd ..
+ echo "new stuff" >file4
+ dotest_fail death2-25 "${testcvs} up file4" \
+"${SPROG} update: conflict: \`file4' is modified but no longer in the repository
+C file4"
+
+ dokeep
+ cd ..
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ rm-update-message)
+ # FIXME
+ # local CVS prints a warning message when update notices a missing
+ # file and client/server CVS doesn't. These should be identical.
+ mkdir rm-update-message; cd rm-update-message
+ modify_repo mkdir $CVSROOT_DIRNAME/rm-update-message
+ dotest rm-update-message-setup-1 "$testcvs -q co rm-update-message" ''
+ cd rm-update-message
+ file=x
+ echo >$file
+ dotest rm-update-message-setup-2 "$testcvs -q add $file" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest rm-update-message-setup-3 "$testcvs -q ci -mcreate $file" \
+"$CVSROOT_DIRNAME/rm-update-message/$file,v <-- $file
+initial revision: 1\.1"
+
+ rm $file
+ dotest rm-update-message-1 "$testcvs up $file" \
+"${SPROG} update: warning: \`$file' was lost
+U $file"
+
+ dokeep
+ cd ../..
+ rm -r rm-update-message
+ modify_repo rm -rf $CVSROOT_DIRNAME/rm-update-message
+ ;;
+
+
+
+ rmadd)
+ # More tests of adding and removing files.
+ # In particular ci -r.
+ # Other ci -r tests:
+ # * editor-9: checking in a modified file,
+ # where "ci -r" means a branch.
+ # * basica-8a1: checking in a modified file with numeric revision.
+ # * basica-8a2: likewise.
+ # * keywordlog-4: adding a new file with numeric revision.
+ mkdir 1; cd 1
+ dotest rmadd-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest rmadd-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo first file1 >file1
+ dotest rmadd-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ dotest_fail rmadd-4 "${testcvs} -q ci -r 1.2.2.4 -m add" \
+"${SPROG} commit: cannot add file .file1' with revision .1\.2\.2\.4'; must be on trunk
+${SPROG} \[commit aborted\]: correct above errors first!"
+ dotest_fail rmadd-5 "${testcvs} -q ci -r 1.2.2 -m add" \
+"${SPROG} commit: cannot add file .file1' with revision .1\.2\.2'; must be on trunk
+${SPROG} \[commit aborted\]: correct above errors first!"
+ dotest_fail rmadd-6 "$testcvs -q ci -r mybranch -m add" \
+"$SPROG \[commit aborted\]: no such tag \`mybranch'"
+
+ # The thing with the trailing periods strikes me as a very
+ # bizarre behavior, but it would seem to be intentional
+ # (see commit.c). It probably could go away....
+ dotest rmadd-7 "${testcvs} -q ci -r 7.... -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 7\.1"
+ if $remote; then
+ # I guess remote doesn't set a sticky tag in this case.
+ # Kind of odd, in the sense that rmadd-24a does set one
+ # both local and remote.
+ dotest_fail rmadd-7a "test -f CVS/Tag"
+ echo T7 >CVS/Tag
+ else
+ dotest rmadd-7a "cat CVS/Tag" "T7"
+ fi
+
+ dotest rmadd-8 "${testcvs} -q tag -b mybranch" "T file1"
+ dotest rmadd-9 "${testcvs} -q tag mynonbranch" "T file1"
+
+ touch file2
+ # The previous "cvs ci -r" set a sticky tag of '7'. Seems a
+ # bit odd, and I guess commit.c (findmaxrev) makes '7' sticky
+ # tags unnecessary (?). I kind of suspect that it should be
+ # saying "sticky tag is not a branch" like keywordlog-4b.
+ # Or something.
+ dotest rmadd-10 "${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition on branch .7'
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ # As in the previous example, CVS is confused....
+ dotest rmadd-11 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 7\.1"
+
+ dotest rmadd-12 "${testcvs} -q update -A" ""
+ touch file3
+ dotest rmadd-13 "${testcvs} add file3" \
+"${SPROG} add: scheduling file .file3. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ # Huh? file2 is not up to date? Seems buggy to me....
+ dotest_fail rmadd-14 "${testcvs} -q ci -r mybranch -m add" \
+"${SPROG} commit: Up-to-date check failed for .file2'
+${SPROG} \[commit aborted\]: correct above errors first!"
+ # Whatever, let's not let file2 distract us....
+ dotest rmadd-15 "${testcvs} -q ci -r mybranch -m add file3" \
+"$CVSROOT_DIRNAME/first-dir/Attic/file3,v <-- file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ touch file4
+ dotest rmadd-16 "${testcvs} add file4" \
+"${SPROG} add: scheduling file .file4. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ # Prior to CVS 1.12.10, this would fail with a, "no such tag" message
+ # since val-tags used to be updated the first time the tag was used
+ # rather than when it was created.
+
+ # Try to make CVS write val-tags.
+ if $proxy; then :; else
+ # First remove the tag.
+ grep -v mynonbranch $CVSROOT_DIRNAME/CVSROOT/val-tags \
+ >$CVSROOT_DIRNAME/CVSROOT/val-tags-tmp
+ mv $CVSROOT_DIRNAME/CVSROOT/val-tags-tmp \
+ $CVSROOT_DIRNAME/CVSROOT/val-tags
+
+ dotest rmadd-18 "$testcvs -q update -p -r mynonbranch file1" \
+"first file1"
+ # Oops, -p suppresses writing val-tags (probably a questionable
+ # behavior).
+ dotest_fail rmadd-19 \
+"$testcvs -q ci -r mynonbranch -m add file4" \
+"$SPROG \[commit aborted\]: no such tag \`mynonbranch'"
+ # Now make CVS write val-tags for real.
+ dotest rmadd-20 "$testcvs -q update -r mynonbranch file1"
+ fi # !$proxy
+
+ # Oops - CVS isn't distinguishing between a branch tag and
+ # a non-branch tag.
+ dotest rmadd-21 \
+"${testcvs} -q ci -r mynonbranch -m add file4" \
+"$CVSROOT_DIRNAME/first-dir/Attic/file4,v <-- file4
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # OK, we add this one in a vanilla way, but then check in
+ # a modification with ci -r and sniff around for sticky tags.
+ echo file5 >file5
+ dotest rmadd-22 "${testcvs} add file5" \
+"${SPROG} add: scheduling file .file5. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ if $remote; then
+ # Interesting bug (or missing feature) here. findmaxrev
+ # gets the major revision from the Entries. Well, remote
+ # doesn't send the entries for files which are not involved.
+ dotest rmadd-23r "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+initial revision: 1\.1"
+ dotest rmadd-23-workaroundr \
+"${testcvs} -q ci -r 7 -m bump-it file5" \
+"$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+new revision: 7\.1; previous revision: 1\.1"
+ else
+ dotest rmadd-23 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+initial revision: 7\.1"
+ fi
+ echo change it >file5
+ dotest_fail rmadd-24 "$testcvs -q ci -r 4.8 -m change file5" \
+"$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+$SPROG commit: $CVSROOT_DIRNAME/first-dir/file5,v: revision 4\.8 too low; must be higher than 7\.1
+$SPROG commit: could not check in file5"
+ dotest rmadd-24a "${testcvs} -q ci -r 8.4 -m change file5" \
+"$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+new revision: 8\.4; previous revision: 7\.1"
+ # I'm not really sure that a sticky tag make sense here.
+ # It seems to be longstanding behavior for what that is worth.
+ dotest rmadd-25 "${testcvs} status file5" \
+"===================================================================
+File: file5 Status: Up-to-date
+
+ Working revision: 8\.4.*
+ Repository revision: 8\.4 ${CVSROOT_DIRNAME}/first-dir/file5,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: 8\.4
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # now try forced revision with recursion
+ mkdir sub
+ dotest rmadd-26 "${testcvs} -q add sub" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/sub added to the repository"
+ echo hello >sub/subfile
+ dotest rmadd-27 "${testcvs} -q add sub/subfile" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ dotest rmadd-28 "${testcvs} -q ci -m. sub" \
+"$CVSROOT_DIRNAME/first-dir/sub/subfile,v <-- sub/subfile
+initial revision: 1\.1"
+
+ # lose the branch
+ dotest rmadd-29 "${testcvs} -q up -A" \
+"${SPROG} update: \`file3' is no longer in the repository
+${SPROG} update: \`file4' is no longer in the repository"
+
+ # -f disables recursion
+ dotest rmadd-30 "${testcvs} -q ci -f -r9 -m." \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 9\.1; previous revision: 7\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 9\.1; previous revision: 7\.1
+$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+new revision: 9\.1; previous revision: 8\.4"
+
+ # add -R to force recursion
+ dotest rmadd-31 "${testcvs} -q ci -f -r9 -R -m." \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 9\.2; previous revision: 9\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 9\.2; previous revision: 9\.1
+$CVSROOT_DIRNAME/first-dir/file5,v <-- file5
+new revision: 9\.2; previous revision: 9\.1
+$CVSROOT_DIRNAME/first-dir/sub/subfile,v <-- sub/subfile
+new revision: 9\.1; previous revision: 1\.1"
+
+ if $remote; then
+ # as noted above, remote doesn't set a sticky tag
+ :
+ else
+ dotest rmadd-32 "cat CVS/Tag" "T9"
+ dotest rmadd-33 "cat sub/CVS/Tag" "T9"
+ fi
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ rmadd2)
+ # Tests of undoing commits, including in the presence of
+ # adding and removing files. See join for a list of -j tests.
+ mkdir 1; cd 1
+ dotest rmadd2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest rmadd2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo 'initial contents' >file1
+ dotest rmadd2-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest rmadd2-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ dotest rmadd2-4a "${testcvs} -Q tag tagone" ""
+ dotest rmadd2-5 "${testcvs} rm -f file1" \
+"${SPROG} remove: scheduling .file1. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest rmadd2-6 "${testcvs} -q ci -m remove" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1"
+ dotest rmadd2-7 "$testcvs -q update -j 1.2 -j 1.1 file1" "U file1"
+ dotest rmadd2-8 "${testcvs} -q ci -m readd" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+ echo 'new contents' >file1
+ dotest rmadd2-9 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3"
+ dotest rmadd2-10 "${testcvs} -q update -j 1.4 -j 1.3 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.4
+retrieving revision 1\.3
+Merging differences between 1\.4 and 1\.3 into file1"
+ dotest rmadd2-11 "${testcvs} -q ci -m undo" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4"
+ dotest rmadd2-12 "cat file1" "initial contents"
+ dotest rmadd2-13 "${testcvs} -q update -p -r 1.3" "initial contents"
+
+ # Hmm, might be a bit odd that this works even if 1.3 is not
+ # the head.
+ dotest rmadd2-14 "${testcvs} -q update -j 1.3 -j 1.2 file1" \
+"${SPROG} update: scheduling \`file1' for removal"
+
+ # Check that -p can get arbitrary revisions of a removed file
+ dotest rmadd2-14a "${testcvs} -q update -p" "initial contents"
+ dotest rmadd2-14b "${testcvs} -q update -p -r 1.5" "initial contents"
+ dotest rmadd2-14c "${testcvs} -q update -p -r 1.3" "initial contents"
+
+ dotest rmadd2-15 "${testcvs} -q ci -m re-remove" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.5"
+ dotest rmadd2-16 "${testcvs} log -h file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+Working file: file1
+head: 1\.6
+branch:
+locks: strict
+access list:
+symbolic names:
+ tagone: 1\.1
+keyword substitution: kv
+total revisions: 6
+============================================================================="
+ dotest rmadd2-17 "${testcvs} status -v file1" \
+"===================================================================
+File: no file file1 Status: Up-to-date
+
+ Working revision: No entry for file1
+ Repository revision: 1\.6 ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+ Commit Identifier: ${commitid}
+
+ Existing Tags:
+ tagone (revision: 1.1)"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ rmadd3)
+ # This test demonstrates that CVS notices that file1 exists rather
+ # that deleting or writing over it after:
+ #
+ # cvs remove -f file1; touch file1; cvs add file1.
+ #
+ # According to the manual, this should work for:
+ #
+ # rm file1; cvs remove file1; cvs add file1
+ #
+ # but in past version of CVS, new content in file1 would be
+ # erroneously deleted when file1 reappeared between the remove and
+ # the add.
+ #
+ # Later versions of CVS would refuse to perform the add, but still
+ # allow a subsequent local commit to erase the file from the
+ # workspace, possibly losing data.
+ mkdir 1; cd 1
+ dotest rmadd3-init1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest rmadd3-init2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ echo initial content for file1 >file1
+ dotest rmadd3-init3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file \`file1' for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ dotest rmadd3-init4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ # Here begins the guts of this test, as detailed above.
+ dotest rmadd3-1 "${testcvs} rm -f file1" \
+"${SPROG} remove: scheduling \`file1' for removal
+${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
+
+ # Now recreate the file:
+ echo desired future contents for file1 >file1
+
+ # And attempt to resurrect it at the same time:
+ dotest_fail rmadd3-2 "${testcvs} add file1" \
+"${SPROG} add: \`file1' should be removed and is still there (or is back again)"
+
+ # Now prove that commit knows that it shouldn't erase files.
+ dotest_fail rmadd3-3 "${testcvs} -q ci -m." \
+"$CPROG commit: \`file1' should be removed and is still there (or is back again)
+$CPROG \[commit aborted\]: correct above errors first!"
+
+ # Then these should pass too:
+ dotest rmadd3-4 "test -f file1"
+ dotest rmadd3-5 "cat file1" "desired future contents for file1"
+
+ if $keep; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ resurrection)
+ # This test tests a few file resurrection scenarios.
+ mkdir 1; cd 1
+ dotest resurrection-init1 "$testcvs -q co -l ." ''
+ mkdir first-dir
+ dotest resurrection-init2 "$testcvs add first-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+ cd first-dir
+
+ echo initial content for file1 >file1
+ dotest resurrection-init3 "$testcvs add file1" \
+"$SPROG add: scheduling file \`file1' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+ dotest resurrection-init4 "$testcvs -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ dotest resurrection-init5 "$testcvs -Q rm -f file1"
+
+ # The first test is that `cvs add' will resurrect a file before its
+ # removal has been committed.
+ dotest_sort resurrection-1 "$testcvs add file1" \
+"U file1
+$SPROG add: \`file1', version 1\.1, resurrected"
+ dotest resurrection-2 "$testcvs -Q diff file1" ""
+
+ dotest resurrection-init6 "$testcvs -Q tag -b resurrection"
+ dotest resurrection-init7 "$testcvs -Q rm -f file1"
+ dotest resurrection-init8 "$testcvs -Q ci -mrm"
+
+ # The next test is that CVS will resurrect a committed removal.
+ dotest_sort resurrection-3 "$testcvs add file1" \
+"U file1
+$SPROG add: Re-adding file \`file1' after dead revision 1\.2\.
+$SPROG add: Resurrecting file \`file1' from revision 1\.1\.
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+ dotest resurrection-4 "$testcvs -q diff -r1.1 file1" ""
+ dotest resurrection-5 "$testcvs -q ci -mreadd" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+
+ dotest resurrection-init9 "$testcvs -Q up -rresurrection"
+ dotest resurrection-init10 "$testcvs -Q rm -f file1"
+ dotest resurrection-init11 "$testcvs -Q ci -mrm-on-resurrection"
+
+ # The next test is that CVS will resurrect a committed removal to a
+ # branch.
+ dotest_sort resurrection-6 "$testcvs -r add file1" \
+"U file1
+$SPROG add: Re-adding file \`file1' on branch \`resurrection' after dead revision 1\.1\.2\.1\.
+$SPROG add: Resurrecting file \`file1' from revision 1\.1\.
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+ # If the file is modified, it had better be read-write
+ # regardless of what the user has requested with the CVSREAD
+ # environment variable or the global -r switch
+ dotest resurrection-6b 'test -w file1' ''
+ dotest resurrection-7 "$testcvs -Q diff -r1.1 file1" ""
+ dotest resurrection-8 "$testcvs -q ci -mreadd" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+
+ # The next few tests verify that an attempted resurrection of a file
+ # with no previous revision on the trunk fails.
+ touch file2
+ dotest resurrection-9 "$testcvs -Q add file2"
+ dotest resurrection-10 "$testcvs -Q ci -mnew-file2"
+ dotest resurrection-11 "$testcvs -Q up -A"
+
+ # This command once caused an assertion failure.
+ dotest resurrection-12 "$testcvs add file2" \
+"$SPROG add: File \`file2' has no previous revision to resurrect\."
+
+ # Check what 'cvs -r add' does with resurrected files.
+ dotest resurrection-13 "$testcvs -Q rm -f file1"
+ dotest_sort resurrection-14 "$testcvs -r add file1" \
+"U file1
+$SPROG add: \`file1', version 1\.3, resurrected"
+ dotest_fail resurrection-15 'test -w file1' ''
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ dirs)
+ # Tests related to removing and adding directories.
+ # See also:
+ # conflicts (especially dir1 in conflicts-130): What happens if
+ # directory exists in repository and a non-CVS-controlled
+ # directory in the working directory?
+ # conflicts3-15. More cases, especially where CVS directory
+ # exists but without CVS/Repository and friends.
+ # conflicts3-22. Similar to conflicts-130 but there is a file
+ # in the directory.
+ # dirs2. Sort of similar to conflicts3-22 but somewhat different.
+ mkdir imp-dir; cd imp-dir
+ echo file1 >file1
+ mkdir sdir
+ echo sfile >sdir/sfile
+ dotest_sort dirs-1 \
+"${testcvs} import -m import-it dir1 vend rel" "
+
+N dir1/file1
+N dir1/sdir/sfile
+No conflicts created by this import
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/dir1/sdir"
+ cd ..
+
+ mkdir 1; cd 1
+ dotest dirs-2 "$testcvs -Q co dir1" ""
+
+ # Various CVS administrators are in the habit of removing
+ # the repository directory for things they don't want any
+ # more. I've even been known to do it myself (on rare
+ # occasions). Not the usual recommended practice, but we want
+ # to try to come up with some kind of reasonable/documented/sensible
+ # behavior.
+ modify_repo rm -rf $CVSROOT_DIRNAME/dir1/sdir
+
+ dotest dirs-3 "${testcvs} update" \
+"${SPROG} update: Updating dir1
+${SPROG} update: Updating dir1/sdir
+${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory
+${SPROG} update: skipping directory dir1/sdir"
+ dotest dirs-3a "${testcvs} update -d" \
+"${SPROG} update: Updating dir1
+${SPROG} update: Updating dir1/sdir
+${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory
+${SPROG} update: skipping directory dir1/sdir"
+
+ # If we say "yes", then CVS gives errors about not being able to
+ # create lock files.
+ # The fact that it says "skipping directory " rather than
+ # "skipping directory dir1/sdir" is some kind of bug.
+ dotest dirs-4 "echo no | ${testcvs} release -d dir1/sdir" \
+"${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory
+${SPROG} update: skipping directory
+You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .dir1/sdir': .. .release' aborted by user choice."
+
+ # OK, if "cvs release" won't help, we'll try it the other way...
+ rm -r dir1/sdir
+
+ dotest dirs-5 "cat dir1/CVS/Entries" \
+"/file1/1.1.1.1/[a-zA-Z0-9 :]*//
+D/sdir////"
+ dotest dirs-6 "${testcvs} update" "${SPROG} update: Updating dir1"
+ dotest dirs-7 "cat dir1/CVS/Entries" \
+"/file1/1.1.1.1/[a-zA-Z0-9 :]*//
+D/sdir////"
+ dotest dirs-8 "${testcvs} update -d dir1" \
+"${SPROG} update: Updating dir1"
+
+ dokeep
+ cd ..
+ rm -r imp-dir 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/dir1
+ ;;
+
+
+
+ dirs2)
+ # See "dirs" for a list of tests involving adding and
+ # removing directories.
+ mkdir 1; cd 1
+ dotest dirs2-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest dirs2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ mkdir sdir
+ dotest dirs2-3 "${testcvs} add sdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository"
+ touch sdir/file1
+ dotest dirs2-4 "${testcvs} add sdir/file1" \
+"${SPROG} add: scheduling file .sdir/file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest dirs2-5 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/sdir/file1,v <-- sdir/file1
+initial revision: 1\.1"
+ rm -r sdir/CVS
+ if $remote; then
+ # This is just like conflicts3-23
+ dotest_fail dirs2-6r "${testcvs} update -d" \
+"${QUESTION} sdir
+${SPROG} update: Updating \.
+${SPROG} update: Updating sdir
+${CPROG} update: move away \`sdir/file1'; it is in the way
+C sdir/file1"
+ rm sdir/file1
+ rm -r sdir/CVS
+
+ # This is where things are not just like conflicts3-23
+ dotest dirs2-7r "${testcvs} update -d" \
+"${QUESTION} sdir
+${SPROG} update: Updating \.
+${SPROG} update: Updating sdir
+U sdir/file1"
+ else
+ dotest dirs2-6 "${testcvs} update -d" \
+"${CPROG} update: Updating \.
+${QUESTION} sdir"
+ rm sdir/file1
+ dotest dirs2-7 "${testcvs} update -d" \
+"${CPROG} update: Updating \.
+${QUESTION} sdir"
+ fi
+ cd ../..
+
+ # Now, the same thing (more or less) on a branch.
+ mkdir 2; cd 2
+ dotest dirs2-8 "${testcvs} -q co first-dir" 'U first-dir/sdir/file1'
+ cd first-dir
+ dotest dirs2-9 "${testcvs} -q tag -b br" "T sdir/file1"
+ rm -r sdir/CVS
+
+ if $remote; then
+ # val-tags used to have a cute little quirk; if an update didn't
+ # recurse into the directories where the tag is defined, val-tags
+ # wouldn't get updated. This is no longer a problem as of 1.12.10.
+ dotest_fail dirs2-10-againr "$testcvs update -d -r br" \
+"$QUESTION sdir
+$SPROG update: Updating \.
+$SPROG update: Updating sdir
+$CPROG update: move away \`sdir/file1'; it is in the way
+C sdir/file1"
+ else
+ dotest dirs2-10 "${testcvs} update -d -r br" \
+"$SPROG update: Updating \.
+$QUESTION sdir"
+# This is what used to happen. I'm not sure why it changed with 1.12.10, but
+# as near as I can tell from the comments in update_direntproc, the new
+# behavior was the intended behavior.
+#"$CPROG update: in directory \`sdir':
+#$CPROG \[update aborted\]: there is no version here; do \`$CPROG checkout' first"
+ fi
+ cd ../..
+
+ # OK, the above tests make the situation somewhat harder
+ # than it might be, in the sense that they actually have a
+ # file which is alive on the branch we are updating. Let's
+ # try it where it is just a directory where all the files
+ # have been removed.
+ mkdir 3; cd 3
+ dotest dirs2-11 "${testcvs} -q co -r br first-dir" \
+"U first-dir/sdir/file1"
+ cd first-dir
+ # Hmm, this doesn't mention the branch like add does. That's
+ # an odd non-orthogonality.
+ dotest dirs2-12 "${testcvs} rm -f sdir/file1" \
+"${SPROG} remove: scheduling .sdir/file1. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest dirs2-13 "${testcvs} -q ci -m remove" \
+"$CVSROOT_DIRNAME/first-dir/sdir/file1,v <-- sdir/file1
+new revision: delete; previous revision: 1\.1"
+ cd ../../2/first-dir
+ if $remote; then
+ dotest dirs2-14 "${testcvs} update -d -r br" \
+"${QUESTION} sdir/file1
+${SPROG} update: Updating \.
+${SPROG} update: Updating sdir"
+ else
+ dotest dirs2-14 "${testcvs} update -d -r br" \
+"${CPROG} update: Updating \.
+${QUESTION} sdir"
+ fi
+
+ dokeep
+ cd ../..
+ rm -r 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ branches)
+ # More branch tests, including branches off of branches
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest branches-1 "$testcvs -q co first-dir"
+ cd first-dir
+ echo 1:ancest >file1
+ echo 2:ancest >file2
+ echo 3:ancest >file3
+ echo 4:trunk-1 >file4
+ dotest branches-2 "${testcvs} add file1 file2 file3 file4" \
+"$SPROG add: scheduling file \`file1' for addition
+$SPROG add: scheduling file \`file2' for addition
+$SPROG add: scheduling file \`file3' for addition
+$SPROG add: scheduling file \`file4' for addition
+$SPROG add: use .$SPROG commit. to add these files permanently"
+ dotest branches-2a "$testcvs -n -q ci -m dont-commit"
+ dotest_lit branches-3 "$testcvs -q ci -m add-it" <<HERE
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1.1
+${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3
+initial revision: 1.1
+${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4
+initial revision: 1.1
+HERE
+ echo 4:trunk-2 >file4
+ dotest branches-3.2 "${testcvs} -q ci -m trunk-before-branch" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.2; previous revision: 1\.1"
+ # The "cvs log file4" in test branches-14.3 will test that we
+ # didn't really add the tag.
+ dotest branches-3.3 "${testcvs} -qn tag dont-tag" \
+"T file1
+T file2
+T file3
+T file4"
+ # Modify this file before branching, to deal with the case where
+ # someone is hacking along, says "oops, I should be doing this on
+ # a branch", and only then creates the branch.
+ echo 1:br1 >file1
+ dotest branches-4 "${testcvs} tag -b br1" "${SPROG}"' tag: Tagging \.
+T file1
+T file2
+T file3
+T file4'
+ dotest branches-5 "${testcvs} update -r br1" \
+"${SPROG} update: Updating \.
+M file1"
+ echo 2:br1 >file2
+ echo 4:br1 >file4
+ dotest branches-6 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.2\.2\.1; previous revision: 1\.2"
+ dotest branches-7 "${testcvs} -q tag -b brbr" 'T file1
+T file2
+T file3
+T file4'
+ dotest branches-8 "${testcvs} -q update -r brbr" ''
+ echo 1:brbr >file1
+ echo 4:brbr >file4
+ dotest branches-9 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1\.2\.1; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.2\.2\.1\.2\.1; previous revision: 1\.2\.2\.1"
+ dotest branches-10 "cat file1 file2 file3 file4" '1:brbr
+2:br1
+3:ancest
+4:brbr'
+ dotest branches-11 "${testcvs} -q update -r br1" \
+'[UP] file1
+[UP] file4'
+ dotest branches-12 "cat file1 file2 file3 file4" '1:br1
+2:br1
+3:ancest
+4:br1'
+ echo 4:br1-2 >file4
+ dotest branches-12.2 "${testcvs} -q ci -m change-on-br1" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.2\.2\.2; previous revision: 1\.2\.2\.1"
+ dotest branches-13 "${testcvs} -q update -A" '[UP] file1
+[UP] file2
+[UP] file4'
+ dotest branches-14 "cat file1 file2 file3 file4" '1:ancest
+2:ancest
+3:ancest
+4:trunk-2'
+ echo 4:trunk-3 >file4
+ dotest branches-14.2 \
+ "${testcvs} -q ci -m trunk-change-after-branch" \
+"$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.3; previous revision: 1\.2"
+ dotest branches-14.3 "${testcvs} log file4" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
+Working file: file4
+head: 1\.3
+branch:
+locks: strict
+access list:
+symbolic names:
+ brbr: 1\.2\.2\.1\.0\.2
+ br1: 1\.2\.0\.2
+keyword substitution: kv
+total revisions: 6; selected revisions: 6
+description:
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+trunk-change-after-branch
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+branches: 1\.2\.2;
+trunk-before-branch
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+add-it
+----------------------------
+revision 1\.2\.2\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+change-on-br1
+----------------------------
+revision 1\.2\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+branches: 1\.2\.2\.1\.2;
+modify
+----------------------------
+revision 1\.2\.2\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+modify
+============================================================================="
+ dotest_fail branches-14.4 \
+ "${testcvs} diff -c -r 1.1 -r 1.3 file4" \
+"Index: file4
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
+retrieving revision 1\.1
+retrieving revision 1\.3
+diff -c -r1\.1 -r1\.3
+\*\*\* file4 ${RFCDATE} 1\.1
+--- file4 ${RFCDATE} 1\.3
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+! 4:trunk-1
+--- 1 ----
+! 4:trunk-3"
+ dotest_fail branches-14.5 \
+ "${testcvs} diff -c -r 1.1 -r 1.2.2.1 file4" \
+"Index: file4
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
+retrieving revision 1\.1
+retrieving revision 1\.2\.2\.1
+diff -c -r1\.1 -r1\.2\.2\.1
+\*\*\* file4 ${RFCDATE} 1\.1
+--- file4 ${RFCDATE} 1\.2\.2\.1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+! 4:trunk-1
+--- 1 ----
+! 4:br1"
+ dotest branches-15 \
+ "${testcvs} update -j 1.1.2.1 -j 1.1.2.1.2.1 file1" \
+ "RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1\.2\.1
+retrieving revision 1\.1\.2\.1\.2\.1
+Merging differences between 1\.1\.2\.1 and 1\.1\.2\.1\.2\.1 into file1
+rcsmerge: warning: conflicts during merge"
+ dotest branches-16 "cat file1" '<<<<<<< file1
+1:ancest
+[=]======
+1:brbr
+[>]>>>>>> 1\.1\.2\.1\.2\.1'
+
+ dotest branches-o1 "${testcvs} -q admin -o ::brbr" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v
+done
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
+done"
+
+ dokeep
+ cd ..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r first-dir
+ ;;
+
+
+
+ branches2)
+ # More branch tests.
+ # Test that when updating a new subdirectory in a directory
+ # which was checked out on a branch, the new subdirectory is
+ # created on the appropriate branch. Test this when joining
+ # as well.
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir trunk; cd trunk
+
+ # Create a file.
+ dotest branches2-1 "${testcvs} -q co first-dir"
+ cd first-dir
+ echo "file1 first revision" > file1
+ dotest branches2-2 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest branches2-3 "${testcvs} commit -m add file1" \
+"${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ # Tag the file.
+ dotest branches2-4 "${testcvs} -q tag tag1" 'T file1'
+
+ # Make two branches.
+ dotest branches2-5 "${testcvs} -q rtag -b -r tag1 b1 first-dir" ''
+ dotest branches2-6 "${testcvs} -q rtag -b -r tag1 b2 first-dir" ''
+
+ # Create some files and a subdirectory on branch b1.
+ cd ../..
+ mkdir b1; cd b1
+ dotest branches2-7 "${testcvs} -q co -r b1 first-dir" \
+"U first-dir/file1"
+ cd first-dir
+ echo "file2 first revision" > file2
+ dotest branches2-8 "${testcvs} add file2" \
+"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `b1'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ mkdir dir1
+ dotest branches2-9 "${testcvs} add dir1" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository
+--> Using per-directory sticky tag "'`'"b1'"
+ echo "file3 first revision" > dir1/file3
+ dotest branches2-10 "${testcvs} add dir1/file3" \
+"${SPROG}"' add: scheduling file `dir1/file3'\'' for addition on branch `b1'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest branches2-11 "${testcvs} -q ci -madd ." \
+"$CVSROOT_DIRNAME/first-dir/Attic/file2,v <-- file2
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir1/Attic/file3,v <-- dir1/file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # Check out the second branch, and update the working
+ # directory to the first branch, to make sure the right
+ # happens with dir1.
+ cd ../..
+ mkdir b2; cd b2
+ dotest branches2-12 "${testcvs} -q co -r b2 first-dir" \
+'U first-dir/file1'
+ cd first-dir
+ dotest branches2-13 "${testcvs} update -d -r b1 dir1" \
+"${SPROG} update: Updating dir1
+U dir1/file3"
+ dotest branches2-14 "${testcvs} -q status" \
+"===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: b2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Up-to-date
+
+ Working revision: 1\.1\.2\.1.*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: b1 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # Test some calls to rls here because we can. These should probably
+ # be somewhere else, but we already have some directories set up.
+ dotest branches2-14-rls-1 "$testcvs rls" \
+"$SPROG rls: Listing module: \`.'
+CVSROOT
+first-dir"
+ dotest branches2-14-rls-2 "$testcvs rls -R" \
+"$SPROG rls: Listing module: \`.'
+\.:
+CVSROOT
+first-dir
+
+CVSROOT:
+checkoutlist
+commitinfo
+config
+cvswrappers
+loginfo
+modules
+notify
+postadmin
+postproxy
+posttag
+postwatch
+preproxy
+rcsinfo
+taginfo
+verifymsg
+Emptydir
+
+CVSROOT/Emptydir:
+
+first-dir:
+file1
+dir1
+
+first-dir/dir1:"
+ dotest branches2-14-rls-3 "$testcvs rls -l -R" \
+"$SPROG rls: Listing module: \`.'
+\.:
+d--- $ISO8601DATE CVSROOT
+d--- $ISO8601DATE first-dir
+
+CVSROOT:
+---- $ISO8601DATE 1\.[0-9][0-9]* checkoutlist
+---- $ISO8601DATE 1\.[0-9][0-9]* commitinfo
+---- $ISO8601DATE 1\.[0-9][0-9]* config
+---- $ISO8601DATE 1\.[0-9][0-9]* cvswrappers
+---- $ISO8601DATE 1\.[0-9][0-9]* loginfo
+---- $ISO8601DATE 1\.[0-9][0-9]* modules
+---- $ISO8601DATE 1\.[0-9][0-9]* notify
+---- $ISO8601DATE 1\.[0-9][0-9]* postadmin
+---- $ISO8601DATE 1\.[0-9][0-9]* postproxy
+---- $ISO8601DATE 1\.[0-9][0-9]* posttag
+---- $ISO8601DATE 1\.[0-9][0-9]* postwatch
+---- $ISO8601DATE 1\.[0-9][0-9]* preproxy
+---- $ISO8601DATE 1\.[0-9][0-9]* rcsinfo
+---- $ISO8601DATE 1\.[0-9][0-9]* taginfo
+---- $ISO8601DATE 1\.[0-9][0-9]* verifymsg
+d--- $ISO8601DATE Emptydir
+
+CVSROOT/Emptydir:
+
+first-dir:
+---- $ISO8601DATE 1\.1 file1
+d--- $ISO8601DATE dir1
+
+first-dir/dir1:"
+ dotest branches2-14-rls-4 "$testcvs rls -eR" \
+"$SPROG rls: Listing module: \`.'
+\.:
+D/CVSROOT////
+D/first-dir////
+
+CVSROOT:
+/checkoutlist/1\.[0-9][0-9]*/$DATE//
+/commitinfo/1\.[0-9][0-9]*/$DATE//
+/config/1\.[0-9][0-9]*/$DATE//
+/cvswrappers/1\.[0-9][0-9]*/$DATE//
+/loginfo/1\.[0-9][0-9]*/$DATE//
+/modules/1\.[0-9][0-9]*/$DATE//
+/notify/1\.[0-9][0-9]*/$DATE//
+/postadmin/1\.[0-9][0-9]*/$DATE//
+/postproxy/1\.[0-9][0-9]*/$DATE//
+/posttag/1\.[0-9][0-9]*/$DATE//
+/postwatch/1\.[0-9][0-9]*/$DATE//
+/preproxy/1\.[0-9][0-9]*/$DATE//
+/rcsinfo/1\.[0-9][0-9]*/$DATE//
+/taginfo/1\.[0-9][0-9]*/$DATE//
+/verifymsg/1\.[0-9][0-9]*/$DATE//
+D/Emptydir////
+
+CVSROOT/Emptydir:
+
+first-dir:
+/file1/1\.1/$DATE//
+D/dir1////
+
+first-dir/dir1:"
+ dotest branches2-14-rls-5 "$testcvs -q rls -R" \
+"\.:
+CVSROOT
+first-dir
+
+CVSROOT:
+checkoutlist
+commitinfo
+config
+cvswrappers
+loginfo
+modules
+notify
+postadmin
+postproxy
+posttag
+postwatch
+preproxy
+rcsinfo
+taginfo
+verifymsg
+Emptydir
+
+CVSROOT/Emptydir:
+
+first-dir:
+file1
+dir1
+
+first-dir/dir1:"
+ dotest branches2-14-rls-6 "$testcvs -q rls -lRrb1" \
+"\.:
+d--- $ISO8601DATE CVSROOT
+d--- $ISO8601DATE first-dir
+
+CVSROOT:
+d--- $ISO8601DATE Emptydir
+
+CVSROOT/Emptydir:
+
+first-dir:
+---- $ISO8601DATE 1\.1 file1
+---- $ISO8601DATE 1\.1\.2\.1 file2
+d--- $ISO8601DATE dir1
+
+first-dir/dir1:
+---- $ISO8601DATE 1\.1\.2\.1 file3"
+ dotest branches2-14-rls-7 "$testcvs -q rls -lRrb2" \
+"\.:
+d--- $ISO8601DATE CVSROOT
+d--- $ISO8601DATE first-dir
+
+CVSROOT:
+d--- $ISO8601DATE Emptydir
+
+CVSROOT/Emptydir:
+
+first-dir:
+---- $ISO8601DATE 1\.1 file1
+d--- $ISO8601DATE dir1
+
+first-dir/dir1:"
+
+ # Now some calls to ls. These are more appropriate here.
+ dotest branches2-14-ls-1 "$testcvs ls" \
+"file1
+dir1"
+ dotest branches2-14-ls-2 "$testcvs ls -e" \
+"/file1/1\.1/$DATE//
+D/dir1////"
+ dotest branches2-14-ls-3 "$testcvs ls -R" \
+"\.:
+file1
+dir1
+
+dir1:
+file3"
+ dotest branches2-14-ls-4 "$testcvs ls -eRrHEAD" \
+"\.:
+/file1/1\.1/$DATE//THEAD
+D/dir1////
+
+dir1:"
+ dotest branches2-14-ls-5 "$testcvs ls -eRrb1" \
+"\.:
+/file1/1\.1/$DATE//Tb1
+/file2/1\.1\.2\.1/$DATE//Tb1
+D/dir1////
+
+dir1:
+/file3/1\.1\.2\.1/$DATE//Tb1"
+ dotest branches2-14-ls-6 "$testcvs ls -eRrb2" \
+"\.:
+/file1/1.1/$DATE//Tb2
+D/dir1////
+
+dir1:"
+ # Nonexistant tags used to cause assertion failures.
+ dotest_fail branches2-14-ls-7 "$testcvs ls -eRrnosuchtag" \
+"$SPROG \[ls aborted\]: no such tag \`nosuchtag'"
+
+ # FIXME: Just clobbering the directory like this is a bit
+ # tacky, although people generally expect it to work. Maybe
+ # we should release it instead. We do it a few other places
+ # below as well.
+ rm -r dir1
+ dotest branches2-15 "${testcvs} update -d -j b1 dir1" \
+"${SPROG} update: Updating dir1
+U dir1/file3"
+ # FIXCVS: The `No revision control file' stuff seems to be
+ # CVS's way of telling us that we're adding the file on a
+ # branch, and the file is not on that branch yet. This
+ # should be nicer.
+ dotest branches2-16 "${testcvs} -q status" \
+"===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: b2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: b2 - MISSING from RCS file!
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ cd ../../trunk/first-dir
+ dotest branches2-17 "${testcvs} update -d -P dir1" \
+"${SPROG} update: Updating dir1"
+ dotest_fail branches2-18 "test -d dir1"
+ dotest branches2-19 "${testcvs} update -d -P -r b1 dir1" \
+"${SPROG} update: Updating dir1
+U dir1/file3"
+ dotest branches2-20 "${testcvs} -q status" \
+"===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Up-to-date
+
+ Working revision: 1\.1\.2\.1.*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: b1 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ rm -r dir1
+ dotest branches2-21 "${testcvs} update -d -P -j b1 dir1" \
+"${SPROG} update: Updating dir1
+U dir1/file3"
+ dotest branches2-22 "${testcvs} -q status" \
+"===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ cd ../..
+ rm -r b1 b2
+
+ # Check out branch b1 twice. Crate a new directory in one
+ # working directory, then do a cvs update in the other
+ # working directory and see if the tags are right.
+ mkdir b1a
+ mkdir b1b
+ cd b1b
+ dotest branches2-23 "${testcvs} -q co -r b1 first-dir" \
+'U first-dir/file1
+U first-dir/file2
+U first-dir/dir1/file3'
+ cd ../b1a
+ dotest branches2-24 "${testcvs} -q co -r b1 first-dir" \
+'U first-dir/file1
+U first-dir/file2
+U first-dir/dir1/file3'
+ cd first-dir
+ mkdir dir2
+ dotest branches2-25 "${testcvs} add dir2" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir2 added to the repository
+--> Using per-directory sticky tag "'`'"b1'"
+ echo "file4 first revision" > dir2/file4
+ dotest branches2-26 "${testcvs} add dir2/file4" \
+"${SPROG}"' add: scheduling file `dir2/file4'\'' for addition on branch `b1'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest branches2-27 "${testcvs} -q commit -madd" \
+"$CVSROOT_DIRNAME/first-dir/dir2/Attic/file4,v <-- dir2/file4
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ cd ../../b1b/first-dir
+ dotest branches2-28 "${testcvs} update -d dir2" \
+"${SPROG} update: Updating dir2
+U dir2/file4"
+ cd dir2
+ dotest branches2-29 "${testcvs} -q status" \
+"===================================================================
+File: file4 Status: Up-to-date
+
+ Working revision: 1\.1\.2\.1.*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/dir2/Attic/file4,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: b1 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest branches2-30 "cat CVS/Tag" 'Tb1'
+
+ # Test update -A on a subdirectory
+ cd ..
+ rm -r dir2
+ dotest branches2-31 "${testcvs} update -A -d dir2" \
+"${SPROG} update: Updating dir2"
+ cd dir2
+ dotest branches2-32 "${testcvs} -q status" ''
+ dotest_fail branches2-33 "test -f CVS/Tag"
+
+ # Add a file on the trunk.
+ echo "file5 first revision" > file5
+ dotest branches2-34 "${testcvs} add file5" \
+"${SPROG}"' add: scheduling file `file5'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest branches2-35 "${testcvs} -q commit -madd" \
+"$CVSROOT_DIRNAME/first-dir/dir2/file5,v <-- file5
+initial revision: 1\.1"
+
+ cd ../../../trunk/first-dir
+ dotest branches2-36 "${testcvs} -q update -d dir2" 'U dir2/file5'
+ cd dir2
+ dotest branches2-37 "${testcvs} -q status" \
+"===================================================================
+File: file5 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir2/file5,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest_fail branches2-38 "test -f CVS/status"
+
+ dotest branches2-39 "$testcvs rls -rb1 -l -R first-dir" \
+"$SPROG rls: Listing module: \`first-dir'
+first-dir:
+---- $ISO8601DATE 1\.1 file1
+---- $ISO8601DATE 1\.1\.2\.1 file2
+d--- $ISO8601DATE dir1
+d--- $ISO8601DATE dir2
+
+first-dir/dir1:
+---- $ISO8601DATE 1\.1\.2\.1 file3
+
+first-dir/dir2:
+---- $ISO8601DATE 1\.1\.2\.1 file4"
+
+ dokeep
+ cd ../../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r trunk b1a b1b
+ ;;
+
+
+
+ branches3)
+ # test local branch number support
+
+ # This test is skipped in $remotehost mode since the
+ # CVS_LOCAL_BRANCH_NUM is not inherited by the server process as it
+ # is with :fork:, for hopefully obvious reasons.
+ #
+ # FIXCVS? Is this correct? Should CVS_LOCAL_BRANCH_NUM be sent as
+ # a protocol extension or is it reasonable to only want this set on
+ # the server?
+
+ if test -n "$remotehost"; then :;else
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir branches3; cd branches3
+
+ dotest branches3-1 "$testcvs -q co first-dir"
+ cd first-dir
+ echo "file1 first revision" > file1
+ dotest branches3-2 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest branches3-3 "${testcvs} commit -m add file1" \
+"${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ # Tag the file using a CVS_LOCAL_BRANCH_NUM of 1000
+ CVS_LOCAL_BRANCH_NUM=1000; export CVS_LOCAL_BRANCH_NUM
+ dotest branches3-4 "${testcvs} -q tag -b tag1" 'T file1'
+ unset CVS_LOCAL_BRANCH_NUM
+ dotest branches3-5 "${testcvs} -q log file1" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ tag1: 1\.1\.0\.1000
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r branches3
+ fi # !$remotehost
+ ;;
+
+
+
+ branches4)
+ # test where a tag is a branch tag in some files and a revision
+ # tag in others
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir branches4; cd branches4
+
+ dotest branches4-1 "$testcvs -q co first-dir"
+ cd first-dir
+ mkdir branches mixed mixed2 versions
+ dotest branches4-2 "${testcvs} -q add branches mixed mixed2 versions" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/branches added to the repository
+Directory ${CVSROOT_DIRNAME}/first-dir/mixed added to the repository
+Directory ${CVSROOT_DIRNAME}/first-dir/mixed2 added to the repository
+Directory ${CVSROOT_DIRNAME}/first-dir/versions added to the repository"
+
+ echo file1 >branches/file1
+ echo file2 >branches/file2
+ echo file3 >branches/file3
+ echo file4 >branches/file4
+ cp branches/file* mixed
+ cp branches/file* mixed2
+ cp branches/file* versions
+
+ dotest branches4-3 "${testcvs} -q add */file*" \
+"${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest branches4-3a "${testcvs} -Q ci -m."
+
+ dotest branches4-4 "${testcvs} -q tag xxx versions/file* mixed*/file1 mixed*/file3" \
+"T versions/file1
+T versions/file2
+T versions/file3
+T versions/file4
+T mixed/file1
+T mixed/file3
+T mixed2/file1
+T mixed2/file3"
+
+ dotest branches4-5 "${testcvs} -q tag -b xxx branches/file* mixed*/file2 mixed*/file4" \
+"T branches/file1
+T branches/file2
+T branches/file3
+T branches/file4
+T mixed/file2
+T mixed/file4
+T mixed2/file2
+T mixed2/file4"
+
+ # make sure we get the appropriate warnings when updating
+ dotest branches4-6 "${testcvs} update -r xxx" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating branches
+${SPROG} update: Updating mixed
+${SPROG} update: warning: xxx is a branch tag in some files and a revision tag in others\.
+${SPROG} update: Updating mixed2
+${SPROG} update: warning: xxx is a branch tag in some files and a revision tag in others\.
+${SPROG} update: Updating versions"
+
+ # make sure we don't get warned in quiet modes
+ dotest branches4-7 "${testcvs} -q update -A"
+ dotest branches4-8 "${testcvs} -q update -r xxx"
+ dotest branches4-9 "${testcvs} -q update -A"
+ dotest branches4-10 "${testcvs} -Q update -r xxx"
+
+ # make sure the Tag files are correct
+ dotest branches4-11 "cat branches/CVS/Tag" "Txxx"
+ dotest branches4-12 "cat mixed/CVS/Tag" "Nxxx"
+ dotest branches4-13 "cat mixed2/CVS/Tag" "Nxxx"
+ dotest branches4-14 "cat versions/CVS/Tag" "Nxxx"
+
+ # We only warn if there's mixed usage in a single directory.
+ # We may want to consider changing that in the future.
+ dotest branches4-15 "${testcvs} update -r xxx branches versions" \
+"${SPROG} update: Updating branches
+${SPROG} update: Updating versions"
+
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r branches4
+ ;;
+
+
+
+ tagc)
+ # Test the tag -c option.
+ mkdir 1; cd 1
+ dotest tagc-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest tagc-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch file1 file2
+ dotest tagc-3 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest tagc-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ dotest tagc-5 "${testcvs} -q tag -c tag1" \
+"T file1
+T file2"
+ touch file1 file2
+ dotest tagc-6 "${testcvs} -q tag -c tag2" \
+"T file1
+T file2"
+ # Avoid timestamp granularity bugs (FIXME: CVS should be
+ # doing the sleep, right?).
+ sleep 1
+ echo myedit >>file1
+ dotest tagc-6a "${testcvs} rm -f file2" \
+"${SPROG} remove: scheduling .file2. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ touch file3
+ dotest tagc-6b "${testcvs} add file3" \
+"${SPROG} add: scheduling file .file3. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest_fail tagc-7 "${testcvs} -q tag -c tag3" \
+"${SPROG} tag: file1 is locally modified
+${SPROG} tag: file2 is locally modified
+${SPROG} tag: file3 is locally modified
+${SPROG} \[tag aborted\]: correct the above errors first!"
+ cd ../..
+ mkdir 2
+ cd 2
+ dotest tagc-8 "${testcvs} -q co first-dir" \
+"U first-dir/file1
+U first-dir/file2"
+ cd ../1/first-dir
+ dotest tagc-9 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+initial revision: 1\.1"
+ cd ../../2/first-dir
+ dotest tagc-10 "${testcvs} -q tag -c tag4" \
+"${SPROG} tag: \`file2' is no longer in the repository
+T file1
+T file2"
+
+ dokeep
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ update-p)
+ # Make sure `cvs update -p -rT FILE' works from a branch when
+ # FILE is already on the trunk and is being added to that branch.
+
+ mkdir 1; cd 1
+ module=x
+
+ echo > unused-file
+
+ # Create the module.
+ dotest update-p-1 \
+ "$testcvs -Q import -m. $module X Y" ''
+
+ file=F
+ # Check it out and tag it.
+ dotest update-p-2 "$testcvs -Q co $module" ''
+ cd $module
+ dotest update-p-3 "$testcvs -Q tag -b B" ''
+ echo v1 > $file
+ dotest update-p-4 "$testcvs -Q add $file" ''
+ dotest update-p-5 "$testcvs -Q ci -m. $file"
+ dotest update-p-6 "$testcvs -Q tag T $file" ''
+ dotest update-p-7 "$testcvs -Q update -rB" ''
+
+ # This merge effectively adds file F on branch B.
+ dotest update-p-8 "$testcvs -Q update -jT" ''
+
+ # Before the fix that prompted the addition of this test,
+ # the following command would fail with this diagnostic:
+ # cvs update: conflict: F created independently by second party
+ dotest update-p-9 "$testcvs update -p -rT $file" \
+"===================================================================
+Checking out $file
+RCS: ${CVSROOT_DIRNAME}/$module/$file,v
+VERS: 1\.1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+v1"
+
+ # Repeat the above, but with $file removed.
+ # This exercises a slightly different code path.
+ rm $file
+ # Before the fix that prompted the addition of this test,
+ # the following command would fail with this diagnostic:
+ # cvs update: warning: new-born \`F' has disappeared
+ dotest update-p-10 "$testcvs update -p -rT $file" \
+"===================================================================
+Checking out $file
+RCS: ${CVSROOT_DIRNAME}/$module/$file,v
+VERS: 1\.1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+v1"
+
+ # Exercise yet another code path:
+ # the one that involves reviving a `dead' file.
+ # And a little more, for good measure...
+ touch new
+ dotest update-p-a1 "$testcvs -Q add new" ''
+ dotest update-p-a2 "$testcvs -Q update -p new" ''
+ dotest update-p-a3 "$testcvs -Q rm -f new" ''
+
+ # Both an update -A, *and* the following update are required
+ # to return to the state of being on the trunk with a $file
+ # that we can then remove.
+ dotest update-p-undead-0 "$testcvs update -A" \
+"${SPROG} update: Updating \.
+${SPROG} update: warning: new-born \`$file' has disappeared"
+ dotest update-p-undead-1 "$testcvs update" \
+"${SPROG} update: Updating \.
+U $file"
+ dotest update-p-undead-2 "$testcvs -Q update -p -rT $file" v1
+ dotest update-p-undead-3 "$testcvs -Q rm -f $file" ''
+ dotest update-p-undead-4 "$testcvs -Q update -p -rT $file" v1
+ dotest update-p-undead-5 "$testcvs -Q ci -m. $file"
+ dotest update-p-undead-6 "$testcvs -Q update -p -rT $file" v1
+ echo v2 > $file
+ dotest update-p-undead-7 "$testcvs -Q update -p -rT $file" v1
+ dotest update-p-undead-8 "$testcvs add $file" \
+"$SPROG add: Re-adding file .$file. after dead revision 1\.2\.
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+
+ dotest update-p-undead-9 "$testcvs -Q update -p -rT $file" v1
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ tagf)
+ # More tagging tests, including using tag -F -B to convert a
+ # branch tag to a regular tag and recovering thereof.
+
+ # Setup; check in first-dir/file1
+ mkdir 1; cd 1
+ dotest tagf-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest tagf-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch file1 file2
+ dotest tagf-3 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest tagf-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+
+ # Now create a branch and commit a revision there.
+ dotest tagf-5 "${testcvs} -q tag -b br" "T file1
+T file2"
+ dotest tagf-6 "${testcvs} -q update -r br" ""
+ echo brmod >> file1
+ echo brmod >> file2
+ dotest tagf-7 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ # Here we try to make it a non-branch tag, but will
+ # succeed in getting only warnings, even with -F
+ # because converting a branch tag to non-branch
+ # is potentially catastrophic.
+ dotest tagf-8a "${testcvs} -q tag -F br" \
+"${SPROG} tag: file1: Not moving branch tag .br. from 1\.1\.2\.1 to 1\.1\\.2\.1\.
+${SPROG} tag: file2: Not moving branch tag .br. from 1\.1\.2\.1 to 1\.1\.2\.1\."
+ # however, if we *really* are sure we want to move a branch tag,
+ # "-F -B" will do the trick
+ dotest tagf-8 "${testcvs} -q tag -F -B br" "T file1
+T file2"
+ echo moremod >> file1
+ echo moremod >> file2
+ dotest tagf-9 "${testcvs} -q status -v file1" \
+"===================================================================
+File: file1 Status: Locally Modified
+
+ Working revision: 1\.1\.2\.1.*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br (revision: 1\.1\.2\.1)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ br (revision: 1\.1\.2\.1)"
+
+ # Now, how do we recover?
+ dotest tagf-10 "${testcvs} -q tag -d br" "D file1
+D file2"
+ # This creates a new branch, 1.1.4. See the code in RCS_magicrev
+ # which will notice that there is a (non-magic) 1.1.2 and thus
+ # skip that number.
+ dotest tagf-11 "${testcvs} -q tag -r 1.1 -b br file1" "T file1"
+ # Fix it with admin -n (cf admin-18, admin-26-4).
+ dotest tagf-12 "${testcvs} -q admin -nbr:1.1.2 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+ # Another variation on the file2 test would be to use two working
+ # directories so that the update -r br would need to
+ # a merge to get from 1.1.2.1 to the head of the 1.1.2 branch.
+ dotest tagf-13 "${testcvs} -q update -r br" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1\.2\.1
+retrieving revision 1\.1
+Merging differences between 1\.1\.2\.1 and 1\.1 into file1
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in file1
+C file1
+M file2"
+ # CVS is giving a conflict because we are trying to get back to
+ # 1.1.4. I'm not sure why it is a conflict rather than just
+ # "M file1".
+ dotest tagf-14 "cat file1" \
+"<<<<<<< file1
+brmod
+moremod
+[=]======
+[>]>>>>>> 1\.1"
+ echo resolve >file1
+ dotest tagf-15 "${testcvs} -q ci -m recovered" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.4\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+ # try accidentally deleting branch tag, "tag -d"
+ dotest_fail tagf-16 "${testcvs} tag -d br" \
+"${SPROG} tag: Untagging \.
+${SPROG} tag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file1,v.\.
+${SPROG} tag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file2,v.\."
+ # try accidentally deleting branch tag, "rtag -d"
+ dotest_fail tagf-17 "${testcvs} rtag -d br first-dir" \
+"${SPROG} rtag: Untagging first-dir
+${SPROG} rtag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file1,v.\.
+${SPROG} rtag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file2,v.\."
+ # try accidentally converting branch tag to non-branch tag "tag -F"
+ dotest tagf-18 "${testcvs} tag -r1.1 -F br file1" \
+"${SPROG} tag: file1: Not moving branch tag .br. from 1\.1\.4\.1 to 1\.1\."
+ # try accidentally converting branch tag to non-branch tag "rtag -F"
+ dotest tagf-19 "${testcvs} rtag -r1.1 -F br first-dir" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: first-dir/file1: Not moving branch tag .br. from 1\.1\.4\.1 to 1\.1\.
+${SPROG} rtag: first-dir/file2: Not moving branch tag .br. from 1\.1\.2\.2 to 1\.1\."
+ # create a non-branch tag
+ dotest tagf-20 "${testcvs} rtag regulartag first-dir" \
+"${SPROG} rtag: Tagging first-dir"
+ # try accidentally converting non-branch tag to branch tag (tag -F -B -b)
+ dotest tagf-21 "${testcvs} tag -F -B -b regulartag file1" \
+"${SPROG} tag: file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1\.0\.2 due to .-B. option\."
+ # try accidentally converting non-branch tag to branch rtag (rtag -F -B -b)
+ dotest tagf-22 "${testcvs} rtag -F -B -b regulartag first-dir" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: first-dir/file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.0\.6 due to .-B. option\.
+${SPROG} rtag: first-dir/file2: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.0\.4 due to .-B. option\."
+ # Try accidentally deleting non-branch: (tag -d -B)
+ dotest_fail tagf-23 "${testcvs} tag -d -B regulartag file1" \
+"${SPROG} tag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file1,v. due to .-B. option\."
+ # Try accidentally deleting non-branch: (rtag -d -B)
+ dotest_fail tagf-24 \
+ "${testcvs} rtag -d -B regulartag first-dir" \
+"${SPROG} rtag: Untagging first-dir
+${SPROG} rtag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file1,v. due to .-B. option\.
+${SPROG} rtag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file2,v. due to .-B. option\."
+
+ # the following tests (throught the next commit) keep moving the same
+ # tag back and forth between 1.1.6 & 1.1.8 in file1 and between
+ # 1.1.4 and 1.1.6 in file2 since nothing was checked in on some of
+ # these branches and CVS only tracks branches via tags unless they contain data.
+
+ # try intentionally converting non-branch tag to branch tag (tag -F -b)
+ dotest tagf-25a "${testcvs} tag -F -b regulartag file1" "T file1"
+ # try intentionally moving a branch tag to a newly created branch (tag -F -b -B)
+ dotest tagf-25b "${testcvs} tag -F -B -b -r1.1 regulartag file1" \
+"T file1"
+ # try intentionally converting mixed tags to branch tags (rtag -F -b)
+ dotest tagf-26a "${testcvs} rtag -F -b regulartag first-dir" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: first-dir/file1: Not moving branch tag .regulartag. from 1\.1 to 1\.1\.0\.8\."
+ # try intentionally converting a branch to a new branch tag (rtag -F -b -B)
+ dotest tagf-26b "${testcvs} rtag -F -B -b -r1.1 regulartag first-dir" \
+"${SPROG} rtag: Tagging first-dir"
+ # update to our new branch
+ dotest tagf-27 "${testcvs} update -r regulartag" \
+"${SPROG} update: Updating \.
+U file1
+U file2"
+ # commit some changes and see that all rev numbers look right
+ echo changes >> file1
+ echo changes >> file2
+ dotest tagf-28 "${testcvs} ci -m changes" \
+"${CPROG} commit: Examining \.
+${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+new revision: 1\.1\.8\.1; previous revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2
+new revision: 1\.1\.6\.1; previous revision: 1\.1"
+ # try intentional branch to non-branch (tag -F -B)
+ dotest tagf-29 "${testcvs} tag -F -B -r1.1 regulartag file1" \
+"T file1"
+ # try non-branch to non-branch (tag -F -B)
+ dotest tagf-29a "${testcvs} tag -F -B -r br regulartag file1" \
+"${SPROG} tag: file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1 due to .-B. option\."
+ # try mixed-branch to non-branch (rtag -F -B )
+ dotest tagf-29b "${testcvs} rtag -F -B -r br regulartag first-dir" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: first-dir/file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1 due to .-B. option\."
+ # at this point, regulartag is a regular tag within
+ # file1 and file2
+
+ # try intentional branch to non-branch (rtag -F -B)
+ dotest tagf-30 "${testcvs} rtag -F -B -r1.1 br first-dir" \
+"${SPROG} rtag: Tagging first-dir"
+ # create a branch tag so we can try to delete it.
+ dotest tagf-31 "${testcvs} rtag -b brtag first-dir" \
+"${SPROG} rtag: Tagging first-dir"
+
+ # try intentinal deletion of branch tag (tag -d -B)
+ dotest tagf-32 "${testcvs} tag -d -B brtag file1" "D file1"
+ # try intentinal deletion of branch tag (rtag -d -B)
+ dotest tagf-33 "${testcvs} rtag -d -B brtag first-dir" \
+"${SPROG} rtag: Untagging first-dir"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ tag-space)
+ # Test tags with spaces in the names.
+ #
+ # Prior to releases 1.11.18 & 1.12.10, some commands used with
+ # tags with spaces in the names could hang CVS.
+
+ # Setup; check in first-dir/file1
+ mkdir 1; cd 1
+ dotest tag-space-init-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest tag-space-init-2 "$testcvs add first-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+ cd first-dir
+ touch file1
+ dotest tag-space-init-3 "$testcvs add file1" \
+"$SPROG add: scheduling file \`file1' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+ dotest tag-space-init-4 "$testcvs -Q ci -m add"
+
+ # Reportedly, the following two tags make it past WinCVS.
+ dotest_fail tag-space-1 "$testcvs tag ' spacetag '" \
+"$SPROG \[tag aborted\]: tag \` spacetag ' must start with a letter"
+ dotest_fail tag-space-2 "$testcvs tag 'spacetag '" \
+"$SPROG \[tag aborted\]: tag \`spacetag ' has non-visible graphic characters"
+
+ if $remote; then
+ # Verify that this isn't a client check.
+ dotest tag-space-3 "$testcvs server" \
+"E $SPROG \[tag aborted\]: tag \` spacetag ' must start with a letter
+error " <<EOF
+Root $CVSROOT_DIRNAME
+UseUnchanged
+Argument --
+Argument spacetag
+Directory .
+$CVSROOT_DIRNAME/first-dir
+Entry /file1/1.1///
+Unchanged file1
+tag
+EOF
+
+ dotest tag-space-4 "$testcvs server" \
+"E $SPROG \[tag aborted\]: tag \`spacetag ' has non-visible graphic characters
+error " <<EOF
+Root $CVSROOT_DIRNAME
+UseUnchanged
+Argument --
+Argument spacetag
+Directory .
+$CVSROOT_DIRNAME/first-dir
+Entry /file1/1.1///
+Unchanged file1
+tag
+EOF
+ fi # $remote
+
+ # Any number of normal tags and branches were handled correctly.
+ dotest tag-space-5 "$testcvs -Q tag t1"
+ dotest tag-space-5b "$testcvs -Q tag t2"
+ dotest tag-space-5c "$testcvs -Q tag -b b1"
+
+ cd ../..
+ mkdir 2; cd 2
+
+ # But once a vendor branch exists, it's all over.
+ mkdir project; cd project
+ touch file1
+ dotest tag-space-init-4 \
+"$testcvs -Q import -mimport second-dir VENDOR RELEASE"
+
+ cd ..
+
+ dotest_fail tag-space-6 "$testcvs -Q co -r ' spacetag ' first-dir" \
+"$SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter"
+
+ # But when any files were imported, this test hung prior to CVS
+ # versions 1.11.18 & 1.12.10.
+ dotest_fail tag-space-7 "$testcvs -Q co -r ' spacetag ' second-dir" \
+"$SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter"
+
+ if $remote; then
+ # I based the client input in the next two tests on actual input
+ # from WinCVS 1.2.
+ dotest tag-space-8 "$testcvs server" \
+"E $SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter
+error " <<EOF
+Root $CVSROOT_DIRNAME
+Argument -P
+Argument -r
+Argument spacetag
+Argument first-dir
+Directory .
+$CVSROOT_DIRNAME
+co
+EOF
+
+ # Verify the test is not on the client side.
+ dotest tag-space-9 "$testcvs server" \
+"E $SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter
+error " <<EOF
+Root $CVSROOT_DIRNAME
+Argument -P
+Argument -r
+Argument spacetag
+Argument second-dir
+Directory .
+$CVSROOT_DIRNAME
+co
+EOF
+ fi # $remote
+
+ dotest tag-space-10 "$testcvs -Q co second-dir"
+ cd second-dir
+
+ # This test would also hang.
+ dotest_fail tag-space-11 "$testcvs -Q up -r ' spacetag '" \
+"$SPROG \[update aborted\]: tag \` spacetag ' must start with a letter"
+
+ if $remote; then
+ dotest tag-space-12 "$testcvs server" \
+"E $SPROG \[update aborted\]: tag \` spacetag ' must start with a letter
+error " <<EOF
+Root $CVSROOT_DIRNAME
+Argument -r
+Argument spacetag
+Argument -u
+Argument --
+Directory .
+$CVSROOT_DIRNAME
+Unchanged file1
+update
+EOF
+ fi # $remote
+
+ # I'm skipping tests for other commands that may have had the same
+ # problem. Hopefully, if a new issue arises, one of the above tests
+ # will catch the problem.
+
+ if $keep; then
+ echo Keeping $TESTDIR and exiting due to --keep
+ exit 0
+ fi
+
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ rcslib)
+ # Test librarification of RCS.
+ # First: test whether `cvs diff' handles $Name expansion
+ # correctly. We diff two revisions with their symbolic tags;
+ # neither tag should be expanded in the output. Also diff
+ # one revision with the working copy.
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest rcsdiff-1 "${testcvs} -q co first-dir" ''
+ cd first-dir
+ echo "I am the first foo, and my name is $""Name$." > foo.c
+ dotest rcsdiff-2 "${testcvs} add -m new-file foo.c" \
+"${SPROG} add: scheduling file .foo\.c. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest rcsdiff-3 "${testcvs} commit -m rev1 foo.c" \
+"${CVSROOT_DIRNAME}/first-dir/foo.c,v <-- foo\.c
+initial revision: 1\.1"
+ dotest rcsdiff-4 "${testcvs} tag first foo.c" "T foo\.c"
+ dotest rcsdiff-5 "${testcvs} update -p -r first foo.c" \
+"===================================================================
+Checking out foo\.c
+RCS: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
+VERS: 1\.1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+I am the first foo, and my name is \$""Name: first \$\."
+
+ echo "I am the second foo, and my name is $""Name$." > foo.c
+ dotest rcsdiff-6 "${testcvs} commit -m rev2 foo.c" \
+"${CVSROOT_DIRNAME}/first-dir/foo\.c,v <-- foo\.c
+new revision: 1\.2; previous revision: 1\.1"
+ dotest rcsdiff-7 "${testcvs} tag second foo.c" "T foo\.c"
+ dotest rcsdiff-8 "${testcvs} update -p -r second foo.c" \
+"===================================================================
+Checking out foo\.c
+RCS: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
+VERS: 1\.2
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+I am the second foo, and my name is \$""Name: second \$\."
+
+ dotest_fail rcsdiff-9 "${testcvs} diff -r first -r second" \
+"${SPROG} diff: Diffing \.
+Index: foo\.c
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+diff -r1\.1 -r1\.2
+1c1
+< I am the first foo, and my name is \$""Name: \$\.
+---
+> I am the second foo, and my name is \$""Name: \$\."
+
+ echo "I am the once and future foo, and my name is $""Name$." > foo.c
+ dotest_fail rcsdiff-10 "${testcvs} diff -r first" \
+"${SPROG} diff: Diffing \.
+Index: foo\.c
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
+retrieving revision 1\.1
+diff -r1\.1 foo\.c
+1c1
+< I am the first foo, and my name is \$""Name: \$\.
+---
+> I am the once and future foo, and my name is \$""Name\$\."
+
+ # Test handling of libdiff options. diff gets quite enough
+ # of a workout elsewhere in sanity.sh, so we assume that it's
+ # mostly working properly if it passes all the other tests.
+ # The main one we want to try is regex handling, since we are
+ # using CVS's regex matcher and not diff's.
+
+ cat >rgx.c <<EOF
+test_regex (whiz, bang)
+{
+foo;
+bar;
+baz;
+grumble;
+}
+EOF
+
+ dotest rcslib-diffrgx-1 "${testcvs} -q add -m '' rgx.c" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest rcslib-diffrgx-2 "${testcvs} -q ci -m '' rgx.c" \
+"$CVSROOT_DIRNAME/first-dir/rgx\.c,v <-- rgx\.c
+initial revision: 1\.1"
+ cat >rgx.c <<EOF
+test_regex (whiz, bang)
+{
+foo;
+bar;
+baz;
+mumble;
+}
+EOF
+ # Use dotest_fail because exit status from `cvs diff' must be 1.
+ #
+ # Incidentally test that CVS no longer splits diff arguments on
+ # spaces.
+ dotest_fail rcslib-diffrgx-3 "$testcvs diff -c -F'.* (' rgx.c" \
+"Index: rgx\.c
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/rgx\.c,v
+retrieving revision 1\.1
+diff -c -F '\.\* (' -r1\.1 rgx\.c
+\*\*\* rgx\.c ${RFCDATE} 1\.1
+--- rgx\.c ${RFCDATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* test_regex (whiz, bang)
+\*\*\* 3,7 \*\*\*\*
+ foo;
+ bar;
+ baz;
+! grumble;
+ }
+--- 3,7 ----
+ foo;
+ bar;
+ baz;
+! mumble;
+ }"
+
+ # Tests of rcsmerge/diff3. Merge operations get a good general
+ # workout elsewhere; we want to make sure that options are still
+ # handled properly. Try merging two branches with -kv, to test
+ # both -j and -k switches.
+
+ cd ..
+
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r first-dir
+
+ mkdir 1; cd 1
+ dotest rcslib-merge-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest rcslib-merge-2 "$testcvs -q add first-dir" \
+"Directory $CVSROOT_DIRNAME.*/first-dir added to the repository"
+ cd ..; rm -r 1
+
+ dotest rcslib-merge-3 "$testcvs -q co first-dir" ""
+ cd first-dir
+
+ echo '$''Revision$' > file1
+ echo '2' >> file1
+ echo '3' >> file1
+ dotest rcslib-merge-4 "${testcvs} -q add file1" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest rcslib-merge-5 "${testcvs} -q commit -m '' file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ sed -e 's/2/two/' file1 > f; mv f file1
+ dotest rcslib-merge-6 "${testcvs} -q commit -m '' file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ dotest rcslib-merge-7 "${testcvs} -q tag -b -r 1.1 patch1" "T file1"
+ dotest rcslib-merge-8 "${testcvs} -q update -r patch1" "[UP] file1"
+ dotest rcslib-merge-9 "${testcvs} -q status" \
+"===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: patch1 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest rcslib-merge-10 "cat file1" \
+'$''Revision: 1\.1 $
+2
+3'
+ sed -e 's/3/three/' file1 > f; mv f file1
+ dotest rcslib-merge-11 "${testcvs} -q commit -m '' file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ dotest rcslib-merge-12 "${testcvs} -q update -kv -j1.2" \
+"U file1
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into file1
+rcsmerge: warning: conflicts during merge"
+ dotest rcslib-merge-13 "cat file1" \
+"<<<<<<< file1
+1\.1\.2\.1
+2
+three
+[=]======
+1\.2
+two
+3
+[>]>>>>>> 1\.2"
+
+ # Test behavior of symlinks in the repository.
+ if test -n "$remotehost"; then
+ # Create the link on the remote system. This is because Cygwin's
+ # Windows support creates *.lnk files for Windows. When creating
+ # these in an SMB share from UNIX, these links won't work from the
+ # UNIX side.
+ modify_repo $CVS_RSH $remotehost "'ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v'"
+ else
+ modify_repo ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v
+ fi
+ dotest rcslib-symlink-2 "$testcvs update file2" "U file2"
+ echo "This is a change" >> file2
+ dotest rcslib-symlink-3 "$testcvs ci -m because file2" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file2
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+
+ # Switch as for rcslib-symlink-1
+ if test -n "$remotehost"; then
+ dotest rcslib-symlink-4 "$CVS_RSH $remotehost 'ls -l $CVSROOT_DIRNAME/first-dir/file2,v'" \
+".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+ else
+ dotest rcslib-symlink-4 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \
+".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+ fi
+
+ # CVS was failing to check both the symlink and the file
+ # for timestamp changes for a while. Test that.
+ rm file1
+ dotest rcslib-symlink-3a "${testcvs} -q up file1" \
+"${SPROG} update: warning: \`file1' was lost
+U file1"
+ echo "This is a change" >> file1
+ dotest rcslib-symlink-3b "${testcvs} ci -m because file1" \
+"${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.[0-9]*; previous revision: 1\.1\.2\.[0-9]*"
+ dotest rcslib-symlink-3c "${testcvs} update file2" "[UP] file2"
+
+ echo some new text >file3
+ dotest rcslib-symlink-3d "${testcvs} -Q add file3" ''
+ dotest rcslib-symlink-3e "$testcvs -Q ci -mtest file3"
+
+ rm -f ${CVSROOT_DIRNAME}/first-dir/file2,v
+ # As for rcslib-symlink-1
+ if test -n "$remotehost"; then
+ modify_repo "$CVS_RSH $remotehost 'ln -s Attic/file3,v $CVSROOT_DIRNAME/first-dir/file2,v'"
+ else
+ modify_repo ln -s Attic/file3,v $CVSROOT_DIRNAME/first-dir/file2,v
+ fi
+
+ dotest rcslib-symlink-3g "$testcvs update file2" "U file2"
+
+ # restore the link to file1 for the following tests
+ dotest rcslib-symlink-3i "$testcvs -Q rm -f file3" ''
+ dotest rcslib-symlink-3j "$testcvs -Q ci -mwhatever file3"
+ rm -f $CVSROOT_DIRNAME/first-dir/file2,v
+ rm -f $CVSROOT_DIRNAME/first-dir/Attic/file3,v
+ # As for rcslib-symlink-1
+ if test -n "$remotehost"; then
+ modify_repo "$CVS_RSH $remotehost 'ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v'"
+ else
+ modify_repo ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v
+ fi
+
+ # Test 5 reveals a problem with having symlinks in the
+ # repository. CVS will try to tag both of the files
+ # separately. After processing one, it will do the same
+ # operation to the other, which is actually the same file,
+ # so the tag will already be there. FIXME: do we bother
+ # changing operations to notice cases like this? This
+ # strikes me as a difficult problem. -Noel
+ dotest rcslib-symlink-5 "$testcvs tag the_tag" \
+"$SPROG tag: Tagging .
+T file1
+W file2 : the_tag already exists on version 1.1.2.3 : NOT MOVING tag to version 1.1.2.1"
+ # As for rcslib-symlink-1
+ if test -n "$remotehost"; then
+ dotest rcslib-symlink-6 "$CVS_RSH $remotehost 'ls -l $CVSROOT_DIRNAME/first-dir/file2,v'" \
+".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+ else
+ dotest rcslib-symlink-6 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \
+".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+ fi
+
+ # Symlinks tend to interact poorly with the Attic.
+ cd ..
+ mkdir 2; cd 2
+ dotest rcslib-symlink-7 "$testcvs -q co first-dir" \
+"U first-dir/file1
+U first-dir/file2"
+ cd first-dir
+ dotest rcslib-symlink-8 "$testcvs rm -f file2" \
+"$SPROG remove: scheduling .file2. for removal
+$SPROG remove: use .$SPROG commit. to remove this file permanently"
+ dotest rcslib-symlink-9 "$testcvs -q ci -m rm-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file2
+new revision: delete; previous revision: 1\.2"
+ # OK, why this message happens twice is relatively clear
+ # (the check_* and rtag_* calls to start_recursion).
+ # Why it happens a third time I didn't try to find out.
+ #
+ # DRP: One of the error messages disappeared while I was making
+ # proxy modifications. Until I detect a deeper issue, I'm not
+ # going to stress over it.
+ #
+ # DRP: Both messages disappear starting with glibc 2.3.3 due to a bug
+ # in the glob function which causes it to fail to return broken
+ # symlinks. I'm submitting a bug fix to glibc which will hopefully
+ # be released with glibc 2.3.6. Once it is released and versions
+ # 2.3.3-2.3.5 of glibc become uncommon, the first, empty case below
+ # should be removed again.
+ dotest rcslib-symlink-10 \
+"$testcvs -q rtag -b -r the_tag brtag first-dir" "" \
+"$SPROG rtag: could not read RCS file for first-dir/file2
+$SPROG rtag: could not read RCS file for first-dir/file2"
+
+ # Restore file1 for the next test.
+ dotest rcslib-long-symlink-init-1 "$testcvs -Q up -A"
+ dotest rcslib-long-symlink-init-2 "$testcvs -Q add file1"
+ dotest rcslib-long-symlink-init-3 "$testcvs -Q ci -mback"
+
+ cd ../.. # $TESTDIR
+
+ # CVS has a hard-coded default link path size of 127 characters.
+ # Make sure it knows how to exceed that.
+ longpath=$CVSROOT_DIRNAME
+ count=0
+ while test $count -lt 10; do
+ # 10 * 30 characters + len $CVSROOT_DIRNAME
+ count=`expr $count + 1`
+ longpath=$longpath/123456789012345678901234567890
+ modify_repo mkdir $longpath
+ done
+ modify_repo cp $CVSROOT_DIRNAME/first-dir/file1,v $longpath
+ modify_repo mkdir $CVSROOT_DIRNAME/second-dir
+
+ # Switch as for rcslib-symlink-1
+ if test -n "$remotehost"; then
+ modify_repo $CVS_RSH $remotehost \
+ 'ln -s $longpath/file1,v $CVSROOT_DIRNAME/second-dir/fileX,v'
+ else
+ modify_repo ln -s $longpath/file1,v \
+ $CVSROOT_DIRNAME/second-dir/fileX,v
+ fi
+
+ dotest rcslib-long-symlink-2 "$testcvs co second-dir" \
+"$SPROG checkout: Updating second-dir
+U second-dir/fileX"
+
+ cd second-dir
+ echo change-it >>fileX
+
+ # Writes actually cause symlinks to be resolved.
+ dotest rcslib-long-symlink-3 "$testcvs -q ci -mwrite-it" \
+"$CVSROOT_DIRNAME/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/file1,v <-- fileX
+new revision: 1\.5; previous revision: 1\.4"
+
+ dokeep
+ cd ..
+
+ # Must remove the symlink first. Samba doesn't appear to show
+ # broken symlink across the SMB share, and rm -rf by itself
+ # will remove file1,v first and leave file2,v a broken link and the
+ # rm -rf will fail since it doesn't find file2,v and it still gets
+ # directory not empty errors removing cvsroot/first-dir.
+ #
+ # I'm not sure why I need to do this on $remotehost. The rm above
+ # rcslib-symlink-3j works fine, but the next one doesn't unless run
+ # remotely under Cygwin and using a TESTDIR on a Samba share.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost \
+"rm -f $CVSROOT_DIRNAME/first-dir/file2,v $CVSROOT_DIRNAME/second-dir/fileX,v"
+ fi
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir \
+ $CVSROOT_DIRNAME/123456789012345678901234567890
+ rm -r first-dir second-dir 2
+ ;;
+
+
+
+ multibranch)
+ # Test the ability to have several branchpoints coming off the
+ # same revision.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest multibranch-1 "${testcvs} -q co first-dir" ''
+ cd first-dir
+ echo 1:trunk-1 >file1
+ dotest multibranch-2 "${testcvs} add file1" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest_lit multibranch-3 "${testcvs} -q ci -m add-it" <<HERE
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1.1
+HERE
+ dotest multibranch-4 "${testcvs} tag -b br1" \
+"${SPROG} tag: Tagging \.
+T file1"
+ dotest multibranch-5 "${testcvs} tag -b br2" \
+"${SPROG} tag: Tagging \.
+T file1"
+ dotest multibranch-6 "${testcvs} -q update -r br1" ''
+ echo on-br1 >file1
+ dotest multibranch-7 "${testcvs} -q ci -m modify-on-br1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ dotest multibranch-8 "${testcvs} -q update -r br2" '[UP] file1'
+ echo br2 adds a line >>file1
+ dotest multibranch-9 "${testcvs} -q ci -m modify-on-br2" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.4\.1; previous revision: 1\.1"
+ dotest multibranch-10 "${testcvs} -q update -r br1" '[UP] file1'
+ dotest multibranch-11 "cat file1" 'on-br1'
+ dotest multibranch-12 "${testcvs} -q update -r br2" '[UP] file1'
+ dotest multibranch-13 "cat file1" '1:trunk-1
+br2 adds a line'
+
+ dotest multibranch-14 "${testcvs} log file1" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ br2: 1\.1\.0\.4
+ br1: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2; 1\.1\.4;
+add-it
+----------------------------
+revision 1\.1\.4\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify-on-br2
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+modify-on-br1
+============================================================================="
+
+ dokeep
+ cd ..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r first-dir
+ ;;
+
+
+
+ import) # test death after import
+ # Tests of "cvs import":
+ # basic2
+ # rdiff -- imports with keywords
+ # import -- more tests of imports with keywords
+ # importb -- -b option.
+ # importc -- bunch o' files in bunch o' directories
+ # importX -- -X option.
+ # importX2 -- CVSROOT/config ImportNewFilesToVendorBranchOnly
+ # flag
+ # modules3
+ # mflag -- various -m messages
+ # ignore -- import and cvsignore
+ # binwrap -- import and -k wrappers
+ # info -- imports which are rejected by verifymsg
+ # head -- intended to test vendor branches and HEAD,
+ # although it doesn't really do it yet.
+ # import-CVS -- refuse to import directories named "CVS".
+ # import-quirks -- short tests of import quirks.
+
+ # import
+ mkdir import-dir ; cd import-dir
+
+ for i in 1 2 3 4 ; do
+ echo imported file"$i" > imported-f"$i"
+ done
+
+ # This directory should be on the default ignore list,
+ # so it shouldn't get imported.
+ mkdir RCS
+ echo ignore.me >RCS/ignore.me
+
+ echo 'import should not expand $''Id$' >>imported-f2
+ cp imported-f2 ../imported-f2-orig.tmp
+
+ dotest_sort import-96 \
+"${testcvs} import -m first-import first-dir vendor-branch junk-1_0" \
+"
+
+I first-dir/RCS
+N first-dir/imported-f1
+N first-dir/imported-f2
+N first-dir/imported-f3
+N first-dir/imported-f4
+No conflicts created by this import"
+
+ dotest import-96.5 "cmp ../imported-f2-orig.tmp imported-f2" ''
+
+ cd ..
+
+ # co
+ dotest import-97 "${testcvs} -q co first-dir" \
+"U first-dir/imported-f1
+U first-dir/imported-f2
+U first-dir/imported-f3
+U first-dir/imported-f4"
+
+ cd first-dir
+
+ for i in 1 2 3 4 ; do
+ dotest import-98-$i "test -f imported-f$i" ''
+ done
+ dotest_fail import-98.5 "test -d RCS" ''
+
+ # remove
+ rm imported-f1
+ dotest import-99 "${testcvs} rm imported-f1" \
+"${SPROG}"' remove: scheduling `imported-f1'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
+
+ # change
+ echo local-change >> imported-f2
+
+ # commit
+ dotest import-100 "${testcvs} ci -m local-changes" \
+"${CPROG} commit: Examining .
+${CVSROOT_DIRNAME}/first-dir/imported-f1,v <-- imported-f1
+new revision: delete; previous revision: 1\.1\.1\.1
+${CVSROOT_DIRNAME}/first-dir/imported-f2,v <-- imported-f2
+new revision: 1\.2; previous revision: 1\.1"
+
+ # log
+ dotest import-101 "${testcvs} log imported-f1" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/imported-f1,v
+Working file: imported-f1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ junk-1_0: 1\.1\.1\.1
+ vendor-branch: 1\.1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: dead; lines: ${PLUS}0 -0; commitid: ${commitid};
+local-changes
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+first-import
+============================================================================="
+
+ # update into the vendor branch.
+ dotest import-102 "${testcvs} update -rvendor-branch" \
+"${SPROG} update: Updating .
+[UP] imported-f1
+[UP] imported-f2"
+
+ # remove file4 on the vendor branch
+ rm imported-f4
+ dotest import-103 "${testcvs} rm imported-f4" \
+"${SPROG}"' remove: scheduling `imported-f4'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
+
+ # commit
+ dotest import-104 \
+"${testcvs} ci -m vendor-removed imported-f4" \
+"${CVSROOT_DIRNAME}/first-dir/imported-f4,v <-- imported-f4
+new revision: delete; previous revision: 1\.1\.1\.1"
+
+ # update to main line
+ dotest import-105 "${testcvs} -q update -A" \
+"${SPROG} update: \`imported-f1' is no longer in the repository
+[UP] imported-f2"
+
+ # second import - file4 deliberately unchanged
+ cd ../import-dir
+ for i in 1 2 3 ; do
+ echo rev 2 of file $i >> imported-f"$i"
+ done
+ cp imported-f2 ../imported-f2-orig.tmp
+
+ dotest_sort import-106 \
+"${testcvs} import -m second-import first-dir vendor-branch junk-2_0" \
+"
+
+
+ ${CPROG} checkout -j<prev_rel_tag> -jjunk-2_0 first-dir
+2 conflicts created by this import.
+C first-dir/imported-f1
+C first-dir/imported-f2
+I first-dir/RCS
+U first-dir/imported-f3
+U first-dir/imported-f4
+Use the following command to help the merge:"
+
+ dotest import-106.5 "cmp ../imported-f2-orig.tmp imported-f2" \
+''
+
+ cd ..
+
+ rm imported-f2-orig.tmp
+
+ # co
+ dotest import-107 "${testcvs} co first-dir" \
+"${SPROG} checkout: Updating first-dir
+[UP] first-dir/imported-f3
+[UP] first-dir/imported-f4"
+
+ cd first-dir
+
+ dotest_fail import-108 "test -f imported-f1" ''
+
+ for i in 2 3 ; do
+ dotest import-109-$i "test -f imported-f$i" ''
+ done
+
+ # check vendor branch for file4
+ dotest import-110 "${testcvs} -q update -rvendor-branch" \
+"[UP] imported-f1
+[UP] imported-f2"
+
+ dotest import-111 "test -f imported-f4" ''
+
+ # update to main line
+ dotest import-112 "${testcvs} -q update -A" \
+"${SPROG} update: \`imported-f1' is no longer in the repository
+[UP] imported-f2"
+
+ cd ..
+
+ dotest import-113 \
+"${testcvs} -q co -jjunk-1_0 -jjunk-2_0 first-dir" \
+"${SPROG} checkout: file first-dir/imported-f1 does not exist, but is present in revision junk-2_0
+RCS file: ${CVSROOT_DIRNAME}/first-dir/imported-f2,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.2
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into imported-f2
+rcsmerge: warning: conflicts during merge
+first-dir/imported-f3 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.2
+first-dir/imported-f4 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.3"
+
+ cd first-dir
+
+ dotest_fail import-114 "test -f imported-f1" ''
+
+ for i in 2 3 ; do
+ dotest import-115-$i "test -f imported-f$i" ''
+ done
+
+ dotest import-116 'cat imported-f2' \
+'imported file2
+[<]<<<<<< imported-f2
+import should not expand \$''Id: imported-f2,v 1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$
+local-change
+[=]======
+import should not expand \$''Id: imported-f2,v 1\.1\.1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$
+rev 2 of file 2
+[>]>>>>>> 1\.1\.1\.2'
+
+ dokeep
+ cd ..
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r import-dir
+ ;;
+
+
+
+ importb)
+ # More cvs import tests, especially -b option.
+
+ # OK, first we get some sources from the NetMunger project, and
+ # import them into the 1.1.1 vendor branch.
+ mkdir imp-dir
+ cd imp-dir
+ echo 'OpenMunger sources' >file1
+ echo 'OpenMunger sources' >file2
+ dotest_sort importb-1 \
+"${testcvs} import -m add first-dir openmunger openmunger-1_0" \
+"
+
+N first-dir/file1
+N first-dir/file2
+No conflicts created by this import"
+ cd ..
+ rm -r imp-dir
+
+ # Now we put the sources we get from FreeMunger into 1.1.3
+ mkdir imp-dir
+ cd imp-dir
+ echo 'FreeMunger sources' >file1
+ echo 'FreeMunger sources' >file2
+ # Not completely sure how the conflict detection is supposed to
+ # be working here (haven't really thought about it).
+ # We use an explicit -d option to test that it is reflected
+ # in the suggested checkout.
+ dotest_sort importb-2 \
+"$testcvs -d '$CVSROOT' import -m add -b 1.1.3 \
+ first-dir freemunger freemunger-1_0" \
+"
+
+
+ ${CPROG} -d ${CVSROOT} checkout -j<prev_rel_tag> -jfreemunger-1_0 first-dir
+2 conflicts created by this import.
+C first-dir/file1
+C first-dir/file2
+Use the following command to help the merge:"
+ cd ..
+ rm -r imp-dir
+
+ # Now a test of main branch import (into second-dir, not first-dir).
+ mkdir imp-dir
+ cd imp-dir
+ echo 'my own stuff' >mine1.c
+ echo 'my own stuff' >mine2.c
+ dotest_fail importb-3 \
+"${testcvs} import -m add -b 1 second-dir dummy really_dumb_y" \
+"$CPROG \[import aborted\]: Only numeric branch specifications with two dots are
+supported by import, not \`1'\. For example: \`1\.1\.1'\."
+ : when we implement main-branch import, should be \
+"N second-dir/mine1\.c
+N second-dir/mine2\.c
+
+No conflicts created by this import"
+ cd ..
+ rm -r imp-dir
+
+ mkdir 1
+ cd 1
+ # when we implement main branch import, will want to
+ # add "second-dir" here.
+ dotest importb-4 "${testcvs} -q co first-dir" \
+"U first-dir/file1
+U first-dir/file2"
+ cd first-dir
+ dotest importb-5 "${testcvs} -q log file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch: 1\.1\.1
+locks: strict
+access list:
+symbolic names:
+ freemunger-1_0: 1\.1\.3\.1
+ freemunger: 1\.1\.3
+ openmunger-1_0: 1\.1\.1\.1
+ openmunger: 1\.1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.1; 1\.1\.3;
+Initial revision
+----------------------------
+revision 1\.1\.3\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+add
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+add
+============================================================================="
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ importc)
+ # Test importing a bunch o' files in a bunch o' directories.
+ # Also the -d option.
+
+ # Set a predictable time zone for these tests.
+ save_TZ=$TZ
+ TZ=UTC0; export TZ
+
+ mkdir 1; cd 1
+ mkdir adir bdir cdir
+ mkdir adir/sub1 adir/sub2
+ mkdir adir/sub1/ssdir
+ mkdir bdir/subdir
+ touch adir/sub1/file1 adir/sub2/file2 adir/sub1/ssdir/ssfile
+ touch -t ${TOUCH1971} bdir/subdir/file1
+ touch -t ${TOUCH2034} cdir/cfile
+ dotest_sort importc-1 \
+"${testcvs} import -d -m import-it first-dir vendor release" \
+"
+
+N first-dir/adir/sub1/file1
+N first-dir/adir/sub1/ssdir/ssfile
+N first-dir/adir/sub2/file2
+N first-dir/bdir/subdir/file1
+N first-dir/cdir/cfile
+No conflicts created by this import
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub1
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub1/ssdir
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub2
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/bdir
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/bdir/subdir
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/cdir"
+ cd ..
+ mkdir 2; cd 2
+ dotest importc-2 "${testcvs} -q co first-dir" \
+"U first-dir/adir/sub1/file1
+U first-dir/adir/sub1/ssdir/ssfile
+U first-dir/adir/sub2/file2
+U first-dir/bdir/subdir/file1
+U first-dir/cdir/cfile"
+ cd first-dir
+ dotest importc-3 "${testcvs} update adir/sub1" \
+"${SPROG} update: Updating adir/sub1
+${SPROG} update: Updating adir/sub1/ssdir"
+ dotest importc-4 "${testcvs} update adir/sub1 bdir/subdir" \
+"${SPROG} update: Updating adir/sub1
+${SPROG} update: Updating adir/sub1/ssdir
+${SPROG} update: Updating bdir/subdir"
+
+ echo modify >>cdir/cfile
+ dotest importc-5 \
+"${testcvs} -q rtag -b -r release wip_test first-dir" ""
+ dotest importc-6 "${testcvs} -q update -r wip_test" "M cdir/cfile"
+
+ # This used to fail in local mode
+ dotest importc-7 "${testcvs} -q ci -m modify -r wip_test" \
+"$CVSROOT_DIRNAME/first-dir/cdir/cfile,v <-- cdir/cfile
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1"
+
+ # TODO: should also be testing "import -d" when we update
+ # an existing file.
+ dotest importc-8 "${testcvs} -q log cdir/cfile" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/cdir/cfile,v
+Working file: cdir/cfile
+head: 1\.1
+branch: 1\.1\.1
+locks: strict
+access list:
+symbolic names:
+ wip_test: 1\.1\.1\.1\.0\.2
+ release: 1\.1\.1\.1
+ vendor: 1\.1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE2034}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE2034}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+branches: 1\.1\.1\.1\.2;
+import-it
+----------------------------
+revision 1\.1\.1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify
+============================================================================="
+
+ dotest importc-9 "${testcvs} -q log bdir/subdir/file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/bdir/subdir/file1,v
+Working file: bdir/subdir/file1
+head: 1\.1
+branch: 1\.1\.1
+locks: strict
+access list:
+symbolic names:
+ wip_test: 1\.1\.1\.1\.0\.2
+ release: 1\.1\.1\.1
+ vendor: 1\.1\.1
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE1971}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE1971}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+import-it
+============================================================================="
+ cd ..
+
+ # Now tests of absolute pathnames and .. as repository directory.
+ cd ../1
+ dotest_fail importc-10 \
+"${testcvs} import -m imp ../other vendor release2" \
+"${CPROG} \[import aborted\]: directory \.\./other not relative within the repository"
+ dotest_fail importc-11 \
+"${testcvs} import -m imp ${TESTDIR}/other vendor release3" \
+"${CPROG} \[import aborted\]: directory ${TESTDIR}/other not relative within the repository"
+ dotest_fail importc-12 "test -d ${TESTDIR}/other" ""
+
+ dokeep
+ TZ=$save_TZ
+ cd ..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ importX)
+ # More cvs import tests, especially -X option.
+
+ # OK, first we get some sources from the Munger version 0.9,
+ # and import them into the 1.1.1 vendor branch (w/o -X). (This
+ # will be used to test subsequent imports of the same file
+ # with -X.)
+ mkdir imp-dir
+ cd imp-dir
+ echo 'Munger sources 0.9' >file0
+ dotest_sort importX-1 \
+"${testcvs} import -m add first-dir munger munger-0_9" \
+"
+
+N first-dir/file0
+No conflicts created by this import"
+ cd ..
+ rm -r imp-dir
+
+ # Now we put the sources we get from Munger version 1.0 on
+ # to the 1.1.1 vendor branch using -X. (This imports a new
+ # version of file0, and imports all-new files file1 and file2.)
+ mkdir imp-dir
+ cd imp-dir
+ echo 'Munger sources' >file0
+ echo 'Munger sources' >file1
+ echo 'Munger sources' >file2
+ dotest_sort importX-2 \
+"${testcvs} import -X -m add first-dir munger munger-1_0" \
+"
+
+
+ ${CPROG} checkout -j<prev_rel_tag> -jmunger-1_0 first-dir
+N first-dir/file1
+N first-dir/file2
+No conflicts created by this import.
+U first-dir/file0
+Use the following command to help the merge:"
+ cd ..
+ rm -r imp-dir
+
+ # Now we put the sources we get from Munger version 1.1 on
+ # to the 1.1.1 vendor branch using -X. (This imports unchanged
+ # versions of file0 and file2, a changed version of file1, and
+ # an all-new file3.)
+ mkdir imp-dir
+ cd imp-dir
+ echo 'Munger sources' >file0
+ echo 'Munger sources 1.1' >file1
+ echo 'Munger sources' >file2
+ echo 'Munger sources 1.1' >file3
+ dotest_sort importX-3 \
+"$testcvs -d '$CVSROOT' import -X -m add first-dir munger munger-1_1" \
+"
+
+
+ ${CPROG} -d ${CVSROOT} checkout -j<prev_rel_tag> -jmunger-1_1 first-dir
+1 conflicts created by this import.
+C first-dir/file1
+N first-dir/file3
+U first-dir/file0
+U first-dir/file2
+Use the following command to help the merge:"
+ cd ..
+ rm -r imp-dir
+
+ mkdir 1
+ cd 1
+ # only file0 should be checked out
+ dotest importX-4 "${testcvs} -q co first-dir" \
+"U first-dir/file0"
+ cd first-dir
+
+ dotest importX-5 "${testcvs} -q log file0" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file0,v
+Working file: file0
+head: 1\.1
+branch: 1\.1\.1
+locks: strict
+access list:
+symbolic names:
+ munger-1_1: 1\.1\.1\.2
+ munger-1_0: 1\.1\.1\.2
+ munger-0_9: 1\.1\.1\.1
+ munger: 1\.1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+add
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+add
+============================================================================="
+
+ dotest importX-6 "${testcvs} -q log file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+Working file: file1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ munger-1_1: 1\.1\.1\.2
+ munger-1_0: 1\.1\.1\.1
+ munger: 1\.1\.1
+keyword substitution: kv
+total revisions: 4; selected revisions: 4
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: dead; lines: ${PLUS}0 -0; commitid: ${commitid};
+Revision 1\.1 was added on the vendor branch\.
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+add
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+add
+============================================================================="
+
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+
+
+ importX2)
+ # Test ImportNewFilesToVendorBranchOnly config file option.
+
+ # On Windows, we can't check out CVSROOT, because the case
+ # insensitivity means that this conflicts with cvsroot.
+ mkdir wnt
+ cd wnt
+
+ dotest importX2-1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}"
+ cd CVSROOT
+ echo "ImportNewFilesToVendorBranchOnly=yes" >> config
+
+ dotest importX2-2 "$testcvs -q ci -m force-cvs-import-X" \
+"$TESTDIR/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ../..
+
+ # Import a sources file, but do NOT specify -X. The new file
+ # should be killed, anyway (because of the config option).
+ mkdir imp-dir
+ cd imp-dir
+ echo 'source' >file1
+ dotest_sort importX2-3 \
+"${testcvs} import -m add first-dir source source-1_0" \
+"
+
+
+ ${CPROG} checkout -j<prev_rel_tag> -jsource-1_0 first-dir
+N first-dir/file1
+No conflicts created by this import.
+Use the following command to help the merge:"
+ cd ..
+ rm -r imp-dir
+
+ mkdir 1
+ cd 1
+ # **nothing** should be checked out**
+ dotest importX2-4 "${testcvs} -q co first-dir" ""
+
+ cd first-dir
+ dotest importX2-5 "${testcvs} -q log file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+Working file: file1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ source-1_0: 1\.1\.1\.1
+ source: 1\.1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: dead; lines: ${PLUS}0 -0; commitid: ${commitid};
+Revision 1\.1 was added on the vendor branch\.
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+add
+============================================================================="
+
+ dokeep
+ cd ../..
+ restore_adm
+ rm -r 1
+ rm -r wnt
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ import-CVS)
+ mkdir import-CVS
+ cd import-CVS
+ touch file1 file2 file3
+ dotest_fail import-CVS-1 "$testcvs import CVS vtag rtag" \
+"$CPROG import: The word \`CVS' is reserved by CVS and may not be used
+$CPROG \[import aborted\]: as a directory in a path or as a file name\."
+ mkdir sdir
+ mkdir sdir/CVS
+ touch sdir/CVS/file4 sdir/CVS/file5 sdir/file6 sdir/file7
+ # Calling the imported directory import-CVS is dual purpose in the
+ # following test. It makes sure the path test which matched above
+ # wasn't too strict.
+ dotest_sort import-CVS-2 \
+"$testcvs import -I! -mimport import-CVS vtag rtag" \
+"
+
+I import-CVS/sdir/CVS
+N import-CVS/file1
+N import-CVS/file2
+N import-CVS/file3
+N import-CVS/sdir/file6
+N import-CVS/sdir/file7
+No conflicts created by this import
+$SPROG import: Importing $CVSROOT_DIRNAME/import-CVS/sdir"
+
+ dokeep
+ cd ..
+ rm -r import-CVS
+ modify_repo rm -rf $CVSROOT_DIRNAME/import-CVS
+ ;;
+
+
+
+ import-quirks)
+ # Short tests of quirky import behavior.
+ #
+ # For a list of other import tests with short descriptions, see the
+ # comment header of the "import" test.
+ mkdir import-quirks
+ cd import-quirks
+ touch file1 file2 file3
+
+ # CVS prior to 1.11.18 and 1.12.10 used to happily import to
+ # "branch 1.1", creating RCS archives with revisions like,
+ # "1.1..1". That double-dot is *not* a typo.
+ dotest_fail import-quirks-1 \
+"$testcvs import -b1.1. -mbad-bad-bad import-quirks VB RT" \
+"$CPROG \[import aborted\]: Only numeric branch specifications with two dots are
+supported by import, not \`1\.1\.'\. For example: \`1\.1\.1'\."
+
+ dotest_fail import-quirks-2 \
+"$testcvs import -b1.1.1.. -mbad-bad-bad import-quirks VB RT" \
+"$CPROG \[import aborted\]: Only numeric branch specifications with two dots are
+supported by import, not \`1\.1\.1\.\.'\. For example: \`1\.1\.1'\."
+
+ # Try a few odd numbers. This is hardly comprehensive.
+ dotest_sort import-quirks-2 \
+"$testcvs import -b10.10.101 -mthis-ones-ok import-quirks-2 VB RT" \
+"
+
+N import-quirks-2/file1
+N import-quirks-2/file2
+N import-quirks-2/file3
+No conflicts created by this import"
+
+ dotest_sort import-quirks-3 \
+"$testcvs import -b2345678901.2345678901.2345678901 -mthis-ones-ok import-quirks-3 VB RT" \
+"
+
+N import-quirks-3/file1
+N import-quirks-3/file2
+N import-quirks-3/file3
+No conflicts created by this import"
+
+ dotest_sort import-quirks-4 \
+"$testcvs import -b1.1.2 -mthis-ones-ok import-quirks-4 VB RT" \
+"
+
+N import-quirks-4/file1
+N import-quirks-4/file2
+N import-quirks-4/file3
+No conflicts created by this import"
+
+ dokeep
+ cd ..
+ rm -r import-quirks
+ rm -rf $CVSROOT_DIRNAME/import-quirks-2 \
+ $CVSROOT_DIRNAME/import-quirks-3 \
+ $CVSROOT_DIRNAME/import-quirks-4
+ ;;
+
+
+
+ import-after-initial)
+ # Properly handle the case in which the first version of a
+ # file is created by a regular cvs add and commit, and there
+ # is a subsequent cvs import of the same file. cvs update with
+ # a date tag must resort to searching the vendor branch only if
+ # the initial version of the file was created at the same time
+ # as the initial version on the vendor branch.
+
+ mkdir 1; cd 1
+ module=x
+
+ echo > unused-file
+
+ # Create the module.
+ dotest import-after-initial-1 \
+ "$testcvs -Q import -m. $module X Y" ''
+
+ file=m
+ # Check it out and add a file.
+ dotest import-after-initial-2 "$testcvs -Q co $module" ''
+ cd $module
+ echo original > $file
+ dotest import-after-initial-3 "${testcvs} -Q add $file" ""
+ dotest import-after-initial-4 "$testcvs -Q ci -m. $file"
+
+ # Delay a little so the following import isn't done in the same
+ # second as the preceding commit.
+ sleep 2
+
+ # Do the first import of $file *after* $file already has an
+ # initial version.
+ mkdir sub
+ cd sub
+ echo newer-via-import > $file
+ dotest import-after-initial-5 \
+ "$testcvs -Q import -m. $module X Y2" ''
+ cd ..
+
+ # Sleep a second so we're sure to be after the second of the import.
+ sleep 1
+
+ dotest import-after-initial-6 \
+ "$testcvs -Q update -p -D now $file" 'original'
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ branch-after-import)
+ # Test branching after an import via both cvs tag -b and
+ # cvs add to verify that the HEAD remains at 1.1.1.1
+ # This was a FreeBSD bug documented at the URL:
+ # http://www.freebsd.org/cgi/query-pr.cgi?pr=4033
+
+ mkdir branch-after-import
+ cd branch-after-import
+
+ # OK, first we get some sources from the NetMunger project,
+ # and import them into the 1.1.1 vendor branch.
+ mkdir imp-dir
+ cd imp-dir
+ echo 'OpenMunger sources' >file1
+ echo 'OpenMunger sources' >file2
+ dotest_sort branch-after-import-1 \
+"${testcvs} import -m add first-dir openmunger openmunger-1_0" \
+'
+
+N first-dir/file1
+N first-dir/file2
+No conflicts created by this import'
+ cd ..
+
+ # Next checkout the new module
+ dotest branch-after-import-2 \
+"${testcvs} -q co first-dir" \
+'U first-dir/file1
+U first-dir/file2'
+ cd first-dir
+ # Branch tag the file1 and cvs add file2,
+ # the branch should remain the same in both cases
+ # such that a new import will not require a conflict
+ # resolution.
+ dotest branch-after-import-3 \
+"${testcvs} tag -b TESTTOTRON file1" \
+'T file1'
+ dotest branch-after-import-4 \
+"${testcvs} -q update -r TESTTOTRON" \
+"${SPROG} update: \`file2' is no longer in the repository"
+
+ cp ../imp-dir/file2 .
+ dotest branch-after-import-5 \
+"${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition on branch .TESTTOTRON.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ dotest branch-after-import-6 \
+"$testcvs commit -m cvs-add file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.1\.1\.2\.2; previous revision: 1\.1\.1\.1\.2\.1"
+
+ dokeep
+ cd ../..
+ rm -r branch-after-import
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ join)
+ # Test doing joins which involve adding and removing files.
+ # Variety of scenarios (see list below), in the context of:
+ # * merge changes from T1 to T2 into the main line
+ # * merge changes from branch 'branch' into the main line
+ # * merge changes from branch 'branch' into branch 'br2'.
+ # See also binfile2, which does similar things with binary files.
+ # See also join2, which tests joining (and update -A) on only
+ # a single file, rather than a directory.
+ # See also rmadd2, which tests -j cases not involving branches
+ # (e.g. undoing a commit)
+ # See also join3, which tests some cases involving the greatest
+ # common ancestor. Here is a list of tests according to branch
+ # topology:
+ #
+ # --->bp---->trunk too many to mention
+ # \----->branch
+ #
+ # /----->branch1
+ # --->bp---->trunk multibranch, multibranch2
+ # \----->branch2
+ #
+ # --->bp1----->bp2---->trunk join3
+ # \->br1 \->br2
+ #
+ # --->bp1----->trunk
+ # \----bp2---->branch branches
+ # \------>branch-of-branch
+
+ # We check merging changes from T1 to T2 into the main line.
+ # Here are the interesting cases I can think of:
+ # 1) File added between T1 and T2, not on main line.
+ # File should be marked for addition.
+ # 2) File added between T1 and T2, also added on main line.
+ # Conflict.
+ # 3) File removed between T1 and T2, unchanged on main line.
+ # File should be marked for removal.
+ # 4) File removed between T1 and T2, modified on main line.
+ # If mod checked in, file should be marked for removal.
+ # If mod still in working directory, conflict.
+ # 5) File removed between T1 and T2, was never on main line.
+ # Nothing should happen.
+ # 6) File removed between T1 and T2, also removed on main line.
+ # Nothing should happen.
+ # 7) File not added between T1 and T2, added on main line.
+ # Nothing should happen.
+ # 8) File not modified between T1 and T2, removed on main line.
+ # Nothing should happen.
+ # 9) File modified between T1 and T2, removed on main line.
+ # Conflict.
+ # 10) File was never on branch, removed on main line.
+ # Nothing should happen.
+
+ # We also check merging changes from a branch into the main
+ # line. Here are the interesting cases:
+ # 1) File added on branch, not on main line.
+ # File should be marked for addition.
+ # 2) File added on branch, also added on main line.
+ # Conflict.
+ # 3) File removed on branch, unchanged on main line.
+ # File should be marked for removal.
+ # 4) File removed on branch, modified on main line.
+ # Conflict.
+ # 5) File removed on branch, was never on main line.
+ # Nothing should happen.
+ # 6) File removed on branch, also removed on main line.
+ # Nothing should happen.
+ # 7) File added on main line, not added on branch.
+ # Nothing should happen.
+ # 8) File removed on main line, not modified on branch.
+ # Nothing should happen.
+ # 9) File modified on branch, removed on main line.
+ # Conflict.
+ # 10) File was never on branch, removed on main line.
+ # Nothing should happen.
+
+ # In the tests below, fileN represents case N in the above
+ # lists.
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1
+ cd 1
+ dotest join-1 "$testcvs -q co first-dir"
+
+ cd first-dir
+
+ # Add two files.
+ echo 'first revision of file3' > file3
+ echo 'first revision of file4' > file4
+ echo 'first revision of file6' > file6
+ echo 'first revision of file8' > file8
+ echo 'first revision of file9' > file9
+ dotest join-2 "${testcvs} add file3 file4 file6 file8 file9" \
+"${SPROG}"' add: scheduling file `file3'\'' for addition
+'"${SPROG}"' add: scheduling file `file4'\'' for addition
+'"${SPROG}"' add: scheduling file `file6'\'' for addition
+'"${SPROG}"' add: scheduling file `file8'\'' for addition
+'"${SPROG}"' add: scheduling file `file9'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+
+ dotest join-3 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file6,v <-- file6
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file8,v <-- file8
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file9,v <-- file9
+initial revision: 1\.1"
+
+ # Make a branch.
+ dotest join-4 "${testcvs} -q tag -b branch ." \
+'T file3
+T file4
+T file6
+T file8
+T file9'
+
+ # Add file2, file7, and file10, modify file4, and remove
+ # file6, file8, and file9.
+ echo 'first revision of file2' > file2
+ echo 'second revision of file4' > file4
+ echo 'first revision of file7' > file7
+ rm file6 file8 file9
+ echo 'first revision of file10' > file10
+ dotest join-5 "${testcvs} add file2 file7 file10" \
+"${SPROG}"' add: scheduling file `file2'\'' for addition
+'"${SPROG}"' add: scheduling file `file7'\'' for addition
+'"${SPROG}"' add: scheduling file `file10'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+ dotest join-6 "${testcvs} rm file6 file8 file9" \
+"${SPROG}"' remove: scheduling `file6'\'' for removal
+'"${SPROG}"' remove: scheduling `file8'\'' for removal
+'"${SPROG}"' remove: scheduling `file9'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'
+ dotest join-7 "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/file10,v <-- file10
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file6,v <-- file6
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file7,v <-- file7
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file8,v <-- file8
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file9,v <-- file9
+new revision: delete; previous revision: 1\.1"
+
+ # Remove file10
+ dotest join-7a "${testcvs} rm -f file10" \
+"${SPROG}"' remove: scheduling `file10'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
+ dotest join-7b "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/file10,v <-- file10
+new revision: delete; previous revision: 1\.1"
+
+ # Check out the branch.
+ cd ../..
+ mkdir 2
+ cd 2
+ dotest join-8 "${testcvs} -q co -r branch first-dir" \
+'U first-dir/file3
+U first-dir/file4
+U first-dir/file6
+U first-dir/file8
+U first-dir/file9'
+
+ cd first-dir
+
+ # Modify the files on the branch, so that T1 is not an
+ # ancestor of the main line, and add file5
+ echo 'first branch revision of file3' > file3
+ echo 'first branch revision of file4' > file4
+ echo 'first branch revision of file5' > file5
+ echo 'first branch revision of file6' > file6
+ echo 'first branch revision of file9' > file9
+ dotest join-9 "${testcvs} add file5" \
+"${SPROG}"' add: scheduling file `file5'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest join-10 "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file5,v <-- file5
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file6,v <-- file6
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file9,v <-- file9
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # Tag the current revisions on the branch.
+ dotest join-11 "${testcvs} -q tag T1 ." \
+'T file3
+T file4
+T file5
+T file6
+T file8
+T file9'
+
+ # Add file1 and file2, modify file9, and remove the other files.
+ echo 'first branch revision of file1' > file1
+ echo 'first branch revision of file2' > file2
+ echo 'second branch revision of file9' > file9
+ rm file3 file4 file5 file6
+ dotest join-12 "${testcvs} add file1 file2" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+ dotest join-13 "${testcvs} rm file3 file4 file5 file6" \
+"${SPROG}"' remove: scheduling `file3'\'' for removal
+'"${SPROG}"' remove: scheduling `file4'\'' for removal
+'"${SPROG}"' remove: scheduling `file5'\'' for removal
+'"${SPROG}"' remove: scheduling `file6'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'
+ dotest join-14 "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/Attic/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file5,v <-- file5
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file6,v <-- file6
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file9,v <-- file9
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+
+ # Tag the current revisions on the branch.
+ dotest join-15 "${testcvs} -q tag T2 ." \
+'T file1
+T file2
+T file8
+T file9'
+
+ # Do a checkout with a merge.
+ cd ../..
+ mkdir 3
+ cd 3
+ dotest join-16 "${testcvs} -q co -jT1 -jT2 first-dir" \
+"U first-dir/file1
+U first-dir/file2
+${SPROG} checkout: file first-dir/file2 exists, but has been added in revision T2
+U first-dir/file3
+${SPROG} checkout: scheduling \`first-dir/file3' for removal
+U first-dir/file4
+${SPROG} checkout: scheduling \`first-dir/file4' for removal
+U first-dir/file7
+${SPROG} checkout: file first-dir/file9 does not exist, but is present in revision T2"
+
+ # Verify that the right changes have been scheduled.
+ cd first-dir
+ dotest join-17 "${testcvs} -q update" \
+'A file1
+R file3
+R file4'
+
+ # Modify file4 locally, and do an update with a merge.
+ cd ../../1/first-dir
+ echo 'third revision of file4' > file4
+ dotest join-18 "${testcvs} -q update -jT1 -jT2 ." \
+"U file1
+$SPROG update: file file2 exists, but has been added in revision T2
+$SPROG update: scheduling \`file3' for removal
+M file4
+$SPROG update: file file4 is locally modified, but has been removed in revision T2
+$SPROG update: file file9 does not exist, but is present in revision T2"
+
+ # Verify that the right changes have been scheduled.
+ dotest join-19 "${testcvs} -q update" \
+'A file1
+R file3
+M file4'
+
+ # Do a checkout with a merge from a single revision.
+
+ # FIXME: CVS currently gets this wrong. file2 has been
+ # added on both the branch and the main line, and so should
+ # be regarded as a conflict. However, given the way that
+ # CVS sets up the RCS file, there is no way to distinguish
+ # this case from the case of file2 having existed before the
+ # branch was made. This could be fixed by reserving
+ # a revision somewhere, perhaps 1.1, as an always dead
+ # revision which can be used as the source for files added
+ # on branches.
+ cd ../../3
+ rm -r first-dir
+ dotest join-20 "${testcvs} -q co -jbranch first-dir" \
+"U first-dir/file1
+U first-dir/file2
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.2
+Merging differences between 1\.1 and 1\.1\.2\.2 into file2
+U first-dir/file3
+${SPROG} checkout: scheduling \`first-dir/file3' for removal
+U first-dir/file4
+${SPROG} checkout: file first-dir/file4 has been modified, but has been removed in revision branch
+U first-dir/file7
+${SPROG} checkout: file first-dir/file9 does not exist, but is present in revision branch"
+
+ # Verify that the right changes have been scheduled.
+ # The M file2 line is a bug; see above join-20.
+ cd first-dir
+ dotest join-21 "${testcvs} -q update" \
+'A file1
+M file2
+R file3'
+
+ # Checkout the main line again.
+ cd ../../1
+ rm -r first-dir
+ dotest join-22 "${testcvs} -q co first-dir" \
+'U first-dir/file2
+U first-dir/file3
+U first-dir/file4
+U first-dir/file7'
+
+ # Modify file4 locally, and do an update with a merge from a
+ # single revision.
+ # The file2 handling is a bug; see above join-20.
+ cd first-dir
+ echo 'third revision of file4' > file4
+ dotest join-23 "${testcvs} -q update -jbranch ." \
+"U file1
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.2
+Merging differences between 1\.1 and 1\.1\.2\.2 into file2
+${SPROG} update: scheduling \`file3' for removal
+M file4
+${SPROG} update: file file4 is locally modified, but has been removed in revision branch
+${SPROG} update: file file9 does not exist, but is present in revision branch"
+
+ # Verify that the right changes have been scheduled.
+ # The M file2 line is a bug; see above join-20
+ dotest join-24 "${testcvs} -q update" \
+'A file1
+M file2
+R file3
+M file4'
+
+ cd ..
+
+ # Checkout the main line again and make a new branch which we
+ # merge to.
+ rm -r first-dir
+ dotest join-25 "${testcvs} -q co first-dir" \
+'U first-dir/file2
+U first-dir/file3
+U first-dir/file4
+U first-dir/file7'
+ cd first-dir
+ dotest join-26 "${testcvs} -q tag -b br2" \
+"T file2
+T file3
+T file4
+T file7"
+ dotest join-27 "${testcvs} -q update -r br2" ""
+ # The handling of file8 and file9 here look fishy to me. I don't
+ # see why it should be different from the case where we merge to
+ # the trunk (e.g. join-23).
+ dotest join-28 "${testcvs} -q update -j branch" \
+"U file1
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+retrieving revision 1.1
+retrieving revision 1.1.2.2
+Merging differences between 1.1 and 1.1.2.2 into file2
+${SPROG} update: scheduling \`file3' for removal
+${SPROG} update: file file4 has been modified, but has been removed in revision branch
+U file8
+U file9"
+ # Verify that the right changes have been scheduled.
+ dotest join-29 "${testcvs} -q update" \
+"A file1
+M file2
+R file3
+A file8
+A file9"
+
+ # Checkout the mainline again to try updating and merging between two
+ # branches in the same step
+ # this seems a likely scenario - the user finishes up on branch and
+ # updates to br2 and merges in the same step - and there was a bug
+ # once that if the file was removed in the update then it wouldn't be
+ # readded in the merge
+ cd ..
+ rm -r first-dir
+ dotest join-twobranch-1 "${testcvs} -q co -rbranch first-dir" \
+'U first-dir/file1
+U first-dir/file2
+U first-dir/file8
+U first-dir/file9'
+ cd first-dir
+ dotest join-twobranch-2 "${testcvs} -q update -rbr2 -jbranch" \
+"${SPROG} update: \`file1' is no longer in the repository
+U file1
+U file2
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.2
+Merging differences between 1\.1 and 1\.1\.2\.2 into file2
+U file3
+${SPROG} update: scheduling \`file3' for removal
+U file4
+${SPROG} update: file file4 has been modified, but has been removed in revision branch
+U file7
+${SPROG} update: \`file8' is no longer in the repository
+U file8
+${SPROG} update: \`file9' is no longer in the repository
+U file9"
+ # Verify that the right changes have been scheduled.
+ dotest join-twobranch-3 "${testcvs} -q update" \
+"A file1
+M file2
+R file3
+A file8
+A file9"
+
+ # Checkout the mainline again to try merging from the trunk
+ # to a branch.
+ cd ..
+ rm -r first-dir
+ dotest join-30 "${testcvs} -q co first-dir" \
+'U first-dir/file2
+U first-dir/file3
+U first-dir/file4
+U first-dir/file7'
+ cd first-dir
+
+ # Tag the current revisions on the trunk.
+ dotest join-31 "${testcvs} -q tag T3 ." \
+'T file2
+T file3
+T file4
+T file7'
+
+ # Modify file7.
+ echo 'second revision of file7' > file7
+ dotest join-32 "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/file7,v <-- file7
+new revision: 1\.2; previous revision: 1\.1"
+
+ # And Tag again.
+ dotest join-33 "${testcvs} -q tag T4 ." \
+'T file2
+T file3
+T file4
+T file7'
+
+ # Now update branch to T3.
+ cd ../../2/first-dir
+ dotest join-34 "${testcvs} -q up -jT3" \
+"${SPROG} update: file file4 does not exist, but is present in revision T3
+U file7"
+
+ # Verify that the right changes have been scheduled.
+ dotest join-35 "${testcvs} -q update" \
+'A file7'
+
+ # Now update to T4.
+ # This is probably a bug, although in this particular case it just
+ # happens to do the right thing; see above join-20.
+ dotest join-36 "${testcvs} -q up -j T3 -j T4" \
+"A file7
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into file7"
+
+ # Verify that the right changes have been scheduled.
+ dotest join-37 "${testcvs} -q update" \
+'A file7'
+
+ dokeep
+ cd ../..
+ rm -r 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ join2)
+ # More joining tests.
+
+ # First the usual setup; create a directory first-dir, a file
+ # first-dir/file1, and a branch br1.
+ mkdir 1; cd 1
+ dotest join2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest join2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo 'initial contents of file1' >file1
+ dotest join2-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest join2-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ dotest join2-5 "${testcvs} -q tag -b br1" "T file1"
+ dotest join2-6 "${testcvs} -q update -r br1" ""
+ echo 'modify on branch' >>file1
+ touch bradd
+ dotest join2-6a "${testcvs} add bradd" \
+"${SPROG} add: scheduling file .bradd. for addition on branch .br1.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest join2-7 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/Attic/bradd,v <-- bradd
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # Here is the unusual/pathological part. We switch back to
+ # the trunk *for file1 only*, not for the whole directory.
+ dotest join2-8 "${testcvs} -q update -A file1" '[UP] file1'
+ dotest join2-9 "${testcvs} -q status file1" \
+"===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest join2-10 "cat CVS/Tag" "Tbr1"
+
+ dotest join2-11 "${testcvs} -q update -j br1 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into file1"
+ dotest join2-12 "cat file1" "initial contents of file1
+modify on branch"
+ # We should have no sticky tag on file1
+ dotest join2-13 "${testcvs} -q status file1" \
+"===================================================================
+File: file1 Status: Locally Modified
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest join2-14 "cat CVS/Tag" "Tbr1"
+ # And the checkin should go to the trunk
+ dotest join2-15 "${testcvs} -q ci -m modify file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+
+ # OK, the above is all well and good and has worked for some
+ # time. Now try the case where the file had been added on
+ # the branch.
+ dotest join2-16 "${testcvs} -q update -r br1" "[UP] file1"
+ # The workaround is to update the whole directory.
+ # The non-circumvented version won't work. The reason is that
+ # update removes the entry from CVS/Entries, so of course we get
+ # the tag from CVS/Tag and not Entries. I suppose maybe
+ # we could invent some new format in Entries which would handle
+ # this, but doing so, and handling it properly throughout
+ # CVS, would be a lot of work and I'm not sure this case justifies
+ # it.
+ dotest join2-17-circumvent "${testcvs} -q update -A" \
+"${SPROG} update: \`bradd' is no longer in the repository
+[UP] file1"
+: dotest join2-17 "${testcvs} -q update -A bradd" \
+"${SPROG} update: warning: \`bradd' is not (any longer) pertinent"
+ dotest join2-18 "${testcvs} -q update -j br1 bradd" "U bradd"
+ dotest join2-19 "${testcvs} -q status bradd" \
+"===================================================================
+File: bradd Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/bradd,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest join2-20 "${testcvs} -q ci -m modify bradd" \
+"$CVSROOT_DIRNAME/first-dir/bradd,v <-- bradd
+new revision: 1\.2; previous revision: 1\.1"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ join3)
+ # See "join" for a list of other joining/branching tests.
+ # First the usual setup; create a directory first-dir, a file
+ # first-dir/file1, and a branch br1.
+ mkdir 1; cd 1
+ dotest join3-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest join3-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo 'initial contents of file1' >file1
+ dotest join3-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest join3-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ dotest join3-5 "${testcvs} -q tag -b br1" "T file1"
+ dotest join3-6 "${testcvs} -q update -r br1" ""
+ echo 'br1:line1' >>file1
+ dotest join3-7 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # Now back to the trunk for:
+ # another revision and another branch for file1.
+ # add file2, which will exist on trunk and br2 but not br1.
+ dotest join3-8 "${testcvs} -q update -A" "[UP] file1"
+ echo 'trunk:line1' > file2
+ dotest join3-8a "${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ echo 'trunk:line1' >>file1
+ dotest join3-9 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ dotest join3-10 "${testcvs} -q tag -b br2" "T file1
+T file2"
+
+ # Before we actually have any revision on br2, let's try a join
+ dotest join3-11 "${testcvs} -q update -r br1" "[UP] file1
+${SPROG} update: \`file2' is no longer in the repository"
+ dotest join3-12 "${testcvs} -q update -j br2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into file1
+rcsmerge: warning: conflicts during merge
+U file2"
+ dotest join3-13 "cat file1" \
+"initial contents of file1
+[<]<<<<<< file1
+br1:line1
+[=]======
+trunk:line1
+[>]>>>>>> 1\.2"
+ rm file1
+
+ # OK, we'll try the same thing with a revision on br2.
+ dotest join3-14 "${testcvs} -q update -r br2 file1" \
+"${SPROG} update: warning: \`file1' was lost
+U file1" "U file1"
+ echo 'br2:line1' >>file1
+ dotest join3-15 "${testcvs} -q ci -m modify file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2\.2\.1; previous revision: 1\.2"
+
+ # OK, now we can join br2 to br1
+ dotest join3-16 "${testcvs} -q update -r br1 file1" "[UP] file1"
+ # It may seem odd, to merge a higher branch into a lower
+ # branch, but in fact CVS defines the ancestor as 1.1
+ # and so it merges both the 1.1->1.2 and 1.2->1.2.2.1 changes.
+ # This seems like a reasonably plausible behavior.
+ dotest join3-17 "${testcvs} -q update -j br2 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.2\.2\.1
+Merging differences between 1\.1 and 1\.2\.2\.1 into file1
+rcsmerge: warning: conflicts during merge"
+ dotest join3-18 "cat file1" \
+"initial contents of file1
+[<]<<<<<< file1
+br1:line1
+[=]======
+trunk:line1
+br2:line1
+[>]>>>>>> 1\.2\.2\.1"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ join4)
+ # Like join, but with local (uncommitted) modifications.
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1
+ cd 1
+ dotest join4-1 "${testcvs} -q co first-dir" ''
+
+ cd first-dir
+
+ # Add two files.
+ echo 'first revision of file3' > file3
+ echo 'first revision of file4' > file4
+ echo 'first revision of file6' > file6
+ echo 'first revision of file8' > file8
+ echo 'first revision of file9' > file9
+ dotest join4-2 "${testcvs} add file3 file4 file6 file8 file9" \
+"${SPROG}"' add: scheduling file `file3'\'' for addition
+'"${SPROG}"' add: scheduling file `file4'\'' for addition
+'"${SPROG}"' add: scheduling file `file6'\'' for addition
+'"${SPROG}"' add: scheduling file `file8'\'' for addition
+'"${SPROG}"' add: scheduling file `file9'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+
+ dotest join4-3 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file6,v <-- file6
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file8,v <-- file8
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file9,v <-- file9
+initial revision: 1\.1"
+
+ # Make a branch.
+ dotest join4-4 "${testcvs} -q tag -b branch ." \
+'T file3
+T file4
+T file6
+T file8
+T file9'
+
+ # Add file10
+ echo 'first revision of file10' > file10
+ dotest join4-7a "${testcvs} add file10" \
+"${SPROG}"' add: scheduling file `file10'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest join4-7b "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/file10,v <-- file10
+initial revision: 1\.1"
+
+ # Add file2 and file7, modify file4, and remove
+ # file6, file8, file9, and file10.
+ echo 'first revision of file2' > file2
+ echo 'second revision of file4' > file4
+ echo 'first revision of file7' > file7
+ rm file6 file8 file9 file10
+ dotest join4-5 "${testcvs} add file2 file7" \
+"${SPROG}"' add: scheduling file `file2'\'' for addition
+'"${SPROG}"' add: scheduling file `file7'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+ dotest join4-6 "${testcvs} rm file6 file8 file9 file10" \
+"${SPROG}"' remove: scheduling `file6'\'' for removal
+'"${SPROG}"' remove: scheduling `file8'\'' for removal
+'"${SPROG}"' remove: scheduling `file9'\'' for removal
+'"${SPROG}"' remove: scheduling `file10'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'
+
+ # Check out the branch.
+ cd ../..
+ mkdir 2
+ cd 2
+ dotest join4-8 "${testcvs} -q co -r branch first-dir" \
+'U first-dir/file3
+U first-dir/file4
+U first-dir/file6
+U first-dir/file8
+U first-dir/file9'
+
+ cd first-dir
+
+ # Modify the files on the branch, so that T1 is not an
+ # ancestor of the main line, and add file5
+ echo 'first branch revision of file3' > file3
+ echo 'first branch revision of file4' > file4
+ echo 'first branch revision of file5' > file5
+ echo 'first branch revision of file6' > file6
+ echo 'first branch revision of file9' > file9
+ dotest join4-9 "${testcvs} add file5" \
+"${SPROG}"' add: scheduling file `file5'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest join4-10 "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file5,v <-- file5
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file6,v <-- file6
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file9,v <-- file9
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # Tag the current revisions on the branch.
+ dotest join4-11 "${testcvs} -q tag T1 ." \
+'T file3
+T file4
+T file5
+T file6
+T file8
+T file9'
+
+ # Add file1 and file2, modify file9, and remove the other files.
+ echo 'first branch revision of file1' > file1
+ echo 'first branch revision of file2' > file2
+ echo 'second branch revision of file9' > file9
+ rm file3 file4 file5 file6
+ dotest join4-12 "${testcvs} add file1 file2" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\''
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+ dotest join4-13 "${testcvs} rm file3 file4 file5 file6" \
+"${SPROG}"' remove: scheduling `file3'\'' for removal
+'"${SPROG}"' remove: scheduling `file4'\'' for removal
+'"${SPROG}"' remove: scheduling `file5'\'' for removal
+'"${SPROG}"' remove: scheduling `file6'\'' for removal
+'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'
+ dotest join4-14 "${testcvs} -q ci -mx ." \
+"$CVSROOT_DIRNAME/first-dir/Attic/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file2,v <-- file2
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file3,v <-- file3
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/file4,v <-- file4
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file5,v <-- file5
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/file6,v <-- file6
+new revision: delete; previous revision: 1\.1\.2\.1
+$CVSROOT_DIRNAME/first-dir/file9,v <-- file9
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+
+ # Tag the current revisions on the branch.
+ dotest join4-15 "${testcvs} -q tag T2 ." \
+'T file1
+T file2
+T file8
+T file9'
+
+ # Modify file4 locally, and do an update with a merge.
+ cd ../../1/first-dir
+ echo 'third revision of file4' > file4
+ dotest join4-18 "${testcvs} -q update -jT1 -jT2 ." \
+"U file1
+R file10
+A file2
+${SPROG} update: file file2 exists, but has been added in revision T2
+${SPROG} update: scheduling \`file3' for removal
+M file4
+${SPROG} update: file file4 is locally modified, but has been removed in revision T2
+R file6
+A file7
+R file8
+R file9
+${SPROG} update: file file9 does not exist, but is present in revision T2"
+
+ # Verify that the right changes have been scheduled.
+ dotest join4-19 "${testcvs} -q update" \
+'A file1
+R file10
+A file2
+R file3
+M file4
+R file6
+A file7
+R file8
+R file9'
+
+ dokeep
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ join5)
+ # This test verifies that CVS can handle filenames starting with a
+ # dash (`-') properly. What used to happen was that CVS handled it
+ # just fine, until it went to pass them as arguments to the diff
+ # library, at which point it neglected to pass `--' before the file
+ # list, causing the diff library to attempt to interpret the file
+ # name as an argument.
+ mkdir join5; cd join5
+ mkdir 1; cd 1
+ dotest join5-init-1 "${testcvs} -Q co -l ."
+ mkdir join5
+ dotest join5-init-2 "${testcvs} -Q add join5"
+ cd join5
+ echo "there once was a file from harrisburg" >-file
+ echo "who's existance it seems was quiteabsurd" >>-file
+ dotest join5-init-3 "${testcvs} -Q add -- -file"
+ dotest join5-init-4 "${testcvs} -q ci -minitial" \
+"$CVSROOT_DIRNAME/join5/-file,v <-- -file
+initial revision: 1\.1"
+ cd ../..
+
+ mkdir 2; cd 2
+ dotest join5-init-5 "${testcvs} -Q co join5"
+ cd join5
+ echo "it tested for free" >>-file
+ echo "when paid it should be" >>-file
+ dotest join5-init-4 "${testcvs} -q ci -msecond" \
+"$CVSROOT_DIRNAME/join5/-file,v <-- -file
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../..
+
+ cd 1/join5
+ echo "but maybe it could charge bytheword" >>-file
+ # This is the test that used to spew complaints from diff3:
+ dotest join5 "${testcvs} up" \
+"${SPROG} update: Updating \.
+RCS file: ${CVSROOT_DIRNAME}/join5/-file,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into -file
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in -file
+C -file"
+
+ dokeep
+ cd ../../..
+ rm -r join5
+ modify_repo rm -rf $CVSROOT_DIRNAME/join5
+ ;;
+
+
+
+ join6)
+ mkdir join6; cd join6
+ mkdir 1; cd 1
+ dotest join6-init-1 "${testcvs} -Q co -l ."
+ mkdir join6
+ dotest join6-init-2 "${testcvs} -Q add join6"
+ cd join6
+ echo aaa >temp.txt
+ echo bbb >>temp.txt
+ echo ccc >>temp.txt
+ dotest join6-1 "${testcvs} -Q add temp.txt"
+ dotest join6-2 "${testcvs} -q commit -minitial temp.txt" \
+"$CVSROOT_DIRNAME/join6/temp\.txt,v <-- temp\.txt
+initial revision: 1\.1"
+ cp temp.txt temp2.txt
+ echo ddd >>temp.txt
+ dotest join6-3 "${testcvs} -q commit -madd temp.txt" \
+"$CVSROOT_DIRNAME/join6/temp.txt,v <-- temp\.txt
+new revision: 1\.2; previous revision: 1\.1"
+
+ # The case where the merge target is up-to-date and its base revision
+ # matches the second argument to -j: CVS doesn't bother attempting
+ # the merge since it already knows that the target contains the
+ # change.
+ dotest join6-3.3 "${testcvs} update -j1.1 -j1.2 temp.txt" \
+"temp\.txt already contains the differences between 1\.1 and 1\.2"
+ dotest join6-3.4 "${testcvs} diff temp.txt" ""
+
+ # The case where the merge target is modified but already contains
+ # the change.
+ echo bbb >temp.txt
+ echo ccc >>temp.txt
+ echo ddd >>temp.txt
+ dotest join6-3.5 "${testcvs} update -j1.1 -j1.2 temp.txt" \
+"M temp\.txt
+RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into temp\.txt
+temp\.txt already contains the differences between 1\.1 and 1\.2"
+ dotest_fail join6-3.6 "${testcvs} diff temp.txt" \
+"Index: temp\.txt
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
+retrieving revision 1\.2
+diff -r1\.2 temp.txt
+1d0
+< aaa"
+
+ cp temp2.txt temp.txt
+ dotest_fail join6-4 "${testcvs} diff temp.txt" \
+"Index: temp.txt
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
+retrieving revision 1\.2
+diff -r1\.2 temp\.txt
+4d3
+< ddd"
+
+ dotest join6-5 "${testcvs} update -j1.1 -j1.2 temp.txt" \
+"M temp\.txt
+RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into temp\.txt"
+ dotest join6-6 "${testcvs} diff temp.txt" ""
+ mv temp.txt temp3.txt
+ dotest join6-7 "sed 's/ddd/dddd/' < temp3.txt > temp.txt" ""
+ dotest join6-8 "${testcvs} update -j1.1 -j1.2 temp.txt" \
+"M temp\.txt
+RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into temp\.txt
+rcsmerge: warning: conflicts during merge"
+ dotest_fail join6-9 "${testcvs} diff temp.txt" \
+"Index: temp\.txt
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
+retrieving revision 1\.2
+diff -r1\.2 temp\.txt
+3a4,6
+> <<<<<<< temp\.txt
+> dddd
+> =======
+4a8
+> >>>>>>> 1\.2"
+ cp temp2.txt temp.txt
+ dotest join6-10 "${testcvs} -q ci -m del temp.txt" \
+"$CVSROOT_DIRNAME/join6/temp.txt,v <-- temp\.txt
+new revision: 1\.3; previous revision: 1\.2"
+ cp temp3.txt temp.txt
+ dotest_fail join6-11 "${testcvs} diff temp.txt" \
+"Index: temp\.txt
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
+retrieving revision 1\.3
+diff -r1\.3 temp\.txt
+3a4
+> ddd"
+ dotest join6-12 "${testcvs} update -j1.2 -j1.3 temp.txt" \
+"M temp\.txt
+RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
+retrieving revision 1\.2
+retrieving revision 1\.3
+Merging differences between 1\.2 and 1\.3 into temp\.txt"
+ dotest join6-13 "${testcvs} diff temp.txt" ""
+
+ # The case where the merge target wasn't created until after the
+ # first tag was applied
+ rm temp2.txt temp3.txt
+ dotest join6-20 "${testcvs} -q tag -r1.1 t1" \
+"T temp.txt"
+ echo xxx >temp2.txt
+ dotest join6-21 "${testcvs} -Q add temp2.txt"
+ dotest join6-22 "${testcvs} -q ci -m." \
+"$CVSROOT_DIRNAME/join6/temp2\.txt,v <-- temp2\.txt
+initial revision: 1\.1"
+ dotest join6-23 "${testcvs} -q tag t2" \
+"T temp.txt
+T temp2.txt"
+ echo xxx >>temp.txt
+ dotest join6-24 "${testcvs} -q ci -m." \
+"$CVSROOT_DIRNAME/join6/temp.txt,v <-- temp\.txt
+new revision: 1\.4; previous revision: 1\.3"
+ dotest join6-25 "${testcvs} -q up -jt1 -jt2" \
+"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
+retrieving revision 1\.1
+retrieving revision 1\.3
+Merging differences between 1\.1 and 1\.3 into temp.txt
+temp.txt already contains the differences between 1\.1 and 1\.3
+temp2.txt already contains the differences between creation and 1\.1"
+
+ # Now for my next trick: delete the file, recreate it, and
+ # try to merge
+ dotest join6-30 "${testcvs} -q rm -f temp2.txt" \
+"${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest join6-31 "${testcvs} -q ci -m. temp2.txt" \
+"$CVSROOT_DIRNAME/join6/temp2\.txt,v <-- temp2\.txt
+new revision: delete; previous revision: 1\.1"
+ echo new >temp2.txt
+ # FIXCVS: Local and remote really shouldn't be different and there
+ # really shouldn't be two different status lines for temp2.txt
+ if $remote; then
+ dotest_fail join6-32 "${testcvs} -q up -jt1 -jt2" \
+"? temp2\.txt
+RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
+retrieving revision 1\.1
+retrieving revision 1\.3
+Merging differences between 1\.1 and 1\.3 into temp.txt
+temp.txt already contains the differences between 1\.1 and 1\.3
+$CPROG update: move away .\./temp2\.txt.; it is in the way
+C temp2\.txt"
+ else
+ dotest join6-32 "${testcvs} -q up -jt1 -jt2" \
+"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
+retrieving revision 1\.1
+retrieving revision 1\.3
+Merging differences between 1\.1 and 1\.3 into temp.txt
+temp.txt already contains the differences between 1\.1 and 1\.3
+${SPROG} update: use .${SPROG} add. to create an entry for .temp2\.txt.
+U temp2\.txt
+? temp2\.txt"
+ fi
+
+ dokeep
+ cd ../../..
+ rm -r join6
+ modify_repo rm -rf $CVSROOT_DIRNAME/join6
+ ;;
+
+
+
+ join7)
+ # This test deals with joins that happen with the -n switch
+ mkdir join7; cd join7
+ mkdir impdir; cd impdir
+ echo aaa >temp.txt
+ echo bbb >>temp.txt
+ echo ccc >>temp.txt
+ dotest join7-1 \
+"${testcvs} -Q import -minitial join7 vendor vers-1" \
+""
+ cd ..
+ dotest join7-2 "${testcvs} -Q co join7" ""
+ cd join7
+ echo ddd >> temp.txt
+ dotest join7-3 "${testcvs} -Q ci -madded-line temp.txt" ""
+ cd ../impdir
+ echo aaaa >temp.txt
+ echo bbbb >>temp.txt
+ echo ccc >>temp.txt
+ echo eee >>temp.txt
+ dotest join7-4 \
+"${testcvs} -Q import -minitial join7 vendor vers-2" \
+""
+ cd ../join7
+ dotest join7-5 \
+"${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \
+"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.2
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
+rcsmerge: warning: conflicts during merge"
+ touch temp.txt
+ dotest join7-6 "${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \
+"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.2
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
+rcsmerge: warning: conflicts during merge" \
+"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.2
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
+rcsmerge: warning: conflicts during merge"
+
+ dokeep
+ cd ../..
+ rm -r join7
+ modify_repo rm -rf $CVSROOT_DIRNAME/join7
+ ;;
+
+
+
+ join-readonly-conflict)
+ # Previously, only tests 1 & 11 were being tested. I added the
+ # intermediate dotest's to try and diagnose a different failure
+ #
+ # Demonstrate that cvs-1.9.29 can fail on 2nd and subsequent
+ # conflict-evoking join attempts.
+ # Even with that version of CVS, This test failed only in
+ # client-server mode, and would have been noticed in normal
+ # operation only for files that were read-only (either due to
+ # use of cvs' global -r option, setting the CVSREAD envvar,
+ # or use of watch lists).
+ mkdir join-readonly-conflict; cd join-readonly-conflict
+ dotest join-readonly-conflict-1 "$testcvs -q co -l ." ''
+ module=join-readonly-conflict
+ mkdir $module
+ $testcvs -q add $module >>$LOGFILE 2>&1
+ cd $module
+
+ file=m
+ echo trunk > $file
+ dotest join-readonly-conflict-2 "$testcvs -Q add $file" ''
+
+ dotest join-readonly-conflict-3 "$testcvs -q ci -m . $file" \
+"$CVSROOT_DIRNAME/$module/$file,v <-- $file
+initial revision: 1\.1"
+
+ dotest join-readonly-conflict-4 "$testcvs tag -b B $file" "T $file"
+ dotest join-readonly-conflict-5 "$testcvs -q update -rB $file" ''
+ echo branch B > $file
+ dotest join-readonly-conflict-6 "$testcvs -q ci -m . $file" \
+"$CVSROOT_DIRNAME/$module/$file,v <-- $file
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ rm $file
+ dotest join-readonly-conflict-7 "$testcvs -Q update -A $file" ''
+ # Make sure $file is read-only. This can happen more realistically
+ # via patch -- which could be used to apply a delta, yet would
+ # preserve a file's read-only permissions.
+ echo conflict > $file; chmod u-w $file
+ dotest join-readonly-conflict-8 "$testcvs update -r B $file" \
+"RCS file: $CVSROOT_DIRNAME/$module/$file,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into $file
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in $file
+C $file"
+
+ # restore to the trunk
+ rm -f $file
+ dotest join-readonly-conflict-9 "$testcvs -Q update -A $file" ''
+
+ # This one would fail because cvs couldn't open the existing
+ # (and read-only) .# file for writing.
+ echo conflict > $file
+
+ # verify that the backup file is not writable
+ if test -w ".#$file.1.1"; then
+ fail "join-readonly-conflict-10 : .#$file.1.1 is writable"
+ else
+ pass "join-readonly-conflict-10"
+ fi
+ dotest join-readonly-conflict-11 "$testcvs update -r B $file" \
+"RCS file: $CVSROOT_DIRNAME/$module/$file,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into $file
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in $file
+C m"
+
+ dokeep
+ cd ../..
+ rm -r join-readonly-conflict
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ join-admin)
+ mkdir 1; cd 1
+ dotest join-admin-0-1 "$testcvs -q co -l ."
+ module=x
+ mkdir $module
+ dotest join-admin-0-2 "$testcvs -q add $module" \
+"Directory $CVSROOT_DIRNAME/$module added to the repository"
+ cd $module
+
+ # Create a file so applying the first tag works.
+ echo foo > a
+ dotest join-admin-0-3 "$testcvs -Q add a" ''
+ dotest join-admin-0-4 "$testcvs -Q ci -m. a" ''
+
+ dotest join-admin-0-5 "$testcvs -Q tag -b B" ''
+ dotest join-admin-0-6 "$testcvs -Q tag -b M1" ''
+ echo '$''Id$' > b
+ dotest join-admin-0-7 "$testcvs -Q add b" ''
+ dotest join-admin-0-8 "$testcvs -Q ci -m. b" ''
+ dotest join-admin-0-9 "$testcvs -Q tag -b M2" ''
+
+ dotest join-admin-0-10 "$testcvs -Q update -r B" ''
+ dotest join-admin-0-11 "$testcvs -Q update -kk -jM1 -jM2" ''
+ dotest join-admin-0-12 "$testcvs -Q ci -m. b" ''
+
+ dotest join-admin-0-13 "$testcvs -Q update -A" ''
+
+ # Verify that the -kk flag from the update did not
+ # propagate to the repository.
+ dotest join-admin-1 "$testcvs status b" \
+"===================================================================
+File: b Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/x/b,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ join-admin-2)
+ # Show that when a merge (via update -kk -jtag1 -jtag2) first
+ # removes a file, then modifies another containing an $Id...$ line,
+ # the resulting file contains the unexpanded `$Id.$' string, as
+ # -kk requires.
+ mkdir 1; cd 1
+ dotest join-admin-2-1 "$testcvs -q co -l ." ''
+ module=x
+ mkdir $module
+ dotest join-admin-2-2 "$testcvs -q add $module" \
+"Directory ${CVSROOT_DIRNAME}/x added to the repository"
+ cd $module
+
+ # Create a file so applying the first tag works.
+ echo '$''Id$' > e0
+ cp e0 e
+ dotest join-admin-2-3 "$testcvs -Q add e"
+ dotest join-admin-2-4 "$testcvs -Q ci -m. e"
+
+ dotest join-admin-2-5 "$testcvs -Q tag -b T" '' "${QUESTION} e0"
+ dotest join-admin-2-6 "$testcvs -Q update -r T" '' "${QUESTION} e0"
+ cp e0 e
+ dotest join-admin-2-7 "$testcvs -Q ci -m. e"
+
+ dotest join-admin-2-8 "$testcvs -Q update -A" '' "${QUESTION} e0"
+ dotest join-admin-2-9 "$testcvs -Q tag -b M1" '' "${QUESTION} e0"
+
+ echo '$''Id$' > b
+ dotest join-admin-2-10 "$testcvs -Q add b" ''
+ cp e0 e
+ dotest join-admin-2-11 "$testcvs -Q ci -m. b e"
+
+ dotest join-admin-2-12 "$testcvs -Q tag -b M2" '' "${QUESTION} e0"
+
+ dotest join-admin-2-13 "$testcvs -Q update -r T" '' "${QUESTION} e0"
+ dotest join-admin-2-14 "$testcvs update -kk -jM1 -jM2" \
+"${SPROG} update: Updating .
+U b
+U e
+RCS file: ${CVSROOT_DIRNAME}/x/e,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into e
+e already contains the differences between 1\.1 and 1\.2
+${QUESTION} e0" \
+"${QUESTION} e0
+${SPROG} update: Updating .
+U b
+U e
+RCS file: ${CVSROOT_DIRNAME}/x/e,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into e
+e already contains the differences between 1\.1 and 1\.2"
+
+ # Verify that the $Id.$ string is not expanded.
+ dotest join-admin-2-15 "cat e" '$''Id$'
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ join-rm)
+ # This first half of this test checks that a single-argument merge
+ # from a branch is capable of removing files.
+ #
+ # The second half verifies that an update to another location with an
+ # uncommitted removal will transfer the destination branch of the
+ # removal.
+
+ module=join-rm
+ mkdir $module; cd $module
+
+ dotest join-rm-init-1 "$testcvs -q co -l ." ''
+ mkdir $module
+ dotest join-rm-init-2 "$testcvs -q add $module" \
+"Directory $CVSROOT_DIRNAME/$module added to the repository"
+ cd $module
+
+ # add some files.
+ touch a b c d e f g
+ dotest join-rm-init-3 "$testcvs -Q add a b c d e f g"
+ dotest join-rm-init-4 "$testcvs -Q ci -m add-em"
+
+ # create the branch and update to it
+ dotest join-rm-init-5 "$testcvs -Q tag -b br"
+ dotest join-rm-init-6 "$testcvs -Q up -rbr"
+
+ # remove a few files from the branch
+ dotest join-rm-init-7 "$testcvs -Q rm -f b d g"
+ dotest join-rm-init-8 "$testcvs -Q ci -mrm"
+
+ # update to the trunk
+ dotest join-rm-init-9 "$testcvs -Q up -A"
+
+ # now for the test - try and merge the removals.
+ dotest join-rm-1 "$testcvs -q up -jbr" \
+"$SPROG update: scheduling \`b' for removal
+$SPROG update: scheduling \`d' for removal
+$SPROG update: scheduling \`g' for removal"
+
+ # And make sure the merge took
+ dotest join-rm-2 "$testcvs -qn up" \
+"R b
+R d
+R g"
+
+ dotest join-rm-3 "$testcvs -q ci -m 'save the merge'" \
+"$CVSROOT_DIRNAME/join-rm/b,v <-- b
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/join-rm/d,v <-- d
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/join-rm/g,v <-- g
+new revision: delete; previous revision: 1\.1"
+
+ # and verify that it was the head revision which was removed.
+ dotest join-rm-4 "$testcvs -q log b" "
+RCS file: $CVSROOT_DIRNAME/join-rm/Attic/b,v
+Working file: b
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ br: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: $username; state: dead; lines: ${PLUS}0 -0; commitid: ${commitid};
+save the merge
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+branches: 1.1.2;
+add-em
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: $username; state: dead; lines: ${PLUS}0 -0; commitid: ${commitid};
+rm
+============================================================================="
+
+ # go back to the branch to set up for the second set of tests
+ dotest join-rm-init-10 "$testcvs -Q up -rbr"
+ dotest join-rm-init-11 "$testcvs -Q rm -f a"
+ dotest join-rm-init-12 "$testcvs -Q ci -m rma"
+
+ # now the test: update to the trunk
+ #
+ # FIXCVS: This update should merge the removal to the trunk. It does
+ # not.
+ dotest join-rm-5 "$testcvs -q up -A" "U a"
+
+ # and verify that there is no sticky tag
+ dotest join-rm-6 "$testcvs status a" \
+"===================================================================
+File: a Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/join-rm/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ rm -r $module
+ ;;
+
+
+
+ new) # look for stray "no longer pertinent" messages.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest new-init-1 "$testcvs -Q co first-dir"
+
+ cd first-dir
+ touch a
+
+ dotest new-1 "$testcvs -Q add a"
+
+ dotest new-2 "$testcvs -Q ci -m added"
+ rm a
+
+ dotest new-3 "$testcvs -Q rm a"
+ dotest new-4 "$testcvs -Q ci -m removed"
+ dotest new-5 "$testcvs -Q update -A"
+ dotest new-6 "$testcvs -Q update -rHEAD"
+
+ dokeep
+ cd ..
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ newb)
+ # Test removing a file on a branch and then checking it out.
+
+ # We call this "newb" only because it, like the "new" tests,
+ # has something to do with "no longer pertinent" messages.
+ # Not necessarily the most brilliant nomenclature.
+
+ # Create file 'a'.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest newb-123a "${testcvs} -q co first-dir" ''
+ cd first-dir
+ touch a
+ dotest newb-123b "${testcvs} add a" \
+"${SPROG} add: scheduling file .a. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest newb-123c "${testcvs} -q ci -m added" \
+"$CVSROOT_DIRNAME/first-dir/a,v <-- a
+initial revision: 1\.1"
+
+ # Make a branch.
+ dotest newb-123d "${testcvs} -q tag -b branch" "T a"
+
+ # Check out the branch.
+ cd ..
+ rm -r first-dir
+ mkdir 1
+ cd 1
+ dotest newb-123e "${testcvs} -q co -r branch first-dir" \
+"U first-dir/a"
+
+ # Remove 'a' on another copy of the branch.
+ cd ..
+ mkdir 2
+ cd 2
+ dotest newb-123f "${testcvs} -q co -r branch first-dir" \
+"U first-dir/a"
+ cd first-dir
+ rm a
+ dotest newb-123g "${testcvs} rm a" \
+"${SPROG} remove: scheduling .a. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest newb-123h "${testcvs} -q ci -m removed" \
+"$CVSROOT_DIRNAME/first-dir/a,v <-- a
+new revision: delete; previous revision: 1\.1"
+
+ # Check out the file on the branch. This should report
+ # that the file is not pertinent, but it should not
+ # say anything else.
+ cd ..
+ rm -r first-dir
+ dotest newb-123i "${testcvs} -q co -r branch first-dir/a" \
+"${SPROG} checkout: warning: \`first-dir/a' is not (any longer) pertinent"
+
+ # Update the other copy, and make sure that a is removed.
+ cd ../1/first-dir
+ # "Entry Invalid" is a rather strange output here. Something like
+ # "Removed in Repository" would make more sense.
+ dotest newb-123j0 "${testcvs} status a" \
+"${SPROG} status: \`a' is no longer in the repository
+===================================================================
+File: a Status: Entry Invalid
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: branch (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)${DOTSTAR}"
+ dotest newb-123j "${testcvs} -q update" \
+"${SPROG} update: \`a' is no longer in the repository"
+
+ if test -f a; then
+ fail newb-123k
+ else
+ pass newb-123k
+ fi
+
+ dokeep
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ conflicts)
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+
+ mkdir 1
+ cd 1
+
+ dotest conflicts-124 "${testcvs} -q co first-dir" ''
+
+ cd first-dir
+ touch a
+
+ dotest conflicts-125 "${testcvs} add a" \
+"${SPROG} add: scheduling file .a. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest conflicts-126 "${testcvs} -q ci -m added" \
+"$CVSROOT_DIRNAME/first-dir/a,v <-- a
+initial revision: 1\.1"
+
+ cd ../..
+ mkdir 2
+ cd 2
+
+ dotest conflicts-126.5 "${testcvs} co -p first-dir" \
+"${SPROG} checkout: Updating first-dir
+===================================================================
+Checking out first-dir/a
+RCS: ${CVSROOT_DIRNAME}/first-dir/a,v
+VERS: 1\.1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*"
+ dotest conflicts-127 "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ dotest conflicts-127a "test -f a" ''
+
+ cd ../../1/first-dir
+ echo add a line >>a
+ mkdir dir1
+ dotest conflicts-127b "${testcvs} add dir1" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository"
+ dotest conflicts-128 "${testcvs} -q ci -m changed" \
+"$CVSROOT_DIRNAME/first-dir/a,v <-- a
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../..
+
+ # Similar to conflicts-126.5, but now the file has nonempty
+ # contents.
+ mkdir 3
+ cd 3
+ dotest conflicts-128.5 "${testcvs} co -p -l first-dir" \
+"${SPROG} checkout: Updating first-dir
+===================================================================
+Checking out first-dir/a
+RCS: ${CVSROOT_DIRNAME}/first-dir/a,v
+VERS: 1\.2
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+add a line"
+ cd ..
+ rmdir 3
+
+ # Now go over the to the other working directory and
+ # start testing conflicts
+ cd 2/first-dir
+ echo add a conflicting line >>a
+ dotest_fail conflicts-129 "${testcvs} -q ci -m changed" \
+"${SPROG}"' commit: Up-to-date check failed for `a'\''
+'"${SPROG}"' \[commit aborted\]: correct above errors first!'
+ mkdir dir1
+ mkdir sdir
+ dotest conflicts-status-0 "${testcvs} status a" \
+"===================================================================
+File: a Status: Needs Merge
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest conflicts-129a "${testcvs} -nq update a" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into a
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in a
+C a"
+ dotest conflicts-130 "${testcvs} -q update" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into a
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in a
+C a
+${QUESTION} dir1
+${QUESTION} sdir" \
+"${QUESTION} dir1
+${QUESTION} sdir
+RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into a
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in a
+C a"
+ rmdir dir1 sdir
+
+ dotest conflicts-status-1 "${testcvs} status a" \
+"===================================================================
+File: a Status: Unresolved Conflict
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest_fail conflicts-131 "${testcvs} -q ci -m try" \
+"${SPROG} commit: file .a. had a conflict and has not been modified
+${SPROG} \[commit aborted\]: correct above errors first!"
+
+ # Try to check in the file with the conflict markers in it.
+ # Make sure we detect any one of the three conflict markers
+ mv a aa
+ grep '^<<<<<<<' aa >a
+ dotest conflicts-status-2 "${testcvs} -nq ci -m try a" \
+"${SPROG} commit: warning: file .a. seems to still contain conflict indicators"
+
+ grep '^=======' aa >a
+ dotest conflicts-status-3 "${testcvs} -nq ci -m try a" \
+"${SPROG} commit: warning: file .a. seems to still contain conflict indicators"
+
+ grep '^>>>>>>>' aa >a
+ dotest conflicts-status-4 "${testcvs} -qn ci -m try a" \
+"${SPROG} commit: warning: file .a. seems to still contain conflict indicators"
+
+ mv aa a
+ echo lame attempt at resolving it >>a
+ dotest conflicts-status-5 "${testcvs} status a" \
+"===================================================================
+File: a Status: File had conflicts on merge
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest conflicts-132 "$testcvs -q ci -m try" \
+"$SPROG commit: warning: file .a. seems to still contain conflict indicators
+$CVSROOT_DIRNAME/first-dir/a,v <-- a
+new revision: 1\.3; previous revision: 1\.2"
+
+ # OK, the user saw the warning (good user), and now
+ # resolves it for real.
+ echo resolve conflict >a
+ dotest conflicts-status-6 "${testcvs} status a" \
+"===================================================================
+File: a Status: Locally Modified
+
+ Working revision: 1\.3.*
+ Repository revision: 1\.3 ${CVSROOT_DIRNAME}/first-dir/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest conflicts-133 "${testcvs} -q ci -m resolved" \
+"$CVSROOT_DIRNAME/first-dir/a,v <-- a
+new revision: 1\.4; previous revision: 1\.3"
+ dotest conflicts-status-7 "${testcvs} status a" \
+"===================================================================
+File: a Status: Up-to-date
+
+ Working revision: 1\.4.*
+ Repository revision: 1\.4 ${CVSROOT_DIRNAME}/first-dir/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # Now test that we can add a file in one working directory
+ # and have an update in another get it.
+ cd ../../1/first-dir
+ echo abc >abc
+ if ${testcvs} add abc >>${LOGFILE} 2>&1; then
+ pass 134
+ else
+ fail 134
+ fi
+ if ${testcvs} ci -m 'add abc' abc >>${LOGFILE} 2>&1; then
+ pass 135
+ else
+ fail 135
+ fi
+ cd ../../2
+ mkdir first-dir/dir1 first-dir/sdir
+ dotest conflicts-136 "${testcvs} -q update first-dir" \
+'[UP] first-dir/abc
+'"${QUESTION}"' first-dir/dir1
+'"${QUESTION}"' first-dir/sdir' \
+''"${QUESTION}"' first-dir/dir1
+'"${QUESTION}"' first-dir/sdir
+[UP] first-dir/abc'
+ dotest conflicts-137 'test -f first-dir/abc' ''
+ rmdir first-dir/dir1 first-dir/sdir
+
+ # Now test something similar, but in which the parent directory
+ # (not the directory in question) has the Entries.Static flag
+ # set.
+ cd ../1/first-dir
+ mkdir subdir
+ dotest conflicts-138 "${testcvs} add subdir" "${DOTSTAR}"
+ cd ../..
+ mkdir 3
+ cd 3
+ dotest conflicts-139 \
+"${testcvs} -q co first-dir/abc first-dir/subdir" "${DOTSTAR}"
+ cd ../1/first-dir/subdir
+ echo sss >sss
+ dotest conflicts-140 "${testcvs} add sss" "${DOTSTAR}"
+ dotest conflicts-140a "${testcvs} ci -m adding sss" \
+"${DOTSTAR}"
+ cd ../../../3/first-dir
+ dotest conflicts-141 "${testcvs} -q update" "${DOTSTAR}"
+ dotest conflicts-142 "test -f subdir/sss"
+
+ dokeep
+ cd ../..
+ rm -r 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ restore_adm
+ ;;
+
+
+
+ conflicts2)
+ # More conflicts tests; separate from conflicts to keep each
+ # test a manageable size.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+
+ mkdir 1
+ cd 1
+
+ dotest conflicts2-142a1 "${testcvs} -q co first-dir" ''
+
+ cd first-dir
+ touch a abc
+
+ dotest conflicts2-142a2 "${testcvs} add a abc" \
+"${SPROG} add: scheduling file .a. for addition
+${SPROG} add: scheduling file .abc. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest conflicts2-142a3 "${testcvs} -q ci -m added" \
+"$CVSROOT_DIRNAME/first-dir/a,v <-- a
+initial revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc
+initial revision: 1\.1"
+
+ cd ../..
+ mkdir 2
+ cd 2
+
+ dotest conflicts2-142a4 "${testcvs} -q co first-dir" 'U first-dir/a
+U first-dir/abc'
+ cd ..
+
+ # BEGIN TESTS USING THE FILE A
+ # FIXME: would be cleaner to separate them out into their own
+ # tests; conflicts2 is getting long.
+ # Now test that if one person modifies and commits a
+ # file and a second person removes it, it is a
+ # conflict
+ cd 1/first-dir
+ echo modify a >>a
+ dotest conflicts2-142b2 "${testcvs} -q ci -m modify-a" \
+"$CVSROOT_DIRNAME/first-dir/a,v <-- a
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../../2/first-dir
+ rm a
+ dotest conflicts2-142b3 "${testcvs} rm a" \
+"${SPROG} remove: scheduling .a. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest_fail conflicts2-142b4 "${testcvs} -q update" \
+"${SPROG} update: conflict: removed \`a' was modified by second party
+C a"
+ # Resolve the conflict by deciding not to remove the file
+ # after all.
+ dotest_sort conflicts2-142b5 "$testcvs add a" "U a
+${SPROG} add: \`a', version 1\.1, resurrected"
+ dotest conflicts2-142b5b1 "$testcvs status a" \
+"===================================================================
+File: a Status: Needs Patch
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/a,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest conflicts2-142b6 "$testcvs -q update" 'U a'
+
+ # Now one level up.
+ cd ..
+ dotest conflicts2-142b7 "${testcvs} rm -f first-dir/a" \
+"${SPROG} remove: scheduling \`first-dir/a' for removal
+${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
+
+ if $remote; then
+ # Haven't investigated this one.
+ dotest_fail conflicts2-142b8r "$testcvs add first-dir/a" \
+"${CPROG} add: in directory \`\.':
+${CPROG} \[add aborted\]: there is no version here; do \`${CPROG} checkout' first"
+ cd first-dir
+ else
+ dotest conflicts2-142b8 "${testcvs} add first-dir/a" \
+"U first-dir/a
+$SPROG add: \`first-dir/a', version 1\.2, resurrected"
+ cd first-dir
+ # Now recover from the damage that the 142b8 test did.
+ dotest conflicts2-142b9 "${testcvs} rm -f a" \
+"${SPROG} remove: scheduling \`a' for removal
+${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
+ fi
+
+ # As before, 1.2 instead of 1.1 is a bug.
+ dotest_sort conflicts2-142b10 "$testcvs add a" "U a
+${SPROG} add: \`a', version 1\.2, resurrected"
+ # As with conflicts2-142b6, check that things are normal again.
+ dotest conflicts2-142b11 "${testcvs} -q update" ''
+ cd ../..
+ # END TESTS USING THE FILE A
+
+ # Now test that if one person removes a file and
+ # commits it, and a second person removes it, is it
+ # not a conflict.
+ cd 1/first-dir
+ rm abc
+ dotest conflicts2-142c0 "${testcvs} rm abc" \
+"${SPROG} remove: scheduling \`abc' for removal
+${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
+ dotest conflicts2-142c1 "${testcvs} -q ci -m remove-abc" \
+"$CVSROOT_DIRNAME/first-dir/abc,v <-- abc
+new revision: delete; previous revision: 1\.1"
+ cd ../../2/first-dir
+ rm abc
+ dotest conflicts2-142c2 "${testcvs} rm abc" \
+"${SPROG} remove: scheduling \`abc' for removal
+${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
+ dotest conflicts2-142c3 "${testcvs} update" \
+"${SPROG} update: Updating \."
+ cd ../..
+
+ # conflicts2-142d*: test that if one party adds a file, and another
+ # party has a file of the same name, cvs notices
+ cd 1/first-dir
+ touch aa.c
+ echo 'contents unchanged' >same.c
+ dotest conflicts2-142d0 "${testcvs} add aa.c same.c" \
+"${SPROG} add: scheduling file .aa\.c. for addition
+${SPROG} add: scheduling file .same\.c. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest conflicts2-142d1 "${testcvs} -q ci -m added" \
+"$CVSROOT_DIRNAME/first-dir/aa\.c,v <-- aa\.c
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/same\.c,v <-- same\.c
+initial revision: 1\.1"
+
+ # Test the case where the second user manages the add before the
+ # first commits
+ touch bb.c
+ dotest conflicts2-142d1a "$testcvs add bb.c" \
+"$SPROG add: scheduling file .bb\.c. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ cd ../../2/first-dir
+ echo "don't you dare obliterate this text" >bb.c
+ dotest conflicts2-142d1b "$testcvs add bb.c" \
+"$SPROG add: scheduling file .bb\.c. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ cd ../../1/first-dir
+ dotest conflicts2-142d1c "$testcvs -q ci -m added" \
+"$CVSROOT_DIRNAME/first-dir/bb\.c,v <-- bb\.c
+initial revision: 1\.1"
+
+ cd ../../2/first-dir
+ echo "don't you dare obliterate this text either" >aa.c
+ echo 'contents unchanged' >same.c
+ # Note the discrepancy between local and remote in the handling
+ # of same.c. I kind
+ # of suspect that the local CVS behavior is the more useful one
+ # although I do sort of wonder whether we should make people run
+ # cvs add just to get them in that habit (also, trying to implement
+ # the local CVS behavior for remote without the cvs add seems
+ # pretty difficult).
+ if $remote; then
+ dotest_fail conflicts2-142d2r "${testcvs} -q update" \
+"${QUESTION} aa\.c
+${QUESTION} same\.c
+${CPROG} update: move away \`\./aa\.c'; it is in the way
+C aa\.c
+${SPROG} update: conflict: \`bb\.c' created independently by second party
+C bb\.c
+${CPROG} update: move away \`\./same\.c'; it is in the way
+C same\.c"
+ else
+ dotest_fail conflicts2-142d2 "${testcvs} -q update" \
+"${CPROG} update: move away \`aa\.c'; it is in the way
+C aa\.c
+${CPROG} update: conflict: \`bb\.c' created independently by second party
+C bb\.c
+U same\.c"
+ fi
+ dotest conflicts2-142d3 "${testcvs} -q status aa.c" \
+"${SPROG} status: move away \`aa\.c'; it is in the way
+===================================================================
+File: aa\.c Status: Unresolved Conflict
+
+ Working revision: No entry for aa\.c
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/aa\.c,v
+ Commit Identifier: ${commitid}"
+ dotest conflicts2-142d3a "${testcvs} -q status bb.c" \
+"${SPROG} status: conflict: \`bb\.c' created independently by second party
+===================================================================
+File: bb\.c Status: Unresolved Conflict
+
+ Working revision: New file!
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/bb\.c,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # FIXCVS
+ # This message seems somewhat bogus. I mean, parallel development
+ # means that we get to work in parallel if we choose, right? And
+ # then at commit time it would be a conflict.
+ #
+ # Well, the status is "Unresolved conflict" before _and_ after
+ # the update/merge (when conflicts happen, not at commit time).
+ # It is possible that this message could be changed to something
+ # more infomrative to novice users, like "File of same name exists
+ # in repository", or "File of same name committed independantly by
+ # second party", but these two messages look too long for the Status
+ # field and the move away & added independantly error messages _are_
+ # displayed. Still, we get a lot of questions about this on the
+ # email lists. Somehow we need to get more information to users
+ # via these messages and the ones generated by update. -DRP
+ dotest_fail conflicts2-142d4 "${testcvs} -q add aa.c" \
+"${SPROG} add: \`aa.c' added independently by second party"
+
+ # The user might want to see just what the conflict is.
+ # Don't bother, diff seems to kind of lose its mind, with or
+ # without -N. This is a CVS bug(s).
+ #dotest conflicts2-142d5 \
+ #"${testcvs} -q diff -r HEAD -N aa.c" FIXCVS THEN FIXME
+
+ # Now: "how can the user resolve this conflict", I hear you cry.
+ # Well, one way is to forget about the file in the working
+ # directory.
+ # Since it didn't let us do the add in conflicts2-142d4, there
+ # is no need to run cvs rm here.
+ #dotest conflicts2-142d6 "${testcvs} -q rm -f aa.c" fixme
+ dotest conflicts2-142d6 "rm aa.c" ''
+ dotest conflicts2-142d7 "${testcvs} -q update aa.c" "U aa\.c"
+ dotest conflicts2-142d8 "cat aa.c" ''
+
+ # The other way is to use the version from the working directory
+ # instead of the version from the repository. Unfortunately,
+ # there doesn't seem to be any particularly clear way to do
+ # this (?).
+
+ dokeep
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ conflicts3)
+ # More tests of conflicts and/or multiple working directories
+ # in general.
+
+ mkdir 1; cd 1
+ dotest conflicts3-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest conflicts3-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd ..
+ mkdir 2; cd 2
+ dotest conflicts3-3 "${testcvs} -q co -l first-dir" ''
+ cd ../1/first-dir
+ touch file1 file2
+ dotest conflicts3-4 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest conflicts3-5 "${testcvs} -q ci -m add-them" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ cd ../../2/first-dir
+ # Check that -n doesn't make CVS lose its mind as it creates
+ # (or rather, doesn't) a new file.
+ dotest conflicts3-6 "${testcvs} -nq update" \
+"U file1
+U file2"
+ dotest_fail conflicts3-7 "test -f file1" ''
+ dotest conflicts3-8 "${testcvs} -q update" \
+"U file1
+U file2"
+ dotest conflicts3-9 "test -f file2" ''
+
+ # OK, now remove two files at once
+ dotest conflicts3-10 "${testcvs} rm -f file1 file2" \
+"${SPROG} remove: scheduling .file1. for removal
+${SPROG} remove: scheduling .file2. for removal
+${SPROG} remove: use .${SPROG} commit. to remove these files permanently"
+ dotest conflicts3-11 "${testcvs} -q ci -m remove-them" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: delete; previous revision: 1\.1"
+ cd ../../1/first-dir
+ dotest conflicts3-12 "${testcvs} -n -q update" \
+"${SPROG} update: \`file1' is no longer in the repository
+${SPROG} update: \`file2' is no longer in the repository"
+ dotest conflicts3-13 "${testcvs} -q update" \
+"${SPROG} update: \`file1' is no longer in the repository
+${SPROG} update: \`file2' is no longer in the repository"
+
+ # OK, now add a directory to both working directories
+ # and see that CVS doesn't lose its mind.
+ mkdir sdir
+ dotest conflicts3-14 "${testcvs} add sdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository"
+ touch sdir/sfile
+ dotest conflicts3-14a "${testcvs} add sdir/sfile" \
+"${SPROG} add: scheduling file .sdir/sfile. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest conflicts3-14b "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/sdir/sfile,v <-- sdir/sfile
+initial revision: 1\.1"
+
+ cd ../../2/first-dir
+
+ # Create a CVS directory without the proper administrative
+ # files in it. This can happen for example if you hit ^C
+ # in the middle of a checkout.
+ mkdir sdir
+ mkdir sdir/CVS
+ # OK, in the local case CVS sees that the directory exists
+ # in the repository and recurses into it. In the remote case
+ # CVS can't see the repository and has no way of knowing
+ # that sdir is even a directory (stat'ing everything would be
+ # too slow). The remote behavior makes more sense to me (but
+ # would this affect other cases?).
+ if $remote; then
+ dotest conflicts3-15 "${testcvs} -q update" \
+"${QUESTION} sdir"
+ else
+ dotest conflicts3-15 "${testcvs} -q update" \
+"${QUESTION} sdir
+${SPROG} update: ignoring sdir (CVS/Repository missing)"
+ touch sdir/CVS/Repository
+ dotest conflicts3-16 "${testcvs} -q update" \
+"${QUESTION} sdir
+${SPROG} update: ignoring sdir (CVS/Entries missing)"
+ cd ..
+ dotest conflicts3-16a "${testcvs} -q update first-dir" \
+"${QUESTION} first-dir/sdir
+${SPROG} update: ignoring first-dir/sdir (CVS/Entries missing)"
+ cd first-dir
+ fi
+ rm -r sdir
+
+ # OK, now the same thing, but the directory doesn't exist
+ # in the repository.
+ mkdir newdir
+ mkdir newdir/CVS
+ dotest conflicts3-17 "${testcvs} -q update" "${QUESTION} newdir"
+ echo "D/newdir////" >> CVS/Entries
+ dotest conflicts3-18 "${testcvs} -q update" \
+"${CPROG} update: ignoring newdir (CVS/Repository missing)"
+ touch newdir/CVS/Repository
+ dotest conflicts3-19 "${testcvs} -q update" \
+"${CPROG} update: ignoring newdir (CVS/Entries missing)"
+ cd ..
+ dotest conflicts3-20 "${testcvs} -q update first-dir" \
+"${CPROG} update: ignoring first-dir/newdir (CVS/Entries missing)"
+ cd first-dir
+ rm -r newdir
+
+ # The previous tests have left CVS/Entries in something of a mess.
+ # While we "should" be able to deal with that (maybe), for now
+ # we just start over.
+ cd ..
+ rm -r first-dir
+ dotest conflicts3-20a "${testcvs} -q co -l first-dir" ''
+ cd first-dir
+
+ dotest conflicts3-21 "${testcvs} -q update -d sdir" "U sdir/sfile"
+ rm -r sdir/CVS
+ dotest conflicts3-22 "${testcvs} -q update" "${QUESTION} sdir"
+ if $remote; then
+ dotest_fail conflicts3-23 "${testcvs} -q update -PdA" \
+"${QUESTION} sdir
+${CPROG} update: move away \`sdir/sfile'; it is in the way
+C sdir/sfile"
+ else
+ dotest conflicts3-23 "${testcvs} -q update -PdA" \
+"${QUESTION} sdir"
+ fi
+
+ # Not that it should really affect much, but let's do the case
+ # where sfile has been removed. For example, suppose that sdir
+ # had been a CVS-controlled directory which was then removed
+ # by removing each file (and using update -P or some such). Then
+ # suppose that the build process creates an sdir directory which
+ # is not supposed to be under CVS.
+ rm -r sdir
+ dotest conflicts3-24 "${testcvs} -q update -d sdir" "U sdir/sfile"
+ rm sdir/sfile
+ dotest conflicts3-25 "${testcvs} rm sdir/sfile" \
+"${SPROG} remove: scheduling .sdir/sfile. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest conflicts3-26 "${testcvs} ci -m remove sdir/sfile" \
+"${CVSROOT_DIRNAME}/first-dir/sdir/sfile,v <-- sdir/sfile
+new revision: delete; previous revision: 1\.1"
+ rm -r sdir/CVS
+ dotest conflicts3-27 "${testcvs} -q update" "${QUESTION} sdir"
+ dotest conflicts3-28 "${testcvs} -q update -PdA" \
+"${QUESTION} sdir"
+
+ dokeep
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ clean)
+ # Test update -C (overwrite local mods w/ repository copies)
+ mkdir 1; cd 1
+ dotest clean-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest clean-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo "The usual boring test text." > cleanme.txt
+ dotest clean-3 "${testcvs} add cleanme.txt" \
+"${SPROG} add: scheduling file .cleanme\.txt. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest clean-4 "${testcvs} -q ci -m clean-3" \
+"$CVSROOT_DIRNAME/first-dir/cleanme\.txt,v <-- cleanme\.txt
+initial revision: 1\.1"
+ # Okay, preparation is done, now test.
+ # Check that updating an unmodified copy works.
+ dotest clean-5 "${testcvs} -q update" ''
+ # Check that updating -C an unmodified copy works.
+ dotest clean-6 "${testcvs} -q update -C" ''
+ # Check that updating a modified copy works.
+ echo "fish" >> cleanme.txt
+ dotest clean-7 "${testcvs} -q update" 'M cleanme\.txt'
+ # Check that updating -C a modified copy works.
+ dotest clean-8 "${testcvs} -q update -C" \
+"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1)
+U cleanme\.txt"
+ # And check that the backup copy really was made.
+ dotest clean-9 "cat .#cleanme.txt.1.1" \
+"The usual boring test text\.
+fish"
+
+ # Do it all again, this time naming the file explicitly.
+ rm .#cleanme.txt.1.1
+ dotest clean-10 "${testcvs} -q update cleanme.txt" ''
+ dotest clean-11 "${testcvs} -q update -C cleanme.txt" ''
+ echo "bluegill" >> cleanme.txt
+ dotest clean-12 "${testcvs} -q update cleanme.txt" 'M cleanme\.txt'
+ dotest clean-13 "${testcvs} -q update -C cleanme.txt" \
+"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1)
+U cleanme\.txt"
+ # And check that the backup copy really was made.
+ dotest clean-14 "cat .#cleanme.txt.1.1" \
+"The usual boring test text\.
+bluegill"
+
+ # Now try with conflicts
+ cd ..
+ dotest clean-15 "${testcvs} -q co -d second-dir first-dir" \
+'U second-dir/cleanme\.txt'
+ cd second-dir
+ echo "conflict test" >> cleanme.txt
+ dotest clean-16 "${testcvs} -q ci -m." \
+"$CVSROOT_DIRNAME/first-dir/cleanme\.txt,v <-- cleanme\.txt
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../first-dir
+ echo "fish" >> cleanme.txt
+ dotest clean-17 "${testcvs} -nq update" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/cleanme\.txt,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into cleanme\.txt
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in cleanme\.txt
+C cleanme\.txt"
+ dotest clean-18 "${testcvs} -q update -C" \
+"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1)
+U cleanme\.txt"
+ dotest clean-19 "cat .#cleanme.txt.1.1" \
+"The usual boring test text\.
+fish"
+
+ # Done. Clean up.
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ keywordexpand)
+ # Tests of the original *BSD tag= and keywordexpand= features
+ # are done via the LocalKeyword= and KeywordExpand features.
+
+ # Skip this in noredirect mode because it is too easy for the primary
+ # and secondary error messages to get out of sync when the
+ # CVSROOT/config files are broken. This is intentional, since it is
+ # possible and even likely that an administrator might want to set up
+ # different configurations on the two servers and the paths to the
+ # config files on the secondary and primary were intentionally left
+ # intact even though they might be different.
+ if $noredirect; then
+ notnoredirect keywordexpand
+ continue
+ fi
+
+ mkdir keywordexpand; cd keywordexpand
+
+ dotest keywordexpand-1 "${testcvs} -q co CVSROOT" \
+'U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg'
+ cd CVSROOT
+ echo LocalKeyword=MyBSD=CVSHeader >> config
+ # First do not expand any keywords
+ echo KeywordExpand=i >> config
+ dotest keywordexpand-2 "${testcvs} -Q ci -mkeywordexpand config"
+
+ cd ..
+
+ mkdir testimport; cd testimport
+ echo '$''Author$' > file1
+ echo '$''Date$' >> file1
+ echo '$''CVSHeader$' >> file1
+ echo '$''Header$' >> file1
+ echo '$''Id$' >> file1
+ echo '$''Locker$' >> file1
+ echo '$''Log$' >> file1
+ echo '$''Name$' >> file1
+ echo '$''RCSfile$' >> file1
+ echo '$''Revision$' >> file1
+ echo '$''Source$' >> file1
+ echo '$''State$' >> file1
+ echo '$''MyBSD$' >> file1
+ dotest keywordexpand-3 \
+"${testcvs} -Q import -I ! -m test-import-with-bsd-keyword keywordexpand vendor v1" \
+''
+ cd ..
+
+ dotest keywordexpand-4 "${testcvs} -Q checkout keywordexpand" ''
+ cd keywordexpand
+ dotest keywordexpand-5 "cat file1" \
+"\$""Author\$
+\$""Date\$
+\$""CVSHeader\$
+\$""Header\$
+\$""Id\$
+\$""Locker\$
+\$""Log\$
+\$""Name\$
+\$""RCSfile\$
+\$""Revision\$
+\$""Source\$
+\$""State\$
+\$MyBSD\$"
+ cd ../CVSROOT
+ # Now expand just the MyBSD and Id keywords
+ mv config config.old
+ sed -e 's/KeywordExpand=i/KeywordExpand=iMyBSD,Id/' < config.old > config
+ rm -f config.old
+ dotest keywordexpand-6 "${testcvs} -Q ci -mkeywordexpand config"
+ cd ../keywordexpand
+ echo 'a change' >> file1
+ dotest keywordexpand-7 "${testcvs} -Q ci -madd"
+ dotest keywordexpand-8 "cat file1" \
+"\$""Author\$
+\$""Date\$
+\$""CVSHeader\$
+\$""Header\$
+\$""Id: file1,v 1\.2 [0-9/]* [0-9:]* ${username} Exp \$
+\$""Locker\$
+\$""Log\$
+\$""Name\$
+\$""RCSfile\$
+\$""Revision\$
+\$""Source\$
+\$""State\$
+\$MyBSD: keywordexpand/file1,v 1\.2 [0-9/]* [0-9:]* ${username} Exp \$
+a change"
+
+ cd ../CVSROOT
+ mv config config.old
+ sed -e 's/LocalKeyword=MyBSD/LocalKeyword=My_BSD/' \
+ <config.old >config
+ dotest keywordexpand-9 "$testcvs -Q ci -minvalidlocalkeyword config"
+ dotest keywordexpand-10 "$testcvs -Q update config" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'"
+ cp config.old config
+ dotest keywordexpand-11 "$testcvs -Q ci -mfixit config" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'
+$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'"
+ dotest keywordexpand-12 "$testcvs -Q update config"
+ sed -e 's/LocalKeyword=MyBSD=CVSHeader/LocalKeyword=MyBSD=Name/' \
+ <config.old >config
+ dotest keywordexpand-13 \
+"$testcvs -Q ci -minvalidlocalkeyword2 config"
+ dotest keywordexpand-14 "$testcvs -Q update config" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'"
+ cp config.old config
+ dotest keywordexpand-15 "$testcvs -Q ci -mfixit2 config" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'
+$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'"
+ dotest keywordexpand-16 "$testcvs -Q update config"
+
+ dokeep
+ # Done. Clean up.
+ cd ../..
+ rm -rf $TESTDIR/keywordexpand
+ modify_repo rm -rf $CVSROOT_DIRNAME/keywordexpand
+ restore_adm
+ ;;
+
+
+
+ modules)
+ # Tests of various ways to define and use modules.
+ # Roadmap to various modules tests:
+ # -a:
+ # error on incorrect placement: modules
+ # error combining with other options: modules2-a*
+ # infinite loops: modules148a1.1 - modules148a1.2
+ # use to specify a file more than once: modules3
+ # use with ! feature: modules4
+ # regular modules: modules, modules2, cvsadm
+ # ampersand modules: modules2
+ # -s: modules.
+ # -d: modules, modules3, cvsadm
+ # -i, -o, -u, -e, -t: modules5
+ # slashes in module names: modules3
+ # invalid module definitions: modules6
+
+ ############################################################
+ # These tests are to make sure that administrative files get
+ # rebuilt, regardless of how and where files are checked
+ # out.
+ ############################################################
+ # Check out the whole repository
+ mkdir 1; cd 1
+ dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg'
+ echo "# made a change" >>CVSROOT/modules
+ dotest modules-1d "${testcvs} -q ci -m add-modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- CVSROOT/modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+ rm -rf 1
+
+ ############################################################
+ # Check out CVSROOT
+ mkdir 1; cd 1
+ dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg'
+ echo "# made a change" >>CVSROOT/modules
+ dotest modules-2d "${testcvs} -q ci -m add-modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- CVSROOT/modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+ rm -rf 1
+
+ ############################################################
+ # Check out CVSROOT in some other directory
+ modify_repo mkdir $CVSROOT_DIRNAME/somedir
+ mkdir 1; cd 1
+ dotest modules-3 "${testcvs} -q co somedir" ''
+ cd somedir
+ dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg'
+ echo "# made a change" >>CVSROOT/modules
+ dotest modules-3g "${testcvs} -q ci -m add-modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- CVSROOT/modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/somedir
+ ############################################################
+ # end rebuild tests
+ ############################################################
+
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+
+ mkdir 1
+ cd 1
+
+ dotest modules-143 "${testcvs} -q co first-dir" ""
+
+ cd first-dir
+ mkdir subdir
+ dotest modules-143a "${testcvs} add subdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"
+
+ cd subdir
+ mkdir ssdir
+ dotest modules-143b "${testcvs} add ssdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/subdir/ssdir added to the repository"
+
+ touch a b
+
+ dotest modules-144 "${testcvs} add a b" \
+"${SPROG} add: scheduling file .a. for addition
+${SPROG} add: scheduling file .b. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+
+ dotest modules-145 "$testcvs ci -m added" \
+"$CPROG commit: Examining .
+$CPROG commit: Examining ssdir
+$CVSROOT_DIRNAME/first-dir/subdir/a,v <-- a
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/subdir/b,v <-- b
+initial revision: 1\.1"
+
+ cd ..
+ dotest modules-146 "$testcvs -q co CVSROOT" \
+"U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg"
+
+ # Here we test that CVS can deal with CVSROOT (whose repository
+ # is at top level) in the same directory as subdir (whose repository
+ # is a subdirectory of first-dir). TODO: Might want to check that
+ # files can actually get updated in this state.
+ dotest modules-147 "$testcvs -q update"
+
+ cat >CVSROOT/modules <<EOF
+realmodule first-dir/subdir a
+dirmodule first-dir/subdir
+namedmodule -d nameddir first-dir/subdir
+aliasmodule -a first-dir/subdir/a
+aliasnested -a first-dir/subdir/ssdir
+topfiles -a first-dir/file1 first-dir/file2
+world -a .
+statusmod -s Mungeable
+# Check for ability to block infinite loops.
+infinitealias -a infinitealias
+# Prior to 1.11.12 & 1.12.6, the infinite alias loop check didn't strip
+# slashes or work if a module called a module which then called itself
+# (A -> A was blocked, but not A -> B -> A or deeper).
+infinitealias2 -a infinitealias2/
+infinitealias3 -a infinitealias4/
+infinitealias4 -a aliasmodule infinitealias5
+infinitealias5 -a infinitealias3/
+# Options must come before arguments. It is possible this should
+# be relaxed at some point (though the result would be bizarre for
+# -a); for now test the current behavior.
+bogusalias first-dir/subdir/a -a
+EOF
+ dotest modules-148 "$testcvs ci -m 'add modules' CVSROOT/modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- CVSROOT/modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ..
+ # The "statusmod" module contains an error; trying to use it
+ # will produce "modules file missing directory" I think.
+ # However, that shouldn't affect the ability of "cvs co -c" or
+ # "cvs co -s" to do something reasonable with it.
+ dotest modules-148a0 "$testcvs co -c" \
+'aliasmodule -a first-dir/subdir/a
+aliasnested -a first-dir/subdir/ssdir
+bogusalias first-dir/subdir/a -a
+dirmodule first-dir/subdir
+infinitealias -a infinitealias
+infinitealias2 -a infinitealias2/
+infinitealias3 -a infinitealias4/
+infinitealias4 -a aliasmodule infinitealias5
+infinitealias5 -a infinitealias3/
+namedmodule -d nameddir first-dir/subdir
+realmodule first-dir/subdir a
+statusmod -s Mungeable
+topfiles -a first-dir/file1 first-dir/file2
+world -a \.'
+ # There is code in modules.c:save_d which explicitly skips
+ # modules defined with -a, which is why aliasmodule is not
+ # listed.
+ dotest modules-148a1 "${testcvs} co -s" \
+'statusmod Mungeable
+bogusalias NONE first-dir/subdir/a -a
+dirmodule NONE first-dir/subdir
+namedmodule NONE first-dir/subdir
+realmodule NONE first-dir/subdir a'
+
+ # Check that infinite loops are avoided
+ dotest modules-148a1.1 "${testcvs} co infinitealias" \
+"$CPROG checkout: module \`infinitealias' in modules file contains infinite loop" \
+"$SPROG server: module \`infinitealias' in modules file contains infinite loop
+$SPROG checkout: module \`infinitealias' in modules file contains infinite loop"
+ # Prior to 1.11.12 & 1.12.6, the inifinte alias loop check did not
+ # strip slashes.
+ dotest modules-148a1.2 "${testcvs} co infinitealias2" \
+"$CPROG checkout: module \`infinitealias2' in modules file contains infinite loop" \
+"$SPROG server: module \`infinitealias2' in modules file contains infinite loop
+$SPROG checkout: module \`infinitealias2' in modules file contains infinite loop"
+ # Prior to 1.11.12 & 1.12.6, the inifinte alias loop check did not
+ # notice when A -> B -> A, it only noticed A -> A.
+ dotest modules-148a1.3 "${testcvs} co infinitealias3/" \
+"$CPROG checkout: module \`infinitealias3' in modules file contains infinite loop" \
+"$SPROG server: module \`infinitealias3' in modules file contains infinite loop
+$SPROG checkout: module \`infinitealias3' in modules file contains infinite loop"
+
+ # Test that real modules check out to realmodule/a, not subdir/a.
+ dotest modules-149a1 "${testcvs} co realmodule" "U realmodule/a"
+ dotest modules-149a2 "test -d realmodule && test -f realmodule/a" ""
+ dotest_fail modules-149a3 "test -f realmodule/b" ""
+ dotest modules-149a4 "${testcvs} -q co realmodule" ""
+ dotest modules-149a5 "echo yes | ${testcvs} release -d realmodule" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .realmodule.: "
+
+ dotest_fail modules-149b1 "${testcvs} co realmodule/a" \
+"${SPROG}"' checkout: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \
+"${SPROG}"' server: module `realmodule/a'\'' is a request for a file in a module which is not a directory
+'"${CPROG}"' \[checkout aborted\]: cannot expand modules'
+
+ # Now test the ability to check out a single file from a directory
+ dotest modules-150c "${testcvs} co dirmodule/a" "U dirmodule/a"
+ dotest modules-150d "test -d dirmodule && test -f dirmodule/a" ""
+ dotest_fail modules-150e "test -f dirmodule/b" ""
+ dotest modules-150f "echo yes | ${testcvs} release -d dirmodule" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .dirmodule.: "
+ # Now test the ability to correctly reject a non-existent filename.
+ # For maximum studliness we would check that an error message is
+ # being output.
+ # We accept a zero exit status because it is what CVS does
+ # (Dec 95). Probably the exit status should be nonzero,
+ # however.
+ dotest modules-150g1 "${testcvs} co dirmodule/nonexist" \
+"${SPROG} checkout: warning: new-born \`dirmodule/nonexist' has disappeared"
+ # We tolerate the creation of the dirmodule directory, since that
+ # is what CVS does, not because we view that as preferable to not
+ # creating it.
+ dotest_fail modules-150g2 "test -f dirmodule/a || test -f dirmodule/b" ""
+ rm -r dirmodule
+
+ # Now test that a module using -d checks out to the specified
+ # directory.
+ dotest modules-150h1 "${testcvs} -q co namedmodule" \
+'U nameddir/a
+U nameddir/b'
+ dotest modules-150h2 "test -f nameddir/a && test -f nameddir/b" ""
+ echo add line >>nameddir/a
+ dotest modules-150h3 "${testcvs} -q co namedmodule" 'M nameddir/a'
+ rm nameddir/a
+ dotest modules-150h4 "${testcvs} -q co namedmodule" 'U nameddir/a'
+ dotest modules-150h99 "echo yes | ${testcvs} release -d nameddir" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .nameddir.: "
+
+ # Now test that alias modules check out to subdir/a, not
+ # aliasmodule/a.
+ dotest modules-151 "${testcvs} co aliasmodule" ""
+ dotest_fail modules-152 "test -d aliasmodule" ""
+ echo abc >>first-dir/subdir/a
+ dotest modules-153 "${testcvs} -q co aliasmodule" "M first-dir/subdir/a"
+
+ cd ..
+ rm -r 1
+
+ mkdir 2
+ cd 2
+ dotest modules-155a0 "${testcvs} co aliasnested" \
+"${SPROG} checkout: Updating first-dir/subdir/ssdir"
+ dotest modules-155a1 "test -d first-dir" ''
+ dotest modules-155a2 "test -d first-dir/subdir" ''
+ dotest modules-155a3 "test -d first-dir/subdir/ssdir" ''
+ # Test that nothing extraneous got created.
+ dotest modules-155a4 "ls" "first-dir" \
+"CVS
+first-dir"
+ cd ..
+ rm -r 2
+
+ # Test checking out everything.
+ mkdir 1
+ cd 1
+ dotest modules-155b "${testcvs} -q co world" \
+"U CVSROOT/${DOTSTAR}
+U first-dir/subdir/a
+U first-dir/subdir/b"
+ cd ..
+ rm -r 1
+
+ # Test checking out a module which lists at least two
+ # specific files twice. At one time, this failed over
+ # remote CVS.
+ mkdir 1
+ cd 1
+ dotest modules-155c1 "${testcvs} -q co first-dir" \
+"U first-dir/subdir/a
+U first-dir/subdir/b"
+
+ cd first-dir
+ echo 'first revision' > file1
+ echo 'first revision' > file2
+ dotest modules-155c2 "${testcvs} add file1 file2" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: scheduling file `file2'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
+ dotest modules-155c3 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+
+ cd ..
+ rm -r first-dir
+ dotest modules-155c4 "${testcvs} -q co topfiles" \
+"U first-dir/file1
+U first-dir/file2"
+ dotest modules-155c5 "${testcvs} -q co topfiles" ""
+
+ # Make sure the right thing happens if we remove a file.
+ cd first-dir
+ dotest modules-155c6 "${testcvs} -q rm -f file1" \
+"${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest modules-155c7 "${testcvs} -q ci -m remove-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1"
+ cd ..
+ rm -r first-dir
+ dotest modules-155c8 "${testcvs} -q co topfiles" \
+"${SPROG} checkout: warning: \`first-dir/file1' is not (any longer) pertinent
+U first-dir/file2"
+
+ dokeep
+ cd ..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ modules2)
+ # More tests of modules, in particular the & feature.
+ mkdir 1; cd 1
+ dotest modules2-setup-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir second-dir third-dir
+ dotest modules2-setup-2 \
+"${testcvs} add first-dir second-dir third-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository
+Directory ${CVSROOT_DIRNAME}/second-dir added to the repository
+Directory ${CVSROOT_DIRNAME}/third-dir added to the repository"
+ cd third-dir
+ touch file3
+ dotest modules2-setup-3 "${testcvs} add file3" \
+"${SPROG} add: scheduling file .file3. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest modules2-setup-4 "${testcvs} -q ci -m add file3" \
+"$CVSROOT_DIRNAME/third-dir/file3,v <-- file3
+initial revision: 1\.1"
+ cd ../..
+ rm -r 1
+
+ mkdir 1
+ cd 1
+
+ dotest modules2-1 "${testcvs} -q co CVSROOT/modules" \
+'U CVSROOT/modules'
+ cd CVSROOT
+ cat >> modules << EOF
+ampermodule &first-dir &second-dir
+combmodule third-dir file3 &first-dir
+ampdirmod -d newdir &first-dir &second-dir
+badmod -d newdir
+messymod first-dir &messymodchild
+messymodchild -d sdir/child second-dir
+EOF
+ # Depending on whether the user also ran the modules test
+ # we will be checking in revision 1.2 or 1.3.
+ dotest modules2-2 "${testcvs} -q ci -m add-modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ..
+
+ dotest modules2-3 "${testcvs} -q co ampermodule" ''
+ dotest modules2-4 "test -d ampermodule/first-dir" ''
+ dotest modules2-5 "test -d ampermodule/second-dir" ''
+
+ # Test ability of cvs release to handle multiple arguments
+ # See comment at "release" for list of other cvs release tests.
+ cd ampermodule
+ if ${testcvs} release -d first-dir second-dir <<EOF >>${LOGFILE}
+yes
+yes
+EOF
+ then
+ pass modules2-6
+ else
+ fail modules2-6
+ fi
+ dotest_fail modules2-7 "test -d first-dir" ''
+ dotest_fail modules2-8 "test -d second-dir" ''
+
+ cd ..
+
+ # There used to be a nasty-hack that made CVS skip creation of the
+ # module dir (in this case ampermodule) when -n was specified
+ dotest modules2-ampermod-1 "${testcvs} -q co -n ampermodule" ''
+ dotest modules2-ampermod-2 "test -d ampermodule/first-dir" ''
+ dotest modules2-ampermod-3 "test -d ampermodule/second-dir" ''
+
+ # Test release of a module
+ if echo yes |${testcvs} release -d ampermodule >>${LOGFILE}; then
+ pass modules2-ampermod-release-1
+ else
+ fail modules2-ampermod-release-1
+ fi
+ dotest_fail modules2-ampermod-release-2 "test -d ampermodule" ''
+
+ # and the '-n' test again, but in conjunction with '-d'
+ dotest modules2-ampermod-4 "${testcvs} -q co -n -d newname ampermodule" ''
+ dotest modules2-ampermod-5 "test -d newname/first-dir" ''
+ dotest modules2-ampermod-6 "test -d newname/second-dir" ''
+ rm -rf newname
+
+ # Now we create another directory named first-dir and make
+ # sure that CVS doesn't get them mixed up.
+ mkdir first-dir
+ # Note that this message should say "Updating ampermodule/first-dir"
+ # I suspect. This is a long-standing behavior/bug....
+ dotest modules2-9 "${testcvs} co ampermodule" \
+"${SPROG} checkout: Updating first-dir
+${SPROG} checkout: Updating second-dir"
+ touch ampermodule/first-dir/amper1
+ cd ampermodule
+ dotest modules2-10 "${testcvs} add first-dir/amper1" \
+"${SPROG} add: scheduling file .first-dir/amper1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cd ..
+
+ # As with the "Updating xxx" message, the "U first-dir/amper1"
+ # message (instead of "U ampermodule/first-dir/amper1") is
+ # rather fishy.
+ dotest modules2-12 "${testcvs} co ampermodule" \
+"${SPROG} checkout: Updating first-dir
+A first-dir/amper1
+${SPROG} checkout: Updating second-dir"
+
+ if $remote; then
+ dotest modules2-13r "$testcvs -q ci -m add-it ampermodule" \
+"$CVSROOT_DIRNAME/first-dir/amper1,v <-- ampermodule/first-dir/amper1
+initial revision: 1\.1"
+ else
+ # Trying this as above led to a "protocol error" message.
+ # Work around this bug.
+ cd ampermodule
+ dotest modules2-13 "$testcvs -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/amper1,v <-- first-dir/amper1
+initial revision: 1\.1"
+ cd ..
+ fi
+ cd ..
+ rm -r 1
+
+ # Now test the "combmodule" module (combining regular modules
+ # and ampersand modules in the same module definition).
+ mkdir 1; cd 1
+ dotest modules2-14 "${testcvs} co combmodule" \
+"U combmodule/file3
+${SPROG} checkout: Updating first-dir
+U first-dir/amper1"
+ dotest modules2-15 "test -f combmodule/file3" ""
+ dotest modules2-16 "test -f combmodule/first-dir/amper1" ""
+ cd combmodule
+ rm -r first-dir
+ # At least for now there is no way to tell CVS that
+ # some files/subdirectories come from one repository directory,
+ # and others from another.
+ # This seems like a pretty sensible behavior to me, in the
+ # sense that first-dir doesn't "really" exist within
+ # third-dir, so CVS just acts as if there is nothing there
+ # to do.
+ dotest modules2-17 "${testcvs} update -d" \
+"${SPROG} update: Updating \."
+
+ cd ..
+ dotest modules2-18 "${testcvs} -q co combmodule" \
+"U first-dir/amper1"
+ dotest modules2-19 "test -f combmodule/first-dir/amper1" ""
+ cd ..
+ rm -r 1
+
+ # Now test the "ampdirmod" and "badmod" modules to be sure that
+ # options work with ampersand modules but don't prevent the
+ # "missing directory" error message.
+ mkdir 1; cd 1
+ dotest modules2-20 "${testcvs} co ampdirmod" \
+"${SPROG} checkout: Updating first-dir
+U first-dir/amper1
+${SPROG} checkout: Updating second-dir"
+ dotest modules2-21 "test -f newdir/first-dir/amper1" ""
+ dotest modules2-22 "test -d newdir/second-dir" ""
+ dotest_fail modules2-23 "${testcvs} co badmod" \
+"${SPROG} checkout: modules file missing directory for module badmod" \
+"${SPROG} server: modules file missing directory for module badmod
+${CPROG} \[checkout aborted\]: cannot expand modules"
+ cd ..
+ rm -r 1
+
+ # Confirm that a rename with added depth nested in an ampersand
+ # module works.
+ mkdir 1; cd 1
+ dotest modules2-nestedrename-1 "${testcvs} -q co messymod" \
+"U messymod/amper1"
+ dotest modules2-nestedrename-2 "test -d messymod/sdir" ''
+ dotest modules2-nestedrename-3 "test -d messymod/sdir/CVS" ''
+ dotest modules2-nestedrename-4 "test -d messymod/sdir/child" ''
+ dotest modules2-nestedrename-5 "test -d messymod/sdir/child/CVS" ''
+ cd ..; rm -r 1
+
+ # FIXME: client/server has a bug. It should be working like a local
+ # repository in this case, but fails to check out the second module
+ # in the list when a branch is specified.
+ mkdir 1; cd 1
+ dotest modules2-ampertag-setup-1 \
+"${testcvs} -Q rtag tag first-dir second-dir third-dir" \
+''
+ dotest modules2-ampertag-1 "${testcvs} -q co -rtag ampermodule" \
+"U first-dir/amper1"
+ if $remote; then
+ dotest_fail modules2-ampertag-2 "test -d ampermodule/second-dir" ''
+ dotest_fail modules2-ampertag-3 "test -d ampermodule/second-dir/CVS" ''
+ else
+ dotest modules2-ampertag-2 "test -d ampermodule/second-dir" ''
+ dotest modules2-ampertag-3 "test -d ampermodule/second-dir/CVS" ''
+ fi
+ cd ..; rm -r 1
+
+ # Test for tag files when an ampermod is renamed with more path
+ # elements than it started with.
+ #
+ # FIXME: This is currently broken in the remote case, possibly only
+ # because the messymodchild isn't being checked out at all.
+ mkdir 1; cd 1
+# dotest modules2-tagfiles-setup-1 \
+#"${testcvs} -Q rtag -b branch first-dir second-dir" \
+#''
+ dotest modules2-tagfiles-1 "${testcvs} -q co -rtag messymod" \
+"U messymod/amper1"
+ if $remote; then
+ dotest_fail modules2-tagfiles-2r "test -d messymod/sdir" ''
+ else
+ dotest modules2-tagfiles-2 "cat messymod/sdir/CVS/Tag" 'Ttag'
+ fi
+ cd ..; rm -r 1
+
+ # Test that CVS gives an error if one combines -a with
+ # other options.
+ # Probably would be better to break this out into a separate
+ # test. Although it is short, it shares no files/state with
+ # the rest of the modules2 tests.
+ mkdir 1; cd 1
+ dotest modules2-a0.5 "${testcvs} -q co CVSROOT/modules" \
+'U CVSROOT/modules'
+ cd CVSROOT
+ echo 'aliasopt -a -d onedir first-dir' >modules
+ dotest modules2-a0 "${testcvs} -q ci -m add-modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+ dotest_fail modules2-a1 "${testcvs} -q co aliasopt" \
+"${SPROG} checkout: -a cannot be specified in the modules file along with other options" \
+"${SPROG} server: -a cannot be specified in the modules file along with other options
+${CPROG} \[checkout aborted\]: cannot expand modules"
+ cd ..; rm -r 1
+
+ # Clean up.
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir \
+ $CVSROOT_DIRNAME/third-dir
+ ;;
+
+
+
+ modules3)
+ # More tests of modules, in particular what happens if several
+ # modules point to the same file.
+
+ # First just set up a directory first-dir and a file file1 in it.
+ mkdir 1; cd 1
+
+ dotest modules3-0 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest modules3-1 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+
+ cd first-dir
+ echo file1 >file1
+ dotest modules3-2 "${testcvs} add file1" \
+"${SPROG} add: scheduling file \`file1' for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ dotest modules3-3 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ cd ..
+
+ dotest modules3-4 "${testcvs} -q update -d CVSROOT" \
+"U CVSROOT${DOTSTAR}"
+ cd CVSROOT
+ cat >modules <<EOF
+mod1 -a first-dir/file1
+bigmod -a mod1 first-dir/file1
+namednest -d src/sub/dir first-dir
+nestdeeper -d src/sub1/sub2/sub3/dir first-dir
+nestshallow -d src/dir second-dir/suba/subb
+path/in/modules &mod1
+another/path/test -d another/path/test first-dir
+EOF
+ dotest modules3-5 "${testcvs} -q ci -m add-modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+
+ dotest modules3-6 "${testcvs} -q co bigmod" ''
+ rm -r first-dir
+ dotest modules3-7 "${testcvs} -q co bigmod" 'U first-dir/file1'
+ cd ..
+ rm -r 1
+
+ mkdir 1; cd 1
+ mkdir suba
+ mkdir suba/subb
+ # This fails to work remote (it doesn't notice the directories,
+ # I suppose because they contain no files). Bummer, especially
+ # considering this is a documented technique and everything.
+ dotest modules3-7a \
+"${testcvs} import -m add-dirs second-dir tag1 tag2" \
+"${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/suba
+${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/suba/subb
+
+No conflicts created by this import" "
+No conflicts created by this import"
+ cd ..; rm -r 1
+ mkdir 1; cd 1
+ dotest modules3-7b "${testcvs} co second-dir" \
+"${SPROG} checkout: Updating second-dir
+${SPROG} checkout: Updating second-dir/suba
+${SPROG} checkout: Updating second-dir/suba/subb" \
+"${SPROG} checkout: Updating second-dir"
+
+ if $remote; then
+ cd second-dir
+ mkdir suba
+ dotest modules3-7-workaround1 "${testcvs} add suba" \
+"Directory ${CVSROOT_DIRNAME}/second-dir/suba added to the repository"
+ cd suba
+ mkdir subb
+ dotest modules3-7-workaround2 "${testcvs} add subb" \
+"Directory ${CVSROOT_DIRNAME}/second-dir/suba/subb added to the repository"
+ cd ../..
+ fi
+
+ cd second-dir/suba/subb
+ touch fileb
+ dotest modules3-7c "${testcvs} add fileb" \
+"${SPROG} add: scheduling file .fileb. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest modules3-7d "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/second-dir/suba/subb/fileb,v <-- fileb
+initial revision: 1\.1"
+ cd ../../..
+ cd ..; rm -r 1
+
+ mkdir 1
+ cd 1
+ dotest modules3-8 "${testcvs} -q co namednest" \
+'U src/sub/dir/file1'
+ dotest modules3-9 "test -f src/sub/dir/file1" ''
+ cd ..
+ rm -r 1
+
+ # Try the same thing, but with the directories nested even
+ # deeper (deeply enough so they are nested more deeply than
+ # the number of directories from / to ${TESTDIR}).
+ mkdir 1
+ cd 1
+ dotest modules3-10 "${testcvs} -q co nestdeeper" \
+'U src/sub1/sub2/sub3/dir/file1'
+ dotest modules3-11 "test -f src/sub1/sub2/sub3/dir/file1" ''
+
+ # While we are doing things like twisted uses of '/' (e.g.
+ # modules3-12), try this one.
+ if $remote; then
+ dotest_fail modules3-11b \
+"${testcvs} -q update ${TESTDIR}/1/src/sub1/sub2/sub3/dir/file1" \
+"absolute pathnames invalid for server (specified .${TESTDIR}/1/src/sub1/sub2/sub3/dir.)"
+ fi # end of remote-only tests
+
+ cd ..
+ rm -r 1
+
+ # This one is almost too twisted for words. The pathname output
+ # in the message from "co" doesn't include the "path/in/modules",
+ # but those directories do get created (with no CVSADM except
+ # in "modules" which has a CVSNULLREPOS).
+ # I'm not sure anyone is relying on this nonsense or whether we
+ # need to keep doing it, but it is what CVS currently does...
+ # Skip it for remote; the remote code has the good sense to
+ # not deal with it (on the minus side it gives
+ # "internal error: repository string too short." (CVS 1.9) or
+ # "warning: server is not creating directories one at a time" (now)
+ # instead of a real error).
+ # I'm tempted to just make it a fatal error to have '/' in a
+ # module name. But see comments at modules3-16.
+ if $remote; then :; else
+ mkdir 1; cd 1
+ dotest modules3-12 "${testcvs} -q co path/in/modules" \
+"U first-dir/file1"
+ dotest modules3-13 "test -f path/in/modules/first-dir/file1" ''
+ cd ..; rm -r 1
+ fi # end of tests skipped for remote
+
+ # Now here is where it used to get seriously bogus.
+ mkdir 1; cd 1
+ dotest modules3-14 \
+"${testcvs} -q rtag tag1 path/in/modules" ''
+ # CVS used to create this even though rtag should *never* affect
+ # the directory current when it is called!
+ dotest_fail modules3-15 "test -d path/in/modules" ''
+ # Just for trivia's sake, rdiff was not similarly vulnerable
+ # because it passed 0 for run_module_prog to do_module.
+ cd ..; rm -r 1
+
+ # Some people seem to want this to work. I still suspect there
+ # are dark corners in slashes in module names. This probably wants
+ # more thought before we start hacking on CVS (one way or the other)
+ # or documenting this.
+ mkdir 2; cd 2
+ dotest modules3-16 "${testcvs} -q co another/path/test" \
+"U another/path/test/file1"
+ dotest modules3-17 "cat another/path/test/file1" 'file1'
+
+ dokeep
+ cd ..; rm -r 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ modules4)
+ # Some tests using the modules file with aliases that
+ # exclude particular directories.
+
+ mkdir 1; cd 1
+
+ dotest modules4-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest modules4-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+
+ cd first-dir
+ mkdir subdir subdir_long
+ dotest modules4-3 "${testcvs} add subdir subdir_long" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository
+Directory ${CVSROOT_DIRNAME}/first-dir/subdir_long added to the repository"
+
+ echo file1 > file1
+ dotest modules4-4 "${testcvs} add file1" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+
+ echo file2 > subdir/file2
+ dotest modules4-5 "${testcvs} add subdir/file2" \
+"${SPROG}"' add: scheduling file `subdir/file2'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+
+ echo file3 > subdir_long/file3
+ dotest modules4-6 "${testcvs} add subdir_long/file3" \
+"${SPROG}"' add: scheduling file `subdir_long/file3'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+
+ dotest modules4-7 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/subdir/file2,v <-- subdir/file2
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/subdir_long/file3,v <-- subdir_long/file3
+initial revision: 1\.1"
+
+ cd ..
+
+ dotest modules4-8 "${testcvs} -q update -d CVSROOT" \
+"U CVSROOT${DOTSTAR}"
+ cd CVSROOT
+ cat >modules <<EOF
+all -a first-dir
+some -a !first-dir/subdir first-dir
+other -a !first-dir/subdir !first-dir/subdir_long first-dir
+somewhat -a first-dir !first-dir/subdir
+EOF
+ dotest modules4-9 "${testcvs} -q ci -m add-modules" \
+"$CVSROOT_DIRNAME/CVSROOT/modules,v <-- modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+
+ cd ..
+ mkdir 2; cd 2
+
+ dotest modules4-10 "${testcvs} -q co all" \
+"U first-dir/file1
+U first-dir/subdir/file2
+U first-dir/subdir_long/file3"
+ rm -r first-dir
+
+ dotest modules4-11 "${testcvs} -q co some" \
+"U first-dir/file1
+U first-dir/subdir_long/file3"
+ dotest_fail modules4-12 "test -d first-dir/subdir" ''
+ dotest modules4-13 "test -d first-dir/subdir_long" ''
+ rm -r first-dir
+
+ if $remote; then
+ # But remote seems to do it the other way.
+ dotest modules4-14r-1 "${testcvs} -q co somewhat" \
+"U first-dir/file1
+U first-dir/subdir_long/file3"
+ dotest_fail modules4-14r-2 "test -d first-dir/subdir" ''
+ dotest modules4-14r-3 "test -d first-dir/subdir_long" ''
+ else
+ # This is strange behavior, in that the order of the
+ # "!first-dir/subdir" and "first-dir" matter, and it isn't
+ # clear that they should. I suspect it is long-standing
+ # strange behavior but I haven't verified that.
+ dotest modules4-14-1 "${testcvs} -q co somewhat" \
+"U first-dir/file1
+U first-dir/subdir/file2
+U first-dir/subdir_long/file3"
+ dotest modules4-14-2 "test -d first-dir/subdir" ''
+ dotest modules4-14-3 "test -d first-dir/subdir_long" ''
+ fi
+ rm -r first-dir
+
+ dotest modules4-15 "${testcvs} -q co other" \
+"U first-dir/file1"
+ dotest_fail modules4-16 "test -d first-dir/subdir" ''
+ dotest_fail modules4-17 "test -d first-dir/subdir_long" ''
+ rm -r first-dir
+
+ cd ..
+ rm -r 2
+
+ dotest modules4-18 "${testcvs} rtag tag some" \
+"${SPROG} rtag: Tagging first-dir
+${SPROG} rtag: Ignoring first-dir/subdir
+${SPROG} rtag: Tagging first-dir/subdir_long"
+
+ cd 1/first-dir/subdir
+ dotest modules4-19 "${testcvs} log file2" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/file2,v
+Working file: file2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+add-it
+============================================================================="
+
+ dokeep
+ cd ../../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ modules5)
+ # Test module programs
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1
+ cd 1
+ dotest modules5-1 "$testcvs -q co first-dir"
+ cd first-dir
+ mkdir subdir
+ dotest modules5-2 "${testcvs} add subdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"
+ cd subdir
+ mkdir ssdir
+ dotest modules5-3 "${testcvs} add ssdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/subdir/ssdir added to the repository"
+ touch a b
+ dotest modules5-4 "${testcvs} add a b" \
+"${SPROG} add: scheduling file .a. for addition
+${SPROG} add: scheduling file .b. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+
+ dotest modules5-5 "${testcvs} ci -m added" \
+"${CPROG} commit: Examining .
+${CPROG} commit: Examining ssdir
+${CVSROOT_DIRNAME}/first-dir/subdir/a,v <-- a
+initial revision: 1\.1
+${CVSROOT_DIRNAME}/first-dir/subdir/b,v <-- b
+initial revision: 1\.1"
+
+ cd ..
+ dotest modules5-6 "${testcvs} -q co CVSROOT" \
+"U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg"
+
+ # FIXCVS: The sleep in the following script helps avoid out of
+ # order messages, but we really need to figure out how to fix
+ # cvs to prevent them in the first place.
+ for i in checkout export tag; do
+ cat >> ${CVSROOT_DIRNAME}/$i.sh <<EOF
+#! $TESTSHELL
+sleep 1
+echo "$i script invoked in \`pwd\`"
+echo "args: \$@"
+EOF
+ # Cygwin doesn't set premissions correctly over the Samba share.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x ${CVSROOT_DIRNAME}/$i.sh"
+ else
+ chmod +x ${CVSROOT_DIRNAME}/$i.sh
+ fi
+ done
+
+ OPTS="-o${CVSROOT_DIRNAME}/checkout.sh -e ${CVSROOT_DIRNAME}/export.sh -t${CVSROOT_DIRNAME}/tag.sh"
+ cat >CVSROOT/modules <<EOF
+realmodule ${OPTS} first-dir/subdir a
+dirmodule ${OPTS} first-dir/subdir
+namedmodule -d nameddir ${OPTS} first-dir/subdir
+EOF
+
+ dotest modules5-7 "$testcvs -Q ci -m 'add modules' CVSROOT/modules"
+
+ cd ..
+ rm -rf first-dir
+
+ # Test that real modules check out to realmodule/a, not subdir/a.
+ if $remote; then
+ # FIXCVS?
+ # Mac OSX 10.3 (Darwin ppc-osx1 5.5) fails here when $TMPDIR
+ # contains a symlink (it does not fail the local modules5-8).
+ # Since no other platforms are exhibiting the same problem, I
+ # suspect an issue with OSX and fork() or the like dereferencing
+ # the symlink, but it is possible it is something that could be
+ # fixed or worked around in CVS.
+ dotest modules5-8r "$testcvs co realmodule" \
+"U realmodule/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .realmodule..
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: realmodule"
+ else
+ dotest modules5-8 "${testcvs} co realmodule" \
+"U realmodule/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .realmodule..
+checkout script invoked in ${TESTDIR}/1
+args: realmodule"
+ fi
+ dotest modules5-9 "test -d realmodule && test -f realmodule/a" ""
+ dotest_fail modules5-10 "test -f realmodule/b" ""
+ if $remote; then
+ dotest modules5-11 "${testcvs} -q co realmodule" \
+"checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: realmodule"
+ dotest modules5-12 "${testcvs} -q update" ''
+ echo "change" >>realmodule/a
+ dotest modules5-13 "${testcvs} -q ci -m." \
+"$CVSROOT_DIRNAME/first-dir/subdir/a,v <-- realmodule/a
+new revision: 1\.2; previous revision: 1\.1"
+ else
+ dotest modules5-11 "${testcvs} -q co realmodule" \
+"checkout script invoked in ${TESTDIR}/1
+args: realmodule"
+ dotest modules5-12 "${testcvs} -q update" ''
+ echo "change" >>realmodule/a
+ dotest modules5-13 "${testcvs} -q ci -m." \
+"$CVSROOT_DIRNAME/first-dir/subdir/a,v <-- realmodule/a
+new revision: 1\.2; previous revision: 1\.1"
+ fi
+ dotest modules5-14 "echo yes | ${testcvs} release -d realmodule" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .realmodule.: "
+ dotest modules5-15 "${testcvs} -q rtag -Dnow MYTAG realmodule" \
+"tag script invoked in ${TESTDIR}/1
+args: realmodule MYTAG" \
+"tag script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: realmodule MYTAG"
+ if $remote; then
+ dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \
+"U realmodule/a
+export script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: realmodule"
+ else
+ dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \
+"U realmodule/a
+export script invoked in ${TESTDIR}/1
+args: realmodule"
+ fi
+ rm -r realmodule
+
+ dotest_fail modules5-17 "${testcvs} co realmodule/a" \
+"${SPROG}"' checkout: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \
+"${SPROG}"' server: module `realmodule/a'\'' is a request for a file in a module which is not a directory
+'"${CPROG}"' \[checkout aborted\]: cannot expand modules'
+
+ # Now test the ability to check out a single file from a directory
+ if $remote; then
+ dotest modules5-18 "${testcvs} co dirmodule/a" \
+"U dirmodule/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: dirmodule"
+ else
+ dotest modules5-18 "${testcvs} co dirmodule/a" \
+"U dirmodule/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
+checkout script invoked in ${TESTDIR}/1
+args: dirmodule"
+ fi
+ dotest modules5-19 "test -d dirmodule && test -f dirmodule/a" ""
+ dotest_fail modules5-20 "test -f dirmodule/b" ""
+ dotest modules5-21 "echo yes | ${testcvs} release -d dirmodule" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .dirmodule.: "
+
+ # Now test the ability to correctly reject a non-existent filename.
+ # For maximum studliness we would check that an error message is
+ # being output.
+ # We accept a zero exit status because it is what CVS does
+ # (Dec 95). Probably the exit status should be nonzero,
+ # however.
+ if $remote; then
+ dotest modules5-22 "${testcvs} co dirmodule/nonexist" \
+"${SPROG} checkout: warning: new-born \`dirmodule/nonexist' has disappeared
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: dirmodule"
+ else
+ dotest modules5-22 "${testcvs} co dirmodule/nonexist" \
+"${SPROG} checkout: warning: new-born \`dirmodule/nonexist' has disappeared
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
+checkout script invoked in ${TESTDIR}/1
+args: dirmodule"
+ fi
+ # We tolerate the creation of the dirmodule directory, since that
+ # is what CVS does, not because we view that as preferable to not
+ # creating it.
+ dotest_fail modules5-23 "test -f dirmodule/a || test -f dirmodule/b" ""
+ rm -r dirmodule
+
+ # Now test that a module using -d checks out to the specified
+ # directory.
+ if $remote; then
+ dotest modules5-24 "${testcvs} -q co namedmodule" \
+"U nameddir/a
+U nameddir/b
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: nameddir"
+ else
+ dotest modules5-24 "${testcvs} -q co namedmodule" \
+"U nameddir/a
+U nameddir/b
+checkout script invoked in ${TESTDIR}/1
+args: nameddir"
+ fi
+ dotest modules5-25 "test -f nameddir/a && test -f nameddir/b" ""
+ echo add line >>nameddir/a
+ # This seems suspicious: when we checkout an existing directory,
+ # the checkout script gets executed in addition to the update
+ # script. Is that by design or accident?
+ if $remote; then
+ dotest modules5-26 "${testcvs} -q co namedmodule" \
+"M nameddir/a
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: nameddir"
+ else
+ dotest modules5-26 "${testcvs} -q co namedmodule" \
+"M nameddir/a
+checkout script invoked in ${TESTDIR}/1
+args: nameddir"
+ fi
+ rm nameddir/a
+
+ if $remote; then
+ dotest modules5-27 "${testcvs} -q co namedmodule" \
+"U nameddir/a
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: nameddir"
+ else
+ dotest modules5-27 "${testcvs} -q co namedmodule" \
+"U nameddir/a
+checkout script invoked in ${TESTDIR}/1
+args: nameddir"
+ fi
+ dotest modules5-28 "echo yes | ${testcvs} release -d nameddir" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .nameddir.: "
+
+ # Now try the same tests with -d on command line
+ # FIXCVS? The manual says the modules programs get the module name,
+ # but they really get the directory name.
+ if $remote; then
+ dotest modules5-29 "${testcvs} co -d mydir realmodule" \
+"U mydir/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ else
+ dotest modules5-29 "${testcvs} co -d mydir realmodule" \
+"U mydir/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
+checkout script invoked in ${TESTDIR}/1
+args: mydir"
+ fi
+ dotest modules5-30 "test -d mydir && test -f mydir/a" ""
+ dotest_fail modules5-31 "test -d realmodule || test -f mydir/b" ""
+ if $remote; then
+ dotest modules5-32 "${testcvs} -q co -d mydir realmodule" \
+"checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ dotest modules5-33 "${testcvs} -q update" ''
+ echo "change" >>mydir/a
+ dotest modules5-34 "${testcvs} -q ci -m." \
+"$CVSROOT_DIRNAME/first-dir/subdir/a,v <-- mydir/a
+new revision: 1\.3; previous revision: 1\.2"
+ else
+ dotest modules5-32 "${testcvs} -q co -d mydir realmodule" \
+"checkout script invoked in ${TESTDIR}/1
+args: mydir"
+ dotest modules5-33 "${testcvs} -q update" ''
+ echo "change" >>mydir/a
+ dotest modules5-34 "${testcvs} -q ci -m." \
+"$CVSROOT_DIRNAME/first-dir/subdir/a,v <-- mydir/a
+new revision: 1\.3; previous revision: 1\.2"
+ fi
+ dotest modules5-35 "echo yes | ${testcvs} release -d mydir" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .mydir.: "
+ if $remote; then
+ dotest modules5-36 "${testcvs} -q rtag -Dnow MYTAG2 realmodule" \
+"tag script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: realmodule MYTAG2"
+ dotest modules5-37 "${testcvs} -q export -r MYTAG2 -d mydir realmodule" \
+"U mydir/a
+export script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ else
+ dotest modules5-36 "${testcvs} -q rtag -Dnow MYTAG2 realmodule" \
+"tag script invoked in ${TESTDIR}/1
+args: realmodule MYTAG2"
+ dotest modules5-37 "${testcvs} -q export -r MYTAG2 -d mydir realmodule" \
+"U mydir/a
+export script invoked in ${TESTDIR}/1
+args: mydir"
+ fi
+ rm -r mydir
+
+ # Now test the ability to check out a single file from a directory
+ if $remote; then
+ dotest modules5-38 "${testcvs} co -d mydir dirmodule/a" \
+"U mydir/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ else
+ dotest modules5-38 "${testcvs} co -d mydir dirmodule/a" \
+"U mydir/a
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
+checkout script invoked in ${TESTDIR}/1
+args: mydir"
+ fi
+ dotest modules5-39 "test -d mydir && test -f mydir/a" ""
+ dotest_fail modules5-40 "test -d dirmodule || test -f mydir/b" ""
+ dotest modules5-41 "echo yes | ${testcvs} release -d mydir" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .mydir.: "
+
+ # Now test the ability to correctly reject a non-existent filename.
+ # For maximum studliness we would check that an error message is
+ # being output.
+ # We accept a zero exit status because it is what CVS does
+ # (Dec 95). Probably the exit status should be nonzero,
+ # however.
+ if $remote; then
+ dotest modules5-42 "${testcvs} co -d mydir dirmodule/nonexist" \
+"${SPROG} checkout: warning: new-born \`mydir/nonexist' has disappeared
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ else
+ dotest modules5-42 "${testcvs} co -d mydir dirmodule/nonexist" \
+"${SPROG} checkout: warning: new-born \`mydir/nonexist' has disappeared
+${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
+checkout script invoked in ${TESTDIR}/1
+args: mydir"
+ fi
+ # We tolerate the creation of the mydir directory, since that
+ # is what CVS does, not because we view that as preferable to not
+ # creating it.
+ dotest_fail modules5-43 "test -f mydir/a || test -f mydir/b" ""
+ rm -r mydir
+
+ if $remote; then
+ dotest modules5-44 "${testcvs} -q co -d mydir namedmodule" \
+"U mydir/a
+U mydir/b
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ else
+ dotest modules5-44 "${testcvs} -q co -d mydir namedmodule" \
+"U mydir/a
+U mydir/b
+checkout script invoked in ${TESTDIR}/1
+args: mydir"
+ fi
+ dotest modules5-45 "test -f mydir/a && test -f mydir/b" ""
+ dotest_fail modules5-46 "test -d namedir"
+ echo add line >>mydir/a
+ # This seems suspicious: when we checkout an existing directory,
+ # the checkout script gets executed in addition to the update
+ # script. Is that by design or accident?
+ if $remote; then
+ dotest modules5-47 "${testcvs} -q co -d mydir namedmodule" \
+"M mydir/a
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ else
+ dotest modules5-47 "${testcvs} -q co -d mydir namedmodule" \
+"M mydir/a
+checkout script invoked in ${TESTDIR}/1
+args: mydir"
+ fi
+ rm mydir/a
+
+ if $remote; then
+ dotest modules5-48 "${testcvs} -q co -d mydir namedmodule" \
+"U mydir/a
+checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
+args: mydir"
+ else
+ dotest modules5-48 "${testcvs} -q co -d mydir namedmodule" \
+"U mydir/a
+checkout script invoked in ${TESTDIR}/1
+args: mydir"
+ fi
+ dotest modules5-49 "echo yes | ${testcvs} release -d mydir" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .mydir.: "
+
+ dokeep
+ cd ..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/*.sh
+ ;;
+
+
+
+ modules6)
+ #
+ # Test invalid module definitions
+ #
+ # See the header comment for the `modules' test for an index of
+ # the complete suite of modules tests.
+ #
+
+ #
+ # There was a bug in CVS through 1.11.1p1 where a bad module name
+ # would cause the previous line to be parsed as the module
+ # definition. This test proves this doesn't happen anymore.
+ #
+ mkdir modules6
+ cd modules6
+ dotest module6-setup-1 "${testcvs} -Q co CVSROOT" ""
+ cd CVSROOT
+ echo "longmodulename who cares" >modules
+ echo "badname" >>modules
+ # This test almost isn't setup since it generates the error message
+ # we are looking for if `-Q' isn't specified, but I want to test the
+ # filename in the message later.
+ dotest modules6-setup-2 "$testcvs -Q ci -mbad-modules"
+
+ # Here's where CVS would report not being able to find `lename'
+ cd ..
+ dotest_fail modules6-1 "${testcvs} -q co badname" \
+"${SPROG} checkout: warning: NULL value for key .badname. at line 2 of .${CVSROOT_DIRNAME}/CVSROOT/modules.
+${SPROG} checkout: cannot find module .badname. - ignored" \
+"${SPROG} server: warning: NULL value for key .badname. at line 2 of .${CVSROOT_DIRNAME}/CVSROOT/modules.
+${SPROG} server: cannot find module .badname. - ignored
+${CPROG} \[checkout aborted\]: cannot expand modules"
+
+ dokeep
+ restore_adm
+ cd ..
+ rm -r modules6
+ ;;
+
+
+
+ modules7)
+ #
+ # Test tag problems vs an empty CVSROOT/val-tags file
+ #
+ # See the header comment for the `modules' test for an index of
+ # the complete suite of modules tests.
+ #
+ mkdir modules7
+ cd modules7
+ dotest modules7-1 "$testcvs -Q co -d top ."
+ cd top
+ mkdir zero one
+ dotest modules7-2 "$testcvs -Q add zero one"
+ cd one
+ echo 'file1 contents' > file1
+ dotest modules7-2 "$testcvs -Q add file1"
+ dotest modules7-3 "$testcvs -Q ci -mnew file1"
+ dotest modules7-4 "$testcvs -Q tag mytag file1"
+ cd ../CVSROOT
+ echo 'all -a zero one' > modules
+ dotest modules7-5 "$testcvs -Q ci -mall-module"
+ cd ../..
+ mkdir myexport
+ cd myexport
+
+ # This failed prior to CVS version 1.12.10.
+ dotest modules7-7 "$testcvs export -rmytag all" \
+"$SPROG export: Updating zero
+$SPROG export: Updating one
+U one/file1"
+ dotest modules7-8 'cat one/file1' 'file1 contents'
+
+ dokeep
+
+ # cleanup
+ restore_adm
+ cd ../..
+ rm -fr modules7
+ rm -rf $CVSROOT_DIRNAME/zero $CVSROOT_DIRNAME/one
+ ;;
+
+
+
+ mkmodules)
+ # When a file listed in checkoutlist doesn't exist, cvs-1.10.4
+ # would fail to remove the CVSROOT/.#[0-9]* temporary file it
+ # creates while mkmodules is in the process of trying to check
+ # out the missing file.
+
+ mkdir 1; cd 1
+ dotest mkmodules-temp-file-removal-1 "${testcvs} -Q co CVSROOT" ''
+ cd CVSROOT
+ echo no-such-file >> checkoutlist
+ dotest mkmodules-temp-file-removal-2 "$testcvs -Q ci -m. checkoutlist"
+
+ dotest mkmodules-temp-file-removal-3 \
+"echo $CVSROOT_DIRNAME/CVSROOT/.#[0-9]*" \
+"$CVSROOT_DIRNAME/CVSROOT/\.#\[0-9\]\*"
+
+ # Versions 1.11.6 & 1.12.1 and earlier of CVS printed most of the
+ # white space included before error messages in checkoutlist.
+ echo "no-such-file Failed to update no-such-file." >checkoutlist
+ dotest mkmodules-error-message-1 "$testcvs -Q ci -m. checkoutlist" \
+"$SPROG commit: Failed to update no-such-file\."
+
+ # Versions 1.11.6 & 1.12.1 and earlier of CVS used the error string
+ # from the checkoutlist file as the format string passed to error()'s
+ # printf. Check that this is no longer the case by verifying that
+ # printf format patterns remain unchanged.
+ echo "no-such-file Failed to update %s %lx times because %s happened %d times." >checkoutlist
+ dotest mkmodules-error-message-2 "$testcvs -Q ci -m. checkoutlist" \
+"$SPROG commit: Failed to update %s %lx times because %s happened %d times\."
+
+ dotest mkmodules-cleanup-1 \
+"$testcvs -Q up -pr1.1 checkoutlist >checkoutlist"
+ dotest mkmodules-cleanup-2 "$testcvs -Q ci -m. checkoutlist"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ ;;
+
+
+
+ co-d)
+ # Some tests of various permutations of co-d when directories exist
+ # and checkouts lengthen.
+ #
+ # Interestingly enough, these same tests pass when the directory
+ # lengthening happens via the modules file. Go figure.
+ module=co-d
+ mkdir $module; cd $module
+ mkdir top; cd top
+ dotest co-d-init-1 "$testcvs -Q co -l ."
+ mkdir $module
+ dotest co-d-init-2 "$testcvs -Q add $module"
+ cd $module
+ echo content >file1
+ echo different content >file2
+ dotest co-d-init-3 "$testcvs -Q add file1 file2"
+ dotest co-d-init-4 "$testcvs -Q ci -madd-em"
+ cd ../..
+
+ mkdir 2; cd 2
+ dotest co-d-1 "$testcvs -q co -d dir $module" \
+"U dir/file1
+U dir/file2"
+ dotest co-d-1.2 "cat dir/CVS/Repository" "$module"
+
+ dotest co-d-2 "$testcvs -q co -d dir2/sdir $module" \
+"U dir2/sdir/file1
+U dir2/sdir/file2"
+ dotest co-d-2.2 "cat dir2/CVS/Repository" "."
+ dotest co-d-2.3 "cat dir2/sdir/CVS/Repository" "$module"
+
+ dotest co-d-2.4 "$testcvs -q co -d dir2.4/sdir/sdir2 $module" \
+"U dir2.4/sdir/sdir2/file1
+U dir2.4/sdir/sdir2/file2"
+ dotest co-d-2.4.2 "cat dir2.4/CVS/Repository" "CVSROOT/Emptydir"
+ dotest co-d-2.4.3 "cat dir2.4/sdir/CVS/Repository" "."
+ dotest co-d-2.4.3 "cat dir2.4/sdir/sdir2/CVS/Repository" "$module"
+
+ mkdir dir3
+ dotest co-d-3 "$testcvs -q co -d dir3 $module" \
+"U dir3/file1
+U dir3/file2"
+ dotest co-d-3.2 "cat dir3/CVS/Repository" "$module"
+
+ mkdir dir4
+ dotest co-d-4 "$testcvs -q co -d dir4/sdir $module" \
+"U dir4/sdir/file1
+U dir4/sdir/file2"
+
+ # CVS is only supposed to create administration directories in
+ # directories it also creates, and in the directory specified by
+ # the last portion of the path passed to -d regardless. This is
+ #
+ # FIXCVS:
+ # This is broken in client/server mode because the server does not
+ # know the client's directory structure and has to create
+ # everything.
+ if $remote; then
+ dotest co-d-4.2r "cat dir4/CVS/Repository" "."
+ else
+ dotest_fail co-d-4.2 "test -d dir4/CVS"
+ fi
+
+ dotest co-d-4.3 "cat dir4/sdir/CVS/Repository" "$module"
+
+ mkdir dir5
+ mkdir dir5/sdir
+ dotest co-d-5 "$testcvs -q co -d dir5/sdir $module" \
+"U dir5/sdir/file1
+U dir5/sdir/file2"
+ # FIXCVS as for co-d-4.2r.
+ if $remote; then
+ dotest co-d-5.2 "cat dir5/CVS/Repository" "."
+ else
+ dotest_fail co-d-5.2 "test -d dir5/CVS"
+ fi
+
+ dotest co-d-5.3 "cat dir5/sdir/CVS/Repository" "$module"
+
+ # clean up
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ rm -r $module
+ ;;
+
+
+
+ cvsadm)
+ # These test check the content of CVS' administrative
+ # files as they are checked out in various configurations.
+ # (As a side note, I'm not using the "-q" flag in any of
+ # this code, which should provide some extra checking for
+ # those messages which don't seem to be checked thoroughly
+ # anywhere else.) To do a thorough test, we need to make
+ # a bunch of modules in various configurations.
+ #
+ # <1mod> is a directory at the top level of cvsroot
+ # ``foo bar''
+ # <2mod> is a directory at the second level of cvsroot
+ # ``foo bar/baz''
+ # <1d1mod> is a directory at the top level which is
+ # checked out into another directory
+ # ``foo -d bar baz''
+ # <1d2mod> is a directory at the second level which is
+ # checked out into another directory
+ # ``foo -d bar baz/quux''
+ # <2d1mod> is a directory at the top level which is
+ # checked out into a directory that is two deep
+ # ``foo -d bar/baz quux''
+ # <2d2mod> is a directory at the second level which is
+ # checked out into a directory that is two deep
+ # ``foo -d bar/baz quux''
+ #
+ # The tests do each of these types separately and in twos.
+ # We also repeat each test -d flag for 1-deep and 2-deep
+ # directories.
+ #
+ # Each test should check the output for the Repository
+ # file, since that is the one which varies depending on
+ # the directory and how it was checked out.
+ #
+ # Yes, this is verbose, but at least it's very thorough.
+
+ # convenience variables
+ REP=${CVSROOT}
+
+ # First, set TopLevelAdmin=yes so we're sure to get
+ # top-level CVS directories.
+ mkdir 1; cd 1
+ dotest cvsadm-setup-1 "${testcvs} -q co CVSROOT/config" \
+"U CVSROOT/config"
+ cd CVSROOT
+ echo "TopLevelAdmin=yes" >>config
+ dotest cvsadm-setup-2 "${testcvs} -q ci -m yes-top-level" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../..
+ rm -r 1
+
+ # Second, check out the modules file and edit it.
+ mkdir 1; cd 1
+ dotest cvsadm-1 "${testcvs} co CVSROOT/modules" \
+"U CVSROOT/modules"
+
+ # Test CVS/Root once. Since there is only one part of
+ # the code which writes CVS/Root files (Create_Admin),
+ # there is no point in testing this every time.
+ dotest cvsadm-1a "cat CVS/Root" ${REP}
+ dotest cvsadm-1b "cat CVS/Repository" "\."
+ dotest cvsadm-1c "cat CVSROOT/CVS/Root" ${REP}
+ dotest cvsadm-1d "cat CVSROOT/CVS/Repository" "CVSROOT"
+ # All of the defined module names begin with a number.
+ # All of the top-level directory names begin with "dir".
+ # All of the subdirectory names begin with "sub".
+ # All of the top-level modules begin with "mod".
+ echo "# Module defs for cvsadm tests" > CVSROOT/modules
+ echo "1mod mod1" >> CVSROOT/modules
+ echo "1mod-2 mod1-2" >> CVSROOT/modules
+ echo "2mod mod2/sub2" >> CVSROOT/modules
+ echo "2mod-2 mod2-2/sub2-2" >> CVSROOT/modules
+ echo "1d1mod -d dir1d1 mod1" >> CVSROOT/modules
+ echo "1d1mod-2 -d dir1d1-2 mod1-2" >> CVSROOT/modules
+ echo "1d2mod -d dir1d2 mod2/sub2" >> CVSROOT/modules
+ echo "1d2mod-2 -d dir1d2-2 mod2-2/sub2-2" >> CVSROOT/modules
+ echo "2d1mod -d dir2d1/sub2d1 mod1" >> CVSROOT/modules
+ echo "2d1mod-2 -d dir2d1-2/sub2d1-2 mod1-2" >> CVSROOT/modules
+ echo "2d2mod -d dir2d2/sub2d2 mod2/sub2" >> CVSROOT/modules
+ echo "2d2mod-2 -d dir2d2-2/sub2d2-2 mod2-2/sub2-2" >> CVSROOT/modules
+ dotest cvsadm-1e "${testcvs} ci -m add-modules" \
+"${CPROG} commit: Examining .
+${CPROG} commit: Examining CVSROOT
+${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- CVSROOT/modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+${SPROG} commit: Rebuilding administrative file database" \
+"${CPROG} commit: Examining .
+${CPROG} commit: Examining CVSROOT"
+ rm -rf CVS CVSROOT;
+
+ # Create the various modules
+ dotest cvsadm-2 "${testcvs} -q co -l ." ''
+ mkdir mod1
+ mkdir mod1-2
+ mkdir mod2
+ mkdir mod2/sub2
+ mkdir mod2-2
+ mkdir mod2-2/sub2-2
+ dotest cvsadm-2a "${testcvs} add mod1 mod1-2 mod2 mod2/sub2 mod2-2 mod2-2/sub2-2" \
+"Directory ${CVSROOT_DIRNAME}/mod1 added to the repository
+Directory ${CVSROOT_DIRNAME}/mod1-2 added to the repository
+Directory ${CVSROOT_DIRNAME}/mod2 added to the repository
+Directory ${CVSROOT_DIRNAME}/mod2/sub2 added to the repository
+Directory ${CVSROOT_DIRNAME}/mod2-2 added to the repository
+Directory ${CVSROOT_DIRNAME}/mod2-2/sub2-2 added to the repository"
+
+ # Populate the directories for the halibut
+ echo "file1" > mod1/file1
+ echo "file1-2" > mod1-2/file1-2
+ echo "file2" > mod2/sub2/file2
+ echo "file2-2" > mod2-2/sub2-2/file2-2
+ dotest cvsadm-2aa "${testcvs} add mod1/file1 mod1-2/file1-2 mod2/sub2/file2 mod2-2/sub2-2/file2-2" \
+"${SPROG} add: scheduling file .mod1/file1. for addition
+${SPROG} add: scheduling file .mod1-2/file1-2. for addition
+${SPROG} add: scheduling file .mod2/sub2/file2. for addition
+${SPROG} add: scheduling file .mod2-2/sub2-2/file2-2. for addition
+${SPROG} add: use \`${SPROG} commit' to add these files permanently"
+
+ dotest cvsadm-2b "${testcvs} ci -m yup mod1 mod1-2 mod2 mod2-2" \
+"${CPROG} commit: Examining mod1
+${CPROG} commit: Examining mod1-2
+${CPROG} commit: Examining mod2
+${CPROG} commit: Examining mod2/sub2
+${CPROG} commit: Examining mod2-2
+${CPROG} commit: Examining mod2-2/sub2-2
+${CVSROOT_DIRNAME}/mod1/file1,v <-- mod1/file1
+initial revision: 1.1
+${CVSROOT_DIRNAME}/mod1-2/file1-2,v <-- mod1-2/file1-2
+initial revision: 1.1
+${CVSROOT_DIRNAME}/mod2/sub2/file2,v <-- mod2/sub2/file2
+initial revision: 1.1
+${CVSROOT_DIRNAME}/mod2-2/sub2-2/file2-2,v <-- mod2-2/sub2-2/file2-2
+initial revision: 1.1"
+ # Finished creating the modules -- clean up.
+ rm -rf CVS mod1 mod1-2 mod2 mod2-2
+ # Done.
+
+ ##################################################
+ ## Start the dizzying array of possibilities.
+ ## Begin with each module type separately.
+ ##################################################
+
+ # Pattern -- after each checkout, first check the top-level
+ # CVS directory. Then, check the directories in numerical
+ # order.
+
+ dotest cvsadm-3 "${testcvs} co 1mod" \
+"${SPROG} checkout: Updating 1mod
+U 1mod/file1"
+ dotest cvsadm-3b "cat CVS/Repository" "\."
+ dotest cvsadm-3d "cat 1mod/CVS/Repository" "mod1"
+ rm -rf CVS 1mod
+
+ dotest cvsadm-4 "${testcvs} co 2mod" \
+"${SPROG} checkout: Updating 2mod
+U 2mod/file2"
+ dotest cvsadm-4b "cat CVS/Repository" "\."
+ dotest cvsadm-4d "cat 2mod/CVS/Repository" "mod2/sub2"
+ rm -rf CVS 2mod
+
+ dotest cvsadm-5 "${testcvs} co 1d1mod" \
+"${SPROG} checkout: Updating dir1d1
+U dir1d1/file1"
+ dotest cvsadm-5b "cat CVS/Repository" "\."
+ dotest cvsadm-5d "cat dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS dir1d1
+
+ dotest cvsadm-6 "${testcvs} co 1d2mod" \
+"${SPROG} checkout: Updating dir1d2
+U dir1d2/file2"
+ dotest cvsadm-6b "cat CVS/Repository" "\."
+ dotest cvsadm-6d "cat dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir1d2
+
+ dotest cvsadm-7 "${testcvs} co 2d1mod" \
+"${SPROG} checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1"
+ dotest cvsadm-7b "cat CVS/Repository" "\."
+ dotest cvsadm-7d "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-7f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir2d1
+
+ dotest cvsadm-8 "${testcvs} co 2d2mod" \
+"${SPROG} checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2"
+ dotest cvsadm-8b "cat CVS/Repository" "\."
+ dotest cvsadm-8d "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-8f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir2d2
+
+ ##################################################
+ ## You are in a shell script of twisted little
+ ## module combination statements, all alike.
+ ##################################################
+
+ ### 1mod
+
+ dotest cvsadm-9 "${testcvs} co 1mod 1mod-2" \
+"${SPROG} checkout: Updating 1mod
+U 1mod/file1
+${SPROG} checkout: Updating 1mod-2
+U 1mod-2/file1-2"
+ # the usual for the top level
+ dotest cvsadm-9b "cat CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-9d "cat 1mod/CVS/Repository" "mod1"
+ # the usual for 1mod copy
+ dotest cvsadm-9f "cat 1mod-2/CVS/Repository" "mod1-2"
+ rm -rf CVS 1mod 1mod-2
+
+ # 1mod 2mod redmod bluemod
+ dotest cvsadm-10 "${testcvs} co 1mod 2mod" \
+"${SPROG} checkout: Updating 1mod
+U 1mod/file1
+${SPROG} checkout: Updating 2mod
+U 2mod/file2"
+ # the usual for the top level
+ dotest cvsadm-10b "cat CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-10d "cat 1mod/CVS/Repository" "mod1"
+ # the usual for 2dmod
+ dotest cvsadm-10f "cat 2mod/CVS/Repository" "mod2/sub2"
+ rm -rf CVS 1mod 2mod
+
+ dotest cvsadm-11 "${testcvs} co 1mod 1d1mod" \
+"${SPROG} checkout: Updating 1mod
+U 1mod/file1
+${SPROG} checkout: Updating dir1d1
+U dir1d1/file1"
+ # the usual for the top level
+ dotest cvsadm-11b "cat CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-11d "cat 1mod/CVS/Repository" "mod1"
+ # the usual for 1d1mod
+ dotest cvsadm-11f "cat dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS 1mod dir1d1
+
+ dotest cvsadm-12 "${testcvs} co 1mod 1d2mod" \
+"${SPROG} checkout: Updating 1mod
+U 1mod/file1
+${SPROG} checkout: Updating dir1d2
+U dir1d2/file2"
+ # the usual for the top level
+ dotest cvsadm-12b "cat CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-12d "cat 1mod/CVS/Repository" "mod1"
+ # the usual for 1d2mod
+ dotest cvsadm-12f "cat dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS 1mod dir1d2
+
+ dotest cvsadm-13 "${testcvs} co 1mod 2d1mod" \
+"${SPROG} checkout: Updating 1mod
+U 1mod/file1
+${SPROG} checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1"
+ # the usual for the top level
+ dotest cvsadm-13b "cat CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-13d "cat 1mod/CVS/Repository" "mod1"
+ # the usual for 2d1mod
+ dotest cvsadm-13f "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-13h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS 1mod dir2d1
+
+ dotest cvsadm-14 "${testcvs} co 1mod 2d2mod" \
+"${SPROG} checkout: Updating 1mod
+U 1mod/file1
+${SPROG} checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2"
+ # the usual for the top level
+ dotest cvsadm-14b "cat CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-14d "cat 1mod/CVS/Repository" "mod1"
+ # the usual for 2d2mod
+ dotest cvsadm-14f "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-14h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS 1mod dir2d2
+
+
+ ### 2mod
+
+ dotest cvsadm-15 "${testcvs} co 2mod 2mod-2" \
+"${SPROG} checkout: Updating 2mod
+U 2mod/file2
+${SPROG} checkout: Updating 2mod-2
+U 2mod-2/file2-2"
+ # the usual for the top level
+ dotest cvsadm-15b "cat CVS/Repository" "\."
+ # the usual for 2mod
+ dotest cvsadm-15d "cat 2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 2mod copy
+ dotest cvsadm-15f "cat 2mod-2/CVS/Repository" "mod2-2/sub2-2"
+ rm -rf CVS 2mod 2mod-2
+
+
+ dotest cvsadm-16 "${testcvs} co 2mod 1d1mod" \
+"${SPROG} checkout: Updating 2mod
+U 2mod/file2
+${SPROG} checkout: Updating dir1d1
+U dir1d1/file1"
+ # the usual for the top level
+ dotest cvsadm-16b "cat CVS/Repository" "\."
+ # the usual for 2mod
+ dotest cvsadm-16d "cat 2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 1d1mod
+ dotest cvsadm-16f "cat dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS 2mod dir1d1
+
+ dotest cvsadm-17 "${testcvs} co 2mod 1d2mod" \
+"${SPROG} checkout: Updating 2mod
+U 2mod/file2
+${SPROG} checkout: Updating dir1d2
+U dir1d2/file2"
+ # the usual for the top level
+ dotest cvsadm-17b "cat CVS/Repository" "\."
+ # the usual for 2mod
+ dotest cvsadm-17d "cat 2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 1d2mod
+ dotest cvsadm-17f "cat dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS 2mod dir1d2
+
+ dotest cvsadm-18 "${testcvs} co 2mod 2d1mod" \
+"${SPROG} checkout: Updating 2mod
+U 2mod/file2
+${SPROG} checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1"
+ # the usual for the top level
+ dotest cvsadm-18b "cat CVS/Repository" "\."
+ # the usual for 2mod
+ dotest cvsadm-18d "cat 2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 2d1mod
+ dotest cvsadm-18f "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-18h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS 2mod dir2d1
+
+ dotest cvsadm-19 "${testcvs} co 2mod 2d2mod" \
+"${SPROG} checkout: Updating 2mod
+U 2mod/file2
+${SPROG} checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2"
+ # the usual for the top level
+ dotest cvsadm-19b "cat CVS/Repository" "\."
+ # the usual for 2mod
+ dotest cvsadm-19d "cat 2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 2d2mod
+ dotest cvsadm-19f "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-19h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS 2mod dir2d2
+
+
+ ### 1d1mod
+
+ dotest cvsadm-20 "${testcvs} co 1d1mod 1d1mod-2" \
+"${SPROG} checkout: Updating dir1d1
+U dir1d1/file1
+${SPROG} checkout: Updating dir1d1-2
+U dir1d1-2/file1-2"
+ # the usual for the top level
+ dotest cvsadm-20b "cat CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-20d "cat dir1d1/CVS/Repository" "mod1"
+ # the usual for 1d1mod copy
+ dotest cvsadm-20f "cat dir1d1-2/CVS/Repository" "mod1-2"
+ rm -rf CVS dir1d1 dir1d1-2
+
+ dotest cvsadm-21 "${testcvs} co 1d1mod 1d2mod" \
+"${SPROG} checkout: Updating dir1d1
+U dir1d1/file1
+${SPROG} checkout: Updating dir1d2
+U dir1d2/file2"
+ # the usual for the top level
+ dotest cvsadm-21b "cat CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-21d "cat dir1d1/CVS/Repository" "mod1"
+ # the usual for 1d2mod
+ dotest cvsadm-21f "cat dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir1d1 dir1d2
+
+ dotest cvsadm-22 "${testcvs} co 1d1mod 2d1mod" \
+"${SPROG} checkout: Updating dir1d1
+U dir1d1/file1
+${SPROG} checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1"
+ # the usual for the top level
+ dotest cvsadm-22b "cat CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-22d "cat dir1d1/CVS/Repository" "mod1"
+ # the usual for 2d1mod
+ dotest cvsadm-22f "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-22h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir1d1 dir2d1
+
+ dotest cvsadm-23 "${testcvs} co 1d1mod 2d2mod" \
+"${SPROG} checkout: Updating dir1d1
+U dir1d1/file1
+${SPROG} checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2"
+ # the usual for the top level
+ dotest cvsadm-23b "cat CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-23d "cat dir1d1/CVS/Repository" "mod1"
+ # the usual for 2d2mod
+ dotest cvsadm-23f "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-23h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir1d1 dir2d2
+
+
+ ### 1d2mod
+
+ dotest cvsadm-24 "${testcvs} co 1d2mod 1d2mod-2" \
+"${SPROG} checkout: Updating dir1d2
+U dir1d2/file2
+${SPROG} checkout: Updating dir1d2-2
+U dir1d2-2/file2-2"
+ # the usual for the top level
+ dotest cvsadm-24b "cat CVS/Repository" "\."
+ # the usual for 1d2mod
+ dotest cvsadm-24d "cat dir1d2/CVS/Repository" "mod2/sub2"
+ # the usual for 1d2mod copy
+ dotest cvsadm-24f "cat dir1d2-2/CVS/Repository" "mod2-2/sub2-2"
+ rm -rf CVS dir1d2 dir1d2-2
+
+ dotest cvsadm-25 "${testcvs} co 1d2mod 2d1mod" \
+"${SPROG} checkout: Updating dir1d2
+U dir1d2/file2
+${SPROG} checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1"
+ # the usual for the top level
+ dotest cvsadm-25b "cat CVS/Repository" "\."
+ # the usual for 1d2mod
+ dotest cvsadm-25d "cat dir1d2/CVS/Repository" "mod2/sub2"
+ # the usual for 2d1mod
+ dotest cvsadm-25f "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-25h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir1d2 dir2d1
+
+ dotest cvsadm-26 "${testcvs} co 1d2mod 2d2mod" \
+"${SPROG} checkout: Updating dir1d2
+U dir1d2/file2
+${SPROG} checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2"
+ # the usual for the top level
+ dotest cvsadm-26b "cat CVS/Repository" "\."
+ # the usual for 1d2mod
+ dotest cvsadm-26d "cat dir1d2/CVS/Repository" "mod2/sub2"
+ # the usual for 2d2mod
+ dotest cvsadm-26f "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-26h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir1d2 dir2d2
+
+
+ # 2d1mod
+
+ dotest cvsadm-27 "${testcvs} co 2d1mod 2d1mod-2" \
+"${SPROG} checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1
+${SPROG} checkout: Updating dir2d1-2/sub2d1-2
+U dir2d1-2/sub2d1-2/file1-2"
+ # the usual for the top level
+ dotest cvsadm-27b "cat CVS/Repository" "\."
+ # the usual for 2d1mod
+ dotest cvsadm-27d "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-27f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ # the usual for 2d1mod
+ dotest cvsadm-27h "cat dir2d1-2/CVS/Repository" "\."
+ dotest cvsadm-27j "cat dir2d1-2/sub2d1-2/CVS/Repository" "mod1-2"
+ rm -rf CVS dir2d1 dir2d1-2
+
+ dotest cvsadm-28 "${testcvs} co 2d1mod 2d2mod" \
+"${SPROG} checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1
+${SPROG} checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2"
+ # the usual for the top level
+ dotest cvsadm-28b "cat CVS/Repository" "\."
+ # the usual for 2d1mod
+ dotest cvsadm-28d "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-28f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ # the usual for 2d2mod
+ dotest cvsadm-28h "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-28j "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir2d1 dir2d2
+
+
+ # 2d2mod
+
+ dotest cvsadm-29 "${testcvs} co 2d2mod 2d2mod-2" \
+"${SPROG} checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2
+${SPROG} checkout: Updating dir2d2-2/sub2d2-2
+U dir2d2-2/sub2d2-2/file2-2"
+ # the usual for the top level
+ dotest cvsadm-29b "cat CVS/Repository" "\."
+ # the usual for 2d2mod
+ dotest cvsadm-29d "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-29f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ # the usual for 2d2mod
+ dotest cvsadm-29h "cat dir2d2-2/CVS/Repository" "mod2-2"
+ dotest cvsadm-29j "cat dir2d2-2/sub2d2-2/CVS/Repository" \
+"mod2-2/sub2-2"
+ rm -rf CVS dir2d2 dir2d2-2
+
+ ##################################################
+ ## And now, all of that again using the "-d" flag
+ ## on the command line.
+ ##################################################
+
+ dotest cvsadm-1d3 "${testcvs} co -d dir 1mod" \
+"${SPROG} checkout: Updating dir
+U dir/file1"
+ dotest cvsadm-1d3b "cat CVS/Repository" "\."
+ dotest cvsadm-1d3d "cat dir/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d4 "${testcvs} co -d dir 2mod" \
+"${SPROG} checkout: Updating dir
+U dir/file2"
+ dotest cvsadm-1d4b "cat CVS/Repository" "\."
+ dotest cvsadm-1d4d "cat dir/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d5 "${testcvs} co -d dir 1d1mod" \
+"${SPROG} checkout: Updating dir
+U dir/file1"
+ dotest cvsadm-1d5b "cat CVS/Repository" "\."
+ dotest cvsadm-1d5d "cat dir/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d6 "${testcvs} co -d dir 1d2mod" \
+"${SPROG} checkout: Updating dir
+U dir/file2"
+ dotest cvsadm-1d6b "cat CVS/Repository" "\."
+ dotest cvsadm-1d6d "cat dir/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d7 "${testcvs} co -d dir 2d1mod" \
+"${SPROG} checkout: Updating dir
+U dir/file1"
+ dotest cvsadm-1d7b "cat CVS/Repository" "\."
+ dotest cvsadm-1d7d "cat dir/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d8 "${testcvs} co -d dir 2d2mod" \
+"${SPROG} checkout: Updating dir
+U dir/file2"
+ dotest cvsadm-1d8b "cat CVS/Repository" "\."
+ dotest cvsadm-1d8d "cat dir/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ ##################################################
+ ## Los Combonaciones
+ ##################################################
+
+ ### 1mod
+
+ dotest cvsadm-1d9 "${testcvs} co -d dir 1mod 1mod-2" \
+"${SPROG} checkout: Updating dir/1mod
+U dir/1mod/file1
+${SPROG} checkout: Updating dir/1mod-2
+U dir/1mod-2/file1-2"
+ # the usual for the top level
+ dotest cvsadm-1d9b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d9d "cat dir/CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-1d9f "cat dir/1mod/CVS/Repository" "mod1"
+ # the usual for 1mod copy
+ dotest cvsadm-1d9h "cat dir/1mod-2/CVS/Repository" "mod1-2"
+ rm -rf CVS dir
+
+ # 1mod 2mod redmod bluemod
+ dotest cvsadm-1d10 "${testcvs} co -d dir 1mod 2mod" \
+"${SPROG} checkout: Updating dir/1mod
+U dir/1mod/file1
+${SPROG} checkout: Updating dir/2mod
+U dir/2mod/file2"
+ dotest cvsadm-1d10b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d10d "cat dir/CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-1d10f "cat dir/1mod/CVS/Repository" "mod1"
+ # the usual for 2dmod
+ dotest cvsadm-1d10h "cat dir/2mod/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d11 "${testcvs} co -d dir 1mod 1d1mod" \
+"${SPROG} checkout: Updating dir/1mod
+U dir/1mod/file1
+${SPROG} checkout: Updating dir/dir1d1
+U dir/dir1d1/file1"
+ dotest cvsadm-1d11b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d11d "cat dir/CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-1d11f "cat dir/1mod/CVS/Repository" "mod1"
+ # the usual for 1d1mod
+ dotest cvsadm-1d11h "cat dir/dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d12 "${testcvs} co -d dir 1mod 1d2mod" \
+"${SPROG} checkout: Updating dir/1mod
+U dir/1mod/file1
+${SPROG} checkout: Updating dir/dir1d2
+U dir/dir1d2/file2"
+ dotest cvsadm-1d12b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d12d "cat dir/CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-1d12f "cat dir/1mod/CVS/Repository" "mod1"
+ # the usual for 1d2mod
+ dotest cvsadm-1d12h "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d13 "${testcvs} co -d dir 1mod 2d1mod" \
+"${SPROG} checkout: Updating dir/1mod
+U dir/1mod/file1
+${SPROG} checkout: Updating dir/dir2d1/sub2d1
+U dir/dir2d1/sub2d1/file1"
+ dotest cvsadm-1d13b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d13d "cat dir/CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-1d13f "cat dir/1mod/CVS/Repository" "mod1"
+ # the usual for 2d1mod
+ dotest cvsadm-1d13h "cat dir/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-1d13j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d14 "${testcvs} co -d dir 1mod 2d2mod" \
+"${SPROG} checkout: Updating dir/1mod
+U dir/1mod/file1
+${SPROG} checkout: Updating dir/dir2d2/sub2d2
+U dir/dir2d2/sub2d2/file2"
+ dotest cvsadm-1d14b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d14d "cat dir/CVS/Repository" "\."
+ # the usual for 1mod
+ dotest cvsadm-1d14f "cat dir/1mod/CVS/Repository" "mod1"
+ # the usual for 2d2mod
+ dotest cvsadm-1d14h "cat dir/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-1d14j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+
+ ### 2mod
+
+ dotest cvsadm-1d15 "${testcvs} co -d dir 2mod 2mod-2" \
+"${SPROG} checkout: Updating dir/2mod
+U dir/2mod/file2
+${SPROG} checkout: Updating dir/2mod-2
+U dir/2mod-2/file2-2"
+ dotest cvsadm-1d15b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d15d "cat dir/CVS/Repository" "mod2"
+ # the usual for 2mod
+ dotest cvsadm-1d15f "cat dir/2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 2mod copy
+ dotest cvsadm-1d15h "cat dir/2mod-2/CVS/Repository" "mod2-2/sub2-2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d16 "${testcvs} co -d dir 2mod 1d1mod" \
+"${SPROG} checkout: Updating dir/2mod
+U dir/2mod/file2
+${SPROG} checkout: Updating dir/dir1d1
+U dir/dir1d1/file1"
+ dotest cvsadm-1d16b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d16d "cat dir/CVS/Repository" "mod2"
+ # the usual for 2mod
+ dotest cvsadm-1d16f "cat dir/2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 1d1mod
+ dotest cvsadm-1d16h "cat dir/dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d17 "${testcvs} co -d dir 2mod 1d2mod" \
+"${SPROG} checkout: Updating dir/2mod
+U dir/2mod/file2
+${SPROG} checkout: Updating dir/dir1d2
+U dir/dir1d2/file2"
+ dotest cvsadm-1d17b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d17d "cat dir/CVS/Repository" "mod2"
+ # the usual for 2mod
+ dotest cvsadm-1d17f "cat dir/2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 1d2mod
+ dotest cvsadm-1d17h "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d18 "${testcvs} co -d dir 2mod 2d1mod" \
+"${SPROG} checkout: Updating dir/2mod
+U dir/2mod/file2
+${SPROG} checkout: Updating dir/dir2d1/sub2d1
+U dir/dir2d1/sub2d1/file1"
+ dotest cvsadm-1d18b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d18d "cat dir/CVS/Repository" "mod2"
+ # the usual for 2mod
+ dotest cvsadm-1d18f "cat dir/2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 2d1mod
+ dotest cvsadm-1d18h "cat dir/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-1d18j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d19 "${testcvs} co -d dir 2mod 2d2mod" \
+"${SPROG} checkout: Updating dir/2mod
+U dir/2mod/file2
+${SPROG} checkout: Updating dir/dir2d2/sub2d2
+U dir/dir2d2/sub2d2/file2"
+ dotest cvsadm-1d19b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d19d "cat dir/CVS/Repository" "mod2"
+ # the usual for 2mod
+ dotest cvsadm-1d19f "cat dir/2mod/CVS/Repository" "mod2/sub2"
+ # the usual for 2d2mod
+ dotest cvsadm-1d19h "cat dir/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-1d19j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+
+ ### 1d1mod
+
+ dotest cvsadm-1d20 "${testcvs} co -d dir 1d1mod 1d1mod-2" \
+"${SPROG} checkout: Updating dir/dir1d1
+U dir/dir1d1/file1
+${SPROG} checkout: Updating dir/dir1d1-2
+U dir/dir1d1-2/file1-2"
+ dotest cvsadm-1d20b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d20d "cat dir/CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-1d20f "cat dir/dir1d1/CVS/Repository" "mod1"
+ # the usual for 1d1mod copy
+ dotest cvsadm-1d20h "cat dir/dir1d1-2/CVS/Repository" "mod1-2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d21 "${testcvs} co -d dir 1d1mod 1d2mod" \
+"${SPROG} checkout: Updating dir/dir1d1
+U dir/dir1d1/file1
+${SPROG} checkout: Updating dir/dir1d2
+U dir/dir1d2/file2"
+ dotest cvsadm-1d21b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d21d "cat dir/CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-1d21f "cat dir/dir1d1/CVS/Repository" "mod1"
+ # the usual for 1d2mod
+ dotest cvsadm-1d21h "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d22 "${testcvs} co -d dir 1d1mod 2d1mod" \
+"${SPROG} checkout: Updating dir/dir1d1
+U dir/dir1d1/file1
+${SPROG} checkout: Updating dir/dir2d1/sub2d1
+U dir/dir2d1/sub2d1/file1"
+ dotest cvsadm-1d22b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d22d "cat dir/CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-1d22f "cat dir/dir1d1/CVS/Repository" "mod1"
+ # the usual for 2d1mod
+ dotest cvsadm-1d22h "cat dir/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-1d22j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d23 "${testcvs} co -d dir 1d1mod 2d2mod" \
+"${SPROG} checkout: Updating dir/dir1d1
+U dir/dir1d1/file1
+${SPROG} checkout: Updating dir/dir2d2/sub2d2
+U dir/dir2d2/sub2d2/file2"
+ dotest cvsadm-1d23b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d23d "cat dir/CVS/Repository" "\."
+ # the usual for 1d1mod
+ dotest cvsadm-1d23f "cat dir/dir1d1/CVS/Repository" "mod1"
+ # the usual for 2d2mod
+ dotest cvsadm-1d23h "cat dir/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-1d23j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+
+ ### 1d2mod
+
+ dotest cvsadm-1d24 "${testcvs} co -d dir 1d2mod 1d2mod-2" \
+"${SPROG} checkout: Updating dir/dir1d2
+U dir/dir1d2/file2
+${SPROG} checkout: Updating dir/dir1d2-2
+U dir/dir1d2-2/file2-2"
+ dotest cvsadm-1d24b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d24d "cat dir/CVS/Repository" "mod2"
+ # the usual for 1d2mod
+ dotest cvsadm-1d24f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
+ # the usual for 1d2mod copy
+ dotest cvsadm-1d24h "cat dir/dir1d2-2/CVS/Repository" "mod2-2/sub2-2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d25 "${testcvs} co -d dir 1d2mod 2d1mod" \
+"${SPROG} checkout: Updating dir/dir1d2
+U dir/dir1d2/file2
+${SPROG} checkout: Updating dir/dir2d1/sub2d1
+U dir/dir2d1/sub2d1/file1"
+ dotest cvsadm-1d25b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d25d "cat dir/CVS/Repository" "mod2"
+ # the usual for 1d2mod
+ dotest cvsadm-1d25f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
+ # the usual for 2d1mod
+ dotest cvsadm-1d25h "cat dir/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-1d25j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d26 "${testcvs} co -d dir 1d2mod 2d2mod" \
+"${SPROG} checkout: Updating dir/dir1d2
+U dir/dir1d2/file2
+${SPROG} checkout: Updating dir/dir2d2/sub2d2
+U dir/dir2d2/sub2d2/file2"
+ dotest cvsadm-1d26b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d26d "cat dir/CVS/Repository" "mod2"
+ # the usual for 1d2mod
+ dotest cvsadm-1d26f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
+ # the usual for 2d2mod
+ dotest cvsadm-1d26h "cat dir/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-1d26j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+
+ # 2d1mod
+
+ dotest cvsadm-1d27 "${testcvs} co -d dir 2d1mod 2d1mod-2" \
+"${SPROG} checkout: Updating dir/dir2d1/sub2d1
+U dir/dir2d1/sub2d1/file1
+${SPROG} checkout: Updating dir/dir2d1-2/sub2d1-2
+U dir/dir2d1-2/sub2d1-2/file1-2"
+ dotest cvsadm-1d27b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d27d "cat dir/CVS/Repository" "CVSROOT/Emptydir"
+ # the usual for 2d1mod
+ dotest cvsadm-1d27f "cat dir/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-1d27h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
+ # the usual for 2d1mod
+ dotest cvsadm-1d27j "cat dir/dir2d1-2/CVS/Repository" "\."
+ dotest cvsadm-1d27l "cat dir/dir2d1-2/sub2d1-2/CVS/Repository" \
+"mod1-2"
+ rm -rf CVS dir
+
+ dotest cvsadm-1d28 "${testcvs} co -d dir 2d1mod 2d2mod" \
+"${SPROG} checkout: Updating dir/dir2d1/sub2d1
+U dir/dir2d1/sub2d1/file1
+${SPROG} checkout: Updating dir/dir2d2/sub2d2
+U dir/dir2d2/sub2d2/file2"
+ dotest cvsadm-1d28b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d28d "cat dir/CVS/Repository" "CVSROOT/Emptydir"
+ # the usual for 2d1mod
+ dotest cvsadm-1d28f "cat dir/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-1d28h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
+ # the usual for 2d2mod
+ dotest cvsadm-1d28j "cat dir/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-1d28l "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+
+ # 2d2mod
+
+ dotest cvsadm-1d29 "${testcvs} co -d dir 2d2mod 2d2mod-2" \
+"${SPROG} checkout: Updating dir/dir2d2/sub2d2
+U dir/dir2d2/sub2d2/file2
+${SPROG} checkout: Updating dir/dir2d2-2/sub2d2-2
+U dir/dir2d2-2/sub2d2-2/file2-2"
+ dotest cvsadm-1d29b "cat CVS/Repository" "\."
+ # the usual for the dir level
+ dotest cvsadm-1d29d "cat dir/CVS/Repository" "\."
+ # the usual for 2d2mod
+ dotest cvsadm-1d29f "cat dir/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-1d29h "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ # the usual for 2d2mod
+ dotest cvsadm-1d29j "cat dir/dir2d2-2/CVS/Repository" "mod2-2"
+ dotest cvsadm-1d29l "cat dir/dir2d2-2/sub2d2-2/CVS/Repository" \
+"mod2-2/sub2-2"
+ rm -rf CVS dir
+
+ ##################################################
+ ## And now, some of that again using the "-d" flag
+ ## on the command line, but use a longer path.
+ ##################################################
+
+ dotest cvsadm-2d3-1 "$testcvs co -d dir/dir2 1mod" \
+"$SPROG checkout: Updating dir/dir2
+U dir/dir2/file1"
+
+ # Remote couldn't handle this, even with the "mkdir dir", before
+ # CVS 1.11.14.
+ dotest cvsadm-2d3b "cat CVS/Repository" "\."
+ dotest cvsadm-2d3d "cat dir/CVS/Repository" "."
+ dotest cvsadm-2d3f "cat dir/dir2/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-2d4 "$testcvs co -d dir/dir2 2mod" \
+"$SPROG checkout: Updating dir/dir2
+U dir/dir2/file2"
+ dotest cvsadm-2d4b "cat CVS/Repository" "\."
+ dotest cvsadm-2d4f "cat dir/dir2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-2d5 "$testcvs co -d dir/dir2 1d1mod" \
+"$SPROG checkout: Updating dir/dir2
+U dir/dir2/file1"
+ dotest cvsadm-2d5b "cat CVS/Repository" "\."
+ dotest cvsadm-2d5f "cat dir/dir2/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-2d6 "$testcvs co -d dir/dir2 1d2mod" \
+"$SPROG checkout: Updating dir/dir2
+U dir/dir2/file2"
+ dotest cvsadm-2d6b "cat CVS/Repository" "\."
+ dotest cvsadm-2d6f "cat dir/dir2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-2d7 "$testcvs co -d dir/dir2 2d1mod" \
+"$SPROG checkout: Updating dir/dir2
+U dir/dir2/file1"
+ dotest cvsadm-2d7b "cat CVS/Repository" "\."
+ dotest cvsadm-2d7f "cat dir/dir2/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-2d8 "$testcvs co -d dir/dir2 2d2mod" \
+"$SPROG checkout: Updating dir/dir2
+U dir/dir2/file2"
+ dotest cvsadm-2d8b "cat CVS/Repository" "\."
+ dotest cvsadm-2d8f "cat dir/dir2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ ##################################################
+ ## And now, a few of those tests revisited to
+ ## test the behavior of the -N flag.
+ ##################################################
+
+ dotest cvsadm-N3 "$testcvs co -N 1mod" \
+"$SPROG checkout: Updating 1mod
+U 1mod/file1"
+ dotest cvsadm-N3b "cat CVS/Repository" "\."
+ dotest cvsadm-N3d "cat 1mod/CVS/Repository" "mod1"
+ rm -rf CVS 1mod
+
+ dotest cvsadm-N4 "$testcvs co -N 2mod" \
+"$SPROG checkout: Updating 2mod
+U 2mod/file2"
+ dotest cvsadm-N4b "cat CVS/Repository" "\."
+ dotest cvsadm-N4d "cat 2mod/CVS/Repository" "mod2/sub2"
+ rm -rf CVS 2mod
+
+ dotest cvsadm-N5 "$testcvs co -N 1d1mod" \
+"$SPROG checkout: Updating dir1d1
+U dir1d1/file1"
+ dotest cvsadm-N5b "cat CVS/Repository" "\."
+ dotest cvsadm-N5d "cat dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS dir1d1
+
+ dotest cvsadm-N6 "$testcvs co -N 1d2mod" \
+"$SPROG checkout: Updating dir1d2
+U dir1d2/file2"
+ dotest cvsadm-N6b "cat CVS/Repository" "\."
+ dotest cvsadm-N6d "cat dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir1d2
+
+ dotest cvsadm-N7 "$testcvs co -N 2d1mod" \
+"$SPROG checkout: Updating dir2d1/sub2d1
+U dir2d1/sub2d1/file1"
+ dotest cvsadm-N7b "cat CVS/Repository" "\."
+ dotest cvsadm-N7d "cat dir2d1/CVS/Repository" "\."
+ dotest cvsadm-N7f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir2d1
+
+ dotest cvsadm-N8 "$testcvs co -N 2d2mod" \
+"$SPROG checkout: Updating dir2d2/sub2d2
+U dir2d2/sub2d2/file2"
+ dotest cvsadm-N8b "cat CVS/Repository" "\."
+ dotest cvsadm-N8d "cat dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-N8f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir2d2
+
+ ## the ones in one-deep directories
+
+ dotest cvsadm-N1d3 "$testcvs co -N -d dir 1mod" \
+"$SPROG checkout: Updating dir/1mod
+U dir/1mod/file1"
+ dotest cvsadm-N1d3b "cat CVS/Repository" "\."
+ dotest cvsadm-N1d3d "cat dir/CVS/Repository" "\."
+ dotest cvsadm-N1d3f "cat dir/1mod/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-N1d4 "$testcvs co -N -d dir 2mod" \
+"$SPROG checkout: Updating dir/2mod
+U dir/2mod/file2"
+ dotest cvsadm-N1d4b "cat CVS/Repository" "\."
+ dotest cvsadm-N1d4d "cat dir/CVS/Repository" "mod2"
+ dotest cvsadm-N1d4f "cat dir/2mod/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-N1d5 "$testcvs co -N -d dir 1d1mod" \
+"$SPROG checkout: Updating dir/dir1d1
+U dir/dir1d1/file1"
+ dotest cvsadm-N1d5b "cat CVS/Repository" "\."
+ dotest cvsadm-N1d5d "cat dir/CVS/Repository" "\."
+ dotest cvsadm-N1d5d "cat dir/dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-N1d6 "$testcvs co -N -d dir 1d2mod" \
+"$SPROG checkout: Updating dir/dir1d2
+U dir/dir1d2/file2"
+ dotest cvsadm-N1d6b "cat CVS/Repository" "\."
+ dotest cvsadm-N1d6d "cat dir/CVS/Repository" "mod2"
+ dotest cvsadm-N1d6f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ dotest cvsadm-N1d7 "$testcvs co -N -d dir 2d1mod" \
+"$SPROG checkout: Updating dir/dir2d1/sub2d1
+U dir/dir2d1/sub2d1/file1"
+ dotest cvsadm-N1d7b "cat CVS/Repository" "\."
+ dotest cvsadm-N1d7d "cat dir/CVS/Repository" "CVSROOT/Emptydir"
+ dotest cvsadm-N1d7f "cat dir/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-N1d7h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ dotest cvsadm-N1d8 "$testcvs co -N -d dir 2d2mod" \
+"$SPROG checkout: Updating dir/dir2d2/sub2d2
+U dir/dir2d2/sub2d2/file2"
+ dotest cvsadm-N1d8b "cat CVS/Repository" "\."
+ dotest cvsadm-N1d8d "cat dir/CVS/Repository" "\."
+ dotest cvsadm-N1d8d "cat dir/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-N1d8d "cat dir/dir2d2/sub2d2/CVS/Repository" \
+"mod2/sub2"
+ rm -rf CVS dir
+
+ ## the ones in two-deep directories
+
+ mkdir dir
+ dotest cvsadm-N2d3 "$testcvs co -N -d dir/dir2 1mod" \
+"$SPROG checkout: Updating dir/dir2/1mod
+U dir/dir2/1mod/file1"
+ dotest cvsadm-N2d3b "cat CVS/Repository" "\."
+ dotest cvsadm-N2d3f "cat dir/dir2/CVS/Repository" "\."
+ dotest cvsadm-N2d3h "cat dir/dir2/1mod/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-N2d4 "$testcvs co -N -d dir/dir2 2mod" \
+"$SPROG checkout: Updating dir/dir2/2mod
+U dir/dir2/2mod/file2"
+ dotest cvsadm-N2d4b "cat CVS/Repository" "\."
+ dotest cvsadm-N2d4f "cat dir/dir2/CVS/Repository" "mod2"
+ dotest cvsadm-N2d4h "cat dir/dir2/2mod/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-N2d5 "$testcvs co -N -d dir/dir2 1d1mod" \
+"$SPROG checkout: Updating dir/dir2/dir1d1
+U dir/dir2/dir1d1/file1"
+ dotest cvsadm-N2d5b "cat CVS/Repository" "\."
+ dotest cvsadm-N2d5f "cat dir/dir2/CVS/Repository" "\."
+ dotest cvsadm-N2d5h "cat dir/dir2/dir1d1/CVS/Repository" "mod1"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-N2d6 "$testcvs co -N -d dir/dir2 1d2mod" \
+"$SPROG checkout: Updating dir/dir2/dir1d2
+U dir/dir2/dir1d2/file2"
+ dotest cvsadm-N2d6b "cat CVS/Repository" "\."
+ dotest cvsadm-N2d6f "cat dir/dir2/CVS/Repository" "mod2"
+ dotest cvsadm-N2d6h "cat dir/dir2/dir1d2/CVS/Repository" "mod2/sub2"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-N2d7 "$testcvs co -N -d dir/dir2 2d1mod" \
+"$SPROG checkout: Updating dir/dir2/dir2d1/sub2d1
+U dir/dir2/dir2d1/sub2d1/file1"
+ dotest cvsadm-N2d7b "cat CVS/Repository" "\."
+ dotest cvsadm-N2d7f "cat dir/dir2/CVS/Repository" "CVSROOT/Emptydir"
+ dotest cvsadm-N2d7g "cat dir/dir2/dir2d1/CVS/Repository" "\."
+ dotest cvsadm-N2d7h "cat dir/dir2/dir2d1/sub2d1/CVS/Repository" \
+"mod1"
+ rm -rf CVS dir
+
+ mkdir dir
+ dotest cvsadm-N2d8 "$testcvs co -N -d dir/dir2 2d2mod" \
+"$SPROG checkout: Updating dir/dir2/dir2d2/sub2d2
+U dir/dir2/dir2d2/sub2d2/file2"
+ dotest cvsadm-N2d8b "cat CVS/Repository" "\."
+ dotest cvsadm-N2d8f "cat dir/dir2/CVS/Repository" "\."
+ dotest cvsadm-N2d8h "cat dir/dir2/dir2d2/CVS/Repository" "mod2"
+ dotest cvsadm-N2d8j "cat dir/dir2/dir2d2/sub2d2/CVS/Repository" \
+"mod2/sub2"
+ rm -rf CVS dir
+ # End of test that didn't work for remote prior to CVS 1.11.14.
+
+ ##################################################
+ ## That's enough of that, thank you very much.
+ ##################################################
+
+ dokeep
+ restore_adm
+
+ # remove our junk
+ cd ..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/1mod $CVSROOT_DIRNAME/1mod-2 \
+ $CVSROOT_DIRNAME/2mod $CVSROOT_DIRNAME/2mod-2 \
+ $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/mod1-2 \
+ $CVSROOT_DIRNAME/mod2 $CVSROOT_DIRNAME/mod2-2
+ ;;
+
+
+
+ emptydir)
+ # Various tests of the Emptydir (CVSNULLREPOS) code. See also:
+ # cvsadm: tests of Emptydir in various module definitions
+ # basicb: Test that "Emptydir" is non-special in ordinary contexts
+
+ mkdir 1; cd 1
+ dotest emptydir-1 "${testcvs} co CVSROOT/modules" \
+"U CVSROOT/modules"
+ echo "# Module defs for emptydir tests" > CVSROOT/modules
+ echo "2d1mod -d dir2d1/sub/sub2d1 mod1" >> CVSROOT/modules
+ echo "2d1moda -d dir2d1/suba moda/modasub" >> CVSROOT/modules
+ echo "2d1modb -d dir2d1/suba mod1" >> CVSROOT/modules
+ echo "comb -a 2d1modb 2d1moda" >> CVSROOT/modules
+
+ dotest emptydir-2 "${testcvs} ci -m add-modules" \
+"${CPROG} commit: Examining CVSROOT
+${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- CVSROOT/modules
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+${SPROG} commit: Rebuilding administrative file database" \
+"${CPROG} commit: Examining CVSROOT"
+ rm -rf CVS CVSROOT
+
+ modify_repo mkdir $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/moda
+ # Populate. Not sure we really need to do this.
+ dotest emptydir-3 "$testcvs -q co -l ."
+ dotest emptydir-3a "${testcvs} co mod1 moda" \
+"${SPROG} checkout: Updating mod1
+${SPROG} checkout: Updating moda"
+ echo "file1" > mod1/file1
+ mkdir moda/modasub
+ dotest emptydir-3b "${testcvs} add moda/modasub" \
+"Directory ${CVSROOT_DIRNAME}/moda/modasub added to the repository"
+ echo "filea" > moda/modasub/filea
+ dotest emptydir-4 "${testcvs} add mod1/file1 moda/modasub/filea" \
+"${SPROG} add: scheduling file .mod1/file1. for addition
+${SPROG} add: scheduling file .moda/modasub/filea. for addition
+${SPROG} add: use \`${SPROG} commit' to add these files permanently"
+ dotest emptydir-5 "${testcvs} -q ci -m yup" \
+"$CVSROOT_DIRNAME/mod1/file1,v <-- mod1/file1
+initial revision: 1\.1
+${CVSROOT_DIRNAME}/moda/modasub/filea,v <-- moda/modasub/filea
+initial revision: 1\.1"
+ rm -rf mod1 moda CVS
+ # End Populate.
+
+ dotest emptydir-6 "${testcvs} co 2d1mod" \
+"${SPROG} checkout: Updating dir2d1/sub/sub2d1
+U dir2d1/sub/sub2d1/file1"
+ cd dir2d1
+ touch emptyfile
+ # It doesn't make any sense to add a file (or do much of anything
+ # else) in Emptydir; Emptydir is a placeholder indicating that
+ # the working directory doesn't correspond to anything in
+ # the repository.
+ dotest_fail emptydir-7 "${testcvs} add emptyfile" \
+"${SPROG} \[add aborted]: cannot add to \`${CVSROOT_DIRNAME}/CVSROOT/Emptydir'"
+ mkdir emptydir
+ dotest_fail emptydir-8 "${testcvs} add emptydir" \
+"${CPROG} \[add aborted]: cannot add to \`${CVSROOT_DIRNAME}/CVSROOT/Emptydir'"
+ cd ..
+ rm -rf CVS dir2d1
+
+ # OK, while we have an Emptydir around, test a few obscure
+ # things about it.
+ mkdir edir; cd edir
+ dotest emptydir-9 "${testcvs} -q co -l CVSROOT" \
+"U CVSROOT${DOTSTAR}"
+ cd CVSROOT
+ dotest_fail emptydir-10 "test -d Emptydir" ''
+ # This tests the code in find_dirs which skips Emptydir.
+ dotest emptydir-11 "${testcvs} -q -n update -d -P" ''
+ cd ../..
+ rm -r edir
+ cd ..
+
+ # Now start playing with moda.
+ mkdir 2; cd 2
+ dotest emptydir-12 "${testcvs} -q co 2d1moda" \
+"U dir2d1/suba/filea"
+ # OK, this is the crux of the matter. This used to show "Emptydir",
+ # but everyone seemed to think it should show "moda". This
+ # usually works better, but not always as shown by the following
+ # test.
+ dotest emptydir-13 "cat dir2d1/CVS/Repository" "moda"
+ dotest_fail emptydir-14 "${testcvs} co comb" \
+"${SPROG} checkout: existing repository ${CVSROOT_DIRNAME}/moda/modasub does not match ${CVSROOT_DIRNAME}/mod1
+${SPROG} checkout: ignoring module 2d1modb
+${SPROG} checkout: Updating dir2d1/suba"
+ dotest emptydir-15 "cat dir2d1/CVS/Repository" "moda"
+ cd ..
+
+ # Test the effect of a non-cvs directory already existing with the
+ # same name as one in the modules file.
+ mkdir 3; cd 3
+ mkdir dir2d1
+ dotest emptydir-16 "${testcvs} co 2d1mod" \
+"${SPROG} checkout: Updating dir2d1/sub/sub2d1
+U dir2d1/sub/sub2d1/file1"
+
+ if $remote; then
+ dotest emptydir-17 "cat dir2d1/CVS/Repository" "CVSROOT/Emptydir"
+ else
+ dotest_fail emptydir-17 "test -d dir2d1/CVS"
+ fi
+
+ dokeep
+ cd ..
+ rm -r 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/moda
+ # I guess for the moment the convention is going to be
+ # that we don't need to remove $CVSROOT_DIRNAME/CVSROOT/Emptydir
+ ;;
+
+
+
+ abspath)
+
+ # These tests test the thituations thin thwitch thoo theck
+ # things thout twith thabsolute thaths. Threally.
+
+ #
+ # CHECKOUTS
+ #
+
+ # Create a few modules to use
+ modify_repo mkdir $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/mod2
+ dotest abspath-1a "${testcvs} co mod1 mod2" \
+"${SPROG} checkout: Updating mod1
+${SPROG} checkout: Updating mod2"
+
+ # Populate the module
+ echo "file1" > mod1/file1
+ echo "file2" > mod2/file2
+ cd mod1
+ dotest abspath-1ba "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ cd ..
+ cd mod2
+ dotest abspath-1bb "${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ cd ..
+
+ dotest abspath-1c "${testcvs} ci -m yup mod1 mod2" \
+"${CPROG} commit: Examining mod1
+${CPROG} commit: Examining mod2
+${CVSROOT_DIRNAME}/mod1/file1,v <-- mod1/file1
+initial revision: 1.1
+${CVSROOT_DIRNAME}/mod2/file2,v <-- mod2/file2
+initial revision: 1.1"
+ # Finished creating the module -- clean up.
+ rm -rf CVS mod1 mod2
+ # Done.
+
+ # Try checking out the module in a local directory
+ if $remote; then
+ dotest_fail abspath-2a "${testcvs} co -d ${TESTDIR}/1 mod1" \
+"${SPROG} \[checkout aborted\]: absolute pathnames invalid for server (specified .${TESTDIR}/1.)"
+ dotest abspath-2a-try2 "${testcvs} co -d 1 mod1" \
+"${SPROG} checkout: Updating 1
+U 1/file1"
+ else
+ dotest abspath-2a "${testcvs} co -d ${TESTDIR}/1 mod1" \
+"${SPROG} checkout: Updating ${TESTDIR}/1
+U ${TESTDIR}/1/file1"
+ fi # remote workaround
+
+ dotest abspath-2b "cat ${TESTDIR}/1/CVS/Repository" "mod1"
+
+ # Done. Clean up.
+ rm -r $TESTDIR/1
+
+
+ # Now try in a subdirectory. We're not covering any more
+ # code here, but we might catch a future error if someone
+ # changes the checkout code.
+
+ # Since CVS 1.11.14, CVS will create leading directories specified
+ # via co -d.
+ # I am unsure that this wasn't the behavior prior to CVS 1.9, but the
+ # comment that used to be here leads me to believe it was not.
+ if $remote; then :; else
+ dotest abspath-3.1 "$testcvs -q co -d $TESTDIR/1/2 mod1" \
+"U $TESTDIR/1/2/file1"
+ rm -r $TESTDIR/1
+ fi
+ dotest abspath-3.2 "$testcvs -q co -d 1/2 mod1" \
+"U 1/2/file1"
+ rm -r 1
+
+ # We don't to mess with an existing directory just to traverse it,
+ # for example by creating a CVS directory, but currently we can't
+ # avoid this in client/server mode.
+ mkdir 1
+ if $remote; then
+ dotest abspath-3ar "$testcvs co -d 1/2 mod1" \
+"$SPROG checkout: Updating 1/2
+U 1/2/file1"
+ dotest abspath-3br "cat 1/CVS/Repository" .
+ else
+ dotest abspath-3a "$testcvs co -d $TESTDIR/1/2 mod1" \
+"$SPROG checkout: Updating $TESTDIR/1/2
+U $TESTDIR/1/2/file1"
+ dotest_fail abspath-3b "test -d ${TESTDIR}/1/CVS"
+ fi
+
+ dotest abspath-3c "cat ${TESTDIR}/1/2/CVS/Repository" mod1
+
+
+ # Done. Clean up.
+ rm -rf ${TESTDIR}/1
+
+
+ # Now try someplace where we don't have permission.
+ mkdir ${TESTDIR}/barf
+ chmod -w ${TESTDIR}/barf
+ dotest_fail abspath-4r "${testcvs} co -d ${TESTDIR}/barf/sub mod1" \
+"${SPROG} \[checkout aborted\]: cannot make directory sub: Permission denied" \
+"${SPROG} \[checkout aborted\]: absolute pathnames invalid for server (specified .${TESTDIR}/barf/sub.)"
+ chmod +w ${TESTDIR}/barf
+ rmdir ${TESTDIR}/barf
+ # Done. Nothing to clean up.
+
+
+ # Try checking out two modules into the same directory.
+ if $remote; then
+ dotest abspath-5ar "${testcvs} co -d 1 mod1 mod2" \
+"${SPROG} checkout: Updating 1/mod1
+U 1/mod1/file1
+${SPROG} checkout: Updating 1/mod2
+U 1/mod2/file2"
+ else
+ dotest abspath-5a "${testcvs} co -d ${TESTDIR}/1 mod1 mod2" \
+"${SPROG} checkout: Updating ${TESTDIR}/1/mod1
+U ${TESTDIR}/1/mod1/file1
+${SPROG} checkout: Updating ${TESTDIR}/1/mod2
+U ${TESTDIR}/1/mod2/file2"
+ fi # end remote workaround
+ dotest abspath-5b "cat ${TESTDIR}/1/CVS/Repository" "\."
+ dotest abspath-5c "cat ${TESTDIR}/1/mod1/CVS/Repository" "mod1"
+ dotest abspath-5d "cat ${TESTDIR}/1/mod2/CVS/Repository" "mod2"
+ # Done. Clean up.
+ rm -rf $TESTDIR/1
+
+
+ # Try checking out the top-level module.
+ if $remote; then
+ dotest abspath-6ar "$testcvs co -d 1 ." \
+"$SPROG checkout: Updating 1
+$SPROG checkout: Updating 1/CVSROOT
+$DOTSTAR
+$SPROG checkout: Updating 1/mod1
+U 1/mod1/file1
+$SPROG checkout: Updating 1/mod2
+U 1/mod2/file2"
+ else
+ dotest abspath-6a "${testcvs} co -d ${TESTDIR}/1 ." \
+"${SPROG} checkout: Updating ${TESTDIR}/1
+${SPROG} checkout: Updating ${TESTDIR}/1/CVSROOT
+${DOTSTAR}
+${SPROG} checkout: Updating ${TESTDIR}/1/mod1
+U ${TESTDIR}/1/mod1/file1
+${SPROG} checkout: Updating ${TESTDIR}/1/mod2
+U ${TESTDIR}/1/mod2/file2"
+ fi # end of remote workaround
+ dotest abspath-6b "cat ${TESTDIR}/1/CVS/Repository" "\."
+ dotest abspath-6c "cat ${TESTDIR}/1/CVSROOT/CVS/Repository" "CVSROOT"
+ dotest abspath-6c "cat ${TESTDIR}/1/mod1/CVS/Repository" "mod1"
+ dotest abspath-6d "cat ${TESTDIR}/1/mod2/CVS/Repository" "mod2"
+ # Done. Clean up.
+ rm -rf ${TESTDIR}/1
+
+ # Test that an absolute pathname to some other directory
+ # doesn't mess with the current working directory.
+ mkdir 1
+ cd 1
+ if $remote; then
+ dotest_fail abspath-7ar "${testcvs} -q co -d ../2 mod2" \
+"${SPROG} checkout: protocol error: .\.\./2. contains more leading \.\.
+${SPROG} \[checkout aborted\]: than the 0 which Max-dotdot specified"
+ cd ..
+ dotest abspath-7a-try2r "${testcvs} -q co -d 2 mod2" \
+"U 2/file2"
+ cd 1
+ else
+ dotest abspath-7a "${testcvs} -q co -d ${TESTDIR}/2 mod2" \
+"U ${TESTDIR}/2/file2"
+ fi # remote workaround
+ dotest abspath-7b "ls" ""
+ dotest abspath-7c "${testcvs} -q co mod1" \
+"U mod1/file1"
+ cd mod1
+ if $remote; then
+ cd ../..
+ dotest abspath-7dr "${testcvs} -q co -d 3 mod2" \
+"U 3/file2"
+ cd 1/mod1
+ else
+ dotest abspath-7d "${testcvs} -q co -d ${TESTDIR}/3 mod2" \
+"U ${TESTDIR}/3/file2"
+ fi # remote workaround
+ dotest abspath-7e "${testcvs} -q update -d"
+
+ #
+ # FIXME: do other functions here (e.g. update /tmp/foo)
+ #
+
+ # Finished with all tests. Cleanup.
+ dokeep
+ cd ../..
+ rm -r 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/mod2
+ ;;
+
+
+
+ abspath2)
+ # More absolute path checks. The following used to attempt to create
+ # directories in /:
+ #
+ # $ cvs -d:fork:/cvsroot co /foo
+ # cvs checkout: warning: cannot make directory CVS in /: Permission denied
+ # cvs [checkout aborted]: cannot make directory /foo: Permission denied
+ # $
+ #
+ # The -z9 in this test also checks for an old server bug where the
+ # server would block indefinitely attempting to read an EOF from the
+ # client in the compression buffer shutdown routine.
+ dotest_fail abspath2-1 "$testcvs -z9 co /foo" \
+"$CPROG \[checkout aborted\]: Absolute module reference invalid: \`/foo'" \
+"$SPROG \[server aborted\]: Absolute module reference invalid: \`/foo'
+$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
+ ;;
+
+
+
+ toplevel)
+ # test the feature that cvs creates a CVS subdir also for
+ # the toplevel directory
+
+ # First set the TopLevelAdmin setting.
+ mkdir 1; cd 1
+ dotest toplevel-1a "${testcvs} -q co CVSROOT/config" \
+"U CVSROOT/config"
+ cd CVSROOT
+ echo "TopLevelAdmin=yes" >>config
+ dotest toplevel-1b "${testcvs} -q ci -m yes-top-level" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../..
+ rm -r 1
+
+ mkdir 1; cd 1
+ dotest toplevel-1 "${testcvs} -q co -l ." ''
+ mkdir top-dir second-dir
+ dotest toplevel-2 "${testcvs} add top-dir second-dir" \
+"Directory ${CVSROOT_DIRNAME}/top-dir added to the repository
+Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
+ cd top-dir
+
+ touch file1
+ dotest toplevel-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest toplevel-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/top-dir/file1,v <-- file1
+initial revision: 1\.1"
+ cd ..
+
+ cd second-dir
+ touch file2
+ dotest toplevel-3s "${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest toplevel-4s "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/second-dir/file2,v <-- file2
+initial revision: 1\.1"
+
+ cd ../..
+ rm -r 1; mkdir 1; cd 1
+ dotest toplevel-5 "${testcvs} co top-dir" \
+"${SPROG} checkout: Updating top-dir
+U top-dir/file1"
+
+ dotest toplevel-6 "${testcvs} update top-dir" \
+"${SPROG} update: Updating top-dir"
+ dotest toplevel-7 "${testcvs} update" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating top-dir"
+
+ dotest toplevel-8 "${testcvs} update -d top-dir" \
+"${SPROG} update: Updating top-dir"
+ # There is some sentiment that
+ # "${SPROG} update: Updating \.
+ # ${SPROG} update: Updating top-dir"
+ # is correct but it isn't clear why that would be correct instead
+ # of the remote CVS behavior (which also updates CVSROOT).
+ #
+ # The DOTSTAR matches of a bunch of lines like
+ # "U CVSROOT/checkoutlist". Trying to match them more precisely
+ # seemed to cause trouble. For example CVSROOT/cvsignore will
+ # be present or absent depending on whether we ran the "ignore"
+ # test or not.
+ dotest toplevel-9 "${testcvs} update -d" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating CVSROOT
+${DOTSTAR}
+${SPROG} update: Updating top-dir"
+
+ cd ..
+ rm -r 1; mkdir 1; cd 1
+ dotest toplevel-10 "${testcvs} co top-dir" \
+"${SPROG} checkout: Updating top-dir
+U top-dir/file1"
+
+ # This tests more or less the same thing, in a particularly
+ # "real life" example.
+ dotest toplevel-11 "${testcvs} -q update -d second-dir" \
+"U second-dir/file2"
+
+ # Now remove the CVS directory (people may do this manually,
+ # especially if they formed their habits with CVS
+ # 1.9 and older, which didn't create it. Or perhaps the working
+ # directory itself was created with 1.9 or older).
+ rm -r CVS
+ # Now set the permissions so we can't recreate it.
+ if test -n "$remotehost"; then
+ # Cygwin again.
+ $CVS_RSH $remotehost "chmod -w $TESTDIR/1"
+ else
+ chmod -w ../1
+ fi
+ # Now see whether CVS has trouble because it can't create CVS.
+ # First string is for local, second is for remote.
+ dotest toplevel-12 "${testcvs} co top-dir" \
+"${SPROG} checkout: warning: cannot make directory CVS in \.: Permission denied
+${SPROG} checkout: Updating top-dir" \
+"${CPROG} checkout: warning: cannot make directory CVS in \.: Permission denied
+${CPROG} checkout: in directory \.:
+${CPROG} checkout: cannot open CVS/Entries for reading: No such file or directory
+${SPROG} checkout: Updating top-dir"
+
+ chmod +w ../1
+
+ dokeep
+ restore_adm
+ cd ..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/top-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ toplevel2)
+ # Similar to toplevel, but test the case where TopLevelAdmin=no.
+
+ # First set the TopLevelAdmin setting.
+ mkdir 1; cd 1
+ dotest toplevel2-1a "${testcvs} -q co CVSROOT/config" \
+"U CVSROOT/config"
+ cd CVSROOT
+ echo "TopLevelAdmin=no" >>config
+ dotest toplevel2-1b "$testcvs -q ci -m no-top-level" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../..
+ rm -r 1
+
+ # Now set up some directories and subdirectories
+ mkdir 1; cd 1
+ dotest toplevel2-1 "${testcvs} -q co -l ." ''
+ mkdir top-dir second-dir
+ dotest toplevel2-2 "${testcvs} add top-dir second-dir" \
+"Directory ${CVSROOT_DIRNAME}/top-dir added to the repository
+Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
+ cd top-dir
+
+ touch file1
+ dotest toplevel2-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest toplevel2-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/top-dir/file1,v <-- file1
+initial revision: 1\.1"
+ cd ..
+
+ cd second-dir
+ touch file2
+ dotest toplevel2-3s "${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest toplevel2-4s "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/second-dir/file2,v <-- file2
+initial revision: 1\.1"
+
+ cd ../..
+ rm -r 1; mkdir 1; cd 1
+ dotest toplevel2-5 "${testcvs} co top-dir" \
+"${SPROG} checkout: Updating top-dir
+U top-dir/file1"
+
+ dotest toplevel2-6 "${testcvs} update top-dir" \
+"${SPROG} update: Updating top-dir"
+ dotest toplevel2-7 "${testcvs} update" \
+"${SPROG} update: Updating top-dir"
+
+ dotest toplevel2-8 "${testcvs} update -d top-dir" \
+"${SPROG} update: Updating top-dir"
+ # Contrast this with toplevel-9, which has TopLevelAdmin=yes.
+ dotest toplevel2-9 "${testcvs} update -d" \
+"${SPROG} update: Updating top-dir"
+
+ cd ..
+ rm -r 1; mkdir 1; cd 1
+ dotest toplevel2-10 "${testcvs} co top-dir" \
+"${SPROG} checkout: Updating top-dir
+U top-dir/file1"
+ # This tests more or less the same thing, in a particularly
+ # "real life" example. With TopLevelAdmin=yes, this command
+ # would give us second-dir and CVSROOT directories too.
+ dotest toplevel2-11 "${testcvs} -q update -d" ""
+
+ dokeep
+ cd ..
+ restore_adm
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/top-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ rstar-toplevel)
+ # This test used to confirm a bug that existed in the r* commands
+ # run against the top-level project prior to CVS 1.11.18 & 1.12.10.
+ #
+ # The assertion failure was something like:
+ # do_recursion: Assertion \`strstr (repository, \"/\./\") == ((void \*)0)' failed\..*"
+ dotest rstar-toplevel-1 "$testcvs -q rlog ." \
+"
+RCS file: $CVSROOT_DIRNAME/CVSROOT$DOTSTAR"
+
+ dokeep
+ ;;
+
+
+
+ trailingslashes)
+ # Some tests of CVS's reactions to path specifications containing
+ # trailing slashes.
+ mkdir trailingslashes; cd trailingslashes
+ dotest trailingslashes-init-1 "$testcvs -Q co -ldt ."
+ dotest trailingslashes-init-2 "$testcvs -Q co -dt2 ."
+ cd t
+ echo "Ahh'll be baaack." >topfile
+ dotest trailingslashes-init-3 "$testcvs -Q add topfile"
+ dotest trailingslashes-init-4 "$testcvs -Q ci -mto-top"
+
+ # First, demonstrate the usual case.
+ cd ../t2
+ dotest trailingslashes-1 "$testcvs -q up CVSROOT"
+ dotest_fail trailingslashes-1a "test -f topfile"
+
+ # FIXCVS:
+ # Now the one that fails in remote mode.
+ # This highlights one of the failure cases mentioned in TODO item
+ # #205.
+ if $remote; then
+ dotest trailingslashes-2 "$testcvs -q up CVSROOT/" \
+"U topfile"
+ dotest trailingslashes-2a "test -f topfile"
+ else
+ dotest trailingslashes-2 "$testcvs -q up CVSROOT/"
+ dotest_fail trailingslashes-2a "test -f topfile"
+ fi
+
+ dokeep
+ cd ../..
+ rm -rf trailingslashes
+ modify_repo rm -rf $CVSROOT_DIRNAME/topfile,v
+ ;;
+
+
+
+ checkout_repository)
+ dotest_fail checkout_repository-1 \
+"${testcvs} co -d ${CVSROOT_DIRNAME} CVSROOT" \
+"${CPROG} \[checkout aborted\]: Cannot check out files into the repository itself" \
+"${SPROG} \[checkout aborted\]: absolute pathnames invalid for server (specified \`${CVSROOT_DIRNAME}')"
+
+ # The behavior of the client/server test below should be correct.
+ # The CVS client currently has no way of knowing that the client and
+ # server are the same machine and thus skips the $CVSROOT checks.
+ # I think checking for this case in CVS would be bloat since this
+ # should be a fairly rare occurance.
+ cd ${CVSROOT_DIRNAME}
+ dotest_fail checkout_repository-2 "${testcvs} co CVSROOT" \
+"${CPROG} \[checkout aborted\]: Cannot check out files into the repository itself" \
+"${SPROG} checkout: Updating CVSROOT
+${CPROG} checkout: move away \`CVSROOT/checkoutlist'; it is in the way
+C CVSROOT/checkoutlist
+${CPROG} checkout: move away \`CVSROOT/commitinfo'; it is in the way
+C CVSROOT/commitinfo
+${CPROG} checkout: move away \`CVSROOT/config'; it is in the way
+C CVSROOT/config
+${CPROG} checkout: move away \`CVSROOT/cvswrappers'; it is in the way
+C CVSROOT/cvswrappers
+${CPROG} checkout: move away \`CVSROOT/loginfo'; it is in the way
+C CVSROOT/loginfo
+${CPROG} checkout: move away \`CVSROOT/modules'; it is in the way
+C CVSROOT/modules
+${CPROG} checkout: move away \`CVSROOT/notify'; it is in the way
+C CVSROOT/notify
+${CPROG} checkout: move away \`CVSROOT/postadmin'; it is in the way
+C CVSROOT/postadmin
+${CPROG} checkout: move away \`CVSROOT/postproxy'; it is in the way
+C CVSROOT/postproxy
+${CPROG} checkout: move away \`CVSROOT/posttag'; it is in the way
+C CVSROOT/posttag
+${CPROG} checkout: move away \`CVSROOT/postwatch'; it is in the way
+C CVSROOT/postwatch
+${CPROG} checkout: move away \`CVSROOT/preproxy'; it is in the way
+C CVSROOT/preproxy
+${CPROG} checkout: move away \`CVSROOT/rcsinfo'; it is in the way
+C CVSROOT/rcsinfo
+${CPROG} checkout: move away \`CVSROOT/taginfo'; it is in the way
+C CVSROOT/taginfo
+${CPROG} checkout: move away \`CVSROOT/verifymsg'; it is in the way
+C CVSROOT/verifymsg"
+
+ dotest checkout_repository-3 \
+"${testcvs} co -p CVSROOT/modules >/dev/null" \
+"===================================================================
+Checking out CVSROOT/modules
+RCS: ${CVSROOT_DIRNAME}/CVSROOT/modules,v
+VERS: 1\.[0-9]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*"
+
+ dokeep
+ cd $TESTDIR
+ ;;
+
+
+
+ mflag)
+ for message in '' ' ' '
+ ' ' test' ; do
+ # Set up
+ mkdir a-dir; cd a-dir
+ # Test handling of -m during import
+ echo testa >>test
+ if ${testcvs} import -m "$message" a-dir A A1 >>${LOGFILE} 2>&1;then
+ pass 156
+ else
+ fail 156
+ fi
+ # Must import twice since the first time uses inline code that
+ # avoids RCS call.
+ echo testb >>test
+ if ${testcvs} import -m "$message" a-dir A A2 >>${LOGFILE} 2>&1;then
+ pass 157
+ else
+ fail 157
+ fi
+ # Test handling of -m during ci
+ cd ..; rm -r a-dir
+ if ${testcvs} co a-dir >>${LOGFILE} 2>&1; then
+ pass 158
+ else
+ fail 158
+ fi
+ cd a-dir
+ echo testc >>test
+ if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then
+ pass 159
+ else
+ fail 159
+ fi
+ # Test handling of -m during rm/ci
+ rm test;
+ if ${testcvs} rm test >>${LOGFILE} 2>&1; then
+ pass 160
+ else
+ fail 160
+ fi
+ if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then
+ pass 161
+ else
+ fail 161
+ fi
+
+ dokeep
+ # Clean up
+ cd ..
+ rm -r a-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/a-dir
+ done
+ ;;
+
+
+
+ editor)
+ # More tests of log messages, in this case the ability to
+ # run an external editor.
+ # TODO:
+ # * also test $EDITOR, $CVSEDITOR, &c.
+ # * test what happens if up-to-date check fails.
+
+ # Our "editor" puts "x" at the start of each line, so we
+ # can see the "CVS:" lines.
+ cat >${TESTDIR}/editme <<EOF
+#!${TESTSHELL}
+sleep 1
+sed <\$1 -e 's/^/x/' >${TESTDIR}/edit.new
+mv ${TESTDIR}/edit.new \$1
+exit 0
+EOF
+ chmod +x ${TESTDIR}/editme
+
+ mkdir 1; cd 1
+ dotest editor-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest editor-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch file1 file2
+ dotest editor-3 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest editor-4 "${testcvs} -e ${TESTDIR}/editme -q ci" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ dotest editor-5 "${testcvs} -q tag -b br" "T file1
+T file2"
+ dotest editor-6 "${testcvs} -q update -r br" ''
+ echo modify >>file1
+ dotest editor-7 "${testcvs} -e ${TESTDIR}/editme -q ci" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ # OK, now we want to make sure "ci -r" puts in the branch
+ # where appropriate. Note that we can check in on the branch
+ # without being on the branch, because there is not a revision
+ # already on the branch. If there were a revision on the branch,
+ # CVS would correctly give an up-to-date check failed.
+ dotest editor-8 "${testcvs} -q update -A" "U file1"
+ echo add a line >>file2
+ dotest editor-9 "${testcvs} -q -e ${TESTDIR}/editme ci -rbr file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ dotest editor-log-file1 "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+xCVS: ----------------------------------------------------------------------
+xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically
+xCVS:
+xCVS: Committing in .
+xCVS:
+xCVS: Added Files:
+xCVS: file1 file2
+xCVS: ----------------------------------------------------------------------
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+xCVS: ----------------------------------------------------------------------
+xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically
+xCVS:
+xCVS: Committing in .
+xCVS:
+xCVS: Modified Files:
+xCVS: Tag: br
+xCVS: file1
+xCVS: ----------------------------------------------------------------------
+============================================================================="
+
+ # The only difference between the two expect strings is the
+ # presence or absence of "Committing in ." for 1.1.2.1.
+ dotest editor-log-file2 "${testcvs} log -N file2" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+xCVS: ----------------------------------------------------------------------
+xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically
+xCVS:
+xCVS: Committing in .
+xCVS:
+xCVS: Added Files:
+xCVS: file1 file2
+xCVS: ----------------------------------------------------------------------
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+xCVS: ----------------------------------------------------------------------
+xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically
+xCVS:
+xCVS: Modified Files:
+xCVS: Tag: br
+xCVS: file2
+xCVS: ----------------------------------------------------------------------
+=============================================================================" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+xCVS: ----------------------------------------------------------------------
+xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically
+xCVS:
+xCVS: Committing in .
+xCVS:
+xCVS: Added Files:
+xCVS: file1 file2
+xCVS: ----------------------------------------------------------------------
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+xCVS: ----------------------------------------------------------------------
+xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically
+xCVS:
+xCVS: Committing in .
+xCVS:
+xCVS: Modified Files:
+xCVS: Tag: br
+xCVS: file2
+xCVS: ----------------------------------------------------------------------
+============================================================================="
+
+ # Test CVS's response to an unchanged log message
+ cat >${TESTDIR}/editme <<EOF
+#!${TESTSHELL}
+sleep 1
+exit 0
+EOF
+ chmod +x ${TESTDIR}/editme
+ dotest_fail editor-emptylog-1 "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
+"
+Log message unchanged or not specified
+a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
+Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"
+
+ # Test CVS's response to an empty log message
+ cat >${TESTDIR}/editme <<EOF
+#!${TESTSHELL}
+sleep 1
+cat /dev/null >\$1
+exit 0
+EOF
+ chmod +x ${TESTDIR}/editme
+ dotest_fail editor-emptylog-1a "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
+"
+Log message unchanged or not specified
+a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
+Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"
+
+ # Test CVS's response to a log message with one blank line
+ cat >${TESTDIR}/editme <<EOF
+#!${TESTSHELL}
+sleep 1
+echo >\$1
+exit 0
+EOF
+ chmod +x ${TESTDIR}/editme
+ dotest_fail editor-emptylog-1b "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
+"
+Log message unchanged or not specified
+a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
+Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"
+
+ # Test CVS's response to a log message with only comments
+ cat >${TESTDIR}/editme <<EOF
+#!${TESTSHELL}
+sleep 1
+cat \$1 >${TESTDIR}/edit.new
+mv ${TESTDIR}/edit.new \$1
+exit 0
+EOF
+ chmod +x ${TESTDIR}/editme
+ dotest_fail editor-emptylog-1c "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
+"
+Log message unchanged or not specified
+a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
+Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"
+
+ # Test CVS's response to a log message that is zero bytes
+ # in length. This caused core dumps in cvs 1.11.5 on Solaris
+ # hosts.
+ cd ..
+ dotest editor-emptylog-continue-1 "${testcvs} -q co CVSROOT/loginfo" \
+"U CVSROOT/loginfo"
+
+ cd CVSROOT
+ cat <<\EOF >>loginfo
+DEFAULT (echo Start-Log;cat;echo End-Log) >> $CVSROOT/CVSROOT/commitlog
+EOF
+ dotest editor-emptylog-continue-2 "$testcvs -Q ci -mloggem"
+
+ cd ../first-dir
+ cat >${TESTDIR}/editme <<EOF
+#!${TESTSHELL}
+sleep 1
+cp /dev/null \$1
+exit 1
+EOF
+ chmod +x ${TESTDIR}/editme
+ dotest editor-emptylog-continue-3 "echo c |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
+"${CPROG} commit: warning: editor session failed
+
+Log message unchanged or not specified
+a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
+Action: (continue) ${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ # The loginfo Log message should be an empty line and not "(null)"
+ # which is what some fprintf() implementations do with "%s"
+ # format and a NULL pointer...
+ if $remote; then
+ dotest editor-emptylog-continue-4r \
+"cat $CVSROOT_DIRNAME/CVSROOT/commitlog" \
+"Start-Log
+Update of $CVSROOT_DIRNAME/CVSROOT
+In directory $hostname:$TMPDIR/cvs-serv[0-9a-z]*
+
+Modified Files:
+ loginfo
+Log Message:
+loggem
+End-Log
+Start-Log
+Update of $CVSROOT_DIRNAME/first-dir
+In directory $hostname:$TMPDIR/cvs-serv[0-9a-z]*
+
+Modified Files:
+ file1
+Log Message:
+
+End-Log"
+ else
+ dotest editor-emptylog-continue-4 \
+"cat $CVSROOT_DIRNAME/CVSROOT/commitlog" \
+"Start-Log
+Update of $CVSROOT_DIRNAME/CVSROOT
+In directory $hostname:$TESTDIR/1/CVSROOT
+
+Modified Files:
+ loginfo
+Log Message:
+loggem
+End-Log
+Start-Log
+Update of $CVSROOT_DIRNAME/first-dir
+In directory $hostname:$TESTDIR/1/first-dir
+
+Modified Files:
+ file1
+Log Message:
+
+End-Log"
+ fi
+ # There should have an empty log message at this point
+ dotest editor-emptylog-continue-5 "${testcvs} log -N -r1.2 file1" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.2
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 3; selected revisions: 1
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: +0 -0; commitid: ${commitid};
+\*\*\* empty log message \*\*\*
+============================================================================="
+
+ # clean up
+ dokeep
+ # restore the default loginfo script
+ restore_adm
+ cd ../..
+ rm -r 1
+ rm $TESTDIR/editme
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ env)
+ # Test to see if the CVS_PID environment variable is being set
+ mkdir ${TESTDIR}/env
+ cd ${TESTDIR}/env
+ dotest env-1 "${testcvs} -Q co . >>${LOGFILE}" ''
+
+ cat > ${TESTDIR}/env/test-cvs-pid <<EOF
+#!${TESTSHELL}
+if test "x\$CVS_PID" != "x"; then
+ # In local mode, there is no directory with the pid in it for use.
+ # In remote mode the CVS_PID will be the parent process of the
+ # cvs process that runs the commitinfo script.
+ if test "x$remote" = "x:" ; then
+ ppid=\`pwd | sed -e 's,.*/cvs-serv,,'\`
+ else
+ # This assumes that the -l switch puts PPID in the banner and does
+ # not run the elements together such that whitespace surrounds the
+ # pid and ppid in the output. This could be made slightly simpler
+ # if all hosts had a 'ps' command that supported the -p switch,
+ # but Solaris 7 /usr/ucb/ps does not and that may be the one we use.
+ # It is because this is so messy that the CVS_PID feature exists.
+ pid=\$\$
+ pidcmd="ps -o pid,ppid -p \$pid || ps -el || ps -al"
+ if echo \$pidcmd | sh >pid.stdout 2> pid.stderr; then
+ ppid=\`cat pid.stdout |\\
+ awk '/PPID/ { for (i=1; i <= NF; i++) {
+ if (\$i == "PPID") ppidx = i;
+ if (\$i == "PID") pidx = i;
+ }
+ next;
+ }
+ { print \$pidx " " \$ppidx }' |\\
+ grep "^\$pid " |\\
+ awk '{ print \$NF }'\`
+ else
+ ppid=unkown
+ fi
+ fi
+ if test "x\$ppid" = "x\${CVS_PID}"; then
+ # The PID looks okay to me
+ # Clean up any temporary files
+ rm -f pid.stdout pid.stderr
+ exit 0
+ else
+ echo The environment variable CVS_PID is not properly set.
+ echo It should have been set to \'\$ppid\' but instead was \'\$CVS_PID\'
+ echo It is possible that this test is broken for your host.
+ echo Current pid: \$pid
+ [ -n "\$pidcmd" ] && echo "Command: \$pidcmd"
+ [ -s pid.stdout ] && echo Standard Out: && cat pid.stdout
+ [ -s pid.stderr ] && echo Standard Error: && cat pid.stderr
+ exit 1
+ fi
+else
+ echo The environment variable CVS_PID is not set.
+ exit 1
+fi
+EOF
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x ${TESTDIR}/env/test-cvs-pid"
+ else
+ chmod +x ${TESTDIR}/env/test-cvs-pid
+ fi
+ cd CVSROOT
+ echo "^env ${TESTDIR}/env/test-cvs-pid %r/%p %s" >>commitinfo
+ dotest env-2 "${testcvs} -q ci -m test-pid commitinfo" \
+"${CVSROOT_DIRNAME}/CVSROOT/commitinfo,v <-- commitinfo
+new revision: 1\.2; previous revision: 1\.1
+${SPROG} commit: Rebuilding administrative file database"
+ cd ..
+ mkdir env
+ dotest env-3 "${testcvs} -q add env" \
+"Directory ${CVSROOT_DIRNAME}/env added to the repository"
+ cd env
+ echo testing >file1
+ dotest env-4 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest env-5 "${testcvs} -q commit -m test-pid" \
+"${CVSROOT_DIRNAME}/env/file1,v <-- file1
+initial revision: 1\.1"
+
+ dokeep
+ # undo commitinfo changes
+ restore_adm
+ cd ../..
+ rm -fr $TESTDIR/env
+ modify_repo rm -rf $CVSROOT_DIRNAME/env
+ ;;
+
+
+
+ errmsg1)
+ modify_repo mkdir $CVSROOT_DIRNAME/1dir
+ mkdir 1
+ cd 1
+ dotest errmsg1-init-1 "$testcvs -Q co 1dir"
+ cd 1dir
+ touch foo
+ dotest errmsg-init-2 "$testcvs -Q add foo"
+ if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then
+ pass 164
+ else
+ fail 164
+ fi
+ cd ../..
+ mkdir 2
+ cd 2
+ if ${testcvs} -q co 1dir >>${LOGFILE}; then
+ pass 165
+ else
+ fail 165
+ fi
+ chmod a-w 1dir
+ cd ../1/1dir
+ rm foo;
+ if ${testcvs} rm foo >>${LOGFILE} 2>&1; then
+ pass 166
+ else
+ fail 166
+ fi
+ if ${testcvs} ci -m removed >>${LOGFILE} 2>&1; then
+ pass 167
+ else
+ fail 167
+ fi
+
+ cd ../../2/1dir
+ # The second case in the local and remote versions of errmsg1-168
+ # below happens on Cygwin under Windows, where write privileges
+ # aren't enforced properly.
+ if $remote; then
+ dotest errmsg1-168r "${testcvs} -q update" \
+"${SPROG} update: \`foo' is no longer in the repository
+$CPROG update: unable to remove \./foo: Permission denied" \
+"${SPROG} update: \`foo' is no longer in the repository"
+ else
+ dotest errmsg1-168 "${testcvs} -q update" \
+"${SPROG} update: \`foo' is no longer in the repository
+${SPROG} update: unable to remove foo: Permission denied" \
+"${SPROG} update: \`foo' is no longer in the repository"
+ fi
+
+ dokeep
+ cd ..
+ chmod u+w 1dir
+ cd ..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/1dir
+ ;;
+
+
+
+ errmsg2)
+ # More tests of various miscellaneous error handling,
+ # and cvs add behavior in general.
+ # See also test basicb-4a, concerning "cvs ci CVS".
+ # Too many tests to mention test the simple cases of
+ # adding files and directories.
+ # Test basicb-2a10 tests cvs -n add.
+
+ # First the usual setup; create a directory first-dir.
+ mkdir 1; cd 1
+ dotest errmsg2-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest errmsg2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ dotest_fail errmsg2-3 "${testcvs} add CVS" \
+"${CPROG} add: cannot add special file .CVS.; skipping"
+ touch file1
+ # For the most part add returns a failure exitstatus if
+ # there are any errors, even if the remaining files are
+ # processed without incident. The "cannot add
+ # special file" message fits this pattern, at
+ # least currently.
+ dotest_fail errmsg2-4 "${testcvs} add CVS file1" \
+"${CPROG} add: cannot add special file .CVS.; skipping
+${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ # I'm not sure these tests completely convey the various strange
+ # behaviors that CVS had before it specially checked for "." and
+ # "..". Suffice it to say that these are unlikely to work right
+ # without a special case.
+ dotest_fail errmsg2-5 "${testcvs} add ." \
+"${CPROG} add: cannot add special file .\..; skipping"
+ dotest_fail errmsg2-6 "${testcvs} add .." \
+"${CPROG} add: cannot add special file .\.\..; skipping"
+ # Make sure that none of the error messages left droppings
+ # which interfere with normal operation.
+ dotest errmsg2-7 "${testcvs} -q ci -m add-file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ mkdir sdir
+ cd ..
+ dotest errmsg2-8 "${testcvs} add first-dir/sdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository"
+ # while we're here... check commit with no CVS directory
+ dotest_fail errmsg2-8a "${testcvs} -q ci first-dir nonexistant" \
+"${CPROG} commit: nothing known about .nonexistant'
+${CPROG} \[commit aborted\]: correct above errors first!"
+ dotest_fail errmsg2-8b "$testcvs -q ci nonexistant first-dir" \
+"$CPROG commit: nothing known about .nonexistant'
+$CPROG \[commit aborted\]: correct above errors first!"
+ dotest errmsg2-8c "$testcvs -q ci first-dir"
+
+ cd first-dir
+
+ touch file10
+ mkdir sdir10
+ dotest errmsg2-10 "${testcvs} add file10 sdir10" \
+"${SPROG} add: scheduling file .file10. for addition
+Directory ${CVSROOT_DIRNAME}/first-dir/sdir10 added to the repository
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest errmsg2-11 "${testcvs} -q ci -m add-file10" \
+"$CVSROOT_DIRNAME/first-dir/file10,v <-- file10
+initial revision: 1\.1"
+ # Try to see that there are no droppings left by
+ # any of the previous tests.
+ dotest errmsg2-12 "${testcvs} -q update" ""
+
+ # Now test adding files with '/' in the name, both one level
+ # down and more than one level down.
+ cd ..
+ mkdir first-dir/sdir10/ssdir
+ dotest errmsg2-13 "${testcvs} add first-dir/sdir10/ssdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/sdir10/ssdir added to the repository"
+
+ touch first-dir/sdir10/ssdir/ssfile
+ dotest errmsg2-14 \
+ "${testcvs} add first-dir/sdir10/ssdir/ssfile" \
+"${SPROG} add: scheduling file .first-dir/sdir10/ssdir/ssfile. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ touch first-dir/file15
+ dotest errmsg2-15 "${testcvs} add first-dir/file15" \
+"${SPROG} add: scheduling file .first-dir/file15. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ # Now the case where we try to give it a directory which is not
+ # under CVS control.
+ mkdir bogus-dir
+ touch bogus-dir/file16
+ # FIXCVS: The first message, from local CVS, is nice. The second one
+ # is not nice; would be good to fix remote CVS to give a clearer
+ # message (e.g. the one from local CVS). But at least it is an
+ # error message.
+ dotest_fail errmsg2-16 "${testcvs} add bogus-dir/file16" \
+"${SPROG} add: in directory \`bogus-dir':
+${SPROG} \[add aborted\]: there is no version here; do .${SPROG} checkout. first" \
+"${CPROG} add: cannot open CVS/Entries for reading: No such file or directory
+${CPROG} \[add aborted\]: no repository"
+ rm -r bogus-dir
+
+ # One error condition we don't test for is trying to add a file
+ # or directory which already is there.
+
+ dotest errmsg2-17 "${testcvs} -q ci -m checkin" \
+"$CVSROOT_DIRNAME/first-dir/file15,v <-- first-dir/file15
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/sdir10/ssdir/ssfile,v <-- first-dir/sdir10/ssdir/ssfile
+initial revision: 1\.1"
+ dotest errmsg2-18 "${testcvs} -Q tag test" ''
+
+ # trying to import the repository
+
+ if $remote; then :; else
+ cd ${CVSROOT_DIRNAME}
+ dotest_fail errmsg2-20 "${testcvs} import -mtest . A B" \
+"${SPROG} \[import aborted\]: attempt to import the repository"
+ dotest_fail errmsg2-21 "${testcvs} import -mtest first-dir A B" \
+"${SPROG} \[import aborted\]: attempt to import the repository"
+ fi
+
+ dokeep
+ cd ..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ errmsg3)
+ # Test the *PANIC* message caused by missing administration files
+ mkdir errmsg3
+ cd errmsg3
+ mkdir CVS
+ dotest_fail errmsg3-1 "${testcvs} -q up" \
+"${CPROG} update: in directory \`.':
+${CPROG} update: CVS directory found without administrative files\.
+${CPROG} update: Use CVS to create the CVS directory, or rename the
+${CPROG} update: directory if it is intended to store something
+${CPROG} update: besides CVS administrative files\.
+${CPROG} \[update aborted\]: \*PANIC\* administration files missing!"
+
+ dokeep
+ cd ..
+ rm -r errmsg3
+ ;;
+
+
+
+ close-stdout)
+ # Ensure that cvs update -p FILE > /dev/full fails
+ # Perform this test IFF /dev/full is a writable character device.
+ if test -w /dev/full && test -c /dev/full; then
+ mkdir close-stdout
+ cd close-stdout
+ echo a > file
+ dotest close-stdout-1 "$testcvs -Q import -m. closeout X Y" ''
+ dotest close-stdout-2 "$testcvs -Q co closeout" ''
+ # Match either a bare `write error' or
+ # `write error: No space left on device',
+ # since closeout.c can produce both.
+ dotest_fail close-stdout-3 \
+ "${testcvs} -Q update -p closeout/file > /dev/full" \
+ "${CPROG} \[update aborted\]: write error.*"
+
+ dokeep
+ cd ..
+ rm -r close-stdout
+ modify_repo rm -rf $CVSROOT_DIRNAME/closeout
+ else
+ skip close-stdout '/dev/full is not available'
+ fi
+ ;;
+
+
+
+ debug-log-nonfatal)
+ # Once upon a time, failure to create the debug log could be fatal.
+ if $remote; then :; else
+ remoteonly debug-log-nonfatal
+ continue
+ fi
+
+ mkdir $TESTDIR/unwritable
+ chmod a-w $TESTDIR/unwritable
+ if test -n "$CVS_CLIENT_LOG"; then
+ save_CVS_CLIENT_LOG=$CVS_CLIENT_LOG
+ fi
+ CVS_CLIENT_LOG=$TESTDIR/unwritable/cvsclientlog
+ export CVS_CLIENT_LOG
+
+ dotest debug-log-nonfatal-1 \
+"$testcvs -Q co -p CVSROOT/config >/dev/null" \
+"$CPROG checkout: opening to-server logfile $TESTDIR/unwritable/cvsclientlog.in: Permission denied
+$CPROG checkout: opening from-server logfile $TESTDIR/unwritable/cvsclientlog.out: Permission denied"
+
+ dokeep
+ rm -rf $TESTDIR/unwritable
+ unset CVS_CLIENT_LOG
+ if test -n "$save_CVS_CLIENT_LOG"; then
+ CVS_CLIENT_LOG=$save_CVS_CLIENT_LOG
+ fi
+ ;;
+
+
+
+ adderrmsg)
+ # Test some of the error messages the 'add' command can return and
+ # their reactions to '-q'.
+
+ # First the usual setup; create a directory first-dir.
+ mkdir 1; cd 1
+ dotest adderrmsg-init1 "${testcvs} -q co -l ." ''
+ mkdir adderrmsg-dir
+ dotest adderrmsg-init2 "${testcvs} add adderrmsg-dir" \
+"Directory ${CVSROOT_DIRNAME}/adderrmsg-dir added to the repository"
+ cd adderrmsg-dir
+
+ # try to add the admin dir
+ dotest_fail adderrmsg-1 "${testcvs} add CVS" \
+"${CPROG} add: cannot add special file .CVS.; skipping"
+ # might not want to see this message when you 'cvs add *'
+ dotest_fail adderrmsg-2 "${testcvs} -q add CVS" ""
+
+ # to test some other messages
+ touch file1
+ dotest adderrmsg-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ # add it twice
+ dotest_fail adderrmsg-4 "${testcvs} add file1" \
+"${SPROG} add: \`file1' has already been entered"
+ dotest_fail adderrmsg-5 "${testcvs} -q add file1" ""
+
+ dotest adderrmsg-6 "${testcvs} -q ci -madd" \
+"$CVSROOT_DIRNAME/adderrmsg-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ # file in Entries & repository
+ dotest_fail adderrmsg-7 "${testcvs} add file1" \
+"${SPROG} add: \`file1' already exists, with version number 1\.1"
+ dotest_fail adderrmsg-8 "${testcvs} -q add file1" ""
+
+ # clean up
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/adderrmsg-dir
+ ;;
+
+
+
+ opterrmsg)
+ # Test some option parsing error messages
+
+ # No init is necessary since these error messages are printed b4
+ # CVS looks for a sandbox or repository
+
+ # -z used to accept non-numeric arguments. This bit someone who
+ # attempted `cvs -z -n up' when the -n was read as the argument to
+ # -z.
+ dotest_fail opterrmsg-1 "${testcvs} -z -n up" \
+"${CPROG}: gzip compression level must be between 0 and 9"
+
+ # Some general -z checks
+ dotest_fail opterrmsg-2 "${testcvs} -z -1 up" \
+"${CPROG}: gzip compression level must be between 0 and 9"
+ dotest_fail opterrmsg-3 "${testcvs} -z10 up" \
+"${CPROG}: gzip compression level must be between 0 and 9"
+ ;;
+
+
+
+ devcom)
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1
+ cd 1
+ dotest devcom-1 "$testcvs -q co first-dir"
+
+ cd first-dir
+ echo abb >abb
+ dotest devcom-2 "$testcvs add abb" \
+"$SPROG add: scheduling file \`abb' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+
+ dotest devcom-3 "$testcvs -q ci -m added" \
+"$CVSROOT_DIRNAME/first-dir/abb,v <-- abb
+initial revision: 1\.1"
+
+ dotest_fail devcom-4 "$testcvs watch" "Usage$DOTSTAR"
+
+ dotest devcom-5 "$testcvs watch on"
+
+ echo abc >abc
+ dotest devcom-6 "$testcvs add abc" \
+"$SPROG add: scheduling file \`abc' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+
+ dotest devcom-7 "$testcvs -q ci -m added" \
+"$CVSROOT_DIRNAME/first-dir/abc,v <-- abc
+initial revision: 1\.1"
+
+ cd ../..
+ mkdir 2
+ cd 2
+
+ dotest devcom-8 "$testcvs -q co first-dir" \
+"U first-dir/abb
+U first-dir/abc"
+
+ cd first-dir
+ dotest_fail devcom-9 "test -w abb"
+ dotest_fail devcom-9b "test -w abc"
+
+ dotest devcom-10 "$testcvs editors"
+ dotest devcom-11 "$testcvs edit abb"
+
+ # Here we test for the traditional ISO C ctime() date format.
+ # We assume the C locale; I guess that works provided we set
+ # LC_ALL at the start of this script but whether these
+ # strings should vary based on locale does not strike me as
+ # self-evident.
+ dotest devcom-12 "$testcvs editors" \
+"abb ${username} [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 [-a-zA-Z_.0-9]* ${TESTDIR}/2/first-dir"
+
+ echo aaaa >>abb
+ dotest devcom-13 "$testcvs ci -m modify abb" \
+"${CVSROOT_DIRNAME}/first-dir/abb,v <-- abb
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Unedit of a file not being edited should be a noop.
+ dotest devcom-14 "$testcvs unedit abb" ''
+
+ dotest devcom-15 "$testcvs editors" ""
+
+ dotest_fail devcom-16 "test -w abb"
+
+ dotest devcom-17 "$testcvs edit abc"
+
+ # Unedit of an unmodified file.
+ dotest devcom-18 "$testcvs unedit abc"
+ dotest devcom-19 "$testcvs edit abc"
+
+ echo changedabc >abc
+ # Try to unedit a modified file; cvs should ask for confirmation
+ dotest devcom-20 "echo no | $testcvs unedit abc" \
+"abc has been modified; revert changes? "
+
+ dotest devcom-21 "echo changedabc | cmp - abc"
+
+ # OK, now confirm the unedit
+ dotest devcom-22 "echo yes |$testcvs unedit abc" \
+"abc has been modified; revert changes? "
+
+ dotest devcom-23 "echo abc |cmp - abc"
+
+ dotest devcom-24 "$testcvs watchers" ''
+
+ # FIXME: This probably should be an error message instead
+ # of silently succeeding and printing nothing.
+ dotest devcom-a-nonexist "$testcvs watchers nonexist" ''
+
+ dotest devcom-a1 "$testcvs watch add" ''
+ dotest devcom-a2 "$testcvs watchers" \
+"abb $username edit unedit commit
+abc $username edit unedit commit"
+ dotest devcom-a3 "$testcvs watch remove -a unedit abb" ''
+ dotest devcom-a4 "$testcvs watchers abb" \
+"abb $username edit commit"
+
+ # Check tagging and checking out while we have a CVS
+ # directory in the repository.
+ dotest devcom-t0 "${testcvs} -q tag tag" \
+'T abb
+T abc'
+ cd ../..
+ mkdir 3
+ cd 3
+
+ # Test commented out because the bug it tests for is not fixed
+ # The error is:
+ # cvs watchers: cannot open CVS/Entries for reading: No such file or directory
+ # cvs: ../../work/ccvs/src/fileattr.c:75: fileattr_read: Assertion `fileattr_stored_repos != ((void *)0)' failed.
+: dotest devcom-t-nonexist "${testcvs} watchers nonexist" fixme
+
+ dotest devcom-t1 "${testcvs} -q co -rtag first-dir/abb" \
+'U first-dir/abb'
+ cd ..
+ # Since first-dir/abb is readonly, use -f.
+ rm -rf 3
+
+ # Test checking out the directory rather than the file.
+ mkdir 3
+ cd 3
+ dotest devcom-t2 "${testcvs} -q co -rtag first-dir" \
+'U first-dir/abb
+U first-dir/abc'
+ cd ..
+ # Since the files are readonly, use -f.
+ rm -rf 3
+
+ # Now do it again, after removing the val-tags file created
+ # by devcom-t1 to force CVS to search the repository
+ # containing CVS directories.
+ rm ${CVSROOT_DIRNAME}/CVSROOT/val-tags
+ mkdir 3
+ cd 3
+ dotest devcom-t3 "${testcvs} -q co -rtag first-dir" \
+'U first-dir/abb
+U first-dir/abc'
+ cd ..
+ # Since the files are readonly, use -f.
+ rm -rf 3
+
+ # Now remove all the file attributes
+ cd 2/first-dir
+ dotest devcom-b0 "${testcvs} watch off" ''
+ dotest devcom-b1 "${testcvs} watch remove" ''
+ # Test that CVS 1.6 and earlier can handle the repository.
+ dotest_fail devcom-b2 "test -d ${CVSROOT_DIRNAME}/first-dir/CVS"
+
+ # Now test watching just some, not all, files.
+ dotest devcom-some0 "${testcvs} watch on abc" ''
+ cd ../..
+ mkdir 3
+ cd 3
+ dotest devcom-some1 "${testcvs} -q co first-dir" 'U first-dir/abb
+U first-dir/abc'
+ dotest devcom-some2 "test -w first-dir/abb" ''
+ dotest_fail devcom-some3 "test -w first-dir/abc" ''
+
+ dokeep
+ cd ..
+ # Use -f because of the readonly files.
+ rm -rf 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ devcom2)
+ # More watch tests, most notably setting watches on
+ # files in various different states.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1
+ cd 1
+ dotest devcom2-1 "${testcvs} -q co first-dir" ''
+ cd first-dir
+
+ # This should probably be an error; setting a watch on a totally
+ # unknown file is more likely to be a typo than intentional.
+ # But that isn't the currently implemented behavior.
+ dotest devcom2-2 "${testcvs} watch on w1" ''
+
+ touch w1 w2 w3 nw1
+ dotest devcom2-3 "${testcvs} add w1 w2 w3 nw1" "${DOTSTAR}"
+ # Letting the user set the watch here probably can be considered
+ # a feature--although it leads to a few potentially strange
+ # consequences like one user can set the watch and another actually
+ # adds the file.
+ dotest devcom2-4 "${testcvs} watch on w2" ''
+ dotest devcom2-5 "${testcvs} -Q ci -m add-them"
+
+ # Note that this test differs in a subtle way from devcom-some0;
+ # in devcom-some0 the watch is creating a new fileattr file, and
+ # here we are modifying an existing one.
+ dotest devcom2-6 "${testcvs} watch on w3" ''
+
+ # Now test that all the watches got set on the correct files
+ # FIXME: CVS should have a way to report whether watches are
+ # set, I think. The "check it out and see if it read-only" is
+ # sort of OK, but is complicated by CVSREAD and doesn't help
+ # if the file is added and not yet committed or some such.
+ # Probably "cvs status" should report "watch: on" if watch is on
+ # (and nothing if watch is off, so existing behavior is preserved).
+ cd ../..
+ mkdir 2
+ cd 2
+ dotest devcom2-7 "${testcvs} -q co first-dir" 'U first-dir/nw1
+U first-dir/w1
+U first-dir/w2
+U first-dir/w3'
+ dotest devcom2-8 "test -w first-dir/nw1" ''
+ dotest_fail devcom2-9 "test -w first-dir/w1" ''
+ dotest_fail devcom2-10 "test -w first-dir/w2" ''
+ dotest_fail devcom2-11 "test -w first-dir/w3" ''
+
+ cd first-dir
+ # OK, now we want to try files in various states with cvs edit.
+ dotest_fail devcom2-12 "$testcvs edit w4" \
+"${CPROG} edit: no such file w4; ignored"
+ # Try the same thing with a per-directory watch set.
+ dotest devcom2-13 "${testcvs} watch on" ''
+ dotest_fail devcom2-14 "$testcvs edit w5" \
+"${CPROG} edit: no such file w5; ignored"
+ dotest devcom2-15 "${testcvs} editors" ''
+ dotest devcom2-16 "${testcvs} editors w4" ''
+ # Make sure there are no droppings lying around
+ dotest devcom2-17 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
+"Fw1 _watched=
+Fw2 _watched=
+Fw3 _watched=
+Fnw1 _watched=
+D _watched="
+ cd ..
+
+ # Do a little error testing
+ dotest devcom2-18 "${testcvs} -q co -d first+dir first-dir" \
+"U first${PLUS}dir/nw1
+U first${PLUS}dir/w1
+U first${PLUS}dir/w2
+U first${PLUS}dir/w3"
+ cd first+dir
+ dotest_fail devcom2-19 "${testcvs} edit" \
+"${CPROG} \[edit aborted\]: current directory (${TESTDIR}/2/first${PLUS}dir) contains an invalid character (${PLUS},>;=\\\\t\\\\n)"
+
+ # Make sure there are no droppings lying around
+ dotest devcom2-20 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
+"Fw1 _watched=
+Fw2 _watched=
+Fw3 _watched=
+Fnw1 _watched=
+D _watched="
+
+ dokeep
+ cd ../..
+ # Use -f because of the readonly files.
+ rm -rf 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ devcom3)
+ # More watch tests, most notably handling of features designed
+ # for future expansion.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1
+ cd 1
+
+ # Set up logging via the postwatch script hook. See the `info' test
+ # for a list of tests where other script hooks are tested.
+ dotest devcom3-init-1 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ echo "ALL $TESTDIR/1/loggit %r %p %c" >>postwatch
+ dotest devcom3-init-2 "$testcvs -Q ci -mlog-watch"
+ cd .. # 1
+
+ cat >loggit <<EOF
+#!$TESTSHELL
+echo \${1+"\$@"} >>$TESTDIR/1/watch-log
+EOF
+ # #^@&!^@ Cygwin.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x $TESTDIR/1/loggit"
+ else
+ chmod +x loggit
+ fi
+
+
+
+ dotest devcom3-1 "$testcvs -q co first-dir"
+ cd first-dir
+
+ touch w1 w2
+ dotest devcom3-2 "${testcvs} add w1 w2" "${DOTSTAR}"
+ dotest devcom3-3 "${testcvs} watch on w1 w2" ''
+ dotest devcom3-4 "${testcvs} -Q ci -m add-them"
+
+ # OK, since we are about to delve into CVS's internals, make
+ # sure that we seem to be correct about how they work.
+ dotest devcom3-5 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
+"Fw1 _watched=
+Fw2 _watched="
+ # Now write a few more lines, just as if we were a newer version
+ # of CVS implementing some new feature.
+ cat <<'EOF' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr
+Enew line here
+G@#$^!@#=&
+EOF
+ # Now get CVS to write to the fileattr file....
+ dotest devcom3-6 "${testcvs} watch off w1" ''
+ # ...and make sure that it hasn't clobbered our new lines.
+ # Note that writing these lines in another order would be OK
+ # too.
+ dotest devcom3-7 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
+"Fw2 _watched=
+G@#..!@#=&
+Enew line here"
+
+ # See what CVS does when a file name is duplicated. The
+ # behavior of all versions of CVS since file attributes were
+ # implemented is that it nukes the duplications. This seems
+ # reasonable enough, although it means it isn't clear how
+ # useful duplicates would be for purposes of future
+ # expansion. But in the interests of keeping behaviors
+ # predictable, might as well test for it, I guess.
+ echo 'Fw2 duplicate=' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr
+ dotest devcom3-8 "${testcvs} watch on w1" ''
+ dotest devcom3-9 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
+"Fw2 _watched=
+Fw1 _watched=
+Enew line here
+G@#..!@#=&"
+
+ # Now test disconnected "cvs edit" and the format of the
+ # CVS/Notify file.
+ if $remote; then
+ CVS_SERVER_save=$CVS_SERVER
+ CVS_SERVER=$TESTDIR/cvs-none; export CVS_SERVER
+
+ # The ${DOTSTAR} below matches the exact CVS server error message,
+ # which in :fork: mode is:
+ # "$SPROG \[edit aborted\]: cannot exec $TESTDIR/cvs-none: ${DOTSTAR}",
+ # but which is:
+ # "bash2: line 1: $TESTDIR/cvs-none: No such file or directory"
+ # when testing across an :ext:/ssh link to my Linux 2.4 box.
+ #
+ # I can't even test for the second part of the error message,
+ # from the client, which varies more consistently, usually either
+ # "end of file from server" (if the process doing the exec exits
+ # before the parent gets around to sending data to it) or
+ # "received broken pipe signal" (if it is the other way around),
+ # since HP-UX fails to output it.
+ dotest_fail devcom3-9ar "$testcvs edit w1 2>/dev/null"
+ dotest devcom3-9br "test -w w1"
+ dotest devcom3-9cr "cat CVS/Notify" \
+"Ew1 [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 [-a-zA-Z_.0-9]* ${TESTDIR}/1/first-dir EUC"
+ CVS_SERVER=${CVS_SERVER_save}; export CVS_SERVER
+ if $proxy; then
+ dotest_fail devcom3-9dp "$testcvs -q update" \
+"This CVS server does not support disconnected \`cvs edit'\. For now, remove all \`CVS/Notify' files in your workspace and try your command again\."
+ dotest devcom3-9ep "test -f CVS/Notify"
+ rm CVS/Notify
+ dotest devcom3-9hp "$testcvs watchers w1"
+ else
+ dotest devcom3-9dr "$testcvs -q update"
+ dotest_fail devcom3-9er "test -f CVS/Notify"
+ dotest devcom3-9fr "$testcvs watchers w1" \
+"w1 $username tedit tunedit tcommit"
+ fi
+ dotest devcom3-9gr "$testcvs unedit w1"
+ dotest devcom3-9hr "$testcvs watchers w1"
+ fi
+
+ cd ../..
+ # OK, now change the tab to a space, and see that CVS gives
+ # a reasonable error (this is database corruption but CVS should
+ # not lose its mind).
+ sed -e 's/Fw2 /Fw2 /' <$CVSROOT_DIRNAME/first-dir/CVS/fileattr \
+ >$CVSROOT_DIRNAME/first-dir/CVS/fileattr.new
+ modify_repo mv $CVSROOT_DIRNAME/first-dir/CVS/fileattr.new \
+ $CVSROOT_DIRNAME/first-dir/CVS/fileattr
+ mkdir 2; cd 2
+ dotest_fail devcom3-10 "${testcvs} -Q co ." \
+"${SPROG} \[checkout aborted\]: file attribute database corruption: tab missing in ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr"
+
+ notifyworks=false
+ if $remote; then
+ if $proxy; then :; else
+ notifyworks=:
+ fi
+ fi
+ if $notifyworks; then
+ dotest devcom3-postwatch-examine-1r "cat $TESTDIR/1/watch-log" \
+"$CVSROOT_DIRNAME first-dir watch
+$CVSROOT_DIRNAME first-dir watch
+$CVSROOT_DIRNAME first-dir watch
+$CVSROOT_DIRNAME first-dir update
+$CVSROOT_DIRNAME first-dir server"
+ else
+ dotest devcom3-postwatch-examine-1 "cat $TESTDIR/1/watch-log" \
+"$CVSROOT_DIRNAME first-dir watch
+$CVSROOT_DIRNAME first-dir watch
+$CVSROOT_DIRNAME first-dir watch"
+ fi
+
+ dokeep
+ restore_adm
+ cd ..
+ # Use -f because of the readonly files.
+ rm -rf 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ watch4)
+ # More watch tests, including adding directories.
+ mkdir 1; cd 1
+ dotest watch4-0a "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest watch4-0b "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+
+ cd first-dir
+ dotest watch4-1 "${testcvs} watch on" ''
+ # This is just like the 173 test
+ touch file1
+ dotest watch4-2 "$testcvs add file1" \
+"$SPROG add: scheduling file .file1. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest watch4-3 "$testcvs -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ # Now test the analogous behavior for directories.
+ mkdir subdir
+ dotest watch4-4 "${testcvs} add subdir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"
+ cd subdir
+ touch sfile
+ dotest watch4-5 "${testcvs} add sfile" \
+"${SPROG} add: scheduling file .sfile. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest watch4-6 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/subdir/sfile,v <-- sfile
+initial revision: 1\.1"
+ cd ../../..
+ mkdir 2; cd 2
+ dotest watch4-7 "${testcvs} -q co first-dir" "U first-dir/file1
+U first-dir/subdir/sfile"
+ dotest_fail watch4-8 "test -w first-dir/file1" ''
+ dotest_fail watch4-9 "test -w first-dir/subdir/sfile" ''
+ cd first-dir
+ dotest watch4-10 "${testcvs} edit file1" ''
+ echo 'edited in 2' >file1
+ cd ../..
+
+ cd 1/first-dir
+
+ # NOTE: I'm leaving in '' as acceptable
+ # to maintain partial compatibility with CVS versions
+ # prior to the edit check patch.
+ editorsLineRE="file1 $username [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR/2/first-dir"
+ dotest watch4-11 "$testcvs edit file1" "$editorsLineRE"
+
+ echo 'edited in 1' >file1
+ dotest watch4-12 "${testcvs} -q ci -m edit-in-1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../..
+ cd 2/first-dir
+ dotest watch4-13 "${testcvs} -q update" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into file1
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in file1
+C file1"
+ if (echo yes | ${testcvs} unedit file1) >>${LOGFILE}; then
+ pass watch4-14
+ else
+ fail watch4-15
+ fi
+ # This could plausibly be defined to either go back to the revision
+ # which was cvs edit'd (the status quo), or back to revision 1.2
+ # (that is, the merge could update CVS/Base/file1). We pick the
+ # former because it is easier to implement, not because we have
+ # thought much about which is better.
+ dotest watch4-16 "cat file1" ''
+ # Make sure CVS really thinks we are at 1.1.
+ dotest watch4-17 "${testcvs} -q update" "U file1"
+ dotest watch4-18 "cat file1" "edited in 1"
+ cd ../..
+
+ # As a sanity check, make sure we are in the right place.
+ dotest watch4-cleanup-1 "test -d 1"
+ dotest watch4-cleanup-1 "test -d 2"
+
+ dokeep
+ # Specify -f because of the readonly files.
+ rm -rf 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ watch5)
+ # This test was designed to catch a problem in server
+ # mode where an 'cvs edit'd file disappeared from the
+ # CVS/Base directory when 'cvs status' or 'cvs update'
+ # was called on the file after the file was touched.
+ #
+ # This test is still here to prevent the bug from
+ # being reintroduced.
+ #
+ # The rationale for having CVS/Base stay around is that
+ # CVS/Base should be there if "cvs edit" has been run (this
+ # may be helpful as a "cvs editors" analogue, it is
+ # client-side and based on working directory not username;
+ # but more importantly, it isn't clear why a "cvs status"
+ # would act like an unedit, and even if it does, it would
+ # need to make the file read-only again).
+
+ mkdir watch5; cd watch5
+ dotest watch5-0a "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest watch5-0b "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+
+ cd first-dir
+ dotest watch5-1 "${testcvs} watch on" ''
+ # This is just like the 173 test
+ touch file1
+ dotest watch5-2 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest watch5-3 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ dotest watch5-4 "${testcvs} edit file1" ''
+ dotest watch5-5 "test -f CVS/Base/file1" ''
+ if ${testcvs} status file1 >>${LOGFILE} 2>&1; then
+ pass watch5-6
+ else
+ fail watch5-6
+ fi
+ dotest watch5-7 "test -f CVS/Base/file1" ''
+
+ # Here's where the file used to dissappear
+ touch file1
+ if ${testcvs} status file1 >>${LOGFILE} 2>&1; then
+ pass watch5-8
+ else
+ fail watch5-8
+ fi
+ dotest watch5-10 "test -f CVS/Base/file1" ''
+
+ # Make sure update won't remove the file either
+ touch file1
+ dotest watch5-11 "${testcvs} -q up" ''
+ dotest watch5-12 "test -f CVS/Base/file1" ''
+
+ dokeep
+ cd ../..
+ rm -r watch5
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ watch6-0)
+
+ # Make sure that default attributes are being set properly.
+ # Specifying a directory has, it seems, never worked,
+ # and 1.12.10 broke it completely.
+ mkdir watch6-0; cd watch6-0
+
+ dotest watch6-0-setup-1 "$testcvs -Q co -ldtop ."
+ cd top
+ mkdir watch6-0
+ dotest watch6-0-setup-2 "$testcvs -Q add watch6-0"
+ cd watch6-0
+ dotest watch6-0-1 "$testcvs watch add"
+ dotest watch6-0-2 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr"
+ dotest watch6-0-3 "$testcvs watch remove"
+ dotest_fail watch6-0-4 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr 2>/dev/null"
+
+ dotest watch6-0-5 "$testcvs watch add ."
+ dotest watch6-0-6 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr"
+ dotest watch6-0-7 "$testcvs watch remove ."
+ dotest_fail watch6-0-8 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr 2>/dev/null"
+
+ # OK, basic add/remove work. Now, make sure it works with named directories
+ mkdir dir1
+ mkdir dir2
+ mkdir dir3
+ echo afile>afile
+ $testcvs -Q add afile dir1 dir2 dir3
+ $testcvs -Q ci -m "Adding test files"
+
+ # Current directory should not be watched, but there should be a watch on the file,
+ # and on dir1 & dir2, but not on dir3.
+ dotest watch6-0-9 "$testcvs -Q watch add afile dir1 dir2"
+ dotest_fail watch6-0-10 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr 2>/dev/null"
+ dotest watch6-0-11 "grep -qE '^Fafile' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr"
+ dotest watch6-0-12 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/dir1/CVS/fileattr"
+ dotest watch6-0-13 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/dir2/CVS/fileattr"
+ dotest_fail watch6-0-12 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/dir3/CVS/fileattr 2>/dev/null"
+
+ dokeep
+ cd ../../..
+ rm -rf watch6-0
+ modify_repo rm -rf $CVSROOT_DIRNAME/watch6-0
+ ;;
+
+
+
+ watch6)
+ # Check that `cvs watch on' does not reset the fileattr file.
+ mkdir watch6; cd watch6
+
+ dotest watch6-setup-1 "$testcvs -Q co -ldtop ."
+ cd top
+ mkdir watch6
+ dotest watch6-setup-2 "$testcvs -Q add watch6"
+
+ # I don't recall why I had these next 3 lines.
+ cd ..
+ dotest watch6-setup-3 "$testcvs -Q co watch6"
+ cd watch6
+
+ mkdir subdir
+ dotest watch6-setup-4 "$testcvs -Q add subdir"
+ cd subdir
+
+ # START watch add/remove sequence
+ dotest watch6-1 "$testcvs -Q watch add"
+ dotest watch6-2 \
+"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+
+ dotest watch6-3 "$testcvs watch on"
+ dotest watch6-4 \
+"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+ dotest watch6-5 \
+"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+
+ dotest watch6-6 "$testcvs watch off"
+ dotest watch6-7 \
+"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+ dotest_fail watch6-8 \
+"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+
+ dotest watch6-9 "$testcvs watch remove"
+ dotest_fail watch6-10 \
+"test -d $CVSROOT_DIRNAME/test-directory/subdir/CVS"
+ dotest_fail watch6-11 \
+"test -f $CVSROOT_DIRNAME/test-directory/subdir/CVS/fileattr"
+ # END watch add/remove sequence
+
+ echo Hi there >afile
+ dotest watch6-12 "$testcvs -Q add afile"
+ dotest watch6-13 "$testcvs ci -m 'A file' afile" \
+"$CVSROOT_DIRNAME/watch6/subdir/afile,v <-- afile
+initial revision: 1.1"
+
+ # START watch add/remove sequence
+ dotest watch6-14 "$testcvs -Q watch add"
+ dotest watch6-15 \
+"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+
+ dotest watch6-16 "$testcvs watch on"
+ dotest watch6-17 \
+"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+ dotest watch6-18 \
+"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+
+ dotest watch6-19 "$testcvs watch off"
+ dotest watch6-20 \
+"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+ dotest_fail watch6-21 \
+"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
+
+ dotest watch6-22 "$testcvs watch remove"
+ dotest_fail watch6-23 \
+"test -d $CVSROOT_DIRNAME/test-directory/subdir/CVS"
+ dotest_fail watch6-24 \
+"test -f $CVSROOT_DIRNAME/test-directory/subdir/CVS/fileattr"
+ # END watch add/remove sequence
+
+ if $keep; then
+ echo Keeping $TESTDIR and exiting due to --keep
+ exit 0
+ fi
+ cd ../../..
+ rm -r watch6
+ modify_repo rm -rf $CVSROOT_DIRNAME/watch6
+ ;;
+
+
+
+ edit-check)
+ # This tests the edit -c/-f and related features.
+
+ mkdir edit-check; cd edit-check
+ dotest edit-check-0a "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest edit-check-0b "$testcvs add first-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+
+ cd first-dir
+ dotest edit-check-1 "$testcvs watch on"
+
+ echo foo > file1
+ dotest edit-check-2a "$testcvs add -minitial file1" \
+"$SPROG [a-z]*: scheduling file .file1. for addition
+$SPROG [a-z]*: use .$SPROG commit. to add this file permanently"
+
+ dotest edit-check-2b "$testcvs commit -m 'c1' file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ editorsLineRE="file1 $username [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR/edit-check/first-dir"
+
+ R_editorsLineRE="first-dir/file1 $username [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR/edit-check"
+ F3_editorsLineRE="second-dir/file3 $username [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR/edit-check/first-dir"
+
+ A_editorsLineRE="file1 [-a-zA-Z0-9_]* [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR[0-9]*/edit-check/first-dir"
+
+ AF_editorsLineRE="file[12] [-a-zA-Z0-9_]* [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR/edit-check/first-dir"
+
+ NF_editorsLineRE=" [-a-zA-Z0-9_]* [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR/edit-check/first-dir"
+
+ dotest edit-check-3 "$testcvs edit file1"
+ dotest edit-check-4 "$testcvs edit file1" "$editorsLineRE"
+
+ dotest_fail edit-check-5a "$testcvs edit -c file1" \
+"$editorsLineRE
+$SPROG edit: Skipping file \`file1' due to existing editors\."
+
+ dotest edit-check-5b "$testcvs editors" "$editorsLineRE"
+
+ dotest edit-check-6a "$testcvs edit -c -f file1" "$editorsLineRE"
+ dotest edit-check-6b "$testcvs editors" "$editorsLineRE"
+
+ dotest edit-check-7a "cat file1" "foo"
+ echo "bar" > file1
+ dotest_fail edit-check-7b "$testcvs edit -c file1" \
+"$editorsLineRE
+$SPROG edit: Skipping file \`file1' due to existing editors\."
+ dotest edit-check-7c "cat file1" "bar"
+
+ # edit-check-8a has issues. It copies the current (modified)
+ # version of the file into CVS/Base, so that edit-check-9a and
+ # edit-check-9b don't get the expected results.
+ # Maybe unedit is *supposed* to return it to the state
+ # it was in before the edit (even if it was modified),
+ # but while that has a certain symetry, it doesn't seem
+ # to pass the intuitive-usability test.
+ # This aspect of the general problem could
+ # be fixed by not overwriting pre-existing Base versions,
+ # but it still wouldn't fix it if the user manually
+ # modified the file before doing the first edit.
+ # Because of the possibility that this is working as
+ # intended, I'm just commenting out the test, not fixing
+ # the issue.
+ #dotest edit-check-8a "${testcvs} edit -c -f file1" \
+ # "${editorsLineRE}"
+ dotest edit-check-8b "$testcvs editors" "$editorsLineRE"
+
+ dotest edit-check-9a "echo yes | $testcvs unedit file1" \
+"file1 has been modified; revert changes? "
+ dotest edit-check-9b "$testcvs editors"
+ dotest edit-check-9c "cat file1" "foo"
+
+ dotest edit-check-10 "$testcvs edit -c file1"
+ dotest_fail edit-check-11 "$testcvs edit -c file1" \
+"$editorsLineRE
+$SPROG edit: Skipping file \`file1' due to existing editors\."
+
+ echo "morefoo" > file1
+ dotest edit-check-12a "$testcvs commit -m 'c2' -c file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ dotest edit-check-12b "$testcvs editors file1"
+
+ chmod u+w file1
+ echo "morebar" > file1
+ dotest_fail edit-check-13a "$testcvs commit -m 'c3' -c file1" \
+"$SPROG [a-z]*: Valid edit does not exist for file1
+$SPROG \[[a-z]* aborted\]: correct above errors first!"
+ dotest edit-check-13b "$testcvs editors file1"
+
+ dotest edit-check-14a "$testcvs commit -m 'c4' -c -f file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+ dotest edit-check-14b "$testcvs editors file1"
+
+ dotest edit-check-15 "$testcvs edit -c file1"
+ cd ..
+
+ dotest edit-check-16a "echo yes | $testcvs release -d first-dir" \
+"You have \[0\] altered files in this repository.
+Are you sure you want to release (and delete) directory \`first-dir': "
+ dotest edit-check-16b "$testcvs -q update -d first-dir" \
+ "U first-dir/file1"
+ cd first-dir
+ dotest edit-check-16c "$testcvs editors file1"
+
+ cd ..
+ dotest edit-check-17a "$testcvs edit -c"
+ dotest_fail edit-check-17b "$testcvs edit -c" \
+"$R_editorsLineRE
+$SPROG edit: Skipping file \`first-dir/file1' due to existing editors\."
+ dotest edit-check-17c "$testcvs edit -c -f" "$R_editorsLineRE"
+
+ echo "more changes" > first-dir/file1
+ dotest edit-check-18a "$testcvs -q commit -m 'c5' -c" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- first-dir/file1
+new revision: 1\.4; previous revision: 1\.3"
+ dotest edit-check-18b "$testcvs editors"
+
+ cd first-dir
+
+ # Manually fake another editor:
+
+ # Try to gaurantee a seperate name for an "other" user editting
+ # the file.
+ otherUser="dummyUser"
+ if [ x"$USER" = x"$otherUser" ] ; then
+ otherUser="dummyUser2"
+ fi
+ if [ x"$LOGNAME" = x"$otherUser" ] ; then
+ otherUser="dummyUser3"
+ fi
+ tabChar=' '
+
+ backupFileattrName="$CVSROOT_DIRNAME/first-dir/CVS/bak.fileattr.$$"
+ mv $CVSROOT_DIRNAME/first-dir/CVS/fileattr $backupFileattrName
+
+ otherDir="`pwd | sed 's%/edit-check/%2/edit-check/%'`"
+ echo \
+"Ffile1${tabChar}_watched=;_editors=$otherUser>Sat Oct 6 04:25:00 2001 -0000+`hostname`+$otherDir;_watchers=$otherUser>tedit+tunedit+tcommit
+D${tabChar}_watched=" > $CVSROOT_DIRNAME/first-dir/CVS/fileattr
+
+ editFileattrName="$CVSROOT_DIRNAME/first-dir/CVS/edit.fileattr.$$"
+ cp $CVSROOT_DIRNAME/first-dir/CVS/fileattr $editFileattrName
+
+ O_editorsLineRE="file1 $otherUser [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR[0-9]/edit-check/first-dir"
+
+ dotest edit-check-19a "$testcvs edit file1" "$O_editorsLineRE"
+ dotest edit-check-19b "$testcvs editors" \
+"$A_editorsLineRE
+$NF_editorsLineRE"
+
+ dotest edit-check-20a "$testcvs unedit file1"
+ dotest edit-check-20b "$testcvs editors" "$O_editorsLineRE"
+
+ dotest_fail edit-check-21a "$testcvs edit -c file1" \
+"$O_editorsLineRE
+$SPROG edit: Skipping file \`file1' due to existing editors\."
+ dotest edit-check-21b "$testcvs editors" "$O_editorsLineRE"
+
+ dotest edit-check-22a "$testcvs edit -c -f file1" "$O_editorsLineRE"
+ dotest edit-check-22b "$testcvs editors" \
+"$A_editorsLineRE
+$NF_editorsLineRE"
+
+ echo "Yet another change" >file1
+
+ dotest_fail edit-check-23a "$testcvs edit -c" \
+"$A_editorsLineRE
+$NF_editorsLineRE
+$SPROG edit: Skipping file \`file1' due to existing editors\."
+
+ dotest edit-check-23b "$testcvs editors" \
+"$A_editorsLineRE
+$NF_editorsLineRE"
+
+ dotest edit-check-24a "echo y | $testcvs unedit" \
+ "file1 has been modified; revert changes? "
+ dotest edit-check-24b "$testcvs editors" "$O_editorsLineRE"
+ dotest edit-check-24c "cat file1" "more changes"
+
+ dotest edit-check-25a "$testcvs unedit"
+ dotest edit-check-25b "$testcvs editors" "$O_editorsLineRE"
+ dotest_fail edit-check-25c "test -w file1"
+
+ dotest edit-check-26a "$testcvs edit file1" "$O_editorsLineRE"
+ dotest edit-check-26b "$testcvs editors file1" \
+"$A_editorsLineRE
+$NF_editorsLineRE"
+ dotest edit-check-26c "test -w file1"
+
+ echo "Yet more changes" >file1
+ dotest edit-check-27a "$testcvs -q commit -mmsg -c file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4"
+ dotest edit-check-27b "$testcvs editors" "$O_editorsLineRE"
+
+ chmod u+w file1
+ echo "unofficial change" >file1
+
+ dotest_fail edit-check-28a "$testcvs -q commit -mmsg -c" \
+"$SPROG commit: Valid edit does not exist for file1
+$SPROG \[commit aborted\]: correct above errors first!"
+ dotest edit-check-28b "$testcvs editors" "$O_editorsLineRE"
+
+ dotest edit-check-29a "$testcvs -q commit -mmsg -c -f" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.6; previous revision: 1\.5"
+ dotest edit-check-29b "$testcvs editors" "$O_editorsLineRE"
+ dotest edit-check-29c "cat file1" "unofficial change"
+
+ modify_repo cp "$backupFileattrName" \
+ $CVSROOT_DIRNAME/first-dir/CVS/fileattr
+ dotest edit-check-30 "$testcvs editors"
+
+ # Make sure earlier unreported editors are reported properly
+ # with the edit-check code running.
+ if $remote; then
+ CVS_SERVER_SAVED=$CVS_SERVER
+ CVS_SERVER=$TESTDIR/cvs-none; export CVS_SERVER
+
+ # The $DOTSTAR matches the exact exec error message
+ # (which varies) and either "end of file from server"
+ # (if the process doing the exec exits before the parent
+ # gets around to sending data to it) or "broken pipe" (if it
+ # is the other way around).
+ dotest_fail edit-check-31ar "$testcvs edit file1" \
+"$SPROG \[edit aborted\]: cannot exec $TESTDIR/cvs-none: $DOTSTAR"
+ dotest edit-check-31br "test -w file1"
+ dotest edit-check-31cr "cat CVS/Notify" \
+"Efile1 [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 [-a-zA-Z_.0-9]* $TESTDIR/edit-check/first-dir EUC"
+ CVS_SERVER=$CVS_SERVER_SAVED; export CVS_SERVER
+
+ dotest_fail edit-check-31dr "$testcvs edit -c file1" \
+"$editorsLineRE
+$SPROG edit: Skipping file \`file1' due to existing editors\."
+ dotest edit-check-31er "$testcvs editors file1" "$editorsLineRE"
+ dotest edit-check-31fr "$testcvs unedit file1"
+ fi
+
+ # Make sure it isn't confused by handling multiple files at
+ # the same time:
+ echo file2Data >file2
+
+ dotest edit-check-32a "$testcvs add file2" \
+"$SPROG [a-z]*: scheduling file .file2. for addition
+$SPROG [a-z]*: use .$SPROG commit. to add this file permanently"
+
+ dotest edit-check-32b "$testcvs commit -m 'c1' file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+
+ mkdir second-dir
+ dotest edit-check-32c "$testcvs add second-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir/second-dir added to the repository"
+ cd second-dir
+ echo ThirdFile >file3
+
+ dotest edit-check-32d "$testcvs add file3" \
+"$SPROG [a-z]*: scheduling file .file3. for addition
+$SPROG [a-z]*: use .$SPROG commit. to add this file permanently"
+
+ dotest edit-check-32f "$testcvs commit -m 'c1' file3" \
+"$CVSROOT_DIRNAME/first-dir/second-dir/file3,v <-- file3
+initial revision: 1\.1"
+ dotest_fail edit-check-32g "test -w file3"
+
+ cd ..
+
+ dotest edit-check-33a "$testcvs edit -c"
+
+ dotest edit-check-33b "$testcvs editors" \
+"$AF_editorsLineRE
+$AF_editorsLineRE
+$F3_editorsLineRE"
+ dotest edit-check-33c "test -w second-dir/file3"
+
+ dotest_fail edit-check-34a "$testcvs edit -c file1 file2" \
+"$AF_editorsLineRE
+$SPROG edit: Skipping file \`file1' due to existing editors\.
+$AF_editorsLineRE
+$SPROG edit: Skipping file \`file2' due to existing editors\."
+
+ dotest edit-check-34b "$testcvs editors file1 file2" \
+"$editorsLineRE
+$AF_editorsLineRE"
+
+ dotest edit-check-35a "$testcvs unedit file1"
+ dotest edit-check-35b "$testcvs editors" \
+"$AF_editorsLineRE
+$F3_editorsLineRE"
+ dotest edit-check-35c "test -w second-dir/file3"
+
+ dotest edit-check-36a "$testcvs unedit"
+ dotest edit-check-36b "$testcvs editors"
+ dotest_fail edit-check-36c "test -w second-dir/file3"
+
+ dokeep
+ cd ../..
+ rm -rf edit-check
+ rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ unedit-without-baserev)
+ mkdir 1; cd 1
+ module=x
+
+ file=m
+ echo foo > $file
+ dotest unedit-without-baserev-1 \
+ "$testcvs -Q import -m . $module X Y" ''
+ dotest unedit-without-baserev-2 "$testcvs -Q co $module" ''
+ cd $module
+
+ dotest unedit-without-baserev-3 "$testcvs -Q edit $file" ''
+
+ echo add a line >> $file
+ rm -f CVS/Baserev
+
+ # This will fail on most systems.
+ dotest unedit-without-baserev-4 "echo yes |${testcvs} -Q unedit $file" \
+"m has been modified; revert changes${QUESTION} ${CPROG} unedit: m not mentioned in CVS/Baserev
+${CPROG} unedit: run update to complete the unedit"
+
+ # SunOS4.1.4 systems make it this far, but with a corrupted
+ # CVS/Entries file. Demonstrate the corruption!
+ dotest unedit-without-baserev-5 "cat CVS/Entries" \
+ "/$file/1\.1\.1\.1/${DOTSTAR}"
+
+ dotest unedit-without-baserev-6 "${testcvs} -q update" \
+"$SPROG update: warning: \`m' was lost
+U m"
+
+ # OK, those were the easy cases. Now tackle the hard one
+ # (the reason that CVS/Baserev was invented rather than just
+ # getting the revision from CVS/Entries). This is very
+ # similar to watch4-10 through watch4-18 but with Baserev
+ # missing.
+ cd ../..
+ mkdir 2; cd 2
+ dotest unedit-without-baserev-7 "${testcvs} -Q co x" ''
+ cd x
+
+ dotest unedit-without-baserev-10 "${testcvs} edit m" ''
+ echo 'edited in 2' >m
+ cd ../..
+
+ cd 1/x
+
+ editorsLineRE="m $username [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000 $hostname $TESTDIR/2/x"
+ dotest unedit-without-baserev-11 "$testcvs edit m" "$editorsLineRE"
+
+ echo 'edited in 1' >m
+ dotest unedit-without-baserev-12 "${testcvs} -q ci -m edit-in-1" \
+"$CVSROOT_DIRNAME/x/m,v <-- m
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../..
+ cd 2/x
+ dotest unedit-without-baserev-13 "${testcvs} -q update" \
+"RCS file: ${CVSROOT_DIRNAME}/x/m,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1\.1\.1 and 1\.2 into m
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in m
+C m"
+ rm CVS/Baserev
+ dotest unedit-without-baserev-14 "echo yes |${testcvs} unedit m" \
+"m has been modified; revert changes${QUESTION} ${CPROG} unedit: m not mentioned in CVS/Baserev
+${CPROG} unedit: run update to complete the unedit"
+ dotest unedit-without-baserev-15 "${testcvs} -q update" \
+"$SPROG update: warning: \`m' was lost
+U m"
+ # The following tests are kind of degenerate compared with
+ # watch4-16 through watch4-18 but might as well make sure that
+ # nothing seriously wrong has happened to the working directory.
+ dotest unedit-without-baserev-16 "cat m" 'edited in 1'
+ # Make sure CVS really thinks we are at 1.2.
+ dotest unedit-without-baserev-17 "${testcvs} -q update" ""
+ dotest unedit-without-baserev-18 "cat m" "edited in 1"
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ rm -r 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ ignore)
+ # On Windows, we can't check out CVSROOT, because the case
+ # insensitivity means that this conflicts with cvsroot.
+ mkdir ignore
+ cd ignore
+
+ dotest ignore-1 "${testcvs} -q co CVSROOT" "U CVSROOT/${DOTSTAR}"
+ cd CVSROOT
+ echo rootig.c >cvsignore
+ dotest ignore-2 "${testcvs} add cvsignore" "${SPROG}"' add: scheduling file `cvsignore'"'"' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+
+ dotest ignore-3 " ${testcvs} ci -m added" \
+"${CPROG} commit: Examining \.
+${CVSROOT_DIRNAME}/CVSROOT/cvsignore,v <-- cvsignore
+initial revision: 1\.1
+${SPROG} commit: Rebuilding administrative file database"
+
+ cd ..
+ if echo "yes" | ${testcvs} release -d CVSROOT >>${LOGFILE} ; then
+ pass ignore-4
+ else
+ fail ignore-4
+ fi
+
+ # CVS looks at the home dir from getpwuid, not HOME (is that correct
+ # behavior?), so this is hard to test and we won't try.
+ # echo foobar.c >${HOME}/.cvsignore
+ CVSIGNORE=envig.c; export CVSIGNORE
+ mkdir dir-to-import
+ cd dir-to-import
+ touch foobar.c bar.c rootig.c defig.o envig.c optig.c
+ # We use sort because we can't predict the order in which
+ # the files will be listed.
+ dotest_sort ignore-5 "${testcvs} import -m m -I optig.c ignore/first-dir tag1 tag2" \
+'
+
+I ignore/first-dir/defig.o
+I ignore/first-dir/envig.c
+I ignore/first-dir/optig.c
+I ignore/first-dir/rootig.c
+N ignore/first-dir/bar.c
+N ignore/first-dir/foobar.c
+No conflicts created by this import'
+ dotest_sort ignore-6 "${testcvs} import -m m -I ! ignore/second-dir tag3 tag4" \
+'
+
+N ignore/second-dir/bar.c
+N ignore/second-dir/defig.o
+N ignore/second-dir/envig.c
+N ignore/second-dir/foobar.c
+N ignore/second-dir/optig.c
+N ignore/second-dir/rootig.c
+No conflicts created by this import'
+ cd ..
+ rm -r dir-to-import
+
+ mkdir 1
+ cd 1
+ dotest ignore-7 "${testcvs} -q co -dsecond-dir ignore/second-dir" \
+'U second-dir/bar.c
+U second-dir/defig.o
+U second-dir/envig.c
+U second-dir/foobar.c
+U second-dir/optig.c
+U second-dir/rootig.c'
+ dotest ignore-8 "${testcvs} -q co -dfirst-dir ignore/first-dir" 'U first-dir/bar.c
+U first-dir/foobar.c'
+ cd first-dir
+ touch rootig.c defig.o envig.c optig.c notig.c
+ dotest ignore-9 "${testcvs} -q update -I optig.c" "${QUESTION} notig.c"
+ # The fact that CVS requires us to specify -I CVS here strikes me
+ # as a bug.
+ dotest_sort ignore-10 "${testcvs} -q update -I ! -I CVS" \
+"${QUESTION} defig.o
+${QUESTION} envig.c
+${QUESTION} notig.c
+${QUESTION} optig.c
+${QUESTION} rootig.c"
+
+ # Now test that commands other than update also print "? notig.c"
+ # where appropriate. Only test this for remote, because local
+ # CVS only prints it on update.
+ rm optig.c
+ if $remote; then
+ dotest ignore-11r "$testcvs -q diff" "$QUESTION notig.c"
+
+ # Force the server to be contacted. Ugh. Having CVS
+ # contact the server for the sole purpose of checking
+ # the CVSROOT/cvsignore file does not seem like such a
+ # good idea, so I imagine this will continue to be
+ # necessary. Oh well, at least we test CVS's ablity to
+ # handle a file with a modified timestamp but unmodified
+ # contents.
+ touch bar.c
+
+ dotest ignore-11ar "$testcvs -q ci -m commit-it" \
+"$QUESTION notig.c"
+ fi
+
+ # now test .cvsignore files
+ cd ..
+ echo notig.c >first-dir/.cvsignore
+ echo foobar.c >second-dir/.cvsignore
+ touch first-dir/notig.c second-dir/notig.c second-dir/foobar.c
+ dotest_sort ignore-12 "${testcvs} -qn update" \
+"${QUESTION} first-dir/.cvsignore
+${QUESTION} second-dir/.cvsignore
+${QUESTION} second-dir/notig.c"
+ dotest_sort ignore-13 "${testcvs} -qn update -I! -I CVS" \
+"${QUESTION} first-dir/.cvsignore
+${QUESTION} first-dir/defig.o
+${QUESTION} first-dir/envig.c
+${QUESTION} first-dir/rootig.c
+${QUESTION} second-dir/.cvsignore
+${QUESTION} second-dir/notig.c"
+
+ echo yes | dotest ignore-14 "${testcvs} release -d first-dir" \
+"${QUESTION} \.cvsignore
+You have \[0\] altered files in this repository.
+Are you sure you want to release (and delete) directory .first-dir': "
+
+ echo add a line >>second-dir/foobar.c
+ rm second-dir/notig.c second-dir/.cvsignore
+ echo yes | dotest ignore-15 "${testcvs} release -d second-dir" \
+"M foobar.c
+You have \[1\] altered files in this repository.
+Are you sure you want to release (and delete) directory .second-dir': "
+
+ dokeep
+ cd ../..
+ rm -r ignore
+ modify_repo rm -rf $CVSROOT_DIRNAME/ignore
+ ;;
+
+
+
+ ignore-on-branch)
+ # Test that CVS _doesn't_ ignore files on branches because they were
+ # added to the trunk.
+ mkdir ignore-on-branch; cd ignore-on-branch
+ modify_repo mkdir $CVSROOT_DIRNAME/ignore-on-branch
+
+ # create file1 & file2 on trunk
+ dotest ignore-on-branch-setup-1 "$testcvs -q co -dsetup ignore-on-branch" ''
+ cd setup
+ echo file1 >file1
+ dotest ignore-on-branch-setup-2 "$testcvs -q add file1" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest ignore-on-branch-setup-3 "$testcvs -q ci -mfile1 file1" \
+"$CVSROOT_DIRNAME/ignore-on-branch/file1,v <-- file1
+initial revision: 1\.1"
+ dotest ignore-on-branch-setup-4 "$testcvs -q tag -b branch" 'T file1'
+ echo file2 >file2
+ dotest ignore-on-branch-setup-5 "$testcvs -q add file2" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest ignore-on-branch-setup-6 "$testcvs -q ci -mtrunk file2" \
+"$CVSROOT_DIRNAME/ignore-on-branch/file2,v <-- file2
+initial revision: 1\.1"
+
+ cd ..
+
+ # Check out branch.
+ #
+ # - This was the original failure case - file2 would not be flagged
+ # with a '?'
+ dotest ignore-on-branch-1 "$testcvs -q co -rbranch ignore-on-branch" \
+'U ignore-on-branch/file1'
+ cd ignore-on-branch
+ echo file2 on branch >file2
+ dotest ignore-on-branch-2 "$testcvs -nq update" '? file2'
+
+ # Now set up for a join. One of the original fixes for this would
+ # print out a 'U' and a '?' during a join which added a file.
+ if $remote; then
+ dotest ignore-on-branch-3 "$testcvs -q tag -b branch2" \
+'? file2
+T file1'
+ else
+ dotest ignore-on-branch-3 "$testcvs -q tag -b branch2" 'T file1'
+ fi
+ dotest ignore-on-branch-4 "$testcvs -q add file2" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest ignore-on-branch-5 "$testcvs -q ci -mbranch file2" \
+"$CVSROOT_DIRNAME/ignore-on-branch/file2,v <-- file2
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+ dotest ignore-on-branch-6 "$testcvs -q up -rbranch2" \
+"${SPROG} update: \`file2' is no longer in the repository"
+ dotest ignore-on-branch-7 "$testcvs -q up -jbranch" 'U file2'
+
+ dokeep
+ cd ../..
+ rm -r ignore-on-branch
+ modify_repo rm -rf $CVSROOT_DIRNAME/ignore-on-branch
+ ;;
+
+
+
+ binfiles)
+ # Test cvs's ability to handle binary files.
+ # List of binary file tests:
+ # * conflicts, "cvs admin": binfiles
+ # * branching and joining: binfiles2
+ # * adding and removing files: binfiles3
+ # * -k wrappers: binwrap, binwrap2, binwrap3
+ # * "cvs import" and wrappers: binwrap, binwrap2, binwrap3
+ # * -k option to "cvs import": none yet, as far as I know.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1; cd 1
+ dotest binfiles-1 "${testcvs} -q co first-dir" ''
+ ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | ${TR} '@' '\000' >binfile.dat
+ cat binfile.dat binfile.dat >binfile2.dat
+ cd first-dir
+ cp ../binfile.dat binfile
+ dotest binfiles-2 "${testcvs} add -kb binfile" \
+"${SPROG}"' add: scheduling file `binfile'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest binfiles-3 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/binfile,v <-- binfile
+initial revision: 1\.1"
+ cd ../..
+ mkdir 2; cd 2
+ dotest binfiles-4 "${testcvs} -q co first-dir" 'U first-dir/binfile'
+ cd first-dir
+ dotest binfiles-5 "cmp ../../1/binfile.dat binfile" ''
+ # Testing that sticky options is -kb is the closest thing we have
+ # to testing that binary files work right on non-unix machines
+ # (until there is automated testing for such machines, of course).
+ dotest binfiles-5.5 "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+
+ # Test that "-kk" does not override "-kb"
+ cd ../..
+ mkdir 2a; cd 2a
+ dotest binfiles-4 "${testcvs} -q co -kk first-dir" 'U first-dir/binfile'
+ cd first-dir
+ # Testing that sticky options is -kb is the closest thing we have
+ # to testing that binary files work right on non-unix machines
+ # (until there is automated testing for such machines, of course).
+ dotest binfiles-5.5 "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+
+ # Test whether the default options from the RCS file are
+ # also used when operating on files instead of whole
+ # directories
+ cd ../..
+ rm -r 2a
+ mkdir 3; cd 3
+ dotest binfiles-5.5b0 "${testcvs} -q co first-dir/binfile" \
+'U first-dir/binfile'
+ cd first-dir
+ dotest binfiles-5.5b1 "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+ cd ../..
+ rm -r 3
+ # test that "-kk" does not override "-kb"
+ mkdir 3; cd 3
+ dotest binfiles-5.5b0 "${testcvs} -q co -kk first-dir/binfile" \
+'U first-dir/binfile'
+ cd first-dir
+ dotest binfiles-5.5b1 "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+ cd ../..
+ rm -r 3
+ cd 2/first-dir
+
+ cp ../../1/binfile2.dat binfile
+ dotest binfiles-6 "${testcvs} -q ci -m modify-it" \
+"$CVSROOT_DIRNAME/first-dir/binfile,v <-- binfile
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../../1/first-dir
+ dotest binfiles-7 "${testcvs} -q update" '[UP] binfile'
+ dotest binfiles-8 "cmp ../binfile2.dat binfile" ''
+
+ # Now test handling of conflicts with binary files.
+ cp ../binfile.dat binfile
+ dotest binfiles-con0 "${testcvs} -q ci -m modify-it" \
+"$CVSROOT_DIRNAME/first-dir/binfile,v <-- binfile
+new revision: 1\.3; previous revision: 1\.2"
+ cd ../../2/first-dir
+ echo 'edits in dir 2' >binfile
+ dotest binfiles-con1 "${testcvs} -q update" \
+"$SPROG update: nonmergeable file needs merge
+$SPROG update: revision 1\.3 from repository is now in binfile
+$SPROG update: file from working directory is now in \.#binfile\.1\.2
+C binfile"
+
+ dotest_fail binfiles-con1b "$testcvs -q up" "C binfile"
+
+ dotest binfiles-con2 "cmp binfile ../../1/binfile.dat" ''
+ dotest binfiles-con3 "cat .#binfile.1.2" 'edits in dir 2'
+
+ cp ../../1/binfile2.dat binfile
+ dotest binfiles-con4 "$testcvs -q ci -m resolve-it" \
+"$CVSROOT_DIRNAME/first-dir/binfile,v <-- binfile
+new revision: 1\.4; previous revision: 1\.3"
+ cd ../../1/first-dir
+ dotest binfiles-con5 "${testcvs} -q update" '[UP] binfile'
+
+ dotest binfiles-9 "${testcvs} -q update -A" ''
+ # "-kk" no longer does anything with "-kb"
+ dotest binfiles-10 "${testcvs} -q update -kk" ''
+ dotest binfiles-11 "${testcvs} -q update" ''
+ # "-kk" no longer does anything with "-kb"
+ dotest binfiles-12 "${testcvs} -q update -A" ''
+ dotest binfiles-13 "${testcvs} -q update -A" ''
+
+ cd ../..
+
+ mkdir 3
+ cd 3
+ dotest binfiles-13a0 "${testcvs} -q co -r HEAD first-dir" \
+'U first-dir/binfile'
+ cd first-dir
+ dotest binfiles-13a1 "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.4.*
+ Repository revision: 1\.4 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: HEAD (revision: 1\.4)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+ cd ../..
+ rm -r 3
+
+ cd 2/first-dir
+ echo 'this file is $''RCSfile$' >binfile
+ dotest binfiles-14a "${testcvs} -q ci -m modify-it" \
+"$CVSROOT_DIRNAME/first-dir/binfile,v <-- binfile
+new revision: 1\.5; previous revision: 1\.4"
+ dotest binfiles-14b "cat binfile" 'this file is $''RCSfile$'
+ # See binfiles-5.5 for discussion of -kb.
+ dotest binfiles-14c "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.5.*
+ Repository revision: 1\.5 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+ dotest binfiles-14d "${testcvs} admin -kv binfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v
+done"
+ # cvs admin doesn't change the checked-out file or its sticky
+ # kopts. There probably should be a way which does (but
+ # what if the file is modified? And do we try to version
+ # control the kopt setting?)
+ dotest binfiles-14e "cat binfile" 'this file is $''RCSfile$'
+ dotest binfiles-14f "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.5.*
+ Repository revision: 1\.5 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+ dotest binfiles-14g "${testcvs} -q update -A" '[UP] binfile'
+ dotest binfiles-14h "cat binfile" 'this file is binfile,v'
+ dotest binfiles-14i "${testcvs} status binfile" \
+"===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.5.*
+ Repository revision: 1\.5 ${CVSROOT_DIRNAME}/first-dir/binfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kv"
+
+ # Do sticky options work when used with 'cvs update'?
+ echo "Not a binary file." > nibfile
+ dotest binfiles-sticky1 "${testcvs} -q add nibfile" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest binfiles-sticky2 "${testcvs} -q ci -m add-it nibfile" \
+"$CVSROOT_DIRNAME/first-dir/nibfile,v <-- nibfile
+initial revision: 1\.1"
+ dotest binfiles-sticky3 "${testcvs} -q update -kb nibfile" \
+ '[UP] nibfile'
+ dotest binfiles-sticky4 "${testcvs} -q status nibfile" \
+"===================================================================
+File: nibfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/nibfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+
+ # Now test that -A can clear the sticky option.
+ dotest binfiles-sticky5 "${testcvs} -q update -A nibfile" \
+"[UP] nibfile"
+ dotest binfiles-sticky6 "${testcvs} -q status nibfile" \
+"===================================================================
+File: nibfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/nibfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest binfiles-15 "${testcvs} -q admin -kb nibfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/nibfile,v
+done"
+ dotest binfiles-16 "${testcvs} -q update nibfile" "[UP] nibfile"
+ dotest binfiles-17 "${testcvs} -q status nibfile" \
+"===================================================================
+File: nibfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/nibfile,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+
+ dotest binfiles-o1 "${testcvs} admin -o1.3:: binfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v
+deleting revision 1\.5
+deleting revision 1\.4
+done"
+ dotest binfiles-o2 "${testcvs} admin -o::1.3 binfile" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v
+deleting revision 1\.2
+deleting revision 1\.1
+done"
+ dotest binfiles-o3 "${testcvs} -q log -h -N binfile" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v
+Working file: binfile
+head: 1\.3
+branch:
+locks: strict
+access list:
+keyword substitution: v
+total revisions: 1
+============================================================================="
+
+ # Check that the contents were right. This isn't the hard case
+ # (in which RCS_delete_revs does a diff), but might as well.
+ dotest binfiles-o4 "${testcvs} -q update binfile" "U binfile"
+ dotest binfiles-o5 "cmp binfile ../../1/binfile.dat" ""
+
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r 1 2
+ ;;
+
+
+
+ binfiles2)
+ # Test cvs's ability to handle binary files, particularly branching
+ # and joining. The key thing we are worrying about is that CVS
+ # doesn't print "cannot merge binary files" or some such, in
+ # situations where no merging is required.
+ # See also "join" which does this with non-binary files.
+ #
+ # Cases (we are merging from the branch to the trunk):
+ # binfile.dat) File added on branch, not on trunk.
+ # File should be marked for addition.
+ # brmod) File modified on branch, not on trunk.
+ # File should be copied over to trunk (no merging is needed).
+ # brmod-trmod) File modified on branch, also on trunk.
+ # This is a conflict. Present the user with both files and
+ # let them figure it out.
+ # brmod-wdmod) File modified on branch, not modified in the trunk
+ # repository, but modified in the (trunk) working directory.
+ # This is also a conflict.
+
+ modify_repo mkdir ${CVSROOT_DIRNAME}/first-dir
+ mkdir 1; cd 1
+ dotest binfiles2-1 "${testcvs} -q co first-dir" ''
+ cd first-dir
+
+ # The most important thing here is that binfile, binfile2, &c
+ # each be distinct from each other. We also make sure to include
+ # a few likely end-of-line patterns to make sure nothing is
+ # being munged as if in text mode.
+ ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | ${TR} '@' '\000' >../binfile
+ # Use binfl2 rather than binfile2 because of a problem with Cygwin
+ # and Samba. that causes cat to report that the input and output file
+ # are the same when outputting to binfile3. Why? I don't know, but
+ # it is consistently reproducible.
+ cat ../binfile ../binfile >../binfl2
+ cat ../binfl2 ../binfile >../binfile3
+
+ # FIXCVS: unless a branch has at least one file on it,
+ # tag_check_valid won't know it exists. So if brmod didn't
+ # exist, we would have to invent it.
+ cp ../binfile brmod
+ cp ../binfile brmod-trmod
+ cp ../binfile brmod-wdmod
+ dotest binfiles2-1a \
+"${testcvs} add -kb brmod brmod-trmod brmod-wdmod" \
+"${SPROG} add: scheduling file .brmod. for addition
+${SPROG} add: scheduling file .brmod-trmod. for addition
+${SPROG} add: scheduling file .brmod-wdmod. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest binfiles2-1b "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/brmod,v <-- brmod
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-wdmod,v <-- brmod-wdmod
+initial revision: 1\.1"
+ dotest binfiles2-2 "${testcvs} -q tag -b br" 'T brmod
+T brmod-trmod
+T brmod-wdmod'
+ dotest binfiles2-3 "${testcvs} -q update -r br" ''
+ cp ../binfile binfile.dat
+ dotest binfiles2-4 "${testcvs} add -kb binfile.dat" \
+"${SPROG} add: scheduling file .binfile\.dat. for addition on branch .br.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cp ../binfl2 brmod
+ cp ../binfl2 brmod-trmod
+ cp ../binfl2 brmod-wdmod
+ dotest binfiles2-5 "${testcvs} -q ci -m br-changes" \
+"$CVSROOT_DIRNAME/first-dir/Attic/binfile\.dat,v <-- binfile\.dat
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod,v <-- brmod
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-wdmod,v <-- brmod-wdmod
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ dotest binfiles2-6 "${testcvs} -q update -A" \
+"${SPROG} update: \`binfile\.dat' is no longer in the repository
+[UP] brmod
+[UP] brmod-trmod
+[UP] brmod-wdmod"
+ dotest_fail binfiles2-7 "test -f binfile.dat" ''
+ dotest binfiles2-7-brmod "cmp ../binfile brmod"
+ cp ../binfile3 brmod-trmod
+ dotest binfiles2-7a "${testcvs} -q ci -m tr-modify" \
+"$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+new revision: 1\.2; previous revision: 1\.1"
+ cp ../binfile3 brmod-wdmod
+
+ dotest binfiles2-8 "${testcvs} -q update -j br" \
+"U binfile\.dat
+U brmod
+${SPROG} update: nonmergeable file needs merge
+${SPROG} update: revision 1.1.2.1 from repository is now in brmod-trmod
+${SPROG} update: file from working directory is now in .#brmod-trmod.1.2
+C brmod-trmod
+M brmod-wdmod
+${SPROG} update: nonmergeable file needs merge
+${SPROG} update: revision 1.1.2.1 from repository is now in brmod-wdmod
+${SPROG} update: file from working directory is now in .#brmod-wdmod.1.1
+C brmod-wdmod"
+
+ dotest binfiles2-9 "cmp ../binfile binfile.dat"
+ dotest binfiles2-9-brmod "cmp ../binfl2 brmod"
+ dotest binfiles2-9-brmod-trmod "cmp ../binfl2 brmod-trmod"
+ dotest binfiles2-9-brmod-trmod "cmp ../binfl2 brmod-wdmod"
+ dotest binfiles2-9a-brmod-trmod "cmp ../binfile3 .#brmod-trmod.1.2"
+ dotest binfiles2-9a-brmod-wdmod "cmp ../binfile3 .#brmod-wdmod.1.1"
+
+ # Test that everything was properly scheduled.
+ dotest binfiles2-10 "${testcvs} -q ci -m checkin" \
+"$CVSROOT_DIRNAME/first-dir/binfile\.dat,v <-- binfile\.dat
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod,v <-- brmod
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+new revision: 1\.3; previous revision: 1\.2
+$CVSROOT_DIRNAME/first-dir/brmod-wdmod,v <-- brmod-wdmod
+new revision: 1\.2; previous revision: 1\.1"
+
+ dotest_fail binfiles2-o1 "${testcvs} -q admin -o :1.2 brmod-trmod" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v
+deleting revision 1\.2
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v: can't remove branch point 1\.1
+${SPROG} admin: RCS file for .brmod-trmod. not modified\."
+ dotest binfiles2-o2 "${testcvs} -q admin -o 1.1.2.1: brmod-trmod" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v
+deleting revision 1\.1\.2\.1
+done"
+ dotest binfiles2-o3 "${testcvs} -q admin -o :1.2 brmod-trmod" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v
+deleting revision 1\.2
+deleting revision 1\.1
+done"
+ dotest binfiles2-o4 "${testcvs} -q log -N brmod-trmod" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v
+Working file: brmod-trmod
+head: 1\.3
+branch:
+locks: strict
+access list:
+keyword substitution: b
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+checkin
+============================================================================="
+
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r 1
+ ;;
+
+
+
+ binfiles3)
+ # More binary file tests, especially removing, adding, &c.
+ # See "binfiles" for a list of binary file tests.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1; cd 1
+ dotest binfiles3-1 "${testcvs} -q co first-dir" ''
+ ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | ${TR} '@' '\000' >binfile.dat
+ cd first-dir
+ echo hello >file1
+ dotest binfiles3-2 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest binfiles3-3 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ rm file1
+ dotest binfiles3-4 "${testcvs} rm file1" \
+"${SPROG} remove: scheduling .file1. for removal
+${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest binfiles3-5 "${testcvs} -q ci -m remove-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1"
+ cp ../binfile.dat file1
+ dotest binfiles3-6 "${testcvs} add -kb file1" \
+"$SPROG add: Re-adding file .file1. after dead revision 1\.2\.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ # The idea behind this test is to make sure that the file
+ # gets opened in binary mode to send to "cvs ci".
+ dotest binfiles3-6a "cat CVS/Entries" \
+"/file1/0/[A-Za-z0-9 :]*/-kb/
+D"
+ # TODO: This just tests the case where the old keyword
+ # expansion mode is the default (RCS_getexpand == NULL
+ # in checkaddfile()); should also test the case in which
+ # we are changing it from one non-default value to another.
+ dotest binfiles3-7 "$testcvs -q ci -m readd-it" \
+"$SPROG commit: changing keyword expansion mode to -kb
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+ dotest binfiles3-8 "${testcvs} -q log -h -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.3
+branch:
+locks: strict
+access list:
+keyword substitution: b
+total revisions: 3
+============================================================================="
+
+ # OK, now test admin -o on a binary file. See "admin"
+ # test for a more complete list of admin -o tests.
+ cp ${TESTDIR}/1/binfile.dat ${TESTDIR}/1/binfile4.dat
+ echo '%%$$##@@!!jjiiuull' | ${TR} j '\000' >>${TESTDIR}/1/binfile4.dat
+ cp ${TESTDIR}/1/binfile4.dat ${TESTDIR}/1/binfile5.dat
+ echo 'aawwee%$$##@@!!jjil' | ${TR} w '\000' >>${TESTDIR}/1/binfile5.dat
+
+ cp ../binfile4.dat file1
+ dotest binfiles3-9 "${testcvs} -q ci -m change" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3"
+ cp ../binfile5.dat file1
+ dotest binfiles3-10 "${testcvs} -q ci -m change" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4"
+ dotest binfiles3-11 "${testcvs} admin -o 1.3::1.5 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+deleting revision 1\.4
+done"
+ dotest binfiles3-12 "${testcvs} -q update -r 1.3 file1" "U file1"
+ dotest binfiles3-13 "cmp file1 ${TESTDIR}/1/binfile.dat" ""
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ mcopy)
+ # See comment at "mwrap" test for list of other wrappers tests.
+ # Test cvs's ability to handle nonmergeable files specified with
+ # -m 'COPY' in wrappers. Similar to the binfiles2 test,
+ # which tests the same thing for binary files
+ # (which are non-mergeable in the same sense).
+ #
+ # Cases (we are merging from the branch to the trunk):
+ # brmod) File modified on branch, not on trunk.
+ # File should be copied over to trunk (no merging is needed).
+ # brmod-trmod) File modified on branch, also on trunk.
+ # This is a conflict. Present the user with both files and
+ # let them figure it out.
+ # brmod-wdmod) File modified on branch, not modified in the trunk
+ # repository, but modified in the (trunk) working directory.
+ # This is also a conflict.
+
+ # For the moment, remote CVS can't pass wrappers from CVSWRAPPERS
+ # (see wrap_send). So skip these tests for remote.
+ if $remote; then :; else
+
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+ mkdir 1; cd 1
+ dotest mcopy-1 "${testcvs} -q co first-dir" ''
+ cd first-dir
+
+ # FIXCVS: unless a branch has at least one file on it,
+ # tag_check_valid won't know it exists. So if brmod didn't
+ # exist, we would have to invent it.
+ echo 'brmod initial contents' >brmod
+ echo 'brmod-trmod initial contents' >brmod-trmod
+ echo 'brmod-wdmod initial contents' >brmod-wdmod
+ echo "* -m 'COPY'" >.cvswrappers
+ dotest mcopy-1a \
+"${testcvs} add .cvswrappers brmod brmod-trmod brmod-wdmod" \
+"${SPROG} add: scheduling file .\.cvswrappers. for addition
+${SPROG} add: scheduling file .brmod. for addition
+${SPROG} add: scheduling file .brmod-trmod. for addition
+${SPROG} add: scheduling file .brmod-wdmod. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest mcopy-1b "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/\.cvswrappers,v <-- \.cvswrappers
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod,v <-- brmod
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-wdmod,v <-- brmod-wdmod
+initial revision: 1\.1"
+
+ # NOTE: .cvswrappers files are broken (see comment in
+ # src/wrapper.c). So doing everything via the environment
+ # variable is a workaround. Better would be to test them
+ # both.
+ CVSWRAPPERS="* -m 'COPY'"
+ export CVSWRAPPERS
+ dotest mcopy-2 "${testcvs} -q tag -b br" 'T \.cvswrappers
+T brmod
+T brmod-trmod
+T brmod-wdmod'
+ dotest mcopy-3 "${testcvs} -q update -r br" ''
+ echo 'modify brmod on br' >brmod
+ echo 'modify brmod-trmod on br' >brmod-trmod
+ echo 'modify brmod-wdmod on br' >brmod-wdmod
+ dotest mcopy-5 "${testcvs} -q ci -m br-changes" \
+"$CVSROOT_DIRNAME/first-dir/brmod,v <-- brmod
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-wdmod,v <-- brmod-wdmod
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ dotest mcopy-6 "${testcvs} -q update -A" \
+"[UP] brmod
+[UP] brmod-trmod
+[UP] brmod-wdmod"
+ dotest mcopy-7 "cat brmod brmod-trmod brmod-wdmod" \
+"brmod initial contents
+brmod-trmod initial contents
+brmod-wdmod initial contents"
+
+ echo 'modify brmod-trmod again on trunk' >brmod-trmod
+ dotest mcopy-7a "${testcvs} -q ci -m tr-modify" \
+"$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+new revision: 1\.2; previous revision: 1\.1"
+ echo 'modify brmod-wdmod in working dir' >brmod-wdmod
+
+ dotest mcopy-8 "${testcvs} -q update -j br" \
+"U brmod
+${SPROG} update: nonmergeable file needs merge
+${SPROG} update: revision 1.1.2.1 from repository is now in brmod-trmod
+${SPROG} update: file from working directory is now in .#brmod-trmod.1.2
+C brmod-trmod
+M brmod-wdmod
+${SPROG} update: nonmergeable file needs merge
+${SPROG} update: revision 1.1.2.1 from repository is now in brmod-wdmod
+${SPROG} update: file from working directory is now in .#brmod-wdmod.1.1
+C brmod-wdmod"
+
+ dotest mcopy-9 "cat brmod brmod-trmod brmod-wdmod" \
+"modify brmod on br
+modify brmod-trmod on br
+modify brmod-wdmod on br"
+ dotest mcopy-9a "cat .#brmod-trmod.1.2 .#brmod-wdmod.1.1" \
+"modify brmod-trmod again on trunk
+modify brmod-wdmod in working dir"
+
+ # Test that everything was properly scheduled.
+ dotest mcopy-10 "${testcvs} -q ci -m checkin" \
+"$CVSROOT_DIRNAME/first-dir/brmod,v <-- brmod
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/brmod-trmod,v <-- brmod-trmod
+new revision: 1\.3; previous revision: 1\.2
+$CVSROOT_DIRNAME/first-dir/brmod-wdmod,v <-- brmod-wdmod
+new revision: 1\.2; previous revision: 1\.1"
+
+ dokeep
+ cd ../..
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -r 1
+ unset CVSWRAPPERS
+ fi # end of tests to be skipped for remote
+ ;;
+
+
+
+ binwrap)
+ # Test the ability to specify binary-ness based on file name.
+ # See "mwrap" for a list of other wrappers tests.
+
+ mkdir dir-to-import
+ cd dir-to-import
+ touch foo.c foo.exe
+
+ # While we're here, test for rejection of duplicate tag names.
+ dotest_fail binwrap-0 \
+ "${testcvs} import -m msg -I ! first-dir dup dup" \
+"${CPROG} \[import aborted\]: tag .dup. was specified more than once"
+
+ if ${testcvs} import -m message -I ! -W "*.exe -k 'b'" \
+ first-dir tag1 tag2 >>${LOGFILE}; then
+ pass binwrap-1
+ else
+ fail binwrap-1
+ fi
+ cd ..
+ rm -r dir-to-import
+ dotest binwrap-2 "${testcvs} -q co first-dir" 'U first-dir/foo.c
+U first-dir/foo.exe'
+ dotest binwrap-3 "${testcvs} -q status first-dir" \
+"===================================================================
+File: foo\.c Status: Up-to-date
+
+ Working revision: 1\.1\.1\.1.*
+ Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: foo\.exe Status: Up-to-date
+
+ Working revision: 1\.1\.1\.1.*
+ Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.exe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+
+ dokeep
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ binwrap2)
+ # Test the ability to specify binary-ness based on file name.
+ # See "mwrap" for a list of other wrappers tests.
+
+ mkdir dir-to-import
+ cd dir-to-import
+ touch foo.c foo.exe
+
+ # Specify that all files are binary except *.c.
+ # The order seems to matter, with the earlier rules taking
+ # precedence. I'm not sure whether that is good or not,
+ # but it is the current behavior.
+ if ${testcvs} import -m message -I ! \
+ -W "*.c -k 'o'" -W "* -k 'b'" \
+ first-dir tag1 tag2 >>${LOGFILE}; then
+ pass binwrap2-1
+ else
+ fail binwrap2-1
+ fi
+ cd ..
+ rm -r dir-to-import
+ dotest binwrap2-2 "${testcvs} -q co first-dir" 'U first-dir/foo.c
+U first-dir/foo.exe'
+ dotest binwrap2-3 "${testcvs} -q status first-dir" \
+"===================================================================
+File: foo\.c Status: Up-to-date
+
+ Working revision: 1\.1\.1\.1.*
+ Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -ko
+
+===================================================================
+File: foo\.exe Status: Up-to-date
+
+ Working revision: 1\.1\.1\.1.*
+ Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.exe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb"
+
+ dokeep
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ binwrap3)
+ # Test communication of file-specified -k wrappers between
+ # client and server, in `import':
+ #
+ # 1. Set up a directory tree, populate it with files.
+ # 2. Give each directory a different .cvswrappers file.
+ # 3. Give the server its own .cvswrappers file.
+ # 4. Import the whole tree, see if the right files got set
+ # to binary.
+ #
+ # The tree has a top ("0th") level, and two subdirs, sub1/
+ # and sub2/; sub2/ contains directory subsub/. Every
+ # directory has a .cvswrappers file as well as regular
+ # files.
+ #
+ # In the file names, "foo-b.*" should end up binary, and
+ # "foo-t.*" should end up text. Don't worry about the two
+ # letter extensions; they're just there to help me keep
+ # things straight.
+ #
+ # Here's the directory tree:
+ #
+ # ./
+ # .cvswrappers
+ # foo-b.c0
+ # foo-b.sb
+ # foo-t.c1
+ # foo-t.st
+ #
+ # sub1/ sub2/
+ # .cvswrappers .cvswrappers
+ # foo-b.c1 foo-b.sb
+ # foo-b.sb foo-b.st
+ # foo-t.c0 foo-t.c0
+ # foo-t.st foo-t.c1
+ # foo-t.c2
+ # foo-t.c3
+ #
+ # subsub/
+ # .cvswrappers
+ # foo-b.c3
+ # foo-b.sb
+ # foo-t.c0
+ # foo-t.c1
+ # foo-t.c2
+ # foo-t.st
+
+ binwrap3_line1="This is a test file "
+ binwrap3_line2="containing little of use "
+ binwrap3_line3="except this non-haiku"
+
+ binwrap3_text="${binwrap3_line1}${binwrap3_line2}${binwrap3_line3}"
+
+ cd ${TESTDIR}
+
+ # On Windows, we can't check out CVSROOT, because the case
+ # insensitivity means that this conflicts with cvsroot.
+ mkdir wnt
+ cd wnt
+
+ mkdir binwrap3 # the 0th dir
+ mkdir binwrap3/sub1
+ mkdir binwrap3/sub2
+ mkdir binwrap3/sub2/subsub
+
+ echo "bar*" > binwrap3/.cvswrappers
+ echo "*.c0 -k 'b'" >> binwrap3/.cvswrappers
+ echo "whatever -k 'b'" >> binwrap3/.cvswrappers
+ echo ${binwrap3_text} > binwrap3/foo-b.c0
+ echo ${binwrap3_text} > binwrap3/bar-t.c0
+ echo ${binwrap3_text} > binwrap3/foo-b.sb
+ echo ${binwrap3_text} > binwrap3/foo-t.sb
+ echo ${binwrap3_text} > binwrap3/foo-t.c1
+ echo ${binwrap3_text} > binwrap3/foo-t.st
+
+ echo "bar* -k 'kv'" > binwrap3/sub1/.cvswrappers
+ echo "*.c1 -k 'b'" >> binwrap3/sub1/.cvswrappers
+ echo "whatever -k 'b'" >> binwrap3/sub1/.cvswrappers
+ echo ${binwrap3_text} > binwrap3/sub1/foo-b.c1
+ echo ${binwrap3_text} > binwrap3/sub1/bar-t.c1
+ echo ${binwrap3_text} > binwrap3/sub1/foo-b.sb
+ echo ${binwrap3_text} > binwrap3/sub1/foo-t.sb
+ echo ${binwrap3_text} > binwrap3/sub1/foo-t.c0
+ echo ${binwrap3_text} > binwrap3/sub1/foo-t.st
+
+ echo "bar*" > binwrap3/sub2/.cvswrappers
+ echo "*.st -k 'b'" >> binwrap3/sub2/.cvswrappers
+ echo ${binwrap3_text} > binwrap3/sub2/foo-b.sb
+ echo ${binwrap3_text} > binwrap3/sub2/foo-t.sb
+ echo ${binwrap3_text} > binwrap3/sub2/foo-b.st
+ echo ${binwrap3_text} > binwrap3/sub2/bar-t.st
+ echo ${binwrap3_text} > binwrap3/sub2/foo-t.c0
+ echo ${binwrap3_text} > binwrap3/sub2/foo-t.c1
+ echo ${binwrap3_text} > binwrap3/sub2/foo-t.c2
+ echo ${binwrap3_text} > binwrap3/sub2/foo-t.c3
+
+ echo "bar* -k 'kv'" > binwrap3/sub2/subsub/.cvswrappers
+ echo "*.c3 -k 'b'" >> binwrap3/sub2/subsub/.cvswrappers
+ echo "foo -k 'b'" >> binwrap3/sub2/subsub/.cvswrappers
+ echo "c0* -k 'b'" >> binwrap3/sub2/subsub/.cvswrappers
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-b.c3
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/bar-t.c3
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-b.sb
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.sb
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.c0
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.c1
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.c2
+ echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.st
+
+ # Now set up CVSROOT/cvswrappers, the easy way:
+ dotest binwrap3-1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}"
+ cd CVSROOT
+ # This destroys anything currently in cvswrappers, but
+ # presumably other tests will take care of it themselves if
+ # they use cvswrappers:
+ echo "foo-t.sb" > cvswrappers
+ echo "foo*.sb -k 'b'" >> cvswrappers
+ dotest binwrap3-2 "${testcvs} -q ci -m cvswrappers-mod" \
+"$CVSROOT_DIRNAME/CVSROOT/cvswrappers,v <-- cvswrappers
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+
+ # Avoid environmental interference
+ CVSWRAPPERS_save=${CVSWRAPPERS}
+ unset CVSWRAPPERS
+
+ # Do the import
+ cd binwrap3
+ # Not importing .cvswrappers tests whether the client is really
+ # letting the server know "honestly" whether the file is binary,
+ # rather than just letting the server see the .cvswrappers file.
+ dotest binwrap3-2a \
+"${testcvs} import -m . -I .cvswrappers binwrap3 tag1 tag2" \
+"[NI] ${DOTSTAR}"
+
+ # OK, now test "cvs add".
+ cd ..
+ rm -r binwrap3
+ dotest binwrap3-2b "${testcvs} co binwrap3" "${DOTSTAR}"
+ cd binwrap3
+ cd sub2
+ echo "*.newbin -k 'b'" > .cvswrappers
+ echo .cvswrappers >.cvsignore
+ echo .cvsignore >>.cvsignore
+ touch file1.newbin file1.txt
+ dotest binwrap3-2c "${testcvs} add file1.newbin file1.txt" \
+"${SPROG} add: scheduling file .file1\.newbin. for addition
+${SPROG} add: scheduling file .file1\.txt. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest binwrap3-2d "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/binwrap3/sub2/file1\.newbin,v <-- file1\.newbin
+initial revision: 1\.1
+$CVSROOT_DIRNAME/binwrap3/sub2/file1\.txt,v <-- file1\.txt
+initial revision: 1\.1"
+ cd ..
+
+ # Now check out the module and see which files are binary.
+ cd ..
+ rm -r binwrap3
+ dotest binwrap3-3 "${testcvs} co binwrap3" "${DOTSTAR}"
+ cd binwrap3
+
+ # Running "cvs status" and matching output is too
+ # error-prone, too likely to falsely fail. Instead, we'll
+ # just grep the Entries lines:
+
+ dotest binwrap3-top1 "grep foo-b.c0 ./CVS/Entries" \
+ "/foo-b.c0/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-top2 "grep foo-b.sb ./CVS/Entries" \
+ "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-top3 "grep foo-t.c1 ./CVS/Entries" \
+ "/foo-t.c1/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-top4 "grep foo-t.st ./CVS/Entries" \
+ "/foo-t.st/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-top5 "grep foo-t.sb ./CVS/Entries" \
+ "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-top6 "grep bar-t.c0 ./CVS/Entries" \
+ "/bar-t.c0/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub1-1 "grep foo-b.c1 sub1/CVS/Entries" \
+ "/foo-b.c1/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-sub1-2 "grep foo-b.sb sub1/CVS/Entries" \
+ "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-sub1-3 "grep foo-t.c0 sub1/CVS/Entries" \
+ "/foo-t.c0/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub1-4 "grep foo-t.st sub1/CVS/Entries" \
+ "/foo-t.st/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub1-5 "grep foo-t.sb sub1/CVS/Entries" \
+ "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub1-6 "grep bar-t.c1 sub1/CVS/Entries" \
+ "/bar-t.c1/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub2-1 "grep foo-b.sb sub2/CVS/Entries" \
+ "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-sub2-2 "grep foo-b.st sub2/CVS/Entries" \
+ "/foo-b.st/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-sub2-3 "grep foo-t.c0 sub2/CVS/Entries" \
+ "/foo-t.c0/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub2-4 "grep foo-t.c1 sub2/CVS/Entries" \
+ "/foo-t.c1/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub2-5 "grep foo-t.c2 sub2/CVS/Entries" \
+ "/foo-t.c2/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub2-6 "grep foo-t.c3 sub2/CVS/Entries" \
+ "/foo-t.c3/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub2-7 "grep foo-t.sb sub2/CVS/Entries" \
+ "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub2-8 "grep bar-t.st sub2/CVS/Entries" \
+ "/bar-t.st/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-subsub1 "grep foo-b.c3 sub2/subsub/CVS/Entries" \
+ "/foo-b.c3/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-subsub2 "grep foo-b.sb sub2/subsub/CVS/Entries" \
+ "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/"
+
+ dotest binwrap3-subsub3 "grep foo-t.c0 sub2/subsub/CVS/Entries" \
+ "/foo-t.c0/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-subsub4 "grep foo-t.c1 sub2/subsub/CVS/Entries" \
+ "/foo-t.c1/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-subsub5 "grep foo-t.c2 sub2/subsub/CVS/Entries" \
+ "/foo-t.c2/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-subsub6 "grep foo-t.st sub2/subsub/CVS/Entries" \
+ "/foo-t.st/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-subsub7 "grep foo-t.sb sub2/subsub/CVS/Entries" \
+ "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-subsub8 "grep bar-t.c3 sub2/subsub/CVS/Entries" \
+ "/bar-t.c3/1.1.1.1/[A-Za-z0-9 :]*//"
+
+ dotest binwrap3-sub2-add1 "grep file1.newbin sub2/CVS/Entries" \
+ "/file1.newbin/1.1/[A-Za-z0-9 :]*/-kb/"
+ dotest binwrap3-sub2-add2 "grep file1.txt sub2/CVS/Entries" \
+ "/file1.txt/1.1/[A-Za-z0-9 :]*//"
+
+ # Restore and clean up
+ dokeep
+ cd ..
+ rm -r binwrap3 CVSROOT
+ cd ..
+ rm -r wnt
+ modify_repo rm -rf $CVSROOT_DIRNAME/binwrap3
+ CVSWRAPPERS=${CVSWRAPPERS_save}
+ ;;
+
+
+
+ mwrap)
+ # Tests of various wrappers features:
+ # -m 'COPY' and cvs update: mwrap
+ # -m 'COPY' and joining: mcopy
+ # -k: binwrap, binwrap2
+ # -t/-f: hasn't been written yet.
+ #
+ # Tests of different ways of specifying wrappers:
+ # CVSROOT/cvswrappers: mwrap
+ # -W: binwrap, binwrap2
+ # .cvswrappers in working directory, local: mcopy
+ # CVSROOT/cvswrappers, .cvswrappers remote: binwrap3
+ # CVSWRAPPERS environment variable: mcopy
+
+ # This test is similar to binfiles-con1; -m 'COPY' specifies
+ # non-mergeableness the same way that -kb does.
+
+ # On Windows, we can't check out CVSROOT, because the case
+ # insensitivity means that this conflicts with cvsroot.
+ mkdir wnt
+ cd wnt
+
+ dotest mwrap-c1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}"
+ cd CVSROOT
+ echo "* -m 'COPY'" >>cvswrappers
+ dotest mwrap-c2 "${testcvs} -q ci -m wrapper-mod" \
+"$CVSROOT_DIRNAME/CVSROOT/cvswrappers,v <-- cvswrappers
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+ mkdir m1; cd m1
+ dotest mwrap-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest mwrap-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch aa
+ dotest mwrap-3 "${testcvs} add aa" \
+"${SPROG} add: scheduling file .aa. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest mwrap-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+initial revision: 1\.1"
+ cd ../..
+ mkdir m2; cd m2
+ dotest mwrap-5 "${testcvs} -q co first-dir" "U first-dir/aa"
+ cd first-dir
+ echo "changed in m2" >aa
+ dotest mwrap-6 "${testcvs} -q ci -m m2-mod" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../..
+ cd m1/first-dir
+ echo "changed in m1" >aa
+ dotest mwrap-7 "$testcvs -nq update" \
+"$SPROG update: nonmergeable file needs merge
+$SPROG update: revision 1\.2 from repository is now in aa
+$SPROG update: file from working directory is now in \.#aa\.1\.1
+C aa"
+ dotest mwrap-8 "$testcvs -q update" \
+"$SPROG update: nonmergeable file needs merge
+$SPROG update: revision 1\.2 from repository is now in aa
+$SPROG update: file from working directory is now in \.#aa\.1\.1
+C aa"
+ dotest mwrap-9 "cat aa" "changed in m2"
+ dotest mwrap-10 "cat .#aa.1.1" "changed in m1"
+
+ dokeep
+ restore_adm
+ cd ../..
+ rm -r CVSROOT
+ rm -r m1 m2
+ cd ..
+ rm -r wnt
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ info)
+ # Administrative file tests.
+ # Here is a list of where each administrative file is tested:
+ # loginfo: info
+ # modules: modules, modules2, modules3
+ # cvsignore: ignore
+ # verifymsg: info
+ # cvswrappers: mwrap
+ # taginfo: taginfo
+ # posttag: posttag
+ # postadmin: admin
+ # postwatch: devcom3
+ # config: config
+ # config2: MinCompressionLevel and MaxCompressionLevel in config
+
+ # On Windows, we can't check out CVSROOT, because the case
+ # insensitivity means that this conflicts with cvsroot.
+ mkdir wnt
+ cd wnt
+
+ dotest info-1 "$testcvs -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}"
+ cd CVSROOT
+ dotest info-2 "$testcvs -Q tag info-start"
+ sed -e's/%p/ALL/' <loginfo >tmploginfo
+ mv tmploginfo loginfo
+ echo "ALL sh -c \"echo x\${=MYENV}\${=OTHER}y\${=ZEE}=\$USER=\$COMMITID=\$SESSIONID=\$CVSROOT= >>$TESTDIR/testlog; cat >/dev/null\"" >> loginfo
+ # The following cases test the format string substitution
+ echo "ALL echo %{} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %x >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo % >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %{sxVv} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %{v} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %s %s >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %{V}AX >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "first-dir echo %sux >>$TESTDIR/testlog2; cat >/dev/null" \
+ >> loginfo
+ sed -e's/^UseNewInfoFmtStrings=yes$/#&/' <config >tmpconfig
+ mv tmpconfig config
+
+ # Might be nice to move this to crerepos tests; it should
+ # work to create a loginfo file if you didn't create one
+ # with "cvs init".
+ : dotest info-2 "$testcvs add loginfo" \
+"$SPROG add: scheduling file \`loginfo' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+
+ dotest_fail info-3 "$testcvs -q ci -m new-loginfo" \
+"$TESTDIR/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$CVSROOT_DIRNAME/CVSROOT/loginfo,v <-- loginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database
+$SPROG commit: loginfo:[0-9]*: no such user variable \${=MYENV}
+$SPROG \[commit aborted\]: Unknown format character in info file ('').
+Info files are the hook files, verifymsg, taginfo, commitinfo, etc\."
+ cd ..
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest info-5 "$testcvs -q co first-dir" ''
+ cd first-dir
+ touch file1
+ dotest info-6 "$testcvs add file1" \
+"$SPROG add: scheduling file \`file1' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+ echo "cvs -s OTHER=not-this -s MYENV=env-" >>$HOME/.cvsrc
+ dotest info-6b "$testcvs -q -s OTHER=value ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$SPROG commit: loginfo:[0-9]*: no such user variable \${=ZEE}
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary .1. in
+all info files after each .%. which doesn.t represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\." \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary .1. in
+all info files after each .%. which doesn.t represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\.
+$SPROG commit: loginfo:[0-9]*: no such user variable \${=ZEE}"
+ echo line0 >>file1
+ dotest info-6c "$testcvs -q -sOTHER=foo ci -m mod-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+$SPROG commit: loginfo:[0-9]*: no such user variable \${=ZEE}
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary .1. in
+all info files after each .%. which doesn.t represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\." \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary .1. in
+all info files after each .%. which doesn.t represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\.
+$SPROG commit: loginfo:[0-9]*: no such user variable \${=ZEE}"
+ echo line1 >>file1
+ dotest info-7 "${testcvs} -q -s OTHER=value -s ZEE=z ci -m mod-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary .1. in
+all info files after each .%. which doesn.t represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\."
+
+ cd ..
+ dotest info-9 "cat $TESTDIR/testlog" \
+"xenv-valueyz=${username}=${commitid}=${commitid}=${CVSROOT_DIRNAME}="
+ dotest info-10 "cat $TESTDIR/testlog2" \
+'first-dir
+first-dir
+first-dir
+first-dir file1,,NONE,1.1
+first-dir 1.1
+first-dir file1 %s
+first-dir NONEAX
+first-dir file1ux
+first-dir
+first-dir
+first-dir
+first-dir file1,,1.1,1.2
+first-dir 1.2
+first-dir file1 %s
+first-dir 1.1AX
+first-dir file1ux
+first-dir
+first-dir
+first-dir
+first-dir file1,,1.2,1.3
+first-dir 1.3
+first-dir file1 %s
+first-dir 1.2AX
+first-dir file1ux'
+
+ # and make sure adding a '1' in the format strings really does ensure
+ # ensure backwards compatibility.
+ #
+ # these tests are identical to the above except for the loginfo setup
+ # and the project name
+ cd CVSROOT
+ dotest info-setup-intfmt-1 "$testcvs -q up -prinfo-start config >config"
+ dotest info-setup-intfmt-2 "$testcvs -q up -prinfo-start loginfo >loginfo"
+ sed -e's/%p/ALL/' <loginfo >tmploginfo
+ mv tmploginfo loginfo
+ echo "ALL sh -c \"echo x\${=MYENV}\${=OTHER}y\${=ZEE}=\$USER=\$CVSROOT= >>$TESTDIR/testlog; cat >/dev/null\"" >> loginfo
+ # The following cases test the format string substitution
+ echo "ALL echo %1{} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %1x >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %1 >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %1{sxVv} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %1{v} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %1s %%s >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %1{V}AX >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "third-dir echo %1sux >>$TESTDIR/testlog2; cat >/dev/null" \
+ >> loginfo
+
+ dotest info-setup-intfmt-2 "${testcvs} -q -s ZEE=garbage ci -m nuke-admin-for-info-intfmt" \
+"$TESTDIR/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$TESTDIR/cvsroot/CVSROOT/loginfo,v <-- loginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary .1. in
+all info files after each .%. which doesn.t represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\."
+ cd ..
+
+ # delete the logs now so the results look more like the last tests
+ # (they won't include the config file update)
+ rm ${TESTDIR}/testlog ${TESTDIR}/testlog2
+
+ modify_repo mkdir $CVSROOT_DIRNAME/third-dir
+ dotest info-intfmt-5 "${testcvs} -q co third-dir" ''
+ cd third-dir
+ touch file1
+ dotest info-intfmt-6 "${testcvs} add file1" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ echo "cvs -s OTHER=not-this -s MYENV=env-" >>$HOME/.cvsrc
+ dotest info-intfmt-6b "${testcvs} -q -s OTHER=value ci -m add-it" \
+"${TESTDIR}/cvsroot/third-dir/file1,v <-- file1
+initial revision: 1\.1
+${SPROG} commit: loginfo:[0-9]*: no such user variable \${=ZEE}
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\."
+ echo line0 >>file1
+ dotest info-intfmt-6c "${testcvs} -q -sOTHER=foo ci -m mod-it" \
+"${TESTDIR}/cvsroot/third-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+${SPROG} commit: loginfo:[0-9]*: no such user variable \${=ZEE}
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\."
+ echo line1 >>file1
+ dotest info-intfmt-7 "${testcvs} -q -s OTHER=value -s ZEE=z ci -m mod-it" \
+"${TESTDIR}/cvsroot/third-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\.
+${SPROG} commit: Using deprecated info format strings\. Convert your scripts to use
+the new argument format and remove '1's from your info file format strings\."
+
+ cd ..
+ dotest info-intfmt-9 "cat $TESTDIR/testlog" "xenv-valueyz=${username}=${TESTDIR}/cvsroot="
+ dotest info-intfmt-10 "cat $TESTDIR/testlog2" \
+'third-dir
+third-dir
+third-dir
+third-dir file1,,NONE,1.1
+third-dir 1.1
+third-dir file1 %s
+third-dir NONEAX
+third-dir file1ux
+third-dir
+third-dir
+third-dir
+third-dir file1,,1.1,1.2
+third-dir 1.2
+third-dir file1 %s
+third-dir 1.1AX
+third-dir file1ux
+third-dir
+third-dir
+third-dir
+third-dir file1,,1.2,1.3
+third-dir 1.3
+third-dir file1 %s
+third-dir 1.2AX
+third-dir file1ux'
+
+ rm ${TESTDIR}/testlog ${TESTDIR}/testlog2
+
+ # test the new format strings too
+ cd CVSROOT
+ dotest info-setup-newfmt-1 "$testcvs -q up -prinfo-start loginfo >loginfo"
+ echo "ALL sh -c \"echo x\${=MYENV}\${=OTHER}y\${=ZEE}=\$USER=\$CVSROOT= >>$TESTDIR/testlog; cat >/dev/null\" %{sVv}" >> loginfo
+ # The following cases test the format string substitution
+ echo "ALL echo %p \"%{sTVv}\" >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %{v} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %s >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "ALL echo %{V}AX >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ echo "second-dir echo %sux >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo
+ dotest info-setup-newfmt-2 "$testcvs -q -s ZEE=garbage ci -m nuke-admin-for-info-newfmt" \
+"${CVSROOT_DIRNAME}/CVSROOT/loginfo,v <-- loginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+${SPROG} commit: Rebuilding administrative file database"
+ cd ..
+
+ # delete the logs now so the results look more like the last tests
+ # (they won't include the config file update)
+ rm ${TESTDIR}/testlog ${TESTDIR}/testlog2
+
+ modify_repo mkdir $CVSROOT_DIRNAME/fourth-dir
+ dotest info-newfmt-1 "${testcvs} -q co fourth-dir" ''
+ cd fourth-dir
+ touch file1
+ dotest info-newfmt-2 "${testcvs} add file1" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ echo "cvs -s OTHER=not-this -s MYENV=env-" >>$HOME/.cvsrc
+ dotest info-newfmt-3 "$testcvs -q -s OTHER=value ci -m add-it" \
+"$TESTDIR/cvsroot/fourth-dir/file1,v <-- file1
+initial revision: 1\.1
+$SPROG commit: loginfo:[0-9]*: no such user variable \${=ZEE}"
+ echo line0 >>file1
+ dotest info-newfmt-4 "$testcvs -q -sOTHER=foo ci -m mod-it" \
+"$TESTDIR/cvsroot/fourth-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+$SPROG commit: loginfo:[0-9]*: no such user variable \${=ZEE}"
+ echo line1 >>file1
+ dotest info-newfmt-5 "${testcvs} -q -s OTHER=value -s ZEE=z ci -m mod-it" \
+"${TESTDIR}/cvsroot/fourth-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+
+ cd ..
+ dotest info-newfmt-6 "cat $TESTDIR/testlog" \
+"xenv-valueyz=${username}=${TESTDIR}/cvsroot="
+ dotest info-newfmt-7 "cat $TESTDIR/testlog2" \
+'fourth-dir file1 NONE 1\.1
+1\.1
+file1
+NONEAX
+fourth-dir file1 1\.1 1\.2
+1\.2
+file1
+1\.1AX
+fourth-dir file1 1\.2 1\.3
+1\.3
+file1
+1\.2AX'
+
+ # clean up after newfmt tests
+ cd CVSROOT
+ dotest info-cleanup-newfmt-1 "$testcvs -q up -prinfo-start loginfo >loginfo"
+ dotest info-cleanup-newfmt-2 "$testcvs -q ci -m nuke-loginfo" \
+"$CVSROOT_DIRNAME/CVSROOT/loginfo,v <-- loginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ # clean up the logs
+ rm ${TESTDIR}/testlog ${TESTDIR}/testlog2
+
+ # Now test verifymsg
+ cat >${TESTDIR}/vscript <<EOF
+#!${TESTSHELL}
+echo vscript "\$@"
+if sed 1q < \$1 | grep '^BugId:[ ]*[0-9][0-9]*$' > /dev/null; then
+ exit 0
+elif sed 1q < \$1 | grep '^BugId:[ ]*new$' > /dev/null; then
+ echo A new bugid was found. >> \$1
+ exit 0
+else
+ echo "No BugId found."
+ sleep 1
+ exit 1
+fi
+EOF
+ cat >${TESTDIR}/vscript2 <<EOF
+#!${TESTSHELL}
+echo vscript2 "\$@"
+if test -f CVS/Repository; then
+ repo=\`cat CVS/Repository\`
+else
+ repo=\`pwd\`
+fi
+echo \$repo
+if echo "\$repo" |grep yet-another/ >/dev/null 2>&1; then
+ exit 1
+else
+ exit 0
+fi
+EOF
+ # Grumble, grumble, mumble, search for "Cygwin".
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x ${TESTDIR}/vscript*"
+ else
+ chmod +x ${TESTDIR}/vscript*
+ fi
+ echo "^first-dir/yet-another\\(/\\|\$\\) ${TESTDIR}/vscript2 %l %{sV}" >verifymsg
+ echo "^first-dir\\(/\\|\$\\) ${TESTDIR}/vscript %l %{sV}" >>verifymsg
+ echo "^missing-script\$ ${TESTDIR}/bogus %l" >>verifymsg
+ echo "^missing-var\$ ${TESTDIR}/vscript %l \${=Bogus}" >>verifymsg
+ # first test the directory independant verifymsg
+ dotest info-v1 "${testcvs} -q ci -m add-verification" \
+"$CVSROOT_DIRNAME/CVSROOT/verifymsg,v <-- verifymsg
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ../first-dir
+ echo line2 >>file1
+ dotest_fail info-v2 "${testcvs} -q ci -m bogus" \
+"vscript $tempname file1 1\.3
+No BugId found\.
+${SPROG} \[commit aborted\]: Message verification failed"
+
+ cat >${TESTDIR}/comment.tmp <<EOF
+BugId: 42
+and many more lines after it
+EOF
+ dotest info-v3 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \
+"vscript $tempname file1 1\.3
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3"
+ rm ${TESTDIR}/comment.tmp
+
+ cd ..
+ mkdir another-dir
+ cd another-dir
+ touch file2
+ dotest_fail info-v4 \
+ "${testcvs} import -m bogus first-dir/another x y" \
+"vscript $tempname - Imported sources NONE
+No BugId found\.
+${SPROG} \[import aborted\]: Message verification failed"
+
+ # now verify that directory dependent verifymsgs work
+ dotest info-v5 \
+ "${testcvs} import -m bogus first-dir/yet-another x y" \
+"vscript2 $tempname - Imported sources NONE
+$TESTDIR/wnt/another-dir
+N first-dir/yet-another/file2
+
+No conflicts created by this import" \
+"vscript2 $tempname - Imported sources NONE
+$CVSROOT_DIRNAME/first-dir/yet-another
+N first-dir/yet-another/file2
+
+No conflicts created by this import"
+
+ # FIXCVS
+ #
+ # note that in the local case the error message is the same as
+ # info-v5
+ #
+ # This means that the verifymsg scripts cannot reliably and
+ # consistantly obtain information on which directory is being
+ # committed to. Thus it is currently useless for them to be
+ # running in every dir. They should either be run once or
+ # directory information should be passed.
+ if $remote; then
+ dotest_fail info-v6r \
+ "${testcvs} import -m bogus first-dir/yet-another/and-another x y" \
+"vscript2 $tempname - Imported sources NONE
+$CVSROOT_DIRNAME/first-dir/yet-another/and-another
+$SPROG \[import aborted\]: Message verification failed"
+ else
+ dotest info-v6 \
+ "${testcvs} import -m bogus first-dir/yet-another/and-another x y" \
+"vscript2 $tempname - Imported sources NONE
+$TESTDIR/wnt/another-dir
+N first-dir/yet-another/and-another/file2
+
+No conflicts created by this import"
+ fi
+
+ # check that errors invoking the script cause verification failure
+ #
+ # The second text below occurs on Cygwin, where I assume execvp
+ # does not return to let CVS print the error message when its
+ # argument does not exist.
+ dotest_fail info-v7 "${testcvs} import -m bogus missing-script x y" \
+"${SPROG} import: cannot exec ${TESTDIR}/bogus: No such file or directory
+${SPROG} \[import aborted\]: Message verification failed" \
+"${SPROG} \[import aborted\]: Message verification failed"
+
+ dotest_fail info-v8 "${testcvs} import -m bogus missing-var x y" \
+"${SPROG} import: verifymsg:4: no such user variable \${=Bogus}
+${SPROG} \[import aborted\]: Message verification failed"
+
+ rm file2
+ cd ..
+ rmdir another-dir
+
+ cd CVSROOT
+ echo "RereadLogAfterVerify=always" >>config
+ dotest info-rereadlog-1 "${testcvs} -q ci -m add-RereadLogAfterVerify=always" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../first-dir
+ echo line3 >>file1
+ cat >${TESTDIR}/comment.tmp <<EOF
+BugId: new
+See what happens next.
+EOF
+ dotest info-reread-2 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \
+"vscript $tempname file1 1\.4
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4"
+ dotest info-reread-3 "${testcvs} -q log -N -r1.5 file1" "
+.*
+BugId: new
+See what happens next.
+A new bugid was found.
+============================================================================="
+
+ cd ../CVSROOT
+ grep -v "RereadLogAfterVerify" config > config.new
+ mv config.new config
+ echo "RereadLogAfterVerify=stat" >>config
+ dotest info-reread-4 \
+"$testcvs -q ci -m add-RereadLogAfterVerify=stat" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../first-dir
+ echo line4 >>file1
+ cat >${TESTDIR}/comment.tmp <<EOF
+BugId: new
+See what happens next with stat.
+EOF
+ dotest info-reread-5 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \
+"vscript $tempname file1 1\.5
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.6; previous revision: 1\.5"
+ dotest info-reread-6 "${testcvs} -q log -N -r1.6 file1" "
+.*
+BugId: new
+See what happens next with stat.
+A new bugid was found.
+============================================================================="
+
+ cd ../CVSROOT
+ grep -v "RereadLogAfterVerify" config > config.new
+ mv config.new config
+ echo "RereadLogAfterVerify=never" >>config
+ dotest info-reread-7 \
+"$testcvs -q ci -m add-RereadLogAfterVerify=never" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../first-dir
+ echo line5 >>file1
+ cat >${TESTDIR}/comment.tmp <<EOF
+BugId: new
+See what happens next.
+EOF
+ dotest info-reread-8 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \
+"vscript $tempname file1 1\.6
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.7; previous revision: 1\.6"
+ dotest info-reread-6 "${testcvs} -q log -N -r1.7 file1" "
+.*
+BugId: new
+See what happens next.
+============================================================================="
+
+ cd ../CVSROOT
+ dotest info-reread-cleanup-1 "$testcvs -q up -prinfo-start config >config"
+ # Append the NULL format string until we remove the deprecation
+ # warning for lack of format strings.
+ echo 'DEFAULT false %n' >verifymsg
+ echo 'DEFAULT true %n' >>verifymsg
+ dotest info-multdef "${testcvs} -q ci -m multdef" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$CVSROOT_DIRNAME/CVSROOT/verifymsg,v <-- verifymsg
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ../CVSROOT
+ dotest info-reread--cleanup-1 \
+"$testcvs -q up -prinfo-start verifymsg >verifymsg"
+ dotest info-cleanup-verifymsg "$testcvs -q ci -m nuke-verifymsg" \
+"$SPROG commit: Multiple .DEFAULT. lines (1 and 2) in verifymsg file
+$CVSROOT_DIRNAME/CVSROOT/verifymsg,v <-- verifymsg
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ dokeep
+ rm ${TESTDIR}/vscript*
+ cd ..
+
+ dotest info-cleanup-0 "$testcvs -n release -d CVSROOT" \
+"You have \[0\] altered files in this repository\."
+
+ dotest info-cleanup-1 \
+"echo yes |${testcvs} -q release -d CVSROOT >/dev/null"
+ dotest info-cleanup-2 \
+"echo yes |${testcvs} -q release -d first-dir >/dev/null"
+ dotest info-cleanup-3 \
+"echo yes |${testcvs} -q release -d third-dir >/dev/null"
+ dotest info-cleanup-4 \
+"echo yes |${testcvs} -q release -d fourth-dir >/dev/null"
+
+ dokeep
+ cd ..
+ rm -r wnt
+ rm $HOME/.cvsrc
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/third-dir \
+ $CVSROOT_DIRNAME/fourth-dir
+ ;;
+
+
+
+ taginfo)
+ # Tests of the CVSROOT/taginfo file. See the comment at the
+ # "info" tests for a full list of administrative file tests.
+
+ # all the oldfmt stuff can come out once we finish deprecating
+ # the old info file command line format stuff.
+ #
+ # grep the code for SUPPORT_OLD_INFO_FMT_STRINGS and see the stuff
+ # in configure.in about oldinfoformatsupport
+
+ mkdir 1; cd 1
+ dotest taginfo-init-1 "$testcvs -q co CVSROOT" "U CVSROOT/$DOTSTAR"
+ cd CVSROOT
+ dotest taginfo-init-2 "$testcvs -Q tag taginfo-start"
+ cat >$TESTDIR/1/loggit <<EOF
+#!$TESTSHELL
+if test "\$1" = rejectme; then
+ exit 1
+else
+ echo "\$@" >>$TESTDIR/1/taglog
+ exit 0
+fi
+EOF
+ # #^@&!^@ Cygwin.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x ${TESTDIR}/1/loggit"
+ else
+ chmod +x ${TESTDIR}/1/loggit
+ fi
+ echo "ALL ${TESTDIR}/1/loggit" >>taginfo
+ sed -e's/^UseNewInfoFmtStrings=yes$/#&/' <config >tmpconfig
+ mv tmpconfig config
+ sed -e's/%p/ALL/' <loginfo >tmploginfo
+ mv tmploginfo loginfo
+ dotest taginfo-2 "${testcvs} -q ci -m check-in-taginfo" \
+"$TESTDIR/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$CVSROOT_DIRNAME/CVSROOT/loginfo,v <-- loginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$CVSROOT_DIRNAME/CVSROOT/taginfo,v <-- taginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+
+ # taginfo-3 used to rely on the top-level CVS directory
+ # being created to add "first-dir" to the repository. Since
+ # that won't happen anymore, we create the directory in the
+ # repository.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest taginfo-3 "$testcvs -q co first-dir"
+
+ cd first-dir
+ echo first >file1
+ dotest taginfo-4 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest taginfo-5 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary '1' in
+all info files after each '%' which doesn't represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\."
+ dotest taginfo-6 "${testcvs} -q tag tag1" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\.
+T file1"
+ dotest taginfo-7 "${testcvs} -q tag -b br" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\.
+T file1"
+ dotest taginfo-8 "$testcvs -q update -r br"
+ echo add text on branch >>file1
+ dotest taginfo-9 "${testcvs} -q ci -m modify-on-br" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary '1' in
+all info files after each '%' which doesn't represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\."
+ dotest taginfo-10 "${testcvs} -q tag -F -c brtag" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\.
+T file1"
+
+ dotest_fail taginfo-11 "${testcvs} -q tag rejectme" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\.
+${SPROG} tag: Pre-tag check failed
+${SPROG} \[tag aborted\]: correct the above errors first!"
+
+ # When we are using taginfo to allow/disallow, it would be
+ # convenient to be able to use "cvs -n tag" to test whether
+ # the allow/disallow functionality is working as expected.
+ dotest taginfo-12 "${testcvs} -nq tag rejectme" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\.
+T file1"
+
+ # But when taginfo is used for logging, it is a pain for -n
+ # to call taginfo, since taginfo doesn't know whether -n was
+ # specified or not.
+ dotest taginfo-13 "${testcvs} -nq tag would-be-tag" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\.
+T file1"
+
+ # Deleting: the cases are basically either the tag existed,
+ # or it didn't exist.
+ dotest taginfo-14 "${testcvs} -q tag -d tag1" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\.
+D file1"
+ dotest taginfo-15 "${testcvs} -q tag -d tag1" \
+"${SPROG} tag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\."
+
+ # Likewise with rtag.
+ dotest taginfo-16 "${testcvs} -q rtag tag1 first-dir" \
+"${SPROG} rtag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\."
+ dotest taginfo-17 "${testcvs} -q rtag -d tag1 first-dir" \
+"${SPROG} rtag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\."
+ dotest taginfo-18 "${testcvs} -q rtag -d tag1 first-dir" \
+"${SPROG} rtag: warning: taginfo line contains no format strings:
+ \"${TESTDIR}/1/loggit\"
+Filling in old defaults ('%t %o %p %{sv}'), but please be aware that this
+usage is deprecated\."
+
+ # The "br" example should be passing 1.1.2 or 1.1.0.2.
+ # But it turns out that is very hard to implement, since
+ # check_fileproc doesn't know what branch number it will
+ # get. Probably the whole thing should be re-architected
+ # so that taginfo only allows/denies tagging, and a new
+ # hook, which is done from tag_fileproc, does logging.
+ # That would solve this, some more subtle races, and also
+ # the fact that it is nice for users to run "-n tag foo" to
+ # see whether a tag would be allowed. Failing that,
+ # I suppose passing "1.1.branch" or "branch" for "br"
+ # would be an improvement.
+ dotest taginfo-examine-1 "cat ${TESTDIR}/1/taglog" \
+"tag1 add first-dir file1 1\.1
+br add first-dir file1 1\.1
+brtag mov first-dir file1 1\.1\.2\.1
+tag1 del first-dir file1 1\.1
+tag1 del first-dir
+tag1 add first-dir file1 1\.1
+tag1 del first-dir file1 1\.1
+tag1 del first-dir"
+
+ # now that we've tested the default operation, try a new
+ # style fmt string.
+ rm $TESTDIR/1/taglog
+ cd ..
+ cd CVSROOT
+ dotest taginfo-newfmt-init-1 \
+"$testcvs -q up -prtaginfo-start taginfo >taginfo"
+ echo "ALL $TESTDIR/1/loggit %r %t %o %b %p %{sTVv}" >>taginfo
+ dotest taginfo-newfmt-init-2 "$testcvs -q ci -m check-in-taginfo" \
+"$TESTDIR/cvsroot/CVSROOT/taginfo,v <-- taginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database" \
+"$TESTDIR/cvsroot/CVSROOT/taginfo,v <-- taginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary '1' in
+all info files after each '%' which doesn't represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\."
+
+ cat >${TESTDIR}/1/loggit <<EOF
+#!${TESTSHELL}
+if test "\$1" = rejectme; then
+ exit 1
+else
+ while test "\$#" -gt 0; do
+ echo "\$1" >>${TESTDIR}/1/taglog
+ shift
+ done
+ exit 0
+fi
+EOF
+
+ cd ..
+ cd first-dir
+ dotest taginfo-newfmt-2 "${testcvs} -q update -A" "[UP] file1"
+ echo "bull pucky" >'file 2'
+ dotest taginfo-newfmt-2b "${testcvs} add 'file 2'" \
+"${SPROG} add: scheduling file .file 2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest taginfo-newfmt-2c "$testcvs -q ci -m add-it" \
+"$TESTDIR/cvsroot/first-dir/file 2,v <-- file 2
+initial revision: 1\.1" \
+"$TESTDIR/cvsroot/first-dir/file 2,v <-- file 2
+initial revision: 1\.1
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary '1' in
+all info files after each '%' which doesn't represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\."
+
+ dotest taginfo-newfmt-3 "${testcvs} -q tag tag1" \
+"T file 2
+T file1"
+ dotest taginfo-newfmt-4 "${testcvs} -q tag tag3" \
+"T file 2
+T file1"
+ dotest taginfo-newfmt-5 "$testcvs -q tag -rtag1 tag4" \
+"T file 2
+T file1"
+
+ dotest taginfo-newfmt-examine-1 "cat ${TESTDIR}/1/taglog" \
+"$TESTDIR/cvsroot
+tag1
+add
+N
+first-dir
+file 2
+
+NONE
+1\.1
+file1
+
+NONE
+1\.1
+$TESTDIR/cvsroot
+tag3
+add
+N
+first-dir
+file 2
+
+NONE
+1\.1
+file1
+
+NONE
+1\.1
+$TESTDIR/cvsroot
+tag4
+add
+N
+first-dir
+file 2
+tag1
+NONE
+1\.1
+file1
+tag1
+NONE
+1\.1"
+
+ # now update to use the new format strings (really, disable support
+ # of the old format) and run the whole gamut of tests again.
+ rm ${TESTDIR}/1/taglog
+ cd ..
+ cd CVSROOT
+ cat >${TESTDIR}/1/loggit <<EOF
+#!${TESTSHELL}
+if test "\$1" = rejectme; then
+ exit 1
+else
+ echo "\$@" >>${TESTDIR}/1/taglog
+ exit 0
+fi
+EOF
+ dotest taginfo-newfmt-init-7 \
+"$testcvs -q up -prtaginfo-start taginfo >taginfo"
+ echo "ALL ${TESTDIR}/1/loggit %{t} %b %{o} %p %{sTVv}" >>taginfo
+ echo "UseNewInfoFmtStrings=yes" >>config
+ dotest taginfo-newfmt-7 "$testcvs -q ci -m check-in-taginfo" \
+"$TESTDIR/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$TESTDIR/cvsroot/CVSROOT/taginfo,v <-- taginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database" \
+"$TESTDIR/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$TESTDIR/cvsroot/CVSROOT/taginfo,v <-- taginfo
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database
+$SPROG commit: warning: Set to use deprecated info format strings\. Establish
+compatibility with the new info file format strings (add a temporary '1' in
+all info files after each '%' which doesn't represent a literal percent)
+and set UseNewInfoFmtStrings=yes in CVSROOT/config\. After that, convert
+individual command lines and scripts to handle the new format at your
+leisure\."
+
+ cd ../first-dir
+ dotest taginfo-newfmt-8 "${testcvs} -q tag tag1" ""
+ mkdir sdir
+ dotest taginfo-newfmt-8b "${testcvs} -q add sdir" \
+"Directory ${TESTDIR}/cvsroot/first-dir/sdir added to the repository"
+ touch sdir/file3
+ dotest taginfo-newfmt-8c "${testcvs} -q add sdir/file3" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest taginfo-newfmt-8d "${testcvs} -q ci -m added-sdir" \
+"${TESTDIR}/cvsroot/first-dir/sdir/file3,v <-- sdir/file3
+initial revision: 1\.1"
+ dotest taginfo-newfmt-9 "${testcvs} -q tag -b br" \
+"T file 2
+W file1 : br already exists on branch 1\.1\.2\.1 : NOT MOVING tag to branch 1\.1\.0\.4
+T sdir/file3"
+ dotest taginfo-newfmt-10 "${testcvs} -q update -r br" "[UP] file1"
+ echo add more text on branch >>file1
+ dotest taginfo-newfmt-11 "${testcvs} -q ci -m modify-on-br" \
+"${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+ dotest taginfo-newfmt-12 "${testcvs} -q tag -F -c brtag" \
+"T file 2
+T file1
+T sdir/file3"
+
+ # we are being called once for each directory. I'm not sure
+ # I like this, but I'm also not sure how hard it would be to change,
+ # It seems like it would be more trouble than it is really worth
+ # to let a partial tag go through...
+ dotest_fail taginfo-newfmt-13 "${testcvs} -q tag rejectme" \
+"${SPROG} tag: Pre-tag check failed
+${SPROG} tag: Pre-tag check failed
+${SPROG} \[tag aborted\]: correct the above errors first!"
+
+ # When we are using taginfo to allow/disallow, it would be
+ # convenient to be able to use "cvs -n tag" to test whether
+ # the allow/disallow functionality is working as expected.
+ # see the comment before taginfo-newfmt-15 for notes on
+ # pretag and posttag proc
+ dotest taginfo-newfmt-14 "${testcvs} -nq tag rejectme" \
+"T file 2
+T file1
+T sdir/file3"
+
+ # But when taginfo is used for logging, it is a pain for -n
+ # to call taginfo, since taginfo doesn't know whether -n was
+ # specified or not. (this could be fixed pretty easily now
+ # with a new fmt string. i suppose it would be better to
+ # have a pretag proc and a posttag proc, though.)
+ dotest taginfo-newfmt-15 "${testcvs} -nq tag would-be-tag" \
+"T file 2
+T file1
+T sdir/file3"
+
+ # Deleting: the cases are basically either the tag existed,
+ # or it didn't exist.
+ dotest taginfo-newfmt-16 "${testcvs} -q tag -d tag1" \
+"D file 2
+D file1"
+ dotest taginfo-newfmt-17 "${testcvs} -q tag -d tag1" ""
+
+ # Likewise with rtag.
+ dotest taginfo-newfmt-18 "${testcvs} -q rtag tag1 first-dir" ""
+ dotest taginfo-newfmt-19 "${testcvs} -q rtag -d tag1 first-dir" ""
+ dotest taginfo-newfmt-20 "${testcvs} -q rtag -d tag1 first-dir" ""
+
+ # The "br" example should be passing 1.1.2 or 1.1.0.2.
+ # But it turns out that is very hard to implement, since
+ # check_fileproc doesn't know what branch number it will
+ # get. Probably the whole thing should be re-architected
+ # so that taginfo only allows/denies tagging, and a new
+ # hook, which is done from tag_fileproc, does logging.
+ # That would solve this, some more subtle races, and also
+ # the fact that it is nice for users to run "-n tag foo" to
+ # see whether a tag would be allowed. Failing that,
+ # I suppose passing "1.1.branch" or "branch" for "br"
+ # would be an improvement.
+ dotest taginfo-newfmt-examine-2 "cat ${TESTDIR}/1/taglog" \
+"tag1 N add first-dir
+br T add first-dir file 2 NONE 1\.1
+br T add first-dir/sdir file3 NONE 1\.1
+brtag N mov first-dir file 2 br NONE 1\.1 file1 br 1\.1\.2\.1 1\.1\.2\.2
+brtag N mov first-dir/sdir file3 br NONE 1\.1
+tag1 ? del first-dir file 2 br 1\.1 1\.1 file1 br 1\.1 1\.1
+tag1 ? del first-dir/sdir
+tag1 ? del first-dir
+tag1 ? del first-dir/sdir
+tag1 N add first-dir file 2 NONE 1\.1 file1 NONE 1\.1
+tag1 N add first-dir/sdir file3 NONE 1\.1
+tag1 ? del first-dir file 2 1\.1 1\.1 file1 1\.1 1\.1
+tag1 ? del first-dir/sdir file3 1\.1 1\.1
+tag1 ? del first-dir
+tag1 ? del first-dir/sdir"
+
+ dokeep
+ restore_adm
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ posttag)
+ # Tests of the CVSROOT/taginfo file. See the comment at the
+ # "info" tests for a full list of administrative file tests.
+
+ mkdir 1; cd 1
+
+ dotest posttag-init-1 "$testcvs -q co CVSROOT" "U CVSROOT/$DOTSTAR"
+
+ # now that we've tested the default operation, try a new
+ # style fmt string.
+ cd CVSROOT
+ echo "ALL $TESTDIR/1/loggit %r %t %o %b %p %{sVv}" >posttag
+ dotest posttag-init-2 "$testcvs -q ci -m check-in-taginfo" \
+"$TESTDIR/cvsroot/CVSROOT/posttag,v <-- posttag
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ..
+
+ cat >$TESTDIR/1/loggit <<EOF
+#!$TESTSHELL
+if test "\$1" = rejectme; then
+ error=:
+else
+ error=false
+fi
+
+while [ -n "\$1" ]; do
+ echo "\$1" >>$TESTDIR/1/taglog
+ shift
+done
+
+if \$error; then
+ exit 1
+fi
+exit 0
+EOF
+ # #^@&!^@ Cygwin.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x $TESTDIR/1/loggit"
+ else
+ chmod +x $TESTDIR/1/loggit
+ fi
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest posttag-init-3 "$testcvs -q co first-dir"
+
+ cd first-dir
+ echo first >file1
+ echo "bull pucky" >'file 2'
+ dotest posttag-init-4 "$testcvs add file1 'file 2'" \
+"$SPROG add: scheduling file \`file1' for addition
+$SPROG add: scheduling file \`file 2' for addition
+$SPROG add: use \`$SPROG commit' to add these files permanently"
+ dotest posttag-init-5 "$testcvs -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file 2,v <-- file 2
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ dotest posttag-1 "$testcvs -q tag tag1" \
+"T file 2
+T file1"
+ dotest posttag-2 "$testcvs -q tag tag3" \
+"T file 2
+T file1"
+
+ dotest posttag-3 "$testcvs -q tag rejectme" \
+"T file 2
+T file1"
+
+ dotest posttag-4 "$testcvs -q tag -d rejectme" \
+"D file 2
+D file1"
+
+ dotest posttag-examine-1 "cat $TESTDIR/1/taglog" \
+"$TESTDIR/cvsroot
+tag1
+add
+N
+first-dir
+file 2
+NONE
+1\.1
+file1
+NONE
+1\.1
+$TESTDIR/cvsroot
+tag3
+add
+N
+first-dir
+file 2
+NONE
+1\.1
+file1
+NONE
+1\.1
+$TESTDIR/cvsroot
+rejectme
+add
+N
+first-dir
+file 2
+NONE
+1.1
+file1
+NONE
+1.1
+$TESTDIR/cvsroot
+rejectme
+del
+?
+first-dir
+file 2
+1.1
+1.1
+file1
+1.1
+1.1"
+
+ dokeep
+ cd ../..
+ restore_adm
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ config)
+ # Tests of the CVSROOT/config file. See the comment at the
+ # "info" tests for a full list of administrative file tests.
+
+ # See note in keywordexpand about config errors from a proxied
+ # primary.
+ if $noredirect; then
+ notnoredirect config
+ continue
+ fi
+
+ # On Windows, we can't check out CVSROOT, because the case
+ # insensitivity means that this conflicts with cvsroot.
+ mkdir wnt
+ cd wnt
+
+ dotest config-init-1 "$testcvs -q co CVSROOT" "U CVSROOT/$DOTSTAR"
+ cd CVSROOT
+ dotest config-init-2 "$testcvs -Q tag config-start"
+ echo 'bogus line' >>config
+ dotest config-3 "$testcvs -q ci -m change-to-bogus-line" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ dotest config-3a "$testcvs -Q update -jHEAD -jconfig-start" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: syntax error: missing \`=' between keyword and value
+RCS file: $CVSROOT_DIRNAME/CVSROOT/config,v
+retrieving revision 1.[0-9]*
+retrieving revision 1.[0-9]*
+Merging differences between 1.[0-9]* and 1.[0-9]* into config"
+ echo 'BogusOption=yes' >>config
+ if $proxy; then
+ dotest config-4p "$testcvs -q ci -m change-to-bogus-opt" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[99\]: syntax error: missing \`=' between keyword and value
+$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[99\]: syntax error: missing \`=' between keyword and value
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ else
+ dotest config-4 "$testcvs -q ci -m change-to-bogus-opt" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: syntax error: missing \`=' between keyword and value
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ fi
+
+ if $proxy; then
+ : # FIXME: don't try in proxy mode
+ else
+ # Now test the HistoryLogPath and HistorySearchPath options.
+ mkdir $TESTDIR/historylogs
+ echo >config \
+ 'HistoryLogPath=$CVSROOT/../historylogs/%Y-%m-%d-%H-%M-%S'
+ echo 'HistorySearchPath=$CVSROOT/../historylogs/*' >>config
+
+ # The warning is left over from the previous test.
+ dotest config-5 "$testcvs -q ci -m set-HistoryLogPath" \
+"$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[98\]: unrecognized keyword \`BogusOption'
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ echo '# noop' >> config
+ dotest config-6 "$testcvs -q ci -mlog-commit" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ sleep 1
+ echo '# noop' >> config
+ dotest config-7 "$testcvs -q ci -mlog-commit" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ # The log entry was intentionally split across multiple files.
+ dotest config-8 "ls -l $TESTDIR/historylogs/*" \
+"-rw-rw-r--.*$TESTDIR/historylogs/2[0-9][0-9][0-9]-[01][0-9]-[0-3][0-9]-[0-2][0-9]-[0-5][0-9]-[0-5][0-9]
+-rw-rw-r--.*$TESTDIR/historylogs/2[0-9][0-9][0-9]-[01][0-9]-[0-3][0-9]-[0-2][0-9]-[0-5][0-9]-[0-5][0-9]"
+
+ # Should still see both commits.
+ if $remote; then
+ dotest config-9r "$testcvs history -ea" \
+"M [0-9-]* [0-9:]* ${PLUS}0000 $username 1\.[0-9]* config CVSROOT == <remote>
+M [0-9-]* [0-9:]* ${PLUS}0000 $username 1\.[0-9]* config CVSROOT == <remote>"
+ else
+ dotest config-9 "$testcvs history -ea" \
+"M [0-9-]* [0-9:]* ${PLUS}0000 $username 1\.[0-9]* config CVSROOT == $TESTDIR/wnt/CVSROOT
+M [0-9-]* [0-9:]* ${PLUS}0000 $username 1\.[0-9]* config CVSROOT == $TESTDIR/wnt/CVSROOT"
+ fi
+
+ # Remove this now to see what kind of error messages we get.
+ rm -r $TESTDIR/historylogs
+ fi
+
+ dokeep
+ restore_adm
+ cd ../..
+ rm -r wnt
+ ;;
+
+
+
+ config2)
+ # Tests of the CVSROOT/config file. See the comment at the
+ # "info" tests for a full list of administrative file tests.
+
+ # No point in testing compression effects in local mode.
+ if $remote; then :; else
+ remoteonly config2
+ continue
+ fi
+
+ # On Windows, we can't check out CVSROOT, because the case
+ # insensitivity means that this conflicts with cvsroot.
+ mkdir wnt
+ cd wnt
+
+ # Set MinCompressionLevel and MaxCompressionLevel in config.
+ dotest config2-init-1 "$testcvs -q co CVSROOT" "U CVSROOT/$DOTSTAR"
+ dotest config2-init-1b "$testcvs -Q tag initial"
+ cd CVSROOT
+ cat << EOF >> config
+MinCompressionLevel=5
+MaxCompressionLevel=6
+EOF
+ dotest config2-init-2 \
+"$testcvs -q ci -m set-compression-constraints" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ # Verify that the server reports forcing compression to an allowed
+ # level.
+
+ # Too high.
+ dotest config2-1 "$testcvs -z9 update" \
+"$SPROG server: Forcing compression level 6 (allowed: 5 <= z <= 6)\.
+$SPROG update: Updating \."
+ # Too low.
+ dotest config2-2 "$testcvs -z1 update" \
+"$SPROG server: Forcing compression level 5 (allowed: 5 <= z <= 6)\.
+$SPROG update: Updating \."
+ # From zero.
+ dotest config2-3 "$testcvs update" \
+"$SPROG server: Forcing compression level 5 (allowed: 5 <= z <= 6)\.
+$SPROG update: Updating \."
+ # Just right.
+ dotest config2-3 "$testcvs -z5 update" \
+"$SPROG update: Updating \."
+
+ # Check that compression may be forced to 0.
+ dotest config2-init-2b "$testcvs -z5 up -jHEAD -jinitial" "$DOTSTAR"
+ cat << EOF >> config
+MaxCompressionLevel=0
+EOF
+ dotest config2-init-3 "$testcvs -qz5 ci -m no-compression" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ # Too high.
+ dotest config2-5 "$testcvs -z9 update" \
+"$SPROG server: Forcing compression level 0 (allowed: 0 <= z <= 0)\.
+$SPROG update: Updating \."
+ # Just right.
+ dotest config2-6 "$testcvs update" \
+"$SPROG update: Updating \."
+
+ # And verify effect without restrictions.
+ dotest config2-init-3b "$testcvs up -jHEAD -jinitial" "$DOTSTAR"
+ dotest config2-init-4 "$testcvs -q ci -m change-to-comment" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ dotest config2-7 "$testcvs update" \
+"$SPROG update: Updating \."
+
+ dokeep
+ restore_adm
+ cd ../..
+ rm -r wnt
+ ;;
+
+ config3)
+ # Verify comments, white space, & [rootspecs] in CVSROOT/config
+ #
+ # `cvs server' `-c' option tested in `server' test
+ modify_repo mkdir $CVSROOT_DIRNAME/config3
+ mkdir config3
+ cd config3
+
+ dotest config3-init-1 "$testcvs -q co CVSROOT" "U CVSROOT/$DOTSTAR"
+ cd CVSROOT
+
+ # I break the usual sanity.sh indentation standard for here-docs
+ # mostly to test that leading white-space is now ignored.
+ dotest config3-init-1b "$testcvs -Q tag initial-config"
+
+ cat <<EOF >>config
+ # Ignore a comment with leading spaces.
+ GLOBAL-BAD-OPTION=WWW
+
+ [/ignore/this/root]
+ [/and/this/one]
+ IGNORED-BAD-OPTION=YYY
+EOF
+ dotest config3-init-2 \
+"$testcvs -q ci -m test-root-specs" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ..
+ dotest config3-1 "$testcvs co config3" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`GLOBAL-BAD-OPTION'
+$SPROG checkout: Updating config3"
+
+ cd CVSROOT
+ dotest config3-init-2a "$testcvs -Q up -jHEAD -jinitial-config" \
+"$DOTSTAR
+Merging differences between 1\.[0-9]* and 1\.[0-9]* into config"
+
+ cat <<EOF >>config
+ # Ignore a comment with leading spaces.
+
+ [/ignore/this/root]
+ [/and/this/one]
+ IGNORED-BAD-OPTION=YYY
+ # Ignore a comment with leading spaces.
+
+ [/some/other/root]
+
+ # Comments and blank lines do not affect fall-through behavior.
+
+ [$CVSROOT_DIRNAME]
+ [$SECONDARY_CVSROOT_DIRNAME]
+
+ # Comments and blank lines do not affect fall-through behavior.
+
+ [/yet/another/root]
+ # Ignore a comment with leading spaces.
+ PROCESS-BAD-OPTION=XXX
+EOF
+ dotest config3-init-3 \
+"$testcvs -q ci -m test-root-specs" \
+"$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`GLOBAL-BAD-OPTION'
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`GLOBAL-BAD-OPTION'
+$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`GLOBAL-BAD-OPTION'
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ..
+ dotest config3-2 "$testcvs co config3" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`PROCESS-BAD-OPTION'
+$SPROG checkout: Updating config3"
+
+ # The next few tests make sure both global options and root
+ # specific options are processed by setting the history log and
+ # search paths in different locations and then verifying that
+ # both registered. It also verifies that a key for a different
+ # root is ignored.
+ cd CVSROOT
+ dotest config3-init-3a "$testcvs -Q up -jHEAD -jinitial-config" \
+"$DOTSTAR
+Merging differences between 1\.[0-9]* and 1\.[0-9]* into config"
+
+ cat <<EOF >>config
+ HistoryLogPath=$TESTDIR/historylog
+
+ [/ignore/this/root]
+ [/and/this/one]
+ IGNORED-BAD-OPTION=YYY
+
+ [/some/other/root]
+ [$CVSROOT_DIRNAME]
+ [$SECONDARY_CVSROOT_DIRNAME]
+ [/yet/another/root]
+ HistorySearchPath=$TESTDIR/historylog
+
+ [/ignore/another/root]
+ [/and/this/one/too]
+ ANOTHER-IGNORED-BAD-OPTION=ZZZ
+
+ [$CVSROOT_DIRNAME]
+ [$SECONDARY_CVSROOT_DIRNAME]
+ LogHistory=TMAR
+EOF
+ dotest config3-init-4 \
+"$testcvs -q ci -m test-root-specs" \
+"$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`PROCESS-BAD-OPTION'
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database" \
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`PROCESS-BAD-OPTION'
+$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: unrecognized keyword \`PROCESS-BAD-OPTION'
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cd ..
+ dotest config3-3 "$testcvs co -d config3-2 config3" \
+"$SPROG checkout: Updating config3-2"
+
+ cd config3-2
+ touch newfile
+ dotest config3-4 "$testcvs -Q add newfile"
+ dotest config3-5 "$testcvs -q ci -madd-file" \
+"$CVSROOT_DIRNAME/config3/newfile,v <-- newfile
+initial revision: 1\.1"
+
+ dotest config3-6 "$testcvs rtag testtag config3" \
+"$SPROG rtag: Tagging config3"
+
+ cd ..
+ dotest config3-7 "$testcvs history -ea" \
+"A [0-9-]* [0-9:]* ${PLUS}0000 $username 1\.1 newfile config3 == [-_/a-zA-Z0-9<>]*
+T [0-9-]* [0-9:]* ${PLUS}0000 $username config3 \[testtag:A\]"
+
+ dokeep
+ restore_adm
+ cd ..
+ rm -r config3
+ modify_repo rm -rf $CVSROOT_DIRNAME/config3
+ ;;
+
+
+
+ config4)
+ # TmpDir
+ mkdir config4
+ cd config4
+
+ dotest config4-init-1 "$testcvs -q co CVSROOT" "U CVSROOT/$DOTSTAR"
+ cd CVSROOT
+ mkdir $TESTDIR/config4/tmp
+ echo "TmpDir=$TESTDIR/config4/tmp" >>config
+ echo "DEFAULT $TESTDIR/config4/verify %l" >>verifymsg
+ dotest config4-init-2 "$testcvs -q ci -m change-tmpdir" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$CVSROOT_DIRNAME/CVSROOT/verifymsg,v <-- verifymsg
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ cat >$TESTDIR/config4/verify <<EOF
+#! /bin/sh
+echo \$1
+exit 0
+EOF
+ chmod a+x $TESTDIR/config4/verify
+ dotest config4-1 \
+"$testcvs -q ci -fmtest-tmpdir config" \
+"$TESTDIR/config4/tmp/$tempfile
+$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ dokeep
+ restore_adm
+ cd ../..
+ rm -r config4
+ modify_repo rm -rf $CVSROOT_DIRNAME/config4
+ ;;
+
+
+
+ serverpatch)
+ # Test remote CVS handling of unpatchable files. This isn't
+ # much of a test for local CVS.
+ # We test this with some keyword expansion games, but the situation
+ # also arises if the user modifies the file while CVS is running.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ mkdir 1
+ cd 1
+ dotest serverpatch-1 "$testcvs -q co first-dir"
+
+ cd first-dir
+
+ # Add a file with an RCS keyword.
+ echo '$''Name$' > file1
+ echo '1' >> file1
+ dotest serverpatch-2 "$testcvs add file1" \
+"$SPROG add: scheduling file \`file1' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+
+ dotest serverpatch-3 "${testcvs} -q commit -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ # Tag the file.
+ dotest serverpatch-4 "${testcvs} -q tag tag file1" 'T file1'
+
+ # Check out a tagged copy of the file.
+ cd ../..
+ mkdir 2
+ cd 2
+ dotest serverpatch-5 "${testcvs} -q co -r tag first-dir" \
+'U first-dir/file1'
+
+ # Remove the tag. This will leave the tag string in the
+ # expansion of the Name keyword.
+ dotest serverpatch-6 "${testcvs} -q update -A first-dir" ''
+
+ # Modify and check in the first copy.
+ cd ../1/first-dir
+ echo '2' >> file1
+ dotest serverpatch-7 "${testcvs} -q ci -mx file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Now update the second copy. When using remote CVS, the
+ # patch will fail, forcing the file to be refetched.
+ cd ../../2/first-dir
+ dotest serverpatch-8 "${testcvs} -q update" \
+'U file1' \
+"P file1
+${CPROG} update: checksum failure after patch to \./file1; will refetch
+${CPROG} client: refetching unpatchable files
+$SPROG update: warning: \`file1' was lost
+U file1"
+
+ dokeep
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ log)
+ # Test selecting revisions with cvs log.
+ # See also log2 tests for more tests.
+ # See also branches-14.3 for logging with a branch off of a branch.
+ # See also multibranch-14 for logging with several branches off the
+ # same branchpoint.
+ # Tests of each option to cvs log:
+ # -h: admin-19a-log
+ # -N: log, log2, admin-19a-log
+ # -b, -r: log
+ # -d: logopt, rcs
+ # -s: logopt, rcs3
+ # -R: logopt, rcs3
+ # -w, -t: not tested yet (TODO)
+
+ # Check in a file with a few revisions and branches.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest log-1 "$testcvs -q co first-dir"
+ cd first-dir
+ echo 'first revision' > file1
+ echo 'first revision' > file2
+ dotest log-2 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+
+ # While we're at it, check multi-line comments, input from file,
+ # and trailing whitespace trimming
+ echo 'line 1 ' >${TESTDIR}/comment.tmp
+ echo ' ' >>${TESTDIR}/comment.tmp
+ echo 'line 2 ' >>${TESTDIR}/comment.tmp
+ echo ' ' >>${TESTDIR}/comment.tmp
+ echo ' ' >>${TESTDIR}/comment.tmp
+ dotest log-3 "${testcvs} -q commit -F ${TESTDIR}/comment.tmp" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ rm -f ${TESTDIR}/comment.tmp
+
+ echo 'second revision' > file1
+ echo 'second revision' > file2
+ dotest log-4 "${testcvs} -q ci -m2 file1 file2" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.2; previous revision: 1\.1"
+
+ dotest log-5 "${testcvs} -q tag -b branch file1" 'T file1'
+ dotest log-5a "${testcvs} -q tag tag1 file2" 'T file2'
+
+ echo 'third revision' > file1
+ echo 'third revision' > file2
+ dotest log-6 "${testcvs} -q ci -m3 file1 file2" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.3; previous revision: 1\.2"
+
+ dotest log-6a "${testcvs} -q tag tag2 file2" 'T file2'
+
+ dotest log-7 "${testcvs} -q update -r branch" \
+"[UP] file1
+${SPROG} update: \`file2' is no longer in the repository"
+
+ echo 'first branch revision' > file1
+ dotest log-8 "${testcvs} -q ci -m1b file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2\.2\.1; previous revision: 1\.2"
+
+ dotest log-9 "${testcvs} -q tag tag file1" 'T file1'
+
+ echo 'second branch revision' > file1
+ dotest log-10 "${testcvs} -q ci -m2b file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2\.2\.2; previous revision: 1\.2\.2\.1"
+
+ # Set up a bunch of shell variables to make the later tests
+ # easier to describe.=
+ log_header1="
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.3
+branch:
+locks: strict
+access list:"
+ rlog_header1="
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+head: 1\.3
+branch:
+locks: strict
+access list:"
+ log_tags1='symbolic names:
+ tag: 1\.2\.2\.1
+ branch: 1\.2\.0\.2'
+ log_keyword='keyword substitution: kv'
+ log_dash='----------------------------
+revision'
+ log_date="date: ${ISO8601DATE}; author: ${username}; state: Exp;"
+ log_lines=" lines: ${PLUS}1 -1;"
+ log_commitid=" commitid: ${commitid};"
+ log_rev1="${log_dash} 1\.1
+${log_date}${log_commitid}
+line 1
+
+line 2"
+ log_rev2="${log_dash} 1\.2
+${log_date}${log_lines}${log_commitid}
+branches: 1\.2\.2;
+2"
+ log_rev3="${log_dash} 1\.3
+${log_date}${log_lines}${log_commitid}
+3"
+ log_rev1b="${log_dash} 1\.2\.2\.1
+${log_date}${log_lines}${log_commitid}
+1b"
+ log_rev2b="${log_dash} 1\.2\.2\.2
+${log_date}${log_lines}${log_commitid}
+2b"
+ log_trailer='============================================================================='
+
+ # Now, finally, test the log output.
+
+ dotest log-11 "${testcvs} log file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 5
+description:
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ dotest log-12 "${testcvs} log -N file1" \
+"${log_header1}
+${log_keyword}
+total revisions: 5; selected revisions: 5
+description:
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ dotest log-13 "${testcvs} log -b file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 3
+description:
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-14 "${testcvs} log -r file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ dotest log-14a "${testcvs} log -rHEAD file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ # The user might not realize that "-r" must not take a space.
+ # In the error message, HEAD is a file name, not a tag name (which
+ # might be confusing itself).
+ dotest_fail log-14b "${testcvs} log -r HEAD file1" \
+"${SPROG} log: nothing known about HEAD
+${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+# Check that unusual syntax works correctly.
+
+ dotest log-14c "${testcvs} log -r: file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+ dotest log-14d "${testcvs} log -r, file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+ dotest log-14e "${testcvs} log -r. file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+ dotest log-14f "${testcvs} log -r:: file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-15 "${testcvs} log -r1.2 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2}
+${log_trailer}"
+
+ dotest log-16 "${testcvs} log -r1.2.2 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ # This test would fail with the old invocation of rlog, but it
+ # works with the builtin log support.
+ dotest log-17 "${testcvs} log -rbranch file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ dotest log-18 "${testcvs} log -r1.2.2. file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2b}
+${log_trailer}"
+
+ # Multiple -r options are undocumented; see comments in
+ # cvs.texinfo about whether they should be deprecated.
+ dotest log-18a "${testcvs} log -r1.2.2.2 -r1.3:1.3 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2b}
+${log_trailer}"
+
+ # This test would fail with the old invocation of rlog, but it
+ # works with the builtin log support.
+ dotest log-19 "${testcvs} log -rbranch. file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2b}
+${log_trailer}"
+
+ dotest log-20 "${testcvs} log -r1.2: file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2}
+${log_trailer}"
+
+ dotest log-20a "${testcvs} log -r1.2:: file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ dotest log-21 "${testcvs} log -r:1.2 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-21a "${testcvs} log -r::1.2 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-22 "${testcvs} log -r1.1:1.2 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-22a "${testcvs} log -r1.1::1.2 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2}
+${log_trailer}"
+
+ dotest log-22b "${testcvs} log -r1.1::1.3 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2}
+${log_trailer}"
+
+ dotest log-23 "${testcvs} log -rfoo:: file1" \
+"${SPROG} log: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-24 "${testcvs} log -rfoo::1.3 file1" \
+"${SPROG} log: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-25 "${testcvs} log -r::foo file1" \
+"${SPROG} log: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-26 "${testcvs} log -r1.1::foo file1" \
+"${SPROG} log: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ # Test BASE pseudotag
+ dotest log-27 "${testcvs} log -rBASE file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2b}
+${log_trailer}"
+
+ dotest log-28 "${testcvs} -q up -r1.2 file1" "[UP] file1"
+ dotest log-29 "${testcvs} log -rBASE file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2}
+${log_trailer}"
+
+ dotest log-30 "${testcvs} -q up -rbranch file1" "[UP] file1"
+
+ # Now the same tests but with rlog
+
+ dotest log-r11 "${testcvs} rlog first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 5
+description:
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ dotest log-r12 "${testcvs} rlog -N first-dir/file1" \
+"${rlog_header1}
+${log_keyword}
+total revisions: 5; selected revisions: 5
+description:
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ dotest log-r13 "${testcvs} rlog -b first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 3
+description:
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-r14 "${testcvs} rlog -r first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ dotest log-r14a "${testcvs} rlog -rHEAD first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ dotest_fail log-r14b "${testcvs} rlog -r HEAD first-dir/file1" \
+"${SPROG} rlog: cannot find module .HEAD. - ignored
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ dotest log-r14c "${testcvs} rlog -r: first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+ dotest log-r14d "${testcvs} rlog -r, first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+ dotest log-r14e "${testcvs} rlog -r. first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+ dotest log-r14f "${testcvs} rlog -r:: first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-r15 "${testcvs} rlog -r1.2 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2}
+${log_trailer}"
+
+ dotest log-r16 "${testcvs} rlog -r1.2.2 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ dotest log-r17 "${testcvs} rlog -rbranch first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+
+ dotest log-r18 "${testcvs} rlog -r1.2.2. first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2b}
+${log_trailer}"
+
+ dotest log-r18a "${testcvs} rlog -r1.2.2.2 -r1.3:1.3 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2b}
+${log_trailer}"
+
+ dotest log-r19 "${testcvs} rlog -rbranch. first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2b}
+${log_trailer}"
+
+ dotest log-r20 "${testcvs} rlog -r1.2: first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2}
+${log_trailer}"
+
+ dotest log-r20a "${testcvs} rlog -r1.2:: first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ dotest log-r21 "${testcvs} rlog -r:1.2 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-r21a "${testcvs} rlog -r::1.2 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-r22 "${testcvs} rlog -r1.1:1.2 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev2}
+${log_rev1}
+${log_trailer}"
+
+ dotest log-r22a "${testcvs} rlog -r1.1::1.2 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev2}
+${log_trailer}"
+
+ dotest log-r22b "${testcvs} rlog -r1.1::1.3 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2}
+${log_trailer}"
+
+ dotest log-r23 "${testcvs} rlog -rfoo:: first-dir/file1" \
+"${SPROG} rlog: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-r24 "${testcvs} rlog -rfoo::1.3 first-dir/file1" \
+"${SPROG} rlog: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-r25 "${testcvs} rlog -r::foo first-dir/file1" \
+"${SPROG} rlog: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-r26 "${testcvs} rlog -r1.1::foo first-dir/file1" \
+"${SPROG} rlog: warning: no revision .foo. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ # Test BASE pseudotag
+ dotest log-r27 "${testcvs} rlog -rBASE first-dir/file1" \
+"${SPROG} rlog: warning: no revision .BASE. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ dotest log-r28 "${testcvs} -q up -r1.2 file1" "[UP] file1"
+ dotest log-r29 "${testcvs} rlog -rBASE first-dir/file1" \
+"${SPROG} rlog: warning: no revision .BASE. in .${CVSROOT_DIRNAME}/first-dir/file1,v.
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 0
+description:
+${log_trailer}"
+
+ # Test when head is dead
+
+ dotest log-d0 "${testcvs} -q up -A" \
+"[UP] file1
+U file2"
+ dotest log-d1 "${testcvs} -q rm -f file1" \
+"${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
+ dotest log-d2 "${testcvs} -q ci -m4" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.3"
+
+ log_header1="
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+Working file: file1
+head: 1\.4
+branch:
+locks: strict
+access list:"
+ rlog_header1="
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+head: 1\.4
+branch:
+locks: strict
+access list:"
+ log_header2="
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.3
+branch:
+locks: strict
+access list:"
+ rlog_header2="
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+head: 1\.3
+branch:
+locks: strict
+access list:"
+ log_tags2='symbolic names:
+ tag2: 1\.3
+ tag1: 1\.2'
+ log_rev4="${log_dash} 1\.4
+date: ${ISO8601DATE}; author: ${username}; state: dead; lines: ${PLUS}0 -0; commitid: ${commitid};
+4"
+ log_rev22="${log_dash} 1\.2
+${log_date}${log_lines}${log_commitid}
+2"
+
+ dotest log-d3 "${testcvs} log -rbranch file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+ dotest log-rd3 "${testcvs} rlog -rbranch first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+ dotest log-d4 "${testcvs} -q log -rbranch" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}
+${SPROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v.
+${log_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 0
+description:
+${log_trailer}"
+ dotest log-d4a "${testcvs} -q log -t -rbranch" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6
+description:
+${log_trailer}
+${SPROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v.
+${log_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3
+description:
+${log_trailer}"
+ dotest log-d4b "${testcvs} -q log -tS -rbranch" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_trailer}
+${SPROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v."
+ dotest log-d4c "${testcvs} -q log -h -rbranch" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6
+${log_trailer}
+${SPROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v.
+${log_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3
+${log_trailer}"
+ dotest log-d4d "${testcvs} -q log -hS -rbranch" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+${log_trailer}
+${SPROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v."
+ dotest log-d4e "$testcvs -q log -R -rbranch" \
+"$CVSROOT_DIRNAME/first-dir/Attic/file1,v
+$CVSROOT_DIRNAME/first-dir/file2,v"
+ dotest log-d4f "${testcvs} -q log -R -S -rbranch" \
+"${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+${SPROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v."
+ dotest log-rd4 "${testcvs} -q rlog -rbranch first-dir" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}
+${SPROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v.
+${rlog_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 0
+description:
+${log_trailer}"
+ dotest log-rd4a "${testcvs} -q rlog -t -rbranch first-dir" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6
+description:
+${log_trailer}
+${SPROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v.
+${rlog_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3
+description:
+${log_trailer}"
+ dotest log-rd4b "${testcvs} -q rlog -St -rbranch first-dir" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_trailer}
+${SPROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v."
+ dotest log-rd4c "${testcvs} -q rlog -h -rbranch first-dir" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6
+${log_trailer}
+${SPROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v.
+${rlog_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3
+${log_trailer}"
+ dotest log-rd4d "${testcvs} -q rlog -Sh -rbranch first-dir" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+${log_trailer}
+${SPROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v."
+ dotest log-rd4e "${testcvs} -q rlog -R -rbranch first-dir" \
+"${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+${CVSROOT_DIRNAME}/first-dir/file2,v"
+ dotest log-rd4f "${testcvs} -q rlog -R -S -rbranch first-dir" \
+"${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+${SPROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v."
+ dotest log-d5 "${testcvs} log -r1.2.2.1:1.2.2.2 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+ dotest log-rd5 "${testcvs} rlog -r1.2.2.1:1.2.2.2 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}"
+ dotest log-d6 "${testcvs} -q log -r1.2.2.1:1.2.2.2" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}
+${log_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 0
+description:
+${log_trailer}"
+ dotest log-rd6 "${testcvs} -q rlog -r1.2.2.1:1.2.2.2 first-dir" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev2b}
+${log_rev1b}
+${log_trailer}
+${rlog_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 0
+description:
+${log_trailer}"
+ dotest log-d7 "${testcvs} log -r1.2:1.3 file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2}
+${log_trailer}"
+ dotest log-rd7 "${testcvs} -q rlog -r1.2:1.3 first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 2
+description:
+${log_rev3}
+${log_rev2}
+${log_trailer}"
+ dotest log-d8 "${testcvs} -q log -rtag1:tag2" \
+"${SPROG} log: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${SPROG} log: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 0
+description:
+${log_trailer}
+${log_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 2
+description:
+${log_rev3}
+${log_rev22}
+${log_trailer}"
+ dotest log-d8a "${testcvs} -q log -rtag1:tag2 -S" \
+"${SPROG} log: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${SPROG} log: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${log_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 2
+description:
+${log_rev3}
+${log_rev22}
+${log_trailer}"
+ dotest log-rd8 "${testcvs} -q rlog -rtag1:tag2 first-dir" \
+"${SPROG} rlog: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${SPROG} rlog: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 6; selected revisions: 0
+description:
+${log_trailer}
+${rlog_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 2
+description:
+${log_rev3}
+${log_rev22}
+${log_trailer}"
+ dotest log-rd8a "${testcvs} -q rlog -rtag1:tag2 -S first-dir" \
+"${SPROG} rlog: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${SPROG} rlog: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v.
+${rlog_header2}
+${log_tags2}
+${log_keyword}
+total revisions: 3; selected revisions: 2
+description:
+${log_rev3}
+${log_rev22}
+${log_trailer}"
+
+ dotest log-d99 "${testcvs} -q up -rbranch" \
+"[UP] file1
+${SPROG} update: \`file2' is no longer in the repository"
+
+ # Now test outdating revisions
+
+ dotest log-o0 "${testcvs} admin -o 1.2.2.2:: file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+done"
+ dotest log-o1 "${testcvs} admin -o ::1.2.2.1 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+done"
+ dotest log-o2 "${testcvs} admin -o 1.2.2.1:: file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+deleting revision 1\.2\.2\.2
+done"
+ dotest log-o3 "${testcvs} log file1" \
+"${log_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 5
+description:
+${log_rev4}
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_rev1b}
+${log_trailer}"
+ dotest log-ro3 "${testcvs} rlog first-dir/file1" \
+"${rlog_header1}
+${log_tags1}
+${log_keyword}
+total revisions: 5; selected revisions: 5
+description:
+${log_rev4}
+${log_rev3}
+${log_rev2}
+${log_rev1}
+${log_rev1b}
+${log_trailer}"
+ dotest log-o4 "${testcvs} -q update -p -r 1.2.2.1 file1" \
+"first branch revision"
+
+ dokeep
+ cd ..
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ log2)
+ # More "cvs log" tests, for example the file description.
+
+ # Check in a file
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest log2-1 "$testcvs -q co first-dir"
+ cd first-dir
+ echo 'first revision' > file1
+ dotest log2-2 "${testcvs} add -m file1-is-for-testing file1" \
+"${SPROG}"' add: scheduling file `file1'\'' for addition
+'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
+ dotest log2-3 "${testcvs} -q commit -m 1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ # Setting the file description with add -m doesn't yet work
+ # client/server, so skip log2-4 for remote.
+ if $remote; then :; else
+
+ dotest log2-4 "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+file1-is-for-testing
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+1
+============================================================================="
+
+ fi # end of tests skipped for remote
+
+ dotest log2-5 "${testcvs} admin -t-change-description file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest log2-6 "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+change-description
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+1
+============================================================================="
+
+ echo 'longer description' >${TESTDIR}/descrip
+ echo 'with two lines' >>${TESTDIR}/descrip
+ dotest log2-7 "${testcvs} admin -t${TESTDIR}/descrip file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest_fail log2-7a "${testcvs} admin -t${TESTDIR}/nonexist file1" \
+"${CPROG} \[admin aborted\]: can't stat ${TESTDIR}/nonexist: No such file or directory"
+ dotest log2-8 "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+longer description
+with two lines
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+1
+============================================================================="
+
+ # TODO: `cvs admin -t "my message" file1' is a request to
+ # read the message from stdin and to operate on two files.
+ # Should test that there is an error because "my message"
+ # doesn't exist.
+
+ dotest log2-9 "echo change from stdin | ${testcvs} admin -t -q file1" ""
+ dotest log2-10 "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+change from stdin
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+1
+============================================================================="
+
+ dokeep
+ cd ..
+ rm $TESTDIR/descrip
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ logopt)
+ # Some tests of log.c's option parsing and such things.
+ mkdir 1; cd 1
+ dotest logopt-1 "$testcvs -q co -l ." ''
+ mkdir first-dir
+ dotest logopt-2 "$testcvs add first-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+ cd first-dir
+ echo hi >file1
+ dotest logopt-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest logopt-4 "${testcvs} -q ci -m add file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ cd ..
+
+ dotest logopt-5 "${testcvs} log -R -d 2038-01-01" \
+"${SPROG} log: Logging \.
+${SPROG} log: Logging first-dir
+${CVSROOT_DIRNAME}/first-dir/file1,v"
+ dotest logopt-6 "${testcvs} log -d 2038-01-01 -R" \
+"${SPROG} log: Logging \.
+${SPROG} log: Logging first-dir
+${CVSROOT_DIRNAME}/first-dir/file1,v"
+ dotest logopt-6a "${testcvs} log -Rd 2038-01-01" \
+"${SPROG} log: Logging \.
+${SPROG} log: Logging first-dir
+${CVSROOT_DIRNAME}/first-dir/file1,v"
+ dotest logopt-7 "${testcvs} log -s Exp -R" \
+"${SPROG} log: Logging \.
+${SPROG} log: Logging first-dir
+${CVSROOT_DIRNAME}/first-dir/file1,v"
+
+ dokeep
+ cd ..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ ann)
+ # Tests of "cvs annotate". See also:
+ # basica-10 A simple annotate test
+ # rcs Annotate and the year 2000
+ # keywordlog Annotate and $Log.
+ mkdir 1; cd 1
+ dotest ann-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest ann-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ cat >file1 <<EOF
+this
+is
+the
+ancestral
+file
+EOF
+ dotest ann-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest ann-4 "${testcvs} -q ci -m add file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ cat >file1 <<EOF
+this
+is
+a
+file
+
+with
+a
+blank
+line
+EOF
+ dotest ann-5 "${testcvs} -q ci -m modify file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ dotest ann-6 "${testcvs} -q tag -b br" "T file1"
+ cat >file1 <<EOF
+this
+is
+a
+trunk file
+
+with
+a
+blank
+line
+EOF
+ dotest ann-7 "${testcvs} -q ci -m modify file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+ dotest ann-8 "${testcvs} -q update -r br" "[UP] file1"
+ cat >file1 <<EOF
+this
+is
+a
+file
+
+with
+a
+blank
+line
+and some
+branched content
+EOF
+ dotest ann-9 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2\.2\.1; previous revision: 1\.2"
+ # Note that this annotates the trunk despite the presence
+ # of a sticky tag in the current directory. This is
+ # fairly bogus, but it is the longstanding behavior for
+ # whatever that is worth.
+ dotest ann-10 "${testcvs} ann" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 ($username8 *[0-9a-zA-Z-]*): this
+1\.1 ($username8 *[0-9a-zA-Z-]*): is
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.3 ($username8 *[0-9a-zA-Z-]*): trunk file
+1\.2 ($username8 *[0-9a-zA-Z-]*):
+1\.2 ($username8 *[0-9a-zA-Z-]*): with
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.2 ($username8 *[0-9a-zA-Z-]*): blank
+1\.2 ($username8 *[0-9a-zA-Z-]*): line"
+ dotest ann-11 "${testcvs} ann -r br" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 ($username8 *[0-9a-zA-Z-]*): this
+1\.1 ($username8 *[0-9a-zA-Z-]*): is
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.1 ($username8 *[0-9a-zA-Z-]*): file
+1\.2 ($username8 *[0-9a-zA-Z-]*):
+1\.2 ($username8 *[0-9a-zA-Z-]*): with
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.2 ($username8 *[0-9a-zA-Z-]*): blank
+1\.2 ($username8 *[0-9a-zA-Z-]*): line
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content"
+ # FIXCVS: shouldn't "-r 1.2.0.2" be the same as "-r br"?
+ dotest ann-12 "${testcvs} ann -r 1.2.0.2 file1" ""
+ dotest ann-13 "${testcvs} ann -r 1.2.2 file1" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 ($username8 *[0-9a-zA-Z-]*): this
+1\.1 ($username8 *[0-9a-zA-Z-]*): is
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.1 ($username8 *[0-9a-zA-Z-]*): file
+1\.2 ($username8 *[0-9a-zA-Z-]*):
+1\.2 ($username8 *[0-9a-zA-Z-]*): with
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.2 ($username8 *[0-9a-zA-Z-]*): blank
+1\.2 ($username8 *[0-9a-zA-Z-]*): line
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content"
+ dotest_fail ann-14 "$testcvs ann -r bill-clintons-chastity file1" \
+"$SPROG \[annotate aborted\]: no such tag \`bill-clintons-chastity'"
+
+ # Now get rid of the working directory and test rannotate
+
+ cd ../..
+ rm -r 1
+ dotest ann-r10 "${testcvs} rann first-dir" \
+"
+Annotations for first-dir/file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 ($username8 *[0-9a-zA-Z-]*): this
+1\.1 ($username8 *[0-9a-zA-Z-]*): is
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.3 ($username8 *[0-9a-zA-Z-]*): trunk file
+1\.2 ($username8 *[0-9a-zA-Z-]*):
+1\.2 ($username8 *[0-9a-zA-Z-]*): with
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.2 ($username8 *[0-9a-zA-Z-]*): blank
+1\.2 ($username8 *[0-9a-zA-Z-]*): line"
+ dotest ann-r11 "${testcvs} rann -r br first-dir" \
+"
+Annotations for first-dir/file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 ($username8 *[0-9a-zA-Z-]*): this
+1\.1 ($username8 *[0-9a-zA-Z-]*): is
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.1 ($username8 *[0-9a-zA-Z-]*): file
+1\.2 ($username8 *[0-9a-zA-Z-]*):
+1\.2 ($username8 *[0-9a-zA-Z-]*): with
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.2 ($username8 *[0-9a-zA-Z-]*): blank
+1\.2 ($username8 *[0-9a-zA-Z-]*): line
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content"
+ dotest ann-r12 "${testcvs} rann -r 1.2.0.2 first-dir/file1" ""
+ dotest ann-r13 "${testcvs} rann -r 1.2.2 first-dir/file1" \
+"
+Annotations for first-dir/file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 ($username8 *[0-9a-zA-Z-]*): this
+1\.1 ($username8 *[0-9a-zA-Z-]*): is
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.1 ($username8 *[0-9a-zA-Z-]*): file
+1\.2 ($username8 *[0-9a-zA-Z-]*):
+1\.2 ($username8 *[0-9a-zA-Z-]*): with
+1\.2 ($username8 *[0-9a-zA-Z-]*): a
+1\.2 ($username8 *[0-9a-zA-Z-]*): blank
+1\.2 ($username8 *[0-9a-zA-Z-]*): line
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some
+1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content"
+ dotest_fail ann-r14 "$testcvs rann -r bill-clintons-chastity first-dir/file1" \
+"$SPROG \[rannotate aborted\]: no such tag \`bill-clintons-chastity'"
+
+ dokeep
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ ann-id)
+ # Demonstrate that cvs-1.9.28.1 improperly expands rcs keywords in
+ # the output of `cvs annotate' -- it uses values from the previous
+ # delta. In this case, `1.1' instead of `1.2', even though it puts
+ # the proper version number on the prefix to each line of output.
+ mkdir 1; cd 1
+ dotest ann-id-1 "$testcvs -q co -l ."
+ module=x
+ mkdir $module
+ dotest ann-id-2 "${testcvs} add $module" \
+"Directory ${CVSROOT_DIRNAME}/$module added to the repository"
+ cd $module
+
+ file=m
+ echo '$Id''$' > $file
+
+ dotest ann-id-3 "$testcvs add $file" \
+"$SPROG add: scheduling file .$file. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest ann-id-4 "$testcvs -Q ci -m . $file"
+
+ echo line2 >> $file
+ dotest ann-id-5 "$testcvs -Q ci -m . $file"
+
+ # The version number after $file,v should be `1.2'.
+ # 1.9.28.1 puts `1.1' there.
+ dotest ann-id-6 "$testcvs -Q ann $file" \
+"
+Annotations for $file
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1.2 ($username8 *[0-9a-zA-Z-]*): "'\$'"Id: $file,v 1.1 [0-9/]* [0-9:]* $username Exp "'\$'"
+1.2 ($username8 *[0-9a-zA-Z-]*): line2"
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ crerepos)
+ # Various tests relating to creating repositories, operating
+ # on repositories created with old versions of CVS, etc.
+
+ CVS_SERVER_save=$CVS_SERVER
+
+ # Because this test is all about -d options and such, it
+ # at least to some extent needs to be different for remote vs.
+ # local.
+ if $remote; then
+
+ # Use :ext: rather than :fork:. Most of the tests use :fork:,
+ # so we want to make sure that we test :ext: _somewhere_.
+ # Make sure 'rsh' works first.
+ require_rsh "$CVS_RSH"
+ if test $? -eq 77; then
+ skip crerepos "$skipreason"
+ continue
+ fi
+
+ # Make sure server ignores real $HOME/.cvsrc:
+ cat >$TESTDIR/cvs-setHome <<EOF
+#!$TESTSHELL
+HOME=$HOME
+export HOME
+exec $CVS_SERVER "\$@"
+EOF
+ chmod a+x $TESTDIR/cvs-setHome
+
+ # Note that we set CVS_SERVER at the beginning.
+ CVS_SERVER=$TESTDIR/cvs-setHome; export CVS_SERVER
+ CREREPOS_ROOT=:ext:$host$TESTDIR/crerepos
+ else # local
+ CREREPOS_ROOT=$TESTDIR/crerepos
+ fi
+
+ # First, if the repository doesn't exist at all...
+ dotest_fail crerepos-1 \
+"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \
+"${SPROG} \[checkout aborted\]: ${TESTDIR}/crerepos/CVSROOT: .*"
+ mkdir crerepos
+
+ # The repository exists but CVSROOT doesn't.
+ dotest_fail crerepos-2 \
+"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \
+"${SPROG} \[checkout aborted\]: ${TESTDIR}/crerepos/CVSROOT: .*"
+ mkdir crerepos/CVSROOT
+
+ # Checkout of nonexistent module
+ dotest_fail crerepos-3 \
+"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \
+"${SPROG} checkout: cannot find module .cvs-sanity. - ignored"
+
+ # Now test that CVS works correctly without a modules file
+ # or any of that other stuff. In particular, it *must*
+ # function if administrative files added to CVS recently (since
+ # CVS 1.3) do not exist, because the repository might have
+ # been created with an old version of CVS.
+ mkdir 1; cd 1
+ dotest crerepos-4 \
+"${testcvs} -q -d ${TESTDIR}/crerepos co CVSROOT" \
+''
+ dotest crerepos-5 \
+"echo yes | $testcvs -d $TESTDIR/crerepos release -d CVSROOT" \
+"You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory \`CVSROOT': "
+ rm -rf CVS
+ cd ..
+ # The directory 1 should be empty
+ dotest crerepos-6 "rmdir 1"
+
+ if $remote; then
+ # Test that CVS rejects a relative path in CVSROOT.
+ mkdir 1; cd 1
+ # Note that having the client reject the pathname (as :fork:
+ # does), does _not_ test for the bugs we are trying to catch
+ # here. The point is that malicious clients might send all
+ # manner of things and the server better protect itself.
+ dotest_fail crerepos-6a-r \
+"${testcvs} -q -d :ext:`hostname`:../crerepos get ." \
+"${CPROG} checkout: CVSROOT may only specify a positive, non-zero, integer port (not .\.\..)\.
+${CPROG} checkout: Perhaps you entered a relative pathname${QUESTION}
+${CPROG} \[checkout aborted\]: Bad CVSROOT: .:ext:${hostname}:\.\./crerepos.\."
+ cd ..
+ rm -r 1
+
+ mkdir 1; cd 1
+ dotest_fail crerepos-6b-r \
+"${testcvs} -d :ext:`hostname`:crerepos init" \
+"${CPROG} init: CVSROOT requires a path spec:
+${CPROG} init: :(gserver|kserver|pserver):\[\[user\]\[:password\]@\]host\[:\[port\]\]/path
+${CPROG} init: \[:(ext|server):\]\[\[user\]@\]host\[:\]/path
+${CPROG} \[init aborted\]: Bad CVSROOT: .:ext:${hostname}:crerepos.\."
+ cd ..
+ rm -r 1
+ else # local
+ # Test that CVS rejects a relative path in CVSROOT.
+
+ mkdir 1; cd 1
+ # Set CVS_RSH=false since ocassionally (e.g. when CVS_RSH=ssh on
+ # some systems) some rsh implementations will block because they
+ # can look up '..' and want to ask the user about the unknown host
+ # key or somesuch. Which error message we get depends on whether
+ # false finishes running before we try to talk to it or not.
+ dotest_fail crerepos-6a "CVS_RSH=false ${testcvs} -q -d ../crerepos get ." \
+"${SPROG} \[checkout aborted\]: end of file from server (consult above messages if any)" \
+"${SPROG} \[checkout aborted\]: received broken pipe signal"
+ cd ..
+ rm -r 1
+
+ mkdir 1; cd 1
+ dotest_fail crerepos-6b "${testcvs} -d crerepos init" \
+"${SPROG} init: CVSROOT must be an absolute pathname (not .crerepos.)
+${SPROG} init: when using local access method\.
+${SPROG} \[init aborted\]: Bad CVSROOT: .crerepos.\."
+ cd ..
+ rm -r 1
+ fi # end of tests to be skipped for remote
+
+ # CVS should have created a history file. If the administrator
+ # doesn't need it and wants to save on disk space, they just
+ # delete it and set LogHistory = the empty string in config.
+ dotest crerepos-7 "test -f $TESTDIR/crerepos/CVSROOT/history"
+
+ # Now test mixing repositories. This kind of thing tends to
+ # happen accidentally when people work with several repositories.
+ mkdir 1; cd 1
+ dotest crerepos-8 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest crerepos-9 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch file1
+ dotest crerepos-10 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest crerepos-11 "${testcvs} -q ci -m add-it" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ cd ../..
+ rm -r 1
+
+ mkdir 1; cd 1
+ dotest crerepos-12 "$testcvs -d $CREREPOS_ROOT -q co -l ."
+ mkdir crerepos-dir
+ dotest crerepos-13 "$testcvs add crerepos-dir" \
+"Directory $TESTDIR/crerepos/crerepos-dir added to the repository"
+ cd crerepos-dir
+ touch cfile
+ dotest crerepos-14 "${testcvs} add cfile" \
+"${SPROG} add: scheduling file .cfile. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest crerepos-15 "${testcvs} -q ci -m add-it" \
+"$TESTDIR/crerepos/crerepos-dir/cfile,v <-- cfile
+initial revision: 1\.1"
+ cd ../..
+ rm -r 1
+
+ mkdir 1; cd 1
+ dotest crerepos-16 "${testcvs} co first-dir" \
+"${SPROG} checkout: Updating first-dir
+U first-dir/file1"
+ dotest crerepos-17 "${testcvs} -d ${CREREPOS_ROOT} co crerepos-dir" \
+"${SPROG} checkout: Updating crerepos-dir
+U crerepos-dir/cfile"
+ dotest crerepos-18 "${testcvs} update" \
+"${SPROG} update: Updating first-dir
+${SPROG} update: Updating crerepos-dir"
+
+ cd ..
+
+ CVS_SERVER=$CVS_SERVER_save; export CVS_SERVER
+
+ if $keep; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ dokeep
+ rm -f $TESTDIR/cvs-setHome
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ rm -rf $TESTDIR/crerepos
+ ;;
+
+
+
+ rcs)
+ # Test ability to import an RCS file. Note that this format
+ # is fixed--files written by RCS5, and other software which
+ # implements this format, will be out there "forever" and
+ # CVS must always be able to import such files.
+
+ # See tests admin-13, admin-25 and rcs-8a for exporting RCS files.
+
+ # Save the timezone and set it to UTC for these tests to make the
+ # value more predicatable.
+ save_TZ=$TZ
+ TZ=UTC0; export TZ
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+
+ # Currently the way to import an RCS file is to copy it
+ # directly into the repository.
+ #
+ # This file was written by RCS 5.7, and then the dates were
+ # hacked so that we test year 2000 stuff. Note also that
+ # "author" names are just strings, as far as importing
+ # RCS files is concerned--they need not correspond to user
+ # IDs on any particular system.
+ #
+ # I also tried writing a file with the RCS supplied with
+ # HPUX A.09.05. According to "man rcsintro" this is
+ # "Revision Number: 3.0; Release Date: 83/05/11". There
+ # were a few minor differences like whitespace but at least
+ # in simple cases like this everything else seemed the same
+ # as the file written by RCS 5.7 (so I won't try to make it
+ # a separate test case).
+
+ cat <<EOF >$TESTDIR/file1,v
+head 1.3;
+access;
+symbols;
+locks; strict;
+comment @# @;
+
+
+1.3
+date ${RAWRCSDATE2000A}; author kingdon; state Exp;
+branches;
+next 1.2;
+
+1.2
+date ${RAWRCSDATE1996A}; author kingdon; state Exp;
+branches;
+next 1.1;
+
+1.1
+date ${RAWRCSDATE1996B}; author kingdon; state Exp;
+branches;
+next ;
+
+
+desc
+@file1 is for testing CVS
+@
+
+
+1.3
+log
+@delete second line; modify twelfth line
+@
+text
+@This is the first line
+This is the third line
+This is the fourth line
+This is the fifth line
+This is the sixth line
+This is the seventh line
+This is the eighth line
+This is the ninth line
+This is the tenth line
+This is the eleventh line
+This is the twelfth line (and what a line it is)
+This is the thirteenth line
+@
+
+
+1.2
+log
+@add more lines
+@
+text
+@a1 1
+This is the second line
+d11 1
+a11 1
+This is the twelfth line
+@
+
+
+1.1
+log
+@add file1
+@
+text
+@d2 12
+@
+EOF
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/first-dir/file1,v
+
+ dotest rcs-1 "$testcvs -q co first-dir" 'U first-dir/file1'
+ cd first-dir
+ dotest rcs-2 "$testcvs -q log" "
+RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
+Working file: file1
+head: 1\.3
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+file1 is for testing CVS
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE2000A}; author: kingdon; state: Exp; lines: ${PLUS}1 -2;
+delete second line; modify twelfth line
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE1996A}; author: kingdon; state: Exp; lines: ${PLUS}12 -0;
+add more lines
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE1996B}; author: kingdon; state: Exp;
+add file1
+============================================================================="
+
+ # Note that the dates here are chosen so that (a) we test
+ # at least one date after 2000, (b) we will notice if the
+ # month and day are getting mixed up with each other.
+ # TODO: also test that year isn't getting mixed up with month
+ # or day, for example 01-02-03.
+
+ # ISO8601 format. There are many, many, other variations
+ # specified by ISO8601 which we should be testing too.
+ dotest rcs-3 "${testcvs} -q log -d '1996-12-11<'" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.3
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 3; selected revisions: 1
+description:
+file1 is for testing CVS
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE2000A}; author: kingdon; state: Exp; lines: ${PLUS}1 -2;
+delete second line; modify twelfth line
+============================================================================="
+
+ # RFC822 format (as amended by RFC1123).
+ dotest rcs-4 "${testcvs} -q log -d '<3 Apr 2000 00:00'" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.3
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 3; selected revisions: 2
+description:
+file1 is for testing CVS
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE1996A}; author: kingdon; state: Exp; lines: ${PLUS}12 -0;
+add more lines
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE1996B}; author: kingdon; state: Exp;
+add file1
+============================================================================="
+
+ # Intended behavior for "cvs annotate" is that it displays the
+ # last two digits of the year. Make sure it does that rather
+ # than some bogosity like "100".
+ dotest rcs-4a "${testcvs} annotate file1" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1 (kingdon 24-Nov-96): This is the first line
+1\.2 (kingdon 24-Nov-96): This is the third line
+1\.2 (kingdon 24-Nov-96): This is the fourth line
+1\.2 (kingdon 24-Nov-96): This is the fifth line
+1\.2 (kingdon 24-Nov-96): This is the sixth line
+1\.2 (kingdon 24-Nov-96): This is the seventh line
+1\.2 (kingdon 24-Nov-96): This is the eighth line
+1\.2 (kingdon 24-Nov-96): This is the ninth line
+1\.2 (kingdon 24-Nov-96): This is the tenth line
+1\.2 (kingdon 24-Nov-96): This is the eleventh line
+1\.3 (kingdon 24-Nov-00): This is the twelfth line (and what a line it is)
+1\.2 (kingdon 24-Nov-96): This is the thirteenth line"
+
+ # Probably should split this test into two at this point (file1
+ # above this line and file2 below), as the two share little
+ # data/setup.
+
+ # OK, here is another one. This one was written by hand based on
+ # doc/RCSFILES and friends. One subtle point is that none of
+ # the lines end with newlines; that is a feature which we
+ # should be testing.
+ cat <<EOF >$TESTDIR/file2,v
+head 1.5 ;
+ branch 1.2.6;
+access ;
+symbols branch:1.2.6;
+locks;
+testofanewphrase @without newphrase we'd have trouble extending @@ all@ ;
+1.5 date 71.01.01.01.00.00; author joe; state bogus; branches; next 1.4;
+1.4 date 71.01.01.00.00.05; author joe; state bogus; branches; next 1.3;
+1.3 date 70.12.31.15.00.05; author joe; state bogus; branches; next 1.2;
+1.2 date 70.12.31.12.15.05; author me; state bogus; branches 1.2.6.1; next 1.1;
+1.1 date 70.12.31.11.00.05; author joe; state bogus; branches; next; newph;
+1.2.6.1 date 71.01.01.08.00.05; author joe; state Exp; branches; next;
+desc @@
+1.5 log @@ newphrase1; newphrase2 42; text @head revision@
+1.4 log @@ text @d1 1
+a1 1
+new year revision@
+1.3 log @@ text @d1 1
+a1 1
+old year revision@
+1.2 log @@ text @d1 1
+a1 1
+mid revision@ 1.1
+
+log @@ text @d1 1
+a1 1
+start revision@
+1.2.6.1 log @@ text @d1 1
+a1 1
+branch revision@
+EOF
+ modify_repo mv $TESTDIR/file2,v $CVSROOT_DIRNAME/first-dir/file2,v
+ # ' Match the single quote in above here doc -- for font-lock mode.
+
+ # First test the default branch.
+ dotest rcs-5 "${testcvs} -q update file2" "U file2"
+ dotest rcs-6 "cat file2" "branch revision"
+
+ # Check in a revision on the branch to force CVS to
+ # interpret every revision in the file.
+ dotest rcs-6a "${testcvs} -q update -r branch file2" ""
+ echo "next branch revision" > file2
+ dotest rcs-6b "${testcvs} -q ci -m mod file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.2\.6\.2; previous revision: 1\.2\.6\.1"
+
+ # Now get rid of the default branch, it will get in the way.
+ dotest rcs-7 "${testcvs} admin -b file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+ # But we do want to make sure that "cvs admin" leaves the newphrases
+ # in the file.
+ # The extra whitespace regexps are for the RCS library, which does
+ # not preserve whitespace in the dogmatic manner of RCS 5.7. -twp
+ dotest rcs-8 \
+"grep testofanewphrase ${CVSROOT_DIRNAME}/first-dir/file2,v" \
+"testofanewphrase[ ][ ]*@without newphrase we'd have trouble extending @@ all@[ ]*;"
+ # The easiest way to test for newphrases in deltas and deltatexts
+ # is to just look at the whole file, I guess.
+ dotest rcs-8a "cat ${CVSROOT_DIRNAME}/first-dir/file2,v" \
+"head 1\.5;
+access;
+symbols
+ branch:1.2.6;
+locks;
+
+testofanewphrase @without newphrase we'd have trouble extending @@ all@;
+
+1\.5
+date 71\.01\.01\.01\.00\.00; author joe; state bogus;
+branches;
+next 1\.4;
+
+1\.4
+date 71\.01\.01\.00\.00\.05; author joe; state bogus;
+branches;
+next 1\.3;
+
+1\.3
+date 70\.12\.31\.15\.00\.05; author joe; state bogus;
+branches;
+next 1\.2;
+
+1\.2
+date 70\.12\.31\.12\.15\.05; author me; state bogus;
+branches
+ 1\.2\.6\.1;
+next 1\.1;
+
+1\.1
+date 70\.12\.31\.11\.00\.05; author joe; state bogus;
+branches;
+next ;
+newph ;
+
+1\.2\.6\.1
+date 71\.01\.01\.08\.00\.05; author joe; state Exp;
+branches;
+next 1\.2\.6\.2;
+
+1\.2\.6\.2
+date [0-9.]*; author ${username}; state Exp;
+branches;
+next ;
+commitid ${commitid};
+
+
+desc
+@@
+
+
+1\.5
+log
+@@
+newphrase1 ;
+newphrase2 42;
+text
+@head revision@
+
+
+1\.4
+log
+@@
+text
+@d1 1
+a1 1
+new year revision@
+
+
+1\.3
+log
+@@
+text
+@d1 1
+a1 1
+old year revision@
+
+
+1\.2
+log
+@@
+text
+@d1 1
+a1 1
+mid revision@
+
+
+1\.1
+log
+@@
+text
+@d1 1
+a1 1
+start revision@
+
+
+1\.2\.6\.1
+log
+@@
+text
+@d1 1
+a1 1
+branch revision@
+
+
+1\.2\.6\.2
+log
+@mod
+@
+text
+@d1 1
+a1 1
+next branch revision
+@"
+
+ dotest rcs-9 "${testcvs} -q update -p -D '1970-12-31 11:30 UT' file2" \
+"start revision"
+
+ dotest rcs-10 "${testcvs} -q update -p -D '1970-12-31 12:30 UT' file2" \
+"mid revision"
+
+ dotest rcs-11 "${testcvs} -q update -p -D '1971-01-01 00:30 UT' file2" \
+"new year revision"
+
+ # Same test as rcs-10, but with am/pm.
+ dotest rcs-12 "${testcvs} -q update -p -D 'December 31, 1970 12:30pm UT' file2" \
+"mid revision"
+
+ # Same test as rcs-11, but with am/pm.
+ dotest rcs-13 "${testcvs} -q update -p -D 'January 1, 1971 12:30am UT' file2" \
+"new year revision"
+
+ # OK, now make sure cvs log doesn't have any trouble with the
+ # newphrases and such.
+ dotest rcs-14 "${testcvs} -q log file2" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.5
+branch:
+locks:
+access list:
+symbolic names:
+ branch: 1\.2\.6
+keyword substitution: kv
+total revisions: 7; selected revisions: 7
+description:
+----------------------------
+revision 1\.5
+date: 1971-01-01 01:00:00 [+-]0000; author: joe; state: bogus; lines: ${PLUS}1 -1;
+\*\*\* empty log message \*\*\*
+----------------------------
+revision 1\.4
+date: 1971-01-01 00:00:05 [+-]0000; author: joe; state: bogus; lines: ${PLUS}1 -1;
+\*\*\* empty log message \*\*\*
+----------------------------
+revision 1\.3
+date: 1970-12-31 15:00:05 [+-]0000; author: joe; state: bogus; lines: ${PLUS}1 -1;
+\*\*\* empty log message \*\*\*
+----------------------------
+revision 1\.2
+date: 1970-12-31 12:15:05 [+-]0000; author: me; state: bogus; lines: ${PLUS}1 -1;
+branches: 1\.2\.6;
+\*\*\* empty log message \*\*\*
+----------------------------
+revision 1\.1
+date: 1970-12-31 11:00:05 [+-]0000; author: joe; state: bogus;
+\*\*\* empty log message \*\*\*
+----------------------------
+revision 1\.2\.6\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+mod
+----------------------------
+revision 1\.2\.6\.1
+date: 1971-01-01 08:00:05 [+-]0000; author: joe; state: Exp; lines: ${PLUS}1 -1;
+\*\*\* empty log message \*\*\*
+============================================================================="
+ # Now test each date format for "cvs log -d".
+ # Earlier than 1971-01-01
+ dotest rcs-15 "${testcvs} -q log -d '<1971-01-01 00:00 GMT' file2 \
+ | grep revision" \
+"total revisions: 7; selected revisions: 3
+revision 1\.3
+revision 1\.2
+revision 1\.1"
+ # Later than 1971-01-01
+ dotest rcs-16 "${testcvs} -q log -d '1971-01-01 00:00 GMT<' file2 \
+ | grep revision" \
+"total revisions: 7; selected revisions: 4
+revision 1\.5
+revision 1\.4
+revision 1\.2\.6\.2
+revision 1\.2\.6\.1"
+ # Alternate syntaxes for later and earlier; multiple -d options
+ dotest rcs-17 "${testcvs} -q log -d '>1971-01-01 00:00 GMT' \
+ -d '1970-12-31 12:15 GMT>' file2 | grep revision" \
+"total revisions: 7; selected revisions: 5
+revision 1\.5
+revision 1\.4
+revision 1\.1
+revision 1\.2\.6\.2
+revision 1\.2\.6\.1"
+ # Range, and single date
+ dotest rcs-18 "${testcvs} -q log -d '1970-12-31 11:30 GMT' \
+ -d '1971-01-01 00:00:05 GMT<1971-01-01 01:00:01 GMT' \
+ file2 | grep revision" \
+"total revisions: 7; selected revisions: 2
+revision 1\.5
+revision 1\.1"
+ # Alternate range syntax; equality
+ dotest rcs-19 "${testcvs} -q log \
+ -d '1971-01-01 01:00:01 GMT>=1971-01-01 00:00:05 GMT' \
+ file2 | grep revision" \
+"total revisions: 7; selected revisions: 2
+revision 1\.5
+revision 1\.4"
+
+ dokeep
+ TZ=$save_TZ
+ cd ..
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ rcs2)
+ # More date tests. Might as well do this as a separate
+ # test from "rcs", so that we don't need to perturb the
+ # "written by RCS 5.7" RCS file.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ # Significance of various dates:
+ # * At least one Y2K standard refers to recognizing 9 Sep 1999
+ # (as an example of a pre-2000 date, I guess).
+ # * At least one Y2K standard refers to recognizing 1 Jan 2001
+ # (as an example of a post-2000 date, I guess).
+ # * Many Y2K standards refer to 2000 being a leap year.
+ cat <<EOF >$TESTDIR/file1,v
+head 1.7; access; symbols; locks; strict;
+1.7 date 2004.08.31.01.01.01; author sue; state; branches; next 1.6;
+1.6 date 2004.02.29.01.01.01; author sue; state; branches; next 1.5;
+1.5 date 2003.02.28.01.01.01; author sue; state; branches; next 1.4;
+1.4 date 2001.01.01.01.01.01; author sue; state; branches; next 1.3;
+1.3 date 2000.02.29.01.01.01; author sue; state; branches; next 1.2;
+1.2 date 99.09.09.01.01.01; author sue; state; branches; next 1.1;
+1.1 date 98.09.10.01.01.01; author sue; state; branches; next;
+desc @a test file@
+1.7 log @@ text @head revision@
+1.6 log @@ text @d1 1
+a1 1
+2004 was a great year for leaping@
+1.5 log @@ text @d1 1
+a1 1
+2003 wasn't@
+1.4 log @@ text @d1 1
+a1 1
+two year hiatus@
+1.3 log @@ text @d1 1
+a1 1
+2000 is also a good year for leaping@
+1.2 log @@ text @d1 1
+a1 1
+Tonight we're going to party like it's a certain year@
+1.1 log @@ text @d1 1
+a1 1
+Need to start somewhere@
+EOF
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/first-dir/file1,v
+ # ' Match the 3rd single quote in the here doc -- for font-lock mode.
+
+ dotest rcs2-1 "${testcvs} -q co first-dir" 'U first-dir/file1'
+ cd first-dir
+
+ # 9 Sep 1999
+ dotest rcs2-2 "${testcvs} -q update -p -D '1999-09-09 11:30 UT' file1" \
+"Tonight we're going to party like it's a certain year"
+ # 1 Jan 2001.
+ dotest rcs2-3 "${testcvs} -q update -p -D '2001-01-01 11:30 UT' file1" \
+"two year hiatus"
+ # 29 Feb 2000
+ dotest rcs2-4 "${testcvs} -q update -p -D '2000-02-29 11:30 UT' file1" \
+"2000 is also a good year for leaping"
+ # 29 Feb 2003 is invalid
+ dotest_fail rcs2-5 "${testcvs} -q update -p -D '2003-02-29 11:30 UT' file1" \
+"$CPROG \[update aborted\]: Can't parse date/time: \`2003-02-29 11:30 UT'"
+
+ dotest rcs2-6 "${testcvs} -q update -p -D 2007-01-07 file1" \
+"head revision"
+ # This assumes that the clock of the machine running the tests
+ # is set to at least the year 1998 or so. There don't seem
+ # to be a lot of ways to test the relative date code (short
+ # of something like LD_LIBRARY_PRELOAD'ing in our own
+ # getttimeofday, or hacking the CVS source with testing
+ # features, which always seems to be problematic since then
+ # someone feels like documenting them and things go downhill
+ # from there).
+ #
+ # These tests can be expected to fail 3 times every 400 years
+ # starting Feb. 29, 2096 (because 8 years from that date would
+ # be Feb. 29, 2100, which is an invalid date -- 2100 isn't a
+ # leap year because it's divisible by 100 but not by 400).
+
+ dotest rcs2-7 "${testcvs} -q update -p -D '96 months' file1" \
+"head revision"
+ dotest rcs2-8 "${testcvs} -q update -p -D '8 years' file1" \
+"head revision"
+
+ dokeep
+ cd ..
+ rm -r first-dir
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ rcs3)
+ # More RCS file tests, in particular at least some of the
+ # error handling issues.
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+ cat <<EOF >$TESTDIR/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc@@1.1log@@text@head@
+EOF
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/first-dir/file1,v
+ mkdir 1; cd 1
+ # CVS requires whitespace between "desc" and its value.
+ # The rcsfile(5) manpage doesn't really seem to answer the
+ # question one way or the other (it has a grammar but almost
+ # nothing about lexical analysis).
+ dotest_fail rcs3-1 "${testcvs} -q co first-dir" \
+"${SPROG} \[checkout aborted\]: EOF while looking for value in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v"
+ cat <<EOF >$TESTDIR/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc @@1.1log@@text@head@
+EOF
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/first-dir/file1,v
+ # Whitespace issues, likewise.
+ dotest_fail rcs3-2 "${testcvs} -q co first-dir" \
+"${SPROG} \[checkout aborted\]: unexpected '.x6c' reading revision number in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v"
+ cat <<EOF >$TESTDIR/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc @@1.1 log@@text@head@
+EOF
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/first-dir/file1,v
+ # Charming array of different messages for similar
+ # whitespace issues (depending on where the whitespace is).
+ dotest_fail rcs3-3 "${testcvs} -q co first-dir" \
+"${SPROG} \[checkout aborted\]: EOF while looking for value in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v"
+ cat <<EOF >$TESTDIR/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc @@1.1 log @@text @head@
+EOF
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/first-dir/file1,v
+ dotest rcs3-4 "${testcvs} -q co first-dir" 'U first-dir/file1'
+
+ # Ouch, didn't expect this one. FIXCVS. Or maybe just remove
+ # the feature, if this is a -s problem?
+ dotest_fail rcs3-5 "${testcvs} log -s nostate first-dir/file1" \
+"${DOTSTAR}ssertion.*failed${DOTSTAR}" "${DOTSTAR}failed assertion${DOTSTAR}"
+ cd first-dir
+ dotest_fail rcs3-5a "${testcvs} log -s nostate file1" \
+"${DOTSTAR}ssertion.*failed${DOTSTAR}" "${DOTSTAR}failed assertion${DOTSTAR}"
+ cd ..
+
+ # See remote code above for rationale for cd.
+ cd first-dir
+ dotest rcs3-6 "${testcvs} log -R file1" \
+"${CVSROOT_DIRNAME}/first-dir/file1,v"
+
+ # OK, now put an extraneous '\0' at the end.
+ mv $CVSROOT_DIRNAME/first-dir/file1,v $TESTDIR/file1,v
+ ${AWK} </dev/null 'BEGIN { printf "@%c", 10 }' | ${TR} '@' '\000' \
+ >>$TESTDIR/file1,v
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/first-dir/file1,v
+ dotest_fail rcs3-7 "${testcvs} log -s nostate file1" \
+"${SPROG} \[log aborted\]: unexpected '.x0' reading revision number in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ rcs4)
+ # Fix a bug that shows up when checking out files by date with the
+ # "-D date" command line option. There is code in the original to
+ # handle a special case. If the date search finds revision 1.1 it
+ # is supposed to check whether revision 1.1.1.1 has the same date
+ # stamp, which would indicate that the file was originally brought
+ # in with "cvs import". In that case it is supposed to return the
+ # vendor branch version 1.1.1.1.
+ #
+ # However, there is a bug in the code. It actually compares
+ # the date of revision 1.1 for equality with the date given
+ # on the command line -- clearly wrong. This commit fixes
+ # the coding bug.
+ #
+ # There is an additional bug which is _not_ fixed yet.
+ # The date comparison should not be a strict
+ # equality test. It should allow a fudge factor of, say, 2-3
+ # seconds. Old versions of CVS created the two revisions
+ # with two separate invocations of the RCS "ci" command. We
+ # have many old files in the tree in which the dates of
+ # revisions 1.1 and 1.1.1.1 differ by 1 second.
+
+ # Need a predictable time zone.
+ save_TZ=$TZ
+ TZ=UTC0; export TZ
+
+ mkdir rcs4
+ cd rcs4
+
+ mkdir imp-dir
+ cd imp-dir
+ echo 'OpenMunger sources' >file1
+
+ # choose a time in the past to demonstrate the problem
+ touch -t 200012010123 file1
+
+ dotest_sort rcs4-1 \
+"${testcvs} import -d -m add rcs4-dir openmunger openmunger-1_0" \
+'
+
+N rcs4-dir/file1
+No conflicts created by this import'
+ echo 'OpenMunger sources release 1.1 extras' >>file1
+ touch -t 200112011234 file1
+ dotest_sort rcs4-2 \
+"${testcvs} import -d -m add rcs4-dir openmunger openmunger-1_1" \
+'
+
+No conflicts created by this import
+U rcs4-dir/file1'
+ cd ..
+ # Next checkout the new module
+ dotest rcs4-3 \
+"${testcvs} -q co rcs4-dir" \
+'U rcs4-dir/file1'
+ cd rcs4-dir
+ echo 'local change' >> file1
+
+ # commit a local change
+ dotest rcs4-4 "${testcvs} -q commit -m hack file1" \
+"$CVSROOT_DIRNAME/rcs4-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ # now see if we get version 1.1 or 1.1.1.1 when we ask for
+ # a checkout by time... it really should be 1.1.1.1 as
+ # that was indeed the version that was visible at the target
+ # time.
+ dotest rcs4-5 \
+"${testcvs} -q update -D 'October 1, 2001 UTC' file1" \
+'[UP] file1'
+ dotest rcs4-6 \
+"${testcvs} -q status file1" \
+'===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1\.1\.1.*
+ Repository revision: 1\.1\.1\.1 '${CVSROOT_DIRNAME}'/rcs4-dir/file1,v
+ Commit Identifier: '${commitid}'
+ Sticky Tag: (none)
+ Sticky Date: 2001\.10\.01\.00\.00\.00
+ Sticky Options: (none)'
+
+ dokeep
+ TZ=$save_TZ
+ cd ../..
+ rm -r rcs4
+ modify_repo rm -rf $CVSROOT_DIRNAME/rcs4-dir
+ ;;
+
+
+
+ rcs5)
+ # Some tests of the $Log keyword and log message without a trailing
+ # EOL. This used to look ugly and, in the worst case, could cause
+ # a seg fault due to a buffer overflow.
+ #
+ # Note that it should not be possible to create this situation via a
+ # CVS server (and any client), since the server itself inserts the
+ # trailing EOL onto log messages that are missing one. Still, we
+ # shouldn't segfault due to a corrupt RCS file and I think that a log
+ # message without the trailing EOL doesn't actually violate the RCS
+ # spec, though it doesn't appear to be possible to create such a log
+ # message using RCS 5.7.
+
+ modify_repo mkdir $CVSROOT_DIRNAME/rcs5
+ cat <<\EOF >$TESTDIR/file1,v
+head 1.1;
+access;
+symbols;
+locks;
+expand kv;
+
+1.1 date 2007.03.20.04.03.02; author jeremiah; state Ext; branches; next;
+
+desc
+@@
+
+1.1
+log
+@he always had very fine wine@
+text
+@line1
+/*
+EOF
+echo ' * History: $''Log$' >>$TESTDIR/file1,v
+ cat <<\EOF >>$TESTDIR/file1,v
+ */
+line5
+@
+EOF
+ modify_repo mv $TESTDIR/file1,v $CVSROOT_DIRNAME/rcs5/file1,v
+
+ mkdir rcs5
+ cd rcs5
+ dotest rcs5-1 "$testcvs -Q co rcs5"
+ dotest rcs5-2 "cat rcs5/file1" \
+"line1
+/\\*
+ \\* History: "'\$'"Log: file1,v "'\$'"
+ \\* History: Revision 1\.1 2007/03/20 04:03:02 jeremiah
+ \\* History: he always had very fine wine
+ \\* History:
+ \\*/
+line5"
+
+ cd ..
+ rm -r rcs5
+ modify_repo rm -rf $CVSROOT_DIRNAME/rcs5
+ ;;
+
+
+
+ lockfiles)
+ # Tests of CVS lock files.
+ # TODO-maybe: Add a test where we arrange for a loginfo
+ # script (or some such) to ensure that locks are in place
+ # so then we can see how they are behaving.
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ mkdir 1; cd 1
+ mkdir sdir
+ mkdir sdir/ssdir
+ echo file >sdir/ssdir/file1
+ dotest lockfiles-1 \
+"${testcvs} -Q import -m import-it first-dir bar baz" ""
+ cd ..
+
+ mkdir 2; cd 2
+ dotest lockfiles-2 "${testcvs} -q co first-dir" \
+"U first-dir/sdir/ssdir/file1"
+ dotest lockfiles-3 "${testcvs} -Q co CVSROOT" ""
+ cd CVSROOT
+ echo "LockDir=${TESTDIR}/locks" >>config
+ dotest lockfiles-4 "${testcvs} -q ci -m config-it" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cd ../first-dir/sdir/ssdir
+ # The error message appears twice because Lock_Cleanup only
+ # stops recursing after the first attempt.
+ dotest_fail lockfiles-5 "${testcvs} -q update" \
+"${SPROG} \[update aborted\]: cannot stat ${TESTDIR}/locks: No such file or directory"
+ mkdir ${TESTDIR}/locks
+ # Grumble, mumble. Cygwin.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod u=rwx,g=r,o= ${TESTDIR}/locks"
+ else
+ chmod u=rwx,g=r,o= ${TESTDIR}/locks
+ fi
+ save_umask=`umask`
+ umask 0077
+ CVSUMASK=0077; export CVSUMASK
+ dotest lockfiles-6 "${testcvs} -q update" ""
+ # TODO: should also be testing that CVS continues to honor the
+ # umask and CVSUMASK normally. In the case of the umask, CVS
+ # doesn't seem to use it for much (although it perhaps should).
+ dotest lockfiles-7 "ls ${TESTDIR}/locks/first-dir/sdir/ssdir" ""
+
+ # The policy is that when CVS creates new lock directories, they
+ # inherit the permissions from the parent directory. CVSUMASK
+ # isn't right, because typically the reason for LockDir is to
+ # use a different set of permissions.
+ #
+ # Bah! Cygwin!
+ if test -n "$remotehost"; then
+ dotest lockfiles-7a "$CVS_RSH $remotehost 'ls -ld ${TESTDIR}/locks/first-dir'" \
+"drwxr-----.*first-dir"
+ dotest lockfiles-7b "$CVS_RSH $remotehost 'ls -ld ${TESTDIR}/locks/first-dir/sdir/ssdir'" \
+"drwxr-----.*first-dir/sdir/ssdir"
+ else
+ dotest lockfiles-7a "ls -ld ${TESTDIR}/locks/first-dir" \
+"drwxr-----.*first-dir"
+ dotest lockfiles-7b "ls -ld ${TESTDIR}/locks/first-dir/sdir/ssdir" \
+"drwxr-----.*first-dir/sdir/ssdir"
+ fi
+
+ cd ../../..
+ dotest lockfiles-8 "${testcvs} -q update" ""
+ dotest lockfiles-9 "${testcvs} -q co -l ." ""
+
+ ###
+ ### There are race conditions in the following tests, but hopefully
+ ### the 5 seconds the first process waits to remove the lockdir and
+ ### the 30 seconds CVS waits betweens checks will be significant
+ ### enough to render the case moot.
+ ###
+ # Considers the following cases:
+ #
+ # Lock Present
+ # Operation Allowed (case #)
+ #
+ # Read Promotable Write
+ # _______ __________ ______
+ # Read |Yes (1) Yes (2) No (3)
+ # Promotable Read |Yes (4) No (5) No (6)
+ # Write |No (7) No (8) No (9)
+ #
+ # Tests do not appear in same ordering as table:
+ # 1. Read when read locks are present...
+ # 2. Read when promotable locks are present...
+ # 3. Don't read when write locks present...
+ # 4. Read but don't write when read locks are present... (fail
+ # commit up-to-date check with promotable lock present).
+ # 5. Don't allow promotable read when promotable locks are present...
+ # (fail to perform commit up-to-date check with promotable lock
+ # present).
+ # 6. Don't allow promotable read when write locks are present...
+ # (fail to perform commit up-to-date check with promotable lock
+ # present).
+ # 7. Don't write when read locks are present...
+ # 8. Don't write when promotable locks are present...
+ # 9. Don't write when write locks are present...
+
+ # 3. Don't read when write locks present...
+ mkdir "$TESTDIR/locks/first-dir/#cvs.lock"
+ (sleep 5; rmdir "$TESTDIR/locks/first-dir/#cvs.lock")&
+ dotest lockfiles-10 "$testcvs -q co -l first-dir" \
+"$SPROG checkout: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir
+$SPROG checkout: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir"
+
+ # 1. Read when read locks are present...
+ touch "$TESTDIR/locks/first-dir/#cvs.rfl.test.lock"
+ dotest lockfiles-11 "$testcvs -q co -l first-dir"
+ rm "$TESTDIR/locks/first-dir/#cvs.rfl.test.lock"
+
+ # 2. Read when promotable locks are present...
+ cd ..
+ mkdir 3; cd 3
+ touch "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.pfl.test.lock"
+ dotest lockfiles-12 "$testcvs -q co first-dir" \
+"U first-dir/sdir/ssdir/file1"
+ rm "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.pfl.test.lock"
+
+ # 7. Don't write when read locks are present...
+ echo I always have trouble coming up with witty text for the test files >>first-dir/sdir/ssdir/file1
+ touch "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.rfl.test.lock"
+ (sleep 5; rm "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.rfl.test.lock")&
+ dotest lockfiles-13 "$testcvs -q ci -mconflict first-dir" \
+"$SPROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$SPROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v <-- first-dir/sdir/ssdir/file1
+new revision: 1\.2; previous revision: 1\.1"
+
+ # 4. Read but don't write when read locks are present... (fail
+ # commit up-to-date check with promotable lock present).
+ cd ../2
+ echo something that would render readers all full of smiles >>first-dir/sdir/ssdir/file1
+ touch "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.rfl.test.lock"
+ dotest_fail lockfiles-14 "$testcvs -q ci -mnot-up-to-date first-dir" \
+"$SPROG commit: Up-to-date check failed for \`first-dir/sdir/ssdir/file1'
+$SPROG \[commit aborted\]: correct above errors first!"
+ rm "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.rfl.test.lock"
+
+ # 5. Don't allow promotable read when promotable locks are present...
+ # (fail to perform commit up-to-date check with promotable lock
+ # present).
+ touch "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.pfl.test.lock"
+ (sleep 5; rm "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.pfl.test.lock")&
+ dotest_fail lockfiles-15 "$testcvs -q ci -mnot-up-to-date first-dir" \
+"$SPROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$SPROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$SPROG commit: Up-to-date check failed for \`first-dir/sdir/ssdir/file1'
+$SPROG \[commit aborted\]: correct above errors first!"
+
+ # 6. Don't allow promotable read when write locks are present...
+ # (fail to perform commit up-to-date check with promotable lock
+ # present).
+ mkdir "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.lock"
+ (sleep 5; rmdir "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.lock")&
+ dotest_fail lockfiles-16 "$testcvs -q ci -mnot-up-to-date first-dir" \
+"$SPROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$SPROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$SPROG commit: Up-to-date check failed for \`first-dir/sdir/ssdir/file1'
+$SPROG \[commit aborted\]: correct above errors first!"
+
+ # 8. Don't write when promotable locks are present...
+ dotest lockfiles-17 "$testcvs -Q up -C first-dir/sdir/ssdir"
+ echo the kinds of smiles that light faces for miles >>first-dir/sdir/ssdir/file1
+ touch "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.pfl.test.lock"
+ (sleep 5; rm "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.pfl.test.lock")&
+ dotest lockfiles-18 "$testcvs -q ci -mnot-up-to-date first-dir" \
+"$SPROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$SPROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v <-- first-dir/sdir/ssdir/file1
+new revision: 1\.3; previous revision: 1\.2"
+
+ # 9. Don't write when write locks are present...
+ echo yet this poem would probably only give longfellow bile >>first-dir/sdir/ssdir/file1
+ mkdir "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.lock"
+ (sleep 5; rmdir "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.lock")&
+ dotest lockfiles-19 "$testcvs -q ci -mnot-up-to-date first-dir" \
+"$SPROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$SPROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir
+$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v <-- first-dir/sdir/ssdir/file1
+new revision: 1\.4; previous revision: 1\.3"
+
+ # 10. Don't write when history locks are present...
+ echo have you ever heard a poem quite so vile\? >>first-dir/sdir/ssdir/file1
+ mkdir "$TESTDIR/locks/CVSROOT/#cvs.history.lock"
+ (sleep 5; rmdir "$TESTDIR/locks/CVSROOT/#cvs.history.lock")&
+ dotest lockfiles-20 "$testcvs -q ci -mnot-up-to-date first-dir" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v <-- first-dir/sdir/ssdir/file1
+new revision: 1\.5; previous revision: 1\.4
+$SPROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/CVSROOT
+$SPROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/CVSROOT"
+
+ dotest lockfiles-21 "$testcvs -Q tag newtag first-dir"
+
+ rm $CVSROOT_DIRNAME/CVSROOT/val-tags
+ mkdir "$TESTDIR/locks/CVSROOT/#cvs.val-tags.lock"
+ (sleep 5; rmdir "$TESTDIR/locks/CVSROOT/#cvs.val-tags.lock")&
+ dotest lockfiles-22 "$testcvs -q up -r newtag first-dir" \
+"$SPROG update: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/CVSROOT
+$SPROG update: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/CVSROOT"
+
+ cd CVSROOT
+ dotest lockfiles-cleanup-1 "$testcvs -q up -pr1.1 config >config" ""
+ dotest lockfiles-cleanup-2 "$testcvs -q ci -m config-it" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ dokeep
+ cd ../..
+ # Restore umask.
+ umask $save_umask
+ unset CVSUMASK
+ rm -r $TESTDIR/locks
+ rm -r 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ backuprecover)
+ # Tests to make sure we get the expected behavior
+ # when we recover a repository from an old backup
+ #
+ # Details:
+ # Backup will be older than some developer's workspaces
+ # This means the first attempt at an update will fail
+ # The workaround for this is to replace the CVS
+ # directories with those from a "new" checkout from
+ # the recovered repository. Due to this, multiple
+ # merges should cause conflicts (the same data
+ # will be merged more than once).
+ # A workspace updated before the date of the recovered
+ # copy will not need any extra attention
+ #
+ # Note that backuprecover-15 is probably a failure case
+ # If nobody else had a more recent update, the data would be lost
+ # permanently
+ # Granted, the developer should have been notified not to do this
+ # by now, but still...
+ #
+ mkdir backuprecover; cd backuprecover
+ mkdir 1; cd 1
+ dotest backuprecover-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest backuprecover-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ mkdir dir
+ dotest backuprecover-3 "${testcvs} add dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir added to the repository"
+ touch file1 dir/file2
+ dotest backuprecover-4 "${testcvs} -q add file1 dir/file2" \
+"${SPROG} add: use \`${SPROG} commit' to add these files permanently"
+ dotest backuprecover-5 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+initial revision: 1\.1"
+ echo "Line one" >>file1
+ echo " is the place" >>file1
+ echo " we like to begin" >>file1
+ echo "Anything else" >>file1
+ echo " looks like" >>file1
+ echo " a sin" >>file1
+ echo "File 2" >>dir/file2
+ echo " is the place" >>dir/file2
+ echo " the rest of it goes" >>dir/file2
+ echo "Why I don't use" >>dir/file2
+ echo " something like 'foo'" >>dir/file2
+ echo " God only knows" >>dir/file2
+ dotest backuprecover-6 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Simulate the lazy developer
+ # (he did some work but didn't check it in...)
+ cd ../..
+ mkdir 2; cd 2
+ dotest backuprecover-7 "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ sed -e "s/looks like/just looks like/" file1 >tmp; mv tmp file1
+ sed -e "s/don't use/don't just use/" dir/file2 >tmp; mv tmp dir/file2
+
+ # developer 1 is on a roll
+ cd ../../1/first-dir
+ echo "I need some more words" >>file1
+ echo " to fill up this space" >>file1
+ echo " anything else would be a disgrace" >>file1
+ echo "My rhymes cross many boundries" >>dir/file2
+ echo " this time it's files" >>dir/file2
+ echo " a word that fits here would be something like dials" >>dir/file2
+ dotest backuprecover-8 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+new revision: 1\.3; previous revision: 1\.2"
+
+ # Save a backup copy
+ cp -R $CVSROOT_DIRNAME/first-dir $TESTDIR/backup
+
+ # Simulate developer 3
+ cd ../..
+ mkdir 3; cd 3
+ dotest backuprecover-9a "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ echo >>file1
+ echo >>dir/file2
+ echo "Developer 1 makes very lame rhymes" >>file1
+ echo " I think he should quit and become a mime" >>file1
+ echo "What the %*^# kind of rhyme crosses a boundry?" >>dir/file2
+ echo " I think you should quit and get a job in the foundry" >>dir/file2
+ dotest backuprecover-9b "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3
+$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+new revision: 1\.4; previous revision: 1\.3"
+
+ # Developer 4 so we can simulate a conflict later...
+ cd ../..
+ mkdir 4; cd 4
+ dotest backuprecover-10 "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ sed -e "s/quit and/be fired so he can/" dir/file2 >tmp; mv tmp dir/file2
+
+ # And back to developer 1
+ cd ../../1/first-dir
+ dotest backuprecover-11 "${testcvs} -Q update" ''
+ echo >>file1
+ echo >>dir/file2
+ echo "Oh yeah, well rhyme this" >>file1
+ echo " developer three" >>file1
+ echo " you want opposition" >>file1
+ echo " you found some in me!" >>file1
+ echo "I'll give you mimes" >>dir/file2
+ echo " and foundries galore!" >>dir/file2
+ echo " your head will spin" >>dir/file2
+ echo " once you find what's in store!" >>dir/file2
+ dotest backuprecover-12 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4
+$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+new revision: 1\.5; previous revision: 1\.4"
+
+ # developer 3'll do a bit of work that never gets checked in
+ cd ../../3/first-dir
+ dotest backuprecover-13 "${testcvs} -Q update" ''
+ sed -e "s/very/some extremely/" file1 >tmp; mv tmp file1
+ dotest backuprecover-14 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.6; previous revision: 1\.5"
+ echo >>file1
+ echo "Tee hee hee hee" >>file1
+ echo >>dir/file2
+ echo "Find what's in store?" >>dir/file2
+ echo " Oh, I'm so sure!" >>dir/file2
+ echo " You've got an ill, and I have the cure!" >>dir/file2
+
+ # Slag the original and restore it a few revisions back
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ modify_repo mv $TESTDIR/backup $CVSROOT_DIRNAME/first-dir
+
+ # Have developer 1 try an update and lose some data
+ #
+ # Feel free to imagine the horrific scream of despair
+ cd ../../1/first-dir
+ dotest backuprecover-15 "${testcvs} update" \
+"${SPROG} update: Updating .
+U file1
+${SPROG} update: Updating dir
+U dir/file2"
+
+ # Developer 3 tries the same thing (he has an office)
+ # but fails without losing data since all of his files have
+ # uncommitted changes
+ cd ../../3/first-dir
+ dotest_fail backuprecover-16 "${testcvs} update" \
+"${SPROG} update: Updating \.
+${SPROG} \[update aborted\]: could not find desired version 1\.6 in ${CVSROOT_DIRNAME}/first-dir/file1,v"
+
+ # create our workspace fixin' script
+ cd ../..
+ echo \
+"#!$TESTSHELL
+
+# This script will copy the CVS database dirs from the checked out
+# version of a newly recovered repository and replace the CVS
+# database dirs in a workspace with later revisions than those in the
+# recovered repository
+cd repos-first-dir
+DATADIRS=\`find . -name CVS -print\`
+cd ../first-dir
+find . -name CVS -print | xargs rm -rf
+for file in \${DATADIRS}; do
+ cp -R ../repos-first-dir/\${file} \${file}
+done" >fixit
+
+ # We only need to fix the workspaces of developers 3 and 4
+ # (1 lost all her data and 2 has an update date from
+ # before the date the backup was made)
+ cd 3
+ dotest backuprecover-17 \
+ "${testcvs} -Q co -d repos-first-dir first-dir" ''
+ cd ../4
+ dotest backuprecover-18 \
+ "${testcvs} -Q co -d repos-first-dir first-dir" ''
+ sh ../fixit
+ cd ../3; sh ../fixit
+
+ # (re)commit developer 3's stuff
+ cd first-dir
+ dotest backuprecover-19 "${testcvs} -q ci -mrecover/merge" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3
+$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+new revision: 1\.4; previous revision: 1\.3"
+
+ # and we should get a conflict on developer 4's stuff
+ cd ../../4/first-dir
+ dotest backuprecover-20 "${testcvs} update" \
+"${SPROG} update: Updating \.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.3
+retrieving revision 1\.4
+Merging differences between 1\.3 and 1\.4 into file1
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in file1
+C file1
+${SPROG} update: Updating dir
+RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/file2,v
+retrieving revision 1\.3
+retrieving revision 1\.4
+Merging differences between 1\.3 and 1\.4 into file2
+rcsmerge: warning: conflicts during merge
+${SPROG} update: conflicts found in dir/file2
+C dir/file2"
+ sed -e \
+"/^<<<<<<</,/^=======/d
+/^>>>>>>>/d" file1 >tmp; mv tmp file1
+ sed -e \
+"/^<<<<<<</,/^=======/d
+/^>>>>>>>/d
+s/quit and/be fired so he can/" dir/file2 >tmp; mv tmp dir/file2
+ dotest backuprecover-21 "${testcvs} -q ci -mrecover/merge" \
+"$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+new revision: 1\.5; previous revision: 1\.4"
+
+ # go back and commit developer 2's stuff to prove it can still be done
+ cd ../../2/first-dir
+ dotest backuprecover-22 "${testcvs} -Q update" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.2
+retrieving revision 1\.4
+Merging differences between 1\.2 and 1\.4 into file1
+RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/file2,v
+retrieving revision 1\.2
+retrieving revision 1\.5
+Merging differences between 1\.2 and 1\.5 into file2"
+ dotest backuprecover-23 "${testcvs} -q ci -mtest" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4
+$CVSROOT_DIRNAME/first-dir/dir/file2,v <-- dir/file2
+new revision: 1\.6; previous revision: 1\.5"
+
+ # and restore the data to developer 1
+ cd ../../1/first-dir
+ dotest backuprecover-24 "${testcvs} -Q update" ''
+
+ dokeep
+ cd ../../..
+ rm -r backuprecover
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ sshstdio)
+ # CVS_RSH=ssh can have a problem with a non-blocking stdio
+ # in some cases. So, this test is all about testing :ext:
+ # with CVS_RSH=ssh. The problem is that not all machines
+ # will necessarily have ssh available, so be prepared to
+ # skip this test.
+
+ if $proxy; then
+ notproxy sshstdio
+ continue
+ fi
+
+ if $remote; then :; else
+ remoteonly sshstdio
+ continue
+ fi
+
+ require_ssh
+ if test $? -eq 77; then
+ skip sshstdio "$skipreason"
+ continue
+ fi
+
+ SSHSTDIO_ROOT=:ext:$host$CVSROOT_DIRNAME
+
+ mkdir sshstdio; cd sshstdio
+ dotest sshstdio-1 "$testcvs -d $SSHSTDIO_ROOT -q co -l ."
+ mkdir first-dir
+ dotest sshstdio-2 "$testcvs add first-dir" \
+ "Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+ cd first-dir
+ a='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ c='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ # Generate 1024 lines of $a
+ cnt=0
+ echo $a > aaa
+ while [ $cnt -lt 5 ] ; do
+ cnt=`expr $cnt + 1` ;
+ mv aaa aaa.old
+ cat aaa.old aaa.old aaa.old aaa.old > aaa
+ done
+ dotest sshstdio-3 "$testcvs -q add aaa" \
+"$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest sshstdio-4 "$testcvs -q ci -mcreate aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+initial revision: 1\.1"
+ # replace lines 1, 512, 513, 1024 with $c
+ sed 510q < aaa > aaa.old
+ (echo $c; cat aaa.old; echo $c; \
+ echo $c; cat aaa.old; echo $c) > aaa
+ dotest sshstdio-5 "$testcvs -q ci -mmodify-it aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.2; previous revision: 1\.1"
+ cat > wrapper.sh <<EOF
+#!$TESTSHELL
+exec "\$@" 2>&1 < /dev/null | cat
+EOF
+ chmod +x wrapper.sh
+ ./wrapper.sh \
+ $testcvs -z5 -Q diff --side-by-side -W 500 -r 1.1 -r 1.2 \
+ aaa > wrapper.dif
+
+ $testcvs -z5 -Q diff --side-by-side -W 500 -r 1.1 -r 1.2 \
+ aaa > good.dif
+
+ dotest sshstdio-6 "cmp wrapper.dif good.dif"
+
+ dokeep
+ cd ../..
+ CVS_RSH=$save_CVS_RSH; export CVS_RSH
+ rm -r sshstdio
+ rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ parseroot2)
+ # Test some :ext: roots for consistancy.
+ if $remote; then :; else
+ remoteonly parseroot2
+ continue
+ fi
+
+ require_rsh "$CVS_RSH"
+ if test $? -eq 77; then
+ skip parseroot2 "$skipreason"
+ continue
+ fi
+
+ # Test checking out and subsequently updating with some different
+ # CVSROOTs.
+
+ # A standard case, hostname:dirname.
+ mkdir parseroot2; cd parseroot2
+ save_CVSROOT=$CVSROOT
+ CVSROOT=$host:$CVSROOT_DIRNAME
+ dotest parseroot2-1 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ dotest parseroot2-2 "$testcvs -Q up"
+ cd ..
+
+ # A degenerate remote case, just the server name and the directory
+ # name, with no :'s to help parsing. It can be mistaken for a
+ # relative directory name.
+ rm -r CVSROOT
+ CVSROOT=$host$CVSROOT_DIRNAME
+ dotest parseroot2-3 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ dotest parseroot2-4 "$testcvs -Q up"
+
+ dokeep
+ cd ../..
+ CVSROOT=$save_CVSROOT
+ rm -r parseroot2
+ ;;
+
+
+
+ parseroot3)
+ # Test some :ext: roots for consistancy.
+ if $remote; then :; else
+ remoteonly parseroot3
+ continue
+ fi
+
+ require_rsh "$CVS_RSH"
+ if test $? -eq 77; then
+ skip parseroot3 "$skipreason"
+ continue
+ fi
+
+ # Test checking out and subsequently updating with some different
+ # CVSROOTs.
+
+ # A standard case, hostname:dirname.
+ mkdir parseroot3; cd parseroot3
+ save_CVSROOT=$CVSROOT
+ save_CVS_RSH=$CVS_RSH
+ save_CVS_SERVER=$CVS_SERVER
+ unset CVS_RSH
+ unset CVS_SERVER
+ CVSROOT=":ext;CVS_RSH=$save_CVS_RSH;CVS_SERVER=$save_CVS_SERVER:$host:$CVSROOT_DIRNAME"
+ dotest parseroot3-1 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ dotest parseroot3-2 "$testcvs -Q up"
+ cd ..
+
+ # Initial checkout.
+ rm -r CVSROOT
+ CVSROOT=":ext;cvs_RSH=$save_CVS_RSH;CVS_Server=$save_CVS_SERVER:$host$CVSROOT_DIRNAME"
+ dotest parseroot3-3 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ dotest parseroot3-4 "$testcvs -Q up"
+ cd ..
+
+ # Checkout bogus values for Redirect
+ rm -r CVSROOT
+ CVSROOT=":ext;Redirect=bogus;CVS_RSH=$save_CVS_RSH;CVS_SERVER=$save_CVS_SERVER:$host$CVSROOT_DIRNAME"
+ dotest parseroot3-5 "$testcvs -Q co CVSROOT" \
+"$SPROG checkout: CVSROOT: unrecognized value \`bogus' for \`Redirect'"
+ cd CVSROOT
+ # FIXCVS: parse_cvsroot is called more often that is
+ # desirable.
+ dotest parseroot3-6 "$testcvs -Q up" \
+"$SPROG update: CVSROOT: unrecognized value \`bogus' for \`Redirect'"
+ cd ..
+
+ # Checkout good values for Redirect
+ rm -r CVSROOT
+ CVSROOT=":EXT;Redirect=no;CVS_RSH=$save_CVS_RSH;CVS_SERVER=$save_CVS_SERVER:$host$CVSROOT_DIRNAME"
+ dotest parseroot3-7 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ dotest parseroot3-8 "$testcvs -Q up"
+ cd ..
+
+ dotest parseroot3-9 "$testcvs -Q co -ldtop ."
+ dotest parseroot3-10 "test -d top"
+ dotest parseroot3-11 "test -d top/CVS"
+ dotest parseroot3-10 "cat top/CVS/Root" "$CVSROOT"
+
+ dokeep
+ cd ..
+ CVSROOT=$save_CVSROOT
+ CVS_RSH=$save_CVS_RSH
+ CVS_SERVER=$save_CVS_SERVER
+ export CVS_RSH CVS_SERVER
+ rm -r parseroot3
+ ;;
+
+
+
+ history)
+ # CVSROOT/history tests:
+ # history: various "cvs history" invocations
+ # basic2: Generating the CVSROOT/history file via CVS commands.
+
+ # Put in some data for the history file (discarding what was
+ # there before). Note that this file format is fixed; the
+ # user may wish to analyze data from a previous version of
+ # CVS. If we phase out this format, it should be done
+ # slowly and carefully.
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ cat <<EOF >$CVSROOT_DIRNAME/CVSROOT/history
+O3395c677|anonymous|<remote>/*0|ccvs||ccvs
+O3396c677|anonymous|<remote>/src|ccvs||src
+O3397c677|kingdon|<remote>/*0|ccvs||ccvs
+M339cafae|nk|<remote>|ccvs/src|1.229|sanity.sh
+M339cafff|anonymous|<remote>|ccvs/src|1.23|Makefile
+M339dc339|kingdon|~/work/*0|ccvs/src|1.231|sanity.sh
+W33a6eada|anonymous|<remote>*4|ccvs/emx||Makefile.in
+C3b235f50|kingdon|<remote>|ccvs/emx|1.3|README
+M3b23af50|kingdon|~/work/*0|ccvs/doc|1.281|cvs.texinfo
+EOF
+
+ dotest history-1 "${testcvs} history -e -a" \
+"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= <remote>/\*
+O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= <remote>/\*
+M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == <remote>
+W 1997-06-17 19:51 ${PLUS}0000 anonymous Makefile\.in ccvs/emx == <remote>/emx
+O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= <remote>/\*
+M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src
+C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == <remote>
+M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc
+M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>"
+
+ dotest history-2 "${testcvs} history -e -a -D '10 Jun 1997 13:00 UT'" \
+"W 1997-06-17 19:51 ${PLUS}0000 anonymous Makefile\.in ccvs/emx == <remote>/emx
+M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src
+C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == <remote>
+M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc"
+
+ dotest history-3 "${testcvs} history -e -a -D '10 Jun 2001 13:00 UT'" \
+"M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc"
+
+ dotest history-4 "${testcvs} history -ac sanity.sh" \
+"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src
+M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>"
+
+ dotest history-5 "${testcvs} history -a -xCGUWAMR README sanity.sh" \
+"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src
+C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == <remote>
+M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>"
+
+ dotest history-6 "${testcvs} history -xCGUWAMR -a -f README -f sanity.sh" \
+"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src
+C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == <remote>
+M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>"
+
+ dotest history-7 "${testcvs} history -xCGUWAMR -a -f sanity.sh README" \
+"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src
+C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == <remote>
+M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>"
+
+ dotest history-8 "${testcvs} history -ca -D '1970-01-01 00:00 UT'" \
+"M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity.sh ccvs/src == <remote>
+M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == <remote>
+M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity.sh ccvs/src == ~/work/ccvs/src
+M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs.texinfo ccvs/doc == ~/work/ccvs/doc"
+
+ dotest history-9 "${testcvs} history -acl" \
+"M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs.texinfo ccvs/doc == ~/work/ccvs/doc
+M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == <remote>
+M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity.sh ccvs/src == ~/work/ccvs/src"
+
+ dotest history-10 "${testcvs} history -lca -D '1970-01-01 00:00 UT'" \
+"M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs.texinfo ccvs/doc == ~/work/ccvs/doc
+M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == <remote>
+M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity.sh ccvs/src == ~/work/ccvs/src"
+
+ dotest history-11 "${testcvs} history -aw" \
+"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= <remote>/\*
+O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= <remote>/\*
+O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= <remote>/\*"
+
+ dotest history-12 "${testcvs} history -aw -D'1970-01-01 00:00 UT'" \
+"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= <remote>/\*
+O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= <remote>/\*
+O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= <remote>/\*"
+ ;;
+
+
+
+ big)
+
+ # Test ability to operate on big files. Intention is to
+ # test various realloc'ing code in RCS_deltas, rcsgetkey,
+ # etc. "big" is currently defined to be 1000 lines (64000
+ # bytes), which in terms of files that users will use is not
+ # large, merely average, but my reasoning is that this
+ # should be big enough to make sure realloc'ing is going on
+ # and that raising it a lot would start to stress resources
+ # on machines which run the tests, without any significant
+ # benefit.
+
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest big-1 "$testcvs -q co first-dir"
+ cd first-dir
+ for i in 0 1 2 3 4 5 6 7 8 9; do
+ for j in 0 1 2 3 4 5 6 7 8 9; do
+ for k in 0 1 2 3 4 5 6 7 8 9; do
+ echo \
+"This is line ($i,$j,$k) which goes into the file file1 for testing" >>file1
+ done
+ done
+ done
+ dotest big-2 "$testcvs add file1" \
+"$SPROG add: scheduling file .file1. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest big-3 "$testcvs -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ cd ..
+ mkdir 2
+ cd 2
+ dotest big-4 "$testcvs -q get first-dir" "U first-dir/file1"
+ cd ../first-dir
+ echo "add a line to the end" >>file1
+
+ dotest_fail big-4b "$testcvs -q diff -u" \
+"Index: file1
+===================================================================
+RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
+retrieving revision 1\.1
+diff -u -r1\.1 file1
+--- file1 $RFCDATE 1\.1
+$PLUS$PLUS$PLUS file1 $RFCDATE
+@@ -998,3 ${PLUS}998,4 @@
+ This is line (9,9,7) which goes into the file file1 for testing
+ This is line (9,9,8) which goes into the file file1 for testing
+ This is line (9,9,9) which goes into the file file1 for testing
+${PLUS}add a line to the end"
+
+ dotest big-5 "$testcvs -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ cd ../2/first-dir
+ # The idea here is particularly to test the Rcs-diff response
+ # and the reallocing thereof, for remote.
+ dotest big-6 "$testcvs -q update" "[UP] file1"
+
+ dokeep
+ cd ../..
+ rm -r first-dir 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ modes)
+ # Test repository permissions (CVSUMASK and so on).
+ # Although the tests in this section "cheat" by testing
+ # repository permissions, which are sort of not a user-visible
+ # sort of thing, the modes do have user-visible consequences,
+ # such as whether a second user can check out the files. But
+ # it would be awkward to test the consequences, so we don't.
+
+ # Solaris /bin/sh doesn't support export -n. I'm not sure
+ # what we can do about this, other than hope that whoever
+ # is running the tests doesn't have CVSUMASK set.
+ #export -n CVSUMASK # if unset, defaults to 002
+
+ save_umask=`umask`
+ umask 077
+ mkdir 1; cd 1
+ dotest modes-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest modes-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch aa
+ dotest modes-3 "${testcvs} add aa" \
+"${SPROG} add: scheduling file .aa. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest modes-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+initial revision: 1\.1"
+ # Yawn. Cygwin.
+ if test -n "$remotehost"; then
+ dotest modes-5remotehost "$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v'" \
+"-r--r--r-- .*"
+ else
+ dotest modes-5 "ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v" \
+"-r--r--r-- .*"
+ fi
+
+ # Test for whether we can set the execute bit.
+ chmod +x aa
+ echo change it >>aa
+ dotest modes-6 "${testcvs} -q ci -m set-execute-bit" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+new revision: 1\.2; previous revision: 1\.1"
+ # If CVS let us update the execute bit, it would be set here.
+ # But it doesn't, and as far as I know that is longstanding
+ # CVS behavior.
+ #
+ # Yeah, yeah. Search for "Cygwin".
+ if test -n "$remotehost"; then
+ dotest modes-7remotehost "$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v'" \
+"-r--r--r-- .*"
+ else
+ dotest modes-7 "ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v" \
+"-r--r--r-- .*"
+ fi
+
+ # OK, now manually change the modes and see what happens.
+ #
+ # Cygwin, already.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod g=r,o= ${CVSROOT_DIRNAME}/first-dir/aa,v"
+ else
+ chmod g=r,o= ${CVSROOT_DIRNAME}/first-dir/aa,v
+ fi
+ echo second line >>aa
+ dotest modes-7a "${testcvs} -q ci -m set-execute-bit" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+new revision: 1\.3; previous revision: 1\.2"
+ # Cygwin.
+ if test -n "$remotehost"; then
+ dotest modes-7bremotehost "$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v'" \
+"-r--r----- .*"
+ else
+ dotest modes-7b "ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v" \
+"-r--r----- .*"
+ fi
+
+ CVSUMASK=007
+ export CVSUMASK
+ touch ab
+ # Might as well test the execute bit too.
+ chmod +x ab
+ dotest modes-8 "$testcvs add ab" \
+"$SPROG add: scheduling file .ab. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest modes-9 "$testcvs -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/ab,v <-- ab
+initial revision: 1\.1"
+
+ # The ssh-wrapper script set up by this script forwards CVSUMASK to
+ # the server. In practice it would be set on the server in some
+ # other manner (for instance, by the `env' command, or as an option
+ # in the xinted.conf file).
+ #
+ # I don't recall why, but I used to look for:
+ #
+ # dotest modes-10remotehost \
+ # "$CVS_RSH $remotehost 'ls -l $CVSROOT_DIRNAME/first-dir/ab,v'" \
+ # "-r--r--r--.*"
+ #
+ # here when $remotehost was set. I'm not sure why. Maybe this was
+ # one of the innumerable Cygwin issues?
+ dotest modes-10 "ls -l $CVSROOT_DIRNAME/first-dir/ab,v" \
+"-r-xr-x---.*"
+
+ # OK, now add a file on a branch. Check that the mode gets
+ # set the same way (it is a different code path in CVS).
+ dotest modes-11 "${testcvs} -q tag -b br" 'T aa
+T ab'
+ dotest modes-12 "${testcvs} -q update -r br" ''
+ touch ac
+ dotest modes-13 "${testcvs} add ac" \
+"${SPROG} add: scheduling file .ac. for addition on branch .br.
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ # Not sure it really makes sense to refer to a "previous revision"
+ # when we are just now adding the file; as far as I know
+ # that is longstanding CVS behavior, for what it's worth.
+ dotest modes-14 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/Attic/ac,v <-- ac
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # ssh-wrapper forwards CVSUMASK. See modes-10 for notes.
+ dotest modes-15 \
+"ls -l ${CVSROOT_DIRNAME}/first-dir/Attic/ac,v" \
+"-r--r-----.*"
+
+ dokeep
+ cd ../..
+ # Restore umask.
+ umask $save_umask
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ modes2)
+ # More tests of file permissions in the working directory
+ # and that sort of thing.
+
+ # The usual setup, file first-dir/aa with two revisions.
+ mkdir 1; cd 1
+ dotest modes2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest modes2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch aa
+ dotest modes2-3 "${testcvs} add aa" \
+"${SPROG} add: scheduling file .aa. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest modes2-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+initial revision: 1\.1"
+ echo "more money" >> aa
+ dotest modes2-5 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+new revision: 1\.2; previous revision: 1\.1"
+
+ # OK, here is the test. The idea is to see what
+ # No_Difference does if it can't open the file.
+ # If we don't change the st_mtime, CVS doesn't even try to read
+ # the file. Note that some versions of "touch" require that we
+ # do this while the file is still writable.
+ touch aa
+ chmod a= aa
+ # Don't try this when permissions are broken, as with Cygwin.
+ if ${LS} ${CVSROOT_DIRNAME}/first-dir >/dev/null 2>&1; then :; else
+ dotest_fail modes2-6 "${testcvs} -q update -r 1.1 aa" \
+"${CPROG} \[update aborted\]: cannot open file aa for comparing: Permission denied" \
+"${CPROG} \[update aborted\]: reading aa: Permission denied"
+ fi
+
+ dokeep
+ chmod u+rwx aa
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ modes3)
+ # Repository permissions. Particularly, what happens if we
+ # can't read/write in the repository.
+ # TODO: the case where we can access the repository, just not
+ # the attic (may that one can remain a fatal error, seems less
+ # useful for access control).
+ mkdir 1; cd 1
+ dotest modes3-1 "$testcvs -q co -l ."
+ mkdir first-dir second-dir
+ dotest modes3-2 "${testcvs} add first-dir second-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository
+Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
+ touch first-dir/aa second-dir/ab
+ dotest modes3-3 "${testcvs} add first-dir/aa second-dir/ab" \
+"${SPROG} add: scheduling file .first-dir/aa. for addition
+${SPROG} add: scheduling file .second-dir/ab. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest modes3-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- first-dir/aa
+initial revision: 1\.1
+$CVSROOT_DIRNAME/second-dir/ab,v <-- second-dir/ab
+initial revision: 1\.1"
+ # quiet down this one as it will be noisy in proxy mode
+ modify_repo chmod a= $CVSROOT_DIRNAME/first-dir >/dev/null 2>&1
+ if ${LS} ${CVSROOT_DIRNAME}/first-dir >/dev/null 2>&1; then
+ # Avoid this test under Cygwin since permissions work differently
+ # there.
+ #
+ # This test also gets avoided under Mac OS X since the system `ls'
+ # is broken and exits with a 0 status despite the permission
+ # denied error.
+ if test -n "$remotehost"; then
+ cygwin_hack=false
+ else
+ cygwin_hack=:
+ fi
+ else
+ cygwin_hack=false
+ fi
+
+ cd $TESTDIR/1
+ if $cygwin_hack; then :; else
+ dotest modes3-5 "${testcvs} update" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating first-dir
+${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/first-dir: Permission denied
+${SPROG} update: skipping directory first-dir
+${SPROG} update: Updating second-dir"
+ fi
+
+ # OK, I can see why one might say the above case could be a
+ # fatal error, because normally users without access to first-dir
+ # won't have it in their working directory. But the next
+ # one is more of a problem if it is fatal.
+ #
+ # The second text string below is for Cygwin again, and again it
+ # should really be XFAIL under Cygwin, but for now deal with the
+ # passing opendir by accepting the alternate string.
+ rm -r first-dir
+ dotest modes3-6 "${testcvs} update -dP" \
+"${SPROG} update: Updating .
+${SPROG} update: Updating CVSROOT
+U ${DOTSTAR}
+${SPROG} update: Updating first-dir
+${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/first-dir: Permission denied
+${SPROG} update: skipping directory first-dir
+${SPROG} update: Updating second-dir" \
+"${SPROG} update: Updating .
+${SPROG} update: Updating CVSROOT
+U ${DOTSTAR}
+${SPROG} update: Updating first-dir
+${SPROG} update: Updating second-dir"
+
+ dokeep
+ cd ..
+ rm -r 1
+ # quiet down this one as it will be noisy in proxy mode
+ modify_repo chmod u+rwx $CVSROOT_DIRNAME/first-dir 2>/dev/null
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
+ $CVSROOT_DIRNAME/second-dir
+ ;;
+
+
+
+ stamps)
+ # Test timestamps.
+ mkdir 1; cd 1
+ dotest stamps-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest stamps-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch aa
+ echo '$''Id$' >kw
+ # Cygwin, *cough*, puts the year in the time column until the minute
+ # is no longer the current minute. Sleep 60 seconds to avoid this
+ # problem.
+ sleep 60
+ ls -l aa >${TESTDIR}/1/stamp.aa.touch
+ ls -l kw >${TESTDIR}/1/stamp.kw.touch
+ # "sleep 1" would suffice if we could assume ls --full-time, but
+ # that is as far as I know unique to GNU ls. Is there some POSIX.2
+ # way to get the timestamp of a file, including the seconds?
+ sleep 60
+ dotest stamps-3 "${testcvs} add aa kw" \
+"${SPROG} add: scheduling file .aa. for addition
+${SPROG} add: scheduling file .kw. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ ls -l aa >${TESTDIR}/1/stamp.aa.add
+ ls -l kw >${TESTDIR}/1/stamp.kw.add
+ # "cvs add" should not muck with the timestamp.
+ dotest stamps-4aa \
+"cmp ${TESTDIR}/1/stamp.aa.touch ${TESTDIR}/1/stamp.aa.add" ''
+ dotest stamps-4kw \
+"cmp ${TESTDIR}/1/stamp.kw.touch ${TESTDIR}/1/stamp.kw.add" ''
+ sleep 60
+ dotest stamps-5 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/kw,v <-- kw
+initial revision: 1\.1"
+ # Cygwin, *cough*, puts the year in the time column until the minute
+ # is no longer the current minute. Sleep 60 seconds to avoid this
+ # problem.
+ sleep 60
+ ls -l aa >${TESTDIR}/1/stamp.aa.ci
+ ls -l kw >${TESTDIR}/1/stamp.kw.ci
+ # If there are no keywords, "cvs ci" leaves the timestamp alone
+ # If there are, it sets the timestamp to the date of the commit.
+ # I'm not sure how logical this is, but it is intentional.
+ # If we wanted to get fancy we would make sure the time as
+ # reported in "cvs log kw" matched stamp.kw.ci. But that would
+ # be a lot of work.
+ dotest stamps-6aa \
+ "cmp ${TESTDIR}/1/stamp.aa.add ${TESTDIR}/1/stamp.aa.ci" ''
+ if cmp ${TESTDIR}/1/stamp.kw.add ${TESTDIR}/1/stamp.kw.ci >/dev/null
+ then
+ fail stamps-6kw
+ else
+ pass stamps-6kw
+ fi
+ cd ../..
+ sleep 60
+ mkdir 2
+ cd 2
+ dotest stamps-7 "${testcvs} -q get first-dir" "U first-dir/aa
+U first-dir/kw"
+ cd first-dir
+ ls -l aa >${TESTDIR}/1/stamp.aa.get
+ ls -l kw >${TESTDIR}/1/stamp.kw.get
+ # On checkout, CVS should set the timestamp to the date that the
+ # file was committed. Could check that the time as reported in
+ # "cvs log aa" matches stamp.aa.get, but that would be a lot of
+ # work.
+ dotest_fail stamps-8aa \
+"cmp $TESTDIR/1/stamp.aa.ci $TESTDIR/1/stamp.aa.get >/dev/null"
+ dotest stamps-8kw \
+"cmp $TESTDIR/1/stamp.kw.ci $TESTDIR/1/stamp.kw.get"
+
+ # Now we want to see what "cvs update" does.
+ sleep 60
+ echo add a line >>aa
+ echo add a line >>kw
+ dotest stamps-9 "${testcvs} -q ci -m change-them" \
+"$CVSROOT_DIRNAME/first-dir/aa,v <-- aa
+new revision: 1\.2; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/kw,v <-- kw
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Cygwin, *cough*, puts the year in the time column until the minute
+ # is no longer the current minute. Sleep 60 seconds to avoid this
+ # problem.
+ sleep 60
+ ls -l aa >${TESTDIR}/1/stamp.aa.ci2
+ ls -l kw >${TESTDIR}/1/stamp.kw.ci2
+ cd ../..
+ cd 1/first-dir
+ sleep 60
+ dotest stamps-10 "${testcvs} -q update" '[UP] aa
+[UP] kw'
+ # this doesn't serve any function other than being able to
+ # look at it manually, as we have no machinery for dates being
+ # newer or older than other dates.
+ date >$TESTDIR/1/stamp.debug.update
+ ls -l aa >$TESTDIR/1/stamp.aa.update
+ ls -l kw >$TESTDIR/1/stamp.kw.update
+ # stamp.aa.update and stamp.kw.update should both be approximately
+ # the same as stamp.debug.update. Perhaps we could be testing
+ # this in a more fancy fashion by "touch stamp.before" before
+ # stamps-10, "touch stamp.after" after, and then using ls -t
+ # to check them. But for now we just make sure that the *.update
+ # stamps differ from the *.ci2 ones.
+ # As for the rationale, this is so that if one updates and gets
+ # a new revision, then "make" will be sure to regard those files
+ # as newer than .o files which may be sitting around.
+ dotest_fail stamps-11aa \
+"cmp $TESTDIR/1/stamp.aa.update $TESTDIR/1/stamp.aa.ci2 >/dev/null"
+ dotest_fail stamps-11kw \
+"cmp $TESTDIR/1/stamp.kw.update $TESTDIR/1/stamp.kw.ci2 >/dev/null"
+
+ dokeep
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ perms)
+ mkdir 1; cd 1
+ dotest perms-init-1 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ echo 'PreservePermissions=yes' >> ${CVSROOT_DIRNAME}/CVSROOT/config
+ dotest perms-init-2 "$testcvs -Q ci -mperms"
+ cd ..
+
+ dotest perms-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest perms-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ touch foo
+ chmod 431 foo
+ dotest perms-3 "${testcvs} add foo" \
+"${SPROG} add: scheduling file .foo. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest perms-4 "${testcvs} -q ci -m ''" \
+"$CVSROOT_DIRNAME/first-dir/foo,v <-- foo
+initial revision: 1\.1"
+
+ # Test checking out files with different permissions.
+ cd ../..
+ mkdir 2; cd 2
+ dotest perms-5 "${testcvs} -q co first-dir" "U first-dir/foo"
+ cd first-dir
+ if $remote; then :; else
+ # PreservePermissions not yet implemented for remote.
+ dotest perms-6 "ls -l foo" "-r---wx--x .* foo"
+ fi
+
+ dokeep
+ cd ../1/CVSROOT
+ restore_adm
+ cd ../..
+ rm -rf 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ symlinks)
+ # short cut around checking out and committing CVSROOT
+ rm -f $CVSROOT_DIRNAME/CVSROOT/config
+ echo 'PreservePermissions=yes' >> $CVSROOT_DIRNAME/CVSROOT/config
+ chmod 444 $CVSROOT_DIRNAME/CVSROOT/config
+
+ mkdir 1; cd 1
+ dotest symlinks-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest symlinks-2 "$testcvs add first-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+ cd first-dir
+
+ dotest symlinks-2.1 "ln -s $TESTDIR/fumble slink"
+ dotest symlinks-3 "$testcvs add slink" \
+"$SPROG add: scheduling file .slink. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ if $remote; then
+ # Remote doesn't implement PreservePermissions, and in its
+ # absence the correct behavior is to follow the symlink.
+ dotest_fail symlinks-4r "$testcvs -q ci -m ''" \
+"$SPROG \[commit aborted\]: reading slink: No such file or directory"
+ else
+ dotest symlinks-4 "$testcvs -q ci -m ''" \
+"$CVSROOT_DIRNAME/first-dir/slink,v <-- slink
+initial revision: 1\.1"
+
+ # Test checking out symbolic links.
+ cd ../..
+ mkdir 2; cd 2
+ dotest symlinks-5 "$testcvs -q co first-dir" "U first-dir/slink"
+ cd first-dir
+ dotest symlinks-6 "ls -l slink" \
+"l[rwx\-]* .* slink -> $TESTDIR/fumble"
+ fi
+
+ dokeep
+ cd ../..
+ rm -rf 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ restore_adm
+ ;;
+
+
+
+ symlinks2)
+ # Symlinks in working directory without PreservePermissions.
+ # Also see: symlinks: with PreservePermissions
+ # rcslib-symlink-*: symlinks in repository.
+ mkdir 1; cd 1
+ dotest symlinks2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest symlinks2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo nonsymlink > slink
+ dotest symlinks2-3 "${testcvs} add slink" \
+"${SPROG} add: scheduling file .slink. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest symlinks2-4 "${testcvs} -q ci -m ''" \
+"$CVSROOT_DIRNAME/first-dir/slink,v <-- slink
+initial revision: 1\.1"
+ rm slink
+ # Choose name cvslog.* so it is in default ignore list.
+ echo second file >cvslog.file2
+ dotest symlinks2-5 "ln -s cvslog.file2 slink" ""
+ dotest symlinks2-6 "${testcvs} -q ci -m linkify" \
+"$CVSROOT_DIRNAME/first-dir/slink,v <-- slink
+new revision: 1\.2; previous revision: 1\.1"
+ dotest symlinks2-7 "${testcvs} -q update -r 1.1 slink" "[UP] slink"
+ dotest symlinks2-8 "cat slink" "nonsymlink"
+ dotest symlinks2-9 "ls -l slink" "-[-rwx]* .* slink"
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ hardlinks)
+ # short cut around checking out and committing CVSROOT
+ rm -f ${CVSROOT_DIRNAME}/CVSROOT/config
+ echo 'PreservePermissions=yes' > ${CVSROOT_DIRNAME}/CVSROOT/config
+ chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config
+
+ mkdir 1; cd 1
+ dotest hardlinks-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest hardlinks-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ # Make up some ugly filenames, to test that they get
+ # encoded properly in the delta nodes. Note that `dotest' screws
+ # up if some arguments have embedded spaces.
+ if touch aaaa
+ then
+ pass hardlinks-2.1
+ else
+ fail hardlinks-2.1
+ fi
+
+ if ln aaaa b.b.b.b
+ then
+ pass hardlinks-2.2
+ else
+ fail hardlinks-2.2
+ fi
+
+ if ln aaaa 'dd dd dd'
+ then
+ pass hardlinks-2.3
+ else
+ fail hardlinks-2.3
+ fi
+
+ dotest hardlinks-3 "${testcvs} add [abd]*" \
+"${SPROG} add: scheduling file .aaaa. for addition
+${SPROG} add: scheduling file .b\.b\.b\.b. for addition
+${SPROG} add: scheduling file .dd dd dd. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest hardlinks-4 "${testcvs} -q ci -m ''" \
+"$CVSROOT_DIRNAME/first-dir/aaaa,v <-- aaaa
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/b\.b\.b\.b,v <-- b\.b\.b\.b
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/dd dd dd,v <-- dd dd dd
+initial revision: 1\.1"
+ # Test checking out hardlinked files.
+ cd ../..
+ mkdir 2; cd 2
+ if $remote; then
+ # Remote does not implement PreservePermissions.
+ dotest hardlinks-5r "${testcvs} -q co first-dir" \
+"U first-dir/aaaa
+U first-dir/b\.b\.b\.b
+U first-dir/dd dd dd"
+ cd first-dir
+ dotest hardlinks-6r "ls -l [abd]*" \
+"-[rwx\-]* *1 .* aaaa
+-[rwx\-]* *1 .* b\.b\.b\.b
+-[rwx\-]* *1 .* dd dd dd"
+ else
+ dotest hardlinks-5 "${testcvs} -q co first-dir" \
+"U first-dir/aaaa
+U first-dir/b\.b\.b\.b
+U first-dir/dd dd dd"
+ cd first-dir
+ # To make sure that the files are properly hardlinked, it
+ # would be nice to do `ls -i' and make sure all the inodes
+ # match. But I think that would require expr to support
+ # tagged regexps, and I don't think we can rely on that.
+ # So instead we just see that each file has the right
+ # number of links. -twp
+ dotest hardlinks-6 "ls -l [abd]*" \
+"-[rwx\-]* *3 .* aaaa
+-[rwx\-]* *3 .* b\.b\.b\.b
+-[rwx\-]* *3 .* dd dd dd"
+ fi
+
+ dokeep
+ cd ../..
+ rm -rf 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ restore_adm
+ ;;
+
+
+
+ sticky)
+ # More tests of sticky tags, particularly non-branch sticky tags.
+ # See many tests (e.g. multibranch) for ordinary sticky tag
+ # operations such as adding files on branches.
+ # See "head" test for interaction between stick tags and HEAD.
+ mkdir 1; cd 1
+ dotest sticky-1 "$testcvs -q co -l ."
+ mkdir first-dir
+ dotest sticky-2 "$testcvs add first-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
+ cd first-dir
+
+ touch file1
+ dotest sticky-3 "$testcvs add file1" \
+"$SPROG add: scheduling file .file1. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest sticky-4 "$testcvs -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ dotest sticky-5 "$testcvs -q tag tag1" "T file1"
+ echo add a line >>file1
+ dotest sticky-6 "$testcvs -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ dotest sticky-7 "$testcvs -q update -r tag1" "[UP] file1"
+ dotest sticky-8 "cat file1" ''
+ dotest sticky-9 "$testcvs -q update" ''
+ dotest sticky-10 "cat file1" ''
+ touch file2
+ dotest_fail sticky-11 "$testcvs add file2" \
+"$SPROG add: cannot add file on non-branch tag \`tag1'"
+ dotest sticky-12 "$testcvs -q update -A" "[UP] file1
+$QUESTION file2" "$QUESTION file2
+[UP] file1"
+ dotest sticky-13 "${testcvs} add file2" \
+"$SPROG add: scheduling file .file2. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest sticky-14 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+
+ # Now back to tag1
+ dotest sticky-15 "${testcvs} -q update -r tag1" "[UP] file1
+$SPROG update: \`file2' is no longer in the repository"
+
+ rm file1
+ dotest sticky-16 "${testcvs} rm file1" \
+"$SPROG remove: scheduling .file1. for removal
+$SPROG remove: use .$SPROG commit. to remove this file permanently"
+ # Hmm, this command seems to silently remove the tag from
+ # the file. This appears to be intentional.
+ # The silently part especially strikes me as odd, though.
+ dotest sticky-17 "$testcvs -q ci -m remove-it" ""
+ dotest sticky-18 "$testcvs -q update -A" "U file1
+U file2"
+ dotest sticky-19 "$testcvs -q update -r tag1" \
+"${SPROG} update: \`file1' is no longer in the repository
+${SPROG} update: \`file2' is no longer in the repository"
+ dotest sticky-20 "$testcvs -q update -A" "U file1
+U file2"
+
+ # Now try with a numeric revision.
+ dotest sticky-21 "$testcvs -q update -r 1.1 file1" "U file1"
+ dotest sticky-22 "$testcvs rm -f file1" \
+"$SPROG remove: cannot remove file .file1. which has a numeric sticky tag of .1\.1."
+ # The old behavior was that remove allowed this and then commit
+ # gave an error, which was somewhat hard to clear. I mean, you
+ # could get into a long elaborate discussion of this being a
+ # conflict and two ways to resolve it, but I don't really see
+ # why CVS should have a concept of conflict that arises, not from
+ # parallel development, but from CVS's own sticky tags.
+
+ # Ditto with a sticky date.
+ #
+ # I'm kind of surprised that the "file1 was lost" doesn't crop
+ # up elsewhere in the testsuite. It is a long-standing
+ # discrepency between local and remote CVS and should probably
+ # be cleaned up at some point.
+ dotest sticky-23 "$testcvs -q update -Dnow file1" \
+"$SPROG update: warning: \`file1' was lost
+U file1" "U file1"
+ dotest sticky-24 "$testcvs rm -f file1" \
+"$SPROG remove: cannot remove file .file1. which has a sticky date of .[0-9.]*."
+
+ dotest sticky-25 "$testcvs -q update -A" \
+"$SPROG update: warning: \`file1' was lost
+U file1" "U file1"
+
+ dokeep
+ restore_adm
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ keyword)
+ # Test keyword expansion.
+ # Various other tests relate to our ability to correctly
+ # set the keyword expansion mode.
+ # "binfiles" tests "cvs admin -k".
+ # "binfiles" and "binfiles2" test "cvs add -k".
+ # "rdiff" tests "cvs co -k".
+ # "binfiles" (and this test) test "cvs update -k".
+ # "binwrap" tests setting the mode from wrappers.
+ # "keyword2" tests "cvs update -kk -j" with text and binary files
+ # I don't think any test is testing "cvs import -k".
+ # Other keyword expansion tests:
+ # keywordlog - $Log.
+ mkdir 1; cd 1
+ dotest keyword-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest keyword-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ echo '$''Author$' > file1
+ echo '$''Date$' >> file1
+ echo '$''Header$' >> file1
+ echo '$''Id$' >> file1
+ echo '$''Locker$' >> file1
+ echo '$''Name$' >> file1
+ echo '$''RCSfile$' >> file1
+ echo '$''Revision$' >> file1
+ echo '$''Source$' >> file1
+ echo '$''State$' >> file1
+ echo '$''Nonkey$' >> file1
+ # Omit the trailing dollar sign
+ echo '$''Date' >> file1
+ # Put two keywords on one line
+ echo '$''State$' '$''State$' >> file1
+ # Use a header for Log
+ echo 'xx $''Log$' >> file1
+
+ dotest keyword-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest keyword-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ dotest keyword-5 "cat file1" \
+'\$'"Author: ${username} "'\$'"
+"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'"
+"'\$'"Header: ${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'"
+"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'"
+"'\$'"Locker: "'\$'"
+"'\$'"Name: "'\$'"
+"'\$'"RCSfile: file1,v "'\$'"
+"'\$'"Revision: 1\.1 "'\$'"
+"'\$'"Source: ${CVSROOT_DIRNAME}/first-dir/file1,v "'\$'"
+"'\$'"State: Exp "'\$'"
+"'\$'"Nonkey"'\$'"
+"'\$'"Date
+"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'"
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.1 [0-9/]* [0-9:]* ${username}
+xx add
+xx"
+
+ # Use cvs admin to lock the RCS file in order to check -kkvl
+ # vs. -kkv. CVS does not normally lock RCS files, but some
+ # people use cvs admin to enforce reserved checkouts.
+ dotest keyword-6 "${testcvs} admin -l file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+1\.1 locked
+done"
+
+ dotest keyword-7 "${testcvs} update -kkv file1" "U file1"
+ dotest keyword-8 "cat file1" \
+'\$'"Author: ${username} "'\$'"
+"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'"
+"'\$'"Header: ${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'"
+"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'"
+"'\$'"Locker: "'\$'"
+"'\$'"Name: "'\$'"
+"'\$'"RCSfile: file1,v "'\$'"
+"'\$'"Revision: 1\.1 "'\$'"
+"'\$'"Source: ${CVSROOT_DIRNAME}/first-dir/file1,v "'\$'"
+"'\$'"State: Exp "'\$'"
+"'\$'"Nonkey"'\$'"
+"'\$'"Date
+"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'"
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.1 [0-9/]* [0-9:]* ${username}
+xx add
+xx"
+
+ dotest keyword-9 "${testcvs} update -kkvl file1" "U file1"
+ dotest keyword-10 "cat file1" \
+'\$'"Author: ${username} "'\$'"
+"'\$'"Date: ${RCSKEYDATE} "'\$'"
+"'\$'"Header: ${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 ${RCSKEYDATE} ${username} Exp ${username} "'\$'"
+"'\$'"Id: file1,v 1\.1 ${RCSKEYDATE} ${username} Exp ${username} "'\$'"
+"'\$'"Locker: ${username} "'\$'"
+"'\$'"Name: "'\$'"
+"'\$'"RCSfile: file1,v "'\$'"
+"'\$'"Revision: 1\.1 "'\$'"
+"'\$'"Source: ${CVSROOT_DIRNAME}/first-dir/file1,v "'\$'"
+"'\$'"State: Exp "'\$'"
+"'\$'"Nonkey"'\$'"
+"'\$'"Date
+"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'"
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.1 ${RCSKEYDATE} ${username}
+xx add
+xx"
+
+ dotest keyword-11 "${testcvs} update -kk file1" "U file1"
+ dotest keyword-12 "cat file1" \
+'\$'"Author"'\$'"
+"'\$'"Date"'\$'"
+"'\$'"Header"'\$'"
+"'\$'"Id"'\$'"
+"'\$'"Locker"'\$'"
+"'\$'"Name"'\$'"
+"'\$'"RCSfile"'\$'"
+"'\$'"Revision"'\$'"
+"'\$'"Source"'\$'"
+"'\$'"State"'\$'"
+"'\$'"Nonkey"'\$'"
+"'\$'"Date
+"'\$'"State"'\$'" "'\$'"State"'\$'"
+xx "'\$'"Log"'\$'"
+xx Revision 1\.1 ${RCSKEYDATE} ${username}
+xx add
+xx"
+
+ dotest keyword-13 "${testcvs} update -kv file1" "U file1"
+ dotest keyword-14 "cat file1" \
+"${username}
+${RCSKEYDATE}
+${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 ${RCSKEYDATE} ${username} Exp
+file1,v 1\.1 ${RCSKEYDATE} ${username} Exp
+
+
+file1,v
+1\.1
+${CVSROOT_DIRNAME}/first-dir/file1,v
+Exp
+"'\$'"Nonkey"'\$'"
+"'\$'"Date
+Exp Exp
+xx file1,v
+xx Revision 1\.1 ${RCSKEYDATE} ${username}
+xx add
+xx"
+
+ dotest keyword-15 "${testcvs} update -ko file1" "U file1"
+ dotest keyword-16 "cat file1" \
+'\$'"Author"'\$'"
+"'\$'"Date"'\$'"
+"'\$'"Header"'\$'"
+"'\$'"Id"'\$'"
+"'\$'"Locker"'\$'"
+"'\$'"Name"'\$'"
+"'\$'"RCSfile"'\$'"
+"'\$'"Revision"'\$'"
+"'\$'"Source"'\$'"
+"'\$'"State"'\$'"
+"'\$'"Nonkey"'\$'"
+"'\$'"Date
+"'\$'"State"'\$'" "'\$'"State"'\$'"
+xx "'\$'"Log"'\$'
+
+ # Test the Name keyword. First go back to normal expansion.
+
+ dotest keyword-17 "${testcvs} update -A file1" "U file1"
+
+ echo '$''Name$' > file1
+ dotest keyword-18 "${testcvs} ci -m modify file1" \
+"${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ dotest keyword-19 "${testcvs} -q tag tag1" "T file1"
+ echo "change" >> file1
+ dotest keyword-20 "${testcvs} -q ci -m mod2 file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+ # FIXCVS - These unpatchable files are happening because the tag
+ # associated with the current base version of the file in the
+ # sandbox is not available in these cases. See the note in the
+ # patch_file function in update.c.
+ dotest keyword-21 "${testcvs} -q update -r tag1" "U file1" \
+"P file1
+${CPROG} update: checksum failure after patch to \./file1; will refetch
+${CPROG} client: refetching unpatchable files
+$SPROG update: warning: \`file1' was lost
+U file1"
+
+ dotest keyword-22 "cat file1" '\$'"Name: tag1 "'\$'
+
+ if $remote; then
+ # Like serverpatch-8. Not sure there is anything much we
+ # can or should do about this.
+ dotest keyword-23r "${testcvs} update -A file1" "P file1
+${CPROG} update: checksum failure after patch to \./file1; will refetch
+${CPROG} client: refetching unpatchable files
+$SPROG update: warning: \`file1' was lost
+U file1"
+ else
+ dotest keyword-23 "${testcvs} update -A file1" "[UP] file1"
+ fi
+ dotest keyword-24 "cat file1" '\$'"Name: "'\$'"
+change"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ keywordlog)
+ # Test the Log keyword.
+ mkdir 1; cd 1
+ dotest keywordlog-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest keywordlog-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ echo initial >file1
+ dotest keywordlog-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ # See "rmadd" for a list of other tests of cvs ci -r.
+ dotest keywordlog-4 "${testcvs} -q ci -r 1.3 -m add file1" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.3"
+
+ cd ../..
+ mkdir 2; cd 2
+ dotest keywordlog-4a "${testcvs} -q co first-dir" "U first-dir/file1"
+ cd ../1/first-dir
+
+ echo 'xx $''Log$' >> file1
+ cat >${TESTDIR}/comment.tmp <<EOF
+First log line
+Second log line
+EOF
+ # As with rmadd-25, "cvs ci -r" sets a sticky tag.
+ dotest_fail keywordlog-4b \
+"${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \
+"${SPROG} commit: sticky tag .1\.3. for file .file1. is not a branch
+${SPROG} \[commit aborted\]: correct above errors first!"
+ dotest keywordlog-4c "${testcvs} -q update -A" "M file1"
+
+ dotest keywordlog-5 "${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \
+"${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3"
+ rm -f ${TESTDIR}/comment.tmp
+ dotest keywordlog-6 "${testcvs} -q tag -b br" "T file1"
+ dotest keywordlog-7 "cat file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx"
+
+ cd ../../2/first-dir
+ dotest keywordlog-8 "${testcvs} -q update" "[UP] file1"
+ dotest keywordlog-9 "cat file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx"
+ cd ../../1/first-dir
+
+ echo "change" >> file1
+ dotest keywordlog-10 "${testcvs} ci -m modify file1" \
+"${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4"
+ dotest keywordlog-11 "cat file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.5 ${RCSKEYDATE} ${username}
+xx modify
+xx
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx
+change"
+
+ cd ../../2/first-dir
+ dotest keywordlog-12 "${testcvs} -q update" "[UP] file1"
+ dotest keywordlog-13 "cat file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.5 ${RCSKEYDATE} ${username}
+xx modify
+xx
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx
+change"
+
+ cd ../../1/first-dir
+ dotest keywordlog-14 "${testcvs} -q update -r br" "[UP] file1"
+ echo br-change >>file1
+ dotest keywordlog-15 "${testcvs} -q ci -m br-modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4\.2\.1; previous revision: 1\.4"
+ dotest keywordlog-16 "cat file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4\.2\.1 ${RCSKEYDATE} ${username}
+xx br-modify
+xx
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx
+br-change"
+ cd ../../2/first-dir
+ dotest keywordlog-17 "${testcvs} -q update -r br" "[UP] file1"
+ dotest keywordlog-18 "cat file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4\.2\.1 ${RCSKEYDATE} ${username}
+xx br-modify
+xx
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx
+br-change"
+ cd ../..
+ dotest keywordlog-19 "${testcvs} -q co -p -r br first-dir/file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4\.2\.1 ${RCSKEYDATE} ${username}
+xx br-modify
+xx
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx
+br-change"
+ dotest keywordlog-20 "${testcvs} -q co -p first-dir/file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.5 ${RCSKEYDATE} ${username}
+xx modify
+xx
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx
+change"
+ dotest keywordlog-21 "${testcvs} -q co -p -r 1.4 first-dir/file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx"
+
+ cd 2/first-dir
+ # OK, the basic rule for keyword expansion is that it
+ # happens on checkout. And the rule for annotate is that
+ # it annotates a checked-in revision, rather than a checked-out
+ # file. So, although it is kind of confusing that the latest
+ # revision does not appear in the annotated output, and the
+ # annotated output does not quite match what you'd get with
+ # update or checkout, the behavior is more or less logical.
+ # The same issue occurs with annotate and other keywords,
+ # I think, although it is particularly noticeable for $Log.
+ dotest keywordlog-22 "${testcvs} ann -r br file1" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.3 ($username8 *[0-9a-zA-Z-]*): initial
+1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'"
+1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx Revision 1\.4 ${RCSKEYDATE} $username
+1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx First log line
+1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx Second log line
+1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx
+1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): br-change"
+ dotest keywordlog-23 "${testcvs} ann -r HEAD file1" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.3 ($username8 *[0-9a-zA-Z-]*): initial
+1\.5 ($username8 *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'"
+1\.5 ($username8 *[0-9a-zA-Z-]*): xx Revision 1\.4 ${RCSKEYDATE} $username
+1\.5 ($username8 *[0-9a-zA-Z-]*): xx First log line
+1\.5 ($username8 *[0-9a-zA-Z-]*): xx Second log line
+1\.5 ($username8 *[0-9a-zA-Z-]*): xx
+1\.5 ($username8 *[0-9a-zA-Z-]*): change"
+ cd ../..
+
+ #
+ # test the operation of 'admin -o' in conjunction with keywords
+ # (especially Log - this used to munge the RCS file for all time)
+ #
+
+ dotest keywordlog-24 \
+"${testcvs} admin -oHEAD 1/first-dir/file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+deleting revision 1\.5
+done"
+
+ dotest keywordlog-25 \
+"${testcvs} -q co -p first-dir/file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 ${RCSKEYDATE} ${username}
+xx First log line
+xx Second log line
+xx"
+
+ # Now test the behavior when the comment leader exceeds the
+ # configured maximum.
+ mkdir 3; cd 3
+ dotest keywordlog-26 "$testcvs -Q co first-dir"
+
+ cd first-dir
+ sed 's/xx \$/1234567890123456789 $/' <file1 >tmp
+ mv tmp file1
+ dotest keywordlog-27 "$testcvs -Q ci -mrevision-5"
+ dotest keywordlog-28 "cat file1" \
+"initial
+1234567890123456789 "'\$'"Log: file1,v "'\$'"
+1234567890123456789 Revision 1\.5 $RCSKEYDATE $username
+1234567890123456789 revision-5
+1234567890123456789
+xx Revision 1\.4 $RCSKEYDATE $username
+xx First log line
+xx Second log line
+xx"
+
+ sed 's/1234567890123456789 \$/12345678901234567890 $/' <file1 >tmp
+ mv tmp file1
+ dotest keywordlog-29 "$testcvs -Q ci -mrevision-6" \
+"$SPROG commit: Skipping "'`$''Log$'"' keyword due to excessive comment leader\."
+ dotest keywordlog-30 "cat file1" \
+"initial
+12345678901234567890 "'\$'"Log: file1,v "'\$'"
+1234567890123456789 Revision 1\.5 $RCSKEYDATE $username
+1234567890123456789 revision-5
+1234567890123456789
+xx Revision 1\.4 $RCSKEYDATE $username
+xx First log line
+xx Second log line
+xx"
+
+ # Check that the Log-related config options work.
+ cd ..
+ dotest keywordlog-31 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ echo "UseArchiveCommentLeader=TrUe" >>config
+ dotest keywordlog-32 "$testcvs -Q ci -mset-UseArchiveCommentLeader"
+
+ cd ../first-dir
+ dotest keywordlog-33 "$testcvs -Q ci -fmrevision-7 file1"
+ dotest keywordlog-34 "cat file1" \
+"initial
+12345678901234567890 "'\$'"Log: file1,v "'\$'"
+# Revision 1\.7 $RCSKEYDATE $username
+# revision-7
+#
+1234567890123456789 Revision 1\.5 $RCSKEYDATE $username
+1234567890123456789 revision-5
+1234567890123456789
+xx Revision 1\.4 $RCSKEYDATE $username
+xx First log line
+xx Second log line
+xx"
+
+ cd ../CVSROOT
+ echo "MaxCommentLeaderLength=1k" >>config
+ dotest keywordlog-35 "$testcvs -Q ci -mset-MaxCommentLeaderLength"
+
+ cd ../first-dir
+ dotest keywordlog-36 "$testcvs -Q ci -fmrevision-8 file1"
+ dotest keywordlog-37 "cat file1" \
+"initial
+12345678901234567890 "'\$'"Log: file1,v "'\$'"
+12345678901234567890 Revision 1\.8 $RCSKEYDATE $username
+12345678901234567890 revision-8
+12345678901234567890
+# Revision 1\.7 $RCSKEYDATE $username
+# revision-7
+#
+1234567890123456789 Revision 1\.5 $RCSKEYDATE $username
+1234567890123456789 revision-5
+1234567890123456789
+xx Revision 1\.4 $RCSKEYDATE $username
+xx First log line
+xx Second log line
+xx"
+
+ dokeep
+ cd ../..
+ restore_adm
+ rm -r 1 2 3
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ keywordname)
+ # Test the Name keyword.
+ # See the keyword test for a descriptions of some other tests that
+ # test keyword expansion modes.
+ mkdir keywordname; cd keywordname
+ mkdir 1; cd 1
+ dotest keywordname-init-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest keywordname-init-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ echo '$'"Name$" >file1
+ echo '$'"Name$" >file2
+ dotest keywordname-init-3 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+
+ # See "rmadd" for a list of other tests of cvs ci -r.
+ dotest keywordname-init-4 "${testcvs} -q ci -r 1.3 -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.3
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.3"
+
+ dotest keywordname-init-6 "${testcvs} -q up -A"
+ dotest keywordname-init-7 "${testcvs} -q tag -b br" \
+"T file1
+T file2"
+
+ echo new data >>file1
+ dotest keywordname-init-8 "${testcvs} -q ci -mchange" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3"
+
+ # First check out a branch.
+ #
+ # There used to be a bug where static tags would be substituted for
+ # Name keywords but not branch tags.
+ #
+ # FIXCVS - BUG
+ # Why shouldn't the non-update case not cause a substitution?
+ # An update -kk or -A will unsub and sub keywords without updates
+ # being required.
+ # FIXCVS - see note above keyword-21
+ dotest keywordname-update-1 "${testcvs} -q up -rbr" "U file1" \
+"P file1
+${CPROG} update: checksum failure after patch to \./file1; will refetch
+${CPROG} client: refetching unpatchable files
+$SPROG update: warning: \`file1' was lost
+U file1"
+ dotest keywordname-update-2 "cat file1" '\$'"Name: br "'\$'
+ dotest keywordname-update-3 "cat file2" '\$'"Name: "'\$'
+
+ # Now verify that updating to the trunk leaves no substitution for
+ # $Name
+ dotest keywordname-update-4 "${testcvs} -q tag firsttag" \
+"T file1
+T file2"
+ # FIXCVS - see note above keyword-21
+ dotest keywordname-update-5 "${testcvs} -q up -A" "U file1" \
+"P file1
+${CPROG} update: checksum failure after patch to \./file1; will refetch
+${CPROG} client: refetching unpatchable files
+$SPROG update: warning: \`file1' was lost
+U file1"
+ dotest keywordname-update-6 "cat file1" \
+'\$'"Name: "'\$'"
+new data"
+ dotest keywordname-update-7 "cat file2" '\$'"Name: "'\$'
+
+ # But updating to a static tag does cause a substitution
+ # FIXCVS - see same note above
+ dotest keywordname-update-8 "${testcvs} -q up -rfirsttag" "U file1" \
+"P file1
+${CPROG} update: checksum failure after patch to \./file1; will refetch
+${CPROG} client: refetching unpatchable files
+$SPROG update: warning: \`file1' was lost
+U file1"
+ dotest keywordname-update-9 "cat file1" '\$'"Name: firsttag "'\$'
+ dotest keywordname-update-10 "cat file2" '\$'"Name: "'\$'
+
+ # And reverify the trunk update when the change is actually removed.
+ dotest keywordname-update-11 "${testcvs} -q up -A" "[UP] file1" \
+"P file1
+${CPROG} update: checksum failure after patch to ./file1; will refetch
+${CPROG} client: refetching unpatchable files
+$SPROG update: warning: \`file1' was lost
+U file1"
+ dotest keywordname-update-12 "cat file1" \
+'\$'"Name: "'\$'"
+new data"
+ dotest keywordname-update-13 "cat file2" '\$'"Name: "'\$'
+
+ cd ../..
+
+ # now verify that a fresh checkout substitutes all the $Name fields
+ mkdir 2; cd 2
+ dotest keywordname-checkout-1 \
+"${testcvs} -q co -rfirsttag first-dir" \
+"U first-dir/file1
+U first-dir/file2"
+ cd first-dir
+ dotest keywordname-checkout-2 "cat file1" '\$'"Name: firsttag "'\$'
+ dotest keywordname-checkout-3 "cat file2" '\$'"Name: firsttag "'\$'
+
+ dokeep
+ cd ../../..
+ rm -r keywordname
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ keyword2)
+ # Test merging on files with keywords:
+ # without -kk
+ # with -kk
+ # on text files
+ # on binary files
+ # Note: This test assumes that CVS has already passed the binfiles
+ # test sequence
+ # Note2: We are testing positive on binary corruption here
+ # we probably really DON'T want to 'cvs update -kk' a binary file...
+ mkdir 1; cd 1
+ dotest keyword2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest keyword2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ echo '$''Revision$' >> file1
+ echo "I" >>file1
+ echo "like" >>file1
+ echo "long" >>file1
+ echo "files!" >>file1
+ echo "" >>file1
+ echo "a test line for our times" >>file1
+ echo "" >>file1
+ echo "They" >>file1
+ echo "make" >>file1
+ echo "diff" >>file1
+ echo "look like it" >>file1
+ echo "did a much better" >>file1
+ echo "job." >>file1
+ dotest keyword2-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ ${AWK} 'BEGIN { printf "%c%c%c%sRevision: 1.1 $@%c%c", \
+ 2, 10, 137, "$", 13, 10 }' \
+ </dev/null | ${TR} '@' '\000' >../binfile.dat
+ cp ../binfile.dat .
+ dotest keyword2-5 "${testcvs} add -kb binfile.dat" \
+"${SPROG} add: scheduling file .binfile\.dat. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+
+ dotest keyword2-6 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/binfile\.dat,v <-- binfile\.dat
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ dotest keyword2-7 "${testcvs} -q tag -b branch" \
+"T binfile\.dat
+T file1"
+
+ sed -e 's/our/the best of and the worst of/' file1 >f; mv f file1
+ dotest keyword2-8 "${testcvs} -q ci -m change" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+
+ dotest keyword2-9 "${testcvs} -q update -r branch" '[UP] file1'
+
+ echo "what else do we have?" >>file1
+ dotest keyword2-10 "${testcvs} -q ci -m change" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ # Okay, first a conflict in file1 - should be okay with binfile.dat
+ dotest keyword2-11 "${testcvs} -q update -A -j branch" \
+"U file1
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into file1
+rcsmerge: warning: conflicts during merge"
+
+ dotest_fail keyword2-12 "${testcvs} diff file1" \
+"Index: file1
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.2
+diff -r1\.2 file1
+0a1
+> <<<<<<< file1
+1a3,5
+> =======
+> \\\$""Revision: 1\.1\.2\.1 \\\$
+> >>>>>>> 1\.1\.2\.1
+14a19
+> what else do we have${QUESTION}"
+
+ # Here's the problem... shouldn't -kk a binary file...
+ rm file1
+ dotest keyword2-13 "${testcvs} -q update -A -kk -j branch" \
+"${SPROG} update: warning: \`file1' was lost
+U file1
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into file1"
+
+ # binfile won't get checked in, but it is now corrupt and could
+ # have been checked in if it had changed on the branch...
+ dotest keyword2-14 "${testcvs} -q ci -m change" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+
+ # "-kk" no longer corrupts binary files
+ dotest keyword2-15 "cmp binfile.dat ../binfile.dat" ''
+
+ # Okay, restore everything and make CVS try and merge a binary file...
+ # "-kk" no longer affects binary files
+ dotest keyword2-16 "${testcvs} -q update -A" \
+"[UP] file1"
+ dotest keyword2-17 "${testcvs} -q tag -b branch2" \
+"T binfile\.dat
+T file1"
+ dotest keyword2-18 "${testcvs} -q update -r branch2" ''
+
+ ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | ${TR} '@' '\000' >>binfile.dat
+ dotest keyword2-19 "$testcvs -q ci -m badbadbad" \
+"$CVSROOT_DIRNAME/first-dir/binfile\.dat,v <-- binfile\.dat
+new revision: 1\.1\.4\.1; previous revision: 1\.1"
+ # "-kk" no longer affects binary files
+
+ # XXXX: do not ask, why we get the "U binfile.dat" line twice
+ # looks like a bug!
+ dotest keyword2-20 "${testcvs} -q update -A -kk -j branch2" \
+"U binfile\.dat
+U binfile\.dat
+U file1"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ head)
+ # Testing handling of the HEAD special tag.
+ # There are many cases involving added and removed files
+ # which we don't yet try to deal with.
+ # TODO: We also could be paying much closer attention to
+ # "head of the trunk" versus "head of the default branch".
+ # That is what "cvs import" is doing here (but I didn't really
+ # fully follow through on writing the tests for that case).
+ mkdir imp-dir
+ cd imp-dir
+ echo 'imported contents' >file1
+ # It may seem like we don't do much with file2, but do note that
+ # the "cvs diff" invocations do also diff file2 (and come up empty).
+ echo 'imported contents' >file2
+ dotest_sort head-1 "${testcvs} import -m add first-dir tag1 tag2" \
+"
+
+N first-dir/file1
+N first-dir/file2
+No conflicts created by this import"
+ cd ..
+ rm -r imp-dir
+ mkdir 1
+ cd 1
+ dotest head-2 "${testcvs} -q co first-dir" \
+"U first-dir/file1
+U first-dir/file2"
+ cd first-dir
+ echo 'add a line on trunk' >> file1
+ dotest head-3 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ dotest head-4 "${testcvs} -q tag trunktag" "T file1
+T file2"
+ echo 'add a line on trunk after trunktag' >> file1
+ dotest head-5 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2"
+ dotest head-6 "${testcvs} -q tag -b br1" "T file1
+T file2"
+ dotest head-7 "${testcvs} -q update -r br1" ""
+ echo 'modify on branch' >>file1
+ dotest head-8 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3\.2\.1; previous revision: 1\.3"
+ dotest head-9 "${testcvs} -q tag brtag" "T file1
+T file2"
+ echo 'modify on branch after brtag' >>file1
+ dotest head-10 "${testcvs} -q ci -m modify" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.3\.2\.2; previous revision: 1\.3\.2\.1"
+ # With no sticky tags, HEAD is the head of the trunk.
+ dotest head-trunk-setup "${testcvs} -q update -A" "[UP] file1"
+ dotest head-trunk-update "${testcvs} -q update -r HEAD -p file1" \
+"imported contents
+add a line on trunk
+add a line on trunk after trunktag"
+ # and diff thinks so too. Case (a) from the comment in
+ # cvs.texinfo (Common options).
+ dotest_fail head-trunk-diff "${testcvs} -q diff -c -r HEAD -r br1" \
+"Index: file1
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.3
+retrieving revision 1\.3\.2\.2
+diff -c -r1\.3 -r1\.3\.2\.2
+\*\*\* file1 ${RFCDATE} 1\.3
+--- file1 ${RFCDATE} 1\.3\.2\.2
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1,3 \*\*\*\*
+--- 1,5 ----
+ imported contents
+ add a line on trunk
+ add a line on trunk after trunktag
+${PLUS} modify on branch
+${PLUS} modify on branch after brtag"
+
+ # With a branch sticky tag, HEAD is the head of the trunk.
+ dotest head-br1-setup "${testcvs} -q update -r br1" "[UP] file1"
+ dotest head-br1-update "${testcvs} -q update -r HEAD -p file1" \
+"imported contents
+add a line on trunk
+add a line on trunk after trunktag"
+ # But diff thinks that HEAD is "br1". Case (b) from cvs.texinfo.
+ # Probably people are relying on it.
+ dotest head-br1-diff "${testcvs} -q diff -c -r HEAD -r br1" ""
+
+ # With a nonbranch sticky tag on a branch,
+ # HEAD is the head of the trunk
+ dotest head-brtag-setup "${testcvs} -q update -r brtag" "[UP] file1"
+ dotest head-brtag-update "${testcvs} -q update -r HEAD -p file1" \
+"imported contents
+add a line on trunk
+add a line on trunk after trunktag"
+
+ # CVS 1.9 and older thought that HEAD is "brtag" (this was
+ # noted as "strange, maybe accidental"). But "br1" makes a
+ # whole lot more sense.
+ dotest head-brtag-diff "${testcvs} -q diff -c -r HEAD -r br1" ""
+
+ # With a nonbranch sticky tag on the trunk, HEAD is the head
+ # of the trunk, I think.
+ dotest head-trunktag-setup "${testcvs} -q update -r trunktag" \
+"[UP] file1"
+ dotest head-trunktag-check "cat file1" "imported contents
+add a line on trunk"
+ dotest head-trunktag-update "${testcvs} -q update -r HEAD -p file1" \
+"imported contents
+add a line on trunk
+add a line on trunk after trunktag"
+ # Like head-brtag-diff, there is a non-branch sticky tag.
+ dotest_fail head-trunktag-diff \
+ "${testcvs} -q diff -c -r HEAD -r br1" \
+"Index: file1
+===================================================================
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+retrieving revision 1\.3
+retrieving revision 1\.3\.2\.2
+diff -c -r1\.3 -r1\.3\.2\.2
+\*\*\* file1 ${RFCDATE} 1\.3
+--- file1 ${RFCDATE} 1\.3\.2\.2
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1,3 \*\*\*\*
+--- 1,5 ----
+ imported contents
+ add a line on trunk
+ add a line on trunk after trunktag
+${PLUS} modify on branch
+${PLUS} modify on branch after brtag"
+
+ # Also might test what happens if we setup with update -r
+ # HEAD. In general, if sticky tags matter, does the
+ # behavior of "update -r <foo>" (without -p) depend on the
+ # sticky tags before or after the update?
+
+ # Note that we are testing both the case where this deletes
+ # a revision (file1) and the case where it does not (file2)
+ dotest_fail head-o0a "${testcvs} admin -o ::br1" \
+"${SPROG} admin: Administrating \.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+${SPROG} admin: cannot remove revision 1\.3\.2\.1 because it has tags
+${SPROG} admin: RCS file for .file1. not modified\.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+ dotest head-o0b "${testcvs} tag -d brtag" \
+"${SPROG} tag: Untagging \.
+D file1
+D file2"
+ dotest head-o1 "${testcvs} admin -o ::br1" \
+"${SPROG} admin: Administrating \.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+deleting revision 1\.3\.2\.1
+done
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ tagdate)
+ # Test combining -r and -D.
+ #
+ # Note that this is not a complete test. It relies on the fact
+ # that update, checkout and export have a LOT of shared code.
+ # Notice:
+ # 1) checkout is never tested at all with -r -D
+ # 2) update never uses an argument to '-D' besides 'now'
+ # (this test does not provide enough data to prove
+ # that 'cvs update' with both a '-r' and a '-D'
+ # specified does not ignore '-D': a 'cvs up
+ # -r<branch> -Dnow' and a 'cvs up -r<branch>'
+ # should specify the same file revision).
+ # 3) export uses '-r<branch> -D<when there was a different
+ # revision>', hopefully completing this behavior test
+ # for checkout and update as well.
+ #
+ mkdir 1; cd 1
+ save_TZ=$TZ
+ TZ=UTC0; export TZ
+ dotest tagdate-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest tagdate-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ echo trunk-1 >file1
+ dotest tagdate-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest tagdate-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+ date_T1=`getrlogdate -r1.1 first-dir/file1`
+
+ dotest tagdate-5 "${testcvs} -q tag -b br1" "T file1"
+ dotest tagdate-6 "${testcvs} -q tag -b br2" "T file1"
+ echo trunk-2 >file1
+ dotest tagdate-7 "${testcvs} -q ci -m modify-on-trunk" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1"
+ date_T2=`getrlogdate -r1.2 first-dir/file1`
+
+ # We are testing -r -D where br1 is a (magic) branch without
+ # any revisions. First the case where br2 doesn't have any
+ # revisions either:
+ dotest tagdate-8 "${testcvs} -q update -p -r br1 -D now" "trunk-1"
+ dotest tagdate-9 "${testcvs} -q update -r br2" "[UP] file1"
+ echo br2-1 >file1
+ dotest tagdate-10 "${testcvs} -q ci -m modify-on-br2" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.4\.1; previous revision: 1\.1"
+ date_T3=`getrlogdate -r1.1.4.1 first-dir/file1`
+
+ # Then the case where br2 does have revisions:
+ dotest tagdate-11 "${testcvs} -q update -p -r br1 -D now" "trunk-1"
+
+ # Joins from dates on the head used to be prohibited.
+ dotest tagdate-12 "$testcvs -q update -j:yesterday -j:now"
+ dotest tagdate-12b "$testcvs -Q update -C"
+ # And check export
+
+ echo br2-2 >file1
+ dotest tagdate-13 "${testcvs} -q ci -m modify-2-on-br2" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.4\.2; previous revision: 1\.1\.4\.1"
+ date_T4=`getrlogdate -r1.1.4.2 first-dir/file1`
+
+ # Test diff -r<tag>:<date> with two revisions specified.
+ dotest_fail tagdate-13b \
+"$testcvs -q diff -u -rbr2:'$date_T3' -rbr2:now file1" \
+"Index: file1
+===================================================================
+RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
+retrieving revision 1\.1\.4\.1
+retrieving revision 1\.1\.4\.2
+diff -u -r1\.1\.4\.1 -r1\.1\.4\.2
+--- file1 $RFCDATE 1\.1\.4\.1
++++ file1 $RFCDATE 1\.1\.4\.2
+@@ -1 ${PLUS}1 @@
+-br2-1
+${PLUS}br2-2"
+
+ # Tag a date on a branch.
+ dotest tagdate-13c "$testcvs -q tag -rbr2:'$date_T3' tagdate" \
+"T file1"
+ dotest tagdate-13d "$testcvs -q update -rtagdate" "[UP] file1"
+ dotest tagdate-13e "cat file1" "br2-1"
+
+ # This one should fail, though currently without an error message,
+ # since a date on a static tag is meaningless.
+ dotest tagdate-13f "$testcvs -q tag -rtagdate:'$date_T3' tagdate"
+
+ # and restore to using the trunk for future tests.
+ dotest tagdate-13g "$testcvs -q up -rbr2" "[UP] file1"
+
+ cd ../..
+ mkdir 2; cd 2
+ dotest tagdate-14 \
+"$testcvs -q export -r br2 -D'$date_T3' first-dir" \
+"[UP] first-dir/file1"
+ dotest tagdate-14b "cat first-dir/file1" "br2-1"
+ dotest tagdate-15 \
+"$testcvs -q export -rbr2:'$date_T3' -dsecond-dir first-dir" \
+"[UP] second-dir/file1"
+ dotest tagdate-15b "cat second-dir/file1" "br2-1"
+
+ # Now for annotate
+ cd ../1/first-dir
+ dotest tagdate-16 "${testcvs} annotate -rbr2 -D'$date_T3'" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1\.4\.1 ($username8 *[0-9a-zA-Z-]*): br2-1"
+
+ dotest tagdate-17 "${testcvs} annotate -rbr2 -Dnow" \
+"
+Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1\.4\.2 ($username8 *[0-9a-zA-Z-]*): br2-2"
+
+ # Now check to see what happens when we add files to br2 and trunk
+ echo br2-1 > file3
+ dotest tagdate-18 "${testcvs} add file3" \
+"${SPROG} add: scheduling file \`file3' for addition on branch \`br2'
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ dotest tagdate-19 "${testcvs} -q ci -m add file3" \
+"$CVSROOT_DIRNAME/first-dir/Attic/file3,v <-- file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ date_T5=`getrlogdate -r1.1 first-dir/file3`
+ date_T6=`getrlogdate -r1.1.2.1 first-dir/file3`
+
+ cd ../..
+ mkdir 3; cd 3
+ dotest tagdate-20 "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ echo trunk-1 > file2
+ dotest tagdate-21 "${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest tagdate-22 "${testcvs} -q ci -m add file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ date_T7=`getrlogdate -r1.1 first-dir/file2`
+ echo "trunk-2" >file2
+ dotest tagdate-23 "${testcvs} -q ci -m update file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.2; previous revision: 1\.1"
+ date_T8=`getrlogdate -r1.2 first-dir/file2`
+
+ cd ../../1/first-dir
+ echo br2-1 > file2
+ dotest tagdate-24 "${testcvs} add file2" \
+"${SPROG} add: scheduling file \`file2' for addition on branch \`br2'
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ dotest tagdate-25 "${testcvs} -q ci -m add file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.2\.2\.2; previous revision: 1\.2\.2\.1"
+ date_T9=`getrlogdate -r1.2.2.2 first-dir/file2`
+ cd ../..
+
+ # Time Rev Branch Comments
+ # T0 trunk first-dir created
+ # T1 1.1 trunk first-dir/file1 committed "trunk-1"
+ # br1 branch created
+ # br2 branch created
+ # T2 1.2 trunk first-dir/file1 committed "trunk-2"
+ # T3 1.1.4.1 br2 first-dir/file1 committed "br2-1"
+ # +60s
+ # T4 1.1.4.2 br2 first-dir/file1 committed "br2-2"
+ # T5 1.1 trunk first-dir/file3 dead
+ # T6 1.1.2.1 br2 first-dir/file3 committed "br2-1"
+ # T7 1.1 trunk first-dir/file2 committed "trunk-1"
+ # T8 1.2 trunk first-dir/file2 committed "trunk-2"
+ # T8 1.2.2.1 br2 first-dir/file2 dead
+ # T9 1.2.2.2 br2 first-dir/file2 committed "br2-1"
+ #
+
+ mkdir 4; cd 4
+ (echo Dates for tagdate-26-* are:;\
+ echo " date_T1='$date_T1'";\
+ echo " date_T2='$date_T2'";\
+ echo " date_T3='$date_T3'";\
+ echo " date_T4='$date_T4'";\
+ echo " date_T5='$date_T5'";\
+ echo " date_T6='$date_T6'";\
+ echo " date_T7='$date_T7'";\
+ echo " date_T8='$date_T8'";\
+ echo " date_T9='$date_T9'") >>$LOGFILE
+ dotest tagdate-26-trunk-t1 \
+"${testcvs} co -D'$date_T1' -d first-dir-trunk-t1 first-dir" \
+"${SPROG} checkout: Updating first-dir-trunk-t1
+U first-dir-trunk-t1/file1"
+ dotest tagdate-26-br2-t1 \
+"${testcvs} co -r br2 -D'$date_T1' -d first-dir-br2-t1 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t1
+U first-dir-br2-t1/file1"
+ dotest tagdate-26-trunk-t2 \
+"${testcvs} co -D'$date_T2' -d first-dir-trunk-t2 first-dir" \
+"${SPROG} checkout: Updating first-dir-trunk-t2
+U first-dir-trunk-t2/file1"
+ dotest tagdate-26-br2-t2 \
+"${testcvs} co -r br2 -D'$date_T2' -d first-dir-br2-t2 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t2
+U first-dir-br2-t2/file1"
+ dotest tagdate-26-br2-t3 \
+"${testcvs} co -r br2 -D'$date_T3' -d first-dir-br2-t3 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t3
+U first-dir-br2-t3/file1"
+ dotest tagdate-26-br2-t4 \
+"${testcvs} co -r br2 -D'$date_T4' -d first-dir-br2-t4 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t4
+U first-dir-br2-t4/file1"
+ dotest tagdate-26-br2-t6 \
+"${testcvs} co -r br2 -D'$date_T6' -d first-dir-br2-t6 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t6
+U first-dir-br2-t6/file1
+U first-dir-br2-t6/file3"
+ dotest tagdate-26-trunk-t7 \
+"${testcvs} co -D'$date_T7' -d first-dir-trunk-t7 first-dir" \
+"${SPROG} checkout: Updating first-dir-trunk-t7
+U first-dir-trunk-t7/file1
+U first-dir-trunk-t7/file2"
+ dotest tagdate-26-br2-t7 \
+"${testcvs} co -r br2 -D'$date_T7' -d first-dir-br2-t7 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t7
+U first-dir-br2-t7/file1
+U first-dir-br2-t7/file3"
+ dotest tagdate-26-trunk-t8 \
+"${testcvs} co -D'$date_T8' -d first-dir-trunk-t8 first-dir" \
+"${SPROG} checkout: Updating first-dir-trunk-t8
+U first-dir-trunk-t8/file1
+U first-dir-trunk-t8/file2"
+ dotest tagdate-26-br2-t8 \
+"${testcvs} co -r br2 -D'$date_T8' -d first-dir-br2-t8 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t8
+U first-dir-br2-t8/file1
+U first-dir-br2-t8/file3"
+ dotest tagdate-26-br2-t9 \
+"${testcvs} co -r br2 -D'$date_T9' -d first-dir-br2-t9 first-dir" \
+"${SPROG} checkout: Updating first-dir-br2-t9
+U first-dir-br2-t9/file1
+U first-dir-br2-t9/file2
+U first-dir-br2-t9/file3"
+ dotest tagdate-27-trunk-t1 \
+"${testcvs} status first-dir-trunk-t1" \
+"${SPROG} status: Examining first-dir-trunk-t1
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1[^.]*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: ${RCSDELTADATE}
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t1 \
+"${testcvs} status first-dir-br2-t1" \
+"${SPROG} status: Examining first-dir-br2-t1
+===================================================================
+File: file1 Status: Needs Patch
+
+ Working revision: 1\.1[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest tagdate-27-trunk-t2 \
+"${testcvs} status first-dir-trunk-t2" \
+"${SPROG} status: Examining first-dir-trunk-t2
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.2[^.]*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: ${RCSDELTADATE}
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t2 \
+"${testcvs} status first-dir-br2-t2" \
+"${SPROG} status: Examining first-dir-br2-t2
+===================================================================
+File: file1 Status: Needs Patch
+
+ Working revision: 1\.1[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t3 \
+"${testcvs} status first-dir-br2-t3" \
+"${SPROG} status: Examining first-dir-br2-t3
+===================================================================
+File: file1 Status: Needs Patch
+
+ Working revision: 1\.1\.4\.1[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t4 \
+"${testcvs} status first-dir-br2-t4" \
+"${SPROG} status: Examining first-dir-br2-t4
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1\.4\.2[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t6 \
+"${testcvs} status first-dir-br2-t6" \
+"${SPROG} status: Examining first-dir-br2-t6
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1\.4\.2[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Up-to-date
+
+ Working revision: 1\.1\.2\.1[^.]*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest tagdate-27-trunk-t7 \
+"${testcvs} status first-dir-trunk-t7" \
+"${SPROG} status: Examining first-dir-trunk-t7
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.2[^.]*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: ${RCSDELTADATE}
+ Sticky Options: (none)
+
+===================================================================
+File: file2 Status: Up-to-date
+
+ Working revision: 1\.1[^.]*
+ Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: ${RCSDELTADATE}
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t7 \
+"${testcvs} status first-dir-br2-t7" \
+"${SPROG} status: Examining first-dir-br2-t7
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1\.4\.2[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Up-to-date
+
+ Working revision: 1\.1\.2\.1[^.]*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest tagdate-27-trunk-t8 \
+"${testcvs} status first-dir-trunk-t8" \
+"${SPROG} status: Examining first-dir-trunk-t8
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.2[^.]*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: ${RCSDELTADATE}
+ Sticky Options: (none)
+
+===================================================================
+File: file2 Status: Up-to-date
+
+ Working revision: 1\.2[^.]*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: ${RCSDELTADATE}
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t8 \
+"${testcvs} status first-dir-br2-t8" \
+"${SPROG} status: Examining first-dir-br2-t8
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1\.4\.2[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Up-to-date
+
+ Working revision: 1\.1\.2\.1[^.]*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest tagdate-27-br2-t9 \
+"${testcvs} status first-dir-br2-t9" \
+"${SPROG} status: Examining first-dir-br2-t9
+===================================================================
+File: file1 Status: Up-to-date
+
+ Working revision: 1\.1\.4\.2[^.]*
+ Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.4)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2 Status: Up-to-date
+
+ Working revision: 1\.2\.2\.2[^.]*
+ Repository revision: 1\.2\.2\.2 ${CVSROOT_DIRNAME}/first-dir/file2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.2\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file3 Status: Up-to-date
+
+ Working revision: 1\.1\.2\.1[^.]*
+ Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: br2 (branch: 1\.1\.2)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ # Now check the contents of the files
+ dotest tagdate-28-trunk-t1 'cat first-dir-trunk-t1/file1' 'trunk-1'
+ dotest tagdate-28-br2-t1 'cat first-dir-br2-t1/file1' 'trunk-1'
+ dotest tagdate-28-trunk-t2 'cat first-dir-trunk-t2/file1' 'trunk-2'
+ dotest tagdate-28-br2-t2 'cat first-dir-br2-t2/file1' 'trunk-1'
+ dotest tagdate-28-br2-t3 'cat first-dir-br2-t3/file1' 'br2-1'
+ dotest tagdate-28-br2-t4 'cat first-dir-br2-t4/file1' 'br2-2'
+ dotest tagdate-28-br2-t6a 'cat first-dir-br2-t6/file1' "br2-2"
+ dotest tagdate-28-br2-t6b 'cat first-dir-br2-t6/file3' "br2-1"
+ dotest tagdate-28-trunk-t7a 'cat first-dir-trunk-t7/file1' "trunk-2"
+ dotest tagdate-28-trunk-t7b 'cat first-dir-trunk-t7/file2' "trunk-1"
+ dotest tagdate-28-br2-t7a 'cat first-dir-br2-t7/file1' "br2-2"
+ dotest tagdate-28-br2-t7b 'cat first-dir-br2-t7/file3' "br2-1"
+ dotest tagdate-28-trunk-t8a 'cat first-dir-trunk-t8/file1' "trunk-2"
+ dotest tagdate-28-trunk-t8b 'cat first-dir-trunk-t8/file2' "trunk-2"
+ dotest tagdate-28-br2-t8a 'cat first-dir-br2-t8/file1' "br2-2"
+ dotest tagdate-28-br2-t8c 'cat first-dir-br2-t8/file3' "br2-1"
+ dotest tagdate-28-br2-t9a 'cat first-dir-br2-t9/file1' "br2-2"
+ dotest tagdate-28-br2-t9b 'cat first-dir-br2-t9/file2' "br2-1"
+ dotest tagdate-28-br2-t9c 'cat first-dir-br2-t9/file3' "br2-1"
+ cd ..
+
+ unset date_T1 date_T2 date_T3 date_T4 date_T5
+ unset date_T6 date_T7 date_T8 date_T9
+ TZ=$save_TZ
+
+ dokeep
+ rm -r 1 2 3 4
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ multibranch2)
+ # Commit the first delta on branch A when there is an older
+ # branch, B, that already has a delta. A and B come from the
+ # same branch point. Then verify that branches A and B are
+ # in the right order.
+ mkdir 1; cd 1
+ dotest multibranch2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest multibranch2-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ echo trunk-1 >file1
+ echo trunk-1 >file2
+ dotest multibranch2-3 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest multibranch2-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ dotest multibranch2-5 "${testcvs} -q tag -b A" "T file1
+T file2"
+ dotest multibranch2-6 "${testcvs} -q tag -b B" "T file1
+T file2"
+
+ dotest multibranch2-7 "${testcvs} -q update -r B" ''
+ echo branch-B >file1
+ echo branch-B >file2
+ dotest multibranch2-8 "${testcvs} -q ci -m modify-on-B" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.4\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.4\.1; previous revision: 1\.1"
+
+ dotest multibranch2-9 "${testcvs} -q update -r A" '[UP] file1
+[UP] file2'
+ echo branch-A >file1
+ # When using cvs-1.9.20, this commit gets a failed assertion in rcs.c.
+ dotest multibranch2-10 "${testcvs} -q ci -m modify-on-A" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ dotest multibranch2-11 "${testcvs} -q log file1" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ B: 1\.1\.0\.4
+ A: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2; 1\.1\.4;
+add
+----------------------------
+revision 1\.1\.4\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+modify-on-B
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; lines: ${PLUS}1 -1; commitid: ${commitid};
+modify-on-A
+============================================================================="
+
+ # This one is more concise.
+ dotest multibranch2-12 "${testcvs} -q log -r1.1 file1" \
+"
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ B: 1\.1\.0\.4
+ A: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 3; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2; 1\.1\.4;
+add
+============================================================================="
+
+ # OK, try very much the same thing except we run update -j to
+ # bring the changes from B to A. Probably tests many of the
+ # same code paths but might as well keep it separate, I guess.
+
+ dotest multibranch2-13 "${testcvs} -q update -r B" "[UP] file1
+[UP] file2"
+ dotest multibranch2-14 "${testcvs} -q update -r A -j B file2" \
+"[UP] file2
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+retrieving revision 1.1
+retrieving revision 1.1.4.1
+Merging differences between 1.1 and 1.1.4.1 into file2"
+ dotest multibranch2-15 "${testcvs} -q ci -m commit-on-A file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ tag8k)
+ # In cvs-1.9.27, there is a bug that can cause an abort.
+ # It happens when you commit a change to a ,v file that has
+ # just the right amount of tag/branch info to align one of the
+ # semicolons in the branch info to be on a 8k-byte boundary.
+ # The result: rcsbuf_getkey got an abort. This failure doesn't
+ # corrupt the ,v file -- that would be really serious. But it
+ # does leave stale write locks that have to be removed manually.
+
+ mkdir 1
+ cd 1
+
+ module=x
+
+ : > junk
+ dotest tag8k-1 "$testcvs -Q import -m . $module X Y" ''
+ dotest tag8k-2 "$testcvs -Q co $module" ''
+ cd $module
+
+ file=m
+ : > $file
+ dotest tag8k-3 "$testcvs add $file" \
+"$SPROG add: scheduling file .$file. for addition
+$SPROG add: use .$SPROG commit. to add this file permanently"
+ dotest tag8k-4 "$testcvs -Q ci -m . $file"
+
+ # It seems there have to be at least two versions.
+ echo a > $file
+ dotest tag8k-5 "$testcvs -Q ci -m . $file"
+
+ # Add just under 8K worth of tags.
+ t=TAG---------------------------------------------------------------------
+ t=$t$t
+ t=$t$t$t$t$t
+ # Now $t is 720 bytes long.
+
+ # Apply some tags with that long prefix.
+ dotest tag8k-6 "$testcvs -Q tag $t-0 $file" ''
+ dotest tag8k-7 "$testcvs -Q tag $t-1 $file" ''
+ dotest tag8k-8 "$testcvs -Q tag $t-2 $file" ''
+ dotest tag8k-9 "$testcvs -Q tag $t-3 $file" ''
+ dotest tag8k-10 "$testcvs -Q tag $t-4 $file" ''
+ dotest tag8k-11 "$testcvs -Q tag $t-5 $file" ''
+ dotest tag8k-12 "$testcvs -Q tag $t-6 $file" ''
+ dotest tag8k-13 "$testcvs -Q tag $t-7 $file" ''
+ dotest tag8k-14 "$testcvs -Q tag $t-8 $file" ''
+ dotest tag8k-15 "$testcvs -Q tag $t-9 $file" ''
+ dotest tag8k-16 "$testcvs -Q tag $t-a $file" ''
+
+ # Extract the author value.
+ name=`sed -n 's/.*; author \([^;]*\);.*/\1/p' ${CVSROOT_DIRNAME}/$module/$file,v|sed 1q`
+
+ # Form a suffix string of length (16 - length($name)).
+ # CAREFUL: this will lose if $name is longer than 16.
+ sed_pattern=`echo $name|sed s/././g`
+ suffix=`echo 1234567890123456|sed s/$sed_pattern//`
+
+ # Add a final tag with length chosen so that it will push the
+ # offset of the `;' in the 2nd occurrence of `;\tauthor' in the
+ # ,v file to exactly 8192.
+ dotest tag8k-17 "$testcvs -Q tag "x8bytes-$suffix" $file" ''
+
+ # This commit would fail with 1.9.27.
+ echo a >> $file
+ dotest tag8k-18 "$testcvs -Q ci -m . $file"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ admin)
+ # More "cvs admin" tests.
+ # The basicb-21 test tests rejecting an invalid option.
+ # For -l and -u, see "reserved" and "keyword" tests.
+ # "binfiles" test has a test of "cvs admin -k".
+ # "log2" test has tests of -t and -q options to cvs admin.
+ # "rcs" tests -b option also.
+ # For -o, see:
+ # admin-22-o1 through admin-23 (various cases not involving ::)
+ # binfiles2-o* (:rev, rev on trunk; rev:, deleting entire branch)
+ # basicb-o* (attempt to delete all revisions)
+ # basica-o1 through basica-o3 (basic :: usage)
+ # head-o1 (::branch, where this deletes a revision or is noop)
+ # branches-o1 (::branch, similar, with different branch topology)
+ # log-o1 (1.3.2.1::)
+ # binfiles-o1 (1.3:: and ::1.3; binary files)
+ # binfiles3-9 (binary files)
+ # Also could be testing:
+ # 1.3.2.6::1.3.2.8
+ # 1.3.2.6::1.3.2
+ # 1.3.2.1::1.3.2.6
+ # 1.3::1.3.2.6 (error? or synonym for ::1.3.2.6?)
+ # -n: admin, tagf tests.
+
+ # Test the postadmin hook as a side effect of the rest of the tests.
+ # See the `info' test for notes on where other script hooks are
+ # tested.
+ mkdir 2; cd 2
+ dotest admin-init-1 "$testcvs -Q co CVSROOT"
+ cd CVSROOT
+ echo "ALL $TESTDIR/2/loggit %r %p %c" >>postadmin
+ dotest admin-init-2 "$testcvs -Q ci -mlog-admin"
+ cd .. # 2
+
+ cat >loggit <<EOF
+#!$TESTSHELL
+echo \${1+"\$@"} >>$TESTDIR/2/admin-log
+EOF
+ # #^@&!^@ Cygwin.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x $TESTDIR/2/loggit"
+ else
+ chmod +x loggit
+ fi
+ cd .. # $TESTDIR
+
+
+ mkdir 1; cd 1
+ dotest admin-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest admin-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+
+ dotest_fail admin-3 "${testcvs} -q admin -i file1" \
+"${CPROG} admin: the -i option to admin is not supported
+${CPROG} admin: run add or import to create an RCS file
+${CPROG} \[admin aborted\]: specify ${CPROG} -H admin for usage information"
+ dotest_fail admin-4 "${testcvs} -q log file1" \
+"${SPROG} log: nothing known about file1"
+ dotest_fail admin-4a "${testcvs} -q admin file1" \
+"${SPROG} admin: nothing known about file1"
+
+ # Set up some files, file2 a plain one and file1 with a revision
+ # on a branch.
+ touch file1 file2
+ dotest admin-5 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest admin-6 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ dotest admin-7 "${testcvs} -q tag -b br" "T file1
+T file2"
+ dotest admin-8 "${testcvs} -q update -r br" ""
+ echo 'add a line on the branch' >> file1
+ echo 'add a file on the branch' >> file3
+ dotest admin-9a "${testcvs} -q add file3" \
+"${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest admin-9b "${testcvs} -q ci -m modify-on-branch" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/Attic/file3,v <-- file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1"
+ dotest admin-10 "${testcvs} -q update -A" \
+"U file1
+${SPROG} update: \`file3' is no longer in the repository"
+
+ # Check that we can administer files in the repository that
+ # aren't in the working directory.
+ dotest admin-10-1 "${testcvs} admin ." \
+"${SPROG} admin: Administrating .
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+ dotest admin-10-2 "${testcvs} -q admin file3" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
+done"
+
+ # Try to recurse with a numeric revision arg.
+ # If we wanted to comprehensive about this, we would also test
+ # this for -l, -u, and all the different -o syntaxes.
+ dotest_fail admin-10a "${testcvs} -q admin -b1.1.2" \
+"${CPROG} admin: while processing more than one file:
+${CPROG} \[admin aborted\]: attempt to specify a numeric revision"
+ dotest_fail admin-10b "${testcvs} -q admin -m1.1:bogus file1 file2" \
+"${CPROG} admin: while processing more than one file:
+${CPROG} \[admin aborted\]: attempt to specify a numeric revision"
+
+ # try a bad symbolic revision
+ dotest_fail admin-10c "${testcvs} -q admin -bBOGUS" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/file1,v: Symbolic name BOGUS is undefined.
+${SPROG} admin: RCS file for .file1. not modified\.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: Symbolic name BOGUS is undefined.
+${SPROG} admin: RCS file for .file2. not modified\."
+
+ # Note that -s option applies to the new default branch, not
+ # the old one.
+ # Also note that the implementation of -a via "rcs" requires
+ # no space between -a and the argument. However, we expect
+ # to change that once CVS parses options.
+ dotest admin-11 "${testcvs} -q admin -afoo,bar -abaz \
+-b1.1.2 -cxx -U -sfoo file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest admin-11a "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch: 1\.1\.2
+locks:
+access list:
+ foo
+ bar
+ baz
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+add
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: foo; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify-on-branch
+============================================================================="
+ dotest admin-12 "${testcvs} -q admin -bbr file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest admin-12a "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch: 1\.1\.2
+locks:
+access list:
+ foo
+ bar
+ baz
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+add
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: foo; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify-on-branch
+============================================================================="
+
+ # "cvs log" doesn't print the comment leader. RCS 5.7 will print
+ # the comment leader only if one specifies "-V4" to rlog. So it
+ # seems like the only way to test it is by looking at the RCS file
+ # directly. This also serves as a test of exporting RCS files
+ # (analogous to the import tests in "rcs").
+ # Rather than try to write a rigorous check for whether the
+ # file CVS exports is valid, we just write a simpler
+ # test for what CVS actually exports, and figure we can revise
+ # the check as needed (within the confines of the RCS5 format as
+ # documented in RCSFILES).
+ # Note that we must accept either 2 or 4 digit year.
+ dotest admin-13 "cat ${CVSROOT_DIRNAME}/first-dir/file1,v" \
+"head 1\.1;
+branch 1\.1\.2;
+access
+ foo
+ bar
+ baz;
+symbols
+ br:1\.1\.0\.2;
+locks;
+comment @xx@;
+
+
+1\.1
+date ${RCSDELTADATE}; author ${username}; state Exp;
+branches
+ 1\.1\.2\.1;
+next ;
+commitid ${commitid};
+
+1\.1\.2\.1
+date ${RCSDELTADATE}; author ${username}; state foo;
+branches;
+next ;
+commitid ${commitid};
+
+
+desc
+@@
+
+
+1\.1
+log
+@add
+@
+text
+@@
+
+
+1\.1\.2\.1
+log
+@modify-on-branch
+@
+text
+@a0 1
+add a line on the branch
+@"
+ dotest_fail admin-14-1 "${testcvs} -q admin \
+-m1.1.1.1:changed-bogus-log-message file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+$SPROG admin: $CVSROOT_DIRNAME/first-dir/file2,v: no such revision 1\.1\.1\.1
+$SPROG admin: RCS file for .file2. not modified."
+ dotest admin-14-2 "${testcvs} -q log file2" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ br: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+
+ dotest admin-14-3 "${testcvs} -q admin -aauth3 -aauth2,foo \
+-soneone:1.1 -m1.1:changed-log-message -ntagone: file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+ dotest admin-15 "${testcvs} -q log file2" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.1
+branch:
+locks: strict
+access list:
+ auth3
+ auth2
+ foo
+symbolic names:
+ tagone: 1\.1
+ br: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: oneone; commitid: ${commitid};
+changed-log-message
+============================================================================="
+
+ dotest admin-16 "${testcvs} -q admin \
+-A${CVSROOT_DIRNAME}/first-dir/file2,v -b -L -Nbr:1.1 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest admin-17 "${testcvs} -q log file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+ foo
+ bar
+ baz
+ auth3
+ auth2
+symbolic names:
+ br: 1\.1
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+add
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: foo; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify-on-branch
+============================================================================="
+
+ dotest_fail admin-18 "${testcvs} -q admin -nbr:1.1.2 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/file1,v: symbolic name br already bound to 1\.1
+${SPROG} admin: RCS file for .file1. not modified\."
+ dotest admin-19 "${testcvs} -q admin -ebaz -ebar,auth3 -nbr file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest admin-20 "${testcvs} -q log file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+ foo
+ auth2
+symbolic names:
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+add
+----------------------------
+revision 1.1.2.1
+date: ${ISO8601DATE}; author: ${username}; state: foo; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify-on-branch
+============================================================================="
+
+ # OK, this is starting to get ridiculous, in terms of
+ # testing a feature (access lists) which doesn't do anything
+ # useful, but what about nonexistent files and
+ # relative pathnames in admin -A?
+ dotest_fail admin-19a-nonexist \
+"${testcvs} -q admin -A${TESTDIR}/foo/bar file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+${SPROG} admin: Couldn't open rcs file .${TESTDIR}/foo/bar.: No such file or directory
+${SPROG} \[admin aborted\]: cannot continue"
+
+ # In the remote case, we are cd'd off into the temp directory
+ # and so these tests give "No such file or directory" errors.
+ if $remote; then :; else
+ dotest admin-19a-admin "${testcvs} -q admin -A../../cvsroot/first-dir/file2,v file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest admin-19a-log "${testcvs} -q log -h -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+ foo
+ auth2
+ auth3
+keyword substitution: kv
+total revisions: 2
+============================================================================="
+ fi # end of tests skipped for remote
+
+ # Now test that plain -e works right.
+ dotest admin-19a-2 "${testcvs} -q admin -e file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+ dotest admin-19a-3 "${testcvs} -q log -h -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 2
+============================================================================="
+
+ # Put the access list back, to avoid special cases later.
+ dotest admin-19a-4 "${testcvs} -q admin -afoo,auth2 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+
+ # Add another revision to file2, so we can delete one.
+ echo 'add a line' >> file2
+ dotest admin-21 "${testcvs} -q ci -m modify file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.2; previous revision: 1\.1"
+ dotest admin-22 "${testcvs} -q admin -o1.1 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+deleting revision 1\.1
+done"
+ # Test admin -o. More variants that we could be testing:
+ # * REV: [on branch]
+ # * REV1:REV2 [deleting whole branch]
+ # * high branch numbers (e.g. 1.2.2.3.2.3)
+ # ... and probably others. See RCS_delete_revs for ideas.
+
+ echo first rev > aaa
+ dotest admin-22-o1 "${testcvs} add aaa" \
+"${SPROG} add: scheduling file .aaa. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest admin-22-o2 "${testcvs} -q ci -m first aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+initial revision: 1\.1"
+ echo second rev >> aaa
+ dotest admin-22-o3 "${testcvs} -q ci -m second aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.2; previous revision: 1\.1"
+ echo third rev >> aaa
+ dotest admin-22-o4 "${testcvs} -q ci -m third aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.3; previous revision: 1\.2"
+ echo fourth rev >> aaa
+ dotest admin-22-o5 "${testcvs} -q ci -m fourth aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.4; previous revision: 1\.3"
+ echo fifth rev >>aaa
+ dotest admin-22-o6 "${testcvs} -q ci -m fifth aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.5; previous revision: 1\.4"
+ echo sixth rev >> aaa
+ dotest admin-22-o7 "${testcvs} -q ci -m sixth aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.6; previous revision: 1\.5"
+ dotest admin-22-o8 "${testcvs} admin -l1.6 aaa" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+1\.6 locked
+done"
+ dotest admin-22-o9 "${testcvs} log -r1.6 aaa" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+Working file: aaa
+head: 1\.6
+branch:
+locks: strict
+ ${username}: 1\.6
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 6; selected revisions: 1
+description:
+----------------------------
+revision 1\.6 locked by: ${username};
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+sixth
+============================================================================="
+ dotest_fail admin-22-o10 "${testcvs} admin -o1.5: aaa" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/aaa,v: can't remove locked revision 1\.6
+${SPROG} admin: RCS file for .aaa. not modified\."
+ dotest admin-22-o11 "${testcvs} admin -u aaa" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+1\.6 unlocked
+done"
+ dotest admin-22-o12 "${testcvs} admin -o1.5: aaa" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+deleting revision 1\.6
+deleting revision 1\.5
+done"
+ dotest admin-22-o13 "${testcvs} log aaa" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+Working file: aaa
+head: 1\.4
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 4; selected revisions: 4
+description:
+----------------------------
+revision 1\.4
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+fourth
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+third
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+second
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+first
+============================================================================="
+
+ dotest admin-22-o14 "${testcvs} tag -b -r1.3 br1 aaa" "T aaa"
+ dotest admin-22-o15 "${testcvs} update -rbr1 aaa" "U aaa"
+ echo new branch rev >> aaa
+ dotest admin-22-o16 "${testcvs} ci -m new-branch aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.3\.2\.1; previous revision: 1\.3"
+ dotest_fail admin-22-o17 "${testcvs} admin -o1.2:1.4 aaa" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+deleting revision 1\.4
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/aaa,v: can't remove branch point 1\.3
+${SPROG} admin: RCS file for .aaa. not modified\."
+ dotest admin-22-o18 "${testcvs} update -p -r1.4 aaa" \
+"===================================================================
+Checking out aaa
+RCS: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+VERS: 1\.4
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+first rev
+second rev
+third rev
+fourth rev"
+ echo second branch rev >> aaa
+ dotest admin-22-o19 "${testcvs} ci -m branch-two aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.3\.2\.2; previous revision: 1\.3\.2\.1"
+ echo third branch rev >> aaa
+ dotest admin-22-o20 "${testcvs} ci -m branch-three aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.3\.2\.3; previous revision: 1\.3\.2\.2"
+ echo fourth branch rev >> aaa
+ dotest admin-22-o21 "${testcvs} ci -m branch-four aaa" \
+"$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa
+new revision: 1\.3\.2\.4; previous revision: 1\.3\.2\.3"
+ dotest admin-22-o22 "${testcvs} admin -o:1.3.2.3 aaa" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+deleting revision 1\.3\.2\.1
+deleting revision 1\.3\.2\.2
+deleting revision 1\.3\.2\.3
+done"
+ dotest admin-22-o23 "${testcvs} log aaa" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+Working file: aaa
+head: 1\.4
+branch:
+locks: strict
+access list:
+symbolic names:
+ br1: 1\.3\.0\.2
+keyword substitution: kv
+total revisions: 5; selected revisions: 5
+description:
+----------------------------
+revision 1\.4
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+fourth
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+branches: 1\.3\.2;
+third
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+second
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+first
+----------------------------
+revision 1\.3\.2\.4
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}4 -0; commitid: ${commitid};
+branch-four
+============================================================================="
+
+ dotest admin-22-o24 "${testcvs} -q update -p -r 1.3.2.4 aaa" \
+"first rev
+second rev
+third rev
+new branch rev
+second branch rev
+third branch rev
+fourth branch rev"
+
+ # The bit here about how there is a "tagone" tag pointing to
+ # a nonexistent revision is documented by rcs. I dunno, I
+ # wonder whether the "cvs admin -o" should give a warning in
+ # this case.
+ dotest admin-23 "${testcvs} -q log file2" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.2
+branch:
+locks: strict
+access list:
+ auth3
+ auth2
+ foo
+symbolic names:
+ tagone: 1\.1
+ br: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+modify
+============================================================================="
+
+ dotest admin-25 "cat ${CVSROOT_DIRNAME}/first-dir/file1,v" \
+"head 1\.1;
+access
+ foo
+ auth2;
+symbols;
+locks; strict;
+comment @xx@;
+
+
+1\.1
+date ${RCSDELTADATE}; author ${username}; state Exp;
+branches
+ 1\.1\.2\.1;
+next ;
+commitid ${commitid};
+
+1\.1\.2\.1
+date ${RCSDELTADATE}; author ${username}; state foo;
+branches;
+next ;
+commitid ${commitid};
+
+
+desc
+@@
+
+
+1\.1
+log
+@add
+@
+text
+@@
+
+
+1\.1\.2\.1
+log
+@modify-on-branch
+@
+text
+@a0 1
+add a line on the branch
+@"
+
+ # Tests of cvs admin -n. Make use of the results of
+ # admin-1 through admin-25.
+ # FIXME: We probably shouldn't make use of those results;
+ # this test is way too long as it is.
+
+ # tagtwo should be a revision
+ #
+ dotest admin-26-1 "${testcvs} admin -ntagtwo:tagone file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ # br1 should be a branch
+ #
+ dotest admin-26-2 "${testcvs} admin -nbr1:br file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ # Attach some tags using RCS versions
+ #
+ dotest admin-26-3 "${testcvs} admin -ntagthree:1.1 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ dotest admin-26-4 "${testcvs} admin -nbr2:1.1.2 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ dotest admin-26-5 "${testcvs} admin -nbr4:1.1.0.2 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ # Check results so far
+ #
+ dotest admin-26-6 "${testcvs} status -v file2" \
+"===================================================================
+File: file2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ br4 (branch: 1\.1\.2)
+ br2 (branch: 1\.1\.2)
+ tagthree (revision: 1\.1)
+ br1 (branch: 1\.1\.2)
+ tagtwo (revision: 1\.1)
+ tagone (revision: 1\.1)
+ br (branch: 1\.1\.2)"
+
+
+ # Add a couple more revisions
+ #
+ echo "nuthr_line" >> file2
+ dotest admin-27-1 "${testcvs} commit -m nuthr_line file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.3; previous revision: 1\.2"
+
+ echo "yet_another" >> file2
+ dotest admin-27-2 "${testcvs} commit -m yet_another file2" \
+"$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+new revision: 1\.4; previous revision: 1\.3"
+
+ # Fail trying to reattach existing tag with -n
+ #
+ dotest admin-27-3 "${testcvs} admin -ntagfour:1.1 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ dotest_fail admin-27-4 "${testcvs} admin -ntagfour:1.3 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: symbolic name tagfour already bound to 1\.1
+${SPROG} admin: RCS file for .file2. not modified\."
+
+ # Succeed at reattaching existing tag, using -N
+ #
+ dotest admin-27-5 "${testcvs} admin -Ntagfour:1.3 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+done"
+
+ # Fail on some bogus operations
+ # Try to attach to nonexistant tag
+ #
+ dotest_fail admin-28-1 "${testcvs} admin -ntagsix:tagfive file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: Symbolic name or revision tagfive is undefined\.
+${SPROG} admin: RCS file for .file2. not modified\."
+
+ # Try a some nonexisting numeric target tags
+ #
+ dotest_fail admin-28-2 "${testcvs} admin -ntagseven:2.1 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} \[admin aborted\]: revision .2\.1. does not exist"
+
+ dotest_fail admin-28-3 "${testcvs} admin -ntageight:2.1.2 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} \[admin aborted\]: revision .2\.1\.2. does not exist"
+
+ # Try some invalid targets
+ #
+ dotest_fail admin-28-4 "${testcvs} admin -ntagnine:1.a.2 file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} \[admin aborted\]: tag .1\.a\.2. must start with a letter"
+
+ # Confirm that a missing tag is not a fatal error.
+ dotest admin-28-5.1 "${testcvs} -Q tag BO+GUS file1" ''
+ dotest_fail admin-28-5.2 "${testcvs} admin -ntagten:BO+GUS file2 file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: Symbolic name or revision BO${PLUS}GUS is undefined\.
+${SPROG} admin: RCS file for .file2. not modified\.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+done"
+
+ dotest_fail admin-28-6 "${testcvs} admin -nq.werty:tagfour file2" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} \[admin aborted\]: tag .q\.werty. must not contain the characters ..*"
+
+ # Verify the archive
+ #
+ dotest admin-29 "cat ${CVSROOT_DIRNAME}/first-dir/file2,v" \
+"head 1\.4;
+access
+ auth3
+ auth2
+ foo;
+symbols
+ tagfour:1\.3
+ br4:1\.1\.0\.2
+ br2:1\.1\.0\.2
+ tagthree:1\.1
+ br1:1\.1\.0\.2
+ tagtwo:1\.1
+ tagone:1\.1
+ br:1\.1\.0\.2;
+locks; strict;
+comment @# @;
+
+
+1\.4
+date ${RCSDELTADATE}; author ${username}; state Exp;
+branches;
+next 1\.3;
+commitid ${commitid};
+
+1\.3
+date ${RCSDELTADATE}; author ${username}; state Exp;
+branches;
+next 1\.2;
+commitid ${commitid};
+
+1\.2
+date ${RCSDELTADATE}; author ${username}; state Exp;
+branches;
+next ;
+commitid ${commitid};
+
+
+desc
+@@
+
+
+1\.4
+log
+@yet_another
+@
+text
+@add a line
+nuthr_line
+yet_another
+@
+
+
+1\.3
+log
+@nuthr_line
+@
+text
+@d3 1
+@
+
+
+1\.2
+log
+@modify
+@
+text
+@d2 1
+@"
+
+ dotest_fail admin-30 "${testcvs} admin -mbr:another-log-message \
+file2 aaa file3" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: no such revision br: 1\.1
+${SPROG} admin: RCS file for .file2. not modified.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/aaa,v: no such revision br
+${SPROG} admin: RCS file for .aaa. not modified.
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
+done"
+ dotest admin-31 "${testcvs} log" \
+"${SPROG} log: Logging \.
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
+Working file: aaa
+head: 1\.4
+branch:
+locks: strict
+access list:
+symbolic names:
+ br1: 1\.3\.0\.2
+keyword substitution: kv
+total revisions: 5; selected revisions: 5
+description:
+----------------------------
+revision 1\.4
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+fourth
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+branches: 1\.3\.2;
+third
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+second
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+first
+----------------------------
+revision 1\.3\.2\.4
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}4 -0; commitid: ${commitid};
+branch-four
+=============================================================================
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+ foo
+ auth2
+symbolic names:
+ tagten: 1\.1
+ BO${PLUS}GUS: 1\.1
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+branches: 1\.1\.2;
+add
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: foo; lines: ${PLUS}1 -0; commitid: ${commitid};
+modify-on-branch
+=============================================================================
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
+Working file: file2
+head: 1\.4
+branch:
+locks: strict
+access list:
+ auth3
+ auth2
+ foo
+symbolic names:
+ tagfour: 1\.3
+ br4: 1\.1\.0\.2
+ br2: 1\.1\.0\.2
+ tagthree: 1\.1
+ br1: 1\.1\.0\.2
+ tagtwo: 1\.1
+ tagone: 1\.1
+ br: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.4
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+yet_another
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+nuthr_line
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+modify
+=============================================================================
+
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
+Working file: file3
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ br: 1\.1\.0\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: dead; commitid: ${commitid};
+branches: 1\.1\.2;
+file file3 was initially added on branch br\.
+----------------------------
+revision 1\.1\.2\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+another-log-message
+============================================================================="
+
+ # Currently, this test outputs 36 identical lines, so I am just
+ # checking $DOTSTAR for brevity.
+ dotest admin-postadmin-examine-1 "cat $TESTDIR/2/admin-log" \
+"$CVSROOT_DIRNAME first-dir admin$DOTSTAR"
+
+ dokeep
+
+ # clean up our after ourselves
+ restore_adm
+ cd ../..
+ rm -r 1 2
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ reserved)
+ # Tests of reserved checkouts. Eventually this will test
+ # rcslock.pl (or equivalent) and all kinds of stuff. Right
+ # now it just does some very basic checks on cvs admin -u
+ # and cvs admin -l.
+ # Also should test locking on a branch (and making sure that
+ # locks from one branch don't get mixed up with those from
+ # another. Both the case where one of the branches is the
+ # main branch, and in which neither one is).
+ # See also test keyword, which tests that keywords and -kkvl
+ # do the right thing in the presence of locks.
+
+ # The usual setup, directory first-dir containing file file1.
+ mkdir 1; cd 1
+ dotest reserved-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest reserved-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch file1
+ dotest reserved-3 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest reserved-4 "${testcvs} -q ci -m add" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1"
+
+ dotest reserved-5 "${testcvs} -q admin -l file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+1\.1 locked
+done"
+ dotest reserved-6 "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+ ${username}: 1\.1
+access list:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1 locked by: ${username};
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+
+ # Note that this just tests the owner of the lock giving
+ # it up. It doesn't test breaking a lock.
+ dotest reserved-7 "${testcvs} -q admin -u file1" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+1\.1 unlocked
+done"
+
+ dotest reserved-8 "${testcvs} log -N file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
+Working file: file1
+head: 1\.1
+branch:
+locks: strict
+access list:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+
+ # rcslock.pl tests. Of course, the point isn't to test
+ # rcslock.pl from the distribution but equivalent
+ # functionality (for example, many sites may have an old
+ # rcslock.pl). The functionality of this hook falls
+ # short of the real rcslock.pl though.
+ # Note that we can use rlog or look at the RCS file directly,
+ # but we can't use "cvs log" because "cvs commit" has a lock.
+
+ cat >${TESTDIR}/lockme <<EOF
+#!${TESTSHELL}
+line=\`grep <\$1/\$2,v 'locks $anyusername:1\.[0-9];'\`
+if test -z "\$line"; then
+ # It isn't locked
+ exit 0
+else
+ user=\`echo \$line | sed -e 's/locks \\($anyusername\\):[0-9.]*;.*/\\1/'\`
+ version=\`echo \$line | sed -e 's/locks $anyusername:\\([0-9.]*\\);.*/\\1/'\`
+ echo "\$user has file a-lock locked for version \$version" >&2
+ exit 1
+fi
+EOF
+ # Cygwin. Blaaarg.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x ${TESTDIR}/lockme"
+ else
+ chmod +x ${TESTDIR}/lockme
+ fi
+
+ echo stuff > a-lock
+ dotest reserved-9 "${testcvs} add a-lock" \
+"${SPROG} add: scheduling file .a-lock. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest reserved-10 "${testcvs} -q ci -m new a-lock" \
+"$CVSROOT_DIRNAME/first-dir/a-lock,v <-- a-lock
+initial revision: 1\.1"
+ # FIXME: the contents of CVSROOT fluctuate a lot
+ # here. Maybe the expect pattern should just
+ # confirm that commitinfo is one of the files checked out,
+ # but for now we just check that CVS exited with success.
+ cd ..
+ if ${testcvs} -q co CVSROOT >>${LOGFILE} ; then
+ pass reserved-11
+ else
+ fail reserved-11
+ fi
+ cd CVSROOT
+ echo "DEFAULT ${TESTDIR}/lockme" >>commitinfo
+ dotest reserved-12 "${testcvs} -q ci -m rcslock commitinfo" \
+"$CVSROOT_DIRNAME/CVSROOT/commitinfo,v <-- commitinfo
+new revision: 1\.2; previous revision: 1\.1
+$SPROG commit: Rebuilding administrative file database"
+ cd ..; cd first-dir
+
+ # Simulate (approximately) what a-lock would look like
+ # if someone else had locked revision 1.1.
+ sed -e 's/locks; strict;/locks fred:1.1; strict;/' ${CVSROOT_DIRNAME}/first-dir/a-lock,v > a-lock,v
+ # Cygwin.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod 644 ${CVSROOT_DIRNAME}/first-dir/a-lock,v"
+ else
+ chmod 644 ${CVSROOT_DIRNAME}/first-dir/a-lock,v
+ fi
+ dotest reserved-13 "mv a-lock,v ${CVSROOT_DIRNAME}/first-dir/a-lock,v"
+ # Cygwin. Blah.
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod 444 ${CVSROOT_DIRNAME}/first-dir/a-lock,v"
+ else
+ chmod 444 ${CVSROOT_DIRNAME}/first-dir/a-lock,v
+ fi
+ echo more stuff >> a-lock
+ dotest_fail_sort reserved-13b "$testcvs ci -m '' a-lock" \
+" \"$TESTDIR/lockme\"
+Appending defaults (\" %r/%p %s\"), but please be aware that this usage is
+$SPROG \[commit aborted\]: correct above errors first!
+$SPROG commit: Pre-commit check failed
+$SPROG commit: warning: commitinfo line contains no format strings:
+deprecated\.
+fred has file a-lock locked for version 1\.1"
+ # OK, now test "cvs admin -l" in the case where someone
+ # else has the file locked.
+ dotest_fail reserved-13c "${testcvs} admin -l a-lock" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/a-lock,v
+${SPROG} \[admin aborted\]: Revision 1\.1 is already locked by fred"
+
+ dotest reserved-14 "${testcvs} admin -u1.1 a-lock" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/a-lock,v
+${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/a-lock,v: revision 1\.1 locked by fred; breaking lock
+1\.1 unlocked
+done"
+ dotest reserved-15 "$testcvs -q ci -m success a-lock" \
+"$SPROG commit: warning: commitinfo line contains no format strings:
+ \"$TESTDIR/lockme\"
+Appending defaults (\" %r/%p %s\"), but please be aware that this usage is
+deprecated\.
+$CVSROOT_DIRNAME/first-dir/a-lock,v <-- a-lock
+new revision: 1\.2; previous revision: 1\.1"
+
+ # Now test for a bug involving branches and locks
+ sed -e 's/locks; strict;/locks fred:1.2; strict;/' ${CVSROOT_DIRNAME}/first-dir/a-lock,v > a-lock,v
+ chmod 644 ${CVSROOT_DIRNAME}/first-dir/a-lock,v
+ dotest reserved-16 \
+"mv a-lock,v ${CVSROOT_DIRNAME}/first-dir/a-lock,v" ""
+ chmod 444 ${CVSROOT_DIRNAME}/first-dir/a-lock,v
+ dotest reserved-17 "${testcvs} -q tag -b br a-lock" "T a-lock"
+ dotest reserved-18 "${testcvs} -q update -r br a-lock" ""
+ echo edit it >>a-lock
+ dotest reserved-19 "${testcvs} -q ci -m modify a-lock" \
+"$SPROG commit: warning: commitinfo line contains no format strings:
+ \"$TESTDIR/lockme\"
+Appending defaults (\" %r/%p %s\"), but please be aware that this usage is
+deprecated\.
+$CVSROOT_DIRNAME/first-dir/a-lock,v <-- a-lock
+new revision: 1\.2\.2\.1; previous revision: 1\.2"
+
+ # undo commitinfo changes
+ cd ../CVSROOT
+ echo '# vanilla commitinfo' >commitinfo
+ dotest reserved-cleanup-1 "${testcvs} -q ci -m back commitinfo" \
+"$SPROG commit: warning: commitinfo line contains no format strings:
+ \"$TESTDIR/lockme\"
+Appending defaults (\" %r/%p %s\"), but please be aware that this usage is
+deprecated\.
+$CVSROOT_DIRNAME/CVSROOT/commitinfo,v <-- commitinfo
+new revision: 1\.3; previous revision: 1\.2
+$SPROG commit: Rebuilding administrative file database"
+
+ dokeep
+ cd ..; rm -r CVSROOT
+ cd ..
+ rm -r 1
+ rm $TESTDIR/lockme
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ diffmerge1)
+ # Make sure CVS can merge correctly in circumstances where it
+ # used to mess up (due to a bug which existed in diffutils 2.7
+ # and 2.6, but not 2.5, and which has been fixed in CVS's diff
+ # lib by Paul Eggert, bless his bitty heart).
+
+ # This first test involves two working copies, "mine" and
+ # "yours", checked out from the same repository at the same
+ # time. In yours, you remove some text from the end of the
+ # file and check it in; meanwhile, "me" has commented out some
+ # lines earlier in the file, and I go to check it in right
+ # after you checked yours in. CVS naturally tells me the file
+ # is not up-to-date, so I run cvs update, but it updates
+ # incorrectly, leaving in the lines of text you just deleted.
+ # Bad! I'm in too much of a hurry to actually look at the
+ # file, so I check it in and go home, and so your changes have
+ # been lost. Later you discover this, and you suspect me of
+ # deliberately sabotaging your work, so you let all the air
+ # out of my tires. Only after a series of expensive lawsuits
+ # and countersuits do we discover that this was all CVS's
+ # fault.
+ #
+ # Luckily, this problem has been fixed now, as our test will
+ # handily confirm, no doubt:
+
+ # First make a repository containing the original text:
+
+ # We should be here anyway, but cd to it just in case:
+ cd ${TESTDIR}
+
+ mkdir diffmerge1
+ cd diffmerge1
+
+ # These are the files we both start out with:
+ mkdir import
+ cd import
+ diffmerge_create_older_files
+
+ dotest diffmerge1_import \
+ "${testcvs} import -m import diffmerge1 tag1 tag2" \
+ "${DOTSTAR}No conflicts created by this import"
+ cd ..
+
+ # Check out two working copies, one for "you" and one for
+ # "me". If no branch is used and cvs detects that only one
+ # of the two people made changes, then cvs does not run the
+ # merge algorithm. But if a branch is used, then cvs does run
+ # the merge algorithm (even in this case of only one of the two
+ # people having made changes). CVS used to have a bug in this
+ # case. Therefore, it is important to test this case by
+ # using a branch:
+ ${testcvs} rtag -b tag diffmerge1 >/dev/null 2>&1
+ ${testcvs} checkout -r tag diffmerge1 >/dev/null 2>&1
+ mv diffmerge1 yours
+ ${testcvs} checkout diffmerge1 >/dev/null 2>&1
+ mv diffmerge1 mine
+
+ # In your working copy, you'll make changes, and
+ # then check in your changes before I check in mine:
+ cd yours
+ diffmerge_create_your_files
+ dotest diffmerge1_yours "${testcvs} -q ci -m yours" \
+"$CVSROOT_DIRNAME/diffmerge1/testcase01,v <-- testcase01
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase02,v <-- testcase02
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase03,v <-- testcase03
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase04,v <-- testcase04
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase05,v <-- testcase05
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase06,v <-- testcase06
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase07,v <-- testcase07
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase08,v <-- testcase08
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase09,v <-- testcase09
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
+$CVSROOT_DIRNAME/diffmerge1/testcase10,v <-- testcase10
+new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1"
+
+ # Change my copy. Then I
+ # update, after both my modifications and your checkin:
+ cd ../mine
+ diffmerge_create_my_files
+ dotest diffmerge1_mine "${testcvs} -q update -j tag" \
+"M testcase01
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase01,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase01
+M testcase02
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase02,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase02
+M testcase03
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase03,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase03
+M testcase04
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase04,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase04
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase05,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase05
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase06,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase06
+M testcase07
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase07,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase07
+testcase07 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1
+M testcase08
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase08,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase08
+M testcase09
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase09,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase09
+M testcase10
+RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase10,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.1\.1\.1\.2\.1
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase10"
+
+ # So if your changes didn't make it into my working copy, or
+ # in any case if the files do not look like the final text
+ # in the files in directory comp_me, then the test flunks:
+ cd ..
+ mkdir comp_me
+ cd comp_me
+ diffmerge_create_expected_files
+ cd ..
+ rm mine/.#*
+
+ # If you have GNU's version of diff, you may try
+ # uncommenting the following line which will give more
+ # fine-grained information about how cvs differed from the
+ # correct result:
+ #dotest diffmerge1_cmp "diff -u --recursive --exclude=CVS comp_me mine" ''
+ dotest diffmerge1_cmp "directory_cmp comp_me mine"
+
+ # Clean up after ourselves:
+ dokeep
+ cd ..
+ rm -r diffmerge1
+ modify_repo rm -rf $CVSROOT_DIRNAME/diffmerge1
+ ;;
+
+
+
+ diffmerge2)
+
+ # FIXME: This test should be rewritten to be much more concise.
+ # It currently weighs in at something like 600 lines, but the
+ # same thing could probably be tested in more like 50-100 lines.
+ mkdir diffmerge2
+
+ # This tests for another diffmerge bug reported by Martin
+ # Tomes; actually, his bug was probably caused by an initial
+ # fix for the bug in test diffmerge1, and likely wasn't ever
+ # a problem in CVS as long as one was using a normal
+ # distribution of diff or a version of CVS that has the diff
+ # lib in it.
+ #
+ # Nevertheless, once burned twice cautious, so we test for his
+ # bug here.
+ #
+ # Here is his report, more or less verbatim:
+ # ------------------------------------------
+ #
+ # Put the attached file (sgrid.h,v) into your repository
+ # somewhere, check out the module and do this:
+ #
+ # cvs update -j Review_Phase_2_Enhancements sgrid.h
+ # cvs diff -r Review_V1p3 sgrid.h
+ #
+ # As there have been no changes made on the trunk there
+ # should be no differences, however this is output:
+ #
+ # % cvs diff -r Review_V1p3 sgrid.h
+ # Index: sgrid.h
+ # ===================================================================
+ # RCS file: /usr/local/repository/play/fred/sgrid.h,v
+ # retrieving revision 1.1.2.1
+ # diff -r1.1.2.1 sgrid.h
+ # 178a179,184
+ # > /*--------------------------------------------------------------
+ # > INLINE FUNCTION : HORIZONTALLINES
+ # > NOTES : Description at the end of the file
+ # > ----------------------------------------------------------------*/
+ # > uint16 horizontalLines( void );
+ # >
+ #
+ # I did a cvs diff -c -r 1.1 -r 1.1.2.1 sgrid.h and patched those
+ # differences to sgrid.h version 1.1 and got the correct result
+ # so it looks like the built in patch is faulty.
+ # -------------------------------------------------------------------
+ #
+ # This is the RCS file, sgrid.h,v, that he sent:
+
+ echo "head 1.1;
+access;
+symbols
+ Review_V1p3:1.1.2.1
+ Review_V1p3C:1.1.2.1
+ Review_1p3A:1.1.2.1
+ Review_V1p3A:1.1.2.1
+ Review_Phase_2_Enhancements:1.1.0.2
+ Review_V1p2:1.1
+ Review_V1p2B:1.1
+ Review_V1p2A:1.1
+ Review_V1p1:1.1
+ Review_1p1:1.1;
+locks; strict;
+comment @ * @;
+
+
+1.1
+date 97.04.02.11.20.05; author colinl; state Exp;
+branches
+ 1.1.2.1;
+next ;
+
+1.1.2.1
+date 97.06.09.10.00.07; author colinl; state Exp;
+branches;
+next ;
+
+
+desc
+@@
+
+
+1.1
+log
+@Project: DEV1175
+DCN:
+Tested By: Colin Law
+Reviewed By:
+Reason for Change: Initial Revision of all files
+
+Design Change Details:
+
+Implications:
+@
+text
+@/* \$""Header: L:/gpanels/dis/sgrid.h_v 1.1.1.0 24 Jan 1996 14:59:20 PAULT \$ */
+/*
+ * \$""Log: L:/gpanels/dis/sgrid.h_v \$
+ *
+ * Rev 1.1.1.0 24 Jan 1996 14:59:20 PAULT
+ * Branched
+ *
+ * Rev 1.1 24 Jan 1996 12:09:52 PAULT
+ * Consolidated 4100 code merged to trunk
+ *
+ * Rev 1.0.2.0 01 Jun 1995 14:18:58 DAVEH
+ * Branched
+ *
+ * Rev 1.0 19 Apr 1995 16:32:48 COLINL
+ * Initial revision.
+*/
+/*****************************************************************************
+FILE : SGRID.H
+VERSION : 2.1
+AUTHOR : Dave Hartley
+SYSTEM : Borland C++
+DESCRIPTION : The declaration of the scrolling grid class
+
+*****************************************************************************/
+#if !defined(__SGRID_H)
+#define __SGRID_H
+
+#if !defined(__SCROLL_H)
+#include <scroll.h>
+#endif
+
+#if !defined(__GKI_H)
+#include \"gki.h\"
+#endif
+
+#if defined PRINTING_SUPPORT
+class Printer;
+#endif
+
+/*****************************************************************************
+CLASS : ScrollingGrid
+DESCRIPTION: This class inherits from a grid and a scrollable, and
+ can therefore use all the PUBLIC services provided by these
+ classes. A description of these can be found in
+ GRID.H and SCROLL.H.
+ A scrolling grid is a set of horizontal and vertical lines
+ that scroll and continually update to provide a complete grid
+
+*****************************************************************************/
+
+class ScrollingGrid : public Scrollable
+{
+ public:
+#if defined _WINDOWS
+/*---------------------------------------------------------------------------
+FUNCTION : CONSTRUCTOR
+DESCRIPTION : sets up the details of the grid, ready for painting
+ARGUMENTS : name : sgColour
+ - the colour of the grid
+ sgLineType
+ - the syle of line
+ sgHorizontalTotal
+ - the total number of horizontal grid lines
+ verticalSpacingMin
+ - the min distance between the vertical grid lines
+ on the scrolling axis
+ currentTimestamp
+ - timestamp value now
+ ticksPerSecond
+ - number of timestamp ticks per second
+ ticksPerPixel
+ - number of timestamp ticks per pixel required
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ ScrollingGrid( GkiColour sgColour, GkiLineType sgLineType,
+ uint16 sgHorizontalTotal,
+ uint16 verticalSpacingMin, uint32 currentTimestamp,
+ uint16 ticksPerSecond, uint32 ticksPerPixel );
+#else
+/*---------------------------------------------------------------------------
+FUNCTION : CONSTRUCTOR
+DESCRIPTION : sets up the details of the grid, ready for painting
+ARGUMENTS : name : sgColour
+ - the colour of the grid
+ sgLineType
+ - the syle of line
+ sgHorizontalTotal ( THE MAX NUMBER OF LINES IS 100 )
+ - the total number of horizontal grid lines
+ sgVerticalSpacing
+ - the distance between the vertical grid lines
+ on the scrolling axis
+
+RETURN : None
+NOTES : If the caller does not get the total grid lines value, synced
+ with the overall size of the viewport, the spacing between
+ grid lines will not be consistent.
+
+---------------------------------------------------------------------------*/
+ ScrollingGrid( GkiColour sgColour, GkiLineType sgLineType
+ , uint16 sgHorizontalTotal, uint16 sgVerticalSpacing );
+#endif
+/*---------------------------------------------------------------------------
+FUNCTION : DESTRUCTOR
+DESCRIPTION : tidies it all up
+ARGUMENTS : name :
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ ~ScrollingGrid( void );
+
+/*---------------------------------------------------------------------------
+FUNCTION : ATTACH
+DESCRIPTION : This service overloads the base class service, as it does
+ additional work at the time of attachment.
+
+ARGUMENTS : name : tDrawingArea
+ - the scrolled viewport to attach this trend to
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void attach( SViewport *tDrawingArea );
+
+#if defined _WINDOWS
+/*---------------------------------------------------------------------------
+FUNCTION : calculateVerticalSpacing
+DESCRIPTION : determines optimum spacing along time axis
+ARGUMENTS :
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void calculateVerticalSpacing();
+
+/*---------------------------------------------------------------------------
+FUNCTION : gridSpacingTicks
+DESCRIPTION : Provides the grid spacing in the time axis in ticks
+ARGUMENTS :
+RETURN : Number of ticks
+NOTES :
+---------------------------------------------------------------------------*/
+ uint32 gridSpacingTicks();
+
+#endif
+
+/*---------------------------------------------------------------------------
+INLINE FUNCTION : HORIZONTALLINES
+NOTES : Description at the end of the file
+---------------------------------------------------------------------------*/
+ uint16 horizontalLines( void );
+
+#if defined _WINDOWS
+// In Windows the OnDraw() function replaces paint()
+/*---------------------------------------------------------------------------
+FUNCTION : ScrollingGrid OnDraw
+DESCRIPTION : Paints the given area of the grid.
+ Pure virtual
+ARGUMENTS : pDC pointer to the device context to use for display
+ Note that the device context operates in the coords
+ of the window owning the viewport
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ virtual void OnDraw( CDC *pDC );
+
+#else // not Windows
+
+/*---------------------------------------------------------------------------
+FUNCTION : PAINT
+DESCRIPTION : This extends the standard grid paint method to paint the
+ viewport relative to its current position.
+
+ARGUMENTS : name :
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void paint( void );
+#endif
+
+/*---------------------------------------------------------------------------
+FUNCTION : P A I N T T E X T M A R K E R S
+DESCRIPTION : this service allow the text markers to be painted seperatley
+ from the grid lines
+
+ARGUMENTS : name :
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void paintTextMarkers();
+
+#if defined PRINTING_SUPPORT
+/*---------------------------------------------------------------------------
+FUNCTION : P R I N T
+DESCRIPTION : This print service prints a grid marker ( being either a
+ timestamp or a date, IF there is one at the plot position
+ given
+
+ARGUMENTS : name :
+ displayPosition
+ - Where in the log to look to see if there is an
+ entry to print
+
+ - printerPtr
+ the printer to print to
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void print( uint16 currentPrintPos, Printer *printerPtr );
+#endif
+
+/*---------------------------------------------------------------------------
+FUNCTION : S E T D R I V E D I R E C T I O N
+DESCRIPTION : Sets direction for update and scrolling forwards or backwards
+ARGUMENTS : direction - required direction
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void setDriveDirection( ScrollDirection direction );
+
+/*---------------------------------------------------------------------------
+FUNCTION : S E T U P
+DESCRIPTION : service that will setup the grid prior to a paint
+
+ARGUMENTS : name :
+ - newTimestamp
+
+
+ - newTimeBase
+ the number of ticks that represent a plot point on
+ the trendgraph.
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void setup( uint32 newTimestamp, uint32 newTimeBase );
+
+#if defined PRINTING_SUPPORT
+/*---------------------------------------------------------------------------
+FUNCTION : S E T U P F O R P R I N T
+DESCRIPTION : This service iis to be called prior to printing. It allows
+ the grid to prepare its markers ready for the print
+ commands
+
+ARGUMENTS : name :
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void setupForPrint();
+#endif
+
+/*---------------------------------------------------------------------------
+FUNCTION : UPDATE
+DESCRIPTION : When this service is called it will calculate what needs to
+ be painted and fill in the display again.
+
+ARGUMENTS : name : timeStamp
+ - the reference time of this update.
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void update( uint32 timeStamp );
+
+/*---------------------------------------------------------------------------
+FUNCTION : U P D A T E B U F F E R
+DESCRIPTION : When a display update is not required, use this method. It
+ updates the internal data ready for a call to paint that
+ will then show the grid in the right position
+
+ARGUMENTS : name :
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void updateBuffer( void );
+
+ private:
+
+/*---------------------------------------------------------------------------
+FUNCTION : M A K E G R I D M A R K E R
+DESCRIPTION : service that perpares a string for display. The string will
+ either be a short date, or short time. this is determined
+ by the current setting of the dateMarker flag
+
+ARGUMENTS : name : timestampVal
+ - the value to convert
+
+ storePtr
+ - the place to put the string
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void makeGridMarker( uint32 timestampVal, char *storePtr );
+
+/*---------------------------------------------------------------------------
+FUNCTION : P A I N T G R I D M A R K E R
+DESCRIPTION : given a position will put the string on the display
+
+ARGUMENTS : name :
+ yPos
+ - were it goes on the Y-axis
+
+ gridMarkerPtr
+ - what it is
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void paintGridMarker( uint16 yPos, char *gridMarkerPtr );
+
+#if defined _WINDOWS
+/*---------------------------------------------------------------------------
+FUNCTION : PAINTHORIZONTALLINES
+DESCRIPTION : responsible for painting the grids horizontal lines
+ARGUMENTS : pRectToDraw pointer to rectangle that needs refreshing.
+ in viewport coords
+ pDC pointer to device context to use
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void paintHorizontalLines(RectCoords* pRectToDraw, CDC* pDC );
+#else
+/*---------------------------------------------------------------------------
+FUNCTION : PAINTHORIZONTALLINES
+DESCRIPTION : responsible for painting the grids horizontal lines
+ARGUMENTS : name: xStart
+ - the starting X co-ordinate for the horizontal line
+ xEnd
+ - the ending X co-ordinate for the horizontal line
+
+RETURN : None
+NOTES : Remember lines are drawn from origin. The origin in a
+ horizontal viewport will be the top.
+---------------------------------------------------------------------------*/
+ void paintHorizontalLines( uint16 xStart, uint16 xEnd );
+#endif
+
+#if defined _WINDOWS
+/*---------------------------------------------------------------------------
+FUNCTION : PAINTVERTICALLINES
+DESCRIPTION : responsible for painting the grids vertical lines
+ARGUMENTS : pRectToDraw pointer to rectangle that needs refreshing.
+ in viewport coords
+ offset offset from rhs that rightmost line would be
+ drawn if rectangle included whole viewport
+ pDC pointer to device context to use
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void paintVerticalLines( RectCoords* pRectToDraw, uint16 offset,
+ CDC* pDC );
+#else
+/*---------------------------------------------------------------------------
+FUNCTION : PAINTVERTICALLINES
+DESCRIPTION : responsible for painting the grids vertical lines
+ARGUMENTS : name : yStart
+ - the starting Y co-ordinate for the vertical line
+ yEnd
+ - the ending Y co-ordinate for the vertical line
+ offset
+ - a starting point offset that determines at what X
+ position the first line will be drawn
+
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void paintVerticalLines( uint16 yStart, uint16 yEnd, uint16 offset );
+#endif
+
+#if defined _WINDOWS
+/*---------------------------------------------------------------------------
+FUNCTION : PAINTVERTICALLINE
+DESCRIPTION : paints one line at the position specified, and length
+ARGUMENTS : name : yStart
+ - the starting point on the y axis for the line
+ yEnd
+ - the end point on the y axis for the line
+ xPosition
+ - The horizontal offset from the start of the viewport
+ pDC pointer to device context to use
+
+RETURN : None
+NOTES : There is not an equivalent horizontal method as yet. This
+ is a seperate method because the service is useful to a
+ derivation of this class
+---------------------------------------------------------------------------*/
+ void paintVerticalLine( uint16 yStart, uint16 yEnd
+ , uint16 xPosition, CDC *pDC );
+#else
+/*---------------------------------------------------------------------------
+FUNCTION : PAINTVERTICALLINE
+DESCRIPTION : paints one line at the position specified, and length
+ARGUMENTS : name : yStart
+ - the starting point on the y axis for the line
+ yEnd
+ - the end point on the y axis for the line
+ xPosition
+ - The horizontal offset from the start of the viewport
+
+RETURN : None
+NOTES : There is not an equivalent horizontal method as yet. This
+ is a seperate method because the service is useful to a
+ derivation of this class
+---------------------------------------------------------------------------*/
+ void paintVerticalLine( uint16 yStart, uint16 yEnd
+ , uint16 xPosition );
+#endif
+
+/*---------------------------------------------------------------------------
+INLINE FUNCTION : VERTICALSPACING
+NOTES : Description at the end of the file
+---------------------------------------------------------------------------*/
+ uint16 verticalSpacing( void );
+
+
+ // Position in viewport that we are now writing to if going forwards
+ // Note that if this is greater than viewport length then we have
+ // just scrolled and value must be adjusted before use.
+ sint16 forwardsOutputPosition;
+
+ // Position in viewport that we are now writing to if going backwards
+ // Note that if this is less than zero then we have
+ // just scrolled and value must be adjusted before use.
+ sint16 backwardsOutputPosition;
+
+ // position in grid cycle of forwards output position.
+ // if zero then it is time to output a grid line
+ sint16 forwardsIntervalCount;
+
+ // position in grid cycle of forwards output position.
+ // if zero then it is time to output a grid line
+ sint16 backwardsIntervalCount;
+
+ uint32 lastUpdateTimestamp;
+ uint32 timeBase; // ticks per pixel
+ uint16 currentOutputPosition;
+ uint16 gridTimestampSpacing;
+ uint16 intervalCount;
+ uint16 horizontalTotal;
+ uint16 vSpacing;
+#if defined PRINTING_SUPPORT
+ uint16 numberOfGridMarkersPrinted;
+#endif
+ bool firstTime; // indicates first time through
+ bool dateMarker;
+
+ GkiLineType lineType;
+ GkiColour gridColour;
+
+ #if defined _WINDOWS
+ uint16 ticksPerSec; // number of time ticks per second
+ uint16 vSpacingMin; // minimum pixels per division along time axis
+ CPen *pPen; // the pen to use for drawing in windows
+ #endif
+
+};
+
+
+/*****************************************************************************
+ I N L I N E F U N C T I O N S
+*****************************************************************************/
+
+/*---------------------------------------------------------------------------
+FUNCTION : HORIZONTALLINES
+DESCRIPTION : supplies the number of horizontal lines in the grid
+ARGUMENTS : name :
+
+RETURN :
+NOTES :
+---------------------------------------------------------------------------*/
+inline uint16 ScrollingGrid::horizontalLines( void )
+{
+ return( horizontalTotal );
+}
+/*---------------------------------------------------------------------------
+FUNCTION : VERTICALSPACING
+DESCRIPTION : returns the distance between adjacent vertical lines
+ARGUMENTS : name :
+
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+inline uint16 ScrollingGrid::verticalSpacing( void )
+{
+ return( vSpacing );
+}
+
+#endif
+@
+
+
+1.1.2.1
+log
+@DEV1194:DS4 Provision of major and minor grid lines
+@
+text
+@d1 1
+a1 1
+/* \$""Header: /usr/local/repository/cmnsrc/review/src/sgrid.h,v 1.1 1997/04/02 11:20:05 colinl Exp \$ */
+d3 1
+a3 12
+ * \$""Log: sgrid.h,v \$
+ * Revision 1.1 1997/04/02 11:20:05 colinl
+ * Project: DEV1175
+ * DCN:
+ * Tested By: Colin Law
+ * Reviewed By:
+ * Reason for Change: Initial Revision of all files
+ *
+ * Design Change Details:
+ *
+ * Implications:
+ *
+d58 6
+a63 5
+ARGUMENTS : name : majorColour colour for major grid lines
+ minorColour colour for minor grid lines
+ sgLineType line type for minor grid lines
+ yMajorGridLines number of major y lines on grid
+ yMinorGridLines number of major y lines on grid
+d77 2
+a78 3
+ ScrollingGrid( GkiColour majorColour, GkiColour minorColour,
+ GkiLineType sgLineType,
+ uint16 yMajorGridLines, uint16 yMinorGridLines,
+a137 17
+FUNCTION : DrawHorizontalGridLines
+
+DESCRIPTION : Draws major or minor grid lines
+ARGUMENTS : pDC device context
+ pPen pen to use
+ numLines total lines required
+ yLow, yHigh, xLow, xHigh rectangle to draw in
+ yMax max y value
+RETURN : None
+NOTES :
+---------------------------------------------------------------------------*/
+ void DrawHorizontalGridLines( CDC* pDC, CPen* pPen,
+ uint16 numLines,
+ uint16 yLow, uint16 yHigh, uint16 xLow, uint16 xHigh,
+ uint16 yMax );
+
+/*---------------------------------------------------------------------------
+d148 6
+d448 1
+a448 2
+ uint16 m_yMajorGridLines;
+ uint16 m_yMinorGridLines;
+d456 2
+a457 3
+ GkiLineType lineType; // line type for minor grid lines
+ GkiColour m_majorColour;
+ GkiColour m_minorColour;
+d462 1
+a462 2
+ CPen *pMajorPen; // pen to use for drawing major grid lines
+ CPen *pMinorPen; // pen to use for drawing minor grid lines
+d472 12
+@" > diffmerge2/sgrid.h,v
+
+ # We have to put the RCS file in the repository by hand for
+ # this test:
+ modify_repo mkdir $CVSROOT_DIRNAME/diffmerge2
+ modify_repo cp diffmerge2/sgrid.h,v \
+ $CVSROOT_DIRNAME/diffmerge2/sgrid.h,v
+ rm -rf diffmerge2
+ dotest diffmerge2_co \
+ "$testcvs co diffmerge2" "${DOTSTAR}U $DOTSTAR"
+ cd diffmerge2
+ dotest diffmerge2_update \
+ "${testcvs} update -j Review_Phase_2_Enhancements sgrid.h" \
+ "${DOTSTAR}erging ${DOTSTAR}"
+ # This is the one that counts -- there should be no output:
+ dotest diffmerge2_diff \
+ "${testcvs} diff -r Review_V1p3 sgrid.h" ''
+
+ dokeep
+ cd ..
+ rm -rf diffmerge2
+ modify_repo rm -rf $CVSROOT_DIRNAME/diffmerge2
+ ;;
+
+
+
+ release)
+ # Tests of "cvs release", particularly multiple arguments.
+ # Other CVS release tests:
+ # info-cleanup-0 for "cvs -n release".
+ # ignore-193 for the text of the question that cvs release asks.
+ # Also for interactions with cvsignore.
+ # basicc: "-d .", global -Q, no arguments (is a noop),
+ # "cvs release" without -d, multiple arguments.
+ # dirs-4: repository directory has been deleted.
+ # modules2-6: multiple arguments.
+
+ # First the usual setup; create a directory first-dir.
+ mkdir 1; cd 1
+ dotest release-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest release-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ mkdir dir1
+ dotest release-3 "${testcvs} add dir1" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository"
+ mkdir dir2
+ dotest release-4 "${testcvs} add dir2" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir2 added to the repository"
+ cd dir2
+ mkdir dir3
+ dotest release-5 "${testcvs} add dir3" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir2/dir3 added to the repository"
+
+ cd ../..
+ dotest release-6 "${testcvs} release -d first-dir/dir2/dir3 first-dir/dir1" \
+"You have .0. altered files in this repository.
+Are you sure you want to release (and delete) directory .first-dir/dir2/dir3.: \
+You have .0. altered files in this repository.
+Are you sure you want to release (and delete) directory .first-dir/dir1.: " <<EOF
+yes
+yes
+EOF
+ dotest_fail release-7 "test -d first-dir/dir1" ''
+ dotest_fail release-8 "test -d first-dir/dir2/dir3" ''
+ dotest release-9 "${testcvs} update" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating first-dir
+${SPROG} update: Updating first-dir/dir2"
+
+ cd first-dir
+ mkdir dir1
+ dotest release-10 "${testcvs} add dir1" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository"
+ cd dir2
+ mkdir dir3
+ dotest release-11 "${testcvs} add dir3" \
+"Directory ${CVSROOT_DIRNAME}/first-dir/dir2/dir3 added to the repository"
+
+ cd ../..
+ dotest release-12 "${testcvs} release first-dir/dir2/dir3 first-dir/dir1" \
+"You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir2/dir3.: .. .release. aborted by user choice.
+You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir1.: " <<EOF
+no
+yes
+EOF
+ dotest release-13 "${testcvs} release first-dir/dir2/dir3 first-dir/dir2" \
+"You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir2/dir3.: \
+You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir2.: " <<EOF
+yes
+yes
+EOF
+ dotest release-14 "test -d first-dir/dir1" ''
+ dotest release-15 "test -d first-dir/dir2/dir3" ''
+
+ mkdir first-dir/dir1/dir4
+ # FIXCVS: There should be a path showing in front of dir below,
+ # I believe.
+ dotest release-unrecognized-dir-1 \
+"${testcvs} release -d first-dir/dir1" \
+"${QUESTION} dir4
+You have .0. altered files in this repository.
+Are you sure you want to release (and delete) directory \`first-dir/dir1': " <<EOF
+yes
+EOF
+
+ rm -rf first-dir/dir2
+
+ dotest release-16 "${testcvs} update" \
+"$SPROG update: Updating \.
+$SPROG update: Updating first-dir"
+
+ # Check to make sure release isn't overwriting a
+ # CVS/Entries file in the current directory (using data
+ # from the released directory).
+
+ # cvs 1.11 (remote) fails on release-21 (a message about
+ # chdir into the removed directory), although it seemingly
+ # unedits and removes the directory correctly. If
+ # you manually continue, it then fails on release-22 do
+ # to the messed up CVS/Entries file from release-21.
+ cd first-dir
+ mkdir second-dir
+ dotest release-18 "$testcvs add second-dir" \
+"Directory $CVSROOT_DIRNAME/first-dir/second-dir added to the repository"
+
+ cd second-dir
+ touch file1
+ dotest release-19 "$testcvs -Q add file1"
+ dotest release-20 '$testcvs -q ci -m add' \
+"$CVSROOT_DIRNAME/first-dir/second-dir/file1,v <-- file1
+initial revision: 1\.1"
+ dotest release-21 "$testcvs edit file1"
+ cd ..
+ dotest release-22 "echo yes | $testcvs release -d second-dir" \
+"You have \[0\] altered files in this repository.
+Are you sure you want to release (and delete) directory \`second-dir': "
+ dotest release-23 "$testcvs -q update -d" "U second-dir/file1"
+ dotest release-24 "$testcvs edit"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ modify_repo rm -rf 1 $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ recase)
+ #
+ # Some tests of behavior which broke at one time or another when run
+ # from case insensitive clients against case sensitive servers.
+ #
+ # These tests are namned according to the following convention:
+ #
+ # ci Client (sandbox filesystem) case Insensitive
+ # cs Client (sandbox filesystem) case Sensitive
+ # si Server (repository filesystem) case Insensitive
+ # ss Server (repository filesystem) case Sensitive
+ #
+
+ mkdir 1; cd 1
+
+ # First, we will expect different results for a few of these tests
+ # based on whether the repository is on a case sensitive filesystem
+ # or not and whether the sandbox is on a case sensitive filesystem or
+ # not, so determine which cases we are dealing with:
+ echo file >file
+ echo FiLe >FiLe
+ if cmp file FiLe >/dev/null; then
+ client_sensitive=false
+ else
+ client_sensitive=:
+ fi
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost 'echo file >file'
+ $CVS_RSH $remotehost 'echo FiLe >FiLe'
+ if $CVS_RSH $remotehost 'cmp file FiLe >/dev/null'; then
+ server_sensitive=false
+ else
+ server_sensitive=:
+ fi
+ else
+ server_sensitive=$client_sensitive
+ fi
+
+ # The first test (recase-1 & recase-2) is for a remove of a file then
+ # a readd in a different case.
+ modify_repo mkdir $CVSROOT_DIRNAME/first-dir
+ dotest recase-init-1 "$testcvs -Q co first-dir"
+ cd first-dir
+
+ echo this file has no content >file
+ dotest recase-init-2 "$testcvs -Q add file"
+ dotest recase-init-3 "$testcvs -Q ci -madd"
+ dotest recase-init-4 "$testcvs -Q tag first"
+
+ # Now remove the file.
+ dotest recase-init-5 "$testcvs -Q rm -f file"
+ dotest recase-init-6 "$testcvs -Q ci -mrm"
+
+ # Now the test - readd in a different case.
+ echo this file needs some content >FiLe
+ if $server_sensitive; then
+ dotest recase-1ss "$testcvs add FiLe" \
+"$SPROG add: scheduling file \`FiLe' for addition
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+ dotest recase-2ss "$testcvs -q ci -mrecase" \
+"$CVSROOT_DIRNAME/first-dir/FiLe,v <-- FiLe
+initial revision: 1\.1"
+ else # server insensitive
+ dotest recase-1si "$testcvs add FiLe" \
+"$SPROG add: Re-adding file \`FiLe' after dead revision 1\.2\.
+$SPROG add: use \`$SPROG commit' to add this file permanently"
+ dotest recase-2si "$testcvs -q ci -mrecase" \
+"$CVSROOT_DIRNAME/first-dir/FiLe,v <-- FiLe
+new revision: 1\.3; previous revision: 1\.2"
+ fi
+
+ # Now verify that a checkout will still work
+ cd ../..
+ mkdir 2; cd 2
+ dotest recase-3 "$testcvs -q co first-dir" \
+"U first-dir/FiLe"
+
+ cd first-dir
+ # Prove that we can still get status and log information on
+ # conflicting case files (1 in Attic, one in parent).
+ if $remote; then
+ if $client_sensitive; then
+ file=file
+ fIlE=fIlE
+ else # client insensitive
+ # Because FiLe is present on a case insensitive client, it is the
+ # only one ever found and queried or altered.
+ file=FiLe
+ fIlE=FiLe
+ fi
+ else # ! $remote
+ file=file
+ fIlE=fIlE
+ fi
+ if $server_sensitive; then
+ if $client_sensitive; then
+ # Client finds Entry only for FiLe. Others returned by server.
+ dotest recase-4sscs "$testcvs status file" \
+"===================================================================
+File: no file file Status: Up-to-date
+
+ Working revision: No entry for file
+ Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/Attic/file,v
+ Commit Identifier: ${commitid}"
+ dotest recase-5sscs "$testcvs log file" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/Attic/file,v
+Working file: file
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ first: 1\.1
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: $username; state: dead; lines: +0 -0; commitid: ${commitid};
+rm
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+ dotest recase-6sscs "$testcvs status FiLe" \
+"===================================================================
+File: FiLe Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-7sscs "$testcvs log FiLe" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v
+Working file: FiLe
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+recase
+============================================================================="
+ else # server sensitive && client insensitive
+ # Client finds same Entry for file & FiLe.
+ dotest recase-4ssci "$testcvs status file" \
+"===================================================================
+File: FiLe Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-5ssci "$testcvs log file" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v
+Working file: FiLe
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+recase
+============================================================================="
+ dotest recase-6ss "$testcvs status FiLe" \
+"===================================================================
+File: FiLe Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-7ss "$testcvs log FiLe" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v
+Working file: FiLe
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+recase
+============================================================================="
+ fi
+ else # server insensitive
+ # There is only one archive when the server is insensitive, but the
+ # printed file/archive name can vary.
+ dotest recase-4si "$testcvs status file" \
+"===================================================================
+File: $file Status: Up-to-date
+
+ Working revision: 1\.3.*
+ Repository revision: 1\.3 $CVSROOT_DIRNAME/first-dir/$file,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-5si "$testcvs log file" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/$file,v
+Working file: $file
+head: 1\.3
+branch:
+locks: strict
+access list:
+symbolic names:
+ first: 1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: $username; state: Exp; lines: +1 -1; commitid: ${commitid};
+recase
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: $username; state: dead; lines: +0 -0; commitid: ${commitid};
+rm
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+ dotest recase-6si "$testcvs status FiLe" \
+"===================================================================
+File: FiLe Status: Up-to-date
+
+ Working revision: 1\.3.*
+ Repository revision: 1\.3 $CVSROOT_DIRNAME/first-dir/FiLe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-7si "$testcvs log FiLe" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v
+Working file: FiLe
+head: 1\.3
+branch:
+locks: strict
+access list:
+symbolic names:
+ first: 1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.3
+date: ${ISO8601DATE}; author: $username; state: Exp; lines: +1 -1; commitid: ${commitid};
+recase
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: $username; state: dead; lines: +0 -0; commitid: ${commitid};
+rm
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+ fi
+
+ # And when the file does not exist on the client, we go with the
+ # client Entries match.
+ if $client_sensitive && $server_sensitive; then
+ dotest recase-8sscs "$testcvs status fIlE" \
+"$SPROG status: nothing known about \`fIlE'
+===================================================================
+File: no file fIlE Status: Unknown
+
+ Working revision: No entry for fIlE
+ Repository revision: No revision control file"
+ else # !$client_sensitive || !$server_sensitive
+ dotest recase-8anyi "$testcvs status fIlE" \
+"===================================================================
+File: $fIlE Status: Up-to-date
+
+ Working revision: 1\.[0-9]*.*
+ Repository revision: 1\.[0-9]* $CVSROOT_DIRNAME/first-dir/$fIlE,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ fi
+
+ # and an update
+ if $server_sensitive; then
+ dotest recase-9ss "$testcvs -q up -rfirst" \
+"$SPROG update: \`FiLe' is no longer in the repository
+U file"
+
+ if $client_sensitive; then
+ dotest recase-10sscs "$testcvs -q up -A" \
+"U FiLe
+$SPROG update: \`file' is no longer in the repository"
+ else # client insensitive
+ # FIXCVS: This should remove the offending file first.
+ dotest_fail recase-10ssci "$testcvs -q up -A" \
+"$SPROG update: move away \`\./FiLe'; it is in the way
+C FiLe
+$SPROG update: \`file' is no longer in the repository"
+
+ cd ..
+ rm -r first-dir
+ dotest recase-11ssci "$testcvs -q co first-dir" \
+"U first-dir/FiLe"
+ cd first-dir
+ fi
+
+ #
+ # See what happens when cased names clash.
+ #
+
+ # Copy the archive
+ if test -n "$remotehost"; then
+ modify_repo $CVS_RSH $remotehost \
+ "cp $CVSROOT_DIRNAME/first-dir/FiLe,v \
+ $CVSROOT_DIRNAME/first-dir/FILE,v"
+ else
+ modify_repo cp $CVSROOT_DIRNAME/first-dir/FiLe,v \
+ $CVSROOT_DIRNAME/first-dir/FILE,v
+ fi
+
+ if $client_sensitive; then
+ dotest recase-12sscs "$testcvs -q up" "U FILE"
+ else # client insensitive
+ dotest_fail recase-12ssci "$testcvs -q up" \
+"$SPROG update: move away \`\./FILE'; it is in the way
+C FILE"
+ fi
+ else # server insensitive
+ dotest recase-9si "$testcvs -q up -rfirst" "U FiLe"
+ dotest recase-10si "$testcvs -q up -A" "U FiLe"
+ fi
+
+ # Prove that we can still get status and log information on
+ # conflicting case files (1 in Attic, two in parent).
+ if $server_sensitive; then
+ if $client_sensitive; then
+ # Client finds Entry only for FiLe. Others returned by server.
+ dotest recase-13sscs "$testcvs status file" \
+"===================================================================
+File: no file file Status: Up-to-date
+
+ Working revision: No entry for file
+ Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/Attic/file,v
+ Commit Identifier: ${commitid}"
+ dotest recase-14sscs "$testcvs log file" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/Attic/file,v
+Working file: file
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ first: 1\.1
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: $username; state: dead; lines: +0 -0; commitid: ${commitid};
+rm
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+add
+============================================================================="
+ dotest recase-15sscs "$testcvs status FiLe" \
+"===================================================================
+File: FiLe Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-16sscs "$testcvs log FiLe" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v
+Working file: FiLe
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+recase
+============================================================================="
+ dotest recase-17sscs "$testcvs status FILE" \
+"===================================================================
+File: FILE Status: Up-to-date
+
+ Working revision: 1.1.*
+ Repository revision: 1.1 ${CVSROOT_DIRNAME}/first-dir/FILE,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-18sscs "$testcvs log FILE" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FILE,v
+Working file: FILE
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+recase
+============================================================================="
+ else # $server_sensitive && !$client_sensitive
+ # Client finds same Entry for file & FiLe.
+ dotest recase-13ssci "$testcvs status file" \
+"===================================================================
+File: FiLe Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-16ssci "$testcvs log FiLe" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v
+Working file: FiLe
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+recase
+============================================================================="
+ dotest recase-17ssci "$testcvs status FILE" \
+"===================================================================
+File: FiLe Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ dotest recase-18ssci "$testcvs log FILE" \
+"
+RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v
+Working file: FiLe
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: $username; state: Exp; commitid: ${commitid};
+recase
+============================================================================="
+ fi
+ else # !$server_sensitive
+ # Skip these when the server is case insensitive - nothing
+ # has changed since recase-[4-7]si
+ :
+ fi
+
+ if $client_sensitive && $server_sensitive; then
+ dotest recase-19sscs "$testcvs status fIlE" \
+"$SPROG status: nothing known about \`fIlE'
+===================================================================
+File: no file fIlE Status: Unknown
+
+ Working revision: No entry for fIlE
+ Repository revision: No revision control file"
+ else # !$client_sensitive || !$server_sensitive
+ dotest recase-19anyi "$testcvs status fIlE" \
+"===================================================================
+File: $fIlE Status: Up-to-date
+
+ Working revision: 1\.[0-9]*.*
+ Repository revision: 1\.[0-9]* $CVSROOT_DIRNAME/first-dir/$fIlE,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)"
+ fi
+
+ # And last but not least, prove that a checkout is still possible.
+ cd ../..
+ mkdir 3; cd 3
+ if $server_sensitive; then
+ if $client_sensitive; then
+ dotest recase-20sscs "$testcvs -q co first-dir" \
+"U first-dir/FILE
+U first-dir/FiLe"
+ else # $server_senstive && !$client_sensitive
+ dotest_fail recase-20ssci "$testcvs -q co first-dir" \
+"U first-dir/FILE
+$SPROG checkout: move away \`first-dir/FiLe'; it is in the way
+C first-dir/FiLe"
+ fi
+ else # !$server_sensitive
+ # Skip these since nothing has changed.
+ :
+ fi
+
+ dokeep
+ cd ..
+ rm -r 1 2 3
+ if $server_sensitive && test -n "$remotehost"; then
+ # It is necessary to remove one of the case-conflicted files before
+ # recursively removing the rest under Cygwin on a Samba share or
+ # Samba returns a permission denied error due to its case
+ # confusion.
+ $CVS_RSH $remotehost "rm -f $CVSROOT_DIRNAME/first-dir/FILE,v"
+ fi
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ multiroot)
+ #
+ # set up two repositories
+ #
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ CVSROOT1_DIRNAME=${TESTDIR}/root.1
+ CVSROOT2_DIRNAME=${TESTDIR}/root.2
+ CVSROOT1=`newroot $CVSROOT1_DIRNAME`
+ CVSROOT2=`newroot $CVSROOT2_DIRNAME`
+ testcvs1="$testcvs -d '$CVSROOT1'"
+ testcvs2="$testcvs -d '$CVSROOT2'"
+
+ dotest multiroot-setup-1 "mkdir $CVSROOT1_DIRNAME $CVSROOT2_DIRNAME"
+ dotest multiroot-setup-2 "$testcvs1 init"
+ dotest multiroot-setup-3 "$testcvs2 init"
+
+ #
+ # create some directories in ${CVSROOT1_DIRNAME}
+ #
+ mkdir 1; cd 1
+ dotest multiroot-setup-4 "${testcvs1} co -l ." "${SPROG} checkout: Updating ."
+ mkdir mod1-1 mod1-2
+ dotest multiroot-setup-5 "${testcvs1} add mod1-1 mod1-2" \
+"Directory ${CVSROOT1_DIRNAME}/mod1-1 added to the repository
+Directory ${CVSROOT1_DIRNAME}/mod1-2 added to the repository"
+ echo file1-1 > mod1-1/file1-1
+ echo file1-2 > mod1-2/file1-2
+ dotest multiroot-setup-6 "${testcvs1} add mod1-1/file1-1 mod1-2/file1-2" \
+"${SPROG} add: scheduling file .mod1-1/file1-1. for addition
+${SPROG} add: scheduling file .mod1-2/file1-2. for addition
+${SPROG} add: use \`${SPROG} commit' to add these files permanently"
+ dotest multiroot-setup-7 "${testcvs1} commit -m is" \
+"${CPROG} commit: Examining \.
+${CPROG} commit: Examining mod1-1
+${CPROG} commit: Examining mod1-2
+${CVSROOT1_DIRNAME}/mod1-1/file1-1,v <-- mod1-1/file1-1
+initial revision: 1.1
+${CVSROOT1_DIRNAME}/mod1-2/file1-2,v <-- mod1-2/file1-2
+initial revision: 1.1"
+ cd ..
+ rm -rf 1
+
+ #
+ # create some directories in ${CVSROOT2_DIRNAME}
+ #
+ mkdir 1; cd 1
+ dotest multiroot-setup-8 "${testcvs2} co -l ." "${SPROG} checkout: Updating ."
+ mkdir mod2-1 mod2-2
+ dotest multiroot-setup-9 "${testcvs2} add mod2-1 mod2-2" \
+"Directory ${CVSROOT2_DIRNAME}/mod2-1 added to the repository
+Directory ${CVSROOT2_DIRNAME}/mod2-2 added to the repository"
+ echo file2-1 > mod2-1/file2-1
+ echo file2-2 > mod2-2/file2-2
+ dotest multiroot-setup-6 "${testcvs2} add mod2-1/file2-1 mod2-2/file2-2" \
+"${SPROG} add: scheduling file .mod2-1/file2-1. for addition
+${SPROG} add: scheduling file .mod2-2/file2-2. for addition
+${SPROG} add: use \`${SPROG} commit' to add these files permanently"
+ dotest multiroot-setup-10 "${testcvs2} commit -m anyone" \
+"${CPROG} commit: Examining \.
+${CPROG} commit: Examining mod2-1
+${CPROG} commit: Examining mod2-2
+${CVSROOT2_DIRNAME}/mod2-1/file2-1,v <-- mod2-1/file2-1
+initial revision: 1.1
+${CVSROOT2_DIRNAME}/mod2-2/file2-2,v <-- mod2-2/file2-2
+initial revision: 1.1"
+ cd ..
+ rm -rf 1
+
+ # check out a few directories, from simple/shallow to
+ # complex/deep
+ mkdir 1; cd 1
+
+ # OK, this case is kind of weird. If we just run things from
+ # here, without CVS/Root, then CVS will contact the server
+ # mentioned in CVSROOT (which is irrelevant) which will print
+ # some messages. Our workaround is to make sure we have a
+ # CVS/Root file at top level. In the future, it is possible
+ # the best behavior will be to extend the existing behavior
+ # ("being called from a directory without CVS administration
+ # has always meant to process each of the sub-dirs") to also
+ # do that if there is no CVSROOT, CVS/Root, or -d at top level.
+ #
+ # The local case could stumble through the tests without creating
+ # the top-level CVS/Root, but we create it for local and for
+ # remote to reduce special cases later in the test.
+ dotest multiroot-workaround "${testcvs1} -q co -l ." ""
+
+ dotest multiroot-setup-11 "${testcvs1} co mod1-1 mod1-2" \
+"${SPROG} checkout: Updating mod1-1
+U mod1-1/file1-1
+${SPROG} checkout: Updating mod1-2
+U mod1-2/file1-2"
+ dotest multiroot-setup-12 "${testcvs2} co mod2-1 mod2-2" \
+"${SPROG} checkout: Updating mod2-1
+U mod2-1/file2-1
+${SPROG} checkout: Updating mod2-2
+U mod2-2/file2-2"
+ cd mod1-2
+ dotest multiroot-setup-13 "${testcvs2} co mod2-2" \
+"${SPROG} checkout: Updating mod2-2
+U mod2-2/file2-2"
+ cd ..
+ cd mod2-2
+ dotest multiroot-setup-14 "${testcvs1} co mod1-2" \
+"${SPROG} checkout: Updating mod1-2
+U mod1-2/file1-2"
+ cd ..
+
+ #
+ # Make sure that the Root and Repository files contain the
+ # correct information.
+ #
+ dotest multiroot-cvsadm-1a "cat mod1-1/CVS/Root" "${CVSROOT1}"
+ dotest multiroot-cvsadm-1b "cat mod1-1/CVS/Repository" "mod1-1"
+ dotest multiroot-cvsadm-2a "cat mod2-1/CVS/Root" "${CVSROOT2}"
+ dotest multiroot-cvsadm-2b "cat mod2-1/CVS/Repository" "mod2-1"
+ dotest multiroot-cvsadm-3a "cat mod1-2/CVS/Root" "${CVSROOT1}"
+ dotest multiroot-cvsadm-3b "cat mod1-2/CVS/Repository" "mod1-2"
+ dotest multiroot-cvsadm-3c "cat mod1-2/mod2-2/CVS/Root" "${CVSROOT2}"
+ dotest multiroot-cvsadm-3d "cat mod1-2/mod2-2/CVS/Repository" "mod2-2"
+ dotest multiroot-cvsadm-4a "cat mod2-2/CVS/Root" "${CVSROOT2}"
+ dotest multiroot-cvsadm-4b "cat mod2-2/CVS/Repository" "mod2-2"
+ dotest multiroot-cvsadm-4c "cat mod2-2/mod1-2/CVS/Root" "${CVSROOT1}"
+ dotest multiroot-cvsadm-4d "cat mod2-2/mod1-2/CVS/Repository" "mod1-2"
+
+ #
+ # Start testing various cvs commands. Begin with commands
+ # without extra arguments (e.g. "cvs update", "cvs diff",
+ # etc.
+ #
+
+ # Do at least one command with both CVSROOTs to make sure
+ # that there's not some kind of unexpected dependency on the
+ # choice of which CVSROOT is specified on the command line.
+
+ dotest multiroot-update-1a "${testcvs1} update" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating mod1-1
+${SPROG} update: Updating mod1-2
+${SPROG} update: Updating mod1-2/mod2-2
+${SPROG} update: cannot open directory ${CVSROOT1_DIRNAME}/mod2-2: No such file or directory
+${SPROG} update: skipping directory mod1-2/mod2-2
+${SPROG} update: Updating mod2-1
+${SPROG} update: cannot open directory ${CVSROOT1_DIRNAME}/mod2-1: No such file or directory
+${SPROG} update: skipping directory mod2-1
+${SPROG} update: Updating mod2-2
+${SPROG} update: cannot open directory ${CVSROOT1_DIRNAME}/mod2-2: No such file or directory
+${SPROG} update: skipping directory mod2-2"
+
+ # Same deal but with -d ${CVSROOT2}.
+ dotest multiroot-update-1b "${testcvs2} update" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating mod1-1
+${SPROG} update: cannot open directory ${CVSROOT2_DIRNAME}/mod1-1: No such file or directory
+${SPROG} update: skipping directory mod1-1
+${SPROG} update: Updating mod1-2
+${SPROG} update: cannot open directory ${CVSROOT2_DIRNAME}/mod1-2: No such file or directory
+${SPROG} update: skipping directory mod1-2
+${SPROG} update: Updating mod2-1
+${SPROG} update: Updating mod2-2
+${SPROG} update: Updating mod2-2/mod1-2
+${SPROG} update: cannot open directory ${CVSROOT2_DIRNAME}/mod1-2: No such file or directory
+${SPROG} update: skipping directory mod2-2/mod1-2"
+
+ # modify all files and do a diff
+
+ echo bobby >> mod1-1/file1-1
+ echo brown >> mod1-2/file1-2
+ echo goes >> mod2-1/file2-1
+ echo down >> mod2-2/file2-2
+
+ dotest_fail multiroot-diff-1 "${testcvs} diff" \
+"${SPROG} diff: Diffing \.
+${SPROG} diff: Diffing mod1-1
+Index: mod1-1/file1-1
+===================================================================
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+retrieving revision 1\.1
+diff -r1\.1 file1-1
+1a2
+> bobby
+${SPROG} diff: Diffing mod1-2
+Index: mod1-2/file1-2
+===================================================================
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+retrieving revision 1\.1
+diff -r1\.1 file1-2
+1a2
+> brown
+${SPROG} diff: Diffing mod2-2/mod1-2
+${SPROG} diff: Diffing mod1-2/mod2-2
+${SPROG} diff: Diffing mod2-1
+Index: mod2-1/file2-1
+===================================================================
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+retrieving revision 1\.1
+diff -r1\.1 file2-1
+1a2
+> goes
+${SPROG} diff: Diffing mod2-2
+Index: mod2-2/file2-2
+===================================================================
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+retrieving revision 1\.1
+diff -r1\.1 file2-2
+1a2
+> down" \
+"${SPROG} diff: Diffing \.
+${SPROG} diff: Diffing mod1-1
+Index: mod1-1/file1-1
+===================================================================
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+retrieving revision 1\.1
+diff -r1\.1 file1-1
+1a2
+> bobby
+${SPROG} diff: Diffing mod1-2
+Index: mod1-2/file1-2
+===================================================================
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+retrieving revision 1\.1
+diff -r1\.1 file1-2
+1a2
+> brown
+${SPROG} diff: Diffing mod2-2
+${SPROG} diff: Diffing mod2-2/mod1-2
+${SPROG} diff: Diffing mod1-2
+${SPROG} diff: Diffing mod1-2/mod2-2
+${SPROG} diff: Diffing mod2-1
+Index: mod2-1/file2-1
+===================================================================
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+retrieving revision 1\.1
+diff -r1\.1 file2-1
+1a2
+> goes
+${SPROG} diff: Diffing mod2-2
+Index: mod2-2/file2-2
+===================================================================
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+retrieving revision 1\.1
+diff -r1\.1 file2-2
+1a2
+> down"
+
+ dotest multiroot-commit-1 "${testcvs} commit -m actually" \
+"${CPROG} commit: Examining \.
+${CPROG} commit: Examining mod1-1
+${CPROG} commit: Examining mod1-2
+${CPROG} commit: Examining mod2-2/mod1-2
+${CVSROOT1_DIRNAME}/mod1-1/file1-1,v <-- mod1-1/file1-1
+new revision: 1.2; previous revision: 1.1
+${CVSROOT1_DIRNAME}/mod1-2/file1-2,v <-- mod1-2/file1-2
+new revision: 1.2; previous revision: 1.1
+${CPROG} commit: Examining mod1-2/mod2-2
+${CPROG} commit: Examining mod2-1
+${CPROG} commit: Examining mod2-2
+${CVSROOT2_DIRNAME}/mod2-1/file2-1,v <-- mod2-1/file2-1
+new revision: 1.2; previous revision: 1.1
+${CVSROOT2_DIRNAME}/mod2-2/file2-2,v <-- mod2-2/file2-2
+new revision: 1.2; previous revision: 1.1"
+
+ dotest multiroot-update-2 "${testcvs} update" \
+"${CPROG} update: Updating \.
+${CPROG} update: Updating mod1-1
+${CPROG} update: Updating mod1-2
+${CPROG} update: Updating mod2-2/mod1-2
+U mod2-2/mod1-2/file1-2
+${CPROG} update: Updating mod1-2/mod2-2
+U mod1-2/mod2-2/file2-2
+${CPROG} update: Updating mod2-1
+${CPROG} update: Updating mod2-2" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating mod1-1
+${SPROG} update: Updating mod1-2
+${SPROG} update: Updating mod2-2
+${SPROG} update: Updating mod2-2/mod1-2
+P mod2-2/mod1-2/file1-2
+${SPROG} update: Updating mod1-2
+${SPROG} update: Updating mod1-2/mod2-2
+P mod1-2/mod2-2/file2-2
+${SPROG} update: Updating mod2-1
+${SPROG} update: Updating mod2-2"
+
+ dotest multiroot-tag-1 "${testcvs} tag cattle" \
+"${SPROG} tag: Tagging \.
+${SPROG} tag: Tagging mod1-1
+T mod1-1/file1-1
+${SPROG} tag: Tagging mod1-2
+T mod1-2/file1-2
+${SPROG} tag: Tagging mod2-2/mod1-2
+${SPROG} tag: Tagging mod1-2/mod2-2
+T mod1-2/mod2-2/file2-2
+${SPROG} tag: Tagging mod2-1
+T mod2-1/file2-1
+${SPROG} tag: Tagging mod2-2" \
+"${SPROG} tag: Tagging \.
+${SPROG} tag: Tagging mod1-1
+T mod1-1/file1-1
+${SPROG} tag: Tagging mod1-2
+T mod1-2/file1-2
+${SPROG} tag: Tagging mod2-2
+${SPROG} tag: Tagging mod2-2/mod1-2
+${SPROG} tag: Tagging mod1-2
+${SPROG} tag: Tagging mod1-2/mod2-2
+T mod1-2/mod2-2/file2-2
+${SPROG} tag: Tagging mod2-1
+T mod2-1/file2-1
+${SPROG} tag: Tagging mod2-2"
+
+ echo anotherfile1-1 > mod1-1/anotherfile1-1
+ echo anotherfile2-1 > mod2-1/anotherfile2-1
+ echo anotherfile1-2 > mod2-2/mod1-2/anotherfile1-2
+ echo anotherfile2-2 > mod1-2/mod2-2/anotherfile2-2
+
+ if $remote; then
+ cd mod1-1
+ dotest multiroot-add-1ar "${testcvs} add anotherfile1-1" \
+"${SPROG} add: scheduling file .anotherfile1-1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cd ../mod2-1
+ dotest multiroot-add-1br "${testcvs} add anotherfile2-1" \
+"${SPROG} add: scheduling file .anotherfile2-1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cd ../mod2-2/mod1-2
+ dotest multiroot-add-1cr "${testcvs} add anotherfile1-2" \
+"${SPROG} add: scheduling file .anotherfile1-2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cd ../../mod1-2/mod2-2
+ dotest multiroot-add-1dr "${testcvs} add anotherfile2-2" \
+"${SPROG} add: scheduling file .anotherfile2-2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cd ../..
+ else
+ dotest multiroot-add-1 "${testcvs} add mod1-1/anotherfile1-1 mod2-1/anotherfile2-1 mod2-2/mod1-2/anotherfile1-2 mod1-2/mod2-2/anotherfile2-2" \
+"${SPROG} add: scheduling file .mod1-1/anotherfile1-1. for addition
+${SPROG} add: scheduling file .mod2-1/anotherfile2-1. for addition
+${SPROG} add: scheduling file .mod2-2/mod1-2/anotherfile1-2. for addition
+${SPROG} add: scheduling file .mod1-2/mod2-2/anotherfile2-2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ fi
+
+ dotest multiroot-status-1 "${testcvs} status -v" \
+"${SPROG} status: Examining \.
+${SPROG} status: Examining mod1-1
+===================================================================
+File: anotherfile1-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod1-2
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod2-2/mod1-2
+===================================================================
+File: anotherfile1-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod1-2/mod2-2
+===================================================================
+File: anotherfile2-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod2-1
+===================================================================
+File: anotherfile2-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod2-2
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)" \
+"${SPROG} status: Examining \.
+${SPROG} status: Examining mod1-1
+===================================================================
+File: anotherfile1-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod1-2
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod2-2
+${SPROG} status: Examining mod2-2/mod1-2
+===================================================================
+File: anotherfile1-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod1-2
+${SPROG} status: Examining mod1-2/mod2-2
+===================================================================
+File: anotherfile2-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod2-1
+===================================================================
+File: anotherfile2-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${SPROG} status: Examining mod2-2
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Commit Identifier: ${commitid}
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)"
+
+ dotest multiroot-commit-2 "${testcvs} commit -m reading" \
+"${CPROG} commit: Examining \.
+${CPROG} commit: Examining mod1-1
+${CPROG} commit: Examining mod1-2
+${CPROG} commit: Examining mod2-2/mod1-2
+${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v <-- mod1-1/anotherfile1-1
+initial revision: 1\.1
+${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v <-- mod2-2/mod1-2/anotherfile1-2
+initial revision: 1\.1
+${CPROG} commit: Examining mod1-2/mod2-2
+${CPROG} commit: Examining mod2-1
+${CPROG} commit: Examining mod2-2
+${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v <-- mod1-2/mod2-2/anotherfile2-2
+initial revision: 1\.1
+${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v <-- mod2-1/anotherfile2-1
+initial revision: 1\.1"
+
+ dotest multiroot-update-3 "${testcvs} update" \
+"${CPROG} update: Updating \.
+${CPROG} update: Updating mod1-1
+${CPROG} update: Updating mod1-2
+U mod1-2/anotherfile1-2
+${CPROG} update: Updating mod2-2/mod1-2
+${CPROG} update: Updating mod1-2/mod2-2
+${CPROG} update: Updating mod2-1
+${CPROG} update: Updating mod2-2
+U mod2-2/anotherfile2-2" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating mod1-1
+${SPROG} update: Updating mod1-2
+U mod1-2/anotherfile1-2
+${SPROG} update: Updating mod2-2
+${SPROG} update: Updating mod2-2/mod1-2
+${SPROG} update: Updating mod1-2
+${SPROG} update: Updating mod1-2/mod2-2
+${SPROG} update: Updating mod2-1
+${SPROG} update: Updating mod2-2
+U mod2-2/anotherfile2-2"
+
+ dotest multiroot-log-1 "${testcvs} log" \
+"${SPROG} log: Logging \.
+${SPROG} log: Logging mod1-1
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v
+Working file: mod1-1/anotherfile1-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+Working file: mod1-1/file1-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+is
+=============================================================================
+${SPROG} log: Logging mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+is
+=============================================================================
+${SPROG} log: Logging mod2-2/mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod2-2/mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod2-2/mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+is
+=============================================================================
+${SPROG} log: Logging mod1-2/mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod1-2/mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod1-2/mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+anyone
+=============================================================================
+${SPROG} log: Logging mod2-1
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v
+Working file: mod2-1/anotherfile2-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+Working file: mod2-1/file2-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+anyone
+=============================================================================
+${SPROG} log: Logging mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+anyone
+=============================================================================" \
+"${SPROG} log: Logging \.
+${SPROG} log: Logging mod1-1
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v
+Working file: mod1-1/anotherfile1-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+Working file: mod1-1/file1-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+is
+=============================================================================
+${SPROG} log: Logging mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+is
+=============================================================================
+${SPROG} log: Logging mod2-2
+${SPROG} log: Logging mod2-2/mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod2-2/mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod2-2/mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+is
+=============================================================================
+${SPROG} log: Logging mod1-2
+${SPROG} log: Logging mod1-2/mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod1-2/mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod1-2/mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+anyone
+=============================================================================
+${SPROG} log: Logging mod2-1
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v
+Working file: mod2-1/anotherfile2-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+Working file: mod2-1/file2-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+anyone
+=============================================================================
+${SPROG} log: Logging mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}1 -0; commitid: ${commitid};
+actually
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+anyone
+============================================================================="
+
+
+ # After the simple cases, let's execute some commands which
+ # refer to parts of our checked-out tree (e.g. "cvs update
+ # mod1-1 mod2-2")
+
+ dokeep
+
+ # clean up after ourselves
+ cd ..
+ rm -r 1
+
+ # clean up our repositories
+ rm -rf ${CVSROOT1_DIRNAME} ${CVSROOT2_DIRNAME}
+ ;;
+
+
+
+ multiroot2)
+ # More multiroot tests. In particular, nested directories.
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ CVSROOT1_DIRNAME=${TESTDIR}/root1
+ CVSROOT2_DIRNAME=${TESTDIR}/root2
+ CVSROOT1=`newroot $CVSROOT1_DIRNAME`
+ CVSROOT2=`newroot $CVSROOT2_DIRNAME`
+
+ dotest multiroot2-1 "${testcvs} -d ${CVSROOT1} init" ""
+ dotest multiroot2-2 "${testcvs} -d ${CVSROOT2} init" ""
+
+ mkdir imp-dir; cd imp-dir
+ echo file1 >file1
+ mkdir sdir
+ echo sfile >sdir/sfile
+ mkdir sdir/ssdir
+ echo ssfile >sdir/ssdir/ssfile
+ dotest_sort multiroot2-3 \
+"${testcvs} -d ${CVSROOT1} import -m import-to-root1 dir1 vend rel" "
+
+N dir1/file1
+N dir1/sdir/sfile
+N dir1/sdir/ssdir/ssfile
+No conflicts created by this import
+${SPROG} import: Importing ${TESTDIR}/root1/dir1/sdir
+${SPROG} import: Importing ${TESTDIR}/root1/dir1/sdir/ssdir"
+ cd sdir
+ dotest_sort multiroot2-4 \
+"${testcvs} -d ${CVSROOT2} import -m import-to-root2 sdir vend2 rel2" "
+
+N sdir/sfile
+N sdir/ssdir/ssfile
+No conflicts created by this import
+${SPROG} import: Importing ${TESTDIR}/root2/sdir/ssdir"
+ cd ../..
+
+ mkdir 1; cd 1
+ # Get TopLevelAdmin-like behavior.
+ dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co -l ."
+ dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co dir1" \
+"U dir1/file1
+U dir1/sdir/sfile
+U dir1/sdir/ssdir/ssfile"
+ cd dir1
+ dotest multiroot2-6 "${testcvs} -Q release -d sdir" ""
+ dotest multiroot2-7 "${testcvs} -d ${CVSROOT2} -q co sdir" \
+"U sdir/sfile
+U sdir/ssdir/ssfile"
+ cd ..
+ # This has one subtle effect - it deals with Entries.Log
+ # so that the next test doesn't get trace messages for
+ # Entries.Log
+ dotest multiroot2-8 "${testcvs} update" \
+"${CPROG} update: Updating \.
+${CPROG} update: Updating dir1
+${CPROG} update: Updating dir1/sdir
+${CPROG} update: Updating dir1/sdir/ssdir" \
+"${SPROG} update: Updating \.
+${SPROG} update: Updating dir1
+${SPROG} update: Updating dir1
+${SPROG} update: Updating dir1/sdir
+${SPROG} update: Updating dir1/sdir/ssdir"
+ # Two reasons we don't run this on the server: (1) the server
+ # also prints some trace messages, and (2) the server trace
+ # messages are subject to out-of-order bugs (this one is hard
+ # to work around).
+ if $remote; then :; else
+ dotest multiroot2-9a "${testcvs} -t update" \
+" *-> main: Session ID is ${commitid}
+ *-> main loop with CVSROOT=${TESTDIR}/root1
+ *-> parse_config ($TESTDIR/root1)
+ *-> do_update ((null), (null), (null), 1, 0, 0, 0, 0, 0, 3, (null), (null), (null), (null), (null), 1, (null))
+ *-> Write_Template (\., ${TESTDIR}/root1)
+${CPROG} update: Updating \.
+ *-> Reader_Lock(${TESTDIR}/root1)
+ *-> Simple_Lock_Cleanup()
+ *-> Write_Template (dir1, ${TESTDIR}/root1/dir1)
+${CPROG} update: Updating dir1
+ *-> Reader_Lock(${TESTDIR}/root1/dir1)
+ *-> Simple_Lock_Cleanup()
+ *-> main loop with CVSROOT=${TESTDIR}/root2
+ *-> parse_config ($TESTDIR/root2)
+ *-> do_update ((null), (null), (null), 1, 0, 0, 0, 0, 0, 3, (null), (null), (null), (null), (null), 1, (null))
+ *-> Write_Template (dir1/sdir, ${TESTDIR}/root2/dir1/sdir)
+${CPROG} update: Updating dir1/sdir
+ *-> Reader_Lock(${TESTDIR}/root2/sdir)
+ *-> Simple_Lock_Cleanup()
+ *-> Write_Template (dir1/sdir/ssdir, ${TESTDIR}/root2/sdir/ssdir)
+${CPROG} update: Updating dir1/sdir/ssdir
+ *-> Reader_Lock(${TESTDIR}/root2/sdir/ssdir)
+ *-> Simple_Lock_Cleanup()
+ *-> Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()"
+ fi
+
+ dotest multiroot2-9 "${testcvs} -q tag tag1" \
+"T dir1/file1
+T dir1/sdir/sfile
+T dir1/sdir/ssdir/ssfile"
+ echo "change it" >>dir1/file1
+ echo "change him too" >>dir1/sdir/sfile
+ dotest multiroot2-10 "${testcvs} -q ci -m modify" \
+"$TESTDIR/root1/dir1/file1,v <-- dir1/file1
+new revision: 1\.2; previous revision: 1\.1
+$TESTDIR/root2/sdir/sfile,v <-- dir1/sdir/sfile
+new revision: 1\.2; previous revision: 1\.1"
+ dotest multiroot2-11 "${testcvs} -q tag tag2" \
+"T dir1/file1
+T dir1/sdir/sfile
+T dir1/sdir/ssdir/ssfile"
+ dotest_fail multiroot2-12 \
+"${testcvs} -q diff -u -r tag1 -r tag2" \
+"Index: dir1/file1
+===================================================================
+RCS file: ${TESTDIR}/root1/dir1/file1,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.2
+diff -u -r1\.1\.1\.1 -r1\.2
+--- dir1/file1 ${RFCDATE} 1\.1\.1\.1
+${PLUS}${PLUS}${PLUS} dir1/file1 ${RFCDATE} 1\.2
+@@ -1 ${PLUS}1,2 @@
+ file1
+${PLUS}change it
+Index: dir1/sdir/sfile
+===================================================================
+RCS file: ${TESTDIR}/root2/sdir/sfile,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.2
+diff -u -r1\.1\.1\.1 -r1\.2
+--- dir1/sdir/sfile ${RFCDATE} 1\.1\.1\.1
+${PLUS}${PLUS}${PLUS} dir1/sdir/sfile ${RFCDATE} 1\.2
+@@ -1 ${PLUS}1,2 @@
+ sfile
+${PLUS}change him too"
+
+ if $keep; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ # clean up after ourselves
+ cd ..
+ rm -r imp-dir 1
+
+ # clean up our repositories
+ rm -rf root1 root2
+ ;;
+
+
+
+ multiroot3)
+ # More multiroot tests. Directories are side-by-side, not nested.
+ # Not drastically different from multiroot but it covers somewhat
+ # different stuff.
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ CVSROOT1=`newroot ${TESTDIR}/root1`
+ CVSROOT2=`newroot ${TESTDIR}/root2`
+
+ mkdir 1; cd 1
+ dotest multiroot3-1 "${testcvs} -d ${CVSROOT1} init" ""
+ dotest multiroot3-2 "${testcvs} -d ${CVSROOT1} -q co -l ." ""
+ mkdir dir1
+ dotest multiroot3-3 "${testcvs} add dir1" \
+"Directory ${TESTDIR}/root1/dir1 added to the repository"
+ dotest multiroot3-4 "${testcvs} -d ${CVSROOT2} init" ""
+ rm -r CVS
+ dotest multiroot3-5 "${testcvs} -d ${CVSROOT2} -q co -l ." ""
+ mkdir dir2
+
+ # OK, the problem is that CVS/Entries doesn't look quite right,
+ # I suppose because of the "rm -r". Then again, why *should* it
+ # look right? CVS/Root can only point to a single location, but
+ # we expect CVS/Entries to hold entries for two repositories? It
+ # just plain isn't part of the filespec yet.
+ #
+ # Use the quick and dirty fix.
+ echo "D/dir1////" >CVS/Entries
+ echo "D/dir2////" >>CVS/Entries
+
+ dotest multiroot3-7 "${testcvs} add dir2" \
+"Directory ${TESTDIR}/root2/dir2 added to the repository"
+
+ touch dir1/file1 dir2/file2
+ if $remote; then
+ # Trying to add them both in one command doesn't work,
+ # because add.c doesn't do multiroot (it doesn't use recurse.c).
+ # Furthermore, it can't deal with the parent directory
+ # having a different root from the child, hence the cd.
+ cd dir1
+ dotest multiroot3-8 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ cd ..
+ dotest multiroot3-8a "${testcvs} add dir2/file2" \
+"${SPROG} add: scheduling file .dir2/file2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ else
+ dotest multiroot3-8 "${testcvs} add dir1/file1 dir2/file2" \
+"${SPROG} add: scheduling file .dir1/file1. for addition
+${SPROG} add: scheduling file .dir2/file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ fi
+
+ dotest multiroot3-9 "${testcvs} -q ci -m add-them" \
+"$TESTDIR/root2/dir2/file2,v <-- dir2/file2
+initial revision: 1\.1
+$TESTDIR/root1/dir1/file1,v <-- dir1/file1
+initial revision: 1\.1"
+
+ # That this is an error is good - we are asking CVS to do
+ # something which doesn't make sense.
+ dotest_fail multiroot3-10 \
+"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" \
+"${SPROG} diff: failed to create lock directory for .${TESTDIR}/root1/dir2' (${TESTDIR}/root1/dir2/#cvs.lock): No such file or directory
+${SPROG} diff: failed to obtain dir lock in repository .${TESTDIR}/root1/dir2'
+${SPROG} \[diff aborted\]: read lock failed - giving up"
+
+ # This one is supposed to work.
+ dotest multiroot3-11 "${testcvs} -q diff dir1/file1 dir2/file2" ""
+
+ # make sure we can't access across repositories
+ # FIXCVS: we probably shouldn't even create the local directories
+ # in this case, but we do, so deal with it.
+ mkdir 1a
+ cd 1a
+ dotest_fail multiroot3-12 \
+"$testcvs -d $CVSROOT1 -q co ../root2/dir2" \
+"$CPROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\." \
+"$SPROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\.
+$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
+ dotest_fail multiroot3-13 \
+"$testcvs -d $CVSROOT2 -q co ../root1/dir1" \
+"$CPROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\.\./root1/dir1'\." \
+"$SPROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\.\./root1/dir1'\.
+$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
+ dotest_fail multiroot3-14 \
+"$testcvs -d $CVSROOT1 -q co ./../root2/dir2" \
+"$CPROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root2/dir2'\." \
+"$SPROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root2/dir2'\.
+$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
+ dotest_fail multiroot3-15 \
+"$testcvs -d $CVSROOT2 -q co ./../root1/dir1" \
+"$CPROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\." \
+"$SPROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\.
+$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
+ dotest_fail multiroot3-16 \
+"$testcvs -d $CVSROOT1 -q co -p ../root2/dir2" \
+"$CPROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\." \
+"$SPROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\.
+$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
+ dotest_fail multiroot3-17 \
+"$testcvs -d $CVSROOT1 -q co -p ./../root1/dir1" \
+"$CPROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\." \
+"$SPROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\.
+$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
+
+ cd ../..
+
+ if $keep; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ rm -r 1
+ rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2
+ unset CVSROOT1
+ unset CVSROOT2
+ ;;
+
+
+
+ multiroot4)
+ # More multiroot tests, in particular we have two roots with
+ # similarly-named directories and we try to see that CVS can
+ # keep them separate.
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ CVSROOT1=`newroot ${TESTDIR}/root1`
+ CVSROOT2=`newroot ${TESTDIR}/root2`
+
+ mkdir 1; cd 1
+ dotest multiroot4-1 "${testcvs} -d ${CVSROOT1} init" ""
+ dotest multiroot4-2 "${testcvs} -d ${CVSROOT1} -q co -l ." ""
+ mkdir dircom
+ dotest multiroot4-3 "${testcvs} add dircom" \
+"Directory ${TESTDIR}/root1/dircom added to the repository"
+ cd dircom
+ touch file1
+ dotest multiroot4-4 "${testcvs} add file1" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest multiroot4-5 "${testcvs} -q ci -m add" \
+"$TESTDIR/root1/dircom/file1,v <-- file1
+initial revision: 1\.1"
+ cd ../..
+ mkdir 2; cd 2
+ dotest multiroot4-6 "${testcvs} -d ${CVSROOT2} init" ""
+ dotest multiroot4-7 "${testcvs} -d ${CVSROOT2} -q co -l ." ""
+ mkdir dircom
+ dotest multiroot4-8 "${testcvs} add dircom" \
+"Directory ${TESTDIR}/root2/dircom added to the repository"
+ cd dircom
+ touch file2
+ dotest multiroot4-9 "${testcvs} add file2" \
+"${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add this file permanently"
+ dotest multiroot4-10 "${testcvs} -q ci -m add" \
+"$TESTDIR/root2/dircom/file2,v <-- file2
+initial revision: 1\.1"
+
+ cd ../..
+ cd 1/dircom
+ # This may look contrived; the real world example which inspired
+ # it was that a user was changing from local to remote. Cases
+ # like switching servers (among those mounting the same
+ # repository) and so on would also look the same.
+ mkdir sdir2
+ dotest multiroot4-11 "${testcvs} -d ${CVSROOT2} add sdir2" \
+"Directory ${TESTDIR}/root2/dircom/sdir2 added to the repository"
+
+ dotest multiroot4-12 "${testcvs} -q update" ""
+ cd ..
+ dotest multiroot4-13 "${testcvs} -q update dircom" ""
+ cd ..
+
+ rm -r 1 2
+ rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2
+ unset CVSROOT1
+ unset CVSROOT2
+ ;;
+
+
+
+ rmroot)
+ # When the Entries/Root file is removed from an existing
+ # workspace, CVS should assume $CVSROOT instead
+ #
+ # Right now only checking that CVS exits normally on an
+ # update once CVS/Root is deleted
+ #
+ # There was a time when this would core dump when run in
+ # client/server mode
+
+ mkdir 1; cd 1
+ dotest rmroot-setup-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest rmroot-setup-2 "${testcvs} add first-dir" \
+"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+ cd first-dir
+ touch file1 file2
+ dotest rmroot-setup-3 "${testcvs} add file1 file2" \
+"${SPROG} add: scheduling file .file1. for addition
+${SPROG} add: scheduling file .file2. for addition
+${SPROG} add: use .${SPROG} commit. to add these files permanently"
+ dotest rmroot-setup-4 "${testcvs} -q commit -minit" \
+"$CVSROOT_DIRNAME/first-dir/file1,v <-- file1
+initial revision: 1\.1
+$CVSROOT_DIRNAME/first-dir/file2,v <-- file2
+initial revision: 1\.1"
+ rm CVS/Root
+ dotest rmroot-1 "${testcvs} -q update" ''
+
+ dokeep
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+ ;;
+
+
+
+ reposmv)
+ # More tests of repositories and specifying them.
+ # Similar to crerepos but that test is probably getting big
+ # enough.
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ CVSROOT1=`newroot ${TESTDIR}/root1`
+ CVSROOT_MOVED=`newroot ${TESTDIR}/root-moved`
+
+ dotest reposmv-setup-1 "${testcvs} -d ${CVSROOT1} init" ""
+ mkdir imp-dir; cd imp-dir
+ echo file1 >file1
+ dotest reposmv-setup-2 \
+"${testcvs} -d ${CVSROOT1} import -m add dir1 vendor release" \
+"N dir1/file1
+
+No conflicts created by this import"
+ cd ..
+
+ mkdir 1; cd 1
+ dotest reposmv-1 "${testcvs} -d ${CVSROOT1} -Q co dir1" ""
+ mv ${TESTDIR}/root1 ${TESTDIR}/root-moved
+ cd dir1
+
+ # If we didn't have a relative repository, get one now.
+ dotest reposmv-1a "cat CVS/Repository" \
+"${TESTDIR}/root1/dir1" "dir1"
+ echo dir1 >CVS/Repository
+
+ # There were some duplicated warnings and such; only test
+ # for the part of the error message which makes sense.
+ #
+ # FIXCVS then FIXME
+ # Now the duplicated error messages only occur on some platforms,
+ # including, apparently, NetBSD 1.6.1, RedHat Linux 7.3, whatever
+ # kernel that is using, and Solaris 9. These platforms somehow
+ # decide to call Name_Root() up to four times, via do_recursion, but
+ # I'm not sure of the rest of the details. Other platforms,
+ # including Fedora Core 1 (Linux 2.4.22-1.2199.nptl), RH Linux 9
+ # (Linux 2.4.20-37.9.legacy), and probably AIX 3.4, Solaris 8,
+ # BSD/OS 4.2, & IRIX 6.5 only call Name_Root() once as a result of
+ # this test.
+ #
+ # Bug: "skipping directory " without filename.
+ if $remote; then
+ dotest_fail reposmv-2r "${testcvs} update" \
+"Cannot access ${TESTDIR}/root1/CVSROOT
+No such file or directory"
+ else
+ dotest reposmv-2 "$testcvs update" \
+"$DOTSTAR$CPROG update: in directory \.:
+$CPROG update: ignoring CVS/Root because it specifies a non-existent repository $TESTDIR/root1
+$CPROG update: Updating \.
+$DOTSTAR$CPROG update: cannot open directory $CVSROOT_DIRNAME/dir1: No such file or directory
+$CPROG update: skipping directory "
+ fi
+
+ # CVS/Root overrides $CVSROOT
+ if $remote; then
+ CVSROOT_save=${CVSROOT}
+ CVSROOT=:fork:${TESTDIR}/root-moved; export CVSROOT
+ dotest_fail reposmv-3r "${testcvs} update" \
+"Cannot access ${TESTDIR}/root1/CVSROOT
+No such file or directory"
+ CVSROOT=${CVSROOT_save}; export CVSROOT
+ else
+ CVSROOT_save=$CVSROOT
+ CVSROOT=$TESTDIR/root-moved; export CVSROOT
+ dotest reposmv-3 "$testcvs update" \
+"$DOTSTAR$CPROG update: in directory \.:
+$CPROG update: ignoring CVS/Root because it specifies a non-existent repository $TESTDIR/root1
+$CPROG update: Updating \.$DOTSTAR"
+ CVSROOT=$CVSROOT_save; export CVSROOT
+ fi
+
+ if $remote; then
+ CVSROOT_save=${CVSROOT}
+ CVSROOT=:fork:${TESTDIR}/root-none; export CVSROOT
+ dotest_fail reposmv-4r "${testcvs} update" \
+"Cannot access ${TESTDIR}/root1/CVSROOT
+No such file or directory"
+ CVSROOT=${CVSROOT_save}; export CVSROOT
+ else
+ # CVS/Root doesn't seem to quite completely override $CVSROOT
+ # Bug? Not necessarily a big deal if it only affects error
+ # messages.
+ CVSROOT_save=${CVSROOT}
+ CVSROOT=${TESTDIR}/root-none; export CVSROOT
+ dotest_fail reposmv-4 "${testcvs} update" \
+"${CPROG} update: in directory \.:
+${CPROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1
+${CPROG} \[update aborted\]: ${TESTDIR}/root-none/CVSROOT: No such file or directory"
+ CVSROOT=${CVSROOT_save}; export CVSROOT
+ fi
+
+ # -d overrides CVS/Root
+ #
+ # Oddly enough, with CVS 1.10 I think this didn't work for
+ # local (that is, it would appear that CVS/Root would not
+ # get used, but would produce an error if it didn't exist).
+ dotest reposmv-5 "${testcvs} -d ${CVSROOT_MOVED} update" \
+"${SPROG} update: Updating \."
+
+ # TODO: could also test various other things, like what if the
+ # user removes CVS/Root (which is legit). Or another set of
+ # tests would be if both repositories exist but we want to make
+ # sure that CVS is using the correct one.
+
+ cd ../..
+ rm -r imp-dir 1
+ rm -rf root1 root2
+ unset CVSROOT1
+ ;;
+
+
+
+ pserver)
+ # Test basic pserver functionality.
+ if $remote; then
+ if test -n "$remotehost"; then
+ # Don't even try. (The issue is getting servercvs & testcvs
+ # set correctly for the following tests. Some expect one access
+ # method and some another, which in $remotehost mode, means that
+ # sometimes the executables must run on one platform and
+ # sometimes another.)
+ continue
+ fi
+ save_servercvs=$servercvs
+ servercvs=$testcvs
+ # First set SystemAuth=no. Not really necessary, I don't
+ # think, but somehow it seems like the clean thing for
+ # the testsuite.
+ mkdir 1; cd 1
+ dotest pserver-1 "$testcvs -Q co CVSROOT" ""
+ cd CVSROOT
+ echo "SystemAuth=no" >>config
+ dotest pserver-2 "$testcvs -q ci -m config-it" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+ cat >$CVSROOT_DIRNAME/CVSROOT/passwd <<EOF
+testme:q6WV9d2t848B2:$username
+dontroot:q6WV9d2t848B2:root
+anonymous::$username
+$username:
+willfail: :whocares
+EOF
+ dotest_fail pserver-3 "$servercvs pserver" \
+"error 0 Server configuration missing --allow-root in inetd.conf" <<EOF
+BEGIN AUTH REQUEST
+$CVSROOT_DIRNAME
+testme
+Ay::'d
+END AUTH REQUEST
+EOF
+
+ # Confirm that not sending a newline during auth cannot constitute
+ # a denial-of-service attack. This assumes that PATH_MAX is less
+ # than 65536 bytes. If PATH_MAX is larger than 65535 bytes, this
+ # test could hang indefinitely.
+ ${AWK} 'BEGIN { printf "0123456789abcdef" }' </dev/null >garbageseg
+ echo "BEGIN AUTH REQUEST" >garbageinput
+ i=0
+ while test $i -lt 64; do
+ cat <garbageseg >>garbageseg2
+ i=`expr $i + 1`
+ done
+ i=0
+ while test $i -lt 64; do
+ cat <garbageseg2 >>garbageinput
+ i=`expr $i + 1`
+ done
+ dotest_fail pserver-auth-no-dos \
+"${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"$CPROG \\[pserver aborted\\]: error reading from net while validating pserver: Not enough space" \
+"$CPROG \\[pserver aborted\\]: error reading from net while validating pserver: Cannot allocate memory" <garbageinput
+ unset i
+ rm garbageseg garbageseg2 garbageinput
+
+ # Sending the Root and noop before waiting for the
+ # "I LOVE YOU" is bogus, but hopefully we can get
+ # away with it.
+ dotest pserver-4 "$servercvs --allow-root=$CVSROOT_DIRNAME pserver" \
+"$DOTSTAR LOVE YOU
+ok" <<EOF
+BEGIN AUTH REQUEST
+$CVSROOT_DIRNAME
+testme
+Ay::'d
+END AUTH REQUEST
+Root $CVSROOT_DIRNAME
+noop
+EOF
+
+ dotest_fail pserver-4.2 \
+"$servercvs --allow-root=$CVSROOT_DIRNAME pserver" \
+"error 0: root not allowed" <<EOF
+BEGIN AUTH REQUEST
+$CVSROOT_DIRNAME
+dontroot
+Ay::'d
+END AUTH REQUEST
+EOF
+
+ dotest pserver-5 "$servercvs --allow-root=$CVSROOT_DIRNAME pserver" \
+"$DOTSTAR LOVE YOU
+E Protocol error: Root says \"$TESTDIR/1\" but pserver says \"$CVSROOT_DIRNAME\"
+error " <<EOF
+BEGIN AUTH REQUEST
+$CVSROOT_DIRNAME
+testme
+Ay::'d
+END AUTH REQUEST
+Root $TESTDIR/1
+noop
+EOF
+
+ dotest pserver-5a "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+E Protocol error: init says \"${TESTDIR}/2\" but pserver says \"${CVSROOT_DIRNAME}\"
+error " <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+init ${TESTDIR}/2
+EOF
+ dotest_fail pserver-5b "test -d ${TESTDIR}/2" ''
+
+ dotest pserver-5c "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+E init xxx must be an absolute pathname
+error " <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+init xxx
+EOF
+ dotest_fail pserver-5d "test -d xxx" ''
+
+ dotest_fail pserver-6 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"I HATE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d^b?hd
+END AUTH REQUEST
+EOF
+
+ dotest_fail pserver-7 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"I HATE YOU" <<EOF
+BEGIN VERIFICATION REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d^b?hd
+END VERIFICATION REQUEST
+EOF
+
+ dotest pserver-8 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU" <<EOF
+BEGIN VERIFICATION REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END VERIFICATION REQUEST
+EOF
+
+# Tests pserver-9 through pserver-13 are about empty passwords
+
+ # Test empty password (both sides) for aliased user
+ dotest pserver-9 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+anonymous
+A
+END AUTH REQUEST
+EOF
+
+ # Test empty password (server side only) for aliased user
+ dotest pserver-10 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+anonymous
+Aanythingwouldworkhereittrulydoesnotmatter
+END AUTH REQUEST
+EOF
+
+ # Test empty (both sides) password for non-aliased user
+ dotest pserver-11 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+A
+END AUTH REQUEST
+EOF
+
+ # Test empty (server side only) password for non-aliased user
+ dotest pserver-12 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+Anypasswordwouldworkwhynotthisonethen
+END AUTH REQUEST
+EOF
+
+ # Test failure of whitespace password
+ dotest_fail pserver-13 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} HATE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+willfail
+Amquiteunabletocomeupwithinterestingpasswordsanymore
+END AUTH REQUEST
+EOF
+
+ # The following tests are for read-only access
+
+ # Check that readers can only read, everyone else can write
+
+ echo anonymous >$CVSROOT_DIRNAME/CVSROOT/readers
+
+ dotest pserver-14 "$servercvs --allow-root=$CVSROOT_DIRNAME pserver" \
+"$DOTSTAR LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+$CVSROOT_DIRNAME
+anonymous
+Ay::'d
+END AUTH REQUEST
+Root $CVSROOT_DIRNAME
+version
+EOF
+
+ dotest pserver-15 "$servercvs --allow-root=$CVSROOT_DIRNAME pserver" \
+"$DOTSTAR LOVE YOU
+E $CPROG \\[server aborted\\]: .init. requires write access to the repository
+error " <<EOF
+BEGIN AUTH REQUEST
+$CVSROOT_DIRNAME
+anonymous
+Ay::'d
+END AUTH REQUEST
+init $CVSROOT_DIRNAME
+EOF
+
+ dotest pserver-16 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-17 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ dotest pserver-18 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-19 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+Anything
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ # Check that writers can write, everyone else can only read
+ # even if not listed in readers
+
+ cat >${CVSROOT_DIRNAME}/CVSROOT/writers <<EOF
+testme
+EOF
+
+ dotest pserver-20 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+anonymous
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-21 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+E $CPROG \\[server aborted\\]: .init. requires write access to the repository
+error " <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+anonymous
+Ay::'d
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ dotest pserver-22 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-23 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ dotest pserver-24 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-25 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+E $CPROG \\[server aborted\\]: .init. requires write access to the repository
+error " <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+Anything
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ # Should work the same without readers
+
+ rm ${CVSROOT_DIRNAME}/CVSROOT/readers
+
+ dotest pserver-26 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+anonymous
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-27 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+E $CPROG \\[server aborted\\]: .init. requires write access to the repository
+error " <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+anonymous
+Ay::'d
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ dotest pserver-28 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-29 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ dotest pserver-30 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+M Concurrent Versions System (CVS) .*
+ok" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+version
+EOF
+
+ dotest pserver-31 "${servercvs} --allow-root=${CVSROOT_DIRNAME} pserver" \
+"${DOTSTAR} LOVE YOU
+E $CPROG \\[server aborted\\]: .init. requires write access to the repository
+error " <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+${username}
+Anything
+END AUTH REQUEST
+init ${CVSROOT_DIRNAME}
+EOF
+
+ # pserver used to try and print from the NULL pointer
+ # in this error message in this case
+ dotest_fail pserver-bufinit "${servercvs} pserver" \
+"$CPROG \[pserver aborted\]: unexpected EOF encountered during authentication" </dev/null
+
+ # Clean up.
+ dotest pserver-cleanup-1 "${testcvs} -q up -pr1.1 config >config" ""
+ dotest pserver-cleanup-2 "${testcvs} -q ci -m config-it" \
+"$CVSROOT_DIRNAME/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+$SPROG commit: Rebuilding administrative file database"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ restore_adm
+ servercvs=$save_servercvs
+ fi # skip the whole thing for local
+ ;;
+
+
+
+ server)
+ # Some tests of the server (independent of the client).
+ if $remote; then
+ save_servercvs=$servercvs
+ servercvs=$testcvs
+ dotest server-1 "${servercvs} server" \
+"E Protocol error: Root request missing
+error " <<EOF
+Directory bogus
+mumble/bar
+update
+EOF
+
+ # Could also test for relative pathnames here (so that crerepos-6a
+ # and crerepos-6b can use :fork:).
+ dotest server-2 "${servercvs} server" "ok" <<EOF
+Set OTHER=variable
+Set MYENV=env-value
+init ${TESTDIR}/crerepos
+EOF
+ dotest server-3 "test -d ${TESTDIR}/crerepos/CVSROOT" ""
+
+ # Now some tests of gzip-file-contents (used by jCVS).
+ ${AWK} 'BEGIN { \
+printf "%c%c%c%c%c%c.6%c%c+I-.%c%c%c%c5%c;%c%c%c%c", \
+31, 139, 8, 64, 5, 7, 64, 3, 225, 2, 64, 198, 185, 5, 64, 64, 64}' \
+ </dev/null | ${TR} '\100' '\000' >gzipped.dat
+ # Note that the CVS client sends "-b 1.1.1", and this
+ # test doesn't. But the server also defaults to that.
+ cat <<EOF >session.dat
+Root ${TESTDIR}/crerepos
+UseUnchanged
+gzip-file-contents 3
+Argument -m
+Argument msg
+Argumentx
+Argument dir1
+Argument tag1
+Argument tag2
+Directory .
+${TESTDIR}/crerepos
+Modified file1
+u=rw,g=r,o=r
+z25
+EOF
+ cat gzipped.dat >>session.dat
+ echo import >>session.dat
+ dotest server-4 "${servercvs} server" \
+"M N dir1/file1
+M
+M No conflicts created by this import
+M
+ok" <session.dat
+ dotest server-5 \
+"${testcvs} -q -d ${TESTDIR}/crerepos co -p dir1/file1" "test"
+
+ # OK, here are some notify tests.
+ dotest server-6 "${servercvs} server" \
+"Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Fri May 7 13:21:09 1999 -0000 myhost some-work-dir EUC
+noop
+EOF
+ # Sending the second "noop" before waiting for the output
+ # from the first is bogus but hopefully we can get away
+ # with it.
+ dotest server-7 "${servercvs} server" \
+"M file1 $username Fri May 7 13:21:09 1999 -0000 myhost some-work-dir
+Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok
+M file1 $username Fri May 7 13:21:09 1999 -0000 myhost some-work-dir
+Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Fri May 7 13:21:09 1999 -0000 myhost some-work-dir EUC
+noop
+Notify file1
+E The 57th day of Discord in the YOLD 3165 myhost some-work-dir EUC
+noop
+EOF
+
+ # OK, now test a few error conditions.
+ # FIXCVS: should give "error" and no "Notified", like server-9
+ dotest server-8 "${servercvs} server" \
+"M file1 $username The 57th day of Discord in the YOLD 3165 myhost some-work-dir
+E $CPROG server: invalid character in editor value
+Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Setting Orange, the 52th day of Discord in the YOLD 3165 myhost some-work-dir EUC
+noop
+EOF
+
+ dotest server-9 "${servercvs} server" \
+"E Protocol error; misformed Notify request
+error " <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Setting Orange+57th day of Discord myhost some-work-dir EUC
+noop
+EOF
+
+ # First demonstrate an interesting quirk in the protocol.
+ # The "watchers" request selects the files to operate based
+ # on files which exist in the working directory. So if we
+ # don't send "Entry" or the like, it won't do anything.
+ # Wants to be documented in cvsclient.texi...
+ dotest server-10 "${servercvs} server" "ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+watchers
+EOF
+ # See if "watchers" and "editors" display the right thing.
+ dotest server-11 "${servercvs} server" \
+"M file1 ${username} tedit tunedit tcommit
+ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Entry /file1/1.1////
+watchers
+EOF
+ dotest server-12 "${servercvs} server" \
+"M file1 ${username} The 57th day of Discord in the YOLD 3165 myhost some-work-dir
+ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Entry /file1/1.1////
+editors
+EOF
+
+ # Now do an unedit.
+ dotest server-13 "${servercvs} server" \
+"Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+U 7 May 1999 15:00 -0000 myhost some-work-dir EUC
+noop
+EOF
+
+ # Now try "watchers" and "editors" again.
+ dotest server-14 "${servercvs} server" "ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+watchers
+EOF
+ dotest server-15 "${servercvs} server" "ok" <<EOF
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+editors
+EOF
+
+ # Test that the global `-l' option is ignored nonfatally.
+ dotest server-16 "${testcvs} server" \
+"E $CPROG server: WARNING: global \`-l' option ignored\.
+ok" <<EOF
+Global_option -l
+noop
+EOF
+
+ # There used to be some exploits based on malformed Entry requests
+ dotest server-17 "$testcvs server" \
+"E protocol error: Malformed Entry
+error " <<EOF
+Root $TESTDIR/crerepos
+Directory .
+$TESTDIR/crerepos/dir1
+Entry X/file1/1.1////
+noop
+EOF
+
+ dotest server-18 "$testcvs server" \
+"E protocol error: Malformed Entry
+error " <<EOF
+Root $TESTDIR/crerepos
+Directory .
+$TESTDIR/crerepos/dir1
+Entry /CC/CC/CC
+noop
+EOF
+
+ # Check that the config file may be set from the command line.
+ # But first verify the default config produces no error messages.
+ dotest server-19 "$testcvs server" \
+"ok" <<EOF
+Root $TESTDIR/crerepos
+Directory .
+$TESTDIR/crerepos
+noop
+EOF
+ echo THIS-CONFIG-OPTION-IS-BAD=XXX >$TESTDIR/newconfig
+ dotest_fail server-20 "$testcvs server -c $TESTDIR/newconfig" \
+"E $SPROG \[server aborted\]: Invalid path to config file specified: \`$TESTDIR/newconfig'" <<EOF
+Root $TESTDIR/crerepos
+Directory .
+$TESTDIR/crerepos
+noop
+EOF
+ dotest_fail server-21 \
+"$testcvs server -c /etc/cvs/this-shouldnt-exist" \
+"E $SPROG \[server aborted\]: Failed to resolve path: \`/etc/cvs/this-shouldnt-exist': No such file or directory" <<EOF
+Root $TESTDIR/crerepos
+Directory .
+$TESTDIR/crerepos
+noop
+EOF
+
+ # Now make sure that the config file can't be set via the user's
+ # .cvsrc.
+ echo server -c $TESTDIR/newconfig >$HOME/.cvsrc
+ dotest server-22 "$testcvs server" \
+"ok" <<EOF
+Root $TESTDIR/crerepos
+Directory .
+$TESTDIR/crerepos
+noop
+EOF
+
+ dokeep
+ rm -rf $TESTDIR/crerepos
+ rm gzipped.dat session.dat
+ rm $TESTDIR/newconfig $HOME/.cvsrc
+ servercvs=$save_servercvs
+ fi # skip the whole thing for local
+ ;;
+
+
+
+ server2)
+ # More server tests, in particular testing that various
+ # possible security holes are plugged.
+ if $remote; then
+ if test -n "$remotehost"; then
+ # Don't even try. (The issue is getting servercvs & testcvs
+ # set correctly for the following tests. Some expect one access
+ # method and some another, which in $remotehost mode, means that
+ # sometimes the executables must run on one platform and
+ # sometimes another.)
+ continue
+ fi
+ save_servercvs=$servercvs
+ servercvs=$testcvs
+ dotest server2-1 "${servercvs} server" \
+"E protocol error: directory '${CVSROOT_DIRNAME}/\.\./dir1' not within root '${CVSROOT_DIRNAME}'
+error " <<EOF
+Root ${CVSROOT_DIRNAME}
+Directory .
+${CVSROOT_DIRNAME}/../dir1
+noop
+EOF
+
+ dotest server2-2 "${servercvs} server" \
+"E protocol error: directory '${CVSROOT_DIRNAME}dir1' not within root '${CVSROOT_DIRNAME}'
+error " <<EOF
+Root ${CVSROOT_DIRNAME}
+Directory .
+${CVSROOT_DIRNAME}dir1
+noop
+EOF
+
+ dotest 2-3 "${servercvs} server" \
+"E protocol error: directory '${TESTDIR}' not within root '${CVSROOT_DIRNAME}'
+error " <<EOF
+Root ${CVSROOT_DIRNAME}
+Directory .
+${TESTDIR}
+noop
+EOF
+
+ # OK, now a few tests for the rule that one cannot pass a
+ # filename containing a slash to Modified, Is-modified,
+ # Notify, Questionable, or Unchanged. For completeness
+ # we'd try them all. For lazyness/conciseness we don't.
+ dotest server2-4 "${servercvs} server" \
+"E protocol error: directory 'foo/bar' not within current directory
+error " <<EOF
+Root ${CVSROOT_DIRNAME}
+Directory .
+${CVSROOT_DIRNAME}
+Unchanged foo/bar
+noop
+EOF
+ servercvs=$save_servercvs
+ fi
+ ;;
+
+
+
+ client)
+ # Some tests of the client (independent of the server).
+ if $remote; then :; else
+ remoteonly client
+ continue
+ fi
+
+ if $proxy; then
+ # Skip these tests in proxy mode since they assume we are not
+ # writing through a proxy server. There is no writeproxy-client
+ # test currently. The writeproxy & writeproxy-noredirect tests
+ # test the writeproxy server.
+ notproxy client
+ continue
+ fi
+
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+# This is admittedly a bit cheezy, in the sense that we make lots
+# of assumptions about what the client is going to send us.
+# We don't mention Repository, because current clients don't require it.
+# Sending these at our own pace, rather than waiting for the client to
+# make the requests, is bogus, but hopefully we can get away with it.
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M special message"
+echo "Created first-dir/"
+echo "$CVSROOT_DIRNAME/first-dir/file1"
+echo "/file1/1.1///"
+echo "u=rw,g=rw,o=rw"
+echo "4"
+echo "xyz"
+echo "ok"
+cat >/dev/null
+EOF
+ # Cygwin. Pthffffffffft!
+ if test -n "$remotehost"; then
+ $CVS_RSH $remotehost "chmod +x $TESTDIR/serveme"
+ else
+ chmod +x $TESTDIR/serveme
+ fi
+ save_CVS_SERVER=$CVS_SERVER
+ CVS_SERVER=$TESTDIR/serveme; export CVS_SERVER
+ mkdir 1; cd 1
+ dotest_fail client-1 "$testcvs -q co first-dir" \
+"$CPROG \[checkout aborted\]: This server does not support the global -q option$DOTSTAR"
+ dotest client-2 "$testcvs co first-dir" "special message"
+
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M merge-it"
+echo "Copy-file ./"
+echo "$CVSROOT_DIRNAME/first-dir/file1"
+echo "$TESTDIR/bogus/.#file1.1.1"
+echo "Merged ./"
+echo "$CVSROOT_DIRNAME/first-dir/file1"
+echo "/file1/1.2///"
+echo "u=rw,g=rw,o=rw"
+echo "4"
+echo "abd"
+echo "ok"
+cat >/dev/null
+EOF
+ cd first-dir
+ mkdir $TESTDIR/bogus
+ # The ${DOTSTAR} is to match a potential "broken pipe" if the
+ # client exits before the server script sends everything
+ dotest_fail client-3 "$testcvs update" \
+"merge-it
+$CPROG \[update aborted\]: protocol error: Copy-file tried to specify director$DOTSTAR"
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M merge-it"
+echo "Copy-file ./"
+echo "$CVSROOT_DIRNAME/first-dir/file1"
+echo ".#file1.1.1"
+echo "Merged ./"
+echo "$CVSROOT_DIRNAME/first-dir/file1"
+echo "/file1/1.2///"
+echo "u=rw,g=rw,o=rw"
+echo "4"
+echo "abc"
+echo "ok"
+cat >/dev/null
+EOF
+ dotest client-4 "$testcvs update" "merge-it"
+ dotest client-5 "cat .#file1.1.1" "xyz"
+ dotest client-6 "cat CVS/Entries" "/file1/1.2/[A-Za-z0-9 :]*//
+D"
+ dotest client-7 "cat file1" "abc"
+
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M OK, whatever"
+echo "ok"
+cat >$TESTDIR/client.tmp
+EOF
+ chmod u=rw,go= file1
+ # By specifying the time zone in local time, we don't
+ # know exactly how that will translate to GMT.
+ dotest client-8 "$testcvs update -D 99-10-04" "OK, whatever"
+ # String 2 below is Cygwin again - ptoooey.
+ dotest client-9 "cat $TESTDIR/client.tmp" \
+"Root $CVSROOT_DIRNAME
+Valid-responses [-a-zA-Z ]*
+valid-requests
+Argument -D
+Argument [34] Oct 1999 [0-9][0-9]:00:00 -0000
+Argument --
+Directory \.
+$CVSROOT_DIRNAME/first-dir
+Entry /file1/1\.2///
+Modified file1
+u=rw,g=,o=
+4
+abc
+update" \
+"Root $CVSROOT_DIRNAME
+Valid-responses [-a-zA-Z ]*
+valid-requests
+Argument -D
+Argument [34] Oct 1999 [0-9][0-9]:00:00 -0000
+Argument --
+Directory \.
+$CVSROOT_DIRNAME/first-dir
+Entry /file1/1\.2///
+Modified file1
+u=rw,g=r,o=r
+4
+abc
+update"
+
+ # The following test tests what was a potential client exploit in
+ # CVS versions 1.11.14 and CVS versions 1.12.6 and earlier. This
+ # exploit would allow a trojan server to create arbitrary files,
+ # anywhere the user had write permissions, even outside of the
+ # user's sandbox.
+ cat >$HOME/.bashrc <<EOF
+#!$TESTSHELL
+# This is where login scripts would usually be
+# stored.
+EOF
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Rcs-diff $HOME/"
+echo "$HOME/.bashrc"
+echo "/.bashrc/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "20"
+echo "a1 1"
+echo "echo 'gotcha!'"
+echo "ok"
+cat >/dev/null
+EOF
+
+ # If I don't run the following sleep between the above cat and
+ # the following calls to dotest, sometimes the serveme file isn't
+ # completely written yet by the time CVS tries to execute it,
+ # causing the shell to intermittantly report syntax errors (usually
+ # early EOF). There's probably a new race condition here, but this
+ # works.
+ #
+ # Incidentally, I can reproduce this behavior with Linux 2.4.20 and
+ # Bash 2.05 or Bash 2.05b.
+ sleep 1
+ dotest_fail client-10 "$testcvs update" \
+"$CPROG update: Server attempted to update a file via an invalid pathname:
+$CPROG \[update aborted\]: \`$HOME/.bashrc'\."
+
+ # A second try at a client exploit. This one never actually
+ # failed in the past, but I thought it wouldn't hurt to add a test.
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Rcs-diff ./"
+echo "$HOME/.bashrc"
+echo "/.bashrc/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "20"
+echo "a1 1"
+echo "echo 'gotcha!'"
+echo "ok"
+cat >/dev/null
+EOF
+ sleep 1
+ dotest_fail client-11 "$testcvs update" \
+"$CPROG \[update aborted\]: patch original file \./\.bashrc does not exist"
+
+ # A third try at a client exploit. This one did used to fail like
+ # client-10.
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Rcs-diff ../../home/"
+echo "../../.bashrc"
+echo "/.bashrc/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "20"
+echo "a1 1"
+echo "echo 'gotcha!'"
+echo "ok"
+cat >/dev/null
+EOF
+ sleep 1
+ dotest_fail client-12 "$testcvs update" \
+"$CPROG update: Server attempted to update a file via an invalid pathname:
+$CPROG \[update aborted\]: \`\.\./\.\./home/.bashrc'\."
+
+ # Try the same exploit using the Created response.
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Created $HOME/"
+echo "$HOME/.bashrc"
+echo "/.bashrc/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "26"
+echo "#! $TESTSHELL"
+echo "echo 'gotcha!'"
+echo "ok"
+cat >/dev/null
+EOF
+ sleep 1
+ dotest_fail client-13 "$testcvs update" \
+"$CPROG update: Server attempted to update a file via an invalid pathname:
+$CPROG \[update aborted\]: \`$HOME/.bashrc'\."
+
+ # Now try using the Update-existing response
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Update-existing ../../home/"
+echo "../../home/.bashrc"
+echo "/.bashrc/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "26"
+echo "#! $TESTSHELL"
+echo "echo 'gotcha!'"
+echo "ok"
+cat >/dev/null
+EOF
+ sleep 1
+ dotest_fail client-14 "$testcvs update" \
+"$CPROG update: Server attempted to update a file via an invalid pathname:
+$CPROG \[update aborted\]: \`\.\./\.\./home/.bashrc'\."
+
+ # Try the same exploit using the Merged response.
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Merged $HOME/"
+echo "$HOME/.bashrc"
+echo "/.bashrc/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "26"
+echo "#! $TESTSHELL"
+echo "echo 'gotcha!'"
+echo "ok"
+cat >/dev/null
+EOF
+ sleep 1
+ dotest_fail client-15 "$testcvs update" \
+"$CPROG update: Server attempted to update a file via an invalid pathname:
+$CPROG \[update aborted\]: \`$HOME/.bashrc'\."
+
+ # Now try using the Updated response
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Updated ../../home/"
+echo "../../home/.bashrc"
+echo "/.bashrc/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "26"
+echo "#! $TESTSHELL"
+echo "echo 'gotcha!'"
+echo "ok"
+cat >/dev/null
+EOF
+ sleep 1
+ dotest_fail client-16 "$testcvs update" \
+"$CPROG update: Server attempted to update a file via an invalid pathname:
+$CPROG \[update aborted\]: \`\.\./\.\./home/.bashrc'\."
+
+ # Try the same exploit using the Copy-file response.
+ # As far as I know, Copy-file was never exploitable either.
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "Created ."
+echo "./innocuous"
+echo "/innocuous/73.50///"
+echo "u=rw,g=rw,o=rw"
+echo "26"
+echo "#! $TESTSHELL"
+echo "echo 'gotcha!'"
+echo "Copy-file ."
+echo "./innocuous"
+echo "$HOME/innocuous"
+echo "ok"
+cat >/dev/null
+EOF
+ sleep 1
+ dotest_fail client-18 "$testcvs update" \
+"$CPROG \[update aborted\]: protocol error: Copy-file tried to specify directory"
+
+ # And verify that none of the exploits was successful.
+ dotest client-19 "cat $HOME/.bashrc" \
+"#!$TESTSHELL
+# This is where login scripts would usually be
+# stored\."
+
+ # Check that the client detects redirect loops.
+ cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+echo "Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set Gssapi-authenticate expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version"
+echo "ok"
+echo "Redirect $CVSROOT"
+
+# Eat up data from the client to avoid broken pipe errors.
+cat >/dev/null
+EOF
+ echo newstuff >file1
+ sleep 1
+ dotest_fail client-20 "$testcvs ci" \
+"$CPROG commit: Examining \.
+$CPROG \[commit aborted\]: \`Redirect' loop detected\. Server misconfiguration$QUESTION"
+
+ dokeep
+ cd ../..
+ rm -r 1
+ rmdir $TESTDIR/bogus
+ rm $TESTDIR/serveme $HOME/.bashrc
+ CVS_SERVER=$save_CVS_SERVER; export CVS_SERVER
+ ;;
+
+
+
+ dottedroot)
+ # Check that a CVSROOT with a "." in the name will work.
+
+ if $proxy; then
+ # don't even try
+ continue
+ fi
+
+ CVSROOT_save=${CVSROOT}
+ CVSROOT_DIRNAME_save=${CVSROOT_DIRNAME}
+ CVSROOT_DIRNAME=${TESTDIR}/cvs.root
+ CVSROOT=`newroot ${CVSROOT_DIRNAME}`
+
+ dotest dottedroot-init-1 "${testcvs} init" ""
+ mkdir dir1
+ mkdir dir1/dir2
+ echo version1 >dir1/dir2/file1
+ cd dir1
+ dotest dottedroot-1 "${testcvs} import -m '' module1 AUTHOR INITIAL" \
+"${SPROG} import: Importing ${CVSROOT_DIRNAME}/module1/dir2
+N module1/dir2/file1
+
+No conflicts created by this import"
+ cd ..
+
+ # This is the test that used to cause an assertion failure
+ # in recurse.c:do_recursion().
+ dotest dottedroot-2 "${testcvs} co -rINITIAL module1" \
+"${SPROG} checkout: Updating module1
+${SPROG} checkout: Updating module1/dir2
+U module1/dir2/file1"
+
+ dokeep
+
+ rm -rf ${CVSROOT_DIRNAME}
+ rm -r dir1 module1
+ CVSROOT_DIRNAME=${CVSROOT_DIRNAME_save}
+ CVSROOT=${CVSROOT_save}
+ ;;
+
+
+
+ fork)
+ # Test that the server defaults to the correct executable in :fork:
+ # mode. See the note in the TODO at the end of this file about this.
+ #
+ # This test and client should be left after all other references to
+ # CVS_SERVER are removed from this script.
+ #
+ # The client series of tests already tests that CVS_SERVER is
+ # working, but that test might be better here.
+ if $remote; then
+ if test -n "$remotehost"; then
+ # Don't even try. If our caller specified a remotehost, our
+ # access method has been determined anyhow.
+ continue
+ fi
+ mkdir fork; cd fork
+ save_CVS_SERVER=$CVS_SERVER
+ unset CVS_SERVER
+ # So looking through $PATH for cvs won't work...
+ echo "echo junk" >cvs
+ chmod a+x cvs
+ save_PATH=$PATH; PATH=.:$PATH
+ # The second error message below is for testing clients without
+ # server support.
+ if ${testcvs_server_support}; then
+ dotest fork-1 "$testcvs -d:fork:$CVSROOT_DIRNAME version" \
+'Client: \(.*\)
+Server: \1'
+ else
+ dotest_fail fork-1-noss \
+"$testcvs -d:fork:$CVSROOT_DIRNAME version" \
+"Client: .*
+Server: ${CPROG} version: You must set the CVS_SERVER environment variable when
+${CPROG} version: using the :fork: access method\.
+${CPROG} \[version aborted\]: This CVS was not compiled with server support\."
+ fi
+
+ CVS_SERVER=${save_CVS_SERVER}; export CVS_SERVER
+ unset save_CVS_SERVER
+ PATH=$save_PATH; unset save_PATH
+
+ dokeep
+ cd ..
+ rm -r fork
+ fi
+ ;;
+
+
+
+ commit-add-missing)
+ # Make sure that a commit fails when a `cvs add'ed file has
+ # been removed from the working directory.
+
+ mkdir 1; cd 1
+ module=c-a-m
+ echo > unused-file
+ dotest commit-add-missing-1 \
+ "$testcvs -Q import -m. $module X Y" ''
+
+ file=F
+ # Check it out and tag it.
+ dotest commit-add-missing-2 "$testcvs -Q co $module" ''
+ cd $module
+ dotest commit-add-missing-3 "$testcvs -Q tag -b B" ''
+ echo v1 > $file
+ dotest commit-add-missing-4 "$testcvs -Q add $file" ''
+ rm -f $file
+ dotest_fail commit-add-missing-5 "$testcvs -Q ci -m. $file" \
+"${SPROG} commit: Up-to-date check failed for .$file'
+${SPROG} \[commit aborted\]: correct above errors first!"
+
+ dotest
+ cd ../..
+ rm -rf 1
+ modify_repo rm -rf $CVSROOT_DIRNAME/$module
+ ;;
+
+
+
+ commit-d)
+ # Check that top-level commits work when CVS/Root
+ # is overridden by cvs -d.
+
+ mkdir -p 1/subdir; cd 1
+ touch file1 subdir/file2
+ dotest commit-d-1 "$testcvs -Q import -m. c-d-c X Y" ""
+ dotest commit-d-2 "$testcvs -Q co c-d-c" ""
+ cd c-d-c
+ echo change >>file1; echo another change >>subdir/file2
+ # Changing working root, then override with -d
+ echo nosuchhost:/cvs > CVS/Root
+ dotest commit-d-3 "$testcvs -q -d '$CVSROOT' commit -m." \
+"$CVSROOT_DIRNAME/c-d-c/file1,v <-- file1
+new revision: 1.2; previous revision: 1.1
+$CVSROOT_DIRNAME/c-d-c/subdir/file2,v <-- subdir/file2
+new revision: 1.2; previous revision: 1.1"
+
+ dokeep
+ cd ../..
+ rm -rf 1 cvsroot/c-d-c
+ ;;
+
+
+
+ template)
+ # Check that the CVS/Template directory is being
+ # properly created.
+ modify_repo mkdir -p $CVSROOT_DIRNAME/first/subdir
+ modify_repo mkdir $CVSROOT_DIRNAME/second
+ mkdir template; cd template
+
+ # check that no CVS/Template is created for an empty rcsinfo
+ # Note: For cvs clients with no Clear-template response, the
+ # CVS/Template file will exist and be zero bytes in length.
+ dotest template-empty-1 "${testcvs} -Q co first" ''
+ dotest template-empty-2 \
+"test ! -s first/CVS/Template" ''
+ dotest template-empty-3 \
+"test ! -s first/subdir/CVS/Template" ''
+ rm -fr first
+
+ # create some template files
+ echo 'CVS: the default template' > ${TESTDIR}/template/temp.def
+ echo 'CVS: the first template' > ${TESTDIR}/template/temp.first
+ echo 'CVS: the subdir template' > ${TESTDIR}/template/temp.subdir
+
+ dotest template-rcsinfo-1 "${testcvs} -Q co CVSROOT" ''
+ cd CVSROOT
+ echo DEFAULT ${TESTDIR}/template/temp.def >>rcsinfo
+ dotest template-rcsinfo-2 "$testcvs -Q ci -m."
+ # Make sure we get the update without a commit.
+ dotest template-rcsinfo-3 "${testcvs} -Q ci -m." ''
+ # Did the CVSROOT/CVS/Template file get the updated version?
+ if $remote; then
+ dotest template-rcsinfo-4r \
+"cmp CVS/Template ${TESTDIR}/template/temp.def" ''
+ else
+ dotest template-rcsinfo-4 \
+"test ! -f CVS/Template" ''
+ fi
+ echo "^first/subdir ${TESTDIR}/template/temp.subdir" >>rcsinfo
+ echo "^first ${TESTDIR}/template/temp.first" >>rcsinfo
+ dotest template-rcsinfo-4.1 "${testcvs} -Q ci -m. rcsinfo"
+ # Did the CVSROOT/CVS/Template file get the updated version?
+ if $remote; then
+ dotest template-rcsinfo-5r \
+"cmp CVS/Template ${TESTDIR}/template/temp.def" ''
+ else
+ dotest template-rcsinfo-5 \
+"test ! -f CVS/Template" ''
+ fi
+ cd ..
+
+ # Now checkout the first and second modules and see
+ # if the proper template has been provided for each
+ dotest template-first "${testcvs} co first second" \
+"${SPROG} checkout: Updating first
+${SPROG} checkout: Updating first/subdir
+${SPROG} checkout: Updating second"
+
+ if $remote; then
+ # When in client/server CVS/Template must exist
+ dotest template-first-r-1 "test -f first/CVS/Template" ''
+ dotest template-first-r-2 "test -f first/subdir/CVS/Template" ''
+ dotest template-first-r-3 "test -f second/CVS/Template" ''
+ # The value of the CVS/Template should be equal to the
+ # file called out in the rcsinfo file.
+ dotest template-first-r-4 \
+"cmp first/CVS/Template ${TESTDIR}/template/temp.first" ''
+ dotest template-first-r-5 \
+"cmp first/subdir/CVS/Template ${TESTDIR}/template/temp.subdir" ''
+ dotest template-first-r-6 \
+"cmp second/CVS/Template ${TESTDIR}/template/temp.def" ''
+ else
+ # When in local mode CVS/Template must NOT exist
+ dotest_fail template-first-1 "test -f first/CVS/Template" ''
+ dotest_fail template-first-2 "test -f first/subdir/CVS/Template" ''
+ dotest_fail template-first-3 "test -f second/CVS/Template" ''
+ fi
+
+ # Next, create a new subdirectory and see if it gets the
+ # correct template or not
+ cd second
+ mkdir otherdir
+ dotest template-add-1 "${testcvs} add otherdir" \
+"Directory ${CVSROOT_DIRNAME}/second/otherdir added to the repository"
+ if $remote; then
+ dotest template-add-2r \
+"cmp otherdir/CVS/Template ${TESTDIR}/template/temp.def" ''
+ else
+ dotest_fail template-add-2 "test -f otherdir/CVS/Template" ''
+ fi
+ cd ..
+
+ # Update the remote template. Then see if doing an
+ # update of a checked out tree will properly update
+ # the CVS/Template files.
+ echo 'CVS: Line two' >> ${TESTDIR}/template/temp.def
+ echo 'CVS: Line two' >> ${TESTDIR}/template/temp.first
+ echo 'CVS: Line two' >> ${TESTDIR}/template/temp.subdir
+ dotest template-second "${testcvs} update first second" \
+"${SPROG} update: Updating first
+${SPROG} update: Updating first/subdir
+${SPROG} update: Updating second
+${SPROG} update: Updating second/otherdir"
+
+ if $remote; then
+ dotest template-second-r-1 \
+"cmp first/CVS/Template ${TESTDIR}/template/temp.first" ''
+ dotest template-second-r-2 \
+"cmp first/subdir/CVS/Template ${TESTDIR}/template/temp.subdir" ''
+ dotest template-second-r-3 \
+"cmp second/CVS/Template ${TESTDIR}/template/temp.def" ''
+ dotest template-second-r-4 \
+"cmp second/otherdir/CVS/Template ${TESTDIR}/template/temp.def" ''
+ else
+ # When in local mode CVS/Template must NOT exist
+ dotest_fail template-second-1 "test -f CVS/Template" ''
+ dotest_fail template-second-2 "test -f subdir/CVS/Template" ''
+ dotest_fail template-second-3 "test -f second/CVS/Template" ''
+ dotest_fail template-second-4 \
+"test -f second/otherdir/CVS/Template" ''
+ fi
+ # Update the remote template with a zero-length template
+ : > ${TESTDIR}/template/temp.def
+ dotest template-third-1 "${testcvs} update second" \
+"${SPROG} update: Updating second
+${SPROG} update: Updating second/otherdir"
+
+ if $remote; then
+ dotest_fail template-third-r-2 "test -s second/CVS/Template" ''
+ dotest_fail template-third-r-3 "test -s second/otherdir/CVS/Template" ''
+ else
+ dotest_fail template-third-2 "test -f second/CVS/Template" ''
+ dotest_fail template-third-3 \
+"test -f second/otherdir/CVS/Template" ''
+ fi
+
+ # fun with remote protocols and tags
+ if $remote; then
+ cd second
+ echo hello > file1
+ dotest template-tag-r-1 "${testcvs} -Q add file1" ''
+ dotest template-tag-r-2 "${testcvs} -Q commit -madd file1"
+ dotest template-tag-r-3 "${testcvs} -q tag tag" 'T file1'
+ rm ${CVSROOT_DIRNAME}/CVSROOT/val-tags
+ cd ..
+ rm -fr second
+ dotest template-tag-r-4 "${testcvs} -Q co -rtag second" ''
+ fi
+
+ cd CVSROOT
+ dotest template-norcsinfo-1 "${testcvs} up" \
+"${SPROG} update: Updating \."
+ # Did the CVSROOT/CVS/Template file get the updated version?
+ if $remote; then
+ dotest template-norcsinfo-r-2 \
+"cmp CVS/Template ${TESTDIR}/template/temp.def" ''
+ else
+ dotest_fail template-norcsinfo-2 "test -f CVS/Template" ''
+ fi
+
+ : > rcsinfo
+ dotest template-norcsinfo-3 "${testcvs} -Q ci -m. rcsinfo"
+ # Did the CVSROOT/CVS/Template file get the updated version?
+ # The file should be gone or of zero length.
+ dotest template-norcsinfo-4 \
+"test ! -s CVS/Template" ''
+ cd ..
+
+ dotest template-norcsinfo-5 "${testcvs} update first" \
+"${SPROG} update: Updating first
+${SPROG} update: Updating first/subdir"
+
+ # Note: For cvs clients with no Clear-template response, the
+ # CVS/Template file will exist and be zero bytes in length.
+ dotest template-norcsinfo-6 \
+"test ! -s first/CVS/Template" ''
+ dotest template-norcsinfo-7 \
+"test ! -s first/subdir/CVS/Template" ''
+
+ dokeep
+
+ # cleanup
+ modify_repo rm -rf $CVSROOT_DIRNAME/first $CVSROOT_DIRNAME/second
+ restore_adm
+ cd ..
+ rm -rf template
+ ;;
+
+
+
+ writeproxy)
+ # Various tests for a read-only CVS mirror set up as a write-proxy
+ # for a central server.
+ #
+ # These tests are only meaningful in client/server mode.
+ if $remote; then :; else
+ remoteonly writeproxy
+ continue
+ fi
+
+ if $noredirect; then
+ notnoredirect writeproxy
+ continue
+ fi
+
+ require_rsync
+ if test $? -eq 77; then
+ skip writeproxy "$skipreason"
+ continue
+ fi
+
+ PRIMARY_CVSROOT_DIRNAME_save=$PRIMARY_CVSROOT_DIRNAME
+ PRIMARY_CVSROOT_save=$PRIMARY_CVSROOT
+ PRIMARY_CVSROOT_DIRNAME=$TESTDIR/primary_cvsroot
+ PRIMARY_CVSROOT=`newroot $PRIMARY_CVSROOT_DIRNAME`
+ SECONDARY_CVSROOT_DIRNAME_save=$SECONDARY_CVSROOT_DIRNAME
+ SECONDARY_CVSROOT_save=$SECONDARY_CVSROOT
+ SECONDARY_CVSROOT_DIRNAME=$TESTDIR/writeproxy_cvsroot
+ SECONDARY_CVSROOT=`newroot $SECONDARY_CVSROOT_DIRNAME`
+
+ # Initialize the primary repository
+ dotest writeproxy-init-1 "$testcvs -d$PRIMARY_CVSROOT init"
+ mkdir writeproxy; cd writeproxy
+ mkdir primary; cd primary
+ dotest writeproxy-init-2 "$testcvs -Qd$PRIMARY_CVSROOT co CVSROOT"
+ cd CVSROOT
+ cat >>loginfo <<EOF
+ALL (cat >/dev/null; echo %R) >$TESTDIR/referrer
+ALL $RSYNC -gopr --delete $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+EOF
+ cat >>config <<EOF
+PrimaryServer=$PRIMARY_CVSROOT
+EOF
+ dotest writeproxy-init-3 \
+"$testcvs -Q ci -mconfigure-writeproxy"
+
+ # Quickly verify that the server can resolve symlinks when
+ # determining whether it is the primary.
+ # This shouldn't actually change the repository.
+ save_CVS_SERVER=$CVS_SERVER
+ ln -s $PRIMARY_CVSROOT_DIRNAME $TESTDIR/primary_link
+ dotest writeproxy-0 "$CVS_SERVER server" \
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version
+ok
+ok
+ok" \
+<< EOF
+Root $TESTDIR/primary_link
+Valid-responses ok error Valid-requests Redirect Checked-in New-entry Checksum Copy-file Updated Created Update-existing Merged Patched Rcs-diff Mode Mod-time Removed Remove-entry Set-static-directory Clear-static-directory Set-sticky Clear-sticky Edit-file Template Clear-template Notified Module-expansion Wrapper-rcsOption M Mbinary E F MT
+valid-requests
+UseUnchanged
+Command-prep commit
+Global_option -q
+Global_option -Q
+Argument -m
+Argument configure-writeproxy
+Argument --
+Directory .
+CVSROOT
+Entry /checkoutlist/1.1///
+Modified checkoutlist
+u=rw,g=rw,o=r
+495
+# The "checkoutlist" file is used to support additional version controlled
+# administrative files in \$CVSROOT/CVSROOT, such as template files.
+#
+# The first entry on a line is a filename which will be checked out from
+# the corresponding RCS file in the \$CVSROOT/CVSROOT directory.
+# The remainder of the line is an error message to use if the file cannot
+# be checked out.
+#
+# File format:
+#
+# [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>
+#
+# comment lines begin with '#'
+ci
+EOF
+ rm $TESTDIR/primary_link
+
+ # And now the secondary.
+ $RSYNC -gopr $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+
+ # Checkout from secondary
+ #
+ # For now, move the primary root out of the way to satisfy
+ # ourselves that the data is coming from the secondary.
+ mv $PRIMARY_CVSROOT_DIRNAME $TESTDIR/save-root
+ cd ../..
+ mkdir secondary; cd secondary
+ dotest writeproxy-1 "$testcvs -qd$SECONDARY_CVSROOT co CVSROOT" \
+"U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg"
+
+ # Confirm data present
+ cd CVSROOT
+ dotest writeproxy-2 "grep rsync loginfo" \
+"ALL $RSYNC -gopr --delete $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME"
+ dotest writeproxy-3 "grep PrimaryServer config" \
+"${DOTSTAR}
+PrimaryServer=$PRIMARY_CVSROOT"
+
+ # Checkin to secondary
+ cd ..
+ dotest writeproxy-4 "$testcvs -Qd$SECONDARY_CVSROOT co -ldtop ."
+ cd top
+ mkdir firstdir
+
+ # Have to move the primary root back before we can perform write
+ # operations.
+ mv $TESTDIR/save-root $PRIMARY_CVSROOT_DIRNAME
+
+ dotest writeproxy-5 "$testcvs -Q add firstdir"
+ cd firstdir
+ echo now you see me >file1
+ dotest writeproxy-6 "$testcvs -Q add file1"
+ dotest writeproxy-6a "grep file1 CVS/Entries >/dev/null"
+ dotest writeproxy-7 "$testcvs -Q ci -mfirst-file file1"
+
+ # Verify that the server got the correct referrer.
+ #
+ # This happens even when using a :fork:ed server because CVS is
+ # hardcoded to support only :ext: servers.
+ #
+ # This test meaningfully detects that a referrer was passed in fork
+ # mode because the only time the referrer string can be altered from
+ # its original state is when the server sends a Referrer response.
+ # If the client were not parsing and resending the referrer, this
+ # string would still match $SECONDARY_CVSROOT_DIRNAME.
+ dotest writeproxy-7a "cat $TESTDIR/referrer" \
+":ext:$username@$hostname$SECONDARY_CVSROOT_DIRNAME"
+
+ # Make sure the sync took place
+ dotest writeproxy-7b "$testcvs -Q up"
+
+ # Checkout from primary
+ cd ../../../primary
+ dotest writeproxy-8 "$testcvs -qd$PRIMARY_CVSROOT co firstdir" \
+"U firstdir/file1"
+
+ # Confirm data present
+ # - This test indirectly confirms that the commit did not take
+ # place on the secondary.
+ cd firstdir
+ dotest writeproxy-9 "cat file1" "now you see me"
+
+ # Commit to primary
+ echo now you see me again >file1
+ dotest writeproxy-10 "$testcvs -Q ci -medit file1"
+
+ # Update from secondary
+ cd ../../secondary/top/firstdir
+ dotest writeproxy-11 "$testcvs -q up" \
+"U file1"
+
+ # Confirm data present
+ dotest writeproxy-12 "cat file1" "now you see me again"
+
+ # Test a failing rsync
+ cd ../../CVSROOT
+ sed \$d <loginfo >tmp
+ mv tmp loginfo
+ echo >>loginfo \
+"ALL echo >&2 'Im rsync and I encountered an error!'; cat >/dev/null; exit 1"
+ dotest writeproxy-init-13 "$testcvs -Q ci -mbreak-rsync" \
+"Im rsync and I encountered an error!"
+ echo "# a comment" >>loginfo
+ dotest writeproxy-13 "$testcvs -Q ci -mtest-broken-rsync" \
+"Im rsync and I encountered an error!"
+ touch loginfo
+ dotest_fail writeproxy-14 "$testcvs up" \
+"$SPROG update: Updating \.
+$SPROG \[update aborted\]: could not find desired version 1\.4 in $PRIMARY_CVSROOT_DIRNAME/CVSROOT/loginfo,v"
+
+ dokeep
+ cd ../../..
+ rm -r writeproxy $TESTDIR/referrer
+ rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
+ PRIMARY_CVSROOT_DIRNAME=$PRIMARY_CVSROOT_DIRNAME_save
+ PRIMARY_CVSROOT=$PRIMARY_CVSROOT_save
+ SECONDARY_CVSROOT_DIRNAME=$SECONDARY_CVSROOT_DIRNAME_save
+ SECONDARY_CVSROOT=$SECONDARY_CVSROOT_save
+ ;;
+
+
+
+ writeproxy-noredirect)
+ # Various tests for a read-only CVS mirror set up as a write-proxy
+ # for a central server.
+ #
+ # These tests are only meaningful in client/server mode.
+ #
+ # These tests are a few simple tests for a writeproxy setup with a
+ # client that can't handle the `Redirect' response. Mostly they
+ # parallel the "writeproxy" tests but, in the style of the "server",
+ # "server2", "pserver", and related tests, they bypass the CVS client
+ # for write commands by piping data into a server on STDIN to mimic
+ # a client that cannot handle the `Redirect' response.
+ if $remote; then :; else
+ remoteonly writeproxy-noredirect
+ continue
+ fi
+
+ require_rsync
+ if test $? -eq 77; then
+ skip writeproxy-noredirect "$skipreason"
+ continue
+ fi
+
+ PRIMARY_CVSROOT_DIRNAME_save=$PRIMARY_CVSROOT_DIRNAME
+ PRIMARY_CVSROOT_save=$PRIMARY_CVSROOT
+ PRIMARY_CVSROOT_DIRNAME=$TESTDIR/primary_cvsroot
+ PRIMARY_CVSROOT=`newroot $PRIMARY_CVSROOT_DIRNAME`
+ SECONDARY_CVSROOT_DIRNAME_save=$SECONDARY_CVSROOT_DIRNAME
+ SECONDARY_CVSROOT_DIRNAME=$TESTDIR/writeproxy_cvsroot
+
+ # Initialize the primary repository
+ dotest writeproxy-noredirect-init-1 \
+"$testcvs -d'$PRIMARY_CVSROOT' init"
+ mkdir writeproxy-noredirect; cd writeproxy-noredirect
+ mkdir primary; cd primary
+ dotest writeproxy-noredirect-init-2 \
+"$testcvs -Qd'$PRIMARY_CVSROOT' co CVSROOT"
+ cd CVSROOT
+ cat >>loginfo <<EOF
+ALL $RSYNC -gopr --delete $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+EOF
+ cat >>config <<EOF
+PrimaryServer=$PRIMARY_CVSROOT
+EOF
+ dotest writeproxy-noredirect-init-3 \
+"$testcvs -Q ci -mconfigure-writeproxy"
+
+ # And now the secondary.
+ $RSYNC -gopr $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+
+ CVS_SERVER_save=$CVS_SERVER
+ CVS_SERVER_secondary=$TESTDIR/writeproxy-secondary-wrapper
+ CVS_SERVER=$CVS_SERVER_secondary
+
+ # Wrap the CVS server to allow --primary-root to be set by the
+ # secondary.
+ cat <<EOF >$TESTDIR/writeproxy-secondary-wrapper
+#! $TESTSHELL
+CVS_SERVER=$TESTDIR/writeproxy-primary-wrapper
+export CVS_SERVER
+
+# No need to check the PID of the last client since we are testing with
+# Redirect disabled.
+proot_arg="--allow-root $SECONDARY_CVSROOT_DIRNAME"
+exec $servercvs \$proot_arg "\$@"
+EOF
+ cat <<EOF >$TESTDIR/writeproxy-primary-wrapper
+#! $TESTSHELL
+#CVS_SERVER_LOG=/tmp/cvsprimarylog
+exec $servercvs "\$@"
+EOF
+
+ chmod a+x $TESTDIR/writeproxy-secondary-wrapper \
+ $TESTDIR/writeproxy-primary-wrapper
+
+ # Checkout from secondary
+ #
+ # It may look like we are checking out from the primary here, but
+ # in fork mode, the deciding factor is the PrimaryServer translation
+ # above.
+ #
+ # When the primary and secondary hostname were different, the server
+ # the client is talking directly to is more obvious.
+ #
+ # For now, move the primary root out of the way to satisfy
+ # ourselves that the data is coming from the secondary.
+ mv $PRIMARY_CVSROOT_DIRNAME $TESTDIR/save-root
+ cd ../..
+ mkdir secondary; cd secondary
+ dotest writeproxy-noredirect-1 \
+"$testcvs -qd'$PRIMARY_CVSROOT' co CVSROOT" \
+"U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/postadmin
+U CVSROOT/postproxy
+U CVSROOT/posttag
+U CVSROOT/postwatch
+U CVSROOT/preproxy
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg"
+
+ # Confirm data present
+ cd CVSROOT
+ dotest writeproxy-noredirect-2 "grep rsync loginfo" \
+"ALL $RSYNC -gopr --delete $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME"
+ dotest writeproxy-noredirect-3 "grep PrimaryServer config" \
+"${DOTSTAR}
+PrimaryServer=$PRIMARY_CVSROOT"
+
+ # Checkin to secondary
+ cd ..
+ dotest writeproxy-noredirect-4 \
+"$testcvs -Qd'$PRIMARY_CVSROOT' co -ldtop ."
+ cd top
+ mkdir firstdir
+
+ # Have to move the primary root back before we can perform write
+ # operations.
+ mv $TESTDIR/save-root $PRIMARY_CVSROOT_DIRNAME
+
+ dotest writeproxy-noredirect-5 "$CVS_SERVER server" \
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version
+ok
+ok
+ok
+Clear-template firstdir/
+firstdir/
+ok" \
+<< EOF
+Root $PRIMARY_CVSROOT_DIRNAME
+Valid-responses ok error Valid-requests Checked-in New-entry Checksum Copy-file Updated Created Update-existing Merged Patched Rcs-diff Mode Mod-time Removed Remove-entry Set-static-directory Clear-static-directory Set-sticky Clear-sticky Template Clear-template Notified Module-expansion Wrapper-rcsOption M Mbinary E F MT
+valid-requests
+UseUnchanged
+Command-prep add
+Global_option -q
+Global_option -Q
+wrapper-sendme-rcsOptions
+Argument --
+Directory firstdir
+firstdir
+Directory .
+
+Argument firstdir
+add
+EOF
+
+ # Gotta update the workspace ourselves since we bypassed the client.
+ cp -R CVS firstdir/CVS
+ echo "firstdir" >firstdir/CVS/Repository
+
+ cd firstdir
+ echo now you see me >file1
+ dotest writeproxy-noredirect-6 "$CVS_SERVER server" \
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version
+ok
+ok
+ok
+Checked-in \./
+firstdir/file1
+/file1/0///
+ok" \
+<< EOF
+Root $PRIMARY_CVSROOT_DIRNAME
+Valid-responses ok error Valid-requests Checked-in New-entry Checksum Copy-file Updated Created Update-existing Merged Patched Rcs-diff Mode Mod-time Removed Remove-entry Set-static-directory Clear-static-directory Set-sticky Clear-sticky Template Clear-template Notified Module-expansion Wrapper-rcsOption M Mbinary E F MT
+valid-requests
+UseUnchanged
+Command-prep add
+Global_option -q
+Global_option -Q
+wrapper-sendme-rcsOptions
+Argument --
+Directory .
+firstdir
+Is-modified file1
+Argument file1
+add
+EOF
+
+ # Have to add it to the workspace ourselves again since we are
+ # bypassing the client.
+ echo /file1/0/dummy+timestamp// >>CVS/Entries
+
+ dotest writeproxy-noredirect-7 "$CVS_SERVER server" \
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version
+ok
+ok
+Mode u=rw,g=rw,o=r
+Checked-in \./
+firstdir/file1
+/file1/1\.1///
+ok" \
+<< EOF
+Root $PRIMARY_CVSROOT_DIRNAME
+Valid-responses ok error Valid-requests Checked-in New-entry Checksum Copy-file Updated Created Update-existing Merged Patched Rcs-diff Mode Mod-time Removed Remove-entry Set-static-directory Clear-static-directory Set-sticky Clear-sticky Template Clear-template Notified Module-expansion Wrapper-rcsOption M Mbinary E F MT
+valid-requests
+UseUnchanged
+Command-prep commit
+Global_option -q
+Global_option -Q
+Argument -m
+Argument first-file
+Argument --
+Directory .
+firstdir
+Entry /file1/0/+modified//
+Modified file1
+u=rw,g=rw,o=r
+15
+now you see me
+Argument file1
+ci
+EOF
+
+ # Have to add it to the workspace ourselves again since we are
+ # bypassing the client.
+ echo D >CVS/Entries
+ echo /file1/1.1/dummy+timestamp// >>CVS/Entries
+
+ # Make sure the sync took place
+ dotest writeproxy-noredirect-7a "$testcvs -Q up"
+
+ CVS_SERVER=$servercvs
+ # Checkout from primary
+ cd ../../../primary
+ dotest writeproxy-noredirect-8 \
+"$testcvs -qd'$PRIMARY_CVSROOT' co firstdir" \
+"U firstdir/file1"
+
+ # Confirm data present
+ # - This test indirectly confirms that the commit did not take
+ # place on the secondary.
+ cd firstdir
+ dotest writeproxy-noredirect-9 "cat file1" "now you see me"
+
+ # Commit to primary
+ echo now you see me again >file1
+ dotest writeproxy-noredirect-10 "$testcvs -Q ci -medit file1"
+
+ CVS_SERVER=$CVS_SERVER_secondary
+ # Update from secondary
+ cd ../../secondary/top/firstdir
+ dotest writeproxy-noredirect-11 "$testcvs -q up" "U file1"
+
+ # Confirm data present
+ dotest writeproxy-noredirect-12 "cat file1" "now you see me again"
+
+ dokeep
+ cd ../../../..
+ rm -r writeproxy-noredirect
+ rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
+ rm $TESTDIR/writeproxy-secondary-wrapper \
+ $TESTDIR/writeproxy-primary-wrapper
+ CVS_SERVER=$CVS_SERVER_save
+ PRIMARY_CVSROOT_DIRNAME=$PRIMARY_CVSROOT_DIRNAME_save
+ PRIMARY_CVSROOT=$PRIMARY_CVSROOT_save
+ SECONDARY_CVSROOT_DIRNAME=$SECONDARY_CVSROOT_DIRNAME_save
+ ;;
+
+
+
+ writeproxy-ssh)
+ # Various tests for a read-only CVS mirror set up as a write-proxy
+ # for a central server accessed via the :ext: method.
+ #
+ # Mostly these tests are intended to set up for the final test which
+ # verifies that the server registers the referrer.
+ if $remote; then :; else
+ remoteonly writeproxy-ssh
+ continue
+ fi
+
+ if $noredirect; then
+ notnoredirect writeproxy-ssh
+ continue
+ fi
+
+ require_rsh "$CVS_RSH"
+ if test $? -eq 77; then
+ skip writeproxy-ssh "$skipreason"
+ continue
+ fi
+
+ require_rsync
+ if test $? -eq 77; then
+ skip writeproxy-ssh "$skipreason"
+ continue
+ fi
+
+ # Save old roots.
+ PRIMARY_CVSROOT_DIRNAME_save=$PRIMARY_CVSROOT_DIRNAME
+ PRIMARY_CVSROOT_save=$PRIMARY_CVSROOT
+ SECONDARY_CVSROOT_DIRNAME_save=$SECONDARY_CVSROOT_DIRNAME
+ SECONDARY_CVSROOT_save=$SECONDARY_CVSROOT
+
+ # Set new roots.
+ PRIMARY_CVSROOT_DIRNAME=$TESTDIR/primary_cvsroot
+ PRIMARY_CVSROOT=:ext:$host$PRIMARY_CVSROOT_DIRNAME
+ SECONDARY_CVSROOT_DIRNAME=$TESTDIR/writeproxy_cvsroot
+ SECONDARY_CVSROOT=":ext;Redirect=yes:$host$SECONDARY_CVSROOT_DIRNAME"
+
+ # Initialize the primary repository
+ dotest writeproxy-ssh-init-1 "$testcvs -d$PRIMARY_CVSROOT init"
+ mkdir writeproxy-ssh; cd writeproxy-ssh
+ mkdir primary; cd primary
+ dotest writeproxy-ssh-init-2 "$testcvs -Qd$PRIMARY_CVSROOT co CVSROOT"
+ cd CVSROOT
+ cat >>loginfo <<EOF
+ALL $RSYNC -gopr --delete $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+EOF
+ cat >>loginfo <<EOF
+ALL echo Referrer=%R; cat >/dev/null
+EOF
+ cat >>config <<EOF
+PrimaryServer=$PRIMARY_CVSROOT
+EOF
+ dotest writeproxy-ssh-init-3 \
+"$testcvs -Q ci -mconfigure-writeproxy-ssh" \
+"Referrer=NONE"
+
+ # And now the secondary.
+ $RSYNC -gopr $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+
+ # Checkout from secondary
+ #
+ # For now, move the primary root out of the way to satisfy
+ # ourselves that the data is coming from the secondary.
+ mv $PRIMARY_CVSROOT_DIRNAME $TESTDIR/save-root
+
+ # Checkin to secondary
+ cd ../..
+ save_CVSROOT=$CVSROOT
+ CVSROOT=$SECONDARY_CVSROOT
+ export CVSROOT
+ dotest writeproxy-ssh-1 "$testcvs -Q co -ldtop ."
+ CVSROOT=$save_CVSROOT
+ export CVSROOT
+ cd top
+ mkdir firstdir
+
+ # Have to move the primary root back before we can perform write
+ # operations.
+ mv $TESTDIR/save-root $PRIMARY_CVSROOT_DIRNAME
+
+ dotest writeproxy-ssh-2 "$testcvs -Q add firstdir" \
+"Referrer=:ext:$username@$hostname$SECONDARY_CVSROOT_DIRNAME"
+
+ cd firstdir
+ echo now you see me >file1
+ dotest writeproxy-ssh-3 "$testcvs -Q add file1"
+ dotest writeproxy-ssh-4 "$testcvs -Q ci -mfirst-file file1" \
+"Referrer=:ext:$username@$hostname$SECONDARY_CVSROOT_DIRNAME"
+
+ dokeep
+ cd ../../..
+ rm -r writeproxy-ssh
+ rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
+ PRIMARY_CVSROOT_DIRNAME=$PRIMARY_CVSROOT_DIRNAME_save
+ PRIMARY_CVSROOT=$PRIMARY_CVSROOT_save
+ SECONDARY_CVSROOT_DIRNAME=$SECONDARY_CVSROOT_DIRNAME_save
+ SECONDARY_CVSROOT=$SECONDARY_CVSROOT_save
+ ;;
+
+
+
+ writeproxy-ssh-noredirect)
+ # Various tests for a read-only CVS mirror set up as a write-proxy
+ # for a central server accessed via the :ext: method.
+ #
+ # Mostly these tests are intended to set up for the final test which
+ # verifies that the server registers the referrer.
+ if $remote; then :; else
+ remoteonly writeproxy-ssh-noredirect
+ continue
+ fi
+
+ require_rsh "$CVS_RSH"
+ if test $? -eq 77; then
+ skip writeproxy-ssh-noredirect "$skipreason"
+ continue
+ fi
+
+ require_rsync
+ if test $? -eq 77; then
+ skip writeproxy-ssh-noredirect "$skipreason"
+ continue
+ fi
+
+ # Save old roots.
+ PRIMARY_CVSROOT_DIRNAME_save=$PRIMARY_CVSROOT_DIRNAME
+ PRIMARY_CVSROOT_save=$PRIMARY_CVSROOT
+ SECONDARY_CVSROOT_DIRNAME_save=$SECONDARY_CVSROOT_DIRNAME
+ SECONDARY_CVSROOT_save=$SECONDARY_CVSROOT
+
+ # Set new roots.
+ PRIMARY_CVSROOT_DIRNAME=$TESTDIR/primary_cvsroot
+ PRIMARY_CVSROOT=:ext:$host$PRIMARY_CVSROOT_DIRNAME
+ SECONDARY_CVSROOT_DIRNAME=$TESTDIR/writeproxy_cvsroot
+ SECONDARY_CVSROOT=":ext;Redirect=no:$host$PRIMARY_CVSROOT_DIRNAME"
+
+ # Initialize the primary repository
+ dotest writeproxy-ssh-noredirect-init-1 \
+"$testcvs -d$PRIMARY_CVSROOT init"
+ mkdir writeproxy-ssh-noredirect; cd writeproxy-ssh-noredirect
+ mkdir primary; cd primary
+ dotest writeproxy-ssh-noredirect-init-2 \
+"$testcvs -Qd$PRIMARY_CVSROOT co CVSROOT"
+ cd CVSROOT
+ cat >>loginfo <<EOF
+ALL $RSYNC -gopr --delete $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+EOF
+ cat >>loginfo <<EOF
+ALL echo Referrer=%R; cat >/dev/null
+EOF
+ cat >>config <<EOF
+PrimaryServer=$PRIMARY_CVSROOT
+EOF
+ dotest writeproxy-ssh-noredirect-init-3 \
+"$testcvs -Q ci -mconfigure-writeproxy-ssh-noredirect" \
+"Referrer=NONE"
+
+ # And now the secondary.
+ $RSYNC -gopr $PRIMARY_CVSROOT_DIRNAME/ $SECONDARY_CVSROOT_DIRNAME
+
+ # Wrap the CVS server to allow --primary-root to be set by the
+ # secondary.
+ cat <<EOF >$TESTDIR/writeproxy-secondary-wrapper
+#! $TESTSHELL
+CVS_SERVER=$TESTDIR/writeproxy-primary-wrapper
+export CVS_SERVER
+
+# No need to check the PID of the last client since we are testing with
+# Redirect disabled.
+proot_arg="--allow-root=$SECONDARY_CVSROOT_DIRNAME"
+exec $CVS_SERVER \$proot_arg "\$@"
+EOF
+ cat <<EOF >$TESTDIR/writeproxy-primary-wrapper
+#! $TESTSHELL
+if test -n "\$CVS_SERVER_LOG"; then
+ CVS_SERVER_LOG=$TMPDIR/cvsprimarylog; export CVS_SERVER_LOG
+fi
+exec $CVS_SERVER "\$@"
+EOF
+
+ CVS_SERVER_save=$CVS_SERVER
+ CVS_SERVER_secondary=$TESTDIR/writeproxy-secondary-wrapper
+ CVS_SERVER=$CVS_SERVER_secondary
+
+ chmod a+x $TESTDIR/writeproxy-secondary-wrapper \
+ $TESTDIR/writeproxy-primary-wrapper
+
+ # Checkout from secondary
+ #
+ # For now, move the primary root out of the way to satisfy
+ # ourselves that the data is coming from the secondary.
+ mv $PRIMARY_CVSROOT_DIRNAME $TESTDIR/save-root
+
+ # Checkin to secondary
+ cd ../..
+ dotest writeproxy-ssh-noredirect-1 \
+"$testcvs -qd '$SECONDARY_CVSROOT' co -ldtop ."
+
+ cd top
+ mkdir firstdir
+
+ # Have to move the primary root back before we can perform write
+ # operations.
+ mv $TESTDIR/save-root $PRIMARY_CVSROOT_DIRNAME
+
+ dotest writeproxy-ssh-noredirect-2 "$testcvs -Q add firstdir" \
+"Referrer=NONE"
+
+ cd firstdir
+ echo now you see me >file1
+ dotest writeproxy-ssh-noredirect-3 "$testcvs -Q add file1"
+ dotest writeproxy-ssh-noredirect-4 \
+"$testcvs -Q ci -mfirst-file file1" \
+"Referrer=NONE"
+
+ dokeep
+ cd ../../..
+ rm -r writeproxy-ssh-noredirect
+ rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
+ PRIMARY_CVSROOT_DIRNAME=$PRIMARY_CVSROOT_DIRNAME_save
+ PRIMARY_CVSROOT=$PRIMARY_CVSROOT_save
+ SECONDARY_CVSROOT_DIRNAME=$SECONDARY_CVSROOT_DIRNAME_save
+ SECONDARY_CVSROOT=$SECONDARY_CVSROOT_save
+ rm $TESTDIR/writeproxy-secondary-wrapper \
+ $TESTDIR/writeproxy-primary-wrapper
+ CVS_SERVER=$CVS_SERVER_save
+ ;;
+
+
+
+ trace)
+ # Check that there are no core dumps lurking in the trace
+ # options.
+
+ # Perform some cleanup for normalized testing...
+ rm ${CVSROOT_DIRNAME}/CVSROOT/history
+ rm -f ${CVSROOT_DIRNAME}/CVSROOT/cvsignore
+ rm -f ${CVSROOT_DIRNAME}/CVSROOT/cvsignore,v
+
+ # checkout the trace option
+
+ mkdir trace && cd trace
+ mkdir imp && cd imp
+ touch file1
+
+ dotest_sort trace-1 "${testcvs} -t -t -t init" \
+" *-> Lock_Cleanup()
+ *-> RCS_checkout (checkoutlist,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (commitinfo,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (config,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (cvswrappers,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (loginfo,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (modules,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (notify,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (postadmin,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (postproxy,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (posttag,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (postwatch,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (preproxy,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (rcsinfo,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (taginfo,v, , , , \.#[0-9][0-9]*)
+ *-> RCS_checkout (verifymsg,v, , , , \.#[0-9][0-9]*)
+ *-> Simple_Lock_Cleanup()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#[0-9][0-9]*)
+ *-> unlink_file(\.#checkoutlist)
+ *-> unlink_file(\.#commitinfo)
+ *-> unlink_file(\.#config)
+ *-> unlink_file(\.#cvswrappers)
+ *-> unlink_file(\.#loginfo)
+ *-> unlink_file(\.#modules)
+ *-> unlink_file(\.#notify)
+ *-> unlink_file(\.#postadmin)
+ *-> unlink_file(\.#postproxy)
+ *-> unlink_file(\.#posttag)
+ *-> unlink_file(\.#postwatch)
+ *-> unlink_file(\.#preproxy)
+ *-> unlink_file(\.#rcsinfo)
+ *-> unlink_file(\.#taginfo)
+ *-> unlink_file(\.#verifymsg)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )" \
+"
+ *-> Forking server: ${CVS_SERVER} server
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> CVS_SERVER_SLEEP not set\.
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> RCS_checkout (checkoutlist,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (commitinfo,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (config,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (cvswrappers,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (loginfo,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (modules,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (notify,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (postadmin,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (postproxy,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (posttag,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (postwatch,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (preproxy,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (rcsinfo,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (taginfo,v, , , , \.#[0-9][0-9]*)
+S -> RCS_checkout (verifymsg,v, , , , \.#[0-9][0-9]*)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> do_cvs_command (init)
+S -> remove_locks()
+S -> remove_locks()
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#[0-9][0-9]*)
+S -> unlink_file(\.#checkoutlist)
+S -> unlink_file(\.#commitinfo)
+S -> unlink_file(\.#config)
+S -> unlink_file(\.#cvswrappers)
+S -> unlink_file(\.#loginfo)
+S -> unlink_file(\.#modules)
+S -> unlink_file(\.#notify)
+S -> unlink_file(\.#postadmin)
+S -> unlink_file(\.#postproxy)
+S -> unlink_file(\.#posttag)
+S -> unlink_file(\.#postwatch)
+S -> unlink_file(\.#preproxy)
+S -> unlink_file(\.#rcsinfo)
+S -> unlink_file(\.#taginfo)
+S -> unlink_file(\.#verifymsg)" \
+
+ dotest_sort trace-2 \
+"${testcvs} -t -t -t import -mimport trace MYVENDOR version-1" \
+"
+
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+ *-> Simple_Lock_Cleanup()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> safe_location( where=(null) )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+N trace/file1
+No conflicts created by this import" \
+"
+
+
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Sending file \`file1' to server
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+N trace/file1
+No conflicts created by this import
+S -> CVS_SERVER_SLEEP not set\.
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (import)
+S -> remove_locks()
+S -> remove_locks()
+S -> safe_location( where=(null) )
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()"
+
+ cd ..
+ rm -fr imp
+
+ dotest_sort trace-3 "${testcvs} -t -t -t co trace" \
+" *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *local=0, which=3, aflag=0,
+ *locktype=1, update_preload=trace
+ *-> Create_Admin
+ *-> Create_Admin (\., trace, ${CVSROOT_DIRNAME}/trace, , , 0, 0, 1)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, , , file1)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Register(file1, 1\.1\.1\.1, ${DATE}, , )
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Write_Template (trace, ${CVSROOT_DIRNAME}/trace)
+ *-> chmod(file1,[0-7][0-7]*)
+ *-> do_module (trace, Updating, NULL, NULL)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> safe_location( where=(null) )
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(\./CVS/Entries\.Static)
+ *-> unlink_file(\./CVS/Tag)
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> unlink_file_dir(CVS/,,file1)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+U trace/file1
+${SPROG} checkout: Updating trace" \
+"
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *local=0, which=3, aflag=0,
+ *locktype=1, update_preload=trace
+ *-> Create_Admin
+ *-> Create_Admin (trace, trace, ${CVSROOT_DIRNAME}/trace, , , 0, 0, 1)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Register(file1, 1\.1\.1\.1, ${DATE}, , )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(\.new\.file1,file1)
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> safe_location( where=(null) )
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> unlink_file(CVS/Entries\.Static)
+ *-> unlink_file(CVS/Tag)
+ *-> unlink_file(CVS/Template)
+ *-> unlink_file(trace/CVS/Tag)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> CVS_SERVER_SLEEP not set\.
+S -> Create_Admin
+S -> Create_Admin (\., trace, ${CVSROOT_DIRNAME}/trace, , , 0, 0, 1)
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/rcsinfo, trace, ALL)
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, , , (function))
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Register(file1, 1\.1\.1\.1, , , )
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Write_Template (trace, ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (\., ${CVSROOT_DIRNAME})
+S -> dirswitch (\., ${CVSROOT_DIRNAME})
+S -> do_cvs_command (checkout)
+S -> do_module (trace, Updating, NULL, NULL)
+S -> do_module (trace, Updating, NULL, NULL)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> safe_location( where=(null) )
+S -> serve_directory (\.)
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_register(file1, 1\.1\.1\.1, , , , , )
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(\./CVS/Entries\.Static)
+S -> unlink_file(\./CVS/Tag)
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+U trace/file1
+${SPROG} checkout: Updating trace"
+
+ cd trace
+ mkdir subdir
+ dotest_sort trace-4 "${testcvs} -t -t -t add subdir" \
+" *-> Create_Admin
+ *-> Create_Admin (\., subdir, ${CVSROOT_DIRNAME}/trace/subdir, , , 0, 0, 1)
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace/subdir, ALL)
+ *-> Simple_Lock_Cleanup()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> unlink_file(\./CVS/Tag)
+ *-> unlink_file(${CVSROOT_DIRNAME}/trace/subdir/CVS/fileattr)
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+Directory ${CVSROOT_DIRNAME}/trace/subdir added to the repository" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *-> Create_Admin
+ *-> Create_Admin (subdir, subdir, ${CVSROOT_DIRNAME}/trace/subdir, , , 0, 0, 1)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+${DOTSTAR} *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+${DOTSTAR} *-> unlink_file(CVS/Template)
+ *-> unlink_file(subdir/CVS/Tag)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${DOTSTAR}Directory ${CVSROOT_DIRNAME}/trace/subdir added to the repository
+S -> CVS_SERVER_SLEEP not set\.
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace/subdir, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/rcsinfo, trace/subdir, ALL)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Write_Template (subdir, ${CVSROOT_DIRNAME}/trace/subdir)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (subdir, ${CVSROOT_DIRNAME}/trace/subdir)
+S -> do_cvs_command (add)
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> serve_directory (subdir)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> unlink_file(${CVSROOT_DIRNAME}/trace/subdir/CVS/fileattr)
+S -> unlink_file(CVS/Entries\.Log)
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )"
+ touch file2
+ dotest_sort trace-5 "${testcvs} -t -t -t add file2" \
+" *-> Lock_Cleanup()
+ *-> Register(file2, 0, Initial file2, , )
+ *-> Simple_Lock_Cleanup()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${SPROG} add: scheduling file \`file2' for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Register(file2, 0, dummy timestamp, , )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+${DOTSTAR} *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+${DOTSTAR} *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${DOTSTAR}S -> CVS_SERVER_SLEEP not set\.
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Register(file2, 0, Initial file2, , )
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (add)
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_register(file2, 0, Initial file2, , , , )
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${SPROG} add: scheduling file \`file2' for addition
+${SPROG} add: use \`${SPROG} commit' to add this file permanently"
+ dotest_sort trace-6 "${testcvs} -t -t -t ci -mnew-file file2" \
+" *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/commitinfo, trace, ALL)
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+ *-> Promotable_Lock ()
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file2,v, 1, , , (function))
+ *-> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file2,v, 1, (null), , file2 )
+ *-> Register(file2, 1\.1, ${DATE}, , )
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_tree_promotably (1, argv, 0, 1, 0)
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_lock(${CVSROOT_DIRNAME}/trace)
+ *-> rcs_cleanup()
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace)
+ *-> remove_locks()
+ *-> remove_locks()
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 0)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Base/file2)
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> unlink_file(CVS/file2,t)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${CVSROOT_DIRNAME}/trace/file2,v <-- file2
+initial revision: 1\.1" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Register(file2, 1\.1, ${DATE}, , )
+ *-> Sending file \`file2' to server
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Base/file2)
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${CVSROOT_DIRNAME}/trace/file2,v <-- file2
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/commitinfo, trace, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+S -> Promotable_Lock ()
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file2,v, 1, , , (function))
+S -> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file2,v, 1, (null), , file2 )
+S -> Register(file2, 1\.1, ${DATE}, , )
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (commit)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_tree_promotably (1, argv, 0, 1, 0)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_lock(${CVSROOT_DIRNAME}/trace)
+S -> rcs_cleanup()
+S -> readers_exist (${CVSROOT_DIRNAME}/trace)
+S -> remove_locks()
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+S -> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file2)
+S -> server_pathname_check (file2)
+S -> server_pathname_check (file2)
+S -> server_register(file2, 1\.1, ${DATE}, , , , )
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 0)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(CVS/Entries\.Log)
+S -> unlink_file(CVS/file2,t)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+initial revision: 1\.1"
+ dotest_sort trace-7 "${testcvs} -t -t -t tag bp" \
+" *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in= )
+ *dosrcs=1, repository_in= )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=1, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *local_specified=0, mname=(null), msg=(null) )
+ *mwhere=(null), mfile=(null), shorten=0,
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/taginfo, trace, ALL)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.\*, (null))
+ *-> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file1, ${CVSROOT_DIRNAME}/trace/file1,v )
+ *-> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file2, ${CVSROOT_DIRNAME}/trace/file2,v )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> rcs_cleanup()
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace)
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> remove_locks()
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> rtag_proc ( argc=1, argv=${PFMT}, xwhere=(null),
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+T file1
+T file2
+${SPROG} tag: Tagging \.
+${SPROG} tag: Tagging subdir" \
+"
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in= )
+ *dosrcs=1, repository_in= )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *local_specified=0, mname=(null), msg=(null) )
+ *mwhere=(null), mfile=(null), shorten=0,
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/taginfo, trace, ALL)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.\*, (null))
+S -> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file1, ${CVSROOT_DIRNAME}/trace/file1,v )
+S -> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file2, ${CVSROOT_DIRNAME}/trace/file2,v )
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (subdir, ${CVSROOT_DIRNAME}/trace/subdir)
+S -> do_cvs_command (tag)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace/subdir)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+S -> rcs_cleanup()
+S -> readers_exist (${CVSROOT_DIRNAME}/trace)
+S -> readers_exist (${CVSROOT_DIRNAME}/trace/subdir)
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+S -> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> rtag_proc ( argc=1, argv=${PFMT}, xwhere=(null),
+S -> serve_directory (\.)
+S -> serve_directory (\.)
+S -> serve_directory (subdir)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(CVS/Entries\.Log)
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+T file1
+T file2
+${SPROG} tag: Tagging \.
+${SPROG} tag: Tagging subdir"
+
+ dotest_sort trace-8 "${testcvs} -t -t -t tag -b branch1" \
+" *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in= )
+ *dosrcs=1, repository_in= )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=1, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *local_specified=0, mname=(null), msg=(null) )
+ *mwhere=(null), mfile=(null), shorten=0,
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/taginfo, trace, ALL)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.\*, (null))
+ *-> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file1, ${CVSROOT_DIRNAME}/trace/file1,v )
+ *-> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file2, ${CVSROOT_DIRNAME}/trace/file2,v )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> rcs_cleanup()
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace)
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> remove_locks()
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+ *-> rtag_proc ( argc=1, argv=${PFMT}, xwhere=(null),
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+T file1
+T file2
+${SPROG} tag: Tagging \.
+${SPROG} tag: Tagging subdir" \
+"
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in= )
+ *dosrcs=1, repository_in= )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *local_specified=0, mname=(null), msg=(null) )
+ *mwhere=(null), mfile=(null), shorten=0,
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/taginfo, trace, ALL)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.\*, (null))
+S -> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file1, ${CVSROOT_DIRNAME}/trace/file1,v )
+S -> check_fileproc ( ${CVSROOT_DIRNAME}/trace, file2, ${CVSROOT_DIRNAME}/trace/file2,v )
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (subdir, ${CVSROOT_DIRNAME}/trace/subdir)
+S -> do_cvs_command (tag)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace/subdir)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+S -> rcs_cleanup()
+S -> readers_exist (${CVSROOT_DIRNAME}/trace)
+S -> readers_exist (${CVSROOT_DIRNAME}/trace/subdir)
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+S -> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> rtag_proc ( argc=1, argv=${PFMT}, xwhere=(null),
+S -> serve_directory (\.)
+S -> serve_directory (\.)
+S -> serve_directory (subdir)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(CVS/Entries\.Log)
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+T file1
+T file2
+${SPROG} tag: Tagging \.
+${SPROG} tag: Tagging subdir"
+ dotest_sort trace-9 "${testcvs} -t -t -t log" \
+"
+
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=7, aflag=0,
+ *locktype=1, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ MYVENDOR: 1\.1\.1
+ bp: 1\.1
+ bp: 1\.1\.1\.1
+ branch1: 1\.1\.0\.2
+ branch1: 1\.1\.1\.1\.0\.2
+ version-1: 1\.1\.1\.1
+----------------------------
+----------------------------
+----------------------------
+=============================================================================
+=============================================================================
+Initial revision
+RCS file: ${CVSROOT_DIRNAME}/trace/file1,v
+RCS file: ${CVSROOT_DIRNAME}/trace/file2,v
+Working file: file1
+Working file: file2
+access list:
+access list:
+branch:
+branch: 1\.1\.1
+branches: 1\.1\.1;
+${SPROG} log: Logging \.
+${SPROG} log: Logging subdir
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+description:
+description:
+head: 1\.1
+head: 1\.1
+import
+keyword substitution: kv
+keyword substitution: kv
+locks: strict
+locks: strict
+new-file
+revision 1\.1
+revision 1\.1
+revision 1\.1\.1\.1
+symbolic names:
+symbolic names:
+total revisions: 1; selected revisions: 1
+total revisions: 2; selected revisions: 2" \
+"
+
+
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=7, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ MYVENDOR: 1\.1\.1
+ bp: 1\.1
+ bp: 1\.1\.1\.1
+ branch1: 1\.1\.0\.2
+ branch1: 1\.1\.1\.1\.0\.2
+ version-1: 1\.1\.1\.1
+----------------------------
+----------------------------
+----------------------------
+=============================================================================
+=============================================================================
+Initial revision
+RCS file: ${CVSROOT_DIRNAME}/trace/file1,v
+RCS file: ${CVSROOT_DIRNAME}/trace/file2,v
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> dirswitch (subdir, ${CVSROOT_DIRNAME}/trace/subdir)
+S -> do_cvs_command (log)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> serve_directory (\.)
+S -> serve_directory (subdir)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(CVS/Entries\.Log)
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+Working file: file1
+Working file: file2
+access list:
+access list:
+branch:
+branch: 1\.1\.1
+branches: 1\.1\.1;
+${SPROG} log: Logging \.
+${SPROG} log: Logging subdir
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+date: ${ISO8601DATE}; author: ${username}; state: Exp; lines: ${PLUS}0 -0; commitid: ${commitid};
+date: ${ISO8601DATE}; author: ${username}; state: Exp; commitid: ${commitid};
+description:
+description:
+head: 1\.1
+head: 1\.1
+import
+keyword substitution: kv
+keyword substitution: kv
+locks: strict
+locks: strict
+new-file
+revision 1\.1
+revision 1\.1
+revision 1\.1\.1\.1
+symbolic names:
+symbolic names:
+total revisions: 1; selected revisions: 1
+total revisions: 2; selected revisions: 2"
+
+ dotest_sort trace-10 "${testcvs} -t -t -t annotate file1" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in= )
+ *local=0, which=1, aflag=0,
+ *locktype=1, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+Annotations for file1" \
+"
+
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in= )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+Annotations for file1
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (annotate)
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> remove_locks()
+S -> remove_locks()
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )"
+
+ dotest_sort \
+trace-11 "${testcvs} -t -t -t rtag -r bp -b branch2 trace" \
+" *aflag=0, repository=${CVSROOT_DIRNAME}/trace )
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *local=0, which=6, aflag=0,
+ *local=0, which=6, aflag=0,
+ *local=0, which=6, aflag=0,
+ *locktype=1, update_preload=(null)
+ *locktype=1, update_preload=trace
+ *locktype=2, update_preload=trace
+ *local_specified=0, mname=trace, msg=Tagging )
+ *mwhere=(null), mfile=(null), shorten=0,
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/taginfo, trace, ALL)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, (null))
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.\*, (null))
+ *-> check_fileproc ( ${CVSROOT_DIRNAME}/trace, trace/file1, ${CVSROOT_DIRNAME}/trace/file1,v )
+ *-> check_fileproc ( ${CVSROOT_DIRNAME}/trace, trace/file2, ${CVSROOT_DIRNAME}/trace/file2,v )
+ *-> do_module (trace, Tagging, NULL, branch2)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> rcs_cleanup()
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace)
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> remove_locks()
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+ *-> rtag_proc ( argc=1, argv=${PFMT}, xwhere=(null),
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> tag_check_valid ( name=bp, argc=0, argv=${PFMT}, local=0,
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${SPROG} rtag: Tagging trace
+${SPROG} rtag: Tagging trace/subdir" \
+"
+ *aflag=0, repository=${CVSROOT_DIRNAME}/trace )
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *local=0, which=6, aflag=0,
+ *local=0, which=6, aflag=0,
+ *local=0, which=6, aflag=0,
+ *locktype=1, update_preload=(null)
+ *locktype=1, update_preload=trace
+ *locktype=2, update_preload=trace
+ *local_specified=0, mname=trace, msg=Tagging )
+ *mwhere=(null), mfile=(null), shorten=0,
+ *-> Forking server: ${CVS_SERVER} server
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/taginfo, trace, ALL)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace/subdir)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, (null))
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.\*, (null))
+S -> check_fileproc ( ${CVSROOT_DIRNAME}/trace, trace/file1, ${CVSROOT_DIRNAME}/trace/file1,v )
+S -> check_fileproc ( ${CVSROOT_DIRNAME}/trace, trace/file2, ${CVSROOT_DIRNAME}/trace/file2,v )
+S -> do_cvs_command (rtag)
+S -> do_module (trace, Tagging, NULL, branch2)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace/subdir)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+S -> rcs_cleanup()
+S -> readers_exist (${CVSROOT_DIRNAME}/trace)
+S -> readers_exist (${CVSROOT_DIRNAME}/trace/subdir)
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+S -> rename(${CVSROOT_DIRNAME}/trace/,file2,,${CVSROOT_DIRNAME}/trace/file2,v)
+S -> rtag_proc ( argc=1, argv=${PFMT}, xwhere=(null),
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> tag_check_valid ( name=bp, argc=0, argv=${PFMT}, local=0,
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${SPROG} rtag: Tagging trace
+${SPROG} rtag: Tagging trace/subdir"
+
+ dotest_sort trace-12 "${testcvs} -t -t -t status file1" \
+"
+
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *locktype=1, update_preload=(null)
+ Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/trace/file1,v
+ Sticky Date: (none)
+ Sticky Options: (none)
+ Sticky Tag: (none)
+ Working revision: 1\.1\.1\.1 ${DATE}
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+===================================================================
+File: file1 *Status: Up-to-date" \
+"
+
+
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/trace/file1,v
+ Sticky Date: (none)
+ Sticky Options: (none)
+ Sticky Tag: (none)
+ Working revision: 1\.1\.1\.1
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+===================================================================
+File: file1 *Status: Up-to-date
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (status)
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> remove_locks()
+S -> remove_locks()
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )"
+
+ echo foo >> file1
+ dotest_sort trace-13 "${testcvs} -t -t -t up -C file1" \
+" *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=3, aflag=0,
+ *locktype=1, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, , , (function))
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, , , file1)
+ *-> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, (null), , file1 )
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Register(file1, 1\.1\.1\.1, ${DATE}, , )
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> chmod(file1,[0-7][0-7]*)
+ *-> copy(file1,\.#file1\.1\.1\.1\.1)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> rename(file1,CVS/,,file1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> unlink_file_dir(CVS/,,file1)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+(Locally modified file1 moved to \.#file1\.1\.1\.1\.1)
+U file1" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=3, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Register(file1, 1\.1\.1\.1, ${DATE}, , )
+ *-> copy(file1,\.#file1\.1\.1\.1\.1)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(\.new\.file1,file1)
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+(Locally modified file1 moved to \.#file1\.1\.1\.1\.1)
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, , , (function))
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Register(file1, 1\.1\.1\.1, M, , )
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (update)
+S -> do_recursion ( frame=${PFMT} )
+S -> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> server_register(file1, 1\.1\.1\.1, M, , , , )
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+U file1"
+ echo foo >> file1
+ dotest_sort trace-14 "${testcvs} -t -t -t ci -madd-data file1" \
+" *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/commitinfo, trace, ALL)
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+ *-> Promotable_Lock ()
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, , , , (function))
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1, , -ko, ${tempname})
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, , , (function))
+ *-> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file1,v, (null), (null), , file1 )
+ *-> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, (null), , file1 )
+ *-> Register(file1, 1\.2, ${DATE}, , )
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_tree_promotably (1, argv, 0, 1, 0)
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_lock(${CVSROOT_DIRNAME}/trace)
+ *-> rcs_cleanup()
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace)
+ *-> remove_locks()
+ *-> remove_locks()
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 0)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(${tempname})
+ *-> unlink_file(${tempname})
+ *-> unlink_file(CVS/Base/file1)
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${CVSROOT_DIRNAME}/trace/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Register(file1, 1\.2, ${DATE}, , )
+ *-> Sending file \`file1' to server
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Base/file1)
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${CVSROOT_DIRNAME}/trace/file1,v <-- file1
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/commitinfo, trace, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+S -> Promotable_Lock ()
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, , , , (function))
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1, , -ko, ${tempname})
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, , , (function))
+S -> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file1,v, (null), (null), , file1 )
+S -> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, (null), , file1 )
+S -> Register(file1, 1\.2, ${DATE}, , )
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (commit)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_tree_promotably (1, argv, 0, 1, 0)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_lock(${CVSROOT_DIRNAME}/trace)
+S -> rcs_cleanup()
+S -> readers_exist (${CVSROOT_DIRNAME}/trace)
+S -> remove_locks()
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> server_pathname_check (file1)
+S -> server_pathname_check (file1)
+S -> server_register(file1, 1\.2, ${DATE}, , , , )
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 0)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(${tempname})
+S -> unlink_file(${tempname})
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+new revision: 1\.2; previous revision: 1\.1"
+
+ dotest_fail_sort trace-15 "${testcvs} -t -t -t diff -r1.1 file1" \
+" *aflag=0, repository= )
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=7, aflag=0,
+ *locktype=1, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1, , , ${tempname})
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , , (function))
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , , ${tempname})
+ *-> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file1,v, 1\.1, 1\.2, , file1 )
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> diff_file_nodiff (file1, 3)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> tag_check_valid ( name=1\.1, argc=1, argv=${PFMT}, local=0,
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+0a1
+===================================================================
+> foo
+Index: file1
+RCS file: ${CVSROOT_DIRNAME}/trace/file1,v
+diff -r1\.1 -r1\.2
+retrieving revision 1\.1
+retrieving revision 1\.2" \
+"
+ *aflag=0, repository= )
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=7, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+0a1
+===================================================================
+> foo
+Index: file1
+RCS file: ${CVSROOT_DIRNAME}/trace/file1,v
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1, , , ${tempname})
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , , (function))
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , , ${tempname})
+S -> RCS_cmp_file( ${CVSROOT_DIRNAME}/trace/file1,v, 1\.1, 1\.2, , file1 )
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> diff_file_nodiff (file1, 3)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (diff)
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> remove_locks()
+S -> remove_locks()
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> tag_check_valid ( name=1\.1, argc=1, argv=${PFMT}, local=0,
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+diff -r1\.1 -r1\.2
+retrieving revision 1\.1
+retrieving revision 1\.2"
+
+ dotest_sort trace-16 "${testcvs} -t -t -t rdiff -rbp trace/file1" \
+" *aflag=0, repository=${CVSROOT_DIRNAME}/trace )
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *local=0, which=6, aflag=0,
+ *locktype=1, update_preload=trace
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, bp, , ${tempname})
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , , ${tempname})
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> do_module (trace/file1, Patching, NULL, NULL)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> patch_proc ( (null), (null), (null), 0, 0, trace/file1, Patching )
+ *-> remove_locks()
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> tag_check_valid ( name=bp, argc=1, argv=${PFMT}, local=0,
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+\*\*\* 0 \*\*\*\*
+\*\*\* trace/file1:1\.1\.1\.1 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+${PLUS} foo
+--- 1 ----
+--- trace/file1 ${DATE}
+Index: trace/file1
+diff -c trace/file1:1\.1\.1\.1 trace/file1:1\.2" \
+"
+ *aflag=0, repository=${CVSROOT_DIRNAME}/trace )
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=${CVSROOT_DIRNAME}/trace )
+ *local=0, which=6, aflag=0,
+ *locktype=1, update_preload=trace
+ *-> Forking server: ${CVS_SERVER} server
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+\*\*\* 0 \*\*\*\*
+\*\*\* trace/file1:1\.1\.1\.1 ${DATE}
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+${PLUS} foo
+--- 1 ----
+--- trace/file1 ${DATE}
+Index: trace/file1
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.1\.1\.1, bp, , ${tempname})
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , , ${tempname})
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> do_cvs_command (rdiff)
+S -> do_module (trace/file1, Patching, NULL, NULL)
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> patch_proc ( (null), (null), (null), 0, 0, trace/file1, Patching )
+S -> remove_locks()
+S -> remove_locks()
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> tag_check_valid ( name=bp, argc=1, argv=${PFMT}, local=0,
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+diff -c trace/file1:1\.1\.1\.1 trace/file1:1\.2"
+
+ dotest_sort trace-17 "${testcvs} -t -t -t rm -f file1" \
+" *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *locktype=1, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+ *-> Register(file1, -1\.2, ${DATE}, , )
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> do_recursion ( frame=${PFMT} )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_simple_remove()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${SPROG} remove: scheduling \`file1' for removal
+${SPROG} remove: use \`${SPROG} commit' to remove this file permanently" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=1, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Register(file1, -1\.2, dummy timestamp, , )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Reader_Lock(${CVSROOT_DIRNAME}/trace)
+S -> Register(file1, -1\.2, , , )
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (remove)
+S -> do_recursion ( frame=${PFMT} )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_simple_remove()
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> server_register(file1, -1\.2, , , , , )
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(CVS/Entries\.Log)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${SPROG} remove: scheduling \`file1' for removal
+${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
+
+ dotest_sort trace-18 "${testcvs} -t -t -t ci -mremove file1" \
+" *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Lock_Cleanup()
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/commitinfo, trace, ALL)
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+ *-> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+ *-> Promotable_Lock ()
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, , , , file1)
+ *-> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , -ko, ${tempname})
+ *-> Scratch_Entry(file1)
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, #cvs.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_tree_promotably (1, argv, 0, 1, 0)
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_lock(${CVSROOT_DIRNAME}/trace)
+ *-> rcs_cleanup()
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace)
+ *-> remove_locks()
+ *-> remove_locks()
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+ *-> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 0)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(${tempname})
+ *-> unlink_file(${tempname})
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> unlink_file(file1)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${CVSROOT_DIRNAME}/trace/file1,v <-- file1
+new revision: delete; previous revision: 1\.2" \
+"
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *callerdat=${PFMT}, argc=1, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *dosrcs=1, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Scratch_Entry(file1)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> rename(CVS/Entries\.Backup,CVS/Entries)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file(CVS/Entries\.Log)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+${CVSROOT_DIRNAME}/trace/file1,v <-- file1
+S -> CVS_SERVER_SLEEP not set\.
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Leaving do_recursion ( frame=${PFMT} )
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/commitinfo, trace, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/loginfo, trace, ALL)
+S -> Parse_Info (${CVSROOT_DIRNAME}/CVSROOT/verifymsg, trace, not ALL)
+S -> Promotable_Lock ()
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, , , , file1)
+S -> RCS_checkout (${CVSROOT_DIRNAME}/trace/file1,v, 1\.2, , -ko, ${tempname})
+S -> Scratch_Entry(file1)
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs.pfl\.${hostname}\.[0-9][0-9]*)
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs.pfl\.${hostname}\.[0-9][0-9]*)
+S -> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, #cvs.rfl\.${hostname}\.[0-9][0-9]*)
+S -> dirswitch (\., ${CVSROOT_DIRNAME}/trace)
+S -> do_cvs_command (commit)
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> do_recursion ( frame=${PFMT} )
+S -> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+S -> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_name (${CVSROOT_DIRNAME}/trace, )
+S -> lock_simple_remove()
+S -> lock_simple_remove()
+S -> lock_tree_promotably (1, argv, 0, 1, 0)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_exists (${CVSROOT_DIRNAME}/trace)
+S -> promotable_lock(${CVSROOT_DIRNAME}/trace)
+S -> rcs_cleanup()
+S -> readers_exist (${CVSROOT_DIRNAME}/trace)
+S -> remove_locks()
+S -> remove_locks()
+S -> remove_locks()
+S -> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+S -> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+S -> rename(${CVSROOT_DIRNAME}/trace/,file1,,${CVSROOT_DIRNAME}/trace/file1,v)
+S -> rename(CVS/Entries\.Backup,CVS/Entries)
+S -> serve_directory (\.)
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_pathname_check (file1)
+S -> server_pathname_check (file1)
+S -> server_pathname_check (file1)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 0)
+S -> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> unlink_file(${tempname})
+S -> unlink_file(${tempname})
+S -> unlink_file(CVS/Entries\.Log)
+S -> unlink_file(file1)
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+done
+new revision: delete; previous revision: 1\.2"
+
+ # SGI IRIX seems to have problems with the stdout and stderr
+ # mix for this test, so separate them.
+ dotest_sort trace-19 "${testcvs} -t -t -t history file1 2>stderr19" \
+"O ${ISODATE} ${username} trace =trace= ${TESTDIR}/trace/\*" \
+"O ${ISODATE} ${username} trace =trace= <remote>/\*"
+ dotest_sort trace-19stderr "sort < stderr19" \
+" *-> Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> remove_locks()
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )" \
+"
+ *-> Forking server: ${CVS_SERVER} server
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+S -> CVS_SERVER_SLEEP not set\.
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> do_cvs_command (history)
+S -> remove_locks()
+S -> remove_locks()
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()"
+ rm stderr19
+
+ cd ..
+ dotest_sort \
+trace-20 "echo yes | ${testcvs} -t -t -t release -d trace" \
+" *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *locktype=2, update_preload=(null)
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Lock_Cleanup()
+ *-> Lock_Cleanup()
+ *-> Promotable_Lock ()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> Simple_Lock_Cleanup()
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.\*, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.\*, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> _lock_exists (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.\*, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace)
+ *-> lock_dir_for_write (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.lock)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.pfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.rfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, #cvs\.wfl\.${hostname}\.[0-9][0-9]*)
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_name (${CVSROOT_DIRNAME}/trace/subdir, )
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_simple_remove()
+ *-> lock_tree_promotably (0, argv, 0, 1, 0)
+ *-> main loop with CVSROOT=${CVSROOT_DIRNAME}
+ *-> parse_cvsroot ( ${CVSROOT_DIRNAME} )
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> promotable_exists (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> promotable_lock(${CVSROOT_DIRNAME}/trace)
+ *-> promotable_lock(${CVSROOT_DIRNAME}/trace/subdir)
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace)
+ *-> readers_exist (${CVSROOT_DIRNAME}/trace/subdir)
+ *-> remove_locks()
+ *-> remove_locks()
+ *-> run_popen(${testcvs} -n -q -d ${CVSROOT_DIRNAME} update,r)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 0)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace, 1)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 0)
+ *-> set_lock (${CVSROOT_DIRNAME}/trace/subdir, 1)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file_dir(trace)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+Are you sure you want to release (and delete) directory \`trace': *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+You have \[0\] altered files in this repository\." \
+"
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *callerdat=${PFMT}, argc=0, argv=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *direntproc=${PFMT}, dirleavproc=${PFMT},
+ *dosrcs=0, repository_in=(null) )
+ *dosrcs=0, repository_in=(null) )
+ *local=0, which=1, aflag=0,
+ *local=0, which=1, aflag=0,
+ *locktype=0, update_preload=(null)
+ *locktype=0, update_preload=(null)
+ *-> Forking server: ${CVS_SERVER} server
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> Leaving do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> do_recursion ( frame=${PFMT} )
+ *-> main loop with CVSROOT=${CVSROOT}
+ *-> parse_cvsroot ( ${CVSROOT} )
+ *-> run_popen(${testcvs} -n -q -d ${CVSROOT} update,r)
+ *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+ *-> unlink_file_dir(trace)
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+ *-> walklist ( list=${PFMT}, proc=${PFMT}, closure=${PFMT} )
+Are you sure you want to release (and delete) directory \`trace': *-> start_recursion ( fileproc=${PFMT}, filesdoneproc=${PFMT},
+S -> CVS_SERVER_SLEEP not set\.
+S -> Lock_Cleanup()
+S -> Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> Simple_Lock_Cleanup()
+S -> do_cvs_command (release)
+S -> fopen(${CVSROOT_DIRNAME}/CVSROOT/history,a)
+S -> remove_locks()
+S -> remove_locks()
+S -> server_cleanup()
+S -> server_cleanup()
+S -> server_notify()
+S -> server_notify()
+S -> server_notify()
+You have \[0\] altered files in this repository\."
+
+ dokeep
+ cd ..
+ rm -fr trace
+ modify_repo rm -fr $CVSROOT_DIRNAME/trace
+ ;;
+
+
+
+ *)
+ echo $what is not the name of a test -- ignored
+ ;;
+ esac
+
+ # Sanity check sanity.sh. :)
+ #
+ # Test our exit directory so that tests that exit in an incorrect directory
+ # are noticed during single test runs.
+ #
+ # FIXME?
+ # Sparc Solaris 9 is dereferencing paths here as if /bin/pwd were
+ # called when /tmp is a symlink. This might be a new problem with this
+ # test, but since this was recently tested I think it more likely to be
+ # A Solaris issue.
+ if test "x$TESTDIR" != "x`pwd`"; then
+ fail "cleanup: PWD != TESTDIR (\``pwd`' != \`$TESTDIR')"
+ fi
+
+ # Test that the last test didn't overwrite any write proxy configuration
+ # which may be in place.
+ if $proxy; then
+ problem=false
+ for file in \
+ $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \
+ $CVSROOT_DIRNAME/CVSROOT/config \
+ $SECONDARY_CVSROOT_DIRNAME/CVSROOT/loginfo \
+ $CVSROOT_DIRNAME/CVSROOT/loginfo \
+ $SECONDARY_CVSROOT_DIRNAME/CVSROOT/postadmin \
+ $CVSROOT_DIRNAME/CVSROOT/postadmin \
+ $SECONDARY_CVSROOT_DIRNAME/CVSROOT/posttag \
+ $CVSROOT_DIRNAME/CVSROOT/posttag \
+ $SECONDARY_CVSROOT_DIRNAME/CVSROOT/postwatch \
+ $CVSROOT_DIRNAME/CVSROOT/postwatch; do
+ if cmp $file $TESTDIR/`basename $file`-clean >/dev/null 2>&1; then
+ :;
+ else
+ echo "\`$file' and \`$TESTDIR/`basename $file`-clean' differ." \
+ >>$LOGFILE
+ problem=:
+ fi
+ done
+ if $problem; then
+ fail "cleanup: write proxy configuration not preserved"
+ fi
+ fi
+
+ if $remote && test "$servercvs_orig" != "$servercvs" >/dev/null 2>&1; then
+ fail "test slagged \$servercvs"
+ fi
+
+ # Reset val-tags to a pristine state.
+ if test -s $CVSROOT_DIRNAME/CVSROOT/val-tags; then
+ modify_repo ":" > $CVSROOT_DIRNAME/CVSROOT/val-tags
+ fi
+ verify_tmp_empty "post $what"
+
+done # The big loop
+
+# Set up summary data for output.
+skippedoutput=
+warningsoutput=
+extendedinfo=
+if test $skipped -ne 0; then
+ skippedoutput="$skipped test group"
+ if test $skipped -ne 1; then
+ skippedoutput="${skippedoutput}s"
+ fi
+ skippedoutput="$skippedoutput skipped"
+fi
+if test $warnings -ne 0; then
+ warningsoutput="$warnings test"
+ if test $warnings -ne 1; then
+ warningsoutput="${warningsoutput}s"
+ fi
+ warningsoutput="$warningsoutput passed with warnings"
+fi
+if test -n "$skippedoutput" || test -n "$warningsoutput"; then
+ extendedinfo=" ("
+ if test -n "$skippedoutput"; then
+ extendedinfo="$extendedinfo$skippedoutput"
+ fi
+ if test -n "$skippedoutput" && test -n "$warningsoutput"; then
+ extendedinfo="$extendedinfo and "
+ fi
+ if test -n "$warningsoutput"; then
+ extendedinfo="$extendedinfo$warningsoutput"
+ fi
+ extendedinfo="$extendedinfo)"
+fi
+
+echo "OK, all $passed tests passed$extendedinfo."
+
+# TODO:
+# * Test `cvs update -d foo' (where foo does not exist).
+# * Test `cvs update foo bar' (where foo and bar are both from the
+# same directory in the repository). Suppose one is a branch--make
+# sure that both directories get updated with the respective correct
+# thing.
+# * `cvs update ../foo'. Also ../../foo ./../foo foo/../../bar /foo/bar
+# foo/.././../bar foo/../bar etc.
+# * Test all flags in modules file.
+# Test that ciprog gets run both on checkin in that directory, or a
+# higher-level checkin which recurses into it.
+# * Test operations on a directory that contains other directories but has
+# no files of its own.
+# * -t global option
+# * cvs rm followed by cvs add or vice versa (with no checkin in between).
+# * cvs rm twice (should be a nice error message).
+# * -P option to checkout--(a) refrains from checking out new empty dirs,
+# (b) prunes empty dirs already there.
+# * Test that cvs -d `hostname`:${TESTDIR}/non/existent co foo
+# gives an appropriate error (e.g.
+# Cannot access ${TESTDIR}/non-existent/CVSROOT
+# No such file or directory).
+# (like basica-9, but for remote).
+# * Test ability to send notifications in response to watches. (currently
+# hard to test because CVS doesn't send notifications if username is the
+# same).
+# * Test the contents of adm files other than Root and Repository.
+# Entries seems the next most important thing.
+# * Test the following compatibility issues:
+# - The filler fields in "D" entries in CVS/Entries get preserved
+# (per cvs.texinfo).
+# - Unrecognized entry types in CVS/Entries get ignored (looks like
+# this needs to be documented in cvs.texinfo, but is not)
+# - Test that unrecognized files in CVS directories (e.g. CVS/Foobar)
+# are ignored (per cvs.texinfo).
+# - Test 'cvs history' with symlinks in the path to the working directory.
+# - Remove most of the CVS_SERVER stuff after a reasonable amount of time.
+# The "fork" & "client" series of tests should be left. 4/2/00, CVS
+# 1.11.0.1 was altered so that it would default to program_name (set from
+# argv[0]) rather than "cvs", but I'd like this script to work on legacy
+# versions of CVS for awhile.
+# - Testsuite doesn't work with usernames over eight characters in length.
+# Fix it.
+# End of TODO list.
+
+# Exit if keep set
+dokeep
+
+# Remove the test directory, but first change out of it.
+if $TIMING; then
+ echo "exiting without removing test dir in order to preserve timing information."
+else
+ cd `dirname $TESTDIR`
+ rm -rf $TESTDIR
+fi
+
+# end of sanity.sh
diff --git a/src/scramble.c b/src/scramble.c
new file mode 100644
index 0000000..126d140
--- /dev/null
+++ b/src/scramble.c
@@ -0,0 +1,243 @@
+/*
+ * Trivially encode strings to protect them from innocent eyes (i.e.,
+ * inadvertent password compromises, like a network administrator
+ * who's watching packets for legitimate reasons and accidentally sees
+ * the password protocol go by).
+ *
+ * This is NOT secure encryption.
+ *
+ * It would be tempting to encode the password according to username
+ * and repository, so that the same password would encode to a
+ * different string when used with different usernames and/or
+ * repositories. However, then users would not be able to cut and
+ * paste passwords around. They're not supposed to anyway, but we all
+ * know they will, and there's no reason to make it harder for them if
+ * we're not trying to provide real security anyway.
+ */
+
+/* Set this to test as a standalone program. */
+/* #define DIAGNOSTIC */
+
+#ifndef DIAGNOSTIC
+#include "cvs.h"
+#else /* ! DIAGNOSTIC */
+/* cvs.h won't define this for us */
+#define AUTH_CLIENT_SUPPORT
+#define xmalloc malloc
+/* Use "gcc -fwritable-strings". */
+#include <stdio.h>
+#include <stdio.h>
+#include <string.h>
+#endif /* ! DIAGNOSTIC */
+
+#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT)
+
+/* Map characters to each other randomly and symmetrically, A <--> B.
+ *
+ * We divide the ASCII character set into 3 domains: control chars (0
+ * thru 31), printing chars (32 through 126), and "meta"-chars (127
+ * through 255). The control chars map _to_ themselves, the printing
+ * chars map _among_ themselves, and the meta chars map _among_
+ * themselves. Why is this thus?
+ *
+ * No character in any of these domains maps to a character in another
+ * domain, because I'm not sure what characters are valid in
+ * passwords, or what tools people are likely to use to cut and paste
+ * them. It seems prudent not to introduce control or meta chars,
+ * unless the user introduced them first. And having the control
+ * chars all map to themselves insures that newline and
+ * carriage-return are safely handled.
+ */
+
+static unsigned char
+shifts[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
+ 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
+ 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
+ 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
+ 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
+ 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
+ 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
+ 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
+ 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
+ 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
+ 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
+ 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
+ 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
+ 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 };
+
+
+/* SCRAMBLE and DESCRAMBLE work like this:
+ *
+ * scramble(STR) returns SCRM, a scrambled copy of STR. SCRM[0] is a
+ * single letter indicating the scrambling method. As of this
+ * writing, the only valid method is 'A', but check the code for more
+ * up-to-date information. The copy will have been allocated with
+ * xmalloc().
+ *
+ * descramble(SCRM) returns STR, again in its own xmalloc'd space.
+ * descramble() uses SCRM[0] to determine which method of unscrambling
+ * to use. If it does not recognize the method, it dies with error.
+ */
+
+/* Return a xmalloc'd, scrambled version of STR. */
+char *
+scramble (char *str)
+{
+ int i;
+ char *s;
+
+ /* +2 to hold the 'A' prefix that indicates which version of
+ scrambling this is (the first, obviously, since we only do one
+ kind of scrambling so far), and then the '\0' of course. */
+ s = (char *) xmalloc (strlen (str) + 2);
+
+ /* Scramble (TM) version prefix. */
+ s[0] = 'A';
+ strcpy (s + 1, str);
+
+ for (i = 1; s[i]; i++)
+ s[i] = shifts[(unsigned char)(s[i])];
+
+ return s;
+}
+
+/* Decode the string in place. */
+char *
+descramble (char *str)
+{
+ char *s;
+ int i;
+
+ /* For now we can only handle one kind of scrambling. In the future
+ there may be other kinds, and this `if' will become a `switch'. */
+ if (str[0] != 'A')
+#ifndef DIAGNOSTIC
+ error (1, 0, "descramble: unknown scrambling method");
+#else /* DIAGNOSTIC */
+ {
+ fprintf (stderr, "descramble: unknown scrambling method\n", str);
+ fflush (stderr);
+ exit (EXIT_FAILURE);
+ }
+#endif /* DIAGNOSTIC */
+
+ /* Method `A' is symmetrical, so scramble again to decrypt. */
+ s = scramble (str + 1);
+
+ /* Shift the whole string one char to the left, pushing the unwanted
+ 'A' off the left end. Safe, because s is null-terminated. */
+ for (i = 0; s[i]; i++)
+ s[i] = s[i + 1];
+
+ return s;
+}
+
+#endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */
+
+#ifdef DIAGNOSTIC
+int
+main( int argc, char **argv )
+{
+ int i;
+ char *e, *m, biggie[256];
+
+ char *cleartexts[5];
+ cleartexts[0] = "first";
+ cleartexts[1] = "the second";
+ cleartexts[2] = "this is the third";
+ cleartexts[3] = "$#% !!\\3";
+ cleartexts[4] = biggie;
+
+ /* Set up the most important test string: */
+ /* Can't have a real ASCII zero in the string, because we want to
+ use printf, so we substitute the character zero. */
+ biggie[0] = '0';
+ /* The rest of the string gets straight ascending ASCII. */
+ for (i = 1; i < 256; i++)
+ biggie[i] = i;
+
+ /* Test all the strings. */
+ for (i = 0; i < 5; i++)
+ {
+ printf ("clear%d: %s\n", i, cleartexts[i]);
+ e = scramble (cleartexts[i]);
+ printf ("scram%d: %s\n", i, e);
+ m = descramble (e);
+ free (e);
+ printf ("clear%d: %s\n\n", i, m);
+ free (m);
+ }
+
+ fflush (stdout);
+ return 0;
+}
+#endif /* DIAGNOSTIC */
+
+/*
+ * ;;; The Emacs Lisp that did the dirty work ;;;
+ * (progn
+ *
+ * ;; Helper func.
+ * (defun random-elt (lst)
+ * (let* ((len (length lst))
+ * (rnd (random len)))
+ * (nth rnd lst)))
+ *
+ * ;; A list of all characters under 127, each appearing once.
+ * (setq non-meta-chars
+ * (let ((i 0)
+ * (l nil))
+ * (while (< i 127)
+ * (setq l (cons i l)
+ * i (1+ i)))
+ * l))
+ *
+ * ;; A list of all characters 127 and above, each appearing once.
+ * (setq meta-chars
+ * (let ((i 127)
+ * (l nil))
+ * (while (< i 256)
+ * (setq l (cons i l)
+ * i (1+ i)))
+ * l))
+ *
+ * ;; A vector that will hold the chars in a random order.
+ * (setq scrambled-chars (make-vector 256 0))
+ *
+ * ;; These characters should map to themselves.
+ * (let ((i 0))
+ * (while (< i 32)
+ * (aset scrambled-chars i i)
+ * (setq non-meta-chars (delete i non-meta-chars)
+ * i (1+ i))))
+ *
+ * ;; Assign random (but unique) values, within the non-meta chars.
+ * (let ((i 32))
+ * (while (< i 127)
+ * (let ((ch (random-elt non-meta-chars)))
+ * (if (= 0 (aref scrambled-chars i))
+ * (progn
+ * (aset scrambled-chars i ch)
+ * (aset scrambled-chars ch i)
+ * (setq non-meta-chars (delete ch non-meta-chars)
+ * non-meta-chars (delete i non-meta-chars))))
+ * (setq i (1+ i)))))
+ *
+ * ;; Assign random (but unique) values, within the non-meta chars.
+ * (let ((i 127))
+ * (while (< i 256)
+ * (let ((ch (random-elt meta-chars)))
+ * (if (= 0 (aref scrambled-chars i))
+ * (progn
+ * (aset scrambled-chars i ch)
+ * (aset scrambled-chars ch i)
+ * (setq meta-chars (delete ch meta-chars)
+ * meta-chars (delete i meta-chars))))
+ * (setq i (1+ i)))))
+ *
+ * ;; Now use the `scrambled-chars' vector to get your C array.
+ * )
+ */
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 0000000..41ece74
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,7987 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+
+/* CVS */
+#include "edit.h"
+#include "fileattr.h"
+#include "watch.h"
+
+/* GNULIB */
+#include "buffer.h"
+#include "getline.h"
+#include "getnline.h"
+
+int server_active = 0;
+
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+
+# include "log-buffer.h"
+# include "ms-buffer.h"
+#endif /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */
+
+#if defined (HAVE_GSSAPI) && defined (SERVER_SUPPORT)
+# include "canon-host.h"
+# include "gssapi-client.h"
+
+/* This stuff isn't included solely with SERVER_SUPPORT since some of these
+ * functions (encryption & the like) get compiled with or without server
+ * support.
+ *
+ * FIXME - They should be in a different file.
+ */
+/* We use Kerberos 5 routines to map the GSSAPI credential to a user
+ name. */
+# include <krb5.h>
+
+static void gserver_authenticate_connection (void);
+
+/* Whether we are already wrapping GSSAPI communication. */
+static int cvs_gssapi_wrapping;
+
+#endif /* defined (HAVE_GSSAPI) && defined (SERVER_SUPPORT) */
+
+#ifdef SERVER_SUPPORT
+
+extern char *server_hostname;
+
+# if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI)
+# include <sys/socket.h>
+# endif
+
+# ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+# ifndef LOG_DAEMON /* for ancient syslogs */
+# define LOG_DAEMON 0
+# endif
+# endif /* HAVE_SYSLOG_H */
+
+# ifdef HAVE_KERBEROS
+# include <netinet/in.h>
+# include <krb.h>
+# ifndef HAVE_KRB_GET_ERR_TEXT
+# define krb_get_err_text(status) krb_err_txt[status]
+# endif
+
+/* Information we need if we are going to use Kerberos encryption. */
+static C_Block kblock;
+static Key_schedule sched;
+
+# endif /* HAVE_KERBEROS */
+
+/* for select */
+# include "xselect.h"
+
+# ifndef O_NONBLOCK
+# define O_NONBLOCK O_NDELAY
+# endif
+
+/* For initgroups(). */
+# if HAVE_INITGROUPS
+# include <grp.h>
+# endif /* HAVE_INITGROUPS */
+
+# ifdef AUTH_SERVER_SUPPORT
+
+# ifdef HAVE_GETSPNAM
+# include <shadow.h>
+# endif
+
+/* The cvs username sent by the client, which might or might not be
+ the same as the system username the server eventually switches to
+ run as. CVS_Username gets set iff password authentication is
+ successful. */
+char *CVS_Username = NULL;
+
+/* Used to check that same repos is transmitted in pserver auth and in
+ later CVS protocol. Exported because root.c also uses. */
+static char *Pserver_Repos = NULL;
+
+# endif /* AUTH_SERVER_SUPPORT */
+
+# ifdef HAVE_PAM
+# if defined(HAVE_SECURITY_PAM_APPL_H)
+# include <security/pam_appl.h>
+# elif defined(HAVE_PAM_PAM_APPL_H)
+# include <pam/pam_appl.h>
+# endif
+
+static pam_handle_t *pamh = NULL;
+
+static char *pam_username;
+static char *pam_password;
+# endif /* HAVE_PAM */
+
+
+
+/* While processing requests, this buffer accumulates data to be sent to
+ the client, and then once we are in do_cvs_command, we use it
+ for all the data to be sent. */
+static struct buffer *buf_to_net;
+
+/* This buffer is used to read input from the client. */
+static struct buffer *buf_from_net;
+
+
+
+# ifdef PROXY_SUPPORT
+/* These are the secondary log buffers so that we can disable them after
+ * creation, when it is determined that they are unneeded, regardless of what
+ * other filters have been prepended to the buffer chain.
+ */
+static struct buffer *proxy_log;
+static struct buffer *proxy_log_out;
+
+/* Set while we are reprocessing a log so that we can avoid sending responses
+ * to some requests twice.
+ */
+static bool reprocessing;
+# endif /* PROXY_SUPPORT */
+
+
+
+/* Arguments storage for `Argument' & `Argumentx' requests. */
+static int argument_count;
+static char **argument_vector;
+static int argument_vector_size;
+
+/*
+ * This is where we stash stuff we are going to use. Format string
+ * which expects a single directory within it, starting with a slash.
+ */
+static char *server_temp_dir;
+
+/* This is the original value of server_temp_dir, before any possible
+ changes inserted by serve_max_dotdot. */
+static char *orig_server_temp_dir;
+
+/* Nonzero if we should keep the temp directory around after we exit. */
+static int dont_delete_temp;
+
+static void server_write_entries (void);
+
+cvsroot_t *referrer;
+
+
+
+/* Populate all of the directories between BASE_DIR and its relative
+ subdirectory DIR with CVSADM directories. Return 0 for success or
+ errno value. */
+static int
+create_adm_p (char *base_dir, char *dir)
+{
+ char *dir_where_cvsadm_lives, *dir_to_register, *p, *tmp;
+ int retval, done;
+ FILE *f;
+
+ if (strcmp (dir, ".") == 0)
+ return 0; /* nothing to do */
+
+ /* Allocate some space for our directory-munging string. */
+ p = xmalloc (strlen (dir) + 1);
+ if (p == NULL)
+ return ENOMEM;
+
+ dir_where_cvsadm_lives = xmalloc (strlen (base_dir) + strlen (dir) + 100);
+ if (dir_where_cvsadm_lives == NULL)
+ {
+ free (p);
+ return ENOMEM;
+ }
+
+ /* Allocate some space for the temporary string in which we will
+ construct filenames. */
+ tmp = xmalloc (strlen (base_dir) + strlen (dir) + 100);
+ if (tmp == NULL)
+ {
+ free (p);
+ free (dir_where_cvsadm_lives);
+ return ENOMEM;
+ }
+
+
+ /* We make several passes through this loop. On the first pass,
+ we simply create the CVSADM directory in the deepest directory.
+ For each subsequent pass, we try to remove the last path
+ element from DIR, create the CVSADM directory in the remaining
+ pathname, and register the subdirectory in the newly created
+ CVSADM directory. */
+
+ retval = done = 0;
+
+ strcpy (p, dir);
+ strcpy (dir_where_cvsadm_lives, base_dir);
+ strcat (dir_where_cvsadm_lives, "/");
+ strcat (dir_where_cvsadm_lives, p);
+ dir_to_register = NULL;
+
+ while (1)
+ {
+ /* Create CVSADM. */
+ (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM);
+ if ((CVS_MKDIR (tmp, 0777) < 0) && (errno != EEXIST))
+ {
+ retval = errno;
+ goto finish;
+ }
+
+ /* Create CVSADM_REP. */
+ (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_REP);
+ if (! isfile (tmp))
+ {
+ /* Use Emptydir as the placeholder until the client sends
+ us the real value. This code is similar to checkout.c
+ (emptydir_name), but the code below returns errors
+ differently. */
+
+ char *empty;
+ empty = xmalloc (strlen (current_parsed_root->directory)
+ + sizeof (CVSROOTADM)
+ + sizeof (CVSNULLREPOS)
+ + 3);
+ if (! empty)
+ {
+ retval = ENOMEM;
+ goto finish;
+ }
+
+ /* Create the directory name. */
+ (void) sprintf (empty, "%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSNULLREPOS);
+
+ /* Create the directory if it doesn't exist. */
+ if (! isfile (empty))
+ {
+ mode_t omask;
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (empty, 0777) < 0)
+ {
+ retval = errno;
+ free (empty);
+ goto finish;
+ }
+ (void) umask (omask);
+ }
+
+ f = CVS_FOPEN (tmp, "w");
+ if (f == NULL)
+ {
+ retval = errno;
+ free (empty);
+ goto finish;
+ }
+ /* Write the directory name to CVSADM_REP. */
+ if (fprintf (f, "%s\n", empty) < 0)
+ {
+ retval = errno;
+ fclose (f);
+ free (empty);
+ goto finish;
+ }
+ if (fclose (f) == EOF)
+ {
+ retval = errno;
+ free (empty);
+ goto finish;
+ }
+
+ /* Clean up after ourselves. */
+ free (empty);
+ }
+
+ /* Create CVSADM_ENT. We open in append mode because we
+ don't want to clobber an existing Entries file. */
+ (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_ENT);
+ f = CVS_FOPEN (tmp, "a");
+ if (f == NULL)
+ {
+ retval = errno;
+ goto finish;
+ }
+ if (fclose (f) == EOF)
+ {
+ retval = errno;
+ goto finish;
+ }
+
+ if (dir_to_register != NULL)
+ {
+ /* FIXME: Yes, this results in duplicate entries in the
+ Entries.Log file, but it doesn't currently matter. We
+ might need to change this later on to make sure that we
+ only write one entry. */
+
+ Subdir_Register (NULL, dir_where_cvsadm_lives, dir_to_register);
+ }
+
+ if (done)
+ break;
+
+ dir_to_register = strrchr (p, '/');
+ if (dir_to_register == NULL)
+ {
+ dir_to_register = p;
+ strcpy (dir_where_cvsadm_lives, base_dir);
+ done = 1;
+ }
+ else
+ {
+ *dir_to_register = '\0';
+ dir_to_register++;
+ strcpy (dir_where_cvsadm_lives, base_dir);
+ strcat (dir_where_cvsadm_lives, "/");
+ strcat (dir_where_cvsadm_lives, p);
+ }
+ }
+
+ finish:
+ free (tmp);
+ free (dir_where_cvsadm_lives);
+ free (p);
+ return retval;
+}
+
+
+
+/*
+ * Make directory DIR, including all intermediate directories if necessary.
+ * Returns 0 for success or errno code.
+ */
+static int
+mkdir_p (char *dir)
+{
+ char *p;
+ char *q = xmalloc (strlen (dir) + 1);
+ int retval;
+
+ if (q == NULL)
+ return ENOMEM;
+
+ retval = 0;
+
+ /*
+ * Skip over leading slash if present. We won't bother to try to
+ * make '/'.
+ */
+ p = dir + 1;
+ while (1)
+ {
+ while (*p != '/' && *p != '\0')
+ ++p;
+ if (*p == '/')
+ {
+ strncpy (q, dir, p - dir);
+ q[p - dir] = '\0';
+ if (q[p - dir - 1] != '/' && CVS_MKDIR (q, 0777) < 0)
+ {
+ int saved_errno = errno;
+
+ if (saved_errno != EEXIST
+ && ((saved_errno != EACCES && saved_errno != EROFS)
+ || !isdir (q)))
+ {
+ retval = saved_errno;
+ goto done;
+ }
+ }
+ ++p;
+ }
+ else
+ {
+ if (CVS_MKDIR (dir, 0777) < 0)
+ retval = errno;
+ goto done;
+ }
+ }
+ done:
+ free (q);
+ return retval;
+}
+
+
+
+/*
+ * Print the error response for error code STATUS. The caller is
+ * reponsible for making sure we get back to the command loop without
+ * any further output occuring.
+ * Must be called only in contexts where it is OK to send output.
+ */
+static void
+print_error (int status)
+{
+ char *msg;
+ char tmpstr[80];
+
+ buf_output0 (buf_to_net, "error ");
+ msg = strerror (status);
+ if (msg == NULL)
+ {
+ sprintf (tmpstr, "unknown error %d", status);
+ msg = tmpstr;
+ }
+ buf_output0 (buf_to_net, msg);
+ buf_append_char (buf_to_net, '\n');
+
+ buf_flush (buf_to_net, 0);
+}
+
+
+
+static int pending_error;
+/*
+ * Malloc'd text for pending error. Each line must start with "E ". The
+ * last line should not end with a newline.
+ */
+static char *pending_error_text;
+static char *pending_warning_text;
+
+/* If an error is pending, print it and return 1. If not, return 0.
+ Also prints pending warnings, but this does not affect the return value.
+ Must be called only in contexts where it is OK to send output. */
+static int
+print_pending_error (void)
+{
+ /* Check this case first since it usually means we are out of memory and
+ * the buffer output routines might try and allocate memory.
+ */
+ if (!pending_error_text && pending_error)
+ {
+ print_error (pending_error);
+ pending_error = 0;
+ return 1;
+ }
+
+ if (pending_warning_text)
+ {
+ buf_output0 (buf_to_net, pending_warning_text);
+ buf_append_char (buf_to_net, '\n');
+ buf_flush (buf_to_net, 0);
+
+ free (pending_warning_text);
+ pending_warning_text = NULL;
+ }
+
+ if (pending_error_text)
+ {
+ buf_output0 (buf_to_net, pending_error_text);
+ buf_append_char (buf_to_net, '\n');
+ if (pending_error)
+ print_error (pending_error);
+ else
+ buf_output0 (buf_to_net, "error \n");
+
+ buf_flush (buf_to_net, 0);
+
+ pending_error = 0;
+ free (pending_error_text);
+ pending_error_text = NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+/* Is an error pending? */
+# define error_pending() (pending_error || pending_error_text)
+# define warning_pending() (pending_warning_text)
+
+/* Allocate SIZE bytes for pending_error_text and return nonzero
+ if we could do it. */
+static inline int
+alloc_pending_internal (char **dest, size_t size)
+{
+ *dest = malloc (size);
+ if (!*dest)
+ {
+ pending_error = ENOMEM;
+ return 0;
+ }
+ return 1;
+}
+
+
+
+/* Allocate SIZE bytes for pending_error_text and return nonzero
+ if we could do it. */
+static int
+alloc_pending (size_t size)
+{
+ if (error_pending ())
+ /* Probably alloc_pending callers will have already checked for
+ this case. But we might as well handle it if they don't, I
+ guess. */
+ return 0;
+ return alloc_pending_internal (&pending_error_text, size);
+}
+
+
+
+/* Allocate SIZE bytes for pending_error_text and return nonzero
+ if we could do it. */
+static int
+alloc_pending_warning (size_t size)
+{
+ if (warning_pending ())
+ /* Warnings can be lost here. */
+ return 0;
+ return alloc_pending_internal (&pending_warning_text, size);
+}
+
+
+
+static int
+supported_response (char *name)
+{
+ struct response *rs;
+
+ for (rs = responses; rs->name != NULL; ++rs)
+ if (strcmp (rs->name, name) == 0)
+ return rs->status == rs_supported;
+ error (1, 0, "internal error: testing support for unknown response?");
+ /* NOTREACHED */
+ return 0;
+}
+
+
+
+/*
+ * Return true if we need to relay write requests to a primary server
+ * and false otherwise.
+ *
+ * NOTES
+ *
+ * - primarily handles :ext: method as this seems most likely to be used in
+ * practice.
+ *
+ * - :fork: method is handled for testing.
+ *
+ * - Could handle pserver too, but would have to store the password
+ * the client sent us.
+ *
+ *
+ * GLOBALS
+ * config->PrimaryServer
+ * The parsed setting from CVSROOT/config, if any, or
+ * NULL, otherwise.
+ * current_parsed_root The current repository.
+ *
+ * RETURNS
+ * true If this server is configured as a secondary server.
+ * false Otherwise.
+ */
+static inline bool
+isProxyServer (void)
+{
+ assert (current_parsed_root);
+
+ /***
+ *** The following is done as a series of if/return combinations an an
+ *** optimization.
+ ***/
+
+ /* If there is no primary server defined in CVSROOT/config, then we can't
+ * be a secondary.
+ */
+ if (!config || !config->PrimaryServer) return false;
+
+ /* The directory must not match for all methods. */
+ if (!isSamePath (config->PrimaryServer->directory,
+ current_parsed_root->directory))
+ return true;
+
+ /* Only the directory is important for fork. */
+ if (config->PrimaryServer->method == fork_method)
+ return false;
+
+ /* Must be :ext: method, then. This is enforced when CVSROOT/config is
+ * parsed.
+ */
+ assert (config->PrimaryServer->isremote);
+
+ if (isThisHost (config->PrimaryServer->hostname))
+ return false;
+
+ return true;
+}
+
+
+
+static void
+serve_valid_responses (char *arg)
+{
+ char *p = arg;
+ char *q;
+ struct response *rs;
+
+# ifdef PROXY_SUPPORT
+ /* Process this in the first pass since the data it gathers can be used
+ * prior to a `Root' request.
+ */
+ if (reprocessing) return;
+# endif /* PROXY_SUPPORT */
+
+ do
+ {
+ q = strchr (p, ' ');
+ if (q != NULL)
+ *q++ = '\0';
+ for (rs = responses; rs->name != NULL; ++rs)
+ {
+ if (strcmp (rs->name, p) == 0)
+ break;
+ }
+ if (rs->name == NULL)
+ /*
+ * It is a response we have never heard of (and thus never
+ * will want to use). So don't worry about it.
+ */
+ ;
+ else
+ rs->status = rs_supported;
+ p = q;
+ } while (q != NULL);
+ for (rs = responses; rs->name != NULL; ++rs)
+ {
+ if (rs->status == rs_essential)
+ {
+ buf_output0 (buf_to_net, "E response `");
+ buf_output0 (buf_to_net, rs->name);
+ buf_output0 (buf_to_net, "' not supported by client\nerror \n");
+
+ /* FIXME: This call to buf_flush could conceivably
+ cause deadlock, as noted in server_cleanup. */
+ buf_flush (buf_to_net, 1);
+
+ exit (EXIT_FAILURE);
+ }
+ else if (rs->status == rs_optional)
+ rs->status = rs_not_supported;
+ }
+}
+
+
+
+/*
+ * Process IDs of the subprocess, or negative if that subprocess
+ * does not exist.
+ */
+static pid_t command_pid;
+
+static void
+outbuf_memory_error (struct buffer *buf)
+{
+ static const char msg[] = "E Fatal server error\n\
+error ENOMEM Virtual memory exhausted.\n";
+ if (command_pid > 0)
+ kill (command_pid, SIGTERM);
+
+ /*
+ * We have arranged things so that printing this now either will
+ * be valid, or the "E fatal error" line will get glommed onto the
+ * end of an existing "E" or "M" response.
+ */
+
+ /* If this gives an error, not much we could do. syslog() it? */
+ write (STDOUT_FILENO, msg, sizeof (msg) - 1);
+# ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_ERR, "virtual memory exhausted");
+# endif /* HAVE_SYSLOG_H */
+ exit (EXIT_FAILURE);
+}
+
+
+
+static void
+input_memory_error (struct buffer *buf)
+{
+ outbuf_memory_error (buf);
+}
+
+
+
+# ifdef PROXY_SUPPORT
+/* This function rewinds the net connection using the write proxy log file.
+ *
+ * GLOBALS
+ * proxy_log The buffer object containing the write proxy log.
+ *
+ * RETURNS
+ * Nothing.
+ */
+static void
+rewind_buf_from_net (void)
+{
+ struct buffer *log;
+
+ assert (proxy_log);
+
+ /* Free the arguments since we processed some of them in the first pass.
+ */
+ {
+ /* argument_vector[0] is a dummy argument, we don't mess with
+ * it.
+ */
+ char **cp;
+ for (cp = argument_vector + 1;
+ cp < argument_vector + argument_count;
+ ++cp)
+ free (*cp);
+
+ argument_count = 1;
+ }
+
+ log = log_buffer_rewind (proxy_log);
+ proxy_log = NULL;
+ /* Dispose of any read but unused data in the net buffer since it will
+ * already be in the log.
+ */
+ buf_free_data (buf_from_net);
+ buf_from_net = ms_buffer_initialize (outbuf_memory_error, log,
+ buf_from_net);
+ reprocessing = true;
+}
+# endif /* PROXY_SUPPORT */
+
+
+
+char *gConfigPath;
+
+
+
+/*
+ * This request cannot be ignored by a potential secondary since it is used to
+ * determine if we _are_ a secondary.
+ */
+static void
+serve_root (char *arg)
+{
+ char *path;
+
+ TRACE (TRACE_FUNCTION, "serve_root (%s)", arg ? arg : "(null)");
+
+ /* Don't process this twice or when errors are pending. */
+ if (error_pending()
+# ifdef PROXY_SUPPORT
+ || reprocessing
+# endif /* PROXY_SUPPORT */
+ ) return;
+
+ if (!ISABSOLUTE (arg))
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E Root %s must be an absolute pathname", arg);
+ return;
+ }
+
+ /* Sending "Root" twice is invalid.
+
+ The other way to handle a duplicate Root requests would be as a
+ request to clear out all state and start over as if it was a
+ new connection. Doing this would cause interoperability
+ headaches, so it should be a different request, if there is
+ any reason why such a feature is needed. */
+ if (current_parsed_root != NULL)
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E Protocol error: Duplicate Root request, for %s", arg);
+ return;
+ }
+
+ /* Set original_parsed_root here, not because it can be changed in the
+ * client Redirect sense, but so we don't have to switch in code that
+ * runs in both modes to decide which to print.
+ */
+ original_parsed_root = current_parsed_root = local_cvsroot (arg);
+
+# ifdef AUTH_SERVER_SUPPORT
+ if (Pserver_Repos != NULL)
+ {
+ if (strcmp (Pserver_Repos, current_parsed_root->directory) != 0)
+ {
+ if (alloc_pending (80 + strlen (Pserver_Repos)
+ + strlen (current_parsed_root->directory)))
+ /* The explicitness is to aid people who are writing clients.
+ I don't see how this information could help an
+ attacker. */
+ sprintf (pending_error_text, "\
+E Protocol error: Root says \"%s\" but pserver says \"%s\"",
+ current_parsed_root->directory, Pserver_Repos);
+ return;
+ }
+ }
+# endif
+
+ /* For pserver, this will already have happened, and the call will do
+ nothing. But for rsh, we need to do it now. */
+ config = get_root_allow_config (current_parsed_root->directory,
+ gConfigPath);
+
+# ifdef PROXY_SUPPORT
+ /* At this point we have enough information to determine if we are a
+ * secondary server or not.
+ */
+ if (proxy_log && !isProxyServer ())
+ {
+ /* Else we are not a secondary server. There is no point in
+ * reprocessing since we handle all the requests we can receive
+ * before `Root' as we receive them. But close the logs.
+ */
+ log_buffer_closelog (proxy_log);
+ log_buffer_closelog (proxy_log_out);
+ proxy_log = NULL;
+ /*
+ * Don't need this. We assume it when proxy_log == NULL.
+ *
+ * proxy_log_out = NULL;
+ */
+ }
+# endif /* PROXY_SUPPORT */
+
+ /* Now set the TMPDIR environment variable. If it was set in the config
+ * file, we now know it.
+ */
+ push_env_temp_dir ();
+
+ /* OK, now figure out where we stash our temporary files. */
+ {
+ char *p;
+
+ /* The code which wants to chdir into server_temp_dir is not set
+ * up to deal with it being a relative path. So give an error
+ * for that case.
+ */
+ if (!ISABSOLUTE (get_cvs_tmp_dir ()))
+ {
+ if (alloc_pending (80 + strlen (get_cvs_tmp_dir ())))
+ sprintf (pending_error_text,
+ "E Value of %s for TMPDIR is not absolute",
+ get_cvs_tmp_dir ());
+
+ /* FIXME: we would like this error to be persistent, that
+ * is, not cleared by print_pending_error. The current client
+ * will exit as soon as it gets an error, but the protocol spec
+ * does not require a client to do so.
+ */
+ }
+ else
+ {
+ int status;
+ int i = 0;
+
+ server_temp_dir = xmalloc (strlen (get_cvs_tmp_dir ()) + 80);
+ if (!server_temp_dir)
+ {
+ /* Strictly speaking, we're not supposed to output anything
+ * now. But we're about to exit(), give it a try.
+ */
+ printf ("E Fatal server error, aborting.\n\
+error ENOMEM Virtual memory exhausted.\n");
+
+ exit (EXIT_FAILURE);
+ }
+ strcpy (server_temp_dir, get_cvs_tmp_dir ());
+
+ /* Remove a trailing slash from TMPDIR if present. */
+ p = server_temp_dir + strlen (server_temp_dir) - 1;
+ if (*p == '/')
+ *p = '\0';
+
+ /* I wanted to use cvs-serv/PID, but then you have to worry about
+ * the permissions on the cvs-serv directory being right. So
+ * use cvs-servPID.
+ */
+ strcat (server_temp_dir, "/cvs-serv");
+
+ p = server_temp_dir + strlen (server_temp_dir);
+ sprintf (p, "%ld", (long) getpid ());
+
+ orig_server_temp_dir = server_temp_dir;
+
+ /* Create the temporary directory, and set the mode to
+ * 700, to discourage random people from tampering with
+ * it.
+ */
+ while ((status = mkdir_p (server_temp_dir)) == EEXIST)
+ {
+ static const char suffix[] = "abcdefghijklmnopqrstuvwxyz";
+
+ if (i >= sizeof suffix - 1) break;
+ if (i == 0) p = server_temp_dir + strlen (server_temp_dir);
+ p[0] = suffix[i++];
+ p[1] = '\0';
+ }
+ if (status)
+ {
+ if (alloc_pending (80 + strlen (server_temp_dir)))
+ sprintf (pending_error_text,
+ "E can't create temporary directory %s",
+ server_temp_dir);
+ pending_error = status;
+ }
+#ifndef CHMOD_BROKEN
+ else if (chmod (server_temp_dir, S_IRWXU) < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (server_temp_dir)))
+ sprintf (pending_error_text,
+"E cannot change permissions on temporary directory %s",
+ server_temp_dir);
+ pending_error = save_errno;
+ }
+#endif
+ else if (CVS_CHDIR (server_temp_dir) < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (server_temp_dir)))
+ sprintf (pending_error_text,
+"E cannot change to temporary directory %s",
+ server_temp_dir);
+ pending_error = save_errno;
+ }
+ }
+ }
+
+ /* Now that we have a config, verify our compression level. Since
+ * most clients do not send Gzip-stream requests until after the root
+ * request, wait until the first request following Root to verify that
+ * compression is being used when level 0 is not allowed.
+ */
+ if (gzip_level)
+ {
+ bool forced = false;
+
+ if (gzip_level < config->MinCompressionLevel)
+ {
+ gzip_level = config->MinCompressionLevel;
+ forced = true;
+ }
+
+ if (gzip_level > config->MaxCompressionLevel)
+ {
+ gzip_level = config->MaxCompressionLevel;
+ forced = true;
+ }
+
+ if (forced && !quiet
+ && alloc_pending_warning (120 + strlen (program_name)))
+ sprintf (pending_warning_text,
+"E %s server: Forcing compression level %d (allowed: %d <= z <= %d).",
+ program_name, gzip_level, config->MinCompressionLevel,
+ config->MaxCompressionLevel);
+ }
+
+ path = xmalloc (strlen (current_parsed_root->directory)
+ + sizeof (CVSROOTADM)
+ + 2);
+ if (path == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM);
+ if (!isaccessible (path, R_OK | X_OK))
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (path)))
+ sprintf (pending_error_text, "E Cannot access %s", path);
+ pending_error = save_errno;
+ }
+ free (path);
+
+ setenv (CVSROOT_ENV, current_parsed_root->directory, 1);
+}
+
+
+
+static int max_dotdot_limit = 0;
+
+/* Is this pathname OK to recurse into when we are running as the server?
+ If not, call error() with a fatal error. */
+void
+server_pathname_check (char *path)
+{
+ TRACE (TRACE_FUNCTION, "server_pathname_check (%s)",
+ path ? path : "(null)");
+
+ /* An absolute pathname is almost surely a path on the *client* machine,
+ and is unlikely to do us any good here. It also is probably capable
+ of being a security hole in the anonymous readonly case. */
+ if (ISABSOLUTE (path))
+ /* Giving an error is actually kind of a cop-out, in the sense
+ that it would be nice for "cvs co -d /foo/bar/baz" to work.
+ A quick fix in the server would be requiring Max-dotdot of
+ at least one if pathnames are absolute, and then putting
+ /abs/foo/bar/baz in the temp dir beside the /d/d/d stuff.
+ A cleaner fix in the server might be to decouple the
+ pathnames we pass back to the client from pathnames in our
+ temp directory (this would also probably remove the need
+ for Max-dotdot). A fix in the client would have the client
+ turn it into "cd /foo/bar; cvs co -d baz" (more or less).
+ This probably has some problems with pathnames which appear
+ in messages. */
+ error ( 1, 0,
+ "absolute pathnames invalid for server (specified `%s')",
+ path );
+ if (pathname_levels (path) > max_dotdot_limit)
+ {
+ /* Similar to the ISABSOLUTE case in security implications. */
+ error (0, 0, "protocol error: `%s' contains more leading ..", path);
+ error (1, 0, "than the %d which Max-dotdot specified",
+ max_dotdot_limit);
+ }
+}
+
+
+
+/* Is file or directory REPOS an absolute pathname within the
+ current_parsed_root->directory? If yes, return 0. If no, set pending_error
+ and return 1. */
+static int
+outside_root (char *repos)
+{
+ size_t repos_len = strlen (repos);
+ size_t root_len = strlen (current_parsed_root->directory);
+
+ /* ISABSOLUTE (repos) should always be true, but
+ this is a good security precaution regardless. -DRP
+ */
+ if (!ISABSOLUTE (repos))
+ {
+ if (alloc_pending (repos_len + 80))
+ sprintf (pending_error_text, "\
+E protocol error: %s is not absolute", repos);
+ return 1;
+ }
+
+ if (repos_len < root_len
+ || strncmp (current_parsed_root->directory, repos, root_len) != 0)
+ {
+ not_within:
+ if (alloc_pending (strlen (current_parsed_root->directory)
+ + strlen (repos)
+ + 80))
+ sprintf (pending_error_text, "\
+E protocol error: directory '%s' not within root '%s'",
+ repos, current_parsed_root->directory);
+ return 1;
+ }
+ if (repos_len > root_len)
+ {
+ if (repos[root_len] != '/')
+ goto not_within;
+ if (pathname_levels (repos + root_len + 1) > 0)
+ goto not_within;
+ }
+ return 0;
+}
+
+
+
+/* Is file or directory FILE outside the current directory (that is, does
+ it contain '/')? If no, return 0. If yes, set pending_error
+ and return 1. */
+static int
+outside_dir (char *file)
+{
+ if (strchr (file, '/') != NULL)
+ {
+ if (alloc_pending (strlen (file)
+ + 80))
+ sprintf (pending_error_text, "\
+E protocol error: directory '%s' not within current directory",
+ file);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/*
+ * Add as many directories to the temp directory as the client tells us it
+ * will use "..", so we never try to access something outside the temp
+ * directory via "..".
+ */
+static void
+serve_max_dotdot (char *arg)
+{
+ int lim = atoi (arg);
+ int i;
+ char *p;
+
+#ifdef PROXY_SUPPORT
+ if (proxy_log) return;
+#endif /* PROXY_SUPPORT */
+
+ if (lim < 0 || lim > 10000)
+ return;
+ p = xmalloc (strlen (server_temp_dir) + 2 * lim + 10);
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (p, server_temp_dir);
+ for (i = 0; i < lim; ++i)
+ strcat (p, "/d");
+ if (server_temp_dir != orig_server_temp_dir)
+ free (server_temp_dir);
+ server_temp_dir = p;
+ max_dotdot_limit = lim;
+}
+
+
+
+static char *gDirname;
+static char *gupdate_dir;
+
+static void
+dirswitch (char *dir, char *repos)
+{
+ int status;
+ FILE *f;
+ size_t dir_len;
+
+ TRACE (TRACE_FUNCTION, "dirswitch (%s, %s)", dir ? dir : "(null)",
+ repos ? repos : "(null)");
+
+ server_write_entries ();
+
+ if (error_pending()) return;
+
+ /* Check for bad directory name.
+
+ FIXME: could/should unify these checks with server_pathname_check
+ except they need to report errors differently. */
+ if (ISABSOLUTE (dir))
+ {
+ if (alloc_pending (80 + strlen (dir)))
+ sprintf ( pending_error_text,
+ "E absolute pathnames invalid for server (specified `%s')",
+ dir);
+ return;
+ }
+ if (pathname_levels (dir) > max_dotdot_limit)
+ {
+ if (alloc_pending (80 + strlen (dir)))
+ sprintf (pending_error_text,
+ "E protocol error: `%s' has too many ..", dir);
+ return;
+ }
+
+ dir_len = strlen (dir);
+
+ /* Check for a trailing '/'. This is not ISSLASH because \ in the
+ protocol is an ordinary character, not a directory separator (of
+ course, it is perhaps unwise to use it in directory names, but that
+ is another issue). */
+ if (dir_len > 0
+ && dir[dir_len - 1] == '/')
+ {
+ if (alloc_pending (80 + dir_len))
+ sprintf (pending_error_text,
+ "E protocol error: invalid directory syntax in %s", dir);
+ return;
+ }
+
+ if (gDirname != NULL)
+ free (gDirname);
+ if (gupdate_dir != NULL)
+ free (gupdate_dir);
+
+ if (!strcmp (dir, "."))
+ gupdate_dir = xstrdup ("");
+ else
+ gupdate_dir = xstrdup (dir);
+
+ gDirname = xmalloc (strlen (server_temp_dir) + dir_len + 40);
+ if (gDirname == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+
+ strcpy (gDirname, server_temp_dir);
+ strcat (gDirname, "/");
+ strcat (gDirname, dir);
+
+ status = mkdir_p (gDirname);
+ if (status != 0
+ && status != EEXIST)
+ {
+ if (alloc_pending (80 + strlen (gDirname)))
+ sprintf (pending_error_text, "E cannot mkdir %s", gDirname);
+ pending_error = status;
+ return;
+ }
+
+ /* We need to create adm directories in all path elements because
+ we want the server to descend them, even if the client hasn't
+ sent the appropriate "Argument xxx" command to match the
+ already-sent "Directory xxx" command. See recurse.c
+ (start_recursion) for a big discussion of this. */
+
+ status = create_adm_p (server_temp_dir, dir);
+ if (status != 0)
+ {
+ if (alloc_pending (80 + strlen (gDirname)))
+ sprintf (pending_error_text, "E cannot create_adm_p %s", gDirname);
+ pending_error = status;
+ return;
+ }
+
+ if ( CVS_CHDIR (gDirname) < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (gDirname)))
+ sprintf (pending_error_text, "E cannot change to %s", gDirname);
+ pending_error = save_errno;
+ return;
+ }
+ /*
+ * This is pretty much like calling Create_Admin, but Create_Admin doesn't
+ * report errors in the right way for us.
+ */
+ if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST))
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM)))
+ sprintf (pending_error_text,
+ "E cannot mkdir %s/%s", gDirname, CVSADM);
+ pending_error = save_errno;
+ return;
+ }
+
+ /* The following will overwrite the contents of CVSADM_REP. This
+ is the correct behavior -- mkdir_p may have written a
+ placeholder value to this file and we need to insert the
+ correct value. */
+
+ f = CVS_FOPEN (CVSADM_REP, "w");
+ if (f == NULL)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E cannot open %s/%s", gDirname, CVSADM_REP);
+ pending_error = save_errno;
+ return;
+ }
+ if (fprintf (f, "%s", repos) < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", gDirname, CVSADM_REP);
+ pending_error = save_errno;
+ fclose (f);
+ return;
+ }
+ /* Non-remote CVS handles a module representing the entire tree
+ (e.g., an entry like ``world -a .'') by putting /. at the end
+ of the Repository file, so we do the same. */
+ if (strcmp (dir, ".") == 0
+ && current_parsed_root != NULL
+ && current_parsed_root->directory != NULL
+ && strcmp (current_parsed_root->directory, repos) == 0)
+ {
+ if (fprintf (f, "/.") < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", gDirname, CVSADM_REP);
+ pending_error = save_errno;
+ fclose (f);
+ return;
+ }
+ }
+ if (fprintf (f, "\n") < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", gDirname, CVSADM_REP);
+ pending_error = save_errno;
+ fclose (f);
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error closing %s/%s", gDirname, CVSADM_REP);
+ pending_error = save_errno;
+ return;
+ }
+ /* We open in append mode because we don't want to clobber an
+ existing Entries file. */
+ f = CVS_FOPEN (CVSADM_ENT, "a");
+ if (f == NULL)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_ENT)))
+ sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
+ pending_error = save_errno;
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_ENT)))
+ sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
+ pending_error = save_errno;
+ return;
+ }
+}
+
+
+
+static void
+serve_repository (char *arg)
+{
+# ifdef PROXY_SUPPORT
+ assert (!proxy_log);
+# endif /* PROXY_SUPPORT */
+
+ if (alloc_pending (80))
+ strcpy (pending_error_text,
+ "E Repository request is obsolete; aborted");
+ return;
+}
+
+
+
+static void
+serve_directory (char *arg)
+{
+ int status;
+ char *repos;
+
+ TRACE (TRACE_FUNCTION, "serve_directory (%s)", arg ? arg : "(null)");
+
+
+ /* The data needs to be read into the secondary log regardless, but
+ * processing of anything other than errors is skipped until later.
+ */
+ status = buf_read_line (buf_from_net, &repos, NULL);
+ if (status == 0)
+ {
+ if (!ISABSOLUTE (repos))
+ {
+ /* Make absolute.
+ *
+ * FIXME: This is kinda hacky - we should probably only ever store
+ * and pass SHORT_REPOS (perhaps with the occassional exception
+ * for optimizations, but many, many functions end up
+ * deconstructing REPOS to gain SHORT_REPOS anyhow) - the
+ * CVSROOT portion of REPOS is redundant with
+ * current_parsed_root->directory - but since this is the way
+ * things have always been done, changing this will likely involve
+ * a major overhaul.
+ */
+ char *short_repos;
+
+ short_repos = repos;
+ repos = Xasprintf ("%s/%s",
+ current_parsed_root->directory, short_repos);
+ free (short_repos);
+ }
+ else
+ repos = xstrdup (primary_root_translate (repos));
+
+ if (
+# ifdef PROXY_SUPPORT
+ !proxy_log &&
+# endif /* PROXY_SUPPORT */
+ !outside_root (repos))
+ dirswitch (arg, repos);
+ free (repos);
+ }
+ else if (status == -2)
+ {
+ pending_error = ENOMEM;
+ }
+ else if (status != 0)
+ {
+ pending_error_text = xmalloc (80 + strlen (arg));
+ if (pending_error_text == NULL)
+ {
+ pending_error = ENOMEM;
+ }
+ else if (status == -1)
+ {
+ sprintf (pending_error_text,
+ "E end of file reading mode for %s", arg);
+ }
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading mode for %s", arg);
+ pending_error = status;
+ }
+ }
+}
+
+
+
+static void
+serve_static_directory (char *arg)
+{
+ FILE *f;
+
+ if (error_pending ()
+# ifdef PROXY_SUPPORT
+ || proxy_log
+# endif /* PROXY_SUPPORT */
+ ) return;
+
+ f = CVS_FOPEN (CVSADM_ENTSTAT, "w+");
+ if (f == NULL)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
+ sprintf (pending_error_text, "E cannot open %s", CVSADM_ENTSTAT);
+ pending_error = save_errno;
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
+ sprintf (pending_error_text, "E cannot close %s", CVSADM_ENTSTAT);
+ pending_error = save_errno;
+ return;
+ }
+}
+
+
+
+static void
+serve_sticky (char *arg)
+{
+ FILE *f;
+
+ if (error_pending ()
+# ifdef PROXY_SUPPORT
+ || proxy_log
+# endif /* PROXY_SUPPORT */
+ ) return;
+
+ f = CVS_FOPEN (CVSADM_TAG, "w+");
+ if (f == NULL)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_TAG)))
+ sprintf (pending_error_text, "E cannot open %s", CVSADM_TAG);
+ pending_error = save_errno;
+ return;
+ }
+ if (fprintf (f, "%s\n", arg) < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_TAG)))
+ sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG);
+ pending_error = save_errno;
+ return;
+ }
+ if (fclose (f) == EOF)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_TAG)))
+ sprintf (pending_error_text, "E cannot close %s", CVSADM_TAG);
+ pending_error = save_errno;
+ return;
+ }
+}
+
+
+
+/*
+ * Read SIZE bytes from buf_from_net, write them to FILE.
+ *
+ * Currently this isn't really used for receiving parts of a file --
+ * the file is still sent over in one chunk. But if/when we get
+ * spiffy in-process gzip support working, perhaps the compressed
+ * pieces could be sent over as they're ready, if the network is fast
+ * enough. Or something.
+ */
+static void
+receive_partial_file (size_t size, int file)
+{
+ while (size > 0)
+ {
+ int status;
+ size_t nread;
+ char *data;
+
+ status = buf_read_data (buf_from_net, size, &data, &nread);
+ if (status != 0)
+ {
+ if (status == -2)
+ pending_error = ENOMEM;
+ else
+ {
+ pending_error_text = xmalloc (80);
+ if (pending_error_text == NULL)
+ pending_error = ENOMEM;
+ else if (status == -1)
+ {
+ sprintf (pending_error_text,
+ "E premature end of file from client");
+ pending_error = 0;
+ }
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading from client");
+ pending_error = status;
+ }
+ }
+ return;
+ }
+
+ size -= nread;
+
+ while (nread > 0)
+ {
+ ssize_t nwrote;
+
+ nwrote = write (file, data, nread);
+ if (nwrote < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (40))
+ strcpy (pending_error_text, "E unable to write");
+ pending_error = save_errno;
+
+ /* Read and discard the file data. */
+ while (size > 0)
+ {
+ int status;
+ size_t nread;
+ char *data;
+
+ status = buf_read_data (buf_from_net, size, &data, &nread);
+ if (status != 0)
+ return;
+ size -= nread;
+ }
+
+ return;
+ }
+ nread -= nwrote;
+ data += nwrote;
+ }
+ }
+}
+
+
+
+/* Receive SIZE bytes, write to filename FILE. */
+static void
+receive_file (size_t size, char *file, int gzipped)
+{
+ int fd;
+ char *arg = file;
+
+ /* Write the file. */
+ fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (40 + strlen (arg)))
+ sprintf (pending_error_text, "E cannot open %s", arg);
+ pending_error = save_errno;
+ return;
+ }
+
+ if (gzipped)
+ {
+ /* Using gunzip_and_write isn't really a high-performance
+ approach, because it keeps the whole thing in memory
+ (contiguous memory, worse yet). But it seems easier to
+ code than the alternative (and less vulnerable to subtle
+ bugs). Given that this feature is mainly for
+ compatibility, that is the better tradeoff. */
+
+ size_t toread = size;
+ char *filebuf;
+ char *p;
+
+ filebuf = xmalloc (size);
+ p = filebuf;
+ /* If NULL, we still want to read the data and discard it. */
+
+ while (toread > 0)
+ {
+ int status;
+ size_t nread;
+ char *data;
+
+ status = buf_read_data (buf_from_net, toread, &data, &nread);
+ if (status != 0)
+ {
+ if (status == -2)
+ pending_error = ENOMEM;
+ else
+ {
+ pending_error_text = xmalloc (80);
+ if (pending_error_text == NULL)
+ pending_error = ENOMEM;
+ else if (status == -1)
+ {
+ sprintf (pending_error_text,
+ "E premature end of file from client");
+ pending_error = 0;
+ }
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading from client");
+ pending_error = status;
+ }
+ }
+ return;
+ }
+
+ toread -= nread;
+
+ if (filebuf != NULL)
+ {
+ memcpy (p, data, nread);
+ p += nread;
+ }
+ }
+ if (filebuf == NULL)
+ {
+ pending_error = ENOMEM;
+ goto out;
+ }
+
+ if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size))
+ {
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E aborting due to compression error");
+ }
+ free (filebuf);
+ }
+ else
+ receive_partial_file (size, fd);
+
+ if (pending_error_text)
+ {
+ char *p = xrealloc (pending_error_text,
+ strlen (pending_error_text) + strlen (arg) + 30);
+ if (p)
+ {
+ pending_error_text = p;
+ sprintf (p + strlen (p), ", file %s", arg);
+ }
+ /* else original string is supposed to be unchanged */
+ }
+
+ out:
+ if (close (fd) < 0 && !error_pending ())
+ {
+ int save_errno = errno;
+ if (alloc_pending (40 + strlen (arg)))
+ sprintf (pending_error_text, "E cannot close %s", arg);
+ pending_error = save_errno;
+ return;
+ }
+}
+
+
+
+/* Kopt for the next file sent in Modified or Is-modified. */
+static char *kopt;
+
+/* Timestamp (Checkin-time) for next file sent in Modified or
+ Is-modified. */
+static int checkin_time_valid;
+static time_t checkin_time;
+
+
+
+/*
+ * Used to keep track of Entry requests.
+ */
+struct an_entry {
+ struct an_entry *next;
+ char *entry;
+};
+
+static struct an_entry *entries;
+
+static void
+serve_is_modified (char *arg)
+{
+ struct an_entry *p;
+ char *name;
+ char *cp;
+ char *timefield;
+ /* Have we found this file in "entries" yet. */
+ int found;
+
+ if (error_pending ()
+# ifdef PROXY_SUPPORT
+ || proxy_log
+# endif /* PROXY_SUPPORT */
+ ) return;
+
+ if (outside_dir (arg))
+ return;
+
+ /* Rewrite entries file to have `M' in timestamp field. */
+ found = 0;
+ for (p = entries; p != NULL; p = p->next)
+ {
+ name = p->entry + 1;
+ cp = strchr (name, '/');
+ if (cp != NULL
+ && strlen (arg) == cp - name
+ && strncmp (arg, name, cp - name) == 0)
+ {
+ if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0')
+ {
+ /* We didn't find the record separator or it is followed by
+ * the end of the string, so just exit.
+ */
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E Malformed Entry encountered.");
+ return;
+ }
+ /* If the time field is not currently empty, then one of
+ * serve_modified, serve_is_modified, & serve_unchanged were
+ * already called for this file. We would like to ignore the
+ * reinvocation silently or, better yet, exit with an error
+ * message, but we just avoid the copy-forward and overwrite the
+ * value from the last invocation instead. See the comment below
+ * for more.
+ */
+ if (*timefield == '/')
+ {
+ /* Copy forward one character. Space was allocated for this
+ * already in serve_entry(). */
+ cp = timefield + strlen (timefield);
+ cp[1] = '\0';
+ while (cp > timefield)
+ {
+ *cp = cp[-1];
+ --cp;
+ }
+
+ /* *timefield == '/'; */
+ }
+ /* If *TIMEFIELD wasn't '/' and wasn't '+', we assume that it was
+ * because of multiple calls to Is-modified & Unchanged by the
+ * client and just overwrite the value from the last call.
+ * Technically, we should probably either ignore calls after the
+ * first or send the client an error, since the client/server
+ * protocol specification specifies that only one call to either
+ * Is-Modified or Unchanged is allowed, but broken versions of
+ * CVSNT (at least 2.0.34 - 2.0.41, reported fixed in 2.0.41a) and
+ * the WinCVS & TortoiseCVS clients which depend on those broken
+ * versions of CVSNT (WinCVS 1.3 & at least one TortoiseCVS
+ * release) rely on this behavior.
+ */
+ if (*timefield != '+')
+ *timefield = 'M';
+
+ if (kopt != NULL)
+ {
+ if (alloc_pending (strlen (name) + 80))
+ sprintf (pending_error_text,
+ "E protocol error: both Kopt and Entry for %s",
+ arg);
+ free (kopt);
+ kopt = NULL;
+ return;
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ {
+ /* We got Is-modified but no Entry. Add a dummy entry.
+ The "D" timestamp is what makes it a dummy. */
+ p = xmalloc (sizeof (struct an_entry));
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ p->entry = xmalloc (strlen (arg) + 80);
+ if (p->entry == NULL)
+ {
+ pending_error = ENOMEM;
+ free (p);
+ return;
+ }
+ strcpy (p->entry, "/");
+ strcat (p->entry, arg);
+ strcat (p->entry, "//D/");
+ if (kopt != NULL)
+ {
+ strcat (p->entry, kopt);
+ free (kopt);
+ kopt = NULL;
+ }
+ strcat (p->entry, "/");
+ p->next = entries;
+ entries = p;
+ }
+}
+
+
+
+static void
+serve_modified (char *arg)
+{
+ size_t size;
+ int read_size;
+ int status;
+ char *size_text;
+ char *mode_text;
+
+ int gzipped = 0;
+
+ /*
+ * This used to return immediately if error_pending () was true.
+ * However, that fails, because it causes each line of the file to
+ * be echoed back to the client as an unrecognized command. The
+ * client isn't reading from the socket, so eventually both
+ * processes block trying to write to the other. Now, we try to
+ * read the file if we can.
+ */
+
+ status = buf_read_line (buf_from_net, &mode_text, NULL);
+ if (status != 0)
+ {
+ if (status == -2)
+ pending_error = ENOMEM;
+ else
+ {
+ pending_error_text = xmalloc (80 + strlen (arg));
+ if (pending_error_text == NULL)
+ pending_error = ENOMEM;
+ else
+ {
+ if (status == -1)
+ sprintf (pending_error_text,
+ "E end of file reading mode for %s", arg);
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading mode for %s", arg);
+ pending_error = status;
+ }
+ }
+ }
+ return;
+ }
+
+ status = buf_read_line (buf_from_net, &size_text, NULL);
+ if (status != 0)
+ {
+ if (status == -2)
+ pending_error = ENOMEM;
+ else
+ {
+ pending_error_text = xmalloc (80 + strlen (arg));
+ if (pending_error_text == NULL)
+ pending_error = ENOMEM;
+ else
+ {
+ if (status == -1)
+ sprintf (pending_error_text,
+ "E end of file reading size for %s", arg);
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading size for %s", arg);
+ pending_error = status;
+ }
+ }
+ }
+ free (mode_text);
+ return;
+ }
+ if (size_text[0] == 'z')
+ {
+ gzipped = 1;
+ read_size = atoi (size_text + 1);
+ }
+ else
+ read_size = atoi (size_text);
+ free (size_text);
+
+ if (read_size < 0 && alloc_pending (80))
+ {
+ sprintf (pending_error_text,
+ "E client sent invalid (negative) file size");
+ return;
+ }
+ else
+ size = read_size;
+
+ if (error_pending ())
+ {
+ /* Now that we know the size, read and discard the file data. */
+ while (size > 0)
+ {
+ int status;
+ size_t nread;
+ char *data;
+
+ status = buf_read_data (buf_from_net, size, &data, &nread);
+ if (status != 0)
+ return;
+ size -= nread;
+ }
+ free (mode_text);
+ return;
+ }
+
+ if (
+# ifdef PROXY_SUPPORT
+ !proxy_log &&
+# endif /* PROXY_SUPPORT */
+ outside_dir (arg))
+ {
+ free (mode_text);
+ return;
+ }
+
+ receive_file (size,
+# ifdef PROXY_SUPPORT
+ proxy_log ? DEVNULL :
+# endif /* PROXY_SUPPORT */
+ arg,
+ gzipped);
+ if (error_pending ())
+ {
+ free (mode_text);
+ return;
+ }
+
+# ifdef PROXY_SUPPORT
+ /* We've read all the data that needed to be read if we're still logging
+ * for a secondary. Return.
+ */
+ if (proxy_log) return;
+# endif /* PROXY_SUPPORT */
+
+ if (checkin_time_valid)
+ {
+ struct utimbuf t;
+
+ memset (&t, 0, sizeof (t));
+ t.modtime = t.actime = checkin_time;
+ if (utime (arg, &t) < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text, "E cannot utime %s", arg);
+ pending_error = save_errno;
+ free (mode_text);
+ return;
+ }
+ checkin_time_valid = 0;
+ }
+
+ {
+ int status = change_mode (arg, mode_text, 0);
+ free (mode_text);
+ if (status)
+ {
+ if (alloc_pending (40 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E cannot change mode for %s", arg);
+ pending_error = status;
+ return;
+ }
+ }
+
+ /* Make sure that the Entries indicate the right kopt. We probably
+ could do this even in the non-kopt case and, I think, save a stat()
+ call in time_stamp_server. But for conservatism I'm leaving the
+ non-kopt case alone. */
+ if (kopt != NULL)
+ serve_is_modified (arg);
+}
+
+
+
+static void
+serve_enable_unchanged (char *arg)
+{
+# ifdef PROXY_SUPPORT
+ /* Might as well skip this since this function does nothing anyhow. If
+ * it did do anything and could generate errors, then the line below would
+ * be necessary since this can be processed before a `Root' request.
+ *
+ * if (reprocessing) return;
+ */
+# endif /* PROXY_SUPPORT */
+}
+
+
+
+static void
+serve_unchanged (char *arg)
+{
+ struct an_entry *p;
+ char *name;
+ char *cp;
+ char *timefield;
+
+ if (error_pending ()
+# ifdef PROXY_SUPPORT
+ || proxy_log
+# endif /* PROXY_SUPPORT */
+ ) return;
+
+ if (outside_dir (arg))
+ return;
+
+ /* Rewrite entries file to have `=' in timestamp field. */
+ for (p = entries; p != NULL; p = p->next)
+ {
+ name = p->entry + 1;
+ cp = strchr (name, '/');
+ if (cp != NULL
+ && strlen (arg) == cp - name
+ && strncmp (arg, name, cp - name) == 0)
+ {
+ if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0')
+ {
+ /* We didn't find the record separator or it is followed by
+ * the end of the string, so just exit.
+ */
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E Malformed Entry encountered.");
+ return;
+ }
+ /* If the time field is not currently empty, then one of
+ * serve_modified, serve_is_modified, & serve_unchanged were
+ * already called for this file. We would like to ignore the
+ * reinvocation silently or, better yet, exit with an error
+ * message, but we just avoid the copy-forward and overwrite the
+ * value from the last invocation instead. See the comment below
+ * for more.
+ */
+ if (*timefield == '/')
+ {
+ /* Copy forward one character. Space was allocated for this
+ * already in serve_entry(). */
+ cp = timefield + strlen (timefield);
+ cp[1] = '\0';
+ while (cp > timefield)
+ {
+ *cp = cp[-1];
+ --cp;
+ }
+
+ /* *timefield == '/'; */
+ }
+ if (*timefield != '+')
+ {
+ /* '+' is a conflict marker and we don't want to mess with it
+ * until Version_TS catches it.
+ */
+ if (timefield[1] != '/')
+ {
+ /* Obliterate anything else in TIMEFIELD. This is again to
+ * support the broken CVSNT clients mentioned below, in
+ * conjunction with strict timestamp string boundry
+ * checking in time_stamp_server() from vers_ts.c &
+ * file_has_conflict() from subr.c, since the broken
+ * clients used to send malformed timestamp fields in the
+ * Entry request that they then depended on the subsequent
+ * Unchanged request to overwrite.
+ */
+ char *d = timefield + 1;
+ if ((cp = strchr (d, '/')))
+ {
+ while (*cp)
+ {
+ *d++ = *cp++;
+ }
+ *d = '\0';
+ }
+ }
+ /* If *TIMEFIELD wasn't '/', we assume that it was because of
+ * multiple calls to Is-modified & Unchanged by the client and
+ * just overwrite the value from the last call. Technically,
+ * we should probably either ignore calls after the first or
+ * send the client an error, since the client/server protocol
+ * specification specifies that only one call to either
+ * Is-Modified or Unchanged is allowed, but broken versions of
+ * CVSNT (at least 2.0.34 - 2.0.41, reported fixed in 2.0.41a)
+ * and the WinCVS & TortoiseCVS clients which depend on those
+ * broken versions of CVSNT (WinCVS 1.3 & at least one
+ * TortoiseCVS release) rely on this behavior.
+ */
+ *timefield = '=';
+ }
+ break;
+ }
+ }
+}
+
+
+
+static void
+serve_entry (char *arg)
+{
+ struct an_entry *p;
+ char *cp;
+ int i = 0;
+
+ if (error_pending()
+# ifdef PROXY_SUPPORT
+ || proxy_log
+# endif /* PROXY_SUPPORT */
+ ) return;
+
+ /* Verify that the entry is well-formed. This can avoid problems later.
+ * At the moment we only check that the Entry contains five slashes in
+ * approximately the correct locations since some of the code makes
+ * assumptions about this.
+ */
+ cp = arg;
+ if (*cp == 'D') cp++;
+ while (i++ < 5)
+ {
+ if (!cp || *cp != '/')
+ {
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E protocol error: Malformed Entry");
+ return;
+ }
+ cp = strchr (cp + 1, '/');
+ }
+
+ p = xmalloc (sizeof (struct an_entry));
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ /* Leave space for serve_unchanged to write '=' if it wants. */
+ cp = xmalloc (strlen (arg) + 2);
+ if (cp == NULL)
+ {
+ free (p);
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (cp, arg);
+ p->next = entries;
+ p->entry = cp;
+ entries = p;
+}
+
+
+
+static void
+serve_kopt (char *arg)
+{
+ if (error_pending ()
+# ifdef PROXY_SUPPORT
+ || proxy_log
+# endif /* PROXY_SUPPORT */
+ )
+ return;
+
+ if (kopt != NULL)
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E protocol error: duplicate Kopt request: %s", arg);
+ return;
+ }
+
+ /* Do some sanity checks. In particular, that it is not too long.
+ This lets the rest of the code not worry so much about buffer
+ overrun attacks. Probably should call RCS_check_kflag here,
+ but that would mean changing RCS_check_kflag to handle errors
+ other than via exit(), fprintf(), and such. */
+ if (strlen (arg) > 10)
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E protocol error: invalid Kopt request: %s", arg);
+ return;
+ }
+
+ kopt = xmalloc (strlen (arg) + 1);
+ if (kopt == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (kopt, arg);
+}
+
+
+
+static void
+serve_checkin_time (char *arg)
+{
+ struct timespec t;
+
+ if (error_pending ()
+# ifdef PROXY_SUPPORT
+ || proxy_log
+# endif /* PROXY_SUPPORT */
+ )
+ return;
+
+ if (checkin_time_valid)
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E protocol error: duplicate Checkin-time request: %s",
+ arg);
+ return;
+ }
+
+ if (!get_date (&t, arg, NULL))
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text, "E cannot parse date %s", arg);
+ return;
+ }
+
+ /* Truncate any nanoseconds returned by get_date(). */
+ checkin_time = t.tv_sec;
+ checkin_time_valid = 1;
+}
+
+
+
+static void
+server_write_entries (void)
+{
+ FILE *f;
+ struct an_entry *p;
+ struct an_entry *q;
+
+ if (entries == NULL)
+ return;
+
+ f = NULL;
+ /* Note that we free all the entries regardless of errors. */
+ if (!error_pending ())
+ {
+ /* We open in append mode because we don't want to clobber an
+ existing Entries file. If we are checking out a module
+ which explicitly lists more than one file in a particular
+ directory, then we will wind up calling
+ server_write_entries for each such file. */
+ f = CVS_FOPEN (CVSADM_ENT, "a");
+ if (f == NULL)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_ENT)))
+ sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
+ pending_error = save_errno;
+ }
+ }
+ for (p = entries; p != NULL;)
+ {
+ if (!error_pending ())
+ {
+ if (fprintf (f, "%s\n", p->entry) < 0)
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen(CVSADM_ENT)))
+ sprintf (pending_error_text,
+ "E cannot write to %s", CVSADM_ENT);
+ pending_error = save_errno;
+ }
+ }
+ free (p->entry);
+ q = p->next;
+ free (p);
+ p = q;
+ }
+ entries = NULL;
+ if (f != NULL && fclose (f) == EOF && !error_pending ())
+ {
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (CVSADM_ENT)))
+ sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
+ pending_error = save_errno;
+ }
+}
+
+
+
+# ifdef PROXY_SUPPORT
+/*
+ * callback proc to run a script when admin finishes.
+ */
+static int
+prepost_proxy_proc (const char *repository, const char *filter, void *closure)
+{
+ char *cmdline;
+ bool *pre = closure;
+
+ /* %c = cvs_cmd_name
+ * %p = shortrepos
+ * %r = repository
+ */
+ TRACE (TRACE_FUNCTION, "prepost_proxy_proc (%s, %s, %s)", repository,
+ filter, *pre ? "pre" : "post");
+
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+# ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ 0, ".",
+# endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "c", "s", cvs_cmd_name,
+ "R", "s", referrer ? referrer->original : "NONE",
+ "p", "s", ".",
+ "r", "s", current_parsed_root->directory,
+ "P", "s", config->PrimaryServer->original,
+ (char *) NULL);
+
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ if (*pre)
+ error (0, 0, "preadmin proc resolved to the empty string!");
+ else
+ error (0, 0, "postadmin proc resolved to the empty string!");
+ return 1;
+ }
+
+ run_setup (cmdline);
+
+ free (cmdline);
+
+ /* FIXME - read the comment in verifymsg_proc() about why we use abs()
+ * below() and shouldn't.
+ */
+ return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ RUN_NORMAL | RUN_SIGIGNORE));
+}
+
+
+
+/* Become a secondary write proxy to a master server.
+ *
+ * This function opens the connection to the primary, dumps the secondary log
+ * to the primary, then reads data from any available connection and writes it
+ * to its partner:
+ *
+ * buf_from_net -> buf_to_primary
+ * buf_from_primary -> buf_to_net
+ *
+ * When all "from" connections have sent EOF and all data has been sent to
+ * "to" connections, this function closes the "to" pipes and returns.
+ */
+static void
+become_proxy (void)
+{
+ struct buffer *buf_to_primary;
+ struct buffer *buf_from_primary;
+
+ /* Close the client log and open it for read. */
+ struct buffer *buf_clientlog = log_buffer_rewind (proxy_log_out);
+ int status, to_primary_fd, from_primary_fd, to_net_fd, from_net_fd;
+
+ /* Call presecondary script. */
+ bool pre = true;
+
+ char *data;
+ size_t thispass, got;
+ int s;
+ char *newdata;
+
+ Parse_Info (CVSROOTADM_PREPROXY, current_parsed_root->directory,
+ prepost_proxy_proc, PIOPT_ALL, &pre);
+
+ /* Open connection to primary server. */
+ open_connection_to_server (config->PrimaryServer, &buf_to_primary,
+ &buf_from_primary);
+ setup_logfiles ("CVS_SECONDARY_LOG", &buf_to_primary, &buf_from_primary);
+ if ((status = set_nonblock (buf_from_primary)))
+ error (1, status, "failed to set nonblocking io from primary");
+ if ((status = set_nonblock (buf_from_net)))
+ error (1, status, "failed to set nonblocking io from client");
+ if ((status = set_nonblock (buf_to_primary)))
+ error (1, status, "failed to set nonblocking io to primary");
+ if ((status = set_nonblock (buf_to_net)))
+ error (1, status, "failed to set nonblocking io to client");
+
+ to_primary_fd = buf_get_fd (buf_to_primary);
+ from_primary_fd = buf_get_fd (buf_from_primary);
+ to_net_fd = buf_get_fd (buf_to_net);
+ assert (to_primary_fd >= 0 && from_primary_fd >= 0 && to_net_fd >= 0);
+
+ /* Close the client log and open it for read. */
+ rewind_buf_from_net ();
+
+ while (from_primary_fd >= 0 || to_primary_fd >= 0)
+ {
+ fd_set readfds, writefds;
+ int status, numfds = -1;
+ struct timeval *timeout_ptr;
+ struct timeval timeout;
+ size_t toread;
+
+ FD_ZERO (&readfds);
+ FD_ZERO (&writefds);
+
+ /* The fd for a multi-source buffer can change with any read. */
+ from_net_fd = buf_from_net ? buf_get_fd (buf_from_net) : -1;
+
+ if ((buf_from_net && !buf_empty_p (buf_from_net))
+ || (buf_from_primary && !buf_empty_p (buf_from_primary)))
+ {
+ /* There is data pending so don't block if we don't find any new
+ * data on the fds.
+ */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ timeout_ptr = &timeout;
+ }
+ else
+ /* block indefinately */
+ timeout_ptr = NULL;
+
+ /* Set writefds if data is pending. */
+ if (to_net_fd >= 0 && !buf_empty_p (buf_to_net))
+ {
+ FD_SET (to_net_fd, &writefds);
+ numfds = MAX (numfds, to_net_fd);
+ }
+ if (to_primary_fd >= 0 && !buf_empty_p (buf_to_primary))
+ {
+ FD_SET (to_primary_fd, &writefds);
+ numfds = MAX (numfds, to_primary_fd);
+ }
+
+ /* Set readfds if descriptors are still open. */
+ if (from_net_fd >= 0)
+ {
+ FD_SET (from_net_fd, &readfds);
+ numfds = MAX (numfds, from_net_fd);
+ }
+ if (from_primary_fd >= 0)
+ {
+ FD_SET (from_primary_fd, &readfds);
+ numfds = MAX (numfds, from_primary_fd);
+ }
+
+ /* NUMFDS needs to be the highest descriptor + 1 according to the
+ * select spec.
+ */
+ numfds++;
+
+ do {
+ /* This used to select on exceptions too, but as far
+ as I know there was never any reason to do that and
+ SCO doesn't let you select on exceptions on pipes. */
+ numfds = select (numfds, &readfds, &writefds,
+ NULL, timeout_ptr);
+ if (numfds < 0 && errno != EINTR)
+ {
+ /* Sending an error to the client, possibly in the middle of a
+ * separate protocol message, will likely not mean much to the
+ * client, but it's better than nothing, I guess.
+ */
+ buf_output0 (buf_to_net, "E select failed\n");
+ print_error (errno);
+ exit (EXIT_FAILURE);
+ }
+ } while (numfds < 0);
+
+ if (numfds == 0)
+ {
+ FD_ZERO (&readfds);
+ FD_ZERO (&writefds);
+ }
+
+ if (to_net_fd >= 0 && FD_ISSET (to_net_fd, &writefds))
+ {
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ buf_flush (buf_to_net, false);
+ }
+
+ status = 0;
+ if (from_net_fd >= 0 && (FD_ISSET (from_net_fd, &readfds)))
+ status = buf_input_data (buf_from_net, NULL);
+
+ if (buf_from_net && !buf_empty_p (buf_from_net))
+ {
+ if (buf_to_primary)
+ buf_append_buffer (buf_to_primary, buf_from_net);
+ else
+ /* (Sys?)log this? */;
+
+ }
+
+ if (status == -1 /* EOF */)
+ {
+ SIG_beginCrSect();
+ /* Need only to shut this down and set to NULL, really, in
+ * crit sec, to ensure no double-dispose and to make sure
+ * network pipes are closed as properly as possible, but I
+ * don't see much optimization potential in saving values and
+ * postponing the free.
+ */
+ buf_shutdown (buf_from_net);
+ buf_free (buf_from_net);
+ buf_from_net = NULL;
+ /* So buf_to_primary will be closed at the end of this loop. */
+ from_net_fd = -1;
+ SIG_endCrSect();
+ }
+ else if (status > 0 /* ERRNO */)
+ {
+ buf_output0 (buf_to_net,
+ "E buf_input_data failed reading from client\n");
+ print_error (status);
+ exit (EXIT_FAILURE);
+ }
+
+ if (to_primary_fd >= 0 && FD_ISSET (to_primary_fd, &writefds))
+ {
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_primary);
+ buf_flush (buf_to_primary, false);
+ }
+
+ status = 0;
+ if (from_primary_fd >= 0 && FD_ISSET (from_primary_fd, &readfds))
+ status = buf_input_data (buf_from_primary, &toread);
+
+ /* Avoid resending data from the server which we already sent to the
+ * client. Otherwise clients get really confused.
+ */
+ if (buf_clientlog
+ && buf_from_primary && !buf_empty_p (buf_from_primary))
+ {
+ /* Dispose of data we already sent to the client. */
+ while (buf_clientlog && toread > 0)
+ {
+ s = buf_read_data (buf_clientlog, toread, &data, &got);
+ if (s == -2)
+ error (1, ENOMEM, "Failed to read data.");
+ if (s == -1)
+ {
+ buf_shutdown (buf_clientlog);
+ buf_clientlog = NULL;
+ }
+ else if (s)
+ error (1, s, "Error reading writeproxy log.");
+ else
+ {
+ thispass = got;
+ while (thispass > 0)
+ {
+ /* No need to check for errors here since we know we
+ * won't read more than buf_input read into
+ * BUF_FROM_PRIMARY (see how TOREAD is set above).
+ */
+ buf_read_data (buf_from_primary, thispass, &newdata,
+ &got);
+ /* Verify that we are throwing away what we think we
+ * are.
+ *
+ * It is valid to assume that the secondary and primary
+ * are closely enough in sync that this portion of the
+ * communication will be in sync beacuse if they were
+ * not, then the secondary might provide a
+ * valid-request string to the client which contained a
+ * request that the primary didn't support. If the
+ * client later used the request, the primary server
+ * would exit anyhow.
+ *
+ * FIXME?
+ * An alternative approach might be to make sure that
+ * the secondary provides the same string as the
+ * primary regardless, for purposes like pointing a
+ * secondary at an unwitting primary, in which case it
+ * might be useful to have some way to override the
+ * valid-requests string on a secondary, but it seems
+ * much easier to simply sync the versions, at the
+ * moment.
+ */
+ if (memcmp (data, newdata, got))
+ error (1, 0, "Secondary out of sync with primary!");
+ data += got;
+ thispass -= got;
+ }
+ toread -= got;
+ }
+ }
+ }
+
+ if (buf_from_primary && !buf_empty_p (buf_from_primary))
+ {
+ if (buf_to_net)
+ buf_append_buffer (buf_to_net, buf_from_primary);
+ else
+ /* (Sys?)log this? */;
+
+ }
+
+ if (status == -1 /* EOF */)
+ {
+ buf_shutdown (buf_from_primary);
+ buf_from_primary = NULL;
+ from_primary_fd = -1;
+ }
+ else if (status > 0 /* ERRNO */)
+ {
+ buf_output0 (buf_to_net,
+ "E buf_input_data failed reading from primary\n");
+ print_error (status);
+ exit (EXIT_FAILURE);
+ }
+
+ /* If our "source pipe" is closed and all data has been sent, avoid
+ * selecting it for writability, but don't actually close the buffer in
+ * case other routines want to use it later. The buffer will be closed
+ * in server_cleanup ().
+ */
+ if (from_primary_fd < 0
+ && buf_to_net && buf_empty_p (buf_to_net))
+ to_net_fd = -1;
+
+ if (buf_to_primary
+ && (/* Assume that there is no further reason to keep the buffer to
+ * the primary open if we can no longer read its responses.
+ */
+ (from_primary_fd < 0 && buf_to_primary)
+ /* Also close buf_to_primary when it becomes impossible to find
+ * more data to send to it. We don't close buf_from_primary
+ * yet since there may be data pending or the primary may react
+ * to the EOF on its input pipe.
+ */
+ || (from_net_fd < 0 && buf_empty_p (buf_to_primary))))
+ {
+ buf_shutdown (buf_to_primary);
+ buf_free (buf_to_primary);
+ buf_to_primary = NULL;
+
+ /* Setting the fd < 0 with from_primary_fd already < 0 will cause
+ * an escape from this while loop.
+ */
+ to_primary_fd = -1;
+ }
+ }
+
+ /* Call postsecondary script. */
+ pre = false;
+ Parse_Info (CVSROOTADM_POSTPROXY, current_parsed_root->directory,
+ prepost_proxy_proc, PIOPT_ALL, &pre);
+}
+# endif /* PROXY_SUPPORT */
+
+
+
+struct notify_note {
+ /* Directory in which this notification happens. xmalloc'd*/
+ char *dir;
+
+ /* xmalloc'd. */
+ char *update_dir;
+
+ /* xmalloc'd. */
+ char *filename;
+
+ /* The following three all in one xmalloc'd block, pointed to by TYPE.
+ Each '\0' terminated. */
+ /* "E" or "U". */
+ char *type;
+ /* time+host+dir */
+ char *val;
+ char *watches;
+
+ struct notify_note *next;
+};
+
+static struct notify_note *notify_list;
+/* Used while building list, to point to the last node that already exists. */
+static struct notify_note *last_node;
+
+static void
+serve_notify (char *arg)
+{
+ struct notify_note *new = NULL;
+ char *data = NULL;
+ int status;
+
+ if (error_pending ()) return;
+
+ if (isProxyServer())
+ {
+# ifdef PROXY_SUPPORT
+ if (!proxy_log)
+ {
+# endif /* PROXY_SUPPORT */
+ if (alloc_pending (160) + strlen (program_name))
+ sprintf (pending_error_text,
+"E This CVS server does not support disconnected `%s edit'. For now, remove all `%s' files in your workspace and try your command again.",
+ program_name, CVSADM_NOTIFY);
+ return;
+# ifdef PROXY_SUPPORT
+ }
+ else
+ {
+ /* This is effectively a write command, so run it on the primary. */
+ become_proxy ();
+ exit (EXIT_SUCCESS);
+ }
+# endif /* PROXY_SUPPORT */
+ }
+
+ if (outside_dir (arg))
+ return;
+
+ if (gDirname == NULL)
+ goto error;
+
+ new = xmalloc (sizeof (struct notify_note));
+ if (new == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ new->dir = xmalloc (strlen (gDirname) + 1);
+ new->update_dir = xmalloc (strlen (gupdate_dir) + 1);
+ new->filename = xmalloc (strlen (arg) + 1);
+ if (new->dir == NULL || new->update_dir == NULL || new->filename == NULL)
+ {
+ pending_error = ENOMEM;
+ if (new->dir != NULL)
+ free (new->dir);
+ free (new);
+ return;
+ }
+ strcpy (new->dir, gDirname);
+ strcpy (new->update_dir, gupdate_dir);
+ strcpy (new->filename, arg);
+
+ status = buf_read_line (buf_from_net, &data, NULL);
+ if (status != 0)
+ {
+ if (status == -2)
+ pending_error = ENOMEM;
+ else
+ {
+ pending_error_text = xmalloc (80 + strlen (arg));
+ if (pending_error_text == NULL)
+ pending_error = ENOMEM;
+ else
+ {
+ if (status == -1)
+ sprintf (pending_error_text,
+ "E end of file reading notification for %s", arg);
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading notification for %s", arg);
+ pending_error = status;
+ }
+ }
+ }
+ free (new->filename);
+ free (new->dir);
+ free (new);
+ }
+ else
+ {
+ char *cp;
+
+ if (!data[0])
+ goto error;
+
+ if (strchr (data, '+'))
+ goto error;
+
+ new->type = data;
+ if (data[1] != '\t')
+ goto error;
+ data[1] = '\0';
+ cp = data + 2;
+ new->val = cp;
+ cp = strchr (cp, '\t');
+ if (cp == NULL)
+ goto error;
+ *cp++ = '+';
+ cp = strchr (cp, '\t');
+ if (cp == NULL)
+ goto error;
+ *cp++ = '+';
+ cp = strchr (cp, '\t');
+ if (cp == NULL)
+ goto error;
+ *cp++ = '\0';
+ new->watches = cp;
+ /* If there is another tab, ignore everything after it,
+ for future expansion. */
+ cp = strchr (cp, '\t');
+ if (cp != NULL)
+ *cp = '\0';
+
+ new->next = NULL;
+
+ if (last_node == NULL)
+ notify_list = new;
+ else
+ last_node->next = new;
+ last_node = new;
+ }
+ return;
+ error:
+ pending_error = 0;
+ if (alloc_pending (80))
+ strcpy (pending_error_text,
+ "E Protocol error; misformed Notify request");
+ if (data != NULL)
+ free (data);
+ if (new != NULL)
+ {
+ free (new->filename);
+ free (new->update_dir);
+ free (new->dir);
+ free (new);
+ }
+ return;
+}
+
+
+
+static void
+serve_hostname (char *arg)
+{
+ free (hostname);
+ hostname = xstrdup (arg);
+ return;
+}
+
+
+
+static void
+serve_localdir (char *arg)
+{
+ if (CurDir) free (CurDir);
+ CurDir = xstrdup (arg);
+}
+
+
+
+/* Process all the Notify requests that we have stored up. Returns 0
+ if successful, if not prints error message (via error()) and
+ returns negative value. */
+static int
+server_notify (void)
+{
+ struct notify_note *p;
+ char *repos;
+
+ TRACE (TRACE_FUNCTION, "server_notify()");
+
+ while (notify_list != NULL)
+ {
+ if (CVS_CHDIR (notify_list->dir) < 0)
+ {
+ error (0, errno, "cannot change to %s", notify_list->dir);
+ return -1;
+ }
+ repos = Name_Repository (NULL, NULL);
+
+ lock_dir_for_write (repos);
+
+ fileattr_startdir (repos);
+
+ notify_do (*notify_list->type, notify_list->filename,
+ notify_list->update_dir, getcaller(), notify_list->val,
+ notify_list->watches, repos);
+
+ buf_output0 (buf_to_net, "Notified ");
+ {
+ char *dir = notify_list->dir + strlen (server_temp_dir) + 1;
+ if (dir[0] == '\0')
+ buf_append_char (buf_to_net, '.');
+ else
+ buf_output0 (buf_to_net, dir);
+ buf_append_char (buf_to_net, '/');
+ buf_append_char (buf_to_net, '\n');
+ }
+ buf_output0 (buf_to_net, repos);
+ buf_append_char (buf_to_net, '/');
+ buf_output0 (buf_to_net, notify_list->filename);
+ buf_append_char (buf_to_net, '\n');
+ free (repos);
+
+ p = notify_list->next;
+ free (notify_list->filename);
+ free (notify_list->dir);
+ free (notify_list->type);
+ free (notify_list);
+ notify_list = p;
+
+ fileattr_write ();
+ fileattr_free ();
+
+ Lock_Cleanup ();
+ }
+
+ last_node = NULL;
+
+ /* The code used to call fflush (stdout) here, but that is no
+ longer necessary. The data is now buffered in buf_to_net,
+ which will be flushed by the caller, do_cvs_command. */
+
+ return 0;
+}
+
+
+
+/* This request is processed in all passes since requests which must
+ * sometimes be processed before it is known whether we are running as a
+ * secondary or not, for instance the `expand-modules' request, sometimes use
+ * the `Arguments'.
+ */
+static void
+serve_argument (char *arg)
+{
+ char *p;
+
+ if (error_pending()) return;
+
+ if (argument_count >= 10000)
+ {
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E Protocol error: too many arguments");
+ return;
+ }
+
+ if (argument_vector_size <= argument_count)
+ {
+ argument_vector_size *= 2;
+ argument_vector = xnrealloc (argument_vector,
+ argument_vector_size, sizeof (char *));
+ if (argument_vector == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ }
+ p = xmalloc (strlen (arg) + 1);
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (p, arg);
+ argument_vector[argument_count++] = p;
+}
+
+
+
+/* For secondary servers, this is handled in all passes, as is the `Argument'
+ * request, and for the same reasons.
+ */
+static void
+serve_argumentx (char *arg)
+{
+ char *p;
+
+ if (error_pending()) return;
+
+ if (argument_count <= 1)
+ {
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+"E Protocol error: called argumentx without prior call to argument");
+ return;
+ }
+
+ p = argument_vector[argument_count - 1];
+ p = xrealloc (p, strlen (p) + 1 + strlen (arg) + 1);
+ if (p == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcat (p, "\n");
+ strcat (p, arg);
+ argument_vector[argument_count - 1] = p;
+}
+
+
+
+static void
+serve_global_option (char *arg)
+{
+# ifdef PROXY_SUPPORT
+ /* This can generate error messages and termination before `Root' requests,
+ * so it must be dealt with in the first pass.
+ */
+ if (reprocessing) return;
+# endif /* PROXY_SUPPORT */
+
+ if (arg[0] != '-' || arg[1] == '\0' || arg[2] != '\0')
+ {
+ error_return:
+ if (alloc_pending (strlen (arg) + 80))
+ sprintf (pending_error_text,
+ "E Protocol error: bad global option %s",
+ arg);
+ return;
+ }
+ switch (arg[1])
+ {
+ case 'l':
+ error(0, 0, "WARNING: global `-l' option ignored.");
+ break;
+ case 'n':
+ noexec = 1;
+ logoff = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ cvswrite = 0;
+ break;
+ case 'Q':
+ really_quiet = 1;
+ break;
+ case 't':
+ trace++;
+ break;
+ default:
+ goto error_return;
+ }
+}
+
+
+
+/* This needs to be processed before Root requests, so we allow it to be
+ * be processed before knowing whether we are running as a secondary server
+ * to allow `noop' and `Root' requests to generate errors as before.
+ */
+static void
+serve_set (char *arg)
+{
+# ifdef PROXY_SUPPORT
+ if (reprocessing) return;
+# endif /* PROXY_SUPPORT */
+
+ /* FIXME: This sends errors immediately (I think); they should be
+ put into pending_error. */
+ variable_set (arg);
+}
+
+# ifdef ENCRYPTION
+
+# ifdef HAVE_KERBEROS
+
+static void
+serve_kerberos_encrypt( char *arg )
+{
+# ifdef PROXY_SUPPORT
+ assert (!proxy_log);
+# endif /* PROXY_SUPPORT */
+
+ /* All future communication with the client will be encrypted. */
+
+ buf_to_net = krb_encrypt_buffer_initialize (buf_to_net, 0, sched,
+ kblock,
+ buf_to_net->memory_error);
+ buf_from_net = krb_encrypt_buffer_initialize (buf_from_net, 1, sched,
+ kblock,
+ buf_from_net->memory_error);
+}
+
+# endif /* HAVE_KERBEROS */
+
+# ifdef HAVE_GSSAPI
+
+static void
+serve_gssapi_encrypt( char *arg )
+{
+# ifdef PROXY_SUPPORT
+ assert (!proxy_log);
+# endif /* PROXY_SUPPORT */
+
+ if (cvs_gssapi_wrapping)
+ {
+ /* We're already using a gssapi_wrap buffer for stream
+ authentication. Flush everything we've output so far, and
+ turn on encryption for future data. On the input side, we
+ should only have unwrapped as far as the Gssapi-encrypt
+ command, so future unwrapping will become encrypted. */
+ buf_flush (buf_to_net, 1);
+ cvs_gssapi_encrypt = 1;
+ return;
+ }
+
+ /* All future communication with the client will be encrypted. */
+
+ cvs_gssapi_encrypt = 1;
+
+ buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0,
+ gcontext,
+ buf_to_net->memory_error);
+ buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1,
+ gcontext,
+ buf_from_net->memory_error);
+
+ cvs_gssapi_wrapping = 1;
+}
+
+# endif /* HAVE_GSSAPI */
+
+# endif /* ENCRYPTION */
+
+# ifdef HAVE_GSSAPI
+
+static void
+serve_gssapi_authenticate (char *arg)
+{
+# ifdef PROXY_SUPPORT
+ assert (!proxy_log);
+# endif /* PROXY_SUPPORT */
+
+ if (cvs_gssapi_wrapping)
+ {
+ /* We're already using a gssapi_wrap buffer for encryption.
+ That includes authentication, so we don't have to do
+ anything further. */
+ return;
+ }
+
+ buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0,
+ gcontext,
+ buf_to_net->memory_error);
+ buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1,
+ gcontext,
+ buf_from_net->memory_error);
+
+ cvs_gssapi_wrapping = 1;
+}
+
+# endif /* HAVE_GSSAPI */
+
+
+
+# ifdef SERVER_FLOWCONTROL
+/* The maximum we'll queue to the remote client before blocking. */
+# ifndef SERVER_HI_WATER
+# define SERVER_HI_WATER (2 * 1024 * 1024)
+# endif /* SERVER_HI_WATER */
+/* When the buffer drops to this, we restart the child */
+# ifndef SERVER_LO_WATER
+# define SERVER_LO_WATER (1 * 1024 * 1024)
+# endif /* SERVER_LO_WATER */
+# endif /* SERVER_FLOWCONTROL */
+
+
+
+static void
+serve_questionable (char *arg)
+{
+ static int initted;
+
+# ifdef PROXY_SUPPORT
+ if (proxy_log) return;
+# endif /* PROXY_SUPPORT */
+
+ if (error_pending ()) return;
+
+ if (!initted)
+ {
+ /* Pick up ignores from CVSROOTADM_IGNORE, $HOME/.cvsignore on server,
+ and CVSIGNORE on server. */
+ ign_setup ();
+ initted = 1;
+ }
+
+ if (gDirname == NULL)
+ {
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+"E Protocol error: `Directory' missing");
+ return;
+ }
+
+ if (outside_dir (arg))
+ return;
+
+ if (!ign_name (arg))
+ {
+ char *update_dir;
+
+ buf_output (buf_to_net, "M ? ", 4);
+ update_dir = gDirname + strlen (server_temp_dir) + 1;
+ if (!(update_dir[0] == '.' && update_dir[1] == '\0'))
+ {
+ buf_output0 (buf_to_net, update_dir);
+ buf_output (buf_to_net, "/", 1);
+ }
+ buf_output0 (buf_to_net, arg);
+ buf_output (buf_to_net, "\n", 1);
+ }
+}
+
+
+
+static struct buffer *protocol = NULL;
+
+/* This is the output which we are saving up to send to the server, in the
+ child process. We will push it through, via the `protocol' buffer, when
+ we have a complete line. */
+static struct buffer *saved_output;
+
+/* Likewise, but stuff which will go to stderr. */
+static struct buffer *saved_outerr;
+
+
+
+static void
+protocol_memory_error (struct buffer *buf)
+{
+ error (1, ENOMEM, "Virtual memory exhausted");
+}
+
+
+
+/* If command is valid, return 1.
+ * Else if command is invalid and croak_on_invalid is set, then die.
+ * Else just return 0 to indicate that command is invalid.
+ */
+static bool
+check_command_valid_p (char *cmd_name)
+{
+ /* Right now, only pserver notices invalid commands -- namely,
+ * write attempts by a read-only user. Therefore, if CVS_Username
+ * is not set, this just returns 1, because CVS_Username unset
+ * means pserver is not active.
+ */
+# ifdef AUTH_SERVER_SUPPORT
+ if (CVS_Username == NULL)
+ return true;
+
+ if (lookup_command_attribute (cmd_name) & CVS_CMD_MODIFIES_REPOSITORY)
+ {
+ /* This command has the potential to modify the repository, so
+ * we check if the user have permission to do that.
+ *
+ * (Only relevant for remote users -- local users can do
+ * whatever normal Unix file permissions allow them to do.)
+ *
+ * The decision method:
+ *
+ * If $CVSROOT/CVSADMROOT_READERS exists and user is listed
+ * in it, then read-only access for user.
+ *
+ * Or if $CVSROOT/CVSADMROOT_WRITERS exists and user NOT
+ * listed in it, then also read-only access for user.
+ *
+ * Else read-write access for user.
+ */
+
+ char *linebuf = NULL;
+ int num_red = 0;
+ size_t linebuf_len = 0;
+ char *fname;
+ size_t flen;
+ FILE *fp;
+ int found_it = 0;
+
+ /* else */
+ flen = strlen (current_parsed_root->directory)
+ + strlen (CVSROOTADM)
+ + strlen (CVSROOTADM_READERS)
+ + 3;
+
+ fname = xmalloc (flen);
+ (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_READERS);
+
+ fp = fopen (fname, "r");
+
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ {
+ /* Need to deny access, so that attackers can't fool
+ us with some sort of denial of service attack. */
+ error (0, errno, "cannot open %s", fname);
+ free (fname);
+ return false;
+ }
+ }
+ else /* successfully opened readers file */
+ {
+ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ /* Hmmm, is it worth importing my own readline
+ library into CVS? It takes care of chopping
+ leading and trailing whitespace, "#" comments, and
+ newlines automatically when so requested. Would
+ save some code here... -kff */
+
+ /* Chop newline by hand, for strcmp()'s sake. */
+ if (num_red > 0 && linebuf[num_red - 1] == '\n')
+ linebuf[num_red - 1] = '\0';
+
+ if (strcmp (linebuf, CVS_Username) == 0)
+ goto handle_invalid;
+ }
+ if (num_red < 0 && !feof (fp))
+ error (0, errno, "cannot read %s", fname);
+
+ /* If not listed specifically as a reader, then this user
+ has write access by default unless writers are also
+ specified in a file . */
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", fname);
+ }
+ free (fname);
+
+ /* Now check the writers file. */
+
+ flen = strlen (current_parsed_root->directory)
+ + strlen (CVSROOTADM)
+ + strlen (CVSROOTADM_WRITERS)
+ + 3;
+
+ fname = xmalloc (flen);
+ (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_WRITERS);
+
+ fp = fopen (fname, "r");
+
+ if (fp == NULL)
+ {
+ if (linebuf)
+ free (linebuf);
+ if (existence_error (errno))
+ {
+ /* Writers file does not exist, so everyone is a writer,
+ by default. */
+ free (fname);
+ return true;
+ }
+ else
+ {
+ /* Need to deny access, so that attackers can't fool
+ us with some sort of denial of service attack. */
+ error (0, errno, "cannot read %s", fname);
+ free (fname);
+ return false;
+ }
+ }
+
+ found_it = 0;
+ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ /* Chop newline by hand, for strcmp()'s sake. */
+ if (num_red > 0 && linebuf[num_red - 1] == '\n')
+ linebuf[num_red - 1] = '\0';
+
+ if (strcmp (linebuf, CVS_Username) == 0)
+ {
+ found_it = 1;
+ break;
+ }
+ }
+ if (num_red < 0 && !feof (fp))
+ error (0, errno, "cannot read %s", fname);
+
+ if (found_it)
+ {
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", fname);
+ if (linebuf)
+ free (linebuf);
+ free (fname);
+ return true;
+ }
+ else /* writers file exists, but this user not listed in it */
+ {
+ handle_invalid:
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", fname);
+ if (linebuf)
+ free (linebuf);
+ free (fname);
+ return false;
+ }
+ }
+# endif /* AUTH_SERVER_SUPPORT */
+
+ /* If ever reach end of this function, command must be valid. */
+ return true;
+}
+
+
+
+/* Execute COMMAND in a subprocess with the approriate funky things done. */
+
+static struct fd_set_wrapper { fd_set fds; } command_fds_to_drain;
+# ifdef SUNOS_KLUDGE
+static int max_command_fd;
+# endif
+
+# ifdef SERVER_FLOWCONTROL
+static int flowcontrol_pipe[2];
+# endif /* SERVER_FLOWCONTROL */
+
+
+
+/*
+ * Set buffer FD to non-blocking I/O. Returns 0 for success or errno
+ * code.
+ */
+int
+set_nonblock_fd (int fd)
+{
+# if defined (F_GETFL) && defined (O_NONBLOCK) && defined (F_SETFL)
+ int flags;
+
+ flags = fcntl (fd, F_GETFL, 0);
+ if (flags < 0)
+ return errno;
+ if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
+ return errno;
+# endif /* F_GETFL && O_NONBLOCK && F_SETFL */
+ return 0;
+}
+
+
+
+static void
+do_cvs_command (char *cmd_name, int (*command) (int, char **))
+{
+ /*
+ * The following file descriptors are set to -1 if that file is not
+ * currently open.
+ */
+
+ /* Data on these pipes is a series of '\n'-terminated lines. */
+ int stdout_pipe[2];
+ int stderr_pipe[2];
+
+ /*
+ * Data on this pipe is a series of counted (see buf_send_counted)
+ * packets. Each packet must be processed atomically (i.e. not
+ * interleaved with data from stdout_pipe or stderr_pipe).
+ */
+ int protocol_pipe[2];
+
+ int dev_null_fd = -1;
+
+ int errs;
+
+ TRACE (TRACE_FUNCTION, "do_cvs_command (%s)", cmd_name);
+
+ /* Write proxy logging is always terminated when a command is received.
+ * Therefore, we wish to avoid reprocessing the command since that would
+ * cause endless recursion.
+ */
+ if (isProxyServer())
+ {
+# ifdef PROXY_SUPPORT
+ if (reprocessing)
+ /* This must be the second time we've reached this point.
+ * Done reprocessing.
+ */
+ reprocessing = false;
+ else
+ {
+ if (lookup_command_attribute (cmd_name)
+ & CVS_CMD_MODIFIES_REPOSITORY)
+ {
+ become_proxy ();
+ exit (EXIT_SUCCESS);
+ }
+ else if (/* serve_co may have called this already and missing logs
+ * should have generated an error in serve_root().
+ */
+ proxy_log)
+ {
+ /* Set up the log for reprocessing. */
+ rewind_buf_from_net ();
+ /* And return to the main loop in server(), where we will now
+ * find the logged secondary data and reread it.
+ */
+ return;
+ }
+ }
+# else /* !PROXY_SUPPORT */
+ if (lookup_command_attribute (cmd_name)
+ & CVS_CMD_MODIFIES_REPOSITORY
+ && alloc_pending (120))
+ sprintf (pending_error_text,
+"E You need a CVS client that supports the `Redirect' response for write requests to this server.");
+ return;
+# endif /* PROXY_SUPPORT */
+ }
+
+ command_pid = -1;
+ stdout_pipe[0] = -1;
+ stdout_pipe[1] = -1;
+ stderr_pipe[0] = -1;
+ stderr_pipe[1] = -1;
+ protocol_pipe[0] = -1;
+ protocol_pipe[1] = -1;
+
+ server_write_entries ();
+
+ if (print_pending_error ())
+ goto free_args_and_return;
+
+ /* Global `cvs_cmd_name' is probably "server" right now -- only
+ serve_export() sets it to anything else. So we will use local
+ parameter `cmd_name' to determine if this command is valid for
+ this user. */
+ if (!check_command_valid_p (cmd_name))
+ {
+ buf_output0 (buf_to_net, "E ");
+ buf_output0 (buf_to_net, program_name);
+ buf_output0 (buf_to_net, " [server aborted]: \"");
+ buf_output0 (buf_to_net, cmd_name);
+ buf_output0 (buf_to_net,
+"\" requires write access to the repository\n\
+error \n");
+ goto free_args_and_return;
+ }
+ cvs_cmd_name = cmd_name;
+
+ (void) server_notify ();
+
+ /*
+ * We use a child process which actually does the operation. This
+ * is so we can intercept its standard output. Even if all of CVS
+ * were written to go to some special routine instead of writing
+ * to stdout or stderr, we would still need to do the same thing
+ * for the RCS commands.
+ */
+
+ if (pipe (stdout_pipe) < 0)
+ {
+ buf_output0 (buf_to_net, "E pipe failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ if (pipe (stderr_pipe) < 0)
+ {
+ buf_output0 (buf_to_net, "E pipe failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ if (pipe (protocol_pipe) < 0)
+ {
+ buf_output0 (buf_to_net, "E pipe failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+# ifdef SERVER_FLOWCONTROL
+ if (pipe (flowcontrol_pipe) < 0)
+ {
+ buf_output0 (buf_to_net, "E pipe failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ set_nonblock_fd (flowcontrol_pipe[0]);
+ set_nonblock_fd (flowcontrol_pipe[1]);
+# endif /* SERVER_FLOWCONTROL */
+
+ dev_null_fd = CVS_OPEN (DEVNULL, O_RDONLY);
+ if (dev_null_fd < 0)
+ {
+ buf_output0 (buf_to_net, "E open /dev/null failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+
+ /* We shouldn't have any partial lines from cvs_output and
+ cvs_outerr, but we handle them here in case there is a bug. */
+ /* FIXME: appending a newline, rather than using "MT" as we
+ do in the child process, is probably not really a very good
+ way to "handle" them. */
+ if (! buf_empty_p (saved_output))
+ {
+ buf_append_char (saved_output, '\n');
+ buf_copy_lines (buf_to_net, saved_output, 'M');
+ }
+ if (! buf_empty_p (saved_outerr))
+ {
+ buf_append_char (saved_outerr, '\n');
+ buf_copy_lines (buf_to_net, saved_outerr, 'E');
+ }
+
+ /* Flush out any pending data. */
+ buf_flush (buf_to_net, 1);
+
+ /* Don't use vfork; we're not going to exec(). */
+ command_pid = fork ();
+ if (command_pid < 0)
+ {
+ buf_output0 (buf_to_net, "E fork failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ if (command_pid == 0)
+ {
+ int exitstatus;
+
+ /* Since we're in the child, and the parent is going to take
+ care of packaging up our error messages, we can clear this
+ flag. */
+ error_use_protocol = 0;
+
+ protocol = fd_buffer_initialize (protocol_pipe[1], 0, NULL, false,
+ protocol_memory_error);
+
+ /* At this point we should no longer be using buf_to_net and
+ buf_from_net. Instead, everything should go through
+ protocol. */
+ if (buf_to_net != NULL)
+ {
+ buf_free (buf_to_net);
+ buf_to_net = NULL;
+ }
+ if (buf_from_net != NULL)
+ {
+ buf_free (buf_from_net);
+ buf_from_net = NULL;
+ }
+
+ /* These were originally set up to use outbuf_memory_error.
+ Since we're now in the child, we should use the simpler
+ protocol_memory_error function. */
+ saved_output->memory_error = protocol_memory_error;
+ saved_outerr->memory_error = protocol_memory_error;
+
+ if (dup2 (dev_null_fd, STDIN_FILENO) < 0)
+ error (1, errno, "can't set up pipes");
+ if (dup2 (stdout_pipe[1], STDOUT_FILENO) < 0)
+ error (1, errno, "can't set up pipes");
+ if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
+ error (1, errno, "can't set up pipes");
+ close (dev_null_fd);
+ close (stdout_pipe[0]);
+ close (stdout_pipe[1]);
+ close (stderr_pipe[0]);
+ close (stderr_pipe[1]);
+ close (protocol_pipe[0]);
+ close_on_exec (protocol_pipe[1]);
+# ifdef SERVER_FLOWCONTROL
+ close_on_exec (flowcontrol_pipe[0]);
+ close (flowcontrol_pipe[1]);
+# endif /* SERVER_FLOWCONTROL */
+
+ /*
+ * Set this in .bashrc if you want to give yourself time to attach
+ * to the subprocess with a debugger.
+ */
+ if (getenv ("CVS_SERVER_SLEEP"))
+ {
+ int secs = atoi (getenv ("CVS_SERVER_SLEEP"));
+ TRACE (TRACE_DATA, "Sleeping CVS_SERVER_SLEEP (%d) seconds", secs);
+ sleep (secs);
+ }
+ else
+ TRACE (TRACE_DATA, "CVS_SERVER_SLEEP not set.");
+
+ exitstatus = (*command) (argument_count, argument_vector);
+
+ /* Output any partial lines. If the client doesn't support
+ "MT", we go ahead and just tack on a newline since the
+ protocol doesn't support anything better. */
+ if (! buf_empty_p (saved_output))
+ {
+ buf_output0 (protocol, supported_response ("MT") ? "MT text " : "M ");
+ buf_append_buffer (protocol, saved_output);
+ buf_output (protocol, "\n", 1);
+ buf_send_counted (protocol);
+ }
+ /* For now we just discard partial lines on stderr. I suspect
+ that CVS can't write such lines unless there is a bug. */
+
+ buf_free (protocol);
+
+ /* Close the pipes explicitly in order to send an EOF to the parent,
+ * then wait for the parent to close the flow control pipe. This
+ * avoids a race condition where a child which dumped more than the
+ * high water mark into the pipes could complete its job and exit,
+ * leaving the parent process to attempt to write a stop byte to the
+ * closed flow control pipe, which earned the parent a SIGPIPE, which
+ * it normally only expects on the network pipe and that causes it to
+ * exit with an error message, rather than the SIGCHILD that it knows
+ * how to handle correctly.
+ */
+ /* Let exit() close STDIN - it's from /dev/null anyhow. */
+ fclose (stderr);
+ fclose (stdout);
+ close (protocol_pipe[1]);
+# ifdef SERVER_FLOWCONTROL
+ {
+ char junk;
+ ssize_t status;
+ while ((status = read (flowcontrol_pipe[0], &junk, 1)) > 0
+ || (status == -1 && errno == EAGAIN));
+ }
+ /* FIXME: No point in printing an error message with error(),
+ * as STDERR is already closed, but perhaps this could be syslogged?
+ */
+# endif
+
+ exit (exitstatus);
+ }
+
+ /* OK, sit around getting all the input from the child. */
+ {
+ struct buffer *stdoutbuf;
+ struct buffer *stderrbuf;
+ struct buffer *protocol_inbuf;
+ /* Number of file descriptors to check in select (). */
+ int num_to_check;
+ int count_needed = 1;
+# ifdef SERVER_FLOWCONTROL
+ int have_flowcontrolled = 0;
+# endif /* SERVER_FLOWCONTROL */
+
+ FD_ZERO (&command_fds_to_drain.fds);
+ num_to_check = stdout_pipe[0];
+ FD_SET (stdout_pipe[0], &command_fds_to_drain.fds);
+ num_to_check = MAX (num_to_check, stderr_pipe[0]);
+ FD_SET (stderr_pipe[0], &command_fds_to_drain.fds);
+ num_to_check = MAX (num_to_check, protocol_pipe[0]);
+ FD_SET (protocol_pipe[0], &command_fds_to_drain.fds);
+ num_to_check = MAX (num_to_check, STDOUT_FILENO);
+# ifdef SUNOS_KLUDGE
+ max_command_fd = num_to_check;
+# endif
+ /*
+ * File descriptors are numbered from 0, so num_to_check needs to
+ * be one larger than the largest descriptor.
+ */
+ ++num_to_check;
+ if (num_to_check > FD_SETSIZE)
+ {
+ buf_output0 (buf_to_net,
+ "E internal error: FD_SETSIZE not big enough.\n\
+error \n");
+ goto error_exit;
+ }
+
+ stdoutbuf = fd_buffer_initialize (stdout_pipe[0], 0, NULL, true,
+ input_memory_error);
+
+ stderrbuf = fd_buffer_initialize (stderr_pipe[0], 0, NULL, true,
+ input_memory_error);
+
+ protocol_inbuf = fd_buffer_initialize (protocol_pipe[0], 0, NULL, true,
+ input_memory_error);
+
+ set_nonblock (buf_to_net);
+ set_nonblock (stdoutbuf);
+ set_nonblock (stderrbuf);
+ set_nonblock (protocol_inbuf);
+
+ if (close (stdout_pipe[1]) < 0)
+ {
+ buf_output0 (buf_to_net, "E close failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ stdout_pipe[1] = -1;
+
+ if (close (stderr_pipe[1]) < 0)
+ {
+ buf_output0 (buf_to_net, "E close failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ stderr_pipe[1] = -1;
+
+ if (close (protocol_pipe[1]) < 0)
+ {
+ buf_output0 (buf_to_net, "E close failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ protocol_pipe[1] = -1;
+
+# ifdef SERVER_FLOWCONTROL
+ if (close (flowcontrol_pipe[0]) < 0)
+ {
+ buf_output0 (buf_to_net, "E close failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ flowcontrol_pipe[0] = -1;
+# endif /* SERVER_FLOWCONTROL */
+
+ if (close (dev_null_fd) < 0)
+ {
+ buf_output0 (buf_to_net, "E close failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ dev_null_fd = -1;
+
+ while (stdout_pipe[0] >= 0
+ || stderr_pipe[0] >= 0
+ || protocol_pipe[0] >= 0
+ || count_needed <= 0)
+ {
+ fd_set readfds;
+ fd_set writefds;
+ int numfds;
+ struct timeval *timeout_ptr;
+ struct timeval timeout;
+# ifdef SERVER_FLOWCONTROL
+ int bufmemsize;
+
+ /*
+ * See if we are swamping the remote client and filling our VM.
+ * Tell child to hold off if we do.
+ */
+ bufmemsize = buf_count_mem (buf_to_net);
+ if (!have_flowcontrolled && (bufmemsize > SERVER_HI_WATER))
+ {
+ if (write(flowcontrol_pipe[1], "S", 1) == 1)
+ have_flowcontrolled = 1;
+ }
+ else if (have_flowcontrolled && (bufmemsize < SERVER_LO_WATER))
+ {
+ if (write(flowcontrol_pipe[1], "G", 1) == 1)
+ have_flowcontrolled = 0;
+ }
+# endif /* SERVER_FLOWCONTROL */
+
+ FD_ZERO (&readfds);
+ FD_ZERO (&writefds);
+
+ if (count_needed <= 0)
+ {
+ /* there is data pending which was read from the protocol pipe
+ * so don't block if we don't find any data
+ */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ timeout_ptr = &timeout;
+ }
+ else
+ {
+ /* block indefinately */
+ timeout_ptr = NULL;
+ }
+
+ if (! buf_empty_p (buf_to_net))
+ FD_SET (STDOUT_FILENO, &writefds);
+
+ if (stdout_pipe[0] >= 0)
+ {
+ FD_SET (stdout_pipe[0], &readfds);
+ }
+ if (stderr_pipe[0] >= 0)
+ {
+ FD_SET (stderr_pipe[0], &readfds);
+ }
+ if (protocol_pipe[0] >= 0)
+ {
+ FD_SET (protocol_pipe[0], &readfds);
+ }
+
+ /* This process of selecting on the three pipes means that
+ we might not get output in the same order in which it
+ was written, thus producing the well-known
+ "out-of-order" bug. If the child process uses
+ cvs_output and cvs_outerr, it will send everything on
+ the protocol_pipe and avoid this problem, so the
+ solution is to use cvs_output and cvs_outerr in the
+ child process. */
+ do {
+ /* This used to select on exceptions too, but as far
+ as I know there was never any reason to do that and
+ SCO doesn't let you select on exceptions on pipes. */
+ numfds = select (num_to_check, &readfds, &writefds,
+ NULL, timeout_ptr);
+ if (numfds < 0
+ && errno != EINTR)
+ {
+ buf_output0 (buf_to_net, "E select failed\n");
+ print_error (errno);
+ goto error_exit;
+ }
+ } while (numfds < 0);
+
+ if (numfds == 0)
+ {
+ FD_ZERO (&readfds);
+ FD_ZERO (&writefds);
+ }
+
+ if (FD_ISSET (STDOUT_FILENO, &writefds))
+ {
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ }
+
+ if (protocol_pipe[0] >= 0
+ && (FD_ISSET (protocol_pipe[0], &readfds)))
+ {
+ int status;
+ size_t count_read;
+
+ status = buf_input_data (protocol_inbuf, &count_read);
+
+ if (status == -1)
+ {
+ close (protocol_pipe[0]);
+ protocol_pipe[0] = -1;
+ }
+ else if (status > 0)
+ {
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
+ print_error (status);
+ goto error_exit;
+ }
+
+ /*
+ * We only call buf_copy_counted if we have read
+ * enough bytes to make it worthwhile. This saves us
+ * from continually recounting the amount of data we
+ * have.
+ */
+ count_needed -= count_read;
+ }
+ /* this is still part of the protocol pipe procedure, but it is
+ * outside the above conditional so that unprocessed data can be
+ * left in the buffer and stderr/stdout can be read when a flush
+ * signal is received and control can return here without passing
+ * through the select code and maybe blocking
+ */
+ while (count_needed <= 0)
+ {
+ int special = 0;
+
+ count_needed = buf_copy_counted (buf_to_net,
+ protocol_inbuf,
+ &special);
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+
+ /* If SPECIAL got set to <0, it means that the child
+ * wants us to flush the pipe & maybe stderr or stdout.
+ *
+ * After that we break to read stderr & stdout again before
+ * going back to the protocol pipe
+ *
+ * Upon breaking, count_needed = 0, so the next pass will only
+ * perform a non-blocking select before returning here to finish
+ * processing data we already read from the protocol buffer
+ */
+ if (special == -1)
+ {
+ cvs_flushout();
+ break;
+ }
+ if (special == -2)
+ {
+ /* If the client supports the 'F' command, we send it. */
+ if (supported_response ("F"))
+ {
+ buf_append_char (buf_to_net, 'F');
+ buf_append_char (buf_to_net, '\n');
+ }
+ cvs_flusherr ();
+ break;
+ }
+ }
+
+ if (stdout_pipe[0] >= 0
+ && (FD_ISSET (stdout_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (stdoutbuf, NULL);
+
+ buf_copy_lines (buf_to_net, stdoutbuf, 'M');
+
+ if (status == -1)
+ {
+ close (stdout_pipe[0]);
+ stdout_pipe[0] = -1;
+ }
+ else if (status > 0)
+ {
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ }
+
+ if (stderr_pipe[0] >= 0
+ && (FD_ISSET (stderr_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (stderrbuf, NULL);
+
+ buf_copy_lines (buf_to_net, stderrbuf, 'E');
+
+ if (status == -1)
+ {
+ close (stderr_pipe[0]);
+ stderr_pipe[0] = -1;
+ }
+ else if (status > 0)
+ {
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ }
+ }
+
+ /*
+ * OK, we've gotten EOF on all the pipes. If there is
+ * anything left on stdoutbuf or stderrbuf (this could only
+ * happen if there was no trailing newline), send it over.
+ */
+ if (! buf_empty_p (stdoutbuf))
+ {
+ buf_append_char (stdoutbuf, '\n');
+ buf_copy_lines (buf_to_net, stdoutbuf, 'M');
+ }
+ if (! buf_empty_p (stderrbuf))
+ {
+ buf_append_char (stderrbuf, '\n');
+ buf_copy_lines (buf_to_net, stderrbuf, 'E');
+ }
+ if (! buf_empty_p (protocol_inbuf))
+ buf_output0 (buf_to_net,
+ "E Protocol error: uncounted data discarded\n");
+
+# ifdef SERVER_FLOWCONTROL
+ close (flowcontrol_pipe[1]);
+ flowcontrol_pipe[1] = -1;
+# endif /* SERVER_FLOWCONTROL */
+
+ errs = 0;
+
+ while (command_pid > 0)
+ {
+ int status;
+ pid_t waited_pid;
+ waited_pid = waitpid (command_pid, &status, 0);
+ if (waited_pid < 0)
+ {
+ /*
+ * Intentionally ignoring EINTR. Other errors
+ * "can't happen".
+ */
+ continue;
+ }
+
+ if (WIFEXITED (status))
+ errs += WEXITSTATUS (status);
+ else
+ {
+ int sig = WTERMSIG (status);
+ char buf[50];
+ /*
+ * This is really evil, because signals might be numbered
+ * differently on the two systems. We should be using
+ * signal names (either of the "Terminated" or the "SIGTERM"
+ * variety). But cvs doesn't currently use libiberty...we
+ * could roll our own.... FIXME.
+ */
+ buf_output0 (buf_to_net, "E Terminated with fatal signal ");
+ sprintf (buf, "%d\n", sig);
+ buf_output0 (buf_to_net, buf);
+
+ /* Test for a core dump. */
+ if (WCOREDUMP (status))
+ {
+ buf_output0 (buf_to_net, "E Core dumped; preserving ");
+ buf_output0 (buf_to_net, orig_server_temp_dir);
+ buf_output0 (buf_to_net, " on server.\n\
+E CVS locks may need cleaning up.\n");
+ dont_delete_temp = 1;
+ }
+ ++errs;
+ }
+ if (waited_pid == command_pid)
+ command_pid = -1;
+ }
+
+ /*
+ * OK, we've waited for the child. By now all CVS locks are free
+ * and it's OK to block on the network.
+ */
+ set_block (buf_to_net);
+ buf_flush (buf_to_net, 1);
+ buf_shutdown (protocol_inbuf);
+ buf_free (protocol_inbuf);
+ protocol_inbuf = NULL;
+ buf_shutdown (stderrbuf);
+ buf_free (stderrbuf);
+ stderrbuf = NULL;
+ buf_shutdown (stdoutbuf);
+ buf_free (stdoutbuf);
+ stdoutbuf = NULL;
+ }
+
+ if (errs)
+ /* We will have printed an error message already. */
+ buf_output0 (buf_to_net, "error \n");
+ else
+ buf_output0 (buf_to_net, "ok\n");
+ goto free_args_and_return;
+
+ error_exit:
+ if (command_pid > 0)
+ kill (command_pid, SIGTERM);
+
+ while (command_pid > 0)
+ {
+ pid_t waited_pid;
+ waited_pid = waitpid (command_pid, NULL, 0);
+ if (waited_pid < 0 && errno == EINTR)
+ continue;
+ if (waited_pid == command_pid)
+ command_pid = -1;
+ }
+
+ close (dev_null_fd);
+ close (protocol_pipe[0]);
+ close (protocol_pipe[1]);
+ close (stderr_pipe[0]);
+ close (stderr_pipe[1]);
+ close (stdout_pipe[0]);
+ close (stdout_pipe[1]);
+# ifdef SERVER_FLOWCONTROL
+ close (flowcontrol_pipe[0]);
+ close (flowcontrol_pipe[1]);
+# endif /* SERVER_FLOWCONTROL */
+
+ free_args_and_return:
+ /* Now free the arguments. */
+ {
+ /* argument_vector[0] is a dummy argument, we don't mess with it. */
+ char **cp;
+ for (cp = argument_vector + 1;
+ cp < argument_vector + argument_count;
+ ++cp)
+ free (*cp);
+
+ argument_count = 1;
+ }
+
+ /* Flush out any data not yet sent. */
+ set_block (buf_to_net);
+ buf_flush (buf_to_net, 1);
+
+ return;
+}
+
+
+
+# ifdef SERVER_FLOWCONTROL
+/*
+ * Called by the child at convenient points in the server's execution for
+ * the server child to block.. ie: when it has no locks active.
+ */
+void
+server_pause_check(void)
+{
+ int paused = 0;
+ char buf[1];
+
+ while (read (flowcontrol_pipe[0], buf, 1) == 1)
+ {
+ if (*buf == 'S') /* Stop */
+ paused = 1;
+ else if (*buf == 'G') /* Go */
+ paused = 0;
+ else
+ return; /* ??? */
+ }
+ while (paused) {
+ int numfds, numtocheck;
+ fd_set fds;
+
+ FD_ZERO (&fds);
+ FD_SET (flowcontrol_pipe[0], &fds);
+ numtocheck = flowcontrol_pipe[0] + 1;
+
+ do {
+ numfds = select (numtocheck, &fds, NULL, NULL, NULL);
+ if (numfds < 0
+ && errno != EINTR)
+ {
+ buf_output0 (buf_to_net, "E select failed\n");
+ print_error (errno);
+ return;
+ }
+ } while (numfds < 0);
+
+ if (FD_ISSET (flowcontrol_pipe[0], &fds))
+ {
+ int got;
+
+ while ((got = read (flowcontrol_pipe[0], buf, 1)) == 1)
+ {
+ if (*buf == 'S') /* Stop */
+ paused = 1;
+ else if (*buf == 'G') /* Go */
+ paused = 0;
+ else
+ return; /* ??? */
+ }
+
+ /* This assumes that we are using BSD or POSIX nonblocking
+ I/O. System V nonblocking I/O returns zero if there is
+ nothing to read. */
+ if (got == 0)
+ error (1, 0, "flow control EOF");
+ if (got < 0 && ! blocking_error (errno))
+ {
+ error (1, errno, "flow control read failed");
+ }
+ }
+ }
+}
+# endif /* SERVER_FLOWCONTROL */
+
+
+
+/* This variable commented in server.h. */
+char *server_dir = NULL;
+
+
+
+static void
+output_dir (const char *update_dir, const char *repository)
+{
+ /* Set up SHORT_REPOS. */
+ const char *short_repos = Short_Repository (repository);
+
+ /* Send the update_dir/repos. */
+ if (server_dir != NULL)
+ {
+ buf_output0 (protocol, server_dir);
+ buf_output0 (protocol, "/");
+ }
+ if (update_dir[0] == '\0')
+ buf_output0 (protocol, ".");
+ else
+ buf_output0 (protocol, update_dir);
+ buf_output0 (protocol, "/\n");
+ if (short_repos[0] == '\0')
+ buf_output0 (protocol, ".");
+ else
+ buf_output0 (protocol, short_repos);
+ buf_output0 (protocol, "/");
+}
+
+
+
+/*
+ * Entries line that we are squirreling away to send to the client when
+ * we are ready.
+ */
+static char *entries_line;
+
+/*
+ * File which has been Scratch_File'd, we are squirreling away that fact
+ * to inform the client when we are ready.
+ */
+static char *scratched_file;
+
+/*
+ * The scratched_file will need to be removed as well as having its entry
+ * removed.
+ */
+static int kill_scratched_file;
+
+
+
+void
+server_register (const char *name, const char *version, const char *timestamp,
+ const char *options, const char *tag, const char *date,
+ const char *conflict)
+{
+ int len;
+
+ if (options == NULL)
+ options = "";
+
+ TRACE (TRACE_FUNCTION, "server_register(%s, %s, %s, %s, %s, %s, %s)",
+ name, version, timestamp ? timestamp : "", options,
+ tag ? tag : "", date ? date : "",
+ conflict ? conflict : "");
+
+ if (entries_line != NULL)
+ {
+ /*
+ * If CVS decides to Register it more than once (which happens
+ * on "cvs update foo/foo.c" where foo and foo.c are already
+ * checked out), use the last of the entries lines Register'd.
+ */
+ free (entries_line);
+ }
+
+ /*
+ * I have reports of Scratch_Entry and Register both happening, in
+ * two different cases. Using the last one which happens is almost
+ * surely correct; I haven't tracked down why they both happen (or
+ * even verified that they are for the same file).
+ */
+ if (scratched_file != NULL)
+ {
+ free (scratched_file);
+ scratched_file = NULL;
+ }
+
+ len = (strlen (name) + strlen (version) + strlen (options) + 80);
+ if (tag)
+ len += strlen (tag);
+ if (date)
+ len += strlen (date);
+
+ entries_line = xmalloc (len);
+ sprintf (entries_line, "/%s/%s/", name, version);
+ if (conflict != NULL)
+ {
+ strcat (entries_line, "+=");
+ }
+ strcat (entries_line, "/");
+ strcat (entries_line, options);
+ strcat (entries_line, "/");
+ if (tag != NULL)
+ {
+ strcat (entries_line, "T");
+ strcat (entries_line, tag);
+ }
+ else if (date != NULL)
+ {
+ strcat (entries_line, "D");
+ strcat (entries_line, date);
+ }
+}
+
+
+
+void
+server_scratch (const char *fname)
+{
+ /*
+ * I have reports of Scratch_Entry and Register both happening, in
+ * two different cases. Using the last one which happens is almost
+ * surely correct; I haven't tracked down why they both happen (or
+ * even verified that they are for the same file).
+ *
+ * Don't know if this is what whoever wrote the above comment was
+ * talking about, but this can happen in the case where a join
+ * removes a file - the call to Register puts the '-vers' into the
+ * Entries file after the file is removed
+ */
+ if (entries_line != NULL)
+ {
+ free (entries_line);
+ entries_line = NULL;
+ }
+
+ if (scratched_file != NULL)
+ {
+ buf_output0 (protocol,
+ "E CVS server internal error: duplicate Scratch_Entry\n");
+ buf_send_counted (protocol);
+ return;
+ }
+ scratched_file = xstrdup (fname);
+ kill_scratched_file = 1;
+}
+
+
+
+void
+server_scratch_entry_only (void)
+{
+ kill_scratched_file = 0;
+}
+
+
+
+/* Print a new entries line, from a previous server_register. */
+static void
+new_entries_line (void)
+{
+ if (entries_line)
+ {
+ buf_output0 (protocol, entries_line);
+ buf_output (protocol, "\n", 1);
+ }
+ else
+ /* Return the error message as the Entries line. */
+ buf_output0 (protocol,
+ "CVS server internal error: Register missing\n");
+ free (entries_line);
+ entries_line = NULL;
+}
+
+
+
+static void
+serve_ci (char *arg)
+{
+ do_cvs_command ("commit", commit);
+}
+
+
+
+static void
+checked_in_response (const char *file, const char *update_dir,
+ const char *repository)
+{
+ if (supported_response ("Mode"))
+ {
+ struct stat sb;
+ char *mode_string;
+
+ if (stat (file, &sb) < 0)
+ {
+ /* Not clear to me why the file would fail to exist, but it
+ was happening somewhere in the testsuite. */
+ if (!existence_error (errno))
+ error (0, errno, "cannot stat %s", file);
+ }
+ else
+ {
+ buf_output0 (protocol, "Mode ");
+ mode_string = mode_to_string (sb.st_mode);
+ buf_output0 (protocol, mode_string);
+ buf_output0 (protocol, "\n");
+ free (mode_string);
+ }
+ }
+
+ buf_output0 (protocol, "Checked-in ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, file);
+ buf_output (protocol, "\n", 1);
+ new_entries_line ();
+}
+
+
+
+void
+server_checked_in (const char *file, const char *update_dir,
+ const char *repository)
+{
+ if (noexec)
+ return;
+ if (scratched_file != NULL && entries_line == NULL)
+ {
+ /*
+ * This happens if we are now doing a "cvs remove" after a previous
+ * "cvs add" (without a "cvs ci" in between).
+ */
+ buf_output0 (protocol, "Remove-entry ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, file);
+ buf_output (protocol, "\n", 1);
+ free (scratched_file);
+ scratched_file = NULL;
+ }
+ else
+ {
+ checked_in_response (file, update_dir, repository);
+ }
+ buf_send_counted (protocol);
+}
+
+
+
+void
+server_update_entries (const char *file, const char *update_dir,
+ const char *repository,
+ enum server_updated_arg4 updated)
+{
+ if (noexec)
+ return;
+ if (updated == SERVER_UPDATED)
+ checked_in_response (file, update_dir, repository);
+ else
+ {
+ if (!supported_response ("New-entry"))
+ return;
+ buf_output0 (protocol, "New-entry ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, file);
+ buf_output (protocol, "\n", 1);
+ new_entries_line ();
+ }
+
+ buf_send_counted (protocol);
+}
+
+
+
+static void
+serve_update (char *arg)
+{
+ do_cvs_command ("update", update);
+}
+
+
+
+static void
+serve_diff (char *arg)
+{
+ do_cvs_command ("diff", diff);
+}
+
+
+
+static void
+serve_log (char *arg)
+{
+ do_cvs_command ("log", cvslog);
+}
+
+
+
+static void
+serve_rlog (char *arg)
+{
+ do_cvs_command ("rlog", cvslog);
+}
+
+
+
+static void
+serve_ls (char *arg)
+{
+ do_cvs_command ("ls", ls);
+}
+
+
+
+static void
+serve_rls (char *arg)
+{
+ do_cvs_command ("rls", ls);
+}
+
+
+
+static void
+serve_add (char *arg)
+{
+ do_cvs_command ("add", add);
+}
+
+
+
+static void
+serve_remove (char *arg)
+{
+ do_cvs_command ("remove", cvsremove);
+}
+
+
+
+static void
+serve_status (char *arg)
+{
+ do_cvs_command ("status", cvsstatus);
+}
+
+
+
+static void
+serve_rdiff (char *arg)
+{
+ do_cvs_command ("rdiff", patch);
+}
+
+
+
+static void
+serve_tag (char *arg)
+{
+ do_cvs_command ("tag", cvstag);
+}
+
+
+
+static void
+serve_rtag (char *arg)
+{
+ do_cvs_command ("rtag", cvstag);
+}
+
+
+
+static void
+serve_import (char *arg)
+{
+ do_cvs_command ("import", import);
+}
+
+
+
+static void
+serve_admin (char *arg)
+{
+ do_cvs_command ("admin", admin);
+}
+
+
+
+static void
+serve_history (char *arg)
+{
+ do_cvs_command ("history", history);
+}
+
+
+
+static void
+serve_release (char *arg)
+{
+ do_cvs_command ("release", release);
+}
+
+
+
+static void
+serve_watch_on (char *arg)
+{
+ do_cvs_command ("watch", watch_on);
+}
+
+
+
+static void
+serve_watch_off (char *arg)
+{
+ do_cvs_command ("watch", watch_off);
+}
+
+
+
+static void
+serve_watch_add (char *arg)
+{
+ do_cvs_command ("watch", watch_add);
+}
+
+
+
+static void
+serve_watch_remove (char *arg)
+{
+ do_cvs_command ("watch", watch_remove);
+}
+
+
+
+static void
+serve_watchers (char *arg)
+{
+ do_cvs_command ("watchers", watchers);
+}
+
+
+
+static void
+serve_editors (char *arg)
+{
+ do_cvs_command ("editors", editors);
+}
+
+
+
+static void
+serve_edit (char *arg)
+{
+ do_cvs_command ("edit", edit);
+}
+
+
+
+# ifdef PROXY_SUPPORT
+/* We need to handle some of this before reprocessing since it is defined to
+ * send a response and print errors before a Root request is received.
+ */
+# endif /* PROXY_SUPPORT */
+static void
+serve_noop (char *arg)
+{
+ /* Errors could be encountered in the first or second passes, so always
+ * send them to the client.
+ */
+ bool pe = print_pending_error();
+
+# ifdef PROXY_SUPPORT
+ /* The portions below need not be handled until reprocessing anyhow since
+ * there should be no entries or notifications prior to that. */
+ if (!proxy_log)
+# endif /* PROXY_SUPPORT */
+ {
+ server_write_entries ();
+ if (!pe)
+ (void) server_notify ();
+ }
+
+ if (!pe
+# ifdef PROXY_SUPPORT
+ /* "ok" only goes across in the first pass. */
+ && !reprocessing
+# endif /* PROXY_SUPPORT */
+ )
+ buf_output0 (buf_to_net, "ok\n");
+ buf_flush (buf_to_net, 1);
+}
+
+
+
+static void
+serve_version (char *arg)
+{
+ do_cvs_command ("version", version);
+}
+
+
+
+static void
+serve_init (char *arg)
+{
+ cvsroot_t *saved_parsed_root;
+
+ if (!ISABSOLUTE (arg))
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E init %s must be an absolute pathname", arg);
+ }
+# ifdef AUTH_SERVER_SUPPORT
+ else if (Pserver_Repos != NULL)
+ {
+ if (strcmp (Pserver_Repos, arg) != 0)
+ {
+ if (alloc_pending (80 + strlen (Pserver_Repos) + strlen (arg)))
+ /* The explicitness is to aid people who are writing clients.
+ I don't see how this information could help an
+ attacker. */
+ sprintf (pending_error_text, "\
+E Protocol error: init says \"%s\" but pserver says \"%s\"",
+ arg, Pserver_Repos);
+ }
+ }
+# endif
+
+ if (print_pending_error ())
+ return;
+
+ saved_parsed_root = current_parsed_root;
+ current_parsed_root = local_cvsroot (arg);
+
+ do_cvs_command ("init", init);
+
+ /* Do not free CURRENT_PARSED_ROOT since it is still in the cache. */
+ current_parsed_root = saved_parsed_root;
+}
+
+
+
+static void
+serve_annotate (char *arg)
+{
+ do_cvs_command ("annotate", annotate);
+}
+
+
+
+static void
+serve_rannotate (char *arg)
+{
+ do_cvs_command ("rannotate", annotate);
+}
+
+
+
+static void
+serve_co (char *arg)
+{
+ if (print_pending_error ())
+ return;
+
+# ifdef PROXY_SUPPORT
+ /* If we are not a secondary server, the write proxy log will already have
+ * been processed.
+ */
+ if (isProxyServer ())
+ {
+ if (reprocessing)
+ reprocessing = false;
+ else if (/* The proxy log may be closed if the client sent a
+ * `Command-prep' request.
+ */
+ proxy_log)
+ {
+ /* Set up the log for reprocessing. */
+ rewind_buf_from_net ();
+ /* And return to the main loop in server(), where we will now find
+ * the logged secondary data and reread it.
+ */
+ return;
+ }
+ }
+# endif /* PROXY_SUPPORT */
+
+ /* Compensate for server_export()'s setting of cvs_cmd_name.
+ *
+ * [It probably doesn't matter if do_cvs_command() gets "export"
+ * or "checkout", but we ought to be accurate where possible.]
+ */
+ do_cvs_command (!strcmp (cvs_cmd_name, "export") ? "export" : "checkout",
+ checkout);
+}
+
+
+
+static void
+serve_export (char *arg)
+{
+ /* Tell checkout() to behave like export not checkout. */
+ cvs_cmd_name = "export";
+ serve_co (arg);
+}
+
+
+
+void
+server_copy_file (const char *file, const char *update_dir,
+ const char *repository, const char *newfile)
+{
+ /* At least for now, our practice is to have the server enforce
+ noexec for the repository and the client enforce it for the
+ working directory. This might want more thought, and/or
+ documentation in cvsclient.texi (other responses do it
+ differently). */
+
+ if (!supported_response ("Copy-file"))
+ return;
+ buf_output0 (protocol, "Copy-file ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, file);
+ buf_output0 (protocol, "\n");
+ buf_output0 (protocol, newfile);
+ buf_output0 (protocol, "\n");
+}
+
+
+
+/* See server.h for description. */
+void
+server_modtime (struct file_info *finfo, Vers_TS *vers_ts)
+{
+ char date[MAXDATELEN];
+ char outdate[MAXDATELEN];
+
+ assert (vers_ts->vn_rcs != NULL);
+
+ if (!supported_response ("Mod-time"))
+ return;
+
+ if (RCS_getrevtime (finfo->rcs, vers_ts->vn_rcs, date, 0) == (time_t) -1)
+ /* FIXME? should we be printing some kind of warning? For one
+ thing I'm not 100% sure whether this happens in non-error
+ circumstances. */
+ return;
+ date_to_internet (outdate, date);
+ buf_output0 (protocol, "Mod-time ");
+ buf_output0 (protocol, outdate);
+ buf_output0 (protocol, "\n");
+}
+
+
+
+/* See server.h for description. */
+void
+server_updated (
+ struct file_info *finfo,
+ Vers_TS *vers,
+ enum server_updated_arg4 updated,
+ mode_t mode,
+ unsigned char *checksum,
+ struct buffer *filebuf)
+{
+ if (noexec)
+ {
+ /* Hmm, maybe if we did the same thing for entries_file, we
+ could get rid of the kludges in server_register and
+ server_scratch which refrain from warning if both
+ Scratch_Entry and Register get called. Maybe. */
+ if (scratched_file)
+ {
+ free (scratched_file);
+ scratched_file = NULL;
+ }
+ buf_send_counted (protocol);
+ return;
+ }
+
+ if (entries_line != NULL && scratched_file == NULL)
+ {
+ FILE *f;
+ struct buffer_data *list, *last;
+ unsigned long size;
+ char size_text[80];
+
+ /* The contents of the file will be in one of filebuf,
+ list/last, or here. */
+ unsigned char *file;
+ size_t file_allocated;
+ size_t file_used;
+
+ if (filebuf != NULL)
+ {
+ size = buf_length (filebuf);
+ if (mode == (mode_t) -1)
+ error (1, 0, "\
+CVS server internal error: no mode in server_updated");
+ }
+ else
+ {
+ struct stat sb;
+
+ if (stat (finfo->file, &sb) < 0)
+ {
+ if (existence_error (errno))
+ {
+ /* If we have a sticky tag for a branch on which
+ the file is dead, and cvs update the directory,
+ it gets a T_CHECKOUT but no file. So in this
+ case just forget the whole thing. */
+ free (entries_line);
+ entries_line = NULL;
+ goto done;
+ }
+ error (1, errno, "reading %s", finfo->fullname);
+ }
+ size = sb.st_size;
+ if (mode == (mode_t) -1)
+ {
+ /* FIXME: When we check out files the umask of the
+ server (set in .bashrc if rsh is in use) affects
+ what mode we send, and it shouldn't. */
+ mode = sb.st_mode;
+ }
+ }
+
+ if (checksum != NULL)
+ {
+ static int checksum_supported = -1;
+
+ if (checksum_supported == -1)
+ {
+ checksum_supported = supported_response ("Checksum");
+ }
+
+ if (checksum_supported)
+ {
+ int i;
+ char buf[3];
+
+ buf_output0 (protocol, "Checksum ");
+ for (i = 0; i < 16; i++)
+ {
+ sprintf (buf, "%02x", (unsigned int) checksum[i]);
+ buf_output0 (protocol, buf);
+ }
+ buf_append_char (protocol, '\n');
+ }
+ }
+
+ if (updated == SERVER_UPDATED)
+ {
+ Node *node;
+ Entnode *entnode;
+
+ if (!(supported_response ("Created")
+ && supported_response ("Update-existing")))
+ buf_output0 (protocol, "Updated ");
+ else
+ {
+ assert (vers != NULL);
+ if (vers->ts_user == NULL)
+ buf_output0 (protocol, "Created ");
+ else
+ buf_output0 (protocol, "Update-existing ");
+ }
+
+ /* Now munge the entries to say that the file is unmodified,
+ in case we end up processing it again (e.g. modules3-6
+ in the testsuite). */
+ node = findnode_fn (finfo->entries, finfo->file);
+ entnode = node->data;
+ free (entnode->timestamp);
+ entnode->timestamp = xstrdup ("=");
+ }
+ else if (updated == SERVER_MERGED)
+ buf_output0 (protocol, "Merged ");
+ else if (updated == SERVER_PATCHED)
+ buf_output0 (protocol, "Patched ");
+ else if (updated == SERVER_RCS_DIFF)
+ buf_output0 (protocol, "Rcs-diff ");
+ else
+ abort ();
+ output_dir (finfo->update_dir, finfo->repository);
+ buf_output0 (protocol, finfo->file);
+ buf_output (protocol, "\n", 1);
+
+ new_entries_line ();
+
+ {
+ char *mode_string;
+
+ mode_string = mode_to_string (mode);
+ buf_output0 (protocol, mode_string);
+ buf_output0 (protocol, "\n");
+ free (mode_string);
+ }
+
+ list = last = NULL;
+
+ file = NULL;
+ file_allocated = 0;
+ file_used = 0;
+
+ if (size > 0)
+ {
+ /* Throughout this section we use binary mode to read the
+ file we are sending. The client handles any line ending
+ translation if necessary. */
+
+ if (file_gzip_level
+ /*
+ * For really tiny files, the gzip process startup
+ * time will outweigh the compression savings. This
+ * might be computable somehow; using 100 here is just
+ * a first approximation.
+ */
+ && size > 100)
+ {
+ /* Basing this routine on read_and_gzip is not a
+ high-performance approach. But it seems easier
+ to code than the alternative (and less
+ vulnerable to subtle bugs). Given that this feature
+ is mainly for compatibility, that is the better
+ tradeoff. */
+
+ int fd;
+
+ /* Callers must avoid passing us a buffer if
+ file_gzip_level is set. We could handle this case,
+ but it's not worth it since this case never arises
+ with a current client and server. */
+ if (filebuf != NULL)
+ error (1, 0, "\
+CVS server internal error: unhandled case in server_updated");
+
+ fd = CVS_OPEN (finfo->file, O_RDONLY | OPEN_BINARY, 0);
+ if (fd < 0)
+ error (1, errno, "reading %s", finfo->fullname);
+ if (read_and_gzip (fd, finfo->fullname, &file,
+ &file_allocated, &file_used,
+ file_gzip_level))
+ error (1, 0, "aborting due to compression error");
+ size = file_used;
+ if (close (fd) < 0)
+ error (1, errno, "reading %s", finfo->fullname);
+ /* Prepending length with "z" is flag for using gzip here. */
+ buf_output0 (protocol, "z");
+ }
+ else if (filebuf == NULL)
+ {
+ long status;
+
+ f = CVS_FOPEN (finfo->file, "rb");
+ if (f == NULL)
+ error (1, errno, "reading %s", finfo->fullname);
+ status = buf_read_file (f, size, &list, &last);
+ if (status == -2)
+ (*protocol->memory_error) (protocol);
+ else if (status != 0)
+ error (1, ferror (f) ? errno : 0, "reading %s",
+ finfo->fullname);
+ if (fclose (f) == EOF)
+ error (1, errno, "reading %s", finfo->fullname);
+ }
+ }
+
+ sprintf (size_text, "%lu\n", size);
+ buf_output0 (protocol, size_text);
+
+ if (file != NULL)
+ {
+ buf_output (protocol, (char *) file, file_used);
+ free (file);
+ file = NULL;
+ }
+ else if (filebuf == NULL)
+ buf_append_data (protocol, list, last);
+ else
+ buf_append_buffer (protocol, filebuf);
+ /* Note we only send a newline here if the file ended with one. */
+
+ /*
+ * Avoid using up too much disk space for temporary files.
+ * A file which does not exist indicates that the file is up-to-date,
+ * which is now the case. If this is SERVER_MERGED, the file is
+ * not up-to-date, and we indicate that by leaving the file there.
+ * I'm thinking of cases like "cvs update foo/foo.c foo".
+ */
+ if ((updated == SERVER_UPDATED
+ || updated == SERVER_PATCHED
+ || updated == SERVER_RCS_DIFF)
+ && filebuf == NULL
+ /* But if we are joining, we'll need the file when we call
+ join_file. */
+ && !joining ())
+ {
+ if (CVS_UNLINK (finfo->file) < 0)
+ error (0, errno, "cannot remove temp file for %s",
+ finfo->fullname);
+ }
+ }
+ else if (scratched_file != NULL && entries_line == NULL)
+ {
+ if (strcmp (scratched_file, finfo->file) != 0)
+ error (1, 0,
+ "CVS server internal error: `%s' vs. `%s' scratched",
+ scratched_file,
+ finfo->file);
+ free (scratched_file);
+ scratched_file = NULL;
+
+ if (kill_scratched_file)
+ buf_output0 (protocol, "Removed ");
+ else
+ buf_output0 (protocol, "Remove-entry ");
+ output_dir (finfo->update_dir, finfo->repository);
+ buf_output0 (protocol, finfo->file);
+ buf_output (protocol, "\n", 1);
+ /* keep the vers structure up to date in case we do a join
+ * - if there isn't a file, it can't very well have a version number,
+ * can it?
+ *
+ * we do it here on the assumption that since we just told the client
+ * to remove the file/entry, it will, and we want to remember that.
+ * If it fails, that's the client's problem, not ours
+ */
+ if (vers && vers->vn_user != NULL)
+ {
+ free (vers->vn_user);
+ vers->vn_user = NULL;
+ }
+ if (vers && vers->ts_user != NULL)
+ {
+ free (vers->ts_user);
+ vers->ts_user = NULL;
+ }
+ }
+ else if (scratched_file == NULL && entries_line == NULL)
+ {
+ /*
+ * This can happen with death support if we were processing
+ * a dead file in a checkout.
+ */
+ }
+ else
+ error (1, 0,
+ "CVS server internal error: Register *and* Scratch_Entry.\n");
+ buf_send_counted (protocol);
+ done:;
+}
+
+
+
+/* Return whether we should send patches in RCS format. */
+int
+server_use_rcs_diff (void)
+{
+ return supported_response ("Rcs-diff");
+}
+
+
+
+void
+server_set_entstat (const char *update_dir, const char *repository)
+{
+ static int set_static_supported = -1;
+ if (set_static_supported == -1)
+ set_static_supported = supported_response ("Set-static-directory");
+ if (!set_static_supported) return;
+
+ buf_output0 (protocol, "Set-static-directory ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, "\n");
+ buf_send_counted (protocol);
+}
+
+
+
+void
+server_clear_entstat (const char *update_dir, const char *repository)
+{
+ static int clear_static_supported = -1;
+ if (clear_static_supported == -1)
+ clear_static_supported = supported_response ("Clear-static-directory");
+ if (!clear_static_supported) return;
+
+ if (noexec)
+ return;
+
+ buf_output0 (protocol, "Clear-static-directory ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, "\n");
+ buf_send_counted (protocol);
+}
+
+
+
+void
+server_set_sticky (const char *update_dir, const char *repository,
+ const char *tag, const char *date, int nonbranch)
+{
+ static int set_sticky_supported = -1;
+
+ assert (update_dir != NULL);
+
+ if (set_sticky_supported == -1)
+ set_sticky_supported = supported_response ("Set-sticky");
+ if (!set_sticky_supported) return;
+
+ if (noexec)
+ return;
+
+ if (tag == NULL && date == NULL)
+ {
+ buf_output0 (protocol, "Clear-sticky ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, "\n");
+ }
+ else
+ {
+ buf_output0 (protocol, "Set-sticky ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, "\n");
+ if (tag != NULL)
+ {
+ if (nonbranch)
+ buf_output0 (protocol, "N");
+ else
+ buf_output0 (protocol, "T");
+ buf_output0 (protocol, tag);
+ }
+ else
+ {
+ buf_output0 (protocol, "D");
+ buf_output0 (protocol, date);
+ }
+ buf_output0 (protocol, "\n");
+ }
+ buf_send_counted (protocol);
+}
+
+
+
+void
+server_edit_file (struct file_info *finfo)
+{
+ buf_output (protocol, "Edit-file ", 10);
+ output_dir (finfo->update_dir, finfo->repository);
+ buf_output0 (protocol, finfo->file);
+ buf_output (protocol, "\n", 1);
+ buf_send_counted (protocol);
+}
+
+
+
+struct template_proc_data
+{
+ const char *update_dir;
+ const char *repository;
+};
+
+static int
+template_proc (const char *repository, const char *template, void *closure)
+{
+ FILE *fp;
+ char buf[1024];
+ size_t n;
+ struct stat sb;
+ struct template_proc_data *data = (struct template_proc_data *)closure;
+
+ if (!supported_response ("Template"))
+ /* Might want to warn the user that the rcsinfo feature won't work. */
+ return 0;
+ buf_output0 (protocol, "Template ");
+ output_dir (data->update_dir, data->repository);
+ buf_output0 (protocol, "\n");
+
+ fp = CVS_FOPEN (template, "rb");
+ if (fp == NULL)
+ {
+ error (0, errno, "Couldn't open rcsinfo template file %s", template);
+ return 1;
+ }
+ if (fstat (fileno (fp), &sb) < 0)
+ {
+ error (0, errno, "cannot stat rcsinfo template file %s", template);
+ return 1;
+ }
+ sprintf (buf, "%ld\n", (long) sb.st_size);
+ buf_output0 (protocol, buf);
+ while (!feof (fp))
+ {
+ n = fread (buf, 1, sizeof buf, fp);
+ buf_output (protocol, buf, n);
+ if (ferror (fp))
+ {
+ error (0, errno, "cannot read rcsinfo template file %s", template);
+ (void) fclose (fp);
+ return 1;
+ }
+ }
+ buf_send_counted (protocol);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close rcsinfo template file %s", template);
+ return 0;
+}
+
+
+
+void
+server_clear_template (const char *update_dir, const char *repository)
+{
+ assert (update_dir != NULL);
+
+ if (noexec)
+ return;
+
+ if (!supported_response ("Clear-template") &&
+ !supported_response ("Template"))
+ /* Might want to warn the user that the rcsinfo feature won't work. */
+ return;
+
+ if (supported_response ("Clear-template"))
+ {
+ buf_output0 (protocol, "Clear-template ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, "\n");
+ buf_send_counted (protocol);
+ }
+ else
+ {
+ buf_output0 (protocol, "Template ");
+ output_dir (update_dir, repository);
+ buf_output0 (protocol, "\n");
+ buf_output0 (protocol, "0\n");
+ buf_send_counted (protocol);
+ }
+}
+
+
+
+void
+server_template (const char *update_dir, const char *repository)
+{
+ struct template_proc_data data;
+ data.update_dir = update_dir;
+ data.repository = repository;
+ (void) Parse_Info (CVSROOTADM_RCSINFO, repository, template_proc,
+ PIOPT_ALL, &data);
+}
+
+
+
+static void
+serve_gzip_contents (char *arg)
+{
+ int level;
+ bool forced = false;
+
+# ifdef PROXY_SUPPORT
+ assert (!proxy_log);
+# endif /* PROXY_SUPPORT */
+
+ level = atoi (arg);
+ if (level == 0)
+ level = 6;
+
+ if (config && level < config->MinCompressionLevel)
+ {
+ level = config->MinCompressionLevel;
+ forced = true;
+ }
+ if (config && level > config->MaxCompressionLevel)
+ {
+ level = config->MaxCompressionLevel;
+ forced = true;
+ }
+
+ if (forced && !quiet
+ && alloc_pending_warning (120 + strlen (program_name)))
+ sprintf (pending_warning_text,
+"E %s server: Forcing compression level %d (allowed: %d <= z <= %d).",
+ program_name, level, config->MinCompressionLevel,
+ config->MaxCompressionLevel);
+
+ gzip_level = file_gzip_level = level;
+}
+
+
+
+static void
+serve_gzip_stream (char *arg)
+{
+ int level;
+ bool forced = false;
+
+ level = atoi (arg);
+
+ if (config && level < config->MinCompressionLevel)
+ {
+ level = config->MinCompressionLevel;
+ forced = true;
+ }
+ if (config && level > config->MaxCompressionLevel)
+ {
+ level = config->MaxCompressionLevel;
+ forced = true;
+ }
+
+ if (forced && !quiet
+ && alloc_pending_warning (120 + strlen (program_name)))
+ sprintf (pending_warning_text,
+"E %s server: Forcing compression level %d (allowed: %d <= z <= %d).",
+ program_name, level, config->MinCompressionLevel,
+ config->MaxCompressionLevel);
+
+ gzip_level = level;
+
+ /* All further communication with the client will be compressed.
+ *
+ * The deflate buffers need to be initialized even for compression level
+ * 0, or the client will no longer be able to understand us. At
+ * compression level 0, the correct compression headers will be created and
+ * sent, but data will thereafter simply be copied to the network buffers.
+ */
+
+ /* This needs to be processed in both passes so that we may continue to
+ * understand client requests on both the socket and from the log.
+ */
+ buf_from_net = compress_buffer_initialize (buf_from_net, 1,
+ 0 /* Not used. */,
+ buf_from_net->memory_error);
+
+ /* This needs to be skipped in subsequent passes to avoid compressing data
+ * to the client twice.
+ */
+# ifdef PROXY_SUPPORT
+ if (reprocessing) return;
+# endif /* PROXY_SUPPORT */
+ buf_to_net = compress_buffer_initialize (buf_to_net, 0, level,
+ buf_to_net->memory_error);
+}
+
+
+
+/* Tell the client about RCS options set in CVSROOT/cvswrappers. */
+static void
+serve_wrapper_sendme_rcs_options (char *arg)
+{
+ /* Actually, this is kind of sdrawkcab-ssa: the client wants
+ * verbatim lines from a cvswrappers file, but the server has
+ * already parsed the cvswrappers file into the wrap_list struct.
+ * Therefore, the server loops over wrap_list, unparsing each
+ * entry before sending it.
+ */
+ char *wrapper_line = NULL;
+
+# ifdef PROXY_SUPPORT
+ if (reprocessing) return;
+# endif /* PROXY_SUPPORT */
+
+ wrap_setup ();
+
+ for (wrap_unparse_rcs_options (&wrapper_line, 1);
+ wrapper_line;
+ wrap_unparse_rcs_options (&wrapper_line, 0))
+ {
+ buf_output0 (buf_to_net, "Wrapper-rcsOption ");
+ buf_output0 (buf_to_net, wrapper_line);
+ buf_output0 (buf_to_net, "\012");;
+ free (wrapper_line);
+ }
+
+ buf_output0 (buf_to_net, "ok\012");
+
+ /* The client is waiting for us, so we better send the data now. */
+ buf_flush (buf_to_net, 1);
+}
+
+
+
+static void
+serve_ignore (char *arg)
+{
+ /*
+ * Just ignore this command. This is used to support the
+ * update-patches command, which is not a real command, but a signal
+ * to the client that update will accept the -u argument.
+ */
+# ifdef PROXY_SUPPORT
+ assert (!proxy_log);
+# endif /* PROXY_SUPPORT */
+}
+
+
+
+static int
+expand_proc (int argc, char **argv, char *where, char *mwhere, char *mfile, int shorten, int local_specified, char *omodule, char *msg)
+{
+ int i;
+ char *dir = argv[0];
+
+ /* If mwhere has been specified, the thing we're expanding is a
+ module -- just return its name so the client will ask for the
+ right thing later. If it is an alias or a real directory,
+ mwhere will not be set, so send out the appropriate
+ expansion. */
+
+ if (mwhere != NULL)
+ {
+ buf_output0 (buf_to_net, "Module-expansion ");
+ if (server_dir != NULL)
+ {
+ buf_output0 (buf_to_net, server_dir);
+ buf_output0 (buf_to_net, "/");
+ }
+ buf_output0 (buf_to_net, mwhere);
+ if (mfile != NULL)
+ {
+ buf_append_char (buf_to_net, '/');
+ buf_output0 (buf_to_net, mfile);
+ }
+ buf_append_char (buf_to_net, '\n');
+ }
+ else
+ {
+ /* We may not need to do this anymore -- check the definition
+ of aliases before removing */
+ if (argc == 1)
+ {
+ buf_output0 (buf_to_net, "Module-expansion ");
+ if (server_dir != NULL)
+ {
+ buf_output0 (buf_to_net, server_dir);
+ buf_output0 (buf_to_net, "/");
+ }
+ buf_output0 (buf_to_net, dir);
+ buf_append_char (buf_to_net, '\n');
+ }
+ else
+ {
+ for (i = 1; i < argc; ++i)
+ {
+ buf_output0 (buf_to_net, "Module-expansion ");
+ if (server_dir != NULL)
+ {
+ buf_output0 (buf_to_net, server_dir);
+ buf_output0 (buf_to_net, "/");
+ }
+ buf_output0 (buf_to_net, dir);
+ buf_append_char (buf_to_net, '/');
+ buf_output0 (buf_to_net, argv[i]);
+ buf_append_char (buf_to_net, '\n');
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+static void
+serve_expand_modules (char *arg)
+{
+ int i;
+ int err = 0;
+ DBM *db;
+
+# ifdef PROXY_SUPPORT
+ /* This needs to be processed in the first pass since the client expects a
+ * response but we may not yet know if we are a secondary.
+ *
+ * On the second pass, we still must make sure to ignore the arguments.
+ */
+ if (!reprocessing)
+# endif /* PROXY_SUPPORT */
+ {
+ err = 0;
+
+ db = open_module ();
+ for (i = 1; i < argument_count; i++)
+ err += do_module (db, argument_vector[i],
+ CHECKOUT, "Updating", expand_proc,
+ NULL, 0, 0, 0, 0, NULL);
+ close_module (db);
+ }
+
+ {
+ /* argument_vector[0] is a dummy argument, we don't mess with it. */
+ char **cp;
+ for (cp = argument_vector + 1;
+ cp < argument_vector + argument_count;
+ ++cp)
+ free (*cp);
+
+ argument_count = 1;
+ }
+
+# ifdef PROXY_SUPPORT
+ if (!reprocessing)
+# endif /* PROXY_SUPPORT */
+ {
+ if (err)
+ /* We will have printed an error message already. */
+ buf_output0 (buf_to_net, "error \n");
+ else
+ buf_output0 (buf_to_net, "ok\n");
+
+ /* The client is waiting for the module expansions, so we must
+ send the output now. */
+ buf_flush (buf_to_net, 1);
+ }
+}
+
+
+
+/* Decide if we should redirect the client to another server.
+ *
+ * GLOBALS
+ * config->PrimaryServer The server to redirect write requests to, if
+ * any.
+ *
+ * ASSUMPTIONS
+ * The `Root' request has already been processed.
+ *
+ * RETURNS
+ * Nothing.
+ */
+static void
+serve_command_prep (char *arg)
+{
+ bool redirect_supported;
+# ifdef PROXY_SUPPORT
+ bool ditch_log;
+# endif /* PROXY_SUPPORT */
+
+ if (print_pending_error ()) return;
+
+ redirect_supported = supported_response ("Redirect");
+ if (redirect_supported
+ && lookup_command_attribute (arg) & CVS_CMD_MODIFIES_REPOSITORY
+ /* I call isProxyServer() last because it can probably be the slowest
+ * call due to the call to gethostbyname().
+ */
+ && isProxyServer ())
+ {
+ /* Before sending a redirect, send a "Referrer" line to the client,
+ * if possible, to give admins more control over canonicalizing roots
+ * sent from the client.
+ */
+ if (supported_response ("Referrer"))
+ {
+ /* assume :ext:, since that is all we currently support for
+ * proxies and redirection.
+ */
+ char *referrer = Xasprintf (":ext:%s@%s%s", getcaller(),
+ server_hostname,
+ current_parsed_root->directory);
+
+ buf_output0 (buf_to_net, "Referrer ");
+ buf_output0 (buf_to_net, referrer);
+ buf_output0 (buf_to_net, "\n");
+
+ free (referrer);
+ }
+
+ /* Send `Redirect' to redirect client requests to the primary. */
+ buf_output0 (buf_to_net, "Redirect ");
+ buf_output0 (buf_to_net, config->PrimaryServer->original);
+ buf_output0 (buf_to_net, "\n");
+ buf_flush (buf_to_net, 1);
+# ifdef PROXY_SUPPORT
+ ditch_log = true;
+# endif /* PROXY_SUPPORT */
+ }
+ else
+ {
+ /* Send `ok' so the client can proceed. */
+ buf_output0 (buf_to_net, "ok\n");
+ buf_flush (buf_to_net, 1);
+# ifdef PROXY_SUPPORT
+ if (lookup_command_attribute (arg) & CVS_CMD_MODIFIES_REPOSITORY
+ && isProxyServer ())
+ /* Don't ditch the log for write commands on a proxy server. We
+ * we got here because the `Redirect' response was not supported.
+ */
+ ditch_log = false;
+ else
+ ditch_log = true;
+# endif /* PROXY_SUPPORT */
+ }
+# ifdef PROXY_SUPPORT
+ if (proxy_log && ditch_log)
+ {
+ /* If the client supported the redirect response, then they will always
+ * be redirected if they are preparing for a write request. It is
+ * therefore safe to close the proxy logs.
+ *
+ * If the client is broken and ignores the redirect, this will be
+ * detected later, in rewind_buf_from_net().
+ *
+ * Since a `Command-prep' response is only acceptable immediately
+ * following the `Root' request according to the specification, there
+ * is no need to rewind the log and reprocess.
+ */
+ log_buffer_closelog (proxy_log);
+ log_buffer_closelog (proxy_log_out);
+ proxy_log = NULL;
+ }
+# endif /* PROXY_SUPPORT */
+}
+
+
+
+/* Save a referrer, potentially for passing to hook scripts later.
+ *
+ * GLOBALS
+ * referrer Where we save the parsed referrer.
+ *
+ * ASSUMPTIONS
+ * The `Root' request has already been processed.
+ * There is no need to dispose of REFERRER if it is set. It's memory is
+ * tracked by parse_root().
+ *
+ * RETURNS
+ * Nothing.
+ */
+static void
+serve_referrer (char *arg)
+{
+ if (error_pending ()) return;
+
+ referrer = parse_cvsroot (arg);
+
+ if (!referrer
+ && alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E Protocol error: Invalid Referrer: `%s'",
+ arg);
+}
+
+
+
+static void serve_valid_requests (char *arg);
+
+#endif /* SERVER_SUPPORT */
+/*
+ * Comment to move position of the following #if line which works
+ * around an apparent bug in Microsoft Visual C++ 6.0 compiler.
+ */
+#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
+/*
+ * Parts of this table are shared with the client code,
+ * but the client doesn't need to know about the handler
+ * functions.
+ */
+
+struct request requests[] =
+{
+#ifdef SERVER_SUPPORT
+#define REQ_LINE(n, f, s) {n, f, s}
+#else
+#define REQ_LINE(n, f, s) {n, s}
+#endif
+
+ REQ_LINE("Root", serve_root, RQ_ESSENTIAL | RQ_ROOTLESS),
+ REQ_LINE("Valid-responses", serve_valid_responses,
+ RQ_ESSENTIAL | RQ_ROOTLESS),
+ REQ_LINE("valid-requests", serve_valid_requests,
+ RQ_ESSENTIAL | RQ_ROOTLESS),
+ REQ_LINE("Command-prep", serve_command_prep, 0),
+ REQ_LINE("Referrer", serve_referrer, 0),
+ REQ_LINE("Repository", serve_repository, 0),
+ REQ_LINE("Directory", serve_directory, RQ_ESSENTIAL),
+ REQ_LINE("Relative-directory", serve_directory, 0),
+ REQ_LINE("Max-dotdot", serve_max_dotdot, 0),
+ REQ_LINE("Static-directory", serve_static_directory, 0),
+ REQ_LINE("Sticky", serve_sticky, 0),
+ REQ_LINE("Entry", serve_entry, RQ_ESSENTIAL),
+ REQ_LINE("Kopt", serve_kopt, 0),
+ REQ_LINE("Checkin-time", serve_checkin_time, 0),
+ REQ_LINE("Modified", serve_modified, RQ_ESSENTIAL),
+ REQ_LINE("Is-modified", serve_is_modified, 0),
+
+ /* The client must send this request to interoperate with CVS 1.5
+ through 1.9 servers. The server must support it (although it can
+ be and is a noop) to interoperate with CVS 1.5 to 1.9 clients. */
+ REQ_LINE("UseUnchanged", serve_enable_unchanged, RQ_ENABLEME | RQ_ROOTLESS),
+
+ REQ_LINE("Unchanged", serve_unchanged, RQ_ESSENTIAL),
+ REQ_LINE("Notify", serve_notify, 0),
+ REQ_LINE("Hostname", serve_hostname, 0),
+ REQ_LINE("LocalDir", serve_localdir, 0),
+ REQ_LINE("Questionable", serve_questionable, 0),
+ REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL),
+ REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL),
+ REQ_LINE("Global_option", serve_global_option, RQ_ROOTLESS),
+ /* This is rootless, even though the client/server spec does not specify
+ * such, to allow error messages to be understood by the client when they are
+ * sent.
+ */
+ REQ_LINE("Gzip-stream", serve_gzip_stream, RQ_ROOTLESS),
+ REQ_LINE("wrapper-sendme-rcsOptions",
+ serve_wrapper_sendme_rcs_options,
+ 0),
+ REQ_LINE("Set", serve_set, RQ_ROOTLESS),
+#ifdef ENCRYPTION
+ /* These are rootless despite what the client/server spec says for the same
+ * reasons as Gzip-stream.
+ */
+# ifdef HAVE_KERBEROS
+ REQ_LINE("Kerberos-encrypt", serve_kerberos_encrypt, RQ_ROOTLESS),
+# endif
+# ifdef HAVE_GSSAPI
+ REQ_LINE("Gssapi-encrypt", serve_gssapi_encrypt, RQ_ROOTLESS),
+# endif
+#endif
+#ifdef HAVE_GSSAPI
+ REQ_LINE("Gssapi-authenticate", serve_gssapi_authenticate, RQ_ROOTLESS),
+#endif
+ REQ_LINE("expand-modules", serve_expand_modules, 0),
+ REQ_LINE("ci", serve_ci, RQ_ESSENTIAL),
+ REQ_LINE("co", serve_co, RQ_ESSENTIAL),
+ REQ_LINE("update", serve_update, RQ_ESSENTIAL),
+ REQ_LINE("diff", serve_diff, 0),
+ REQ_LINE("log", serve_log, 0),
+ REQ_LINE("rlog", serve_rlog, 0),
+ REQ_LINE("list", serve_ls, 0),
+ REQ_LINE("rlist", serve_rls, 0),
+ /* This allows us to avoid sending `-q' as a command argument to `cvs ls',
+ * or more accurately, allows us to send `-q' to backwards CVSNT servers.
+ */
+ REQ_LINE("global-list-quiet", serve_noop, RQ_ROOTLESS),
+ /* Deprecated synonym for rlist, for compatibility with CVSNT. */
+ REQ_LINE("ls", serve_rls, 0),
+ REQ_LINE("add", serve_add, 0),
+ REQ_LINE("remove", serve_remove, 0),
+ REQ_LINE("update-patches", serve_ignore, 0),
+ REQ_LINE("gzip-file-contents", serve_gzip_contents, RQ_ROOTLESS),
+ REQ_LINE("status", serve_status, 0),
+ REQ_LINE("rdiff", serve_rdiff, 0),
+ REQ_LINE("tag", serve_tag, 0),
+ REQ_LINE("rtag", serve_rtag, 0),
+ REQ_LINE("import", serve_import, 0),
+ REQ_LINE("admin", serve_admin, 0),
+ REQ_LINE("export", serve_export, 0),
+ REQ_LINE("history", serve_history, 0),
+ REQ_LINE("release", serve_release, 0),
+ REQ_LINE("watch-on", serve_watch_on, 0),
+ REQ_LINE("watch-off", serve_watch_off, 0),
+ REQ_LINE("watch-add", serve_watch_add, 0),
+ REQ_LINE("watch-remove", serve_watch_remove, 0),
+ REQ_LINE("watchers", serve_watchers, 0),
+ REQ_LINE("editors", serve_editors, 0),
+ REQ_LINE("edit", serve_edit, 0),
+ REQ_LINE("init", serve_init, RQ_ROOTLESS),
+ REQ_LINE("annotate", serve_annotate, 0),
+ REQ_LINE("rannotate", serve_rannotate, 0),
+ REQ_LINE("noop", serve_noop, RQ_ROOTLESS),
+ REQ_LINE("version", serve_version, RQ_ROOTLESS),
+ REQ_LINE(NULL, NULL, 0)
+
+#undef REQ_LINE
+};
+#endif /* SERVER_SUPPORT or CLIENT_SUPPORT */
+
+
+
+#ifdef SERVER_SUPPORT
+/*
+ * This server request is not ignored by the secondary.
+ */
+static void
+serve_valid_requests (char *arg)
+{
+ struct request *rq;
+
+ /* Since this is processed in the first pass, don't reprocess it in the
+ * second.
+ *
+ * We still print errors since new errors could have been generated in the
+ * second pass.
+ */
+ if (print_pending_error ()
+#ifdef PROXY_SUPPORT
+ || reprocessing
+#endif /* PROXY_SUPPORT */
+ )
+ return;
+
+ buf_output0 (buf_to_net, "Valid-requests");
+ for (rq = requests; rq->name != NULL; rq++)
+ {
+ if (rq->func != NULL)
+ {
+ buf_append_char (buf_to_net, ' ');
+ buf_output0 (buf_to_net, rq->name);
+ }
+ }
+
+ if (config && config->MinCompressionLevel
+ && supported_response ("Force-gzip"))
+ {
+ buf_output0 (buf_to_net, "\n");
+ buf_output0 (buf_to_net, "Force-gzip");
+ }
+
+ buf_output0 (buf_to_net, "\nok\n");
+
+ /* The client is waiting for the list of valid requests, so we
+ must send the output now. */
+ buf_flush (buf_to_net, 1);
+}
+
+
+
+#ifdef SUNOS_KLUDGE
+/*
+ * Delete temporary files. SIG is the signal making this happen, or
+ * 0 if not called as a result of a signal.
+ */
+static int command_pid_is_dead;
+static void wait_sig (int sig)
+{
+ int status;
+ pid_t r = wait (&status);
+ if (r == command_pid)
+ command_pid_is_dead++;
+}
+#endif /* SUNOS_KLUDGE */
+
+
+
+/*
+ * This function cleans up after the server. Specifically, it:
+ *
+ * <ol>
+ * <li>Sets BUF_TO_NET to blocking and fluxhes it.</li>
+ * <li>With SUNOS_KLUDGE enabled:
+ * <ol>
+ * <li>Terminates the command process.</li>
+ * <li>Waits on the command process, draining output as necessary.</li>
+ * </ol>
+ * </li>
+ * <li>Removes the temporary directory.</li>
+ * <li>Flush and shutdown the buffers.</li>
+ * <li>Set ERROR_USE_PROTOCOL and SERVER_ACTIVE to false.</li>
+ * </ol>
+ *
+ * NOTES
+ * This function needs to be reentrant since a call to exit() can cause a
+ * call to this function, which can then be interrupted by a signal, which
+ * can cause a second call to this function.
+ *
+ * GLOBALS
+ * buf_from_net The input buffer which brings data from the
+ * CVS client.
+ * buf_to_net The output buffer which moves data to the CVS
+ * client.
+ * error_use_protocol Set when the server parent process is active.
+ * Cleared for the server child processes.
+ * dont_delete_temp Set when a core dump of a child process is
+ * detected so that the core and related data may
+ * be preserved.
+ * noexec Whether we are supposed to change the disk.
+ * orig_server_temp_dir The temporary directory we created within
+ * Tmpdir for our duplicate of the client
+ * workspace.
+ *
+ * INPUTS
+ * None.
+ *
+ * ERRORS
+ * Problems encountered during the cleanup, for instance low memory or
+ * problems deleting the temp files and directories, can cause the error
+ * function to be called, which might call exit. If exit gets called in this
+ * manner. this routine will not complete, but the other exit handlers
+ * registered via atexit() will still run.
+ *
+ * RETURNS
+ * Nothing.
+ */
+void
+server_cleanup (void)
+{
+ TRACE (TRACE_FUNCTION, "server_cleanup()");
+
+ assert (server_active);
+
+ /* FIXME: Do not perform buffered I/O from an interrupt handler like
+ * this (via error). However, I'm leaving the error-calling code there
+ * in the hope that on the rare occasion the error call is actually made
+ * (e.g., a fluky I/O error or permissions problem prevents the deletion
+ * of a just-created file) reentrancy won't be an issue.
+ */
+
+ /* We don't want to be interrupted during calls which set globals to NULL,
+ * but we know that by the time we reach this function, interrupts have
+ * already been blocked.
+ */
+
+ /* Since we install this function in an atexit() handler before forking,
+ * reuse the ERROR_USE_PROTOCOL flag, which we know is only set in the
+ * parent server process, to avoid cleaning up the temp space multiple
+ * times. Skip the buf_to_net checks too as an optimization since we know
+ * they will be set to NULL in the child process anyhow.
+ */
+ if (error_use_protocol)
+ {
+ if (buf_to_net != NULL)
+ {
+ int status;
+
+ /* Since we're done, go ahead and put BUF_TO_NET back into blocking
+ * mode and send any pending output. In the usual case there won't
+ * won't be any, but there might be if an error occured.
+ */
+
+ set_block (buf_to_net);
+ buf_flush (buf_to_net, 1);
+
+ /* Next we shut down BUF_FROM_NET. That will pick up the checksum
+ * generated when the client shuts down its buffer. Then, after we
+ * have generated any final output, we shut down BUF_TO_NET.
+ */
+
+ /* SIG_beginCrSect(); */
+ if (buf_from_net)
+ {
+ status = buf_shutdown (buf_from_net);
+ if (status != 0)
+ error (0, status, "shutting down buffer from client");
+ buf_free (buf_from_net);
+ buf_from_net = NULL;
+ }
+ /* SIG_endCrSect(); */
+ }
+
+ if (!dont_delete_temp)
+ {
+ int save_noexec;
+
+ /* What a bogus kludge. This disgusting code makes all kinds of
+ assumptions about SunOS, and is only for a bug in that system.
+ So only enable it on Suns. */
+#ifdef SUNOS_KLUDGE
+ if (command_pid > 0)
+ {
+ /* To avoid crashes on SunOS due to bugs in SunOS tmpfs
+ * triggered by the use of rename() in RCS, wait for the
+ * subprocess to die. Unfortunately, this means draining
+ * output while waiting for it to unblock the signal we sent
+ * it. Yuck!
+ */
+ int status;
+ pid_t r;
+
+ signal (SIGCHLD, wait_sig);
+ /* Perhaps SIGTERM would be more correct. But the child
+ process will delay the SIGINT delivery until its own
+ children have exited. */
+ kill (command_pid, SIGINT);
+ /* The caller may also have sent a signal to command_pid, so
+ * always try waiting. First, though, check and see if it's
+ * still there....
+ */
+ do_waitpid:
+ r = waitpid (command_pid, &status, WNOHANG);
+ if (r == 0)
+ ;
+ else if (r == command_pid)
+ command_pid_is_dead++;
+ else if (r == -1)
+ switch (errno)
+ {
+ case ECHILD:
+ command_pid_is_dead++;
+ break;
+ case EINTR:
+ goto do_waitpid;
+ }
+ else
+ /* waitpid should always return one of the above values */
+ abort ();
+ while (!command_pid_is_dead)
+ {
+ struct timeval timeout;
+ struct fd_set_wrapper readfds;
+ char buf[100];
+ int i;
+
+ /* Use a non-zero timeout to avoid eating up CPU cycles. */
+ timeout.tv_sec = 2;
+ timeout.tv_usec = 0;
+ readfds = command_fds_to_drain;
+ switch (select (max_command_fd + 1, &readfds.fds,
+ NULL, NULL &timeout))
+ {
+ case -1:
+ if (errno != EINTR)
+ abort ();
+ case 0:
+ /* timeout */
+ break;
+ case 1:
+ for (i = 0; i <= max_command_fd; i++)
+ {
+ if (!FD_ISSET (i, &readfds.fds))
+ continue;
+ /* this fd is non-blocking */
+ while (read (i, buf, sizeof (buf)) >= 1)
+ ;
+ }
+ break;
+ default:
+ abort ();
+ }
+ }
+ }
+#endif /* SUNOS_KLUDGE */
+
+ /* Make sure our working directory isn't inside the tree we're
+ going to delete. */
+ CVS_CHDIR (get_cvs_tmp_dir ());
+
+ /* Temporarily clear noexec, so that we clean up our temp directory
+ regardless of it (this could more cleanly be handled by moving
+ the noexec check to all the unlink_file_dir callers from
+ unlink_file_dir itself). */
+ save_noexec = noexec;
+
+ /* SIG_beginCrSect(); */
+ noexec = 0;
+ unlink_file_dir (orig_server_temp_dir);
+ noexec = save_noexec;
+ /* SIG_endCrSect(); */
+ } /* !dont_delete_temp */
+
+ /* SIG_beginCrSect(); */
+ if (buf_to_net != NULL)
+ {
+ /* Save BUF_TO_NET and set the global pointer to NULL so that any
+ * error messages generated during shutdown go to the syslog rather
+ * than getting lost.
+ */
+ struct buffer *buf_to_net_save = buf_to_net;
+ buf_to_net = NULL;
+
+ (void) buf_flush (buf_to_net_save, 1);
+ (void) buf_shutdown (buf_to_net_save);
+ buf_free (buf_to_net_save);
+ error_use_protocol = 0;
+ }
+ /* SIG_endCrSect(); */
+ }
+
+ server_active = 0;
+}
+
+
+
+#ifdef PROXY_SUPPORT
+size_t MaxProxyBufferSize = (size_t)(8 * 1024 * 1024); /* 8 megabytes,
+ * by default.
+ */
+#endif /* PROXY_SUPPORT */
+
+static const char *const server_usage[] =
+{
+ "Usage: %s %s [-c config-file]\n",
+ "\t-c config-file\tPath to an alternative CVS config file.\n",
+ "Normally invoked by a cvs client on a remote machine.\n",
+ NULL
+};
+
+
+
+void
+parseServerOptions (int argc, char **argv)
+{
+ int c;
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+c:")) != -1)
+ {
+ switch (c)
+ {
+#ifdef ALLOW_CONFIG_OVERRIDE
+ case 'c':
+ if (gConfigPath) free (gConfigPath);
+ gConfigPath = xstrdup (optarg);
+ break;
+#endif
+ case '?':
+ default:
+ usage (server_usage);
+ break;
+ }
+ }
+}
+
+
+
+int
+server (int argc, char **argv)
+{
+ char *error_prog_name; /* Used in error messages */
+
+ if (argc == -1)
+ usage (server_usage);
+
+ /* Options were pre-parsed in main.c. */
+
+ /*
+ * Set this in .bashrc if you want to give yourself time to attach
+ * to the subprocess with a debugger.
+ */
+ if (getenv ("CVS_PARENT_SERVER_SLEEP"))
+ {
+ int secs = atoi (getenv ("CVS_PARENT_SERVER_SLEEP"));
+ TRACE (TRACE_DATA, "Sleeping CVS_PARENT_SERVER_SLEEP (%d) seconds",
+ secs);
+ sleep (secs);
+ }
+ else
+ TRACE (TRACE_DATA, "CVS_PARENT_SERVER_SLEEP not set.");
+
+ /* pserver_authenticate_connection () (called from main ()) can initialize
+ * these.
+ */
+ if (!buf_to_net)
+ {
+ buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0, NULL, false,
+ outbuf_memory_error);
+ buf_from_net = fd_buffer_initialize (STDIN_FILENO, 0, NULL, true,
+ outbuf_memory_error);
+ }
+
+ setup_logfiles ("CVS_SERVER_LOG", &buf_to_net, &buf_from_net);
+
+#ifdef PROXY_SUPPORT
+ /* We have to set up the recording for all servers. Until we receive the
+ * `Root' request and load CVSROOT/config, we can't tell if we are a
+ * secondary or primary.
+ */
+ {
+ /* Open the secondary log. */
+ buf_from_net = log_buffer_initialize (buf_from_net, NULL,
+# ifdef PROXY_SUPPORT
+ true,
+ config
+ ? config->MaxProxyBufferSize
+ : MaxProxyBufferSize,
+# endif /* PROXY_SUPPORT */
+ true, outbuf_memory_error);
+ proxy_log = buf_from_net;
+
+ /* And again for the out log. */
+ buf_to_net = log_buffer_initialize (buf_to_net, NULL,
+# ifdef PROXY_SUPPORT
+ true,
+ config
+ ? config->MaxProxyBufferSize
+ : MaxProxyBufferSize,
+# endif /* PROXY_SUPPORT */
+ false, outbuf_memory_error);
+ proxy_log_out = buf_to_net;
+ }
+#endif /* PROXY_SUPPORT */
+
+ saved_output = buf_nonio_initialize (outbuf_memory_error);
+ saved_outerr = buf_nonio_initialize (outbuf_memory_error);
+
+ /* Since we're in the server parent process, error should use the
+ protocol to report error messages. */
+ error_use_protocol = 1;
+
+ /* Now initialize our argument vector (for arguments from the client). */
+
+ /* Small for testing. */
+ argument_vector_size = 1;
+ argument_vector = xmalloc (argument_vector_size * sizeof (char *));
+ argument_count = 1;
+ /* This gets printed if the client supports an option which the
+ server doesn't, causing the server to print a usage message.
+ FIXME: just a nit, I suppose, but the usage message the server
+ prints isn't literally true--it suggests "cvs server" followed
+ by options which are for a particular command. Might be nice to
+ say something like "client apparently supports an option not supported
+ by this server" or something like that instead of usage message. */
+ error_prog_name = xmalloc (strlen (program_name) + 8);
+ sprintf(error_prog_name, "%s server", program_name);
+ argument_vector[0] = error_prog_name;
+
+ while (1)
+ {
+ char *cmd, *orig_cmd;
+ struct request *rq;
+ int status;
+
+ status = buf_read_line (buf_from_net, &cmd, NULL);
+ if (status == -2)
+ {
+ buf_output0 (buf_to_net, "E Fatal server error, aborting.\n\
+error ENOMEM Virtual memory exhausted.\n");
+ break;
+ }
+ if (status != 0)
+ break;
+
+ orig_cmd = cmd;
+ for (rq = requests; rq->name != NULL; ++rq)
+ if (strncmp (cmd, rq->name, strlen (rq->name)) == 0)
+ {
+ int len = strlen (rq->name);
+ if (cmd[len] == '\0')
+ cmd += len;
+ else if (cmd[len] == ' ')
+ cmd += len + 1;
+ else
+ /*
+ * The first len characters match, but it's a different
+ * command. e.g. the command is "cooperate" but we matched
+ * "co".
+ */
+ continue;
+
+ if (!(rq->flags & RQ_ROOTLESS)
+ && current_parsed_root == NULL)
+ {
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E Protocol error: Root request missing");
+ }
+ else
+ {
+ if (config && config->MinCompressionLevel && !gzip_level
+ && !(rq->flags & RQ_ROOTLESS))
+ {
+ /* This is a rootless request, a minimum compression
+ * level has been configured, and no compression has
+ * been requested by the client.
+ */
+ if (alloc_pending (80 + strlen (program_name)))
+ sprintf (pending_error_text,
+"E %s [server aborted]: Compression must be used with this server.",
+ program_name);
+ }
+ (*rq->func) (cmd);
+ }
+ break;
+ }
+ if (rq->name == NULL)
+ {
+ if (!print_pending_error ())
+ {
+ buf_output0 (buf_to_net, "error unrecognized request `");
+ buf_output0 (buf_to_net, cmd);
+ buf_append_char (buf_to_net, '\'');
+ buf_append_char (buf_to_net, '\n');
+ }
+ }
+ free (orig_cmd);
+ }
+
+ free (error_prog_name);
+
+ /* We expect the client is done talking to us at this point. If there is
+ * any data in the buffer or on the network pipe, then something we didn't
+ * prepare for is happening.
+ */
+ if (!buf_empty (buf_from_net))
+ {
+ /* Try to send the error message to the client, but also syslog it, in
+ * case the client isn't listening anymore.
+ */
+#ifdef HAVE_SYSLOG_H
+ /* FIXME: Can the IP address of the connecting client be retrieved
+ * and printed here?
+ */
+ syslog (LOG_DAEMON | LOG_ERR, "Dying gasps received from client.");
+#endif /* HAVE_SYSLOG_H */
+ error (0, 0, "Dying gasps received from client.");
+ }
+
+#ifdef HAVE_PAM
+ if (pamh)
+ {
+ int retval;
+
+ retval = pam_close_session (pamh, 0);
+# ifdef HAVE_SYSLOG_H
+ if (retval != PAM_SUCCESS)
+ syslog (LOG_DAEMON | LOG_ERR,
+ "PAM close session error: %s",
+ pam_strerror (pamh, retval));
+# endif /* HAVE_SYSLOG_H */
+
+ retval = pam_end (pamh, retval);
+# ifdef HAVE_SYSLOG_H
+ if (retval != PAM_SUCCESS)
+ syslog (LOG_DAEMON | LOG_ERR,
+ "PAM failed to release authenticator, error: %s",
+ pam_strerror (pamh, retval));
+# endif /* HAVE_SYSLOG_H */
+ }
+#endif /* HAVE_PAM */
+
+ /* server_cleanup() will be called on a normal exit and close the buffers
+ * explicitly.
+ */
+ return 0;
+}
+
+
+
+#if defined (HAVE_KERBEROS) || defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
+static void
+switch_to_user (const char *cvs_username, const char *username)
+{
+ struct passwd *pw;
+#ifdef HAVE_PAM
+ int retval;
+ char *pam_stage = "open session";
+
+ if (pamh)
+ {
+ retval = pam_open_session (pamh, 0);
+ if (retval == PAM_SUCCESS)
+ {
+ pam_stage = "get pam user";
+ retval = pam_get_item (pamh, PAM_USER, (const void **)&username);
+ }
+
+ if (retval != PAM_SUCCESS)
+ {
+ printf("E PAM %s error: %s\n", pam_stage,
+ pam_strerror (pamh, retval));
+ exit (EXIT_FAILURE);
+ }
+ }
+#endif
+
+ pw = getpwnam (username);
+ if (pw == NULL)
+ {
+ /* check_password contains a similar check, so this usually won't be
+ reached unless the CVS user is mapped to an invalid system user. */
+
+ printf ("E Fatal error, aborting.\n\
+error 0 %s: no such system user\n", username);
+ exit (EXIT_FAILURE);
+ }
+
+ if (pw->pw_uid == 0)
+ {
+#ifdef HAVE_SYSLOG_H
+ /* FIXME: Can the IP address of the connecting client be retrieved
+ * and printed here?
+ */
+ syslog (LOG_DAEMON | LOG_ALERT,
+ "attempt to root from account: %s", cvs_username
+ );
+#endif /* HAVE_SYSLOG_H */
+ printf("error 0: root not allowed\n");
+ exit (EXIT_FAILURE);
+ }
+
+#if HAVE_INITGROUPS
+ if (initgroups (pw->pw_name, pw->pw_gid) < 0
+# ifdef EPERM
+ /* At least on the system I tried, initgroups() only works as root.
+ But we do still want to report ENOMEM and whatever other
+ errors initgroups() might dish up. */
+ && errno != EPERM
+# endif
+ )
+ {
+ /* This could be a warning, but I'm not sure I see the point
+ in doing that instead of an error given that it would happen
+ on every connection. We could log it somewhere and not tell
+ the user. But at least for now make it an error. */
+ printf ("error 0 initgroups failed: %s\n", strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+#endif /* HAVE_INITGROUPS */
+
+#ifdef HAVE_PAM
+ if (pamh)
+ {
+ retval = pam_setcred (pamh, PAM_ESTABLISH_CRED);
+ if (retval != PAM_SUCCESS)
+ {
+ printf("E PAM reestablish credentials error: %s\n",
+ pam_strerror (pamh, retval));
+ exit (EXIT_FAILURE);
+ }
+ }
+#endif
+
+#ifdef SETXID_SUPPORT
+ /* honor the setgid bit iff set*/
+ if (getgid() != getegid())
+ {
+ if (setgid (getegid ()) < 0)
+ {
+ /* See comments at setuid call below for more discussion. */
+ printf ("error 0 setgid failed: %s\n", strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+ }
+ else
+#endif
+ {
+ if (setgid (pw->pw_gid) < 0)
+ {
+ /* See comments at setuid call below for more discussion. */
+ printf ("error 0 setgid failed: %s\n", strerror (errno));
+#ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_ERR,
+ "setgid to %d failed (%m): real %d/%d, effective %d/%d ",
+ pw->pw_gid, getuid(), getgid(), geteuid(), getegid());
+#endif /* HAVE_SYSLOG_H */
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (setuid (pw->pw_uid) < 0)
+ {
+ /* Note that this means that if run as a non-root user,
+ CVSROOT/passwd must contain the user we are running as
+ (e.g. "joe:FsEfVcu:cvs" if run as "cvs" user). This seems
+ cleaner than ignoring the error like CVS 1.10 and older but
+ it does mean that some people might need to update their
+ CVSROOT/passwd file. */
+ printf ("error 0 setuid failed: %s\n", strerror (errno));
+#ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_ERR,
+ "setuid to %d failed (%m): real %d/%d, effective %d/%d ",
+ pw->pw_uid, getuid(), getgid(), geteuid(), getegid());
+#endif /* HAVE_SYSLOG_H */
+ exit (EXIT_FAILURE);
+ }
+
+ /* We don't want our umask to change file modes. The modes should
+ be set by the modes used in the repository, and by the umask of
+ the client. */
+ umask (0);
+
+#ifdef AUTH_SERVER_SUPPORT
+ /* Make sure our CVS_Username has been set. */
+ if (CVS_Username == NULL)
+ CVS_Username = xstrdup (username);
+#endif
+
+ /* Set LOGNAME, USER and CVS_USER in the environment, in case they
+ are already set to something else. */
+ setenv ("LOGNAME", username, 1);
+ setenv ("USER", username, 1);
+# ifdef AUTH_SERVER_SUPPORT
+ setenv ("CVS_USER", CVS_Username, 1);
+# endif
+}
+#endif
+
+#ifdef AUTH_SERVER_SUPPORT
+
+extern char *crypt (const char *, const char *);
+
+
+/*
+ * 0 means no entry found for this user.
+ * 1 means entry found and password matches (or found password is empty)
+ * 2 means entry found, but password does not match.
+ *
+ * If 1, host_user_ptr will be set to point at the system
+ * username (i.e., the "real" identity, which may or may not be the
+ * CVS username) of this user; caller may free this. Global
+ * CVS_Username will point at an allocated copy of cvs username (i.e.,
+ * the username argument below).
+ * kff todo: FIXME: last sentence is not true, it applies to caller.
+ */
+static int
+check_repository_password (char *username, char *password, char *repository, char **host_user_ptr)
+{
+ int retval = 0;
+ FILE *fp;
+ char *filename;
+ char *linebuf = NULL;
+ size_t linebuf_len;
+ int found_it = 0;
+ int namelen;
+
+ /* We don't use current_parsed_root->directory because it hasn't been
+ * set yet -- our `repository' argument came from the authentication
+ * protocol, not the regular CVS protocol.
+ */
+
+ filename = xmalloc (strlen (repository)
+ + 1
+ + strlen (CVSROOTADM)
+ + 1
+ + strlen (CVSROOTADM_PASSWD)
+ + 1);
+
+ (void) sprintf (filename, "%s/%s/%s", repository,
+ CVSROOTADM, CVSROOTADM_PASSWD);
+
+ fp = CVS_FOPEN (filename, "r");
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", filename);
+ free (filename);
+ return 0;
+ }
+
+ /* Look for a relevant line -- one with this user's name. */
+ namelen = strlen (username);
+ while (getline (&linebuf, &linebuf_len, fp) >= 0)
+ {
+ if ((strncmp (linebuf, username, namelen) == 0)
+ && (linebuf[namelen] == ':'))
+ {
+ found_it = 1;
+ break;
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", filename);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", filename);
+
+ /* If found_it, then linebuf contains the information we need. */
+ if (found_it)
+ {
+ char *found_password, *host_user_tmp;
+ char *non_cvsuser_portion;
+
+ /* We need to make sure lines such as
+ *
+ * "username::sysuser\n"
+ * "username:\n"
+ * "username: \n"
+ *
+ * all result in a found_password of NULL, but we also need to
+ * make sure that
+ *
+ * "username: :sysuser\n"
+ * "username: <whatever>:sysuser\n"
+ *
+ * continues to result in an impossible password. That way,
+ * an admin would be on safe ground by going in and tacking a
+ * space onto the front of a password to disable the account
+ * (a technique some people use to close accounts
+ * temporarily).
+ */
+
+ /* Make `non_cvsuser_portion' contain everything after the CVS
+ username, but null out any final newline. */
+ non_cvsuser_portion = linebuf + namelen;
+ strtok (non_cvsuser_portion, "\n");
+
+ /* If there's a colon now, we just want to inch past it. */
+ if (strchr (non_cvsuser_portion, ':') == non_cvsuser_portion)
+ non_cvsuser_portion++;
+
+ /* Okay, after this conditional chain, found_password and
+ host_user_tmp will have useful values: */
+
+ if ((non_cvsuser_portion == NULL)
+ || (strlen (non_cvsuser_portion) == 0)
+ || ((strspn (non_cvsuser_portion, " \t"))
+ == strlen (non_cvsuser_portion)))
+ {
+ found_password = NULL;
+ host_user_tmp = NULL;
+ }
+ else if (strncmp (non_cvsuser_portion, ":", 1) == 0)
+ {
+ found_password = NULL;
+ host_user_tmp = non_cvsuser_portion + 1;
+ if (strlen (host_user_tmp) == 0)
+ host_user_tmp = NULL;
+ }
+ else
+ {
+ found_password = strtok (non_cvsuser_portion, ":");
+ host_user_tmp = strtok (NULL, ":");
+ }
+
+ /* Of course, maybe there was no system user portion... */
+ if (host_user_tmp == NULL)
+ host_user_tmp = username;
+
+ /* Verify blank passwords directly, otherwise use crypt(). */
+ if ((found_password == NULL)
+ || ((strcmp (found_password, crypt (password, found_password))
+ == 0)))
+ {
+ /* Give host_user_ptr permanent storage. */
+ *host_user_ptr = xstrdup (host_user_tmp);
+ retval = 1;
+ }
+ else
+ {
+#ifdef LOG_AUTHPRIV
+ syslog (LOG_AUTHPRIV | LOG_NOTICE,
+ "password mismatch for %s in %s: %s vs. %s", username,
+ repository, crypt(password, found_password), found_password);
+#endif
+ *host_user_ptr = NULL;
+ retval = 2;
+ }
+ }
+ else /* Didn't find this user, so deny access. */
+ {
+ *host_user_ptr = NULL;
+ retval = 0;
+ }
+
+ free (filename);
+ if (linebuf)
+ free (linebuf);
+
+ return retval;
+}
+
+#ifdef HAVE_PAM
+
+static int
+cvs_pam_conv (int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+{
+ int i;
+ struct pam_response *response;
+
+ assert (msg && resp);
+
+ response = xnmalloc (num_msg, sizeof (struct pam_response));
+ memset (response, 0, num_msg * sizeof (struct pam_response));
+
+ for (i = 0; i < num_msg; i++)
+ {
+ switch (msg[i]->msg_style)
+ {
+ /* PAM wants a username */
+ case PAM_PROMPT_ECHO_ON:
+ assert (pam_username != 0);
+ response[i].resp = xstrdup (pam_username);
+ break;
+ /* PAM wants a password */
+ case PAM_PROMPT_ECHO_OFF:
+ assert (pam_password != 0);
+ response[i].resp = xstrdup (pam_password);
+ break;
+ case PAM_ERROR_MSG:
+ case PAM_TEXT_INFO:
+ printf ("E %s\n", msg[i]->msg);
+ break;
+ /* PAM wants something we don't understand - bail out */
+ default:
+ goto cleanup;
+ }
+ }
+
+ *resp = response;
+ return PAM_SUCCESS;
+
+cleanup:
+ for (i = 0; i < num_msg; i++)
+ {
+ if (response[i].resp)
+ {
+ free (response[i].resp);
+ response[i].resp = 0;
+ }
+ }
+ free (response);
+ return PAM_CONV_ERR;
+}
+
+static int
+check_pam_password (char **username, char *password)
+{
+ int retval, err;
+ struct pam_conv conv = { cvs_pam_conv, 0 };
+ char *pam_stage = "start";
+
+ pam_username = *username;
+ pam_password = password;
+
+ retval = pam_start (PAM_SERVICE_NAME, *username, &conv, &pamh);
+
+ /* sets a dummy tty name which pam modules can check for */
+ if (retval == PAM_SUCCESS)
+ {
+ pam_stage = "set dummy tty";
+ retval = pam_set_item (pamh, PAM_TTY, PAM_SERVICE_NAME);
+ }
+
+ if (retval == PAM_SUCCESS)
+ {
+ pam_stage = "authenticate";
+ retval = pam_authenticate (pamh, 0);
+ }
+
+ if (retval == PAM_SUCCESS)
+ {
+ pam_stage = "account";
+ retval = pam_acct_mgmt (pamh, 0);
+ }
+
+ if (retval == PAM_SUCCESS)
+ {
+ pam_stage = "get pam user";
+ retval = pam_get_item (pamh, PAM_USER, (const void **)username);
+ }
+
+ if (retval != PAM_SUCCESS)
+ printf ("E PAM %s error: %s\n", pam_stage, pam_strerror (pamh, retval));
+
+ /* clear the pointers to make sure we don't use these references again */
+ pam_username = 0;
+ pam_password = 0;
+
+ return retval == PAM_SUCCESS; /* indicate success */
+}
+#endif
+
+static int
+check_system_password (char *username, char *password)
+{
+ char *found_passwd = NULL;
+ struct passwd *pw;
+#ifdef HAVE_GETSPNAM
+ {
+ struct spwd *spw;
+
+ spw = getspnam (username);
+ if (spw != NULL)
+ found_passwd = spw->sp_pwdp;
+ }
+#endif
+
+ if (found_passwd == NULL && (pw = getpwnam (username)) != NULL)
+ found_passwd = pw->pw_passwd;
+
+ if (found_passwd == NULL)
+ {
+ printf ("E Fatal error, aborting.\n\
+error 0 %s: no such user\n", username);
+
+ exit (EXIT_FAILURE);
+ }
+
+ /* Allow for dain bramaged HPUX passwd aging
+ * - Basically, HPUX adds a comma and some data
+ * about whether the passwd has expired or not
+ * on the end of the passwd field.
+ * - This code replaces the ',' with '\0'.
+ *
+ * FIXME - our workaround is brain damaged too. I'm
+ * guessing that HPUX WANTED other systems to think the
+ * password was wrong so logins would fail if the
+ * system didn't handle expired passwds and the passwd
+ * might be expired. I think the way to go here
+ * is with PAM.
+ */
+ strtok (found_passwd, ",");
+
+ if (*found_passwd)
+ {
+ /* user exists and has a password */
+ if (strcmp (found_passwd, crypt (password, found_passwd)) == 0)
+ return 1;
+ else
+ {
+#ifdef LOG_AUTHPRIV
+ syslog (LOG_AUTHPRIV | LOG_NOTICE,
+ "password mismatch for %s: %s vs. %s", username,
+ crypt(password, found_passwd), found_passwd);
+#endif
+ return 0;
+ }
+ }
+
+#ifdef LOG_AUTHPRIV
+ syslog (LOG_AUTHPRIV | LOG_NOTICE,
+ "user %s authenticated because of blank system password",
+ username);
+#endif
+ return 1;
+}
+
+
+
+/* Return a hosting username if password matches, else NULL. */
+static char *
+check_password (char *username, char *password, char *repository)
+{
+ int rc;
+ char *host_user = NULL;
+
+ /* First we see if this user has a password in the CVS-specific
+ password file. If so, that's enough to authenticate with. If
+ not, we'll check /etc/passwd or maybe whatever is configured via PAM. */
+
+ rc = check_repository_password (username, password, repository,
+ &host_user);
+
+ if (rc == 2)
+ return NULL;
+
+ if (rc == 1)
+ /* host_user already set by reference, so just return. */
+ goto handle_return;
+
+ assert (rc == 0);
+
+ if (!config->system_auth)
+ {
+ /* Note that the message _does_ distinguish between the case in
+ which we check for a system password and the case in which
+ we do not. It is a real pain to track down why it isn't
+ letting you in if it won't say why, and I am not convinced
+ that the potential information disclosure to an attacker
+ outweighs this. */
+ printf ("error 0 no such user %s in CVSROOT/passwd\n", username);
+
+ exit (EXIT_FAILURE);
+ }
+
+ /* No cvs password found, so try /etc/passwd. */
+#ifdef HAVE_PAM
+ if (check_pam_password (&username, password))
+#else /* !HAVE_PAM */
+ if (check_system_password (username, password))
+#endif /* HAVE_PAM */
+ host_user = xstrdup (username);
+ else
+ host_user = NULL;
+
+#ifdef LOG_AUTHPRIV
+ if (!host_user)
+ syslog (LOG_AUTHPRIV | LOG_NOTICE,
+ "login refused for %s: user has no password", username);
+#endif
+
+handle_return:
+ if (host_user)
+ {
+ /* Set CVS_Username here, in allocated space.
+ It might or might not be the same as host_user. */
+ CVS_Username = xmalloc (strlen (username) + 1);
+ strcpy (CVS_Username, username);
+ }
+
+ return host_user;
+}
+
+#endif /* AUTH_SERVER_SUPPORT */
+
+#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
+
+static void
+pserver_read_line (char **tmp, size_t *tmp_len)
+{
+ int status;
+
+ /* Make sure the protocol starts off on the right foot... */
+ status = buf_read_short_line (buf_from_net, tmp, tmp_len, PATH_MAX);
+ if (status == -1)
+ {
+# ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_NOTICE,
+ "unexpected EOF encountered during authentication");
+# endif /* HAVE_SYSLOG_H */
+ error (1, 0, "unexpected EOF encountered during authentication");
+ }
+ if (status == -2)
+ status = ENOMEM;
+ if (status != 0)
+ {
+# ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_NOTICE,
+ "error reading from net while validating pserver");
+# endif /* HAVE_SYSLOG_H */
+ error (1, status, "error reading from net while validating pserver");
+ }
+}
+
+/* Read username and password from client (i.e., stdin).
+ If correct, then switch to run as that user and send an ACK to the
+ client via stdout, else send NACK and die. */
+void
+pserver_authenticate_connection (void)
+{
+ char *tmp;
+#ifdef AUTH_SERVER_SUPPORT
+ char *repository = NULL;
+ char *username = NULL;
+ char *password = NULL;
+
+ char *host_user;
+ char *descrambled_password;
+#endif /* AUTH_SERVER_SUPPORT */
+ int verify_and_exit = 0;
+
+ /* The Authentication Protocol. Client sends:
+ *
+ * BEGIN AUTH REQUEST\n
+ * <REPOSITORY>\n
+ * <USERNAME>\n
+ * <PASSWORD>\n
+ * END AUTH REQUEST\n
+ *
+ * Server uses above information to authenticate, then sends
+ *
+ * I LOVE YOU\n
+ *
+ * if it grants access, else
+ *
+ * I HATE YOU\n
+ *
+ * if it denies access (and it exits if denying).
+ *
+ * When the client is "cvs login", the user does not desire actual
+ * repository access, but would like to confirm the password with
+ * the server. In this case, the start and stop strings are
+ *
+ * BEGIN VERIFICATION REQUEST\n
+ *
+ * and
+ *
+ * END VERIFICATION REQUEST\n
+ *
+ * On a verification request, the server's responses are the same
+ * (with the obvious semantics), but it exits immediately after
+ * sending the response in both cases.
+ *
+ * Why is the repository sent? Well, note that the actual
+ * client/server protocol can't start up until authentication is
+ * successful. But in order to perform authentication, the server
+ * needs to look up the password in the special CVS passwd file,
+ * before trying /etc/passwd. So the client transmits the
+ * repository as part of the "authentication protocol". The
+ * repository will be redundantly retransmitted later, but that's no
+ * big deal.
+ */
+
+ /* Initialize buffers. */
+ buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0, NULL, false,
+ outbuf_memory_error);
+ buf_from_net = fd_buffer_initialize (STDIN_FILENO, 0, NULL, true,
+ outbuf_memory_error);
+
+#ifdef SO_KEEPALIVE
+ /* Set SO_KEEPALIVE on the socket, so that we don't hang forever
+ if the client dies while we are waiting for input. */
+ {
+ int on = 1;
+
+ if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
+ &on, sizeof on) < 0)
+ {
+# ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m");
+# endif /* HAVE_SYSLOG_H */
+ }
+ }
+#endif
+
+ /* Make sure the protocol starts off on the right foot... */
+ pserver_read_line (&tmp, NULL);
+
+ if (strcmp (tmp, "BEGIN VERIFICATION REQUEST") == 0)
+ verify_and_exit = 1;
+ else if (strcmp (tmp, "BEGIN AUTH REQUEST") == 0)
+ ;
+ else if (strcmp (tmp, "BEGIN GSSAPI REQUEST") == 0)
+ {
+#ifdef HAVE_GSSAPI
+ free (tmp);
+ gserver_authenticate_connection ();
+ return;
+#else
+ error (1, 0, "GSSAPI authentication not supported by this server");
+#endif
+ }
+ else
+ error (1, 0, "bad auth protocol start: %s", tmp);
+
+#ifndef AUTH_SERVER_SUPPORT
+
+ error (1, 0, "Password authentication not supported by this server");
+
+#else /* AUTH_SERVER_SUPPORT */
+
+ free (tmp);
+
+ /* Get the three important pieces of information in order. */
+ /* See above comment about error handling. */
+ pserver_read_line (&repository, NULL);
+ pserver_read_line (&username, NULL);
+ pserver_read_line (&password, NULL);
+
+ /* ... and make sure the protocol ends on the right foot. */
+ /* See above comment about error handling. */
+ pserver_read_line (&tmp, NULL);
+ if (strcmp (tmp,
+ verify_and_exit ?
+ "END VERIFICATION REQUEST" : "END AUTH REQUEST")
+ != 0)
+ {
+ error (1, 0, "bad auth protocol end: %s", tmp);
+ }
+ free (tmp);
+
+ if (!root_allow_ok (repository))
+ {
+ error (1, 0, "%s: no such repository", repository);
+# ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_NOTICE, "login refused for %s", repository);
+# endif /* HAVE_SYSLOG_H */
+ goto i_hate_you;
+ }
+
+ /* OK, now parse the config file, so we can use it to control how
+ to check passwords. If there was an error parsing the config
+ file, parse_config already printed an error. We keep going.
+ Why? Because if we didn't, then there would be no way to check
+ in a new CVSROOT/config file to fix the broken one! */
+ config = get_root_allow_config (repository, gConfigPath);
+
+ /* We need the real cleartext before we hash it. */
+ descrambled_password = descramble (password);
+ host_user = check_password (username, descrambled_password, repository);
+ if (host_user == NULL)
+ {
+# ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_NOTICE, "login failure (for %s)", repository);
+# endif /* HAVE_SYSLOG_H */
+ memset (descrambled_password, 0, strlen (descrambled_password));
+ free (descrambled_password);
+ i_hate_you:
+ buf_output0 (buf_to_net, "I HATE YOU\n");
+ buf_flush (buf_to_net, true);
+
+ /* Don't worry about server_cleanup, server_active isn't set
+ yet. */
+ exit (EXIT_FAILURE);
+ }
+ memset (descrambled_password, 0, strlen (descrambled_password));
+ free (descrambled_password);
+
+ /* Don't go any farther if we're just responding to "cvs login". */
+ if (verify_and_exit)
+ {
+ buf_output0 (buf_to_net, "I LOVE YOU\n");
+ buf_flush (buf_to_net, true);
+ exit (EXIT_SUCCESS);
+ }
+
+ /* Set Pserver_Repos so that we can check later that the same
+ repository is sent in later client/server protocol. */
+ Pserver_Repos = xmalloc (strlen (repository) + 1);
+ strcpy (Pserver_Repos, repository);
+
+ /* Switch to run as this user. */
+ switch_to_user (username, host_user);
+ free (host_user);
+ free (repository);
+ free (username);
+ free (password);
+
+ buf_output0 (buf_to_net, "I LOVE YOU\n");
+ buf_flush (buf_to_net, true);
+#endif /* AUTH_SERVER_SUPPORT */
+}
+
+#endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
+
+
+#ifdef HAVE_KERBEROS
+void
+kserver_authenticate_connection( void )
+{
+ int status;
+ char instance[INST_SZ];
+ struct sockaddr_in peer;
+ struct sockaddr_in laddr;
+ int len;
+ KTEXT_ST ticket;
+ AUTH_DAT auth;
+ char version[KRB_SENDAUTH_VLEN];
+ char user[ANAME_SZ];
+
+ strcpy (instance, "*");
+ len = sizeof peer;
+ if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0
+ || getsockname (STDIN_FILENO, (struct sockaddr *) &laddr,
+ &len) < 0)
+ {
+ printf ("E Fatal error, aborting.\n\
+error %s getpeername or getsockname failed\n", strerror (errno));
+
+ exit (EXIT_FAILURE);
+ }
+
+#ifdef SO_KEEPALIVE
+ /* Set SO_KEEPALIVE on the socket, so that we don't hang forever
+ if the client dies while we are waiting for input. */
+ {
+ int on = 1;
+
+ if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
+ (char *) &on, sizeof on) < 0)
+ {
+# ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m");
+# endif /* HAVE_SYSLOG_H */
+ }
+ }
+#endif
+
+ status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd",
+ instance, &peer, &laddr, &auth, "", sched,
+ version);
+ if (status != KSUCCESS)
+ {
+ printf ("E Fatal error, aborting.\n\
+error 0 kerberos: %s\n", krb_get_err_text(status));
+
+ exit (EXIT_FAILURE);
+ }
+
+ memcpy (kblock, auth.session, sizeof (C_Block));
+
+ /* Get the local name. */
+ status = krb_kntoln (&auth, user);
+ if (status != KSUCCESS)
+ {
+ printf ("E Fatal error, aborting.\n"
+ "error 0 kerberos: can't get local name: %s\n",
+ krb_get_err_text(status));
+
+ exit (EXIT_FAILURE);
+ }
+
+ /* Switch to run as this user. */
+ switch_to_user ("Kerberos 4", user);
+}
+#endif /* HAVE_KERBEROS */
+
+
+
+# ifdef HAVE_GSSAPI /* && SERVER_SUPPORT */
+/* Authenticate a GSSAPI connection. This is called from
+ * pserver_authenticate_connection, and it handles success and failure
+ * the same way.
+ *
+ * GLOBALS
+ * server_hostname The name of this host, as set via a call to
+ * xgethostname() in main().
+ */
+static void
+gserver_authenticate_connection (void)
+{
+ char *hn;
+ gss_buffer_desc tok_in, tok_out;
+ char buf[1024];
+ char *credbuf;
+ size_t credbuflen;
+ OM_uint32 stat_min, ret;
+ gss_name_t server_name, client_name;
+ gss_cred_id_t server_creds;
+ int nbytes;
+ gss_OID mechid;
+
+ hn = canon_host (server_hostname);
+ if (!hn)
+ error (1, 0, "can't get canonical hostname for `%s': %s",
+ server_hostname, ch_strerror ());
+
+ sprintf (buf, "cvs@%s", hn);
+ free (hn);
+ tok_in.value = buf;
+ tok_in.length = strlen (buf);
+
+ if (gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE,
+ &server_name) != GSS_S_COMPLETE)
+ error (1, 0, "could not import GSSAPI service name %s", buf);
+
+ /* Acquire the server credential to verify the client's
+ authentication. */
+ if (gss_acquire_cred (&stat_min, server_name, 0, GSS_C_NULL_OID_SET,
+ GSS_C_ACCEPT, &server_creds,
+ NULL, NULL) != GSS_S_COMPLETE)
+ error (1, 0, "could not acquire GSSAPI server credentials");
+
+ gss_release_name (&stat_min, &server_name);
+
+ /* The client will send us a two byte length followed by that many
+ bytes. */
+ if (fread (buf, 1, 2, stdin) != 2)
+ error (1, errno, "read of length failed");
+
+ nbytes = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff);
+ if (nbytes <= sizeof buf)
+ {
+ credbuf = buf;
+ credbuflen = sizeof buf;
+ }
+ else
+ {
+ credbuflen = nbytes;
+ credbuf = xmalloc (credbuflen);
+ }
+
+ if (fread (credbuf, 1, nbytes, stdin) != nbytes)
+ error (1, errno, "read of data failed");
+
+ gcontext = GSS_C_NO_CONTEXT;
+ tok_in.length = nbytes;
+ tok_in.value = credbuf;
+
+ if (gss_accept_sec_context (&stat_min,
+ &gcontext, /* context_handle */
+ server_creds, /* verifier_cred_handle */
+ &tok_in, /* input_token */
+ NULL, /* channel bindings */
+ &client_name, /* src_name */
+ &mechid, /* mech_type */
+ &tok_out, /* output_token */
+ &ret,
+ NULL, /* ignore time_rec */
+ NULL) /* ignore del_cred_handle */
+ != GSS_S_COMPLETE)
+ {
+ error (1, 0, "could not verify credentials");
+ }
+
+ /* FIXME: Use Kerberos v5 specific code to authenticate to a user.
+ We could instead use an authentication to access mapping. */
+ {
+ krb5_context kc;
+ krb5_principal p;
+ gss_buffer_desc desc;
+
+ krb5_init_context (&kc);
+ if (gss_display_name (&stat_min, client_name, &desc,
+ &mechid) != GSS_S_COMPLETE
+ || krb5_parse_name (kc, ((gss_buffer_t) &desc)->value, &p) != 0
+ || krb5_aname_to_localname (kc, p, sizeof buf, buf) != 0
+ || krb5_kuserok (kc, p, buf) != TRUE)
+ {
+ error (1, 0, "access denied");
+ }
+ krb5_free_principal (kc, p);
+ krb5_free_context (kc);
+ }
+
+ if (tok_out.length != 0)
+ {
+ char cbuf[2];
+
+ cbuf[0] = (tok_out.length >> 8) & 0xff;
+ cbuf[1] = tok_out.length & 0xff;
+ if (fwrite (cbuf, 1, 2, stdout) != 2
+ || (fwrite (tok_out.value, 1, tok_out.length, stdout)
+ != tok_out.length))
+ error (1, errno, "fwrite failed");
+ }
+
+ switch_to_user ("GSSAPI", buf);
+
+ if (credbuf != buf)
+ free (credbuf);
+
+ printf ("I LOVE YOU\n");
+ fflush (stdout);
+}
+
+# endif /* HAVE_GSSAPI */
+
+#endif /* SERVER_SUPPORT */
+
+#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
+
+/* This global variable is non-zero if the user requests encryption on
+ the command line. */
+int cvsencrypt;
+
+/* This global variable is non-zero if the users requests stream
+ authentication on the command line. */
+int cvsauthenticate;
+
+#ifdef ENCRYPTION
+
+#ifdef HAVE_KERBEROS
+
+/* An encryption interface using Kerberos. This is built on top of a
+ packetizing buffer. */
+
+/* This structure is the closure field of the Kerberos translation
+ routines. */
+struct krb_encrypt_data
+{
+ /* The Kerberos key schedule. */
+ Key_schedule sched;
+ /* The Kerberos DES block. */
+ C_Block block;
+};
+
+
+
+/* Decrypt Kerberos data. */
+static int
+krb_encrypt_input( void *fnclosure, const char *input, char *output, int size )
+{
+ struct krb_encrypt_data *kd = (struct krb_encrypt_data *) fnclosure;
+ int tcount;
+
+ des_cbc_encrypt ((C_Block *) input, (C_Block *) output,
+ size, kd->sched, &kd->block, 0);
+
+ /* SIZE is the size of the buffer, which is set by the encryption
+ routine. The packetizing buffer will arrange for the first two
+ bytes in the decrypted buffer to be the real (unaligned)
+ length. As a safety check, make sure that the length in the
+ buffer corresponds to SIZE. Note that the length in the buffer
+ is just the length of the data. We must add 2 to account for
+ the buffer count itself. */
+ tcount = ((output[0] & 0xff) << 8) + (output[1] & 0xff);
+ if (((tcount + 2 + 7) & ~7) != size)
+ error (1, 0, "Decryption failure");
+
+ return 0;
+}
+
+
+
+/* Encrypt Kerberos data. */
+static int
+krb_encrypt_output( void *fnclosure, const char *input, char *output,
+ int size, int *translated )
+{
+ struct krb_encrypt_data *kd = (struct krb_encrypt_data *) fnclosure;
+ int aligned;
+
+ /* For security against a known plaintext attack, we should
+ initialize any padding bytes to random values. Instead, we
+ just pick up whatever is on the stack, which is at least better
+ than using zero. */
+
+ /* Align SIZE to an 8 byte boundary. Note that SIZE includes the
+ two byte buffer count at the start of INPUT which was added by
+ the packetizing buffer. */
+ aligned = (size + 7) & ~7;
+
+ /* We use des_cbc_encrypt rather than krb_mk_priv because the
+ latter sticks a timestamp in the block, and krb_rd_priv expects
+ that timestamp to be within five minutes of the current time.
+ Given the way the CVS server buffers up data, that can easily
+ fail over a long network connection. We trust krb_recvauth to
+ guard against a replay attack. */
+
+ des_cbc_encrypt ((C_Block *) input, (C_Block *) output, aligned,
+ kd->sched, &kd->block, 1);
+
+ *translated = aligned;
+
+ return 0;
+}
+
+
+
+/* Create a Kerberos encryption buffer. We use a packetizing buffer
+ with Kerberos encryption translation routines. */
+struct buffer *
+krb_encrypt_buffer_initialize( struct buffer *buf, int input,
+ Key_schedule sched, C_Block block,
+ void *memory( struct buffer * ) )
+{
+ struct krb_encrypt_data *kd;
+
+ kd = (struct krb_encrypt_data *) xmalloc (sizeof *kd);
+ memcpy (kd->sched, sched, sizeof (Key_schedule));
+ memcpy (kd->block, block, sizeof (C_Block));
+
+ return packetizing_buffer_initialize (buf,
+ input ? krb_encrypt_input : NULL,
+ input ? NULL : krb_encrypt_output,
+ kd,
+ memory);
+}
+
+#endif /* HAVE_KERBEROS */
+#endif /* ENCRYPTION */
+#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
+
+
+
+/* Output LEN bytes at STR. If LEN is zero, then output up to (not including)
+ the first '\0' byte. */
+void
+cvs_output (const char *str, size_t len)
+{
+ if (len == 0)
+ len = strlen (str);
+#ifdef SERVER_SUPPORT
+ if (error_use_protocol)
+ {
+ if (buf_to_net)
+ {
+ buf_output (saved_output, str, len);
+ buf_copy_lines (buf_to_net, saved_output, 'M');
+ }
+# if HAVE_SYSLOG_H
+ else
+ syslog (LOG_DAEMON | LOG_ERR,
+ "Attempt to write message after close of network buffer. "
+ "Message was: %s",
+ str);
+# endif /* HAVE_SYSLOG_H */
+ }
+ else if (server_active)
+ {
+ if (protocol)
+ {
+ buf_output (saved_output, str, len);
+ buf_copy_lines (protocol, saved_output, 'M');
+ buf_send_counted (protocol);
+ }
+# if HAVE_SYSLOG_H
+ else
+ syslog (LOG_DAEMON | LOG_ERR,
+ "Attempt to write message before initialization of "
+ "protocol buffer. Message was: %s",
+ str);
+# endif /* HAVE_SYSLOG_H */
+ }
+ else
+#endif
+ {
+ size_t written;
+ size_t to_write = len;
+ const char *p = str;
+
+ /* Local users that do 'cvs status 2>&1' on a local repository
+ may see the informational messages out-of-order with the
+ status messages unless we use the fflush (stderr) here. */
+ fflush (stderr);
+
+ while (to_write > 0)
+ {
+ written = fwrite (p, 1, to_write, stdout);
+ if (written == 0)
+ break;
+ p += written;
+ to_write -= written;
+ }
+ }
+}
+
+/* Output LEN bytes at STR in binary mode. If LEN is zero, then
+ output zero bytes. */
+
+void
+cvs_output_binary (char *str, size_t len)
+{
+#ifdef SERVER_SUPPORT
+ if (error_use_protocol || server_active)
+ {
+ struct buffer *buf;
+ char size_text[40];
+
+ if (error_use_protocol)
+ buf = buf_to_net;
+ else
+ buf = protocol;
+
+ assert (buf);
+
+ if (!supported_response ("Mbinary"))
+ {
+ error (0, 0, "\
+this client does not support writing binary files to stdout");
+ return;
+ }
+
+ buf_output0 (buf, "Mbinary\012");
+ sprintf (size_text, "%lu\012", (unsigned long) len);
+ buf_output0 (buf, size_text);
+
+ /* Not sure what would be involved in using buf_append_data here
+ without stepping on the toes of our caller (which is responsible
+ for the memory allocation of STR). */
+ buf_output (buf, str, len);
+
+ if (!error_use_protocol)
+ buf_send_counted (protocol);
+ }
+ else
+#endif
+ {
+ size_t written;
+ size_t to_write = len;
+ const char *p = str;
+#ifdef USE_SETMODE_STDOUT
+ int oldmode;
+#endif
+
+ /* Local users that do 'cvs status 2>&1' on a local repository
+ may see the informational messages out-of-order with the
+ status messages unless we use the fflush (stderr) here. */
+ fflush (stderr);
+
+#ifdef USE_SETMODE_STDOUT
+ /* It is possible that this should be the same ifdef as
+ USE_SETMODE_BINARY but at least for the moment we keep them
+ separate. Mostly this is just laziness and/or a question
+ of what has been tested where. Also there might be an
+ issue of setmode vs. _setmode. */
+ /* The Windows doc says to call setmode only right after startup.
+ I assume that what they are talking about can also be helped
+ by flushing the stream before changing the mode. */
+ fflush (stdout);
+ oldmode = _setmode (_fileno (stdout), OPEN_BINARY);
+ if (oldmode < 0)
+ error (0, errno, "failed to setmode on stdout");
+#endif
+
+ while (to_write > 0)
+ {
+ written = fwrite (p, 1, to_write, stdout);
+ if (written == 0)
+ break;
+ p += written;
+ to_write -= written;
+ }
+#ifdef USE_SETMODE_STDOUT
+ fflush (stdout);
+ if (_setmode (_fileno (stdout), oldmode) != OPEN_BINARY)
+ error (0, errno, "failed to setmode on stdout");
+#endif
+ }
+}
+
+
+
+/* Like CVS_OUTPUT but output is for stderr not stdout. */
+void
+cvs_outerr (const char *str, size_t len)
+{
+ if (len == 0)
+ len = strlen (str);
+#ifdef SERVER_SUPPORT
+ if (error_use_protocol)
+ {
+ if (buf_to_net)
+ {
+ buf_output (saved_outerr, str, len);
+ buf_copy_lines (buf_to_net, saved_outerr, 'E');
+ }
+# if HAVE_SYSLOG_H
+ else
+ syslog (LOG_DAEMON | LOG_ERR,
+ "Attempt to write error message after close of network "
+ "buffer. Message was: `%s'",
+ str);
+# endif /* HAVE_SYSLOG_H */
+ }
+ else if (server_active)
+ {
+ if (protocol)
+ {
+ buf_output (saved_outerr, str, len);
+ buf_copy_lines (protocol, saved_outerr, 'E');
+ buf_send_counted (protocol);
+ }
+# if HAVE_SYSLOG_H
+ else
+ syslog (LOG_DAEMON | LOG_ERR,
+ "Attempt to write error message before initialization of "
+ "protocol buffer. Message was: `%s'",
+ str);
+# endif /* HAVE_SYSLOG_H */
+ }
+ else
+#endif
+ {
+ size_t written;
+ size_t to_write = len;
+ const char *p = str;
+
+ /* Make sure that output appears in order if stdout and stderr
+ point to the same place. For the server case this is taken
+ care of by the fact that saved_outerr always holds less
+ than a line. */
+ fflush (stdout);
+
+ while (to_write > 0)
+ {
+ written = fwrite (p, 1, to_write, stderr);
+ if (written == 0)
+ break;
+ p += written;
+ to_write -= written;
+ }
+ }
+}
+
+
+
+/* Flush stderr. stderr is normally flushed automatically, of course,
+ but this function is used to flush information from the server back
+ to the client. */
+void
+cvs_flusherr (void)
+{
+#ifdef SERVER_SUPPORT
+ if (error_use_protocol)
+ {
+ /* skip the actual stderr flush in this case since the parent process
+ * on the server should only be writing to stdout anyhow
+ */
+ /* Flush what we can to the network, but don't block. */
+ buf_flush (buf_to_net, 0);
+ }
+ else if (server_active)
+ {
+ /* make sure stderr is flushed before we send the flush count on the
+ * protocol pipe
+ */
+ fflush (stderr);
+ /* Send a special count to tell the parent to flush. */
+ buf_send_special_count (protocol, -2);
+ }
+ else
+#endif
+ fflush (stderr);
+}
+
+
+
+/* Make it possible for the user to see what has been written to
+ stdout (it is up to the implementation to decide exactly how far it
+ should go to ensure this). */
+void
+cvs_flushout (void)
+{
+#ifdef SERVER_SUPPORT
+ if (error_use_protocol)
+ {
+ /* Flush what we can to the network, but don't block. */
+ buf_flush (buf_to_net, 0);
+ }
+ else if (server_active)
+ {
+ /* Just do nothing. This is because the code which
+ cvs_flushout replaces, setting stdout to line buffering in
+ main.c, didn't get called in the server child process. But
+ in the future it is quite plausible that we'll want to make
+ this case work analogously to cvs_flusherr.
+
+ FIXME - DRP - I tried to implement this and triggered the following
+ error: "Protocol error: uncounted data discarded". I don't need
+ this feature right now, so I'm not going to bother with it yet.
+ */
+ buf_send_special_count (protocol, -1);
+ }
+ else
+#endif
+ fflush (stdout);
+}
+
+
+
+/* Output TEXT, tagging it according to TAG. There are lots more
+ details about what TAG means in cvsclient.texi but for the simple
+ case (e.g. non-client/server), TAG is just "newline" to output a
+ newline (in which case TEXT must be NULL), and any other tag to
+ output normal text.
+
+ Note that there is no way to output either \0 or \n as part of TEXT. */
+
+void
+cvs_output_tagged (const char *tag, const char *text)
+{
+ if (text != NULL && strchr (text, '\n') != NULL)
+ /* Uh oh. The protocol has no way to cope with this. For now
+ we dump core, although that really isn't such a nice
+ response given that this probably can be caused by newlines
+ in filenames and other causes other than bugs in CVS. Note
+ that we don't want to turn this into "MT newline" because
+ this case is a newline within a tagged item, not a newline
+ as extraneous sugar for the user. */
+ assert (0);
+
+ /* Start and end tags don't take any text, per cvsclient.texi. */
+ if (tag[0] == '+' || tag[0] == '-')
+ assert (text == NULL);
+
+#ifdef SERVER_SUPPORT
+ if (server_active && supported_response ("MT"))
+ {
+ struct buffer *buf;
+
+ if (error_use_protocol)
+ buf = buf_to_net;
+ else
+ buf = protocol;
+
+ buf_output0 (buf, "MT ");
+ buf_output0 (buf, tag);
+ if (text != NULL)
+ {
+ buf_output (buf, " ", 1);
+ buf_output0 (buf, text);
+ }
+ buf_output (buf, "\n", 1);
+
+ if (!error_use_protocol)
+ buf_send_counted (protocol);
+ }
+ else
+#endif /* SERVER_SUPPORT */
+ {
+ /* No MT support or we are using a local repository. */
+ if (strcmp (tag, "newline") == 0)
+ cvs_output ("\n", 1);
+ else if (strcmp (tag, "date") == 0)
+ {
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ /* Output UTC when running as a server without MT support in
+ * the client since it is likely to be more meaningful than
+ * localtime.
+ */
+ cvs_output (text, 0);
+ else
+#endif /* SERVER_SUPPORT */
+ {
+ char *date_in = xstrdup (text);
+ char *date = format_date_alloc (date_in);
+ cvs_output (date, 0);
+ free (date);
+ free (date_in);
+ }
+ }
+ else if (text != NULL)
+ cvs_output (text, 0);
+ }
+}
+
+
+
+/*
+ * void cvs_trace(int level, const char *fmt, ...)
+ *
+ * Print tracing information to stderr on request. Levels are implemented
+ * as with CVSNT.
+ */
+void
+cvs_trace (int level, const char *fmt, ...)
+{
+ if (trace >= level)
+ {
+ va_list va;
+
+ va_start (va, fmt);
+#ifdef SERVER_SUPPORT
+ fprintf (stderr,"%c -> ",server_active?(isProxyServer()?'P':'S'):' ');
+#else /* ! SERVER_SUPPORT */
+ fprintf (stderr," -> ");
+#endif
+ vfprintf (stderr, fmt, va);
+ fprintf (stderr,"\n");
+ va_end (va);
+ }
+}
diff --git a/src/server.h b/src/server.h
new file mode 100644
index 0000000..8819dea
--- /dev/null
+++ b/src/server.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS kit.
+ *
+ *
+ *
+ * This file contains the interface between the server and the rest of CVS.
+ */
+
+/* Miscellaneous stuff which isn't actually particularly server-specific. */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#endif
+
+
+/*
+ * Nonzero if we are using the server. Used by various places to call
+ * server-specific functions.
+ */
+extern int server_active;
+
+/*
+ * Expand to `S', ` ', or the empty string. Used in `%s-> ...' trace printfs.
+ */
+#ifdef SERVER_SUPPORT
+# define CLIENT_SERVER_STR ((server_active) ? "S" : " ")
+#else
+# define CLIENT_SERVER_STR ""
+#endif
+
+#ifdef SERVER_SUPPORT
+
+/* Server functions exported to the rest of CVS. */
+
+/* pre-parse the server options. */
+void parseServerOptions (int argc, char **argv);
+
+/* Run the server. */
+int server (int argc, char **argv);
+
+/* kserver user authentication. */
+# ifdef HAVE_KERBEROS
+void kserver_authenticate_connection (void);
+# endif
+
+/* pserver user authentication. */
+# if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
+void pserver_authenticate_connection (void);
+# endif
+
+/* See server.c for description. */
+void server_pathname_check (char *);
+
+/* We have a new Entries line for a file. TAG or DATE can be NULL. */
+void server_register (const char *name, const char *version,
+ const char *timestamp, const char *options,
+ const char *tag, const char *date, const char *conflict);
+
+/* Set the modification time of the next file sent. This must be
+ followed by a call to server_updated on the same file. */
+void server_modtime (struct file_info *finfo, Vers_TS *vers_ts);
+
+/*
+ * We want to nuke the Entries line for a file, and (unless
+ * server_scratch_entry_only is subsequently called) the file itself.
+ */
+void server_scratch (const char *name);
+
+/*
+ * The file which just had server_scratch called on it needs to have only
+ * the Entries line removed, not the file itself.
+ */
+void server_scratch_entry_only (void);
+
+/*
+ * We just successfully checked in FILE (which is just the bare
+ * filename, with no directory). REPOSITORY is the directory for the
+ * repository.
+ */
+void server_checked_in (const char *file, const char *update_dir,
+ const char *repository);
+
+void server_copy_file (const char *file, const char *update_dir,
+ const char *repository, const char *newfile);
+
+/* Send the appropriate responses for a file described by FINFO and
+ VERS. This is called after server_register or server_scratch. In
+ the latter case the file is to be removed (and VERS can be NULL).
+ In the former case, VERS must be non-NULL, and UPDATED indicates
+ whether the file is now up to date (SERVER_UPDATED, yes,
+ SERVER_MERGED, no, SERVER_PATCHED, yes, but file is a diff from
+ user version to repository version, SERVER_RCS_DIFF, yes, like
+ SERVER_PATCHED but with an RCS style diff). MODE is the mode the
+ file should get, or (mode_t) -1 if this should be obtained from the
+ file itself. CHECKSUM is the MD5 checksum of the file, or NULL if
+ this need not be sent. If FILEBUF is not NULL, it holds the
+ contents of the file, in which case the file itself may not exist.
+ If FILEBUF is not NULL, server_updated will free it. */
+enum server_updated_arg4
+{
+ SERVER_UPDATED,
+ SERVER_MERGED,
+ SERVER_PATCHED,
+ SERVER_RCS_DIFF
+};
+
+struct buffer;
+
+void server_updated (struct file_info *finfo, Vers_TS *vers,
+ enum server_updated_arg4 updated, mode_t mode,
+ unsigned char *checksum, struct buffer *filebuf);
+
+/* Whether we should send RCS format patches. */
+int server_use_rcs_diff (void);
+
+/* Set the Entries.Static flag. */
+void server_set_entstat (const char *update_dir, const char *repository);
+/* Clear it. */
+void server_clear_entstat (const char *update_dir, const char *repository);
+
+/* Set or clear a per-directory sticky tag or date. */
+void server_set_sticky (const char *update_dir, const char *repository,
+ const char *tag, const char *date, int nonbranch);
+
+/* Send Clear-template response. */
+void server_clear_template (const char *update_dir, const char *repository);
+
+/* Send Template response. */
+void server_template (const char *update_dir, const char *repository);
+
+void server_update_entries (const char *file, const char *update_dir,
+ const char *repository,
+ enum server_updated_arg4 updated);
+
+/* Pointer to a malloc'd string which is the directory which
+ the server should prepend to the pathnames which it sends
+ to the client. */
+extern char *server_dir;
+
+void server_cleanup (void);
+
+#ifdef SERVER_FLOWCONTROL
+/* Pause if it's convenient to avoid memory blowout */
+void server_pause_check (void);
+#endif /* SERVER_FLOWCONTROL */
+
+#ifdef AUTH_SERVER_SUPPORT
+extern char *CVS_Username;
+#endif /* AUTH_SERVER_SUPPORT */
+
+#endif /* SERVER_SUPPORT */
+
+/* Stuff shared with the client. */
+struct request
+{
+ /* Name of the request. */
+ char *name;
+
+#ifdef SERVER_SUPPORT
+ /*
+ * Function to carry out the request. ARGS is the text of the command
+ * after name and, if present, a single space, have been stripped off.
+ */
+ void (*func) (char *args);
+#endif
+
+ /* One or more of the RQ_* flags described below. */
+ int flags;
+
+ /* If set, failure to implement this request can imply a fatal
+ error. This should be set only for commands which were in the
+ original version of the protocol; it should not be set for new
+ commands. */
+#define RQ_ESSENTIAL 1
+
+ /* Set by the client if the server we are talking to supports it. */
+#define RQ_SUPPORTED 2
+
+ /* If set, and client and server both support the request, the
+ client should tell the server by making the request. */
+#define RQ_ENABLEME 4
+
+ /* The server may accept this request before "Root". */
+#define RQ_ROOTLESS 8
+};
+
+/* Table of requests ending with an entry with a NULL name. */
+extern struct request requests[];
+
+/* Gzip library, see zlib.c. */
+int gunzip_and_write (int, const char *, unsigned char *, size_t);
+int read_and_gzip (int, const char *, unsigned char **, size_t *, size_t *,
+ int);
+void server_edit_file (struct file_info *finfo);
+
+/* The TRACE macro */
+void cvs_trace (int level, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+#define TRACE cvs_trace
+/* Trace levels:
+ *
+ * TRACE_FUNCTION Trace function calls, often including function
+ * arguments. This is the trace level that, historically,
+ * applied to all trace calls.
+ * TRACE_FLOW Include the flow control functions, such as
+ * start_recursion, do_recursion, and walklist in the
+ * function traces.
+ * TRACE_DATA Trace important internal function data.
+ */
+#define TRACE_FUNCTION 1
+#define TRACE_FLOW 2
+#define TRACE_DATA 3
+
+extern cvsroot_t *referrer;
diff --git a/src/socket-client.c b/src/socket-client.c
new file mode 100644
index 0000000..159cacf
--- /dev/null
+++ b/src/socket-client.c
@@ -0,0 +1,241 @@
+/* CVS socket client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/***
+ *** THIS FILE SHOULD NEVER BE COMPILED UNLESS NO_SOCKET_TO_FD IS DEFINED.
+ ***/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef CLIENT_SUPPORT
+
+#include "cvs.h"
+#include "buffer.h"
+
+#include "socket-client.h"
+
+
+/* Under certain circumstances, we must communicate with the server
+ via a socket using send() and recv(). This is because under some
+ operating systems (OS/2 and Windows 95 come to mind), a socket
+ cannot be converted to a file descriptor -- it must be treated as a
+ socket and nothing else.
+
+ We may also need to deal with socket routine error codes differently
+ in these cases. This is handled through the SOCK_ERRNO and
+ SOCK_STRERROR macros. */
+
+/* These routines implement a buffer structure which uses send and
+ recv. The buffer is always in blocking mode so we don't implement
+ the block routine. */
+
+/* Note that it is important that these routines always handle errors
+ internally and never return a positive errno code, since it would in
+ general be impossible for the caller to know in general whether any
+ error code came from a socket routine (to decide whether to use
+ SOCK_STRERROR or simply strerror to print an error message). */
+
+/* We use an instance of this structure as the closure field. */
+
+struct socket_buffer
+{
+ /* The socket number. */
+ int socket;
+};
+
+
+
+/* The buffer input function for a buffer built on a socket. */
+
+static int
+socket_buffer_input (void *closure, char *data, size_t need, size_t size,
+ size_t *got)
+{
+ struct socket_buffer *sb = closure;
+ int nbytes;
+
+ /* I believe that the recv function gives us exactly the semantics
+ we want. If there is a message, it returns immediately with
+ whatever it could get. If there is no message, it waits until
+ one comes in. In other words, it is not like read, which in
+ blocking mode normally waits until all the requested data is
+ available. */
+
+ assert (size >= need);
+
+ *got = 0;
+
+ do
+ {
+
+ /* Note that for certain (broken?) networking stacks, like
+ VMS's UCX (not sure what version, problem reported with
+ recv() in 1997), and (according to windows-NT/config.h)
+ Windows NT 3.51, we must call recv or send with a
+ moderately sized buffer (say, less than 200K or something),
+ or else there may be network errors (somewhat hard to
+ produce, e.g. WAN not LAN or some such). buf_read_data
+ makes sure that we only recv() BUFFER_DATA_SIZE bytes at
+ a time. */
+
+ nbytes = recv (sb->socket, data + *got, size - *got, 0);
+ if (nbytes < 0)
+ error (1, 0, "reading from server: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+ if (nbytes == 0)
+ {
+ /* End of file (for example, the server has closed
+ the connection). If we've already read something, we
+ just tell the caller about the data, not about the end of
+ file. If we've read nothing, we return end of file. */
+ if (*got == 0)
+ return -1;
+ else
+ return 0;
+ }
+ *got += nbytes;
+ }
+ while (*got < need);
+
+ return 0;
+}
+
+
+
+/* The buffer output function for a buffer built on a socket. */
+
+static int
+socket_buffer_output (void *closure, const char *data, size_t have,
+ size_t *wrote)
+{
+ struct socket_buffer *sb = closure;
+
+ *wrote = have;
+
+ /* See comment in socket_buffer_input regarding buffer size we pass
+ to send and recv. */
+
+# ifdef SEND_NEVER_PARTIAL
+ /* If send() never will produce a partial write, then just do it. This
+ is needed for systems where its return value is something other than
+ the number of bytes written. */
+ if (send (sb->socket, data, have, 0) < 0)
+ error (1, 0, "writing to server socket: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+# else
+ while (have > 0)
+ {
+ int nbytes;
+
+ nbytes = send (sb->socket, data, have, 0);
+ if (nbytes < 0)
+ error (1, 0, "writing to server socket: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+
+ have -= nbytes;
+ data += nbytes;
+ }
+# endif
+
+ return 0;
+}
+
+
+
+/* The buffer flush function for a buffer built on a socket. */
+
+/*ARGSUSED*/
+static int
+socket_buffer_flush (void *closure)
+{
+ /* Nothing to do. Sockets are always flushed. */
+ return 0;
+}
+
+
+
+static int
+socket_buffer_shutdown (struct buffer *buf)
+{
+ struct socket_buffer *n = buf->closure;
+ char tmp;
+
+ /* no need to flush children of an endpoint buffer here */
+
+ if (buf->input)
+ {
+ int err = 0;
+ if (! buf_empty_p (buf)
+ || (err = recv (n->socket, &tmp, 1, 0)) > 0)
+ error (0, 0, "dying gasps from %s unexpected",
+ current_parsed_root->hostname);
+ else if (err == -1)
+ error (0, 0, "reading from %s: %s", current_parsed_root->hostname,
+ SOCK_STRERROR (SOCK_ERRNO));
+
+ /* shutdown() socket */
+# ifdef SHUTDOWN_SERVER
+ if (current_parsed_root->method != server_method)
+# endif
+ if (shutdown (n->socket, 0) < 0)
+ {
+ error (1, 0, "shutting down server socket: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+ }
+
+ buf->input = NULL;
+ }
+ else if (buf->output)
+ {
+ /* shutdown() socket */
+# ifdef SHUTDOWN_SERVER
+ /* FIXME: Should have a SHUTDOWN_SERVER_INPUT &
+ * SHUTDOWN_SERVER_OUTPUT
+ */
+ if (current_parsed_root->method == server_method)
+ SHUTDOWN_SERVER (n->socket);
+ else
+# endif
+ if (shutdown (n->socket, 1) < 0)
+ {
+ error (1, 0, "shutting down server socket: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+ }
+
+ buf->output = NULL;
+ }
+
+ return 0;
+}
+
+
+
+/* Create a buffer based on a socket. */
+
+struct buffer *
+socket_buffer_initialize (int socket, int input,
+ void (*memory) (struct buffer *))
+{
+ struct socket_buffer *sbuf = xmalloc (sizeof *sbuf);
+ sbuf->socket = socket;
+ return buf_initialize (input ? socket_buffer_input : NULL,
+ input ? NULL : socket_buffer_output,
+ input ? NULL : socket_buffer_flush,
+ NULL, NULL,
+ socket_buffer_shutdown,
+ memory,
+ sbuf);
+}
+
+#endif /* CLIENT_SUPPORT */
diff --git a/src/socket-client.h b/src/socket-client.h
new file mode 100644
index 0000000..793b1da
--- /dev/null
+++ b/src/socket-client.h
@@ -0,0 +1,46 @@
+/* CVS socket client stuff.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#ifndef SOCKET_CLIENT_H__
+#define SOCKET_CLIENT_H__ 1
+
+#if defined SOCK_ERRNO || defined SOCK_STRERROR
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif
+
+struct buffer *socket_buffer_initialize
+ (int, int, void (*) (struct buffer *));
+
+/* If SOCK_ERRNO is defined, then send()/recv() and other socket calls
+ do not set errno, but that this macro should be used to obtain an
+ error code. This probably doesn't make sense unless
+ NO_SOCKET_TO_FD is also defined. */
+#ifndef SOCK_ERRNO
+# define SOCK_ERRNO errno
+#endif
+
+/* If SOCK_STRERROR is defined, then the error codes returned by
+ socket operations are not known to strerror, and this macro must be
+ used instead to convert those error codes to strings. */
+#ifndef SOCK_STRERROR
+# define SOCK_STRERROR strerror
+
+# include <string.h>
+# ifndef strerror
+extern char *strerror (int);
+# endif
+#endif /* ! SOCK_STRERROR */
+
+#endif /* SOCKET_CLIENT_H__ */
diff --git a/src/stack.c b/src/stack.c
new file mode 100644
index 0000000..7b26ec3
--- /dev/null
+++ b/src/stack.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2004-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 2004-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * This module uses the hash.c module to implement a stack.
+ */
+
+#include "cvs.h"
+#include <assert.h>
+
+
+
+static void
+do_push (List *stack, void *elem, int isstring)
+{
+ Node *p = getnode();
+
+ if (isstring)
+ p->key = elem;
+ else
+ p->data = elem;
+
+ addnode(stack, p);
+}
+
+
+
+void
+push (List *stack, void *elem)
+{
+ do_push (stack, elem, 0);
+}
+
+
+
+void
+push_string (List *stack, char *elem)
+{
+ do_push (stack, elem, 1);
+}
+
+
+
+static void *
+do_pop (List *stack, int isstring)
+{
+ void *elem;
+
+ if (isempty (stack)) return NULL;
+
+ if (isstring)
+ {
+ elem = stack->list->prev->key;
+ stack->list->prev->key = NULL;
+ }
+ else
+ {
+ elem = stack->list->prev->data;
+ stack->list->prev->data = NULL;
+ }
+
+ delnode (stack->list->prev);
+ return elem;
+}
+
+
+
+void *
+pop (List *stack)
+{
+ return do_pop (stack, 0);
+}
+
+
+
+char *
+pop_string (List *stack)
+{
+ return do_pop (stack, 1);
+}
+
+
+
+static void
+do_unshift (List *stack, void *elem, int isstring)
+{
+ Node *p = getnode();
+
+ if (isstring)
+ p->key = elem;
+ else
+ p->data = elem;
+
+ addnode_at_front(stack, p);
+}
+
+
+
+void
+unshift (List *stack, void *elem)
+{
+ do_unshift (stack, elem, 0);
+}
+
+
+
+void
+unshift_string (List *stack, char *elem)
+{
+ do_unshift (stack, elem, 1);
+}
+
+
+
+static void *
+do_shift (List *stack, int isstring)
+{
+ void *elem;
+
+ if (isempty (stack)) return NULL;
+
+ if (isstring)
+ {
+ elem = stack->list->next->key;
+ stack->list->next->key = NULL;
+ }
+ else
+ {
+ elem = stack->list->next->data;
+ stack->list->next->data = NULL;
+ }
+ delnode (stack->list->next);
+ return elem;
+}
+
+
+
+void *
+shift (List *stack)
+{
+ return do_shift (stack, 0);
+}
+
+
+
+char *
+shift_string (List *stack)
+{
+ return do_shift (stack, 1);
+}
+
+
+
+int
+isempty (List *stack)
+{
+ if (stack->list == stack->list->next)
+ return 1;
+ return 0;
+}
diff --git a/src/stack.h b/src/stack.h
new file mode 100644
index 0000000..6f348c5
--- /dev/null
+++ b/src/stack.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2004-2005 The Free Software Foundation,
+ * Derek Price, and Ximbiot <http://ximbiot.com>.
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ */
+
+void push (List *_stack, void *_elem);
+void *pop (List *_stack);
+void unshift (List *_stack, void *_elem);
+void *shift (List *_stack);
+void push_string (List *_stack, char *_elem);
+char *pop_string (List *_stack);
+void unshift_string (List *_stack, char *_elem);
+char *shift_string (List *_stack);
+int isempty (List *_stack);
diff --git a/src/status.c b/src/status.c
new file mode 100644
index 0000000..11ab5ac
--- /dev/null
+++ b/src/status.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Status Information
+ */
+
+#include "cvs.h"
+
+static Dtype status_dirproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int status_fileproc (void *callerdat, struct file_info *finfo);
+static int tag_list_proc (Node * p, void *closure);
+
+static int local = 0;
+static int long_format = 0;
+static RCSNode *xrcsnode;
+
+static const char *const status_usage[] =
+{
+ "Usage: %s %s [-vlR] [files...]\n",
+ "\t-v\tVerbose format; includes tag information for the file\n",
+ "\t-l\tProcess this directory only (not recursive).\n",
+ "\t-R\tProcess directories recursively.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+cvsstatus (int argc, char **argv)
+{
+ int c;
+ int err = 0;
+
+ if (argc == -1)
+ usage (status_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+vlR")) != -1)
+ {
+ switch (c)
+ {
+ case 'v':
+ long_format = 1;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (status_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+
+ ign_setup ();
+
+ if (long_format)
+ send_arg("-v");
+ if (local)
+ send_arg("-l");
+ send_arg ("--");
+
+ /* For a while, we tried setting SEND_NO_CONTENTS here so this
+ could be a fast operation. That prevents the
+ server from updating our timestamp if the timestamp is
+ changed but the file is unmodified. Worse, it is user-visible
+ (shows "locally modified" instead of "up to date" if
+ timestamp is changed but file is not). And there is no good
+ workaround (you might not want to run "cvs update"; "cvs -n
+ update" doesn't update CVS/Entries; "cvs diff --brief" or
+ something perhaps could be made to work but somehow that
+ seems nonintuitive to me even if so). Given that timestamps
+ seem to have the potential to get munged for any number of
+ reasons, it seems better to not rely too much on them. */
+
+ send_files (argc, argv, local, 0, 0);
+
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+
+ send_to_server ("status\012", 0);
+ err = get_responses_and_close ();
+
+ return err;
+ }
+#endif
+
+ /* start the recursion processor */
+ err = start_recursion (status_fileproc, NULL, status_dirproc,
+ NULL, NULL, argc, argv, local, W_LOCAL,
+ 0, CVS_LOCK_READ, NULL, 1, NULL);
+
+ return (err);
+}
+
+/*
+ * display the status of a file
+ */
+/* ARGSUSED */
+static int
+status_fileproc (void *callerdat, struct file_info *finfo)
+{
+ Ctype status;
+ char *sstat;
+ Vers_TS *vers;
+ Node *node;
+
+ status = Classify_File (finfo, NULL, NULL, NULL, 1, 0, &vers, 0);
+ sstat = "Classify Error";
+ switch (status)
+ {
+ case T_UNKNOWN:
+ sstat = "Unknown";
+ break;
+ case T_CHECKOUT:
+ sstat = "Needs Checkout";
+ break;
+ case T_PATCH:
+ sstat = "Needs Patch";
+ break;
+ case T_CONFLICT:
+ /* FIXME - This message could be clearer. It comes up
+ * when a file exists or has been added in the local sandbox
+ * and a file of the same name has been committed indepenently to
+ * the repository from a different sandbox, as well as when a
+ * timestamp hasn't changed since a merge resulted in conflicts.
+ * It also comes up whether an update has been attempted or not, so
+ * technically, I think the double-add case is not actually a
+ * conflict yet.
+ */
+ sstat = "Unresolved Conflict";
+ break;
+ case T_ADDED:
+ sstat = "Locally Added";
+ break;
+ case T_REMOVED:
+ sstat = "Locally Removed";
+ break;
+ case T_MODIFIED:
+ if (file_has_markers (finfo))
+ sstat = "File had conflicts on merge";
+ else
+ /* Note that we do not re Register() the file when we spot
+ * a resolved conflict like update_fileproc() does on the
+ * premise that status should not alter the sandbox.
+ */
+ sstat = "Locally Modified";
+ break;
+ case T_REMOVE_ENTRY:
+ sstat = "Entry Invalid";
+ break;
+ case T_UPTODATE:
+ sstat = "Up-to-date";
+ break;
+ case T_NEEDS_MERGE:
+ sstat = "Needs Merge";
+ break;
+ case T_TITLE:
+ /* I don't think this case can occur here. Just print
+ "Classify Error". */
+ break;
+ }
+
+ cvs_output ("\
+===================================================================\n", 0);
+ if (vers->ts_user == NULL)
+ {
+ cvs_output ("File: no file ", 0);
+ cvs_output (finfo->file, 0);
+ cvs_output ("\t\tStatus: ", 0);
+ cvs_output (sstat, 0);
+ cvs_output ("\n\n", 0);
+ }
+ else
+ {
+ char *buf;
+ buf = Xasprintf ("File: %-17s\tStatus: %s\n\n", finfo->file, sstat);
+ cvs_output (buf, 0);
+ free (buf);
+ }
+
+ if (vers->vn_user == NULL)
+ {
+ cvs_output (" Working revision:\tNo entry for ", 0);
+ cvs_output (finfo->file, 0);
+ cvs_output ("\n", 0);
+ }
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ cvs_output (" Working revision:\tNew file!\n", 0);
+ else
+ {
+ cvs_output (" Working revision:\t", 0);
+ cvs_output (vers->vn_user, 0);
+
+ /* Only add the UTC timezone if there is a time to use. */
+ if (!server_active && strlen (vers->ts_rcs) > 0)
+ {
+ /* Convert from the asctime() format to ISO 8601 */
+ char *buf;
+
+ cvs_output ("\t", 0);
+
+ /* Allow conversion from CVS/Entries asctime() to ISO 8601 */
+ buf = Xasprintf ("%s UTC", vers->ts_rcs);
+ cvs_output_tagged ("date", buf);
+ free (buf);
+ }
+ cvs_output ("\n", 0);
+ }
+
+ if (vers->vn_rcs == NULL)
+ cvs_output (" Repository revision:\tNo revision control file\n", 0);
+ else
+ {
+ cvs_output (" Repository revision:\t", 0);
+ cvs_output (vers->vn_rcs, 0);
+ cvs_output ("\t", 0);
+ cvs_output (vers->srcfile->print_path, 0);
+ cvs_output ("\n", 0);
+
+ node = findnode(vers->srcfile->versions,vers->vn_rcs);
+ if (node)
+ {
+ RCSVers *v;
+ v=(RCSVers*)node->data;
+ node = findnode(v->other_delta,"commitid");
+ cvs_output(" Commit Identifier:\t", 0);
+ if(node && node->data)
+ cvs_output(node->data, 0);
+ else
+ cvs_output("(none)",0);
+ cvs_output("\n",0);
+ }
+ }
+
+ if (vers->entdata)
+ {
+ Entnode *edata;
+
+ edata = vers->entdata;
+ if (edata->tag)
+ {
+ if (vers->vn_rcs == NULL)
+ {
+ cvs_output (" Sticky Tag:\t\t", 0);
+ cvs_output (edata->tag, 0);
+ cvs_output (" - MISSING from RCS file!\n", 0);
+ }
+ else
+ {
+ if (isdigit ((unsigned char) edata->tag[0]))
+ {
+ cvs_output (" Sticky Tag:\t\t", 0);
+ cvs_output (edata->tag, 0);
+ cvs_output ("\n", 0);
+ }
+ else
+ {
+ char *branch = NULL;
+
+ if (RCS_nodeisbranch (finfo->rcs, edata->tag))
+ branch = RCS_whatbranch(finfo->rcs, edata->tag);
+
+ cvs_output (" Sticky Tag:\t\t", 0);
+ cvs_output (edata->tag, 0);
+ cvs_output (" (", 0);
+ cvs_output (branch ? "branch" : "revision", 0);
+ cvs_output (": ", 0);
+ cvs_output (branch ? branch : vers->vn_rcs, 0);
+ cvs_output (")\n", 0);
+
+ if (branch)
+ free (branch);
+ }
+ }
+ }
+ else if (!really_quiet)
+ cvs_output (" Sticky Tag:\t\t(none)\n", 0);
+
+ if (edata->date)
+ {
+ cvs_output (" Sticky Date:\t\t", 0);
+ cvs_output (edata->date, 0);
+ cvs_output ("\n", 0);
+ }
+ else if (!really_quiet)
+ cvs_output (" Sticky Date:\t\t(none)\n", 0);
+
+ if (edata->options && edata->options[0])
+ {
+ cvs_output (" Sticky Options:\t", 0);
+ cvs_output (edata->options, 0);
+ cvs_output ("\n", 0);
+ }
+ else if (!really_quiet)
+ cvs_output (" Sticky Options:\t(none)\n", 0);
+ }
+
+ if (long_format && vers->srcfile)
+ {
+ List *symbols = RCS_symbols(vers->srcfile);
+
+ cvs_output ("\n Existing Tags:\n", 0);
+ if (symbols)
+ {
+ xrcsnode = finfo->rcs;
+ (void) walklist (symbols, tag_list_proc, NULL);
+ }
+ else
+ cvs_output ("\tNo Tags Exist\n", 0);
+ }
+
+ cvs_output ("\n", 0);
+ freevers_ts (&vers);
+ return (0);
+}
+
+
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+status_dirproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+ if (!quiet)
+ error (0, 0, "Examining %s", update_dir);
+ return (R_PROCESS);
+}
+
+
+
+/*
+ * Print out a tag and its type
+ */
+static int
+tag_list_proc (Node *p, void *closure)
+{
+ char *branch = NULL;
+ char *buf;
+
+ if (RCS_nodeisbranch (xrcsnode, p->key))
+ branch = RCS_whatbranch(xrcsnode, p->key) ;
+
+ buf = Xasprintf ("\t%-25s\t(%s: %s)\n", p->key,
+ branch ? "branch" : "revision",
+ branch ? branch : (char *)p->data);
+ cvs_output (buf, 0);
+ free (buf);
+
+ if (branch)
+ free (branch);
+
+ return (0);
+}
diff --git a/src/subr.c b/src/subr.c
new file mode 100644
index 0000000..3c3a5e1
--- /dev/null
+++ b/src/subr.c
@@ -0,0 +1,2003 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Various useful functions for the CVS support code.
+ */
+
+#include "cvs.h"
+
+#include "canonicalize.h"
+#include "canon-host.h"
+#include "getline.h"
+#include "vasprintf.h"
+#include "vasnprintf.h"
+
+/* Get wint_t. */
+#ifdef HAVE_WINT_T
+# include <wchar.h>
+#endif
+
+
+
+extern char *getlogin (void);
+
+
+
+/* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N
+ characters of space. Reallocate it so that points to at least
+ NEWSIZE bytes of space. Gives a fatal error if out of memory;
+ if it returns it was successful. */
+void
+expand_string (char **strptr, size_t *n, size_t newsize)
+{
+ while (*n < newsize)
+ *strptr = x2realloc (*strptr, n);
+}
+
+
+
+/* char *
+ * Xreadlink (const char *link, size_t size)
+ *
+ * INPUTS
+ * link The original path.
+ * size A guess as to the size needed for the path. It need
+ * not be right.
+ * RETURNS
+ * The resolution of the final symbolic link in the path.
+ *
+ * ERRORS
+ * This function exits with a fatal error if it fails to read the
+ * link for any reason.
+ */
+char *
+Xreadlink (const char *link, size_t size)
+{
+ char *file = xreadlink (link, size);
+
+ if (file == NULL)
+ error (1, errno, "cannot readlink %s", link);
+
+ return file;
+}
+
+
+
+/* *STR is a pointer to a malloc'd string or NULL. *LENP is its allocated
+ * length. If *STR is NULL then *LENP must be 0 and visa-versa.
+ * Add SRC to the end of *STR, reallocating *STR if necessary. */
+void
+xrealloc_and_strcat (char **str, size_t *lenp, const char *src)
+{
+ bool newstr = !*lenp;
+ expand_string (str, lenp, (newstr ? 0 : strlen (*str)) + strlen (src) + 1);
+ if (newstr)
+ strcpy (*str, src);
+ else
+ strcat (*str, src);
+}
+
+
+
+/* Remove trailing newlines from STRING, destructively.
+ *
+ * RETURNS
+ *
+ * True if any newlines were removed, false otherwise.
+ */
+int
+strip_trailing_newlines (char *str)
+{
+ size_t index, origlen;
+ index = origlen = strlen (str);
+
+ while (index > 0 && str[index-1] == '\n')
+ str[--index] = '\0';
+
+ return index != origlen;
+}
+
+
+
+/* Return the number of levels that PATH ascends above where it starts.
+ * For example:
+ *
+ * "../../foo" -> 2
+ * "foo/../../bar" -> 1
+ */
+int
+pathname_levels (const char *p)
+{
+ int level;
+ int max_level;
+
+ if (p == NULL) return 0;
+
+ max_level = 0;
+ level = 0;
+ do
+ {
+ /* Now look for pathname level-ups. */
+ if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || ISSLASH (p[2])))
+ {
+ --level;
+ if (-level > max_level)
+ max_level = -level;
+ }
+ else if (p[0] == '\0' || ISSLASH (p[0]) ||
+ (p[0] == '.' && (p[1] == '\0' || ISSLASH (p[1]))))
+ ;
+ else
+ ++level;
+
+ /* q = strchr (p, '/'); but sub ISSLASH() for '/': */
+ while (*p != '\0' && !ISSLASH (*p)) p++;
+ if (*p != '\0') p++;
+ } while (*p != '\0');
+ return max_level;
+}
+
+
+
+/* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1]
+ are malloc'd and so is *ARGV itself. Such a vector is allocated by
+ line2argv or expand_wild, for example. */
+void
+free_names (int *pargc, char **argv)
+{
+ register int i;
+
+ for (i = 0; i < *pargc; i++)
+ { /* only do through *pargc */
+ free (argv[i]);
+ }
+ free (argv);
+ *pargc = 0; /* and set it to zero when done */
+}
+
+
+
+/* Convert LINE into arguments separated by SEPCHARS. Set *ARGC
+ to the number of arguments found, and (*ARGV)[0] to the first argument,
+ (*ARGV)[1] to the second, etc. *ARGV is malloc'd and so are each of
+ (*ARGV)[0], (*ARGV)[1], ... Use free_names() to return the memory
+ allocated here back to the free pool. */
+void
+line2argv (int *pargc, char ***argv, char *line, char *sepchars)
+{
+ char *cp;
+ /* Could make a case for size_t or some other unsigned type, but
+ we'll stick with int to avoid signed/unsigned warnings when
+ comparing with *pargc. */
+ int argv_allocated;
+
+ /* Small for testing. */
+ argv_allocated = 1;
+ *argv = xnmalloc (argv_allocated, sizeof (**argv));
+
+ *pargc = 0;
+ for (cp = strtok (line, sepchars); cp; cp = strtok (NULL, sepchars))
+ {
+ if (*pargc == argv_allocated)
+ {
+ argv_allocated *= 2;
+ *argv = xnrealloc (*argv, argv_allocated, sizeof (**argv));
+ }
+ (*argv)[*pargc] = xstrdup (cp);
+ (*pargc)++;
+ }
+}
+
+
+
+/*
+ * Returns the number of dots ('.') found in an RCS revision number
+ */
+int
+numdots (const char *s)
+{
+ int dots = 0;
+
+ for (; *s; s++)
+ {
+ if (*s == '.')
+ dots++;
+ }
+ return (dots);
+}
+
+
+
+/* Compare revision numbers REV1 and REV2 by consecutive fields.
+ Return negative, zero, or positive in the manner of strcmp. The
+ two revision numbers must have the same number of fields, or else
+ compare_revnums will return an inaccurate result. */
+int
+compare_revnums (const char *rev1, const char *rev2)
+{
+ const char *sp, *tp;
+ char *snext, *tnext;
+ int result = 0;
+
+ sp = rev1;
+ tp = rev2;
+ while (result == 0)
+ {
+ result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
+ if (*snext == '\0' || *tnext == '\0')
+ break;
+ sp = snext + 1;
+ tp = tnext + 1;
+ }
+
+ return result;
+}
+
+
+
+/* Increment a revision number. Working on the string is a bit awkward,
+ but it avoid problems with integer overflow should the revision numbers
+ get really big. */
+char *
+increment_revnum (const char *rev)
+{
+ char *newrev, *p;
+ size_t len = strlen (rev);
+
+ newrev = xmalloc (len + 2);
+ memcpy (newrev, rev, len + 1);
+ for (p = newrev + len; p != newrev; )
+ {
+ --p;
+ if (!isdigit(*p))
+ {
+ ++p;
+ break;
+ }
+ if (*p != '9')
+ {
+ ++*p;
+ return newrev;
+ }
+ *p = '0';
+ }
+ /* The number was all 9s, so change the first character to 1 and add
+ a 0 to the end. */
+ *p = '1';
+ p = newrev + len;
+ *p++ = '0';
+ *p = '\0';
+ return newrev;
+}
+
+
+
+/* Return the username by which the caller should be identified in
+ CVS, in contexts such as the author field of RCS files, various
+ logs, etc. */
+char *
+getcaller (void)
+{
+#ifndef SYSTEM_GETCALLER
+ static char *cache;
+ struct passwd *pw;
+ uid_t uid;
+#endif
+
+ /* If there is a CVS username, return it. */
+#ifdef AUTH_SERVER_SUPPORT
+ if (CVS_Username != NULL)
+ return CVS_Username;
+#endif
+
+#ifdef SYSTEM_GETCALLER
+ return SYSTEM_GETCALLER ();
+#else
+ /* Get the caller's login from his uid. If the real uid is "root"
+ try LOGNAME USER or getlogin(). If getlogin() and getpwuid()
+ both fail, return the uid as a string. */
+
+ if (cache != NULL)
+ return cache;
+
+ uid = getuid ();
+ if (uid == (uid_t) 0)
+ {
+ char *name;
+
+ /* super-user; try getlogin() to distinguish */
+ if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
+ (name = getenv("USER"))) && *name)
+ {
+ cache = xstrdup (name);
+ return cache;
+ }
+ }
+ if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
+ {
+ cache = Xasprintf ("uid%lu", (unsigned long) uid);
+ return cache;
+ }
+ cache = xstrdup (pw->pw_name);
+ return cache;
+#endif
+}
+
+
+
+#ifdef lint
+# ifndef __GNUC__
+/* ARGSUSED */
+bool
+get_date (struct timespec *result, char const *p, struct timespec const *now)
+{
+ result->tv_sec = 0;
+ result->tv_nsec = 0;
+
+ return false;
+}
+# endif
+#endif
+
+
+
+/* Given some revision, REV, return the first prior revision that exists in the
+ * RCS file, RCS.
+ *
+ * ASSUMPTIONS
+ * REV exists.
+ *
+ * INPUTS
+ * RCS The RCS node pointer.
+ * REV An existing revision in the RCS file referred to by RCS.
+ *
+ * RETURNS
+ * The first prior revision that exists in the RCS file, or NULL if no prior
+ * revision exists. The caller is responsible for disposing of this string.
+ *
+ * NOTES
+ * This function currently neglects the case where we are on the trunk with
+ * rev = X.1, where X != 1. If rev = X.Y, where X != 1 and Y > 1, then this
+ * function should work fine, as revision X.1 must exist, due to RCS rules.
+ */
+char *
+previous_rev (RCSNode *rcs, const char *rev)
+{
+ char *p;
+ char *tmp = xstrdup (rev);
+ long r1;
+ char *retval;
+
+ /* Our retval can have no more digits and dots than our input revision. */
+ retval = xmalloc (strlen (rev) + 1);
+ p = strrchr (tmp, '.');
+ *p = '\0';
+ r1 = strtol (p+1, NULL, 10);
+ do {
+ if (--r1 == 0)
+ {
+ /* If r1 == 0, then we must be on a branch and our parent must
+ * exist, or we must be on the trunk with a REV like X.1.
+ * We are neglecting the X.1 with X != 1 case by assuming that
+ * there is no previous revision when we discover we were on
+ * the trunk.
+ */
+ p = strrchr (tmp, '.');
+ if (p == NULL)
+ /* We are on the trunk. */
+ retval = NULL;
+ else
+ {
+ *p = '\0';
+ sprintf (retval, "%s", tmp);
+ }
+ break;
+ }
+ sprintf (retval, "%s.%ld", tmp, r1);
+ } while (!RCS_exist_rev (rcs, retval));
+
+ free (tmp);
+ return retval;
+}
+
+
+
+/* Given two revisions, find their greatest common ancestor. If the
+ two input revisions exist, then rcs guarantees that the gca will
+ exist. */
+char *
+gca (const char *rev1, const char *rev2)
+{
+ int dots;
+ char *gca, *g;
+ const char *p1, *p2;
+ int r1, r2;
+ char *retval;
+
+ if (rev1 == NULL || rev2 == NULL)
+ {
+ error (0, 0, "sanity failure in gca");
+ abort();
+ }
+
+ /* The greatest common ancestor will have no more dots, and numbers
+ of digits for each component no greater than the arguments. Therefore
+ this string will be big enough. */
+ g = gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
+
+ /* walk the strings, reading the common parts. */
+ p1 = rev1;
+ p2 = rev2;
+ do
+ {
+ r1 = strtol (p1, (char **) &p1, 10);
+ r2 = strtol (p2, (char **) &p2, 10);
+
+ /* use the lowest. */
+ (void) sprintf (g, "%d.", r1 < r2 ? r1 : r2);
+ g += strlen (g);
+ if (*p1 == '.') ++p1;
+ else break;
+ if (*p2 == '.') ++p2;
+ else break;
+ } while (r1 == r2);
+
+ /* erase that last dot. */
+ *--g = '\0';
+
+ /* numbers differ, or we ran out of strings. we're done with the
+ common parts. */
+
+ dots = numdots (gca);
+ if (dots == 0)
+ {
+ /* revisions differ in trunk major number. */
+
+ if (r2 < r1) p1 = p2;
+ if (*p1 == '\0')
+ {
+ /* we only got one number. this is strange. */
+ error (0, 0, "bad revisions %s or %s", rev1, rev2);
+ abort();
+ }
+ else
+ {
+ /* we have a minor number. use it. */
+ *g++ = '.';
+ while (*p1 != '.' && *p1 != '\0')
+ *g++ = *p1++;
+ *g = '\0';
+ }
+ }
+ else if ((dots & 1) == 0)
+ {
+ /* if we have an even number of dots, then we have a branch.
+ remove the last number in order to make it a revision. */
+
+ g = strrchr (gca, '.');
+ *g = '\0';
+ }
+
+ retval = xstrdup (gca);
+ free (gca);
+ return retval;
+}
+
+
+
+/* Give fatal error if REV is numeric and ARGC,ARGV imply we are
+ planning to operate on more than one file. The current directory
+ should be the working directory. Note that callers assume that we
+ will only be checking the first character of REV; it need not have
+ '\0' at the end of the tag name and other niceties. Right now this
+ is only called from admin.c, but if people like the concept it probably
+ should also be called from diff -r, update -r, get -r, and log -r. */
+void
+check_numeric (const char *rev, int argc, char **argv)
+{
+ if (rev == NULL || !isdigit ((unsigned char) *rev))
+ return;
+
+ /* Note that the check for whether we are processing more than one
+ file is (basically) syntactic; that is, we don't behave differently
+ depending on whether a directory happens to contain only a single
+ file or whether it contains more than one. I strongly suspect this
+ is the least confusing behavior. */
+ if (argc != 1
+ || (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0])))
+ {
+ error (0, 0, "while processing more than one file:");
+ error (1, 0, "attempt to specify a numeric revision");
+ }
+}
+
+
+
+/*
+ * Sanity checks and any required fix-up on message passed to RCS via '-m'.
+ * RCS 5.7 requires that a non-total-whitespace, non-null message be provided
+ * with '-m'. Returns a newly allocated, non-empty buffer with whitespace
+ * stripped from end of lines and end of buffer.
+ *
+ * TODO: We no longer use RCS to manage repository files, so maybe this
+ * nonsense about non-empty log fields can be dropped.
+ */
+char *
+make_message_rcsvalid (const char *message)
+{
+ char *dst, *dp;
+ const char *mp;
+
+ if (message == NULL) message = "";
+
+ /* Strip whitespace from end of lines and end of string. */
+ dp = dst = (char *) xmalloc (strlen (message) + 1);
+ for (mp = message; *mp != '\0'; ++mp)
+ {
+ if (*mp == '\n')
+ {
+ /* At end-of-line; backtrack to last non-space. */
+ while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t'))
+ --dp;
+ }
+ *dp++ = *mp;
+ }
+
+ /* Backtrack to last non-space at end of string, and truncate. */
+ while (dp > dst && isspace ((unsigned char) dp[-1]))
+ --dp;
+ *dp = '\0';
+
+ /* After all that, if there was no non-space in the string,
+ substitute a non-empty message. */
+ if (*dst == '\0')
+ {
+ free (dst);
+ dst = xstrdup ("*** empty log message ***");
+ }
+
+ return dst;
+}
+
+
+
+/* Does the file FINFO contain conflict markers? The whole concept
+ of looking at the contents of the file to figure out whether there are
+ unresolved conflicts is kind of bogus (people do want to manage files
+ which contain those patterns not as conflict markers), but for now it
+ is what we do. */
+int
+file_has_markers (const struct file_info *finfo)
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ int result;
+
+ result = 0;
+ fp = CVS_FOPEN (finfo->file, "r");
+ if (fp == NULL)
+ error (1, errno, "cannot open %s", finfo->fullname);
+ while (getline (&line, &line_allocated, fp) > 0)
+ {
+ if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 ||
+ strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 ||
+ strncmp (line, RCS_MERGE_PAT_3, sizeof RCS_MERGE_PAT_3 - 1) == 0)
+ {
+ result = 1;
+ goto out;
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", finfo->fullname);
+out:
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", finfo->fullname);
+ if (line != NULL)
+ free (line);
+ return result;
+}
+
+
+
+/* Read the entire contents of the file NAME into *BUF.
+ If NAME is NULL, read from stdin. *BUF
+ is a pointer returned from malloc (or NULL), pointing to *BUFSIZE
+ bytes of space. The actual size is returned in *LEN. On error,
+ give a fatal error. The name of the file to use in error messages
+ (typically will include a directory if we have changed directory)
+ is FULLNAME. MODE is "r" for text or "rb" for binary. */
+void
+get_file (const char *name, const char *fullname, const char *mode, char **buf,
+ size_t *bufsize, size_t *len)
+{
+ struct stat s;
+ size_t nread;
+ char *tobuf;
+ FILE *e;
+ size_t filesize;
+
+ if (name == NULL)
+ {
+ e = stdin;
+ filesize = 100; /* force allocation of minimum buffer */
+ }
+ else
+ {
+ /* Although it would be cleaner in some ways to just read
+ until end of file, reallocating the buffer, this function
+ does get called on files in the working directory which can
+ be of arbitrary size, so I think we better do all that
+ extra allocation. */
+
+ if (stat (name, &s) < 0)
+ error (1, errno, "can't stat %s", fullname);
+
+ /* Convert from signed to unsigned. */
+ filesize = s.st_size;
+
+ e = xfopen (name, mode);
+ }
+
+ if (*buf == NULL || *bufsize <= filesize)
+ {
+ *bufsize = filesize + 1;
+ *buf = xrealloc (*buf, *bufsize);
+ }
+
+ tobuf = *buf;
+ nread = 0;
+ while (1)
+ {
+ size_t got;
+
+ got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
+ if (ferror (e))
+ error (1, errno, "can't read %s", fullname);
+ nread += got;
+ tobuf += got;
+
+ if (feof (e))
+ break;
+
+ /* Allocate more space if needed. */
+ if (tobuf == *buf + *bufsize)
+ {
+ int c;
+ long off;
+
+ c = getc (e);
+ if (c == EOF)
+ break;
+ off = tobuf - *buf;
+ expand_string (buf, bufsize, *bufsize + 100);
+ tobuf = *buf + off;
+ *tobuf++ = c;
+ ++nread;
+ }
+ }
+
+ if (e != stdin && fclose (e) < 0)
+ error (0, errno, "cannot close %s", fullname);
+
+ *len = nread;
+
+ /* Force *BUF to be large enough to hold a null terminator. */
+ if (nread == *bufsize)
+ expand_string (buf, bufsize, *bufsize + 1);
+ (*buf)[nread] = '\0';
+}
+
+
+
+/* Follow a chain of symbolic links to its destination. FILENAME
+ should be a handle to a malloc'd block of memory which contains the
+ beginning of the chain. This routine will replace the contents of
+ FILENAME with the destination (a real file). */
+void
+resolve_symlink (char **filename)
+{
+ ssize_t rsize;
+
+ if (filename == NULL || *filename == NULL)
+ return;
+
+ while ((rsize = islink (*filename)) > 0)
+ {
+#ifdef HAVE_READLINK
+ /* The clean thing to do is probably to have each filesubr.c
+ implement this (with an error if not supported by the
+ platform, in which case islink would presumably return 0).
+ But that would require editing each filesubr.c and so the
+ expedient hack seems to be looking at HAVE_READLINK. */
+ char *newname = Xreadlink (*filename, rsize);
+
+ if (ISABSOLUTE (newname))
+ {
+ free (*filename);
+ *filename = newname;
+ }
+ else
+ {
+ const char *oldname = last_component (*filename);
+ int dirlen = oldname - *filename;
+ char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
+ strncpy (fullnewname, *filename, dirlen);
+ strcpy (fullnewname + dirlen, newname);
+ free (newname);
+ free (*filename);
+ *filename = fullnewname;
+ }
+#else
+ error (1, 0, "internal error: islink doesn't like readlink");
+#endif
+ }
+}
+
+
+
+/*
+ * Rename a file to an appropriate backup name based on BAKPREFIX.
+ * If suffix non-null, then ".<suffix>" is appended to the new name.
+ *
+ * Returns the new name, which caller may free() if desired.
+ */
+char *
+backup_file (const char *filename, const char *suffix)
+{
+ char *backup_name = Xasprintf ("%s%s%s%s", BAKPREFIX, filename,
+ suffix ? "." : "", suffix ? suffix : "");
+
+ if (isfile (filename))
+ copy_file (filename, backup_name);
+
+ return backup_name;
+}
+
+
+
+/*
+ * Copy a string into a buffer escaping any shell metacharacters. The
+ * buffer should be at least twice as long as the string.
+ *
+ * Returns a pointer to the terminating NUL byte in buffer.
+ */
+char *
+shell_escape(char *buf, const char *str)
+{
+ static const char meta[] = "$`\\\"";
+ const char *p;
+
+ for (;;)
+ {
+ p = strpbrk(str, meta);
+ if (!p) p = str + strlen(str);
+ if (p > str)
+ {
+ memcpy(buf, str, p - str);
+ buf += p - str;
+ }
+ if (!*p) break;
+ *buf++ = '\\';
+ *buf++ = *p++;
+ str = p;
+ }
+ *buf = '\0';
+ return buf;
+}
+
+
+
+/*
+ * We can only travel forwards in time, not backwards. :)
+ */
+void
+sleep_past (time_t desttime)
+{
+ time_t t;
+ long s;
+ long us;
+
+ while (time (&t) <= desttime)
+ {
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ if (tv.tv_sec > desttime)
+ break;
+ s = desttime - tv.tv_sec;
+ if (tv.tv_usec > 0)
+ us = 1000000 - tv.tv_usec;
+ else
+ {
+ s++;
+ us = 0;
+ }
+#else
+ /* default to 20 ms increments */
+ s = desttime - t;
+ us = 20000;
+#endif
+
+ {
+ struct timespec ts;
+ ts.tv_sec = s;
+ ts.tv_nsec = us * 1000;
+ (void)nanosleep (&ts, NULL);
+ }
+ }
+}
+
+
+
+/* used to store callback data in a list indexed by the user format string
+ */
+typedef int (*CONVPROC_t) (Node *, void *);
+struct cmdline_bindings
+{
+ char conversion;
+ void *data;
+ CONVPROC_t convproc;
+ void *closure;
+};
+/* since we store the above in a list, we need to dispose of the data field.
+ * we don't have to worry about convproc or closure since pointers are stuck
+ * in there directly and format_cmdline's caller is responsible for disposing
+ * of those if necessary.
+ */
+static void
+cmdline_bindings_hash_node_delete (Node *p)
+{
+ struct cmdline_bindings *b = p->data;
+
+ if (b->conversion != ',')
+ {
+ free (b->data);
+ }
+ free (b);
+}
+
+
+
+/*
+ * assume s is a literal argument and put it between quotes,
+ * escaping as appropriate for a shell command line
+ *
+ * the caller is responsible for disposing of the new string
+ */
+char *
+cmdlinequote (char quotes, char *s)
+{
+ char *quoted = cmdlineescape (quotes, s);
+ char *buf = Xasprintf ("%c%s%c", quotes, quoted, quotes);
+
+ free (quoted);
+ return buf;
+}
+
+
+
+/* read quotes as the type of quotes we are between (if any) and then make our
+ * argument so it could make it past a cmdline parser (using sh as a model)
+ * inside the quotes (if any).
+ *
+ * if you were planning on expanding any paths, it should be done before
+ * calling this function, as it escapes shell metacharacters.
+ *
+ * the caller is responsible for disposing of the new string
+ *
+ * FIXME: See about removing/combining this functionality with shell_escape()
+ * in subr.c.
+ */
+char *
+cmdlineescape (char quotes, char *s)
+{
+ char *buf = NULL;
+ size_t length = 0;
+ char *d = NULL;
+ size_t doff;
+ char *lastspace;
+
+ lastspace = s - 1;
+ do
+ {
+ /* FIXME: Single quotes only require other single quotes to be escaped
+ * for Bourne Shell.
+ */
+ if ( isspace( *s ) ) lastspace = s;
+ if( quotes
+ ? ( *s == quotes
+ || ( quotes == '"'
+ && ( *s == '$' || *s == '`' || *s == '\\' ) ) )
+ : ( strchr( "\\$`'\"*?", *s )
+ || isspace( *s )
+ || ( lastspace == ( s - 1 )
+ && *s == '~' ) ) )
+ {
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ *d++ = '\\';
+ }
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ } while ((*d++ = *s++) != '\0');
+ return (buf);
+}
+
+
+
+/* expand format strings in a command line. modeled roughly after printf
+ *
+ * this function's arg list must be NULL terminated
+ *
+ * assume a space delimited list of args is the desired final output,
+ * but args can be quoted (" or ').
+ *
+ * the best usage examples are in tag.c & logmsg.c, but here goes:
+ *
+ * INPUTS
+ * int oldway to support old format strings
+ * char *srepos you guessed it
+ * char *format the format string to parse
+ * ... NULL terminated data list in the following format:
+ * char *userformat, char *printfformat, <type> data
+ * where
+ * char *userformat a list of possible
+ * format characters the
+ * end user might pass us
+ * in the format string
+ * (e.g. those found in
+ * taginfo or loginfo)
+ * multiple characters in
+ * this strings will be
+ * aliases for each other
+ * char *printfformat the same list of args
+ * printf uses to
+ * determine what kind of
+ * data the next arg will
+ * be
+ * <type> data a piece of data to be
+ * formatted into the user
+ * string, <type>
+ * determined by the
+ * printfformat string.
+ * or
+ * char *userformat, char *printfformat, List *data,
+ * int (*convproc) (Node *, void *), void *closure
+ * where
+ * char *userformat same as above, except
+ * multiple characters in
+ * this string represent
+ * different node
+ * attributes which can be
+ * retrieved from data by
+ * convproc
+ * char *printfformat = ","
+ * List *data the list to be walked
+ * with walklist &
+ * convproc to retrieve
+ * data for each of the
+ * possible format
+ * characters in
+ * userformat
+ * int (*convproc)() see data
+ * void *closure arg to be passed into
+ * walklist as closure
+ * data for convproc
+ *
+ * EXAMPLE
+ * (ignoring oldway variable and srepos since those are only around while we
+ * SUPPORT_OLD_INFO_FMT_STRINGS)
+ * format_cmdline ("/cvsroot/CVSROOT/mytaginfoproc %t %o %{sVv}",
+ * "t", "s", "newtag",
+ * "o", "s", "mov",
+ * "xG", "ld", longintwhichwontbeusedthispass,
+ * "sVv", ",", tlist, pretag_list_to_args_proc,
+ * (void *) mydata,
+ * (char *) NULL);
+ *
+ * would generate the following command line, assuming two files in tlist,
+ * file1 & file2, each with old versions 1.1 and new version 1.1.2.3:
+ *
+ * /cvsroot/CVSROOT/mytaginfoproc "newtag" "mov" "file1" "1.1" "1.1.2.3" "file2" "1.1" "1.1.2.3"
+ *
+ * RETURNS
+ * pointer to newly allocated string. the caller is responsible for
+ * disposing of this string.
+ */
+char *
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+format_cmdline (bool oldway, const char *srepos, const char *format, ...)
+#else /* SUPPORT_OLD_INFO_FMT_STRINGS */
+format_cmdline (const char *format, ...)
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+{
+ va_list args; /* our input function args */
+ char *buf; /* where we store our output string */
+ size_t length; /* the allocated length of our output string in bytes.
+ * used as a temporary storage for the length of the
+ * next function argument during function
+ * initialization
+ */
+ char *pfmt; /* initially the list of fmt keys passed in,
+ * but used as a temporary key buffer later
+ */
+ char *fmt; /* buffer for format string which we are processing */
+ size_t flen; /* length of fmt buffer */
+ char *d, *q, *r; /* for walking strings */
+ const char *s;
+ size_t doff, qoff;
+ char inquotes;
+
+ List *pflist = getlist(); /* our list of input data indexed by format
+ * "strings"
+ */
+ Node *p;
+ struct cmdline_bindings *b;
+ static int warned_of_deprecation = 0;
+ char key[] = "?"; /* Used as temporary storage for a single
+ * character search string used to locate a
+ * hash key.
+ */
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ /* state varialbes in the while loop which parses the actual
+ * format string in the final parsing pass*/
+ int onearg;
+ int subbedsomething;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (oldway && !warned_of_deprecation)
+ {
+ /* warn the user that we don't like his kind 'round these parts */
+ warned_of_deprecation = 1;
+ error (0, 0,
+"warning: Set to use deprecated info format strings. Establish\n"
+"compatibility with the new info file format strings (add a temporary '1' in\n"
+"all info files after each '%%' which doesn't represent a literal percent)\n"
+"and set UseNewInfoFmtStrings=yes in CVSROOT/config. After that, convert\n"
+"individual command lines and scripts to handle the new format at your\n"
+"leisure.");
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+ va_start (args, format);
+
+ /* read our possible format strings
+ * expect a certain number of arguments by type and a NULL format
+ * string to terminate the list.
+ */
+ while ((pfmt = va_arg (args, char *)) != NULL)
+ {
+ char *conversion = va_arg (args, char *);
+
+ char conversion_error = 0;
+ char char_conversion = 0;
+ char decimal_conversion = 0;
+ char integer_conversion = 0;
+ char string_conversion = 0;
+
+ /* allocate space to save our data */
+ b = xmalloc(sizeof(struct cmdline_bindings));
+
+ /* where did you think we were going to store all this data??? */
+ b->convproc = NULL;
+ b->closure = NULL;
+
+ /* read a length from the conversion string */
+ s = conversion;
+ length = 0;
+ while (!length && *s)
+ {
+ switch (*s)
+ {
+ case 'h':
+ integer_conversion = 1;
+ if (s[1] == 'h')
+ {
+ length = sizeof (char);
+ s += 2;
+ }
+ else
+ {
+ char_conversion = 1;
+ length = sizeof (short);
+ s++;
+ }
+ break;
+#ifdef HAVE_INTMAX_T
+ case 'j':
+ integer_conversion = 1;
+ length = sizeof (intmax_t);
+ s++;
+ break;
+#endif /* HAVE_INTMAX_T */
+ case 'l':
+ integer_conversion = 1;
+ if (s[1] == 'l')
+ {
+#ifdef HAVE_LONG_LONG
+ length = sizeof (long long);
+#endif
+ s += 2;
+ }
+ else
+ {
+ char_conversion = 2;
+ string_conversion = 2;
+ length = sizeof (long);
+ s++;
+ }
+ break;
+ case 't':
+ integer_conversion = 1;
+ length = sizeof (ptrdiff_t);
+ s++;
+ break;
+ case 'z':
+ integer_conversion = 1;
+ length = sizeof (size_t);
+ s++;
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case 'L':
+ decimal_conversion = 1;
+ length = sizeof (long double);
+ s++;
+ break;
+#endif
+ default:
+ char_conversion = 1;
+ decimal_conversion = 1;
+ integer_conversion = 1;
+ string_conversion = 1;
+ /* take care of it when we find out what we're looking for */
+ length = -1;
+ break;
+ }
+ }
+ /* if we don't have a valid conversion left, that is an error */
+ /* read an argument conversion */
+ buf = xmalloc (strlen(conversion) + 2);
+ *buf = '%';
+ strcpy (buf+1, conversion);
+ switch (*s)
+ {
+ case 'c':
+ /* chars (an integer conversion) */
+ if (!char_conversion)
+ {
+ conversion_error = 1;
+ break;
+ }
+ if (char_conversion == 2)
+ {
+#ifdef HAVE_WINT_T
+ length = sizeof (wint_t);
+#else
+ conversion_error = 1;
+ break;
+#endif
+ }
+ else
+ length = sizeof (char);
+ /* fall through... */
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ /* integer conversions */
+ if (!integer_conversion)
+ {
+ conversion_error = 1;
+ break;
+ }
+ if (length == -1)
+ {
+ length = sizeof (int);
+ }
+ switch (length)
+ {
+ case sizeof(char):
+ {
+ char arg_char = (char) va_arg (args, int);
+ b->data = Xasprintf (buf, arg_char);
+ break;
+ }
+#ifdef UNIQUE_INT_TYPE_WINT_T /* implies HAVE_WINT_T */
+ case sizeof(wint_t):
+ {
+ wint_t arg_wint_t = va_arg (args, wint_t);
+ b->data = Xasprintf (buf, arg_wint_t);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_WINT_T */
+#ifdef UNIQUE_INT_TYPE_SHORT
+ case sizeof(short):
+ {
+ short arg_short = (short) va_arg (args, int);
+ b->data = Xasprintf (buf, arg_short);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_SHORT */
+#ifdef UNIQUE_INT_TYPE_INT
+ case sizeof(int):
+ {
+ int arg_int = va_arg (args, int);
+ b->data = Xasprintf(buf, arg_int);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_INT */
+#ifdef UNIQUE_INT_TYPE_LONG
+ case sizeof(long):
+ {
+ long arg_long = va_arg (args, long);
+ b->data = Xasprintf (buf, arg_long);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_LONG */
+#ifdef UNIQUE_INT_TYPE_LONG_LONG /* implies HAVE_LONG_LONG */
+ case sizeof(long long):
+ {
+ long long arg_long_long = va_arg (args, long long);
+ b->data = Xasprintf (buf, arg_long_long);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_LONG_LONG */
+#ifdef UNIQUE_INT_TYPE_INTMAX_T /* implies HAVE_INTMAX_T */
+ case sizeof(intmax_t):
+ {
+ intmax_t arg_intmax_t = va_arg (args, intmax_t);
+ b->data = Xasprintf (buf, arg_intmax_t);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_INTMAX_T */
+#ifdef UNIQUE_INT_TYPE_SIZE_T
+ case sizeof(size_t):
+ {
+ size_t arg_size_t = va_arg (args, size_t);
+ b->data = Xasprintf (buf, arg_size_t);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_SIZE_T */
+#ifdef UNIQUE_INT_TYPE_PTRDIFF_T
+ case sizeof(ptrdiff_t):
+ {
+ ptrdiff_t arg_ptrdiff_t = va_arg (args, ptrdiff_t);
+ b->data = Xasprintf (buf, arg_ptrdiff_t);
+ break;
+ }
+#endif /* UNIQUE_INT_TYPE_PTRDIFF_T */
+ default:
+ dellist(&pflist);
+ free(b);
+ error (1, 0,
+"internal error: unknown integer arg size (%d)",
+ length);
+ break;
+ }
+ break;
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ /* decimal conversions */
+ if (!decimal_conversion)
+ {
+ conversion_error = 1;
+ break;
+ }
+ if (length == -1)
+ {
+ length = sizeof (double);
+ }
+ switch (length)
+ {
+ case sizeof(double):
+ {
+ double arg_double = va_arg (args, double);
+ b->data = Xasprintf (buf, arg_double);
+ break;
+ }
+#ifdef UNIQUE_FLOAT_TYPE_LONG_DOUBLE /* implies HAVE_LONG_DOUBLE */
+ case sizeof(long double):
+ {
+ long double arg_long_double = va_arg (args, long double);
+ b->data = Xasprintf (buf, arg_long_double);
+ break;
+ }
+#endif /* UNIQUE_FLOAT_TYPE_LONG_DOUBLE */
+ default:
+ dellist(&pflist);
+ free(b);
+ error (1, 0,
+"internal error: unknown floating point arg size (%d)",
+ length);
+ break;
+ }
+ break;
+ case 's':
+ switch (string_conversion)
+ {
+ case 1:
+ b->data = xstrdup (va_arg (args, char *));
+ break;
+#ifdef HAVE_WCHAR_T
+ case 2:
+ {
+ wchar_t *arg_wchar_t_string = va_arg (args, wchar_t *);
+ b->data = Xasprintf (buf, arg_wchar_t_string);
+ break;
+ }
+#endif /* HAVE_WCHAR_T */
+ default:
+ conversion_error = 1;
+ break;
+ }
+ break;
+ case ',':
+ if (length != -1)
+ {
+ conversion_error = 1;
+ break;
+ }
+ b->data = va_arg (args, List *);
+ b->convproc = va_arg (args, CONVPROC_t);
+ b->closure = va_arg (args, void *);
+ break;
+ default:
+ conversion_error = 1;
+ break;
+ }
+ free (buf);
+ /* fail if we found an error or haven't found the end of the string */
+ if (conversion_error || s[1])
+ {
+ error (1, 0,
+"internal error (format_cmdline): '%s' is not a valid conversion!!!",
+ conversion);
+ }
+
+
+ /* save our type - we really only care wheter it's a list type (',')
+ * or not from now on, but what the hell...
+ */
+ b->conversion = *s;
+
+ /* separate the user format string into parts and stuff our data into
+ * the pflist (once for each possible string - diverse keys can have
+ * duplicate data).
+ */
+ q = pfmt;
+ while (*q)
+ {
+ struct cmdline_bindings *tb;
+ if (*q == '{')
+ {
+ s = q + 1;
+ while (*++q && *q != '}');
+ r = q + 1;
+ }
+ else
+ {
+ s = q++;
+ r = q;
+ }
+ if (*r)
+ {
+ /* copy the data since we'll need it again */
+ tb = xmalloc(sizeof(struct cmdline_bindings));
+ if (b->conversion == ',')
+ {
+ tb->data = b->data;
+ }
+ else
+ {
+ tb->data = xstrdup(b->data);
+ }
+ tb->conversion = b->conversion;
+ tb->convproc = b->convproc;
+ tb->closure = b->closure;
+ }
+ else
+ {
+ /* we're done after this, so we don't need to copy the data */
+ tb = b;
+ }
+ p = getnode();
+ p->key = xmalloc((q - s) + 1);
+ strncpy (p->key, s, q - s);
+ p->key[q-s] = '\0';
+ p->data = tb;
+ p->delproc = cmdline_bindings_hash_node_delete;
+ addnode(pflist,p);
+ }
+ }
+
+ /* we're done with va_list */
+ va_end(args);
+
+ /* All formatted strings include a format character that resolves to the
+ * empty string by default, so put it in pflist.
+ */
+ /* allocate space to save our data */
+ b = xmalloc(sizeof(struct cmdline_bindings));
+ b->conversion = 's';
+ b->convproc = NULL;
+ b->closure = NULL;
+ b->data = xstrdup( "" );
+ p = getnode();
+ p->key = xstrdup( "n" );
+ p->data = b;
+ p->delproc = cmdline_bindings_hash_node_delete;
+ addnode( pflist,p );
+
+ /* finally, read the user string and copy it into rargv as appropriate */
+ /* user format strings look as follows:
+ *
+ * %% is a literal %
+ * \X, where X is any character = \X, (this is the escape you'd expect, but
+ * we are leaving the \ for an expected final pass which splits our
+ * output string into separate arguments
+ *
+ * %X means sub var "X" into location
+ * %{VWXYZ} means sub V,W,X,Y,Z into location as a single arg. The shell
+ * || would be to quote the comma separated arguments. Each list
+ * that V, W, X, Y, and Z represent attributes of will cause a new
+ * tuple to be inserted for each list item with a space between
+ * items.
+ * e.g."V W1,X1,Z1 W2,X2,Z2 W3,X3,Z3 Y1 Y2" where V is not a list
+ * variable, W,X,&Z are attributes of a list with 3 items and Y is an
+ * attribute of a second list with 2 items.
+ * %,{VWXYZ} means to separate the args. The previous example would produce
+ * V W1 X1 Z1 W2 X2 Z2 W3 X3 Z3 Y1 Y2, where each variable is now a
+ * separate, space delimited, arguments within a single argument.
+ * a%{XY}, where 'a' is a literal, still produces a single arg (a"X Y", in
+ * shell)
+ * a%1{XY}, where 'a' is a literal, splits the literal as it produces
+ * multiple args (a X Y). The rule is that each sub will produce a
+ * separate arg. Without a comma, attributes will still be grouped
+ * together & comma separated in what could be a single argument,
+ * but internal quotes, commas, and spaces are not excaped.
+ *
+ * clearing the variable oldway, passed into this function, causes the
+ * behavior of '1' and "," in the format string to reverse.
+ */
+
+ /* for convenience, use fmt as a temporary key buffer.
+ * for speed, attempt to realloc it as little as possible
+ */
+ fmt = NULL;
+ flen = 0;
+
+ /* buf = current argv entry being built
+ * length = current length of buf
+ * s = next char in source buffer to read
+ * d = next char location to write (in buf)
+ * inquotes = current quote char or NUL
+ */
+ s = format;
+ d = buf = NULL;
+ length = 0;
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+
+ inquotes = '\0';
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ subbedsomething = 0;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ while ((*d++ = *s) != '\0')
+ {
+ int list = 0;
+ switch (*s++)
+ {
+ case '\\':
+ /* the character after a \ goes unprocessed but leave the \ in
+ * the string so the function that splits this string into a
+ * command line later can deal with quotes properly
+ *
+ * ignore a NUL
+ */
+ if (*s)
+ {
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ *d++ = *s++;
+ }
+ break;
+ case '\'':
+ case '"':
+ /* keep track of quotes so we can escape quote chars we sub in
+ * - the API is that a quoted format string will guarantee that
+ * it gets passed into the command as a single arg
+ */
+ if (!inquotes) inquotes = s[-1];
+ else if (s[-1] == inquotes) inquotes = '\0';
+ break;
+ case '%':
+ if (*s == '%')
+ {
+ /* "%%" is a literal "%" */
+ s++;
+ break;
+ }
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (oldway && subbedsomething)
+ {
+ /* the old method was to sub only the first format string */
+ break;
+ }
+ /* initialize onearg each time we get a new format string */
+ onearg = oldway ? 1 : 0;
+ subbedsomething = 1;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ d--; /* we're going to overwrite the '%' regardless
+ * of other factors... */
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ /* detect '1' && ',' in the fmt string. */
+ if (*s == '1')
+ {
+ onearg = 1;
+ s++;
+ if (!oldway)
+ {
+ /* FIXME - add FILE && LINE */
+ error (0, 0,
+"Using deprecated info format strings. Convert your scripts to use\n"
+"the new argument format and remove '1's from your info file format strings.");
+ }
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+ /* parse the format string and sub in... */
+ if (*s == '{')
+ {
+ list = 1;
+ s++;
+ }
+ /* q = fmt start
+ * r = fmt end + 1
+ */
+ q = fmt;
+ do
+ {
+ qoff = q - fmt;
+ expand_string (&fmt, &flen, qoff + 1);
+ q = fmt + qoff;
+ } while ((*q = *s++) && list && *q++ != '}');
+ /* we will always copy one character, so, whether in list mode
+ * or not, if we just copied a '\0', then we hit the end of the
+ * string before we should have
+ */
+ if (!s[-1])
+ {
+ /* if we copied a NUL while processing a list, fail
+ * - we had an empty fmt string or didn't find a list
+ * terminator ('}')
+ */
+ /* FIXME - this wants a file name and line number in a bad
+ * way.
+ */
+ error(1, 0,
+"unterminated format string encountered in command spec.\n"
+"This error is likely to have been caused by an invalid line in a hook script\n"
+"spec (see taginfo, loginfo, verifymsginfo, etc. in the Cederqvist). Most\n"
+"likely the offending line would end with a '%%' character or contain a string\n"
+"beginning \"%%{\" and no closing '}' before the end of the line.");
+ }
+ if (list)
+ {
+ q[-1] = '\0';
+ }
+ else
+ {
+ /* We're not in a list, so we must have just copied a
+ * single character. Terminate the string.
+ */
+ q++;
+ qoff = q - fmt;
+ expand_string (&fmt, &flen, qoff + 1);
+ q = fmt + qoff;
+ *q = '\0';
+ }
+ /* fmt is now a pointer to a list of fmt chars, though the list
+ * could be a single element one
+ */
+ q = fmt;
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ /* always add quotes in the deprecated onearg case - for
+ * backwards compatibility
+ */
+ if (onearg)
+ {
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ *d++ = '"';
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ /*
+ * for each character in the fmt string,
+ *
+ * all output will be separate quoted arguments (with
+ * internal quotes escaped) if the argument is in quotes
+ * unless the oldway variable is set, in which case the fmt
+ * statment will correspond to a single argument with
+ * internal space or comma delimited arguments
+ *
+ * see the "user format strings" section above for more info
+ */
+ key[0] = *q;
+ if ((p = findnode (pflist, key)) != NULL)
+ {
+ b = p->data;
+ if (b->conversion == ',')
+ {
+ /* process the rest of the format string as a list */
+ struct format_cmdline_walklist_closure c;
+ c.format = q;
+ c.buf = &buf;
+ c.length = &length;
+ c.d = &d;
+ c.quotes = inquotes;
+ c.closure = b->closure;
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ c.onearg = onearg;
+ c.firstpass = 1;
+ c.srepos = srepos;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ walklist(b->data, b->convproc, &c);
+ d--; /* back up one space. we know that ^
+ always adds 1 extra */
+ q += strlen(q);
+ }
+ else
+ {
+ /* got a flat item */
+ char *outstr;
+ if (strlen(q) > 1)
+ {
+ error (1, 0,
+"Multiple non-list variables are not allowed in a single format string.");
+ }
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (onearg)
+ {
+ outstr = b->data;
+ }
+ else /* !onearg */
+ {
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ /* the *only* case possible without
+ * SUPPORT_OLD_INFO_FORMAT_STRINGS
+ * - !onearg */
+ if (!inquotes)
+ {
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ *d++ = '"';
+ }
+ outstr = cmdlineescape (inquotes ? inquotes : '"', b->data);
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ } /* onearg */
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ doff = d - buf;
+ expand_string (&buf, &length, doff + strlen(outstr));
+ d = buf + doff;
+ strncpy(d, outstr, strlen(outstr));
+ d += strlen(outstr);
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (!onearg)
+ {
+ free(outstr);
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ if (!inquotes)
+ {
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ *d++ = '"';
+ }
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ q++;
+ }
+ }
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ else if (onearg)
+ {
+ /* the old standard was to ignore unknown format
+ * characters (print the empty string), but also that
+ * any format character meant print srepos first
+ */
+ q++;
+ doff = d - buf;
+ expand_string (&buf, &length, doff + strlen(srepos));
+ d = buf + doff;
+ strncpy(d, srepos, strlen(srepos));
+ d += strlen(srepos);
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ else /* no key */
+ {
+ /* print an error message to the user
+ * FIXME - this should have a file and line number!!! */
+ error (1, 0,
+"Unknown format character in info file ('%s').\n"
+"Info files are the hook files, verifymsg, taginfo, commitinfo, etc.",
+ q);
+ }
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ /* always add quotes in the deprecated onearg case - for
+ * backwards compatibility
+ */
+ if (onearg)
+ {
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ *d++ = '"';
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ break;
+ }
+ doff = d - buf;
+ expand_string (&buf, &length, doff + 1);
+ d = buf + doff;
+ } /* while (*d++ = *s) */
+ if (fmt) free (fmt);
+ if (inquotes)
+ {
+ /* FIXME - we shouldn't need this - Parse_Info should be handling
+ * multiple lines...
+ */
+ error (1, 0, "unterminated quote in format string: %s", format);
+ }
+
+ dellist (&pflist);
+ return buf;
+}
+
+
+
+/* Like xstrdup (), but can handle a NULL argument.
+ */
+char *
+Xstrdup (const char *string)
+{
+ if (string == NULL) return NULL;
+ return xmemdup (string, strlen (string) + 1);
+}
+
+
+
+/* Like xasprintf(), but consider all errors fatal (may never return NULL).
+ */
+char *
+Xasprintf (const char *format, ...)
+{
+ va_list args;
+ char *result;
+
+ va_start (args, format);
+ if (vasprintf (&result, format, args) < 0)
+ error (1, errno, "Failed to write to string.");
+ va_end (args);
+
+ return result;
+}
+
+
+
+/* Like xasnprintf(), but consider all errors fatal (may never return NULL).
+ */
+char *
+Xasnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+{
+ va_list args;
+ char *result;
+
+ va_start (args, format);
+ result = vasnprintf (resultbuf, lengthp, format, args);
+ if (result == NULL)
+ error (1, errno, "Failed to write to string.");
+ va_end (args);
+
+ return result;
+}
+
+
+
+/* Print a warning and return false if P doesn't look like a string specifying
+ * a boolean value.
+ *
+ * Sets *VAL to the parsed value when it is found to be valid. *VAL will not
+ * be altered when false is returned.
+ *
+ * INPUTS
+ * infopath Where the error is reported to be from on error. This could
+ * be, for example, the name of the file the boolean is being read
+ * from.
+ * option An option name being parsed, reported in traces and any error
+ * message.
+ * p The string to actually read the option from.
+ * val Pointer to where to store the boolean read from P.
+ *
+ * OUTPUTS
+ * val TRUE/FALSE stored, as read, when there are no errors.
+ *
+ * RETURNS
+ * true If VAL was read.
+ * false On error.
+ */
+bool
+readBool (const char *infopath, const char *option, const char *p, bool *val)
+{
+ TRACE (TRACE_FLOW, "readBool (%s, %s, %s)", infopath, option, p);
+ if (!strcasecmp (p, "no") || !strcasecmp (p, "false")
+ || !strcasecmp (p, "off") || !strcmp (p, "0"))
+ {
+ TRACE (TRACE_DATA, "Read %d for %s", *val, option);
+ *val = false;
+ return true;
+ }
+ else if (!strcasecmp (p, "yes") || !strcasecmp (p, "true")
+ || !strcasecmp (p, "on") || !strcmp (p, "1"))
+ {
+ TRACE (TRACE_DATA, "Read %d for %s", *val, option);
+ *val = true;
+ return true;
+ }
+
+ error (0, 0, "%s: unrecognized value `%s' for `%s'",
+ infopath, p, option);
+ return false;
+}
+
+
+
+/*
+ * Open a file, exiting with a message on error.
+ *
+ * INPUTS
+ * name The name of the file to open.
+ * mode Mode to open file in, as POSIX fopen().
+ *
+ * NOTES
+ * If you want to handle errors, just call fopen (NAME, MODE).
+ *
+ * RETURNS
+ * The new FILE pointer.
+ */
+FILE *
+xfopen (const char *name, const char *mode)
+{
+ FILE *fp;
+
+ if (!(fp = fopen (name, mode)))
+ error (1, errno, "cannot open %s", name);
+ return fp;
+}
+
+
+
+/* char *
+ * xcanonicalize_file_name (const char *path)
+ *
+ * Like canonicalize_file_name(), but exit on error.
+ *
+ * INPUTS
+ * path The original path.
+ *
+ * RETURNS
+ * The path with any symbolic links, `.'s, or `..'s, expanded.
+ *
+ * ERRORS
+ * This function exits with a fatal error if it fails to read the link for
+ * any reason.
+ */
+char *
+xcanonicalize_file_name (const char *path)
+{
+ char *hardpath = canonicalize_file_name (path);
+ if (!hardpath)
+ error (1, errno, "Failed to resolve path: `%s'", path);
+ return hardpath;
+}
+
+
+
+/* Declared in main.c. */
+extern char *server_hostname;
+
+/* Return true if OTHERHOST resolves to this host in the DNS.
+ *
+ * GLOBALS
+ * server_hostname The name of this host, as determined by the call to
+ * xgethostname() in main().
+ *
+ * RETURNS
+ * true If OTHERHOST equals or resolves to HOSTNAME.
+ * false Otherwise.
+ */
+bool
+isThisHost (const char *otherhost)
+{
+ char *fqdno;
+ char *fqdns;
+ bool retval;
+
+ /* As an optimization, check the literal strings before looking up
+ * OTHERHOST in the DNS.
+ */
+ if (!strcasecmp (server_hostname, otherhost))
+ return true;
+
+ fqdno = canon_host (otherhost);
+ if (!fqdno)
+ error (1, 0, "Name lookup failed for `%s': %s",
+ otherhost, ch_strerror ());
+ fqdns = canon_host (server_hostname);
+ if (!fqdns)
+ error (1, 0, "Name lookup failed for `%s': %s",
+ server_hostname, ch_strerror ());
+
+ retval = !strcasecmp (fqdns, fqdno);
+
+ free (fqdno);
+ free (fqdns);
+ return retval;
+}
+
+
+
+/* Return true if two paths match, resolving symlinks.
+ */
+bool
+isSamePath (const char *path1_in, const char *path2_in)
+{
+ char *p1, *p2;
+ bool same;
+
+ if (!strcmp (path1_in, path2_in))
+ return true;
+
+ /* Path didn't match, but try to resolve any links that may be
+ * present.
+ */
+ if (!isdir (path1_in) || !isdir (path2_in))
+ /* To be resolvable, paths must exist on this server. */
+ return false;
+
+ p1 = xcanonicalize_file_name (path1_in);
+ p2 = xcanonicalize_file_name (path2_in);
+ if (strcmp (p1, p2))
+ same = false;
+ else
+ same = true;
+
+ free (p1);
+ free (p2);
+ return same;
+}
diff --git a/src/subr.h b/src/subr.h
new file mode 100644
index 0000000..c60be55
--- /dev/null
+++ b/src/subr.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ * Copyright (c) 2004, Derek R. Price and Ximbiot <http://ximbiot.com>
+ * Copyright (c) 1989-2004 The Free Software Foundation <http://gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SUBR_H
+# define SUBR_H
+
+void expand_string (char **, size_t *, size_t);
+char *Xreadlink (const char *link, size_t size);
+void xrealloc_and_strcat (char **, size_t *, const char *);
+int strip_trailing_newlines (char *str);
+int pathname_levels (const char *path);
+void free_names (int *pargc, char *argv[]);
+void line2argv (int *pargc, char ***argv, char *line, char *sepchars);
+int numdots (const char *s);
+int compare_revnums (const char *, const char *);
+char *increment_revnum (const char *);
+char *getcaller (void);
+char *previous_rev (RCSNode *rcs, const char *rev);
+char *gca (const char *rev1, const char *rev2);
+void check_numeric (const char *, int, char **);
+char *make_message_rcsvalid (const char *message);
+int file_has_markers (const struct file_info *);
+void get_file (const char *, const char *, const char *,
+ char **, size_t *, size_t *);
+void resolve_symlink (char **filename);
+char *backup_file (const char *file, const char *suffix);
+char *shell_escape (char *buf, const char *str);
+void sleep_past (time_t desttime);
+
+/* for format_cmdline function - when a list variable is bound to a user string,
+ * we need to pass some data through walklist into the callback function.
+ * We use this struct.
+ */
+struct format_cmdline_walklist_closure
+{
+ const char *format; /* the format string the user passed us */
+ char **buf; /* *dest = our NUL terminated and possibly too short
+ * destination string
+ */
+ size_t *length; /* *dlen = how many bytes have already been allocated to
+ * *dest.
+ */
+ char **d; /* our pointer into buf where the next char should go */
+ char quotes; /* quotes we are currently between, if any */
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ int onearg;
+ int firstpass;
+ const char *srepos;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ void *closure; /* our user defined closure */
+};
+char *cmdlinequote (char quotes, char *s);
+char *cmdlineescape (char quotes, char *s);
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+char *format_cmdline (bool oldway, const char *srepos, const char *format, ...);
+#else /* SUPPORT_OLD_INFO_FMT_STRINGS */
+char *format_cmdline (const char *format, ...);
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+/* Many, many CVS calls to xstrdup depend on it to return NULL when its
+ * argument is NULL.
+ */
+#define xstrdup Xstrdup
+char *Xstrdup (const char *str)
+ __attribute__ ((__malloc__));
+
+char *Xasprintf (const char *format, ...)
+ __attribute__ ((__malloc__, __format__ (__printf__, 1, 2)));
+char *Xasnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+ __attribute__ ((__malloc__, __format__ (__printf__, 3, 4)));
+bool readBool (const char *infopath, const char *option,
+ const char *p, bool *val);
+
+FILE *xfopen (const char *, const char *);
+char *xcanonicalize_file_name (const char *path);
+bool isThisHost (const char *otherhost);
+bool isSamePath (const char *path1_in, const char *path2_in);
+#endif /* !SUBR_H */
diff --git a/src/tag.c b/src/tag.c
new file mode 100644
index 0000000..7f2fbba
--- /dev/null
+++ b/src/tag.c
@@ -0,0 +1,1689 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * Tag and Rtag
+ *
+ * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
+ * Tag uses the checked out revision in the current directory, rtag uses
+ * the modules database, if necessary.
+ */
+
+#include "cvs.h"
+#include "save-cwd.h"
+
+static int rtag_proc (int argc, char **argv, char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *mname, char *msg);
+static int check_fileproc (void *callerdat, struct file_info *finfo);
+static int check_filesdoneproc (void *callerdat, int err,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int pretag_proc (const char *_repository, const char *_filter,
+ void *_closure);
+static void masterlist_delproc (Node *_p);
+static void tag_delproc (Node *_p);
+static int pretag_list_to_args_proc (Node *_p, void *_closure);
+
+static Dtype tag_dirproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int rtag_fileproc (void *callerdat, struct file_info *finfo);
+static int rtag_delete (RCSNode *rcsfile);
+static int tag_fileproc (void *callerdat, struct file_info *finfo);
+
+static char *numtag; /* specific revision to tag */
+static bool numtag_validated = false;
+static char *date = NULL;
+static char *symtag; /* tag to add or delete */
+static bool delete_flag; /* adding a tag by default */
+static bool branch_mode; /* make an automagic "branch" tag */
+static bool disturb_branch_tags = false;/* allow -F,-d to disturb branch tags */
+static bool force_tag_match = true; /* force tag to match by default */
+static bool force_tag_move; /* don't force tag to move by default */
+static bool check_uptodate; /* no uptodate-check by default */
+static bool attic_too; /* remove tag from Attic files */
+static bool is_rtag;
+
+struct tag_info
+{
+ Ctype status;
+ char *oldrev;
+ char *rev;
+ char *tag;
+ char *options;
+};
+
+struct master_lists
+{
+ List *tlist;
+};
+
+static List *mtlist;
+
+static const char rtag_opts[] = "+aBbdFflnQqRr:D:";
+static const char *const rtag_usage[] =
+{
+ "Usage: %s %s [-abdFflnR] [-r rev|-D date] tag modules...\n",
+ "\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
+ "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
+ "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
+ "\t-d\tDelete the given tag.\n",
+ "\t-F\tMove tag if it already exists.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive.\n",
+ "\t-n\tNo execution of 'tag program'.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-r rev\tExisting revision/tag.\n",
+ "\t-D\tExisting date.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+static const char tag_opts[] = "+BbcdFflQqRr:D:";
+static const char *const tag_usage[] =
+{
+ "Usage: %s %s [-bcdFflR] [-r rev|-D date] tag [files...]\n",
+ "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
+ "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
+ "\t-c\tCheck that working files are unmodified.\n",
+ "\t-d\tDelete the given tag.\n",
+ "\t-F\tMove tag if it already exists.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, not recursive.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-r rev\tExisting revision/tag.\n",
+ "\t-D\tExisting date.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+
+
+int
+cvstag (int argc, char **argv)
+{
+ bool local = false; /* recursive by default */
+ int c;
+ int err = 0;
+ bool run_module_prog = true;
+
+ is_rtag = (strcmp (cvs_cmd_name, "rtag") == 0);
+
+ if (argc == -1)
+ usage (is_rtag ? rtag_usage : tag_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, is_rtag ? rtag_opts : tag_opts)) != -1)
+ {
+ switch (c)
+ {
+ case 'a':
+ attic_too = true;
+ break;
+ case 'b':
+ branch_mode = true;
+ break;
+ case 'B':
+ disturb_branch_tags = true;
+ break;
+ case 'c':
+ check_uptodate = true;
+ break;
+ case 'd':
+ delete_flag = true;
+ break;
+ case 'F':
+ force_tag_move = true;
+ break;
+ case 'f':
+ force_tag_match = false;
+ break;
+ case 'l':
+ local = true;
+ break;
+ case 'n':
+ run_module_prog = false;
+ break;
+ case 'Q':
+ case 'q':
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ cvs_cmd_name);
+ break;
+ case 'R':
+ local = false;
+ break;
+ case 'r':
+ parse_tagdate (&numtag, &date, optarg);
+ break;
+ case 'D':
+ if (date) free (date);
+ date = Make_Date (optarg);
+ break;
+ case '?':
+ default:
+ usage (is_rtag ? rtag_usage : tag_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < (is_rtag ? 2 : 1))
+ usage (is_rtag ? rtag_usage : tag_usage);
+ symtag = argv[0];
+ argc--;
+ argv++;
+
+ if (date && delete_flag)
+ error (1, 0, "-d makes no sense with a date specification.");
+ if (delete_flag && branch_mode)
+ error (0, 0, "warning: -b ignored with -d options");
+ RCS_check_tag (symtag);
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ /* We're the client side. Fire up the remote server. */
+ start_server ();
+
+ ign_setup ();
+
+ if (attic_too)
+ send_arg ("-a");
+ if (branch_mode)
+ send_arg ("-b");
+ if (disturb_branch_tags)
+ send_arg ("-B");
+ if (check_uptodate)
+ send_arg ("-c");
+ if (delete_flag)
+ send_arg ("-d");
+ if (force_tag_move)
+ send_arg ("-F");
+ if (!force_tag_match)
+ send_arg ("-f");
+ if (local)
+ send_arg ("-l");
+ if (!run_module_prog)
+ send_arg ("-n");
+
+ if (numtag)
+ option_with_arg ("-r", numtag);
+ if (date)
+ client_senddate (date);
+
+ send_arg ("--");
+
+ send_arg (symtag);
+
+ if (is_rtag)
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ send_arg (argv[i]);
+ send_to_server ("rtag\012", 0);
+ }
+ else
+ {
+ send_files (argc, argv, local, 0,
+
+ /* I think the -c case is like "cvs status", in
+ which we really better be correct rather than
+ being fast; it is just too confusing otherwise. */
+ check_uptodate ? 0 : SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("tag\012", 0);
+ }
+
+ return get_responses_and_close ();
+ }
+#endif
+
+ if (is_rtag)
+ {
+ DBM *db;
+ int i;
+ db = open_module ();
+ for (i = 0; i < argc; i++)
+ {
+ /* XXX last arg should be repository, but doesn't make sense here */
+ history_write ('T', (delete_flag ? "D" : (numtag ? numtag :
+ (date ? date : "A"))), symtag, argv[i], "");
+ err += do_module (db, argv[i], TAG,
+ delete_flag ? "Untagging" : "Tagging",
+ rtag_proc, NULL, 0, local, run_module_prog,
+ 0, symtag);
+ }
+ close_module (db);
+ }
+ else
+ {
+ err = rtag_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL,
+ NULL);
+ }
+
+ return err;
+}
+
+
+
+struct pretag_proc_data {
+ List *tlist;
+ bool delete_flag;
+ bool force_tag_move;
+ char *symtag;
+};
+
+/*
+ * called from Parse_Info, this routine processes a line that came out
+ * of the posttag file and turns it into a command and executes it.
+ *
+ * RETURNS
+ * the absolute value of the return value of run_exec, which may or
+ * may not be the return value of the child process. this is
+ * contrained to return positive values because Parse_Info is summing
+ * return values and testing for non-zeroness to signify one or more
+ * of its callbacks having returned an error.
+ */
+static int
+posttag_proc (const char *repository, const char *filter, void *closure)
+{
+ char *cmdline;
+ const char *srepos = Short_Repository (repository);
+ struct pretag_proc_data *ppd = closure;
+
+ /* %t = tag being added/moved/removed
+ * %o = operation = "add" | "mov" | "del"
+ * %b = branch mode = "?" (delete ops - unknown) | "T" (branch)
+ * | "N" (not branch)
+ * %c = cvs_cmd_name
+ * %p = path from $CVSROOT
+ * %r = path from root
+ * %{sVv} = attribute list = file name, old version tag will be deleted
+ * from, new version tag will be added to (or
+ * deleted from until
+ * SUPPORT_OLD_INFO_FMT_STRINGS is undefined).
+ */
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ false, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "t", "s", ppd->symtag,
+ "o", "s", ppd->delete_flag
+ ? "del" : ppd->force_tag_move ? "mov" : "add",
+ "b", "c", delete_flag
+ ? '?' : branch_mode ? 'T' : 'N',
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s", current_parsed_root->directory,
+ "sVv", ",", ppd->tlist,
+ pretag_list_to_args_proc, (void *) NULL,
+ (char *) NULL);
+
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ error (0, 0, "pretag proc resolved to the empty string!");
+ return 1;
+ }
+
+ run_setup (cmdline);
+
+ free (cmdline);
+ return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL));
+}
+
+
+
+/*
+ * Call any postadmin procs.
+ */
+static int
+tag_filesdoneproc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ Node *p;
+ List *mtlist, *tlist;
+ struct pretag_proc_data ppd;
+
+ TRACE (TRACE_FUNCTION, "tag_filesdoneproc (%d, %s, %s)", err, repository,
+ update_dir);
+
+ mtlist = callerdat;
+ p = findnode (mtlist, update_dir);
+ if (p != NULL)
+ tlist = ((struct master_lists *) p->data)->tlist;
+ else
+ tlist = NULL;
+ if (tlist == NULL || tlist->list->next == tlist->list)
+ return err;
+
+ ppd.tlist = tlist;
+ ppd.delete_flag = delete_flag;
+ ppd.force_tag_move = force_tag_move;
+ ppd.symtag = symtag;
+ Parse_Info (CVSROOTADM_POSTTAG, repository, posttag_proc,
+ PIOPT_ALL, &ppd);
+
+ return err;
+}
+
+
+
+/*
+ * callback proc for doing the real work of tagging
+ */
+/* ARGSUSED */
+static int
+rtag_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile,
+ int shorten, int local_specified, char *mname, char *msg)
+{
+ /* Begin section which is identical to patch_proc--should this
+ be abstracted out somehow? */
+ char *myargv[2];
+ int err = 0;
+ int which;
+ char *repository;
+ char *where;
+
+#ifdef HAVE_PRINTF_PTR
+ TRACE (TRACE_FUNCTION,
+ "rtag_proc (argc=%d, argv=%p, xwhere=%s,\n"
+ " mwhere=%s, mfile=%s, shorten=%d,\n"
+ " local_specified=%d, mname=%s, msg=%s)",
+ argc, (void *)argv, xwhere ? xwhere : "(null)",
+ mwhere ? mwhere : "(null)", mfile ? mfile : "(null)",
+ shorten, local_specified,
+ mname ? mname : "(null)", msg ? msg : "(null)" );
+#else
+ TRACE (TRACE_FUNCTION,
+ "rtag_proc (argc=%d, argv=%lx, xwhere=%s,\n"
+ " mwhere=%s, mfile=%s, shorten=%d,\n"
+ " local_specified=%d, mname=%s, msg=%s )",
+ argc, (unsigned long)argv, xwhere ? xwhere : "(null)",
+ mwhere ? mwhere : "(null)", mfile ? mfile : "(null)",
+ shorten, local_specified,
+ mname ? mname : "(null)", msg ? msg : "(null)" );
+#endif
+
+ if (is_rtag)
+ {
+ repository = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ + 2);
+ (void) sprintf (repository, "%s/%s", current_parsed_root->directory,
+ argv[0]);
+ where = xmalloc (strlen (argv[0])
+ + (mfile == NULL ? 0 : strlen (mfile) + 1)
+ + 1);
+ (void) strcpy (where, argv[0]);
+
+ /* If MFILE isn't null, we need to set up to do only part of the
+ * module.
+ */
+ if (mfile != NULL)
+ {
+ char *cp;
+ char *path;
+
+ /* If the portion of the module is a path, put the dir part on
+ * REPOS.
+ */
+ if ((cp = strrchr (mfile, '/')) != NULL)
+ {
+ *cp = '\0';
+ (void) strcat (repository, "/");
+ (void) strcat (repository, mfile);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ mfile = cp + 1;
+ }
+
+ /* take care of the rest */
+ path = xmalloc (strlen (repository) + strlen (mfile) + 5);
+ (void) sprintf (path, "%s/%s", repository, mfile);
+ if (isdir (path))
+ {
+ /* directory means repository gets the dir tacked on */
+ (void) strcpy (repository, path);
+ (void) strcat (where, "/");
+ (void) strcat (where, mfile);
+ }
+ else
+ {
+ myargv[0] = argv[0];
+ myargv[1] = mfile;
+ argc = 2;
+ argv = myargv;
+ }
+ free (path);
+ }
+
+ /* cd to the starting repository */
+ if (CVS_CHDIR (repository) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", repository);
+ free (repository);
+ free (where);
+ return 1;
+ }
+ /* End section which is identical to patch_proc. */
+
+ if (delete_flag || attic_too || (force_tag_match && numtag))
+ which = W_REPOS | W_ATTIC;
+ else
+ which = W_REPOS;
+ }
+ else
+ {
+ where = NULL;
+ which = W_LOCAL;
+ repository = "";
+ }
+
+ if (numtag != NULL && !numtag_validated)
+ {
+ tag_check_valid (numtag, argc - 1, argv + 1, local_specified, 0,
+ repository, false);
+ numtag_validated = true;
+ }
+
+ /* check to make sure they are authorized to tag all the
+ specified files in the repository */
+
+ mtlist = getlist ();
+ err = start_recursion (check_fileproc, check_filesdoneproc,
+ NULL, NULL, NULL,
+ argc - 1, argv + 1, local_specified, which, 0,
+ CVS_LOCK_READ, where, 1, repository);
+
+ if (err)
+ {
+ error (1, 0, "correct the above errors first!");
+ }
+
+ /* It would be nice to provide consistency with respect to
+ commits; however CVS lacks the infrastructure to do that (see
+ Concurrency in cvs.texinfo and comment in do_recursion). */
+
+ /* start the recursion processor */
+ err = start_recursion
+ (is_rtag ? rtag_fileproc : tag_fileproc,
+ tag_filesdoneproc, tag_dirproc, NULL, mtlist, argc - 1, argv + 1,
+ local_specified, which, 0, CVS_LOCK_WRITE, where, 1,
+ repository);
+ dellist (&mtlist);
+ if (which & W_REPOS) free (repository);
+ if (where != NULL)
+ free (where);
+ return err;
+}
+
+
+
+/* check file that is to be tagged */
+/* All we do here is add it to our list */
+static int
+check_fileproc (void *callerdat, struct file_info *finfo)
+{
+ const char *xdir;
+ Node *p;
+ Vers_TS *vers;
+ List *tlist;
+ struct tag_info *ti;
+ int addit = 1;
+
+ TRACE (TRACE_FUNCTION, "check_fileproc (%s, %s, %s)",
+ finfo->repository ? finfo->repository : "(null)",
+ finfo->fullname ? finfo->fullname : "(null)",
+ finfo->rcs ? (finfo->rcs->path ? finfo->rcs->path : "(null)")
+ : "NULL");
+
+ if (check_uptodate)
+ {
+ switch (Classify_File (finfo, NULL, NULL, NULL, 1, 0, &vers, 0))
+ {
+ case T_UPTODATE:
+ case T_CHECKOUT:
+ case T_PATCH:
+ case T_REMOVE_ENTRY:
+ break;
+ case T_UNKNOWN:
+ case T_CONFLICT:
+ case T_NEEDS_MERGE:
+ case T_MODIFIED:
+ case T_ADDED:
+ case T_REMOVED:
+ default:
+ error (0, 0, "%s is locally modified", finfo->fullname);
+ freevers_ts (&vers);
+ return 1;
+ }
+ }
+ else
+ vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
+
+ if (finfo->update_dir[0] == '\0')
+ xdir = ".";
+ else
+ xdir = finfo->update_dir;
+ if ((p = findnode (mtlist, xdir)) != NULL)
+ {
+ tlist = ((struct master_lists *) p->data)->tlist;
+ }
+ else
+ {
+ struct master_lists *ml;
+
+ tlist = getlist ();
+ p = getnode ();
+ p->key = xstrdup (xdir);
+ p->type = UPDATE;
+ ml = xmalloc (sizeof (struct master_lists));
+ ml->tlist = tlist;
+ p->data = ml;
+ p->delproc = masterlist_delproc;
+ (void) addnode (mtlist, p);
+ }
+ /* do tlist */
+ p = getnode ();
+ p->key = xstrdup (finfo->file);
+ p->type = UPDATE;
+ p->delproc = tag_delproc;
+ if (vers->srcfile == NULL)
+ {
+ if (!really_quiet)
+ error (0, 0, "nothing known about %s", finfo->file);
+ freevers_ts (&vers);
+ freenode (p);
+ return 1;
+ }
+
+ /* Here we duplicate the calculation in tag_fileproc about which
+ version we are going to tag. There probably are some subtle races
+ (e.g. numtag is "foo" which gets moved between here and
+ tag_fileproc). */
+ p->data = ti = xmalloc (sizeof (struct tag_info));
+ ti->tag = xstrdup (numtag ? numtag : vers->tag);
+ if (!is_rtag && numtag == NULL && date == NULL)
+ ti->rev = xstrdup (vers->vn_user);
+ else
+ ti->rev = RCS_getversion (vers->srcfile, numtag, date,
+ force_tag_match, NULL);
+
+ if (ti->rev != NULL)
+ {
+ ti->oldrev = RCS_getversion (vers->srcfile, symtag, NULL, 1, NULL);
+
+ if (ti->oldrev == NULL)
+ {
+ if (delete_flag)
+ {
+ /* Deleting a tag which did not exist is a noop and
+ should not be logged. */
+ addit = 0;
+ }
+ }
+ else if (delete_flag)
+ {
+ free (ti->rev);
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ /* a hack since %v used to mean old or new rev */
+ ti->rev = xstrdup (ti->oldrev);
+#else /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ ti->rev = NULL;
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ }
+ else if (strcmp(ti->oldrev, p->data) == 0)
+ addit = 0;
+ else if (!force_tag_move)
+ addit = 0;
+ }
+ else
+ addit = 0;
+ if (!addit)
+ {
+ free(p->data);
+ p->data = NULL;
+ }
+ freevers_ts (&vers);
+ (void)addnode (tlist, p);
+ return 0;
+}
+
+
+
+static int
+check_filesdoneproc (void *callerdat, int err, const char *repos,
+ const char *update_dir, List *entries)
+{
+ int n;
+ Node *p;
+ List *tlist;
+ struct pretag_proc_data ppd;
+
+ p = findnode (mtlist, update_dir);
+ if (p != NULL)
+ tlist = ((struct master_lists *) p->data)->tlist;
+ else
+ tlist = NULL;
+ if (tlist == NULL || tlist->list->next == tlist->list)
+ return err;
+
+ ppd.tlist = tlist;
+ ppd.delete_flag = delete_flag;
+ ppd.force_tag_move = force_tag_move;
+ ppd.symtag = symtag;
+ if ((n = Parse_Info (CVSROOTADM_TAGINFO, repos, pretag_proc, PIOPT_ALL,
+ &ppd)) > 0)
+ {
+ error (0, 0, "Pre-tag check failed");
+ err += n;
+ }
+ return err;
+}
+
+
+
+/*
+ * called from Parse_Info, this routine processes a line that came out
+ * of a taginfo file and turns it into a command and executes it.
+ *
+ * RETURNS
+ * the absolute value of the return value of run_exec, which may or
+ * may not be the return value of the child process. this is
+ * contrained to return positive values because Parse_Info is adding up
+ * return values and testing for non-zeroness to signify one or more
+ * of its callbacks having returned an error.
+ */
+static int
+pretag_proc (const char *repository, const char *filter, void *closure)
+{
+ char *newfilter = NULL;
+ char *cmdline;
+ const char *srepos = Short_Repository (repository);
+ struct pretag_proc_data *ppd = closure;
+
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ if (!strchr (filter, '%'))
+ {
+ error (0,0,
+ "warning: taginfo line contains no format strings:\n"
+ " \"%s\"\n"
+ "Filling in old defaults ('%%t %%o %%p %%{sv}'), but please be aware that this\n"
+ "usage is deprecated.", filter);
+ newfilter = xmalloc (strlen (filter) + 16);
+ strcpy (newfilter, filter);
+ strcat (newfilter, " %t %o %p %{sv}");
+ filter = newfilter;
+ }
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+
+ /* %t = tag being added/moved/removed
+ * %o = operation = "add" | "mov" | "del"
+ * %b = branch mode = "?" (delete ops - unknown) | "T" (branch)
+ * | "N" (not branch)
+ * %c = cvs_cmd_name
+ * %p = path from $CVSROOT
+ * %r = path from root
+ * %{sVv} = attribute list = file name, old version tag will be deleted
+ * from, new version tag will be added to (or
+ * deleted from until
+ * SUPPORT_OLD_INFO_FMT_STRINGS is undefined)
+ */
+ /*
+ * Cast any NULL arguments as appropriate pointers as this is an
+ * stdarg function and we need to be certain the caller gets what
+ * is expected.
+ */
+ cmdline = format_cmdline (
+#ifdef SUPPORT_OLD_INFO_FMT_STRINGS
+ false, srepos,
+#endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
+ filter,
+ "t", "s", ppd->symtag,
+ "o", "s", ppd->delete_flag ? "del" :
+ ppd->force_tag_move ? "mov" : "add",
+ "b", "c", delete_flag
+ ? '?' : branch_mode ? 'T' : 'N',
+ "c", "s", cvs_cmd_name,
+#ifdef SERVER_SUPPORT
+ "R", "s", referrer ? referrer->original : "NONE",
+#endif /* SERVER_SUPPORT */
+ "p", "s", srepos,
+ "r", "s", current_parsed_root->directory,
+ "sVv", ",", ppd->tlist,
+ pretag_list_to_args_proc, (void *) NULL,
+ (char *) NULL);
+
+ if (newfilter) free (newfilter);
+
+ if (!cmdline || !strlen (cmdline))
+ {
+ if (cmdline) free (cmdline);
+ error (0, 0, "pretag proc resolved to the empty string!");
+ return 1;
+ }
+
+ run_setup (cmdline);
+
+ /* FIXME - the old code used to run the following here:
+ *
+ * if (!isfile(s))
+ * {
+ * error (0, errno, "cannot find pre-tag filter '%s'", s);
+ * free(s);
+ * return (1);
+ * }
+ *
+ * not sure this is really necessary. it might give a little finer grained
+ * error than letting the execution attempt fail but i'm not sure. in any
+ * case it should be easy enough to add a function in run.c to test its
+ * first arg for fileness & executability.
+ */
+
+ free (cmdline);
+ return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL));
+}
+
+
+
+static void
+masterlist_delproc (Node *p)
+{
+ struct master_lists *ml = p->data;
+
+ dellist (&ml->tlist);
+ free (ml);
+ return;
+}
+
+
+
+static void
+tag_delproc (Node *p)
+{
+ struct tag_info *ti;
+ if (p->data)
+ {
+ ti = (struct tag_info *) p->data;
+ if (ti->oldrev) free (ti->oldrev);
+ if (ti->rev) free (ti->rev);
+ free (ti->tag);
+ free (p->data);
+ p->data = NULL;
+ }
+ return;
+}
+
+
+
+/* to be passed into walklist with a list of tags
+ * p->key = tagname
+ * p->data = struct tag_info *
+ * p->data->oldrev = rev tag will be deleted from
+ * p->data->rev = rev tag will be added to
+ * p->data->tag = tag oldrev is attached to, if any
+ *
+ * closure will be a struct format_cmdline_walklist_closure
+ * where closure is undefined
+ */
+static int
+pretag_list_to_args_proc (Node *p, void *closure)
+{
+ struct tag_info *taginfo = (struct tag_info *)p->data;
+ struct format_cmdline_walklist_closure *c =
+ (struct format_cmdline_walklist_closure *)closure;
+ char *arg = NULL;
+ const char *f;
+ char *d;
+ size_t doff;
+
+ if (!p->data) return 1;
+
+ f = c->format;
+ d = *c->d;
+ /* foreach requested attribute */
+ while (*f)
+ {
+ switch (*f++)
+ {
+ case 's':
+ arg = p->key;
+ break;
+ case 'T':
+ arg = taginfo->tag ? taginfo->tag : "";
+ break;
+ case 'v':
+ arg = taginfo->rev ? taginfo->rev : "NONE";
+ break;
+ case 'V':
+ arg = taginfo->oldrev ? taginfo->oldrev : "NONE";
+ break;
+ default:
+ error(1,0,
+ "Unknown format character or not a list attribute: %c",
+ f[-1]);
+ break;
+ }
+ /* copy the attribute into an argument */
+ if (c->quotes)
+ {
+ arg = cmdlineescape (c->quotes, arg);
+ }
+ else
+ {
+ arg = cmdlinequote ('"', arg);
+ }
+
+ doff = d - *c->buf;
+ expand_string (c->buf, c->length, doff + strlen (arg));
+ d = *c->buf + doff;
+ strncpy (d, arg, strlen (arg));
+ d += strlen (arg);
+
+ free (arg);
+
+ /* and always put the extra space on. we'll have to back up a char when we're
+ * done, but that seems most efficient
+ */
+ doff = d - *c->buf;
+ expand_string (c->buf, c->length, doff + 1);
+ d = *c->buf + doff;
+ *d++ = ' ';
+ }
+ /* correct our original pointer into the buff */
+ *c->d = d;
+ return 0;
+}
+
+
+/*
+ * Called to rtag a particular file, as appropriate with the options that were
+ * set above.
+ */
+/* ARGSUSED */
+static int
+rtag_fileproc (void *callerdat, struct file_info *finfo)
+{
+ RCSNode *rcsfile;
+ char *version = NULL, *rev = NULL;
+ int retcode = 0;
+ int retval = 0;
+ static bool valtagged = false;
+
+ /* find the parsed RCS data */
+ if ((rcsfile = finfo->rcs) == NULL)
+ {
+ retval = 1;
+ goto free_vars_and_return;
+ }
+
+ /*
+ * For tagging an RCS file which is a symbolic link, you'd best be
+ * running with RCS 5.6, since it knows how to handle symbolic links
+ * correctly without breaking your link!
+ */
+
+ if (delete_flag)
+ {
+ retval = rtag_delete (rcsfile);
+ goto free_vars_and_return;
+ }
+
+ /*
+ * If we get here, we are adding a tag. But, if -a was specified, we
+ * need to check to see if a -r or -D option was specified. If neither
+ * was specified and the file is in the Attic, remove the tag.
+ */
+ if (attic_too && (!numtag && !date))
+ {
+ if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
+ {
+ retval = rtag_delete (rcsfile);
+ goto free_vars_and_return;
+ }
+ }
+
+ version = RCS_getversion (rcsfile, numtag, date, force_tag_match, NULL);
+ if (version == NULL)
+ {
+ /* If -a specified, clean up any old tags */
+ if (attic_too)
+ (void)rtag_delete (rcsfile);
+
+ if (!quiet && !force_tag_match)
+ {
+ error (0, 0, "cannot find tag `%s' in `%s'",
+ numtag ? numtag : "head", rcsfile->path);
+ retval = 1;
+ }
+ goto free_vars_and_return;
+ }
+ if (numtag
+ && isdigit ((unsigned char)*numtag)
+ && strcmp (numtag, version) != 0)
+ {
+
+ /*
+ * We didn't find a match for the numeric tag that was specified, but
+ * that's OK. just pass the numeric tag on to rcs, to be tagged as
+ * specified. Could get here if one tried to tag "1.1.1" and there
+ * was a 1.1.1 branch with some head revision. In this case, we want
+ * the tag to reference "1.1.1" and not the revision at the head of
+ * the branch. Use a symbolic tag for that.
+ */
+ rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
+ retcode = RCS_settag(rcsfile, symtag, numtag);
+ if (retcode == 0)
+ RCS_rewrite (rcsfile, NULL, NULL);
+ }
+ else
+ {
+ char *oversion;
+
+ /*
+ * As an enhancement for the case where a tag is being re-applied to
+ * a large body of a module, make one extra call to RCS_getversion to
+ * see if the tag is already set in the RCS file. If so, check to
+ * see if it needs to be moved. If not, do nothing. This will
+ * likely save a lot of time when simply moving the tag to the
+ * "current" head revisions of a module -- which I have found to be a
+ * typical tagging operation.
+ */
+ rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
+ oversion = RCS_getversion (rcsfile, symtag, NULL, 1, NULL);
+ if (oversion != NULL)
+ {
+ int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
+
+ /*
+ * if versions the same and neither old or new are branches don't
+ * have to do anything
+ */
+ if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
+ {
+ free (oversion);
+ goto free_vars_and_return;
+ }
+
+ if (!force_tag_move)
+ {
+ /* we're NOT going to move the tag */
+ (void)printf ("W %s", finfo->fullname);
+
+ (void)printf (" : %s already exists on %s %s",
+ symtag, isbranch ? "branch" : "version",
+ oversion);
+ (void)printf (" : NOT MOVING tag to %s %s\n",
+ branch_mode ? "branch" : "version", rev);
+ free (oversion);
+ goto free_vars_and_return;
+ }
+ else /* force_tag_move is set and... */
+ if ((isbranch && !disturb_branch_tags) ||
+ (!isbranch && disturb_branch_tags))
+ {
+ error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
+ finfo->fullname,
+ isbranch ? "branch" : "non-branch",
+ symtag, oversion, rev,
+ isbranch ? "" : " due to `-B' option");
+ free (oversion);
+ goto free_vars_and_return;
+ }
+ free (oversion);
+ }
+ retcode = RCS_settag (rcsfile, symtag, rev);
+ if (retcode == 0)
+ RCS_rewrite (rcsfile, NULL, NULL);
+ }
+
+ if (retcode != 0)
+ {
+ error (1, retcode == -1 ? errno : 0,
+ "failed to set tag `%s' to revision `%s' in `%s'",
+ symtag, rev, rcsfile->path);
+ retval = 1;
+ goto free_vars_and_return;
+ }
+
+free_vars_and_return:
+ if (branch_mode && rev) free (rev);
+ if (version) free (version);
+ if (!delete_flag && !retval && !valtagged)
+ {
+ tag_check_valid (symtag, 0, NULL, 0, 0, NULL, true);
+ valtagged = true;
+ }
+ return retval;
+}
+
+
+
+/*
+ * If -d is specified, "force_tag_match" is set, so that this call to
+ * RCS_getversion() will return a NULL version string if the symbolic
+ * tag does not exist in the RCS file.
+ *
+ * If the -r flag was used, numtag is set, and we only delete the
+ * symtag from files that have numtag.
+ *
+ * This is done here because it's MUCH faster than just blindly calling
+ * "rcs" to remove the tag... trust me.
+ */
+static int
+rtag_delete (RCSNode *rcsfile)
+{
+ char *version;
+ int retcode, isbranch;
+
+ if (numtag)
+ {
+ version = RCS_getversion (rcsfile, numtag, NULL, 1, NULL);
+ if (version == NULL)
+ return (0);
+ free (version);
+ }
+
+ version = RCS_getversion (rcsfile, symtag, NULL, 1, NULL);
+ if (version == NULL)
+ return 0;
+ free (version);
+
+
+ isbranch = RCS_nodeisbranch (rcsfile, symtag);
+ if ((isbranch && !disturb_branch_tags) ||
+ (!isbranch && disturb_branch_tags))
+ {
+ if (!quiet)
+ error (0, 0,
+ "Not removing %s tag `%s' from `%s'%s.",
+ isbranch ? "branch" : "non-branch",
+ symtag, rcsfile->path,
+ isbranch ? "" : " due to `-B' option");
+ return 1;
+ }
+
+ if ((retcode = RCS_deltag(rcsfile, symtag)) != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to remove tag `%s' from `%s'", symtag,
+ rcsfile->path);
+ return 1;
+ }
+ RCS_rewrite (rcsfile, NULL, NULL);
+ return 0;
+}
+
+
+
+/*
+ * Called to tag a particular file (the currently checked out version is
+ * tagged with the specified tag - or the specified tag is deleted).
+ */
+/* ARGSUSED */
+static int
+tag_fileproc (void *callerdat, struct file_info *finfo)
+{
+ char *version, *oversion;
+ char *nversion = NULL;
+ char *rev;
+ Vers_TS *vers;
+ int retcode = 0;
+ int retval = 0;
+ static bool valtagged = false;
+
+ vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
+
+ if (numtag || date)
+ {
+ nversion = RCS_getversion (vers->srcfile, numtag, date,
+ force_tag_match, NULL);
+ if (!nversion)
+ goto free_vars_and_return;
+ }
+ if (delete_flag)
+ {
+
+ int isbranch;
+ /*
+ * If -d is specified, "force_tag_match" is set, so that this call to
+ * RCS_getversion() will return a NULL version string if the symbolic
+ * tag does not exist in the RCS file.
+ *
+ * This is done here because it's MUCH faster than just blindly calling
+ * "rcs" to remove the tag... trust me.
+ */
+
+ version = RCS_getversion (vers->srcfile, symtag, NULL, 1, NULL);
+ if (version == NULL || vers->srcfile == NULL)
+ goto free_vars_and_return;
+
+ free (version);
+
+ isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
+ if ((isbranch && !disturb_branch_tags) ||
+ (!isbranch && disturb_branch_tags))
+ {
+ if (!quiet)
+ error(0, 0,
+ "Not removing %s tag `%s' from `%s'%s.",
+ isbranch ? "branch" : "non-branch",
+ symtag, vers->srcfile->path,
+ isbranch ? "" : " due to `-B' option");
+ retval = 1;
+ goto free_vars_and_return;
+ }
+
+ if ((retcode = RCS_deltag (vers->srcfile, symtag)) != 0)
+ {
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to remove tag %s from %s", symtag,
+ vers->srcfile->path);
+ retval = 1;
+ goto free_vars_and_return;
+ }
+ RCS_rewrite (vers->srcfile, NULL, NULL);
+
+ /* warm fuzzies */
+ if (!really_quiet)
+ {
+ cvs_output ("D ", 2);
+ cvs_output (finfo->fullname, 0);
+ cvs_output ("\n", 1);
+ }
+
+ goto free_vars_and_return;
+ }
+
+ /*
+ * If we are adding a tag, we need to know which version we have checked
+ * out and we'll tag that version.
+ */
+ if (!nversion)
+ version = vers->vn_user;
+ else
+ version = nversion;
+ if (!version)
+ goto free_vars_and_return;
+ else if (strcmp (version, "0") == 0)
+ {
+ if (!quiet)
+ error (0, 0, "couldn't tag added but un-commited file `%s'",
+ finfo->file);
+ goto free_vars_and_return;
+ }
+ else if (version[0] == '-')
+ {
+ if (!quiet)
+ error (0, 0, "skipping removed but un-commited file `%s'",
+ finfo->file);
+ goto free_vars_and_return;
+ }
+ else if (vers->srcfile == NULL)
+ {
+ if (!quiet)
+ error (0, 0, "cannot find revision control file for `%s'",
+ finfo->file);
+ goto free_vars_and_return;
+ }
+
+ /*
+ * As an enhancement for the case where a tag is being re-applied to a
+ * large number of files, make one extra call to RCS_getversion to see
+ * if the tag is already set in the RCS file. If so, check to see if it
+ * needs to be moved. If not, do nothing. This will likely save a lot of
+ * time when simply moving the tag to the "current" head revisions of a
+ * module -- which I have found to be a typical tagging operation.
+ */
+ rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
+ oversion = RCS_getversion (vers->srcfile, symtag, NULL, 1, NULL);
+ if (oversion != NULL)
+ {
+ int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
+
+ /*
+ * if versions the same and neither old or new are branches don't have
+ * to do anything
+ */
+ if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
+ {
+ free (oversion);
+ if (branch_mode)
+ free (rev);
+ goto free_vars_and_return;
+ }
+
+ if (!force_tag_move)
+ {
+ /* we're NOT going to move the tag */
+ cvs_output ("W ", 2);
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" : ", 0);
+ cvs_output (symtag, 0);
+ cvs_output (" already exists on ", 0);
+ cvs_output (isbranch ? "branch" : "version", 0);
+ cvs_output (" ", 0);
+ cvs_output (oversion, 0);
+ cvs_output (" : NOT MOVING tag to ", 0);
+ cvs_output (branch_mode ? "branch" : "version", 0);
+ cvs_output (" ", 0);
+ cvs_output (rev, 0);
+ cvs_output ("\n", 1);
+ free (oversion);
+ if (branch_mode)
+ free (rev);
+ goto free_vars_and_return;
+ }
+ else /* force_tag_move == 1 and... */
+ if ((isbranch && !disturb_branch_tags) ||
+ (!isbranch && disturb_branch_tags))
+ {
+ error (0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
+ finfo->fullname,
+ isbranch ? "branch" : "non-branch",
+ symtag, oversion, rev,
+ isbranch ? "" : " due to `-B' option");
+ free (oversion);
+ if (branch_mode)
+ free (rev);
+ goto free_vars_and_return;
+ }
+ free (oversion);
+ }
+
+ if ((retcode = RCS_settag(vers->srcfile, symtag, rev)) != 0)
+ {
+ error (1, retcode == -1 ? errno : 0,
+ "failed to set tag %s to revision %s in %s",
+ symtag, rev, vers->srcfile->path);
+ if (branch_mode)
+ free (rev);
+ retval = 1;
+ goto free_vars_and_return;
+ }
+ if (branch_mode)
+ free (rev);
+ RCS_rewrite (vers->srcfile, NULL, NULL);
+
+ /* more warm fuzzies */
+ if (!really_quiet)
+ {
+ cvs_output ("T ", 2);
+ cvs_output (finfo->fullname, 0);
+ cvs_output ("\n", 1);
+ }
+
+ free_vars_and_return:
+ if (nversion != NULL)
+ free (nversion);
+ freevers_ts (&vers);
+ if (!delete_flag && !retval && !valtagged)
+ {
+ tag_check_valid (symtag, 0, NULL, 0, 0, NULL, true);
+ valtagged = true;
+ }
+ return retval;
+}
+
+
+
+/*
+ * Print a warm fuzzy message
+ */
+/* ARGSUSED */
+static Dtype
+tag_dirproc (void *callerdat, const char *dir, const char *repos,
+ const char *update_dir, List *entries)
+{
+
+ if (ignore_directory (update_dir))
+ {
+ /* print the warm fuzzy message */
+ if (!quiet)
+ error (0, 0, "Ignoring %s", update_dir);
+ return R_SKIP_ALL;
+ }
+
+ if (!quiet)
+ error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging",
+ update_dir);
+ return R_PROCESS;
+}
+
+
+
+/* Code relating to the val-tags file. Note that this file has no way
+ of knowing when a tag has been deleted. The problem is that there
+ is no way of knowing whether a tag still exists somewhere, when we
+ delete it some places. Using per-directory val-tags files (in
+ CVSREP) might be better, but that might slow down the process of
+ verifying that a tag is correct (maybe not, for the likely cases,
+ if carefully done), and/or be harder to implement correctly. */
+
+struct val_args {
+ const char *name;
+ int found;
+};
+
+static int
+val_fileproc (void *callerdat, struct file_info *finfo)
+{
+ RCSNode *rcsdata;
+ struct val_args *args = callerdat;
+ char *tag;
+
+ if ((rcsdata = finfo->rcs) == NULL)
+ /* Not sure this can happen, after all we passed only
+ W_REPOS | W_ATTIC. */
+ return 0;
+
+ tag = RCS_gettag (rcsdata, args->name, 1, NULL);
+ if (tag != NULL)
+ {
+ /* FIXME: should find out a way to stop the search at this point. */
+ args->found = 1;
+ free (tag);
+ }
+ return 0;
+}
+
+
+
+/* This routine determines whether a tag appears in CVSROOT/val-tags.
+ *
+ * The val-tags file will be open read-only when IDB is NULL. Since writes to
+ * val-tags always append to it, the lack of locking is okay. The worst case
+ * race condition might misinterpret a partially written "foobar" matched, for
+ * instance, a request for "f", "foo", of "foob". Such a mismatch would be
+ * caught harmlessly later.
+ *
+ * Before CVS adds a tag to val-tags, it will lock val-tags for write and
+ * verify that the tag is still not present to avoid adding it twice.
+ *
+ * NOTES
+ * This function expects its parent to handle any necessary locking of the
+ * val-tags file.
+ *
+ * INPUTS
+ * idb When this value is NULL, the val-tags file is opened in
+ * in read-only mode. When present, the val-tags file is opened
+ * in read-write mode and the DBM handle is stored in *IDB.
+ * name The tag to search for.
+ *
+ * OUTPUTS
+ * *idb The val-tags file opened for read/write, or NULL if it couldn't
+ * be opened.
+ *
+ * ERRORS
+ * Exits with an error message if the val-tags file cannot be opened for
+ * read (failure to open val-tags read/write is harmless - see below).
+ *
+ * RETURNS
+ * true 1. If NAME exists in val-tags.
+ * 2. If IDB is non-NULL and val-tags cannot be opened for write.
+ * This allows callers to ignore the harmless inability to
+ * update the val-tags cache.
+ * false If the file could be opened and the tag is not present.
+ */
+static int is_in_val_tags (DBM **idb, const char *name)
+{
+ DBM *db = NULL;
+ char *valtags_filename;
+ datum mytag;
+ int status;
+
+ /* Casting out const should be safe here - input datums are not
+ * written to by the myndbm functions.
+ */
+ mytag.dptr = (char *)name;
+ mytag.dsize = strlen (name);
+
+ valtags_filename = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_VALTAGS);
+
+ if (idb)
+ {
+ mode_t omask;
+
+ omask = umask (cvsumask);
+ db = dbm_open (valtags_filename, O_RDWR | O_CREAT, 0666);
+ umask (omask);
+
+ if (!db)
+ {
+
+ error (0, errno, "warning: cannot open `%s' read/write",
+ valtags_filename);
+ *idb = NULL;
+ return 1;
+ }
+
+ *idb = db;
+ }
+ else
+ {
+ db = dbm_open (valtags_filename, O_RDONLY, 0444);
+ if (!db && !existence_error (errno))
+ error (1, errno, "cannot read %s", valtags_filename);
+ }
+
+ /* If the file merely fails to exist, we just keep going and create
+ it later if need be. */
+
+ status = 0;
+ if (db)
+ {
+ datum val;
+
+ val = dbm_fetch (db, mytag);
+ if (val.dptr != NULL)
+ /* Found. The tag is valid. */
+ status = 1;
+
+ /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
+
+ if (!idb) dbm_close (db);
+ }
+
+ free (valtags_filename);
+ return status;
+}
+
+
+
+/* Add a tag to the CVSROOT/val-tags cache. Establishes a write lock and
+ * reverifies that the tag does not exist before adding it.
+ */
+static void add_to_val_tags (const char *name)
+{
+ DBM *db;
+ datum mytag;
+ datum value;
+
+ if (noexec) return;
+
+ val_tags_lock (current_parsed_root->directory);
+
+ /* Check for presence again since we have a lock now. */
+ if (is_in_val_tags (&db, name)) return;
+
+ /* Casting out const should be safe here - input datums are not
+ * written to by the myndbm functions.
+ */
+ mytag.dptr = (char *)name;
+ mytag.dsize = strlen (name);
+ value.dptr = "y";
+ value.dsize = 1;
+
+ if (dbm_store (db, mytag, value, DBM_REPLACE) < 0)
+ error (0, errno, "failed to store %s into val-tags", name);
+ dbm_close (db);
+
+ clear_val_tags_lock ();
+}
+
+
+
+static Dtype
+val_direntproc (void *callerdat, const char *dir, const char *repository,
+ const char *update_dir, List *entries)
+{
+ /* This is not quite right--it doesn't get right the case of "cvs
+ update -d -r foobar" where foobar is a tag which exists only in
+ files in a directory which does not exist yet, but which is
+ about to be created. */
+ if (isdir (dir))
+ return R_PROCESS;
+ return R_SKIP_ALL;
+}
+
+
+
+/* With VALID set, insert NAME into val-tags if it is not already present
+ * there.
+ *
+ * Without VALID set, check to see whether NAME is a valid tag. If so, return.
+ * If not print an error message and exit.
+ *
+ * INPUTS
+ *
+ * ARGC, ARGV, LOCAL, and AFLAG specify which files we will be operating on.
+ *
+ * REPOSITORY is the repository if we need to cd into it, or NULL if
+ * we are already there, or "" if we should do a W_LOCAL recursion.
+ * Sorry for three cases, but the "" case is needed in case the
+ * working directories come from diverse parts of the repository, the
+ * NULL case avoids an unneccesary chdir, and the non-NULL, non-""
+ * case is needed for checkout, where we don't want to chdir if the
+ * tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any
+ * local directory.
+ *
+ * ERRORS
+ * Errors may be encountered opening and accessing the DBM file. Write
+ * errors generate warnings and read errors are fatal. When !VALID and NAME
+ * is not in val-tags, errors may also be generated as per start_recursion.
+ * When !VALID, non-existance of tags both in val-tags and in the archive
+ * files also causes a fatal error.
+ *
+ * RETURNS
+ * Nothing.
+ */
+void
+tag_check_valid (const char *name, int argc, char **argv, int local, int aflag,
+ char *repository, bool valid)
+{
+ struct val_args the_val_args;
+ struct saved_cwd cwd;
+ int which;
+
+#ifdef HAVE_PRINTF_PTR
+ TRACE (TRACE_FUNCTION,
+ "tag_check_valid (name=%s, argc=%d, argv=%p, local=%d,\n"
+ " aflag=%d, repository=%s, valid=%s)",
+ name ? name : "(name)", argc, (void *)argv, local, aflag,
+ repository ? repository : "(null)",
+ valid ? "true" : "false");
+#else
+ TRACE (TRACE_FUNCTION,
+ "tag_check_valid (name=%s, argc=%d, argv=%lx, local=%d,\n"
+ " aflag=%d, repository=%s, valid=%s)",
+ name ? name : "(name)", argc, (unsigned long)argv, local, aflag,
+ repository ? repository : "(null)",
+ valid ? "true" : "false");
+#endif
+
+ /* Numeric tags require only a syntactic check. */
+ if (isdigit ((unsigned char) name[0]))
+ {
+ /* insert is not possible for numeric revisions */
+ assert (!valid);
+ if (RCS_valid_rev (name)) return;
+ else
+ error (1, 0, "\
+Numeric tag %s invalid. Numeric tags should be of the form X[.X]...", name);
+ }
+
+ /* Special tags are always valid. */
+ if (strcmp (name, TAG_BASE) == 0
+ || strcmp (name, TAG_HEAD) == 0)
+ {
+ /* insert is not possible for numeric revisions */
+ assert (!valid);
+ return;
+ }
+
+ /* Verify that the tag is valid syntactically. Some later code once made
+ * assumptions about this.
+ */
+ RCS_check_tag (name);
+
+ if (is_in_val_tags (NULL, name)) return;
+
+ if (!valid)
+ {
+ /* We didn't find the tag in val-tags, so look through all the RCS files
+ * to see whether it exists there. Yes, this is expensive, but there
+ * is no other way to cope with a tag which might have been created
+ * by an old version of CVS, from before val-tags was invented
+ */
+
+ the_val_args.name = name;
+ the_val_args.found = 0;
+ which = W_REPOS | W_ATTIC;
+
+ if (repository == NULL || repository[0] == '\0')
+ which |= W_LOCAL;
+ else
+ {
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+ if (CVS_CHDIR (repository) < 0)
+ error (1, errno, "cannot change to %s directory", repository);
+ }
+
+ start_recursion
+ (val_fileproc, NULL, val_direntproc, NULL,
+ &the_val_args, argc, argv, local, which, aflag,
+ CVS_LOCK_READ, NULL, 1, repository);
+ if (repository != NULL && repository[0] != '\0')
+ {
+ if (restore_cwd (&cwd))
+ error (1, errno, "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+ }
+
+ if (!the_val_args.found)
+ error (1, 0, "no such tag `%s'", name);
+ }
+
+ /* The tags is valid but not mentioned in val-tags. Add it. */
+ add_to_val_tags (name);
+}
diff --git a/src/update.c b/src/update.c
new file mode 100644
index 0000000..4fb3440
--- /dev/null
+++ b/src/update.c
@@ -0,0 +1,2907 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * "update" updates the version in the present directory with respect to the RCS
+ * repository. The present version must have been created by "checkout". The
+ * user can keep up-to-date by calling "update" whenever he feels like it.
+ *
+ * The present version can be committed by "commit", but this keeps the version
+ * in tact.
+ *
+ * Arguments following the options are taken to be file names to be updated,
+ * rather than updating the entire directory.
+ *
+ * Modified or non-existent RCS files are checked out and reported as U
+ * <user_file>
+ *
+ * Modified user files are reported as M <user_file>. If both the RCS file and
+ * the user file have been modified, the user file is replaced by the result
+ * of rcsmerge, and a backup file is written for the user in .#file.version.
+ * If this throws up irreconcilable differences, the file is reported as C
+ * <user_file>, and as M <user_file> otherwise.
+ *
+ * Files added but not yet committed are reported as A <user_file>. Files
+ * removed but not yet committed are reported as R <user_file>.
+ *
+ * If the current directory contains subdirectories that hold concurrent
+ * versions, these are updated too. If the -d option was specified, new
+ * directories added to the repository are automatically created and updated
+ * as well.
+ */
+
+#include "cvs.h"
+#include <assert.h>
+#include "save-cwd.h"
+#ifdef SERVER_SUPPORT
+# include "md5.h"
+#endif
+#include "watch.h"
+#include "fileattr.h"
+#include "edit.h"
+#include "getline.h"
+#include "buffer.h"
+#include "hardlink.h"
+
+static int checkout_file (struct file_info *finfo, Vers_TS *vers_ts,
+ int adding, int merging, int update_server);
+#ifdef SERVER_SUPPORT
+static void checkout_to_buffer (void *, const char *, size_t);
+static int patch_file (struct file_info *finfo,
+ Vers_TS *vers_ts,
+ int *docheckout, struct stat *file_info,
+ unsigned char *checksum);
+static void patch_file_write (void *, const char *, size_t);
+#endif
+static int merge_file (struct file_info *finfo, Vers_TS *vers);
+static int scratch_file (struct file_info *finfo, Vers_TS *vers);
+static Dtype update_dirent_proc (void *callerdat, const char *dir,
+ const char *repository,
+ const char *update_dir,
+ List *entries);
+static int update_dirleave_proc (void *callerdat, const char *dir,
+ int err, const char *update_dir,
+ List *entries);
+static int update_fileproc (void *callerdat, struct file_info *);
+static int update_filesdone_proc (void *callerdat, int err,
+ const char *repository,
+ const char *update_dir, List *entries);
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+static int get_linkinfo_proc( void *_callerdat, struct _finfo * );
+#endif
+static void join_file (struct file_info *finfo, Vers_TS *vers_ts);
+
+static char *options = NULL;
+static char *tag = NULL;
+static char *date = NULL;
+/* This is a bit of a kludge. We call WriteTag at the beginning
+ before we know whether nonbranch is set or not. And then at the
+ end, once we have the right value for nonbranch, we call WriteTag
+ again. I don't know whether the first call is necessary or not.
+ rewrite_tag is nonzero if we are going to have to make that second
+ call. warned is nonzero if we've already warned the user that the
+ tag occurs as both a revision tag and a branch tag. */
+static int rewrite_tag;
+static int nonbranch;
+static int warned;
+
+/* If we set the tag or date for a subdirectory, we use this to undo
+ the setting. See update_dirent_proc. */
+static char *tag_update_dir;
+
+static char *join_rev1, *join_date1;
+static char *join_rev2, *join_date2;
+static int aflag = 0;
+static int toss_local_changes = 0;
+static int force_tag_match = 1;
+static int update_build_dirs = 0;
+static int update_prune_dirs = 0;
+static int pipeout = 0;
+static int dotemplate = 0;
+#ifdef SERVER_SUPPORT
+static int patches = 0;
+static int rcs_diff_patches = 0;
+#endif
+static List *ignlist = NULL;
+static time_t last_register_time;
+static const char *const update_usage[] =
+{
+ "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n",
+ " [-I ign] [-W spec] [files...]\n",
+ "\t-A\tReset any sticky tags/date/kopts.\n",
+ "\t-P\tPrune empty directories.\n",
+ "\t-C\tOverwrite locally modified files with clean repository copies.\n",
+ "\t-d\tBuild directories, like checkout does.\n",
+ "\t-f\tForce a head revision match if tag/date not found.\n",
+ "\t-l\tLocal directory only, no recursion.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-p\tSend updates to standard output (avoids stickiness).\n",
+ "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n",
+ "\t-r rev\tUpdate using specified revision/tag (is sticky).\n",
+ "\t-D date\tSet date to update from (is sticky).\n",
+ "\t-j rev\tMerge in changes made between current revision and rev.\n",
+ "\t-I ign\tMore files to ignore (! to reset).\n",
+ "\t-W spec\tWrappers specification line.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+
+
+/*
+ * update is the argv,argc based front end for arg parsing
+ */
+int
+update (int argc, char **argv)
+{
+ int c, err;
+ int local = 0; /* recursive by default */
+ int which; /* where to look for files and dirs */
+ char *xjoin_rev1, *xjoin_date1,
+ *xjoin_rev2, *xjoin_date2,
+ *join_orig1, *join_orig2;
+
+ if (argc == -1)
+ usage (update_usage);
+
+ xjoin_rev1 = xjoin_date1 = xjoin_rev2 = xjoin_date2 = join_orig1 =
+ join_orig2 = NULL;
+
+ ign_setup ();
+ wrap_setup ();
+
+ /* parse the args */
+ optind = 0;
+ while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:D:j:I:W:")) != -1)
+ {
+ switch (c)
+ {
+ case 'A':
+ aflag = 1;
+ break;
+ case 'C':
+ toss_local_changes = 1;
+ break;
+ case 'I':
+ ign_add (optarg, 0);
+ break;
+ case 'W':
+ wrap_add (optarg, 0);
+ break;
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'Q':
+ case 'q':
+ /* The CVS 1.5 client sends these options (in addition to
+ Global_option requests), so we must ignore them. */
+ if (!server_active)
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ cvs_cmd_name);
+ break;
+ case 'd':
+ update_build_dirs = 1;
+ break;
+ case 'f':
+ force_tag_match = 0;
+ break;
+ case 'r':
+ parse_tagdate (&tag, &date, optarg);
+ break;
+ case 'D':
+ if (date) free (date);
+ date = Make_Date (optarg);
+ break;
+ case 'P':
+ update_prune_dirs = 1;
+ break;
+ case 'p':
+ pipeout = 1;
+ noexec = 1; /* so no locks will be created */
+ break;
+ case 'j':
+ if (join_orig2)
+ error (1, 0, "only two -j options can be specified");
+ if (join_orig1)
+ {
+ join_orig2 = xstrdup (optarg);
+ parse_tagdate (&xjoin_rev2, &xjoin_date2, optarg);
+ }
+ else
+ {
+ join_orig1 = xstrdup (optarg);
+ parse_tagdate (&xjoin_rev1, &xjoin_date1, optarg);
+ }
+ break;
+ case 'u':
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ patches = 1;
+ rcs_diff_patches = server_use_rcs_diff ();
+ }
+ else
+#endif
+ usage (update_usage);
+ break;
+ case '?':
+ default:
+ usage (update_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ int pass;
+
+ /* The first pass does the regular update. If we receive at least
+ one patch which failed, we do a second pass and just fetch
+ those files whose patches failed. */
+ pass = 1;
+ do
+ {
+ int status;
+
+ start_server ();
+
+ if (local)
+ send_arg("-l");
+ if (update_build_dirs)
+ send_arg("-d");
+ if (pipeout)
+ send_arg("-p");
+ if (!force_tag_match)
+ send_arg("-f");
+ if (aflag)
+ send_arg("-A");
+ if (toss_local_changes)
+ send_arg("-C");
+ if (update_prune_dirs)
+ send_arg("-P");
+ client_prune_dirs = update_prune_dirs;
+ option_with_arg ("-r", tag);
+ if (options && options[0] != '\0')
+ send_arg (options);
+ if (date)
+ client_senddate (date);
+ if (join_orig1)
+ option_with_arg ("-j", join_orig1);
+ if (join_orig2)
+ option_with_arg ("-j", join_orig2);
+ wrap_send ();
+
+ if (failed_patches_count == 0)
+ {
+ unsigned int flags = 0;
+
+ /* If the server supports the command "update-patches", that
+ means that it knows how to handle the -u argument to update,
+ which means to send patches instead of complete files.
+
+ We don't send -u if failed_patches != NULL, so that the
+ server doesn't try to send patches which will just fail
+ again. At least currently, the client also clobbers the
+ file and tells the server it is lost, which also will get
+ a full file instead of a patch, but it seems clean to omit
+ -u. */
+ if (supported_request ("update-patches"))
+ send_arg ("-u");
+
+ send_arg ("--");
+
+ if (update_build_dirs)
+ flags |= SEND_BUILD_DIRS;
+
+ if (toss_local_changes) {
+ flags |= SEND_NO_CONTENTS;
+ flags |= BACKUP_MODIFIED_FILES;
+ }
+
+ /* If noexec, probably could be setting SEND_NO_CONTENTS.
+ Same caveats as for "cvs status" apply. */
+
+ send_files (argc, argv, local, aflag, flags);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ }
+ else
+ {
+ int i;
+
+ (void) printf ("%s client: refetching unpatchable files\n",
+ program_name);
+
+ if (toplevel_wd != NULL
+ && CVS_CHDIR (toplevel_wd) < 0)
+ {
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+ }
+
+ send_arg ("--");
+
+ for (i = 0; i < failed_patches_count; i++)
+ if (unlink_file (failed_patches[i]) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s",
+ failed_patches[i]);
+ send_files (failed_patches_count, failed_patches, local,
+ aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
+ send_file_names (failed_patches_count, failed_patches, 0);
+ free_names (&failed_patches_count, failed_patches);
+ }
+
+ send_to_server ("update\012", 0);
+
+ status = get_responses_and_close ();
+
+ /* If there are any conflicts, the server will return a
+ non-zero exit status. If any patches failed, we still
+ want to run the update again. We use a pass count to
+ avoid an endless loop. */
+
+ /* Notes: (1) assuming that status != 0 implies a
+ potential conflict is the best we can cleanly do given
+ the current protocol. I suppose that trying to
+ re-fetch in cases where there was a more serious error
+ is probably more or less harmless, but it isn't really
+ ideal. (2) it would be nice to have a testsuite case for the
+ conflict-and-patch-failed case. */
+
+ if (status != 0
+ && (failed_patches_count == 0 || pass > 1))
+ {
+ if (failed_patches_count > 0)
+ free_names (&failed_patches_count, failed_patches);
+ return status;
+ }
+
+ ++pass;
+ } while (failed_patches_count > 0);
+
+ return 0;
+ }
+#endif
+
+ if (tag != NULL)
+ tag_check_valid (tag, argc, argv, local, aflag, "", false);
+ if (join_rev1 != NULL)
+ tag_check_valid (xjoin_rev1, argc, argv, local, aflag, "", false);
+ if (join_rev2 != NULL)
+ tag_check_valid (xjoin_rev2, argc, argv, local, aflag, "", false);
+
+ /*
+ * If we are updating the entire directory (for real) and building dirs
+ * as we go, we make sure there is no static entries file and write the
+ * tag file as appropriate
+ */
+ if (argc <= 0 && !pipeout)
+ {
+ if (update_build_dirs)
+ {
+ if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ char *repos = Name_Repository (NULL, NULL);
+ server_clear_entstat (".", repos);
+ free (repos);
+ }
+#endif
+ }
+
+ /* keep the CVS/Tag file current with the specified arguments */
+ if (aflag || tag || date)
+ {
+ char *repos = Name_Repository (NULL, NULL);
+ WriteTag (NULL, tag, date, 0, ".", repos);
+ free (repos);
+ rewrite_tag = 1;
+ nonbranch = -1;
+ warned = 0;
+ }
+ }
+
+ /* look for files/dirs locally and in the repository */
+ which = W_LOCAL | W_REPOS;
+
+ /* look in the attic too if a tag or date is specified */
+ if (tag || date || join_orig1)
+ {
+ TRACE (TRACE_DATA, "update: searching attic");
+ which |= W_ATTIC;
+ }
+
+ /* call the command line interface */
+ err = do_update (argc, argv, options, tag, date, force_tag_match,
+ local, update_build_dirs, aflag, update_prune_dirs,
+ pipeout, which, xjoin_rev1, xjoin_date1, xjoin_rev2,
+ xjoin_date2, NULL, 1, NULL);
+
+ /* Free the space allocated for tags and dates, if necessary. */
+ if (tag) free (tag);
+ if (date) free (date);
+
+ return err;
+}
+
+
+
+/*
+ * Command line interface to update (used by checkout)
+ *
+ * repository = cvsroot->repository + update_dir. This is necessary for
+ * checkout so that start_recursion can determine our repository. In the
+ * update case, start_recursion can use the CVS/Root & CVS/Repository file
+ * to determine this value.
+ */
+int
+do_update (int argc, char **argv, char *xoptions, char *xtag, char *xdate,
+ int xforce, int local, int xbuild, int xaflag, int xprune,
+ int xpipeout, int which, char *xjoin_rev1, char *xjoin_date1,
+ char *xjoin_rev2, char *xjoin_date2,
+ char *preload_update_dir, int xdotemplate, char *repository)
+{
+ int err = 0;
+
+ TRACE (TRACE_FUNCTION,
+"do_update (%s, %s, %s, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %s, %s, %d, %s)",
+ xoptions ? xoptions : "(null)", xtag ? xtag : "(null)",
+ xdate ? xdate : "(null)", xforce, local, xbuild, xaflag, xprune,
+ xpipeout, which, xjoin_rev1 ? xjoin_rev1 : "(null)",
+ xjoin_date1 ? xjoin_date1 : "(null)",
+ xjoin_rev2 ? xjoin_rev2 : "(null)",
+ xjoin_date2 ? xjoin_date2 : "(null)",
+ preload_update_dir ? preload_update_dir : "(null)", xdotemplate,
+ repository ? repository : "(null)");
+
+ /* fill in the statics */
+ options = xoptions;
+ tag = xtag;
+ date = xdate;
+ force_tag_match = xforce;
+ update_build_dirs = xbuild;
+ aflag = xaflag;
+ update_prune_dirs = xprune;
+ pipeout = xpipeout;
+ dotemplate = xdotemplate;
+
+ /* setup the join support */
+ join_rev1 = xjoin_rev1;
+ join_date1 = xjoin_date1;
+ join_rev2 = xjoin_rev2;
+ join_date2 = xjoin_date2;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms)
+ {
+ /* We need to do an extra recursion, bleah. It's to make sure
+ that we know as much as possible about file linkage. */
+ hardlist = getlist();
+ working_dir = xgetcwd (); /* save top-level working dir */
+
+ /* FIXME-twp: the arguments to start_recursion make me dizzy. This
+ function call was copied from the update_fileproc call that
+ follows it; someone should make sure that I did it right. */
+ err = start_recursion
+ (get_linkinfo_proc, NULL, NULL, NULL, NULL,
+ argc, argv, local, which, aflag, CVS_LOCK_READ,
+ preload_update_dir, 1, NULL);
+ if (err)
+ return err;
+
+ /* FIXME-twp: at this point we should walk the hardlist
+ and update the `links' field of each hardlink_info struct
+ to list the files that are linked on dist. That would make
+ it easier & more efficient to compare the disk linkage with
+ the repository linkage (a simple strcmp). */
+ }
+#endif
+
+ /* call the recursion processor */
+ err = start_recursion (update_fileproc, update_filesdone_proc,
+ update_dirent_proc, update_dirleave_proc, NULL,
+ argc, argv, local, which, aflag, CVS_LOCK_READ,
+ preload_update_dir, 1, repository);
+
+ /* see if we need to sleep before returning to avoid time-stamp races */
+ if (!server_active && last_register_time)
+ {
+ sleep_past (last_register_time);
+ }
+
+ return err;
+}
+
+
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+/*
+ * The get_linkinfo_proc callback adds each file to the hardlist
+ * (see hardlink.c).
+ */
+
+static int
+get_linkinfo_proc (void *callerdat, struct file_info *finfo)
+{
+ char *fullpath;
+ Node *linkp;
+ struct hardlink_info *hlinfo;
+
+ /* Get the full pathname of the current file. */
+ fullpath = Xasprintf ("%s/%s", working_dir, finfo->fullname);
+
+ /* To permit recursing into subdirectories, files
+ are keyed on the full pathname and not on the basename. */
+ linkp = lookup_file_by_inode (fullpath);
+ if (linkp == NULL)
+ {
+ /* The file isn't on disk; we are probably restoring
+ a file that was removed. */
+ return 0;
+ }
+
+ /* Create a new, empty hardlink_info node. */
+ hlinfo = xmalloc (sizeof (struct hardlink_info));
+
+ hlinfo->status = (Ctype) 0; /* is this dumb? */
+ hlinfo->checked_out = 0;
+
+ linkp->data = hlinfo;
+
+ return 0;
+}
+#endif
+
+
+
+/*
+ * This is the callback proc for update. It is called for each file in each
+ * directory by the recursion code. The current directory is the local
+ * instantiation. file is the file name we are to operate on. update_dir is
+ * set to the path relative to where we started (for pretty printing).
+ * repository is the repository. entries and srcfiles are the pre-parsed
+ * entries and source control files.
+ *
+ * This routine decides what needs to be done for each file and does the
+ * appropriate magic for checkout
+ */
+static int
+update_fileproc (void *callerdat, struct file_info *finfo)
+{
+ int retval, nb;
+ Ctype status;
+ Vers_TS *vers;
+
+ status = Classify_File (finfo, tag, date, options, force_tag_match,
+ aflag, &vers, pipeout);
+
+ /* Keep track of whether TAG is a branch tag.
+ Note that if it is a branch tag in some files and a nonbranch tag
+ in others, treat it as a nonbranch tag. */
+ if (rewrite_tag
+ && tag != NULL
+ && finfo->rcs != NULL)
+ {
+ char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL);
+ if (rev != NULL
+ && nonbranch != (nb = !RCS_nodeisbranch (finfo->rcs, tag)))
+ {
+ if (nonbranch >= 0 && !warned && !quiet)
+ {
+ error (0, 0,
+"warning: %s is a branch tag in some files and a revision tag in others.",
+ tag);
+ warned = 1;
+ }
+ if (nonbranch < nb) nonbranch = nb;
+ }
+ if (rev != NULL)
+ free (rev);
+ }
+
+ if (pipeout)
+ {
+ /*
+ * We just return success without doing anything if any of the really
+ * funky cases occur
+ *
+ * If there is still a valid RCS file, do a regular checkout type
+ * operation
+ */
+ switch (status)
+ {
+ case T_UNKNOWN: /* unknown file was explicitly asked
+ * about */
+ case T_REMOVE_ENTRY: /* needs to be un-registered */
+ case T_ADDED: /* added but not committed */
+ retval = 0;
+ break;
+ case T_CONFLICT: /* old punt-type errors */
+ retval = 1;
+ break;
+ case T_UPTODATE: /* file was already up-to-date */
+ case T_NEEDS_MERGE: /* needs merging */
+ case T_MODIFIED: /* locally modified */
+ case T_REMOVED: /* removed but not committed */
+ case T_CHECKOUT: /* needs checkout */
+ case T_PATCH: /* needs patch */
+ retval = checkout_file (finfo, vers, 0, 0, 0);
+ break;
+
+ default: /* can't ever happen :-) */
+ error (0, 0,
+ "unknown file status %d for file %s", status, finfo->file);
+ retval = 0;
+ break;
+ }
+ }
+ else
+ {
+ switch (status)
+ {
+ case T_UNKNOWN: /* unknown file was explicitly asked
+ * about */
+ case T_UPTODATE: /* file was already up-to-date */
+ retval = 0;
+ break;
+ case T_CONFLICT: /* old punt-type errors */
+ retval = 1;
+ write_letter (finfo, 'C');
+ break;
+ case T_NEEDS_MERGE: /* needs merging */
+ if (! toss_local_changes)
+ {
+ retval = merge_file (finfo, vers);
+ break;
+ }
+ /* else FALL THROUGH */
+ case T_MODIFIED: /* locally modified */
+ retval = 0;
+ if (toss_local_changes)
+ {
+ char *bakname;
+ bakname = backup_file (finfo->file, vers->vn_user);
+ /* This behavior is sufficiently unexpected to
+ justify overinformativeness, I think. */
+ if (!really_quiet && !server_active)
+ (void) printf ("(Locally modified %s moved to %s)\n",
+ finfo->file, bakname);
+ free (bakname);
+
+ /* The locally modified file is still present, but
+ it will be overwritten by the repository copy
+ after this. */
+ status = T_CHECKOUT;
+ retval = checkout_file (finfo, vers, 0, 0, 1);
+ }
+ else
+ {
+ if (vers->ts_conflict)
+ {
+ if (file_has_markers (finfo))
+ {
+ write_letter (finfo, 'C');
+ retval = 1;
+ }
+ else
+ {
+ /* Reregister to clear conflict flag. */
+ Register (finfo->entries, finfo->file,
+ vers->vn_rcs, vers->ts_rcs,
+ vers->options, vers->tag,
+ vers->date, NULL);
+ }
+ }
+ if (!retval)
+ write_letter (finfo, 'M');
+ }
+ break;
+ case T_PATCH: /* needs patch */
+#ifdef SERVER_SUPPORT
+ if (patches)
+ {
+ int docheckout;
+ struct stat file_info;
+ unsigned char checksum[16];
+
+ retval = patch_file (finfo,
+ vers, &docheckout,
+ &file_info, checksum);
+ if (! docheckout)
+ {
+ if (server_active && retval == 0)
+ server_updated (finfo, vers,
+ (rcs_diff_patches
+ ? SERVER_RCS_DIFF
+ : SERVER_PATCHED),
+ file_info.st_mode, checksum,
+ NULL);
+ break;
+ }
+ }
+#endif
+ /* If we're not running as a server, just check the
+ file out. It's simpler and faster than producing
+ and applying patches. */
+ /* Fall through. */
+ case T_CHECKOUT: /* needs checkout */
+ retval = checkout_file (finfo, vers, 0, 0, 1);
+ break;
+ case T_ADDED: /* added but not committed */
+ write_letter (finfo, 'A');
+ retval = 0;
+ break;
+ case T_REMOVED: /* removed but not committed */
+ write_letter (finfo, 'R');
+ retval = 0;
+ break;
+ case T_REMOVE_ENTRY: /* needs to be un-registered */
+ retval = scratch_file (finfo, vers);
+ break;
+ default: /* can't ever happen :-) */
+ error (0, 0,
+ "unknown file status %d for file %s", status, finfo->file);
+ retval = 0;
+ break;
+ }
+ }
+
+ /* only try to join if things have gone well thus far */
+ if (retval == 0 && join_rev1)
+ join_file (finfo, vers);
+
+ /* if this directory has an ignore list, add this file to it */
+ if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL))
+ {
+ Node *p;
+
+ p = getnode ();
+ p->type = FILES;
+ p->key = xstrdup (finfo->file);
+ if (addnode (ignlist, p) != 0)
+ freenode (p);
+ }
+
+ freevers_ts (&vers);
+ return retval;
+}
+
+
+
+static void
+update_ignproc (const char *file, const char *dir)
+{
+ struct file_info finfo;
+ char *tmp;
+
+ memset (&finfo, 0, sizeof (finfo));
+ finfo.file = file;
+ finfo.update_dir = dir;
+
+ finfo.fullname = tmp = Xasprintf ("%s%s%s",
+ dir[0] == '\0' ? "" : dir,
+ dir[0] == '\0' ? "" : "/",
+ file);
+ write_letter (&finfo, '?');
+ free (tmp);
+}
+
+
+
+/* ARGSUSED */
+static int
+update_filesdone_proc (void *callerdat, int err, const char *repository,
+ const char *update_dir, List *entries)
+{
+ if (nonbranch < 0) nonbranch = 0;
+ if (rewrite_tag)
+ {
+ WriteTag (NULL, tag, date, nonbranch, update_dir, repository);
+ rewrite_tag = 0;
+ }
+
+ /* if this directory has an ignore list, process it then free it */
+ if (ignlist)
+ {
+ ignore_files (ignlist, entries, update_dir, update_ignproc);
+ dellist (&ignlist);
+ }
+
+ /* Clean up CVS admin dirs if we are export */
+ if (strcmp (cvs_cmd_name, "export") == 0)
+ {
+ /* I'm not sure the existence_error is actually possible (except
+ in cases where we really should print a message), but since
+ this code used to ignore all errors, I'll play it safe. */
+ if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
+ error (0, errno, "cannot remove %s directory", CVSADM);
+ }
+ else if (!server_active && !pipeout)
+ {
+ /* If there is no CVS/Root file, add one */
+ if (!isfile (CVSADM_ROOT))
+ Create_Root (NULL, original_parsed_root->original);
+ }
+
+ return err;
+}
+
+
+
+/*
+ * update_dirent_proc () is called back by the recursion processor before a
+ * sub-directory is processed for update. In this case, update_dirent proc
+ * will probably create the directory unless -d isn't specified and this is a
+ * new directory. A return code of 0 indicates the directory should be
+ * processed by the recursion code. A return of non-zero indicates the
+ * recursion code should skip this directory.
+ */
+static Dtype
+update_dirent_proc (void *callerdat, const char *dir, const char *repository,
+ const char *update_dir, List *entries)
+{
+ if (ignore_directory (update_dir))
+ {
+ /* print the warm fuzzy message */
+ if (!quiet)
+ error (0, 0, "Ignoring %s", update_dir);
+ return R_SKIP_ALL;
+ }
+
+ if (!isdir (dir))
+ {
+ /* if we aren't building dirs, blow it off */
+ if (!update_build_dirs)
+ return R_SKIP_ALL;
+
+ /* Various CVS administrators are in the habit of removing
+ the repository directory for things they don't want any
+ more. I've even been known to do it myself (on rare
+ occasions). Not the usual recommended practice, but we
+ want to try to come up with some kind of
+ reasonable/documented/sensible behavior. Generally
+ the behavior is to just skip over that directory (see
+ dirs test in sanity.sh; the case which reaches here
+ is when update -d is specified, and the working directory
+ is gone but the subdirectory is still mentioned in
+ CVS/Entries). */
+ /* In the remote case, the client should refrain from
+ sending us the directory in the first place. So we
+ want to continue to give an error, so clients make
+ sure to do this. */
+ if (!server_active && !isdir (repository))
+ return R_SKIP_ALL;
+
+ if (noexec)
+ {
+ /* ignore the missing dir if -n is specified */
+ error (0, 0, "New directory `%s' -- ignored", update_dir);
+ return R_SKIP_ALL;
+ }
+ else
+ {
+ /* otherwise, create the dir and appropriate adm files */
+
+ /* If no tag or date were specified on the command line,
+ and we're not using -A, we want the subdirectory to use
+ the tag and date, if any, of the current directory.
+ That way, update -d will work correctly when working on
+ a branch.
+
+ We use TAG_UPDATE_DIR to undo the tag setting in
+ update_dirleave_proc. If we did not do this, we would
+ not correctly handle a working directory with multiple
+ tags (and maybe we should prohibit such working
+ directories, but they work now and we shouldn't make
+ them stop working without more thought). */
+ if ((tag == NULL && date == NULL) && ! aflag)
+ {
+ ParseTag (&tag, &date, &nonbranch);
+ if (tag != NULL || date != NULL)
+ tag_update_dir = xstrdup (update_dir);
+ }
+
+ make_directory (dir);
+ Create_Admin (dir, update_dir, repository, tag, date,
+ /* This is a guess. We will rewrite it later
+ via WriteTag. */
+ 0,
+ 0,
+ dotemplate);
+ rewrite_tag = 1;
+ nonbranch = -1;
+ warned = 0;
+ Subdir_Register (entries, NULL, dir);
+ }
+ }
+ /* Do we need to check noexec here? */
+ else if (!pipeout)
+ {
+ char *cvsadmdir;
+
+ /* The directory exists. Check to see if it has a CVS
+ subdirectory. */
+
+ cvsadmdir = Xasprintf ("%s/%s", dir, CVSADM);
+
+ if (!isdir (cvsadmdir))
+ {
+ /* We cannot successfully recurse into a directory without a CVS
+ subdirectory. Generally we will have already printed
+ "? foo". */
+ free (cvsadmdir);
+ return R_SKIP_ALL;
+ }
+ free (cvsadmdir);
+ }
+
+ /*
+ * If we are building dirs and not going to stdout, we make sure there is
+ * no static entries file and write the tag file as appropriate
+ */
+ if (!pipeout)
+ {
+ if (update_build_dirs)
+ {
+ char *tmp = Xasprintf ("%s/%s", dir, CVSADM_ENTSTAT);
+
+ if (unlink_file (tmp) < 0 && ! existence_error (errno))
+ error (1, errno, "cannot remove file %s", tmp);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_clear_entstat (update_dir, repository);
+#endif
+ free (tmp);
+ }
+
+ /* keep the CVS/Tag file current with the specified arguments */
+ if (aflag || tag || date)
+ {
+ WriteTag (dir, tag, date, 0, update_dir, repository);
+ rewrite_tag = 1;
+ nonbranch = -1;
+ warned = 0;
+ }
+
+ WriteTemplate (update_dir, dotemplate, repository);
+
+ /* initialize the ignore list for this directory */
+ ignlist = getlist ();
+ }
+
+ /* print the warm fuzzy message */
+ if (!quiet)
+ error (0, 0, "Updating %s", update_dir);
+
+ return R_PROCESS;
+}
+
+
+
+/*
+ * update_dirleave_proc () is called back by the recursion code upon leaving
+ * a directory. It will prune empty directories if needed and will execute
+ * any appropriate update programs.
+ */
+/* ARGSUSED */
+static int
+update_dirleave_proc (void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries)
+{
+ /* Delete the ignore list if it hasn't already been done. */
+ if (ignlist)
+ dellist (&ignlist);
+
+ /* If we set the tag or date for a new subdirectory in
+ update_dirent_proc, and we're now done with that subdirectory,
+ undo the tag/date setting. Note that we know that the tag and
+ date were both originally NULL in this case. */
+ if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0)
+ {
+ if (tag != NULL)
+ {
+ free (tag);
+ tag = NULL;
+ }
+ if (date != NULL)
+ {
+ free (date);
+ date = NULL;
+ }
+ nonbranch = -1;
+ warned = 0;
+ free (tag_update_dir);
+ tag_update_dir = NULL;
+ }
+
+ if (strchr (dir, '/') == NULL)
+ {
+ /* FIXME: chdir ("..") loses with symlinks. */
+ /* Prune empty dirs on the way out - if necessary */
+ (void) CVS_CHDIR ("..");
+ if (update_prune_dirs && isemptydir (dir, 0))
+ {
+ /* I'm not sure the existence_error is actually possible (except
+ in cases where we really should print a message), but since
+ this code used to ignore all errors, I'll play it safe. */
+ if (unlink_file_dir (dir) < 0 && !existence_error (errno))
+ error (0, errno, "cannot remove %s directory", dir);
+ Subdir_Deregister (entries, NULL, dir);
+ }
+ }
+
+ return err;
+}
+
+
+
+/* Returns 1 if the file indicated by node has been removed. */
+static int
+isremoved (Node *node, void *closure)
+{
+ Entnode *entdata = node->data;
+
+ /* If the first character of the version is a '-', the file has been
+ removed. */
+ return (entdata->version && entdata->version[0] == '-') ? 1 : 0;
+}
+
+
+
+/* Returns 1 if the argument directory is completely empty, other than the
+ existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST
+ and the directory doesn't exist, then just return 0. */
+int
+isemptydir (const char *dir, int might_not_exist)
+{
+ DIR *dirp;
+ struct dirent *dp;
+
+ if ((dirp = CVS_OPENDIR (dir)) == NULL)
+ {
+ if (might_not_exist && existence_error (errno))
+ return 0;
+ error (0, errno, "cannot open directory %s for empty check", dir);
+ return 0;
+ }
+ errno = 0;
+ while ((dp = CVS_READDIR (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") != 0
+ && strcmp (dp->d_name, "..") != 0)
+ {
+ if (strcmp (dp->d_name, CVSADM) != 0)
+ {
+ /* An entry other than the CVS directory. The directory
+ is certainly not empty. */
+ (void) CVS_CLOSEDIR (dirp);
+ return 0;
+ }
+ else
+ {
+ /* The CVS directory entry. We don't have to worry about
+ this unless the Entries file indicates that files have
+ been removed, but not committed, in this directory.
+ (Removing the directory would prevent people from
+ comitting the fact that they removed the files!) */
+ List *l;
+ int files_removed;
+ struct saved_cwd cwd;
+
+ if (save_cwd (&cwd))
+ error (1, errno, "Failed to save current directory.");
+
+ if (CVS_CHDIR (dir) < 0)
+ error (1, errno, "cannot change directory to %s", dir);
+ l = Entries_Open (0, NULL);
+ files_removed = walklist (l, isremoved, 0);
+ Entries_Close (l);
+
+ if (restore_cwd (&cwd))
+ error (1, errno,
+ "Failed to restore current directory, `%s'.",
+ cwd.name);
+ free_cwd (&cwd);
+
+ if (files_removed != 0)
+ {
+ /* There are files that have been removed, but not
+ committed! Do not consider the directory empty. */
+ (void) CVS_CLOSEDIR (dirp);
+ return 0;
+ }
+ }
+ }
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ error (0, errno, "cannot read directory %s", dir);
+ (void) CVS_CLOSEDIR (dirp);
+ return 0;
+ }
+ (void) CVS_CLOSEDIR (dirp);
+ return 1;
+}
+
+
+
+/*
+ * scratch the Entries file entry associated with a file
+ */
+static int
+scratch_file (struct file_info *finfo, Vers_TS *vers)
+{
+ history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository);
+ Scratch_Entry (finfo->entries, finfo->file);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ if (vers->ts_user == NULL)
+ server_scratch_entry_only ();
+ server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1, NULL, NULL);
+ }
+#endif
+ if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
+ error (0, errno, "unable to remove %s", finfo->fullname);
+ else if (!server_active)
+ {
+ /* skip this step when the server is running since
+ * server_updated should have handled it */
+ /* keep the vers structure up to date in case we do a join
+ * - if there isn't a file, it can't very well have a version number, can it?
+ */
+ if (vers->vn_user != NULL)
+ {
+ free (vers->vn_user);
+ vers->vn_user = NULL;
+ }
+ if (vers->ts_user != NULL)
+ {
+ free (vers->ts_user);
+ vers->ts_user = NULL;
+ }
+ }
+ return 0;
+}
+
+
+
+/*
+ * Check out a file.
+ */
+static int
+checkout_file (struct file_info *finfo, Vers_TS *vers_ts, int adding,
+ int merging, int update_server)
+{
+ char *backup;
+ int set_time, retval = 0;
+ int status;
+ int file_is_dead;
+ struct buffer *revbuf;
+
+ backup = NULL;
+ revbuf = NULL;
+
+ /* Don't screw with backup files if we're going to stdout, or if
+ we are the server. */
+ if (!pipeout && !server_active)
+ {
+ backup = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
+ if (isfile (finfo->file))
+ rename_file (finfo->file, backup);
+ else
+ {
+ /* If -f/-t wrappers are being used to wrap up a directory,
+ then backup might be a directory instead of just a file. */
+ if (unlink_file_dir (backup) < 0)
+ {
+ /* Not sure if the existence_error check is needed here. */
+ if (!existence_error (errno))
+ /* FIXME: should include update_dir in message. */
+ error (0, errno, "error removing %s", backup);
+ }
+ free (backup);
+ backup = NULL;
+ }
+ }
+
+ file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
+
+ if (!file_is_dead)
+ {
+ /*
+ * if we are checking out to stdout, print a nice message to
+ * stderr, and add the -p flag to the command */
+ if (pipeout)
+ {
+ if (!quiet)
+ {
+ cvs_outerr ("\
+===================================================================\n\
+Checking out ", 0);
+ cvs_outerr (finfo->fullname, 0);
+ cvs_outerr ("\n\
+RCS: ", 0);
+ cvs_outerr (vers_ts->srcfile->print_path, 0);
+ cvs_outerr ("\n\
+VERS: ", 0);
+ cvs_outerr (vers_ts->vn_rcs, 0);
+ cvs_outerr ("\n***************\n", 0);
+ }
+ }
+
+#ifdef SERVER_SUPPORT
+ if (update_server
+ && server_active
+ && ! pipeout
+ && ! file_gzip_level
+ && ! joining ()
+ && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
+ {
+ revbuf = buf_nonio_initialize (NULL);
+ status = RCS_checkout (vers_ts->srcfile, NULL,
+ vers_ts->vn_rcs, vers_ts->tag,
+ vers_ts->options, RUN_TTY,
+ checkout_to_buffer, revbuf);
+ }
+ else
+#endif
+ status = RCS_checkout (vers_ts->srcfile,
+ pipeout ? NULL : finfo->file,
+ vers_ts->vn_rcs, vers_ts->tag,
+ vers_ts->options, RUN_TTY, NULL, NULL);
+ }
+ if (file_is_dead || status == 0)
+ {
+ mode_t mode;
+
+ mode = (mode_t) -1;
+
+ if (!pipeout)
+ {
+ Vers_TS *xvers_ts;
+
+ if (revbuf != NULL && !noexec)
+ {
+ struct stat sb;
+
+ /* FIXME: We should have RCS_checkout return the mode.
+ That would also fix the kludge with noexec, above, which
+ is here only because noexec doesn't write srcfile->path
+ for us to stat. */
+ if (stat (vers_ts->srcfile->path, &sb) < 0)
+ {
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+ buf_free (revbuf);
+#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
+ error (1, errno, "cannot stat %s",
+ vers_ts->srcfile->path);
+ }
+ mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
+ }
+
+ if (cvswrite
+ && !file_is_dead
+ && !fileattr_get (finfo->file, "_watched"))
+ {
+ if (revbuf == NULL)
+ xchmod (finfo->file, 1);
+ else
+ {
+ /* We know that we are the server here, so
+ although xchmod checks umask, we don't bother. */
+ mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
+ | ((mode & S_IRGRP) ? S_IWGRP : 0)
+ | ((mode & S_IROTH) ? S_IWOTH : 0));
+ }
+ }
+
+ {
+ /* A newly checked out file is never under the spell
+ of "cvs edit". If we think we were editing it
+ from a previous life, clean up. Would be better to
+ check for same the working directory instead of
+ same user, but that is hairy. */
+
+ struct addremove_args args;
+
+ editor_set (finfo->file, getcaller (), NULL);
+
+ memset (&args, 0, sizeof args);
+ args.remove_temp = 1;
+ watch_modify_watchers (finfo->file, &args);
+ }
+
+ /* set the time from the RCS file iff it was unknown before */
+ set_time =
+ (!noexec
+ && (vers_ts->vn_user == NULL ||
+ strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
+ && !file_is_dead);
+
+ wrap_fromcvs_process_file (finfo->file);
+
+ xvers_ts = Version_TS (finfo, options, tag, date,
+ force_tag_match, set_time);
+ if (strcmp (xvers_ts->options, "-V4") == 0)
+ xvers_ts->options[0] = '\0';
+
+ if (revbuf != NULL)
+ {
+ /* If we stored the file data into a buffer, then we
+ didn't create a file at all, so xvers_ts->ts_user
+ is wrong. The correct value is to have it be the
+ same as xvers_ts->ts_rcs, meaning that the working
+ file is unchanged from the RCS file.
+
+ FIXME: We should tell Version_TS not to waste time
+ statting the nonexistent file.
+
+ FIXME: Actually, I don't think the ts_user value
+ matters at all here. The only use I know of is
+ that it is printed in a trace message by
+ Server_Register. */
+
+ if (xvers_ts->ts_user != NULL)
+ free (xvers_ts->ts_user);
+ xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
+ }
+
+ (void) time (&last_register_time);
+
+ if (file_is_dead)
+ {
+ if (xvers_ts->vn_user != NULL)
+ {
+ error (0, 0,
+ "warning: %s is not (any longer) pertinent",
+ finfo->fullname);
+ }
+ Scratch_Entry (finfo->entries, finfo->file);
+#ifdef SERVER_SUPPORT
+ if (server_active && xvers_ts->ts_user == NULL)
+ server_scratch_entry_only ();
+#endif
+ /* FIXME: Rather than always unlink'ing, and ignoring the
+ existence_error, we should do the unlink only if
+ vers_ts->ts_user is non-NULL. Then there would be no
+ need to ignore an existence_error (for example, if the
+ user removes the file while we are running). */
+ if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
+ {
+ error (0, errno, "cannot remove %s", finfo->fullname);
+ }
+ }
+ else
+ Register (finfo->entries, finfo->file,
+ adding ? "0" : xvers_ts->vn_rcs,
+ xvers_ts->ts_user, xvers_ts->options,
+ xvers_ts->tag, xvers_ts->date,
+ NULL); /* Clear conflict flag on fresh checkout */
+
+ /* fix up the vers structure, in case it is used by join */
+ if (join_rev1)
+ {
+ /* FIXME: Throwing away the original revision info is almost
+ certainly wrong -- what if join_rev1 is "BASE"? */
+ if (vers_ts->vn_user != NULL)
+ free (vers_ts->vn_user);
+ if (vers_ts->vn_rcs != NULL)
+ free (vers_ts->vn_rcs);
+ vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
+ vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
+ }
+
+ /* If this is really Update and not Checkout, recode history */
+ if (strcmp (cvs_cmd_name, "update") == 0)
+ history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
+ finfo->repository);
+
+ freevers_ts (&xvers_ts);
+
+ if (!really_quiet && !file_is_dead)
+ {
+ write_letter (finfo, 'U');
+ }
+ }
+
+#ifdef SERVER_SUPPORT
+ if (update_server && server_active)
+ server_updated (finfo, vers_ts,
+ merging ? SERVER_MERGED : SERVER_UPDATED,
+ mode, NULL, revbuf);
+#endif
+ }
+ else
+ {
+ if (backup != NULL)
+ {
+ rename_file (backup, finfo->file);
+ free (backup);
+ backup = NULL;
+ }
+
+ error (0, 0, "could not check out %s", finfo->fullname);
+
+ retval = status;
+ }
+
+ if (backup != NULL)
+ {
+ /* If -f/-t wrappers are being used to wrap up a directory,
+ then backup might be a directory instead of just a file. */
+ if (unlink_file_dir (backup) < 0)
+ {
+ /* Not sure if the existence_error check is needed here. */
+ if (!existence_error (errno))
+ /* FIXME: should include update_dir in message. */
+ error (0, errno, "error removing %s", backup);
+ }
+ free (backup);
+ }
+
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+ if (revbuf != NULL)
+ buf_free (revbuf);
+#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
+ return retval;
+}
+
+
+
+#ifdef SERVER_SUPPORT
+
+/* This function is used to write data from a file being checked out
+ into a buffer. */
+
+static void
+checkout_to_buffer (void *callerdat, const char *data, size_t len)
+{
+ struct buffer *buf = (struct buffer *) callerdat;
+
+ buf_output (buf, data, len);
+}
+
+#endif /* SERVER_SUPPORT */
+
+#ifdef SERVER_SUPPORT
+
+/* This structure is used to pass information between patch_file and
+ patch_file_write. */
+
+struct patch_file_data
+{
+ /* File name, for error messages. */
+ const char *filename;
+ /* File to which to write. */
+ FILE *fp;
+ /* Whether to compute the MD5 checksum. */
+ int compute_checksum;
+ /* Data structure for computing the MD5 checksum. */
+ struct md5_ctx context;
+ /* Set if the file has a final newline. */
+ int final_nl;
+};
+
+/* Patch a file. Runs diff. This is only done when running as the
+ * server. The hope is that the diff will be smaller than the file
+ * itself.
+ */
+static int
+patch_file (struct file_info *finfo, Vers_TS *vers_ts, int *docheckout,
+ struct stat *file_info, unsigned char *checksum)
+{
+ char *backup;
+ char *file1;
+ char *file2;
+ int retval = 0;
+ int retcode = 0;
+ int fail;
+ FILE *e;
+ struct patch_file_data data;
+
+ *docheckout = 0;
+
+ if (noexec || pipeout || joining ())
+ {
+ *docheckout = 1;
+ return 0;
+ }
+
+ /* If this file has been marked as being binary, then never send a
+ patch. */
+ if (strcmp (vers_ts->options, "-kb") == 0)
+ {
+ *docheckout = 1;
+ return 0;
+ }
+
+ /* First check that the first revision exists. If it has been nuked
+ by cvs admin -o, then just fall back to checking out entire
+ revisions. In some sense maybe we don't have to do this; after
+ all cvs.texinfo says "Make sure that no-one has checked out a
+ copy of the revision you outdate" but then again, that advice
+ doesn't really make complete sense, because "cvs admin" operates
+ on a working directory and so _someone_ will almost always have
+ _some_ revision checked out. */
+ {
+ char *rev;
+
+ rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL);
+ if (rev == NULL)
+ {
+ *docheckout = 1;
+ return 0;
+ }
+ else
+ free (rev);
+ }
+
+ /* If the revision is dead, let checkout_file handle it rather
+ than duplicating the processing here. */
+ if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs))
+ {
+ *docheckout = 1;
+ return 0;
+ }
+
+ backup = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
+ if (isfile (finfo->file))
+ rename_file (finfo->file, backup);
+ else
+ {
+ if (unlink_file (backup) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", backup);
+ }
+
+ file1 = Xasprintf ("%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
+ file2 = Xasprintf ("%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
+
+ fail = 0;
+
+ /* We need to check out both revisions first, to see if either one
+ has a trailing newline. Because of this, we don't use rcsdiff,
+ but just use diff. */
+
+ e = CVS_FOPEN (file1, "w");
+ if (e == NULL)
+ error (1, errno, "cannot open %s", file1);
+
+ data.filename = file1;
+ data.fp = e;
+ data.final_nl = 0;
+ data.compute_checksum = 0;
+
+ /* FIXME - Passing vers_ts->tag here is wrong in the least number
+ * of cases. Since we don't know whether vn_user was checked out
+ * using a tag, we pass vers_ts->tag, which, assuming the user did
+ * not specify a new TAG to -r, will be the branch we are on.
+ *
+ * The only thing it is used for is to substitute in for the Name
+ * RCS keyword, so in the error case, the patch fails to apply on
+ * the client end and we end up resending the whole file.
+ *
+ * At least, if we are keeping track of the tag vn_user came from,
+ * I don't know where yet. -DRP
+ */
+ retcode = RCS_checkout (vers_ts->srcfile, NULL,
+ vers_ts->vn_user, vers_ts->tag,
+ vers_ts->options, RUN_TTY,
+ patch_file_write, (void *) &data);
+
+ if (fclose (e) < 0)
+ error (1, errno, "cannot close %s", file1);
+
+ if (retcode != 0 || ! data.final_nl)
+ fail = 1;
+
+ if (! fail)
+ {
+ e = CVS_FOPEN (file2, "w");
+ if (e == NULL)
+ error (1, errno, "cannot open %s", file2);
+
+ data.filename = file2;
+ data.fp = e;
+ data.final_nl = 0;
+ data.compute_checksum = 1;
+ md5_init_ctx (&data.context);
+
+ retcode = RCS_checkout (vers_ts->srcfile, NULL,
+ vers_ts->vn_rcs, vers_ts->tag,
+ vers_ts->options, RUN_TTY,
+ patch_file_write, (void *) &data);
+
+ if (fclose (e) < 0)
+ error (1, errno, "cannot close %s", file2);
+
+ if (retcode != 0 || ! data.final_nl)
+ fail = 1;
+ else
+ md5_finish_ctx (&data.context, checksum);
+ }
+
+ retcode = 0;
+ if (! fail)
+ {
+ int dargc = 0;
+ size_t darg_allocated = 0;
+ char **dargv = NULL;
+
+ /* If the client does not support the Rcs-diff command, we
+ send a context diff, and the client must invoke patch.
+ That approach was problematical for various reasons. The
+ new approach only requires running diff in the server; the
+ client can handle everything without invoking an external
+ program. */
+ if (!rcs_diff_patches)
+ /* We use -c, not -u, because that is what CVS has
+ traditionally used. Kind of a moot point, now that
+ Rcs-diff is preferred, so there is no point in making
+ the compatibility issues worse. */
+ run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c");
+ else
+ /* Now that diff is librarified, we could be passing -a if
+ we wanted to. However, it is unclear to me whether we
+ would want to. Does diff -a, in any significant
+ percentage of cases, produce patches which are smaller
+ than the files it is patching? I guess maybe text
+ files with character sets which diff regards as
+ 'binary'. Conversely, do they tend to be much larger
+ in the bad cases? This needs some more
+ thought/investigation, I suspect. */
+ run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
+ retcode = diff_exec (file1, file2, NULL, NULL, dargc, dargv,
+ finfo->file);
+ run_arg_free_p (dargc, dargv);
+ free (dargv);
+
+ /* A retcode of 0 means no differences. 1 means some differences. */
+ if (retcode != 0 && retcode != 1)
+ fail = 1;
+ }
+
+ if (!fail)
+ {
+ struct stat file2_info;
+
+ /* Check to make sure the patch is really shorter */
+ if (stat (file2, &file2_info) < 0)
+ error (1, errno, "could not stat %s", file2);
+ if (stat (finfo->file, file_info) < 0)
+ error (1, errno, "could not stat %s", finfo->file);
+ if (file2_info.st_size <= file_info->st_size)
+ fail = 1;
+ }
+
+ if (! fail)
+ {
+# define BINARY "Binary"
+ char buf[sizeof BINARY];
+ unsigned int c;
+
+ /* Check the diff output to make sure patch will be handle it. */
+ e = CVS_FOPEN (finfo->file, "r");
+ if (e == NULL)
+ error (1, errno, "could not open diff output file %s",
+ finfo->fullname);
+ c = fread (buf, 1, sizeof BINARY - 1, e);
+ buf[c] = '\0';
+ if (strcmp (buf, BINARY) == 0)
+ {
+ /* These are binary files. We could use diff -a, but
+ patch can't handle that. */
+ fail = 1;
+ }
+ fclose (e);
+ }
+
+ if (! fail)
+ {
+ Vers_TS *xvers_ts;
+
+ /* Stat the original RCS file, and then adjust it the way
+ that RCS_checkout would. FIXME: This is an abstraction
+ violation. */
+ if (stat (vers_ts->srcfile->path, file_info) < 0)
+ error (1, errno, "could not stat %s", vers_ts->srcfile->path);
+ if (chmod (finfo->file,
+ file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH))
+ < 0)
+ error (0, errno, "cannot change mode of file %s", finfo->file);
+ if (cvswrite
+ && !fileattr_get (finfo->file, "_watched"))
+ xchmod (finfo->file, 1);
+
+ /* This stuff is just copied blindly from checkout_file. I
+ don't really know what it does. */
+ xvers_ts = Version_TS (finfo, options, tag, date,
+ force_tag_match, 0);
+ if (strcmp (xvers_ts->options, "-V4") == 0)
+ xvers_ts->options[0] = '\0';
+
+ Register (finfo->entries, finfo->file, xvers_ts->vn_rcs,
+ xvers_ts->ts_user, xvers_ts->options,
+ xvers_ts->tag, xvers_ts->date, NULL);
+
+ if (stat (finfo->file, file_info) < 0)
+ error (1, errno, "could not stat %s", finfo->file);
+
+ /* If this is really Update and not Checkout, record history. */
+ if (strcmp (cvs_cmd_name, "update") == 0)
+ history_write ('P', finfo->update_dir, xvers_ts->vn_rcs,
+ finfo->file, finfo->repository);
+
+ freevers_ts (&xvers_ts);
+
+ if (!really_quiet)
+ {
+ write_letter (finfo, 'P');
+ }
+ }
+ else
+ {
+ int old_errno = errno; /* save errno value over the rename */
+
+ if (isfile (backup))
+ rename_file (backup, finfo->file);
+
+ if (retcode != 0 && retcode != 1)
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
+ "could not diff %s", finfo->fullname);
+
+ *docheckout = 1;
+ retval = retcode;
+ }
+
+ if (unlink_file (backup) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", backup);
+ if (unlink_file (file1) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", file1);
+ if (unlink_file (file2) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", file2);
+
+ free (backup);
+ free (file1);
+ free (file2);
+ return retval;
+}
+
+
+
+/* Write data to a file. Record whether the last byte written was a
+ newline. Optionally compute a checksum. This is called by
+ patch_file via RCS_checkout. */
+
+static void
+patch_file_write (void *callerdat, const char *buffer, size_t len)
+{
+ struct patch_file_data *data = (struct patch_file_data *) callerdat;
+
+ if (fwrite (buffer, 1, len, data->fp) != len)
+ error (1, errno, "cannot write %s", data->filename);
+
+ data->final_nl = (buffer[len - 1] == '\n');
+
+ if (data->compute_checksum)
+ md5_process_bytes (buffer, len, &data->context);
+}
+
+#endif /* SERVER_SUPPORT */
+
+/*
+ * Several of the types we process only print a bit of information consisting
+ * of a single letter and the name.
+ */
+void
+write_letter (struct file_info *finfo, int letter)
+{
+ if (!really_quiet)
+ {
+ char *tag = NULL;
+ /* Big enough for "+updated" or any of its ilk. */
+ char buf[80];
+
+ switch (letter)
+ {
+ case 'U':
+ tag = "updated";
+ break;
+ default:
+ /* We don't yet support tagged output except for "U". */
+ break;
+ }
+
+ if (tag != NULL)
+ {
+ sprintf (buf, "+%s", tag);
+ cvs_output_tagged (buf, NULL);
+ }
+ buf[0] = letter;
+ buf[1] = ' ';
+ buf[2] = '\0';
+ cvs_output_tagged ("text", buf);
+ cvs_output_tagged ("fname", finfo->fullname);
+ cvs_output_tagged ("newline", NULL);
+ if (tag != NULL)
+ {
+ sprintf (buf, "-%s", tag);
+ cvs_output_tagged (buf, NULL);
+ }
+ }
+ return;
+}
+
+
+
+/* Reregister a file after a merge. */
+static void
+RegisterMerge (struct file_info *finfo, Vers_TS *vers,
+ const char *backup, int has_conflicts)
+{
+ /* This file is the result of a merge, which means that it has
+ been modified. We use a special timestamp string which will
+ not compare equal to any actual timestamp. */
+ char *cp = NULL;
+
+ if (has_conflicts)
+ {
+ time (&last_register_time);
+ cp = time_stamp (finfo->file);
+ }
+ Register (finfo->entries, finfo->file, vers->vn_rcs ? vers->vn_rcs : "0",
+ "Result of merge", vers->options, vers->tag, vers->date, cp);
+ if (cp)
+ free (cp);
+
+#ifdef SERVER_SUPPORT
+ /* Send the new contents of the file before the message. If we
+ wanted to be totally correct, we would have the client write
+ the message only after the file has safely been written. */
+ if (server_active)
+ {
+ server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
+ backup);
+ server_updated (finfo, vers, SERVER_MERGED, (mode_t) -1, NULL, NULL);
+ }
+#endif
+}
+
+
+
+/*
+ * Do all the magic associated with a file which needs to be merged
+ */
+static int
+merge_file (struct file_info *finfo, Vers_TS *vers)
+{
+ char *backup;
+ int status;
+ int retval;
+
+ assert (vers->vn_user);
+
+ /*
+ * The users currently modified file is moved to a backup file name
+ * ".#filename.version", so that it will stay around for a few days
+ * before being automatically removed by some cron daemon. The "version"
+ * is the version of the file that the user was most up-to-date with
+ * before the merge.
+ */
+ backup = Xasprintf ("%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
+
+ if (unlink_file (backup) && !existence_error (errno))
+ error (0, errno, "unable to remove %s", backup);
+ copy_file (finfo->file, backup);
+ xchmod (finfo->file, 1);
+
+ if (strcmp (vers->options, "-kb") == 0
+ || wrap_merge_is_copy (finfo->file)
+ || special_file_mismatch (finfo, NULL, vers->vn_rcs))
+ {
+ /* For binary files, a merge is always a conflict. Same for
+ files whose permissions or linkage do not match. We give the
+ user the two files, and let them resolve it. It is possible
+ that we should require a "touch foo" or similar step before
+ we allow a checkin. */
+
+ /* TODO: it may not always be necessary to regard a permission
+ mismatch as a conflict. The working file and the RCS file
+ have a common ancestor `A'; if the working file's permissions
+ match A's, then it's probably safe to overwrite them with the
+ RCS permissions. Only if the working file, the RCS file, and
+ A all disagree should this be considered a conflict. But more
+ thought needs to go into this, and in the meantime it is safe
+ to treat any such mismatch as an automatic conflict. -twp */
+
+ status = RCS_checkout (finfo->rcs, finfo->file, vers->vn_rcs,
+ vers->tag, vers->options, NULL, NULL, NULL);
+ if (status)
+ {
+ error (0, 0, "failed to check out `%s' file", finfo->fullname);
+ error (0, 0, "restoring `%s' from backup file `%s'",
+ finfo->fullname, backup);
+ rename_file (backup, finfo->file);
+ retval = 1;
+ goto out;
+ }
+
+ xchmod (finfo->file, 1);
+
+ RegisterMerge (finfo, vers, backup, 1);
+
+ /* Is there a better term than "nonmergeable file"? What we
+ really mean is, not something that CVS cannot or does not
+ want to merge (there might be an external manual or
+ automatic merge process). */
+ error (0, 0, "nonmergeable file needs merge");
+ error (0, 0, "revision %s from repository is now in %s",
+ vers->vn_rcs, finfo->fullname);
+ error (0, 0, "file from working directory is now in %s", backup);
+ write_letter (finfo, 'C');
+
+ history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
+ finfo->repository);
+ retval = 0;
+ goto out;
+ }
+
+ status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
+ vers->options, vers->vn_user, vers->vn_rcs);
+ if (status != 0 && status != 1)
+ {
+ error (0, status == -1 ? errno : 0,
+ "could not merge revision %s of %s", vers->vn_user, finfo->fullname);
+ error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
+ finfo->fullname, backup);
+ rename_file (backup, finfo->file);
+ retval = 1;
+ goto out;
+ }
+
+ if (strcmp (vers->options, "-V4") == 0)
+ vers->options[0] = '\0';
+
+ /* fix up the vers structure, in case it is used by join */
+ if (join_rev1)
+ {
+ /* FIXME: Throwing away the original revision info is almost
+ certainly wrong -- what if join_rev1 is "BASE"? */
+ if (vers->vn_user != NULL)
+ free (vers->vn_user);
+ vers->vn_user = xstrdup (vers->vn_rcs);
+ }
+
+ RegisterMerge (finfo, vers, backup, status);
+
+ if (status == 1)
+ {
+ error (0, 0, "conflicts found in %s", finfo->fullname);
+
+ write_letter (finfo, 'C');
+
+ history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
+ finfo->repository);
+
+ }
+ else /* status == 0 */
+ {
+ history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
+ finfo->repository);
+
+ /* FIXME: the noexec case is broken. RCS_merge could be doing the
+ xcmp on the temporary files without much hassle, I think. */
+ if (!noexec && !xcmp (backup, finfo->file))
+ {
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" already contains the differences between ", 0);
+ cvs_output (vers->vn_user, 0);
+ cvs_output (" and ", 0);
+ cvs_output (vers->vn_rcs, 0);
+ cvs_output ("\n", 1);
+
+ retval = 0;
+ goto out;
+ }
+
+ write_letter (finfo, 'M');
+ }
+ retval = 0;
+ out:
+ free (backup);
+ return retval;
+}
+
+
+
+/*
+ * Do all the magic associated with a file which needs to be joined
+ * (reached via the -j option to checkout or update).
+ *
+ * INPUTS
+ * finfo File information about the destination file.
+ * vers The Vers_TS structure for finfo.
+ *
+ * GLOBALS
+ * join_rev1 From the command line.
+ * join_rev2 From the command line.
+ * server_active Natch.
+ *
+ * ASSUMPTIONS
+ * 1. Is not called in client mode.
+ */
+static void
+join_file (struct file_info *finfo, Vers_TS *vers)
+{
+ char *backup;
+ char *t_options;
+ int status;
+
+ char *rev1;
+ char *rev2;
+ char *jrev1;
+ char *jrev2;
+ char *jdate1;
+ char *jdate2;
+
+ TRACE (TRACE_FUNCTION, "join_file(%s, %s%s%s%s, %s, %s)",
+ finfo->file,
+ vers->tag ? vers->tag : "",
+ vers->tag ? " (" : "",
+ vers->vn_rcs ? vers->vn_rcs : "",
+ vers->tag ? ")" : "",
+ join_rev1 ? join_rev1 : "",
+ join_rev2 ? join_rev2 : "");
+
+ jrev1 = join_rev1;
+ jrev2 = join_rev2;
+ jdate1 = join_date1;
+ jdate2 = join_date2;
+
+ /* Determine if we need to do anything at all. */
+ if (vers->srcfile == NULL ||
+ vers->srcfile->path == NULL)
+ {
+ return;
+ }
+
+ /* If only one join revision is specified, it becomes the second
+ revision. */
+ if (jrev2 == NULL)
+ {
+ jrev2 = jrev1;
+ jrev1 = NULL;
+ jdate2 = jdate1;
+ jdate1 = NULL;
+ }
+
+ /* FIXME: Need to handle "BASE" for jrev1 and/or jrev2. Note caveat
+ below about vn_user. */
+
+ /* Convert the second revision, walking branches and dates. */
+ rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, NULL);
+
+ /* If this is a merge of two revisions, get the first revision.
+ If only one join tag was specified, then the first revision is
+ the greatest common ancestor of the second revision and the
+ working file. */
+ if (jrev1 != NULL)
+ rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, NULL);
+ else
+ {
+ /* Note that we use vn_rcs here, since vn_user may contain a
+ special string such as "-nn". */
+ if (vers->vn_rcs == NULL)
+ rev1 = NULL;
+ else if (rev2 == NULL)
+ {
+ /* This means that the file never existed on the branch.
+ It does not mean that the file was removed on the
+ branch: that case is represented by a dead rev2. If
+ the file never existed on the branch, then we have
+ nothing to merge, so we just return. */
+ return;
+ }
+ else
+ rev1 = gca (vers->vn_rcs, rev2);
+ }
+
+ /* Handle a nonexistent or dead merge target. */
+ if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2))
+ {
+ char *mrev;
+
+ if (rev2 != NULL)
+ free (rev2);
+
+ /* If the first revision doesn't exist either, then there is
+ no change between the two revisions, so we don't do
+ anything. */
+ if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
+ {
+ if (rev1 != NULL)
+ free (rev1);
+ return;
+ }
+
+ /* If we are merging two revisions, then the file was removed
+ between the first revision and the second one. In this
+ case we want to mark the file for removal.
+
+ If we are merging one revision, then the file has been
+ removed between the greatest common ancestor and the merge
+ revision. From the perspective of the branch on to which
+ we ar emerging, which may be the trunk, either 1) the file
+ does not currently exist on the target, or 2) the file has
+ not been modified on the target branch since the greatest
+ common ancestor, or 3) the file has been modified on the
+ target branch since the greatest common ancestor. In case
+ 1 there is nothing to do. In case 2 we mark the file for
+ removal. In case 3 we have a conflict.
+
+ Note that the handling is slightly different depending upon
+ whether one or two join targets were specified. If two
+ join targets were specified, we don't check whether the
+ file was modified since a given point. My reasoning is
+ that if you ask for an explicit merge between two tags,
+ then you want to merge in whatever was changed between
+ those two tags. If a file was removed between the two
+ tags, then you want it to be removed. However, if you ask
+ for a merge of a branch, then you want to merge in all
+ changes which were made on the branch. If a file was
+ removed on the branch, that is a change to the file. If
+ the file was also changed on the main line, then that is
+ also a change. These two changes--the file removal and the
+ modification--must be merged. This is a conflict. */
+
+ /* If the user file is dead, or does not exist, or has been
+ marked for removal, then there is nothing to do. */
+ if (vers->vn_user == NULL
+ || vers->vn_user[0] == '-'
+ || RCS_isdead (vers->srcfile, vers->vn_user))
+ {
+ if (rev1 != NULL)
+ free (rev1);
+ return;
+ }
+
+ /* If the user file has been marked for addition, or has been
+ locally modified, then we have a conflict which we can not
+ resolve. No_Difference will already have been called in
+ this case, so comparing the timestamps is sufficient to
+ determine whether the file is locally modified. */
+ if (strcmp (vers->vn_user, "0") == 0
+ || (vers->ts_user != NULL
+ && strcmp (vers->ts_user, vers->ts_rcs) != 0))
+ {
+ if (jdate2 != NULL)
+ error (0, 0,
+ "file %s is locally modified, but has been removed in revision %s as of %s",
+ finfo->fullname, jrev2, jdate2);
+ else
+ error (0, 0,
+ "file %s is locally modified, but has been removed in revision %s",
+ finfo->fullname, jrev2);
+
+ /* FIXME: Should we arrange to return a non-zero exit
+ status? */
+
+ if (rev1 != NULL)
+ free (rev1);
+
+ return;
+ }
+
+ /* If only one join tag was specified, and the user file has
+ been changed since the greatest common ancestor (rev1),
+ then there is a conflict we can not resolve. See above for
+ the rationale. */
+ if (join_rev2 == NULL
+ && strcmp (rev1, vers->vn_user) != 0)
+ {
+ if (jdate2 != NULL)
+ error (0, 0,
+ "file %s has been modified, but has been removed in revision %s as of %s",
+ finfo->fullname, jrev2, jdate2);
+ else
+ error (0, 0,
+ "file %s has been modified, but has been removed in revision %s",
+ finfo->fullname, jrev2);
+
+ /* FIXME: Should we arrange to return a non-zero exit
+ status? */
+
+ if (rev1 != NULL)
+ free (rev1);
+
+ return;
+ }
+
+ if (rev1 != NULL)
+ free (rev1);
+
+ /* The user file exists and has not been modified. Mark it
+ for removal. FIXME: If we are doing a checkout, this has
+ the effect of first checking out the file, and then
+ removing it. It would be better to just register the
+ removal.
+
+ The same goes for a removal then an add. e.g.
+ cvs up -rbr -jbr2 could remove and readd the same file
+ */
+ /* save the rev since server_updated might invalidate it */
+ mrev = Xasprintf ("-%s", vers->vn_user);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ server_scratch (finfo->file);
+ server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
+ NULL, NULL);
+ }
+#endif
+ Register (finfo->entries, finfo->file, mrev, vers->ts_rcs,
+ vers->options, vers->tag, vers->date, vers->ts_conflict);
+ free (mrev);
+ /* We need to check existence_error here because if we are
+ running as the server, and the file is up to date in the
+ working directory, the client will not have sent us a copy. */
+ if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
+ error (0, errno, "cannot remove file %s", finfo->fullname);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_checked_in (finfo->file, finfo->update_dir,
+ finfo->repository);
+#endif
+ if (! really_quiet)
+ error (0, 0, "scheduling `%s' for removal", finfo->fullname);
+
+ return;
+ }
+
+ /* If the two merge revisions are the same, then there is nothing
+ * to do. This needs to be checked before the rev2 == up-to-date base
+ * revision check tha comes next. Otherwise, rev1 can == rev2 and get an
+ * "already contains the changes between <rev1> and <rev1>" message.
+ */
+ if (rev1 && strcmp (rev1, rev2) == 0)
+ {
+ free (rev1);
+ free (rev2);
+ return;
+ }
+
+ /* If we know that the user file is up-to-date, then it becomes an
+ * optimization to skip the merge when rev2 is the same as the base
+ * revision. i.e. we know that diff3(file2,file1,file2) will produce
+ * file2.
+ */
+ if (vers->vn_user != NULL && vers->ts_user != NULL
+ && strcmp (vers->ts_user, vers->ts_rcs) == 0
+ && strcmp (rev2, vers->vn_user) == 0)
+ {
+ if (!really_quiet)
+ {
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" already contains the differences between ", 0);
+ cvs_output (rev1 ? rev1 : "creation", 0);
+ cvs_output (" and ", 0);
+ cvs_output (rev2, 0);
+ cvs_output ("\n", 1);
+ }
+
+ if (rev1 != NULL)
+ free (rev1);
+ free (rev2);
+
+ return;
+ }
+
+ /* If rev1 is dead or does not exist, then the file was added
+ between rev1 and rev2. */
+ if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
+ {
+ if (rev1 != NULL)
+ free (rev1);
+ free (rev2);
+
+ /* If the file does not exist in the working directory, then
+ we can just check out the new revision and mark it for
+ addition. */
+ if (vers->vn_user == NULL)
+ {
+ char *saved_options = options;
+ Vers_TS *xvers;
+
+ xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
+
+ /* Reset any keyword expansion option. Otherwise, when a
+ command like `cvs update -kk -jT1 -jT2' creates a new file
+ (because a file had the T2 tag, but not T1), the subsequent
+ commit of that just-added file effectively would set the
+ admin `-kk' option for that file in the repository. */
+ options = NULL;
+
+ /* FIXME: If checkout_file fails, we should arrange to
+ return a non-zero exit status. */
+ status = checkout_file (finfo, xvers, 1, 0, 1);
+ options = saved_options;
+
+ freevers_ts (&xvers);
+
+ return;
+ }
+
+ /* The file currently exists in the working directory, so we
+ have a conflict which we can not resolve. Note that this
+ is true even if the file is marked for addition or removal. */
+
+ if (jdate2 != NULL)
+ error (0, 0,
+ "file %s exists, but has been added in revision %s as of %s",
+ finfo->fullname, jrev2, jdate2);
+ else
+ error (0, 0,
+ "file %s exists, but has been added in revision %s",
+ finfo->fullname, jrev2);
+
+ return;
+ }
+
+ /* If there is no working file, then we can't do the merge. */
+ if (vers->vn_user == NULL || vers->vn_user[0] == '-')
+ {
+ free (rev1);
+ free (rev2);
+
+ if (jdate2 != NULL)
+ error (0, 0,
+ "file %s does not exist, but is present in revision %s as of %s",
+ finfo->fullname, jrev2, jdate2);
+ else
+ error (0, 0,
+ "file %s does not exist, but is present in revision %s",
+ finfo->fullname, jrev2);
+
+ /* FIXME: Should we arrange to return a non-zero exit status? */
+
+ return;
+ }
+
+#ifdef SERVER_SUPPORT
+ if (server_active && !isreadable (finfo->file))
+ {
+ int retcode;
+ /* The file is up to date. Need to check out the current contents. */
+ /* FIXME - see the FIXME comment above the call to RCS_checkout in the
+ * patch_file function.
+ */
+ retcode = RCS_checkout (vers->srcfile, finfo->file,
+ vers->vn_user, vers->tag,
+ NULL, RUN_TTY, NULL, NULL);
+ if (retcode != 0)
+ error (1, 0,
+ "failed to check out %s file", finfo->fullname);
+ }
+#endif
+
+ /*
+ * The users currently modified file is moved to a backup file name
+ * ".#filename.version", so that it will stay around for a few days
+ * before being automatically removed by some cron daemon. The "version"
+ * is the version of the file that the user was most up-to-date with
+ * before the merge.
+ */
+ backup = Xasprintf ("%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
+
+ if (unlink_file (backup) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", backup);
+ copy_file (finfo->file, backup);
+ xchmod (finfo->file, 1);
+
+ t_options = vers->options;
+#if 0
+ if (*t_options == '\0')
+ t_options = "-kk"; /* to ignore keyword expansions */
+#endif
+
+ /* If the source of the merge is the same as the working file
+ revision, then we can just RCS_checkout the target (no merging
+ as such). In the text file case, this is probably quite
+ similar to the RCS_merge, but in the binary file case,
+ RCS_merge gives all kinds of trouble. */
+ if (vers->vn_user != NULL
+ && strcmp (rev1, vers->vn_user) == 0
+ /* See comments above about how No_Difference has already been
+ called. */
+ && vers->ts_user != NULL
+ && strcmp (vers->ts_user, vers->ts_rcs) == 0
+
+ /* Avoid this in the text file case. See below for why.
+ */
+ && (strcmp (t_options, "-kb") == 0
+ || wrap_merge_is_copy (finfo->file)))
+ {
+ /* FIXME: Verify my comment below:
+ *
+ * RCS_merge does nothing with keywords. It merges the changes between
+ * two revisions without expanding the keywords (it might expand in
+ * -kk mode before computing the diff between rev1 and rev2 - I'm not
+ * sure). In other words, the keyword lines in the current work file
+ * get left alone.
+ *
+ * Therfore, checking out the destination revision (rev2) is probably
+ * incorrect in the text case since we should see the keywords that were
+ * substituted into the original file at the time it was checked out
+ * and not the keywords from rev2.
+ *
+ * Also, it is safe to pass in NULL for nametag since we know no
+ * substitution is happening during the binary mode checkout.
+ */
+ if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options,
+ RUN_TTY, NULL, NULL) != 0)
+ status = 2;
+ else
+ status = 0;
+
+ /* OK, this is really stupid. RCS_checkout carefully removes
+ write permissions, and we carefully put them back. But
+ until someone gets around to fixing it, that seems like the
+ easiest way to get what would seem to be the right mode.
+ I don't check CVSWRITE or _watched; I haven't thought about
+ that in great detail, but it seems like a watched file should
+ be checked out (writable) after a merge. */
+ xchmod (finfo->file, 1);
+
+ /* Traditionally, the text file case prints a whole bunch of
+ scary looking and verbose output which fails to tell the user
+ what is really going on (it gives them rev1 and rev2 but doesn't
+ indicate in any way that rev1 == vn_user). I think just a
+ simple "U foo" is good here; it seems analogous to the case in
+ which the file was added on the branch in terms of what to
+ print. */
+ write_letter (finfo, 'U');
+ }
+ else if (strcmp (t_options, "-kb") == 0
+ || wrap_merge_is_copy (finfo->file)
+ || special_file_mismatch (finfo, rev1, rev2))
+ {
+ /* We are dealing with binary files, or files with a
+ permission/linkage mismatch (this second case only occurs when
+ PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would
+ need to take place. This is a conflict. We give the user
+ the two files, and let them resolve it. It is possible
+ that we should require a "touch foo" or similar step before
+ we allow a checkin. */
+ if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL,
+ t_options, RUN_TTY, NULL, NULL) != 0)
+ status = 2;
+ else
+ status = 0;
+
+ /* OK, this is really stupid. RCS_checkout carefully removes
+ write permissions, and we carefully put them back. But
+ until someone gets around to fixing it, that seems like the
+ easiest way to get what would seem to be the right mode.
+ I don't check CVSWRITE or _watched; I haven't thought about
+ that in great detail, but it seems like a watched file should
+ be checked out (writable) after a merge. */
+ xchmod (finfo->file, 1);
+
+ /* Hmm. We don't give them REV1 anywhere. I guess most people
+ probably don't have a 3-way merge tool for the file type in
+ question, and might just get confused if we tried to either
+ provide them with a copy of the file from REV1, or even just
+ told them what REV1 is so they can get it themself, but it
+ might be worth thinking about. */
+ /* See comment in merge_file about the "nonmergeable file"
+ terminology. */
+ error (0, 0, "nonmergeable file needs merge");
+ error (0, 0, "revision %s from repository is now in %s",
+ rev2, finfo->fullname);
+ error (0, 0, "file from working directory is now in %s", backup);
+ write_letter (finfo, 'C');
+ }
+ else
+ status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
+ t_options, rev1, rev2);
+
+ if (status != 0)
+ {
+ if (status != 1)
+ {
+ error (0, status == -1 ? errno : 0,
+ "could not merge revision %s of %s", rev2, finfo->fullname);
+ error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
+ finfo->fullname, backup);
+ rename_file (backup, finfo->file);
+ }
+ }
+ else /* status == 0 */
+ {
+ /* FIXME: the noexec case is broken. RCS_merge could be doing the
+ xcmp on the temporary files without much hassle, I think. */
+ if (!noexec && !xcmp (backup, finfo->file))
+ {
+ if (!really_quiet)
+ {
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" already contains the differences between ", 0);
+ cvs_output (rev1, 0);
+ cvs_output (" and ", 0);
+ cvs_output (rev2, 0);
+ cvs_output ("\n", 1);
+ }
+
+ /* and skip the registering and sending the new file since it
+ * hasn't been updated.
+ */
+ goto out;
+ }
+ }
+
+ /* The file has changed, but if we just checked it out it may
+ still have the same timestamp it did when it was first
+ registered above in checkout_file. We register it again with a
+ dummy timestamp to make sure that later runs of CVS will
+ recognize that it has changed.
+
+ We don't actually need to register again if we called
+ RCS_checkout above, and we aren't running as the server.
+ However, that is not the normal case, and calling Register
+ again won't cost much in that case. */
+ RegisterMerge (finfo, vers, backup, status);
+
+out:
+ free (rev1);
+ free (rev2);
+ free (backup);
+}
+
+
+
+/*
+ * Report whether revisions REV1 and REV2 of FINFO agree on:
+ * . file ownership
+ * . permissions
+ * . major and minor device numbers
+ * . symbolic links
+ * . hard links
+ *
+ * If either REV1 or REV2 is NULL, the working copy is used instead.
+ *
+ * Return 1 if the files differ on these data.
+ */
+
+int
+special_file_mismatch (struct file_info *finfo, char *rev1, char *rev2)
+{
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ struct stat sb;
+ RCSVers *vp;
+ Node *n;
+ uid_t rev1_uid, rev2_uid;
+ gid_t rev1_gid, rev2_gid;
+ mode_t rev1_mode, rev2_mode;
+ unsigned long dev_long;
+ dev_t rev1_dev, rev2_dev;
+ char *rev1_symlink = NULL;
+ char *rev2_symlink = NULL;
+ List *rev1_hardlinks = NULL;
+ List *rev2_hardlinks = NULL;
+ int check_uids, check_gids, check_modes;
+ int result;
+
+ /* If we don't care about special file info, then
+ don't report a mismatch in any case. */
+ if (!preserve_perms)
+ return 0;
+
+ /* When special_file_mismatch is called from No_Difference, the
+ RCS file has been only partially parsed. We must read the
+ delta tree in order to compare special file info recorded in
+ the delta nodes. (I think this is safe. -twp) */
+ if (finfo->rcs->flags & PARTIAL)
+ RCS_reparsercsfile (finfo->rcs, NULL, NULL);
+
+ check_uids = check_gids = check_modes = 1;
+
+ /* Obtain file information for REV1. If this is null, then stat
+ finfo->file and use that info. */
+ /* If a revision does not know anything about its status,
+ then presumably it doesn't matter, and indicates no conflict. */
+
+ if (rev1 == NULL)
+ {
+ ssize_t rsize;
+
+ if ((rsize = islink (finfo->file)) > 0)
+ rev1_symlink = Xreadlink (finfo->file, rsize);
+ else
+ {
+# ifdef HAVE_STRUCT_STAT_ST_RDEV
+ if (lstat (finfo->file, &sb) < 0)
+ error (1, errno, "could not get file information for %s",
+ finfo->file);
+ rev1_uid = sb.st_uid;
+ rev1_gid = sb.st_gid;
+ rev1_mode = sb.st_mode;
+ if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
+ rev1_dev = sb.st_rdev;
+# else
+ error (1, 0, "cannot handle device files on this system (%s)",
+ finfo->file);
+# endif
+ }
+ rev1_hardlinks = list_linked_files_on_disk (finfo->file);
+ }
+ else
+ {
+ n = findnode (finfo->rcs->versions, rev1);
+ vp = n->data;
+
+ n = findnode (vp->other_delta, "symlink");
+ if (n != NULL)
+ rev1_symlink = xstrdup (n->data);
+ else
+ {
+ n = findnode (vp->other_delta, "owner");
+ if (n == NULL)
+ check_uids = 0; /* don't care */
+ else
+ rev1_uid = strtoul (n->data, NULL, 10);
+
+ n = findnode (vp->other_delta, "group");
+ if (n == NULL)
+ check_gids = 0; /* don't care */
+ else
+ rev1_gid = strtoul (n->data, NULL, 10);
+
+ n = findnode (vp->other_delta, "permissions");
+ if (n == NULL)
+ check_modes = 0; /* don't care */
+ else
+ rev1_mode = strtoul (n->data, NULL, 8);
+
+ n = findnode (vp->other_delta, "special");
+ if (n == NULL)
+ rev1_mode |= S_IFREG;
+ else
+ {
+ /* If the size of `ftype' changes, fix the sscanf call also */
+ char ftype[16];
+ if (sscanf (n->data, "%15s %lu", ftype,
+ &dev_long) < 2)
+ error (1, 0, "%s:%s has bad `special' newphrase %s",
+ finfo->file, rev1, (char *)n->data);
+ rev1_dev = dev_long;
+ if (strcmp (ftype, "character") == 0)
+ rev1_mode |= S_IFCHR;
+ else if (strcmp (ftype, "block") == 0)
+ rev1_mode |= S_IFBLK;
+ else
+ error (0, 0, "%s:%s unknown file type `%s'",
+ finfo->file, rev1, ftype);
+ }
+
+ rev1_hardlinks = vp->hardlinks;
+ if (rev1_hardlinks == NULL)
+ rev1_hardlinks = getlist();
+ }
+ }
+
+ /* Obtain file information for REV2. */
+ if (rev2 == NULL)
+ {
+ ssize_t rsize;
+
+ if ((rsize = islink (finfo->file)) > 0)
+ rev2_symlink = Xreadlink (finfo->file, rsize);
+ else
+ {
+# ifdef HAVE_STRUCT_STAT_ST_RDEV
+ if (lstat (finfo->file, &sb) < 0)
+ error (1, errno, "could not get file information for %s",
+ finfo->file);
+ rev2_uid = sb.st_uid;
+ rev2_gid = sb.st_gid;
+ rev2_mode = sb.st_mode;
+ if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
+ rev2_dev = sb.st_rdev;
+# else
+ error (1, 0, "cannot handle device files on this system (%s)",
+ finfo->file);
+# endif
+ }
+ rev2_hardlinks = list_linked_files_on_disk (finfo->file);
+ }
+ else
+ {
+ n = findnode (finfo->rcs->versions, rev2);
+ vp = n->data;
+
+ n = findnode (vp->other_delta, "symlink");
+ if (n != NULL)
+ rev2_symlink = xstrdup (n->data);
+ else
+ {
+ n = findnode (vp->other_delta, "owner");
+ if (n == NULL)
+ check_uids = 0; /* don't care */
+ else
+ rev2_uid = strtoul (n->data, NULL, 10);
+
+ n = findnode (vp->other_delta, "group");
+ if (n == NULL)
+ check_gids = 0; /* don't care */
+ else
+ rev2_gid = strtoul (n->data, NULL, 10);
+
+ n = findnode (vp->other_delta, "permissions");
+ if (n == NULL)
+ check_modes = 0; /* don't care */
+ else
+ rev2_mode = strtoul (n->data, NULL, 8);
+
+ n = findnode (vp->other_delta, "special");
+ if (n == NULL)
+ rev2_mode |= S_IFREG;
+ else
+ {
+ /* If the size of `ftype' changes, fix the sscanf call also */
+ char ftype[16];
+ if (sscanf (n->data, "%15s %lu", ftype,
+ &dev_long) < 2)
+ error (1, 0, "%s:%s has bad `special' newphrase %s",
+ finfo->file, rev2, (char *)n->data);
+ rev2_dev = dev_long;
+ if (strcmp (ftype, "character") == 0)
+ rev2_mode |= S_IFCHR;
+ else if (strcmp (ftype, "block") == 0)
+ rev2_mode |= S_IFBLK;
+ else
+ error (0, 0, "%s:%s unknown file type `%s'",
+ finfo->file, rev2, ftype);
+ }
+
+ rev2_hardlinks = vp->hardlinks;
+ if (rev2_hardlinks == NULL)
+ rev2_hardlinks = getlist();
+ }
+ }
+
+ /* Check the user/group ownerships and file permissions, printing
+ an error for each mismatch found. Return 0 if all characteristics
+ matched, and 1 otherwise. */
+
+ result = 0;
+
+ /* Compare symlinks first, since symlinks are simpler (don't have
+ any other characteristics). */
+ if (rev1_symlink != NULL && rev2_symlink == NULL)
+ {
+ error (0, 0, "%s is a symbolic link",
+ (rev1 == NULL ? "working file" : rev1));
+ result = 1;
+ }
+ else if (rev1_symlink == NULL && rev2_symlink != NULL)
+ {
+ error (0, 0, "%s is a symbolic link",
+ (rev2 == NULL ? "working file" : rev2));
+ result = 1;
+ }
+ else if (rev1_symlink != NULL)
+ result = (strcmp (rev1_symlink, rev2_symlink) == 0);
+ else
+ {
+ /* Compare user ownership. */
+ if (check_uids && rev1_uid != rev2_uid)
+ {
+ error (0, 0, "%s: owner mismatch between %s and %s",
+ finfo->file,
+ (rev1 == NULL ? "working file" : rev1),
+ (rev2 == NULL ? "working file" : rev2));
+ result = 1;
+ }
+
+ /* Compare group ownership. */
+ if (check_gids && rev1_gid != rev2_gid)
+ {
+ error (0, 0, "%s: group mismatch between %s and %s",
+ finfo->file,
+ (rev1 == NULL ? "working file" : rev1),
+ (rev2 == NULL ? "working file" : rev2));
+ result = 1;
+ }
+
+ /* Compare permissions. */
+ if (check_modes &&
+ (rev1_mode & 07777) != (rev2_mode & 07777))
+ {
+ error (0, 0, "%s: permission mismatch between %s and %s",
+ finfo->file,
+ (rev1 == NULL ? "working file" : rev1),
+ (rev2 == NULL ? "working file" : rev2));
+ result = 1;
+ }
+
+ /* Compare device file characteristics. */
+ if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT))
+ {
+ error (0, 0, "%s: %s and %s are different file types",
+ finfo->file,
+ (rev1 == NULL ? "working file" : rev1),
+ (rev2 == NULL ? "working file" : rev2));
+ result = 1;
+ }
+ else if (S_ISBLK (rev1_mode))
+ {
+ if (rev1_dev != rev2_dev)
+ {
+ error (0, 0, "%s: device numbers of %s and %s do not match",
+ finfo->file,
+ (rev1 == NULL ? "working file" : rev1),
+ (rev2 == NULL ? "working file" : rev2));
+ result = 1;
+ }
+ }
+
+ /* Compare hard links. */
+ if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0)
+ {
+ error (0, 0, "%s: hard linkage of %s and %s do not match",
+ finfo->file,
+ (rev1 == NULL ? "working file" : rev1),
+ (rev2 == NULL ? "working file" : rev2));
+ result = 1;
+ }
+ }
+
+ if (rev1_symlink != NULL)
+ free (rev1_symlink);
+ if (rev2_symlink != NULL)
+ free (rev2_symlink);
+ if (rev1_hardlinks != NULL)
+ dellist (&rev1_hardlinks);
+ if (rev2_hardlinks != NULL)
+ dellist (&rev2_hardlinks);
+
+ return result;
+#else
+ return 0;
+#endif
+}
+
+
+
+int
+joining (void)
+{
+ return join_rev1 || join_date1;
+}
diff --git a/src/update.h b/src/update.h
new file mode 100644
index 0000000..fcbf4ef
--- /dev/null
+++ b/src/update.h
@@ -0,0 +1,21 @@
+/* Declarations for update.c.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+int do_update (int argc, char *argv[], char *xoptions, char *xtag,
+ char *xdate, int xforce, int local, int xbuild,
+ int xaflag, int xprune, int xpipeout, int which,
+ char *xjoin_rev1, char *xjoin_date1,
+ char *xjoin_rev2, char *xjoin_date2,
+ char *preload_update_dir, int xdotemplate,
+ char *repository);
+int joining (void);
+extern int isemptydir (const char *dir, int might_not_exist);
diff --git a/src/vers_ts.c b/src/vers_ts.c
new file mode 100644
index 0000000..b5791dd
--- /dev/null
+++ b/src/vers_ts.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ */
+
+#include "cvs.h"
+#include "lstat.h"
+
+#ifdef SERVER_SUPPORT
+static void time_stamp_server (const char *, Vers_TS *, Entnode *);
+#endif
+
+/* Fill in and return a Vers_TS structure for the file FINFO.
+ *
+ * INPUTS
+ * finfo struct file_info data about the file to be examined.
+ * options Keyword expansion options, I think generally from the
+ * command line. Can be either NULL or "" to indicate
+ * none are specified here.
+ * tag Tag specified by user on the command line (via -r).
+ * date Date specified by user on the command line (via -D).
+ * force_tag_match If set and TAG is specified, will only set RET->vn_rcs
+ * based on TAG. Otherwise, if TAG is specified and does
+ * not exist in the file, RET->vn_rcs will be set to the
+ * head revision.
+ * set_time If set, set the last modification time of the user file
+ * specified by FINFO to the checkin time of RET->vn_rcs.
+ *
+ * RETURNS
+ * Vers_TS structure for FINFO.
+ */
+Vers_TS *
+Version_TS (struct file_info *finfo, char *options, char *tag, char *date,
+ int force_tag_match, int set_time)
+{
+ Node *p;
+ RCSNode *rcsdata;
+ Vers_TS *vers_ts;
+ struct stickydirtag *sdtp;
+ Entnode *entdata;
+ char *rcsexpand = NULL;
+
+ /* get a new Vers_TS struct */
+
+ vers_ts = xmalloc (sizeof (Vers_TS));
+ memset (vers_ts, 0, sizeof (*vers_ts));
+
+ /*
+ * look up the entries file entry and fill in the version and timestamp
+ * if entries is NULL, there is no entries file so don't bother trying to
+ * look it up (used by checkout -P)
+ */
+ if (finfo->entries == NULL)
+ {
+ sdtp = NULL;
+ p = NULL;
+ }
+ else
+ {
+ p = findnode_fn (finfo->entries, finfo->file);
+ sdtp = finfo->entries->list->data; /* list-private */
+ }
+
+ if (p == NULL)
+ {
+ entdata = NULL;
+ }
+ else
+ {
+ entdata = p->data;
+
+ if (entdata->type == ENT_SUBDIR)
+ {
+ /* According to cvs.texinfo, the various fields in the Entries
+ file for a directory (other than the name) do not have a
+ defined meaning. We need to pass them along without getting
+ confused based on what is in them. Therefore we make sure
+ not to set vn_user and the like from Entries, add.c and
+ perhaps other code will expect these fields to be NULL for
+ a directory. */
+ vers_ts->entdata = entdata;
+ }
+ else
+#ifdef SERVER_SUPPORT
+ /* An entries line with "D" in the timestamp indicates that the
+ client sent Is-modified without sending Entry. So we want to
+ use the entries line for the sole purpose of telling
+ time_stamp_server what is up; we don't want the rest of CVS
+ to think there is an entries line. */
+ if (strcmp (entdata->timestamp, "D") != 0)
+#endif
+ {
+ vers_ts->vn_user = xstrdup (entdata->version);
+ vers_ts->ts_rcs = xstrdup (entdata->timestamp);
+ vers_ts->ts_conflict = xstrdup (entdata->conflict);
+ if (!(tag || date) && !(sdtp && sdtp->aflag))
+ {
+ vers_ts->tag = xstrdup (entdata->tag);
+ vers_ts->date = xstrdup (entdata->date);
+ }
+ vers_ts->entdata = entdata;
+ }
+ /* Even if we don't have an "entries line" as such
+ (vers_ts->entdata), we want to pick up options which could
+ have been from a Kopt protocol request. */
+ if (!options || *options == '\0')
+ {
+ if (!(sdtp && sdtp->aflag))
+ vers_ts->options = xstrdup (entdata->options);
+ }
+ }
+
+ /* Always look up the RCS keyword mode when we have an RCS archive. It
+ * will either be needed as a default or to avoid allowing the -k options
+ * specified on the command line from overriding binary mode (-kb).
+ */
+ if (finfo->rcs != NULL)
+ rcsexpand = RCS_getexpand (finfo->rcs);
+
+ /*
+ * -k options specified on the command line override (and overwrite)
+ * options stored in the entries file and default options from the RCS
+ * archive, except for binary mode (-kb).
+ */
+ if (options && *options != '\0')
+ {
+ if (vers_ts->options != NULL)
+ free (vers_ts->options);
+ if (rcsexpand != NULL && strcmp (rcsexpand, "b") == 0)
+ vers_ts->options = xstrdup ("-kb");
+ else
+ vers_ts->options = xstrdup (options);
+ }
+ else if ((!vers_ts->options || *vers_ts->options == '\0')
+ && rcsexpand != NULL)
+ {
+ /* If no keyword expansion was specified on command line,
+ use whatever was in the rcs file (if there is one). This
+ is how we, if we are the server, tell the client whether
+ a file is binary. */
+ if (vers_ts->options != NULL)
+ free (vers_ts->options);
+ vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
+ strcpy (vers_ts->options, "-k");
+ strcat (vers_ts->options, rcsexpand);
+ }
+ if (!vers_ts->options)
+ vers_ts->options = xstrdup ("");
+
+ /*
+ * if tags were specified on the command line, they override what is in
+ * the Entries file
+ */
+ if (tag || date)
+ {
+ vers_ts->tag = xstrdup (tag);
+ vers_ts->date = xstrdup (date);
+ }
+ else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
+ {
+ if (!vers_ts->tag)
+ {
+ vers_ts->tag = xstrdup (sdtp->tag);
+ vers_ts->nonbranch = sdtp->nonbranch;
+ }
+ if (!vers_ts->date)
+ vers_ts->date = xstrdup (sdtp->date);
+ }
+
+ /* Now look up the info on the source controlled file */
+ if (finfo->rcs != NULL)
+ {
+ rcsdata = finfo->rcs;
+ rcsdata->refcount++;
+ }
+ else if (finfo->repository != NULL)
+ rcsdata = RCS_parse (finfo->file, finfo->repository);
+ else
+ rcsdata = NULL;
+
+ if (rcsdata != NULL)
+ {
+ /* squirrel away the rcsdata pointer for others */
+ vers_ts->srcfile = rcsdata;
+
+ if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
+ {
+ vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
+ vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
+ }
+ else
+ {
+ int simple;
+
+ vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
+ vers_ts->date, force_tag_match,
+ &simple);
+ if (vers_ts->vn_rcs == NULL)
+ vers_ts->vn_tag = NULL;
+ else if (simple)
+ vers_ts->vn_tag = xstrdup (vers_ts->tag);
+ else
+ vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
+ }
+
+ /*
+ * If the source control file exists and has the requested revision,
+ * get the Date the revision was checked in. If "user" exists, set
+ * its mtime.
+ */
+ if (set_time && vers_ts->vn_rcs != NULL)
+ {
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_modtime (finfo, vers_ts);
+ else
+#endif
+ {
+ struct utimbuf t;
+
+ memset (&t, 0, sizeof (t));
+ t.modtime = RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0);
+ if (t.modtime != (time_t) -1)
+ {
+#ifdef UTIME_EXPECTS_WRITABLE
+ int change_it_back = 0;
+#endif
+
+ (void) time (&t.actime);
+
+#ifdef UTIME_EXPECTS_WRITABLE
+ if (!iswritable (finfo->file))
+ {
+ xchmod (finfo->file, 1);
+ change_it_back = 1;
+ }
+#endif /* UTIME_EXPECTS_WRITABLE */
+
+ /* This used to need to ignore existence_errors
+ (for cases like where update.c now clears
+ set_time if noexec, but didn't used to). I
+ think maybe now it doesn't (server_modtime does
+ not like those kinds of cases). */
+ (void) utime (finfo->file, &t);
+
+#ifdef UTIME_EXPECTS_WRITABLE
+ if (change_it_back)
+ xchmod (finfo->file, 0);
+#endif /* UTIME_EXPECTS_WRITABLE */
+ }
+ }
+ }
+ }
+
+ /* get user file time-stamp in ts_user */
+ if (finfo->entries != NULL)
+ {
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ time_stamp_server (finfo->file, vers_ts, entdata);
+ else
+#endif
+ vers_ts->ts_user = time_stamp (finfo->file);
+ }
+
+ return (vers_ts);
+}
+
+
+
+#ifdef SERVER_SUPPORT
+
+/* Set VERS_TS->TS_USER to time stamp for FILE. */
+
+/* Separate these out to keep the logic below clearer. */
+#define mark_lost(V) ((V)->ts_user = 0)
+#define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs))
+
+static void
+time_stamp_server (const char *file, Vers_TS *vers_ts, Entnode *entdata)
+{
+ struct stat sb;
+ char *cp;
+
+ TRACE (TRACE_FUNCTION, "time_stamp_server (%s, %s, %s, %s)",
+ file,
+ entdata && entdata->version ? entdata->version : "(null)",
+ entdata && entdata->timestamp ? entdata->timestamp : "(null)",
+ entdata && entdata->conflict ? entdata->conflict : "(null)");
+
+ if (lstat (file, &sb) < 0)
+ {
+ if (! existence_error (errno))
+ error (1, errno, "cannot stat temp file");
+
+ /* Missing file means lost or unmodified; check entries
+ file to see which.
+
+ XXX FIXME - If there's no entries file line, we
+ wouldn't be getting the file at all, so consider it
+ lost. I don't know that that's right, but it's not
+ clear to me that either choice is. Besides, would we
+ have an RCS string in that case anyways? */
+ if (entdata == NULL)
+ mark_lost (vers_ts);
+ else if (entdata->timestamp
+ && entdata->timestamp[0] == '='
+ && entdata->timestamp[1] == '\0')
+ mark_unchanged (vers_ts);
+ else if (entdata->conflict
+ && entdata->conflict[0] == '=')
+ {
+ /* These just need matching content. Might as well minimize it. */
+ vers_ts->ts_user = xstrdup ("");
+ vers_ts->ts_conflict = xstrdup ("");
+ }
+ else if (entdata->timestamp
+ && (entdata->timestamp[0] == 'M'
+ || entdata->timestamp[0] == 'D')
+ && entdata->timestamp[1] == '\0')
+ vers_ts->ts_user = xstrdup ("Is-modified");
+ else
+ mark_lost (vers_ts);
+ }
+ else if (sb.st_mtime == 0)
+ {
+ /* We shouldn't reach this case any more! */
+ abort ();
+ }
+ else
+ {
+ struct tm *tm_p;
+
+ vers_ts->ts_user = xmalloc (25);
+ /* We want to use the same timestamp format as is stored in the
+ st_mtime. For unix (and NT I think) this *must* be universal
+ time (UT), so that files don't appear to be modified merely
+ because the timezone has changed. For VMS, or hopefully other
+ systems where gmtime returns NULL, the modification time is
+ stored in local time, and therefore it is not possible to cause
+ st_mtime to be out of sync by changing the timezone. */
+ tm_p = gmtime (&sb.st_mtime);
+ cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime);
+ cp[24] = 0;
+ /* Fix non-standard format. */
+ if (cp[8] == '0') cp[8] = ' ';
+ (void) strcpy (vers_ts->ts_user, cp);
+ }
+}
+
+#endif /* SERVER_SUPPORT */
+
+
+
+/* Given a UNIX seconds since the epoch, return a string in the format used by
+ * the Entries file.
+ *
+ *
+ * INPUTS
+ * UNIXTIME The timestamp to be formatted.
+ *
+ * RETURNS
+ * A freshly allocated string the caller is responsible for disposing of.
+ */
+char *
+entries_time (time_t unixtime)
+{
+ struct tm *tm_p;
+ char *cp;
+
+ /* We want to use the same timestamp format as is stored in the
+ st_mtime. For unix (and NT I think) this *must* be universal
+ time (UT), so that files don't appear to be modified merely
+ because the timezone has changed. For VMS, or hopefully other
+ systems where gmtime returns NULL, the modification time is
+ stored in local time, and therefore it is not possible to cause
+ st_mtime to be out of sync by changing the timezone. */
+ tm_p = gmtime (&unixtime);
+ cp = tm_p ? asctime (tm_p) : ctime (&unixtime);
+ /* Get rid of the EOL */
+ cp[24] = '\0';
+ /* Fix non-standard format. */
+ if (cp[8] == '0') cp[8] = ' ';
+
+ return Xasprintf ("%s", cp);
+}
+
+
+
+time_t
+unix_time_stamp (const char *file)
+{
+ struct stat sb;
+ time_t mtime = 0L;
+
+ if (!lstat (file, &sb))
+ {
+ mtime = sb.st_mtime;
+ }
+
+ /* If it's a symlink, return whichever is the newest mtime of
+ the link and its target, for safety.
+ */
+ if (!stat (file, &sb))
+ {
+ if (mtime < sb.st_mtime)
+ mtime = sb.st_mtime;
+ }
+
+ return mtime;
+}
+
+
+
+/*
+ * Gets the time-stamp for the file "file" and returns it in space it
+ * allocates
+ */
+char *
+time_stamp (const char *file)
+{
+ time_t mtime = unix_time_stamp (file);
+ return mtime ? entries_time (mtime) : NULL;
+}
+
+
+
+/*
+ * free up a Vers_TS struct
+ */
+void
+freevers_ts (Vers_TS **versp)
+{
+ if ((*versp)->srcfile)
+ freercsnode (&((*versp)->srcfile));
+ if ((*versp)->vn_user)
+ free ((*versp)->vn_user);
+ if ((*versp)->vn_rcs)
+ free ((*versp)->vn_rcs);
+ if ((*versp)->vn_tag)
+ free ((*versp)->vn_tag);
+ if ((*versp)->ts_user)
+ free ((*versp)->ts_user);
+ if ((*versp)->ts_rcs)
+ free ((*versp)->ts_rcs);
+ if ((*versp)->options)
+ free ((*versp)->options);
+ if ((*versp)->tag)
+ free ((*versp)->tag);
+ if ((*versp)->date)
+ free ((*versp)->date);
+ if ((*versp)->ts_conflict)
+ free ((*versp)->ts_conflict);
+ free ((char *) *versp);
+ *versp = NULL;
+}
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..ebce4b2
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1994 david d `zoo' zuhn
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions Copyright (C) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with this CVS source distribution.
+ *
+ * version.c - the CVS version number
+ */
+
+#include "cvs.h"
+
+#ifdef CLIENT_SUPPORT
+#ifdef SERVER_SUPPORT
+char *config_string = " (client/server)\n";
+#else
+char *config_string = " (client)\n";
+#endif
+#else
+#ifdef SERVER_SUPPORT
+char *config_string = " (server)\n";
+#else
+char *config_string = "\n";
+#endif
+#endif
+
+
+
+static const char *const version_usage[] =
+{
+ "Usage: %s %s\n",
+ NULL
+};
+
+
+
+/*
+ * Output a version string for the client and server.
+ *
+ * This function will output the simple version number (for the '--version'
+ * option) or the version numbers of the client and server (using the 'version'
+ * command).
+ */
+int
+version (int argc, char **argv)
+{
+ int err = 0;
+
+ if (argc == -1)
+ usage (version_usage);
+
+ if (current_parsed_root && current_parsed_root->isremote)
+ (void) fputs ("Client: ", stdout);
+
+ /* Having the year here is a good idea, so people have
+ some idea of how long ago their version of CVS was
+ released. */
+ (void) fputs (PACKAGE_STRING, stdout);
+ (void) fputs (config_string, stdout);
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root && current_parsed_root->isremote)
+ {
+ (void) fputs ("Server: ", stdout);
+ start_server ();
+ if (supported_request ("version"))
+ send_to_server ("version\012", 0);
+ else
+ {
+ send_to_server ("noop\012", 0);
+ fputs ("(unknown)\n", stdout);
+ }
+ err = get_responses_and_close ();
+ }
+#endif
+ return err;
+}
+
diff --git a/src/watch.c b/src/watch.c
new file mode 100644
index 0000000..13dc940
--- /dev/null
+++ b/src/watch.c
@@ -0,0 +1,540 @@
+/* Implementation for "cvs watch add", "cvs watchers", and related commands
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+#include "edit.h"
+#include "fileattr.h"
+#include "watch.h"
+
+const char *const watch_usage[] =
+{
+ "Usage: %s %s {on|off|add|remove} [-lR] [-a <action>]... [<path>]...\n",
+ "on/off: Turn on/off read-only checkouts of files.\n",
+ "add/remove: Add or remove notification on actions.\n",
+ "-l (on/off/add/remove): Local directory only, not recursive.\n",
+ "-R (on/off/add/remove): Process directories recursively (default).\n",
+ "-a (add/remove): Specify what actions, one of: `edit', `unedit',\n",
+ " `commit', `all', or `none' (defaults to `all').\n",
+ "(Specify the --help global option for a list of other help options.)\n",
+ NULL
+};
+
+static struct addremove_args the_args;
+
+void
+watch_modify_watchers (const char *file, struct addremove_args *what)
+{
+ char *curattr = fileattr_get0 (file, "_watchers");
+ char *p;
+ char *pend;
+ char *nextp;
+ char *who;
+ int who_len;
+ char *mycurattr;
+ char *mynewattr;
+ size_t mynewattr_size;
+
+ int add_edit_pending;
+ int add_unedit_pending;
+ int add_commit_pending;
+ int remove_edit_pending;
+ int remove_unedit_pending;
+ int remove_commit_pending;
+ int add_tedit_pending;
+ int add_tunedit_pending;
+ int add_tcommit_pending;
+
+ TRACE( TRACE_FUNCTION, "modify_watchers ( %s )", file );
+
+ who = getcaller ();
+ who_len = strlen (who);
+
+ /* Look for current watcher types for this user. */
+ mycurattr = NULL;
+ if (curattr != NULL)
+ {
+ p = curattr;
+ while (1) {
+ if (strncmp (who, p, who_len) == 0
+ && p[who_len] == '>')
+ {
+ /* Found this user. */
+ mycurattr = p + who_len + 1;
+ }
+ p = strchr (p, ',');
+ if (p == NULL)
+ break;
+ ++p;
+ }
+ }
+ if (mycurattr != NULL)
+ {
+ mycurattr = xstrdup (mycurattr);
+ p = strchr (mycurattr, ',');
+ if (p != NULL)
+ *p = '\0';
+ }
+
+ /* Now copy mycurattr to mynewattr, making the requisite modifications.
+ Note that we add a dummy '+' to the start of mynewattr, to reduce
+ special cases (but then we strip it off when we are done). */
+
+ mynewattr_size = sizeof "+edit+unedit+commit+tedit+tunedit+tcommit";
+ if (mycurattr != NULL)
+ mynewattr_size += strlen (mycurattr);
+ mynewattr = xmalloc (mynewattr_size);
+ mynewattr[0] = '\0';
+
+ add_edit_pending = what->adding && what->edit;
+ add_unedit_pending = what->adding && what->unedit;
+ add_commit_pending = what->adding && what->commit;
+ remove_edit_pending = !what->adding && what->edit;
+ remove_unedit_pending = !what->adding && what->unedit;
+ remove_commit_pending = !what->adding && what->commit;
+ add_tedit_pending = what->add_tedit;
+ add_tunedit_pending = what->add_tunedit;
+ add_tcommit_pending = what->add_tcommit;
+
+ /* Copy over existing watch types, except those to be removed. */
+ p = mycurattr;
+ while (p != NULL)
+ {
+ pend = strchr (p, '+');
+ if (pend == NULL)
+ {
+ pend = p + strlen (p);
+ nextp = NULL;
+ }
+ else
+ nextp = pend + 1;
+
+ /* Process this item. */
+ if (pend - p == 4 && strncmp ("edit", p, 4) == 0)
+ {
+ if (!remove_edit_pending)
+ strcat (mynewattr, "+edit");
+ add_edit_pending = 0;
+ }
+ else if (pend - p == 6 && strncmp ("unedit", p, 6) == 0)
+ {
+ if (!remove_unedit_pending)
+ strcat (mynewattr, "+unedit");
+ add_unedit_pending = 0;
+ }
+ else if (pend - p == 6 && strncmp ("commit", p, 6) == 0)
+ {
+ if (!remove_commit_pending)
+ strcat (mynewattr, "+commit");
+ add_commit_pending = 0;
+ }
+ else if (pend - p == 5 && strncmp ("tedit", p, 5) == 0)
+ {
+ if (!what->remove_temp)
+ strcat (mynewattr, "+tedit");
+ add_tedit_pending = 0;
+ }
+ else if (pend - p == 7 && strncmp ("tunedit", p, 7) == 0)
+ {
+ if (!what->remove_temp)
+ strcat (mynewattr, "+tunedit");
+ add_tunedit_pending = 0;
+ }
+ else if (pend - p == 7 && strncmp ("tcommit", p, 7) == 0)
+ {
+ if (!what->remove_temp)
+ strcat (mynewattr, "+tcommit");
+ add_tcommit_pending = 0;
+ }
+ else
+ {
+ char *mp;
+
+ /* Copy over any unrecognized watch types, for future
+ expansion. */
+ mp = mynewattr + strlen (mynewattr);
+ *mp++ = '+';
+ strncpy (mp, p, pend - p);
+ *(mp + (pend - p)) = '\0';
+ }
+
+ /* Set up for next item. */
+ p = nextp;
+ }
+
+ /* Add in new watch types. */
+ if (add_edit_pending)
+ strcat (mynewattr, "+edit");
+ if (add_unedit_pending)
+ strcat (mynewattr, "+unedit");
+ if (add_commit_pending)
+ strcat (mynewattr, "+commit");
+ if (add_tedit_pending)
+ strcat (mynewattr, "+tedit");
+ if (add_tunedit_pending)
+ strcat (mynewattr, "+tunedit");
+ if (add_tcommit_pending)
+ strcat (mynewattr, "+tcommit");
+
+ {
+ char *curattr_new;
+
+ curattr_new =
+ fileattr_modify (curattr,
+ who,
+ mynewattr[0] == '\0' ? NULL : mynewattr + 1,
+ '>',
+ ',');
+ /* If the attribute is unchanged, don't rewrite the attribute file. */
+ if (!((curattr_new == NULL && curattr == NULL)
+ || (curattr_new != NULL
+ && curattr != NULL
+ && strcmp (curattr_new, curattr) == 0)))
+ fileattr_set (file,
+ "_watchers",
+ curattr_new);
+ if (curattr_new != NULL)
+ free (curattr_new);
+ }
+
+ if (curattr != NULL)
+ free (curattr);
+ if (mycurattr != NULL)
+ free (mycurattr);
+ if (mynewattr != NULL)
+ free (mynewattr);
+}
+
+static int addremove_fileproc (void *callerdat,
+ struct file_info *finfo);
+
+static int
+addremove_fileproc (void *callerdat, struct file_info *finfo)
+{
+ watch_modify_watchers (finfo->file, &the_args);
+ return 0;
+}
+
+static int addremove_filesdoneproc (void * callerdat, int err, const char * repository,
+ const char *update_dir, List * entries)
+{
+ int set_default = the_args.setting_default;
+ int dir_check = 0;
+
+ while ( !set_default && dir_check < the_args.num_dirs )
+ {
+ /* If we are recursing, then just see if the first part of update_dir
+ matches any of the specified directories. Otherwise, it must be an exact
+ match. */
+ if ( the_args.local )
+ set_default = strcmp( update_dir, the_args.dirs[ dir_check ] )==0;
+ else
+ set_default = strncmp( update_dir, the_args.dirs[ dir_check ], strlen( the_args.dirs[ dir_check ] ) ) == 0;
+ dir_check++;
+ }
+
+ if (set_default)
+ watch_modify_watchers (NULL, &the_args);
+ return err;
+}
+
+
+static int
+watch_addremove (int argc, char **argv)
+{
+ int c;
+ int err;
+ int a_omitted;
+ int arg_index;
+ int max_dirs;
+
+ a_omitted = 1;
+ the_args.commit = 0;
+ the_args.edit = 0;
+ the_args.unedit = 0;
+ the_args.num_dirs = 0;
+ the_args.dirs = NULL;
+ the_args.local = 0;
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lRa:")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ the_args.local = 1;
+ break;
+ case 'R':
+ the_args.local = 0;
+ break;
+ case 'a':
+ a_omitted = 0;
+ if (strcmp (optarg, "edit") == 0)
+ the_args.edit = 1;
+ else if (strcmp (optarg, "unedit") == 0)
+ the_args.unedit = 1;
+ else if (strcmp (optarg, "commit") == 0)
+ the_args.commit = 1;
+ else if (strcmp (optarg, "all") == 0)
+ {
+ the_args.edit = 1;
+ the_args.unedit = 1;
+ the_args.commit = 1;
+ }
+ else if (strcmp (optarg, "none") == 0)
+ {
+ the_args.edit = 0;
+ the_args.unedit = 0;
+ the_args.commit = 0;
+ }
+ else
+ usage (watch_usage);
+ break;
+ case '?':
+ default:
+ usage (watch_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ the_args.num_dirs = 0;
+ max_dirs = 4; /* Arbitrary choice. */
+ the_args.dirs = xmalloc( sizeof( const char * ) * max_dirs );
+
+ TRACE (TRACE_FUNCTION, "watch_addremove (%d)", argc);
+ for ( arg_index=0; arg_index<argc; ++arg_index )
+ {
+ TRACE( TRACE_FUNCTION, "\t%s", argv[ arg_index ]);
+ if ( isdir( argv[ arg_index ] ) )
+ {
+ if ( the_args.num_dirs >= max_dirs )
+ {
+ max_dirs *= 2;
+ the_args.dirs = (const char ** )xrealloc( (void *)the_args.dirs, max_dirs );
+ }
+ the_args.dirs[ the_args.num_dirs++ ] = argv[ arg_index ];
+ }
+ }
+
+ if (a_omitted)
+ {
+ the_args.edit = 1;
+ the_args.unedit = 1;
+ the_args.commit = 1;
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+ ign_setup ();
+
+ if (the_args.local)
+ send_arg ("-l");
+ /* FIXME: copes poorly with "all" if server is extended to have
+ new watch types and client is still running an old version. */
+ if (the_args.edit)
+ option_with_arg ("-a", "edit");
+ if (the_args.unedit)
+ option_with_arg ("-a", "unedit");
+ if (the_args.commit)
+ option_with_arg ("-a", "commit");
+ if (!the_args.edit && !the_args.unedit && !the_args.commit)
+ option_with_arg ("-a", "none");
+ send_arg ("--");
+ send_files (argc, argv, the_args.local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server (the_args.adding ?
+ "watch-add\012" : "watch-remove\012",
+ 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ the_args.setting_default = (argc <= 0);
+
+ lock_tree_promotably (argc, argv, the_args.local, W_LOCAL, 0);
+
+ err = start_recursion
+ (addremove_fileproc, addremove_filesdoneproc, NULL, NULL, NULL,
+ argc, argv, the_args.local, W_LOCAL, 0, CVS_LOCK_WRITE,
+ NULL, 1, NULL);
+
+ Lock_Cleanup ();
+ free( (void *)the_args.dirs );
+ the_args.dirs = NULL;
+
+ return err;
+}
+
+
+
+int
+watch_add (int argc, char **argv)
+{
+ the_args.adding = 1;
+ return watch_addremove (argc, argv);
+}
+
+int
+watch_remove (int argc, char **argv)
+{
+ the_args.adding = 0;
+ return watch_addremove (argc, argv);
+}
+
+int
+watch (int argc, char **argv)
+{
+ if (argc <= 1)
+ usage (watch_usage);
+ if (strcmp (argv[1], "on") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_on (argc, argv);
+ }
+ else if (strcmp (argv[1], "off") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_off (argc, argv);
+ }
+ else if (strcmp (argv[1], "add") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_add (argc, argv);
+ }
+ else if (strcmp (argv[1], "remove") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_remove (argc, argv);
+ }
+ else
+ usage (watch_usage);
+ return 0;
+}
+
+static const char *const watchers_usage[] =
+{
+ "Usage: %s %s [-lR] [<file>]...\n",
+ "-l\tProcess this directory only (not recursive).\n",
+ "-R\tProcess directories recursively (default).\n",
+ "(Specify the --help global option for a list of other help options.)\n",
+ NULL
+};
+
+static int watchers_fileproc (void *callerdat,
+ struct file_info *finfo);
+
+static int
+watchers_fileproc (void *callerdat, struct file_info *finfo)
+{
+ char *them;
+ char *p;
+
+ them = fileattr_get0 (finfo->file, "_watchers");
+ if (them == NULL)
+ return 0;
+
+ cvs_output (finfo->fullname, 0);
+
+ p = them;
+ while (1)
+ {
+ cvs_output ("\t", 1);
+ while (*p != '>' && *p != '\0')
+ cvs_output (p++, 1);
+ if (*p == '\0')
+ {
+ /* Only happens if attribute is misformed. */
+ cvs_output ("\n", 1);
+ break;
+ }
+ ++p;
+ cvs_output ("\t", 1);
+ while (1)
+ {
+ while (*p != '+' && *p != ',' && *p != '\0')
+ cvs_output (p++, 1);
+ if (*p == '\0')
+ {
+ cvs_output ("\n", 1);
+ goto out;
+ }
+ if (*p == ',')
+ {
+ ++p;
+ break;
+ }
+ ++p;
+ cvs_output ("\t", 1);
+ }
+ cvs_output ("\n", 1);
+ }
+ out:;
+ free (them);
+ return 0;
+}
+
+int
+watchers (int argc, char **argv)
+{
+ int local = 0;
+ int c;
+
+ if (argc == -1)
+ usage (watchers_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lR")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (watchers_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
+ {
+ start_server ();
+ ign_setup ();
+
+ if (local)
+ send_arg ("-l");
+ send_arg ("--");
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ send_to_server ("watchers\012", 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ return start_recursion (watchers_fileproc, NULL, NULL,
+ NULL, NULL, argc, argv, local, W_LOCAL, 0,
+ CVS_LOCK_READ, NULL, 1, NULL);
+}
diff --git a/src/watch.h b/src/watch.h
new file mode 100644
index 0000000..4e143d4
--- /dev/null
+++ b/src/watch.h
@@ -0,0 +1,61 @@
+/* Interface to "cvs watch add", "cvs watchers", and related features
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+extern const char *const watch_usage[];
+
+/* Flags to pass between the various functions making up the
+ add/remove code. All in a single structure in case there is some
+ need to make the code reentrant some day. */
+
+struct addremove_args {
+ /* A flag for each watcher type. */
+ int edit;
+ int unedit;
+ int commit;
+
+ /* Are we adding or removing (non-temporary) edit,unedit,and/or commit
+ watches? */
+ int adding;
+
+ /* Should we add a temporary edit watch? */
+ int add_tedit;
+ /* Should we add a temporary unedit watch? */
+ int add_tunedit;
+ /* Should we add a temporary commit watch? */
+ int add_tcommit;
+
+ /* Should we remove all temporary watches? */
+ int remove_temp;
+
+ /* Should we set the default? This is here for passing among various
+ routines in watch.c (a good place for it if there is ever any reason
+ to make the stuff reentrant), not for watch_modify_watchers.
+ This is only set if there are no arguments specified, e.g. 'cvs watch add' */
+ int setting_default;
+
+ /* List of directories specified on the command line, to set the
+ default attributes. */
+ const char ** dirs;
+ int num_dirs;
+
+ /* Is this recursive? */
+ int local;
+
+};
+
+/* Modify the watchers for FILE. *WHAT tells what to do to them.
+ If FILE is NULL, modify default args (WHAT->SETTING_DEFAULT is
+ not used). */
+void watch_modify_watchers (const char *file, struct addremove_args *what);
+
+int watch_add (int argc, char **argv);
+int watch_remove (int argc, char **argv);
diff --git a/src/wrapper.c b/src/wrapper.c
new file mode 100644
index 0000000..30fe9d0
--- /dev/null
+++ b/src/wrapper.c
@@ -0,0 +1,574 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+#include "getline.h"
+
+/*
+ Original Author: athan@morgan.com <Andrew C. Athan> 2/1/94
+ Modified By: vdemarco@bou.shl.com
+
+ This package was written to support the NEXTSTEP concept of
+ "wrappers." These are essentially directories that are to be
+ treated as "files." This package allows such wrappers to be
+ "processed" on the way in and out of CVS. The intended use is to
+ wrap up a wrapper into a single tar, such that that tar can be
+ treated as a single binary file in CVS. To solve the problem
+ effectively, it was also necessary to be able to prevent rcsmerge
+ application at appropriate times.
+
+ ------------------
+ Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
+
+ wildcard [option value][option value]...
+
+ where option is one of
+ -m update methodology value: MERGE or COPY
+ -k default -k rcs option to use on import or add
+
+ and value is a single-quote delimited value.
+
+ E.g:
+ *.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY'
+*/
+
+
+typedef struct {
+ char *wildCard;
+ char *tocvsFilter;
+ char *fromcvsFilter;
+ char *rcsOption;
+ WrapMergeMethod mergeMethod;
+} WrapperEntry;
+
+static WrapperEntry **wrap_list=NULL;
+static WrapperEntry **wrap_saved_list=NULL;
+
+static int wrap_size=0;
+static int wrap_count=0;
+static int wrap_tempcount=0;
+
+/* FIXME: the relationship between wrap_count, wrap_tempcount,
+ * wrap_saved_count, and wrap_saved_tempcount is not entirely clear;
+ * it is certainly suspicious that wrap_saved_count is never set to a
+ * value other than zero! If the variable isn't being used, it should
+ * be removed. And in general, we should describe how temporary
+ * vs. permanent wrappers are implemented, and then make sure the
+ * implementation is actually doing that.
+ *
+ * Right now things seem to be working, but that's no guarantee there
+ * isn't a bug lurking somewhere in the murk.
+ */
+
+static int wrap_saved_count=0;
+
+static int wrap_saved_tempcount=0;
+
+#define WRAPPER_GROW 8
+
+void wrap_add_entry (WrapperEntry *e,int temp);
+void wrap_kill (void);
+void wrap_kill_temp (void);
+void wrap_free_entry (WrapperEntry *e);
+void wrap_free_entry_internal (WrapperEntry *e);
+void wrap_restore_saved (void);
+
+void wrap_setup(void)
+{
+ /* FIXME-reentrancy: if we do a multithreaded server, will need to
+ move this to a per-connection data structure, or better yet
+ think about a cleaner solution. */
+ static int wrap_setup_already_done = 0;
+ char *homedir;
+
+ if (wrap_setup_already_done != 0)
+ return;
+ else
+ wrap_setup_already_done = 1;
+
+ if (!current_parsed_root->isremote)
+ {
+ char *file;
+
+ /* Then add entries found in repository, if it exists. */
+ file = Xasprintf ("%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_WRAPPER);
+ if (isfile (file))
+ {
+ wrap_add_file(file,0);
+ }
+ free (file);
+ }
+
+ /* Then add entries found in home dir, (if user has one) and file
+ exists. */
+ homedir = get_homedir ();
+ /* If we can't find a home directory, ignore ~/.cvswrappers. This may
+ make tracking down problems a bit of a pain, but on the other
+ hand it might be obnoxious to complain when CVS will function
+ just fine without .cvswrappers (and many users won't even know what
+ .cvswrappers is). */
+ if (homedir != NULL)
+ {
+ char *file = strcat_filename_onto_homedir (homedir, CVSDOTWRAPPER);
+ if (isfile (file))
+ {
+ wrap_add_file (file, 0);
+ }
+ free (file);
+ }
+
+ /* FIXME: calling wrap_add() below implies that the CVSWRAPPERS
+ * environment variable contains exactly one "wrapper" -- a line
+ * of the form
+ *
+ * FILENAME_PATTERN FLAG OPTS [ FLAG OPTS ...]
+ *
+ * This may disagree with the documentation, which states:
+ *
+ * `$CVSWRAPPERS'
+ * A whitespace-separated list of file name patterns that CVS
+ * should treat as wrappers. *Note Wrappers::.
+ *
+ * Does this mean the environment variable can hold multiple
+ * wrappers lines? If so, a single call to wrap_add() is
+ * insufficient.
+ */
+
+ /* Then add entries found in CVSWRAPPERS environment variable. */
+ wrap_add (getenv (WRAPPER_ENV), 0);
+}
+
+#ifdef CLIENT_SUPPORT
+/* Send -W arguments for the wrappers to the server. The command must
+ be one that accepts them (e.g. update, import). */
+void
+wrap_send (void)
+{
+ int i;
+
+ for (i = 0; i < wrap_count + wrap_tempcount; ++i)
+ {
+ if (wrap_list[i]->tocvsFilter != NULL
+ || wrap_list[i]->fromcvsFilter != NULL)
+ /* For greater studliness we would print the offending option
+ and (more importantly) where we found it. */
+ error (0, 0, "\
+-t and -f wrapper options are not supported remotely; ignored");
+ if (wrap_list[i]->mergeMethod == WRAP_COPY)
+ /* For greater studliness we would print the offending option
+ and (more importantly) where we found it. */
+ error (0, 0, "\
+-m wrapper option is not supported remotely; ignored");
+ send_to_server ("Argument -W\012Argument ", 0);
+ send_to_server (wrap_list[i]->wildCard, 0);
+ send_to_server (" -k '", 0);
+ if (wrap_list[i]->rcsOption != NULL)
+ send_to_server (wrap_list[i]->rcsOption, 0);
+ else
+ send_to_server ("kv", 0);
+ send_to_server ("'\012", 0);
+ }
+}
+#endif /* CLIENT_SUPPORT */
+
+#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
+/* Output wrapper entries in the format of cvswrappers lines.
+ *
+ * This is useful when one side of a client/server connection wants to
+ * send its wrappers to the other; since the receiving side would like
+ * to use wrap_add() to incorporate the wrapper, it's best if the
+ * entry arrives in this format.
+ *
+ * The entries are stored in `line', which is allocated here. Caller
+ * can free() it.
+ *
+ * If first_call_p is nonzero, then start afresh. */
+void
+wrap_unparse_rcs_options (char **line, int first_call_p)
+{
+ /* FIXME-reentrancy: we should design a reentrant interface, like
+ a callback which gets handed each wrapper (a multithreaded
+ server being the most concrete reason for this, but the
+ non-reentrant interface is fairly unnecessary/ugly). */
+ static int i;
+
+ if (first_call_p)
+ i = 0;
+
+ if (i >= wrap_count + wrap_tempcount) {
+ *line = NULL;
+ return;
+ }
+
+ *line = Xasprintf ("%s -k '%s'",
+ wrap_list[i]->wildCard,
+ wrap_list[i]->rcsOption
+ ? wrap_list[i]->rcsOption : "kv");
+ ++i;
+}
+#endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
+
+/*
+ * Remove fmt str specifier other than %% or %s. And allow
+ * only max_s %s specifiers
+ */
+static void
+wrap_clean_fmt_str(char *fmt, int max_s)
+{
+ while (*fmt) {
+ if (fmt[0] == '%' && fmt[1])
+ {
+ if (fmt[1] == '%')
+ fmt++;
+ else
+ if (fmt[1] == 's' && max_s > 0)
+ {
+ max_s--;
+ fmt++;
+ } else
+ *fmt = ' ';
+ }
+ fmt++;
+ }
+}
+
+/*
+ * Open a file and read lines, feeding each line to a line parser. Arrange
+ * for keeping a temporary list of wrappers at the end, if the "temp"
+ * argument is set.
+ */
+void
+wrap_add_file (const char *file, int temp)
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t line_allocated = 0;
+
+ wrap_restore_saved ();
+ wrap_kill_temp ();
+
+ /* Load the file. */
+ fp = CVS_FOPEN (file, "r");
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", file);
+ return;
+ }
+ while (getline (&line, &line_allocated, fp) >= 0)
+ wrap_add (line, temp);
+ if (line)
+ free (line);
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", file);
+ if (fclose (fp) == EOF)
+ error (0, errno, "cannot close %s", file);
+}
+
+void
+wrap_kill(void)
+{
+ wrap_kill_temp();
+ while(wrap_count)
+ wrap_free_entry(wrap_list[--wrap_count]);
+}
+
+void
+wrap_kill_temp(void)
+{
+ WrapperEntry **temps=wrap_list+wrap_count;
+
+ while(wrap_tempcount)
+ wrap_free_entry(temps[--wrap_tempcount]);
+}
+
+void
+wrap_free_entry(WrapperEntry *e)
+{
+ wrap_free_entry_internal(e);
+ free(e);
+}
+
+void
+wrap_free_entry_internal(WrapperEntry *e)
+{
+ free (e->wildCard);
+ if (e->tocvsFilter)
+ free (e->tocvsFilter);
+ if (e->fromcvsFilter)
+ free (e->fromcvsFilter);
+ if (e->rcsOption)
+ free (e->rcsOption);
+}
+
+void
+wrap_restore_saved(void)
+{
+ if(!wrap_saved_list)
+ return;
+
+ wrap_kill();
+
+ free(wrap_list);
+
+ wrap_list=wrap_saved_list;
+ wrap_count=wrap_saved_count;
+ wrap_tempcount=wrap_saved_tempcount;
+
+ wrap_saved_list=NULL;
+ wrap_saved_count=0;
+ wrap_saved_tempcount=0;
+}
+
+void
+wrap_add (char *line, int isTemp)
+{
+ char *temp;
+ char ctemp;
+ WrapperEntry e;
+ char opt;
+
+ if (!line || line[0] == '#')
+ return;
+
+ memset (&e, 0, sizeof(e));
+
+ /* Search for the wild card */
+ while (*line && isspace ((unsigned char) *line))
+ ++line;
+ for (temp = line;
+ *line && !isspace ((unsigned char) *line);
+ ++line)
+ ;
+ if(temp==line)
+ return;
+
+ ctemp=*line;
+ *line='\0';
+
+ e.wildCard=xstrdup(temp);
+ *line=ctemp;
+
+ while(*line){
+ /* Search for the option */
+ while(*line && *line!='-')
+ ++line;
+ if(!*line)
+ break;
+ ++line;
+ if(!*line)
+ break;
+ opt=*line;
+
+ /* Search for the filter commandline */
+ for(++line;*line && *line!='\'';++line);
+ if(!*line)
+ break;
+
+ for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line)
+ ;
+
+ /* This used to "break;" (ignore the option) if there was a
+ single character between the single quotes (I'm guessing
+ that was accidental). Now it "break;"s if there are no
+ characters. I'm not sure either behavior is particularly
+ necessary--the current options might not require ''
+ arguments, but surely some future option legitimately
+ might. Also I'm not sure that ignoring the option is a
+ swift way to handle syntax errors in general. */
+ if (line==temp)
+ break;
+
+ ctemp=*line;
+ *line='\0';
+ switch(opt){
+ case 'f':
+ /* Before this is reenabled, need to address the problem in
+ commit.c (see
+ <http://ximbiot.com/cvs/cvshome/docs/infowrapper.html>). */
+ error (1, 0,
+ "-t/-f wrappers not supported by this version of CVS");
+
+ if(e.fromcvsFilter)
+ free(e.fromcvsFilter);
+ /* FIXME: error message should say where the bad value
+ came from. */
+ e.fromcvsFilter =
+ expand_path (temp, current_parsed_root->directory, false,
+ "<wrapper>", 0);
+ if (!e.fromcvsFilter)
+ error (1, 0, "Correct above errors first");
+ break;
+ case 't':
+ /* Before this is reenabled, need to address the problem in
+ commit.c (see
+ <http://ximbiot.com/cvs/cvshome/docs/infowrapper.html>). */
+ error (1, 0,
+ "-t/-f wrappers not supported by this version of CVS");
+
+ if(e.tocvsFilter)
+ free(e.tocvsFilter);
+ /* FIXME: error message should say where the bad value
+ came from. */
+ e.tocvsFilter = expand_path (temp, current_parsed_root->directory,
+ false, "<wrapper>", 0);
+ if (!e.tocvsFilter)
+ error (1, 0, "Correct above errors first");
+ break;
+ case 'm':
+ if(*temp=='C' || *temp=='c')
+ e.mergeMethod=WRAP_COPY;
+ else
+ e.mergeMethod=WRAP_MERGE;
+ break;
+ case 'k':
+ if (e.rcsOption)
+ free (e.rcsOption);
+ e.rcsOption = strcmp (temp, "kv") ? xstrdup (temp) : NULL;
+ break;
+ default:
+ break;
+ }
+ *line=ctemp;
+ if(!*line)break;
+ ++line;
+ }
+
+ wrap_add_entry(&e, isTemp);
+}
+
+void
+wrap_add_entry (WrapperEntry *e, int temp)
+{
+ int x;
+ if (wrap_count + wrap_tempcount >= wrap_size)
+ {
+ wrap_size += WRAPPER_GROW;
+ wrap_list = xnrealloc (wrap_list, wrap_size, sizeof (WrapperEntry *));
+ }
+
+ if (!temp && wrap_tempcount)
+ {
+ for (x = wrap_count + wrap_tempcount - 1; x >= wrap_count; --x)
+ wrap_list[x + 1] = wrap_list[x];
+ }
+
+ x = (temp ? wrap_count + (wrap_tempcount++) : (wrap_count++));
+ wrap_list[x] = xmalloc (sizeof (WrapperEntry));
+ *wrap_list[x] = *e;
+}
+
+/* Return 1 if the given filename is a wrapper filename */
+int
+wrap_name_has (const char *name, WrapMergeHas has)
+{
+ int x,count=wrap_count+wrap_tempcount;
+ char *temp;
+
+ for(x=0;x<count;++x)
+ if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0){
+ switch(has){
+ case WRAP_TOCVS:
+ temp=wrap_list[x]->tocvsFilter;
+ break;
+ case WRAP_FROMCVS:
+ temp=wrap_list[x]->fromcvsFilter;
+ break;
+ case WRAP_RCSOPTION:
+ temp = wrap_list[x]->rcsOption;
+ break;
+ default:
+ abort ();
+ }
+ if(temp==NULL)
+ return (0);
+ else
+ return (1);
+ }
+ return (0);
+}
+
+static WrapperEntry *wrap_matching_entry (const char *);
+
+static WrapperEntry *
+wrap_matching_entry (const char *name)
+{
+ int x,count=wrap_count+wrap_tempcount;
+
+ for(x=0;x<count;++x)
+ if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0)
+ return wrap_list[x];
+ return NULL;
+}
+
+/* Return the RCS options for FILENAME in a newly malloc'd string. If
+ ASFLAG, then include "-k" at the beginning (e.g. "-kb"), otherwise
+ just give the option itself (e.g. "b"). */
+char *
+wrap_rcsoption (const char *filename, int asflag)
+{
+ WrapperEntry *e = wrap_matching_entry (filename);
+
+ if (e == NULL || e->rcsOption == NULL || (*e->rcsOption == '\0'))
+ return NULL;
+
+ return Xasprintf ("%s%s", asflag ? "-k" : "", e->rcsOption);
+}
+
+char *
+wrap_tocvs_process_file(const char *fileName)
+{
+ WrapperEntry *e=wrap_matching_entry(fileName);
+ static char *buf = NULL;
+ char *args;
+
+ if(e==NULL || e->tocvsFilter==NULL)
+ return NULL;
+
+ if (buf != NULL)
+ free (buf);
+ buf = cvs_temp_name ();
+
+ wrap_clean_fmt_str (e->tocvsFilter, 2);
+ args = Xasprintf (e->tocvsFilter, fileName, buf);
+ run_setup (args);
+ run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL | RUN_REALLY );
+ free (args);
+
+ return buf;
+}
+
+int
+wrap_merge_is_copy (const char *fileName)
+{
+ WrapperEntry *e=wrap_matching_entry(fileName);
+ if(e==NULL || e->mergeMethod==WRAP_MERGE)
+ return 0;
+
+ return 1;
+}
+
+void
+wrap_fromcvs_process_file(const char *fileName)
+{
+ char *args;
+ WrapperEntry *e = wrap_matching_entry(fileName);
+
+ if (e != NULL && e->fromcvsFilter != NULL)
+ {
+ wrap_clean_fmt_str (e->fromcvsFilter, 1);
+ args = Xasprintf (e->fromcvsFilter, fileName);
+ run_setup (args);
+ run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ free (args);
+ }
+ return;
+}
diff --git a/src/zlib.c b/src/zlib.c
new file mode 100644
index 0000000..dd72fcf
--- /dev/null
+++ b/src/zlib.c
@@ -0,0 +1,810 @@
+/* zlib.c --- interface to the zlib compression library
+ Ian Lance Taylor <ian@cygnus.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* The routines in this file are the interface between the CVS
+ client/server support and the zlib compression library. */
+
+#include "cvs.h"
+#include "buffer.h"
+#include "pagealign_alloc.h"
+
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+
+#if HAVE_ZLIB_H
+# include <zlib.h>
+#else
+# include "zlib.h"
+#endif
+
+/* OS/2 doesn't have EIO. FIXME: this whole notion of turning
+ a different error into EIO strikes me as pretty dubious. */
+#if !defined (EIO)
+#define EIO EBADPOS
+#endif
+
+/* The compression interface is built upon the buffer data structure.
+ We provide a buffer type which compresses or decompresses the data
+ which passes through it. An input buffer decompresses the data
+ read from an underlying buffer, and an output buffer compresses the
+ data before writing it to an underlying buffer. */
+
+/* This structure is the closure field of the buffer. */
+
+struct compress_buffer
+{
+ /* The underlying buffer. */
+ struct buffer *buf;
+
+ /* The compression information. */
+ z_stream zstr;
+ int level;
+};
+
+static void compress_error (int, int, z_stream *, const char *);
+static int compress_buffer_input (void *, char *, size_t, size_t, size_t *);
+static int compress_buffer_output (void *, const char *, size_t, size_t *);
+static int compress_buffer_flush (void *);
+static int compress_buffer_block (void *, bool);
+static int compress_buffer_get_fd (void *);
+static int compress_buffer_shutdown_input (struct buffer *);
+static int compress_buffer_shutdown_output (struct buffer *);
+
+/* Report an error from one of the zlib functions. */
+
+static void
+compress_error (int status, int zstatus, z_stream *zstr, const char *msg)
+{
+ int hold_errno;
+ const char *zmsg;
+ char buf[100];
+
+ hold_errno = errno;
+
+ zmsg = zstr->msg;
+ if (zmsg == NULL)
+ {
+ sprintf (buf, "error %d", zstatus);
+ zmsg = buf;
+ }
+
+ error (status,
+ zstatus == Z_ERRNO ? hold_errno : 0,
+ "%s: %s", msg, zmsg);
+}
+
+
+
+/* Create a compression buffer. */
+struct buffer *
+compress_buffer_initialize (struct buffer *buf, int input, int level,
+ void (*memory) (struct buffer *))
+{
+ struct compress_buffer *n;
+ int zstatus;
+
+ n = xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->buf = buf;
+ n->level = level;
+
+ if (input)
+ zstatus = inflateInit (&n->zstr);
+ else
+ zstatus = deflateInit (&n->zstr, level);
+ if (zstatus != Z_OK)
+ compress_error (1, zstatus, &n->zstr, "compression initialization");
+
+ /* There may already be data buffered on BUF. For an output
+ buffer, this is OK, because these routines will just use the
+ buffer routines to append data to the (uncompressed) data
+ already on BUF. An input buffer expects to handle a single
+ buffer_data of buffered input to be uncompressed, so that is OK
+ provided there is only one buffer. At present that is all
+ there ever will be; if this changes, compress_buffer_input must
+ be modified to handle multiple input buffers. */
+ assert (! input || buf->data == NULL || buf->data->next == NULL);
+
+ return buf_initialize (input ? compress_buffer_input : NULL,
+ input ? NULL : compress_buffer_output,
+ input ? NULL : compress_buffer_flush,
+ compress_buffer_block, compress_buffer_get_fd,
+ (input
+ ? compress_buffer_shutdown_input
+ : compress_buffer_shutdown_output),
+ memory,
+ n);
+}
+
+
+
+/* Input data from a compression buffer. */
+static int
+compress_buffer_input (void *closure, char *data, size_t need, size_t size,
+ size_t *got)
+{
+ struct compress_buffer *cb = closure;
+ struct buffer_data *bd;
+
+ assert (cb->buf->input);
+
+ /* We use a single buffer_data structure to buffer up data which
+ the z_stream structure won't use yet. We can safely store this
+ on cb->buf->data, because we never call the buffer routines on
+ cb->buf; we only call the buffer input routine, since that
+ gives us the semantics we want. As noted in
+ compress_buffer_initialize, the buffer_data structure may
+ already exist, and hold data which was already read and
+ buffered before the decompression began. */
+ bd = cb->buf->data;
+ if (bd == NULL)
+ {
+ bd = xmalloc (sizeof (struct buffer_data));
+ if (bd == NULL)
+ return -2;
+ bd->text = pagealign_xalloc (BUFFER_DATA_SIZE);
+ if (bd->text == NULL)
+ {
+ free (bd);
+ return -2;
+ }
+ bd->bufp = bd->text;
+ bd->size = 0;
+ cb->buf->data = bd;
+ }
+
+ cb->zstr.avail_out = size;
+ cb->zstr.next_out = (Bytef *) data;
+
+ while (1)
+ {
+ int zstatus, sofar, status;
+ size_t nread;
+
+ /* First try to inflate any data we already have buffered up.
+ This is useful even if we don't have any buffered data,
+ because there may be data buffered inside the z_stream
+ structure. */
+
+ cb->zstr.avail_in = bd->size;
+ cb->zstr.next_in = (Bytef *) bd->bufp;
+
+ do
+ {
+ zstatus = inflate (&cb->zstr, Z_NO_FLUSH);
+ if (zstatus == Z_STREAM_END)
+ break;
+ if (zstatus != Z_OK && zstatus != Z_BUF_ERROR)
+ {
+ compress_error (0, zstatus, &cb->zstr, "inflate");
+ return EIO;
+ }
+ } while (cb->zstr.avail_in > 0
+ && cb->zstr.avail_out > 0);
+
+ bd->size = cb->zstr.avail_in;
+ bd->bufp = (char *) cb->zstr.next_in;
+
+ sofar = size - cb->zstr.avail_out;
+
+ if (zstatus == Z_STREAM_END)
+ {
+ /* If we read any data, then return it, relying on the fact that
+ * we will get Z_STREAM_END on the next read too.
+ */
+ if (sofar > 0) break;
+
+ /* Otherwise, return EOF. */
+ return -1;
+ }
+
+ /* If we have obtained NEED bytes, then return, unless NEED is
+ zero and we haven't obtained anything at all. If NEED is
+ zero, we will attempt at least one nonblocking read and see if
+ we can inflate anything then. */
+ if (sofar > 0 && sofar >= need)
+ break;
+
+ /* All our buffered data should have been processed at this
+ point. */
+ assert (bd->size == 0);
+
+ /* This will work well in the server, because this call will
+ do an unblocked read and fetch all the available data. In
+ the client, this will read a single byte from the stdio
+ stream, which will cause us to call inflate once per byte.
+ It would be more efficient if we could make a call which
+ would fetch all the available bytes, and at least one byte. */
+
+ status = (*cb->buf->input) (cb->buf->closure, bd->text,
+ need, BUFFER_DATA_SIZE, &nread);
+
+ if (status == -2)
+ /* Don't try to recover from memory allcoation errors. */
+ return status;
+
+ if (status != 0)
+ {
+ /* If we read any data, then return it, relying on the fact that
+ * we will get the same error reading the underlying buffer
+ * on the next read too.
+ */
+ if (sofar > 0) break;
+
+ /* Otherwise, return EOF. */
+ return status;
+ }
+
+ /* If we didn't read anything, then presumably the buffer is
+ in nonblocking mode, and we should just get out now with
+ whatever we've inflated. */
+ if (nread == 0)
+ {
+ assert (need == 0);
+ break;
+ }
+
+ bd->bufp = bd->text;
+ bd->size = nread;
+ }
+
+ *got = size - cb->zstr.avail_out;
+
+ return 0;
+}
+
+
+
+extern int gzip_level;
+
+/* Output data to a compression buffer.
+ *
+ * GLOBALS
+ * gzip_level If GZIP_LEVEL has changed to a value different from
+ * CLOSURE->level, then set the compression level on the
+ * stream to the new value.
+ */
+static int
+compress_buffer_output (void *closure, const char *data, size_t have,
+ size_t *wrote)
+{
+ struct compress_buffer *cb = closure;
+
+ /* This is only used within the while loop below, but allocated here for
+ * efficiency.
+ */
+ static char *buffer = NULL;
+ if (!buffer)
+ buffer = pagealign_xalloc (BUFFER_DATA_SIZE);
+
+ if (cb->level != gzip_level)
+ {
+ cb->level = gzip_level;
+ deflateParams (&cb->zstr, gzip_level, Z_DEFAULT_STRATEGY);
+ }
+
+ cb->zstr.avail_in = have;
+ cb->zstr.next_in = (unsigned char *) data;
+
+ while (cb->zstr.avail_in > 0)
+ {
+ int zstatus;
+
+ cb->zstr.avail_out = BUFFER_DATA_SIZE;
+ cb->zstr.next_out = (unsigned char *) buffer;
+
+ zstatus = deflate (&cb->zstr, Z_NO_FLUSH);
+ if (zstatus != Z_OK)
+ {
+ compress_error (0, zstatus, &cb->zstr, "deflate");
+ return EIO;
+ }
+
+ if (cb->zstr.avail_out != BUFFER_DATA_SIZE)
+ buf_output (cb->buf, buffer,
+ BUFFER_DATA_SIZE - cb->zstr.avail_out);
+ }
+
+ *wrote = have;
+
+ /* We will only be here because buf_send_output was called on the
+ compression buffer. That means that we should now call
+ buf_send_output on the underlying buffer. */
+ return buf_send_output (cb->buf);
+}
+
+
+
+/* Flush a compression buffer. */
+static int
+compress_buffer_flush (void *closure)
+{
+ struct compress_buffer *cb = closure;
+
+ /* This is only used within the while loop below, but allocated here for
+ * efficiency.
+ */
+ static char *buffer = NULL;
+ if (!buffer)
+ buffer = pagealign_xalloc (BUFFER_DATA_SIZE);
+
+ cb->zstr.avail_in = 0;
+ cb->zstr.next_in = NULL;
+
+ while (1)
+ {
+ int zstatus;
+
+ cb->zstr.avail_out = BUFFER_DATA_SIZE;
+ cb->zstr.next_out = (unsigned char *) buffer;
+
+ zstatus = deflate (&cb->zstr, Z_SYNC_FLUSH);
+
+ /* The deflate function will return Z_BUF_ERROR if it can't do
+ anything, which in this case means that all data has been
+ flushed. */
+ if (zstatus == Z_BUF_ERROR)
+ break;
+
+ if (zstatus != Z_OK)
+ {
+ compress_error (0, zstatus, &cb->zstr, "deflate flush");
+ return EIO;
+ }
+
+ if (cb->zstr.avail_out != BUFFER_DATA_SIZE)
+ buf_output (cb->buf, buffer,
+ BUFFER_DATA_SIZE - cb->zstr.avail_out);
+
+ /* If the deflate function did not fill the output buffer,
+ then all data has been flushed. */
+ if (cb->zstr.avail_out > 0)
+ break;
+ }
+
+ /* Now flush the underlying buffer. Note that if the original
+ call to buf_flush passed 1 for the BLOCK argument, then the
+ buffer will already have been set into blocking mode, so we
+ should always pass 0 here. */
+ return buf_flush (cb->buf, 0);
+}
+
+
+
+/* The block routine for a compression buffer. */
+static int
+compress_buffer_block (void *closure, bool block)
+{
+ struct compress_buffer *cb = closure;
+
+ if (block)
+ return set_block (cb->buf);
+ else
+ return set_nonblock (cb->buf);
+}
+
+
+
+/* Return the file descriptor underlying any child buffers. */
+static int
+compress_buffer_get_fd (void *closure)
+{
+ struct compress_buffer *cb = closure;
+ return buf_get_fd (cb->buf);
+}
+
+
+
+/* Shut down an input buffer. */
+static int
+compress_buffer_shutdown_input (struct buffer *buf)
+{
+ struct compress_buffer *cb = buf->closure;
+ int zstatus;
+
+ /* Don't make any attempt to pick up trailing data since we are shutting
+ * down. If the client doesn't know we are shutting down, we might not
+ * see the EOF we are expecting.
+ */
+
+ zstatus = inflateEnd (&cb->zstr);
+ if (zstatus != Z_OK)
+ {
+ compress_error (0, zstatus, &cb->zstr, "inflateEnd");
+ return EIO;
+ }
+
+ return buf_shutdown (cb->buf);
+}
+
+
+
+/* Shut down an output buffer. */
+static int
+compress_buffer_shutdown_output (struct buffer *buf)
+{
+ struct compress_buffer *cb = buf->closure;
+ int zstatus, status;
+
+ /* This is only used within the while loop below, but allocated here for
+ * efficiency.
+ */
+ static char *buffer = NULL;
+ if (!buffer)
+ buffer = pagealign_xalloc (BUFFER_DATA_SIZE);
+
+ do
+ {
+ cb->zstr.avail_out = BUFFER_DATA_SIZE;
+ cb->zstr.next_out = (unsigned char *) buffer;
+
+ zstatus = deflate (&cb->zstr, Z_FINISH);
+ if (zstatus != Z_OK && zstatus != Z_STREAM_END)
+ {
+ compress_error (0, zstatus, &cb->zstr, "deflate finish");
+ return EIO;
+ }
+
+ if (cb->zstr.avail_out != BUFFER_DATA_SIZE)
+ buf_output (cb->buf, buffer,
+ BUFFER_DATA_SIZE - cb->zstr.avail_out);
+ } while (zstatus != Z_STREAM_END);
+
+ zstatus = deflateEnd (&cb->zstr);
+ if (zstatus != Z_OK)
+ {
+ compress_error (0, zstatus, &cb->zstr, "deflateEnd");
+ return EIO;
+ }
+
+ status = buf_flush (cb->buf, 1);
+ if (status != 0)
+ return status;
+
+ return buf_shutdown (cb->buf);
+}
+
+
+
+/* Here is our librarified gzip implementation. It is very minimal
+ but attempts to be RFC1952 compliant. */
+
+/* GZIP ID byte values */
+#define GZIP_ID1 31
+#define GZIP_ID2 139
+
+/* Compression methods */
+#define GZIP_CDEFLATE 8
+
+/* Flags */
+#define GZIP_FTEXT 1
+#define GZIP_FHCRC 2
+#define GZIP_FEXTRA 4
+#define GZIP_FNAME 8
+#define GZIP_FCOMMENT 16
+
+/* BUF should contain SIZE bytes of gzipped data (RFC1952/RFC1951).
+ We are to uncompress the data and write the result to the file
+ descriptor FD. If something goes wrong, give a nonfatal error message
+ mentioning FULLNAME as the name of the file for FD. Return 1 if
+ it is an error we can't recover from. */
+
+int
+gunzip_and_write (int fd, const char *fullname, unsigned char *buf,
+ size_t size)
+{
+ size_t pos;
+ z_stream zstr;
+ int zstatus;
+ unsigned char outbuf[32768];
+ unsigned long crc;
+
+ if (size < 10)
+ {
+ error (0, 0, "gzipped data too small - lacks complete header");
+ return 1;
+ }
+ if (buf[0] != GZIP_ID1 || buf[1] != GZIP_ID2)
+ {
+ error (0, 0, "gzipped data does not start with gzip identification");
+ return 1;
+ }
+ if (buf[2] != GZIP_CDEFLATE)
+ {
+ error (0, 0, "only the deflate compression method is supported");
+ return 1;
+ }
+
+ /* Skip over the fixed header, and then skip any of the variable-length
+ fields. As we skip each field, we keep pos <= size. The checks
+ on positions and lengths are really checks for malformed or
+ incomplete gzip data. */
+ pos = 10;
+ if (buf[3] & GZIP_FEXTRA)
+ {
+ if (pos + 2 >= size)
+ {
+ error (0, 0, "%s lacks proper gzip XLEN field", fullname);
+ return 1;
+ }
+ pos += buf[pos] + (buf[pos + 1] << 8) + 2;
+ if (pos > size)
+ {
+ error (0, 0, "%s lacks proper gzip \"extra field\"", fullname);
+ return 1;
+ }
+
+ }
+ if (buf[3] & GZIP_FNAME)
+ {
+ unsigned char *p = memchr(buf + pos, '\0', size - pos);
+ if (p == NULL)
+ {
+ error (0, 0, "%s has bad gzip filename field", fullname);
+ return 1;
+ }
+ pos = p - buf + 1;
+ }
+ if (buf[3] & GZIP_FCOMMENT)
+ {
+ unsigned char *p = memchr(buf + pos, '\0', size - pos);
+ if (p == NULL)
+ {
+ error (0, 0, "%s has bad gzip comment field", fullname);
+ return 1;
+ }
+ pos = p - buf + 1;
+ }
+ if (buf[3] & GZIP_FHCRC)
+ {
+ pos += 2;
+ if (pos > size)
+ {
+ error (0, 0, "%s has bad gzip CRC16 field", fullname);
+ return 1;
+ }
+ }
+
+ /* There could be no data to decompress - check and short circuit. */
+ if (pos >= size)
+ {
+ error (0, 0, "gzip data incomplete for %s (no data)", fullname);
+ return 1;
+ }
+
+ memset (&zstr, 0, sizeof zstr);
+ /* Passing a negative argument tells zlib not to look for a zlib
+ (RFC1950) header. This is an undocumented feature; I suppose if
+ we wanted to be anal we could synthesize a header instead,
+ but why bother? */
+ zstatus = inflateInit2 (&zstr, -15);
+
+ if (zstatus != Z_OK)
+ compress_error (1, zstatus, &zstr, fullname);
+
+ /* I don't see why we should have to include the 8 byte trailer in
+ avail_in. But I see that zlib/gzio.c does, and it seemed to fix
+ a fairly rare bug in which we'd get a Z_BUF_ERROR for no obvious
+ reason. */
+ zstr.avail_in = size - pos;
+ zstr.next_in = buf + pos;
+
+ crc = crc32 (0, NULL, 0);
+
+ do
+ {
+ zstr.avail_out = sizeof (outbuf);
+ zstr.next_out = outbuf;
+ zstatus = inflate (&zstr, Z_NO_FLUSH);
+ if (zstatus != Z_STREAM_END && zstatus != Z_OK)
+ {
+ compress_error (0, zstatus, &zstr, fullname);
+ return 1;
+ }
+ if (write (fd, outbuf, sizeof (outbuf) - zstr.avail_out) < 0)
+ {
+ error (0, errno, "writing decompressed file %s", fullname);
+ return 1;
+ }
+ crc = crc32 (crc, outbuf, sizeof (outbuf) - zstr.avail_out);
+ } while (zstatus != Z_STREAM_END);
+ zstatus = inflateEnd (&zstr);
+ if (zstatus != Z_OK)
+ compress_error (0, zstatus, &zstr, fullname);
+
+ /* Check that there is still 8 trailer bytes remaining (CRC32
+ and ISIZE). Check total decomp. data, plus header len (pos)
+ against input buffer total size. */
+ pos += zstr.total_in;
+ if (size - pos != 8)
+ {
+ error (0, 0, "gzip data incomplete for %s (no trailer)", fullname);
+ return 1;
+ }
+
+ if (crc != ((unsigned long)buf[pos]
+ + ((unsigned long)buf[pos + 1] << 8)
+ + ((unsigned long)buf[pos + 2] << 16)
+ + ((unsigned long)buf[pos + 3] << 24)))
+ {
+ error (0, 0, "CRC error uncompressing %s", fullname);
+ return 1;
+ }
+
+ if (zstr.total_out != ((unsigned long)buf[pos + 4]
+ + ((unsigned long)buf[pos + 5] << 8)
+ + ((unsigned long)buf[pos + 6] << 16)
+ + ((unsigned long)buf[pos + 7] << 24)))
+ {
+ error (0, 0, "invalid length uncompressing %s", fullname);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Read all of FD and put the gzipped data (RFC1952/RFC1951) into *BUF,
+ replacing previous contents of *BUF. *BUF is xmalloc'd and *SIZE is
+ its allocated size. Put the actual number of bytes of data in
+ *LEN. If something goes wrong, give a nonfatal error mentioning
+ FULLNAME as the name of the file for FD, and return 1 if we can't
+ recover from it). LEVEL is the compression level (1-9). */
+
+int
+read_and_gzip (int fd, const char *fullname, unsigned char **buf, size_t *size,
+ size_t *len, int level)
+{
+ z_stream zstr;
+ int zstatus;
+ unsigned char inbuf[8192];
+ int nread;
+ unsigned long crc;
+
+ if (*size < 1024)
+ {
+ unsigned char *newbuf;
+
+ *size = 1024;
+ newbuf = xrealloc (*buf, *size);
+ if (newbuf == NULL)
+ {
+ error (0, 0, "out of memory");
+ return 1;
+ }
+ *buf = newbuf;
+ }
+ (*buf)[0] = GZIP_ID1;
+ (*buf)[1] = GZIP_ID2;
+ (*buf)[2] = GZIP_CDEFLATE;
+ (*buf)[3] = 0;
+ (*buf)[4] = (*buf)[5] = (*buf)[6] = (*buf)[7] = 0;
+ /* Could set this based on level, but why bother? */
+ (*buf)[8] = 0;
+ (*buf)[9] = 255;
+
+ memset (&zstr, 0, sizeof zstr);
+ zstatus = deflateInit2 (&zstr, level, Z_DEFLATED, -15, 8,
+ Z_DEFAULT_STRATEGY);
+ crc = crc32 (0, NULL, 0);
+ if (zstatus != Z_OK)
+ {
+ compress_error (0, zstatus, &zstr, fullname);
+ return 1;
+ }
+
+ /* Adjust for 10-byte output header (filled in above) */
+ zstr.total_out = 10;
+ zstr.avail_out = *size - 10;
+ zstr.next_out = *buf + 10;
+
+ while (1)
+ {
+ int finish = 0;
+
+ nread = read (fd, inbuf, sizeof inbuf);
+ if (nread < 0)
+ {
+ error (0, errno, "cannot read %s", fullname);
+ return 1;
+ }
+ else if (nread == 0)
+ /* End of file. */
+ finish = 1;
+ crc = crc32 (crc, inbuf, nread);
+ zstr.next_in = inbuf;
+ zstr.avail_in = nread;
+
+ do
+ {
+ /* I don't see this documented anywhere, but deflate seems
+ to tend to dump core sometimes if we pass it Z_FINISH and
+ a small (e.g. 2147 byte) avail_out. So we insist on at
+ least 4096 bytes (that is what zlib/gzio.c uses). */
+
+ if (zstr.avail_out < 4096)
+ {
+ unsigned char *newbuf;
+
+ assert(zstr.avail_out + zstr.total_out == *size);
+ assert(zstr.next_out == *buf + zstr.total_out);
+ *size *= 2;
+ newbuf = xrealloc (*buf, *size);
+ if (newbuf == NULL)
+ {
+ error (0, 0, "out of memory");
+ return 1;
+ }
+ *buf = newbuf;
+ zstr.next_out = *buf + zstr.total_out;
+ zstr.avail_out = *size - zstr.total_out;
+ assert(zstr.avail_out + zstr.total_out == *size);
+ assert(zstr.next_out == *buf + zstr.total_out);
+ }
+
+ zstatus = deflate (&zstr, finish ? Z_FINISH : 0);
+ if (zstatus == Z_STREAM_END)
+ goto done;
+ else if (zstatus != Z_OK)
+ compress_error (0, zstatus, &zstr, fullname);
+ } while (zstr.avail_out == 0);
+ }
+ done:
+ /* Need to add the CRC information (8 bytes)
+ to the end of the gzip'd output.
+ Ensure there is enough space in the output buffer
+ to do so. */
+ if (zstr.avail_out < 8)
+ {
+ unsigned char *newbuf;
+
+ assert(zstr.avail_out + zstr.total_out == *size);
+ assert(zstr.next_out == *buf + zstr.total_out);
+ *size += 8 - zstr.avail_out;
+ newbuf = realloc (*buf, *size);
+ if (newbuf == NULL)
+ {
+ error (0, 0, "out of memory");
+ return 1;
+ }
+ *buf = newbuf;
+ zstr.next_out = *buf + zstr.total_out;
+ zstr.avail_out = *size - zstr.total_out;
+ assert(zstr.avail_out + zstr.total_out == *size);
+ assert(zstr.next_out == *buf + zstr.total_out);
+ }
+ *zstr.next_out++ = (unsigned char)(crc & 0xff);
+ *zstr.next_out++ = (unsigned char)((crc >> 8) & 0xff);
+ *zstr.next_out++ = (unsigned char)((crc >> 16) & 0xff);
+ *zstr.next_out++ = (unsigned char)((crc >> 24) & 0xff);
+
+ *zstr.next_out++ = (unsigned char)(zstr.total_in & 0xff);
+ *zstr.next_out++ = (unsigned char)((zstr.total_in >> 8) & 0xff);
+ *zstr.next_out++ = (unsigned char)((zstr.total_in >> 16) & 0xff);
+ *zstr.next_out++ = (unsigned char)((zstr.total_in >> 24) & 0xff);
+
+ zstr.total_out += 8;
+ zstr.avail_out -= 8;
+ assert(zstr.avail_out + zstr.total_out == *size);
+ assert(zstr.next_out == *buf + zstr.total_out);
+
+ *len = zstr.total_out;
+
+ zstatus = deflateEnd (&zstr);
+ if (zstatus != Z_OK)
+ compress_error (0, zstatus, &zstr, fullname);
+
+ return 0;
+}
+#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
diff --git a/tools/.cvsignore b/tools/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/tools/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/tools/ChangeLog b/tools/ChangeLog
new file mode 100644
index 0000000..c7ee1ee
--- /dev/null
+++ b/tools/ChangeLog
@@ -0,0 +1,142 @@
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notices.
+
+2004-12-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * README: Remove Dr. Pascal Molli's CVS URL from the
+ documentation.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2002-04-17 Derek Price <oberon@umich.edu>
+
+ * README: Replace cyclic.com with cvshome.org.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Update now that pcl-cvs is no longer here.
+ * pcl-cvs: Remove this subdirectory and all its contents.
+ * Makefile.in: Remove references to pcl-cvs directory.
+
+Sat Feb 21 22:02:12 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * Makefile.in (clean): Change "/bin/rm" to "rm".
+
+Wed Jan 8 14:50:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Remove CVSid; we decided to get rid
+ of these some time ago.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Remove "675" paragraph; see ../ChangeLog for rationale.
+
+Fri Aug 16 16:05:56 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in (installdirs): new (empty) target
+
+Sun Apr 14 11:07:43 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * .cvsignore: new file.
+
+ * Makefile.in (subdir): `tools', not `contrib'.
+
+ * Added ChangeLog (this file), and subdir `pcl-cvs'.
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..2a26eb0
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,24 @@
+## Process this file with automake to produce Makefile.in
+# Makefile for GNU CVS auxiliary tools.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+EXTRA_DIST = \
+ README .cvsignore
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/tools/Makefile.in b/tools/Makefile.in
new file mode 100644
index 0000000..59a2a42
--- /dev/null
+++ b/tools/Makefile.in
@@ -0,0 +1,424 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for GNU CVS auxiliary tools.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = tools
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+EXTRA_DIST = \
+ README .cvsignore
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tools/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu tools/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-info-am
+
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tools/README b/tools/README
new file mode 100644
index 0000000..9593c96
--- /dev/null
+++ b/tools/README
@@ -0,0 +1,10 @@
+This subdirectory formerly contained tools that can be used with CVS.
+In particular, it used to contain a copy of pcl-cvs version 1.x.
+Pcl-cvs is an Emacs interface to CVS.
+
+If you are looking for pcl-cvs, we'd suggest pcl-cvs version 2.x, at:
+ ftp://ftp.weird.com/pub/local/
+
+The following CVS site has a page about pcl-cvs:
+ http://ximbiot.com
+It also has much information about CVS tools more generally.
diff --git a/vms/.cvsignore b/vms/.cvsignore
new file mode 100644
index 0000000..14fdc2c
--- /dev/null
+++ b/vms/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+stamp-ch
diff --git a/vms/ChangeLog b/vms/ChangeLog
new file mode 100755
index 0000000..d39f2f5
--- /dev/null
+++ b/vms/ChangeLog
@@ -0,0 +1,472 @@
+2005-09-04 Derek Price <derek@ximbiot.com>
+
+ * config.h.in (HAVE_PUTENV): Remove.
+
+2005-04-08 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Add stamp-ch.
+
+2005-04-07 Derek Price <derek@ximbiot.com>
+
+ * stamp-ch: Remove this file.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (DISTCLEANFILES): Add stamp-ch for removal on distclean.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (open_file): Remove this function.
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Remove obsolete timeb cruft.
+
+2005-02-21 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Undo some changes accidentally imported from 1.11.x.
+
+2005-02-08 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (config.h, stamp-ch): New targets.
+ * config.h.in: New file.
+ (PACKAGE_STRING): Generate automatically.
+ (FOLD_FN_CHAR): Delete this macro...
+ (fncmp, fnfold): ...and these prototypes to pick up default definitions
+ from lib/system.h.
+ * filesubr.c (VMS_filename_classes): Ditto for this global var.
+ (Inspired by report Piet Schuermans <pschuermans@mac.com>.)
+
+ * config.h.in: (inline, SIZE_MAX): Define.
+ (Original patch from Piet Schuermans <pschuermans@mac.com>.)
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Back copyright date off since Makefile.am hasn't changed
+ since 2002.
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notices.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add .cvsignore.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-10-18 Derek Price <derek@ximbiot.com>
+
+ * config.h: Define DEVNULL.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (isabsolute): Remove this function.
+ * config.h (ISABSOLUTE): Define.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-11-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (xresolvepath): New function.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c: s/PROTO/.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h (RSH_DFLT): Default to "rsh".
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-12-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Remove reference to options.h.
+ * startserver.c: Replace reference to options.h with config.h.
+ * options.h: Remove file and move relevant content...
+ * config.h: ...here.
+
+ * Makefile.in: Regenerated.
+
+2002-12-06 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c: Change some calls to malloc to use xmalloc.
+ * filutils.c: Ditto.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2002-12-06 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c: Change some calls to strdup to use xstrdup.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove prototype of STDC exit(). Move definition of
+ NO_SOCKET_TO_FD & include of "vms.h"...
+ * config.h: here.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-09-24 Larry Jones <lawrence.jones@eds.com>
+
+ * options.h: Remove PATCH_PROGRAM.
+
+2002-08-16 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove RELATIVE_REPOS & move CVS_BADROOT...
+ * config.h: ...here.
+
+2002-05-23 Larry Jones <lawrence.jones@eds.com>
+
+ * filesubr.c (strcat_filename_onto_homedir): Make arguments const,
+ move more code here from callers, change all callers.
+
+2002-05-22 Derek Price <oberon@umich.edu>
+
+ * config.h: Remove obsolete definition of NO_SLASH_AFTER_HOMEDIR.
+ * filesubr.c (strcat_filename_onto_homedir): New function.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-07 Derek Price <dprice@collab.net>
+
+ * build_vms.com: Verify.
+ * filesubr.c: Cut/paste 1.11.1 cvs_temp_file, cvs_temp_name from
+ ../src/filesubr.c. Include assert.h so that assert's work.
+ (Patch from Mike Marciniszyn <Mike.Marciniszyn@sanchez.com>.)
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-02-06 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+ Shawn Smith <Shawn_Smith@notes.ymp.gov>
+
+ * filesubr.c: Changes to handle VMS DEC C 5.7 {open,read,close}dir
+ (expand_wild): Handle comma-separated lists of files for VMS 7.2 and
+ DEC C 5.7.
+ * config.h: Changes to handle VMS DEC C 5.7 {open,read,close}dir
+ problems.
+ * ndir.c: ditto
+ * ndir.h: ditto
+
+2001-01-10 Derek Price <derek.price@openavenue.com>
+ Rex Jolliff <Rex_Jolliff@notes.ymp.gov>
+ Shawn Smith <Shawn_Smith@notes.ymp.gov>
+
+ * filesubr.c (expand_wild): rewrote for VMS 7.x. Actually
+ globs vms wildcarded filespecs now.
+ * pwd.h: put the pid_t define in a conditional since it's
+ now typedefed in VMS 7.x
+ * unlink.c: provided correct prototype for unlink based on
+ version of VMS since it changes.
+ * vms.h: put conditional compilation macros around mode_t as
+ it is defined as of VMS 7.x, and fixed prototype of unlink
+ as per above.
+ * ndir.c: undefine function for 7.x+ since it is now defined by system
+ * pipe.c: ditto
+ * pwd.c: ditto
+ * rmdir.c: ditto
+ * waitpid.c: ditto
+ * config.h: various new defines & switches
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * options.h: Make RELATIVE_REPOS the default, as in
+ ../src/options.h.in.
+ Remove CVS_DIFFDATE; removed from CVS on 27 Jun 1996.
+
+1998-05-12 Jim Meyering <meyering@ascend.com>
+
+ * Makefile.in (distclean): New rule to remove Makefile.
+
+1998-04-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * getpass.c: Rewrite to use SYS$QIOW instead of curses. This
+ means we don't need to clear the screen, and also the curses
+ version was sometimes dying with a traceback on VMS 7.1 (I don't
+ know why).
+
+1998-04-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (link_file): Remove; no longer used.
+
+Tue Feb 17 02:29:24 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * filesubr.c (last_component): return the top-level directory when
+ asked about the top-level directory.
+
+Tue Jan 13 13:17:33 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (DIFF, RCSBIN_DFLT): Remove; no longer used.
+
+Sat Dec 27 16:57:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (HAVE_RCS5): Remove; no longer used.
+
+ * config.h (LINES_CRLF_TERMINATED): Remove; no longer used.
+
+Sat Nov 29 22:21:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ See lib/ChangeLog for rationale:
+ * options.h: Remove declaration of getwd
+ * getwd.c: Implement xgetwd not getwd.
+ * stat.c: Call xgetwd not getwd.
+
+Thu Sep 25 15:26:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * misc.c, misc.h (fatal, xmalloc, xrealloc): Remove; nowhere used.
+
+ * ndir.c, ndir.h: Change return type of closedir from void to int.
+
+ * config.h (HAVE_NDIR_H): Define.
+ * vms.h: Add comment about the include of ndir.h.
+ * ndir.h: Protect against multiple inclusion.
+
+Tue, 9 Sep 1997 Jim Kingdon
+
+ * config.h: Define HAVE_VPRINTF.
+
+ * pwd.h, vms.h: Define pid_t and mode_t.
+
+Tue Sep 9 18:53:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * pwd.h, pwd.c: Remove getpwnam per change to expand_path.
+ * config.h: Define GETPWNAM_MISSING.
+
+ * pwd.c (getpwuid): Declare argument as unsigned int not uid_t.
+
+ * config.h (SYSTEM_GETCALLER): Define.
+ * pwd.c (getpwuid, getpwnam): Always return NULL (see comment
+ for rationale).
+ * options.h: Don't define CVS_BADROOT.
+ * pwd.h: Nuke uid_t and related changes.
+
+ * filesubr.c (fnfold): Further expand comment about how to handle
+ filenames like "y.tab.c".
+
+Sun Sep 7 17:38:58 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h (HAVE_STRDUP): Remove; not used anywhere.
+ * misc.h, misc.c: Remove strdup per change to ../configure.in.
+
+Sun Jun 8 23:42:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h (HAVE_MKFIFO): Remove; not used anywhere.
+
+Sun May 11 11:49:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Remove USE_DIRECT_TCP; see ../ChangeLog for rationale.
+
+Wed Mar 12 16:10:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h (HAVE_SETVBUF): Removed; no longer used.
+
+Wed Jan 29 18:27:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (GREP): Remove; no longer used.
+
+Tue Jan 28 18:29:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Remove SIZEOF_INT and SIZEOF_LONG; no longer needed
+ with lib/md5.c changes.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * dir.h, filesubr.c, filutils.c, filutils.h, misc.c, misc.h,
+ ndir.c, pipe.c, pipe.h, waitpid.c: Remove "675" paragraph;
+ see ../ChangeLog for rationale.
+
+Wed Jan 1 22:50:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Reword comment for TMPDIR_DFLT to make it clear that
+ this isn't specific to the pserver server.
+
+Tue Nov 19 17:13:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ndir.c (opendir): Change strip_path to strip_trailing_slashes
+ per corresponding change to src.
+ * stat.c (wrapped_stat): Likewise.
+
+Sat Oct 12 19:36:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vms.h: Don't declare/define mode_t and rmdir; they conflict with
+ declarations in system include files on VAX/VMS 6.2.
+ * pwd.h: #include sys/types.h instead of trying to define uid_t,
+ gid_t and pid_t ourselves.
+
+Tue Oct 8 12:37:45 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * options.h: Remove; no longer used.
+
+Wed Sep 25 15:09:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Define TMPDIR_DFLT to sys$scratch not sys$login.
+
+Tue Sep 24 14:11:30 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Add TMPDIR_DFLT.
+
+ * Makefile.in (DISTFILES): Add getpass.c.
+
+Thu Sep 12 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * config.h: Define ARGV0_NOT_PROGRAM_NAME.
+
+Thu Sep 12 14:56:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h, filesubr.c: Add FOLD_FN_CHAR, VMS_filename_classes,
+ fncmp, and fnfold. This is copied from the NT port except various
+ comments were changed and '/' is not considered the same as '\'.
+
+Wed Sep 11 15:53:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Define NO_SLASH_AFTER_HOME.
+
+ * options.h: Define AUTH_CLIENT_SUPPORT.
+ * build_vms.com: Add getpass.c.
+ * getpass.c: New file.
+
+ * config.h: Define getopt, optind, optopt, optarg, and opterr to
+ avoid name conflicts with system libraries.
+
+ * filesubr.c (expand_wild): Added.
+
+Wed Sep 11 11:12:01 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (DISTFILES): Omit filesubr.c.rej.
+
+Tue Sep 10 19:15:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: New file.
+
+ * config.h (START_SERVER_RETURNS_SOCKET, SEND_NEVER_PARTIAL):
+ Define. This just preserves the behavior the VMS port has had all
+ along.
+
+Mon Aug 26 12:51:52 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (mkdir_if_needed): Added.
+
+Tue May 14 13:38:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (cvs_temp_name): New function.
+
+Tue Mar 19 17:49:16 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * startserver.c (vms_start_server): Added support for
+ CVS_RCMD_PORT (and thus made consistent with WindowsNT and Mac)
+
+Fri Mar 1 00:10:06 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * startserver.c, rcmd.c: Made privileged/non-privileged
+ rsh communication more adaptive. Removed USE_PRIVILEGED_RCMD.
+
+Wed Feb 28 11:08:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove comment about automatic generation from
+ options.h.in.
+
+ * options.h: Remove AUTH_SERVER_SUPPORT; no longer should be
+ defined in options.h.
+
+ * options.h: Remove RM and SORT; no longer used.
+
+ * config.h: Remove C_ALLOCA, CRAY_STACKSEG_END, HAVE_ALLOCA,
+ HAVE_ALLOCA_H, and STACK_DIRECTION to reflect alloca removal.
+
+ * vms.h: Remove DEATH_SUPPORT; it was removed from CVS Feb 9.
+
+ * alloca.c: Removed.
+ * build_vms.com: Remove alloca.
+ * startserver.c (vms_start_server): Use xmalloc/free, not alloca.
+
+Wed Feb 28 03:38:42 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * VMS support files added.
+
diff --git a/vms/Makefile.am b/vms/Makefile.am
new file mode 100644
index 0000000..fc23143
--- /dev/null
+++ b/vms/Makefile.am
@@ -0,0 +1,94 @@
+## Process this file with automake to produce Makefile.in
+
+# *** Under VMS, we use *.COM to build, not
+# *** this makefile. However, we need this file in order for 'make
+# *** dist' to work properly on Unix machines.
+
+# Makefile for GNU CVS VMS distribution.
+#
+# Copyright (C) 1986-2002 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2002 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ Makefile.in \
+ build_vms.com \
+ config.h \
+ config.h.in \
+ dir.h \
+ filesubr.c \
+ filutils.c \
+ filutils.h \
+ getpass.c \
+ getwd.c \
+ misc.c \
+ misc.h \
+ ndir.c \
+ ndir.h \
+ pathnames.h \
+ pc.c \
+ pipe.c \
+ pipe.h \
+ piped_child.c \
+ pwd.c \
+ pwd.h \
+ rcmd.c \
+ readlink.c \
+ rmdir.c \
+ startserver.c \
+ stat.c \
+ unlink.c \
+ utime.c \
+ vms-types.h \
+ vms.h \
+ vmsmunch.c \
+ vmsmunch.h \
+ vmsmunch_private.h \
+ waitpid.c
+
+
+
+## Zero a few variables for Automake so they may be appended to.
+DISTCLEANFILES =
+
+###
+### Maintainer targets
+###
+all-local: config.h
+config.h: stamp-ch
+stamp-ch: config.h.in $(top_srcdir)/configure
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >config.tmp
+ @echo " * config.h.in file." >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * Edit config.h.in instead." >>config.tmp
+ @echo " */" >>config.tmp
+ sed "s/%PACKAGE_VERSION%/$(VERSION)/" <$(srcdir)/config.h.in \
+ >>config.tmp
+ @cmp -s config.tmp $(srcdir)/config.h \
+ || (echo "Updating config.h"; \
+ cp config.tmp $(srcdir)/config.h)
+ -@rm -f config.tmp
+ @cp $(srcdir)/config.h $@
+
+DISTCLEANFILES += stamp-ch
+
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/vms/Makefile.in b/vms/Makefile.in
new file mode 100644
index 0000000..a084153
--- /dev/null
+++ b/vms/Makefile.in
@@ -0,0 +1,486 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# *** Under VMS, we use *.COM to build, not
+# *** this makefile. However, we need this file in order for 'make
+# *** dist' to work properly on Unix machines.
+
+# Makefile for GNU CVS VMS distribution.
+#
+# Copyright (C) 1986-2002 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2002 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = vms
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+EXTRA_DIST = \
+ .cvsignore \
+ ChangeLog \
+ Makefile.in \
+ build_vms.com \
+ config.h \
+ config.h.in \
+ dir.h \
+ filesubr.c \
+ filutils.c \
+ filutils.h \
+ getpass.c \
+ getwd.c \
+ misc.c \
+ misc.h \
+ ndir.c \
+ ndir.h \
+ pathnames.h \
+ pc.c \
+ pipe.c \
+ pipe.h \
+ piped_child.c \
+ pwd.c \
+ pwd.h \
+ rcmd.c \
+ readlink.c \
+ rmdir.c \
+ startserver.c \
+ stat.c \
+ unlink.c \
+ utime.c \
+ vms-types.h \
+ vms.h \
+ vmsmunch.c \
+ vmsmunch.h \
+ vmsmunch_private.h \
+ waitpid.c
+
+DISTCLEANFILES = stamp-ch
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu vms/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu vms/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+ distclean distclean-generic distdir dvi dvi-am html html-am \
+ info info-am install install-am install-data install-data-am \
+ install-exec install-exec-am install-info install-info-am \
+ install-man install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \
+ uninstall-am uninstall-info-am
+
+
+###
+### Maintainer targets
+###
+all-local: config.h
+config.h: stamp-ch
+stamp-ch: config.h.in $(top_srcdir)/configure
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >config.tmp
+ @echo " * config.h.in file." >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * Edit config.h.in instead." >>config.tmp
+ @echo " */" >>config.tmp
+ sed "s/%PACKAGE_VERSION%/$(VERSION)/" <$(srcdir)/config.h.in \
+ >>config.tmp
+ @cmp -s config.tmp $(srcdir)/config.h \
+ || (echo "Updating config.h"; \
+ cp config.tmp $(srcdir)/config.h)
+ -@rm -f config.tmp
+ @cp $(srcdir)/config.h $@
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/vms/build_vms.com b/vms/build_vms.com
new file mode 100755
index 0000000..e584f60
--- /dev/null
+++ b/vms/build_vms.com
@@ -0,0 +1,26 @@
+$ set verify
+$ CC :== CC/DEBUG/NOOPTIMIZE/STANDARD=VAXC/DEFINE=HAVE_CONFIG_H-
+/INCLUDE_DIRECTORY=([-],[-.LIB],[-.SRC],[-.VMS])/PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
+$ CC filesubr.c
+$ CC filutils.c
+$ CC getpass.c
+$ CC getwd.c
+$ CC misc.c
+$ CC ndir.c
+$ CC pipe.c
+$ CC piped_child.c
+$ CC pwd.c
+$ CC rcmd.c
+$ CC readlink.c
+$ CC rmdir.c
+$ CC stat.c
+$ CC startserver.c
+$ CC unlink.c
+$ CC utime.c
+$ CC /NOSTANDARD vmsmunch.c
+$ CC waitpid.c
+$ library/create openvmslib.olb filesubr.obj,-
+filutils.obj,getpass.obj,getwd.obj,misc.obj,ndir.obj,pipe.obj,-
+pwd.obj,rcmd.obj,readlink.obj,rmdir.obj,stat.obj,startserver.obj,-
+unlink.obj,utime.obj,vmsmunch.obj,waitpid.obj
+$ set noverify
diff --git a/vms/config.h b/vms/config.h
new file mode 100755
index 0000000..be2a964
--- /dev/null
+++ b/vms/config.h
@@ -0,0 +1,341 @@
+/* This file is generated via a rule in Makefile.am from the
+ * config.h.in file.
+ *
+ * *** DO NOT EDIT THIS FILE DIRECTLY ***
+ *
+ * Edit config.h.in instead.
+ */
+/* config.h - OpenVMS/AXP specific configuration
+ June 1995 - <benjamin@cyclic.com> */
+
+/* The following macro are defined by running ./configure under UNIX OSs. */
+#define PACKAGE_STRING "Concurrent Versions System (CVS) 1.12.13"
+
+/* We only want to build the client */
+#define CLIENT_SUPPORT 1
+#undef SERVER_SUPPORT
+
+/* Define as the maximum value of type 'size_t', if the system doesn't define
+ it. */
+#define SIZE_MAX SSIZE_MAX
+
+/* Set up for other #if's which follow */
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+
+/* VMS is case insensitive */
+/* #define FOLD_FN_CHAR(c) tolower(c) */
+
+/* Temporary files named "#booger.3.6~" aren't legal under VMS,
+ Define this if you want to use names which are legal for VMS */
+#define USE_VMS_FILENAMES 1
+
+/* What VMS calls /dev/null. */
+#define DEVNULL "NLA0:"
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define if you have <dirent.h>. */
+/* #undef DIRENT */
+
+/* Define if you have <sys/param.h> */
+/* #undef HAVE_SYS_PARAM_H */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#define inline
+#endif
+
+/* Define if you support file names longer than 14 characters. */
+/* #undef HAVE_LONG_FILE_NAMES */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* #define HAVE_SYS_WAIT_H 1 OpenVMS POSIX has it, but VMS does not. */
+#undef POSIX
+
+/* Define if utime(file, NULL) sets file's timestamp to the present. */
+/* #undef HAVE_UTIME_NULL */
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define if you don't have <dirent.h>, but have <ndir.h>. */
+#define HAVE_NDIR_H 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you don't have <dirent.h>, but have <sys/dir.h>. */
+/* #undef SYSDIR */
+
+/* Define if you don't have <dirent.h>, but have <sys/ndir.h>. */
+/* #undef SYSNDIR */
+
+/* Define if your <sys/time.h> declares struct tm. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define if the closedir function returns void instead of int. */
+/* #undef VOID_CLOSEDIR */
+
+/* Define if you have MIT Kerberos version 4 available. */
+/* #undef HAVE_KERBEROS */
+
+/* Define if you have the fchmod function. */
+/* #undef HAVE_FCHMOD */
+
+/* Define if you have the fsync function. */
+/* #undef HAVE_FSYNC */
+
+/* Define if you have the ftime function. */
+/* #undef HAVE_FTIME */
+
+/* Define if you have the ftruncate function. */
+/* #undef HAVE_FTRUNCATE */
+
+/* Define if you have the getpagesize function. */
+/* #undef HAVE_GETPAGESIZE */
+
+/* Define if you have the krb_get_err_text function. */
+/* #undef HAVE_KRB_GET_ERR_TEXT */
+
+/* Define if you have the mkdir function */
+#define HAVE_MKDIR 1
+
+/* Define if you have the rmdir function */
+#define HAVE_RMDIR 1
+
+/* Define if you have the rename function */
+#define HAVE_RENAME 1
+
+/* Define if you have the timezone function. */
+/* #undef HAVE_TIMEZONE */
+
+/* Define if you have the vfork function. */
+#define HAVE_VFORK
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF
+
+/* Define if you have the <errno.h> header file. */
+/* #undef HAVE_ERRNO_H */
+
+/* Define if you have the <fcntl.h> header file. */
+#if __DECC_VER >= 50700000
+# define HAVE_FCNTL_H 1
+#endif
+
+/* Define if you have the <memory.h> header file. */
+/* #undef HAVE_MEMORY_H */
+
+/* Define if you have the <ndbm.h> header file. */
+/* #undef HAVE_NDBM_H */
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to force lib/regex.c to use malloc instead of alloca. */
+#define REGEX_MALLOC 1
+
+/* Define to force lib/regex.c to define re_comp et al. */
+#define _REGEX_RE_COMP 1
+
+/* Define if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define this if your <sys/socket.h> defines select() */
+#define SYS_SOCKET_H_DEFINES_SELECT 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <utime.h> header file. */
+/* #undef HAVE_UTIME_H */
+
+/* Define if you have the nsl library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define if you have the socket library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Under VMS, filenames are case-insensitive. */
+#define FILENAMES_CASE_INSENSITIVE 1
+
+#define RSH_NOT_TRANSPARENT 1
+#define START_SERVER vms_start_server
+#define NO_SOCKET_TO_FD 1
+#define START_SERVER_RETURNS_SOCKET 1
+#define SEND_NEVER_PARTIAL 1
+#define SYSTEM_GETCALLER() getlogin ()
+#define GETPWNAM_MISSING 1
+
+/* Avoid name conflicts with VMS libraries. */
+#define getopt cvs_getopt
+#define optind cvs_optind
+#define optopt cvs_optopt
+#define optarg cvs_optarg
+#define opterr cvs_opterr
+
+/* Avoid open/read/closedir name conflicts with DEC C 5.7 libraries,
+ and fix the problem with readdir() retaining the trailing period. */
+#define CVS_OPENDIR vms_opendir
+#define CVS_READDIR vms_readdir
+#define CVS_CLOSEDIR vms_closedir
+
+/* argv[0] in VMS is the full pathname which would look really ugly in error
+ messages. Even if we stripped out the directory and ".EXE;5", it would
+ still be misleading, as if one has used "OLDCVS :== ...CVS-JULY.EXE",
+ then argv[0] does not contain the name of the command which the user
+ invokes CVS with. If there is a way for VMS to find the latter, that
+ might be worth messing with, but it also seems fine to just always call
+ it "cvs". */
+#define ARGV0_NOT_PROGRAM_NAME
+
+#define CVS_UNLINK vms_unlink
+
+/* There is some pretty unixy code in src/commit.c which tries to
+ prevent people from commiting changes as "root" (which would prevent
+ CVS from making a log entry with the actual user). On VMS, I suppose
+ one could say that SYSTEM is equivalent, but I would think that it
+ actually is not necessary; at least at the VMS sites I've worked at
+ people just used their own accounts (turning privileges on and off
+ as desired). */
+#undef CVS_BADROOT
+
+#define NO_SOCKET_TO_FD 1
+
+/*
+ * The following configuration options used to be defined in options.h.
+ */
+
+/*
+ * For portability and heterogeneity reasons, CVS is shipped by default using
+ * my own text-file version of the ndbm database library in the src/myndbm.c
+ * file. If you want better performance and are not concerned about
+ * heterogeneous hosts accessing your modules file, turn this option off.
+ */
+#ifndef MY_NDBM
+#define MY_NDBM
+#endif
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little
+ need to change this (-T is a better mechanism if you need to use a
+ different directory for temporary files). */
+#ifndef TMPDIR_DFLT
+#define TMPDIR_DFLT "sys$scratch"
+#endif
+
+/*
+ * The default editor to use, if one does not specify the "-e" option to cvs,
+ * or does not have an EDITOR environment variable. I set this to just "vi",
+ * and use the shell to find where "vi" actually is. This allows sites with
+ * /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that your PATH
+ * is reasonable).
+ */
+#ifndef EDITOR_DFLT
+#define EDITOR_DFLT ""
+#endif
+
+/*
+ * The default umask to use when creating or otherwise setting file or
+ * directory permissions in the repository. Must be a value in the
+ * range of 0 through 0777. For example, a value of 002 allows group
+ * rwx access and world rx access; a value of 007 allows group rwx
+ * access but no world access. This value is overridden by the value
+ * of the CVSUMASK environment variable, which is interpreted as an
+ * octal number.
+ */
+#ifndef UMASK_DFLT
+#define UMASK_DFLT 002
+#endif
+
+/*
+ * The cvs admin command is restricted to the members of the group
+ * CVS_ADMIN_GROUP. If this group does not exist, all users are
+ * allowed to run cvs admin. To disable the cvs admin for all users,
+ * create an empty group CVS_ADMIN_GROUP. To disable access control for
+ * cvs admin, comment out the define below.
+ */
+#ifndef CVS_ADMIN_GROUP
+/* #define CVS_ADMIN_GROUP "cvsadmin" */
+#endif
+
+/*
+ * When committing or importing files, you must enter a log message.
+ * Normally, you can do this either via the -m flag on the command line or an
+ * editor will be started for you. If you like to use logging templates (the
+ * rcsinfo file within the $CVSROOT/CVSROOT directory), you might want to
+ * force people to use the editor even if they specify a message with -m.
+ * Enabling FORCE_USE_EDITOR will cause the -m message to be appended to the
+ * temp file when the editor is started.
+ */
+#ifndef FORCE_USE_EDITOR
+/* #define FORCE_USE_EDITOR */
+#endif
+
+/*
+ * Yes, we can do the authenticated client.
+ */
+#define AUTH_CLIENT_SUPPORT 1
+
+/*
+ * If you are working with a large remote repository and a 'cvs checkout' is
+ * swamping your network and memory, define these to enable flow control.
+ * You will end up with even less guarantees of a consistant checkout,
+ * but that may be better than no checkout at all. The master server process
+ * will monitor how far it is getting behind, if it reaches the high water
+ * mark, it will signal the child process to stop generating data when
+ * convenient (ie: no locks are held, currently at the beginning of a
+ * new directory). Once the buffer has drained sufficiently to reach the
+ * low water mark, it will be signalled to start again.
+ * -- EXPERIMENTAL! -- A better solution may be in the works.
+ * You may override the default hi/low watermarks here too.
+ */
+#ifndef SERVER_FLOWCONTROL
+/* #define SERVER_FLOWCONTROL */
+/* #define SERVER_HI_WATER (2 * 1024 * 1024) */
+/* #define SERVER_LO_WATER (1 * 1024 * 1024) */
+#endif
+
+/* End of CVS options.h section */
+
+/* Return non-zero iff FILENAME is absolute.
+ Trivial under Unix, but more complicated under other systems. */
+#define ISABSOLUTE(filename) (filename[0] == '/' || filename[0] == '[' || filename[0] == '<' || strchr(filename, ':'))
+
+#include "vms.h"
diff --git a/vms/config.h.in b/vms/config.h.in
new file mode 100644
index 0000000..1a7df3f
--- /dev/null
+++ b/vms/config.h.in
@@ -0,0 +1,334 @@
+/* config.h - OpenVMS/AXP specific configuration
+ June 1995 - <benjamin@cyclic.com> */
+
+/* The following macro are defined by running ./configure under UNIX OSs. */
+#define PACKAGE_STRING "Concurrent Versions System (CVS) %PACKAGE_VERSION%"
+
+/* We only want to build the client */
+#define CLIENT_SUPPORT 1
+#undef SERVER_SUPPORT
+
+/* Define as the maximum value of type 'size_t', if the system doesn't define
+ it. */
+#define SIZE_MAX SSIZE_MAX
+
+/* Set up for other #if's which follow */
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+
+/* VMS is case insensitive */
+/* #define FOLD_FN_CHAR(c) tolower(c) */
+
+/* Temporary files named "#booger.3.6~" aren't legal under VMS,
+ Define this if you want to use names which are legal for VMS */
+#define USE_VMS_FILENAMES 1
+
+/* What VMS calls /dev/null. */
+#define DEVNULL "NLA0:"
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define if you have <dirent.h>. */
+/* #undef DIRENT */
+
+/* Define if you have <sys/param.h> */
+/* #undef HAVE_SYS_PARAM_H */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#define inline
+#endif
+
+/* Define if you support file names longer than 14 characters. */
+/* #undef HAVE_LONG_FILE_NAMES */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* #define HAVE_SYS_WAIT_H 1 OpenVMS POSIX has it, but VMS does not. */
+#undef POSIX
+
+/* Define if utime(file, NULL) sets file's timestamp to the present. */
+/* #undef HAVE_UTIME_NULL */
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define if you don't have <dirent.h>, but have <ndir.h>. */
+#define HAVE_NDIR_H 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you don't have <dirent.h>, but have <sys/dir.h>. */
+/* #undef SYSDIR */
+
+/* Define if you don't have <dirent.h>, but have <sys/ndir.h>. */
+/* #undef SYSNDIR */
+
+/* Define if your <sys/time.h> declares struct tm. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define if the closedir function returns void instead of int. */
+/* #undef VOID_CLOSEDIR */
+
+/* Define if you have MIT Kerberos version 4 available. */
+/* #undef HAVE_KERBEROS */
+
+/* Define if you have the fchmod function. */
+/* #undef HAVE_FCHMOD */
+
+/* Define if you have the fsync function. */
+/* #undef HAVE_FSYNC */
+
+/* Define if you have the ftime function. */
+/* #undef HAVE_FTIME */
+
+/* Define if you have the ftruncate function. */
+/* #undef HAVE_FTRUNCATE */
+
+/* Define if you have the getpagesize function. */
+/* #undef HAVE_GETPAGESIZE */
+
+/* Define if you have the krb_get_err_text function. */
+/* #undef HAVE_KRB_GET_ERR_TEXT */
+
+/* Define if you have the mkdir function */
+#define HAVE_MKDIR 1
+
+/* Define if you have the rmdir function */
+#define HAVE_RMDIR 1
+
+/* Define if you have the rename function */
+#define HAVE_RENAME 1
+
+/* Define if you have the timezone function. */
+/* #undef HAVE_TIMEZONE */
+
+/* Define if you have the vfork function. */
+#define HAVE_VFORK
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF
+
+/* Define if you have the <errno.h> header file. */
+/* #undef HAVE_ERRNO_H */
+
+/* Define if you have the <fcntl.h> header file. */
+#if __DECC_VER >= 50700000
+# define HAVE_FCNTL_H 1
+#endif
+
+/* Define if you have the <memory.h> header file. */
+/* #undef HAVE_MEMORY_H */
+
+/* Define if you have the <ndbm.h> header file. */
+/* #undef HAVE_NDBM_H */
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to force lib/regex.c to use malloc instead of alloca. */
+#define REGEX_MALLOC 1
+
+/* Define to force lib/regex.c to define re_comp et al. */
+#define _REGEX_RE_COMP 1
+
+/* Define if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define this if your <sys/socket.h> defines select() */
+#define SYS_SOCKET_H_DEFINES_SELECT 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <utime.h> header file. */
+/* #undef HAVE_UTIME_H */
+
+/* Define if you have the nsl library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define if you have the socket library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Under VMS, filenames are case-insensitive. */
+#define FILENAMES_CASE_INSENSITIVE 1
+
+#define RSH_NOT_TRANSPARENT 1
+#define START_SERVER vms_start_server
+#define NO_SOCKET_TO_FD 1
+#define START_SERVER_RETURNS_SOCKET 1
+#define SEND_NEVER_PARTIAL 1
+#define SYSTEM_GETCALLER() getlogin ()
+#define GETPWNAM_MISSING 1
+
+/* Avoid name conflicts with VMS libraries. */
+#define getopt cvs_getopt
+#define optind cvs_optind
+#define optopt cvs_optopt
+#define optarg cvs_optarg
+#define opterr cvs_opterr
+
+/* Avoid open/read/closedir name conflicts with DEC C 5.7 libraries,
+ and fix the problem with readdir() retaining the trailing period. */
+#define CVS_OPENDIR vms_opendir
+#define CVS_READDIR vms_readdir
+#define CVS_CLOSEDIR vms_closedir
+
+/* argv[0] in VMS is the full pathname which would look really ugly in error
+ messages. Even if we stripped out the directory and ".EXE;5", it would
+ still be misleading, as if one has used "OLDCVS :== ...CVS-JULY.EXE",
+ then argv[0] does not contain the name of the command which the user
+ invokes CVS with. If there is a way for VMS to find the latter, that
+ might be worth messing with, but it also seems fine to just always call
+ it "cvs". */
+#define ARGV0_NOT_PROGRAM_NAME
+
+#define CVS_UNLINK vms_unlink
+
+/* There is some pretty unixy code in src/commit.c which tries to
+ prevent people from commiting changes as "root" (which would prevent
+ CVS from making a log entry with the actual user). On VMS, I suppose
+ one could say that SYSTEM is equivalent, but I would think that it
+ actually is not necessary; at least at the VMS sites I've worked at
+ people just used their own accounts (turning privileges on and off
+ as desired). */
+#undef CVS_BADROOT
+
+#define NO_SOCKET_TO_FD 1
+
+/*
+ * The following configuration options used to be defined in options.h.
+ */
+
+/*
+ * For portability and heterogeneity reasons, CVS is shipped by default using
+ * my own text-file version of the ndbm database library in the src/myndbm.c
+ * file. If you want better performance and are not concerned about
+ * heterogeneous hosts accessing your modules file, turn this option off.
+ */
+#ifndef MY_NDBM
+#define MY_NDBM
+#endif
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little
+ need to change this (-T is a better mechanism if you need to use a
+ different directory for temporary files). */
+#ifndef TMPDIR_DFLT
+#define TMPDIR_DFLT "sys$scratch"
+#endif
+
+/*
+ * The default editor to use, if one does not specify the "-e" option to cvs,
+ * or does not have an EDITOR environment variable. I set this to just "vi",
+ * and use the shell to find where "vi" actually is. This allows sites with
+ * /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that your PATH
+ * is reasonable).
+ */
+#ifndef EDITOR_DFLT
+#define EDITOR_DFLT ""
+#endif
+
+/*
+ * The default umask to use when creating or otherwise setting file or
+ * directory permissions in the repository. Must be a value in the
+ * range of 0 through 0777. For example, a value of 002 allows group
+ * rwx access and world rx access; a value of 007 allows group rwx
+ * access but no world access. This value is overridden by the value
+ * of the CVSUMASK environment variable, which is interpreted as an
+ * octal number.
+ */
+#ifndef UMASK_DFLT
+#define UMASK_DFLT 002
+#endif
+
+/*
+ * The cvs admin command is restricted to the members of the group
+ * CVS_ADMIN_GROUP. If this group does not exist, all users are
+ * allowed to run cvs admin. To disable the cvs admin for all users,
+ * create an empty group CVS_ADMIN_GROUP. To disable access control for
+ * cvs admin, comment out the define below.
+ */
+#ifndef CVS_ADMIN_GROUP
+/* #define CVS_ADMIN_GROUP "cvsadmin" */
+#endif
+
+/*
+ * When committing or importing files, you must enter a log message.
+ * Normally, you can do this either via the -m flag on the command line or an
+ * editor will be started for you. If you like to use logging templates (the
+ * rcsinfo file within the $CVSROOT/CVSROOT directory), you might want to
+ * force people to use the editor even if they specify a message with -m.
+ * Enabling FORCE_USE_EDITOR will cause the -m message to be appended to the
+ * temp file when the editor is started.
+ */
+#ifndef FORCE_USE_EDITOR
+/* #define FORCE_USE_EDITOR */
+#endif
+
+/*
+ * Yes, we can do the authenticated client.
+ */
+#define AUTH_CLIENT_SUPPORT 1
+
+/*
+ * If you are working with a large remote repository and a 'cvs checkout' is
+ * swamping your network and memory, define these to enable flow control.
+ * You will end up with even less guarantees of a consistant checkout,
+ * but that may be better than no checkout at all. The master server process
+ * will monitor how far it is getting behind, if it reaches the high water
+ * mark, it will signal the child process to stop generating data when
+ * convenient (ie: no locks are held, currently at the beginning of a
+ * new directory). Once the buffer has drained sufficiently to reach the
+ * low water mark, it will be signalled to start again.
+ * -- EXPERIMENTAL! -- A better solution may be in the works.
+ * You may override the default hi/low watermarks here too.
+ */
+#ifndef SERVER_FLOWCONTROL
+/* #define SERVER_FLOWCONTROL */
+/* #define SERVER_HI_WATER (2 * 1024 * 1024) */
+/* #define SERVER_LO_WATER (1 * 1024 * 1024) */
+#endif
+
+/* End of CVS options.h section */
+
+/* Return non-zero iff FILENAME is absolute.
+ Trivial under Unix, but more complicated under other systems. */
+#define ISABSOLUTE(filename) (filename[0] == '/' || filename[0] == '[' || filename[0] == '<' || strchr(filename, ':'))
+
+#include "vms.h"
diff --git a/vms/dir.h b/vms/dir.h
new file mode 100644
index 0000000..b1fdb0e
--- /dev/null
+++ b/vms/dir.h
@@ -0,0 +1,93 @@
+/* GNU Emacs VMS directory definition file.
+ Copyright (C) 1986 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details. */
+
+/*
+ * Files-11 Ver. 2 directory structure (VMS V4.x - long names)
+ */
+#ifndef DIR$K_LENGTH
+
+#define DIR$C_FID 0
+#define DIR$C_LINKNAME 1
+#define DIR$K_LENGTH 6
+#define DIR$C_LENGTH 6
+#define DIR$S_DIRDEF 6
+#define DIR$W_SIZE 0
+#define DIR$W_VERLIMIT 2
+#define DIR$B_FLAGS 4
+#define DIR$S_TYPE 3
+#define DIR$V_TYPE 0
+#define DIR$V_NEXTREC 6
+#define DIR$V_PREVREC 7
+#define DIR$B_NAMECOUNT 5
+#define DIR$S_NAME 80
+#define DIR$T_NAME 6
+
+#define DIR$K_VERSION 8
+#define DIR$C_VERSION 8
+#define DIR$S_DIRDEF1 8
+#define DIR$W_VERSION 0
+#define DIR$S_FID 6
+#define DIR$W_FID 2
+#define DIR$W_FID_NUM 2
+#define DIR$W_FID_SEQ 4
+#define DIR$W_FID_RVN 6
+#define DIR$B_FID_RVN 6
+#define DIR$B_FID_NMX 7
+
+#define DIR$S_DIRDEF2 1
+#define DIR$T_LINKNAME 0
+
+typedef struct dir$_name {
+/* short dir$w_size; /* if you read with RMS, it eats this... */
+ short dir$w_verlimit; /* maximum number of versions */
+ union {
+ unsigned char dir_b_flags;
+#define dir$b_flags dir__b_flags.dir_b_flags
+ struct {
+ unsigned char dir_v_type: DIR$S_TYPE;
+#define dir$v_type dir__b_flags.dir___b_flags.dir_v_type
+ unsigned char: 3;
+ unsigned char dir_v_nextrec: 1;
+#define dir$v_nextrec dir__b_flags.dir___b_flags.dir_v_nextrec
+ unsigned char dir_v_prevrec: 1;
+#define dir$v_prevrec dir__b_flags.dir___b_flags.dir_v_prevrec
+ } dir___b_flags;
+ } dir__b_flags;
+ unsigned char dir$b_namecount;
+ char dir$t_name[];
+} dir$_dirdef; /* only the fixed first part */
+
+typedef struct dir$_version {
+ short dir$w_version;
+ short dir$w_fid_num;
+ short dir$w_fid_seq;
+ union {
+ short dir_w_fid_rvn;
+#define dir$w_fid_rvn dir__w_fid_rvn.dir_w_fid_rvn
+ struct {
+ char dir_b_fid_rvn;
+#define dir$b_fid_rvn dir__w_fid_rvn.dir___w_fid_rvn.dir_b_fid_rvn
+ char dir_b_fid_nmx;
+#define dir$b_fid_nmx dir__w_fid_rvn.dir___w_fid_rvn.dir_b_fid_nmx
+ } dir___w_fid_rvn;
+ } dir__w_fid_rvn;
+} dir$_dirdef1; /* one for each version of the file */
+
+typedef
+struct dir$_linkname {
+ char dir$t_linkname[];
+} dir$_dirdef2;
+
+#endif
diff --git a/vms/filesubr.c b/vms/filesubr.c
new file mode 100644
index 0000000..a6e02e3
--- /dev/null
+++ b/vms/filesubr.c
@@ -0,0 +1,1161 @@
+/* filesubr.c --- subroutines for dealing with files
+ Gratuitously adapted toward VMS quirks.
+
+ Jim Blandy <jimb@cyclic.com>
+ Benjamin J. Lee <benjamin@cyclic.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+#include <assert.h>
+
+static int deep_remove_dir( const char *path );
+
+/*
+ * Copies "from" to "to".
+ */
+void
+copy_file (from_file, to_file)
+ const char *from_file;
+ const char *to_file;
+{
+ char from[PATH_MAX], to[PATH_MAX];
+ struct stat sb;
+ struct utimbuf t;
+ int fdin, fdout;
+
+ /* Prefer local relative paths to files at expense of logical name
+ access to files. */
+
+ if (isabsolute(from_file))
+ strcpy(from, from_file);
+ else
+ sprintf(from, "./%s", from_file);
+
+ if (isabsolute(to_file))
+ strcpy(to, to_file);
+ else
+ sprintf(to, "./%s", to_file);
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if ((fdin = open (from, O_RDONLY)) < 0)
+ error (1, errno, "cannot open %s for copying", from);
+ if (fstat (fdin, &sb) < 0)
+ error (1, errno, "cannot fstat %s", from);
+ if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
+ error (1, errno, "cannot create %s for copying", to);
+ if (sb.st_size > 0)
+ {
+ char buf[BUFSIZ];
+ int n;
+
+ for (;;)
+ {
+ n = read (fdin, buf, sizeof(buf));
+ if (n == -1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ error (1, errno, "cannot read file %s for copying", from);
+ }
+ else if (n == 0)
+ break;
+
+ if (write(fdout, buf, n) != n) {
+ error (1, errno, "cannot write file %s for copying", to);
+ }
+ }
+
+#ifdef HAVE_FSYNC
+ if (fsync (fdout))
+ error (1, errno, "cannot fsync file %s after copying", to);
+#endif
+ }
+
+ if (close (fdin) < 0)
+ error (0, errno, "cannot close %s", from);
+ if (close (fdout) < 0)
+ error (1, errno, "cannot close %s", to);
+
+ /* now, set the times for the copied file to match those of the original */
+ memset ((char *) &t, 0, sizeof (t));
+ t.actime = sb.st_atime;
+ t.modtime = sb.st_mtime;
+ (void) utime (to, &t);
+}
+
+/* FIXME-krp: these functions would benefit from caching the char * &
+ stat buf. */
+
+/*
+ * Returns non-zero if the argument file is a directory, or is a symbolic
+ * link which points to a directory.
+ */
+int
+isdir (file)
+ const char *file;
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return (0);
+ return (S_ISDIR (sb.st_mode));
+}
+
+/*
+ * Returns non-zero if the argument file is a symbolic link.
+ */
+int
+islink (file)
+ const char *file;
+{
+#ifdef S_ISLNK
+ struct stat sb;
+
+ if (lstat (file, &sb) < 0)
+ return (0);
+ return (S_ISLNK (sb.st_mode));
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Returns non-zero if the argument file exists.
+ */
+int
+isfile (file)
+ const char *file;
+{
+ return isaccessible(file, F_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is readable.
+ */
+int
+isreadable (file)
+ const char *file;
+{
+ return isaccessible(file, R_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is writable.
+ */
+int
+iswritable (file)
+ const char *file;
+{
+ return isaccessible(file, W_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is accessable according to
+ * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
+ * bits set.
+ */
+int
+isaccessible (file, mode)
+ const char *file;
+ const int mode;
+{
+#ifdef SETXID_SUPPORT
+ struct stat sb;
+ int umask = 0;
+ int gmask = 0;
+ int omask = 0;
+ int uid;
+
+ if (stat(file, &sb) == -1)
+ return 0;
+ if (mode == F_OK)
+ return 1;
+
+ uid = geteuid();
+ if (uid == 0) /* superuser */
+ {
+ if (mode & X_OK)
+ return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
+ else
+ return 1;
+ }
+
+ if (mode & R_OK)
+ {
+ umask |= S_IRUSR;
+ gmask |= S_IRGRP;
+ omask |= S_IROTH;
+ }
+ if (mode & W_OK)
+ {
+ umask |= S_IWUSR;
+ gmask |= S_IWGRP;
+ omask |= S_IWOTH;
+ }
+ if (mode & X_OK)
+ {
+ umask |= S_IXUSR;
+ gmask |= S_IXGRP;
+ omask |= S_IXOTH;
+ }
+
+ if (sb.st_uid == uid)
+ return (sb.st_mode & umask) == umask;
+ else if (sb.st_gid == getegid())
+ return (sb.st_mode & gmask) == gmask;
+ else
+ return (sb.st_mode & omask) == omask;
+#else
+ return access(file, mode) == 0;
+#endif
+}
+
+
+
+/*
+ * Make a directory and die if it fails
+ */
+void
+make_directory (name)
+ const char *name;
+{
+ struct stat sb;
+
+ if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
+ error (0, 0, "%s already exists but is not a directory", name);
+ if (!noexec && mkdir (name, 0777) < 0)
+ error (1, errno, "cannot make directory %s", name);
+}
+
+/*
+ * Make a path to the argument directory, printing a message if something
+ * goes wrong.
+ */
+void
+make_directories (name)
+ const char *name;
+{
+ char *cp;
+
+ if (noexec)
+ return;
+
+ if (mkdir (name, 0777) == 0 || errno == EEXIST)
+ return;
+ if (! existence_error (errno))
+ {
+ error (0, errno, "cannot make path to %s", name);
+ return;
+ }
+ if ((cp = strrchr (name, '/')) == NULL)
+ return;
+ *cp = '\0';
+ make_directories (name);
+ *cp++ = '/';
+ if (*cp == '\0')
+ return;
+ (void) mkdir (name, 0777);
+}
+
+/* Create directory NAME if it does not already exist; fatal error for
+ other errors. Returns 0 if directory was created; 1 if it already
+ existed. */
+int
+mkdir_if_needed (name)
+ char *name;
+{
+ if (mkdir (name, 0777) < 0)
+ {
+ if (errno != EEXIST
+#ifdef EACCESS
+ /* This was copied over from the OS/2 code; I would guess it
+ isn't needed here but that has not been verified. */
+ && errno != EACCESS
+#endif
+ )
+ error (1, errno, "cannot make directory %s", name);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Change the mode of a file, either adding write permissions, or removing
+ * all write permissions. Either change honors the current umask setting.
+ */
+void
+xchmod (fname_file, writable)
+ char *fname_file;
+ int writable;
+{
+ char fname[PATH_MAX];
+ struct stat sb;
+ mode_t mode, oumask;
+
+ /* Prefer local relative paths to files at expense of logical name
+ access to files. */
+
+ if (isabsolute(fname_file))
+ strcpy(fname, fname_file);
+ else
+ sprintf(fname, "./%s", fname_file);
+
+ if (stat (fname, &sb) < 0)
+ {
+ if (!noexec)
+ error (0, errno, "cannot stat %s", fname);
+ return;
+ }
+ oumask = umask (0);
+ (void) umask (oumask);
+ if (writable)
+ {
+ mode = sb.st_mode | (~oumask
+ & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
+ | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
+ | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
+ }
+ else
+ {
+ mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
+ }
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
+ (server_active) ? 'S' : ' ', fname, mode);
+#else
+ (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
+#endif
+ if (noexec)
+ return;
+
+ if (chmod (fname, mode) < 0)
+ error (0, errno, "cannot change mode of file %s", fname);
+}
+
+/*
+ * Rename a file and die if it fails
+ */
+void
+rename_file (from_file, to_file)
+ const char *from_file;
+ const char *to_file;
+{
+ char from[PATH_MAX], to[PATH_MAX];
+
+ /* Prefer local relative paths to files at expense of logical name
+ access to files. */
+
+ if (isabsolute(from_file))
+ strcpy(from, from_file);
+ else
+ sprintf(from, "./%s", from_file);
+
+ if (isabsolute(to_file))
+ strcpy(to, to_file);
+ else
+ sprintf(to, "./%s", to_file);
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if (rename (from, to) < 0)
+ error (1, errno, "cannot rename file %s to %s", from, to);
+}
+
+/*
+ * unlink a file, if possible.
+ */
+int
+unlink_file (f_file)
+ const char *f_file;
+{
+ char f[PATH_MAX];
+
+ /* Prefer local relative paths to files at expense of logical name
+ access to files. */
+
+ if (isabsolute(f_file))
+ strcpy(f, f_file);
+ else
+ sprintf(f, "./%s", f_file);
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ return (vms_unlink (f));
+}
+
+/*
+ * Unlink a file or dir, if possible. If it is a directory do a deep
+ * removal of all of the files in the directory. Return -1 on error
+ * (in which case errno is set).
+ */
+int
+unlink_file_dir (f_file)
+ const char *f_file;
+{
+ char f[PATH_MAX];
+
+ /* Prefer local relative paths to files at expense of logical name
+ access to files. */
+
+ if (isabsolute(f_file))
+ strcpy(f, f_file);
+ else
+ sprintf(f, "./%s", f_file);
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ if (vms_unlink (f) != 0)
+ {
+ /* under NEXTSTEP errno is set to return EPERM if
+ * the file is a directory,or if the user is not
+ * allowed to read or write to the file.
+ * [This is probably a bug in the O/S]
+ * other systems will return EISDIR to indicate
+ * that the path is a directory.
+ */
+ if (errno == EISDIR || errno == EPERM)
+ return deep_remove_dir (f);
+ else
+ /* The file wasn't a directory and some other
+ * error occured
+ */
+ return -1;
+ }
+ /* We were able to remove the file from the disk */
+ return 0;
+}
+
+/* Remove a directory and everything it contains. Returns 0 for
+ * success, -1 for failure (in which case errno is set).
+ */
+
+static int
+deep_remove_dir (path)
+ const char *path;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char buf[PATH_MAX];
+
+ if (rmdir (path) != 0 && (errno == ENOTEMPTY || errno == EEXIST))
+ {
+ if ((dirp = CVS_OPENDIR (path)) == NULL)
+ /* If unable to open the directory return
+ * an error
+ */
+ return -1;
+
+ while ((dp = CVS_READDIR (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0)
+ continue;
+
+ sprintf (buf, "%s/%s", path, dp->d_name);
+
+ if (vms_unlink (buf) != 0 )
+ {
+ if (errno == EISDIR || errno == EPERM)
+ {
+ if (deep_remove_dir (buf))
+ {
+ CVS_CLOSEDIR (dirp);
+ return -1;
+ }
+ }
+ else
+ {
+ /* buf isn't a directory, or there are
+ * some sort of permision problems
+ */
+ CVS_CLOSEDIR (dirp);
+ return -1;
+ }
+ }
+ }
+ CVS_CLOSEDIR (dirp);
+ return rmdir (path);
+ }
+
+ /* Was able to remove the directory return 0 */
+ return 0;
+}
+
+/* Read NCHARS bytes from descriptor FD into BUF.
+ Return the number of characters successfully read.
+ The number returned is always NCHARS unless end-of-file or error. */
+static size_t
+block_read (fd, buf, nchars)
+ int fd;
+ char *buf;
+ size_t nchars;
+{
+ char *bp = buf;
+ size_t nread;
+
+ do
+ {
+ nread = read (fd, bp, nchars);
+ if (nread == (size_t)-1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ return (size_t)-1;
+ }
+
+ if (nread == 0)
+ break;
+
+ bp += nread;
+ nchars -= nread;
+ } while (nchars != 0);
+
+ return bp - buf;
+}
+
+
+/*
+ * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
+ */
+int
+xcmp (file1_file, file2_file)
+ const char *file1_file;
+ const char *file2_file;
+{
+ char file1[PATH_MAX], file2[PATH_MAX];
+ char *buf1, *buf2;
+ struct stat sb1, sb2;
+ int fd1, fd2;
+ int ret;
+
+ /* Prefer local relative paths to files at expense of logical name
+ access to files. */
+
+ if (isabsolute(file1_file))
+ strcpy(file1, file1_file);
+ else
+ sprintf(file1, "./%s", file1_file);
+
+ if (isabsolute(file2_file))
+ strcpy(file2, file2_file);
+ else
+ sprintf(file2, "./%s", file2_file);
+
+ if ((fd1 = open (file1, O_RDONLY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file1);
+ if ((fd2 = open (file2, O_RDONLY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file2);
+ if (fstat (fd1, &sb1) < 0)
+ error (1, errno, "cannot fstat %s", file1);
+ if (fstat (fd2, &sb2) < 0)
+ error (1, errno, "cannot fstat %s", file2);
+
+ /* A generic file compare routine might compare st_dev & st_ino here
+ to see if the two files being compared are actually the same file.
+ But that won't happen in CVS, so we won't bother. */
+
+ if (sb1.st_size != sb2.st_size)
+ ret = 1;
+ else if (sb1.st_size == 0)
+ ret = 0;
+ else
+ {
+ /* FIXME: compute the optimal buffer size by computing the least
+ common multiple of the files st_blocks field */
+ size_t buf_size = 8 * 1024;
+ size_t read1;
+ size_t read2;
+
+ buf1 = xmalloc (buf_size);
+ buf2 = xmalloc (buf_size);
+
+ do
+ {
+ read1 = block_read (fd1, buf1, buf_size);
+ if (read1 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file1);
+
+ read2 = block_read (fd2, buf2, buf_size);
+ if (read2 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file2);
+
+ assert (read1 == read2);
+
+ ret = memcmp(buf1, buf2, read1);
+ } while (ret == 0 && read1 == buf_size);
+
+ free (buf1);
+ free (buf2);
+ }
+
+ (void) close (fd1);
+ (void) close (fd2);
+ return (ret);
+}
+
+
+
+/* Like strcmp, but with the appropriate tweaks for file names.
+ Under VMS, filenames are case-insensitive but case-preserving.
+ FIXME: this should compare y.tab.c equal with y_tab.c, at least
+ if fnfold is modified (see below). */
+int
+fncmp (const char *n1, const char *n2)
+{
+ while (*n1 && *n2
+ && (VMS_filename_classes[(unsigned char) *n1]
+ == VMS_filename_classes[(unsigned char) *n2]))
+ n1++, n2++;
+ return (VMS_filename_classes[(unsigned char) *n1]
+ - VMS_filename_classes[(unsigned char) *n2]);
+}
+
+/* Fold characters in FILENAME to their canonical forms. FIXME: this
+ probably should be mapping y.tab.c to y_tab.c but first we have to
+ figure out whether fnfold is the right hook for that functionality
+ (probable answer: yes, but it should not fold case on OS/2, VMS, or
+ NT. You see, fnfold isn't called anywhere, so we can define it to
+ mean whatever makes sense. Of course to solve the VMS y.tab.c
+ problem we'd need to call it where appropriate. It would need to
+ be redocumented as "fold to a form we can create in the filesystem"
+ rather than "canonical form"). The idea is that files we create
+ would get thusly munged, but CVS can cope with their names being
+ different the same way that the NT port copes with it if the user
+ renames a file from "foo" to "FOO".
+
+ Alternately, this kind of handling could/should go into CVS_FOPEN
+ and friends (if we want to do it like the Mac port, anyway). */
+void
+fnfold (char *filename)
+{
+ while (*filename)
+ {
+ *filename = FOLD_FN_CHAR (*filename);
+ filename++;
+ }
+}
+
+/* Generate a unique temporary filename. Returns a pointer to a newly
+ * malloc'd string containing the name. Returns successfully or not at
+ * all.
+ *
+ * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!!
+ *
+ * and yes, I know about the way the rcs commands use temp files. I think
+ * they should be converted too but I don't have time to look into it right
+ * now.
+ */
+char *
+cvs_temp_name ()
+{
+ char *fn;
+ FILE *fp;
+
+ fp = cvs_temp_file (&fn);
+ if (fp == NULL)
+ error (1, errno, "Failed to create temporary file");
+ if (fclose (fp) == EOF)
+ error (0, errno, "Failed to close temporary file %s", fn);
+ return fn;
+}
+
+/* Generate a unique temporary filename and return an open file stream
+ * to the truncated file by that name
+ *
+ * INPUTS
+ * filename where to place the pointer to the newly allocated file
+ * name string
+ *
+ * OUTPUTS
+ * filename dereferenced, will point to the newly allocated file
+ * name string. This value is undefined if the function
+ * returns an error.
+ *
+ * RETURNS
+ * An open file pointer to a read/write mode empty temporary file with the
+ * unique file name or NULL on failure.
+ *
+ * ERRORS
+ * on error, errno will be set to some value either by CVS_FOPEN or
+ * whatever system function is called to generate the temporary file name
+ */
+/* There are at least four functions for generating temporary
+ * filenames. We use mkstemp (BSD 4.3) if possible, else tempnam (SVID 3),
+ * else mktemp (BSD 4.3), and as last resort tmpnam (POSIX). Reason is that
+ * mkstemp, tempnam, and mktemp both allow to specify the directory in which
+ * the temporary file will be created.
+ *
+ * And the _correct_ way to use the deprecated functions probably involves
+ * opening file descriptors using O_EXCL & O_CREAT and even doing the annoying
+ * NFS locking thing, but until I hear of more problems, I'm not going to
+ * bother.
+ */
+FILE *cvs_temp_file (filename)
+ char **filename;
+{
+ char *fn;
+ FILE *fp;
+
+ /* FIXME - I'd like to be returning NULL here in noexec mode, but I think
+ * some of the rcs & diff functions which rely on a temp file run in
+ * noexec mode too.
+ */
+
+ assert (filename != NULL);
+
+#ifdef HAVE_MKSTEMP
+
+ {
+ int fd;
+
+ fn = xmalloc (strlen (Tmpdir) + 11);
+ sprintf (fn, "%s/%s", Tmpdir, "cvsXXXXXX" );
+ fd = mkstemp (fn);
+
+ /* a NULL return will be interpreted by callers as an error and
+ * errno should still be set
+ */
+ if (fd == -1) fp = NULL;
+ else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL)
+ {
+ /* attempt to close and unlink the file since mkstemp returned sucessfully and
+ * we believe it's been created and opened
+ */
+ int save_errno = errno;
+ if (close (fd))
+ error (0, errno, "Failed to close temporary file %s", fn);
+ if (CVS_UNLINK (fn))
+ error (0, errno, "Failed to unlink temporary file %s", fn);
+ errno = save_errno;
+ }
+
+ if (fp == NULL) free (fn);
+ /* mkstemp is defined to open mode 0600 using glibc 2.0.7+ */
+ /* FIXME - configure can probably tell us which version of glibc we are
+ * linking to and not chmod for 2.0.7+
+ */
+ else chmod (fn, 0600);
+
+ }
+
+#elif HAVE_TEMPNAM
+
+ /* tempnam has been deprecated due to under-specification */
+
+ fn = tempnam (Tmpdir, "cvs");
+ if (fn == NULL) fp = NULL;
+ else if ((fp = CVS_FOPEN (fn, "w+")) == NULL) free (fn);
+ else chmod (fn, 0600);
+
+ /* tempnam returns a pointer to a newly malloc'd string, so there's
+ * no need for a xstrdup
+ */
+
+#elif HAVE_MKTEMP
+
+ /* mktemp has been deprecated due to the BSD 4.3 specification specifying
+ * that XXXXXX will be replaced by a PID and a letter, creating only 26
+ * possibilities, a security risk, and a race condition.
+ */
+
+ {
+ char *ifn;
+
+ ifn = xmalloc (strlen (Tmpdir) + 11);
+ sprintf (ifn, "%s/%s", Tmpdir, "cvsXXXXXX" );
+ fn = mktemp (ifn);
+
+ if (fn == NULL) fp = NULL;
+ else fp = CVS_FOPEN (fn, "w+");
+
+ if (fp == NULL) free (ifn);
+ else chmod (fn, 0600);
+
+ }
+
+#else /* use tmpnam if all else fails */
+
+ /* tmpnam is deprecated */
+
+ {
+ char ifn[L_tmpnam + 1];
+
+ fn = tmpnam (ifn);
+
+ if (fn == NULL) fp = NULL;
+ else if ((fp = CVS_FOPEN (ifn, "w+")) != NULL)
+ {
+ fn = xstrdup (ifn);
+ chmod (fn, 0600);
+ }
+
+ }
+
+#endif
+
+ *filename = fn;
+ return fp;
+}
+
+
+
+/* char *
+ * xresolvepath ( const char *path )
+ *
+ * Like xreadlink(), but resolve all links in a path.
+ *
+ * INPUTS
+ * path The original path.
+ *
+ * RETURNS
+ * The path with any symbolic links expanded.
+ *
+ * ERRORS
+ * This function exits with a fatal error if it fails to read the link for
+ * any reason.
+ */
+char *
+xresolvepath ( path )
+ const char *path;
+{
+ char *hardpath;
+ char *owd;
+
+ assert ( isdir ( path ) );
+
+ /* FIXME - If HAVE_READLINK is defined, we should probably walk the path
+ * bit by bit calling xreadlink().
+ */
+
+ owd = xgetwd();
+ if ( CVS_CHDIR ( path ) < 0)
+ error ( 1, errno, "cannot chdir to %s", path );
+ if ( ( hardpath = xgetwd() ) == NULL )
+ error (1, errno, "cannot readlink %s", hardpath);
+ if ( CVS_CHDIR ( owd ) < 0)
+ error ( 1, errno, "cannot chdir to %s", owd );
+ free (owd);
+ return hardpath;
+}
+
+/* Return a pointer into PATH's last component. */
+char *
+last_component (path)
+ char *path;
+{
+ char *last = strrchr (path, '/');
+
+ if (last && (last != path))
+ return last + 1;
+ else
+ return path;
+}
+
+/* Return the home directory. Returns a pointer to storage
+ managed by this function or its callees (currently getenv). */
+char *
+get_homedir ()
+{
+ return getenv ("HOME");
+}
+
+/* Compose a path to a file in the home directory. This is different than
+ * the UNIX version since, on VMS, foo:[bar]/.cvspass is not
+ * a legal filename but foo:[bar].cvspass is.
+ *
+ * A more clean solution would be something more along the lines of a
+ * "join a directory to a filename" kind of thing which was not specific to
+ * the homedir. This should aid portability between UNIX, Mac, Windows, VMS,
+ * and possibly others. This is already handled by Perl - it might be
+ * interesting to see how much of the code was written in C since Perl is under
+ * the GPL and the Artistic license - we might be able to use it.
+ */
+char *
+strcat_filename_onto_homedir (dir, file)
+ const char *dir;
+ const char *file;
+{
+ char *path = xmalloc (strlen (dir) + strlen(file) + 1);
+ sprintf (path, "%s%s", dir, file);
+ return path;
+}
+
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+
+#if __VMS_VER < 70200000 || __DECC_VER < 50700000
+/* See cvs.h for description. On VMS this currently does nothing, although
+ I think we should be expanding wildcards here. */
+void
+expand_wild (argc, argv, pargc, pargv)
+ int argc;
+ char **argv;
+ int *pargc;
+ char ***pargv;
+{
+ int i;
+ *pargc = argc;
+ *pargv = (char **) xmalloc (argc * sizeof (char *));
+ for (i = 0; i < argc; ++i)
+ (*pargv)[i] = xstrdup (argv[i]);
+}
+
+#else /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
+
+/* These global variables are necessary to pass information from the
+ * routine that calls decc$from_vms into the callback routine. In a
+ * multi-threaded environment, access to these variables MUST be
+ * serialized.
+ */
+static char CurWorkingDir[PATH_MAX+1];
+static char **ArgvList;
+static int CurArg;
+static int MaxArgs;
+
+static int ew_no_op (char *fname) {
+ (void) fname; /* Shut the compiler up */
+ return 1; /* Continue */
+}
+
+static int ew_add_file (char *fname) {
+ char *lastslash, *firstper;
+ int i;
+
+ if (strncmp(fname,CurWorkingDir,strlen(CurWorkingDir)) == 0) {
+ fname += strlen(CurWorkingDir);
+ }
+ lastslash = strrchr(fname,'/');
+ if (!lastslash) {
+ lastslash = fname;
+ }
+ if ((firstper=strchr(lastslash,'.')) != strrchr(lastslash,'.')) {
+ /* We have two periods -- one is to separate the version off */
+ *strrchr(fname,'.') = '\0';
+ }
+ if (firstper && firstper[1]=='\0') {
+ *firstper = '\0';
+ }
+ /* The following code is to insure that no duplicates appear,
+ * because most of the time it will just be a different version
+ */
+ for (i=0; i<CurArg && strcmp(ArgvList[i],fname)!=0; ++i) {
+ ;
+ }
+ if (i==CurArg && CurArg<MaxArgs) {
+ ArgvList[CurArg++] = xstrdup(fname);
+ }
+ return ArgvList[CurArg-1] != 0; /* Stop if we couldn't dup the string */
+}
+
+/* The following two routines are meant to allow future versions of new_arglist
+ * routine to be multi-thread-safe. It will be necessary in that environment
+ * to serialize access to CurWorkingDir, ArgvList, MaxArg, and CurArg. We
+ * currently don't do any multi-threaded programming, so right now these
+ * routines are no-ops.
+ */
+static void wait_and_protect_globs (void) {
+ return;
+}
+
+static void release_globs (void) {
+ return;
+}
+
+/*pf---------------------------------------------------------------- expand_wild
+ *
+ * New Argument List - (SDS)
+ *
+ * DESCRIPTION:
+ * This routine takes the argc, argv passed in from main() and returns a
+ * new argc, argv list, which simulates (to an extent) Unix-Style filename
+ * globbing with VMS wildcards. The key difference is that it will return
+ * Unix-style filenames, i.e., no VMS file version numbers. The complexity
+ * comes from the desire to not simply allocate 10000 argv entries.
+ *
+ * INPUTS:
+ * argc - The integer argc passed into main
+ * argv - The pointer to the array of char*'s passed into main
+ *
+ * OUTPUTS:
+ * pargv - A pointer to a (char **) to hold the new argv list
+ * pargc - A pointer to an int to hold the new argc
+ *
+ * RETURNS:
+ * NONE
+ *
+ * SIDE EFFECTS:
+ * This routine will normally modify the global statics CurArg, MaxArg,
+ * ArgvList, and CurWorkingDir.
+ *
+ * NOTES:
+ * It is ok for &argc == pargc and &argv == pargv.
+ *
+ *------------------------------------------------------------------------------
+ */
+void expand_wild (int argc, char **argv, int *pargc, char ***pargv) {
+ int totfiles, filesgotten;
+ int i;
+ int largc;
+ char **largv;
+
+ /* This first loop is to find out AT MOST how big to make the
+ * pargv array.
+ */
+ for (totfiles=0,i=0; i<argc; ++i) {
+ char *arg = argv[i];
+
+ if (arg != 0 && ( strchr(arg,' ') != 0
+ || strcmp(arg,".") == 0
+ || strcmp(arg,"..") == 0) ) {
+ ++totfiles;
+ }else if (arg != 0) {
+ int num;
+ char *p = arg;
+ /* Handle comma-separated filelists */
+ while ( (p=strchr(p,',')) != 0) {
+ *p = '\0';
+ num = decc$from_vms (arg, ew_no_op, 1);
+ totfiles += num>0 ? num : 1;
+ *p++ = ',';
+ arg = p;
+ }
+ if (*arg != '\0') {
+ num = decc$from_vms (arg, ew_no_op, 1);
+ totfiles += num>0 ? num : 1;
+ }
+ }
+ }
+ largv = 0;
+ if (totfiles) {
+ largv = xmalloc (sizeof*largv * (totfiles + 1));
+ }
+ filesgotten = 0;
+ if (largv != 0) {
+ int len;
+ /* All bits set to zero may not be a NULL ptr */
+ for (i=totfiles; --i>=0; ) {
+ largv[i] = 0;
+ }
+ largv[totfiles] = 0;
+
+ wait_and_protect_globs ();
+
+ /*--- getcwd has an OpenVMS extension that allows us to ---*/
+ /*--- get back Unix-style path names ---*/
+ (void) getcwd (CurWorkingDir, sizeof CurWorkingDir - 1, 0);
+ len = strlen (CurWorkingDir);
+ if ( len > 0 && CurWorkingDir[len-1] != '/') {
+ (void) strcat (CurWorkingDir, "/");
+ }
+ CurArg = 0;
+ ArgvList = largv;
+ MaxArgs = totfiles + 1;
+
+ for (i=0; i<argc; ++i) {
+ char *arg = argv[i];
+
+ if (arg != 0 && ( strchr(arg,' ') != 0
+ || strcmp(arg,".") == 0
+ || strcmp(arg,"..") == 0) ) {
+ if (CurArg < MaxArgs) {
+ ArgvList[CurArg++] = xstrdup(arg);
+ }
+ ++filesgotten;
+ }else if (arg != 0) {
+ char *p = arg;
+ int num;
+ /* Handle comma-separated filelists */
+ while ( (p=strchr(p,',')) != 0) {
+ *p = '\0';
+ num = decc$from_vms (arg, ew_add_file, 1);
+ if (num <= 0 && CurArg < MaxArgs) {
+ ArgvList[CurArg++] = xstrdup(arg);
+ }
+ filesgotten += num>0 ? num : 1;
+ *p++ = ',';
+ arg = p;
+ }
+ if (*arg != '\0') {
+ num = decc$from_vms (arg, ew_add_file, 1);
+ if (num <= 0 && CurArg < MaxArgs) {
+ ArgvList[CurArg++] = xstrdup(arg);
+ }
+ filesgotten += num>0 ? num : 1;
+ }
+ }
+ }
+ if (filesgotten != totfiles) {
+ /*--- Files must have been created/deleted here ---*/;
+ }
+ filesgotten = CurArg;
+
+ release_globs();
+ }
+ if (!largv) {
+ (*pargv) = xmalloc (sizeof(char *));
+ if ((*pargv) != 0) {
+ *(*pargv) = 0;
+ }
+ }else {
+ (*pargv) = largv;
+ }
+ (*pargc) = largv ? filesgotten : 0;
+
+ return;
+}
+
+#endif /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
diff --git a/vms/filutils.c b/vms/filutils.c
new file mode 100644
index 0000000..8cae5f7
--- /dev/null
+++ b/vms/filutils.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright © 1994 the Free Software Foundation, Inc.
+ *
+ * Author: Richard Levitte (levitte@e.kth.se)
+ *
+ * This file is a part of GNU VMSLIB, the GNU library for porting GNU
+ * software to VMS.
+ *
+ * GNU VMSLIB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU VMSLIB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <string.h>
+#include <file.h>
+#include <rmsdef.h>
+#include <fab.h>
+#include <nam.h>
+#include <stdlib.h>
+#include <lib$routines.h>
+#include <descrip.h>
+#include "filutils.h"
+
+/* file_name_as_directory was snarfed from src/fileio.c in GNU Emacs. */
+
+char *
+file_name_as_directory (out, in)
+ char *out, *in;
+{
+ int size = strlen (in) - 1;
+ int ext_point = 0;
+
+ strcpy (out, in);
+
+ /* Is it already a directory string? */
+ if (in[size] == ':' || in[size] == ']' || in[size] == '>')
+ return out;
+ /* Is it a VMS directory file name? If so, hack VMS syntax. */
+ else
+ if (! strchr (in, '/'))
+ {
+ ext_point = 1;
+ if (size > 3 && (! strcmp (&in[size - 3], ".DIR")
+ || ! strcmp (&in[size - 3], ".dir")))
+ ext_point = -3;
+ else
+ if (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
+ || ! strncmp (&in[size - 5], ".dir", 4))
+ && (in[size - 1] == '.' || in[size - 1] == ';')
+ && in[size] == '1')
+ ext_point = -5;
+ }
+ if (ext_point != 0)
+ {
+ register char *p, *dot;
+ char brack;
+
+ /* dir:[000000]x.dir --> dir:x.dir --> dir:[x]
+ dir:[000000.x]y.dir --> dir:[x]y.dir --> dir:[x.y]
+ but dir:[000000.000000]x.dir --> dir:[000000.000000.x]
+ dir:[000000.000000.x]y.dir --> dir:[000000.000000.x.y] */
+ static char tem[256];
+
+ p = dot = strchr(in,':');
+ if (p != 0 && (p[1] == '[' || p[1] == '<'))
+ {
+ p += 2;
+ if (strncmp(p,"000000",6) == 0)
+ {
+ p += 6;
+ if (strncmp(p,".000000",7) != 0
+ && (*p == ']' || *p == '>' || *p == '.'))
+ {
+ size = dot - in + 1;
+ strncpy(tem, in, size);
+ if (*p == '.')
+ tem[size++] = '[';
+ strcpy(tem + size, p + 1);
+ in = tem;
+ size = strlen(in) - 1;
+ }
+ }
+ }
+ /* x.dir -> [.x]
+ dir:x.dir --> dir:[x]
+ dir:[x]y.dir --> dir:[x.y] */
+ p = in + size;
+ while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
+ {
+ char *emergency_dir = 0;
+ int emergency_point = 0; /* relative to the end of `out' */
+
+ if (p != in)
+ {
+ strncpy (out, in, p - in);
+ out[p - in] = '\0';
+ if (*p == ':')
+ {
+ brack = ']';
+ strcat (out, ":[");
+ emergency_dir = "000000";
+ emergency_point = 0;
+ }
+ else
+ {
+ brack = *p;
+ strcat (out, ".");
+ emergency_dir = "";
+ emergency_point = -1;
+ }
+ p++;
+ }
+ else
+ {
+ brack = ']';
+ strcpy (out, "[.");
+ emergency_dir = "";
+ emergency_point = -2;
+ }
+ if (strncmp (p, "000000.", 7) == 0
+ && (strncmp (p+7, "000000", 6) != 0
+ || (p[13] != ']' && p[13] != '>' && p[13] != '.')))
+ p += 7;
+ if (p < (in + size + ext_point))
+ {
+ register copy_len = ((in + size + ext_point) - p);
+ size = strlen (out) + copy_len;
+ strncat (out, p, copy_len);
+ }
+ else
+ {
+ size = strlen (out) + emergency_point;
+ strcpy (out + size, emergency_dir);
+ size += strlen (emergency_dir);
+ }
+ }
+ out[size++] = brack;
+ out[size] = '\0';
+ }
+ return out;
+}
+
+/*
+ * Convert from directory name to filename.
+ * On VMS:
+ * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
+ * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
+ * On UNIX, it's simple: just make sure there is a terminating /
+
+ * Value is nonzero if the string output is different from the input.
+ */
+
+/* directory_file_name was snarfed from src/fileio.c in GNU Emacs. */
+
+#include <stdio.h>
+directory_file_name (src, dst)
+ char *src, *dst;
+{
+ long slen;
+ long rlen;
+ char * ptr, * rptr;
+ char bracket;
+ struct FAB fab = cc$rms_fab;
+ struct NAM nam = cc$rms_nam;
+ char esa[NAM$C_MAXRSS];
+
+ slen = strlen (src);
+
+ if (! strchr (src, '/')
+ && (src[slen - 1] == ']'
+ || src[slen - 1] == ':'
+ || src[slen - 1] == '>'))
+ {
+ /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
+ fab.fab$l_fna = src;
+ fab.fab$b_fns = slen;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+
+ nam.nam$l_esa = esa;
+ nam.nam$b_ess = sizeof esa;
+ nam.nam$b_nop |= NAM$M_SYNCHK;
+
+ /* We call SYS$PARSE to handle such things as [--] for us. */
+ if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
+ {
+ slen = nam.nam$b_esl;
+ if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
+ slen -= 2;
+ esa[slen] = '\0';
+ src = esa;
+ }
+ if (src[slen - 1] != ']' && src[slen - 1] != '>')
+ {
+ /* what about when we have logical_name:???? */
+ if (src[slen - 1] == ':')
+ { /* Xlate logical name and see what we get */
+ ptr = strcpy (dst, src); /* upper case for getenv */
+ while (*ptr)
+ {
+ if ('a' <= *ptr && *ptr <= 'z')
+ *ptr -= 040;
+ ptr++;
+ }
+ dst[slen - 1] = 0; /* remove colon */
+ if (!(src = getenv (dst)))
+ return 0;
+ /* should we jump to the beginning of this procedure?
+ Good points: allows us to use logical names that xlate
+ to Unix names,
+ Bad points: can be a problem if we just translated to a device
+ name...
+ For now, I'll punt and always expect VMS names, and hope for
+ the best! */
+ slen = strlen (src);
+ if (src[slen - 1] != ']' && src[slen - 1] != '>')
+ { /* no recursion here! */
+ strcpy (dst, src);
+ return 0;
+ }
+ }
+ else
+ { /* not a directory spec */
+ strcpy (dst, src);
+ return 0;
+ }
+ }
+ bracket = src[slen - 1];
+
+ /* If bracket is ']' or '>', bracket - 2 is the corresponding
+ opening bracket. */
+ ptr = strchr (src, bracket - 2);
+ if (ptr == 0)
+ { /* no opening bracket */
+ strcpy (dst, src);
+ return 0;
+ }
+ if (!(rptr = strrchr (src, '.')))
+ rptr = ptr;
+ slen = rptr - src;
+ strncpy (dst, src, slen);
+ dst[slen] = '\0';
+#if 0
+ fprintf (stderr, "dst = \"%s\"\nsrc = \"%s\"\nslen = %d\n",
+ dst, src, slen);
+#endif
+ if (*rptr == '.')
+ {
+ dst[slen++] = bracket;
+ dst[slen] = '\0';
+ }
+ else
+ {
+ /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
+ then translate the device and recurse. */
+ if (dst[slen - 1] == ':'
+ && dst[slen - 2] != ':' /* skip decnet nodes */
+ && ((src[slen] == '['
+ && strcmp(src + slen + 1, "000000]") == 0)
+ || src[slen] == '<'
+ && strcmp(src + slen + 1, "000000>") == 0))
+ {
+ static char equiv_buf[256];
+ static struct dsc$descriptor_s equiv
+ = {sizeof (equiv_buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, equiv_buf};
+ static struct dsc$descriptor_s d_name
+ = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+ short eqlen;
+
+ dst[slen - 1] = '\0';
+ d_name.dsc$w_length = strlen (dst);
+ d_name.dsc$a_pointer = dst;
+ if (LIB$SYS_TRNLOG (&d_name, &eqlen, &equiv) == 1
+ && (equiv_buf[eqlen] = '\0', ptr = equiv_buf) != 0
+ && (rlen = strlen (ptr) - 1) > 0
+ && (ptr[rlen] == ']' || ptr[rlen] == '>')
+ && ptr[rlen - 1] == '.')
+ {
+ char * buf = (char *) xmalloc (strlen (ptr) + 1);
+ int tmp = ptr[rlen];
+ if (buf == 0)
+ return 0; /* bad luck */
+ strcpy (buf, ptr);
+ buf[rlen - 1] = tmp;
+ buf[rlen] = '\0';
+ tmp = directory_file_name (buf, dst);
+ free (buf);
+ return tmp;
+ }
+ else
+ dst[slen - 1] = ':';
+ }
+ strcat (dst, "[000000]");
+ slen += 8;
+ }
+ rptr++;
+ rlen = strlen (rptr) - 1;
+ strncat (dst, rptr, rlen);
+ dst[slen + rlen] = '\0';
+ strcat (dst, ".DIR.1");
+ return 1;
+ }
+
+ /* Process as Unix format: just remove any final slash.
+ But leave "/" unchanged; do not change it to "". */
+ strcpy (dst, src);
+ if (slen > 1 && dst[slen - 1] == '/')
+ {
+ dst[slen - 1] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+/* end of snarf. */
diff --git a/vms/filutils.h b/vms/filutils.h
new file mode 100644
index 0000000..1c484e8
--- /dev/null
+++ b/vms/filutils.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright © 1994 the Free Software Foundation, Inc.
+ *
+ * Author: Richard Levitte (levitte@e.kth.se)
+ *
+ * This file is a part of GNU VMSLIB, the GNU library for porting GNU
+ * software to VMS.
+ *
+ * GNU VMSLIB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU VMSLIB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+char *file_name_as_directory ();
+int directory_file_name ();
diff --git a/vms/getpass.c b/vms/getpass.c
new file mode 100644
index 0000000..75891c1
--- /dev/null
+++ b/vms/getpass.c
@@ -0,0 +1,75 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#undef TEST
+
+#include <stdio.h>
+#include <iodef.h>
+#include <descrip.h>
+#include <starlet.h>
+#include <string.h>
+
+#ifdef TEST
+#include <stdlib.h>
+static void error (int, int, char *);
+#else
+# include "cvs.h"
+#endif
+
+char *
+getpass (char *prompt)
+{
+ int status;
+ unsigned short chan;
+ static $DESCRIPTOR (sys_command, "SYS$COMMAND");
+ unsigned short iosb[4];
+ /* Arbitrary limit. It doesn't seem worth going through multiple
+ SYS$QIOW calls and who knows what to get rid of it, I don't
+ think. */
+ static char buf[2048];
+
+ /* Try to ensure that we avoid stepping on whatever output has
+ been sent to stdout. */
+ printf ("\n");
+ fflush (stdout);
+
+ status = sys$assign (&sys_command, &chan, 0, 0);
+ if (!(status & 1))
+ error (1, 0, "sys$assign failed in getpass");
+ status = sys$qiow (0, chan, IO$_READPROMPT | IO$M_NOECHO, &iosb, 0, 0,
+ buf, sizeof (buf) - 1, 0, 0, prompt, strlen (prompt));
+ if (!(status & 1))
+ error (1, 0, "sys$qiow failed in getpass");
+ if (!(iosb[0] & 1))
+ error (1, 0, "sys$qiow (iosb) failed in getpass");
+ buf[iosb[1]] = '\0';
+ status = sys$dassgn (chan);
+ if (!(status & 1))
+ error (0, 0, "sys$dassgn failed in getpass");
+ /* Since there is no echo, we better go to the next line ourselves. */
+ printf ("\n");
+ return buf;
+}
+
+#ifdef TEST
+int
+main ()
+{
+ printf ("thank you for saying \"%s\"\n", getpass ("What'll it be? "));
+ return 0;
+}
+
+static void error (int x, int y, char *msg)
+{
+ printf ("error: %s\n", msg);
+ if (x)
+ exit (EXIT_FAILURE);
+}
+#endif
diff --git a/vms/getwd.c b/vms/getwd.c
new file mode 100644
index 0000000..7bbdc55
--- /dev/null
+++ b/vms/getwd.c
@@ -0,0 +1,23 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <unixlib.h>
+
+#include "cvs.h"
+
+/* Return the current directory, newly allocated, arbitrarily long.
+ Return NULL and set errno on error. */
+char *
+xgetwd ()
+{
+ char pathname[256];
+
+ return xstrdup (getcwd (pathname, sizeof (pathname) - 2, 0));
+}
diff --git a/vms/misc.c b/vms/misc.c
new file mode 100644
index 0000000..cc564ec
--- /dev/null
+++ b/vms/misc.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright © 1994 the Free Software Foundation, Inc.
+ *
+ * Author: Roland B. Roberts (roberts@nsrl.rochester.edu)
+ *
+ * This file is a part of GNU VMSLIB, the GNU library for porting GNU
+ * software to VMS.
+ *
+ * GNU VMSLIB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU VMSLIB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Miscellaneous utilities used by hackargv().
+ * Some of these are useful in their own right.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <lib$routines.h>
+
+/* See in misc.h why it is done like this. */
+void x_free (void *block)
+{
+ free (block);
+}
+
+/*
+ * Some string utilities.
+ */
+char *downcase (char *s)
+{
+ register char *t;
+ for (t = s ; *t; t++)
+ *t = tolower(*t);
+ return (s);
+}
+
+char *strndup (char *src, int len) {
+ char *dst = (char *) xmalloc (len + 1);
+ strncpy (dst, src, len);
+ dst[len] = 0;
+ return (dst);
+}
+
+#include <string.h>
+
+/*
+ * int fixpath (char *path)
+ *
+ * Synopsis:
+ * `Fix' VMS pathnames, converting them to canonical form.
+ *
+ * Description:
+ * The following conversions are performed
+ * x:[y.][000000.z] --> x:[y.z]
+ * x:[y.][z] --> x:[y.z]
+ * x:[000000.y] --> x:[y]
+ *
+ * Author:
+ * Roland B Roberts (roberts@nsrl.rochester.edu)
+ * March 1994
+ */
+int fixpath (char *path)
+{
+ char *s, *d, *t;
+ int skip = 0;
+ d = s = path;
+ if (t = strstr(path ,".][000000"))
+ skip = 9;
+ else if (t = strstr(path,"]["))
+ skip = 2;
+ else if (t = strstr(path,"[000000."))
+ t++, skip = 7;
+ if (t) {
+ while (s < t)
+ *d++ = *s++;
+ s += skip;
+ while (*d++ = *s++);
+ }
+ return 0;
+}
+
+
+#include <ctype.h>
+#include <string.h>
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/*
+ * char *argvconcat (int argc, char **argv)
+ *
+ * Synopsis:
+ * Concatenate all elements of argv into a single string suitable for
+ * use as a command line.
+ *
+ * Description:
+ * This is intended for use with hackargv() in order to build a command
+ * line for background() or popen(). Each element of argv (except the
+ * first) is surrounded by double quotes to insure the command line is
+ * unaltered when DCL rereads it.
+ *
+ * Side Effect:
+ * Space for the new string is allocated with xmalloc().
+ *
+ * Author:
+ * Roland B Roberts (roberts@nsrl.rochester.edu)
+ * March 1994
+ */
+
+char *argvconcat (int argc, char **argv)
+{
+ int i, j, n, addquotes, flags, pid, status;
+ char *cmdline;
+ /*
+ * Allocate space
+ */
+ for (j = n = 0; j < argc; j++)
+ n += 3 + strlen(argv[j]); /* Need 3 extra spaces, not 1; see below */
+ cmdline = (char *) xmalloc ((n + 1) * sizeof (char));
+ sprintf (cmdline, "%s ", argv[0]);
+ for (j = 1, addquotes = FALSE; j < argc; j++) {
+ /*
+ * Add double quotes to arg if it contains uppercase of spaces.
+ * Hence, the need to allocate three extra spaces for each argument.
+ */
+ for (i = 0; i < strlen(argv[j]); i++)
+ if (isupper(argv[j][i]) || isspace(argv[j][i])) {
+ addquotes = TRUE;
+ break;
+ }
+ if (addquotes) {
+ strcat (cmdline, argv[j]);
+ strcat (cmdline, " ");
+ }
+ else {
+ strcat (cmdline, "\""); /* use quotes to preserve case */
+ strcat (cmdline, argv[j]);
+ strcat (cmdline, "\" ");
+ }
+ }
+ cmdline[strlen(cmdline)-1] = 0;
+ return (cmdline);
+}
diff --git a/vms/misc.h b/vms/misc.h
new file mode 100644
index 0000000..e92596c
--- /dev/null
+++ b/vms/misc.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 1994 the Free Software Foundation, Inc.
+ *
+ * Author: Richard Levitte (levitte@e.kth.se)
+ *
+ * This file is a part of GNU VMSLIB, the GNU library for porting GNU
+ * software to VMS.
+ *
+ * GNU VMSLIB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU VMSLIB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+void x_free();
+/* This is a trick, because the linker wants uppercase symbols, and in
+ that case, xfree is confused with Xfree, which is bad. */
+#define xfree x_free
+
+/*
+ * Some string utilities.
+ */
+char *downcase ();
+char *strndup ();
+
+int fixpath ();
+char *argvconcat ();
diff --git a/vms/ndir.c b/vms/ndir.c
new file mode 100644
index 0000000..1e65186
--- /dev/null
+++ b/vms/ndir.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright © 1994 the Free Software Foundation, Inc.
+ *
+ * Author: Richard Levitte (levitte@e.kth.se)
+ *
+ * This file is a part of GNU VMSLIB, the GNU library for porting GNU
+ * software to VMS.
+ *
+ * GNU VMSLIB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU VMSLIB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+
+#include <varargs.h>
+#include <rms.h>
+#include <descrip.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __GNUC__
+#include <sys/stat.h>
+#else
+#include <stat.h>
+#endif
+#include <lib$routines.h>
+
+#include "ndir.h"
+#include "filutils.h"
+
+/* The following was snarfed from lib-src/alloca.c in GNU Emacs,
+ the hacked. */
+
+#if __STDC__
+typedef void procedure;
+typedef void *pointer;
+#else
+typedef int procedure;
+typedef char *pointer;
+#endif
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc.
+
+ There is some need for BLOCK_INPUT and UNBLOCK_INPUT, but it is really
+ only used in Emacs, so that's the only time it's used. Otherwise,
+ they are just empty statements. */
+
+#ifndef emacs
+#include "misc.h"
+#define malloc xmalloc
+#define free xfree
+#endif
+
+#if 0
+extern pointer malloc ();
+extern procedure free ();
+#endif
+
+/* end of snarf. */
+
+#ifndef BLOCK_INPUT
+#define BLOCK_INPUT
+#endif
+#ifndef UNBLOCK_INPUT
+#define UNBLOCK_INPUT
+#endif
+
+static struct direct *vms_low_readdir ();
+
+typedef struct
+{
+ DIR s_dir;
+ unsigned long context;
+ unsigned long uflags;
+ struct dsc$descriptor_s dir_spec;
+ struct dsc$descriptor_s file_spec;
+ int version_flag;
+ unsigned long status;
+} VMS_DIR;
+
+DIR *
+vms_opendir (infilename, filepattern)
+ char *infilename; /* name of directory */
+ char *filepattern;
+{
+ register VMS_DIR *dirp; /* -> malloc'ed storage */
+ register unsigned int length = 1024;
+ register int fd; /* file descriptor for read */
+ char *filename;
+ struct stat sbuf; /* result of fstat */
+
+ filename = (char *) malloc(length+1);
+ strcpy(filename, infilename);
+
+ strip_trailing_slashes (filename);
+ if(strcmp(filename, ".") == 0)
+ {
+ getcwd(filename, length+1, 1); /* Get a VMS filespec */
+ length = strlen(filename);
+ }
+
+ BLOCK_INPUT;
+ if ((filename[length-1] != ']'
+ && filename[length-1] != '>'
+ && filename[length-1] != ':'
+ && (stat (filename, &sbuf) < 0
+ || (sbuf.st_mode & S_IFMT) != S_IFDIR)))
+ {
+ errno = ENOTDIR;
+ UNBLOCK_INPUT;
+ free(filename);
+ return 0; /* bad luck today */
+ }
+
+ if ((dirp = (VMS_DIR *) xmalloc (sizeof (VMS_DIR))) == 0)
+ {
+ errno = ENOMEM;
+ UNBLOCK_INPUT;
+ free(filename);
+ return 0; /* bad luck today */
+ }
+
+ {
+ int count;
+ va_count(count);
+ if (count == 2)
+ {
+ dirp->file_spec.dsc$a_pointer =
+ (char *) xmalloc (strlen (filepattern) + 1);
+ strcpy (dirp->file_spec.dsc$a_pointer, filepattern);
+ }
+ else
+ {
+ dirp->file_spec.dsc$a_pointer =
+ (char *) xmalloc (4);
+ strcpy (dirp->file_spec.dsc$a_pointer, "*.*");
+ }
+ dirp->file_spec.dsc$w_length = strlen (dirp->file_spec.dsc$a_pointer);
+ dirp->file_spec.dsc$b_dtype = DSC$K_DTYPE_T;
+ dirp->file_spec.dsc$b_class = DSC$K_CLASS_S;
+ dirp->version_flag = strchr (dirp->file_spec.dsc$a_pointer, ';') != 0;
+ }
+ dirp->dir_spec.dsc$a_pointer = (char *) xmalloc (strlen (filename) + 10);
+ UNBLOCK_INPUT;
+ file_name_as_directory (dirp->dir_spec.dsc$a_pointer, filename);
+ dirp->dir_spec.dsc$w_length = strlen (dirp->dir_spec.dsc$a_pointer);
+ dirp->dir_spec.dsc$b_dtype = DSC$K_DTYPE_T;
+ dirp->dir_spec.dsc$b_class = DSC$K_CLASS_S;
+ dirp->context = 0;
+ dirp->uflags = 2;
+ dirp->s_dir.dd_fd = 0;
+ dirp->s_dir.dd_loc = dirp->s_dir.dd_size = 0; /* refill needed */
+
+ free(filename);
+
+ /* In the cases where the filename ended with `]', `>' or `:',
+ we never checked if it really was a directory, so let's do that
+ now, by trying to read the first entry. */
+ if (vms_low_readdir ((DIR *) dirp) == (struct direct *) -1)
+ {
+ vms_closedir (dirp); /* was: xfree (dirp); */
+ errno = ENOENT;
+ return 0;
+ }
+ dirp->s_dir.dd_loc = 0; /* Make sure the entry just read is
+ reused at the next call to readdir. */
+
+ return (DIR *) dirp; /* I had to cast, for VMS sake. */
+}
+
+int
+vms_closedir (dirp)
+ register DIR *dirp; /* stream from vms_opendir */
+{
+ {
+ VMS_DIR *vms_dirp = (VMS_DIR *) dirp;
+
+ if (vms_dirp->context != 0)
+ lib$find_file_end (&(vms_dirp->context));
+ xfree (vms_dirp->dir_spec.dsc$a_pointer);
+ xfree (vms_dirp->file_spec.dsc$a_pointer);
+ }
+
+ xfree ((char *) dirp);
+ return 0;
+}
+
+struct direct dir_static; /* simulated directory contents */
+
+static struct direct *
+vms_low_readdir (dirp)
+ register DIR *dirp;
+{
+ static char rbuf[257];
+ static struct dsc$descriptor_s rdsc =
+ { sizeof (rbuf), DSC$K_DTYPE_T, DSC$K_CLASS_S, rbuf };
+ VMS_DIR * vms_dirp = (VMS_DIR *) dirp;
+
+ if (dirp->dd_size == 0)
+ {
+ char *cp, *cp2;
+ unsigned long status;
+
+ status = lib$find_file (&vms_dirp->file_spec, &rdsc, &vms_dirp->context,
+ &vms_dirp->dir_spec, 0, 0, &vms_dirp->uflags);
+ vms_dirp->status = status;
+ if (status == RMS$_NMF || status == RMS$_FNF)
+ return 0;
+ if (status != RMS$_NORMAL)
+ return (struct direct *) -1;
+
+ rbuf [256] = '\0';
+ if (cp = strchr (rbuf, ' '))
+ *cp = '\0';
+ if ((cp = strchr (rbuf, ';')) != 0
+ && !vms_dirp->version_flag)
+ *cp = '\0';
+
+ for (cp2 = rbuf - 1; cp2 != 0;)
+ {
+ char *cp2tmp = 0;
+ cp = cp2 + 1;
+ cp2 = strchr (cp, ']');
+ if (cp2 != 0)
+ cp2tmp = strchr (cp2 + 1, '>');
+ if (cp2tmp != 0)
+ cp2 = cp2tmp;
+ }
+
+ /* Propagate names as lower case only,
+ directories have ".dir" truncated,
+ do not propagate null extensions "makefile." */
+ {
+ char *p, *q;
+
+ if(strcmp(cp, "CVS.DIR") == 0)
+ strcpy(dirp->dd_buf, "CVS");
+ else
+ {
+ for(p = cp, q = dirp->dd_buf; *p;)
+ {
+ if(strcmp(p, ".DIR") == 0)
+ break;
+ else
+ *q++ = tolower(*p++);
+ }
+ *q = '\0';
+ if(*(q-1) == '.')
+ *(q-1) = '\0';
+ }
+ }
+#if 0
+ strcpy (dirp->dd_buf, cp);
+#endif
+
+ dirp->dd_size = strlen (dirp->dd_buf);
+ dirp->dd_loc = 0;
+ }
+
+ if (vms_dirp->status != RMS$_NORMAL)
+ return 0;
+
+ dir_static.d_ino = -1; /* Couldn't care less... */
+ dir_static.d_namlen = strlen (dirp->dd_buf);
+ dir_static.d_reclen = sizeof (struct direct)
+ - MAXNAMLEN + 3
+ + dir_static.d_namlen - dir_static.d_namlen % 4;
+ strcpy (dir_static.d_name, dirp->dd_buf);
+ dir_static.d_name[dir_static.d_namlen] = '\0';
+ dirp->dd_loc = dirp->dd_size; /* only one record at a time */
+
+ return &dir_static;
+}
+
+/* ARGUSED */
+struct direct *
+vms_readdir (dirp)
+ register DIR *dirp; /* stream from vms_opendir */
+{
+ register struct direct *dp;
+
+ for (; ;)
+ {
+ if (dirp->dd_loc >= dirp->dd_size)
+ dirp->dd_loc = dirp->dd_size = 0;
+
+ dp = vms_low_readdir (dirp);
+ if (dp == 0 || dp == (struct direct *) -1)
+ return 0;
+ return dp;
+ }
+}
diff --git a/vms/ndir.h b/vms/ndir.h
new file mode 100644
index 0000000..b704726
--- /dev/null
+++ b/vms/ndir.h
@@ -0,0 +1,63 @@
+/*
+ <ndir.h> -- definitions for 4.2BSD-compatible directory access
+
+ 28-dec-1994 Richard Levitte
+ See ChangeLog for more recent modification history.
+*/
+
+#ifndef NDIR_H
+
+#if 0
+#ifndef FAB$C_BID
+#include <fab.h>
+#endif
+#endif
+#ifndef NAM$C_BID
+#include <nam.h>
+#endif
+#if 0
+#ifndef RMS$_SUC
+#include <rmsdef.h>
+#endif
+#include <dir.h>
+#else
+#define DIR$S_NAME 80
+#endif
+
+#define DIRBLKSIZ 512 /* size of directory block */
+#ifdef VMS
+#define MAXNAMLEN (DIR$S_NAME + 7) /* 80 plus room for version #. */
+#define MAXFULLSPEC NAM$C_MAXRSS /* Maximum full spec */
+#else
+#define MAXNAMLEN 15 /* maximum filename length */
+#endif /* VMS */
+ /* NOTE: MAXNAMLEN must be one less than a multiple of 4 */
+
+struct direct /* data from readdir() */
+ {
+ long d_ino; /* inode number of entry */
+ unsigned short d_reclen; /* length of this record */
+ unsigned short d_namlen; /* length of string in d_name */
+ char d_name[MAXNAMLEN+1]; /* name of file */
+ };
+
+typedef struct
+ {
+ int dd_fd; /* file descriptor */
+ int dd_loc; /* offset in block */
+ int dd_size; /* amount of valid data */
+ char dd_buf[DIRBLKSIZ]; /* directory block */
+ } DIR; /* stream data from opendir() */
+
+extern DIR *vms_opendir();
+extern struct direct *vms_readdir();
+#ifndef VMS
+extern long telldir();
+extern void seekdir();
+#endif
+extern int vms_closedir();
+
+#define rewinddir( dirp ) seekdir( dirp, 0L )
+
+#define NDIR_H 1
+#endif /* ndir.h */
diff --git a/vms/pathnames.h b/vms/pathnames.h
new file mode 100644
index 0000000..be0f75e
--- /dev/null
+++ b/vms/pathnames.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pathnames.h 5.2 (Berkeley) 4/9/90
+ * $Id: pathnames.h,v 1.1 1996/02/28 08:49:08 benjamin Exp $
+ */
+
+#define _PATH_RLOGIN "/usr/bin/rlogin"
diff --git a/vms/pc.c b/vms/pc.c
new file mode 100644
index 0000000..5868a7f
--- /dev/null
+++ b/vms/pc.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <unixio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int trace = 1;
+
+extern int piped_child();
+extern int piped_child_shutdown();
+
+main (argc, argv)
+ int argc;
+ char ** argv;
+{
+ static char line[512];
+ char *linep[] = {line, NULL};
+ int pid;
+ int tofd, fromfd;
+ FILE *in, *out;
+
+ while (1)
+ {
+ printf("\nEnter a command to run: ");
+ line[0] = '\0';
+ fgets(line, 511, stdin);
+ if (!strlen(line))
+ exit(2);
+
+ line[strlen(line)-1] = '\0';
+ pid = piped_child(linep, &tofd, &fromfd);
+
+ in = fdopen(fromfd, "r");
+ out = fdopen(tofd, "w");
+
+#if 0
+ out = fdopen(tofd, "w");
+ fclose(out);
+#endif
+
+ do
+ {
+ if(!feof(stdin))
+ {
+ fprintf(stdout, "> ");
+ fgets(line, 511, stdin);
+ fputs(line, out);
+ }
+ else
+ {
+ fclose(out);
+ close(tofd);
+ }
+
+ fgets(line, 511, in);
+ fputs(line, stdout);
+ line[0] = '\0';
+ } while (!feof(in));
+
+ fprintf(stderr, "waiting for child to stop\n");
+ piped_child_shutdown(pid);
+ }
+}
diff --git a/vms/pipe.c b/vms/pipe.c
new file mode 100644
index 0000000..ea81a8e
--- /dev/null
+++ b/vms/pipe.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright © 1994 the Free Software Foundation, Inc.
+ *
+ * Author: Roland B. Roberts (roberts@nsrl.rochester.edu)
+ *
+ * This file is a part of GNU VMSLIB, the GNU library for porting GNU
+ * software to VMS.
+ *
+ * GNU VMSLIB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU VMSLIB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Modification History
+ * 13 Sep 94 - RBR
+ * Use event flag one -- zero seems to cause sys$synch to hang.
+ * 12 Sep 94 - RBR
+ * All pipes now use event flag zero.
+ * Removed the limit on the number of pipes.
+ * Added members to PIPE structure and memory corruption tests.
+ */
+
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+
+#if __VMS_VER < 70200000 || __DECC_VER < 50700000
+
+/* This won't work with GCC, but it won't cause any problems either. */
+#define MODULE PIPE
+#define VERSION "V1.5"
+
+#ifdef __DECC
+#pragma module MODULE VERSION
+#else
+#ifdef VAXC
+#module MODULE VERSION
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <syidef.h>
+#include <clidef.h>
+#include <stsdef.h>
+#include <dvidef.h>
+#include <nam.h>
+#include <descrip.h>
+#include <errno.h>
+#include <file.h>
+#include <lib$routines.h>
+#include <starlet.h>
+#include <setjmp.h>
+#include "vms-types.h"
+
+/* A linked list of pipes, for internal use only */
+struct PIPE
+{
+ struct PIPE *next; /* next pipe in the chain */
+ struct PIPE *prev; /* previous pipe in the chain */
+ struct PIPE *self; /* self reference */
+ int mode; /* pipe I/O mode (read or write) */
+ long status; /* subprocess completion status */
+ struct IOSB iosb; /* pipe I/O status block */
+ FILE *file; /* pipe file structure */
+ int pid; /* pipe process id */
+ short chan; /* pipe channel */
+ jmp_buf jmpbuf; /* jump buffer, if needed */
+ int has_jmpbuf; /* flag */
+};
+
+/* Head of the pipe chain */
+static struct PIPE *phead = NULL, *ptail = NULL;
+
+static unsigned char evf = 1;
+
+/*
+ * Exit handler for current process, established by popen().
+ * Force the current process to wait for the completion of children
+ * which were started via popen().
+ * Since
+ */
+static int
+pwait (status)
+ int status;
+{
+ struct IOSB iosb;
+ struct PIPE *this;
+ int ret = 0;
+
+ this = phead;
+ while (this)
+ {
+ if (this->self != this)
+ {
+ ret = -1;
+ continue;
+ }
+ if (!this->iosb.status)
+ {
+ fflush (this->file);
+ if (this->mode == O_WRONLY)
+ sys$qio (0, this->chan, IO$_WRITEOF, &iosb,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+ fclose (this->file);
+ sys$synch (evf, &this->iosb);
+ }
+ else
+ fclose(this->file);
+ sys$dassgn (this->chan);
+ this = this->next;
+ }
+ return ret;
+}
+
+/*
+ * Close a "pipe" created by popen()
+ * Return codes
+ * >0 VMS exit status of process
+ * 0 success, pipe was closed
+ * -1 stream not found in list of pipes
+ * -2 memory corruption detected
+ */
+int
+pclose (stream)
+ FILE *stream;
+{
+ struct IOSB iosb;
+ struct PIPE *this = phead;
+
+ while (this && this->self == this && this->file != stream)
+ this = this->next;
+
+ /* Pipe not found or failed sanity check */
+ if (!this)
+ return -1;
+ else if (this->self != this)
+ return -2;
+
+ /* Flush the I/O buffer and wait for the close to complete */
+ if (!this->iosb.status)
+ {
+ fflush (this->file);
+ if (this->mode == O_WRONLY)
+ sys$qio (0, this->chan, IO$_WRITEOF, &iosb,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+ fclose (this->file);
+ sys$synch (evf, &this->iosb);
+ }
+ else
+ fclose (this->file);
+ sys$dassgn (this->chan);
+
+ /* Remove `this' from the list of pipes and free its storage */
+ if (this == ptail)
+ ptail = this->prev;
+ if (this == phead)
+ phead = this->next;
+ if (this->prev)
+ this->prev->next = this->next;
+ if (this->next)
+ this->next->prev = this->prev;
+ free (this);
+
+ if (this->status & STS$M_SUCCESS != STS$M_SUCCESS)
+ return this->status;
+ else
+ return 0;
+}
+
+/*
+ * Subprocess AST completion routine
+ * Indicate successful completion in the iosb and clear the pid.
+ * Note that the channel is *not* deassigned and the file is
+ * *not* closed.
+ */
+void
+pdone (this)
+ struct PIPE *this;
+{
+ struct IOSB iosb;
+
+ if (this->self != this)
+ return;
+ this->iosb.status = 1;
+ this->pid = 0;
+ if (this->has_jmpbuf)
+ {
+ this->has_jmpbuf = 0;
+ longjmp (this->jmpbuf, 1);
+ }
+}
+
+int
+pipe_set_fd_jmpbuf (fd, jmpbuf)
+ int fd;
+ jmp_buf jmpbuf;
+{
+ struct PIPE *this = phead;
+
+ while (this)
+ if (fileno (this->file) == fd)
+ {
+ memcpy (this->jmpbuf, jmpbuf, sizeof (jmp_buf));
+ this->has_jmpbuf = 1;
+ if (this->pid == 0)
+ {
+ this->has_jmpbuf = 0;
+ longjmp (this->jmpbuf, 1);
+ }
+ return 0;
+ }
+ else
+ this = this->next;
+ return 1;
+}
+
+pipe_unset_fd_jmpbuf (fd)
+ int fd;
+{
+ struct PIPE *this = phead;
+
+ while (this)
+ if (fileno (this->file) == fd)
+ {
+ this->has_jmpbuf = 0;
+ return 0;
+ }
+ else
+ this = this->next;
+ return 1;
+}
+
+/* Exit handler control block for the current process. */
+static struct EXHCB pexhcb = { 0, pwait, 1, &pexhcb.exh$l_status, 0 };
+
+struct Vstring
+{
+ short length;
+ char body[NAM$C_MAXRSS+1];
+};
+
+/*
+ * Emulate a unix popen() call using lib$spawn
+ *
+ * if mode == "w", lib$spawn uses the mailbox for sys$input
+ * if mode == "r", lib$spawn uses the mailbox for sys$output
+ *
+ * Don't now how to handle both read and write
+ *
+ * Returns
+ * FILE * file pointer to the pipe
+ * NULL indicates an error ocurred, check errno value
+ */
+FILE *
+popen (cmd, mode)
+ const char *cmd;
+ const char *mode;
+{
+ int i, status, flags, mbxsize;
+ struct IOSB iosb;
+ struct dsc$descriptor_s cmddsc, mbxdsc;
+ struct Vstring mbxname = { sizeof(mbxname.body) };
+ struct itm$list3 mbxlist[2] = {
+ { sizeof(mbxname.body)-1, DVI$_DEVNAM, &mbxname.body, &mbxname.length },
+ { 0, 0, 0, 0} };
+ struct itm$list3 syilist[2] = {
+ { sizeof(mbxsize), SYI$_MAXBUF, &mbxsize, (void *) 0 },
+ { 0, 0, 0, 0} };
+ static int noExitHandler = 1;
+ struct PIPE *this;
+
+ /* First allocate space for the new pipe */
+ this = (struct PIPE *) calloc (1, sizeof(struct PIPE));
+ if (!this)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* Sanity check value */
+ this->self = this;
+
+ /* Use the smaller of SYI$_MAXBUF and 2048 for the mailbox size */
+ status = sys$getsyiw(0, 0, 0, syilist, &iosb, 0, 0, 0);
+ if (status != SS$_NORMAL && !(iosb.status & STS$M_SUCCESS))
+ {
+ vaxc$errno = iosb.status;
+ errno = EVMSERR;
+ free (this);
+ perror ("popen, $GETSYIW failure for SYI$_MAXBUF");
+ return NULL;
+ }
+
+ if (mbxsize > 2048)
+ mbxsize = 2048;
+
+ status = sys$crembx (0, &this->chan, mbxsize, mbxsize, 0, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ {
+ vaxc$errno = status;
+ errno = EVMSERR;
+ free (this);
+ perror ("popen, $CREMBX failure");
+ return NULL;
+ }
+
+ /* Retrieve mailbox name, use for fopen */
+ status = sys$getdviw (0, this->chan, 0, &mbxlist, &iosb, 0, 0, 0);
+ if (status != SS$_NORMAL && !(iosb.status & STS$M_SUCCESS))
+ {
+ vaxc$errno = iosb.status;
+ errno = EVMSERR;
+ sys$dassgn (this->chan);
+ free (this);
+ perror ("popen, $GETDVIW failure");
+ return NULL;
+ }
+
+ /* Spawn the command using the mailbox as the name for sys$input */
+ mbxname.body[mbxname.length] = 0;
+ mbxdsc.dsc$w_length = mbxname.length;
+ mbxdsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ mbxdsc.dsc$b_class = DSC$K_CLASS_S;
+ mbxdsc.dsc$a_pointer = mbxname.body;
+
+ cmddsc.dsc$w_length = strlen(cmd);
+ cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ cmddsc.dsc$b_class = DSC$K_CLASS_S;
+ cmddsc.dsc$a_pointer = (char *)cmd;
+ flags = CLI$M_NOWAIT;
+ if (strcmp(mode,"w") == 0)
+ {
+ status = lib$spawn (&cmddsc, &mbxdsc, 0, &flags, 0, &this->pid,
+ &this->status, &evf, &pdone, this->self);
+ this->mode = O_WRONLY;
+ }
+ else
+ {
+ status = lib$spawn (&cmddsc, 0, &mbxdsc, &flags, 0, &this->pid,
+ &this->status, &evf, &pdone, this->self);
+ this->mode = O_RDONLY;
+ }
+ if (status != SS$_NORMAL)
+ {
+ vaxc$errno = status;
+ errno = EVMSERR;
+ sys$dassgn (this->chan);
+ free (this);
+ perror("popen, LIB$SPAWN failure");
+ return NULL;
+ }
+
+ /* Set up an exit handler so the subprocess isn't prematurely killed */
+ if (noExitHandler)
+ {
+ status = sys$dclexh (&pexhcb);
+ if (status != SS$_NORMAL)
+ {
+ vaxc$errno = status;
+ errno = EVMSERR;
+ sys$dassgn (this->chan);
+ sys$delprc (&this->pid, 0);
+ free (this);
+ perror("popen, $DCLEXH failure");
+ return NULL;
+ }
+ noExitHandler = 0;
+ }
+
+ /* Pipes are always binary mode devices */
+ if (this->mode == O_WRONLY)
+ this->file = fopen (mbxname.body, "wb");
+ else
+ this->file = fopen (mbxname.body, "rb");
+
+ /* Paranoia, check for failure again */
+ if (!this->file)
+ {
+ sys$dassgn (this->chan);
+ sys$delprc (this->pid);
+ free (this);
+ perror ("popen, fopen failure");
+ return NULL;
+ }
+
+ this->has_jmpbuf = 0;
+
+ /* Insert the new pipe into the list of open pipes */
+ if (phead)
+ {
+ ptail->next = this;
+ this->prev = ptail;
+ ptail = this;
+ }
+ else
+ phead = ptail = this;
+
+ return (this->file);
+}
+
+
+#ifdef TEST_PIPE
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *stdpipe;
+ char line[512];
+
+ while (1)
+ {
+ printf ("\nEnter a command to run >> ");
+ fgets (line, 511, stdin);
+ if (!strlen(line))
+ exit (1);
+ line[strlen(line)-1] = 0;
+ stdpipe = popen (line, "r");
+ if (!stdpipe)
+ {
+ fprintf (stderr, "popen failed.\n");
+ exit(44);
+ }
+ do {
+ fgets (line, 511, stdpipe);
+ fputs (line, stdout);
+ } while (!feof(stdpipe));
+ pclose (stdpipe);
+ }
+}
+#endif
+
+#else /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
+#pragma message disable EMPTYFILE
+#endif /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
diff --git a/vms/pipe.h b/vms/pipe.h
new file mode 100644
index 0000000..3b6b8f2
--- /dev/null
+++ b/vms/pipe.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright © 1994 the Free Software Foundation, Inc.
+ *
+ * Author: Richard Levitte (levitte@e.kth.se)
+ *
+ * This file is a part of GNU VMSLIB, the GNU library for porting GNU
+ * software to VMS.
+ *
+ * GNU VMSLIB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU VMSLIB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+
+int pclose (FILE *);
+FILE *popen (const char *, const char *);
diff --git a/vms/piped_child.c b/vms/piped_child.c
new file mode 100644
index 0000000..af0266a
--- /dev/null
+++ b/vms/piped_child.c
@@ -0,0 +1,382 @@
+/*
+ * piped_child.c
+ *
+ * An experimental VMS implementation of the same routine in [-.src]run.c
+ * <benjamin@cyclic.com>
+ *
+ * Derived in part from pipe.c, in this directory.
+ */
+
+#include "vms.h"
+#include "vms-types.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <syidef.h>
+#include <clidef.h>
+#include <stsdef.h>
+#include <dvidef.h>
+#include <nam.h>
+#include <descrip.h>
+#include <errno.h>
+#include <file.h>
+#include <lib$routines.h>
+#include <starlet.h>
+
+extern int trace;
+
+/* Subprocess IO structure */
+typedef struct _SUBIO {
+ struct _SUBIO *self;
+ struct _SUBIO *prev;
+ struct _SUBIO *next;
+ short read_chan;
+ short write_chan;
+ FILE *read_fp;
+ FILE *write_fp;
+ struct IOSB read_iosb;
+ struct IOSB write_iosb;
+ int pid;
+ int return_status;
+ unsigned long event_flag;
+ unsigned char event_flag_byte;
+} SUBIO;
+
+static SUBIO *siop_head = NULL, *siop_tail = NULL;
+
+static int piped_child_exith(int);
+
+static struct EXHCB piped_child_exit_handler_block =
+ {0, piped_child_exith, 1, &piped_child_exit_handler_block.exh$l_status, 0};
+
+typedef struct
+{
+ short length;
+ char body[NAM$C_MAXRSS+1];
+} Vstring;
+
+/* Subprocess Completion AST */
+void piped_child_done(siop)
+ SUBIO *siop;
+{
+ struct IOSB iosb;
+ int status;
+
+ if (siop->self != siop)
+ return;
+ siop->read_iosb.status = SS$_NORMAL;
+ siop->write_iosb.status = SS$_NORMAL;
+
+}
+
+/* Exit handler, established by piped_child() */
+static int
+piped_child_exith(status)
+ int status;
+{
+ struct IOSB iosb;
+ SUBIO *siop;
+ int return_value = 0;
+
+ siop = siop_head;
+ while (siop)
+ {
+ if (siop->self != siop)
+ {
+ return_value = -1;
+ continue;
+ }
+
+ /* Finish pending reads and shutdown */
+ if(!siop->read_iosb.status)
+ {
+ fflush (siop->read_fp);
+ fclose (siop->read_fp);
+ }
+ else
+ fclose (siop->read_fp);
+ sys$dassgn (siop->read_chan);
+
+ /* Finish pending writes and shutdown */
+ if(!siop->write_iosb.status)
+ {
+ fflush (siop->write_fp);
+ sys$qio (0, siop->write_chan, IO$_WRITEOF, &iosb,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+ fclose (siop->write_fp);
+ }
+ else
+ fclose (siop->write_fp);
+ sys$dassgn (siop->write_chan);
+
+ sys$synch (siop->event_flag, &siop->write_iosb);
+
+ siop = siop->next;
+ }
+ return return_value;
+}
+
+int piped_child(command, tofdp, fromfdp)
+char **command;
+int *tofdp, *fromfdp;
+{
+ static int exit_handler = 0;
+ struct IOSB iosb1, iosb2;
+ int rs1, rs2, i;
+ unsigned long flags, vmspid, return_status;
+ char cmd[1024];
+ struct dsc$descriptor_s cmddsc;
+ struct dsc$descriptor_s read_mbxdsc, write_mbxdsc;
+ SUBIO *siop;
+ static Vstring read_mbxname, write_mbxname;
+ static struct itm$list3 write_mbxlist[2] = {
+ {sizeof(write_mbxname.body)-1, DVI$_DEVNAM,
+ &write_mbxname.body, (size_t *) &write_mbxname.length},
+ {0, 0, 0, 0} };
+ static struct itm$list3 read_mbxlist[2] = {
+ {sizeof(read_mbxname.body)-1, DVI$_DEVNAM,
+ &read_mbxname.body, (size_t *) &read_mbxname.length},
+ {0, 0, 0, 0} };
+
+ read_mbxname.length = sizeof(read_mbxname.body);
+ write_mbxname.length = sizeof(write_mbxname.body);
+
+ siop = (SUBIO *) calloc(1, sizeof(SUBIO));
+ if (!siop)
+ {
+ perror("piped_child: malloc failed\n");
+ return -1;
+ }
+
+ siop->self = siop;
+
+ /* Construct command line by concatenating argument list */
+ strcpy(cmd, command[0]);
+ for(i=1; command[i] != NULL; i++)
+ {
+ strcat(cmd, " ");
+ strcat(cmd, command[i]);
+ }
+
+ if(trace)
+ fprintf(stderr, "piped_child: running '%s'\n", cmd);
+
+ /* Allocate a pair of temporary mailboxes (2kB each) */
+ rs1 = sys$crembx (0, &siop->read_chan, 2048, 2048, 0, 0, 0, 0);
+ rs2 = sys$crembx (0, &siop->write_chan, 2048, 2048, 0, 0, 0, 0);
+
+ if (rs1 != SS$_NORMAL || rs2 != SS$_NORMAL)
+ {
+ vaxc$errno = rs1 | rs2;
+ errno = EVMSERR;
+ free (siop);
+ perror ("piped_child: $CREMBX failure");
+ return -1;
+ }
+
+ /* Get mailbox names, so we can fopen() them */
+ rs1 = sys$getdviw (0, siop->read_chan, 0, &read_mbxlist,
+ &iosb1, 0, 0, 0);
+
+ rs2 = sys$getdviw (0, siop->write_chan, 0, &write_mbxlist,
+ &iosb2, 0, 0, 0);
+
+ if ((rs1 != SS$_NORMAL && !(iosb1.status & STS$M_SUCCESS)) ||
+ (rs2 != SS$_NORMAL && !(iosb2.status & STS$M_SUCCESS)))
+ {
+ vaxc$errno = iosb1.status | iosb2.status;
+ errno = EVMSERR;
+ sys$dassgn (siop->read_chan);
+ sys$dassgn (siop->write_chan);
+ free (siop);
+ perror ("piped_child: $GETDVIW failure, could not get mailbox names");
+ return -1;
+ }
+
+ if (trace)
+ {
+ fprintf(stderr, "piped_child: $GETDVIW succeeded, got mailbox names\n");
+ fprintf(stderr, "piped_child: ReadMBX: %s, WriteMBX: %s\n",
+ read_mbxname.body, write_mbxname.body);
+ }
+
+ /* Make C happy */
+ write_mbxname.body[write_mbxname.length] = '\0';
+ read_mbxname.body[read_mbxname.length] = '\0';
+
+ /* Make VMS happy */
+ write_mbxdsc.dsc$w_length = write_mbxname.length;
+ write_mbxdsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ write_mbxdsc.dsc$b_class = DSC$K_CLASS_S;
+ write_mbxdsc.dsc$a_pointer = write_mbxname.body;
+
+ read_mbxdsc.dsc$w_length = read_mbxname.length;
+ read_mbxdsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ read_mbxdsc.dsc$b_class = DSC$K_CLASS_S;
+ read_mbxdsc.dsc$a_pointer = read_mbxname.body;
+
+ /* Build descriptor for command line */
+ cmddsc.dsc$w_length = strlen(cmd);
+ cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ cmddsc.dsc$b_class = DSC$K_CLASS_S;
+ cmddsc.dsc$a_pointer = (char *) cmd;
+
+ flags = CLI$M_NOWAIT;
+
+ /* Allocate an event flag to signal process termination */
+ rs1 = lib$get_ef(&siop->event_flag);
+ if (rs1 != SS$_NORMAL)
+ {
+ vaxc$errno = rs1;
+ errno = EVMSERR;
+ sys$dassgn(siop->read_chan);
+ sys$dassgn(siop->write_chan);
+ perror("piped_child: LIB$GET_EF failed");
+ return -1;
+ }
+
+ /* Save the EFN as a byte for later calls to other routines */
+ siop->event_flag_byte = 0xff & siop->event_flag;
+
+ if (trace)
+ fprintf(stderr, "piped_child: Got an EFN: %d\n", siop->event_flag_byte);
+
+ rs1 = lib$spawn(&cmddsc, &write_mbxdsc, &read_mbxdsc, &flags, 0,
+ &siop->pid, &siop->return_status, &siop->event_flag_byte,
+ &piped_child_done, siop->self);
+
+ if (rs1 != SS$_NORMAL)
+ {
+ vaxc$errno = rs1;
+ errno = EVMSERR;
+ sys$dassgn(siop->read_chan);
+ sys$dassgn(siop->write_chan);
+ perror("piped_child: LIB$SPAWN failure");
+ return -1;
+ }
+
+ if (trace)
+ fprintf(stderr, "piped_child: LIB$SPAWN succeeded, pid is %08x.\n",
+ siop->pid);
+
+ /* Establish an exit handler so the process isn't prematurely terminated */
+ if (!exit_handler)
+ {
+ rs1 = sys$dclexh (&piped_child_exit_handler_block);
+ if (rs1 != SS$_NORMAL)
+ {
+ vaxc$errno = rs1;
+ errno = EVMSERR;
+ sys$dassgn (siop->read_chan);
+ sys$dassgn (siop->write_chan);
+ sys$delprc (siop->pid, 0);
+ free (siop);
+ perror("piped_child: $DCLEXH failure");
+ return -1;
+ }
+ exit_handler = 1;
+ }
+
+ /* Let's open some files */
+ siop->read_fp = fopen (read_mbxname.body, "r");
+ siop->write_fp = fopen (write_mbxname.body, "w");
+
+ if (!siop->read_fp || !siop->write_fp)
+ {
+ sys$dassgn (siop->read_chan);
+ sys$dassgn (siop->write_chan);
+ sys$delprc (siop->pid);
+ free (siop);
+ perror("piped_child: fopen() failed");
+ return -1;
+ }
+
+ *fromfdp = fileno(siop->read_fp);
+ *tofdp = fileno(siop->write_fp);
+
+ if (trace)
+ fprintf(stderr, "piped_child: file open successful: tofd=%d fromfd=%d\n",
+ *tofdp, *fromfdp);
+
+ /* Keep track of active subprocess I/O (SUBIO) structures */
+ if (siop_head)
+ {
+ siop_tail->next = siop;
+ siop->prev = siop_tail;
+ siop_tail = siop;
+ }
+ else
+ siop_head = siop_tail = siop;
+
+ return siop->pid;
+}
+
+/*
+ * Return codes
+ * >0 VMS exit status of subprocess
+ * 0 success, subprocess was shutdown
+ * -1 pid not found in list of subprocesses
+ * -2 memory corruption detected
+ */
+int
+piped_child_shutdown(pid)
+ pid_t pid;
+{
+ int return_status;
+ struct IOSB iosb;
+ SUBIO *siop = siop_head;
+
+ while (siop && siop->self == siop && siop->pid != pid)
+ siop = siop->next;
+
+ if (!siop)
+ return -1;
+ else if (siop->self != siop)
+ return -2;
+
+ /* Finish reading and writing and shutdown */
+ if (siop->read_iosb.status)
+ {
+ fflush (siop->read_fp);
+ fclose (siop->read_fp);
+ }
+ else
+ fclose(siop->read_fp);
+ sys$dassgn (siop->read_chan);
+
+ if (siop->write_iosb.status)
+ {
+ fflush (siop->write_fp);
+ sys$qio (0, siop->write_chan, IO$_WRITEOF, &iosb,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+ fclose (siop->write_fp);
+ }
+ else
+ fclose(siop->write_fp);
+ sys$dassgn (siop->write_chan);
+
+ sys$synch (siop->event_flag, &siop->write_iosb);
+ lib$free_ef(&siop->event_flag);
+
+ /* Ditch SUBIO structure */
+ if (siop == siop_tail)
+ siop_tail = siop->prev;
+ if (siop == siop_head)
+ siop_head = siop->next;
+ if (siop->prev)
+ siop->prev->next = siop->next;
+ if (siop->next)
+ siop->next->prev = siop->prev;
+
+ if (siop->return_status)
+ return_status = siop->return_status;
+ else
+ return_status = 0;
+
+ free (siop);
+
+ return return_status;
+}
diff --git a/vms/pwd.c b/vms/pwd.c
new file mode 100644
index 0000000..40c6f5a
--- /dev/null
+++ b/vms/pwd.c
@@ -0,0 +1,33 @@
+#include "pwd.h"
+#include <stdio.h>
+#include <unixlib.h>
+
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+
+#if __VMS_VER < 70200000 || __DECC_VER < 50700000
+
+static struct passwd pw;
+
+/* This is only called from one relevant place, lock.c. In that context
+ the code is really trying to figure out who owns a directory. Nothing
+ which has anything to do with getpwuid or anything of the sort can help
+ us on VMS (getuid returns only the group part of the UIC). */
+struct passwd *getpwuid(unsigned int uid)
+{
+ return NULL;
+}
+
+char *getlogin()
+{
+ static char login[256];
+ return cuserid(login);
+}
+
+#else /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
+#pragma message disable EMPTYFILE
+#endif /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
diff --git a/vms/pwd.h b/vms/pwd.h
new file mode 100644
index 0000000..0fe9cd4
--- /dev/null
+++ b/vms/pwd.h
@@ -0,0 +1,25 @@
+#ifndef _PWD_H
+#define _PWD_H
+
+/* Trying to declare uid_t is a mess. We tried #include <sys/types.h>, which
+ only worked on VAX (VMS 6.2, I think), and we tried defining it here
+ which only worked on alpha, I think. In any event, the VMS C library's
+ concept of uid_t is fundamentally broken anyway (getuid() returns only
+ the group part of the UIC), so we are better off with higher-level
+ hooks like get_homedir and SYSTEM_GETCALLER. */
+
+#if !defined(__VMS_VER)
+#define pid_t int
+#elif __VMS_VER < 70000000
+#define pid_t int
+#endif
+
+struct passwd {
+ char *pw_name;
+};
+
+struct passwd *getpwuid(/* really uid_t, but see above about declaring it */);
+char *getlogin(void);
+
+#else
+#endif /* _PWD_H */
diff --git a/vms/rcmd.c b/vms/rcmd.c
new file mode 100644
index 0000000..e403021
--- /dev/null
+++ b/vms/rcmd.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unixio.h>
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+int rcmd(char **remote_hostname, int remote_port,
+ char *local_user, char *remote_user,
+ char *command, int zero)
+{
+ struct hostent *remote_hp;
+ struct hostent *local_hp;
+ struct sockaddr_in remote_isa;
+ struct sockaddr_in local_isa;
+ char local_hostname[80];
+ char ch;
+ int s;
+ int local_port;
+ int rs;
+
+ remote_hp = gethostbyname(*remote_hostname);
+ if(!remote_hp)
+ {
+ perror("couldn't get remote host address");
+ exit(-1);
+ }
+
+ /* Copy remote IP address into socket address structure */
+ remote_isa.sin_family = AF_INET;
+ remote_isa.sin_port = htons(remote_port);
+ memcpy(&remote_isa.sin_addr, remote_hp->h_addr, sizeof(remote_isa.sin_addr));
+
+ gethostname(local_hostname, 80);
+ local_hp = gethostbyname(local_hostname);
+ if(!local_hp)
+ {
+ perror("couldn't get local host address");
+ exit(-1);
+ }
+
+ /* Copy local IP address into socket address structure */
+ local_isa.sin_family = AF_INET;
+ memcpy(&local_isa.sin_addr, local_hp->h_addr, sizeof(local_isa.sin_addr));
+
+ /* Create the local socket */
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if(s < 0)
+ {
+ perror("socket failed\n");
+ exit(-1);
+ }
+
+ /* Bind local socket with a port from IPPORT_RESERVED/2 to IPPORT_RESERVED - 1
+ this requires the OPER privilege under VMS -- to allow communication with
+ a stock rshd under UNIX */
+
+ for(local_port = IPPORT_RESERVED - 1; local_port >= IPPORT_RESERVED/2; local_port--)
+ {
+ local_isa.sin_port = htons(local_port);
+ rs = bind(s, (struct sockaddr *)&local_isa, sizeof(local_isa));
+ if(rs == 0)
+ break;
+ }
+
+ /* Bind local socket to an unprivileged port. A normal rshd will drop the
+ connection; you must be running a patched rshd invoked through inetd for
+ this connection method to work */
+
+ if (rs != 0)
+ for(local_port = IPPORT_USERRESERVED - 1;
+ local_port > IPPORT_RESERVED;
+ local_port--)
+ {
+ local_isa.sin_port = htons(local_port);
+ rs = bind(s, (struct sockaddr *)&local_isa, sizeof(local_isa));
+ if(rs == 0)
+ break;
+ }
+
+ rs = connect(s, (struct sockaddr *) &remote_isa, sizeof(remote_isa));
+ if(rs == -1)
+ {
+ fprintf(stderr, "connect: errno = %d\n", errno);
+ close(s);
+ exit(-2);
+ }
+
+ /* Now supply authentication information */
+
+ /* Auxiliary port number for error messages, we don't use it */
+ write(s, "0\0", 2);
+
+ /* Who are we */
+ write(s, local_user, strlen(local_user) + 1);
+
+ /* Who do we want to be */
+ write(s, remote_user, strlen(remote_user) + 1);
+
+ /* What do we want to run */
+ write(s, command, strlen(command) + 1);
+
+ /* NUL is sent back to us if information is acceptable */
+ read(s, &ch, 1);
+ if(ch != '\0')
+ {
+ errno = EPERM;
+ return -1;
+ }
+
+ return s;
+}
diff --git a/vms/readlink.c b/vms/readlink.c
new file mode 100644
index 0000000..1d844d7
--- /dev/null
+++ b/vms/readlink.c
@@ -0,0 +1,5 @@
+int readlink(char *path, char *buf, int bufsiz)
+{
+ /* OpenVMS dosen't have symbolic links in the UNIX sense */
+ return -1;
+}
diff --git a/vms/rmdir.c b/vms/rmdir.c
new file mode 100644
index 0000000..bebe1ea
--- /dev/null
+++ b/vms/rmdir.c
@@ -0,0 +1,23 @@
+
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+
+#if __VMS_VER < 70200000 || __DECC_VER < 50700000
+
+#include <stdio.h>
+#include <unixio.h>
+
+int rmdir(path)
+char *path;
+{
+ chmod(path, 0777);
+ return remove(path);
+}
+
+#else /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
+#pragma message disable EMPTYFILE
+#endif /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
diff --git a/vms/startserver.c b/vms/startserver.c
new file mode 100755
index 0000000..251f66a
--- /dev/null
+++ b/vms/startserver.c
@@ -0,0 +1,56 @@
+#include <socket.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include "config.h"
+
+static char *cvs_server;
+static char *command;
+
+extern int trace;
+
+void
+vms_start_server (int *tofd, int *fromfd,
+ char *client_user, char *server_user,
+ char *server_host, char *server_cvsroot)
+{
+ int fd, port;
+ char *portenv;
+ struct servent *sptr;
+
+ if (! (cvs_server = getenv ("CVS_SERVER")))
+ cvs_server = "cvs";
+ command = xmalloc (strlen (cvs_server)
+ + strlen (server_cvsroot)
+ + 50);
+ sprintf(command, "%s server", cvs_server);
+
+ portenv = getenv("CVS_RCMD_PORT");
+ if (portenv)
+ port = atoi(portenv);
+ else if ((sptr = getservbyname("shell", "tcp")) != NULL)
+ port = sptr->s_port;
+ else
+ port = 514; /* shell/tcp */
+
+ if(trace)
+ {
+ fprintf(stderr, "vms_start_server(): connecting to %s:%d\n",
+ server_host, port);
+ fprintf(stderr, "local_user = %s, remote_user = %s, CVSROOT = %s\n",
+ client_user, (server_user ? server_user : client_user),
+ server_cvsroot);
+ }
+
+ fd = rcmd(&server_host, port,
+ client_user,
+ (server_user ? server_user : client_user),
+ command, 0);
+
+ if (fd < 0)
+ error (1, errno, "cannot start server via rcmd()");
+
+ *tofd = fd;
+ *fromfd = fd;
+ free (command);
+}
diff --git a/vms/stat.c b/vms/stat.c
new file mode 100644
index 0000000..661df75
--- /dev/null
+++ b/vms/stat.c
@@ -0,0 +1,33 @@
+#include <string.h>
+#include <stat.h>
+#include <unixlib.h>
+
+int wrapped_stat (path, buffer)
+const char *path;
+struct stat *buffer;
+{
+ char statpath[1024];
+ int rs;
+
+ strcpy(statpath, path);
+ strip_trailing_slashes (statpath);
+ if(strcmp(statpath, ".") == 0)
+ {
+ char *wd;
+ wd = xgetwd ();
+ rs = stat (wd, buffer);
+ free (wd);
+ }
+ else
+ rs = stat (statpath, buffer);
+
+ if (rs < 0)
+ {
+ /* If stat() fails try again after appending ".dir" to the filename
+ this allows you to stat things like "bloogle/CVS" from VMS 6.1 */
+ strcat(statpath, ".dir");
+ rs = stat (statpath, buffer);
+ }
+
+ return rs;
+}
diff --git a/vms/unlink.c b/vms/unlink.c
new file mode 100644
index 0000000..80a5a74
--- /dev/null
+++ b/vms/unlink.c
@@ -0,0 +1,28 @@
+#include <unixio.h>
+
+/* UNIX-like file deletion, deletes previous VMS file versions so UNIX
+ style locking through files dosen't lose. */
+#ifndef __VMS_VER
+int vms_unlink(char *path)
+#elif __VMS_VER < 70200000
+int vms_unlink(char *path)
+#else
+int vms_unlink(char const*path)
+#endif
+{
+ int rs, junk_rs;
+
+ rs = remove(path);
+ while(remove(path) >= 0);
+
+ return rs;
+}
+
+int link(char *from, char *to)
+{
+ int rs = -1;
+
+ /* Link always fails */
+
+ return rs;
+}
diff --git a/vms/utime.c b/vms/utime.c
new file mode 100644
index 0000000..999aecb
--- /dev/null
+++ b/vms/utime.c
@@ -0,0 +1,42 @@
+/* This is REALLY gross, but at least it is a full implementation */
+
+#include <ctype.h>
+#include <time.h>
+#include "vmsmunch.h"
+
+#define ASCTIMEMAX 23
+
+struct utimbuf {
+ long actime;
+ long modtime;
+ };
+
+utime(file, buf)
+char *file;
+struct utimbuf *buf;
+{
+ static struct VMStimbuf vtb;
+ static char conversion_buf[80];
+ static char vms_actime[80];
+ static char vms_modtime[80];
+
+ strcpy(conversion_buf, ctime(&buf->actime));
+ conversion_buf[ASCTIMEMAX + 1] = '\0';
+ sprintf(vms_actime, "%2.2s-%3.3s-%4.4s %8.5s.00",
+ &(conversion_buf[8]), &(conversion_buf[4]),
+ &(conversion_buf[20]), &(conversion_buf[11]));
+ vms_actime[4] = _toupper(vms_actime[4]);
+ vms_actime[5] = _toupper(vms_actime[5]);
+
+ strcpy(conversion_buf, ctime(&buf->modtime));
+ conversion_buf[ASCTIMEMAX + 1] = '\0';
+ sprintf(vms_modtime, "%2.2s-%3.3s-%4.4s %8.5s.00",
+ &(conversion_buf[8]), &(conversion_buf[4]),
+ &(conversion_buf[20]), &(conversion_buf[11]));
+ vms_modtime[4] = _toupper(vms_modtime[4]);
+ vms_modtime[4] = _toupper(vms_modtime[5]);
+
+ vtb.actime = vms_actime;
+ vtb.modtime = vms_modtime;
+ VMSmunch(file, SET_TIMES, &vtb);
+}
diff --git a/vms/vms-types.h b/vms/vms-types.h
new file mode 100644
index 0000000..658b1e2
--- /dev/null
+++ b/vms/vms-types.h
@@ -0,0 +1,45 @@
+#ifndef __types_loaded__
+#define __types_loaded__ 1
+
+#include <stddef.h>
+
+/*
+ * Miscellaneous VMS types that are not normally defined
+ * in any consistent fashion.
+ */
+
+/* VMS I/O status block */
+struct IOSB
+{
+ short status, count;
+ long devinfo;
+};
+
+/* VMS Item List 3 structure */
+struct itm$list3
+{
+ short buflen;
+ short itemcode;
+ void *buffer;
+ size_t *retlen;
+};
+
+/* VMS Lock status block with value block */
+struct LOCK
+{
+ short status, reserved;
+ long lockid;
+ long value[4];
+};
+
+/* VMS Exit Handler Control block */
+struct EXHCB
+{
+ struct exhcb *exh$a_link;
+ int (*exh$a_routine)();
+ long exh$l_argcount;
+ long *exh$a_status;
+ long exh$l_status;
+};
+
+#endif /* __types_loaded__ 1 */
diff --git a/vms/vms.h b/vms/vms.h
new file mode 100755
index 0000000..d96ffad
--- /dev/null
+++ b/vms/vms.h
@@ -0,0 +1,45 @@
+/* Determined from CC RTL function prototypes in online documentation */
+
+#if !defined(__VMS_VER)
+#define mode_t unsigned int
+#elif __VMS_VER < 70000000
+#define mode_t unsigned int
+#endif
+
+#define fork(x) vfork(x)
+
+#include <sys/types.h>
+#include <unixio.h>
+#include <unixlib.h>
+#include <stdlib.h>
+#include <processes.h>
+#include <socket.h>
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+extern int fnmatch(char *pattern, char *string, int options);
+
+/* With the define of HAVE_NDIR_H in config.h, lib/system.h and
+ diff/system.h should include ndir.h for us. But I'm too lazy to
+ track down and make _sure_ all bases are covered, so I'm leaving in
+ this include for now. */
+#include "ndir.h"
+
+#include "pwd.h"
+#include "pipe.h"
+
+#if !defined(__VMS_VER)
+int vms_unlink(char *path);
+#elif __VMS_VER < 70000000
+int vms_unlink(char *path);
+#else
+int vms_unlink(char const*path);
+#endif
+int link(char *from, char *to);
+
+#define stat(a, b) wrapped_stat(a, b)
+#define lstat stat
+
+#undef POSIX
diff --git a/vms/vmsmunch.c b/vms/vmsmunch.c
new file mode 100644
index 0000000..198d45e
--- /dev/null
+++ b/vms/vmsmunch.c
@@ -0,0 +1,370 @@
+/*---------------------------------------------------------------------------
+
+ VMSmunch.c version 1.3 28 Apr 1992
+
+ This routine is a blatant and unrepentent appropriation of all the nasty
+ and difficult-to-do and complicated VMS shenanigans which Joe Meadows has
+ so magnificently captured in his FILE utility. Not only that, it's even
+ allowed! (see below). But let it be clear at the outset that Joe did all
+ the work; yea, verily, he is truly a godlike unit.
+
+ The appropriations and modifications herein were performed primarily by
+ him known as "Cave Newt," although the Info-ZIP working group probably had
+ their fingers in it somewhere along the line. The idea is to put the raw
+ power of Joe's original routine at the disposal of various routines used
+ by UnZip (and Zip, possibly), not least among them the utime() function.
+ Read on for details...
+
+ 18-JUL-1994 Hunter Goatley <goathunter@WKU.EDU>
+ Fixed IO$_ACCESS call.
+
+ 18-Jul-1994 Richard Levitte levitte@e.kth.se
+ Changed VMSmunch() to deassign the channel before
+ returning when an error has occured.
+
+ 02-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved definition of VMStimbuf struct from here
+ to vmsmunch.h
+ ---------------------------------------------------------------------------
+
+ Usage (i.e., "interface," in geek-speak):
+
+ int VMSmunch( char *filename, int action, char *ptr );
+
+ filename the name of the file on which to be operated, obviously
+ action an integer which specifies what action to take
+ ptr pointer to any extra item which may be needed (else NULL)
+
+ The possible values for the action argument are as follows:
+
+ GET_TIMES get the creation and revision dates of filename; ptr
+ must point to an empty VMStimbuf struct, as defined
+ in vmsmunch.h
+ (with room for at least 24 characters, including term.)
+ SET_TIMES set the creation and revision dates of filename (utime
+ option); ptr must point to a valid VMStimbuf struct,
+ as defined in vmsmunch.h
+ GET_RTYPE get the record type of filename; ptr must point to an
+ integer which, on return, is set to the type (as defined
+ in VMSmunch.h: FAT$C_* defines)
+ CHANGE_RTYPE change the record type to that specified by the integer
+ to which ptr points; save the old record type (later
+ saves overwrite earlier ones)
+ RESTORE_RTYPE restore the record type to the previously saved value;
+ or, if none, set it to "fixed-length, 512-byte" record
+ format (ptr not used)
+
+ ---------------------------------------------------------------------------
+
+ Comments from FILE.C, a utility to modify file characteristics:
+
+ Written by Joe Meadows Jr, at the Fred Hutchinson Cancer Research Center
+ BITNET: JOE@FHCRCVAX
+ PHONE: (206) 467-4970
+
+ There are no restrictions on this code, you may sell it, include it
+ with any commercial package, or feed it to a whale.. However, I would
+ appreciate it if you kept this comment in the source code so that anyone
+ receiving this code knows who to contact in case of problems. Note that
+ I do not demand this condition..
+
+ ---------------------------------------------------------------------------*/
+
+
+
+
+/*****************************/
+/* Includes, Defines, etc. */
+/*****************************/
+
+#include <descrip.h>
+#include <rms.h>
+#include <stdio.h>
+#include <iodef.h>
+#include <string.h>
+#include <starlet.h>
+#include <atrdef.h> /* this gets created with the c3.0 compiler */
+#include <fibdef.h> /* this gets created with the c3.0 compiler */
+
+#include "VMSmunch.h" /* GET/SET_TIMES, RTYPE, etc. */
+#include "VMSmunch_private.h" /* fatdef.h, etc. */
+
+#define RTYPE fat$r_rtype_overlay.fat$r_rtype_bits
+#define RATTRIB fat$r_rattrib_overlay.fat$r_rattrib_bits
+
+static void asctim();
+static void bintim();
+
+/* from <ssdef.h> */
+#ifndef SS$_NORMAL
+# define SS$_NORMAL 1
+# define SS$_BADPARAM 20
+#endif
+
+
+
+
+
+/*************************/
+/* Function VMSmunch() */
+/*************************/
+
+int VMSmunch( filename, action, ptr )
+ char *filename, *ptr;
+ int action;
+{
+
+ /* original file.c variables */
+
+ static struct FAB Fab;
+ static struct NAM Nam;
+ static struct fibdef Fib; /* short fib */
+
+ static struct dsc$descriptor FibDesc =
+ {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,(char *)&Fib};
+ static struct dsc$descriptor_s DevDesc =
+ {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.nam$t_dvi[1]};
+ static struct fatdef Fat;
+ static union {
+ struct fchdef fch;
+ long int dummy;
+ } uchar;
+ static struct fjndef jnl;
+ static long int Cdate[2],Rdate[2],Edate[2],Bdate[2];
+ static short int revisions;
+ static unsigned long uic;
+ static union {
+ unsigned short int value;
+ struct {
+ unsigned system : 4;
+ unsigned owner : 4;
+ unsigned group : 4;
+ unsigned world : 4;
+ } bits;
+ } prot;
+
+ static struct atrdef Atr[] = {
+ {ATR$S_RECATTR,ATR$C_RECATTR,&Fat}, /* record attributes */
+ {ATR$S_UCHAR,ATR$C_UCHAR,&uchar}, /* File characteristics */
+ {ATR$S_CREDATE,ATR$C_CREDATE,&Cdate[0]}, /* Creation date */
+ {ATR$S_REVDATE,ATR$C_REVDATE,&Rdate[0]}, /* Revision date */
+ {ATR$S_EXPDATE,ATR$C_EXPDATE,&Edate[0]}, /* Expiration date */
+ {ATR$S_BAKDATE,ATR$C_BAKDATE,&Bdate[0]}, /* Backup date */
+ {ATR$S_ASCDATES,ATR$C_ASCDATES,&revisions}, /* number of revisions */
+ {ATR$S_FPRO,ATR$C_FPRO,&prot}, /* file protection */
+ {ATR$S_UIC,ATR$C_UIC,&uic}, /* file owner */
+ {ATR$S_JOURNAL,ATR$C_JOURNAL,&jnl}, /* journal flags */
+ {0,0,0}
+ } ;
+
+ static char EName[NAM$C_MAXRSS];
+ static char RName[NAM$C_MAXRSS];
+ static struct dsc$descriptor_s FileName =
+ {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+ static struct dsc$descriptor_s string = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+ static short int DevChan;
+ static short int iosb[4];
+
+ static long int i,status;
+/* static char *retval; */
+
+
+ /* new VMSmunch variables */
+
+ static int old_rtype=FAT$C_FIXED; /* storage for record type */
+
+
+
+/*---------------------------------------------------------------------------
+ Initialize attribute blocks, parse filename, resolve any wildcards, and
+ get the file info.
+ ---------------------------------------------------------------------------*/
+
+ /* initialize RMS structures, we need a NAM to retrieve the FID */
+ Fab = cc$rms_fab;
+ Fab.fab$l_fna = filename;
+ Fab.fab$b_fns = strlen(filename);
+ Fab.fab$l_nam = &Nam; /* FAB has an associated NAM */
+ Nam = cc$rms_nam;
+ Nam.nam$l_esa = EName; /* expanded filename */
+ Nam.nam$b_ess = sizeof(EName);
+ Nam.nam$l_rsa = RName; /* resultant filename */
+ Nam.nam$b_rss = sizeof(RName);
+
+ /* do $PARSE and $SEARCH here */
+ status = sys$parse(&Fab);
+ if (!(status & 1)) return(status);
+
+ /* search for the first file.. If none signal error */
+ status = sys$search(&Fab);
+ if (!(status & 1)) return(status);
+
+ while (status & 1) {
+ /* initialize Device name length, note that this points into the NAM
+ to get the device name filled in by the $PARSE, $SEARCH services */
+ DevDesc.dsc$w_length = Nam.nam$t_dvi[0];
+
+ status = sys$assign(&DevDesc,&DevChan,0,0);
+ if (!(status & 1)) return(status);
+
+ FileName.dsc$a_pointer = Nam.nam$l_name;
+ FileName.dsc$w_length = Nam.nam$b_name+Nam.nam$b_type+Nam.nam$b_ver;
+
+ /* Initialize the FIB */
+ for (i=0;i<3;i++)
+#ifdef VAXC
+ Fib.fib$r_fid_overlay.fib$w_fid[i]=Nam.nam$w_fid[i];
+#else
+ Fib.fib$w_fid[i]=Nam.nam$w_fid[i];
+#endif
+ for (i=0;i<3;i++)
+#ifdef VAXC
+ Fib.fib$r_did_overlay.fib$w_did[i]=Nam.nam$w_did[i];
+#else
+ Fib.fib$w_did[i]=Nam.nam$w_did[i];
+#endif
+
+ /* Use the IO$_ACCESS function to return info about the file */
+ /* Note, used this way, the file is not opened, and the expiration */
+ /* and revision dates are not modified */
+ status = sys$qiow(0,DevChan,IO$_ACCESS,&iosb,0,0,
+ &FibDesc,&FileName,0,0,&Atr,0);
+ if (!(status & 1))
+ {
+ sys$dassgn(DevChan);
+ return(status);
+ }
+ status = iosb[0];
+ if (!(status & 1))
+ {
+ sys$dassgn(DevChan);
+ return(status);
+ }
+
+ /*-----------------------------------------------------------------------
+ We have the current information from the file: now see what user
+ wants done with it.
+ -----------------------------------------------------------------------*/
+
+ switch (action) {
+
+ case GET_TIMES:
+ asctim(((struct VMStimbuf *)ptr)->modtime, Cdate);
+ asctim(((struct VMStimbuf *)ptr)->actime, Rdate);
+ break;
+
+ case SET_TIMES:
+ bintim(((struct VMStimbuf *)ptr)->modtime, Cdate);
+ bintim(((struct VMStimbuf *)ptr)->actime, Rdate);
+ break;
+
+ case GET_RTYPE: /* non-modifying */
+ *(int *)ptr = Fat.RTYPE.fat$v_rtype;
+ return RMS$_NORMAL; /* return to user */
+ break;
+
+ case CHANGE_RTYPE:
+ old_rtype = Fat.RTYPE.fat$v_rtype; /* save current one */
+ if ((*(int *)ptr < FAT$C_UNDEFINED) ||
+ (*(int *)ptr > FAT$C_STREAMCR))
+ Fat.RTYPE.fat$v_rtype = FAT$C_STREAMLF; /* Unix I/O happy */
+ else
+ Fat.RTYPE.fat$v_rtype = *(int *)ptr;
+ break;
+
+ case RESTORE_RTYPE:
+ Fat.RTYPE.fat$v_rtype = old_rtype;
+ break;
+
+ default:
+ return SS$_BADPARAM; /* anything better? */
+ }
+
+ /*-----------------------------------------------------------------------
+ Go back and write modified data to the file header.
+ -----------------------------------------------------------------------*/
+
+ /* note, part of the FIB was cleared by earlier QIOW, so reset it */
+#ifdef VAXC
+ Fib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_NORECORD;
+#else
+ Fib.fib$l_acctl = FIB$M_NORECORD;
+#endif
+ for (i=0;i<3;i++)
+#ifdef VAXC
+ Fib.fib$r_fid_overlay.fib$w_fid[i]=Nam.nam$w_fid[i];
+#else
+ Fib.fib$w_fid[i]=Nam.nam$w_fid[i];
+#endif
+ for (i=0;i<3;i++)
+#ifdef VAXC
+ Fib.fib$r_did_overlay.fib$w_did[i]=Nam.nam$w_did[i];
+#else
+ Fib.fib$w_did[i]=Nam.nam$w_did[i];
+#endif
+
+ /* Use the IO$_MODIFY function to change info about the file */
+ /* Note, used this way, the file is not opened, however this would */
+ /* normally cause the expiration and revision dates to be modified. */
+ /* Using FIB$M_NORECORD prohibits this from happening. */
+ status = sys$qiow(0,DevChan,IO$_MODIFY,&iosb,0,0,
+ &FibDesc,&FileName,0,0,&Atr,0);
+ if (!(status & 1))
+ {
+ sys$dassgn(DevChan);
+ return(status);
+ }
+
+ status = iosb[0];
+ if (!(status & 1))
+ {
+ sys$dassgn(DevChan);
+ return(status);
+ }
+
+ status = sys$dassgn(DevChan);
+ if (!(status & 1)) return(status);
+
+ /* look for next file, if none, no big deal.. */
+ status = sys$search(&Fab);
+ }
+} /* end function VMSmunch() */
+
+
+
+
+
+/***********************/
+/* Function bintim() */
+/***********************/
+
+void asctim(time,binval) /* convert 64-bit binval to string, put in time */
+ char *time;
+ long int binval[2];
+{
+ static struct dsc$descriptor date_str={23,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+ /* dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer */
+
+ date_str.dsc$a_pointer = time;
+ sys$asctim(0, &date_str, binval, 0);
+ time[23] = '\0';
+}
+
+
+
+
+
+/***********************/
+/* Function bintim() */
+/***********************/
+
+void bintim(time,binval) /* convert time string to 64 bits, put in binval */
+ char *time;
+ long int binval[2];
+{
+ static struct dsc$descriptor date_str={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+
+ date_str.dsc$w_length = strlen(time);
+ date_str.dsc$a_pointer = time;
+ sys$bintim(&date_str, binval);
+}
diff --git a/vms/vmsmunch.h b/vms/vmsmunch.h
new file mode 100644
index 0000000..cc304c9
--- /dev/null
+++ b/vms/vmsmunch.h
@@ -0,0 +1,32 @@
+/*---------------------------------------------------------------------------
+
+ VMSmunch.h
+
+ A few handy #defines, plus the contents of three header files from Joe
+ Meadows' FILE program. Used by VMSmunch and by various routines which
+ call VMSmunch (e.g., in Zip and UnZip).
+
+ 02-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved definition of VMStimbuf struct from vmsmunch.c
+ to here.
+
+ 06-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved "contents of three header files" (not needed by
+ callers of vmsmunch) to vmsmunch_private.h .
+
+ 07-Apr-1994 Richard Levitte levitte@e.kth.se
+ Inserted a forward declaration of VMSmunch.
+ ---------------------------------------------------------------------------*/
+
+#define GET_TIMES 4
+#define SET_TIMES 0
+#define GET_RTYPE 1
+#define CHANGE_RTYPE 2
+#define RESTORE_RTYPE 3
+
+struct VMStimbuf { /* VMSmunch */
+ char *actime; /* VMS revision date, ASCII format */
+ char *modtime; /* VMS creation date, ASCII format */
+};
+
+extern int VMSmunch();
diff --git a/vms/vmsmunch_private.h b/vms/vmsmunch_private.h
new file mode 100644
index 0000000..33577c1
--- /dev/null
+++ b/vms/vmsmunch_private.h
@@ -0,0 +1,176 @@
+/*---------------------------------------------------------------------------
+
+ VMSmunch_private.h
+
+ Contents of three header files from Joe
+ Meadows' FILE program. Used by VMSmunch
+
+ 06-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved "contents of three header files" from
+ vmsmunch.h to vmsmunch_private.h .
+ ---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ fatdef.h
+ ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+ in any way. No guarantee is made as to the accuracy of the contents
+ of this header file. This header file was last modified on Sep. 22th,
+ 1987. (Modified to include this statement) */
+#define FAT$K_LENGTH 32
+#define FAT$C_LENGTH 32
+#define FAT$S_FATDEF 32
+
+struct fatdef {
+ union {
+ unsigned char fat$b_rtype;
+ struct {
+ unsigned fat$v_rtype : 4;
+ unsigned fat$v_fileorg : 4;
+ } fat$r_rtype_bits;
+ } fat$r_rtype_overlay;
+# define FAT$S_RTYPE 4
+# define FAT$V_RTYPE 0
+# define FAT$C_UNDEFINED 0
+# define FAT$C_FIXED 1
+# define FAT$C_VARIABLE 2
+# define FAT$C_VFC 3
+# define FAT$C_STREAM 4
+# define FAT$C_STREAMLF 5
+# define FAT$C_STREAMCR 6
+# define FAT$S_FILEORG 4
+# define FAT$V_FILEORG 4
+# define FAT$C_SEQUENTIAL 0
+# define FAT$C_RELATIVE 1
+# define FAT$C_INDEXED 2
+# define FAT$C_DIRECT 3
+ union {
+ unsigned char fat$b_rattrib;
+ struct {
+ unsigned fat$v_fortrancc : 1;
+ unsigned fat$v_impliedcc : 1;
+ unsigned fat$v_printcc : 1;
+ unsigned fat$v_nospan : 1;
+ } fat$r_rattrib_bits;
+ } fat$r_rattrib_overlay;
+# define FAT$V_FORTRANCC 0
+# define FAT$M_FORTRANCC 1
+# define FAT$V_IMPLIEDCC 1
+# define FAT$M_IMPLIEDCC 2
+# define FAT$V_PRINTCC 2
+# define FAT$M_PRINTCC 4
+# define FAT$V_NOSPAN 3
+# define FAT$M_NOSPAN 8
+ unsigned short int fat$w_rsize;
+ union
+ {
+ unsigned long int fat$l_hiblk;
+ struct
+ {
+ unsigned short int fat$w_hiblkh;
+ unsigned short int fat$w_hiblkl;
+ } fat$r_hiblk_fields;
+ } fat$r_hiblk_overlay;
+ union
+ {
+ unsigned long int fat$l_efblk;
+ struct
+ {
+ unsigned short int fat$w_efblkh;
+ unsigned short int fat$w_efblkl;
+ } fat$r_efblk_fields;
+ } fat$r_efblk_overlay;
+ unsigned short int fat$w_ffbyte;
+ unsigned char fat$b_bktsize;
+ unsigned char fat$b_vfcsize;
+ unsigned short int fat$w_maxrec;
+ unsigned short int fat$w_defext;
+ unsigned short int fat$w_gbc;
+ char fat$fill[8];
+ unsigned short int fat$w_versions;
+};
+
+/*---------------------------------------------------------------------------
+ fchdef.h
+ ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+ in any way. No guarantee is made as to the accuracy of the contents
+ of this header file. This header file was last modified on Sep. 22th,
+ 1987. (Modified to include this statement) */
+
+#define FCH$V_BADACL 0x00B
+#define FCH$M_BADACL (1 << FCH$V_ACL)
+#define FCH$V_BADBLOCK 0x00E
+#define FCH$M_BADBLOCK (1 << FCH$V_BADBLOCK)
+#define FCH$V_CONTIG 0x007
+#define FCH$M_CONTIG (1 << FCH$V_CONTIG)
+#define FCH$V_CONTIGB 0x005
+#define FCH$M_CONTIGB (1 << FCH$V_CONTIGB)
+#define FCH$V_DIRECTORY 0x00D
+#define FCH$M_DIRECTORY (1 << FCH$V_DIRECTORY)
+#define FCH$V_ERASE 0x011
+#define FCH$M_ERASE (1 << FCH$V_ERASE)
+#define FCH$V_LOCKED 0x006
+#define FCH$M_LOCKED (1 << FCH$V_LOCKED)
+#define FCH$V_MARKDEL 0x00F
+#define FCH$M_MARKDEL (1 << FCH$V_MARKDEL)
+#define FCH$V_NOBACKUP 0x001
+#define FCH$M_NOBACKUP (1 << FCH$V_NOBACKUP)
+#define FCH$V_NOCHARGE 0x010
+#define FCH$M_NOCHARGE (1 << FCH$V_NOCHARGE)
+#define FCH$V_READCHECK 0x003
+#define FCH$M_READCHECK (1 << FCH$V_READCHECK)
+#define FCH$V_SPOOL 0x00C
+#define FCH$M_SPOOL (1 << FCH$V_SPOOL)
+#define FCH$V_WRITCHECK 0x004
+#define FCH$M_WRITCHECK (1 << FCH$V_WRITCHECK)
+#define FCH$V_WRITEBACK 0x002
+#define FCH$M_WRITEBACK (1 << FCH$V_WRITEBACK)
+
+struct fchdef {
+ unsigned : 1;
+ unsigned fch$v_nobackup : 1 ;
+ unsigned fch$v_writeback : 1;
+ unsigned fch$v_readcheck : 1;
+ unsigned fch$v_writcheck : 1;
+ unsigned fch$v_contigb : 1;
+ unsigned fch$v_locked : 1;
+ unsigned fch$v_contig : 1;
+ unsigned : 3;
+ unsigned fch$v_badacl : 1;
+ unsigned fch$v_spool : 1;
+ unsigned fch$v_directory : 1;
+ unsigned fch$v_badblock : 1;
+ unsigned fch$v_markdel : 1;
+ unsigned fch$v_nocharge : 1;
+ unsigned fch$v_erase : 1;
+};
+
+/*---------------------------------------------------------------------------
+ fjndef.h
+ ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+ in any way. No guarantee is made as to the accuracy of the contents
+ of this header file. This header file was last modified on Sep. 22th,
+ 1987. (Modified to include this statement) */
+
+#define FJN$M_ONLY_RU 1
+#define FJN$M_RUJNL 2
+#define FJN$M_BIJNL 4
+#define FJN$M_AIJNL 8
+#define FJN$M_ATJNL 16
+#define FJN$M_NEVER_RU 32
+#define FJN$M_JOURNAL_FILE 64
+#define FJN$S_FJNDEF 1
+struct fjndef {
+ unsigned fjn$v_only_ru : 1;
+ unsigned fjn$v_rujnl : 1;
+ unsigned fjn$v_bijnl : 1;
+ unsigned fjn$v_aijnl : 1;
+ unsigned fjn$v_atjnl : 1;
+ unsigned fjn$v_never_ru : 1;
+ unsigned fjn$v_journal_file:1;
+} ;
diff --git a/vms/waitpid.c b/vms/waitpid.c
new file mode 100644
index 0000000..ff9f551
--- /dev/null
+++ b/vms/waitpid.c
@@ -0,0 +1,77 @@
+/* Emulate waitpid on systems that just have wait.
+ Copyright (C) 1994 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details. */
+
+#ifndef __VMS_VER
+#define __VMS_VER 0
+#endif
+#ifndef __DECC_VER
+#define __DECC_VER 0
+#endif
+
+#if __VMS_VER < 70200000 || __DECC_VER < 50700000
+
+#include "vms.h"
+
+#define WAITPID_CHILDREN 8
+static pid_t waited_pid[WAITPID_CHILDREN];
+static int waited_status[WAITPID_CHILDREN];
+
+pid_t
+waitpid (pid, stat_loc, options)
+ pid_t pid;
+ int *stat_loc;
+ int options;
+{
+ int i;
+ pid_t p;
+
+ if (!options && (0 < pid || pid == -1))
+ {
+ /* If we have already waited for this child, return it immediately. */
+ for (i = 0; i < WAITPID_CHILDREN; i++)
+ {
+ p = waited_pid[i];
+ if (p && (p == pid || pid == -1))
+ {
+ waited_pid[i] = 0;
+ goto success;
+ }
+ }
+
+ /* The child has not returned yet; wait for it, accumulating status. */
+ for (i = 0; i < WAITPID_CHILDREN; i++)
+ if (! waited_pid[i])
+ {
+ p = wait (&waited_status[i]);
+ if (p < 0)
+ return p;
+ if (p == pid || pid == -1)
+ goto success;
+ waited_pid[i] = p;
+ }
+ }
+
+ /* We cannot emulate this wait call, e.g. because of too many children. */
+ abort ();
+
+success:
+ if (stat_loc)
+ *stat_loc = waited_status[i];
+ return p;
+}
+
+#else /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
+#pragma message disable EMPTYFILE
+#endif /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
diff --git a/windows-NT/.cvsignore b/windows-NT/.cvsignore
new file mode 100644
index 0000000..111e6f9
--- /dev/null
+++ b/windows-NT/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+check.log
+check.plog
+stamp-ch
+stamp-sh
+stamp-sh2
diff --git a/windows-NT/ChangeLog b/windows-NT/ChangeLog
new file mode 100644
index 0000000..7888d62
--- /dev/null
+++ b/windows-NT/ChangeLog
@@ -0,0 +1,1871 @@
+2005-09-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * woe32.c woe32.h: Add "woe32_fd_select" function.
+
+2005-09-29 Conrad T. Pino <Conrad@Pino.com>
+
+ * run.c: Add "bool fix_stderr" argument to "piped_child" function.
+ Add "false" to "piped_child" call in "run_piped" function.
+
+2005-09-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.footer: Extend "mbsinit" Visual C++ 6.0 implementation
+ to add Visual C++ 5.0, Visual C++ .NET, Visual C++ .NET 2003.
+
+ * config.h config.h.in stamp-chi: Regenerated on UNIX.
+
+2005-09-26 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add unistd.c, woe32.h.
+
+2005-09-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add new files.
+
+2005-09-25 Conrad T. Pino <Conrad@Pino.com>
+
+ * filesubr.c: Change <windows.h> to <sys/socket.h> which includes
+ <windows.h> through <winsock2.h> include.
+
+ * rcmd.c sockerror.c startserver.c unistd.c woe32.c: Change
+ <winsock.h> to <sys/socket.h> which includes <winsock2.h>.
+
+ * unistd.h: Change "gethostname" prototype to match <winsock2.h>.
+
+2005-09-25 Conrad T. Pino <Conrad@Pino.com>
+
+ * filesubr.c: New (get_system_temp_dir push_env_temp_dir) functions.
+
+2005-09-25 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.footer: Add "#pragma once" in "#ifdef _MSC_VER" block.
+ Add "#define HAVE_DECL__SNPRINTF 1" macro. Add "#include <direct.h>"
+ and "#define mkdir wnt_mkdir" macro. Add "mbsinit" implementation as
+ an inline function for Microsoft Visual C++ 6.0 only.
+
+ * config.h.in.in: Remove (GLOB_PREFIX HAVE_HSTRERROR HAVE_STRCASECMP
+ HAVE_STRSTR ST_MTIM_NSEC _SYS_CDEFS_H) macros which now obsolete.
+ Change (HAVE_ATEXIT HAVE_DECL_GETENV HAVE_DUP2 HAVE_ENVIRON_DECL
+ HAVE_ERRNO_DECL HAVE_GETHOSTNAME HAVE_ISASCII HAVE_MBLEN HAVE_MBRLEN
+ HAVE_MBSRTOWCS HAVE_MBSTATE_T HAVE_MEMCHR HAVE_MEMMOVE HAVE_PTRDIFF_T
+ HAVE_SEARCH_H HAVE_STRCHR HAVE_STRTOUL HAVE_STRUCT_STAT_ST_RDEV
+ HAVE_TZNAME HAVE_TZSET HAVE_WCSLEN HAVE_WCTYPE_H HAVE_WINT_T
+ HAVE_WMEMCHR HAVE_WMEMCPY) from "#undef ..." to "#define ... 1".
+ Change from "#define HAVE_DIRECT_H 1" to "#undef HAVE_DIRECT_H" since
+ some functions aren't POSIX compliant.
+ Change (SIZEOF_CHAR SIZEOF_DOUBLE SIZEOF_FLOAT SIZEOF_INT SIZEOF_LONG
+ SIZEOF_LONG_DOUBLE SIZEOF_PTRDIFF_T SIZEOF_SHORT SIZEOF_SIZE_T
+ SIZEOF_WINT_T) from "#undef ..." to "#define ... constant" where
+ "constant" is the size in Microsoft Visual C++ 6.0 for 32-bit API.
+ Add (ALLOW_CONFIG_OVERRIDE HAVE_BP_SYM_H HAVE_DECL_GETDELIM
+ HAVE_DECL_GETLINE HAVE_FLOCKFILE HAVE_FUNLOCKFILE HAVE_GAI_STRERROR
+ HAVE_GETADDRINFO HAVE_IPV6 HAVE_ISBLANK HAVE_LANGINFO_CODESET
+ HAVE_TCGETATTR HAVE_TCSETATTR HAVE_TERMIOS_H HAVE___FSETLOCKING
+ _REGEX_LARGE_OFFSETS) as "#undef ..." macro.
+ Add (HAVE_IPV4 HAVE_LOCALE_H HAVE_WCRTOMB HAVE_WCSCOLL) as
+ "#define ... 1" macro.
+ Add "#define strcasecmp rpl_strcasecmp" macro.
+
+ * config.h config.h.in: Regenerated on UNIX for "config.h.in.footer"
+ and "config.h.in.in" changes.
+
+ * filesubr.c mkdir.c: Add "#undef mkdir" to use Microsoft function.
+
+ * unistd.h: Don't include Microsoft "mkdir" function from here, done
+ in "config.h.in.footer" file per Derek Price.
+
+2005-09-22 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.footer: Move macros to correct section in sorted order.
+
+2005-09-21 Conrad T. Pino <Conrad@Pino.com>
+
+ * fix-msvc-mak.pl: Remove "basetsd" from "../lib/libcvs.dep".
+
+2005-09-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): s/netdb.c/netdb.h/.
+
+ * Makefile.am (EXTRA_DIST): Add netdb.h, sys/socket.h, & sys/types.h.
+
+2005-09-20 Conrad T. Pino <Conrad@Pino.com>
+
+ * netdb.h: Add empty file since Windows doesn't provide one.
+
+2005-09-19 Conrad T. Pino <Conrad@Pino.com>
+
+ * pwd.c: Replace include of "woe32.h" with "config.h" which
+ includes "woe32.h" to fix compile error in "lib/timespec.h"
+ that depends on "config.h".
+
+2005-09-19 Conrad T. Pino <Conrad@Pino.com>
+
+ * filesubr.c: Remove "extern char *Tmpdir" reference.
+
+2005-09-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-ch): Sub PACKAGE_STRING rather than reconstructing
+ it. Sub PACKAGE_BUGREPORT.
+ (stamp-chi): Fix grammar in comment.
+ * config.h.in.in (PACKAGE_BUGREPORT): Define macro.
+ (PACKAGE_STRING): Use $PACKAGE_STRING directly.
+
+2005-09-04 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (HAVE_PUTENV): Remove.
+
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * README, sys/types.h: Update links and email addresses.
+
+2005-08-12 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (HAVE_GETCWD): Remove this macro.
+
+2005-08-03 Jim Hyslop <jhyslop@dreampossible.ca>
+
+ * filesubr.c: don't expand "." to the name of the current directory.
+ * config.h, config.h.in, config.h.in.in: enabled HAVE_PRINTF_PTR and
+ HAVE_GETCWD.
+
+2005-07-12 Derek Price <derek@ximbiot.com>
+
+ * mkdir.c, startserver.c, woe32.c: Add copyright notices.
+
+2005-07-12 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.footer: Restore missing FIXME response.
+
+2005-07-11 Derek Price <derek@ximbiot.com>
+
+ * mkdir.c, startserver.c, woe32.c: Update license notices.
+
+2005-07-07 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.footer (WOE32): New macro.
+
+2005-06-10 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in: Remove HAVE_LSTAT_EMPTY_STRING_BUG,
+ HAVE_STAT_EMPTY_STRING_BUG, stat, and lstat definitions.
+ * config.h.in.footer: Add stat & lstat definitions.
+
+2005-05-31 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h, config.h.in, stamp-chi: Regenerated on Solaris for updates
+ to config.h.in.footer and config.h.in.in committed on Windows.
+
+2005-05-31 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.in: Change macros (gid_t,pid_t,uid_t) to #undef.
+ * pwd.c, pwd.h: Prototypes now (gid_t,uid_t) instead of "int".
+ * pwd.c: Stop useing "root:root" for "uid:gid" values.
+ * unistd.h: Use "windows-NT/sys/types.h" for definitions.
+
+2005-05-31 Conrad T. Pino <Conrad@Pino.com>
+
+ * unistd.c, unistd.c: Add new "usleep" function using "my_usleep"
+ logic taken from "woe32.c" file.
+ * woe32.c, woe32.h: Add new (woe32_home_dir,woe32_shell) functions.
+ * woe32.c: Modify "woe32_nanosleep" to use "unistd.h" "usleep".
+ * filesubr.c: Modify "get_homedir" to use "woe32_home_dir".
+ * pwd.c: Modify "getpwuid" to use "woe32_home_dir" & "woe32_shell".
+ Append "USERNAME" to "login_strings" array.
+
+
+2005-05-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * woe32.c, woe32.h: Move functions into alpabetical order.
+
+2005-05-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * woe32.c: Remove function (getpass,getpid,sleep) implementations.
+ * unistd.c: Add function (getpass,getpid,sleep) implementations.
+
+2005-05-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h, config.h.in, stamp-chi: Regenerated on Solaris for updates
+ to config.h.in.footer and config.h.in.in committed on Windows.
+
+2005-05-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * woe32.h: Create header file with ANSI style function prototypes.
+ * woe32.c: Use "woe32.h" header and ANSI style function prototypes.
+ Use minimal #include file set (#include "cvs.h" dropped). Rename:
+ function "init_winsock" to "woe32_init_winsock"
+ function "wnt_cleanup" to "woe32_cleanup"
+ function "nanosleep" to "woe32_nanosleep"
+ function "win32getlogin" to "woe32_getlogin"
+ Change function "sleep" return type to "unsigned int" was "unsigned".
+ * unistd.h: Move function (getpass,getpid,sleep) prototypes here.
+ * config.h.in.footer: Update 2 macros for the above changes:
+ #define SYSTEM_CLEANUP woe32_cleanup
+ #define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock()
+ Use "woe32.h" header file and remove function prototypes:
+ pid_t getpid (void);
+ void init_winsock (void);
+ unsigned int sleep (unsigned int);
+ void wnt_cleanup (void);
+ * config.h.in.in: Modify 3 macros:
+ #define HAVE_DECL_GETPASS 1 /* was 0 */
+ #define HAVE_DECL_NANOSLEEP 1 /* was #undef */
+ #define nanosleep woe32_nanosleep /* was #undef */
+ * pwd.c: Update to use "woe32.h" and renamed "woe32.c" function.
+
+2005-05-28 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (MISSING_SYS_CDEFS_H): Rename...
+ (_SYS_CDEFS_H): ...as this.
+
+2005-05-28 Conrad T. Pino <Conrad@Pino.com>
+
+ * run.c: Implement functions "run_add_arg_p" and "run_arg_free_p" by
+ copying from "../src/run.c" and change all K&R style function argument
+ declarations to ANSI style.
+
+2005-05-26 Derek Price <derek@ximbiot.com>
+
+ * pwd.h, pwd.c: Reformat to CVS conventions.
+
+2005-05-26 Derek Price <derek@ximbiot.com>
+
+ * ndir.h, ndir.c: Reformatting to CVS conventions.
+
+2005-05-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * filesubr.c: Remove "wnt_lstat" function. Collapse static function
+ "check_statbuf" logic into "wnt_stat" function body.
+
+2005-05-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h, config.h.in, stamp-chi: Regenerated on Solaris for updates
+ to config.h.in.footer and config.h.in.in committed on Windows.
+
+2005-05-26 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.footer: Reorganize into 3 sections (macros, typedefs and
+ function prototypes) and alphabetize each section. Synchronize with
+ GNULib import so Windows build succeeds.
+ * config.h.in.in: Synchronize with GNULib import so Windows build
+ succeeds.
+ * unistd.h: Include standard function prototypes from Microsoft files
+ to decrease warnings in GNULib import.
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (_POSIX_PTHREAD_SEMANTICS): Undef on Windows.
+
+2005-05-25 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (MISSING_SYS_CDEFS_H): Guess this should be defined.
+
+2005-05-23 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (xresolvepath): Remove this function.
+
+2005-05-17 Conrad T. Pino <Conrad@Pino.com>
+
+ * pwd.c, pwd.h: Add "const" modifier to "getpwnam" & "getgrnam" function
+ "char *" argument to elminate warning in "../lib/glob.c" module.
+
+2005-05-02 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in: Define LOCK_COMPATIBILITY.
+
+2005-04-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in.in: Syncronize with ../config.h.in file.
+ Added: #undef HAVE_DECL_MEMRCHR, #undef HAVE_PAM_PAM_APPL_H,
+ #undef HAVE_SECURITY_PAM_APPL_H
+ * config.h, config.h.in: Regenerated.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am, stdint.h: Updated from GNULIB.
+ * Makefile.in: Regenerated.
+
+2005-03-16 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (open_file): Remove this function.
+
+2005-03-09 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Remove mkconfig & fix-msvc-mak.
+ * Makefile.am (EXTRA_DIST): Include mkconfig.pl & fix-msvc-mak.pl.
+ (stamp-chi): Call $(PERL) mkconfig.pl explicitly.
+ * plhead.pl: Remove this file.
+ * mkconfig.pl, fix-msvc-mak.pl: Turn on warnings.
+
+2005-03-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h, config.h.in: Regenerate for config.h.in.in change.
+
+2005-03-07 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.in: Synchronize with ../config.h.in file.
+ Removed:
+ #define HAVE_GETCWD 1
+ #define HAVE_GETCWD_NULL 1
+ #undef HAVE_MKDIR
+ #undef HAVE_RENAME
+ #undef HAVE_VALLOC
+ Added:
+ #undef D_INO_IN_DIRENT
+ #undef HAVE_CFLOCALECOPYCURRENT
+ #undef HAVE_CFPREFERENCESCOPYAPPVALUE
+ #define HAVE_CHSIZE 1
+ #define HAVE_DECL___FPENDING 0
+ #define HAVE_DECL_GETCWD 1
+ #define HAVE_ISWPRINT 1
+ #undef HAVE_MAP_ANONYMOUS
+ #define HAVE_MBRTOWC 1
+ #undef HAVE_MBSINIT
+ #undef HAVE_MEMRCHR
+ #undef HAVE_NANOTIME
+ #undef HAVE_OPENAT
+ #undef HAVE_PARTLY_WORKING_GETCWD
+ #undef HAVE_POSIX_MEMALIGN
+ #define HAVE_STRTOL 1
+ #undef HAVE___FPENDING
+ #undef MAP_ANONYMOUS
+ #define PENDING_OUTPUT_N_BYTES ( fp ? fp->_ptr - fp->_base : 0 )
+ #undef RENAME_TRAILING_SLASH_BUG
+ #undef __GETCWD_PREFIX
+ #undef __OPENAT_PREFIX
+ #undef mkdir
+ #undef rename
+ Changed:
+ #undef HAVE_WCHAR_H replaced with #define HAVE_WCHAR_H 1
+ #undef HAVE_WCHAR_T replaced with #define HAVE_WCHAR_T 1
+
+2005-03-01 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.footer: Remove obsolete timeb stuff.
+
+2005-02-22 Derek Price <derek@ximbiot.com>
+
+ * run.c: Sync with src/run.c.
+ (Patch from Conrad Pino <conrad@pino.com>.)
+
+ * run.c (run_add_arg): Some cleanup.
+
+2005-02-22 Derek Price <derek@ximbiot.com>
+
+ * run.c: Remove several unneeded declarations.
+ (Suggestion from Conrad Pino <conrad@pino.com>.)
+
+2005-01-31 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notices.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-chi): Comment dist stamp-chi reasoning.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add stamp-chi.
+ (config.h.in, stamp-chi, DISTCLEANFILES, MAINTAINERCLEANFILES):
+ Reorganize for distributing stamp-chi.
+ * stamp-chi: Restore this file.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * stamp-chi: Remove this file - it is generated only in maintainer
+ mode.
+
+2004-11-29 Conrad T. Pino <Conrad@Pino.com>
+
+ * unistd.h: FIXME gethostname prototype for lib/xgethostname.c
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * mkconfig.pl (make_config_h): Use stricter regex to avoid warning of
+ the use of "#define" in comments.
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add JmgStat.c & JmgStat.h.
+ (Thanks to a report from Chris Bohn <cbohn@rrinc.com>.)
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add unistd.h.
+ (Thanks to a report from Chris Bohn <cbohn@rrinc.com>.)
+
+2004-11-17 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (getopt, getopt_long, getopt_long_only, optarg,
+ opterr, optind, optopt): Remove obsolete definitions.
+ (__GETOPT_PREFIX): Define this for GNULIB getopt.
+
+2004-11-16 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Remove stamp-chi.
+ ($(srcdir)/stamp-chi, $(srcdir)/config.h.in): Rename to...
+ (stamp-chi, config.h.in): Respectively, including associated required
+ target changes.
+
+2004-11-16 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-ch): Replace dependency on Makefile with a
+ dependency on configure.
+
+2004-11-16 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-chi, config.h.in): Rename to...
+ ($(srcdir)/stamp-chi, $(srcdir)/config.h.in): Respectively, including
+ associated required target changes.
+
+2004-11-16 Derek Price <derek@ximbiot.com>
+
+ * mkconfig.pl (save_copy): Revert previous change.
+ (make_config_h): Don't output full paths to generated comment.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * mkconfig.pl (save_copy): Try to deal with not having write
+ permissions.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * mkconfig.pl: Improve diagnostic messages.
+ (make_config_h): Don't use dir when creating temp file.
+ (save_copy): Use File::Copy::move to portably rename the file, possibly
+ across device boundries.
+
+2004-11-15 Derek Price <derek@ximbiot.com>
+
+ * mkconfig.pl (make_config_h): Improve diagnostic message.
+
+2004-11-11 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in.in (opterr): Define as rpl_opterr for consistency.
+ * config.h.in, config.h: Regenerated.
+
+2004-11-05 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (readlink): Removed. Use lib/readlink.c instead.
+
+2004-11-03 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in.in (_UINT32_T): Add from top-level config.h.in file.
+ * Makefile.in, config.h.in, config.h, stamp-chi: Regenerated.
+
+2004-11-02 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in.in (HAVE_DECL_FLOCKFILE, HAVE_DECL_FUNLOCKFILE,
+ HAVE_ENVIRON_DECL, HAVE_ERRNO_DECL, HAVE_SEARCH_H, HAVE_SETENV,
+ HAVE_TSEARCH, HAVE_UNSETENV, MALLOC_0_IS_NONNULL, VOID_UNSETENV):
+ Add new config options from top-level config.h.in using #undef.
+ Some of these probably exist under Windows and need to be defined.
+ (nanosleep): Move into alphabetical order.
+ (TRUST_OS_FILE_CACHE): Removed as obsolete.
+ * config.h.in, config.h, stamp-chi: Regenerated.
+
+2004-10-30 Mark D. Baushke <mdb@juniper.net>
+
+ * config.h.in.in, config.h.in, config.h: Regenerated
+
+2004-10-26 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (config.h.in): Allow this file to be built even when not
+ in maintainer mode when it is actually missing. Add comment.
+ (stamp-chi): Remove maintainer mode restriction. Add comments.
+
+2004-10-25 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (HAVE_RPMATCH): Undef this irrelevant macro on WOE32.
+
+2004-10-23 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.in: Change #undef HAVE_STDINT_H to #define ... 1.
+ Change #undef HAVE_STDINT_H_WITH_UINTMAX to #define ... 1.
+ * config.h.in: Regenerated for "config.h.in.in" change.
+ * config.h Regenerated for "config.h.in.in" change.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * .cvsignore: Ignore stamp-sh2
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.am (EXTRA_DIST): Add stdint.h.
+ * stdint.h: Regenerated.
+ * Makefile.in: Ditto.
+
+ * config.h.in.in (HAVE_SYS_INTTYPES_H): Update from GNULIB.
+ * Makefile.am (stamp-sh2): Add stdint from GNULIB.
+
+2004-10-22 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (UINT32_MAX, WORDS_BIGENDIAN, uint32_t): Guess that
+ these should all be undef on WOE32.
+
+2004-10-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h.in.footer (getpagesize): Define as 4096 because GNULIB
+ assumes it can include <sys/param.h> which is not available.
+ * config.h.in, config.h, stamp-chi: Regenerated.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (HAVE_OS_H): Undef this on Windoze.
+
+2004-10-20 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (select): Undef this for new sunos57-select.
+
+2004-10-20 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2004-10-15 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (HAVE_VASPRINTF): Define this for GNULIB.
+
+2004-10-11 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.in: Add #undef for "HAVE_STDIO_EXT_H", "HAVE_STRCASECMP",
+ "HAVE_STRNCASECMP", "HAVE_WMEMCHR" and "HAVE_WMEMCPY".
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (HAVE_DECL_FREE): Remove this define.
+
+2004-10-09 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (optopt, optind, optarg): Define these for GNULIB.
+
+2004-10-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Remove stripslash.c.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * mkconfig.pl: Check definition is defined, not false, before deciding
+ not to print it.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ Use getpass proto from getpass.h.
+ * config.h.in.in: Undo last defn.
+ * unistd.h (getpass): Remove proto.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in: Tell compiler we have a decl for getpass().
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in: Define use of replacement getopt functions.
+
+2004-10-06 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in: Undef HAVE_GETOPT_H and HAVE_GETOPT_LONG_ONLY. It
+ sounds like a fairly safe bet that Windoze doesn't have them.
+
+2004-10-06 Mark D. Baushke <mdb@cvshome.org>
+
+ * unistd.h: Add prototype entries for chdir and close
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in: s/FILESYSTEM/FILE_SYSTEM/ in keeping with GNULIB.
+
+2004-10-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * config.h.in.in: Add #define EOVERFLOW, HAVE_GETCWD, HAVE_GETCWD_NULL.
+ * config.h.in: Regenerated for "config.h.in.in" change.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (xresolvepath): s/xgetwd/xgetcwd/.
+
+2004-10-05 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in: #undef USE_UNLOCKED_IO.
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Remove TRUST_OS_FILE_CACHE.
+
+2004-09-17 Derek Price <derek@ximbiot.com>
+
+ * stripslash.c: Remove file.
+
+2004-09-14 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (cvs_casecmp): Moved to src/subr.c
+
+2004-09-09 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (check_statbuf): Remove unused variables.
+
+2004-09-08 Derek Price <derek@ximbiot.com>
+
+ * JmgStat.c, JmgStat.h: Convert to use UNIX line endings on UNIX.
+ (Thanks to report from Conrad T. Pino <conrad@pino.com>.)
+
+2004-09-07 Derek Price <derek@ximbiot.com>
+
+ * JmgStat.c, JmgStat.h: New files.
+ * filesubr.c (check_statbuf): Use new Windows mod time routine.
+ (Thanks to a report from Chris Bohn <cbohn@rrinc.com>, help from J. C.
+ Hamlin <jchamlin@ibsys.com>, and a published patch from Jonathan
+ Gilligan.)
+
+2004-09-02 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (PROXY_SUPPORT, TRUST_OS_FILE_CACHE): New defines.
+
+2004-06-24 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (restrict): Define empty for Windows.
+ (Patch submitted by Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-06-24 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in (HAVE_RUN_TZSET_TEST, my_strftime): Define to values
+ more appropriate for Windows.
+ (Original patch submitted by Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-06-22 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Add "inline" & "SIZE_MAX" macros for "xsize.h" header.
+ * config.h: Regenerated for "config.h.in" change.
+ (Original patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-06-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Remove some files that are included by
+ virtue of appearing in configure.in rules.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.footer (ssize_t): Move...
+ * config.h.in (size_t): ...here.
+ (MBLEN, MBRLEN, HAVE_RUN_TZSET_TEST, HAVE_STRFTIME,
+ TZSET_CLOBBERS_LOCALTIME_BUFFER, my_strftime, tzset): New macros.
+ * config.h.in, stamp-chi: Regenerated.
+
+2004-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-chi): Don't cross line boundries since this does
+ not work portably when @MAINTAINER_MODE_TRUE@ is replaced with a
+ comment. Add config.h.in.footer.
+ * Makefile.in: Regenerated.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-chi): This should be a copy of config.h.in, not
+ config.h.
+ * mkconfig.pl: Accept a -q argument to limit verbosity.
+ * Makefile.in, stamp-chi: Regenerated.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore recently removed stamp files & mkconfig.
+
+2004-05-19 Derek Price <derek@ximbiot.com>
+
+ * config.h.in.in, config.h.in.footer: New files.
+ (Original patch from Conrad Pino <conrad@pino.com>.)
+
+ * Makefile.am (config.h.in): New target.
+ (EXTRA_DIST): Add new files, fix-msvc-mak.pl, & plhead.pl. Remove
+ stamp-ch & stamp-sh.
+ (DISTCLEANFILES): Add stamp-ch & stamp-sh.
+ (MAINTAINERCLEANFILES): Add config.h.in & stamp-chi.
+ * stamp-ch, stamp-sh: Remove these files. There is no need to check in
+ targets that don't require maintainer tools to build.
+ * fix-msvc-mak-head.pl: Move to...
+ * plhead.pl: ...here.
+ * mkconfig.pl: New file.
+
+ * Makefile.in, config.h, config.h.in: Regenerated.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ * ndir.c, pwd.c: Include xmalloc.h.
+ (Patch from Conrad Pino <conrad@pino.com>.)
+
+2004-05-14 Derek Price <derek@ximbiot.com>
+
+ * woe32.c (my_usleep): Declare as static.
+ (Report from Conrad Pino <conrad@pino.com>.)
+
+2004-05-14 Derek Price <derek@ximbiot.com>
+
+ * woe32.c: Fix typo in last commit.
+ (Patch from Conrad Pino <conrad@pino.com>.)
+
+2004-05-14 Derek Price <derek@ximbiot.com>
+
+ * stamp-ch: Regenerated.
+
+2004-05-14 Derek Price <derek@ximbiot.com>
+
+ * woe32.c (usleep): Remove.
+ (my_usleep, nanosleep): New functions.
+ (Reported by Conrad Pino <conrad@pino.com>.)
+
+2004-05-12 Mark D. Baushke <mdb@cvshome.org>
+
+ * unistd.h: New file (to provide a getpass prototype).
+ * config.h.in (HAVE_UNISTD_H): #define instead of #undef.
+ * config.h: Regenerated.
+ (Original from Conrad Pino <conrad@pino.com>)
+
+2004-05-11 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (last_component): s/ISDIRSEP/ISSLASH/.
+
+2004-04-27 Derek Price <derek@ximbiot.com>
+
+ * config.h.in (FILENAMES_CASE_INSENSITIVE,
+ FILESYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX,
+ FILESYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR, FILESYSTEM_PREFIX_LEN,
+ ISSLASH): Define these.
+ * config.h, stamp-ch: Regenerated.
+
+2004-04-26 Derek Price <derek@ximbiot.com>
+
+ * fix-msvc-mak.pl: Default to RECURSE=1 for cvsnt.mak.
+
+2004-04-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (stamp-sh): s/\$\(HAVE__BOOL\)/0/. Windows does not
+ HAVE__BOOL.
+ * stdbool.h, stamp-sh, Makefile.in: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * stamp-ch: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add stdbool.h & stamp-sh.
+ (stdbool.h, stamp-sh): New targets.
+ * stdbool.h, stamp-sh: New files.
+ * Makefile.in: Regenerated.
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Don't define HAVE_ALLOCA. Let alloca_.h do it instead.
+ * config.h: Regenerated.
+
+2004-04-20 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (deep_remove_dir): Correct typo.
+
+2004-04-20 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (unlink_file_dir, deep_remove_dir): Handle errno of
+ ENOTEMPTY from dirs under Windows XP.
+ (Report and suggested fix from Ken Raeburn <raeburn@mit.edu>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Define HAVE_ALLOCA_H and HAVE_ALLOCA to get around the
+ dain bramage of a few GNULIB modules.
+ * config.h, stamp-ch: Regenerated.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * fix-msvc-mak.pl: Remove default build configuration hooks.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * fix-msvc-mak.pl: Set default build configuration to Debug.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * cvsntfix.pl: Rename to...
+ * fix-msvc-mak.pl: ...this.
+ * fix-msvc-mak-head.pl: New file.
+ * .cvsignore: Add fix-msvc-mak.
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * cvsntfix.pl: New file.
+ (Original from Conrad Pino <conrad@pino.com>.)
+
+2004-04-05 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (isabsolute): Remove this function for real.
+
+2004-04-04 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (isabsolute): Remove this function.
+
+2004-03-29 Derek Price <derek@ximbiot.com>
+
+ * README: Note makefiles geenerated with MSVC++ 5.x.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * README: Note MSVC pathing problem when exporting makefiles.
+
+2004-03-26 Derek Price <derek@ximbiot.com>
+
+ * README: Note build files generated using MSVC 6.0. Erase uneccessary
+ jab at Microsoft's inability to create a portable makefile.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Define realloc to rpl_realloc to use the version from
+ lib/realloc.c.
+ * config.h: Regenerated.
+
+2004-03-20 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (mkdir_if_needed, xchmod, last_component), run.c
+ (piped_child): Comply with new prototypes.
+
+2004-03-11 Derek Price <derek@ximbiot.com>
+
+ * config.h.in (SIZE_MAX): Define.
+
+2004-02-26 Derek Price <derek@ximbiot.com>
+
+ * config.h.in: Add definition for inline for GNULIB xalloc module.
+ * config.h, stamp-ch: Regenerated.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for 1.12.5.1.
+
+2003-12-18 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for release 1.12.5.
+
+2003-12-10 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Include code to put a warning at the beginning of the
+ generated config.h that it should not be edited and to edit config.h.in
+ instead.
+ * Makefile.in, config.h: Regenerated.
+
+2003-12-10 Derek Price <derek@ximbiot.com>
+
+ * config.h.in (SYSTEM_CLEANUP): That's because you need to change it
+ here.
+ * config.h: Regenerated.
+
+2003-12-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h (SYSTEM_CLEANUP): Update macro to be a name
+ replacement rather than a macro function. Note: This
+ change seems to be undone by 'autoreconf'.
+
+2003-12-10 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h (SYSTEM_CLEANUP): Update macro to be a name replacement
+ rather than a macro function.
+ (Patch from Rob Clevenger <rob@robsite.org>.)
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for release 1.12.4.1.
+
+2003-12-09 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for release 1.12.4.
+
+2003-12-05 Mark D. Baushke <mdb@cvshome.org>
+
+ * filesubr.c (xresolvepath): Comment out assert() call.
+
+2003-12-05 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for dev version 1.12.3.1.
+
+2003-12-04 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for release 1.12.3.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for 1.12.2.1.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * config.h, stamp-ch: Regenerated for 1.12.2.
+
+2003-10-27 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am (EXTRA_DIST): Add stamp-ch.
+ * Makefile.in: Regenerated.
+
+2003-07-30 Derek Price <derek@ximbiot.com>
+
+ * README: Correct name and links to the Cygwin project.
+ (Original patch from Max Bowsher <maxb@ukf.net>.)
+
+2003-07-17 Derek Price <derek@ximbiot.com>
+
+ * stamp-ch: Regenerated.
+
+2003-07-17 Larry Jones <lawrence.jones@eds.com>
+
+ * config.h.in (PROTOTYPES): Remove as per config.h.
+
+2003-07-16 Derek Price <derek@ximbiot.com>
+
+ * config.h (PROTOTYPES): Remove definition.
+ * filesubr.c: s/PROTO/.
+ * run.c: Ditto.
+
+2003-06-13 Derek Price <derek@ximbiot.com>
+
+ * filesubr.c (cvs_temp_file): Add a FIXME comment in regards to using
+ mkstemp() from GNULIB (already in lib/mkstemp.c).
+
+2003-06-11 Larry Jones <lawrence.jones@eds.com>
+
+ * filesubr.c (xresolvepath): Fix memory leak.
+ (Original patch from Kenneth Lorber <keni@his.com>.)
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-07-30 Derek Price <derek@ximbiot.com>
+
+ * README: Correct name and links to the Cygwin project.
+ (Original patch from Max Bowsher <maxb@ukf.net>.)
+
+2003-06-09 Derek Price <derek@ximbiot.com>
+
+ * win32.c (gethostname): Remove this function. It has been commented
+ out since 1995-08-30 and...
+ (*): ...move the rest of the contents...
+ * woe32.c: ...to this new file in accordance with the GNU convention to
+ avoid implying that we consider the Microsoft Windows Operating
+ Environment any sort of "win".
+ * Makefile.am (EXTRA_DIST): Rename win32.c woe32.c.
+
+ * Makefile.in: Regenerated.
+
+2003-06-04 Derek Price <derek@ximbiot.com>
+
+ * config.h.in (RSH_DFLT): Replace accidentally deleted macro.
+ (USE_PROTOTYPES): Move back to...
+ (PROTOTYPES): ...here.
+ (HAVE_STDLIB_H, HAVE_SYS_TYPES_H, HAVE_SYS_STAT_H, HAVE_MALLOC,
+ HAVE_REALLOC): New defines to sync with UNIX code.
+ * filesubr.c (locate_rcs, find_file_in_dir): Remove these functions
+ since they are now available in the generic source.
+
+ * config.h: Regenerated.
+
+2003-06-04 Derek Price <derek@ximbiot.com>
+
+ * config.h: Regenerated, but move the contents...
+ * config.h.in: ...into this new file first and stick a token in...
+ (PACKAGE_STRING): ...here in place of the CVS version number.
+ * Makefile.am (all-local, stamp-ch, config.h): New targets providing
+ for dynamic generation of config.h so that I can no longer forget to
+ update the version number in config.h when I update configure.in.
+ * stamp-ch: New file.
+
+ * Makefile.in: Regenerated.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-19 Derek Price <derek@ximbiot.com>
+
+ * config.h (PACKAGE_STRING): updated to 1.12.0.1;
+ changed USE_PROTOTYPES to PROTOTYPES
+ * filesubr.c: synchronized logic in deep_remove_dir() with
+ src/filesubr.c; copied xresolvepath(), cvs_casecmp(),
+ locate_file_in_dir(), and locate_rcs().
+ (Patch from Anthon Pang <apang@telus.net>.)
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * config.h (RSH_DFLT): Default to "rsh".
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-01-20 Derek Price <derek@ximbiot.com>
+
+ * config.h: Update to dev version 1.11.5.1.
+
+2003-01-16 Derek Price <derek@ximbiot.com>
+
+ * config.h: Update to CVS version 1.11.5.
+
+2003-01-16 Derek Price <derek@ximbiot.com>
+
+ * config.h (PACKAGE_STRING): Update for dev version (1.11.4.1).
+
+2002-12-28 Derek Price <derek@ximbiot.com>
+
+ * config.h (PACKAGE_STRING): Add FIXME.
+
+2002-12-28 Derek Price <derek@ximbiot.com>
+
+ * config.h (PACKAGE_STRING): Define.
+ * filesubr.c (strcat_filename_onto_homedir): New function.
+ (Thanks to Stephane Rouleau <s.rouleau@videotron.ca>,
+ Cristopher Seawood <cls@seawood.org>, and
+ Frederico Costa <frederico.costa@tiscali.no> for all their hints,
+ tips, and patches for this problem.)
+
+2002-12-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Remove reference to options.h.
+ * options.h: Remove file and move relevant content...
+ * config.h: ...here.
+
+ * Makefile.in: Regenerated.
+
+2002-12-06 Derek Price <derek@ximbiot.com>
+
+ * ndir.c: Replace some calls to malloc with calls to xmalloc.
+ * pwd.c: Ditto.
+ (Reported by Dan Peterson <dbpete@aol.com>.)
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove prototype of STDC exit().
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-09-24 Larry Jones <lawrence.jones@eds.com>
+
+ * options.h: Remove PATCH_PROGRAM.
+
+2002-08-16 Derek Price <derek@ximbiot.com>
+
+ * options.h: Remove RELATIVE_REPOS & move CVS_BADROOT...
+ * config.h: ...here.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2001-09-18 Derek Price <dprice@collab.net>
+
+ * win32.c: config.h should be #included with double quotes; and be the
+ first among the headers.
+ (Patch from Corey Minyard <minyard@acm.org> via
+ Alexey Mahotkin <alexm@hsys.msk.ru>.)
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * config.h: Back out the HAVE_GETPAGESIZE thing. That was a mistake.
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * config.h: Define ssize_t as int.
+ (Bug report and patch from "Manfred Klug" <manklu@web.de>.)
+
+2001-08-09 Derek Price <dprice@collab.net>
+
+ * config.h: Define HAVE_GETPAGESIZE under Windows.
+ (Bug report from "Manfred Klug" <manklu@web.de>.)
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2001-02-15 Derek Price <derek.price@openavenue.com>
+ Laine Stump <laine+info-cvs@laine.org>
+
+ * config.h: Define HAVE_USLEEP and define a prototype for usleep.
+ * win32.c (usleep): New function.
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+
+2000-11-21 Derek Price <derek.price@openavenue.com>
+
+ * filesubr.c (check_statbuf): subtract 3600 from the times returned
+ by the stat function when daylight savings time is in effect due to a
+ bug in Windoze. Fixes a bug where CVS thinks all files have been
+ touched after a transition to or from daylight savings time.
+
+2000-11-20 Derek Price <derek.price@openavenue.com>
+
+ * filesubr.c (cvs_temp_file): add this function to match the one in
+ src/filesubr.c
+ (cvs_temp_name): wrap cvs_temp_file as in src/filesubr.c
+
+2000-10-18 Derek Price <derek.price@openavenue.com>
+
+ * config.h: Add () to a macro function to supress a warning.
+
+2000-06-26 Larry Jones <larry.jones@sdrc.com>
+
+ * config.h: Define REGEX_MALLOC and _REGEX_RE_COMP.
+
+2000-01-02 Karl Fogel <kfogel@red-bean.com>
+
+ * pwd.c (getlogin): try to find login name in environment
+ variables before asking the operating system.
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * options.h: Make RELATIVE_REPOS the default, as in
+ ../src/options.h.in.
+ Remove CVS_DIFFDATE; removed from CVS on 27 Jun 1996.
+
+1998-10-13 Jim Kingdon
+
+ * README: Update information about make/project files, cygwin and
+ the (lack of) need for RCS 5.7. Tweak a few more things.
+
+1998-10-03 Jim Kingdon
+
+ * win32.c: Include cvs.h and only check server_active if
+ SERVER_SUPPORT is defined.
+
+1998-10-02 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ (This was reported by someone else but I don't remember who).
+ * config.h: Define SYSTEM_CLEANUP.
+ * win32.c (wnt_cleanup): New function, implements it.
+
+1998-09-28 Johannes Stezenbach <johannes.stezenbach@propack-data.de>
+ and Jim Kingdon
+
+ * config.h (CVS_RENAME): Define.
+ * filesubr.c, config.h (wnt_rename): New function.
+ * filesubr.c (rename_file): Call CVS_RENAME not rename.
+
+1998-09-04 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * win32.c (gethostname): Expand comment about gethostname
+ vs. GetComputerName (reported by Randy Coulman).
+
+1998-07-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * startserver.c (wnt_shutdown_server): Check for errors from close().
+
+1998-06-30 Noel Cragg
+
+ * startserver.c: add a global variable which notes if we've opened
+ a socket. Since the code in client.c will call wnt_shutdown_server
+ regardless of which client method we've selected, we need to make
+ sure and not call shutdown or closesocket on a pipe (it won't work).
+ (wnt_shutdown_server): use the new global to decide whether or not
+ to call socket routines or simply use close.
+
+
+1998-06-11 Jim Kingdon
+
+ * config.h (CVS_STAT, CVS_LSTAT): Define.
+ * filesubr.c, config.h (wnt_stat, wnt_lstat, check_statbuf):
+ New functions.
+
+1998-04-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (link_file): Remove; no longer used.
+
+Tue Feb 17 02:31:41 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * filesubr.c (last_component): return the top-level directory when
+ asked about the top-level directory.
+
+Fri Jan 16 00:57:31 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Remove. As far as I know the Windows hacks in this
+ file have been superceded by improvements to Cygwin and/or Ian's
+ recent changes to src/sanity.sh. The ones I noticed: we had been
+ working around lack of /dev/null (apprently Cygwin now has it); we
+ had been not expecting rm -rf to delete readonly files (apparently
+ it now does); there was an issue with case of arguments passed on
+ command line (it would seem like Cygwin has changed this).
+ I also notice that the file had not even been in the distribution
+ because it was missing from Makefile.in (ugh).
+
+13 Jan 1998 Jim Kingdon
+
+ * run.c (run_exec): Change parameters from char * to const char *.
+
+Tue Jan 13 16:57:56 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * config.h (FOLD_FN_CHAR): Don't define; instead move to
+ lib/system.h, where it is defined conditionally.
+ (FILENAMES_CASE_INSENSITIVE, ISDIRSEP): Likewise.
+ (WNT_filename_classes, fncmp, fnfold): Likewise for declarations.
+ * filesubr.c (WNT_filename_classes): Remove; now in lib/fncase.c.
+ (fncmp, fnfold): Likewise.
+
+Tue Jan 13 13:15:34 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c: Adjust run_setup for new calling convention.
+
+ * config.h (DIFF): Remove; no longer used.
+ * options.h (DIFF, RCSBIN_DFLT): Remove; no longer used.
+
+Wed Dec 31 10:56:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h, filesubr.c (convert_file): Remove; no longer used
+ (except for BROKEN_READWRITE_CONVERSION which doesn't apply).
+
+Sat Dec 27 16:57:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (HAVE_RCS5): Remove; no longer used.
+
+ * config.h (LINES_CRLF_TERMINATED): Remove; no longer used.
+
+Tue Dec 23 08:28:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Change bug-cvs address from prep.ai.mit.edu to gnu.org
+ per email from Martin Hamilton.
+
+Sun Nov 30 18:03:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (run_args): Remove; nowhere used.
+
+Sat Nov 29 22:21:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove declaration of getwd; see lib/ChangeLog for
+ rationale.
+
+Wed, 12 Nov 1997 Jim Kingdon
+
+ * config.h: Define same_file.
+
+Sun, 9 Nov 1997 Jim Kingdon
+
+ * config.h: Define HAVE_SETMODE.
+
+Mon Nov 10 11:15:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (call_diff, call_diff3): Removed, per change to
+ src/rcscmds.c.
+
+Fri Oct 31 16:52:30 1997 Abe Feldman
+
+ * config.h: Define UTIME_EXPECTS_WRITABLE.
+
+Tue Oct 28 14:50:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c: Also define call_diff and call_diff3.
+
+Sat Sep 13 20:13:09 1997 <Martin.Sjoelin@ubs.ch>
+ indentation/whitespace fixes by Jim Kingdon
+
+ * run.c (quote): quote any " included in argument string to
+ avoid having ci choke on message string format.
+
+Sun Sep 7 19:59:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Add section on coding standards (win32, ANSI, &c).
+
+Fri Aug 29 19:13:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (isabsolute): Add comment about interaction with
+ strip_trailing_slashes (reported by Jin S Choi <jsc@w3health.com>).
+
+Thu Aug 28 12:06:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (link_file): Remove #if 0'd version; the real version
+ is elsewhere in this file.
+
+Sun Aug 10 21:08:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * ndir.c, ndir.h, pwd.c, pwd.h: Remove $Header; we decided to
+ get rid of these some time ago.
+
+Sun Aug 3 21:14:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Note KLUDGE_FOR_WNT_TESTSUITE when discussing tests.
+
+Fri Jul 18 09:49:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Adjust discussion of makefiles to deal with Visual C++
+ 5.x. One doesn't need patch if client and server are current.
+
+10 Jul 1997 Jim Kingdon
+
+ * config.h: Define USE_SETMODE_STDOUT.
+
+8 Jul 1997 Jim Kingdon
+
+ * rcmd.c (rcmd_authenticate): With error message, print the
+ user names that we were attempting to use.
+ * win32.c (win32getlogin): If GetUserName returns "", return
+ NULL.
+
+Sun, 22 Jun 1997 Jim Kingdon
+
+ * win32.c: Also include winsock.h.
+ Include stdlib.h (for exit()).
+ * rcmd.c: Move include of cvs.h above test of HAVE_WINSOCK_H.
+
+Tue Jun 17 16:35:06 1997 Jim Kingdon (unknown@beezley)
+
+ * rcmd.c: Check HAVE_WINSOCK_H in figuring out which files
+ to include (see comment about making this portable). If not
+ HAVE_WINSOCK_H, make various #definitions.
+ * rcmd.c (init_winsock): Move from here...
+ * win32.c: ...to here.
+ * rcmd.c (bind_and_connect, resolve_address): Shut up gcc -Wall
+ (which doesn't know that error (1, ...) doesn't return).
+
+Sun Jun 8 23:43:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h (HAVE_MKFIFO): Remove; not used anywhere.
+
+Sat May 3 11:15:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcmd.c: Add "copyright" notice.
+
+Thu Apr 17 00:15:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: Add sockerror.c.
+
+Wed Apr 9 15:29:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (expand_wild): Add comments about "." and comparing
+ NULL pointers.
+
+8 Apr 1997 Jim Kingdon
+
+ * rcmd.c: Instead of returning -1 and passing that back to
+ startserver.c which will print a very vague error message, call
+ error() right away with a specific message. This also fixes
+ some places where we had bogusly called GetLastError instead of
+ WSAGetLastError.
+ (init_winsock): Remove call to setsockopt. It was an artifact
+ from before the time that we defined NO_SOCKET_TO_FD, doesn't
+ seem to be needed any more, and fails with some non-Microsoft
+ winsock implementations.
+
+Wed Apr 2 14:08:10 1997 Vince Del Vecchio <vdelvecc@spd.analog.com>
+ and Jim Kingdon
+
+ * sockerror.c: New file.
+ * config.h (SOCK_STRERROR, SOCK_ERRNO): New macros.
+ * startserver.c: In reporting errors from socket calls, use
+ SOCK_STRERROR and SOCK_ERRNO since strerror(errno) doesn't work
+ for Win32.
+ * rcmd.c (rcmd_authenticate): Use WSASetLastError instead of
+ assigning to errno, since that is where the caller will look.
+
+Sun Apr 6 17:22:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (copy_file): Add comment about CopyFile.
+
+Wed Mar 26 13:13:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Also mention tar and gzip.
+
+ * README: Binaries are now under 1.9, not 1.8.3, on
+ ftp.cyclic.com. Also mention http URL.
+
+13 Mar 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (get_homedir): Allocate pathbuf; removes arbitrary
+ limit.
+
+Wed Mar 12 16:10:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (get_homedir): Expand comment about HOME
+ vs. HOMEDRIVE/HOMEPATH.
+
+ * config.h (HAVE_SETVBUF): Removed; no longer used.
+
+Thu Mar 6 19:46:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: tab stop setting apparently was under "Editor" in Visual
+ C++ 2.x but it is under "Tabs" in Visual C++ 4.x.
+ List number of warnings for regex.c (103, which is actually down
+ from 121 prior to the change I just made to regex.c).
+
+Sat Feb 15 15:27:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (dist-dir): Also handle SUBDIRS.
+ (SUBDIRS): New variable.
+
+Wed Jan 29 18:28:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h, options.h (GREP): Remove; no longer used.
+
+Tue Jan 28 18:29:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Remove SIZEOF_INT and SIZEOF_LONG; no longer needed
+ with lib/md5.c changes.
+
+1997-01-08 Jim Kingdon
+
+ * filesubr.c (expand_wild): If we just find a file (that
+ is, without expanding a wildcard), return the file name
+ as specified rather than as it exists in the filesystem.
+
+Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c, ndir.c, ndir.h, pwd.c, pwd.h, run.c, stripslash.c:
+ Remove "675" paragraph; see ../ChangeLog for rationale.
+
+Wed Jan 1 22:51:01 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Reword comment for TMPDIR_DFLT to make it clear that
+ this isn't specific to the pserver server.
+
+Tue Dec 31 14:17:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Remove another mention of grep; CVS no longer uses it.
+
+Tue Dec 31 11:01:29 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * README: Add note that the various support utilities can also be
+ found at the Cyclic FTP site; things move around on the net.
+
+Tue Dec 31 12:33:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Add note about lack of need for rsh. I don't know if
+ this is the best place to talk about this, but many people get
+ confused by it.
+
+Sat Nov 30 15:33:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Grep is no longer required. Specify when gzip is required.
+
+Tue Nov 19 17:19:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (SOURCES): Remove strippath.c.
+ * strippath.c: Removed.
+
+Sun Nov 10 22:54:04 1996 Paul Sanders <p.sanders@dial.pipex.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (run_popen): Save and restore file descriptors.
+
+Fri Oct 18 16:54:00 1996 Tony Brusseau <brusseau@jprc.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * strippath.c (strip_path): Leave leading "\\" unmolested for UNC.
+
+Thu Oct 17 10:57:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Clarify who it is who needs to be able to mount the
+ repository.
+
+Mon Oct 14 08:30:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Remove item about markso Win95 web site now that it is
+ merged in. Mention Win95 at beginning.
+
+Tue Oct 8 12:37:54 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * options.h (HAD_RCS4): Remove; no longer used.
+
+Wed Sep 25 14:31:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h (TMPDIR_DFLT): Change from c:\temp to c:\\temp.
+
+Tue Sep 24 14:37:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Add TMPDIR_DFLT.
+
+Tue Sep 10 19:20:25 1996 Mark A. Solinski <markso@mcs.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ This is said to be the last set of changes needed for Win95:
+ * rcmd.c: Include cvs.h.
+ (rcmd_authenticate): Use send/recv instead of read/write.
+ (rcmd): Don't call _open_osfhandle; just return the socket.
+ * options.h: Move NO_SOCKET_TO_FD from here...
+ * config.h: ...to here. Update comment.
+ * config.h (START_SERVER_RETURNS_SOCKET, SEND_NEVER_PARTIAL):
+ Define.
+ * startserver.c (shutdown_fd): Remove; it is unused.
+ (wnt_start_server): Don't dup the file descriptor; instead set
+ both *tofd and *fromfd to read_fd.
+ (wnt_shutdown_server): Don't call _get_osfhandle; just use the
+ argument as the socket.
+
+Wed Sep 4 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * filesubr.c (mkdir_if_needed): mkdir on NT only takes one,
+ not two, arguments.
+
+Thu Aug 29 09:47:33 1996 Mark A. Solinski <markso@mcs.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (deep_remove_dir, unlink_file_dir): ENOENT can also
+ mean that we tried to unlink a directory (Win95).
+
+Mon Aug 26 12:47:58 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (mkdir_if_needed): Added.
+
+Thu Aug 22 19:12:17 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ The following changes are said to be necessary (but not
+ sufficient) for Win95:
+ * config.h (sleep): Use "unsigned int" not just "unsigned".
+ * filesubr.c (deep_remove_dir): Treat EACCES as well as ENOTEMPTY
+ as an indication that we need to remove the directory.
+
+Fri Aug 16 16:06:22 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in (installdirs): new (empty) target
+
+Mon Aug 12 14:45:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Remove CLIENT_ONLY; it is nowhere used.
+
+Mon Jul 15 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * README: Add note about tab stop setting.
+
+Fri Jun 7 13:07:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Change INITIALIZE_SOCKET_SUBSYSTEM to
+ SYSTEM_INITIALIZE to reflect change in ../src/main.c.
+
+Mon Jun 03 01:00:08 1996 noel <noel@BOAT_ANCHOR>
+
+ * sanity.sh: include new tests from ../src/sanity.sh.
+
+ * filesubr.c (copy_file): use open with O_CREAT instead of creat
+ so we can also use O_BINARY -- we don't want to do any LF -> CR/LF
+ translations when we copy files.
+
+Fri May 17 11:53:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: In a few places it used to say "server" when it meant
+ "client". Fix it. Say explicitly that there is no server on NT.
+ Fix typos (4,0 -> 4.0; CVS.system -> CVS).
+
+Thu May 16 16:52:45 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * README: explain which utilities are required for client support
+ and local support in separate paragraphs.
+
+ * filesubr.c (expand_wild): rename max to cvs_max to avoid
+ conflicts with other already-defined routines.
+ (get_homedir): rename min to cvs_min.
+
+Thu May 16 01:18:22 1996 noel <noel@BOAT_ANCHOR>
+
+ * sanity.sh: Hacked version of src/sanity.sh for use under
+ CYGWIN32.
+
+ * filesubr.c (expand_wild): Since FindFirstFile and FindNextFile
+ don't return the pathname of a file, we need to keep track of it
+ ourselves.
+
+ * options.h: Fix defines for DIFF and GREP.
+
+ * run.c (run_exec): Flush stdout and stderr so we end up with the
+ correct interleaving of output for sanity.sh. This can be removed
+ later, if desired.
+
+Wed May 15 23:51:49 1996 Noel Cragg <noel@gargle.rain.org>
+
+ * README: mention that grep is mandatory.
+
+Tue May 14 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * filesubr.c (cvs_temp_name): Call _tempnam not tmpnam.
+
+Tue May 14 13:38:51 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (cvs_temp_name): New function..
+
+Wed May 01 01:28:41 1996 noel <noel@BOAT_ANCHOR>
+
+ * filesubr.c (get_homedir): use both HOMEDRIVE and HOMEPATH to
+ construct the user's home directory.
+
+Tue Apr 9 20:56:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Mention CRLF for src/server.c.
+
+Mon Mar 25 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * filesubr.c (expand_wild): New function.
+
+Tue Mar 19 17:55:39 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * startserver.c (wnt_start_server): Cleaned up code to get port
+ (and thus made consistent with VMS and Mac)
+
+Mon Mar 18 14:54:50 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * config.h: Don't declare gethostname; main.c already includes
+ winsock.h. Define FILENAMES_CASE_INSENSITIVE.
+
+Fri Mar 15 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * filesubr.c (fncmp): Fix typo (n1 -> n2) which had caused the
+ function to always return 0.
+
+Thu Mar 7 08:55:39 1996 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (HEADERS): Remove alloca.h from list.
+
+Wed Feb 28 11:08:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove AUTH_SERVER_SUPPORT; no longer should be
+ defined in options.h.
+
+ * config.h: Remove C_ALLOCA, CRAY_STACKSEG_END, HAVE_ALLOCA,
+ HAVE_ALLOCA_H, and STACK_DIRECTION to reflect alloca removal.
+ * startserver.c (wnt_start_server): Don't use alloca.
+ * alloca.h: Removed.
+
+Fri Feb 23 18:00:00 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * options.h: Define AUTH_CLIENT_SUPPORT and NO_SOCKET_TO_FD.
+ * config.h: Define HAVE_WINSOCK_H.
+ * win32.c (getpass): New function.
+ * filesubr.c (get_homedir): New function.
+
+Mon Feb 12 16:09:24 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * run.c (run_popen): Changed more Popen() to run_popen()
+
+Mon Feb 12 03:33:27 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * run.c: Changed Popen() to run_popen() for the benefit of
+ case-insensitive linkers (VMS) which confuse Popen() with popen()
+
+Fri Feb 9 22:10:12 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (distclean): Remove Makefile.
+
+ * config.h: Remove SYSTEM_COMMENT_TABLE.
+
+Thu Feb 1 15:09:17 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Remove RM; no longer used.
+
+ * filesubr.c: Remove rcsid.
+
+Thu Jan 11 16:01:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Update with information for Visual C++ 4.0, some
+ warnings that weren't mentioned, etc.
+
+Thu Jan 11 12:04:42 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * options.h: remove CVS_NOADMIN
+
+Wed Jan 3 16:17:19 1996 Jon Dart <jdart@tss.com>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * run.c (filter_stream_through_program): If pidp is NULL, don't
+ store to *pidp.
+ * ndir.h: Change MAXNAMLEN to 255.
+ * run.c (build_command): Deal with it if there are no arguments at
+ all.
+
+Mon Jan 1 23:40:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (link_file): New function.
+
+ * README: Mention CRLF vs. LF in cvsnt.mak. Other minor revisions.
+
+Fri Dec 22 12:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * run.c (filter_stream_through_program): On error, error() rather
+ than returning -1.
+
+Thu Dec 21 16:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com>
+
+ * options.h: Don't define NO_SOCKET_TO_FD.
+
+Mon Dec 18 09:57:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h: Explain NO_SOCKET_TO_FD some more.
+
+Sun Dec 17 21:19:18 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h (NO_SOCKET_TO_FD): define to 1.
+
+Tue Dec 12 19:18:00 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * options.h (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): these
+ replace CVS_LOGIN.
+ (RCSBIN_DFLT): expand comment.
+
+Mon Dec 11 12:43:35 1995 adamg <adamg@microsoft.com>
+
+ * config.h: Add INITIALIZE_SOCKET_SUBSYSTEM macro to ensure that
+ winsock is initialized early enough for the gethostname() in
+ main.c to succeed.
+ * rcmd.c: Remove from init_winsock(), and rcmd() code that
+ initialized winsock on demand.
+
+Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com)
+
+ * filesubr.c (isaccessible): Rename from isaccessable.
+ Update callers.
+
+Mon Dec 4 10:46:31 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * The following change was copied from src/filesubr.c. This is
+ because we need filesubr.c to compile, not because we are trying
+ to make set*id work on NT (if it even has set*id).
+ * filesubr.c (isaccessable): new function. Checks access-rights
+ for files like access(), but is getxid-safe. Falls back to
+ access() if SETXID_SUPPORT is not enabled.
+ (isfile): replace stat() by isaccessable(file, F_OK)
+ (isreadable): replace access() by isaccessable()
+ (iswritable): ditto
+ (make_directory): rename local variable buf to sb
+
+Fri Nov 24 11:17:16 EST 1995 Boleslaw Ciesielski <bolek@viewlogic.com>
+
+ * filesubr.c (convert_file): Pass S_IWRITE to open when creating
+ file (fixes problem with deleting temporary files).
+
+Fri Nov 24 11:12:47 1995 Boleslaw Ciesielski <bolek@viewlogic.com>
+
+ * run.c (build_command): Move len++ inside loop, to make room for
+ spaces between arguments.
+
+Thu Oct 26 10:12:51 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Say that patch is required, not optional.
+
+Wed Oct 25 07:40:17 1995 Noel Cragg <noel@virtual.office.com>
+
+ * startserver.c (wnt_start_server): removed NTOHS call; since the
+ resulting number was passed as the port number to rcmd which
+ called NTOHS again, we did a complicated NOOP.
+
+Tue Oct 24 10:59:03 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in: insert autoconf variables. This allows e.g. make
+ dist to work when configure was called from within a subdir.
+
+ * Makefile.in (dist): replace by rule which honors $(srcdir)
+
+Mon Oct 23 18:51:49 1995 Karl Fogel <kfogel@floss.cyclic.com>
+
+ * Makefile.in (clean): new rule, does nothing but satisfy
+ top-level Makefile's beliefs about what its children can do.
+
+Fri Oct 20 11:09:55 1995 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * config.h: use same layout and comments as current ../config.h.in
+
+ * options.h: as above for ../src/options.h.in
+
+Tue Oct 10 16:04:18 1995 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Update to remove obsolete information (e.g. ftp
+ distributions).
+
+Thu Oct 5 17:28:52 1995 Kevin Layer <layer@franz.com>
+
+ * filesubr.c: Add semicolon after USE.
+
+Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * config.h (CVS_SUPPORT): #define this.
+
+ * ndir.c (opendir): Make the directory name argument a const
+ char *, instead of just a char *.
+ * ndir.h (opendir): Extern declaration changed to match.
+
+Thu Aug 31 12:00:08 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Makefile.in (HEADERS, SOURCES): New variables.
+ (DISTFILES): Refer to them, and include README, Makefile.in, and
+ .cvsignore.
+
+ * filesubr.c (unlink_file_dir, deep_remove_dir): New functions,
+ originally added to src/filesubr.c and then adapted here for
+ Windows NT.
+
+Wed Aug 30 15:39:57 1995 Jim Blandy <jimb@totoro.cyclic.com>
+
+ * Windows NT port merged.
+ * README, config.h, filesubr.c, mkdir.c, ndir.c, ndir.h,
+ options.h, pwd.c, pwd.h, rcmd.c, rcmd.h, run.c, startserver.c,
+ strippath.c, stripslash.c, waitpid.c, win32.c: Changed or added.
+
+Thu Aug 10 13:30:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * filesubr.c, mkdir.c, pwd.c, run.c, win32.c: New source files.
+ * pwd.h: New header file.
+
+Wed Jul 19 18:00:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * alloca.h: New file.
+
+ * config.h (HAVE_IO_H): Define this.
+
+Tue Jul 18 21:18:00 1995 Jim Blandy <jimb@cyclic.com>
+
+ * config.h, options.h, pwd.h: New files.
diff --git a/windows-NT/JmgStat.c b/windows-NT/JmgStat.c
new file mode 100644
index 0000000..b339577
--- /dev/null
+++ b/windows-NT/JmgStat.c
@@ -0,0 +1,214 @@
+//
+// Original Authors: Jonathan M. Gilligan, Tony M. Hoyle
+//
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Modification History:
+// 18 May 2001, JMG -- First version
+
+#include <windows.h>
+#include <tchar.h>
+#include <time.h>
+#include <stdbool.h>
+
+#include "JmgStat.h"
+
+
+/* Tony Hoyle's function for testing whether a given volume uses UTC or
+ * local time to record file modification times
+ *
+ * Reproduced here with permission of Tony Hoyle.
+ *
+ * This code is copyright by Tony Hoyle and is licensed under the Gnu
+ * Public License. (See above)
+ *
+ * NTFS, HPFS, and OWFS store file times as UTC times.
+ * FAT stores file times as local time.
+ *
+ * INPUTS:
+ * LPCSTR name: fully qualified path
+ *
+ * OUTPUTS:
+ * Return true if the file system on the volume in question
+ * stores file times as UTC
+ */
+bool IsUTCVolume ( LPCTSTR name )
+{
+ _TCHAR szDrive[_MAX_DRIVE + 1] = _T("");
+ _TCHAR szFs[32]=_T("");
+ _tsplitpath(name, szDrive, NULL, NULL, NULL);
+
+ _tcscat(szDrive, _T("\\"));
+ GetVolumeInformation( szDrive, NULL, 0, NULL, NULL, NULL, szFs, 32 );
+ return ! ( _tcsicmp( szFs, _T("NTFS") )
+ && _tcsicmp( szFs, _T("HPFS") )
+ && _tcsicmp( szFs, _T("OWFS") ) );
+}
+
+/* Convert a file time to a Unix time_t structure. This function is as
+ * complicated as it is because it needs to ask what time system the
+ * filetime describes.
+ *
+ * INPUTS:
+ * const FILETIME * ft: A file time. It may be in UTC or in local
+ * time (see local_time, below, for details).
+ *
+ * time_t * ut: The destination for the converted time.
+ *
+ * bool local_time: TRUE if the time in *ft is in local time
+ * and I need to convert to a real UTC time.
+ *
+ * OUTPUTS:
+ * time_t * ut: Store the result in *ut.
+ */
+static bool FileTimeToUnixTime ( const FILETIME* ft, time_t* ut, bool local_time )
+{
+ bool success = FALSE;
+ if ( local_time )
+ {
+ struct tm atm;
+ SYSTEMTIME st;
+
+ success = FileTimeToSystemTime ( ft, &st );
+
+ /* Important: mktime looks at the tm_isdst field to determine
+ * whether to apply the DST correction. If this field is zero,
+ * then no DST is applied. If the field is one, then DST is
+ * applied. If the field is minus one, then DST is applied
+ * if the United States rule calls for it (DST starts at
+ * 02:00 on the first Sunday in April and ends at 02:00 on
+ * the last Sunday in October.
+ *
+ * If you are concerned about time zones that follow different
+ * rules, then you must either use GetTimeZoneInformation() to
+ * get your system's TIME_ZONE_INFO and use the information
+ * therein to figure out whether the time in question was in
+ * DST or not, or else use SystemTimeToTzSpecifiedLocalTime()
+ * to do the same.
+ *
+ * I haven't tried playing with SystemTimeToTzSpecifiedLocalTime()
+ * so I am nor sure how well it handles funky stuff.
+ */
+ atm.tm_sec = st.wSecond;
+ atm.tm_min = st.wMinute;
+ atm.tm_hour = st.wHour;
+ atm.tm_mday = st.wDay;
+ /* tm_mon is 0 based */
+ atm.tm_mon = st.wMonth - 1;
+ /* tm_year is 1900 based */
+ atm.tm_year = st.wYear>1900?st.wYear - 1900:st.wYear;
+ atm.tm_isdst = -1; /* see notes above */
+ *ut = mktime ( &atm );
+ }
+ else
+ {
+
+ /* FILETIME = number of 100-nanosecond ticks since midnight
+ * 1 Jan 1601 UTC. time_t = number of 1-second ticks since
+ * midnight 1 Jan 1970 UTC. To translate, we subtract a
+ * FILETIME representation of midnight, 1 Jan 1970 from the
+ * time in question and divide by the number of 100-ns ticks
+ * in one second.
+ */
+
+ /* One second = 10,000,000 * 100 nsec */
+ const ULONGLONG second = 10000000L;
+
+ SYSTEMTIME base_st =
+ {
+ 1970, /* wYear */
+ 1, /* wMonth */
+ 0, /* wDayOfWeek */
+ 1, /* wDay */
+ 0, /* wHour */
+ 0, /* wMinute */
+ 0, /* wSecond */
+ 0 /* wMilliseconds */
+ };
+
+ ULARGE_INTEGER itime;
+ FILETIME base_ft;
+
+ success = SystemTimeToFileTime ( &base_st, &base_ft );
+ if (success)
+ {
+ itime.QuadPart = ((ULARGE_INTEGER *)ft)->QuadPart;
+
+ itime.QuadPart -= ((ULARGE_INTEGER *)&base_ft)->QuadPart;
+ itime.QuadPart /= second;
+
+ *ut = itime.LowPart;
+ }
+ }
+ if (!success)
+ {
+ *ut = -1; /* error value used by mktime() */
+ }
+ return success;
+}
+
+/* Get file modification time using FileTimeToUnixTime()
+ *
+ * INPUTS:
+ * LPCTSTR name: the file name
+ */
+bool GetUTCFileModTime ( LPCTSTR name, time_t * utc_mod_time )
+{
+ WIN32_FIND_DATA find_buf;
+ FILETIME mod_time;
+ HANDLE find_handle;
+ bool success = FALSE;
+
+ * utc_mod_time = 0L;
+
+ find_handle = FindFirstFile ( name, &find_buf );
+ success = ( find_handle != INVALID_HANDLE_VALUE );
+ if (success)
+ {
+ /* Originally I thought that I needed to apply a correction
+ * LocalTimeToFileTime() to files from FAT volumes, but the
+ * FindFirstFile() system call thoughtfully applies this
+ * correction itself.
+ *
+ * Thus, the file time returned is allegedly in UTC.
+ *
+ * However, the correction from local to UTC is applied
+ * incorrectly (Thanks a lot, Microsoft!). As documented in the
+ * Win32 API (see MSDN or the PSDK), DST is applied if and only
+ * if the computer's system time is in DST at the time we call
+ * FindFirstFile(), irrespective or whether DST applied at the
+ * time the file was modified!
+ *
+ * Thus, we have to call FileTimeToLocalFileTime() to undo
+ * Windows's good intentions. We correctly translate the time
+ * In FileTimeToUnixTime().
+ *
+ */
+ if ( IsUTCVolume ( name ) )
+ {
+ mod_time = find_buf.ftLastWriteTime;
+ success = FileTimeToUnixTime ( &mod_time, utc_mod_time, FALSE );
+ }
+ else
+ {
+ // See notes above...
+ success = FileTimeToLocalFileTime ( &find_buf.ftLastWriteTime, &mod_time );
+ success = success && FileTimeToUnixTime ( &mod_time, utc_mod_time, TRUE );
+ }
+ }
+ FindClose ( find_handle );
+ return success;
+}
diff --git a/windows-NT/JmgStat.h b/windows-NT/JmgStat.h
new file mode 100644
index 0000000..0c6d95d
--- /dev/null
+++ b/windows-NT/JmgStat.h
@@ -0,0 +1,4 @@
+#ifndef JMGSTAT_H
+# define JMGSTAT_H
+bool GetUTCFileModTime ( LPCTSTR name, time_t * utc_mod_time );
+#endif /* !JMGSTAT_H */
diff --git a/windows-NT/Makefile.am b/windows-NT/Makefile.am
new file mode 100644
index 0000000..c40e73d
--- /dev/null
+++ b/windows-NT/Makefile.am
@@ -0,0 +1,154 @@
+## Process this file with automake to produce Makefile.in
+
+# *** Under Windows NT and Microsoft Visual C++, we use cvsnt.mak, not
+# *** this makefile. However, we need this file in order for 'make
+# *** dist' to work properly on Unix machines.
+
+# Makefile for GNU CVS windows-NT dist.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+EXTRA_DIST = \
+ JmgStat.c \
+ JmgStat.h \
+ config.h \
+ config.h.in \
+ config.h.in.in \
+ config.h.in.footer \
+ stamp-chi \
+ mkconfig.pl \
+ fix-msvc-mak.pl \
+ ndir.h \
+ pwd.h \
+ rcmd.h \
+ stdbool.h \
+ stdint.h \
+ filesubr.c \
+ mkdir.c \
+ ndir.c \
+ netdb.h \
+ pwd.c \
+ rcmd.c \
+ run.c \
+ sockerror.c \
+ startserver.c \
+ arpa/inet.h \
+ netinet/in.h \
+ sys/socket.h \
+ sys/types.h \
+ unistd.c \
+ unistd.h \
+ waitpid.c \
+ woe32.c \
+ woe32.h \
+ .cvsignore
+
+SUBDIRS = SCC
+
+###
+### Maintainer targets
+###
+MAINTAINERCLEANFILES =
+DISTCLEANFILES =
+
+all-local: config.h stdbool.h stdint.h
+config.h: stamp-ch
+stamp-ch: config.h.in $(top_srcdir)/configure
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >config.tmp
+ @echo " * config.h.in file." >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * Edit config.h.in instead." >>config.tmp
+ @echo " */" >>config.tmp
+ sed -e "s/%PACKAGE_STRING%/$(PACKAGE_STRING)/" \
+ -e "s/%PACKAGE_BUGREPORT%/$(PACKAGE_BUGREPORT)/" \
+ <$(srcdir)/config.h.in >>config.tmp
+ @cmp -s config.tmp $(srcdir)/config.h \
+ || (echo "Updating config.h"; \
+ cp config.tmp $(srcdir)/config.h)
+ -@rm -f config.tmp
+ @cp $(srcdir)/config.h $@
+DISTCLEANFILES += stamp-ch
+
+# The shell portion of this target is so that this file will be regenerated
+# when it is missing, even when not in maintainer mode.
+config.h.in: @MAINTAINER_MODE_TRUE@ stamp-chi
+ @if test ! -f $(srcdir)/$@; then \
+ rm -f $(srcdir)/stamp-chi; \
+ $(MAKE) stamp-chi; \
+ else :; fi
+
+# The following target exists for two reasons. The first is so that the rule
+# for config.h.in above may be conditionally dependent on it and thus only
+# built in maintainer mode. The second reason is so that the config.h.in, and
+# thus the config.h file, only gets touched when it actually changes, which
+# could potentially save unnecessary rebuilds of many dependent files.
+#
+# This file is distributed since, without it, config.h.in will always be
+# rebuilt on the first run in maintainer mode, even if its dependencies are
+# unchanged.
+stamp-chi: $(srcdir)/mkconfig.pl $(top_srcdir)/config.h.in \
+ $(srcdir)/config.h.in.in $(srcdir)/config.h.in.footer
+ @$(PERL) mkconfig.pl -q $(top_srcdir)/config.h.in \
+ $(srcdir)/config.h.in \
+ $(srcdir)/config.h.in.in \
+ $(srcdir)/config.h.in.footer
+ @cp $(srcdir)/config.h.in $(srcdir)/$@
+MAINTAINERCLEANFILES += $(srcdir)/config.h.in $(srcdir)/stamp-chi
+
+stdbool.h: stamp-sh
+stamp-sh: $(top_srcdir)/lib/stdbool_.h
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >stdbool.tmp
+ @echo " * ../lib/stdbool_.h.in file." >>stdbool.tmp
+ @echo " *" >>stdbool.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>stdbool.tmp
+ @echo " *" >>stdbool.tmp
+ @echo " * Edit ../lib/stdbool_.h instead." >>stdbool.tmp
+ @echo " */" >>stdbool.tmp
+ sed 's/@''HAVE__BOOL''@/0/' <$(top_srcdir)/lib/stdbool_.h \
+ >>stdbool.tmp
+ @cmp -s stdbool.tmp $(srcdir)/stdbool.h \
+ || (echo "Updating stdbool.h"; \
+ cp stdbool.tmp $(srcdir)/stdbool.h)
+ -@rm -f stdbool.tmp
+ @cp $(srcdir)/stdbool.h $@
+DISTCLEANFILES += stamp-sh
+
+stdint.h: stamp-sh2
+stamp-sh2: $(top_srcdir)/lib/stdint_.h
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >stdint.tmp
+ @echo " * ../lib/stdint_.h.in file." >>stdint.tmp
+ @echo " *" >>stdint.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>stdint.tmp
+ @echo " *" >>stdint.tmp
+ @echo " * Edit ../lib/stdint_.h instead." >>stdint.tmp
+ @echo " */" >>stdint.tmp
+ sed 's/@''HAVE_LONG_64BIT''@/0/g;s/@''HAVE_LONG_LONG_64BIT@/0/g' \
+ <$(top_srcdir)/lib/stdint_.h >>stdint.tmp
+ @cmp -s stdint.tmp $(srcdir)/stdint.h \
+ || (echo "Updating stdint.h"; \
+ cp stdint.tmp $(srcdir)/stdint.h)
+ -@rm -f stdint.tmp
+ @cp $(srcdir)/stdint.h $@
+DISTCLEANFILES += stamp-sh2
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/windows-NT/Makefile.in b/windows-NT/Makefile.in
new file mode 100644
index 0000000..700573d
--- /dev/null
+++ b/windows-NT/Makefile.in
@@ -0,0 +1,708 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# *** Under Windows NT and Microsoft Visual C++, we use cvsnt.mak, not
+# *** this makefile. However, we need this file in order for 'make
+# *** dist' to work properly on Unix machines.
+
+# Makefile for GNU CVS windows-NT dist.
+#
+# Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+#
+# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+# and others.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = windows-NT
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+EXTRA_DIST = \
+ JmgStat.c \
+ JmgStat.h \
+ config.h \
+ config.h.in \
+ config.h.in.in \
+ config.h.in.footer \
+ stamp-chi \
+ mkconfig.pl \
+ fix-msvc-mak.pl \
+ ndir.h \
+ pwd.h \
+ rcmd.h \
+ stdbool.h \
+ stdint.h \
+ filesubr.c \
+ mkdir.c \
+ ndir.c \
+ netdb.h \
+ pwd.c \
+ rcmd.c \
+ run.c \
+ sockerror.c \
+ startserver.c \
+ arpa/inet.h \
+ netinet/in.h \
+ sys/socket.h \
+ sys/types.h \
+ unistd.c \
+ unistd.h \
+ waitpid.c \
+ woe32.c \
+ woe32.h \
+ .cvsignore
+
+SUBDIRS = SCC
+
+###
+### Maintainer targets
+###
+MAINTAINERCLEANFILES = $(srcdir)/config.h.in $(srcdir)/stamp-chi
+DISTCLEANFILES = stamp-ch stamp-sh stamp-sh2
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu windows-NT/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu windows-NT/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/arpa $(distdir)/netinet $(distdir)/sys
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile all-local
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am all-local check \
+ check-am clean clean-generic clean-recursive ctags \
+ ctags-recursive distclean distclean-generic \
+ distclean-recursive distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-recursive \
+ mostlyclean mostlyclean-generic mostlyclean-recursive pdf \
+ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-info-am
+
+
+all-local: config.h stdbool.h stdint.h
+config.h: stamp-ch
+stamp-ch: config.h.in $(top_srcdir)/configure
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >config.tmp
+ @echo " * config.h.in file." >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>config.tmp
+ @echo " *" >>config.tmp
+ @echo " * Edit config.h.in instead." >>config.tmp
+ @echo " */" >>config.tmp
+ sed -e "s/%PACKAGE_STRING%/$(PACKAGE_STRING)/" \
+ -e "s/%PACKAGE_BUGREPORT%/$(PACKAGE_BUGREPORT)/" \
+ <$(srcdir)/config.h.in >>config.tmp
+ @cmp -s config.tmp $(srcdir)/config.h \
+ || (echo "Updating config.h"; \
+ cp config.tmp $(srcdir)/config.h)
+ -@rm -f config.tmp
+ @cp $(srcdir)/config.h $@
+
+# The shell portion of this target is so that this file will be regenerated
+# when it is missing, even when not in maintainer mode.
+config.h.in: @MAINTAINER_MODE_TRUE@ stamp-chi
+ @if test ! -f $(srcdir)/$@; then \
+ rm -f $(srcdir)/stamp-chi; \
+ $(MAKE) stamp-chi; \
+ else :; fi
+
+# The following target exists for two reasons. The first is so that the rule
+# for config.h.in above may be conditionally dependent on it and thus only
+# built in maintainer mode. The second reason is so that the config.h.in, and
+# thus the config.h file, only gets touched when it actually changes, which
+# could potentially save unnecessary rebuilds of many dependent files.
+#
+# This file is distributed since, without it, config.h.in will always be
+# rebuilt on the first run in maintainer mode, even if its dependencies are
+# unchanged.
+stamp-chi: $(srcdir)/mkconfig.pl $(top_srcdir)/config.h.in \
+ $(srcdir)/config.h.in.in $(srcdir)/config.h.in.footer
+ @$(PERL) mkconfig.pl -q $(top_srcdir)/config.h.in \
+ $(srcdir)/config.h.in \
+ $(srcdir)/config.h.in.in \
+ $(srcdir)/config.h.in.footer
+ @cp $(srcdir)/config.h.in $(srcdir)/$@
+
+stdbool.h: stamp-sh
+stamp-sh: $(top_srcdir)/lib/stdbool_.h
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >stdbool.tmp
+ @echo " * ../lib/stdbool_.h.in file." >>stdbool.tmp
+ @echo " *" >>stdbool.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>stdbool.tmp
+ @echo " *" >>stdbool.tmp
+ @echo " * Edit ../lib/stdbool_.h instead." >>stdbool.tmp
+ @echo " */" >>stdbool.tmp
+ sed 's/@''HAVE__BOOL''@/0/' <$(top_srcdir)/lib/stdbool_.h \
+ >>stdbool.tmp
+ @cmp -s stdbool.tmp $(srcdir)/stdbool.h \
+ || (echo "Updating stdbool.h"; \
+ cp stdbool.tmp $(srcdir)/stdbool.h)
+ -@rm -f stdbool.tmp
+ @cp $(srcdir)/stdbool.h $@
+
+stdint.h: stamp-sh2
+stamp-sh2: $(top_srcdir)/lib/stdint_.h
+ @echo "/* This file is generated via a rule in Makefile.am from the" \
+ >stdint.tmp
+ @echo " * ../lib/stdint_.h.in file." >>stdint.tmp
+ @echo " *" >>stdint.tmp
+ @echo " * *** DO NOT EDIT THIS FILE DIRECTLY ***" >>stdint.tmp
+ @echo " *" >>stdint.tmp
+ @echo " * Edit ../lib/stdint_.h instead." >>stdint.tmp
+ @echo " */" >>stdint.tmp
+ sed 's/@''HAVE_LONG_64BIT''@/0/g;s/@''HAVE_LONG_LONG_64BIT@/0/g' \
+ <$(top_srcdir)/lib/stdint_.h >>stdint.tmp
+ @cmp -s stdint.tmp $(srcdir)/stdint.h \
+ || (echo "Updating stdint.h"; \
+ cp stdint.tmp $(srcdir)/stdint.h)
+ -@rm -f stdint.tmp
+ @cp $(srcdir)/stdint.h $@
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/windows-NT/README b/windows-NT/README
new file mode 100644
index 0000000..23d57eb
--- /dev/null
+++ b/windows-NT/README
@@ -0,0 +1,113 @@
+ Concurrent Versions System (CVS)
+ ported to Microsoft Windows NT
+
+Check the ../INSTALL file for information on the most recent version
+of CVS which has been known to be tested with NT and/or Win95.
+
+This port implements the full set of CVS commands, both local and
+client. It does not provide a CVS server for NT. Multiple users can
+access a common CVS repository, if they can mount the repository,
+either directly or via a networked file system.
+
+We don't distribute a .ZIP source distribution partly because, as far
+as I can tell, PKZIP insists on munging long file names, which would
+confuse the makefile for Visual C++.
+
+To compile, use Microsoft Visual C++ on the file cvsnt.mak in the
+distribution's top directory. At least with the tar port I'm using,
+the sources get extracted without carriage returns and you must add
+carriage returns to the end of every line in cvsnt.mak. It doesn't
+seem to be necessary to add them to any other file. This makefile was
+generated with Visual C++ 5.x. With Visual C++ 6.x you can also try
+cvsnt.dsw. For Visual C++ 2.x you probably are in the position of
+digging through old versions of CVS for a cvsnt.mak and then updating
+it. Feel free to let us know about problems of this sort as with
+other bug reports.
+
+If you end up regenerating the MSVC makefiles and submitting a patch back to
+us, please be careful. MSVC appears to be trying to write absolute paths into
+the diff/libdiff.mak file and a relative path to a file in the local MSVC
+install in cvsnt.dep (this last only with MSVC 6.x).
+
+Send bug reports to bug-cvs@nongnu.org.
+
+As of May 1996, this port passed all of the tests in src/sanity.sh,
+save the one that deals with reserved all-upper-case tags (BASE and
+HEAD), due to a limitation in the NT command shell. sanity.sh
+provides pretty minimal feature coverage, but still gives me some
+confidence it isn't totally broken. The tests were run by defining
+KLUDGE_FOR_WNT_TESTSUITE (see src/main.c).
+
+To operate in client mode with old versions of CVS (1.9 and older),
+you will need GNU patch. To do compressed transfers with old versions
+of CVS (1.8 and older), you also need gzip. Note that you do NOT need
+an rsh client if you are using the :server: access method (which uses
+the internal rsh client), except perhaps for debugging.
+
+To operate in local mode, you should need nothing other than CVS (that
+is, you no longer need RCS, diff, &c, in order to run CVS).
+
+One useful site may be the Congruent ports of various packages to
+Windows NT, binary and source:
+
+ ftp://microlib.cc.utexas.edu/microlib/nt/gnu/
+
+In particular, microlib seems to have versions of GNU tar and gzip
+which support long file names, which you will need to unpack the CVS
+source distribution.
+
+The Cygwin project is a port of various GNU tools for NT, providing
+bash as the shell and gcc as the compiler. Basically, you don't want
+the stuff in this directory for CVS running under Cygwin; you want
+the same stuff as for unix (../configure, Makefile.in, &c). For
+Cygwin information see
+
+ http://www.cygwin.com/
+
+Morten Hindsholm's port of CVS 1.4A2 to Windows NT may be useful if
+you're modifying CVS itself:
+
+ ftp://ftp.digex.net/pub/access/schueman/cvs/cvsnt14b.zip
+
+Here are some other things which may be of interest for unix junkies:
+
+ http://www.halcyon.com/gvr/vim/ (VI clone)
+ ftp://wuarchive.wustl.edu/systems/ibmpc/gnuish/less177.zip
+
+If you want to browse/edit the sources using Visual C++, we recommend
+setting tab stops to 8 spaces, since that is what the CVS sources
+expect. The tab stop setting is in the "Editor" or "Tabs" section of
+the "Options..." dialog which is in the "Tools..." menu.
+
+The following harmless warnings are known:
+
+- regex.c: 103 warnings, mostly signed/unsigned comparison conflicts.
+ I am not going to *touch* this code. :-) I got my fill of it when I was
+ hacking GNU Emacs.
+
+.\lib\getdate.c(760) : warning C4013: 'getdate_yyparse' undefined; assuming extern returning int
+.\lib\getdate.c(1612) : warning C4102: 'yyerrlab' : unreferenced label
+.\lib\getdate.c(1612) : warning C4102: 'yynewstate' : unreferenced label
+
+Oct 1998 update: there are more now. I've gotten lax about removing
+the warnings lately :-( -kingdon.
+
+CODING STANDARDS for Windows
+
+For general coding standards, see ../HACKING.
+
+In my opinion win32 is the right API to write to. Microsoft seems to
+be better about compatibility across versions than unix vendors (on a
+good day, anyway)--the Visual C++ package I bought has not only win32
+but also win16 too (that is, they also include Visual C++ 1.x). As
+far as I know there is only one win32 (not counting win32s or win32c
+or whatever), not multiple versions.
+
+ANSI C is also good. As far as I know these calls work fairly well on
+NT.
+
+What one should avoid like the plague on NT (IMHO) is POSIX calls such
+as stat(). These tend to be very poorly supported, and tend to break
+from version to version or vendor to vendor (the latter being
+particularly an issue on OS/2, with IBM, Watcom, and EMX all having
+_very_ different C libraries).
diff --git a/windows-NT/SCC/.cvsignore b/windows-NT/SCC/.cvsignore
new file mode 100644
index 0000000..e880feb
--- /dev/null
+++ b/windows-NT/SCC/.cvsignore
@@ -0,0 +1,8 @@
+SCC.mdp
+SCC.ncb
+SCC.opt
+SCC.dsw
+SCC.plg
+Debug
+Release
+Makefile
diff --git a/windows-NT/SCC/ChangeLog b/windows-NT/SCC/ChangeLog
new file mode 100644
index 0000000..27f5bbf
--- /dev/null
+++ b/windows-NT/SCC/ChangeLog
@@ -0,0 +1,250 @@
+2005-09-01 Derek Price <derek@ximbiot.com>
+
+ * README: Update links and email addresses.
+
+2005-03-22 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regnerated.
+
+2003-11-25 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-06-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate for new configure.in.
+
+2003-05-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerate with Automake version 1.7.5.
+
+2003-05-20 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-05-09 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-30 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-04-10 Larry Jones <lawrence.jones@eds.com>
+
+ * Makefile.in: Regenerated.
+
+2003-03-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.am: Update copyright notice.
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Mark D. Baushke <mdb@cvshome.org>
+
+ * Makefile.in: Regenerated.
+
+2003-03-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2003-02-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated using Automake 1.6.3.
+
+2002-09-24 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Regenerated.
+
+2002-04-30 Derek Price <oberon@umich.edu>
+
+ * Makefile.in: Regenerated with automake 1.6.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-06 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated.
+
+2001-07-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new Automake release candidate 1.4h.
+
+2001-06-28 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with new version of Automake.
+
+2001-04-25 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400.
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-22 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.am: New file needed by Automake
+ * Makefile.in: Regenerated
+
+1999-04-09 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add SCC.dsp.
+
+1998-09-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt: Also mention HAHTsite.
+
+1998-03-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * pubscc.h: Describe how SccGetCommandOptions works.
+
+1998-03-10 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt: Update and clarify various minor points.
+
+Tue Jan 27 12:54:05 1998 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt: Update bug-cvs address to gnu.org.
+
+Thu Dec 11 22:17:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt: Add Access to list of development environments which
+ implement SCC.
+
+Wed Oct 29 11:45:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt: CVSwiz runs the command line CVS; it is not an
+ independent implementation of the protocol.
+
+Sun Oct 26 14:57:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt: Add section "OTHER INTERFACES".
+
+Tue Oct 21 23:25:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt (TOOLS IMPLEMENTING THE SCC): Add comment about
+ Powerbuilder versions.
+
+Mon Sep 8 08:52:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt (TOOLS IMPLEMENTING THE SCC): Be a little more
+ specific about Powersoft and CodeWright.
+
+ * Makefile.in (DISTFILES): Add pubscc.h. Thanks to Frederic Van
+ Haren for pointing this out.
+
+Tue Sep 2 13:39:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt (SPECIFICATIONS OR OTHER DOCUMENTS DESCRIBING THE
+ SCC): New section.
+
+Mon Aug 4 10:46:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * pubscc.h: Add comment listing new CodeWright 5.00c functions.
+ Add comment about CodeWright calling SccQueryInfo without
+ SCC_cap_QueryInfo set. Thanks to Frederic Van Haren for
+ pointing out these issues.
+
+4 Aug 1997 Jim Kingdon
+
+ Changes for Visual C++ 5.0:
+ * SCC.dsp: New file.
+ * .cvsignore: add SCC.dsw SCC.opt SCC.plg Release.
+
+ * scc.c (SccGet): Replace #if 0'd code with a comment and
+ adjust to avoid compiler warning.
+
+Mon Aug 4 09:58:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * scc.c: Split out the interface declarations into a new file
+ pubscc.h. This should make it easier to handle multiple
+ scc.c-equivalents.
+
+Mon Jul 14 15:58:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * scc.c: Add many comments and defines to document additional
+ aspects of the SCC API.
+
+7 Jul 1997 Frederic Van Haren <Frederic.Van.Haren@lhs.be>
+
+ * scc.c (SccHistory): file_names is LPSTR * not LPSTR.
+
+Mon Jul 7 16:45:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * scc.c (SccGetVersion): Change arguments from () to (void).
+ Clarify context_arg. Also document 'window' arg.
+
+Sat Jul 5 13:01:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt: PowerJ and Power++ are also said to implement SCC.
+
+21 Mar 1997 Jim Kingdon
+
+ * scc.c (SccCheckout): Write to debuglog and return
+ -11 instead of -14. I though maybe that this may be
+ related to the crashes I've been seeing, but those
+ crashes persisted when I deinstalled the SCC DLL.
+
+14 Mar 1997 Jim Kingdon
+
+ * scc.c: Go back to using debuglog not outproc for
+ most debugging messages. Developer Studio tends to
+ erase the outproc messages on an error.
+ More playing around with projects.
+ * README.txt: Describe results of this. I am making
+ grey (source controlled) file icons appear, which is
+ exciting.
+
+4 Mar 1997 Jim Kingdon
+
+ Still some distance from being able to open a
+ project, but that's what I'm playing with:
+ * scc.c (SccOpenProject): Use outproc not debuglog
+ for debugging messages.
+ (SccGet): Add debugging messages.
+ (SccAddFromScc): Implemented.
+ (SccInitialize): Return AddFromScc in capabilities.
+ * scc.c: Change out_proc to outproc for consistency.
+
+2 Mar 1997 Jim Kingdon
+
+ * scc.c: Add a bunch of things, to SccOpenProject,
+ SccGetProjPath, and perhaps elsewhere. The project
+ stuff doesn't really work yet, but the outproc does.
+
+27 Feb 1997 Jim Kingdon
+
+ * scc.c (SCC_max_init_path, SCC_max_name): Added.
+ (SccInitialize): Set and use more arguments.
+ (SccUninitialize): Might want to check ferror here.
+ (SccOpenProject): Print to debug log if we get here.
+
+Thu Feb 27 19:02:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README.txt (TOOLS IMPLEMENTING THE SCC): New section.
+
+Wed Feb 26 22:55:43 1997 David H. Hovemeyer <Hovemeyer_D@mediasoft.net>
+ and Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * scc.c (SccGetVersion): Return the version number of the SCC
+ spec; we don't get to pick what to return here.
+ * README.txt: Update with current status.
+
+Sat Feb 15 15:19:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in: New file.
+
+ * README.txt: Clarify a little more what this stuff does (and more
+ the point, does not) do.
+
diff --git a/windows-NT/SCC/Makefile.am b/windows-NT/SCC/Makefile.am
new file mode 100644
index 0000000..435ff85
--- /dev/null
+++ b/windows-NT/SCC/Makefile.am
@@ -0,0 +1,33 @@
+## Process this file with automake to produce Makefile.in
+
+# *** Under Windows NT and Microsoft Visual C++, we use cvsnt.mak, not
+# *** this makefile. However, we need this file in order for 'make
+# *** dist' to work properly on Unix machines.
+
+# Makefile for GNU CVS windows-NT/SCC dist.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+EXTRA_DIST = \
+ .cvsignore \
+ README.txt \
+ SCC.mak \
+ SCC.dsp \
+ scc.c \
+ scc.def \
+ pubscc.h
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
diff --git a/windows-NT/SCC/Makefile.in b/windows-NT/SCC/Makefile.in
new file mode 100644
index 0000000..aa0abbb
--- /dev/null
+++ b/windows-NT/SCC/Makefile.in
@@ -0,0 +1,431 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# *** Under Windows NT and Microsoft Visual C++, we use cvsnt.mak, not
+# *** this makefile. However, we need this file in order for 'make
+# *** dist' to work properly on Unix machines.
+
+# Makefile for GNU CVS windows-NT/SCC dist.
+# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+# 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = windows-NT/SCC
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_extract_cpp_defn.m4 \
+ $(top_srcdir)/m4/acx_with_external_zlib.m4 \
+ $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/allocsa.m4 \
+ $(top_srcdir)/m4/asx_version_compare.m4 \
+ $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
+ $(top_srcdir)/m4/canon-host.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/cvs_func_printf_ptr.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/d-type.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eealloc.m4 \
+ $(top_srcdir)/m4/eoverflow.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/filenamecat.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/ftruncate.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/gethostname.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getndelim2.m4 \
+ $(top_srcdir)/m4/getnline.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 $(top_srcdir)/m4/getpass.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettime.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glob.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/mbchar.m4 \
+ $(top_srcdir)/m4/mbiter.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/md5.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmove.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir-slash.m4 \
+ $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/onceonly_2_57.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pagealign_alloc.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \
+ $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/signed.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-macros.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint.m4 \
+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \
+ $(top_srcdir)/m4/strftime.m4 $(top_srcdir)/m4/strstr.m4 \
+ $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \
+ $(top_srcdir)/m4/sunos57-select.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/uint32_t.m4 \
+ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 \
+ $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/yesno.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSH = @CSH@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EDITOR = @EDITOR@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXEEXT = @EXEEXT@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GLOB_H = @GLOB_H@
+GMSGFMT = @GMSGFMT@
+HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
+HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
+HAVE__BOOL = @HAVE__BOOL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRB4 = @KRB4@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_TARGETS_IN_VPATH_FALSE = @MAKE_TARGETS_IN_VPATH_FALSE@
+MAKE_TARGETS_IN_VPATH_TRUE = @MAKE_TARGETS_IN_VPATH_TRUE@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MKTEMP = @MKTEMP@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+POSUB = @POSUB@
+PR = @PR@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+ROFF = @ROFF@
+RSH_DFLT = @RSH_DFLT@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+TEXI2DVI = @TEXI2DVI@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZLIB_SUBDIRS = @ZLIB_SUBDIRS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_prefix_program = @ac_prefix_program@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cvs_client_objects = @cvs_client_objects@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+with_default_rsh = @with_default_rsh@
+EXTRA_DIST = \
+ .cvsignore \
+ README.txt \
+ SCC.mak \
+ SCC.dsp \
+ scc.c \
+ scc.def \
+ pubscc.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu windows-NT/SCC/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu windows-NT/SCC/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-info-am
+
+
+# for backwards compatibility with the old makefiles
+realclean: maintainer-clean
+.PHONY: realclean
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/windows-NT/SCC/README.txt b/windows-NT/SCC/README.txt
new file mode 100644
index 0000000..42a5db6
--- /dev/null
+++ b/windows-NT/SCC/README.txt
@@ -0,0 +1,116 @@
+This is an experimental attempt to interface to the SCC API.
+
+Note that this code doesn't (yet) do anything useful; this file
+is currently for people who want to hack on the SCC interface,
+not people who want a plug-in integration between any particular pair
+of packages.
+
+To install the test DLL, build scc.dll and then add the following
+to the registry using the registry editor:
+
+key/value what to put there
+HKEY_LOCAL_MACHINE
+ SOFTWARE
+ CVS
+ CVS
+ SCCServerName Concurrent Versions System
+ SCCServerPath <full pathname of scc.dll>
+ SourceCodeControlProvider
+ ProviderRegKey "SOFTWARE\CVS\CVS"
+ InstalledSCCProviders
+ Concurrent Versions System "SOFTWARE\CVS\CVS"
+
+Note that ProviderRegKey is the default source control
+system, and InstalledSCCProviders list _all_ installed
+source control systems. A development environment is allowed
+to use either or both, so you should set both of them.
+
+Note also that we are using "CVS" as the supplier of CVS.
+CVS is not owned by any one company, so CVS seems like the
+most appropriate string to put there.
+
+If you do this right, then "Source Control" should appear
+under the "Tools" menu (for Visual C++ 4.x; the details of course may
+vary for other development environments).
+
+NOW WHAT?
+
+Well, I haven't yet figured out _all_ the different ways
+that projects work at the SCC level. But here is what I
+have done which has worked. SPECIAL NOTE: many paths are
+hardcoded in scc.c, so you will need to fix that or put
+things the same place I did. As you try the following you
+will want to follow along in d:\debug.scc.
+
+* Create a dummy project in d:\sccwork.
+* On the Tools/Source Control menu, select "Share from CVS..."
+* This will cause SccAddFromScc to be called, which will
+ claim there are two files, foo.c and bar.c, which should
+ appear as source controlled (grey) files in the file
+ listing.
+* Now select one of the files and pick "Get Latest Version..."
+ from Tools/Source Control. You'll get a cheezy dialog (we
+ need to see why it is cheezy--by that I mean the size and
+ placement are funny), and if you say OK, then SccGet will
+ get called (which doesn't currently do anything).
+
+TOOLS IMPLEMENTING THE SCC
+
+I'm not sure whether we'll want to try to make this a comprehensive
+list, but at least for the moment it seems worthwhile to list a few of
+the programs which implement the Integrated Development Environment
+(IDE) side of the SCC. Some of this information is based on rumor or,
+worse yet, usenet posting, so it probably should be verified before
+relying on it.
+
+* Microsoft Developer Studio 4.x Professional (not Standard, not 2.x).
+* Microsoft Access V7.0
+* Powersoft's Optima++, PowerJ, and Power++
+ (not sure which versions, but this information was added in 1997 if
+ that helps. Someone on usenet reports 32 bit Powerbuilder version
+ 5.03 but not version 4, version 5.0, or 16 bit Powerbuilder.).
+* Premia's CodeWright editor
+ (versions 5.00b and 5.00c; not sure about older versions).
+* HAHTsite (not sure what versions).
+
+SPECIFICATIONS OR OTHER DOCUMENTS DESCRIBING THE SCC
+
+The only publicly available document which we are aware of is pubscc.h
+in this directory. This should be sufficient to get a start at
+playing around with the SCC, and if you have done that and then
+proceed to run into those areas which pubscc.h does not document well,
+you are encouraged to send mail to bug-cvs@nongnu.org with your
+questions.
+
+OTHER INTERFACES
+
+There are other interfaces which interface between a development
+environment (or other front-end) and a source control system. That
+is, in general terms they provide somewhat the function of the SCC,
+although they may be at a somewhat different level and systems may
+support/use several interfaces rather than it being an either/or thing.
+
+If you know of other interfaces which should be added here I guess the
+best place to make suggestions is bug-cvs@nongnu.org (although
+the following list is not intended to be particularly CVS-centric).
+
+* The CVS remote protocol is documented in doc/cvsclient.texi in the
+CVS distribution and has at least 2 implementations of the client
+(jCVS and CVS command line client), in addition to having been
+implemented at least once by a special-purpose perl script.
+
+* Microsoft's OLE Automation interface. The spec is available for
+download at http://www.microsoft.com/ssafe. I'm not sure whether this
+has been implemented by other source control systems. Metrowerks
+implements this via a module which speaks the Metrowerks API out one
+end and the OLE Automation interface out the other (the module runs on
+Windows, not Mac).
+
+* Symantec's Visual Cafe interface.
+
+* Metrowerks publishes and implements the CodeWarrior IDE Version
+Control System API. I think maybe the way to get a copy of the spec
+is as part of CodeWarrior but I'm not completely clear on that.
+
+For (some) more details on these interfaces, and others, see
+ http://www.cyclic.com/cvs/dev-int.html
diff --git a/windows-NT/SCC/SCC.dsp b/windows-NT/SCC/SCC.dsp
new file mode 100644
index 0000000..5a50f01
--- /dev/null
+++ b/windows-NT/SCC/SCC.dsp
@@ -0,0 +1,108 @@
+# Microsoft Developer Studio Project File - Name="SCC" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=SCC - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "SCC.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "SCC.mak" CFG="SCC - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "SCC - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "SCC - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "SCC - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "SCC - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "SCC - Win32 Release"
+# Name "SCC - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\scc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\scc.def
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows-NT/SCC/SCC.mak b/windows-NT/SCC/SCC.mak
new file mode 100644
index 0000000..ef4da64
--- /dev/null
+++ b/windows-NT/SCC/SCC.mak
@@ -0,0 +1,216 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 40001
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+!IF "$(CFG)" == ""
+CFG=SCC - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to SCC - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "SCC - Win32 Release" && "$(CFG)" != "SCC - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "SCC.mak" CFG="SCC - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "SCC - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "SCC - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "SCC - Win32 Debug"
+CPP=cl.exe
+RSC=rc.exe
+MTL=mktyplib.exe
+
+!IF "$(CFG)" == "SCC - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\SCC.dll"
+
+CLEAN :
+ -@erase ".\Release\SCC.dll"
+ -@erase ".\Release\scc.obj"
+ -@erase ".\Release\SCC.lib"
+ -@erase ".\Release\SCC.exp"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/SCC.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/SCC.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\
+ /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)/SCC.pdb" /machine:I386\
+ /def:".\scc.def" /out:"$(OUTDIR)/SCC.dll" /implib:"$(OUTDIR)/SCC.lib"
+DEF_FILE= \
+ ".\scc.def"
+LINK32_OBJS= \
+ "$(INTDIR)/scc.obj"
+
+"$(OUTDIR)\SCC.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "SCC - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\SCC.dll"
+
+CLEAN :
+ -@erase ".\Debug\vc40.pdb"
+ -@erase ".\Debug\vc40.idb"
+ -@erase ".\Debug\SCC.dll"
+ -@erase ".\Debug\scc.obj"
+ -@erase ".\Debug\SCC.ilk"
+ -@erase ".\Debug\SCC.lib"
+ -@erase ".\Debug\SCC.exp"
+ -@erase ".\Debug\SCC.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/SCC.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/SCC.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo\
+ /subsystem:windows /dll /incremental:yes /pdb:"$(OUTDIR)/SCC.pdb" /debug\
+ /machine:I386 /def:".\scc.def" /out:"$(OUTDIR)/SCC.dll"\
+ /implib:"$(OUTDIR)/SCC.lib"
+DEF_FILE= \
+ ".\scc.def"
+LINK32_OBJS= \
+ "$(INTDIR)/scc.obj"
+
+"$(OUTDIR)\SCC.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "SCC - Win32 Release"
+# Name "SCC - Win32 Debug"
+
+!IF "$(CFG)" == "SCC - Win32 Release"
+
+!ELSEIF "$(CFG)" == "SCC - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\scc.c
+
+"$(INTDIR)\scc.obj" : $(SOURCE) "$(INTDIR)"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\scc.def
+
+!IF "$(CFG)" == "SCC - Win32 Release"
+
+!ELSEIF "$(CFG)" == "SCC - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/windows-NT/SCC/pubscc.h b/windows-NT/SCC/pubscc.h
new file mode 100644
index 0000000..f97d925
--- /dev/null
+++ b/windows-NT/SCC/pubscc.h
@@ -0,0 +1,546 @@
+/* This file was written by Jim Kingdon, and is hereby placed
+ in the public domain. */
+
+/* Bits of the SCC interface.
+ For paranoia's sake, I'm not using the same names as Microsoft.
+ I don't imagine copying a few names could be a credible copyright
+ case, but it seems safer to stick to only what is necessary for
+ the interface to work.
+
+ Note that some of the descriptions here have a certain amount of
+ guesswork (for example, sometimes I have tried to translate to CVS
+ terminology without actually verifying that the item means what I
+ think it does). If you find errors, please let us know according to
+ the usual procedures for reporting CVS bugs. */
+typedef long SCC_return;
+#define SCC_return_success 0
+#define SCC_return_unknown_project -2
+/* The file is not under SCC control. */
+#define SCC_return_non_scc_file -11
+/* This operation is not supported. I believe this status can only
+ be returned from SccGet, SccAdd, SccRemove, SccHistory, or
+ SccQueryInfo. I'm not really sure what happens if it is returned
+ from other calls. */
+#define SCC_return_not_supported -14
+#define SCC_return_non_specific_error -15
+
+enum SCC_command
+{
+ SCC_command_get,
+ SCC_command_checkout,
+ SCC_command_checkin,
+ SCC_command_uncheckout,
+ SCC_command_add,
+ SCC_command_remove,
+ SCC_command_diff,
+ SCC_command_history,
+ SCC_command_rename,
+ SCC_command_properties,
+ SCC_command_options
+};
+
+/* Outproc codes, for second argument to outproc. */
+#define SCC_outproc_info 1L
+#define SCC_outproc_warning 2L
+#define SCC_outproc_error 3L
+/* Codes 4-7 relate to cancels and are only supported if the
+ development environment said so with SccSetOption. */
+/* A status message, typically goes in something analogous to the emacs
+ minibuffer. For both this and SCC_outproc_nostatus, the development
+ environment returns SCC_outproc_return_cancelled if the user has
+ hit the cancel button. */
+#define SCC_outproc_status 4L
+/* Like SCC_outproc_status, but there is no message to report. */
+#define SCC_outproc_nostatus 5L
+/* Tell the development environment to offer a cancel button. */
+#define SCC_outproc_cancel_on 6L
+/* Tell the development environment to not offer a cancel button. */
+#define SCC_outproc_cancel_off 7L
+
+/* Return values from outproc. */
+#define SCC_outproc_return_success 0L
+#define SCC_outproc_return_cancelled -1L
+typedef long (*SCC_outproc) (char *, long);
+
+typedef BOOL (*SCC_popul_proc) (LPVOID callerdat, BOOL add_keep,
+ LONG status, LPCSTR file);
+
+/* Maximum sizes of various strings. These are arbitrary limits
+ which are imposed by the SCC. */
+/* Name argument to SccInitialize. */
+#define SCC_max_name 31
+/* Path argument to SccInitialize. */
+#define SCC_max_init_path 31
+/* Various paths many places in the interface. */
+#include <stdlib.h>
+#define SCC_max_path _MAX_PATH
+
+/* Status codes, as used by QueryInfo and GetEvents. */
+/* This means that we can't get status. If the status is not
+ SCC_status_error, then the status is a set of bit flags, as defined by
+ the other SCC_status_* codes. */
+#define SCC_status_error -1L
+
+/* The following status codes are things which the development environment
+ is encouraged to check to determine things like whether to allow
+ a checkin. */
+/* The current user has the file checked out (that is, under "cvs edit").
+ It may or may not be in the directory where the development
+ environment thinks it should be. */
+#define SCC_status_out_me 0x1000L
+/* Should be set only if out_me is set. The file is checked out where
+ the development environment thinks it should be. */
+#define SCC_status_out_here 2L
+/* Some other user has the file checked out. */
+#define SCC_status_out_someoneelse 4L
+/* Reserved checkouts are in effect for the file. */
+#define SCC_status_reserved 8L
+/* Reserved checkouts are not in effect for the file. Multiple users
+ can edit it. Only one of SCC_status_reserved or SCC_status_nonreserved
+ should be set. I think maybe this flag should only be set if there
+ actually is more than one copy currently checked out. */
+#define SCC_status_nonreserved 0x10L
+
+/* The following flags are intended for the development environment to
+ display the status of a file. We are allowed to support them or not
+ as we choose. */
+/* The file in the working directory is not the latest version in the
+ repository. Like when "cvs status" says "Needs Checkout". */
+#define SCC_status_needs_update 0x20L
+/* The file is no longer in the project. I think this is the case where
+ cvs update prints "file xxx is no longer pertinent" (but I don't know,
+ there are other statuses involved with removed files). */
+#define SCC_status_not_pertinent 0x40L
+/* No checkins are permitted for this file. No real CVS analogue, because
+ this sort of thing would be done by commitinfo, &c. */
+#define SCC_status_no_checkins 0x80L
+/* There was a merge, but the user hasn't yet dealt with it. I think this
+ probably should be used both if there were conflicts on the merge and
+ if there were not (not sure, though). */
+#define SCC_status_had_conflicts 0x100L
+/* This indicates something has happened to the file. I suspect it mainly
+ is intended for cases in which we detect that something happened to the
+ file behind our backs. I suppose CVS might use this for cases in which
+ sanity checks on the CVSADM files fail, or in which the file has been
+ made read/write without a "cvs edit", or that sort of thing.
+
+ Or maybe it should be set if the file has been edited in the
+ normal fashion. I'm not sure. */
+#define SCC_status_munged 0x800L
+/* The file exists in several projects. In CVS I would suppose the
+ equivalent probably would be that several modules (using features
+ like -d) are capable of checking out a given file in the repository
+ in several locations. CVS has no current ability to give a different
+ status when that has happened, but it might be cool. */
+#define SCC_status_several_projects 0x200L
+/* There is a sticky tag or date in effect. */
+#define SCC_status_stuck 0x400L
+
+/* Bits to set in the caps used by SccInitialize. Most of these are
+ relatively straightforward, for example SCC_cap_QueryInfo is set to
+ indicate that the SccQueryInfo function is supported. */
+/* CodeWright 5.00b and 5.00c seem to call SccQueryInfo regardless of whether
+ this bit is set in caps. */
+#define SCC_cap_QueryInfo 0x80L
+#define SCC_cap_GetProjPath 0x200L
+#define SCC_cap_AddFromScc 0x400L
+#define SCC_cap_want_outproc 0x8000L
+
+/* These are command options. Some of them are specific to a particular
+ command, some of them are good for more than one command. Because many
+ values are reused for different commands, look at the listed commands
+ to see what a particular value means for a particular command. */
+/* Recurse into directories. SccGet. */
+#define SCC_cmdopt_recurse 2L
+/* This means to get all the files in a directory. SccGet. */
+#define SCC_cmdopt_dir 1L
+/* Without this flag, after a checkin, files are normally not checked
+ out. This flag disables that handling, and if it is set files will
+ still be checked out after the checkin completes. SccCheckin, SccAdd. */
+#define SCC_cmdopt_no_unedit 0x1000L
+/* File is text. SccAdd. */
+#define SCC_cmdopt_text 1L
+/* File is binary. SccAdd. */
+#define SCC_cmdopt_binary 2L
+/* We are supposed to decide whether it is text or binary. We can use the
+ CVS wrappers stuff to decide based on the file name. Obviously, this
+ constant is just another way of saying that neither SCC_cmdopt_text nor
+ SCC_cmdopt_binary are set. SccAdd. */
+#define SCC_cmdopt_auto 0L
+/* Maintain only a head revision for the file, no history. SccAdd. */
+#define SCC_cmdopt_only_one 4L
+/* In addition to removing the file from the repository, also delete it
+ from the working directory. My guess is that development environments
+ would generally tend to pass this flag by default. SccRemove. */
+#define SCC_cmdopt_retain_local 1L
+/* Compare files in a case-insensitive fashion. SccDiff. */
+#define SCC_cmdopt_case_insensitive 2L
+/* Ignore whitespace in comparing files. SccDiff. */
+#define SCC_cmdopt_ignore_all_space 4L
+/* Instead of generating diffs, just say whether files are equal, based on
+ the file contents. SccDiff. */
+#define SCC_cmdopt_compare_files 0x10L
+/* Instead of generating diffs, just say whether files are equal. This may
+ use a checksum if we want, or if not, it can be the same as
+ SCC_cmdopt_compare_files. */
+#define SCC_cmdopt_consult_checksum 0x20L
+/* Instead of generating diffs, just say whether files are equal. This may
+ use a timestamp if we want, or if not, it can be the same as either
+ SCC_cmdopt_consult_checksum or SCC_cmdopt_compare_files. */
+#define SCC_cmdopt_consult_timestamp 0x40L
+
+/* Values for the flags argument to OpenProject. */
+/* If this is set, and the development environment tries to open a project
+ which doesn't exist, then create it. */
+#define SCC_open_autocreate 1L
+/* If autocreate is not set, and the development environment tries to
+ open a project which doesn't exist, and may_prompt is set, we are
+ allowed to prompt the user to create a new project. If may_prompt
+ is not set, we should just return SCC_return_unknown_project and
+ not open the project. */
+#define SCC_open_may_prompt 2L
+
+/* Constants for SccSetOption. */
+#define SCC_option_background 1L
+/* If option is SCC_option_background, then val turns background
+ processing on or off. If it is off, we can, if we need to, queue
+ up events or something which won't disturb the development
+ environment. */
+# define SCC_option_background_yes 1L
+# define SCC_option_background_no 0L
+#define SCC_option_cancel 3L
+/* If option is SCC_option_cancel, then val says whether the development
+ environment supports the SCC_outproc_* codes related to having the
+ development environment handle a cancel button. If this is not set,
+ we are allowed/encouraged to implement a cancel button ourselves. */
+# define SCC_option_cancel_on 1L
+# define SCC_option_cancel_off 0L
+/* A SCC_option_* value of 10 has also been observed (I think from
+ CodeWright 5.00). I have no idea what it means; it isn't documented
+ by the SCC API from Microsoft (version 0.99.0823). */
+
+/* The "void *context_arg" argument to most of the Scc* functions
+ stores a pointer to a structure that the version control system
+ gets to allocate, so it doesn't need any global variables. */
+
+/* In addition to context_arg, most of the Scc* functions take a
+ "HWND window" argument. This is so that we can put up dialogs.
+ The window which is passed in is the IDE's window, which we
+ should use as the parent of dialogs that we put up. */
+
+#include <windows.h>
+
+/* Return the version of the SCC spec, major version in the high word,
+ minor version in the low word. Recommended value is 0x10001 for
+ version 1.1 of the spec. */
+extern LONG SccGetVersion (void);
+
+/* Set up the version control system. This should be called before any
+ other SCC calls other than SccGetVersion. */
+extern SCC_return SccInitialize
+ (/* The version control system should allocate the context argument
+ in SccInitialize and store a pointer to it in *contextp. */
+ void **contextp,
+
+ HWND window, LPSTR caller,
+ /* Version control system should copy in the
+ name of the version control system here,
+ up to SCC_max_name bytes. */
+ LPSTR name,
+
+ /* Version control system should set *caps to indicate what it
+ supports, using bits from SCC_cap_*. */
+ LPLONG caps,
+
+ /* Version control system should copy in a string here, that the
+ development environment can put places like a makefile to
+ distinguish this version control system from others. Up to
+ SCC_max_init_path bytes. */
+ LPSTR path,
+
+ /* Version control system should set these to the maximum size for
+ checkout comments and comments. I'm not sure whether existing
+ development environments tend to allocate fixed size arrays
+ based on the return length (I would recommend that a development
+ environment not do so, but that is a different question). */
+ LPDWORD co_comment_len,
+ LPDWORD comment_len);
+
+/* The version control system should free any resources it has allocated,
+ including the context structure itself. */
+extern SCC_return SccUninitialize (void *context_arg);
+
+extern SCC_return SccOpenProject
+ (void *context_arg, HWND window, LPSTR user,
+ LPSTR project, LPSTR local_proj,
+ LPSTR aux_proj,
+ LPSTR comment,
+
+ /* This is the function which the version control system can call
+ to ask the development environment to display output, or
+ (SCC_outproc)0 if the development environment doesn't support
+ the outproc feature. */
+ SCC_outproc outproc,
+
+ /* One or more of the SCC_open_* settings. */
+ LONG flags);
+
+extern SCC_return SccCloseProject (void *context_arg);
+
+/* cvs get. */
+extern SCC_return SccGet
+ (void *context_arg, HWND window,
+
+ /* Files to get, where file_names is an array
+ of num_files names. */
+ /* As with all file names passed to us by the SCC, these file names
+ are absolute pathnames. I think they will tend to be paths
+ within the local directory specified by the local_proj argument
+ to SccOpenProject, although I don't know whether there are any
+ exceptions to that. */
+ LONG num_files,
+ LPSTR *file_names,
+
+ /* Command options. */
+ LONG options,
+
+ void *prov_options);
+
+/* cvs edit. */
+extern SCC_return SccCheckout
+ (void *context_arg, HWND window,
+
+ /* Files to operate on, where file_names is an array of num_files
+ names. */
+ LONG num_files,
+ LPSTR *file_names,
+
+ LPSTR comment,
+
+ /* Command options. I'm not sure what command options, if any, are
+ defined for SccCheckout. */
+ LONG options,
+
+ void *prov_options);
+
+/* cvs ci. */
+extern SCC_return SccCheckin
+ (void *context_arg, HWND window,
+
+ /* Files to operate on, where file_names is an array of num_files
+ names. */
+ LONG num_files,
+ LPSTR *file_names,
+
+ LPSTR comment,
+
+ /* Command options. */
+ LONG options,
+
+ void *prov_options);
+
+/* cvs unedit. */
+extern SCC_return SccUncheckout
+ (void *context_arg, HWND window,
+
+ /* Files to operate on, where file_names is an array of num_files
+ names. */
+ LONG num_files,
+ LPSTR *file_names,
+
+ /* Command options. I'm not sure what command options, if any, are
+ defined for SccUncheckout. */
+ LONG options,
+
+ void *prov_options);
+
+/* cvs add + cvs ci, more or less, I think (but see also
+ the "keep checked out" flag in options). */
+extern SCC_return SccAdd
+ (void *context_arg, HWND window,
+
+ /* Files to operate on, where file_names is an array of num_files
+ names. */
+ LONG num_files,
+ LPSTR *file_names,
+
+ LPSTR comment,
+
+ /* Array of num_files command options, one for each file. */
+ LONG *options,
+
+ void *prov_options);
+
+/* cvs rm -f + cvs ci, I think. Should barf if SCC_REMOVE_KEEP
+ (or maybe just put the file there, as if the user had removed
+ it and then done a "copy <saved-file> <filename>". */
+extern SCC_return SccRemove
+ (void *context_arg, HWND window,
+
+ /* Files to operate on, where file_names is an array of num_files
+ names. */
+ LONG num_files,
+ LPSTR *file_names,
+
+ LPSTR comment,
+
+ /* Command options. */
+ LONG options,
+
+ void *prov_options);
+
+/* mv, cvs add, cvs rm, and cvs ci, I think. */
+extern SCC_return SccRename
+ (void *context_arg, HWND window, LPSTR old_name,
+ LPSTR new_name);
+
+/* If SCC_cmdopt_compare_files, SCC_cmdopt_consult_checksum, or
+ SCC_cmdopt_consult_timestamp, then we are supposed to silently
+ return a status, without providing any information directly to the
+ user. For no args or checksum (which we fall back to full compare)
+ basically a call to No_Diff or ? in the client case. For
+ timestamp, just a Classify_File. Now, if contents not set, then
+ want to do a cvs diff, and preferably start up WinDiff or something
+ (to be determined, for now perhaps could just return text via
+ outproc). */
+extern SCC_return SccDiff
+ (void *context_arg, HWND window, LPSTR file_name,
+
+ /* Command options. */
+ LONG options,
+
+ void *prov_options);
+
+/* cvs log, I presume. If we want to get fancier we could bring
+ up a screen more analogous to the tkCVS log window, let the user
+ do "cvs update -r", etc. */
+extern SCC_return SccHistory
+ (void *context_arg, HWND window,
+
+ /* Files to operate on, where file_names is an array of num_files
+ names. */
+ LONG num_files,
+ LPSTR *file_names,
+
+ /* Command options. I'm not sure what command options,
+ if any, are defined for SccHistory. */
+ LONG options,
+
+ void *prov_options);
+
+/* cvs status, presumably. */
+extern SCC_return SccProperties
+ (void *context_arg, HWND window, LPSTR file_name);
+
+/* Not sure what this should do. The most obvious thing is some
+ kind of front-end to "cvs admin" but I'm not actually sure that
+ is the most useful thing. */
+extern SCC_return SccRunScc
+ (void *context_arg, HWND window,
+
+ LONG num_files,
+ LPSTR *file_names);
+
+/* If the user invokes version-control-system-defined behavior
+ (typically by clicking an Advanced button in a dialog, e.g. the Get
+ dialog), and the user clicks on that button, then the development
+ environment calls SccGetCommandOptions. The version control system
+ interacts with the user and then sets *PROV_OPTIONSP to whatever it
+ wants. The development environment doesn't do anything with it,
+ but does pass it to the various commands as prov_options. If it
+ calls SccGetCommandOptions again, it will pass the same value (so
+ user choices from the previous "Advanced" click can serve as
+ defaults).
+
+ Note that "provider options" (prov_options) are unrelated to
+ "command options" (SCC_cmdopt_*). */
+
+extern SCC_return SccGetCommandOptions
+ (void *context_arg, HWND window,
+ enum SCC_command command,
+ void **prov_optionsp);
+
+/* Not existing CVS functionality, I don't think.
+ Need to be able to tell user about what files
+ are out there without actually getting them. */
+extern SCC_return SccPopulateList
+ (void *context_arg, enum SCC_command command,
+
+ LONG num_files,
+ LPSTR *file_names,
+
+ SCC_popul_proc populate,
+ void *callerdat,
+
+ /* Command options. I'm not sure what command options,
+ if any, are defined for SccPopulateList. */
+ LONG options);
+
+/* cvs status, sort of. */
+extern SCC_return SccQueryInfo
+ (void *context_arg,
+
+ LONG num_files, LPSTR *file_names,
+
+ /* This is an array of NUM_FILES entries. In each one
+ we store a SCC_status_* code. */
+ LPLONG status);
+
+/* Like QueryInfo, but fast and for only a single file. For example, the
+ development environment might call this quite frequently to keep its
+ screen display updated. Supposed to only return cached status
+ information, not go to disk or anything. I assume that
+ QueryInfo and probably the usual calls like Get would cause
+ the version control system to cache the status in the first place. */
+extern SCC_return SccGetEvents
+ (void *context_arg, LPSTR file_name,
+
+ /* Here the version control system stores the SCC_status_* code. */
+ LPLONG status,
+
+ LPLONG events_remaining);
+
+/* This is where the user gives us the CVSROOT. */
+extern SCC_return SccGetProjPath
+ (void *context_arg, HWND window, LPSTR user,
+
+ /* Version control system copies in the project name
+ here, up to SCC_max_path bytes. */
+ LPSTR proj_name,
+
+ /* If allow_change, the version control system may copy
+ into this field, up to SCC_max_path bytes. */
+ LPSTR local_proj,
+
+ /* Version control system copies into this field, up to
+ SCC_max_path bytes. */
+ LPSTR aux_proj,
+
+ BOOL allow_change, BOOL *new);
+
+/* Pretty much similar to SccPopulateList. Not sure whether this also
+ involves getting the files, or whether the development environment will
+ typically call SccGet after this function. */
+extern SCC_return SccAddFromScc
+ (void *context_arg, HWND window,
+
+ /* Version control system sets *files to the number of files and
+ *file_names to an array each element of which and contains the
+ name of one of the files. The names can be relative pathnames
+ (e.g. "foo.c"). If files is NULL, that means something different;
+ the version control system should free the memory that it allocated
+ for file_names. */
+ LONG *files,
+ char ***file_names);
+
+/* This changes several aspects of how we interact with the IDE. */
+extern SCC_return SccSetOption
+ (void *context_arg,
+ /* One of the SCC_option_* codes. */
+ LONG option,
+ /* Meaning of this will depend on the value of option. */
+ LONG val);
+
+/* New functions with CodeWright 5.00c: SccAddRef, SccRelease,
+ SccDiffToRev, SccLabel, SccLock and SccMerge. I don't have any
+ details on them. */
diff --git a/windows-NT/SCC/scc.c b/windows-NT/SCC/scc.c
new file mode 100644
index 0000000..9f74af4
--- /dev/null
+++ b/windows-NT/SCC/scc.c
@@ -0,0 +1,469 @@
+/* This file was written by Jim Kingdon, and is hereby placed
+ in the public domain. */
+
+#include <Wtypes.h>
+#include <stdio.h>
+#include <direct.h> /* For chdir */
+
+#include "pubscc.h"
+
+/* We get to put whatever we want here, and the caller will pass it
+ to us, so we don't need any global variables. This is the
+ "void *context_arg" argument to most of the Scc* functions. */
+struct context {
+ FILE *debuglog;
+ /* Value of the CVSROOT we are currently working with (that is, the
+ "open project" in SCC terminology), malloc'd, or NULL if there is
+ no project currently open. */
+ char *root;
+ /* Local directory (working directory in CVS parlance). */
+ char *local;
+ SCC_outproc outproc;
+};
+
+/* In addition to context_arg, most of the Scc* functions take a
+ "HWND window" argument. This is so that we can put up dialogs.
+ The window which is passed in is the IDE's window, which we
+ should use as the parent of dialogs that we put up. */
+
+#include <windows.h>
+
+/* Report a malloc error and return the SCC_return_* value which the
+ caller should return to the IDE. Probably this should be getting
+ the window argument too, but for the moment we don't need it.
+ Note that we only use this for errors which occur after the
+ context->outproc is set up. */
+SCC_return
+malloc_error (struct context *context)
+{
+ (*context->outproc) ("Out of memory\n", SCC_outproc_error);
+ return SCC_return_non_specific_error;
+}
+
+/* Return the version of the SCC spec, major version in the high word,
+ minor version in the low word. */
+LONG
+SccGetVersion (void)
+{
+ /* We implement version 1.1 of the spec. */
+ return 0x10001;
+}
+
+SCC_return
+SccInitialize (void **contextp, HWND window, LPSTR caller, LPSTR name,
+ LPLONG caps, LPSTR path, LPDWORD co_comment_len,
+ LPDWORD comment_len)
+{
+ struct context *context;
+ FILE *fp;
+ fp = fopen ("d:\\debug.scc", "w");
+ if (fp == NULL)
+ /* Do what? Return some error value? */
+ abort ();
+ context = malloc (sizeof (struct context));
+ if (context == NULL)
+ {
+ fprintf (fp, "Out of memory\n");
+ fclose (fp);
+ /* Do what? Return some error? */
+ abort ();
+ }
+ context->debuglog = fp;
+ context->root = NULL;
+ *contextp = context;
+ fprintf (fp, "Made it into SccInitialize!\n");
+ *caps = (SCC_cap_GetProjPath
+ | SCC_cap_AddFromScc
+ | SCC_cap_want_outproc);
+
+ /* I think maybe this should have some more CVS-like
+ name, like "CVS Root", if we decide that is what
+ a SCC "project" is. */
+ strncpy (path, "CVS Project:", SCC_max_init_path);
+ fprintf (fp, "Caller name is %s\n", caller);
+ strncpy (name, "CVS", SCC_max_name);
+ /* CVS has no limit on comment length. But I suppose
+ we need to return a value which is small enough for
+ a caller to allocate a buffer this big. Not that I
+ would write a caller that way, but..... */
+ *co_comment_len = 8192;
+ *comment_len = 8192;
+ fflush (fp);
+ return SCC_return_success;
+}
+
+SCC_return
+SccUninitialize (void *context_arg)
+{
+ struct context *context = (struct context *)context_arg;
+ if (ferror (context->debuglog))
+ /* FIXME: return error value... */
+ if (fclose (context->debuglog) == EOF)
+ /* FIXME: return error value, I think. */
+ ;
+ free (context);
+ return SCC_return_success;
+}
+
+SCC_return
+SccOpenProject (void *context_arg, HWND window, LPSTR user,
+ LPSTR project, LPSTR local_proj, LPSTR aux_proj,
+ LPSTR comment, SCC_outproc outproc,
+ LONG flags)
+{
+ struct context *context = (struct context *)context_arg;
+
+ /* This can happen if the IDE opens a project which is not under
+ CVS control. I'm not sure whether checking for aux_proj
+ being "" is the right way to detect this case, but it seems
+ it should work because I think that the source code control
+ system is what has control over the contents of aux_proj. */
+ if (aux_proj[0] == '\0')
+ return SCC_return_unknown_project;
+
+ context->root = malloc (strlen (aux_proj) + 5);
+ if (context->root == NULL)
+ return SCC_return_non_specific_error;
+ strcpy (context->root, aux_proj);
+ /* Since we don't yet support creating projects, we don't
+ do anything with flags. */
+
+ if (outproc == 0)
+ {
+ /* This supposedly can happen if the IDE chooses not to implement
+ the outproc feature. */
+ fprintf (context->debuglog, "Uh oh. outproc is a null pointer\n");
+ context->root = NULL;
+ fflush (context->debuglog);
+ return SCC_return_non_specific_error;
+ }
+ context->outproc = outproc;
+
+ fprintf (context->debuglog, "SccOpenProject (aux_proj=%s)\n", aux_proj);
+
+ context->local = malloc (strlen (local_proj) + 5);
+ if (context->local == NULL)
+ return malloc_error (context);
+ strcpy (context->local, local_proj);
+
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+SCC_return
+SccCloseProject (void *context_arg)
+{
+ struct context *context = (struct context *)context_arg;
+ fprintf (context->debuglog, "SccCloseProject\n");
+ fflush (context->debuglog);
+ if (context->root != NULL)
+ free (context->root);
+ context->root = NULL;
+ return SCC_return_success;
+}
+
+/* cvs get. */
+SCC_return
+SccGet (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names,
+ LONG options,
+ void *prov_options)
+{
+ struct context *context = (struct context *)context_arg;
+ int i;
+ char *fname;
+
+ fprintf (context->debuglog, "SccGet: %d; files:", num_files);
+#if 1
+ for (i = 0; i < num_files; ++i)
+ {
+ fprintf (context->debuglog, "%s ", file_names[i]);
+ }
+#endif
+ fprintf (context->debuglog, "\n");
+ if (options & SCC_cmdopt_dir)
+ fprintf (context->debuglog, " Get all\n");
+ /* Should be using this flag to set -R vs. -l. */
+ if (options & SCC_cmdopt_recurse)
+ fprintf (context->debuglog, " recurse\n");
+
+ for (i = 0; i < num_files; ++i)
+ {
+ /* As with all file names passed to us by the SCC, these
+ file names are absolute pathnames. I think they will
+ tend to be paths within context->local, although I
+ don't know whether there are any exceptions to that. */
+ fname = file_names[i];
+ fprintf (context->debuglog, "%s ", fname);
+ /* Here we would write to the file named fname. */
+ }
+ fprintf (context->debuglog, "\nExiting SccGet\n");
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+/* cvs edit. */
+SCC_return
+SccCheckout (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment,
+ LONG options,
+ void *prov_options)
+{
+ struct context *context = (struct context *)context_arg;
+ fprintf (context->debuglog, "SccCheckout num_files=%ld\n", num_files);
+ fflush (context->debuglog);
+ /* For the moment we say that all files are not ours. I'm not sure
+ whether this is ever necessary; that is, whether the IDE will call
+ us except where we have told the IDE that a file is under source
+ control. */
+ /* I'm not sure what we would do if num_files > 1 and we wanted to
+ return different statuses for different files. */
+ return SCC_return_non_scc_file;
+}
+
+/* cvs ci. */
+SCC_return
+SccCheckin (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment,
+ LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs unedit. */
+SCC_return
+SccUncheckout (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names,
+ LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs add + cvs ci, more or less, I think (but see also
+ the "keep checked out" flag in options). */
+SCC_return
+SccAdd (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment,
+ LONG *options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs rm -f + cvs ci, I think. Should barf if SCC_REMOVE_KEEP
+ (or maybe just put the file there, as if the user had removed
+ it and then done a "copy <saved-file> <filename>". */
+SCC_return
+SccRemove (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment,
+ LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* mv, cvs add, cvs rm, and cvs ci, I think. */
+SCC_return
+SccRename (void *context_arg, HWND window, LPSTR old_name,
+ LPSTR new_name)
+{
+ return SCC_return_not_supported;
+}
+
+/* If SCC_cmdopt_compare_files, SCC_cmdopt_consult_checksum, or
+ SCC_cmdopt_consult_timestamp, then we are supposed to silently
+ return a status, without providing any information directly to the
+ user. For no args or checksum (which we fall back to full compare)
+ basically a call to No_Diff or ? in the client case. For
+ timestamp, just a Classify_File. Now, if contents not set, then
+ want to do a cvs diff, and preferably start up WinDiff or something
+ (to be determined, for now perhaps could just return text via
+ outproc). */
+SCC_return
+SccDiff (void *context_arg, HWND window, LPSTR file_name,
+ LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs log, I presume. If we want to get fancier we could bring
+ up a screen more analogous to the tkCVS log window, let the user
+ do "cvs update -r", etc. */
+SCC_return
+SccHistory (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names,
+ LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs status, presumably. */
+SCC_return
+SccProperties (void *context_arg, HWND window, LPSTR file_name)
+{
+ return SCC_return_not_supported;
+}
+
+/* Not sure what this should do. The most obvious thing is some
+ kind of front-end to "cvs admin" but I'm not actually sure that
+ is the most useful thing. */
+SCC_return
+SccRunScc (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names)
+{
+ return SCC_return_not_supported;
+}
+
+/* Lots of things that we could do here. Options to get/update
+ such as -r -D -k etc. just for starters. Note that the terminology is
+ a little confusing here. This function relates to "provider options"
+ (prov_options) which are a way for us to provide extra dialogs beyond
+ the basic ones for a particular command. It is unrelated to "command
+ options" (SCC_cmdopt_*). */
+SCC_return
+SccGetCommandOptions (void *context_arg, HWND window,
+ enum SCC_command command,
+ void **prov_optionsp)
+{
+ return SCC_return_not_supported;
+}
+
+/* Not existing CVS functionality, I don't think.
+ Need to be able to tell user about what files
+ are out there without actually getting them. */
+SCC_return
+SccPopulateList (void *context_arg, enum SCC_command command,
+ LONG num_files,
+ LPSTR *file_names, SCC_popul_proc populate,
+ void *callerdat,
+ LONG options)
+{
+ return SCC_return_success;
+}
+
+/* cvs status, sort of. */
+SCC_return
+SccQueryInfo (void *context_arg, LONG num_files, LPSTR *file_names,
+ LPLONG status)
+{
+ return SCC_return_not_supported;
+}
+
+/* Like QueryInfo, but fast and for only a single file. For example, the
+ development environment might call this quite frequently to keep its
+ screen display updated. */
+SCC_return
+SccGetEvents (void *context_arg, LPSTR file_name,
+ LPLONG status,
+ LPLONG events_remaining)
+{
+ /* They say this is supposed to only return cached status
+ information, not go to disk or anything. I assume that
+ QueryInfo and probably the usual calls like Get would cause
+ us to cache the status in the first place. */
+ return SCC_return_success;
+}
+
+/* This is where the user gives us the CVSROOT. */
+SCC_return
+SccGetProjPath (void *context_arg, HWND window, LPSTR user,
+ LPSTR proj_name, LPSTR local_proj, LPSTR aux_proj,
+ BOOL allow_change, BOOL *new)
+{
+ /* For now we just hardcode the CVSROOT. In the future we will
+ of course prompt the user for it (simple implementation would
+ have them supply a string; potentially better implementation
+ would have menus or something for access methods and so on,
+ although it might also have a way of bypassing that in case
+ CVS supports new features that the GUI code doesn't
+ understand). We probably will also at some point want a
+ "project" to encompass both a CVSROOT and a directory or
+ module name within that CVSROOT, but we don't try to handle
+ that yet either. We also will want to be able to use "user"
+ instead of having the username encoded in the aux_proj or
+ proj_name, probably. */
+
+ struct context *context = (struct context *)context_arg;
+ fprintf (context->debuglog, "SccGetProjPath called\n");
+
+ /* At least for now we leave the proj_name alone, and just use
+ the aux_proj. */
+ strncpy (proj_name, "zwork", SCC_max_path);
+ strncpy (aux_proj, ":server:harvey:/home/kingdon/zwork/cvsroot",
+ SCC_max_path);
+ if (local_proj[0] == '\0' && allow_change)
+ strncpy (local_proj, "d:\\sccwork", SCC_max_path);
+ /* I don't think I saw anything in the spec about this,
+ but let's see if it helps. */
+ if (_chdir (local_proj) < 0)
+ fprintf (context->debuglog, "Error in chdir: %s", strerror (errno));
+
+ if (*new)
+ /* It is OK for us to prompt the user for creating a new
+ project. */
+ /* We will say that the user said to create a new one. */
+ *new = 1;
+
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+/* Pretty much similar to SccPopulateList. */
+SCC_return
+SccAddFromScc (void *context_arg, HWND window, LONG *files,
+ char ***file_names)
+{
+ struct context *context = (struct context *)context_arg;
+
+ /* For now we have hardcoded the notion that there are two files,
+ foo.c and bar.c. */
+#define NUM_FILES 2
+ if (files == NULL)
+ {
+ char **p;
+
+ /* This means to free the memory that is allocated for
+ file_names. */
+ for (p = *file_names; *p != NULL; ++p)
+ {
+ fprintf (context->debuglog, "Freeing %s\n", *p);
+ free (*p);
+ }
+ }
+ else
+ {
+ *file_names = malloc ((NUM_FILES + 1) * sizeof (char **));
+ if (*file_names == NULL)
+ return malloc_error (context);
+ (*file_names)[0] = malloc (80);
+ if ((*file_names)[0] == NULL)
+ return malloc_error (context);
+ strcpy ((*file_names)[0], "foo.c");
+ (*file_names)[1] = malloc (80);
+ if ((*file_names)[1] == NULL)
+ return malloc_error (context);
+ strcpy ((*file_names)[1], "bar.c");
+ (*file_names)[2] = NULL;
+ *files = 2;
+
+ /* Are we supposed to also Get the files? Or is the IDE
+ next going to call SccGet on each one? The spec doesn't
+ say explicitly. */
+ }
+ fprintf (context->debuglog, "Success in SccAddFromScc\n");
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+/* This changes several aspects of how we interact with the IDE. */
+SCC_return
+SccSetOption (void *context_arg,
+ LONG option,
+ LONG val)
+{
+ return SCC_return_success;
+}
diff --git a/windows-NT/SCC/scc.def b/windows-NT/SCC/scc.def
new file mode 100644
index 0000000..cf4eded
--- /dev/null
+++ b/windows-NT/SCC/scc.def
@@ -0,0 +1,25 @@
+LIBRARY SCC
+EXPORTS
+ SccInitialize @1
+ SccUninitialize @2
+ SccOpenProject @3
+ SccCloseProject @4
+ SccGet @5
+ SccCheckout @6
+ SccUncheckout @7
+ SccCheckin @8
+ SccAdd @9
+ SccRemove @10
+ SccRename @11
+ SccDiff @12
+ SccHistory @13
+ SccProperties @14
+ SccRunScc @15
+ SccGetCommandOptions @16
+ SccQueryInfo @17
+ SccGetEvents @18
+ SccGetProjPath @19
+ SccPopulateList @20
+ SccAddFromScc @21
+ SccSetOption @22
+ SccGetVersion @23
diff --git a/windows-NT/arpa/inet.h b/windows-NT/arpa/inet.h
new file mode 100644
index 0000000..fa882cb
--- /dev/null
+++ b/windows-NT/arpa/inet.h
@@ -0,0 +1 @@
+/* empty file */
diff --git a/windows-NT/config.h b/windows-NT/config.h
new file mode 100644
index 0000000..da2335f
--- /dev/null
+++ b/windows-NT/config.h
@@ -0,0 +1,1452 @@
+/* This file is generated via a rule in Makefile.am from the
+ * config.h.in file.
+ *
+ * *** DO NOT EDIT THIS FILE DIRECTLY ***
+ *
+ * Edit config.h.in instead.
+ */
+/***
+ *** config.h.in, generated by mkconfig.pl:
+ ***
+ *** (config.h.in.in
+ *** + ../config.h.in)
+ *** . config.h.in.footer
+ *** --> config.h.in
+ ***
+ *** ***** DO NOT ALTER THIS FILE!!! *****
+ ***
+ *** Changes to this file will be overwritten by automatic script runs.
+ *** Changes should be made to the config.h.in.in & config.h.in.footer
+ *** files instead.
+ ***/
+
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define this to a NULL terminated list of allowed path prefixes (for
+ directories) and paths to files the CVS server will allow configuration to
+ be read from when specified from the command line. */
+#undef ALLOW_CONFIG_OVERRIDE
+
+/* Enable AUTH_CLIENT_SUPPORT to enable pserver as a remote access method in
+ the CVS client (default) */
+#define AUTH_CLIENT_SUPPORT 1
+
+/* Define if you want to use the password authenticated server. */
+#undef AUTH_SERVER_SUPPORT
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#define CLIENT_SUPPORT
+
+/* Define to 1 if the `closedir' function returns void instead of `int'. */
+#undef CLOSEDIR_VOID
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* define if cross compiling */
+#undef CROSS_COMPILING
+
+/* The CVS admin command is restricted to the members of the group
+ CVS_ADMIN_GROUP. If this group does not exist, all users are allowed to run
+ CVS admin. To disable the CVS admin command for all users, create an empty
+ CVS_ADMIN_GROUP by running configure with the --with-cvs-admin-group=
+ option. To disable access control for CVS admin, run configure with the
+ --without-cvs-admin-group option in order to comment out the define below.
+ */
+#undef CVS_ADMIN_GROUP
+
+/* When committing a permanent change, CVS and RCS make a log entry of who
+ committed the change. If you are committing the change logged in as "root"
+ (not under "su" or other root-priv giving program), CVS/RCS cannot
+ determine who is actually making the change. As such, by default, CVS
+ prohibits changes committed by users logged in as "root". You can disable
+ checking by passing the "--enable-rootcommit" option to configure or by
+ commenting out the lines below. */
+#undef CVS_BADROOT
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define if there is a member named d_ino in the struct describing directory
+ headers. */
+#undef D_INO_IN_DIRENT
+
+/* The default editor to use, if one does not specify the "-e" option to cvs,
+ or does not have an EDITOR environment variable. If this is not set to an
+ absolute path to an executable, use the shell to find where the editor
+ actually is. This allows sites with /usr/bin/vi or /usr/ucb/vi to work
+ equally well (assuming that their PATH is reasonable). */
+#define EDITOR_DFLT "notepad"
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#undef ENABLE_NLS
+
+/* Define to enable encryption support. */
+#undef ENCRYPTION
+
+/* Define as good substitute value for EOVERFLOW. */
+#define EOVERFLOW EINVAL
+
+/* Define if this executable will be running on case insensitive file systems.
+ In the client case, this means that it will request that the server pretend
+ to be case insensitive if it isn't already. */
+#define FILENAMES_CASE_INSENSITIVE 1
+
+/* Define on systems for which file names may have a so-called `drive letter'
+ prefix, define this to compute the length of that prefix, including the
+ colon. */
+#define FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX 1
+
+/* Define if the backslash character may also serve as a file name component
+ separator. */
+#define FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR 1
+
+#if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+# define FILE_SYSTEM_PREFIX_LEN(Filename) \
+ ((Filename)[0] && (Filename)[1] == ':' ? 2 : 0)
+#else
+# define FILE_SYSTEM_PREFIX_LEN(Filename) 0
+#endif
+
+/* When committing or importing files, you must enter a log message. Normally,
+ you can do this either via the -m flag on the command line, the -F flag on
+ the command line, or an editor will be started for you. If you like to use
+ logging templates (the rcsinfo file within the $CVSROOT/CVSROOT directory),
+ you might want to force people to use the editor even if they specify a
+ message with -m or -F. Enabling FORCE_USE_EDITOR will cause the -m or -F
+ message to be appended to the temp file when the editor is started. */
+#undef FORCE_USE_EDITOR
+
+/* Define to an alternative value if GSS_C_NT_HOSTBASED_SERVICE isn't defined
+ in the gssapi.h header file. MIT Kerberos 1.2.1 requires this. Only
+ relevant when using GSSAPI. */
+#undef GSS_C_NT_HOSTBASED_SERVICE
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have `alloca' after including <alloca.h>, a header that
+ may be supplied by this distribution. */
+#undef HAVE_ALLOCA
+
+/* Define HAVE_ALLOCA_H for backward compatibility with older code that
+ includes <alloca.h> only if HAVE_ALLOCA_H is defined. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the `atexit' function. */
+#define HAVE_ATEXIT 1
+
+/* Define to 1 if you have the <bp-sym.h> header file. */
+#undef HAVE_BP_SYM_H
+
+/* Define to 1 if you have the `btowc' function. */
+#undef HAVE_BTOWC
+
+/* Define to 1 if you have the `canonicalize_file_name' function. */
+#undef HAVE_CANONICALIZE_FILE_NAME
+
+/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+#undef HAVE_CFLOCALECOPYCURRENT
+
+/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+#undef HAVE_CFPREFERENCESCOPYAPPVALUE
+
+/* Define to 1 if you have the `chsize' function. */
+#define HAVE_CHSIZE 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `clock_settime' function. */
+#undef HAVE_CLOCK_SETTIME
+
+/* Define if you have the connect function. */
+#define HAVE_CONNECT
+
+/* Define if you have the crypt function. */
+#undef HAVE_CRYPT
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+#undef HAVE_DCGETTEXT
+
+/* Define to 1 if you have the declaration of `clearerr_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_CLEARERR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FEOF_UNLOCKED
+
+/* Define to 1 if you have the declaration of `ferror_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FERROR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fflush_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FFLUSH_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FGETS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `flockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FLOCKFILE
+
+/* Define to 1 if you have the declaration of `fputc_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fputs_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fread_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FREAD_UNLOCKED
+
+/* Define to 1 if you have the declaration of `funlockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FUNLOCKFILE
+
+/* Define to 1 if you have the declaration of `fwrite_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FWRITE_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getcwd', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETCWD 1
+
+/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getdelim', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETDELIM
+
+/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETENV 1
+
+/* Define to 1 if you have the declaration of `getline', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLINE
+
+/* Define to 1 if you have the declaration of `getlogin', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN
+
+/* Define to 1 if you have the declaration of `getlogin_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN_R
+
+/* Define to 1 if you have the declaration of `getpass', and to 0 if you
+ don't. */
+#define HAVE_DECL_GETPASS 1
+
+/* Define to 1 if you have the declaration of `memrchr', and to 0 if you
+ don't. */
+#undef HAVE_DECL_MEMRCHR
+
+/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
+ don't. */
+#define HAVE_DECL_NANOSLEEP 1
+
+/* Define to 1 if you have the declaration of `putchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_PUTCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `putc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_PUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `strdup', and to 0 if you don't.
+ */
+#define HAVE_DECL_STRDUP 1
+
+/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_STRERROR_R
+
+/* Define to 1 if you have the declaration of `__fpending', and to 0 if you
+ don't. */
+#define HAVE_DECL___FPENDING 0
+
+/* Define to 1 if you have the <direct.h> header file. */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dup2' function. */
+#define HAVE_DUP2 1
+
+/* Define if you have the declaration of environ. */
+#define HAVE_ENVIRON_DECL 1
+
+/* Define if you have the declaration of errno. */
+#define HAVE_ERRNO_DECL 1
+
+/* Define to 1 if you have the `fchdir' function. */
+#undef HAVE_FCHDIR
+
+/* Define to 1 if you have the `fchmod' function. */
+#undef HAVE_FCHMOD
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `flockfile' function. */
+#undef HAVE_FLOCKFILE
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `fsync' function. */
+#undef HAVE_FSYNC
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have the `funlockfile' function. */
+#undef HAVE_FUNLOCKFILE
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `getgroups' function. */
+#undef HAVE_GETGROUPS
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `getlogin_r' function. */
+#undef HAVE_GETLOGIN_R
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long_only' function. */
+#undef HAVE_GETOPT_LONG_ONLY
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define if you have the getspnam function. */
+#undef HAVE_GETSPNAM
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#undef HAVE_GETTEXT
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H 1
+
+/* Define if you have GSSAPI with Kerberos version 5 available. */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
+/* Define if you have the iconv() function. */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_INTMAX_T
+
+/* Define if <inttypes.h> exists and doesn't clash with <sys/types.h>. */
+#undef HAVE_INTTYPES_H
+
+/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
+ declares uintmax_t. */
+#undef HAVE_INTTYPES_H_WITH_UINTMAX
+
+/* Define to 1 if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET. */
+#define HAVE_IPV4 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET6. */
+#undef HAVE_IPV6
+
+/* Define to 1 if you have the `isascii' function. */
+#define HAVE_ISASCII 1
+
+/* Define to 1 if you have the `isblank' function. */
+#undef HAVE_ISBLANK
+
+/* Define to 1 if you have the `iswprint' function. */
+#define HAVE_ISWPRINT 1
+
+/* Define if you have MIT Kerberos version 4 available. */
+#undef HAVE_KERBEROS
+
+/* Define to 1 if you have the <krb5.h> header file. */
+#undef HAVE_KRB5_H
+
+/* Define to 1 if you have the `krb_get_err_text' function. */
+#undef HAVE_KRB_GET_ERR_TEXT
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#undef HAVE_LANGINFO_CODESET
+
+/* Define to 1 if you have the `krb' library (-lkrb). */
+#undef HAVE_LIBKRB
+
+/* Define to 1 if you have the `krb4' library (-lkrb4). */
+#undef HAVE_LIBKRB4
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `login' function. */
+#undef HAVE_LOGIN
+
+/* Define to 1 if you have the `logout' function. */
+#undef HAVE_LOGOUT
+
+/* Define if you have the 'long double' type. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have the 'long long' type. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including
+ config.h and <sys/mman.h>. */
+#undef HAVE_MAP_ANONYMOUS
+
+/* Define to 1 if you have the `mblen' function. */
+#define HAVE_MBLEN 1
+
+/* Define to 1 if you have the `mbrlen' function. */
+#define HAVE_MBRLEN 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if you have the `mbsinit' function. */
+#undef HAVE_MBSINIT
+
+/* Define to 1 if you have the `mbsrtowcs' function. */
+#define HAVE_MBSRTOWCS 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define if you have memchr (always for CVS). */
+#define HAVE_MEMCHR 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mempcpy' function. */
+#undef HAVE_MEMPCPY
+
+/* Define to 1 if you have the `memrchr' function. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if <limits.h> defines the MIN and MAX macros. */
+#define HAVE_MINMAX_IN_LIMITS_H 1
+
+/* Define to 1 if <sys/param.h> defines the MIN and MAX macros. */
+#undef HAVE_MINMAX_IN_SYS_PARAM_H
+
+/* Define to 1 if you have the `mknod' function. */
+#undef HAVE_MKNOD
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `nanotime' function. */
+#undef HAVE_NANOTIME
+
+/* Define to 1 if you have the <ndbm.h> header file. */
+#undef HAVE_NDBM_H
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#define HAVE_NDIR_H 1
+
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
+/* Define to 1 if you have the <OS.h> header file. */
+#undef HAVE_OS_H
+
+/* Define to enable system authentication with PAM instead of using the simple
+ getpwnam interface. This allows authentication (in theory) with any PAM
+ module, e.g. on systems with shadow passwords or via LDAP */
+#undef HAVE_PAM
+
+/* Define to 1 if pam/pam_appl.h is available */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
+ setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX is not
+ defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD is defined.
+ */
+#undef HAVE_PARTLY_WORKING_GETCWD
+
+/* Define to 1 if you have the `posix_memalign' function. */
+#undef HAVE_POSIX_MEMALIGN
+
+/* Define to 1 if the `printf' function supports the %p format for printing
+ pointers. */
+#define HAVE_PRINTF_PTR 1
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#define HAVE_PTRDIFF_T 1
+
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#define HAVE_REALLOC 1
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the `regerror' function. */
+#undef HAVE_REGERROR
+
+/* Define to 1 if you have the `regexec' function. */
+#undef HAVE_REGEXEC
+
+/* Define to 1 if you have the `regfree' function. */
+#undef HAVE_REGFREE
+
+/* Define to 1 if you have the `resolvepath' function. */
+#undef HAVE_RESOLVEPATH
+
+/* Define to 1 if you have the `rpmatch' function. */
+#undef HAVE_RPMATCH
+
+/* Define to 1 if you have run the test for working tzset. */
+#define HAVE_RUN_TZSET_TEST 1
+
+/* Define to 1 if you have the <search.h> header file. */
+#define HAVE_SEARCH_H 1
+
+/* Define to 1 if security/pam_appl.h is available */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define if the diff library should use setmode for binary files. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigblock' function. */
+#undef HAVE_SIGBLOCK
+
+/* Define to 1 if you have the `siginterrupt' function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define to 1 if you have the `sigsetmask' function. */
+#undef HAVE_SIGSETMASK
+
+/* Define to 1 if you have the `sigvec' function. */
+#undef HAVE_SIGVEC
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
+ uintmax_t. */
+#define HAVE_STDINT_H_WITH_UINTMAX 1
+
+/* Define to 1 if you have the <stdio_ext.h> header file. */
+#undef HAVE_STDIO_EXT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have strchr (always for CVS). */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define if there is a member named d_type in the struct describing directory
+ headers. */
+#undef HAVE_STRUCT_DIRENT_D_TYPE
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define if struct timespec is declared in <time.h>. */
+#undef HAVE_STRUCT_TIMESPEC
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_ZONE
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/inttypes.h> header file. */
+#undef HAVE_SYS_INTTYPES_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `tcgetattr' function. */
+#undef HAVE_TCGETATTR
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the `timezone' function. */
+#undef HAVE_TIMEZONE
+
+/* Define to 1 if localtime_r, etc. have the type signatures that POSIX
+ requires. */
+#undef HAVE_TIME_R_POSIX
+
+/* Define if struct tm has the tm_gmtoff member. */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#undef HAVE_TM_ZONE
+
+/* Define to 1 if you have the `tsearch' function. */
+#undef HAVE_TSEARCH
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the `tzset' function. */
+#define HAVE_TZSET 1
+
+/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_UINTMAX_T
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define if you have the 'unsigned long long' type. */
+#undef HAVE_UNSIGNED_LONG_LONG
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
+#define HAVE_UTIME_NULL 1
+
+/* Define to 1 if you have the `vasnprintf' function. */
+#undef HAVE_VASNPRINTF
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `wait3' function. */
+#undef HAVE_WAIT3
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define if you have the 'wchar_t' type. */
+#define HAVE_WCHAR_T 1
+
+/* Define to 1 if you have the `wcrtomb' function. */
+#define HAVE_WCRTOMB 1
+
+/* Define to 1 if you have the `wcscoll' function. */
+#define HAVE_WCSCOLL 1
+
+/* Define to 1 if you have the `wcslen' function. */
+#define HAVE_WCSLEN 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define if you have the 'wint_t' type. */
+#define HAVE_WINT_T 1
+
+/* Define to 1 if you have the `wmemchr' function. */
+#define HAVE_WMEMCHR 1
+
+/* Define to 1 if you have the `wmemcpy' function. */
+#define HAVE_WMEMCPY 1
+
+/* Define to 1 if you have the `wmempcpy' function. */
+#undef HAVE_WMEMPCPY
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to 1 if you have the `__fpending' function. */
+#undef HAVE___FPENDING
+
+/* Define to 1 if you have the `__fsetlocking' function. */
+#undef HAVE___FSETLOCKING
+
+/* Define to 1 if you have the `__secure_getenv' function. */
+#undef HAVE___SECURE_GETENV
+
+#if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+#else
+# define ISSLASH(C) ((C) == '/')
+#endif
+
+/* Define to include locking code which prevents versions of CVS earlier than
+ 1.12.4 directly accessing the same repositiory as this executable from
+ ignoring this executable's promotable read locks. If only CVS versions
+ 1.12.4 and later will be accessing your repository directly (as a server or
+ locally), you can safely disable this option in return for fewer disk
+ accesses and a small speed increase. Disabling this option when versions of
+ CVS earlier than 1,12,4 _will_ be accessing your repository, however, is
+ *VERY* *VERY* *VERY* dangerous and could result in data loss. As such, by
+ default, CVS is compiled with this code enabled. If you are sure you would
+ like this code disabled, you can disable it by passing the
+ "--disable-lock-compatibility" option to configure or by commenting out the
+ lines below. */
+#define LOCK_COMPATIBILITY
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
+
+/* If malloc(0) is != NULL, define this to 1. Otherwise define this to 0. */
+#undef MALLOC_0_IS_NONNULL
+
+/* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */
+#undef MAP_ANONYMOUS
+
+/* By default, CVS stores its modules and other such items in flat text files
+ (MY_NDBM enables this). Turning off MY_NDBM causes CVS to look for a
+ system-supplied ndbm database library and use it instead. That may speed
+ things up, but the default setting generally works fine too. */
+#define MY_NDBM
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "bug-cvs@nongnu.org"
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "Concurrent Versions System (CVS) 1.12.13"
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to set a service name for PAM. This must be defined. Define to
+ `program_name', without the quotes, to use whatever name CVS was invoked
+ as. Otherwise, define to a double-quoted literal string, such as `"cvs"'.
+ */
+#undef PAM_SERVICE_NAME
+
+/* the number of pending output bytes on stream `fp' */
+#define PENDING_OUTPUT_N_BYTES ( fp ? fp->_ptr - fp->_base : 0 )
+
+/* Define if you want CVS to be able to serve as a transparent proxy for write
+ operations. Disabling this may produce a slight performance gain on some
+ systems, at the expense of write proxy support. */
+#undef PROXY_SUPPORT
+
+/* Path to the pr utility */
+#undef PR_PROGRAM
+
+/* Define to force lib/regex.c to use malloc instead of alloca. */
+#define REGEX_MALLOC 1
+
+/* Define if rename does not work for source file names with a trailing slash,
+ like the one from SunOS 4.1.1_U1. */
+#undef RENAME_TRAILING_SLASH_BUG
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* If you are working with a large remote repository and a 'cvs checkout' is
+ swamping your network and memory, define these to enable flow control. You
+ will end up with even less probability of a consistent checkout (see
+ Concurrency in cvs.texinfo), but CVS doesn't try to guarantee that anyway.
+ The master server process will monitor how far it is getting behind, if it
+ reaches the high water mark, it will signal the child process to stop
+ generating data when convenient (ie: no locks are held, currently at the
+ beginning of a new directory). Once the buffer has drained sufficiently to
+ reach the low water mark, it will be signalled to start again. */
+#undef SERVER_FLOWCONTROL
+
+/* The high water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_HI_WATER
+
+/* The low water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_LO_WATER
+
+/* Define if you want CVS to be able to serve repositories to remote clients.
+ */
+#undef SERVER_SUPPORT
+
+/* The size of a `char', as computed by sizeof. */
+#define SIZEOF_CHAR 1
+
+/* The size of a `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of a `float', as computed by sizeof. */
+#define SIZEOF_FLOAT 4
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `intmax_t', as computed by sizeof. */
+#undef SIZEOF_INTMAX_T
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of a `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 8
+
+/* The size of a `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of a `ptrdiff_t', as computed by sizeof. */
+#define SIZEOF_PTRDIFF_T 4
+
+/* The size of a `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of a `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of a `wint_t', as computed by sizeof. */
+#define SIZEOF_WINT_T 2
+
+/* Define as the maximum value of type 'size_t', if the system doesn't define
+ it. */
+#define SIZE_MAX (~(size_t)0)
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#define STAT_MACROS_BROKEN 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r returns char *. */
+#undef STRERROR_R_CHAR_P
+
+/* Enable support for the pre 1.12.1 *info scripting hook format strings.
+ Disable this option for a smaller executable once your scripting hooks have
+ been updated to use the new *info format strings by passing
+ "--disable-old-info-format-support" option to configure or by commenting
+ out the line below. */
+#undef SUPPORT_OLD_INFO_FMT_STRINGS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little need
+ to change this (-T is a better mechanism if you need to use a different
+ directory for temporary files). */
+#define TMPDIR_DFLT "c:\\temp"
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define if tzset clobbers localtime's static buffer. */
+#undef TZSET_CLOBBERS_LOCALTIME_BUFFER
+
+/* Define to its maximum value if an unsigned integer type of width exactly 32
+ bits exists and the standard includes do not define UINT32_MAX. */
+#undef UINT32_MAX
+
+/* The default umask to use when creating or otherwise setting file or
+ directory permissions in the repository. Must be a value in the range of 0
+ through 0777. For example, a value of 002 allows group rwx access and world
+ rx access; a value of 007 allows group rwx access but no world access. This
+ value is overridden by the value of the CVSUMASK environment variable,
+ which is interpreted as an octal number. */
+#define UMASK_DFLT 002
+
+/* Define if double is the first floating point type detected with its size.
+ */
+#undef UNIQUE_FLOAT_TYPE_DOUBLE
+
+/* Define if float is the first floating point type detected with its size. */
+#undef UNIQUE_FLOAT_TYPE_FLOAT
+
+/* Define if long double is the first floating point type detected with its
+ size. */
+#undef UNIQUE_FLOAT_TYPE_LONG_DOUBLE
+
+/* Define if char is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_CHAR
+
+/* Define if int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INT
+
+/* Define if intmax_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INTMAX_T
+
+/* Define if long int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG
+
+/* Define if long long is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG_LONG
+
+/* Define if ptrdiff_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_PTRDIFF_T
+
+/* Define if short is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SHORT
+
+/* Define if size_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SIZE_T
+
+/* Define if wint_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_WINT_T
+
+/* Define if setmode is required when writing binary data to stdout. */
+#define USE_SETMODE_STDOUT 1
+
+/* Define to 1 if you want getc etc. to use unlocked I/O if available.
+ Unlocked I/O can improve performance in unithreaded apps, but it is not
+ safe for multithreaded apps. */
+#undef USE_UNLOCKED_IO
+
+/* Define if utime requires write access to the file (true on Windows, but not
+ Unix). */
+#define UTIME_EXPECTS_WRITABLE
+
+/* Define if unsetenv() returns void, not int. */
+#undef VOID_UNSETENV
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define if you want regoff_t to be at least as wide POSIX requires. */
+#undef _REGEX_LARGE_OFFSETS
+
+/* Define to force lib/regex.c to define re_comp et al. */
+#define _REGEX_RE_COMP 1
+
+/* Define for Solaris 2.5.1 so uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+
+/* Define to rpl_ if the getcwd replacement function should be used. */
+#undef __GETCWD_PREFIX
+
+/* Define to rpl_ if the getopt replacement functions and variables should be
+ used. */
+#define __GETOPT_PREFIX rpl_
+
+/* Define to rpl_ if the openat replacement function should be used. */
+#undef __OPENAT_PREFIX
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to a replacement function name for fnmatch(). */
+#undef fnmatch
+
+/* Define to a replacement function name for getline(). */
+#undef getline
+
+/* Define to a replacement function name for getpass(). */
+#undef getpass
+
+/* Define to rpl_gettimeofday if the replacement function should be used. */
+#undef gettimeofday
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to rpl_gmtime if the replacement function should be used. */
+#undef gmtime
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+
+/* Define to long or long long if <inttypes.h> and <stdint.h> don't define. */
+#undef intmax_t
+
+/* Define to rpl_localtime if the replacement function should be used. */
+#undef localtime
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to a type if <wchar.h> does not define. */
+#undef mbstate_t
+
+/* Define to rpl_mkdir if the replacement function should be used. */
+#undef mkdir
+
+/* Define to rpl_mkstemp if the replacement function should be used. */
+#undef mkstemp
+
+/* Define to rpl_mktime if the replacement function should be used. */
+#undef mktime
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define mode_t int
+
+/* Define to the name of the strftime replacement function. */
+#define my_strftime nstrftime
+
+/* Define to rpl_nanosleep if the replacement function should be used. */
+#define nanosleep woe32_nanosleep
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to rpl_realloc if the replacement function should be used. */
+#define realloc rpl_realloc
+
+/* Define to rpl_rename if the replacement function should be used. */
+#undef rename
+
+/* Define to equivalent of C99 restrict keyword, or to nothing if this is not
+ supported. Do not define if restrict is supported directly. */
+#define restrict
+
+/* Define to rpl_select if the replacement function should be used. */
+#undef select
+
+/* Define to empty if the C compiler doesn't support this keyword. */
+#undef signed
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define as a signed type of the same size as size_t. */
+#define ssize_t int
+
+/* Define to rpl_strcasecmp always. */
+#define strcasecmp rpl_strcasecmp
+
+/* Define to rpl_tzset if the wrapper function should be used. */
+#undef tzset
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to the type of a unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to unsigned long or unsigned long long if <stdint.h> and
+ <inttypes.h> don't define. */
+#undef uintmax_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
+/*============================================================================*/
+/* config.h.in.footer: configuration file for Windows NT
+ Conrad T. Pino <Conrad@Pino.com> --- May 2004 */
+
+/* This file lives in the windows-NT subdirectory, which is only included
+ in your header search path if you're working under Microsoft Visual C++,
+ and use ../cvsnt.mak for your project. Thus, this is the right place to
+ put configuration information for Windows NT. */
+
+/* This file is getting chaotic and will be organized as follows:
+
+ Macros appears first alphabetized in case sensitive order.
+ Typedefs appear next alphabetized in case sensitive order.
+ Function prototypes alphabetized in case sensitive order.
+
+ Reorgnized by Conrad T. Pino <Conrad@Pino.com> May 25, 2005 */
+
+/* just one time please */
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+/* ======================= Macro Definnitions Follow ====================== */
+
+/* Under Windows NT, mkdir only takes one argument. */
+#define CVS_MKDIR wnt_mkdir
+
+#define CVS_RENAME wnt_rename
+
+/* This is where old bits go to die under Windows NT. */
+#define DEVNULL "nul"
+
+/* Windows has no ELOOP value in errno.h */
+#define ELOOP EMLINK
+
+/* Windows has _snprintf function.
+ HAVE_DECL__SNPRINTF used in ../lib/vasnprintf.c */
+#define HAVE_DECL__SNPRINTF 1
+
+#define HAVE_WINSOCK_H
+
+/* This tells the client that it must use send()/recv() to talk to the
+ server if it is connected to the server via a socket; Win95 needs
+ it because _open_osfhandle doesn't work. */
+#define NO_SOCKET_TO_FD 1
+
+/* Is this true on NT? Seems like I remember reports that NT 3.51 has
+ problems with 200K writes (of course, the issue of large writes is
+ moot since the use of buffer.c ensures that writes will only be as big
+ as the buffers). */
+#define SEND_NEVER_PARTIAL 1
+
+/* Stop server macro */
+#define SHUTDOWN_SERVER wnt_shutdown_server
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not available through errno.
+ Instead, this macro should be used to obtain an error code. */
+#define SOCK_ERRNO (WSAGetLastError ())
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not known to strerror. Instead,
+ this macro should be used to convert the error codes to strings. */
+#define SOCK_STRERROR sock_strerror
+
+/* Start server macro */
+#define START_SERVER wnt_start_server
+
+/* The internal rsh client uses sockets not file descriptors. Note
+ that as the code stands now, it often takes values from a SOCKET and
+ puts them in an int. This is ugly but it seems like sizeof
+ (SOCKET) <= sizeof (int) on win32, even the 64-bit variants. */
+#define START_SERVER_RETURNS_SOCKET 1
+
+/* Macro name tells the story */
+#define SYSTEM_CLEANUP woe32_cleanup
+
+/* Macro name tells the story */
+#define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock()
+
+/*
+ * According to GNU conventions, we should avoid referencing any macro
+ * containing "WIN" as a reference to Microsoft Windows, as we would like to
+ * avoid any implication that we consider Microsoft Windows any sort of "win".
+ *
+ * FIXME: As of 2003-06-09, folks on the GNULIB project were discussing
+ * defining a configure macro to define WOE32 appropriately. If they ever do
+ * write such a beast, we should use it, though in most cases it would be
+ * preferable to avoid referencing any OS or compiler anyhow, per Autoconf
+ * convention, and reference only tested features of the system.
+ *
+ * re FIXME: This definition would still be necessary since systems which run
+ * configure do not use this config.h and vice-versa.
+ */
+#define WOE32 1
+
+/* Define POSIX name to Microsoft name */
+#define dup _dup
+
+/* getpagesize is missing on Windows, 4096 does the right thing. */
+#define getpagesize() 4096
+
+/* Define to a substitute for the `lstat' function. */
+#define lstat stat
+
+/* Define POSIX name to Microsoft name */
+#define popen _popen
+
+/* Define POSIX name to Microsoft name */
+#define pclose _pclose
+
+/* Diff needs us to define this. I think it could always be
+ -1 for CVS, because we pass temporary files to diff, but
+ config.h seems like the easiest place to put this, so for
+ now we put it here. */
+#define same_file(s,t) (-1)
+
+/* Define to a substitute for the stat function. */
+#define stat wnt_stat
+
+/* ====================== Typedef Declarations Follow ===================== */
+
+/* ====================== Function Prototypes Follow ====================== */
+
+#include <woe32.h>
+
+/* #define SOCK_STRERROR sock_strerror */
+char *sock_strerror (int errnum);
+
+/* #define CVS_MKDIR wnt_mkdir */
+int wnt_mkdir (const char *PATH, int MODE);
+
+/* #define CVS_RENAME wnt_rename */
+int wnt_rename (const char *, const char *);
+
+/* #define SHUTDOWN_SERVER wnt_shutdown_server */
+void wnt_shutdown_server (int fd);
+
+/* #define START_SERVER wnt_start_server */
+void wnt_start_server (int *tofd, int *fromfd,
+ char *client_user,
+ char *server_user,
+ char *server_host,
+ char *server_cvsroot);
+
+/* #define stat wnt_stat and #define lstat wnt_stat */
+int wnt_stat (const char *file, struct wnt_stat *sb);
+
+/* =============== Special mkdir Prototype Handling Follows =============== */
+
+#include <direct.h>
+#define mkdir wnt_mkdir
+
+/* ===================== Special Function Definitions ===================== */
+
+/*
+ Microsoft defines "mbinit" in <wchar.h> for C++ code only.
+
+ Expect link errors for versions:
+
+ earlier than Visual C++ 5.0
+
+ later than Visual C++ .NET 2003
+
+ and Visual C++ .NET is just a guess which might be wrong.
+*/
+
+#if _MSC_VER >= 1100 && _MSC_VER <= 1200
+
+/* If within Visual C++ 5.0 to Visual C++ 6.0 */
+
+inline int mbsinit (const void * arg)
+ { return 1; }
+
+#elif _MSC_VER >= 1300 && _MSC_VER <= 1310
+
+/* If within Visual C++ .NET to Visual C++ .NET 2003 */
+
+inline int mbsinit (const int * arg)
+ { return arg == NULL || ! *arg; }
+
+#endif
+
+/* =========================== End Of This File =========================== */
diff --git a/windows-NT/config.h.in b/windows-NT/config.h.in
new file mode 100644
index 0000000..c5bc371
--- /dev/null
+++ b/windows-NT/config.h.in
@@ -0,0 +1,1445 @@
+/***
+ *** config.h.in, generated by mkconfig.pl:
+ ***
+ *** (config.h.in.in
+ *** + ../config.h.in)
+ *** . config.h.in.footer
+ *** --> config.h.in
+ ***
+ *** ***** DO NOT ALTER THIS FILE!!! *****
+ ***
+ *** Changes to this file will be overwritten by automatic script runs.
+ *** Changes should be made to the config.h.in.in & config.h.in.footer
+ *** files instead.
+ ***/
+
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define this to a NULL terminated list of allowed path prefixes (for
+ directories) and paths to files the CVS server will allow configuration to
+ be read from when specified from the command line. */
+#undef ALLOW_CONFIG_OVERRIDE
+
+/* Enable AUTH_CLIENT_SUPPORT to enable pserver as a remote access method in
+ the CVS client (default) */
+#define AUTH_CLIENT_SUPPORT 1
+
+/* Define if you want to use the password authenticated server. */
+#undef AUTH_SERVER_SUPPORT
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#define CLIENT_SUPPORT
+
+/* Define to 1 if the `closedir' function returns void instead of `int'. */
+#undef CLOSEDIR_VOID
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* define if cross compiling */
+#undef CROSS_COMPILING
+
+/* The CVS admin command is restricted to the members of the group
+ CVS_ADMIN_GROUP. If this group does not exist, all users are allowed to run
+ CVS admin. To disable the CVS admin command for all users, create an empty
+ CVS_ADMIN_GROUP by running configure with the --with-cvs-admin-group=
+ option. To disable access control for CVS admin, run configure with the
+ --without-cvs-admin-group option in order to comment out the define below.
+ */
+#undef CVS_ADMIN_GROUP
+
+/* When committing a permanent change, CVS and RCS make a log entry of who
+ committed the change. If you are committing the change logged in as "root"
+ (not under "su" or other root-priv giving program), CVS/RCS cannot
+ determine who is actually making the change. As such, by default, CVS
+ prohibits changes committed by users logged in as "root". You can disable
+ checking by passing the "--enable-rootcommit" option to configure or by
+ commenting out the lines below. */
+#undef CVS_BADROOT
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define if there is a member named d_ino in the struct describing directory
+ headers. */
+#undef D_INO_IN_DIRENT
+
+/* The default editor to use, if one does not specify the "-e" option to cvs,
+ or does not have an EDITOR environment variable. If this is not set to an
+ absolute path to an executable, use the shell to find where the editor
+ actually is. This allows sites with /usr/bin/vi or /usr/ucb/vi to work
+ equally well (assuming that their PATH is reasonable). */
+#define EDITOR_DFLT "notepad"
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#undef ENABLE_NLS
+
+/* Define to enable encryption support. */
+#undef ENCRYPTION
+
+/* Define as good substitute value for EOVERFLOW. */
+#define EOVERFLOW EINVAL
+
+/* Define if this executable will be running on case insensitive file systems.
+ In the client case, this means that it will request that the server pretend
+ to be case insensitive if it isn't already. */
+#define FILENAMES_CASE_INSENSITIVE 1
+
+/* Define on systems for which file names may have a so-called `drive letter'
+ prefix, define this to compute the length of that prefix, including the
+ colon. */
+#define FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX 1
+
+/* Define if the backslash character may also serve as a file name component
+ separator. */
+#define FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR 1
+
+#if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+# define FILE_SYSTEM_PREFIX_LEN(Filename) \
+ ((Filename)[0] && (Filename)[1] == ':' ? 2 : 0)
+#else
+# define FILE_SYSTEM_PREFIX_LEN(Filename) 0
+#endif
+
+/* When committing or importing files, you must enter a log message. Normally,
+ you can do this either via the -m flag on the command line, the -F flag on
+ the command line, or an editor will be started for you. If you like to use
+ logging templates (the rcsinfo file within the $CVSROOT/CVSROOT directory),
+ you might want to force people to use the editor even if they specify a
+ message with -m or -F. Enabling FORCE_USE_EDITOR will cause the -m or -F
+ message to be appended to the temp file when the editor is started. */
+#undef FORCE_USE_EDITOR
+
+/* Define to an alternative value if GSS_C_NT_HOSTBASED_SERVICE isn't defined
+ in the gssapi.h header file. MIT Kerberos 1.2.1 requires this. Only
+ relevant when using GSSAPI. */
+#undef GSS_C_NT_HOSTBASED_SERVICE
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have `alloca' after including <alloca.h>, a header that
+ may be supplied by this distribution. */
+#undef HAVE_ALLOCA
+
+/* Define HAVE_ALLOCA_H for backward compatibility with older code that
+ includes <alloca.h> only if HAVE_ALLOCA_H is defined. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the `atexit' function. */
+#define HAVE_ATEXIT 1
+
+/* Define to 1 if you have the <bp-sym.h> header file. */
+#undef HAVE_BP_SYM_H
+
+/* Define to 1 if you have the `btowc' function. */
+#undef HAVE_BTOWC
+
+/* Define to 1 if you have the `canonicalize_file_name' function. */
+#undef HAVE_CANONICALIZE_FILE_NAME
+
+/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+#undef HAVE_CFLOCALECOPYCURRENT
+
+/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+#undef HAVE_CFPREFERENCESCOPYAPPVALUE
+
+/* Define to 1 if you have the `chsize' function. */
+#define HAVE_CHSIZE 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `clock_settime' function. */
+#undef HAVE_CLOCK_SETTIME
+
+/* Define if you have the connect function. */
+#define HAVE_CONNECT
+
+/* Define if you have the crypt function. */
+#undef HAVE_CRYPT
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+#undef HAVE_DCGETTEXT
+
+/* Define to 1 if you have the declaration of `clearerr_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_CLEARERR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FEOF_UNLOCKED
+
+/* Define to 1 if you have the declaration of `ferror_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FERROR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fflush_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FFLUSH_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FGETS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `flockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FLOCKFILE
+
+/* Define to 1 if you have the declaration of `fputc_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fputs_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fread_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FREAD_UNLOCKED
+
+/* Define to 1 if you have the declaration of `funlockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FUNLOCKFILE
+
+/* Define to 1 if you have the declaration of `fwrite_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FWRITE_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getcwd', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETCWD 1
+
+/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getdelim', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETDELIM
+
+/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETENV 1
+
+/* Define to 1 if you have the declaration of `getline', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLINE
+
+/* Define to 1 if you have the declaration of `getlogin', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN
+
+/* Define to 1 if you have the declaration of `getlogin_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN_R
+
+/* Define to 1 if you have the declaration of `getpass', and to 0 if you
+ don't. */
+#define HAVE_DECL_GETPASS 1
+
+/* Define to 1 if you have the declaration of `memrchr', and to 0 if you
+ don't. */
+#undef HAVE_DECL_MEMRCHR
+
+/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
+ don't. */
+#define HAVE_DECL_NANOSLEEP 1
+
+/* Define to 1 if you have the declaration of `putchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_PUTCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `putc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_PUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `strdup', and to 0 if you don't.
+ */
+#define HAVE_DECL_STRDUP 1
+
+/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_STRERROR_R
+
+/* Define to 1 if you have the declaration of `__fpending', and to 0 if you
+ don't. */
+#define HAVE_DECL___FPENDING 0
+
+/* Define to 1 if you have the <direct.h> header file. */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dup2' function. */
+#define HAVE_DUP2 1
+
+/* Define if you have the declaration of environ. */
+#define HAVE_ENVIRON_DECL 1
+
+/* Define if you have the declaration of errno. */
+#define HAVE_ERRNO_DECL 1
+
+/* Define to 1 if you have the `fchdir' function. */
+#undef HAVE_FCHDIR
+
+/* Define to 1 if you have the `fchmod' function. */
+#undef HAVE_FCHMOD
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `flockfile' function. */
+#undef HAVE_FLOCKFILE
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `fsync' function. */
+#undef HAVE_FSYNC
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have the `funlockfile' function. */
+#undef HAVE_FUNLOCKFILE
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `getgroups' function. */
+#undef HAVE_GETGROUPS
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `getlogin_r' function. */
+#undef HAVE_GETLOGIN_R
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long_only' function. */
+#undef HAVE_GETOPT_LONG_ONLY
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define if you have the getspnam function. */
+#undef HAVE_GETSPNAM
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#undef HAVE_GETTEXT
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H 1
+
+/* Define if you have GSSAPI with Kerberos version 5 available. */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
+/* Define if you have the iconv() function. */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_INTMAX_T
+
+/* Define if <inttypes.h> exists and doesn't clash with <sys/types.h>. */
+#undef HAVE_INTTYPES_H
+
+/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
+ declares uintmax_t. */
+#undef HAVE_INTTYPES_H_WITH_UINTMAX
+
+/* Define to 1 if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET. */
+#define HAVE_IPV4 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET6. */
+#undef HAVE_IPV6
+
+/* Define to 1 if you have the `isascii' function. */
+#define HAVE_ISASCII 1
+
+/* Define to 1 if you have the `isblank' function. */
+#undef HAVE_ISBLANK
+
+/* Define to 1 if you have the `iswprint' function. */
+#define HAVE_ISWPRINT 1
+
+/* Define if you have MIT Kerberos version 4 available. */
+#undef HAVE_KERBEROS
+
+/* Define to 1 if you have the <krb5.h> header file. */
+#undef HAVE_KRB5_H
+
+/* Define to 1 if you have the `krb_get_err_text' function. */
+#undef HAVE_KRB_GET_ERR_TEXT
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#undef HAVE_LANGINFO_CODESET
+
+/* Define to 1 if you have the `krb' library (-lkrb). */
+#undef HAVE_LIBKRB
+
+/* Define to 1 if you have the `krb4' library (-lkrb4). */
+#undef HAVE_LIBKRB4
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `login' function. */
+#undef HAVE_LOGIN
+
+/* Define to 1 if you have the `logout' function. */
+#undef HAVE_LOGOUT
+
+/* Define if you have the 'long double' type. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have the 'long long' type. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including
+ config.h and <sys/mman.h>. */
+#undef HAVE_MAP_ANONYMOUS
+
+/* Define to 1 if you have the `mblen' function. */
+#define HAVE_MBLEN 1
+
+/* Define to 1 if you have the `mbrlen' function. */
+#define HAVE_MBRLEN 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if you have the `mbsinit' function. */
+#undef HAVE_MBSINIT
+
+/* Define to 1 if you have the `mbsrtowcs' function. */
+#define HAVE_MBSRTOWCS 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define if you have memchr (always for CVS). */
+#define HAVE_MEMCHR 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mempcpy' function. */
+#undef HAVE_MEMPCPY
+
+/* Define to 1 if you have the `memrchr' function. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if <limits.h> defines the MIN and MAX macros. */
+#define HAVE_MINMAX_IN_LIMITS_H 1
+
+/* Define to 1 if <sys/param.h> defines the MIN and MAX macros. */
+#undef HAVE_MINMAX_IN_SYS_PARAM_H
+
+/* Define to 1 if you have the `mknod' function. */
+#undef HAVE_MKNOD
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `nanotime' function. */
+#undef HAVE_NANOTIME
+
+/* Define to 1 if you have the <ndbm.h> header file. */
+#undef HAVE_NDBM_H
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#define HAVE_NDIR_H 1
+
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
+/* Define to 1 if you have the <OS.h> header file. */
+#undef HAVE_OS_H
+
+/* Define to enable system authentication with PAM instead of using the simple
+ getpwnam interface. This allows authentication (in theory) with any PAM
+ module, e.g. on systems with shadow passwords or via LDAP */
+#undef HAVE_PAM
+
+/* Define to 1 if pam/pam_appl.h is available */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
+ setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX is not
+ defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD is defined.
+ */
+#undef HAVE_PARTLY_WORKING_GETCWD
+
+/* Define to 1 if you have the `posix_memalign' function. */
+#undef HAVE_POSIX_MEMALIGN
+
+/* Define to 1 if the `printf' function supports the %p format for printing
+ pointers. */
+#define HAVE_PRINTF_PTR 1
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#define HAVE_PTRDIFF_T 1
+
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#define HAVE_REALLOC 1
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the `regerror' function. */
+#undef HAVE_REGERROR
+
+/* Define to 1 if you have the `regexec' function. */
+#undef HAVE_REGEXEC
+
+/* Define to 1 if you have the `regfree' function. */
+#undef HAVE_REGFREE
+
+/* Define to 1 if you have the `resolvepath' function. */
+#undef HAVE_RESOLVEPATH
+
+/* Define to 1 if you have the `rpmatch' function. */
+#undef HAVE_RPMATCH
+
+/* Define to 1 if you have run the test for working tzset. */
+#define HAVE_RUN_TZSET_TEST 1
+
+/* Define to 1 if you have the <search.h> header file. */
+#define HAVE_SEARCH_H 1
+
+/* Define to 1 if security/pam_appl.h is available */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define if the diff library should use setmode for binary files. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigblock' function. */
+#undef HAVE_SIGBLOCK
+
+/* Define to 1 if you have the `siginterrupt' function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define to 1 if you have the `sigsetmask' function. */
+#undef HAVE_SIGSETMASK
+
+/* Define to 1 if you have the `sigvec' function. */
+#undef HAVE_SIGVEC
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
+ uintmax_t. */
+#define HAVE_STDINT_H_WITH_UINTMAX 1
+
+/* Define to 1 if you have the <stdio_ext.h> header file. */
+#undef HAVE_STDIO_EXT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have strchr (always for CVS). */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define if there is a member named d_type in the struct describing directory
+ headers. */
+#undef HAVE_STRUCT_DIRENT_D_TYPE
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define if struct timespec is declared in <time.h>. */
+#undef HAVE_STRUCT_TIMESPEC
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_ZONE
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/inttypes.h> header file. */
+#undef HAVE_SYS_INTTYPES_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `tcgetattr' function. */
+#undef HAVE_TCGETATTR
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the `timezone' function. */
+#undef HAVE_TIMEZONE
+
+/* Define to 1 if localtime_r, etc. have the type signatures that POSIX
+ requires. */
+#undef HAVE_TIME_R_POSIX
+
+/* Define if struct tm has the tm_gmtoff member. */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#undef HAVE_TM_ZONE
+
+/* Define to 1 if you have the `tsearch' function. */
+#undef HAVE_TSEARCH
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the `tzset' function. */
+#define HAVE_TZSET 1
+
+/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_UINTMAX_T
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define if you have the 'unsigned long long' type. */
+#undef HAVE_UNSIGNED_LONG_LONG
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
+#define HAVE_UTIME_NULL 1
+
+/* Define to 1 if you have the `vasnprintf' function. */
+#undef HAVE_VASNPRINTF
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `wait3' function. */
+#undef HAVE_WAIT3
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define if you have the 'wchar_t' type. */
+#define HAVE_WCHAR_T 1
+
+/* Define to 1 if you have the `wcrtomb' function. */
+#define HAVE_WCRTOMB 1
+
+/* Define to 1 if you have the `wcscoll' function. */
+#define HAVE_WCSCOLL 1
+
+/* Define to 1 if you have the `wcslen' function. */
+#define HAVE_WCSLEN 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define if you have the 'wint_t' type. */
+#define HAVE_WINT_T 1
+
+/* Define to 1 if you have the `wmemchr' function. */
+#define HAVE_WMEMCHR 1
+
+/* Define to 1 if you have the `wmemcpy' function. */
+#define HAVE_WMEMCPY 1
+
+/* Define to 1 if you have the `wmempcpy' function. */
+#undef HAVE_WMEMPCPY
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to 1 if you have the `__fpending' function. */
+#undef HAVE___FPENDING
+
+/* Define to 1 if you have the `__fsetlocking' function. */
+#undef HAVE___FSETLOCKING
+
+/* Define to 1 if you have the `__secure_getenv' function. */
+#undef HAVE___SECURE_GETENV
+
+#if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+#else
+# define ISSLASH(C) ((C) == '/')
+#endif
+
+/* Define to include locking code which prevents versions of CVS earlier than
+ 1.12.4 directly accessing the same repositiory as this executable from
+ ignoring this executable's promotable read locks. If only CVS versions
+ 1.12.4 and later will be accessing your repository directly (as a server or
+ locally), you can safely disable this option in return for fewer disk
+ accesses and a small speed increase. Disabling this option when versions of
+ CVS earlier than 1,12,4 _will_ be accessing your repository, however, is
+ *VERY* *VERY* *VERY* dangerous and could result in data loss. As such, by
+ default, CVS is compiled with this code enabled. If you are sure you would
+ like this code disabled, you can disable it by passing the
+ "--disable-lock-compatibility" option to configure or by commenting out the
+ lines below. */
+#define LOCK_COMPATIBILITY
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
+
+/* If malloc(0) is != NULL, define this to 1. Otherwise define this to 0. */
+#undef MALLOC_0_IS_NONNULL
+
+/* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */
+#undef MAP_ANONYMOUS
+
+/* By default, CVS stores its modules and other such items in flat text files
+ (MY_NDBM enables this). Turning off MY_NDBM causes CVS to look for a
+ system-supplied ndbm database library and use it instead. That may speed
+ things up, but the default setting generally works fine too. */
+#define MY_NDBM
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "%PACKAGE_BUGREPORT%"
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "%PACKAGE_STRING%"
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to set a service name for PAM. This must be defined. Define to
+ `program_name', without the quotes, to use whatever name CVS was invoked
+ as. Otherwise, define to a double-quoted literal string, such as `"cvs"'.
+ */
+#undef PAM_SERVICE_NAME
+
+/* the number of pending output bytes on stream `fp' */
+#define PENDING_OUTPUT_N_BYTES ( fp ? fp->_ptr - fp->_base : 0 )
+
+/* Define if you want CVS to be able to serve as a transparent proxy for write
+ operations. Disabling this may produce a slight performance gain on some
+ systems, at the expense of write proxy support. */
+#undef PROXY_SUPPORT
+
+/* Path to the pr utility */
+#undef PR_PROGRAM
+
+/* Define to force lib/regex.c to use malloc instead of alloca. */
+#define REGEX_MALLOC 1
+
+/* Define if rename does not work for source file names with a trailing slash,
+ like the one from SunOS 4.1.1_U1. */
+#undef RENAME_TRAILING_SLASH_BUG
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* If you are working with a large remote repository and a 'cvs checkout' is
+ swamping your network and memory, define these to enable flow control. You
+ will end up with even less probability of a consistent checkout (see
+ Concurrency in cvs.texinfo), but CVS doesn't try to guarantee that anyway.
+ The master server process will monitor how far it is getting behind, if it
+ reaches the high water mark, it will signal the child process to stop
+ generating data when convenient (ie: no locks are held, currently at the
+ beginning of a new directory). Once the buffer has drained sufficiently to
+ reach the low water mark, it will be signalled to start again. */
+#undef SERVER_FLOWCONTROL
+
+/* The high water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_HI_WATER
+
+/* The low water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_LO_WATER
+
+/* Define if you want CVS to be able to serve repositories to remote clients.
+ */
+#undef SERVER_SUPPORT
+
+/* The size of a `char', as computed by sizeof. */
+#define SIZEOF_CHAR 1
+
+/* The size of a `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of a `float', as computed by sizeof. */
+#define SIZEOF_FLOAT 4
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `intmax_t', as computed by sizeof. */
+#undef SIZEOF_INTMAX_T
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of a `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 8
+
+/* The size of a `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of a `ptrdiff_t', as computed by sizeof. */
+#define SIZEOF_PTRDIFF_T 4
+
+/* The size of a `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of a `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of a `wint_t', as computed by sizeof. */
+#define SIZEOF_WINT_T 2
+
+/* Define as the maximum value of type 'size_t', if the system doesn't define
+ it. */
+#define SIZE_MAX (~(size_t)0)
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#define STAT_MACROS_BROKEN 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r returns char *. */
+#undef STRERROR_R_CHAR_P
+
+/* Enable support for the pre 1.12.1 *info scripting hook format strings.
+ Disable this option for a smaller executable once your scripting hooks have
+ been updated to use the new *info format strings by passing
+ "--disable-old-info-format-support" option to configure or by commenting
+ out the line below. */
+#undef SUPPORT_OLD_INFO_FMT_STRINGS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little need
+ to change this (-T is a better mechanism if you need to use a different
+ directory for temporary files). */
+#define TMPDIR_DFLT "c:\\temp"
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define if tzset clobbers localtime's static buffer. */
+#undef TZSET_CLOBBERS_LOCALTIME_BUFFER
+
+/* Define to its maximum value if an unsigned integer type of width exactly 32
+ bits exists and the standard includes do not define UINT32_MAX. */
+#undef UINT32_MAX
+
+/* The default umask to use when creating or otherwise setting file or
+ directory permissions in the repository. Must be a value in the range of 0
+ through 0777. For example, a value of 002 allows group rwx access and world
+ rx access; a value of 007 allows group rwx access but no world access. This
+ value is overridden by the value of the CVSUMASK environment variable,
+ which is interpreted as an octal number. */
+#define UMASK_DFLT 002
+
+/* Define if double is the first floating point type detected with its size.
+ */
+#undef UNIQUE_FLOAT_TYPE_DOUBLE
+
+/* Define if float is the first floating point type detected with its size. */
+#undef UNIQUE_FLOAT_TYPE_FLOAT
+
+/* Define if long double is the first floating point type detected with its
+ size. */
+#undef UNIQUE_FLOAT_TYPE_LONG_DOUBLE
+
+/* Define if char is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_CHAR
+
+/* Define if int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INT
+
+/* Define if intmax_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INTMAX_T
+
+/* Define if long int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG
+
+/* Define if long long is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG_LONG
+
+/* Define if ptrdiff_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_PTRDIFF_T
+
+/* Define if short is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SHORT
+
+/* Define if size_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SIZE_T
+
+/* Define if wint_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_WINT_T
+
+/* Define if setmode is required when writing binary data to stdout. */
+#define USE_SETMODE_STDOUT 1
+
+/* Define to 1 if you want getc etc. to use unlocked I/O if available.
+ Unlocked I/O can improve performance in unithreaded apps, but it is not
+ safe for multithreaded apps. */
+#undef USE_UNLOCKED_IO
+
+/* Define if utime requires write access to the file (true on Windows, but not
+ Unix). */
+#define UTIME_EXPECTS_WRITABLE
+
+/* Define if unsetenv() returns void, not int. */
+#undef VOID_UNSETENV
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define if you want regoff_t to be at least as wide POSIX requires. */
+#undef _REGEX_LARGE_OFFSETS
+
+/* Define to force lib/regex.c to define re_comp et al. */
+#define _REGEX_RE_COMP 1
+
+/* Define for Solaris 2.5.1 so uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+
+/* Define to rpl_ if the getcwd replacement function should be used. */
+#undef __GETCWD_PREFIX
+
+/* Define to rpl_ if the getopt replacement functions and variables should be
+ used. */
+#define __GETOPT_PREFIX rpl_
+
+/* Define to rpl_ if the openat replacement function should be used. */
+#undef __OPENAT_PREFIX
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to a replacement function name for fnmatch(). */
+#undef fnmatch
+
+/* Define to a replacement function name for getline(). */
+#undef getline
+
+/* Define to a replacement function name for getpass(). */
+#undef getpass
+
+/* Define to rpl_gettimeofday if the replacement function should be used. */
+#undef gettimeofday
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to rpl_gmtime if the replacement function should be used. */
+#undef gmtime
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+
+/* Define to long or long long if <inttypes.h> and <stdint.h> don't define. */
+#undef intmax_t
+
+/* Define to rpl_localtime if the replacement function should be used. */
+#undef localtime
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to a type if <wchar.h> does not define. */
+#undef mbstate_t
+
+/* Define to rpl_mkdir if the replacement function should be used. */
+#undef mkdir
+
+/* Define to rpl_mkstemp if the replacement function should be used. */
+#undef mkstemp
+
+/* Define to rpl_mktime if the replacement function should be used. */
+#undef mktime
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define mode_t int
+
+/* Define to the name of the strftime replacement function. */
+#define my_strftime nstrftime
+
+/* Define to rpl_nanosleep if the replacement function should be used. */
+#define nanosleep woe32_nanosleep
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to rpl_realloc if the replacement function should be used. */
+#define realloc rpl_realloc
+
+/* Define to rpl_rename if the replacement function should be used. */
+#undef rename
+
+/* Define to equivalent of C99 restrict keyword, or to nothing if this is not
+ supported. Do not define if restrict is supported directly. */
+#define restrict
+
+/* Define to rpl_select if the replacement function should be used. */
+#undef select
+
+/* Define to empty if the C compiler doesn't support this keyword. */
+#undef signed
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define as a signed type of the same size as size_t. */
+#define ssize_t int
+
+/* Define to rpl_strcasecmp always. */
+#define strcasecmp rpl_strcasecmp
+
+/* Define to rpl_tzset if the wrapper function should be used. */
+#undef tzset
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to the type of a unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to unsigned long or unsigned long long if <stdint.h> and
+ <inttypes.h> don't define. */
+#undef uintmax_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
+/*============================================================================*/
+/* config.h.in.footer: configuration file for Windows NT
+ Conrad T. Pino <Conrad@Pino.com> --- May 2004 */
+
+/* This file lives in the windows-NT subdirectory, which is only included
+ in your header search path if you're working under Microsoft Visual C++,
+ and use ../cvsnt.mak for your project. Thus, this is the right place to
+ put configuration information for Windows NT. */
+
+/* This file is getting chaotic and will be organized as follows:
+
+ Macros appears first alphabetized in case sensitive order.
+ Typedefs appear next alphabetized in case sensitive order.
+ Function prototypes alphabetized in case sensitive order.
+
+ Reorgnized by Conrad T. Pino <Conrad@Pino.com> May 25, 2005 */
+
+/* just one time please */
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+/* ======================= Macro Definnitions Follow ====================== */
+
+/* Under Windows NT, mkdir only takes one argument. */
+#define CVS_MKDIR wnt_mkdir
+
+#define CVS_RENAME wnt_rename
+
+/* This is where old bits go to die under Windows NT. */
+#define DEVNULL "nul"
+
+/* Windows has no ELOOP value in errno.h */
+#define ELOOP EMLINK
+
+/* Windows has _snprintf function.
+ HAVE_DECL__SNPRINTF used in ../lib/vasnprintf.c */
+#define HAVE_DECL__SNPRINTF 1
+
+#define HAVE_WINSOCK_H
+
+/* This tells the client that it must use send()/recv() to talk to the
+ server if it is connected to the server via a socket; Win95 needs
+ it because _open_osfhandle doesn't work. */
+#define NO_SOCKET_TO_FD 1
+
+/* Is this true on NT? Seems like I remember reports that NT 3.51 has
+ problems with 200K writes (of course, the issue of large writes is
+ moot since the use of buffer.c ensures that writes will only be as big
+ as the buffers). */
+#define SEND_NEVER_PARTIAL 1
+
+/* Stop server macro */
+#define SHUTDOWN_SERVER wnt_shutdown_server
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not available through errno.
+ Instead, this macro should be used to obtain an error code. */
+#define SOCK_ERRNO (WSAGetLastError ())
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not known to strerror. Instead,
+ this macro should be used to convert the error codes to strings. */
+#define SOCK_STRERROR sock_strerror
+
+/* Start server macro */
+#define START_SERVER wnt_start_server
+
+/* The internal rsh client uses sockets not file descriptors. Note
+ that as the code stands now, it often takes values from a SOCKET and
+ puts them in an int. This is ugly but it seems like sizeof
+ (SOCKET) <= sizeof (int) on win32, even the 64-bit variants. */
+#define START_SERVER_RETURNS_SOCKET 1
+
+/* Macro name tells the story */
+#define SYSTEM_CLEANUP woe32_cleanup
+
+/* Macro name tells the story */
+#define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock()
+
+/*
+ * According to GNU conventions, we should avoid referencing any macro
+ * containing "WIN" as a reference to Microsoft Windows, as we would like to
+ * avoid any implication that we consider Microsoft Windows any sort of "win".
+ *
+ * FIXME: As of 2003-06-09, folks on the GNULIB project were discussing
+ * defining a configure macro to define WOE32 appropriately. If they ever do
+ * write such a beast, we should use it, though in most cases it would be
+ * preferable to avoid referencing any OS or compiler anyhow, per Autoconf
+ * convention, and reference only tested features of the system.
+ *
+ * re FIXME: This definition would still be necessary since systems which run
+ * configure do not use this config.h and vice-versa.
+ */
+#define WOE32 1
+
+/* Define POSIX name to Microsoft name */
+#define dup _dup
+
+/* getpagesize is missing on Windows, 4096 does the right thing. */
+#define getpagesize() 4096
+
+/* Define to a substitute for the `lstat' function. */
+#define lstat stat
+
+/* Define POSIX name to Microsoft name */
+#define popen _popen
+
+/* Define POSIX name to Microsoft name */
+#define pclose _pclose
+
+/* Diff needs us to define this. I think it could always be
+ -1 for CVS, because we pass temporary files to diff, but
+ config.h seems like the easiest place to put this, so for
+ now we put it here. */
+#define same_file(s,t) (-1)
+
+/* Define to a substitute for the stat function. */
+#define stat wnt_stat
+
+/* ====================== Typedef Declarations Follow ===================== */
+
+/* ====================== Function Prototypes Follow ====================== */
+
+#include <woe32.h>
+
+/* #define SOCK_STRERROR sock_strerror */
+char *sock_strerror (int errnum);
+
+/* #define CVS_MKDIR wnt_mkdir */
+int wnt_mkdir (const char *PATH, int MODE);
+
+/* #define CVS_RENAME wnt_rename */
+int wnt_rename (const char *, const char *);
+
+/* #define SHUTDOWN_SERVER wnt_shutdown_server */
+void wnt_shutdown_server (int fd);
+
+/* #define START_SERVER wnt_start_server */
+void wnt_start_server (int *tofd, int *fromfd,
+ char *client_user,
+ char *server_user,
+ char *server_host,
+ char *server_cvsroot);
+
+/* #define stat wnt_stat and #define lstat wnt_stat */
+int wnt_stat (const char *file, struct wnt_stat *sb);
+
+/* =============== Special mkdir Prototype Handling Follows =============== */
+
+#include <direct.h>
+#define mkdir wnt_mkdir
+
+/* ===================== Special Function Definitions ===================== */
+
+/*
+ Microsoft defines "mbinit" in <wchar.h> for C++ code only.
+
+ Expect link errors for versions:
+
+ earlier than Visual C++ 5.0
+
+ later than Visual C++ .NET 2003
+
+ and Visual C++ .NET is just a guess which might be wrong.
+*/
+
+#if _MSC_VER >= 1100 && _MSC_VER <= 1200
+
+/* If within Visual C++ 5.0 to Visual C++ 6.0 */
+
+inline int mbsinit (const void * arg)
+ { return 1; }
+
+#elif _MSC_VER >= 1300 && _MSC_VER <= 1310
+
+/* If within Visual C++ .NET to Visual C++ .NET 2003 */
+
+inline int mbsinit (const int * arg)
+ { return arg == NULL || ! *arg; }
+
+#endif
+
+/* =========================== End Of This File =========================== */
diff --git a/windows-NT/config.h.in.footer b/windows-NT/config.h.in.footer
new file mode 100644
index 0000000..8c10d4d
--- /dev/null
+++ b/windows-NT/config.h.in.footer
@@ -0,0 +1,186 @@
+/*============================================================================*/
+/* config.h.in.footer: configuration file for Windows NT
+ Conrad T. Pino <Conrad@Pino.com> --- May 2004 */
+
+/* This file lives in the windows-NT subdirectory, which is only included
+ in your header search path if you're working under Microsoft Visual C++,
+ and use ../cvsnt.mak for your project. Thus, this is the right place to
+ put configuration information for Windows NT. */
+
+/* This file is getting chaotic and will be organized as follows:
+
+ Macros appears first alphabetized in case sensitive order.
+ Typedefs appear next alphabetized in case sensitive order.
+ Function prototypes alphabetized in case sensitive order.
+
+ Reorgnized by Conrad T. Pino <Conrad@Pino.com> May 25, 2005 */
+
+/* just one time please */
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+/* ======================= Macro Definnitions Follow ====================== */
+
+/* Under Windows NT, mkdir only takes one argument. */
+#define CVS_MKDIR wnt_mkdir
+
+#define CVS_RENAME wnt_rename
+
+/* This is where old bits go to die under Windows NT. */
+#define DEVNULL "nul"
+
+/* Windows has no ELOOP value in errno.h */
+#define ELOOP EMLINK
+
+/* Windows has _snprintf function.
+ HAVE_DECL__SNPRINTF used in ../lib/vasnprintf.c */
+#define HAVE_DECL__SNPRINTF 1
+
+#define HAVE_WINSOCK_H
+
+/* This tells the client that it must use send()/recv() to talk to the
+ server if it is connected to the server via a socket; Win95 needs
+ it because _open_osfhandle doesn't work. */
+#define NO_SOCKET_TO_FD 1
+
+/* Is this true on NT? Seems like I remember reports that NT 3.51 has
+ problems with 200K writes (of course, the issue of large writes is
+ moot since the use of buffer.c ensures that writes will only be as big
+ as the buffers). */
+#define SEND_NEVER_PARTIAL 1
+
+/* Stop server macro */
+#define SHUTDOWN_SERVER wnt_shutdown_server
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not available through errno.
+ Instead, this macro should be used to obtain an error code. */
+#define SOCK_ERRNO (WSAGetLastError ())
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not known to strerror. Instead,
+ this macro should be used to convert the error codes to strings. */
+#define SOCK_STRERROR sock_strerror
+
+/* Start server macro */
+#define START_SERVER wnt_start_server
+
+/* The internal rsh client uses sockets not file descriptors. Note
+ that as the code stands now, it often takes values from a SOCKET and
+ puts them in an int. This is ugly but it seems like sizeof
+ (SOCKET) <= sizeof (int) on win32, even the 64-bit variants. */
+#define START_SERVER_RETURNS_SOCKET 1
+
+/* Macro name tells the story */
+#define SYSTEM_CLEANUP woe32_cleanup
+
+/* Macro name tells the story */
+#define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock()
+
+/*
+ * According to GNU conventions, we should avoid referencing any macro
+ * containing "WIN" as a reference to Microsoft Windows, as we would like to
+ * avoid any implication that we consider Microsoft Windows any sort of "win".
+ *
+ * FIXME: As of 2003-06-09, folks on the GNULIB project were discussing
+ * defining a configure macro to define WOE32 appropriately. If they ever do
+ * write such a beast, we should use it, though in most cases it would be
+ * preferable to avoid referencing any OS or compiler anyhow, per Autoconf
+ * convention, and reference only tested features of the system.
+ *
+ * re FIXME: This definition would still be necessary since systems which run
+ * configure do not use this config.h and vice-versa.
+ */
+#define WOE32 1
+
+/* Define POSIX name to Microsoft name */
+#define dup _dup
+
+/* getpagesize is missing on Windows, 4096 does the right thing. */
+#define getpagesize() 4096
+
+/* Define to a substitute for the `lstat' function. */
+#define lstat stat
+
+/* Define POSIX name to Microsoft name */
+#define popen _popen
+
+/* Define POSIX name to Microsoft name */
+#define pclose _pclose
+
+/* Diff needs us to define this. I think it could always be
+ -1 for CVS, because we pass temporary files to diff, but
+ config.h seems like the easiest place to put this, so for
+ now we put it here. */
+#define same_file(s,t) (-1)
+
+/* Define to a substitute for the stat function. */
+#define stat wnt_stat
+
+/* ====================== Typedef Declarations Follow ===================== */
+
+/* ====================== Function Prototypes Follow ====================== */
+
+#include <woe32.h>
+
+/* #define SOCK_STRERROR sock_strerror */
+char *sock_strerror (int errnum);
+
+/* #define CVS_MKDIR wnt_mkdir */
+int wnt_mkdir (const char *PATH, int MODE);
+
+/* #define CVS_RENAME wnt_rename */
+int wnt_rename (const char *, const char *);
+
+/* #define SHUTDOWN_SERVER wnt_shutdown_server */
+void wnt_shutdown_server (int fd);
+
+/* #define START_SERVER wnt_start_server */
+void wnt_start_server (int *tofd, int *fromfd,
+ char *client_user,
+ char *server_user,
+ char *server_host,
+ char *server_cvsroot);
+
+/* #define stat wnt_stat and #define lstat wnt_stat */
+int wnt_stat (const char *file, struct wnt_stat *sb);
+
+/* =============== Special mkdir Prototype Handling Follows =============== */
+
+#include <direct.h>
+#define mkdir wnt_mkdir
+
+/* ===================== Special Function Definitions ===================== */
+
+/*
+ Microsoft defines "mbinit" in <wchar.h> for C++ code only.
+
+ Expect link errors for versions:
+
+ earlier than Visual C++ 5.0
+
+ later than Visual C++ .NET 2003
+
+ and Visual C++ .NET is just a guess which might be wrong.
+*/
+
+#if _MSC_VER >= 1100 && _MSC_VER <= 1200
+
+/* If within Visual C++ 5.0 to Visual C++ 6.0 */
+
+inline int mbsinit (const void * arg)
+ { return 1; }
+
+#elif _MSC_VER >= 1300 && _MSC_VER <= 1310
+
+/* If within Visual C++ .NET to Visual C++ .NET 2003 */
+
+inline int mbsinit (const int * arg)
+ { return arg == NULL || ! *arg; }
+
+#endif
+
+/* =========================== End Of This File =========================== */
diff --git a/windows-NT/config.h.in.in b/windows-NT/config.h.in.in
new file mode 100644
index 0000000..08bae9b
--- /dev/null
+++ b/windows-NT/config.h.in.in
@@ -0,0 +1,1240 @@
+/* config.h.in.in: configuration file for Windows NT
+ Conrad T. Pino <Conrad@Pino.com> --- May 2004 */
+
+/* This file lives in the windows-NT subdirectory, which is only included
+ in your header search path if you're working under Microsoft Visual C++,
+ and use ../cvsnt.mak for your project. Thus, this is the right place to
+ put configuration information for Windows NT. */
+
+/* Define this to a NULL terminated list of allowed path prefixes (for
+ directories) and paths to files the CVS server will allow configuration to
+ be read from when specified from the command line. */
+#undef ALLOW_CONFIG_OVERRIDE
+
+/* Enable AUTH_CLIENT_SUPPORT to enable pserver as a remote access method in
+ the CVS client (default) */
+#define AUTH_CLIENT_SUPPORT 1
+
+/* Define if you want to use the password authenticated server. */
+#undef AUTH_SERVER_SUPPORT
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#define CLIENT_SUPPORT
+
+/* Define to 1 if the `closedir' function returns void instead of `int'. */
+#undef CLOSEDIR_VOID
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* define if cross compiling */
+#undef CROSS_COMPILING
+
+/* The CVS admin command is restricted to the members of the group
+ CVS_ADMIN_GROUP. If this group does not exist, all users are allowed to run
+ CVS admin. To disable the CVS admin command for all users, create an empty
+ CVS_ADMIN_GROUP by running configure with the --with-cvs-admin-group=
+ option. To disable access control for CVS admin, run configure with the
+ --without-cvs-admin-group option in order to comment out the define below.
+ */
+#undef CVS_ADMIN_GROUP
+
+/* When committing a permanent change, CVS and RCS make a log entry of who
+ committed the change. If you are committing the change logged in as "root"
+ (not under "su" or other root-priv giving program), CVS/RCS cannot
+ determine who is actually making the change. As such, by default, CVS
+ prohibits changes committed by users logged in as "root". You can disable
+ checking by passing the "--enable-rootcommit" option to configure or by
+ commenting out the lines below. */
+#undef CVS_BADROOT
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define if there is a member named d_ino in the struct describing directory
+ headers. */
+#undef D_INO_IN_DIRENT
+
+/* The default editor to use, if one does not specify the "-e" option to cvs,
+ or does not have an EDITOR environment variable. If this is not set to an
+ absolute path to an executable, use the shell to find where the editor
+ actually is. This allows sites with /usr/bin/vi or /usr/ucb/vi to work
+ equally well (assuming that their PATH is reasonable). */
+#define EDITOR_DFLT "notepad"
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#undef ENABLE_NLS
+
+/* Define to enable encryption support. */
+#undef ENCRYPTION
+
+/* Define as good substitute value for EOVERFLOW. */
+#define EOVERFLOW EINVAL
+
+/* Define if this executable will be running on case insensitive file systems.
+ In the client case, this means that it will request that the server pretend
+ to be case insensitive if it isn't already. */
+#define FILENAMES_CASE_INSENSITIVE 1
+
+/* Define on systems for which file names may have a so-called `drive letter'
+ prefix, define this to compute the length of that prefix, including the
+ colon. */
+#define FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX 1
+
+/* Define if the backslash character may also serve as a file name component
+ separator. */
+#define FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR 1
+
+/* When committing or importing files, you must enter a log message. Normally,
+ you can do this either via the -m flag on the command line, the -F flag on
+ the command line, or an editor will be started for you. If you like to use
+ logging templates (the rcsinfo file within the $CVSROOT/CVSROOT directory),
+ you might want to force people to use the editor even if they specify a
+ message with -m or -F. Enabling FORCE_USE_EDITOR will cause the -m or -F
+ message to be appended to the temp file when the editor is started. */
+#undef FORCE_USE_EDITOR
+
+/* Define to an alternative value if GSS_C_NT_HOSTBASED_SERVICE isn't defined
+ in the gssapi.h header file. MIT Kerberos 1.2.1 requires this. Only
+ relevant when using GSSAPI. */
+#undef GSS_C_NT_HOSTBASED_SERVICE
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have `alloca' after including <alloca.h>, a header that
+ may be supplied by this distribution. */
+#undef HAVE_ALLOCA
+
+/* Define HAVE_ALLOCA_H for backward compatibility with older code that
+ includes <alloca.h> only if HAVE_ALLOCA_H is defined. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the `atexit' function. */
+#define HAVE_ATEXIT 1
+
+/* Define to 1 if you have the <bp-sym.h> header file. */
+#undef HAVE_BP_SYM_H
+
+/* Define to 1 if you have the `btowc' function. */
+#undef HAVE_BTOWC
+
+/* Define to 1 if you have the `canonicalize_file_name' function. */
+#undef HAVE_CANONICALIZE_FILE_NAME
+
+/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+#undef HAVE_CFLOCALECOPYCURRENT
+
+/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+#undef HAVE_CFPREFERENCESCOPYAPPVALUE
+
+/* Define to 1 if you have the `chsize' function. */
+#define HAVE_CHSIZE 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `clock_settime' function. */
+#undef HAVE_CLOCK_SETTIME
+
+/* Define if you have the connect function. */
+#define HAVE_CONNECT
+
+/* Define if you have the crypt function. */
+#undef HAVE_CRYPT
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+#undef HAVE_DCGETTEXT
+
+/* Define to 1 if you have the declaration of `clearerr_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_CLEARERR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `__fpending', and to 0 if you
+ don't. */
+#define HAVE_DECL___FPENDING 0
+
+/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FEOF_UNLOCKED
+
+/* Define to 1 if you have the declaration of `ferror_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FERROR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fflush_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FFLUSH_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FGETS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `flockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FLOCKFILE
+
+/* Define to 1 if you have the declaration of `fputc_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fputs_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fread_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FREAD_UNLOCKED
+
+/* Define to 1 if you have the declaration of `funlockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FUNLOCKFILE
+
+/* Define to 1 if you have the declaration of `fwrite_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FWRITE_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getcwd', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETCWD 1
+
+/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getdelim', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETDELIM
+
+/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETENV 1
+
+/* Define to 1 if you have the declaration of `getline', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLINE
+
+/* Define to 1 if you have the declaration of `getlogin', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN
+
+/* Define to 1 if you have the declaration of `getlogin_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN_R
+
+/* Define to 1 if you have the declaration of `getpass', and to 0 if you
+ don't. */
+#define HAVE_DECL_GETPASS 1
+
+/* Define to 1 if you have the declaration of `memrchr', and to 0 if you
+ don't. */
+#undef HAVE_DECL_MEMRCHR
+
+/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
+ don't. */
+#define HAVE_DECL_NANOSLEEP 1
+
+/* Define to 1 if you have the declaration of `putchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_PUTCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `putc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_PUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `strdup', and to 0 if you don't.
+ */
+#define HAVE_DECL_STRDUP 1
+
+/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_STRERROR_R
+
+/* Define to 1 if you have the <direct.h> header file. */
+/* Windows has <direct.h> but some functions aren't POSIX compliant */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dup2' function. */
+#define HAVE_DUP2 1
+
+/* Define if you have the declaration of environ. */
+#define HAVE_ENVIRON_DECL 1
+
+/* Define if you have the declaration of errno. */
+#define HAVE_ERRNO_DECL 1
+
+/* Define to 1 if you have the `fchdir' function. */
+#undef HAVE_FCHDIR
+
+/* Define to 1 if you have the `fchmod' function. */
+#undef HAVE_FCHMOD
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `flockfile' function. */
+#undef HAVE_FLOCKFILE
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `fsync' function. */
+#undef HAVE_FSYNC
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have the `funlockfile' function. */
+#undef HAVE_FUNLOCKFILE
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `getgroups' function. */
+#undef HAVE_GETGROUPS
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `getlogin_r' function. */
+#undef HAVE_GETLOGIN_R
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long_only' function. */
+#undef HAVE_GETOPT_LONG_ONLY
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define if you have the getspnam function. */
+#undef HAVE_GETSPNAM
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#undef HAVE_GETTEXT
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H 1
+
+/* Define if you have GSSAPI with Kerberos version 5 available. */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
+/* Define if you have the iconv() function. */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_INTMAX_T
+
+/* Define if <inttypes.h> exists and doesn't clash with <sys/types.h>. */
+#undef HAVE_INTTYPES_H
+
+/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
+ declares uintmax_t. */
+#undef HAVE_INTTYPES_H_WITH_UINTMAX
+
+/* Define to 1 if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET. */
+#define HAVE_IPV4 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET6. */
+#undef HAVE_IPV6
+
+/* Define to 1 if you have the `isascii' function. */
+#define HAVE_ISASCII 1
+
+/* Define to 1 if you have the `isblank' function. */
+#undef HAVE_ISBLANK
+
+/* Define to 1 if you have the `iswprint' function. */
+#define HAVE_ISWPRINT 1
+
+/* Define if you have MIT Kerberos version 4 available. */
+#undef HAVE_KERBEROS
+
+/* Define to 1 if you have the <krb5.h> header file. */
+#undef HAVE_KRB5_H
+
+/* Define to 1 if you have the `krb_get_err_text' function. */
+#undef HAVE_KRB_GET_ERR_TEXT
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#undef HAVE_LANGINFO_CODESET
+
+/* Define to 1 if you have the `krb' library (-lkrb). */
+#undef HAVE_LIBKRB
+
+/* Define to 1 if you have the `krb4' library (-lkrb4). */
+#undef HAVE_LIBKRB4
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `login' function. */
+#undef HAVE_LOGIN
+
+/* Define to 1 if you have the `logout' function. */
+#undef HAVE_LOGOUT
+
+/* Define if you have the 'long double' type. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have the 'long long' type. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including
+ config.h and <sys/mman.h>. */
+#undef HAVE_MAP_ANONYMOUS
+
+/* Define to 1 if you have the `mblen' function. */
+#define HAVE_MBLEN 1
+
+/* Define to 1 if you have the `mbrlen' function. */
+#define HAVE_MBRLEN 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if you have the `mbsinit' function. */
+#undef HAVE_MBSINIT
+
+/* Define to 1 if you have the `mbsrtowcs' function. */
+#define HAVE_MBSRTOWCS 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define if you have memchr (always for CVS). */
+#define HAVE_MEMCHR 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mempcpy' function. */
+#undef HAVE_MEMPCPY
+
+/* Define to 1 if you have the `memrchr' function. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if <limits.h> defines the MIN and MAX macros. */
+#define HAVE_MINMAX_IN_LIMITS_H 1
+
+/* Define to 1 if <sys/param.h> defines the MIN and MAX macros. */
+#undef HAVE_MINMAX_IN_SYS_PARAM_H
+
+/* Define to 1 if you have the `mknod' function. */
+#undef HAVE_MKNOD
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `nanotime' function. */
+#undef HAVE_NANOTIME
+
+/* Define to 1 if you have the <ndbm.h> header file. */
+#undef HAVE_NDBM_H
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#define HAVE_NDIR_H 1
+
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
+/* Define to 1 if you have the <OS.h> header file. */
+#undef HAVE_OS_H
+
+/* Define to enable system authentication with PAM instead of using the simple
+ getpwnam interface. This allows authentication (in theory) with any PAM
+ module, e.g. on systems with shadow passwords or via LDAP */
+#undef HAVE_PAM
+
+/* Define to 1 if pam/pam_appl.h is available */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
+ setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX is not
+ defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD is defined.
+ */
+#undef HAVE_PARTLY_WORKING_GETCWD
+
+/* Define to 1 if you have the `posix_memalign' function. */
+#undef HAVE_POSIX_MEMALIGN
+
+/* Define to 1 if the `printf' function supports the %p format for printing
+ pointers. */
+#define HAVE_PRINTF_PTR 1
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#define HAVE_PTRDIFF_T 1
+
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#define HAVE_REALLOC 1
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the `regerror' function. */
+#undef HAVE_REGERROR
+
+/* Define to 1 if you have the `regexec' function. */
+#undef HAVE_REGEXEC
+
+/* Define to 1 if you have the `regfree' function. */
+#undef HAVE_REGFREE
+
+/* Define to 1 if you have the `resolvepath' function. */
+#undef HAVE_RESOLVEPATH
+
+/* Define to 1 if you have the `rpmatch' function. */
+#undef HAVE_RPMATCH
+
+/* Define to 1 if you have run the test for working tzset. */
+#define HAVE_RUN_TZSET_TEST 1
+
+/* Define to 1 if you have the <search.h> header file. */
+#define HAVE_SEARCH_H 1
+
+/* Define to 1 if security/pam_appl.h is available */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define if the diff library should use setmode for binary files. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigblock' function. */
+#undef HAVE_SIGBLOCK
+
+/* Define to 1 if you have the `siginterrupt' function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define to 1 if you have the `sigsetmask' function. */
+#undef HAVE_SIGSETMASK
+
+/* Define to 1 if you have the `sigvec' function. */
+#undef HAVE_SIGVEC
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
+ uintmax_t. */
+#define HAVE_STDINT_H_WITH_UINTMAX 1
+
+/* Define to 1 if you have the <stdio_ext.h> header file. */
+#undef HAVE_STDIO_EXT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have strchr (always for CVS). */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define if there is a member named d_type in the struct describing directory
+ headers. */
+#undef HAVE_STRUCT_DIRENT_D_TYPE
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define if struct timespec is declared in <time.h>. */
+#undef HAVE_STRUCT_TIMESPEC
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_ZONE
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/inttypes.h> header file. */
+#undef HAVE_SYS_INTTYPES_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `tcgetattr' function. */
+#undef HAVE_TCGETATTR
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the `timezone' function. */
+#undef HAVE_TIMEZONE
+
+/* Define to 1 if localtime_r, etc. have the type signatures that POSIX
+ requires. */
+#undef HAVE_TIME_R_POSIX
+
+/* Define if struct tm has the tm_gmtoff member. */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#undef HAVE_TM_ZONE
+
+/* Define to 1 if you have the `tsearch' function. */
+#undef HAVE_TSEARCH
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the `tzset' function. */
+#define HAVE_TZSET 1
+
+/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_UINTMAX_T
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define if you have the 'unsigned long long' type. */
+#undef HAVE_UNSIGNED_LONG_LONG
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
+#define HAVE_UTIME_NULL 1
+
+/* Define to 1 if you have the `vasnprintf' function. */
+#undef HAVE_VASNPRINTF
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `wait3' function. */
+#undef HAVE_WAIT3
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define if you have the 'wchar_t' type. */
+#define HAVE_WCHAR_T 1
+
+/* Define to 1 if you have the `wcrtomb' function. */
+#define HAVE_WCRTOMB 1
+
+/* Define to 1 if you have the `wcscoll' function. */
+#define HAVE_WCSCOLL 1
+
+/* Define to 1 if you have the `wcslen' function. */
+#define HAVE_WCSLEN 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define if you have the 'wint_t' type. */
+#define HAVE_WINT_T 1
+
+/* Define to 1 if you have the `wmemchr' function. */
+#define HAVE_WMEMCHR 1
+
+/* Define to 1 if you have the `wmemcpy' function. */
+#define HAVE_WMEMCPY 1
+
+/* Define to 1 if you have the `wmempcpy' function. */
+#undef HAVE_WMEMPCPY
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to 1 if you have the `__fpending' function. */
+#undef HAVE___FPENDING
+
+/* Define to 1 if you have the `__fsetlocking' function. */
+#undef HAVE___FSETLOCKING
+
+/* Define to 1 if you have the `__secure_getenv' function. */
+#undef HAVE___SECURE_GETENV
+
+/* Define to include locking code which prevents versions of CVS earlier than
+ 1.12.4 directly accessing the same repositiory as this executable from
+ ignoring this executable's promotable read locks. If only CVS versions
+ 1.12.4 and later will be accessing your repository directly (as a server or
+ locally), you can safely disable this option in return for fewer disk
+ accesses and a small speed increase. Disabling this option when versions of
+ CVS earlier than 1,12,4 _will_ be accessing your repository, however, is
+ *VERY* *VERY* *VERY* dangerous and could result in data loss. As such, by
+ default, CVS is compiled with this code enabled. If you are sure you would
+ like this code disabled, you can disable it by passing the
+ "--disable-lock-compatibility" option to configure or by commenting out the
+ lines below. */
+#define LOCK_COMPATIBILITY
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
+
+/* If malloc(0) is != NULL, define this to 1. Otherwise define this to 0. */
+#undef MALLOC_0_IS_NONNULL
+
+/* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */
+#undef MAP_ANONYMOUS
+
+/* By default, CVS stores its modules and other such items in flat text files
+ (MY_NDBM enables this). Turning off MY_NDBM causes CVS to look for a
+ system-supplied ndbm database library and use it instead. That may speed
+ things up, but the default setting generally works fine too. */
+#define MY_NDBM
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "%PACKAGE_BUGREPORT%"
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "%PACKAGE_STRING%"
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to set a service name for PAM. This must be defined. Define to
+ `program_name', without the quotes, to use whatever name CVS was invoked
+ as. Otherwise, define to a double-quoted literal string, such as `"cvs"'.
+ */
+#undef PAM_SERVICE_NAME
+
+/* the number of pending output bytes on stream `fp' */
+#define PENDING_OUTPUT_N_BYTES ( fp ? fp->_ptr - fp->_base : 0 )
+
+/* Define if you want CVS to be able to serve as a transparent proxy for write
+ operations. Disabling this may produce a slight performance gain on some
+ systems, at the expense of write proxy support. */
+#undef PROXY_SUPPORT
+
+/* Path to the pr utility */
+#undef PR_PROGRAM
+
+/* Define to force lib/regex.c to use malloc instead of alloca. */
+#define REGEX_MALLOC 1
+
+/* Define if rename does not work for source paths with a trailing slash, like
+ the one from SunOS 4.1.1_U1. */
+#undef RENAME_TRAILING_SLASH_BUG
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* If you are working with a large remote repository and a 'cvs checkout' is
+ swamping your network and memory, define these to enable flow control. You
+ will end up with even less probability of a consistent checkout (see
+ Concurrency in cvs.texinfo), but CVS doesn't try to guarantee that anyway.
+ The master server process will monitor how far it is getting behind, if it
+ reaches the high water mark, it will signal the child process to stop
+ generating data when convenient (ie: no locks are held, currently at the
+ beginning of a new directory). Once the buffer has drained sufficiently to
+ reach the low water mark, it will be signalled to start again. */
+#undef SERVER_FLOWCONTROL
+
+/* The high water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_HI_WATER
+
+/* The low water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_LO_WATER
+
+/* Define if you want CVS to be able to serve repositories to remote clients.
+ */
+#undef SERVER_SUPPORT
+
+/* The size of a `char', as computed by sizeof. */
+#define SIZEOF_CHAR 1
+
+/* The size of a `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of a `float', as computed by sizeof. */
+#define SIZEOF_FLOAT 4
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `intmax_t', as computed by sizeof. */
+#undef SIZEOF_INTMAX_T
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of a `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 8
+
+/* The size of a `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of a `ptrdiff_t', as computed by sizeof. */
+#define SIZEOF_PTRDIFF_T 4
+
+/* The size of a `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of a `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of a `wint_t', as computed by sizeof. */
+#define SIZEOF_WINT_T 2
+
+/* Define as the maximum value of type 'size_t', if the system doesn't define
+ it. */
+#define SIZE_MAX (~(size_t)0)
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#define STAT_MACROS_BROKEN 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r returns char *. */
+#undef STRERROR_R_CHAR_P
+
+/* Enable support for the pre 1.12.1 *info scripting hook format strings.
+ Disable this option for a smaller executable once your scripting hooks have
+ been updated to use the new *info format strings by passing
+ "--disable-old-info-format-support" option to configure or by commenting
+ out the line below. */
+#undef SUPPORT_OLD_INFO_FMT_STRINGS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little need
+ to change this (-T is a better mechanism if you need to use a different
+ directory for temporary files). */
+#define TMPDIR_DFLT "c:\\temp"
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define if tzset clobbers localtime's static buffer. */
+#undef TZSET_CLOBBERS_LOCALTIME_BUFFER
+
+/* Define to its maximum value if an unsigned integer type of width exactly 32
+ bits exists and the standard includes do not define UINT32_MAX. */
+#undef UINT32_MAX
+
+/* The default umask to use when creating or otherwise setting file or
+ directory permissions in the repository. Must be a value in the range of 0
+ through 0777. For example, a value of 002 allows group rwx access and world
+ rx access; a value of 007 allows group rwx access but no world access. This
+ value is overridden by the value of the CVSUMASK environment variable,
+ which is interpreted as an octal number. */
+#define UMASK_DFLT 002
+
+/* Define if double is the first floating point type detected with its size.
+ */
+#undef UNIQUE_FLOAT_TYPE_DOUBLE
+
+/* Define if float is the first floating point type detected with its size. */
+#undef UNIQUE_FLOAT_TYPE_FLOAT
+
+/* Define if long double is the first floating point type detected with its
+ size. */
+#undef UNIQUE_FLOAT_TYPE_LONG_DOUBLE
+
+/* Define if char is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_CHAR
+
+/* Define if int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INT
+
+/* Define if intmax_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INTMAX_T
+
+/* Define if long int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG
+
+/* Define if long long is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG_LONG
+
+/* Define if ptrdiff_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_PTRDIFF_T
+
+/* Define if short is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SHORT
+
+/* Define if size_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SIZE_T
+
+/* Define if wint_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_WINT_T
+
+/* Define if setmode is required when writing binary data to stdout. */
+#define USE_SETMODE_STDOUT 1
+
+/* Define to 1 if you want getc etc. to use unlocked I/O if available.
+ Unlocked I/O can improve performance in unithreaded apps, but it is not
+ safe for multithreaded apps. */
+#undef USE_UNLOCKED_IO
+
+/* Define if utime requires write access to the file (true on Windows, but not
+ Unix). */
+#define UTIME_EXPECTS_WRITABLE
+
+/* Define if unsetenv() returns void, not int. */
+#undef VOID_UNSETENV
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define if you want regoff_t to be at least as wide POSIX requires. */
+#undef _REGEX_LARGE_OFFSETS
+
+/* Define to force lib/regex.c to define re_comp et al. */
+#define _REGEX_RE_COMP 1
+
+/* Define for Solaris 2.5.1 so uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+
+/* Define to rpl_ if the getcwd replacement function should be used. */
+#undef __GETCWD_PREFIX
+
+/* Define to rpl_ if the getopt replacement functions and variables should be
+ used. */
+#define __GETOPT_PREFIX rpl_
+
+/* Define to rpl_ if the openat replacement function should be used. */
+#undef __OPENAT_PREFIX
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to a replacement function name for fnmatch(). */
+#undef fnmatch
+
+/* Define to a replacement function name for getline(). */
+#undef getline
+
+/* We want to always use the GNULIB version of getpass which we have in lib,
+ so define getpass to something that won't conflict with any existing system
+ declarations. */
+#undef getpass
+
+/* Define to rpl_gettimeofday if the replacement function should be used. */
+#undef gettimeofday
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to rpl_gmtime if the replacement function should be used. */
+#undef gmtime
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+
+/* Define to long or long long if <inttypes.h> and <stdint.h> don't define. */
+#undef intmax_t
+
+/* Define to rpl_localtime if the replacement function should be used. */
+#undef localtime
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to a type if <wchar.h> does not define. */
+#undef mbstate_t
+
+/* Define to rpl_mkdir if the replacement function should be used. */
+#undef mkdir
+
+/* Define to rpl_mkstemp if the replacement function should be used. */
+#undef mkstemp
+
+/* Define to rpl_mktime if the replacement function should be used. */
+#undef mktime
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define mode_t int
+
+/* Define to the name of the strftime replacement function. */
+#define my_strftime nstrftime
+
+/* Define to rpl_nanosleep if the replacement function should be used. */
+#define nanosleep woe32_nanosleep
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to rpl_realloc if the replacement function should be used. */
+#define realloc rpl_realloc
+
+/* Define to rpl_rename if the replacement function should be used. */
+#undef rename
+
+/* Define to equivalent of C99 restrict keyword, or to nothing if this is not
+ supported. Do not define if restrict is supported directly. */
+#define restrict
+
+/* Define to rpl_select if the replacement function should be used. */
+#undef select
+
+/* Define to empty if the C compiler doesn't support this keyword. */
+#undef signed
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define as a signed type of the same size as size_t. */
+#define ssize_t int
+
+/* Define to rpl_strcasecmp always. */
+#define strcasecmp rpl_strcasecmp
+
+/* Define to rpl_tzset if the wrapper function should be used. */
+#undef tzset
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to the type of a unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to unsigned long or unsigned long long if <stdint.h> and
+ <inttypes.h> don't define. */
+#undef uintmax_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
diff --git a/windows-NT/filesubr.c b/windows-NT/filesubr.c
new file mode 100644
index 0000000..55d57de
--- /dev/null
+++ b/windows-NT/filesubr.c
@@ -0,0 +1,1029 @@
+/* filesubr.c --- subroutines for dealing with files
+ Jim Blandy <jimb@cyclic.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* These functions were moved out of subr.c because they need different
+ definitions under operating systems (like, say, Windows NT) with different
+ file system semantics. */
+
+#include <assert.h>
+#include <io.h>
+#include <sys/socket.h> /* This does: #include <windows.h> */
+
+#include "cvs.h"
+#include "setenv.h"
+
+#include "JmgStat.h"
+
+#undef mkdir
+
+static int deep_remove_dir( const char *path );
+
+/* Copies "from" to "to". Note that the functionality here is similar
+ to the win32 function CopyFile, but (1) we copy LastAccessTime and
+ CopyFile doesn't, (2) we set file attributes to the default set by
+ the C library and CopyFile copies them. Neither #1 nor #2 was intentional
+ as far as I know, but changing them could be confusing, unless there
+ is some reason they should be changed (this would need more
+ investigation). */
+void
+copy_file (from, to)
+ const char *from;
+ const char *to;
+{
+ struct stat sb;
+ struct utimbuf t;
+ int fdin, fdout;
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open %s for copying", from);
+ if (fstat (fdin, &sb) < 0)
+ error (1, errno, "cannot fstat %s", from);
+ if ((fdout = open (to, O_CREAT | O_TRUNC | O_RDWR | O_BINARY,
+ (int) sb.st_mode & 07777)) < 0)
+ error (1, errno, "cannot create %s for copying", to);
+ if (sb.st_size > 0)
+ {
+ char buf[BUFSIZ];
+ int n;
+
+ for (;;)
+ {
+ n = read (fdin, buf, sizeof(buf));
+ if (n == -1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ error (1, errno, "cannot read file %s for copying", from);
+ }
+ else if (n == 0)
+ break;
+
+ if (write(fdout, buf, n) != n) {
+ error (1, errno, "cannot write file %s for copying", to);
+ }
+ }
+
+#ifdef HAVE_FSYNC
+ if (fsync (fdout))
+ error (1, errno, "cannot fsync file %s after copying", to);
+#endif
+ }
+
+ if (close (fdin) < 0)
+ error (0, errno, "cannot close %s", from);
+ if (close (fdout) < 0)
+ error (1, errno, "cannot close %s", to);
+
+ /* now, set the times for the copied file to match those of the original */
+ memset ((char *) &t, 0, sizeof (t));
+ t.actime = sb.st_atime;
+ t.modtime = sb.st_mtime;
+ (void) utime (to, &t);
+}
+
+
+static char *tmpdir_env;
+/*
+ * Return seperator (\) terminated path to system temporary directory.
+ */
+const char *
+get_system_temp_dir (void)
+{
+ if (! tmpdir_env)
+ {
+ DWORD dwBufferSize, dwReturn;
+
+ dwReturn = 0;
+ dwBufferSize = 64;
+ do {
+ if (dwReturn >= dwBufferSize)
+ {
+ dwBufferSize = dwReturn + 4;
+ }
+
+ tmpdir_env = xrealloc (tmpdir_env, dwBufferSize);
+ if (tmpdir_env)
+ {
+ dwReturn = GetTempPath (dwBufferSize, tmpdir_env);
+ if (dwReturn <= 0)
+ {
+ free (tmpdir_env);
+ tmpdir_env = NULL;
+ }
+ }
+ } while (tmpdir_env && dwReturn >= dwBufferSize);
+ }
+
+ return tmpdir_env;
+}
+
+
+void
+push_env_temp_dir (void)
+{
+ const char *tmpdir = get_cvs_tmp_dir ();
+
+ if (tmpdir_env && strcmp (tmpdir_env, tmpdir))
+ setenv ("TMP", tmpdir, 1);
+}
+
+
+/* FIXME-krp: these functions would benefit from caching the char * &
+ stat buf. */
+
+/*
+ * Returns non-zero if the argument file is a directory, or is a symbolic
+ * link which points to a directory.
+ */
+int
+isdir (file)
+ const char *file;
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return (0);
+ return (S_ISDIR (sb.st_mode));
+}
+
+/*
+ * Returns non-zero if the argument file is a symbolic link.
+ */
+int
+islink (file)
+ const char *file;
+{
+#ifdef S_ISLNK
+ struct stat sb;
+
+ if (lstat (file, &sb) < 0)
+ return (0);
+ return (S_ISLNK (sb.st_mode));
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Returns non-zero if the argument file exists.
+ */
+int
+isfile (file)
+ const char *file;
+{
+ return isaccessible(file, F_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is readable.
+ */
+int
+isreadable (file)
+ const char *file;
+{
+ return isaccessible(file, R_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is writable.
+ */
+int
+iswritable (file)
+ const char *file;
+{
+ return isaccessible(file, W_OK);
+}
+
+/*
+ * Returns non-zero if the argument file is accessable according to
+ * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
+ * bits set.
+ */
+int
+isaccessible (file, mode)
+ const char *file;
+ const int mode;
+{
+#ifdef SETXID_SUPPORT
+ struct stat sb;
+ int umask = 0;
+ int gmask = 0;
+ int omask = 0;
+ int uid;
+
+ if (stat(file, &sb) == -1)
+ return 0;
+ if (mode == F_OK)
+ return 1;
+
+ uid = geteuid();
+ if (uid == 0) /* superuser */
+ {
+ if (mode & X_OK)
+ return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
+ else
+ return 1;
+ }
+
+ if (mode & R_OK)
+ {
+ umask |= S_IRUSR;
+ gmask |= S_IRGRP;
+ omask |= S_IROTH;
+ }
+ if (mode & W_OK)
+ {
+ umask |= S_IWUSR;
+ gmask |= S_IWGRP;
+ omask |= S_IWOTH;
+ }
+ if (mode & X_OK)
+ {
+ umask |= S_IXUSR;
+ gmask |= S_IXGRP;
+ omask |= S_IXOTH;
+ }
+
+ if (sb.st_uid == uid)
+ return (sb.st_mode & umask) == umask;
+ else if (sb.st_gid == getegid())
+ return (sb.st_mode & gmask) == gmask;
+ else
+ return (sb.st_mode & omask) == omask;
+#else
+ return access(file, mode) == 0;
+#endif
+}
+
+
+
+/*
+ * Make a directory and die if it fails
+ */
+void
+make_directory (name)
+ const char *name;
+{
+ struct stat sb;
+
+ if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
+ error (0, 0, "%s already exists but is not a directory", name);
+ if (!noexec && mkdir (name) < 0)
+ error (1, errno, "cannot make directory %s", name);
+}
+
+/*
+ * Make a path to the argument directory, printing a message if something
+ * goes wrong.
+ */
+void
+make_directories (name)
+ const char *name;
+{
+ char *cp;
+
+ if (noexec)
+ return;
+
+ if (mkdir (name) == 0 || errno == EEXIST)
+ return;
+ if (errno != ENOENT)
+ {
+ error (0, errno, "cannot make path to %s", name);
+ return;
+ }
+ if ((cp = strrchr (name, '/')) == NULL)
+ return;
+ *cp = '\0';
+ make_directories (name);
+ *cp++ = '/';
+ if (*cp == '\0')
+ return;
+ (void) mkdir (name);
+}
+
+/* Create directory NAME if it does not already exist; fatal error for
+ other errors. Returns 0 if directory was created; 1 if it already
+ existed. */
+int
+mkdir_if_needed (name)
+ const char *name;
+{
+ if (mkdir (name) < 0)
+ {
+ if (errno != EEXIST
+#ifdef EACCESS
+ /* This was copied over from the OS/2 code; I would guess it
+ isn't needed here but that has not been verified. */
+ && errno != EACCESS
+#endif
+#ifdef EACCES
+ /* This is said to be needed by NT on Alpha or PowerPC
+ (not sure what version) --August, 1996. */
+ && errno != EACCES
+#endif
+ )
+ error (1, errno, "cannot make directory %s", name);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Change the mode of a file, either adding write permissions, or removing
+ * all write permissions. Adding write permissions honors the current umask
+ * setting.
+ */
+void
+xchmod (fname, writable)
+ const char *fname;
+ int writable;
+{
+ struct stat sb;
+ mode_t mode, oumask;
+
+ if (stat (fname, &sb) < 0)
+ {
+ if (!noexec)
+ error (0, errno, "cannot stat %s", fname);
+ return;
+ }
+ if (writable)
+ {
+ oumask = umask (0);
+ (void) umask (oumask);
+ mode = sb.st_mode | ~oumask & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) |
+ ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) |
+ ((sb.st_mode & S_IROTH) ? S_IWOTH : 0));
+ }
+ else
+ {
+ mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH);
+ }
+
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
+ (server_active) ? 'S' : ' ', fname, mode);
+#else
+ (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
+#endif
+ if (noexec)
+ return;
+
+ if (chmod (fname, mode) < 0)
+ error (0, errno, "cannot change mode of file %s", fname);
+}
+
+
+/* Rename for NT which works for read only files. Apparently if we are
+ accessing FROM and TO via a Novell network, this is an issue. */
+int
+wnt_rename (from, to)
+ const char *from;
+ const char *to;
+{
+ int result, save_errno;
+ int readonly = !iswritable (from);
+
+ if (readonly)
+ {
+ if (chmod (from, S_IWRITE) < 0)
+ return -1;
+ }
+ result = rename (from, to);
+ save_errno = errno;
+ if (readonly)
+ {
+ if (result == 0)
+ {
+ if (chmod (to, S_IREAD) < 0)
+ return -1;
+ }
+ else
+ {
+ /* We have a choice of which error to report, if there is
+ one here too; report the one from rename (). */
+ chmod (from, S_IREAD);
+ }
+ errno = save_errno;
+ }
+ return result;
+}
+
+/*
+ * Rename a file and die if it fails
+ */
+void
+rename_file (from, to)
+ const char *from;
+ const char *to;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return;
+
+ /* Win32 unlink is stupid --- it fails if the file is read-only */
+ chmod(to, S_IWRITE);
+ unlink(to);
+ if (CVS_RENAME (from, to) < 0)
+ error (1, errno, "cannot rename file %s to %s", from, to);
+}
+
+/*
+ * unlink a file, if possible.
+ */
+int
+unlink_file (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ /* Win32 unlink is stupid - it fails if the file is read-only */
+ chmod (f, _S_IWRITE);
+ return (unlink (f));
+}
+
+/*
+ * Unlink a file or dir, if possible. If it is a directory do a deep
+ * removal of all of the files in the directory. Return -1 on error
+ * (in which case errno is set).
+ */
+int
+unlink_file_dir (f)
+ const char *f;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
+ (server_active) ? 'S' : ' ', f);
+#else
+ (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
+#endif
+ if (noexec)
+ return (0);
+
+ /* Win32 unlink is stupid - it fails if the file is read-only */
+ chmod (f, _S_IWRITE);
+ if (unlink (f) != 0)
+ {
+ /* Under Windows NT, unlink returns EACCES if the path
+ is a directory. Under Windows 95, it returns ENOENT.
+ Under Windows XP, it can return ENOTEMPTY. */
+ if (errno == EISDIR || errno == EACCES || errno == ENOENT
+ || errno == ENOTEMPTY)
+ return deep_remove_dir (f);
+ else
+ /* The file wasn't a directory and some other
+ * error occured
+ */
+ return -1;
+ }
+ /* We were able to remove the file from the disk */
+ return 0;
+}
+
+/* Remove a directory and everything it contains. Returns 0 for
+ * success, -1 for failure (in which case errno is set).
+ */
+
+static int
+deep_remove_dir (path)
+ const char *path;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char buf[PATH_MAX];
+
+ /* ENOTEMPTY for NT (obvious) but EACCES for Win95 (not obvious) */
+ if (rmdir (path) != 0)
+ {
+ if (errno == ENOTEMPTY || errno == EACCES)
+ {
+ if ((dirp = CVS_OPENDIR (path)) == NULL)
+ /* If unable to open the directory return
+ * an error
+ */
+ return -1;
+
+ while ((dp = CVS_READDIR (dirp)) != NULL)
+ {
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0)
+ continue;
+
+ sprintf (buf, "%s/%s", path, dp->d_name);
+
+ /* Win32 unlink is stupid - it fails if the file is read-only */
+ chmod (buf, _S_IWRITE);
+ if (unlink (buf) != 0 )
+ {
+ /* Under Windows NT, unlink returns EACCES if the path
+ * is a directory. Under Windows 95, it returns ENOENT.
+ * Under Windows XP, it can return ENOTEMPTY. It
+ * isn't really clear to me whether checking errno is
+ * better or worse than using _stat to check for a
+ * directory.
+ * We aren't really trying to prevent race conditions here
+ * (e.g. what if something changes between readdir and
+ * unlink?)
+ */
+ if (errno == EISDIR || errno == EACCES || errno == ENOENT
+ || errno == ENOTEMPTY)
+ {
+ if (deep_remove_dir (buf))
+ {
+ closedir (dirp);
+ return -1;
+ }
+ }
+ else
+ {
+ /* buf isn't a directory, or there are
+ * some sort of permision problems
+ */
+ CVS_CLOSEDIR (dirp);
+ return -1;
+ }
+ }
+ }
+ CVS_CLOSEDIR (dirp);
+ return rmdir (path);
+ }
+ else
+ return -1;
+ }
+ /* Was able to remove the directory return 0 */
+ return 0;
+}
+
+/* Read NCHARS bytes from descriptor FD into BUF.
+ Return the number of characters successfully read.
+ The number returned is always NCHARS unless end-of-file or error. */
+static size_t
+block_read (fd, buf, nchars)
+ int fd;
+ char *buf;
+ size_t nchars;
+{
+ char *bp = buf;
+ size_t nread;
+
+ do
+ {
+ nread = read (fd, bp, nchars);
+ if (nread == (size_t)-1)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ return (size_t)-1;
+ }
+
+ if (nread == 0)
+ break;
+
+ bp += nread;
+ nchars -= nread;
+ } while (nchars != 0);
+
+ return bp - buf;
+}
+
+
+/*
+ * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
+ */
+int
+xcmp (file1, file2)
+ const char *file1;
+ const char *file2;
+{
+ char *buf1, *buf2;
+ struct stat sb1, sb2;
+ int fd1, fd2;
+ int ret;
+
+ if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file1);
+ if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
+ error (1, errno, "cannot open file %s for comparing", file2);
+ if (fstat (fd1, &sb1) < 0)
+ error (1, errno, "cannot fstat %s", file1);
+ if (fstat (fd2, &sb2) < 0)
+ error (1, errno, "cannot fstat %s", file2);
+
+ /* A generic file compare routine might compare st_dev & st_ino here
+ to see if the two files being compared are actually the same file.
+ But that won't happen in CVS, so we won't bother. */
+
+ if (sb1.st_size != sb2.st_size)
+ ret = 1;
+ else if (sb1.st_size == 0)
+ ret = 0;
+ else
+ {
+ /* FIXME: compute the optimal buffer size by computing the least
+ common multiple of the files st_blocks field */
+ size_t buf_size = 8 * 1024;
+ size_t read1;
+ size_t read2;
+
+ buf1 = xmalloc (buf_size);
+ buf2 = xmalloc (buf_size);
+
+ do
+ {
+ read1 = block_read (fd1, buf1, buf_size);
+ if (read1 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file1);
+
+ read2 = block_read (fd2, buf2, buf_size);
+ if (read2 == (size_t)-1)
+ error (1, errno, "cannot read file %s for comparing", file2);
+
+ /* assert (read1 == read2); */
+
+ ret = memcmp(buf1, buf2, read1);
+ } while (ret == 0 && read1 == buf_size);
+
+ free (buf1);
+ free (buf2);
+ }
+
+ (void) close (fd1);
+ (void) close (fd2);
+ return (ret);
+}
+
+/* Generate a unique temporary filename. Returns a pointer to a newly
+ * malloc'd string containing the name. Returns successfully or not at
+ * all.
+ *
+ * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!!
+ *
+ * and yes, I know about the way the rcs commands use temp files. I think
+ * they should be converted too but I don't have time to look into it right
+ * now.
+ */
+char *
+cvs_temp_name ()
+{
+ char *fn;
+ FILE *fp;
+
+ fp = cvs_temp_file (&fn);
+ if (fp == NULL)
+ error (1, errno, "Failed to create temporary file");
+ if (fclose (fp) == EOF)
+ error (0, errno, "Failed to close temporary file %s", fn);
+ return fn;
+}
+
+/* Generate a unique temporary filename and return an open file stream
+ * to the truncated file by that name
+ *
+ * INPUTS
+ * filename where to place the pointer to the newly allocated file
+ * name string
+ *
+ * OUTPUTS
+ * filename dereferenced, will point to the newly allocated file
+ * name string. This value is undefined if the function
+ * returns an error.
+ *
+ * RETURNS
+ * An open file pointer to a read/write mode empty temporary file with the
+ * unique file name or NULL on failure.
+ *
+ * ERRORS
+ * on error, errno will be set to some value either by CVS_FOPEN or
+ * whatever system function is called to generate the temporary file name
+ */
+/* FIXME: This should use the mkstemp() function from the lib/mkstemp.c file
+ * from the GNULIB project.
+ */
+FILE *cvs_temp_file (char ** filename)
+{
+ char *fn;
+ FILE *fp;
+
+ /* FIXME - I'd like to be returning NULL here in noexec mode, but I think
+ * some of the rcs & diff functions which rely on a temp file run in
+ * noexec mode too.
+ */
+
+ /* assert (filename != NULL); */
+
+ fn = _tempnam (getenv("TEMP"), "cvs");
+ if (fn == NULL) fp = NULL;
+ else
+ if ((fp = CVS_FOPEN (fn, "w+")) == NULL)
+ {
+ free (fn);
+ fn = NULL;
+ }
+
+ /* tempnam returns a pointer to a newly malloc'd string, so there's
+ * no need for a xstrdup
+ */
+
+ *filename = fn;
+ return fp;
+}
+
+
+
+/* Return a pointer into PATH's last component. */
+const char *
+last_component (const char *path)
+{
+ const char *scan;
+ const char *last = 0;
+
+ for (scan = path; *scan; scan++)
+ if (ISSLASH (*scan))
+ last = scan;
+
+ if (last && (last != path))
+ return last + 1;
+ else
+ return path;
+}
+
+
+/* NT has two evironment variables, HOMEPATH and HOMEDRIVE, which,
+ when combined as ${HOMEDRIVE}${HOMEPATH}, give the unix equivalent
+ of HOME. Some NT users are just too unixy, though, and set the
+ HOME variable themselves. Therefore, we check for HOME first, and
+ then try to combine the other two if that fails.
+
+ Looking for HOME strikes me as bogus, particularly if the only reason
+ is to cater to "unixy users". On the other hand, if the reasoning is
+ there should be a single variable, rather than requiring people to
+ set both HOMEDRIVE and HOMEPATH, then it starts to make a little more
+ sense.
+
+ Win95: The system doesn't set HOME, HOMEDRIVE, or HOMEPATH (at
+ least if you set it up as the "all users under one user ID" or
+ whatever the name of that option is). Based on thing overheard on
+ the net, it seems that users of the pserver client have gotten in
+ the habit of setting HOME (if you don't use pserver, you can
+ probably get away without having a reasonable return from
+ get_homedir. Of course you lose .cvsrc and .cvsignore, but many
+ users won't notice). So it would seem that we should be somewhat
+ careful if we try to change the current behavior.
+
+ NT 3.51 or NT 4.0: I haven't checked this myself, but I am told
+ that HOME gets set, but not to the user's home directory. It is
+ said to be set to c:\users\default by default. */
+
+char *
+get_homedir (void)
+{
+ char *homedir;
+
+ homedir = getenv ("HOME");
+
+ if (homedir == NULL)
+ homedir = woe32_home_dir ();
+
+ return homedir;
+}
+
+/* Compose a path to a file in the home directory. This is necessary because
+ * of different behavior on UNIX, Windows, and VMS. See more notes in
+ * vms/filesubr.c.
+ *
+ * A more clean solution would be something more along the lines of a
+ * "join a directory to a filename" kind of thing which was not specific to
+ * the homedir. This should aid portability between UNIX, Mac, Windows, VMS,
+ * and possibly others. This is already handled by Perl - it might be
+ * interesting to see how much of the code was written in C since Perl is under
+ * the GPL and the Artistic license - we might be able to use it.
+ */
+char *
+strcat_filename_onto_homedir (dir, file)
+ const char *dir;
+ const char *file;
+{
+ char *path = xmalloc (strlen (dir) + 1 + strlen(file) + 1);
+ sprintf (path, "%s\\%s", dir, file);
+ return path;
+}
+
+/* See cvs.h for description. */
+void
+expand_wild (argc, argv, pargc, pargv)
+ int argc;
+ char **argv;
+ int *pargc;
+ char ***pargv;
+{
+ int i;
+ int new_argc;
+ char **new_argv;
+ /* Allocated size of new_argv. We arrange it so there is always room for
+ one more element. */
+ int max_new_argc;
+
+ new_argc = 0;
+ /* Add one so this is never zero. */
+ max_new_argc = argc + 1;
+ new_argv = (char **) xmalloc (max_new_argc * sizeof (char *));
+ for (i = 0; i < argc; ++i)
+ {
+ HANDLE h;
+ WIN32_FIND_DATA fdata;
+
+ /* These variables help us extract the directory name from the
+ given pathname. */
+
+ char *last_forw_slash, *last_back_slash, *end_of_dirname;
+ int dirname_length = 0;
+
+ if ( strcmp( argv[i], "." ) == 0 )
+ {
+ new_argv[new_argc] = (char *) xmalloc ( 2 );
+ strcpy( new_argv[ new_argc++ ], "." );
+ continue;
+ }
+
+ /* FindFirstFile doesn't return pathnames, so we have to do
+ this ourselves. Luckily, it's no big deal, since globbing
+ characters under Win32s can only occur in the last segment
+ of the path. For example,
+ /a/path/q*.h valid
+ /w32/q*.dir/cant/do/this/q*.h invalid */
+
+ /* Win32 can handle both forward and backward slashes as
+ filenames -- check for both. */
+
+ last_forw_slash = strrchr (argv[i], '/');
+ last_back_slash = strrchr (argv[i], '\\');
+
+#define cvs_max(x,y) ((x >= y) ? (x) : (y))
+
+ /* FIXME: this comparing a NULL pointer to a non-NULL one is
+ extremely ugly, and I strongly suspect *NOT* sanctioned by
+ ANSI C. The code should just use last_component instead. */
+ end_of_dirname = cvs_max (last_forw_slash, last_back_slash);
+
+ if (end_of_dirname == NULL)
+ dirname_length = 0; /* no directory name */
+ else
+ dirname_length = end_of_dirname - argv[i] + 1; /* include slash */
+
+ h = FindFirstFile (argv[i], &fdata);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError () == ENOENT)
+ {
+ /* No match. The file specified didn't contain a wildcard (in which case
+ we clearly should return it unchanged), or it contained a wildcard which
+ didn't match (in which case it might be better for it to be an error,
+ but we don't try to do that). */
+ new_argv [new_argc++] = xstrdup (argv[i]);
+ if (new_argc == max_new_argc)
+ {
+ max_new_argc *= 2;
+ new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
+ }
+ }
+ else
+ {
+ error (1, errno, "cannot find %s", argv[i]);
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ new_argv[new_argc] =
+ (char *) xmalloc (strlen (fdata.cFileName) + 1
+ + dirname_length);
+
+ /* Copy the directory name, if there is one. */
+
+ if (dirname_length)
+ {
+ strncpy (new_argv[new_argc], argv[i], dirname_length);
+ new_argv[new_argc][dirname_length] = '\0';
+ }
+ else
+ new_argv[new_argc][0] = '\0';
+
+ /* Copy the file name. */
+
+ if (fncmp (argv[i] + dirname_length, fdata.cFileName) == 0)
+ /* We didn't expand a wildcard; we just matched a filename.
+ Use the file name as specified rather than the filename
+ which exists in the directory (they may differ in case).
+ This is needed to make cvs add on a directory consistently
+ use the name specified on the command line, but it is
+ probably a good idea in other contexts too. */
+ strcpy (new_argv[new_argc], argv[i]);
+ else
+ strcat (new_argv[new_argc], fdata.cFileName);
+
+ new_argc++;
+
+ if (new_argc == max_new_argc)
+ {
+ max_new_argc *= 2;
+ new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
+ }
+ if (!FindNextFile (h, &fdata))
+ {
+ if (GetLastError () == ERROR_NO_MORE_FILES)
+ break;
+ else
+ error (1, errno, "cannot find %s", argv[i]);
+ }
+ }
+ if (!FindClose (h))
+ error (1, GetLastError (), "cannot close %s", argv[i]);
+ }
+ }
+ *pargc = new_argc;
+ *pargv = new_argv;
+}
+
+/* undo config.h stat macro */
+#undef stat
+extern int stat (const char *file, struct wnt_stat *sb);
+
+/* see config.h stat macro */
+int
+wnt_stat (const char *file, struct wnt_stat *sb)
+{
+ int retval;
+
+ retval = stat (file, sb);
+ if (retval < 0)
+ return retval;
+
+ /* Win32 processes file times in a 64 bit format
+ (see Win32 functions SetFileTime and GetFileTime).
+ If the file time on a file doesn't fit into the
+ 32 bit time_t format, then stat will set that time
+ to -1. This would be OK, except that functions
+ like ctime() don't check for validity. So what we
+ do here is to give a error on -1. A cleaner solution
+ might be to change CVS's interfaces to return a time
+ in RCS format (for example), and then implement it
+ on Win32 via GetFileTime, but that would be a lot of
+ hair and I'm not sure there is much payoff. */
+ if (sb->st_mtime == (time_t) -1)
+ error (1, 0, "invalid modification time for %s", file);
+ if (sb->st_ctime == (time_t) -1)
+ /* I'm not sure what this means on windows. It
+ might be a creation time (unlike unix).... */
+ error (1, 0, "invalid ctime for %s", file);
+ if (sb->st_atime == (time_t) -1)
+ error (1, 0, "invalid access time for %s", file);
+
+ if (!GetUTCFileModTime (file, &sb->st_mtime))
+ error (1, 0, "Failed to retrieve modification time for %s", file);
+
+ return retval;
+}
diff --git a/windows-NT/fix-msvc-mak.pl b/windows-NT/fix-msvc-mak.pl
new file mode 100644
index 0000000..28c0cf0
--- /dev/null
+++ b/windows-NT/fix-msvc-mak.pl
@@ -0,0 +1,99 @@
+#! perl -w
+
+use strict;
+
+
+
+sub save_edit {
+ my ($found, $file_name, $temp_name) = @_;
+
+ if ($found <= 0) {
+ unlink $temp_name;
+ print "no change: ", $file_name, "\n";
+ } else {
+ rename $temp_name, $file_name;
+ print "save edit: ", $file_name, "\n";
+ }
+}
+
+
+
+sub fix_basetsd_dep {
+ my ($file_name) = @_;
+ my $temp_name = $file_name . ".tmp";
+
+ open FINP, "< " . $file_name or die "open error: ", $file_name;
+ open FOUT, "> " . $temp_name or die "open error: ", $temp_name;
+
+ my $found = 0;
+ while (<FINP>) {
+ if (/basetsd\.h/) {
+ $found += 1;
+ } else {
+ print FOUT $_;
+ }
+ }
+
+ close FOUT;
+ close FINP;
+
+ save_edit $found, $file_name, $temp_name;
+}
+
+
+
+sub fix_cvsnt_mak {
+ my $file_name = "cvsnt.mak";
+ my $temp_name = $file_name . ".tmp";
+
+ open FINP, "< " . $file_name or die "open error: ", $file_name;
+ open FOUT, "> " . $temp_name or die "open error: ", $temp_name;
+
+ my $found = 0;
+ while (<FINP>) {
+ if ($. == 2 && !/RECURSE/) {
+ $found += 1;
+ print FOUT qq/!IF "\$(RECURSE)" == ""\n/;
+ print FOUT "RECURSE=1\n";
+ print FOUT "!ENDIF\n";
+ }
+ print FOUT $_;
+ }
+
+ close FOUT;
+ close FINP;
+
+ save_edit $found, $file_name, $temp_name;
+}
+
+
+
+sub fix_libdiff_mak {
+ my $file_name = "diff/libdiff.mak";
+ my $temp_name = $file_name . ".tmp";
+
+ open FINP, "< " . $file_name or die "open error: ", $file_name;
+ open FOUT, "> " . $temp_name or die "open error: ", $temp_name;
+
+ my $found = 0;
+ while (<FINP>) {
+ if (/^[ \t]+cd[ \t]+"\\.*\\[Ll][Ii][Bb]"$/) {
+ $found += 1;
+ s/cd[ \t]+.*/cd "..\\lib"/;
+ }
+ print FOUT $_;
+ }
+
+ close FOUT;
+ close FINP;
+
+ save_edit $found, $file_name, $temp_name;
+}
+
+
+
+
+fix_basetsd_dep "cvsnt.dep";
+fix_basetsd_dep "lib/libcvs.dep";
+fix_cvsnt_mak;
+fix_libdiff_mak;
diff --git a/windows-NT/mkconfig.pl b/windows-NT/mkconfig.pl
new file mode 100644
index 0000000..3a478e4
--- /dev/null
+++ b/windows-NT/mkconfig.pl
@@ -0,0 +1,314 @@
+#! perl -w
+
+use strict;
+
+# For the `mv' function which is smart enough to cross device boundries.
+use File::Copy qw{mv};
+# For the `basename' function.
+use File::Basename;
+
+
+
+###
+### FUNCTIONS
+###
+sub save_edit
+{
+ my ($same, $file_name, $temp_name) = @_;
+
+ if ($same)
+ {
+ unlink $temp_name
+ or warn "Failed to unlink ", $temp_name, ": $!";
+ print "no change: ", $file_name, "\n";
+ }
+ else
+ {
+ mv $temp_name, $file_name
+ or die "Failed to rename ", $temp_name, " to ", $file_name, ": $!";
+
+ print "save edit: ", $file_name, "\n";
+ }
+}
+
+sub get_default
+{
+ my ($value, $default) = @_;
+
+ if ($value eq "")
+ {
+ $value = $default;
+ }
+
+ return $value;
+}
+
+
+
+sub show_repeat
+{
+ my ($file, $new_no, $old_no, $line) = @_;
+
+ print $file, " line ", $new_no, " duplicates line ", $old_no, ": ", $line;
+}
+
+
+
+sub show_orphan
+{
+ my ($case, $that, $this, $this_key, %this_macros) = @_;
+ my $type = $this_macros{$this_key}[1];
+
+ if ($case eq 0)
+ {
+ # roots file has extra macro statement
+ # tell only of #undef
+ return if $type eq "d";
+ }
+ elsif ($case eq 1)
+ {
+ # build file has extra macro statement
+ # tell only of #define
+ return if $type eq "u";
+ }
+ else
+ {
+ die "Internal script error";
+ }
+
+ if ($type eq "d")
+ {
+ $type = "#define";
+ }
+ elsif ($type eq "u")
+ {
+ $type = "#undef";
+ }
+ else
+ {
+ die "Internal script error";
+ }
+
+ print $this, " line ", $this_macros{$this_key}[0], " has ", $type, " ",
+ $this_key, " not found in ", $that, "\n";
+}
+
+
+
+sub make_config_h
+{
+ my $quiet;
+ if ($_[0] eq "-q")
+ {
+ $quiet = 1;
+ shift;
+ }
+
+ my ($ph_name, $out_name, $inp_name, $end_name) = @_;
+
+ $ph_name = get_default $ph_name, "../config.h.in";
+ $out_name = get_default $out_name, "config.h.in";
+ $inp_name = get_default $inp_name, $out_name . ".in";
+ $end_name = get_default $end_name, $out_name . ".footer";
+
+ print STDERR "($inp_name + $ph_name) . $end_name --> $out_name\n"
+ if !$quiet;
+
+ #==========================================================================
+ # scan build level configuration to collect define/undef values
+ #==========================================================================
+
+ open FINP, "< $inp_name"
+ or die "error opening ", $inp_name, " for read: $!";
+ my %build_macros;
+ while (<FINP>)
+ {
+ if (/^#\s*define\s*(\w+)(\s+(.+))?$/)
+ {
+ if (exists $build_macros{$1})
+ {
+ show_repeat $inp_name, $., $build_macros{$1}[0], $_;
+ }
+ else
+ {
+ $build_macros{$1} = [$., "d", $3];
+ }
+ }
+ elsif (/^\s*#\s*undef\s+(\w+)/)
+ {
+ if (exists $build_macros{$1})
+ {
+ show_repeat $inp_name, $., $build_macros{$1}[0], $_;
+ }
+ else
+ {
+ $build_macros{$1} = [$., "u"];
+ }
+ }
+ }
+ close FINP;
+ #==========================================================================
+
+ #==========================================================================
+ # temporary output file
+ #==========================================================================
+ my $temp_name = basename($out_name) . ".tmp";
+
+ open FOUT, "> $temp_name"
+ or die "error opening ", $temp_name, " for write: $!";
+
+ #==========================================================================
+ # copy build level configuration append file to output file
+ #==========================================================================
+ my $base_out = basename $out_name;
+ my $base_prog = basename $0;
+ my $base_inp = basename $inp_name;
+ my $base_ph = basename $ph_name;
+ my $base_end = basename $end_name;
+
+ print FOUT <<EOF;
+/***
+ *** $base_out, generated by $base_prog:
+ ***
+ *** ($base_inp
+ *** + ../$base_ph)
+ *** . $base_end
+ *** --> $base_out
+ ***
+ *** ***** DO NOT ALTER THIS FILE!!! *****
+ ***
+ *** Changes to this file will be overwritten by automatic script runs.
+ *** Changes should be made to the $base_inp & $base_end
+ *** files instead.
+ ***/
+
+EOF
+
+ #==========================================================================
+ # copy root level configuration to output file
+ # while keeping track of conditional compile nesting level
+ #==========================================================================
+ open FINP, "< $ph_name"
+ or die "error opening ", $ph_name, " for read: $!";
+ my %ph_macros;
+ while (<FINP>)
+ {
+
+ my $out_line = $_;
+
+ if (/^\s*#\s*undef\s+(\w+)/)
+ {
+ if (exists $ph_macros{$1})
+ {
+ show_repeat $ph_name, $., $ph_macros{$1}[0], $_;
+ }
+ else
+ {
+ $ph_macros{$1} = [$., "u"];
+ }
+
+ if (exists $build_macros{$1}
+ and $build_macros{$1}[1] eq "d")
+ {
+ $out_line = "#define $1";
+
+ $out_line .= " " . $build_macros{$1}[2]
+ if defined $build_macros{$1}[2];
+
+ $out_line .= "\n";
+ }
+ }
+ print FOUT $out_line;
+ }
+ close FINP;
+ #==========================================================================
+
+ #==========================================================================
+ # copy build level configuration append file to output file
+ #==========================================================================
+ if (open FINP, "< $end_name")
+ {
+ while (<FINP>)
+ {
+ print FOUT $_;
+ }
+ close FINP;
+ }
+ #==========================================================================
+ close FOUT;
+ #==========================================================================
+
+ #==========================================================================
+ # determine whether output (if any) has changed from last run
+ #==========================================================================
+ my $same = 0;
+
+ if (open FINP, "< $out_name")
+ {
+ open FOUT, "< $temp_name"
+ or die "error opening ", $temp_name, " for read: $!";
+
+ $same = 1;
+ while ($same)
+ {
+ last if eof FINP and eof FOUT;
+ if (eof FINP or eof FOUT or <FINP> ne <FOUT>)
+ {
+ $same = 0;
+ last;
+ }
+ }
+ close FOUT;
+ close FINP;
+ }
+
+ #==========================================================================
+ # nag the guilty
+ #==========================================================================
+ my @keys_build = sort keys %build_macros;
+ my @keys_roots = sort keys %ph_macros;
+ my ($idx_build, $idx_roots) = (0, 0);
+ while ($idx_build < @keys_build or $idx_roots < @keys_roots) {
+ if ($idx_build >= @keys_build)
+ {
+ show_orphan 0, $inp_name, $ph_name, $keys_roots[$idx_roots],
+ %ph_macros;
+ $idx_roots++;
+ }
+ elsif ($idx_roots >= @keys_roots)
+ {
+ show_orphan 1, $ph_name, $inp_name, $keys_build[$idx_build],
+ %build_macros;
+ $idx_build++;
+ }
+ elsif ($keys_build[$idx_build] gt $keys_roots[$idx_roots])
+ {
+ show_orphan 0, $inp_name, $ph_name, $keys_roots[$idx_roots],
+ %ph_macros;
+ $idx_roots++;
+ }
+ elsif ($keys_roots[$idx_roots] gt $keys_build[$idx_build])
+ {
+ show_orphan 1, $ph_name, $inp_name, $keys_build[$idx_build],
+ %build_macros;
+ $idx_build++;
+ }
+ else
+ {
+ $idx_build++;
+ $idx_roots++;
+ }
+ }
+
+ #==========================================================================
+ # save output only if changed
+ #==========================================================================
+ save_edit $same, $out_name, $temp_name;
+}
+
+
+
+###
+### MAIN
+###
+make_config_h @ARGV;
diff --git a/windows-NT/mkdir.c b/windows-NT/mkdir.c
new file mode 100644
index 0000000..cd17f74
--- /dev/null
+++ b/windows-NT/mkdir.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* mkdir.c --- mkdir for Windows NT
+ Jim Blandy <jimb@cyclic.com> --- July 1995 */
+
+#include <assert.h>
+
+#include "cvs.h"
+
+#undef mkdir
+
+int
+wnt_mkdir (const char *path, int mode)
+{
+ /* This is true for all extant calls to CVS_MKDIR. If
+ someone adds a call that uses something else later,
+ we should tweak this function to handle that. */
+ assert (mode == 0777);
+
+ return mkdir (path);
+}
diff --git a/windows-NT/ndir.c b/windows-NT/ndir.c
new file mode 100644
index 0000000..8b32e4f
--- /dev/null
+++ b/windows-NT/ndir.c
@@ -0,0 +1,214 @@
+/* msd_dir.c - portable directory routines
+ Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* Everything non trivial in this code is from: @(#)msd_dir.c 1.4
+ 87/11/06. A public domain implementation of BSD directory routines
+ for MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
+ August 1897 */
+
+
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dos.h>
+
+#include <ndir.h>
+#include "xalloc.h"
+
+static void free_dircontents (struct _dircontents *);
+
+/* find ALL files! */
+#define ATTRIBUTES (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR)
+
+
+
+DIR *
+opendir (const char *name)
+{
+ struct _finddata_t find_buf;
+ DIR *dirp;
+ struct _dircontents *dp;
+ char name_buf[_MAX_PATH + 1];
+ char *slash = "";
+ long hFile;
+
+ if (!name)
+ name = "";
+ else if (*name)
+ {
+ const char *s;
+ int l = strlen (name);
+
+ s = name + l - 1;
+ if ( !(l == 2 && *s == ':') && *s != '\\' && *s != '/')
+ slash = "/"; /* save to insert slash between path and "*.*" */
+ }
+
+ strcat (strcat (strcpy (name_buf, name), slash), "*.*");
+
+ dirp = xmalloc (sizeof (DIR));
+ if (!dirp) return NULL;
+
+ dirp->dd_loc = 0;
+ dirp->dd_contents = dirp->dd_cp = NULL;
+
+ if ((hFile = _findfirst (name_buf, &find_buf)) < 0)
+ {
+ free (dirp);
+ return NULL;
+ }
+
+ do
+ {
+ dp = xmalloc (sizeof (struct _dircontents));
+ if (!dp)
+ {
+ free_dircontents (dirp->dd_contents);
+ return NULL;
+ }
+
+ dp->_d_entry = xmalloc (strlen (find_buf.name) + 1);
+ if (!dp->_d_entry)
+ {
+ free (dp);
+ free_dircontents (dirp->dd_contents);
+ return NULL;
+ }
+
+ if (dirp->dd_contents)
+ dirp->dd_cp = dirp->dd_cp->_d_next = dp;
+ else
+ dirp->dd_contents = dirp->dd_cp = dp;
+
+ strcpy (dp->_d_entry, find_buf.name);
+
+ dp->_d_next = NULL;
+
+ } while (!_findnext (hFile, &find_buf));
+
+ dirp->dd_cp = dirp->dd_contents;
+
+ _findclose(hFile);
+
+ return dirp;
+}
+
+
+void
+closedir (DIR *dirp)
+{
+ free_dircontents (dirp->dd_contents);
+ free (dirp);
+}
+
+
+struct direct *
+readdir (DIR *dirp)
+{
+ static struct direct dp;
+
+ if (!dirp->dd_cp) return NULL;
+ dp.d_namlen = dp.d_reclen =
+ strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
+#if 0 /* JB */
+ strlwr (dp.d_name); /* JF */
+#endif
+ dp.d_ino = 0;
+ dirp->dd_cp = dirp->dd_cp->_d_next;
+ dirp->dd_loc++;
+
+ return &dp;
+}
+
+
+void
+seekdir (DIR *dirp, long off)
+{
+ long i = off;
+ struct _dircontents *dp;
+
+ if (off < 0)
+ return;
+ for (dp = dirp->dd_contents; --i >= 0 && dp; dp = dp->_d_next)
+ ;
+ dirp->dd_loc = off - (i + 1);
+ dirp->dd_cp = dp;
+}
+
+
+long
+telldir (DIR *dirp)
+{
+ return dirp->dd_loc;
+}
+
+
+/* Garbage collection */
+
+static void
+free_dircontents (struct _dircontents *dp)
+{
+ struct _dircontents *odp;
+
+ while (dp)
+ {
+ if (dp->_d_entry)
+ free (dp->_d_entry);
+ dp = (odp = dp)->_d_next;
+ free (odp);
+ }
+}
+
+
+#ifdef TEST
+
+void main (int argc, char *argv[]);
+
+void
+main (int argc, char *argv[])
+{
+ static DIR *directory;
+ struct direct *entry = NULL;
+
+ char *name = "";
+
+ if (argc > 1)
+ name = argv[1];
+
+ directory = opendir (name);
+
+ if (!directory)
+ {
+ fprintf (stderr, "can't open directory `%s'.\n", name);
+ exit (2);
+ }
+
+ while (entry = readdir (directory))
+ printf ("> %s\n", entry->d_name);
+
+ printf ("done.\n");
+}
+
+#endif /* TEST */
+
+/*
+ * Local Variables:
+ * mode:C
+ * ChangeLog:ChangeLog
+ * compile-command:make
+ * End:
+ */
diff --git a/windows-NT/ndir.h b/windows-NT/ndir.h
new file mode 100644
index 0000000..a498058
--- /dev/null
+++ b/windows-NT/ndir.h
@@ -0,0 +1,62 @@
+/* ndir.c - portable directory routines
+ Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* Everything non trivial in this code is taken from: @(#)msd_dir.c 1.4
+ 87/11/06. A public domain implementation of BSD directory routines
+ for MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
+ August 1897 */
+
+#include <sys/types.h> /* ino_t definition */
+
+#define rewinddir(dirp) seekdir(dirp, 0L)
+
+/* 255 is said to be big enough for Windows NT. The more elegant
+ solution would be declaring d_name as one byte long and allocating
+ it to the actual size needed. */
+#define MAXNAMLEN 255
+
+struct direct
+{
+ ino_t d_ino; /* a bit of a farce */
+ int d_reclen; /* more farce */
+ int d_namlen; /* length of d_name */
+ char d_name[MAXNAMLEN + 1]; /* garentee null termination */
+};
+
+struct _dircontents
+{
+ char *_d_entry;
+ struct _dircontents *_d_next;
+};
+
+typedef struct _dirdesc
+{
+ int dd_id; /* uniquely identify each open directory */
+ long dd_loc; /* where we are in directory entry is this */
+ struct _dircontents *dd_contents; /* pointer to contents of dir */
+ struct _dircontents *dd_cp; /* pointer to current position */
+} DIR;
+
+void seekdir (DIR *, long);
+long telldir (DIR *);
+DIR *opendir (const char *);
+void closedir (DIR *);
+struct direct *readdir (DIR *);
+
+/*
+ * Local Variables:
+ * mode:C
+ * ChangeLog:ChangeLog
+ * compile-command:make
+ * End:
+ */
diff --git a/windows-NT/netdb.h b/windows-NT/netdb.h
new file mode 100644
index 0000000..fa882cb
--- /dev/null
+++ b/windows-NT/netdb.h
@@ -0,0 +1 @@
+/* empty file */
diff --git a/windows-NT/netinet/in.h b/windows-NT/netinet/in.h
new file mode 100644
index 0000000..fa882cb
--- /dev/null
+++ b/windows-NT/netinet/in.h
@@ -0,0 +1 @@
+/* empty file */
diff --git a/windows-NT/pwd.c b/windows-NT/pwd.c
new file mode 100644
index 0000000..36e6148
--- /dev/null
+++ b/windows-NT/pwd.c
@@ -0,0 +1,207 @@
+/* pwd.c - Try to approximate UN*X's getuser...() functions under MS-DOS.
+ Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This 'implementation' is conjectured from the use of this functions in
+ the RCS and BASH distributions. Of course these functions don't do too
+ much useful things under MS-DOS, but using them avoids many "#ifdef
+ MSDOS" in ported UN*X code ... */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "pwd.h"
+#include "xalloc.h"
+
+static char *lookup_env (char **);
+
+/* where people might scribble their name into the environment ... */
+
+static char *login_strings[] =
+{
+ "LOGIN", "USER", "MAILNAME", "USERNAME", NULL
+};
+
+static char *group_strings[] =
+{
+ "GROUP", NULL
+};
+
+
+static char *anonymous = "anonymous"; /* if all else fails ... */
+
+static char *login = NULL;/* cache the names here */
+static char *group = NULL;
+
+static struct passwd pw; /* should we return a malloc()'d structure */
+static struct group gr; /* instead of pointers to static structures? */
+
+/* implement limited uid behavior */
+#define my_fake_uid ((const uid_t) 4545)
+#define my_fake_gid my_fake_uid
+
+/* return something like a username in a (butchered!) passwd structure. */
+struct passwd *
+getpwuid (int uid)
+{
+ pw.pw_name = getlogin ();
+ pw.pw_dir = woe32_home_dir ();
+ pw.pw_shell = woe32_shell ();
+ pw.pw_uid = 0;
+
+ return &pw;
+}
+
+struct passwd *
+getpwnam (const char *name)
+{
+ return NULL;
+}
+
+/* return something like a groupname in a (butchered!) group structure. */
+struct group *
+getgrgid (int uid)
+{
+ gr.gr_name = getgr_name ();
+ gr.gr_gid = 0;
+
+ return &gr;
+}
+
+struct group *
+getgrnam (const char *name)
+{
+ return NULL;
+}
+
+/* return something like a username. */
+char *
+getlogin (void)
+{
+ /* This is how a windows user would override their login name. */
+ if (!login)
+ login = lookup_env (login_strings);
+
+ /* In the absence of user override, ask the operating system. */
+ if (!login)
+ login = woe32_getlogin ();
+
+ /* If all else fails, fall back on Old Faithful. */
+ if (!login)
+ login = anonymous;
+
+ return login;
+}
+
+/* return something like a group. */
+char *
+getgr_name (void)
+{
+ if (!group) /* have we been called before? */
+ group = lookup_env (group_strings);
+
+ if (!group) /* have we been successful? */
+ group = anonymous;
+
+ return group;
+}
+
+/* return something like a uid. */
+uid_t
+getuid (void)
+{
+ return my_fake_uid;
+}
+
+gid_t
+getgid (void)
+{
+ return my_fake_gid;
+}
+
+uid_t
+geteuid (void)
+{
+ return my_fake_uid;
+}
+
+gid_t
+getegid (void)
+{
+ return my_fake_gid;
+}
+
+struct passwd *
+getpwent (void)
+{
+ return NULL;
+}
+
+void
+setpwent (void)
+{
+}
+
+void
+endpwent (void)
+{
+}
+
+void
+endgrent (void)
+{
+}
+
+/* return groups. */
+int
+getgroups (int ngroups, gid_t *groups)
+{
+ if (ngroups > 0)
+ *groups = my_fake_gid;
+ return 1;
+}
+
+/* lookup environment. */
+static char *
+lookup_env (char *table[])
+{
+ char *ptr;
+ char *entry;
+ size_t len;
+
+ while (*table && !(ptr = getenv (*table++))) ; /* scan table */
+
+ if (!ptr) return NULL;
+
+ len = strcspn (ptr, " \n\t\n\r"); /* any WS? */
+ if (!(entry = xmalloc (len + 1)))
+ {
+ fprintf (stderr, "Out of memory.\nStop.");
+ exit (-1);
+ }
+
+ strncpy (entry, ptr, len);
+ entry[len] = '\0';
+
+ return entry;
+
+}
+
+/*
+ * Local Variables:
+ * mode:C
+ * ChangeLog:ChangeLog
+ * compile-command:make
+ * End:
+ */
diff --git a/windows-NT/pwd.h b/windows-NT/pwd.h
new file mode 100644
index 0000000..05abce6
--- /dev/null
+++ b/windows-NT/pwd.h
@@ -0,0 +1,67 @@
+/* pwd.h - Try to approximate UN*X's getuser...() functions under MS-DOS.
+ Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+/* This 'implementation' is conjectured from the use of this functions in
+ the RCS and BASH distributions. Of course these functions don't do too
+ much useful things under MS-DOS, but using them avoids many "#ifdef
+ MSDOS" in ported UN*X code ... */
+
+#include <sys/types.h>
+
+struct passwd
+{
+ /* ... */
+ /* missing stuff */
+ /* ... */
+ char *pw_name; /* login user id */
+ char *pw_dir; /* home directory */
+ char *pw_shell; /* login shell */
+ int pw_uid;
+};
+
+struct group
+{
+ /* ... */
+ /* missing stuff */
+ /* ... */
+ char *gr_name; /* login user id */
+ int gr_gid;
+};
+
+struct passwd *getpwuid (uid_t);
+struct passwd *getpwnam (const char *);
+struct group *getgrgid (gid_t);
+struct group *getgrnam (const char *);
+char *getlogin (void);
+char *getgr_name (void);
+uid_t getuid (void);
+gid_t getgid (void);
+uid_t geteuid (void);
+gid_t getegid (void);
+
+extern int *groups;
+extern int ngroups;
+int getgroups (int, gid_t *);
+
+struct passwd *getpwent (void);
+void setpwent (void);
+void endpwent (void);
+void endgrent (void);
+
+/*
+ * Local Variables:
+ * mode:C
+ * ChangeLog:ChangeLog
+ * compile-command:make
+ * End:
+ */
diff --git a/windows-NT/rcmd.c b/windows-NT/rcmd.c
new file mode 100644
index 0000000..33da637
--- /dev/null
+++ b/windows-NT/rcmd.c
@@ -0,0 +1,190 @@
+/* rcmd.c --- execute a command on a remote host from Windows NT
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Jim Blandy <jimb@cyclic.com> --- August 1995 */
+
+#include "cvs.h"
+#include "rcmd.h"
+
+#include <io.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+
+#include <stdio.h>
+#include <assert.h>
+
+/* The rest of this file contains the rcmd() code, which is used
+ only by START_SERVER. The idea for a long-term direction is
+ that this code can be made portable (by using SOCK_ERRNO and
+ so on), and then moved to client.c or someplace it can be
+ shared with the VMS port and any other ports which may want it. */
+
+
+static int
+resolve_address (const char **ahost, struct sockaddr_in *sai)
+{
+ {
+ unsigned long addr = inet_addr (*ahost);
+
+ if (addr != (unsigned long) -1)
+ {
+ sai->sin_family = AF_INET;
+ sai->sin_addr.s_addr = addr;
+ return 0;
+ }
+ }
+
+ {
+ struct hostent *e = gethostbyname (*ahost);
+
+ if (e)
+ {
+ assert (e->h_addrtype == AF_INET);
+ assert (e->h_addr);
+ *ahost = e->h_name;
+ sai->sin_family = AF_INET;
+ memcpy (&sai->sin_addr, e->h_addr, sizeof (sai->sin_addr));
+ return 0;
+ }
+ }
+
+ error (1, 0, "no such host %s", *ahost);
+ /* Shut up gcc -Wall. */
+ return 1;
+}
+
+static SOCKET
+bind_and_connect (struct sockaddr_in *server_sai)
+{
+ SOCKET s;
+ struct sockaddr_in client_sai;
+ u_short client_port;
+
+ client_sai.sin_family = AF_INET;
+ client_sai.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ for (client_port = IPPORT_RESERVED - 1;
+ client_port >= IPPORT_RESERVED/2;
+ client_port--)
+ {
+ int result, errcode;
+ client_sai.sin_port = htons (client_port);
+
+ if ((s = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ error (1, 0, "cannot create socket: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+
+ result = bind (s, (struct sockaddr *) &client_sai,
+ sizeof (client_sai));
+ errcode = SOCK_ERRNO;
+ if (result == SOCKET_ERROR)
+ {
+ closesocket (s);
+ if (errcode == WSAEADDRINUSE)
+ continue;
+ else
+ error (1, 0, "cannot bind to socket: %s",
+ SOCK_STRERROR (errcode));
+ }
+
+ result = connect (s, (struct sockaddr *) server_sai,
+ sizeof (*server_sai));
+ errcode = SOCK_ERRNO;
+ if (result == SOCKET_ERROR)
+ {
+ closesocket (s);
+ if (errcode == WSAEADDRINUSE)
+ continue;
+ else
+ error (1, 0, "cannot connect to socket: %s",
+ SOCK_STRERROR (errcode));
+ }
+
+ return s;
+ }
+
+ error (1, 0, "cannot find free port");
+ /* Shut up gcc -Wall. */
+ return s;
+}
+
+static int
+rcmd_authenticate (int fd, char *locuser, char *remuser, char *command)
+{
+ /* Send them a bunch of information, each terminated by '\0':
+ - secondary stream port number (we don't use this)
+ - username on local machine
+ - username on server machine
+ - command
+ Now, the Ultrix man page says you transmit the username on the
+ server first, but that doesn't seem to work. Transmitting the
+ client username first does. Go figure. The Linux man pages
+ get it right --- hee hee. */
+ if ((send (fd, "0\0", 2, 0) == SOCKET_ERROR)
+ || (send (fd, locuser, strlen (locuser) + 1, 0) == SOCKET_ERROR)
+ || (send (fd, remuser, strlen (remuser) + 1, 0) == SOCKET_ERROR)
+ || (send (fd, command, strlen (command) + 1, 0) == SOCKET_ERROR))
+ error (1, 0, "cannot send authentication info to rshd: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+
+ /* They sniff our butt, and send us a '\0' character if they
+ like us. */
+ {
+ char c;
+ if (recv (fd, &c, 1, 0) == SOCKET_ERROR)
+ {
+ error (1, 0, "cannot receive authentication info from rshd: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+ }
+ if (c != '\0')
+ {
+ /* All the junk with USER, LOGNAME, GetUserName, &c, is so
+ confusing that we better give some clue as to what sort
+ of user name we decided on. */
+ error (0, 0, "cannot log in as local user '%s', remote user '%s'",
+ locuser, remuser);
+ error (1, 0, "Permission denied by rshd");
+ }
+ }
+
+ return 0;
+}
+
+int
+rcmd (const char **ahost,
+ unsigned short inport,
+ char *locuser,
+ char *remuser,
+ char *cmd,
+ int *fd2p)
+{
+ struct sockaddr_in sai;
+ SOCKET s;
+
+ assert (fd2p == 0);
+
+ if (resolve_address (ahost, &sai) < 0)
+ error (1, 0, "internal error: resolve_address < 0");
+
+ sai.sin_port = htons (inport);
+
+ if ((s = bind_and_connect (&sai)) == INVALID_SOCKET)
+ error (1, 0, "internal error: bind_and_connect < 0");
+
+ if (rcmd_authenticate (s, locuser, remuser, cmd) < 0)
+ error (1, 0, "internal error: rcmd_authenticate < 0");
+
+ return s;
+}
diff --git a/windows-NT/rcmd.h b/windows-NT/rcmd.h
new file mode 100644
index 0000000..d2516a8
--- /dev/null
+++ b/windows-NT/rcmd.h
@@ -0,0 +1,30 @@
+/* rcmd.h --- interface to executing commands on remote hosts
+ Jim Blandy <jimb@cyclic.com> --- August 1995 */
+
+/* Run the command CMD on the host *AHOST, and return a file descriptor for
+ a bidirectional stream socket connected to the command's standard input
+ and output.
+
+ rcmd looks up *AHOST using gethostbyname, and sets *AHOST to the host's
+ canonical name. If *AHOST is not found, rcmd returns -1.
+
+ rcmd connects to the remote host at TCP port INPORT. This should
+ probably be the "shell" service, port 514.
+
+ LOCUSER is the name of the user on the local machine, and REMUSER is
+ the name of the user on the remote machine; the remote machine uses this,
+ along with the source address of the TCP connection, to authenticate
+ the connection.
+
+ CMD is the command to execute. The remote host will tokenize it any way
+ it damn well pleases. Welcome to Unix.
+
+ FD2P is a feature we don't support, but there's no point in making mindless
+ deviations from the interface. Callers should always pass this argument
+ as zero. */
+extern int rcmd (const char **AHOST,
+ unsigned short INPORT,
+ char *LOCUSER,
+ char *REMUSER,
+ char *CMD,
+ int *fd2p);
diff --git a/windows-NT/run.c b/windows-NT/run.c
new file mode 100644
index 0000000..404ef1c
--- /dev/null
+++ b/windows-NT/run.c
@@ -0,0 +1,721 @@
+/* run.c --- routines for executing subprocesses under Windows NT.
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include "cvs.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdlib.h>
+#include <process.h>
+#include <errno.h>
+#include <io.h>
+#include <fcntl.h>
+
+
+
+/*
+ * To exec a program under CVS, first call run_setup() to setup any initial
+ * arguments. The options to run_setup are essentially like printf(). The
+ * arguments will be parsed into whitespace separated words and added to the
+ * global run_argv list.
+ *
+ * Then, optionally call run_arg() for each additional argument that you'd like
+ * to pass to the executed program.
+ *
+ * Finally, call run_exec() to execute the program with the specified arguments.
+ * The execvp() syscall will be used, so that the PATH is searched correctly.
+ * File redirections can be performed in the call to run_exec().
+ */
+static char **run_argv;
+static int run_argc;
+static size_t run_arg_allocated;
+
+
+
+void
+run_arg_free_p (int argc, char **argv)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ free (argv[i]);
+}
+
+
+
+/* VARARGS */
+void
+run_setup (const char *prog)
+{
+ char *cp;
+ int i;
+
+ char *run_prog;
+
+ /* clean out any malloc'ed values from run_argv */
+ for (i = 0; i < run_argc; i++)
+ {
+ if (run_argv[i])
+ {
+ free (run_argv[i]);
+ run_argv[i] = (char *) 0;
+ }
+ }
+ run_argc = 0;
+
+ run_prog = xstrdup (prog);
+
+ /* put each word into run_argv, allocating it as we go */
+ for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
+ run_add_arg (cp);
+
+ free (run_prog);
+}
+
+
+
+/* Return a malloc'd copy of s, with double quotes around it. */
+static char *
+quote (const char *s)
+{
+ size_t s_len = 0;
+ char *copy = NULL;
+ char *scan = (char *) s;
+
+ /* scan string for extra quotes ... */
+ while (*scan)
+ if ('"' == *scan++)
+ s_len += 2; /* one extra for the quote character */
+ else
+ s_len++;
+ /* allocate length + byte for ending zero + for double quotes around */
+ scan = copy = xmalloc(s_len + 3);
+ *scan++ = '"';
+ while (*s)
+ {
+ if ('"' == *s)
+ *scan++ = '\\';
+ *scan++ = *s++;
+ }
+ /* ending quote and closing zero */
+ *scan++ = '"';
+ *scan++ = '\0';
+ return copy;
+}
+
+
+
+void
+run_add_arg_p (int *iargc, size_t *iarg_allocated, char ***iargv,
+ const char *s)
+{
+ /* allocate more argv entries if we've run out */
+ if (*iargc >= *iarg_allocated)
+ {
+ *iarg_allocated += 50;
+ *iargv = xnrealloc (*iargv, *iarg_allocated, sizeof (char **));
+ }
+
+ if (s)
+ (*iargv)[(*iargc)++] = xstrdup (s);
+ else
+ (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */
+}
+
+
+
+void
+run_add_arg (const char *s)
+{
+ run_add_arg_p (&run_argc, &run_arg_allocated, &run_argv, s);
+}
+
+
+
+int
+run_exec (const char *stin, const char *stout, const char *sterr, int flags)
+{
+ int shin, shout, sherr;
+ int sain, saout, saerr; /* saved handles */
+ int mode_out, mode_err;
+ int status = -1;
+ int rerrno = 0;
+ int rval = -1;
+ void (*old_sigint) (int);
+
+ if (trace) /* if in trace mode */
+ {
+ (void) fprintf (stderr, "-> system(");
+ run_print (stderr);
+ (void) fprintf (stderr, ")\n");
+ }
+
+ /* Flush standard output and standard error, or otherwise we end
+ up with strange interleavings of stuff called from CYGWIN
+ vs. CMD. */
+
+ fflush (stderr);
+ fflush (stdout);
+
+ if (noexec && (flags & RUN_REALLY) == 0) /* if in noexec mode */
+ return (0);
+
+ /*
+ * start the engine and take off
+ */
+
+ /* make sure that we are null terminated, since we didn't calloc */
+ run_add_arg ((char *) 0);
+
+ /* setup default file descriptor numbers */
+ shin = 0;
+ shout = 1;
+ sherr = 2;
+
+ /* set the file modes for stdout and stderr */
+ mode_out = mode_err = O_WRONLY | O_CREAT;
+ mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
+ mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
+
+ /* open the files as required, shXX are shadows of stdin... */
+ if (stin && (shin = open (stin, O_RDONLY)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for reading (prog %s)",
+ stin, run_argv[0]);
+ goto out0;
+ }
+ if (stout && (shout = open (stout, mode_out, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ stout, run_argv[0]);
+ goto out1;
+ }
+ if (sterr && (flags & RUN_COMBINED) == 0)
+ {
+ if ((sherr = open (sterr, mode_err, 0666)) == -1)
+ {
+ rerrno = errno;
+ error (0, errno, "cannot open %s for writing (prog %s)",
+ sterr, run_argv[0]);
+ goto out2;
+ }
+ }
+ /* now save the standard handles */
+ sain = saout = saerr = -1;
+ sain = dup( 0); /* dup stdin */
+ saout = dup( 1); /* dup stdout */
+ saerr = dup( 2); /* dup stderr */
+
+ /* the new handles will be dup'd to the standard handles
+ * for the spawn.
+ */
+
+ if (shin != 0)
+ {
+ (void) dup2 (shin, 0);
+ (void) close (shin);
+ }
+ if (shout != 1)
+ {
+ (void) dup2 (shout, 1);
+ (void) close (shout);
+ }
+ if (flags & RUN_COMBINED)
+ (void) dup2 (1, 2);
+ else if (sherr != 2)
+ {
+ (void) dup2 (sherr, 2);
+ (void) close (sherr);
+ }
+
+ /* Ignore signals while we're running this. */
+ old_sigint = signal (SIGINT, SIG_IGN);
+
+ /* dup'ing is done. try to run it now */
+ rval = spawnvp ( P_WAIT, run_argv[0], run_argv);
+
+ /* Restore signal handling. */
+ signal (SIGINT, old_sigint);
+
+ /* restore the original file handles */
+ if (sain != -1) {
+ (void) dup2( sain, 0); /* re-connect stdin */
+ (void) close( sain);
+ }
+ if (saout != -1) {
+ (void) dup2( saout, 1); /* re-connect stdout */
+ (void) close( saout);
+ }
+ if (saerr != -1) {
+ (void) dup2( saerr, 2); /* re-connect stderr */
+ (void) close( saerr);
+ }
+
+ /* Flush standard output and standard error, or otherwise we end
+ up with strange interleavings of stuff called from CYGWIN
+ vs. CMD. */
+
+ fflush (stderr);
+ fflush (stdout);
+
+ /* Recognize the return code for an interrupted subprocess. */
+ if (rval == CONTROL_C_EXIT)
+ return 2;
+ else
+ return rval; /* end, if all went coorect */
+
+ /* error cases */
+ /* cleanup the open file descriptors */
+ out2:
+ if (stout)
+ (void) close (shout);
+ out1:
+ if (stin)
+ (void) close (shin);
+
+ out0:
+ if (rerrno)
+ errno = rerrno;
+ return (status);
+}
+
+void
+run_print (FILE *fp)
+{
+ int i;
+
+ for (i = 0; i < run_argc; i++)
+ {
+ (void) fprintf (fp, "'%s'", run_argv[i]);
+ if (i != run_argc - 1)
+ (void) fprintf (fp, " ");
+ }
+}
+
+static char *
+requote (const char *cmd)
+{
+ char *requoted = xmalloc (strlen (cmd) + 1);
+ char *p = requoted;
+
+ strcpy (requoted, cmd);
+ while ((p = strchr (p, '\'')) != NULL)
+ {
+ *p++ = '"';
+ }
+
+ return requoted;
+}
+
+FILE *
+run_popen (const char *cmd, const char *mode)
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> run_popen(%s,%s)\n",
+ (server_active) ? 'S' : ' ', cmd, mode);
+#else
+ (void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode);
+#endif
+ if (noexec)
+ return (NULL);
+
+ /* If the command string uses single quotes, turn them into
+ double quotes. */
+ {
+ char *requoted = requote (cmd);
+ /* Save and restore our file descriptors to work around
+ apparent bugs in _popen. We are perhaps better off using
+ the win32 functions instead of _popen. */
+ int old_stdin = dup (STDIN_FILENO);
+ int old_stdout = dup (STDOUT_FILENO);
+ int old_stderr = dup (STDERR_FILENO);
+
+ FILE *result = popen (requoted, mode);
+
+ dup2 (old_stdin, STDIN_FILENO);
+ dup2 (old_stdout, STDOUT_FILENO);
+ dup2 (old_stderr, STDERR_FILENO);
+ close (old_stdin);
+ close (old_stdout);
+ close (old_stderr);
+
+ free (requoted);
+ return result;
+ }
+}
+
+
+/* Running children with pipes connected to them. */
+
+/* It's kind of ridiculous the hoops we're jumping through to get
+ this working. _pipe and dup2 and _spawnmumble work just fine, except
+ that the child inherits a file descriptor for the writing end of the
+ pipe, and thus will never receive end-of-file on it. If you know of
+ a better way to implement the piped_child function, please let me know.
+
+ You can apparently specify _O_NOINHERIT when you open a file, but there's
+ apparently no fcntl function, so you can't change that bit on an existing
+ file descriptor. */
+
+/* Given a handle, make an inheritable duplicate of it, and close
+ the original. */
+static HANDLE
+inheritable (HANDLE in)
+{
+ HANDLE copy;
+ HANDLE self = GetCurrentProcess ();
+
+ if (! DuplicateHandle (self, in, self, &copy,
+ 0, 1 /* fInherit */,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+ return INVALID_HANDLE_VALUE;
+
+ return copy;
+}
+
+
+/* Initialize the SECURITY_ATTRIBUTES structure *LPSA. Set its
+ bInheritHandle flag according to INHERIT. */
+static void
+init_sa (LPSECURITY_ATTRIBUTES lpsa, BOOL inherit)
+{
+ lpsa->nLength = sizeof(*lpsa);
+ lpsa->bInheritHandle = inherit;
+ lpsa->lpSecurityDescriptor = NULL;
+}
+
+
+enum inherit_pipe { inherit_reading, inherit_writing };
+
+/* Create a pipe. Set READWRITE[0] to its reading end, and
+ READWRITE[1] to its writing end. If END is inherit_reading,
+ make the only the handle for the pipe's reading end inheritable.
+ If END is inherit_writing, make only the handle for the pipe's
+ writing end inheritable. Return 0 if we succeed, -1 if we fail.
+
+ Why does inheritability matter? Consider the case of a
+ pipe carrying data from the parent process to the child
+ process. The child wants to read data from the parent until
+ it reaches the EOF. Now, the only way to send an EOF on a pipe
+ is to close all the handles to its writing end. Obviously, the
+ parent has a handle to the writing end when it creates the child.
+ If the child inherits this handle, then it will never close it
+ (the child has no idea it's inherited it), and will thus never
+ receive an EOF on the pipe because it's holding a handle
+ to it.
+
+ In Unix, the child process closes the pipe ends before it execs.
+ In Windows NT, you create the pipe with uninheritable handles, and then use
+ DuplicateHandle to make the appropriate ends inheritable. */
+
+static int
+my_pipe (HANDLE *readwrite, enum inherit_pipe end)
+{
+ HANDLE read, write;
+ SECURITY_ATTRIBUTES sa;
+
+ init_sa (&sa, 0);
+ if (! CreatePipe (&read, &write, &sa, 1 << 13))
+ {
+ errno = EMFILE;
+ return -1;
+ }
+ if (end == inherit_reading)
+ read = inheritable (read);
+ else
+ write = inheritable (write);
+
+ if (read == INVALID_HANDLE_VALUE
+ || write == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (read);
+ CloseHandle (write);
+ errno = EMFILE;
+ return -1;
+ }
+
+ readwrite[0] = read;
+ readwrite[1] = write;
+
+ return 0;
+}
+
+
+/* Initialize the STARTUPINFO structure *LPSI. */
+static void
+init_si (LPSTARTUPINFO lpsi)
+{
+ memset (lpsi, 0, sizeof (*lpsi));
+ lpsi->cb = sizeof(*lpsi);
+ lpsi->lpReserved = NULL;
+ lpsi->lpTitle = NULL;
+ lpsi->lpReserved2 = NULL;
+ lpsi->cbReserved2 = 0;
+ lpsi->lpDesktop = NULL;
+ lpsi->dwFlags = 0;
+}
+
+
+/* Create a child process running COMMAND with IN as its standard input,
+ and OUT as its standard output. Return a handle to the child, or
+ INVALID_HANDLE_VALUE. */
+static int
+start_child (char *command, HANDLE in, HANDLE out)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ BOOL status;
+
+ /* The STARTUPINFO structure can specify handles to pass to the
+ child as its standard input, output, and error. */
+ init_si (&si);
+ si.hStdInput = in;
+ si.hStdOutput = out;
+ si.hStdError = (HANDLE) _get_osfhandle (2);
+ si.dwFlags = STARTF_USESTDHANDLES;
+
+ status = CreateProcess ((LPCTSTR) NULL,
+ (LPTSTR) command,
+ (LPSECURITY_ATTRIBUTES) NULL, /* lpsaProcess */
+ (LPSECURITY_ATTRIBUTES) NULL, /* lpsaThread */
+ TRUE, /* fInheritHandles */
+ 0, /* fdwCreate */
+ (LPVOID) 0, /* lpvEnvironment */
+ (LPCTSTR) 0, /* lpszCurDir */
+ &si, /* lpsiStartInfo */
+ &pi); /* lppiProcInfo */
+
+ if (! status)
+ {
+ DWORD error_code = GetLastError ();
+ switch (error_code)
+ {
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_OUTOFMEMORY:
+ errno = ENOMEM; break;
+ case ERROR_BAD_EXE_FORMAT:
+ errno = ENOEXEC; break;
+ case ERROR_ACCESS_DENIED:
+ errno = EACCES; break;
+ case ERROR_NOT_READY:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ default:
+ errno = ENOENT; break;
+ }
+ return (int) INVALID_HANDLE_VALUE;
+ }
+
+ /* The _spawn and _cwait functions in the C runtime library
+ seem to operate on raw NT handles, not PID's. Odd, but we'll
+ deal. */
+ return (int) pi.hProcess;
+}
+
+
+/* Given an array of arguments that one might pass to spawnv,
+ construct a command line that one might pass to CreateProcess.
+ Try to quote things appropriately. */
+static char *
+build_command (char *const *argv)
+{
+ int len;
+
+ /* Compute the total length the command will have. */
+ {
+ int i;
+
+ len = 0;
+ for (i = 0; argv[i]; i++)
+ {
+ char *p;
+
+ len += 2; /* for the double quotes */
+
+ for (p = argv[i]; *p; p++)
+ {
+ if (*p == '"')
+ len += 2;
+ else
+ len++;
+ }
+ len++; /* for the space or the '\0' */
+ }
+ }
+
+ {
+ /* The + 10 is in case len is 0. */
+ char *command = (char *) malloc (len + 10);
+ int i;
+ char *p;
+
+ if (! command)
+ {
+ errno = ENOMEM;
+ return command;
+ }
+
+ p = command;
+ *p = '\0';
+ /* copy each element of argv to command, putting each command
+ in double quotes, and backslashing any quotes that appear
+ within an argument. */
+ for (i = 0; argv[i]; i++)
+ {
+ char *a;
+ *p++ = '"';
+ for (a = argv[i]; *a; a++)
+ {
+ if (*a == '"')
+ *p++ = '\\', *p++ = '"';
+ else
+ *p++ = *a;
+ }
+ *p++ = '"';
+ *p++ = ' ';
+ }
+ if (p > command)
+ p[-1] = '\0';
+
+ return command;
+ }
+}
+
+
+/* Create an asynchronous child process executing ARGV,
+ with its standard input and output connected to the
+ parent with pipes. Set *TO to the file descriptor on
+ which one writes data for the child; set *FROM to
+ the file descriptor from which one reads data from the child.
+ Return the handle of the child process (this is what
+ _cwait and waitpid expect). */
+int
+piped_child (char *const *argv, int *to, int *from, bool fix_stderr)
+{
+ int child;
+ HANDLE pipein[2], pipeout[2];
+ char *command;
+
+ /* Turn argv into a form acceptable to CreateProcess. */
+ command = build_command (argv);
+ if (!command)
+ return -1;
+
+ /* Create pipes for communicating with child. Arrange for
+ the child not to inherit the ends it won't use. */
+ if (my_pipe (pipein, inherit_reading) == -1
+ || my_pipe (pipeout, inherit_writing) == -1)
+ return -1;
+
+ child = start_child (command, pipein[0], pipeout[1]);
+ free (command);
+ if (child == (int) INVALID_HANDLE_VALUE)
+ return -1;
+
+ /* Close the pipe ends the parent doesn't use. */
+ CloseHandle (pipein[0]);
+ CloseHandle (pipeout[1]);
+
+ /* Given the pipe handles, turn them into file descriptors for
+ use by the caller. */
+ if ((*to = _open_osfhandle ((long) pipein[1], _O_BINARY)) == -1
+ || (*from = _open_osfhandle ((long) pipeout[0], _O_BINARY)) == -1)
+ return -1;
+
+ return child;
+}
+
+/*
+ * dir = 0 : main proc writes to new proc, which writes to oldfd
+ * dir = 1 : main proc reads from new proc, which reads from oldfd
+ *
+ * Returns: a file descriptor. On failure (e.g., the exec fails),
+ * then filter_stream_through_program() complains and dies.
+ */
+
+int
+filter_stream_through_program (int oldfd, int dir, char **prog, pid_t *pidp)
+{
+ HANDLE pipe[2];
+ char *command;
+ int child;
+ HANDLE oldfd_handle;
+ HANDLE newfd_handle;
+ int newfd;
+
+ /* Get the OS handle associated with oldfd, to be passed to the child. */
+ if ((oldfd_handle = (HANDLE) _get_osfhandle (oldfd)) < 0)
+ error (1, errno, "cannot _get_osfhandle");
+
+ if (dir)
+ {
+ /* insert child before parent, pipe goes child->parent. */
+ if (my_pipe (pipe, inherit_writing) == -1)
+ error (1, errno, "cannot my_pipe");
+ if ((command = build_command (prog)) == NULL)
+ error (1, errno, "cannot build_command");
+ child = start_child (command, oldfd_handle, pipe[1]);
+ free (command);
+ if (child == (int) INVALID_HANDLE_VALUE)
+ error (1, errno, "cannot start_child");
+ close (oldfd);
+ CloseHandle (pipe[1]);
+ newfd_handle = pipe[0];
+ }
+ else
+ {
+ /* insert child after parent, pipe goes parent->child. */
+ if (my_pipe (pipe, inherit_reading) == -1)
+ error (1, errno, "cannot my_pipe");
+ if ((command = build_command (prog)) == NULL)
+ error (1, errno, "cannot build_command");
+ child = start_child (command, pipe[0], oldfd_handle);
+ free (command);
+ if (child == (int) INVALID_HANDLE_VALUE)
+ error (1, errno, "cannot start_child");
+ close (oldfd);
+ CloseHandle (pipe[0]);
+ newfd_handle = pipe[1];
+ }
+
+ if ((newfd = _open_osfhandle ((long) newfd_handle, _O_BINARY)) == -1)
+ error (1, errno, "cannot _open_osfhandle");
+
+ if (pidp)
+ *pidp = child;
+ return newfd;
+}
+
+
+
+int
+run_piped (int *tofdp, int *fromfdp)
+{
+ run_add_arg (NULL);
+ return piped_child (run_argv, tofdp, fromfdp, false);
+}
+
+
+
+/* Arrange for the file descriptor FD to not be inherited by child
+ processes. At the moment, CVS uses this function only on pipes
+ returned by piped_child, and our implementation of piped_child
+ takes care of setting the file handles' inheritability, so this
+ can be a no-op. */
+void
+close_on_exec (int fd)
+{
+}
diff --git a/windows-NT/sockerror.c b/windows-NT/sockerror.c
new file mode 100644
index 0000000..81f1959
--- /dev/null
+++ b/windows-NT/sockerror.c
@@ -0,0 +1,136 @@
+/* sockerror.c --- convert WinSock error number to string
+ Vince Del Vecchio <vdelvecc@spd.analog.com>
+
+ This file is part of GNU CVS.
+
+ GNU CVS is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <stdio.h>
+#include <sys/socket.h>
+
+struct err_strs {
+ char **strs;
+ int first;
+ int last;
+};
+
+static char *errs1[] = {
+ /* EINTR */ "Interrupted system call"
+};
+
+static char *errs2[] = {
+ /* EBADF */ "Bad file descriptor"
+};
+
+static char *errs3[] = {
+ /* EACCES */ "Permission denied",
+ /* EFAULT */ "Bad address"
+};
+
+static char *errs4[] = {
+ /* EINVAL */ "Invalid argument"
+};
+
+static char *errs5[] = {
+ /* EMFILE */ "Too many open files",
+};
+
+static char *errs6[] = {
+ /* EWOULDBLOCK */ "Resource temporarily unavailable",
+ /* EINPROGRESS */ "Operation now in progress",
+ /* EALREADY */ "Operation already in progress",
+ /* ENOTSOCK */ "Socket operation on non-socket",
+ /* EDESTADDRREQ */ "Destination address required",
+ /* EMSGSIZE */ "Message too long",
+ /* EPROTOTYPE */ "Protocol wrong type for socket",
+ /* ENOPROTOOPT */ "Protocol not available",
+ /* EPROTONOSUPPORT */ "Protocol not supported",
+ /* ESOCKTNOSUPPORT */ "Socket type not supported",
+ /* EOPNOTSUPP */ "Operation not supported on socket",
+ /* EPFNOSUPPORT */ "Protocol family not supported",
+ /* EAFNOSUPPORT */ "Address family not supported by protocol",
+ /* EADDRINUSE */ "Address already in use",
+ /* EADDRNOTAVAIL */ "Can't assign requested address",
+ /* ENETDOWN */ "Network is down",
+ /* ENETUNREACH */ "Network is unreachable",
+ /* ENETRESET */ "Network connection dropped on reset",
+ /* ECONNABORTED */ "Software caused connection abort",
+ /* ECONNRESET */ "Connection reset by peer",
+ /* ENOBUFS */ "No buffer space available",
+ /* EISCONN */ "Socket is already connected",
+ /* ENOTCONN */ "Socket is not connected",
+ /* ESHUTDOWN */ "Can't send after socket shutdown",
+ /* ETOOMANYREFS */ "Too many references: can't splice",
+ /* ETIMEDOUT */ "Connection timed out",
+ /* ECONNREFUSED */ "Connection refused",
+ /* ELOOP */ "Too many levels of symbolic links",
+ /* ENAMETOOLONG */ "File name too long",
+ /* EHOSTDOWN */ "Host is down",
+ /* EHOSTUNREACH */ "No route to host",
+ /* ENOTEMPTY */ "Directory not empty",
+ /* EPROCLIM */ "Too many processes",
+ /* EUSERS */ "Too many users",
+ /* EDQUOT */ "Disc quota exceeded",
+ /* ESTALE */ "Stale NFS file handle",
+ /* EREMOTE */ "Object is remote"
+};
+
+static char *errs7[] = {
+ /* SYSNOTREADY */ "Network subsystem unavailable",
+ /* VERNOTSUPPORTED */ "Requested WinSock version not supported",
+ /* NOTINITIALISED */ "WinSock was not initialized"
+};
+
+#ifdef WSAEDISCON
+static char *errs8[] = {
+ /* EDISCON */ "Graceful shutdown in progress"
+};
+#endif
+
+static char *errs9[] = {
+ /* HOST_NOT_FOUND */ "Unknown host",
+ /* TRY_AGAIN */ "Host name lookup failure",
+ /* NO_RECOVERY */ "Unknown server error",
+ /* NO_DATA */ "No address associated with name",
+};
+
+/* Some of these errors are defined in the winsock.h header file I have,
+ but not in the Winsock 1.1 spec. I include them some of them anyway,
+ where it is not too hard to avoid referencing the symbolic constant. */
+
+static struct err_strs sock_errlist[] = {
+ { errs1, WSAEINTR, WSAEINTR },
+ { errs2, WSAEBADF, WSAEBADF },
+ { errs3, WSAEACCES, WSAEFAULT },
+ { errs4, WSAEINVAL, WSAEINVAL },
+ { errs5, WSAEMFILE, WSAEMFILE },
+ { errs6, WSAEWOULDBLOCK, WSAEHOSTUNREACH + 6 },
+ { errs7, WSASYSNOTREADY, WSANOTINITIALISED },
+#ifdef WSAEDISCON
+ { errs8, WSAEDISCON, WSAEDISCON },
+#endif
+ { errs9, WSAHOST_NOT_FOUND, WSANO_DATA }
+};
+
+char *
+sock_strerror (int errnum)
+{
+ static char buf[40];
+ int i;
+
+ for (i = 0; i < (sizeof sock_errlist / sizeof *sock_errlist); i++)
+ {
+ if (errnum >= sock_errlist[i].first && errnum <= sock_errlist[i].last)
+ return sock_errlist[i].strs[errnum - sock_errlist[i].first];
+ }
+ sprintf(buf, "Unknown socket error: %d", errnum);
+ return buf;
+}
diff --git a/windows-NT/stamp-chi b/windows-NT/stamp-chi
new file mode 100644
index 0000000..c5bc371
--- /dev/null
+++ b/windows-NT/stamp-chi
@@ -0,0 +1,1445 @@
+/***
+ *** config.h.in, generated by mkconfig.pl:
+ ***
+ *** (config.h.in.in
+ *** + ../config.h.in)
+ *** . config.h.in.footer
+ *** --> config.h.in
+ ***
+ *** ***** DO NOT ALTER THIS FILE!!! *****
+ ***
+ *** Changes to this file will be overwritten by automatic script runs.
+ *** Changes should be made to the config.h.in.in & config.h.in.footer
+ *** files instead.
+ ***/
+
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define this to a NULL terminated list of allowed path prefixes (for
+ directories) and paths to files the CVS server will allow configuration to
+ be read from when specified from the command line. */
+#undef ALLOW_CONFIG_OVERRIDE
+
+/* Enable AUTH_CLIENT_SUPPORT to enable pserver as a remote access method in
+ the CVS client (default) */
+#define AUTH_CLIENT_SUPPORT 1
+
+/* Define if you want to use the password authenticated server. */
+#undef AUTH_SERVER_SUPPORT
+
+/* Define if you want CVS to be able to be a remote repository client. */
+#define CLIENT_SUPPORT
+
+/* Define to 1 if the `closedir' function returns void instead of `int'. */
+#undef CLOSEDIR_VOID
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* define if cross compiling */
+#undef CROSS_COMPILING
+
+/* The CVS admin command is restricted to the members of the group
+ CVS_ADMIN_GROUP. If this group does not exist, all users are allowed to run
+ CVS admin. To disable the CVS admin command for all users, create an empty
+ CVS_ADMIN_GROUP by running configure with the --with-cvs-admin-group=
+ option. To disable access control for CVS admin, run configure with the
+ --without-cvs-admin-group option in order to comment out the define below.
+ */
+#undef CVS_ADMIN_GROUP
+
+/* When committing a permanent change, CVS and RCS make a log entry of who
+ committed the change. If you are committing the change logged in as "root"
+ (not under "su" or other root-priv giving program), CVS/RCS cannot
+ determine who is actually making the change. As such, by default, CVS
+ prohibits changes committed by users logged in as "root". You can disable
+ checking by passing the "--enable-rootcommit" option to configure or by
+ commenting out the lines below. */
+#undef CVS_BADROOT
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define if there is a member named d_ino in the struct describing directory
+ headers. */
+#undef D_INO_IN_DIRENT
+
+/* The default editor to use, if one does not specify the "-e" option to cvs,
+ or does not have an EDITOR environment variable. If this is not set to an
+ absolute path to an executable, use the shell to find where the editor
+ actually is. This allows sites with /usr/bin/vi or /usr/ucb/vi to work
+ equally well (assuming that their PATH is reasonable). */
+#define EDITOR_DFLT "notepad"
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#undef ENABLE_NLS
+
+/* Define to enable encryption support. */
+#undef ENCRYPTION
+
+/* Define as good substitute value for EOVERFLOW. */
+#define EOVERFLOW EINVAL
+
+/* Define if this executable will be running on case insensitive file systems.
+ In the client case, this means that it will request that the server pretend
+ to be case insensitive if it isn't already. */
+#define FILENAMES_CASE_INSENSITIVE 1
+
+/* Define on systems for which file names may have a so-called `drive letter'
+ prefix, define this to compute the length of that prefix, including the
+ colon. */
+#define FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX 1
+
+/* Define if the backslash character may also serve as a file name component
+ separator. */
+#define FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR 1
+
+#if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+# define FILE_SYSTEM_PREFIX_LEN(Filename) \
+ ((Filename)[0] && (Filename)[1] == ':' ? 2 : 0)
+#else
+# define FILE_SYSTEM_PREFIX_LEN(Filename) 0
+#endif
+
+/* When committing or importing files, you must enter a log message. Normally,
+ you can do this either via the -m flag on the command line, the -F flag on
+ the command line, or an editor will be started for you. If you like to use
+ logging templates (the rcsinfo file within the $CVSROOT/CVSROOT directory),
+ you might want to force people to use the editor even if they specify a
+ message with -m or -F. Enabling FORCE_USE_EDITOR will cause the -m or -F
+ message to be appended to the temp file when the editor is started. */
+#undef FORCE_USE_EDITOR
+
+/* Define to an alternative value if GSS_C_NT_HOSTBASED_SERVICE isn't defined
+ in the gssapi.h header file. MIT Kerberos 1.2.1 requires this. Only
+ relevant when using GSSAPI. */
+#undef GSS_C_NT_HOSTBASED_SERVICE
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have `alloca' after including <alloca.h>, a header that
+ may be supplied by this distribution. */
+#undef HAVE_ALLOCA
+
+/* Define HAVE_ALLOCA_H for backward compatibility with older code that
+ includes <alloca.h> only if HAVE_ALLOCA_H is defined. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the `atexit' function. */
+#define HAVE_ATEXIT 1
+
+/* Define to 1 if you have the <bp-sym.h> header file. */
+#undef HAVE_BP_SYM_H
+
+/* Define to 1 if you have the `btowc' function. */
+#undef HAVE_BTOWC
+
+/* Define to 1 if you have the `canonicalize_file_name' function. */
+#undef HAVE_CANONICALIZE_FILE_NAME
+
+/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+#undef HAVE_CFLOCALECOPYCURRENT
+
+/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+#undef HAVE_CFPREFERENCESCOPYAPPVALUE
+
+/* Define to 1 if you have the `chsize' function. */
+#define HAVE_CHSIZE 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `clock_settime' function. */
+#undef HAVE_CLOCK_SETTIME
+
+/* Define if you have the connect function. */
+#define HAVE_CONNECT
+
+/* Define if you have the crypt function. */
+#undef HAVE_CRYPT
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+#undef HAVE_DCGETTEXT
+
+/* Define to 1 if you have the declaration of `clearerr_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_CLEARERR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FEOF_UNLOCKED
+
+/* Define to 1 if you have the declaration of `ferror_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FERROR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fflush_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FFLUSH_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FGETS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `flockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FLOCKFILE
+
+/* Define to 1 if you have the declaration of `fputc_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fputs_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FPUTS_UNLOCKED
+
+/* Define to 1 if you have the declaration of `fread_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FREAD_UNLOCKED
+
+/* Define to 1 if you have the declaration of `funlockfile', and to 0 if you
+ don't. */
+#undef HAVE_DECL_FUNLOCKFILE
+
+/* Define to 1 if you have the declaration of `fwrite_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_FWRITE_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getcwd', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETCWD 1
+
+/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `getdelim', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETDELIM
+
+/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
+ */
+#define HAVE_DECL_GETENV 1
+
+/* Define to 1 if you have the declaration of `getline', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLINE
+
+/* Define to 1 if you have the declaration of `getlogin', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN
+
+/* Define to 1 if you have the declaration of `getlogin_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETLOGIN_R
+
+/* Define to 1 if you have the declaration of `getpass', and to 0 if you
+ don't. */
+#define HAVE_DECL_GETPASS 1
+
+/* Define to 1 if you have the declaration of `memrchr', and to 0 if you
+ don't. */
+#undef HAVE_DECL_MEMRCHR
+
+/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
+ don't. */
+#define HAVE_DECL_NANOSLEEP 1
+
+/* Define to 1 if you have the declaration of `putchar_unlocked', and to 0 if
+ you don't. */
+#undef HAVE_DECL_PUTCHAR_UNLOCKED
+
+/* Define to 1 if you have the declaration of `putc_unlocked', and to 0 if you
+ don't. */
+#undef HAVE_DECL_PUTC_UNLOCKED
+
+/* Define to 1 if you have the declaration of `strdup', and to 0 if you don't.
+ */
+#define HAVE_DECL_STRDUP 1
+
+/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_STRERROR_R
+
+/* Define to 1 if you have the declaration of `__fpending', and to 0 if you
+ don't. */
+#define HAVE_DECL___FPENDING 0
+
+/* Define to 1 if you have the <direct.h> header file. */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dup2' function. */
+#define HAVE_DUP2 1
+
+/* Define if you have the declaration of environ. */
+#define HAVE_ENVIRON_DECL 1
+
+/* Define if you have the declaration of errno. */
+#define HAVE_ERRNO_DECL 1
+
+/* Define to 1 if you have the `fchdir' function. */
+#undef HAVE_FCHDIR
+
+/* Define to 1 if you have the `fchmod' function. */
+#undef HAVE_FCHMOD
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `flockfile' function. */
+#undef HAVE_FLOCKFILE
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `fsync' function. */
+#undef HAVE_FSYNC
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have the `funlockfile' function. */
+#undef HAVE_FUNLOCKFILE
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `getgroups' function. */
+#undef HAVE_GETGROUPS
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `getlogin_r' function. */
+#undef HAVE_GETLOGIN_R
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long_only' function. */
+#undef HAVE_GETOPT_LONG_ONLY
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define if you have the getspnam function. */
+#undef HAVE_GETSPNAM
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#undef HAVE_GETTEXT
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H 1
+
+/* Define if you have GSSAPI with Kerberos version 5 available. */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
+/* Define if you have the iconv() function. */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_INTMAX_T
+
+/* Define if <inttypes.h> exists and doesn't clash with <sys/types.h>. */
+#undef HAVE_INTTYPES_H
+
+/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
+ declares uintmax_t. */
+#undef HAVE_INTTYPES_H_WITH_UINTMAX
+
+/* Define to 1 if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET. */
+#define HAVE_IPV4 1
+
+/* Define to 1 if <sys/socket.h> defines AF_INET6. */
+#undef HAVE_IPV6
+
+/* Define to 1 if you have the `isascii' function. */
+#define HAVE_ISASCII 1
+
+/* Define to 1 if you have the `isblank' function. */
+#undef HAVE_ISBLANK
+
+/* Define to 1 if you have the `iswprint' function. */
+#define HAVE_ISWPRINT 1
+
+/* Define if you have MIT Kerberos version 4 available. */
+#undef HAVE_KERBEROS
+
+/* Define to 1 if you have the <krb5.h> header file. */
+#undef HAVE_KRB5_H
+
+/* Define to 1 if you have the `krb_get_err_text' function. */
+#undef HAVE_KRB_GET_ERR_TEXT
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#undef HAVE_LANGINFO_CODESET
+
+/* Define to 1 if you have the `krb' library (-lkrb). */
+#undef HAVE_LIBKRB
+
+/* Define to 1 if you have the `krb4' library (-lkrb4). */
+#undef HAVE_LIBKRB4
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `login' function. */
+#undef HAVE_LOGIN
+
+/* Define to 1 if you have the `logout' function. */
+#undef HAVE_LOGOUT
+
+/* Define if you have the 'long double' type. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have the 'long long' type. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including
+ config.h and <sys/mman.h>. */
+#undef HAVE_MAP_ANONYMOUS
+
+/* Define to 1 if you have the `mblen' function. */
+#define HAVE_MBLEN 1
+
+/* Define to 1 if you have the `mbrlen' function. */
+#define HAVE_MBRLEN 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if you have the `mbsinit' function. */
+#undef HAVE_MBSINIT
+
+/* Define to 1 if you have the `mbsrtowcs' function. */
+#define HAVE_MBSRTOWCS 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define if you have memchr (always for CVS). */
+#define HAVE_MEMCHR 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mempcpy' function. */
+#undef HAVE_MEMPCPY
+
+/* Define to 1 if you have the `memrchr' function. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if <limits.h> defines the MIN and MAX macros. */
+#define HAVE_MINMAX_IN_LIMITS_H 1
+
+/* Define to 1 if <sys/param.h> defines the MIN and MAX macros. */
+#undef HAVE_MINMAX_IN_SYS_PARAM_H
+
+/* Define to 1 if you have the `mknod' function. */
+#undef HAVE_MKNOD
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `nanotime' function. */
+#undef HAVE_NANOTIME
+
+/* Define to 1 if you have the <ndbm.h> header file. */
+#undef HAVE_NDBM_H
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#define HAVE_NDIR_H 1
+
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
+/* Define to 1 if you have the <OS.h> header file. */
+#undef HAVE_OS_H
+
+/* Define to enable system authentication with PAM instead of using the simple
+ getpwnam interface. This allows authentication (in theory) with any PAM
+ module, e.g. on systems with shadow passwords or via LDAP */
+#undef HAVE_PAM
+
+/* Define to 1 if pam/pam_appl.h is available */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
+ setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX is not
+ defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD is defined.
+ */
+#undef HAVE_PARTLY_WORKING_GETCWD
+
+/* Define to 1 if you have the `posix_memalign' function. */
+#undef HAVE_POSIX_MEMALIGN
+
+/* Define to 1 if the `printf' function supports the %p format for printing
+ pointers. */
+#define HAVE_PRINTF_PTR 1
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#define HAVE_PTRDIFF_T 1
+
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#define HAVE_REALLOC 1
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the `regerror' function. */
+#undef HAVE_REGERROR
+
+/* Define to 1 if you have the `regexec' function. */
+#undef HAVE_REGEXEC
+
+/* Define to 1 if you have the `regfree' function. */
+#undef HAVE_REGFREE
+
+/* Define to 1 if you have the `resolvepath' function. */
+#undef HAVE_RESOLVEPATH
+
+/* Define to 1 if you have the `rpmatch' function. */
+#undef HAVE_RPMATCH
+
+/* Define to 1 if you have run the test for working tzset. */
+#define HAVE_RUN_TZSET_TEST 1
+
+/* Define to 1 if you have the <search.h> header file. */
+#define HAVE_SEARCH_H 1
+
+/* Define to 1 if security/pam_appl.h is available */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define if the diff library should use setmode for binary files. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigblock' function. */
+#undef HAVE_SIGBLOCK
+
+/* Define to 1 if you have the `siginterrupt' function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define to 1 if you have the `sigsetmask' function. */
+#undef HAVE_SIGSETMASK
+
+/* Define to 1 if you have the `sigvec' function. */
+#undef HAVE_SIGVEC
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
+ uintmax_t. */
+#define HAVE_STDINT_H_WITH_UINTMAX 1
+
+/* Define to 1 if you have the <stdio_ext.h> header file. */
+#undef HAVE_STDIO_EXT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have strchr (always for CVS). */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define if there is a member named d_type in the struct describing directory
+ headers. */
+#undef HAVE_STRUCT_DIRENT_D_TYPE
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define if struct timespec is declared in <time.h>. */
+#undef HAVE_STRUCT_TIMESPEC
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_ZONE
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/inttypes.h> header file. */
+#undef HAVE_SYS_INTTYPES_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `tcgetattr' function. */
+#undef HAVE_TCGETATTR
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the `timezone' function. */
+#undef HAVE_TIMEZONE
+
+/* Define to 1 if localtime_r, etc. have the type signatures that POSIX
+ requires. */
+#undef HAVE_TIME_R_POSIX
+
+/* Define if struct tm has the tm_gmtoff member. */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#undef HAVE_TM_ZONE
+
+/* Define to 1 if you have the `tsearch' function. */
+#undef HAVE_TSEARCH
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the `tzset' function. */
+#define HAVE_TZSET 1
+
+/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
+#undef HAVE_UINTMAX_T
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define if you have the 'unsigned long long' type. */
+#undef HAVE_UNSIGNED_LONG_LONG
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
+#define HAVE_UTIME_NULL 1
+
+/* Define to 1 if you have the `vasnprintf' function. */
+#undef HAVE_VASNPRINTF
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `wait3' function. */
+#undef HAVE_WAIT3
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define if you have the 'wchar_t' type. */
+#define HAVE_WCHAR_T 1
+
+/* Define to 1 if you have the `wcrtomb' function. */
+#define HAVE_WCRTOMB 1
+
+/* Define to 1 if you have the `wcscoll' function. */
+#define HAVE_WCSCOLL 1
+
+/* Define to 1 if you have the `wcslen' function. */
+#define HAVE_WCSLEN 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define if you have the 'wint_t' type. */
+#define HAVE_WINT_T 1
+
+/* Define to 1 if you have the `wmemchr' function. */
+#define HAVE_WMEMCHR 1
+
+/* Define to 1 if you have the `wmemcpy' function. */
+#define HAVE_WMEMCPY 1
+
+/* Define to 1 if you have the `wmempcpy' function. */
+#undef HAVE_WMEMPCPY
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to 1 if you have the `__fpending' function. */
+#undef HAVE___FPENDING
+
+/* Define to 1 if you have the `__fsetlocking' function. */
+#undef HAVE___FSETLOCKING
+
+/* Define to 1 if you have the `__secure_getenv' function. */
+#undef HAVE___SECURE_GETENV
+
+#if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+#else
+# define ISSLASH(C) ((C) == '/')
+#endif
+
+/* Define to include locking code which prevents versions of CVS earlier than
+ 1.12.4 directly accessing the same repositiory as this executable from
+ ignoring this executable's promotable read locks. If only CVS versions
+ 1.12.4 and later will be accessing your repository directly (as a server or
+ locally), you can safely disable this option in return for fewer disk
+ accesses and a small speed increase. Disabling this option when versions of
+ CVS earlier than 1,12,4 _will_ be accessing your repository, however, is
+ *VERY* *VERY* *VERY* dangerous and could result in data loss. As such, by
+ default, CVS is compiled with this code enabled. If you are sure you would
+ like this code disabled, you can disable it by passing the
+ "--disable-lock-compatibility" option to configure or by commenting out the
+ lines below. */
+#define LOCK_COMPATIBILITY
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
+
+/* If malloc(0) is != NULL, define this to 1. Otherwise define this to 0. */
+#undef MALLOC_0_IS_NONNULL
+
+/* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */
+#undef MAP_ANONYMOUS
+
+/* By default, CVS stores its modules and other such items in flat text files
+ (MY_NDBM enables this). Turning off MY_NDBM causes CVS to look for a
+ system-supplied ndbm database library and use it instead. That may speed
+ things up, but the default setting generally works fine too. */
+#define MY_NDBM
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "%PACKAGE_BUGREPORT%"
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "%PACKAGE_STRING%"
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to set a service name for PAM. This must be defined. Define to
+ `program_name', without the quotes, to use whatever name CVS was invoked
+ as. Otherwise, define to a double-quoted literal string, such as `"cvs"'.
+ */
+#undef PAM_SERVICE_NAME
+
+/* the number of pending output bytes on stream `fp' */
+#define PENDING_OUTPUT_N_BYTES ( fp ? fp->_ptr - fp->_base : 0 )
+
+/* Define if you want CVS to be able to serve as a transparent proxy for write
+ operations. Disabling this may produce a slight performance gain on some
+ systems, at the expense of write proxy support. */
+#undef PROXY_SUPPORT
+
+/* Path to the pr utility */
+#undef PR_PROGRAM
+
+/* Define to force lib/regex.c to use malloc instead of alloca. */
+#define REGEX_MALLOC 1
+
+/* Define if rename does not work for source file names with a trailing slash,
+ like the one from SunOS 4.1.1_U1. */
+#undef RENAME_TRAILING_SLASH_BUG
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The default remote shell to use, if one does not specify the CVS_RSH
+ environment variable. */
+#define RSH_DFLT "rsh"
+
+/* If you are working with a large remote repository and a 'cvs checkout' is
+ swamping your network and memory, define these to enable flow control. You
+ will end up with even less probability of a consistent checkout (see
+ Concurrency in cvs.texinfo), but CVS doesn't try to guarantee that anyway.
+ The master server process will monitor how far it is getting behind, if it
+ reaches the high water mark, it will signal the child process to stop
+ generating data when convenient (ie: no locks are held, currently at the
+ beginning of a new directory). Once the buffer has drained sufficiently to
+ reach the low water mark, it will be signalled to start again. */
+#undef SERVER_FLOWCONTROL
+
+/* The high water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_HI_WATER
+
+/* The low water mark in bytes for server flow control. Required if
+ SERVER_FLOWCONTROL is defined, and useless otherwise. */
+#undef SERVER_LO_WATER
+
+/* Define if you want CVS to be able to serve repositories to remote clients.
+ */
+#undef SERVER_SUPPORT
+
+/* The size of a `char', as computed by sizeof. */
+#define SIZEOF_CHAR 1
+
+/* The size of a `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of a `float', as computed by sizeof. */
+#define SIZEOF_FLOAT 4
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `intmax_t', as computed by sizeof. */
+#undef SIZEOF_INTMAX_T
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of a `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 8
+
+/* The size of a `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of a `ptrdiff_t', as computed by sizeof. */
+#define SIZEOF_PTRDIFF_T 4
+
+/* The size of a `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of a `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of a `wint_t', as computed by sizeof. */
+#define SIZEOF_WINT_T 2
+
+/* Define as the maximum value of type 'size_t', if the system doesn't define
+ it. */
+#define SIZE_MAX (~(size_t)0)
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#define STAT_MACROS_BROKEN 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r returns char *. */
+#undef STRERROR_R_CHAR_P
+
+/* Enable support for the pre 1.12.1 *info scripting hook format strings.
+ Disable this option for a smaller executable once your scripting hooks have
+ been updated to use the new *info format strings by passing
+ "--disable-old-info-format-support" option to configure or by commenting
+ out the line below. */
+#undef SUPPORT_OLD_INFO_FMT_STRINGS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Directory used for storing temporary files, if not overridden by
+ environment variables or the -T global option. There should be little need
+ to change this (-T is a better mechanism if you need to use a different
+ directory for temporary files). */
+#define TMPDIR_DFLT "c:\\temp"
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define if tzset clobbers localtime's static buffer. */
+#undef TZSET_CLOBBERS_LOCALTIME_BUFFER
+
+/* Define to its maximum value if an unsigned integer type of width exactly 32
+ bits exists and the standard includes do not define UINT32_MAX. */
+#undef UINT32_MAX
+
+/* The default umask to use when creating or otherwise setting file or
+ directory permissions in the repository. Must be a value in the range of 0
+ through 0777. For example, a value of 002 allows group rwx access and world
+ rx access; a value of 007 allows group rwx access but no world access. This
+ value is overridden by the value of the CVSUMASK environment variable,
+ which is interpreted as an octal number. */
+#define UMASK_DFLT 002
+
+/* Define if double is the first floating point type detected with its size.
+ */
+#undef UNIQUE_FLOAT_TYPE_DOUBLE
+
+/* Define if float is the first floating point type detected with its size. */
+#undef UNIQUE_FLOAT_TYPE_FLOAT
+
+/* Define if long double is the first floating point type detected with its
+ size. */
+#undef UNIQUE_FLOAT_TYPE_LONG_DOUBLE
+
+/* Define if char is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_CHAR
+
+/* Define if int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INT
+
+/* Define if intmax_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_INTMAX_T
+
+/* Define if long int is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG
+
+/* Define if long long is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_LONG_LONG
+
+/* Define if ptrdiff_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_PTRDIFF_T
+
+/* Define if short is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SHORT
+
+/* Define if size_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_SIZE_T
+
+/* Define if wint_t is the first integer type detected with its size. */
+#undef UNIQUE_INT_TYPE_WINT_T
+
+/* Define if setmode is required when writing binary data to stdout. */
+#define USE_SETMODE_STDOUT 1
+
+/* Define to 1 if you want getc etc. to use unlocked I/O if available.
+ Unlocked I/O can improve performance in unithreaded apps, but it is not
+ safe for multithreaded apps. */
+#undef USE_UNLOCKED_IO
+
+/* Define if utime requires write access to the file (true on Windows, but not
+ Unix). */
+#define UTIME_EXPECTS_WRITABLE
+
+/* Define if unsetenv() returns void, not int. */
+#undef VOID_UNSETENV
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define if you want regoff_t to be at least as wide POSIX requires. */
+#undef _REGEX_LARGE_OFFSETS
+
+/* Define to force lib/regex.c to define re_comp et al. */
+#define _REGEX_RE_COMP 1
+
+/* Define for Solaris 2.5.1 so uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+
+/* Define to rpl_ if the getcwd replacement function should be used. */
+#undef __GETCWD_PREFIX
+
+/* Define to rpl_ if the getopt replacement functions and variables should be
+ used. */
+#define __GETOPT_PREFIX rpl_
+
+/* Define to rpl_ if the openat replacement function should be used. */
+#undef __OPENAT_PREFIX
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to a replacement function name for fnmatch(). */
+#undef fnmatch
+
+/* Define to a replacement function name for getline(). */
+#undef getline
+
+/* Define to a replacement function name for getpass(). */
+#undef getpass
+
+/* Define to rpl_gettimeofday if the replacement function should be used. */
+#undef gettimeofday
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to rpl_gmtime if the replacement function should be used. */
+#undef gmtime
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+
+/* Define to long or long long if <inttypes.h> and <stdint.h> don't define. */
+#undef intmax_t
+
+/* Define to rpl_localtime if the replacement function should be used. */
+#undef localtime
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to a type if <wchar.h> does not define. */
+#undef mbstate_t
+
+/* Define to rpl_mkdir if the replacement function should be used. */
+#undef mkdir
+
+/* Define to rpl_mkstemp if the replacement function should be used. */
+#undef mkstemp
+
+/* Define to rpl_mktime if the replacement function should be used. */
+#undef mktime
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define mode_t int
+
+/* Define to the name of the strftime replacement function. */
+#define my_strftime nstrftime
+
+/* Define to rpl_nanosleep if the replacement function should be used. */
+#define nanosleep woe32_nanosleep
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to rpl_realloc if the replacement function should be used. */
+#define realloc rpl_realloc
+
+/* Define to rpl_rename if the replacement function should be used. */
+#undef rename
+
+/* Define to equivalent of C99 restrict keyword, or to nothing if this is not
+ supported. Do not define if restrict is supported directly. */
+#define restrict
+
+/* Define to rpl_select if the replacement function should be used. */
+#undef select
+
+/* Define to empty if the C compiler doesn't support this keyword. */
+#undef signed
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define as a signed type of the same size as size_t. */
+#define ssize_t int
+
+/* Define to rpl_strcasecmp always. */
+#define strcasecmp rpl_strcasecmp
+
+/* Define to rpl_tzset if the wrapper function should be used. */
+#undef tzset
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to the type of a unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to unsigned long or unsigned long long if <stdint.h> and
+ <inttypes.h> don't define. */
+#undef uintmax_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
+/*============================================================================*/
+/* config.h.in.footer: configuration file for Windows NT
+ Conrad T. Pino <Conrad@Pino.com> --- May 2004 */
+
+/* This file lives in the windows-NT subdirectory, which is only included
+ in your header search path if you're working under Microsoft Visual C++,
+ and use ../cvsnt.mak for your project. Thus, this is the right place to
+ put configuration information for Windows NT. */
+
+/* This file is getting chaotic and will be organized as follows:
+
+ Macros appears first alphabetized in case sensitive order.
+ Typedefs appear next alphabetized in case sensitive order.
+ Function prototypes alphabetized in case sensitive order.
+
+ Reorgnized by Conrad T. Pino <Conrad@Pino.com> May 25, 2005 */
+
+/* just one time please */
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+/* ======================= Macro Definnitions Follow ====================== */
+
+/* Under Windows NT, mkdir only takes one argument. */
+#define CVS_MKDIR wnt_mkdir
+
+#define CVS_RENAME wnt_rename
+
+/* This is where old bits go to die under Windows NT. */
+#define DEVNULL "nul"
+
+/* Windows has no ELOOP value in errno.h */
+#define ELOOP EMLINK
+
+/* Windows has _snprintf function.
+ HAVE_DECL__SNPRINTF used in ../lib/vasnprintf.c */
+#define HAVE_DECL__SNPRINTF 1
+
+#define HAVE_WINSOCK_H
+
+/* This tells the client that it must use send()/recv() to talk to the
+ server if it is connected to the server via a socket; Win95 needs
+ it because _open_osfhandle doesn't work. */
+#define NO_SOCKET_TO_FD 1
+
+/* Is this true on NT? Seems like I remember reports that NT 3.51 has
+ problems with 200K writes (of course, the issue of large writes is
+ moot since the use of buffer.c ensures that writes will only be as big
+ as the buffers). */
+#define SEND_NEVER_PARTIAL 1
+
+/* Stop server macro */
+#define SHUTDOWN_SERVER wnt_shutdown_server
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not available through errno.
+ Instead, this macro should be used to obtain an error code. */
+#define SOCK_ERRNO (WSAGetLastError ())
+
+/* This tells the client that, in addition to needing to use
+ send()/recv() to do socket I/O, the error codes for send()/recv()
+ and other socket operations are not known to strerror. Instead,
+ this macro should be used to convert the error codes to strings. */
+#define SOCK_STRERROR sock_strerror
+
+/* Start server macro */
+#define START_SERVER wnt_start_server
+
+/* The internal rsh client uses sockets not file descriptors. Note
+ that as the code stands now, it often takes values from a SOCKET and
+ puts them in an int. This is ugly but it seems like sizeof
+ (SOCKET) <= sizeof (int) on win32, even the 64-bit variants. */
+#define START_SERVER_RETURNS_SOCKET 1
+
+/* Macro name tells the story */
+#define SYSTEM_CLEANUP woe32_cleanup
+
+/* Macro name tells the story */
+#define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock()
+
+/*
+ * According to GNU conventions, we should avoid referencing any macro
+ * containing "WIN" as a reference to Microsoft Windows, as we would like to
+ * avoid any implication that we consider Microsoft Windows any sort of "win".
+ *
+ * FIXME: As of 2003-06-09, folks on the GNULIB project were discussing
+ * defining a configure macro to define WOE32 appropriately. If they ever do
+ * write such a beast, we should use it, though in most cases it would be
+ * preferable to avoid referencing any OS or compiler anyhow, per Autoconf
+ * convention, and reference only tested features of the system.
+ *
+ * re FIXME: This definition would still be necessary since systems which run
+ * configure do not use this config.h and vice-versa.
+ */
+#define WOE32 1
+
+/* Define POSIX name to Microsoft name */
+#define dup _dup
+
+/* getpagesize is missing on Windows, 4096 does the right thing. */
+#define getpagesize() 4096
+
+/* Define to a substitute for the `lstat' function. */
+#define lstat stat
+
+/* Define POSIX name to Microsoft name */
+#define popen _popen
+
+/* Define POSIX name to Microsoft name */
+#define pclose _pclose
+
+/* Diff needs us to define this. I think it could always be
+ -1 for CVS, because we pass temporary files to diff, but
+ config.h seems like the easiest place to put this, so for
+ now we put it here. */
+#define same_file(s,t) (-1)
+
+/* Define to a substitute for the stat function. */
+#define stat wnt_stat
+
+/* ====================== Typedef Declarations Follow ===================== */
+
+/* ====================== Function Prototypes Follow ====================== */
+
+#include <woe32.h>
+
+/* #define SOCK_STRERROR sock_strerror */
+char *sock_strerror (int errnum);
+
+/* #define CVS_MKDIR wnt_mkdir */
+int wnt_mkdir (const char *PATH, int MODE);
+
+/* #define CVS_RENAME wnt_rename */
+int wnt_rename (const char *, const char *);
+
+/* #define SHUTDOWN_SERVER wnt_shutdown_server */
+void wnt_shutdown_server (int fd);
+
+/* #define START_SERVER wnt_start_server */
+void wnt_start_server (int *tofd, int *fromfd,
+ char *client_user,
+ char *server_user,
+ char *server_host,
+ char *server_cvsroot);
+
+/* #define stat wnt_stat and #define lstat wnt_stat */
+int wnt_stat (const char *file, struct wnt_stat *sb);
+
+/* =============== Special mkdir Prototype Handling Follows =============== */
+
+#include <direct.h>
+#define mkdir wnt_mkdir
+
+/* ===================== Special Function Definitions ===================== */
+
+/*
+ Microsoft defines "mbinit" in <wchar.h> for C++ code only.
+
+ Expect link errors for versions:
+
+ earlier than Visual C++ 5.0
+
+ later than Visual C++ .NET 2003
+
+ and Visual C++ .NET is just a guess which might be wrong.
+*/
+
+#if _MSC_VER >= 1100 && _MSC_VER <= 1200
+
+/* If within Visual C++ 5.0 to Visual C++ 6.0 */
+
+inline int mbsinit (const void * arg)
+ { return 1; }
+
+#elif _MSC_VER >= 1300 && _MSC_VER <= 1310
+
+/* If within Visual C++ .NET to Visual C++ .NET 2003 */
+
+inline int mbsinit (const int * arg)
+ { return arg == NULL || ! *arg; }
+
+#endif
+
+/* =========================== End Of This File =========================== */
diff --git a/windows-NT/startserver.c b/windows-NT/startserver.c
new file mode 100644
index 0000000..82e1ab6
--- /dev/null
+++ b/windows-NT/startserver.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 1995-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* startserver.c --- open a connection to the CVS server under Windows NT
+ Jim Blandy <jimb@cyclic.com> --- August 1995 */
+
+#include "cvs.h"
+#include "rcmd.h"
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <malloc.h>
+#include <io.h>
+#include <errno.h>
+
+/* Keep track of whether we've opened a socket so that wnt_shutdown_server
+ can do the correct thing. We don't want to call shutdown or
+ closesocket on a pipe. */
+
+static int opened_a_socket = 0;
+
+void
+wnt_start_server (int *tofd, int *fromfd,
+ char *client_user,
+ char *server_user,
+ char *server_host,
+ char *server_cvsroot)
+{
+ char *cvs_server;
+ char *command;
+ struct servent *sptr;
+ unsigned short port;
+ int read_fd;
+ char *portenv;
+
+ if (! (cvs_server = getenv ("CVS_SERVER")))
+ cvs_server = "cvs";
+ command = xmalloc (strlen (cvs_server)
+ + strlen (server_cvsroot)
+ + 50);
+ sprintf (command, "%s -d %s server", cvs_server, server_cvsroot);
+
+ portenv = getenv("CVS_RCMD_PORT");
+ if (portenv)
+ port = atoi(portenv);
+ else if ((sptr = getservbyname("shell", "tcp")) != NULL)
+ port = sptr->s_port;
+ else
+ port = IPPORT_CMDSERVER; /* shell/tcp */
+
+ read_fd = rcmd (&server_host,
+ port,
+ client_user,
+ (server_user ? server_user : client_user),
+ command,
+ 0);
+ if (read_fd < 0)
+ error (1, 0, "cannot start server via rcmd: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+
+ *tofd = read_fd;
+ *fromfd = read_fd;
+ free (command);
+
+ opened_a_socket = 1;
+}
+
+
+void
+wnt_shutdown_server (int fd)
+{
+ if (opened_a_socket)
+ {
+ SOCKET s;
+
+ s = fd;
+ if (shutdown (s, 2) == SOCKET_ERROR)
+ error (1, 0, "couldn't shutdown server connection: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+ if (closesocket (s) == SOCKET_ERROR)
+ error (1, 0, "couldn't close server connection: %s",
+ SOCK_STRERROR (SOCK_ERRNO));
+ }
+ else
+ {
+ if (close (fd) < 0)
+ error (1, errno, "cannot close server connection");
+ }
+}
diff --git a/windows-NT/stdbool.h b/windows-NT/stdbool.h
new file mode 100644
index 0000000..6faee73
--- /dev/null
+++ b/windows-NT/stdbool.h
@@ -0,0 +1,100 @@
+/* This file is generated via a rule in Makefile.am from the
+ * ../lib/stdbool_.h.in file.
+ *
+ * *** DO NOT EDIT THIS FILE DIRECTLY ***
+ *
+ * Edit ../lib/stdbool_.h instead.
+ */
+/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+/* ISO C 99 <stdbool.h> for platforms that lack it. */
+
+/* Usage suggestions:
+
+ Programs that use <stdbool.h> should be aware of some limitations
+ and standards compliance issues.
+
+ Standards compliance:
+
+ - <stdbool.h> must be #included before 'bool', 'false', 'true'
+ can be used.
+
+ - You cannot assume that sizeof (bool) == 1.
+
+ - Programs should not undefine the macros bool, true, and false,
+ as C99 lists that as an "obsolescent feature".
+
+ Limitations of this substitute, when used in a C89 environment:
+
+ - <stdbool.h> must be #included before the '_Bool' type can be used.
+
+ - You cannot assume that _Bool is a typedef; it might be a macro.
+
+ - In C99, casts and automatic conversions to '_Bool' or 'bool' are
+ performed in such a way that every nonzero value gets converted
+ to 'true', and zero gets converted to 'false'. This doesn't work
+ with this substitute. With this substitute, only the values 0 and 1
+ give the expected result when converted to _Bool' or 'bool'.
+
+ Also, it is suggested that programs use 'bool' rather than '_Bool';
+ this isn't required, but 'bool' is more common. */
+
+
+/* 7.16. Boolean type and values */
+
+/* BeOS <sys/socket.h> already #defines false 0, true 1. We use the same
+ definitions below, but temporarily we have to #undef them. */
+#ifdef __BEOS__
+# include <OS.h> /* defines bool but not _Bool */
+# undef false
+# undef true
+#endif
+
+/* For the sake of symbolic names in gdb, we define true and false as
+ enum constants, not only as macros.
+ It is tempting to write
+ typedef enum { false = 0, true = 1 } _Bool;
+ so that gdb prints values of type 'bool' symbolically. But if we do
+ this, values of type '_Bool' may promote to 'int' or 'unsigned int'
+ (see ISO C 99 6.7.2.2.(4)); however, '_Bool' must promote to 'int'
+ (see ISO C 99 6.3.1.1.(2)). So we add a negative value to the
+ enum; this ensures that '_Bool' promotes to 'int'. */
+#if !(defined __cplusplus || defined __BEOS__)
+# if !0
+# if defined __SUNPRO_C && (__SUNPRO_C < 0x550 || __STDC__ == 1)
+ /* Avoid stupid "warning: _Bool is a keyword in ISO C99". */
+# define _Bool signed char
+enum { false = 0, true = 1 };
+# else
+typedef enum { _Bool_must_promote_to_int = -1, false = 0, true = 1 } _Bool;
+# endif
+# endif
+#else
+typedef bool _Bool;
+#endif
+#define bool _Bool
+
+/* The other macros must be usable in preprocessor directives. */
+#define false 0
+#define true 1
+#define __bool_true_false_are_defined 1
+
+#endif /* _STDBOOL_H */
diff --git a/windows-NT/stdint.h b/windows-NT/stdint.h
new file mode 100644
index 0000000..051e9a2
--- /dev/null
+++ b/windows-NT/stdint.h
@@ -0,0 +1,290 @@
+/* This file is generated via a rule in Makefile.am from the
+ * ../lib/stdint_.h.in file.
+ *
+ * *** DO NOT EDIT THIS FILE DIRECTLY ***
+ *
+ * Edit ../lib/stdint_.h instead.
+ */
+/* Copyright (C) 2001-2002, 2004-2005 Free Software Foundation, Inc.
+ Written by Bruno Haible, Sam Steingold, Peter Burwood.
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+/*
+ * ISO C 99 <stdint.h> for platforms that lack it.
+ * <http://www.opengroup.org/onlinepubs/007904975/basedefs/stdint.h.html>
+ */
+
+/* Get wchar_t, WCHAR_MIN, WCHAR_MAX. */
+#include <stddef.h>
+/* Get CHAR_BIT, LONG_MIN, LONG_MAX, ULONG_MAX. */
+#include <limits.h>
+
+/* Get those types that are already defined in other system include files. */
+#if defined(__FreeBSD__)
+# include <sys/inttypes.h>
+#endif
+#if defined(__sun) && HAVE_SYS_INTTYPES_H
+# include <sys/inttypes.h>
+ /* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and
+ the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX.
+ But note that <sys/int_types.h> contains only the type definitions! */
+# define _STDINT_H_HAVE_SYSTEM_INTTYPES
+#endif
+#if (defined(__hpux) || defined(_AIX)) && HAVE_INTTYPES_H
+# include <inttypes.h>
+ /* HP-UX 10 <inttypes.h> has nearly everything, except UINT_LEAST8_MAX,
+ UINT_FAST8_MAX, PTRDIFF_MIN, PTRDIFF_MAX. */
+ /* AIX 4 <inttypes.h> has nearly everything, except INTPTR_MIN, INTPTR_MAX,
+ UINTPTR_MAX, PTRDIFF_MIN, PTRDIFF_MAX. */
+# define _STDINT_H_HAVE_SYSTEM_INTTYPES
+#endif
+#if !(defined(UNIX_CYGWIN32) && defined(__BIT_TYPES_DEFINED__))
+# define _STDINT_H_NEED_SIGNED_INT_TYPES
+#endif
+
+#if !defined(_STDINT_H_HAVE_SYSTEM_INTTYPES)
+
+/* 7.18.1.1. Exact-width integer types */
+
+#if !defined(__FreeBSD__)
+
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef signed char int8_t;
+#endif
+typedef unsigned char uint8_t;
+
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef short int16_t;
+#endif
+typedef unsigned short uint16_t;
+
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef int int32_t;
+#endif
+typedef unsigned int uint32_t;
+
+#if 0
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef long int64_t;
+#endif
+typedef unsigned long uint64_t;
+#define _STDINT_H_HAVE_INT64
+#elif 0
+#ifdef _STDINT_H_NEED_SIGNED_INT_TYPES
+typedef long long int64_t;
+#endif
+typedef unsigned long long uint64_t;
+#define _STDINT_H_HAVE_INT64
+#elif defined(_MSC_VER)
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#define _STDINT_H_HAVE_INT64
+#endif
+
+#endif /* !FreeBSD */
+
+/* 7.18.1.2. Minimum-width integer types */
+
+typedef int8_t int_least8_t;
+typedef uint8_t uint_least8_t;
+typedef int16_t int_least16_t;
+typedef uint16_t uint_least16_t;
+typedef int32_t int_least32_t;
+typedef uint32_t uint_least32_t;
+#ifdef _STDINT_H_HAVE_INT64
+typedef int64_t int_least64_t;
+typedef uint64_t uint_least64_t;
+#endif
+
+/* 7.18.1.3. Fastest minimum-width integer types */
+
+typedef int32_t int_fast8_t;
+typedef uint32_t uint_fast8_t;
+typedef int32_t int_fast16_t;
+typedef uint32_t uint_fast16_t;
+typedef int32_t int_fast32_t;
+typedef uint32_t uint_fast32_t;
+#ifdef _STDINT_H_HAVE_INT64
+typedef int64_t int_fast64_t;
+typedef uint64_t uint_fast64_t;
+#endif
+
+/* 7.18.1.4. Integer types capable of holding object pointers */
+
+#if !defined(__FreeBSD__)
+
+/* On some platforms (like IRIX6 MIPS with -n32) sizeof(void*) < sizeof(long),
+ but this doesn't matter here. */
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+
+#endif /* !FreeBSD */
+
+/* 7.18.1.5. Greatest-width integer types */
+
+#ifdef _STDINT_H_HAVE_INT64
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+#else
+typedef int32_t intmax_t;
+typedef uint32_t uintmax_t;
+#endif
+
+/* 7.18.2. Limits of specified-width integer types */
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+/* 7.18.2.1. Limits of exact-width integer types */
+
+#define INT8_MIN -128
+#define INT8_MAX 127
+#define UINT8_MAX 255U
+#define INT16_MIN -32768
+#define INT16_MAX 32767
+#define UINT16_MAX 65535U
+#define INT32_MIN (~INT32_MAX)
+#define INT32_MAX 2147483647
+#define UINT32_MAX 4294967295U
+#ifdef _STDINT_H_HAVE_INT64
+#define INT64_MIN (~INT64_MAX)
+#if 0
+#define INT64_MAX 9223372036854775807L
+#define UINT64_MAX 18446744073709551615UL
+#elif 0
+#define INT64_MAX 9223372036854775807LL
+#define UINT64_MAX 18446744073709551615ULL
+#elif defined(_MSC_VER)
+#define INT64_MAX 9223372036854775807i64
+#define UINT64_MAX 18446744073709551615ui64
+#endif
+#endif
+
+/* 7.18.2.2. Limits of minimum-width integer types */
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#ifdef _STDINT_H_HAVE_INT64
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+#endif
+
+/* 7.18.2.3. Limits of fastest minimum-width integer types */
+
+#define INT_FAST8_MIN INT32_MIN
+#define INT_FAST8_MAX INT32_MAX
+#define UINT_FAST8_MAX UINT32_MAX
+#define INT_FAST16_MIN INT32_MIN
+#define INT_FAST16_MAX INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#ifdef _STDINT_H_HAVE_INT64
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+#endif
+
+/* 7.18.2.4. Limits of integer types capable of holding object pointers */
+
+#define INTPTR_MIN LONG_MIN
+#define INTPTR_MAX LONG_MAX
+#define UINTPTR_MAX ULONG_MAX
+
+/* 7.18.2.5. Limits of greatest-width integer types */
+
+#ifdef _STDINT_H_HAVE_INT64
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+#else
+#define INTMAX_MIN INT32_MIN
+#define INTMAX_MAX INT32_MAX
+#define UINTMAX_MAX UINT32_MAX
+#endif
+
+/* 7.18.3. Limits of other integer types */
+
+#define PTRDIFF_MIN (~(ptrdiff_t)0 << (sizeof(ptrdiff_t)*CHAR_BIT-1))
+#define PTRDIFF_MAX (~PTRDIFF_MIN)
+
+/* This may be wrong... */
+#define SIG_ATOMIC_MIN 0
+#define SIG_ATOMIC_MAX 127
+
+#define SIZE_MAX (~(size_t)0)
+
+/* wchar_t limits already defined in <stddef.h>. */
+/* wint_t limits already defined in <wchar.h>. */
+
+#endif
+
+/* 7.18.4. Macros for integer constants */
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+
+/* 7.18.4.1. Macros for minimum-width integer constants */
+
+#define INT8_C(x) x
+#define UINT8_C(x) x##U
+#define INT16_C(x) x
+#define UINT16_C(x) x##U
+#define INT32_C(x) x
+#define UINT32_C(x) x##U
+#if 0
+#define INT64_C(x) x##L
+#define UINT64_C(x) x##UL
+#elif 0
+#define INT64_C(x) x##LL
+#define UINT64_C(x) x##ULL
+#elif defined(_MSC_VER)
+#define INT64_C(x) x##i64
+#define UINT64_C(x) x##ui64
+#endif
+
+/* 7.18.4.2. Macros for greatest-width integer constants */
+
+#if 0
+#define INTMAX_C(x) x##L
+#define UINTMAX_C(x) x##UL
+#elif 0
+#define INTMAX_C(x) x##LL
+#define UINTMAX_C(x) x##ULL
+#elif defined(_MSC_VER)
+#define INTMAX_C(x) x##i64
+#define UINTMAX_C(x) x##ui64
+#else
+#define INTMAX_C(x) x
+#define UINTMAX_C(x) x##U
+#endif
+
+#endif
+
+#endif /* !_STDINT_H_HAVE_SYSTEM_INTTYPES */
+
+#endif /* _STDINT_H */
diff --git a/windows-NT/sys/socket.h b/windows-NT/sys/socket.h
new file mode 100644
index 0000000..99af149
--- /dev/null
+++ b/windows-NT/sys/socket.h
@@ -0,0 +1,9 @@
+#ifndef SYS_SOCKET_H
+#define SYS_SOCKET_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+
+typedef size_t socklen_t;
+
+#endif /* SYS_SOCKET_H */
diff --git a/windows-NT/sys/types.h b/windows-NT/sys/types.h
new file mode 100644
index 0000000..b6b5f1a
--- /dev/null
+++ b/windows-NT/sys/types.h
@@ -0,0 +1,155 @@
+/*
+ * windows-NT/sys/types.h
+ */
+
+#ifdef _MSC_VER
+
+#pragma once
+
+/* cl.exe version number legend: */
+/* */
+/* ! cl.exe version number confirmed */
+/* ? cl.exe version number uncertain */
+/* */
+/* Verified with Visual C++ 5.0 - cl.exe version 11.00 ! */
+/* Verified with Visual C++ 6.0 - cl.exe version 12.00 ! */
+/* No tests with Visual C++ .NET - cl.exe version 13.00 ? */
+/* Verified with Visual C++ .NET 2003 - cl.exe version 13.10 ! */
+/* No tests with Visual C++ 2005 - cl.exe version 14.00 ? */
+/* */
+#if _MSC_VER != 1100 && _MSC_VER != 1200 && _MSC_VER != 1310
+#pragma message ( "Please email Microsoft's <sys/types.h> file" )
+#pragma message ( "and version number from \"cl /?\" command to" )
+#pragma message ( "<conradpino@cvsproject.org>. Thank you." )
+#endif /* _MSC_VER != 1200 */
+
+/***************************************************************************/
+/* Mimic what Micrsoft defines in their <sys/types.h> */
+#ifndef _INC_TYPES
+#define _INC_TYPES
+
+
+
+/* Define time_t */
+#ifndef _TIME_T_DEFINED
+#define _TIME_T_DEFINED
+
+#if defined(_WIN64) && _MSC_VER >= 1300
+typedef __int64 time_t;
+#else
+typedef long time_t;
+#endif
+
+#if _INTEGRAL_MAX_BITS >= 64
+typedef __int64 __time64_t;
+#endif
+#endif /* _TIME_T_DEFINED */
+
+
+
+/* Define ino_t */
+#ifndef _INO_T_DEFINED
+#define _INO_T_DEFINED
+
+#if _MSC_VER == 1100
+
+typedef unsigned short _ino_t; /* i-node number (not used on DOS) */
+
+#if !__STDC__
+/* Non-ANSI name for compatibility */
+#ifdef _NTSDK
+#define ino_t _ino_t
+#else /* ndef _NTSDK */
+typedef unsigned short ino_t;
+#endif /* _NTSDK */
+#endif /* !__STDC__ */
+
+#else /* _MSC_VER != 1100 */
+
+typedef unsigned short ino_t;
+
+/* Microsoft uses _ino_t */
+typedef ino_t _ino_t;
+
+#endif /* _MSC_VER != 1100 */
+
+#endif /* _INO_T_DEFINED */
+
+
+
+/* Define dev_t */
+#ifndef _DEV_T_DEFINED
+#define _DEV_T_DEFINED
+
+#if _MSC_VER == 1100
+
+#ifdef _NTSDK
+typedef short _dev_t; /* device code */
+#else /* ndef _NTSDK */
+typedef unsigned int _dev_t; /* device code */
+#endif /* _NTSDK */
+
+#if !__STDC__
+/* Non-ANSI name for compatibility */
+#ifdef _NTSDK
+#define dev_t _dev_t
+#else /* ndef _NTSDK */
+typedef unsigned int dev_t;
+#endif /* _NTSDK */
+#endif /* !__STDC__ */
+
+#else /* _MSC_VER != 1100 */
+
+typedef unsigned int dev_t;
+
+/* Microsoft uses _dev_t */
+typedef dev_t _dev_t;
+
+#endif /* _MSC_VER != 1100 */
+
+#endif /* _DEV_T_DEFINED */
+
+
+
+/* Define off_t */
+#ifndef _OFF_T_DEFINED
+#define _OFF_T_DEFINED
+
+#if _MSC_VER == 1100
+
+typedef long _off_t; /* file offset value */
+
+#if !__STDC__
+/* Non-ANSI name for compatibility */
+#ifdef _NTSDK
+#define off_t _off_t
+#else /* ndef _NTSDK */
+typedef long off_t;
+#endif /* _NTSDK */
+#endif /* !__STDC__ */
+
+#else /* _MSC_VER != 1100 */
+
+typedef long off_t;
+
+/* Microsoft uses _off_t */
+typedef off_t _off_t;
+
+#endif /* _MSC_VER != 1100 */
+
+#endif /* _OFF_T_DEFINED */
+
+#endif /* _INC_TYPES */
+
+/***************************************************************************/
+/* define what Micrsoft doesn't */
+typedef int gid_t;
+typedef int pid_t;
+typedef int uid_t;
+
+typedef unsigned int useconds_t;
+/***************************************************************************/
+
+#else /* _MSC_VER */
+#error This file is for use with Microsoft compilers only.
+#endif /* _MSC_VER */
diff --git a/windows-NT/unistd.c b/windows-NT/unistd.c
new file mode 100644
index 0000000..6ff09c8
--- /dev/null
+++ b/windows-NT/unistd.c
@@ -0,0 +1,71 @@
+/*
+ * windows-NT/unitstd.c
+ * POSIX/UNIX functions not provided by Win32 platform
+ * and declared in <unistd.h> header file
+ */
+
+#include "unistd.h"
+
+#include <stdio.h>
+#include <conio.h>
+
+#include <sys/socket.h> /* This does: #include <windows.h> */
+
+/* Please order functions by name if possible */
+
+
+
+char *
+getpass (const char *prompt)
+{
+ static char pwd_buf[128];
+ size_t i;
+
+ fputs (prompt, stderr);
+ fflush (stderr);
+ for (i = 0; i < sizeof (pwd_buf) - 1; ++i)
+ {
+ pwd_buf[i] = _getch ();
+ if (pwd_buf[i] == '\r')
+ break;
+ }
+ pwd_buf[i] = '\0';
+ fputs ("\n", stderr);
+ return pwd_buf;
+}
+
+
+
+/* This is just a call to GetCurrentProcessID */
+pid_t
+getpid (void)
+{
+ return (pid_t) GetCurrentProcessId();
+}
+
+
+
+unsigned int sleep (unsigned seconds)
+{
+ Sleep (1000*seconds);
+ return 0;
+}
+
+
+
+/*
+ * Sleep at least some number of microseconds
+ */
+int usleep (useconds_t microseconds)
+{
+ if ( microseconds )
+ {
+ const useconds_t one_second = 1000000;
+ struct timeval tv_delay;
+
+ tv_delay.tv_sec = microseconds / one_second;
+ tv_delay.tv_usec = microseconds % one_second;
+ return select (0, NULL, NULL, NULL, &tv_delay);
+ }
+ return 0;
+}
diff --git a/windows-NT/unistd.h b/windows-NT/unistd.h
new file mode 100644
index 0000000..7d5dfd3
--- /dev/null
+++ b/windows-NT/unistd.h
@@ -0,0 +1,96 @@
+/* unistd.h -- Unix standard function prototypes
+
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Conrad T. Pino and Mark D. Baushke */
+
+#ifndef UNISTD_H
+#define UNISTD_H
+
+/* Don't include Microsoft's chdir, getcwd here, done in config.h now */
+#include <stddef.h>
+
+/* include Microsoft's close, dup */
+#include <io.h>
+
+#include <sys/types.h>
+
+/* These functions doesn't exist under Windows NT; we provide stubs */
+char * getpass (const char *prompt);
+pid_t getpid (void);
+int readlink (const char *path, char *buf, size_t buf_size);
+unsigned int sleep (unsigned int seconds);
+int usleep (useconds_t microseconds);
+
+/*
+FIXME: gethostname prototype for lib/xgethostname.c, no #include <winsock.h>
+ Remove when GNULib folks provide a permenant fix.
+ Requested by Mark D. Baushke and committed by Conrad T. Pino
+*/
+int __declspec(dllimport) __stdcall gethostname (char * name, int namelen);
+
+#if 0 /* someday maybe these should be added here as well */
+
+int chdir (const char *pathname);
+int mkdir (const char *pathname, mode_t mode);
+int rmdir (const char *pathname);
+int link (const char *oldpath, const char *newpath);
+int unlink (const char *pathname);
+int rename (const char *oldpath, const char *newpath);
+int stat (const char *file_name, struct stat *buf);
+int chmod (const char *path, mode_t mode);
+int chown (const char *path, uid_t owner, gid_t group);
+int utime (const char *filename, struct utimbuf *buf);
+DIR *opendir (const char *name);
+struct dirent *readdir(DIR *dir);
+int closedir (DIR *dir);
+void rewinddir (DIR *dir);
+int access (const char *pathname, int mode);
+int open (const char *pathname, int flags);
+int creat (const char *pathname, mode_t mode);
+int close (int fd);
+ssize_t read (int fd, void *buf, size_t count);
+ssize_t write (int fd, const void *buf, size_t count);
+int fcntl (int fd, int cmd);
+int fstat (int filedes, struct stat *buf);
+off_t lseek (int fildes, off_t offset, int whence);
+int dup (int oldfd);
+int dup2 (int oldfd, int newfd);
+int pipe (int filedes[2]);
+mode_t umask (mode_t mask);
+FILE *fdopen (int fildes, const char *mode);
+int fileno (FILE *stream);
+pid_t fork (void);
+int execl (const char *path, const char *arg, ...);
+int execle (const char *path, const char *arg, ...);
+int execlp (const char *file, const char *arg, ...);
+int execv (const char *path, char *const argv[]);
+int execve (const char *path, char *const argv[],
+ char *const envp[]);
+int execvp (const char *file, char *const argv[]);
+pid_t waitpid (pid_t pid, int *status, int options);
+pid_t waitpid (pid_t pid, int *status, int options);
+void _exit (int status);
+int kill (pid_t pid, int sig);
+int pause (void);
+unsigned int alarm (unsigned int seconds);
+int setuid (uid_t uid);
+int setgid (gid_t gid);
+
+#endif /* someday */
+
+#endif /* UNISTD_H */
diff --git a/windows-NT/waitpid.c b/windows-NT/waitpid.c
new file mode 100644
index 0000000..9d7932c
--- /dev/null
+++ b/windows-NT/waitpid.c
@@ -0,0 +1,22 @@
+/* waitpid.c --- waiting for process termination, under Windows NT
+ Jim Blandy <jimb@cyclic.com> --- August 1995 */
+
+#include <assert.h>
+#include <stdio.h>
+#include <process.h>
+#include <errno.h>
+
+#include "config.h"
+
+/* Wait for the process PID to exit. Put the return status in *statusp.
+ OPTIONS is not supported yet under Windows NT. We hope it's always zero. */
+pid_t waitpid (pid, statusp, options)
+ pid_t pid;
+ int *statusp;
+ int options;
+{
+ /* We don't know how to deal with any options yet. */
+ assert (options == 0);
+
+ return _cwait (statusp, pid, _WAIT_CHILD);
+}
diff --git a/windows-NT/woe32.c b/windows-NT/woe32.c
new file mode 100644
index 0000000..f01b63d
--- /dev/null
+++ b/windows-NT/woe32.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2003-2005 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * woe32.c
+ * - utility functions for cvs under win32
+ *
+ */
+
+#include "config.h"
+
+#include "woe32.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/socket.h> /* This does: #include <windows.h> */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <xalloc.h>
+
+
+
+/* #define SYSTEM_CLEANUP woe32_cleanup */
+void
+woe32_cleanup (void)
+{
+ if (WSACleanup ())
+ {
+#ifdef SERVER_ACTIVE
+ if (server_active || error_use_protocol)
+ /* FIXME: how are we supposed to report errors? As of now
+ (Sep 98), error() can in turn call us (if it is out of
+ memory) and in general is built on top of lots of
+ stuff. */
+ ;
+ else
+#endif
+ fprintf (stderr, "cvs: cannot WSACleanup: %s\n",
+ sock_strerror (WSAGetLastError ()));
+ }
+}
+
+
+
+/*============================================================================*/
+/*
+How Microsoft does fd_set in Windows 2000 and Visual C++ 6.0:
+
+ * Select uses arrays of SOCKETs. These macros manipulate such
+ * arrays. FD_SETSIZE may be defined by the user before including
+ * this file, but the default here should be >= 64.
+ *
+ * CAVEAT IMPLEMENTOR and USER: THESE MACROS AND TYPES MUST BE
+ * INCLUDED IN WINSOCK2.H EXACTLY AS SHOWN HERE.
+
+ #ifndef FD_SETSIZE
+ #define FD_SETSIZE 64
+ #endif
+
+ typedef struct fd_set {
+ u_int fd_count;
+ SOCKET fd_array[FD_SETSIZE];
+ } fd_set;
+
+Microsoft packs all handles between fd_array[0] and fd_array[fd_count-1]
+*/
+
+typedef struct
+{
+ int is_ready;
+ SOCKET crt;
+ DWORD type;
+ union
+ {
+ long osf;
+ HANDLE w32;
+ };
+} woe32_handle_set;
+
+typedef struct
+{
+ u_int ready_count, used_count;
+ woe32_handle_set handle[ FD_SETSIZE ];
+} woe32_select_set;
+
+static int woe32_select_set_fini (woe32_select_set * w32_set, fd_set * crt_set)
+{
+ FD_ZERO (crt_set);
+
+ if (w32_set->ready_count)
+ {
+ u_int index;
+ woe32_handle_set * handle;
+
+ index = 0;
+ handle = w32_set->handle;
+ while (index < w32_set->used_count)
+ {
+ if (handle->is_ready)
+ {
+ FD_SET (handle->crt, crt_set);
+ }
+
+ ++index;
+ ++handle;
+ }
+ }
+
+ return w32_set->ready_count;
+}
+
+static int woe32_select_set_init (woe32_select_set * w32_set, fd_set * crt_set)
+{
+ u_int index;
+ DWORD dwBytesAvail;
+ woe32_handle_set * handle;
+
+ w32_set->ready_count = w32_set->used_count = index = 0;
+ handle = w32_set->handle;
+
+ if (crt_set) while (index < crt_set->fd_count)
+ {
+ handle->crt = crt_set->fd_array[index];
+
+ handle->osf = _get_osfhandle (handle->crt);
+ if (handle->w32 == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ handle->type = GetFileType (handle->w32);
+ switch (handle->type)
+ {
+ case FILE_TYPE_DISK:
+ w32_set->ready_count += handle->is_ready = 1;
+ break;
+
+ case FILE_TYPE_PIPE:
+ if ( PeekNamedPipe (handle->w32, NULL, 0, NULL, &dwBytesAvail, NULL) )
+ {
+ w32_set->ready_count += handle->is_ready = dwBytesAvail > 0;
+ }
+ else
+ {
+ errno = EBADF;
+ return -1;
+ }
+ break;
+
+ case FILE_TYPE_CHAR:
+ case FILE_TYPE_REMOTE:
+ case FILE_TYPE_UNKNOWN:
+ default:
+ errno = EBADF;
+ return -1;
+ }
+
+ ++index;
+ ++handle;
+ }
+ w32_set->used_count = index;
+
+ while (index < FD_SETSIZE)
+ {
+ handle->crt = -1;
+
+ handle->w32 = INVALID_HANDLE_VALUE;
+
+ handle->type = FILE_TYPE_UNKNOWN;
+
+ handle->is_ready = 0;
+
+ ++index;
+ ++handle;
+ }
+
+ return w32_set->ready_count;
+}
+
+static int woe32_select_set_wait (woe32_select_set * w32_set)
+{
+ char buffer[ 8 ];
+ DWORD dwBytesRead;
+
+ /* set contains only non-ready pipes */
+ if (w32_set->used_count != 1)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (! ReadFile (w32_set->handle[0].w32, buffer, 0, &dwBytesRead, NULL))
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ return w32_set->handle[0].is_ready = 1;
+}
+
+/* #define fd_select woe32_fd_select */
+#undef fd_select
+int woe32_fd_select ( int nfds,
+ struct fd_set * readfds,
+ struct fd_set * writefds,
+ struct fd_set * errorfds,
+ struct timeval * timeout)
+{
+ int ready_fds;
+ woe32_select_set woe32_rset;
+
+ /* we don't support these for now */
+ assert(writefds != NULL);
+ assert(errorfds != NULL);
+ assert(timeout != NULL);
+
+ /* Windows doesn't care but POSIX says it does */
+ if (nfds < 0 || nfds > FD_SETSIZE)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ready_fds = woe32_select_set_init (&woe32_rset, readfds);
+ if (! ready_fds)
+ {
+ ready_fds = woe32_select_set_wait (&woe32_rset);
+ }
+
+ if (ready_fds >= 0)
+ {
+ woe32_select_set_fini (&woe32_rset, readfds);
+ }
+
+ return ready_fds;
+}
+/*============================================================================*/
+
+
+
+char *
+woe32_getlogin (void)
+{
+ static char name[256];
+ DWORD dw = sizeof (name);
+ GetUserName (name, &dw);
+ if (name[0] == '\0')
+ return NULL;
+ else
+ return name;
+}
+
+
+
+/* #define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock() */
+void
+woe32_init_winsock (void)
+{
+ WSADATA data;
+
+ if (WSAStartup (MAKEWORD (1, 1), &data))
+ {
+ fprintf (stderr, "cvs: unable to initialize winsock\n");
+ exit (1);
+ }
+}
+
+
+
+char *
+woe32_home_dir (void)
+{
+ static char *home_dir = NULL;
+ char *home_drive, *home_path;
+
+ if (home_dir)
+ return home_dir;
+
+ if ((home_drive = getenv ("HOMEDRIVE")) && (home_path = getenv ("HOMEPATH")))
+ {
+ const char NUL = '\0';
+ size_t home_drive_len, home_path_len;
+
+ home_drive_len = strlen (home_drive);
+ home_path_len = strlen (home_path);
+
+ home_dir = xmalloc (home_drive_len + home_path_len + sizeof NUL);
+
+ memcpy (home_dir, home_drive, home_drive_len );
+ memcpy (home_dir + home_drive_len, home_path, home_path_len );
+ home_dir[ home_drive_len + home_path_len ] = NUL;
+
+ return home_dir;
+ }
+
+ return NULL;
+}
+
+
+
+/* #define nanosleep woe32_nanosleep */
+int
+woe32_nanosleep (const struct timespec *requested_delay,
+ struct timespec *remaining_delay)
+{
+ const useconds_t one_second = 1000000;
+ const useconds_t nano_per_micro = 1000;
+ useconds_t micro_delay;
+
+ micro_delay = requested_delay->tv_sec * one_second
+ + ( requested_delay->tv_nsec + nano_per_micro - 1 ) / nano_per_micro
+ ;
+
+ return usleep (micro_delay);
+}
+
+
+
+char *
+woe32_shell (void)
+{
+ char *shell;
+
+ shell = getenv ("ComSpec");
+
+ if (shell == NULL)
+ {
+ /* Windows always sets ComSpec, the user is messing with us */
+ const char *os;
+
+ if ((os = getenv ("OS")) && strcmp (os, "Windows_NT"))
+ /* Windows NT, Windows 2000, Windows XP, Windows 2003 */
+ shell = "cmd.exe";
+ else
+ /* Windows 95, Windows 98, Windows Me */
+ shell = "command.com";
+ }
+
+ return shell;
+}
diff --git a/windows-NT/woe32.h b/windows-NT/woe32.h
new file mode 100644
index 0000000..d33d777
--- /dev/null
+++ b/windows-NT/woe32.h
@@ -0,0 +1,35 @@
+/*
+ * woe32.h
+ * - utility functions for cvs under win32
+ *
+ */
+
+#ifndef WOE32_H
+#define WOE32_H
+
+#include <timespec.h>
+
+/* #define SYSTEM_CLEANUP woe32_cleanup */
+void woe32_cleanup (void);
+
+/* #define fd_select woe32_fd_select */
+int woe32_fd_select ( int nfds,
+ struct fd_set * readfds,
+ struct fd_set * writefds,
+ struct fd_set * errorfds,
+ struct timeval * timeout);
+
+char *woe32_getlogin (void);
+
+char *woe32_home_dir (void);
+
+/* #define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock() */
+void woe32_init_winsock (void);
+
+/* #define nanosleep woe32_nanosleep */
+int woe32_nanosleep (const struct timespec *requested_delay,
+ struct timespec *remaining_delay);
+
+char * woe32_shell (void);
+
+#endif /* WOE32_H */
diff --git a/zlib/.cvsignore b/zlib/.cvsignore
new file mode 100644
index 0000000..85464c2
--- /dev/null
+++ b/zlib/.cvsignore
@@ -0,0 +1,10 @@
+*.bb
+*.bbg
+*.da
+Makefile
+example
+minigzip
+foo.gz
+WinDebug
+WinRel
+zlib.001
diff --git a/zlib/CVS/Entries b/zlib/CVS/Entries
new file mode 100644
index 0000000..c8b005d
--- /dev/null
+++ b/zlib/CVS/Entries
@@ -0,0 +1,11 @@
+/README.examples/1.1.1.1/Sun Sep 25 15:25:30 2005//
+/fitblk.c/1.1.1.1/Sun Sep 25 15:25:30 2005//
+/gun.c/1.1.1.1/Sun Sep 25 15:25:30 2005//
+/gzappend.c/1.1.1.1/Sun Sep 25 15:25:30 2005//
+/gzjoin.c/1.1.1.1/Sun Sep 25 15:25:30 2005//
+/gzlog.c/1.1.1.1/Sun Sep 25 15:25:30 2005//
+/gzlog.h/1.1.1.1/Sun Sep 25 15:25:30 2005//
+/zlib_how.html/1.1.1.1/Sun Sep 25 15:25:31 2005//
+/zpipe.c/1.1.1.1/Sun Sep 25 15:25:31 2005//
+/zran.c/1.1.1.1/Sun Sep 25 15:25:31 2005//
+D
diff --git a/zlib/CVS/Repository b/zlib/CVS/Repository
new file mode 100644
index 0000000..898b9cc
--- /dev/null
+++ b/zlib/CVS/Repository
@@ -0,0 +1 @@
+ccvs/zlib/examples
diff --git a/zlib/CVS/Root b/zlib/CVS/Root
new file mode 100644
index 0000000..e6a4c0c
--- /dev/null
+++ b/zlib/CVS/Root
@@ -0,0 +1 @@
+dprice@savannah.nongnu.org:/cvsroot/cvs
diff --git a/zlib/ChangeLog b/zlib/ChangeLog
new file mode 100644
index 0000000..664ada5
--- /dev/null
+++ b/zlib/ChangeLog
@@ -0,0 +1,1097 @@
+2005-09-25 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (DISTFILES): Remove contrib/gzappend/*. Add new files.
+
+ * ChangeLog, Makefile.in, infback.c, inflate.c, zconf.h: Merge after
+ 1.2.3 import.
+ * contrib/gzappend/gzappend.c, contrib/testzlib/testzlib.sln,
+ contrib/testzlib/testzlib.vcproj, old/Make_vms.com: Remove after 1.2.3
+ import.
+
+2005-04-06 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (DISTFILES): Remove obsolete contrib/*.txt.
+
+2005-02-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in, infback.c, inflate.c, zconf.h: Merge after zlib 1.2.2
+ import.
+ * contrib/visual-basic.txt: Ditto for this removed file.
+
+2004-12-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (DISTFILES): Add contrib/inflate86/*.
+ * algorithm.doc, build_zlib.com, zlib.def, zlib.rc: Remove these
+ obsolete files.
+
+2004-11-30 Conrad T. Pino <Conrad@Pino.com>
+
+ * libz.mak: Regenerated for "../cvsnt.dsp" change.
+
+2004-11-16 Derek Price <derek@ximbiot.com>
+
+ * zconf.in.h: Remove unneeded file.
+ * Makefile.in (distclean): Don't "configure clean". Remove Makefile.
+
+2004-11-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (DISTFILES): Update for zlib 1.2.1.
+
+2004-11-11 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (clean): Don't remove Windows build files.
+
+2004-10-27 Mark D. Baushke <mdb@cvshome.org>
+
+ * infback.c (out_desc): Security Bugfixes (CAN-2004-0797,
+ OpenPKG-SA-2004.038-zlib).
+ * inflate.c (inflate): Ditto.
+
+2004-10-21 Conrad T. Pino <Conrad@Pino.com>
+
+ * libz.dsp: Add "crc32.h" and "inflate.h" to project.
+ Remove "infblock.c", "infblock.h", "infcodes.c", "infcodes.h",
+ "infutil.c", and "infutil.h" from project.
+ * libz.dep: Regenerated for "libz.dsp" changes.
+ * libz.mak: Regenerated for "libz.dsp" changes.
+
+2004-10-21 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in: Merge changes from zlib 1.2.1.
+ * Make_vms.com, Makefile.riscos, descrip.mms, infblock.c, infblock.h,
+ infcodes.c, infcodes.h, infutil.c, infutil.h, maketree.c, zlib.html,
+ contrib/asm386/gvmat32.asm, contrib/asm386/gvmat32c.c,
+ contrib/asm386/mkgvmt32.bat, contrib/asm386/zlibvc.def,
+ contrib/asm386/zlibvc.dsp, contrib/asm386/zlibvc.dsw,
+ contrib/delphi/zlib.mak, contrib/delphi/zlibdef.pas,
+ contrib/delphi2/d_zlib.bpr, contrib/delphi2/d_zlib.cpp,
+ contrib/delphi2/readme.txt, contrib/delphi2/zlib.bpg,
+ contrib/delphi2/zlib.bpr, contrib/delphi2/zlib.cpp,
+ contrib/delphi2/zlib.pas, contrib/delphi2/zlib32.bpr,
+ contrib/delphi2/zlib32.cpp, contrib/minizip/readme.txt,
+ contrib/minizip/unzip.def, contrib/minizip/zip.def,
+ contrib/minizip/zlibvc.def, contrib/minizip/zlibvc.dsp,
+ contrib/minizip/zlibvc.dsw, contrib/untgz/makefile.w32,
+ msdos/Makefile.b32, msdos/Makefile.w32, msdos/Makefile.wat,
+ msdos/zlib.def, msdos/zlib.rc, nt/Makefile.emx, nt/Makefile.gcc,
+ nt/Makefile.nt, nt/zlib.dnt, os2/Makefile.os2, os2/zlib.def: Merge file
+ removals from zlib 1.2.1.
+
+2004-10-05 Conrad T. Pino <Conrad@Pino.com>
+
+ * libz.mak: Regenerated for "../cvsnt.dsp" and "../lib/libcvs.dsp"
+ changes made 2004-10-05.
+
+2004-09-09 Conrad T. Pino <Conrad@Pino.com>
+
+ * libz.mak: Regenerated for "../cvsnt.dsp" changes made 2004-09-08.
+
+2004-07-13 Derek Price <derek@ximbiot.com>
+
+ * .cvsignore: Ignore GCC profiling data.
+
+2004-05-15 Derek Price <derek@ximbiot.com>
+
+ * libz.dsp: Header file list updated for GNULIB updates.
+ * libz.mak: Regenerated for "libz.dsp" changes.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-23 Derek Price <derek@ximbiot.com>
+
+ * zlib.mak: Regenerated.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (DISTFILES): Account for new MSVC project file names.
+
+2004-04-19 Derek Price <derek@ximbiot.com>
+
+ * libz.dsp: Drop "example.c" & "minigzip.c" from build.
+ * libz.dep, libz.dep: Regenerated for "libz.dsp" change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-17 Derek Price <derek@ximbiot.com>
+
+ * zlib.dep, zlib.dsp, zlib.mak: Move...
+ * libz.dep, libz.dsp, libz.mak: ...here.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * zlib.dsp: Set PROP BASE directories to projet standard,
+ remove child note property overrides which taken together
+ reduce file size and "Reset" function use project defaults.
+ * zlib.mak: Regenerated for zlib.dsp change.
+ (Patch from Conrad T. Pino <Conrad@Pino.com>.)
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (DISTFILES): Add zlib.dep.
+
+2004-04-15 Derek Price <derek@ximbiot.com>
+
+ * zlib.dep: New generated file.
+ * zlib.mak: Regenerated.
+ (Patch from Conrad T. Pino <conrad@pino.com>.)
+
+2004-04-14 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (EXTRA_DIST): Remove zlib.dep.
+
+2004-03-29 Derek Price <derek@ximbiot.com>
+
+ * zlib.mak: Regenerated with VC++ 5.0.
+ (Sent by Dennis Jones <djones@oregon.com>.)
+ * zlib.dep: Removed.
+
+2004-03-28 Derek Price <derek@ximbiot.com>
+
+ * zlib.mak: Regenerated.
+
+2004-03-26 Derek Price <derek@ximbiot.com>
+
+ * zlib.dep, zlib.mak: Repaired & egenerated.
+
+2004-03-25 Derek Price <derek@ximbiot.com>
+
+ * zlib.dep, zlib.mak: New files created by Visual C++ 6.0.
+ * zlib.dsp: Updated by Visual C++ 6.0.
+ * Makefile.in (DISTFILES): Add zlib.dep & zlib.mak.
+ * .cvsignore: Add and remove files for new MSVC++ setup.
+
+2003-08-07 Derek Price <derek@ximbiot.com>
+
+ * Makefile.in (pdf ps): New recursive targets to be ignored for
+ Automake's benefit.
+
+2001-09-04 Derek Price <dprice@collab.net>
+
+ * Makefile.in: Regenerated with automake 1.5.
+
+2001-08-07 Derek Price <derek.price@openavenue.com>
+
+ * Make_vms.com: Changes for VMS. I don't know why, but the rest made
+ sense and was verified by other users.
+ (Patch from Mike Marciniszyn <Mike.Marciniszyn@sanchez.com>.)
+
+2001-05-02 Larry Jones <larry.jones@sdrc.com>
+
+ * Makefile.in (DISTFILES): Re-add zlib.dsp.
+ (Reported by Dennis Jones <djones@oregon.com>.)
+
+2001-03-14 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in: Regenerated
+
+2000-12-21 Derek Price <derek.price@openavenue.com>
+
+ * .cvsignore: Added the foo.gz file created by 'make check'
+ * Makefile.in: Added support for Automake targets
+
+2000-10-31 Derek Price <derek.price@openavenue.com>
+
+ * Makefile.in (DISTFILES, test, libz.a): propogate local (CVS)
+ zlib mods to the most recent version of zlib (1.1.3).
+
+1999-05-06 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove zlib.mak.
+ * zlib.mak: Removed; we are back to a single makefile for
+ Visual C++ version 4.
+
+1999-04-26 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add zlib.dsp zlib.mak.
+
+1999-04-26 (submitted 1999-03-24) John O'Connor <john@shore.net>
+
+ * zlib.dsp: new file. MSVC project file used to build the library.
+
+ * zlib.mak: new file. Makefile for building from the command-line.
+
+ * .cvsignore: Added entries to ignore directories generated by the
+ NT build, Debug and Release.
+
+1999-02-24 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add .cvsignore.
+
+Tue Mar 18 13:05:37 1997 Jim Meyering <meyering@totoro.cyclic.com>
+
+ * Makefile.in (DISTFILES): Change glob pattern so that it doesn't
+ match `Makefile'. Add Make_vms.com explicitly.
+
+1997-01-01 Fred Fish <fnf@ninemoons.com>
+
+ * Makefile.in (CC): Use @CC@ rather than hard coded "cc".
+ (CFLAGS): Use @CFLAGS@ rather than hard coded "-O".
+ (LDFLAGS): Use @LDFLAGS@ rather than hard coded "-L. -lz".
+ (prefix): Use @prefix@ rather than hard coded "/usr/local".
+ (example, minigzip): Use $(LIBS) when linking.
+
+Wed Sep 11 00:59:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * build_zlib.com: Add infblock.c and infcodes.c.
+
+ * build_zlib.com: New file.
+
+ * Makefile.in (DISTFILES): Add build_zlib.com.
+
+Fri Aug 16 16:07:38 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * Makefile.in (installdirs): new (empty) target
+
+ ChangeLog file for zlib
+
+Changes in 1.2.3 (18 July 2005)
+- Apply security vulnerability fixes to contrib/infback9 as well
+- Clean up some text files (carriage returns, trailing space)
+- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]
+
+Changes in 1.2.2.4 (11 July 2005)
+- Add inflatePrime() function for starting inflation at bit boundary
+- Avoid some Visual C warnings in deflate.c
+- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit
+ compile
+- Fix some spelling errors in comments [Betts]
+- Correct inflateInit2() error return documentation in zlib.h
+- Added zran.c example of compressed data random access to examples
+ directory, shows use of inflatePrime()
+- Fix cast for assignments to strm->state in inflate.c and infback.c
+- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]
+- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]
+- Add cast in trees.c t avoid a warning [Oberhumer]
+- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]
+- Update make_vms.com [Zinser]
+- Initialize state->write in inflateReset() since copied in inflate_fast()
+- Be more strict on incomplete code sets in inflate_table() and increase
+ ENOUGH and MAXD -- this repairs a possible security vulnerability for
+ invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for
+ discovering the vulnerability and providing test cases.
+- Add ia64 support to configure for HP-UX [Smith]
+- Add error return to gzread() for format or i/o error [Levin]
+- Use malloc.h for OS/2 [Necasek]
+
+Changes in 1.2.2.3 (27 May 2005)
+- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile
+- Typecast fread() return values in gzio.c [Vollant]
+- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)
+- Fix crc check bug in gzread() after gzungetc() [Heiner]
+- Add the deflateTune() function to adjust internal compression parameters
+- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)
+- Remove an incorrect assertion in examples/zpipe.c
+- Add C++ wrapper in infback9.h [Donais]
+- Fix bug in inflateCopy() when decoding fixed codes
+- Note in zlib.h how much deflateSetDictionary() actually uses
+- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)
+- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]
+- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]
+- Add gzdirect() function to indicate transparent reads
+- Update contrib/minizip [Vollant]
+- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]
+- Add casts in crc32.c to avoid warnings [Oberhumer]
+- Add contrib/masmx64 [Vollant]
+- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]
+
+Changes in 1.2.2.2 (30 December 2004)
+- Replace structure assignments in deflate.c and inflate.c with zmemcpy to
+ avoid implicit memcpy calls (portability for no-library compilation)
+- Increase sprintf() buffer size in gzdopen() to allow for large numbers
+- Add INFLATE_STRICT to check distances against zlib header
+- Improve WinCE errno handling and comments [Chang]
+- Remove comment about no gzip header processing in FAQ
+- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
+- Add updated make_vms.com [Coghlan], update README
+- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
+ fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
+- Add FAQ entry and comments in deflate.c on uninitialized memory access
+- Add Solaris 9 make options in configure [Gilbert]
+- Allow strerror() usage in gzio.c for STDC
+- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]
+- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]
+- Use z_off_t for adler32_combine() and crc32_combine() lengths
+- Make adler32() much faster for small len
+- Use OS_CODE in deflate() default gzip header
+
+Changes in 1.2.2.1 (31 October 2004)
+- Allow inflateSetDictionary() call for raw inflate
+- Fix inflate header crc check bug for file names and comments
+- Add deflateSetHeader() and gz_header structure for custom gzip headers
+- Add inflateGetheader() to retrieve gzip headers
+- Add crc32_combine() and adler32_combine() functions
+- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list
+- Use zstreamp consistently in zlib.h (inflate_back functions)
+- Remove GUNZIP condition from definition of inflate_mode in inflate.h
+ and in contrib/inflate86/inffast.S [Truta, Anderson]
+- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]
+- Update projects/README.projects and projects/visualc6 [Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]
+- Deprecate Z_ASCII; use Z_TEXT instead [Truta]
+- Use a new algorithm for setting strm->data_type in trees.c [Truta]
+- Do not define an exit() prototype in zutil.c unless DEBUG defined
+- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]
+- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()
+- Fix Darwin build version identification [Peterson]
+
+Changes in 1.2.2 (3 October 2004)
+- Update zlib.h comments on gzip in-memory processing
+- Set adler to 1 in inflateReset() to support Java test suite [Walles]
+- Add contrib/dotzlib [Ravn]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update contrib/minizip [Vollant]
+- Move contrib/visual-basic.txt to old/ [Truta]
+- Fix assembler builds in projects/visualc6/ [Truta]
+
+Changes in 1.2.1.2 (9 September 2004)
+- Update INDEX file
+- Fix trees.c to update strm->data_type (no one ever noticed!)
+- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown]
+- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE)
+- Add limited multitasking protection to DYNAMIC_CRC_TABLE
+- Add NO_vsnprintf for VMS in zutil.h [Mozilla]
+- Don't declare strerror() under VMS [Mozilla]
+- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize
+- Update contrib/ada [Anisimkov]
+- Update contrib/minizip [Vollant]
+- Fix configure to not hardcode directories for Darwin [Peterson]
+- Fix gzio.c to not return error on empty files [Brown]
+- Fix indentation; update version in contrib/delphi/ZLib.pas and
+ contrib/pascal/zlibpas.pas [Truta]
+- Update mkasm.bat in contrib/masmx86 [Truta]
+- Update contrib/untgz [Truta]
+- Add projects/README.projects [Truta]
+- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta]
+- Remove an unnecessary assignment to curr in inftrees.c [Truta]
+- Add OS/2 to exe builds in configure [Poltorak]
+- Remove err dummy parameter in zlib.h [Kientzle]
+
+Changes in 1.2.1.1 (9 January 2004)
+- Update email address in README
+- Several FAQ updates
+- Fix a big fat bug in inftrees.c that prevented decoding valid
+ dynamic blocks with only literals and no distance codes --
+ Thanks to "Hot Emu" for the bug report and sample file
+- Add a note to puff.c on no distance codes case.
+
+Changes in 1.2.1 (17 November 2003)
+- Remove a tab in contrib/gzappend/gzappend.c
+- Update some interfaces in contrib for new zlib functions
+- Update zlib version number in some contrib entries
+- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
+- Support shared libraries on Hurd and KFreeBSD [Brown]
+- Fix error in NO_DIVIDE option of adler32.c
+
+Changes in 1.2.0.8 (4 November 2003)
+- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
+- Add experimental NO_DIVIDE #define in adler32.c
+ - Possibly faster on some processors (let me know if it is)
+- Correct Z_BLOCK to not return on first inflate call if no wrap
+- Fix strm->data_type on inflate() return to correctly indicate EOB
+- Add deflatePrime() function for appending in the middle of a byte
+- Add contrib/gzappend for an example of appending to a stream
+- Update win32/DLL_FAQ.txt [Truta]
+- Delete Turbo C comment in README [Truta]
+- Improve some indentation in zconf.h [Truta]
+- Fix infinite loop on bad input in configure script [Church]
+- Fix gzeof() for concatenated gzip files [Johnson]
+- Add example to contrib/visual-basic.txt [Michael B.]
+- Add -p to mkdir's in Makefile.in [vda]
+- Fix configure to properly detect presence or lack of printf functions
+- Add AS400 support [Monnerat]
+- Add a little Cygwin support [Wilson]
+
+Changes in 1.2.0.7 (21 September 2003)
+- Correct some debug formats in contrib/infback9
+- Cast a type in a debug statement in trees.c
+- Change search and replace delimiter in configure from % to # [Beebe]
+- Update contrib/untgz to 0.2 with various fixes [Truta]
+- Add build support for Amiga [Nikl]
+- Remove some directories in old that have been updated to 1.2
+- Add dylib building for Mac OS X in configure and Makefile.in
+- Remove old distribution stuff from Makefile
+- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
+- Update links in README
+
+Changes in 1.2.0.6 (13 September 2003)
+- Minor FAQ updates
+- Update contrib/minizip to 1.00 [Vollant]
+- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
+- Update POSTINC comment for 68060 [Nikl]
+- Add contrib/infback9 with deflate64 decoding (unsupported)
+- For MVS define NO_vsnprintf and undefine FAR [van Burik]
+- Add pragma for fdopen on MVS [van Burik]
+
+Changes in 1.2.0.5 (8 September 2003)
+- Add OF to inflateBackEnd() declaration in zlib.h
+- Remember start when using gzdopen in the middle of a file
+- Use internal off_t counters in gz* functions to properly handle seeks
+- Perform more rigorous check for distance-too-far in inffast.c
+- Add Z_BLOCK flush option to return from inflate at block boundary
+- Set strm->data_type on return from inflate
+ - Indicate bits unused, if at block boundary, and if in last block
+- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
+- Add condition so old NO_DEFLATE define still works for compatibility
+- FAQ update regarding the Windows DLL [Truta]
+- INDEX update: add qnx entry, remove aix entry [Truta]
+- Install zlib.3 into mandir [Wilson]
+- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
+- Adapt the zlib interface to the new DLL convention guidelines [Truta]
+- Introduce ZLIB_WINAPI macro to allow the export of functions using
+ the WINAPI calling convention, for Visual Basic [Vollant, Truta]
+- Update msdos and win32 scripts and makefiles [Truta]
+- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
+- Add contrib/ada [Anisimkov]
+- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
+- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
+- Add contrib/masm686 [Truta]
+- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
+ [Truta, Vollant]
+- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
+- Remove contrib/delphi2; add a new contrib/delphi [Truta]
+- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream,
+ and fix some method prototypes [Truta]
+- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
+ [Truta]
+- Avoid the use of backslash (\) in contrib/minizip [Vollant]
+- Fix file time handling in contrib/untgz; update makefiles [Truta]
+- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
+ [Vollant]
+- Remove contrib/vstudio/vc15_16 [Vollant]
+- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
+- Update README.contrib [Truta]
+- Invert the assignment order of match_head and s->prev[...] in
+ INSERT_STRING [Truta]
+- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
+ [Truta]
+- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
+- Fix prototype of syncsearch in inflate.c [Truta]
+- Introduce ASMINF macro to be enabled when using an ASM implementation
+ of inflate_fast [Truta]
+- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
+- Modify test_gzio in example.c to take a single file name as a
+ parameter [Truta]
+- Exit the example.c program if gzopen fails [Truta]
+- Add type casts around strlen in example.c [Truta]
+- Remove casting to sizeof in minigzip.c; give a proper type
+ to the variable compared with SUFFIX_LEN [Truta]
+- Update definitions of STDC and STDC99 in zconf.h [Truta]
+- Synchronize zconf.h with the new Windows DLL interface [Truta]
+- Use SYS16BIT instead of __32BIT__ to distinguish between
+ 16- and 32-bit platforms [Truta]
+- Use far memory allocators in small 16-bit memory models for
+ Turbo C [Truta]
+- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
+ zlibCompileFlags [Truta]
+- Cygwin has vsnprintf [Wilson]
+- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
+- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]
+
+Changes in 1.2.0.4 (10 August 2003)
+- Minor FAQ updates
+- Be more strict when checking inflateInit2's windowBits parameter
+- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
+- Add gzip wrapper option to deflateInit2 using windowBits
+- Add updated QNX rule in configure and qnx directory [Bonnefoy]
+- Make inflate distance-too-far checks more rigorous
+- Clean up FAR usage in inflate
+- Add casting to sizeof() in gzio.c and minigzip.c
+
+Changes in 1.2.0.3 (19 July 2003)
+- Fix silly error in gzungetc() implementation [Vollant]
+- Update contrib/minizip and contrib/vstudio [Vollant]
+- Fix printf format in example.c
+- Correct cdecl support in zconf.in.h [Anisimkov]
+- Minor FAQ updates
+
+Changes in 1.2.0.2 (13 July 2003)
+- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
+- Attempt to avoid warnings in crc32.c for pointer-int conversion
+- Add AIX to configure, remove aix directory [Bakker]
+- Add some casts to minigzip.c
+- Improve checking after insecure sprintf() or vsprintf() calls
+- Remove #elif's from crc32.c
+- Change leave label to inf_leave in inflate.c and infback.c to avoid
+ library conflicts
+- Remove inflate gzip decoding by default--only enable gzip decoding by
+ special request for stricter backward compatibility
+- Add zlibCompileFlags() function to return compilation information
+- More typecasting in deflate.c to avoid warnings
+- Remove leading underscore from _Capital #defines [Truta]
+- Fix configure to link shared library when testing
+- Add some Windows CE target adjustments [Mai]
+- Remove #define ZLIB_DLL in zconf.h [Vollant]
+- Add zlib.3 [Rodgers]
+- Update RFC URL in deflate.c and algorithm.txt [Mai]
+- Add zlib_dll_FAQ.txt to contrib [Truta]
+- Add UL to some constants [Truta]
+- Update minizip and vstudio [Vollant]
+- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
+- Expand use of NO_DUMMY_DECL to avoid all dummy structures
+- Added iostream3 to contrib [Schwardt]
+- Replace rewind() with fseek() for WinCE [Truta]
+- Improve setting of zlib format compression level flags
+ - Report 0 for huffman and rle strategies and for level == 0 or 1
+ - Report 2 only for level == 6
+- Only deal with 64K limit when necessary at compile time [Truta]
+- Allow TOO_FAR check to be turned off at compile time [Truta]
+- Add gzclearerr() function [Souza]
+- Add gzungetc() function
+
+Changes in 1.2.0.1 (17 March 2003)
+- Add Z_RLE strategy for run-length encoding [Truta]
+ - When Z_RLE requested, restrict matches to distance one
+ - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
+- Correct FASTEST compilation to allow level == 0
+- Clean up what gets compiled for FASTEST
+- Incorporate changes to zconf.in.h [Vollant]
+ - Refine detection of Turbo C need for dummy returns
+ - Refine ZLIB_DLL compilation
+ - Include additional header file on VMS for off_t typedef
+- Try to use _vsnprintf where it supplants vsprintf [Vollant]
+- Add some casts in inffast.c
+- Enchance comments in zlib.h on what happens if gzprintf() tries to
+ write more than 4095 bytes before compression
+- Remove unused state from inflateBackEnd()
+- Remove exit(0) from minigzip.c, example.c
+- Get rid of all those darn tabs
+- Add "check" target to Makefile.in that does the same thing as "test"
+- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
+- Update contrib/inflate86 [Anderson]
+- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]
+- Add msdos and win32 directories with makefiles [Truta]
+- More additions and improvements to the FAQ
+
+Changes in 1.2.0 (9 March 2003)
+- New and improved inflate code
+ - About 20% faster
+ - Does not allocate 32K window unless and until needed
+ - Automatically detects and decompresses gzip streams
+ - Raw inflate no longer needs an extra dummy byte at end
+ - Added inflateBack functions using a callback interface--even faster
+ than inflate, useful for file utilities (gzip, zip)
+ - Added inflateCopy() function to record state for random access on
+ externally generated deflate streams (e.g. in gzip files)
+ - More readable code (I hope)
+- New and improved crc32()
+ - About 50% faster, thanks to suggestions from Rodney Brown
+- Add deflateBound() and compressBound() functions
+- Fix memory leak in deflateInit2()
+- Permit setting dictionary for raw deflate (for parallel deflate)
+- Fix const declaration for gzwrite()
+- Check for some malloc() failures in gzio.c
+- Fix bug in gzopen() on single-byte file 0x1f
+- Fix bug in gzread() on concatenated file with 0x1f at end of buffer
+ and next buffer doesn't start with 0x8b
+- Fix uncompress() to return Z_DATA_ERROR on truncated input
+- Free memory at end of example.c
+- Remove MAX #define in trees.c (conflicted with some libraries)
+- Fix static const's in deflate.c, gzio.c, and zutil.[ch]
+- Declare malloc() and free() in gzio.c if STDC not defined
+- Use malloc() instead of calloc() in zutil.c if int big enough
+- Define STDC for AIX
+- Add aix/ with approach for compiling shared library on AIX
+- Add HP-UX support for shared libraries in configure
+- Add OpenUNIX support for shared libraries in configure
+- Use $cc instead of gcc to build shared library
+- Make prefix directory if needed when installing
+- Correct Macintosh avoidance of typedef Byte in zconf.h
+- Correct Turbo C memory allocation when under Linux
+- Use libz.a instead of -lz in Makefile (assure use of compiled library)
+- Update configure to check for snprintf or vsnprintf functions and their
+ return value, warn during make if using an insecure function
+- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that
+ is lost when library is used--resolution is to build new zconf.h
+- Documentation improvements (in zlib.h):
+ - Document raw deflate and inflate
+ - Update RFCs URL
+ - Point out that zlib and gzip formats are different
+ - Note that Z_BUF_ERROR is not fatal
+ - Document string limit for gzprintf() and possible buffer overflow
+ - Note requirement on avail_out when flushing
+ - Note permitted values of flush parameter of inflate()
+- Add some FAQs (and even answers) to the FAQ
+- Add contrib/inflate86/ for x86 faster inflate
+- Add contrib/blast/ for PKWare Data Compression Library decompression
+- Add contrib/puff/ simple inflate for deflate format description
+
+Changes in 1.1.4 (11 March 2002)
+- ZFREE was repeated on same allocation on some error conditions.
+ This creates a security problem described in
+ http://www.zlib.org/advisory-2002-03-11.txt
+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
+- Avoid accesses before window for invalid distances with inflate window
+ less than 32K.
+- force windowBits > 8 to avoid a bug in the encoder for a window size
+ of 256 bytes. (A complete fix will be available in 1.1.5).
+
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+ occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+ (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean" (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+ . zutil.c, zutil.h: added "const" for zmem*
+ . Make_vms.com: fixed some typos
+ . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+ . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+ . msdos/Makefile.*: use model-dependent name for the built zlib library
+ . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+ new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+ See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+ completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+ (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+ compression ratio on some files. This also allows inlining _tr_tally for
+ matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+ on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+ the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+ them at run time (thanks to Ken Raeburn for this suggestion). To create
+ trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+ gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occurring only with compression level 0 (thanks to
+ Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+ (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+ (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+ inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+ contrib/asm386/ by Gilles Vollant <info@winimage.com>
+ 386 asm code replacing longest_match().
+ contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+ A C++ I/O streams interface to the zlib gz* functions
+ contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
+ Another C++ I/O streams interface
+ contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ A very simple tar.gz file extractor using zlib
+ contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+ How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+ level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+ (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+ bit, so the decompressor could decompress all the correct data but went
+ on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+ small and medium models; this makes the library incompatible with previous
+ versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+ avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+ Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+ and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+ -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+ warning C4746: 'inflate_mask' : unsized array treated as '__far'
+ (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+ not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+ (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+ typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+ was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+ pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+ is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+ (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+ TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+ (one's complement) is now done inside crc32(). WARNING: this is
+ incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+ not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+ Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+ if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+ user-provided history buffer. This is supported only in deflateInit2
+ and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
diff --git a/zlib/FAQ b/zlib/FAQ
new file mode 100644
index 0000000..441d910
--- /dev/null
+++ b/zlib/FAQ
@@ -0,0 +1,339 @@
+
+ Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page
+http://www.zlib.org which may have more recent information.
+The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
+
+
+ 1. Is zlib Y2K-compliant?
+
+ Yes. zlib doesn't handle dates.
+
+ 2. Where can I get a Windows DLL version?
+
+ The zlib sources can be compiled without change to produce a DLL.
+ See the file win32/DLL_FAQ.txt in the zlib distribution.
+ Pointers to the precompiled DLL are found in the zlib web site at
+ http://www.zlib.org.
+
+ 3. Where can I get a Visual Basic interface to zlib?
+
+ See
+ * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm
+ * contrib/visual-basic.txt in the zlib distribution
+ * win32/DLL_FAQ.txt in the zlib distribution
+
+ 4. compress() returns Z_BUF_ERROR.
+
+ Make sure that before the call of compress, the length of the compressed
+ buffer is equal to the total size of the compressed buffer and not
+ zero. For Visual Basic, check that this parameter is passed by reference
+ ("as any"), not by value ("as long").
+
+ 5. deflate() or inflate() returns Z_BUF_ERROR.
+
+ Before making the call, make sure that avail_in and avail_out are not
+ zero. When setting the parameter flush equal to Z_FINISH, also make sure
+ that avail_out is big enough to allow processing all pending input.
+ Note that a Z_BUF_ERROR is not fatal--another call to deflate() or
+ inflate() can be made with more input or output space. A Z_BUF_ERROR
+ may in fact be unavoidable depending on how the functions are used, since
+ it is not possible to tell whether or not there is more output pending
+ when strm.avail_out returns with zero.
+
+ 6. Where's the zlib documentation (man pages, etc.)?
+
+ It's in zlib.h for the moment, and Francis S. Lin has converted it to a
+ web page zlib.html. Volunteers to transform this to Unix-style man pages,
+ please contact us (zlib@gzip.org). Examples of zlib usage are in the files
+ example.c and minigzip.c.
+
+ 7. Why don't you use GNU autoconf or libtool or ...?
+
+ Because we would like to keep zlib as a very small and simple
+ package. zlib is rather portable and doesn't need much configuration.
+
+ 8. I found a bug in zlib.
+
+ Most of the time, such problems are due to an incorrect usage of
+ zlib. Please try to reproduce the problem with a small program and send
+ the corresponding source to us at zlib@gzip.org . Do not send
+ multi-megabyte data files without prior agreement.
+
+ 9. Why do I get "undefined reference to gzputc"?
+
+ If "make test" produces something like
+
+ example.o(.text+0x154): undefined reference to `gzputc'
+
+ check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
+ /usr/X11R6/lib. Remove any old versions, then do "make install".
+
+10. I need a Delphi interface to zlib.
+
+ See the contrib/delphi directory in the zlib distribution.
+
+11. Can zlib handle .zip archives?
+
+ Not by itself, no. See the directory contrib/minizip in the zlib
+ distribution.
+
+12. Can zlib handle .Z files?
+
+ No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
+ the code of uncompress on your own.
+
+13. How can I make a Unix shared library?
+
+ make clean
+ ./configure -s
+ make
+
+14. How do I install a shared zlib library on Unix?
+
+ After the above, then:
+
+ make install
+
+ However, many flavors of Unix come with a shared zlib already installed.
+ Before going to the trouble of compiling a shared version of zlib and
+ trying to install it, you may want to check if it's already there! If you
+ can #include <zlib.h>, it's there. The -lz option will probably link to it.
+
+15. I have a question about OttoPDF.
+
+ We are not the authors of OttoPDF. The real author is on the OttoPDF web
+ site: Joel Hainley, jhainley@myndkryme.com.
+
+16. Can zlib decode Flate data in an Adobe PDF file?
+
+ Yes. See http://www.fastio.com/ (ClibPDF), or http://www.pdflib.com/ .
+ To modify PDF forms, see http://sourceforge.net/projects/acroformtool/ .
+
+17. Why am I getting this "register_frame_info not found" error on Solaris?
+
+ After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib
+ generates an error such as:
+
+ ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so:
+ symbol __register_frame_info: referenced symbol not found
+
+ The symbol __register_frame_info is not part of zlib, it is generated by
+ the C compiler (cc or gcc). You must recompile applications using zlib
+ which have this problem. This problem is specific to Solaris. See
+ http://www.sunfreeware.com for Solaris versions of zlib and applications
+ using zlib.
+
+18. Why does gzip give an error on a file I make with compress/deflate?
+
+ The compress and deflate functions produce data in the zlib format, which
+ is different and incompatible with the gzip format. The gz* functions in
+ zlib on the other hand use the gzip format. Both the zlib and gzip
+ formats use the same compressed data format internally, but have different
+ headers and trailers around the compressed data.
+
+19. Ok, so why are there two different formats?
+
+ The gzip format was designed to retain the directory information about
+ a single file, such as the name and last modification date. The zlib
+ format on the other hand was designed for in-memory and communication
+ channel applications, and has a much more compact header and trailer and
+ uses a faster integrity check than gzip.
+
+20. Well that's nice, but how do I make a gzip file in memory?
+
+ You can request that deflate write the gzip format instead of the zlib
+ format using deflateInit2(). You can also request that inflate decode
+ the gzip format using inflateInit2(). Read zlib.h for more details.
+
+21. Is zlib thread-safe?
+
+ Yes. However any library routines that zlib uses and any application-
+ provided memory allocation routines must also be thread-safe. zlib's gz*
+ functions use stdio library routines, and most of zlib's functions use the
+ library memory allocation routines by default. zlib's Init functions allow
+ for the application to provide custom memory allocation routines.
+
+ Of course, you should only operate on any given zlib or gzip stream from a
+ single thread at a time.
+
+22. Can I use zlib in my commercial application?
+
+ Yes. Please read the license in zlib.h.
+
+23. Is zlib under the GNU license?
+
+ No. Please read the license in zlib.h.
+
+24. The license says that altered source versions must be "plainly marked". So
+ what exactly do I need to do to meet that requirement?
+
+ You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
+ particular, the final version number needs to be changed to "f", and an
+ identification string should be appended to ZLIB_VERSION. Version numbers
+ x.x.x.f are reserved for modifications to zlib by others than the zlib
+ maintainers. For example, if the version of the base zlib you are altering
+ is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
+ ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
+ update the version strings in deflate.c and inftrees.c.
+
+ For altered source distributions, you should also note the origin and
+ nature of the changes in zlib.h, as well as in ChangeLog and README, along
+ with the dates of the alterations. The origin should include at least your
+ name (or your company's name), and an email address to contact for help or
+ issues with the library.
+
+ Note that distributing a compiled zlib library along with zlib.h and
+ zconf.h is also a source distribution, and so you should change
+ ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
+ in zlib.h as you would for a full source distribution.
+
+25. Will zlib work on a big-endian or little-endian architecture, and can I
+ exchange compressed data between them?
+
+ Yes and yes.
+
+26. Will zlib work on a 64-bit machine?
+
+ It should. It has been tested on 64-bit machines, and has no dependence
+ on any data types being limited to 32-bits in length. If you have any
+ difficulties, please provide a complete problem report to zlib@gzip.org
+
+27. Will zlib decompress data from the PKWare Data Compression Library?
+
+ No. The PKWare DCL uses a completely different compressed data format
+ than does PKZIP and zlib. However, you can look in zlib's contrib/blast
+ directory for a possible solution to your problem.
+
+28. Can I access data randomly in a compressed stream?
+
+ No, not without some preparation. If when compressing you periodically
+ use Z_FULL_FLUSH, carefully write all the pending data at those points,
+ and keep an index of those locations, then you can start decompression
+ at those points. You have to be careful to not use Z_FULL_FLUSH too
+ often, since it can significantly degrade compression.
+
+29. Does zlib work on MVS, OS/390, CICS, etc.?
+
+ We don't know for sure. We have heard occasional reports of success on
+ these systems. If you do use it on one of these, please provide us with
+ a report, instructions, and patches that we can reference when we get
+ these questions. Thanks.
+
+30. Is there some simpler, easier to read version of inflate I can look at
+ to understand the deflate format?
+
+ First off, you should read RFC 1951. Second, yes. Look in zlib's
+ contrib/puff directory.
+
+31. Does zlib infringe on any patents?
+
+ As far as we know, no. In fact, that was originally the whole point behind
+ zlib. Look here for some more information:
+
+ http://www.gzip.org/#faq11
+
+32. Can zlib work with greater than 4 GB of data?
+
+ Yes. inflate() and deflate() will process any amount of data correctly.
+ Each call of inflate() or deflate() is limited to input and output chunks
+ of the maximum value that can be stored in the compiler's "unsigned int"
+ type, but there is no limit to the number of chunks. Note however that the
+ strm.total_in and strm_total_out counters may be limited to 4 GB. These
+ counters are provided as a convenience and are not used internally by
+ inflate() or deflate(). The application can easily set up its own counters
+ updated after each call of inflate() or deflate() to count beyond 4 GB.
+ compress() and uncompress() may be limited to 4 GB, since they operate in a
+ single call. gzseek() and gztell() may be limited to 4 GB depending on how
+ zlib is compiled. See the zlibCompileFlags() function in zlib.h.
+
+ The word "may" appears several times above since there is a 4 GB limit
+ only if the compiler's "long" type is 32 bits. If the compiler's "long"
+ type is 64 bits, then the limit is 16 exabytes.
+
+33. Does zlib have any security vulnerabilities?
+
+ The only one that we are aware of is potentially in gzprintf(). If zlib
+ is compiled to use sprintf() or vsprintf(), then there is no protection
+ against a buffer overflow of a 4K string space, other than the caller of
+ gzprintf() assuring that the output will not exceed 4K. On the other
+ hand, if zlib is compiled to use snprintf() or vsnprintf(), which should
+ normally be the case, then there is no vulnerability. The ./configure
+ script will display warnings if an insecure variation of sprintf() will
+ be used by gzprintf(). Also the zlibCompileFlags() function will return
+ information on what variant of sprintf() is used by gzprintf().
+
+ If you don't have snprintf() or vsnprintf() and would like one, you can
+ find a portable implementation here:
+
+ http://www.ijs.si/software/snprintf/
+
+ Note that you should be using the most recent version of zlib. Versions
+ 1.1.3 and before were subject to a double-free vulnerability.
+
+34. Is there a Java version of zlib?
+
+ Probably what you want is to use zlib in Java. zlib is already included
+ as part of the Java SDK in the java.util.zip package. If you really want
+ a version of zlib written in the Java language, look on the zlib home
+ page for links: http://www.zlib.org/
+
+35. I get this or that compiler or source-code scanner warning when I crank it
+ up to maximally-pedantic. Can't you guys write proper code?
+
+ Many years ago, we gave up attempting to avoid warnings on every compiler
+ in the universe. It just got to be a waste of time, and some compilers
+ were downright silly. So now, we simply make sure that the code always
+ works.
+
+36. Valgrind (or some similar memory access checker) says that deflate is
+ performing a conditional jump that depends on an uninitialized value.
+ Isn't that a bug?
+
+ No. That is intentional for performance reasons, and the output of
+ deflate is not affected. This only started showing up recently since
+ zlib 1.2.x uses malloc() by default for allocations, whereas earlier
+ versions used calloc(), which zeros out the allocated memory.
+
+37. Will zlib read the (insert any ancient or arcane format here) compressed
+ data format?
+
+ Probably not. Look in the comp.compression FAQ for pointers to various
+ formats and associated software.
+
+38. How can I encrypt/decrypt zip files with zlib?
+
+ zlib doesn't support encryption. The original PKZIP encryption is very weak
+ and can be broken with freely available programs. To get strong encryption,
+ use GnuPG, http://www.gnupg.org/ , which already includes zlib compression.
+ For PKZIP compatible "encryption", look at http://www.info-zip.org/
+
+39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
+
+ "gzip" is the gzip format, and "deflate" is the zlib format. They should
+ probably have called the second one "zlib" instead to avoid confusion
+ with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
+ correctly points to the zlib specification in RFC 1950 for the "deflate"
+ transfer encoding, there have been reports of servers and browsers that
+ incorrectly produce or expect raw deflate data per the deflate
+ specficiation in RFC 1951, most notably Microsoft. So even though the
+ "deflate" transfer encoding using the zlib format would be the more
+ efficient approach (and in fact exactly what the zlib format was designed
+ for), using the "gzip" transfer encoding is probably more reliable due to
+ an unfortunate choice of name on the part of the HTTP 1.1 authors.
+
+ Bottom line: use the gzip format for HTTP 1.1 encoding.
+
+40. Does zlib support the new "Deflate64" format introduced by PKWare?
+
+ No. PKWare has apparently decided to keep that format proprietary, since
+ they have not documented it as they have previous compression formats.
+ In any case, the compression improvements are so modest compared to other
+ more modern approaches, that it's not worth the effort to implement.
+
+41. Can you please sign these lengthy legal documents and fax them back to us
+ so that we can use your software in our product?
+
+ No. Go away. Shoo.
diff --git a/zlib/INDEX b/zlib/INDEX
new file mode 100644
index 0000000..0587e59
--- /dev/null
+++ b/zlib/INDEX
@@ -0,0 +1,51 @@
+ChangeLog history of changes
+FAQ Frequently Asked Questions about zlib
+INDEX this file
+Makefile makefile for Unix (generated by configure)
+Makefile.in makefile for Unix (template for configure)
+README guess what
+algorithm.txt description of the (de)compression algorithm
+configure configure script for Unix
+zconf.in.h template for zconf.h (used by configure)
+
+amiga/ makefiles for Amiga SAS C
+as400/ makefiles for IBM AS/400
+msdos/ makefiles for MSDOS
+old/ makefiles for various architectures and zlib documentation
+ files that have not yet been updated for zlib 1.2.x
+projects/ projects for various Integrated Development Environments
+qnx/ makefiles for QNX
+win32/ makefiles for Windows
+
+ zlib public header files (must be kept):
+zconf.h
+zlib.h
+
+ private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+crc32.h
+deflate.c
+deflate.h
+gzio.c
+infback.c
+inffast.c
+inffast.h
+inffixed.h
+inflate.c
+inflate.h
+inftrees.c
+inftrees.h
+trees.c
+trees.h
+uncompr.c
+zutil.c
+zutil.h
+
+ source files for sample programs:
+example.c
+minigzip.c
+
+ unsupported contribution by third parties
+See contrib/README.contrib
diff --git a/zlib/Makefile.b32 b/zlib/Makefile.b32
new file mode 100644
index 0000000..fc3ac68
--- /dev/null
+++ b/zlib/Makefile.b32
@@ -0,0 +1,104 @@
+# Makefile for zlib
+# Borland C++
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Borland C 4.5x with the Dos Power Pack for a 32-bit protected mode
+# flat memory model. It was created for use with POV-Ray ray tracer and
+# you may choose to edit the CFLAGS to suit your needs but the
+# switches -WX and -DMSDOS are required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "make -fmakefile.b32"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Borland C++ -------------
+MODEL=-WX
+CFLAGS= $(MODEL) -P-C -K -N- -k- -d -3 -r- -v- -f -DMSDOS
+CC=bcc32
+LD=bcc32
+LIB=tlib
+LDFLAGS= $(MODEL)
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ del zlib.lib
+ $(LIB) zlib +$(OBJP1)
+ $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/zlib/Makefile.bor b/zlib/Makefile.bor
new file mode 100644
index 0000000..2116563
--- /dev/null
+++ b/zlib/Makefile.bor
@@ -0,0 +1,105 @@
+# Makefile for zlib
+# Borland C++ ************ UNTESTED ***********
+
+# To use, do "make -fmakefile.bor"
+# To compile in small model, set below: MODEL=-ms
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C++, Borland C++ -------------
+MODEL=-ml
+CFLAGS=-O2 -Z $(MODEL)
+CC=bcc
+LD=bcc
+LIB=tlib
+# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version
+LDFLAGS=$(MODEL)
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ del zlib.lib
+ $(LIB) zlib +$(OBJP1)
+ $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/zlib/Makefile.dj2 b/zlib/Makefile.dj2
new file mode 100644
index 0000000..398f28b
--- /dev/null
+++ b/zlib/Makefile.dj2
@@ -0,0 +1,93 @@
+# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96.
+# Copyright (C) 1995-1996 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.dj2; make test -fmakefile.dj2
+#
+# To install libz.a, zconf.h and zlib.h in the djgpp directories, type:
+#
+# make install -fmakefile.dj2
+#
+# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as
+# in the sample below if the pattern of the DJGPP distribution is to
+# be followed. Remember that, while <sp>'es around <=> are ignored in
+# makefiles, they are *not* in batch files or in djgpp.env.
+# - - - - -
+# [make]
+# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include
+# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib
+# BUTT=-m486
+# - - - - -
+# Alternately, these variables may be defined below, overriding the values
+# in djgpp.env, as
+INCLUDE_PATH=c:\usr\include
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is not found, replace with copy /Y .
+CP=cp -f
+# If install.exe is not found, replace with $(CP).
+INSTALL=install
+# The default value of RM is "rm -f." If "rm.exe" is not found, uncomment:
+# RM=del
+LDLIBS=-L. -lz
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+libz.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env .
+
+.PHONY : uninstall clean
+
+install: $(INCL) $(LIBS)
+ -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH)
+ -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH)
+ for %%f in ($(INCL)) do $(INSTALL) %%f $(INCLUDE_PATH)
+ for %%p in ($(LIBS)) do $(INSTALL) %%p $(LIBRARY_PATH)
+
+uninstall:
+ for %%f in ($(INCL)) do $(RM) $(INCLUDE_PATH)\%%f
+ for %%p in ($(LIBS)) do $(RM) $(LIBRARY_PATH)\%%p
+
+clean:
+ for %%p in (*.d *.o *.exe libz.a libz.so* foo.gz) do $(RM) %%p
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/zlib/Makefile.in b/zlib/Makefile.in
new file mode 100644
index 0000000..1c13dcc
--- /dev/null
+++ b/zlib/Makefile.in
@@ -0,0 +1,275 @@
+# Makefile for zlib
+# Copyright (C) 1995-2005 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To use the asm code, type:
+# cp contrib/asm?86/match.S ./match.S
+# make LOC=-DASMV OBJA=match.o
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=@CC@
+
+CFLAGS=@CFLAGS@
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=libz.a @LDFLAGS@
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+LIBS=libz.a
+SHAREDLIB=libz.so
+SHAREDLIBV=libz.so.1.2.3
+SHAREDLIBM=libz.so.1
+
+# For CVS, separate AR and ARFLAGS.
+AR=ar
+RANLIB=@RANLIB@
+AMTAR=@AMTAR@
+SHELL=/bin/sh
+EXE=
+
+prefix=@prefix@
+exec_prefix = $(prefix)
+libdir = ${exec_prefix}/lib
+includedir = ${prefix}/include
+mandir = ${prefix}/share/man
+man3dir = ${mandir}/man3
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README FAQ INDEX ChangeLog configure Makefile.* *.[ch] \
+ make_vms.com algorithm.txt zlib.3 \
+ amiga/[a-z0-9ABD-Z]* \
+ as400/[a-z0-9ABD-Z]* \
+ msdos/[a-z0-9ABD-Z]* \
+ qnx/package.qpg \
+ win32/[a-z0-9ABD-Z]* \
+ contrib/RE*.contrib \
+ contrib/ada/[a-z0-9]* \
+ contrib/asm586/match.S contrib/asm586/README.586 \
+ contrib/asm686/match.S contrib/asm686/README.686 \
+ contrib/blast/[a-z0-9ABD-Z]* \
+ contrib/delphi/[a-z0-9ABD-Z]* \
+ contrib/infback9/[a-z0-9ABD-Z]* \
+ contrib/inflate86/[a-z0-9ABD-Z]* \
+ contrib/iostream/[a-z0-9ABD-Z]* \
+ contrib/iostream2/[a-z0-9ABD-Z]* \
+ contrib/iostream3/[a-z0-9ABD-Z]* \
+ contrib/masm686/[a-z0-9ABD-Z]* \
+ contrib/masmx64/[a-z0-9ABD-Z]* \
+ contrib/masmx86/[a-z0-9ABD-Z]* \
+ contrib/minizip/[a-z0-9ABD-Z]* contrib/minizip/Ch* \
+ contrib/pascal/[a-z0-9ABD-Z]* \
+ contrib/puff/[a-z0-9ABD-Z]* \
+ contrib/testzlib/[a-z0-9ABD-Z]* \
+ contrib/untgz/[a-z0-9ABD-Z]* \
+ contrib/vstudio/readme.txt \
+ contrib/vstudio/vc7/[a-z0-9ABD-Z]* \
+ contrib/vstudio/vc8/[a-z0-9ABD-Z]* \
+ old/[a-np-z0-9ABD-Z]* old/os2/[a-z0-9ABD-Z]* \
+ examples/[a-z0-9ABD-Z]* \
+ libz.dep libz.dsp libz.mak .cvsignore
+
+# for CVS's distdir & Makefile targets
+subdir = zlib
+
+# For CVS, just build libz.a
+all: libz.a
+
+# To reenable make test
+all-original: example$(EXE) minigzip$(EXE)
+
+check test: all-original
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+# For CVS, use an explict rc after $(AR).
+libz.a: $(OBJS) $(OBJA)
+ $(AR) rc $@ $(OBJS) $(OBJA)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+$(SHAREDLIBV): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f $(SHAREDLIB) $(SHAREDLIBM)
+ ln -s $@ $(SHAREDLIB)
+ ln -s $@ $(SHAREDLIBM)
+
+example$(EXE): example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip$(EXE): minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+# For CVS, make install dependant on all and remove the uninstall target.
+install: all
+uninstall:
+.PHONY: install uninstall
+
+# Remove targets for CVS
+dvi info pdf ps:
+.PHONY: dvi info pdf ps
+installcheck:
+.PHONY: installcheck
+
+#install: $(LIBS)
+# -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi
+# -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi
+# -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi
+# -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi
+# cp zlib.h zconf.h $(includedir)
+# chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+# cp $(LIBS) $(libdir)
+# cd $(libdir); chmod 755 $(LIBS)
+# -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+# cd $(libdir); if test -f $(SHAREDLIBV); then \
+# rm -f $(SHAREDLIB) $(SHAREDLIBM); \
+# ln -s $(SHAREDLIBV) $(SHAREDLIB); \
+# ln -s $(SHAREDLIBV) $(SHAREDLIBM); \
+# (ldconfig || true) >/dev/null 2>&1; \
+# fi
+# cp zlib.3 $(man3dir)
+# chmod 644 $(man3dir)/zlib.3
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+#uninstall:
+# cd $(includedir); \
+# cd $(libdir); rm -f libz.a; \
+# if test -f $(SHAREDLIBV); then \
+# rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
+# fi
+# cd $(man3dir); rm -f zlib.3
+
+installdirs:
+.PHONY: installdirs
+
+# distdir added for CVS.
+top_builddir = ..
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir:
+ @d=$(srcdir); \
+ for file in `cd $$d; echo $(DISTFILES)`; do \
+ if test -d $(distdir)/`dirname $$file`; then \
+ :; \
+ else \
+ mkdir $(distdir)/`dirname $$file`; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+.PHONY: distdir
+
+mostlyclean: clean
+clean:
+ rm -f *.o *~ example$(EXE) minigzip$(EXE) \
+ libz.a libz.so* foo.gz so_locations \
+ _match.s maketree contrib/infback9/*.o \
+ tags
+.PHONY: mostlyclean clean
+
+realclean: distclean
+maintainer-clean: distclean
+distclean: clean
+ rm -f Makefile .DS_Store
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c contrib/minizip/test.zip
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c contrib/minizip/test.zip
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(AMTAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+.PHONY: tags
+tags: TAGS
+
+TAGS:
+ tags=; \
+ here=`pwd`; \
+ list=`(echo *.[ch] && cd $(srcdir) && echo *.[ch]) |sort |uniq`; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+# Makefile target added for CVS.
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/zlib/Makefile.msc b/zlib/Makefile.msc
new file mode 100644
index 0000000..112684a
--- /dev/null
+++ b/zlib/Makefile.msc
@@ -0,0 +1,101 @@
+# Makefile for zlib
+# Microsoft C 5.1 or later
+
+# To use, do "make makefile.msc"
+# To compile in small model, set below: MODEL=-AS
+
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Microsoft C 5.1 and later -------------
+MODEL=-AL
+CFLAGS=-Oait -Gs -nologo -W3 $(MODEL)
+#-Ox generates bad code with MSC 5.1
+CC=cl
+LD=link
+LDFLAGS=/e/st:0x1000/noe
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: zlib.lib example.exe minigzip.exe
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ if exist zlib.lib del zlib.lib
+ lib zlib $(OBJ1);
+ lib zlib $(OBJ2);
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj,,,zlib.lib;
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj,,,zlib.lib;
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/zlib/Makefile.sas b/zlib/Makefile.sas
new file mode 100644
index 0000000..5323e82
--- /dev/null
+++ b/zlib/Makefile.sas
@@ -0,0 +1,64 @@
+# SMakefile for zlib
+# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
+# Osma Ahvenlampi <Osma.Ahvenlampi@hut.fi>
+# Amiga, SAS/C 6.56 & Smake
+
+CC=sc
+CFLAGS=OPT
+#CFLAGS=OPT CPU=68030
+#CFLAGS=DEBUG=LINE
+LDFLAGS=LIB z.lib
+
+SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
+ NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: SCOPTIONS example minigzip
+
+test: all
+ `cd`/example
+ echo hello world | minigzip | minigzip -d
+
+install: z.lib
+ copy zlib.h zconf.h INCLUDE: clone
+ copy z.lib LIB: clone
+
+z.lib: $(OBJS)
+ oml z.lib r $(OBJS)
+
+example: example.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
+
+clean:
+ -delete force quiet *.o example minigzip z.lib foo.gz *.lnk SCOPTIONS
+
+SCOPTIONS: Smakefile
+ copy to $@ <from <
+$(SCOPTIONS)
+<
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zutil.h zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zutil.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.o: zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/zlib/Makefile.tc b/zlib/Makefile.tc
new file mode 100644
index 0000000..a46ce73
--- /dev/null
+++ b/zlib/Makefile.tc
@@ -0,0 +1,105 @@
+# Makefile for zlib
+# TurboC 2.0
+
+# To use, do "make -fmakefile.tc"
+# To compile in small model, set below: MODEL=-ms
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C 2.0 -------------
+MODEL=-ml
+# CFLAGS=-O2 -G -Z $(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+CFLAGS=-O2 -G -Z $(MODEL)
+CC=tcc -I\tc\include
+LD=tcc -L\tc\lib
+LIB=tlib
+LDFLAGS=$(MODEL) -f-
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ del zlib.lib
+ $(LIB) zlib +$(OBJP1)
+ $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) -eexample.exe example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) -eminigzip.exe minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/zlib/Makefile.wat b/zlib/Makefile.wat
new file mode 100644
index 0000000..2a3b629
--- /dev/null
+++ b/zlib/Makefile.wat
@@ -0,0 +1,103 @@
+# Makefile for zlib
+# Watcom 10a
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Watcom 10a 32-bit protected mode flat memory model. It was created
+# for use with POV-Ray ray tracer and you may choose to edit the CFLAGS to
+# suit your needs but the -DMSDOS is required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "wmake -f makefile.wat"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Watcom 10a -------------
+MODEL=-mf
+CFLAGS= $(MODEL) -fpi87 -fp5 -zp4 -5r -w5 -oneatx -DMSDOS
+CC=wcc386
+LD=wcl386
+LIB=wlib -b -c
+LDFLAGS=
+O=.obj
+
+# variables
+OBJ1=adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O)
+OBJ2=trees$(O) zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O)
+OBJ3=infutil$(O) inffast$(O)
+OBJP1=adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)
+OBJP2=trees$(O)+zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)
+OBJP3=infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h &
+ infcodes.h infutil.h
+ $(CC) $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h &
+ infcodes.h inffast.h
+ $(CC) $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2) $(OBJ3)
+ del zlib.lib
+ $(LIB) zlib.lib +$(OBJP1)
+ $(LIB) zlib.lib +$(OBJP2)
+ $(LIB) zlib.lib +$(OBJP3)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: minigzip.exe example.exe
+ example
+ echo hello world | minigzip | minigzip -d >test
+ type test
+
+#clean:
+# del *.obj
+# del *.exe
diff --git a/zlib/README b/zlib/README
new file mode 100644
index 0000000..758cc50
--- /dev/null
+++ b/zlib/README
@@ -0,0 +1,125 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.3 is a general purpose data compression library. All the code is
+thread safe. The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
+and rfc1952.txt (gzip format). These documents are also available in other
+formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file example.c which also tests that the library
+is working correctly. Another example is given in the file minigzip.c. The
+compression library itself is composed of all source files except example.c and
+minigzip.c.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile. In short "make test; make install" should work for most
+machines. For Unix: "./configure; make test; make install". For MSDOS, use one
+of the special makefiles such as Makefile.msc. For VMS, use make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version. The zlib home page is
+http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
+please check this site to verify that you have the latest version of zlib;
+otherwise get the latest version and check whether the problem still exists or
+not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
+for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.2.3 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the
+CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is
+availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+ -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+ compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+ when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+ necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+ other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+- When building a shared, i.e. dynamic library on Mac OS X, the library must be
+ installed before testing (do "make install" before "make test"), since the
+ library location is specified in the library.
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate
+ and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib;
+ they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
diff --git a/zlib/adler32.c b/zlib/adler32.c
new file mode 100644
index 0000000..007ba26
--- /dev/null
+++ b/zlib/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 > BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
diff --git a/zlib/algorithm.txt b/zlib/algorithm.txt
new file mode 100644
index 0000000..b022dde
--- /dev/null
+++ b/zlib/algorithm.txt
@@ -0,0 +1,209 @@
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data. The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length). Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes. (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The key question is how to represent a Huffman code (or any prefix code) so
+that you can decode fast. The most important characteristic is that shorter
+codes are much more common than longer codes, so pay attention to decoding the
+short codes fast, and let the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code. It gets that many bits from the
+stream, and looks it up in the table. The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table. If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code. However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table. What inflate() does is
+simply to make the number of bits in the first table a variable, and then
+to set that variable for the maximum speed.
+
+For inflate, which has 286 possible codes for the literal/length tree, the size
+of the first table is nine bits. Also the distance trees have 30 possible
+values, and the size of the first table is six bits. Note that for each of
+those cases, the table ended up one bit longer than the ``average'' code
+length, i.e. the code length of an approximately flat code which would be a
+little more than eight bits for 286 symbols and a little less than five bits
+for 30 symbols.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually
+looks like. You are correct that it's not a Huffman tree. It is simply a
+lookup table for the first, let's say, nine bits of a Huffman symbol. The
+symbol could be as short as one bit or as long as 15 bits. If a particular
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits. For example, if the
+symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points
+to another similar table for the remaining bits. Again, there are duplicated
+entries as needed. The idea is that most of the time the symbol will be short
+and there will only be one table look up. (That's whole idea behind data
+compression in the first place.) For the less frequent long symbols, there
+will be two lookups. If you had a compression method with really long
+symbols, you could have as many levels of lookups as is efficient. For
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in
+the above example are gobbled), or it contains the translation for the symbol
+and the number of bits to gobble. Then you start again with the next
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the
+longest symbol is? The reason is that if you do that, you end up spending
+more time filling in duplicate symbol entries than you do actually decoding.
+At least for deflate's output that generates new trees every several 10's of
+kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code
+would take too long if you're only decoding several thousand symbols. At the
+other extreme, you could make a new table for every bit in the code. In fact,
+that's essentially a Huffman tree. But then you spend two much time
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode as and how many bits that is, i.e. how
+many bits to gobble. Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to
+be constructed. That's compared to 64 entries for a single table. Or
+compared to 16 entries for a Huffman tree (six two entry tables and one four
+entry table). Assuming that the code ideally represents the probability of
+the symbols, it takes on the average 1.25 lookups per symbol. That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the
+Huffman tree.
+
+There, I think that gives you a picture of what's going on. For inflate, the
+meaning of a particular symbol is often more than just a letter. It can be a
+byte (a "literal"), or it can be either a length or a distance which
+indicates a base value and a number of bits to fetch after the code that is
+added to the base value. Or it might be the special end-of-block code. The
+data structures created in inftrees.c try to encode all that information
+compactly in the tables.
+
+
+Jean-loup Gailly Mark Adler
+jloup@gzip.org madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+http://www.ietf.org/rfc/rfc1951.txt
diff --git a/zlib/amiga/Makefile.pup b/zlib/amiga/Makefile.pup
new file mode 100644
index 0000000..3f7e155
--- /dev/null
+++ b/zlib/amiga/Makefile.pup
@@ -0,0 +1,66 @@
+# Amiga powerUP (TM) Makefile
+# makefile for libpng and SAS C V6.58/7.00 PPC compiler
+# Copyright (C) 1998 by Andreas R. Kleinert
+
+LIBNAME = libzip.a
+
+CC = scppc
+CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \
+ OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER
+AR = ppc-amigaos-ar cr
+RANLIB = ppc-amigaos-ranlib
+LD = ppc-amigaos-ld -r
+LDFLAGS = -o
+LDLIBS = LIB:scppc.a LIB:end.o
+RM = delete quiet
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example minigzip
+
+check: test
+test: all
+ example
+ echo hello world | minigzip | minigzip -d
+
+$(LIBNAME): $(OBJS)
+ $(AR) $@ $(OBJS)
+ -$(RANLIB) $@
+
+example: example.o $(LIBNAME)
+ $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
+
+minigzip: minigzip.o $(LIBNAME)
+ $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
+
+mostlyclean: clean
+clean:
+ $(RM) *.o example minigzip $(LIBNAME) foo.gz
+
+zip:
+ zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \
+ descrip.mms *.[ch]
+
+tgz:
+ cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \
+ zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/zlib/amiga/Makefile.sas b/zlib/amiga/Makefile.sas
new file mode 100644
index 0000000..296ef48
--- /dev/null
+++ b/zlib/amiga/Makefile.sas
@@ -0,0 +1,65 @@
+# SMakefile for zlib
+# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
+# Osma Ahvenlampi <Osma.Ahvenlampi@hut.fi>
+# Amiga, SAS/C 6.56 & Smake
+
+CC=sc
+CFLAGS=OPT
+#CFLAGS=OPT CPU=68030
+#CFLAGS=DEBUG=LINE
+LDFLAGS=LIB z.lib
+
+SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
+ NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \
+ DEF=POSTINC
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: SCOPTIONS example minigzip
+
+check: test
+test: all
+ example
+ echo hello world | minigzip | minigzip -d
+
+install: z.lib
+ copy clone zlib.h zconf.h INCLUDE:
+ copy clone z.lib LIB:
+
+z.lib: $(OBJS)
+ oml z.lib r $(OBJS)
+
+example: example.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
+
+mostlyclean: clean
+clean:
+ -delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS
+
+SCOPTIONS: Makefile.sas
+ copy to $@ <from <
+$(SCOPTIONS)
+<
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/zlib/as400/bndsrc b/zlib/as400/bndsrc
new file mode 100644
index 0000000..9cf94bb
--- /dev/null
+++ b/zlib/as400/bndsrc
@@ -0,0 +1,132 @@
+STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('ZLIB')
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/* Version 1.1.3 entry points. */
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+/********************************************************************/
+/* *MODULE ADLER32 ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("adler32")
+
+/********************************************************************/
+/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("compress")
+ EXPORT SYMBOL("compress2")
+
+/********************************************************************/
+/* *MODULE CRC32 ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("crc32")
+ EXPORT SYMBOL("get_crc_table")
+
+/********************************************************************/
+/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("deflate")
+ EXPORT SYMBOL("deflateEnd")
+ EXPORT SYMBOL("deflateSetDictionary")
+ EXPORT SYMBOL("deflateCopy")
+ EXPORT SYMBOL("deflateReset")
+ EXPORT SYMBOL("deflateParams")
+ EXPORT SYMBOL("deflatePrime")
+ EXPORT SYMBOL("deflateInit_")
+ EXPORT SYMBOL("deflateInit2_")
+
+/********************************************************************/
+/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("gzopen")
+ EXPORT SYMBOL("gzdopen")
+ EXPORT SYMBOL("gzsetparams")
+ EXPORT SYMBOL("gzread")
+ EXPORT SYMBOL("gzwrite")
+ EXPORT SYMBOL("gzprintf")
+ EXPORT SYMBOL("gzputs")
+ EXPORT SYMBOL("gzgets")
+ EXPORT SYMBOL("gzputc")
+ EXPORT SYMBOL("gzgetc")
+ EXPORT SYMBOL("gzflush")
+ EXPORT SYMBOL("gzseek")
+ EXPORT SYMBOL("gzrewind")
+ EXPORT SYMBOL("gztell")
+ EXPORT SYMBOL("gzeof")
+ EXPORT SYMBOL("gzclose")
+ EXPORT SYMBOL("gzerror")
+
+/********************************************************************/
+/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("inflate")
+ EXPORT SYMBOL("inflateEnd")
+ EXPORT SYMBOL("inflateSetDictionary")
+ EXPORT SYMBOL("inflateSync")
+ EXPORT SYMBOL("inflateReset")
+ EXPORT SYMBOL("inflateInit_")
+ EXPORT SYMBOL("inflateInit2_")
+ EXPORT SYMBOL("inflateSyncPoint")
+
+/********************************************************************/
+/* *MODULE UNCOMPR ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("uncompress")
+
+/********************************************************************/
+/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("zlibVersion")
+ EXPORT SYMBOL("zError")
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/* Version 1.2.1 additional entry points. */
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+/********************************************************************/
+/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("compressBound")
+
+/********************************************************************/
+/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("deflateBound")
+
+/********************************************************************/
+/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("gzungetc")
+ EXPORT SYMBOL("gzclearerr")
+
+/********************************************************************/
+/* *MODULE INFBACK ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("inflateBack")
+ EXPORT SYMBOL("inflateBackEnd")
+ EXPORT SYMBOL("inflateBackInit_")
+
+/********************************************************************/
+/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("inflateCopy")
+
+/********************************************************************/
+/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */
+/********************************************************************/
+
+ EXPORT SYMBOL("zlibCompileFlags")
+
+ENDPGMEXP
diff --git a/zlib/as400/compile.clp b/zlib/as400/compile.clp
new file mode 100644
index 0000000..8554951
--- /dev/null
+++ b/zlib/as400/compile.clp
@@ -0,0 +1,123 @@
+/******************************************************************************/
+/* */
+/* ZLIB */
+/* */
+/* Compile sources into modules and link them into a service program. */
+/* */
+/******************************************************************************/
+
+ PGM
+
+/* Configuration adjustable parameters. */
+
+ DCL VAR(&SRCLIB) TYPE(*CHAR) LEN(10) +
+ VALUE('ZLIB') /* Source library. */
+ DCL VAR(&SRCFILE) TYPE(*CHAR) LEN(10) +
+ VALUE('SOURCES') /* Source member file. */
+ DCL VAR(&CTLFILE) TYPE(*CHAR) LEN(10) +
+ VALUE('TOOLS') /* Control member file. */
+
+ DCL VAR(&MODLIB) TYPE(*CHAR) LEN(10) +
+ VALUE('ZLIB') /* Module library. */
+
+ DCL VAR(&SRVLIB) TYPE(*CHAR) LEN(10) +
+ VALUE('LGPL') /* Service program library. */
+
+ DCL VAR(&CFLAGS) TYPE(*CHAR) +
+ VALUE('OPTIMIZE(40)') /* Compile options. */
+
+
+/* Working storage. */
+
+ DCL VAR(&CMDLEN) TYPE(*DEC) LEN(15 5) VALUE(300) /* Command length. */
+ DCL VAR(&CMD) TYPE(*CHAR) LEN(512)
+
+
+/* Compile sources into modules. */
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/ADLER32) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/COMPRESS) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/CRC32) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/DEFLATE) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/GZIO) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/INFBACK) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/INFFAST) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/INFLATE) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/INFTREES) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/TREES) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/UNCOMPR) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+ CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
+ '/ZUTIL) SRCFILE(' *TCAT +
+ &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
+ ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
+ CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
+
+
+/* Link modules into a service program. */
+
+ CRTSRVPGM SRVPGM(&SRVLIB/ZLIB) +
+ MODULE(&MODLIB/ADLER32 &MODLIB/COMPRESS +
+ &MODLIB/CRC32 &MODLIB/DEFLATE +
+ &MODLIB/GZIO &MODLIB/INFBACK +
+ &MODLIB/INFFAST &MODLIB/INFLATE +
+ &MODLIB/INFTREES &MODLIB/TREES +
+ &MODLIB/UNCOMPR &MODLIB/ZUTIL) +
+ SRCFILE(&SRCLIB/&CTLFILE) SRCMBR(BNDSRC) +
+ TEXT('ZLIB 1.2.3') TGTRLS(V4R4M0)
+
+ ENDPGM
diff --git a/zlib/as400/readme.txt b/zlib/as400/readme.txt
new file mode 100644
index 0000000..beae13f
--- /dev/null
+++ b/zlib/as400/readme.txt
@@ -0,0 +1,111 @@
+ ZLIB version 1.2.3 for AS400 installation instructions
+
+I) From an AS400 *SAVF file:
+
+1) Unpacking archive to an AS400 save file
+
+On the AS400:
+
+_ Create the ZLIB AS400 library:
+
+ CRTLIB LIB(ZLIB) TYPE(PROD) TEXT('ZLIB compression API library')
+
+_ Create a work save file, for example:
+
+ CRTSAVF FILE(ZLIB/ZLIBSAVF)
+
+On a PC connected to the target AS400:
+
+_ Unpack the save file image to a PC file "ZLIBSAVF"
+_ Upload this file into the save file on the AS400, for example
+ using ftp in BINARY mode.
+
+
+2) Populating the ZLIB AS400 source library
+
+On the AS400:
+
+_ Extract the saved objects into the ZLIB AS400 library using:
+
+RSTOBJ OBJ(*ALL) SAVLIB(ZLIB) DEV(*SAVF) SAVF(ZLIB/ZLIBSAVF) RSTLIB(ZLIB)
+
+
+3) Customize installation:
+
+_ Edit CL member ZLIB/TOOLS(COMPILE) and change parameters if needed,
+ according to the comments.
+
+_ Compile this member with:
+
+ CRTCLPGM PGM(ZLIB/COMPILE) SRCFILE(ZLIB/TOOLS) SRCMBR(COMPILE)
+
+
+4) Compile and generate the service program:
+
+_ This can now be done by executing:
+
+ CALL PGM(ZLIB/COMPILE)
+
+
+
+II) From the original source distribution:
+
+1) On the AS400, create the source library:
+
+ CRTLIB LIB(ZLIB) TYPE(PROD) TEXT('ZLIB compression API library')
+
+2) Create the source files:
+
+ CRTSRCPF FILE(ZLIB/SOURCES) RCDLEN(112) TEXT('ZLIB library modules')
+ CRTSRCPF FILE(ZLIB/H) RCDLEN(112) TEXT('ZLIB library includes')
+ CRTSRCPF FILE(ZLIB/TOOLS) RCDLEN(112) TEXT('ZLIB library control utilities')
+
+3) From the machine hosting the distribution files, upload them (with
+ FTP in text mode, for example) according to the following table:
+
+ Original AS400 AS400 AS400 AS400
+ file file member type description
+ SOURCES Original ZLIB C subprogram sources
+ adler32.c ADLER32 C ZLIB - Compute the Adler-32 checksum of a dta strm
+ compress.c COMPRESS C ZLIB - Compress a memory buffer
+ crc32.c CRC32 C ZLIB - Compute the CRC-32 of a data stream
+ deflate.c DEFLATE C ZLIB - Compress data using the deflation algorithm
+ gzio.c GZIO C ZLIB - IO on .gz files
+ infback.c INFBACK C ZLIB - Inflate using a callback interface
+ inffast.c INFFAST C ZLIB - Fast proc. literals & length/distance pairs
+ inflate.c INFLATE C ZLIB - Interface to inflate modules
+ inftrees.c INFTREES C ZLIB - Generate Huffman trees for efficient decode
+ trees.c TREES C ZLIB - Output deflated data using Huffman coding
+ uncompr.c UNCOMPR C ZLIB - Decompress a memory buffer
+ zutil.c ZUTIL C ZLIB - Target dependent utility functions
+ H Original ZLIB C and ILE/RPG include files
+ crc32.h CRC32 C ZLIB - CRC32 tables
+ deflate.h DEFLATE C ZLIB - Internal compression state
+ inffast.h INFFAST C ZLIB - Header to use inffast.c
+ inffixed.h INFFIXED C ZLIB - Table for decoding fixed codes
+ inflate.h INFLATE C ZLIB - Internal inflate state definitions
+ inftrees.h INFTREES C ZLIB - Header to use inftrees.c
+ trees.h TREES C ZLIB - Created automatically with -DGEN_TREES_H
+ zconf.h ZCONF C ZLIB - Compression library configuration
+ zlib.h ZLIB C ZLIB - Compression library C user interface
+ as400/zlib.inc ZLIB.INC RPGLE ZLIB - Compression library ILE RPG user interface
+ zutil.h ZUTIL C ZLIB - Internal interface and configuration
+ TOOLS Building source software & AS/400 README
+ as400/bndsrc BNDSRC Entry point exportation list
+ as400/compile.clp COMPILE CLP Compile sources & generate service program
+ as400/readme.txt README TXT Installation instructions
+
+4) Continue as in I)3).
+
+
+
+
+Notes: For AS400 ILE RPG programmers, a /copy member defining the ZLIB
+ API prototypes for ILE RPG can be found in ZLIB/H(ZLIB.INC).
+ Please read comments in this member for more information.
+
+ Remember that most foreign textual data are ASCII coded: this
+ implementation does not handle conversion from/to ASCII, so
+ text data code conversions must be done explicitely.
+
+ Always open zipped files in binary mode.
diff --git a/zlib/as400/zlib.inc b/zlib/as400/zlib.inc
new file mode 100644
index 0000000..7bbfb7e
--- /dev/null
+++ b/zlib/as400/zlib.inc
@@ -0,0 +1,331 @@
+ * ZLIB.INC - Interface to the general purpose compression library
+ *
+ * ILE RPG400 version by Patrick Monnerat, DATASPHERE.
+ * Version 1.2.3
+ *
+ *
+ * WARNING:
+ * Procedures inflateInit(), inflateInit2(), deflateInit(),
+ * deflateInit2() and inflateBackInit() need to be called with
+ * two additional arguments:
+ * the package version string and the stream control structure.
+ * size. This is needed because RPG lacks some macro feature.
+ * Call these procedures as:
+ * inflateInit(...: ZLIB_VERSION: %size(z_stream))
+ *
+ /if not defined(ZLIB_H_)
+ /define ZLIB_H_
+ *
+ **************************************************************************
+ * Constants
+ **************************************************************************
+ *
+ * Versioning information.
+ *
+ D ZLIB_VERSION C '1.2.3'
+ D ZLIB_VERNUM C X'1230'
+ *
+ * Other equates.
+ *
+ D Z_NO_FLUSH C 0
+ D Z_SYNC_FLUSH C 2
+ D Z_FULL_FLUSH C 3
+ D Z_FINISH C 4
+ D Z_BLOCK C 5
+ *
+ D Z_OK C 0
+ D Z_STREAM_END C 1
+ D Z_NEED_DICT C 2
+ D Z_ERRNO C -1
+ D Z_STREAM_ERROR C -2
+ D Z_DATA_ERROR C -3
+ D Z_MEM_ERROR C -4
+ D Z_BUF_ERROR C -5
+ DZ_VERSION_ERROR C -6
+ *
+ D Z_NO_COMPRESSION...
+ D C 0
+ D Z_BEST_SPEED C 1
+ D Z_BEST_COMPRESSION...
+ D C 9
+ D Z_DEFAULT_COMPRESSION...
+ D C -1
+ *
+ D Z_FILTERED C 1
+ D Z_HUFFMAN_ONLY C 2
+ D Z_RLE C 3
+ D Z_DEFAULT_STRATEGY...
+ D C 0
+ *
+ D Z_BINARY C 0
+ D Z_ASCII C 1
+ D Z_UNKNOWN C 2
+ *
+ D Z_DEFLATED C 8
+ *
+ D Z_NULL C 0
+ *
+ **************************************************************************
+ * Types
+ **************************************************************************
+ *
+ D z_streamp S * Stream struct ptr
+ D gzFile S * File pointer
+ D z_off_t S 10i 0 Stream offsets
+ *
+ **************************************************************************
+ * Structures
+ **************************************************************************
+ *
+ * The GZIP encode/decode stream support structure.
+ *
+ D z_stream DS align based(z_streamp)
+ D zs_next_in * Next input byte
+ D zs_avail_in 10U 0 Byte cnt at next_in
+ D zs_total_in 10U 0 Total bytes read
+ D zs_next_out * Output buffer ptr
+ D zs_avail_out 10U 0 Room left @ next_out
+ D zs_total_out 10U 0 Total bytes written
+ D zs_msg * Last errmsg or null
+ D zs_state * Internal state
+ D zs_zalloc * procptr Int. state allocator
+ D zs_free * procptr Int. state dealloc.
+ D zs_opaque * Private alloc. data
+ D zs_data_type 10i 0 ASC/BIN best guess
+ D zs_adler 10u 0 Uncompr. adler32 val
+ D 10U 0 Reserved
+ D 10U 0 Ptr. alignment
+ *
+ **************************************************************************
+ * Utility function prototypes
+ **************************************************************************
+ *
+ D compress PR 10I 0 extproc('compress')
+ D dest 32767 options(*varsize) Destination buffer
+ D destLen 10U 0 Destination length
+ D source 32767 const options(*varsize) Source buffer
+ D sourceLen 10u 0 value Source length
+ *
+ D compress2 PR 10I 0 extproc('compress2')
+ D dest 32767 options(*varsize) Destination buffer
+ D destLen 10U 0 Destination length
+ D source 32767 const options(*varsize) Source buffer
+ D sourceLen 10U 0 value Source length
+ D level 10I 0 value Compression level
+ *
+ D compressBound PR 10U 0 extproc('compressBound')
+ D sourceLen 10U 0 value
+ *
+ D uncompress PR 10I 0 extproc('uncompress')
+ D dest 32767 options(*varsize) Destination buffer
+ D destLen 10U 0 Destination length
+ D source 32767 const options(*varsize) Source buffer
+ D sourceLen 10U 0 value Source length
+ *
+ D gzopen PR extproc('gzopen')
+ D like(gzFile)
+ D path * value options(*string) File pathname
+ D mode * value options(*string) Open mode
+ *
+ D gzdopen PR extproc('gzdopen')
+ D like(gzFile)
+ D fd 10i 0 value File descriptor
+ D mode * value options(*string) Open mode
+ *
+ D gzsetparams PR 10I 0 extproc('gzsetparams')
+ D file value like(gzFile) File pointer
+ D level 10I 0 value
+ D strategy 10i 0 value
+ *
+ D gzread PR 10I 0 extproc('gzread')
+ D file value like(gzFile) File pointer
+ D buf 32767 options(*varsize) Buffer
+ D len 10u 0 value Buffer length
+ *
+ D gzwrite PR 10I 0 extproc('gzwrite')
+ D file value like(gzFile) File pointer
+ D buf 32767 const options(*varsize) Buffer
+ D len 10u 0 value Buffer length
+ *
+ D gzputs PR 10I 0 extproc('gzputs')
+ D file value like(gzFile) File pointer
+ D s * value options(*string) String to output
+ *
+ D gzgets PR * extproc('gzgets')
+ D file value like(gzFile) File pointer
+ D buf 32767 options(*varsize) Read buffer
+ D len 10i 0 value Buffer length
+ *
+ D gzflush PR 10i 0 extproc('gzflush')
+ D file value like(gzFile) File pointer
+ D flush 10I 0 value Type of flush
+ *
+ D gzseek PR extproc('gzseek')
+ D like(z_off_t)
+ D file value like(gzFile) File pointer
+ D offset value like(z_off_t) Offset
+ D whence 10i 0 value Origin
+ *
+ D gzrewind PR 10i 0 extproc('gzrewind')
+ D file value like(gzFile) File pointer
+ *
+ D gztell PR extproc('gztell')
+ D like(z_off_t)
+ D file value like(gzFile) File pointer
+ *
+ D gzeof PR 10i 0 extproc('gzeof')
+ D file value like(gzFile) File pointer
+ *
+ D gzclose PR 10i 0 extproc('gzclose')
+ D file value like(gzFile) File pointer
+ *
+ D gzerror PR * extproc('gzerror') Error string
+ D file value like(gzFile) File pointer
+ D errnum 10I 0 Error code
+ *
+ D gzclearerr PR extproc('gzclearerr')
+ D file value like(gzFile) File pointer
+ *
+ **************************************************************************
+ * Basic function prototypes
+ **************************************************************************
+ *
+ D zlibVersion PR * extproc('zlibVersion') Version string
+ *
+ D deflateInit PR 10I 0 extproc('deflateInit_') Init. compression
+ D strm like(z_stream) Compression stream
+ D level 10I 0 value Compression level
+ D version * value options(*string) Version string
+ D stream_size 10i 0 value Stream struct. size
+ *
+ D deflate PR 10I 0 extproc('deflate') Compress data
+ D strm like(z_stream) Compression stream
+ D flush 10I 0 value Flush type required
+ *
+ D deflateEnd PR 10I 0 extproc('deflateEnd') Termin. compression
+ D strm like(z_stream) Compression stream
+ *
+ D inflateInit PR 10I 0 extproc('inflateInit_') Init. expansion
+ D strm like(z_stream) Expansion stream
+ D version * value options(*string) Version string
+ D stream_size 10i 0 value Stream struct. size
+ *
+ D inflate PR 10I 0 extproc('inflate') Expand data
+ D strm like(z_stream) Expansion stream
+ D flush 10I 0 value Flush type required
+ *
+ D inflateEnd PR 10I 0 extproc('inflateEnd') Termin. expansion
+ D strm like(z_stream) Expansion stream
+ *
+ **************************************************************************
+ * Advanced function prototypes
+ **************************************************************************
+ *
+ D deflateInit2 PR 10I 0 extproc('deflateInit2_') Init. compression
+ D strm like(z_stream) Compression stream
+ D level 10I 0 value Compression level
+ D method 10I 0 value Compression method
+ D windowBits 10I 0 value log2(window size)
+ D memLevel 10I 0 value Mem/cmpress tradeoff
+ D strategy 10I 0 value Compression stategy
+ D version * value options(*string) Version string
+ D stream_size 10i 0 value Stream struct. size
+ *
+ D deflateSetDictionary...
+ D PR 10I 0 extproc('deflateSetDictionary') Init. dictionary
+ D strm like(z_stream) Compression stream
+ D dictionary 32767 const options(*varsize) Dictionary bytes
+ D dictLength 10U 0 value Dictionary length
+ *
+ D deflateCopy PR 10I 0 extproc('deflateCopy') Compress strm 2 strm
+ D dest like(z_stream) Destination stream
+ D source like(z_stream) Source stream
+ *
+ D deflateReset PR 10I 0 extproc('deflateReset') End and init. stream
+ D strm like(z_stream) Compression stream
+ *
+ D deflateParams PR 10I 0 extproc('deflateParams') Change level & strat
+ D strm like(z_stream) Compression stream
+ D level 10I 0 value Compression level
+ D strategy 10I 0 value Compression stategy
+ *
+ D deflateBound PR 10U 0 extproc('deflateBound') Change level & strat
+ D strm like(z_stream) Compression stream
+ D sourcelen 10U 0 value Compression level
+ *
+ D deflatePrime PR 10I 0 extproc('deflatePrime') Change level & strat
+ D strm like(z_stream) Compression stream
+ D bits 10I 0 value Number of bits to insert
+ D value 10I 0 value Bits to insert
+ *
+ D inflateInit2 PR 10I 0 extproc('inflateInit2_') Init. expansion
+ D strm like(z_stream) Expansion stream
+ D windowBits 10I 0 value log2(window size)
+ D version * value options(*string) Version string
+ D stream_size 10i 0 value Stream struct. size
+ *
+ D inflateSetDictionary...
+ D PR 10I 0 extproc('inflateSetDictionary') Init. dictionary
+ D strm like(z_stream) Expansion stream
+ D dictionary 32767 const options(*varsize) Dictionary bytes
+ D dictLength 10U 0 value Dictionary length
+ *
+ D inflateSync PR 10I 0 extproc('inflateSync') Sync. expansion
+ D strm like(z_stream) Expansion stream
+ *
+ D inflateCopy PR 10I 0 extproc('inflateCopy')
+ D dest like(z_stream) Destination stream
+ D source like(z_stream) Source stream
+ *
+ D inflateReset PR 10I 0 extproc('inflateReset') End and init. stream
+ D strm like(z_stream) Expansion stream
+ *
+ D inflateBackInit...
+ D PR 10I 0 extproc('inflateBackInit_')
+ D strm like(z_stream) Expansion stream
+ D windowBits 10I 0 value Log2(buffer size)
+ D window 32767 options(*varsize) Buffer
+ D version * value options(*string) Version string
+ D stream_size 10i 0 value Stream struct. size
+ *
+ D inflateBack PR 10I 0 extproc('inflateBack')
+ D strm like(z_stream) Expansion stream
+ D in * value procptr Input function
+ D in_desc * value Input descriptor
+ D out * value procptr Output function
+ D out_desc * value Output descriptor
+ *
+ D inflateBackEnd PR 10I 0 extproc('inflateBackEnd')
+ D strm like(z_stream) Expansion stream
+ *
+ D zlibCompileFlags...
+ D PR 10U 0 extproc('zlibCompileFlags')
+ *
+ **************************************************************************
+ * Checksum function prototypes
+ **************************************************************************
+ *
+ D adler32 PR 10U 0 extproc('adler32') New checksum
+ D adler 10U 0 value Old checksum
+ D buf 32767 const options(*varsize) Bytes to accumulate
+ D len 10U 0 value Buffer length
+ *
+ D crc32 PR 10U 0 extproc('crc32') New checksum
+ D crc 10U 0 value Old checksum
+ D buf 32767 const options(*varsize) Bytes to accumulate
+ D len 10U 0 value Buffer length
+ *
+ **************************************************************************
+ * Miscellaneous function prototypes
+ **************************************************************************
+ *
+ D zError PR * extproc('zError') Error string
+ D err 10I 0 value Error code
+ *
+ D inflateSyncPoint...
+ D PR 10I 0 extproc('inflateSyncPoint')
+ D strm like(z_stream) Expansion stream
+ *
+ D get_crc_table PR * extproc('get_crc_table') Ptr to ulongs
+ *
+ /endif
diff --git a/zlib/compress.c b/zlib/compress.c
new file mode 100644
index 0000000..df04f01
--- /dev/null
+++ b/zlib/compress.c
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/zlib/configure b/zlib/configure
new file mode 100755
index 0000000..d7ffdc3
--- /dev/null
+++ b/zlib/configure
@@ -0,0 +1,459 @@
+#!/bin/sh
+# configure script for zlib. This script is needed only if
+# you wish to build a shared library and your system supports them,
+# of if you need special compiler, flags or install directory.
+# Otherwise, you can just use directly "make test; make install"
+#
+# To create a shared library, use "configure --shared"; by default a static
+# library is created. If the primitive shared library support provided here
+# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz
+#
+# To impose specific compiler or flags or install directory, use for example:
+# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+# LDSHARED is the command to be used to create a shared library
+
+# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
+# If you have problems, try without defining CC and CFLAGS before reporting
+# an error.
+
+LIBS=libz.a
+LDFLAGS="-L. ${LIBS}"
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
+VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h`
+VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h`
+AR=${AR-"ar rc"}
+RANLIB=${RANLIB-"ranlib"}
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-'${prefix}'}
+libdir=${libdir-'${exec_prefix}/lib'}
+includedir=${includedir-'${prefix}/include'}
+mandir=${mandir-'${prefix}/share/man'}
+shared_ext='.so'
+shared=0
+gcc=0
+old_cc="$CC"
+old_cflags="$CFLAGS"
+
+while test $# -ge 1
+do
+case "$1" in
+ -h* | --h*)
+ echo 'usage:'
+ echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]'
+ echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]'
+ exit 0;;
+ -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;;
+ -p* | --p*) prefix="$2"; shift; shift;;
+ -e* | --e*) exec_prefix="$2"; shift; shift;;
+ -l* | --l*) libdir="$2"; shift; shift;;
+ -i* | --i*) includedir="$2"; shift; shift;;
+ -s* | --s*) shared=1; shift;;
+ *) echo "unknown option: $1"; echo "$0 --help for help"; exit 1;;
+ esac
+done
+
+test=ztest$$
+cat > $test.c <<EOF
+extern int getchar();
+int hello() {return getchar();}
+EOF
+
+test -z "$CC" && echo Checking for gcc...
+cc=${CC-gcc}
+cflags=${CFLAGS-"-O3"}
+# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
+case "$cc" in
+ *gcc*) gcc=1;;
+esac
+
+if test "$gcc" -eq 1 && ($cc -c $cflags $test.c) 2>/dev/null; then
+ CC="$cc"
+ SFLAGS=${CFLAGS-"-fPIC -O3"}
+ CFLAGS="$cflags"
+ case `(uname -s || echo unknown) 2>/dev/null` in
+ Linux | linux | GNU | GNU/*) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1"};;
+ CYGWIN* | Cygwin* | cygwin* | OS/2* )
+ EXE='.exe';;
+ QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
+ # (alain.bonnefoy@icbt.com)
+ LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"};;
+ HP-UX*)
+ LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
+ case `(uname -m || echo unknown) 2>/dev/null` in
+ ia64)
+ shared_ext='.so'
+ SHAREDLIB='libz.so';;
+ *)
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl';;
+ esac;;
+ Darwin*) shared_ext='.dylib'
+ SHAREDLIB=libz$shared_ext
+ SHAREDLIBV=libz.$VER$shared_ext
+ SHAREDLIBM=libz.$VER1$shared_ext
+ LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER"};;
+ *) LDSHARED=${LDSHARED-"$cc -shared"};;
+ esac
+else
+ # find system name and corresponding cc options
+ CC=${CC-cc}
+ case `(uname -sr || echo unknown) 2>/dev/null` in
+ HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
+ CFLAGS=${CFLAGS-"-O"}
+# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
+ LDSHARED=${LDSHARED-"ld -b"}
+ case `(uname -m || echo unknown) 2>/dev/null` in
+ ia64)
+ shared_ext='.so'
+ SHAREDLIB='libz.so';;
+ *)
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl';;
+ esac;;
+ IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+ CFLAGS=${CFLAGS-"-ansi -O2"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};;
+ OSF1*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ QNX*) SFLAGS=${CFLAGS-"-4 -O"}
+ CFLAGS=${CFLAGS-"-4 -O"}
+ LDSHARED=${LDSHARED-"cc"}
+ RANLIB=${RANLIB-"true"}
+ AR="cc -A";;
+ SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+ CFLAGS=${CFLAGS-"-O3"}
+ LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};;
+ SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."}
+ CFLAGS=${CFLAGS-"-fast -xcg89"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+ CFLAGS=${CFLAGS-"-O2"}
+ LDSHARED=${LDSHARED-"ld"};;
+ SunStudio\ 9*) SFLAGS=${CFLAGS-"-DUSE_MMAP -fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"}
+ CFLAGS=${CFLAGS-"-DUSE_MMAP -fast -xtarget=ultra3 -xarch=v9b"}
+ LDSHARED=${LDSHARED-"cc -xarch=v9b"};;
+ UNIX_System_V\ 4.2.0)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ UNIX_SV\ 4.2MP)
+ SFLAGS=${CFLAGS-"-Kconform_pic -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ OpenUNIX\ 5)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ AIX*) # Courtesy of dbakker@arrayasolutions.com
+ SFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ CFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ LDSHARED=${LDSHARED-"xlc -G"};;
+ # send working options for other systems to support@gzip.org
+ *) SFLAGS=${CFLAGS-"-O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ esac
+fi
+
+SHAREDLIB=${SHAREDLIB-"libz$shared_ext"}
+SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"}
+SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"}
+
+if test $shared -eq 1; then
+ echo Checking for shared library support...
+ # we must test in two steps (cc then ld), required at least on SunOS 4.x
+ if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" &&
+ test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then
+ CFLAGS="$SFLAGS"
+ LIBS="$SHAREDLIBV"
+ echo Building shared library $SHAREDLIBV with $CC.
+ elif test -z "$old_cc" -a -z "$old_cflags"; then
+ echo No shared library support.
+ shared=0;
+ else
+ echo 'No shared library support; try without defining CC and CFLAGS'
+ shared=0;
+ fi
+fi
+if test $shared -eq 0; then
+ LDSHARED="$CC"
+ echo Building static library $LIBS version $VER with $CC.
+else
+ LDFLAGS="-L. ${SHAREDLIBV}"
+fi
+
+cat > $test.c <<EOF
+#include <unistd.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ sed < zconf.in.h "/HAVE_UNISTD_H/s%0%1%" > zconf.h
+ echo "Checking for unistd.h... Yes."
+else
+ cp -p zconf.in.h zconf.h
+ echo "Checking for unistd.h... No."
+fi
+
+cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+#include "zconf.h"
+
+int main()
+{
+#ifndef STDC
+ choke me
+#endif
+
+ return 0;
+}
+EOF
+
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()"
+
+ cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return 0;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
+ echo "Checking for vsnprintf() in stdio.h... Yes."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return n;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of vsnprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_vsnprintf_void"
+ echo "Checking for return value of vsnprintf()... No."
+ echo " WARNING: apparently vsnprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_vsnprintf"
+ echo "Checking for vsnprintf() in stdio.h... No."
+ echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib"
+ echo " can build but will be open to possible buffer-overflow security"
+ echo " vulnerabilities."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = vsprintf(buf, fmt, ap);
+ va_end(ap);
+ return n;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of vsprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_vsprintf_void"
+ echo "Checking for return value of vsprintf()... No."
+ echo " WARNING: apparently vsprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ fi
+else
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()"
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ snprintf(buf, sizeof(buf), "%s", "foo");
+ return 0;
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
+ echo "Checking for snprintf() in stdio.h... Yes."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ return snprintf(buf, sizeof(buf), "%s", "foo");
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of snprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_snprintf_void"
+ echo "Checking for return value of snprintf()... No."
+ echo " WARNING: apparently snprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_snprintf"
+ echo "Checking for snprintf() in stdio.h... No."
+ echo " WARNING: snprintf() not found, falling back to sprintf(). zlib"
+ echo " can build but will be open to possible buffer-overflow security"
+ echo " vulnerabilities."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ return sprintf(buf, "%s", "foo");
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of sprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_sprintf_void"
+ echo "Checking for return value of sprintf()... No."
+ echo " WARNING: apparently sprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ fi
+fi
+
+cat >$test.c <<EOF
+#include <errno.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for errno.h... Yes."
+else
+ echo "Checking for errno.h... No."
+ CFLAGS="$CFLAGS -DNO_ERRNO_H"
+fi
+
+cat > $test.c <<EOF
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+caddr_t hello() {
+ return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0);
+}
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ CFLAGS="$CFLAGS -DUSE_MMAP"
+ echo Checking for mmap support... Yes.
+else
+ echo Checking for mmap support... No.
+fi
+
+CPP=${CPP-"$CC -E"}
+case $CFLAGS in
+ *ASMV*)
+ if test "`nm $test.o | grep _hello`" = ""; then
+ CPP="$CPP -DNO_UNDERLINE"
+ echo Checking for underline in external names... No.
+ else
+ echo Checking for underline in external names... Yes.
+ fi;;
+esac
+
+rm -f $test.[co] $test $test$shared_ext
+
+# udpate Makefile
+sed < Makefile.in "
+/^CC *=/s#=.*#=$CC#
+/^CFLAGS *=/s#=.*#=$CFLAGS#
+/^CPP *=/s#=.*#=$CPP#
+/^LDSHARED *=/s#=.*#=$LDSHARED#
+/^LIBS *=/s#=.*#=$LIBS#
+/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
+/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
+/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
+/^AR *=/s#=.*#=$AR#
+/^RANLIB *=/s#=.*#=$RANLIB#
+/^EXE *=/s#=.*#=$EXE#
+/^prefix *=/s#=.*#=$prefix#
+/^exec_prefix *=/s#=.*#=$exec_prefix#
+/^libdir *=/s#=.*#=$libdir#
+/^includedir *=/s#=.*#=$includedir#
+/^mandir *=/s#=.*#=$mandir#
+/^LDFLAGS *=/s#=.*#=$LDFLAGS#
+" > Makefile
diff --git a/zlib/contrib/README.contrib b/zlib/contrib/README.contrib
new file mode 100644
index 0000000..20afc62
--- /dev/null
+++ b/zlib/contrib/README.contrib
@@ -0,0 +1,71 @@
+All files under this contrib directory are UNSUPPORTED. There were
+provided by users of zlib and were not tested by the authors of zlib.
+Use at your own risk. Please contact the authors of the contributions
+for help about these, not the zlib authors. Thanks.
+
+
+ada/ by Dmitriy Anisimkov <anisimkov@yahoo.com>
+ Support for Ada
+ See http://zlib-ada.sourceforge.net/
+
+asm586/
+asm686/ by Brian Raiter <breadbox@muppetlabs.com>
+ asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+blast/ by Mark Adler <madler@alumni.caltech.edu>
+ Decompressor for output of PKWare Data Compression Library (DCL)
+
+delphi/ by Cosmin Truta <cosmint@cs.ubbcluj.ro>
+ Support for Delphi and C++ Builder
+
+dotzlib/ by Henrik Ravn <henrik@ravn.com>
+ Support for Microsoft .Net and Visual C++ .Net
+
+infback9/ by Mark Adler <madler@alumni.caltech.edu>
+ Unsupported diffs to infback to decode the deflate64 format
+
+inflate86/ by Chris Anderson <christop@charm.net>
+ Tuned x86 gcc asm code to replace inflate_fast()
+
+iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+ A C++ I/O streams interface to the zlib gz* functions
+
+iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
+ Another C++ I/O streams interface
+
+iostream3/ by Ludwig Schwardt <schwardt@sun.ac.za>
+ and Kevin Ruland <kevin@rodin.wustl.edu>
+ Yet another C++ I/O streams interface
+
+masm686/ by Dan Higdon <hdan@kinesoft.com>
+ and Chuck Walbourn <chuckw@kinesoft.com>
+ asm code for Pentium Pro/PII, using the MASM syntax
+
+masmx64/ by Gilles Vollant <info@winimage.com>
+ x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to
+ replace longest_match() and inflate_fast()
+
+masmx86/ by Gilles Vollant <info@winimage.com>
+ x86 asm code to replace longest_match() and inflate_fast(),
+ for Visual C++ and MASM
+
+minizip/ by Gilles Vollant <info@winimage.com>
+ Mini zip and unzip based on zlib
+ See http://www.winimage.com/zLibDll/unzip.html
+
+pascal/ by Bob Dellaca <bobdl@xtra.co.nz> et al.
+ Support for Pascal
+
+puff/ by Mark Adler <madler@alumni.caltech.edu>
+ Small, low memory usage inflate. Also serves to provide an
+ unambiguous description of the deflate format.
+
+testzlib/ by Gilles Vollant <info@winimage.com>
+ Example of the use of zlib
+
+untgz/ by Pedro A. Aranda Gutierrez <paag@tid.es>
+ A very simple tar.gz file extractor using zlib
+
+vstudio/ by Gilles Vollant <info@winimage.com>
+ Building a minizip-enhanced zlib with Microsoft Visual Studio
diff --git a/zlib/contrib/ada/buffer_demo.adb b/zlib/contrib/ada/buffer_demo.adb
new file mode 100644
index 0000000..3969e7b
--- /dev/null
+++ b/zlib/contrib/ada/buffer_demo.adb
@@ -0,0 +1,106 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2004 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+--
+-- $Id: buffer_demo.adb,v 1.1.1.1 2005/02/20 17:57:20 dprice Exp $
+
+-- This demo program provided by Dr Steve Sangwine <sjs@essex.ac.uk>
+--
+-- Demonstration of a problem with Zlib-Ada (already fixed) when a buffer
+-- of exactly the correct size is used for decompressed data, and the last
+-- few bytes passed in to Zlib are checksum bytes.
+
+-- This program compresses a string of text, and then decompresses the
+-- compressed text into a buffer of the same size as the original text.
+
+with Ada.Streams; use Ada.Streams;
+with Ada.Text_IO;
+
+with ZLib; use ZLib;
+
+procedure Buffer_Demo is
+ EOL : Character renames ASCII.LF;
+ Text : constant String
+ := "Four score and seven years ago our fathers brought forth," & EOL &
+ "upon this continent, a new nation, conceived in liberty," & EOL &
+ "and dedicated to the proposition that `all men are created equal'.";
+
+ Source : Stream_Element_Array (1 .. Text'Length);
+ for Source'Address use Text'Address;
+
+begin
+ Ada.Text_IO.Put (Text);
+ Ada.Text_IO.New_Line;
+ Ada.Text_IO.Put_Line
+ ("Uncompressed size : " & Positive'Image (Text'Length) & " bytes");
+
+ declare
+ Compressed_Data : Stream_Element_Array (1 .. Text'Length);
+ L : Stream_Element_Offset;
+ begin
+ Compress : declare
+ Compressor : Filter_Type;
+ I : Stream_Element_Offset;
+ begin
+ Deflate_Init (Compressor);
+
+ -- Compress the whole of T at once.
+
+ Translate (Compressor, Source, I, Compressed_Data, L, Finish);
+ pragma Assert (I = Source'Last);
+
+ Close (Compressor);
+
+ Ada.Text_IO.Put_Line
+ ("Compressed size : "
+ & Stream_Element_Offset'Image (L) & " bytes");
+ end Compress;
+
+ -- Now we decompress the data, passing short blocks of data to Zlib
+ -- (because this demonstrates the problem - the last block passed will
+ -- contain checksum information and there will be no output, only a
+ -- check inside Zlib that the checksum is correct).
+
+ Decompress : declare
+ Decompressor : Filter_Type;
+
+ Uncompressed_Data : Stream_Element_Array (1 .. Text'Length);
+
+ Block_Size : constant := 4;
+ -- This makes sure that the last block contains
+ -- only Adler checksum data.
+
+ P : Stream_Element_Offset := Compressed_Data'First - 1;
+ O : Stream_Element_Offset;
+ begin
+ Inflate_Init (Decompressor);
+
+ loop
+ Translate
+ (Decompressor,
+ Compressed_Data
+ (P + 1 .. Stream_Element_Offset'Min (P + Block_Size, L)),
+ P,
+ Uncompressed_Data
+ (Total_Out (Decompressor) + 1 .. Uncompressed_Data'Last),
+ O,
+ No_Flush);
+
+ Ada.Text_IO.Put_Line
+ ("Total in : " & Count'Image (Total_In (Decompressor)) &
+ ", out : " & Count'Image (Total_Out (Decompressor)));
+
+ exit when P = L;
+ end loop;
+
+ Ada.Text_IO.New_Line;
+ Ada.Text_IO.Put_Line
+ ("Decompressed text matches original text : "
+ & Boolean'Image (Uncompressed_Data = Source));
+ end Decompress;
+ end;
+end Buffer_Demo;
diff --git a/zlib/contrib/ada/mtest.adb b/zlib/contrib/ada/mtest.adb
new file mode 100644
index 0000000..ed4e6e1
--- /dev/null
+++ b/zlib/contrib/ada/mtest.adb
@@ -0,0 +1,156 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+-- Continuous test for ZLib multithreading. If the test would fail
+-- we should provide thread safe allocation routines for the Z_Stream.
+--
+-- $Id: mtest.adb,v 1.1.1.2 2005/02/20 17:57:20 dprice Exp $
+
+with ZLib;
+with Ada.Streams;
+with Ada.Numerics.Discrete_Random;
+with Ada.Text_IO;
+with Ada.Exceptions;
+with Ada.Task_Identification;
+
+procedure MTest is
+ use Ada.Streams;
+ use ZLib;
+
+ Stop : Boolean := False;
+
+ pragma Atomic (Stop);
+
+ subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#;
+
+ package Random_Elements is
+ new Ada.Numerics.Discrete_Random (Visible_Symbols);
+
+ task type Test_Task;
+
+ task body Test_Task is
+ Buffer : Stream_Element_Array (1 .. 100_000);
+ Gen : Random_Elements.Generator;
+
+ Buffer_First : Stream_Element_Offset;
+ Compare_First : Stream_Element_Offset;
+
+ Deflate : Filter_Type;
+ Inflate : Filter_Type;
+
+ procedure Further (Item : in Stream_Element_Array);
+
+ procedure Read_Buffer
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+
+ -------------
+ -- Further --
+ -------------
+
+ procedure Further (Item : in Stream_Element_Array) is
+
+ procedure Compare (Item : in Stream_Element_Array);
+
+ -------------
+ -- Compare --
+ -------------
+
+ procedure Compare (Item : in Stream_Element_Array) is
+ Next_First : Stream_Element_Offset := Compare_First + Item'Length;
+ begin
+ if Buffer (Compare_First .. Next_First - 1) /= Item then
+ raise Program_Error;
+ end if;
+
+ Compare_First := Next_First;
+ end Compare;
+
+ procedure Compare_Write is new ZLib.Write (Write => Compare);
+ begin
+ Compare_Write (Inflate, Item, No_Flush);
+ end Further;
+
+ -----------------
+ -- Read_Buffer --
+ -----------------
+
+ procedure Read_Buffer
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset)
+ is
+ Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First;
+ Next_First : Stream_Element_Offset;
+ begin
+ if Item'Length <= Buff_Diff then
+ Last := Item'Last;
+
+ Next_First := Buffer_First + Item'Length;
+
+ Item := Buffer (Buffer_First .. Next_First - 1);
+
+ Buffer_First := Next_First;
+ else
+ Last := Item'First + Buff_Diff;
+ Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last);
+ Buffer_First := Buffer'Last + 1;
+ end if;
+ end Read_Buffer;
+
+ procedure Translate is new Generic_Translate
+ (Data_In => Read_Buffer,
+ Data_Out => Further);
+
+ begin
+ Random_Elements.Reset (Gen);
+
+ Buffer := (others => 20);
+
+ Main : loop
+ for J in Buffer'Range loop
+ Buffer (J) := Random_Elements.Random (Gen);
+
+ Deflate_Init (Deflate);
+ Inflate_Init (Inflate);
+
+ Buffer_First := Buffer'First;
+ Compare_First := Buffer'First;
+
+ Translate (Deflate);
+
+ if Compare_First /= Buffer'Last + 1 then
+ raise Program_Error;
+ end if;
+
+ Ada.Text_IO.Put_Line
+ (Ada.Task_Identification.Image
+ (Ada.Task_Identification.Current_Task)
+ & Stream_Element_Offset'Image (J)
+ & ZLib.Count'Image (Total_Out (Deflate)));
+
+ Close (Deflate);
+ Close (Inflate);
+
+ exit Main when Stop;
+ end loop;
+ end loop Main;
+ exception
+ when E : others =>
+ Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E));
+ Stop := True;
+ end Test_Task;
+
+ Test : array (1 .. 4) of Test_Task;
+
+ pragma Unreferenced (Test);
+
+ Dummy : Character;
+
+begin
+ Ada.Text_IO.Get_Immediate (Dummy);
+ Stop := True;
+end MTest;
diff --git a/zlib/contrib/ada/read.adb b/zlib/contrib/ada/read.adb
new file mode 100644
index 0000000..1eccc25
--- /dev/null
+++ b/zlib/contrib/ada/read.adb
@@ -0,0 +1,156 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: read.adb,v 1.1.1.2 2005/02/20 17:57:20 dprice Exp $
+
+-- Test/demo program for the generic read interface.
+
+with Ada.Numerics.Discrete_Random;
+with Ada.Streams;
+with Ada.Text_IO;
+
+with ZLib;
+
+procedure Read is
+
+ use Ada.Streams;
+
+ ------------------------------------
+ -- Test configuration parameters --
+ ------------------------------------
+
+ File_Size : Stream_Element_Offset := 100_000;
+
+ Continuous : constant Boolean := False;
+ -- If this constant is True, the test would be repeated again and again,
+ -- with increment File_Size for every iteration.
+
+ Header : constant ZLib.Header_Type := ZLib.Default;
+ -- Do not use Header other than Default in ZLib versions 1.1.4 and older.
+
+ Init_Random : constant := 8;
+ -- We are using the same random sequence, in case of we catch bug,
+ -- so we would be able to reproduce it.
+
+ -- End --
+
+ Pack_Size : Stream_Element_Offset;
+ Offset : Stream_Element_Offset;
+
+ Filter : ZLib.Filter_Type;
+
+ subtype Visible_Symbols
+ is Stream_Element range 16#20# .. 16#7E#;
+
+ package Random_Elements is new
+ Ada.Numerics.Discrete_Random (Visible_Symbols);
+
+ Gen : Random_Elements.Generator;
+ Period : constant Stream_Element_Offset := 200;
+ -- Period constant variable for random generator not to be very random.
+ -- Bigger period, harder random.
+
+ Read_Buffer : Stream_Element_Array (1 .. 2048);
+ Read_First : Stream_Element_Offset;
+ Read_Last : Stream_Element_Offset;
+
+ procedure Reset;
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset);
+ -- this procedure is for generic instantiation of
+ -- ZLib.Read
+ -- reading data from the File_In.
+
+ procedure Read is new ZLib.Read
+ (Read,
+ Read_Buffer,
+ Rest_First => Read_First,
+ Rest_Last => Read_Last);
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset) is
+ begin
+ Last := Stream_Element_Offset'Min
+ (Item'Last,
+ Item'First + File_Size - Offset);
+
+ for J in Item'First .. Last loop
+ if J < Item'First + Period then
+ Item (J) := Random_Elements.Random (Gen);
+ else
+ Item (J) := Item (J - Period);
+ end if;
+
+ Offset := Offset + 1;
+ end loop;
+ end Read;
+
+ -----------
+ -- Reset --
+ -----------
+
+ procedure Reset is
+ begin
+ Random_Elements.Reset (Gen, Init_Random);
+ Pack_Size := 0;
+ Offset := 1;
+ Read_First := Read_Buffer'Last + 1;
+ Read_Last := Read_Buffer'Last;
+ end Reset;
+
+begin
+ Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version);
+
+ loop
+ for Level in ZLib.Compression_Level'Range loop
+
+ Ada.Text_IO.Put ("Level ="
+ & ZLib.Compression_Level'Image (Level));
+
+ -- Deflate using generic instantiation.
+
+ ZLib.Deflate_Init
+ (Filter,
+ Level,
+ Header => Header);
+
+ Reset;
+
+ Ada.Text_IO.Put
+ (Stream_Element_Offset'Image (File_Size) & " ->");
+
+ loop
+ declare
+ Buffer : Stream_Element_Array (1 .. 1024);
+ Last : Stream_Element_Offset;
+ begin
+ Read (Filter, Buffer, Last);
+
+ Pack_Size := Pack_Size + Last - Buffer'First + 1;
+
+ exit when Last < Buffer'Last;
+ end;
+ end loop;
+
+ Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size));
+
+ ZLib.Close (Filter);
+ end loop;
+
+ exit when not Continuous;
+
+ File_Size := File_Size + 1;
+ end loop;
+end Read;
diff --git a/zlib/contrib/ada/readme.txt b/zlib/contrib/ada/readme.txt
new file mode 100644
index 0000000..ce4d2ca
--- /dev/null
+++ b/zlib/contrib/ada/readme.txt
@@ -0,0 +1,65 @@
+ ZLib for Ada thick binding (ZLib.Ada)
+ Release 1.3
+
+ZLib.Ada is a thick binding interface to the popular ZLib data
+compression library, available at http://www.gzip.org/zlib/.
+It provides Ada-style access to the ZLib C library.
+
+
+ Here are the main changes since ZLib.Ada 1.2:
+
+- Attension: ZLib.Read generic routine have a initialization requirement
+ for Read_Last parameter now. It is a bit incompartible with previous version,
+ but extends functionality, we could use new parameters Allow_Read_Some and
+ Flush now.
+
+- Added Is_Open routines to ZLib and ZLib.Streams packages.
+
+- Add pragma Assert to check Stream_Element is 8 bit.
+
+- Fix extraction to buffer with exact known decompressed size. Error reported by
+ Steve Sangwine.
+
+- Fix definition of ULong (changed to unsigned_long), fix regression on 64 bits
+ computers. Patch provided by Pascal Obry.
+
+- Add Status_Error exception definition.
+
+- Add pragma Assertion that Ada.Streams.Stream_Element size is 8 bit.
+
+
+ How to build ZLib.Ada under GNAT
+
+You should have the ZLib library already build on your computer, before
+building ZLib.Ada. Make the directory of ZLib.Ada sources current and
+issue the command:
+
+ gnatmake test -largs -L<directory where libz.a is> -lz
+
+Or use the GNAT project file build for GNAT 3.15 or later:
+
+ gnatmake -Pzlib.gpr -L<directory where libz.a is>
+
+
+ How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2
+
+1. Make a project with all *.ads and *.adb files from the distribution.
+2. Build the libz.a library from the ZLib C sources.
+3. Rename libz.a to z.lib.
+4. Add the library z.lib to the project.
+5. Add the libc.lib library from the ObjectAda distribution to the project.
+6. Build the executable using test.adb as a main procedure.
+
+
+ How to use ZLib.Ada
+
+The source files test.adb and read.adb are small demo programs that show
+the main functionality of ZLib.Ada.
+
+The routines from the package specifications are commented.
+
+
+Homepage: http://zlib-ada.sourceforge.net/
+Author: Dmitriy Anisimkov <anisimkov@yahoo.com>
+
+Contributors: Pascal Obry <pascal@obry.org>, Steve Sangwine <sjs@essex.ac.uk>
diff --git a/zlib/contrib/ada/test.adb b/zlib/contrib/ada/test.adb
new file mode 100644
index 0000000..da96e6b
--- /dev/null
+++ b/zlib/contrib/ada/test.adb
@@ -0,0 +1,463 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: test.adb,v 1.1.1.1 2004/10/21 15:30:08 dprice Exp $
+
+-- The program has a few aims.
+-- 1. Test ZLib.Ada95 thick binding functionality.
+-- 2. Show the example of use main functionality of the ZLib.Ada95 binding.
+-- 3. Build this program automatically compile all ZLib.Ada95 packages under
+-- GNAT Ada95 compiler.
+
+with ZLib.Streams;
+with Ada.Streams.Stream_IO;
+with Ada.Numerics.Discrete_Random;
+
+with Ada.Text_IO;
+
+with Ada.Calendar;
+
+procedure Test is
+
+ use Ada.Streams;
+ use Stream_IO;
+
+ ------------------------------------
+ -- Test configuration parameters --
+ ------------------------------------
+
+ File_Size : Count := 100_000;
+ Continuous : constant Boolean := False;
+
+ Header : constant ZLib.Header_Type := ZLib.Default;
+ -- ZLib.None;
+ -- ZLib.Auto;
+ -- ZLib.GZip;
+ -- Do not use Header other then Default in ZLib versions 1.1.4
+ -- and older.
+
+ Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy;
+ Init_Random : constant := 10;
+
+ -- End --
+
+ In_File_Name : constant String := "testzlib.in";
+ -- Name of the input file
+
+ Z_File_Name : constant String := "testzlib.zlb";
+ -- Name of the compressed file.
+
+ Out_File_Name : constant String := "testzlib.out";
+ -- Name of the decompressed file.
+
+ File_In : File_Type;
+ File_Out : File_Type;
+ File_Back : File_Type;
+ File_Z : ZLib.Streams.Stream_Type;
+
+ Filter : ZLib.Filter_Type;
+
+ Time_Stamp : Ada.Calendar.Time;
+
+ procedure Generate_File;
+ -- Generate file of spetsified size with some random data.
+ -- The random data is repeatable, for the good compression.
+
+ procedure Compare_Streams
+ (Left, Right : in out Root_Stream_Type'Class);
+ -- The procedure compearing data in 2 streams.
+ -- It is for compare data before and after compression/decompression.
+
+ procedure Compare_Files (Left, Right : String);
+ -- Compare files. Based on the Compare_Streams.
+
+ procedure Copy_Streams
+ (Source, Target : in out Root_Stream_Type'Class;
+ Buffer_Size : in Stream_Element_Offset := 1024);
+ -- Copying data from one stream to another. It is for test stream
+ -- interface of the library.
+
+ procedure Data_In
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset);
+ -- this procedure is for generic instantiation of
+ -- ZLib.Generic_Translate.
+ -- reading data from the File_In.
+
+ procedure Data_Out (Item : in Stream_Element_Array);
+ -- this procedure is for generic instantiation of
+ -- ZLib.Generic_Translate.
+ -- writing data to the File_Out.
+
+ procedure Stamp;
+ -- Store the timestamp to the local variable.
+
+ procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count);
+ -- Print the time statistic with the message.
+
+ procedure Translate is new ZLib.Generic_Translate
+ (Data_In => Data_In,
+ Data_Out => Data_Out);
+ -- This procedure is moving data from File_In to File_Out
+ -- with compression or decompression, depend on initialization of
+ -- Filter parameter.
+
+ -------------------
+ -- Compare_Files --
+ -------------------
+
+ procedure Compare_Files (Left, Right : String) is
+ Left_File, Right_File : File_Type;
+ begin
+ Open (Left_File, In_File, Left);
+ Open (Right_File, In_File, Right);
+ Compare_Streams (Stream (Left_File).all, Stream (Right_File).all);
+ Close (Left_File);
+ Close (Right_File);
+ end Compare_Files;
+
+ ---------------------
+ -- Compare_Streams --
+ ---------------------
+
+ procedure Compare_Streams
+ (Left, Right : in out Ada.Streams.Root_Stream_Type'Class)
+ is
+ Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#);
+ Left_Last, Right_Last : Stream_Element_Offset;
+ begin
+ loop
+ Read (Left, Left_Buffer, Left_Last);
+ Read (Right, Right_Buffer, Right_Last);
+
+ if Left_Last /= Right_Last then
+ Ada.Text_IO.Put_Line ("Compare error :"
+ & Stream_Element_Offset'Image (Left_Last)
+ & " /= "
+ & Stream_Element_Offset'Image (Right_Last));
+
+ raise Constraint_Error;
+
+ elsif Left_Buffer (0 .. Left_Last)
+ /= Right_Buffer (0 .. Right_Last)
+ then
+ Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal.");
+ raise Constraint_Error;
+
+ end if;
+
+ exit when Left_Last < Left_Buffer'Last;
+ end loop;
+ end Compare_Streams;
+
+ ------------------
+ -- Copy_Streams --
+ ------------------
+
+ procedure Copy_Streams
+ (Source, Target : in out Ada.Streams.Root_Stream_Type'Class;
+ Buffer_Size : in Stream_Element_Offset := 1024)
+ is
+ Buffer : Stream_Element_Array (1 .. Buffer_Size);
+ Last : Stream_Element_Offset;
+ begin
+ loop
+ Read (Source, Buffer, Last);
+ Write (Target, Buffer (1 .. Last));
+
+ exit when Last < Buffer'Last;
+ end loop;
+ end Copy_Streams;
+
+ -------------
+ -- Data_In --
+ -------------
+
+ procedure Data_In
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset) is
+ begin
+ Read (File_In, Item, Last);
+ end Data_In;
+
+ --------------
+ -- Data_Out --
+ --------------
+
+ procedure Data_Out (Item : in Stream_Element_Array) is
+ begin
+ Write (File_Out, Item);
+ end Data_Out;
+
+ -------------------
+ -- Generate_File --
+ -------------------
+
+ procedure Generate_File is
+ subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#;
+
+ package Random_Elements is
+ new Ada.Numerics.Discrete_Random (Visible_Symbols);
+
+ Gen : Random_Elements.Generator;
+ Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10;
+
+ Buffer_Count : constant Count := File_Size / Buffer'Length;
+ -- Number of same buffers in the packet.
+
+ Density : constant Count := 30; -- from 0 to Buffer'Length - 2;
+
+ procedure Fill_Buffer (J, D : in Count);
+ -- Change the part of the buffer.
+
+ -----------------
+ -- Fill_Buffer --
+ -----------------
+
+ procedure Fill_Buffer (J, D : in Count) is
+ begin
+ for K in 0 .. D loop
+ Buffer
+ (Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1))
+ := Random_Elements.Random (Gen);
+
+ end loop;
+ end Fill_Buffer;
+
+ begin
+ Random_Elements.Reset (Gen, Init_Random);
+
+ Create (File_In, Out_File, In_File_Name);
+
+ Fill_Buffer (1, Buffer'Length - 2);
+
+ for J in 1 .. Buffer_Count loop
+ Write (File_In, Buffer);
+
+ Fill_Buffer (J, Density);
+ end loop;
+
+ -- fill remain size.
+
+ Write
+ (File_In,
+ Buffer
+ (1 .. Stream_Element_Offset
+ (File_Size - Buffer'Length * Buffer_Count)));
+
+ Flush (File_In);
+ Close (File_In);
+ end Generate_File;
+
+ ---------------------
+ -- Print_Statistic --
+ ---------------------
+
+ procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is
+ use Ada.Calendar;
+ use Ada.Text_IO;
+
+ package Count_IO is new Integer_IO (ZLib.Count);
+
+ Curr_Dur : Duration := Clock - Time_Stamp;
+ begin
+ Put (Msg);
+
+ Set_Col (20);
+ Ada.Text_IO.Put ("size =");
+
+ Count_IO.Put
+ (Data_Size,
+ Width => Stream_IO.Count'Image (File_Size)'Length);
+
+ Put_Line (" duration =" & Duration'Image (Curr_Dur));
+ end Print_Statistic;
+
+ -----------
+ -- Stamp --
+ -----------
+
+ procedure Stamp is
+ begin
+ Time_Stamp := Ada.Calendar.Clock;
+ end Stamp;
+
+begin
+ Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version);
+
+ loop
+ Generate_File;
+
+ for Level in ZLib.Compression_Level'Range loop
+
+ Ada.Text_IO.Put_Line ("Level ="
+ & ZLib.Compression_Level'Image (Level));
+
+ -- Test generic interface.
+ Open (File_In, In_File, In_File_Name);
+ Create (File_Out, Out_File, Z_File_Name);
+
+ Stamp;
+
+ -- Deflate using generic instantiation.
+
+ ZLib.Deflate_Init
+ (Filter => Filter,
+ Level => Level,
+ Strategy => Strategy,
+ Header => Header);
+
+ Translate (Filter);
+ Print_Statistic ("Generic compress", ZLib.Total_Out (Filter));
+ ZLib.Close (Filter);
+
+ Close (File_In);
+ Close (File_Out);
+
+ Open (File_In, In_File, Z_File_Name);
+ Create (File_Out, Out_File, Out_File_Name);
+
+ Stamp;
+
+ -- Inflate using generic instantiation.
+
+ ZLib.Inflate_Init (Filter, Header => Header);
+
+ Translate (Filter);
+ Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter));
+
+ ZLib.Close (Filter);
+
+ Close (File_In);
+ Close (File_Out);
+
+ Compare_Files (In_File_Name, Out_File_Name);
+
+ -- Test stream interface.
+
+ -- Compress to the back stream.
+
+ Open (File_In, In_File, In_File_Name);
+ Create (File_Back, Out_File, Z_File_Name);
+
+ Stamp;
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.Out_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => True,
+ Level => Level,
+ Strategy => Strategy,
+ Header => Header);
+
+ Copy_Streams
+ (Source => Stream (File_In).all,
+ Target => File_Z);
+
+ -- Flushing internal buffers to the back stream.
+
+ ZLib.Streams.Flush (File_Z, ZLib.Finish);
+
+ Print_Statistic ("Write compress",
+ ZLib.Streams.Write_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+
+ Close (File_In);
+ Close (File_Back);
+
+ -- Compare reading from original file and from
+ -- decompression stream.
+
+ Open (File_In, In_File, In_File_Name);
+ Open (File_Back, In_File, Z_File_Name);
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.In_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => True,
+ Header => Header);
+
+ Stamp;
+ Compare_Streams (Stream (File_In).all, File_Z);
+
+ Print_Statistic ("Read decompress",
+ ZLib.Streams.Read_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+ Close (File_In);
+ Close (File_Back);
+
+ -- Compress by reading from compression stream.
+
+ Open (File_Back, In_File, In_File_Name);
+ Create (File_Out, Out_File, Z_File_Name);
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.In_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => False,
+ Level => Level,
+ Strategy => Strategy,
+ Header => Header);
+
+ Stamp;
+ Copy_Streams
+ (Source => File_Z,
+ Target => Stream (File_Out).all);
+
+ Print_Statistic ("Read compress",
+ ZLib.Streams.Read_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+
+ Close (File_Out);
+ Close (File_Back);
+
+ -- Decompress to decompression stream.
+
+ Open (File_In, In_File, Z_File_Name);
+ Create (File_Back, Out_File, Out_File_Name);
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.Out_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => False,
+ Header => Header);
+
+ Stamp;
+
+ Copy_Streams
+ (Source => Stream (File_In).all,
+ Target => File_Z);
+
+ Print_Statistic ("Write decompress",
+ ZLib.Streams.Write_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+ Close (File_In);
+ Close (File_Back);
+
+ Compare_Files (In_File_Name, Out_File_Name);
+ end loop;
+
+ Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok.");
+
+ exit when not Continuous;
+
+ File_Size := File_Size + 1;
+ end loop;
+end Test;
diff --git a/zlib/contrib/ada/zlib-streams.adb b/zlib/contrib/ada/zlib-streams.adb
new file mode 100644
index 0000000..fa8b79d
--- /dev/null
+++ b/zlib/contrib/ada/zlib-streams.adb
@@ -0,0 +1,225 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-streams.adb,v 1.1.1.2 2005/02/20 17:57:20 dprice Exp $
+
+with Ada.Unchecked_Deallocation;
+
+package body ZLib.Streams is
+
+ -----------
+ -- Close --
+ -----------
+
+ procedure Close (Stream : in out Stream_Type) is
+ procedure Free is new Ada.Unchecked_Deallocation
+ (Stream_Element_Array, Buffer_Access);
+ begin
+ if Stream.Mode = Out_Stream or Stream.Mode = Duplex then
+ -- We should flush the data written by the writer.
+
+ Flush (Stream, Finish);
+
+ Close (Stream.Writer);
+ end if;
+
+ if Stream.Mode = In_Stream or Stream.Mode = Duplex then
+ Close (Stream.Reader);
+ Free (Stream.Buffer);
+ end if;
+ end Close;
+
+ ------------
+ -- Create --
+ ------------
+
+ procedure Create
+ (Stream : out Stream_Type;
+ Mode : in Stream_Mode;
+ Back : in Stream_Access;
+ Back_Compressed : in Boolean;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Header : in Header_Type := Default;
+ Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size;
+ Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size)
+ is
+
+ subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size);
+
+ procedure Init_Filter
+ (Filter : in out Filter_Type;
+ Compress : in Boolean);
+
+ -----------------
+ -- Init_Filter --
+ -----------------
+
+ procedure Init_Filter
+ (Filter : in out Filter_Type;
+ Compress : in Boolean) is
+ begin
+ if Compress then
+ Deflate_Init
+ (Filter, Level, Strategy, Header => Header);
+ else
+ Inflate_Init (Filter, Header => Header);
+ end if;
+ end Init_Filter;
+
+ begin
+ Stream.Back := Back;
+ Stream.Mode := Mode;
+
+ if Mode = Out_Stream or Mode = Duplex then
+ Init_Filter (Stream.Writer, Back_Compressed);
+ Stream.Buffer_Size := Write_Buffer_Size;
+ else
+ Stream.Buffer_Size := 0;
+ end if;
+
+ if Mode = In_Stream or Mode = Duplex then
+ Init_Filter (Stream.Reader, not Back_Compressed);
+
+ Stream.Buffer := new Buffer_Subtype;
+ Stream.Rest_First := Stream.Buffer'Last + 1;
+ Stream.Rest_Last := Stream.Buffer'Last;
+ end if;
+ end Create;
+
+ -----------
+ -- Flush --
+ -----------
+
+ procedure Flush
+ (Stream : in out Stream_Type;
+ Mode : in Flush_Mode := Sync_Flush)
+ is
+ Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size);
+ Last : Stream_Element_Offset;
+ begin
+ loop
+ Flush (Stream.Writer, Buffer, Last, Mode);
+
+ Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last));
+
+ exit when Last < Buffer'Last;
+ end loop;
+ end Flush;
+
+ -------------
+ -- Is_Open --
+ -------------
+
+ function Is_Open (Stream : Stream_Type) return Boolean is
+ begin
+ return Is_Open (Stream.Reader) or else Is_Open (Stream.Writer);
+ end Is_Open;
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Stream : in out Stream_Type;
+ Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset)
+ is
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset);
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset) is
+ begin
+ Ada.Streams.Read (Stream.Back.all, Item, Last);
+ end Read;
+
+ procedure Read is new ZLib.Read
+ (Read => Read,
+ Buffer => Stream.Buffer.all,
+ Rest_First => Stream.Rest_First,
+ Rest_Last => Stream.Rest_Last);
+
+ begin
+ Read (Stream.Reader, Item, Last);
+ end Read;
+
+ -------------------
+ -- Read_Total_In --
+ -------------------
+
+ function Read_Total_In (Stream : in Stream_Type) return Count is
+ begin
+ return Total_In (Stream.Reader);
+ end Read_Total_In;
+
+ --------------------
+ -- Read_Total_Out --
+ --------------------
+
+ function Read_Total_Out (Stream : in Stream_Type) return Count is
+ begin
+ return Total_Out (Stream.Reader);
+ end Read_Total_Out;
+
+ -----------
+ -- Write --
+ -----------
+
+ procedure Write
+ (Stream : in out Stream_Type;
+ Item : in Stream_Element_Array)
+ is
+
+ procedure Write (Item : in Stream_Element_Array);
+
+ -----------
+ -- Write --
+ -----------
+
+ procedure Write (Item : in Stream_Element_Array) is
+ begin
+ Ada.Streams.Write (Stream.Back.all, Item);
+ end Write;
+
+ procedure Write is new ZLib.Write
+ (Write => Write,
+ Buffer_Size => Stream.Buffer_Size);
+
+ begin
+ Write (Stream.Writer, Item, No_Flush);
+ end Write;
+
+ --------------------
+ -- Write_Total_In --
+ --------------------
+
+ function Write_Total_In (Stream : in Stream_Type) return Count is
+ begin
+ return Total_In (Stream.Writer);
+ end Write_Total_In;
+
+ ---------------------
+ -- Write_Total_Out --
+ ---------------------
+
+ function Write_Total_Out (Stream : in Stream_Type) return Count is
+ begin
+ return Total_Out (Stream.Writer);
+ end Write_Total_Out;
+
+end ZLib.Streams;
diff --git a/zlib/contrib/ada/zlib-streams.ads b/zlib/contrib/ada/zlib-streams.ads
new file mode 100644
index 0000000..3c216f1
--- /dev/null
+++ b/zlib/contrib/ada/zlib-streams.ads
@@ -0,0 +1,114 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-streams.ads,v 1.1.1.2 2005/02/20 17:57:20 dprice Exp $
+
+package ZLib.Streams is
+
+ type Stream_Mode is (In_Stream, Out_Stream, Duplex);
+
+ type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class;
+
+ type Stream_Type is
+ new Ada.Streams.Root_Stream_Type with private;
+
+ procedure Read
+ (Stream : in out Stream_Type;
+ Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+
+ procedure Write
+ (Stream : in out Stream_Type;
+ Item : in Ada.Streams.Stream_Element_Array);
+
+ procedure Flush
+ (Stream : in out Stream_Type;
+ Mode : in Flush_Mode := Sync_Flush);
+ -- Flush the written data to the back stream,
+ -- all data placed to the compressor is flushing to the Back stream.
+ -- Should not be used untill necessary, becouse it is decreasing
+ -- compression.
+
+ function Read_Total_In (Stream : in Stream_Type) return Count;
+ pragma Inline (Read_Total_In);
+ -- Return total number of bytes read from back stream so far.
+
+ function Read_Total_Out (Stream : in Stream_Type) return Count;
+ pragma Inline (Read_Total_Out);
+ -- Return total number of bytes read so far.
+
+ function Write_Total_In (Stream : in Stream_Type) return Count;
+ pragma Inline (Write_Total_In);
+ -- Return total number of bytes written so far.
+
+ function Write_Total_Out (Stream : in Stream_Type) return Count;
+ pragma Inline (Write_Total_Out);
+ -- Return total number of bytes written to the back stream.
+
+ procedure Create
+ (Stream : out Stream_Type;
+ Mode : in Stream_Mode;
+ Back : in Stream_Access;
+ Back_Compressed : in Boolean;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Header : in Header_Type := Default;
+ Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size;
+ Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size);
+ -- Create the Comression/Decompression stream.
+ -- If mode is In_Stream then Write operation is disabled.
+ -- If mode is Out_Stream then Read operation is disabled.
+
+ -- If Back_Compressed is true then
+ -- Data written to the Stream is compressing to the Back stream
+ -- and data read from the Stream is decompressed data from the Back stream.
+
+ -- If Back_Compressed is false then
+ -- Data written to the Stream is decompressing to the Back stream
+ -- and data read from the Stream is compressed data from the Back stream.
+
+ -- !!! When the Need_Header is False ZLib-Ada is using undocumented
+ -- ZLib 1.1.4 functionality to do not create/wait for ZLib headers.
+
+ function Is_Open (Stream : Stream_Type) return Boolean;
+
+ procedure Close (Stream : in out Stream_Type);
+
+private
+
+ use Ada.Streams;
+
+ type Buffer_Access is access all Stream_Element_Array;
+
+ type Stream_Type
+ is new Root_Stream_Type with
+ record
+ Mode : Stream_Mode;
+
+ Buffer : Buffer_Access;
+ Rest_First : Stream_Element_Offset;
+ Rest_Last : Stream_Element_Offset;
+ -- Buffer for Read operation.
+ -- We need to have this buffer in the record
+ -- becouse not all read data from back stream
+ -- could be processed during the read operation.
+
+ Buffer_Size : Stream_Element_Offset;
+ -- Buffer size for write operation.
+ -- We do not need to have this buffer
+ -- in the record becouse all data could be
+ -- processed in the write operation.
+
+ Back : Stream_Access;
+ Reader : Filter_Type;
+ Writer : Filter_Type;
+ end record;
+
+end ZLib.Streams;
diff --git a/zlib/contrib/ada/zlib-thin.adb b/zlib/contrib/ada/zlib-thin.adb
new file mode 100644
index 0000000..0728251
--- /dev/null
+++ b/zlib/contrib/ada/zlib-thin.adb
@@ -0,0 +1,141 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-thin.adb,v 1.1.1.2 2005/02/20 17:57:20 dprice Exp $
+
+package body ZLib.Thin is
+
+ ZLIB_VERSION : constant Chars_Ptr := zlibVersion;
+
+ Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit;
+
+ --------------
+ -- Avail_In --
+ --------------
+
+ function Avail_In (Strm : in Z_Stream) return UInt is
+ begin
+ return Strm.Avail_In;
+ end Avail_In;
+
+ ---------------
+ -- Avail_Out --
+ ---------------
+
+ function Avail_Out (Strm : in Z_Stream) return UInt is
+ begin
+ return Strm.Avail_Out;
+ end Avail_Out;
+
+ ------------------
+ -- Deflate_Init --
+ ------------------
+
+ function Deflate_Init
+ (strm : Z_Streamp;
+ level : Int;
+ method : Int;
+ windowBits : Int;
+ memLevel : Int;
+ strategy : Int)
+ return Int is
+ begin
+ return deflateInit2
+ (strm,
+ level,
+ method,
+ windowBits,
+ memLevel,
+ strategy,
+ ZLIB_VERSION,
+ Z_Stream_Size);
+ end Deflate_Init;
+
+ ------------------
+ -- Inflate_Init --
+ ------------------
+
+ function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is
+ begin
+ return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size);
+ end Inflate_Init;
+
+ ------------------------
+ -- Last_Error_Message --
+ ------------------------
+
+ function Last_Error_Message (Strm : in Z_Stream) return String is
+ use Interfaces.C.Strings;
+ begin
+ if Strm.msg = Null_Ptr then
+ return "";
+ else
+ return Value (Strm.msg);
+ end if;
+ end Last_Error_Message;
+
+ ------------
+ -- Set_In --
+ ------------
+
+ procedure Set_In
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt) is
+ begin
+ Strm.Next_In := Buffer;
+ Strm.Avail_In := Size;
+ end Set_In;
+
+ ------------------
+ -- Set_Mem_Func --
+ ------------------
+
+ procedure Set_Mem_Func
+ (Strm : in out Z_Stream;
+ Opaque : in Voidp;
+ Alloc : in alloc_func;
+ Free : in free_func) is
+ begin
+ Strm.opaque := Opaque;
+ Strm.zalloc := Alloc;
+ Strm.zfree := Free;
+ end Set_Mem_Func;
+
+ -------------
+ -- Set_Out --
+ -------------
+
+ procedure Set_Out
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt) is
+ begin
+ Strm.Next_Out := Buffer;
+ Strm.Avail_Out := Size;
+ end Set_Out;
+
+ --------------
+ -- Total_In --
+ --------------
+
+ function Total_In (Strm : in Z_Stream) return ULong is
+ begin
+ return Strm.Total_In;
+ end Total_In;
+
+ ---------------
+ -- Total_Out --
+ ---------------
+
+ function Total_Out (Strm : in Z_Stream) return ULong is
+ begin
+ return Strm.Total_Out;
+ end Total_Out;
+
+end ZLib.Thin;
diff --git a/zlib/contrib/ada/zlib-thin.ads b/zlib/contrib/ada/zlib-thin.ads
new file mode 100644
index 0000000..eb234a4
--- /dev/null
+++ b/zlib/contrib/ada/zlib-thin.ads
@@ -0,0 +1,450 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-thin.ads,v 1.1.1.2 2005/02/20 17:57:20 dprice Exp $
+
+with Interfaces.C.Strings;
+
+with System;
+
+private package ZLib.Thin is
+
+ -- From zconf.h
+
+ MAX_MEM_LEVEL : constant := 9; -- zconf.h:105
+ -- zconf.h:105
+ MAX_WBITS : constant := 15; -- zconf.h:115
+ -- 32K LZ77 window
+ -- zconf.h:115
+ SEEK_SET : constant := 8#0000#; -- zconf.h:244
+ -- Seek from beginning of file.
+ -- zconf.h:244
+ SEEK_CUR : constant := 1; -- zconf.h:245
+ -- Seek from current position.
+ -- zconf.h:245
+ SEEK_END : constant := 2; -- zconf.h:246
+ -- Set file pointer to EOF plus "offset"
+ -- zconf.h:246
+
+ type Byte is new Interfaces.C.unsigned_char; -- 8 bits
+ -- zconf.h:214
+ type UInt is new Interfaces.C.unsigned; -- 16 bits or more
+ -- zconf.h:216
+ type Int is new Interfaces.C.int;
+
+ type ULong is new Interfaces.C.unsigned_long; -- 32 bits or more
+ -- zconf.h:217
+ subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr;
+
+ type ULong_Access is access ULong;
+ type Int_Access is access Int;
+
+ subtype Voidp is System.Address; -- zconf.h:232
+
+ subtype Byte_Access is Voidp;
+
+ Nul : constant Voidp := System.Null_Address;
+ -- end from zconf
+
+ Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125
+ -- zlib.h:125
+ Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126
+ -- will be removed, use
+ -- Z_SYNC_FLUSH instead
+ -- zlib.h:126
+ Z_SYNC_FLUSH : constant := 2; -- zlib.h:127
+ -- zlib.h:127
+ Z_FULL_FLUSH : constant := 3; -- zlib.h:128
+ -- zlib.h:128
+ Z_FINISH : constant := 4; -- zlib.h:129
+ -- zlib.h:129
+ Z_OK : constant := 8#0000#; -- zlib.h:132
+ -- zlib.h:132
+ Z_STREAM_END : constant := 1; -- zlib.h:133
+ -- zlib.h:133
+ Z_NEED_DICT : constant := 2; -- zlib.h:134
+ -- zlib.h:134
+ Z_ERRNO : constant := -1; -- zlib.h:135
+ -- zlib.h:135
+ Z_STREAM_ERROR : constant := -2; -- zlib.h:136
+ -- zlib.h:136
+ Z_DATA_ERROR : constant := -3; -- zlib.h:137
+ -- zlib.h:137
+ Z_MEM_ERROR : constant := -4; -- zlib.h:138
+ -- zlib.h:138
+ Z_BUF_ERROR : constant := -5; -- zlib.h:139
+ -- zlib.h:139
+ Z_VERSION_ERROR : constant := -6; -- zlib.h:140
+ -- zlib.h:140
+ Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145
+ -- zlib.h:145
+ Z_BEST_SPEED : constant := 1; -- zlib.h:146
+ -- zlib.h:146
+ Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147
+ -- zlib.h:147
+ Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148
+ -- zlib.h:148
+ Z_FILTERED : constant := 1; -- zlib.h:151
+ -- zlib.h:151
+ Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152
+ -- zlib.h:152
+ Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153
+ -- zlib.h:153
+ Z_BINARY : constant := 8#0000#; -- zlib.h:156
+ -- zlib.h:156
+ Z_ASCII : constant := 1; -- zlib.h:157
+ -- zlib.h:157
+ Z_UNKNOWN : constant := 2; -- zlib.h:158
+ -- zlib.h:158
+ Z_DEFLATED : constant := 8; -- zlib.h:161
+ -- zlib.h:161
+ Z_NULL : constant := 8#0000#; -- zlib.h:164
+ -- for initializing zalloc, zfree, opaque
+ -- zlib.h:164
+ type gzFile is new Voidp; -- zlib.h:646
+
+ type Z_Stream is private;
+
+ type Z_Streamp is access all Z_Stream; -- zlib.h:89
+
+ type alloc_func is access function
+ (Opaque : Voidp;
+ Items : UInt;
+ Size : UInt)
+ return Voidp; -- zlib.h:63
+
+ type free_func is access procedure (opaque : Voidp; address : Voidp);
+
+ function zlibVersion return Chars_Ptr;
+
+ function Deflate (strm : Z_Streamp; flush : Int) return Int;
+
+ function DeflateEnd (strm : Z_Streamp) return Int;
+
+ function Inflate (strm : Z_Streamp; flush : Int) return Int;
+
+ function InflateEnd (strm : Z_Streamp) return Int;
+
+ function deflateSetDictionary
+ (strm : Z_Streamp;
+ dictionary : Byte_Access;
+ dictLength : UInt)
+ return Int;
+
+ function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int;
+ -- zlib.h:478
+
+ function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495
+
+ function deflateParams
+ (strm : Z_Streamp;
+ level : Int;
+ strategy : Int)
+ return Int; -- zlib.h:506
+
+ function inflateSetDictionary
+ (strm : Z_Streamp;
+ dictionary : Byte_Access;
+ dictLength : UInt)
+ return Int; -- zlib.h:548
+
+ function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565
+
+ function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580
+
+ function compress
+ (dest : Byte_Access;
+ destLen : ULong_Access;
+ source : Byte_Access;
+ sourceLen : ULong)
+ return Int; -- zlib.h:601
+
+ function compress2
+ (dest : Byte_Access;
+ destLen : ULong_Access;
+ source : Byte_Access;
+ sourceLen : ULong;
+ level : Int)
+ return Int; -- zlib.h:615
+
+ function uncompress
+ (dest : Byte_Access;
+ destLen : ULong_Access;
+ source : Byte_Access;
+ sourceLen : ULong)
+ return Int;
+
+ function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile;
+
+ function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile;
+
+ function gzsetparams
+ (file : gzFile;
+ level : Int;
+ strategy : Int)
+ return Int;
+
+ function gzread
+ (file : gzFile;
+ buf : Voidp;
+ len : UInt)
+ return Int;
+
+ function gzwrite
+ (file : in gzFile;
+ buf : in Voidp;
+ len : in UInt)
+ return Int;
+
+ function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int;
+
+ function gzputs (file : in gzFile; s : in Chars_Ptr) return Int;
+
+ function gzgets
+ (file : gzFile;
+ buf : Chars_Ptr;
+ len : Int)
+ return Chars_Ptr;
+
+ function gzputc (file : gzFile; char : Int) return Int;
+
+ function gzgetc (file : gzFile) return Int;
+
+ function gzflush (file : gzFile; flush : Int) return Int;
+
+ function gzseek
+ (file : gzFile;
+ offset : Int;
+ whence : Int)
+ return Int;
+
+ function gzrewind (file : gzFile) return Int;
+
+ function gztell (file : gzFile) return Int;
+
+ function gzeof (file : gzFile) return Int;
+
+ function gzclose (file : gzFile) return Int;
+
+ function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr;
+
+ function adler32
+ (adler : ULong;
+ buf : Byte_Access;
+ len : UInt)
+ return ULong;
+
+ function crc32
+ (crc : ULong;
+ buf : Byte_Access;
+ len : UInt)
+ return ULong;
+
+ function deflateInit
+ (strm : Z_Streamp;
+ level : Int;
+ version : Chars_Ptr;
+ stream_size : Int)
+ return Int;
+
+ function deflateInit2
+ (strm : Z_Streamp;
+ level : Int;
+ method : Int;
+ windowBits : Int;
+ memLevel : Int;
+ strategy : Int;
+ version : Chars_Ptr;
+ stream_size : Int)
+ return Int;
+
+ function Deflate_Init
+ (strm : Z_Streamp;
+ level : Int;
+ method : Int;
+ windowBits : Int;
+ memLevel : Int;
+ strategy : Int)
+ return Int;
+ pragma Inline (Deflate_Init);
+
+ function inflateInit
+ (strm : Z_Streamp;
+ version : Chars_Ptr;
+ stream_size : Int)
+ return Int;
+
+ function inflateInit2
+ (strm : in Z_Streamp;
+ windowBits : in Int;
+ version : in Chars_Ptr;
+ stream_size : in Int)
+ return Int;
+
+ function inflateBackInit
+ (strm : in Z_Streamp;
+ windowBits : in Int;
+ window : in Byte_Access;
+ version : in Chars_Ptr;
+ stream_size : in Int)
+ return Int;
+ -- Size of window have to be 2**windowBits.
+
+ function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int;
+ pragma Inline (Inflate_Init);
+
+ function zError (err : Int) return Chars_Ptr;
+
+ function inflateSyncPoint (z : Z_Streamp) return Int;
+
+ function get_crc_table return ULong_Access;
+
+ -- Interface to the available fields of the z_stream structure.
+ -- The application must update next_in and avail_in when avail_in has
+ -- dropped to zero. It must update next_out and avail_out when avail_out
+ -- has dropped to zero. The application must initialize zalloc, zfree and
+ -- opaque before calling the init function.
+
+ procedure Set_In
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt);
+ pragma Inline (Set_In);
+
+ procedure Set_Out
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt);
+ pragma Inline (Set_Out);
+
+ procedure Set_Mem_Func
+ (Strm : in out Z_Stream;
+ Opaque : in Voidp;
+ Alloc : in alloc_func;
+ Free : in free_func);
+ pragma Inline (Set_Mem_Func);
+
+ function Last_Error_Message (Strm : in Z_Stream) return String;
+ pragma Inline (Last_Error_Message);
+
+ function Avail_Out (Strm : in Z_Stream) return UInt;
+ pragma Inline (Avail_Out);
+
+ function Avail_In (Strm : in Z_Stream) return UInt;
+ pragma Inline (Avail_In);
+
+ function Total_In (Strm : in Z_Stream) return ULong;
+ pragma Inline (Total_In);
+
+ function Total_Out (Strm : in Z_Stream) return ULong;
+ pragma Inline (Total_Out);
+
+ function inflateCopy
+ (dest : in Z_Streamp;
+ Source : in Z_Streamp)
+ return Int;
+
+ function compressBound (Source_Len : in ULong) return ULong;
+
+ function deflateBound
+ (Strm : in Z_Streamp;
+ Source_Len : in ULong)
+ return ULong;
+
+ function gzungetc (C : in Int; File : in gzFile) return Int;
+
+ function zlibCompileFlags return ULong;
+
+private
+
+ type Z_Stream is record -- zlib.h:68
+ Next_In : Voidp := Nul; -- next input byte
+ Avail_In : UInt := 0; -- number of bytes available at next_in
+ Total_In : ULong := 0; -- total nb of input bytes read so far
+ Next_Out : Voidp := Nul; -- next output byte should be put there
+ Avail_Out : UInt := 0; -- remaining free space at next_out
+ Total_Out : ULong := 0; -- total nb of bytes output so far
+ msg : Chars_Ptr; -- last error message, NULL if no error
+ state : Voidp; -- not visible by applications
+ zalloc : alloc_func := null; -- used to allocate the internal state
+ zfree : free_func := null; -- used to free the internal state
+ opaque : Voidp; -- private data object passed to
+ -- zalloc and zfree
+ data_type : Int; -- best guess about the data type:
+ -- ascii or binary
+ adler : ULong; -- adler32 value of the uncompressed
+ -- data
+ reserved : ULong; -- reserved for future use
+ end record;
+
+ pragma Convention (C, Z_Stream);
+
+ pragma Import (C, zlibVersion, "zlibVersion");
+ pragma Import (C, Deflate, "deflate");
+ pragma Import (C, DeflateEnd, "deflateEnd");
+ pragma Import (C, Inflate, "inflate");
+ pragma Import (C, InflateEnd, "inflateEnd");
+ pragma Import (C, deflateSetDictionary, "deflateSetDictionary");
+ pragma Import (C, deflateCopy, "deflateCopy");
+ pragma Import (C, deflateReset, "deflateReset");
+ pragma Import (C, deflateParams, "deflateParams");
+ pragma Import (C, inflateSetDictionary, "inflateSetDictionary");
+ pragma Import (C, inflateSync, "inflateSync");
+ pragma Import (C, inflateReset, "inflateReset");
+ pragma Import (C, compress, "compress");
+ pragma Import (C, compress2, "compress2");
+ pragma Import (C, uncompress, "uncompress");
+ pragma Import (C, gzopen, "gzopen");
+ pragma Import (C, gzdopen, "gzdopen");
+ pragma Import (C, gzsetparams, "gzsetparams");
+ pragma Import (C, gzread, "gzread");
+ pragma Import (C, gzwrite, "gzwrite");
+ pragma Import (C, gzprintf, "gzprintf");
+ pragma Import (C, gzputs, "gzputs");
+ pragma Import (C, gzgets, "gzgets");
+ pragma Import (C, gzputc, "gzputc");
+ pragma Import (C, gzgetc, "gzgetc");
+ pragma Import (C, gzflush, "gzflush");
+ pragma Import (C, gzseek, "gzseek");
+ pragma Import (C, gzrewind, "gzrewind");
+ pragma Import (C, gztell, "gztell");
+ pragma Import (C, gzeof, "gzeof");
+ pragma Import (C, gzclose, "gzclose");
+ pragma Import (C, gzerror, "gzerror");
+ pragma Import (C, adler32, "adler32");
+ pragma Import (C, crc32, "crc32");
+ pragma Import (C, deflateInit, "deflateInit_");
+ pragma Import (C, inflateInit, "inflateInit_");
+ pragma Import (C, deflateInit2, "deflateInit2_");
+ pragma Import (C, inflateInit2, "inflateInit2_");
+ pragma Import (C, zError, "zError");
+ pragma Import (C, inflateSyncPoint, "inflateSyncPoint");
+ pragma Import (C, get_crc_table, "get_crc_table");
+
+ -- since zlib 1.2.0:
+
+ pragma Import (C, inflateCopy, "inflateCopy");
+ pragma Import (C, compressBound, "compressBound");
+ pragma Import (C, deflateBound, "deflateBound");
+ pragma Import (C, gzungetc, "gzungetc");
+ pragma Import (C, zlibCompileFlags, "zlibCompileFlags");
+
+ pragma Import (C, inflateBackInit, "inflateBackInit_");
+
+ -- I stopped binding the inflateBack routines, becouse realize that
+ -- it does not support zlib and gzip headers for now, and have no
+ -- symmetric deflateBack routines.
+ -- ZLib-Ada is symmetric regarding deflate/inflate data transformation
+ -- and has a similar generic callback interface for the
+ -- deflate/inflate transformation based on the regular Deflate/Inflate
+ -- routines.
+
+ -- pragma Import (C, inflateBack, "inflateBack");
+ -- pragma Import (C, inflateBackEnd, "inflateBackEnd");
+
+end ZLib.Thin;
diff --git a/zlib/contrib/ada/zlib.adb b/zlib/contrib/ada/zlib.adb
new file mode 100644
index 0000000..29c89ea
--- /dev/null
+++ b/zlib/contrib/ada/zlib.adb
@@ -0,0 +1,701 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2004 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib.adb,v 1.1.1.2 2005/02/20 17:57:26 dprice Exp $
+
+with Ada.Exceptions;
+with Ada.Unchecked_Conversion;
+with Ada.Unchecked_Deallocation;
+
+with Interfaces.C.Strings;
+
+with ZLib.Thin;
+
+package body ZLib is
+
+ use type Thin.Int;
+
+ type Z_Stream is new Thin.Z_Stream;
+
+ type Return_Code_Enum is
+ (OK,
+ STREAM_END,
+ NEED_DICT,
+ ERRNO,
+ STREAM_ERROR,
+ DATA_ERROR,
+ MEM_ERROR,
+ BUF_ERROR,
+ VERSION_ERROR);
+
+ type Flate_Step_Function is access
+ function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int;
+ pragma Convention (C, Flate_Step_Function);
+
+ type Flate_End_Function is access
+ function (Ctrm : in Thin.Z_Streamp) return Thin.Int;
+ pragma Convention (C, Flate_End_Function);
+
+ type Flate_Type is record
+ Step : Flate_Step_Function;
+ Done : Flate_End_Function;
+ end record;
+
+ subtype Footer_Array is Stream_Element_Array (1 .. 8);
+
+ Simple_GZip_Header : constant Stream_Element_Array (1 .. 10)
+ := (16#1f#, 16#8b#, -- Magic header
+ 16#08#, -- Z_DEFLATED
+ 16#00#, -- Flags
+ 16#00#, 16#00#, 16#00#, 16#00#, -- Time
+ 16#00#, -- XFlags
+ 16#03# -- OS code
+ );
+ -- The simplest gzip header is not for informational, but just for
+ -- gzip format compatibility.
+ -- Note that some code below is using assumption
+ -- Simple_GZip_Header'Last > Footer_Array'Last, so do not make
+ -- Simple_GZip_Header'Last <= Footer_Array'Last.
+
+ Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum
+ := (0 => OK,
+ 1 => STREAM_END,
+ 2 => NEED_DICT,
+ -1 => ERRNO,
+ -2 => STREAM_ERROR,
+ -3 => DATA_ERROR,
+ -4 => MEM_ERROR,
+ -5 => BUF_ERROR,
+ -6 => VERSION_ERROR);
+
+ Flate : constant array (Boolean) of Flate_Type
+ := (True => (Step => Thin.Deflate'Access,
+ Done => Thin.DeflateEnd'Access),
+ False => (Step => Thin.Inflate'Access,
+ Done => Thin.InflateEnd'Access));
+
+ Flush_Finish : constant array (Boolean) of Flush_Mode
+ := (True => Finish, False => No_Flush);
+
+ procedure Raise_Error (Stream : in Z_Stream);
+ pragma Inline (Raise_Error);
+
+ procedure Raise_Error (Message : in String);
+ pragma Inline (Raise_Error);
+
+ procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int);
+
+ procedure Free is new Ada.Unchecked_Deallocation
+ (Z_Stream, Z_Stream_Access);
+
+ function To_Thin_Access is new Ada.Unchecked_Conversion
+ (Z_Stream_Access, Thin.Z_Streamp);
+
+ procedure Translate_GZip
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ -- Separate translate routine for make gzip header.
+
+ procedure Translate_Auto
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ -- translate routine without additional headers.
+
+ -----------------
+ -- Check_Error --
+ -----------------
+
+ procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is
+ use type Thin.Int;
+ begin
+ if Code /= Thin.Z_OK then
+ Raise_Error
+ (Return_Code_Enum'Image (Return_Code (Code))
+ & ": " & Last_Error_Message (Stream));
+ end if;
+ end Check_Error;
+
+ -----------
+ -- Close --
+ -----------
+
+ procedure Close
+ (Filter : in out Filter_Type;
+ Ignore_Error : in Boolean := False)
+ is
+ Code : Thin.Int;
+ begin
+ if not Ignore_Error and then not Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm));
+
+ if Ignore_Error or else Code = Thin.Z_OK then
+ Free (Filter.Strm);
+ else
+ declare
+ Error_Message : constant String
+ := Last_Error_Message (Filter.Strm.all);
+ begin
+ Free (Filter.Strm);
+ Ada.Exceptions.Raise_Exception
+ (ZLib_Error'Identity,
+ Return_Code_Enum'Image (Return_Code (Code))
+ & ": " & Error_Message);
+ end;
+ end if;
+ end Close;
+
+ -----------
+ -- CRC32 --
+ -----------
+
+ function CRC32
+ (CRC : in Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array)
+ return Unsigned_32
+ is
+ use Thin;
+ begin
+ return Unsigned_32 (crc32 (ULong (CRC),
+ Data'Address,
+ Data'Length));
+ end CRC32;
+
+ procedure CRC32
+ (CRC : in out Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array) is
+ begin
+ CRC := CRC32 (CRC, Data);
+ end CRC32;
+
+ ------------------
+ -- Deflate_Init --
+ ------------------
+
+ procedure Deflate_Init
+ (Filter : in out Filter_Type;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Method : in Compression_Method := Deflated;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Memory_Level : in Memory_Level_Type := Default_Memory_Level;
+ Header : in Header_Type := Default)
+ is
+ use type Thin.Int;
+ Win_Bits : Thin.Int := Thin.Int (Window_Bits);
+ begin
+ if Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ -- We allow ZLib to make header only in case of default header type.
+ -- Otherwise we would either do header by ourselfs, or do not do
+ -- header at all.
+
+ if Header = None or else Header = GZip then
+ Win_Bits := -Win_Bits;
+ end if;
+
+ -- For the GZip CRC calculation and make headers.
+
+ if Header = GZip then
+ Filter.CRC := 0;
+ Filter.Offset := Simple_GZip_Header'First;
+ else
+ Filter.Offset := Simple_GZip_Header'Last + 1;
+ end if;
+
+ Filter.Strm := new Z_Stream;
+ Filter.Compression := True;
+ Filter.Stream_End := False;
+ Filter.Header := Header;
+
+ if Thin.Deflate_Init
+ (To_Thin_Access (Filter.Strm),
+ Level => Thin.Int (Level),
+ method => Thin.Int (Method),
+ windowBits => Win_Bits,
+ memLevel => Thin.Int (Memory_Level),
+ strategy => Thin.Int (Strategy)) /= Thin.Z_OK
+ then
+ Raise_Error (Filter.Strm.all);
+ end if;
+ end Deflate_Init;
+
+ -----------
+ -- Flush --
+ -----------
+
+ procedure Flush
+ (Filter : in out Filter_Type;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode)
+ is
+ No_Data : Stream_Element_Array := (1 .. 0 => 0);
+ Last : Stream_Element_Offset;
+ begin
+ Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush);
+ end Flush;
+
+ -----------------------
+ -- Generic_Translate --
+ -----------------------
+
+ procedure Generic_Translate
+ (Filter : in out ZLib.Filter_Type;
+ In_Buffer_Size : in Integer := Default_Buffer_Size;
+ Out_Buffer_Size : in Integer := Default_Buffer_Size)
+ is
+ In_Buffer : Stream_Element_Array
+ (1 .. Stream_Element_Offset (In_Buffer_Size));
+ Out_Buffer : Stream_Element_Array
+ (1 .. Stream_Element_Offset (Out_Buffer_Size));
+ Last : Stream_Element_Offset;
+ In_Last : Stream_Element_Offset;
+ In_First : Stream_Element_Offset;
+ Out_Last : Stream_Element_Offset;
+ begin
+ Main : loop
+ Data_In (In_Buffer, Last);
+
+ In_First := In_Buffer'First;
+
+ loop
+ Translate
+ (Filter => Filter,
+ In_Data => In_Buffer (In_First .. Last),
+ In_Last => In_Last,
+ Out_Data => Out_Buffer,
+ Out_Last => Out_Last,
+ Flush => Flush_Finish (Last < In_Buffer'First));
+
+ if Out_Buffer'First <= Out_Last then
+ Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last));
+ end if;
+
+ exit Main when Stream_End (Filter);
+
+ -- The end of in buffer.
+
+ exit when In_Last = Last;
+
+ In_First := In_Last + 1;
+ end loop;
+ end loop Main;
+
+ end Generic_Translate;
+
+ ------------------
+ -- Inflate_Init --
+ ------------------
+
+ procedure Inflate_Init
+ (Filter : in out Filter_Type;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Header : in Header_Type := Default)
+ is
+ use type Thin.Int;
+ Win_Bits : Thin.Int := Thin.Int (Window_Bits);
+
+ procedure Check_Version;
+ -- Check the latest header types compatibility.
+
+ procedure Check_Version is
+ begin
+ if Version <= "1.1.4" then
+ Raise_Error
+ ("Inflate header type " & Header_Type'Image (Header)
+ & " incompatible with ZLib version " & Version);
+ end if;
+ end Check_Version;
+
+ begin
+ if Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ case Header is
+ when None =>
+ Check_Version;
+
+ -- Inflate data without headers determined
+ -- by negative Win_Bits.
+
+ Win_Bits := -Win_Bits;
+ when GZip =>
+ Check_Version;
+
+ -- Inflate gzip data defined by flag 16.
+
+ Win_Bits := Win_Bits + 16;
+ when Auto =>
+ Check_Version;
+
+ -- Inflate with automatic detection
+ -- of gzip or native header defined by flag 32.
+
+ Win_Bits := Win_Bits + 32;
+ when Default => null;
+ end case;
+
+ Filter.Strm := new Z_Stream;
+ Filter.Compression := False;
+ Filter.Stream_End := False;
+ Filter.Header := Header;
+
+ if Thin.Inflate_Init
+ (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK
+ then
+ Raise_Error (Filter.Strm.all);
+ end if;
+ end Inflate_Init;
+
+ -------------
+ -- Is_Open --
+ -------------
+
+ function Is_Open (Filter : in Filter_Type) return Boolean is
+ begin
+ return Filter.Strm /= null;
+ end Is_Open;
+
+ -----------------
+ -- Raise_Error --
+ -----------------
+
+ procedure Raise_Error (Message : in String) is
+ begin
+ Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message);
+ end Raise_Error;
+
+ procedure Raise_Error (Stream : in Z_Stream) is
+ begin
+ Raise_Error (Last_Error_Message (Stream));
+ end Raise_Error;
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Filter : in out Filter_Type;
+ Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode := No_Flush)
+ is
+ In_Last : Stream_Element_Offset;
+ Item_First : Ada.Streams.Stream_Element_Offset := Item'First;
+ V_Flush : Flush_Mode := Flush;
+
+ begin
+ pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1);
+ pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last);
+
+ loop
+ if Rest_Last = Buffer'First - 1 then
+ V_Flush := Finish;
+
+ elsif Rest_First > Rest_Last then
+ Read (Buffer, Rest_Last);
+ Rest_First := Buffer'First;
+
+ if Rest_Last < Buffer'First then
+ V_Flush := Finish;
+ end if;
+ end if;
+
+ Translate
+ (Filter => Filter,
+ In_Data => Buffer (Rest_First .. Rest_Last),
+ In_Last => In_Last,
+ Out_Data => Item (Item_First .. Item'Last),
+ Out_Last => Last,
+ Flush => V_Flush);
+
+ Rest_First := In_Last + 1;
+
+ exit when Stream_End (Filter)
+ or else Last = Item'Last
+ or else (Last >= Item'First and then Allow_Read_Some);
+
+ Item_First := Last + 1;
+ end loop;
+ end Read;
+
+ ----------------
+ -- Stream_End --
+ ----------------
+
+ function Stream_End (Filter : in Filter_Type) return Boolean is
+ begin
+ if Filter.Header = GZip and Filter.Compression then
+ return Filter.Stream_End
+ and then Filter.Offset = Footer_Array'Last + 1;
+ else
+ return Filter.Stream_End;
+ end if;
+ end Stream_End;
+
+ --------------
+ -- Total_In --
+ --------------
+
+ function Total_In (Filter : in Filter_Type) return Count is
+ begin
+ return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all));
+ end Total_In;
+
+ ---------------
+ -- Total_Out --
+ ---------------
+
+ function Total_Out (Filter : in Filter_Type) return Count is
+ begin
+ return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all));
+ end Total_Out;
+
+ ---------------
+ -- Translate --
+ ---------------
+
+ procedure Translate
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode) is
+ begin
+ if Filter.Header = GZip and then Filter.Compression then
+ Translate_GZip
+ (Filter => Filter,
+ In_Data => In_Data,
+ In_Last => In_Last,
+ Out_Data => Out_Data,
+ Out_Last => Out_Last,
+ Flush => Flush);
+ else
+ Translate_Auto
+ (Filter => Filter,
+ In_Data => In_Data,
+ In_Last => In_Last,
+ Out_Data => Out_Data,
+ Out_Last => Out_Last,
+ Flush => Flush);
+ end if;
+ end Translate;
+
+ --------------------
+ -- Translate_Auto --
+ --------------------
+
+ procedure Translate_Auto
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode)
+ is
+ use type Thin.Int;
+ Code : Thin.Int;
+
+ begin
+ if not Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ if Out_Data'Length = 0 and then In_Data'Length = 0 then
+ raise Constraint_Error;
+ end if;
+
+ Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length);
+ Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length);
+
+ Code := Flate (Filter.Compression).Step
+ (To_Thin_Access (Filter.Strm),
+ Thin.Int (Flush));
+
+ if Code = Thin.Z_STREAM_END then
+ Filter.Stream_End := True;
+ else
+ Check_Error (Filter.Strm.all, Code);
+ end if;
+
+ In_Last := In_Data'Last
+ - Stream_Element_Offset (Avail_In (Filter.Strm.all));
+ Out_Last := Out_Data'Last
+ - Stream_Element_Offset (Avail_Out (Filter.Strm.all));
+ end Translate_Auto;
+
+ --------------------
+ -- Translate_GZip --
+ --------------------
+
+ procedure Translate_GZip
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode)
+ is
+ Out_First : Stream_Element_Offset;
+
+ procedure Add_Data (Data : in Stream_Element_Array);
+ -- Add data to stream from the Filter.Offset till necessary,
+ -- used for add gzip headr/footer.
+
+ procedure Put_32
+ (Item : in out Stream_Element_Array;
+ Data : in Unsigned_32);
+ pragma Inline (Put_32);
+
+ --------------
+ -- Add_Data --
+ --------------
+
+ procedure Add_Data (Data : in Stream_Element_Array) is
+ Data_First : Stream_Element_Offset renames Filter.Offset;
+ Data_Last : Stream_Element_Offset;
+ Data_Len : Stream_Element_Offset; -- -1
+ Out_Len : Stream_Element_Offset; -- -1
+ begin
+ Out_First := Out_Last + 1;
+
+ if Data_First > Data'Last then
+ return;
+ end if;
+
+ Data_Len := Data'Last - Data_First;
+ Out_Len := Out_Data'Last - Out_First;
+
+ if Data_Len <= Out_Len then
+ Out_Last := Out_First + Data_Len;
+ Data_Last := Data'Last;
+ else
+ Out_Last := Out_Data'Last;
+ Data_Last := Data_First + Out_Len;
+ end if;
+
+ Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last);
+
+ Data_First := Data_Last + 1;
+ Out_First := Out_Last + 1;
+ end Add_Data;
+
+ ------------
+ -- Put_32 --
+ ------------
+
+ procedure Put_32
+ (Item : in out Stream_Element_Array;
+ Data : in Unsigned_32)
+ is
+ D : Unsigned_32 := Data;
+ begin
+ for J in Item'First .. Item'First + 3 loop
+ Item (J) := Stream_Element (D and 16#FF#);
+ D := Shift_Right (D, 8);
+ end loop;
+ end Put_32;
+
+ begin
+ Out_Last := Out_Data'First - 1;
+
+ if not Filter.Stream_End then
+ Add_Data (Simple_GZip_Header);
+
+ Translate_Auto
+ (Filter => Filter,
+ In_Data => In_Data,
+ In_Last => In_Last,
+ Out_Data => Out_Data (Out_First .. Out_Data'Last),
+ Out_Last => Out_Last,
+ Flush => Flush);
+
+ CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last));
+ end if;
+
+ if Filter.Stream_End and then Out_Last <= Out_Data'Last then
+ -- This detection method would work only when
+ -- Simple_GZip_Header'Last > Footer_Array'Last
+
+ if Filter.Offset = Simple_GZip_Header'Last + 1 then
+ Filter.Offset := Footer_Array'First;
+ end if;
+
+ declare
+ Footer : Footer_Array;
+ begin
+ Put_32 (Footer, Filter.CRC);
+ Put_32 (Footer (Footer'First + 4 .. Footer'Last),
+ Unsigned_32 (Total_In (Filter)));
+ Add_Data (Footer);
+ end;
+ end if;
+ end Translate_GZip;
+
+ -------------
+ -- Version --
+ -------------
+
+ function Version return String is
+ begin
+ return Interfaces.C.Strings.Value (Thin.zlibVersion);
+ end Version;
+
+ -----------
+ -- Write --
+ -----------
+
+ procedure Write
+ (Filter : in out Filter_Type;
+ Item : in Ada.Streams.Stream_Element_Array;
+ Flush : in Flush_Mode := No_Flush)
+ is
+ Buffer : Stream_Element_Array (1 .. Buffer_Size);
+ In_Last : Stream_Element_Offset;
+ Out_Last : Stream_Element_Offset;
+ In_First : Stream_Element_Offset := Item'First;
+ begin
+ if Item'Length = 0 and Flush = No_Flush then
+ return;
+ end if;
+
+ loop
+ Translate
+ (Filter => Filter,
+ In_Data => Item (In_First .. Item'Last),
+ In_Last => In_Last,
+ Out_Data => Buffer,
+ Out_Last => Out_Last,
+ Flush => Flush);
+
+ if Out_Last >= Buffer'First then
+ Write (Buffer (1 .. Out_Last));
+ end if;
+
+ exit when In_Last = Item'Last or Stream_End (Filter);
+
+ In_First := In_Last + 1;
+ end loop;
+ end Write;
+
+end ZLib;
diff --git a/zlib/contrib/ada/zlib.ads b/zlib/contrib/ada/zlib.ads
new file mode 100644
index 0000000..32d8fa0
--- /dev/null
+++ b/zlib/contrib/ada/zlib.ads
@@ -0,0 +1,328 @@
+------------------------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2004 Dmitriy Anisimkov --
+-- --
+-- This library is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation; either version 2 of the License, or (at --
+-- your option) any later version. --
+-- --
+-- This library is distributed in the hope that it will be useful, but --
+-- WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
+-- General Public License for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this library; if not, write to the Free Software Foundation, --
+-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --
+-- --
+-- As a special exception, if other files instantiate generics from this --
+-- unit, or you link this unit with other files to produce an executable, --
+-- this unit does not by itself cause the resulting executable to be --
+-- covered by the GNU General Public License. This exception does not --
+-- however invalidate any other reasons why the executable file might be --
+-- covered by the GNU Public License. --
+------------------------------------------------------------------------------
+
+-- $Id: zlib.ads,v 1.1.1.2 2005/02/20 17:57:26 dprice Exp $
+
+with Ada.Streams;
+
+with Interfaces;
+
+package ZLib is
+
+ ZLib_Error : exception;
+ Status_Error : exception;
+
+ type Compression_Level is new Integer range -1 .. 9;
+
+ type Flush_Mode is private;
+
+ type Compression_Method is private;
+
+ type Window_Bits_Type is new Integer range 8 .. 15;
+
+ type Memory_Level_Type is new Integer range 1 .. 9;
+
+ type Unsigned_32 is new Interfaces.Unsigned_32;
+
+ type Strategy_Type is private;
+
+ type Header_Type is (None, Auto, Default, GZip);
+ -- Header type usage have a some limitation for inflate.
+ -- See comment for Inflate_Init.
+
+ subtype Count is Ada.Streams.Stream_Element_Count;
+
+ Default_Memory_Level : constant Memory_Level_Type := 8;
+ Default_Window_Bits : constant Window_Bits_Type := 15;
+
+ ----------------------------------
+ -- Compression method constants --
+ ----------------------------------
+
+ Deflated : constant Compression_Method;
+ -- Only one method allowed in this ZLib version
+
+ ---------------------------------
+ -- Compression level constants --
+ ---------------------------------
+
+ No_Compression : constant Compression_Level := 0;
+ Best_Speed : constant Compression_Level := 1;
+ Best_Compression : constant Compression_Level := 9;
+ Default_Compression : constant Compression_Level := -1;
+
+ --------------------------
+ -- Flush mode constants --
+ --------------------------
+
+ No_Flush : constant Flush_Mode;
+ -- Regular way for compression, no flush
+
+ Partial_Flush : constant Flush_Mode;
+ -- Will be removed, use Z_SYNC_FLUSH instead
+
+ Sync_Flush : constant Flush_Mode;
+ -- All pending output is flushed to the output buffer and the output
+ -- is aligned on a byte boundary, so that the decompressor can get all
+ -- input data available so far. (In particular avail_in is zero after the
+ -- call if enough output space has been provided before the call.)
+ -- Flushing may degrade compression for some compression algorithms and so
+ -- it should be used only when necessary.
+
+ Block_Flush : constant Flush_Mode;
+ -- Z_BLOCK requests that inflate() stop
+ -- if and when it get to the next deflate block boundary. When decoding the
+ -- zlib or gzip format, this will cause inflate() to return immediately
+ -- after the header and before the first block. When doing a raw inflate,
+ -- inflate() will go ahead and process the first block, and will return
+ -- when it gets to the end of that block, or when it runs out of data.
+
+ Full_Flush : constant Flush_Mode;
+ -- All output is flushed as with SYNC_FLUSH, and the compression state
+ -- is reset so that decompression can restart from this point if previous
+ -- compressed data has been damaged or if random access is desired. Using
+ -- Full_Flush too often can seriously degrade the compression.
+
+ Finish : constant Flush_Mode;
+ -- Just for tell the compressor that input data is complete.
+
+ ------------------------------------
+ -- Compression strategy constants --
+ ------------------------------------
+
+ -- RLE stategy could be used only in version 1.2.0 and later.
+
+ Filtered : constant Strategy_Type;
+ Huffman_Only : constant Strategy_Type;
+ RLE : constant Strategy_Type;
+ Default_Strategy : constant Strategy_Type;
+
+ Default_Buffer_Size : constant := 4096;
+
+ type Filter_Type is tagged limited private;
+ -- The filter is for compression and for decompression.
+ -- The usage of the type is depend of its initialization.
+
+ function Version return String;
+ pragma Inline (Version);
+ -- Return string representation of the ZLib version.
+
+ procedure Deflate_Init
+ (Filter : in out Filter_Type;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Method : in Compression_Method := Deflated;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Memory_Level : in Memory_Level_Type := Default_Memory_Level;
+ Header : in Header_Type := Default);
+ -- Compressor initialization.
+ -- When Header parameter is Auto or Default, then default zlib header
+ -- would be provided for compressed data.
+ -- When Header is GZip, then gzip header would be set instead of
+ -- default header.
+ -- When Header is None, no header would be set for compressed data.
+
+ procedure Inflate_Init
+ (Filter : in out Filter_Type;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Header : in Header_Type := Default);
+ -- Decompressor initialization.
+ -- Default header type mean that ZLib default header is expecting in the
+ -- input compressed stream.
+ -- Header type None mean that no header is expecting in the input stream.
+ -- GZip header type mean that GZip header is expecting in the
+ -- input compressed stream.
+ -- Auto header type mean that header type (GZip or Native) would be
+ -- detected automatically in the input stream.
+ -- Note that header types parameter values None, GZip and Auto are
+ -- supported for inflate routine only in ZLib versions 1.2.0.2 and later.
+ -- Deflate_Init is supporting all header types.
+
+ function Is_Open (Filter : in Filter_Type) return Boolean;
+ pragma Inline (Is_Open);
+ -- Is the filter opened for compression or decompression.
+
+ procedure Close
+ (Filter : in out Filter_Type;
+ Ignore_Error : in Boolean := False);
+ -- Closing the compression or decompressor.
+ -- If stream is closing before the complete and Ignore_Error is False,
+ -- The exception would be raised.
+
+ generic
+ with procedure Data_In
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+ with procedure Data_Out
+ (Item : in Ada.Streams.Stream_Element_Array);
+ procedure Generic_Translate
+ (Filter : in out Filter_Type;
+ In_Buffer_Size : in Integer := Default_Buffer_Size;
+ Out_Buffer_Size : in Integer := Default_Buffer_Size);
+ -- Compress/decompress data fetch from Data_In routine and pass the result
+ -- to the Data_Out routine. User should provide Data_In and Data_Out
+ -- for compression/decompression data flow.
+ -- Compression or decompression depend on Filter initialization.
+
+ function Total_In (Filter : in Filter_Type) return Count;
+ pragma Inline (Total_In);
+ -- Returns total number of input bytes read so far
+
+ function Total_Out (Filter : in Filter_Type) return Count;
+ pragma Inline (Total_Out);
+ -- Returns total number of bytes output so far
+
+ function CRC32
+ (CRC : in Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array)
+ return Unsigned_32;
+ pragma Inline (CRC32);
+ -- Compute CRC32, it could be necessary for make gzip format
+
+ procedure CRC32
+ (CRC : in out Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array);
+ pragma Inline (CRC32);
+ -- Compute CRC32, it could be necessary for make gzip format
+
+ -------------------------------------------------
+ -- Below is more complex low level routines. --
+ -------------------------------------------------
+
+ procedure Translate
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ -- Compress/decompress the In_Data buffer and place the result into
+ -- Out_Data. In_Last is the index of last element from In_Data accepted by
+ -- the Filter. Out_Last is the last element of the received data from
+ -- Filter. To tell the filter that incoming data are complete put the
+ -- Flush parameter to Finish.
+
+ function Stream_End (Filter : in Filter_Type) return Boolean;
+ pragma Inline (Stream_End);
+ -- Return the true when the stream is complete.
+
+ procedure Flush
+ (Filter : in out Filter_Type;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ pragma Inline (Flush);
+ -- Flushing the data from the compressor.
+
+ generic
+ with procedure Write
+ (Item : in Ada.Streams.Stream_Element_Array);
+ -- User should provide this routine for accept
+ -- compressed/decompressed data.
+
+ Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size;
+ -- Buffer size for Write user routine.
+
+ procedure Write
+ (Filter : in out Filter_Type;
+ Item : in Ada.Streams.Stream_Element_Array;
+ Flush : in Flush_Mode := No_Flush);
+ -- Compress/Decompress data from Item to the generic parameter procedure
+ -- Write. Output buffer size could be set in Buffer_Size generic parameter.
+
+ generic
+ with procedure Read
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+ -- User should provide data for compression/decompression
+ -- thru this routine.
+
+ Buffer : in out Ada.Streams.Stream_Element_Array;
+ -- Buffer for keep remaining data from the previous
+ -- back read.
+
+ Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset;
+ -- Rest_First have to be initialized to Buffer'Last + 1
+ -- Rest_Last have to be initialized to Buffer'Last
+ -- before usage.
+
+ Allow_Read_Some : in Boolean := False;
+ -- Is it allowed to return Last < Item'Last before end of data.
+
+ procedure Read
+ (Filter : in out Filter_Type;
+ Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode := No_Flush);
+ -- Compress/Decompress data from generic parameter procedure Read to the
+ -- Item. User should provide Buffer and initialized Rest_First, Rest_Last
+ -- indicators. If Allow_Read_Some is True, Read routines could return
+ -- Last < Item'Last only at end of stream.
+
+private
+
+ use Ada.Streams;
+
+ pragma Assert (Ada.Streams.Stream_Element'Size = 8);
+ pragma Assert (Ada.Streams.Stream_Element'Modulus = 2**8);
+
+ type Flush_Mode is new Integer range 0 .. 5;
+
+ type Compression_Method is new Integer range 8 .. 8;
+
+ type Strategy_Type is new Integer range 0 .. 3;
+
+ No_Flush : constant Flush_Mode := 0;
+ Partial_Flush : constant Flush_Mode := 1;
+ Sync_Flush : constant Flush_Mode := 2;
+ Full_Flush : constant Flush_Mode := 3;
+ Finish : constant Flush_Mode := 4;
+ Block_Flush : constant Flush_Mode := 5;
+
+ Filtered : constant Strategy_Type := 1;
+ Huffman_Only : constant Strategy_Type := 2;
+ RLE : constant Strategy_Type := 3;
+ Default_Strategy : constant Strategy_Type := 0;
+
+ Deflated : constant Compression_Method := 8;
+
+ type Z_Stream;
+
+ type Z_Stream_Access is access all Z_Stream;
+
+ type Filter_Type is tagged limited record
+ Strm : Z_Stream_Access;
+ Compression : Boolean;
+ Stream_End : Boolean;
+ Header : Header_Type;
+ CRC : Unsigned_32;
+ Offset : Stream_Element_Offset;
+ -- Offset for gzip header/footer output.
+ end record;
+
+end ZLib;
diff --git a/zlib/contrib/ada/zlib.gpr b/zlib/contrib/ada/zlib.gpr
new file mode 100644
index 0000000..296b22a
--- /dev/null
+++ b/zlib/contrib/ada/zlib.gpr
@@ -0,0 +1,20 @@
+project Zlib is
+
+ for Languages use ("Ada");
+ for Source_Dirs use (".");
+ for Object_Dir use ".";
+ for Main use ("test.adb", "mtest.adb", "read.adb", "buffer_demo");
+
+ package Compiler is
+ for Default_Switches ("ada") use ("-gnatwcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst");
+ end Compiler;
+
+ package Linker is
+ for Default_Switches ("ada") use ("-lz");
+ end Linker;
+
+ package Builder is
+ for Default_Switches ("ada") use ("-s", "-gnatQ");
+ end Builder;
+
+end Zlib;
diff --git a/zlib/contrib/asm586/README.586 b/zlib/contrib/asm586/README.586
new file mode 100644
index 0000000..6bb78f3
--- /dev/null
+++ b/zlib/contrib/asm586/README.586
@@ -0,0 +1,43 @@
+This is a patched version of zlib modified to use
+Pentium-optimized assembly code in the deflation algorithm. The files
+changed/added by this patch are:
+
+README.586
+match.S
+
+The effectiveness of these modifications is a bit marginal, as the the
+program's bottleneck seems to be mostly L1-cache contention, for which
+there is no real way to work around without rewriting the basic
+algorithm. The speedup on average is around 5-10% (which is generally
+less than the amount of variance between subsequent executions).
+However, when used at level 9 compression, the cache contention can
+drop enough for the assembly version to achieve 10-20% speedup (and
+sometimes more, depending on the amount of overall redundancy in the
+files). Even here, though, cache contention can still be the limiting
+factor, depending on the nature of the program using the zlib library.
+This may also mean that better improvements will be seen on a Pentium
+with MMX, which suffers much less from L1-cache contention, but I have
+not yet verified this.
+
+Note that this code has been tailored for the Pentium in particular,
+and will not perform well on the Pentium Pro (due to the use of a
+partial register in the inner loop).
+
+If you are using an assembler other than GNU as, you will have to
+translate match.S to use your assembler's syntax. (Have fun.)
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 1998
+
+
+Added for zlib 1.1.3:
+
+The patches come from
+http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+To compile zlib with this asm file, copy match.S to the zlib directory
+then do:
+
+CFLAGS="-O3 -DASMV" ./configure
+make OBJA=match.o
diff --git a/zlib/contrib/asm586/match.S b/zlib/contrib/asm586/match.S
new file mode 100644
index 0000000..0368b35
--- /dev/null
+++ b/zlib/contrib/asm586/match.S
@@ -0,0 +1,364 @@
+/* match.s -- Pentium-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define match_init _match_init
+#define longest_match _longest_match
+#endif
+
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define wmask 0 /* local copy of s->wmask */
+#define window 4 /* local copy of s->window */
+#define windowbestlen 8 /* s->window + bestlen */
+#define chainlenscanend 12 /* high word: current chain len */
+ /* low word: last bytes sought */
+#define scanstart 16 /* first two bytes of string */
+#define scanalign 20 /* dword-misalignment of string */
+#define nicematch 24 /* a good enough match size */
+#define bestlen 28 /* size of best match so far */
+#define scan 32 /* ptr to string wanting match */
+
+#define LocalVarsSize (36)
+/* saved ebx 36 */
+/* saved edi 40 */
+/* saved esi 44 */
+/* saved ebp 48 */
+/* return address 52 */
+#define deflatestate 56 /* the function arguments */
+#define curmatch 60
+
+/* Offsets for fields in the deflate_state structure. These numbers
+ * are calculated from the definition of deflate_state, with the
+ * assumption that the compiler will dword-align the fields. (Thus,
+ * changing the definition of deflate_state could easily cause this
+ * program to crash horribly, without so much as a warning at
+ * compile time. Sigh.)
+ */
+
+/* All the +zlib1222add offsets are due to the addition of fields
+ * in zlib in the deflate_state structure since the asm code was first written
+ * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+ * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+ * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+ */
+
+#define zlib1222add (8)
+
+#define dsWSize (36+zlib1222add)
+#define dsWMask (44+zlib1222add)
+#define dsWindow (48+zlib1222add)
+#define dsPrev (56+zlib1222add)
+#define dsMatchLen (88+zlib1222add)
+#define dsPrevMatch (92+zlib1222add)
+#define dsStrStart (100+zlib1222add)
+#define dsMatchStart (104+zlib1222add)
+#define dsLookahead (108+zlib1222add)
+#define dsPrevLen (112+zlib1222add)
+#define dsMaxChainLen (116+zlib1222add)
+#define dsGoodMatch (132+zlib1222add)
+#define dsNiceMatch (136+zlib1222add)
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to */
+/* make room for our stack frame. */
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match */
+/* throughout the entire function. %edx will hold the pointer to the */
+/* deflate_state structure during the function's setup (before */
+/* entering the main loop). */
+
+ movl deflatestate(%esp), %edx
+ movl curmatch(%esp), %ecx
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch(%edx), %eax
+ movl dsLookahead(%edx), %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ movl dsWindow(%edx), %esi
+ movl %esi, window(%esp)
+ movl dsStrStart(%edx), %ebp
+ lea (%esi,%ebp), %edi
+ movl %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ movl %edi, %eax
+ negl %eax
+ andl $3, %eax
+ movl %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize(%edx), %eax
+ subl $MIN_LOOKAHEAD, %eax
+ subl %eax, %ebp
+ jg LimitPositive
+ xorl %ebp, %ebp
+LimitPositive:
+
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen(%edx), %eax
+ movl dsGoodMatch(%edx), %ebx
+ cmpl %ebx, %eax
+ movl dsMaxChainLen(%edx), %ebx
+ jl LastMatchGood
+ shrl $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the scanend */
+/* scanend value, which it will always accompany. */
+
+ decl %ebx
+ shll $16, %ebx
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen(%edx), %eax
+ movl %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+
+ movw (%edi), %bx
+ movw %bx, scanstart(%esp)
+ movw -1(%edi,%eax), %bx
+ movl %ebx, chainlenscanend(%esp)
+
+/* Posf *prev = s->prev; */
+/* uInt wmask = s->w_mask; */
+
+ movl dsPrev(%edx), %edi
+ movl dsWMask(%edx), %edx
+ mov %edx, wmask(%esp)
+
+/* Jump into the main loop. */
+
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend)
+ * %ecx = curmatch
+ * %edx = curmatch & wmask
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ *
+ * Two optimization notes on the choice of instructions:
+ *
+ * The first instruction uses a 16-bit address, which costs an extra,
+ * unpairable cycle. This is cheaper than doing a 32-bit access and
+ * zeroing the high word, due to the 3-cycle misalignment penalty which
+ * would occur half the time. This also turns out to be cheaper than
+ * doing two separate 8-bit accesses, as the memory is so rarely in the
+ * L1 cache.
+ *
+ * The window buffer, however, apparently spends a lot of time in the
+ * cache, and so it is faster to retrieve the word at the end of the
+ * match string with two 8-bit loads. The instructions that test the
+ * word at the beginning of the match string, however, are executed
+ * much less frequently, and there it was cheaper to use 16-bit
+ * instructions, which avoided the necessity of saving off and
+ * subsequently reloading one of the other registers.
+ */
+LookupLoop:
+ /* 1 U & V */
+ movw (%edi,%edx,2), %cx /* 2 U pipe */
+ movl wmask(%esp), %edx /* 2 V pipe */
+ cmpl %ebp, %ecx /* 3 U pipe */
+ jbe LeaveNow /* 3 V pipe */
+ subl $0x00010000, %ebx /* 4 U pipe */
+ js LeaveNow /* 4 V pipe */
+LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */
+ andl %ecx, %edx /* 5 V pipe */
+ cmpb %bl, %al /* 6 U pipe */
+ jnz LookupLoop /* 6 V pipe */
+ movb (%esi,%ecx), %ah
+ cmpb %bh, %ah
+ jnz LookupLoop
+ movl window(%esp), %eax
+ movw (%eax,%ecx), %ax
+ cmpw scanstart(%esp), %ax
+ jnz LookupLoop
+
+/* Store the current value of chainlen. */
+
+ movl %ebx, chainlenscanend(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ movl window(%esp), %esi
+ movl scan(%esp), %edi
+ addl %ecx, %esi
+ movl scanalign(%esp), %eax
+ movl $(-MAX_MATCH_8), %edx
+ lea MAX_MATCH_8(%edi,%eax), %edi
+ lea MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+ movl (%esi,%edx), %eax
+ movl (%edi,%edx), %ebx
+ xorl %ebx, %eax
+ jnz LeaveLoopCmps
+ movl 4(%esi,%edx), %eax
+ movl 4(%edi,%edx), %ebx
+ xorl %ebx, %eax
+ jnz LeaveLoopCmps4
+ addl $8, %edx
+ jnz LoopCmps
+ jmp LenMaximum
+LeaveLoopCmps4: addl $4, %edx
+LeaveLoopCmps: testl $0x0000FFFF, %eax
+ jnz LenLower
+ addl $2, %edx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adcl $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%edi,%edx), %eax
+ movl scan(%esp), %edi
+ subl %edi, %eax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ cmpl %ebx, %eax
+ jg LongerMatch
+ movl chainlenscanend(%esp), %ebx
+ movl windowbestlen(%esp), %esi
+ movl dsPrev(%edx), %edi
+ movl wmask(%esp), %edx
+ andl %ecx, %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch: movl nicematch(%esp), %ebx
+ movl %eax, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+ cmpl %ebx, %eax
+ jge LeaveNow
+ movl window(%esp), %esi
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+ movl chainlenscanend(%esp), %ebx
+ movw -1(%edi,%eax), %bx
+ movl dsPrev(%edx), %edi
+ movl %ebx, chainlenscanend(%esp)
+ movl wmask(%esp), %edx
+ andl %ecx, %edx
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum: movl deflatestate(%esp), %edx
+ movl $MAX_MATCH, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ movl dsLookahead(%edx), %eax
+ cmpl %eax, %ebx
+ jg LookaheadRet
+ movl %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came. */
+
+ addl $LocalVarsSize, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+match_init: ret
diff --git a/zlib/contrib/asm686/README.686 b/zlib/contrib/asm686/README.686
new file mode 100644
index 0000000..a593f23
--- /dev/null
+++ b/zlib/contrib/asm686/README.686
@@ -0,0 +1,34 @@
+This is a patched version of zlib, modified to use
+Pentium-Pro-optimized assembly code in the deflation algorithm. The
+files changed/added by this patch are:
+
+README.686
+match.S
+
+The speedup that this patch provides varies, depending on whether the
+compiler used to build the original version of zlib falls afoul of the
+PPro's speed traps. My own tests show a speedup of around 10-20% at
+the default compression level, and 20-30% using -9, against a version
+compiled using gcc 2.7.2.3. Your mileage may vary.
+
+Note that this code has been tailored for the PPro/PII in particular,
+and will not perform particuarly well on a Pentium.
+
+If you are using an assembler other than GNU as, you will have to
+translate match.S to use your assembler's syntax. (Have fun.)
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 1998
+
+
+Added for zlib 1.1.3:
+
+The patches come from
+http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+To compile zlib with this asm file, copy match.S to the zlib directory
+then do:
+
+CFLAGS="-O3 -DASMV" ./configure
+make OBJA=match.o
diff --git a/zlib/contrib/asm686/match.S b/zlib/contrib/asm686/match.S
new file mode 100644
index 0000000..5c3e9ee
--- /dev/null
+++ b/zlib/contrib/asm686/match.S
@@ -0,0 +1,329 @@
+/* match.s -- Pentium-Pro-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define match_init _match_init
+#define longest_match _longest_match
+#endif
+
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define chainlenwmask 0 /* high word: current chain len */
+ /* low word: s->wmask */
+#define window 4 /* local copy of s->window */
+#define windowbestlen 8 /* s->window + bestlen */
+#define scanstart 16 /* first two bytes of string */
+#define scanend 12 /* last two bytes of string */
+#define scanalign 20 /* dword-misalignment of string */
+#define nicematch 24 /* a good enough match size */
+#define bestlen 28 /* size of best match so far */
+#define scan 32 /* ptr to string wanting match */
+
+#define LocalVarsSize (36)
+/* saved ebx 36 */
+/* saved edi 40 */
+/* saved esi 44 */
+/* saved ebp 48 */
+/* return address 52 */
+#define deflatestate 56 /* the function arguments */
+#define curmatch 60
+
+/* All the +zlib1222add offsets are due to the addition of fields
+ * in zlib in the deflate_state structure since the asm code was first written
+ * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+ * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+ * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+ */
+
+#define zlib1222add (8)
+
+#define dsWSize (36+zlib1222add)
+#define dsWMask (44+zlib1222add)
+#define dsWindow (48+zlib1222add)
+#define dsPrev (56+zlib1222add)
+#define dsMatchLen (88+zlib1222add)
+#define dsPrevMatch (92+zlib1222add)
+#define dsStrStart (100+zlib1222add)
+#define dsMatchStart (104+zlib1222add)
+#define dsLookahead (108+zlib1222add)
+#define dsPrevLen (112+zlib1222add)
+#define dsMaxChainLen (116+zlib1222add)
+#define dsGoodMatch (132+zlib1222add)
+#define dsNiceMatch (136+zlib1222add)
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to */
+/* make room for our stack frame. */
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match */
+/* throughout the entire function. %edx will hold the pointer to the */
+/* deflate_state structure during the function's setup (before */
+/* entering the main loop). */
+
+ movl deflatestate(%esp), %edx
+ movl curmatch(%esp), %ecx
+
+/* uInt wmask = s->w_mask; */
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen(%edx), %eax
+ movl dsGoodMatch(%edx), %ebx
+ cmpl %ebx, %eax
+ movl dsWMask(%edx), %eax
+ movl dsMaxChainLen(%edx), %ebx
+ jl LastMatchGood
+ shrl $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the wmask */
+/* value, which it will always accompany. */
+
+ decl %ebx
+ shll $16, %ebx
+ orl %eax, %ebx
+ movl %ebx, chainlenwmask(%esp)
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch(%edx), %eax
+ movl dsLookahead(%edx), %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ movl dsWindow(%edx), %esi
+ movl %esi, window(%esp)
+ movl dsStrStart(%edx), %ebp
+ lea (%esi,%ebp), %edi
+ movl %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ movl %edi, %eax
+ negl %eax
+ andl $3, %eax
+ movl %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize(%edx), %eax
+ subl $MIN_LOOKAHEAD, %eax
+ subl %eax, %ebp
+ jg LimitPositive
+ xorl %ebp, %ebp
+LimitPositive:
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen(%edx), %eax
+ movl %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+/* Posf *prev = s->prev; */
+
+ movzwl (%edi), %ebx
+ movl %ebx, scanstart(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl %ebx, scanend(%esp)
+ movl dsPrev(%edx), %edi
+
+/* Jump into the main loop. */
+
+ movl chainlenwmask(%esp), %edx
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = scanend
+ * %ecx = curmatch
+ * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ */
+LookupLoop:
+ andl %edx, %ecx
+ movzwl (%edi,%ecx,2), %ecx
+ cmpl %ebp, %ecx
+ jbe LeaveNow
+ subl $0x00010000, %edx
+ js LeaveNow
+LoopEntry: movzwl -1(%esi,%ecx), %eax
+ cmpl %ebx, %eax
+ jnz LookupLoop
+ movl window(%esp), %eax
+ movzwl (%eax,%ecx), %eax
+ cmpl scanstart(%esp), %eax
+ jnz LookupLoop
+
+/* Store the current value of chainlen. */
+
+ movl %edx, chainlenwmask(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ movl window(%esp), %esi
+ movl scan(%esp), %edi
+ addl %ecx, %esi
+ movl scanalign(%esp), %eax
+ movl $(-MAX_MATCH_8), %edx
+ lea MAX_MATCH_8(%edi,%eax), %edi
+ lea MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+ movl (%esi,%edx), %eax
+ xorl (%edi,%edx), %eax
+ jnz LeaveLoopCmps
+ movl 4(%esi,%edx), %eax
+ xorl 4(%edi,%edx), %eax
+ jnz LeaveLoopCmps4
+ addl $8, %edx
+ jnz LoopCmps
+ jmp LenMaximum
+LeaveLoopCmps4: addl $4, %edx
+LeaveLoopCmps: testl $0x0000FFFF, %eax
+ jnz LenLower
+ addl $2, %edx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adcl $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%edi,%edx), %eax
+ movl scan(%esp), %edi
+ subl %edi, %eax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ cmpl %ebx, %eax
+ jg LongerMatch
+ movl windowbestlen(%esp), %esi
+ movl dsPrev(%edx), %edi
+ movl scanend(%esp), %ebx
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch: movl nicematch(%esp), %ebx
+ movl %eax, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+ cmpl %ebx, %eax
+ jge LeaveNow
+ movl window(%esp), %esi
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl dsPrev(%edx), %edi
+ movl %ebx, scanend(%esp)
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum: movl deflatestate(%esp), %edx
+ movl $MAX_MATCH, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ movl dsLookahead(%edx), %eax
+ cmpl %eax, %ebx
+ jg LookaheadRet
+ movl %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came. */
+
+ addl $LocalVarsSize, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+match_init: ret
diff --git a/zlib/contrib/blast/Makefile b/zlib/contrib/blast/Makefile
new file mode 100644
index 0000000..9be80ba
--- /dev/null
+++ b/zlib/contrib/blast/Makefile
@@ -0,0 +1,8 @@
+blast: blast.c blast.h
+ cc -DTEST -o blast blast.c
+
+test: blast
+ blast < test.pk | cmp - test.txt
+
+clean:
+ rm -f blast blast.o
diff --git a/zlib/contrib/blast/README b/zlib/contrib/blast/README
new file mode 100644
index 0000000..e3a60b3
--- /dev/null
+++ b/zlib/contrib/blast/README
@@ -0,0 +1,4 @@
+Read blast.h for purpose and usage.
+
+Mark Adler
+madler@alumni.caltech.edu
diff --git a/zlib/contrib/blast/blast.c b/zlib/contrib/blast/blast.c
new file mode 100644
index 0000000..4ce697a
--- /dev/null
+++ b/zlib/contrib/blast/blast.c
@@ -0,0 +1,444 @@
+/* blast.c
+ * Copyright (C) 2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in blast.h
+ * version 1.1, 16 Feb 2003
+ *
+ * blast.c decompresses data compressed by the PKWare Compression Library.
+ * This function provides functionality similar to the explode() function of
+ * the PKWare library, hence the name "blast".
+ *
+ * This decompressor is based on the excellent format description provided by
+ * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the
+ * example Ben provided in the post is incorrect. The distance 110001 should
+ * instead be 111000. When corrected, the example byte stream becomes:
+ *
+ * 00 04 82 24 25 8f 80 7f
+ *
+ * which decompresses to "AIAIAIAIAIAIA" (without the quotes).
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0 12 Feb 2003 - First version
+ * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data
+ */
+
+#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
+#include "blast.h" /* prototype for blast() */
+
+#define local static /* for local function definitions */
+#define MAXBITS 13 /* maximum code length */
+#define MAXWIN 4096 /* maximum window size */
+
+/* input and output state */
+struct state {
+ /* input state */
+ blast_in infun; /* input function provided by user */
+ void *inhow; /* opaque information passed to infun() */
+ unsigned char *in; /* next input location */
+ unsigned left; /* available input at in */
+ int bitbuf; /* bit buffer */
+ int bitcnt; /* number of bits in bit buffer */
+
+ /* input limit error return state for bits() and decode() */
+ jmp_buf env;
+
+ /* output state */
+ blast_out outfun; /* output function provided by user */
+ void *outhow; /* opaque information passed to outfun() */
+ unsigned next; /* index of next write location in out[] */
+ int first; /* true to check distances (for first 4K) */
+ unsigned char out[MAXWIN]; /* output buffer and sliding window */
+};
+
+/*
+ * Return need bits from the input stream. This always leaves less than
+ * eight bits in the buffer. bits() works properly for need == 0.
+ *
+ * Format notes:
+ *
+ * - Bits are stored in bytes from the least significant bit to the most
+ * significant bit. Therefore bits are dropped from the bottom of the bit
+ * buffer, using shift right, and new bytes are appended to the top of the
+ * bit buffer, using shift left.
+ */
+local int bits(struct state *s, int need)
+{
+ int val; /* bit accumulator */
+
+ /* load at least need bits into val */
+ val = s->bitbuf;
+ while (s->bitcnt < need) {
+ if (s->left == 0) {
+ s->left = s->infun(s->inhow, &(s->in));
+ if (s->left == 0) longjmp(s->env, 1); /* out of input */
+ }
+ val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */
+ s->left--;
+ s->bitcnt += 8;
+ }
+
+ /* drop need bits and update buffer, always zero to seven bits left */
+ s->bitbuf = val >> need;
+ s->bitcnt -= need;
+
+ /* return need bits, zeroing the bits above that */
+ return val & ((1 << need) - 1);
+}
+
+/*
+ * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
+ * each length, which for a canonical code are stepped through in order.
+ * symbol[] are the symbol values in canonical order, where the number of
+ * entries is the sum of the counts in count[]. The decoding process can be
+ * seen in the function decode() below.
+ */
+struct huffman {
+ short *count; /* number of symbols of each length */
+ short *symbol; /* canonically ordered symbols */
+};
+
+/*
+ * Decode a code from the stream s using huffman table h. Return the symbol or
+ * a negative value if there is an error. If all of the lengths are zero, i.e.
+ * an empty code, or if the code is incomplete and an invalid code is received,
+ * then -9 is returned after reading MAXBITS bits.
+ *
+ * Format notes:
+ *
+ * - The codes as stored in the compressed data are bit-reversed relative to
+ * a simple integer ordering of codes of the same lengths. Hence below the
+ * bits are pulled from the compressed data one at a time and used to
+ * build the code value reversed from what is in the stream in order to
+ * permit simple integer comparisons for decoding.
+ *
+ * - The first code for the shortest length is all ones. Subsequent codes of
+ * the same length are simply integer decrements of the previous code. When
+ * moving up a length, a one bit is appended to the code. For a complete
+ * code, the last code of the longest length will be all zeros. To support
+ * this ordering, the bits pulled during decoding are inverted to apply the
+ * more "natural" ordering starting with all zeros and incrementing.
+ */
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+ int bitbuf; /* bits from stream */
+ int left; /* bits left in next or left to process */
+ short *next; /* next number of codes */
+
+ bitbuf = s->bitbuf;
+ left = s->bitcnt;
+ code = first = index = 0;
+ len = 1;
+ next = h->count + 1;
+ while (1) {
+ while (left--) {
+ code |= (bitbuf & 1) ^ 1; /* invert code */
+ bitbuf >>= 1;
+ count = *next++;
+ if (code < first + count) { /* if length len, return symbol */
+ s->bitbuf = bitbuf;
+ s->bitcnt = (s->bitcnt - len) & 7;
+ return h->symbol[index + (code - first)];
+ }
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+ }
+ left = (MAXBITS+1) - len;
+ if (left == 0) break;
+ if (s->left == 0) {
+ s->left = s->infun(s->inhow, &(s->in));
+ if (s->left == 0) longjmp(s->env, 1); /* out of input */
+ }
+ bitbuf = *(s->in)++;
+ s->left--;
+ if (left > 8) left = 8;
+ }
+ return -9; /* ran out of codes */
+}
+
+/*
+ * Given a list of repeated code lengths rep[0..n-1], where each byte is a
+ * count (high four bits + 1) and a code length (low four bits), generate the
+ * list of code lengths. This compaction reduces the size of the object code.
+ * Then given the list of code lengths length[0..n-1] representing a canonical
+ * Huffman code for n symbols, construct the tables required to decode those
+ * codes. Those tables are the number of codes of each length, and the symbols
+ * sorted by length, retaining their original order within each length. The
+ * return value is zero for a complete code set, negative for an over-
+ * subscribed code set, and positive for an incomplete code set. The tables
+ * can be used if the return value is zero or positive, but they cannot be used
+ * if the return value is negative. If the return value is zero, it is not
+ * possible for decode() using that table to return an error--any stream of
+ * enough bits will resolve to a symbol. If the return value is positive, then
+ * it is possible for decode() using that table to return an error for received
+ * codes past the end of the incomplete lengths.
+ */
+local int construct(struct huffman *h, const unsigned char *rep, int n)
+{
+ int symbol; /* current symbol when stepping through length[] */
+ int len; /* current length when stepping through h->count[] */
+ int left; /* number of possible codes left of current length */
+ short offs[MAXBITS+1]; /* offsets in symbol table for each length */
+ short length[256]; /* code lengths */
+
+ /* convert compact repeat counts into symbol bit length list */
+ symbol = 0;
+ do {
+ len = *rep++;
+ left = (len >> 4) + 1;
+ len &= 15;
+ do {
+ length[symbol++] = len;
+ } while (--left);
+ } while (--n);
+ n = symbol;
+
+ /* count number of codes of each length */
+ for (len = 0; len <= MAXBITS; len++)
+ h->count[len] = 0;
+ for (symbol = 0; symbol < n; symbol++)
+ (h->count[length[symbol]])++; /* assumes lengths are within bounds */
+ if (h->count[0] == n) /* no codes! */
+ return 0; /* complete, but decode() will fail */
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1; /* one possible code of zero length */
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1; /* one more bit, double codes left */
+ left -= h->count[len]; /* deduct count from possible codes */
+ if (left < 0) return left; /* over-subscribed--return negative */
+ } /* left > 0 means incomplete */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + h->count[len];
+
+ /*
+ * put symbols in table sorted by length, by symbol order within each
+ * length
+ */
+ for (symbol = 0; symbol < n; symbol++)
+ if (length[symbol] != 0)
+ h->symbol[offs[length[symbol]]++] = symbol;
+
+ /* return zero for complete set, positive for incomplete set */
+ return left;
+}
+
+/*
+ * Decode PKWare Compression Library stream.
+ *
+ * Format notes:
+ *
+ * - First byte is 0 if literals are uncoded or 1 if they are coded. Second
+ * byte is 4, 5, or 6 for the number of extra bits in the distance code.
+ * This is the base-2 logarithm of the dictionary size minus six.
+ *
+ * - Compressed data is a combination of literals and length/distance pairs
+ * terminated by an end code. Literals are either Huffman coded or
+ * uncoded bytes. A length/distance pair is a coded length followed by a
+ * coded distance to represent a string that occurs earlier in the
+ * uncompressed data that occurs again at the current location.
+ *
+ * - A bit preceding a literal or length/distance pair indicates which comes
+ * next, 0 for literals, 1 for length/distance.
+ *
+ * - If literals are uncoded, then the next eight bits are the literal, in the
+ * normal bit order in th stream, i.e. no bit-reversal is needed. Similarly,
+ * no bit reversal is needed for either the length extra bits or the distance
+ * extra bits.
+ *
+ * - Literal bytes are simply written to the output. A length/distance pair is
+ * an instruction to copy previously uncompressed bytes to the output. The
+ * copy is from distance bytes back in the output stream, copying for length
+ * bytes.
+ *
+ * - Distances pointing before the beginning of the output data are not
+ * permitted.
+ *
+ * - Overlapped copies, where the length is greater than the distance, are
+ * allowed and common. For example, a distance of one and a length of 518
+ * simply copies the last byte 518 times. A distance of four and a length of
+ * twelve copies the last four bytes three times. A simple forward copy
+ * ignoring whether the length is greater than the distance or not implements
+ * this correctly.
+ */
+local int decomp(struct state *s)
+{
+ int lit; /* true if literals are coded */
+ int dict; /* log2(dictionary size) - 6 */
+ int symbol; /* decoded symbol, extra bits for distance */
+ int len; /* length for copy */
+ int dist; /* distance for copy */
+ int copy; /* copy counter */
+ unsigned char *from, *to; /* copy pointers */
+ static int virgin = 1; /* build tables once */
+ static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */
+ static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */
+ static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */
+ static struct huffman litcode = {litcnt, litsym}; /* length code */
+ static struct huffman lencode = {lencnt, lensym}; /* length code */
+ static struct huffman distcode = {distcnt, distsym};/* distance code */
+ /* bit lengths of literal codes */
+ static const unsigned char litlen[] = {
+ 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8,
+ 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
+ 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
+ 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
+ 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45,
+ 44, 173};
+ /* bit lengths of length codes 0..15 */
+ static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23};
+ /* bit lengths of distance codes 0..63 */
+ static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248};
+ static const short base[16] = { /* base for length codes */
+ 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264};
+ static const char extra[16] = { /* extra bits for length codes */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
+
+ /* set up decoding tables (once--might not be thread-safe) */
+ if (virgin) {
+ construct(&litcode, litlen, sizeof(litlen));
+ construct(&lencode, lenlen, sizeof(lenlen));
+ construct(&distcode, distlen, sizeof(distlen));
+ virgin = 0;
+ }
+
+ /* read header */
+ lit = bits(s, 8);
+ if (lit > 1) return -1;
+ dict = bits(s, 8);
+ if (dict < 4 || dict > 6) return -2;
+
+ /* decode literals and length/distance pairs */
+ do {
+ if (bits(s, 1)) {
+ /* get length */
+ symbol = decode(s, &lencode);
+ len = base[symbol] + bits(s, extra[symbol]);
+ if (len == 519) break; /* end code */
+
+ /* get distance */
+ symbol = len == 2 ? 2 : dict;
+ dist = decode(s, &distcode) << symbol;
+ dist += bits(s, symbol);
+ dist++;
+ if (s->first && dist > s->next)
+ return -3; /* distance too far back */
+
+ /* copy length bytes from distance bytes back */
+ do {
+ to = s->out + s->next;
+ from = to - dist;
+ copy = MAXWIN;
+ if (s->next < dist) {
+ from += copy;
+ copy = dist;
+ }
+ copy -= s->next;
+ if (copy > len) copy = len;
+ len -= copy;
+ s->next += copy;
+ do {
+ *to++ = *from++;
+ } while (--copy);
+ if (s->next == MAXWIN) {
+ if (s->outfun(s->outhow, s->out, s->next)) return 1;
+ s->next = 0;
+ s->first = 0;
+ }
+ } while (len != 0);
+ }
+ else {
+ /* get literal and write it */
+ symbol = lit ? decode(s, &litcode) : bits(s, 8);
+ s->out[s->next++] = symbol;
+ if (s->next == MAXWIN) {
+ if (s->outfun(s->outhow, s->out, s->next)) return 1;
+ s->next = 0;
+ s->first = 0;
+ }
+ }
+ } while (1);
+ return 0;
+}
+
+/* See comments in blast.h */
+int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow)
+{
+ struct state s; /* input/output state */
+ int err; /* return value */
+
+ /* initialize input state */
+ s.infun = infun;
+ s.inhow = inhow;
+ s.left = 0;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+
+ /* initialize output state */
+ s.outfun = outfun;
+ s.outhow = outhow;
+ s.next = 0;
+ s.first = 1;
+
+ /* return if bits() or decode() tries to read past available input */
+ if (setjmp(s.env) != 0) /* if came back here via longjmp(), */
+ err = 2; /* then skip decomp(), return error */
+ else
+ err = decomp(&s); /* decompress */
+
+ /* write any leftover output and update the error code if needed */
+ if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0)
+ err = 1;
+ return err;
+}
+
+#ifdef TEST
+/* Example of how to use blast() */
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CHUNK 16384
+
+local unsigned inf(void *how, unsigned char **buf)
+{
+ static unsigned char hold[CHUNK];
+
+ *buf = hold;
+ return fread(hold, 1, CHUNK, (FILE *)how);
+}
+
+local int outf(void *how, unsigned char *buf, unsigned len)
+{
+ return fwrite(buf, 1, len, (FILE *)how) != len;
+}
+
+/* Decompress a PKWare Compression Library stream from stdin to stdout */
+int main(void)
+{
+ int ret, n;
+
+ /* decompress to stdout */
+ ret = blast(inf, stdin, outf, stdout);
+ if (ret != 0) fprintf(stderr, "blast error: %d\n", ret);
+
+ /* see if there are any leftover bytes */
+ n = 0;
+ while (getchar() != EOF) n++;
+ if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n);
+
+ /* return blast() error code */
+ return ret;
+}
+#endif
diff --git a/zlib/contrib/blast/blast.h b/zlib/contrib/blast/blast.h
new file mode 100644
index 0000000..ce9e541
--- /dev/null
+++ b/zlib/contrib/blast/blast.h
@@ -0,0 +1,71 @@
+/* blast.h -- interface for blast.c
+ Copyright (C) 2003 Mark Adler
+ version 1.1, 16 Feb 2003
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+
+/*
+ * blast() decompresses the PKWare Data Compression Library (DCL) compressed
+ * format. It provides the same functionality as the explode() function in
+ * that library. (Note: PKWare overused the "implode" verb, and the format
+ * used by their library implode() function is completely different and
+ * incompatible with the implode compression method supported by PKZIP.)
+ */
+
+
+typedef unsigned (*blast_in)(void *how, unsigned char **buf);
+typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len);
+/* Definitions for input/output functions passed to blast(). See below for
+ * what the provided functions need to do.
+ */
+
+
+int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow);
+/* Decompress input to output using the provided infun() and outfun() calls.
+ * On success, the return value of blast() is zero. If there is an error in
+ * the source data, i.e. it is not in the proper format, then a negative value
+ * is returned. If there is not enough input available or there is not enough
+ * output space, then a positive error is returned.
+ *
+ * The input function is invoked: len = infun(how, &buf), where buf is set by
+ * infun() to point to the input buffer, and infun() returns the number of
+ * available bytes there. If infun() returns zero, then blast() returns with
+ * an input error. (blast() only asks for input if it needs it.) inhow is for
+ * use by the application to pass an input descriptor to infun(), if desired.
+ *
+ * The output function is invoked: err = outfun(how, buf, len), where the bytes
+ * to be written are buf[0..len-1]. If err is not zero, then blast() returns
+ * with an output error. outfun() is always called with len <= 4096. outhow
+ * is for use by the application to pass an output descriptor to outfun(), if
+ * desired.
+ *
+ * The return codes are:
+ *
+ * 2: ran out of input before completing decompression
+ * 1: output error before completing decompression
+ * 0: successful decompression
+ * -1: literal flag not zero or one
+ * -2: dictionary size not in 4..6
+ * -3: distance is too far back
+ *
+ * At the bottom of blast.c is an example program that uses blast() that can be
+ * compiled to produce a command-line decompression filter by defining TEST.
+ */
diff --git a/zlib/contrib/blast/test.pk b/zlib/contrib/blast/test.pk
new file mode 100644
index 0000000..be10b2b
--- /dev/null
+++ b/zlib/contrib/blast/test.pk
Binary files differ
diff --git a/zlib/contrib/blast/test.txt b/zlib/contrib/blast/test.txt
new file mode 100644
index 0000000..bfdf1c5
--- /dev/null
+++ b/zlib/contrib/blast/test.txt
@@ -0,0 +1 @@
+AIAIAIAIAIAIA \ No newline at end of file
diff --git a/zlib/contrib/delphi/ZLib.pas b/zlib/contrib/delphi/ZLib.pas
new file mode 100644
index 0000000..3f2b8b4
--- /dev/null
+++ b/zlib/contrib/delphi/ZLib.pas
@@ -0,0 +1,557 @@
+{*******************************************************}
+{ }
+{ Borland Delphi Supplemental Components }
+{ ZLIB Data Compression Interface Unit }
+{ }
+{ Copyright (c) 1997,99 Borland Corporation }
+{ }
+{*******************************************************}
+
+{ Updated for zlib 1.2.x by Cosmin Truta <cosmint@cs.ubbcluj.ro> }
+
+unit ZLib;
+
+interface
+
+uses SysUtils, Classes;
+
+type
+ TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
+ TFree = procedure (AppData, Block: Pointer); cdecl;
+
+ // Internal structure. Ignore.
+ TZStreamRec = packed record
+ next_in: PChar; // next input byte
+ avail_in: Integer; // number of bytes available at next_in
+ total_in: Longint; // total nb of input bytes read so far
+
+ next_out: PChar; // next output byte should be put here
+ avail_out: Integer; // remaining free space at next_out
+ total_out: Longint; // total nb of bytes output so far
+
+ msg: PChar; // last error message, NULL if no error
+ internal: Pointer; // not visible by applications
+
+ zalloc: TAlloc; // used to allocate the internal state
+ zfree: TFree; // used to free the internal state
+ AppData: Pointer; // private data object passed to zalloc and zfree
+
+ data_type: Integer; // best guess about the data type: ascii or binary
+ adler: Longint; // adler32 value of the uncompressed data
+ reserved: Longint; // reserved for future use
+ end;
+
+ // Abstract ancestor class
+ TCustomZlibStream = class(TStream)
+ private
+ FStrm: TStream;
+ FStrmPos: Integer;
+ FOnProgress: TNotifyEvent;
+ FZRec: TZStreamRec;
+ FBuffer: array [Word] of Char;
+ protected
+ procedure Progress(Sender: TObject); dynamic;
+ property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
+ constructor Create(Strm: TStream);
+ end;
+
+{ TCompressionStream compresses data on the fly as data is written to it, and
+ stores the compressed data to another stream.
+
+ TCompressionStream is write-only and strictly sequential. Reading from the
+ stream will raise an exception. Using Seek to move the stream pointer
+ will raise an exception.
+
+ Output data is cached internally, written to the output stream only when
+ the internal output buffer is full. All pending output data is flushed
+ when the stream is destroyed.
+
+ The Position property returns the number of uncompressed bytes of
+ data that have been written to the stream so far.
+
+ CompressionRate returns the on-the-fly percentage by which the original
+ data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100
+ If raw data size = 100 and compressed data size = 25, the CompressionRate
+ is 75%
+
+ The OnProgress event is called each time the output buffer is filled and
+ written to the output stream. This is useful for updating a progress
+ indicator when you are writing a large chunk of data to the compression
+ stream in a single call.}
+
+
+ TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+ TCompressionStream = class(TCustomZlibStream)
+ private
+ function GetCompressionRate: Single;
+ public
+ constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property CompressionRate: Single read GetCompressionRate;
+ property OnProgress;
+ end;
+
+{ TDecompressionStream decompresses data on the fly as data is read from it.
+
+ Compressed data comes from a separate source stream. TDecompressionStream
+ is read-only and unidirectional; you can seek forward in the stream, but not
+ backwards. The special case of setting the stream position to zero is
+ allowed. Seeking forward decompresses data until the requested position in
+ the uncompressed data has been reached. Seeking backwards, seeking relative
+ to the end of the stream, requesting the size of the stream, and writing to
+ the stream will raise an exception.
+
+ The Position property returns the number of bytes of uncompressed data that
+ have been read from the stream so far.
+
+ The OnProgress event is called each time the internal input buffer of
+ compressed data is exhausted and the next block is read from the input stream.
+ This is useful for updating a progress indicator when you are reading a
+ large chunk of data from the decompression stream in a single call.}
+
+ TDecompressionStream = class(TCustomZlibStream)
+ public
+ constructor Create(Source: TStream);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property OnProgress;
+ end;
+
+
+
+{ CompressBuf compresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+ OutBytes = number of bytes in OutBuf }
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ out OutBuf: Pointer; out OutBytes: Integer);
+
+
+{ DecompressBuf decompresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ OutEstimate = zero, or est. size of the decompressed data
+ Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+ OutBytes = number of bytes in OutBuf }
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+
+{ DecompressToUserBuf decompresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ Out: OutBuf = ptr to user-allocated buffer to contain decompressed data
+ BufSize = number of bytes in OutBuf }
+procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
+ const OutBuf: Pointer; BufSize: Integer);
+
+const
+ zlib_version = '1.2.3';
+
+type
+ EZlibError = class(Exception);
+ ECompressionError = class(EZlibError);
+ EDecompressionError = class(EZlibError);
+
+implementation
+
+uses ZLibConst;
+
+const
+ Z_NO_FLUSH = 0;
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+ Z_NEED_DICT = 2;
+ Z_ERRNO = (-1);
+ Z_STREAM_ERROR = (-2);
+ Z_DATA_ERROR = (-3);
+ Z_MEM_ERROR = (-4);
+ Z_BUF_ERROR = (-5);
+ Z_VERSION_ERROR = (-6);
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = (-1);
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_RLE = 3;
+ Z_DEFAULT_STRATEGY = 0;
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_UNKNOWN = 2;
+
+ Z_DEFLATED = 8;
+
+
+{$L adler32.obj}
+{$L compress.obj}
+{$L crc32.obj}
+{$L deflate.obj}
+{$L infback.obj}
+{$L inffast.obj}
+{$L inflate.obj}
+{$L inftrees.obj}
+{$L trees.obj}
+{$L uncompr.obj}
+{$L zutil.obj}
+
+procedure adler32; external;
+procedure compressBound; external;
+procedure crc32; external;
+procedure deflateInit2_; external;
+procedure deflateParams; external;
+
+function _malloc(Size: Integer): Pointer; cdecl;
+begin
+ Result := AllocMem(Size);
+end;
+
+procedure _free(Block: Pointer); cdecl;
+begin
+ FreeMem(Block);
+end;
+
+procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl;
+begin
+ FillChar(P^, count, B);
+end;
+
+procedure _memcpy(dest, source: Pointer; count: Integer); cdecl;
+begin
+ Move(source^, dest^, count);
+end;
+
+
+
+// deflate compresses data
+function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
+ recsize: Integer): Integer; external;
+function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function deflateEnd(var strm: TZStreamRec): Integer; external;
+
+// inflate decompresses data
+function inflateInit_(var strm: TZStreamRec; version: PChar;
+ recsize: Integer): Integer; external;
+function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function inflateEnd(var strm: TZStreamRec): Integer; external;
+function inflateReset(var strm: TZStreamRec): Integer; external;
+
+
+function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
+begin
+// GetMem(Result, Items*Size);
+ Result := AllocMem(Items * Size);
+end;
+
+procedure zlibFreeMem(AppData, Block: Pointer); cdecl;
+begin
+ FreeMem(Block);
+end;
+
+{function zlibCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise EZlibError.Create('error'); //!!
+end;}
+
+function CCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise ECompressionError.Create('error'); //!!
+end;
+
+function DCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise EDecompressionError.Create('error'); //!!
+end;
+
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ out OutBuf: Pointer; out OutBytes: Integer);
+var
+ strm: TZStreamRec;
+ P: Pointer;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ strm.zalloc := zlibAllocMem;
+ strm.zfree := zlibFreeMem;
+ OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
+ GetMem(OutBuf, OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
+ try
+ while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, 256);
+ ReallocMem(OutBuf, OutBytes);
+ strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := 256;
+ end;
+ finally
+ CCheck(deflateEnd(strm));
+ end;
+ ReallocMem(OutBuf, strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise
+ end;
+end;
+
+
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+var
+ strm: TZStreamRec;
+ P: Pointer;
+ BufInc: Integer;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ strm.zalloc := zlibAllocMem;
+ strm.zfree := zlibFreeMem;
+ BufInc := (InBytes + 255) and not 255;
+ if OutEstimate = 0 then
+ OutBytes := BufInc
+ else
+ OutBytes := OutEstimate;
+ GetMem(OutBuf, OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
+ try
+ while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, BufInc);
+ ReallocMem(OutBuf, OutBytes);
+ strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := BufInc;
+ end;
+ finally
+ DCheck(inflateEnd(strm));
+ end;
+ ReallocMem(OutBuf, strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise
+ end;
+end;
+
+procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
+ const OutBuf: Pointer; BufSize: Integer);
+var
+ strm: TZStreamRec;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ strm.zalloc := zlibAllocMem;
+ strm.zfree := zlibFreeMem;
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := BufSize;
+ DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
+ try
+ if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then
+ raise EZlibError.CreateRes(@sTargetBufferTooSmall);
+ finally
+ DCheck(inflateEnd(strm));
+ end;
+end;
+
+// TCustomZlibStream
+
+constructor TCustomZLibStream.Create(Strm: TStream);
+begin
+ inherited Create;
+ FStrm := Strm;
+ FStrmPos := Strm.Position;
+ FZRec.zalloc := zlibAllocMem;
+ FZRec.zfree := zlibFreeMem;
+end;
+
+procedure TCustomZLibStream.Progress(Sender: TObject);
+begin
+ if Assigned(FOnProgress) then FOnProgress(Sender);
+end;
+
+
+// TCompressionStream
+
+constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
+ Dest: TStream);
+const
+ Levels: array [TCompressionLevel] of ShortInt =
+ (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
+begin
+ inherited Create(Dest);
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
+end;
+
+destructor TCompressionStream.Destroy;
+begin
+ FZRec.next_in := nil;
+ FZRec.avail_in := 0;
+ try
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
+ and (FZRec.avail_out = 0) do
+ begin
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ end;
+ if FZRec.avail_out < sizeof(FBuffer) then
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
+ finally
+ deflateEnd(FZRec);
+ end;
+ inherited Destroy;
+end;
+
+function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ raise ECompressionError.CreateRes(@sInvalidStreamOp);
+end;
+
+function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_in := @Buffer;
+ FZRec.avail_in := Count;
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (FZRec.avail_in > 0) do
+ begin
+ CCheck(deflate(FZRec, 0));
+ if FZRec.avail_out = 0 then
+ begin
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ FStrmPos := FStrm.Position;
+ Progress(Self);
+ end;
+ end;
+ Result := Count;
+end;
+
+function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+ if (Offset = 0) and (Origin = soFromCurrent) then
+ Result := FZRec.total_in
+ else
+ raise ECompressionError.CreateRes(@sInvalidStreamOp);
+end;
+
+function TCompressionStream.GetCompressionRate: Single;
+begin
+ if FZRec.total_in = 0 then
+ Result := 0
+ else
+ Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
+end;
+
+
+// TDecompressionStream
+
+constructor TDecompressionStream.Create(Source: TStream);
+begin
+ inherited Create(Source);
+ FZRec.next_in := FBuffer;
+ FZRec.avail_in := 0;
+ DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
+end;
+
+destructor TDecompressionStream.Destroy;
+begin
+ FStrm.Seek(-FZRec.avail_in, 1);
+ inflateEnd(FZRec);
+ inherited Destroy;
+end;
+
+function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_out := @Buffer;
+ FZRec.avail_out := Count;
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (FZRec.avail_out > 0) do
+ begin
+ if FZRec.avail_in = 0 then
+ begin
+ FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
+ if FZRec.avail_in = 0 then
+ begin
+ Result := Count - FZRec.avail_out;
+ Exit;
+ end;
+ FZRec.next_in := FBuffer;
+ FStrmPos := FStrm.Position;
+ Progress(Self);
+ end;
+ CCheck(inflate(FZRec, 0));
+ end;
+ Result := Count;
+end;
+
+function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ raise EDecompressionError.CreateRes(@sInvalidStreamOp);
+end;
+
+function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+ I: Integer;
+ Buf: array [0..4095] of Char;
+begin
+ if (Offset = 0) and (Origin = soFromBeginning) then
+ begin
+ DCheck(inflateReset(FZRec));
+ FZRec.next_in := FBuffer;
+ FZRec.avail_in := 0;
+ FStrm.Position := 0;
+ FStrmPos := 0;
+ end
+ else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
+ ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
+ begin
+ if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
+ if Offset > 0 then
+ begin
+ for I := 1 to Offset div sizeof(Buf) do
+ ReadBuffer(Buf, sizeof(Buf));
+ ReadBuffer(Buf, Offset mod sizeof(Buf));
+ end;
+ end
+ else
+ raise EDecompressionError.CreateRes(@sInvalidStreamOp);
+ Result := FZRec.total_out;
+end;
+
+
+end.
diff --git a/zlib/contrib/delphi/ZLibConst.pas b/zlib/contrib/delphi/ZLibConst.pas
new file mode 100644
index 0000000..cdfe136
--- /dev/null
+++ b/zlib/contrib/delphi/ZLibConst.pas
@@ -0,0 +1,11 @@
+unit ZLibConst;
+
+interface
+
+resourcestring
+ sTargetBufferTooSmall = 'ZLib error: target buffer may be too small';
+ sInvalidStreamOp = 'Invalid stream operation';
+
+implementation
+
+end.
diff --git a/zlib/contrib/delphi/readme.txt b/zlib/contrib/delphi/readme.txt
new file mode 100644
index 0000000..2dc9a8b
--- /dev/null
+++ b/zlib/contrib/delphi/readme.txt
@@ -0,0 +1,76 @@
+
+Overview
+========
+
+This directory contains an update to the ZLib interface unit,
+distributed by Borland as a Delphi supplemental component.
+
+The original ZLib unit is Copyright (c) 1997,99 Borland Corp.,
+and is based on zlib version 1.0.4. There are a series of bugs
+and security problems associated with that old zlib version, and
+we recommend the users to update their ZLib unit.
+
+
+Summary of modifications
+========================
+
+- Improved makefile, adapted to zlib version 1.2.1.
+
+- Some field types from TZStreamRec are changed from Integer to
+ Longint, for consistency with the zlib.h header, and for 64-bit
+ readiness.
+
+- The zlib_version constant is updated.
+
+- The new Z_RLE strategy has its corresponding symbolic constant.
+
+- The allocation and deallocation functions and function types
+ (TAlloc, TFree, zlibAllocMem and zlibFreeMem) are now cdecl,
+ and _malloc and _free are added as C RTL stubs. As a result,
+ the original C sources of zlib can be compiled out of the box,
+ and linked to the ZLib unit.
+
+
+Suggestions for improvements
+============================
+
+Currently, the ZLib unit provides only a limited wrapper around
+the zlib library, and much of the original zlib functionality is
+missing. Handling compressed file formats like ZIP/GZIP or PNG
+cannot be implemented without having this functionality.
+Applications that handle these formats are either using their own,
+duplicated code, or not using the ZLib unit at all.
+
+Here are a few suggestions:
+
+- Checksum class wrappers around adler32() and crc32(), similar
+ to the Java classes that implement the java.util.zip.Checksum
+ interface.
+
+- The ability to read and write raw deflate streams, without the
+ zlib stream header and trailer. Raw deflate streams are used
+ in the ZIP file format.
+
+- The ability to read and write gzip streams, used in the GZIP
+ file format, and normally produced by the gzip program.
+
+- The ability to select a different compression strategy, useful
+ to PNG and MNG image compression, and to multimedia compression
+ in general. Besides the compression level
+
+ TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+ which, in fact, could have used the 'z' prefix and avoided
+ TColor-like symbols
+
+ TCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax);
+
+ there could be a compression strategy
+
+ TCompressionStrategy = (zsDefault, zsFiltered, zsHuffmanOnly, zsRle);
+
+- ZIP and GZIP stream handling via TStreams.
+
+
+--
+Cosmin Truta <cosmint@cs.ubbcluj.ro>
diff --git a/zlib/contrib/delphi/zlibd32.mak b/zlib/contrib/delphi/zlibd32.mak
new file mode 100644
index 0000000..88fafa0
--- /dev/null
+++ b/zlib/contrib/delphi/zlibd32.mak
@@ -0,0 +1,93 @@
+# Makefile for zlib
+# For use with Delphi and C++ Builder under Win32
+# Updated for zlib 1.2.x by Cosmin Truta
+
+# ------------ Borland C++ ------------
+
+# This project uses the Delphi (fastcall/register) calling convention:
+LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl
+
+CC = bcc32
+LD = bcc32
+AR = tlib
+# do not use "-pr" in CFLAGS
+CFLAGS = -a -d -k- -O2 $(LOC)
+LDFLAGS =
+
+
+# variables
+ZLIB_LIB = zlib.lib
+
+OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj
+OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj
+OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj
+
+
+# targets
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: example.c zlib.h zconf.h
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+
+
+# For the sake of the old Borland make,
+# the command line is cut to fit in the MS-DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ -del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) $(OBJP1)
+ $(AR) $(ZLIB_LIB) $(OBJP2)
+
+
+# testing
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+
+# cleanup
+clean:
+ -del *.obj
+ -del *.exe
+ -del *.lib
+ -del *.tds
+ -del zlib.bak
+ -del foo.gz
+
diff --git a/zlib/contrib/infback9/README b/zlib/contrib/infback9/README
new file mode 100644
index 0000000..e75ed13
--- /dev/null
+++ b/zlib/contrib/infback9/README
@@ -0,0 +1 @@
+See infback9.h for what this is and how to use it.
diff --git a/zlib/contrib/infback9/infback9.c b/zlib/contrib/infback9/infback9.c
new file mode 100644
index 0000000..f5ddde6
--- /dev/null
+++ b/zlib/contrib/infback9/infback9.c
@@ -0,0 +1,608 @@
+/* infback9.c -- inflate deflate64 data using a call-back interface
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infback9.h"
+#include "inftree9.h"
+#include "inflate9.h"
+
+#define WSIZE 65536UL
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ window is a user-supplied window and output buffer that is 64K bytes.
+ */
+int ZEXPORT inflateBack9Init_(strm, window, version, stream_size)
+z_stream FAR *strm;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (voidpf)state;
+ state->window = window;
+ return Z_OK;
+}
+
+/*
+ Build and output length and distance decoding tables for fixed code
+ decoding.
+ */
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+void makefixed9(void)
+{
+ unsigned sym, bits, low, size;
+ code *next, *lenfix, *distfix;
+ struct inflate_state state;
+ code fixed[544];
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state.lens[sym++] = 8;
+ while (sym < 256) state.lens[sym++] = 9;
+ while (sym < 280) state.lens[sym++] = 7;
+ while (sym < 288) state.lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table9(LENS, state.lens, 288, &(next), &(bits), state.work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state.lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table9(DISTS, state.lens, 32, &(next), &(bits), state.work);
+
+ /* write tables */
+ puts(" /* inffix9.h -- table for decoding deflate64 fixed codes");
+ puts(" * Generated automatically by makefixed9().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", lenfix[low].op, lenfix[low].bits,
+ lenfix[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 5) == 0) printf("\n ");
+ printf("{%u,%u,%d}", distfix[low].op, distfix[low].bits,
+ distfix[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/* Macros for inflateBack(): */
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n <= 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = window; \
+ left = WSIZE; \
+ wrap = 1; \
+ if (out(out_desc, put, (unsigned)left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack9(strm, in, in_desc, out, out_desc)
+z_stream FAR *strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have; /* available input */
+ unsigned long left; /* available output */
+ inflate_mode mode; /* current inflate mode */
+ int lastblock; /* true if processing last block */
+ int wrap; /* true if the window has wrapped */
+ unsigned long write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned extra; /* extra bits needed */
+ unsigned long length; /* literal or length of data to copy */
+ unsigned long offset; /* distance back to copy string from */
+ unsigned long copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+#include "inffix9.h"
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ mode = TYPE;
+ lastblock = 0;
+ write = 0;
+ wrap = 0;
+ window = state->window;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = window;
+ left = WSIZE;
+ lencode = Z_NULL;
+ distcode = Z_NULL;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (lastblock) {
+ BYTEBITS();
+ mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ lastblock = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ lastblock ? " (last)" : ""));
+ mode = STORED;
+ break;
+ case 1: /* fixed block */
+ lencode = lenfix;
+ lenbits = 9;
+ distcode = distfix;
+ distbits = 5;
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ lastblock ? " (last)" : ""));
+ mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ lastblock ? " (last)" : ""));
+ mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ mode = BAD;
+ break;
+ }
+ length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %lu\n",
+ length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (length != 0) {
+ copy = length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+ if (state->nlen > 286) {
+ strm->msg = (char *)"too many length symbols";
+ mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ lencode = (code const FAR *)(state->next);
+ lenbits = 7;
+ ret = inflate_table9(CODES, state->lens, 19, &(state->next),
+ &(lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = lencode[BITS(lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ lencode = (code const FAR *)(state->next);
+ lenbits = 9;
+ ret = inflate_table9(LENS, state->lens, state->nlen,
+ &(state->next), &(lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ mode = BAD;
+ break;
+ }
+ distcode = (code const FAR *)(state->next);
+ distbits = 6;
+ ret = inflate_table9(DISTS, state->lens + state->nlen,
+ state->ndist, &(state->next), &(distbits),
+ state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ mode = LEN;
+
+ case LEN:
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = lencode[BITS(lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(length);
+ left--;
+ mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ extra = (unsigned)(this.op) & 31;
+ if (extra != 0) {
+ NEEDBITS(extra);
+ length += BITS(extra);
+ DROPBITS(extra);
+ }
+ Tracevv((stderr, "inflate: length %lu\n", length));
+
+ /* get distance code */
+ for (;;) {
+ this = distcode[BITS(distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ mode = BAD;
+ break;
+ }
+ offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ extra = (unsigned)(this.op) & 15;
+ if (extra != 0) {
+ NEEDBITS(extra);
+ offset += BITS(extra);
+ DROPBITS(extra);
+ }
+ if (offset > WSIZE - (wrap ? 0: left)) {
+ strm->msg = (char *)"invalid distance too far back";
+ mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %lu\n", offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = WSIZE - offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - offset;
+ copy = left;
+ }
+ if (copy > length) copy = length;
+ length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < WSIZE) {
+ if (out(out_desc, window, (unsigned)(WSIZE - left)))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBack9End(strm)
+z_stream FAR *strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/zlib/contrib/infback9/infback9.h b/zlib/contrib/infback9/infback9.h
new file mode 100644
index 0000000..1073c0a
--- /dev/null
+++ b/zlib/contrib/infback9/infback9.h
@@ -0,0 +1,37 @@
+/* infback9.h -- header for using inflateBack9 functions
+ * Copyright (C) 2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * This header file and associated patches provide a decoder for PKWare's
+ * undocumented deflate64 compression method (method 9). Use with infback9.c,
+ * inftree9.h, inftree9.c, and inffix9.h. These patches are not supported.
+ * This should be compiled with zlib, since it uses zutil.h and zutil.o.
+ * This code has not yet been tested on 16-bit architectures. See the
+ * comments in zlib.h for inflateBack() usage. These functions are used
+ * identically, except that there is no windowBits parameter, and a 64K
+ * window must be provided. Also if int's are 16 bits, then a zero for
+ * the third parameter of the "out" function actually means 65536UL.
+ * zlib.h must be included before this header file.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ZEXTERN int ZEXPORT inflateBack9 OF((z_stream FAR *strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+ZEXTERN int ZEXPORT inflateBack9End OF((z_stream FAR *strm));
+ZEXTERN int ZEXPORT inflateBack9Init_ OF((z_stream FAR *strm,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define inflateBack9Init(strm, window) \
+ inflateBack9Init_((strm), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/zlib/contrib/infback9/inffix9.h b/zlib/contrib/infback9/inffix9.h
new file mode 100644
index 0000000..ee5671d
--- /dev/null
+++ b/zlib/contrib/infback9/inffix9.h
@@ -0,0 +1,107 @@
+ /* inffix9.h -- table for decoding deflate64 fixed codes
+ * Generated automatically by makefixed9().
+ */
+
+ /* WARNING: this file should *not* be used by applications.
+ It is part of the implementation of this library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{132,8,115},{130,7,31},{0,8,112},
+ {0,8,48},{0,9,192},{128,7,10},{0,8,96},{0,8,32},{0,9,160},
+ {0,8,0},{0,8,128},{0,8,64},{0,9,224},{128,7,6},{0,8,88},
+ {0,8,24},{0,9,144},{131,7,59},{0,8,120},{0,8,56},{0,9,208},
+ {129,7,17},{0,8,104},{0,8,40},{0,9,176},{0,8,8},{0,8,136},
+ {0,8,72},{0,9,240},{128,7,4},{0,8,84},{0,8,20},{133,8,227},
+ {131,7,43},{0,8,116},{0,8,52},{0,9,200},{129,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},
+ {128,7,8},{0,8,92},{0,8,28},{0,9,152},{132,7,83},{0,8,124},
+ {0,8,60},{0,9,216},{130,7,23},{0,8,108},{0,8,44},{0,9,184},
+ {0,8,12},{0,8,140},{0,8,76},{0,9,248},{128,7,3},{0,8,82},
+ {0,8,18},{133,8,163},{131,7,35},{0,8,114},{0,8,50},{0,9,196},
+ {129,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},{0,8,130},
+ {0,8,66},{0,9,228},{128,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {132,7,67},{0,8,122},{0,8,58},{0,9,212},{130,7,19},{0,8,106},
+ {0,8,42},{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},
+ {128,7,5},{0,8,86},{0,8,22},{65,8,0},{131,7,51},{0,8,118},
+ {0,8,54},{0,9,204},{129,7,15},{0,8,102},{0,8,38},{0,9,172},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,236},{128,7,9},{0,8,94},
+ {0,8,30},{0,9,156},{132,7,99},{0,8,126},{0,8,62},{0,9,220},
+ {130,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{133,8,131},
+ {130,7,31},{0,8,113},{0,8,49},{0,9,194},{128,7,10},{0,8,97},
+ {0,8,33},{0,9,162},{0,8,1},{0,8,129},{0,8,65},{0,9,226},
+ {128,7,6},{0,8,89},{0,8,25},{0,9,146},{131,7,59},{0,8,121},
+ {0,8,57},{0,9,210},{129,7,17},{0,8,105},{0,8,41},{0,9,178},
+ {0,8,9},{0,8,137},{0,8,73},{0,9,242},{128,7,4},{0,8,85},
+ {0,8,21},{144,8,3},{131,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {129,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},
+ {0,8,69},{0,9,234},{128,7,8},{0,8,93},{0,8,29},{0,9,154},
+ {132,7,83},{0,8,125},{0,8,61},{0,9,218},{130,7,23},{0,8,109},
+ {0,8,45},{0,9,186},{0,8,13},{0,8,141},{0,8,77},{0,9,250},
+ {128,7,3},{0,8,83},{0,8,19},{133,8,195},{131,7,35},{0,8,115},
+ {0,8,51},{0,9,198},{129,7,11},{0,8,99},{0,8,35},{0,9,166},
+ {0,8,3},{0,8,131},{0,8,67},{0,9,230},{128,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{132,7,67},{0,8,123},{0,8,59},{0,9,214},
+ {130,7,19},{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},
+ {0,8,75},{0,9,246},{128,7,5},{0,8,87},{0,8,23},{77,8,0},
+ {131,7,51},{0,8,119},{0,8,55},{0,9,206},{129,7,15},{0,8,103},
+ {0,8,39},{0,9,174},{0,8,7},{0,8,135},{0,8,71},{0,9,238},
+ {128,7,9},{0,8,95},{0,8,31},{0,9,158},{132,7,99},{0,8,127},
+ {0,8,63},{0,9,222},{130,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},
+ {0,8,16},{132,8,115},{130,7,31},{0,8,112},{0,8,48},{0,9,193},
+ {128,7,10},{0,8,96},{0,8,32},{0,9,161},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,225},{128,7,6},{0,8,88},{0,8,24},{0,9,145},
+ {131,7,59},{0,8,120},{0,8,56},{0,9,209},{129,7,17},{0,8,104},
+ {0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},{0,9,241},
+ {128,7,4},{0,8,84},{0,8,20},{133,8,227},{131,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{129,7,13},{0,8,100},{0,8,36},{0,9,169},
+ {0,8,4},{0,8,132},{0,8,68},{0,9,233},{128,7,8},{0,8,92},
+ {0,8,28},{0,9,153},{132,7,83},{0,8,124},{0,8,60},{0,9,217},
+ {130,7,23},{0,8,108},{0,8,44},{0,9,185},{0,8,12},{0,8,140},
+ {0,8,76},{0,9,249},{128,7,3},{0,8,82},{0,8,18},{133,8,163},
+ {131,7,35},{0,8,114},{0,8,50},{0,9,197},{129,7,11},{0,8,98},
+ {0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {128,7,7},{0,8,90},{0,8,26},{0,9,149},{132,7,67},{0,8,122},
+ {0,8,58},{0,9,213},{130,7,19},{0,8,106},{0,8,42},{0,9,181},
+ {0,8,10},{0,8,138},{0,8,74},{0,9,245},{128,7,5},{0,8,86},
+ {0,8,22},{65,8,0},{131,7,51},{0,8,118},{0,8,54},{0,9,205},
+ {129,7,15},{0,8,102},{0,8,38},{0,9,173},{0,8,6},{0,8,134},
+ {0,8,70},{0,9,237},{128,7,9},{0,8,94},{0,8,30},{0,9,157},
+ {132,7,99},{0,8,126},{0,8,62},{0,9,221},{130,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},
+ {96,7,0},{0,8,81},{0,8,17},{133,8,131},{130,7,31},{0,8,113},
+ {0,8,49},{0,9,195},{128,7,10},{0,8,97},{0,8,33},{0,9,163},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,227},{128,7,6},{0,8,89},
+ {0,8,25},{0,9,147},{131,7,59},{0,8,121},{0,8,57},{0,9,211},
+ {129,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},{0,8,137},
+ {0,8,73},{0,9,243},{128,7,4},{0,8,85},{0,8,21},{144,8,3},
+ {131,7,43},{0,8,117},{0,8,53},{0,9,203},{129,7,13},{0,8,101},
+ {0,8,37},{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},
+ {128,7,8},{0,8,93},{0,8,29},{0,9,155},{132,7,83},{0,8,125},
+ {0,8,61},{0,9,219},{130,7,23},{0,8,109},{0,8,45},{0,9,187},
+ {0,8,13},{0,8,141},{0,8,77},{0,9,251},{128,7,3},{0,8,83},
+ {0,8,19},{133,8,195},{131,7,35},{0,8,115},{0,8,51},{0,9,199},
+ {129,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{128,7,7},{0,8,91},{0,8,27},{0,9,151},
+ {132,7,67},{0,8,123},{0,8,59},{0,9,215},{130,7,19},{0,8,107},
+ {0,8,43},{0,9,183},{0,8,11},{0,8,139},{0,8,75},{0,9,247},
+ {128,7,5},{0,8,87},{0,8,23},{77,8,0},{131,7,51},{0,8,119},
+ {0,8,55},{0,9,207},{129,7,15},{0,8,103},{0,8,39},{0,9,175},
+ {0,8,7},{0,8,135},{0,8,71},{0,9,239},{128,7,9},{0,8,95},
+ {0,8,31},{0,9,159},{132,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {130,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},
+ {0,8,79},{0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {128,5,1},{135,5,257},{131,5,17},{139,5,4097},{129,5,5},
+ {137,5,1025},{133,5,65},{141,5,16385},{128,5,3},{136,5,513},
+ {132,5,33},{140,5,8193},{130,5,9},{138,5,2049},{134,5,129},
+ {142,5,32769},{128,5,2},{135,5,385},{131,5,25},{139,5,6145},
+ {129,5,7},{137,5,1537},{133,5,97},{141,5,24577},{128,5,4},
+ {136,5,769},{132,5,49},{140,5,12289},{130,5,13},{138,5,3073},
+ {134,5,193},{142,5,49153}
+ };
diff --git a/zlib/contrib/infback9/inflate9.h b/zlib/contrib/infback9/inflate9.h
new file mode 100644
index 0000000..ee9a793
--- /dev/null
+++ b/zlib/contrib/infback9/inflate9.h
@@ -0,0 +1,47 @@
+/* inflate9.h -- internal inflate state definition
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ STORED, /* i: waiting for stored size (length and complement) */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LEN, /* i: waiting for length/lit code */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD /* got a data error -- remain here until reset */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD mode -- not shown for clarity)
+
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or DONE
+ STORED -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LEN or TYPE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ /* sliding window */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/zlib/contrib/infback9/inftree9.c b/zlib/contrib/infback9/inftree9.c
new file mode 100644
index 0000000..0993f75
--- /dev/null
+++ b/zlib/contrib/infback9/inftree9.c
@@ -0,0 +1,323 @@
+/* inftree9.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftree9.h"
+
+#define MAXBITS 15
+
+const char inflate9_copyright[] =
+ " inflate9 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table9(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17,
+ 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115,
+ 131, 163, 195, 227, 3, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129,
+ 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132,
+ 133, 133, 133, 133, 144, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..31 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49,
+ 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073,
+ 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153};
+ static const unsigned short dext[32] = { /* Distance codes 0..31 extra */
+ 128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132,
+ 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138,
+ 139, 139, 140, 140, 141, 141, 142, 142};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) return -1; /* no codes! */
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += 1U << curr;
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ curr = root;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/zlib/contrib/infback9/inftree9.h b/zlib/contrib/infback9/inftree9.h
new file mode 100644
index 0000000..a268084
--- /dev/null
+++ b/zlib/contrib/infback9/inftree9.h
@@ -0,0 +1,55 @@
+/* inftree9.h -- header to use inftree9.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 100eeeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table9 OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/zlib/contrib/inflate86/inffas86.c b/zlib/contrib/inflate86/inffas86.c
new file mode 100644
index 0000000..6da7635
--- /dev/null
+++ b/zlib/contrib/inflate86/inffas86.c
@@ -0,0 +1,1157 @@
+/* inffas86.c is a hand tuned assembler version of
+ *
+ * inffast.c -- fast decoding
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Copyright (C) 2003 Chris Anderson <christop@charm.net>
+ * Please use the copyright conditions above.
+ *
+ * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also
+ * slightly quicker on x86 systems because, instead of using rep movsb to copy
+ * data, it uses rep movsw, which moves data in 2-byte chunks instead of single
+ * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates
+ * from http://fedora.linux.duke.edu/fc1_x86_64
+ * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with
+ * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version,
+ * when decompressing mozilla-source-1.3.tar.gz.
+ *
+ * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from
+ * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at
+ * the moment. I have successfully compiled and tested this code with gcc2.96,
+ * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S
+ * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX
+ * enabled. I will attempt to merge the MMX code into this version. Newer
+ * versions of this and inffast.S can be found at
+ * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* Mark Adler's comments from inffast.c: */
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ struct inffast_ar {
+/* 64 32 x86 x86_64 */
+/* ar offset register */
+/* 0 0 */ void *esp; /* esp save */
+/* 8 4 */ void *ebp; /* ebp save */
+/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */
+/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */
+/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */
+/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */
+/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */
+/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */
+/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */
+/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */
+/* 80 40 */ unsigned long hold; /* edx rdx local strm->hold */
+/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */
+/* 92 48 */ unsigned wsize; /* window size */
+/* 96 52 */ unsigned write; /* window write index */
+/*100 56 */ unsigned lmask; /* r12 mask for lcode */
+/*104 60 */ unsigned dmask; /* r13 mask for dcode */
+/*108 64 */ unsigned len; /* r14 match length */
+/*112 68 */ unsigned dist; /* r15 match distance */
+/*116 72 */ unsigned status; /* set when state chng*/
+ } ar;
+
+#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )
+#define PAD_AVAIL_IN 6
+#define PAD_AVAIL_OUT 258
+#else
+#define PAD_AVAIL_IN 5
+#define PAD_AVAIL_OUT 257
+#endif
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ ar.in = strm->next_in;
+ ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN);
+ ar.out = strm->next_out;
+ ar.beg = ar.out - (start - strm->avail_out);
+ ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT);
+ ar.wsize = state->wsize;
+ ar.write = state->write;
+ ar.window = state->window;
+ ar.hold = state->hold;
+ ar.bits = state->bits;
+ ar.lcode = state->lencode;
+ ar.dcode = state->distcode;
+ ar.lmask = (1U << state->lenbits) - 1;
+ ar.dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+
+ /* align in on 1/2 hold size boundary */
+ while (((unsigned long)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) {
+ ar.hold += (unsigned long)*ar.in++ << ar.bits;
+ ar.bits += 8;
+ }
+
+#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )
+ __asm__ __volatile__ (
+" leaq %0, %%rax\n"
+" movq %%rbp, 8(%%rax)\n" /* save regs rbp and rsp */
+" movq %%rsp, (%%rax)\n"
+" movq %%rax, %%rsp\n" /* make rsp point to &ar */
+" movq 16(%%rsp), %%rsi\n" /* rsi = in */
+" movq 32(%%rsp), %%rdi\n" /* rdi = out */
+" movq 24(%%rsp), %%r9\n" /* r9 = last */
+" movq 48(%%rsp), %%r10\n" /* r10 = end */
+" movq 64(%%rsp), %%rbp\n" /* rbp = lcode */
+" movq 72(%%rsp), %%r11\n" /* r11 = dcode */
+" movq 80(%%rsp), %%rdx\n" /* rdx = hold */
+" movl 88(%%rsp), %%ebx\n" /* ebx = bits */
+" movl 100(%%rsp), %%r12d\n" /* r12d = lmask */
+" movl 104(%%rsp), %%r13d\n" /* r13d = dmask */
+ /* r14d = len */
+ /* r15d = dist */
+" cld\n"
+" cmpq %%rdi, %%r10\n"
+" je .L_one_time\n" /* if only one decode left */
+" cmpq %%rsi, %%r9\n"
+" je .L_one_time\n"
+" jmp .L_do_loop\n"
+
+".L_one_time:\n"
+" movq %%r12, %%r8\n" /* r8 = lmask */
+" cmpb $32, %%bl\n"
+" ja .L_get_length_code_one_time\n"
+
+" lodsl\n" /* eax = *(uint *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $32, %%bl\n" /* bits += 32 */
+" shlq %%cl, %%rax\n"
+" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */
+" jmp .L_get_length_code_one_time\n"
+
+".align 32,0x90\n"
+".L_while_test:\n"
+" cmpq %%rdi, %%r10\n"
+" jbe .L_break_loop\n"
+" cmpq %%rsi, %%r9\n"
+" jbe .L_break_loop\n"
+
+".L_do_loop:\n"
+" movq %%r12, %%r8\n" /* r8 = lmask */
+" cmpb $32, %%bl\n"
+" ja .L_get_length_code\n" /* if (32 < bits) */
+
+" lodsl\n" /* eax = *(uint *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $32, %%bl\n" /* bits += 32 */
+" shlq %%cl, %%rax\n"
+" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */
+
+".L_get_length_code:\n"
+" andq %%rdx, %%r8\n" /* r8 &= hold */
+" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */
+
+" movb %%ah, %%cl\n" /* cl = this.bits */
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrq %%cl, %%rdx\n" /* hold >>= this.bits */
+
+" testb %%al, %%al\n"
+" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */
+
+" movq %%r12, %%r8\n" /* r8 = lmask */
+" shrl $16, %%eax\n" /* output this.val char */
+" stosb\n"
+
+".L_get_length_code_one_time:\n"
+" andq %%rdx, %%r8\n" /* r8 &= hold */
+" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */
+
+".L_dolen:\n"
+" movb %%ah, %%cl\n" /* cl = this.bits */
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrq %%cl, %%rdx\n" /* hold >>= this.bits */
+
+" testb %%al, %%al\n"
+" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */
+
+" shrl $16, %%eax\n" /* output this.val char */
+" stosb\n"
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_length_base:\n"
+" movl %%eax, %%r14d\n" /* len = this */
+" shrl $16, %%r14d\n" /* len = this.val */
+" movb %%al, %%cl\n"
+
+" testb $16, %%al\n"
+" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_decode_distance\n" /* if (!op) */
+
+".L_add_bits_to_len:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrq %%cl, %%rdx\n"
+" addl %%eax, %%r14d\n" /* len += hold & mask[op] */
+
+".L_decode_distance:\n"
+" movq %%r13, %%r8\n" /* r8 = dmask */
+" cmpb $32, %%bl\n"
+" ja .L_get_distance_code\n" /* if (32 < bits) */
+
+" lodsl\n" /* eax = *(uint *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $32, %%bl\n" /* bits += 32 */
+" shlq %%cl, %%rax\n"
+" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */
+
+".L_get_distance_code:\n"
+" andq %%rdx, %%r8\n" /* r8 &= hold */
+" movl (%%r11,%%r8,4), %%eax\n" /* eax = dcode[hold & dmask] */
+
+".L_dodist:\n"
+" movl %%eax, %%r15d\n" /* dist = this */
+" shrl $16, %%r15d\n" /* dist = this.val */
+" movb %%ah, %%cl\n"
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrq %%cl, %%rdx\n" /* hold >>= this.bits */
+" movb %%al, %%cl\n" /* cl = this.op */
+
+" testb $16, %%al\n" /* if ((op & 16) == 0) */
+" jz .L_test_for_second_level_dist\n"
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_check_dist_one\n"
+
+".L_add_bits_to_dist:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n" /* (1 << op) - 1 */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrq %%cl, %%rdx\n"
+" addl %%eax, %%r15d\n" /* dist += hold & ((1 << op) - 1) */
+
+".L_check_window:\n"
+" movq %%rsi, %%r8\n" /* save in so from can use it's reg */
+" movq %%rdi, %%rax\n"
+" subq 40(%%rsp), %%rax\n" /* nbytes = out - beg */
+
+" cmpl %%r15d, %%eax\n"
+" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */
+
+" movl %%r14d, %%ecx\n" /* ecx = len */
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = out - dist */
+
+" sarl %%ecx\n"
+" jnc .L_copy_two\n" /* if len % 2 == 0 */
+
+" rep movsw\n"
+" movb (%%rsi), %%al\n"
+" movb %%al, (%%rdi)\n"
+" incq %%rdi\n"
+
+" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */
+" jmp .L_while_test\n"
+
+".L_copy_two:\n"
+" rep movsw\n"
+" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_check_dist_one:\n"
+" cmpl $1, %%r15d\n" /* if dist 1, is a memset */
+" jne .L_check_window\n"
+" cmpq %%rdi, 40(%%rsp)\n" /* if out == beg, outside window */
+" je .L_check_window\n"
+
+" movl %%r14d, %%ecx\n" /* ecx = len */
+" movb -1(%%rdi), %%al\n"
+" movb %%al, %%ah\n"
+
+" sarl %%ecx\n"
+" jnc .L_set_two\n"
+" movb %%al, (%%rdi)\n"
+" incq %%rdi\n"
+
+".L_set_two:\n"
+" rep stosw\n"
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_length:\n"
+" testb $64, %%al\n"
+" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl %%r14d, %%eax\n" /* eax += len */
+" movl (%%rbp,%%rax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/
+" jmp .L_dolen\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_dist:\n"
+" testb $64, %%al\n"
+" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl %%r15d, %%eax\n" /* eax += dist */
+" movl (%%r11,%%rax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/
+" jmp .L_dodist\n"
+
+".align 32,0x90\n"
+".L_clip_window:\n"
+" movl %%eax, %%ecx\n" /* ecx = nbytes */
+" movl 92(%%rsp), %%eax\n" /* eax = wsize, prepare for dist cmp */
+" negl %%ecx\n" /* nbytes = -nbytes */
+
+" cmpl %%r15d, %%eax\n"
+" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */
+
+" addl %%r15d, %%ecx\n" /* nbytes = dist - nbytes */
+" cmpl $0, 96(%%rsp)\n"
+" jne .L_wrap_around_window\n" /* if (write != 0) */
+
+" movq 56(%%rsp), %%rsi\n" /* from = window */
+" subl %%ecx, %%eax\n" /* eax -= nbytes */
+" addq %%rax, %%rsi\n" /* from += wsize - nbytes */
+
+" movl %%r14d, %%eax\n" /* eax = len */
+" cmpl %%ecx, %%r14d\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* eax -= nbytes */
+" rep movsb\n"
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = &out[ -dist ] */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_wrap_around_window:\n"
+" movl 96(%%rsp), %%eax\n" /* eax = write */
+" cmpl %%eax, %%ecx\n"
+" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */
+
+" movl 92(%%rsp), %%esi\n" /* from = wsize */
+" addq 56(%%rsp), %%rsi\n" /* from += window */
+" addq %%rax, %%rsi\n" /* from += write */
+" subq %%rcx, %%rsi\n" /* from -= nbytes */
+" subl %%eax, %%ecx\n" /* nbytes -= write */
+
+" movl %%r14d, %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movq 56(%%rsp), %%rsi\n" /* from = window */
+" movl 96(%%rsp), %%ecx\n" /* nbytes = write */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = out - dist */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_contiguous_in_window:\n"
+" movq 56(%%rsp), %%rsi\n" /* rsi = window */
+" addq %%rax, %%rsi\n"
+" subq %%rcx, %%rsi\n" /* from += write - nbytes */
+
+" movl %%r14d, %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = out - dist */
+" jmp .L_do_copy\n" /* if (nbytes >= len) */
+
+".align 32,0x90\n"
+".L_do_copy:\n"
+" movl %%eax, %%ecx\n" /* ecx = len */
+" rep movsb\n"
+
+" movq %%r8, %%rsi\n" /* move in back to %esi, toss from */
+" jmp .L_while_test\n"
+
+".L_test_for_end_of_block:\n"
+" testb $32, %%al\n"
+" jz .L_invalid_literal_length_code\n"
+" movl $1, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_literal_length_code:\n"
+" movl $2, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_code:\n"
+" movl $3, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_too_far:\n"
+" movl $4, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_break_loop:\n"
+" movl $0, 116(%%rsp)\n"
+
+".L_break_loop_with_status:\n"
+/* put in, out, bits, and hold back into ar and pop esp */
+" movq %%rsi, 16(%%rsp)\n" /* in */
+" movq %%rdi, 32(%%rsp)\n" /* out */
+" movl %%ebx, 88(%%rsp)\n" /* bits */
+" movq %%rdx, 80(%%rsp)\n" /* hold */
+" movq (%%rsp), %%rax\n" /* restore rbp and rsp */
+" movq 8(%%rsp), %%rbp\n"
+" movq %%rax, %%rsp\n"
+ :
+ : "m" (ar)
+ : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
+ );
+#elif ( defined( __GNUC__ ) || defined( __ICC ) ) && defined( __i386 )
+ __asm__ __volatile__ (
+" leal %0, %%eax\n"
+" movl %%esp, (%%eax)\n" /* save esp, ebp */
+" movl %%ebp, 4(%%eax)\n"
+" movl %%eax, %%esp\n"
+" movl 8(%%esp), %%esi\n" /* esi = in */
+" movl 16(%%esp), %%edi\n" /* edi = out */
+" movl 40(%%esp), %%edx\n" /* edx = hold */
+" movl 44(%%esp), %%ebx\n" /* ebx = bits */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+
+" cld\n"
+" jmp .L_do_loop\n"
+
+".align 32,0x90\n"
+".L_while_test:\n"
+" cmpl %%edi, 24(%%esp)\n" /* out < end */
+" jbe .L_break_loop\n"
+" cmpl %%esi, 12(%%esp)\n" /* in < last */
+" jbe .L_break_loop\n"
+
+".L_do_loop:\n"
+" cmpb $15, %%bl\n"
+" ja .L_get_length_code\n" /* if (15 < bits) */
+
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+
+".L_get_length_code:\n"
+" movl 56(%%esp), %%eax\n" /* eax = lmask */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */
+
+".L_dolen:\n"
+" movb %%ah, %%cl\n" /* cl = this.bits */
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrl %%cl, %%edx\n" /* hold >>= this.bits */
+
+" testb %%al, %%al\n"
+" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */
+
+" shrl $16, %%eax\n" /* output this.val char */
+" stosb\n"
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_length_base:\n"
+" movl %%eax, %%ecx\n" /* len = this */
+" shrl $16, %%ecx\n" /* len = this.val */
+" movl %%ecx, 64(%%esp)\n" /* save len */
+" movb %%al, %%cl\n"
+
+" testb $16, %%al\n"
+" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_decode_distance\n" /* if (!op) */
+" cmpb %%cl, %%bl\n"
+" jae .L_add_bits_to_len\n" /* if (op <= bits) */
+
+" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+" movb %%ch, %%cl\n" /* move op back to ecx */
+
+".L_add_bits_to_len:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrl %%cl, %%edx\n"
+" addl %%eax, 64(%%esp)\n" /* len += hold & mask[op] */
+
+".L_decode_distance:\n"
+" cmpb $15, %%bl\n"
+" ja .L_get_distance_code\n" /* if (15 < bits) */
+
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+
+".L_get_distance_code:\n"
+" movl 60(%%esp), %%eax\n" /* eax = dmask */
+" movl 36(%%esp), %%ecx\n" /* ecx = dcode */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" movl (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */
+
+".L_dodist:\n"
+" movl %%eax, %%ebp\n" /* dist = this */
+" shrl $16, %%ebp\n" /* dist = this.val */
+" movb %%ah, %%cl\n"
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrl %%cl, %%edx\n" /* hold >>= this.bits */
+" movb %%al, %%cl\n" /* cl = this.op */
+
+" testb $16, %%al\n" /* if ((op & 16) == 0) */
+" jz .L_test_for_second_level_dist\n"
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_check_dist_one\n"
+" cmpb %%cl, %%bl\n"
+" jae .L_add_bits_to_dist\n" /* if (op <= bits) 97.6% */
+
+" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+" movb %%ch, %%cl\n" /* move op back to ecx */
+
+".L_add_bits_to_dist:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n" /* (1 << op) - 1 */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrl %%cl, %%edx\n"
+" addl %%eax, %%ebp\n" /* dist += hold & ((1 << op) - 1) */
+
+".L_check_window:\n"
+" movl %%esi, 8(%%esp)\n" /* save in so from can use it's reg */
+" movl %%edi, %%eax\n"
+" subl 20(%%esp), %%eax\n" /* nbytes = out - beg */
+
+" cmpl %%ebp, %%eax\n"
+" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */
+
+" movl 64(%%esp), %%ecx\n" /* ecx = len */
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+
+" sarl %%ecx\n"
+" jnc .L_copy_two\n" /* if len % 2 == 0 */
+
+" rep movsw\n"
+" movb (%%esi), %%al\n"
+" movb %%al, (%%edi)\n"
+" incl %%edi\n"
+
+" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".L_copy_two:\n"
+" rep movsw\n"
+" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_check_dist_one:\n"
+" cmpl $1, %%ebp\n" /* if dist 1, is a memset */
+" jne .L_check_window\n"
+" cmpl %%edi, 20(%%esp)\n"
+" je .L_check_window\n" /* out == beg, if outside window */
+
+" movl 64(%%esp), %%ecx\n" /* ecx = len */
+" movb -1(%%edi), %%al\n"
+" movb %%al, %%ah\n"
+
+" sarl %%ecx\n"
+" jnc .L_set_two\n"
+" movb %%al, (%%edi)\n"
+" incl %%edi\n"
+
+".L_set_two:\n"
+" rep stosw\n"
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_length:\n"
+" testb $64, %%al\n"
+" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl 64(%%esp), %%eax\n" /* eax += len */
+" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/
+" jmp .L_dolen\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_dist:\n"
+" testb $64, %%al\n"
+" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl %%ebp, %%eax\n" /* eax += dist */
+" movl 36(%%esp), %%ecx\n" /* ecx = dcode */
+" movl (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/
+" jmp .L_dodist\n"
+
+".align 32,0x90\n"
+".L_clip_window:\n"
+" movl %%eax, %%ecx\n"
+" movl 48(%%esp), %%eax\n" /* eax = wsize */
+" negl %%ecx\n" /* nbytes = -nbytes */
+" movl 28(%%esp), %%esi\n" /* from = window */
+
+" cmpl %%ebp, %%eax\n"
+" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */
+
+" addl %%ebp, %%ecx\n" /* nbytes = dist - nbytes */
+" cmpl $0, 52(%%esp)\n"
+" jne .L_wrap_around_window\n" /* if (write != 0) */
+
+" subl %%ecx, %%eax\n"
+" addl %%eax, %%esi\n" /* from += wsize - nbytes */
+
+" movl 64(%%esp), %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_wrap_around_window:\n"
+" movl 52(%%esp), %%eax\n" /* eax = write */
+" cmpl %%eax, %%ecx\n"
+" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */
+
+" addl 48(%%esp), %%esi\n" /* from += wsize */
+" addl %%eax, %%esi\n" /* from += write */
+" subl %%ecx, %%esi\n" /* from -= nbytes */
+" subl %%eax, %%ecx\n" /* nbytes -= write */
+
+" movl 64(%%esp), %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl 28(%%esp), %%esi\n" /* from = window */
+" movl 52(%%esp), %%ecx\n" /* nbytes = write */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_contiguous_in_window:\n"
+" addl %%eax, %%esi\n"
+" subl %%ecx, %%esi\n" /* from += write - nbytes */
+
+" movl 64(%%esp), %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+" jmp .L_do_copy\n" /* if (nbytes >= len) */
+
+".align 32,0x90\n"
+".L_do_copy:\n"
+" movl %%eax, %%ecx\n"
+" rep movsb\n"
+
+" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".L_test_for_end_of_block:\n"
+" testb $32, %%al\n"
+" jz .L_invalid_literal_length_code\n"
+" movl $1, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_literal_length_code:\n"
+" movl $2, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_code:\n"
+" movl $3, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_too_far:\n"
+" movl 8(%%esp), %%esi\n"
+" movl $4, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_break_loop:\n"
+" movl $0, 72(%%esp)\n"
+
+".L_break_loop_with_status:\n"
+/* put in, out, bits, and hold back into ar and pop esp */
+" movl %%esi, 8(%%esp)\n" /* save in */
+" movl %%edi, 16(%%esp)\n" /* save out */
+" movl %%ebx, 44(%%esp)\n" /* save bits */
+" movl %%edx, 40(%%esp)\n" /* save hold */
+" movl 4(%%esp), %%ebp\n" /* restore esp, ebp */
+" movl (%%esp), %%esp\n"
+ :
+ : "m" (ar)
+ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi"
+ );
+#elif defined( _MSC_VER ) && ! defined( _M_AMD64 )
+ __asm {
+ lea eax, ar
+ mov [eax], esp /* save esp, ebp */
+ mov [eax+4], ebp
+ mov esp, eax
+ mov esi, [esp+8] /* esi = in */
+ mov edi, [esp+16] /* edi = out */
+ mov edx, [esp+40] /* edx = hold */
+ mov ebx, [esp+44] /* ebx = bits */
+ mov ebp, [esp+32] /* ebp = lcode */
+
+ cld
+ jmp L_do_loop
+
+ALIGN 4
+L_while_test:
+ cmp [esp+24], edi
+ jbe L_break_loop
+ cmp [esp+12], esi
+ jbe L_break_loop
+
+L_do_loop:
+ cmp bl, 15
+ ja L_get_length_code /* if (15 < bits) */
+
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+
+L_get_length_code:
+ mov eax, [esp+56] /* eax = lmask */
+ and eax, edx /* eax &= hold */
+ mov eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */
+
+L_dolen:
+ mov cl, ah /* cl = this.bits */
+ sub bl, ah /* bits -= this.bits */
+ shr edx, cl /* hold >>= this.bits */
+
+ test al, al
+ jnz L_test_for_length_base /* if (op != 0) 45.7% */
+
+ shr eax, 16 /* output this.val char */
+ stosb
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_length_base:
+ mov ecx, eax /* len = this */
+ shr ecx, 16 /* len = this.val */
+ mov [esp+64], ecx /* save len */
+ mov cl, al
+
+ test al, 16
+ jz L_test_for_second_level_length /* if ((op & 16) == 0) 8% */
+ and cl, 15 /* op &= 15 */
+ jz L_decode_distance /* if (!op) */
+ cmp bl, cl
+ jae L_add_bits_to_len /* if (op <= bits) */
+
+ mov ch, cl /* stash op in ch, freeing cl */
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+ mov cl, ch /* move op back to ecx */
+
+L_add_bits_to_len:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx /* eax &= hold */
+ shr edx, cl
+ add [esp+64], eax /* len += hold & mask[op] */
+
+L_decode_distance:
+ cmp bl, 15
+ ja L_get_distance_code /* if (15 < bits) */
+
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+
+L_get_distance_code:
+ mov eax, [esp+60] /* eax = dmask */
+ mov ecx, [esp+36] /* ecx = dcode */
+ and eax, edx /* eax &= hold */
+ mov eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */
+
+L_dodist:
+ mov ebp, eax /* dist = this */
+ shr ebp, 16 /* dist = this.val */
+ mov cl, ah
+ sub bl, ah /* bits -= this.bits */
+ shr edx, cl /* hold >>= this.bits */
+ mov cl, al /* cl = this.op */
+
+ test al, 16 /* if ((op & 16) == 0) */
+ jz L_test_for_second_level_dist
+ and cl, 15 /* op &= 15 */
+ jz L_check_dist_one
+ cmp bl, cl
+ jae L_add_bits_to_dist /* if (op <= bits) 97.6% */
+
+ mov ch, cl /* stash op in ch, freeing cl */
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+ mov cl, ch /* move op back to ecx */
+
+L_add_bits_to_dist:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax /* (1 << op) - 1 */
+ and eax, edx /* eax &= hold */
+ shr edx, cl
+ add ebp, eax /* dist += hold & ((1 << op) - 1) */
+
+L_check_window:
+ mov [esp+8], esi /* save in so from can use it's reg */
+ mov eax, edi
+ sub eax, [esp+20] /* nbytes = out - beg */
+
+ cmp eax, ebp
+ jb L_clip_window /* if (dist > nbytes) 4.2% */
+
+ mov ecx, [esp+64] /* ecx = len */
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+
+ sar ecx, 1
+ jnc L_copy_two
+
+ rep movsw
+ mov al, [esi]
+ mov [edi], al
+ inc edi
+
+ mov esi, [esp+8] /* move in back to %esi, toss from */
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+L_copy_two:
+ rep movsw
+ mov esi, [esp+8] /* move in back to %esi, toss from */
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+ALIGN 4
+L_check_dist_one:
+ cmp ebp, 1 /* if dist 1, is a memset */
+ jne L_check_window
+ cmp [esp+20], edi
+ je L_check_window /* out == beg, if outside window */
+
+ mov ecx, [esp+64] /* ecx = len */
+ mov al, [edi-1]
+ mov ah, al
+
+ sar ecx, 1
+ jnc L_set_two
+ mov [edi], al /* memset out with from[-1] */
+ inc edi
+
+L_set_two:
+ rep stosw
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_second_level_length:
+ test al, 64
+ jnz L_test_for_end_of_block /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx /* eax &= hold */
+ add eax, [esp+64] /* eax += len */
+ mov eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/
+ jmp L_dolen
+
+ALIGN 4
+L_test_for_second_level_dist:
+ test al, 64
+ jnz L_invalid_distance_code /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx /* eax &= hold */
+ add eax, ebp /* eax += dist */
+ mov ecx, [esp+36] /* ecx = dcode */
+ mov eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/
+ jmp L_dodist
+
+ALIGN 4
+L_clip_window:
+ mov ecx, eax
+ mov eax, [esp+48] /* eax = wsize */
+ neg ecx /* nbytes = -nbytes */
+ mov esi, [esp+28] /* from = window */
+
+ cmp eax, ebp
+ jb L_invalid_distance_too_far /* if (dist > wsize) */
+
+ add ecx, ebp /* nbytes = dist - nbytes */
+ cmp dword ptr [esp+52], 0
+ jne L_wrap_around_window /* if (write != 0) */
+
+ sub eax, ecx
+ add esi, eax /* from += wsize - nbytes */
+
+ mov eax, [esp+64] /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_wrap_around_window:
+ mov eax, [esp+52] /* eax = write */
+ cmp ecx, eax
+ jbe L_contiguous_in_window /* if (write >= nbytes) */
+
+ add esi, [esp+48] /* from += wsize */
+ add esi, eax /* from += write */
+ sub esi, ecx /* from -= nbytes */
+ sub ecx, eax /* nbytes -= write */
+
+ mov eax, [esp+64] /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, [esp+28] /* from = window */
+ mov ecx, [esp+52] /* nbytes = write */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_contiguous_in_window:
+ add esi, eax
+ sub esi, ecx /* from += write - nbytes */
+
+ mov eax, [esp+64] /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_do_copy:
+ mov ecx, eax
+ rep movsb
+
+ mov esi, [esp+8] /* move in back to %esi, toss from */
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+L_test_for_end_of_block:
+ test al, 32
+ jz L_invalid_literal_length_code
+ mov dword ptr [esp+72], 1
+ jmp L_break_loop_with_status
+
+L_invalid_literal_length_code:
+ mov dword ptr [esp+72], 2
+ jmp L_break_loop_with_status
+
+L_invalid_distance_code:
+ mov dword ptr [esp+72], 3
+ jmp L_break_loop_with_status
+
+L_invalid_distance_too_far:
+ mov esi, [esp+4]
+ mov dword ptr [esp+72], 4
+ jmp L_break_loop_with_status
+
+L_break_loop:
+ mov dword ptr [esp+72], 0
+
+L_break_loop_with_status:
+/* put in, out, bits, and hold back into ar and pop esp */
+ mov [esp+8], esi /* save in */
+ mov [esp+16], edi /* save out */
+ mov [esp+44], ebx /* save bits */
+ mov [esp+40], edx /* save hold */
+ mov ebp, [esp+4] /* restore esp, ebp */
+ mov esp, [esp]
+ }
+#else
+#error "x86 architecture not defined"
+#endif
+
+ if (ar.status > 1) {
+ if (ar.status == 2)
+ strm->msg = "invalid literal/length code";
+ else if (ar.status == 3)
+ strm->msg = "invalid distance code";
+ else
+ strm->msg = "invalid distance too far back";
+ state->mode = BAD;
+ }
+ else if ( ar.status == 1 ) {
+ state->mode = TYPE;
+ }
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ ar.len = ar.bits >> 3;
+ ar.in -= ar.len;
+ ar.bits -= ar.len << 3;
+ ar.hold &= (1U << ar.bits) - 1;
+
+ /* update state and return */
+ strm->next_in = ar.in;
+ strm->next_out = ar.out;
+ strm->avail_in = (unsigned)(ar.in < ar.last ?
+ PAD_AVAIL_IN + (ar.last - ar.in) :
+ PAD_AVAIL_IN - (ar.in - ar.last));
+ strm->avail_out = (unsigned)(ar.out < ar.end ?
+ PAD_AVAIL_OUT + (ar.end - ar.out) :
+ PAD_AVAIL_OUT - (ar.out - ar.end));
+ state->hold = ar.hold;
+ state->bits = ar.bits;
+ return;
+}
+
diff --git a/zlib/contrib/inflate86/inffast.S b/zlib/contrib/inflate86/inffast.S
new file mode 100644
index 0000000..2245a29
--- /dev/null
+++ b/zlib/contrib/inflate86/inffast.S
@@ -0,0 +1,1368 @@
+/*
+ * inffast.S is a hand tuned assembler version of:
+ *
+ * inffast.c -- fast decoding
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Copyright (C) 2003 Chris Anderson <christop@charm.net>
+ * Please use the copyright conditions above.
+ *
+ * This version (Jan-23-2003) of inflate_fast was coded and tested under
+ * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution. On that
+ * machine, I found that gzip style archives decompressed about 20% faster than
+ * the gcc-3.2 -O3 -fomit-frame-pointer compiled version. Your results will
+ * depend on how large of a buffer is used for z_stream.next_in & next_out
+ * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in
+ * stream processing I/O and crc32/addler32. In my case, this routine used
+ * 70% of the cpu time and crc32 used 20%.
+ *
+ * I am confident that this version will work in the general case, but I have
+ * not tested a wide variety of datasets or a wide variety of platforms.
+ *
+ * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating.
+ * It should be a runtime flag instead of compile time flag...
+ *
+ * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction.
+ * With -DUSE_MMX, only MMX code is compiled. With -DNO_MMX, only non-MMX code
+ * is compiled. Without either option, runtime detection is enabled. Runtime
+ * detection should work on all modern cpus and the recomended algorithm (flip
+ * ID bit on eflags and then use the cpuid instruction) is used in many
+ * multimedia applications. Tested under win2k with gcc-2.95 and gas-2.12
+ * distributed with cygwin3. Compiling with gcc-2.95 -c inffast.S -o
+ * inffast.obj generates a COFF object which can then be linked with MSVC++
+ * compiled code. Tested under FreeBSD 4.7 with gcc-2.95.
+ *
+ * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and
+ * slower than compiler generated code). Adjusted cpuid check to use the MMX
+ * code only for Pentiums < P4 until I have more data on the P4. Speed
+ * improvment is only about 15% on the Athlon when compared with code generated
+ * with MSVC++. Not sure yet, but I think the P4 will also be slower using the
+ * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and
+ * have less latency than MMX ops. Added code to buffer the last 11 bytes of
+ * the input stream since the MMX code grabs bits in chunks of 32, which
+ * differs from the inffast.c algorithm. I don't think there would have been
+ * read overruns where a page boundary was crossed (a segfault), but there
+ * could have been overruns when next_in ends on unaligned memory (unintialized
+ * memory read).
+ *
+ * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX. I created a C
+ * version of the non-MMX code so that it doesn't depend on zstrm and zstate
+ * structure offsets which are hard coded in this file. This was last tested
+ * with zlib-1.2.0 which is currently in beta testing, newer versions of this
+ * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and
+ * http://www.charm.net/~christop/zlib/
+ */
+
+
+/*
+ * if you have underscore linking problems (_inflate_fast undefined), try
+ * using -DGAS_COFF
+ */
+#if ! defined( GAS_COFF ) && ! defined( GAS_ELF )
+
+#if defined( WIN32 ) || defined( __CYGWIN__ )
+#define GAS_COFF /* windows object format */
+#else
+#define GAS_ELF
+#endif
+
+#endif /* ! GAS_COFF && ! GAS_ELF */
+
+
+#if defined( GAS_COFF )
+
+/* coff externals have underscores */
+#define inflate_fast _inflate_fast
+#define inflate_fast_use_mmx _inflate_fast_use_mmx
+
+#endif /* GAS_COFF */
+
+
+.file "inffast.S"
+
+.globl inflate_fast
+
+.text
+.align 4,0
+.L_invalid_literal_length_code_msg:
+.string "invalid literal/length code"
+
+.align 4,0
+.L_invalid_distance_code_msg:
+.string "invalid distance code"
+
+.align 4,0
+.L_invalid_distance_too_far_msg:
+.string "invalid distance too far back"
+
+#if ! defined( NO_MMX )
+.align 4,0
+.L_mask: /* mask[N] = ( 1 << N ) - 1 */
+.long 0
+.long 1
+.long 3
+.long 7
+.long 15
+.long 31
+.long 63
+.long 127
+.long 255
+.long 511
+.long 1023
+.long 2047
+.long 4095
+.long 8191
+.long 16383
+.long 32767
+.long 65535
+.long 131071
+.long 262143
+.long 524287
+.long 1048575
+.long 2097151
+.long 4194303
+.long 8388607
+.long 16777215
+.long 33554431
+.long 67108863
+.long 134217727
+.long 268435455
+.long 536870911
+.long 1073741823
+.long 2147483647
+.long 4294967295
+#endif /* NO_MMX */
+
+.text
+
+/*
+ * struct z_stream offsets, in zlib.h
+ */
+#define next_in_strm 0 /* strm->next_in */
+#define avail_in_strm 4 /* strm->avail_in */
+#define next_out_strm 12 /* strm->next_out */
+#define avail_out_strm 16 /* strm->avail_out */
+#define msg_strm 24 /* strm->msg */
+#define state_strm 28 /* strm->state */
+
+/*
+ * struct inflate_state offsets, in inflate.h
+ */
+#define mode_state 0 /* state->mode */
+#define wsize_state 32 /* state->wsize */
+#define write_state 40 /* state->write */
+#define window_state 44 /* state->window */
+#define hold_state 48 /* state->hold */
+#define bits_state 52 /* state->bits */
+#define lencode_state 68 /* state->lencode */
+#define distcode_state 72 /* state->distcode */
+#define lenbits_state 76 /* state->lenbits */
+#define distbits_state 80 /* state->distbits */
+
+/*
+ * inflate_fast's activation record
+ */
+#define local_var_size 64 /* how much local space for vars */
+#define strm_sp 88 /* first arg: z_stream * (local_var_size + 24) */
+#define start_sp 92 /* second arg: unsigned int (local_var_size + 28) */
+
+/*
+ * offsets for local vars on stack
+ */
+#define out 60 /* unsigned char* */
+#define window 56 /* unsigned char* */
+#define wsize 52 /* unsigned int */
+#define write 48 /* unsigned int */
+#define in 44 /* unsigned char* */
+#define beg 40 /* unsigned char* */
+#define buf 28 /* char[ 12 ] */
+#define len 24 /* unsigned int */
+#define last 20 /* unsigned char* */
+#define end 16 /* unsigned char* */
+#define dcode 12 /* code* */
+#define lcode 8 /* code* */
+#define dmask 4 /* unsigned int */
+#define lmask 0 /* unsigned int */
+
+/*
+ * typedef enum inflate_mode consts, in inflate.h
+ */
+#define INFLATE_MODE_TYPE 11 /* state->mode flags enum-ed in inflate.h */
+#define INFLATE_MODE_BAD 26
+
+
+#if ! defined( USE_MMX ) && ! defined( NO_MMX )
+
+#define RUN_TIME_MMX
+
+#define CHECK_MMX 1
+#define DO_USE_MMX 2
+#define DONT_USE_MMX 3
+
+.globl inflate_fast_use_mmx
+
+.data
+
+.align 4,0
+inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */
+.long CHECK_MMX
+
+#if defined( GAS_ELF )
+/* elf info */
+.type inflate_fast_use_mmx,@object
+.size inflate_fast_use_mmx,4
+#endif
+
+#endif /* RUN_TIME_MMX */
+
+#if defined( GAS_COFF )
+/* coff info: scl 2 = extern, type 32 = function */
+.def inflate_fast; .scl 2; .type 32; .endef
+#endif
+
+.text
+
+.align 32,0x90
+inflate_fast:
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ pushl %ebx
+ pushf /* save eflags (strm_sp, state_sp assumes this is 32 bits) */
+ subl $local_var_size, %esp
+ cld
+
+#define strm_r %esi
+#define state_r %edi
+
+ movl strm_sp(%esp), strm_r
+ movl state_strm(strm_r), state_r
+
+ /* in = strm->next_in;
+ * out = strm->next_out;
+ * last = in + strm->avail_in - 11;
+ * beg = out - (start - strm->avail_out);
+ * end = out + (strm->avail_out - 257);
+ */
+ movl avail_in_strm(strm_r), %edx
+ movl next_in_strm(strm_r), %eax
+
+ addl %eax, %edx /* avail_in += next_in */
+ subl $11, %edx /* avail_in -= 11 */
+
+ movl %eax, in(%esp)
+ movl %edx, last(%esp)
+
+ movl start_sp(%esp), %ebp
+ movl avail_out_strm(strm_r), %ecx
+ movl next_out_strm(strm_r), %ebx
+
+ subl %ecx, %ebp /* start -= avail_out */
+ negl %ebp /* start = -start */
+ addl %ebx, %ebp /* start += next_out */
+
+ subl $257, %ecx /* avail_out -= 257 */
+ addl %ebx, %ecx /* avail_out += out */
+
+ movl %ebx, out(%esp)
+ movl %ebp, beg(%esp)
+ movl %ecx, end(%esp)
+
+ /* wsize = state->wsize;
+ * write = state->write;
+ * window = state->window;
+ * hold = state->hold;
+ * bits = state->bits;
+ * lcode = state->lencode;
+ * dcode = state->distcode;
+ * lmask = ( 1 << state->lenbits ) - 1;
+ * dmask = ( 1 << state->distbits ) - 1;
+ */
+
+ movl lencode_state(state_r), %eax
+ movl distcode_state(state_r), %ecx
+
+ movl %eax, lcode(%esp)
+ movl %ecx, dcode(%esp)
+
+ movl $1, %eax
+ movl lenbits_state(state_r), %ecx
+ shll %cl, %eax
+ decl %eax
+ movl %eax, lmask(%esp)
+
+ movl $1, %eax
+ movl distbits_state(state_r), %ecx
+ shll %cl, %eax
+ decl %eax
+ movl %eax, dmask(%esp)
+
+ movl wsize_state(state_r), %eax
+ movl write_state(state_r), %ecx
+ movl window_state(state_r), %edx
+
+ movl %eax, wsize(%esp)
+ movl %ecx, write(%esp)
+ movl %edx, window(%esp)
+
+ movl hold_state(state_r), %ebp
+ movl bits_state(state_r), %ebx
+
+#undef strm_r
+#undef state_r
+
+#define in_r %esi
+#define from_r %esi
+#define out_r %edi
+
+ movl in(%esp), in_r
+ movl last(%esp), %ecx
+ cmpl in_r, %ecx
+ ja .L_align_long /* if in < last */
+
+ addl $11, %ecx /* ecx = &in[ avail_in ] */
+ subl in_r, %ecx /* ecx = avail_in */
+ movl $12, %eax
+ subl %ecx, %eax /* eax = 12 - avail_in */
+ leal buf(%esp), %edi
+ rep movsb /* memcpy( buf, in, avail_in ) */
+ movl %eax, %ecx
+ xorl %eax, %eax
+ rep stosb /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */
+ leal buf(%esp), in_r /* in = buf */
+ movl in_r, last(%esp) /* last = in, do just one iteration */
+ jmp .L_is_aligned
+
+ /* align in_r on long boundary */
+.L_align_long:
+ testl $3, in_r
+ jz .L_is_aligned
+ xorl %eax, %eax
+ movb (in_r), %al
+ incl in_r
+ movl %ebx, %ecx
+ addl $8, %ebx
+ shll %cl, %eax
+ orl %eax, %ebp
+ jmp .L_align_long
+
+.L_is_aligned:
+ movl out(%esp), out_r
+
+#if defined( NO_MMX )
+ jmp .L_do_loop
+#endif
+
+#if defined( USE_MMX )
+ jmp .L_init_mmx
+#endif
+
+/*** Runtime MMX check ***/
+
+#if defined( RUN_TIME_MMX )
+.L_check_mmx:
+ cmpl $DO_USE_MMX, inflate_fast_use_mmx
+ je .L_init_mmx
+ ja .L_do_loop /* > 2 */
+
+ pushl %eax
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushf
+ movl (%esp), %eax /* copy eflags to eax */
+ xorl $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21)
+ * to see if cpu supports cpuid...
+ * ID bit method not supported by NexGen but
+ * bios may load a cpuid instruction and
+ * cpuid may be disabled on Cyrix 5-6x86 */
+ popf
+ pushf
+ popl %edx /* copy new eflags to edx */
+ xorl %eax, %edx /* test if ID bit is flipped */
+ jz .L_dont_use_mmx /* not flipped if zero */
+ xorl %eax, %eax
+ cpuid
+ cmpl $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */
+ jne .L_dont_use_mmx
+ cmpl $0x6c65746e, %ecx
+ jne .L_dont_use_mmx
+ cmpl $0x49656e69, %edx
+ jne .L_dont_use_mmx
+ movl $1, %eax
+ cpuid /* get cpu features */
+ shrl $8, %eax
+ andl $15, %eax
+ cmpl $6, %eax /* check for Pentium family, is 0xf for P4 */
+ jne .L_dont_use_mmx
+ testl $0x800000, %edx /* test if MMX feature is set (bit 23) */
+ jnz .L_use_mmx
+ jmp .L_dont_use_mmx
+.L_use_mmx:
+ movl $DO_USE_MMX, inflate_fast_use_mmx
+ jmp .L_check_mmx_pop
+.L_dont_use_mmx:
+ movl $DONT_USE_MMX, inflate_fast_use_mmx
+.L_check_mmx_pop:
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ jmp .L_check_mmx
+#endif
+
+
+/*** Non-MMX code ***/
+
+#if defined ( NO_MMX ) || defined( RUN_TIME_MMX )
+
+#define hold_r %ebp
+#define bits_r %bl
+#define bitslong_r %ebx
+
+.align 32,0x90
+.L_while_test:
+ /* while (in < last && out < end)
+ */
+ cmpl out_r, end(%esp)
+ jbe .L_break_loop /* if (out >= end) */
+
+ cmpl in_r, last(%esp)
+ jbe .L_break_loop
+
+.L_do_loop:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
+ *
+ * do {
+ * if (bits < 15) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * this = lcode[hold & lmask]
+ */
+ cmpb $15, bits_r
+ ja .L_get_length_code /* if (15 < bits) */
+
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+
+.L_get_length_code:
+ movl lmask(%esp), %edx /* edx = lmask */
+ movl lcode(%esp), %ecx /* ecx = lcode */
+ andl hold_r, %edx /* edx &= hold */
+ movl (%ecx,%edx,4), %eax /* eax = lcode[hold & lmask] */
+
+.L_dolen:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
+ *
+ * dolen:
+ * bits -= this.bits;
+ * hold >>= this.bits
+ */
+ movb %ah, %cl /* cl = this.bits */
+ subb %ah, bits_r /* bits -= this.bits */
+ shrl %cl, hold_r /* hold >>= this.bits */
+
+ /* check if op is a literal
+ * if (op == 0) {
+ * PUP(out) = this.val;
+ * }
+ */
+ testb %al, %al
+ jnz .L_test_for_length_base /* if (op != 0) 45.7% */
+
+ shrl $16, %eax /* output this.val char */
+ stosb
+ jmp .L_while_test
+
+.L_test_for_length_base:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len
+ *
+ * else if (op & 16) {
+ * len = this.val
+ * op &= 15
+ * if (op) {
+ * if (op > bits) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * len += hold & mask[op];
+ * bits -= op;
+ * hold >>= op;
+ * }
+ */
+#define len_r %edx
+ movl %eax, len_r /* len = this */
+ shrl $16, len_r /* len = this.val */
+ movb %al, %cl
+
+ testb $16, %al
+ jz .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */
+ andb $15, %cl /* op &= 15 */
+ jz .L_save_len /* if (!op) */
+ cmpb %cl, bits_r
+ jae .L_add_bits_to_len /* if (op <= bits) */
+
+ movb %cl, %ch /* stash op in ch, freeing cl */
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+ movb %ch, %cl /* move op back to ecx */
+
+.L_add_bits_to_len:
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax
+ subb %cl, bits_r
+ andl hold_r, %eax /* eax &= hold */
+ shrl %cl, hold_r
+ addl %eax, len_r /* len += hold & mask[op] */
+
+.L_save_len:
+ movl len_r, len(%esp) /* save len */
+#undef len_r
+
+.L_decode_distance:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ *
+ * if (bits < 15) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * this = dcode[hold & dmask];
+ * dodist:
+ * bits -= this.bits;
+ * hold >>= this.bits;
+ * op = this.op;
+ */
+
+ cmpb $15, bits_r
+ ja .L_get_distance_code /* if (15 < bits) */
+
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+
+.L_get_distance_code:
+ movl dmask(%esp), %edx /* edx = dmask */
+ movl dcode(%esp), %ecx /* ecx = dcode */
+ andl hold_r, %edx /* edx &= hold */
+ movl (%ecx,%edx,4), %eax /* eax = dcode[hold & dmask] */
+
+#define dist_r %edx
+.L_dodist:
+ movl %eax, dist_r /* dist = this */
+ shrl $16, dist_r /* dist = this.val */
+ movb %ah, %cl
+ subb %ah, bits_r /* bits -= this.bits */
+ shrl %cl, hold_r /* hold >>= this.bits */
+
+ /* if (op & 16) {
+ * dist = this.val
+ * op &= 15
+ * if (op > bits) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * dist += hold & mask[op];
+ * bits -= op;
+ * hold >>= op;
+ */
+ movb %al, %cl /* cl = this.op */
+
+ testb $16, %al /* if ((op & 16) == 0) */
+ jz .L_test_for_second_level_dist
+ andb $15, %cl /* op &= 15 */
+ jz .L_check_dist_one
+ cmpb %cl, bits_r
+ jae .L_add_bits_to_dist /* if (op <= bits) 97.6% */
+
+ movb %cl, %ch /* stash op in ch, freeing cl */
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+ movb %ch, %cl /* move op back to ecx */
+
+.L_add_bits_to_dist:
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax /* (1 << op) - 1 */
+ subb %cl, bits_r
+ andl hold_r, %eax /* eax &= hold */
+ shrl %cl, hold_r
+ addl %eax, dist_r /* dist += hold & ((1 << op) - 1) */
+ jmp .L_check_window
+
+.L_check_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes
+ *
+ * nbytes = out - beg;
+ * if (dist <= nbytes) {
+ * from = out - dist;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--len > 0) {
+ * }
+ */
+
+ movl in_r, in(%esp) /* save in so from can use it's reg */
+ movl out_r, %eax
+ subl beg(%esp), %eax /* nbytes = out - beg */
+
+ cmpl dist_r, %eax
+ jb .L_clip_window /* if (dist > nbytes) 4.2% */
+
+ movl len(%esp), %ecx
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+ subl $3, %ecx
+ movb (from_r), %al
+ movb %al, (out_r)
+ movb 1(from_r), %al
+ movb 2(from_r), %dl
+ addl $3, from_r
+ movb %al, 1(out_r)
+ movb %dl, 2(out_r)
+ addl $3, out_r
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ jmp .L_while_test
+
+.align 16,0x90
+.L_check_dist_one:
+ cmpl $1, dist_r
+ jne .L_check_window
+ cmpl out_r, beg(%esp)
+ je .L_check_window
+
+ decl out_r
+ movl len(%esp), %ecx
+ movb (out_r), %al
+ subl $3, %ecx
+
+ movb %al, 1(out_r)
+ movb %al, 2(out_r)
+ movb %al, 3(out_r)
+ addl $4, out_r
+ rep stosb
+
+ jmp .L_while_test
+
+.align 16,0x90
+.L_test_for_second_level_length:
+ /* else if ((op & 64) == 0) {
+ * this = lcode[this.val + (hold & mask[op])];
+ * }
+ */
+ testb $64, %al
+ jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */
+
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax
+ andl hold_r, %eax /* eax &= hold */
+ addl %edx, %eax /* eax += this.val */
+ movl lcode(%esp), %edx /* edx = lcode */
+ movl (%edx,%eax,4), %eax /* eax = lcode[val + (hold&mask[op])] */
+ jmp .L_dolen
+
+.align 16,0x90
+.L_test_for_second_level_dist:
+ /* else if ((op & 64) == 0) {
+ * this = dcode[this.val + (hold & mask[op])];
+ * }
+ */
+ testb $64, %al
+ jnz .L_invalid_distance_code /* if ((op & 64) != 0) */
+
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax
+ andl hold_r, %eax /* eax &= hold */
+ addl %edx, %eax /* eax += this.val */
+ movl dcode(%esp), %edx /* edx = dcode */
+ movl (%edx,%eax,4), %eax /* eax = dcode[val + (hold&mask[op])] */
+ jmp .L_dodist
+
+.align 16,0x90
+.L_clip_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes
+ *
+ * else {
+ * if (dist > wsize) {
+ * invalid distance
+ * }
+ * from = window;
+ * nbytes = dist - nbytes;
+ * if (write == 0) {
+ * from += wsize - nbytes;
+ */
+#define nbytes_r %ecx
+ movl %eax, nbytes_r
+ movl wsize(%esp), %eax /* prepare for dist compare */
+ negl nbytes_r /* nbytes = -nbytes */
+ movl window(%esp), from_r /* from = window */
+
+ cmpl dist_r, %eax
+ jb .L_invalid_distance_too_far /* if (dist > wsize) */
+
+ addl dist_r, nbytes_r /* nbytes = dist - nbytes */
+ cmpl $0, write(%esp)
+ jne .L_wrap_around_window /* if (write != 0) */
+
+ subl nbytes_r, %eax
+ addl %eax, from_r /* from += wsize - nbytes */
+
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes, %eax = len
+ *
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--nbytes);
+ * from = out - dist;
+ * }
+ * }
+ */
+#define len_r %eax
+ movl len(%esp), len_r
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1
+
+.L_wrap_around_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes, %eax = write, %eax = len
+ *
+ * else if (write < nbytes) {
+ * from += wsize + write - nbytes;
+ * nbytes -= write;
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--nbytes);
+ * from = window;
+ * nbytes = write;
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while(--nbytes);
+ * from = out - dist;
+ * }
+ * }
+ * }
+ */
+#define write_r %eax
+ movl write(%esp), write_r
+ cmpl write_r, nbytes_r
+ jbe .L_contiguous_in_window /* if (write >= nbytes) */
+
+ addl wsize(%esp), from_r
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += wsize + write - nbytes */
+ subl write_r, nbytes_r /* nbytes -= write */
+#undef write_r
+
+ movl len(%esp), len_r
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl window(%esp), from_r /* from = window */
+ movl write(%esp), nbytes_r /* nbytes = write */
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1
+
+.L_contiguous_in_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes, %eax = write, %eax = len
+ *
+ * else {
+ * from += write - nbytes;
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--nbytes);
+ * from = out - dist;
+ * }
+ * }
+ */
+#define write_r %eax
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += write - nbytes */
+#undef write_r
+
+ movl len(%esp), len_r
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+.L_do_copy1:
+ /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out
+ * %eax = len
+ *
+ * while (len > 0) {
+ * PUP(out) = PUP(from);
+ * len--;
+ * }
+ * }
+ * } while (in < last && out < end);
+ */
+#undef nbytes_r
+#define in_r %esi
+ movl len_r, %ecx
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ jmp .L_while_test
+
+#undef len_r
+#undef dist_r
+
+#endif /* NO_MMX || RUN_TIME_MMX */
+
+
+/*** MMX code ***/
+
+#if defined( USE_MMX ) || defined( RUN_TIME_MMX )
+
+.align 32,0x90
+.L_init_mmx:
+ emms
+
+#undef bits_r
+#undef bitslong_r
+#define bitslong_r %ebp
+#define hold_mm %mm0
+ movd %ebp, hold_mm
+ movl %ebx, bitslong_r
+
+#define used_mm %mm1
+#define dmask2_mm %mm2
+#define lmask2_mm %mm3
+#define lmask_mm %mm4
+#define dmask_mm %mm5
+#define tmp_mm %mm6
+
+ movd lmask(%esp), lmask_mm
+ movq lmask_mm, lmask2_mm
+ movd dmask(%esp), dmask_mm
+ movq dmask_mm, dmask2_mm
+ pxor used_mm, used_mm
+ movl lcode(%esp), %ebx /* ebx = lcode */
+ jmp .L_do_loop_mmx
+
+.align 32,0x90
+.L_while_test_mmx:
+ /* while (in < last && out < end)
+ */
+ cmpl out_r, end(%esp)
+ jbe .L_break_loop /* if (out >= end) */
+
+ cmpl in_r, last(%esp)
+ jbe .L_break_loop
+
+.L_do_loop_mmx:
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+
+ cmpl $32, bitslong_r
+ ja .L_get_length_code_mmx /* if (32 < bits) */
+
+ movd bitslong_r, tmp_mm
+ movd (in_r), %mm7
+ addl $4, in_r
+ psllq tmp_mm, %mm7
+ addl $32, bitslong_r
+ por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */
+
+.L_get_length_code_mmx:
+ pand hold_mm, lmask_mm
+ movd lmask_mm, %eax
+ movq lmask2_mm, lmask_mm
+ movl (%ebx,%eax,4), %eax /* eax = lcode[hold & lmask] */
+
+.L_dolen_mmx:
+ movzbl %ah, %ecx /* ecx = this.bits */
+ movd %ecx, used_mm
+ subl %ecx, bitslong_r /* bits -= this.bits */
+
+ testb %al, %al
+ jnz .L_test_for_length_base_mmx /* if (op != 0) 45.7% */
+
+ shrl $16, %eax /* output this.val char */
+ stosb
+ jmp .L_while_test_mmx
+
+.L_test_for_length_base_mmx:
+#define len_r %edx
+ movl %eax, len_r /* len = this */
+ shrl $16, len_r /* len = this.val */
+
+ testb $16, %al
+ jz .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */
+ andl $15, %eax /* op &= 15 */
+ jz .L_decode_distance_mmx /* if (!op) */
+
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd %eax, used_mm
+ movd hold_mm, %ecx
+ subl %eax, bitslong_r
+ andl .L_mask(,%eax,4), %ecx
+ addl %ecx, len_r /* len += hold & mask[op] */
+
+.L_decode_distance_mmx:
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+
+ cmpl $32, bitslong_r
+ ja .L_get_dist_code_mmx /* if (32 < bits) */
+
+ movd bitslong_r, tmp_mm
+ movd (in_r), %mm7
+ addl $4, in_r
+ psllq tmp_mm, %mm7
+ addl $32, bitslong_r
+ por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */
+
+.L_get_dist_code_mmx:
+ movl dcode(%esp), %ebx /* ebx = dcode */
+ pand hold_mm, dmask_mm
+ movd dmask_mm, %eax
+ movq dmask2_mm, dmask_mm
+ movl (%ebx,%eax,4), %eax /* eax = dcode[hold & lmask] */
+
+.L_dodist_mmx:
+#define dist_r %ebx
+ movzbl %ah, %ecx /* ecx = this.bits */
+ movl %eax, dist_r
+ shrl $16, dist_r /* dist = this.val */
+ subl %ecx, bitslong_r /* bits -= this.bits */
+ movd %ecx, used_mm
+
+ testb $16, %al /* if ((op & 16) == 0) */
+ jz .L_test_for_second_level_dist_mmx
+ andl $15, %eax /* op &= 15 */
+ jz .L_check_dist_one_mmx
+
+.L_add_bits_to_dist_mmx:
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd %eax, used_mm /* save bit length of current op */
+ movd hold_mm, %ecx /* get the next bits on input stream */
+ subl %eax, bitslong_r /* bits -= op bits */
+ andl .L_mask(,%eax,4), %ecx /* ecx = hold & mask[op] */
+ addl %ecx, dist_r /* dist += hold & mask[op] */
+
+.L_check_window_mmx:
+ movl in_r, in(%esp) /* save in so from can use it's reg */
+ movl out_r, %eax
+ subl beg(%esp), %eax /* nbytes = out - beg */
+
+ cmpl dist_r, %eax
+ jb .L_clip_window_mmx /* if (dist > nbytes) 4.2% */
+
+ movl len_r, %ecx
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+ subl $3, %ecx
+ movb (from_r), %al
+ movb %al, (out_r)
+ movb 1(from_r), %al
+ movb 2(from_r), %dl
+ addl $3, from_r
+ movb %al, 1(out_r)
+ movb %dl, 2(out_r)
+ addl $3, out_r
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */
+ jmp .L_while_test_mmx
+
+.align 16,0x90
+.L_check_dist_one_mmx:
+ cmpl $1, dist_r
+ jne .L_check_window_mmx
+ cmpl out_r, beg(%esp)
+ je .L_check_window_mmx
+
+ decl out_r
+ movl len_r, %ecx
+ movb (out_r), %al
+ subl $3, %ecx
+
+ movb %al, 1(out_r)
+ movb %al, 2(out_r)
+ movb %al, 3(out_r)
+ addl $4, out_r
+ rep stosb
+
+ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */
+ jmp .L_while_test_mmx
+
+.align 16,0x90
+.L_test_for_second_level_length_mmx:
+ testb $64, %al
+ jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */
+
+ andl $15, %eax
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd hold_mm, %ecx
+ andl .L_mask(,%eax,4), %ecx
+ addl len_r, %ecx
+ movl (%ebx,%ecx,4), %eax /* eax = lcode[hold & lmask] */
+ jmp .L_dolen_mmx
+
+.align 16,0x90
+.L_test_for_second_level_dist_mmx:
+ testb $64, %al
+ jnz .L_invalid_distance_code /* if ((op & 64) != 0) */
+
+ andl $15, %eax
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd hold_mm, %ecx
+ andl .L_mask(,%eax,4), %ecx
+ movl dcode(%esp), %eax /* ecx = dcode */
+ addl dist_r, %ecx
+ movl (%eax,%ecx,4), %eax /* eax = lcode[hold & lmask] */
+ jmp .L_dodist_mmx
+
+.align 16,0x90
+.L_clip_window_mmx:
+#define nbytes_r %ecx
+ movl %eax, nbytes_r
+ movl wsize(%esp), %eax /* prepare for dist compare */
+ negl nbytes_r /* nbytes = -nbytes */
+ movl window(%esp), from_r /* from = window */
+
+ cmpl dist_r, %eax
+ jb .L_invalid_distance_too_far /* if (dist > wsize) */
+
+ addl dist_r, nbytes_r /* nbytes = dist - nbytes */
+ cmpl $0, write(%esp)
+ jne .L_wrap_around_window_mmx /* if (write != 0) */
+
+ subl nbytes_r, %eax
+ addl %eax, from_r /* from += wsize - nbytes */
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1_mmx
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1_mmx
+
+.L_wrap_around_window_mmx:
+#define write_r %eax
+ movl write(%esp), write_r
+ cmpl write_r, nbytes_r
+ jbe .L_contiguous_in_window_mmx /* if (write >= nbytes) */
+
+ addl wsize(%esp), from_r
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += wsize + write - nbytes */
+ subl write_r, nbytes_r /* nbytes -= write */
+#undef write_r
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl window(%esp), from_r /* from = window */
+ movl write(%esp), nbytes_r /* nbytes = write */
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1_mmx
+
+.L_contiguous_in_window_mmx:
+#define write_r %eax
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += write - nbytes */
+#undef write_r
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+.L_do_copy1_mmx:
+#undef nbytes_r
+#define in_r %esi
+ movl len_r, %ecx
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */
+ jmp .L_while_test_mmx
+
+#undef hold_r
+#undef bitslong_r
+
+#endif /* USE_MMX || RUN_TIME_MMX */
+
+
+/*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/
+
+.L_invalid_distance_code:
+ /* else {
+ * strm->msg = "invalid distance code";
+ * state->mode = BAD;
+ * }
+ */
+ movl $.L_invalid_distance_code_msg, %ecx
+ movl $INFLATE_MODE_BAD, %edx
+ jmp .L_update_stream_state
+
+.L_test_for_end_of_block:
+ /* else if (op & 32) {
+ * state->mode = TYPE;
+ * break;
+ * }
+ */
+ testb $32, %al
+ jz .L_invalid_literal_length_code /* if ((op & 32) == 0) */
+
+ movl $0, %ecx
+ movl $INFLATE_MODE_TYPE, %edx
+ jmp .L_update_stream_state
+
+.L_invalid_literal_length_code:
+ /* else {
+ * strm->msg = "invalid literal/length code";
+ * state->mode = BAD;
+ * }
+ */
+ movl $.L_invalid_literal_length_code_msg, %ecx
+ movl $INFLATE_MODE_BAD, %edx
+ jmp .L_update_stream_state
+
+.L_invalid_distance_too_far:
+ /* strm->msg = "invalid distance too far back";
+ * state->mode = BAD;
+ */
+ movl in(%esp), in_r /* from_r has in's reg, put in back */
+ movl $.L_invalid_distance_too_far_msg, %ecx
+ movl $INFLATE_MODE_BAD, %edx
+ jmp .L_update_stream_state
+
+.L_update_stream_state:
+ /* set strm->msg = %ecx, strm->state->mode = %edx */
+ movl strm_sp(%esp), %eax
+ testl %ecx, %ecx /* if (msg != NULL) */
+ jz .L_skip_msg
+ movl %ecx, msg_strm(%eax) /* strm->msg = msg */
+.L_skip_msg:
+ movl state_strm(%eax), %eax /* state = strm->state */
+ movl %edx, mode_state(%eax) /* state->mode = edx (BAD | TYPE) */
+ jmp .L_break_loop
+
+.align 32,0x90
+.L_break_loop:
+
+/*
+ * Regs:
+ *
+ * bits = %ebp when mmx, and in %ebx when non-mmx
+ * hold = %hold_mm when mmx, and in %ebp when non-mmx
+ * in = %esi
+ * out = %edi
+ */
+
+#if defined( USE_MMX ) || defined( RUN_TIME_MMX )
+
+#if defined( RUN_TIME_MMX )
+
+ cmpl $DO_USE_MMX, inflate_fast_use_mmx
+ jne .L_update_next_in
+
+#endif /* RUN_TIME_MMX */
+
+ movl %ebp, %ebx
+
+.L_update_next_in:
+
+#endif
+
+#define strm_r %eax
+#define state_r %edx
+
+ /* len = bits >> 3;
+ * in -= len;
+ * bits -= len << 3;
+ * hold &= (1U << bits) - 1;
+ * state->hold = hold;
+ * state->bits = bits;
+ * strm->next_in = in;
+ * strm->next_out = out;
+ */
+ movl strm_sp(%esp), strm_r
+ movl %ebx, %ecx
+ movl state_strm(strm_r), state_r
+ shrl $3, %ecx
+ subl %ecx, in_r
+ shll $3, %ecx
+ subl %ecx, %ebx
+ movl out_r, next_out_strm(strm_r)
+ movl %ebx, bits_state(state_r)
+ movl %ebx, %ecx
+
+ leal buf(%esp), %ebx
+ cmpl %ebx, last(%esp)
+ jne .L_buf_not_used /* if buf != last */
+
+ subl %ebx, in_r /* in -= buf */
+ movl next_in_strm(strm_r), %ebx
+ movl %ebx, last(%esp) /* last = strm->next_in */
+ addl %ebx, in_r /* in += strm->next_in */
+ movl avail_in_strm(strm_r), %ebx
+ subl $11, %ebx
+ addl %ebx, last(%esp) /* last = &strm->next_in[ avail_in - 11 ] */
+
+.L_buf_not_used:
+ movl in_r, next_in_strm(strm_r)
+
+ movl $1, %ebx
+ shll %cl, %ebx
+ decl %ebx
+
+#if defined( USE_MMX ) || defined( RUN_TIME_MMX )
+
+#if defined( RUN_TIME_MMX )
+
+ cmpl $DO_USE_MMX, inflate_fast_use_mmx
+ jne .L_update_hold
+
+#endif /* RUN_TIME_MMX */
+
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd hold_mm, %ebp
+
+ emms
+
+.L_update_hold:
+
+#endif /* USE_MMX || RUN_TIME_MMX */
+
+ andl %ebx, %ebp
+ movl %ebp, hold_state(state_r)
+
+#define last_r %ebx
+
+ /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */
+ movl last(%esp), last_r
+ cmpl in_r, last_r
+ jbe .L_last_is_smaller /* if (in >= last) */
+
+ subl in_r, last_r /* last -= in */
+ addl $11, last_r /* last += 11 */
+ movl last_r, avail_in_strm(strm_r)
+ jmp .L_fixup_out
+.L_last_is_smaller:
+ subl last_r, in_r /* in -= last */
+ negl in_r /* in = -in */
+ addl $11, in_r /* in += 11 */
+ movl in_r, avail_in_strm(strm_r)
+
+#undef last_r
+#define end_r %ebx
+
+.L_fixup_out:
+ /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/
+ movl end(%esp), end_r
+ cmpl out_r, end_r
+ jbe .L_end_is_smaller /* if (out >= end) */
+
+ subl out_r, end_r /* end -= out */
+ addl $257, end_r /* end += 257 */
+ movl end_r, avail_out_strm(strm_r)
+ jmp .L_done
+.L_end_is_smaller:
+ subl end_r, out_r /* out -= end */
+ negl out_r /* out = -out */
+ addl $257, out_r /* out += 257 */
+ movl out_r, avail_out_strm(strm_r)
+
+#undef end_r
+#undef strm_r
+#undef state_r
+
+.L_done:
+ addl $local_var_size, %esp
+ popf
+ popl %ebx
+ popl %ebp
+ popl %esi
+ popl %edi
+ ret
+
+#if defined( GAS_ELF )
+/* elf info */
+.type inflate_fast,@function
+.size inflate_fast,.-inflate_fast
+#endif
diff --git a/zlib/contrib/iostream/test.cpp b/zlib/contrib/iostream/test.cpp
new file mode 100644
index 0000000..7d265b3
--- /dev/null
+++ b/zlib/contrib/iostream/test.cpp
@@ -0,0 +1,24 @@
+
+#include "zfstream.h"
+
+int main() {
+
+ // Construct a stream object with this filebuffer. Anything sent
+ // to this stream will go to standard out.
+ gzofstream os( 1, ios::out );
+
+ // This text is getting compressed and sent to stdout.
+ // To prove this, run 'test | zcat'.
+ os << "Hello, Mommy" << endl;
+
+ os << setcompressionlevel( Z_NO_COMPRESSION );
+ os << "hello, hello, hi, ho!" << endl;
+
+ setcompressionlevel( os, Z_DEFAULT_COMPRESSION )
+ << "I'm compressing again" << endl;
+
+ os.close();
+
+ return 0;
+
+}
diff --git a/zlib/contrib/iostream/zfstream.cpp b/zlib/contrib/iostream/zfstream.cpp
new file mode 100644
index 0000000..d0cd85f
--- /dev/null
+++ b/zlib/contrib/iostream/zfstream.cpp
@@ -0,0 +1,329 @@
+
+#include "zfstream.h"
+
+gzfilebuf::gzfilebuf() :
+ file(NULL),
+ mode(0),
+ own_file_descriptor(0)
+{ }
+
+gzfilebuf::~gzfilebuf() {
+
+ sync();
+ if ( own_file_descriptor )
+ close();
+
+}
+
+gzfilebuf *gzfilebuf::open( const char *name,
+ int io_mode ) {
+
+ if ( is_open() )
+ return NULL;
+
+ char char_mode[10];
+ char *p = char_mode;
+
+ if ( io_mode & ios::in ) {
+ mode = ios::in;
+ *p++ = 'r';
+ } else if ( io_mode & ios::app ) {
+ mode = ios::app;
+ *p++ = 'a';
+ } else {
+ mode = ios::out;
+ *p++ = 'w';
+ }
+
+ if ( io_mode & ios::binary ) {
+ mode |= ios::binary;
+ *p++ = 'b';
+ }
+
+ // Hard code the compression level
+ if ( io_mode & (ios::out|ios::app )) {
+ *p++ = '9';
+ }
+
+ // Put the end-of-string indicator
+ *p = '\0';
+
+ if ( (file = gzopen(name, char_mode)) == NULL )
+ return NULL;
+
+ own_file_descriptor = 1;
+
+ return this;
+
+}
+
+gzfilebuf *gzfilebuf::attach( int file_descriptor,
+ int io_mode ) {
+
+ if ( is_open() )
+ return NULL;
+
+ char char_mode[10];
+ char *p = char_mode;
+
+ if ( io_mode & ios::in ) {
+ mode = ios::in;
+ *p++ = 'r';
+ } else if ( io_mode & ios::app ) {
+ mode = ios::app;
+ *p++ = 'a';
+ } else {
+ mode = ios::out;
+ *p++ = 'w';
+ }
+
+ if ( io_mode & ios::binary ) {
+ mode |= ios::binary;
+ *p++ = 'b';
+ }
+
+ // Hard code the compression level
+ if ( io_mode & (ios::out|ios::app )) {
+ *p++ = '9';
+ }
+
+ // Put the end-of-string indicator
+ *p = '\0';
+
+ if ( (file = gzdopen(file_descriptor, char_mode)) == NULL )
+ return NULL;
+
+ own_file_descriptor = 0;
+
+ return this;
+
+}
+
+gzfilebuf *gzfilebuf::close() {
+
+ if ( is_open() ) {
+
+ sync();
+ gzclose( file );
+ file = NULL;
+
+ }
+
+ return this;
+
+}
+
+int gzfilebuf::setcompressionlevel( int comp_level ) {
+
+ return gzsetparams(file, comp_level, -2);
+
+}
+
+int gzfilebuf::setcompressionstrategy( int comp_strategy ) {
+
+ return gzsetparams(file, -2, comp_strategy);
+
+}
+
+
+streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) {
+
+ return streampos(EOF);
+
+}
+
+int gzfilebuf::underflow() {
+
+ // If the file hasn't been opened for reading, error.
+ if ( !is_open() || !(mode & ios::in) )
+ return EOF;
+
+ // if a buffer doesn't exists, allocate one.
+ if ( !base() ) {
+
+ if ( (allocate()) == EOF )
+ return EOF;
+ setp(0,0);
+
+ } else {
+
+ if ( in_avail() )
+ return (unsigned char) *gptr();
+
+ if ( out_waiting() ) {
+ if ( flushbuf() == EOF )
+ return EOF;
+ }
+
+ }
+
+ // Attempt to fill the buffer.
+
+ int result = fillbuf();
+ if ( result == EOF ) {
+ // disable get area
+ setg(0,0,0);
+ return EOF;
+ }
+
+ return (unsigned char) *gptr();
+
+}
+
+int gzfilebuf::overflow( int c ) {
+
+ if ( !is_open() || !(mode & ios::out) )
+ return EOF;
+
+ if ( !base() ) {
+ if ( allocate() == EOF )
+ return EOF;
+ setg(0,0,0);
+ } else {
+ if (in_avail()) {
+ return EOF;
+ }
+ if (out_waiting()) {
+ if (flushbuf() == EOF)
+ return EOF;
+ }
+ }
+
+ int bl = blen();
+ setp( base(), base() + bl);
+
+ if ( c != EOF ) {
+
+ *pptr() = c;
+ pbump(1);
+
+ }
+
+ return 0;
+
+}
+
+int gzfilebuf::sync() {
+
+ if ( !is_open() )
+ return EOF;
+
+ if ( out_waiting() )
+ return flushbuf();
+
+ return 0;
+
+}
+
+int gzfilebuf::flushbuf() {
+
+ int n;
+ char *q;
+
+ q = pbase();
+ n = pptr() - q;
+
+ if ( gzwrite( file, q, n) < n )
+ return EOF;
+
+ setp(0,0);
+
+ return 0;
+
+}
+
+int gzfilebuf::fillbuf() {
+
+ int required;
+ char *p;
+
+ p = base();
+
+ required = blen();
+
+ int t = gzread( file, p, required );
+
+ if ( t <= 0) return EOF;
+
+ setg( base(), base(), base()+t);
+
+ return t;
+
+}
+
+gzfilestream_common::gzfilestream_common() :
+ ios( gzfilestream_common::rdbuf() )
+{ }
+
+gzfilestream_common::~gzfilestream_common()
+{ }
+
+void gzfilestream_common::attach( int fd, int io_mode ) {
+
+ if ( !buffer.attach( fd, io_mode) )
+ clear( ios::failbit | ios::badbit );
+ else
+ clear();
+
+}
+
+void gzfilestream_common::open( const char *name, int io_mode ) {
+
+ if ( !buffer.open( name, io_mode ) )
+ clear( ios::failbit | ios::badbit );
+ else
+ clear();
+
+}
+
+void gzfilestream_common::close() {
+
+ if ( !buffer.close() )
+ clear( ios::failbit | ios::badbit );
+
+}
+
+gzfilebuf *gzfilestream_common::rdbuf()
+{
+ return &buffer;
+}
+
+gzifstream::gzifstream() :
+ ios( gzfilestream_common::rdbuf() )
+{
+ clear( ios::badbit );
+}
+
+gzifstream::gzifstream( const char *name, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::open( name, io_mode );
+}
+
+gzifstream::gzifstream( int fd, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::attach( fd, io_mode );
+}
+
+gzifstream::~gzifstream() { }
+
+gzofstream::gzofstream() :
+ ios( gzfilestream_common::rdbuf() )
+{
+ clear( ios::badbit );
+}
+
+gzofstream::gzofstream( const char *name, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::open( name, io_mode );
+}
+
+gzofstream::gzofstream( int fd, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::attach( fd, io_mode );
+}
+
+gzofstream::~gzofstream() { }
diff --git a/zlib/contrib/iostream/zfstream.h b/zlib/contrib/iostream/zfstream.h
new file mode 100644
index 0000000..ed79098
--- /dev/null
+++ b/zlib/contrib/iostream/zfstream.h
@@ -0,0 +1,128 @@
+
+#ifndef zfstream_h
+#define zfstream_h
+
+#include <fstream.h>
+#include "zlib.h"
+
+class gzfilebuf : public streambuf {
+
+public:
+
+ gzfilebuf( );
+ virtual ~gzfilebuf();
+
+ gzfilebuf *open( const char *name, int io_mode );
+ gzfilebuf *attach( int file_descriptor, int io_mode );
+ gzfilebuf *close();
+
+ int setcompressionlevel( int comp_level );
+ int setcompressionstrategy( int comp_strategy );
+
+ inline int is_open() const { return (file !=NULL); }
+
+ virtual streampos seekoff( streamoff, ios::seek_dir, int );
+
+ virtual int sync();
+
+protected:
+
+ virtual int underflow();
+ virtual int overflow( int = EOF );
+
+private:
+
+ gzFile file;
+ short mode;
+ short own_file_descriptor;
+
+ int flushbuf();
+ int fillbuf();
+
+};
+
+class gzfilestream_common : virtual public ios {
+
+ friend class gzifstream;
+ friend class gzofstream;
+ friend gzofstream &setcompressionlevel( gzofstream &, int );
+ friend gzofstream &setcompressionstrategy( gzofstream &, int );
+
+public:
+ virtual ~gzfilestream_common();
+
+ void attach( int fd, int io_mode );
+ void open( const char *name, int io_mode );
+ void close();
+
+protected:
+ gzfilestream_common();
+
+private:
+ gzfilebuf *rdbuf();
+
+ gzfilebuf buffer;
+
+};
+
+class gzifstream : public gzfilestream_common, public istream {
+
+public:
+
+ gzifstream();
+ gzifstream( const char *name, int io_mode = ios::in );
+ gzifstream( int fd, int io_mode = ios::in );
+
+ virtual ~gzifstream();
+
+};
+
+class gzofstream : public gzfilestream_common, public ostream {
+
+public:
+
+ gzofstream();
+ gzofstream( const char *name, int io_mode = ios::out );
+ gzofstream( int fd, int io_mode = ios::out );
+
+ virtual ~gzofstream();
+
+};
+
+template<class T> class gzomanip {
+ friend gzofstream &operator<<(gzofstream &, const gzomanip<T> &);
+public:
+ gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { }
+private:
+ gzofstream &(*func)(gzofstream &, T);
+ T val;
+};
+
+template<class T> gzofstream &operator<<(gzofstream &s, const gzomanip<T> &m)
+{
+ return (*m.func)(s, m.val);
+}
+
+inline gzofstream &setcompressionlevel( gzofstream &s, int l )
+{
+ (s.rdbuf())->setcompressionlevel(l);
+ return s;
+}
+
+inline gzofstream &setcompressionstrategy( gzofstream &s, int l )
+{
+ (s.rdbuf())->setcompressionstrategy(l);
+ return s;
+}
+
+inline gzomanip<int> setcompressionlevel(int l)
+{
+ return gzomanip<int>(&setcompressionlevel,l);
+}
+
+inline gzomanip<int> setcompressionstrategy(int l)
+{
+ return gzomanip<int>(&setcompressionstrategy,l);
+}
+
+#endif
diff --git a/zlib/contrib/iostream2/zstream.h b/zlib/contrib/iostream2/zstream.h
new file mode 100644
index 0000000..08b68a8
--- /dev/null
+++ b/zlib/contrib/iostream2/zstream.h
@@ -0,0 +1,307 @@
+/*
+ *
+ * Copyright (c) 1997
+ * Christian Michelsen Research AS
+ * Advanced Computing
+ * Fantoftvegen 38, 5036 BERGEN, Norway
+ * http://www.cmr.no
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Christian Michelsen Research AS makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef ZSTREAM__H
+#define ZSTREAM__H
+
+/*
+ * zstream.h - C++ interface to the 'zlib' general purpose compression library
+ * $Id: zstream.h,v 1.1.1.1 2000/11/01 00:12:01 dprice Exp $
+ */
+
+#include <strstream.h>
+#include <string.h>
+#include <stdio.h>
+#include "zlib.h"
+
+#if defined(_WIN32)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+class zstringlen {
+public:
+ zstringlen(class izstream&);
+ zstringlen(class ozstream&, const char*);
+ size_t value() const { return val.word; }
+private:
+ struct Val { unsigned char byte; size_t word; } val;
+};
+
+// ----------------------------- izstream -----------------------------
+
+class izstream
+{
+ public:
+ izstream() : m_fp(0) {}
+ izstream(FILE* fp) : m_fp(0) { open(fp); }
+ izstream(const char* name) : m_fp(0) { open(name); }
+ ~izstream() { close(); }
+
+ /* Opens a gzip (.gz) file for reading.
+ * open() can be used to read a file which is not in gzip format;
+ * in this case read() will directly read from the file without
+ * decompression. errno can be checked to distinguish two error
+ * cases (if errno is zero, the zlib error is Z_MEM_ERROR).
+ */
+ void open(const char* name) {
+ if (m_fp) close();
+ m_fp = ::gzopen(name, "rb");
+ }
+
+ void open(FILE* fp) {
+ SET_BINARY_MODE(fp);
+ if (m_fp) close();
+ m_fp = ::gzdopen(fileno(fp), "rb");
+ }
+
+ /* Flushes all pending input if necessary, closes the compressed file
+ * and deallocates all the (de)compression state. The return value is
+ * the zlib error number (see function error() below).
+ */
+ int close() {
+ int r = ::gzclose(m_fp);
+ m_fp = 0; return r;
+ }
+
+ /* Binary read the given number of bytes from the compressed file.
+ */
+ int read(void* buf, size_t len) {
+ return ::gzread(m_fp, buf, len);
+ }
+
+ /* Returns the error message for the last error which occurred on the
+ * given compressed file. errnum is set to zlib error number. If an
+ * error occurred in the file system and not in the compression library,
+ * errnum is set to Z_ERRNO and the application may consult errno
+ * to get the exact error code.
+ */
+ const char* error(int* errnum) {
+ return ::gzerror(m_fp, errnum);
+ }
+
+ gzFile fp() { return m_fp; }
+
+ private:
+ gzFile m_fp;
+};
+
+/*
+ * Binary read the given (array of) object(s) from the compressed file.
+ * If the input file was not in gzip format, read() copies the objects number
+ * of bytes into the buffer.
+ * returns the number of uncompressed bytes actually read
+ * (0 for end of file, -1 for error).
+ */
+template <class T, class Items>
+inline int read(izstream& zs, T* x, Items items) {
+ return ::gzread(zs.fp(), x, items*sizeof(T));
+}
+
+/*
+ * Binary input with the '>' operator.
+ */
+template <class T>
+inline izstream& operator>(izstream& zs, T& x) {
+ ::gzread(zs.fp(), &x, sizeof(T));
+ return zs;
+}
+
+
+inline zstringlen::zstringlen(izstream& zs) {
+ zs > val.byte;
+ if (val.byte == 255) zs > val.word;
+ else val.word = val.byte;
+}
+
+/*
+ * Read length of string + the string with the '>' operator.
+ */
+inline izstream& operator>(izstream& zs, char* x) {
+ zstringlen len(zs);
+ ::gzread(zs.fp(), x, len.value());
+ x[len.value()] = '\0';
+ return zs;
+}
+
+inline char* read_string(izstream& zs) {
+ zstringlen len(zs);
+ char* x = new char[len.value()+1];
+ ::gzread(zs.fp(), x, len.value());
+ x[len.value()] = '\0';
+ return x;
+}
+
+// ----------------------------- ozstream -----------------------------
+
+class ozstream
+{
+ public:
+ ozstream() : m_fp(0), m_os(0) {
+ }
+ ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION)
+ : m_fp(0), m_os(0) {
+ open(fp, level);
+ }
+ ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION)
+ : m_fp(0), m_os(0) {
+ open(name, level);
+ }
+ ~ozstream() {
+ close();
+ }
+
+ /* Opens a gzip (.gz) file for writing.
+ * The compression level parameter should be in 0..9
+ * errno can be checked to distinguish two error cases
+ * (if errno is zero, the zlib error is Z_MEM_ERROR).
+ */
+ void open(const char* name, int level = Z_DEFAULT_COMPRESSION) {
+ char mode[4] = "wb\0";
+ if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+ if (m_fp) close();
+ m_fp = ::gzopen(name, mode);
+ }
+
+ /* open from a FILE pointer.
+ */
+ void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) {
+ SET_BINARY_MODE(fp);
+ char mode[4] = "wb\0";
+ if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+ if (m_fp) close();
+ m_fp = ::gzdopen(fileno(fp), mode);
+ }
+
+ /* Flushes all pending output if necessary, closes the compressed file
+ * and deallocates all the (de)compression state. The return value is
+ * the zlib error number (see function error() below).
+ */
+ int close() {
+ if (m_os) {
+ ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+ delete[] m_os->str(); delete m_os; m_os = 0;
+ }
+ int r = ::gzclose(m_fp); m_fp = 0; return r;
+ }
+
+ /* Binary write the given number of bytes into the compressed file.
+ */
+ int write(const void* buf, size_t len) {
+ return ::gzwrite(m_fp, (voidp) buf, len);
+ }
+
+ /* Flushes all pending output into the compressed file. The parameter
+ * _flush is as in the deflate() function. The return value is the zlib
+ * error number (see function gzerror below). flush() returns Z_OK if
+ * the flush_ parameter is Z_FINISH and all output could be flushed.
+ * flush() should be called only when strictly necessary because it can
+ * degrade compression.
+ */
+ int flush(int _flush) {
+ os_flush();
+ return ::gzflush(m_fp, _flush);
+ }
+
+ /* Returns the error message for the last error which occurred on the
+ * given compressed file. errnum is set to zlib error number. If an
+ * error occurred in the file system and not in the compression library,
+ * errnum is set to Z_ERRNO and the application may consult errno
+ * to get the exact error code.
+ */
+ const char* error(int* errnum) {
+ return ::gzerror(m_fp, errnum);
+ }
+
+ gzFile fp() { return m_fp; }
+
+ ostream& os() {
+ if (m_os == 0) m_os = new ostrstream;
+ return *m_os;
+ }
+
+ void os_flush() {
+ if (m_os && m_os->pcount()>0) {
+ ostrstream* oss = new ostrstream;
+ oss->fill(m_os->fill());
+ oss->flags(m_os->flags());
+ oss->precision(m_os->precision());
+ oss->width(m_os->width());
+ ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+ delete[] m_os->str(); delete m_os; m_os = oss;
+ }
+ }
+
+ private:
+ gzFile m_fp;
+ ostrstream* m_os;
+};
+
+/*
+ * Binary write the given (array of) object(s) into the compressed file.
+ * returns the number of uncompressed bytes actually written
+ * (0 in case of error).
+ */
+template <class T, class Items>
+inline int write(ozstream& zs, const T* x, Items items) {
+ return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T));
+}
+
+/*
+ * Binary output with the '<' operator.
+ */
+template <class T>
+inline ozstream& operator<(ozstream& zs, const T& x) {
+ ::gzwrite(zs.fp(), (voidp) &x, sizeof(T));
+ return zs;
+}
+
+inline zstringlen::zstringlen(ozstream& zs, const char* x) {
+ val.byte = 255; val.word = ::strlen(x);
+ if (val.word < 255) zs < (val.byte = val.word);
+ else zs < val;
+}
+
+/*
+ * Write length of string + the string with the '<' operator.
+ */
+inline ozstream& operator<(ozstream& zs, const char* x) {
+ zstringlen len(zs, x);
+ ::gzwrite(zs.fp(), (voidp) x, len.value());
+ return zs;
+}
+
+#ifdef _MSC_VER
+inline ozstream& operator<(ozstream& zs, char* const& x) {
+ return zs < (const char*) x;
+}
+#endif
+
+/*
+ * Ascii write with the << operator;
+ */
+template <class T>
+inline ostream& operator<<(ozstream& zs, const T& x) {
+ zs.os_flush();
+ return zs.os() << x;
+}
+
+#endif
diff --git a/zlib/contrib/iostream2/zstream_test.cpp b/zlib/contrib/iostream2/zstream_test.cpp
new file mode 100644
index 0000000..6273f62
--- /dev/null
+++ b/zlib/contrib/iostream2/zstream_test.cpp
@@ -0,0 +1,25 @@
+#include "zstream.h"
+#include <math.h>
+#include <stdlib.h>
+#include <iomanip.h>
+
+void main() {
+ char h[256] = "Hello";
+ char* g = "Goodbye";
+ ozstream out("temp.gz");
+ out < "This works well" < h < g;
+ out.close();
+
+ izstream in("temp.gz"); // read it back
+ char *x = read_string(in), *y = new char[256], z[256];
+ in > y > z;
+ in.close();
+ cout << x << endl << y << endl << z << endl;
+
+ out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results
+ out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl;
+ out << z << endl << y << endl << x << endl;
+ out << 1.1234567890123456789 << endl;
+
+ delete[] x; delete[] y;
+}
diff --git a/zlib/contrib/iostream3/README b/zlib/contrib/iostream3/README
new file mode 100644
index 0000000..f7b319a
--- /dev/null
+++ b/zlib/contrib/iostream3/README
@@ -0,0 +1,35 @@
+These classes provide a C++ stream interface to the zlib library. It allows you
+to do things like:
+
+ gzofstream outf("blah.gz");
+ outf << "These go into the gzip file " << 123 << endl;
+
+It does this by deriving a specialized stream buffer for gzipped files, which is
+the way Stroustrup would have done it. :->
+
+The gzifstream and gzofstream classes were originally written by Kevin Ruland
+and made available in the zlib contrib/iostream directory. The older version still
+compiles under gcc 2.xx, but not under gcc 3.xx, which sparked the development of
+this version.
+
+The new classes are as standard-compliant as possible, closely following the
+approach of the standard library's fstream classes. It compiles under gcc versions
+3.2 and 3.3, but not under gcc 2.xx. This is mainly due to changes in the standard
+library naming scheme. The new version of gzifstream/gzofstream/gzfilebuf differs
+from the previous one in the following respects:
+- added showmanyc
+- added setbuf, with support for unbuffered output via setbuf(0,0)
+- a few bug fixes of stream behavior
+- gzipped output file opened with default compression level instead of maximum level
+- setcompressionlevel()/strategy() members replaced by single setcompression()
+
+The code is provided "as is", with the permission to use, copy, modify, distribute
+and sell it for any purpose without fee.
+
+Ludwig Schwardt
+<schwardt@sun.ac.za>
+
+DSP Lab
+Electrical & Electronic Engineering Department
+University of Stellenbosch
+South Africa
diff --git a/zlib/contrib/iostream3/TODO b/zlib/contrib/iostream3/TODO
new file mode 100644
index 0000000..7032f97
--- /dev/null
+++ b/zlib/contrib/iostream3/TODO
@@ -0,0 +1,17 @@
+Possible upgrades to gzfilebuf:
+
+- The ability to do putback (e.g. putbackfail)
+
+- The ability to seek (zlib supports this, but could be slow/tricky)
+
+- Simultaneous read/write access (does it make sense?)
+
+- Support for ios_base::ate open mode
+
+- Locale support?
+
+- Check public interface to see which calls give problems
+ (due to dependence on library internals)
+
+- Override operator<<(ostream&, gzfilebuf*) to allow direct copying
+ of stream buffer to stream ( i.e. os << is.rdbuf(); )
diff --git a/zlib/contrib/iostream3/test.cc b/zlib/contrib/iostream3/test.cc
new file mode 100644
index 0000000..9423533
--- /dev/null
+++ b/zlib/contrib/iostream3/test.cc
@@ -0,0 +1,50 @@
+/*
+ * Test program for gzifstream and gzofstream
+ *
+ * by Ludwig Schwardt <schwardt@sun.ac.za>
+ * original version by Kevin Ruland <kevin@rodin.wustl.edu>
+ */
+
+#include "zfstream.h"
+#include <iostream> // for cout
+
+int main() {
+
+ gzofstream outf;
+ gzifstream inf;
+ char buf[80];
+
+ outf.open("test1.txt.gz");
+ outf << "The quick brown fox sidestepped the lazy canine\n"
+ << 1.3 << "\nPlan " << 9 << std::endl;
+ outf.close();
+ std::cout << "Wrote the following message to 'test1.txt.gz' (check with zcat or zless):\n"
+ << "The quick brown fox sidestepped the lazy canine\n"
+ << 1.3 << "\nPlan " << 9 << std::endl;
+
+ std::cout << "\nReading 'test1.txt.gz' (buffered) produces:\n";
+ inf.open("test1.txt.gz");
+ while (inf.getline(buf,80,'\n')) {
+ std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n";
+ }
+ inf.close();
+
+ outf.rdbuf()->pubsetbuf(0,0);
+ outf.open("test2.txt.gz");
+ outf << setcompression(Z_NO_COMPRESSION)
+ << "The quick brown fox sidestepped the lazy canine\n"
+ << 1.3 << "\nPlan " << 9 << std::endl;
+ outf.close();
+ std::cout << "\nWrote the same message to 'test2.txt.gz' in uncompressed form";
+
+ std::cout << "\nReading 'test2.txt.gz' (unbuffered) produces:\n";
+ inf.rdbuf()->pubsetbuf(0,0);
+ inf.open("test2.txt.gz");
+ while (inf.getline(buf,80,'\n')) {
+ std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n";
+ }
+ inf.close();
+
+ return 0;
+
+}
diff --git a/zlib/contrib/iostream3/zfstream.cc b/zlib/contrib/iostream3/zfstream.cc
new file mode 100644
index 0000000..94eb933
--- /dev/null
+++ b/zlib/contrib/iostream3/zfstream.cc
@@ -0,0 +1,479 @@
+/*
+ * A C++ I/O streams interface to the zlib gz* functions
+ *
+ * by Ludwig Schwardt <schwardt@sun.ac.za>
+ * original version by Kevin Ruland <kevin@rodin.wustl.edu>
+ *
+ * This version is standard-compliant and compatible with gcc 3.x.
+ */
+
+#include "zfstream.h"
+#include <cstring> // for strcpy, strcat, strlen (mode strings)
+#include <cstdio> // for BUFSIZ
+
+// Internal buffer sizes (default and "unbuffered" versions)
+#define BIGBUFSIZE BUFSIZ
+#define SMALLBUFSIZE 1
+
+/*****************************************************************************/
+
+// Default constructor
+gzfilebuf::gzfilebuf()
+: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false),
+ buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true)
+{
+ // No buffers to start with
+ this->disable_buffer();
+}
+
+// Destructor
+gzfilebuf::~gzfilebuf()
+{
+ // Sync output buffer and close only if responsible for file
+ // (i.e. attached streams should be left open at this stage)
+ this->sync();
+ if (own_fd)
+ this->close();
+ // Make sure internal buffer is deallocated
+ this->disable_buffer();
+}
+
+// Set compression level and strategy
+int
+gzfilebuf::setcompression(int comp_level,
+ int comp_strategy)
+{
+ return gzsetparams(file, comp_level, comp_strategy);
+}
+
+// Open gzipped file
+gzfilebuf*
+gzfilebuf::open(const char *name,
+ std::ios_base::openmode mode)
+{
+ // Fail if file already open
+ if (this->is_open())
+ return NULL;
+ // Don't support simultaneous read/write access (yet)
+ if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
+ return NULL;
+
+ // Build mode string for gzopen and check it [27.8.1.3.2]
+ char char_mode[6] = "\0\0\0\0\0";
+ if (!this->open_mode(mode, char_mode))
+ return NULL;
+
+ // Attempt to open file
+ if ((file = gzopen(name, char_mode)) == NULL)
+ return NULL;
+
+ // On success, allocate internal buffer and set flags
+ this->enable_buffer();
+ io_mode = mode;
+ own_fd = true;
+ return this;
+}
+
+// Attach to gzipped file
+gzfilebuf*
+gzfilebuf::attach(int fd,
+ std::ios_base::openmode mode)
+{
+ // Fail if file already open
+ if (this->is_open())
+ return NULL;
+ // Don't support simultaneous read/write access (yet)
+ if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
+ return NULL;
+
+ // Build mode string for gzdopen and check it [27.8.1.3.2]
+ char char_mode[6] = "\0\0\0\0\0";
+ if (!this->open_mode(mode, char_mode))
+ return NULL;
+
+ // Attempt to attach to file
+ if ((file = gzdopen(fd, char_mode)) == NULL)
+ return NULL;
+
+ // On success, allocate internal buffer and set flags
+ this->enable_buffer();
+ io_mode = mode;
+ own_fd = false;
+ return this;
+}
+
+// Close gzipped file
+gzfilebuf*
+gzfilebuf::close()
+{
+ // Fail immediately if no file is open
+ if (!this->is_open())
+ return NULL;
+ // Assume success
+ gzfilebuf* retval = this;
+ // Attempt to sync and close gzipped file
+ if (this->sync() == -1)
+ retval = NULL;
+ if (gzclose(file) < 0)
+ retval = NULL;
+ // File is now gone anyway (postcondition [27.8.1.3.8])
+ file = NULL;
+ own_fd = false;
+ // Destroy internal buffer if it exists
+ this->disable_buffer();
+ return retval;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Convert int open mode to mode string
+bool
+gzfilebuf::open_mode(std::ios_base::openmode mode,
+ char* c_mode) const
+{
+ bool testb = mode & std::ios_base::binary;
+ bool testi = mode & std::ios_base::in;
+ bool testo = mode & std::ios_base::out;
+ bool testt = mode & std::ios_base::trunc;
+ bool testa = mode & std::ios_base::app;
+
+ // Check for valid flag combinations - see [27.8.1.3.2] (Table 92)
+ // Original zfstream hardcoded the compression level to maximum here...
+ // Double the time for less than 1% size improvement seems
+ // excessive though - keeping it at the default level
+ // To change back, just append "9" to the next three mode strings
+ if (!testi && testo && !testt && !testa)
+ strcpy(c_mode, "w");
+ if (!testi && testo && !testt && testa)
+ strcpy(c_mode, "a");
+ if (!testi && testo && testt && !testa)
+ strcpy(c_mode, "w");
+ if (testi && !testo && !testt && !testa)
+ strcpy(c_mode, "r");
+ // No read/write mode yet
+// if (testi && testo && !testt && !testa)
+// strcpy(c_mode, "r+");
+// if (testi && testo && testt && !testa)
+// strcpy(c_mode, "w+");
+
+ // Mode string should be empty for invalid combination of flags
+ if (strlen(c_mode) == 0)
+ return false;
+ if (testb)
+ strcat(c_mode, "b");
+ return true;
+}
+
+// Determine number of characters in internal get buffer
+std::streamsize
+gzfilebuf::showmanyc()
+{
+ // Calls to underflow will fail if file not opened for reading
+ if (!this->is_open() || !(io_mode & std::ios_base::in))
+ return -1;
+ // Make sure get area is in use
+ if (this->gptr() && (this->gptr() < this->egptr()))
+ return std::streamsize(this->egptr() - this->gptr());
+ else
+ return 0;
+}
+
+// Fill get area from gzipped file
+gzfilebuf::int_type
+gzfilebuf::underflow()
+{
+ // If something is left in the get area by chance, return it
+ // (this shouldn't normally happen, as underflow is only supposed
+ // to be called when gptr >= egptr, but it serves as error check)
+ if (this->gptr() && (this->gptr() < this->egptr()))
+ return traits_type::to_int_type(*(this->gptr()));
+
+ // If the file hasn't been opened for reading, produce error
+ if (!this->is_open() || !(io_mode & std::ios_base::in))
+ return traits_type::eof();
+
+ // Attempt to fill internal buffer from gzipped file
+ // (buffer must be guaranteed to exist...)
+ int bytes_read = gzread(file, buffer, buffer_size);
+ // Indicates error or EOF
+ if (bytes_read <= 0)
+ {
+ // Reset get area
+ this->setg(buffer, buffer, buffer);
+ return traits_type::eof();
+ }
+ // Make all bytes read from file available as get area
+ this->setg(buffer, buffer, buffer + bytes_read);
+
+ // Return next character in get area
+ return traits_type::to_int_type(*(this->gptr()));
+}
+
+// Write put area to gzipped file
+gzfilebuf::int_type
+gzfilebuf::overflow(int_type c)
+{
+ // Determine whether put area is in use
+ if (this->pbase())
+ {
+ // Double-check pointer range
+ if (this->pptr() > this->epptr() || this->pptr() < this->pbase())
+ return traits_type::eof();
+ // Add extra character to buffer if not EOF
+ if (!traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ *(this->pptr()) = traits_type::to_char_type(c);
+ this->pbump(1);
+ }
+ // Number of characters to write to file
+ int bytes_to_write = this->pptr() - this->pbase();
+ // Overflow doesn't fail if nothing is to be written
+ if (bytes_to_write > 0)
+ {
+ // If the file hasn't been opened for writing, produce error
+ if (!this->is_open() || !(io_mode & std::ios_base::out))
+ return traits_type::eof();
+ // If gzipped file won't accept all bytes written to it, fail
+ if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write)
+ return traits_type::eof();
+ // Reset next pointer to point to pbase on success
+ this->pbump(-bytes_to_write);
+ }
+ }
+ // Write extra character to file if not EOF
+ else if (!traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ // If the file hasn't been opened for writing, produce error
+ if (!this->is_open() || !(io_mode & std::ios_base::out))
+ return traits_type::eof();
+ // Impromptu char buffer (allows "unbuffered" output)
+ char_type last_char = traits_type::to_char_type(c);
+ // If gzipped file won't accept this character, fail
+ if (gzwrite(file, &last_char, 1) != 1)
+ return traits_type::eof();
+ }
+
+ // If you got here, you have succeeded (even if c was EOF)
+ // The return value should therefore be non-EOF
+ if (traits_type::eq_int_type(c, traits_type::eof()))
+ return traits_type::not_eof(c);
+ else
+ return c;
+}
+
+// Assign new buffer
+std::streambuf*
+gzfilebuf::setbuf(char_type* p,
+ std::streamsize n)
+{
+ // First make sure stuff is sync'ed, for safety
+ if (this->sync() == -1)
+ return NULL;
+ // If buffering is turned off on purpose via setbuf(0,0), still allocate one...
+ // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at
+ // least a buffer of size 1 (very inefficient though, therefore make it bigger?)
+ // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems)
+ if (!p || !n)
+ {
+ // Replace existing buffer (if any) with small internal buffer
+ this->disable_buffer();
+ buffer = NULL;
+ buffer_size = 0;
+ own_buffer = true;
+ this->enable_buffer();
+ }
+ else
+ {
+ // Replace existing buffer (if any) with external buffer
+ this->disable_buffer();
+ buffer = p;
+ buffer_size = n;
+ own_buffer = false;
+ this->enable_buffer();
+ }
+ return this;
+}
+
+// Write put area to gzipped file (i.e. ensures that put area is empty)
+int
+gzfilebuf::sync()
+{
+ return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Allocate internal buffer
+void
+gzfilebuf::enable_buffer()
+{
+ // If internal buffer required, allocate one
+ if (own_buffer && !buffer)
+ {
+ // Check for buffered vs. "unbuffered"
+ if (buffer_size > 0)
+ {
+ // Allocate internal buffer
+ buffer = new char_type[buffer_size];
+ // Get area starts empty and will be expanded by underflow as need arises
+ this->setg(buffer, buffer, buffer);
+ // Setup entire internal buffer as put area.
+ // The one-past-end pointer actually points to the last element of the buffer,
+ // so that overflow(c) can safely add the extra character c to the sequence.
+ // These pointers remain in place for the duration of the buffer
+ this->setp(buffer, buffer + buffer_size - 1);
+ }
+ else
+ {
+ // Even in "unbuffered" case, (small?) get buffer is still required
+ buffer_size = SMALLBUFSIZE;
+ buffer = new char_type[buffer_size];
+ this->setg(buffer, buffer, buffer);
+ // "Unbuffered" means no put buffer
+ this->setp(0, 0);
+ }
+ }
+ else
+ {
+ // If buffer already allocated, reset buffer pointers just to make sure no
+ // stale chars are lying around
+ this->setg(buffer, buffer, buffer);
+ this->setp(buffer, buffer + buffer_size - 1);
+ }
+}
+
+// Destroy internal buffer
+void
+gzfilebuf::disable_buffer()
+{
+ // If internal buffer exists, deallocate it
+ if (own_buffer && buffer)
+ {
+ // Preserve unbuffered status by zeroing size
+ if (!this->pbase())
+ buffer_size = 0;
+ delete[] buffer;
+ buffer = NULL;
+ this->setg(0, 0, 0);
+ this->setp(0, 0);
+ }
+ else
+ {
+ // Reset buffer pointers to initial state if external buffer exists
+ this->setg(buffer, buffer, buffer);
+ if (buffer)
+ this->setp(buffer, buffer + buffer_size - 1);
+ else
+ this->setp(0, 0);
+ }
+}
+
+/*****************************************************************************/
+
+// Default constructor initializes stream buffer
+gzifstream::gzifstream()
+: std::istream(NULL), sb()
+{ this->init(&sb); }
+
+// Initialize stream buffer and open file
+gzifstream::gzifstream(const char* name,
+ std::ios_base::openmode mode)
+: std::istream(NULL), sb()
+{
+ this->init(&sb);
+ this->open(name, mode);
+}
+
+// Initialize stream buffer and attach to file
+gzifstream::gzifstream(int fd,
+ std::ios_base::openmode mode)
+: std::istream(NULL), sb()
+{
+ this->init(&sb);
+ this->attach(fd, mode);
+}
+
+// Open file and go into fail() state if unsuccessful
+void
+gzifstream::open(const char* name,
+ std::ios_base::openmode mode)
+{
+ if (!sb.open(name, mode | std::ios_base::in))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Attach to file and go into fail() state if unsuccessful
+void
+gzifstream::attach(int fd,
+ std::ios_base::openmode mode)
+{
+ if (!sb.attach(fd, mode | std::ios_base::in))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Close file
+void
+gzifstream::close()
+{
+ if (!sb.close())
+ this->setstate(std::ios_base::failbit);
+}
+
+/*****************************************************************************/
+
+// Default constructor initializes stream buffer
+gzofstream::gzofstream()
+: std::ostream(NULL), sb()
+{ this->init(&sb); }
+
+// Initialize stream buffer and open file
+gzofstream::gzofstream(const char* name,
+ std::ios_base::openmode mode)
+: std::ostream(NULL), sb()
+{
+ this->init(&sb);
+ this->open(name, mode);
+}
+
+// Initialize stream buffer and attach to file
+gzofstream::gzofstream(int fd,
+ std::ios_base::openmode mode)
+: std::ostream(NULL), sb()
+{
+ this->init(&sb);
+ this->attach(fd, mode);
+}
+
+// Open file and go into fail() state if unsuccessful
+void
+gzofstream::open(const char* name,
+ std::ios_base::openmode mode)
+{
+ if (!sb.open(name, mode | std::ios_base::out))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Attach to file and go into fail() state if unsuccessful
+void
+gzofstream::attach(int fd,
+ std::ios_base::openmode mode)
+{
+ if (!sb.attach(fd, mode | std::ios_base::out))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Close file
+void
+gzofstream::close()
+{
+ if (!sb.close())
+ this->setstate(std::ios_base::failbit);
+}
diff --git a/zlib/contrib/iostream3/zfstream.h b/zlib/contrib/iostream3/zfstream.h
new file mode 100644
index 0000000..8574479
--- /dev/null
+++ b/zlib/contrib/iostream3/zfstream.h
@@ -0,0 +1,466 @@
+/*
+ * A C++ I/O streams interface to the zlib gz* functions
+ *
+ * by Ludwig Schwardt <schwardt@sun.ac.za>
+ * original version by Kevin Ruland <kevin@rodin.wustl.edu>
+ *
+ * This version is standard-compliant and compatible with gcc 3.x.
+ */
+
+#ifndef ZFSTREAM_H
+#define ZFSTREAM_H
+
+#include <istream> // not iostream, since we don't need cin/cout
+#include <ostream>
+#include "zlib.h"
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file stream buffer class.
+ *
+ * This class implements basic_filebuf for gzipped files. It doesn't yet support
+ * seeking (allowed by zlib but slow/limited), putback and read/write access
+ * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard
+ * file streambuf.
+*/
+class gzfilebuf : public std::streambuf
+{
+public:
+ // Default constructor.
+ gzfilebuf();
+
+ // Destructor.
+ virtual
+ ~gzfilebuf();
+
+ /**
+ * @brief Set compression level and strategy on the fly.
+ * @param comp_level Compression level (see zlib.h for allowed values)
+ * @param comp_strategy Compression strategy (see zlib.h for allowed values)
+ * @return Z_OK on success, Z_STREAM_ERROR otherwise.
+ *
+ * Unfortunately, these parameters cannot be modified separately, as the
+ * previous zfstream version assumed. Since the strategy is seldom changed,
+ * it can default and setcompression(level) then becomes like the old
+ * setcompressionlevel(level).
+ */
+ int
+ setcompression(int comp_level,
+ int comp_strategy = Z_DEFAULT_STRATEGY);
+
+ /**
+ * @brief Check if file is open.
+ * @return True if file is open.
+ */
+ bool
+ is_open() const { return (file != NULL); }
+
+ /**
+ * @brief Open gzipped file.
+ * @param name File name.
+ * @param mode Open mode flags.
+ * @return @c this on success, NULL on failure.
+ */
+ gzfilebuf*
+ open(const char* name,
+ std::ios_base::openmode mode);
+
+ /**
+ * @brief Attach to already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags.
+ * @return @c this on success, NULL on failure.
+ */
+ gzfilebuf*
+ attach(int fd,
+ std::ios_base::openmode mode);
+
+ /**
+ * @brief Close gzipped file.
+ * @return @c this on success, NULL on failure.
+ */
+ gzfilebuf*
+ close();
+
+protected:
+ /**
+ * @brief Convert ios open mode int to mode string used by zlib.
+ * @return True if valid mode flag combination.
+ */
+ bool
+ open_mode(std::ios_base::openmode mode,
+ char* c_mode) const;
+
+ /**
+ * @brief Number of characters available in stream buffer.
+ * @return Number of characters.
+ *
+ * This indicates number of characters in get area of stream buffer.
+ * These characters can be read without accessing the gzipped file.
+ */
+ virtual std::streamsize
+ showmanyc();
+
+ /**
+ * @brief Fill get area from gzipped file.
+ * @return First character in get area on success, EOF on error.
+ *
+ * This actually reads characters from gzipped file to stream
+ * buffer. Always buffered.
+ */
+ virtual int_type
+ underflow();
+
+ /**
+ * @brief Write put area to gzipped file.
+ * @param c Extra character to add to buffer contents.
+ * @return Non-EOF on success, EOF on error.
+ *
+ * This actually writes characters in stream buffer to
+ * gzipped file. With unbuffered output this is done one
+ * character at a time.
+ */
+ virtual int_type
+ overflow(int_type c = traits_type::eof());
+
+ /**
+ * @brief Installs external stream buffer.
+ * @param p Pointer to char buffer.
+ * @param n Size of external buffer.
+ * @return @c this on success, NULL on failure.
+ *
+ * Call setbuf(0,0) to enable unbuffered output.
+ */
+ virtual std::streambuf*
+ setbuf(char_type* p,
+ std::streamsize n);
+
+ /**
+ * @brief Flush stream buffer to file.
+ * @return 0 on success, -1 on error.
+ *
+ * This calls underflow(EOF) to do the job.
+ */
+ virtual int
+ sync();
+
+//
+// Some future enhancements
+//
+// virtual int_type uflow();
+// virtual int_type pbackfail(int_type c = traits_type::eof());
+// virtual pos_type
+// seekoff(off_type off,
+// std::ios_base::seekdir way,
+// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
+// virtual pos_type
+// seekpos(pos_type sp,
+// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
+
+private:
+ /**
+ * @brief Allocate internal buffer.
+ *
+ * This function is safe to call multiple times. It will ensure
+ * that a proper internal buffer exists if it is required. If the
+ * buffer already exists or is external, the buffer pointers will be
+ * reset to their original state.
+ */
+ void
+ enable_buffer();
+
+ /**
+ * @brief Destroy internal buffer.
+ *
+ * This function is safe to call multiple times. It will ensure
+ * that the internal buffer is deallocated if it exists. In any
+ * case, it will also reset the buffer pointers.
+ */
+ void
+ disable_buffer();
+
+ /**
+ * Underlying file pointer.
+ */
+ gzFile file;
+
+ /**
+ * Mode in which file was opened.
+ */
+ std::ios_base::openmode io_mode;
+
+ /**
+ * @brief True if this object owns file descriptor.
+ *
+ * This makes the class responsible for closing the file
+ * upon destruction.
+ */
+ bool own_fd;
+
+ /**
+ * @brief Stream buffer.
+ *
+ * For simplicity this remains allocated on the free store for the
+ * entire life span of the gzfilebuf object, unless replaced by setbuf.
+ */
+ char_type* buffer;
+
+ /**
+ * @brief Stream buffer size.
+ *
+ * Defaults to system default buffer size (typically 8192 bytes).
+ * Modified by setbuf.
+ */
+ std::streamsize buffer_size;
+
+ /**
+ * @brief True if this object owns stream buffer.
+ *
+ * This makes the class responsible for deleting the buffer
+ * upon destruction.
+ */
+ bool own_buffer;
+};
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file input stream class.
+ *
+ * This class implements ifstream for gzipped files. Seeking and putback
+ * is not supported yet.
+*/
+class gzifstream : public std::istream
+{
+public:
+ // Default constructor
+ gzifstream();
+
+ /**
+ * @brief Construct stream on gzipped file to be opened.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::in).
+ */
+ explicit
+ gzifstream(const char* name,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * @brief Construct stream on already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::in).
+ */
+ explicit
+ gzifstream(int fd,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * Obtain underlying stream buffer.
+ */
+ gzfilebuf*
+ rdbuf() const
+ { return const_cast<gzfilebuf*>(&sb); }
+
+ /**
+ * @brief Check if file is open.
+ * @return True if file is open.
+ */
+ bool
+ is_open() { return sb.is_open(); }
+
+ /**
+ * @brief Open gzipped file.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::in).
+ *
+ * Stream will be in state good() if file opens successfully;
+ * otherwise in state fail(). This differs from the behavior of
+ * ifstream, which never sets the state to good() and therefore
+ * won't allow you to reuse the stream for a second file unless
+ * you manually clear() the state. The choice is a matter of
+ * convenience.
+ */
+ void
+ open(const char* name,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * @brief Attach to already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::in).
+ *
+ * Stream will be in state good() if attach succeeded; otherwise
+ * in state fail().
+ */
+ void
+ attach(int fd,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * @brief Close gzipped file.
+ *
+ * Stream will be in state fail() if close failed.
+ */
+ void
+ close();
+
+private:
+ /**
+ * Underlying stream buffer.
+ */
+ gzfilebuf sb;
+};
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file output stream class.
+ *
+ * This class implements ofstream for gzipped files. Seeking and putback
+ * is not supported yet.
+*/
+class gzofstream : public std::ostream
+{
+public:
+ // Default constructor
+ gzofstream();
+
+ /**
+ * @brief Construct stream on gzipped file to be opened.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::out).
+ */
+ explicit
+ gzofstream(const char* name,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * @brief Construct stream on already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::out).
+ */
+ explicit
+ gzofstream(int fd,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * Obtain underlying stream buffer.
+ */
+ gzfilebuf*
+ rdbuf() const
+ { return const_cast<gzfilebuf*>(&sb); }
+
+ /**
+ * @brief Check if file is open.
+ * @return True if file is open.
+ */
+ bool
+ is_open() { return sb.is_open(); }
+
+ /**
+ * @brief Open gzipped file.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::out).
+ *
+ * Stream will be in state good() if file opens successfully;
+ * otherwise in state fail(). This differs from the behavior of
+ * ofstream, which never sets the state to good() and therefore
+ * won't allow you to reuse the stream for a second file unless
+ * you manually clear() the state. The choice is a matter of
+ * convenience.
+ */
+ void
+ open(const char* name,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * @brief Attach to already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::out).
+ *
+ * Stream will be in state good() if attach succeeded; otherwise
+ * in state fail().
+ */
+ void
+ attach(int fd,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * @brief Close gzipped file.
+ *
+ * Stream will be in state fail() if close failed.
+ */
+ void
+ close();
+
+private:
+ /**
+ * Underlying stream buffer.
+ */
+ gzfilebuf sb;
+};
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file output stream manipulator class.
+ *
+ * This class defines a two-argument manipulator for gzofstream. It is used
+ * as base for the setcompression(int,int) manipulator.
+*/
+template<typename T1, typename T2>
+ class gzomanip2
+ {
+ public:
+ // Allows insertor to peek at internals
+ template <typename Ta, typename Tb>
+ friend gzofstream&
+ operator<<(gzofstream&,
+ const gzomanip2<Ta,Tb>&);
+
+ // Constructor
+ gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2),
+ T1 v1,
+ T2 v2);
+ private:
+ // Underlying manipulator function
+ gzofstream&
+ (*func)(gzofstream&, T1, T2);
+
+ // Arguments for manipulator function
+ T1 val1;
+ T2 val2;
+ };
+
+/*****************************************************************************/
+
+// Manipulator function thunks through to stream buffer
+inline gzofstream&
+setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY)
+{
+ (gzs.rdbuf())->setcompression(l, s);
+ return gzs;
+}
+
+// Manipulator constructor stores arguments
+template<typename T1, typename T2>
+ inline
+ gzomanip2<T1,T2>::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2),
+ T1 v1,
+ T2 v2)
+ : func(f), val1(v1), val2(v2)
+ { }
+
+// Insertor applies underlying manipulator function to stream
+template<typename T1, typename T2>
+ inline gzofstream&
+ operator<<(gzofstream& s, const gzomanip2<T1,T2>& m)
+ { return (*m.func)(s, m.val1, m.val2); }
+
+// Insert this onto stream to simplify setting of compression level
+inline gzomanip2<int,int>
+setcompression(int l, int s = Z_DEFAULT_STRATEGY)
+{ return gzomanip2<int,int>(&setcompression, l, s); }
+
+#endif // ZFSTREAM_H
diff --git a/zlib/contrib/masm686/match.asm b/zlib/contrib/masm686/match.asm
new file mode 100644
index 0000000..4b03a71
--- /dev/null
+++ b/zlib/contrib/masm686/match.asm
@@ -0,0 +1,413 @@
+
+; match.asm -- Pentium-Pro optimized version of longest_match()
+;
+; Updated for zlib 1.1.3 and converted to MASM 6.1x
+; Copyright (C) 2000 Dan Higdon <hdan@kinesoft.com>
+; and Chuck Walbourn <chuckw@kinesoft.com>
+; Corrections by Cosmin Truta <cosmint@cs.ubbcluj.ro>
+;
+; This is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License.
+
+; Based on match.S
+; Written for zlib 1.1.2
+; Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+;
+; Modified by Gilles Vollant (2005) for add gzhead and gzindex
+
+ .686P
+ .MODEL FLAT
+
+;===========================================================================
+; EQUATES
+;===========================================================================
+
+MAX_MATCH EQU 258
+MIN_MATCH EQU 3
+MIN_LOOKAHEAD EQU (MAX_MATCH + MIN_MATCH + 1)
+MAX_MATCH_8 EQU ((MAX_MATCH + 7) AND (NOT 7))
+
+;===========================================================================
+; STRUCTURES
+;===========================================================================
+
+; This STRUCT assumes a 4-byte alignment
+
+DEFLATE_STATE STRUCT
+ds_strm dd ?
+ds_status dd ?
+ds_pending_buf dd ?
+ds_pending_buf_size dd ?
+ds_pending_out dd ?
+ds_pending dd ?
+ds_wrap dd ?
+; gzhead and gzindex are added in zlib 1.2.2.2 (see deflate.h)
+ds_gzhead dd ?
+ds_gzindex dd ?
+ds_data_type db ?
+ds_method db ?
+ db ? ; padding
+ db ? ; padding
+ds_last_flush dd ?
+ds_w_size dd ? ; used
+ds_w_bits dd ?
+ds_w_mask dd ? ; used
+ds_window dd ? ; used
+ds_window_size dd ?
+ds_prev dd ? ; used
+ds_head dd ?
+ds_ins_h dd ?
+ds_hash_size dd ?
+ds_hash_bits dd ?
+ds_hash_mask dd ?
+ds_hash_shift dd ?
+ds_block_start dd ?
+ds_match_length dd ? ; used
+ds_prev_match dd ? ; used
+ds_match_available dd ?
+ds_strstart dd ? ; used
+ds_match_start dd ? ; used
+ds_lookahead dd ? ; used
+ds_prev_length dd ? ; used
+ds_max_chain_length dd ? ; used
+ds_max_laxy_match dd ?
+ds_level dd ?
+ds_strategy dd ?
+ds_good_match dd ? ; used
+ds_nice_match dd ? ; used
+
+; Don't need anymore of the struct for match
+DEFLATE_STATE ENDS
+
+;===========================================================================
+; CODE
+;===========================================================================
+_TEXT SEGMENT
+
+;---------------------------------------------------------------------------
+; match_init
+;---------------------------------------------------------------------------
+ ALIGN 4
+PUBLIC _match_init
+_match_init PROC
+ ; no initialization needed
+ ret
+_match_init ENDP
+
+;---------------------------------------------------------------------------
+; uInt longest_match(deflate_state *deflatestate, IPos curmatch)
+;---------------------------------------------------------------------------
+ ALIGN 4
+
+PUBLIC _longest_match
+_longest_match PROC
+
+; Since this code uses EBP for a scratch register, the stack frame must
+; be manually constructed and referenced relative to the ESP register.
+
+; Stack image
+; Variables
+chainlenwmask = 0 ; high word: current chain len
+ ; low word: s->wmask
+window = 4 ; local copy of s->window
+windowbestlen = 8 ; s->window + bestlen
+scanend = 12 ; last two bytes of string
+scanstart = 16 ; first two bytes of string
+scanalign = 20 ; dword-misalignment of string
+nicematch = 24 ; a good enough match size
+bestlen = 28 ; size of best match so far
+scan = 32 ; ptr to string wanting match
+varsize = 36 ; number of bytes (also offset to last saved register)
+
+; Saved Registers (actually pushed into place)
+ebx_save = 36
+edi_save = 40
+esi_save = 44
+ebp_save = 48
+
+; Parameters
+retaddr = 52
+deflatestate = 56
+curmatch = 60
+
+; Save registers that the compiler may be using
+ push ebp
+ push edi
+ push esi
+ push ebx
+
+; Allocate local variable space
+ sub esp,varsize
+
+; Retrieve the function arguments. ecx will hold cur_match
+; throughout the entire function. edx will hold the pointer to the
+; deflate_state structure during the function's setup (before
+; entering the main loop).
+
+ mov edx, [esp+deflatestate]
+ASSUME edx:PTR DEFLATE_STATE
+
+ mov ecx, [esp+curmatch]
+
+; uInt wmask = s->w_mask;
+; unsigned chain_length = s->max_chain_length;
+; if (s->prev_length >= s->good_match) {
+; chain_length >>= 2;
+; }
+
+ mov eax, [edx].ds_prev_length
+ mov ebx, [edx].ds_good_match
+ cmp eax, ebx
+ mov eax, [edx].ds_w_mask
+ mov ebx, [edx].ds_max_chain_length
+ jl SHORT LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+; chainlen is decremented once beforehand so that the function can
+; use the sign flag instead of the zero flag for the exit test.
+; It is then shifted into the high word, to make room for the wmask
+; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+ mov [esp+chainlenwmask], ebx
+
+; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ mov eax, [edx].ds_nice_match
+ mov ebx, [edx].ds_lookahead
+ cmp ebx, eax
+ jl SHORT LookaheadLess
+ mov ebx, eax
+LookaheadLess:
+ mov [esp+nicematch], ebx
+
+;/* register Bytef *scan = s->window + s->strstart; */
+
+ mov esi, [edx].ds_window
+ mov [esp+window], esi
+ mov ebp, [edx].ds_strstart
+ lea edi, [esi+ebp]
+ mov [esp+scan],edi
+
+;/* Determine how many bytes the scan ptr is off from being */
+;/* dword-aligned. */
+
+ mov eax, edi
+ neg eax
+ and eax, 3
+ mov [esp+scanalign], eax
+
+;/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+;/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ mov eax, [edx].ds_w_size
+ sub eax, MIN_LOOKAHEAD
+ sub ebp, eax
+ jg SHORT LimitPositive
+ xor ebp, ebp
+LimitPositive:
+
+;/* int best_len = s->prev_length; */
+
+ mov eax, [edx].ds_prev_length
+ mov [esp+bestlen], eax
+
+;/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ add esi, eax
+ mov [esp+windowbestlen], esi
+
+;/* register ush scan_start = *(ushf*)scan; */
+;/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+;/* Posf *prev = s->prev; */
+
+ movzx ebx, WORD PTR[edi]
+ mov [esp+scanstart], ebx
+ movzx ebx, WORD PTR[eax+edi-1]
+ mov [esp+scanend], ebx
+ mov edi, [edx].ds_prev
+
+;/* Jump into the main loop. */
+
+ mov edx, [esp+chainlenwmask]
+ jmp SHORT LoopEntry
+
+;/* do {
+; * match = s->window + cur_match;
+; * if (*(ushf*)(match+best_len-1) != scan_end ||
+; * *(ushf*)match != scan_start) continue;
+; * [...]
+; * } while ((cur_match = prev[cur_match & wmask]) > limit
+; * && --chain_length != 0);
+; *
+; * Here is the inner loop of the function. The function will spend the
+; * majority of its time in this loop, and majority of that time will
+; * be spent in the first ten instructions.
+; *
+; * Within this loop:
+; * %ebx = scanend
+; * %ecx = curmatch
+; * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+; * %esi = windowbestlen - i.e., (window + bestlen)
+; * %edi = prev
+; * %ebp = limit
+; */
+
+ ALIGN 4
+LookupLoop:
+ and ecx, edx
+ movzx ecx, WORD PTR[edi+ecx*2]
+ cmp ecx, ebp
+ jbe LeaveNow
+ sub edx, 000010000H
+ js LeaveNow
+
+LoopEntry:
+ movzx eax, WORD PTR[esi+ecx-1]
+ cmp eax, ebx
+ jnz SHORT LookupLoop
+
+ mov eax, [esp+window]
+ movzx eax, WORD PTR[eax+ecx]
+ cmp eax, [esp+scanstart]
+ jnz SHORT LookupLoop
+
+;/* Store the current value of chainlen. */
+
+ mov [esp+chainlenwmask], edx
+
+;/* Point %edi to the string under scrutiny, and %esi to the string we */
+;/* are hoping to match it up with. In actuality, %esi and %edi are */
+;/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+;/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ mov esi, [esp+window]
+ mov edi, [esp+scan]
+ add esi, ecx
+ mov eax, [esp+scanalign]
+ mov edx, -MAX_MATCH_8
+ lea edi, [edi+eax+MAX_MATCH_8]
+ lea esi, [esi+eax+MAX_MATCH_8]
+
+;/* Test the strings for equality, 8 bytes at a time. At the end,
+; * adjust %edx so that it is offset to the exact byte that mismatched.
+; *
+; * We already know at this point that the first three bytes of the
+; * strings match each other, and they can be safely passed over before
+; * starting the compare loop. So what this code does is skip over 0-3
+; * bytes, as much as necessary in order to dword-align the %edi
+; * pointer. (%esi will still be misaligned three times out of four.)
+; *
+; * It should be confessed that this loop usually does not represent
+; * much of the total running time. Replacing it with a more
+; * straightforward "rep cmpsb" would not drastically degrade
+; * performance.
+; */
+
+LoopCmps:
+ mov eax, DWORD PTR[esi+edx]
+ xor eax, DWORD PTR[edi+edx]
+ jnz SHORT LeaveLoopCmps
+
+ mov eax, DWORD PTR[esi+edx+4]
+ xor eax, DWORD PTR[edi+edx+4]
+ jnz SHORT LeaveLoopCmps4
+
+ add edx, 8
+ jnz SHORT LoopCmps
+ jmp LenMaximum
+ ALIGN 4
+
+LeaveLoopCmps4:
+ add edx, 4
+
+LeaveLoopCmps:
+ test eax, 00000FFFFH
+ jnz SHORT LenLower
+
+ add edx, 2
+ shr eax, 16
+
+LenLower:
+ sub al, 1
+ adc edx, 0
+
+;/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+;/* then automatically accept it as the best possible match and leave. */
+
+ lea eax, [edi+edx]
+ mov edi, [esp+scan]
+ sub eax, edi
+ cmp eax, MAX_MATCH
+ jge SHORT LenMaximum
+
+;/* If the length of the match is not longer than the best match we */
+;/* have so far, then forget it and return to the lookup loop. */
+
+ mov edx, [esp+deflatestate]
+ mov ebx, [esp+bestlen]
+ cmp eax, ebx
+ jg SHORT LongerMatch
+ mov esi, [esp+windowbestlen]
+ mov edi, [edx].ds_prev
+ mov ebx, [esp+scanend]
+ mov edx, [esp+chainlenwmask]
+ jmp LookupLoop
+ ALIGN 4
+
+;/* s->match_start = cur_match; */
+;/* best_len = len; */
+;/* if (len >= nice_match) break; */
+;/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch:
+ mov ebx, [esp+nicematch]
+ mov [esp+bestlen], eax
+ mov [edx].ds_match_start, ecx
+ cmp eax, ebx
+ jge SHORT LeaveNow
+ mov esi, [esp+window]
+ add esi, eax
+ mov [esp+windowbestlen], esi
+ movzx ebx, WORD PTR[edi+eax-1]
+ mov edi, [edx].ds_prev
+ mov [esp+scanend], ebx
+ mov edx, [esp+chainlenwmask]
+ jmp LookupLoop
+ ALIGN 4
+
+;/* Accept the current string, with the maximum possible length. */
+
+LenMaximum:
+ mov edx, [esp+deflatestate]
+ mov DWORD PTR[esp+bestlen], MAX_MATCH
+ mov [edx].ds_match_start, ecx
+
+;/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+;/* return s->lookahead; */
+
+LeaveNow:
+ mov edx, [esp+deflatestate]
+ mov ebx, [esp+bestlen]
+ mov eax, [edx].ds_lookahead
+ cmp ebx, eax
+ jg SHORT LookaheadRet
+ mov eax, ebx
+LookaheadRet:
+
+; Restore the stack and return from whence we came.
+
+ add esp, varsize
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+
+_longest_match ENDP
+
+_TEXT ENDS
+END
diff --git a/zlib/contrib/masmx64/bld_ml64.bat b/zlib/contrib/masmx64/bld_ml64.bat
new file mode 100644
index 0000000..8f9343d
--- /dev/null
+++ b/zlib/contrib/masmx64/bld_ml64.bat
@@ -0,0 +1,2 @@
+ml64.exe /Flinffasx64 /c /Zi inffasx64.asm
+ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
diff --git a/zlib/contrib/masmx64/gvmat64.asm b/zlib/contrib/masmx64/gvmat64.asm
new file mode 100644
index 0000000..790d655
--- /dev/null
+++ b/zlib/contrib/masmx64/gvmat64.asm
@@ -0,0 +1,513 @@
+;uInt longest_match_x64(
+; deflate_state *s,
+; IPos cur_match); /* current match */
+
+; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-2005 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
+;
+; File written by Gilles Vollant, by converting to assembly the longest_match
+; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+;
+; and by taking inspiration on asm686 with masm, optimised assembly code
+; from Brian Raiter, written 1998
+;
+; http://www.zlib.net
+; http://www.winimage.com/zLibDll
+; http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; to compile this file for infozip Zip, I use option:
+; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm
+;
+; to compile this file for zLib, I use option:
+; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
+; Be carrefull to adapt zlib1222add below to your version of zLib
+; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change
+; value of zlib1222add later)
+;
+; This file compile with Microsoft Macro Assembler (x64) for AMD64
+;
+; ml64.exe is given with Visual Studio 2005 and Windows 2003 server DDK
+;
+; (you can get Windows 2003 server DDK with ml64 and cl for AMD64 from
+; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)
+;
+
+
+;uInt longest_match(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; /* current match */
+.code
+longest_match PROC
+
+
+;LocalVarsSize equ 88
+ LocalVarsSize equ 72
+
+; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
+; free register : r14,r15
+; register can be saved : rsp
+
+ chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len
+ ; low word: s->wmask
+;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10
+;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11
+;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w
+;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx
+;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13
+;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d
+;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9
+IFDEF INFOZIP
+ELSE
+ nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size
+ENDIF
+
+save_rdi equ rsp + 24 - LocalVarsSize
+save_rsi equ rsp + 32 - LocalVarsSize
+save_rbx equ rsp + 40 - LocalVarsSize
+save_rbp equ rsp + 48 - LocalVarsSize
+save_r12 equ rsp + 56 - LocalVarsSize
+save_r13 equ rsp + 64 - LocalVarsSize
+;save_r14 equ rsp + 72 - LocalVarsSize
+;save_r15 equ rsp + 80 - LocalVarsSize
+
+
+
+; all the +4 offsets are due to the addition of pending_buf_size (in zlib
+; in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, remove the +4).
+; Note : these value are good with a 8 bytes boundary pack structure
+
+
+ MAX_MATCH equ 258
+ MIN_MATCH equ 3
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+
+
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+; all the +zlib1222add offsets are due to the addition of fields
+; in zlib in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+
+
+IFDEF INFOZIP
+
+_DATA SEGMENT
+COMM window_size:DWORD
+; WMask ; 7fff
+COMM window:BYTE:010040H
+COMM prev:WORD:08000H
+; MatchLen : unused
+; PrevMatch : unused
+COMM strstart:DWORD
+COMM match_start:DWORD
+; Lookahead : ignore
+COMM prev_length:DWORD ; PrevLen
+COMM max_chain_length:DWORD
+COMM good_match:DWORD
+COMM nice_match:DWORD
+prev_ad equ OFFSET prev
+window_ad equ OFFSET window
+nicematch equ nice_match
+_DATA ENDS
+WMask equ 07fffh
+
+ELSE
+
+ IFNDEF zlib1222add
+ zlib1222add equ 8
+ ENDIF
+dsWSize equ 56+zlib1222add+(zlib1222add/2)
+dsWMask equ 64+zlib1222add+(zlib1222add/2)
+dsWindow equ 72+zlib1222add
+dsPrev equ 88+zlib1222add
+dsMatchLen equ 128+zlib1222add
+dsPrevMatch equ 132+zlib1222add
+dsStrStart equ 140+zlib1222add
+dsMatchStart equ 144+zlib1222add
+dsLookahead equ 148+zlib1222add
+dsPrevLen equ 152+zlib1222add
+dsMaxChainLen equ 156+zlib1222add
+dsGoodMatch equ 172+zlib1222add
+dsNiceMatch equ 176+zlib1222add
+
+window_size equ [ rcx + dsWSize]
+WMask equ [ rcx + dsWMask]
+window_ad equ [ rcx + dsWindow]
+prev_ad equ [ rcx + dsPrev]
+strstart equ [ rcx + dsStrStart]
+match_start equ [ rcx + dsMatchStart]
+Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip
+prev_length equ [ rcx + dsPrevLen]
+max_chain_length equ [ rcx + dsMaxChainLen]
+good_match equ [ rcx + dsGoodMatch]
+nice_match equ [ rcx + dsNiceMatch]
+ENDIF
+
+; parameter 1 in r8(deflate state s), param 2 in rdx (cur match)
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
+
+
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+
+;;; Retrieve the function arguments. r8d will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
+
+; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
+
+ mov [save_rdi],rdi
+ mov [save_rsi],rsi
+ mov [save_rbx],rbx
+ mov [save_rbp],rbp
+IFDEF INFOZIP
+ mov r8d,ecx
+ELSE
+ mov r8d,edx
+ENDIF
+ mov [save_r12],r12
+ mov [save_r13],r13
+; mov [save_r14],r14
+; mov [save_r15],r15
+
+
+;;; uInt wmask = s->w_mask;
+;;; unsigned chain_length = s->max_chain_length;
+;;; if (s->prev_length >= s->good_match) {
+;;; chain_length >>= 2;
+;;; }
+
+ mov edi, prev_length
+ mov esi, good_match
+ mov eax, WMask
+ mov ebx, max_chain_length
+ cmp edi, esi
+ jl LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+;;; chainlen is decremented once beforehand so that the function can
+;;; use the sign flag instead of the zero flag for the exit test.
+;;; It is then shifted into the high word, to make room for the wmask
+;;; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+
+;;; on zlib only
+;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+IFDEF INFOZIP
+ mov [chainlenwmask], ebx
+; on infozip nice_match = [nice_match]
+ELSE
+ mov eax, nice_match
+ mov [chainlenwmask], ebx
+ mov r10d, Lookahead
+ cmp r10d, eax
+ cmovnl r10d, eax
+ mov [nicematch],r10d
+ENDIF
+
+;;; register Bytef *scan = s->window + s->strstart;
+ mov r10, window_ad
+ mov ebp, strstart
+ lea r13, [r10 + rbp]
+
+;;; Determine how many bytes the scan ptr is off from being
+;;; dword-aligned.
+
+ mov r9,r13
+ neg r13
+ and r13,3
+
+;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
+IFDEF INFOZIP
+ mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1))
+ELSE
+ mov eax, window_size
+ sub eax, MIN_LOOKAHEAD
+ENDIF
+ xor edi,edi
+ sub ebp, eax
+
+ mov r11d, prev_length
+
+ cmovng ebp,edi
+
+;;; int best_len = s->prev_length;
+
+
+;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+ lea rsi,[r10+r11]
+
+;;; register ush scan_start = *(ushf*)scan;
+;;; register ush scan_end = *(ushf*)(scan+best_len-1);
+;;; Posf *prev = s->prev;
+
+ movzx r12d,word ptr [r9]
+ movzx ebx, word ptr [r9 + r11 - 1]
+
+ mov rdi, prev_ad
+
+;;; Jump into the main loop.
+
+ mov edx, [chainlenwmask]
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop1:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry1:
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop2:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry2:
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop4:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry4:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jnz LookupLoop1
+ jmp LookupLoopIsZero
+
+
+;;; do {
+;;; match = s->window + cur_match;
+;;; if (*(ushf*)(match+best_len-1) != scan_end ||
+;;; *(ushf*)match != scan_start) continue;
+;;; [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;; && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; r8d = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+
+LookupLoop:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jnz LookupLoop1
+LookupLoopIsZero:
+ cmp r12w, word ptr [r10 + r8]
+ jnz LookupLoop1
+
+
+;;; Store the current value of chainlen.
+ mov [chainlenwmask], edx
+
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+
+ lea rsi,[r8+r10]
+ mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8)
+ lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8]
+ lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8]
+
+ prefetcht1 [rsi+rdx]
+ prefetcht1 [rdi+rdx]
+
+
+;;; Test the strings for equality, 8 bytes at a time. At the end,
+;;; adjust rdx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (rsi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+
+
+LoopCmps:
+ mov rax, [rsi + rdx]
+ xor rax, [rdi + rdx]
+ jnz LeaveLoopCmps
+
+ mov rax, [rsi + rdx + 8]
+ xor rax, [rdi + rdx + 8]
+ jnz LeaveLoopCmps8
+
+
+ mov rax, [rsi + rdx + 8+8]
+ xor rax, [rdi + rdx + 8+8]
+ jnz LeaveLoopCmps16
+
+ add rdx,8+8+8
+
+ jmp short LoopCmps
+LeaveLoopCmps16: add rdx,8
+LeaveLoopCmps8: add rdx,8
+LeaveLoopCmps:
+
+ test eax, 0000FFFFh
+ jnz LenLower
+
+ test eax,0ffffffffh
+
+ jnz LenLower32
+
+ add rdx,4
+ shr rax,32
+ or ax,ax
+ jnz LenLower
+
+LenLower32:
+ shr eax,16
+ add rdx,2
+LenLower: sub al, 1
+ adc rdx, 0
+;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+;;; then automatically accept it as the best possible match and leave.
+
+ lea rax, [rdi + rdx]
+ sub rax, r9
+ cmp eax, MAX_MATCH
+ jge LenMaximum
+
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+;///////////////////////////////////
+
+ cmp eax, r11d
+ jg LongerMatch
+
+ lea rsi,[r10+r11]
+
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; s->match_start = cur_match;
+;;; best_len = len;
+;;; if (len >= nice_match) break;
+;;; scan_end = *(ushf*)(scan+best_len-1);
+
+LongerMatch:
+ mov r11d, eax
+ mov match_start, r8d
+ cmp eax, [nicematch]
+ jge LeaveNow
+
+ lea rsi,[r10+rax]
+
+ movzx ebx, word ptr [r9 + rax - 1]
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; Accept the current string, with the maximum possible length.
+
+LenMaximum:
+ mov r11d,MAX_MATCH
+ mov match_start, r8d
+
+;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+;;; return s->lookahead;
+
+LeaveNow:
+IFDEF INFOZIP
+ mov eax,r11d
+ELSE
+ mov eax, Lookahead
+ cmp r11d, eax
+ cmovng eax, r11d
+ENDIF
+
+;;; Restore the stack and return from whence we came.
+
+
+ mov rsi,[save_rsi]
+ mov rdi,[save_rdi]
+ mov rbx,[save_rbx]
+ mov rbp,[save_rbp]
+ mov r12,[save_r12]
+ mov r13,[save_r13]
+; mov r14,[save_r14]
+; mov r15,[save_r15]
+
+
+ ret 0
+; please don't remove this string !
+; Your can freely use gvmat64 in any free or commercial app
+; but it is far better don't remove the string in the binary!
+ db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0
+longest_match ENDP
+
+match_init PROC
+ ret 0
+match_init ENDP
+
+
+END
diff --git a/zlib/contrib/masmx64/inffas8664.c b/zlib/contrib/masmx64/inffas8664.c
new file mode 100644
index 0000000..3af764d
--- /dev/null
+++ b/zlib/contrib/masmx64/inffas8664.c
@@ -0,0 +1,186 @@
+/* inffas8664.c is a hand tuned assembler version of inffast.c - fast decoding
+ * version for AMD64 on Windows using Microsoft C compiler
+ *
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Copyright (C) 2003 Chris Anderson <christop@charm.net>
+ * Please use the copyright conditions above.
+ *
+ * 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant
+ *
+ * inffas8664.c call function inffas8664fnc in inffasx64.asm
+ * inffasx64.asm is automatically convert from AMD64 portion of inffas86.c
+ *
+ * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also
+ * slightly quicker on x86 systems because, instead of using rep movsb to copy
+ * data, it uses rep movsw, which moves data in 2-byte chunks instead of single
+ * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates
+ * from http://fedora.linux.duke.edu/fc1_x86_64
+ * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with
+ * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version,
+ * when decompressing mozilla-source-1.3.tar.gz.
+ *
+ * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from
+ * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at
+ * the moment. I have successfully compiled and tested this code with gcc2.96,
+ * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S
+ * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX
+ * enabled. I will attempt to merge the MMX code into this version. Newer
+ * versions of this and inffast.S can be found at
+ * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
+ *
+ */
+
+#include <stdio.h>
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* Mark Adler's comments from inffast.c: */
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+
+
+
+ typedef struct inffast_ar {
+/* 64 32 x86 x86_64 */
+/* ar offset register */
+/* 0 0 */ void *esp; /* esp save */
+/* 8 4 */ void *ebp; /* ebp save */
+/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */
+/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */
+/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */
+/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */
+/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */
+/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */
+/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */
+/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */
+/* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */
+/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */
+/* 92 48 */ unsigned wsize; /* window size */
+/* 96 52 */ unsigned write; /* window write index */
+/*100 56 */ unsigned lmask; /* r12 mask for lcode */
+/*104 60 */ unsigned dmask; /* r13 mask for dcode */
+/*108 64 */ unsigned len; /* r14 match length */
+/*112 68 */ unsigned dist; /* r15 match distance */
+/*116 72 */ unsigned status; /* set when state chng*/
+ } type_ar;
+#ifdef ASMINF
+
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ type_ar ar;
+ void inffas8664fnc(struct inffast_ar * par);
+
+
+
+#if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64))
+#define PAD_AVAIL_IN 6
+#define PAD_AVAIL_OUT 258
+#else
+#define PAD_AVAIL_IN 5
+#define PAD_AVAIL_OUT 257
+#endif
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+
+ ar.in = strm->next_in;
+ ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN);
+ ar.out = strm->next_out;
+ ar.beg = ar.out - (start - strm->avail_out);
+ ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT);
+ ar.wsize = state->wsize;
+ ar.write = state->write;
+ ar.window = state->window;
+ ar.hold = state->hold;
+ ar.bits = state->bits;
+ ar.lcode = state->lencode;
+ ar.dcode = state->distcode;
+ ar.lmask = (1U << state->lenbits) - 1;
+ ar.dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+
+ /* align in on 1/2 hold size boundary */
+ while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) {
+ ar.hold += (unsigned long)*ar.in++ << ar.bits;
+ ar.bits += 8;
+ }
+
+ inffas8664fnc(&ar);
+
+ if (ar.status > 1) {
+ if (ar.status == 2)
+ strm->msg = "invalid literal/length code";
+ else if (ar.status == 3)
+ strm->msg = "invalid distance code";
+ else
+ strm->msg = "invalid distance too far back";
+ state->mode = BAD;
+ }
+ else if ( ar.status == 1 ) {
+ state->mode = TYPE;
+ }
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ ar.len = ar.bits >> 3;
+ ar.in -= ar.len;
+ ar.bits -= ar.len << 3;
+ ar.hold &= (1U << ar.bits) - 1;
+
+ /* update state and return */
+ strm->next_in = ar.in;
+ strm->next_out = ar.out;
+ strm->avail_in = (unsigned)(ar.in < ar.last ?
+ PAD_AVAIL_IN + (ar.last - ar.in) :
+ PAD_AVAIL_IN - (ar.in - ar.last));
+ strm->avail_out = (unsigned)(ar.out < ar.end ?
+ PAD_AVAIL_OUT + (ar.end - ar.out) :
+ PAD_AVAIL_OUT - (ar.out - ar.end));
+ state->hold = (unsigned long)ar.hold;
+ state->bits = ar.bits;
+ return;
+}
+
+#endif
diff --git a/zlib/contrib/masmx64/inffasx64.asm b/zlib/contrib/masmx64/inffasx64.asm
new file mode 100644
index 0000000..b5d93a2
--- /dev/null
+++ b/zlib/contrib/masmx64/inffasx64.asm
@@ -0,0 +1,392 @@
+; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding
+; version for AMD64 on Windows using Microsoft C compiler
+;
+; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c
+; inffasx64.asm is called by inffas8664.c, which contain more info.
+
+
+; to compile this file, I use option
+; ml64.exe /Flinffasx64 /c /Zi inffasx64.asm
+; with Microsoft Macro Assembler (x64) for AMD64
+;
+; ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK
+;
+; (you can get Windows 2003 server DDK with ml64 and cl.exe for AMD64 from
+; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)
+;
+
+.code
+inffas8664fnc PROC
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch.
+
+
+ mov [rsp-8],rsi
+ mov [rsp-16],rdi
+ mov [rsp-24],r12
+ mov [rsp-32],r13
+ mov [rsp-40],r14
+ mov [rsp-48],r15
+ mov [rsp-56],rbx
+
+ mov rax,rcx
+
+ mov [rax+8], rbp ; /* save regs rbp and rsp */
+ mov [rax], rsp
+
+ mov rsp, rax ; /* make rsp point to &ar */
+
+ mov rsi, [rsp+16] ; /* rsi = in */
+ mov rdi, [rsp+32] ; /* rdi = out */
+ mov r9, [rsp+24] ; /* r9 = last */
+ mov r10, [rsp+48] ; /* r10 = end */
+ mov rbp, [rsp+64] ; /* rbp = lcode */
+ mov r11, [rsp+72] ; /* r11 = dcode */
+ mov rdx, [rsp+80] ; /* rdx = hold */
+ mov ebx, [rsp+88] ; /* ebx = bits */
+ mov r12d, [rsp+100] ; /* r12d = lmask */
+ mov r13d, [rsp+104] ; /* r13d = dmask */
+ ; /* r14d = len */
+ ; /* r15d = dist */
+
+
+ cld
+ cmp r10, rdi
+ je L_one_time ; /* if only one decode left */
+ cmp r9, rsi
+
+ jne L_do_loop
+
+
+L_one_time:
+ mov r8, r12 ; /* r8 = lmask */
+ cmp bl, 32
+ ja L_get_length_code_one_time
+
+ lodsd ; /* eax = *(uint *)in++ */
+ mov cl, bl ; /* cl = bits, needs it for shifting */
+ add bl, 32 ; /* bits += 32 */
+ shl rax, cl
+ or rdx, rax ; /* hold |= *((uint *)in)++ << bits */
+ jmp L_get_length_code_one_time
+
+ALIGN 4
+L_while_test:
+ cmp r10, rdi
+ jbe L_break_loop
+ cmp r9, rsi
+ jbe L_break_loop
+
+L_do_loop:
+ mov r8, r12 ; /* r8 = lmask */
+ cmp bl, 32
+ ja L_get_length_code ; /* if (32 < bits) */
+
+ lodsd ; /* eax = *(uint *)in++ */
+ mov cl, bl ; /* cl = bits, needs it for shifting */
+ add bl, 32 ; /* bits += 32 */
+ shl rax, cl
+ or rdx, rax ; /* hold |= *((uint *)in)++ << bits */
+
+L_get_length_code:
+ and r8, rdx ; /* r8 &= hold */
+ mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */
+
+ mov cl, ah ; /* cl = this.bits */
+ sub bl, ah ; /* bits -= this.bits */
+ shr rdx, cl ; /* hold >>= this.bits */
+
+ test al, al
+ jnz L_test_for_length_base ; /* if (op != 0) 45.7% */
+
+ mov r8, r12 ; /* r8 = lmask */
+ shr eax, 16 ; /* output this.val char */
+ stosb
+
+L_get_length_code_one_time:
+ and r8, rdx ; /* r8 &= hold */
+ mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */
+
+L_dolen:
+ mov cl, ah ; /* cl = this.bits */
+ sub bl, ah ; /* bits -= this.bits */
+ shr rdx, cl ; /* hold >>= this.bits */
+
+ test al, al
+ jnz L_test_for_length_base ; /* if (op != 0) 45.7% */
+
+ shr eax, 16 ; /* output this.val char */
+ stosb
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_length_base:
+ mov r14d, eax ; /* len = this */
+ shr r14d, 16 ; /* len = this.val */
+ mov cl, al
+
+ test al, 16
+ jz L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */
+ and cl, 15 ; /* op &= 15 */
+ jz L_decode_distance ; /* if (!op) */
+
+L_add_bits_to_len:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx ; /* eax &= hold */
+ shr rdx, cl
+ add r14d, eax ; /* len += hold & mask[op] */
+
+L_decode_distance:
+ mov r8, r13 ; /* r8 = dmask */
+ cmp bl, 32
+ ja L_get_distance_code ; /* if (32 < bits) */
+
+ lodsd ; /* eax = *(uint *)in++ */
+ mov cl, bl ; /* cl = bits, needs it for shifting */
+ add bl, 32 ; /* bits += 32 */
+ shl rax, cl
+ or rdx, rax ; /* hold |= *((uint *)in)++ << bits */
+
+L_get_distance_code:
+ and r8, rdx ; /* r8 &= hold */
+ mov eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */
+
+L_dodist:
+ mov r15d, eax ; /* dist = this */
+ shr r15d, 16 ; /* dist = this.val */
+ mov cl, ah
+ sub bl, ah ; /* bits -= this.bits */
+ shr rdx, cl ; /* hold >>= this.bits */
+ mov cl, al ; /* cl = this.op */
+
+ test al, 16 ; /* if ((op & 16) == 0) */
+ jz L_test_for_second_level_dist
+ and cl, 15 ; /* op &= 15 */
+ jz L_check_dist_one
+
+L_add_bits_to_dist:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax ; /* (1 << op) - 1 */
+ and eax, edx ; /* eax &= hold */
+ shr rdx, cl
+ add r15d, eax ; /* dist += hold & ((1 << op) - 1) */
+
+L_check_window:
+ mov r8, rsi ; /* save in so from can use it's reg */
+ mov rax, rdi
+ sub rax, [rsp+40] ; /* nbytes = out - beg */
+
+ cmp eax, r15d
+ jb L_clip_window ; /* if (dist > nbytes) 4.2% */
+
+ mov ecx, r14d ; /* ecx = len */
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = out - dist */
+
+ sar ecx, 1
+ jnc L_copy_two ; /* if len % 2 == 0 */
+
+ rep movsw
+ mov al, [rsi]
+ mov [rdi], al
+ inc rdi
+
+ mov rsi, r8 ; /* move in back to %rsi, toss from */
+ jmp L_while_test
+
+L_copy_two:
+ rep movsw
+ mov rsi, r8 ; /* move in back to %rsi, toss from */
+ jmp L_while_test
+
+ALIGN 4
+L_check_dist_one:
+ cmp r15d, 1 ; /* if dist 1, is a memset */
+ jne L_check_window
+ cmp [rsp+40], rdi ; /* if out == beg, outside window */
+ je L_check_window
+
+ mov ecx, r14d ; /* ecx = len */
+ mov al, [rdi-1]
+ mov ah, al
+
+ sar ecx, 1
+ jnc L_set_two
+ mov [rdi], al
+ inc rdi
+
+L_set_two:
+ rep stosw
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_second_level_length:
+ test al, 64
+ jnz L_test_for_end_of_block ; /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx ; /* eax &= hold */
+ add eax, r14d ; /* eax += len */
+ mov eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/
+ jmp L_dolen
+
+ALIGN 4
+L_test_for_second_level_dist:
+ test al, 64
+ jnz L_invalid_distance_code ; /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx ; /* eax &= hold */
+ add eax, r15d ; /* eax += dist */
+ mov eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/
+ jmp L_dodist
+
+ALIGN 4
+L_clip_window:
+ mov ecx, eax ; /* ecx = nbytes */
+ mov eax, [rsp+92] ; /* eax = wsize, prepare for dist cmp */
+ neg ecx ; /* nbytes = -nbytes */
+
+ cmp eax, r15d
+ jb L_invalid_distance_too_far ; /* if (dist > wsize) */
+
+ add ecx, r15d ; /* nbytes = dist - nbytes */
+ cmp dword ptr [rsp+96], 0
+ jne L_wrap_around_window ; /* if (write != 0) */
+
+ mov rsi, [rsp+56] ; /* from = window */
+ sub eax, ecx ; /* eax -= nbytes */
+ add rsi, rax ; /* from += wsize - nbytes */
+
+ mov eax, r14d ; /* eax = len */
+ cmp r14d, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* eax -= nbytes */
+ rep movsb
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = &out[ -dist ] */
+ jmp L_do_copy
+
+ALIGN 4
+L_wrap_around_window:
+ mov eax, [rsp+96] ; /* eax = write */
+ cmp ecx, eax
+ jbe L_contiguous_in_window ; /* if (write >= nbytes) */
+
+ mov esi, [rsp+92] ; /* from = wsize */
+ add rsi, [rsp+56] ; /* from += window */
+ add rsi, rax ; /* from += write */
+ sub rsi, rcx ; /* from -= nbytes */
+ sub ecx, eax ; /* nbytes -= write */
+
+ mov eax, r14d ; /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* len -= nbytes */
+ rep movsb
+ mov rsi, [rsp+56] ; /* from = window */
+ mov ecx, [rsp+96] ; /* nbytes = write */
+ cmp eax, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* len -= nbytes */
+ rep movsb
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_contiguous_in_window:
+ mov rsi, [rsp+56] ; /* rsi = window */
+ add rsi, rax
+ sub rsi, rcx ; /* from += write - nbytes */
+
+ mov eax, r14d ; /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* len -= nbytes */
+ rep movsb
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = out - dist */
+ jmp L_do_copy ; /* if (nbytes >= len) */
+
+ALIGN 4
+L_do_copy:
+ mov ecx, eax ; /* ecx = len */
+ rep movsb
+
+ mov rsi, r8 ; /* move in back to %esi, toss from */
+ jmp L_while_test
+
+L_test_for_end_of_block:
+ test al, 32
+ jz L_invalid_literal_length_code
+ mov dword ptr [rsp+116], 1
+ jmp L_break_loop_with_status
+
+L_invalid_literal_length_code:
+ mov dword ptr [rsp+116], 2
+ jmp L_break_loop_with_status
+
+L_invalid_distance_code:
+ mov dword ptr [rsp+116], 3
+ jmp L_break_loop_with_status
+
+L_invalid_distance_too_far:
+ mov dword ptr [rsp+116], 4
+ jmp L_break_loop_with_status
+
+L_break_loop:
+ mov dword ptr [rsp+116], 0
+
+L_break_loop_with_status:
+; /* put in, out, bits, and hold back into ar and pop esp */
+ mov [rsp+16], rsi ; /* in */
+ mov [rsp+32], rdi ; /* out */
+ mov [rsp+88], ebx ; /* bits */
+ mov [rsp+80], rdx ; /* hold */
+
+ mov rax, [rsp] ; /* restore rbp and rsp */
+ mov rbp, [rsp+8]
+ mov rsp, rax
+
+
+
+ mov rsi,[rsp-8]
+ mov rdi,[rsp-16]
+ mov r12,[rsp-24]
+ mov r13,[rsp-32]
+ mov r14,[rsp-40]
+ mov r15,[rsp-48]
+ mov rbx,[rsp-56]
+
+ ret 0
+; :
+; : "m" (ar)
+; : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi",
+; "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
+; );
+
+inffas8664fnc ENDP
+;_TEXT ENDS
+END
diff --git a/zlib/contrib/masmx64/readme.txt b/zlib/contrib/masmx64/readme.txt
new file mode 100644
index 0000000..ee03115
--- /dev/null
+++ b/zlib/contrib/masmx64/readme.txt
@@ -0,0 +1,28 @@
+Summary
+-------
+This directory contains ASM implementations of the functions
+longest_match() and inflate_fast(), for 64 bits x86 (both AMD64 and Intel EM64t),
+for use with Microsoft Macro Assembler (x64) for AMD64 and Microsoft C++ 64 bits.
+
+gvmat64.asm is written by Gilles Vollant (2005), by using Brian Raiter 686/32 bits
+ assembly optimized version from Jean-loup Gailly original longest_match function
+
+inffasx64.asm and inffas8664.c were written by Chris Anderson, by optimizing
+ original function from Mark Adler
+
+Use instructions
+----------------
+Copy these files into the zlib source directory.
+
+define ASMV and ASMINF in your project. Include inffas8664.c in your source tree,
+and inffasx64.obj and gvmat64.obj as object to link.
+
+
+Build instructions
+------------------
+run bld_64.bat with Microsoft Macro Assembler (x64) for AMD64 (ml64.exe)
+
+ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK
+
+You can get Windows 2003 server DDK with ml64 and cl for AMD64 from
+ http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)
diff --git a/zlib/contrib/masmx86/bld_ml32.bat b/zlib/contrib/masmx86/bld_ml32.bat
new file mode 100644
index 0000000..99144d0
--- /dev/null
+++ b/zlib/contrib/masmx86/bld_ml32.bat
@@ -0,0 +1,2 @@
+ml /coff /Zi /c /Flgvmat32.lst gvmat32.asm
+ml /coff /Zi /c /Flinffas32.lst inffas32.asm
diff --git a/zlib/contrib/masmx86/gvmat32.asm b/zlib/contrib/masmx86/gvmat32.asm
new file mode 100644
index 0000000..874bb2d
--- /dev/null
+++ b/zlib/contrib/masmx86/gvmat32.asm
@@ -0,0 +1,972 @@
+; gvmat32.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant.
+; File written by Gilles Vollant, by modifiying the longest_match
+; from Jean-loup Gailly in deflate.c
+;
+; http://www.zlib.net
+; http://www.winimage.com/zLibDll
+; http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; For Visual C++ 4.x and higher and ML 6.x and higher
+; ml.exe is in directory \MASM611C of Win95 DDK
+; ml.exe is also distributed in http://www.masm32.com/masmdl.htm
+; and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/
+;
+; this file contain two implementation of longest_match
+;
+; longest_match_7fff : written 1996 by Gilles Vollant optimized for
+; first Pentium. Assume s->w_mask == 0x7fff
+; longest_match_686 : written by Brian raiter (1998), optimized for Pentium Pro
+;
+; for using an seembly version of longest_match, you need define ASMV in project
+; There is two way in using gvmat32.asm
+;
+; A) Suggested method
+; if you want include both longest_match_7fff and longest_match_686
+; compile the asm file running
+; ml /coff /Zi /Flgvmat32.lst /c gvmat32.asm
+; and include gvmat32c.c in your project
+; if you have an old cpu (386,486 or first Pentium) and s->w_mask==0x7fff,
+; longest_match_7fff will be used
+; if you have a more modern CPU (Pentium Pro, II and higher)
+; longest_match_686 will be used
+; on old cpu with s->w_mask!=0x7fff, longest_match_686 will be used,
+; but this is not a sitation you'll find often
+;
+; B) Alternative
+; if you are not interresed in old cpu performance and want the smaller
+; binaries possible
+;
+; compile the asm file running
+; ml /coff /Zi /c /Flgvmat32.lst /DNOOLDPENTIUMCODE gvmat32.asm
+; and do not include gvmat32c.c in your project (ou define also
+; NOOLDPENTIUMCODE)
+;
+; note : as I known, longest_match_686 is very faster than longest_match_7fff
+; on pentium Pro/II/III, faster (but less) in P4, but it seem
+; longest_match_7fff can be faster (very very litte) on AMD Athlon64/K8
+;
+; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2
+
+;uInt longest_match_7fff(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; /* current match */
+
+ NbStack equ 76
+ cur_match equ dword ptr[esp+NbStack-0]
+ str_s equ dword ptr[esp+NbStack-4]
+; 5 dword on top (ret,ebp,esi,edi,ebx)
+ adrret equ dword ptr[esp+NbStack-8]
+ pushebp equ dword ptr[esp+NbStack-12]
+ pushedi equ dword ptr[esp+NbStack-16]
+ pushesi equ dword ptr[esp+NbStack-20]
+ pushebx equ dword ptr[esp+NbStack-24]
+
+ chain_length equ dword ptr [esp+NbStack-28]
+ limit equ dword ptr [esp+NbStack-32]
+ best_len equ dword ptr [esp+NbStack-36]
+ window equ dword ptr [esp+NbStack-40]
+ prev equ dword ptr [esp+NbStack-44]
+ scan_start equ word ptr [esp+NbStack-48]
+ wmask equ dword ptr [esp+NbStack-52]
+ match_start_ptr equ dword ptr [esp+NbStack-56]
+ nice_match equ dword ptr [esp+NbStack-60]
+ scan equ dword ptr [esp+NbStack-64]
+
+ windowlen equ dword ptr [esp+NbStack-68]
+ match_start equ dword ptr [esp+NbStack-72]
+ strend equ dword ptr [esp+NbStack-76]
+ NbStackAdd equ (NbStack-24)
+
+ .386p
+
+ name gvmatch
+ .MODEL FLAT
+
+
+
+; all the +zlib1222add offsets are due to the addition of fields
+; in zlib in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+
+ zlib1222add equ 8
+
+; Note : these value are good with a 8 bytes boundary pack structure
+ dep_chain_length equ 74h+zlib1222add
+ dep_window equ 30h+zlib1222add
+ dep_strstart equ 64h+zlib1222add
+ dep_prev_length equ 70h+zlib1222add
+ dep_nice_match equ 88h+zlib1222add
+ dep_w_size equ 24h+zlib1222add
+ dep_prev equ 38h+zlib1222add
+ dep_w_mask equ 2ch+zlib1222add
+ dep_good_match equ 84h+zlib1222add
+ dep_match_start equ 68h+zlib1222add
+ dep_lookahead equ 6ch+zlib1222add
+
+
+_TEXT segment
+
+IFDEF NOUNDERLINE
+ IFDEF NOOLDPENTIUMCODE
+ public longest_match
+ public match_init
+ ELSE
+ public longest_match_7fff
+ public cpudetect32
+ public longest_match_686
+ ENDIF
+ELSE
+ IFDEF NOOLDPENTIUMCODE
+ public _longest_match
+ public _match_init
+ ELSE
+ public _longest_match_7fff
+ public _cpudetect32
+ public _longest_match_686
+ ENDIF
+ENDIF
+
+ MAX_MATCH equ 258
+ MIN_MATCH equ 3
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+
+
+
+IFNDEF NOOLDPENTIUMCODE
+IFDEF NOUNDERLINE
+longest_match_7fff proc near
+ELSE
+_longest_match_7fff proc near
+ENDIF
+
+ mov edx,[esp+4]
+
+
+
+ push ebp
+ push edi
+ push esi
+ push ebx
+
+ sub esp,NbStackAdd
+
+; initialize or check the variables used in match.asm.
+ mov ebp,edx
+
+; chain_length = s->max_chain_length
+; if (prev_length>=good_match) chain_length >>= 2
+ mov edx,[ebp+dep_chain_length]
+ mov ebx,[ebp+dep_prev_length]
+ cmp [ebp+dep_good_match],ebx
+ ja noshr
+ shr edx,2
+noshr:
+; we increment chain_length because in the asm, the --chain_lenght is in the beginning of the loop
+ inc edx
+ mov edi,[ebp+dep_nice_match]
+ mov chain_length,edx
+ mov eax,[ebp+dep_lookahead]
+ cmp eax,edi
+; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+ jae nolookaheadnicematch
+ mov edi,eax
+nolookaheadnicematch:
+; best_len = s->prev_length
+ mov best_len,ebx
+
+; window = s->window
+ mov esi,[ebp+dep_window]
+ mov ecx,[ebp+dep_strstart]
+ mov window,esi
+
+ mov nice_match,edi
+; scan = window + strstart
+ add esi,ecx
+ mov scan,esi
+; dx = *window
+ mov dx,word ptr [esi]
+; bx = *(window+best_len-1)
+ mov bx,word ptr [esi+ebx-1]
+ add esi,MAX_MATCH-1
+; scan_start = *scan
+ mov scan_start,dx
+; strend = scan + MAX_MATCH-1
+ mov strend,esi
+; bx = scan_end = *(window+best_len-1)
+
+; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+; s->strstart - (IPos)MAX_DIST(s) : NIL;
+
+ mov esi,[ebp+dep_w_size]
+ sub esi,MIN_LOOKAHEAD
+; here esi = MAX_DIST(s)
+ sub ecx,esi
+ ja nodist
+ xor ecx,ecx
+nodist:
+ mov limit,ecx
+
+; prev = s->prev
+ mov edx,[ebp+dep_prev]
+ mov prev,edx
+
+;
+ mov edx,dword ptr [ebp+dep_match_start]
+ mov bp,scan_start
+ mov eax,cur_match
+ mov match_start,edx
+
+ mov edx,window
+ mov edi,edx
+ add edi,best_len
+ mov esi,prev
+ dec edi
+; windowlen = window + best_len -1
+ mov windowlen,edi
+
+ jmp beginloop2
+ align 4
+
+; here, in the loop
+; eax = ax = cur_match
+; ecx = limit
+; bx = scan_end
+; bp = scan_start
+; edi = windowlen (window + best_len -1)
+; esi = prev
+
+
+;// here; chain_length <=16
+normalbeg0add16:
+ add chain_length,16
+ jz exitloop
+normalbeg0:
+ cmp word ptr[edi+eax],bx
+ je normalbeg2noroll
+rcontlabnoroll:
+; cur_match = prev[cur_match & wmask]
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+; if cur_match > limit, go to exitloop
+ cmp ecx,eax
+ jnb exitloop
+; if --chain_length != 0, go to exitloop
+ dec chain_length
+ jnz normalbeg0
+ jmp exitloop
+
+normalbeg2noroll:
+; if (scan_start==*(cur_match+window)) goto normalbeg2
+ cmp bp,word ptr[edx+eax]
+ jne rcontlabnoroll
+ jmp normalbeg2
+
+contloop3:
+ mov edi,windowlen
+
+; cur_match = prev[cur_match & wmask]
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+; if cur_match > limit, go to exitloop
+ cmp ecx,eax
+jnbexitloopshort1:
+ jnb exitloop
+; if --chain_length != 0, go to exitloop
+
+
+; begin the main loop
+beginloop2:
+ sub chain_length,16+1
+; if chain_length <=16, don't use the unrolled loop
+ jna normalbeg0add16
+
+do16:
+ cmp word ptr[edi+eax],bx
+ je normalbeg2dc0
+
+maccn MACRO lab
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+ cmp ecx,eax
+ jnb exitloop
+ cmp word ptr[edi+eax],bx
+ je lab
+ ENDM
+
+rcontloop0:
+ maccn normalbeg2dc1
+
+rcontloop1:
+ maccn normalbeg2dc2
+
+rcontloop2:
+ maccn normalbeg2dc3
+
+rcontloop3:
+ maccn normalbeg2dc4
+
+rcontloop4:
+ maccn normalbeg2dc5
+
+rcontloop5:
+ maccn normalbeg2dc6
+
+rcontloop6:
+ maccn normalbeg2dc7
+
+rcontloop7:
+ maccn normalbeg2dc8
+
+rcontloop8:
+ maccn normalbeg2dc9
+
+rcontloop9:
+ maccn normalbeg2dc10
+
+rcontloop10:
+ maccn short normalbeg2dc11
+
+rcontloop11:
+ maccn short normalbeg2dc12
+
+rcontloop12:
+ maccn short normalbeg2dc13
+
+rcontloop13:
+ maccn short normalbeg2dc14
+
+rcontloop14:
+ maccn short normalbeg2dc15
+
+rcontloop15:
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+ cmp ecx,eax
+ jnb exitloop
+
+ sub chain_length,16
+ ja do16
+ jmp normalbeg0add16
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+normbeg MACRO rcontlab,valsub
+; if we are here, we know that *(match+best_len-1) == scan_end
+ cmp bp,word ptr[edx+eax]
+; if (match != scan_start) goto rcontlab
+ jne rcontlab
+; calculate the good chain_length, and we'll compare scan and match string
+ add chain_length,16-valsub
+ jmp iseq
+ ENDM
+
+
+normalbeg2dc11:
+ normbeg rcontloop11,11
+
+normalbeg2dc12:
+ normbeg short rcontloop12,12
+
+normalbeg2dc13:
+ normbeg short rcontloop13,13
+
+normalbeg2dc14:
+ normbeg short rcontloop14,14
+
+normalbeg2dc15:
+ normbeg short rcontloop15,15
+
+normalbeg2dc10:
+ normbeg rcontloop10,10
+
+normalbeg2dc9:
+ normbeg rcontloop9,9
+
+normalbeg2dc8:
+ normbeg rcontloop8,8
+
+normalbeg2dc7:
+ normbeg rcontloop7,7
+
+normalbeg2dc6:
+ normbeg rcontloop6,6
+
+normalbeg2dc5:
+ normbeg rcontloop5,5
+
+normalbeg2dc4:
+ normbeg rcontloop4,4
+
+normalbeg2dc3:
+ normbeg rcontloop3,3
+
+normalbeg2dc2:
+ normbeg rcontloop2,2
+
+normalbeg2dc1:
+ normbeg rcontloop1,1
+
+normalbeg2dc0:
+ normbeg rcontloop0,0
+
+
+; we go in normalbeg2 because *(ushf*)(match+best_len-1) == scan_end
+
+normalbeg2:
+ mov edi,window
+
+ cmp bp,word ptr[edi+eax]
+ jne contloop3 ; if *(ushf*)match != scan_start, continue
+
+iseq:
+; if we are here, we know that *(match+best_len-1) == scan_end
+; and (match == scan_start)
+
+ mov edi,edx
+ mov esi,scan ; esi = scan
+ add edi,eax ; edi = window + cur_match = match
+
+ mov edx,[esi+3] ; compare manually dword at match+3
+ xor edx,[edi+3] ; and scan +3
+
+ jz begincompare ; if equal, go to long compare
+
+; we will determine the unmatch byte and calculate len (in esi)
+ or dl,dl
+ je eq1rr
+ mov esi,3
+ jmp trfinval
+eq1rr:
+ or dx,dx
+ je eq1
+
+ mov esi,4
+ jmp trfinval
+eq1:
+ and edx,0ffffffh
+ jz eq11
+ mov esi,5
+ jmp trfinval
+eq11:
+ mov esi,6
+ jmp trfinval
+
+begincompare:
+ ; here we now scan and match begin same
+ add edi,6
+ add esi,6
+ mov ecx,(MAX_MATCH-(2+4))/4 ; scan for at most MAX_MATCH bytes
+ repe cmpsd ; loop until mismatch
+
+ je trfin ; go to trfin if not unmatch
+; we determine the unmatch byte
+ sub esi,4
+ mov edx,[edi-4]
+ xor edx,[esi]
+
+ or dl,dl
+ jnz trfin
+ inc esi
+
+ or dx,dx
+ jnz trfin
+ inc esi
+
+ and edx,0ffffffh
+ jnz trfin
+ inc esi
+
+trfin:
+ sub esi,scan ; esi = len
+trfinval:
+; here we have finised compare, and esi contain len of equal string
+ cmp esi,best_len ; if len > best_len, go newbestlen
+ ja short newbestlen
+; now we restore edx, ecx and esi, for the big loop
+ mov esi,prev
+ mov ecx,limit
+ mov edx,window
+ jmp contloop3
+
+newbestlen:
+ mov best_len,esi ; len become best_len
+
+ mov match_start,eax ; save new position as match_start
+ cmp esi,nice_match ; if best_len >= nice_match, exit
+ jae exitloop
+ mov ecx,scan
+ mov edx,window ; restore edx=window
+ add ecx,esi
+ add esi,edx
+
+ dec esi
+ mov windowlen,esi ; windowlen = window + best_len-1
+ mov bx,[ecx-1] ; bx = *(scan+best_len-1) = scan_end
+
+; now we restore ecx and esi, for the big loop :
+ mov esi,prev
+ mov ecx,limit
+ jmp contloop3
+
+exitloop:
+; exit : s->match_start=match_start
+ mov ebx,match_start
+ mov ebp,str_s
+ mov ecx,best_len
+ mov dword ptr [ebp+dep_match_start],ebx
+ mov eax,dword ptr [ebp+dep_lookahead]
+ cmp ecx,eax
+ ja minexlo
+ mov eax,ecx
+minexlo:
+; return min(best_len,s->lookahead)
+
+; restore stack and register ebx,esi,edi,ebp
+ add esp,NbStackAdd
+
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+InfoAuthor:
+; please don't remove this string !
+; Your are free use gvmat32 in any fre or commercial apps if you don't remove the string in the binary!
+ db 0dh,0ah,"GVMat32 optimised assembly code written 1996-98 by Gilles Vollant",0dh,0ah
+
+
+
+IFDEF NOUNDERLINE
+longest_match_7fff endp
+ELSE
+_longest_match_7fff endp
+ENDIF
+
+
+IFDEF NOUNDERLINE
+cpudetect32 proc near
+ELSE
+_cpudetect32 proc near
+ENDIF
+
+ push ebx
+
+ pushfd ; push original EFLAGS
+ pop eax ; get original EFLAGS
+ mov ecx, eax ; save original EFLAGS
+ xor eax, 40000h ; flip AC bit in EFLAGS
+ push eax ; save new EFLAGS value on stack
+ popfd ; replace current EFLAGS value
+ pushfd ; get new EFLAGS
+ pop eax ; store new EFLAGS in EAX
+ xor eax, ecx ; can’t toggle AC bit, processor=80386
+ jz end_cpu_is_386 ; jump if 80386 processor
+ push ecx
+ popfd ; restore AC bit in EFLAGS first
+
+ pushfd
+ pushfd
+ pop ecx
+
+ mov eax, ecx ; get original EFLAGS
+ xor eax, 200000h ; flip ID bit in EFLAGS
+ push eax ; save new EFLAGS value on stack
+ popfd ; replace current EFLAGS value
+ pushfd ; get new EFLAGS
+ pop eax ; store new EFLAGS in EAX
+ popfd ; restore original EFLAGS
+ xor eax, ecx ; can’t toggle ID bit,
+ je is_old_486 ; processor=old
+
+ mov eax,1
+ db 0fh,0a2h ;CPUID
+
+exitcpudetect:
+ pop ebx
+ ret
+
+end_cpu_is_386:
+ mov eax,0300h
+ jmp exitcpudetect
+
+is_old_486:
+ mov eax,0400h
+ jmp exitcpudetect
+
+IFDEF NOUNDERLINE
+cpudetect32 endp
+ELSE
+_cpudetect32 endp
+ENDIF
+ENDIF
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1)
+MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h)
+
+
+;;; stack frame offsets
+
+chainlenwmask equ esp + 0 ; high word: current chain len
+ ; low word: s->wmask
+window equ esp + 4 ; local copy of s->window
+windowbestlen equ esp + 8 ; s->window + bestlen
+scanstart equ esp + 16 ; first two bytes of string
+scanend equ esp + 12 ; last two bytes of string
+scanalign equ esp + 20 ; dword-misalignment of string
+nicematch equ esp + 24 ; a good enough match size
+bestlen equ esp + 28 ; size of best match so far
+scan equ esp + 32 ; ptr to string wanting match
+
+LocalVarsSize equ 36
+; saved ebx byte esp + 36
+; saved edi byte esp + 40
+; saved esi byte esp + 44
+; saved ebp byte esp + 48
+; return address byte esp + 52
+deflatestate equ esp + 56 ; the function arguments
+curmatch equ esp + 60
+
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+dsWSize equ 36+zlib1222add
+dsWMask equ 44+zlib1222add
+dsWindow equ 48+zlib1222add
+dsPrev equ 56+zlib1222add
+dsMatchLen equ 88+zlib1222add
+dsPrevMatch equ 92+zlib1222add
+dsStrStart equ 100+zlib1222add
+dsMatchStart equ 104+zlib1222add
+dsLookahead equ 108+zlib1222add
+dsPrevLen equ 112+zlib1222add
+dsMaxChainLen equ 116+zlib1222add
+dsGoodMatch equ 132+zlib1222add
+dsNiceMatch equ 136+zlib1222add
+
+
+;;; match.asm -- Pentium-Pro-optimized version of longest_match()
+;;; Written for zlib 1.1.2
+;;; Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html
+;;;
+;;; This is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License.
+
+;GLOBAL _longest_match, _match_init
+
+
+;SECTION .text
+
+;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch)
+
+;_longest_match:
+IFDEF NOOLDPENTIUMCODE
+ IFDEF NOUNDERLINE
+ longest_match proc near
+ ELSE
+ _longest_match proc near
+ ENDIF
+ELSE
+ IFDEF NOUNDERLINE
+ longest_match_686 proc near
+ ELSE
+ _longest_match_686 proc near
+ ENDIF
+ENDIF
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+ push ebp
+ push edi
+ push esi
+ push ebx
+ sub esp, LocalVarsSize
+
+;;; Retrieve the function arguments. ecx will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+ mov edx, [deflatestate]
+ mov ecx, [curmatch]
+
+;;; uInt wmask = s->w_mask;
+;;; unsigned chain_length = s->max_chain_length;
+;;; if (s->prev_length >= s->good_match) {
+;;; chain_length >>= 2;
+;;; }
+
+ mov eax, [edx + dsPrevLen]
+ mov ebx, [edx + dsGoodMatch]
+ cmp eax, ebx
+ mov eax, [edx + dsWMask]
+ mov ebx, [edx + dsMaxChainLen]
+ jl LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+;;; chainlen is decremented once beforehand so that the function can
+;;; use the sign flag instead of the zero flag for the exit test.
+;;; It is then shifted into the high word, to make room for the wmask
+;;; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+ mov [chainlenwmask], ebx
+
+;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ mov eax, [edx + dsNiceMatch]
+ mov ebx, [edx + dsLookahead]
+ cmp ebx, eax
+ jl LookaheadLess
+ mov ebx, eax
+LookaheadLess: mov [nicematch], ebx
+
+;;; register Bytef *scan = s->window + s->strstart;
+
+ mov esi, [edx + dsWindow]
+ mov [window], esi
+ mov ebp, [edx + dsStrStart]
+ lea edi, [esi + ebp]
+ mov [scan], edi
+
+;;; Determine how many bytes the scan ptr is off from being
+;;; dword-aligned.
+
+ mov eax, edi
+ neg eax
+ and eax, 3
+ mov [scanalign], eax
+
+;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
+
+ mov eax, [edx + dsWSize]
+ sub eax, MIN_LOOKAHEAD
+ sub ebp, eax
+ jg LimitPositive
+ xor ebp, ebp
+LimitPositive:
+
+;;; int best_len = s->prev_length;
+
+ mov eax, [edx + dsPrevLen]
+ mov [bestlen], eax
+
+;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+ add esi, eax
+ mov [windowbestlen], esi
+
+;;; register ush scan_start = *(ushf*)scan;
+;;; register ush scan_end = *(ushf*)(scan+best_len-1);
+;;; Posf *prev = s->prev;
+
+ movzx ebx, word ptr [edi]
+ mov [scanstart], ebx
+ movzx ebx, word ptr [edi + eax - 1]
+ mov [scanend], ebx
+ mov edi, [edx + dsPrev]
+
+;;; Jump into the main loop.
+
+ mov edx, [chainlenwmask]
+ jmp short LoopEntry
+
+align 4
+
+;;; do {
+;;; match = s->window + cur_match;
+;;; if (*(ushf*)(match+best_len-1) != scan_end ||
+;;; *(ushf*)match != scan_start) continue;
+;;; [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;; && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; ecx = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+
+LookupLoop:
+ and ecx, edx
+ movzx ecx, word ptr [edi + ecx*2]
+ cmp ecx, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+LoopEntry: movzx eax, word ptr [esi + ecx - 1]
+ cmp eax, ebx
+ jnz LookupLoop
+ mov eax, [window]
+ movzx eax, word ptr [eax + ecx]
+ cmp eax, [scanstart]
+ jnz LookupLoop
+
+;;; Store the current value of chainlen.
+
+ mov [chainlenwmask], edx
+
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+
+ mov esi, [window]
+ mov edi, [scan]
+ add esi, ecx
+ mov eax, [scanalign]
+ mov edx, 0fffffef8h; -(MAX_MATCH_8)
+ lea edi, [edi + eax + 0108h] ;MAX_MATCH_8]
+ lea esi, [esi + eax + 0108h] ;MAX_MATCH_8]
+
+;;; Test the strings for equality, 8 bytes at a time. At the end,
+;;; adjust edx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (esi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+
+LoopCmps:
+ mov eax, [esi + edx]
+ xor eax, [edi + edx]
+ jnz LeaveLoopCmps
+ mov eax, [esi + edx + 4]
+ xor eax, [edi + edx + 4]
+ jnz LeaveLoopCmps4
+ add edx, 8
+ jnz LoopCmps
+ jmp short LenMaximum
+LeaveLoopCmps4: add edx, 4
+LeaveLoopCmps: test eax, 0000FFFFh
+ jnz LenLower
+ add edx, 2
+ shr eax, 16
+LenLower: sub al, 1
+ adc edx, 0
+
+;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+;;; then automatically accept it as the best possible match and leave.
+
+ lea eax, [edi + edx]
+ mov edi, [scan]
+ sub eax, edi
+ cmp eax, MAX_MATCH
+ jge LenMaximum
+
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+
+ mov edx, [deflatestate]
+ mov ebx, [bestlen]
+ cmp eax, ebx
+ jg LongerMatch
+ mov esi, [windowbestlen]
+ mov edi, [edx + dsPrev]
+ mov ebx, [scanend]
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; s->match_start = cur_match;
+;;; best_len = len;
+;;; if (len >= nice_match) break;
+;;; scan_end = *(ushf*)(scan+best_len-1);
+
+LongerMatch: mov ebx, [nicematch]
+ mov [bestlen], eax
+ mov [edx + dsMatchStart], ecx
+ cmp eax, ebx
+ jge LeaveNow
+ mov esi, [window]
+ add esi, eax
+ mov [windowbestlen], esi
+ movzx ebx, word ptr [edi + eax - 1]
+ mov edi, [edx + dsPrev]
+ mov [scanend], ebx
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; Accept the current string, with the maximum possible length.
+
+LenMaximum: mov edx, [deflatestate]
+ mov dword ptr [bestlen], MAX_MATCH
+ mov [edx + dsMatchStart], ecx
+
+;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+;;; return s->lookahead;
+
+LeaveNow:
+ mov edx, [deflatestate]
+ mov ebx, [bestlen]
+ mov eax, [edx + dsLookahead]
+ cmp ebx, eax
+ jg LookaheadRet
+ mov eax, ebx
+LookaheadRet:
+
+;;; Restore the stack and return from whence we came.
+
+ add esp, LocalVarsSize
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+
+ ret
+; please don't remove this string !
+; Your can freely use gvmat32 in any free or commercial app if you don't remove the string in the binary!
+ db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah
+
+
+IFDEF NOOLDPENTIUMCODE
+ IFDEF NOUNDERLINE
+ longest_match endp
+ ELSE
+ _longest_match endp
+ ENDIF
+
+ IFDEF NOUNDERLINE
+ match_init proc near
+ ret
+ match_init endp
+ ELSE
+ _match_init proc near
+ ret
+ _match_init endp
+ ENDIF
+ELSE
+ IFDEF NOUNDERLINE
+ longest_match_686 endp
+ ELSE
+ _longest_match_686 endp
+ ENDIF
+ENDIF
+
+_TEXT ends
+end
diff --git a/zlib/contrib/masmx86/gvmat32c.c b/zlib/contrib/masmx86/gvmat32c.c
new file mode 100644
index 0000000..7ad2b27
--- /dev/null
+++ b/zlib/contrib/masmx86/gvmat32c.c
@@ -0,0 +1,62 @@
+/* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86
+ * Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant.
+ * File written by Gilles Vollant, by modifiying the longest_match
+ * from Jean-loup Gailly in deflate.c
+ * it prepare all parameters and call the assembly longest_match_gvasm
+ * longest_match execute standard C code is wmask != 0x7fff
+ * (assembly code is faster with a fixed wmask)
+ *
+ * Read comment at beginning of gvmat32.asm for more information
+ */
+
+#if defined(ASMV) && (!defined(NOOLDPENTIUMCODE))
+#include "deflate.h"
+
+/* if your C compiler don't add underline before function name,
+ define ADD_UNDERLINE_ASMFUNC */
+#ifdef ADD_UNDERLINE_ASMFUNC
+#define longest_match_7fff _longest_match_7fff
+#define longest_match_686 _longest_match_686
+#define cpudetect32 _cpudetect32
+#endif
+
+
+unsigned long cpudetect32();
+
+uInt longest_match_c(
+ deflate_state *s,
+ IPos cur_match); /* current match */
+
+
+uInt longest_match_7fff(
+ deflate_state *s,
+ IPos cur_match); /* current match */
+
+uInt longest_match_686(
+ deflate_state *s,
+ IPos cur_match); /* current match */
+
+
+static uInt iIsPPro=2;
+
+void match_init ()
+{
+ iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0;
+}
+
+uInt longest_match(
+ deflate_state *s,
+ IPos cur_match) /* current match */
+{
+ if (iIsPPro!=0)
+ return longest_match_686(s,cur_match);
+
+ if (s->w_mask != 0x7fff)
+ return longest_match_686(s,cur_match);
+
+ /* now ((s->w_mask == 0x7fff) && (iIsPPro==0)) */
+ return longest_match_7fff(s,cur_match);
+}
+
+
+#endif /* defined(ASMV) && (!defined(NOOLDPENTIUMCODE)) */
diff --git a/zlib/contrib/masmx86/inffas32.asm b/zlib/contrib/masmx86/inffas32.asm
new file mode 100644
index 0000000..4a20512
--- /dev/null
+++ b/zlib/contrib/masmx86/inffas32.asm
@@ -0,0 +1,1083 @@
+;/* inffas32.asm is a hand tuned assembler version of inffast.c -- fast decoding
+; *
+; * inffas32.asm is derivated from inffas86.c, with translation of assembly code
+; *
+; * Copyright (C) 1995-2003 Mark Adler
+; * For conditions of distribution and use, see copyright notice in zlib.h
+; *
+; * Copyright (C) 2003 Chris Anderson <christop@charm.net>
+; * Please use the copyright conditions above.
+; *
+; * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from
+; * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at
+; * the moment. I have successfully compiled and tested this code with gcc2.96,
+; * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S
+; * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX
+; * enabled. I will attempt to merge the MMX code into this version. Newer
+; * versions of this and inffast.S can be found at
+; * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
+; *
+; * 2005 : modification by Gilles Vollant
+; */
+; For Visual C++ 4.x and higher and ML 6.x and higher
+; ml.exe is in directory \MASM611C of Win95 DDK
+; ml.exe is also distributed in http://www.masm32.com/masmdl.htm
+; and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/
+;
+;
+; compile with command line option
+; ml /coff /Zi /c /Flinffas32.lst inffas32.asm
+
+; if you define NO_GZIP (see inflate.h), compile with
+; ml /coff /Zi /c /Flinffas32.lst /DNO_GUNZIP inffas32.asm
+
+
+; zlib122sup is 0 fort zlib 1.2.2.1 and lower
+; zlib122sup is 8 fort zlib 1.2.2.2 and more (with addition of dmax and head
+; in inflate_state in inflate.h)
+zlib1222sup equ 8
+
+
+IFDEF GUNZIP
+ INFLATE_MODE_TYPE equ 11
+ INFLATE_MODE_BAD equ 26
+ELSE
+ IFNDEF NO_GUNZIP
+ INFLATE_MODE_TYPE equ 11
+ INFLATE_MODE_BAD equ 26
+ ELSE
+ INFLATE_MODE_TYPE equ 3
+ INFLATE_MODE_BAD equ 17
+ ENDIF
+ENDIF
+
+
+; 75 "inffast.S"
+;FILE "inffast.S"
+
+;;;GLOBAL _inflate_fast
+
+;;;SECTION .text
+
+
+
+ .586p
+ .mmx
+
+ name inflate_fast_x86
+ .MODEL FLAT
+
+_DATA segment
+inflate_fast_use_mmx:
+ dd 1
+
+
+_TEXT segment
+PUBLIC _inflate_fast
+
+ALIGN 4
+_inflate_fast:
+ jmp inflate_fast_entry
+
+
+
+ALIGN 4
+ db 'Fast decoding Code from Chris Anderson'
+ db 0
+
+ALIGN 4
+invalid_literal_length_code_msg:
+ db 'invalid literal/length code'
+ db 0
+
+ALIGN 4
+invalid_distance_code_msg:
+ db 'invalid distance code'
+ db 0
+
+ALIGN 4
+invalid_distance_too_far_msg:
+ db 'invalid distance too far back'
+ db 0
+
+
+ALIGN 4
+inflate_fast_mask:
+dd 0
+dd 1
+dd 3
+dd 7
+dd 15
+dd 31
+dd 63
+dd 127
+dd 255
+dd 511
+dd 1023
+dd 2047
+dd 4095
+dd 8191
+dd 16383
+dd 32767
+dd 65535
+dd 131071
+dd 262143
+dd 524287
+dd 1048575
+dd 2097151
+dd 4194303
+dd 8388607
+dd 16777215
+dd 33554431
+dd 67108863
+dd 134217727
+dd 268435455
+dd 536870911
+dd 1073741823
+dd 2147483647
+dd 4294967295
+
+
+mode_state equ 0 ;/* state->mode */
+wsize_state equ (32+zlib1222sup) ;/* state->wsize */
+write_state equ (36+4+zlib1222sup) ;/* state->write */
+window_state equ (40+4+zlib1222sup) ;/* state->window */
+hold_state equ (44+4+zlib1222sup) ;/* state->hold */
+bits_state equ (48+4+zlib1222sup) ;/* state->bits */
+lencode_state equ (64+4+zlib1222sup) ;/* state->lencode */
+distcode_state equ (68+4+zlib1222sup) ;/* state->distcode */
+lenbits_state equ (72+4+zlib1222sup) ;/* state->lenbits */
+distbits_state equ (76+4+zlib1222sup) ;/* state->distbits */
+
+
+;;SECTION .text
+; 205 "inffast.S"
+;GLOBAL inflate_fast_use_mmx
+
+;SECTION .data
+
+
+; GLOBAL inflate_fast_use_mmx:object
+;.size inflate_fast_use_mmx, 4
+; 226 "inffast.S"
+;SECTION .text
+
+ALIGN 4
+inflate_fast_entry:
+ push edi
+ push esi
+ push ebp
+ push ebx
+ pushfd
+ sub esp,64
+ cld
+
+
+
+
+ mov esi, [esp+88]
+ mov edi, [esi+28]
+
+
+
+
+
+
+
+ mov edx, [esi+4]
+ mov eax, [esi+0]
+
+ add edx,eax
+ sub edx,11
+
+ mov [esp+44],eax
+ mov [esp+20],edx
+
+ mov ebp, [esp+92]
+ mov ecx, [esi+16]
+ mov ebx, [esi+12]
+
+ sub ebp,ecx
+ neg ebp
+ add ebp,ebx
+
+ sub ecx,257
+ add ecx,ebx
+
+ mov [esp+60],ebx
+ mov [esp+40],ebp
+ mov [esp+16],ecx
+; 285 "inffast.S"
+ mov eax, [edi+lencode_state]
+ mov ecx, [edi+distcode_state]
+
+ mov [esp+8],eax
+ mov [esp+12],ecx
+
+ mov eax,1
+ mov ecx, [edi+lenbits_state]
+ shl eax,cl
+ dec eax
+ mov [esp+0],eax
+
+ mov eax,1
+ mov ecx, [edi+distbits_state]
+ shl eax,cl
+ dec eax
+ mov [esp+4],eax
+
+ mov eax, [edi+wsize_state]
+ mov ecx, [edi+write_state]
+ mov edx, [edi+window_state]
+
+ mov [esp+52],eax
+ mov [esp+48],ecx
+ mov [esp+56],edx
+
+ mov ebp, [edi+hold_state]
+ mov ebx, [edi+bits_state]
+; 321 "inffast.S"
+ mov esi, [esp+44]
+ mov ecx, [esp+20]
+ cmp ecx,esi
+ ja L_align_long
+
+ add ecx,11
+ sub ecx,esi
+ mov eax,12
+ sub eax,ecx
+ lea edi, [esp+28]
+ rep movsb
+ mov ecx,eax
+ xor eax,eax
+ rep stosb
+ lea esi, [esp+28]
+ mov [esp+20],esi
+ jmp L_is_aligned
+
+
+L_align_long:
+ test esi,3
+ jz L_is_aligned
+ xor eax,eax
+ mov al, [esi]
+ inc esi
+ mov ecx,ebx
+ add ebx,8
+ shl eax,cl
+ or ebp,eax
+ jmp L_align_long
+
+L_is_aligned:
+ mov edi, [esp+60]
+; 366 "inffast.S"
+L_check_mmx:
+ cmp dword ptr [inflate_fast_use_mmx],2
+ je L_init_mmx
+ ja L_do_loop
+
+ push eax
+ push ebx
+ push ecx
+ push edx
+ pushfd
+ mov eax, [esp]
+ xor dword ptr [esp],0200000h
+
+
+
+
+ popfd
+ pushfd
+ pop edx
+ xor edx,eax
+ jz L_dont_use_mmx
+ xor eax,eax
+ cpuid
+ cmp ebx,0756e6547h
+ jne L_dont_use_mmx
+ cmp ecx,06c65746eh
+ jne L_dont_use_mmx
+ cmp edx,049656e69h
+ jne L_dont_use_mmx
+ mov eax,1
+ cpuid
+ shr eax,8
+ and eax,15
+ cmp eax,6
+ jne L_dont_use_mmx
+ test edx,0800000h
+ jnz L_use_mmx
+ jmp L_dont_use_mmx
+L_use_mmx:
+ mov dword ptr [inflate_fast_use_mmx],2
+ jmp L_check_mmx_pop
+L_dont_use_mmx:
+ mov dword ptr [inflate_fast_use_mmx],3
+L_check_mmx_pop:
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ jmp L_check_mmx
+; 426 "inffast.S"
+ALIGN 4
+L_do_loop:
+; 437 "inffast.S"
+ cmp bl,15
+ ja L_get_length_code
+
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+
+L_get_length_code:
+ mov edx, [esp+0]
+ mov ecx, [esp+8]
+ and edx,ebp
+ mov eax, [ecx+edx*4]
+
+L_dolen:
+
+
+
+
+
+
+ mov cl,ah
+ sub bl,ah
+ shr ebp,cl
+
+
+
+
+
+
+ test al,al
+ jnz L_test_for_length_base
+
+ shr eax,16
+ stosb
+
+L_while_test:
+
+
+ cmp [esp+16],edi
+ jbe L_break_loop
+
+ cmp [esp+20],esi
+ ja L_do_loop
+ jmp L_break_loop
+
+L_test_for_length_base:
+; 502 "inffast.S"
+ mov edx,eax
+ shr edx,16
+ mov cl,al
+
+ test al,16
+ jz L_test_for_second_level_length
+ and cl,15
+ jz L_save_len
+ cmp bl,cl
+ jae L_add_bits_to_len
+
+ mov ch,cl
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+ mov cl,ch
+
+L_add_bits_to_len:
+ mov eax,1
+ shl eax,cl
+ dec eax
+ sub bl,cl
+ and eax,ebp
+ shr ebp,cl
+ add edx,eax
+
+L_save_len:
+ mov [esp+24],edx
+
+
+L_decode_distance:
+; 549 "inffast.S"
+ cmp bl,15
+ ja L_get_distance_code
+
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+
+L_get_distance_code:
+ mov edx, [esp+4]
+ mov ecx, [esp+12]
+ and edx,ebp
+ mov eax, [ecx+edx*4]
+
+
+L_dodist:
+ mov edx,eax
+ shr edx,16
+ mov cl,ah
+ sub bl,ah
+ shr ebp,cl
+; 584 "inffast.S"
+ mov cl,al
+
+ test al,16
+ jz L_test_for_second_level_dist
+ and cl,15
+ jz L_check_dist_one
+ cmp bl,cl
+ jae L_add_bits_to_dist
+
+ mov ch,cl
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+ mov cl,ch
+
+L_add_bits_to_dist:
+ mov eax,1
+ shl eax,cl
+ dec eax
+ sub bl,cl
+ and eax,ebp
+ shr ebp,cl
+ add edx,eax
+ jmp L_check_window
+
+L_check_window:
+; 625 "inffast.S"
+ mov [esp+44],esi
+ mov eax,edi
+ sub eax, [esp+40]
+
+ cmp eax,edx
+ jb L_clip_window
+
+ mov ecx, [esp+24]
+ mov esi,edi
+ sub esi,edx
+
+ sub ecx,3
+ mov al, [esi]
+ mov [edi],al
+ mov al, [esi+1]
+ mov dl, [esi+2]
+ add esi,3
+ mov [edi+1],al
+ mov [edi+2],dl
+ add edi,3
+ rep movsb
+
+ mov esi, [esp+44]
+ jmp L_while_test
+
+ALIGN 4
+L_check_dist_one:
+ cmp edx,1
+ jne L_check_window
+ cmp [esp+40],edi
+ je L_check_window
+
+ dec edi
+ mov ecx, [esp+24]
+ mov al, [edi]
+ sub ecx,3
+
+ mov [edi+1],al
+ mov [edi+2],al
+ mov [edi+3],al
+ add edi,4
+ rep stosb
+
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_second_level_length:
+
+
+
+
+ test al,64
+ jnz L_test_for_end_of_block
+
+ mov eax,1
+ shl eax,cl
+ dec eax
+ and eax,ebp
+ add eax,edx
+ mov edx, [esp+8]
+ mov eax, [edx+eax*4]
+ jmp L_dolen
+
+ALIGN 4
+L_test_for_second_level_dist:
+
+
+
+
+ test al,64
+ jnz L_invalid_distance_code
+
+ mov eax,1
+ shl eax,cl
+ dec eax
+ and eax,ebp
+ add eax,edx
+ mov edx, [esp+12]
+ mov eax, [edx+eax*4]
+ jmp L_dodist
+
+ALIGN 4
+L_clip_window:
+; 721 "inffast.S"
+ mov ecx,eax
+ mov eax, [esp+52]
+ neg ecx
+ mov esi, [esp+56]
+
+ cmp eax,edx
+ jb L_invalid_distance_too_far
+
+ add ecx,edx
+ cmp dword ptr [esp+48],0
+ jne L_wrap_around_window
+
+ sub eax,ecx
+ add esi,eax
+; 749 "inffast.S"
+ mov eax, [esp+24]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+ jmp L_do_copy1
+
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+ jmp L_do_copy1
+
+L_wrap_around_window:
+; 793 "inffast.S"
+ mov eax, [esp+48]
+ cmp ecx,eax
+ jbe L_contiguous_in_window
+
+ add esi, [esp+52]
+ add esi,eax
+ sub esi,ecx
+ sub ecx,eax
+
+
+ mov eax, [esp+24]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi, [esp+56]
+ mov ecx, [esp+48]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+ jmp L_do_copy1
+
+L_contiguous_in_window:
+; 836 "inffast.S"
+ add esi,eax
+ sub esi,ecx
+
+
+ mov eax, [esp+24]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+
+L_do_copy1:
+; 862 "inffast.S"
+ mov ecx,eax
+ rep movsb
+
+ mov esi, [esp+44]
+ jmp L_while_test
+; 878 "inffast.S"
+ALIGN 4
+L_init_mmx:
+ emms
+
+
+
+
+
+ movd mm0,ebp
+ mov ebp,ebx
+; 896 "inffast.S"
+ movd mm4,[esp+0]
+ movq mm3,mm4
+ movd mm5,[esp+4]
+ movq mm2,mm5
+ pxor mm1,mm1
+ mov ebx, [esp+8]
+ jmp L_do_loop_mmx
+
+ALIGN 4
+L_do_loop_mmx:
+ psrlq mm0,mm1
+
+ cmp ebp,32
+ ja L_get_length_code_mmx
+
+ movd mm6,ebp
+ movd mm7,[esi]
+ add esi,4
+ psllq mm7,mm6
+ add ebp,32
+ por mm0,mm7
+
+L_get_length_code_mmx:
+ pand mm4,mm0
+ movd eax,mm4
+ movq mm4,mm3
+ mov eax, [ebx+eax*4]
+
+L_dolen_mmx:
+ movzx ecx,ah
+ movd mm1,ecx
+ sub ebp,ecx
+
+ test al,al
+ jnz L_test_for_length_base_mmx
+
+ shr eax,16
+ stosb
+
+L_while_test_mmx:
+
+
+ cmp [esp+16],edi
+ jbe L_break_loop
+
+ cmp [esp+20],esi
+ ja L_do_loop_mmx
+ jmp L_break_loop
+
+L_test_for_length_base_mmx:
+
+ mov edx,eax
+ shr edx,16
+
+ test al,16
+ jz L_test_for_second_level_length_mmx
+ and eax,15
+ jz L_decode_distance_mmx
+
+ psrlq mm0,mm1
+ movd mm1,eax
+ movd ecx,mm0
+ sub ebp,eax
+ and ecx, [inflate_fast_mask+eax*4]
+ add edx,ecx
+
+L_decode_distance_mmx:
+ psrlq mm0,mm1
+
+ cmp ebp,32
+ ja L_get_dist_code_mmx
+
+ movd mm6,ebp
+ movd mm7,[esi]
+ add esi,4
+ psllq mm7,mm6
+ add ebp,32
+ por mm0,mm7
+
+L_get_dist_code_mmx:
+ mov ebx, [esp+12]
+ pand mm5,mm0
+ movd eax,mm5
+ movq mm5,mm2
+ mov eax, [ebx+eax*4]
+
+L_dodist_mmx:
+
+ movzx ecx,ah
+ mov ebx,eax
+ shr ebx,16
+ sub ebp,ecx
+ movd mm1,ecx
+
+ test al,16
+ jz L_test_for_second_level_dist_mmx
+ and eax,15
+ jz L_check_dist_one_mmx
+
+L_add_bits_to_dist_mmx:
+ psrlq mm0,mm1
+ movd mm1,eax
+ movd ecx,mm0
+ sub ebp,eax
+ and ecx, [inflate_fast_mask+eax*4]
+ add ebx,ecx
+
+L_check_window_mmx:
+ mov [esp+44],esi
+ mov eax,edi
+ sub eax, [esp+40]
+
+ cmp eax,ebx
+ jb L_clip_window_mmx
+
+ mov ecx,edx
+ mov esi,edi
+ sub esi,ebx
+
+ sub ecx,3
+ mov al, [esi]
+ mov [edi],al
+ mov al, [esi+1]
+ mov dl, [esi+2]
+ add esi,3
+ mov [edi+1],al
+ mov [edi+2],dl
+ add edi,3
+ rep movsb
+
+ mov esi, [esp+44]
+ mov ebx, [esp+8]
+ jmp L_while_test_mmx
+
+ALIGN 4
+L_check_dist_one_mmx:
+ cmp ebx,1
+ jne L_check_window_mmx
+ cmp [esp+40],edi
+ je L_check_window_mmx
+
+ dec edi
+ mov ecx,edx
+ mov al, [edi]
+ sub ecx,3
+
+ mov [edi+1],al
+ mov [edi+2],al
+ mov [edi+3],al
+ add edi,4
+ rep stosb
+
+ mov ebx, [esp+8]
+ jmp L_while_test_mmx
+
+ALIGN 4
+L_test_for_second_level_length_mmx:
+ test al,64
+ jnz L_test_for_end_of_block
+
+ and eax,15
+ psrlq mm0,mm1
+ movd ecx,mm0
+ and ecx, [inflate_fast_mask+eax*4]
+ add ecx,edx
+ mov eax, [ebx+ecx*4]
+ jmp L_dolen_mmx
+
+ALIGN 4
+L_test_for_second_level_dist_mmx:
+ test al,64
+ jnz L_invalid_distance_code
+
+ and eax,15
+ psrlq mm0,mm1
+ movd ecx,mm0
+ and ecx, [inflate_fast_mask+eax*4]
+ mov eax, [esp+12]
+ add ecx,ebx
+ mov eax, [eax+ecx*4]
+ jmp L_dodist_mmx
+
+ALIGN 4
+L_clip_window_mmx:
+
+ mov ecx,eax
+ mov eax, [esp+52]
+ neg ecx
+ mov esi, [esp+56]
+
+ cmp eax,ebx
+ jb L_invalid_distance_too_far
+
+ add ecx,ebx
+ cmp dword ptr [esp+48],0
+ jne L_wrap_around_window_mmx
+
+ sub eax,ecx
+ add esi,eax
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+ jmp L_do_copy1_mmx
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+ jmp L_do_copy1_mmx
+
+L_wrap_around_window_mmx:
+
+ mov eax, [esp+48]
+ cmp ecx,eax
+ jbe L_contiguous_in_window_mmx
+
+ add esi, [esp+52]
+ add esi,eax
+ sub esi,ecx
+ sub ecx,eax
+
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi, [esp+56]
+ mov ecx, [esp+48]
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+ jmp L_do_copy1_mmx
+
+L_contiguous_in_window_mmx:
+
+ add esi,eax
+ sub esi,ecx
+
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+
+L_do_copy1_mmx:
+
+
+ mov ecx,edx
+ rep movsb
+
+ mov esi, [esp+44]
+ mov ebx, [esp+8]
+ jmp L_while_test_mmx
+; 1174 "inffast.S"
+L_invalid_distance_code:
+
+
+
+
+
+ mov ecx, invalid_distance_code_msg
+ mov edx,INFLATE_MODE_BAD
+ jmp L_update_stream_state
+
+L_test_for_end_of_block:
+
+
+
+
+
+ test al,32
+ jz L_invalid_literal_length_code
+
+ mov ecx,0
+ mov edx,INFLATE_MODE_TYPE
+ jmp L_update_stream_state
+
+L_invalid_literal_length_code:
+
+
+
+
+
+ mov ecx, invalid_literal_length_code_msg
+ mov edx,INFLATE_MODE_BAD
+ jmp L_update_stream_state
+
+L_invalid_distance_too_far:
+
+
+
+ mov esi, [esp+44]
+ mov ecx, invalid_distance_too_far_msg
+ mov edx,INFLATE_MODE_BAD
+ jmp L_update_stream_state
+
+L_update_stream_state:
+
+ mov eax, [esp+88]
+ test ecx,ecx
+ jz L_skip_msg
+ mov [eax+24],ecx
+L_skip_msg:
+ mov eax, [eax+28]
+ mov [eax+mode_state],edx
+ jmp L_break_loop
+
+ALIGN 4
+L_break_loop:
+; 1243 "inffast.S"
+ cmp dword ptr [inflate_fast_use_mmx],2
+ jne L_update_next_in
+
+
+
+ mov ebx,ebp
+
+L_update_next_in:
+; 1266 "inffast.S"
+ mov eax, [esp+88]
+ mov ecx,ebx
+ mov edx, [eax+28]
+ shr ecx,3
+ sub esi,ecx
+ shl ecx,3
+ sub ebx,ecx
+ mov [eax+12],edi
+ mov [edx+bits_state],ebx
+ mov ecx,ebx
+
+ lea ebx, [esp+28]
+ cmp [esp+20],ebx
+ jne L_buf_not_used
+
+ sub esi,ebx
+ mov ebx, [eax+0]
+ mov [esp+20],ebx
+ add esi,ebx
+ mov ebx, [eax+4]
+ sub ebx,11
+ add [esp+20],ebx
+
+L_buf_not_used:
+ mov [eax+0],esi
+
+ mov ebx,1
+ shl ebx,cl
+ dec ebx
+
+
+
+
+
+ cmp dword ptr [inflate_fast_use_mmx],2
+ jne L_update_hold
+
+
+
+ psrlq mm0,mm1
+ movd ebp,mm0
+
+ emms
+
+L_update_hold:
+
+
+
+ and ebp,ebx
+ mov [edx+hold_state],ebp
+
+
+
+
+ mov ebx, [esp+20]
+ cmp ebx,esi
+ jbe L_last_is_smaller
+
+ sub ebx,esi
+ add ebx,11
+ mov [eax+4],ebx
+ jmp L_fixup_out
+L_last_is_smaller:
+ sub esi,ebx
+ neg esi
+ add esi,11
+ mov [eax+4],esi
+
+
+
+
+L_fixup_out:
+
+ mov ebx, [esp+16]
+ cmp ebx,edi
+ jbe L_end_is_smaller
+
+ sub ebx,edi
+ add ebx,257
+ mov [eax+16],ebx
+ jmp L_done
+L_end_is_smaller:
+ sub edi,ebx
+ neg edi
+ add edi,257
+ mov [eax+16],edi
+
+
+
+
+
+L_done:
+ add esp,64
+ popfd
+ pop ebx
+ pop ebp
+ pop esi
+ pop edi
+ ret
+
+_TEXT ends
+end
diff --git a/zlib/contrib/masmx86/mkasm.bat b/zlib/contrib/masmx86/mkasm.bat
new file mode 100755
index 0000000..70a51f8
--- /dev/null
+++ b/zlib/contrib/masmx86/mkasm.bat
@@ -0,0 +1,3 @@
+cl /DASMV /I..\.. /O2 /c gvmat32c.c
+ml /coff /Zi /c /Flgvmat32.lst gvmat32.asm
+ml /coff /Zi /c /Flinffas32.lst inffas32.asm
diff --git a/zlib/contrib/masmx86/readme.txt b/zlib/contrib/masmx86/readme.txt
new file mode 100644
index 0000000..7b57167
--- /dev/null
+++ b/zlib/contrib/masmx86/readme.txt
@@ -0,0 +1,21 @@
+
+Summary
+-------
+This directory contains ASM implementations of the functions
+longest_match() and inflate_fast().
+
+
+Use instructions
+----------------
+Copy these files into the zlib source directory, then run the
+appropriate makefile, as suggested below.
+
+
+Build instructions
+------------------
+* With Microsoft C and MASM:
+nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="gvmat32c.obj gvmat32.obj inffas32.obj"
+
+* With Borland C and TASM:
+make -f win32/Makefile.bor LOCAL_ZLIB="-DASMV -DASMINF" OBJA="gvmat32c.obj gvmat32.obj inffas32.obj" OBJPA="+gvmat32c.obj+gvmat32.obj+inffas32.obj"
+
diff --git a/zlib/contrib/minizip/ChangeLogUnzip b/zlib/contrib/minizip/ChangeLogUnzip
new file mode 100644
index 0000000..50ca6a9
--- /dev/null
+++ b/zlib/contrib/minizip/ChangeLogUnzip
@@ -0,0 +1,67 @@
+Change in 1.01e (12 feb 05)
+- Fix in zipOpen2 for globalcomment (Rolf Kalbermatter)
+- Fix possible memory leak in unzip.c (Zoran Stevanovic)
+
+Change in 1.01b (20 may 04)
+- Integrate patch from Debian package (submited by Mark Brown)
+- Add tools mztools from Xavier Roche
+
+Change in 1.01 (8 may 04)
+- fix buffer overrun risk in unzip.c (Xavier Roche)
+- fix a minor buffer insecurity in minizip.c (Mike Whittaker)
+
+Change in 1.00: (10 sept 03)
+- rename to 1.00
+- cosmetic code change
+
+Change in 0.22: (19 May 03)
+- crypting support (unless you define NOCRYPT)
+- append file in existing zipfile
+
+Change in 0.21: (10 Mar 03)
+- bug fixes
+
+Change in 0.17: (27 Jan 02)
+- bug fixes
+
+Change in 0.16: (19 Jan 02)
+- Support of ioapi for virtualize zip file access
+
+Change in 0.15: (19 Mar 98)
+- fix memory leak in minizip.c
+
+Change in 0.14: (10 Mar 98)
+- fix bugs in minizip.c sample for zipping big file
+- fix problem in month in date handling
+- fix bug in unzlocal_GetCurrentFileInfoInternal in unzip.c for
+ comment handling
+
+Change in 0.13: (6 Mar 98)
+- fix bugs in zip.c
+- add real minizip sample
+
+Change in 0.12: (4 Mar 98)
+- add zip.c and zip.h for creates .zip file
+- fix change_file_date in miniunz.c for Unix (Jean-loup Gailly)
+- fix miniunz.c for file without specific record for directory
+
+Change in 0.11: (3 Mar 98)
+- fix bug in unzGetCurrentFileInfo for get extra field and comment
+- enhance miniunz sample, remove the bad unztst.c sample
+
+Change in 0.10: (2 Mar 98)
+- fix bug in unzReadCurrentFile
+- rename unzip* to unz* function and structure
+- remove Windows-like hungary notation variable name
+- modify some structure in unzip.h
+- add somes comment in source
+- remove unzipGetcCurrentFile function
+- replace ZUNZEXPORT by ZEXPORT
+- add unzGetLocalExtrafield for get the local extrafield info
+- add a new sample, miniunz.c
+
+Change in 0.4: (25 Feb 98)
+- suppress the type unzipFileInZip.
+ Only on file in the zipfile can be open at the same time
+- fix somes typo in code
+- added tm_unz structure in unzip_file_info (date/time in readable format)
diff --git a/zlib/contrib/minizip/Makefile b/zlib/contrib/minizip/Makefile
new file mode 100644
index 0000000..84eaad2
--- /dev/null
+++ b/zlib/contrib/minizip/Makefile
@@ -0,0 +1,25 @@
+CC=cc
+CFLAGS=-O -I../..
+
+UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a
+ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a
+
+.c.o:
+ $(CC) -c $(CFLAGS) $*.c
+
+all: miniunz minizip
+
+miniunz: $(UNZ_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS)
+
+minizip: $(ZIP_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS)
+
+test: miniunz minizip
+ ./minizip test readme.txt
+ ./miniunz -l test.zip
+ mv readme.txt readme.old
+ ./miniunz test.zip
+
+clean:
+ /bin/rm -f *.o *~ minizip miniunz
diff --git a/zlib/contrib/minizip/crypt.h b/zlib/contrib/minizip/crypt.h
new file mode 100644
index 0000000..622f4bc
--- /dev/null
+++ b/zlib/contrib/minizip/crypt.h
@@ -0,0 +1,132 @@
+/* crypt.h -- base code for crypt/uncrypt ZIPfile
+
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ This code is a modified version of crypting code in Infozip distribution
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ If you don't need crypting in your application, just define symbols
+ NOCRYPT and NOUNCRYPT.
+
+ This code support the "Traditional PKWARE Encryption".
+
+ The new AES encryption added on Zip format by Winzip (see the page
+ http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+ Encryption is not supported.
+*/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
+{
+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
+ * unpredictable manner on 16-bit systems; not a problem
+ * with any known compiler so far, though */
+
+ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
+{
+ (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
+ (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+ (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+ {
+ register int keyshift = (int)((*(pkeys+1)) >> 24);
+ (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
+ }
+ return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
+{
+ *(pkeys+0) = 305419896L;
+ *(pkeys+1) = 591751049L;
+ *(pkeys+2) = 878082192L;
+ while (*passwd != '\0') {
+ update_keys(pkeys,pcrc_32_tab,(int)*passwd);
+ passwd++;
+ }
+}
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+
+#define RAND_HEAD_LEN 12
+ /* "last resort" source for second part of crypt seed pattern */
+# ifndef ZCR_SEED2
+# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
+# endif
+
+static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
+ const char *passwd; /* password string */
+ unsigned char *buf; /* where to write header */
+ int bufSize;
+ unsigned long* pkeys;
+ const unsigned long* pcrc_32_tab;
+ unsigned long crcForCrypting;
+{
+ int n; /* index in random header */
+ int t; /* temporary */
+ int c; /* random byte */
+ unsigned char header[RAND_HEAD_LEN-2]; /* random header */
+ static unsigned calls = 0; /* ensure different random header each time */
+
+ if (bufSize<RAND_HEAD_LEN)
+ return 0;
+
+ /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+ * output of rand() to get less predictability, since rand() is
+ * often poorly implemented.
+ */
+ if (++calls == 1)
+ {
+ srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+ }
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ c = (rand() >> 7) & 0xff;
+ header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
+ }
+ /* Encrypt random header (last two bytes is high word of crc) */
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
+ }
+ buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
+ buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
+ return n;
+}
+
+#endif
diff --git a/zlib/contrib/minizip/ioapi.c b/zlib/contrib/minizip/ioapi.c
new file mode 100644
index 0000000..f1bee23
--- /dev/null
+++ b/zlib/contrib/minizip/ioapi.c
@@ -0,0 +1,177 @@
+/* ioapi.c -- IO base function header for compress/uncompress .zip
+ files using zlib + zip or unzip API
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+
+
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+voidpf ZCALLBACK fopen_file_func OF((
+ voidpf opaque,
+ const char* filename,
+ int mode));
+
+uLong ZCALLBACK fread_file_func OF((
+ voidpf opaque,
+ voidpf stream,
+ void* buf,
+ uLong size));
+
+uLong ZCALLBACK fwrite_file_func OF((
+ voidpf opaque,
+ voidpf stream,
+ const void* buf,
+ uLong size));
+
+long ZCALLBACK ftell_file_func OF((
+ voidpf opaque,
+ voidpf stream));
+
+long ZCALLBACK fseek_file_func OF((
+ voidpf opaque,
+ voidpf stream,
+ uLong offset,
+ int origin));
+
+int ZCALLBACK fclose_file_func OF((
+ voidpf opaque,
+ voidpf stream));
+
+int ZCALLBACK ferror_file_func OF((
+ voidpf opaque,
+ voidpf stream));
+
+
+voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
+ voidpf opaque;
+ const char* filename;
+ int mode;
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = fopen(filename, mode_fopen);
+ return file;
+}
+
+
+uLong ZCALLBACK fread_file_func (opaque, stream, buf, size)
+ voidpf opaque;
+ voidpf stream;
+ void* buf;
+ uLong size;
+{
+ uLong ret;
+ ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+
+uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size)
+ voidpf opaque;
+ voidpf stream;
+ const void* buf;
+ uLong size;
+{
+ uLong ret;
+ ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+long ZCALLBACK ftell_file_func (opaque, stream)
+ voidpf opaque;
+ voidpf stream;
+{
+ long ret;
+ ret = ftell((FILE *)stream);
+ return ret;
+}
+
+long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
+ voidpf opaque;
+ voidpf stream;
+ uLong offset;
+ int origin;
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+ fseek((FILE *)stream, offset, fseek_origin);
+ return ret;
+}
+
+int ZCALLBACK fclose_file_func (opaque, stream)
+ voidpf opaque;
+ voidpf stream;
+{
+ int ret;
+ ret = fclose((FILE *)stream);
+ return ret;
+}
+
+int ZCALLBACK ferror_file_func (opaque, stream)
+ voidpf opaque;
+ voidpf stream;
+{
+ int ret;
+ ret = ferror((FILE *)stream);
+ return ret;
+}
+
+void fill_fopen_filefunc (pzlib_filefunc_def)
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ pzlib_filefunc_def->zopen_file = fopen_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell_file = ftell_file_func;
+ pzlib_filefunc_def->zseek_file = fseek_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/zlib/contrib/minizip/ioapi.h b/zlib/contrib/minizip/ioapi.h
new file mode 100644
index 0000000..7d457ba
--- /dev/null
+++ b/zlib/contrib/minizip/ioapi.h
@@ -0,0 +1,75 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ files using zlib + zip or unzip API
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+#ifndef _ZLIBIOAPI_H
+#define _ZLIBIOAPI_H
+
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+
+#ifndef ZCALLBACK
+
+#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+#define ZCALLBACK CALLBACK
+#else
+#define ZCALLBACK
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
+typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc_def;
+
+
+
+void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+
+#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
+#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
+#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
+#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
+#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/zlib/contrib/minizip/iowin32.c b/zlib/contrib/minizip/iowin32.c
new file mode 100644
index 0000000..a9b5f78
--- /dev/null
+++ b/zlib/contrib/minizip/iowin32.c
@@ -0,0 +1,270 @@
+/* iowin32.c -- IO base function header for compress/uncompress .zip
+ files using zlib + zip or unzip API
+ This IO API version uses the Win32 API (for Microsoft Windows)
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+#include <stdlib.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+#include "iowin32.h"
+
+#ifndef INVALID_HANDLE_VALUE
+#define INVALID_HANDLE_VALUE (0xFFFFFFFF)
+#endif
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+voidpf ZCALLBACK win32_open_file_func OF((
+ voidpf opaque,
+ const char* filename,
+ int mode));
+
+uLong ZCALLBACK win32_read_file_func OF((
+ voidpf opaque,
+ voidpf stream,
+ void* buf,
+ uLong size));
+
+uLong ZCALLBACK win32_write_file_func OF((
+ voidpf opaque,
+ voidpf stream,
+ const void* buf,
+ uLong size));
+
+long ZCALLBACK win32_tell_file_func OF((
+ voidpf opaque,
+ voidpf stream));
+
+long ZCALLBACK win32_seek_file_func OF((
+ voidpf opaque,
+ voidpf stream,
+ uLong offset,
+ int origin));
+
+int ZCALLBACK win32_close_file_func OF((
+ voidpf opaque,
+ voidpf stream));
+
+int ZCALLBACK win32_error_file_func OF((
+ voidpf opaque,
+ voidpf stream));
+
+typedef struct
+{
+ HANDLE hf;
+ int error;
+} WIN32FILE_IOWIN;
+
+voidpf ZCALLBACK win32_open_file_func (opaque, filename, mode)
+ voidpf opaque;
+ const char* filename;
+ int mode;
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = 0;
+ voidpf ret=NULL;
+
+ dwDesiredAccess = dwShareMode = dwFlagsAndAttributes = 0;
+
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ {
+ dwDesiredAccess = GENERIC_READ;
+ dwCreationDisposition = OPEN_EXISTING;
+ dwShareMode = FILE_SHARE_READ;
+ }
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ {
+ dwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
+ dwCreationDisposition = OPEN_EXISTING;
+ }
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ {
+ dwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
+ dwCreationDisposition = CREATE_ALWAYS;
+ }
+
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL,
+ dwCreationDisposition, dwFlagsAndAttributes, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ hFile = NULL;
+
+ if (hFile != NULL)
+ {
+ WIN32FILE_IOWIN w32fiow;
+ w32fiow.hf = hFile;
+ w32fiow.error = 0;
+ ret = malloc(sizeof(WIN32FILE_IOWIN));
+ if (ret==NULL)
+ CloseHandle(hFile);
+ else *((WIN32FILE_IOWIN*)ret) = w32fiow;
+ }
+ return ret;
+}
+
+
+uLong ZCALLBACK win32_read_file_func (opaque, stream, buf, size)
+ voidpf opaque;
+ voidpf stream;
+ void* buf;
+ uLong size;
+{
+ uLong ret=0;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ if (hFile != NULL)
+ if (!ReadFile(hFile, buf, size, &ret, NULL))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_HANDLE_EOF)
+ dwErr = 0;
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ }
+
+ return ret;
+}
+
+
+uLong ZCALLBACK win32_write_file_func (opaque, stream, buf, size)
+ voidpf opaque;
+ voidpf stream;
+ const void* buf;
+ uLong size;
+{
+ uLong ret=0;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+
+ if (hFile !=NULL)
+ if (!WriteFile(hFile, buf, size, &ret, NULL))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_HANDLE_EOF)
+ dwErr = 0;
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ }
+
+ return ret;
+}
+
+long ZCALLBACK win32_tell_file_func (opaque, stream)
+ voidpf opaque;
+ voidpf stream;
+{
+ long ret=-1;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ if (hFile != NULL)
+ {
+ DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
+ if (dwSet == INVALID_SET_FILE_POINTER)
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=(long)dwSet;
+ }
+ return ret;
+}
+
+long ZCALLBACK win32_seek_file_func (opaque, stream, offset, origin)
+ voidpf opaque;
+ voidpf stream;
+ uLong offset;
+ int origin;
+{
+ DWORD dwMoveMethod=0xFFFFFFFF;
+ HANDLE hFile = NULL;
+
+ long ret=-1;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ dwMoveMethod = FILE_CURRENT;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ dwMoveMethod = FILE_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ dwMoveMethod = FILE_BEGIN;
+ break;
+ default: return -1;
+ }
+
+ if (hFile != NULL)
+ {
+ DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod);
+ if (dwSet == INVALID_SET_FILE_POINTER)
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=0;
+ }
+ return ret;
+}
+
+int ZCALLBACK win32_close_file_func (opaque, stream)
+ voidpf opaque;
+ voidpf stream;
+{
+ int ret=-1;
+
+ if (stream!=NULL)
+ {
+ HANDLE hFile;
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ if (hFile != NULL)
+ {
+ CloseHandle(hFile);
+ ret=0;
+ }
+ free(stream);
+ }
+ return ret;
+}
+
+int ZCALLBACK win32_error_file_func (opaque, stream)
+ voidpf opaque;
+ voidpf stream;
+{
+ int ret=-1;
+ if (stream!=NULL)
+ {
+ ret = ((WIN32FILE_IOWIN*)stream) -> error;
+ }
+ return ret;
+}
+
+void fill_win32_filefunc (pzlib_filefunc_def)
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ pzlib_filefunc_def->zopen_file = win32_open_file_func;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell_file = win32_tell_file_func;
+ pzlib_filefunc_def->zseek_file = win32_seek_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque=NULL;
+}
diff --git a/zlib/contrib/minizip/iowin32.h b/zlib/contrib/minizip/iowin32.h
new file mode 100644
index 0000000..a3a437a
--- /dev/null
+++ b/zlib/contrib/minizip/iowin32.h
@@ -0,0 +1,21 @@
+/* iowin32.h -- IO base function header for compress/uncompress .zip
+ files using zlib + zip or unzip API
+ This IO API version uses the Win32 API (for Microsoft Windows)
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+#include <windows.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/zlib/contrib/minizip/miniunz.c b/zlib/contrib/minizip/miniunz.c
new file mode 100644
index 0000000..f599938
--- /dev/null
+++ b/zlib/contrib/minizip/miniunz.c
@@ -0,0 +1,585 @@
+/*
+ miniunz.c
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "unzip.h"
+
+#define CASESENSITIVITY (0)
+#define WRITEBUFFERSIZE (8192)
+#define MAXFILENAME (256)
+
+#ifdef WIN32
+#define USEWIN32IOAPI
+#include "iowin32.h"
+#endif
+/*
+ mini unzip, demo of unzip package
+
+ usage :
+ Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir]
+
+ list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
+ if it exists
+*/
+
+
+/* change_file_date : change the date/time of a file
+ filename : the filename of the file where date/time must be modified
+ dosdate : the new date at the MSDos format (4 bytes)
+ tmu_date : the SAME new date at the tm_unz format */
+void change_file_date(filename,dosdate,tmu_date)
+ const char *filename;
+ uLong dosdate;
+ tm_unz tmu_date;
+{
+#ifdef WIN32
+ HANDLE hFile;
+ FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
+
+ hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,
+ 0,NULL,OPEN_EXISTING,0,NULL);
+ GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
+ DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
+ LocalFileTimeToFileTime(&ftLocal,&ftm);
+ SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
+ CloseHandle(hFile);
+#else
+#ifdef unix
+ struct utimbuf ut;
+ struct tm newdate;
+ newdate.tm_sec = tmu_date.tm_sec;
+ newdate.tm_min=tmu_date.tm_min;
+ newdate.tm_hour=tmu_date.tm_hour;
+ newdate.tm_mday=tmu_date.tm_mday;
+ newdate.tm_mon=tmu_date.tm_mon;
+ if (tmu_date.tm_year > 1900)
+ newdate.tm_year=tmu_date.tm_year - 1900;
+ else
+ newdate.tm_year=tmu_date.tm_year ;
+ newdate.tm_isdst=-1;
+
+ ut.actime=ut.modtime=mktime(&newdate);
+ utime(filename,&ut);
+#endif
+#endif
+}
+
+
+/* mymkdir and change_file_date are not 100 % portable
+ As I don't know well Unix, I wait feedback for the unix portion */
+
+int mymkdir(dirname)
+ const char* dirname;
+{
+ int ret=0;
+#ifdef WIN32
+ ret = mkdir(dirname);
+#else
+#ifdef unix
+ ret = mkdir (dirname,0775);
+#endif
+#endif
+ return ret;
+}
+
+int makedir (newdir)
+ char *newdir;
+{
+ char *buffer ;
+ char *p;
+ int len = (int)strlen(newdir);
+
+ if (len <= 0)
+ return 0;
+
+ buffer = (char*)malloc(len+1);
+ strcpy(buffer,newdir);
+
+ if (buffer[len-1] == '/') {
+ buffer[len-1] = '\0';
+ }
+ if (mymkdir(buffer) == 0)
+ {
+ free(buffer);
+ return 1;
+ }
+
+ p = buffer+1;
+ while (1)
+ {
+ char hold;
+
+ while(*p && *p != '\\' && *p != '/')
+ p++;
+ hold = *p;
+ *p = 0;
+ if ((mymkdir(buffer) == -1) && (errno == ENOENT))
+ {
+ printf("couldn't create directory %s\n",buffer);
+ free(buffer);
+ return 0;
+ }
+ if (hold == 0)
+ break;
+ *p++ = hold;
+ }
+ free(buffer);
+ return 1;
+}
+
+void do_banner()
+{
+ printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n");
+ printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
+}
+
+void do_help()
+{
+ printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \
+ " -e Extract without pathname (junk paths)\n" \
+ " -x Extract with pathname\n" \
+ " -v list files\n" \
+ " -l list files\n" \
+ " -d directory to extract into\n" \
+ " -o overwrite files without prompting\n" \
+ " -p extract crypted file using password\n\n");
+}
+
+
+int do_list(uf)
+ unzFile uf;
+{
+ uLong i;
+ unz_global_info gi;
+ int err;
+
+ err = unzGetGlobalInfo (uf,&gi);
+ if (err!=UNZ_OK)
+ printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+ printf(" Length Method Size Ratio Date Time CRC-32 Name\n");
+ printf(" ------ ------ ---- ----- ---- ---- ------ ----\n");
+ for (i=0;i<gi.number_entry;i++)
+ {
+ char filename_inzip[256];
+ unz_file_info file_info;
+ uLong ratio=0;
+ const char *string_method;
+ char charCrypt=' ';
+ err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+ break;
+ }
+ if (file_info.uncompressed_size>0)
+ ratio = (file_info.compressed_size*100)/file_info.uncompressed_size;
+
+ /* display a '*' if the file is crypted */
+ if ((file_info.flag & 1) != 0)
+ charCrypt='*';
+
+ if (file_info.compression_method==0)
+ string_method="Stored";
+ else
+ if (file_info.compression_method==Z_DEFLATED)
+ {
+ uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
+ if (iLevel==0)
+ string_method="Defl:N";
+ else if (iLevel==1)
+ string_method="Defl:X";
+ else if ((iLevel==2) || (iLevel==3))
+ string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
+ }
+ else
+ string_method="Unkn. ";
+
+ printf("%7lu %6s%c%7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n",
+ file_info.uncompressed_size,string_method,
+ charCrypt,
+ file_info.compressed_size,
+ ratio,
+ (uLong)file_info.tmu_date.tm_mon + 1,
+ (uLong)file_info.tmu_date.tm_mday,
+ (uLong)file_info.tmu_date.tm_year % 100,
+ (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
+ (uLong)file_info.crc,filename_inzip);
+ if ((i+1)<gi.number_entry)
+ {
+ err = unzGoToNextFile(uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGoToNextFile\n",err);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite,password)
+ unzFile uf;
+ const int* popt_extract_without_path;
+ int* popt_overwrite;
+ const char* password;
+{
+ char filename_inzip[256];
+ char* filename_withoutpath;
+ char* p;
+ int err=UNZ_OK;
+ FILE *fout=NULL;
+ void* buf;
+ uInt size_buf;
+
+ unz_file_info file_info;
+ uLong ratio=0;
+ err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+ return err;
+ }
+
+ size_buf = WRITEBUFFERSIZE;
+ buf = (void*)malloc(size_buf);
+ if (buf==NULL)
+ {
+ printf("Error allocating memory\n");
+ return UNZ_INTERNALERROR;
+ }
+
+ p = filename_withoutpath = filename_inzip;
+ while ((*p) != '\0')
+ {
+ if (((*p)=='/') || ((*p)=='\\'))
+ filename_withoutpath = p+1;
+ p++;
+ }
+
+ if ((*filename_withoutpath)=='\0')
+ {
+ if ((*popt_extract_without_path)==0)
+ {
+ printf("creating directory: %s\n",filename_inzip);
+ mymkdir(filename_inzip);
+ }
+ }
+ else
+ {
+ const char* write_filename;
+ int skip=0;
+
+ if ((*popt_extract_without_path)==0)
+ write_filename = filename_inzip;
+ else
+ write_filename = filename_withoutpath;
+
+ err = unzOpenCurrentFilePassword(uf,password);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
+ }
+
+ if (((*popt_overwrite)==0) && (err==UNZ_OK))
+ {
+ char rep=0;
+ FILE* ftestexist;
+ ftestexist = fopen(write_filename,"rb");
+ if (ftestexist!=NULL)
+ {
+ fclose(ftestexist);
+ do
+ {
+ char answer[128];
+ int ret;
+
+ printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
+ ret = scanf("%1s",answer);
+ if (ret != 1)
+ {
+ exit(EXIT_FAILURE);
+ }
+ rep = answer[0] ;
+ if ((rep>='a') && (rep<='z'))
+ rep -= 0x20;
+ }
+ while ((rep!='Y') && (rep!='N') && (rep!='A'));
+ }
+
+ if (rep == 'N')
+ skip = 1;
+
+ if (rep == 'A')
+ *popt_overwrite=1;
+ }
+
+ if ((skip==0) && (err==UNZ_OK))
+ {
+ fout=fopen(write_filename,"wb");
+
+ /* some zipfile don't contain directory alone before file */
+ if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
+ (filename_withoutpath!=(char*)filename_inzip))
+ {
+ char c=*(filename_withoutpath-1);
+ *(filename_withoutpath-1)='\0';
+ makedir(write_filename);
+ *(filename_withoutpath-1)=c;
+ fout=fopen(write_filename,"wb");
+ }
+
+ if (fout==NULL)
+ {
+ printf("error opening %s\n",write_filename);
+ }
+ }
+
+ if (fout!=NULL)
+ {
+ printf(" extracting: %s\n",write_filename);
+
+ do
+ {
+ err = unzReadCurrentFile(uf,buf,size_buf);
+ if (err<0)
+ {
+ printf("error %d with zipfile in unzReadCurrentFile\n",err);
+ break;
+ }
+ if (err>0)
+ if (fwrite(buf,err,1,fout)!=1)
+ {
+ printf("error in writing extracted file\n");
+ err=UNZ_ERRNO;
+ break;
+ }
+ }
+ while (err>0);
+ if (fout)
+ fclose(fout);
+
+ if (err==0)
+ change_file_date(write_filename,file_info.dosDate,
+ file_info.tmu_date);
+ }
+
+ if (err==UNZ_OK)
+ {
+ err = unzCloseCurrentFile (uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzCloseCurrentFile\n",err);
+ }
+ }
+ else
+ unzCloseCurrentFile(uf); /* don't lose the error */
+ }
+
+ free(buf);
+ return err;
+}
+
+
+int do_extract(uf,opt_extract_without_path,opt_overwrite,password)
+ unzFile uf;
+ int opt_extract_without_path;
+ int opt_overwrite;
+ const char* password;
+{
+ uLong i;
+ unz_global_info gi;
+ int err;
+ FILE* fout=NULL;
+
+ err = unzGetGlobalInfo (uf,&gi);
+ if (err!=UNZ_OK)
+ printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+
+ for (i=0;i<gi.number_entry;i++)
+ {
+ if (do_extract_currentfile(uf,&opt_extract_without_path,
+ &opt_overwrite,
+ password) != UNZ_OK)
+ break;
+
+ if ((i+1)<gi.number_entry)
+ {
+ err = unzGoToNextFile(uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGoToNextFile\n",err);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite,password)
+ unzFile uf;
+ const char* filename;
+ int opt_extract_without_path;
+ int opt_overwrite;
+ const char* password;
+{
+ int err = UNZ_OK;
+ if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
+ {
+ printf("file %s not found in the zipfile\n",filename);
+ return 2;
+ }
+
+ if (do_extract_currentfile(uf,&opt_extract_without_path,
+ &opt_overwrite,
+ password) == UNZ_OK)
+ return 0;
+ else
+ return 1;
+}
+
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ const char *zipfilename=NULL;
+ const char *filename_to_extract=NULL;
+ const char *password=NULL;
+ char filename_try[MAXFILENAME+16] = "";
+ int i;
+ int opt_do_list=0;
+ int opt_do_extract=1;
+ int opt_do_extract_withoutpath=0;
+ int opt_overwrite=0;
+ int opt_extractdir=0;
+ const char *dirname=NULL;
+ unzFile uf=NULL;
+
+ do_banner();
+ if (argc==1)
+ {
+ do_help();
+ return 0;
+ }
+ else
+ {
+ for (i=1;i<argc;i++)
+ {
+ if ((*argv[i])=='-')
+ {
+ const char *p=argv[i]+1;
+
+ while ((*p)!='\0')
+ {
+ char c=*(p++);;
+ if ((c=='l') || (c=='L'))
+ opt_do_list = 1;
+ if ((c=='v') || (c=='V'))
+ opt_do_list = 1;
+ if ((c=='x') || (c=='X'))
+ opt_do_extract = 1;
+ if ((c=='e') || (c=='E'))
+ opt_do_extract = opt_do_extract_withoutpath = 1;
+ if ((c=='o') || (c=='O'))
+ opt_overwrite=1;
+ if ((c=='d') || (c=='D'))
+ {
+ opt_extractdir=1;
+ dirname=argv[i+1];
+ }
+
+ if (((c=='p') || (c=='P')) && (i+1<argc))
+ {
+ password=argv[i+1];
+ i++;
+ }
+ }
+ }
+ else
+ {
+ if (zipfilename == NULL)
+ zipfilename = argv[i];
+ else if ((filename_to_extract==NULL) && (!opt_extractdir))
+ filename_to_extract = argv[i] ;
+ }
+ }
+ }
+
+ if (zipfilename!=NULL)
+ {
+
+# ifdef USEWIN32IOAPI
+ zlib_filefunc_def ffunc;
+# endif
+
+ strncpy(filename_try, zipfilename,MAXFILENAME-1);
+ /* strncpy doesnt append the trailing NULL, of the string is too long. */
+ filename_try[ MAXFILENAME ] = '\0';
+
+# ifdef USEWIN32IOAPI
+ fill_win32_filefunc(&ffunc);
+ uf = unzOpen2(zipfilename,&ffunc);
+# else
+ uf = unzOpen(zipfilename);
+# endif
+ if (uf==NULL)
+ {
+ strcat(filename_try,".zip");
+# ifdef USEWIN32IOAPI
+ uf = unzOpen2(filename_try,&ffunc);
+# else
+ uf = unzOpen(filename_try);
+# endif
+ }
+ }
+
+ if (uf==NULL)
+ {
+ printf("Cannot open %s or %s.zip\n",zipfilename,zipfilename);
+ return 1;
+ }
+ printf("%s opened\n",filename_try);
+
+ if (opt_do_list==1)
+ return do_list(uf);
+ else if (opt_do_extract==1)
+ {
+ if (opt_extractdir && chdir(dirname))
+ {
+ printf("Error changing into %s, aborting\n", dirname);
+ exit(-1);
+ }
+
+ if (filename_to_extract == NULL)
+ return do_extract(uf,opt_do_extract_withoutpath,opt_overwrite,password);
+ else
+ return do_extract_onefile(uf,filename_to_extract,
+ opt_do_extract_withoutpath,opt_overwrite,password);
+ }
+ unzCloseCurrentFile(uf);
+
+ return 0;
+}
diff --git a/zlib/contrib/minizip/minizip.c b/zlib/contrib/minizip/minizip.c
new file mode 100644
index 0000000..f2dfecd
--- /dev/null
+++ b/zlib/contrib/minizip/minizip.c
@@ -0,0 +1,420 @@
+/*
+ minizip.c
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "zip.h"
+
+#ifdef WIN32
+#define USEWIN32IOAPI
+#include "iowin32.h"
+#endif
+
+
+
+#define WRITEBUFFERSIZE (16384)
+#define MAXFILENAME (256)
+
+#ifdef WIN32
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ int ret = 0;
+ {
+ FILETIME ftLocal;
+ HANDLE hFind;
+ WIN32_FIND_DATA ff32;
+
+ hFind = FindFirstFile(f,&ff32);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
+ FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
+ FindClose(hFind);
+ ret = 1;
+ }
+ }
+ return ret;
+}
+#else
+#ifdef unix
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ int ret=0;
+ struct stat s; /* results of stat() */
+ struct tm* filedate;
+ time_t tm_t=0;
+
+ if (strcmp(f,"-")!=0)
+ {
+ char name[MAXFILENAME+1];
+ int len = strlen(f);
+ if (len > MAXFILENAME)
+ len = MAXFILENAME;
+
+ strncpy(name, f,MAXFILENAME-1);
+ /* strncpy doesnt append the trailing NULL, of the string is too long. */
+ name[ MAXFILENAME ] = '\0';
+
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (stat(name,&s)==0)
+ {
+ tm_t = s.st_mtime;
+ ret = 1;
+ }
+ }
+ filedate = localtime(&tm_t);
+
+ tmzip->tm_sec = filedate->tm_sec;
+ tmzip->tm_min = filedate->tm_min;
+ tmzip->tm_hour = filedate->tm_hour;
+ tmzip->tm_mday = filedate->tm_mday;
+ tmzip->tm_mon = filedate->tm_mon ;
+ tmzip->tm_year = filedate->tm_year;
+
+ return ret;
+}
+#else
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ return 0;
+}
+#endif
+#endif
+
+
+
+
+int check_exist_file(filename)
+ const char* filename;
+{
+ FILE* ftestexist;
+ int ret = 1;
+ ftestexist = fopen(filename,"rb");
+ if (ftestexist==NULL)
+ ret = 0;
+ else
+ fclose(ftestexist);
+ return ret;
+}
+
+void do_banner()
+{
+ printf("MiniZip 1.01b, demo of zLib + Zip package written by Gilles Vollant\n");
+ printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
+}
+
+void do_help()
+{
+ printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] file.zip [files_to_add]\n\n" \
+ " -o Overwrite existing file.zip\n" \
+ " -a Append to existing file.zip\n" \
+ " -0 Store only\n" \
+ " -1 Compress faster\n" \
+ " -9 Compress better\n\n");
+}
+
+/* calculate the CRC32 of a file,
+ because to encrypt a file, we need known the CRC32 of the file before */
+int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc)
+{
+ unsigned long calculate_crc=0;
+ int err=ZIP_OK;
+ FILE * fin = fopen(filenameinzip,"rb");
+ unsigned long size_read = 0;
+ unsigned long total_read = 0;
+ if (fin==NULL)
+ {
+ err = ZIP_ERRNO;
+ }
+
+ if (err == ZIP_OK)
+ do
+ {
+ err = ZIP_OK;
+ size_read = (int)fread(buf,1,size_buf,fin);
+ if (size_read < size_buf)
+ if (feof(fin)==0)
+ {
+ printf("error in reading %s\n",filenameinzip);
+ err = ZIP_ERRNO;
+ }
+
+ if (size_read>0)
+ calculate_crc = crc32(calculate_crc,buf,size_read);
+ total_read += size_read;
+
+ } while ((err == ZIP_OK) && (size_read>0));
+
+ if (fin)
+ fclose(fin);
+
+ *result_crc=calculate_crc;
+ printf("file %s crc %x\n",filenameinzip,calculate_crc);
+ return err;
+}
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ int opt_overwrite=0;
+ int opt_compress_level=Z_DEFAULT_COMPRESSION;
+ int zipfilenamearg = 0;
+ char filename_try[MAXFILENAME+16];
+ int zipok;
+ int err=0;
+ int size_buf=0;
+ void* buf=NULL;
+ const char* password=NULL;
+
+
+ do_banner();
+ if (argc==1)
+ {
+ do_help();
+ return 0;
+ }
+ else
+ {
+ for (i=1;i<argc;i++)
+ {
+ if ((*argv[i])=='-')
+ {
+ const char *p=argv[i]+1;
+
+ while ((*p)!='\0')
+ {
+ char c=*(p++);;
+ if ((c=='o') || (c=='O'))
+ opt_overwrite = 1;
+ if ((c=='a') || (c=='A'))
+ opt_overwrite = 2;
+ if ((c>='0') && (c<='9'))
+ opt_compress_level = c-'0';
+
+ if (((c=='p') || (c=='P')) && (i+1<argc))
+ {
+ password=argv[i+1];
+ i++;
+ }
+ }
+ }
+ else
+ if (zipfilenamearg == 0)
+ zipfilenamearg = i ;
+ }
+ }
+
+ size_buf = WRITEBUFFERSIZE;
+ buf = (void*)malloc(size_buf);
+ if (buf==NULL)
+ {
+ printf("Error allocating memory\n");
+ return ZIP_INTERNALERROR;
+ }
+
+ if (zipfilenamearg==0)
+ zipok=0;
+ else
+ {
+ int i,len;
+ int dot_found=0;
+
+ zipok = 1 ;
+ strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1);
+ /* strncpy doesnt append the trailing NULL, of the string is too long. */
+ filename_try[ MAXFILENAME ] = '\0';
+
+ len=(int)strlen(filename_try);
+ for (i=0;i<len;i++)
+ if (filename_try[i]=='.')
+ dot_found=1;
+
+ if (dot_found==0)
+ strcat(filename_try,".zip");
+
+ if (opt_overwrite==2)
+ {
+ /* if the file don't exist, we not append file */
+ if (check_exist_file(filename_try)==0)
+ opt_overwrite=1;
+ }
+ else
+ if (opt_overwrite==0)
+ if (check_exist_file(filename_try)!=0)
+ {
+ char rep=0;
+ do
+ {
+ char answer[128];
+ int ret;
+ printf("The file %s exists. Overwrite ? [y]es, [n]o, [a]ppend : ",filename_try);
+ ret = scanf("%1s",answer);
+ if (ret != 1)
+ {
+ exit(EXIT_FAILURE);
+ }
+ rep = answer[0] ;
+ if ((rep>='a') && (rep<='z'))
+ rep -= 0x20;
+ }
+ while ((rep!='Y') && (rep!='N') && (rep!='A'));
+ if (rep=='N')
+ zipok = 0;
+ if (rep=='A')
+ opt_overwrite = 2;
+ }
+ }
+
+ if (zipok==1)
+ {
+ zipFile zf;
+ int errclose;
+# ifdef USEWIN32IOAPI
+ zlib_filefunc_def ffunc;
+ fill_win32_filefunc(&ffunc);
+ zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc);
+# else
+ zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0);
+# endif
+
+ if (zf == NULL)
+ {
+ printf("error opening %s\n",filename_try);
+ err= ZIP_ERRNO;
+ }
+ else
+ printf("creating %s\n",filename_try);
+
+ for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++)
+ {
+ if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) &&
+ ((argv[i][1]=='o') || (argv[i][1]=='O') ||
+ (argv[i][1]=='a') || (argv[i][1]=='A') ||
+ (argv[i][1]=='p') || (argv[i][1]=='P') ||
+ ((argv[i][1]>='0') || (argv[i][1]<='9'))) &&
+ (strlen(argv[i]) == 2)))
+ {
+ FILE * fin;
+ int size_read;
+ const char* filenameinzip = argv[i];
+ zip_fileinfo zi;
+ unsigned long crcFile=0;
+
+ zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
+ zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
+ zi.dosDate = 0;
+ zi.internal_fa = 0;
+ zi.external_fa = 0;
+ filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
+
+/*
+ err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
+ NULL,0,NULL,0,NULL / * comment * /,
+ (opt_compress_level != 0) ? Z_DEFLATED : 0,
+ opt_compress_level);
+*/
+ if ((password != NULL) && (err==ZIP_OK))
+ err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
+
+ err = zipOpenNewFileInZip3(zf,filenameinzip,&zi,
+ NULL,0,NULL,0,NULL /* comment*/,
+ (opt_compress_level != 0) ? Z_DEFLATED : 0,
+ opt_compress_level,0,
+ /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ password,crcFile);
+
+ if (err != ZIP_OK)
+ printf("error in opening %s in zipfile\n",filenameinzip);
+ else
+ {
+ fin = fopen(filenameinzip,"rb");
+ if (fin==NULL)
+ {
+ err=ZIP_ERRNO;
+ printf("error in opening %s for reading\n",filenameinzip);
+ }
+ }
+
+ if (err == ZIP_OK)
+ do
+ {
+ err = ZIP_OK;
+ size_read = (int)fread(buf,1,size_buf,fin);
+ if (size_read < size_buf)
+ if (feof(fin)==0)
+ {
+ printf("error in reading %s\n",filenameinzip);
+ err = ZIP_ERRNO;
+ }
+
+ if (size_read>0)
+ {
+ err = zipWriteInFileInZip (zf,buf,size_read);
+ if (err<0)
+ {
+ printf("error in writing %s in the zipfile\n",
+ filenameinzip);
+ }
+
+ }
+ } while ((err == ZIP_OK) && (size_read>0));
+
+ if (fin)
+ fclose(fin);
+
+ if (err<0)
+ err=ZIP_ERRNO;
+ else
+ {
+ err = zipCloseFileInZip(zf);
+ if (err!=ZIP_OK)
+ printf("error in closing %s in the zipfile\n",
+ filenameinzip);
+ }
+ }
+ }
+ errclose = zipClose(zf,NULL);
+ if (errclose != ZIP_OK)
+ printf("error in closing %s\n",filename_try);
+ }
+ else
+ {
+ do_help();
+ }
+
+ free(buf);
+ return 0;
+}
diff --git a/zlib/contrib/minizip/mztools.c b/zlib/contrib/minizip/mztools.c
new file mode 100644
index 0000000..8a50ee4
--- /dev/null
+++ b/zlib/contrib/minizip/mztools.c
@@ -0,0 +1,281 @@
+/*
+ Additional tools for Minizip
+ Code: Xavier Roche '2004
+ License: Same as ZLIB (www.gzip.org)
+*/
+
+/* Code */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "unzip.h"
+
+#define READ_8(adr) ((unsigned char)*(adr))
+#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) )
+#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) )
+
+#define WRITE_8(buff, n) do { \
+ *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \
+} while(0)
+#define WRITE_16(buff, n) do { \
+ WRITE_8((unsigned char*)(buff), n); \
+ WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
+} while(0)
+#define WRITE_32(buff, n) do { \
+ WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
+ WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
+} while(0)
+
+extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered)
+const char* file;
+const char* fileOut;
+const char* fileOutTmp;
+uLong* nRecovered;
+uLong* bytesRecovered;
+{
+ int err = Z_OK;
+ FILE* fpZip = fopen(file, "rb");
+ FILE* fpOut = fopen(fileOut, "wb");
+ FILE* fpOutCD = fopen(fileOutTmp, "wb");
+ if (fpZip != NULL && fpOut != NULL) {
+ int entries = 0;
+ uLong totalBytes = 0;
+ char header[30];
+ char filename[256];
+ char extra[1024];
+ int offset = 0;
+ int offsetCD = 0;
+ while ( fread(header, 1, 30, fpZip) == 30 ) {
+ int currentOffset = offset;
+
+ /* File entry */
+ if (READ_32(header) == 0x04034b50) {
+ unsigned int version = READ_16(header + 4);
+ unsigned int gpflag = READ_16(header + 6);
+ unsigned int method = READ_16(header + 8);
+ unsigned int filetime = READ_16(header + 10);
+ unsigned int filedate = READ_16(header + 12);
+ unsigned int crc = READ_32(header + 14); /* crc */
+ unsigned int cpsize = READ_32(header + 18); /* compressed size */
+ unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */
+ unsigned int fnsize = READ_16(header + 26); /* file name length */
+ unsigned int extsize = READ_16(header + 28); /* extra field length */
+ filename[0] = extra[0] = '\0';
+
+ /* Header */
+ if (fwrite(header, 1, 30, fpOut) == 30) {
+ offset += 30;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+
+ /* Filename */
+ if (fnsize > 0) {
+ if (fread(filename, 1, fnsize, fpZip) == fnsize) {
+ if (fwrite(filename, 1, fnsize, fpOut) == fnsize) {
+ offset += fnsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_STREAM_ERROR;
+ break;
+ }
+
+ /* Extra field */
+ if (extsize > 0) {
+ if (fread(extra, 1, extsize, fpZip) == extsize) {
+ if (fwrite(extra, 1, extsize, fpOut) == extsize) {
+ offset += extsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+ /* Data */
+ {
+ int dataSize = cpsize;
+ if (dataSize == 0) {
+ dataSize = uncpsize;
+ }
+ if (dataSize > 0) {
+ char* data = malloc(dataSize);
+ if (data != NULL) {
+ if ((int)fread(data, 1, dataSize, fpZip) == dataSize) {
+ if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) {
+ offset += dataSize;
+ totalBytes += dataSize;
+ } else {
+ err = Z_ERRNO;
+ }
+ } else {
+ err = Z_ERRNO;
+ }
+ free(data);
+ if (err != Z_OK) {
+ break;
+ }
+ } else {
+ err = Z_MEM_ERROR;
+ break;
+ }
+ }
+ }
+
+ /* Central directory entry */
+ {
+ char header[46];
+ char* comment = "";
+ int comsize = (int) strlen(comment);
+ WRITE_32(header, 0x02014b50);
+ WRITE_16(header + 4, version);
+ WRITE_16(header + 6, version);
+ WRITE_16(header + 8, gpflag);
+ WRITE_16(header + 10, method);
+ WRITE_16(header + 12, filetime);
+ WRITE_16(header + 14, filedate);
+ WRITE_32(header + 16, crc);
+ WRITE_32(header + 20, cpsize);
+ WRITE_32(header + 24, uncpsize);
+ WRITE_16(header + 28, fnsize);
+ WRITE_16(header + 30, extsize);
+ WRITE_16(header + 32, comsize);
+ WRITE_16(header + 34, 0); /* disk # */
+ WRITE_16(header + 36, 0); /* int attrb */
+ WRITE_32(header + 38, 0); /* ext attrb */
+ WRITE_32(header + 42, currentOffset);
+ /* Header */
+ if (fwrite(header, 1, 46, fpOutCD) == 46) {
+ offsetCD += 46;
+
+ /* Filename */
+ if (fnsize > 0) {
+ if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) {
+ offsetCD += fnsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_STREAM_ERROR;
+ break;
+ }
+
+ /* Extra field */
+ if (extsize > 0) {
+ if (fwrite(extra, 1, extsize, fpOutCD) == extsize) {
+ offsetCD += extsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+ /* Comment field */
+ if (comsize > 0) {
+ if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) {
+ offsetCD += comsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+ /* Success */
+ entries++;
+
+ } else {
+ break;
+ }
+ }
+
+ /* Final central directory */
+ {
+ int entriesZip = entries;
+ char header[22];
+ char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools";
+ int comsize = (int) strlen(comment);
+ if (entriesZip > 0xffff) {
+ entriesZip = 0xffff;
+ }
+ WRITE_32(header, 0x06054b50);
+ WRITE_16(header + 4, 0); /* disk # */
+ WRITE_16(header + 6, 0); /* disk # */
+ WRITE_16(header + 8, entriesZip); /* hack */
+ WRITE_16(header + 10, entriesZip); /* hack */
+ WRITE_32(header + 12, offsetCD); /* size of CD */
+ WRITE_32(header + 16, offset); /* offset to CD */
+ WRITE_16(header + 20, comsize); /* comment */
+
+ /* Header */
+ if (fwrite(header, 1, 22, fpOutCD) == 22) {
+
+ /* Comment field */
+ if (comsize > 0) {
+ if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) {
+ err = Z_ERRNO;
+ }
+ }
+
+ } else {
+ err = Z_ERRNO;
+ }
+ }
+
+ /* Final merge (file + central directory) */
+ fclose(fpOutCD);
+ if (err == Z_OK) {
+ fpOutCD = fopen(fileOutTmp, "rb");
+ if (fpOutCD != NULL) {
+ int nRead;
+ char buffer[8192];
+ while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) {
+ if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+ fclose(fpOutCD);
+ }
+ }
+
+ /* Close */
+ fclose(fpZip);
+ fclose(fpOut);
+
+ /* Wipe temporary file */
+ (void)remove(fileOutTmp);
+
+ /* Number of recovered entries */
+ if (err == Z_OK) {
+ if (nRecovered != NULL) {
+ *nRecovered = entries;
+ }
+ if (bytesRecovered != NULL) {
+ *bytesRecovered = totalBytes;
+ }
+ }
+ } else {
+ err = Z_STREAM_ERROR;
+ }
+ return err;
+}
diff --git a/zlib/contrib/minizip/mztools.h b/zlib/contrib/minizip/mztools.h
new file mode 100644
index 0000000..eee78dc
--- /dev/null
+++ b/zlib/contrib/minizip/mztools.h
@@ -0,0 +1,31 @@
+/*
+ Additional tools for Minizip
+ Code: Xavier Roche '2004
+ License: Same as ZLIB (www.gzip.org)
+*/
+
+#ifndef _zip_tools_H
+#define _zip_tools_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#include "unzip.h"
+
+/* Repair a ZIP file (missing central directory)
+ file: file to recover
+ fileOut: output file after recovery
+ fileOutTmp: temporary file name used for recovery
+*/
+extern int ZEXPORT unzRepair(const char* file,
+ const char* fileOut,
+ const char* fileOutTmp,
+ uLong* nRecovered,
+ uLong* bytesRecovered);
+
+#endif
diff --git a/zlib/contrib/minizip/unzip.c b/zlib/contrib/minizip/unzip.c
new file mode 100644
index 0000000..9ad4766
--- /dev/null
+++ b/zlib/contrib/minizip/unzip.c
@@ -0,0 +1,1598 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ Read unzip.h for more info
+*/
+
+/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
+compatibility with older software. The following is from the original crypt.c. Code
+woven in by Terry Thorsen 1/2003.
+*/
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h]
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+ */
+
+/*
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+#ifndef CASESENSITIVITYDEFAULT_NO
+# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+# define CASESENSITIVITYDEFAULT_NO
+# endif
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+
+
+const char unz_copyright[] =
+ " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info_internal_s
+{
+ uLong offset_curfile;/* relative offset of local header 4 bytes */
+} unz_file_info_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+ when reading and decompress it */
+typedef struct
+{
+ char *read_buffer; /* internal buffer for compressed data */
+ z_stream stream; /* zLib stream structure for inflate */
+
+ uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
+ uLong stream_initialised; /* flag set if stream structure is initialised*/
+
+ uLong offset_local_extrafield;/* offset of the local extra field */
+ uInt size_local_extrafield;/* size of the local extra field */
+ uLong pos_local_extrafield; /* position in the local extra field in read*/
+
+ uLong crc32; /* crc32 of all data uncompressed */
+ uLong crc32_wait; /* crc32 we must obtain after decompress all */
+ uLong rest_read_compressed; /* number of byte to be decompressed */
+ uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+ zlib_filefunc_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ uLong compression_method; /* compression method (0==store) */
+ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ int raw;
+} file_in_zip_read_info_s;
+
+
+/* unz_s contain internal information about the zipfile
+*/
+typedef struct
+{
+ zlib_filefunc_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ unz_global_info gi; /* public global information */
+ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ uLong num_file; /* number of the current file in the zipfile*/
+ uLong pos_in_central_dir; /* pos of the current file in the central dir*/
+ uLong current_file_ok; /* flag about the usability of the current file*/
+ uLong central_pos; /* position of the beginning of the central dir*/
+
+ uLong size_central_dir; /* size of the central directory */
+ uLong offset_central_dir; /* offset of start of central directory with
+ respect to the starting disk number */
+
+ unz_file_info cur_file_info; /* public info about the current file in zip*/
+ unz_file_info_internal cur_file_info_internal; /* private info about it*/
+ file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
+ file if we are decompressing it */
+ int encrypted;
+# ifndef NOUNCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const unsigned long* pcrc_32_tab;
+# endif
+} unz_s;
+
+
+#ifndef NOUNCRYPT
+#include "crypt.h"
+#endif
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unzlocal_getByte OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream,
+ int *pi));
+
+local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+ int *pi;
+{
+ unsigned char c;
+ int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return UNZ_OK;
+ }
+ else
+ {
+ if (ZERROR(*pzlib_filefunc_def,filestream))
+ return UNZ_ERRNO;
+ else
+ return UNZ_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int unzlocal_getShort OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+ uLong *pX;
+{
+ uLong x ;
+ int i;
+ int err;
+
+ err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unzlocal_getLong OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+ uLong *pX;
+{
+ uLong x ;
+ int i;
+ int err;
+
+ err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (fileName1,fileName2)
+ const char* fileName1;
+ const char* fileName2;
+{
+ for (;;)
+ {
+ char c1=*(fileName1++);
+ char c2=*(fileName2++);
+ if ((c1>='a') && (c1<='z'))
+ c1 -= 0x20;
+ if ((c2>='a') && (c2<='z'))
+ c2 -= 0x20;
+ if (c1=='\0')
+ return ((c2=='\0') ? 0 : -1);
+ if (c2=='\0')
+ return 1;
+ if (c1<c2)
+ return -1;
+ if (c1>c2)
+ return 1;
+ }
+}
+
+
+#ifdef CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
+ const char* fileName1;
+ const char* fileName2;
+ int iCaseSensitivity;
+{
+ if (iCaseSensitivity==0)
+ iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+ if (iCaseSensitivity==1)
+ return strcmp(fileName1,fileName2);
+
+ return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local uLong unzlocal_SearchCentralDir OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream));
+
+local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+{
+ unsigned char* buf;
+ uLong uSizeFile;
+ uLong uBackRead;
+ uLong uMaxBack=0xffff; /* maximum size of global comment */
+ uLong uPosFound=0;
+
+ if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize,uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
+ if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
+ "zlib/zlib114.zip".
+ If the zipfile cannot be opened (file doesn't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def)
+ const char *path;
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ unz_s us;
+ unz_s *s;
+ uLong central_pos,uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ uLong number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+
+ int err=UNZ_OK;
+
+ if (unz_copyright[0]!=' ')
+ return NULL;
+
+ if (pzlib_filefunc_def==NULL)
+ fill_fopen_filefunc(&us.z_filefunc);
+ else
+ us.z_filefunc = *pzlib_filefunc_def;
+
+ us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque,
+ path,
+ ZLIB_FILEFUNC_MODE_READ |
+ ZLIB_FILEFUNC_MODE_EXISTING);
+ if (us.filestream==NULL)
+ return NULL;
+
+ central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream);
+ if (central_pos==0)
+ err=UNZ_ERRNO;
+
+ if (ZSEEK(us.z_filefunc, us.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central dir */
+ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* zipfile comment length */
+ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
+ (err==UNZ_OK))
+ err=UNZ_BADZIPFILE;
+
+ if (err!=UNZ_OK)
+ {
+ ZCLOSE(us.z_filefunc, us.filestream);
+ return NULL;
+ }
+
+ us.byte_before_the_zipfile = central_pos -
+ (us.offset_central_dir+us.size_central_dir);
+ us.central_pos = central_pos;
+ us.pfile_in_zip_read = NULL;
+ us.encrypted = 0;
+
+
+ s=(unz_s*)ALLOC(sizeof(unz_s));
+ *s=us;
+ unzGoToFirstFile((unzFile)s);
+ return (unzFile)s;
+}
+
+
+extern unzFile ZEXPORT unzOpen (path)
+ const char *path;
+{
+ return unzOpen2(path, NULL);
+}
+
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (file)
+ unzFile file;
+{
+ unz_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+
+ if (s->pfile_in_zip_read!=NULL)
+ unzCloseCurrentFile(file);
+
+ ZCLOSE(s->z_filefunc, s->filestream);
+ TRYFREE(s);
+ return UNZ_OK;
+}
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
+ unzFile file;
+ unz_global_info *pglobal_info;
+{
+ unz_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ *pglobal_info=s->gi;
+ return UNZ_OK;
+}
+
+
+/*
+ Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
+ uLong ulDosDate;
+ tm_unz* ptm;
+{
+ uLong uDate;
+ uDate = (uLong)(ulDosDate>>16);
+ ptm->tm_mday = (uInt)(uDate&0x1f) ;
+ ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+ ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+ ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+ ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
+ ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+ Get Info about the current file in the zipfile, with internal only info
+*/
+local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
+ unz_file_info *pfile_info,
+ unz_file_info_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+local int unzlocal_GetCurrentFileInfoInternal (file,
+ pfile_info,
+ pfile_info_internal,
+ szFileName, fileNameBufferSize,
+ extraField, extraFieldBufferSize,
+ szComment, commentBufferSize)
+ unzFile file;
+ unz_file_info *pfile_info;
+ unz_file_info_internal *pfile_info_internal;
+ char *szFileName;
+ uLong fileNameBufferSize;
+ void *extraField;
+ uLong extraFieldBufferSize;
+ char *szComment;
+ uLong commentBufferSize;
+{
+ unz_s* s;
+ unz_file_info file_info;
+ unz_file_info_internal file_info_internal;
+ int err=UNZ_OK;
+ uLong uMagic;
+ long lSeek=0;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (ZSEEK(s->z_filefunc, s->filestream,
+ s->pos_in_central_dir+s->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+
+ /* we check the magic */
+ if (err==UNZ_OK)
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x02014b50)
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ lSeek+=file_info.size_filename;
+ if ((err==UNZ_OK) && (szFileName!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_filename<fileNameBufferSize)
+ {
+ *(szFileName+file_info.size_filename)='\0';
+ uSizeRead = file_info.size_filename;
+ }
+ else
+ uSizeRead = fileNameBufferSize;
+
+ if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+ if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek -= uSizeRead;
+ }
+
+
+ if ((err==UNZ_OK) && (extraField!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_file_extra<extraFieldBufferSize)
+ uSizeRead = file_info.size_file_extra;
+ else
+ uSizeRead = extraFieldBufferSize;
+
+ if (lSeek!=0)
+ if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+ if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek += file_info.size_file_extra - uSizeRead;
+ }
+ else
+ lSeek+=file_info.size_file_extra;
+
+
+ if ((err==UNZ_OK) && (szComment!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_file_comment<commentBufferSize)
+ {
+ *(szComment+file_info.size_file_comment)='\0';
+ uSizeRead = file_info.size_file_comment;
+ }
+ else
+ uSizeRead = commentBufferSize;
+
+ if (lSeek!=0)
+ if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+ if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek+=file_info.size_file_comment - uSizeRead;
+ }
+ else
+ lSeek+=file_info.size_file_comment;
+
+ if ((err==UNZ_OK) && (pfile_info!=NULL))
+ *pfile_info=file_info;
+
+ if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+ *pfile_info_internal=file_info_internal;
+
+ return err;
+}
+
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo (file,
+ pfile_info,
+ szFileName, fileNameBufferSize,
+ extraField, extraFieldBufferSize,
+ szComment, commentBufferSize)
+ unzFile file;
+ unz_file_info *pfile_info;
+ char *szFileName;
+ uLong fileNameBufferSize;
+ void *extraField;
+ uLong extraFieldBufferSize;
+ char *szComment;
+ uLong commentBufferSize;
+{
+ return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+}
+
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (file)
+ unzFile file;
+{
+ int err=UNZ_OK;
+ unz_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ s->pos_in_central_dir=s->offset_central_dir;
+ s->num_file=0;
+ err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (file)
+ unzFile file;
+{
+ unz_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */
+ if (s->num_file+1==s->gi.number_entry)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+ s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+ s->num_file++;
+ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzipStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
+ unzFile file;
+ const char *szFileName;
+ int iCaseSensitivity;
+{
+ unz_s* s;
+ int err;
+
+ /* We remember the 'current' position in the file so that we can jump
+ * back there if we fail.
+ */
+ unz_file_info cur_file_infoSaved;
+ unz_file_info_internal cur_file_info_internalSaved;
+ uLong num_fileSaved;
+ uLong pos_in_central_dirSaved;
+
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+
+ if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+ return UNZ_PARAMERROR;
+
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ /* Save the current state */
+ num_fileSaved = s->num_file;
+ pos_in_central_dirSaved = s->pos_in_central_dir;
+ cur_file_infoSaved = s->cur_file_info;
+ cur_file_info_internalSaved = s->cur_file_info_internal;
+
+ err = unzGoToFirstFile(file);
+
+ while (err == UNZ_OK)
+ {
+ char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+ err = unzGetCurrentFileInfo(file,NULL,
+ szCurrentFileName,sizeof(szCurrentFileName)-1,
+ NULL,0,NULL,0);
+ if (err == UNZ_OK)
+ {
+ if (unzStringFileNameCompare(szCurrentFileName,
+ szFileName,iCaseSensitivity)==0)
+ return UNZ_OK;
+ err = unzGoToNextFile(file);
+ }
+ }
+
+ /* We failed, so restore the state of the 'current file' to where we
+ * were.
+ */
+ s->num_file = num_fileSaved ;
+ s->pos_in_central_dir = pos_in_central_dirSaved ;
+ s->cur_file_info = cur_file_infoSaved;
+ s->cur_file_info_internal = cur_file_info_internalSaved;
+ return err;
+}
+
+
+/*
+///////////////////////////////////////////
+// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
+// I need random access
+//
+// Further optimization could be realized by adding an ability
+// to cache the directory in memory. The goal being a single
+// comprehensive file read to put the file I need in a memory.
+*/
+
+/*
+typedef struct unz_file_pos_s
+{
+ uLong pos_in_zip_directory; // offset in file
+ uLong num_of_file; // # of file
+} unz_file_pos;
+*/
+
+extern int ZEXPORT unzGetFilePos(file, file_pos)
+ unzFile file;
+ unz_file_pos* file_pos;
+{
+ unz_s* s;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ file_pos->pos_in_zip_directory = s->pos_in_central_dir;
+ file_pos->num_of_file = s->num_file;
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGoToFilePos(file, file_pos)
+ unzFile file;
+ unz_file_pos* file_pos;
+{
+ unz_s* s;
+ int err;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+
+ /* jump to the right spot */
+ s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+ s->num_file = file_pos->num_of_file;
+
+ /* set the current file */
+ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ /* return results */
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+/*
+// Unzip Helper Functions - should be here?
+///////////////////////////////////////////
+*/
+
+/*
+ Read the local header of the current zipfile
+ Check the coherency of the local header and info in the end of central
+ directory about this file
+ store in *piSizeVar the size of extra info in local header
+ (filename and size of extra field data)
+*/
+local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
+ poffset_local_extrafield,
+ psize_local_extrafield)
+ unz_s* s;
+ uInt* piSizeVar;
+ uLong *poffset_local_extrafield;
+ uInt *psize_local_extrafield;
+{
+ uLong uMagic,uData,uFlags;
+ uLong size_filename;
+ uLong size_extra_field;
+ int err=UNZ_OK;
+
+ *piSizeVar = 0;
+ *poffset_local_extrafield = 0;
+ *psize_local_extrafield = 0;
+
+ if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
+ s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+
+ if (err==UNZ_OK)
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x04034b50)
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+/*
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+ err=UNZ_BADZIPFILE;
+*/
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+ err=UNZ_BADZIPFILE;
+
+ if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
+ ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
+ ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
+ ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+ err=UNZ_BADZIPFILE;
+
+ *piSizeVar += (uInt)size_filename;
+
+ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
+ err=UNZ_ERRNO;
+ *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+ SIZEZIPLOCALHEADER + size_filename;
+ *psize_local_extrafield = (uInt)size_extra_field;
+
+ *piSizeVar += (uInt)size_extra_field;
+
+ return err;
+}
+
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
+ unzFile file;
+ int* method;
+ int* level;
+ int raw;
+ const char* password;
+{
+ int err=UNZ_OK;
+ uInt iSizeVar;
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ uLong offset_local_extrafield; /* offset of the local extra field */
+ uInt size_local_extrafield; /* size of the local extra field */
+# ifndef NOUNCRYPT
+ char source[12];
+# else
+ if (password != NULL)
+ return UNZ_PARAMERROR;
+# endif
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_PARAMERROR;
+
+ if (s->pfile_in_zip_read != NULL)
+ unzCloseCurrentFile(file);
+
+ if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
+ &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+ return UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info = (file_in_zip_read_info_s*)
+ ALLOC(sizeof(file_in_zip_read_info_s));
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_INTERNALERROR;
+
+ pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+ pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+ pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+ pfile_in_zip_read_info->pos_local_extrafield=0;
+ pfile_in_zip_read_info->raw=raw;
+
+ if (pfile_in_zip_read_info->read_buffer==NULL)
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return UNZ_INTERNALERROR;
+ }
+
+ pfile_in_zip_read_info->stream_initialised=0;
+
+ if (method!=NULL)
+ *method = (int)s->cur_file_info.compression_method;
+
+ if (level!=NULL)
+ {
+ *level = 6;
+ switch (s->cur_file_info.flag & 0x06)
+ {
+ case 6 : *level = 1; break;
+ case 4 : *level = 2; break;
+ case 2 : *level = 9; break;
+ }
+ }
+
+ if ((s->cur_file_info.compression_method!=0) &&
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+ pfile_in_zip_read_info->crc32=0;
+ pfile_in_zip_read_info->compression_method =
+ s->cur_file_info.compression_method;
+ pfile_in_zip_read_info->filestream=s->filestream;
+ pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
+ pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+ pfile_in_zip_read_info->stream.total_out = 0;
+
+ if ((s->cur_file_info.compression_method==Z_DEFLATED) &&
+ (!raw))
+ {
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = (voidpf)0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=1;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END.
+ * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+ * size of both compressed and uncompressed data
+ */
+ }
+ pfile_in_zip_read_info->rest_read_compressed =
+ s->cur_file_info.compressed_size ;
+ pfile_in_zip_read_info->rest_read_uncompressed =
+ s->cur_file_info.uncompressed_size ;
+
+
+ pfile_in_zip_read_info->pos_in_zipfile =
+ s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+ iSizeVar;
+
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+ s->pfile_in_zip_read = pfile_in_zip_read_info;
+
+# ifndef NOUNCRYPT
+ if (password != NULL)
+ {
+ int i;
+ s->pcrc_32_tab = get_crc_table();
+ init_keys(password,s->keys,s->pcrc_32_tab);
+ if (ZSEEK(s->z_filefunc, s->filestream,
+ s->pfile_in_zip_read->pos_in_zipfile +
+ s->pfile_in_zip_read->byte_before_the_zipfile,
+ SEEK_SET)!=0)
+ return UNZ_INTERNALERROR;
+ if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12)
+ return UNZ_INTERNALERROR;
+
+ for (i = 0; i<12; i++)
+ zdecode(s->keys,s->pcrc_32_tab,source[i]);
+
+ s->pfile_in_zip_read->pos_in_zipfile+=12;
+ s->encrypted=1;
+ }
+# endif
+
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzOpenCurrentFile (file)
+ unzFile file;
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword (file, password)
+ unzFile file;
+ const char* password;
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw)
+ unzFile file;
+ int* method;
+ int* level;
+ int raw;
+{
+ return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/*
+ Read bytes from the current file.
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile (file, buf, len)
+ unzFile file;
+ voidp buf;
+ unsigned len;
+{
+ int err=UNZ_OK;
+ uInt iRead = 0;
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->read_buffer == NULL))
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (len==0)
+ return 0;
+
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+ pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+
+ if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
+ (!(pfile_in_zip_read_info->raw)))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+ if ((len>pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in) &&
+ (pfile_in_zip_read_info->raw))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in;
+
+ while (pfile_in_zip_read_info->stream.avail_out>0)
+ {
+ if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+ (pfile_in_zip_read_info->rest_read_compressed>0))
+ {
+ uInt uReadThis = UNZ_BUFSIZE;
+ if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+ uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+ if (uReadThis == 0)
+ return UNZ_EOF;
+ if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+ if (ZREAD(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->read_buffer,
+ uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+
+
+# ifndef NOUNCRYPT
+ if(s->encrypted)
+ {
+ uInt i;
+ for(i=0;i<uReadThis;i++)
+ pfile_in_zip_read_info->read_buffer[i] =
+ zdecode(s->keys,s->pcrc_32_tab,
+ pfile_in_zip_read_info->read_buffer[i]);
+ }
+# endif
+
+
+ pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+ pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+
+ pfile_in_zip_read_info->stream.next_in =
+ (Bytef*)pfile_in_zip_read_info->read_buffer;
+ pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+ }
+
+ if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
+ {
+ uInt uDoCopy,i ;
+
+ if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ return (iRead==0) ? UNZ_EOF : iRead;
+
+ if (pfile_in_zip_read_info->stream.avail_out <
+ pfile_in_zip_read_info->stream.avail_in)
+ uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+ else
+ uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+
+ for (i=0;i<uDoCopy;i++)
+ *(pfile_in_zip_read_info->stream.next_out+i) =
+ *(pfile_in_zip_read_info->stream.next_in+i);
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+ pfile_in_zip_read_info->stream.next_out,
+ uDoCopy);
+ pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+ pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+ pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+ pfile_in_zip_read_info->stream.next_out += uDoCopy;
+ pfile_in_zip_read_info->stream.next_in += uDoCopy;
+ pfile_in_zip_read_info->stream.total_out += uDoCopy;
+ iRead += uDoCopy;
+ }
+ else
+ {
+ uLong uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ uLong uOutThis;
+ int flush=Z_SYNC_FLUSH;
+
+ uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+ bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+ /*
+ if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+ pfile_in_zip_read_info->stream.avail_out) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ flush = Z_FINISH;
+ */
+ err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+ if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
+ err = Z_DATA_ERROR;
+
+ uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->crc32 =
+ crc32(pfile_in_zip_read_info->crc32,bufBefore,
+ (uInt)(uOutThis));
+
+ pfile_in_zip_read_info->rest_read_uncompressed -=
+ uOutThis;
+
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ if (err==Z_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=Z_OK)
+ break;
+ }
+ }
+
+ if (err==Z_OK)
+ return iRead;
+ return err;
+}
+
+
+/*
+ Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (file)
+ unzFile file;
+{
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+extern int ZEXPORT unzeof (file)
+ unzFile file;
+{
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field that can be read
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
+ unzFile file;
+ voidp buf;
+ unsigned len;
+{
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ uInt read_now;
+ uLong size_to_read;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
+ pfile_in_zip_read_info->pos_local_extrafield);
+
+ if (buf==NULL)
+ return (int)size_to_read;
+
+ if (len>size_to_read)
+ read_now = (uInt)size_to_read;
+ else
+ read_now = (uInt)len ;
+
+ if (read_now==0)
+ return 0;
+
+ if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->offset_local_extrafield +
+ pfile_in_zip_read_info->pos_local_extrafield,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (ZREAD(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ buf,read_now)!=read_now)
+ return UNZ_ERRNO;
+
+ return (int)read_now;
+}
+
+/*
+ Close the file in zip opened with unzipOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (file)
+ unzFile file;
+{
+ int err=UNZ_OK;
+
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+ (!pfile_in_zip_read_info->raw))
+ {
+ if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+ err=UNZ_CRCERROR;
+ }
+
+
+ TRYFREE(pfile_in_zip_read_info->read_buffer);
+ pfile_in_zip_read_info->read_buffer = NULL;
+ if (pfile_in_zip_read_info->stream_initialised)
+ inflateEnd(&pfile_in_zip_read_info->stream);
+
+ pfile_in_zip_read_info->stream_initialised = 0;
+ TRYFREE(pfile_in_zip_read_info);
+
+ s->pfile_in_zip_read=NULL;
+
+ return err;
+}
+
+
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
+ unzFile file;
+ char *szComment;
+ uLong uSizeBuf;
+{
+ int err=UNZ_OK;
+ unz_s* s;
+ uLong uReadThis ;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+
+ uReadThis = uSizeBuf;
+ if (uReadThis>s->gi.size_comment)
+ uReadThis = s->gi.size_comment;
+
+ if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (uReadThis>0)
+ {
+ *szComment='\0';
+ if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+ }
+
+ if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+ *(szComment+s->gi.size_comment)='\0';
+ return (int)uReadThis;
+}
+
+/* Additions by RX '2004 */
+extern uLong ZEXPORT unzGetOffset (file)
+ unzFile file;
+{
+ unz_s* s;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return 0;
+ if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
+ if (s->num_file==s->gi.number_entry)
+ return 0;
+ return s->pos_in_central_dir;
+}
+
+extern int ZEXPORT unzSetOffset (file, pos)
+ unzFile file;
+ uLong pos;
+{
+ unz_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+
+ s->pos_in_central_dir = pos;
+ s->num_file = s->gi.number_entry; /* hack */
+ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
diff --git a/zlib/contrib/minizip/unzip.h b/zlib/contrib/minizip/unzip.h
new file mode 100644
index 0000000..b247937
--- /dev/null
+++ b/zlib/contrib/minizip/unzip.h
@@ -0,0 +1,354 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
+ WinZip, InfoZip tools and compatible.
+
+ Multi volume ZipFile (span) are not supported.
+ Encryption compatible with pkzip 2.04g only supported
+ Old compressions used by old PKZip 1.x are not supported
+
+
+ I WAIT FEEDBACK at mail info@winimage.com
+ Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+
+/* for more info about .ZIP format, see
+ http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
+ http://www.info-zip.org/pub/infozip/doc/
+ PkWare has also a specification at :
+ ftp://ftp.pkware.com/probdesc.zip
+*/
+
+#ifndef _unz_H
+#define _unz_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (Z_ERRNO)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct unz_global_info_s
+{
+ uLong number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ uLong compressed_size; /* compressed size 4 bytes */
+ uLong uncompressed_size; /* uncompressed size 4 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity));
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
+ "zlib/zlib113.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+
+extern unzFile ZEXPORT unzOpen2 OF((const char *path,
+ zlib_filefunc_def* pzlib_filefunc_def));
+/*
+ Open a Zip file, like unzOpen, but provide a set of file low level API
+ for read/write the zip file (see ioapi.h)
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+ unz_global_info *pglobal_info));
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+ char *szComment,
+ uLong uSizeBuf));
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file,
+ const char *szFileName,
+ int iCaseSensitivity));
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+/* ****************************************** */
+/* Ryan supplied functions */
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_pos_s
+{
+ uLong pos_in_zip_directory; /* offset in zip file directory */
+ uLong num_of_file; /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+/* ****************************************** */
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+ unz_file_info *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+/*
+ Get Info about the current file
+ if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+ the current file
+ if szFileName!=NULL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField!=NULL, the extra field information will be copied in extraField
+ (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment!=NULL, the comment string of the file will be copied in szComment
+ (commentBufferSize is the size of the buffer)
+*/
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+ from it, and close it (you can close it before reading all the file)
+ */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
+ const char* password));
+/*
+ Open for reading data the current file in the zipfile.
+ password is a crypting password
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw,
+ const char* password));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+/*
+ Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+
+/***************************************************************************/
+
+/* Get the current file offset */
+extern uLong ZEXPORT unzGetOffset (unzFile file);
+
+/* Set the current file offset */
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz_H */
diff --git a/zlib/contrib/minizip/zip.c b/zlib/contrib/minizip/zip.c
new file mode 100644
index 0000000..7fbe002
--- /dev/null
+++ b/zlib/contrib/minizip/zip.c
@@ -0,0 +1,1219 @@
+/* zip.c -- IO on .zip files using zlib
+ Version 1.01e, February 12th, 2005
+
+ 27 Dec 2004 Rolf Kalbermatter
+ Modification to zipOpen2 to support globalComment retrieval.
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ Read zip.h for more info
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "zlib.h"
+#include "zip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#ifndef VERSIONMADEBY
+# define VERSIONMADEBY (0x0) /* platform depedent */
+#endif
+
+#ifndef Z_BUFSIZE
+#define Z_BUFSIZE (16384)
+#endif
+
+#ifndef Z_MAXFILENAMEINZIP
+#define Z_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+/*
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+*/
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef DEF_MEM_LEVEL
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+#endif
+const char zip_copyright[] =
+ " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+
+#define SIZEDATA_INDATABLOCK (4096-(4*4))
+
+#define LOCALHEADERMAGIC (0x04034b50)
+#define CENTRALHEADERMAGIC (0x02014b50)
+#define ENDHEADERMAGIC (0x06054b50)
+
+#define FLAG_LOCALHEADER_OFFSET (0x06)
+#define CRC_LOCALHEADER_OFFSET (0x0e)
+
+#define SIZECENTRALHEADER (0x2e) /* 46 */
+
+typedef struct linkedlist_datablock_internal_s
+{
+ struct linkedlist_datablock_internal_s* next_datablock;
+ uLong avail_in_this_block;
+ uLong filled_in_this_block;
+ uLong unused; /* for future use and alignement */
+ unsigned char data[SIZEDATA_INDATABLOCK];
+} linkedlist_datablock_internal;
+
+typedef struct linkedlist_data_s
+{
+ linkedlist_datablock_internal* first_block;
+ linkedlist_datablock_internal* last_block;
+} linkedlist_data;
+
+
+typedef struct
+{
+ z_stream stream; /* zLib stream structure for inflate */
+ int stream_initialised; /* 1 is stream is initialised */
+ uInt pos_in_buffered_data; /* last written byte in buffered_data */
+
+ uLong pos_local_header; /* offset of the local header of the file
+ currenty writing */
+ char* central_header; /* central header data for the current file */
+ uLong size_centralheader; /* size of the central header for cur file */
+ uLong flag; /* flag of the file currently writing */
+
+ int method; /* compression method of file currenty wr.*/
+ int raw; /* 1 for directly writing raw data */
+ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
+ uLong dosDate;
+ uLong crc32;
+ int encrypt;
+#ifndef NOCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const unsigned long* pcrc_32_tab;
+ int crypt_header_size;
+#endif
+} curfile_info;
+
+typedef struct
+{
+ zlib_filefunc_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ linkedlist_data central_dir;/* datablock with central dir in construction*/
+ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
+ curfile_info ci; /* info on the file curretly writing */
+
+ uLong begin_pos; /* position of the beginning of the zipfile */
+ uLong add_position_when_writting_offset;
+ uLong number_entry;
+#ifndef NO_ADDFILEINEXISTINGZIP
+ char *globalcomment;
+#endif
+} zip_internal;
+
+
+
+#ifndef NOCRYPT
+#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+#include "crypt.h"
+#endif
+
+local linkedlist_datablock_internal* allocate_new_datablock()
+{
+ linkedlist_datablock_internal* ldi;
+ ldi = (linkedlist_datablock_internal*)
+ ALLOC(sizeof(linkedlist_datablock_internal));
+ if (ldi!=NULL)
+ {
+ ldi->next_datablock = NULL ;
+ ldi->filled_in_this_block = 0 ;
+ ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
+ }
+ return ldi;
+}
+
+local void free_datablock(ldi)
+ linkedlist_datablock_internal* ldi;
+{
+ while (ldi!=NULL)
+ {
+ linkedlist_datablock_internal* ldinext = ldi->next_datablock;
+ TRYFREE(ldi);
+ ldi = ldinext;
+ }
+}
+
+local void init_linkedlist(ll)
+ linkedlist_data* ll;
+{
+ ll->first_block = ll->last_block = NULL;
+}
+
+local void free_linkedlist(ll)
+ linkedlist_data* ll;
+{
+ free_datablock(ll->first_block);
+ ll->first_block = ll->last_block = NULL;
+}
+
+
+local int add_data_in_datablock(ll,buf,len)
+ linkedlist_data* ll;
+ const void* buf;
+ uLong len;
+{
+ linkedlist_datablock_internal* ldi;
+ const unsigned char* from_copy;
+
+ if (ll==NULL)
+ return ZIP_INTERNALERROR;
+
+ if (ll->last_block == NULL)
+ {
+ ll->first_block = ll->last_block = allocate_new_datablock();
+ if (ll->first_block == NULL)
+ return ZIP_INTERNALERROR;
+ }
+
+ ldi = ll->last_block;
+ from_copy = (unsigned char*)buf;
+
+ while (len>0)
+ {
+ uInt copy_this;
+ uInt i;
+ unsigned char* to_copy;
+
+ if (ldi->avail_in_this_block==0)
+ {
+ ldi->next_datablock = allocate_new_datablock();
+ if (ldi->next_datablock == NULL)
+ return ZIP_INTERNALERROR;
+ ldi = ldi->next_datablock ;
+ ll->last_block = ldi;
+ }
+
+ if (ldi->avail_in_this_block < len)
+ copy_this = (uInt)ldi->avail_in_this_block;
+ else
+ copy_this = (uInt)len;
+
+ to_copy = &(ldi->data[ldi->filled_in_this_block]);
+
+ for (i=0;i<copy_this;i++)
+ *(to_copy+i)=*(from_copy+i);
+
+ ldi->filled_in_this_block += copy_this;
+ ldi->avail_in_this_block -= copy_this;
+ from_copy += copy_this ;
+ len -= copy_this;
+ }
+ return ZIP_OK;
+}
+
+
+
+/****************************************************************************/
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+/* ===========================================================================
+ Inputs a long in LSB order to the given file
+ nbByte == 1, 2 or 4 (byte, short or long)
+*/
+
+local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream, uLong x, int nbByte));
+local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+ uLong x;
+ int nbByte;
+{
+ unsigned char buf[4];
+ int n;
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 (X Roche) */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+
+ if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)
+ return ZIP_ERRNO;
+ else
+ return ZIP_OK;
+}
+
+local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte));
+local void ziplocal_putValue_inmemory (dest, x, nbByte)
+ void* dest;
+ uLong x;
+ int nbByte;
+{
+ unsigned char* buf=(unsigned char*)dest;
+ int n;
+ for (n = 0; n < nbByte; n++) {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+}
+
+/****************************************************************************/
+
+
+local uLong ziplocal_TmzDateToDosDate(ptm,dosDate)
+ const tm_zip* ptm;
+ uLong dosDate;
+{
+ uLong year = (uLong)ptm->tm_year;
+ if (year>1980)
+ year-=1980;
+ else if (year>80)
+ year-=80;
+ return
+ (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
+ ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
+}
+
+
+/****************************************************************************/
+
+local int ziplocal_getByte OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream,
+ int *pi));
+
+local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+ int *pi;
+{
+ unsigned char c;
+ int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return ZIP_OK;
+ }
+ else
+ {
+ if (ZERROR(*pzlib_filefunc_def,filestream))
+ return ZIP_ERRNO;
+ else
+ return ZIP_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int ziplocal_getShort OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+ uLong *pX;
+{
+ uLong x ;
+ int i;
+ int err;
+
+ err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int ziplocal_getLong OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+ uLong *pX;
+{
+ uLong x ;
+ int i;
+ int err;
+
+ err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<16;
+
+ if (err==ZIP_OK)
+ err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local uLong ziplocal_SearchCentralDir OF((
+ const zlib_filefunc_def* pzlib_filefunc_def,
+ voidpf filestream));
+
+local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream)
+ const zlib_filefunc_def* pzlib_filefunc_def;
+ voidpf filestream;
+{
+ unsigned char* buf;
+ uLong uSizeFile;
+ uLong uBackRead;
+ uLong uMaxBack=0xffff; /* maximum size of global comment */
+ uLong uPosFound=0;
+
+ if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize,uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
+ if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+#endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+/************************************************************/
+extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc_def)
+ const char *pathname;
+ int append;
+ zipcharpc* globalcomment;
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ zip_internal ziinit;
+ zip_internal* zi;
+ int err=ZIP_OK;
+
+
+ if (pzlib_filefunc_def==NULL)
+ fill_fopen_filefunc(&ziinit.z_filefunc);
+ else
+ ziinit.z_filefunc = *pzlib_filefunc_def;
+
+ ziinit.filestream = (*(ziinit.z_filefunc.zopen_file))
+ (ziinit.z_filefunc.opaque,
+ pathname,
+ (append == APPEND_STATUS_CREATE) ?
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
+
+ if (ziinit.filestream == NULL)
+ return NULL;
+ ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream);
+ ziinit.in_opened_file_inzip = 0;
+ ziinit.ci.stream_initialised = 0;
+ ziinit.number_entry = 0;
+ ziinit.add_position_when_writting_offset = 0;
+ init_linkedlist(&(ziinit.central_dir));
+
+
+ zi = (zip_internal*)ALLOC(sizeof(zip_internal));
+ if (zi==NULL)
+ {
+ ZCLOSE(ziinit.z_filefunc,ziinit.filestream);
+ return NULL;
+ }
+
+ /* now we add file in a zipfile */
+# ifndef NO_ADDFILEINEXISTINGZIP
+ ziinit.globalcomment = NULL;
+ if (append == APPEND_STATUS_ADDINZIP)
+ {
+ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+
+ uLong size_central_dir; /* size of the central directory */
+ uLong offset_central_dir; /* offset of start of central directory */
+ uLong central_pos,uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ uLong number_entry;
+ uLong number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+ uLong size_comment;
+
+ central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream);
+ if (central_pos==0)
+ err=ZIP_ERRNO;
+
+ if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=ZIP_ERRNO;
+
+ /* the signature, already checked */
+ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of this disk */
+ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central dir */
+ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ if ((number_entry_CD!=number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=ZIP_BADZIPFILE;
+
+ /* size of the central directory */
+ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* zipfile global comment length */
+ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ if ((central_pos<offset_central_dir+size_central_dir) &&
+ (err==ZIP_OK))
+ err=ZIP_BADZIPFILE;
+
+ if (err!=ZIP_OK)
+ {
+ ZCLOSE(ziinit.z_filefunc, ziinit.filestream);
+ return NULL;
+ }
+
+ if (size_comment>0)
+ {
+ ziinit.globalcomment = ALLOC(size_comment+1);
+ if (ziinit.globalcomment)
+ {
+ size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment);
+ ziinit.globalcomment[size_comment]=0;
+ }
+ }
+
+ byte_before_the_zipfile = central_pos -
+ (offset_central_dir+size_central_dir);
+ ziinit.add_position_when_writting_offset = byte_before_the_zipfile;
+
+ {
+ uLong size_central_dir_to_read = size_central_dir;
+ size_t buf_size = SIZEDATA_INDATABLOCK;
+ void* buf_read = (void*)ALLOC(buf_size);
+ if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
+ offset_central_dir + byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ while ((size_central_dir_to_read>0) && (err==ZIP_OK))
+ {
+ uLong read_this = SIZEDATA_INDATABLOCK;
+ if (read_this > size_central_dir_to_read)
+ read_this = size_central_dir_to_read;
+ if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this)
+ err=ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&ziinit.central_dir,buf_read,
+ (uLong)read_this);
+ size_central_dir_to_read-=read_this;
+ }
+ TRYFREE(buf_read);
+ }
+ ziinit.begin_pos = byte_before_the_zipfile;
+ ziinit.number_entry = number_entry_CD;
+
+ if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
+ offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=ZIP_ERRNO;
+ }
+
+ if (globalcomment)
+ {
+ *globalcomment = ziinit.globalcomment;
+ }
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+ if (err != ZIP_OK)
+ {
+# ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(ziinit.globalcomment);
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+ TRYFREE(zi);
+ return NULL;
+ }
+ else
+ {
+ *zi = ziinit;
+ return (zipFile)zi;
+ }
+}
+
+extern zipFile ZEXPORT zipOpen (pathname, append)
+ const char *pathname;
+ int append;
+{
+ return zipOpen2(pathname,append,NULL,NULL);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting)
+ zipFile file;
+ const char* filename;
+ const zip_fileinfo* zipfi;
+ const void* extrafield_local;
+ uInt size_extrafield_local;
+ const void* extrafield_global;
+ uInt size_extrafield_global;
+ const char* comment;
+ int method;
+ int level;
+ int raw;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char* password;
+ uLong crcForCrypting;
+{
+ zip_internal* zi;
+ uInt size_filename;
+ uInt size_comment;
+ uInt i;
+ int err = ZIP_OK;
+
+# ifdef NOCRYPT
+ if (password != NULL)
+ return ZIP_PARAMERROR;
+# endif
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ if ((method!=0) && (method!=Z_DEFLATED))
+ return ZIP_PARAMERROR;
+
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ if (err != ZIP_OK)
+ return err;
+ }
+
+
+ if (filename==NULL)
+ filename="-";
+
+ if (comment==NULL)
+ size_comment = 0;
+ else
+ size_comment = (uInt)strlen(comment);
+
+ size_filename = (uInt)strlen(filename);
+
+ if (zipfi == NULL)
+ zi->ci.dosDate = 0;
+ else
+ {
+ if (zipfi->dosDate != 0)
+ zi->ci.dosDate = zipfi->dosDate;
+ else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
+ }
+
+ zi->ci.flag = 0;
+ if ((level==8) || (level==9))
+ zi->ci.flag |= 2;
+ if ((level==2))
+ zi->ci.flag |= 4;
+ if ((level==1))
+ zi->ci.flag |= 6;
+ if (password != NULL)
+ zi->ci.flag |= 1;
+
+ zi->ci.crc32 = 0;
+ zi->ci.method = method;
+ zi->ci.encrypt = 0;
+ zi->ci.stream_initialised = 0;
+ zi->ci.pos_in_buffered_data = 0;
+ zi->ci.raw = raw;
+ zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ;
+ zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename +
+ size_extrafield_global + size_comment;
+ zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader);
+
+ ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
+ /* version info */
+ ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
+ ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
+
+ if (zipfi==NULL)
+ ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
+ else
+ ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
+
+ if (zipfi==NULL)
+ ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
+ else
+ ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
+
+ ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4);
+
+ for (i=0;i<size_filename;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
+
+ for (i=0;i<size_extrafield_global;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
+ *(((const char*)extrafield_global)+i);
+
+ for (i=0;i<size_comment;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
+ size_extrafield_global+i) = *(comment+i);
+ if (zi->ci.central_header == NULL)
+ return ZIP_INTERNALERROR;
+
+ /* write the local header */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2);
+
+ if ((err==ZIP_OK) && (size_filename>0))
+ if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)
+ err = ZIP_ERRNO;
+
+ if ((err==ZIP_OK) && (size_extrafield_local>0))
+ if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local)
+ !=size_extrafield_local)
+ err = ZIP_ERRNO;
+
+ zi->ci.stream.avail_in = (uInt)0;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ zi->ci.stream.total_in = 0;
+ zi->ci.stream.total_out = 0;
+
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ zi->ci.stream.zalloc = (alloc_func)0;
+ zi->ci.stream.zfree = (free_func)0;
+ zi->ci.stream.opaque = (voidpf)0;
+
+ if (windowBits>0)
+ windowBits = -windowBits;
+
+ err = deflateInit2(&zi->ci.stream, level,
+ Z_DEFLATED, windowBits, memLevel, strategy);
+
+ if (err==Z_OK)
+ zi->ci.stream_initialised = 1;
+ }
+# ifndef NOCRYPT
+ zi->ci.crypt_header_size = 0;
+ if ((err==Z_OK) && (password != NULL))
+ {
+ unsigned char bufHead[RAND_HEAD_LEN];
+ unsigned int sizeHead;
+ zi->ci.encrypt = 1;
+ zi->ci.pcrc_32_tab = get_crc_table();
+ /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
+
+ sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
+ zi->ci.crypt_header_size = sizeHead;
+
+ if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
+ err = ZIP_ERRNO;
+ }
+# endif
+
+ if (err==Z_OK)
+ zi->in_opened_file_inzip = 1;
+ return err;
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw)
+ zipFile file;
+ const char* filename;
+ const zip_fileinfo* zipfi;
+ const void* extrafield_local;
+ uInt size_extrafield_local;
+ const void* extrafield_global;
+ uInt size_extrafield_global;
+ const char* comment;
+ int method;
+ int level;
+ int raw;
+{
+ return zipOpenNewFileInZip3 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level)
+ zipFile file;
+ const char* filename;
+ const zip_fileinfo* zipfi;
+ const void* extrafield_local;
+ uInt size_extrafield_local;
+ const void* extrafield_global;
+ uInt size_extrafield_global;
+ const char* comment;
+ int method;
+ int level;
+{
+ return zipOpenNewFileInZip2 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, 0);
+}
+
+local int zipFlushWriteBuffer(zi)
+ zip_internal* zi;
+{
+ int err=ZIP_OK;
+
+ if (zi->ci.encrypt != 0)
+ {
+#ifndef NOCRYPT
+ uInt i;
+ int t;
+ for (i=0;i<zi->ci.pos_in_buffered_data;i++)
+ zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab,
+ zi->ci.buffered_data[i],t);
+#endif
+ }
+ if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data)
+ !=zi->ci.pos_in_buffered_data)
+ err = ZIP_ERRNO;
+ zi->ci.pos_in_buffered_data = 0;
+ return err;
+}
+
+extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
+ zipFile file;
+ const void* buf;
+ unsigned len;
+{
+ zip_internal* zi;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+
+ zi->ci.stream.next_in = (void*)buf;
+ zi->ci.stream.avail_in = len;
+ zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
+
+ while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
+ {
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zipFlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+
+
+ if(err != ZIP_OK)
+ break;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ uLong uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_NO_FLUSH);
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+
+ }
+ else
+ {
+ uInt copy_this,i;
+ if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+ copy_this = zi->ci.stream.avail_in;
+ else
+ copy_this = zi->ci.stream.avail_out;
+ for (i=0;i<copy_this;i++)
+ *(((char*)zi->ci.stream.next_out)+i) =
+ *(((const char*)zi->ci.stream.next_in)+i);
+ {
+ zi->ci.stream.avail_in -= copy_this;
+ zi->ci.stream.avail_out-= copy_this;
+ zi->ci.stream.next_in+= copy_this;
+ zi->ci.stream.next_out+= copy_this;
+ zi->ci.stream.total_in+= copy_this;
+ zi->ci.stream.total_out+= copy_this;
+ zi->ci.pos_in_buffered_data += copy_this;
+ }
+ }
+ }
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32)
+ zipFile file;
+ uLong uncompressed_size;
+ uLong crc32;
+{
+ zip_internal* zi;
+ uLong compressed_size;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+ zi->ci.stream.avail_in = 0;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ while (err==ZIP_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zipFlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_FINISH);
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+
+ if (err==Z_STREAM_END)
+ err=ZIP_OK; /* this is normal */
+
+ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
+ if (zipFlushWriteBuffer(zi)==ZIP_ERRNO)
+ err = ZIP_ERRNO;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ err=deflateEnd(&zi->ci.stream);
+ zi->ci.stream_initialised = 0;
+ }
+
+ if (!zi->ci.raw)
+ {
+ crc32 = (uLong)zi->ci.crc32;
+ uncompressed_size = (uLong)zi->ci.stream.total_in;
+ }
+ compressed_size = (uLong)zi->ci.stream.total_out;
+# ifndef NOCRYPT
+ compressed_size += zi->ci.crypt_header_size;
+# endif
+
+ ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+20,
+ compressed_size,4); /*compr size*/
+ if (zi->ci.stream.data_type == Z_ASCII)
+ ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+24,
+ uncompressed_size,4); /*uncompr size*/
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
+ (uLong)zi->ci.size_centralheader);
+ free(zi->ci.central_header);
+
+ if (err==ZIP_OK)
+ {
+ long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream);
+ if (ZSEEK(zi->z_filefunc,zi->filestream,
+ zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
+
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
+
+ if (ZSEEK(zi->z_filefunc,zi->filestream,
+ cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+ }
+
+ zi->number_entry ++;
+ zi->in_opened_file_inzip = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZip (file)
+ zipFile file;
+{
+ return zipCloseFileInZipRaw (file,0,0);
+}
+
+extern int ZEXPORT zipClose (file, global_comment)
+ zipFile file;
+ const char* global_comment;
+{
+ zip_internal* zi;
+ int err = 0;
+ uLong size_centraldir = 0;
+ uLong centraldir_pos_inzip;
+ uInt size_global_comment;
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ }
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ if (global_comment==NULL)
+ global_comment = zi->globalcomment;
+#endif
+ if (global_comment==NULL)
+ size_global_comment = 0;
+ else
+ size_global_comment = (uInt)strlen(global_comment);
+
+ centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream);
+ if (err==ZIP_OK)
+ {
+ linkedlist_datablock_internal* ldi = zi->central_dir.first_block ;
+ while (ldi!=NULL)
+ {
+ if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
+ if (ZWRITE(zi->z_filefunc,zi->filestream,
+ ldi->data,ldi->filled_in_this_block)
+ !=ldi->filled_in_this_block )
+ err = ZIP_ERRNO;
+
+ size_centraldir += ldi->filled_in_this_block;
+ ldi = ldi->next_datablock;
+ }
+ }
+ free_datablock(zi->central_dir.first_block);
+
+ if (err==ZIP_OK) /* Magic End */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the
+ starting disk number */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,
+ (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
+
+ if (err==ZIP_OK) /* zipfile comment length */
+ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
+
+ if ((err==ZIP_OK) && (size_global_comment>0))
+ if (ZWRITE(zi->z_filefunc,zi->filestream,
+ global_comment,size_global_comment) != size_global_comment)
+ err = ZIP_ERRNO;
+
+ if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0)
+ if (err == ZIP_OK)
+ err = ZIP_ERRNO;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(zi->globalcomment);
+#endif
+ TRYFREE(zi);
+
+ return err;
+}
diff --git a/zlib/contrib/minizip/zip.h b/zlib/contrib/minizip/zip.h
new file mode 100644
index 0000000..acacce8
--- /dev/null
+++ b/zlib/contrib/minizip/zip.h
@@ -0,0 +1,235 @@
+/* zip.h -- IO for compress .zip files using zlib
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
+ WinZip, InfoZip tools and compatible.
+ Multi volume ZipFile (span) are not supported.
+ Encryption compatible with pkzip 2.04g only supported
+ Old compressions used by old PKZip 1.x are not supported
+
+ For uncompress .zip file, look at unzip.h
+
+
+ I WAIT FEEDBACK at mail info@winimage.com
+ Visit also http://www.winimage.com/zLibDll/unzip.html for evolution
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+
+/* for more info about .ZIP format, see
+ http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
+ http://www.info-zip.org/pub/infozip/doc/
+ PkWare has also a specification at :
+ ftp://ftp.pkware.com/probdesc.zip
+*/
+
+#ifndef _zip_H
+#define _zip_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zipFile__;
+typedef zipFile__ *zipFile;
+#else
+typedef voidp zipFile;
+#endif
+
+#define ZIP_OK (0)
+#define ZIP_EOF (0)
+#define ZIP_ERRNO (Z_ERRNO)
+#define ZIP_PARAMERROR (-102)
+#define ZIP_BADZIPFILE (-103)
+#define ZIP_INTERNALERROR (-104)
+
+#ifndef DEF_MEM_LEVEL
+# if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+# else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+# endif
+#endif
+/* default memLevel */
+
+/* tm_zip contain date/time info */
+typedef struct tm_zip_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_zip;
+
+typedef struct
+{
+ tm_zip tmz_date; /* date in understandable format */
+ uLong dosDate; /* if dos_date == 0, tmu_date is used */
+/* uLong flag; */ /* general purpose bit flag 2 bytes */
+
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+} zip_fileinfo;
+
+typedef const char* zipcharpc;
+
+
+#define APPEND_STATUS_CREATE (0)
+#define APPEND_STATUS_CREATEAFTER (1)
+#define APPEND_STATUS_ADDINZIP (2)
+
+extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));
+/*
+ Create a zipfile.
+ pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
+ an Unix computer "zlib/zlib113.zip".
+ if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
+ will be created at the end of the file.
+ (useful if the file contain a self extractor code)
+ if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
+ add files in existing zip (be sure you don't add file that doesn't exist)
+ If the zipfile cannot be opened, the return value is NULL.
+ Else, the return value is a zipFile Handle, usable with other function
+ of this zip package.
+*/
+
+/* Note : there is no delete function into a zipfile.
+ If you want delete file into a zipfile, you must open a zipfile, and create another
+ Of couse, you can use RAW reading and writing to copy the file you did not want delte
+*/
+
+extern zipFile ZEXPORT zipOpen2 OF((const char *pathname,
+ int append,
+ zipcharpc* globalcomment,
+ zlib_filefunc_def* pzlib_filefunc_def));
+
+extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level));
+/*
+ Open a file in the ZIP for writing.
+ filename : the filename in zip (if NULL, '-' without quote will be used
+ *zipfi contain supplemental information
+ if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
+ contains the extrafield data the the local header
+ if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+ contains the extrafield data the the local header
+ if comment != NULL, comment contain the comment string
+ method contain the compression method (0 for store, Z_DEFLATED for deflate)
+ level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
+*/
+
+
+extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw));
+
+/*
+ Same than zipOpenNewFileInZip, except if raw=1, we write raw file
+ */
+
+extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCtypting));
+
+/*
+ Same than zipOpenNewFileInZip2, except
+ windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
+ password : crypting password (NULL for no crypting)
+ crcForCtypting : crc of file to compress (needed for crypting)
+ */
+
+
+extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
+ const void* buf,
+ unsigned len));
+/*
+ Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+ Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
+ uLong uncompressed_size,
+ uLong crc32));
+/*
+ Close the current file in the zipfile, for fiel opened with
+ parameter raw=1 in zipOpenNewFileInZip2
+ uncompressed_size and crc32 are value for the uncompressed size
+*/
+
+extern int ZEXPORT zipClose OF((zipFile file,
+ const char* global_comment));
+/*
+ Close the zipfile
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _zip_H */
diff --git a/zlib/contrib/pascal/example.pas b/zlib/contrib/pascal/example.pas
new file mode 100644
index 0000000..5518b36
--- /dev/null
+++ b/zlib/contrib/pascal/example.pas
@@ -0,0 +1,599 @@
+(* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Pascal translation
+ * Copyright (C) 1998 by Jacques Nomssi Nzali.
+ * For conditions of distribution and use, see copyright notice in readme.txt
+ *
+ * Adaptation to the zlibpas interface
+ * Copyright (C) 2003 by Cosmin Truta.
+ * For conditions of distribution and use, see copyright notice in readme.txt
+ *)
+
+program example;
+
+{$DEFINE TEST_COMPRESS}
+{DO NOT $DEFINE TEST_GZIO}
+{$DEFINE TEST_DEFLATE}
+{$DEFINE TEST_INFLATE}
+{$DEFINE TEST_FLUSH}
+{$DEFINE TEST_SYNC}
+{$DEFINE TEST_DICT}
+
+uses SysUtils, zlibpas;
+
+const TESTFILE = 'foo.gz';
+
+(* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ *)
+const hello: PChar = 'hello, hello!';
+
+const dictionary: PChar = 'hello';
+
+var dictId: LongInt; (* Adler32 value of the dictionary *)
+
+procedure CHECK_ERR(err: Integer; msg: String);
+begin
+ if err <> Z_OK then
+ begin
+ WriteLn(msg, ' error: ', err);
+ Halt(1);
+ end;
+end;
+
+procedure EXIT_ERR(const msg: String);
+begin
+ WriteLn('Error: ', msg);
+ Halt(1);
+end;
+
+(* ===========================================================================
+ * Test compress and uncompress
+ *)
+{$IFDEF TEST_COMPRESS}
+procedure test_compress(compr: Pointer; comprLen: LongInt;
+ uncompr: Pointer; uncomprLen: LongInt);
+var err: Integer;
+ len: LongInt;
+begin
+ len := StrLen(hello)+1;
+
+ err := compress(compr, comprLen, hello, len);
+ CHECK_ERR(err, 'compress');
+
+ StrCopy(PChar(uncompr), 'garbage');
+
+ err := uncompress(uncompr, uncomprLen, compr, comprLen);
+ CHECK_ERR(err, 'uncompress');
+
+ if StrComp(PChar(uncompr), hello) <> 0 then
+ EXIT_ERR('bad uncompress')
+ else
+ WriteLn('uncompress(): ', PChar(uncompr));
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test read/write of .gz files
+ *)
+{$IFDEF TEST_GZIO}
+procedure test_gzio(const fname: PChar; (* compressed file name *)
+ uncompr: Pointer;
+ uncomprLen: LongInt);
+var err: Integer;
+ len: Integer;
+ zfile: gzFile;
+ pos: LongInt;
+begin
+ len := StrLen(hello)+1;
+
+ zfile := gzopen(fname, 'wb');
+ if zfile = NIL then
+ begin
+ WriteLn('gzopen error');
+ Halt(1);
+ end;
+ gzputc(zfile, 'h');
+ if gzputs(zfile, 'ello') <> 4 then
+ begin
+ WriteLn('gzputs err: ', gzerror(zfile, err));
+ Halt(1);
+ end;
+ {$IFDEF GZ_FORMAT_STRING}
+ if gzprintf(zfile, ', %s!', 'hello') <> 8 then
+ begin
+ WriteLn('gzprintf err: ', gzerror(zfile, err));
+ Halt(1);
+ end;
+ {$ELSE}
+ if gzputs(zfile, ', hello!') <> 8 then
+ begin
+ WriteLn('gzputs err: ', gzerror(zfile, err));
+ Halt(1);
+ end;
+ {$ENDIF}
+ gzseek(zfile, 1, SEEK_CUR); (* add one zero byte *)
+ gzclose(zfile);
+
+ zfile := gzopen(fname, 'rb');
+ if zfile = NIL then
+ begin
+ WriteLn('gzopen error');
+ Halt(1);
+ end;
+
+ StrCopy(PChar(uncompr), 'garbage');
+
+ if gzread(zfile, uncompr, uncomprLen) <> len then
+ begin
+ WriteLn('gzread err: ', gzerror(zfile, err));
+ Halt(1);
+ end;
+ if StrComp(PChar(uncompr), hello) <> 0 then
+ begin
+ WriteLn('bad gzread: ', PChar(uncompr));
+ Halt(1);
+ end
+ else
+ WriteLn('gzread(): ', PChar(uncompr));
+
+ pos := gzseek(zfile, -8, SEEK_CUR);
+ if (pos <> 6) or (gztell(zfile) <> pos) then
+ begin
+ WriteLn('gzseek error, pos=', pos, ', gztell=', gztell(zfile));
+ Halt(1);
+ end;
+
+ if gzgetc(zfile) <> ' ' then
+ begin
+ WriteLn('gzgetc error');
+ Halt(1);
+ end;
+
+ if gzungetc(' ', zfile) <> ' ' then
+ begin
+ WriteLn('gzungetc error');
+ Halt(1);
+ end;
+
+ gzgets(zfile, PChar(uncompr), uncomprLen);
+ uncomprLen := StrLen(PChar(uncompr));
+ if uncomprLen <> 7 then (* " hello!" *)
+ begin
+ WriteLn('gzgets err after gzseek: ', gzerror(zfile, err));
+ Halt(1);
+ end;
+ if StrComp(PChar(uncompr), hello + 6) <> 0 then
+ begin
+ WriteLn('bad gzgets after gzseek');
+ Halt(1);
+ end
+ else
+ WriteLn('gzgets() after gzseek: ', PChar(uncompr));
+
+ gzclose(zfile);
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test deflate with small buffers
+ *)
+{$IFDEF TEST_DEFLATE}
+procedure test_deflate(compr: Pointer; comprLen: LongInt);
+var c_stream: z_stream; (* compression stream *)
+ err: Integer;
+ len: LongInt;
+begin
+ len := StrLen(hello)+1;
+
+ c_stream.zalloc := NIL;
+ c_stream.zfree := NIL;
+ c_stream.opaque := NIL;
+
+ err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, 'deflateInit');
+
+ c_stream.next_in := hello;
+ c_stream.next_out := compr;
+
+ while (c_stream.total_in <> len) and
+ (c_stream.total_out < comprLen) do
+ begin
+ c_stream.avail_out := 1; { force small buffers }
+ c_stream.avail_in := 1;
+ err := deflate(c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, 'deflate');
+ end;
+
+ (* Finish the stream, still forcing small buffers: *)
+ while TRUE do
+ begin
+ c_stream.avail_out := 1;
+ err := deflate(c_stream, Z_FINISH);
+ if err = Z_STREAM_END then
+ break;
+ CHECK_ERR(err, 'deflate');
+ end;
+
+ err := deflateEnd(c_stream);
+ CHECK_ERR(err, 'deflateEnd');
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test inflate with small buffers
+ *)
+{$IFDEF TEST_INFLATE}
+procedure test_inflate(compr: Pointer; comprLen : LongInt;
+ uncompr: Pointer; uncomprLen : LongInt);
+var err: Integer;
+ d_stream: z_stream; (* decompression stream *)
+begin
+ StrCopy(PChar(uncompr), 'garbage');
+
+ d_stream.zalloc := NIL;
+ d_stream.zfree := NIL;
+ d_stream.opaque := NIL;
+
+ d_stream.next_in := compr;
+ d_stream.avail_in := 0;
+ d_stream.next_out := uncompr;
+
+ err := inflateInit(d_stream);
+ CHECK_ERR(err, 'inflateInit');
+
+ while (d_stream.total_out < uncomprLen) and
+ (d_stream.total_in < comprLen) do
+ begin
+ d_stream.avail_out := 1; (* force small buffers *)
+ d_stream.avail_in := 1;
+ err := inflate(d_stream, Z_NO_FLUSH);
+ if err = Z_STREAM_END then
+ break;
+ CHECK_ERR(err, 'inflate');
+ end;
+
+ err := inflateEnd(d_stream);
+ CHECK_ERR(err, 'inflateEnd');
+
+ if StrComp(PChar(uncompr), hello) <> 0 then
+ EXIT_ERR('bad inflate')
+ else
+ WriteLn('inflate(): ', PChar(uncompr));
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test deflate with large buffers and dynamic change of compression level
+ *)
+{$IFDEF TEST_DEFLATE}
+procedure test_large_deflate(compr: Pointer; comprLen: LongInt;
+ uncompr: Pointer; uncomprLen: LongInt);
+var c_stream: z_stream; (* compression stream *)
+ err: Integer;
+begin
+ c_stream.zalloc := NIL;
+ c_stream.zfree := NIL;
+ c_stream.opaque := NIL;
+
+ err := deflateInit(c_stream, Z_BEST_SPEED);
+ CHECK_ERR(err, 'deflateInit');
+
+ c_stream.next_out := compr;
+ c_stream.avail_out := Integer(comprLen);
+
+ (* At this point, uncompr is still mostly zeroes, so it should compress
+ * very well:
+ *)
+ c_stream.next_in := uncompr;
+ c_stream.avail_in := Integer(uncomprLen);
+ err := deflate(c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, 'deflate');
+ if c_stream.avail_in <> 0 then
+ EXIT_ERR('deflate not greedy');
+
+ (* Feed in already compressed data and switch to no compression: *)
+ deflateParams(c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+ c_stream.next_in := compr;
+ c_stream.avail_in := Integer(comprLen div 2);
+ err := deflate(c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, 'deflate');
+
+ (* Switch back to compressing mode: *)
+ deflateParams(c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+ c_stream.next_in := uncompr;
+ c_stream.avail_in := Integer(uncomprLen);
+ err := deflate(c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, 'deflate');
+
+ err := deflate(c_stream, Z_FINISH);
+ if err <> Z_STREAM_END then
+ EXIT_ERR('deflate should report Z_STREAM_END');
+
+ err := deflateEnd(c_stream);
+ CHECK_ERR(err, 'deflateEnd');
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test inflate with large buffers
+ *)
+{$IFDEF TEST_INFLATE}
+procedure test_large_inflate(compr: Pointer; comprLen: LongInt;
+ uncompr: Pointer; uncomprLen: LongInt);
+var err: Integer;
+ d_stream: z_stream; (* decompression stream *)
+begin
+ StrCopy(PChar(uncompr), 'garbage');
+
+ d_stream.zalloc := NIL;
+ d_stream.zfree := NIL;
+ d_stream.opaque := NIL;
+
+ d_stream.next_in := compr;
+ d_stream.avail_in := Integer(comprLen);
+
+ err := inflateInit(d_stream);
+ CHECK_ERR(err, 'inflateInit');
+
+ while TRUE do
+ begin
+ d_stream.next_out := uncompr; (* discard the output *)
+ d_stream.avail_out := Integer(uncomprLen);
+ err := inflate(d_stream, Z_NO_FLUSH);
+ if err = Z_STREAM_END then
+ break;
+ CHECK_ERR(err, 'large inflate');
+ end;
+
+ err := inflateEnd(d_stream);
+ CHECK_ERR(err, 'inflateEnd');
+
+ if d_stream.total_out <> 2 * uncomprLen + comprLen div 2 then
+ begin
+ WriteLn('bad large inflate: ', d_stream.total_out);
+ Halt(1);
+ end
+ else
+ WriteLn('large_inflate(): OK');
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test deflate with full flush
+ *)
+{$IFDEF TEST_FLUSH}
+procedure test_flush(compr: Pointer; var comprLen : LongInt);
+var c_stream: z_stream; (* compression stream *)
+ err: Integer;
+ len: Integer;
+begin
+ len := StrLen(hello)+1;
+
+ c_stream.zalloc := NIL;
+ c_stream.zfree := NIL;
+ c_stream.opaque := NIL;
+
+ err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, 'deflateInit');
+
+ c_stream.next_in := hello;
+ c_stream.next_out := compr;
+ c_stream.avail_in := 3;
+ c_stream.avail_out := Integer(comprLen);
+ err := deflate(c_stream, Z_FULL_FLUSH);
+ CHECK_ERR(err, 'deflate');
+
+ Inc(PByteArray(compr)^[3]); (* force an error in first compressed block *)
+ c_stream.avail_in := len - 3;
+
+ err := deflate(c_stream, Z_FINISH);
+ if err <> Z_STREAM_END then
+ CHECK_ERR(err, 'deflate');
+
+ err := deflateEnd(c_stream);
+ CHECK_ERR(err, 'deflateEnd');
+
+ comprLen := c_stream.total_out;
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test inflateSync()
+ *)
+{$IFDEF TEST_SYNC}
+procedure test_sync(compr: Pointer; comprLen: LongInt;
+ uncompr: Pointer; uncomprLen : LongInt);
+var err: Integer;
+ d_stream: z_stream; (* decompression stream *)
+begin
+ StrCopy(PChar(uncompr), 'garbage');
+
+ d_stream.zalloc := NIL;
+ d_stream.zfree := NIL;
+ d_stream.opaque := NIL;
+
+ d_stream.next_in := compr;
+ d_stream.avail_in := 2; (* just read the zlib header *)
+
+ err := inflateInit(d_stream);
+ CHECK_ERR(err, 'inflateInit');
+
+ d_stream.next_out := uncompr;
+ d_stream.avail_out := Integer(uncomprLen);
+
+ inflate(d_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, 'inflate');
+
+ d_stream.avail_in := Integer(comprLen-2); (* read all compressed data *)
+ err := inflateSync(d_stream); (* but skip the damaged part *)
+ CHECK_ERR(err, 'inflateSync');
+
+ err := inflate(d_stream, Z_FINISH);
+ if err <> Z_DATA_ERROR then
+ EXIT_ERR('inflate should report DATA_ERROR');
+ (* Because of incorrect adler32 *)
+
+ err := inflateEnd(d_stream);
+ CHECK_ERR(err, 'inflateEnd');
+
+ WriteLn('after inflateSync(): hel', PChar(uncompr));
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test deflate with preset dictionary
+ *)
+{$IFDEF TEST_DICT}
+procedure test_dict_deflate(compr: Pointer; comprLen: LongInt);
+var c_stream: z_stream; (* compression stream *)
+ err: Integer;
+begin
+ c_stream.zalloc := NIL;
+ c_stream.zfree := NIL;
+ c_stream.opaque := NIL;
+
+ err := deflateInit(c_stream, Z_BEST_COMPRESSION);
+ CHECK_ERR(err, 'deflateInit');
+
+ err := deflateSetDictionary(c_stream, dictionary, StrLen(dictionary));
+ CHECK_ERR(err, 'deflateSetDictionary');
+
+ dictId := c_stream.adler;
+ c_stream.next_out := compr;
+ c_stream.avail_out := Integer(comprLen);
+
+ c_stream.next_in := hello;
+ c_stream.avail_in := StrLen(hello)+1;
+
+ err := deflate(c_stream, Z_FINISH);
+ if err <> Z_STREAM_END then
+ EXIT_ERR('deflate should report Z_STREAM_END');
+
+ err := deflateEnd(c_stream);
+ CHECK_ERR(err, 'deflateEnd');
+end;
+{$ENDIF}
+
+(* ===========================================================================
+ * Test inflate with a preset dictionary
+ *)
+{$IFDEF TEST_DICT}
+procedure test_dict_inflate(compr: Pointer; comprLen: LongInt;
+ uncompr: Pointer; uncomprLen: LongInt);
+var err: Integer;
+ d_stream: z_stream; (* decompression stream *)
+begin
+ StrCopy(PChar(uncompr), 'garbage');
+
+ d_stream.zalloc := NIL;
+ d_stream.zfree := NIL;
+ d_stream.opaque := NIL;
+
+ d_stream.next_in := compr;
+ d_stream.avail_in := Integer(comprLen);
+
+ err := inflateInit(d_stream);
+ CHECK_ERR(err, 'inflateInit');
+
+ d_stream.next_out := uncompr;
+ d_stream.avail_out := Integer(uncomprLen);
+
+ while TRUE do
+ begin
+ err := inflate(d_stream, Z_NO_FLUSH);
+ if err = Z_STREAM_END then
+ break;
+ if err = Z_NEED_DICT then
+ begin
+ if d_stream.adler <> dictId then
+ EXIT_ERR('unexpected dictionary');
+ err := inflateSetDictionary(d_stream, dictionary, StrLen(dictionary));
+ end;
+ CHECK_ERR(err, 'inflate with dict');
+ end;
+
+ err := inflateEnd(d_stream);
+ CHECK_ERR(err, 'inflateEnd');
+
+ if StrComp(PChar(uncompr), hello) <> 0 then
+ EXIT_ERR('bad inflate with dict')
+ else
+ WriteLn('inflate with dictionary: ', PChar(uncompr));
+end;
+{$ENDIF}
+
+var compr, uncompr: Pointer;
+ comprLen, uncomprLen: LongInt;
+
+begin
+ if zlibVersion^ <> ZLIB_VERSION[1] then
+ EXIT_ERR('Incompatible zlib version');
+
+ WriteLn('zlib version: ', zlibVersion);
+ WriteLn('zlib compile flags: ', Format('0x%x', [zlibCompileFlags]));
+
+ comprLen := 10000 * SizeOf(Integer); (* don't overflow on MSDOS *)
+ uncomprLen := comprLen;
+ GetMem(compr, comprLen);
+ GetMem(uncompr, uncomprLen);
+ if (compr = NIL) or (uncompr = NIL) then
+ EXIT_ERR('Out of memory');
+ (* compr and uncompr are cleared to avoid reading uninitialized
+ * data and to ensure that uncompr compresses well.
+ *)
+ FillChar(compr^, comprLen, 0);
+ FillChar(uncompr^, uncomprLen, 0);
+
+ {$IFDEF TEST_COMPRESS}
+ WriteLn('** Testing compress');
+ test_compress(compr, comprLen, uncompr, uncomprLen);
+ {$ENDIF}
+
+ {$IFDEF TEST_GZIO}
+ WriteLn('** Testing gzio');
+ if ParamCount >= 1 then
+ test_gzio(ParamStr(1), uncompr, uncomprLen)
+ else
+ test_gzio(TESTFILE, uncompr, uncomprLen);
+ {$ENDIF}
+
+ {$IFDEF TEST_DEFLATE}
+ WriteLn('** Testing deflate with small buffers');
+ test_deflate(compr, comprLen);
+ {$ENDIF}
+ {$IFDEF TEST_INFLATE}
+ WriteLn('** Testing inflate with small buffers');
+ test_inflate(compr, comprLen, uncompr, uncomprLen);
+ {$ENDIF}
+
+ {$IFDEF TEST_DEFLATE}
+ WriteLn('** Testing deflate with large buffers');
+ test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+ {$ENDIF}
+ {$IFDEF TEST_INFLATE}
+ WriteLn('** Testing inflate with large buffers');
+ test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+ {$ENDIF}
+
+ {$IFDEF TEST_FLUSH}
+ WriteLn('** Testing deflate with full flush');
+ test_flush(compr, comprLen);
+ {$ENDIF}
+ {$IFDEF TEST_SYNC}
+ WriteLn('** Testing inflateSync');
+ test_sync(compr, comprLen, uncompr, uncomprLen);
+ {$ENDIF}
+ comprLen := uncomprLen;
+
+ {$IFDEF TEST_DICT}
+ WriteLn('** Testing deflate and inflate with preset dictionary');
+ test_dict_deflate(compr, comprLen);
+ test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+ {$ENDIF}
+
+ FreeMem(compr, comprLen);
+ FreeMem(uncompr, uncomprLen);
+end.
diff --git a/zlib/contrib/pascal/readme.txt b/zlib/contrib/pascal/readme.txt
new file mode 100644
index 0000000..60e87c8
--- /dev/null
+++ b/zlib/contrib/pascal/readme.txt
@@ -0,0 +1,76 @@
+
+This directory contains a Pascal (Delphi, Kylix) interface to the
+zlib data compression library.
+
+
+Directory listing
+=================
+
+zlibd32.mak makefile for Borland C++
+example.pas usage example of zlib
+zlibpas.pas the Pascal interface to zlib
+readme.txt this file
+
+
+Compatibility notes
+===================
+
+- Although the name "zlib" would have been more normal for the
+ zlibpas unit, this name is already taken by Borland's ZLib unit.
+ This is somehow unfortunate, because that unit is not a genuine
+ interface to the full-fledged zlib functionality, but a suite of
+ class wrappers around zlib streams. Other essential features,
+ such as checksums, are missing.
+ It would have been more appropriate for that unit to have a name
+ like "ZStreams", or something similar.
+
+- The C and zlib-supplied types int, uInt, long, uLong, etc. are
+ translated directly into Pascal types of similar sizes (Integer,
+ LongInt, etc.), to avoid namespace pollution. In particular,
+ there is no conversion of unsigned int into a Pascal unsigned
+ integer. The Word type is non-portable and has the same size
+ (16 bits) both in a 16-bit and in a 32-bit environment, unlike
+ Integer. Even if there is a 32-bit Cardinal type, there is no
+ real need for unsigned int in zlib under a 32-bit environment.
+
+- Except for the callbacks, the zlib function interfaces are
+ assuming the calling convention normally used in Pascal
+ (__pascal for DOS and Windows16, __fastcall for Windows32).
+ Since the cdecl keyword is used, the old Turbo Pascal does
+ not work with this interface.
+
+- The gz* function interfaces are not translated, to avoid
+ interfacing problems with the C runtime library. Besides,
+ gzprintf(gzFile file, const char *format, ...)
+ cannot be translated into Pascal.
+
+
+Legal issues
+============
+
+The zlibpas interface is:
+ Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler.
+ Copyright (C) 1998 by Bob Dellaca.
+ Copyright (C) 2003 by Cosmin Truta.
+
+The example program is:
+ Copyright (C) 1995-2003 by Jean-loup Gailly.
+ Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali.
+ Copyright (C) 2003 by Cosmin Truta.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
diff --git a/zlib/contrib/pascal/zlibd32.mak b/zlib/contrib/pascal/zlibd32.mak
new file mode 100644
index 0000000..88fafa0
--- /dev/null
+++ b/zlib/contrib/pascal/zlibd32.mak
@@ -0,0 +1,93 @@
+# Makefile for zlib
+# For use with Delphi and C++ Builder under Win32
+# Updated for zlib 1.2.x by Cosmin Truta
+
+# ------------ Borland C++ ------------
+
+# This project uses the Delphi (fastcall/register) calling convention:
+LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl
+
+CC = bcc32
+LD = bcc32
+AR = tlib
+# do not use "-pr" in CFLAGS
+CFLAGS = -a -d -k- -O2 $(LOC)
+LDFLAGS =
+
+
+# variables
+ZLIB_LIB = zlib.lib
+
+OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj
+OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj
+OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj
+
+
+# targets
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: example.c zlib.h zconf.h
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+
+
+# For the sake of the old Borland make,
+# the command line is cut to fit in the MS-DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ -del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) $(OBJP1)
+ $(AR) $(ZLIB_LIB) $(OBJP2)
+
+
+# testing
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+
+# cleanup
+clean:
+ -del *.obj
+ -del *.exe
+ -del *.lib
+ -del *.tds
+ -del zlib.bak
+ -del foo.gz
+
diff --git a/zlib/contrib/pascal/zlibpas.pas b/zlib/contrib/pascal/zlibpas.pas
new file mode 100644
index 0000000..836848c
--- /dev/null
+++ b/zlib/contrib/pascal/zlibpas.pas
@@ -0,0 +1,236 @@
+(* zlibpas -- Pascal interface to the zlib data compression library
+ *
+ * Copyright (C) 2003 Cosmin Truta.
+ * Derived from original sources by Bob Dellaca.
+ * For conditions of distribution and use, see copyright notice in readme.txt
+ *)
+
+unit zlibpas;
+
+interface
+
+const
+ ZLIB_VERSION = '1.2.3';
+
+type
+ alloc_func = function(opaque: Pointer; items, size: Integer): Pointer;
+ cdecl;
+ free_func = procedure(opaque, address: Pointer);
+ cdecl;
+
+ in_func = function(opaque: Pointer; var buf: PByte): Integer;
+ cdecl;
+ out_func = function(opaque: Pointer; buf: PByte; size: Integer): Integer;
+ cdecl;
+
+ z_streamp = ^z_stream;
+ z_stream = packed record
+ next_in: PChar; (* next input byte *)
+ avail_in: Integer; (* number of bytes available at next_in *)
+ total_in: LongInt; (* total nb of input bytes read so far *)
+
+ next_out: PChar; (* next output byte should be put there *)
+ avail_out: Integer; (* remaining free space at next_out *)
+ total_out: LongInt; (* total nb of bytes output so far *)
+
+ msg: PChar; (* last error message, NULL if no error *)
+ state: Pointer; (* not visible by applications *)
+
+ zalloc: alloc_func; (* used to allocate the internal state *)
+ zfree: free_func; (* used to free the internal state *)
+ opaque: Pointer; (* private data object passed to zalloc and zfree *)
+
+ data_type: Integer; (* best guess about the data type: ascii or binary *)
+ adler: LongInt; (* adler32 value of the uncompressed data *)
+ reserved: LongInt; (* reserved for future use *)
+ end;
+
+(* constants *)
+const
+ Z_NO_FLUSH = 0;
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+ Z_NEED_DICT = 2;
+ Z_ERRNO = -1;
+ Z_STREAM_ERROR = -2;
+ Z_DATA_ERROR = -3;
+ Z_MEM_ERROR = -4;
+ Z_BUF_ERROR = -5;
+ Z_VERSION_ERROR = -6;
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = -1;
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_RLE = 3;
+ Z_DEFAULT_STRATEGY = 0;
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_UNKNOWN = 2;
+
+ Z_DEFLATED = 8;
+
+(* basic functions *)
+function zlibVersion: PChar;
+function deflateInit(var strm: z_stream; level: Integer): Integer;
+function deflate(var strm: z_stream; flush: Integer): Integer;
+function deflateEnd(var strm: z_stream): Integer;
+function inflateInit(var strm: z_stream): Integer;
+function inflate(var strm: z_stream; flush: Integer): Integer;
+function inflateEnd(var strm: z_stream): Integer;
+
+(* advanced functions *)
+function deflateInit2(var strm: z_stream; level, method, windowBits,
+ memLevel, strategy: Integer): Integer;
+function deflateSetDictionary(var strm: z_stream; const dictionary: PChar;
+ dictLength: Integer): Integer;
+function deflateCopy(var dest, source: z_stream): Integer;
+function deflateReset(var strm: z_stream): Integer;
+function deflateParams(var strm: z_stream; level, strategy: Integer): Integer;
+function deflateBound(var strm: z_stream; sourceLen: LongInt): LongInt;
+function deflatePrime(var strm: z_stream; bits, value: Integer): Integer;
+function inflateInit2(var strm: z_stream; windowBits: Integer): Integer;
+function inflateSetDictionary(var strm: z_stream; const dictionary: PChar;
+ dictLength: Integer): Integer;
+function inflateSync(var strm: z_stream): Integer;
+function inflateCopy(var dest, source: z_stream): Integer;
+function inflateReset(var strm: z_stream): Integer;
+function inflateBackInit(var strm: z_stream;
+ windowBits: Integer; window: PChar): Integer;
+function inflateBack(var strm: z_stream; in_fn: in_func; in_desc: Pointer;
+ out_fn: out_func; out_desc: Pointer): Integer;
+function inflateBackEnd(var strm: z_stream): Integer;
+function zlibCompileFlags: LongInt;
+
+(* utility functions *)
+function compress(dest: PChar; var destLen: LongInt;
+ const source: PChar; sourceLen: LongInt): Integer;
+function compress2(dest: PChar; var destLen: LongInt;
+ const source: PChar; sourceLen: LongInt;
+ level: Integer): Integer;
+function compressBound(sourceLen: LongInt): LongInt;
+function uncompress(dest: PChar; var destLen: LongInt;
+ const source: PChar; sourceLen: LongInt): Integer;
+
+(* checksum functions *)
+function adler32(adler: LongInt; const buf: PChar; len: Integer): LongInt;
+function crc32(crc: LongInt; const buf: PChar; len: Integer): LongInt;
+
+(* various hacks, don't look :) *)
+function deflateInit_(var strm: z_stream; level: Integer;
+ const version: PChar; stream_size: Integer): Integer;
+function inflateInit_(var strm: z_stream; const version: PChar;
+ stream_size: Integer): Integer;
+function deflateInit2_(var strm: z_stream;
+ level, method, windowBits, memLevel, strategy: Integer;
+ const version: PChar; stream_size: Integer): Integer;
+function inflateInit2_(var strm: z_stream; windowBits: Integer;
+ const version: PChar; stream_size: Integer): Integer;
+function inflateBackInit_(var strm: z_stream;
+ windowBits: Integer; window: PChar;
+ const version: PChar; stream_size: Integer): Integer;
+
+
+implementation
+
+{$L adler32.obj}
+{$L compress.obj}
+{$L crc32.obj}
+{$L deflate.obj}
+{$L infback.obj}
+{$L inffast.obj}
+{$L inflate.obj}
+{$L inftrees.obj}
+{$L trees.obj}
+{$L uncompr.obj}
+{$L zutil.obj}
+
+function adler32; external;
+function compress; external;
+function compress2; external;
+function compressBound; external;
+function crc32; external;
+function deflate; external;
+function deflateBound; external;
+function deflateCopy; external;
+function deflateEnd; external;
+function deflateInit_; external;
+function deflateInit2_; external;
+function deflateParams; external;
+function deflatePrime; external;
+function deflateReset; external;
+function deflateSetDictionary; external;
+function inflate; external;
+function inflateBack; external;
+function inflateBackEnd; external;
+function inflateBackInit_; external;
+function inflateCopy; external;
+function inflateEnd; external;
+function inflateInit_; external;
+function inflateInit2_; external;
+function inflateReset; external;
+function inflateSetDictionary; external;
+function inflateSync; external;
+function uncompress; external;
+function zlibCompileFlags; external;
+function zlibVersion; external;
+
+function deflateInit(var strm: z_stream; level: Integer): Integer;
+begin
+ Result := deflateInit_(strm, level, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function deflateInit2(var strm: z_stream; level, method, windowBits, memLevel,
+ strategy: Integer): Integer;
+begin
+ Result := deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit(var strm: z_stream): Integer;
+begin
+ Result := inflateInit_(strm, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit2(var strm: z_stream; windowBits: Integer): Integer;
+begin
+ Result := inflateInit2_(strm, windowBits, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateBackInit(var strm: z_stream;
+ windowBits: Integer; window: PChar): Integer;
+begin
+ Result := inflateBackInit_(strm, windowBits, window,
+ ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function _malloc(Size: Integer): Pointer; cdecl;
+begin
+ GetMem(Result, Size);
+end;
+
+procedure _free(Block: Pointer); cdecl;
+begin
+ FreeMem(Block);
+end;
+
+procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl;
+begin
+ FillChar(P^, count, B);
+end;
+
+procedure _memcpy(dest, source: Pointer; count: Integer); cdecl;
+begin
+ Move(source^, dest^, count);
+end;
+
+end.
diff --git a/zlib/contrib/puff/Makefile b/zlib/contrib/puff/Makefile
new file mode 100644
index 0000000..b6b6940
--- /dev/null
+++ b/zlib/contrib/puff/Makefile
@@ -0,0 +1,8 @@
+puff: puff.c puff.h
+ cc -DTEST -o puff puff.c
+
+test: puff
+ puff zeros.raw
+
+clean:
+ rm -f puff puff.o
diff --git a/zlib/contrib/puff/README b/zlib/contrib/puff/README
new file mode 100644
index 0000000..bbc4cb5
--- /dev/null
+++ b/zlib/contrib/puff/README
@@ -0,0 +1,63 @@
+Puff -- A Simple Inflate
+3 Mar 2003
+Mark Adler
+madler@alumni.caltech.edu
+
+What this is --
+
+puff.c provides the routine puff() to decompress the deflate data format. It
+does so more slowly than zlib, but the code is about one-fifth the size of the
+inflate code in zlib, and written to be very easy to read.
+
+Why I wrote this --
+
+puff.c was written to document the deflate format unambiguously, by virtue of
+being working C code. It is meant to supplement RFC 1951, which formally
+describes the deflate format. I have received many questions on details of the
+deflate format, and I hope that reading this code will answer those questions.
+puff.c is heavily commented with details of the deflate format, especially
+those little nooks and cranies of the format that might not be obvious from a
+specification.
+
+puff.c may also be useful in applications where code size or memory usage is a
+very limited resource, and speed is not as important.
+
+How to use it --
+
+Well, most likely you should just be reading puff.c and using zlib for actual
+applications, but if you must ...
+
+Include puff.h in your code, which provides this prototype:
+
+int puff(unsigned char *dest, /* pointer to destination pointer */
+ unsigned long *destlen, /* amount of output space */
+ unsigned char *source, /* pointer to source data pointer */
+ unsigned long *sourcelen); /* amount of input available */
+
+Then you can call puff() to decompress a deflate stream that is in memory in
+its entirety at source, to a sufficiently sized block of memory for the
+decompressed data at dest. puff() is the only external symbol in puff.c The
+only C library functions that puff.c needs are setjmp() and longjmp(), which
+are used to simplify error checking in the code to improve readabilty. puff.c
+does no memory allocation, and uses less than 2K bytes off of the stack.
+
+If destlen is not enough space for the uncompressed data, then inflate will
+return an error without writing more than destlen bytes. Note that this means
+that in order to decompress the deflate data successfully, you need to know
+the size of the uncompressed data ahead of time.
+
+If needed, puff() can determine the size of the uncompressed data with no
+output space. This is done by passing dest equal to (unsigned char *)0. Then
+the initial value of *destlen is ignored and *destlen is set to the length of
+the uncompressed data. So if the size of the uncompressed data is not known,
+then two passes of puff() can be used--first to determine the size, and second
+to do the actual inflation after allocating the appropriate memory. Not
+pretty, but it works. (This is one of the reasons you should be using zlib.)
+
+The deflate format is self-terminating. If the deflate stream does not end
+in *sourcelen bytes, puff() will return an error without reading at or past
+endsource.
+
+On return, *sourcelen is updated to the amount of input data consumed, and
+*destlen is updated to the size of the uncompressed data. See the comments
+in puff.c for the possible return codes for puff().
diff --git a/zlib/contrib/puff/puff.c b/zlib/contrib/puff/puff.c
new file mode 100644
index 0000000..ce0cc40
--- /dev/null
+++ b/zlib/contrib/puff/puff.c
@@ -0,0 +1,837 @@
+/*
+ * puff.c
+ * Copyright (C) 2002-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in puff.h
+ * version 1.8, 9 Jan 2004
+ *
+ * puff.c is a simple inflate written to be an unambiguous way to specify the
+ * deflate format. It is not written for speed but rather simplicity. As a
+ * side benefit, this code might actually be useful when small code is more
+ * important than speed, such as bootstrap applications. For typical deflate
+ * data, zlib's inflate() is about four times as fast as puff(). zlib's
+ * inflate compiles to around 20K on my machine, whereas puff.c compiles to
+ * around 4K on my machine (a PowerPC using GNU cc). If the faster decode()
+ * function here is used, then puff() is only twice as slow as zlib's
+ * inflate().
+ *
+ * All dynamically allocated memory comes from the stack. The stack required
+ * is less than 2K bytes. This code is compatible with 16-bit int's and
+ * assumes that long's are at least 32 bits. puff.c uses the short data type,
+ * assumed to be 16 bits, for arrays in order to to conserve memory. The code
+ * works whether integers are stored big endian or little endian.
+ *
+ * In the comments below are "Format notes" that describe the inflate process
+ * and document some of the less obvious aspects of the format. This source
+ * code is meant to supplement RFC 1951, which formally describes the deflate
+ * format:
+ *
+ * http://www.zlib.org/rfc-deflate.html
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0 10 Feb 2002 - First version
+ * 1.1 17 Feb 2002 - Clarifications of some comments and notes
+ * - Update puff() dest and source pointers on negative
+ * errors to facilitate debugging deflators
+ * - Remove longest from struct huffman -- not needed
+ * - Simplify offs[] index in construct()
+ * - Add input size and checking, using longjmp() to
+ * maintain easy readability
+ * - Use short data type for large arrays
+ * - Use pointers instead of long to specify source and
+ * destination sizes to avoid arbitrary 4 GB limits
+ * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!),
+ * but leave simple version for readabilty
+ * - Make sure invalid distances detected if pointers
+ * are 16 bits
+ * - Fix fixed codes table error
+ * - Provide a scanning mode for determining size of
+ * uncompressed data
+ * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup]
+ * - Add a puff.h file for the interface
+ * - Add braces in puff() for else do [Jean-loup]
+ * - Use indexes instead of pointers for readability
+ * 1.4 31 Mar 2002 - Simplify construct() code set check
+ * - Fix some comments
+ * - Add FIXLCODES #define
+ * 1.5 6 Apr 2002 - Minor comment fixes
+ * 1.6 7 Aug 2002 - Minor format changes
+ * 1.7 3 Mar 2003 - Added test code for distribution
+ * - Added zlib-like license
+ * 1.8 9 Jan 2004 - Added some comments on no distance codes case
+ */
+
+#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
+#include "puff.h" /* prototype for puff() */
+
+#define local static /* for local function definitions */
+#define NIL ((unsigned char *)0) /* for no output option */
+
+/*
+ * Maximums for allocations and loops. It is not useful to change these --
+ * they are fixed by the deflate format.
+ */
+#define MAXBITS 15 /* maximum bits in a code */
+#define MAXLCODES 286 /* maximum number of literal/length codes */
+#define MAXDCODES 30 /* maximum number of distance codes */
+#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
+#define FIXLCODES 288 /* number of fixed literal/length codes */
+
+/* input and output state */
+struct state {
+ /* output state */
+ unsigned char *out; /* output buffer */
+ unsigned long outlen; /* available space at out */
+ unsigned long outcnt; /* bytes written to out so far */
+
+ /* input state */
+ unsigned char *in; /* input buffer */
+ unsigned long inlen; /* available input at in */
+ unsigned long incnt; /* bytes read so far */
+ int bitbuf; /* bit buffer */
+ int bitcnt; /* number of bits in bit buffer */
+
+ /* input limit error return state for bits() and decode() */
+ jmp_buf env;
+};
+
+/*
+ * Return need bits from the input stream. This always leaves less than
+ * eight bits in the buffer. bits() works properly for need == 0.
+ *
+ * Format notes:
+ *
+ * - Bits are stored in bytes from the least significant bit to the most
+ * significant bit. Therefore bits are dropped from the bottom of the bit
+ * buffer, using shift right, and new bytes are appended to the top of the
+ * bit buffer, using shift left.
+ */
+local int bits(struct state *s, int need)
+{
+ long val; /* bit accumulator (can use up to 20 bits) */
+
+ /* load at least need bits into val */
+ val = s->bitbuf;
+ while (s->bitcnt < need) {
+ if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
+ val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
+ s->bitcnt += 8;
+ }
+
+ /* drop need bits and update buffer, always zero to seven bits left */
+ s->bitbuf = (int)(val >> need);
+ s->bitcnt -= need;
+
+ /* return need bits, zeroing the bits above that */
+ return (int)(val & ((1L << need) - 1));
+}
+
+/*
+ * Process a stored block.
+ *
+ * Format notes:
+ *
+ * - After the two-bit stored block type (00), the stored block length and
+ * stored bytes are byte-aligned for fast copying. Therefore any leftover
+ * bits in the byte that has the last bit of the type, as many as seven, are
+ * discarded. The value of the discarded bits are not defined and should not
+ * be checked against any expectation.
+ *
+ * - The second inverted copy of the stored block length does not have to be
+ * checked, but it's probably a good idea to do so anyway.
+ *
+ * - A stored block can have zero length. This is sometimes used to byte-align
+ * subsets of the compressed data for random access or partial recovery.
+ */
+local int stored(struct state *s)
+{
+ unsigned len; /* length of stored block */
+
+ /* discard leftover bits from current byte (assumes s->bitcnt < 8) */
+ s->bitbuf = 0;
+ s->bitcnt = 0;
+
+ /* get length and check against its one's complement */
+ if (s->incnt + 4 > s->inlen) return 2; /* not enough input */
+ len = s->in[s->incnt++];
+ len |= s->in[s->incnt++] << 8;
+ if (s->in[s->incnt++] != (~len & 0xff) ||
+ s->in[s->incnt++] != ((~len >> 8) & 0xff))
+ return -2; /* didn't match complement! */
+
+ /* copy len bytes from in to out */
+ if (s->incnt + len > s->inlen) return 2; /* not enough input */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen)
+ return 1; /* not enough output space */
+ while (len--)
+ s->out[s->outcnt++] = s->in[s->incnt++];
+ }
+ else { /* just scanning */
+ s->outcnt += len;
+ s->incnt += len;
+ }
+
+ /* done with a valid stored block */
+ return 0;
+}
+
+/*
+ * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
+ * each length, which for a canonical code are stepped through in order.
+ * symbol[] are the symbol values in canonical order, where the number of
+ * entries is the sum of the counts in count[]. The decoding process can be
+ * seen in the function decode() below.
+ */
+struct huffman {
+ short *count; /* number of symbols of each length */
+ short *symbol; /* canonically ordered symbols */
+};
+
+/*
+ * Decode a code from the stream s using huffman table h. Return the symbol or
+ * a negative value if there is an error. If all of the lengths are zero, i.e.
+ * an empty code, or if the code is incomplete and an invalid code is received,
+ * then -9 is returned after reading MAXBITS bits.
+ *
+ * Format notes:
+ *
+ * - The codes as stored in the compressed data are bit-reversed relative to
+ * a simple integer ordering of codes of the same lengths. Hence below the
+ * bits are pulled from the compressed data one at a time and used to
+ * build the code value reversed from what is in the stream in order to
+ * permit simple integer comparisons for decoding. A table-based decoding
+ * scheme (as used in zlib) does not need to do this reversal.
+ *
+ * - The first code for the shortest length is all zeros. Subsequent codes of
+ * the same length are simply integer increments of the previous code. When
+ * moving up a length, a zero bit is appended to the code. For a complete
+ * code, the last code of the longest length will be all ones.
+ *
+ * - Incomplete codes are handled by this decoder, since they are permitted
+ * in the deflate format. See the format notes for fixed() and dynamic().
+ */
+#ifdef SLOW
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+
+ code = first = index = 0;
+ for (len = 1; len <= MAXBITS; len++) {
+ code |= bits(s, 1); /* get next bit */
+ count = h->count[len];
+ if (code < first + count) /* if length len, return symbol */
+ return h->symbol[index + (code - first)];
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ }
+ return -9; /* ran out of codes */
+}
+
+/*
+ * A faster version of decode() for real applications of this code. It's not
+ * as readable, but it makes puff() twice as fast. And it only makes the code
+ * a few percent larger.
+ */
+#else /* !SLOW */
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+ int bitbuf; /* bits from stream */
+ int left; /* bits left in next or left to process */
+ short *next; /* next number of codes */
+
+ bitbuf = s->bitbuf;
+ left = s->bitcnt;
+ code = first = index = 0;
+ len = 1;
+ next = h->count + 1;
+ while (1) {
+ while (left--) {
+ code |= bitbuf & 1;
+ bitbuf >>= 1;
+ count = *next++;
+ if (code < first + count) { /* if length len, return symbol */
+ s->bitbuf = bitbuf;
+ s->bitcnt = (s->bitcnt - len) & 7;
+ return h->symbol[index + (code - first)];
+ }
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+ }
+ left = (MAXBITS+1) - len;
+ if (left == 0) break;
+ if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
+ bitbuf = s->in[s->incnt++];
+ if (left > 8) left = 8;
+ }
+ return -9; /* ran out of codes */
+}
+#endif /* SLOW */
+
+/*
+ * Given the list of code lengths length[0..n-1] representing a canonical
+ * Huffman code for n symbols, construct the tables required to decode those
+ * codes. Those tables are the number of codes of each length, and the symbols
+ * sorted by length, retaining their original order within each length. The
+ * return value is zero for a complete code set, negative for an over-
+ * subscribed code set, and positive for an incomplete code set. The tables
+ * can be used if the return value is zero or positive, but they cannot be used
+ * if the return value is negative. If the return value is zero, it is not
+ * possible for decode() using that table to return an error--any stream of
+ * enough bits will resolve to a symbol. If the return value is positive, then
+ * it is possible for decode() using that table to return an error for received
+ * codes past the end of the incomplete lengths.
+ *
+ * Not used by decode(), but used for error checking, h->count[0] is the number
+ * of the n symbols not in the code. So n - h->count[0] is the number of
+ * codes. This is useful for checking for incomplete codes that have more than
+ * one symbol, which is an error in a dynamic block.
+ *
+ * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS
+ * This is assured by the construction of the length arrays in dynamic() and
+ * fixed() and is not verified by construct().
+ *
+ * Format notes:
+ *
+ * - Permitted and expected examples of incomplete codes are one of the fixed
+ * codes and any code with a single symbol which in deflate is coded as one
+ * bit instead of zero bits. See the format notes for fixed() and dynamic().
+ *
+ * - Within a given code length, the symbols are kept in ascending order for
+ * the code bits definition.
+ */
+local int construct(struct huffman *h, short *length, int n)
+{
+ int symbol; /* current symbol when stepping through length[] */
+ int len; /* current length when stepping through h->count[] */
+ int left; /* number of possible codes left of current length */
+ short offs[MAXBITS+1]; /* offsets in symbol table for each length */
+
+ /* count number of codes of each length */
+ for (len = 0; len <= MAXBITS; len++)
+ h->count[len] = 0;
+ for (symbol = 0; symbol < n; symbol++)
+ (h->count[length[symbol]])++; /* assumes lengths are within bounds */
+ if (h->count[0] == n) /* no codes! */
+ return 0; /* complete, but decode() will fail */
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1; /* one possible code of zero length */
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1; /* one more bit, double codes left */
+ left -= h->count[len]; /* deduct count from possible codes */
+ if (left < 0) return left; /* over-subscribed--return negative */
+ } /* left > 0 means incomplete */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + h->count[len];
+
+ /*
+ * put symbols in table sorted by length, by symbol order within each
+ * length
+ */
+ for (symbol = 0; symbol < n; symbol++)
+ if (length[symbol] != 0)
+ h->symbol[offs[length[symbol]]++] = symbol;
+
+ /* return zero for complete set, positive for incomplete set */
+ return left;
+}
+
+/*
+ * Decode literal/length and distance codes until an end-of-block code.
+ *
+ * Format notes:
+ *
+ * - Compressed data that is after the block type if fixed or after the code
+ * description if dynamic is a combination of literals and length/distance
+ * pairs terminated by and end-of-block code. Literals are simply Huffman
+ * coded bytes. A length/distance pair is a coded length followed by a
+ * coded distance to represent a string that occurs earlier in the
+ * uncompressed data that occurs again at the current location.
+ *
+ * - Literals, lengths, and the end-of-block code are combined into a single
+ * code of up to 286 symbols. They are 256 literals (0..255), 29 length
+ * symbols (257..285), and the end-of-block symbol (256).
+ *
+ * - There are 256 possible lengths (3..258), and so 29 symbols are not enough
+ * to represent all of those. Lengths 3..10 and 258 are in fact represented
+ * by just a length symbol. Lengths 11..257 are represented as a symbol and
+ * some number of extra bits that are added as an integer to the base length
+ * of the length symbol. The number of extra bits is determined by the base
+ * length symbol. These are in the static arrays below, lens[] for the base
+ * lengths and lext[] for the corresponding number of extra bits.
+ *
+ * - The reason that 258 gets its own symbol is that the longest length is used
+ * often in highly redundant files. Note that 258 can also be coded as the
+ * base value 227 plus the maximum extra value of 31. While a good deflate
+ * should never do this, it is not an error, and should be decoded properly.
+ *
+ * - If a length is decoded, including its extra bits if any, then it is
+ * followed a distance code. There are up to 30 distance symbols. Again
+ * there are many more possible distances (1..32768), so extra bits are added
+ * to a base value represented by the symbol. The distances 1..4 get their
+ * own symbol, but the rest require extra bits. The base distances and
+ * corresponding number of extra bits are below in the static arrays dist[]
+ * and dext[].
+ *
+ * - Literal bytes are simply written to the output. A length/distance pair is
+ * an instruction to copy previously uncompressed bytes to the output. The
+ * copy is from distance bytes back in the output stream, copying for length
+ * bytes.
+ *
+ * - Distances pointing before the beginning of the output data are not
+ * permitted.
+ *
+ * - Overlapped copies, where the length is greater than the distance, are
+ * allowed and common. For example, a distance of one and a length of 258
+ * simply copies the last byte 258 times. A distance of four and a length of
+ * twelve copies the last four bytes three times. A simple forward copy
+ * ignoring whether the length is greater than the distance or not implements
+ * this correctly. You should not use memcpy() since its behavior is not
+ * defined for overlapped arrays. You should not use memmove() or bcopy()
+ * since though their behavior -is- defined for overlapping arrays, it is
+ * defined to do the wrong thing in this case.
+ */
+local int codes(struct state *s,
+ struct huffman *lencode,
+ struct huffman *distcode)
+{
+ int symbol; /* decoded symbol */
+ int len; /* length for copy */
+ unsigned dist; /* distance for copy */
+ static const short lens[29] = { /* Size base for length codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
+ static const short lext[29] = { /* Extra bits for length codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+ static const short dists[30] = { /* Offset base for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+ static const short dext[30] = { /* Extra bits for distance codes 0..29 */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+ /* decode literals and length/distance pairs */
+ do {
+ symbol = decode(s, lencode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ if (symbol < 256) { /* literal: symbol is the byte */
+ /* write out the literal */
+ if (s->out != NIL) {
+ if (s->outcnt == s->outlen) return 1;
+ s->out[s->outcnt] = symbol;
+ }
+ s->outcnt++;
+ }
+ else if (symbol > 256) { /* length */
+ /* get and compute length */
+ symbol -= 257;
+ if (symbol >= 29) return -9; /* invalid fixed code */
+ len = lens[symbol] + bits(s, lext[symbol]);
+
+ /* get and check distance */
+ symbol = decode(s, distcode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ dist = dists[symbol] + bits(s, dext[symbol]);
+ if (dist > s->outcnt)
+ return -10; /* distance too far back */
+
+ /* copy length bytes from distance bytes back */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen) return 1;
+ while (len--) {
+ s->out[s->outcnt] = s->out[s->outcnt - dist];
+ s->outcnt++;
+ }
+ }
+ else
+ s->outcnt += len;
+ }
+ } while (symbol != 256); /* end of block symbol */
+
+ /* done with a valid fixed or dynamic block */
+ return 0;
+}
+
+/*
+ * Process a fixed codes block.
+ *
+ * Format notes:
+ *
+ * - This block type can be useful for compressing small amounts of data for
+ * which the size of the code descriptions in a dynamic block exceeds the
+ * benefit of custom codes for that block. For fixed codes, no bits are
+ * spent on code descriptions. Instead the code lengths for literal/length
+ * codes and distance codes are fixed. The specific lengths for each symbol
+ * can be seen in the "for" loops below.
+ *
+ * - The literal/length code is complete, but has two symbols that are invalid
+ * and should result in an error if received. This cannot be implemented
+ * simply as an incomplete code since those two symbols are in the "middle"
+ * of the code. They are eight bits long and the longest literal/length\
+ * code is nine bits. Therefore the code must be constructed with those
+ * symbols, and the invalid symbols must be detected after decoding.
+ *
+ * - The fixed distance codes also have two invalid symbols that should result
+ * in an error if received. Since all of the distance codes are the same
+ * length, this can be implemented as an incomplete code. Then the invalid
+ * codes are detected while decoding.
+ */
+local int fixed(struct state *s)
+{
+ static int virgin = 1;
+ static short lencnt[MAXBITS+1], lensym[FIXLCODES];
+ static short distcnt[MAXBITS+1], distsym[MAXDCODES];
+ static struct huffman lencode = {lencnt, lensym};
+ static struct huffman distcode = {distcnt, distsym};
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ int symbol;
+ short lengths[FIXLCODES];
+
+ /* literal/length table */
+ for (symbol = 0; symbol < 144; symbol++)
+ lengths[symbol] = 8;
+ for (; symbol < 256; symbol++)
+ lengths[symbol] = 9;
+ for (; symbol < 280; symbol++)
+ lengths[symbol] = 7;
+ for (; symbol < FIXLCODES; symbol++)
+ lengths[symbol] = 8;
+ construct(&lencode, lengths, FIXLCODES);
+
+ /* distance table */
+ for (symbol = 0; symbol < MAXDCODES; symbol++)
+ lengths[symbol] = 5;
+ construct(&distcode, lengths, MAXDCODES);
+
+ /* do this just once */
+ virgin = 0;
+ }
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Process a dynamic codes block.
+ *
+ * Format notes:
+ *
+ * - A dynamic block starts with a description of the literal/length and
+ * distance codes for that block. New dynamic blocks allow the compressor to
+ * rapidly adapt to changing data with new codes optimized for that data.
+ *
+ * - The codes used by the deflate format are "canonical", which means that
+ * the actual bits of the codes are generated in an unambiguous way simply
+ * from the number of bits in each code. Therefore the code descriptions
+ * are simply a list of code lengths for each symbol.
+ *
+ * - The code lengths are stored in order for the symbols, so lengths are
+ * provided for each of the literal/length symbols, and for each of the
+ * distance symbols.
+ *
+ * - If a symbol is not used in the block, this is represented by a zero as
+ * as the code length. This does not mean a zero-length code, but rather
+ * that no code should be created for this symbol. There is no way in the
+ * deflate format to represent a zero-length code.
+ *
+ * - The maximum number of bits in a code is 15, so the possible lengths for
+ * any code are 1..15.
+ *
+ * - The fact that a length of zero is not permitted for a code has an
+ * interesting consequence. Normally if only one symbol is used for a given
+ * code, then in fact that code could be represented with zero bits. However
+ * in deflate, that code has to be at least one bit. So for example, if
+ * only a single distance base symbol appears in a block, then it will be
+ * represented by a single code of length one, in particular one 0 bit. This
+ * is an incomplete code, since if a 1 bit is received, it has no meaning,
+ * and should result in an error. So incomplete distance codes of one symbol
+ * should be permitted, and the receipt of invalid codes should be handled.
+ *
+ * - It is also possible to have a single literal/length code, but that code
+ * must be the end-of-block code, since every dynamic block has one. This
+ * is not the most efficient way to create an empty block (an empty fixed
+ * block is fewer bits), but it is allowed by the format. So incomplete
+ * literal/length codes of one symbol should also be permitted.
+ *
+ * - If there are only literal codes and no lengths, then there are no distance
+ * codes. This is represented by one distance code with zero bits.
+ *
+ * - The list of up to 286 length/literal lengths and up to 30 distance lengths
+ * are themselves compressed using Huffman codes and run-length encoding. In
+ * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means
+ * that length, and the symbols 16, 17, and 18 are run-length instructions.
+ * Each of 16, 17, and 18 are follwed by extra bits to define the length of
+ * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10
+ * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols
+ * are common, hence the special coding for zero lengths.
+ *
+ * - The symbols for 0..18 are Huffman coded, and so that code must be
+ * described first. This is simply a sequence of up to 19 three-bit values
+ * representing no code (0) or the code length for that symbol (1..7).
+ *
+ * - A dynamic block starts with three fixed-size counts from which is computed
+ * the number of literal/length code lengths, the number of distance code
+ * lengths, and the number of code length code lengths (ok, you come up with
+ * a better name!) in the code descriptions. For the literal/length and
+ * distance codes, lengths after those provided are considered zero, i.e. no
+ * code. The code length code lengths are received in a permuted order (see
+ * the order[] array below) to make a short code length code length list more
+ * likely. As it turns out, very short and very long codes are less likely
+ * to be seen in a dynamic code description, hence what may appear initially
+ * to be a peculiar ordering.
+ *
+ * - Given the number of literal/length code lengths (nlen) and distance code
+ * lengths (ndist), then they are treated as one long list of nlen + ndist
+ * code lengths. Therefore run-length coding can and often does cross the
+ * boundary between the two sets of lengths.
+ *
+ * - So to summarize, the code description at the start of a dynamic block is
+ * three counts for the number of code lengths for the literal/length codes,
+ * the distance codes, and the code length codes. This is followed by the
+ * code length code lengths, three bits each. This is used to construct the
+ * code length code which is used to read the remainder of the lengths. Then
+ * the literal/length code lengths and distance lengths are read as a single
+ * set of lengths using the code length codes. Codes are constructed from
+ * the resulting two sets of lengths, and then finally you can start
+ * decoding actual compressed data in the block.
+ *
+ * - For reference, a "typical" size for the code description in a dynamic
+ * block is around 80 bytes.
+ */
+local int dynamic(struct state *s)
+{
+ int nlen, ndist, ncode; /* number of lengths in descriptor */
+ int index; /* index of lengths[] */
+ int err; /* construct() return value */
+ short lengths[MAXCODES]; /* descriptor code lengths */
+ short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */
+ short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */
+ struct huffman lencode = {lencnt, lensym}; /* length code */
+ struct huffman distcode = {distcnt, distsym}; /* distance code */
+ static const short order[19] = /* permutation of code length codes */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* get number of lengths in each table, check lengths */
+ nlen = bits(s, 5) + 257;
+ ndist = bits(s, 5) + 1;
+ ncode = bits(s, 4) + 4;
+ if (nlen > MAXLCODES || ndist > MAXDCODES)
+ return -3; /* bad counts */
+
+ /* read code length code lengths (really), missing lengths are zero */
+ for (index = 0; index < ncode; index++)
+ lengths[order[index]] = bits(s, 3);
+ for (; index < 19; index++)
+ lengths[order[index]] = 0;
+
+ /* build huffman table for code lengths codes (use lencode temporarily) */
+ err = construct(&lencode, lengths, 19);
+ if (err != 0) return -4; /* require complete code set here */
+
+ /* read length/literal and distance code length tables */
+ index = 0;
+ while (index < nlen + ndist) {
+ int symbol; /* decoded value */
+ int len; /* last length to repeat */
+
+ symbol = decode(s, &lencode);
+ if (symbol < 16) /* length in 0..15 */
+ lengths[index++] = symbol;
+ else { /* repeat instruction */
+ len = 0; /* assume repeating zeros */
+ if (symbol == 16) { /* repeat last length 3..6 times */
+ if (index == 0) return -5; /* no last length! */
+ len = lengths[index - 1]; /* last length */
+ symbol = 3 + bits(s, 2);
+ }
+ else if (symbol == 17) /* repeat zero 3..10 times */
+ symbol = 3 + bits(s, 3);
+ else /* == 18, repeat zero 11..138 times */
+ symbol = 11 + bits(s, 7);
+ if (index + symbol > nlen + ndist)
+ return -6; /* too many lengths! */
+ while (symbol--) /* repeat last or zero symbol times */
+ lengths[index++] = len;
+ }
+ }
+
+ /* build huffman table for literal/length codes */
+ err = construct(&lencode, lengths, nlen);
+ if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
+ return -7; /* only allow incomplete codes if just one code */
+
+ /* build huffman table for distance codes */
+ err = construct(&distcode, lengths + nlen, ndist);
+ if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
+ return -8; /* only allow incomplete codes if just one code */
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Inflate source to dest. On return, destlen and sourcelen are updated to the
+ * size of the uncompressed data and the size of the deflate data respectively.
+ * On success, the return value of puff() is zero. If there is an error in the
+ * source data, i.e. it is not in the deflate format, then a negative value is
+ * returned. If there is not enough input available or there is not enough
+ * output space, then a positive error is returned. In that case, destlen and
+ * sourcelen are not updated to facilitate retrying from the beginning with the
+ * provision of more input data or more output space. In the case of invalid
+ * inflate data (a negative error), the dest and source pointers are updated to
+ * facilitate the debugging of deflators.
+ *
+ * puff() also has a mode to determine the size of the uncompressed output with
+ * no output written. For this dest must be (unsigned char *)0. In this case,
+ * the input value of *destlen is ignored, and on return *destlen is set to the
+ * size of the uncompressed output.
+ *
+ * The return codes are:
+ *
+ * 2: available inflate data did not terminate
+ * 1: output space exhausted before completing inflate
+ * 0: successful inflate
+ * -1: invalid block type (type == 3)
+ * -2: stored block length did not match one's complement
+ * -3: dynamic block code description: too many length or distance codes
+ * -4: dynamic block code description: code lengths codes incomplete
+ * -5: dynamic block code description: repeat lengths with no first length
+ * -6: dynamic block code description: repeat more than specified lengths
+ * -7: dynamic block code description: invalid literal/length code lengths
+ * -8: dynamic block code description: invalid distance code lengths
+ * -9: invalid literal/length or distance code in fixed or dynamic block
+ * -10: distance is too far back in fixed or dynamic block
+ *
+ * Format notes:
+ *
+ * - Three bits are read for each block to determine the kind of block and
+ * whether or not it is the last block. Then the block is decoded and the
+ * process repeated if it was not the last block.
+ *
+ * - The leftover bits in the last byte of the deflate data after the last
+ * block (if it was a fixed or dynamic block) are undefined and have no
+ * expected values to check.
+ */
+int puff(unsigned char *dest, /* pointer to destination pointer */
+ unsigned long *destlen, /* amount of output space */
+ unsigned char *source, /* pointer to source data pointer */
+ unsigned long *sourcelen) /* amount of input available */
+{
+ struct state s; /* input/output state */
+ int last, type; /* block information */
+ int err; /* return value */
+
+ /* initialize output state */
+ s.out = dest;
+ s.outlen = *destlen; /* ignored if dest is NIL */
+ s.outcnt = 0;
+
+ /* initialize input state */
+ s.in = source;
+ s.inlen = *sourcelen;
+ s.incnt = 0;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+
+ /* return if bits() or decode() tries to read past available input */
+ if (setjmp(s.env) != 0) /* if came back here via longjmp() */
+ err = 2; /* then skip do-loop, return error */
+ else {
+ /* process blocks until last block or error */
+ do {
+ last = bits(&s, 1); /* one if last block */
+ type = bits(&s, 2); /* block type 0..3 */
+ err = type == 0 ? stored(&s) :
+ (type == 1 ? fixed(&s) :
+ (type == 2 ? dynamic(&s) :
+ -1)); /* type == 3, invalid */
+ if (err != 0) break; /* return with error */
+ } while (!last);
+ }
+
+ /* update the lengths and return */
+ if (err <= 0) {
+ *destlen = s.outcnt;
+ *sourcelen = s.incnt;
+ }
+ return err;
+}
+
+#ifdef TEST
+/* Example of how to use puff() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+local unsigned char *yank(char *name, unsigned long *len)
+{
+ unsigned long size;
+ unsigned char *buf;
+ FILE *in;
+ struct stat s;
+
+ *len = 0;
+ if (stat(name, &s)) return NULL;
+ if ((s.st_mode & S_IFMT) != S_IFREG) return NULL;
+ size = (unsigned long)(s.st_size);
+ if (size == 0 || (off_t)size != s.st_size) return NULL;
+ in = fopen(name, "r");
+ if (in == NULL) return NULL;
+ buf = malloc(size);
+ if (buf != NULL && fread(buf, 1, size, in) != size) {
+ free(buf);
+ buf = NULL;
+ }
+ fclose(in);
+ *len = size;
+ return buf;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ unsigned char *source;
+ unsigned long len, sourcelen, destlen;
+
+ if (argc < 2) return 2;
+ source = yank(argv[1], &len);
+ if (source == NULL) return 2;
+ sourcelen = len;
+ ret = puff(NIL, &destlen, source, &sourcelen);
+ if (ret)
+ printf("puff() failed with return code %d\n", ret);
+ else {
+ printf("puff() succeeded uncompressing %lu bytes\n", destlen);
+ if (sourcelen < len) printf("%lu compressed bytes unused\n",
+ len - sourcelen);
+ }
+ free(source);
+ return ret;
+}
+#endif
diff --git a/zlib/contrib/puff/puff.h b/zlib/contrib/puff/puff.h
new file mode 100644
index 0000000..ef61252
--- /dev/null
+++ b/zlib/contrib/puff/puff.h
@@ -0,0 +1,31 @@
+/* puff.h
+ Copyright (C) 2002, 2003 Mark Adler, all rights reserved
+ version 1.7, 3 Mar 2002
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+
+/*
+ * See puff.c for purpose and usage.
+ */
+int puff(unsigned char *dest, /* pointer to destination pointer */
+ unsigned long *destlen, /* amount of output space */
+ unsigned char *source, /* pointer to source data pointer */
+ unsigned long *sourcelen); /* amount of input available */
diff --git a/zlib/contrib/puff/zeros.raw b/zlib/contrib/puff/zeros.raw
new file mode 100644
index 0000000..637b7be
--- /dev/null
+++ b/zlib/contrib/puff/zeros.raw
Binary files differ
diff --git a/zlib/contrib/testzlib/testzlib.c b/zlib/contrib/testzlib/testzlib.c
new file mode 100644
index 0000000..e5574f4
--- /dev/null
+++ b/zlib/contrib/testzlib/testzlib.c
@@ -0,0 +1,275 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+
+#include "zlib.h"
+
+
+void MyDoMinus64(LARGE_INTEGER *R,LARGE_INTEGER A,LARGE_INTEGER B)
+{
+ R->HighPart = A.HighPart - B.HighPart;
+ if (A.LowPart >= B.LowPart)
+ R->LowPart = A.LowPart - B.LowPart;
+ else
+ {
+ R->LowPart = A.LowPart - B.LowPart;
+ R->HighPart --;
+ }
+}
+
+#ifdef _M_X64
+// see http://msdn2.microsoft.com/library/twchhe95(en-us,vs.80).aspx for __rdtsc
+unsigned __int64 __rdtsc(void);
+void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64)
+{
+ // printf("rdtsc = %I64x\n",__rdtsc());
+ pbeginTime64->QuadPart=__rdtsc();
+}
+
+LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
+{
+ LARGE_INTEGER LIres;
+ unsigned _int64 res=__rdtsc()-((unsigned _int64)(beginTime64.QuadPart));
+ LIres.QuadPart=res;
+ // printf("rdtsc = %I64x\n",__rdtsc());
+ return LIres;
+}
+#else
+#ifdef _M_IX86
+void myGetRDTSC32(LARGE_INTEGER * pbeginTime64)
+{
+ DWORD dwEdx,dwEax;
+ _asm
+ {
+ rdtsc
+ mov dwEax,eax
+ mov dwEdx,edx
+ }
+ pbeginTime64->LowPart=dwEax;
+ pbeginTime64->HighPart=dwEdx;
+}
+
+void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64)
+{
+ myGetRDTSC32(pbeginTime64);
+}
+
+LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
+{
+ LARGE_INTEGER LIres,endTime64;
+ myGetRDTSC32(&endTime64);
+
+ LIres.LowPart=LIres.HighPart=0;
+ MyDoMinus64(&LIres,endTime64,beginTime64);
+ return LIres;
+}
+#else
+void myGetRDTSC32(LARGE_INTEGER * pbeginTime64)
+{
+}
+
+void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64)
+{
+}
+
+LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
+{
+ LARGE_INTEGER lr;
+ lr.QuadPart=0;
+ return lr;
+}
+#endif
+#endif
+
+void BeginCountPerfCounter(LARGE_INTEGER * pbeginTime64,BOOL fComputeTimeQueryPerf)
+{
+ if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(pbeginTime64)))
+ {
+ pbeginTime64->LowPart = GetTickCount();
+ pbeginTime64->HighPart = 0;
+ }
+}
+
+DWORD GetMsecSincePerfCounter(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf)
+{
+ LARGE_INTEGER endTime64,ticksPerSecond,ticks;
+ DWORDLONG ticksShifted,tickSecShifted;
+ DWORD dwLog=16+0;
+ DWORD dwRet;
+ if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(&endTime64)))
+ dwRet = (GetTickCount() - beginTime64.LowPart)*1;
+ else
+ {
+ MyDoMinus64(&ticks,endTime64,beginTime64);
+ QueryPerformanceFrequency(&ticksPerSecond);
+
+
+ {
+ ticksShifted = Int64ShrlMod32(*(DWORDLONG*)&ticks,dwLog);
+ tickSecShifted = Int64ShrlMod32(*(DWORDLONG*)&ticksPerSecond,dwLog);
+
+ }
+
+ dwRet = (DWORD)((((DWORD)ticksShifted)*1000)/(DWORD)(tickSecShifted));
+ dwRet *=1;
+ }
+ return dwRet;
+}
+
+int ReadFileMemory(const char* filename,long* plFileSize,void** pFilePtr)
+{
+ FILE* stream;
+ void* ptr;
+ int retVal=1;
+ stream=fopen(filename, "rb");
+ if (stream==NULL)
+ return 0;
+
+ fseek(stream,0,SEEK_END);
+
+ *plFileSize=ftell(stream);
+ fseek(stream,0,SEEK_SET);
+ ptr=malloc((*plFileSize)+1);
+ if (ptr==NULL)
+ retVal=0;
+ else
+ {
+ if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize))
+ retVal=0;
+ }
+ fclose(stream);
+ *pFilePtr=ptr;
+ return retVal;
+}
+
+int main(int argc, char *argv[])
+{
+ int BlockSizeCompress=0x8000;
+ int BlockSizeUncompress=0x8000;
+ int cprLevel=Z_DEFAULT_COMPRESSION ;
+ long lFileSize;
+ unsigned char* FilePtr;
+ long lBufferSizeCpr;
+ long lBufferSizeUncpr;
+ long lCompressedSize=0;
+ unsigned char* CprPtr;
+ unsigned char* UncprPtr;
+ long lSizeCpr,lSizeUncpr;
+ DWORD dwGetTick,dwMsecQP;
+ LARGE_INTEGER li_qp,li_rdtsc,dwResRdtsc;
+
+ if (argc<=1)
+ {
+ printf("run TestZlib <File> [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n");
+ return 0;
+ }
+
+ if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0)
+ {
+ printf("error reading %s\n",argv[1]);
+ return 1;
+ }
+ else printf("file %s read, %u bytes\n",argv[1],lFileSize);
+
+ if (argc>=3)
+ BlockSizeCompress=atol(argv[2]);
+
+ if (argc>=4)
+ BlockSizeUncompress=atol(argv[3]);
+
+ if (argc>=5)
+ cprLevel=(int)atol(argv[4]);
+
+ lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200;
+ lBufferSizeUncpr = lBufferSizeCpr;
+
+ CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress);
+
+ BeginCountPerfCounter(&li_qp,TRUE);
+ dwGetTick=GetTickCount();
+ BeginCountRdtsc(&li_rdtsc);
+ {
+ z_stream zcpr;
+ int ret=Z_OK;
+ long lOrigToDo = lFileSize;
+ long lOrigDone = 0;
+ int step=0;
+ memset(&zcpr,0,sizeof(z_stream));
+ deflateInit(&zcpr,cprLevel);
+
+ zcpr.next_in = FilePtr;
+ zcpr.next_out = CprPtr;
+
+
+ do
+ {
+ long all_read_before = zcpr.total_in;
+ zcpr.avail_in = min(lOrigToDo,BlockSizeCompress);
+ zcpr.avail_out = BlockSizeCompress;
+ ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH);
+ lOrigDone += (zcpr.total_in-all_read_before);
+ lOrigToDo -= (zcpr.total_in-all_read_before);
+ step++;
+ } while (ret==Z_OK);
+
+ lSizeCpr=zcpr.total_out;
+ deflateEnd(&zcpr);
+ dwGetTick=GetTickCount()-dwGetTick;
+ dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE);
+ dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE);
+ printf("total compress size = %u, in %u step\n",lSizeCpr,step);
+ printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.);
+ printf("defcpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.);
+ printf("defcpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart);
+ }
+
+ CprPtr=(unsigned char*)realloc(CprPtr,lSizeCpr);
+ UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress);
+
+ BeginCountPerfCounter(&li_qp,TRUE);
+ dwGetTick=GetTickCount();
+ BeginCountRdtsc(&li_rdtsc);
+ {
+ z_stream zcpr;
+ int ret=Z_OK;
+ long lOrigToDo = lSizeCpr;
+ long lOrigDone = 0;
+ int step=0;
+ memset(&zcpr,0,sizeof(z_stream));
+ inflateInit(&zcpr);
+
+ zcpr.next_in = CprPtr;
+ zcpr.next_out = UncprPtr;
+
+
+ do
+ {
+ long all_read_before = zcpr.total_in;
+ zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress);
+ zcpr.avail_out = BlockSizeUncompress;
+ ret=inflate(&zcpr,Z_SYNC_FLUSH);
+ lOrigDone += (zcpr.total_in-all_read_before);
+ lOrigToDo -= (zcpr.total_in-all_read_before);
+ step++;
+ } while (ret==Z_OK);
+
+ lSizeUncpr=zcpr.total_out;
+ inflateEnd(&zcpr);
+ dwGetTick=GetTickCount()-dwGetTick;
+ dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE);
+ dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE);
+ printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step);
+ printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.);
+ printf("uncpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.);
+ printf("uncpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart);
+ }
+
+ if (lSizeUncpr==lFileSize)
+ {
+ if (memcmp(FilePtr,UncprPtr,lFileSize)==0)
+ printf("compare ok\n");
+
+ }
+
+ return 0;
+}
diff --git a/zlib/contrib/testzlib/testzlib.txt b/zlib/contrib/testzlib/testzlib.txt
new file mode 100644
index 0000000..62258f1
--- /dev/null
+++ b/zlib/contrib/testzlib/testzlib.txt
@@ -0,0 +1,10 @@
+To build testzLib with Visual Studio 2005:
+
+copy to a directory file from :
+- root of zLib tree
+- contrib/testzlib
+- contrib/masmx86
+- contrib/masmx64
+- contrib/vstudio/vc7
+
+and open testzlib8.sln \ No newline at end of file
diff --git a/zlib/contrib/untgz/Makefile b/zlib/contrib/untgz/Makefile
new file mode 100644
index 0000000..b54266f
--- /dev/null
+++ b/zlib/contrib/untgz/Makefile
@@ -0,0 +1,14 @@
+CC=cc
+CFLAGS=-g
+
+untgz: untgz.o ../../libz.a
+ $(CC) $(CFLAGS) -o untgz untgz.o -L../.. -lz
+
+untgz.o: untgz.c ../../zlib.h
+ $(CC) $(CFLAGS) -c -I../.. untgz.c
+
+../../libz.a:
+ cd ../..; ./configure; make
+
+clean:
+ rm -f untgz untgz.o *~
diff --git a/zlib/contrib/untgz/Makefile.msc b/zlib/contrib/untgz/Makefile.msc
new file mode 100644
index 0000000..77b8602
--- /dev/null
+++ b/zlib/contrib/untgz/Makefile.msc
@@ -0,0 +1,17 @@
+CC=cl
+CFLAGS=-MD
+
+untgz.exe: untgz.obj ..\..\zlib.lib
+ $(CC) $(CFLAGS) untgz.obj ..\..\zlib.lib
+
+untgz.obj: untgz.c ..\..\zlib.h
+ $(CC) $(CFLAGS) -c -I..\.. untgz.c
+
+..\..\zlib.lib:
+ cd ..\..
+ $(MAKE) -f win32\makefile.msc
+ cd contrib\untgz
+
+clean:
+ -del untgz.obj
+ -del untgz.exe
diff --git a/zlib/contrib/untgz/untgz.c b/zlib/contrib/untgz/untgz.c
new file mode 100644
index 0000000..2c391e5
--- /dev/null
+++ b/zlib/contrib/untgz/untgz.c
@@ -0,0 +1,674 @@
+/*
+ * untgz.c -- Display contents and extract files from a gzip'd TAR file
+ *
+ * written by Pedro A. Aranda Gutierrez <paag@tid.es>
+ * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
+ * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "zlib.h"
+
+#ifdef unix
+# include <unistd.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+# ifndef F_OK
+# define F_OK 0
+# endif
+# define mkdir(dirname,mode) _mkdir(dirname)
+# ifdef _MSC_VER
+# define access(path,mode) _access(path,mode)
+# define chmod(path,mode) _chmod(path,mode)
+# define strdup(str) _strdup(str)
+# endif
+#else
+# include <utime.h>
+#endif
+
+
+/* values used in typeflag field */
+
+#define REGTYPE '0' /* regular file */
+#define AREGTYPE '\0' /* regular file */
+#define LNKTYPE '1' /* link */
+#define SYMTYPE '2' /* reserved */
+#define CHRTYPE '3' /* character special */
+#define BLKTYPE '4' /* block special */
+#define DIRTYPE '5' /* directory */
+#define FIFOTYPE '6' /* FIFO special */
+#define CONTTYPE '7' /* reserved */
+
+/* GNU tar extensions */
+
+#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */
+#define GNUTYPE_LONGLINK 'K' /* long link name */
+#define GNUTYPE_LONGNAME 'L' /* long file name */
+#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */
+#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */
+#define GNUTYPE_SPARSE 'S' /* sparse file */
+#define GNUTYPE_VOLHDR 'V' /* tape/volume header */
+
+
+/* tar header */
+
+#define BLOCKSIZE 512
+#define SHORTNAMESIZE 100
+
+struct tar_header
+{ /* byte offset */
+ char name[100]; /* 0 */
+ char mode[8]; /* 100 */
+ char uid[8]; /* 108 */
+ char gid[8]; /* 116 */
+ char size[12]; /* 124 */
+ char mtime[12]; /* 136 */
+ char chksum[8]; /* 148 */
+ char typeflag; /* 156 */
+ char linkname[100]; /* 157 */
+ char magic[6]; /* 257 */
+ char version[2]; /* 263 */
+ char uname[32]; /* 265 */
+ char gname[32]; /* 297 */
+ char devmajor[8]; /* 329 */
+ char devminor[8]; /* 337 */
+ char prefix[155]; /* 345 */
+ /* 500 */
+};
+
+union tar_buffer
+{
+ char buffer[BLOCKSIZE];
+ struct tar_header header;
+};
+
+struct attr_item
+{
+ struct attr_item *next;
+ char *fname;
+ int mode;
+ time_t time;
+};
+
+enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
+
+char *TGZfname OF((const char *));
+void TGZnotfound OF((const char *));
+
+int getoct OF((char *, int));
+char *strtime OF((time_t *));
+int setfiletime OF((char *, time_t));
+void push_attr OF((struct attr_item **, char *, int, time_t));
+void restore_attr OF((struct attr_item **));
+
+int ExprMatch OF((char *, char *));
+
+int makedir OF((char *));
+int matchname OF((int, int, char **, char *));
+
+void error OF((const char *));
+int tar OF((gzFile, int, int, int, char **));
+
+void help OF((int));
+int main OF((int, char **));
+
+char *prog;
+
+const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
+
+/* return the file name of the TGZ archive */
+/* or NULL if it does not exist */
+
+char *TGZfname (const char *arcname)
+{
+ static char buffer[1024];
+ int origlen,i;
+
+ strcpy(buffer,arcname);
+ origlen = strlen(buffer);
+
+ for (i=0; TGZsuffix[i]; i++)
+ {
+ strcpy(buffer+origlen,TGZsuffix[i]);
+ if (access(buffer,F_OK) == 0)
+ return buffer;
+ }
+ return NULL;
+}
+
+
+/* error message for the filename */
+
+void TGZnotfound (const char *arcname)
+{
+ int i;
+
+ fprintf(stderr,"%s: Couldn't find ",prog);
+ for (i=0;TGZsuffix[i];i++)
+ fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n",
+ arcname,
+ TGZsuffix[i]);
+ exit(1);
+}
+
+
+/* convert octal digits to int */
+/* on error return -1 */
+
+int getoct (char *p,int width)
+{
+ int result = 0;
+ char c;
+
+ while (width--)
+ {
+ c = *p++;
+ if (c == 0)
+ break;
+ if (c == ' ')
+ continue;
+ if (c < '0' || c > '7')
+ return -1;
+ result = result * 8 + (c - '0');
+ }
+ return result;
+}
+
+
+/* convert time_t to string */
+/* use the "YYYY/MM/DD hh:mm:ss" format */
+
+char *strtime (time_t *t)
+{
+ struct tm *local;
+ static char result[32];
+
+ local = localtime(t);
+ sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d",
+ local->tm_year+1900, local->tm_mon+1, local->tm_mday,
+ local->tm_hour, local->tm_min, local->tm_sec);
+ return result;
+}
+
+
+/* set file time */
+
+int setfiletime (char *fname,time_t ftime)
+{
+#ifdef WIN32
+ static int isWinNT = -1;
+ SYSTEMTIME st;
+ FILETIME locft, modft;
+ struct tm *loctm;
+ HANDLE hFile;
+ int result;
+
+ loctm = localtime(&ftime);
+ if (loctm == NULL)
+ return -1;
+
+ st.wYear = (WORD)loctm->tm_year + 1900;
+ st.wMonth = (WORD)loctm->tm_mon + 1;
+ st.wDayOfWeek = (WORD)loctm->tm_wday;
+ st.wDay = (WORD)loctm->tm_mday;
+ st.wHour = (WORD)loctm->tm_hour;
+ st.wMinute = (WORD)loctm->tm_min;
+ st.wSecond = (WORD)loctm->tm_sec;
+ st.wMilliseconds = 0;
+ if (!SystemTimeToFileTime(&st, &locft) ||
+ !LocalFileTimeToFileTime(&locft, &modft))
+ return -1;
+
+ if (isWinNT < 0)
+ isWinNT = (GetVersion() < 0x80000000) ? 1 : 0;
+ hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0),
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return -1;
+ result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1;
+ CloseHandle(hFile);
+ return result;
+#else
+ struct utimbuf settime;
+
+ settime.actime = settime.modtime = ftime;
+ return utime(fname,&settime);
+#endif
+}
+
+
+/* push file attributes */
+
+void push_attr(struct attr_item **list,char *fname,int mode,time_t time)
+{
+ struct attr_item *item;
+
+ item = (struct attr_item *)malloc(sizeof(struct attr_item));
+ if (item == NULL)
+ error("Out of memory");
+ item->fname = strdup(fname);
+ item->mode = mode;
+ item->time = time;
+ item->next = *list;
+ *list = item;
+}
+
+
+/* restore file attributes */
+
+void restore_attr(struct attr_item **list)
+{
+ struct attr_item *item, *prev;
+
+ for (item = *list; item != NULL; )
+ {
+ setfiletime(item->fname,item->time);
+ chmod(item->fname,item->mode);
+ prev = item;
+ item = item->next;
+ free(prev);
+ }
+ *list = NULL;
+}
+
+
+/* match regular expression */
+
+#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
+
+int ExprMatch (char *string,char *expr)
+{
+ while (1)
+ {
+ if (ISSPECIAL(*expr))
+ {
+ if (*expr == '/')
+ {
+ if (*string != '\\' && *string != '/')
+ return 0;
+ string ++; expr++;
+ }
+ else if (*expr == '*')
+ {
+ if (*expr ++ == 0)
+ return 1;
+ while (*++string != *expr)
+ if (*string == 0)
+ return 0;
+ }
+ }
+ else
+ {
+ if (*string != *expr)
+ return 0;
+ if (*expr++ == 0)
+ return 1;
+ string++;
+ }
+ }
+}
+
+
+/* recursive mkdir */
+/* abort on ENOENT; ignore other errors like "directory already exists" */
+/* return 1 if OK */
+/* 0 on error */
+
+int makedir (char *newdir)
+{
+ char *buffer = strdup(newdir);
+ char *p;
+ int len = strlen(buffer);
+
+ if (len <= 0) {
+ free(buffer);
+ return 0;
+ }
+ if (buffer[len-1] == '/') {
+ buffer[len-1] = '\0';
+ }
+ if (mkdir(buffer, 0755) == 0)
+ {
+ free(buffer);
+ return 1;
+ }
+
+ p = buffer+1;
+ while (1)
+ {
+ char hold;
+
+ while(*p && *p != '\\' && *p != '/')
+ p++;
+ hold = *p;
+ *p = 0;
+ if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT))
+ {
+ fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer);
+ free(buffer);
+ return 0;
+ }
+ if (hold == 0)
+ break;
+ *p++ = hold;
+ }
+ free(buffer);
+ return 1;
+}
+
+
+int matchname (int arg,int argc,char **argv,char *fname)
+{
+ if (arg == argc) /* no arguments given (untgz tgzarchive) */
+ return 1;
+
+ while (arg < argc)
+ if (ExprMatch(fname,argv[arg++]))
+ return 1;
+
+ return 0; /* ignore this for the moment being */
+}
+
+
+/* tar file list or extract */
+
+int tar (gzFile in,int action,int arg,int argc,char **argv)
+{
+ union tar_buffer buffer;
+ int len;
+ int err;
+ int getheader = 1;
+ int remaining = 0;
+ FILE *outfile = NULL;
+ char fname[BLOCKSIZE];
+ int tarmode;
+ time_t tartime;
+ struct attr_item *attributes = NULL;
+
+ if (action == TGZ_LIST)
+ printf(" date time size file\n"
+ " ---------- -------- --------- -------------------------------------\n");
+ while (1)
+ {
+ len = gzread(in, &buffer, BLOCKSIZE);
+ if (len < 0)
+ error(gzerror(in, &err));
+ /*
+ * Always expect complete blocks to process
+ * the tar information.
+ */
+ if (len != BLOCKSIZE)
+ {
+ action = TGZ_INVALID; /* force error exit */
+ remaining = 0; /* force I/O cleanup */
+ }
+
+ /*
+ * If we have to get a tar header
+ */
+ if (getheader >= 1)
+ {
+ /*
+ * if we met the end of the tar
+ * or the end-of-tar block,
+ * we are done
+ */
+ if (len == 0 || buffer.header.name[0] == 0)
+ break;
+
+ tarmode = getoct(buffer.header.mode,8);
+ tartime = (time_t)getoct(buffer.header.mtime,12);
+ if (tarmode == -1 || tartime == (time_t)-1)
+ {
+ buffer.header.name[0] = 0;
+ action = TGZ_INVALID;
+ }
+
+ if (getheader == 1)
+ {
+ strncpy(fname,buffer.header.name,SHORTNAMESIZE);
+ if (fname[SHORTNAMESIZE-1] != 0)
+ fname[SHORTNAMESIZE] = 0;
+ }
+ else
+ {
+ /*
+ * The file name is longer than SHORTNAMESIZE
+ */
+ if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0)
+ error("bad long name");
+ getheader = 1;
+ }
+
+ /*
+ * Act according to the type flag
+ */
+ switch (buffer.header.typeflag)
+ {
+ case DIRTYPE:
+ if (action == TGZ_LIST)
+ printf(" %s <dir> %s\n",strtime(&tartime),fname);
+ if (action == TGZ_EXTRACT)
+ {
+ makedir(fname);
+ push_attr(&attributes,fname,tarmode,tartime);
+ }
+ break;
+ case REGTYPE:
+ case AREGTYPE:
+ remaining = getoct(buffer.header.size,12);
+ if (remaining == -1)
+ {
+ action = TGZ_INVALID;
+ break;
+ }
+ if (action == TGZ_LIST)
+ printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
+ else if (action == TGZ_EXTRACT)
+ {
+ if (matchname(arg,argc,argv,fname))
+ {
+ outfile = fopen(fname,"wb");
+ if (outfile == NULL) {
+ /* try creating directory */
+ char *p = strrchr(fname, '/');
+ if (p != NULL) {
+ *p = '\0';
+ makedir(fname);
+ *p = '/';
+ outfile = fopen(fname,"wb");
+ }
+ }
+ if (outfile != NULL)
+ printf("Extracting %s\n",fname);
+ else
+ fprintf(stderr, "%s: Couldn't create %s",prog,fname);
+ }
+ else
+ outfile = NULL;
+ }
+ getheader = 0;
+ break;
+ case GNUTYPE_LONGLINK:
+ case GNUTYPE_LONGNAME:
+ remaining = getoct(buffer.header.size,12);
+ if (remaining < 0 || remaining >= BLOCKSIZE)
+ {
+ action = TGZ_INVALID;
+ break;
+ }
+ len = gzread(in, fname, BLOCKSIZE);
+ if (len < 0)
+ error(gzerror(in, &err));
+ if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining)
+ {
+ action = TGZ_INVALID;
+ break;
+ }
+ getheader = 2;
+ break;
+ default:
+ if (action == TGZ_LIST)
+ printf(" %s <---> %s\n",strtime(&tartime),fname);
+ break;
+ }
+ }
+ else
+ {
+ unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
+
+ if (outfile != NULL)
+ {
+ if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
+ {
+ fprintf(stderr,
+ "%s: Error writing %s -- skipping\n",prog,fname);
+ fclose(outfile);
+ outfile = NULL;
+ remove(fname);
+ }
+ }
+ remaining -= bytes;
+ }
+
+ if (remaining == 0)
+ {
+ getheader = 1;
+ if (outfile != NULL)
+ {
+ fclose(outfile);
+ outfile = NULL;
+ if (action != TGZ_INVALID)
+ push_attr(&attributes,fname,tarmode,tartime);
+ }
+ }
+
+ /*
+ * Abandon if errors are found
+ */
+ if (action == TGZ_INVALID)
+ {
+ error("broken archive");
+ break;
+ }
+ }
+
+ /*
+ * Restore file modes and time stamps
+ */
+ restore_attr(&attributes);
+
+ if (gzclose(in) != Z_OK)
+ error("failed gzclose");
+
+ return 0;
+}
+
+
+/* ============================================================ */
+
+void help(int exitval)
+{
+ printf("untgz version 0.2.1\n"
+ " using zlib version %s\n\n",
+ zlibVersion());
+ printf("Usage: untgz file.tgz extract all files\n"
+ " untgz file.tgz fname ... extract selected files\n"
+ " untgz -l file.tgz list archive contents\n"
+ " untgz -h display this help\n");
+ exit(exitval);
+}
+
+void error(const char *msg)
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+
+/* ============================================================ */
+
+#if defined(WIN32) && defined(__GNUC__)
+int _CRT_glob = 0; /* disable argument globbing in MinGW */
+#endif
+
+int main(int argc,char **argv)
+{
+ int action = TGZ_EXTRACT;
+ int arg = 1;
+ char *TGZfile;
+ gzFile *f;
+
+ prog = strrchr(argv[0],'\\');
+ if (prog == NULL)
+ {
+ prog = strrchr(argv[0],'/');
+ if (prog == NULL)
+ {
+ prog = strrchr(argv[0],':');
+ if (prog == NULL)
+ prog = argv[0];
+ else
+ prog++;
+ }
+ else
+ prog++;
+ }
+ else
+ prog++;
+
+ if (argc == 1)
+ help(0);
+
+ if (strcmp(argv[arg],"-l") == 0)
+ {
+ action = TGZ_LIST;
+ if (argc == ++arg)
+ help(0);
+ }
+ else if (strcmp(argv[arg],"-h") == 0)
+ {
+ help(0);
+ }
+
+ if ((TGZfile = TGZfname(argv[arg])) == NULL)
+ TGZnotfound(argv[arg]);
+
+ ++arg;
+ if ((action == TGZ_LIST) && (arg != argc))
+ help(1);
+
+/*
+ * Process the TGZ file
+ */
+ switch(action)
+ {
+ case TGZ_LIST:
+ case TGZ_EXTRACT:
+ f = gzopen(TGZfile,"rb");
+ if (f == NULL)
+ {
+ fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile);
+ return 1;
+ }
+ exit(tar(f, action, arg, argc, argv));
+ break;
+
+ default:
+ error("Unknown option");
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/zlib/contrib/vstudio/readme.txt b/zlib/contrib/vstudio/readme.txt
new file mode 100644
index 0000000..16159f9
--- /dev/null
+++ b/zlib/contrib/vstudio/readme.txt
@@ -0,0 +1,73 @@
+Building instructions for the DLL versions of Zlib 1.2.3
+========================================================
+
+This directory contains projects that build zlib and minizip using
+Microsoft Visual C++ 7.0/7.1, and Visual C++ .
+
+You don't need to build these projects yourself. You can download the
+binaries from:
+ http://www.winimage.com/zLibDll
+
+More information can be found at this site.
+
+
+Build instructions for Visual Studio 7.x (32 bits)
+--------------------------------------------------
+- Uncompress current zlib, including all contrib/* files
+- Download the crtdll library from
+ http://www.winimage.com/zLibDll/crtdll.zip
+ Unzip crtdll.zip to extract crtdll.lib on contrib\vstudio\vc7.
+- Open contrib\vstudio\vc7\zlibvc.sln with Microsoft Visual C++ 7.x
+ (Visual Studio .Net 2002 or 2003).
+
+Build instructions for Visual Studio 2005 (32 bits or 64 bits)
+--------------------------------------------------------------
+- Uncompress current zlib, including all contrib/* files
+- For 32 bits only: download the crtdll library from
+ http://www.winimage.com/zLibDll/crtdll.zip
+ Unzip crtdll.zip to extract crtdll.lib on contrib\vstudio\vc8.
+- Open contrib\vstudio\vc8\zlibvc.sln with Microsoft Visual C++ 8.0
+
+Build instructions for Visual Studio 2005 64 bits, PSDK compiler
+----------------------------------------------------------------
+at the time of writing this text file, Visual Studio 2005 (and
+ Microsoft Visual C++ 8.0) is on the beta 2 stage.
+Using you can get the free 64 bits compiler from Platform SDK,
+ which is NOT a beta, and compile using the Visual studio 2005 IDE
+see http://www.winimage.com/misc/sdk64onvs2005/ for instruction
+
+- Uncompress current zlib, including all contrib/* files
+- start Visual Studio 2005 from a platform SDK command prompt, using
+ the /useenv switch
+- Open contrib\vstudio\vc8\zlibvc.sln with Microsoft Visual C++ 8.0
+
+
+Important
+---------
+- To use zlibwapi.dll in your application, you must define the
+ macro ZLIB_WINAPI when compiling your application's source files.
+
+
+Additional notes
+----------------
+- This DLL, named zlibwapi.dll, is compatible to the old zlib.dll built
+ by Gilles Vollant from the zlib 1.1.x sources, and distributed at
+ http://www.winimage.com/zLibDll
+ It uses the WINAPI calling convention for the exported functions, and
+ includes the minizip functionality. If your application needs that
+ particular build of zlib.dll, you can rename zlibwapi.dll to zlib.dll.
+
+- The new DLL was renamed because there exist several incompatible
+ versions of zlib.dll on the Internet.
+
+- There is also an official DLL build of zlib, named zlib1.dll. This one
+ is exporting the functions using the CDECL convention. See the file
+ win32\DLL_FAQ.txt found in this zlib distribution.
+
+- There used to be a ZLIB_DLL macro in zlib 1.1.x, but now this symbol
+ has a slightly different effect. To avoid compatibility problems, do
+ not define it here.
+
+
+Gilles Vollant
+info@winimage.com
diff --git a/zlib/contrib/vstudio/vc7/miniunz.vcproj b/zlib/contrib/vstudio/vc7/miniunz.vcproj
new file mode 100644
index 0000000..ad5117c
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/miniunz.vcproj
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="miniunz"
+ ProjectGUID="{C52F9E7B-498A-42BE-8DB4-85A15694382A}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/miniunz.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+ <File
+ RelativePath="..\..\minizip\miniunz.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc">
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ <File
+ RelativePath="ReleaseDll\zlibwapi.lib">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc7/minizip.vcproj b/zlib/contrib/vstudio/vc7/minizip.vcproj
new file mode 100644
index 0000000..fb5b632
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/minizip.vcproj
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="minizip"
+ ProjectGUID="{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/minizip.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+ <File
+ RelativePath="..\..\minizip\minizip.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc">
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ <File
+ RelativePath="ReleaseDll\zlibwapi.lib">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc7/testzlib.vcproj b/zlib/contrib/vstudio/vc7/testzlib.vcproj
new file mode 100644
index 0000000..97bc3e8
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/testzlib.vcproj
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="testZlibDll"
+ ProjectGUID="{AA6666AA-E09F-4135-9C0C-4FE50C3C654C}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/testzlib.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+ <File
+ RelativePath="..\..\testzlib\testzlib.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc">
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ <File
+ RelativePath="ReleaseDll\zlibwapi.lib">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc7/zlib.rc b/zlib/contrib/vstudio/vc7/zlib.rc
new file mode 100644
index 0000000..72cb8b4
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/zlib.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+#define IDR_VERSION1 1
+IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
+ FILEVERSION 1,2,3,0
+ PRODUCTVERSION 1,2,3,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS_DOS_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0 // not used
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ //language ID = U.S. English, char set = Windows, Multilingual
+
+ BEGIN
+ VALUE "FileDescription", "zlib data compression library\0"
+ VALUE "FileVersion", "1.2.3.0\0"
+ VALUE "InternalName", "zlib\0"
+ VALUE "OriginalFilename", "zlib.dll\0"
+ VALUE "ProductName", "ZLib.DLL\0"
+ VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
+ VALUE "LegalCopyright", "(C) 1995-2003 Jean-loup Gailly & Mark Adler\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+END
diff --git a/zlib/contrib/vstudio/vc7/zlibstat.vcproj b/zlib/contrib/vstudio/vc7/zlibstat.vcproj
new file mode 100644
index 0000000..766d7a4
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/zlibstat.vcproj
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="zlibstat"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\zlibstatDebug"
+ IntermediateDirectory=".\zlibstatDebug"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="5"
+ PrecompiledHeaderFile=".\zlibstatDebug/zlibstat.pch"
+ AssemblerListingLocation=".\zlibstatDebug/"
+ ObjectFile=".\zlibstatDebug/"
+ ProgramDataBaseFileName=".\zlibstatDebug/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="1"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/NODEFAULTLIB "
+ OutputFile=".\zlibstatDebug\zlibstat.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="ReleaseAxp|Win32"
+ OutputDirectory=".\zlibsta0"
+ IntermediateDirectory=".\zlibsta0"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\zlibsta0/zlibstat.pch"
+ AssemblerListingLocation=".\zlibsta0/"
+ ObjectFile=".\zlibsta0/"
+ ProgramDataBaseFileName=".\zlibsta0/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/NODEFAULTLIB "
+ OutputFile=".\zlibsta0\zlibstat.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\zlibstat"
+ IntermediateDirectory=".\zlibstat"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;ASMV;ASMINF"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\zlibstat/zlibstat.pch"
+ AssemblerListingLocation=".\zlibstat/"
+ ObjectFile=".\zlibstat/"
+ ProgramDataBaseFileName=".\zlibstat/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj /NODEFAULTLIB "
+ OutputFile=".\zlibstat\zlibstat.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Win32"
+ OutputDirectory="zlibstatWithoutAsm"
+ IntermediateDirectory="zlibstatWithoutAsm"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\zlibstat/zlibstat.pch"
+ AssemblerListingLocation=".\zlibstatWithoutAsm/"
+ ObjectFile=".\zlibstatWithoutAsm/"
+ ProgramDataBaseFileName=".\zlibstatWithoutAsm/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions=" /NODEFAULTLIB "
+ OutputFile=".\zlibstatWithoutAsm\zlibstat.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="">
+ <File
+ RelativePath="..\..\..\adler32.c">
+ </File>
+ <File
+ RelativePath="..\..\..\compress.c">
+ </File>
+ <File
+ RelativePath="..\..\..\crc32.c">
+ </File>
+ <File
+ RelativePath="..\..\..\deflate.c">
+ </File>
+ <File
+ RelativePath="..\..\masmx86\gvmat32c.c">
+ </File>
+ <File
+ RelativePath="..\..\..\gzio.c">
+ </File>
+ <File
+ RelativePath="..\..\..\infback.c">
+ </File>
+ <File
+ RelativePath="..\..\..\inffast.c">
+ </File>
+ <File
+ RelativePath="..\..\..\inflate.c">
+ </File>
+ <File
+ RelativePath="..\..\..\inftrees.c">
+ </File>
+ <File
+ RelativePath="..\..\minizip\ioapi.c">
+ </File>
+ <File
+ RelativePath="..\..\..\trees.c">
+ </File>
+ <File
+ RelativePath="..\..\..\uncompr.c">
+ </File>
+ <File
+ RelativePath="..\..\minizip\unzip.c">
+ </File>
+ <File
+ RelativePath="..\..\minizip\zip.c">
+ </File>
+ <File
+ RelativePath=".\zlib.rc">
+ </File>
+ <File
+ RelativePath=".\zlibvc.def">
+ </File>
+ <File
+ RelativePath="..\..\..\zutil.c">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc7/zlibvc.def b/zlib/contrib/vstudio/vc7/zlibvc.def
new file mode 100644
index 0000000..a40e715
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/zlibvc.def
@@ -0,0 +1,92 @@
+
+VERSION 1.23
+
+HEAPSIZE 1048576,8192
+
+EXPORTS
+ adler32 @1
+ compress @2
+ crc32 @3
+ deflate @4
+ deflateCopy @5
+ deflateEnd @6
+ deflateInit2_ @7
+ deflateInit_ @8
+ deflateParams @9
+ deflateReset @10
+ deflateSetDictionary @11
+ gzclose @12
+ gzdopen @13
+ gzerror @14
+ gzflush @15
+ gzopen @16
+ gzread @17
+ gzwrite @18
+ inflate @19
+ inflateEnd @20
+ inflateInit2_ @21
+ inflateInit_ @22
+ inflateReset @23
+ inflateSetDictionary @24
+ inflateSync @25
+ uncompress @26
+ zlibVersion @27
+ gzprintf @28
+ gzputc @29
+ gzgetc @30
+ gzseek @31
+ gzrewind @32
+ gztell @33
+ gzeof @34
+ gzsetparams @35
+ zError @36
+ inflateSyncPoint @37
+ get_crc_table @38
+ compress2 @39
+ gzputs @40
+ gzgets @41
+ inflateCopy @42
+ inflateBackInit_ @43
+ inflateBack @44
+ inflateBackEnd @45
+ compressBound @46
+ deflateBound @47
+ gzclearerr @48
+ gzungetc @49
+ zlibCompileFlags @50
+ deflatePrime @51
+
+ unzOpen @61
+ unzClose @62
+ unzGetGlobalInfo @63
+ unzGetCurrentFileInfo @64
+ unzGoToFirstFile @65
+ unzGoToNextFile @66
+ unzOpenCurrentFile @67
+ unzReadCurrentFile @68
+ unzOpenCurrentFile3 @69
+ unztell @70
+ unzeof @71
+ unzCloseCurrentFile @72
+ unzGetGlobalComment @73
+ unzStringFileNameCompare @74
+ unzLocateFile @75
+ unzGetLocalExtrafield @76
+ unzOpen2 @77
+ unzOpenCurrentFile2 @78
+ unzOpenCurrentFilePassword @79
+
+ zipOpen @80
+ zipOpenNewFileInZip @81
+ zipWriteInFileInZip @82
+ zipCloseFileInZip @83
+ zipClose @84
+ zipOpenNewFileInZip2 @86
+ zipCloseFileInZipRaw @87
+ zipOpen2 @88
+ zipOpenNewFileInZip3 @89
+
+ unzGetFilePos @100
+ unzGoToFilePos @101
+
+ fill_win32_filefunc @110
diff --git a/zlib/contrib/vstudio/vc7/zlibvc.sln b/zlib/contrib/vstudio/vc7/zlibvc.sln
new file mode 100644
index 0000000..927b42b
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/zlibvc.sln
@@ -0,0 +1,78 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testZlibDll", "testzlib.vcproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654C}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Debug
+ ConfigName.1 = Release
+ ConfigName.2 = ReleaseAxp
+ ConfigName.3 = ReleaseWithoutAsm
+ ConfigName.4 = ReleaseWithoutCrtdll
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug.ActiveCfg = Debug|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug.Build.0 = Debug|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release.ActiveCfg = Release|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release.Build.0 = Release|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseAxp.ActiveCfg = ReleaseAxp|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseAxp.Build.0 = ReleaseAxp|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm.ActiveCfg = ReleaseWithoutAsm|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm.Build.0 = ReleaseWithoutAsm|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutCrtdll.ActiveCfg = ReleaseAxp|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutCrtdll.Build.0 = ReleaseAxp|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug.ActiveCfg = Debug|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug.Build.0 = Debug|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release.ActiveCfg = Release|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release.Build.0 = Release|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseAxp.ActiveCfg = ReleaseAxp|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseAxp.Build.0 = ReleaseAxp|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm.ActiveCfg = ReleaseWithoutAsm|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm.Build.0 = ReleaseWithoutAsm|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutCrtdll.ActiveCfg = ReleaseWithoutCrtdll|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutCrtdll.Build.0 = ReleaseWithoutCrtdll|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug.ActiveCfg = Debug|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug.Build.0 = Debug|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release.ActiveCfg = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release.Build.0 = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseAxp.ActiveCfg = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseAxp.Build.0 = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm.ActiveCfg = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm.Build.0 = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutCrtdll.ActiveCfg = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutCrtdll.Build.0 = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug.ActiveCfg = Debug|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug.Build.0 = Debug|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release.ActiveCfg = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release.Build.0 = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseAxp.ActiveCfg = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseAxp.Build.0 = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm.ActiveCfg = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm.Build.0 = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutCrtdll.ActiveCfg = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutCrtdll.Build.0 = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.Debug.ActiveCfg = Debug|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.Debug.Build.0 = Debug|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.Release.ActiveCfg = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.Release.Build.0 = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.ReleaseAxp.ActiveCfg = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.ReleaseAxp.Build.0 = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.ReleaseWithoutAsm.ActiveCfg = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.ReleaseWithoutAsm.Build.0 = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.ReleaseWithoutCrtdll.ActiveCfg = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654C}.ReleaseWithoutCrtdll.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/zlib/contrib/vstudio/vc7/zlibvc.vcproj b/zlib/contrib/vstudio/vc7/zlibvc.vcproj
new file mode 100644
index 0000000..8533b49
--- /dev/null
+++ b/zlib/contrib/vstudio/vc7/zlibvc.vcproj
@@ -0,0 +1,445 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="zlibvc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\DebugDll"
+ IntermediateDirectory=".\DebugDll"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,ZLIB_WINAPI,ASMV,ASMINF"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\DebugDll/zlibvc.pch"
+ AssemblerListingLocation=".\DebugDll/"
+ ObjectFile=".\DebugDll/"
+ ProgramDataBaseFileName=".\DebugDll/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj"
+ OutputFile=".\DebugDll\zlibwapi.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile=".\zlibvc.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\DebugDll/zlibwapi.pdb"
+ SubSystem="2"
+ ImportLibrary=".\DebugDll/zlibwapi.lib"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\DebugDll/zlibvc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Win32"
+ OutputDirectory=".\zlibDllWithoutAsm"
+ IntermediateDirectory=".\zlibDllWithoutAsm"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,ZLIB_WINAPI"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\zlibDllWithoutAsm/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation=".\zlibDllWithoutAsm/"
+ ObjectFile=".\zlibDllWithoutAsm/"
+ ProgramDataBaseFileName=".\zlibDllWithoutAsm/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="crtdll.lib"
+ OutputFile=".\zlibDllWithoutAsm\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ IgnoreAllDefaultLibraries="TRUE"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile=".\zlibDllWithoutAsm/zlibwapi.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\zlibDllWithoutAsm/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary=".\zlibDllWithoutAsm/zlibwapi.lib"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\zlibDllWithoutAsm/zlibvc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutCrtdll|Win32"
+ OutputDirectory=".\zlibDllWithoutCrtDll"
+ IntermediateDirectory=".\zlibDllWithoutCrtDll"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,ZLIB_WINAPI,ASMV,ASMINF"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\zlibDllWithoutCrtDll/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation=".\zlibDllWithoutCrtDll/"
+ ObjectFile=".\zlibDllWithoutCrtDll/"
+ ProgramDataBaseFileName=".\zlibDllWithoutCrtDll/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj "
+ OutputFile=".\zlibDllWithoutCrtDll\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ IgnoreAllDefaultLibraries="FALSE"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile=".\zlibDllWithoutCrtDll/zlibwapi.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\zlibDllWithoutCrtDll/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary=".\zlibDllWithoutCrtDll/zlibwapi.lib"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\zlibDllWithoutCrtDll/zlibvc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="ReleaseAxp|Win32"
+ OutputDirectory=".\zlibvc__"
+ IntermediateDirectory=".\zlibvc__"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,ZLIB_WINAPI"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\zlibvc__/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation=".\zlibvc__/"
+ ObjectFile=".\zlibvc__/"
+ ProgramDataBaseFileName=".\zlibvc__/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="crtdll.lib"
+ OutputFile="zlibvc__\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ IgnoreAllDefaultLibraries="TRUE"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile=".\zlibvc__/zlibwapi.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\zlibvc__/zlibwapi.map"
+ SubSystem="2"
+ ImportLibrary=".\zlibvc__/zlibwapi.lib"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\zlibvc__/zlibvc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\ReleaseDll"
+ IntermediateDirectory=".\ReleaseDll"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,ZLIB_WINAPI,ASMV,ASMINF"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\ReleaseDll/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation=".\ReleaseDll/"
+ ObjectFile=".\ReleaseDll/"
+ ProgramDataBaseFileName=".\ReleaseDll/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj crtdll.lib"
+ OutputFile=".\ReleaseDll\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ IgnoreAllDefaultLibraries="TRUE"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile=".\ReleaseDll/zlibwapi.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\ReleaseDll/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary=".\ReleaseDll/zlibwapi.lib"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/zlibvc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90">
+ <File
+ RelativePath="..\..\..\adler32.c">
+ </File>
+ <File
+ RelativePath="..\..\..\compress.c">
+ </File>
+ <File
+ RelativePath="..\..\..\crc32.c">
+ </File>
+ <File
+ RelativePath="..\..\..\deflate.c">
+ </File>
+ <File
+ RelativePath="..\..\masmx86\gvmat32c.c">
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\gzio.c">
+ </File>
+ <File
+ RelativePath="..\..\..\infback.c">
+ </File>
+ <File
+ RelativePath="..\..\..\inffast.c">
+ </File>
+ <File
+ RelativePath="..\..\..\inflate.c">
+ </File>
+ <File
+ RelativePath="..\..\..\inftrees.c">
+ </File>
+ <File
+ RelativePath="..\..\minizip\ioapi.c">
+ </File>
+ <File
+ RelativePath="..\..\minizip\iowin32.c">
+ </File>
+ <File
+ RelativePath="..\..\..\trees.c">
+ </File>
+ <File
+ RelativePath="..\..\..\uncompr.c">
+ </File>
+ <File
+ RelativePath="..\..\minizip\unzip.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\minizip\zip.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\zlib.rc">
+ </File>
+ <File
+ RelativePath=".\zlibvc.def">
+ </File>
+ <File
+ RelativePath="..\..\..\zutil.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;fi;fd">
+ <File
+ RelativePath="..\..\..\deflate.h">
+ </File>
+ <File
+ RelativePath="..\..\..\infblock.h">
+ </File>
+ <File
+ RelativePath="..\..\..\infcodes.h">
+ </File>
+ <File
+ RelativePath="..\..\..\inffast.h">
+ </File>
+ <File
+ RelativePath="..\..\..\inftrees.h">
+ </File>
+ <File
+ RelativePath="..\..\..\infutil.h">
+ </File>
+ <File
+ RelativePath="..\..\..\zconf.h">
+ </File>
+ <File
+ RelativePath="..\..\..\zlib.h">
+ </File>
+ <File
+ RelativePath="..\..\..\zutil.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc8/miniunz.vcproj b/zlib/contrib/vstudio/vc8/miniunz.vcproj
new file mode 100644
index 0000000..4af53e8
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/miniunz.vcproj
@@ -0,0 +1,566 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="miniunz"
+ ProjectGUID="{C52F9E7B-498A-42BE-8DB4-85A15694382A}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ <Platform
+ Name="Itanium"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="x86\MiniUnzip$(ConfigurationName)"
+ IntermediateDirectory="x86\MiniUnzip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x86\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/miniunz.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="x64\MiniUnzip$(ConfigurationName)"
+ IntermediateDirectory="x64\MiniUnzip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x64\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/miniunz.pdb"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Itanium"
+ OutputDirectory="ia64\MiniUnzip$(ConfigurationName)"
+ IntermediateDirectory="ia64\MiniUnzip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ia64\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/miniunz.pdb"
+ SubSystem="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="x86\MiniUnzip$(ConfigurationName)"
+ IntermediateDirectory="x86\MiniUnzip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x86\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="x64\MiniUnzip$(ConfigurationName)"
+ IntermediateDirectory="x64\MiniUnzip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x64\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Itanium"
+ OutputDirectory="ia64\MiniUnzip$(ConfigurationName)"
+ IntermediateDirectory="ia64\MiniUnzip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ia64\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/miniunz.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+ >
+ <File
+ RelativePath="..\..\minizip\miniunz.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc8/minizip.vcproj b/zlib/contrib/vstudio/vc8/minizip.vcproj
new file mode 100644
index 0000000..85f64c4
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/minizip.vcproj
@@ -0,0 +1,563 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="minizip"
+ ProjectGUID="{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ <Platform
+ Name="Itanium"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="x86\MiniZip$(ConfigurationName)"
+ IntermediateDirectory="x86\MiniZip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x86\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/minizip.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="x64\$(ConfigurationName)"
+ IntermediateDirectory="x64\$(ConfigurationName)"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x64\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/minizip.pdb"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Itanium"
+ OutputDirectory="ia64\$(ConfigurationName)"
+ IntermediateDirectory="ia64\$(ConfigurationName)"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ia64\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/minizip.pdb"
+ SubSystem="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="x86\MiniZip$(ConfigurationName)"
+ IntermediateDirectory="x86\MiniZip$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x86\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="x64\$(ConfigurationName)"
+ IntermediateDirectory="x64\$(ConfigurationName)"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x64\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Itanium"
+ OutputDirectory="ia64\$(ConfigurationName)"
+ IntermediateDirectory="ia64\$(ConfigurationName)"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ia64\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/minizip.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+ >
+ <File
+ RelativePath="..\..\minizip\minizip.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc8/testzlib.vcproj b/zlib/contrib/vstudio/vc8/testzlib.vcproj
new file mode 100644
index 0000000..68c3539
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/testzlib.vcproj
@@ -0,0 +1,948 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="testzlib"
+ ProjectGUID="{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}"
+ RootNamespace="testzlib"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ <Platform
+ Name="Itanium"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="x86\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="x86\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerOutput="4"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testzlib.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="x64\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="x64\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ AssemblerListingLocation="$(IntDir)\"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj"
+ GenerateManifest="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Itanium"
+ OutputDirectory="ia64\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="ia64\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerOutput="4"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testzlib.pdb"
+ SubSystem="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Win32"
+ OutputDirectory="x86\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="x86\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|x64"
+ OutputDirectory="x64\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="x64\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ AssemblerListingLocation="$(IntDir)\"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ GenerateManifest="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Itanium"
+ OutputDirectory="ia64\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="ia64\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="x86\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="x86\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="x64\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="x64\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ AssemblerListingLocation="$(IntDir)\"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj"
+ GenerateManifest="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Itanium"
+ OutputDirectory="ia64\TestZlib$(ConfigurationName)"
+ IntermediateDirectory="ia64\TestZlib$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+ >
+ <File
+ RelativePath="..\..\..\adler32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\crc32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\deflate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\masmx86\gvmat32c.c"
+ >
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win64 (AMD64)"
+ ExcludedFromBuild="TRUE"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win64 (AMD64)"
+ ExcludedFromBuild="TRUE"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseAsm|Win64 (AMD64)"
+ ExcludedFromBuild="TRUE"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\infback.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\masmx64\inffas8664.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\inffast.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inflate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inftrees.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\testzlib\testzlib.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\trees.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\uncompr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\zutil.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc8/testzlibdll.vcproj b/zlib/contrib/vstudio/vc8/testzlibdll.vcproj
new file mode 100644
index 0000000..f38ab5e
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/testzlibdll.vcproj
@@ -0,0 +1,567 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="TestZlibDll"
+ ProjectGUID="{C52F9E7B-498A-42BE-8DB4-85A15694366A}"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ <Platform
+ Name="Itanium"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="x86\TestZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x86\TestZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x86\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testzlib.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="x64\TestZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x64\TestZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x64\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testzlib.pdb"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Itanium"
+ OutputDirectory="ia64\TestZlibDll$(ConfigurationName)"
+ IntermediateDirectory="ia64\TestZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ia64\ZlibDllDebug\zlibwapi.lib"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testzlib.pdb"
+ SubSystem="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="x86\TestZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x86\TestZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x86\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="x64\TestZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x64\TestZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="x64\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Itanium"
+ OutputDirectory="ia64\TestZlibDll$(ConfigurationName)"
+ IntermediateDirectory="ia64\TestZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="1"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="..\..\..;..\..\minizip"
+ PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64"
+ StringPooling="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ia64\ZlibDllRelease\zlibwapi.lib"
+ OutputFile="$(OutDir)/testzlib.exe"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+ >
+ <File
+ RelativePath="..\..\testzlib\testzlib.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc8/zlib.rc b/zlib/contrib/vstudio/vc8/zlib.rc
new file mode 100644
index 0000000..72cb8b4
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/zlib.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+#define IDR_VERSION1 1
+IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
+ FILEVERSION 1,2,3,0
+ PRODUCTVERSION 1,2,3,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS_DOS_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0 // not used
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ //language ID = U.S. English, char set = Windows, Multilingual
+
+ BEGIN
+ VALUE "FileDescription", "zlib data compression library\0"
+ VALUE "FileVersion", "1.2.3.0\0"
+ VALUE "InternalName", "zlib\0"
+ VALUE "OriginalFilename", "zlib.dll\0"
+ VALUE "ProductName", "ZLib.DLL\0"
+ VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
+ VALUE "LegalCopyright", "(C) 1995-2003 Jean-loup Gailly & Mark Adler\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+END
diff --git a/zlib/contrib/vstudio/vc8/zlibstat.vcproj b/zlib/contrib/vstudio/vc8/zlibstat.vcproj
new file mode 100644
index 0000000..fb97037
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/zlibstat.vcproj
@@ -0,0 +1,870 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="zlibstat"
+ ProjectGUID="{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ <Platform
+ Name="Itanium"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="x86\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="x86\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ ExceptionHandling="0"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="false"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:X86 /NODEFAULTLIB"
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="x64\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="x64\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:AMD64 /NODEFAULTLIB"
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Itanium"
+ OutputDirectory="ia64\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="ia64\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:IA64 /NODEFAULTLIB"
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="x86\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="x86\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ASMV;ASMINF"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:X86 /NODEFAULTLIB"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj "
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="x64\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="x64\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ASMV;ASMINF;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:AMD64 /NODEFAULTLIB"
+ AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj "
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Itanium"
+ OutputDirectory="ia64\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="ia64\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:IA64 /NODEFAULTLIB"
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Win32"
+ OutputDirectory="x86\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="x86\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:X86 /NODEFAULTLIB"
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|x64"
+ OutputDirectory="x64\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="x64\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:AMD64 /NODEFAULTLIB"
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Itanium"
+ OutputDirectory="ia64\ZlibStat$(ConfigurationName)"
+ IntermediateDirectory="ia64\ZlibStat$(ConfigurationName)\Tmp"
+ ConfigurationType="4"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="2"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibstat.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalOptions="/MACHINE:IA64 /NODEFAULTLIB"
+ OutputFile="$(OutDir)\zlibstat.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath="..\..\..\adler32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\crc32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\deflate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\masmx86\gvmat32c.c"
+ >
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\gzio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\infback.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\masmx64\inffas8664.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\inffast.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inflate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inftrees.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\minizip\ioapi.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\trees.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\uncompr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\minizip\unzip.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\minizip\zip.c"
+ >
+ </File>
+ <File
+ RelativePath=".\zlib.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\zlibvc.def"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\zutil.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/contrib/vstudio/vc8/zlibvc.def b/zlib/contrib/vstudio/vc8/zlibvc.def
new file mode 100644
index 0000000..a40e715
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/zlibvc.def
@@ -0,0 +1,92 @@
+
+VERSION 1.23
+
+HEAPSIZE 1048576,8192
+
+EXPORTS
+ adler32 @1
+ compress @2
+ crc32 @3
+ deflate @4
+ deflateCopy @5
+ deflateEnd @6
+ deflateInit2_ @7
+ deflateInit_ @8
+ deflateParams @9
+ deflateReset @10
+ deflateSetDictionary @11
+ gzclose @12
+ gzdopen @13
+ gzerror @14
+ gzflush @15
+ gzopen @16
+ gzread @17
+ gzwrite @18
+ inflate @19
+ inflateEnd @20
+ inflateInit2_ @21
+ inflateInit_ @22
+ inflateReset @23
+ inflateSetDictionary @24
+ inflateSync @25
+ uncompress @26
+ zlibVersion @27
+ gzprintf @28
+ gzputc @29
+ gzgetc @30
+ gzseek @31
+ gzrewind @32
+ gztell @33
+ gzeof @34
+ gzsetparams @35
+ zError @36
+ inflateSyncPoint @37
+ get_crc_table @38
+ compress2 @39
+ gzputs @40
+ gzgets @41
+ inflateCopy @42
+ inflateBackInit_ @43
+ inflateBack @44
+ inflateBackEnd @45
+ compressBound @46
+ deflateBound @47
+ gzclearerr @48
+ gzungetc @49
+ zlibCompileFlags @50
+ deflatePrime @51
+
+ unzOpen @61
+ unzClose @62
+ unzGetGlobalInfo @63
+ unzGetCurrentFileInfo @64
+ unzGoToFirstFile @65
+ unzGoToNextFile @66
+ unzOpenCurrentFile @67
+ unzReadCurrentFile @68
+ unzOpenCurrentFile3 @69
+ unztell @70
+ unzeof @71
+ unzCloseCurrentFile @72
+ unzGetGlobalComment @73
+ unzStringFileNameCompare @74
+ unzLocateFile @75
+ unzGetLocalExtrafield @76
+ unzOpen2 @77
+ unzOpenCurrentFile2 @78
+ unzOpenCurrentFilePassword @79
+
+ zipOpen @80
+ zipOpenNewFileInZip @81
+ zipWriteInFileInZip @82
+ zipCloseFileInZip @83
+ zipClose @84
+ zipOpenNewFileInZip2 @86
+ zipCloseFileInZipRaw @87
+ zipOpen2 @88
+ zipOpenNewFileInZip3 @89
+
+ unzGetFilePos @100
+ unzGoToFilePos @101
+
+ fill_win32_filefunc @110
diff --git a/zlib/contrib/vstudio/vc8/zlibvc.sln b/zlib/contrib/vstudio/vc8/zlibvc.sln
new file mode 100644
index 0000000..a815a55
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/zlibvc.sln
@@ -0,0 +1,144 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestZlibDll", "testzlibdll.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Itanium = Debug|Itanium
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Itanium = Release|Itanium
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium
+ ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32
+ ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Itanium
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.Build.0 = Debug|Itanium
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Itanium
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.Build.0 = Release|Itanium
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = ReleaseWithoutAsm|x64
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = ReleaseWithoutAsm|x64
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64
+ {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64
+ {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64
+ {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.Build.0 = Debug|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.Build.0 = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Itanium
+ {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.Build.0 = Debug|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.Build.0 = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Itanium
+ {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|Itanium
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/zlib/contrib/vstudio/vc8/zlibvc.vcproj b/zlib/contrib/vstudio/vc8/zlibvc.vcproj
new file mode 100644
index 0000000..e717011
--- /dev/null
+++ b/zlib/contrib/vstudio/vc8/zlibvc.vcproj
@@ -0,0 +1,1219 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="zlibvc"
+ ProjectGUID="{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ <Platform
+ Name="Itanium"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="x86\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x86\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,_CRT_SECURE_NO_DEPRECATE,ZLIB_WINAPI,ASMV,ASMINF"
+ ExceptionHandling="0"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="false"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj"
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="x64\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x64\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,_CRT_SECURE_NO_DEPRECATE,ZLIB_WINAPI,ASMV,ASMINF;WIN64"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj "
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Itanium"
+ OutputDirectory="ia64\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="ia64\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="2"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;WIN64"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="false"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Win32"
+ OutputDirectory="x86\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x86\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,_CRT_SECURE_NO_DEPRECATE,ZLIB_WINAPI"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|x64"
+ OutputDirectory="x64\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x64\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,_CRT_SECURE_NO_DEPRECATE,ZLIB_WINAPI;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseWithoutAsm|Itanium"
+ OutputDirectory="ia64\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="ia64\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="2"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32,_CRT_SECURE_NO_DEPRECATE,ZLIB_WINAPI;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="x86\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x86\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;ASMV;ASMINF"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="..\..\masmx86\gvmat32.obj ..\..\masmx86\inffas32.obj "
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="x64\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="x64\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;ASMV;ASMINF;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj "
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Itanium"
+ OutputDirectory="ia64\ZlibDll$(ConfigurationName)"
+ IntermediateDirectory="ia64\ZlibDll$(ConfigurationName)\Tmp"
+ ConfigurationType="2"
+ InheritedPropertySheets="UpgradeFromVC70.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="2"
+ TypeLibraryName="$(OutDir)/zlibvc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\..;..\..\masmx86"
+ PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;WIN64"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile="$(IntDir)/zlibvc.pch"
+ AssemblerOutput="2"
+ AssemblerListingLocation="$(IntDir)\"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(OutDir)\"
+ BrowseInformation="0"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1036"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\zlibwapi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateManifest="false"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=".\zlibvc.def"
+ ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/zlibwapi.map"
+ SubSystem="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(OutDir)/zlibwapi.lib"
+ TargetMachine="5"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+ >
+ <File
+ RelativePath="..\..\..\adler32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\crc32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\deflate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\masmx86\gvmat32c.c"
+ >
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\gzio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\infback.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\masmx64\inffas8664.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseWithoutAsm|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\inffast.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inflate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inftrees.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\minizip\ioapi.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\minizip\iowin32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\trees.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\uncompr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\minizip\unzip.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\minizip\zip.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Itanium"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="ZLIB_INTERNAL"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\zlib.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\zlibvc.def"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\zutil.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;fi;fd"
+ >
+ <File
+ RelativePath="..\..\..\deflate.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\infblock.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\infcodes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inffast.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\inftrees.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\infutil.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\zconf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\zlib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\zutil.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/zlib/crc32.c b/zlib/crc32.c
new file mode 100644
index 0000000..f658a9e
--- /dev/null
+++ b/zlib/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case */
+ if (len2 == 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320L; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
diff --git a/zlib/crc32.h b/zlib/crc32.h
new file mode 100644
index 0000000..8053b61
--- /dev/null
+++ b/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/zlib/deflate.c b/zlib/deflate.c
new file mode 100644
index 0000000..29ce1f6
--- /dev/null
+++ b/zlib/deflate.c
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong destLen;
+
+ /* conservative upper bound */
+ destLen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+ /* if can't get parameters, return conservative bound */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return destLen;
+
+ /* if not default parameters, return conservative bound */
+ s = strm->state;
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return destLen;
+
+ /* default settings: return tight bound for that case */
+ return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ /* %%% avoid this when Z_RLE */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifdef FASTEST
+ if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+ (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#else
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#endif
+ /* longest_match() or longest_match_fast() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+ /* longest_match() or longest_match_fast() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt run; /* length of run */
+ uInt max; /* maximum length of run */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan; /* scan for end of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ run = 0;
+ if (s->strstart > 0) { /* if there is a previous byte, that is */
+ max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+ scan = s->window + s->strstart - 1;
+ prev = *scan++;
+ do {
+ if (*scan++ != prev)
+ break;
+ } while (++run < max);
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (run >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, run);
+ _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+ s->lookahead -= run;
+ s->strstart += run;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/zlib/deflate.h b/zlib/deflate.h
new file mode 100644
index 0000000..05a5ab3
--- /dev/null
+++ b/zlib/deflate.h
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/zlib/example.c b/zlib/example.c
new file mode 100644
index 0000000..6c8a0ee
--- /dev/null
+++ b/zlib/example.c
@@ -0,0 +1,565 @@
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-2004 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#if defined(VMS) || defined(RISCOS)
+# define TESTFILE "foo-gz"
+#else
+# define TESTFILE "foo.gz"
+#endif
+
+#define CHECK_ERR(err, msg) { \
+ if (err != Z_OK) { \
+ fprintf(stderr, "%s error: %d\n", msg, err); \
+ exit(1); \
+ } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_gzio OF((const char *fname,
+ Byte *uncompr, uLong uncomprLen));
+void test_deflate OF((Byte *compr, uLong comprLen));
+void test_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_flush OF((Byte *compr, uLong *comprLen));
+void test_sync OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate OF((Byte *compr, uLong comprLen));
+void test_dict_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ err = compress(compr, &comprLen, (const Bytef*)hello, len);
+ CHECK_ERR(err, "compress");
+
+ strcpy((char*)uncompr, "garbage");
+
+ err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+ CHECK_ERR(err, "uncompress");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad uncompress\n");
+ exit(1);
+ } else {
+ printf("uncompress(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(fname, uncompr, uncomprLen)
+ const char *fname; /* compressed file name */
+ Byte *uncompr;
+ uLong uncomprLen;
+{
+#ifdef NO_GZCOMPRESS
+ fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
+#else
+ int err;
+ int len = (int)strlen(hello)+1;
+ gzFile file;
+ z_off_t pos;
+
+ file = gzopen(fname, "wb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ gzputc(file, 'h');
+ if (gzputs(file, "ello") != 4) {
+ fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (gzprintf(file, ", %s!", "hello") != 8) {
+ fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
+ gzclose(file);
+
+ file = gzopen(fname, "rb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ strcpy((char*)uncompr, "garbage");
+
+ if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {
+ fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
+ exit(1);
+ } else {
+ printf("gzread(): %s\n", (char*)uncompr);
+ }
+
+ pos = gzseek(file, -8L, SEEK_CUR);
+ if (pos != 6 || gztell(file) != pos) {
+ fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+ (long)pos, (long)gztell(file));
+ exit(1);
+ }
+
+ if (gzgetc(file) != ' ') {
+ fprintf(stderr, "gzgetc error\n");
+ exit(1);
+ }
+
+ if (gzungetc(' ', file) != ' ') {
+ fprintf(stderr, "gzungetc error\n");
+ exit(1);
+ }
+
+ gzgets(file, (char*)uncompr, (int)uncomprLen);
+ if (strlen((char*)uncompr) != 7) { /* " hello!" */
+ fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello + 6)) {
+ fprintf(stderr, "bad gzgets after gzseek\n");
+ exit(1);
+ } else {
+ printf("gzgets() after gzseek: %s\n", (char*)uncompr);
+ }
+
+ gzclose(file);
+#endif
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+
+ while (c_stream.total_in != len && c_stream.total_out < comprLen) {
+ c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ }
+ /* Finish the stream, still forcing small buffers: */
+ for (;;) {
+ c_stream.avail_out = 1;
+ err = deflate(&c_stream, Z_FINISH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "deflate");
+ }
+
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 0;
+ d_stream.next_out = uncompr;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+ d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate\n");
+ exit(1);
+ } else {
+ printf("inflate(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_SPEED);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ /* At this point, uncompr is still mostly zeroes, so it should compress
+ * very well:
+ */
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ if (c_stream.avail_in != 0) {
+ fprintf(stderr, "deflate not greedy\n");
+ exit(1);
+ }
+
+ /* Feed in already compressed data and switch to no compression: */
+ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+ c_stream.next_in = compr;
+ c_stream.avail_in = (uInt)comprLen/2;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ /* Switch back to compressing mode: */
+ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ for (;;) {
+ d_stream.next_out = uncompr; /* discard the output */
+ d_stream.avail_out = (uInt)uncomprLen;
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "large inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+ fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+ exit(1);
+ } else {
+ printf("large_inflate(): OK\n");
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+ Byte *compr;
+ uLong *comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uInt len = (uInt)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+ c_stream.avail_in = 3;
+ c_stream.avail_out = (uInt)*comprLen;
+ err = deflate(&c_stream, Z_FULL_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ compr[3]++; /* force an error in first compressed block */
+ c_stream.avail_in = len - 3;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ CHECK_ERR(err, "deflate");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+
+ *comprLen = c_stream.total_out;
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 2; /* just read the zlib header */
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ inflate(&d_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "inflate");
+
+ d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
+ err = inflateSync(&d_stream); /* but skip the damaged part */
+ CHECK_ERR(err, "inflateSync");
+
+ err = inflate(&d_stream, Z_FINISH);
+ if (err != Z_DATA_ERROR) {
+ fprintf(stderr, "inflate should report DATA_ERROR\n");
+ /* Because of incorrect adler32 */
+ exit(1);
+ }
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ printf("after inflateSync(): hel%s\n", (char *)uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ err = deflateSetDictionary(&c_stream,
+ (const Bytef*)dictionary, sizeof(dictionary));
+ CHECK_ERR(err, "deflateSetDictionary");
+
+ dictId = c_stream.adler;
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.avail_in = (uInt)strlen(hello)+1;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ for (;;) {
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ if (err == Z_NEED_DICT) {
+ if (d_stream.adler != dictId) {
+ fprintf(stderr, "unexpected dictionary");
+ exit(1);
+ }
+ err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+ sizeof(dictionary));
+ }
+ CHECK_ERR(err, "inflate with dict");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate with dict\n");
+ exit(1);
+ } else {
+ printf("inflate with dictionary: %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Usage: example [output.gz [input.gz]]
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ Byte *compr, *uncompr;
+ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+ uLong uncomprLen = comprLen;
+ static const char* myVersion = ZLIB_VERSION;
+
+ if (zlibVersion()[0] != myVersion[0]) {
+ fprintf(stderr, "incompatible zlib version\n");
+ exit(1);
+
+ } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+ fprintf(stderr, "warning: different zlib version\n");
+ }
+
+ printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
+ ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
+
+ compr = (Byte*)calloc((uInt)comprLen, 1);
+ uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
+ /* compr and uncompr are cleared to avoid reading uninitialized
+ * data and to ensure that uncompr compresses well.
+ */
+ if (compr == Z_NULL || uncompr == Z_NULL) {
+ printf("out of memory\n");
+ exit(1);
+ }
+ test_compress(compr, comprLen, uncompr, uncomprLen);
+
+ test_gzio((argc > 1 ? argv[1] : TESTFILE),
+ uncompr, uncomprLen);
+
+ test_deflate(compr, comprLen);
+ test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+ test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_flush(compr, &comprLen);
+ test_sync(compr, comprLen, uncompr, uncomprLen);
+ comprLen = uncomprLen;
+
+ test_dict_deflate(compr, comprLen);
+ test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ free(compr);
+ free(uncompr);
+
+ return 0;
+}
diff --git a/zlib/examples/README.examples b/zlib/examples/README.examples
new file mode 100644
index 0000000..5632d7a
--- /dev/null
+++ b/zlib/examples/README.examples
@@ -0,0 +1,42 @@
+This directory contains examples of the use of zlib.
+
+fitblk.c
+ compress just enough input to nearly fill a requested output size
+ - zlib isn't designed to do this, but fitblk does it anyway
+
+gun.c
+ uncompress a gzip file
+ - illustrates the use of inflateBack() for high speed file-to-file
+ decompression using call-back functions
+ - is approximately twice as fast as gzip -d
+ - also provides Unix uncompress functionality, again twice as fast
+
+gzappend.c
+ append to a gzip file
+ - illustrates the use of the Z_BLOCK flush parameter for inflate()
+ - illustrates the use of deflatePrime() to start at any bit
+
+gzjoin.c
+ join gzip files without recalculating the crc or recompressing
+ - illustrates the use of the Z_BLOCK flush parameter for inflate()
+ - illustrates the use of crc32_combine()
+
+gzlog.c
+gzlog.h
+ efficiently maintain a message log file in gzip format
+ - illustrates use of raw deflate and Z_SYNC_FLUSH
+ - illustrates use of gzip header extra field
+
+zlib_how.html
+ painfully comprehensive description of zpipe.c (see below)
+ - describes in excruciating detail the use of deflate() and inflate()
+
+zpipe.c
+ reads and writes zlib streams from stdin to stdout
+ - illustrates the proper use of deflate() and inflate()
+ - deeply commented in zlib_how.html (see above)
+
+zran.c
+ index a zlib or gzip stream and randomly access it
+ - illustrates the use of Z_BLOCK, inflatePrime(), and
+ inflateSetDictionary() to provide random access
diff --git a/zlib/examples/fitblk.c b/zlib/examples/fitblk.c
new file mode 100644
index 0000000..c61de5c
--- /dev/null
+++ b/zlib/examples/fitblk.c
@@ -0,0 +1,233 @@
+/* fitblk.c: example of fitting compressed output to a specified size
+ Not copyrighted -- provided to the public domain
+ Version 1.1 25 November 2004 Mark Adler */
+
+/* Version history:
+ 1.0 24 Nov 2004 First version
+ 1.1 25 Nov 2004 Change deflateInit2() to deflateInit()
+ Use fixed-size, stack-allocated raw buffers
+ Simplify code moving compression to subroutines
+ Use assert() for internal errors
+ Add detailed description of approach
+ */
+
+/* Approach to just fitting a requested compressed size:
+
+ fitblk performs three compression passes on a portion of the input
+ data in order to determine how much of that input will compress to
+ nearly the requested output block size. The first pass generates
+ enough deflate blocks to produce output to fill the requested
+ output size plus a specfied excess amount (see the EXCESS define
+ below). The last deflate block may go quite a bit past that, but
+ is discarded. The second pass decompresses and recompresses just
+ the compressed data that fit in the requested plus excess sized
+ buffer. The deflate process is terminated after that amount of
+ input, which is less than the amount consumed on the first pass.
+ The last deflate block of the result will be of a comparable size
+ to the final product, so that the header for that deflate block and
+ the compression ratio for that block will be about the same as in
+ the final product. The third compression pass decompresses the
+ result of the second step, but only the compressed data up to the
+ requested size minus an amount to allow the compressed stream to
+ complete (see the MARGIN define below). That will result in a
+ final compressed stream whose length is less than or equal to the
+ requested size. Assuming sufficient input and a requested size
+ greater than a few hundred bytes, the shortfall will typically be
+ less than ten bytes.
+
+ If the input is short enough that the first compression completes
+ before filling the requested output size, then that compressed
+ stream is return with no recompression.
+
+ EXCESS is chosen to be just greater than the shortfall seen in a
+ two pass approach similar to the above. That shortfall is due to
+ the last deflate block compressing more efficiently with a smaller
+ header on the second pass. EXCESS is set to be large enough so
+ that there is enough uncompressed data for the second pass to fill
+ out the requested size, and small enough so that the final deflate
+ block of the second pass will be close in size to the final deflate
+ block of the third and final pass. MARGIN is chosen to be just
+ large enough to assure that the final compression has enough room
+ to complete in all cases.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "zlib.h"
+
+#define local static
+
+/* print nastygram and leave */
+local void quit(char *why)
+{
+ fprintf(stderr, "fitblk abort: %s\n", why);
+ exit(1);
+}
+
+#define RAWLEN 4096 /* intermediate uncompressed buffer size */
+
+/* compress from file to def until provided buffer is full or end of
+ input reached; return last deflate() return value, or Z_ERRNO if
+ there was read error on the file */
+local int partcompress(FILE *in, z_streamp def)
+{
+ int ret, flush;
+ unsigned char raw[RAWLEN];
+
+ flush = Z_NO_FLUSH;
+ do {
+ def->avail_in = fread(raw, 1, RAWLEN, in);
+ if (ferror(in))
+ return Z_ERRNO;
+ def->next_in = raw;
+ if (feof(in))
+ flush = Z_FINISH;
+ ret = deflate(def, flush);
+ assert(ret != Z_STREAM_ERROR);
+ } while (def->avail_out != 0 && flush == Z_NO_FLUSH);
+ return ret;
+}
+
+/* recompress from inf's input to def's output; the input for inf and
+ the output for def are set in those structures before calling;
+ return last deflate() return value, or Z_MEM_ERROR if inflate()
+ was not able to allocate enough memory when it needed to */
+local int recompress(z_streamp inf, z_streamp def)
+{
+ int ret, flush;
+ unsigned char raw[RAWLEN];
+
+ flush = Z_NO_FLUSH;
+ do {
+ /* decompress */
+ inf->avail_out = RAWLEN;
+ inf->next_out = raw;
+ ret = inflate(inf, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR &&
+ ret != Z_NEED_DICT);
+ if (ret == Z_MEM_ERROR)
+ return ret;
+
+ /* compress what was decompresed until done or no room */
+ def->avail_in = RAWLEN - inf->avail_out;
+ def->next_in = raw;
+ if (inf->avail_out != 0)
+ flush = Z_FINISH;
+ ret = deflate(def, flush);
+ assert(ret != Z_STREAM_ERROR);
+ } while (ret != Z_STREAM_END && def->avail_out != 0);
+ return ret;
+}
+
+#define EXCESS 256 /* empirically determined stream overage */
+#define MARGIN 8 /* amount to back off for completion */
+
+/* compress from stdin to fixed-size block on stdout */
+int main(int argc, char **argv)
+{
+ int ret; /* return code */
+ unsigned size; /* requested fixed output block size */
+ unsigned have; /* bytes written by deflate() call */
+ unsigned char *blk; /* intermediate and final stream */
+ unsigned char *tmp; /* close to desired size stream */
+ z_stream def, inf; /* zlib deflate and inflate states */
+
+ /* get requested output size */
+ if (argc != 2)
+ quit("need one argument: size of output block");
+ ret = strtol(argv[1], argv + 1, 10);
+ if (argv[1][0] != 0)
+ quit("argument must be a number");
+ if (ret < 8) /* 8 is minimum zlib stream size */
+ quit("need positive size of 8 or greater");
+ size = (unsigned)ret;
+
+ /* allocate memory for buffers and compression engine */
+ blk = malloc(size + EXCESS);
+ def.zalloc = Z_NULL;
+ def.zfree = Z_NULL;
+ def.opaque = Z_NULL;
+ ret = deflateInit(&def, Z_DEFAULT_COMPRESSION);
+ if (ret != Z_OK || blk == NULL)
+ quit("out of memory");
+
+ /* compress from stdin until output full, or no more input */
+ def.avail_out = size + EXCESS;
+ def.next_out = blk;
+ ret = partcompress(stdin, &def);
+ if (ret == Z_ERRNO)
+ quit("error reading input");
+
+ /* if it all fit, then size was undersubscribed -- done! */
+ if (ret == Z_STREAM_END && def.avail_out >= EXCESS) {
+ /* write block to stdout */
+ have = size + EXCESS - def.avail_out;
+ if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
+ quit("error writing output");
+
+ /* clean up and print results to stderr */
+ ret = deflateEnd(&def);
+ assert(ret != Z_STREAM_ERROR);
+ free(blk);
+ fprintf(stderr,
+ "%u bytes unused out of %u requested (all input)\n",
+ size - have, size);
+ return 0;
+ }
+
+ /* it didn't all fit -- set up for recompression */
+ inf.zalloc = Z_NULL;
+ inf.zfree = Z_NULL;
+ inf.opaque = Z_NULL;
+ inf.avail_in = 0;
+ inf.next_in = Z_NULL;
+ ret = inflateInit(&inf);
+ tmp = malloc(size + EXCESS);
+ if (ret != Z_OK || tmp == NULL)
+ quit("out of memory");
+ ret = deflateReset(&def);
+ assert(ret != Z_STREAM_ERROR);
+
+ /* do first recompression close to the right amount */
+ inf.avail_in = size + EXCESS;
+ inf.next_in = blk;
+ def.avail_out = size + EXCESS;
+ def.next_out = tmp;
+ ret = recompress(&inf, &def);
+ if (ret == Z_MEM_ERROR)
+ quit("out of memory");
+
+ /* set up for next reocmpression */
+ ret = inflateReset(&inf);
+ assert(ret != Z_STREAM_ERROR);
+ ret = deflateReset(&def);
+ assert(ret != Z_STREAM_ERROR);
+
+ /* do second and final recompression (third compression) */
+ inf.avail_in = size - MARGIN; /* assure stream will complete */
+ inf.next_in = tmp;
+ def.avail_out = size;
+ def.next_out = blk;
+ ret = recompress(&inf, &def);
+ if (ret == Z_MEM_ERROR)
+ quit("out of memory");
+ assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */
+
+ /* done -- write block to stdout */
+ have = size - def.avail_out;
+ if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
+ quit("error writing output");
+
+ /* clean up and print results to stderr */
+ free(tmp);
+ ret = inflateEnd(&inf);
+ assert(ret != Z_STREAM_ERROR);
+ ret = deflateEnd(&def);
+ assert(ret != Z_STREAM_ERROR);
+ free(blk);
+ fprintf(stderr,
+ "%u bytes unused out of %u requested (%lu input)\n",
+ size - have, size, def.total_in);
+ return 0;
+}
diff --git a/zlib/examples/gun.c b/zlib/examples/gun.c
new file mode 100644
index 0000000..bfec590
--- /dev/null
+++ b/zlib/examples/gun.c
@@ -0,0 +1,693 @@
+/* gun.c -- simple gunzip to give an example of the use of inflateBack()
+ * Copyright (C) 2003, 2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ Version 1.3 12 June 2005 Mark Adler */
+
+/* Version history:
+ 1.0 16 Feb 2003 First version for testing of inflateBack()
+ 1.1 21 Feb 2005 Decompress concatenated gzip streams
+ Remove use of "this" variable (C++ keyword)
+ Fix return value for in()
+ Improve allocation failure checking
+ Add typecasting for void * structures
+ Add -h option for command version and usage
+ Add a bunch of comments
+ 1.2 20 Mar 2005 Add Unix compress (LZW) decompression
+ Copy file attributes from input file to output file
+ 1.3 12 Jun 2005 Add casts for error messages [Oberhumer]
+ */
+
+/*
+ gun [ -t ] [ name ... ]
+
+ decompresses the data in the named gzip files. If no arguments are given,
+ gun will decompress from stdin to stdout. The names must end in .gz, -gz,
+ .z, -z, _z, or .Z. The uncompressed data will be written to a file name
+ with the suffix stripped. On success, the original file is deleted. On
+ failure, the output file is deleted. For most failures, the command will
+ continue to process the remaining names on the command line. A memory
+ allocation failure will abort the command. If -t is specified, then the
+ listed files or stdin will be tested as gzip files for integrity (without
+ checking for a proper suffix), no output will be written, and no files
+ will be deleted.
+
+ Like gzip, gun allows concatenated gzip streams and will decompress them,
+ writing all of the uncompressed data to the output. Unlike gzip, gun allows
+ an empty file on input, and will produce no error writing an empty output
+ file.
+
+ gun will also decompress files made by Unix compress, which uses LZW
+ compression. These files are automatically detected by virtue of their
+ magic header bytes. Since the end of Unix compress stream is marked by the
+ end-of-file, they cannot be concantenated. If a Unix compress stream is
+ encountered in an input file, it is the last stream in that file.
+
+ Like gunzip and uncompress, the file attributes of the orignal compressed
+ file are maintained in the final uncompressed file, to the extent that the
+ user permissions allow it.
+
+ On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
+ 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the
+ LZW decompression provided by gun is about twice as fast as the standard
+ Unix uncompress command.
+ */
+
+/* external functions and related types and constants */
+#include <stdio.h> /* fprintf() */
+#include <stdlib.h> /* malloc(), free() */
+#include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
+#include <errno.h> /* errno */
+#include <fcntl.h> /* open() */
+#include <unistd.h> /* read(), write(), close(), chown(), unlink() */
+#include <sys/types.h>
+#include <sys/stat.h> /* stat(), chmod() */
+#include <utime.h> /* utime() */
+#include "zlib.h" /* inflateBackInit(), inflateBack(), */
+ /* inflateBackEnd(), crc32() */
+
+/* function declaration */
+#define local static
+
+/* buffer constants */
+#define SIZE 32768U /* input and output buffer sizes */
+#define PIECE 16384 /* limits i/o chunks for 16-bit int case */
+
+/* structure for infback() to pass to input function in() -- it maintains the
+ input file and a buffer of size SIZE */
+struct ind {
+ int infile;
+ unsigned char *inbuf;
+};
+
+/* Load input buffer, assumed to be empty, and return bytes loaded and a
+ pointer to them. read() is called until the buffer is full, or until it
+ returns end-of-file or error. Return 0 on error. */
+local unsigned in(void *in_desc, unsigned char **buf)
+{
+ int ret;
+ unsigned len;
+ unsigned char *next;
+ struct ind *me = (struct ind *)in_desc;
+
+ next = me->inbuf;
+ *buf = next;
+ len = 0;
+ do {
+ ret = PIECE;
+ if ((unsigned)ret > SIZE - len)
+ ret = (int)(SIZE - len);
+ ret = (int)read(me->infile, next, ret);
+ if (ret == -1) {
+ len = 0;
+ break;
+ }
+ next += ret;
+ len += ret;
+ } while (ret != 0 && len < SIZE);
+ return len;
+}
+
+/* structure for infback() to pass to output function out() -- it maintains the
+ output file, a running CRC-32 check on the output and the total number of
+ bytes output, both for checking against the gzip trailer. (The length in
+ the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
+ the output is greater than 4 GB.) */
+struct outd {
+ int outfile;
+ int check; /* true if checking crc and total */
+ unsigned long crc;
+ unsigned long total;
+};
+
+/* Write output buffer and update the CRC-32 and total bytes written. write()
+ is called until all of the output is written or an error is encountered.
+ On success out() returns 0. For a write failure, out() returns 1. If the
+ output file descriptor is -1, then nothing is written.
+ */
+local int out(void *out_desc, unsigned char *buf, unsigned len)
+{
+ int ret;
+ struct outd *me = (struct outd *)out_desc;
+
+ if (me->check) {
+ me->crc = crc32(me->crc, buf, len);
+ me->total += len;
+ }
+ if (me->outfile != -1)
+ do {
+ ret = PIECE;
+ if ((unsigned)ret > len)
+ ret = (int)len;
+ ret = (int)write(me->outfile, buf, ret);
+ if (ret == -1)
+ return 1;
+ buf += ret;
+ len -= ret;
+ } while (len != 0);
+ return 0;
+}
+
+/* next input byte macro for use inside lunpipe() and gunpipe() */
+#define NEXT() (have ? 0 : (have = in(indp, &next)), \
+ last = have ? (have--, (int)(*next++)) : -1)
+
+/* memory for gunpipe() and lunpipe() --
+ the first 256 entries of prefix[] and suffix[] are never used, could
+ have offset the index, but it's faster to waste the memory */
+unsigned char inbuf[SIZE]; /* input buffer */
+unsigned char outbuf[SIZE]; /* output buffer */
+unsigned short prefix[65536]; /* index to LZW prefix string */
+unsigned char suffix[65536]; /* one-character LZW suffix */
+unsigned char match[65280 + 2]; /* buffer for reversed match or gzip
+ 32K sliding window */
+
+/* throw out what's left in the current bits byte buffer (this is a vestigial
+ aspect of the compressed data format derived from an implementation that
+ made use of a special VAX machine instruction!) */
+#define FLUSHCODE() \
+ do { \
+ left = 0; \
+ rem = 0; \
+ if (chunk > have) { \
+ chunk -= have; \
+ have = 0; \
+ if (NEXT() == -1) \
+ break; \
+ chunk--; \
+ if (chunk > have) { \
+ chunk = have = 0; \
+ break; \
+ } \
+ } \
+ have -= chunk; \
+ next += chunk; \
+ chunk = 0; \
+ } while (0)
+
+/* Decompress a compress (LZW) file from indp to outfile. The compress magic
+ header (two bytes) has already been read and verified. There are have bytes
+ of buffered input at next. strm is used for passing error information back
+ to gunpipe().
+
+ lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
+ file, read error, or write error (a write error indicated by strm->next_in
+ not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
+ */
+local int lunpipe(unsigned have, unsigned char *next, struct ind *indp,
+ int outfile, z_stream *strm)
+{
+ int last; /* last byte read by NEXT(), or -1 if EOF */
+ int chunk; /* bytes left in current chunk */
+ int left; /* bits left in rem */
+ unsigned rem; /* unused bits from input */
+ int bits; /* current bits per code */
+ unsigned code; /* code, table traversal index */
+ unsigned mask; /* mask for current bits codes */
+ int max; /* maximum bits per code for this stream */
+ int flags; /* compress flags, then block compress flag */
+ unsigned end; /* last valid entry in prefix/suffix tables */
+ unsigned temp; /* current code */
+ unsigned prev; /* previous code */
+ unsigned final; /* last character written for previous code */
+ unsigned stack; /* next position for reversed string */
+ unsigned outcnt; /* bytes in output buffer */
+ struct outd outd; /* output structure */
+
+ /* set up output */
+ outd.outfile = outfile;
+ outd.check = 0;
+
+ /* process remainder of compress header -- a flags byte */
+ flags = NEXT();
+ if (last == -1)
+ return Z_BUF_ERROR;
+ if (flags & 0x60) {
+ strm->msg = (char *)"unknown lzw flags set";
+ return Z_DATA_ERROR;
+ }
+ max = flags & 0x1f;
+ if (max < 9 || max > 16) {
+ strm->msg = (char *)"lzw bits out of range";
+ return Z_DATA_ERROR;
+ }
+ if (max == 9) /* 9 doesn't really mean 9 */
+ max = 10;
+ flags &= 0x80; /* true if block compress */
+
+ /* clear table */
+ bits = 9;
+ mask = 0x1ff;
+ end = flags ? 256 : 255;
+
+ /* set up: get first 9-bit code, which is the first decompressed byte, but
+ don't create a table entry until the next code */
+ if (NEXT() == -1) /* no compressed data is ok */
+ return Z_OK;
+ final = prev = (unsigned)last; /* low 8 bits of code */
+ if (NEXT() == -1) /* missing a bit */
+ return Z_BUF_ERROR;
+ if (last & 1) { /* code must be < 256 */
+ strm->msg = (char *)"invalid lzw code";
+ return Z_DATA_ERROR;
+ }
+ rem = (unsigned)last >> 1; /* remaining 7 bits */
+ left = 7;
+ chunk = bits - 2; /* 7 bytes left in this chunk */
+ outbuf[0] = (unsigned char)final; /* write first decompressed byte */
+ outcnt = 1;
+
+ /* decode codes */
+ stack = 0;
+ for (;;) {
+ /* if the table will be full after this, increment the code size */
+ if (end >= mask && bits < max) {
+ FLUSHCODE();
+ bits++;
+ mask <<= 1;
+ mask++;
+ }
+
+ /* get a code of length bits */
+ if (chunk == 0) /* decrement chunk modulo bits */
+ chunk = bits;
+ code = rem; /* low bits of code */
+ if (NEXT() == -1) { /* EOF is end of compressed data */
+ /* write remaining buffered output */
+ if (outcnt && out(&outd, outbuf, outcnt)) {
+ strm->next_in = outbuf; /* signal write error */
+ return Z_BUF_ERROR;
+ }
+ return Z_OK;
+ }
+ code += (unsigned)last << left; /* middle (or high) bits of code */
+ left += 8;
+ chunk--;
+ if (bits > left) { /* need more bits */
+ if (NEXT() == -1) /* can't end in middle of code */
+ return Z_BUF_ERROR;
+ code += (unsigned)last << left; /* high bits of code */
+ left += 8;
+ chunk--;
+ }
+ code &= mask; /* mask to current code length */
+ left -= bits; /* number of unused bits */
+ rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
+
+ /* process clear code (256) */
+ if (code == 256 && flags) {
+ FLUSHCODE();
+ bits = 9; /* initialize bits and mask */
+ mask = 0x1ff;
+ end = 255; /* empty table */
+ continue; /* get next code */
+ }
+
+ /* special code to reuse last match */
+ temp = code; /* save the current code */
+ if (code > end) {
+ /* Be picky on the allowed code here, and make sure that the code
+ we drop through (prev) will be a valid index so that random
+ input does not cause an exception. The code != end + 1 check is
+ empirically derived, and not checked in the original uncompress
+ code. If this ever causes a problem, that check could be safely
+ removed. Leaving this check in greatly improves gun's ability
+ to detect random or corrupted input after a compress header.
+ In any case, the prev > end check must be retained. */
+ if (code != end + 1 || prev > end) {
+ strm->msg = (char *)"invalid lzw code";
+ return Z_DATA_ERROR;
+ }
+ match[stack++] = (unsigned char)final;
+ code = prev;
+ }
+
+ /* walk through linked list to generate output in reverse order */
+ while (code >= 256) {
+ match[stack++] = suffix[code];
+ code = prefix[code];
+ }
+ match[stack++] = (unsigned char)code;
+ final = code;
+
+ /* link new table entry */
+ if (end < mask) {
+ end++;
+ prefix[end] = (unsigned short)prev;
+ suffix[end] = (unsigned char)final;
+ }
+
+ /* set previous code for next iteration */
+ prev = temp;
+
+ /* write output in forward order */
+ while (stack > SIZE - outcnt) {
+ while (outcnt < SIZE)
+ outbuf[outcnt++] = match[--stack];
+ if (out(&outd, outbuf, outcnt)) {
+ strm->next_in = outbuf; /* signal write error */
+ return Z_BUF_ERROR;
+ }
+ outcnt = 0;
+ }
+ do {
+ outbuf[outcnt++] = match[--stack];
+ } while (stack);
+
+ /* loop for next code with final and prev as the last match, rem and
+ left provide the first 0..7 bits of the next code, end is the last
+ valid table entry */
+ }
+}
+
+/* Decompress a gzip file from infile to outfile. strm is assumed to have been
+ successfully initialized with inflateBackInit(). The input file may consist
+ of a series of gzip streams, in which case all of them will be decompressed
+ to the output file. If outfile is -1, then the gzip stream(s) integrity is
+ checked and nothing is written.
+
+ The return value is a zlib error code: Z_MEM_ERROR if out of memory,
+ Z_DATA_ERROR if the header or the compressed data is invalid, or if the
+ trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
+ prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
+ stream) follows a valid gzip stream.
+ */
+local int gunpipe(z_stream *strm, int infile, int outfile)
+{
+ int ret, first, last;
+ unsigned have, flags, len;
+ unsigned char *next;
+ struct ind ind, *indp;
+ struct outd outd;
+
+ /* setup input buffer */
+ ind.infile = infile;
+ ind.inbuf = inbuf;
+ indp = &ind;
+
+ /* decompress concatenated gzip streams */
+ have = 0; /* no input data read in yet */
+ first = 1; /* looking for first gzip header */
+ strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
+ for (;;) {
+ /* look for the two magic header bytes for a gzip stream */
+ if (NEXT() == -1) {
+ ret = Z_OK;
+ break; /* empty gzip stream is ok */
+ }
+ if (last != 31 || (NEXT() != 139 && last != 157)) {
+ strm->msg = (char *)"incorrect header check";
+ ret = first ? Z_DATA_ERROR : Z_ERRNO;
+ break; /* not a gzip or compress header */
+ }
+ first = 0; /* next non-header is junk */
+
+ /* process a compress (LZW) file -- can't be concatenated after this */
+ if (last == 157) {
+ ret = lunpipe(have, next, indp, outfile, strm);
+ break;
+ }
+
+ /* process remainder of gzip header */
+ ret = Z_BUF_ERROR;
+ if (NEXT() != 8) { /* only deflate method allowed */
+ if (last == -1) break;
+ strm->msg = (char *)"unknown compression method";
+ ret = Z_DATA_ERROR;
+ break;
+ }
+ flags = NEXT(); /* header flags */
+ NEXT(); /* discard mod time, xflgs, os */
+ NEXT();
+ NEXT();
+ NEXT();
+ NEXT();
+ NEXT();
+ if (last == -1) break;
+ if (flags & 0xe0) {
+ strm->msg = (char *)"unknown header flags set";
+ ret = Z_DATA_ERROR;
+ break;
+ }
+ if (flags & 4) { /* extra field */
+ len = NEXT();
+ len += (unsigned)(NEXT()) << 8;
+ if (last == -1) break;
+ while (len > have) {
+ len -= have;
+ have = 0;
+ if (NEXT() == -1) break;
+ len--;
+ }
+ if (last == -1) break;
+ have -= len;
+ next += len;
+ }
+ if (flags & 8) /* file name */
+ while (NEXT() != 0 && last != -1)
+ ;
+ if (flags & 16) /* comment */
+ while (NEXT() != 0 && last != -1)
+ ;
+ if (flags & 2) { /* header crc */
+ NEXT();
+ NEXT();
+ }
+ if (last == -1) break;
+
+ /* set up output */
+ outd.outfile = outfile;
+ outd.check = 1;
+ outd.crc = crc32(0L, Z_NULL, 0);
+ outd.total = 0;
+
+ /* decompress data to output */
+ strm->next_in = next;
+ strm->avail_in = have;
+ ret = inflateBack(strm, in, indp, out, &outd);
+ if (ret != Z_STREAM_END) break;
+ next = strm->next_in;
+ have = strm->avail_in;
+ strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
+
+ /* check trailer */
+ ret = Z_BUF_ERROR;
+ if (NEXT() != (outd.crc & 0xff) ||
+ NEXT() != ((outd.crc >> 8) & 0xff) ||
+ NEXT() != ((outd.crc >> 16) & 0xff) ||
+ NEXT() != ((outd.crc >> 24) & 0xff)) {
+ /* crc error */
+ if (last != -1) {
+ strm->msg = (char *)"incorrect data check";
+ ret = Z_DATA_ERROR;
+ }
+ break;
+ }
+ if (NEXT() != (outd.total & 0xff) ||
+ NEXT() != ((outd.total >> 8) & 0xff) ||
+ NEXT() != ((outd.total >> 16) & 0xff) ||
+ NEXT() != ((outd.total >> 24) & 0xff)) {
+ /* length error */
+ if (last != -1) {
+ strm->msg = (char *)"incorrect length check";
+ ret = Z_DATA_ERROR;
+ }
+ break;
+ }
+
+ /* go back and look for another gzip stream */
+ }
+
+ /* clean up and return */
+ return ret;
+}
+
+/* Copy file attributes, from -> to, as best we can. This is best effort, so
+ no errors are reported. The mode bits, including suid, sgid, and the sticky
+ bit are copied (if allowed), the owner's user id and group id are copied
+ (again if allowed), and the access and modify times are copied. */
+local void copymeta(char *from, char *to)
+{
+ struct stat was;
+ struct utimbuf when;
+
+ /* get all of from's Unix meta data, return if not a regular file */
+ if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
+ return;
+
+ /* set to's mode bits, ignore errors */
+ (void)chmod(to, was.st_mode & 07777);
+
+ /* copy owner's user and group, ignore errors */
+ (void)chown(to, was.st_uid, was.st_gid);
+
+ /* copy access and modify times, ignore errors */
+ when.actime = was.st_atime;
+ when.modtime = was.st_mtime;
+ (void)utime(to, &when);
+}
+
+/* Decompress the file inname to the file outnname, of if test is true, just
+ decompress without writing and check the gzip trailer for integrity. If
+ inname is NULL or an empty string, read from stdin. If outname is NULL or
+ an empty string, write to stdout. strm is a pre-initialized inflateBack
+ structure. When appropriate, copy the file attributes from inname to
+ outname.
+
+ gunzip() returns 1 if there is an out-of-memory error or an unexpected
+ return code from gunpipe(). Otherwise it returns 0.
+ */
+local int gunzip(z_stream *strm, char *inname, char *outname, int test)
+{
+ int ret;
+ int infile, outfile;
+
+ /* open files */
+ if (inname == NULL || *inname == 0) {
+ inname = "-";
+ infile = 0; /* stdin */
+ }
+ else {
+ infile = open(inname, O_RDONLY, 0);
+ if (infile == -1) {
+ fprintf(stderr, "gun cannot open %s\n", inname);
+ return 0;
+ }
+ }
+ if (test)
+ outfile = -1;
+ else if (outname == NULL || *outname == 0) {
+ outname = "-";
+ outfile = 1; /* stdout */
+ }
+ else {
+ outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
+ if (outfile == -1) {
+ close(infile);
+ fprintf(stderr, "gun cannot create %s\n", outname);
+ return 0;
+ }
+ }
+ errno = 0;
+
+ /* decompress */
+ ret = gunpipe(strm, infile, outfile);
+ if (outfile > 2) close(outfile);
+ if (infile > 2) close(infile);
+
+ /* interpret result */
+ switch (ret) {
+ case Z_OK:
+ case Z_ERRNO:
+ if (infile > 2 && outfile > 2) {
+ copymeta(inname, outname); /* copy attributes */
+ unlink(inname);
+ }
+ if (ret == Z_ERRNO)
+ fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
+ inname);
+ break;
+ case Z_DATA_ERROR:
+ if (outfile > 2) unlink(outname);
+ fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
+ break;
+ case Z_MEM_ERROR:
+ if (outfile > 2) unlink(outname);
+ fprintf(stderr, "gun out of memory error--aborting\n");
+ return 1;
+ case Z_BUF_ERROR:
+ if (outfile > 2) unlink(outname);
+ if (strm->next_in != Z_NULL) {
+ fprintf(stderr, "gun write error on %s: %s\n",
+ outname, strerror(errno));
+ }
+ else if (errno) {
+ fprintf(stderr, "gun read error on %s: %s\n",
+ inname, strerror(errno));
+ }
+ else {
+ fprintf(stderr, "gun unexpected end of file on %s\n",
+ inname);
+ }
+ break;
+ default:
+ if (outfile > 2) unlink(outname);
+ fprintf(stderr, "gun internal error--aborting\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* Process the gun command line arguments. See the command syntax near the
+ beginning of this source file. */
+int main(int argc, char **argv)
+{
+ int ret, len, test;
+ char *outname;
+ unsigned char *window;
+ z_stream strm;
+
+ /* initialize inflateBack state for repeated use */
+ window = match; /* reuse LZW match buffer */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ ret = inflateBackInit(&strm, 15, window);
+ if (ret != Z_OK) {
+ fprintf(stderr, "gun out of memory error--aborting\n");
+ return 1;
+ }
+
+ /* decompress each file to the same name with the suffix removed */
+ argc--;
+ argv++;
+ test = 0;
+ if (argc && strcmp(*argv, "-h") == 0) {
+ fprintf(stderr, "gun 1.3 (12 Jun 2005)\n");
+ fprintf(stderr, "Copyright (c) 2005 Mark Adler\n");
+ fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
+ return 0;
+ }
+ if (argc && strcmp(*argv, "-t") == 0) {
+ test = 1;
+ argc--;
+ argv++;
+ }
+ if (argc)
+ do {
+ if (test)
+ outname = NULL;
+ else {
+ len = (int)strlen(*argv);
+ if (strcmp(*argv + len - 3, ".gz") == 0 ||
+ strcmp(*argv + len - 3, "-gz") == 0)
+ len -= 3;
+ else if (strcmp(*argv + len - 2, ".z") == 0 ||
+ strcmp(*argv + len - 2, "-z") == 0 ||
+ strcmp(*argv + len - 2, "_z") == 0 ||
+ strcmp(*argv + len - 2, ".Z") == 0)
+ len -= 2;
+ else {
+ fprintf(stderr, "gun error: no gz type on %s--skipping\n",
+ *argv);
+ continue;
+ }
+ outname = malloc(len + 1);
+ if (outname == NULL) {
+ fprintf(stderr, "gun out of memory error--aborting\n");
+ ret = 1;
+ break;
+ }
+ memcpy(outname, *argv, len);
+ outname[len] = 0;
+ }
+ ret = gunzip(&strm, *argv, outname, test);
+ if (outname != NULL) free(outname);
+ if (ret) break;
+ } while (argv++, --argc);
+ else
+ ret = gunzip(&strm, NULL, NULL, test);
+
+ /* clean up */
+ inflateBackEnd(&strm);
+ return ret;
+}
diff --git a/zlib/examples/gzappend.c b/zlib/examples/gzappend.c
new file mode 100644
index 0000000..e9e878e
--- /dev/null
+++ b/zlib/examples/gzappend.c
@@ -0,0 +1,500 @@
+/* gzappend -- command to append to a gzip file
+
+ Copyright (C) 2003 Mark Adler, all rights reserved
+ version 1.1, 4 Nov 2003
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0 19 Oct 2003 - First version
+ * 1.1 4 Nov 2003 - Expand and clarify some comments and notes
+ * - Add version and copyright to help
+ * - Send help to stdout instead of stderr
+ * - Add some preemptive typecasts
+ * - Add L to constants in lseek() calls
+ * - Remove some debugging information in error messages
+ * - Use new data_type definition for zlib 1.2.1
+ * - Simplfy and unify file operations
+ * - Finish off gzip file in gztack()
+ * - Use deflatePrime() instead of adding empty blocks
+ * - Keep gzip file clean on appended file read errors
+ * - Use in-place rotate instead of auxiliary buffer
+ * (Why you ask? Because it was fun to write!)
+ */
+
+/*
+ gzappend takes a gzip file and appends to it, compressing files from the
+ command line or data from stdin. The gzip file is written to directly, to
+ avoid copying that file, in case it's large. Note that this results in the
+ unfriendly behavior that if gzappend fails, the gzip file is corrupted.
+
+ This program was written to illustrate the use of the new Z_BLOCK option of
+ zlib 1.2.x's inflate() function. This option returns from inflate() at each
+ block boundary to facilitate locating and modifying the last block bit at
+ the start of the final deflate block. Also whether using Z_BLOCK or not,
+ another required feature of zlib 1.2.x is that inflate() now provides the
+ number of unusued bits in the last input byte used. gzappend will not work
+ with versions of zlib earlier than 1.2.1.
+
+ gzappend first decompresses the gzip file internally, discarding all but
+ the last 32K of uncompressed data, and noting the location of the last block
+ bit and the number of unused bits in the last byte of the compressed data.
+ The gzip trailer containing the CRC-32 and length of the uncompressed data
+ is verified. This trailer will be later overwritten.
+
+ Then the last block bit is cleared by seeking back in the file and rewriting
+ the byte that contains it. Seeking forward, the last byte of the compressed
+ data is saved along with the number of unused bits to initialize deflate.
+
+ A deflate process is initialized, using the last 32K of the uncompressed
+ data from the gzip file to initialize the dictionary. If the total
+ uncompressed data was less than 32K, then all of it is used to initialize
+ the dictionary. The deflate output bit buffer is also initialized with the
+ last bits from the original deflate stream. From here on, the data to
+ append is simply compressed using deflate, and written to the gzip file.
+ When that is complete, the new CRC-32 and uncompressed length are written
+ as the trailer of the gzip file.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "zlib.h"
+
+#define local static
+#define LGCHUNK 14
+#define CHUNK (1U << LGCHUNK)
+#define DSIZE 32768U
+
+/* print an error message and terminate with extreme prejudice */
+local void bye(char *msg1, char *msg2)
+{
+ fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2);
+ exit(1);
+}
+
+/* return the greatest common divisor of a and b using Euclid's algorithm,
+ modified to be fast when one argument much greater than the other, and
+ coded to avoid unnecessary swapping */
+local unsigned gcd(unsigned a, unsigned b)
+{
+ unsigned c;
+
+ while (a && b)
+ if (a > b) {
+ c = b;
+ while (a - c >= c)
+ c <<= 1;
+ a -= c;
+ }
+ else {
+ c = a;
+ while (b - c >= c)
+ c <<= 1;
+ b -= c;
+ }
+ return a + b;
+}
+
+/* rotate list[0..len-1] left by rot positions, in place */
+local void rotate(unsigned char *list, unsigned len, unsigned rot)
+{
+ unsigned char tmp;
+ unsigned cycles;
+ unsigned char *start, *last, *to, *from;
+
+ /* normalize rot and handle degenerate cases */
+ if (len < 2) return;
+ if (rot >= len) rot %= len;
+ if (rot == 0) return;
+
+ /* pointer to last entry in list */
+ last = list + (len - 1);
+
+ /* do simple left shift by one */
+ if (rot == 1) {
+ tmp = *list;
+ memcpy(list, list + 1, len - 1);
+ *last = tmp;
+ return;
+ }
+
+ /* do simple right shift by one */
+ if (rot == len - 1) {
+ tmp = *last;
+ memmove(list + 1, list, len - 1);
+ *list = tmp;
+ return;
+ }
+
+ /* otherwise do rotate as a set of cycles in place */
+ cycles = gcd(len, rot); /* number of cycles */
+ do {
+ start = from = list + cycles; /* start index is arbitrary */
+ tmp = *from; /* save entry to be overwritten */
+ for (;;) {
+ to = from; /* next step in cycle */
+ from += rot; /* go right rot positions */
+ if (from > last) from -= len; /* (pointer better not wrap) */
+ if (from == start) break; /* all but one shifted */
+ *to = *from; /* shift left */
+ }
+ *to = tmp; /* complete the circle */
+ } while (--cycles);
+}
+
+/* structure for gzip file read operations */
+typedef struct {
+ int fd; /* file descriptor */
+ int size; /* 1 << size is bytes in buf */
+ unsigned left; /* bytes available at next */
+ unsigned char *buf; /* buffer */
+ unsigned char *next; /* next byte in buffer */
+ char *name; /* file name for error messages */
+} file;
+
+/* reload buffer */
+local int readin(file *in)
+{
+ int len;
+
+ len = read(in->fd, in->buf, 1 << in->size);
+ if (len == -1) bye("error reading ", in->name);
+ in->left = (unsigned)len;
+ in->next = in->buf;
+ return len;
+}
+
+/* read from file in, exit if end-of-file */
+local int readmore(file *in)
+{
+ if (readin(in) == 0) bye("unexpected end of ", in->name);
+ return 0;
+}
+
+#define read1(in) (in->left == 0 ? readmore(in) : 0, \
+ in->left--, *(in->next)++)
+
+/* skip over n bytes of in */
+local void skip(file *in, unsigned n)
+{
+ unsigned bypass;
+
+ if (n > in->left) {
+ n -= in->left;
+ bypass = n & ~((1U << in->size) - 1);
+ if (bypass) {
+ if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1)
+ bye("seeking ", in->name);
+ n -= bypass;
+ }
+ readmore(in);
+ if (n > in->left)
+ bye("unexpected end of ", in->name);
+ }
+ in->left -= n;
+ in->next += n;
+}
+
+/* read a four-byte unsigned integer, little-endian, from in */
+unsigned long read4(file *in)
+{
+ unsigned long val;
+
+ val = read1(in);
+ val += (unsigned)read1(in) << 8;
+ val += (unsigned long)read1(in) << 16;
+ val += (unsigned long)read1(in) << 24;
+ return val;
+}
+
+/* skip over gzip header */
+local void gzheader(file *in)
+{
+ int flags;
+ unsigned n;
+
+ if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file");
+ if (read1(in) != 8) bye("unknown compression method in", in->name);
+ flags = read1(in);
+ if (flags & 0xe0) bye("unknown header flags set in", in->name);
+ skip(in, 6);
+ if (flags & 4) {
+ n = read1(in);
+ n += (unsigned)(read1(in)) << 8;
+ skip(in, n);
+ }
+ if (flags & 8) while (read1(in) != 0) ;
+ if (flags & 16) while (read1(in) != 0) ;
+ if (flags & 2) skip(in, 2);
+}
+
+/* decompress gzip file "name", return strm with a deflate stream ready to
+ continue compression of the data in the gzip file, and return a file
+ descriptor pointing to where to write the compressed data -- the deflate
+ stream is initialized to compress using level "level" */
+local int gzscan(char *name, z_stream *strm, int level)
+{
+ int ret, lastbit, left, full;
+ unsigned have;
+ unsigned long crc, tot;
+ unsigned char *window;
+ off_t lastoff, end;
+ file gz;
+
+ /* open gzip file */
+ gz.name = name;
+ gz.fd = open(name, O_RDWR, 0);
+ if (gz.fd == -1) bye("cannot open ", name);
+ gz.buf = malloc(CHUNK);
+ if (gz.buf == NULL) bye("out of memory", "");
+ gz.size = LGCHUNK;
+ gz.left = 0;
+
+ /* skip gzip header */
+ gzheader(&gz);
+
+ /* prepare to decompress */
+ window = malloc(DSIZE);
+ if (window == NULL) bye("out of memory", "");
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ ret = inflateInit2(strm, -15);
+ if (ret != Z_OK) bye("out of memory", " or library mismatch");
+
+ /* decompress the deflate stream, saving append information */
+ lastbit = 0;
+ lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left;
+ left = 0;
+ strm->avail_in = gz.left;
+ strm->next_in = gz.next;
+ crc = crc32(0L, Z_NULL, 0);
+ have = full = 0;
+ do {
+ /* if needed, get more input */
+ if (strm->avail_in == 0) {
+ readmore(&gz);
+ strm->avail_in = gz.left;
+ strm->next_in = gz.next;
+ }
+
+ /* set up output to next available section of sliding window */
+ strm->avail_out = DSIZE - have;
+ strm->next_out = window + have;
+
+ /* inflate and check for errors */
+ ret = inflate(strm, Z_BLOCK);
+ if (ret == Z_STREAM_ERROR) bye("internal stream error!", "");
+ if (ret == Z_MEM_ERROR) bye("out of memory", "");
+ if (ret == Z_DATA_ERROR)
+ bye("invalid compressed data--format violated in", name);
+
+ /* update crc and sliding window pointer */
+ crc = crc32(crc, window + have, DSIZE - have - strm->avail_out);
+ if (strm->avail_out)
+ have = DSIZE - strm->avail_out;
+ else {
+ have = 0;
+ full = 1;
+ }
+
+ /* process end of block */
+ if (strm->data_type & 128) {
+ if (strm->data_type & 64)
+ left = strm->data_type & 0x1f;
+ else {
+ lastbit = strm->data_type & 0x1f;
+ lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in;
+ }
+ }
+ } while (ret != Z_STREAM_END);
+ inflateEnd(strm);
+ gz.left = strm->avail_in;
+ gz.next = strm->next_in;
+
+ /* save the location of the end of the compressed data */
+ end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left;
+
+ /* check gzip trailer and save total for deflate */
+ if (crc != read4(&gz))
+ bye("invalid compressed data--crc mismatch in ", name);
+ tot = strm->total_out;
+ if ((tot & 0xffffffffUL) != read4(&gz))
+ bye("invalid compressed data--length mismatch in", name);
+
+ /* if not at end of file, warn */
+ if (gz.left || readin(&gz))
+ fprintf(stderr,
+ "gzappend warning: junk at end of gzip file overwritten\n");
+
+ /* clear last block bit */
+ lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET);
+ if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name);
+ *gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7)));
+ lseek(gz.fd, -1L, SEEK_CUR);
+ if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name);
+
+ /* if window wrapped, build dictionary from window by rotating */
+ if (full) {
+ rotate(window, DSIZE, have);
+ have = DSIZE;
+ }
+
+ /* set up deflate stream with window, crc, total_in, and leftover bits */
+ ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+ if (ret != Z_OK) bye("out of memory", "");
+ deflateSetDictionary(strm, window, have);
+ strm->adler = crc;
+ strm->total_in = tot;
+ if (left) {
+ lseek(gz.fd, --end, SEEK_SET);
+ if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name);
+ deflatePrime(strm, 8 - left, *gz.buf);
+ }
+ lseek(gz.fd, end, SEEK_SET);
+
+ /* clean up and return */
+ free(window);
+ free(gz.buf);
+ return gz.fd;
+}
+
+/* append file "name" to gzip file gd using deflate stream strm -- if last
+ is true, then finish off the deflate stream at the end */
+local void gztack(char *name, int gd, z_stream *strm, int last)
+{
+ int fd, len, ret;
+ unsigned left;
+ unsigned char *in, *out;
+
+ /* open file to compress and append */
+ fd = 0;
+ if (name != NULL) {
+ fd = open(name, O_RDONLY, 0);
+ if (fd == -1)
+ fprintf(stderr, "gzappend warning: %s not found, skipping ...\n",
+ name);
+ }
+
+ /* allocate buffers */
+ in = fd == -1 ? NULL : malloc(CHUNK);
+ out = malloc(CHUNK);
+ if (out == NULL) bye("out of memory", "");
+
+ /* compress input file and append to gzip file */
+ do {
+ /* get more input */
+ len = fd == -1 ? 0 : read(fd, in, CHUNK);
+ if (len == -1) {
+ fprintf(stderr,
+ "gzappend warning: error reading %s, skipping rest ...\n",
+ name);
+ len = 0;
+ }
+ strm->avail_in = (unsigned)len;
+ strm->next_in = in;
+ if (len) strm->adler = crc32(strm->adler, in, (unsigned)len);
+
+ /* compress and write all available output */
+ do {
+ strm->avail_out = CHUNK;
+ strm->next_out = out;
+ ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH);
+ left = CHUNK - strm->avail_out;
+ while (left) {
+ len = write(gd, out + CHUNK - strm->avail_out - left, left);
+ if (len == -1) bye("writing gzip file", "");
+ left -= (unsigned)len;
+ }
+ } while (strm->avail_out == 0 && ret != Z_STREAM_END);
+ } while (len != 0);
+
+ /* write trailer after last entry */
+ if (last) {
+ deflateEnd(strm);
+ out[0] = (unsigned char)(strm->adler);
+ out[1] = (unsigned char)(strm->adler >> 8);
+ out[2] = (unsigned char)(strm->adler >> 16);
+ out[3] = (unsigned char)(strm->adler >> 24);
+ out[4] = (unsigned char)(strm->total_in);
+ out[5] = (unsigned char)(strm->total_in >> 8);
+ out[6] = (unsigned char)(strm->total_in >> 16);
+ out[7] = (unsigned char)(strm->total_in >> 24);
+ len = 8;
+ do {
+ ret = write(gd, out + 8 - len, len);
+ if (ret == -1) bye("writing gzip file", "");
+ len -= ret;
+ } while (len);
+ close(gd);
+ }
+
+ /* clean up and return */
+ free(out);
+ if (in != NULL) free(in);
+ if (fd > 0) close(fd);
+}
+
+/* process the compression level option if present, scan the gzip file, and
+ append the specified files, or append the data from stdin if no other file
+ names are provided on the command line -- the gzip file must be writable
+ and seekable */
+int main(int argc, char **argv)
+{
+ int gd, level;
+ z_stream strm;
+
+ /* ignore command name */
+ argv++;
+
+ /* provide usage if no arguments */
+ if (*argv == NULL) {
+ printf("gzappend 1.1 (4 Nov 2003) Copyright (C) 2003 Mark Adler\n");
+ printf(
+ "usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n");
+ return 0;
+ }
+
+ /* set compression level */
+ level = Z_DEFAULT_COMPRESSION;
+ if (argv[0][0] == '-') {
+ if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0)
+ bye("invalid compression level", "");
+ level = argv[0][1] - '0';
+ if (*++argv == NULL) bye("no gzip file name after options", "");
+ }
+
+ /* prepare to append to gzip file */
+ gd = gzscan(*argv++, &strm, level);
+
+ /* append files on command line, or from stdin if none */
+ if (*argv == NULL)
+ gztack(NULL, gd, &strm, 1);
+ else
+ do {
+ gztack(*argv, gd, &strm, argv[1] == NULL);
+ } while (*++argv != NULL);
+ return 0;
+}
diff --git a/zlib/examples/gzjoin.c b/zlib/examples/gzjoin.c
new file mode 100644
index 0000000..129347c
--- /dev/null
+++ b/zlib/examples/gzjoin.c
@@ -0,0 +1,448 @@
+/* gzjoin -- command to join gzip files into one gzip file
+
+ Copyright (C) 2004 Mark Adler, all rights reserved
+ version 1.0, 11 Dec 2004
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0 11 Dec 2004 - First version
+ * 1.1 12 Jun 2005 - Changed ssize_t to long for portability
+ */
+
+/*
+ gzjoin takes one or more gzip files on the command line and writes out a
+ single gzip file that will uncompress to the concatenation of the
+ uncompressed data from the individual gzip files. gzjoin does this without
+ having to recompress any of the data and without having to calculate a new
+ crc32 for the concatenated uncompressed data. gzjoin does however have to
+ decompress all of the input data in order to find the bits in the compressed
+ data that need to be modified to concatenate the streams.
+
+ gzjoin does not do an integrity check on the input gzip files other than
+ checking the gzip header and decompressing the compressed data. They are
+ otherwise assumed to be complete and correct.
+
+ Each joint between gzip files removes at least 18 bytes of previous trailer
+ and subsequent header, and inserts an average of about three bytes to the
+ compressed data in order to connect the streams. The output gzip file
+ has a minimal ten-byte gzip header with no file name or modification time.
+
+ This program was written to illustrate the use of the Z_BLOCK option of
+ inflate() and the crc32_combine() function. gzjoin will not compile with
+ versions of zlib earlier than 1.2.3.
+ */
+
+#include <stdio.h> /* fputs(), fprintf(), fwrite(), putc() */
+#include <stdlib.h> /* exit(), malloc(), free() */
+#include <fcntl.h> /* open() */
+#include <unistd.h> /* close(), read(), lseek() */
+#include "zlib.h"
+ /* crc32(), crc32_combine(), inflateInit2(), inflate(), inflateEnd() */
+
+#define local static
+
+/* exit with an error (return a value to allow use in an expression) */
+local int bail(char *why1, char *why2)
+{
+ fprintf(stderr, "gzjoin error: %s%s, output incomplete\n", why1, why2);
+ exit(1);
+ return 0;
+}
+
+/* -- simple buffered file input with access to the buffer -- */
+
+#define CHUNK 32768 /* must be a power of two and fit in unsigned */
+
+/* bin buffered input file type */
+typedef struct {
+ char *name; /* name of file for error messages */
+ int fd; /* file descriptor */
+ unsigned left; /* bytes remaining at next */
+ unsigned char *next; /* next byte to read */
+ unsigned char *buf; /* allocated buffer of length CHUNK */
+} bin;
+
+/* close a buffered file and free allocated memory */
+local void bclose(bin *in)
+{
+ if (in != NULL) {
+ if (in->fd != -1)
+ close(in->fd);
+ if (in->buf != NULL)
+ free(in->buf);
+ free(in);
+ }
+}
+
+/* open a buffered file for input, return a pointer to type bin, or NULL on
+ failure */
+local bin *bopen(char *name)
+{
+ bin *in;
+
+ in = malloc(sizeof(bin));
+ if (in == NULL)
+ return NULL;
+ in->buf = malloc(CHUNK);
+ in->fd = open(name, O_RDONLY, 0);
+ if (in->buf == NULL || in->fd == -1) {
+ bclose(in);
+ return NULL;
+ }
+ in->left = 0;
+ in->next = in->buf;
+ in->name = name;
+ return in;
+}
+
+/* load buffer from file, return -1 on read error, 0 or 1 on success, with
+ 1 indicating that end-of-file was reached */
+local int bload(bin *in)
+{
+ long len;
+
+ if (in == NULL)
+ return -1;
+ if (in->left != 0)
+ return 0;
+ in->next = in->buf;
+ do {
+ len = (long)read(in->fd, in->buf + in->left, CHUNK - in->left);
+ if (len < 0)
+ return -1;
+ in->left += (unsigned)len;
+ } while (len != 0 && in->left < CHUNK);
+ return len == 0 ? 1 : 0;
+}
+
+/* get a byte from the file, bail if end of file */
+#define bget(in) (in->left ? 0 : bload(in), \
+ in->left ? (in->left--, *(in->next)++) : \
+ bail("unexpected end of file on ", in->name))
+
+/* get a four-byte little-endian unsigned integer from file */
+local unsigned long bget4(bin *in)
+{
+ unsigned long val;
+
+ val = bget(in);
+ val += (unsigned long)(bget(in)) << 8;
+ val += (unsigned long)(bget(in)) << 16;
+ val += (unsigned long)(bget(in)) << 24;
+ return val;
+}
+
+/* skip bytes in file */
+local void bskip(bin *in, unsigned skip)
+{
+ /* check pointer */
+ if (in == NULL)
+ return;
+
+ /* easy case -- skip bytes in buffer */
+ if (skip <= in->left) {
+ in->left -= skip;
+ in->next += skip;
+ return;
+ }
+
+ /* skip what's in buffer, discard buffer contents */
+ skip -= in->left;
+ in->left = 0;
+
+ /* seek past multiples of CHUNK bytes */
+ if (skip > CHUNK) {
+ unsigned left;
+
+ left = skip & (CHUNK - 1);
+ if (left == 0) {
+ /* exact number of chunks: seek all the way minus one byte to check
+ for end-of-file with a read */
+ lseek(in->fd, skip - 1, SEEK_CUR);
+ if (read(in->fd, in->buf, 1) != 1)
+ bail("unexpected end of file on ", in->name);
+ return;
+ }
+
+ /* skip the integral chunks, update skip with remainder */
+ lseek(in->fd, skip - left, SEEK_CUR);
+ skip = left;
+ }
+
+ /* read more input and skip remainder */
+ bload(in);
+ if (skip > in->left)
+ bail("unexpected end of file on ", in->name);
+ in->left -= skip;
+ in->next += skip;
+}
+
+/* -- end of buffered input functions -- */
+
+/* skip the gzip header from file in */
+local void gzhead(bin *in)
+{
+ int flags;
+
+ /* verify gzip magic header and compression method */
+ if (bget(in) != 0x1f || bget(in) != 0x8b || bget(in) != 8)
+ bail(in->name, " is not a valid gzip file");
+
+ /* get and verify flags */
+ flags = bget(in);
+ if ((flags & 0xe0) != 0)
+ bail("unknown reserved bits set in ", in->name);
+
+ /* skip modification time, extra flags, and os */
+ bskip(in, 6);
+
+ /* skip extra field if present */
+ if (flags & 4) {
+ unsigned len;
+
+ len = bget(in);
+ len += (unsigned)(bget(in)) << 8;
+ bskip(in, len);
+ }
+
+ /* skip file name if present */
+ if (flags & 8)
+ while (bget(in) != 0)
+ ;
+
+ /* skip comment if present */
+ if (flags & 16)
+ while (bget(in) != 0)
+ ;
+
+ /* skip header crc if present */
+ if (flags & 2)
+ bskip(in, 2);
+}
+
+/* write a four-byte little-endian unsigned integer to out */
+local void put4(unsigned long val, FILE *out)
+{
+ putc(val & 0xff, out);
+ putc((val >> 8) & 0xff, out);
+ putc((val >> 16) & 0xff, out);
+ putc((val >> 24) & 0xff, out);
+}
+
+/* Load up zlib stream from buffered input, bail if end of file */
+local void zpull(z_streamp strm, bin *in)
+{
+ if (in->left == 0)
+ bload(in);
+ if (in->left == 0)
+ bail("unexpected end of file on ", in->name);
+ strm->avail_in = in->left;
+ strm->next_in = in->next;
+}
+
+/* Write header for gzip file to out and initialize trailer. */
+local void gzinit(unsigned long *crc, unsigned long *tot, FILE *out)
+{
+ fwrite("\x1f\x8b\x08\0\0\0\0\0\0\xff", 1, 10, out);
+ *crc = crc32(0L, Z_NULL, 0);
+ *tot = 0;
+}
+
+/* Copy the compressed data from name, zeroing the last block bit of the last
+ block if clr is true, and adding empty blocks as needed to get to a byte
+ boundary. If clr is false, then the last block becomes the last block of
+ the output, and the gzip trailer is written. crc and tot maintains the
+ crc and length (modulo 2^32) of the output for the trailer. The resulting
+ gzip file is written to out. gzinit() must be called before the first call
+ of gzcopy() to write the gzip header and to initialize crc and tot. */
+local void gzcopy(char *name, int clr, unsigned long *crc, unsigned long *tot,
+ FILE *out)
+{
+ int ret; /* return value from zlib functions */
+ int pos; /* where the "last block" bit is in byte */
+ int last; /* true if processing the last block */
+ bin *in; /* buffered input file */
+ unsigned char *start; /* start of compressed data in buffer */
+ unsigned char *junk; /* buffer for uncompressed data -- discarded */
+ z_off_t len; /* length of uncompressed data (support > 4 GB) */
+ z_stream strm; /* zlib inflate stream */
+
+ /* open gzip file and skip header */
+ in = bopen(name);
+ if (in == NULL)
+ bail("could not open ", name);
+ gzhead(in);
+
+ /* allocate buffer for uncompressed data and initialize raw inflate
+ stream */
+ junk = malloc(CHUNK);
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, -15);
+ if (junk == NULL || ret != Z_OK)
+ bail("out of memory", "");
+
+ /* inflate and copy compressed data, clear last-block bit if requested */
+ len = 0;
+ zpull(&strm, in);
+ start = strm.next_in;
+ last = start[0] & 1;
+ if (last && clr)
+ start[0] &= ~1;
+ strm.avail_out = 0;
+ for (;;) {
+ /* if input used and output done, write used input and get more */
+ if (strm.avail_in == 0 && strm.avail_out != 0) {
+ fwrite(start, 1, strm.next_in - start, out);
+ start = in->buf;
+ in->left = 0;
+ zpull(&strm, in);
+ }
+
+ /* decompress -- return early when end-of-block reached */
+ strm.avail_out = CHUNK;
+ strm.next_out = junk;
+ ret = inflate(&strm, Z_BLOCK);
+ switch (ret) {
+ case Z_MEM_ERROR:
+ bail("out of memory", "");
+ case Z_DATA_ERROR:
+ bail("invalid compressed data in ", in->name);
+ }
+
+ /* update length of uncompressed data */
+ len += CHUNK - strm.avail_out;
+
+ /* check for block boundary (only get this when block copied out) */
+ if (strm.data_type & 128) {
+ /* if that was the last block, then done */
+ if (last)
+ break;
+
+ /* number of unused bits in last byte */
+ pos = strm.data_type & 7;
+
+ /* find the next last-block bit */
+ if (pos != 0) {
+ /* next last-block bit is in last used byte */
+ pos = 0x100 >> pos;
+ last = strm.next_in[-1] & pos;
+ if (last && clr)
+ strm.next_in[-1] &= ~pos;
+ }
+ else {
+ /* next last-block bit is in next unused byte */
+ if (strm.avail_in == 0) {
+ /* don't have that byte yet -- get it */
+ fwrite(start, 1, strm.next_in - start, out);
+ start = in->buf;
+ in->left = 0;
+ zpull(&strm, in);
+ }
+ last = strm.next_in[0] & 1;
+ if (last && clr)
+ strm.next_in[0] &= ~1;
+ }
+ }
+ }
+
+ /* update buffer with unused input */
+ in->left = strm.avail_in;
+ in->next = strm.next_in;
+
+ /* copy used input, write empty blocks to get to byte boundary */
+ pos = strm.data_type & 7;
+ fwrite(start, 1, in->next - start - 1, out);
+ last = in->next[-1];
+ if (pos == 0 || !clr)
+ /* already at byte boundary, or last file: write last byte */
+ putc(last, out);
+ else {
+ /* append empty blocks to last byte */
+ last &= ((0x100 >> pos) - 1); /* assure unused bits are zero */
+ if (pos & 1) {
+ /* odd -- append an empty stored block */
+ putc(last, out);
+ if (pos == 1)
+ putc(0, out); /* two more bits in block header */
+ fwrite("\0\0\xff\xff", 1, 4, out);
+ }
+ else {
+ /* even -- append 1, 2, or 3 empty fixed blocks */
+ switch (pos) {
+ case 6:
+ putc(last | 8, out);
+ last = 0;
+ case 4:
+ putc(last | 0x20, out);
+ last = 0;
+ case 2:
+ putc(last | 0x80, out);
+ putc(0, out);
+ }
+ }
+ }
+
+ /* update crc and tot */
+ *crc = crc32_combine(*crc, bget4(in), len);
+ *tot += (unsigned long)len;
+
+ /* clean up */
+ inflateEnd(&strm);
+ free(junk);
+ bclose(in);
+
+ /* write trailer if this is the last gzip file */
+ if (!clr) {
+ put4(*crc, out);
+ put4(*tot, out);
+ }
+}
+
+/* join the gzip files on the command line, write result to stdout */
+int main(int argc, char **argv)
+{
+ unsigned long crc, tot; /* running crc and total uncompressed length */
+
+ /* skip command name */
+ argc--;
+ argv++;
+
+ /* show usage if no arguments */
+ if (argc == 0) {
+ fputs("gzjoin usage: gzjoin f1.gz [f2.gz [f3.gz ...]] > fjoin.gz\n",
+ stderr);
+ return 0;
+ }
+
+ /* join gzip files on command line and write to stdout */
+ gzinit(&crc, &tot, stdout);
+ while (argc--)
+ gzcopy(*argv++, argc, &crc, &tot, stdout);
+
+ /* done */
+ return 0;
+}
diff --git a/zlib/examples/gzlog.c b/zlib/examples/gzlog.c
new file mode 100644
index 0000000..f71f817
--- /dev/null
+++ b/zlib/examples/gzlog.c
@@ -0,0 +1,413 @@
+/*
+ * gzlog.c
+ * Copyright (C) 2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in gzlog.h
+ * version 1.0, 26 Nov 2004
+ *
+ */
+
+#include <string.h> /* memcmp() */
+#include <stdlib.h> /* malloc(), free(), NULL */
+#include <sys/types.h> /* size_t, off_t */
+#include <unistd.h> /* read(), close(), sleep(), ftruncate(), */
+ /* lseek() */
+#include <fcntl.h> /* open() */
+#include <sys/file.h> /* flock() */
+#include "zlib.h" /* deflateInit2(), deflate(), deflateEnd() */
+
+#include "gzlog.h" /* interface */
+#define local static
+
+/* log object structure */
+typedef struct {
+ int id; /* object identifier */
+ int fd; /* log file descriptor */
+ off_t extra; /* offset of extra "ap" subfield */
+ off_t mark_off; /* offset of marked data */
+ off_t last_off; /* offset of last block */
+ unsigned long crc; /* uncompressed crc */
+ unsigned long len; /* uncompressed length (modulo 2^32) */
+ unsigned stored; /* length of current stored block */
+} gz_log;
+
+#define GZLOGID 19334 /* gz_log object identifier */
+
+#define LOCK_RETRY 1 /* retry lock once a second */
+#define LOCK_PATIENCE 1200 /* try about twenty minutes before forcing */
+
+/* acquire a lock on a file */
+local int lock(int fd)
+{
+ int patience;
+
+ /* try to lock every LOCK_RETRY seconds for LOCK_PATIENCE seconds */
+ patience = LOCK_PATIENCE;
+ do {
+ if (flock(fd, LOCK_EX + LOCK_NB) == 0)
+ return 0;
+ (void)sleep(LOCK_RETRY);
+ patience -= LOCK_RETRY;
+ } while (patience > 0);
+
+ /* we've run out of patience -- give up */
+ return -1;
+}
+
+/* release lock */
+local void unlock(int fd)
+{
+ (void)flock(fd, LOCK_UN);
+}
+
+/* release a log object */
+local void log_clean(gz_log *log)
+{
+ unlock(log->fd);
+ (void)close(log->fd);
+ free(log);
+}
+
+/* read an unsigned long from a byte buffer little-endian */
+local unsigned long make_ulg(unsigned char *buf)
+{
+ int n;
+ unsigned long val;
+
+ val = (unsigned long)(*buf++);
+ for (n = 8; n < 32; n += 8)
+ val += (unsigned long)(*buf++) << n;
+ return val;
+}
+
+/* read an off_t from a byte buffer little-endian */
+local off_t make_off(unsigned char *buf)
+{
+ int n;
+ off_t val;
+
+ val = (off_t)(*buf++);
+ for (n = 8; n < 64; n += 8)
+ val += (off_t)(*buf++) << n;
+ return val;
+}
+
+/* write an unsigned long little-endian to byte buffer */
+local void dice_ulg(unsigned long val, unsigned char *buf)
+{
+ int n;
+
+ for (n = 0; n < 4; n++) {
+ *buf++ = val & 0xff;
+ val >>= 8;
+ }
+}
+
+/* write an off_t little-endian to byte buffer */
+local void dice_off(off_t val, unsigned char *buf)
+{
+ int n;
+
+ for (n = 0; n < 8; n++) {
+ *buf++ = val & 0xff;
+ val >>= 8;
+ }
+}
+
+/* initial, empty gzip file for appending */
+local char empty_gz[] = {
+ 0x1f, 0x8b, /* magic gzip id */
+ 8, /* compression method is deflate */
+ 4, /* there is an extra field */
+ 0, 0, 0, 0, /* no modification time provided */
+ 0, 0xff, /* no extra flags, no OS */
+ 20, 0, 'a', 'p', 16, 0, /* extra field with "ap" subfield */
+ 32, 0, 0, 0, 0, 0, 0, 0, /* offset of uncompressed data */
+ 32, 0, 0, 0, 0, 0, 0, 0, /* offset of last block */
+ 1, 0, 0, 0xff, 0xff, /* empty stored block (last) */
+ 0, 0, 0, 0, /* crc */
+ 0, 0, 0, 0 /* uncompressed length */
+};
+
+/* initialize a log object with locking */
+void *gzlog_open(char *path)
+{
+ unsigned xlen;
+ unsigned char temp[20];
+ unsigned sub_len;
+ int good;
+ gz_log *log;
+
+ /* allocate log structure */
+ log = malloc(sizeof(gz_log));
+ if (log == NULL)
+ return NULL;
+ log->id = GZLOGID;
+
+ /* open file, creating it if necessary, and locking it */
+ log->fd = open(path, O_RDWR | O_CREAT, 0600);
+ if (log->fd < 0) {
+ free(log);
+ return NULL;
+ }
+ if (lock(log->fd)) {
+ close(log->fd);
+ free(log);
+ return NULL;
+ }
+
+ /* if file is empty, write new gzip stream */
+ if (lseek(log->fd, 0, SEEK_END) == 0) {
+ if (write(log->fd, empty_gz, sizeof(empty_gz)) != sizeof(empty_gz)) {
+ log_clean(log);
+ return NULL;
+ }
+ }
+
+ /* check gzip header */
+ (void)lseek(log->fd, 0, SEEK_SET);
+ if (read(log->fd, temp, 12) != 12 || temp[0] != 0x1f ||
+ temp[1] != 0x8b || temp[2] != 8 || (temp[3] & 4) == 0) {
+ log_clean(log);
+ return NULL;
+ }
+
+ /* process extra field to find "ap" sub-field */
+ xlen = temp[10] + (temp[11] << 8);
+ good = 0;
+ while (xlen) {
+ if (xlen < 4 || read(log->fd, temp, 4) != 4)
+ break;
+ sub_len = temp[2];
+ sub_len += temp[3] << 8;
+ xlen -= 4;
+ if (memcmp(temp, "ap", 2) == 0 && sub_len == 16) {
+ good = 1;
+ break;
+ }
+ if (xlen < sub_len)
+ break;
+ (void)lseek(log->fd, sub_len, SEEK_CUR);
+ xlen -= sub_len;
+ }
+ if (!good) {
+ log_clean(log);
+ return NULL;
+ }
+
+ /* read in "ap" sub-field */
+ log->extra = lseek(log->fd, 0, SEEK_CUR);
+ if (read(log->fd, temp, 16) != 16) {
+ log_clean(log);
+ return NULL;
+ }
+ log->mark_off = make_off(temp);
+ log->last_off = make_off(temp + 8);
+
+ /* get crc, length of gzip file */
+ (void)lseek(log->fd, log->last_off, SEEK_SET);
+ if (read(log->fd, temp, 13) != 13 ||
+ memcmp(temp, "\001\000\000\377\377", 5) != 0) {
+ log_clean(log);
+ return NULL;
+ }
+ log->crc = make_ulg(temp + 5);
+ log->len = make_ulg(temp + 9);
+
+ /* set up to write over empty last block */
+ (void)lseek(log->fd, log->last_off + 5, SEEK_SET);
+ log->stored = 0;
+ return (void *)log;
+}
+
+/* maximum amount to put in a stored block before starting a new one */
+#define MAX_BLOCK 16384
+
+/* write a block to a log object */
+int gzlog_write(void *obj, char *data, size_t len)
+{
+ size_t some;
+ unsigned char temp[5];
+ gz_log *log;
+
+ /* check object */
+ log = (gz_log *)obj;
+ if (log == NULL || log->id != GZLOGID)
+ return 1;
+
+ /* write stored blocks until all of the input is written */
+ do {
+ some = MAX_BLOCK - log->stored;
+ if (some > len)
+ some = len;
+ if (write(log->fd, data, some) != some)
+ return 1;
+ log->crc = crc32(log->crc, data, some);
+ log->len += some;
+ len -= some;
+ data += some;
+ log->stored += some;
+
+ /* if the stored block is full, end it and start another */
+ if (log->stored == MAX_BLOCK) {
+ (void)lseek(log->fd, log->last_off, SEEK_SET);
+ temp[0] = 0;
+ dice_ulg(log->stored + ((unsigned long)(~log->stored) << 16),
+ temp + 1);
+ if (write(log->fd, temp, 5) != 5)
+ return 1;
+ log->last_off = lseek(log->fd, log->stored, SEEK_CUR);
+ (void)lseek(log->fd, 5, SEEK_CUR);
+ log->stored = 0;
+ }
+ } while (len);
+ return 0;
+}
+
+/* recompress the remaining stored deflate data in place */
+local int recomp(gz_log *log)
+{
+ z_stream strm;
+ size_t len, max;
+ unsigned char *in;
+ unsigned char *out;
+ unsigned char temp[16];
+
+ /* allocate space and read it all in (it's around 1 MB) */
+ len = log->last_off - log->mark_off;
+ max = len + (len >> 12) + (len >> 14) + 11;
+ out = malloc(max);
+ if (out == NULL)
+ return 1;
+ in = malloc(len);
+ if (in == NULL) {
+ free(out);
+ return 1;
+ }
+ (void)lseek(log->fd, log->mark_off, SEEK_SET);
+ if (read(log->fd, in, len) != len) {
+ free(in);
+ free(out);
+ return 1;
+ }
+
+ /* recompress in memory, decoding stored data as we go */
+ /* note: this assumes that unsigned is four bytes or more */
+ /* consider not making that assumption */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ if (deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 8,
+ Z_DEFAULT_STRATEGY) != Z_OK) {
+ free(in);
+ free(out);
+ return 1;
+ }
+ strm.next_in = in;
+ strm.avail_out = max;
+ strm.next_out = out;
+ while (len >= 5) {
+ if (strm.next_in[0] != 0)
+ break;
+ strm.avail_in = strm.next_in[1] + (strm.next_in[2] << 8);
+ strm.next_in += 5;
+ len -= 5;
+ if (strm.avail_in != 0) {
+ if (len < strm.avail_in)
+ break;
+ len -= strm.avail_in;
+ (void)deflate(&strm, Z_NO_FLUSH);
+ if (strm.avail_in != 0 || strm.avail_out == 0)
+ break;
+ }
+ }
+ (void)deflate(&strm, Z_SYNC_FLUSH);
+ (void)deflateEnd(&strm);
+ free(in);
+ if (len != 0 || strm.avail_out == 0) {
+ free(out);
+ return 1;
+ }
+
+ /* overwrite stored data with compressed data */
+ (void)lseek(log->fd, log->mark_off, SEEK_SET);
+ len = max - strm.avail_out;
+ if (write(log->fd, out, len) != len) {
+ free(out);
+ return 1;
+ }
+ free(out);
+
+ /* write last empty block, crc, and length */
+ log->mark_off = log->last_off = lseek(log->fd, 0, SEEK_CUR);
+ temp[0] = 1;
+ dice_ulg(0xffffL << 16, temp + 1);
+ dice_ulg(log->crc, temp + 5);
+ dice_ulg(log->len, temp + 9);
+ if (write(log->fd, temp, 13) != 13)
+ return 1;
+
+ /* truncate file to discard remaining stored data and old trailer */
+ ftruncate(log->fd, lseek(log->fd, 0, SEEK_CUR));
+
+ /* update extra field to point to new last empty block */
+ (void)lseek(log->fd, log->extra, SEEK_SET);
+ dice_off(log->mark_off, temp);
+ dice_off(log->last_off, temp + 8);
+ if (write(log->fd, temp, 16) != 16)
+ return 1;
+ return 0;
+}
+
+/* maximum accumulation of stored blocks before compressing */
+#define MAX_STORED 1048576
+
+/* close log object */
+int gzlog_close(void *obj)
+{
+ unsigned char temp[8];
+ gz_log *log;
+
+ /* check object */
+ log = (gz_log *)obj;
+ if (log == NULL || log->id != GZLOGID)
+ return 1;
+
+ /* go to start of most recent block being written */
+ (void)lseek(log->fd, log->last_off, SEEK_SET);
+
+ /* if some stuff was put there, update block */
+ if (log->stored) {
+ temp[0] = 0;
+ dice_ulg(log->stored + ((unsigned long)(~log->stored) << 16),
+ temp + 1);
+ if (write(log->fd, temp, 5) != 5)
+ return 1;
+ log->last_off = lseek(log->fd, log->stored, SEEK_CUR);
+ }
+
+ /* write last block (empty) */
+ if (write(log->fd, "\001\000\000\377\377", 5) != 5)
+ return 1;
+
+ /* write updated crc and uncompressed length */
+ dice_ulg(log->crc, temp);
+ dice_ulg(log->len, temp + 4);
+ if (write(log->fd, temp, 8) != 8)
+ return 1;
+
+ /* put offset of that last block in gzip extra block */
+ (void)lseek(log->fd, log->extra + 8, SEEK_SET);
+ dice_off(log->last_off, temp);
+ if (write(log->fd, temp, 8) != 8)
+ return 1;
+
+ /* if more than 1 MB stored, then time to compress it */
+ if (log->last_off - log->mark_off > MAX_STORED) {
+ if (recomp(log))
+ return 1;
+ }
+
+ /* unlock and close file */
+ log_clean(log);
+ return 0;
+}
diff --git a/zlib/examples/gzlog.h b/zlib/examples/gzlog.h
new file mode 100644
index 0000000..a800bd5
--- /dev/null
+++ b/zlib/examples/gzlog.h
@@ -0,0 +1,58 @@
+/* gzlog.h
+ Copyright (C) 2004 Mark Adler, all rights reserved
+ version 1.0, 26 Nov 2004
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+/*
+ The gzlog object allows writing short messages to a gzipped log file,
+ opening the log file locked for small bursts, and then closing it. The log
+ object works by appending stored data to the gzip file until 1 MB has been
+ accumulated. At that time, the stored data is compressed, and replaces the
+ uncompressed data in the file. The log file is truncated to its new size at
+ that time. After closing, the log file is always valid gzip file that can
+ decompressed to recover what was written.
+
+ A gzip header "extra" field contains two file offsets for appending. The
+ first points to just after the last compressed data. The second points to
+ the last stored block in the deflate stream, which is empty. All of the
+ data between those pointers is uncompressed.
+ */
+
+/* Open a gzlog object, creating the log file if it does not exist. Return
+ NULL on error. Note that gzlog_open() could take a long time to return if
+ there is difficulty in locking the file. */
+void *gzlog_open(char *path);
+
+/* Write to a gzlog object. Return non-zero on error. This function will
+ simply write data to the file uncompressed. Compression of the data
+ will not occur until gzlog_close() is called. It is expected that
+ gzlog_write() is used for a short message, and then gzlog_close() is
+ called. If a large amount of data is to be written, then the application
+ should write no more than 1 MB at a time with gzlog_write() before
+ calling gzlog_close() and then gzlog_open() again. */
+int gzlog_write(void *log, char *data, size_t len);
+
+/* Close a gzlog object. Return non-zero on error. The log file is locked
+ until this function is called. This function will compress stored data
+ at the end of the gzip file if at least 1 MB has been accumulated. Note
+ that the file will not be a valid gzip file until this function completes.
+ */
+int gzlog_close(void *log);
diff --git a/zlib/examples/zlib_how.html b/zlib/examples/zlib_how.html
new file mode 100644
index 0000000..40998db
--- /dev/null
+++ b/zlib/examples/zlib_how.html
@@ -0,0 +1,523 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+ "http://www.w3.org/TR/REC-html40/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>zlib Usage Example</title>
+<!-- Copyright (c) 2004 Mark Adler. -->
+</head>
+<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#00A000">
+<h2 align="center"> zlib Usage Example </h2>
+We often get questions about how the <tt>deflate()</tt> and <tt>inflate()</tt> functions should be used.
+Users wonder when they should provide more input, when they should use more output,
+what to do with a <tt>Z_BUF_ERROR</tt>, how to make sure the process terminates properly, and
+so on. So for those who have read <tt>zlib.h</tt> (a few times), and
+would like further edification, below is an annotated example in C of simple routines to compress and decompress
+from an input file to an output file using <tt>deflate()</tt> and <tt>inflate()</tt> respectively. The
+annotations are interspersed between lines of the code. So please read between the lines.
+We hope this helps explain some of the intricacies of <em>zlib</em>.
+<p>
+Without further adieu, here is the program <a href="zpipe.c"><tt>zpipe.c</tt></a>:
+<pre><b>
+/* zpipe.c: example of proper use of zlib's inflate() and deflate()
+ Not copyrighted -- provided to the public domain
+ Version 1.2 9 November 2004 Mark Adler */
+
+/* Version history:
+ 1.0 30 Oct 2004 First version
+ 1.1 8 Nov 2004 Add void casting for unused return values
+ Use switch statement for inflate() return values
+ 1.2 9 Nov 2004 Add assertions to document zlib guarantees
+ */
+</b></pre><!-- -->
+We now include the header files for the required definitions. From
+<tt>stdio.h</tt> we use <tt>fopen()</tt>, <tt>fread()</tt>, <tt>fwrite()</tt>,
+<tt>feof()</tt>, <tt>ferror()</tt>, and <tt>fclose()</tt> for file i/o, and
+<tt>fputs()</tt> for error messages. From <tt>string.h</tt> we use
+<tt>strcmp()</tt> for command line argument processing.
+From <tt>assert.h</tt> we use the <tt>assert()</tt> macro.
+From <tt>zlib.h</tt>
+we use the basic compression functions <tt>deflateInit()</tt>,
+<tt>deflate()</tt>, and <tt>deflateEnd()</tt>, and the basic decompression
+functions <tt>inflateInit()</tt>, <tt>inflate()</tt>, and
+<tt>inflateEnd()</tt>.
+<pre><b>
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;assert.h&gt;
+#include "zlib.h"
+</b></pre><!-- -->
+<tt>CHUNK</tt> is simply the buffer size for feeding data to and pulling data
+from the <em>zlib</em> routines. Larger buffer sizes would be more efficient,
+especially for <tt>inflate()</tt>. If the memory is available, buffers sizes
+on the order of 128K or 256K bytes should be used.
+<pre><b>
+#define CHUNK 16384
+</b></pre><!-- -->
+The <tt>def()</tt> routine compresses data from an input file to an output file. The output data
+will be in the <em>zlib</em> format, which is different from the <em>gzip</em> or <em>zip</em>
+formats. The <em>zlib</em> format has a very small header of only two bytes to identify it as
+a <em>zlib</em> stream and to provide decoding information, and a four-byte trailer with a fast
+check value to verify the integrity of the uncompressed data after decoding.
+<pre><b>
+/* Compress from file source to file dest until EOF on source.
+ def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+ allocated for processing, Z_STREAM_ERROR if an invalid compression
+ level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
+ version of the library linked do not match, or Z_ERRNO if there is
+ an error reading or writing the files. */
+int def(FILE *source, FILE *dest, int level)
+{
+</b></pre>
+Here are the local variables for <tt>def()</tt>. <tt>ret</tt> will be used for <em>zlib</em>
+return codes. <tt>flush</tt> will keep track of the current flushing state for <tt>deflate()</tt>,
+which is either no flushing, or flush to completion after the end of the input file is reached.
+<tt>have</tt> is the amount of data returned from <tt>deflate()</tt>. The <tt>strm</tt> structure
+is used to pass information to and from the <em>zlib</em> routines, and to maintain the
+<tt>deflate()</tt> state. <tt>in</tt> and <tt>out</tt> are the input and output buffers for
+<tt>deflate()</tt>.
+<pre><b>
+ int ret, flush;
+ unsigned have;
+ z_stream strm;
+ char in[CHUNK];
+ char out[CHUNK];
+</b></pre><!-- -->
+The first thing we do is to initialize the <em>zlib</em> state for compression using
+<tt>deflateInit()</tt>. This must be done before the first use of <tt>deflate()</tt>.
+The <tt>zalloc</tt>, <tt>zfree</tt>, and <tt>opaque</tt> fields in the <tt>strm</tt>
+structure must be initialized before calling <tt>deflateInit()</tt>. Here they are
+set to the <em>zlib</em> constant <tt>Z_NULL</tt> to request that <em>zlib</em> use
+the default memory allocation routines. An application may also choose to provide
+custom memory allocation routines here. <tt>deflateInit()</tt> will allocate on the
+order of 256K bytes for the internal state.
+(See <a href="zlib_tech.html"><em>zlib Technical Details</em></a>.)
+<p>
+<tt>deflateInit()</tt> is called with a pointer to the structure to be initialized and
+the compression level, which is an integer in the range of -1 to 9. Lower compression
+levels result in faster execution, but less compression. Higher levels result in
+greater compression, but slower execution. The <em>zlib</em> constant Z_DEFAULT_COMPRESSION,
+equal to -1,
+provides a good compromise between compression and speed and is equivalent to level 6.
+Level 0 actually does no compression at all, and in fact expands the data slightly to produce
+the <em>zlib</em> format (it is not a byte-for-byte copy of the input).
+More advanced applications of <em>zlib</em>
+may use <tt>deflateInit2()</tt> here instead. Such an application may want to reduce how
+much memory will be used, at some price in compression. Or it may need to request a
+<em>gzip</em> header and trailer instead of a <em>zlib</em> header and trailer, or raw
+encoding with no header or trailer at all.
+<p>
+We must check the return value of <tt>deflateInit()</tt> against the <em>zlib</em> constant
+<tt>Z_OK</tt> to make sure that it was able to
+allocate memory for the internal state, and that the provided arguments were valid.
+<tt>deflateInit()</tt> will also check that the version of <em>zlib</em> that the <tt>zlib.h</tt>
+file came from matches the version of <em>zlib</em> actually linked with the program. This
+is especially important for environments in which <em>zlib</em> is a shared library.
+<p>
+Note that an application can initialize multiple, independent <em>zlib</em> streams, which can
+operate in parallel. The state information maintained in the structure allows the <em>zlib</em>
+routines to be reentrant.
+<pre><b>
+ /* allocate deflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ ret = deflateInit(&amp;strm, level);
+ if (ret != Z_OK)
+ return ret;
+</b></pre><!-- -->
+With the pleasantries out of the way, now we can get down to business. The outer <tt>do</tt>-loop
+reads all of the input file and exits at the bottom of the loop once end-of-file is reached.
+This loop contains the only call of <tt>deflate()</tt>. So we must make sure that all of the
+input data has been processed and that all of the output data has been generated and consumed
+before we fall out of the loop at the bottom.
+<pre><b>
+ /* compress until end of file */
+ do {
+</b></pre>
+We start off by reading data from the input file. The number of bytes read is put directly
+into <tt>avail_in</tt>, and a pointer to those bytes is put into <tt>next_in</tt>. We also
+check to see if end-of-file on the input has been reached. If we are at the end of file, then <tt>flush</tt> is set to the
+<em>zlib</em> constant <tt>Z_FINISH</tt>, which is later passed to <tt>deflate()</tt> to
+indicate that this is the last chunk of input data to compress. We need to use <tt>feof()</tt>
+to check for end-of-file as opposed to seeing if fewer than <tt>CHUNK</tt> bytes have been read. The
+reason is that if the input file length is an exact multiple of <tt>CHUNK</tt>, we will miss
+the fact that we got to the end-of-file, and not know to tell <tt>deflate()</tt> to finish
+up the compressed stream. If we are not yet at the end of the input, then the <em>zlib</em>
+constant <tt>Z_NO_FLUSH</tt> will be passed to <tt>deflate</tt> to indicate that we are still
+in the middle of the uncompressed data.
+<p>
+If there is an error in reading from the input file, the process is aborted with
+<tt>deflateEnd()</tt> being called to free the allocated <em>zlib</em> state before returning
+the error. We wouldn't want a memory leak, now would we? <tt>deflateEnd()</tt> can be called
+at any time after the state has been initialized. Once that's done, <tt>deflateInit()</tt> (or
+<tt>deflateInit2()</tt>) would have to be called to start a new compression process. There is
+no point here in checking the <tt>deflateEnd()</tt> return code. The deallocation can't fail.
+<pre><b>
+ strm.avail_in = fread(in, 1, CHUNK, source);
+ if (ferror(source)) {
+ (void)deflateEnd(&amp;strm);
+ return Z_ERRNO;
+ }
+ flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
+ strm.next_in = in;
+</b></pre><!-- -->
+The inner <tt>do</tt>-loop passes our chunk of input data to <tt>deflate()</tt>, and then
+keeps calling <tt>deflate()</tt> until it is done producing output. Once there is no more
+new output, <tt>deflate()</tt> is guaranteed to have consumed all of the input, i.e.,
+<tt>avail_in</tt> will be zero.
+<pre><b>
+ /* run deflate() on input until output buffer not full, finish
+ compression if all of source has been read in */
+ do {
+</b></pre>
+Output space is provided to <tt>deflate()</tt> by setting <tt>avail_out</tt> to the number
+of available output bytes and <tt>next_out</tt> to a pointer to that space.
+<pre><b>
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+</b></pre>
+Now we call the compression engine itself, <tt>deflate()</tt>. It takes as many of the
+<tt>avail_in</tt> bytes at <tt>next_in</tt> as it can process, and writes as many as
+<tt>avail_out</tt> bytes to <tt>next_out</tt>. Those counters and pointers are then
+updated past the input data consumed and the output data written. It is the amount of
+output space available that may limit how much input is consumed.
+Hence the inner loop to make sure that
+all of the input is consumed by providing more output space each time. Since <tt>avail_in</tt>
+and <tt>next_in</tt> are updated by <tt>deflate()</tt>, we don't have to mess with those
+between <tt>deflate()</tt> calls until it's all used up.
+<p>
+The parameters to <tt>deflate()</tt> are a pointer to the <tt>strm</tt> structure containing
+the input and output information and the internal compression engine state, and a parameter
+indicating whether and how to flush data to the output. Normally <tt>deflate</tt> will consume
+several K bytes of input data before producing any output (except for the header), in order
+to accumulate statistics on the data for optimum compression. It will then put out a burst of
+compressed data, and proceed to consume more input before the next burst. Eventually,
+<tt>deflate()</tt>
+must be told to terminate the stream, complete the compression with provided input data, and
+write out the trailer check value. <tt>deflate()</tt> will continue to compress normally as long
+as the flush parameter is <tt>Z_NO_FLUSH</tt>. Once the <tt>Z_FINISH</tt> parameter is provided,
+<tt>deflate()</tt> will begin to complete the compressed output stream. However depending on how
+much output space is provided, <tt>deflate()</tt> may have to be called several times until it
+has provided the complete compressed stream, even after it has consumed all of the input. The flush
+parameter must continue to be <tt>Z_FINISH</tt> for those subsequent calls.
+<p>
+There are other values of the flush parameter that are used in more advanced applications. You can
+force <tt>deflate()</tt> to produce a burst of output that encodes all of the input data provided
+so far, even if it wouldn't have otherwise, for example to control data latency on a link with
+compressed data. You can also ask that <tt>deflate()</tt> do that as well as erase any history up to
+that point so that what follows can be decompressed independently, for example for random access
+applications. Both requests will degrade compression by an amount depending on how often such
+requests are made.
+<p>
+<tt>deflate()</tt> has a return value that can indicate errors, yet we do not check it here. Why
+not? Well, it turns out that <tt>deflate()</tt> can do no wrong here. Let's go through
+<tt>deflate()</tt>'s return values and dispense with them one by one. The possible values are
+<tt>Z_OK</tt>, <tt>Z_STREAM_END</tt>, <tt>Z_STREAM_ERROR</tt>, or <tt>Z_BUF_ERROR</tt>. <tt>Z_OK</tt>
+is, well, ok. <tt>Z_STREAM_END</tt> is also ok and will be returned for the last call of
+<tt>deflate()</tt>. This is already guaranteed by calling <tt>deflate()</tt> with <tt>Z_FINISH</tt>
+until it has no more output. <tt>Z_STREAM_ERROR</tt> is only possible if the stream is not
+initialized properly, but we did initialize it properly. There is no harm in checking for
+<tt>Z_STREAM_ERROR</tt> here, for example to check for the possibility that some
+other part of the application inadvertently clobbered the memory containing the <em>zlib</em> state.
+<tt>Z_BUF_ERROR</tt> will be explained further below, but
+suffice it to say that this is simply an indication that <tt>deflate()</tt> could not consume
+more input or produce more output. <tt>deflate()</tt> can be called again with more output space
+or more available input, which it will be in this code.
+<pre><b>
+ ret = deflate(&amp;strm, flush); /* no bad return value */
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+</b></pre>
+Now we compute how much output <tt>deflate()</tt> provided on the last call, which is the
+difference between how much space was provided before the call, and how much output space
+is still available after the call. Then that data, if any, is written to the output file.
+We can then reuse the output buffer for the next call of <tt>deflate()</tt>. Again if there
+is a file i/o error, we call <tt>deflateEnd()</tt> before returning to avoid a memory leak.
+<pre><b>
+ have = CHUNK - strm.avail_out;
+ if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+ (void)deflateEnd(&amp;strm);
+ return Z_ERRNO;
+ }
+</b></pre>
+The inner <tt>do</tt>-loop is repeated until the last <tt>deflate()</tt> call fails to fill the
+provided output buffer. Then we know that <tt>deflate()</tt> has done as much as it can with
+the provided input, and that all of that input has been consumed. We can then fall out of this
+loop and reuse the input buffer.
+<p>
+The way we tell that <tt>deflate()</tt> has no more output is by seeing that it did not fill
+the output buffer, leaving <tt>avail_out</tt> greater than zero. However suppose that
+<tt>deflate()</tt> has no more output, but just so happened to exactly fill the output buffer!
+<tt>avail_out</tt> is zero, and we can't tell that <tt>deflate()</tt> has done all it can.
+As far as we know, <tt>deflate()</tt>
+has more output for us. So we call it again. But now <tt>deflate()</tt> produces no output
+at all, and <tt>avail_out</tt> remains unchanged as <tt>CHUNK</tt>. That <tt>deflate()</tt> call
+wasn't able to do anything, either consume input or produce output, and so it returns
+<tt>Z_BUF_ERROR</tt>. (See, I told you I'd cover this later.) However this is not a problem at
+all. Now we finally have the desired indication that <tt>deflate()</tt> is really done,
+and so we drop out of the inner loop to provide more input to <tt>deflate()</tt>.
+<p>
+With <tt>flush</tt> set to <tt>Z_FINISH</tt>, this final set of <tt>deflate()</tt> calls will
+complete the output stream. Once that is done, subsequent calls of <tt>deflate()</tt> would return
+<tt>Z_STREAM_ERROR</tt> if the flush parameter is not <tt>Z_FINISH</tt>, and do no more processing
+until the state is reinitialized.
+<p>
+Some applications of <em>zlib</em> have two loops that call <tt>deflate()</tt>
+instead of the single inner loop we have here. The first loop would call
+without flushing and feed all of the data to <tt>deflate()</tt>. The second loop would call
+<tt>deflate()</tt> with no more
+data and the <tt>Z_FINISH</tt> parameter to complete the process. As you can see from this
+example, that can be avoided by simply keeping track of the current flush state.
+<pre><b>
+ } while (strm.avail_out == 0);
+ assert(strm.avail_in == 0); /* all input will be used */
+</b></pre><!-- -->
+Now we check to see if we have already processed all of the input file. That information was
+saved in the <tt>flush</tt> variable, so we see if that was set to <tt>Z_FINISH</tt>. If so,
+then we're done and we fall out of the outer loop. We're guaranteed to get <tt>Z_STREAM_END</tt>
+from the last <tt>deflate()</tt> call, since we ran it until the last chunk of input was
+consumed and all of the output was generated.
+<pre><b>
+ /* done when last data in file processed */
+ } while (flush != Z_FINISH);
+ assert(ret == Z_STREAM_END); /* stream will be complete */
+</b></pre><!-- -->
+The process is complete, but we still need to deallocate the state to avoid a memory leak
+(or rather more like a memory hemorrhage if you didn't do this). Then
+finally we can return with a happy return value.
+<pre><b>
+ /* clean up and return */
+ (void)deflateEnd(&amp;strm);
+ return Z_OK;
+}
+</b></pre><!-- -->
+Now we do the same thing for decompression in the <tt>inf()</tt> routine. <tt>inf()</tt>
+decompresses what is hopefully a valid <em>zlib</em> stream from the input file and writes the
+uncompressed data to the output file. Much of the discussion above for <tt>def()</tt>
+applies to <tt>inf()</tt> as well, so the discussion here will focus on the differences between
+the two.
+<pre><b>
+/* Decompress from file source to file dest until stream ends or EOF.
+ inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+ allocated for processing, Z_DATA_ERROR if the deflate data is
+ invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
+ the version of the library linked do not match, or Z_ERRNO if there
+ is an error reading or writing the files. */
+int inf(FILE *source, FILE *dest)
+{
+</b></pre>
+The local variables have the same functionality as they do for <tt>def()</tt>. The
+only difference is that there is no <tt>flush</tt> variable, since <tt>inflate()</tt>
+can tell from the <em>zlib</em> stream itself when the stream is complete.
+<pre><b>
+ int ret;
+ unsigned have;
+ z_stream strm;
+ char in[CHUNK];
+ char out[CHUNK];
+</b></pre><!-- -->
+The initialization of the state is the same, except that there is no compression level,
+of course, and two more elements of the structure are initialized. <tt>avail_in</tt>
+and <tt>next_in</tt> must be initialized before calling <tt>inflateInit()</tt>. This
+is because the application has the option to provide the start of the zlib stream in
+order for <tt>inflateInit()</tt> to have access to information about the compression
+method to aid in memory allocation. In the current implementation of <em>zlib</em>
+(up through versions 1.2.x), the method-dependent memory allocations are deferred to the first call of
+<tt>inflate()</tt> anyway. However those fields must be initialized since later versions
+of <em>zlib</em> that provide more compression methods may take advantage of this interface.
+In any case, no decompression is performed by <tt>inflateInit()</tt>, so the
+<tt>avail_out</tt> and <tt>next_out</tt> fields do not need to be initialized before calling.
+<p>
+Here <tt>avail_in</tt> is set to zero and <tt>next_in</tt> is set to <tt>Z_NULL</tt> to
+indicate that no input data is being provided.
+<pre><b>
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&amp;strm);
+ if (ret != Z_OK)
+ return ret;
+</b></pre><!-- -->
+The outer <tt>do</tt>-loop decompresses input until <tt>inflate()</tt> indicates
+that it has reached the end of the compressed data and has produced all of the uncompressed
+output. This is in contrast to <tt>def()</tt> which processes all of the input file.
+If end-of-file is reached before the compressed data self-terminates, then the compressed
+data is incomplete and an error is returned.
+<pre><b>
+ /* decompress until deflate stream ends or end of file */
+ do {
+</b></pre>
+We read input data and set the <tt>strm</tt> structure accordingly. If we've reached the
+end of the input file, then we leave the outer loop and report an error, since the
+compressed data is incomplete. Note that we may read more data than is eventually consumed
+by <tt>inflate()</tt>, if the input file continues past the <em>zlib</em> stream.
+For applications where <em>zlib</em> streams are embedded in other data, this routine would
+need to be modified to return the unused data, or at least indicate how much of the input
+data was not used, so the application would know where to pick up after the <em>zlib</em> stream.
+<pre><b>
+ strm.avail_in = fread(in, 1, CHUNK, source);
+ if (ferror(source)) {
+ (void)inflateEnd(&amp;strm);
+ return Z_ERRNO;
+ }
+ if (strm.avail_in == 0)
+ break;
+ strm.next_in = in;
+</b></pre><!-- -->
+The inner <tt>do</tt>-loop has the same function it did in <tt>def()</tt>, which is to
+keep calling <tt>inflate()</tt> until has generated all of the output it can with the
+provided input.
+<pre><b>
+ /* run inflate() on input until output buffer not full */
+ do {
+</b></pre>
+Just like in <tt>def()</tt>, the same output space is provided for each call of <tt>inflate()</tt>.
+<pre><b>
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+</b></pre>
+Now we run the decompression engine itself. There is no need to adjust the flush parameter, since
+the <em>zlib</em> format is self-terminating. The main difference here is that there are
+return values that we need to pay attention to. <tt>Z_DATA_ERROR</tt>
+indicates that <tt>inflate()</tt> detected an error in the <em>zlib</em> compressed data format,
+which means that either the data is not a <em>zlib</em> stream to begin with, or that the data was
+corrupted somewhere along the way since it was compressed. The other error to be processed is
+<tt>Z_MEM_ERROR</tt>, which can occur since memory allocation is deferred until <tt>inflate()</tt>
+needs it, unlike <tt>deflate()</tt>, whose memory is allocated at the start by <tt>deflateInit()</tt>.
+<p>
+Advanced applications may use
+<tt>deflateSetDictionary()</tt> to prime <tt>deflate()</tt> with a set of likely data to improve the
+first 32K or so of compression. This is noted in the <em>zlib</em> header, so <tt>inflate()</tt>
+requests that that dictionary be provided before it can start to decompress. Without the dictionary,
+correct decompression is not possible. For this routine, we have no idea what the dictionary is,
+so the <tt>Z_NEED_DICT</tt> indication is converted to a <tt>Z_DATA_ERROR</tt>.
+<p>
+<tt>inflate()</tt> can also return <tt>Z_STREAM_ERROR</tt>, which should not be possible here,
+but could be checked for as noted above for <tt>def()</tt>. <tt>Z_BUF_ERROR</tt> does not need to be
+checked for here, for the same reasons noted for <tt>def()</tt>. <tt>Z_STREAM_END</tt> will be
+checked for later.
+<pre><b>
+ ret = inflate(&amp;strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR; /* and fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&amp;strm);
+ return ret;
+ }
+</b></pre>
+The output of <tt>inflate()</tt> is handled identically to that of <tt>deflate()</tt>.
+<pre><b>
+ have = CHUNK - strm.avail_out;
+ if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+ (void)inflateEnd(&amp;strm);
+ return Z_ERRNO;
+ }
+</b></pre>
+The inner <tt>do</tt>-loop ends when <tt>inflate()</tt> has no more output as indicated
+by not filling the output buffer, just as for <tt>deflate()</tt>. In this case, we cannot
+assert that <tt>strm.avail_in</tt> will be zero, since the deflate stream may end before the file
+does.
+<pre><b>
+ } while (strm.avail_out == 0);
+</b></pre><!-- -->
+The outer <tt>do</tt>-loop ends when <tt>inflate()</tt> reports that it has reached the
+end of the input <em>zlib</em> stream, has completed the decompression and integrity
+check, and has provided all of the output. This is indicated by the <tt>inflate()</tt>
+return value <tt>Z_STREAM_END</tt>. The inner loop is guaranteed to leave <tt>ret</tt>
+equal to <tt>Z_STREAM_END</tt> if the last chunk of the input file read contained the end
+of the <em>zlib</em> stream. So if the return value is not <tt>Z_STREAM_END</tt>, the
+loop continues to read more input.
+<pre><b>
+ /* done when inflate() says it's done */
+ } while (ret != Z_STREAM_END);
+</b></pre><!-- -->
+At this point, decompression successfully completed, or we broke out of the loop due to no
+more data being available from the input file. If the last <tt>inflate()</tt> return value
+is not <tt>Z_STREAM_END</tt>, then the <em>zlib</em> stream was incomplete and a data error
+is returned. Otherwise, we return with a happy return value. Of course, <tt>inflateEnd()</tt>
+is called first to avoid a memory leak.
+<pre><b>
+ /* clean up and return */
+ (void)inflateEnd(&amp;strm);
+ return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+</b></pre><!-- -->
+That ends the routines that directly use <em>zlib</em>. The following routines make this
+a command-line program by running data through the above routines from <tt>stdin</tt> to
+<tt>stdout</tt>, and handling any errors reported by <tt>def()</tt> or <tt>inf()</tt>.
+<p>
+<tt>zerr()</tt> is used to interpret the possible error codes from <tt>def()</tt>
+and <tt>inf()</tt>, as detailed in their comments above, and print out an error message.
+Note that these are only a subset of the possible return values from <tt>deflate()</tt>
+and <tt>inflate()</tt>.
+<pre><b>
+/* report a zlib or i/o error */
+void zerr(int ret)
+{
+ fputs("zpipe: ", stderr);
+ switch (ret) {
+ case Z_ERRNO:
+ if (ferror(stdin))
+ fputs("error reading stdin\n", stderr);
+ if (ferror(stdout))
+ fputs("error writing stdout\n", stderr);
+ break;
+ case Z_STREAM_ERROR:
+ fputs("invalid compression level\n", stderr);
+ break;
+ case Z_DATA_ERROR:
+ fputs("invalid or incomplete deflate data\n", stderr);
+ break;
+ case Z_MEM_ERROR:
+ fputs("out of memory\n", stderr);
+ break;
+ case Z_VERSION_ERROR:
+ fputs("zlib version mismatch!\n", stderr);
+ }
+}
+</b></pre><!-- -->
+Here is the <tt>main()</tt> routine used to test <tt>def()</tt> and <tt>inf()</tt>. The
+<tt>zpipe</tt> command is simply a compression pipe from <tt>stdin</tt> to <tt>stdout</tt>, if
+no arguments are given, or it is a decompression pipe if <tt>zpipe -d</tt> is used. If any other
+arguments are provided, no compression or decompression is performed. Instead a usage
+message is displayed. Examples are <tt>zpipe < foo.txt > foo.txt.z</tt> to compress, and
+<tt>zpipe -d < foo.txt.z > foo.txt</tt> to decompress.
+<pre><b>
+/* compress or decompress from stdin to stdout */
+int main(int argc, char **argv)
+{
+ int ret;
+
+ /* do compression if no arguments */
+ if (argc == 1) {
+ ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
+ if (ret != Z_OK)
+ zerr(ret);
+ return ret;
+ }
+
+ /* do decompression if -d specified */
+ else if (argc == 2 &amp;&amp; strcmp(argv[1], "-d") == 0) {
+ ret = inf(stdin, stdout);
+ if (ret != Z_OK)
+ zerr(ret);
+ return ret;
+ }
+
+ /* otherwise, report usage */
+ else {
+ fputs("zpipe usage: zpipe [-d] &lt; source &gt; dest\n", stderr);
+ return 1;
+ }
+}
+</b></pre>
+<hr>
+<i>Copyright (c) 2004 by Mark Adler<br>Last modified 13 November 2004</i>
+</body>
+</html>
diff --git a/zlib/examples/zpipe.c b/zlib/examples/zpipe.c
new file mode 100644
index 0000000..26abb56
--- /dev/null
+++ b/zlib/examples/zpipe.c
@@ -0,0 +1,191 @@
+/* zpipe.c: example of proper use of zlib's inflate() and deflate()
+ Not copyrighted -- provided to the public domain
+ Version 1.2 9 November 2004 Mark Adler */
+
+/* Version history:
+ 1.0 30 Oct 2004 First version
+ 1.1 8 Nov 2004 Add void casting for unused return values
+ Use switch statement for inflate() return values
+ 1.2 9 Nov 2004 Add assertions to document zlib guarantees
+ 1.3 6 Apr 2005 Remove incorrect assertion in inf()
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "zlib.h"
+
+#define CHUNK 16384
+
+/* Compress from file source to file dest until EOF on source.
+ def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+ allocated for processing, Z_STREAM_ERROR if an invalid compression
+ level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
+ version of the library linked do not match, or Z_ERRNO if there is
+ an error reading or writing the files. */
+int def(FILE *source, FILE *dest, int level)
+{
+ int ret, flush;
+ unsigned have;
+ z_stream strm;
+ char in[CHUNK];
+ char out[CHUNK];
+
+ /* allocate deflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ ret = deflateInit(&strm, level);
+ if (ret != Z_OK)
+ return ret;
+
+ /* compress until end of file */
+ do {
+ strm.avail_in = fread(in, 1, CHUNK, source);
+ if (ferror(source)) {
+ (void)deflateEnd(&strm);
+ return Z_ERRNO;
+ }
+ flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
+ strm.next_in = in;
+
+ /* run deflate() on input until output buffer not full, finish
+ compression if all of source has been read in */
+ do {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = deflate(&strm, flush); /* no bad return value */
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ have = CHUNK - strm.avail_out;
+ if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+ (void)deflateEnd(&strm);
+ return Z_ERRNO;
+ }
+ } while (strm.avail_out == 0);
+ assert(strm.avail_in == 0); /* all input will be used */
+
+ /* done when last data in file processed */
+ } while (flush != Z_FINISH);
+ assert(ret == Z_STREAM_END); /* stream will be complete */
+
+ /* clean up and return */
+ (void)deflateEnd(&strm);
+ return Z_OK;
+}
+
+/* Decompress from file source to file dest until stream ends or EOF.
+ inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+ allocated for processing, Z_DATA_ERROR if the deflate data is
+ invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
+ the version of the library linked do not match, or Z_ERRNO if there
+ is an error reading or writing the files. */
+int inf(FILE *source, FILE *dest)
+{
+ int ret;
+ unsigned have;
+ z_stream strm;
+ char in[CHUNK];
+ char out[CHUNK];
+
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&strm);
+ if (ret != Z_OK)
+ return ret;
+
+ /* decompress until deflate stream ends or end of file */
+ do {
+ strm.avail_in = fread(in, 1, CHUNK, source);
+ if (ferror(source)) {
+ (void)inflateEnd(&strm);
+ return Z_ERRNO;
+ }
+ if (strm.avail_in == 0)
+ break;
+ strm.next_in = in;
+
+ /* run inflate() on input until output buffer not full */
+ do {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR; /* and fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&strm);
+ return ret;
+ }
+ have = CHUNK - strm.avail_out;
+ if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+ (void)inflateEnd(&strm);
+ return Z_ERRNO;
+ }
+ } while (strm.avail_out == 0);
+
+ /* done when inflate() says it's done */
+ } while (ret != Z_STREAM_END);
+
+ /* clean up and return */
+ (void)inflateEnd(&strm);
+ return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
+/* report a zlib or i/o error */
+void zerr(int ret)
+{
+ fputs("zpipe: ", stderr);
+ switch (ret) {
+ case Z_ERRNO:
+ if (ferror(stdin))
+ fputs("error reading stdin\n", stderr);
+ if (ferror(stdout))
+ fputs("error writing stdout\n", stderr);
+ break;
+ case Z_STREAM_ERROR:
+ fputs("invalid compression level\n", stderr);
+ break;
+ case Z_DATA_ERROR:
+ fputs("invalid or incomplete deflate data\n", stderr);
+ break;
+ case Z_MEM_ERROR:
+ fputs("out of memory\n", stderr);
+ break;
+ case Z_VERSION_ERROR:
+ fputs("zlib version mismatch!\n", stderr);
+ }
+}
+
+/* compress or decompress from stdin to stdout */
+int main(int argc, char **argv)
+{
+ int ret;
+
+ /* do compression if no arguments */
+ if (argc == 1) {
+ ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
+ if (ret != Z_OK)
+ zerr(ret);
+ return ret;
+ }
+
+ /* do decompression if -d specified */
+ else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
+ ret = inf(stdin, stdout);
+ if (ret != Z_OK)
+ zerr(ret);
+ return ret;
+ }
+
+ /* otherwise, report usage */
+ else {
+ fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
+ return 1;
+ }
+}
diff --git a/zlib/examples/zran.c b/zlib/examples/zran.c
new file mode 100644
index 0000000..8c7717e
--- /dev/null
+++ b/zlib/examples/zran.c
@@ -0,0 +1,404 @@
+/* zran.c -- example of zlib/gzip stream indexing and random access
+ * Copyright (C) 2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ Version 1.0 29 May 2005 Mark Adler */
+
+/* Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary()
+ for random access of a compressed file. A file containing a zlib or gzip
+ stream is provided on the command line. The compressed stream is decoded in
+ its entirety, and an index built with access points about every SPAN bytes
+ in the uncompressed output. The compressed file is left open, and can then
+ be read randomly, having to decompress on the average SPAN/2 uncompressed
+ bytes before getting to the desired block of data.
+
+ An access point can be created at the start of any deflate block, by saving
+ the starting file offset and bit of that block, and the 32K bytes of
+ uncompressed data that precede that block. Also the uncompressed offset of
+ that block is saved to provide a referece for locating a desired starting
+ point in the uncompressed stream. build_index() works by decompressing the
+ input zlib or gzip stream a block at a time, and at the end of each block
+ deciding if enough uncompressed data has gone by to justify the creation of
+ a new access point. If so, that point is saved in a data structure that
+ grows as needed to accommodate the points.
+
+ To use the index, an offset in the uncompressed data is provided, for which
+ the latest accees point at or preceding that offset is located in the index.
+ The input file is positioned to the specified location in the index, and if
+ necessary the first few bits of the compressed data is read from the file.
+ inflate is initialized with those bits and the 32K of uncompressed data, and
+ the decompression then proceeds until the desired offset in the file is
+ reached. Then the decompression continues to read the desired uncompressed
+ data from the file.
+
+ Another approach would be to generate the index on demand. In that case,
+ requests for random access reads from the compressed data would try to use
+ the index, but if a read far enough past the end of the index is required,
+ then further index entries would be generated and added.
+
+ There is some fair bit of overhead to starting inflation for the random
+ access, mainly copying the 32K byte dictionary. So if small pieces of the
+ file are being accessed, it would make sense to implement a cache to hold
+ some lookahead and avoid many calls to extract() for small lengths.
+
+ Another way to build an index would be to use inflateCopy(). That would
+ not be constrained to have access points at block boundaries, but requires
+ more memory per access point, and also cannot be saved to file due to the
+ use of pointers in the state. The approach here allows for storage of the
+ index in a file.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+
+#define local static
+
+#define SPAN 1048576L /* desired distance between access points */
+#define WINSIZE 32768U /* sliding window size */
+#define CHUNK 16384 /* file input buffer size */
+
+/* access point entry */
+struct point {
+ off_t out; /* corresponding offset in uncompressed data */
+ off_t in; /* offset in input file of first full byte */
+ int bits; /* number of bits (1-7) from byte at in - 1, or 0 */
+ unsigned char window[WINSIZE]; /* preceding 32K of uncompressed data */
+};
+
+/* access point list */
+struct access {
+ int have; /* number of list entries filled in */
+ int size; /* number of list entries allocated */
+ struct point *list; /* allocated list */
+};
+
+/* Deallocate an index built by build_index() */
+local void free_index(struct access *index)
+{
+ if (index != NULL) {
+ free(index->list);
+ free(index);
+ }
+}
+
+/* Add an entry to the access point list. If out of memory, deallocate the
+ existing list and return NULL. */
+local struct access *addpoint(struct access *index, int bits,
+ off_t in, off_t out, unsigned left, unsigned char *window)
+{
+ struct point *next;
+
+ /* if list is empty, create it (start with eight points) */
+ if (index == NULL) {
+ index = malloc(sizeof(struct access));
+ if (index == NULL) return NULL;
+ index->list = malloc(sizeof(struct point) << 3);
+ if (index->list == NULL) {
+ free(index);
+ return NULL;
+ }
+ index->size = 8;
+ index->have = 0;
+ }
+
+ /* if list is full, make it bigger */
+ else if (index->have == index->size) {
+ index->size <<= 1;
+ next = realloc(index->list, sizeof(struct point) * index->size);
+ if (next == NULL) {
+ free_index(index);
+ return NULL;
+ }
+ index->list = next;
+ }
+
+ /* fill in entry and increment how many we have */
+ next = index->list + index->have;
+ next->bits = bits;
+ next->in = in;
+ next->out = out;
+ if (left)
+ memcpy(next->window, window + WINSIZE - left, left);
+ if (left < WINSIZE)
+ memcpy(next->window + left, window, WINSIZE - left);
+ index->have++;
+
+ /* return list, possibly reallocated */
+ return index;
+}
+
+/* Make one entire pass through the compressed stream and build an index, with
+ access points about every span bytes of uncompressed output -- span is
+ chosen to balance the speed of random access against the memory requirements
+ of the list, about 32K bytes per access point. Note that data after the end
+ of the first zlib or gzip stream in the file is ignored. build_index()
+ returns the number of access points on success (>= 1), Z_MEM_ERROR for out
+ of memory, Z_DATA_ERROR for an error in the input file, or Z_ERRNO for a
+ file read error. On success, *built points to the resulting index. */
+local int build_index(FILE *in, off_t span, struct access **built)
+{
+ int ret;
+ off_t totin, totout; /* our own total counters to avoid 4GB limit */
+ off_t last; /* totout value of last access point */
+ struct access *index; /* access points being generated */
+ z_stream strm;
+ unsigned char input[CHUNK];
+ unsigned char window[WINSIZE];
+
+ /* initialize inflate */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, 47); /* automatic zlib or gzip decoding */
+ if (ret != Z_OK)
+ return ret;
+
+ /* inflate the input, maintain a sliding window, and build an index -- this
+ also validates the integrity of the compressed data using the check
+ information at the end of the gzip or zlib stream */
+ totin = totout = last = 0;
+ index = NULL; /* will be allocated by first addpoint() */
+ strm.avail_out = 0;
+ do {
+ /* get some compressed data from input file */
+ strm.avail_in = fread(input, 1, CHUNK, in);
+ if (ferror(in)) {
+ ret = Z_ERRNO;
+ goto build_index_error;
+ }
+ if (strm.avail_in == 0) {
+ ret = Z_DATA_ERROR;
+ goto build_index_error;
+ }
+ strm.next_in = input;
+
+ /* process all of that, or until end of stream */
+ do {
+ /* reset sliding window if necessary */
+ if (strm.avail_out == 0) {
+ strm.avail_out = WINSIZE;
+ strm.next_out = window;
+ }
+
+ /* inflate until out of input, output, or at end of block --
+ update the total input and output counters */
+ totin += strm.avail_in;
+ totout += strm.avail_out;
+ ret = inflate(&strm, Z_BLOCK); /* return at end of block */
+ totin -= strm.avail_in;
+ totout -= strm.avail_out;
+ if (ret == Z_NEED_DICT)
+ ret = Z_DATA_ERROR;
+ if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
+ goto build_index_error;
+ if (ret == Z_STREAM_END)
+ break;
+
+ /* if at end of block, consider adding an index entry (note that if
+ data_type indicates an end-of-block, then all of the
+ uncompressed data from that block has been delivered, and none
+ of the compressed data after that block has been consumed,
+ except for up to seven bits) -- the totout == 0 provides an
+ entry point after the zlib or gzip header, and assures that the
+ index always has at least one access point; we avoid creating an
+ access point after the last block by checking bit 6 of data_type
+ */
+ if ((strm.data_type & 128) && !(strm.data_type & 64) &&
+ (totout == 0 || totout - last > span)) {
+ index = addpoint(index, strm.data_type & 7, totin,
+ totout, strm.avail_out, window);
+ if (index == NULL) {
+ ret = Z_MEM_ERROR;
+ goto build_index_error;
+ }
+ last = totout;
+ }
+ } while (strm.avail_in != 0);
+ } while (ret != Z_STREAM_END);
+
+ /* clean up and return index (release unused entries in list) */
+ (void)inflateEnd(&strm);
+ index = realloc(index, sizeof(struct point) * index->have);
+ index->size = index->have;
+ *built = index;
+ return index->size;
+
+ /* return error */
+ build_index_error:
+ (void)inflateEnd(&strm);
+ if (index != NULL)
+ free_index(index);
+ return ret;
+}
+
+/* Use the index to read len bytes from offset into buf, return bytes read or
+ negative for error (Z_DATA_ERROR or Z_MEM_ERROR). If data is requested past
+ the end of the uncompressed data, then extract() will return a value less
+ than len, indicating how much as actually read into buf. This function
+ should not return a data error unless the file was modified since the index
+ was generated. extract() may also return Z_ERRNO if there is an error on
+ reading or seeking the input file. */
+local int extract(FILE *in, struct access *index, off_t offset,
+ unsigned char *buf, int len)
+{
+ int ret, skip;
+ z_stream strm;
+ struct point *here;
+ unsigned char input[CHUNK];
+ unsigned char discard[WINSIZE];
+
+ /* proceed only if something reasonable to do */
+ if (len < 0)
+ return 0;
+
+ /* find where in stream to start */
+ here = index->list;
+ ret = index->have;
+ while (--ret && here[1].out <= offset)
+ here++;
+
+ /* initialize file and inflate state to start there */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, -15); /* raw inflate */
+ if (ret != Z_OK)
+ return ret;
+ ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET);
+ if (ret == -1)
+ goto extract_ret;
+ if (here->bits) {
+ ret = getc(in);
+ if (ret == -1) {
+ ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR;
+ goto extract_ret;
+ }
+ (void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits));
+ }
+ (void)inflateSetDictionary(&strm, here->window, WINSIZE);
+
+ /* skip uncompressed bytes until offset reached, then satisfy request */
+ offset -= here->out;
+ strm.avail_in = 0;
+ skip = 1; /* while skipping to offset */
+ do {
+ /* define where to put uncompressed data, and how much */
+ if (offset == 0 && skip) { /* at offset now */
+ strm.avail_out = len;
+ strm.next_out = buf;
+ skip = 0; /* only do this once */
+ }
+ if (offset > WINSIZE) { /* skip WINSIZE bytes */
+ strm.avail_out = WINSIZE;
+ strm.next_out = discard;
+ offset -= WINSIZE;
+ }
+ else if (offset != 0) { /* last skip */
+ strm.avail_out = (unsigned)offset;
+ strm.next_out = discard;
+ offset = 0;
+ }
+
+ /* uncompress until avail_out filled, or end of stream */
+ do {
+ if (strm.avail_in == 0) {
+ strm.avail_in = fread(input, 1, CHUNK, in);
+ if (ferror(in)) {
+ ret = Z_ERRNO;
+ goto extract_ret;
+ }
+ if (strm.avail_in == 0) {
+ ret = Z_DATA_ERROR;
+ goto extract_ret;
+ }
+ strm.next_in = input;
+ }
+ ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */
+ if (ret == Z_NEED_DICT)
+ ret = Z_DATA_ERROR;
+ if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
+ goto extract_ret;
+ if (ret == Z_STREAM_END)
+ break;
+ } while (strm.avail_out != 0);
+
+ /* if reach end of stream, then don't keep trying to get more */
+ if (ret == Z_STREAM_END)
+ break;
+
+ /* do until offset reached and requested data read, or stream ends */
+ } while (skip);
+
+ /* compute number of uncompressed bytes read after offset */
+ ret = skip ? 0 : len - strm.avail_out;
+
+ /* clean up and return bytes read or error */
+ extract_ret:
+ (void)inflateEnd(&strm);
+ return ret;
+}
+
+/* Demonstrate the use of build_index() and extract() by processing the file
+ provided on the command line, and the extracting 16K from about 2/3rds of
+ the way through the uncompressed output, and writing that to stdout. */
+int main(int argc, char **argv)
+{
+ int len;
+ off_t offset;
+ FILE *in;
+ struct access *index;
+ unsigned char buf[CHUNK];
+
+ /* open input file */
+ if (argc != 2) {
+ fprintf(stderr, "usage: zran file.gz\n");
+ return 1;
+ }
+ in = fopen(argv[1], "rb");
+ if (in == NULL) {
+ fprintf(stderr, "zran: could not open %s for reading\n", argv[1]);
+ return 1;
+ }
+
+ /* build index */
+ len = build_index(in, SPAN, &index);
+ if (len < 0) {
+ fclose(in);
+ switch (len) {
+ case Z_MEM_ERROR:
+ fprintf(stderr, "zran: out of memory\n");
+ break;
+ case Z_DATA_ERROR:
+ fprintf(stderr, "zran: compressed data error in %s\n", argv[1]);
+ break;
+ case Z_ERRNO:
+ fprintf(stderr, "zran: read error on %s\n", argv[1]);
+ break;
+ default:
+ fprintf(stderr, "zran: error %d while building index\n", len);
+ }
+ return 1;
+ }
+ fprintf(stderr, "zran: built index with %d access points\n", len);
+
+ /* use index by reading some bytes from an arbitrary offset */
+ offset = (index->list[index->have - 1].out << 1) / 3;
+ len = extract(in, index, offset, buf, CHUNK);
+ if (len < 0)
+ fprintf(stderr, "zran: extraction failed: %s error\n",
+ len == Z_MEM_ERROR ? "out of memory" : "input corrupted");
+ else {
+ fwrite(buf, 1, len, stdout);
+ fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset);
+ }
+
+ /* clean up and exit */
+ free_index(index);
+ fclose(in);
+ return 0;
+}
diff --git a/zlib/gzio.c b/zlib/gzio.c
new file mode 100644
index 0000000..7e90f49
--- /dev/null
+++ b/zlib/gzio.c
@@ -0,0 +1,1026 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE /* for compatibility with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+# pragma map (fdopen , "\174\174FDOPEN")
+ FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ z_off_t start; /* start of compressed data in file (header skipped) */
+ z_off_t in; /* bytes into deflate or inflate */
+ z_off_t out; /* bytes out of deflate or inflate */
+ int back; /* one character push-back */
+ int last; /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->in = 0;
+ s->out = 0;
+ s->back = EOF;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else if (*p == 'R') {
+ strategy = Z_RLE;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->start = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * start anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->start = ftell(s->file) - s->stream.avail_in;
+ }
+
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[46]; /* allow for up to 128-bit integers */
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Assure two bytes in the buffer so we can peek ahead -- handle case
+ where first byte of header is at the end of the buffer after the last
+ gzip segment */
+ len = s->stream.avail_in;
+ if (len < 2) {
+ if (len) s->inbuf[0] = s->stream.next_in[0];
+ errno = 0;
+ len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+ if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+ s->stream.avail_in += len;
+ s->stream.next_in = s->inbuf;
+ if (s->stream.avail_in < 2) {
+ s->transparent = s->stream.avail_in;
+ return;
+ }
+ }
+
+ /* Peek ahead to check the gzip magic header */
+ if (s->stream.next_in[0] != gz_magic[0] ||
+ s->stream.next_in[1] != gz_magic[1]) {
+ s->transparent = 1;
+ return;
+ }
+ s->stream.avail_in -= 2;
+ s->stream.next_in += 2;
+
+ /* Check the rest of the gzip header */
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ if (s->stream.avail_out && s->back != EOF) {
+ *next_out++ = s->back;
+ s->stream.next_out++;
+ s->stream.avail_out--;
+ s->back = EOF;
+ s->out++;
+ start++;
+ if (s->last) {
+ s->z_err = Z_STREAM_END;
+ return 1;
+ }
+ }
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -=
+ (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+ }
+ len -= s->stream.avail_out;
+ s->in += len;
+ s->out += len;
+ if (len == 0) s->z_eof = 1;
+ return (int)len;
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may be
+ * different from s->out in case of concatenated .gz files.
+ * Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ inflateReset(&(s->stream));
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ if (len == s->stream.avail_out &&
+ (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+ return -1;
+ return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+ s->back = c;
+ s->out--;
+ s->last = (s->z_err == Z_STREAM_END);
+ if (s->last) s->z_err = Z_OK;
+ s->z_eof = 0;
+ return c;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+ va_start(va, format);
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf(buf, format, va);
+ va_end(va);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = vsprintf(buf, format, va);
+ va_end(va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+ len = strlen(buf);
+# else
+ len = vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+# endif
+#endif
+ if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen(buf);
+# else
+ len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#endif
+ if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), flush);
+ s->out -= s->stream.avail_out;
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->in;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ if (s->inbuf == Z_NULL) return -1L;
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return s->in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->in = s->out = offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if (offset >= s->out) {
+ offset -= s->out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ if (s->outbuf == Z_NULL) return -1L;
+ }
+ if (offset && s->back != EOF) {
+ s->back = EOF;
+ s->out++;
+ offset--;
+ if (s->last) s->z_err = Z_STREAM_END;
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return s->out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+ if (!s->transparent) (void)inflateReset(&s->stream);
+ s->in = 0;
+ s->out = 0;
+ return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ /* With concatenated compressed files that can have embedded
+ * crc trailers, z_eof is no longer the only/best indicator of EOF
+ * on a gz_stream. Handle end-of-stream error explicitly here.
+ */
+ if (s == NULL || s->mode != 'r') return 0;
+ if (s->z_eof) return 1;
+ return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+ Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return 0;
+ return s->transparent;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return Z_STREAM_ERROR;
+#else
+ if (do_flush (file, Z_FINISH) != Z_OK)
+ return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
+
+/* ===========================================================================
+ Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return;
+ if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+ s->z_eof = 0;
+ clearerr(s->file);
+}
diff --git a/zlib/infback.c b/zlib/infback.c
new file mode 100644
index 0000000..455dbc9
--- /dev/null
+++ b/zlib/infback.c
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->write = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/zlib/inffast.c b/zlib/inffast.c
new file mode 100644
index 0000000..bbee92e
--- /dev/null
+++ b/zlib/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/zlib/inffast.h b/zlib/inffast.h
new file mode 100644
index 0000000..1e88d2d
--- /dev/null
+++ b/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/zlib/inffixed.h b/zlib/inffixed.h
new file mode 100644
index 0000000..75ed4b5
--- /dev/null
+++ b/zlib/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/zlib/inflate.c b/zlib/inflate.c
new file mode 100644
index 0000000..792fdee
--- /dev/null
+++ b/zlib/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->write = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
diff --git a/zlib/inflate.h b/zlib/inflate.h
new file mode 100644
index 0000000..07bd3e7
--- /dev/null
+++ b/zlib/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/zlib/inftrees.c b/zlib/inftrees.c
new file mode 100644
index 0000000..8a9c13f
--- /dev/null
+++ b/zlib/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/zlib/inftrees.h b/zlib/inftrees.h
new file mode 100644
index 0000000..b1104c8
--- /dev/null
+++ b/zlib/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/zlib/libz.dep b/zlib/libz.dep
new file mode 100644
index 0000000..b2ce94b
--- /dev/null
+++ b/zlib/libz.dep
@@ -0,0 +1,76 @@
+# Microsoft Developer Studio Generated Dependency File, included by libz.mak
+
+.\adler32.c : \
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+.\compress.c : \
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+.\crc32.c : \
+ ".\crc32.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+.\deflate.c : \
+ ".\deflate.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+.\gzio.c : \
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+.\inffast.c : \
+ ".\inffast.h"\
+ ".\inflate.h"\
+ ".\inftrees.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+.\inflate.c : \
+ ".\inffast.h"\
+ ".\inffixed.h"\
+ ".\inflate.h"\
+ ".\inftrees.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+.\inftrees.c : \
+ ".\inftrees.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+.\trees.c : \
+ ".\deflate.h"\
+ ".\trees.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+.\uncompr.c : \
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+.\zutil.c : \
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
diff --git a/zlib/libz.dsp b/zlib/libz.dsp
new file mode 100644
index 0000000..bb49a20
--- /dev/null
+++ b/zlib/libz.dsp
@@ -0,0 +1,176 @@
+# Microsoft Developer Studio Project File - Name="libz" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libz - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libz.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libz.mak" CFG="libz - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libz - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libz - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libz - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "WinRel"
+# PROP BASE Intermediate_Dir "WinRel"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "WinRel"
+# PROP Intermediate_Dir "WinRel"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "libz - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "WinDebug"
+# PROP BASE Intermediate_Dir "WinDebug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "WinDebug"
+# PROP Intermediate_Dir "WinDebug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "libz - Win32 Release"
+# Name "libz - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "*.c"
+# Begin Source File
+
+SOURCE=.\adler32.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\gzio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\uncompr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\crc32.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffixed.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/zlib/libz.mak b/zlib/libz.mak
new file mode 100644
index 0000000..3c0f4fb
--- /dev/null
+++ b/zlib/libz.mak
@@ -0,0 +1,272 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on libz.dsp
+!IF "$(CFG)" == ""
+CFG=libz - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to libz - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "libz - Win32 Release" && "$(CFG)" != "libz - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libz.mak" CFG="libz - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libz - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libz - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "libz - Win32 Release"
+
+OUTDIR=.\WinRel
+INTDIR=.\WinRel
+# Begin Custom Macros
+OutDir=.\WinRel
+# End Custom Macros
+
+ALL : "$(OUTDIR)\libz.lib"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\adler32.obj"
+ -@erase "$(INTDIR)\compress.obj"
+ -@erase "$(INTDIR)\crc32.obj"
+ -@erase "$(INTDIR)\deflate.obj"
+ -@erase "$(INTDIR)\gzio.obj"
+ -@erase "$(INTDIR)\inffast.obj"
+ -@erase "$(INTDIR)\inflate.obj"
+ -@erase "$(INTDIR)\inftrees.obj"
+ -@erase "$(INTDIR)\trees.obj"
+ -@erase "$(INTDIR)\uncompr.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\zutil.obj"
+ -@erase "$(OUTDIR)\libz.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"$(INTDIR)\libz.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libz.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)\libz.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\adler32.obj" \
+ "$(INTDIR)\compress.obj" \
+ "$(INTDIR)\crc32.obj" \
+ "$(INTDIR)\deflate.obj" \
+ "$(INTDIR)\gzio.obj" \
+ "$(INTDIR)\inffast.obj" \
+ "$(INTDIR)\inflate.obj" \
+ "$(INTDIR)\inftrees.obj" \
+ "$(INTDIR)\trees.obj" \
+ "$(INTDIR)\uncompr.obj" \
+ "$(INTDIR)\zutil.obj"
+
+"$(OUTDIR)\libz.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "libz - Win32 Debug"
+
+OUTDIR=.\WinDebug
+INTDIR=.\WinDebug
+# Begin Custom Macros
+OutDir=.\WinDebug
+# End Custom Macros
+
+ALL : "$(OUTDIR)\libz.lib"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\adler32.obj"
+ -@erase "$(INTDIR)\compress.obj"
+ -@erase "$(INTDIR)\crc32.obj"
+ -@erase "$(INTDIR)\deflate.obj"
+ -@erase "$(INTDIR)\gzio.obj"
+ -@erase "$(INTDIR)\inffast.obj"
+ -@erase "$(INTDIR)\inflate.obj"
+ -@erase "$(INTDIR)\inftrees.obj"
+ -@erase "$(INTDIR)\trees.obj"
+ -@erase "$(INTDIR)\uncompr.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\zutil.obj"
+ -@erase "$(OUTDIR)\libz.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fp"$(INTDIR)\libz.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libz.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)\libz.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\adler32.obj" \
+ "$(INTDIR)\compress.obj" \
+ "$(INTDIR)\crc32.obj" \
+ "$(INTDIR)\deflate.obj" \
+ "$(INTDIR)\gzio.obj" \
+ "$(INTDIR)\inffast.obj" \
+ "$(INTDIR)\inflate.obj" \
+ "$(INTDIR)\inftrees.obj" \
+ "$(INTDIR)\trees.obj" \
+ "$(INTDIR)\uncompr.obj" \
+ "$(INTDIR)\zutil.obj"
+
+"$(OUTDIR)\libz.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("libz.dep")
+!INCLUDE "libz.dep"
+!ELSE
+!MESSAGE Warning: cannot find "libz.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "libz - Win32 Release" || "$(CFG)" == "libz - Win32 Debug"
+SOURCE=.\adler32.c
+
+"$(INTDIR)\adler32.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\compress.c
+
+"$(INTDIR)\compress.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\crc32.c
+
+"$(INTDIR)\crc32.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\deflate.c
+
+"$(INTDIR)\deflate.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\gzio.c
+
+"$(INTDIR)\gzio.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\inffast.c
+
+"$(INTDIR)\inffast.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\inflate.c
+
+"$(INTDIR)\inflate.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\inftrees.c
+
+"$(INTDIR)\inftrees.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\trees.c
+
+"$(INTDIR)\trees.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\uncompr.c
+
+"$(INTDIR)\uncompr.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\zutil.c
+
+"$(INTDIR)\zutil.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/zlib/make_vms.com b/zlib/make_vms.com
new file mode 100644
index 0000000..c2a1fb5
--- /dev/null
+++ b/zlib/make_vms.com
@@ -0,0 +1,461 @@
+$! make libz under VMS written by
+$! Martin P.J. Zinser
+$! <zinser@zinser.no-ip.info or zinser@sysdev.deutsche-boerse.com>
+$!
+$ on error then goto err_exit
+$!
+$!
+$! Just some general constants...
+$!
+$ true = 1
+$ false = 0
+$ tmpnam = "temp_" + f$getjpi("","pid")
+$ SAY = "WRITE SYS$OUTPUT"
+$!
+$! Setup variables holding "config" information
+$!
+$ Make = ""
+$ name = "Zlib"
+$ version = "?.?.?"
+$ v_string = "ZLIB_VERSION"
+$ v_file = "zlib.h"
+$ ccopt = ""
+$ lopts = ""
+$ linkonly = false
+$ optfile = name + ".opt"
+$ its_decc = false
+$ its_vaxc = false
+$ its_gnuc = false
+$ axp = f$getsyi("HW_MODEL").ge.1024
+$ s_case = false
+$! Check for MMK/MMS
+$!
+$ If F$Search ("Sys$System:MMS.EXE") .nes. "" Then Make = "MMS"
+$ If F$Type (MMK) .eqs. "STRING" Then Make = "MMK"
+$!
+$!
+$ gosub find_version
+$!
+$ gosub check_opts
+$!
+$! Look for the compiler used
+$!
+$ gosub check_compiler
+$ if its_decc
+$ then
+$ ccopt = "/prefix=all" + ccopt
+$ if f$trnlnm("SYS") .eqs. ""
+$ then
+$ if axp
+$ then
+$ define sys sys$library:
+$ else
+$ ccopt = "/decc" + ccopt
+$ define sys decc$library_include:
+$ endif
+$ endif
+$ endif
+$ if its_vaxc .or. its_gnuc
+$ then
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ endif
+$!
+$! Build the thing plain or with mms
+$!
+$ write sys$output "Compiling Zlib sources ..."
+$ if make.eqs.""
+$ then
+$ dele example.obj;*,minigzip.obj;*
+$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" -
+ adler32.c zlib.h zconf.h
+$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" -
+ compress.c zlib.h zconf.h
+$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" -
+ crc32.c zlib.h zconf.h
+$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" -
+ deflate.c deflate.h zutil.h zlib.h zconf.h
+$ CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" -
+ gzio.c zutil.h zlib.h zconf.h
+$ CALL MAKE infback.OBJ "CC ''CCOPT' infback" -
+ infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h
+$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" -
+ inffast.c zutil.h zlib.h zconf.h inffast.h
+$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" -
+ inflate.c zutil.h zlib.h zconf.h infblock.h
+$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" -
+ inftrees.c zutil.h zlib.h zconf.h inftrees.h
+$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" -
+ trees.c deflate.h zutil.h zlib.h zconf.h
+$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" -
+ uncompr.c zlib.h zconf.h
+$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" -
+ zutil.c zutil.h zlib.h zconf.h
+$ write sys$output "Building Zlib ..."
+$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ
+$ write sys$output "Building example..."
+$ CALL MAKE example.OBJ "CC ''CCOPT' example" -
+ example.c zlib.h zconf.h
+$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb
+$ if f$search("x11vms:xvmsutils.olb") .nes. ""
+$ then
+$ write sys$output "Building minigzip..."
+$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" -
+ minigzip.c zlib.h zconf.h
+$ call make minigzip.exe -
+ "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" -
+ minigzip.obj libz.olb
+$ endif
+$ else
+$ gosub crea_mms
+$ SAY "Make ''name' ''version' with ''Make' "
+$ 'make'
+$ endif
+$!
+$! Alpha gets a shareable image
+$!
+$ If axp
+$ Then
+$ gosub crea_olist
+$ write sys$output "Creating libzshr.exe"
+$ call anal_obj_axp modules.opt _link.opt
+$ if s_case
+$ then
+$ open/append optf modules.opt
+$ write optf "case_sensitive=YES"
+$ close optf
+$ endif
+$ LINK_'lopts'/SHARE=libzshr.exe modules.opt/opt,_link.opt/opt
+$ endif
+$ write sys$output "Zlib build completed"
+$ exit
+$CC_ERR:
+$ write sys$output "C compiler required to build ''name'"
+$ goto err_exit
+$ERR_EXIT:
+$ set message/facil/ident/sever/text
+$ write sys$output "Exiting..."
+$ exit 2
+$!
+$!
+$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8 What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$ Argument = P'arg
+$ If Argument .Eqs. "" Then Goto Exit
+$ El=0
+$Loop2:
+$ File = F$Element(El," ",Argument)
+$ If File .Eqs. " " Then Goto Endl
+$ AFile = ""
+$Loop3:
+$ OFile = AFile
+$ AFile = F$Search(File)
+$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$ Goto Loop3
+$NextEL:
+$ El = El + 1
+$ Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
+$!------------------------------------------------------------------------------
+$!
+$! Check command line options and set symbols accordingly
+$!
+$ CHECK_OPTS:
+$ i = 1
+$ OPT_LOOP:
+$ if i .lt. 9
+$ then
+$ cparm = f$edit(p'i',"upcase")
+$ if cparm .eqs. "DEBUG"
+$ then
+$ ccopt = ccopt + "/noopt/deb"
+$ lopts = lopts + "/deb"
+$ endif
+$ if f$locate("CCOPT=",cparm) .lt. f$length(cparm)
+$ then
+$ start = f$locate("=",cparm) + 1
+$ len = f$length(cparm) - start
+$ ccopt = ccopt + f$extract(start,len,cparm)
+$ if f$locate("AS_IS",f$edit(ccopt,"UPCASE")) .lt. f$length(ccopt) -
+ then s_case = true
+$ endif
+$ if cparm .eqs. "LINK" then linkonly = true
+$ if f$locate("LOPTS=",cparm) .lt. f$length(cparm)
+$ then
+$ start = f$locate("=",cparm) + 1
+$ len = f$length(cparm) - start
+$ lopts = lopts + f$extract(start,len,cparm)
+$ endif
+$ if f$locate("CC=",cparm) .lt. f$length(cparm)
+$ then
+$ start = f$locate("=",cparm) + 1
+$ len = f$length(cparm) - start
+$ cc_com = f$extract(start,len,cparm)
+ if (cc_com .nes. "DECC") .and. -
+ (cc_com .nes. "VAXC") .and. -
+ (cc_com .nes. "GNUC")
+$ then
+$ write sys$output "Unsupported compiler choice ''cc_com' ignored"
+$ write sys$output "Use DECC, VAXC, or GNUC instead"
+$ else
+$ if cc_com .eqs. "DECC" then its_decc = true
+$ if cc_com .eqs. "VAXC" then its_vaxc = true
+$ if cc_com .eqs. "GNUC" then its_gnuc = true
+$ endif
+$ endif
+$ if f$locate("MAKE=",cparm) .lt. f$length(cparm)
+$ then
+$ start = f$locate("=",cparm) + 1
+$ len = f$length(cparm) - start
+$ mmks = f$extract(start,len,cparm)
+$ if (mmks .eqs. "MMK") .or. (mmks .eqs. "MMS")
+$ then
+$ make = mmks
+$ else
+$ write sys$output "Unsupported make choice ''mmks' ignored"
+$ write sys$output "Use MMK or MMS instead"
+$ endif
+$ endif
+$ i = i + 1
+$ goto opt_loop
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Look for the compiler used
+$!
+$CHECK_COMPILER:
+$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc))
+$ then
+$ its_decc = (f$search("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "")
+$ its_vaxc = .not. its_decc .and. (F$Search("SYS$System:VAXC.Exe") .nes. "")
+$ its_gnuc = .not. (its_decc .or. its_vaxc) .and. (f$trnlnm("gnu_cc") .nes. "")
+$ endif
+$!
+$! Exit if no compiler available
+$!
+$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc))
+$ then goto CC_ERR
+$ else
+$ if its_decc then write sys$output "CC compiler check ... Compaq C"
+$ if its_vaxc then write sys$output "CC compiler check ... VAX C"
+$ if its_gnuc then write sys$output "CC compiler check ... GNU C"
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! If MMS/MMK are available dump out the descrip.mms if required
+$!
+$CREA_MMS:
+$ write sys$output "Creating descrip.mms..."
+$ create descrip.mms
+$ open/append out descrip.mms
+$ copy sys$input: out
+$ deck
+# descrip.mms: MMS description file for building zlib on VMS
+# written by Martin P.J. Zinser
+# <zinser@zinser.no-ip.info or zinser@sysdev.deutsche-boerse.com>
+
+OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj, infback.obj\
+ deflate.obj, trees.obj, zutil.obj, inflate.obj, \
+ inftrees.obj, inffast.obj
+
+$ eod
+$ write out "CFLAGS=", ccopt
+$ write out "LOPTS=", lopts
+$ copy sys$input: out
+$ deck
+
+all : example.exe minigzip.exe libz.olb
+ @ write sys$output " Example applications available"
+
+libz.olb : libz.olb($(OBJS))
+ @ write sys$output " libz available"
+
+example.exe : example.obj libz.olb
+ link $(LOPTS) example,libz.olb/lib
+
+minigzip.exe : minigzip.obj libz.olb
+ link $(LOPTS) minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib
+
+clean :
+ delete *.obj;*,libz.olb;*,*.opt;*,*.exe;*
+
+
+# Other dependencies.
+adler32.obj : adler32.c zutil.h zlib.h zconf.h
+compress.obj : compress.c zlib.h zconf.h
+crc32.obj : crc32.c zutil.h zlib.h zconf.h
+deflate.obj : deflate.c deflate.h zutil.h zlib.h zconf.h
+example.obj : example.c zlib.h zconf.h
+gzio.obj : gzio.c zutil.h zlib.h zconf.h
+inffast.obj : inffast.c zutil.h zlib.h zconf.h inftrees.h inffast.h
+inflate.obj : inflate.c zutil.h zlib.h zconf.h
+inftrees.obj : inftrees.c zutil.h zlib.h zconf.h inftrees.h
+minigzip.obj : minigzip.c zlib.h zconf.h
+trees.obj : trees.c deflate.h zutil.h zlib.h zconf.h
+uncompr.obj : uncompr.c zlib.h zconf.h
+zutil.obj : zutil.c zutil.h zlib.h zconf.h
+infback.obj : infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h
+$ eod
+$ close out
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Read list of core library sources from makefile.in and create options
+$! needed to build shareable image
+$!
+$CREA_OLIST:
+$ open/read min makefile.in
+$ open/write mod modules.opt
+$ src_check = "OBJS ="
+$MRLOOP:
+$ read/end=mrdone min rec
+$ if (f$extract(0,6,rec) .nes. src_check) then goto mrloop
+$ rec = rec - src_check
+$ gosub extra_filnam
+$ if (f$element(1,"\",rec) .eqs. "\") then goto mrdone
+$MRSLOOP:
+$ read/end=mrdone min rec
+$ gosub extra_filnam
+$ if (f$element(1,"\",rec) .nes. "\") then goto mrsloop
+$MRDONE:
+$ close min
+$ close mod
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Take record extracted in crea_olist and split it into single filenames
+$!
+$EXTRA_FILNAM:
+$ myrec = f$edit(rec - "\", "trim,compress")
+$ i = 0
+$FELOOP:
+$ srcfil = f$element(i," ", myrec)
+$ if (srcfil .nes. " ")
+$ then
+$ write mod f$parse(srcfil,,,"NAME"), ".obj"
+$ i = i + 1
+$ goto feloop
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Find current Zlib version number
+$!
+$FIND_VERSION:
+$ open/read h_in 'v_file'
+$hloop:
+$ read/end=hdone h_in rec
+$ rec = f$edit(rec,"TRIM")
+$ if (f$extract(0,1,rec) .nes. "#") then goto hloop
+$ rec = f$edit(rec - "#", "TRIM")
+$ if f$element(0," ",rec) .nes. "define" then goto hloop
+$ if f$element(1," ",rec) .eqs. v_string
+$ then
+$ version = 'f$element(2," ",rec)'
+$ goto hdone
+$ endif
+$ goto hloop
+$hdone:
+$ close h_in
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Analyze Object files for OpenVMS AXP to extract Procedure and Data
+$! information to build a symbol vector for a shareable image
+$! All the "brains" of this logic was suggested by Hartmut Becker
+$! (Hartmut.Becker@compaq.com). All the bugs were introduced by me
+$! (zinser@decus.de), so if you do have problem reports please do not
+$! bother Hartmut/HP, but get in touch with me
+$!
+$ ANAL_OBJ_AXP: Subroutine
+$ V = 'F$Verify(0)
+$ SAY := "WRITE_ SYS$OUTPUT"
+$
+$ IF F$SEARCH("''P1'") .EQS. ""
+$ THEN
+$ SAY "ANAL_OBJ_AXP-E-NOSUCHFILE: Error, inputfile ''p1' not available"
+$ goto exit_aa
+$ ENDIF
+$ IF "''P2'" .EQS. ""
+$ THEN
+$ SAY "ANAL_OBJ_AXP: Error, no output file provided"
+$ goto exit_aa
+$ ENDIF
+$
+$ open/read in 'p1
+$ create a.tmp
+$ open/append atmp a.tmp
+$ loop:
+$ read/end=end_loop in line
+$ f= f$search(line)
+$ if f .eqs. ""
+$ then
+$ write sys$output "ANAL_OBJ_AXP-w-nosuchfile, ''line'"
+$ goto loop
+$ endif
+$ define/user sys$output nl:
+$ define/user sys$error nl:
+$ anal/obj/gsd 'f /out=x.tmp
+$ open/read xtmp x.tmp
+$ XLOOP:
+$ read/end=end_xloop xtmp xline
+$ xline = f$edit(xline,"compress")
+$ write atmp xline
+$ goto xloop
+$ END_XLOOP:
+$ close xtmp
+$ goto loop
+$ end_loop:
+$ close in
+$ close atmp
+$ if f$search("a.tmp") .eqs. "" -
+ then $ exit
+$ ! all global definitions
+$ search a.tmp "symbol:","EGSY$V_DEF 1","EGSY$V_NORM 1"/out=b.tmp
+$ ! all procedures
+$ search b.tmp "EGSY$V_NORM 1"/wind=(0,1) /out=c.tmp
+$ search c.tmp "symbol:"/out=d.tmp
+$ define/user sys$output nl:
+$ edito/edt/command=sys$input d.tmp
+sub/symbol: "/symbol_vector=(/whole
+sub/"/=PROCEDURE)/whole
+exit
+$ ! all data
+$ search b.tmp "EGSY$V_DEF 1"/wind=(0,1) /out=e.tmp
+$ search e.tmp "symbol:"/out=f.tmp
+$ define/user sys$output nl:
+$ edito/edt/command=sys$input f.tmp
+sub/symbol: "/symbol_vector=(/whole
+sub/"/=DATA)/whole
+exit
+$ sort/nodupl d.tmp,f.tmp 'p2'
+$ delete a.tmp;*,b.tmp;*,c.tmp;*,d.tmp;*,e.tmp;*,f.tmp;*
+$ if f$search("x.tmp") .nes. "" -
+ then $ delete x.tmp;*
+$!
+$ EXIT_AA:
+$ if V then set verify
+$ endsubroutine
+$!------------------------------------------------------------------------------
diff --git a/zlib/minigzip.c b/zlib/minigzip.c
new file mode 100644
index 0000000..4524b96
--- /dev/null
+++ b/zlib/minigzip.c
@@ -0,0 +1,322 @@
+/* minigzip.c -- simulate gzip using the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * minigzip is a minimal implementation of the gzip utility. This is
+ * only an example of using zlib and isn't meant to replace the
+ * full-featured gzip. No attempt is made to deal with file systems
+ * limiting names to 14 or 8+3 characters, etc... Error checking is
+ * very limited. So use minigzip only for testing; use gzip for the
+ * real thing. On MSDOS, use only on file names without extension
+ * or in pipe mode.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifdef USE_MMAP
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <sys/stat.h>
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+#ifdef VMS
+# define unlink delete
+# define GZ_SUFFIX "-gz"
+#endif
+#ifdef RISCOS
+# define unlink remove
+# define GZ_SUFFIX "-gz"
+# define fileno(file) file->__file
+#endif
+#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fileno */
+#endif
+
+#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
+ extern int unlink OF((const char *));
+#endif
+
+#ifndef GZ_SUFFIX
+# define GZ_SUFFIX ".gz"
+#endif
+#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
+
+#define BUFLEN 16384
+#define MAX_NAME_LEN 1024
+
+#ifdef MAXSEG_64K
+# define local static
+ /* Needed for systems with limitation on stack size. */
+#else
+# define local
+#endif
+
+char *prog;
+
+void error OF((const char *msg));
+void gz_compress OF((FILE *in, gzFile out));
+#ifdef USE_MMAP
+int gz_compress_mmap OF((FILE *in, gzFile out));
+#endif
+void gz_uncompress OF((gzFile in, FILE *out));
+void file_compress OF((char *file, char *mode));
+void file_uncompress OF((char *file));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Display error message and exit
+ */
+void error(msg)
+ const char *msg;
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+/* ===========================================================================
+ * Compress input to output then close both files.
+ */
+
+void gz_compress(in, out)
+ FILE *in;
+ gzFile out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+#ifdef USE_MMAP
+ /* Try first compressing with mmap. If mmap fails (minigzip used in a
+ * pipe), use the normal fread loop.
+ */
+ if (gz_compress_mmap(in, out) == Z_OK) return;
+#endif
+ for (;;) {
+ len = (int)fread(buf, 1, sizeof(buf), in);
+ if (ferror(in)) {
+ perror("fread");
+ exit(1);
+ }
+ if (len == 0) break;
+
+ if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
+ }
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+}
+
+#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
+
+/* Try compressing the input file at once using mmap. Return Z_OK if
+ * if success, Z_ERRNO otherwise.
+ */
+int gz_compress_mmap(in, out)
+ FILE *in;
+ gzFile out;
+{
+ int len;
+ int err;
+ int ifd = fileno(in);
+ caddr_t buf; /* mmap'ed buffer for the entire input file */
+ off_t buf_len; /* length of the input file */
+ struct stat sb;
+
+ /* Determine the size of the file, needed for mmap: */
+ if (fstat(ifd, &sb) < 0) return Z_ERRNO;
+ buf_len = sb.st_size;
+ if (buf_len <= 0) return Z_ERRNO;
+
+ /* Now do the actual mmap: */
+ buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
+ if (buf == (caddr_t)(-1)) return Z_ERRNO;
+
+ /* Compress the whole file at once: */
+ len = gzwrite(out, (char *)buf, (unsigned)buf_len);
+
+ if (len != (int)buf_len) error(gzerror(out, &err));
+
+ munmap(buf, buf_len);
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+ return Z_OK;
+}
+#endif /* USE_MMAP */
+
+/* ===========================================================================
+ * Uncompress input to output then close both files.
+ */
+void gz_uncompress(in, out)
+ gzFile in;
+ FILE *out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+ for (;;) {
+ len = gzread(in, buf, sizeof(buf));
+ if (len < 0) error (gzerror(in, &err));
+ if (len == 0) break;
+
+ if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
+ error("failed fwrite");
+ }
+ }
+ if (fclose(out)) error("failed fclose");
+
+ if (gzclose(in) != Z_OK) error("failed gzclose");
+}
+
+
+/* ===========================================================================
+ * Compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+void file_compress(file, mode)
+ char *file;
+ char *mode;
+{
+ local char outfile[MAX_NAME_LEN];
+ FILE *in;
+ gzFile out;
+
+ strcpy(outfile, file);
+ strcat(outfile, GZ_SUFFIX);
+
+ in = fopen(file, "rb");
+ if (in == NULL) {
+ perror(file);
+ exit(1);
+ }
+ out = gzopen(outfile, mode);
+ if (out == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
+ exit(1);
+ }
+ gz_compress(in, out);
+
+ unlink(file);
+}
+
+
+/* ===========================================================================
+ * Uncompress the given file and remove the original.
+ */
+void file_uncompress(file)
+ char *file;
+{
+ local char buf[MAX_NAME_LEN];
+ char *infile, *outfile;
+ FILE *out;
+ gzFile in;
+ uInt len = (uInt)strlen(file);
+
+ strcpy(buf, file);
+
+ if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
+ infile = file;
+ outfile = buf;
+ outfile[len-3] = '\0';
+ } else {
+ outfile = file;
+ infile = buf;
+ strcat(infile, GZ_SUFFIX);
+ }
+ in = gzopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
+ exit(1);
+ }
+ out = fopen(outfile, "wb");
+ if (out == NULL) {
+ perror(file);
+ exit(1);
+ }
+
+ gz_uncompress(in, out);
+
+ unlink(infile);
+}
+
+
+/* ===========================================================================
+ * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...]
+ * -d : decompress
+ * -f : compress with Z_FILTERED
+ * -h : compress with Z_HUFFMAN_ONLY
+ * -r : compress with Z_RLE
+ * -1 to -9 : compression level
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int uncompr = 0;
+ gzFile file;
+ char outmode[20];
+
+ strcpy(outmode, "wb6 ");
+
+ prog = argv[0];
+ argc--, argv++;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "-d") == 0)
+ uncompr = 1;
+ else if (strcmp(*argv, "-f") == 0)
+ outmode[3] = 'f';
+ else if (strcmp(*argv, "-h") == 0)
+ outmode[3] = 'h';
+ else if (strcmp(*argv, "-r") == 0)
+ outmode[3] = 'R';
+ else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
+ (*argv)[2] == 0)
+ outmode[2] = (*argv)[1];
+ else
+ break;
+ argc--, argv++;
+ }
+ if (outmode[3] == ' ')
+ outmode[3] = 0;
+ if (argc == 0) {
+ SET_BINARY_MODE(stdin);
+ SET_BINARY_MODE(stdout);
+ if (uncompr) {
+ file = gzdopen(fileno(stdin), "rb");
+ if (file == NULL) error("can't gzdopen stdin");
+ gz_uncompress(file, stdout);
+ } else {
+ file = gzdopen(fileno(stdout), outmode);
+ if (file == NULL) error("can't gzdopen stdout");
+ gz_compress(stdin, file);
+ }
+ } else {
+ do {
+ if (uncompr) {
+ file_uncompress(*argv);
+ } else {
+ file_compress(*argv, outmode);
+ }
+ } while (argv++, --argc);
+ }
+ return 0;
+}
diff --git a/zlib/msdos/Makefile.bor b/zlib/msdos/Makefile.bor
new file mode 100644
index 0000000..8f8132d
--- /dev/null
+++ b/zlib/msdos/Makefile.bor
@@ -0,0 +1,109 @@
+# Makefile for zlib
+# Borland C++
+# Last updated: 15-Mar-2003
+
+# To use, do "make -fmakefile.bor"
+# To compile in small model, set below: MODEL=s
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to the LOC macro below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------ Turbo C++, Borland C++ ------------
+
+# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7)
+# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZLIB)
+
+# type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# memory model: one of s, m, c, l (small, medium, compact, large)
+MODEL=l
+
+# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version
+CC=bcc
+LD=bcc
+AR=tlib
+
+# compiler flags
+# replace "-O2" by "-O -G -a -d" for Turbo C++ 1.0
+CFLAGS=-O2 -Z -m$(MODEL) $(LOC)
+
+LDFLAGS=-m$(MODEL) -f-
+
+
+# variables
+ZLIB_LIB = zlib_$(MODEL).lib
+
+OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj
+OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj
+OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj
+
+
+# targets
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: example.c zlib.h zconf.h
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+
+
+# the command line is cut to fit in the MS-DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ -del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) $(OBJP1)
+ $(AR) $(ZLIB_LIB) $(OBJP2)
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+clean:
+ -del *.obj
+ -del *.lib
+ -del *.exe
+ -del zlib_*.bak
+ -del foo.gz
diff --git a/zlib/msdos/Makefile.dj2 b/zlib/msdos/Makefile.dj2
new file mode 100644
index 0000000..283d1d9
--- /dev/null
+++ b/zlib/msdos/Makefile.dj2
@@ -0,0 +1,104 @@
+# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.dj2; make test -fmakefile.dj2
+#
+# To install libz.a, zconf.h and zlib.h in the djgpp directories, type:
+#
+# make install -fmakefile.dj2
+#
+# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as
+# in the sample below if the pattern of the DJGPP distribution is to
+# be followed. Remember that, while <sp>'es around <=> are ignored in
+# makefiles, they are *not* in batch files or in djgpp.env.
+# - - - - -
+# [make]
+# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include
+# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib
+# BUTT=-m486
+# - - - - -
+# Alternately, these variables may be defined below, overriding the values
+# in djgpp.env, as
+# INCLUDE_PATH=c:\usr\include
+# LIBRARY_PATH=c:\usr\lib
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lz
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+check: test
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+libz.a: $(OBJS) $(OBJA)
+ $(AR) $@ $(OBJS) $(OBJA)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env .
+
+.PHONY : uninstall clean
+
+install: $(INCL) $(LIBS)
+ -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH)
+ -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH)
+ $(INSTALL) zlib.h $(INCLUDE_PATH)
+ $(INSTALL) zconf.h $(INCLUDE_PATH)
+ $(INSTALL) libz.a $(LIBRARY_PATH)
+
+uninstall:
+ $(RM) $(INCLUDE_PATH)\zlib.h
+ $(RM) $(INCLUDE_PATH)\zconf.h
+ $(RM) $(LIBRARY_PATH)\libz.a
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) libz.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/zlib/msdos/Makefile.emx b/zlib/msdos/Makefile.emx
new file mode 100644
index 0000000..ed4c31f
--- /dev/null
+++ b/zlib/msdos/Makefile.emx
@@ -0,0 +1,69 @@
+# Makefile for zlib. Modified for emx 0.9c by Chr. Spieler, 6/17/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.emx; make test -fmakefile.emx
+#
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) zlib.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/zlib/msdos/Makefile.msc b/zlib/msdos/Makefile.msc
new file mode 100644
index 0000000..b8fc665
--- /dev/null
+++ b/zlib/msdos/Makefile.msc
@@ -0,0 +1,106 @@
+# Makefile for zlib
+# Microsoft C 5.1 or later
+# Last updated: 19-Mar-2003
+
+# To use, do "make makefile.msc"
+# To compile in small model, set below: MODEL=S
+
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to the LOC macro below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Microsoft C 5.1 and later -------------
+
+# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7)
+# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZLIB)
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Memory model: one of S, M, C, L (small, medium, compact, large)
+MODEL=L
+
+CC=cl
+CFLAGS=-nologo -A$(MODEL) -G$(CPU_TYP) -W3 -Oait -Gs $(LOC)
+#-Ox generates bad code with MSC 5.1
+LIB_CFLAGS=-Zl $(CFLAGS)
+
+LD=link
+LDFLAGS=/noi/e/st:0x1500/noe/farcall/packcode
+# "/farcall/packcode" are only useful for `large code' memory models
+# but should be a "no-op" for small code models.
+
+
+# variables
+ZLIB_LIB = zlib_$(MODEL).lib
+
+OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj
+OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+
+
+# targets
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+.c.obj:
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+
+# the command line is cut to fit in the MS-DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ if exist $(ZLIB_LIB) del $(ZLIB_LIB)
+ lib $(ZLIB_LIB) $(OBJ1);
+ lib $(ZLIB_LIB) $(OBJ2);
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj,,,$(ZLIB_LIB);
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj,,,$(ZLIB_LIB);
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+clean:
+ -del *.obj
+ -del *.lib
+ -del *.exe
+ -del *.map
+ -del zlib_*.bak
+ -del foo.gz
diff --git a/zlib/msdos/Makefile.tc b/zlib/msdos/Makefile.tc
new file mode 100644
index 0000000..480750a
--- /dev/null
+++ b/zlib/msdos/Makefile.tc
@@ -0,0 +1,94 @@
+# Makefile for zlib
+# Turbo C 2.01, Turbo C++ 1.01
+# Last updated: 15-Mar-2003
+
+# To use, do "make -fmakefile.tc"
+# To compile in small model, set below: MODEL=s
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------ Turbo C 2.01, Turbo C++ 1.01 ------------
+MODEL=l
+CC=tcc
+LD=tcc
+AR=tlib
+# CFLAGS=-O2 -G -Z -m$(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+CFLAGS=-O2 -G -Z -m$(MODEL)
+LDFLAGS=-m$(MODEL) -f-
+
+
+# variables
+ZLIB_LIB = zlib_$(MODEL).lib
+
+OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj
+OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj
+OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj
+
+
+# targets
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: example.c zlib.h zconf.h
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+
+
+# the command line is cut to fit in the MS-DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ -del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) $(OBJP1)
+ $(AR) $(ZLIB_LIB) $(OBJP2)
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+clean:
+ -del *.obj
+ -del *.lib
+ -del *.exe
+ -del zlib_*.bak
+ -del foo.gz
diff --git a/zlib/old/Makefile.riscos b/zlib/old/Makefile.riscos
new file mode 100644
index 0000000..57e29d3
--- /dev/null
+++ b/zlib/old/Makefile.riscos
@@ -0,0 +1,151 @@
+# Project: zlib_1_03
+# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430
+# test works out-of-the-box, installs `somewhere' on demand
+
+# Toolflags:
+CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fah
+C++flags = -c -depend !Depend -IC: -throwback
+Linkflags = -aif -c++ -o $@
+ObjAsmflags = -throwback -NoCache -depend !Depend
+CMHGflags =
+LibFileflags = -c -l -o $@
+Squeezeflags = -o $@
+
+# change the line below to where _you_ want the library installed.
+libdest = lib:zlib
+
+# Final targets:
+@.lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \
+ @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \
+ @.o.uncompr @.o.zutil
+ LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \
+ @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \
+ @.o.trees @.o.uncompr @.o.zutil
+test: @.minigzip @.example @.lib
+ @copy @.lib @.libc A~C~DF~L~N~P~Q~RS~TV
+ @echo running tests: hang on.
+ @/@.minigzip -f -9 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -f -1 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -h -9 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -h -1 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -9 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -1 libc
+ @/@.minigzip -d libc-gz
+ @diff @.lib @.libc
+ @echo that should have reported '@.lib and @.libc identical' if you have diff.
+ @/@.example @.fred @.fred
+ @echo that will have given lots of hello!'s.
+
+@.minigzip: @.o.minigzip @.lib C:o.Stubs
+ Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs
+@.example: @.o.example @.lib C:o.Stubs
+ Link $(Linkflags) @.o.example @.lib C:o.Stubs
+
+install: @.lib
+ cdir $(libdest)
+ cdir $(libdest).h
+ @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV
+ @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV
+ @copy @.lib $(libdest).lib A~C~DF~L~N~P~Q~RS~TV
+ @echo okay, installed zlib in $(libdest)
+
+clean:; remove @.minigzip
+ remove @.example
+ remove @.libc
+ -wipe @.o.* F~r~cV
+ remove @.fred
+
+# User-editable dependencies:
+.c.o:
+ cc $(ccflags) -o $@ $<
+
+# Static dependencies:
+
+# Dynamic dependencies:
+o.example: c.example
+o.example: h.zlib
+o.example: h.zconf
+o.minigzip: c.minigzip
+o.minigzip: h.zlib
+o.minigzip: h.zconf
+o.adler32: c.adler32
+o.adler32: h.zlib
+o.adler32: h.zconf
+o.compress: c.compress
+o.compress: h.zlib
+o.compress: h.zconf
+o.crc32: c.crc32
+o.crc32: h.zlib
+o.crc32: h.zconf
+o.deflate: c.deflate
+o.deflate: h.deflate
+o.deflate: h.zutil
+o.deflate: h.zlib
+o.deflate: h.zconf
+o.gzio: c.gzio
+o.gzio: h.zutil
+o.gzio: h.zlib
+o.gzio: h.zconf
+o.infblock: c.infblock
+o.infblock: h.zutil
+o.infblock: h.zlib
+o.infblock: h.zconf
+o.infblock: h.infblock
+o.infblock: h.inftrees
+o.infblock: h.infcodes
+o.infblock: h.infutil
+o.infcodes: c.infcodes
+o.infcodes: h.zutil
+o.infcodes: h.zlib
+o.infcodes: h.zconf
+o.infcodes: h.inftrees
+o.infcodes: h.infblock
+o.infcodes: h.infcodes
+o.infcodes: h.infutil
+o.infcodes: h.inffast
+o.inffast: c.inffast
+o.inffast: h.zutil
+o.inffast: h.zlib
+o.inffast: h.zconf
+o.inffast: h.inftrees
+o.inffast: h.infblock
+o.inffast: h.infcodes
+o.inffast: h.infutil
+o.inffast: h.inffast
+o.inflate: c.inflate
+o.inflate: h.zutil
+o.inflate: h.zlib
+o.inflate: h.zconf
+o.inflate: h.infblock
+o.inftrees: c.inftrees
+o.inftrees: h.zutil
+o.inftrees: h.zlib
+o.inftrees: h.zconf
+o.inftrees: h.inftrees
+o.inftrees: h.inffixed
+o.infutil: c.infutil
+o.infutil: h.zutil
+o.infutil: h.zlib
+o.infutil: h.zconf
+o.infutil: h.infblock
+o.infutil: h.inftrees
+o.infutil: h.infcodes
+o.infutil: h.infutil
+o.trees: c.trees
+o.trees: h.deflate
+o.trees: h.zutil
+o.trees: h.zlib
+o.trees: h.zconf
+o.trees: h.trees
+o.uncompr: c.uncompr
+o.uncompr: h.zlib
+o.uncompr: h.zconf
+o.zutil: c.zutil
+o.zutil: h.zutil
+o.zutil: h.zlib
+o.zutil: h.zconf
diff --git a/zlib/old/README b/zlib/old/README
new file mode 100644
index 0000000..800bf07
--- /dev/null
+++ b/zlib/old/README
@@ -0,0 +1,3 @@
+This directory contains files that have not been updated for zlib 1.2.x
+
+(Volunteers are encouraged to help clean this up. Thanks.)
diff --git a/zlib/old/descrip.mms b/zlib/old/descrip.mms
new file mode 100644
index 0000000..7066da5
--- /dev/null
+++ b/zlib/old/descrip.mms
@@ -0,0 +1,48 @@
+# descrip.mms: MMS description file for building zlib on VMS
+# written by Martin P.J. Zinser <m.zinser@gsi.de>
+
+cc_defs =
+c_deb =
+
+.ifdef __DECC__
+pref = /prefix=all
+.endif
+
+OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\
+ deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\
+ inftrees.obj, infcodes.obj, infutil.obj, inffast.obj
+
+CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF)
+
+all : example.exe minigzip.exe
+ @ write sys$output " Example applications available"
+libz.olb : libz.olb($(OBJS))
+ @ write sys$output " libz available"
+
+example.exe : example.obj libz.olb
+ link example,libz.olb/lib
+
+minigzip.exe : minigzip.obj libz.olb
+ link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib
+
+clean :
+ delete *.obj;*,libz.olb;*
+
+
+# Other dependencies.
+adler32.obj : zutil.h zlib.h zconf.h
+compress.obj : zlib.h zconf.h
+crc32.obj : zutil.h zlib.h zconf.h
+deflate.obj : deflate.h zutil.h zlib.h zconf.h
+example.obj : zlib.h zconf.h
+gzio.obj : zutil.h zlib.h zconf.h
+infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.obj : zutil.h zlib.h zconf.h infblock.h
+inftrees.obj : zutil.h zlib.h zconf.h inftrees.h
+infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.obj : zlib.h zconf.h
+trees.obj : deflate.h zutil.h zlib.h zconf.h
+uncompr.obj : zlib.h zconf.h
+zutil.obj : zutil.h zlib.h zconf.h
diff --git a/zlib/old/os2/Makefile.os2 b/zlib/old/os2/Makefile.os2
new file mode 100644
index 0000000..a105aaa
--- /dev/null
+++ b/zlib/old/os2/Makefile.os2
@@ -0,0 +1,136 @@
+# Makefile for zlib under OS/2 using GCC (PGCC)
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# cp Makefile.os2 ..
+# cd ..
+# make -f Makefile.os2 test
+
+# This makefile will build a static library z.lib, a shared library
+# z.dll and a import library zdll.lib. You can use either z.lib or
+# zdll.lib by specifying either -lz or -lzdll on gcc's command line
+
+CC=gcc -Zomf -s
+
+CFLAGS=-O6 -Wall
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+#################### BUG WARNING: #####################
+## infcodes.c hits a bug in pgcc-1.0, so you have to use either
+## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem)
+## This bug is reportedly fixed in pgcc >1.0, but this was not tested
+CFLAGS+=-fno-force-mem
+
+LDFLAGS=-s -L. -lzdll -Zcrtdll
+LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll
+
+VER=1.1.0
+ZLIB=z.lib
+SHAREDLIB=z.dll
+SHAREDLIBIMP=zdll.lib
+LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP)
+
+AR=emxomfar cr
+IMPLIB=emximp
+RANLIB=echo
+TAR=tar
+SHELL=bash
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \
+ algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+ nt/Makefile.nt nt/zlib.dnt contrib/README.contrib contrib/*.txt \
+ contrib/asm386/*.asm contrib/asm386/*.c \
+ contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \
+ contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \
+ contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32
+
+all: example.exe minigzip.exe
+
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+$(ZLIB): $(OBJS)
+ $(AR) $@ $(OBJS)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+$(SHAREDLIB): $(OBJS) os2/z.def
+ $(LDSHARED) -o $@ $^
+
+$(SHAREDLIBIMP): os2/z.def
+ $(IMPLIB) -o $@ $^
+
+example.exe: example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip.exe: minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+clean:
+ rm -f *.o *~ example minigzip libz.a libz.so* foo.gz
+
+distclean: clean
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/zlib/old/os2/zlib.def b/zlib/old/os2/zlib.def
new file mode 100644
index 0000000..4c753f1
--- /dev/null
+++ b/zlib/old/os2/zlib.def
@@ -0,0 +1,51 @@
+;
+; Slightly modified version of ../nt/zlib.dnt :-)
+;
+
+LIBRARY Z
+DESCRIPTION "Zlib compression library for OS/2"
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+EXPORTS
+ adler32
+ compress
+ crc32
+ deflate
+ deflateCopy
+ deflateEnd
+ deflateInit2_
+ deflateInit_
+ deflateParams
+ deflateReset
+ deflateSetDictionary
+ gzclose
+ gzdopen
+ gzerror
+ gzflush
+ gzopen
+ gzread
+ gzwrite
+ inflate
+ inflateEnd
+ inflateInit2_
+ inflateInit_
+ inflateReset
+ inflateSetDictionary
+ inflateSync
+ uncompress
+ zlibVersion
+ gzprintf
+ gzputc
+ gzgetc
+ gzseek
+ gzrewind
+ gztell
+ gzeof
+ gzsetparams
+ zError
+ inflateSyncPoint
+ get_crc_table
+ compress2
+ gzputs
+ gzgets
diff --git a/zlib/old/visual-basic.txt b/zlib/old/visual-basic.txt
new file mode 100644
index 0000000..57efe58
--- /dev/null
+++ b/zlib/old/visual-basic.txt
@@ -0,0 +1,160 @@
+See below some functions declarations for Visual Basic.
+
+Frequently Asked Question:
+
+Q: Each time I use the compress function I get the -5 error (not enough
+ room in the output buffer).
+
+A: Make sure that the length of the compressed buffer is passed by
+ reference ("as any"), not by value ("as long"). Also check that
+ before the call of compress this length is equal to the total size of
+ the compressed buffer and not zero.
+
+
+From: "Jon Caruana" <jon-net@usa.net>
+Subject: Re: How to port zlib declares to vb?
+Date: Mon, 28 Oct 1996 18:33:03 -0600
+
+Got the answer! (I haven't had time to check this but it's what I got, and
+looks correct):
+
+He has the following routines working:
+ compress
+ uncompress
+ gzopen
+ gzwrite
+ gzread
+ gzclose
+
+Declares follow: (Quoted from Carlos Rios <c_rios@sonda.cl>, in Vb4 form)
+
+#If Win16 Then 'Use Win16 calls.
+Declare Function compress Lib "ZLIB.DLL" (ByVal compr As
+ String, comprLen As Any, ByVal buf As String, ByVal buflen
+ As Long) As Integer
+Declare Function uncompress Lib "ZLIB.DLL" (ByVal uncompr
+ As String, uncomprLen As Any, ByVal compr As String, ByVal
+ lcompr As Long) As Integer
+Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As
+ String, ByVal mode As String) As Long
+Declare Function gzread Lib "ZLIB.DLL" (ByVal file As
+ Long, ByVal uncompr As String, ByVal uncomprLen As Integer)
+ As Integer
+Declare Function gzwrite Lib "ZLIB.DLL" (ByVal file As
+ Long, ByVal uncompr As String, ByVal uncomprLen As Integer)
+ As Integer
+Declare Function gzclose Lib "ZLIB.DLL" (ByVal file As
+ Long) As Integer
+#Else
+Declare Function compress Lib "ZLIB32.DLL"
+ (ByVal compr As String, comprLen As Any, ByVal buf As
+ String, ByVal buflen As Long) As Integer
+Declare Function uncompress Lib "ZLIB32.DLL"
+ (ByVal uncompr As String, uncomprLen As Any, ByVal compr As
+ String, ByVal lcompr As Long) As Long
+Declare Function gzopen Lib "ZLIB32.DLL"
+ (ByVal file As String, ByVal mode As String) As Long
+Declare Function gzread Lib "ZLIB32.DLL"
+ (ByVal file As Long, ByVal uncompr As String, ByVal
+ uncomprLen As Long) As Long
+Declare Function gzwrite Lib "ZLIB32.DLL"
+ (ByVal file As Long, ByVal uncompr As String, ByVal
+ uncomprLen As Long) As Long
+Declare Function gzclose Lib "ZLIB32.DLL"
+ (ByVal file As Long) As Long
+#End If
+
+-Jon Caruana
+jon-net@usa.net
+Microsoft Sitebuilder Network Level 1 Member - HTML Writer's Guild Member
+
+
+Here is another example from Michael <michael_borgsys@hotmail.com> that he
+says conforms to the VB guidelines, and that solves the problem of not
+knowing the uncompressed size by storing it at the end of the file:
+
+'Calling the functions:
+'bracket meaning: <parameter> [optional] {Range of possible values}
+'Call subCompressFile(<path with filename to compress> [, <path with
+filename to write to>, [level of compression {1..9}]])
+'Call subUncompressFile(<path with filename to compress>)
+
+Option Explicit
+Private lngpvtPcnSml As Long 'Stores value for 'lngPercentSmaller'
+Private Const SUCCESS As Long = 0
+Private Const strFilExt As String = ".cpr"
+Private Declare Function lngfncCpr Lib "zlib.dll" Alias "compress2" (ByRef
+dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long,
+ByVal level As Integer) As Long
+Private Declare Function lngfncUcp Lib "zlib.dll" Alias "uncompress" (ByRef
+dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long)
+As Long
+
+Public Sub subCompressFile(ByVal strargOriFilPth As String, Optional ByVal
+strargCprFilPth As String, Optional ByVal intLvl As Integer = 9)
+ Dim strCprPth As String
+ Dim lngOriSiz As Long
+ Dim lngCprSiz As Long
+ Dim bytaryOri() As Byte
+ Dim bytaryCpr() As Byte
+ lngOriSiz = FileLen(strargOriFilPth)
+ ReDim bytaryOri(lngOriSiz - 1)
+ Open strargOriFilPth For Binary Access Read As #1
+ Get #1, , bytaryOri()
+ Close #1
+ strCprPth = IIf(strargCprFilPth = "", strargOriFilPth, strargCprFilPth)
+'Select file path and name
+ strCprPth = strCprPth & IIf(Right(strCprPth, Len(strFilExt)) =
+strFilExt, "", strFilExt) 'Add file extension if not exists
+ lngCprSiz = (lngOriSiz * 1.01) + 12 'Compression needs temporary a bit
+more space then original file size
+ ReDim bytaryCpr(lngCprSiz - 1)
+ If lngfncCpr(bytaryCpr(0), lngCprSiz, bytaryOri(0), lngOriSiz, intLvl) =
+SUCCESS Then
+ lngpvtPcnSml = (1# - (lngCprSiz / lngOriSiz)) * 100
+ ReDim Preserve bytaryCpr(lngCprSiz - 1)
+ Open strCprPth For Binary Access Write As #1
+ Put #1, , bytaryCpr()
+ Put #1, , lngOriSiz 'Add the the original size value to the end
+(last 4 bytes)
+ Close #1
+ Else
+ MsgBox "Compression error"
+ End If
+ Erase bytaryCpr
+ Erase bytaryOri
+End Sub
+
+Public Sub subUncompressFile(ByVal strargFilPth As String)
+ Dim bytaryCpr() As Byte
+ Dim bytaryOri() As Byte
+ Dim lngOriSiz As Long
+ Dim lngCprSiz As Long
+ Dim strOriPth As String
+ lngCprSiz = FileLen(strargFilPth)
+ ReDim bytaryCpr(lngCprSiz - 1)
+ Open strargFilPth For Binary Access Read As #1
+ Get #1, , bytaryCpr()
+ Close #1
+ 'Read the original file size value:
+ lngOriSiz = bytaryCpr(lngCprSiz - 1) * (2 ^ 24) _
+ + bytaryCpr(lngCprSiz - 2) * (2 ^ 16) _
+ + bytaryCpr(lngCprSiz - 3) * (2 ^ 8) _
+ + bytaryCpr(lngCprSiz - 4)
+ ReDim Preserve bytaryCpr(lngCprSiz - 5) 'Cut of the original size value
+ ReDim bytaryOri(lngOriSiz - 1)
+ If lngfncUcp(bytaryOri(0), lngOriSiz, bytaryCpr(0), lngCprSiz) = SUCCESS
+Then
+ strOriPth = Left(strargFilPth, Len(strargFilPth) - Len(strFilExt))
+ Open strOriPth For Binary Access Write As #1
+ Put #1, , bytaryOri()
+ Close #1
+ Else
+ MsgBox "Uncompression error"
+ End If
+ Erase bytaryCpr
+ Erase bytaryOri
+End Sub
+Public Property Get lngPercentSmaller() As Long
+ lngPercentSmaller = lngpvtPcnSml
+End Property
diff --git a/zlib/old/zlib.html b/zlib/old/zlib.html
new file mode 100644
index 0000000..8c1b190
--- /dev/null
+++ b/zlib/old/zlib.html
@@ -0,0 +1,971 @@
+<html>
+<head>
+ <title>
+ zlib general purpose compression library version 1.1.4
+ </title>
+</head>
+<body bgcolor="White" text="Black" vlink="Red" alink="Navy" link="Red">
+<!-- background="zlibbg.gif" -->
+
+<h1> zlib 1.1.4 Manual </h1>
+<hr>
+<a name="Contents"><h2>Contents</h2>
+<ol type="I">
+<li> <a href="#Prologue">Prologue</a>
+<li> <a href="#Introduction">Introduction</a>
+<li> <a href="#Utility functions">Utility functions</a>
+<li> <a href="#Basic functions">Basic functions</a>
+<li> <a href="#Advanced functions">Advanced functions</a>
+<li> <a href="#Constants">Constants</a>
+<li> <a href="#struct z_stream_s">struct z_stream_s</a>
+<li> <a href="#Checksum functions">Checksum functions</a>
+<li> <a href="#Misc">Misc</a>
+</ol>
+<hr>
+<a name="Prologue"><h2> Prologue </h2>
+ 'zlib' general purpose compression library version 1.1.4, March 11th, 2002
+ <p>
+ Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
+ <p>
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ <p>
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ <ol>
+ <li> The origin of this software must not be misrepresented ; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ <li> Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ <li> This notice may not be removed or altered from any source distribution.
+ </ol>
+
+ <dl>
+ <dt>Jean-loup Gailly
+ <dd><a href="mailto:jloup@gzip.org">jloup@gzip.org</a>
+ <dt>Mark Adler
+ <dd><a href="mailto:madler@alumni.caltech.edu">madler@alumni.caltech.edu</a>
+ </dl>
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files
+ <a href="ftp://ds.internic.net/rfc/rfc1950.txt">
+ ftp://ds.internic.net/rfc/rfc1950.txt </a>
+ (zlib format),
+ <a href="ftp://ds.internic.net/rfc/rfc1951.txt">
+ rfc1951.txt </a>
+ (<a href="#deflate">deflate</a> format) and
+ <a href="ftp://ds.internic.net/rfc/rfc1952.txt">
+ rfc1952.txt </a>
+ (gzip format).
+ <p>
+ This manual is converted from zlib.h by
+ <a href="mailto:piaip@csie.ntu.edu.tw"> piaip </a>
+ <p>
+ Visit <a href="http://ftp.cdrom.com/pub/infozip/zlib/">
+ http://ftp.cdrom.com/pub/infozip/zlib/</a>
+ for the official zlib web page.
+ <p>
+
+<hr>
+<a name="Introduction"><h2> Introduction </h2>
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+ <p>
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+ <p>
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio.
+ <p>
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+ <p>
+
+<hr>
+<a name="Utility functions"><h2> Utility functions </h2>
+ The following utility functions are implemented on top of the
+ <a href="#Basic functions">basic stream-oriented functions</a>.
+ To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+<h3> Function list </h3>
+<ul>
+<li> int <a href="#compress">compress</a> (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
+<li> int <a href="#compress2">compress2</a> (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level);
+<li> int <a href="#uncompress">uncompress</a> (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
+<li> typedef voidp gzFile;
+<li> gzFile <a href="#gzopen">gzopen</a> (const char *path, const char *mode);
+<li> gzFile <a href="#gzdopen">gzdopen</a> (int fd, const char *mode);
+<li> int <a href="#gzsetparams">gzsetparams</a> (gzFile file, int level, int strategy);
+<li> int <a href="#gzread">gzread</a> (gzFile file, voidp buf, unsigned len);
+<li> int <a href="#gzwrite">gzwrite</a> (gzFile file, const voidp buf, unsigned len);
+<li> int VA <a href="#gzprintf">gzprintf</a> (gzFile file, const char *format, ...);
+<li> int <a href="#gzputs">gzputs</a> (gzFile file, const char *s);
+<li> char * <a href="#gzgets">gzgets</a> (gzFile file, char *buf, int len);
+<li> int <a href="#gzputc">gzputc</a> (gzFile file, int c);
+<li> int <a href="#gzgetc">gzgetc</a> (gzFile file);
+<li> int <a href="#gzflush">gzflush</a> (gzFile file, int flush);
+<li> z_off_t <a href="#gzseek">gzseek</a> (gzFile file, z_off_t offset, int whence);
+<li> z_off_t <a href="#gztell">gztell</a> (gzFile file);
+<li> int <a href="#gzrewind">gzrewind</a> (gzFile file);
+<li> int <a href="#gzeof">gzeof</a> (gzFile file);
+<li> int <a href="#gzclose">gzclose</a> (gzFile file);
+<li> const char * <a href="#gzerror">gzerror</a> (gzFile file, int *errnum);
+</ul>
+<h3> Function description </h3>
+<dl>
+<font color="Blue"><dt> int <a name="compress">compress</a> (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);</font>
+<dd>
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.<p>
+ This function can be used to <a href="#compress">compress</a> a whole file at once if the
+ input file is mmap'ed.<p>
+ <a href="#compress">compress</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not
+ enough memory, <a href="#Z_BUF_ERROR">Z_BUF_ERROR</a> if there was not enough room in the output
+ buffer.<p>
+
+<font color="Blue"><dt> int <a name="compress2">compress2</a> (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level);</font>
+<dd>
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in <a href="#deflateInit">deflateInit</a>. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+ <p>
+
+ <a href="#compress2">compress2</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not enough
+ memory, <a href="#Z_BUF_ERROR">Z_BUF_ERROR</a> if there was not enough room in the output buffer,
+ <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the level parameter is invalid.
+ <p>
+
+<font color="Blue"><dt> int <a name="uncompress">uncompress</a> (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);</font>
+<dd>
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer. <p>
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+ <p>
+
+ <a href="#uncompress">uncompress</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not
+ enough memory, <a href="#Z_BUF_ERROR">Z_BUF_ERROR</a> if there was not enough room in the output
+ buffer, or <a href="#Z_DATA_ERROR">Z_DATA_ERROR</a> if the input data was corrupted.
+ <p>
+
+<dt> typedef voidp gzFile;
+<dd> <p>
+
+<font color="Blue"><dt> gzFile <a name="gzopen">gzopen</a> (const char *path, const char *mode);</font>
+<dd>
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h". (See the description
+ of <a href="#deflateInit2">deflateInit2</a> for more information about the strategy parameter.)
+ <p>
+
+ <a href="#gzopen">gzopen</a> can be used to read a file which is not in gzip format ; in this
+ case <a href="#gzread">gzread</a> will directly read from the file without decompression.
+ <p>
+
+ <a href="#gzopen">gzopen</a> returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression <a href="#state">state</a> ; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a>).
+ <p>
+
+<font color="Blue"><dt> gzFile <a name="gzdopen">gzdopen</a> (int fd, const char *mode);</font>
+<dd>
+ <a href="#gzdopen">gzdopen</a>() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in <a href="#gzopen">gzopen</a>.
+ <p>
+ The next call of <a href="#gzclose">gzclose</a> on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use <a href="#gzdopen">gzdopen</a>(dup(fd), mode).
+ <p>
+ <a href="#gzdopen">gzdopen</a> returns NULL if there was insufficient memory to allocate
+ the (de)compression <a href="#state">state</a>.
+ <p>
+
+<font color="Blue"><dt> int <a name="gzsetparams">gzsetparams</a> (gzFile file, int level, int strategy);</font>
+<dd>
+ Dynamically update the compression level or strategy. See the description
+ of <a href="#deflateInit2">deflateInit2</a> for the meaning of these parameters.
+ <p>
+ <a href="#gzsetparams">gzsetparams</a> returns <a href="#Z_OK">Z_OK</a> if success, or <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the file was not
+ opened for writing.
+ <p>
+
+<font color="Blue"><dt> int <a name="gzread">gzread</a> (gzFile file, voidp buf, unsigned len);</font>
+<dd>
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, <a href="#gzread">gzread</a> copies the given number
+ of bytes into the buffer.
+ <p>
+ <a href="#gzread">gzread</a> returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error).
+ <p>
+
+<font color="Blue"><dt> int <a name="gzwrite">gzwrite</a> (gzFile file, const voidp buf, unsigned len);</font>
+<dd>
+ Writes the given number of uncompressed bytes into the compressed file.
+ <a href="#gzwrite">gzwrite</a> returns the number of uncompressed bytes actually written
+ (0 in case of error).
+ <p>
+
+<font color="Blue"><dt> int VA <a name="gzprintf">gzprintf</a> (gzFile file, const char *format, ...);</font>
+<dd>
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. <a href="#gzprintf">gzprintf</a> returns the number of
+ uncompressed bytes actually written (0 in case of error).
+ <p>
+
+<font color="Blue"><dt> int <a name="gzputs">gzputs</a> (gzFile file, const char *s);</font>
+<dd>
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ <p>
+ <a href="#gzputs">gzputs</a> returns the number of characters written, or -1 in case of error.
+ <p>
+
+<font color="Blue"><dt> char * <a name="gzgets">gzgets</a> (gzFile file, char *buf, int len);</font>
+<dd>
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ <p>
+ <a href="#gzgets">gzgets</a> returns buf, or <a href="#Z_NULL">Z_NULL</a> in case of error.
+ <p>
+
+<font color="Blue"><dt> int <a name="gzputc">gzputc</a> (gzFile file, int c);</font>
+<dd>
+ Writes c, converted to an unsigned char, into the compressed file.
+ <a href="#gzputc">gzputc</a> returns the value that was written, or -1 in case of error.
+ <p>
+
+<font color="Blue"><dt> int <a name="gzgetc">gzgetc</a> (gzFile file);</font>
+<dd>
+ Reads one byte from the compressed file. <a href="#gzgetc">gzgetc</a> returns this byte
+ or -1 in case of end of file or error.
+ <p>
+
+<font color="Blue"><dt> int <a name="gzflush">gzflush</a> (gzFile file, int flush);</font>
+<dd>
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the <a href="#deflate">deflate</a>() function. The return value is the zlib
+ error number (see function <a href="#gzerror">gzerror</a> below). <a href="#gzflush">gzflush</a> returns <a href="#Z_OK">Z_OK</a> if
+ the flush parameter is <a href="#Z_FINISH">Z_FINISH</a> and all output could be flushed.
+ <p>
+ <a href="#gzflush">gzflush</a> should be called only when strictly necessary because it can
+ degrade compression.
+ <p>
+
+<font color="Blue"><dt> z_off_t <a name="gzseek">gzseek</a> (gzFile file, z_off_t offset, int whence);</font>
+<dd>
+ Sets the starting position for the next <a href="#gzread">gzread</a> or <a href="#gzwrite">gzwrite</a> on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ <p>
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported ; <a href="#gzseek">gzseek</a> then compresses a sequence of zeroes up to the new
+ starting position.
+ <p>
+ <a href="#gzseek">gzseek</a> returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+ <p>
+
+<font color="Blue"><dt> int <a name="gzrewind">gzrewind</a> (gzFile file);</font>
+<dd>
+ Rewinds the given file. This function is supported only for reading.
+ <p>
+ <a href="#gzrewind">gzrewind</a>(file) is equivalent to (int)<a href="#gzseek">gzseek</a>(file, 0L, SEEK_SET)
+ <p>
+
+<font color="Blue"><dt> z_off_t <a name="gztell">gztell</a> (gzFile file);</font>
+<dd>
+ Returns the starting position for the next <a href="#gzread">gzread</a> or <a href="#gzwrite">gzwrite</a> on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+ <p>
+
+ <a href="#gztell">gztell</a>(file) is equivalent to <a href="#gzseek">gzseek</a>(file, 0L, SEEK_CUR)
+ <p>
+
+<font color="Blue"><dt> int <a name="gzeof">gzeof</a> (gzFile file);</font>
+<dd>
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+ <p>
+
+<font color="Blue"><dt> int <a name="gzclose">gzclose</a> (gzFile file);</font>
+<dd>
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression <a href="#state">state</a>. The return value is the zlib
+ error number (see function <a href="#gzerror">gzerror</a> below).
+ <p>
+
+<font color="Blue"><dt> const char * <a name="gzerror">gzerror</a> (gzFile file, int *errnum);</font>
+<dd>
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to <a href="#Z_ERRNO">Z_ERRNO</a> and the application may consult errno
+ to get the exact error code.
+ <p>
+</dl>
+<hr>
+<a name="Basic functions"><h2> Basic functions </h2>
+<h3> Function list </h3>
+<ul>
+<li> const char * <a href="#zlibVersion">zlibVersion</a> (void);
+<li> int <a href="#deflateInit">deflateInit</a> (<a href="#z_streamp">z_streamp</a> strm, int level);
+<li> int <a href="#deflate">deflate</a> (<a href="#z_streamp">z_streamp</a> strm, int flush);
+<li> int <a href="#deflateEnd">deflateEnd</a> (<a href="#z_streamp">z_streamp</a> strm);
+<li> int <a href="#inflateInit">inflateInit</a> (<a href="#z_streamp">z_streamp</a> strm);
+<li> int <a href="#inflate">inflate</a> (<a href="#z_streamp">z_streamp</a> strm, int flush);
+<li> int <a href="#inflateEnd">inflateEnd</a> (<a href="#z_streamp">z_streamp</a> strm);
+</ul>
+
+<h3> Function description </h3>
+<dl>
+<font color="Blue"><dt> const char * <a name="zlibVersion">zlibVersion</a> (void);</font>
+<dd> The application can compare <a href="#zlibVersion">zlibVersion</a> and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by <a href="#deflateInit">deflateInit</a> and <a href="#inflateInit">inflateInit</a>.
+ <p>
+
+<font color="Blue"><dt> int <a name="deflateInit">deflateInit</a> (<a href="#z_streamp">z_streamp</a> strm, int level);</font>
+<dd>
+ Initializes the internal stream <a href="#state">state</a> for compression. The fields
+ <a href="#zalloc">zalloc</a>, <a href="#zfree">zfree</a> and <a href="#opaque">opaque</a> must be initialized before by the caller.
+ If <a href="#zalloc">zalloc</a> and <a href="#zfree">zfree</a> are set to <a href="#Z_NULL">Z_NULL</a>, <a href="#deflateInit">deflateInit</a> updates them to
+ use default allocation functions.
+ <p>
+
+ The compression level must be <a href="#Z_DEFAULT_COMPRESSION">Z_DEFAULT_COMPRESSION</a>, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ <p>
+
+ <a href="#Z_DEFAULT_COMPRESSION">Z_DEFAULT_COMPRESSION</a> requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+ <p>
+
+ <a href="#deflateInit">deflateInit</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not
+ enough memory, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if level is not a valid compression level,
+ <a href="#Z_VERSION_ERROR">Z_VERSION_ERROR</a> if the zlib library version (<a href="#zlib_version">zlib_version</a>) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ <a href="#msg">msg</a> is set to null if there is no error message. <a href="#deflateInit">deflateInit</a> does not
+ perform any compression: this will be done by <a href="#deflate">deflate</a>().
+ <p>
+
+<font color="Blue"><dt> int <a name="deflate">deflate</a> (<a href="#z_streamp">z_streamp</a> strm, int flush);</font>
+<dd>
+ <a href="#deflate">deflate</a> compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.<p>
+
+ The detailed semantics are as follows. <a href="#deflate">deflate</a> performs one or both of the
+ following actions:
+
+ <ul>
+ <li> Compress more input starting at <a href="#next_in">next_in</a> and update <a href="#next_in">next_in</a> and <a href="#avail_in">avail_in</a>
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), <a href="#next_in">next_in</a> and <a href="#avail_in">avail_in</a> are updated and
+ processing will resume at this point for the next call of <a href="#deflate">deflate</a>().
+
+ <li>
+ Provide more output starting at <a href="#next_out">next_out</a> and update <a href="#next_out">next_out</a> and <a href="#avail_out">avail_out</a>
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+ </ul> <p>
+
+ Before the call of <a href="#deflate">deflate</a>(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating <a href="#avail_in">avail_in</a> or <a href="#avail_out">avail_out</a> accordingly ; <a href="#avail_out">avail_out</a>
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (<a href="#avail_out">avail_out</a> == 0), or after each call of <a href="#deflate">deflate</a>(). If <a href="#deflate">deflate</a> returns <a href="#Z_OK">Z_OK</a>
+ and with zero <a href="#avail_out">avail_out</a>, it must be called again after making room in the
+ output buffer because there might be more output pending.
+ <p>
+
+ If the parameter flush is set to <a href="#Z_SYNC_FLUSH">Z_SYNC_FLUSH</a>, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ <a href="#avail_in">avail_in</a> is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+ <p>
+
+ If flush is set to <a href="#Z_FULL_FLUSH">Z_FULL_FLUSH</a>, all output is flushed as with
+ <a href="#Z_SYNC_FLUSH">Z_SYNC_FLUSH</a>, and the compression <a href="#state">state</a> is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using <a href="#Z_FULL_FLUSH">Z_FULL_FLUSH</a> too often can seriously degrade
+ the compression.
+ <p>
+
+ If <a href="#deflate">deflate</a> returns with <a href="#avail_out">avail_out</a> == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ <a href="#avail_out">avail_out</a>), until the flush is complete (<a href="#deflate">deflate</a> returns with non-zero
+ <a href="#avail_out">avail_out</a>).
+ <p>
+
+ If the parameter flush is set to <a href="#Z_FINISH">Z_FINISH</a>, pending input is processed,
+ pending output is flushed and <a href="#deflate">deflate</a> returns with <a href="#Z_STREAM_END">Z_STREAM_END</a> if there
+ was enough output space ; if <a href="#deflate">deflate</a> returns with <a href="#Z_OK">Z_OK</a>, this function must be
+ called again with <a href="#Z_FINISH">Z_FINISH</a> and more output space (updated <a href="#avail_out">avail_out</a>) but no
+ more input data, until it returns with <a href="#Z_STREAM_END">Z_STREAM_END</a> or an error. After
+ <a href="#deflate">deflate</a> has returned <a href="#Z_STREAM_END">Z_STREAM_END</a>, the only possible operations on the
+ stream are <a href="#deflateReset">deflateReset</a> or <a href="#deflateEnd">deflateEnd</a>.
+ <p>
+
+ <a href="#Z_FINISH">Z_FINISH</a> can be used immediately after <a href="#deflateInit">deflateInit</a> if all the compression
+ is to be done in a single step. In this case, <a href="#avail_out">avail_out</a> must be at least
+ 0.1% larger than <a href="#avail_in">avail_in</a> plus 12 bytes. If <a href="#deflate">deflate</a> does not return
+ <a href="#Z_STREAM_END">Z_STREAM_END</a>, then it must be called again as described above.
+ <p>
+
+ <a href="#deflate">deflate</a>() sets strm-&gt <a href="#adler">adler</a> to the <a href="#adler32">adler32</a> checksum of all input read
+ so far (that is, <a href="#total_in">total_in</a> bytes).
+ <p>
+
+ <a href="#deflate">deflate</a>() may update <a href="#data_type">data_type</a> if it can make a good guess about
+ the input data type (<a href="#Z_ASCII">Z_ASCII</a> or <a href="#Z_BINARY">Z_BINARY</a>). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+ <p>
+
+ <a href="#deflate">deflate</a>() returns <a href="#Z_OK">Z_OK</a> if some progress has been made (more input
+ processed or more output produced), <a href="#Z_STREAM_END">Z_STREAM_END</a> if all input has been
+ consumed and all output has been produced (only when flush is set to
+ <a href="#Z_FINISH">Z_FINISH</a>), <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the stream <a href="#state">state</a> was inconsistent (for example
+ if <a href="#next_in">next_in</a> or <a href="#next_out">next_out</a> was NULL), <a href="#Z_BUF_ERROR">Z_BUF_ERROR</a> if no progress is possible
+ (for example <a href="#avail_in">avail_in</a> or <a href="#avail_out">avail_out</a> was zero).
+ <p>
+
+<font color="Blue"><dt> int <a name="deflateEnd">deflateEnd</a> (<a href="#z_streamp">z_streamp</a> strm);</font>
+<dd>
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+ <p>
+
+ <a href="#deflateEnd">deflateEnd</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the
+ stream <a href="#state">state</a> was inconsistent, <a href="#Z_DATA_ERROR">Z_DATA_ERROR</a> if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ <a href="#msg">msg</a> may be set but then points to a static string (which must not be
+ deallocated).
+ <p>
+
+<font color="Blue"><dt> int <a name="inflateInit">inflateInit</a> (<a href="#z_streamp">z_streamp</a> strm);</font>
+<dd>
+ Initializes the internal stream <a href="#state">state</a> for decompression. The fields
+ <a href="#next_in">next_in</a>, <a href="#avail_in">avail_in</a>, <a href="#zalloc">zalloc</a>, <a href="#zfree">zfree</a> and <a href="#opaque">opaque</a> must be initialized before by
+ the caller. If <a href="#next_in">next_in</a> is not <a href="#Z_NULL">Z_NULL</a> and <a href="#avail_in">avail_in</a> is large enough (the exact
+ value depends on the compression method), <a href="#inflateInit">inflateInit</a> determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly ; otherwise the allocation will be deferred to the first call of
+ <a href="#inflate">inflate</a>. If <a href="#zalloc">zalloc</a> and <a href="#zfree">zfree</a> are set to <a href="#Z_NULL">Z_NULL</a>, <a href="#inflateInit">inflateInit</a> updates them to
+ use default allocation functions.
+ <p>
+
+ <a href="#inflateInit">inflateInit</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not enough
+ memory, <a href="#Z_VERSION_ERROR">Z_VERSION_ERROR</a> if the zlib library version is incompatible with the
+ version assumed by the caller. <a href="#msg">msg</a> is set to null if there is no error
+ message. <a href="#inflateInit">inflateInit</a> does not perform any decompression apart from reading
+ the zlib header if present: this will be done by <a href="#inflate">inflate</a>(). (So <a href="#next_in">next_in</a> and
+ <a href="#avail_in">avail_in</a> may be modified, but <a href="#next_out">next_out</a> and <a href="#avail_out">avail_out</a> are unchanged.)
+ <p>
+
+<font color="Blue"><dt> int <a name="inflate">inflate</a> (<a href="#z_streamp">z_streamp</a> strm, int flush);</font>
+<dd>
+ <a href="#inflate">inflate</a> decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may some
+ introduce some output latency (reading input without producing any output)
+ except when forced to flush.
+ <p>
+
+ The detailed semantics are as follows. <a href="#inflate">inflate</a> performs one or both of the
+ following actions:
+
+ <ul>
+ <li> Decompress more input starting at <a href="#next_in">next_in</a> and update <a href="#next_in">next_in</a> and <a href="#avail_in">avail_in</a>
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), <a href="#next_in">next_in</a> is updated and processing
+ will resume at this point for the next call of <a href="#inflate">inflate</a>().
+
+ <li> Provide more output starting at <a href="#next_out">next_out</a> and update <a href="#next_out">next_out</a> and
+ <a href="#avail_out">avail_out</a> accordingly. <a href="#inflate">inflate</a>() provides as much output as possible,
+ until there is no more input data or no more space in the output buffer
+ (see below about the flush parameter).
+ </ul> <p>
+
+ Before the call of <a href="#inflate">inflate</a>(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (<a href="#avail_out">avail_out</a> == 0), or after each
+ call of <a href="#inflate">inflate</a>(). If <a href="#inflate">inflate</a> returns <a href="#Z_OK">Z_OK</a> and with zero <a href="#avail_out">avail_out</a>, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+ <p>
+
+ If the parameter flush is set to <a href="#Z_SYNC_FLUSH">Z_SYNC_FLUSH</a>, <a href="#inflate">inflate</a> flushes as much
+ output as possible to the output buffer. The flushing behavior of <a href="#inflate">inflate</a> is
+ not specified for values of the flush parameter other than <a href="#Z_SYNC_FLUSH">Z_SYNC_FLUSH</a>
+ and <a href="#Z_FINISH">Z_FINISH</a>, but the current implementation actually flushes as much output
+ as possible anyway.
+ <p>
+
+ <a href="#inflate">inflate</a>() should normally be called until it returns <a href="#Z_STREAM_END">Z_STREAM_END</a> or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of <a href="#inflate">inflate</a>), the parameter flush should be set to
+ <a href="#Z_FINISH">Z_FINISH</a>. In this case all pending input is processed and all pending
+ output is flushed ; <a href="#avail_out">avail_out</a> must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be <a href="#inflateEnd">inflateEnd</a> to deallocate the decompression <a href="#state">state</a>. The use of <a href="#Z_FINISH">Z_FINISH</a>
+ is never required, but can be used to inform <a href="#inflate">inflate</a> that a faster routine
+ may be used for the single <a href="#inflate">inflate</a>() call.
+ <p>
+
+ If a preset dictionary is needed at this point (see <a href="#inflateSetDictionary">inflateSetDictionary</a>
+ below), <a href="#inflate">inflate</a> sets strm-<a href="#adler">adler</a> to the <a href="#adler32">adler32</a> checksum of the
+ dictionary chosen by the compressor and returns <a href="#Z_NEED_DICT">Z_NEED_DICT</a> ; otherwise
+ it sets strm-&gt <a href="#adler">adler</a> to the <a href="#adler32">adler32</a> checksum of all output produced
+ so far (that is, <a href="#total_out">total_out</a> bytes) and returns <a href="#Z_OK">Z_OK</a>, <a href="#Z_STREAM_END">Z_STREAM_END</a> or
+ an error code as described below. At the end of the stream, <a href="#inflate">inflate</a>()
+ checks that its computed <a href="#adler32">adler32</a> checksum is equal to that saved by the
+ compressor and returns <a href="#Z_STREAM_END">Z_STREAM_END</a> only if the checksum is correct.
+ <p>
+
+ <a href="#inflate">inflate</a>() returns <a href="#Z_OK">Z_OK</a> if some progress has been made (more input processed
+ or more output produced), <a href="#Z_STREAM_END">Z_STREAM_END</a> if the end of the compressed data has
+ been reached and all uncompressed output has been produced, <a href="#Z_NEED_DICT">Z_NEED_DICT</a> if a
+ preset dictionary is needed at this point, <a href="#Z_DATA_ERROR">Z_DATA_ERROR</a> if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect
+ <a href="#adler32">adler32</a> checksum), <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the stream structure was inconsistent
+ (for example if <a href="#next_in">next_in</a> or <a href="#next_out">next_out</a> was NULL), <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not
+ enough memory, <a href="#Z_BUF_ERROR">Z_BUF_ERROR</a> if no progress is possible or if there was not
+ enough room in the output buffer when <a href="#Z_FINISH">Z_FINISH</a> is used. In the <a href="#Z_DATA_ERROR">Z_DATA_ERROR</a>
+ case, the application may then call <a href="#inflateSync">inflateSync</a> to look for a good
+ compression block.
+ <p>
+
+<font color="Blue"><dt> int <a name="inflateEnd">inflateEnd</a> (<a href="#z_streamp">z_streamp</a> strm);</font>
+<dd>
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+ <p>
+
+ <a href="#inflateEnd">inflateEnd</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the stream <a href="#state">state</a>
+ was inconsistent. In the error case, <a href="#msg">msg</a> may be set but then points to a
+ static string (which must not be deallocated).
+</dl>
+<hr>
+<a name="Advanced functions"><h2> Advanced functions </h2>
+ The following functions are needed only in some special applications.
+<h3> Function list </h3>
+<ul>
+<li> int <a href="#deflateInit2">deflateInit2</a> (<a href="#z_streamp">z_streamp</a> strm,
+<li> int <a href="#deflateSetDictionary">deflateSetDictionary</a> (<a href="#z_streamp">z_streamp</a> strm, const Bytef *dictionary, uInt dictLength);
+<li> int <a href="#deflateCopy">deflateCopy</a> (<a href="#z_streamp">z_streamp</a> dest, <a href="#z_streamp">z_streamp</a> source);
+<li> int <a href="#deflateReset">deflateReset</a> (<a href="#z_streamp">z_streamp</a> strm);
+<li> int <a href="#deflateParams">deflateParams</a> (<a href="#z_streamp">z_streamp</a> strm, int level, int strategy);
+<li> int <a href="#inflateInit2">inflateInit2</a> (<a href="#z_streamp">z_streamp</a> strm, int windowBits);
+<li> int <a href="#inflateSetDictionary">inflateSetDictionary</a> (<a href="#z_streamp">z_streamp</a> strm, const Bytef *dictionary, uInt dictLength);
+<li> int <a href="#inflateSync">inflateSync</a> (<a href="#z_streamp">z_streamp</a> strm);
+<li> int <a href="#inflateReset">inflateReset</a> (<a href="#z_streamp">z_streamp</a> strm);
+
+</ul>
+<h3> Function description </h3>
+<dl>
+<font color="Blue"><dt> int <a name="deflateInit2">deflateInit2</a> (<a href="#z_streamp">z_streamp</a> strm, int level, int method, int windowBits, int memLevel, int strategy);</font>
+
+<dd> This is another version of <a href="#deflateInit">deflateInit</a> with more compression options. The
+ fields <a href="#next_in">next_in</a>, <a href="#zalloc">zalloc</a>, <a href="#zfree">zfree</a> and <a href="#opaque">opaque</a> must be initialized before by
+ the caller.<p>
+
+ The method parameter is the compression method. It must be <a href="#Z_DEFLATED">Z_DEFLATED</a> in
+ this version of the library.<p>
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ <a href="#deflateInit">deflateInit</a> is used instead.<p>
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression <a href="#state">state</a>. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio ; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.<p>
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value <a href="#Z_DEFAULT_STRATEGY">Z_DEFAULT_STRATEGY</a> for normal data, <a href="#Z_FILTERED">Z_FILTERED</a> for data produced by a
+ filter (or predictor), or <a href="#Z_HUFFMAN_ONLY">Z_HUFFMAN_ONLY</a> to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to <a href="#compress">compress</a> them better. The effect of <a href="#Z_FILTERED">Z_FILTERED</a> is to force more
+ Huffman coding and less string matching ; it is somewhat intermediate
+ between Z_DEFAULT and <a href="#Z_HUFFMAN_ONLY">Z_HUFFMAN_ONLY</a>. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.<p>
+
+ <a href="#deflateInit2">deflateInit2</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not enough
+ memory, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if a parameter is invalid (such as an invalid
+ method). <a href="#msg">msg</a> is set to null if there is no error message. <a href="#deflateInit2">deflateInit2</a> does
+ not perform any compression: this will be done by <a href="#deflate">deflate</a>().<p>
+
+<font color="Blue"><dt> int <a name="deflateSetDictionary">deflateSetDictionary</a> (<a href="#z_streamp">z_streamp</a> strm, const Bytef *dictionary, uInt dictLength);</font>
+<dd>
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after <a href="#deflateInit">deflateInit</a>, <a href="#deflateInit2">deflateInit2</a> or <a href="#deflateReset">deflateReset</a>, before any
+ call of <a href="#deflate">deflate</a>. The compressor and decompressor must use exactly the same
+ dictionary (see <a href="#inflateSetDictionary">inflateSetDictionary</a>).<p>
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy ; the data can then be compressed better than
+ with the default empty dictionary.<p>
+
+ Depending on the size of the compression data structures selected by
+ <a href="#deflateInit">deflateInit</a> or <a href="#deflateInit2">deflateInit2</a>, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ <a href="#deflate">deflate</a> or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front.<p>
+
+ Upon return of this function, strm-&gt <a href="#adler">adler</a> is set to the Adler32 value
+ of the dictionary ; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)<p>
+
+ <a href="#deflateSetDictionary">deflateSetDictionary</a> returns <a href="#Z_OK">Z_OK</a> if success, or <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if a
+ parameter is invalid (such as NULL dictionary) or the stream <a href="#state">state</a> is
+ inconsistent (for example if <a href="#deflate">deflate</a> has already been called for this stream
+ or if the compression method is bsort). <a href="#deflateSetDictionary">deflateSetDictionary</a> does not
+ perform any compression: this will be done by <a href="#deflate">deflate</a>().<p>
+
+<font color="Blue"><dt> int <a name="deflateCopy">deflateCopy</a> (<a href="#z_streamp">z_streamp</a> dest, <a href="#z_streamp">z_streamp</a> source);</font>
+<dd>
+ Sets the destination stream as a complete copy of the source stream.<p>
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling <a href="#deflateEnd">deflateEnd</a>. Note that <a href="#deflateCopy">deflateCopy</a> duplicates the internal
+ compression <a href="#state">state</a> which can be quite large, so this strategy is slow and
+ can consume lots of memory.<p>
+
+ <a href="#deflateCopy">deflateCopy</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not
+ enough memory, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the source stream <a href="#state">state</a> was inconsistent
+ (such as <a href="#zalloc">zalloc</a> being NULL). <a href="#msg">msg</a> is left unchanged in both source and
+ destination.<p>
+
+<font color="Blue"><dt> int <a name="deflateReset">deflateReset</a> (<a href="#z_streamp">z_streamp</a> strm);</font>
+<dd> This function is equivalent to <a href="#deflateEnd">deflateEnd</a> followed by <a href="#deflateInit">deflateInit</a>,
+ but does not free and reallocate all the internal compression <a href="#state">state</a>.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by <a href="#deflateInit2">deflateInit2</a>.<p>
+
+ <a href="#deflateReset">deflateReset</a> returns <a href="#Z_OK">Z_OK</a> if success, or <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the source
+ stream <a href="#state">state</a> was inconsistent (such as <a href="#zalloc">zalloc</a> or <a href="#state">state</a> being NULL).<p>
+
+<font color="Blue"><dt> int <a name="deflateParams">deflateParams</a> (<a href="#z_streamp">z_streamp</a> strm, int level, int strategy);</font>
+<dd>
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in <a href="#deflateInit2">deflateInit2</a>. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of <a href="#deflate">deflate</a>().<p>
+
+ Before the call of <a href="#deflateParams">deflateParams</a>, the stream <a href="#state">state</a> must be set as for
+ a call of <a href="#deflate">deflate</a>(), since the currently available input may have to
+ be compressed and flushed. In particular, strm-&gt <a href="#avail_out">avail_out</a> must be
+ non-zero.<p>
+
+ <a href="#deflateParams">deflateParams</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the source
+ stream <a href="#state">state</a> was inconsistent or if a parameter was invalid, <a href="#Z_BUF_ERROR">Z_BUF_ERROR</a>
+ if strm-&gtavail_out was zero.<p>
+
+<font color="Blue"><dt> int <a name="inflateInit2">inflateInit2</a> (<a href="#z_streamp">z_streamp</a> strm, int windowBits);</font>
+
+<dd> This is another version of <a href="#inflateInit">inflateInit</a> with an extra parameter. The
+ fields <a href="#next_in">next_in</a>, <a href="#avail_in">avail_in</a>, <a href="#zalloc">zalloc</a>, <a href="#zfree">zfree</a> and <a href="#opaque">opaque</a> must be initialized
+ before by the caller.<p>
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if <a href="#inflateInit">inflateInit</a> is used
+ instead. If a compressed stream with a larger window size is given as
+ input, <a href="#inflate">inflate</a>() will return with the error code <a href="#Z_DATA_ERROR">Z_DATA_ERROR</a> instead of
+ trying to allocate a larger window.<p>
+
+ <a href="#inflateInit2">inflateInit2</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_MEM_ERROR">Z_MEM_ERROR</a> if there was not enough
+ memory, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if a parameter is invalid (such as a negative
+ memLevel). <a href="#msg">msg</a> is set to null if there is no error message. <a href="#inflateInit2">inflateInit2</a>
+ does not perform any decompression apart from reading the zlib header if
+ present: this will be done by <a href="#inflate">inflate</a>(). (So <a href="#next_in">next_in</a> and <a href="#avail_in">avail_in</a> may be
+ modified, but <a href="#next_out">next_out</a> and <a href="#avail_out">avail_out</a> are unchanged.)<p>
+
+<font color="Blue"><dt> int <a name="inflateSetDictionary">inflateSetDictionary</a> (<a href="#z_streamp">z_streamp</a> strm, const Bytef *dictionary, uInt dictLength);</font>
+<dd>
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of <a href="#inflate">inflate</a>
+ if this call returned <a href="#Z_NEED_DICT">Z_NEED_DICT</a>. The dictionary chosen by the compressor
+ can be determined from the Adler32 value returned by this call of
+ <a href="#inflate">inflate</a>. The compressor and decompressor must use exactly the same
+ dictionary (see <a href="#deflateSetDictionary">deflateSetDictionary</a>).<p>
+
+ <a href="#inflateSetDictionary">inflateSetDictionary</a> returns <a href="#Z_OK">Z_OK</a> if success, <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if a
+ parameter is invalid (such as NULL dictionary) or the stream <a href="#state">state</a> is
+ inconsistent, <a href="#Z_DATA_ERROR">Z_DATA_ERROR</a> if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). <a href="#inflateSetDictionary">inflateSetDictionary</a> does not
+ perform any decompression: this will be done by subsequent calls of
+ <a href="#inflate">inflate</a>().<p>
+
+<font color="Blue"><dt> int <a name="inflateSync">inflateSync</a> (<a href="#z_streamp">z_streamp</a> strm);</font>
+
+<dd> Skips invalid compressed data until a full flush point (see above the
+ description of <a href="#deflate">deflate</a> with <a href="#Z_FULL_FLUSH">Z_FULL_FLUSH</a>) can be found, or until all
+ available input is skipped. No output is provided.<p>
+
+ <a href="#inflateSync">inflateSync</a> returns <a href="#Z_OK">Z_OK</a> if a full flush point has been found, <a href="#Z_BUF_ERROR">Z_BUF_ERROR</a>
+ if no more input was provided, <a href="#Z_DATA_ERROR">Z_DATA_ERROR</a> if no flush point has been found,
+ or <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of <a href="#total_in">total_in</a> which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call <a href="#inflateSync">inflateSync</a>, providing more input each time,
+ until success or end of the input data.<p>
+
+<font color="Blue"><dt> int <a name="inflateReset">inflateReset</a> (<a href="#z_streamp">z_streamp</a> strm);</font>
+<dd>
+ This function is equivalent to <a href="#inflateEnd">inflateEnd</a> followed by <a href="#inflateInit">inflateInit</a>,
+ but does not free and reallocate all the internal decompression <a href="#state">state</a>.
+ The stream will keep attributes that may have been set by <a href="#inflateInit2">inflateInit2</a>.
+ <p>
+
+ <a href="#inflateReset">inflateReset</a> returns <a href="#Z_OK">Z_OK</a> if success, or <a href="#Z_STREAM_ERROR">Z_STREAM_ERROR</a> if the source
+ stream <a href="#state">state</a> was inconsistent (such as <a href="#zalloc">zalloc</a> or <a href="#state">state</a> being NULL).
+ <p>
+</dl>
+
+<hr>
+<a name="Checksum functions"><h2> Checksum functions </h2>
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+<h3> Function list </h3>
+<ul>
+<li> uLong <a href="#adler32">adler32</a> (uLong <a href="#adler">adler</a>, const Bytef *buf, uInt len);
+<li> uLong <a href="#crc32">crc32</a> (uLong crc, const Bytef *buf, uInt len);
+</ul>
+<h3> Function description </h3>
+<dl>
+<font color="Blue"><dt> uLong <a name="adler32">adler32</a> (uLong <a href="#adler">adler</a>, const Bytef *buf, uInt len);</font>
+<dd>
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ <p>
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+ <pre>
+
+ uLong <a href="#adler">adler</a> = <a href="#adler32">adler32</a>(0L, <a href="#Z_NULL">Z_NULL</a>, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ <a href="#adler">adler</a> = <a href="#adler32">adler32</a>(<a href="#adler">adler</a>, buffer, length);
+ }
+ if (<a href="#adler">adler</a> != original_adler) error();
+ </pre>
+
+<font color="Blue"><dt> uLong <a name="crc32">crc32</a> (uLong crc, const Bytef *buf, uInt len);</font>
+<dd>
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+ <pre>
+
+ uLong crc = <a href="#crc32">crc32</a>(0L, <a href="#Z_NULL">Z_NULL</a>, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = <a href="#crc32">crc32</a>(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+ </pre>
+</dl>
+<hr>
+<a name="struct z_stream_s"><h2> struct z_stream_s </h2>
+<font color="Blue">
+<a name="z_stream_s">
+<pre>
+typedef struct z_stream_s {
+ Bytef *<a name="next_in">next_in</a>; /* next input byte */
+ uInt <a name="avail_in">avail_in</a>; /* number of bytes available at <a href="#next_in">next_in</a> */
+ uLong <a name="total_in">total_in</a>; /* total nb of input bytes read so far */
+
+ Bytef *<a name="next_out">next_out</a>; /* next output byte should be put there */
+ uInt <a name="avail_out">avail_out</a>; /* remaining free space at <a href="#next_out">next_out</a> */
+ uLong <a name="total_out">total_out</a>; /* total nb of bytes output so far */
+
+ char *<a name="msg">msg</a>; /* last error message, NULL if no error */
+ struct internal_state FAR *<a name="state">state</a>; /* not visible by applications */
+
+ alloc_func <a name="zalloc">zalloc</a>; /* used to allocate the internal <a href="#state">state</a> */
+ free_func <a name="zfree">zfree</a>; /* used to free the internal <a href="#state">state</a> */
+ voidpf <a name="opaque">opaque</a>; /* private data object passed to <a href="#zalloc">zalloc</a> and <a href="#zfree">zfree</a> */
+
+ int <a name="data_type">data_type</a>; /* best guess about the data type: ascii or binary */
+ uLong <a name="adler">adler</a>; /* <a href="#adler32">adler32</a> value of the uncompressed data */
+ uLong <a name="reserved">reserved</a>; /* <a href="#reserved">reserved</a> for future use */
+} <a href="#z_stream_s">z_stream</a> ;
+
+typedef <a href="#z_stream_s">z_stream</a> FAR * <a name="z_streamp">z_streamp</a>; ÿ
+</pre>
+</font>
+ The application must update <a href="#next_in">next_in</a> and <a href="#avail_in">avail_in</a> when <a href="#avail_in">avail_in</a> has
+ dropped to zero. It must update <a href="#next_out">next_out</a> and <a href="#avail_out">avail_out</a> when <a href="#avail_out">avail_out</a>
+ has dropped to zero. The application must initialize <a href="#zalloc">zalloc</a>, <a href="#zfree">zfree</a> and
+ <a href="#opaque">opaque</a> before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application. <p>
+
+ The <a href="#opaque">opaque</a> value provided by the application will be passed as the first
+ parameter for calls of <a href="#zalloc">zalloc</a> and <a href="#zfree">zfree</a>. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ <a href="#opaque">opaque</a> value. <p>
+
+ <a href="#zalloc">zalloc</a> must return <a href="#Z_NULL">Z_NULL</a> if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, <a href="#zalloc">zalloc</a> and <a href="#zfree">zfree</a> must be
+ thread safe. <p>
+
+ On 16-bit systems, the functions <a href="#zalloc">zalloc</a> and <a href="#zfree">zfree</a> must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by <a href="#zalloc">zalloc</a> for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+ <p>
+
+ The fields <a href="#total_in">total_in</a> and <a href="#total_out">total_out</a> can be used for statistics or
+ progress reports. After compression, <a href="#total_in">total_in</a> holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step). <p>
+
+<hr>
+<a name="Constants"><h2> Constants </h2>
+<font color="Blue">
+<pre>
+#define <a name="Z_NO_FLUSH">Z_NO_FLUSH</a> 0
+#define <a name="Z_PARTIAL_FLUSH">Z_PARTIAL_FLUSH</a> 1
+ /* will be removed, use <a href="#Z_SYNC_FLUSH">Z_SYNC_FLUSH</a> instead */
+#define <a name="Z_SYNC_FLUSH">Z_SYNC_FLUSH</a> 2
+#define <a name="Z_FULL_FLUSH">Z_FULL_FLUSH</a> 3
+#define <a name="Z_FINISH">Z_FINISH</a> 4
+/* Allowed flush values ; see <a href="#deflate">deflate</a>() below for details */
+
+#define <a name="Z_OK">Z_OK</a> 0
+#define <a name="Z_STREAM_END">Z_STREAM_END</a> 1
+#define <a name="Z_NEED_DICT">Z_NEED_DICT</a> 2
+#define <a name="Z_ERRNO">Z_ERRNO</a> (-1)
+#define <a name="Z_STREAM_ERROR">Z_STREAM_ERROR</a> (-2)
+#define <a name="Z_DATA_ERROR">Z_DATA_ERROR</a> (-3)
+#define <a name="Z_MEM_ERROR">Z_MEM_ERROR</a> (-4)
+#define <a name="Z_BUF_ERROR">Z_BUF_ERROR</a> (-5)
+#define <a name="Z_VERSION_ERROR">Z_VERSION_ERROR</a> (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define <a name="Z_NO_COMPRESSION">Z_NO_COMPRESSION</a> 0
+#define <a name="Z_BEST_SPEED">Z_BEST_SPEED</a> 1
+#define <a name="Z_BEST_COMPRESSION">Z_BEST_COMPRESSION</a> 9
+#define <a name="Z_DEFAULT_COMPRESSION">Z_DEFAULT_COMPRESSION</a> (-1)
+/* compression levels */
+
+#define <a name="Z_FILTERED">Z_FILTERED</a> 1
+#define <a name="Z_HUFFMAN_ONLY">Z_HUFFMAN_ONLY</a> 2
+#define <a name="Z_DEFAULT_STRATEGY">Z_DEFAULT_STRATEGY</a> 0
+/* compression strategy ; see <a href="#deflateInit2">deflateInit2</a>() below for details */
+
+#define <a name="Z_BINARY">Z_BINARY</a> 0
+#define <a name="Z_ASCII">Z_ASCII</a> 1
+#define <a name="Z_UNKNOWN">Z_UNKNOWN</a> 2
+/* Possible values of the <a href="#data_type">data_type</a> field */
+
+#define <a name="Z_DEFLATED">Z_DEFLATED</a> 8
+/* The <a href="#deflate">deflate</a> compression method (the only one supported in this version) */
+
+#define <a name="Z_NULL">Z_NULL</a> 0 /* for initializing <a href="#zalloc">zalloc</a>, <a href="#zfree">zfree</a>, <a href="#opaque">opaque</a> */
+
+#define <a name="zlib_version">zlib_version</a> <a href="#zlibVersion">zlibVersion</a>()
+/* for compatibility with versions less than 1.0.2 */
+</pre>
+</font>
+
+<hr>
+<a name="Misc"><h2> Misc </h2>
+ <a href="#deflateInit">deflateInit</a> and <a href="#inflateInit">inflateInit</a> are macros to allow checking the zlib version
+ and the compiler's view of <a href="#z_stream_s">z_stream</a>.
+ <p>
+ Other functions:
+ <dl>
+ <font color="Blue"><dt> const char * <a name="zError">zError</a> (int err);</font>
+ <font color="Blue"><dt> int <a name="inflateSyncPoint">inflateSyncPoint</a> (<a href="#z_streamp">z_streamp</a> z);</font>
+ <font color="Blue"><dt> const uLongf * <a name="get_crc_table">get_crc_table</a> (void);</font>
+ </dl>
+ <hr>
+ <font size="-1">
+ Last update: Wed Oct 13 20:42:34 1999<br>
+ piapi@csie.ntu.edu.tw
+ </font>
+
+</body>
+</html>
diff --git a/zlib/os2/CVS/Entries b/zlib/os2/CVS/Entries
new file mode 100644
index 0000000..efc83bb
--- /dev/null
+++ b/zlib/os2/CVS/Entries
@@ -0,0 +1,3 @@
+/Makefile.os2/1.1.1.1/Thu Oct 21 15:30:25 2004//
+/zlib.def/1.1.1.1/Thu Oct 21 15:30:25 2004//
+D
diff --git a/zlib/os2/CVS/Repository b/zlib/os2/CVS/Repository
new file mode 100644
index 0000000..bc51cc9
--- /dev/null
+++ b/zlib/os2/CVS/Repository
@@ -0,0 +1 @@
+ccvs/zlib/old/os2
diff --git a/zlib/os2/CVS/Root b/zlib/os2/CVS/Root
new file mode 100644
index 0000000..e6a4c0c
--- /dev/null
+++ b/zlib/os2/CVS/Root
@@ -0,0 +1 @@
+dprice@savannah.nongnu.org:/cvsroot/cvs
diff --git a/zlib/os2/Makefile.os2 b/zlib/os2/Makefile.os2
new file mode 100644
index 0000000..a105aaa
--- /dev/null
+++ b/zlib/os2/Makefile.os2
@@ -0,0 +1,136 @@
+# Makefile for zlib under OS/2 using GCC (PGCC)
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# cp Makefile.os2 ..
+# cd ..
+# make -f Makefile.os2 test
+
+# This makefile will build a static library z.lib, a shared library
+# z.dll and a import library zdll.lib. You can use either z.lib or
+# zdll.lib by specifying either -lz or -lzdll on gcc's command line
+
+CC=gcc -Zomf -s
+
+CFLAGS=-O6 -Wall
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+#################### BUG WARNING: #####################
+## infcodes.c hits a bug in pgcc-1.0, so you have to use either
+## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem)
+## This bug is reportedly fixed in pgcc >1.0, but this was not tested
+CFLAGS+=-fno-force-mem
+
+LDFLAGS=-s -L. -lzdll -Zcrtdll
+LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll
+
+VER=1.1.0
+ZLIB=z.lib
+SHAREDLIB=z.dll
+SHAREDLIBIMP=zdll.lib
+LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP)
+
+AR=emxomfar cr
+IMPLIB=emximp
+RANLIB=echo
+TAR=tar
+SHELL=bash
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \
+ algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+ nt/Makefile.nt nt/zlib.dnt contrib/README.contrib contrib/*.txt \
+ contrib/asm386/*.asm contrib/asm386/*.c \
+ contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \
+ contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \
+ contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32
+
+all: example.exe minigzip.exe
+
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+$(ZLIB): $(OBJS)
+ $(AR) $@ $(OBJS)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+$(SHAREDLIB): $(OBJS) os2/z.def
+ $(LDSHARED) -o $@ $^
+
+$(SHAREDLIBIMP): os2/z.def
+ $(IMPLIB) -o $@ $^
+
+example.exe: example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip.exe: minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+clean:
+ rm -f *.o *~ example minigzip libz.a libz.so* foo.gz
+
+distclean: clean
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/zlib/os2/zlib.def b/zlib/os2/zlib.def
new file mode 100644
index 0000000..4c753f1
--- /dev/null
+++ b/zlib/os2/zlib.def
@@ -0,0 +1,51 @@
+;
+; Slightly modified version of ../nt/zlib.dnt :-)
+;
+
+LIBRARY Z
+DESCRIPTION "Zlib compression library for OS/2"
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+EXPORTS
+ adler32
+ compress
+ crc32
+ deflate
+ deflateCopy
+ deflateEnd
+ deflateInit2_
+ deflateInit_
+ deflateParams
+ deflateReset
+ deflateSetDictionary
+ gzclose
+ gzdopen
+ gzerror
+ gzflush
+ gzopen
+ gzread
+ gzwrite
+ inflate
+ inflateEnd
+ inflateInit2_
+ inflateInit_
+ inflateReset
+ inflateSetDictionary
+ inflateSync
+ uncompress
+ zlibVersion
+ gzprintf
+ gzputc
+ gzgetc
+ gzseek
+ gzrewind
+ gztell
+ gzeof
+ gzsetparams
+ zError
+ inflateSyncPoint
+ get_crc_table
+ compress2
+ gzputs
+ gzgets
diff --git a/zlib/qnx/package.qpg b/zlib/qnx/package.qpg
new file mode 100644
index 0000000..8a4a47c
--- /dev/null
+++ b/zlib/qnx/package.qpg
@@ -0,0 +1,141 @@
+<QPG:Generation>
+ <QPG:Options>
+ <QPG:User unattended="no" verbosity="2" listfiles="yes"/>
+ <QPG:Defaults type="qnx_package"/>
+ <QPG:Source></QPG:Source>
+ <QPG:Release number="+"/>
+ <QPG:Build></QPG:Build>
+ <QPG:FileSorting strip="yes"/>
+ <QPG:Package targets="combine"/>
+ <QPG:Repository generate="yes"/>
+ <QPG:FinalDir></QPG:FinalDir>
+ <QPG:Cleanup></QPG:Cleanup>
+ </QPG:Options>
+
+ <QPG:Responsible>
+ <QPG:Company></QPG:Company>
+ <QPG:Department></QPG:Department>
+ <QPG:Group></QPG:Group>
+ <QPG:Team></QPG:Team>
+ <QPG:Employee></QPG:Employee>
+ <QPG:EmailAddress></QPG:EmailAddress>
+ </QPG:Responsible>
+
+ <QPG:Values>
+ <QPG:Files>
+ <QPG:Add file="../zconf.h" install="/opt/include/" user="root:sys" permission="644"/>
+ <QPG:Add file="../zlib.h" install="/opt/include/" user="root:sys" permission="644"/>
+ <QPG:Add file="../libz.so.1.2.3" install="/opt/lib/" user="root:bin" permission="644"/>
+ <QPG:Add file="libz.so" install="/opt/lib/" component="dev" filetype="symlink" linkto="libz.so.1.2.3"/>
+ <QPG:Add file="libz.so.1" install="/opt/lib/" filetype="symlink" linkto="libz.so.1.2.3"/>
+ <QPG:Add file="../libz.so.1.2.3" install="/opt/lib/" component="slib"/>
+ </QPG:Files>
+
+ <QPG:PackageFilter>
+ <QPM:PackageManifest>
+ <QPM:PackageDescription>
+ <QPM:PackageType>Library</QPM:PackageType>
+ <QPM:PackageReleaseNotes></QPM:PackageReleaseNotes>
+ <QPM:PackageReleaseUrgency>Medium</QPM:PackageReleaseUrgency>
+ <QPM:PackageRepository></QPM:PackageRepository>
+ <QPM:FileVersion>2.0</QPM:FileVersion>
+ </QPM:PackageDescription>
+
+ <QPM:ProductDescription>
+ <QPM:ProductName>zlib</QPM:ProductName>
+ <QPM:ProductIdentifier>zlib</QPM:ProductIdentifier>
+ <QPM:ProductEmail>alain.bonnefoy@icbt.com</QPM:ProductEmail>
+ <QPM:VendorName>Public</QPM:VendorName>
+ <QPM:VendorInstallName>public</QPM:VendorInstallName>
+ <QPM:VendorURL>www.gzip.org/zlib</QPM:VendorURL>
+ <QPM:VendorEmbedURL></QPM:VendorEmbedURL>
+ <QPM:VendorEmail></QPM:VendorEmail>
+ <QPM:AuthorName>Jean-Loup Gailly,Mark Adler</QPM:AuthorName>
+ <QPM:AuthorURL>www.gzip.org/zlib</QPM:AuthorURL>
+ <QPM:AuthorEmbedURL></QPM:AuthorEmbedURL>
+ <QPM:AuthorEmail>zlib@gzip.org</QPM:AuthorEmail>
+ <QPM:ProductIconSmall></QPM:ProductIconSmall>
+ <QPM:ProductIconLarge></QPM:ProductIconLarge>
+ <QPM:ProductDescriptionShort>A massively spiffy yet delicately unobtrusive compression library.</QPM:ProductDescriptionShort>
+ <QPM:ProductDescriptionLong>zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system.</QPM:ProductDescriptionLong>
+ <QPM:ProductDescriptionURL>http://www.gzip.org/zlib</QPM:ProductDescriptionURL>
+ <QPM:ProductDescriptionEmbedURL></QPM:ProductDescriptionEmbedURL>
+ </QPM:ProductDescription>
+
+ <QPM:ReleaseDescription>
+ <QPM:ReleaseVersion>1.2.3</QPM:ReleaseVersion>
+ <QPM:ReleaseUrgency>Medium</QPM:ReleaseUrgency>
+ <QPM:ReleaseStability>Stable</QPM:ReleaseStability>
+ <QPM:ReleaseNoteMinor></QPM:ReleaseNoteMinor>
+ <QPM:ReleaseNoteMajor></QPM:ReleaseNoteMajor>
+ <QPM:ExcludeCountries>
+ <QPM:Country></QPM:Country>
+ </QPM:ExcludeCountries>
+
+ <QPM:ReleaseCopyright>No License</QPM:ReleaseCopyright>
+ </QPM:ReleaseDescription>
+
+ <QPM:ContentDescription>
+ <QPM:ContentTopic xmlmultiple="true">Software Development/Libraries and Extensions/C Libraries</QPM:ContentTopic>
+ <QPM:ContentKeyword>zlib,compression</QPM:ContentKeyword>
+ <QPM:TargetOS>qnx6</QPM:TargetOS>
+ <QPM:HostOS>qnx6</QPM:HostOS>
+ <QPM:DisplayEnvironment xmlmultiple="true">None</QPM:DisplayEnvironment>
+ <QPM:TargetAudience xmlmultiple="true">Developer</QPM:TargetAudience>
+ </QPM:ContentDescription>
+ </QPM:PackageManifest>
+ </QPG:PackageFilter>
+
+ <QPG:PackageFilter proc="none" target="none">
+ <QPM:PackageManifest>
+ <QPM:ProductInstallationDependencies>
+ <QPM:ProductRequirements></QPM:ProductRequirements>
+ </QPM:ProductInstallationDependencies>
+
+ <QPM:ProductInstallationProcedure>
+ <QPM:Script xmlmultiple="true">
+ <QPM:ScriptName></QPM:ScriptName>
+ <QPM:ScriptType>Install</QPM:ScriptType>
+ <QPM:ScriptTiming>Post</QPM:ScriptTiming>
+ <QPM:ScriptBlocking>No</QPM:ScriptBlocking>
+ <QPM:ScriptResult>Ignore</QPM:ScriptResult>
+ <QPM:ShortDescription></QPM:ShortDescription>
+ <QPM:UseBinaries>No</QPM:UseBinaries>
+ <QPM:Priority>Optional</QPM:Priority>
+ </QPM:Script>
+ </QPM:ProductInstallationProcedure>
+ </QPM:PackageManifest>
+
+ <QPM:Launch>
+ </QPM:Launch>
+ </QPG:PackageFilter>
+
+ <QPG:PackageFilter type="core" component="none">
+ <QPM:PackageManifest>
+ <QPM:ProductInstallationProcedure>
+ <QPM:OrderDependency xmlmultiple="true">
+ <QPM:Order>InstallOver</QPM:Order>
+ <QPM:Product>zlib</QPM:Product>
+ </QPM:OrderDependency>
+ </QPM:ProductInstallationProcedure>
+ </QPM:PackageManifest>
+
+ <QPM:Launch>
+ </QPM:Launch>
+ </QPG:PackageFilter>
+
+ <QPG:PackageFilter type="core" component="dev">
+ <QPM:PackageManifest>
+ <QPM:ProductInstallationProcedure>
+ <QPM:OrderDependency xmlmultiple="true">
+ <QPM:Order>InstallOver</QPM:Order>
+ <QPM:Product>zlib-dev</QPM:Product>
+ </QPM:OrderDependency>
+ </QPM:ProductInstallationProcedure>
+ </QPM:PackageManifest>
+
+ <QPM:Launch>
+ </QPM:Launch>
+ </QPG:PackageFilter>
+ </QPG:Values>
+</QPG:Generation>
diff --git a/zlib/trees.c b/zlib/trees.c
new file mode 100644
index 0000000..395e4e1
--- /dev/null
+++ b/zlib/trees.c
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+ set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n;
+
+ for (n = 0; n < 9; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ if (n == 9)
+ for (n = 14; n < 32; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/zlib/trees.h b/zlib/trees.h
new file mode 100644
index 0000000..72facf9
--- /dev/null
+++ b/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/zlib/uncompr.c b/zlib/uncompr.c
new file mode 100644
index 0000000..b59e3d0
--- /dev/null
+++ b/zlib/uncompr.c
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/zlib/win32/DLL_FAQ.txt b/zlib/win32/DLL_FAQ.txt
new file mode 100644
index 0000000..fb18e07
--- /dev/null
+++ b/zlib/win32/DLL_FAQ.txt
@@ -0,0 +1,397 @@
+
+ Frequently Asked Questions about ZLIB1.DLL
+
+
+This document describes the design, the rationale, and the usage
+of the official DLL build of zlib, named ZLIB1.DLL. If you have
+general questions about zlib, you should see the file "FAQ" found
+in the zlib distribution, or at the following location:
+ http://www.gzip.org/zlib/zlib_faq.html
+
+
+ 1. What is ZLIB1.DLL, and how can I get it?
+
+ - ZLIB1.DLL is the official build of zlib as a DLL.
+ (Please remark the character '1' in the name.)
+
+ Pointers to a precompiled ZLIB1.DLL can be found in the zlib
+ web site at:
+ http://www.zlib.org/
+
+ Applications that link to ZLIB1.DLL can rely on the following
+ specification:
+
+ * The exported symbols are exclusively defined in the source
+ files "zlib.h" and "zlib.def", found in an official zlib
+ source distribution.
+ * The symbols are exported by name, not by ordinal.
+ * The exported names are undecorated.
+ * The calling convention of functions is "C" (CDECL).
+ * The ZLIB1.DLL binary is linked to MSVCRT.DLL.
+
+ The archive in which ZLIB1.DLL is bundled contains compiled
+ test programs that must run with a valid build of ZLIB1.DLL.
+ It is recommended to download the prebuilt DLL from the zlib
+ web site, instead of building it yourself, to avoid potential
+ incompatibilities that could be introduced by your compiler
+ and build settings. If you do build the DLL yourself, please
+ make sure that it complies with all the above requirements,
+ and it runs with the precompiled test programs, bundled with
+ the original ZLIB1.DLL distribution.
+
+ If, for any reason, you need to build an incompatible DLL,
+ please use a different file name.
+
+
+ 2. Why did you change the name of the DLL to ZLIB1.DLL?
+ What happened to the old ZLIB.DLL?
+
+ - The old ZLIB.DLL, built from zlib-1.1.4 or earlier, required
+ compilation settings that were incompatible to those used by
+ a static build. The DLL settings were supposed to be enabled
+ by defining the macro ZLIB_DLL, before including "zlib.h".
+ Incorrect handling of this macro was silently accepted at
+ build time, resulting in two major problems:
+
+ * ZLIB_DLL was missing from the old makefile. When building
+ the DLL, not all people added it to the build options. In
+ consequence, incompatible incarnations of ZLIB.DLL started
+ to circulate around the net.
+
+ * When switching from using the static library to using the
+ DLL, applications had to define the ZLIB_DLL macro and
+ to recompile all the sources that contained calls to zlib
+ functions. Failure to do so resulted in creating binaries
+ that were unable to run with the official ZLIB.DLL build.
+
+ The only possible solution that we could foresee was to make
+ a binary-incompatible change in the DLL interface, in order to
+ remove the dependency on the ZLIB_DLL macro, and to release
+ the new DLL under a different name.
+
+ We chose the name ZLIB1.DLL, where '1' indicates the major
+ zlib version number. We hope that we will not have to break
+ the binary compatibility again, at least not as long as the
+ zlib-1.x series will last.
+
+ There is still a ZLIB_DLL macro, that can trigger a more
+ efficient build and use of the DLL, but compatibility no
+ longer dependents on it.
+
+
+ 3. Can I build ZLIB.DLL from the new zlib sources, and replace
+ an old ZLIB.DLL, that was built from zlib-1.1.4 or earlier?
+
+ - In principle, you can do it by assigning calling convention
+ keywords to the macros ZEXPORT and ZEXPORTVA. In practice,
+ it depends on what you mean by "an old ZLIB.DLL", because the
+ old DLL exists in several mutually-incompatible versions.
+ You have to find out first what kind of calling convention is
+ being used in your particular ZLIB.DLL build, and to use the
+ same one in the new build. If you don't know what this is all
+ about, you might be better off if you would just leave the old
+ DLL intact.
+
+
+ 4. Can I compile my application using the new zlib interface, and
+ link it to an old ZLIB.DLL, that was built from zlib-1.1.4 or
+ earlier?
+
+ - The official answer is "no"; the real answer depends again on
+ what kind of ZLIB.DLL you have. Even if you are lucky, this
+ course of action is unreliable.
+
+ If you rebuild your application and you intend to use a newer
+ version of zlib (post- 1.1.4), it is strongly recommended to
+ link it to the new ZLIB1.DLL.
+
+
+ 5. Why are the zlib symbols exported by name, and not by ordinal?
+
+ - Although exporting symbols by ordinal is a little faster, it
+ is risky. Any single glitch in the maintenance or use of the
+ DEF file that contains the ordinals can result in incompatible
+ builds and frustrating crashes. Simply put, the benefits of
+ exporting symbols by ordinal do not justify the risks.
+
+ Technically, it should be possible to maintain ordinals in
+ the DEF file, and still export the symbols by name. Ordinals
+ exist in every DLL, and even if the dynamic linking performed
+ at the DLL startup is searching for names, ordinals serve as
+ hints, for a faster name lookup. However, if the DEF file
+ contains ordinals, the Microsoft linker automatically builds
+ an implib that will cause the executables linked to it to use
+ those ordinals, and not the names. It is interesting to
+ notice that the GNU linker for Win32 does not suffer from this
+ problem.
+
+ It is possible to avoid the DEF file if the exported symbols
+ are accompanied by a "__declspec(dllexport)" attribute in the
+ source files. You can do this in zlib by predefining the
+ ZLIB_DLL macro.
+
+
+ 6. I see that the ZLIB1.DLL functions use the "C" (CDECL) calling
+ convention. Why not use the STDCALL convention?
+ STDCALL is the standard convention in Win32, and I need it in
+ my Visual Basic project!
+
+ (For readability, we use CDECL to refer to the convention
+ triggered by the "__cdecl" keyword, STDCALL to refer to
+ the convention triggered by "__stdcall", and FASTCALL to
+ refer to the convention triggered by "__fastcall".)
+
+ - Most of the native Windows API functions (without varargs) use
+ indeed the WINAPI convention (which translates to STDCALL in
+ Win32), but the standard C functions use CDECL. If a user
+ application is intrinsically tied to the Windows API (e.g.
+ it calls native Windows API functions such as CreateFile()),
+ sometimes it makes sense to decorate its own functions with
+ WINAPI. But if ANSI C or POSIX portability is a goal (e.g.
+ it calls standard C functions such as fopen()), it is not a
+ sound decision to request the inclusion of <windows.h>, or to
+ use non-ANSI constructs, for the sole purpose to make the user
+ functions STDCALL-able.
+
+ The functionality offered by zlib is not in the category of
+ "Windows functionality", but is more like "C functionality".
+
+ Technically, STDCALL is not bad; in fact, it is slightly
+ faster than CDECL, and it works with variable-argument
+ functions, just like CDECL. It is unfortunate that, in spite
+ of using STDCALL in the Windows API, it is not the default
+ convention used by the C compilers that run under Windows.
+ The roots of the problem reside deep inside the unsafety of
+ the K&R-style function prototypes, where the argument types
+ are not specified; but that is another story for another day.
+
+ The remaining fact is that CDECL is the default convention.
+ Even if an explicit convention is hard-coded into the function
+ prototypes inside C headers, problems may appear. The
+ necessity to expose the convention in users' callbacks is one
+ of these problems.
+
+ The calling convention issues are also important when using
+ zlib in other programming languages. Some of them, like Ada
+ (GNAT) and Fortran (GNU G77), have C bindings implemented
+ initially on Unix, and relying on the C calling convention.
+ On the other hand, the pre- .NET versions of Microsoft Visual
+ Basic require STDCALL, while Borland Delphi prefers, although
+ it does not require, FASTCALL.
+
+ In fairness to all possible uses of zlib outside the C
+ programming language, we choose the default "C" convention.
+ Anyone interested in different bindings or conventions is
+ encouraged to maintain specialized projects. The "contrib/"
+ directory from the zlib distribution already holds a couple
+ of foreign bindings, such as Ada, C++, and Delphi.
+
+
+ 7. I need a DLL for my Visual Basic project. What can I do?
+
+ - Define the ZLIB_WINAPI macro before including "zlib.h", when
+ building both the DLL and the user application (except that
+ you don't need to define anything when using the DLL in Visual
+ Basic). The ZLIB_WINAPI macro will switch on the WINAPI
+ (STDCALL) convention. The name of this DLL must be different
+ than the official ZLIB1.DLL.
+
+ Gilles Vollant has contributed a build named ZLIBWAPI.DLL,
+ with the ZLIB_WINAPI macro turned on, and with the minizip
+ functionality built in. For more information, please read
+ the notes inside "contrib/vstudio/readme.txt", found in the
+ zlib distribution.
+
+
+ 8. I need to use zlib in my Microsoft .NET project. What can I
+ do?
+
+ - Henrik Ravn has contributed a .NET wrapper around zlib. Look
+ into contrib/dotzlib/, inside the zlib distribution.
+
+
+ 9. If my application uses ZLIB1.DLL, should I link it to
+ MSVCRT.DLL? Why?
+
+ - It is not required, but it is recommended to link your
+ application to MSVCRT.DLL, if it uses ZLIB1.DLL.
+
+ The executables (.EXE, .DLL, etc.) that are involved in the
+ same process and are using the C run-time library (i.e. they
+ are calling standard C functions), must link to the same
+ library. There are several libraries in the Win32 system:
+ CRTDLL.DLL, MSVCRT.DLL, the static C libraries, etc.
+ Since ZLIB1.DLL is linked to MSVCRT.DLL, the executables that
+ depend on it should also be linked to MSVCRT.DLL.
+
+
+10. Why are you saying that ZLIB1.DLL and my application should
+ be linked to the same C run-time (CRT) library? I linked my
+ application and my DLLs to different C libraries (e.g. my
+ application to a static library, and my DLLs to MSVCRT.DLL),
+ and everything works fine.
+
+ - If a user library invokes only pure Win32 API (accessible via
+ <windows.h> and the related headers), its DLL build will work
+ in any context. But if this library invokes standard C API,
+ things get more complicated.
+
+ There is a single Win32 library in a Win32 system. Every
+ function in this library resides in a single DLL module, that
+ is safe to call from anywhere. On the other hand, there are
+ multiple versions of the C library, and each of them has its
+ own separate internal state. Standalone executables and user
+ DLLs that call standard C functions must link to a C run-time
+ (CRT) library, be it static or shared (DLL). Intermixing
+ occurs when an executable (not necessarily standalone) and a
+ DLL are linked to different CRTs, and both are running in the
+ same process.
+
+ Intermixing multiple CRTs is possible, as long as their
+ internal states are kept intact. The Microsoft Knowledge Base
+ articles KB94248 "HOWTO: Use the C Run-Time" and KB140584
+ "HOWTO: Link with the Correct C Run-Time (CRT) Library"
+ mention the potential problems raised by intermixing.
+
+ If intermixing works for you, it's because your application
+ and DLLs are avoiding the corruption of each of the CRTs'
+ internal states, maybe by careful design, or maybe by fortune.
+
+ Also note that linking ZLIB1.DLL to non-Microsoft CRTs, such
+ as those provided by Borland, raises similar problems.
+
+
+11. Why are you linking ZLIB1.DLL to MSVCRT.DLL?
+
+ - MSVCRT.DLL exists on every Windows 95 with a new service pack
+ installed, or with Microsoft Internet Explorer 4 or later, and
+ on all other Windows 4.x or later (Windows 98, Windows NT 4,
+ or later). It is freely distributable; if not present in the
+ system, it can be downloaded from Microsoft or from other
+ software provider for free.
+
+ The fact that MSVCRT.DLL does not exist on a virgin Windows 95
+ is not so problematic. Windows 95 is scarcely found nowadays,
+ Microsoft ended its support a long time ago, and many recent
+ applications from various vendors, including Microsoft, do not
+ even run on it. Furthermore, no serious user should run
+ Windows 95 without a proper update installed.
+
+
+12. Why are you not linking ZLIB1.DLL to
+ <<my favorite C run-time library>> ?
+
+ - We considered and abandoned the following alternatives:
+
+ * Linking ZLIB1.DLL to a static C library (LIBC.LIB, or
+ LIBCMT.LIB) is not a good option. People are using the DLL
+ mainly to save disk space. If you are linking your program
+ to a static C library, you may as well consider linking zlib
+ in statically, too.
+
+ * Linking ZLIB1.DLL to CRTDLL.DLL looks appealing, because
+ CRTDLL.DLL is present on every Win32 installation.
+ Unfortunately, it has a series of problems: it does not
+ work properly with Microsoft's C++ libraries, it does not
+ provide support for 64-bit file offsets, (and so on...),
+ and Microsoft discontinued its support a long time ago.
+
+ * Linking ZLIB1.DLL to MSVCR70.DLL or MSVCR71.DLL, supplied
+ with the Microsoft .NET platform, and Visual C++ 7.0/7.1,
+ raises problems related to the status of ZLIB1.DLL as a
+ system component. According to the Microsoft Knowledge Base
+ article KB326922 "INFO: Redistribution of the Shared C
+ Runtime Component in Visual C++ .NET", MSVCR70.DLL and
+ MSVCR71.DLL are not supposed to function as system DLLs,
+ because they may clash with MSVCRT.DLL. Instead, the
+ application's installer is supposed to put these DLLs
+ (if needed) in the application's private directory.
+ If ZLIB1.DLL depends on a non-system runtime, it cannot
+ function as a redistributable system component.
+
+ * Linking ZLIB1.DLL to non-Microsoft runtimes, such as
+ Borland's, or Cygwin's, raises problems related to the
+ reliable presence of these runtimes on Win32 systems.
+ It's easier to let the DLL build of zlib up to the people
+ who distribute these runtimes, and who may proceed as
+ explained in the answer to Question 14.
+
+
+13. If ZLIB1.DLL cannot be linked to MSVCR70.DLL or MSVCR71.DLL,
+ how can I build/use ZLIB1.DLL in Microsoft Visual C++ 7.0
+ (Visual Studio .NET) or newer?
+
+ - Due to the problems explained in the Microsoft Knowledge Base
+ article KB326922 (see the previous answer), the C runtime that
+ comes with the VC7 environment is no longer considered a
+ system component. That is, it should not be assumed that this
+ runtime exists, or may be installed in a system directory.
+ Since ZLIB1.DLL is supposed to be a system component, it may
+ not depend on a non-system component.
+
+ In order to link ZLIB1.DLL and your application to MSVCRT.DLL
+ in VC7, you need the library of Visual C++ 6.0 or older. If
+ you don't have this library at hand, it's probably best not to
+ use ZLIB1.DLL.
+
+ We are hoping that, in the future, Microsoft will provide a
+ way to build applications linked to a proper system runtime,
+ from the Visual C++ environment. Until then, you have a
+ couple of alternatives, such as linking zlib in statically.
+ If your application requires dynamic linking, you may proceed
+ as explained in the answer to Question 14.
+
+
+14. I need to link my own DLL build to a CRT different than
+ MSVCRT.DLL. What can I do?
+
+ - Feel free to rebuild the DLL from the zlib sources, and link
+ it the way you want. You should, however, clearly state that
+ your build is unofficial. You should give it a different file
+ name, and/or install it in a private directory that can be
+ accessed by your application only, and is not visible to the
+ others (e.g. it's not in the SYSTEM or the SYSTEM32 directory,
+ and it's not in the PATH). Otherwise, your build may clash
+ with applications that link to the official build.
+
+ For example, in Cygwin, zlib is linked to the Cygwin runtime
+ CYGWIN1.DLL, and it is distributed under the name CYGZ.DLL.
+
+
+15. May I include additional pieces of code that I find useful,
+ link them in ZLIB1.DLL, and export them?
+
+ - No. A legitimate build of ZLIB1.DLL must not include code
+ that does not originate from the official zlib source code.
+ But you can make your own private DLL build, under a different
+ file name, as suggested in the previous answer.
+
+ For example, zlib is a part of the VCL library, distributed
+ with Borland Delphi and C++ Builder. The DLL build of VCL
+ is a redistributable file, named VCLxx.DLL.
+
+
+16. May I remove some functionality out of ZLIB1.DLL, by enabling
+ macros like NO_GZCOMPRESS or NO_GZIP at compile time?
+
+ - No. A legitimate build of ZLIB1.DLL must provide the complete
+ zlib functionality, as implemented in the official zlib source
+ code. But you can make your own private DLL build, under a
+ different file name, as suggested in the previous answer.
+
+
+17. I made my own ZLIB1.DLL build. Can I test it for compliance?
+
+ - We prefer that you download the official DLL from the zlib
+ web site. If you need something peculiar from this DLL, you
+ can send your suggestion to the zlib mailing list.
+
+ However, in case you do rebuild the DLL yourself, you can run
+ it with the test programs found in the DLL distribution.
+ Running these test programs is not a guarantee of compliance,
+ but a failure can imply a detected problem.
+
+**
+
+This document is written and maintained by
+Cosmin Truta <cosmint@cs.ubbcluj.ro>
diff --git a/zlib/win32/Makefile.bor b/zlib/win32/Makefile.bor
new file mode 100644
index 0000000..b802519
--- /dev/null
+++ b/zlib/win32/Makefile.bor
@@ -0,0 +1,107 @@
+# Makefile for zlib
+# Borland C++ for Win32
+#
+# Updated for zlib 1.2.x by Cosmin Truta, 11-Mar-2003
+# Last updated: 28-Aug-2003
+#
+# Usage:
+# make -f win32/Makefile.bor
+# make -f win32/Makefile.bor LOCAL_ZLIB=-DASMV OBJA=match.obj OBJPA=+match.obj
+
+# ------------ Borland C++ ------------
+
+# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7)
+# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or
+# added to the declaration of LOC here:
+LOC = $(LOCAL_ZLIB)
+
+CC = bcc32
+AS = bcc32
+LD = bcc32
+AR = tlib
+CFLAGS = -a -d -k- -O2 $(LOC)
+ASFLAGS = $(LOC)
+LDFLAGS = $(LOC)
+
+
+# variables
+ZLIB_LIB = zlib.lib
+
+OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj
+OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+#OBJA =
+OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj
+OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj
+#OBJPA=
+
+
+# targets
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $<
+
+.asm.obj:
+ $(AS) -c $(ASFLAGS) $<
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: example.c zlib.h zconf.h
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+
+
+# For the sake of the old Borland make,
+# the command line is cut to fit in the MS-DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2) $(OBJA)
+ -del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) $(OBJP1)
+ $(AR) $(ZLIB_LIB) $(OBJP2)
+ $(AR) $(ZLIB_LIB) $(OBJPA)
+
+
+# testing
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+
+# cleanup
+clean:
+ -del *.obj
+ -del *.lib
+ -del *.exe
+ -del *.tds
+ -del zlib.bak
+ -del foo.gz
diff --git a/zlib/win32/Makefile.emx b/zlib/win32/Makefile.emx
new file mode 100644
index 0000000..7b08424
--- /dev/null
+++ b/zlib/win32/Makefile.emx
@@ -0,0 +1,69 @@
+# Makefile for zlib. Modified for emx/rsxnt by Chr. Spieler, 6/16/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.emx; make test -fmakefile.emx
+#
+
+CC=gcc -Zwin32
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) zlib.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/zlib/win32/Makefile.gcc b/zlib/win32/Makefile.gcc
new file mode 100644
index 0000000..62a8430
--- /dev/null
+++ b/zlib/win32/Makefile.gcc
@@ -0,0 +1,141 @@
+# Makefile for zlib, derived from Makefile.dj2.
+# Modified for mingw32 by C. Spieler, 6/16/98.
+# Updated for zlib 1.2.x by Christian Spieler and Cosmin Truta, Mar-2003.
+# Last updated: 1-Aug-2003.
+# Tested under Cygwin and MinGW.
+
+# Copyright (C) 1995-2003 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.gcc; make test testdll -fmakefile.gcc
+#
+# To use the asm code, type:
+# cp contrib/asm?86/match.S ./match.S
+# make LOC=-DASMV OBJA=match.o -fmakefile.gcc
+#
+# To install libz.a, zconf.h and zlib.h in the system directories, type:
+#
+# make install -fmakefile.gcc
+
+# Note:
+# If the platform is *not* MinGW (e.g. it is Cygwin or UWIN),
+# the DLL name should be changed from "zlib1.dll".
+
+STATICLIB = libz.a
+SHAREDLIB = zlib1.dll
+IMPLIB = libzdll.a
+
+#LOC = -DASMV
+#LOC = -DDEBUG -g
+
+CC = gcc
+CFLAGS = $(LOC) -O3 -Wall
+
+AS = $(CC)
+ASFLAGS = $(LOC) -Wall
+
+LD = $(CC)
+LDFLAGS = $(LOC) -s
+
+AR = ar
+ARFLAGS = rcs
+
+RC = windres
+RCFLAGS = --define GCC_WINDRES
+
+CP = cp -fp
+# If GNU install is available, replace $(CP) with install.
+INSTALL = $(CP)
+RM = rm -f
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o deflate.o gzio.o infback.o \
+ inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o
+OBJA =
+
+all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) example minigzip example_d minigzip_d
+
+test: example minigzip
+ ./example
+ echo hello world | ./minigzip | ./minigzip -d
+
+testdll: example_d minigzip_d
+ ./example_d
+ echo hello world | ./minigzip_d | ./minigzip_d -d
+
+.c.o:
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+.S.o:
+ $(AS) $(ASFLAGS) -c -o $@ $<
+
+$(STATICLIB): $(OBJS) $(OBJA)
+ $(AR) $(ARFLAGS) $@ $(OBJS) $(OBJA)
+
+$(IMPLIB): $(SHAREDLIB)
+
+$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlibrc.o
+ dllwrap --driver-name $(CC) --def win32/zlib.def \
+ --implib $(IMPLIB) -o $@ $(OBJS) $(OBJA) zlibrc.o
+ strip $@
+
+example: example.o $(STATICLIB)
+ $(LD) $(LDFLAGS) -o $@ example.o $(STATICLIB)
+
+minigzip: minigzip.o $(STATICLIB)
+ $(LD) $(LDFLAGS) -o $@ minigzip.o $(STATICLIB)
+
+example_d: example.o $(IMPLIB)
+ $(LD) $(LDFLAGS) -o $@ example.o $(IMPLIB)
+
+minigzip_d: minigzip.o $(IMPLIB)
+ $(LD) $(LDFLAGS) -o $@ minigzip.o $(IMPLIB)
+
+zlibrc.o: win32/zlib1.rc
+ $(RC) $(RCFLAGS) -o $@ win32/zlib1.rc
+
+
+# INCLUDE_PATH and LIBRARY_PATH must be set.
+
+.PHONY: install uninstall clean
+
+install: zlib.h zconf.h $(LIB)
+ -@if not exist $(INCLUDE_PATH)/nul mkdir $(INCLUDE_PATH)
+ -@if not exist $(LIBRARY_PATH)/nul mkdir $(LIBRARY_PATH)
+ -$(INSTALL) zlib.h $(INCLUDE_PATH)
+ -$(INSTALL) zconf.h $(INCLUDE_PATH)
+ -$(INSTALL) $(STATICLIB) $(LIBRARY_PATH)
+ -$(INSTALL) $(IMPLIB) $(LIBRARY_PATH)
+
+uninstall:
+ -$(RM) $(INCLUDE_PATH)/zlib.h
+ -$(RM) $(INCLUDE_PATH)/zconf.h
+ -$(RM) $(LIBRARY_PATH)/$(STATICLIB)
+ -$(RM) $(LIBRARY_PATH)/$(IMPLIB)
+
+clean:
+ -$(RM) $(STATICLIB)
+ -$(RM) $(SHAREDLIB)
+ -$(RM) $(IMPLIB)
+ -$(RM) *.o
+ -$(RM) *.exe
+ -$(RM) foo.gz
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/zlib/win32/Makefile.msc b/zlib/win32/Makefile.msc
new file mode 100644
index 0000000..528ecaa
--- /dev/null
+++ b/zlib/win32/Makefile.msc
@@ -0,0 +1,126 @@
+# Makefile for zlib -- Microsoft (Visual) C
+#
+# Authors:
+# Cosmin Truta, 11-Mar-2003
+# Christian Spieler, 19-Mar-2003
+#
+# Last updated:
+# Cosmin Truta, 27-Aug-2003
+#
+# Usage:
+# nmake -f win32/Makefile.msc (standard build)
+# nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build)
+# nmake -f win32/Makefile.msc LOC=-DASMV OBJA=match.obj (use ASM code)
+
+
+# optional build flags
+LOC =
+
+
+# variables
+STATICLIB = zlib.lib
+SHAREDLIB = zlib1.dll
+IMPLIB = zdll.lib
+
+CC = cl
+AS = ml
+LD = link
+AR = lib
+RC = rc
+CFLAGS = -nologo -MD -O2 $(LOC)
+ASFLAGS = -coff
+LDFLAGS = -nologo -release
+ARFLAGS = -nologo
+RCFLAGS = /dWIN32 /r
+
+OBJS = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj \
+ inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+OBJA =
+
+
+# targets
+all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \
+ example.exe minigzip.exe example_d.exe minigzip_d.exe
+
+$(STATICLIB): $(OBJS) $(OBJA)
+ $(AR) $(ARFLAGS) -out:$@ $(OBJS) $(OBJA)
+
+$(IMPLIB): $(SHAREDLIB)
+
+$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlib1.res
+ $(LD) $(LDFLAGS) -def:win32/zlib.def -dll -implib:$(IMPLIB) \
+ -out:$@ $(OBJS) $(OBJA) zlib1.res
+
+example.exe: example.obj $(STATICLIB)
+ $(LD) $(LDFLAGS) example.obj $(STATICLIB)
+
+minigzip.exe: minigzip.obj $(STATICLIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(STATICLIB)
+
+example_d.exe: example.obj $(IMPLIB)
+ $(LD) $(LDFLAGS) -out:$@ example.obj $(IMPLIB)
+
+minigzip_d.exe: minigzip.obj $(IMPLIB)
+ $(LD) $(LDFLAGS) -out:$@ minigzip.obj $(IMPLIB)
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $<
+
+.asm.obj:
+ $(AS) -c $(ASFLAGS) $<
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: example.c zlib.h zconf.h
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+
+zlib1.res: win32/zlib1.rc
+ $(RC) $(RCFLAGS) /fo$@ win32/zlib1.rc
+
+
+# testing
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+testdll: example_d.exe minigzip_d.exe
+ example_d
+ echo hello world | minigzip_d | minigzip_d -d
+
+
+# cleanup
+clean:
+ -del $(STATICLIB)
+ -del $(SHAREDLIB)
+ -del $(IMPLIB)
+ -del *.obj
+ -del *.res
+ -del *.exp
+ -del *.exe
+ -del foo.gz
diff --git a/zlib/win32/VisualC.txt b/zlib/win32/VisualC.txt
new file mode 100644
index 0000000..579a5fc
--- /dev/null
+++ b/zlib/win32/VisualC.txt
@@ -0,0 +1,3 @@
+
+To build zlib using the Microsoft Visual C++ environment,
+use the appropriate project from the projects/ directory.
diff --git a/zlib/win32/zlib.def b/zlib/win32/zlib.def
new file mode 100644
index 0000000..a47cbc1
--- /dev/null
+++ b/zlib/win32/zlib.def
@@ -0,0 +1,60 @@
+LIBRARY
+; zlib data compression library
+
+EXPORTS
+; basic functions
+ zlibVersion
+ deflate
+ deflateEnd
+ inflate
+ inflateEnd
+; advanced functions
+ deflateSetDictionary
+ deflateCopy
+ deflateReset
+ deflateParams
+ deflateBound
+ deflatePrime
+ inflateSetDictionary
+ inflateSync
+ inflateCopy
+ inflateReset
+ inflateBack
+ inflateBackEnd
+ zlibCompileFlags
+; utility functions
+ compress
+ compress2
+ compressBound
+ uncompress
+ gzopen
+ gzdopen
+ gzsetparams
+ gzread
+ gzwrite
+ gzprintf
+ gzputs
+ gzgets
+ gzputc
+ gzgetc
+ gzungetc
+ gzflush
+ gzseek
+ gzrewind
+ gztell
+ gzeof
+ gzclose
+ gzerror
+ gzclearerr
+; checksum functions
+ adler32
+ crc32
+; various hacks, don't look :)
+ deflateInit_
+ deflateInit2_
+ inflateInit_
+ inflateInit2_
+ inflateBackInit_
+ inflateSyncPoint
+ get_crc_table
+ zError
diff --git a/zlib/win32/zlib1.rc b/zlib/win32/zlib1.rc
new file mode 100644
index 0000000..99025c9
--- /dev/null
+++ b/zlib/win32/zlib1.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+
+#ifdef GCC_WINDRES
+VS_VERSION_INFO VERSIONINFO
+#else
+VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
+#endif
+ FILEVERSION 1,2,2,0
+ PRODUCTVERSION 1,2,2,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS 1
+#else
+ FILEFLAGS 0
+#endif
+ FILEOS VOS_DOS_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0 // not used
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ //language ID = U.S. English, char set = Windows, Multilingual
+ BEGIN
+ VALUE "FileDescription", "zlib data compression library\0"
+ VALUE "FileVersion", "1.2.3\0"
+ VALUE "InternalName", "zlib1.dll\0"
+ VALUE "LegalCopyright", "(C) 1995-2004 Jean-loup Gailly & Mark Adler\0"
+ VALUE "OriginalFilename", "zlib1.dll\0"
+ VALUE "ProductName", "zlib\0"
+ VALUE "ProductVersion", "1.2.3\0"
+ VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+END
diff --git a/zlib/zconf.h b/zlib/zconf.h
new file mode 100644
index 0000000..b92eb28
--- /dev/null
+++ b/zlib/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.in.h,v 1.1.1.1 2004/10/21 15:30:03 dprice Exp $ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/zlib/zlib.3 b/zlib/zlib.3
new file mode 100644
index 0000000..90b8162
--- /dev/null
+++ b/zlib/zlib.3
@@ -0,0 +1,159 @@
+.TH ZLIB 3 "18 July 2005"
+.SH NAME
+zlib \- compression/decompression library
+.SH SYNOPSIS
+[see
+.I zlib.h
+for full description]
+.SH DESCRIPTION
+The
+.I zlib
+library is a general purpose data compression library.
+The code is thread safe.
+It provides in-memory compression and decompression functions,
+including integrity checks of the uncompressed data.
+This version of the library supports only one compression method (deflation)
+but other algorithms will be added later
+and will have the same stream interface.
+.LP
+Compression can be done in a single step if the buffers are large enough
+(for example if an input file is mmap'ed),
+or can be done by repeated calls of the compression function.
+In the latter case,
+the application must provide more input and/or consume the output
+(providing more output space) before each call.
+.LP
+The library also supports reading and writing files in
+.IR gzip (1)
+(.gz) format
+with an interface similar to that of stdio.
+.LP
+The library does not install any signal handler.
+The decoder checks the consistency of the compressed data,
+so the library should never crash even in case of corrupted input.
+.LP
+All functions of the compression library are documented in the file
+.IR zlib.h .
+The distribution source includes examples of use of the library
+in the files
+.I example.c
+and
+.IR minigzip.c .
+.LP
+Changes to this version are documented in the file
+.I ChangeLog
+that accompanies the source,
+and are concerned primarily with bug fixes and portability enhancements.
+.LP
+A Java implementation of
+.I zlib
+is available in the Java Development Kit 1.1:
+.IP
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+.LP
+A Perl interface to
+.IR zlib ,
+written by Paul Marquess (pmqs@cpan.org),
+is available at CPAN (Comprehensive Perl Archive Network) sites,
+including:
+.IP
+http://www.cpan.org/modules/by-module/Compress/
+.LP
+A Python interface to
+.IR zlib ,
+written by A.M. Kuchling (amk@magnet.com),
+is available in Python 1.5 and later versions:
+.IP
+http://www.python.org/doc/lib/module-zlib.html
+.LP
+A
+.I zlib
+binding for
+.IR tcl (1),
+written by Andreas Kupries (a.kupries@westend.com),
+is availlable at:
+.IP
+http://www.westend.com/~kupries/doc/trf/man/man.html
+.LP
+An experimental package to read and write files in .zip format,
+written on top of
+.I zlib
+by Gilles Vollant (info@winimage.com),
+is available at:
+.IP
+http://www.winimage.com/zLibDll/unzip.html
+and also in the
+.I contrib/minizip
+directory of the main
+.I zlib
+web site.
+.SH "SEE ALSO"
+The
+.I zlib
+web site can be found at either of these locations:
+.IP
+http://www.zlib.org
+.br
+http://www.gzip.org/zlib/
+.LP
+The data format used by the zlib library is described by RFC
+(Request for Comments) 1950 to 1952 in the files:
+.IP
+http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format)
+.br
+http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format)
+.br
+http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format)
+.LP
+These documents are also available in other formats from:
+.IP
+ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+.LP
+Mark Nelson (markn@ieee.org) wrote an article about
+.I zlib
+for the Jan. 1997 issue of Dr. Dobb's Journal;
+a copy of the article is available at:
+.IP
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+.SH "REPORTING PROBLEMS"
+Before reporting a problem,
+please check the
+.I zlib
+web site to verify that you have the latest version of
+.IR zlib ;
+otherwise,
+obtain the latest version and see if the problem still exists.
+Please read the
+.I zlib
+FAQ at:
+.IP
+http://www.gzip.org/zlib/zlib_faq.html
+.LP
+before asking for help.
+Send questions and/or comments to zlib@gzip.org,
+or (for the Windows DLL version) to Gilles Vollant (info@winimage.com).
+.SH AUTHORS
+Version 1.2.3
+Copyright (C) 1995-2005 Jean-loup Gailly (jloup@gzip.org)
+and Mark Adler (madler@alumni.caltech.edu).
+.LP
+This software is provided "as-is,"
+without any express or implied warranty.
+In no event will the authors be held liable for any damages
+arising from the use of this software.
+See the distribution directory with respect to requirements
+governing redistribution.
+The deflate format used by
+.I zlib
+was defined by Phil Katz.
+The deflate and
+.I zlib
+specifications were written by L. Peter Deutsch.
+Thanks to all the people who reported problems and suggested various
+improvements in
+.IR zlib ;
+who are too numerous to cite here.
+.LP
+UNIX manual page by R. P. C. Rodgers,
+U.S. National Library of Medicine (rodgers@nlm.nih.gov).
+.\" end of man page
diff --git a/zlib/zlib.h b/zlib/zlib.h
new file mode 100644
index 0000000..0228179
--- /dev/null
+++ b/zlib/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.3, July 18th, 2005
+
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumualte before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately. Z_FIXED prevents the
+ use of dynamic Huffman codes, allowing for a simpler decoder for special
+ applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front. In addition, the
+ current implementation of deflate will use at most the window size minus
+ 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK can be used to
+ force inflate() to return immediately after header processing is complete
+ and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When
+ any of extra, name, or comment are not Z_NULL and the respective field is
+ not present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns 1 if file is being read directly without decompression, otherwise
+ zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+/*
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is NULL, this function returns the required initial
+ value for the for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/zlib/zutil.c b/zlib/zutil.c
new file mode 100644
index 0000000..d55f594
--- /dev/null
+++ b/zlib/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/zlib/zutil.h b/zlib/zutil.h
new file mode 100644
index 0000000..b7d5eff
--- /dev/null
+++ b/zlib/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+# ifdef _WIN32_WCE
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used. We rename it to
+ * avoid conflict with other libraries that use the same workaround.
+ */
+# define errno z_errno
+# endif
+ extern int errno;
+#else
+# ifndef _WIN32_WCE
+# include <errno.h>
+# endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+ #include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */